From 5a0168d904e1a6315cfec445bf5486b57b6bb391 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 25 Apr 2017 18:44:05 +1000 Subject: [PATCH 0001/2058] Add missing changelog entries, Update build directory layout --- .gitignore | 8 +++++++- CHANGELOG.txt | 6 ++++++ ProcessHacker/ProcessHacker.vcxproj | 16 ++++++++-------- build/build_binaries.cmd | 2 +- build/build_debug.cmd | 2 +- build/build_release.cmd | 2 +- build/build_sdk.cmd | 2 +- build/build_sdk_rebuild.cmd | 2 +- .../CustomBuildTool.csproj | 2 +- tools/CustomBuildTool/CustomBuildTool.sln | 2 +- .../CustomBuildTool/CustomBuildTool/app.config | 3 --- .../Properties/AssemblyInfo.cs | 0 .../Resource Files/ProcessHacker.ico | Bin .../Resource Files/app.manifest | 0 .../Source Files/Build.cs | 11 ----------- .../Source Files/HeaderGen.cs | 0 .../{CustomBuildTool => }/Source Files/Json.cs | 0 .../Source Files/NativeMethods.cs | 0 .../Source Files/Nightly.cs | 0 .../Source Files/Program.cs | 0 .../Source Files/Verify.cs | 0 .../Source Files/VisualStudio.cs | 0 .../{CustomBuildTool => }/Source Files/Zip.cs | 0 tools/CustomBuildTool/app.config | 8 ++++++++ .../bin/Release/CustomBuildTool.exe | Bin 0 -> 143360 bytes .../bin/Release/CustomBuildTool.exe.config | 8 ++++++++ .../bin/Release/CustomBuildTool.pdb | Bin 0 -> 62976 bytes .../resources/ProcessHacker.ico | Bin 28 files changed, 44 insertions(+), 30 deletions(-) rename tools/CustomBuildTool/{CustomBuildTool => }/CustomBuildTool.csproj (98%) delete mode 100644 tools/CustomBuildTool/CustomBuildTool/app.config rename tools/CustomBuildTool/{CustomBuildTool => }/Properties/AssemblyInfo.cs (100%) rename tools/CustomBuildTool/{CustomBuildTool => }/Resource Files/ProcessHacker.ico (100%) rename tools/CustomBuildTool/{CustomBuildTool => }/Resource Files/app.manifest (100%) rename tools/CustomBuildTool/{CustomBuildTool => }/Source Files/Build.cs (99%) rename tools/CustomBuildTool/{CustomBuildTool => }/Source Files/HeaderGen.cs (100%) rename tools/CustomBuildTool/{CustomBuildTool => }/Source Files/Json.cs (100%) rename tools/CustomBuildTool/{CustomBuildTool => }/Source Files/NativeMethods.cs (100%) rename tools/CustomBuildTool/{CustomBuildTool => }/Source Files/Nightly.cs (100%) rename tools/CustomBuildTool/{CustomBuildTool => }/Source Files/Program.cs (100%) rename tools/CustomBuildTool/{CustomBuildTool => }/Source Files/Verify.cs (100%) rename tools/CustomBuildTool/{CustomBuildTool => }/Source Files/VisualStudio.cs (100%) rename tools/CustomBuildTool/{CustomBuildTool => }/Source Files/Zip.cs (100%) create mode 100644 tools/CustomBuildTool/app.config create mode 100644 tools/CustomBuildTool/bin/Release/CustomBuildTool.exe create mode 100644 tools/CustomBuildTool/bin/Release/CustomBuildTool.exe.config create mode 100644 tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb rename tools/CustomBuildTool/{CustomBuildTool => }/resources/ProcessHacker.ico (100%) diff --git a/.gitignore b/.gitignore index f29e5c0572b9..1a44e8b91e28 100644 --- a/.gitignore +++ b/.gitignore @@ -101,7 +101,6 @@ Desktop.ini ########################## build/installer/*.exe -ProcessHacker/include/phapprev.h ProcessHacker/sdk/phapppub.h plugins-extra/ /sdk/ @@ -121,6 +120,13 @@ plugins/SamplePlugin/bin/Release64/* !plugins/SamplePlugin/bin/Release64/SamplePlugin.dll plugins/OnlineChecks/virustotal.h +!tools/CustomBuildTool/bin/ +tools/CustomBuildTool/bin/Debug*/ +tools/CustomBuildTool/bin/Release*/* +!tools/CustomBuildTool/bin/Release/CustomBuildTool.exe +!tools/CustomBuildTool/bin/Release/CustomBuildTool.exe.config +!tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb + !tools/CustomSignTool/bin/ tools/CustomSignTool/bin/Debug*/ tools/CustomSignTool/bin/Release*/* diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 6860af3f2ae8..561d9aacd6a2 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -2,7 +2,13 @@ Process Hacker 3.0 * HIGHLIGHTS: + * New Process Hacker setup. + * Added F11 hotkey for fullscreen System Information window. * OTHER CHANGES: +* Updated Updater plugin: + * New design and layout. +* Updated WindowExplorer plugin: + * Added Windows process properties page. * NOTE: * Support for Windows XP and Vista has been dropped. For those platforms, use Process Hacker 2.38. * This release has significant internal code changes. Please make sure all plugins are up-to-date. diff --git a/ProcessHacker/ProcessHacker.vcxproj b/ProcessHacker/ProcessHacker.vcxproj index 7b8342faa6c4..ae99a1ad051e 100644 --- a/ProcessHacker/ProcessHacker.vcxproj +++ b/ProcessHacker/ProcessHacker.vcxproj @@ -105,11 +105,11 @@ aclui.dll;iphlpapi.dll;ws2_32.dll;%(DelayLoadDLLs) - ..\build\CustomBuildTool.exe -updaterev + ..\tools\CustomBuildTool\bin\Release\CustomBuildTool.exe -updaterev Generating revision number... - ..\build\CustomBuildTool.exe -cleanup + ..\tools\CustomBuildTool\bin\Release\CustomBuildTool.exe -cleanup Cleaning up build... @@ -137,11 +137,11 @@ aclui.dll;iphlpapi.dll;ws2_32.dll;%(DelayLoadDLLs) - ..\build\CustomBuildTool.exe -updaterev + ..\tools\CustomBuildTool\bin\Release\CustomBuildTool.exe -updaterev Generating revision number... - ..\build\CustomBuildTool.exe -cleanup + ..\tools\CustomBuildTool\bin\Release\CustomBuildTool.exe -cleanup Cleaning up build... @@ -176,11 +176,11 @@ aclui.dll;iphlpapi.dll;ws2_32.dll;%(DelayLoadDLLs) - ..\build\CustomBuildTool.exe -updaterev + ..\tools\CustomBuildTool\bin\Release\CustomBuildTool.exe -updaterev Generating revision number... - ..\build\CustomBuildTool.exe -cleanup + ..\tools\CustomBuildTool\bin\Release\CustomBuildTool.exe -cleanup Cleaning up build... @@ -214,11 +214,11 @@ aclui.dll;iphlpapi.dll;ws2_32.dll;%(DelayLoadDLLs) - ..\build\CustomBuildTool.exe -updaterev + ..\tools\CustomBuildTool\bin\Release\CustomBuildTool.exe -updaterev Generating revision number... - ..\build\CustomBuildTool.exe -cleanup + ..\tools\CustomBuildTool\bin\Release\CustomBuildTool.exe -cleanup Cleaning up build... diff --git a/build/build_binaries.cmd b/build/build_binaries.cmd index 3fad7f7d524c..8c42e4bbe1b1 100644 --- a/build/build_binaries.cmd +++ b/build/build_binaries.cmd @@ -1,5 +1,5 @@ @echo off -CustomBuildTool.exe -bin +..\tools\CustomBuildTool\bin\Release\CustomBuildTool.exe -bin pause diff --git a/build/build_debug.cmd b/build/build_debug.cmd index d11d2ffedd85..7f3fbb6d6035 100644 --- a/build/build_debug.cmd +++ b/build/build_debug.cmd @@ -1,5 +1,5 @@ @echo off -CustomBuildTool.exe -debug +..\tools\CustomBuildTool\bin\Release\CustomBuildTool.exe -debug pause diff --git a/build/build_release.cmd b/build/build_release.cmd index c92eb4847d49..15e528690fb6 100644 --- a/build/build_release.cmd +++ b/build/build_release.cmd @@ -12,6 +12,6 @@ set KPH_BUILD_KEY=%KPH_BUILD_KEY% set NIGHTLY_BUILD_KEY=%NIGHTLY_BUILD_KEY% -CustomBuildTool.exe -release +..\tools\CustomBuildTool\bin\Release\CustomBuildTool.exe -release pause diff --git a/build/build_sdk.cmd b/build/build_sdk.cmd index 31bed7a1b211..11e16deb7d05 100644 --- a/build/build_sdk.cmd +++ b/build/build_sdk.cmd @@ -1,3 +1,3 @@ @echo off -CustomBuildTool.exe -sdk \ No newline at end of file +..\tools\CustomBuildTool\bin\Release\CustomBuildTool.exe -sdk \ No newline at end of file diff --git a/build/build_sdk_rebuild.cmd b/build/build_sdk_rebuild.cmd index 8658cf1b1a04..bc9493c504d5 100644 --- a/build/build_sdk_rebuild.cmd +++ b/build/build_sdk_rebuild.cmd @@ -1,5 +1,5 @@ @echo off -CustomBuildTool.exe -cleansdk +..\tools\CustomBuildTool\bin\Release\CustomBuildTool.exe -cleansdk pause diff --git a/tools/CustomBuildTool/CustomBuildTool/CustomBuildTool.csproj b/tools/CustomBuildTool/CustomBuildTool.csproj similarity index 98% rename from tools/CustomBuildTool/CustomBuildTool/CustomBuildTool.csproj rename to tools/CustomBuildTool/CustomBuildTool.csproj index 7e2f0b447a35..08d1323194e2 100644 --- a/tools/CustomBuildTool/CustomBuildTool/CustomBuildTool.csproj +++ b/tools/CustomBuildTool/CustomBuildTool.csproj @@ -9,7 +9,7 @@ Properties CustomBuildTool CustomBuildTool - v4.6.2 + v4.5 512 true diff --git a/tools/CustomBuildTool/CustomBuildTool.sln b/tools/CustomBuildTool/CustomBuildTool.sln index 43914052a1c2..811b822b2e06 100644 --- a/tools/CustomBuildTool/CustomBuildTool.sln +++ b/tools/CustomBuildTool/CustomBuildTool.sln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 VisualStudioVersion = 15.0.26403.0 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CustomBuildTool", "CustomBuildTool\CustomBuildTool.csproj", "{CD644DF2-A658-4CBC-9497-CA5DD13CFEC3}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CustomBuildTool", "CustomBuildTool.csproj", "{CD644DF2-A658-4CBC-9497-CA5DD13CFEC3}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/tools/CustomBuildTool/CustomBuildTool/app.config b/tools/CustomBuildTool/CustomBuildTool/app.config deleted file mode 100644 index 2a0024f75eca..000000000000 --- a/tools/CustomBuildTool/CustomBuildTool/app.config +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/tools/CustomBuildTool/CustomBuildTool/Properties/AssemblyInfo.cs b/tools/CustomBuildTool/Properties/AssemblyInfo.cs similarity index 100% rename from tools/CustomBuildTool/CustomBuildTool/Properties/AssemblyInfo.cs rename to tools/CustomBuildTool/Properties/AssemblyInfo.cs diff --git a/tools/CustomBuildTool/CustomBuildTool/Resource Files/ProcessHacker.ico b/tools/CustomBuildTool/Resource Files/ProcessHacker.ico similarity index 100% rename from tools/CustomBuildTool/CustomBuildTool/Resource Files/ProcessHacker.ico rename to tools/CustomBuildTool/Resource Files/ProcessHacker.ico diff --git a/tools/CustomBuildTool/CustomBuildTool/Resource Files/app.manifest b/tools/CustomBuildTool/Resource Files/app.manifest similarity index 100% rename from tools/CustomBuildTool/CustomBuildTool/Resource Files/app.manifest rename to tools/CustomBuildTool/Resource Files/app.manifest diff --git a/tools/CustomBuildTool/CustomBuildTool/Source Files/Build.cs b/tools/CustomBuildTool/Source Files/Build.cs similarity index 99% rename from tools/CustomBuildTool/CustomBuildTool/Source Files/Build.cs rename to tools/CustomBuildTool/Source Files/Build.cs index 8f229f0064e7..e2dd8230d978 100644 --- a/tools/CustomBuildTool/CustomBuildTool/Source Files/Build.cs +++ b/tools/CustomBuildTool/Source Files/Build.cs @@ -183,18 +183,7 @@ public static void CleanupBuildEnvironment() { try { - // BUG - if (File.Exists("ProcessHacker\\include\\phapprev.h")) - File.Delete("ProcessHacker\\include\\phapprev.h"); - File.WriteAllText("ProcessHacker\\include\\phapprev.h", -@"#ifndef PHAPPREV_H -#define PHAPPREV_H - -#define PHAPP_VERSION_REVISION 0 - -#endif // PHAPPREV_H -"); } catch (Exception ex) { diff --git a/tools/CustomBuildTool/CustomBuildTool/Source Files/HeaderGen.cs b/tools/CustomBuildTool/Source Files/HeaderGen.cs similarity index 100% rename from tools/CustomBuildTool/CustomBuildTool/Source Files/HeaderGen.cs rename to tools/CustomBuildTool/Source Files/HeaderGen.cs diff --git a/tools/CustomBuildTool/CustomBuildTool/Source Files/Json.cs b/tools/CustomBuildTool/Source Files/Json.cs similarity index 100% rename from tools/CustomBuildTool/CustomBuildTool/Source Files/Json.cs rename to tools/CustomBuildTool/Source Files/Json.cs diff --git a/tools/CustomBuildTool/CustomBuildTool/Source Files/NativeMethods.cs b/tools/CustomBuildTool/Source Files/NativeMethods.cs similarity index 100% rename from tools/CustomBuildTool/CustomBuildTool/Source Files/NativeMethods.cs rename to tools/CustomBuildTool/Source Files/NativeMethods.cs diff --git a/tools/CustomBuildTool/CustomBuildTool/Source Files/Nightly.cs b/tools/CustomBuildTool/Source Files/Nightly.cs similarity index 100% rename from tools/CustomBuildTool/CustomBuildTool/Source Files/Nightly.cs rename to tools/CustomBuildTool/Source Files/Nightly.cs diff --git a/tools/CustomBuildTool/CustomBuildTool/Source Files/Program.cs b/tools/CustomBuildTool/Source Files/Program.cs similarity index 100% rename from tools/CustomBuildTool/CustomBuildTool/Source Files/Program.cs rename to tools/CustomBuildTool/Source Files/Program.cs diff --git a/tools/CustomBuildTool/CustomBuildTool/Source Files/Verify.cs b/tools/CustomBuildTool/Source Files/Verify.cs similarity index 100% rename from tools/CustomBuildTool/CustomBuildTool/Source Files/Verify.cs rename to tools/CustomBuildTool/Source Files/Verify.cs diff --git a/tools/CustomBuildTool/CustomBuildTool/Source Files/VisualStudio.cs b/tools/CustomBuildTool/Source Files/VisualStudio.cs similarity index 100% rename from tools/CustomBuildTool/CustomBuildTool/Source Files/VisualStudio.cs rename to tools/CustomBuildTool/Source Files/VisualStudio.cs diff --git a/tools/CustomBuildTool/CustomBuildTool/Source Files/Zip.cs b/tools/CustomBuildTool/Source Files/Zip.cs similarity index 100% rename from tools/CustomBuildTool/CustomBuildTool/Source Files/Zip.cs rename to tools/CustomBuildTool/Source Files/Zip.cs diff --git a/tools/CustomBuildTool/app.config b/tools/CustomBuildTool/app.config new file mode 100644 index 000000000000..9f787f35ef79 --- /dev/null +++ b/tools/CustomBuildTool/app.config @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe b/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe new file mode 100644 index 0000000000000000000000000000000000000000..5e2154b8d6b793832261812d5971bfb277e2b5eb GIT binary patch literal 143360 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 z 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®xezAOXBe(@oib`1ii(7nW3+DccU}2!|xgSd! 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 CjrFns literal 0 HcmV?d00001 diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe.config b/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe.config new file mode 100644 index 000000000000..9f787f35ef79 --- /dev/null +++ b/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe.config @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb b/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb new file mode 100644 index 0000000000000000000000000000000000000000..bc21e1d516acfa1eaa34099d5de2f91520936a9d GIT binary patch literal 62976 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 RX@Qd#IB9{C7C1&0`2Wz59HamM literal 0 HcmV?d00001 diff --git a/tools/CustomBuildTool/CustomBuildTool/resources/ProcessHacker.ico b/tools/CustomBuildTool/resources/ProcessHacker.ico similarity index 100% rename from tools/CustomBuildTool/CustomBuildTool/resources/ProcessHacker.ico rename to tools/CustomBuildTool/resources/ProcessHacker.ico From 1ef703b3ee69c0c63bcf252132ce65ab71884da4 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 25 Apr 2017 18:51:01 +1000 Subject: [PATCH 0002/2058] Update build tools --- build/CustomBuildTool.exe | Bin 143872 -> 0 bytes tools/CustomBuildTool/Source Files/Build.cs | 22 +++++++++++++----- tools/CustomBuildTool/Source Files/Program.cs | 3 --- .../bin/Release/CustomBuildTool.exe | Bin 143360 -> 143360 bytes .../bin/Release/CustomBuildTool.pdb | Bin 62976 -> 62976 bytes 5 files changed, 16 insertions(+), 9 deletions(-) delete mode 100644 build/CustomBuildTool.exe diff --git a/build/CustomBuildTool.exe b/build/CustomBuildTool.exe deleted file mode 100644 index 1acc5834cacd17643cdf36a6766a3c2c0213bb23..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 143872 zcmd?S34B}Cu|GcdN|t1KmAu7E632;S#T(vYI~&AnVsJLwNeJZCv1P?EaV&9V$4&x4 zAwUd;21=l1YuO5=rIZ4FEtIxlX$x&Bbf;SgU0zF9O1Hc|9{GJ|&b^ZCI3ewO@BiNC z^H-v|Gjrz5nKS2{Im^AeUUSinWFsOwz9&x-eHK^#tQ2@=5J7V4+^16MiNu%YeOBvy zXScy2o4&3y9)h%BO}4l!u~*^F*Z^-G*Z~QuDftoa3D~blHy)qs$Snl)T!C% zyyxG(&?@aX6;YB_MRY$n*K5LdKZi>pzQ^%p>k4tvmEFL|!GJ$^gNgtAvC+1xiPGhN z>}rxqgg*N$(K^PD6TNz^D$7h#mxxZuz#`8O6--HZ7ow2J6(`~Xy*iGr91Tp2f=<5= z0BKTJ({51mDJ0rfX@m_wD6#E0kn3RM1GvV0RuZkOGy=mx2(qmNo5crJQx!t4nUmu` zzkOCwY@1FAG~7v)IYz{u*c0d0_&jIA^Q&ysh|Ku!@#PS?Bf#tiK*%?X$rO;j2sA4) zl~d2NQU%NR3y;l8G5!R>#A$XM({oB)rJ8iKHd=Rt@-xMi zXyZc?^%3D?{- z)i?IDJxVsu$by(9Aqke0u_!JjQFJPGmKHXv!sD^Wl6;F$Tq$K#*$I7+m#-k$7I7CT)&G0T~AVUpAFzM-0*?MH{Rr(|c?%SsbH z_S-WOj9XB+Cqa6&@u?WD?DyDnF3hld?1{+x@_sM!W;n7loMmMmhsSw)hRgUG=Wxa4 zR=AlP73JB&9_ zU=X9(;Rqt~I*hrgaNrgI)8U7helkYC#&kwnG<^wBV`r2;HY-VNnm%c$V2!dZo3?C; z`FsudnEySZ$5)M!10I*e{n1L=Gd1Z)ak=t6Q*vDnQgUJL5nSe;C*!z+ z3->Q^T)~CA*c;OzcuckqZV4_1FeD*LN)3%M&WK6HQ7lu8d!b?%X3WU`+B9}Wma#vR z1C+#jYY9-QbbJ&k@v0$wan`BAITAB}hclR2@TRar?AQRFlcFhr*A)xhR-nl zeE^4||AXoCawy~y`dDs?aS+t>0ce*2Xh#S)`}WYCUmxt@IYp`a zDioh;PmC+}*mJGYV+l9HxHAXbs6U9>+G6E@ZA$scP7Op2(G9|EbW9xH_FA~_7stFmzp$t&c$)YOV|pZug%&jk7i z>dA3V7Fbpkc>r2t9hQ_K$GOnhYTfJ;F)sVyG!316tVJ#0^75=|9bwGI@op*d$&f{W zMNn{K$f^a%)bY&=>u6gQQ2A=B4mR1B#rn!C(0r<$F|M-nOsgErPvzxS8Fso1F*-Tg zAKm#gl@a4|8Pf*>2k-JZ)41VfT>Iq!5wwDRdXvZJiFSmzJeW1iJkv&O?zD1zSD^Dm z5bS0y!W54dp~Mjn?BNx#4Ri8()Hrx9@P!WJdf@w6ms$;D_vf~fJ~Um7bxapiwne?= z2(E;NvzR`c;x_Qx&>sB7o|M$y$4(L8{5jJ+%7N4B=HG*{RyWTno$fLAJvNfF3SvUp z<}A|>o)Z5cFdsWWdT<0i#Lja|0=)v;Qnn_JdVaH zz5*KT#*evxCS(r|FjICd!R?aH9mdzpNjsP}jzctfiJ+Ti!$1rPyOA=-G%z?kEoFW* zWrS12&|pYVHZy1l%0>o91!WV1yMg*zP^dXtQLAa&|JYQRWGv<~&_q}V0E?w0o0Fhc zYEFC5(#sNTvkcz3N#@?(*NW`nHh`4GU^}b21A?yLDxir@hi^5rJ^@y^16c5U0A9@o zF93o|Co{2_b63nUUWSy#S_zga$Xr1jb0?NN5`$~O|M9U|STu`tg0Bz^>mUKUZr
O?EePA;o-x^7qVdm&>I7qe50^B_ER@oITt3o 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 diff --git a/tools/CustomBuildTool/Source Files/Build.cs b/tools/CustomBuildTool/Source Files/Build.cs index e2dd8230d978..6819e256a7bf 100644 --- a/tools/CustomBuildTool/Source Files/Build.cs +++ b/tools/CustomBuildTool/Source Files/Build.cs @@ -206,13 +206,23 @@ public static void ShowBuildEnvironment(bool ShowBuildInfo) if (ShowBuildInfo) { + string buildMessage = string.Empty; + + if (BuildNightly) + { + buildMessage = Win32.ExecCommand(GitExePath, "log -n 5 --date=format:%Y-%m-%d --pretty=format:\"[%cd] %an: %<(65,trunc)%s (%h)\" --abbrev-commit"); + } + else + { + Win32.GetConsoleMode(Win32.GetStdHandle(Win32.STD_OUTPUT_HANDLE), out ConsoleMode mode); + Win32.SetConsoleMode(Win32.GetStdHandle(Win32.STD_OUTPUT_HANDLE), mode | ConsoleMode.ENABLE_VIRTUAL_TERMINAL_PROCESSING); + buildMessage = Win32.ExecCommand(GitExePath, "log -n 5 --date=format:%Y-%m-%d --pretty=format:\"%C(green)[%cd]%Creset %C(bold blue)%an%Creset %<(65,trunc)%s%Creset (%C(yellow)%h%Creset)\" --abbrev-commit"); + } + string currentBranch = Win32.ExecCommand(GitExePath, "rev-parse --abbrev-ref HEAD"); string currentCommitTag = Win32.ExecCommand(GitExePath, "rev-parse --short HEAD"); // rev-parse HEAD //string latestGitCount = Win32.GitExecCommand("rev-list --count " + BuildBranch); - string buildMessageColor = !BuildNightly ? - Win32.ExecCommand(GitExePath, "log -n 5 --date=format:%Y-%m-%d --pretty=format:\"%C(green)[%cd]%Creset %C(bold blue)%an%Creset %<(65,trunc)%s%Creset (%C(yellow)%h%Creset)\" --abbrev-commit") : - Win32.ExecCommand(GitExePath, "log -n 5 --date=format:%Y-%m-%d --pretty=format:\"[%cd] %an %<(65,trunc)%s (%h)\" --abbrev-commit"); - + if (!string.IsNullOrEmpty(currentBranch)) { Program.PrintColorMessage(Environment.NewLine + "Branch: ", ConsoleColor.Cyan, false); @@ -228,9 +238,9 @@ public static void ShowBuildEnvironment(bool ShowBuildInfo) Program.PrintColorMessage("Commit: ", ConsoleColor.Cyan, false); Program.PrintColorMessage(currentCommitTag + Environment.NewLine, ConsoleColor.White); - if (!BuildNightly) + if (!BuildNightly && !string.IsNullOrEmpty(buildMessage)) { - Console.WriteLine(buildMessageColor + Environment.NewLine); + Console.WriteLine(buildMessage + Environment.NewLine); } } } diff --git a/tools/CustomBuildTool/Source Files/Program.cs b/tools/CustomBuildTool/Source Files/Program.cs index 89e4f603c114..4cc566b5c6d3 100644 --- a/tools/CustomBuildTool/Source Files/Program.cs +++ b/tools/CustomBuildTool/Source Files/Program.cs @@ -22,9 +22,6 @@ public static void PrintColorMessage(string Message, ConsoleColor Color, bool Ne public static void Main(string[] args) { - if (Win32.GetConsoleMode(Win32.GetStdHandle(Win32.STD_OUTPUT_HANDLE), out ConsoleMode mode)) - Win32.SetConsoleMode(Win32.GetStdHandle(Win32.STD_OUTPUT_HANDLE), mode | ConsoleMode.ENABLE_VIRTUAL_TERMINAL_PROCESSING); - ProgramArgs = ParseArgs(args); BuildDebug = ProgramArgs.ContainsKey("-debug"); diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe b/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe index 5e2154b8d6b793832261812d5971bfb277e2b5eb..0416602b5cdd7fcbf6f32c9600c257ccb91d5a4a 100644 GIT binary patch delta 9869 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 delta 9824 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 diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb b/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb index bc21e1d516acfa1eaa34099d5de2f91520936a9d..586c922cd41f3527db93e1e43b3502a94fcdcaed 100644 GIT binary patch delta 11261 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 AQvd(} delta 11786 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 From 8475e8ca4dad8f64c31fa51188152cc6496aa617 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 25 Apr 2017 18:53:40 +1000 Subject: [PATCH 0003/2058] Fix appveyor build config --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 15728ca977a5..4ad9645b488a 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -28,7 +28,7 @@ test: off # Run custom build script. build_script: -- cmd: .\build\CustomBuildTool.exe +- cmd: tools\CustomBuildTool\bin\Release\CustomBuildTool.exe # Setup build notifications. notifications: From 55b59fc9863d6f380e304c15931e535d8bb9d259 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 25 Apr 2017 20:11:06 +1000 Subject: [PATCH 0004/2058] Move Searchbox control into main program, Update plugins with new Searchbox control --- ProcessHacker/ProcessHacker.rc | 14 +- ProcessHacker/ProcessHacker.vcxproj | 37 ++- ProcessHacker/ProcessHacker.vcxproj.filters | 15 + ProcessHacker/include/phapp.h | 64 ++++ ProcessHacker/resource.h | 6 +- ProcessHacker/resources/active_search.bmp | Bin 0 -> 1494 bytes ProcessHacker/resources/active_search.png | Bin 0 -> 569 bytes ProcessHacker/resources/inactive_search.bmp | Bin 0 -> 1494 bytes ProcessHacker/resources/inactive_search.png | Bin 0 -> 755 bytes .../CommonUtil => ProcessHacker}/searchbox.c | 297 +++++++++++++++--- plugins/CommonUtil/CommonUtil.vcxproj | 8 - plugins/CommonUtil/CommonUtil.vcxproj.filters | 20 -- plugins/CommonUtil/main.c | 4 - plugins/CommonUtil/main.h | 40 --- plugins/CommonUtil/png.c | 190 ----------- plugins/ExtraPlugins/dialog.c | 6 +- plugins/ExtraPlugins/setup/updater.c | 2 +- plugins/ExtraPlugins/wndtree.c | 6 +- plugins/NetworkTools/main.c | 2 +- plugins/NetworkTools/nettools.h | 1 + plugins/NetworkTools/ping.c | 2 +- plugins/NetworkTools/tracert.c | 2 +- plugins/NetworkTools/tracetree.c | 2 +- plugins/NetworkTools/whois.c | 2 +- plugins/ToolStatus/searchbox.c | 2 +- plugins/ToolStatus/toolbar.c | 18 +- plugins/ToolStatus/toolstatus.h | 1 + plugins/Updater/updater.c | 2 +- plugins/WindowExplorer/wnddlg.c | 4 +- plugins/WindowExplorer/wndexp.h | 1 + plugins/include/commonutil.h | 117 ------- 31 files changed, 403 insertions(+), 462 deletions(-) create mode 100644 ProcessHacker/resources/active_search.bmp create mode 100644 ProcessHacker/resources/active_search.png create mode 100644 ProcessHacker/resources/inactive_search.bmp create mode 100644 ProcessHacker/resources/inactive_search.png rename {plugins/CommonUtil => ProcessHacker}/searchbox.c (59%) delete mode 100644 plugins/CommonUtil/png.c diff --git a/ProcessHacker/ProcessHacker.rc b/ProcessHacker/ProcessHacker.rc index 1fdef831b78a..6b3a616f4b86 100644 --- a/ProcessHacker/ProcessHacker.rc +++ b/ProcessHacker/ProcessHacker.rc @@ -2498,7 +2498,7 @@ BEGIN VK_F6, IDC_PAUSE, VIRTKEY, NOINVERT VK_PAUSE, IDC_PAUSE, VIRTKEY, NOINVERT VK_F5, IDC_REFRESH, VIRTKEY, NOINVERT - VK_F11, IDC_MAXSCREEN, VIRTKEY, NOINVERT + VK_F11, IDC_MAXSCREEN, VIRTKEY, NOINVERT END @@ -2508,8 +2508,9 @@ END // IDB_CROSS BITMAP "resources\\cross.bmp" - IDB_TICK BITMAP "resources\\tick.bmp" +IDB_SEARCH_ACTIVE_BMP BITMAP "resources\\active_search.bmp" +IDB_SEARCH_INACTIVE_BMP BITMAP "resources\\inactive_search.bmp" ///////////////////////////////////////////////////////////////////////////// @@ -2590,6 +2591,15 @@ BEGIN 0 END + +///////////////////////////////////////////////////////////////////////////// +// +// PNG +// + +IDB_SEARCH_ACTIVE PNG "resources\\active_search.png" +IDB_SEARCH_INACTIVE PNG "resources\\inactive_search.png" + #endif // English (Australia) resources ///////////////////////////////////////////////////////////////////////////// diff --git a/ProcessHacker/ProcessHacker.vcxproj b/ProcessHacker/ProcessHacker.vcxproj index ae99a1ad051e..10b281657fd7 100644 --- a/ProcessHacker/ProcessHacker.vcxproj +++ b/ProcessHacker/ProcessHacker.vcxproj @@ -95,7 +95,7 @@ true - aclui.lib;comctl32.lib;iphlpapi.lib;noarg.obj;noenv.obj;ntdll.lib;phlib.lib;uxtheme.lib;version.lib;winsta.lib;ws2_32.lib;%(AdditionalDependencies) + aclui.lib;comctl32.lib;iphlpapi.lib;noarg.obj;noenv.obj;ntdll.lib;phlib.lib;uxtheme.lib;version.lib;windowscodecs.lib;winsta.lib;ws2_32.lib;%(AdditionalDependencies) true Windows MachineX86 @@ -109,8 +109,10 @@ Generating revision number... - ..\tools\CustomBuildTool\bin\Release\CustomBuildTool.exe -cleanup - Cleaning up build... + + + + @@ -127,7 +129,7 @@ true - aclui.lib;comctl32.lib;iphlpapi.lib;noarg.obj;noenv.obj;ntdll.lib;phlib.lib;uxtheme.lib;version.lib;winsta.lib;ws2_32.lib;%(AdditionalDependencies) + aclui.lib;comctl32.lib;iphlpapi.lib;noarg.obj;noenv.obj;ntdll.lib;phlib.lib;uxtheme.lib;version.lib;windowscodecs.lib;winsta.lib;ws2_32.lib;%(AdditionalDependencies) true Windows MachineX64 @@ -141,8 +143,10 @@ Generating revision number... - ..\tools\CustomBuildTool\bin\Release\CustomBuildTool.exe -cleanup - Cleaning up build... + + + + @@ -163,7 +167,7 @@ StreamingSIMDExtensions - aclui.lib;comctl32.lib;iphlpapi.lib;noarg.obj;noenv.obj;ntdll.lib;phlib.lib;uxtheme.lib;version.lib;winsta.lib;ws2_32.lib;%(AdditionalDependencies) + aclui.lib;comctl32.lib;iphlpapi.lib;noarg.obj;noenv.obj;ntdll.lib;phlib.lib;uxtheme.lib;version.lib;windowscodecs.lib;winsta.lib;ws2_32.lib;%(AdditionalDependencies) true Windows true @@ -180,8 +184,10 @@ Generating revision number... - ..\tools\CustomBuildTool\bin\Release\CustomBuildTool.exe -cleanup - Cleaning up build... + + + + @@ -201,7 +207,7 @@ true - aclui.lib;comctl32.lib;iphlpapi.lib;noarg.obj;noenv.obj;ntdll.lib;phlib.lib;uxtheme.lib;version.lib;winsta.lib;ws2_32.lib;%(AdditionalDependencies) + aclui.lib;comctl32.lib;iphlpapi.lib;noarg.obj;noenv.obj;ntdll.lib;phlib.lib;uxtheme.lib;version.lib;windowscodecs.lib;winsta.lib;ws2_32.lib;%(AdditionalDependencies) true Windows true @@ -218,8 +224,10 @@ Generating revision number... - ..\tools\CustomBuildTool\bin\Release\CustomBuildTool.exe -cleanup - Cleaning up build... + + + + @@ -322,6 +330,7 @@ + @@ -428,7 +437,11 @@ + + + + diff --git a/ProcessHacker/ProcessHacker.vcxproj.filters b/ProcessHacker/ProcessHacker.vcxproj.filters index 85a5e1b50318..6b6d551e6e04 100644 --- a/ProcessHacker/ProcessHacker.vcxproj.filters +++ b/ProcessHacker/ProcessHacker.vcxproj.filters @@ -408,6 +408,9 @@ Process Hacker + + Process Hacker + @@ -634,5 +637,17 @@ Resources + + Resources + + + Resources + + + Resources + + + Resources + \ No newline at end of file diff --git a/ProcessHacker/include/phapp.h b/ProcessHacker/include/phapp.h index 077f2e7b828a..b9fafef05156 100644 --- a/ProcessHacker/include/phapp.h +++ b/ProcessHacker/include/phapp.h @@ -605,6 +605,70 @@ NTSTATUS PhInvokeRunAsService( _In_ PPH_RUNAS_SERVICE_PARAMETERS Parameters ); +// searchbox + +// begin_phapppub +PHAPPAPI +VOID +NTAPI +PhCreateSearchControl( + _In_ HWND Parent, + _In_ HWND WindowHandle, + _In_ PWSTR BannerText + ); + +PHAPPAPI +HBITMAP +NTAPI +PhLoadPngImageFromResource( + _In_ PVOID DllBase, + _In_ UINT Width, + _In_ UINT Height, + _In_ PCWSTR Name, + _In_ BOOLEAN RGBAImage + ); + +FORCEINLINE +HFONT +PhCreateCommonFont( + _In_ LONG Size, + _In_ INT Weight, + _In_opt_ HWND hwnd + ) +{ + HFONT fontHandle; + LOGFONT logFont; + + if (!SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(LOGFONT), &logFont, 0)) + return NULL; + + fontHandle = CreateFont( + -PhMultiplyDivideSigned(Size, PhGlobalDpi, 72), + 0, + 0, + 0, + Weight, + FALSE, + FALSE, + FALSE, + ANSI_CHARSET, + OUT_DEFAULT_PRECIS, + CLIP_DEFAULT_PRECIS, + CLEARTYPE_QUALITY | ANTIALIASED_QUALITY, + DEFAULT_PITCH, + logFont.lfFaceName + ); + + if (!fontHandle) + return NULL; + + if (hwnd) + SendMessage(hwnd, WM_SETFONT, (WPARAM)fontHandle, TRUE); + + return fontHandle; +} +// end_phapppub + // sessmsg VOID PhShowSessionSendMessageDialog( diff --git a/ProcessHacker/resource.h b/ProcessHacker/resource.h index cd3680fce5b1..9d8e082d45af 100644 --- a/ProcessHacker/resource.h +++ b/ProcessHacker/resource.h @@ -121,6 +121,10 @@ #define IDI_PENCIL 218 #define IDI_MAGNIFIER 219 #define IDD_EDITENV 221 +#define IDB_SEARCH_ACTIVE 223 +#define IDB_SEARCH_INACTIVE 224 +#define IDB_SEARCH_ACTIVE_BMP 225 +#define IDB_SEARCH_INACTIVE_BMP 226 #define IDC_TERMINATE 1003 #define IDC_FILEICON 1005 #define IDC_FILE 1006 @@ -738,7 +742,7 @@ // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 223 +#define _APS_NEXT_RESOURCE_VALUE 227 #define _APS_NEXT_COMMAND_VALUE 40295 #define _APS_NEXT_CONTROL_VALUE 1385 #define _APS_NEXT_SYMED_VALUE 169 diff --git a/ProcessHacker/resources/active_search.bmp b/ProcessHacker/resources/active_search.bmp new file mode 100644 index 0000000000000000000000000000000000000000..61b13de9a1152694de72dd81c01c47282773298e GIT binary patch literal 1494 zcmZ?ry~fG_24+A~1Bk_eSOka}8650^YlUPk4#vGuUW6N6R zWNHFQJcaSx|X%2hHw&(QFzR`wykGxlOd1cH4UFR%aZTy0vQ4UK=!p| e$uJ%|jmI2xrFi+H=HLw;0_g|8USwG+hBE*$K{!VM literal 0 HcmV?d00001 diff --git a/ProcessHacker/resources/active_search.png b/ProcessHacker/resources/active_search.png new file mode 100644 index 0000000000000000000000000000000000000000..1cf29576b0b50ed5ee88c1ea8565fe2e9adb9b69 GIT binary patch literal 569 zcmV-90>=G`P)sM}kty8!R#X_B;6=p#3k05!yiVY9d zlP4*H^pRy55Oc`+@ds70n9+mE9;(NrCYe{xn9wV|9VBsU+d(|PXf{(L44hUrH>@-V-11oc);or!AQP^ zGA=1rIynoT>*g-{55qdy^B+mtM4?zjp=AgQmBSj+v@_=Xhhe3lstAxc%pz)8#;6wA zW~r4l^}SZ|wEr*+mw^5uN{4!`dE+8h9B2g+;~9Laf!o+nq2=@QC~4{5 zzNMIgKr``}1C-rcX?bp5HnP>n`l5h>$RZFnesj((%HG>#cy3wt`|HP^U*3CeUNVq- zZ5@_$h2I>YUDuXnAL}xNqidV67y?vA&>V=f-`}3|{{B)38!JhqIau`~3l2ha0LuUq A!~g&Q literal 0 HcmV?d00001 diff --git a/ProcessHacker/resources/inactive_search.png b/ProcessHacker/resources/inactive_search.png new file mode 100644 index 0000000000000000000000000000000000000000..29eaa91305b3de1ce3854f19d86780a552bff734 GIT binary patch literal 755 zcmV;^k2Oj%`vu0L~h9Ndt{Z?B0N*TK5C5_$jUJj2-f3Mf; z=Q4%>h(lx3%*O9D(}M#pG|-AZmB~Y^5Kn3OGXm_qV;y8!p2Ycr{A~&Vh&eaG$uG|C z6Av0_h0HQDGp8TB=MgF`eoUj*zR2Kp69(V&kV6d|aG`-#)NJOFTW(>}f=4uY!z&#( zy!b0FYT$qi4YZzi z!U4p{@mX8WMy*7RX54w@=Gkk?VfutyFI>F1**tDmn1AarCNdTRhz$lqT^w#vqiIjf z++4ek*{XCNwS|Dwx6J)v#I?d`27J0X0K~|N-h&;@?7SR0m@dn1EiEQs_o;`$Fyb>) z{!a}>%}S)Dt6pr_b2g-Y=aI^?%}2xWn%Jm@kdeTRQJW3s_yq*>%`QLV|Bc0r1Qr_O lJMbXX`SgwQ{nsmReE`jH|7l`4W6l5o002ovPDHLkV1naFZkYf8 literal 0 HcmV?d00001 diff --git a/plugins/CommonUtil/searchbox.c b/ProcessHacker/searchbox.c similarity index 59% rename from plugins/CommonUtil/searchbox.c rename to ProcessHacker/searchbox.c index b79ea2096480..c07b6cb2fd7f 100644 --- a/plugins/CommonUtil/searchbox.c +++ b/ProcessHacker/searchbox.c @@ -1,8 +1,8 @@ /* - * Process Hacker CommonUtil Plugin - * Subclassed Edit control + * Process Hacker - + * Searchbox control * - * Copyright (C) 2012-2016 dmex + * Copyright (C) 2012-2017 dmex * * This file is part of Process Hacker. * @@ -21,12 +21,56 @@ * */ -#include "main.h" +#include +#include +#define CINTERFACE +#define COBJMACROS +#include #include #include -#include +#include -VOID NcAreaFreeTheme( +typedef struct _EDIT_CONTEXT +{ + union + { + ULONG Flags; + struct + { + ULONG Hot : 1; + ULONG Pushed : 1; + ULONG Spare : 30; + }; + }; + + LONG CXWidth; + INT CXBorder; + INT ImageWidth; + INT ImageHeight; + HWND WindowHandle; + HFONT WindowFont; + HICON BitmapActive; + HICON BitmapInactive; + HBRUSH BrushNormal; + HBRUSH BrushPushed; + HBRUSH BrushHot; +} EDIT_CONTEXT, *PEDIT_CONTEXT; + +HBITMAP PhpSearchLoadPngImageFromResources( + _In_ PVOID DllBase, + _In_ UINT Width, + _In_ UINT Height, + _In_ PCWSTR Name, + _In_ BOOLEAN RGBAImage + ); + +HICON PhpSearchBitmapToIcon( + _In_ HBITMAP BitmapHandle, + _In_ INT Width, + _In_ INT Height + ); + +VOID PhpSearchFreeTheme( _Inout_ PEDIT_CONTEXT Context ) { @@ -40,17 +84,19 @@ VOID NcAreaFreeTheme( DeleteObject(Context->BrushPushed); } -VOID NcAreaInitializeFont( +VOID PhpSearchInitializeFont( _Inout_ PEDIT_CONTEXT Context ) { - if (Context->WindowFont) DeleteObject(Context->WindowFont); - Context->WindowFont = CommonCreateFont(10, FW_MEDIUM, Context->WindowHandle); + if (Context->WindowFont) + DeleteObject(Context->WindowFont); + + Context->WindowFont = PhCreateCommonFont(10, FW_MEDIUM, Context->WindowHandle); } -VOID NcAreaInitializeTheme( +VOID PhpSearchInitializeTheme( _Inout_ PEDIT_CONTEXT Context -) + ) { Context->CXWidth = PhMultiplyDivide(20, PhGlobalDpi, 96); Context->BrushNormal = GetSysColorBrush(COLOR_WINDOW); @@ -89,42 +135,42 @@ VOID NcAreaInitializeTheme( } } -VOID NcAreaInitializeImages( +VOID PhpSearchInitializeImages( _Inout_ PEDIT_CONTEXT Context -) + ) { HBITMAP bitmap; Context->ImageWidth = GetSystemMetrics(SM_CXSMICON) + 4; Context->ImageHeight = GetSystemMetrics(SM_CYSMICON) + 4; - if (bitmap = LoadImageFromResources(PluginInstance->DllBase, Context->ImageWidth, Context->ImageHeight, MAKEINTRESOURCE(IDB_SEARCH_ACTIVE), TRUE)) + if (bitmap = PhLoadPngImageFromResource(PhInstanceHandle, Context->ImageWidth, Context->ImageHeight, MAKEINTRESOURCE(IDB_SEARCH_ACTIVE), TRUE)) { - Context->BitmapActive = BitmapToIcon(bitmap, Context->ImageWidth, Context->ImageHeight); + Context->BitmapActive = PhpSearchBitmapToIcon(bitmap, Context->ImageWidth, Context->ImageHeight); DeleteObject(bitmap); } - else if (bitmap = LoadImage(PluginInstance->DllBase, MAKEINTRESOURCE(IDB_SEARCH_ACTIVE_BMP), IMAGE_BITMAP, 0, 0, 0)) + else if (bitmap = LoadImage(PhInstanceHandle, MAKEINTRESOURCE(IDB_SEARCH_ACTIVE_BMP), IMAGE_BITMAP, 0, 0, 0)) { - Context->BitmapActive = BitmapToIcon(bitmap, Context->ImageWidth, Context->ImageHeight); + Context->BitmapActive = PhpSearchBitmapToIcon(bitmap, Context->ImageWidth, Context->ImageHeight); DeleteObject(bitmap); } - if (bitmap = LoadImageFromResources(PluginInstance->DllBase, Context->ImageWidth, Context->ImageHeight, MAKEINTRESOURCE(IDB_SEARCH_INACTIVE), TRUE)) + if (bitmap = PhLoadPngImageFromResource(PhInstanceHandle, Context->ImageWidth, Context->ImageHeight, MAKEINTRESOURCE(IDB_SEARCH_INACTIVE), TRUE)) { - Context->BitmapInactive = BitmapToIcon(bitmap, Context->ImageWidth, Context->ImageHeight); + Context->BitmapInactive = PhpSearchBitmapToIcon(bitmap, Context->ImageWidth, Context->ImageHeight); DeleteObject(bitmap); } - else if (bitmap = LoadImage(PluginInstance->DllBase, MAKEINTRESOURCE(IDB_SEARCH_INACTIVE_BMP), IMAGE_BITMAP, 0, 0, 0)) + else if (bitmap = LoadImage(PhInstanceHandle, MAKEINTRESOURCE(IDB_SEARCH_INACTIVE_BMP), IMAGE_BITMAP, 0, 0, 0)) { - Context->BitmapInactive = BitmapToIcon(bitmap, Context->ImageWidth, Context->ImageHeight); + Context->BitmapInactive = PhpSearchBitmapToIcon(bitmap, Context->ImageWidth, Context->ImageHeight); DeleteObject(bitmap); } } -VOID NcAreaGetButtonRect( +VOID PhpSearchGetButtonRect( _Inout_ PEDIT_CONTEXT Context, _Inout_ PRECT ButtonRect -) + ) { ButtonRect->left = (ButtonRect->right - Context->CXWidth) - Context->CXBorder - 1; // offset left border by 1 ButtonRect->bottom -= Context->CXBorder; @@ -132,7 +178,7 @@ VOID NcAreaGetButtonRect( ButtonRect->top += Context->CXBorder; } -VOID NcAreaDrawButton( +VOID PhpSearchDrawButton( _Inout_ PEDIT_CONTEXT Context, _In_ RECT ButtonRect ) @@ -207,14 +253,14 @@ VOID NcAreaDrawButton( ReleaseDC(Context->WindowHandle, hdc); } -LRESULT CALLBACK NcAreaWndSubclassProc( +LRESULT CALLBACK PhpSearchWndSubclassProc( _In_ HWND hWnd, _In_ UINT uMsg, _In_ WPARAM wParam, _In_ LPARAM lParam, _In_ UINT_PTR uIdSubclass, _In_ ULONG_PTR dwRefData -) + ) { PEDIT_CONTEXT context; @@ -224,12 +270,12 @@ LRESULT CALLBACK NcAreaWndSubclassProc( { case WM_NCDESTROY: { - NcAreaFreeTheme(context); + PhpSearchFreeTheme(context); if (context->WindowFont) DeleteObject(context->WindowFont); - RemoveWindowSubclass(hWnd, NcAreaWndSubclassProc, uIdSubclass); + RemoveWindowSubclass(hWnd, PhpSearchWndSubclassProc, uIdSubclass); RemoveProp(hWnd, L"SearchBoxContext"); PhFree(context); } @@ -261,10 +307,10 @@ LRESULT CALLBACK NcAreaWndSubclassProc( OffsetRect(&windowRect, -windowRect.left, -windowRect.top); // Get the position of the inserted button. - NcAreaGetButtonRect(context, &windowRect); + PhpSearchGetButtonRect(context, &windowRect); // Draw the button. - NcAreaDrawButton(context, windowRect); + PhpSearchDrawButton(context, windowRect); } return 0; case WM_NCHITTEST: @@ -280,7 +326,7 @@ LRESULT CALLBACK NcAreaWndSubclassProc( GetWindowRect(hWnd, &windowRect); // Get the position of the inserted button. - NcAreaGetButtonRect(context, &windowRect); + PhpSearchGetButtonRect(context, &windowRect); // Check that the mouse is within the inserted button. if (PtInRect(&windowRect, windowPoint)) @@ -302,7 +348,7 @@ LRESULT CALLBACK NcAreaWndSubclassProc( GetWindowRect(hWnd, &windowRect); // Get the position of the inserted button. - NcAreaGetButtonRect(context, &windowRect); + PhpSearchGetButtonRect(context, &windowRect); // Check that the mouse is within the inserted button. if (PtInRect(&windowRect, windowPoint)) @@ -328,7 +374,7 @@ LRESULT CALLBACK NcAreaWndSubclassProc( GetWindowRect(hWnd, &windowRect); // Get the position of the inserted button. - NcAreaGetButtonRect(context, &windowRect); + PhpSearchGetButtonRect(context, &windowRect); // Check that the mouse is within the inserted button. if (PtInRect(&windowRect, windowPoint)) @@ -362,9 +408,9 @@ LRESULT CALLBACK NcAreaWndSubclassProc( case WM_SYSCOLORCHANGE: case WM_THEMECHANGED: { - NcAreaFreeTheme(context); - NcAreaInitializeTheme(context); - NcAreaInitializeFont(context); + PhpSearchFreeTheme(context); + PhpSearchInitializeTheme(context); + PhpSearchInitializeFont(context); // Reset the client area margins. SendMessage(hWnd, EM_SETMARGINS, EC_LEFTMARGIN, MAKELPARAM(0, 0)); @@ -389,7 +435,7 @@ LRESULT CALLBACK NcAreaWndSubclassProc( GetWindowRect(hWnd, &windowRect); // Get the position of the inserted button. - NcAreaGetButtonRect(context, &windowRect); + PhpSearchGetButtonRect(context, &windowRect); // Check that the mouse is within the inserted button. if (PtInRect(&windowRect, windowPoint) && !context->Hot) @@ -433,7 +479,7 @@ LRESULT CALLBACK NcAreaWndSubclassProc( GetWindowRect(hWnd, &windowRect); // Get the position of the inserted button. - NcAreaGetButtonRect(context, &windowRect); + PhpSearchGetButtonRect(context, &windowRect); // Check that the mouse is within the inserted button. context->Pushed = PtInRect(&windowRect, windowPoint); @@ -447,7 +493,7 @@ LRESULT CALLBACK NcAreaWndSubclassProc( return DefSubclassProc(hWnd, uMsg, wParam, lParam); } -HICON BitmapToIcon( +HICON PhpSearchBitmapToIcon( _In_ HBITMAP BitmapHandle, _In_ INT Width, _In_ INT Height @@ -473,7 +519,7 @@ HICON BitmapToIcon( return icon; } -VOID UtilCreateSearchControl( +VOID PhCreateSearchControl( _In_ HWND Parent, _In_ HWND WindowHandle, _In_ PWSTR BannerText @@ -486,8 +532,8 @@ VOID UtilCreateSearchControl( context->WindowHandle = WindowHandle; - //NcAreaInitializeTheme(context); - NcAreaInitializeImages(context); + //PhpSearchInitializeTheme(context); + PhpSearchInitializeImages(context); // Set initial text Edit_SetCueBannerText(context->WindowHandle, BannerText); @@ -496,8 +542,173 @@ VOID UtilCreateSearchControl( SetProp(context->WindowHandle, L"SearchBoxContext", (HANDLE)context); // Subclass the Edit control window procedure. - SetWindowSubclass(context->WindowHandle, NcAreaWndSubclassProc, 0, (ULONG_PTR)context); + SetWindowSubclass(context->WindowHandle, PhpSearchWndSubclassProc, 0, (ULONG_PTR)context); // Initialize the theme parameters. SendMessage(context->WindowHandle, WM_THEMECHANGED, 0, 0); +} + +HBITMAP PhLoadPngImageFromResource( + _In_ PVOID DllBase, + _In_ UINT Width, + _In_ UINT Height, + _In_ PCWSTR Name, + _In_ BOOLEAN RGBAImage + ) +{ + BOOLEAN success = FALSE; + UINT frameCount = 0; + ULONG resourceLength = 0; + HGLOBAL resourceHandle = NULL; + HRSRC resourceHandleSource = NULL; + WICInProcPointer resourceBuffer = NULL; + HDC screenHdc = NULL; + HDC bufferDc = NULL; + BITMAPINFO bitmapInfo = { 0 }; + HBITMAP bitmapHandle = NULL; + PVOID bitmapBuffer = NULL; + IWICStream* wicStream = NULL; + IWICBitmapSource* wicBitmapSource = NULL; + IWICBitmapDecoder* wicDecoder = NULL; + IWICBitmapFrameDecode* wicFrame = NULL; + IWICImagingFactory* wicFactory = NULL; + IWICBitmapScaler* wicScaler = NULL; + WICPixelFormatGUID pixelFormat; + WICRect rect = { 0, 0, Width, Height }; + + // Create the ImagingFactory + if (FAILED(CoCreateInstance(&CLSID_WICImagingFactory1, NULL, CLSCTX_INPROC_SERVER, &IID_IWICImagingFactory, &wicFactory))) + goto CleanupExit; + + // Find the resource + if ((resourceHandleSource = FindResource(DllBase, Name, L"PNG")) == NULL) + goto CleanupExit; + + // Get the resource length + resourceLength = SizeofResource(DllBase, resourceHandleSource); + + // Load the resource + if ((resourceHandle = LoadResource(DllBase, resourceHandleSource)) == NULL) + goto CleanupExit; + + if ((resourceBuffer = (WICInProcPointer)LockResource(resourceHandle)) == NULL) + goto CleanupExit; + + // Create the Stream + if (FAILED(IWICImagingFactory_CreateStream(wicFactory, &wicStream))) + goto CleanupExit; + + // Initialize the Stream from Memory + if (FAILED(IWICStream_InitializeFromMemory(wicStream, resourceBuffer, resourceLength))) + goto CleanupExit; + + if (FAILED(IWICImagingFactory_CreateDecoder(wicFactory, &GUID_ContainerFormatPng, NULL, &wicDecoder))) + goto CleanupExit; + + if (FAILED(IWICBitmapDecoder_Initialize(wicDecoder, (IStream*)wicStream, WICDecodeMetadataCacheOnLoad))) + goto CleanupExit; + + // Get the Frame count + if (FAILED(IWICBitmapDecoder_GetFrameCount(wicDecoder, &frameCount)) || frameCount < 1) + goto CleanupExit; + + // Get the Frame + if (FAILED(IWICBitmapDecoder_GetFrame(wicDecoder, 0, &wicFrame))) + goto CleanupExit; + + // Get the WicFrame image format + if (FAILED(IWICBitmapFrameDecode_GetPixelFormat(wicFrame, &pixelFormat))) + goto CleanupExit; + + // Check if the image format is supported: + if (IsEqualGUID(&pixelFormat, RGBAImage ? &GUID_WICPixelFormat32bppPRGBA : &GUID_WICPixelFormat32bppPBGRA)) + { + wicBitmapSource = (IWICBitmapSource*)wicFrame; + } + else + { + IWICFormatConverter* wicFormatConverter = NULL; + + if (FAILED(IWICImagingFactory_CreateFormatConverter(wicFactory, &wicFormatConverter))) + goto CleanupExit; + + if (FAILED(IWICFormatConverter_Initialize( + wicFormatConverter, + (IWICBitmapSource*)wicFrame, + RGBAImage ? &GUID_WICPixelFormat32bppPRGBA : &GUID_WICPixelFormat32bppPBGRA, + WICBitmapDitherTypeNone, + NULL, + 0.0, + WICBitmapPaletteTypeCustom + ))) + { + IWICFormatConverter_Release(wicFormatConverter); + goto CleanupExit; + } + + // Convert the image to the correct format: + IWICFormatConverter_QueryInterface(wicFormatConverter, &IID_IWICBitmapSource, &wicBitmapSource); + + // Cleanup the converter. + IWICFormatConverter_Release(wicFormatConverter); + + // Dispose the old frame now that the converted frame is in wicBitmapSource. + IWICBitmapFrameDecode_Release(wicFrame); + } + + bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bitmapInfo.bmiHeader.biWidth = rect.Width; + bitmapInfo.bmiHeader.biHeight = -((LONG)rect.Height); + bitmapInfo.bmiHeader.biPlanes = 1; + bitmapInfo.bmiHeader.biBitCount = 32; + bitmapInfo.bmiHeader.biCompression = BI_RGB; + + screenHdc = CreateIC(L"DISPLAY", NULL, NULL, NULL); + bufferDc = CreateCompatibleDC(screenHdc); + bitmapHandle = CreateDIBSection(screenHdc, &bitmapInfo, DIB_RGB_COLORS, &bitmapBuffer, NULL, 0); + + // Check if it's the same rect as the requested size. + //if (width != rect.Width || height != rect.Height) + if (FAILED(IWICImagingFactory_CreateBitmapScaler(wicFactory, &wicScaler))) + goto CleanupExit; + if (FAILED(IWICBitmapScaler_Initialize(wicScaler, wicBitmapSource, rect.Width, rect.Height, WICBitmapInterpolationModeFant))) + goto CleanupExit; + if (FAILED(IWICBitmapScaler_CopyPixels(wicScaler, &rect, rect.Width * 4, rect.Width * rect.Height * 4, (PBYTE)bitmapBuffer))) + goto CleanupExit; + + success = TRUE; + +CleanupExit: + + if (wicScaler) + IWICBitmapScaler_Release(wicScaler); + + if (bufferDc) + DeleteDC(bufferDc); + + if (screenHdc) + DeleteDC(screenHdc); + + if (wicBitmapSource) + IWICBitmapSource_Release(wicBitmapSource); + + if (wicStream) + IWICStream_Release(wicStream); + + if (wicDecoder) + IWICBitmapDecoder_Release(wicDecoder); + + if (wicFactory) + IWICImagingFactory_Release(wicFactory); + + if (resourceHandle) + FreeResource(resourceHandle); + + if (success) + { + return bitmapHandle; + } + + DeleteObject(bitmapHandle); + return NULL; } \ No newline at end of file diff --git a/plugins/CommonUtil/CommonUtil.vcxproj b/plugins/CommonUtil/CommonUtil.vcxproj index 2f1bb83743f6..c2b017b83820 100644 --- a/plugins/CommonUtil/CommonUtil.vcxproj +++ b/plugins/CommonUtil/CommonUtil.vcxproj @@ -92,8 +92,6 @@ - - @@ -119,11 +117,5 @@ - - - - - - \ No newline at end of file diff --git a/plugins/CommonUtil/CommonUtil.vcxproj.filters b/plugins/CommonUtil/CommonUtil.vcxproj.filters index 4cff34c3c810..83a49f7f2074 100644 --- a/plugins/CommonUtil/CommonUtil.vcxproj.filters +++ b/plugins/CommonUtil/CommonUtil.vcxproj.filters @@ -25,12 +25,6 @@ Source Files - - Source Files - - - Source Files - Source Files @@ -130,20 +124,6 @@ Header Files\json-c - - - Resource Files\Images - - - Resource Files\Images - - - Resource Files\Images - - - Resource Files\Images - - Resource Files diff --git a/plugins/CommonUtil/main.c b/plugins/CommonUtil/main.c index 26bc8af83ebe..ea019c1f52aa 100644 --- a/plugins/CommonUtil/main.c +++ b/plugins/CommonUtil/main.c @@ -27,10 +27,6 @@ PPH_PLUGIN PluginInstance; COMMONUTIL_INTERFACE PluginInterface = { COMMONUTIL_INTERFACE_VERSION, - - UtilCreateSearchControl, - UtilLoadImageFromResources, - UtilCreateJsonParser, UtilCleanupJsonParser, UtilGetJsonValueAsString, diff --git a/plugins/CommonUtil/main.h b/plugins/CommonUtil/main.h index 014638f6d94a..22604b66963c 100644 --- a/plugins/CommonUtil/main.h +++ b/plugins/CommonUtil/main.h @@ -44,46 +44,6 @@ extern PPH_PLUGIN PluginInstance; -typedef struct _EDIT_CONTEXT -{ - union - { - ULONG Flags; - struct - { - ULONG Hot : 1; - ULONG Pushed : 1; - ULONG Spare : 30; - }; - }; - - LONG CXWidth; - INT CXBorder; - INT ImageWidth; - INT ImageHeight; - HWND WindowHandle; - HFONT WindowFont; - HICON BitmapActive; - HICON BitmapInactive; - HBRUSH BrushNormal; - HBRUSH BrushPushed; - HBRUSH BrushHot; -} EDIT_CONTEXT, *PEDIT_CONTEXT; - -VOID UtilCreateSearchControl( - _In_ HWND Parent, - _In_ HWND WindowHandle, - _In_ PWSTR BannerText - ); - -HBITMAP UtilLoadImageFromResources( - _In_ PVOID DllBase, - _In_ UINT Width, - _In_ UINT Height, - _In_ PCWSTR Name, - _In_ BOOLEAN RGBAImage - ); - HICON BitmapToIcon( _In_ HBITMAP BitmapHandle, _In_ INT Width, diff --git a/plugins/CommonUtil/png.c b/plugins/CommonUtil/png.c deleted file mode 100644 index 9ed44280287b..000000000000 --- a/plugins/CommonUtil/png.c +++ /dev/null @@ -1,190 +0,0 @@ -/* - * Process Hacker CommonUtil Plugin - * PNG image control - * - * Copyright (C) 2012-2016 dmex - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - * - */ - -#include "main.h" -#include - -HBITMAP UtilLoadImageFromResources( - _In_ PVOID DllBase, - _In_ UINT Width, - _In_ UINT Height, - _In_ PCWSTR Name, - _In_ BOOLEAN RGBAImage - ) -{ - BOOLEAN success = FALSE; - UINT frameCount = 0; - ULONG resourceLength = 0; - HGLOBAL resourceHandle = NULL; - HRSRC resourceHandleSource = NULL; - WICInProcPointer resourceBuffer = NULL; - HDC screenHdc = NULL; - HDC bufferDc = NULL; - BITMAPINFO bitmapInfo = { 0 }; - HBITMAP bitmapHandle = NULL; - PVOID bitmapBuffer = NULL; - IWICStream* wicStream = NULL; - IWICBitmapSource* wicBitmapSource = NULL; - IWICBitmapDecoder* wicDecoder = NULL; - IWICBitmapFrameDecode* wicFrame = NULL; - IWICImagingFactory* wicFactory = NULL; - IWICBitmapScaler* wicScaler = NULL; - WICPixelFormatGUID pixelFormat; - WICRect rect = { 0, 0, Width, Height }; - - // Create the ImagingFactory - if (FAILED(CoCreateInstance(&CLSID_WICImagingFactory1, NULL, CLSCTX_INPROC_SERVER, &IID_IWICImagingFactory, &wicFactory))) - goto CleanupExit; - - // Find the resource - if ((resourceHandleSource = FindResource(DllBase, Name, L"PNG")) == NULL) - goto CleanupExit; - - // Get the resource length - resourceLength = SizeofResource(DllBase, resourceHandleSource); - - // Load the resource - if ((resourceHandle = LoadResource(DllBase, resourceHandleSource)) == NULL) - goto CleanupExit; - - if ((resourceBuffer = (WICInProcPointer)LockResource(resourceHandle)) == NULL) - goto CleanupExit; - - // Create the Stream - if (FAILED(IWICImagingFactory_CreateStream(wicFactory, &wicStream))) - goto CleanupExit; - - // Initialize the Stream from Memory - if (FAILED(IWICStream_InitializeFromMemory(wicStream, resourceBuffer, resourceLength))) - goto CleanupExit; - - if (FAILED(IWICImagingFactory_CreateDecoder(wicFactory, &GUID_ContainerFormatPng, NULL, &wicDecoder))) - goto CleanupExit; - - if (FAILED(IWICBitmapDecoder_Initialize(wicDecoder, (IStream*)wicStream, WICDecodeMetadataCacheOnLoad))) - goto CleanupExit; - - // Get the Frame count - if (FAILED(IWICBitmapDecoder_GetFrameCount(wicDecoder, &frameCount)) || frameCount < 1) - goto CleanupExit; - - // Get the Frame - if (FAILED(IWICBitmapDecoder_GetFrame(wicDecoder, 0, &wicFrame))) - goto CleanupExit; - - // Get the WicFrame image format - if (FAILED(IWICBitmapFrameDecode_GetPixelFormat(wicFrame, &pixelFormat))) - goto CleanupExit; - - // Check if the image format is supported: - if (IsEqualGUID(&pixelFormat, RGBAImage ? &GUID_WICPixelFormat32bppPRGBA : &GUID_WICPixelFormat32bppPBGRA)) - { - wicBitmapSource = (IWICBitmapSource*)wicFrame; - } - else - { - IWICFormatConverter* wicFormatConverter = NULL; - - if (FAILED(IWICImagingFactory_CreateFormatConverter(wicFactory, &wicFormatConverter))) - goto CleanupExit; - - if (FAILED(IWICFormatConverter_Initialize( - wicFormatConverter, - (IWICBitmapSource*)wicFrame, - RGBAImage ? &GUID_WICPixelFormat32bppPRGBA : &GUID_WICPixelFormat32bppPBGRA, - WICBitmapDitherTypeNone, - NULL, - 0.0, - WICBitmapPaletteTypeCustom - ))) - { - IWICFormatConverter_Release(wicFormatConverter); - goto CleanupExit; - } - - // Convert the image to the correct format: - IWICFormatConverter_QueryInterface(wicFormatConverter, &IID_IWICBitmapSource, &wicBitmapSource); - - // Cleanup the converter. - IWICFormatConverter_Release(wicFormatConverter); - - // Dispose the old frame now that the converted frame is in wicBitmapSource. - IWICBitmapFrameDecode_Release(wicFrame); - } - - bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); - bitmapInfo.bmiHeader.biWidth = rect.Width; - bitmapInfo.bmiHeader.biHeight = -((LONG)rect.Height); - bitmapInfo.bmiHeader.biPlanes = 1; - bitmapInfo.bmiHeader.biBitCount = 32; - bitmapInfo.bmiHeader.biCompression = BI_RGB; - - screenHdc = CreateIC(L"DISPLAY", NULL, NULL, NULL); - bufferDc = CreateCompatibleDC(screenHdc); - bitmapHandle = CreateDIBSection(screenHdc, &bitmapInfo, DIB_RGB_COLORS, &bitmapBuffer, NULL, 0); - - // Check if it's the same rect as the requested size. - //if (width != rect.Width || height != rect.Height) - if (FAILED(IWICImagingFactory_CreateBitmapScaler(wicFactory, &wicScaler))) - goto CleanupExit; - if (FAILED(IWICBitmapScaler_Initialize(wicScaler, wicBitmapSource, rect.Width, rect.Height, WICBitmapInterpolationModeFant))) - goto CleanupExit; - if (FAILED(IWICBitmapScaler_CopyPixels(wicScaler, &rect, rect.Width * 4, rect.Width * rect.Height * 4, (PBYTE)bitmapBuffer))) - goto CleanupExit; - - success = TRUE; - -CleanupExit: - - if (wicScaler) - IWICBitmapScaler_Release(wicScaler); - - if (bufferDc) - DeleteDC(bufferDc); - - if (screenHdc) - DeleteDC(screenHdc); - - if (wicBitmapSource) - IWICBitmapSource_Release(wicBitmapSource); - - if (wicStream) - IWICStream_Release(wicStream); - - if (wicDecoder) - IWICBitmapDecoder_Release(wicDecoder); - - if (wicFactory) - IWICImagingFactory_Release(wicFactory); - - if (resourceHandle) - FreeResource(resourceHandle); - - if (success) - { - return bitmapHandle; - } - - DeleteObject(bitmapHandle); - return NULL; -} \ No newline at end of file diff --git a/plugins/ExtraPlugins/dialog.c b/plugins/ExtraPlugins/dialog.c index c272e21a2e9f..b924fe09d2d9 100644 --- a/plugins/ExtraPlugins/dialog.c +++ b/plugins/ExtraPlugins/dialog.c @@ -239,9 +239,9 @@ INT_PTR CALLBACK CloudPluginsDlgProc( context->SearchHandle = GetDlgItem(hwndDlg, IDC_SEARCHBOX); context->SearchboxText = PhReferenceEmptyString(); - CreateSearchControl(hwndDlg, context->SearchHandle, L"Search Plugins (Ctrl+K)"); - context->NormalFontHandle = CommonCreateFont(-14, FW_NORMAL, NULL); - context->BoldFontHandle = CommonCreateFont(-16, FW_BOLD, NULL); + PhCreateSearchControl(hwndDlg, context->SearchHandle, L"Search Plugins (Ctrl+K)"); + context->NormalFontHandle = PhCreateCommonFont(-14, FW_NORMAL, NULL); + context->BoldFontHandle = PhCreateCommonFont(-16, FW_BOLD, NULL); PhCenterWindow(hwndDlg, PhMainWndHandle); InitializePluginsTree(context, hwndDlg, context->TreeNewHandle); diff --git a/plugins/ExtraPlugins/setup/updater.c b/plugins/ExtraPlugins/setup/updater.c index d3b20ea48b02..a17321e1cc1c 100644 --- a/plugins/ExtraPlugins/setup/updater.c +++ b/plugins/ExtraPlugins/setup/updater.c @@ -735,7 +735,7 @@ LRESULT CALLBACK TaskDialogSubclassProc( // NULL // ); // - // CommonCreateFont(-11, hwndEdit); + // PhCreateCommonFont(-11, hwndEdit); // // // Add text to the window. // SendMessage(hwndEdit, WM_SETTEXT, 0, (LPARAM)L"TEST"); diff --git a/plugins/ExtraPlugins/wndtree.c b/plugins/ExtraPlugins/wndtree.c index 21604c7d70dd..54be25aaa2a8 100644 --- a/plugins/ExtraPlugins/wndtree.c +++ b/plugins/ExtraPlugins/wndtree.c @@ -314,7 +314,7 @@ BOOLEAN NTAPI PluginsTreeNewCallback( { HBITMAP bitmapActive; - if (bitmapActive = LoadImageFromResources(PluginInstance->DllBase, 17, 17, MAKEINTRESOURCE(IDB_SETTINGS_PNG), TRUE)) + if (bitmapActive = PhLoadPngImageFromResource(PluginInstance->DllBase, 17, 17, MAKEINTRESOURCE(IDB_SETTINGS_PNG), TRUE)) { node->Icon = CommonBitmapToIcon(bitmapActive, 17, 17); DeleteObject(bitmapActive); @@ -439,8 +439,8 @@ VOID InitializePluginsTree( Context->TreeNewHandle = TreeNewHandle; PhSetControlTheme(TreeNewHandle, L"explorer"); - Context->NormalFontHandle = CommonCreateFont(-10, FW_NORMAL, NULL); - Context->TitleFontHandle = CommonCreateFont(-14, FW_BOLD, NULL); + Context->NormalFontHandle = PhCreateCommonFont(-10, FW_NORMAL, NULL); + Context->TitleFontHandle = PhCreateCommonFont(-14, FW_BOLD, NULL); TreeNew_SetCallback(TreeNewHandle, PluginsTreeNewCallback, Context); TreeNew_SetRowHeight(TreeNewHandle, 48); diff --git a/plugins/NetworkTools/main.c b/plugins/NetworkTools/main.c index 10922e4581cd..8134d8ed4f8c 100644 --- a/plugins/NetworkTools/main.c +++ b/plugins/NetworkTools/main.c @@ -580,7 +580,7 @@ VOID NTAPI TreeNewMessageCallback( if ((resourceCode = LookupResourceCode(extension->RemoteCountryCode)) != 0) { - if (countryBitmap = LoadImageFromResources(PluginInstance->DllBase, 16, 11, MAKEINTRESOURCE(resourceCode), TRUE)) + if (countryBitmap = PhLoadPngImageFromResource(PluginInstance->DllBase, 16, 11, MAKEINTRESOURCE(resourceCode), TRUE)) { extension->CountryIcon = CommonBitmapToIcon(countryBitmap, 16, 11); } diff --git a/plugins/NetworkTools/nettools.h b/plugins/NetworkTools/nettools.h index a0a36d9222e0..f79de0beb6d7 100644 --- a/plugins/NetworkTools/nettools.h +++ b/plugins/NetworkTools/nettools.h @@ -28,6 +28,7 @@ #define COBJMACROS #include #include +#include #include #include #include diff --git a/plugins/NetworkTools/ping.c b/plugins/NetworkTools/ping.c index c485c8131f33..a971a9c83a86 100644 --- a/plugins/NetworkTools/ping.c +++ b/plugins/NetworkTools/ping.c @@ -295,7 +295,7 @@ INT_PTR CALLBACK NetworkPingWndProc( context->WindowHandle = hwndDlg; context->StatusHandle = GetDlgItem(hwndDlg, IDC_MAINTEXT); context->MaxPingTimeout = PhGetIntegerSetting(SETTING_NAME_PING_MINIMUM_SCALING); - context->FontHandle = CommonCreateFont(-15, FW_MEDIUM, context->StatusHandle); + context->FontHandle = PhCreateCommonFont(-15, FW_MEDIUM, context->StatusHandle); context->PingGraphHandle = CreateWindow( PH_GRAPH_CLASSNAME, NULL, diff --git a/plugins/NetworkTools/tracert.c b/plugins/NetworkTools/tracert.c index 967ede48a701..b1c63a06a26f 100644 --- a/plugins/NetworkTools/tracert.c +++ b/plugins/NetworkTools/tracert.c @@ -579,7 +579,7 @@ INT_PTR CALLBACK TracertDlgProc( context->WindowHandle = hwndDlg; context->TreeNewHandle = GetDlgItem(hwndDlg, IDC_LIST_TRACERT); - context->FontHandle = CommonCreateFont(-15, FW_MEDIUM, GetDlgItem(hwndDlg, IDC_STATUS)); + context->FontHandle = PhCreateCommonFont(-15, FW_MEDIUM, GetDlgItem(hwndDlg, IDC_STATUS)); InitializeTracertTree(context); diff --git a/plugins/NetworkTools/tracetree.c b/plugins/NetworkTools/tracetree.c index 5b7ec58b8463..a8deb46521b9 100644 --- a/plugins/NetworkTools/tracetree.c +++ b/plugins/NetworkTools/tracetree.c @@ -411,7 +411,7 @@ BOOLEAN NTAPI TracertTreeNewCallback( { HBITMAP countryBitmap; - if (countryBitmap = LoadImageFromResources(PluginInstance->DllBase, 16, 11, MAKEINTRESOURCE(resourceCode), TRUE)) + if (countryBitmap = PhLoadPngImageFromResource(PluginInstance->DllBase, 16, 11, MAKEINTRESOURCE(resourceCode), TRUE)) { node->CountryIcon = CommonBitmapToIcon(countryBitmap, 16, 11); } diff --git a/plugins/NetworkTools/whois.c b/plugins/NetworkTools/whois.c index c14a847273f1..4755af27061f 100644 --- a/plugins/NetworkTools/whois.c +++ b/plugins/NetworkTools/whois.c @@ -409,7 +409,7 @@ INT_PTR CALLBACK NetworkOutputDlgProc( SendMessage(context->RichEditHandle, EM_SETEVENTMASK, 0, SendMessage(context->RichEditHandle, EM_GETEVENTMASK, 0, 0) | ENM_LINK); SendMessage(context->RichEditHandle, EM_AUTOURLDETECT, AURL_ENABLEURL, 0); SendMessage(context->RichEditHandle, EM_SETWORDWRAPMODE, WBF_WORDWRAP, 0); - context->FontHandle = CommonCreateFont(-11, FW_MEDIUM, context->RichEditHandle); + context->FontHandle = PhCreateCommonFont(-11, FW_MEDIUM, context->RichEditHandle); PhInitializeLayoutManager(&context->LayoutManager, hwndDlg); PhAddLayoutItem(&context->LayoutManager, context->RichEditHandle, NULL, PH_ANCHOR_ALL); diff --git a/plugins/ToolStatus/searchbox.c b/plugins/ToolStatus/searchbox.c index c23f5f5ba8bc..4cd68dadd33b 100644 --- a/plugins/ToolStatus/searchbox.c +++ b/plugins/ToolStatus/searchbox.c @@ -40,7 +40,7 @@ BOOLEAN CreateSearchboxControl( NULL )) { - CreateSearchControl(RebarHandle, SearchboxHandle, L"Search Processes (Ctrl+K)"); + PhCreateSearchControl(RebarHandle, SearchboxHandle, L"Search Processes (Ctrl+K)"); return TRUE; } diff --git a/plugins/ToolStatus/toolbar.c b/plugins/ToolStatus/toolbar.c index aeadee129653..d5609cda8848 100644 --- a/plugins/ToolStatus/toolbar.c +++ b/plugins/ToolStatus/toolbar.c @@ -442,7 +442,7 @@ HBITMAP ToolbarGetImage( if (ToolStatusConfig.ModernIcons) { - toolbarBitmap = LoadImageFromResources(PluginInstance->DllBase, ToolBarImageSize.cx, ToolBarImageSize.cy, MAKEINTRESOURCE(IDB_ARROW_REFRESH_MODERN), FALSE); + toolbarBitmap = PhLoadPngImageFromResource(PluginInstance->DllBase, ToolBarImageSize.cx, ToolBarImageSize.cy, MAKEINTRESOURCE(IDB_ARROW_REFRESH_MODERN), FALSE); } else { @@ -458,7 +458,7 @@ HBITMAP ToolbarGetImage( if (ToolStatusConfig.ModernIcons) { - toolbarBitmap = LoadImageFromResources(PluginInstance->DllBase, ToolBarImageSize.cx, ToolBarImageSize.cy, MAKEINTRESOURCE(IDB_COG_EDIT_MODERN), FALSE); + toolbarBitmap = PhLoadPngImageFromResource(PluginInstance->DllBase, ToolBarImageSize.cx, ToolBarImageSize.cy, MAKEINTRESOURCE(IDB_COG_EDIT_MODERN), FALSE); } else { @@ -474,7 +474,7 @@ HBITMAP ToolbarGetImage( if (ToolStatusConfig.ModernIcons) { - toolbarBitmap = LoadImageFromResources(PluginInstance->DllBase, ToolBarImageSize.cx, ToolBarImageSize.cy, MAKEINTRESOURCE(IDB_FIND_MODERN), FALSE); + toolbarBitmap = PhLoadPngImageFromResource(PluginInstance->DllBase, ToolBarImageSize.cx, ToolBarImageSize.cy, MAKEINTRESOURCE(IDB_FIND_MODERN), FALSE); } else { @@ -490,7 +490,7 @@ HBITMAP ToolbarGetImage( if (ToolStatusConfig.ModernIcons) { - toolbarBitmap = LoadImageFromResources(PluginInstance->DllBase, ToolBarImageSize.cx, ToolBarImageSize.cy, MAKEINTRESOURCE(IDB_CHART_LINE_MODERN), FALSE); + toolbarBitmap = PhLoadPngImageFromResource(PluginInstance->DllBase, ToolBarImageSize.cx, ToolBarImageSize.cy, MAKEINTRESOURCE(IDB_CHART_LINE_MODERN), FALSE); } else { @@ -506,7 +506,7 @@ HBITMAP ToolbarGetImage( if (ToolStatusConfig.ModernIcons) { - toolbarBitmap = LoadImageFromResources(PluginInstance->DllBase, ToolBarImageSize.cx, ToolBarImageSize.cy, MAKEINTRESOURCE(IDB_APPLICATION_MODERN), FALSE); + toolbarBitmap = PhLoadPngImageFromResource(PluginInstance->DllBase, ToolBarImageSize.cx, ToolBarImageSize.cy, MAKEINTRESOURCE(IDB_APPLICATION_MODERN), FALSE); } else { @@ -522,7 +522,7 @@ HBITMAP ToolbarGetImage( if (ToolStatusConfig.ModernIcons) { - toolbarBitmap = LoadImageFromResources(PluginInstance->DllBase, ToolBarImageSize.cx, ToolBarImageSize.cy, MAKEINTRESOURCE(IDB_APPLICATION_GO_MODERN), FALSE); + toolbarBitmap = PhLoadPngImageFromResource(PluginInstance->DllBase, ToolBarImageSize.cx, ToolBarImageSize.cy, MAKEINTRESOURCE(IDB_APPLICATION_GO_MODERN), FALSE); } else { @@ -538,7 +538,7 @@ HBITMAP ToolbarGetImage( if (ToolStatusConfig.ModernIcons) { - toolbarBitmap = LoadImageFromResources(PluginInstance->DllBase, ToolBarImageSize.cx, ToolBarImageSize.cy, MAKEINTRESOURCE(IDB_CROSS_MODERN), FALSE); + toolbarBitmap = PhLoadPngImageFromResource(PluginInstance->DllBase, ToolBarImageSize.cx, ToolBarImageSize.cy, MAKEINTRESOURCE(IDB_CROSS_MODERN), FALSE); } else { @@ -554,7 +554,7 @@ HBITMAP ToolbarGetImage( if (ToolStatusConfig.ModernIcons) { - toolbarBitmap = LoadImageFromResources(PluginInstance->DllBase, ToolBarImageSize.cx, ToolBarImageSize.cy, MAKEINTRESOURCE(IDB_APPLICATION_GET_MODERN), FALSE); + toolbarBitmap = PhLoadPngImageFromResource(PluginInstance->DllBase, ToolBarImageSize.cx, ToolBarImageSize.cy, MAKEINTRESOURCE(IDB_APPLICATION_GET_MODERN), FALSE); } else { @@ -570,7 +570,7 @@ HBITMAP ToolbarGetImage( if (ToolStatusConfig.ModernIcons) { - toolbarBitmap = LoadImageFromResources(PluginInstance->DllBase, ToolBarImageSize.cx, ToolBarImageSize.cy, MAKEINTRESOURCE(IDB_POWER_MODERN), FALSE); + toolbarBitmap = PhLoadPngImageFromResource(PluginInstance->DllBase, ToolBarImageSize.cx, ToolBarImageSize.cy, MAKEINTRESOURCE(IDB_POWER_MODERN), FALSE); } else { diff --git a/plugins/ToolStatus/toolstatus.h b/plugins/ToolStatus/toolstatus.h index 1bf451bf28f0..45b08fd9f807 100644 --- a/plugins/ToolStatus/toolstatus.h +++ b/plugins/ToolStatus/toolstatus.h @@ -28,6 +28,7 @@ #define COBJMACROS #define INITGUID #include +#include #include #include #include diff --git a/plugins/Updater/updater.c b/plugins/Updater/updater.c index 4742288974d8..d910e02f6d94 100644 --- a/plugins/Updater/updater.c +++ b/plugins/Updater/updater.c @@ -1165,7 +1165,7 @@ LRESULT CALLBACK TaskDialogSubclassProc( // NULL // ); // - // CommonCreateFont(-11, hwndEdit); + // PhCreateCommonFont(-11, hwndEdit); // // // Add text to the window. // SendMessage(hwndEdit, WM_SETTEXT, 0, (LPARAM)L"TEST"); diff --git a/plugins/WindowExplorer/wnddlg.c b/plugins/WindowExplorer/wnddlg.c index 030850942bb2..189d52ea3ea9 100644 --- a/plugins/WindowExplorer/wnddlg.c +++ b/plugins/WindowExplorer/wnddlg.c @@ -353,7 +353,7 @@ INT_PTR CALLBACK WepWindowsDlgProc( SetWindowText(hwndDlg, PH_AUTO_T(PH_STRING, WepGetWindowTitleForSelector(&context->Selector))->Buffer); - CreateSearchControl(hwndDlg, context->SearchBoxHandle, L"Search Windows (Ctrl+K)"); + PhCreateSearchControl(hwndDlg, context->SearchBoxHandle, L"Search Windows (Ctrl+K)"); WeInitializeWindowTree(hwndDlg, context->TreeNewHandle, &context->TreeContext); @@ -788,7 +788,7 @@ INT_PTR CALLBACK WepWindowsPageProc( context->TreeNewHandle = GetDlgItem(hwndDlg, IDC_LIST); context->SearchBoxHandle = GetDlgItem(hwndDlg, IDC_SEARCHEDIT); - CreateSearchControl(hwndDlg, context->SearchBoxHandle, L"Search Windows (Ctrl+K)"); + PhCreateSearchControl(hwndDlg, context->SearchBoxHandle, L"Search Windows (Ctrl+K)"); WeInitializeWindowTree(hwndDlg, context->TreeNewHandle, &context->TreeContext); diff --git a/plugins/WindowExplorer/wndexp.h b/plugins/WindowExplorer/wndexp.h index 804350ae9030..05c330d571b8 100644 --- a/plugins/WindowExplorer/wndexp.h +++ b/plugins/WindowExplorer/wndexp.h @@ -2,6 +2,7 @@ #define WNDEXP_H #include +#include #include "wndtree.h" extern BOOLEAN IsHookClient; diff --git a/plugins/include/commonutil.h b/plugins/include/commonutil.h index 737d9328b42f..a6e265992413 100644 --- a/plugins/include/commonutil.h +++ b/plugins/include/commonutil.h @@ -27,20 +27,6 @@ #define COMMONUTIL_PLUGIN_NAME L"ProcessHacker.CommonUtil" #define COMMONUTIL_INTERFACE_VERSION 1 -typedef VOID (NTAPI *PUTIL_CREATE_SEARCHBOX_CONTROL)( - _In_ HWND Parent, - _In_ HWND WindowHandle, - _In_ PWSTR BannerText - ); - -typedef HBITMAP (NTAPI *PUTIL_CREATE_IMAGE_FROM_RESOURCE)( - _In_ PVOID DllBase, - _In_ UINT Width, - _In_ UINT Height, - _In_ PCWSTR Name, - _In_ BOOLEAN RGBAImage - ); - typedef PVOID (NTAPI *PUTIL_CREATE_JSON_PARSER)( _In_ PSTR JsonString ); @@ -123,10 +109,6 @@ typedef PPH_LIST (NTAPI *PUTIL_GET_JSON_OBJECT_ARRAY_LIST)( typedef struct _COMMONUTIL_INTERFACE { ULONG Version; - - PUTIL_CREATE_SEARCHBOX_CONTROL CreateSearchControl; - PUTIL_CREATE_IMAGE_FROM_RESOURCE CreateImageFromResource; - PUTIL_CREATE_JSON_PARSER CreateJsonParser; PUTIL_CLEANUP_JSON_PARSER CleanupJsonParser; PUTIL_GET_JSON_VALUE_STRING GetJsonValueAsString; @@ -145,65 +127,6 @@ typedef struct _COMMONUTIL_INTERFACE PUTIL_GET_JSON_OBJECT_ARRAY_LIST JsonGetObjectArrayList; } COMMONUTIL_INTERFACE, *P_COMMONUTIL_INTERFACE; -FORCEINLINE -VOID -CreateSearchControl( - _In_ HWND Parent, - _In_ HWND WindowHandle, - _In_ PWSTR BannerText - ) -{ - PPH_PLUGIN toolStatusPlugin; - - if (toolStatusPlugin = PhFindPlugin(COMMONUTIL_PLUGIN_NAME)) - { - P_COMMONUTIL_INTERFACE Interface; - - if (Interface = PhGetPluginInformation(toolStatusPlugin)->Interface) - { - if (Interface->Version <= COMMONUTIL_INTERFACE_VERSION) - { - Interface->CreateSearchControl(Parent, WindowHandle, BannerText); - } - } - } -} - -FORCEINLINE -HBITMAP LoadImageFromResources( - _In_ PVOID DllBase, - _In_ UINT Width, - _In_ UINT Height, - _In_ PCWSTR Name, - _In_ BOOLEAN RGBAImage - ) -{ - static PUTIL_CREATE_IMAGE_FROM_RESOURCE createImageFromResource = NULL; - - if (!createImageFromResource) - { - PPH_PLUGIN toolStatusPlugin; - - if (toolStatusPlugin = PhFindPlugin(COMMONUTIL_PLUGIN_NAME)) - { - P_COMMONUTIL_INTERFACE Interface; - - if (Interface = PhGetPluginInformation(toolStatusPlugin)->Interface) - { - if (Interface->Version <= COMMONUTIL_INTERFACE_VERSION) - { - createImageFromResource = Interface->CreateImageFromResource; - } - } - } - } - - if (createImageFromResource) - return createImageFromResource(DllBase, Width, Height, Name, RGBAImage); - else - return NULL; -} - FORCEINLINE PVOID CreateJsonParser( @@ -646,46 +569,6 @@ FormatAnsiString( return FormatAnsiString_V(Format, argptr); } -FORCEINLINE -HFONT -CommonCreateFont( - _In_ LONG Size, - _In_ INT Weight, - _In_opt_ HWND hwnd - ) -{ - LOGFONT logFont; - - if (SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(LOGFONT), &logFont, 0)) - { - HFONT fontHandle = CreateFont( - -PhMultiplyDivideSigned(Size, PhGlobalDpi, 72), - 0, - 0, - 0, - Weight, - FALSE, - FALSE, - FALSE, - ANSI_CHARSET, - OUT_DEFAULT_PRECIS, - CLIP_DEFAULT_PRECIS, - CLEARTYPE_QUALITY | ANTIALIASED_QUALITY, - DEFAULT_PITCH, - logFont.lfFaceName - ); - - if (hwnd) - { - SendMessage(hwnd, WM_SETFONT, (WPARAM)fontHandle, TRUE); - } - - return fontHandle; - } - - return NULL; -} - FORCEINLINE HFONT CommonDuplicateFont( From e4f3ee8cc03e282d093f4e327f5ef75bf390f181 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 26 Apr 2017 00:49:38 +1000 Subject: [PATCH 0005/2058] Add process properties handle searching, Add splitter control for resizing process properties > token groups/privileges controls --- .gitignore | 1 + CHANGELOG.txt | 1 + ProcessHacker/ProcessHacker.rc | 21 +- ProcessHacker/ProcessHacker.vcxproj | 1 + ProcessHacker/ProcessHacker.vcxproj.filters | 3 + ProcessHacker/findobj.c | 2 + ProcessHacker/hndllist.c | 59 ++--- ProcessHacker/include/appsup.h | 67 +++++ ProcessHacker/include/hndllist.h | 9 +- ProcessHacker/include/procprpp.h | 4 + ProcessHacker/prpghndl.c | 127 ++++++++- ProcessHacker/prpgtok.c | 22 -- ProcessHacker/resource.h | 5 +- ProcessHacker/searchbox.c | 15 +- ProcessHacker/splitter.c | 275 ++++++++++++++++++++ ProcessHacker/tokprp.c | 43 ++- 16 files changed, 571 insertions(+), 84 deletions(-) create mode 100644 ProcessHacker/splitter.c diff --git a/.gitignore b/.gitignore index 1a44e8b91e28..d8d3deaf0cc8 100644 --- a/.gitignore +++ b/.gitignore @@ -102,6 +102,7 @@ Desktop.ini build/installer/*.exe ProcessHacker/sdk/phapppub.h +ProcessHacker/include/phapprev.h plugins-extra/ /sdk/ diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 561d9aacd6a2..493211cc7e7d 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -3,6 +3,7 @@ Process Hacker 3.0 * HIGHLIGHTS: * New Process Hacker setup. + * New process properties handle search. * Added F11 hotkey for fullscreen System Information window. * OTHER CHANGES: * Updated Updater plugin: diff --git a/ProcessHacker/ProcessHacker.rc b/ProcessHacker/ProcessHacker.rc index 6b3a616f4b86..db1968f60b85 100644 --- a/ProcessHacker/ProcessHacker.rc +++ b/ProcessHacker/ProcessHacker.rc @@ -603,6 +603,7 @@ FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN CONTROL "Hide unnamed handles",IDC_HIDEUNNAMEDHANDLES,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,7,88,10 CONTROL "",IDC_LIST,"PhTreeNew",WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP | 0x2,7,21,246,232,WS_EX_CLIENTEDGE + EDITTEXT IDC_HANDLESEARCH,110,4,143,14,ES_AUTOHSCROLL END IDD_PROCENVIRONMENT DIALOGEX 0, 0, 260, 260 @@ -723,7 +724,7 @@ CAPTION "Find Handles or DLLs" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN LTEXT "Filter:",IDC_STATIC,7,9,20,8 - EDITTEXT IDC_FILTER,32,8,223,12,ES_AUTOHSCROLL + EDITTEXT IDC_FILTER,32,8,224,14,ES_AUTOHSCROLL PUSHBUTTON "Find",IDOK,300,7,50,14 CONTROL "",IDC_RESULTS,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,26,343,200 CONTROL "&Regex",IDC_REGEX,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,261,9,36,10 @@ -746,8 +747,8 @@ BEGIN LTEXT "Unknown",IDC_VIRTUALIZED,209,29,44,8 LTEXT "App container SID:",IDC_STATIC,7,40,62,8 EDITTEXT IDC_APPCONTAINERSID,75,40,178,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER - CONTROL "",IDC_GROUPS,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,53,246,84 - CONTROL "",IDC_PRIVILEGES,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,142,246,83 + CONTROL "",IDC_GROUPS,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,53,246,112 + CONTROL "",IDC_PRIVILEGES,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,168,246,57 LTEXT "To view capabilities, claims and other attributes, click Advanced.",IDC_INSTRUCTION,7,228,206,8 PUSHBUTTON "Integrity",IDC_INTEGRITY,149,239,50,14 PUSHBUTTON "Advanced",IDC_ADVANCED,203,239,50,14 @@ -2508,8 +2509,11 @@ END // IDB_CROSS BITMAP "resources\\cross.bmp" + IDB_TICK BITMAP "resources\\tick.bmp" + IDB_SEARCH_ACTIVE_BMP BITMAP "resources\\active_search.bmp" + IDB_SEARCH_INACTIVE_BMP BITMAP "resources\\inactive_search.bmp" @@ -2591,6 +2595,16 @@ BEGIN 0 END +IDD_PROCHANDLES AFX_DIALOG_LAYOUT +BEGIN + 0 +END + +IDD_OBJTOKEN AFX_DIALOG_LAYOUT +BEGIN + 0 +END + ///////////////////////////////////////////////////////////////////////////// // @@ -2598,6 +2612,7 @@ END // IDB_SEARCH_ACTIVE PNG "resources\\active_search.png" + IDB_SEARCH_INACTIVE PNG "resources\\inactive_search.png" #endif // English (Australia) resources diff --git a/ProcessHacker/ProcessHacker.vcxproj b/ProcessHacker/ProcessHacker.vcxproj index 10b281657fd7..c2e557e676dc 100644 --- a/ProcessHacker/ProcessHacker.vcxproj +++ b/ProcessHacker/ProcessHacker.vcxproj @@ -334,6 +334,7 @@ + diff --git a/ProcessHacker/ProcessHacker.vcxproj.filters b/ProcessHacker/ProcessHacker.vcxproj.filters index 6b6d551e6e04..fbed89f82328 100644 --- a/ProcessHacker/ProcessHacker.vcxproj.filters +++ b/ProcessHacker/ProcessHacker.vcxproj.filters @@ -411,6 +411,9 @@ Process Hacker + + Process Hacker + diff --git a/ProcessHacker/findobj.c b/ProcessHacker/findobj.c index 98c68b117ee3..182f4055e882 100644 --- a/ProcessHacker/findobj.c +++ b/ProcessHacker/findobj.c @@ -218,6 +218,8 @@ static INT_PTR CALLBACK PhpFindObjectsDlgProc( PhCenterWindow(hwndDlg, GetParent(hwndDlg)); PhFindObjectsListViewHandle = lvHandle = GetDlgItem(hwndDlg, IDC_RESULTS); + PhCreateSearchControl(hwndDlg, GetDlgItem(hwndDlg, IDC_FILTER), NULL); + PhInitializeLayoutManager(&WindowLayoutManager, hwndDlg); PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDC_FILTER), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); diff --git a/ProcessHacker/hndllist.c b/ProcessHacker/hndllist.c index 0f6de031b6a6..c34947dd9502 100644 --- a/ProcessHacker/hndllist.c +++ b/ProcessHacker/hndllist.c @@ -109,6 +109,8 @@ VOID PhInitializeHandleList( TreeNew_SetSort(hwnd, 0, AscendingSortOrder); PhCmInitializeManager(&Context->Cm, hwnd, PHHNTLC_MAXIMUM, PhpHandleTreeNewPostSortFunction); + + PhInitializeTreeNewFilterSupport(&Context->TreeFilterSupport, hwnd, Context->NodeList); } VOID PhDeleteHandleList( @@ -177,39 +179,9 @@ VOID PhSetOptionsHandleList( _In_ BOOLEAN HideUnnamedHandles ) { - ULONG i; - BOOLEAN modified; - if (Context->HideUnnamedHandles != HideUnnamedHandles) { Context->HideUnnamedHandles = HideUnnamedHandles; - - modified = FALSE; - - for (i = 0; i < Context->NodeList->Count; i++) - { - PPH_HANDLE_NODE node = Context->NodeList->Items[i]; - BOOLEAN visible; - - visible = TRUE; - - if (HideUnnamedHandles && PhIsNullOrEmptyString(node->HandleItem->BestObjectName)) - visible = FALSE; - - if (node->Node.Visible != visible) - { - node->Node.Visible = visible; - modified = TRUE; - - if (!visible) - node->Node.Selected = FALSE; - } - } - - if (modified) - { - TreeNew_NodesStructured(Context->TreeNewHandle); - } } } @@ -248,8 +220,8 @@ PPH_HANDLE_NODE PhAddHandleNode( PhAddEntryHashtable(Context->NodeHashtable, &handleNode); PhAddItemList(Context->NodeList, handleNode); - if (Context->HideUnnamedHandles && PhIsNullOrEmptyString(HandleItem->BestObjectName)) - handleNode->Node.Visible = FALSE; + if (Context->TreeFilterSupport.FilterList) + handleNode->Node.Visible = PhApplyTreeNewFiltersToNode(&Context->TreeFilterSupport, &handleNode->Node); PhEmCallObjectOperation(EmHandleNodeType, handleNode, EmObjectCreate); @@ -346,6 +318,29 @@ VOID PhUpdateHandleNode( TreeNew_NodesStructured(Context->TreeNewHandle); } +VOID PhExpandAllHandleNodes( + _In_ PPH_HANDLE_LIST_CONTEXT Context, + _In_ BOOLEAN Expand + ) +{ + ULONG i; + BOOLEAN needsRestructure = FALSE; + + for (i = 0; i < Context->NodeList->Count; i++) + { + PPH_HANDLE_NODE node = Context->NodeList->Items[i]; + + if (node->Node.Expanded != Expand) + { + node->Node.Expanded = Expand; + needsRestructure = TRUE; + } + } + + if (needsRestructure) + TreeNew_NodesStructured(Context->TreeNewHandle); +} + VOID PhTickHandleNodes( _In_ PPH_HANDLE_LIST_CONTEXT Context ) diff --git a/ProcessHacker/include/appsup.h b/ProcessHacker/include/appsup.h index e631485c30b9..27912c57b459 100644 --- a/ProcessHacker/include/appsup.h +++ b/ProcessHacker/include/appsup.h @@ -499,4 +499,71 @@ FORCEINLINE PVOID PhpGenericPropertyPageHeader( #define SWP_SHOWWINDOW_ONLY (SWP_NO_ACTIVATE_MOVE_SIZE_ZORDER | SWP_SHOWWINDOW) #define SWP_HIDEWINDOW_ONLY (SWP_NO_ACTIVATE_MOVE_SIZE_ZORDER | SWP_HIDEWINDOW) +// splitter + +typedef struct _PH_HSPLITTER_CONTEXT +{ + union + { + ULONG Flags; + struct + { + ULONG Hot : 1; + ULONG Pushed : 1; + ULONG Moved : 1; + ULONG DragMode : 1; + ULONG Spare : 28; + }; + }; + + ULONG Height; + PH_LAYOUT_MANAGER LayoutManager; + PPH_LAYOUT_ITEM Topitem; + PPH_LAYOUT_ITEM Bottomitem; +} PH_HSPLITTER_CONTEXT, *PPH_HSPLITTER_CONTEXT; + +PPH_HSPLITTER_CONTEXT PhInitializeHSplitterSupport( + _In_ HWND Parent, + _In_ HWND TopChild, + _In_ HWND BottomChild + ); + +VOID PhDeleteHSplitterSupportSupport( + _Inout_ PPH_HSPLITTER_CONTEXT Context + ); + +VOID PhHSplitterHandleWmSize( + _Inout_ PPH_HSPLITTER_CONTEXT Context, + _In_ INT Width, + _In_ INT Height + ); + +VOID PhHSplitterHandleLButtonDown( + _Inout_ PPH_HSPLITTER_CONTEXT Context, + _In_ HWND hwnd, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +VOID PhHSplitterHandleLButtonUp( + _Inout_ PPH_HSPLITTER_CONTEXT Context, + _In_ HWND hwnd, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +VOID PhHSplitterHandleMouseMove( + _Inout_ PPH_HSPLITTER_CONTEXT Context, + _In_ HWND hwnd, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +VOID PhHSplitterHandleMouseLeave( + _Inout_ PPH_HSPLITTER_CONTEXT Context, + _In_ HWND hwnd, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + #endif diff --git a/ProcessHacker/include/hndllist.h b/ProcessHacker/include/hndllist.h index 579b06ced3a2..4d7a1c8a555f 100644 --- a/ProcessHacker/include/hndllist.h +++ b/ProcessHacker/include/hndllist.h @@ -43,14 +43,16 @@ typedef struct _PH_HANDLE_LIST_CONTEXT HWND ParentWindowHandle; HWND TreeNewHandle; ULONG TreeNewSortColumn; + PH_TN_FILTER_SUPPORT TreeFilterSupport; PH_SORT_ORDER TreeNewSortOrder; PH_CM_MANAGER Cm; - BOOLEAN HideUnnamedHandles; PPH_HASHTABLE NodeHashtable; PPH_LIST NodeList; BOOLEAN EnableStateHighlighting; + BOOLEAN HideUnnamedHandles; + PPH_POINTER_LIST NodeStateList; } PH_HANDLE_LIST_CONTEXT, *PPH_HANDLE_LIST_CONTEXT; @@ -98,6 +100,11 @@ VOID PhUpdateHandleNode( _In_ PPH_HANDLE_NODE HandleNode ); +VOID PhExpandAllHandleNodes( + _In_ PPH_HANDLE_LIST_CONTEXT Context, + _In_ BOOLEAN Expand + ); + VOID PhTickHandleNodes( _In_ PPH_HANDLE_LIST_CONTEXT Context ); diff --git a/ProcessHacker/include/procprpp.h b/ProcessHacker/include/procprpp.h index ffa14bee1e82..64149e5078b4 100644 --- a/ProcessHacker/include/procprpp.h +++ b/ProcessHacker/include/procprpp.h @@ -255,6 +255,7 @@ typedef struct _PH_HANDLES_CONTEXT PH_CALLBACK_REGISTRATION UpdatedEventRegistration; HWND WindowHandle; + HWND SearchboxHandle; // end_phapppub union @@ -271,6 +272,9 @@ typedef struct _PH_HANDLES_CONTEXT BOOLEAN SelectedHandleInherit; NTSTATUS LastRunStatus; PPH_STRING ErrorMessage; + + PPH_STRING SearchboxText; + PPH_TN_FILTER_ENTRY FilterEntry; // begin_phapppub } PH_HANDLES_CONTEXT, *PPH_HANDLES_CONTEXT; // end_phapppub diff --git a/ProcessHacker/prpghndl.c b/ProcessHacker/prpghndl.c index fe7dc80849fb..ada104e8e0b3 100644 --- a/ProcessHacker/prpghndl.c +++ b/ProcessHacker/prpghndl.c @@ -208,6 +208,78 @@ VOID PhShowHandleContextMenu( PhFree(handles); } +static BOOLEAN PhpWordMatchHandleStringRef( + _In_ PPH_STRING SearchText, + _In_ PPH_STRINGREF Text + ) +{ + PH_STRINGREF part; + PH_STRINGREF remainingPart; + + remainingPart = SearchText->sr; + + while (remainingPart.Length) + { + PhSplitStringRefAtChar(&remainingPart, '|', &part, &remainingPart); + + if (part.Length) + { + if (PhFindStringInStringRef(Text, &part, TRUE) != -1) + return TRUE; + } + } + + return FALSE; +} + +static BOOLEAN PhpWordMatchHandleStringZ( + _In_ PPH_STRING SearchText, + _In_ PWSTR Text + ) +{ + PH_STRINGREF text; + + PhInitializeStringRef(&text, Text); + + return PhpWordMatchHandleStringRef(SearchText, &text); +} + +BOOLEAN PhpHandleTreeFilterCallback( + _In_ PPH_TREENEW_NODE Node, + _In_opt_ PVOID Context + ) +{ + PPH_HANDLES_CONTEXT handlesContext = Context; + PPH_HANDLE_NODE processNode = (PPH_HANDLE_NODE)Node; + PPH_HANDLE_ITEM handleItem = processNode->HandleItem; + + if (handlesContext->ListContext.HideUnnamedHandles && PhIsNullOrEmptyString(handleItem->BestObjectName)) + return FALSE; + + if (PhIsNullOrEmptyString(handlesContext->SearchboxText)) + return TRUE; + + if (!PhIsNullOrEmptyString(handleItem->TypeName)) + { + if (PhpWordMatchHandleStringRef(handlesContext->SearchboxText, &handleItem->TypeName->sr)) + return TRUE; + } + + if (!PhIsNullOrEmptyString(handleItem->ObjectName)) + { + if (PhpWordMatchHandleStringRef(handlesContext->SearchboxText, &handleItem->ObjectName->sr)) + return TRUE; + } + + if (!PhIsNullOrEmptyString(handleItem->BestObjectName)) + { + if (PhpWordMatchHandleStringRef(handlesContext->SearchboxText, &handleItem->BestObjectName->sr)) + return TRUE; + } + + return FALSE; +} + INT_PTR CALLBACK PhpProcessHandlesDlgProc( _In_ HWND hwndDlg, _In_ UINT uMsg, @@ -276,6 +348,9 @@ INT_PTR CALLBACK PhpProcessHandlesDlgProc( ); handlesContext->WindowHandle = hwndDlg; + handlesContext->SearchboxHandle = GetDlgItem(hwndDlg, IDC_HANDLESEARCH); + PhCreateSearchControl(hwndDlg, handlesContext->SearchboxHandle, L"Search Handles (Ctrl+K)"); + // Initialize the list. tnHandle = GetDlgItem(hwndDlg, IDC_LIST); BringWindowToTop(tnHandle); @@ -284,6 +359,8 @@ INT_PTR CALLBACK PhpProcessHandlesDlgProc( PhInitializeProviderEventQueue(&handlesContext->EventQueue, 100); handlesContext->LastRunStatus = -1; handlesContext->ErrorMessage = NULL; + handlesContext->SearchboxText = PhReferenceEmptyString(); + handlesContext->FilterEntry = PhAddTreeNewFilter(&handlesContext->ListContext.TreeFilterSupport, PhpHandleTreeFilterCallback, handlesContext); PhEmCallObjectOperation(EmHandlesContextType, handlesContext, EmObjectCreate); @@ -353,11 +430,10 @@ INT_PTR CALLBACK PhpProcessHandlesDlgProc( if (!propPageContext->LayoutInitialized) { PPH_LAYOUT_ITEM dialogItem; - - dialogItem = PhAddPropPageLayoutItem(hwndDlg, hwndDlg, - PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL); - PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_LIST), - dialogItem, PH_ANCHOR_ALL); + + dialogItem = PhAddPropPageLayoutItem(hwndDlg, hwndDlg, PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL); + PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_HANDLESEARCH), dialogItem, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); + PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_LIST), dialogItem, PH_ANCHOR_ALL); PhDoPropPageLayout(hwndDlg); @@ -367,9 +443,35 @@ INT_PTR CALLBACK PhpProcessHandlesDlgProc( break; case WM_COMMAND: { - INT id = LOWORD(wParam); + switch (GET_WM_COMMAND_CMD(wParam, lParam)) + { + case EN_CHANGE: + { + PPH_STRING newSearchboxText; + + if (GET_WM_COMMAND_HWND(wParam, lParam) != handlesContext->SearchboxHandle) + break; + + newSearchboxText = PhGetWindowText(handlesContext->SearchboxHandle); + + if (!PhEqualString(handlesContext->SearchboxText, newSearchboxText, FALSE)) + { + // Cache the current search text for our callback. + PhMoveReference(&handlesContext->SearchboxText, newSearchboxText); + + if (!PhIsNullOrEmptyString(handlesContext->SearchboxText)) + { + // Expand any hidden nodes to make search results visible. + PhExpandAllHandleNodes(&handlesContext->ListContext, TRUE); + } - switch (id) + PhApplyTreeNewFilters(&handlesContext->ListContext.TreeFilterSupport); + } + } + break; + } + + switch (GET_WM_COMMAND_ID(wParam, lParam)) { case ID_SHOWCONTEXTMENU: { @@ -409,9 +511,9 @@ INT_PTR CALLBACK PhpProcessHandlesDlgProc( // Toggle the appropriate bit. - if (id == ID_HANDLE_PROTECTED) + if (GET_WM_COMMAND_ID(wParam, lParam) == ID_HANDLE_PROTECTED) attributes ^= OBJ_PROTECT_CLOSE; - else if (id == ID_HANDLE_INHERIT) + else if (GET_WM_COMMAND_ID(wParam, lParam) == ID_HANDLE_INHERIT) attributes ^= OBJ_INHERIT; PhReferenceObject(handleItem); @@ -434,7 +536,7 @@ INT_PTR CALLBACK PhpProcessHandlesDlgProc( info.TypeName = handleItem->TypeName; info.BestObjectName = handleItem->BestObjectName; - if (id == ID_HANDLE_OBJECTPROPERTIES1) + if (GET_WM_COMMAND_ID(wParam, lParam) == ID_HANDLE_OBJECTPROPERTIES1) PhShowHandleObjectProperties1(hwndDlg, &info); else PhShowHandleObjectProperties2(hwndDlg, &info); @@ -467,9 +569,10 @@ INT_PTR CALLBACK PhpProcessHandlesDlgProc( BOOLEAN hide; hide = Button_GetCheck(GetDlgItem(hwndDlg, IDC_HIDEUNNAMEDHANDLES)) == BST_CHECKED; - - PhSetIntegerSetting(L"HideUnnamedHandles", hide); + + PhSetIntegerSetting(L"HideUnnamedHandles", hide); PhSetOptionsHandleList(&handlesContext->ListContext, hide); + PhApplyTreeNewFilters(&handlesContext->ListContext.TreeFilterSupport); } break; } diff --git a/ProcessHacker/prpgtok.c b/ProcessHacker/prpgtok.c index 2f8ec1cfe583..d6de9b5eaf9f 100644 --- a/ProcessHacker/prpgtok.c +++ b/ProcessHacker/prpgtok.c @@ -65,8 +65,6 @@ INT_PTR CALLBACK PhpProcessTokenHookProc( if (!GetProp(hwndDlg, PhMakeContextAtom())) // LayoutInitialized { PPH_LAYOUT_ITEM dialogItem; - HWND groupsLv; - HWND privilegesLv; // This is a big violation of abstraction... @@ -80,10 +78,6 @@ INT_PTR CALLBACK PhpProcessTokenHookProc( dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_APPCONTAINERSID), dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); - PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_GROUPS), - dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); - PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_PRIVILEGES), - dialogItem, PH_ANCHOR_ALL); PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_INSTRUCTION), dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_BOTTOM); PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_INTEGRITY), @@ -93,22 +87,6 @@ INT_PTR CALLBACK PhpProcessTokenHookProc( PhDoPropPageLayout(hwndDlg); - groupsLv = GetDlgItem(hwndDlg, IDC_GROUPS); - privilegesLv = GetDlgItem(hwndDlg, IDC_PRIVILEGES); - - if (ListView_GetItemCount(groupsLv) != 0) - { - ListView_SetColumnWidth(groupsLv, 0, LVSCW_AUTOSIZE); - ExtendedListView_SetColumnWidth(groupsLv, 1, ELVSCW_AUTOSIZE_REMAININGSPACE); - } - - if (ListView_GetItemCount(privilegesLv) != 0) - { - ListView_SetColumnWidth(privilegesLv, 0, LVSCW_AUTOSIZE); - ListView_SetColumnWidth(privilegesLv, 1, LVSCW_AUTOSIZE); - ExtendedListView_SetColumnWidth(privilegesLv, 2, ELVSCW_AUTOSIZE_REMAININGSPACE); - } - SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)TRUE); } } diff --git a/ProcessHacker/resource.h b/ProcessHacker/resource.h index 9d8e082d45af..ce6d174476b4 100644 --- a/ProcessHacker/resource.h +++ b/ProcessHacker/resource.h @@ -532,6 +532,7 @@ #define IDC_DELETE 1382 #define IDC_EDIT 1383 #define IDC_NEW 1384 +#define IDC_HANDLESEARCH 1385 #define ID_MAINWND_PROCESSTL 2001 #define ID_MAINWND_SERVICETL 2002 #define ID_MAINWND_NETWORKTL 2003 @@ -742,9 +743,9 @@ // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 227 +#define _APS_NEXT_RESOURCE_VALUE 228 #define _APS_NEXT_COMMAND_VALUE 40295 -#define _APS_NEXT_CONTROL_VALUE 1385 +#define _APS_NEXT_CONTROL_VALUE 1387 #define _APS_NEXT_SYMED_VALUE 169 #endif #endif diff --git a/ProcessHacker/searchbox.c b/ProcessHacker/searchbox.c index c07b6cb2fd7f..4cc1c8e132af 100644 --- a/ProcessHacker/searchbox.c +++ b/ProcessHacker/searchbox.c @@ -56,14 +56,6 @@ typedef struct _EDIT_CONTEXT HBRUSH BrushHot; } EDIT_CONTEXT, *PEDIT_CONTEXT; -HBITMAP PhpSearchLoadPngImageFromResources( - _In_ PVOID DllBase, - _In_ UINT Width, - _In_ UINT Height, - _In_ PCWSTR Name, - _In_ BOOLEAN RGBAImage - ); - HICON PhpSearchBitmapToIcon( _In_ HBITMAP BitmapHandle, _In_ INT Width, @@ -91,7 +83,7 @@ VOID PhpSearchInitializeFont( if (Context->WindowFont) DeleteObject(Context->WindowFont); - Context->WindowFont = PhCreateCommonFont(10, FW_MEDIUM, Context->WindowHandle); + Context->WindowFont = PhCreateCommonFont(PH_SCALE_DPI(10), FW_MEDIUM, Context->WindowHandle); } VOID PhpSearchInitializeTheme( @@ -522,7 +514,7 @@ HICON PhpSearchBitmapToIcon( VOID PhCreateSearchControl( _In_ HWND Parent, _In_ HWND WindowHandle, - _In_ PWSTR BannerText + _In_opt_ PWSTR BannerText ) { PEDIT_CONTEXT context; @@ -536,7 +528,8 @@ VOID PhCreateSearchControl( PhpSearchInitializeImages(context); // Set initial text - Edit_SetCueBannerText(context->WindowHandle, BannerText); + if (BannerText) + Edit_SetCueBannerText(context->WindowHandle, BannerText); // Set our window context data. SetProp(context->WindowHandle, L"SearchBoxContext", (HANDLE)context); diff --git a/ProcessHacker/splitter.c b/ProcessHacker/splitter.c new file mode 100644 index 000000000000..23682b89c28d --- /dev/null +++ b/ProcessHacker/splitter.c @@ -0,0 +1,275 @@ +/* + * Process Hacker - + * Splitter control + * + * Copyright (C) 2017 dmex + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + * + */ + +#include +#include +#include + +static INT nSplitterPos = 250; +static INT nSplitterBorder = 6; +static INT SplitterOffset = -4; + +VOID DrawXorBar(HDC hdc, INT x1, INT y1, INT width, INT height); + +PPH_HSPLITTER_CONTEXT PhInitializeHSplitterSupport( + _In_ HWND Parent, + _In_ HWND TopChild, + _In_ HWND BottomChild + ) +{ + PPH_HSPLITTER_CONTEXT context; + + context = PhAllocate(sizeof(PH_HSPLITTER_CONTEXT)); + memset(context, 0, sizeof(PH_HSPLITTER_CONTEXT)); + + PhInitializeLayoutManager(&context->LayoutManager, Parent); + + context->Topitem = PhAddLayoutItem(&context->LayoutManager, TopChild, NULL, PH_ANCHOR_ALL); + context->Bottomitem = PhAddLayoutItem(&context->LayoutManager, BottomChild, NULL, PH_ANCHOR_ALL); + + return context; +} + +VOID PhDeleteHSplitterSupportSupport( + _Inout_ PPH_HSPLITTER_CONTEXT Context + ) +{ + PhDeleteLayoutManager(&Context->LayoutManager); +} + +VOID PhHSplitterHandleWmSize( + _Inout_ PPH_HSPLITTER_CONTEXT Context, + _In_ INT Width, + _In_ INT Height + ) +{ + // HACK: Use the PH layout manager as the 'splitter' control by abusing layout margins. + + // Set the bottom margin of the top control. + Context->Topitem->Margin.bottom = Height - nSplitterPos - nSplitterBorder; + + // Set the top margin of the bottom control. + Context->Bottomitem->Margin.top = nSplitterPos + nSplitterBorder * 2; + + PhLayoutManagerLayout(&Context->LayoutManager); +} + +VOID PhHSplitterHandleLButtonDown( + _Inout_ PPH_HSPLITTER_CONTEXT Context, + _In_ HWND hwnd, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + POINT pt; + HDC hdc; + RECT rect; + + pt.x = GET_X_LPARAM(lParam); + pt.y = GET_Y_LPARAM(lParam); + + GetWindowRect(hwnd, &rect); + ClientToScreen(hwnd, &pt); + + pt.x -= rect.left; + pt.y -= rect.top; + + // Adjust the coordinates (start from 0,0). + OffsetRect(&rect, -rect.left, -rect.top); + + if (pt.y < 0) + pt.y = 0; + if (pt.y > rect.bottom - 4) + pt.y = rect.bottom - 4; + + Context->DragMode = TRUE; + + SetCapture(hwnd); + + hdc = GetWindowDC(hwnd); + DrawXorBar(hdc, 1, pt.y - 2, rect.right - 2, 4); + ReleaseDC(hwnd, hdc); + + SplitterOffset = pt.y; +} + +VOID PhHSplitterHandleLButtonUp( + _Inout_ PPH_HSPLITTER_CONTEXT Context, + _In_ HWND hwnd, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + HDC hdc; + RECT rect; + POINT pt; + + pt.x = GET_X_LPARAM(lParam); + pt.y = GET_Y_LPARAM(lParam); + + if (Context->DragMode == FALSE) + return; + + GetWindowRect(hwnd, &rect); + ClientToScreen(hwnd, &pt); + + pt.x -= rect.left; + pt.y -= rect.top; + + // Adjust the coordinates (start from 0,0). + OffsetRect(&rect, -rect.left, -rect.top); + + if (pt.y < 0) + pt.y = 0; + if (pt.y > rect.bottom - 4) + pt.y = rect.bottom - 4; + + hdc = GetWindowDC(hwnd); + DrawXorBar(hdc, 1, SplitterOffset - 2, rect.right - 2, 4); + ReleaseDC(hwnd, hdc); + + SplitterOffset = pt.y; + + Context->DragMode = FALSE; + + GetWindowRect(hwnd, &rect); + + pt.x += rect.left; + pt.y += rect.top; + + ScreenToClient(hwnd, &pt); + GetClientRect(hwnd, &rect); + + nSplitterPos = pt.y; + + // position the child controls + PhHSplitterHandleWmSize(Context, rect.right, rect.bottom); + + ReleaseCapture(); +} + +VOID PhHSplitterHandleMouseMove( + _Inout_ PPH_HSPLITTER_CONTEXT Context, + _In_ HWND hwnd, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + HDC hdc; + RECT windowRect; + POINT windowPoint; + + //if (Context->DragMode == FALSE) + // return; + + windowPoint.x = GET_X_LPARAM(lParam); + windowPoint.y = GET_Y_LPARAM(lParam); + + GetWindowRect(hwnd, &windowRect); + ClientToScreen(hwnd, &windowPoint); + + windowPoint.x -= windowRect.left; + windowPoint.y -= windowRect.top; + + OffsetRect(&windowRect, -windowRect.left, -windowRect.top); + + if (windowPoint.y < 0) + windowPoint.y = 0; + if (windowPoint.y > windowRect.bottom - 4) + windowPoint.y = windowRect.bottom - 4; + + if (windowPoint.y != SplitterOffset) + { + hdc = GetWindowDC(hwnd); + + if (wParam & MK_LBUTTON) + { + DrawXorBar(hdc, 1, SplitterOffset - 2, windowRect.right - 2, 4); + DrawXorBar(hdc, 1, windowPoint.y - 2, windowRect.right - 2, 4); + } + else + { + //if (!Context->Hot) + { + TRACKMOUSEEVENT trackMouseEvent; + + trackMouseEvent.cbSize = sizeof(TRACKMOUSEEVENT); + trackMouseEvent.dwFlags = TME_LEAVE; + trackMouseEvent.hwndTrack = hwnd; + trackMouseEvent.dwHoverTime = 0; + + Context->Hot = TRUE; + + SetCursor(LoadCursor(NULL, IDC_SIZENS)); + + TrackMouseEvent(&trackMouseEvent); + } + } + + ReleaseDC(hwnd, hdc); + SplitterOffset = windowPoint.y; + } +} + +VOID PhHSplitterHandleMouseLeave( + _Inout_ PPH_HSPLITTER_CONTEXT Context, + _In_ HWND hwnd, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + if (Context->Hot) + { + Context->Hot = FALSE; + + // Reset the original cursor. + SetCursor(LoadCursor(NULL, IDC_ARROW)); + } +} + +// http://www.catch22.net/tuts/splitter-windows +VOID DrawXorBar(HDC hdc, INT x1, INT y1, INT width, INT height) +{ + static WORD _dotPatternBmp[8] = + { + 0x00aa, 0x0055, 0x00aa, 0x0055, + 0x00aa, 0x0055, 0x00aa, 0x0055 + }; + + HBITMAP hbm; + HBRUSH hbr, hbrushOld; + + hbm = CreateBitmap(8, 8, 1, 1, _dotPatternBmp); + hbr = CreatePatternBrush(hbm); + + SetBrushOrgEx(hdc, x1, y1, 0); + hbrushOld = (HBRUSH)SelectObject(hdc, hbr); + + PatBlt(hdc, x1, y1, width, height, PATINVERT); + + SelectObject(hdc, hbrushOld); + + DeleteObject(hbr); + DeleteObject(hbm); +} + diff --git a/ProcessHacker/tokprp.c b/ProcessHacker/tokprp.c index c973169123ce..034d6c65d1bb 100644 --- a/ProcessHacker/tokprp.c +++ b/ProcessHacker/tokprp.c @@ -50,6 +50,7 @@ typedef struct _TOKEN_PAGE_CONTEXT HWND GroupsListViewHandle; HWND PrivilegesListViewHandle; + PPH_HSPLITTER_CONTEXT HSplitterContext; PTOKEN_GROUPS Groups; PTOKEN_PRIVILEGES Privileges; @@ -423,6 +424,12 @@ INT_PTR CALLBACK PhpTokenPageProc( PhSetControlTheme(groupsLv, L"explorer"); PhSetControlTheme(privilegesLv, L"explorer"); + tokenPageContext->HSplitterContext = PhInitializeHSplitterSupport( + hwndDlg, + tokenPageContext->GroupsListViewHandle, + tokenPageContext->PrivilegesListViewHandle + ); + PhAddListViewColumn(groupsLv, 0, 0, 0, LVCFMT_LEFT, 160, L"Name"); PhAddListViewColumn(groupsLv, 1, 1, 1, LVCFMT_LEFT, 200, L"Flags"); @@ -432,7 +439,6 @@ INT_PTR CALLBACK PhpTokenPageProc( PhSetExtendedListView(groupsLv); ExtendedListView_SetItemColorFunction(groupsLv, PhpTokenGroupColorFunction); - PhSetExtendedListView(privilegesLv); ExtendedListView_SetItemColorFunction(privilegesLv, PhpTokenPrivilegeColorFunction); @@ -576,6 +582,19 @@ INT_PTR CALLBACK PhpTokenPageProc( ExtendedListView_SortItems(privilegesLv); } + if (ListView_GetItemCount(groupsLv) != 0) + { + ListView_SetColumnWidth(groupsLv, 0, LVSCW_AUTOSIZE); + ExtendedListView_SetColumnWidth(groupsLv, 1, ELVSCW_AUTOSIZE_REMAININGSPACE); + } + + if (ListView_GetItemCount(privilegesLv) != 0) + { + ListView_SetColumnWidth(privilegesLv, 0, LVSCW_AUTOSIZE); + ListView_SetColumnWidth(privilegesLv, 1, LVSCW_AUTOSIZE); + ExtendedListView_SetColumnWidth(privilegesLv, 2, ELVSCW_AUTOSIZE_REMAININGSPACE); + } + NtClose(tokenHandle); } } @@ -584,6 +603,7 @@ INT_PTR CALLBACK PhpTokenPageProc( { if (tokenPageContext->Groups) PhFree(tokenPageContext->Groups); if (tokenPageContext->Privileges) PhFree(tokenPageContext->Privileges); + if (tokenPageContext->HSplitterContext) PhDeleteHSplitterSupportSupport(tokenPageContext->HSplitterContext); } break; case WM_COMMAND: @@ -917,6 +937,27 @@ INT_PTR CALLBACK PhpTokenPageProc( } } break; + case WM_SIZE: + PhHSplitterHandleWmSize(tokenPageContext->HSplitterContext, LOWORD(lParam), HIWORD(lParam)); + return 0; + case WM_LBUTTONDOWN: + PhHSplitterHandleLButtonDown(tokenPageContext->HSplitterContext, hwndDlg, wParam, lParam); + return 0; + case WM_LBUTTONUP: + PhHSplitterHandleLButtonUp(tokenPageContext->HSplitterContext, hwndDlg, wParam, lParam); + return 0; + case WM_MOUSEMOVE: + PhHSplitterHandleMouseMove(tokenPageContext->HSplitterContext, hwndDlg, wParam, lParam); + return 0; + case WM_NCMOUSELEAVE: + { + //if (context->Hot) + { + //context->Hot = FALSE; + //RedrawWindow(hWnd, NULL, NULL, RDW_FRAME | RDW_INVALIDATE); + } + } + break; } REFLECT_MESSAGE_DLG(hwndDlg, tokenPageContext->GroupsListViewHandle, uMsg, wParam, lParam); From fe9e9ea84c28aa2e37b69d406b7c034c5ae1c3ed Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 26 Apr 2017 01:04:54 +1000 Subject: [PATCH 0006/2058] Update gitattributes --- .gitattributes | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/.gitattributes b/.gitattributes index 31335b861e1d..1f89c58b64ff 100644 --- a/.gitattributes +++ b/.gitattributes @@ -9,6 +9,19 @@ *.fsproj merge=union *.dbproj merge=union +# Project files +*.bat eol=crlf +*.c eol=crlf +*.config eol=crlf +*.cmd eol=crlf +*.csproj eol=crlf +*.h eol=crlf +*.manifest eol=crlf +*.rc eol=crlf +*.sln eol=crlf +*.txt eol=crlf +*.vcxproj eol=crlf + # Standard to msysgit *.doc diff=astextplain *.DOC diff=astextplain From 2a9ed627eb3121542e685cd310822441e7cb8155 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 26 Apr 2017 01:22:38 +1000 Subject: [PATCH 0007/2058] Updater: Make nightly builds the default branch --- plugins/Updater/Updater.rc | 293 +++-- plugins/Updater/main.c | 279 ++-- plugins/Updater/options.c | 148 +-- plugins/Updater/page3.c | 48 +- plugins/Updater/page4.c | 9 +- plugins/Updater/page5.c | 91 +- plugins/Updater/resource.h | 35 +- plugins/Updater/updater.c | 2508 +++++++++++++++++------------------- plugins/Updater/updater.h | 443 +++---- plugins/Updater/verify.c | 38 +- 10 files changed, 1861 insertions(+), 2031 deletions(-) diff --git a/plugins/Updater/Updater.rc b/plugins/Updater/Updater.rc index 163e82bf6de4..3819a0a7ca80 100644 --- a/plugins/Updater/Updater.rc +++ b/plugins/Updater/Updater.rc @@ -1,147 +1,146 @@ -// Microsoft Visual C++ generated resource script. -// -#include "resource.h" - -#define APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// -#include "winres.h" - -///////////////////////////////////////////////////////////////////////////// -#undef APSTUDIO_READONLY_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -// English (Australia) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENA) -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_AUS -#pragma code_page(1252) - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -1 TEXTINCLUDE -BEGIN - "resource.h\0" -END - -2 TEXTINCLUDE -BEGIN - "#include ""winres.h""\r\n" - "\0" -END - -3 TEXTINCLUDE -BEGIN - "\r\n" - "\0" -END - -#endif // APSTUDIO_INVOKED - - -///////////////////////////////////////////////////////////////////////////// -// -// Version -// - -VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,0,0,0 - PRODUCTVERSION 2,0,0,0 - FILEFLAGSMASK 0x3fL -#ifdef _DEBUG - FILEFLAGS 0x1L -#else - FILEFLAGS 0x0L -#endif - FILEOS 0x40004L - FILETYPE 0x2L - FILESUBTYPE 0x0L -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "0c0904b0" - BEGIN - VALUE "CompanyName", "dmex" - VALUE "FileDescription", "Update checker plugin for Process Hacker" - VALUE "FileVersion", "2.0" - VALUE "InternalName", "ProcessHacker.UpdateChecker" - VALUE "LegalCopyright", "Licensed under the GNU GPL, v3." - VALUE "OriginalFilename", "Updater.dll" - VALUE "ProductName", "Update checker plugin for Process Hacker" - VALUE "ProductVersion", "2.0" - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0xc09, 1200 - END -END - - -///////////////////////////////////////////////////////////////////////////// -// -// Dialog -// - -IDD_OPTIONS DIALOGEX 0, 0, 215, 54 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Updater Options" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - CONTROL "Check for updates automatically",IDC_AUTOCHECKBOX, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,7,142,10 - DEFPUSHBUTTON "Close",IDCANCEL,158,33,50,14 - CONTROL "Check for nightly builds",IDC_NIGHTLY,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,19,142,10 -END - - -///////////////////////////////////////////////////////////////////////////// -// -// DESIGNINFO -// - -#ifdef APSTUDIO_INVOKED -GUIDELINES DESIGNINFO -BEGIN - IDD_OPTIONS, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 208 - TOPMARGIN, 7 - BOTTOMMARGIN, 47 - END -END -#endif // APSTUDIO_INVOKED - - -///////////////////////////////////////////////////////////////////////////// -// -// AFX_DIALOG_LAYOUT -// - -IDD_OPTIONS AFX_DIALOG_LAYOUT -BEGIN - 0 -END - -#endif // English (Australia) resources -///////////////////////////////////////////////////////////////////////////// - - - -#ifndef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// - - -///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED - +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "winres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (Australia) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENA) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_AUS +#pragma code_page(1252) + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""winres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 2,0,0,0 + PRODUCTVERSION 2,0,0,0 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "0c0904b0" + BEGIN + VALUE "CompanyName", "dmex" + VALUE "FileDescription", "Update checker plugin for Process Hacker" + VALUE "FileVersion", "2.0" + VALUE "InternalName", "ProcessHacker.UpdateChecker" + VALUE "LegalCopyright", "Licensed under the GNU GPL, v3." + VALUE "OriginalFilename", "Updater.dll" + VALUE "ProductName", "Update checker plugin for Process Hacker" + VALUE "ProductVersion", "2.0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0xc09, 1200 + END +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_OPTIONS DIALOGEX 0, 0, 215, 54 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Updater Options" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + CONTROL "Check for updates automatically",IDC_AUTOCHECKBOX, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,7,142,10 + DEFPUSHBUTTON "Close",IDCANCEL,158,33,50,14 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_OPTIONS, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 208 + TOPMARGIN, 7 + BOTTOMMARGIN, 47 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// AFX_DIALOG_LAYOUT +// + +IDD_OPTIONS AFX_DIALOG_LAYOUT +BEGIN + 0 +END + +#endif // English (Australia) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/plugins/Updater/main.c b/plugins/Updater/main.c index 31095e0052cb..a6a73649f820 100644 --- a/plugins/Updater/main.c +++ b/plugins/Updater/main.c @@ -1,143 +1,138 @@ -/* - * Process Hacker Plugins - - * Update Checker Plugin - * - * Copyright (C) 2011-2016 dmex - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include "updater.h" - -PPH_PLUGIN PluginInstance; -PH_CALLBACK_REGISTRATION PluginMenuItemCallbackRegistration; -PH_CALLBACK_REGISTRATION MainMenuInitializingCallbackRegistration; -PH_CALLBACK_REGISTRATION MainWindowShowingCallbackRegistration; -PH_CALLBACK_REGISTRATION PluginShowOptionsCallbackRegistration; - -VOID NTAPI MainWindowShowingCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - // Check if the user want's us to auto-check for updates. - if (PhGetIntegerSetting(SETTING_NAME_AUTO_CHECK)) - { - // All good, queue up our update check. - StartInitialCheck(); - } -} - -VOID NTAPI MainMenuInitializingCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - PPH_PLUGIN_MENU_INFORMATION menuInfo = Parameter; - - // Check this menu is the Help menu - if (menuInfo->u.MainMenu.SubMenuIndex != 4) - return; - - PhInsertEMenuItem(menuInfo->Menu, PhPluginCreateEMenuItem(PluginInstance, 0, UPDATE_MENUITEM, L"Check for updates", NULL), 0); -} - -VOID NTAPI MenuItemCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - PPH_PLUGIN_MENU_ITEM menuItem = Parameter; - - if (menuItem && menuItem->Id == UPDATE_MENUITEM) - { - ShowUpdateDialog(NULL); - } -} - -VOID NTAPI ShowOptionsCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - ShowOptionsDialog((HWND)Parameter); -} - -LOGICAL DllMain( - _In_ HINSTANCE Instance, - _In_ ULONG Reason, - _Reserved_ PVOID Reserved - ) -{ - switch (Reason) - { - case DLL_PROCESS_ATTACH: - { - PPH_PLUGIN_INFORMATION info; - PH_SETTING_CREATE settings[] = - { - { IntegerSettingType, SETTING_NAME_AUTO_CHECK, L"1" }, - { StringSettingType, SETTING_NAME_LAST_CHECK, L"0" }, -#ifdef VIRUSTOTAL_API - { IntegerSettingType, SETTING_NAME_NIGHTLY_BUILD, L"1" } -#else - { IntegerSettingType, SETTING_NAME_NIGHTLY_BUILD, L"0" } -#endif - }; - - PluginInstance = PhRegisterPlugin(PLUGIN_NAME, Instance, &info); - - if (!PluginInstance) - return FALSE; - - info->DisplayName = L"Update Checker"; - info->Author = L"dmex"; - info->Description = L"Plugin for checking new Process Hacker releases via the Help menu."; - info->Url = L"https://wj32.org/processhacker/forums/viewtopic.php?t=1121"; - info->HasOptions = TRUE; - - PhRegisterCallback( - PhGetGeneralCallback(GeneralCallbackMainWindowShowing), - MainWindowShowingCallback, - NULL, - &MainWindowShowingCallbackRegistration - ); - PhRegisterCallback( - PhGetGeneralCallback(GeneralCallbackMainMenuInitializing), - MainMenuInitializingCallback, - NULL, - &MainMenuInitializingCallbackRegistration - ); - PhRegisterCallback( - PhGetPluginCallback(PluginInstance, PluginCallbackMenuItem), - MenuItemCallback, - NULL, - &PluginMenuItemCallbackRegistration - ); - PhRegisterCallback( - PhGetPluginCallback(PluginInstance, PluginCallbackShowOptions), - ShowOptionsCallback, - NULL, - &PluginShowOptionsCallbackRegistration - ); - - PhAddSettings(settings, ARRAYSIZE(settings)); - } - break; - } - - return TRUE; +/* + * Process Hacker Plugins - + * Update Checker Plugin + * + * Copyright (C) 2011-2016 dmex + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include "updater.h" + +PPH_PLUGIN PluginInstance; +PH_CALLBACK_REGISTRATION PluginMenuItemCallbackRegistration; +PH_CALLBACK_REGISTRATION MainMenuInitializingCallbackRegistration; +PH_CALLBACK_REGISTRATION MainWindowShowingCallbackRegistration; +PH_CALLBACK_REGISTRATION PluginShowOptionsCallbackRegistration; + +VOID NTAPI MainWindowShowingCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + // Check if the user want's us to auto-check for updates. + if (PhGetIntegerSetting(SETTING_NAME_AUTO_CHECK)) + { + // All good, queue up our update check. + StartInitialCheck(); + } +} + +VOID NTAPI MainMenuInitializingCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + PPH_PLUGIN_MENU_INFORMATION menuInfo = Parameter; + + // Check this menu is the Help menu + if (menuInfo->u.MainMenu.SubMenuIndex != 4) + return; + + PhInsertEMenuItem(menuInfo->Menu, PhPluginCreateEMenuItem(PluginInstance, 0, UPDATE_MENUITEM, L"Check for updates", NULL), 0); +} + +VOID NTAPI MenuItemCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + PPH_PLUGIN_MENU_ITEM menuItem = Parameter; + + if (menuItem && menuItem->Id == UPDATE_MENUITEM) + { + ShowUpdateDialog(NULL); + } +} + +VOID NTAPI ShowOptionsCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + ShowOptionsDialog((HWND)Parameter); +} + +LOGICAL DllMain( + _In_ HINSTANCE Instance, + _In_ ULONG Reason, + _Reserved_ PVOID Reserved + ) +{ + switch (Reason) + { + case DLL_PROCESS_ATTACH: + { + PPH_PLUGIN_INFORMATION info; + PH_SETTING_CREATE settings[] = + { + { IntegerSettingType, SETTING_NAME_AUTO_CHECK, L"1" }, + { StringSettingType, SETTING_NAME_LAST_CHECK, L"0" }, + }; + + PluginInstance = PhRegisterPlugin(PLUGIN_NAME, Instance, &info); + + if (!PluginInstance) + return FALSE; + + info->DisplayName = L"Update Checker"; + info->Author = L"dmex"; + info->Description = L"Plugin for checking new Process Hacker releases via the Help menu."; + info->Url = L"https://wj32.org/processhacker/forums/viewtopic.php?t=1121"; + info->HasOptions = TRUE; + + PhRegisterCallback( + PhGetGeneralCallback(GeneralCallbackMainWindowShowing), + MainWindowShowingCallback, + NULL, + &MainWindowShowingCallbackRegistration + ); + PhRegisterCallback( + PhGetGeneralCallback(GeneralCallbackMainMenuInitializing), + MainMenuInitializingCallback, + NULL, + &MainMenuInitializingCallbackRegistration + ); + PhRegisterCallback( + PhGetPluginCallback(PluginInstance, PluginCallbackMenuItem), + MenuItemCallback, + NULL, + &PluginMenuItemCallbackRegistration + ); + PhRegisterCallback( + PhGetPluginCallback(PluginInstance, PluginCallbackShowOptions), + ShowOptionsCallback, + NULL, + &PluginShowOptionsCallbackRegistration + ); + + PhAddSettings(settings, ARRAYSIZE(settings)); + } + break; + } + + return TRUE; } \ No newline at end of file diff --git a/plugins/Updater/options.c b/plugins/Updater/options.c index 1d3d06de2cf5..cbef57deb360 100644 --- a/plugins/Updater/options.c +++ b/plugins/Updater/options.c @@ -1,78 +1,72 @@ -/* - * Process Hacker Plugins - - * Update Checker Plugin - * - * Copyright (C) 2011-2016 dmex - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include "updater.h" - -INT_PTR CALLBACK OptionsDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - switch (uMsg) - { - case WM_INITDIALOG: - { - PhCenterWindow(hwndDlg, GetParent(hwndDlg)); - - if (PhGetIntegerSetting(SETTING_NAME_AUTO_CHECK)) - Button_SetCheck(GetDlgItem(hwndDlg, IDC_AUTOCHECKBOX), BST_CHECKED); - - if (PhGetIntegerSetting(SETTING_NAME_NIGHTLY_BUILD)) - Button_SetCheck(GetDlgItem(hwndDlg, IDC_NIGHTLY), BST_CHECKED); - } - break; - case WM_COMMAND: - { - switch (GET_WM_COMMAND_ID(wParam, lParam)) - { - case IDCANCEL: - { - PhSetIntegerSetting(SETTING_NAME_AUTO_CHECK, - Button_GetCheck(GetDlgItem(hwndDlg, IDC_AUTOCHECKBOX)) == BST_CHECKED); - - PhSetIntegerSetting(SETTING_NAME_NIGHTLY_BUILD, - Button_GetCheck(GetDlgItem(hwndDlg, IDC_NIGHTLY)) == BST_CHECKED); - - EndDialog(hwndDlg, IDCANCEL); - } - break; - } - } - break; - } - - return FALSE; -} - -VOID ShowOptionsDialog( - _In_opt_ HWND Parent - ) -{ - DialogBox( - PluginInstance->DllBase, - MAKEINTRESOURCE(IDD_OPTIONS), - Parent, - OptionsDlgProc - ); +/* + * Process Hacker Plugins - + * Update Checker Plugin + * + * Copyright (C) 2011-2016 dmex + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include "updater.h" + +INT_PTR CALLBACK OptionsDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + switch (uMsg) + { + case WM_INITDIALOG: + { + PhCenterWindow(hwndDlg, GetParent(hwndDlg)); + + if (PhGetIntegerSetting(SETTING_NAME_AUTO_CHECK)) + Button_SetCheck(GetDlgItem(hwndDlg, IDC_AUTOCHECKBOX), BST_CHECKED); + } + break; + case WM_COMMAND: + { + switch (GET_WM_COMMAND_ID(wParam, lParam)) + { + case IDCANCEL: + { + PhSetIntegerSetting(SETTING_NAME_AUTO_CHECK, + Button_GetCheck(GetDlgItem(hwndDlg, IDC_AUTOCHECKBOX)) == BST_CHECKED); + + EndDialog(hwndDlg, IDCANCEL); + } + break; + } + } + break; + } + + return FALSE; +} + +VOID ShowOptionsDialog( + _In_opt_ HWND Parent + ) +{ + DialogBox( + PluginInstance->DllBase, + MAKEINTRESOURCE(IDD_OPTIONS), + Parent, + OptionsDlgProc + ); } \ No newline at end of file diff --git a/plugins/Updater/page3.c b/plugins/Updater/page3.c index 6b79f7aaede3..a34e8c6c07cf 100644 --- a/plugins/Updater/page3.c +++ b/plugins/Updater/page3.c @@ -52,15 +52,8 @@ HRESULT CALLBACK ShowAvailableCallbackProc( return S_FALSE; } else - { - if (PhGetIntegerSetting(SETTING_NAME_NIGHTLY_BUILD)) - { - PhShellExecute(hwndDlg, L"https://wj32.org/processhacker/nightly.php", NULL); - } - else - { - PhShellExecute(hwndDlg, L"https://wj32.org/processhacker/downloads.php", NULL); - } + { + PhShellExecute(hwndDlg, L"https://wj32.org/processhacker/nightly.php", NULL); } } } @@ -68,6 +61,7 @@ HRESULT CALLBACK ShowAvailableCallbackProc( case TDN_HYPERLINK_CLICKED: { TaskDialogLinkClicked(context); + return S_FALSE; } break; } @@ -91,34 +85,18 @@ VOID ShowAvailableDialog( config.cButtons = ARRAYSIZE(TaskDialogButtonArray); config.lpCallbackData = (LONG_PTR)Context; config.pfCallback = ShowAvailableCallbackProc; - config.pszWindowTitle = L"Process Hacker - Updater"; - if (PhGetIntegerSetting(SETTING_NAME_NIGHTLY_BUILD)) - { - config.pszMainInstruction = L"A new Process Hacker nightly build is available"; - config.pszContent = PhaFormatString(L"Build: %lu.%lu.%lu\r\nDownload size: %s", - Context->MajorVersion, - Context->MinorVersion, - Context->RevisionVersion, - PhGetStringOrEmpty(Context->Size) - )->Buffer; + config.pszWindowTitle = L"Process Hacker - Updater"; + config.pszMainInstruction = L"A newer build of Process Hacker is available."; + config.pszContent = PhaFormatString(L"Version: %lu.%lu.%lu\r\nDownload size: %s\r\n\r\nView Changelog", + Context->MajorVersion, + Context->MinorVersion, + Context->RevisionVersion, + PhGetStringOrEmpty(Context->Size) + )->Buffer; - if (PhIsNullOrEmptyString(Context->BuildMessage)) - config.pszExpandedInformation = L"View Changelog"; - else - config.pszExpandedInformation = PhGetStringOrEmpty(Context->BuildMessage); - } - else - { - config.pszMainInstruction = L"A new Process Hacker release is available"; - config.pszContent = PhaFormatString(L"Version: %lu.%lu.%lu\r\nDownload size: %s", - Context->MajorVersion, - Context->MinorVersion, - Context->RevisionVersion, - PhGetStringOrEmpty(Context->Size) - )->Buffer; - config.pszExpandedInformation = L"View Changelog"; - } + //if (!PhIsNullOrEmptyString(Context->BuildMessage)) + // config.pszExpandedInformation = PhGetStringOrEmpty(Context->BuildMessage); SendMessage(Context->DialogHandle, TDM_NAVIGATE_PAGE, 0, (LPARAM)&config); } \ No newline at end of file diff --git a/plugins/Updater/page4.c b/plugins/Updater/page4.c index 206634cb4383..2f636ac13d0b 100644 --- a/plugins/Updater/page4.c +++ b/plugins/Updater/page4.c @@ -46,6 +46,7 @@ HRESULT CALLBACK ShowProgressCallbackProc( case TDN_HYPERLINK_CLICKED: { TaskDialogLinkClicked(context); + return S_FALSE; } break; } @@ -61,7 +62,7 @@ VOID ShowProgressDialog( memset(&config, 0, sizeof(TASKDIALOGCONFIG)); config.cbSize = sizeof(TASKDIALOGCONFIG); - config.dwFlags = TDF_USE_HICON_MAIN | TDF_ALLOW_DIALOG_CANCELLATION | TDF_CAN_BE_MINIMIZED | TDF_EXPAND_FOOTER_AREA | TDF_ENABLE_HYPERLINKS | TDF_SHOW_PROGRESS_BAR; + config.dwFlags = TDF_USE_HICON_MAIN | TDF_ALLOW_DIALOG_CANCELLATION | TDF_CAN_BE_MINIMIZED | TDF_ENABLE_HYPERLINKS | TDF_SHOW_PROGRESS_BAR; config.dwCommonButtons = TDCBF_CANCEL_BUTTON; config.hMainIcon = Context->IconLargeHandle; config.cxWidth = 200; @@ -75,11 +76,7 @@ VOID ShowProgressDialog( Context->RevisionVersion )->Buffer; config.pszContent = L"Downloaded: ~ of ~ (0%)\r\nSpeed: ~ KB/s"; - - if (PhIsNullOrEmptyString(Context->BuildMessage)) - config.pszExpandedInformation = L"View Changelog"; - else - config.pszExpandedInformation = PhGetStringOrEmpty(Context->BuildMessage); + config.pszExpandedInformation = L"View Changelog"; SendMessage(Context->DialogHandle, TDM_NAVIGATE_PAGE, 0, (LPARAM)&config); } \ No newline at end of file diff --git a/plugins/Updater/page5.c b/plugins/Updater/page5.c index 58e22e502855..ca014212da1d 100644 --- a/plugins/Updater/page5.c +++ b/plugins/Updater/page5.c @@ -92,6 +92,7 @@ HRESULT CALLBACK FinalTaskDialogCallbackProc( case TDN_HYPERLINK_CLICKED: { TaskDialogLinkClicked(context); + return S_FALSE; } break; } @@ -128,6 +129,10 @@ VOID ShowLatestVersionDialog( ) { TASKDIALOGCONFIG config; + LARGE_INTEGER time; + SYSTEMTIME systemTime = { 0 }; + PIMAGE_DOS_HEADER imageDosHeader; + PIMAGE_NT_HEADERS imageNtHeader; memset(&config, 0, sizeof(TASKDIALOGCONFIG)); config.cbSize = sizeof(TASKDIALOGCONFIG); @@ -137,52 +142,22 @@ VOID ShowLatestVersionDialog( config.cxWidth = 200; config.pfCallback = FinalTaskDialogCallbackProc; config.lpCallbackData = (LONG_PTR)Context; + + // HACK + imageDosHeader = (PIMAGE_DOS_HEADER)NtCurrentPeb()->ImageBaseAddress; + imageNtHeader = (PIMAGE_NT_HEADERS)PTR_ADD_OFFSET(imageDosHeader, (ULONG)imageDosHeader->e_lfanew); + RtlSecondsSince1970ToTime(imageNtHeader->FileHeader.TimeDateStamp, &time); + PhLargeIntegerToLocalSystemTime(&systemTime, &time); config.pszWindowTitle = L"Process Hacker - Updater"; - - if (PhGetIntegerSetting(SETTING_NAME_NIGHTLY_BUILD)) - { - LARGE_INTEGER time; - SYSTEMTIME systemTime = { 0 }; - PIMAGE_DOS_HEADER imageDosHeader; - PIMAGE_NT_HEADERS imageNtHeader; - - // HACK - imageDosHeader = (PIMAGE_DOS_HEADER)NtCurrentPeb()->ImageBaseAddress; - imageNtHeader = (PIMAGE_NT_HEADERS)PTR_ADD_OFFSET(imageDosHeader, (ULONG)imageDosHeader->e_lfanew); - - RtlSecondsSince1970ToTime(imageNtHeader->FileHeader.TimeDateStamp, &time); - PhLargeIntegerToLocalSystemTime(&systemTime, &time); - - config.pszMainInstruction = L"You're running the latest nightly build"; - config.pszContent = PhaFormatString( - L"Version: v%lu.%lu.%lu\r\nCompiled: %s", - Context->CurrentMajorVersion, - Context->CurrentMinorVersion, - Context->CurrentRevisionVersion, - PhaFormatDateTime(&systemTime)->Buffer - )->Buffer; - - if (PhIsNullOrEmptyString(Context->BuildMessage)) - config.pszExpandedInformation = L"View Changelog"; - else - config.pszExpandedInformation = PhGetStringOrEmpty(Context->BuildMessage); - } - else - { - config.pszMainInstruction = L"You're running the latest version"; - config.pszContent = PhaFormatString( - L"Stable release build: v%lu.%lu.%lu\r\n\r\n", - Context->CurrentMajorVersion, - Context->CurrentMinorVersion, - Context->CurrentRevisionVersion - )->Buffer; - - if (PhIsNullOrEmptyString(Context->BuildMessage)) - config.pszExpandedInformation = L"View Changelog"; - else - config.pszExpandedInformation = PhGetStringOrEmpty(Context->BuildMessage); - } + config.pszMainInstruction = L"You're running the latest version."; + config.pszContent = PhaFormatString( + L"Version: v%lu.%lu.%lu\r\nCompiled: %s\r\n\r\nView Changelog", + Context->CurrentMajorVersion, + Context->CurrentMinorVersion, + Context->CurrentRevisionVersion, + PhaFormatDateTime(&systemTime)->Buffer + )->Buffer; SendMessage(Context->DialogHandle, TDM_NAVIGATE_PAGE, 0, (LPARAM)&config); } @@ -200,27 +175,13 @@ VOID ShowNewerVersionDialog( config.hMainIcon = Context->IconLargeHandle; config.pszWindowTitle = L"Process Hacker - Updater"; - - if (PhGetIntegerSetting(SETTING_NAME_NIGHTLY_BUILD)) - { - config.pszMainInstruction = L"You're running the latest nightly build"; - config.pszContent = PhaFormatString( - L"Pre-release build: v%lu.%lu.%lu\r\n", - Context->CurrentMajorVersion, - Context->CurrentMinorVersion, - Context->CurrentRevisionVersion - )->Buffer; - } - else - { - config.pszMainInstruction = L"You're running a pre-release version!"; - config.pszContent = PhaFormatString( - L"Pre-release build: v%lu.%lu.%lu\r\n", - Context->CurrentMajorVersion, - Context->CurrentMinorVersion, - Context->CurrentRevisionVersion - )->Buffer; - } + config.pszMainInstruction = L"You're running a pre-release build."; + config.pszContent = PhaFormatString( + L"Pre-release build: v%lu.%lu.%lu\r\n", + Context->CurrentMajorVersion, + Context->CurrentMinorVersion, + Context->CurrentRevisionVersion + )->Buffer; config.cxWidth = 200; config.pfCallback = FinalTaskDialogCallbackProc; diff --git a/plugins/Updater/resource.h b/plugins/Updater/resource.h index 77750932f2ba..11f1b12fef3e 100644 --- a/plugins/Updater/resource.h +++ b/plugins/Updater/resource.h @@ -1,18 +1,17 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by Updater.rc -// -#define IDD_OPTIONS 103 -#define IDC_AUTOCHECKBOX 1002 -#define IDC_NIGHTLY 1003 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 105 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1009 -#define _APS_NEXT_SYMED_VALUE 103 -#endif -#endif +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by Updater.rc +// +#define IDD_OPTIONS 103 +#define IDC_AUTOCHECKBOX 1002 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 107 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1010 +#define _APS_NEXT_SYMED_VALUE 103 +#endif +#endif diff --git a/plugins/Updater/updater.c b/plugins/Updater/updater.c index d910e02f6d94..156148a2b59b 100644 --- a/plugins/Updater/updater.c +++ b/plugins/Updater/updater.c @@ -1,1295 +1,1215 @@ -/* - * Process Hacker Plugins - - * Update Checker Plugin - * - * Copyright (C) 2011-2016 dmex - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include "updater.h" -#include -#include - -HWND UpdateDialogHandle = NULL; -HANDLE UpdateDialogThreadHandle = NULL; -PH_EVENT InitializedEvent = PH_EVENT_INIT; - -PPH_UPDATER_CONTEXT CreateUpdateContext( - _In_ BOOLEAN StartupCheck - ) -{ - PPH_UPDATER_CONTEXT context; - - context = (PPH_UPDATER_CONTEXT)PhCreateAlloc(sizeof(PH_UPDATER_CONTEXT)); - memset(context, 0, sizeof(PH_UPDATER_CONTEXT)); - - PhGetPhVersionNumbers( - &context->CurrentMajorVersion, - &context->CurrentMinorVersion, - NULL, - &context->CurrentRevisionVersion - ); - context->StartupCheck = StartupCheck; - - return context; -} - -VOID FreeUpdateContext( - _In_ _Post_invalid_ PPH_UPDATER_CONTEXT Context - ) -{ - PhClearReference(&Context->Version); - PhClearReference(&Context->RevVersion); - PhClearReference(&Context->RelDate); - PhClearReference(&Context->Size); - PhClearReference(&Context->Hash); - PhClearReference(&Context->Signature); - PhClearReference(&Context->ReleaseNotesUrl); - PhClearReference(&Context->SetupFilePath); - PhClearReference(&Context->SetupFileDownloadUrl); - - if (Context->IconLargeHandle) - DestroyIcon(Context->IconLargeHandle); - - if (Context->IconSmallHandle) - DestroyIcon(Context->IconSmallHandle); - - PhDereferenceObject(Context); -} - -VOID TaskDialogCreateIcons( - _In_ PPH_UPDATER_CONTEXT Context - ) -{ - Context->IconLargeHandle = PhLoadIcon( - NtCurrentPeb()->ImageBaseAddress, - MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER), - PH_LOAD_ICON_SIZE_LARGE, - GetSystemMetrics(SM_CXICON), - GetSystemMetrics(SM_CYICON) - ); - Context->IconSmallHandle = PhLoadIcon( - NtCurrentPeb()->ImageBaseAddress, - MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER), - PH_LOAD_ICON_SIZE_LARGE, - GetSystemMetrics(SM_CXICON), - GetSystemMetrics(SM_CYICON) - ); - - SendMessage(Context->DialogHandle, WM_SETICON, ICON_SMALL, (LPARAM)Context->IconSmallHandle); - SendMessage(Context->DialogHandle, WM_SETICON, ICON_BIG, (LPARAM)Context->IconLargeHandle); -} - -VOID TaskDialogLinkClicked( - _In_ PPH_UPDATER_CONTEXT Context - ) -{ - if (!PhIsNullOrEmptyString(Context->ReleaseNotesUrl)) - { - PhShellExecute(Context->DialogHandle, PhGetStringOrEmpty(Context->ReleaseNotesUrl), NULL); - } -} - -PPH_STRING UpdaterGetOpaqueXmlNodeText( - _In_ mxml_node_t *xmlNode - ) -{ - if (xmlNode && xmlNode->child && xmlNode->child->type == MXML_OPAQUE && xmlNode->child->value.opaque) - { - return PhConvertUtf8ToUtf16(xmlNode->child->value.opaque); - } - - return PhReferenceEmptyString(); -} - -BOOLEAN UpdaterInstalledUsingSetup( - VOID - ) -{ - static PH_STRINGREF keyName = PH_STRINGREF_INIT(L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Process_Hacker2_is1"); - - HANDLE keyHandle = NULL; - - // Check uninstall entries for the 'Process_Hacker2_is1' registry key. - if (NT_SUCCESS(PhOpenKey( - &keyHandle, - KEY_READ, - PH_KEY_LOCAL_MACHINE, - &keyName, - 0 - ))) - { - NtClose(keyHandle); - return TRUE; - } - - return FALSE; -} - -BOOLEAN LastUpdateCheckExpired( - VOID - ) -{ - ULONG64 lastUpdateTimeTicks = 0; - LARGE_INTEGER currentUpdateTimeTicks; - PPH_STRING lastUpdateTimeString; - - PhQuerySystemTime(¤tUpdateTimeTicks); - - lastUpdateTimeString = PhGetStringSetting(SETTING_NAME_LAST_CHECK); - PhStringToInteger64(&lastUpdateTimeString->sr, 0, &lastUpdateTimeTicks); - PhDereferenceObject(lastUpdateTimeString); - - if (currentUpdateTimeTicks.QuadPart - lastUpdateTimeTicks >= 7 * PH_TICKS_PER_DAY) - { - PPH_STRING currentUpdateTimeString = PhFormatUInt64(currentUpdateTimeTicks.QuadPart, FALSE); - - PhSetStringSetting2(SETTING_NAME_LAST_CHECK, ¤tUpdateTimeString->sr); - - PhDereferenceObject(currentUpdateTimeString); - return TRUE; - } - - return FALSE; -} - -PPH_STRING UpdateVersionString( - VOID - ) -{ - ULONG majorVersion; - ULONG minorVersion; - ULONG revisionVersion; - PPH_STRING currentVersion; - PPH_STRING versionHeader = NULL; - - PhGetPhVersionNumbers(&majorVersion, &minorVersion, NULL, &revisionVersion); - - if (currentVersion = PhFormatString(L"%lu.%lu.%lu", majorVersion, minorVersion, revisionVersion)) - { - versionHeader = PhConcatStrings2(L"ProcessHacker-Build: ", currentVersion->Buffer); - PhDereferenceObject(currentVersion); - } - - return versionHeader; -} - -PPH_STRING UpdateWindowsString( - VOID - ) -{ - static PH_STRINGREF keyName = PH_STRINGREF_INIT(L"Software\\Microsoft\\Windows NT\\CurrentVersion"); - - HANDLE keyHandle; - PPH_STRING buildLabHeader = NULL; - - if (NT_SUCCESS(PhOpenKey( - &keyHandle, - KEY_READ, - PH_KEY_LOCAL_MACHINE, - &keyName, - 0 - ))) - { - PPH_STRING buildLabString; - - if (buildLabString = PhQueryRegistryString(keyHandle, L"BuildLabEx")) - { - buildLabHeader = PhConcatStrings2(L"ProcessHacker-OsBuild: ", buildLabString->Buffer); - PhDereferenceObject(buildLabString); - } - else if (buildLabString = PhQueryRegistryString(keyHandle, L"BuildLab")) - { - buildLabHeader = PhConcatStrings2(L"ProcessHacker-OsBuild: ", buildLabString->Buffer); - PhDereferenceObject(buildLabString); - } - - NtClose(keyHandle); - } - - return buildLabHeader; -} - -BOOLEAN ParseVersionString( - _Inout_ PPH_UPDATER_CONTEXT Context - ) -{ - PH_STRINGREF remaining, majorPart, minorPart, revisionPart; - ULONG64 majorInteger = 0, minorInteger = 0, revisionInteger = 0; - - if (PhGetIntegerSetting(SETTING_NAME_NIGHTLY_BUILD)) - { - PhInitializeStringRef(&remaining, PhGetStringOrEmpty(Context->Version)); - - PhSplitStringRefAtChar(&remaining, '.', &majorPart, &remaining); - PhSplitStringRefAtChar(&remaining, '.', &minorPart, &remaining); - PhSplitStringRefAtChar(&remaining, '.', &revisionPart, &remaining); - - PhStringToInteger64(&majorPart, 10, &majorInteger); - PhStringToInteger64(&minorPart, 10, &minorInteger); - PhStringToInteger64(&revisionPart, 10, &revisionInteger); - - Context->MajorVersion = (ULONG)majorInteger; - Context->MinorVersion = (ULONG)minorInteger; - Context->RevisionVersion = (ULONG)revisionInteger; - } - else - { - PhInitializeStringRef(&remaining, PhGetStringOrEmpty(Context->Version)); - PhInitializeStringRef(&revisionPart, PhGetStringOrEmpty(Context->RevVersion)); - - PhSplitStringRefAtChar(&remaining, '.', &majorPart, &remaining); - PhSplitStringRefAtChar(&remaining, '.', &minorPart, &remaining); - - PhStringToInteger64(&majorPart, 10, &majorInteger); - PhStringToInteger64(&minorPart, 10, &minorInteger); - PhStringToInteger64(&revisionPart, 10, &revisionInteger); - - Context->MajorVersion = (ULONG)majorInteger; - Context->MinorVersion = (ULONG)minorInteger; - Context->RevisionVersion = (ULONG)revisionInteger; - } - - return TRUE; -} - -BOOLEAN ReadRequestString( - _In_ HINTERNET Handle, - _Out_ _Deref_post_z_cap_(*DataLength) PSTR *Data, - _Out_ ULONG *DataLength - ) -{ - PSTR data; - ULONG allocatedLength; - ULONG dataLength; - ULONG returnLength; - BYTE buffer[PAGE_SIZE]; - - allocatedLength = sizeof(buffer); - data = (PSTR)PhAllocate(allocatedLength); - dataLength = 0; - - memset(buffer, 0, PAGE_SIZE); - memset(data, 0, allocatedLength); - - while (WinHttpReadData(Handle, buffer, PAGE_SIZE, &returnLength)) - { - if (returnLength == 0) - break; - - if (allocatedLength < dataLength + returnLength) - { - allocatedLength *= 2; - data = (PSTR)PhReAllocate(data, allocatedLength); - } - - memcpy(data + dataLength, buffer, returnLength); - - dataLength += returnLength; - } - - if (allocatedLength < dataLength + 1) - { - allocatedLength++; - data = (PSTR)PhReAllocate(data, allocatedLength); - } - - data[dataLength] = 0; - - *DataLength = dataLength; - *Data = data; - - return TRUE; -} - -BOOLEAN QueryUpdateData( - _Inout_ PPH_UPDATER_CONTEXT Context - ) -{ - BOOLEAN success = FALSE; - HINTERNET httpSessionHandle = NULL; - HINTERNET httpConnectionHandle = NULL; - HINTERNET httpRequestHandle = NULL; - WINHTTP_CURRENT_USER_IE_PROXY_CONFIG proxyConfig = { 0 }; - ULONG stringBufferLength = 0; - PSTR stringBuffer = NULL; - PVOID jsonObject = NULL; - mxml_node_t* xmlNode = NULL; - PPH_STRING versionHeader = UpdateVersionString(); - PPH_STRING windowsHeader = UpdateWindowsString(); - - // Query the current system proxy - WinHttpGetIEProxyConfigForCurrentUser(&proxyConfig); - - // Open the HTTP session with the system proxy configuration if available - if (!(httpSessionHandle = WinHttpOpen( - NULL, - proxyConfig.lpszProxy ? WINHTTP_ACCESS_TYPE_NAMED_PROXY : WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, - proxyConfig.lpszProxy, - proxyConfig.lpszProxyBypass, - 0 - ))) - { - Context->ErrorCode = GetLastError(); - goto CleanupExit; - } - - if (WindowsVersion >= WINDOWS_8_1) - { - ULONG httpFlags = WINHTTP_DECOMPRESSION_FLAG_GZIP | WINHTTP_DECOMPRESSION_FLAG_DEFLATE; - - WinHttpSetOption( - httpSessionHandle, - WINHTTP_OPTION_DECOMPRESSION, - &httpFlags, - sizeof(ULONG) - ); - } - - if (!(httpConnectionHandle = WinHttpConnect( - httpSessionHandle, - L"wj32.org", - INTERNET_DEFAULT_HTTPS_PORT, - 0 - ))) - { - Context->ErrorCode = GetLastError(); - goto CleanupExit; - } - - if (PhGetIntegerSetting(SETTING_NAME_NIGHTLY_BUILD)) - { - if (!(httpRequestHandle = WinHttpOpenRequest( - httpConnectionHandle, - NULL, - L"/processhacker/plugins/nightly.php", - NULL, - WINHTTP_NO_REFERER, - WINHTTP_DEFAULT_ACCEPT_TYPES, - WINHTTP_FLAG_REFRESH | WINHTTP_FLAG_SECURE - ))) - { - Context->ErrorCode = GetLastError(); - goto CleanupExit; - } - } - else - { - if (!(httpRequestHandle = WinHttpOpenRequest( - httpConnectionHandle, - NULL, - L"/processhacker/update.php", - NULL, - WINHTTP_NO_REFERER, - WINHTTP_DEFAULT_ACCEPT_TYPES, - WINHTTP_FLAG_REFRESH | WINHTTP_FLAG_SECURE - ))) - { - Context->ErrorCode = GetLastError(); - goto CleanupExit; - } - } - - if (WindowsVersion >= WINDOWS_7) - { - ULONG keepAlive = WINHTTP_DISABLE_KEEP_ALIVE; - WinHttpSetOption(httpRequestHandle, WINHTTP_OPTION_DISABLE_FEATURE, &keepAlive, sizeof(ULONG)); - } - - if (versionHeader) - { - WinHttpAddRequestHeaders( - httpRequestHandle, - versionHeader->Buffer, - (ULONG)versionHeader->Length / sizeof(WCHAR), - WINHTTP_ADDREQ_FLAG_ADD - ); - } - - if (windowsHeader) - { - WinHttpAddRequestHeaders( - httpRequestHandle, - windowsHeader->Buffer, - (ULONG)windowsHeader->Length / sizeof(WCHAR), - WINHTTP_ADDREQ_FLAG_ADD - ); - } - - if (!WinHttpSendRequest( - httpRequestHandle, - WINHTTP_NO_ADDITIONAL_HEADERS, - 0, - WINHTTP_NO_REQUEST_DATA, - 0, - WINHTTP_IGNORE_REQUEST_TOTAL_LENGTH, - 0 - )) - { - Context->ErrorCode = GetLastError(); - goto CleanupExit; - } - - if (!WinHttpReceiveResponse(httpRequestHandle, NULL)) - { - Context->ErrorCode = GetLastError(); - goto CleanupExit; - } - - if (!ReadRequestString(httpRequestHandle, &stringBuffer, &stringBufferLength)) - goto CleanupExit; - - // Check the buffer for valid data - if (stringBuffer == NULL || stringBuffer[0] == '\0') - goto CleanupExit; - - if (PhGetIntegerSetting(SETTING_NAME_NIGHTLY_BUILD)) - { - if (!(jsonObject = CreateJsonParser(stringBuffer))) - goto CleanupExit; - - Context->Version = PhConvertUtf8ToUtf16(GetJsonValueAsString(jsonObject, "version")); - Context->RevVersion = PhConvertUtf8ToUtf16(GetJsonValueAsString(jsonObject, "version")); - Context->RelDate = PhConvertUtf8ToUtf16(GetJsonValueAsString(jsonObject, "updated")); - Context->Size = PhFormatSize(GetJsonValueAsUlong(jsonObject, "size"), 2); - Context->Hash = PhConvertUtf8ToUtf16(GetJsonValueAsString(jsonObject, "hash_setup")); - Context->Signature = PhConvertUtf8ToUtf16(GetJsonValueAsString(jsonObject, "sig")); - Context->ReleaseNotesUrl = PhConvertUtf8ToUtf16(GetJsonValueAsString(jsonObject, "forum_url")); - Context->SetupFileDownloadUrl = PhConvertUtf8ToUtf16(GetJsonValueAsString(jsonObject, "setup_url")); - Context->BuildMessage = PhConvertUtf8ToUtf16(GetJsonValueAsString(jsonObject, "message")); - - CleanupJsonParser(jsonObject); - - if (PhIsNullOrEmptyString(Context->Signature)) - goto CleanupExit; - - if (!ParseVersionString(Context)) - goto CleanupExit; - } - else - { - xmlNode = mxmlLoadString(NULL, stringBuffer, MXML_OPAQUE_CALLBACK); - - if (xmlNode == NULL || xmlNode->type != MXML_ELEMENT) - goto CleanupExit; - - Context->Version = UpdaterGetOpaqueXmlNodeText( - mxmlFindElement(xmlNode->child, xmlNode, "ver", NULL, NULL, MXML_DESCEND) - ); - Context->RevVersion = UpdaterGetOpaqueXmlNodeText( - mxmlFindElement(xmlNode->child, xmlNode, "rev", NULL, NULL, MXML_DESCEND) - ); - Context->RelDate = UpdaterGetOpaqueXmlNodeText( - mxmlFindElement(xmlNode->child, xmlNode, "reldate", NULL, NULL, MXML_DESCEND) - ); - Context->Size = UpdaterGetOpaqueXmlNodeText( - mxmlFindElement(xmlNode->child, xmlNode, "size", NULL, NULL, MXML_DESCEND) - ); - Context->Hash = UpdaterGetOpaqueXmlNodeText( - mxmlFindElement(xmlNode->child, xmlNode, "sha2", NULL, NULL, MXML_DESCEND) - ); - Context->Signature = UpdaterGetOpaqueXmlNodeText( - mxmlFindElement(xmlNode->child, xmlNode, "sig", NULL, NULL, MXML_DESCEND) - ); - Context->ReleaseNotesUrl = UpdaterGetOpaqueXmlNodeText( - mxmlFindElement(xmlNode->child, xmlNode, "relnotes", NULL, NULL, MXML_DESCEND) - ); - Context->SetupFileDownloadUrl = UpdaterGetOpaqueXmlNodeText( - mxmlFindElement(xmlNode->child, xmlNode, "setupurl", NULL, NULL, MXML_DESCEND) - ); - - if (PhIsNullOrEmptyString(Context->Signature)) - goto CleanupExit; - - if (!ParseVersionString(Context)) - goto CleanupExit; - } - - if (PhIsNullOrEmptyString(Context->Version)) - goto CleanupExit; - if (PhIsNullOrEmptyString(Context->RevVersion)) - goto CleanupExit; - if (PhIsNullOrEmptyString(Context->RelDate)) - goto CleanupExit; - if (PhIsNullOrEmptyString(Context->Size)) - goto CleanupExit; - if (PhIsNullOrEmptyString(Context->Hash)) - goto CleanupExit; - if (PhIsNullOrEmptyString(Context->ReleaseNotesUrl)) - goto CleanupExit; - if (PhIsNullOrEmptyString(Context->SetupFileDownloadUrl)) - goto CleanupExit; - - success = TRUE; - -CleanupExit: - - if (httpRequestHandle) - WinHttpCloseHandle(httpRequestHandle); - - if (httpConnectionHandle) - WinHttpCloseHandle(httpConnectionHandle); - - if (httpSessionHandle) - WinHttpCloseHandle(httpSessionHandle); - - if (xmlNode) - mxmlDelete(xmlNode); - - if (stringBuffer) - PhFree(stringBuffer); - - PhClearReference(&versionHeader); - PhClearReference(&windowsHeader); - - return success; -} - -NTSTATUS UpdateCheckSilentThread( - _In_ PVOID Parameter - ) -{ - PPH_UPDATER_CONTEXT context = NULL; - ULONGLONG currentVersion = 0; - ULONGLONG latestVersion = 0; - - context = CreateUpdateContext(TRUE); - -#ifndef FORCE_UPDATE_CHECK - if (!LastUpdateCheckExpired()) - goto CleanupExit; -#endif - if (!QueryUpdateData(context)) - goto CleanupExit; - - currentVersion = MAKE_VERSION_ULONGLONG( - context->CurrentMajorVersion, - context->CurrentMinorVersion, - context->CurrentRevisionVersion, - 0 - ); - -#ifdef FORCE_UPDATE_CHECK - latestVersion = MAKE_VERSION_ULONGLONG( - 9999, - 9999, - 9999, - 0 - ); -#else - latestVersion = MAKE_VERSION_ULONGLONG( - context->MajorVersion, - context->MinorVersion, - context->RevisionVersion, - 0 - ); -#endif - - // Compare the current version against the latest available version - if (currentVersion < latestVersion) - { - // Don't spam the user the second they open PH, delay dialog creation for 3 seconds. - //Sleep(3000); - - // Check if the user hasn't already opened the dialog. - if (!UpdateDialogHandle) - { - // We have data we're going to cache and pass into the dialog - context->HaveData = TRUE; - - // Show the dialog asynchronously on a new thread. - ShowUpdateDialog(context); - } - } - -CleanupExit: - - if (!context->HaveData) - FreeUpdateContext(context); - - return STATUS_SUCCESS; -} - -NTSTATUS UpdateCheckThread( - _In_ PVOID Parameter - ) -{ - PPH_UPDATER_CONTEXT context = NULL; - ULONGLONG currentVersion = 0; - ULONGLONG latestVersion = 0; - - context = (PPH_UPDATER_CONTEXT)Parameter; - context->ErrorCode = STATUS_SUCCESS; - - // Check if we have cached update data - if (!context->HaveData) - { - context->HaveData = QueryUpdateData(context); - } - - if (!context->HaveData) - { - PostMessage(context->DialogHandle, PH_UPDATEISERRORED, 0, 0); - - PhDereferenceObject(context); - return STATUS_SUCCESS; - } - - currentVersion = MAKE_VERSION_ULONGLONG( - context->CurrentMajorVersion, - context->CurrentMinorVersion, - context->CurrentRevisionVersion, - 0 - ); - -#ifdef FORCE_UPDATE_CHECK - latestVersion = MAKE_VERSION_ULONGLONG( - 9999, - 9999, - 9999, - 0 - ); -#else - latestVersion = MAKE_VERSION_ULONGLONG( - context->MajorVersion, - context->MinorVersion, - context->RevisionVersion, - 0 - ); -#endif - - if (currentVersion == latestVersion) - { - // User is running the latest version - PostMessage(context->DialogHandle, PH_UPDATEISCURRENT, 0, 0); - } - else if (currentVersion > latestVersion) - { - // User is running a newer version - PostMessage(context->DialogHandle, PH_UPDATENEWER, 0, 0); - } - else - { - // User is running an older version - PostMessage(context->DialogHandle, PH_UPDATEAVAILABLE, 0, 0); - } - - PhDereferenceObject(context); - return STATUS_SUCCESS; -} - -NTSTATUS UpdateDownloadThread( - _In_ PVOID Parameter - ) -{ - BOOLEAN downloadSuccess = FALSE; - BOOLEAN hashSuccess = FALSE; - BOOLEAN signatureSuccess = FALSE; - HANDLE tempFileHandle = NULL; - HINTERNET httpSessionHandle = NULL; - HINTERNET httpConnectionHandle = NULL; - HINTERNET httpRequestHandle = NULL; - PPH_STRING setupTempPath = NULL; - PPH_STRING downloadHostPath = NULL; - PPH_STRING downloadUrlPath = NULL; - PPH_STRING userAgentString = NULL; - PPH_STRING fullSetupPath = NULL; - PPH_STRING randomGuidString = NULL; - PUPDATER_HASH_CONTEXT hashContext = NULL; - ULONG indexOfFileName = -1; - GUID randomGuid; - URL_COMPONENTS httpUrlComponents = { sizeof(URL_COMPONENTS) }; - WINHTTP_CURRENT_USER_IE_PROXY_CONFIG proxyConfig = { 0 }; - LARGE_INTEGER timeNow; - LARGE_INTEGER timeStart; - ULONG64 timeTicks = 0; - ULONG64 timeBitsPerSecond = 0; - PPH_UPDATER_CONTEXT context = (PPH_UPDATER_CONTEXT)Parameter; - - SendMessage(context->DialogHandle, TDM_UPDATE_ELEMENT_TEXT, TDE_MAIN_INSTRUCTION, (LPARAM)L"Initializing download request..."); - - // Create a user agent string. - userAgentString = PhFormatString( - L"PH_%lu.%lu_%lu", - context->CurrentMajorVersion, - context->CurrentMinorVersion, - context->CurrentRevisionVersion - ); - if (PhIsNullOrEmptyString(userAgentString)) - goto CleanupExit; - - setupTempPath = PhCreateStringEx(NULL, GetTempPath(0, NULL) * sizeof(WCHAR)); - if (PhIsNullOrEmptyString(setupTempPath)) - goto CleanupExit; - - if (GetTempPath((ULONG)setupTempPath->Length / sizeof(WCHAR), setupTempPath->Buffer) == 0) - goto CleanupExit; - if (PhIsNullOrEmptyString(setupTempPath)) - goto CleanupExit; - - // Generate random guid for our directory path. - PhGenerateGuid(&randomGuid); - - if (randomGuidString = PhFormatGuid(&randomGuid)) - { - PPH_STRING guidSubString; - - // Strip the left and right curly brackets. - guidSubString = PhSubstring(randomGuidString, 1, randomGuidString->Length / sizeof(WCHAR) - 2); - - PhMoveReference(&randomGuidString, guidSubString); - } - - // Append the tempath to our string: %TEMP%RandomString\\processhacker-%lu.%lu-setup.exe - // Example: C:\\Users\\dmex\\AppData\\Temp\\ABCD\\processhacker-2.90-setup.exe - context->SetupFilePath = PhFormatString( - L"%s%s\\processhacker-%lu.%lu-setup.exe", - PhGetStringOrEmpty(setupTempPath), - PhGetStringOrEmpty(randomGuidString), - context->MajorVersion, - context->MinorVersion - ); - if (PhIsNullOrEmptyString(context->SetupFilePath)) - goto CleanupExit; - - // Create the directory if it does not exist. - if (fullSetupPath = PhGetFullPath(PhGetString(context->SetupFilePath), &indexOfFileName)) - { - PPH_STRING directoryPath; - - if (indexOfFileName == -1) - goto CleanupExit; - - if (directoryPath = PhSubstring(fullSetupPath, 0, indexOfFileName)) - { - SHCreateDirectoryEx(NULL, directoryPath->Buffer, NULL); - PhDereferenceObject(directoryPath); - } - } - - // Create output file - if (!NT_SUCCESS(PhCreateFileWin32( - &tempFileHandle, - PhGetString(context->SetupFilePath), - FILE_GENERIC_READ | FILE_GENERIC_WRITE, - FILE_ATTRIBUTE_NOT_CONTENT_INDEXED | FILE_ATTRIBUTE_TEMPORARY, - FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, - FILE_OVERWRITE_IF, - FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT - ))) - { - goto CleanupExit; - } - - // Set lengths to non-zero enabling these params to be cracked. - httpUrlComponents.dwSchemeLength = (ULONG)-1; - httpUrlComponents.dwHostNameLength = (ULONG)-1; - httpUrlComponents.dwUrlPathLength = (ULONG)-1; - - if (!WinHttpCrackUrl( - PhGetStringOrEmpty(context->SetupFileDownloadUrl), - 0, - 0, - &httpUrlComponents - )) - { - context->ErrorCode = GetLastError(); - goto CleanupExit; - } - - // Create the Host string. - downloadHostPath = PhCreateStringEx( - httpUrlComponents.lpszHostName, - httpUrlComponents.dwHostNameLength * sizeof(WCHAR) - ); - if (PhIsNullOrEmptyString(downloadHostPath)) - goto CleanupExit; - - // Create the Path string. - downloadUrlPath = PhCreateStringEx( - httpUrlComponents.lpszUrlPath, - httpUrlComponents.dwUrlPathLength * sizeof(WCHAR) - ); - if (PhIsNullOrEmptyString(downloadUrlPath)) - goto CleanupExit; - - SendMessage(context->DialogHandle, TDM_UPDATE_ELEMENT_TEXT, TDE_MAIN_INSTRUCTION, (LPARAM)L"Connecting..."); - - // Query the current system proxy - WinHttpGetIEProxyConfigForCurrentUser(&proxyConfig); - - // Open the HTTP session with the system proxy configuration if available - if (!(httpSessionHandle = WinHttpOpen( - PhGetStringOrEmpty(userAgentString), - proxyConfig.lpszProxy ? WINHTTP_ACCESS_TYPE_NAMED_PROXY : WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, - proxyConfig.lpszProxy, - proxyConfig.lpszProxyBypass, - 0 - ))) - { - context->ErrorCode = GetLastError(); - goto CleanupExit; - } - - if (WindowsVersion >= WINDOWS_8_1) - { - ULONG httpFlags = WINHTTP_DECOMPRESSION_FLAG_GZIP | WINHTTP_DECOMPRESSION_FLAG_DEFLATE; - - WinHttpSetOption( - httpSessionHandle, - WINHTTP_OPTION_DECOMPRESSION, - &httpFlags, - sizeof(ULONG) - ); - } - - if (!(httpConnectionHandle = WinHttpConnect( - httpSessionHandle, - PhGetStringOrEmpty(downloadHostPath), - httpUrlComponents.nScheme == INTERNET_SCHEME_HTTP ? INTERNET_DEFAULT_HTTP_PORT : INTERNET_DEFAULT_HTTPS_PORT, - 0 - ))) - { - context->ErrorCode = GetLastError(); - goto CleanupExit; - } - - if (!(httpRequestHandle = WinHttpOpenRequest( - httpConnectionHandle, - NULL, - PhGetStringOrEmpty(downloadUrlPath), - NULL, - WINHTTP_NO_REFERER, - WINHTTP_DEFAULT_ACCEPT_TYPES, - WINHTTP_FLAG_REFRESH | (httpUrlComponents.nScheme == INTERNET_SCHEME_HTTPS ? WINHTTP_FLAG_SECURE : 0) - ))) - { - context->ErrorCode = GetLastError(); - goto CleanupExit; - } - - if (WindowsVersion >= WINDOWS_7) - { - ULONG keepAlive = WINHTTP_DISABLE_KEEP_ALIVE; - WinHttpSetOption(httpRequestHandle, WINHTTP_OPTION_DISABLE_FEATURE, &keepAlive, sizeof(ULONG)); - } - - SendMessage(context->DialogHandle, TDM_UPDATE_ELEMENT_TEXT, TDE_MAIN_INSTRUCTION, (LPARAM)L"Sending download request..."); - - if (!WinHttpSendRequest( - httpRequestHandle, - WINHTTP_NO_ADDITIONAL_HEADERS, - 0, - WINHTTP_NO_REQUEST_DATA, - 0, - WINHTTP_IGNORE_REQUEST_TOTAL_LENGTH, - 0 - )) - { - context->ErrorCode = GetLastError(); - goto CleanupExit; - } - - SendMessage(context->DialogHandle, TDM_UPDATE_ELEMENT_TEXT, TDE_MAIN_INSTRUCTION, (LPARAM)L"Waiting for response..."); - - if (!WinHttpReceiveResponse(httpRequestHandle, NULL)) - { - context->ErrorCode = GetLastError(); - goto CleanupExit; - } - else - { - ULONG bytesDownloaded = 0; - ULONG downloadedBytes = 0; - ULONG contentLengthSize = sizeof(ULONG); - ULONG contentLength = 0; - PPH_STRING status; - IO_STATUS_BLOCK isb; - BYTE buffer[PAGE_SIZE]; - - status = PhFormatString(L"Downloading update %lu.%lu.%lu...", - context->MajorVersion, - context->MinorVersion, - context->RevisionVersion - ); - - SendMessage(context->DialogHandle, TDM_SET_MARQUEE_PROGRESS_BAR, FALSE, 0); - SendMessage(context->DialogHandle, TDM_UPDATE_ELEMENT_TEXT, TDE_MAIN_INSTRUCTION, (LPARAM)status->Buffer); - PhDereferenceObject(status); - - // Start the clock. - PhQuerySystemTime(&timeStart); - - if (!WinHttpQueryHeaders( - httpRequestHandle, - WINHTTP_QUERY_CONTENT_LENGTH | WINHTTP_QUERY_FLAG_NUMBER, - WINHTTP_HEADER_NAME_BY_INDEX, - &contentLength, - &contentLengthSize, - 0 - )) - { - context->ErrorCode = GetLastError(); - goto CleanupExit; - } - - // Initialize hash algorithm. - if (!(hashContext = UpdaterInitializeHash())) - goto CleanupExit; - - // Zero the buffer. - memset(buffer, 0, PAGE_SIZE); - - // Download the data. - while (WinHttpReadData(httpRequestHandle, buffer, PAGE_SIZE, &bytesDownloaded)) - { - // If we get zero bytes, the file was uploaded or there was an error - if (bytesDownloaded == 0) - break; - - // If the dialog was closed, just cleanup and exit - if (!UpdateDialogThreadHandle) - goto CleanupExit; - - // Update the hash of bytes we downloaded. - UpdaterUpdateHash(hashContext, buffer, bytesDownloaded); - - // Write the downloaded bytes to disk. - if (!NT_SUCCESS(NtWriteFile( - tempFileHandle, - NULL, - NULL, - NULL, - &isb, - buffer, - bytesDownloaded, - NULL, - NULL - ))) - { - goto CleanupExit; - } - - downloadedBytes += (DWORD)isb.Information; - - // Check the number of bytes written are the same we downloaded. - if (bytesDownloaded != isb.Information) - goto CleanupExit; - - // Query the current time - PhQuerySystemTime(&timeNow); - - // Calculate the number of ticks - timeTicks = (timeNow.QuadPart - timeStart.QuadPart) / PH_TICKS_PER_SEC; - timeBitsPerSecond = downloadedBytes / __max(timeTicks, 1); - - // TODO: Update on timer callback. - { - FLOAT percent = ((FLOAT)downloadedBytes / contentLength * 100); - PPH_STRING totalLength = PhFormatSize(contentLength, -1); - PPH_STRING totalDownloaded = PhFormatSize(downloadedBytes, -1); - PPH_STRING totalSpeed = PhFormatSize(timeBitsPerSecond, -1); - - PPH_STRING statusMessage = PhFormatString( - L"Downloaded: %s of %s (%.0f%%)\r\nSpeed: %s/s", - PhGetStringOrEmpty(totalDownloaded), - PhGetStringOrEmpty(totalLength), - percent, - PhGetStringOrEmpty(totalSpeed) - ); - - SendMessage(context->DialogHandle, TDM_UPDATE_ELEMENT_TEXT, TDE_CONTENT, (LPARAM)statusMessage->Buffer); - SendMessage(context->DialogHandle, TDM_SET_PROGRESS_BAR_POS, (WPARAM)percent, 0); - - PhDereferenceObject(statusMessage); - PhDereferenceObject(totalSpeed); - PhDereferenceObject(totalLength); - PhDereferenceObject(totalDownloaded); - } - } - - if (UpdaterVerifyHash(hashContext, context->Hash)) - { - hashSuccess = TRUE; - } - - if (UpdaterVerifySignature(hashContext, context->Signature)) - { - signatureSuccess = TRUE; - } - - if (hashSuccess && signatureSuccess) - { - downloadSuccess = TRUE; - } - } - -CleanupExit: - - if (hashContext) - UpdaterDestroyHash(hashContext); - - if (tempFileHandle) - NtClose(tempFileHandle); - - if (httpRequestHandle) - WinHttpCloseHandle(httpRequestHandle); - - if (httpConnectionHandle) - WinHttpCloseHandle(httpConnectionHandle); - - if (httpSessionHandle) - WinHttpCloseHandle(httpSessionHandle); - - PhClearReference(&randomGuidString); - PhClearReference(&fullSetupPath); - PhClearReference(&setupTempPath); - PhClearReference(&downloadHostPath); - PhClearReference(&downloadUrlPath); - PhClearReference(&userAgentString); - - if (UpdateDialogThreadHandle) - { - if (downloadSuccess && hashSuccess && signatureSuccess) - { - PostMessage(context->DialogHandle, PH_UPDATESUCCESS, 0, 0); - } - else if (downloadSuccess) - { - PostMessage(context->DialogHandle, PH_UPDATEFAILURE, signatureSuccess, hashSuccess); - } - else - { - PostMessage(context->DialogHandle, PH_UPDATEISERRORED, 0, 0); - } - } - - PhDereferenceObject(context); - return STATUS_SUCCESS; -} - -LRESULT CALLBACK TaskDialogSubclassProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam, - _In_ UINT_PTR uIdSubclass, - _In_ ULONG_PTR dwRefData - ) -{ - PPH_UPDATER_CONTEXT context = (PPH_UPDATER_CONTEXT)dwRefData; - - switch (uMsg) - { - case WM_NCDESTROY: - { - RemoveWindowSubclass(hwndDlg, TaskDialogSubclassProc, uIdSubclass); - } - break; - case WM_SHOWDIALOG: - { - if (IsMinimized(hwndDlg)) - ShowWindow(hwndDlg, SW_RESTORE); - else - ShowWindow(hwndDlg, SW_SHOW); - - SetForegroundWindow(hwndDlg); - } - break; - case PH_UPDATEAVAILABLE: - { - ShowAvailableDialog(context); - } - break; - case PH_UPDATEISCURRENT: - { - ShowLatestVersionDialog(context); - } - break; - case PH_UPDATENEWER: - { - ShowNewerVersionDialog(context); - } - break; - case PH_UPDATESUCCESS: - { - ShowUpdateInstallDialog(context); - } - break; - case PH_UPDATEFAILURE: - { - if ((BOOLEAN)wParam) - ShowUpdateFailedDialog(context, TRUE, FALSE); - else if ((BOOLEAN)lParam) - ShowUpdateFailedDialog(context, FALSE, TRUE); - else - ShowUpdateFailedDialog(context, FALSE, FALSE); - } - break; - case PH_UPDATEISERRORED: - { - ShowUpdateFailedDialog(context, FALSE, FALSE); - } - break; - //case WM_PARENTNOTIFY: - // { - // if (wParam == WM_CREATE) - // { - // // uMsg == 49251 for expand/collapse button click - // HWND hwndEdit = CreateWindowEx( - // WS_EX_CLIENTEDGE, - // L"EDIT", - // NULL, - // WS_CHILD | WS_VISIBLE | WS_VSCROLL | ES_LEFT | ES_MULTILINE | ES_AUTOVSCROLL, - // 5, - // 5, - // 390, - // 85, - // (HWND)lParam, // parent window - // 0, - // NULL, - // NULL - // ); - // - // PhCreateCommonFont(-11, hwndEdit); - // - // // Add text to the window. - // SendMessage(hwndEdit, WM_SETTEXT, 0, (LPARAM)L"TEST"); - // } - // } - // break; - //case WM_NCACTIVATE: - // { - // if (IsWindowVisible(PhMainWndHandle) && !IsMinimized(PhMainWndHandle)) - // { - // if (!context->FixedWindowStyles) - // { - // SetWindowLongPtr(hwndDlg, GWLP_HWNDPARENT, (LONG_PTR)PhMainWndHandle); - // PhSetWindowExStyle(hwndDlg, WS_EX_APPWINDOW, WS_EX_APPWINDOW); - // context->FixedWindowStyles = TRUE; - // } - // } - // } - // break; - } - - return DefSubclassProc(hwndDlg, uMsg, wParam, lParam); -} - -HRESULT CALLBACK TaskDialogBootstrapCallback( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam, - _In_ LONG_PTR dwRefData - ) -{ - PPH_UPDATER_CONTEXT context = (PPH_UPDATER_CONTEXT)dwRefData; - - switch (uMsg) - { - case TDN_CREATED: - { - UpdateDialogHandle = context->DialogHandle = hwndDlg; - - // Center the update window on PH if it's visible else we center on the desktop. - PhCenterWindow(hwndDlg, (IsWindowVisible(PhMainWndHandle) && !IsMinimized(PhMainWndHandle)) ? PhMainWndHandle : NULL); - - // Create the Taskdialog icons - TaskDialogCreateIcons(context); - - // Subclass the Taskdialog - SetWindowSubclass(hwndDlg, TaskDialogSubclassProc, 0, (ULONG_PTR)context); - - if (context->StartupCheck) - { - ShowAvailableDialog(context); - } - else - { - ShowCheckForUpdatesDialog(context); - } - } - break; - } - - return S_OK; -} - -NTSTATUS ShowUpdateDialogThread( - _In_ PVOID Parameter - ) -{ - PH_AUTO_POOL autoPool; - PPH_UPDATER_CONTEXT context; - TASKDIALOGCONFIG config = { sizeof(TASKDIALOGCONFIG) }; - - if (Parameter) - context = (PPH_UPDATER_CONTEXT)Parameter; - else - context = CreateUpdateContext(FALSE); - - PhInitializeAutoPool(&autoPool); - - // Start TaskDialog bootstrap - config.dwFlags = TDF_ALLOW_DIALOG_CANCELLATION | TDF_CAN_BE_MINIMIZED; - config.pszContent = L"Initializing..."; - config.lpCallbackData = (LONG_PTR)context; - config.pfCallback = TaskDialogBootstrapCallback; - TaskDialogIndirect(&config, NULL, NULL, NULL); - - FreeUpdateContext(context); - PhDeleteAutoPool(&autoPool); - - if (UpdateDialogThreadHandle) - { - NtClose(UpdateDialogThreadHandle); - UpdateDialogThreadHandle = NULL; - } - - PhResetEvent(&InitializedEvent); - - return STATUS_SUCCESS; -} - -VOID ShowUpdateDialog( - _In_opt_ PPH_UPDATER_CONTEXT Context - ) -{ - if (!UpdateDialogThreadHandle) - { - if (!(UpdateDialogThreadHandle = PhCreateThread(0, ShowUpdateDialogThread, Context))) - { - PhShowStatus(PhMainWndHandle, L"Unable to create the updater window.", 0, GetLastError()); - return; - } - - PhWaitForEvent(&InitializedEvent, NULL); - } - - PostMessage(UpdateDialogHandle, WM_SHOWDIALOG, 0, 0); -} - -VOID StartInitialCheck( - VOID - ) -{ - HANDLE silentCheckThread = NULL; - - if (silentCheckThread = PhCreateThread(0, UpdateCheckSilentThread, NULL)) - NtClose(silentCheckThread); +/* + * Process Hacker Plugins - + * Update Checker Plugin + * + * Copyright (C) 2011-2016 dmex + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include "updater.h" +#include +#include + +HWND UpdateDialogHandle = NULL; +HANDLE UpdateDialogThreadHandle = NULL; +PH_EVENT InitializedEvent = PH_EVENT_INIT; + +PPH_UPDATER_CONTEXT CreateUpdateContext( + _In_ BOOLEAN StartupCheck + ) +{ + PPH_UPDATER_CONTEXT context; + + context = (PPH_UPDATER_CONTEXT)PhCreateAlloc(sizeof(PH_UPDATER_CONTEXT)); + memset(context, 0, sizeof(PH_UPDATER_CONTEXT)); + + PhGetPhVersionNumbers( + &context->CurrentMajorVersion, + &context->CurrentMinorVersion, + NULL, + &context->CurrentRevisionVersion + ); + context->StartupCheck = StartupCheck; + + return context; +} + +VOID FreeUpdateContext( + _In_ _Post_invalid_ PPH_UPDATER_CONTEXT Context + ) +{ + PhClearReference(&Context->Version); + PhClearReference(&Context->RevVersion); + PhClearReference(&Context->RelDate); + PhClearReference(&Context->Size); + PhClearReference(&Context->Hash); + PhClearReference(&Context->Signature); + PhClearReference(&Context->ReleaseNotesUrl); + PhClearReference(&Context->SetupFilePath); + PhClearReference(&Context->SetupFileDownloadUrl); + + if (Context->IconLargeHandle) + DestroyIcon(Context->IconLargeHandle); + + if (Context->IconSmallHandle) + DestroyIcon(Context->IconSmallHandle); + + PhDereferenceObject(Context); +} + +VOID TaskDialogCreateIcons( + _In_ PPH_UPDATER_CONTEXT Context + ) +{ + Context->IconLargeHandle = PhLoadIcon( + NtCurrentPeb()->ImageBaseAddress, + MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER), + PH_LOAD_ICON_SIZE_LARGE, + GetSystemMetrics(SM_CXICON), + GetSystemMetrics(SM_CYICON) + ); + Context->IconSmallHandle = PhLoadIcon( + NtCurrentPeb()->ImageBaseAddress, + MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER), + PH_LOAD_ICON_SIZE_LARGE, + GetSystemMetrics(SM_CXICON), + GetSystemMetrics(SM_CYICON) + ); + + SendMessage(Context->DialogHandle, WM_SETICON, ICON_SMALL, (LPARAM)Context->IconSmallHandle); + SendMessage(Context->DialogHandle, WM_SETICON, ICON_BIG, (LPARAM)Context->IconLargeHandle); +} + +VOID TaskDialogLinkClicked( + _In_ PPH_UPDATER_CONTEXT Context + ) +{ + if (!PhIsNullOrEmptyString(Context->ReleaseNotesUrl)) + { + PhShellExecute(Context->DialogHandle, PhGetStringOrEmpty(Context->ReleaseNotesUrl), NULL); + } +} + +PPH_STRING UpdaterGetOpaqueXmlNodeText( + _In_ mxml_node_t *xmlNode + ) +{ + if (xmlNode && xmlNode->child && xmlNode->child->type == MXML_OPAQUE && xmlNode->child->value.opaque) + { + return PhConvertUtf8ToUtf16(xmlNode->child->value.opaque); + } + + return PhReferenceEmptyString(); +} + +BOOLEAN UpdaterInstalledUsingSetup( + VOID + ) +{ + static PH_STRINGREF keyName = PH_STRINGREF_INIT(L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Process_Hacker2_is1"); + + HANDLE keyHandle = NULL; + + // Check uninstall entries for the 'Process_Hacker2_is1' registry key. + if (NT_SUCCESS(PhOpenKey( + &keyHandle, + KEY_READ, + PH_KEY_LOCAL_MACHINE, + &keyName, + 0 + ))) + { + NtClose(keyHandle); + return TRUE; + } + + return FALSE; +} + +BOOLEAN LastUpdateCheckExpired( + VOID + ) +{ + ULONG64 lastUpdateTimeTicks = 0; + LARGE_INTEGER currentUpdateTimeTicks; + PPH_STRING lastUpdateTimeString; + + PhQuerySystemTime(¤tUpdateTimeTicks); + + lastUpdateTimeString = PhGetStringSetting(SETTING_NAME_LAST_CHECK); + PhStringToInteger64(&lastUpdateTimeString->sr, 0, &lastUpdateTimeTicks); + PhDereferenceObject(lastUpdateTimeString); + + if (currentUpdateTimeTicks.QuadPart - lastUpdateTimeTicks >= 7 * PH_TICKS_PER_DAY) + { + PPH_STRING currentUpdateTimeString = PhFormatUInt64(currentUpdateTimeTicks.QuadPart, FALSE); + + PhSetStringSetting2(SETTING_NAME_LAST_CHECK, ¤tUpdateTimeString->sr); + + PhDereferenceObject(currentUpdateTimeString); + return TRUE; + } + + return FALSE; +} + +PPH_STRING UpdateVersionString( + VOID + ) +{ + ULONG majorVersion; + ULONG minorVersion; + ULONG revisionVersion; + PPH_STRING currentVersion; + PPH_STRING versionHeader = NULL; + + PhGetPhVersionNumbers(&majorVersion, &minorVersion, NULL, &revisionVersion); + + if (currentVersion = PhFormatString(L"%lu.%lu.%lu", majorVersion, minorVersion, revisionVersion)) + { + versionHeader = PhConcatStrings2(L"ProcessHacker-Build: ", currentVersion->Buffer); + PhDereferenceObject(currentVersion); + } + + return versionHeader; +} + +PPH_STRING UpdateWindowsString( + VOID + ) +{ + static PH_STRINGREF keyName = PH_STRINGREF_INIT(L"Software\\Microsoft\\Windows NT\\CurrentVersion"); + + HANDLE keyHandle; + PPH_STRING buildLabHeader = NULL; + + if (NT_SUCCESS(PhOpenKey( + &keyHandle, + KEY_READ, + PH_KEY_LOCAL_MACHINE, + &keyName, + 0 + ))) + { + PPH_STRING buildLabString; + + if (buildLabString = PhQueryRegistryString(keyHandle, L"BuildLabEx")) + { + buildLabHeader = PhConcatStrings2(L"ProcessHacker-OsBuild: ", buildLabString->Buffer); + PhDereferenceObject(buildLabString); + } + else if (buildLabString = PhQueryRegistryString(keyHandle, L"BuildLab")) + { + buildLabHeader = PhConcatStrings2(L"ProcessHacker-OsBuild: ", buildLabString->Buffer); + PhDereferenceObject(buildLabString); + } + + NtClose(keyHandle); + } + + return buildLabHeader; +} + +BOOLEAN ParseVersionString( + _Inout_ PPH_UPDATER_CONTEXT Context + ) +{ + PH_STRINGREF remaining, majorPart, minorPart, revisionPart; + ULONG64 majorInteger = 0, minorInteger = 0, revisionInteger = 0; + + PhInitializeStringRef(&remaining, PhGetStringOrEmpty(Context->Version)); + + PhSplitStringRefAtChar(&remaining, '.', &majorPart, &remaining); + PhSplitStringRefAtChar(&remaining, '.', &minorPart, &remaining); + PhSplitStringRefAtChar(&remaining, '.', &revisionPart, &remaining); + + PhStringToInteger64(&majorPart, 10, &majorInteger); + PhStringToInteger64(&minorPart, 10, &minorInteger); + PhStringToInteger64(&revisionPart, 10, &revisionInteger); + + Context->MajorVersion = (ULONG)majorInteger; + Context->MinorVersion = (ULONG)minorInteger; + Context->RevisionVersion = (ULONG)revisionInteger; + return TRUE; +} + +BOOLEAN ReadRequestString( + _In_ HINTERNET Handle, + _Out_ _Deref_post_z_cap_(*DataLength) PSTR *Data, + _Out_ ULONG *DataLength + ) +{ + PSTR data; + ULONG allocatedLength; + ULONG dataLength; + ULONG returnLength; + BYTE buffer[PAGE_SIZE]; + + allocatedLength = sizeof(buffer); + data = (PSTR)PhAllocate(allocatedLength); + dataLength = 0; + + memset(buffer, 0, PAGE_SIZE); + memset(data, 0, allocatedLength); + + while (WinHttpReadData(Handle, buffer, PAGE_SIZE, &returnLength)) + { + if (returnLength == 0) + break; + + if (allocatedLength < dataLength + returnLength) + { + allocatedLength *= 2; + data = (PSTR)PhReAllocate(data, allocatedLength); + } + + memcpy(data + dataLength, buffer, returnLength); + + dataLength += returnLength; + } + + if (allocatedLength < dataLength + 1) + { + allocatedLength++; + data = (PSTR)PhReAllocate(data, allocatedLength); + } + + data[dataLength] = 0; + + *DataLength = dataLength; + *Data = data; + + return TRUE; +} + +BOOLEAN QueryUpdateData( + _Inout_ PPH_UPDATER_CONTEXT Context + ) +{ + BOOLEAN success = FALSE; + HINTERNET httpSessionHandle = NULL; + HINTERNET httpConnectionHandle = NULL; + HINTERNET httpRequestHandle = NULL; + WINHTTP_CURRENT_USER_IE_PROXY_CONFIG proxyConfig = { 0 }; + ULONG stringBufferLength = 0; + PSTR stringBuffer = NULL; + PVOID jsonObject = NULL; + mxml_node_t* xmlNode = NULL; + PPH_STRING versionHeader = UpdateVersionString(); + PPH_STRING windowsHeader = UpdateWindowsString(); + + // Query the current system proxy + WinHttpGetIEProxyConfigForCurrentUser(&proxyConfig); + + // Open the HTTP session with the system proxy configuration if available + if (!(httpSessionHandle = WinHttpOpen( + NULL, + proxyConfig.lpszProxy ? WINHTTP_ACCESS_TYPE_NAMED_PROXY : WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY, + proxyConfig.lpszProxy, + proxyConfig.lpszProxyBypass, + 0 + ))) + { + Context->ErrorCode = GetLastError(); + goto CleanupExit; + } + + if (WindowsVersion >= WINDOWS_8_1) + { + ULONG httpFlags = WINHTTP_DECOMPRESSION_FLAG_GZIP | WINHTTP_DECOMPRESSION_FLAG_DEFLATE; + + WinHttpSetOption( + httpSessionHandle, + WINHTTP_OPTION_DECOMPRESSION, + &httpFlags, + sizeof(ULONG) + ); + } + + if (!(httpConnectionHandle = WinHttpConnect( + httpSessionHandle, + L"wj32.org", + INTERNET_DEFAULT_HTTPS_PORT, + 0 + ))) + { + Context->ErrorCode = GetLastError(); + goto CleanupExit; + } + + if (!(httpRequestHandle = WinHttpOpenRequest( + httpConnectionHandle, + NULL, + L"/processhacker/plugins/nightly.php", + NULL, + WINHTTP_NO_REFERER, + WINHTTP_DEFAULT_ACCEPT_TYPES, + WINHTTP_FLAG_REFRESH | WINHTTP_FLAG_SECURE + ))) + { + Context->ErrorCode = GetLastError(); + goto CleanupExit; + } + + if (WindowsVersion >= WINDOWS_7) + { + ULONG keepAlive = WINHTTP_DISABLE_KEEP_ALIVE; + WinHttpSetOption(httpRequestHandle, WINHTTP_OPTION_DISABLE_FEATURE, &keepAlive, sizeof(ULONG)); + } + + if (versionHeader) + { + WinHttpAddRequestHeaders( + httpRequestHandle, + versionHeader->Buffer, + (ULONG)versionHeader->Length / sizeof(WCHAR), + WINHTTP_ADDREQ_FLAG_ADD + ); + } + + if (windowsHeader) + { + WinHttpAddRequestHeaders( + httpRequestHandle, + windowsHeader->Buffer, + (ULONG)windowsHeader->Length / sizeof(WCHAR), + WINHTTP_ADDREQ_FLAG_ADD + ); + } + + if (!WinHttpSendRequest( + httpRequestHandle, + WINHTTP_NO_ADDITIONAL_HEADERS, + 0, + WINHTTP_NO_REQUEST_DATA, + 0, + WINHTTP_IGNORE_REQUEST_TOTAL_LENGTH, + 0 + )) + { + Context->ErrorCode = GetLastError(); + goto CleanupExit; + } + + if (!WinHttpReceiveResponse(httpRequestHandle, NULL)) + { + Context->ErrorCode = GetLastError(); + goto CleanupExit; + } + + if (!ReadRequestString(httpRequestHandle, &stringBuffer, &stringBufferLength)) + goto CleanupExit; + + // Check the buffer for valid data + if (stringBuffer == NULL || stringBuffer[0] == '\0') + goto CleanupExit; + + if (!(jsonObject = CreateJsonParser(stringBuffer))) + goto CleanupExit; + + Context->Version = PhConvertUtf8ToUtf16(GetJsonValueAsString(jsonObject, "version")); + Context->RevVersion = PhConvertUtf8ToUtf16(GetJsonValueAsString(jsonObject, "version")); + Context->RelDate = PhConvertUtf8ToUtf16(GetJsonValueAsString(jsonObject, "updated")); + Context->Size = PhFormatSize(GetJsonValueAsUlong(jsonObject, "size"), 2); + Context->Hash = PhConvertUtf8ToUtf16(GetJsonValueAsString(jsonObject, "hash_setup")); + Context->Signature = PhConvertUtf8ToUtf16(GetJsonValueAsString(jsonObject, "sig")); + Context->ReleaseNotesUrl = PhConvertUtf8ToUtf16(GetJsonValueAsString(jsonObject, "forum_url")); + Context->SetupFileDownloadUrl = PhConvertUtf8ToUtf16(GetJsonValueAsString(jsonObject, "setup_url")); + Context->BuildMessage = PhConvertUtf8ToUtf16(GetJsonValueAsString(jsonObject, "message")); + + CleanupJsonParser(jsonObject); + + if (PhIsNullOrEmptyString(Context->Signature)) + goto CleanupExit; + + if (!ParseVersionString(Context)) + goto CleanupExit; + + if (PhIsNullOrEmptyString(Context->Version)) + goto CleanupExit; + if (PhIsNullOrEmptyString(Context->RevVersion)) + goto CleanupExit; + if (PhIsNullOrEmptyString(Context->RelDate)) + goto CleanupExit; + if (PhIsNullOrEmptyString(Context->Size)) + goto CleanupExit; + if (PhIsNullOrEmptyString(Context->Hash)) + goto CleanupExit; + if (PhIsNullOrEmptyString(Context->ReleaseNotesUrl)) + goto CleanupExit; + if (PhIsNullOrEmptyString(Context->SetupFileDownloadUrl)) + goto CleanupExit; + + success = TRUE; + +CleanupExit: + + if (httpRequestHandle) + WinHttpCloseHandle(httpRequestHandle); + + if (httpConnectionHandle) + WinHttpCloseHandle(httpConnectionHandle); + + if (httpSessionHandle) + WinHttpCloseHandle(httpSessionHandle); + + if (xmlNode) + mxmlDelete(xmlNode); + + if (stringBuffer) + PhFree(stringBuffer); + + PhClearReference(&versionHeader); + PhClearReference(&windowsHeader); + + return success; +} + +NTSTATUS UpdateCheckSilentThread( + _In_ PVOID Parameter + ) +{ + PPH_UPDATER_CONTEXT context = NULL; + ULONGLONG currentVersion = 0; + ULONGLONG latestVersion = 0; + + context = CreateUpdateContext(TRUE); + +#ifndef FORCE_UPDATE_CHECK + if (!LastUpdateCheckExpired()) + goto CleanupExit; +#endif + if (!QueryUpdateData(context)) + goto CleanupExit; + + currentVersion = MAKE_VERSION_ULONGLONG( + context->CurrentMajorVersion, + context->CurrentMinorVersion, + context->CurrentRevisionVersion, + 0 + ); + +#ifdef FORCE_UPDATE_CHECK + latestVersion = MAKE_VERSION_ULONGLONG( + 9999, + 9999, + 9999, + 0 + ); +#else + latestVersion = MAKE_VERSION_ULONGLONG( + context->MajorVersion, + context->MinorVersion, + context->RevisionVersion, + 0 + ); +#endif + + // Compare the current version against the latest available version + if (currentVersion < latestVersion) + { + // Don't spam the user the second they open PH, delay dialog creation for 3 seconds. + //Sleep(3000); + + // Check if the user hasn't already opened the dialog. + if (!UpdateDialogHandle) + { + // We have data we're going to cache and pass into the dialog + context->HaveData = TRUE; + + // Show the dialog asynchronously on a new thread. + ShowUpdateDialog(context); + } + } + +CleanupExit: + + if (!context->HaveData) + FreeUpdateContext(context); + + return STATUS_SUCCESS; +} + +NTSTATUS UpdateCheckThread( + _In_ PVOID Parameter + ) +{ + PPH_UPDATER_CONTEXT context = NULL; + ULONGLONG currentVersion = 0; + ULONGLONG latestVersion = 0; + + context = (PPH_UPDATER_CONTEXT)Parameter; + context->ErrorCode = STATUS_SUCCESS; + + // Check if we have cached update data + if (!context->HaveData) + { + context->HaveData = QueryUpdateData(context); + } + + if (!context->HaveData) + { + PostMessage(context->DialogHandle, PH_UPDATEISERRORED, 0, 0); + + PhDereferenceObject(context); + return STATUS_SUCCESS; + } + + currentVersion = MAKE_VERSION_ULONGLONG( + context->CurrentMajorVersion, + context->CurrentMinorVersion, + context->CurrentRevisionVersion, + 0 + ); + +#ifdef FORCE_UPDATE_CHECK + latestVersion = MAKE_VERSION_ULONGLONG( + 9999, + 9999, + 9999, + 0 + ); +#else + latestVersion = MAKE_VERSION_ULONGLONG( + context->MajorVersion, + context->MinorVersion, + context->RevisionVersion, + 0 + ); +#endif + + if (currentVersion == latestVersion) + { + // User is running the latest version + PostMessage(context->DialogHandle, PH_UPDATEISCURRENT, 0, 0); + } + else if (currentVersion > latestVersion) + { + // User is running a newer version + PostMessage(context->DialogHandle, PH_UPDATENEWER, 0, 0); + } + else + { + // User is running an older version + PostMessage(context->DialogHandle, PH_UPDATEAVAILABLE, 0, 0); + } + + PhDereferenceObject(context); + return STATUS_SUCCESS; +} + +NTSTATUS UpdateDownloadThread( + _In_ PVOID Parameter + ) +{ + BOOLEAN downloadSuccess = FALSE; + BOOLEAN hashSuccess = FALSE; + BOOLEAN signatureSuccess = FALSE; + HANDLE tempFileHandle = NULL; + HINTERNET httpSessionHandle = NULL; + HINTERNET httpConnectionHandle = NULL; + HINTERNET httpRequestHandle = NULL; + PPH_STRING setupTempPath = NULL; + PPH_STRING downloadHostPath = NULL; + PPH_STRING downloadUrlPath = NULL; + PPH_STRING userAgentString = NULL; + PPH_STRING fullSetupPath = NULL; + PPH_STRING randomGuidString = NULL; + PUPDATER_HASH_CONTEXT hashContext = NULL; + ULONG indexOfFileName = -1; + GUID randomGuid; + URL_COMPONENTS httpUrlComponents = { sizeof(URL_COMPONENTS) }; + WINHTTP_CURRENT_USER_IE_PROXY_CONFIG proxyConfig = { 0 }; + LARGE_INTEGER timeNow; + LARGE_INTEGER timeStart; + ULONG64 timeTicks = 0; + ULONG64 timeBitsPerSecond = 0; + PPH_UPDATER_CONTEXT context = (PPH_UPDATER_CONTEXT)Parameter; + + SendMessage(context->DialogHandle, TDM_UPDATE_ELEMENT_TEXT, TDE_MAIN_INSTRUCTION, (LPARAM)L"Initializing download request..."); + + // Create a user agent string. + userAgentString = PhFormatString( + L"PH_%lu.%lu_%lu", + context->CurrentMajorVersion, + context->CurrentMinorVersion, + context->CurrentRevisionVersion + ); + if (PhIsNullOrEmptyString(userAgentString)) + goto CleanupExit; + + setupTempPath = PhCreateStringEx(NULL, GetTempPath(0, NULL) * sizeof(WCHAR)); + if (PhIsNullOrEmptyString(setupTempPath)) + goto CleanupExit; + + if (GetTempPath((ULONG)setupTempPath->Length / sizeof(WCHAR), setupTempPath->Buffer) == 0) + goto CleanupExit; + if (PhIsNullOrEmptyString(setupTempPath)) + goto CleanupExit; + + // Generate random guid for our directory path. + PhGenerateGuid(&randomGuid); + + if (randomGuidString = PhFormatGuid(&randomGuid)) + { + PPH_STRING guidSubString; + + // Strip the left and right curly brackets. + guidSubString = PhSubstring(randomGuidString, 1, randomGuidString->Length / sizeof(WCHAR) - 2); + + PhMoveReference(&randomGuidString, guidSubString); + } + + // Append the tempath to our string: %TEMP%RandomString\\processhacker-%lu.%lu-setup.exe + // Example: C:\\Users\\dmex\\AppData\\Temp\\ABCD\\processhacker-2.90-setup.exe + context->SetupFilePath = PhFormatString( + L"%s%s\\processhacker-%lu.%lu-setup.exe", + PhGetStringOrEmpty(setupTempPath), + PhGetStringOrEmpty(randomGuidString), + context->MajorVersion, + context->MinorVersion + ); + if (PhIsNullOrEmptyString(context->SetupFilePath)) + goto CleanupExit; + + // Create the directory if it does not exist. + if (fullSetupPath = PhGetFullPath(PhGetString(context->SetupFilePath), &indexOfFileName)) + { + PPH_STRING directoryPath; + + if (indexOfFileName == -1) + goto CleanupExit; + + if (directoryPath = PhSubstring(fullSetupPath, 0, indexOfFileName)) + { + SHCreateDirectoryEx(NULL, directoryPath->Buffer, NULL); + PhDereferenceObject(directoryPath); + } + } + + // Create output file + if (!NT_SUCCESS(PhCreateFileWin32( + &tempFileHandle, + PhGetString(context->SetupFilePath), + FILE_GENERIC_READ | FILE_GENERIC_WRITE, + FILE_ATTRIBUTE_NOT_CONTENT_INDEXED | FILE_ATTRIBUTE_TEMPORARY, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + FILE_OVERWRITE_IF, + FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT + ))) + { + goto CleanupExit; + } + + // Set lengths to non-zero enabling these params to be cracked. + httpUrlComponents.dwSchemeLength = (ULONG)-1; + httpUrlComponents.dwHostNameLength = (ULONG)-1; + httpUrlComponents.dwUrlPathLength = (ULONG)-1; + + if (!WinHttpCrackUrl( + PhGetStringOrEmpty(context->SetupFileDownloadUrl), + 0, + 0, + &httpUrlComponents + )) + { + context->ErrorCode = GetLastError(); + goto CleanupExit; + } + + // Create the Host string. + downloadHostPath = PhCreateStringEx( + httpUrlComponents.lpszHostName, + httpUrlComponents.dwHostNameLength * sizeof(WCHAR) + ); + if (PhIsNullOrEmptyString(downloadHostPath)) + goto CleanupExit; + + // Create the Path string. + downloadUrlPath = PhCreateStringEx( + httpUrlComponents.lpszUrlPath, + httpUrlComponents.dwUrlPathLength * sizeof(WCHAR) + ); + if (PhIsNullOrEmptyString(downloadUrlPath)) + goto CleanupExit; + + SendMessage(context->DialogHandle, TDM_UPDATE_ELEMENT_TEXT, TDE_MAIN_INSTRUCTION, (LPARAM)L"Connecting..."); + + // Query the current system proxy + WinHttpGetIEProxyConfigForCurrentUser(&proxyConfig); + + // Open the HTTP session with the system proxy configuration if available + if (!(httpSessionHandle = WinHttpOpen( + PhGetStringOrEmpty(userAgentString), + proxyConfig.lpszProxy ? WINHTTP_ACCESS_TYPE_NAMED_PROXY : WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, + proxyConfig.lpszProxy, + proxyConfig.lpszProxyBypass, + 0 + ))) + { + context->ErrorCode = GetLastError(); + goto CleanupExit; + } + + if (WindowsVersion >= WINDOWS_8_1) + { + ULONG httpFlags = WINHTTP_DECOMPRESSION_FLAG_GZIP | WINHTTP_DECOMPRESSION_FLAG_DEFLATE; + + WinHttpSetOption( + httpSessionHandle, + WINHTTP_OPTION_DECOMPRESSION, + &httpFlags, + sizeof(ULONG) + ); + } + + if (!(httpConnectionHandle = WinHttpConnect( + httpSessionHandle, + PhGetStringOrEmpty(downloadHostPath), + httpUrlComponents.nScheme == INTERNET_SCHEME_HTTP ? INTERNET_DEFAULT_HTTP_PORT : INTERNET_DEFAULT_HTTPS_PORT, + 0 + ))) + { + context->ErrorCode = GetLastError(); + goto CleanupExit; + } + + if (!(httpRequestHandle = WinHttpOpenRequest( + httpConnectionHandle, + NULL, + PhGetStringOrEmpty(downloadUrlPath), + NULL, + WINHTTP_NO_REFERER, + WINHTTP_DEFAULT_ACCEPT_TYPES, + WINHTTP_FLAG_REFRESH | (httpUrlComponents.nScheme == INTERNET_SCHEME_HTTPS ? WINHTTP_FLAG_SECURE : 0) + ))) + { + context->ErrorCode = GetLastError(); + goto CleanupExit; + } + + if (WindowsVersion >= WINDOWS_7) + { + ULONG keepAlive = WINHTTP_DISABLE_KEEP_ALIVE; + WinHttpSetOption(httpRequestHandle, WINHTTP_OPTION_DISABLE_FEATURE, &keepAlive, sizeof(ULONG)); + } + + SendMessage(context->DialogHandle, TDM_UPDATE_ELEMENT_TEXT, TDE_MAIN_INSTRUCTION, (LPARAM)L"Sending download request..."); + + if (!WinHttpSendRequest( + httpRequestHandle, + WINHTTP_NO_ADDITIONAL_HEADERS, + 0, + WINHTTP_NO_REQUEST_DATA, + 0, + WINHTTP_IGNORE_REQUEST_TOTAL_LENGTH, + 0 + )) + { + context->ErrorCode = GetLastError(); + goto CleanupExit; + } + + SendMessage(context->DialogHandle, TDM_UPDATE_ELEMENT_TEXT, TDE_MAIN_INSTRUCTION, (LPARAM)L"Waiting for response..."); + + if (!WinHttpReceiveResponse(httpRequestHandle, NULL)) + { + context->ErrorCode = GetLastError(); + goto CleanupExit; + } + else + { + ULONG bytesDownloaded = 0; + ULONG downloadedBytes = 0; + ULONG contentLengthSize = sizeof(ULONG); + ULONG contentLength = 0; + PPH_STRING status; + IO_STATUS_BLOCK isb; + BYTE buffer[PAGE_SIZE]; + + status = PhFormatString(L"Downloading update %lu.%lu.%lu...", + context->MajorVersion, + context->MinorVersion, + context->RevisionVersion + ); + + SendMessage(context->DialogHandle, TDM_SET_MARQUEE_PROGRESS_BAR, FALSE, 0); + SendMessage(context->DialogHandle, TDM_UPDATE_ELEMENT_TEXT, TDE_MAIN_INSTRUCTION, (LPARAM)status->Buffer); + PhDereferenceObject(status); + + // Start the clock. + PhQuerySystemTime(&timeStart); + + if (!WinHttpQueryHeaders( + httpRequestHandle, + WINHTTP_QUERY_CONTENT_LENGTH | WINHTTP_QUERY_FLAG_NUMBER, + WINHTTP_HEADER_NAME_BY_INDEX, + &contentLength, + &contentLengthSize, + 0 + )) + { + context->ErrorCode = GetLastError(); + goto CleanupExit; + } + + // Initialize hash algorithm. + if (!(hashContext = UpdaterInitializeHash())) + goto CleanupExit; + + // Zero the buffer. + memset(buffer, 0, PAGE_SIZE); + + // Download the data. + while (WinHttpReadData(httpRequestHandle, buffer, PAGE_SIZE, &bytesDownloaded)) + { + // If we get zero bytes, the file was uploaded or there was an error + if (bytesDownloaded == 0) + break; + + // If the dialog was closed, just cleanup and exit + if (!UpdateDialogThreadHandle) + goto CleanupExit; + + // Update the hash of bytes we downloaded. + UpdaterUpdateHash(hashContext, buffer, bytesDownloaded); + + // Write the downloaded bytes to disk. + if (!NT_SUCCESS(NtWriteFile( + tempFileHandle, + NULL, + NULL, + NULL, + &isb, + buffer, + bytesDownloaded, + NULL, + NULL + ))) + { + goto CleanupExit; + } + + downloadedBytes += (DWORD)isb.Information; + + // Check the number of bytes written are the same we downloaded. + if (bytesDownloaded != isb.Information) + goto CleanupExit; + + // Query the current time + PhQuerySystemTime(&timeNow); + + // Calculate the number of ticks + timeTicks = (timeNow.QuadPart - timeStart.QuadPart) / PH_TICKS_PER_SEC; + timeBitsPerSecond = downloadedBytes / __max(timeTicks, 1); + + // TODO: Update on timer callback. + { + FLOAT percent = ((FLOAT)downloadedBytes / contentLength * 100); + PPH_STRING totalLength = PhFormatSize(contentLength, -1); + PPH_STRING totalDownloaded = PhFormatSize(downloadedBytes, -1); + PPH_STRING totalSpeed = PhFormatSize(timeBitsPerSecond, -1); + + PPH_STRING statusMessage = PhFormatString( + L"Downloaded: %s of %s (%.0f%%)\r\nSpeed: %s/s", + PhGetStringOrEmpty(totalDownloaded), + PhGetStringOrEmpty(totalLength), + percent, + PhGetStringOrEmpty(totalSpeed) + ); + + SendMessage(context->DialogHandle, TDM_UPDATE_ELEMENT_TEXT, TDE_CONTENT, (LPARAM)statusMessage->Buffer); + SendMessage(context->DialogHandle, TDM_SET_PROGRESS_BAR_POS, (WPARAM)percent, 0); + + PhDereferenceObject(statusMessage); + PhDereferenceObject(totalSpeed); + PhDereferenceObject(totalLength); + PhDereferenceObject(totalDownloaded); + } + } + + if (UpdaterVerifyHash(hashContext, context->Hash)) + { + hashSuccess = TRUE; + } + + if (UpdaterVerifySignature(hashContext, context->Signature)) + { + signatureSuccess = TRUE; + } + + if (hashSuccess && signatureSuccess) + { + downloadSuccess = TRUE; + } + } + +CleanupExit: + + if (hashContext) + UpdaterDestroyHash(hashContext); + + if (tempFileHandle) + NtClose(tempFileHandle); + + if (httpRequestHandle) + WinHttpCloseHandle(httpRequestHandle); + + if (httpConnectionHandle) + WinHttpCloseHandle(httpConnectionHandle); + + if (httpSessionHandle) + WinHttpCloseHandle(httpSessionHandle); + + PhClearReference(&randomGuidString); + PhClearReference(&fullSetupPath); + PhClearReference(&setupTempPath); + PhClearReference(&downloadHostPath); + PhClearReference(&downloadUrlPath); + PhClearReference(&userAgentString); + + if (UpdateDialogThreadHandle) + { + if (downloadSuccess && hashSuccess && signatureSuccess) + { + PostMessage(context->DialogHandle, PH_UPDATESUCCESS, 0, 0); + } + else if (downloadSuccess) + { + PostMessage(context->DialogHandle, PH_UPDATEFAILURE, signatureSuccess, hashSuccess); + } + else + { + PostMessage(context->DialogHandle, PH_UPDATEISERRORED, 0, 0); + } + } + + PhDereferenceObject(context); + return STATUS_SUCCESS; +} + +LRESULT CALLBACK TaskDialogSubclassProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam, + _In_ UINT_PTR uIdSubclass, + _In_ ULONG_PTR dwRefData + ) +{ + PPH_UPDATER_CONTEXT context = (PPH_UPDATER_CONTEXT)dwRefData; + + switch (uMsg) + { + case WM_NCDESTROY: + { + RemoveWindowSubclass(hwndDlg, TaskDialogSubclassProc, uIdSubclass); + } + break; + case WM_SHOWDIALOG: + { + if (IsMinimized(hwndDlg)) + ShowWindow(hwndDlg, SW_RESTORE); + else + ShowWindow(hwndDlg, SW_SHOW); + + SetForegroundWindow(hwndDlg); + } + break; + case PH_UPDATEAVAILABLE: + { + ShowAvailableDialog(context); + } + break; + case PH_UPDATEISCURRENT: + { + ShowLatestVersionDialog(context); + } + break; + case PH_UPDATENEWER: + { + ShowNewerVersionDialog(context); + } + break; + case PH_UPDATESUCCESS: + { + ShowUpdateInstallDialog(context); + } + break; + case PH_UPDATEFAILURE: + { + if ((BOOLEAN)wParam) + ShowUpdateFailedDialog(context, TRUE, FALSE); + else if ((BOOLEAN)lParam) + ShowUpdateFailedDialog(context, FALSE, TRUE); + else + ShowUpdateFailedDialog(context, FALSE, FALSE); + } + break; + case PH_UPDATEISERRORED: + { + ShowUpdateFailedDialog(context, FALSE, FALSE); + } + break; + //case WM_PARENTNOTIFY: + // { + // if (wParam == WM_CREATE) + // { + // // uMsg == 49251 for expand/collapse button click + // HWND hwndEdit = CreateWindowEx( + // WS_EX_CLIENTEDGE, + // L"EDIT", + // NULL, + // WS_CHILD | WS_VISIBLE | WS_VSCROLL | ES_LEFT | ES_MULTILINE | ES_AUTOVSCROLL, + // 5, + // 5, + // 390, + // 85, + // (HWND)lParam, // parent window + // 0, + // NULL, + // NULL + // ); + // + // PhCreateCommonFont(-11, hwndEdit); + // + // // Add text to the window. + // SendMessage(hwndEdit, WM_SETTEXT, 0, (LPARAM)L"TEST"); + // } + // } + // break; + //case WM_NCACTIVATE: + // { + // if (IsWindowVisible(PhMainWndHandle) && !IsMinimized(PhMainWndHandle)) + // { + // if (!context->FixedWindowStyles) + // { + // SetWindowLongPtr(hwndDlg, GWLP_HWNDPARENT, (LONG_PTR)PhMainWndHandle); + // PhSetWindowExStyle(hwndDlg, WS_EX_APPWINDOW, WS_EX_APPWINDOW); + // context->FixedWindowStyles = TRUE; + // } + // } + // } + // break; + } + + return DefSubclassProc(hwndDlg, uMsg, wParam, lParam); +} + +HRESULT CALLBACK TaskDialogBootstrapCallback( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam, + _In_ LONG_PTR dwRefData + ) +{ + PPH_UPDATER_CONTEXT context = (PPH_UPDATER_CONTEXT)dwRefData; + + switch (uMsg) + { + case TDN_CREATED: + { + UpdateDialogHandle = context->DialogHandle = hwndDlg; + + // Center the update window on PH if it's visible else we center on the desktop. + PhCenterWindow(hwndDlg, (IsWindowVisible(PhMainWndHandle) && !IsMinimized(PhMainWndHandle)) ? PhMainWndHandle : NULL); + + // Create the Taskdialog icons + TaskDialogCreateIcons(context); + + // Subclass the Taskdialog + SetWindowSubclass(hwndDlg, TaskDialogSubclassProc, 0, (ULONG_PTR)context); + + if (context->StartupCheck) + { + ShowAvailableDialog(context); + } + else + { + ShowCheckForUpdatesDialog(context); + } + } + break; + } + + return S_OK; +} + +NTSTATUS ShowUpdateDialogThread( + _In_ PVOID Parameter + ) +{ + PH_AUTO_POOL autoPool; + PPH_UPDATER_CONTEXT context; + TASKDIALOGCONFIG config = { sizeof(TASKDIALOGCONFIG) }; + + if (Parameter) + context = (PPH_UPDATER_CONTEXT)Parameter; + else + context = CreateUpdateContext(FALSE); + + PhInitializeAutoPool(&autoPool); + + // Start TaskDialog bootstrap + config.dwFlags = TDF_ALLOW_DIALOG_CANCELLATION | TDF_CAN_BE_MINIMIZED; + config.pszContent = L"Initializing..."; + config.lpCallbackData = (LONG_PTR)context; + config.pfCallback = TaskDialogBootstrapCallback; + TaskDialogIndirect(&config, NULL, NULL, NULL); + + FreeUpdateContext(context); + PhDeleteAutoPool(&autoPool); + + if (UpdateDialogThreadHandle) + { + NtClose(UpdateDialogThreadHandle); + UpdateDialogThreadHandle = NULL; + } + + PhResetEvent(&InitializedEvent); + + return STATUS_SUCCESS; +} + +VOID ShowUpdateDialog( + _In_opt_ PPH_UPDATER_CONTEXT Context + ) +{ + if (!UpdateDialogThreadHandle) + { + if (!(UpdateDialogThreadHandle = PhCreateThread(0, ShowUpdateDialogThread, Context))) + { + PhShowStatus(PhMainWndHandle, L"Unable to create the updater window.", 0, GetLastError()); + return; + } + + PhWaitForEvent(&InitializedEvent, NULL); + } + + PostMessage(UpdateDialogHandle, WM_SHOWDIALOG, 0, 0); +} + +VOID StartInitialCheck( + VOID + ) +{ + HANDLE silentCheckThread = NULL; + + if (silentCheckThread = PhCreateThread(0, UpdateCheckSilentThread, NULL)) + NtClose(silentCheckThread); } \ No newline at end of file diff --git a/plugins/Updater/updater.h b/plugins/Updater/updater.h index 2a5cafa71846..b2032e6f432d 100644 --- a/plugins/Updater/updater.h +++ b/plugins/Updater/updater.h @@ -1,220 +1,225 @@ -/* - * Process Hacker Plugins - - * Update Checker Plugin - * - * Copyright (C) 2011-2015 dmex - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#ifndef __UPDATER_H__ -#define __UPDATER_H__ - -#define CINTERFACE -#define COBJMACROS -#define INITGUID -#include -#include -#include -#include -#include -#include -#include - -#include "resource.h" - -#define UPDATE_MENUITEM 1001 -#define PH_UPDATEISERRORED (WM_APP + 501) -#define PH_UPDATEAVAILABLE (WM_APP + 502) -#define PH_UPDATEISCURRENT (WM_APP + 503) -#define PH_UPDATENEWER (WM_APP + 504) -#define PH_UPDATESUCCESS (WM_APP + 505) -#define PH_UPDATEFAILURE (WM_APP + 506) -#define WM_SHOWDIALOG (WM_APP + 550) - -#define PLUGIN_NAME L"ProcessHacker.UpdateChecker" -#define SETTING_NAME_AUTO_CHECK (PLUGIN_NAME L".PromptStart") -#define SETTING_NAME_LAST_CHECK (PLUGIN_NAME L".LastUpdateCheckTime") -#define SETTING_NAME_NIGHTLY_BUILD (PLUGIN_NAME L".NightlyBuilds") - -#define MAKE_VERSION_ULONGLONG(major, minor, build, revision) \ - (((ULONGLONG)(major) << 48) | \ - ((ULONGLONG)(minor) << 32) | \ - ((ULONGLONG)(build) << 16) | \ - ((ULONGLONG)(revision) << 0)) - -#ifdef _DEBUG -// Force update checks to succeed (most of the below flags require this to be defined). -//#define FORCE_UPDATE_CHECK -// Force update check to show the current version as the latest version. -//#define FORCE_LATEST_VERSION -#endif - -extern HWND UpdateDialogHandle; -extern PH_EVENT InitializedEvent; -extern PPH_PLUGIN PluginInstance; - -typedef struct _PH_UPDATER_CONTEXT -{ - union - { - BOOLEAN Flags; - struct - { - BOOLEAN StartupCheck : 1; - BOOLEAN HaveData : 1; - BOOLEAN FixedWindowStyles : 1; - BOOLEAN Spare : 5; - }; - }; - - HICON IconSmallHandle; - HICON IconLargeHandle; - - HWND DialogHandle; - - ULONG ErrorCode; - ULONG MinorVersion; - ULONG MajorVersion; - ULONG RevisionVersion; - ULONG CurrentMinorVersion; - ULONG CurrentMajorVersion; - ULONG CurrentRevisionVersion; - PPH_STRING Version; - PPH_STRING RevVersion; - PPH_STRING RelDate; - PPH_STRING Size; - PPH_STRING Hash; - PPH_STRING Signature; - PPH_STRING ReleaseNotesUrl; - PPH_STRING SetupFileDownloadUrl; - PPH_STRING SetupFilePath; - - // Nightly builds only - PPH_STRING BuildMessage; -} PH_UPDATER_CONTEXT, *PPH_UPDATER_CONTEXT; - -VOID TaskDialogLinkClicked( - _In_ PPH_UPDATER_CONTEXT Context - ); - -NTSTATUS UpdateCheckThread( - _In_ PVOID Parameter - ); - -NTSTATUS UpdateDownloadThread( - _In_ PVOID Parameter - ); - -// page1.c -VOID ShowCheckForUpdatesDialog( - _In_ PPH_UPDATER_CONTEXT Context - ); - -// page2.c -VOID ShowCheckingForUpdatesDialog( - _In_ PPH_UPDATER_CONTEXT Context - ); - -// page3.c -VOID ShowAvailableDialog( - _In_ PPH_UPDATER_CONTEXT Context - ); - -// page4.c -VOID ShowProgressDialog( - _In_ PPH_UPDATER_CONTEXT Context - ); - -// page5.c - -VOID ShowUpdateInstallDialog( - _In_ PPH_UPDATER_CONTEXT Context - ); - -VOID ShowLatestVersionDialog( - _In_ PPH_UPDATER_CONTEXT Context - ); - -VOID ShowNewerVersionDialog( - _In_ PPH_UPDATER_CONTEXT Context - ); - -VOID ShowUpdateFailedDialog( - _In_ PPH_UPDATER_CONTEXT Context, - _In_ BOOLEAN HashFailed, - _In_ BOOLEAN SignatureFailed - ); - -// updater.c - -VOID ShowUpdateDialog( - _In_opt_ PPH_UPDATER_CONTEXT Context - ); - -VOID StartInitialCheck( - VOID - ); - -BOOLEAN UpdaterInstalledUsingSetup( - VOID - ); - -// options.c - -VOID ShowOptionsDialog( - _In_opt_ HWND Parent - ); - -// verify.c - -typedef struct _UPDATER_HASH_CONTEXT -{ - BCRYPT_ALG_HANDLE SignAlgHandle; - BCRYPT_ALG_HANDLE HashAlgHandle; - BCRYPT_KEY_HANDLE KeyHandle; - BCRYPT_HASH_HANDLE HashHandle; - ULONG HashObjectSize; - ULONG HashSize; - PVOID HashObject; - PVOID Hash; -} UPDATER_HASH_CONTEXT, *PUPDATER_HASH_CONTEXT; - -PUPDATER_HASH_CONTEXT UpdaterInitializeHash( - VOID - ); - -BOOLEAN UpdaterUpdateHash( - _Inout_ PUPDATER_HASH_CONTEXT Context, - _In_reads_bytes_(Length) PVOID Buffer, - _In_ ULONG Length - ); - -BOOLEAN UpdaterVerifyHash( - _Inout_ PUPDATER_HASH_CONTEXT Context, - _In_ PPH_STRING Sha2Hash - ); - -BOOLEAN UpdaterVerifySignature( - _Inout_ PUPDATER_HASH_CONTEXT Context, - _In_ PPH_STRING HexSignature - ); - -VOID UpdaterDestroyHash( - _Inout_ PUPDATER_HASH_CONTEXT Context - ); - +/* + * Process Hacker Plugins - + * Update Checker Plugin + * + * Copyright (C) 2011-2015 dmex + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#ifndef __UPDATER_H__ +#define __UPDATER_H__ + +#define CINTERFACE +#define COBJMACROS +#define INITGUID +#include +#include +#include +#include +#include +#include +#include + +#include "resource.h" + +#define UPDATE_MENUITEM 1001 +#define PH_UPDATEISERRORED (WM_APP + 501) +#define PH_UPDATEAVAILABLE (WM_APP + 502) +#define PH_UPDATEISCURRENT (WM_APP + 503) +#define PH_UPDATENEWER (WM_APP + 504) +#define PH_UPDATESUCCESS (WM_APP + 505) +#define PH_UPDATEFAILURE (WM_APP + 506) +#define WM_SHOWDIALOG (WM_APP + 550) + +#define PLUGIN_NAME L"ProcessHacker.UpdateChecker" +#define SETTING_NAME_AUTO_CHECK (PLUGIN_NAME L".PromptStart") +#define SETTING_NAME_LAST_CHECK (PLUGIN_NAME L".LastUpdateCheckTime") + +#define MAKE_VERSION_ULONGLONG(major, minor, build, revision) \ + (((ULONGLONG)(major) << 48) | \ + ((ULONGLONG)(minor) << 32) | \ + ((ULONGLONG)(build) << 16) | \ + ((ULONGLONG)(revision) << 0)) + +#ifdef _DEBUG +// Force update checks to succeed (most of the below flags require this to be defined). +//#define FORCE_UPDATE_CHECK +// Force update check to show the current version as the latest version. +//#define FORCE_LATEST_VERSION +#endif + +extern HWND UpdateDialogHandle; +extern PH_EVENT InitializedEvent; +extern PPH_PLUGIN PluginInstance; + +typedef struct _PH_UPDATER_CONTEXT +{ + union + { + BOOLEAN Flags; + struct + { + BOOLEAN StartupCheck : 1; + BOOLEAN HaveData : 1; + BOOLEAN FixedWindowStyles : 1; + BOOLEAN Spare : 5; + }; + }; + + HICON IconSmallHandle; + HICON IconLargeHandle; + + HWND DialogHandle; + + ULONG ErrorCode; + ULONG MinorVersion; + ULONG MajorVersion; + ULONG RevisionVersion; + ULONG CurrentMinorVersion; + ULONG CurrentMajorVersion; + ULONG CurrentRevisionVersion; + PPH_STRING Version; + PPH_STRING RevVersion; + PPH_STRING RelDate; + PPH_STRING Size; + PPH_STRING Hash; + PPH_STRING Signature; + PPH_STRING ReleaseNotesUrl; + PPH_STRING SetupFileDownloadUrl; + PPH_STRING SetupFilePath; + + // Nightly builds only + PPH_STRING BuildMessage; +} PH_UPDATER_CONTEXT, *PPH_UPDATER_CONTEXT; + +VOID TaskDialogLinkClicked( + _In_ PPH_UPDATER_CONTEXT Context + ); + +NTSTATUS UpdateCheckThread( + _In_ PVOID Parameter + ); + +NTSTATUS UpdateDownloadThread( + _In_ PVOID Parameter + ); + +// page1.c +VOID ShowCheckForUpdatesDialog( + _In_ PPH_UPDATER_CONTEXT Context + ); + +// page2.c +VOID ShowCheckingForUpdatesDialog( + _In_ PPH_UPDATER_CONTEXT Context + ); + +// page3.c +VOID ShowAvailableDialog( + _In_ PPH_UPDATER_CONTEXT Context + ); + +// page4.c +VOID ShowProgressDialog( + _In_ PPH_UPDATER_CONTEXT Context + ); + +// page5.c + +VOID ShowUpdateInstallDialog( + _In_ PPH_UPDATER_CONTEXT Context + ); + +VOID ShowLatestVersionDialog( + _In_ PPH_UPDATER_CONTEXT Context + ); + +VOID ShowNewerVersionDialog( + _In_ PPH_UPDATER_CONTEXT Context + ); + +VOID ShowUpdateFailedDialog( + _In_ PPH_UPDATER_CONTEXT Context, + _In_ BOOLEAN HashFailed, + _In_ BOOLEAN SignatureFailed + ); + +// updater.c + +VOID ShowUpdateDialog( + _In_opt_ PPH_UPDATER_CONTEXT Context + ); + +VOID StartInitialCheck( + VOID + ); + +BOOLEAN UpdaterInstalledUsingSetup( + VOID + ); + +// options.c + +VOID ShowOptionsDialog( + _In_opt_ HWND Parent + ); + +// verify.c + +typedef struct _UPDATER_HASH_CONTEXT +{ + BCRYPT_ALG_HANDLE SignAlgHandle; + BCRYPT_ALG_HANDLE HashAlgHandle; + BCRYPT_KEY_HANDLE KeyHandle; + BCRYPT_HASH_HANDLE HashHandle; + ULONG HashObjectSize; + ULONG HashSize; + PVOID HashObject; + PVOID Hash; +} UPDATER_HASH_CONTEXT, *PUPDATER_HASH_CONTEXT; + +PUPDATER_HASH_CONTEXT UpdaterInitializeHash( + VOID + ); + +BOOLEAN UpdaterUpdateHash( + _Inout_ PUPDATER_HASH_CONTEXT Context, + _In_reads_bytes_(Length) PVOID Buffer, + _In_ ULONG Length + ); + +BOOLEAN UpdaterVerifyHash( + _Inout_ PUPDATER_HASH_CONTEXT Context, + _In_ PPH_STRING Sha2Hash + ); + +BOOLEAN UpdaterVerifySignature( + _Inout_ PUPDATER_HASH_CONTEXT Context, + _In_ PPH_STRING HexSignature + ); + +VOID UpdaterDestroyHash( + _Inout_ PUPDATER_HASH_CONTEXT Context + ); + +// info.c + +VOID ShowLinkDialog( + _In_ PPH_UPDATER_CONTEXT Context + ); + #endif \ No newline at end of file diff --git a/plugins/Updater/verify.c b/plugins/Updater/verify.c index 80dd999d870c..c2fb55e1780c 100644 --- a/plugins/Updater/verify.c +++ b/plugins/Updater/verify.c @@ -70,35 +70,17 @@ PUPDATER_HASH_CONTEXT UpdaterInitializeHash( goto CleanupExit; } - if (PhGetIntegerSetting(SETTING_NAME_NIGHTLY_BUILD)) - { - if (!NT_SUCCESS(BCryptImportKeyPair( - hashContext->SignAlgHandle, - NULL, - BCRYPT_ECCPUBLIC_BLOB, - &hashContext->KeyHandle, - UpdaterTrustedNightlyPublicKey, - sizeof(UpdaterTrustedNightlyPublicKey), - 0 - ))) - { - goto CleanupExit; - } - } - else + if (!NT_SUCCESS(BCryptImportKeyPair( + hashContext->SignAlgHandle, + NULL, + BCRYPT_ECCPUBLIC_BLOB, + &hashContext->KeyHandle, + UpdaterTrustedNightlyPublicKey, + sizeof(UpdaterTrustedNightlyPublicKey), + 0 + ))) { - if (!NT_SUCCESS(BCryptImportKeyPair( - hashContext->SignAlgHandle, - NULL, - BCRYPT_ECCPUBLIC_BLOB, - &hashContext->KeyHandle, - UpdaterTrustedPublicKey, - sizeof(UpdaterTrustedPublicKey), - 0 - ))) - { - goto CleanupExit; - } + goto CleanupExit; } // Open the hash algorithm and allocate memory for the hash object. From 863dc81a2941f6d567cd40b43aaa91dd8608ef28 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 26 Apr 2017 02:28:58 +1000 Subject: [PATCH 0008/2058] Fix github attributes --- .gitattributes | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitattributes b/.gitattributes index 1f89c58b64ff..7d0255299ac0 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,5 +1,5 @@ -# Auto detect text files and perform LF normalization -* text=crlf +# Auto detect text files +* text=auto # Custom for Visual Studio *.cs diff=csharp From fd84dbc1b2f29bb4e24ffbe54b0955d00cf3ae1f Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 26 Apr 2017 03:16:01 +1000 Subject: [PATCH 0009/2058] CustomSetupTool: Fix uninstalling setup --- tools/CustomBuildTool/Source Files/Program.cs | 126 ++++--- .../bin/Release/CustomBuildTool.exe | Bin 143360 -> 143360 bytes .../bin/Release/CustomBuildTool.pdb | Bin 62976 -> 62976 bytes .../CustomSetupTool/CustomSetupTool.vcxproj | 1 + .../CustomSetupTool.vcxproj.filters | 3 + .../CustomSetupTool/CustomSetupTool/extract.c | 9 +- .../CustomSetupTool/include/setup.h | 21 +- tools/CustomSetupTool/CustomSetupTool/main.c | 1 + tools/CustomSetupTool/CustomSetupTool/page4.c | 15 +- tools/CustomSetupTool/CustomSetupTool/setup.c | 115 +++++- .../CustomSetupTool/uninstall.c | 326 ++++++++++++++++++ .../CustomSetupTool/CustomSetupTool/update.c | 97 ++---- 12 files changed, 572 insertions(+), 142 deletions(-) create mode 100644 tools/CustomSetupTool/CustomSetupTool/uninstall.c diff --git a/tools/CustomBuildTool/Source Files/Program.cs b/tools/CustomBuildTool/Source Files/Program.cs index 4cc566b5c6d3..8774e49e97aa 100644 --- a/tools/CustomBuildTool/Source Files/Program.cs +++ b/tools/CustomBuildTool/Source Files/Program.cs @@ -34,8 +34,7 @@ public static void Main(string[] args) Build.CleanupBuildEnvironment(); return; } - - if (ProgramArgs.ContainsKey("-updaterev")) + else if (ProgramArgs.ContainsKey("-updaterev")) { if (!Build.InitializeBuildEnvironment(false)) return; @@ -45,8 +44,7 @@ public static void Main(string[] args) Build.UpdateHeaderFileVersion(); return; } - - if (ProgramArgs.ContainsKey("-phapppub_gen")) + else if (ProgramArgs.ContainsKey("-phapppub_gen")) { if (!Build.InitializeBuildEnvironment(false)) return; @@ -55,14 +53,12 @@ public static void Main(string[] args) Build.BuildPublicHeaderFiles(); return; } - - if (ProgramArgs.ContainsKey("-sign")) + else if (ProgramArgs.ContainsKey("-sign")) { Build.BuildKphSignatureFile(); return; } - - if (ProgramArgs.ContainsKey("-cleansdk")) + else if (ProgramArgs.ContainsKey("-cleansdk")) { if (!Build.InitializeBuildEnvironment(false)) return; @@ -89,8 +85,7 @@ public static void Main(string[] args) Build.ShowBuildStats(false); return; } - - if (ProgramArgs.ContainsKey("-sdk")) + else if (ProgramArgs.ContainsKey("-sdk")) { if (!Build.InitializeBuildEnvironment(false)) return; @@ -114,8 +109,7 @@ public static void Main(string[] args) Build.ShowBuildStats(false); return; } - - if (ProgramArgs.ContainsKey("-bin")) + else if (ProgramArgs.ContainsKey("-bin")) { if (!Build.InitializeBuildEnvironment(false)) return; @@ -151,8 +145,7 @@ public static void Main(string[] args) Build.ShowBuildStats(false); return; } - - if (ProgramArgs.ContainsKey("-exe")) + else if (ProgramArgs.ContainsKey("-exe")) { if (!Build.InitializeBuildEnvironment(false)) return; @@ -167,75 +160,78 @@ public static void Main(string[] args) Build.BuildSdkZip(); return; } + else + { - if (!Build.InitializeBuildEnvironment(true)) - return; + if (!Build.InitializeBuildEnvironment(true)) + return; - PrintColorMessage("Setting up build environment...", ConsoleColor.Cyan); - Build.ShowBuildEnvironment(true); - Build.BuildSecureFiles(); + PrintColorMessage("Setting up build environment...", ConsoleColor.Cyan); + Build.ShowBuildEnvironment(true); + Build.BuildSecureFiles(); - if (!Build.BuildSolution("ProcessHacker.sln", true, true)) - return; + if (!Build.BuildSolution("ProcessHacker.sln", true, true)) + return; - PrintColorMessage("Building KPH signature...", ConsoleColor.Cyan); - if (!Build.BuildKphSignatureFile()) - return; + PrintColorMessage("Building KPH signature...", ConsoleColor.Cyan); + if (!Build.BuildKphSignatureFile()) + return; - PrintColorMessage("Copying text files...", ConsoleColor.Cyan); - if (!Build.CopyTextFiles()) - return; + PrintColorMessage("Copying text files...", ConsoleColor.Cyan); + if (!Build.CopyTextFiles()) + return; - PrintColorMessage("Copying KPH driver...", ConsoleColor.Cyan); - if (!Build.CopyKProcessHacker()) - return; + PrintColorMessage("Copying KPH driver...", ConsoleColor.Cyan); + if (!Build.CopyKProcessHacker()) + return; - PrintColorMessage("Copying SDK headers...", ConsoleColor.Cyan); - if (!Build.CopyPluginSdkHeaders()) - return; + PrintColorMessage("Copying SDK headers...", ConsoleColor.Cyan); + if (!Build.CopyPluginSdkHeaders()) + return; - PrintColorMessage("Copying version headers...", ConsoleColor.Cyan); - if (!Build.CopyVersionHeader()) - return; + PrintColorMessage("Copying version headers...", ConsoleColor.Cyan); + if (!Build.CopyVersionHeader()) + return; - PrintColorMessage("Building sdk resource header...", ConsoleColor.Cyan); - if (!Build.FixupResourceHeader()) - return; + PrintColorMessage("Building sdk resource header...", ConsoleColor.Cyan); + if (!Build.FixupResourceHeader()) + return; - PrintColorMessage("Copying plugin linker files...", ConsoleColor.Cyan); - if (!Build.CopyLibFiles()) - return; + PrintColorMessage("Copying plugin linker files...", ConsoleColor.Cyan); + if (!Build.CopyLibFiles()) + return; - if (!Build.BuildSolution("plugins\\Plugins.sln", true, true)) - return; + if (!Build.BuildSolution("plugins\\Plugins.sln", true, true)) + return; - PrintColorMessage("Copying Wow64 support files...", ConsoleColor.Cyan); - if (!Build.CopyWow64Files()) - return; + PrintColorMessage("Copying Wow64 support files...", ConsoleColor.Cyan); + if (!Build.CopyWow64Files()) + return; - PrintColorMessage("Building build-bin.zip...", ConsoleColor.Cyan); - if (!Build.BuildBinZip()) - return; + PrintColorMessage("Building build-bin.zip...", ConsoleColor.Cyan); + if (!Build.BuildBinZip()) + return; - //Build.BuildSrcZip(); - //Build.BuildSdkZip(); - //Build.BuildPdbZip(); + //Build.BuildSrcZip(); + //Build.BuildSdkZip(); + //Build.BuildPdbZip(); - PrintColorMessage("Building build-setup.exe...", ConsoleColor.Cyan); - if (!Build.BuildSetupExe()) - return; + PrintColorMessage("Building build-setup.exe...", ConsoleColor.Cyan); + if (!Build.BuildSetupExe()) + return; - PrintColorMessage("Building build-checksums.txt...", ConsoleColor.Cyan); - if (!Build.BuildChecksumsFile()) - return; + PrintColorMessage("Building build-checksums.txt...", ConsoleColor.Cyan); + if (!Build.BuildChecksumsFile()) + return; - PrintColorMessage("Building release signature...", ConsoleColor.Cyan); - if (!Build.BuildUpdateSignature()) - return; + PrintColorMessage("Building release signature...", ConsoleColor.Cyan); + if (!Build.BuildUpdateSignature()) + return; - Build.AppveyorUploadBuildFiles(); - Build.WebServiceUpdateConfig(); - Build.ShowBuildStats(true); + Build.AppveyorUploadBuildFiles(); + Build.WebServiceUpdateConfig(); + Build.ShowBuildStats(true); + } } private static Dictionary ParseArgs(string[] args) diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe b/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe index 0416602b5cdd7fcbf6f32c9600c257ccb91d5a4a..29a6995bd64d0eb702065d554efad9fe67977c92 100644 GIT binary patch delta 70 zcmZp8z|ru4V?qa$SL4Pmx2XctHdQMpXpWDF;2rH zr4z){k%3A02qt4DX5&iC!)(k)R!drsk7F4=f#tXww_q;rz&xx)R#kc(SygEtK85?S z5L+z-PZNBIMc9t(uoIubWB4qd!{_i4@>--GEWz(^1KP0+uOqKZ8o>%2#Y!B*jd+KH z5N4c)RcN`3fJKn*Mu|TUtVU0K9(`~V&c+(_!_8>KEf|6?U?{$bi*PGO<4d>%w_yVA zz;vv|mH0B3ma+-hNYZNDg}L|&7GoV&;%?lCY&2;TveBd(d;_=Po46g{!dv1nO z;5)b%8*v}LiwCfYN0-_Nn(6om*|AbLw%}=O#fx|ld+`wV;RiT`ZTKr5#$jwnjiV49 z=z>RZI)02Ecoe;{6Me8tUiv_S;~0h~FdRR@7(9tf@f0TFr_Fxl!i_O@F?bwgU@G^Gc0G`1scpeAw0{(#C zpdI`0M;yeT(4A`HE}}T*3$2J2vxLE#ZFYCmi70E4*~_S-2&nzIg5v=Wz0iq;7^=pR z)@E}OV-{FP%(04*RV9kHD&I&g1%-L}Y!*itM*v5P+Lul|PmPxo2Th1g)*I%9sms)! zOtQffMg^#G#)MJw6-;XXqr~BAEMHZ=^C0VP%Ulb^OS+T7^|P`9Li~bS&aYk@m1dxP zuE$|C;&n9P2u9-{7>j>mJl@0v97Bql5E>z+$sn~%P!y#cbVf>vPPx!}I^+wLqN^=U z>R#;7QD8H49WhvprCVnz^_-MEnZNuQrD=q*w4K~^&8_p>bH`^1A>WzYCXaLQP)h8S zxfSH((kwSB@a>aUcv1)WDk;fHIk$U+@E%Y7=Yn&|MNOHb1e1$XbL!N}nS2k4jS~h= zO6ms4ZBPd~3Olc2yfILhb*~U^6LK~~Z-hf~N#PCpZ{4J`NGSYwOi7{MAjJ248{{@Q zH#%D>-T&mQd-^Lvv<2_oC)ilyZJN*(s3Fg?|C0FLP)6I@hnwzN1Q$wbz%=7i**Ts}M=iw-F@{X08yKo-1*#`_x|MQ!~e#QN7 D??8_E delta 2247 zcmaLZdr%cs9Ki9jJQ9g(11MbcqWK3Gh=-x6B}hC<1S23IOS14)P0+)f2vE3dibX0# zn-8QK1QI7o$(xBdfYfMVqfCZbW`d#(IRwq9*pxxvv+Qk@VLIdT`JLZych9+J?>(#9 z>#X)V*Solz+e|}`D?*6(8$T-Oh$xxAV`ll(Zwiu{?H2bCkMY-*6j#J$eO{ILN3OE_ zF5heI3!~aUi>XoencckHd=KUiR5qPdwA8cSWhs94=(__I7xNACkUb|jFUe*VLS4+A z191fg;WHSFt1txfF%)eWhAM_*8P33Rycc)iEUd-Z_$l6pdoTi9a4sIfC_E~JO~eqK zCJ~37_#k%SJnX}G?8gMWfr;qMS}Z^pOhQk51kIR?6EPL7_$Y>A8irv8M&M%@tMHK) z62y^s0uyi%CL*h%X5!Ph46|@KF2$9&4D)a~<|C`7Zop@8Gd_o<_&io%HdbK{R^y9U zZzFh#-~hgi4fqN+Bg?P0U@m@-dH6H(IMlPa8ZY1)?7<=&Kt7Xt9aa7f;#wTS*YP$d zA=cp-T#vSK1jPh*;0E-;H_#W~#K~BKQ}8Xc;zkU>O&EroaT=E5Tzng&@Ev>z`JSlr zP{TBQ4;SGU=Bj2AY$LG*x8qW*z*YDGuEq~>4OZeh+==V48aHAMZo*yoF4p39+>PZ} zhdc2TtinCG7x%JO>VATH5{GafwxJ!5;eI@gU*I`BfSq^{d$AF(;32$@2M9+A%~nBXW*$FFe)wqZ0L!+87_=i_nAz!Uf+w&P;_4zuwj=3ocr z<0(|}2V9FkVk!QFThMlfU@JivR^xg67%yNQUc?5xge~|h9>yL#j=y0CUdB_{i)Zk6 z?8H92g#Bn@S22l5j+w%f9bkg6Xqkm3XOoz%Wfx8iFo`*iJf?Hp!(rz9={U`ZXK8hX z30xDdT`!E$jVO9m*IwjrGl~0+^D?+DjKj(iZ{(7R9rs*79BAZa9BRZ56FbIAAr86a ze#7%gCm&$s6Afi9DB9@AfviTHO6(X&PRcP*8nI&_InfY#p0>>vWV^y*-7bWrRjKM*SLq*{Si0qqcGO}-~spyJn=!RK17GDs; zOCM+@2|3VfIL@A`wmslf5o@;`ZnW6SVoSyg=04mMQNs@6h|6LdsBtH~jjXj!5OT*K zwdUlb@7AN%(y7VaTsAiCTL&!g6+-^(_2P({$DKm>4VT2o$plf09JLl&yn z_Y@IY>{=@?)S7b&Hu%vn$S&O75zlyS%IP5*$7MK6||4Gk9)4#s?kG%i@ diff --git a/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj b/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj index 6dd368455d93..3cce033fdf19 100644 --- a/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj +++ b/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj @@ -118,6 +118,7 @@ + diff --git a/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj.filters b/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj.filters index 1731321acc26..f3ed066b91de 100644 --- a/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj.filters +++ b/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj.filters @@ -63,6 +63,9 @@ Source Files + + Source Files + diff --git a/tools/CustomSetupTool/CustomSetupTool/extract.c b/tools/CustomSetupTool/CustomSetupTool/extract.c index 7a19147bac2d..1c600f73a771 100644 --- a/tools/CustomSetupTool/CustomSetupTool/extract.c +++ b/tools/CustomSetupTool/CustomSetupTool/extract.c @@ -50,7 +50,7 @@ PVOID GetZipResourceData( } BOOLEAN SetupExtractBuild( - _In_ PVOID Arguments + _In_ PSETUP_PROGRESS_THREAD Context ) { mz_bool status = MZ_FALSE; @@ -73,9 +73,6 @@ BOOLEAN SetupExtractBuild( //for (ULONG i = 0; i < ARRAYSIZE(SetupRemoveFiles); i++) // SetupDeleteDirectoryFile(SetupRemoveFiles[i].FileName); - if (!CreateDirectoryPath(PhGetString(SetupInstallPath))) - goto CleanupExit; - for (mz_uint i = 0; i < mz_zip_reader_get_num_files(&zip_archive); i++) { mz_zip_archive_file_stat zipFileStat; @@ -100,7 +97,7 @@ BOOLEAN SetupExtractBuild( InterlockedExchange64(&ExtractTotalLength, totalLength); } - SendMessage(Arguments, WM_START_SETUP, 0, 0); + SendMessage(Context->DialogHandle, WM_START_SETUP, 0, 0); for (mz_uint i = 0; i < mz_zip_reader_get_num_files(&zip_archive); i++) { @@ -218,7 +215,7 @@ BOOLEAN SetupExtractBuild( currentLength += bufferLength; InterlockedExchange64(&ExtractCurrentLength, currentLength); - SendMessage(Arguments, WM_UPDATE_SETUP, 0, (LPARAM)extractPath); + SendMessage(Context->DialogHandle, WM_UPDATE_SETUP, 0, (LPARAM)extractPath); NtClose(fileHandle); mz_free(buffer); diff --git a/tools/CustomSetupTool/CustomSetupTool/include/setup.h b/tools/CustomSetupTool/CustomSetupTool/include/setup.h index 2b4a6ecec879..bfbb5e84a9cf 100644 --- a/tools/CustomSetupTool/CustomSetupTool/include/setup.h +++ b/tools/CustomSetupTool/CustomSetupTool/include/setup.h @@ -128,6 +128,7 @@ typedef struct _SETUP_PROGRESS_THREAD { HWND DialogHandle; HWND PropSheetHandle; + HICON PropSheetIcon; } SETUP_PROGRESS_THREAD, *PSETUP_PROGRESS_THREAD; extern BOOLEAN SetupRunning; @@ -148,10 +149,18 @@ NTSTATUS SetupCreateUninstallKey( VOID ); +NTSTATUS SetupDeleteUninstallKey( + VOID + ); + VOID SetupSetWindowsOptions( VOID ); +VOID SetupDeleteWindowsOptions( + VOID + ); + VOID SetupCreateUninstallFile( VOID ); @@ -160,10 +169,14 @@ BOOLEAN SetupExecuteProcessHacker( _In_ HWND Parent ); +VOID SetupUpgradeSettingsFile( + VOID + ); + // extract.c BOOLEAN SetupExtractBuild( - _In_ PVOID Arguments + _In_ PSETUP_PROGRESS_THREAD Context ); // update.c @@ -172,4 +185,10 @@ VOID SetupShowUpdateDialog( VOID ); +// uninstall.c + +VOID SetupShowUninstallDialog( + VOID + ); + #endif \ No newline at end of file diff --git a/tools/CustomSetupTool/CustomSetupTool/main.c b/tools/CustomSetupTool/CustomSetupTool/main.c index 694a1809cb9c..19103442a8c2 100644 --- a/tools/CustomSetupTool/CustomSetupTool/main.c +++ b/tools/CustomSetupTool/CustomSetupTool/main.c @@ -182,6 +182,7 @@ INT WINAPI wWinMain( } break; case SETUP_COMMAND_UNINSTALL: + SetupShowUninstallDialog(); break; case SETUP_COMMAND_UPDATE: SetupShowUpdateDialog(); diff --git a/tools/CustomSetupTool/CustomSetupTool/page4.c b/tools/CustomSetupTool/CustomSetupTool/page4.c index 485fa6370bd3..d8d55b33f949 100644 --- a/tools/CustomSetupTool/CustomSetupTool/page4.c +++ b/tools/CustomSetupTool/CustomSetupTool/page4.c @@ -41,24 +41,25 @@ NTSTATUS SetupProgressThread( if (!SetupUninstallKph()) goto CleanupExit; - // Remove the previous installation. - if (SetupResetSettings) - RemoveDirectoryPath(PhGetString(SetupInstallPath)); - // Create the install folder path. if (!CreateDirectoryPath(PhGetString(SetupInstallPath))) goto CleanupExit; + SetupUpgradeSettingsFile(); + + // Remove the previous installation. + if (SetupResetSettings) + RemoveDirectoryPath(PhGetString(SetupInstallPath)); + // Create the ARP uninstall entries. SetupCreateUninstallKey(); // Create the uninstaller. SetupCreateUninstallFile(); - - // + // Create autorun and shortcuts. SetupSetWindowsOptions(); // Setup new installation. - if (!SetupExtractBuild(Context->DialogHandle)) + if (!SetupExtractBuild(Context)) goto CleanupExit; // Install updated kernel driver diff --git a/tools/CustomSetupTool/CustomSetupTool/setup.c b/tools/CustomSetupTool/CustomSetupTool/setup.c index f73deb19f54e..d32e501f5282 100644 --- a/tools/CustomSetupTool/CustomSetupTool/setup.c +++ b/tools/CustomSetupTool/CustomSetupTool/setup.c @@ -97,7 +97,33 @@ NTSTATUS SetupCreateUninstallKey( return status; } -VOID SetupFindInstallDirectory(VOID) +NTSTATUS SetupDeleteUninstallKey( + VOID + ) +{ + NTSTATUS status; + HANDLE keyHandle; + + status = PhOpenKey( + &keyHandle, + KEY_WRITE | DELETE, + PH_KEY_LOCAL_MACHINE, + &UninstallKeyName, + 0 + ); + + if (NT_SUCCESS(status)) + { + status = NtDeleteKey(keyHandle); + NtClose(keyHandle); + } + + return status; +} + +VOID SetupFindInstallDirectory( + VOID + ) { // Find the current installation path. SetupInstallPath = GetProcessHackerInstallPath(); @@ -207,7 +233,9 @@ VOID SetupInstallKph( PhDereferenceObject(clientPath); } -ULONG SetupUninstallKph(VOID) +ULONG SetupUninstallKph( + VOID + ) { ULONG status = ERROR_SUCCESS; SC_HANDLE scmHandle; @@ -273,7 +301,7 @@ VOID SetupSetWindowsOptions( if (SetupResetSettings) { - PPH_STRING settingsFileName = PhGetKnownLocation(CSIDL_APPDATA, L"\\Process Hacker 2\\settings.xml"); + PPH_STRING settingsFileName = PhGetKnownLocation(CSIDL_APPDATA, L"\\Process Hacker\\settings.xml"); SetupDeleteDirectoryFile(settingsFileName->Buffer); PhDereferenceObject(settingsFileName); @@ -359,6 +387,68 @@ VOID SetupSetWindowsOptions( } } +VOID SetupDeleteWindowsOptions( + VOID + ) +{ + static PH_STRINGREF TaskMgrImageOptionsKeyName = PH_STRINGREF_INIT(L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\taskmgr.exe"); + static PH_STRINGREF CurrentUserRunKeyName = PH_STRINGREF_INIT(L"Software\\Microsoft\\Windows\\CurrentVersion\\Run"); + PPH_STRING startmenuFolderString; + HANDLE keyHandle; + + if (startmenuFolderString = PhGetKnownLocation(CSIDL_COMMON_PROGRAMS, L"\\Process Hacker.lnk")) + { + SetupDeleteDirectoryFile(PhGetString(startmenuFolderString)); + PhDereferenceObject(startmenuFolderString); + } + + if (startmenuFolderString = PhGetKnownLocation(CSIDL_COMMON_PROGRAMS, L"\\PE Viewer.lnk")) + { + SetupDeleteDirectoryFile(PhGetString(startmenuFolderString)); + PhDereferenceObject(startmenuFolderString); + } + + if (startmenuFolderString = PhGetKnownLocation(CSIDL_DESKTOPDIRECTORY, L"\\Process Hacker.lnk")); + { + SetupDeleteDirectoryFile(PhGetString(startmenuFolderString)); + PhDereferenceObject(startmenuFolderString); + } + + if (startmenuFolderString = PhGetKnownLocation(CSIDL_COMMON_DESKTOPDIRECTORY, L"\\Process Hacker.lnk")) + { + SetupDeleteDirectoryFile(PhGetString(startmenuFolderString)); + PhDereferenceObject(startmenuFolderString); + } + + //PPH_STRING settingsFileName = PhGetKnownLocation(CSIDL_APPDATA, L"\\Process Hacker\\settings.xml"); + //SetupDeleteDirectoryFile(settingsFileName->Buffer); + //PhDereferenceObject(settingsFileName); + + if (NT_SUCCESS(PhOpenKey( + &keyHandle, + KEY_WRITE | DELETE, + PH_KEY_LOCAL_MACHINE, + &TaskMgrImageOptionsKeyName, + 0 + ))) + { + NtDeleteKey(keyHandle); + NtClose(keyHandle); + } + + if (NT_SUCCESS(PhOpenKey( + &keyHandle, + KEY_WRITE, + PH_KEY_CURRENT_USER, + &CurrentUserRunKeyName, + 0 + ))) + { + NtDeleteKey(keyHandle); + NtClose(keyHandle); + } +} + BOOLEAN SetupExecuteProcessHacker( _In_ HWND Parent ) @@ -383,4 +473,23 @@ BOOLEAN SetupExecuteProcessHacker( PhDereferenceObject(clientPath); return success; +} + +VOID SetupUpgradeSettingsFile( + VOID + ) +{ + PPH_STRING settingsFilePath; + PPH_STRING oldSettingsFileName; + + settingsFilePath = PhGetKnownLocation(CSIDL_APPDATA, L"\\Process Hacker\\settings.xml"); + oldSettingsFileName = PhGetKnownLocation(CSIDL_APPDATA, L"\\Process Hacker 2\\settings.xml"); + + if (!RtlDoesFileExists_U(settingsFilePath->Buffer)) + { + CopyFile(oldSettingsFileName->Buffer, settingsFilePath->Buffer, FALSE); + } + + PhDereferenceObject(oldSettingsFileName); + PhDereferenceObject(settingsFilePath); } \ No newline at end of file diff --git a/tools/CustomSetupTool/CustomSetupTool/uninstall.c b/tools/CustomSetupTool/CustomSetupTool/uninstall.c new file mode 100644 index 000000000000..f2d5124f120a --- /dev/null +++ b/tools/CustomSetupTool/CustomSetupTool/uninstall.c @@ -0,0 +1,326 @@ +/* + * Process Hacker Toolchain - + * project setup + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include +#include +#include + +typedef struct _PH_SETUP_UNINSTALL_CONTEXT +{ + HWND DialogHandle; + HICON IconSmallHandle; + HICON IconLargeHandle; +} PH_SETUP_UNINSTALL_CONTEXT, *PPH_SETUP_UNINSTALL_CONTEXT; + +#define WM_TASKDIALOGINIT (WM_APP + 550) +HWND UninstallDialogHandle = NULL; +HANDLE UninstallDialogThreadHandle = NULL; +PH_EVENT UninstallInitializedEvent = PH_EVENT_INIT; + +VOID ShowUninstallConfirmDialog( + _In_ PPH_SETUP_UNINSTALL_CONTEXT Context + ); +VOID ShowUninstallDialog( + _In_ PPH_SETUP_UNINSTALL_CONTEXT Context + ); +VOID ShowUninstallCompleteDialog( + _In_ PPH_SETUP_UNINSTALL_CONTEXT Context + ); +VOID ShowUninstallErrorDialog( + _In_ PPH_SETUP_UNINSTALL_CONTEXT Context + ); + +NTSTATUS SetupUninstallBuild( + _In_ PVOID Context + ) +{ + PPH_SETUP_UNINSTALL_CONTEXT context = Context; + + SetupFindInstallDirectory(); + + // Stop Process Hacker. + if (!ShutdownProcessHacker()) + goto CleanupExit; + + // Stop the kernel driver(s). + if (!SetupUninstallKph()) + goto CleanupExit; + + // Remove autorun and shortcuts. + SetupDeleteWindowsOptions(); + + // Remove the previous installation. + if (!RemoveDirectoryPath(PhGetString(SetupInstallPath))) + goto CleanupExit; + + // Remove the ARP uninstall entry. + SetupDeleteUninstallKey(); + + ShowUninstallCompleteDialog(context); + return STATUS_SUCCESS; + +CleanupExit: + ShowUninstallErrorDialog(context); + return STATUS_SUCCESS; +} + +static VOID TaskDialogCreateIcons( + _In_ PPH_SETUP_UNINSTALL_CONTEXT Context + ) +{ + HICON largeIcon; + HICON smallIcon; + + largeIcon = PhLoadIcon( + NtCurrentPeb()->ImageBaseAddress, + MAKEINTRESOURCE(IDI_ICON1), + PH_LOAD_ICON_SIZE_LARGE, + GetSystemMetrics(SM_CXICON), + GetSystemMetrics(SM_CYICON) + ); + smallIcon = PhLoadIcon( + NtCurrentPeb()->ImageBaseAddress, + MAKEINTRESOURCE(IDI_ICON1), + PH_LOAD_ICON_SIZE_LARGE, + GetSystemMetrics(SM_CXSMICON), + GetSystemMetrics(SM_CYSMICON) + ); + + Context->IconLargeHandle = largeIcon; + Context->IconSmallHandle = smallIcon; + + SendMessage(Context->DialogHandle, WM_SETICON, ICON_SMALL, (LPARAM)largeIcon); + SendMessage(Context->DialogHandle, WM_SETICON, ICON_BIG, (LPARAM)smallIcon); +} + +HRESULT CALLBACK TaskDialogUninstallConfirmCallbackProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam, + _In_ LONG_PTR dwRefData + ) +{ + PPH_SETUP_UNINSTALL_CONTEXT context = (PPH_SETUP_UNINSTALL_CONTEXT)dwRefData; + + switch (uMsg) + { + case TDN_BUTTON_CLICKED: + { + if ((INT)wParam == IDYES) + { + ShowUninstallDialog(context); + return S_FALSE; + } + else if ((INT)wParam == IDRETRY) + { + ShowUninstallCompleteDialog(context); + return S_FALSE; + } + } + break; + } + + return S_OK; +} + +HRESULT CALLBACK TaskDialogUninstallCallbackProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam, + _In_ LONG_PTR dwRefData + ) +{ + PPH_SETUP_UNINSTALL_CONTEXT context = (PPH_SETUP_UNINSTALL_CONTEXT)dwRefData; + + switch (uMsg) + { + case TDN_NAVIGATED: + { + SendMessage(hwndDlg, TDM_SET_MARQUEE_PROGRESS_BAR, TRUE, 0); + SendMessage(hwndDlg, TDM_SET_PROGRESS_BAR_MARQUEE, TRUE, 1); + + PhQueueItemWorkQueue(PhGetGlobalWorkQueue(), SetupUninstallBuild, context); + } + break; + } + + return S_OK; +} + +HRESULT CALLBACK TaskDialogUninstallCompleteCallbackProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam, + _In_ LONG_PTR dwRefData + ) +{ + PPH_SETUP_UNINSTALL_CONTEXT context = (PPH_SETUP_UNINSTALL_CONTEXT)dwRefData; + + switch (uMsg) + { + case TDN_NAVIGATED: + SendMessage(hwndDlg, TDM_SET_PROGRESS_BAR_POS, 100, 0); + break; + } + + return S_OK; +} + +VOID ShowUninstallCompleteDialog( + _In_ PPH_SETUP_UNINSTALL_CONTEXT Context + ) +{ + TASKDIALOGCONFIG config; + + memset(&config, 0, sizeof(TASKDIALOGCONFIG)); + config.cbSize = sizeof(TASKDIALOGCONFIG); + config.dwFlags = TDF_USE_HICON_MAIN | TDF_ALLOW_DIALOG_CANCELLATION | TDF_CAN_BE_MINIMIZED | TDF_SHOW_PROGRESS_BAR; + config.dwCommonButtons = TDCBF_CLOSE_BUTTON; + config.hMainIcon = Context->IconLargeHandle; + config.pfCallback = TaskDialogUninstallCompleteCallbackProc; + config.lpCallbackData = (LONG_PTR)Context; + config.pszWindowTitle = PhApplicationName; + config.pszMainInstruction = L"Process Hacker has been uninstalled."; + config.pszContent = L"Click close to exit setup."; + config.cxWidth = 200; + + SendMessage(Context->DialogHandle, TDM_NAVIGATE_PAGE, 0, (LPARAM)&config); +} + +VOID ShowUninstallConfirmDialog( + _In_ PPH_SETUP_UNINSTALL_CONTEXT Context + ) +{ + TASKDIALOGCONFIG config; + + memset(&config, 0, sizeof(TASKDIALOGCONFIG)); + config.cbSize = sizeof(TASKDIALOGCONFIG); + config.dwFlags = TDF_USE_HICON_MAIN | TDF_ALLOW_DIALOG_CANCELLATION | TDF_CAN_BE_MINIMIZED; + config.dwCommonButtons = TDCBF_YES_BUTTON | TDCBF_NO_BUTTON; + config.nDefaultButton = IDNO; + config.hMainIcon = Context->IconLargeHandle; + config.pfCallback = TaskDialogUninstallConfirmCallbackProc; + config.lpCallbackData = (LONG_PTR)Context; + config.pszWindowTitle = PhApplicationName; + config.pszMainInstruction = L"Process Hacker - Setup"; + config.pszContent = L"Are you sure you want to uninstall Process Hacker?"; + config.cxWidth = 200; + + SendMessage(Context->DialogHandle, TDM_NAVIGATE_PAGE, 0, (LPARAM)&config); +} + +VOID ShowUninstallDialog( + _In_ PPH_SETUP_UNINSTALL_CONTEXT Context + ) +{ + TASKDIALOGCONFIG config; + + memset(&config, 0, sizeof(TASKDIALOGCONFIG)); + config.cbSize = sizeof(TASKDIALOGCONFIG); + config.dwFlags = TDF_USE_HICON_MAIN | TDF_ALLOW_DIALOG_CANCELLATION | TDF_CAN_BE_MINIMIZED | TDF_SHOW_MARQUEE_PROGRESS_BAR; + config.dwCommonButtons = TDCBF_CANCEL_BUTTON; + config.hMainIcon = Context->IconLargeHandle; + config.pfCallback = TaskDialogUninstallCallbackProc; + config.lpCallbackData = (LONG_PTR)Context; + config.pszWindowTitle = PhApplicationName; + config.pszMainInstruction = L"Uninstalling Process Hacker..."; + config.cxWidth = 200; + + SendMessage(Context->DialogHandle, TDM_NAVIGATE_PAGE, 0, (LPARAM)&config); +} + +VOID ShowUninstallErrorDialog( + _In_ PPH_SETUP_UNINSTALL_CONTEXT Context + ) +{ + TASKDIALOGCONFIG config; + + memset(&config, 0, sizeof(TASKDIALOGCONFIG)); + config.cbSize = sizeof(TASKDIALOGCONFIG); + config.dwFlags = TDF_USE_HICON_MAIN | TDF_ALLOW_DIALOG_CANCELLATION | TDF_CAN_BE_MINIMIZED; + config.dwCommonButtons = TDCBF_RETRY_BUTTON | TDCBF_CLOSE_BUTTON; + config.hMainIcon = Context->IconLargeHandle; + config.pfCallback = TaskDialogUninstallConfirmCallbackProc; + config.lpCallbackData = (LONG_PTR)Context; + config.pszWindowTitle = PhApplicationName; + config.pszMainInstruction = L"Process Hacker could not be uninstalled."; + config.pszContent = L"Click retry to try again or close to exit setup."; + config.cxWidth = 200; + + SendMessage(Context->DialogHandle, TDM_NAVIGATE_PAGE, 0, (LPARAM)&config); +} +HRESULT CALLBACK TaskDialogUninstallBootstrapCallback( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam, + _In_ LONG_PTR dwRefData + ) +{ + PPH_SETUP_UNINSTALL_CONTEXT context = (PPH_SETUP_UNINSTALL_CONTEXT)dwRefData; + + switch (uMsg) + { + case TDN_CREATED: + { + context->DialogHandle = hwndDlg; + + // Center the window on the desktop + PhCenterWindow(hwndDlg, NULL); + // Create the Taskdialog icons + TaskDialogCreateIcons(context); + // Navigate to the first page + ShowUninstallConfirmDialog(context); + } + break; + } + + return S_OK; +} + +VOID SetupShowUninstallDialog( + VOID + ) +{ + PVOID context; + TASKDIALOGCONFIG config; + PH_AUTO_POOL autoPool; + + memset(&config, 0, sizeof(TASKDIALOGCONFIG)); + + PhInitializeAutoPool(&autoPool); + context = (PPH_SETUP_UNINSTALL_CONTEXT)PhCreateAlloc(sizeof(PH_SETUP_UNINSTALL_CONTEXT)); + memset(context, 0, sizeof(PH_SETUP_UNINSTALL_CONTEXT)); + + config.cbSize = sizeof(TASKDIALOGCONFIG); + config.dwFlags = TDF_POSITION_RELATIVE_TO_WINDOW; + config.dwCommonButtons = TDCBF_CANCEL_BUTTON; + config.pszWindowTitle = PhApplicationName; + config.pfCallback = TaskDialogUninstallBootstrapCallback; + config.lpCallbackData = (LONG_PTR)context; + + TaskDialogIndirect(&config, NULL, NULL, NULL); + + PhDereferenceObject(context); + PhDeleteAutoPool(&autoPool); +} \ No newline at end of file diff --git a/tools/CustomSetupTool/CustomSetupTool/update.c b/tools/CustomSetupTool/CustomSetupTool/update.c index 4de7ddc61e9d..5b02a4002cd3 100644 --- a/tools/CustomSetupTool/CustomSetupTool/update.c +++ b/tools/CustomSetupTool/CustomSetupTool/update.c @@ -24,7 +24,6 @@ typedef struct _PH_SETUP_UPDATE_CONTEXT { - BOOLEAN FixedWindowStyles; HWND DialogHandle; HICON IconSmallHandle; HICON IconLargeHandle; @@ -35,7 +34,7 @@ typedef struct _PH_SETUP_UPDATE_CONTEXT PPH_STRING SetupFilePath; } PH_SETUP_UPDATE_CONTEXT, *PPH_SETUP_UPDATE_CONTEXT; -#define WM_SHOWDIALOG (WM_APP + 550) +#define WM_TASKDIALOGINIT (WM_APP + 550) HWND UpdateDialogHandle = NULL; HANDLE UpdateDialogThreadHandle = NULL; PH_EVENT InitializedEvent = PH_EVENT_INIT; @@ -56,23 +55,22 @@ NTSTATUS SetupUpdateBuild( SetupCreateUninstallFile(); //SetupSetWindowsOptions(); - if (!SetupExtractBuild(Context->DialogHandle)) + if (!SetupExtractBuild(Context)) goto CleanupExit; if (SetupInstallKphService) SetupInstallKph(); - if (SetupExecuteProcessHacker(Context->DialogHandle)) - { - PostMessage(Context->DialogHandle, WM_QUIT, 0, 0); - } + if (!SetupExecuteProcessHacker(Context->DialogHandle)) + goto CleanupExit; + PostMessage(Context->DialogHandle, WM_QUIT, 0, 0); PhDereferenceObject(Context); return STATUS_SUCCESS; CleanupExit: - //PostMessage(Context->DialogHandle, IDD_ERROR, 0, 0); + PostMessage(Context->DialogHandle, IDD_ERROR, 0, 0); PhDereferenceObject(Context); return STATUS_FAIL_CHECK; } @@ -117,29 +115,29 @@ VOID TaskDialogCreateIcons( _In_ PPH_SETUP_UPDATE_CONTEXT Context ) { - //HICON largeIcon; - //HICON smallIcon; - - //largeIcon = PhLoadIcon( - // NtCurrentPeb()->ImageBaseAddress, - // MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER), - // PH_LOAD_ICON_SIZE_LARGE, - // GetSystemMetrics(SM_CXICON), - // GetSystemMetrics(SM_CYICON) - // ); - //smallIcon = PhLoadIcon( - // NtCurrentPeb()->ImageBaseAddress, - // MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER), - // PH_LOAD_ICON_SIZE_LARGE, - // GetSystemMetrics(SM_CXSMICON), - // GetSystemMetrics(SM_CYSMICON) - // ); - - //Context->IconLargeHandle = largeIcon; - //Context->IconSmallHandle = smallIcon; - - //SendMessage(Context->DialogHandle, WM_SETICON, ICON_SMALL, (LPARAM)largeIcon); - //SendMessage(Context->DialogHandle, WM_SETICON, ICON_BIG, (LPARAM)smallIcon); + HICON largeIcon; + HICON smallIcon; + + largeIcon = PhLoadIcon( + NtCurrentPeb()->ImageBaseAddress, + MAKEINTRESOURCE(IDI_ICON1), + PH_LOAD_ICON_SIZE_LARGE, + GetSystemMetrics(SM_CXICON), + GetSystemMetrics(SM_CYICON) + ); + smallIcon = PhLoadIcon( + NtCurrentPeb()->ImageBaseAddress, + MAKEINTRESOURCE(IDI_ICON1), + PH_LOAD_ICON_SIZE_LARGE, + GetSystemMetrics(SM_CXSMICON), + GetSystemMetrics(SM_CYSMICON) + ); + + Context->IconLargeHandle = largeIcon; + Context->IconSmallHandle = smallIcon; + + SendMessage(Context->DialogHandle, WM_SETICON, ICON_SMALL, (LPARAM)largeIcon); + SendMessage(Context->DialogHandle, WM_SETICON, ICON_BIG, (LPARAM)smallIcon); } VOID TaskDialogLinkClicked( @@ -162,12 +160,7 @@ LRESULT CALLBACK TaskDialogSubclassProc( switch (uMsg) { - case WM_NCDESTROY: - { - RemoveWindowSubclass(hwndDlg, TaskDialogSubclassProc, uIdSubclass); - } - break; - case WM_SHOWDIALOG: + case WM_TASKDIALOGINIT: { if (IsMinimized(hwndDlg)) ShowWindow(hwndDlg, SW_RESTORE); @@ -177,26 +170,11 @@ LRESULT CALLBACK TaskDialogSubclassProc( SetForegroundWindow(hwndDlg); } break; - //case PH_UPDATESUCCESS: - // { - // ShowInstallRestartDialog(context); - // } - // break; - //case PH_UPDATEFAILURE: - // { - // // if ((BOOLEAN)wParam) - // // ShowUpdateFailedDialog(context, TRUE, FALSE); - // // else if ((BOOLEAN)lParam) - // // ShowUpdateFailedDialog(context, FALSE, TRUE); - // //else - // //ShowUpdateFailedDialog(context, FALSE, FALSE); - // } - // break; - //case PH_UPDATEISERRORED: - // { - // //ShowUpdateFailedDialog(context, FALSE, FALSE); - // } - // break; + case WM_NCDESTROY: + { + RemoveWindowSubclass(hwndDlg, TaskDialogSubclassProc, uIdSubclass); + } + break; } return DefSubclassProc(hwndDlg, uMsg, wParam, lParam); @@ -241,8 +219,7 @@ VOID ShowCheckForUpdatesDialog( config.pfCallback = CheckingForUpdatesCallbackProc; config.lpCallbackData = (LONG_PTR)Context; config.pszWindowTitle = PhApplicationName; - //config.pszMainInstruction = L"Updating Process Hacker..."; - config.pszContent = PhaFormatString(L"Updating to version %lu.%lu.%lu...", PHAPP_VERSION_MAJOR, PHAPP_VERSION_MINOR, PHAPP_VERSION_REVISION)->Buffer; + config.pszMainInstruction = PhaFormatString(L"Updating to version %lu.%lu.%lu...", PHAPP_VERSION_MAJOR, PHAPP_VERSION_MINOR, PHAPP_VERSION_REVISION)->Buffer; config.cxWidth = 200; SendMessage(Context->DialogHandle, TDM_NAVIGATE_PAGE, 0, (LPARAM)&config); @@ -273,7 +250,7 @@ HRESULT CALLBACK TaskDialogBootstrapCallback( // Navigate to the first page ShowCheckForUpdatesDialog(context); - PostMessage(hwndDlg, WM_SHOWDIALOG, 0, 0); + SendMessage(hwndDlg, WM_TASKDIALOGINIT, 0, 0); } break; } From 8d4f8bf819706a228080372b448cafa725bf446f Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 26 Apr 2017 03:36:02 +1000 Subject: [PATCH 0010/2058] Fix build warnings --- plugins/Updater/updater.c | 14 +++++++------- plugins/Updater/updater.h | 1 - tools/CustomSetupTool/CustomSetupTool/extract.c | 6 +++--- .../CustomSetupTool/include/setup.h | 2 +- tools/CustomSetupTool/CustomSetupTool/page4.c | 2 +- tools/CustomSetupTool/CustomSetupTool/update.c | 2 +- 6 files changed, 13 insertions(+), 14 deletions(-) diff --git a/plugins/Updater/updater.c b/plugins/Updater/updater.c index 156148a2b59b..51f75f11c329 100644 --- a/plugins/Updater/updater.c +++ b/plugins/Updater/updater.c @@ -1015,12 +1015,7 @@ LRESULT CALLBACK TaskDialogSubclassProc( switch (uMsg) { - case WM_NCDESTROY: - { - RemoveWindowSubclass(hwndDlg, TaskDialogSubclassProc, uIdSubclass); - } - break; - case WM_SHOWDIALOG: + case WM_INITDIALOG: { if (IsMinimized(hwndDlg)) ShowWindow(hwndDlg, SW_RESTORE); @@ -1030,6 +1025,11 @@ LRESULT CALLBACK TaskDialogSubclassProc( SetForegroundWindow(hwndDlg); } break; + case WM_NCDESTROY: + { + RemoveWindowSubclass(hwndDlg, TaskDialogSubclassProc, uIdSubclass); + } + break; case PH_UPDATEAVAILABLE: { ShowAvailableDialog(context); @@ -1201,7 +1201,7 @@ VOID ShowUpdateDialog( PhWaitForEvent(&InitializedEvent, NULL); } - PostMessage(UpdateDialogHandle, WM_SHOWDIALOG, 0, 0); + PostMessage(UpdateDialogHandle, WM_INITDIALOG, 0, 0); } VOID StartInitialCheck( diff --git a/plugins/Updater/updater.h b/plugins/Updater/updater.h index b2032e6f432d..41899d0c5cbf 100644 --- a/plugins/Updater/updater.h +++ b/plugins/Updater/updater.h @@ -43,7 +43,6 @@ #define PH_UPDATENEWER (WM_APP + 504) #define PH_UPDATESUCCESS (WM_APP + 505) #define PH_UPDATEFAILURE (WM_APP + 506) -#define WM_SHOWDIALOG (WM_APP + 550) #define PLUGIN_NAME L"ProcessHacker.UpdateChecker" #define SETTING_NAME_AUTO_CHECK (PLUGIN_NAME L".PromptStart") diff --git a/tools/CustomSetupTool/CustomSetupTool/extract.c b/tools/CustomSetupTool/CustomSetupTool/extract.c index 1c600f73a771..f89aa45dbbef 100644 --- a/tools/CustomSetupTool/CustomSetupTool/extract.c +++ b/tools/CustomSetupTool/CustomSetupTool/extract.c @@ -50,7 +50,7 @@ PVOID GetZipResourceData( } BOOLEAN SetupExtractBuild( - _In_ PSETUP_PROGRESS_THREAD Context + _In_ HWND Context ) { mz_bool status = MZ_FALSE; @@ -97,7 +97,7 @@ BOOLEAN SetupExtractBuild( InterlockedExchange64(&ExtractTotalLength, totalLength); } - SendMessage(Context->DialogHandle, WM_START_SETUP, 0, 0); + SendMessage(Context, WM_START_SETUP, 0, 0); for (mz_uint i = 0; i < mz_zip_reader_get_num_files(&zip_archive); i++) { @@ -215,7 +215,7 @@ BOOLEAN SetupExtractBuild( currentLength += bufferLength; InterlockedExchange64(&ExtractCurrentLength, currentLength); - SendMessage(Context->DialogHandle, WM_UPDATE_SETUP, 0, (LPARAM)extractPath); + SendMessage(Context, WM_UPDATE_SETUP, 0, (LPARAM)extractPath); NtClose(fileHandle); mz_free(buffer); diff --git a/tools/CustomSetupTool/CustomSetupTool/include/setup.h b/tools/CustomSetupTool/CustomSetupTool/include/setup.h index bfbb5e84a9cf..6bfa3a0ad149 100644 --- a/tools/CustomSetupTool/CustomSetupTool/include/setup.h +++ b/tools/CustomSetupTool/CustomSetupTool/include/setup.h @@ -176,7 +176,7 @@ VOID SetupUpgradeSettingsFile( // extract.c BOOLEAN SetupExtractBuild( - _In_ PSETUP_PROGRESS_THREAD Context + _In_ HWND Context ); // update.c diff --git a/tools/CustomSetupTool/CustomSetupTool/page4.c b/tools/CustomSetupTool/CustomSetupTool/page4.c index d8d55b33f949..0fa1f085be1e 100644 --- a/tools/CustomSetupTool/CustomSetupTool/page4.c +++ b/tools/CustomSetupTool/CustomSetupTool/page4.c @@ -59,7 +59,7 @@ NTSTATUS SetupProgressThread( SetupSetWindowsOptions(); // Setup new installation. - if (!SetupExtractBuild(Context)) + if (!SetupExtractBuild(Context->DialogHandle)) goto CleanupExit; // Install updated kernel driver diff --git a/tools/CustomSetupTool/CustomSetupTool/update.c b/tools/CustomSetupTool/CustomSetupTool/update.c index 5b02a4002cd3..01db439aa0e1 100644 --- a/tools/CustomSetupTool/CustomSetupTool/update.c +++ b/tools/CustomSetupTool/CustomSetupTool/update.c @@ -55,7 +55,7 @@ NTSTATUS SetupUpdateBuild( SetupCreateUninstallFile(); //SetupSetWindowsOptions(); - if (!SetupExtractBuild(Context)) + if (!SetupExtractBuild(Context->DialogHandle)) goto CleanupExit; if (SetupInstallKphService) From b90c25f6899fbb0be68a3018d897325d6e8e6e59 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 26 Apr 2017 12:28:52 +1000 Subject: [PATCH 0011/2058] peview: Improve propsheet layout --- tools/peview/prpsh.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/tools/peview/prpsh.c b/tools/peview/prpsh.c index 70f9d0ed53da..14e7557875e1 100644 --- a/tools/peview/prpsh.c +++ b/tools/peview/prpsh.c @@ -228,26 +228,25 @@ LRESULT CALLBACK PvpPropSheetWndProc( } BOOLEAN PhpInitializePropSheetLayoutStage1( + _In_ PPV_PROPSHEETCONTEXT PropSheetContext, _In_ HWND hwnd ) { - PPV_PROPSHEETCONTEXT propSheetContext = PvpGetPropSheetContext(hwnd); - - if (!propSheetContext->LayoutInitialized) + if (!Context->LayoutInitialized) { HWND tabControlHandle; PPH_LAYOUT_ITEM tabControlItem; PPH_LAYOUT_ITEM tabPageItem; tabControlHandle = PropSheet_GetTabControl(hwnd); - tabControlItem = PhAddLayoutItem(&propSheetContext->LayoutManager, tabControlHandle, + tabControlItem = PhAddLayoutItem(&PropSheetContext->LayoutManager, tabControlHandle, NULL, PH_ANCHOR_ALL | PH_LAYOUT_IMMEDIATE_RESIZE); - tabPageItem = PhAddLayoutItem(&propSheetContext->LayoutManager, tabControlHandle, + tabPageItem = PhAddLayoutItem(&PropSheetContext->LayoutManager, tabControlHandle, NULL, PH_LAYOUT_TAB_CONTROL); // dummy item to fix multiline tab control - propSheetContext->TabPageItem = tabPageItem; + PropSheetContext->TabPageItem = tabPageItem; - PhAddLayoutItem(&propSheetContext->LayoutManager, GetDlgItem(hwnd, IDCANCEL), + PhAddLayoutItem(&PropSheetContext->LayoutManager, GetDlgItem(hwnd, IDCANCEL), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); // Hide the OK button. @@ -255,7 +254,7 @@ BOOLEAN PhpInitializePropSheetLayoutStage1( // Set the Cancel button's text to "Close". SetDlgItemText(hwnd, IDCANCEL, L"Close"); - propSheetContext->LayoutInitialized = TRUE; + PropSheetContext->LayoutInitialized = TRUE; return TRUE; } @@ -385,7 +384,7 @@ PPH_LAYOUT_ITEM PvAddPropPageLayoutItem( propSheetContext = PvpGetPropSheetContext(parent); layoutManager = &propSheetContext->LayoutManager; - PhpInitializePropSheetLayoutStage1(parent); + PhpInitializePropSheetLayoutStage1(propSheetContext, parent); if (ParentItem != PH_PROP_PAGE_TAB_CONTROL_PARENT) realParentItem = ParentItem; From 3161bba67e0c99a5e83ef9cfd079ef6c002ecbd8 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 26 Apr 2017 15:42:21 +1000 Subject: [PATCH 0012/2058] Fix token properties highlighting, Update handles tab layout, Fix peview typo --- ProcessHacker/ProcessHacker.rc | 14 ++--- ProcessHacker/ProcessHacker.vcxproj | 1 + ProcessHacker/ProcessHacker.vcxproj.filters | 3 + ProcessHacker/hndllist.c | 5 +- ProcessHacker/include/appsup.h | 67 -------------------- ProcessHacker/include/splitter.h | 70 +++++++++++++++++++++ ProcessHacker/splitter.c | 42 +++++-------- ProcessHacker/tokprp.c | 52 +++++++-------- tools/peview/prpsh.c | 2 +- 9 files changed, 122 insertions(+), 134 deletions(-) create mode 100644 ProcessHacker/include/splitter.h diff --git a/ProcessHacker/ProcessHacker.rc b/ProcessHacker/ProcessHacker.rc index db1968f60b85..74667f423a66 100644 --- a/ProcessHacker/ProcessHacker.rc +++ b/ProcessHacker/ProcessHacker.rc @@ -601,9 +601,9 @@ STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSM CAPTION "Handles" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN - CONTROL "Hide unnamed handles",IDC_HIDEUNNAMEDHANDLES,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,7,88,10 - CONTROL "",IDC_LIST,"PhTreeNew",WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP | 0x2,7,21,246,232,WS_EX_CLIENTEDGE - EDITTEXT IDC_HANDLESEARCH,110,4,143,14,ES_AUTOHSCROLL + CONTROL "Hide unnamed handles",IDC_HIDEUNNAMEDHANDLES,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,3,5,88,10 + CONTROL "",IDC_LIST,"PhTreeNew",WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP | 0x2,2,19,256,239,WS_EX_CLIENTEDGE + EDITTEXT IDC_HANDLESEARCH,114,3,144,14,ES_AUTOHSCROLL END IDD_PROCENVIRONMENT DIALOGEX 0, 0, 260, 260 @@ -1956,10 +1956,10 @@ BEGIN IDD_PROCHANDLES, DIALOG BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 253 - TOPMARGIN, 7 - BOTTOMMARGIN, 253 + LEFTMARGIN, 2 + RIGHTMARGIN, 258 + TOPMARGIN, 3 + BOTTOMMARGIN, 258 END IDD_PROCENVIRONMENT, DIALOG diff --git a/ProcessHacker/ProcessHacker.vcxproj b/ProcessHacker/ProcessHacker.vcxproj index c2e557e676dc..dc1045b9f277 100644 --- a/ProcessHacker/ProcessHacker.vcxproj +++ b/ProcessHacker/ProcessHacker.vcxproj @@ -385,6 +385,7 @@ + diff --git a/ProcessHacker/ProcessHacker.vcxproj.filters b/ProcessHacker/ProcessHacker.vcxproj.filters index fbed89f82328..0af73f22ef55 100644 --- a/ProcessHacker/ProcessHacker.vcxproj.filters +++ b/ProcessHacker/ProcessHacker.vcxproj.filters @@ -584,6 +584,9 @@ Headers + + Headers + diff --git a/ProcessHacker/hndllist.c b/ProcessHacker/hndllist.c index c34947dd9502..110316c924ed 100644 --- a/ProcessHacker/hndllist.c +++ b/ProcessHacker/hndllist.c @@ -3,6 +3,7 @@ * handle list * * Copyright (C) 2011-2013 wj32 + * Copyright (C) 2017 dmex * * This file is part of Process Hacker. * @@ -95,12 +96,12 @@ VOID PhInitializeHandleList( // Default columns PhAddTreeNewColumn(hwnd, PHHNTLC_TYPE, TRUE, L"Type", 100, PH_ALIGN_LEFT, 0, 0); PhAddTreeNewColumn(hwnd, PHHNTLC_NAME, TRUE, L"Name", 200, PH_ALIGN_LEFT, 1, 0); - PhAddTreeNewColumn(hwnd, PHHNTLC_HANDLE, TRUE, L"Handle", 80, PH_ALIGN_LEFT, 2, 0); + PhAddTreeNewColumn(hwnd, PHHNTLC_GRANTEDACCESSSYMBOLIC, TRUE, L"Granted access (symbolic)", 140, PH_ALIGN_LEFT, 2, 0); + PhAddTreeNewColumn(hwnd, PHHNTLC_HANDLE, FALSE, L"Handle", 80, PH_ALIGN_LEFT, -1, 0); PhAddTreeNewColumn(hwnd, PHHNTLC_OBJECTADDRESS, FALSE, L"Object address", 80, PH_ALIGN_LEFT, -1, 0); PhAddTreeNewColumnEx(hwnd, PHHNTLC_ATTRIBUTES, FALSE, L"Attributes", 120, PH_ALIGN_LEFT, -1, 0, TRUE); PhAddTreeNewColumn(hwnd, PHHNTLC_GRANTEDACCESS, FALSE, L"Granted access", 80, PH_ALIGN_LEFT, -1, 0); - PhAddTreeNewColumn(hwnd, PHHNTLC_GRANTEDACCESSSYMBOLIC, FALSE, L"Granted access (symbolic)", 140, PH_ALIGN_LEFT, -1, 0); PhAddTreeNewColumn(hwnd, PHHNTLC_ORIGINALNAME, FALSE, L"Original name", 200, PH_ALIGN_LEFT, -1, 0); PhAddTreeNewColumnEx(hwnd, PHHNTLC_FILESHAREACCESS, FALSE, L"File share access", 50, PH_ALIGN_LEFT, -1, 0, TRUE); diff --git a/ProcessHacker/include/appsup.h b/ProcessHacker/include/appsup.h index 27912c57b459..e631485c30b9 100644 --- a/ProcessHacker/include/appsup.h +++ b/ProcessHacker/include/appsup.h @@ -499,71 +499,4 @@ FORCEINLINE PVOID PhpGenericPropertyPageHeader( #define SWP_SHOWWINDOW_ONLY (SWP_NO_ACTIVATE_MOVE_SIZE_ZORDER | SWP_SHOWWINDOW) #define SWP_HIDEWINDOW_ONLY (SWP_NO_ACTIVATE_MOVE_SIZE_ZORDER | SWP_HIDEWINDOW) -// splitter - -typedef struct _PH_HSPLITTER_CONTEXT -{ - union - { - ULONG Flags; - struct - { - ULONG Hot : 1; - ULONG Pushed : 1; - ULONG Moved : 1; - ULONG DragMode : 1; - ULONG Spare : 28; - }; - }; - - ULONG Height; - PH_LAYOUT_MANAGER LayoutManager; - PPH_LAYOUT_ITEM Topitem; - PPH_LAYOUT_ITEM Bottomitem; -} PH_HSPLITTER_CONTEXT, *PPH_HSPLITTER_CONTEXT; - -PPH_HSPLITTER_CONTEXT PhInitializeHSplitterSupport( - _In_ HWND Parent, - _In_ HWND TopChild, - _In_ HWND BottomChild - ); - -VOID PhDeleteHSplitterSupportSupport( - _Inout_ PPH_HSPLITTER_CONTEXT Context - ); - -VOID PhHSplitterHandleWmSize( - _Inout_ PPH_HSPLITTER_CONTEXT Context, - _In_ INT Width, - _In_ INT Height - ); - -VOID PhHSplitterHandleLButtonDown( - _Inout_ PPH_HSPLITTER_CONTEXT Context, - _In_ HWND hwnd, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -VOID PhHSplitterHandleLButtonUp( - _Inout_ PPH_HSPLITTER_CONTEXT Context, - _In_ HWND hwnd, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -VOID PhHSplitterHandleMouseMove( - _Inout_ PPH_HSPLITTER_CONTEXT Context, - _In_ HWND hwnd, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -VOID PhHSplitterHandleMouseLeave( - _Inout_ PPH_HSPLITTER_CONTEXT Context, - _In_ HWND hwnd, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - #endif diff --git a/ProcessHacker/include/splitter.h b/ProcessHacker/include/splitter.h new file mode 100644 index 000000000000..50b9c1fb7bf4 --- /dev/null +++ b/ProcessHacker/include/splitter.h @@ -0,0 +1,70 @@ +#ifndef PH_HSPLITTER_H +#define PH_HSPLITTER_H + +typedef struct _PH_HSPLITTER_CONTEXT +{ + union + { + ULONG Flags; + struct + { + ULONG Hot : 1; + ULONG Pushed : 1; + ULONG Moved : 1; + ULONG DragMode : 1; + ULONG Spare : 28; + }; + }; + + LONG SplitterOffset; + LONG SplitterPosition; + PH_LAYOUT_MANAGER LayoutManager; + PPH_LAYOUT_ITEM Topitem; + PPH_LAYOUT_ITEM Bottomitem; +} PH_HSPLITTER_CONTEXT, *PPH_HSPLITTER_CONTEXT; + +PPH_HSPLITTER_CONTEXT PhInitializeHSplitter( + _In_ HWND Parent, + _In_ HWND TopChild, + _In_ HWND BottomChild + ); + +VOID PhDeleteHSplitter( + _Inout_ PPH_HSPLITTER_CONTEXT Context + ); + +VOID PhHSplitterHandleWmSize( + _Inout_ PPH_HSPLITTER_CONTEXT Context, + _In_ INT Width, + _In_ INT Height + ); + +VOID PhHSplitterHandleLButtonDown( + _Inout_ PPH_HSPLITTER_CONTEXT Context, + _In_ HWND hwnd, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +VOID PhHSplitterHandleLButtonUp( + _Inout_ PPH_HSPLITTER_CONTEXT Context, + _In_ HWND hwnd, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +VOID PhHSplitterHandleMouseMove( + _Inout_ PPH_HSPLITTER_CONTEXT Context, + _In_ HWND hwnd, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +VOID PhHSplitterHandleMouseLeave( + _Inout_ PPH_HSPLITTER_CONTEXT Context, + _In_ HWND hwnd, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +#endif diff --git a/ProcessHacker/splitter.c b/ProcessHacker/splitter.c index 23682b89c28d..4f0352f7e1aa 100644 --- a/ProcessHacker/splitter.c +++ b/ProcessHacker/splitter.c @@ -22,16 +22,16 @@ */ #include +#include #include #include static INT nSplitterPos = 250; -static INT nSplitterBorder = 6; static INT SplitterOffset = -4; VOID DrawXorBar(HDC hdc, INT x1, INT y1, INT width, INT height); -PPH_HSPLITTER_CONTEXT PhInitializeHSplitterSupport( +PPH_HSPLITTER_CONTEXT PhInitializeHSplitter( _In_ HWND Parent, _In_ HWND TopChild, _In_ HWND BottomChild @@ -43,14 +43,13 @@ PPH_HSPLITTER_CONTEXT PhInitializeHSplitterSupport( memset(context, 0, sizeof(PH_HSPLITTER_CONTEXT)); PhInitializeLayoutManager(&context->LayoutManager, Parent); - context->Topitem = PhAddLayoutItem(&context->LayoutManager, TopChild, NULL, PH_ANCHOR_ALL); context->Bottomitem = PhAddLayoutItem(&context->LayoutManager, BottomChild, NULL, PH_ANCHOR_ALL); return context; } -VOID PhDeleteHSplitterSupportSupport( +VOID PhDeleteHSplitter( _Inout_ PPH_HSPLITTER_CONTEXT Context ) { @@ -64,12 +63,11 @@ VOID PhHSplitterHandleWmSize( ) { // HACK: Use the PH layout manager as the 'splitter' control by abusing layout margins. - +#define SPLITTER_PADDING 6 // Set the bottom margin of the top control. - Context->Topitem->Margin.bottom = Height - nSplitterPos - nSplitterBorder; - + Context->Topitem->Margin.bottom = Height - nSplitterPos - SPLITTER_PADDING; // Set the top margin of the bottom control. - Context->Bottomitem->Margin.top = nSplitterPos + nSplitterBorder * 2; + Context->Bottomitem->Margin.top = nSplitterPos + SPLITTER_PADDING * 2; PhLayoutManagerLayout(&Context->LayoutManager); } @@ -209,21 +207,16 @@ VOID PhHSplitterHandleMouseMove( } else { - //if (!Context->Hot) - { - TRACKMOUSEEVENT trackMouseEvent; - - trackMouseEvent.cbSize = sizeof(TRACKMOUSEEVENT); - trackMouseEvent.dwFlags = TME_LEAVE; - trackMouseEvent.hwndTrack = hwnd; - trackMouseEvent.dwHoverTime = 0; + TRACKMOUSEEVENT trackMouseEvent; - Context->Hot = TRUE; + trackMouseEvent.cbSize = sizeof(TRACKMOUSEEVENT); + trackMouseEvent.dwFlags = TME_LEAVE; + trackMouseEvent.hwndTrack = hwnd; + trackMouseEvent.dwHoverTime = 0; - SetCursor(LoadCursor(NULL, IDC_SIZENS)); + SetCursor(LoadCursor(NULL, IDC_SIZENS)); - TrackMouseEvent(&trackMouseEvent); - } + TrackMouseEvent(&trackMouseEvent); } ReleaseDC(hwnd, hdc); @@ -238,13 +231,8 @@ VOID PhHSplitterHandleMouseLeave( _In_ LPARAM lParam ) { - if (Context->Hot) - { - Context->Hot = FALSE; - - // Reset the original cursor. - SetCursor(LoadCursor(NULL, IDC_ARROW)); - } + // Reset the original cursor. + SetCursor(LoadCursor(NULL, IDC_ARROW)); } // http://www.catch22.net/tuts/splitter-windows diff --git a/ProcessHacker/tokprp.c b/ProcessHacker/tokprp.c index 034d6c65d1bb..27263e020fac 100644 --- a/ProcessHacker/tokprp.c +++ b/ProcessHacker/tokprp.c @@ -3,6 +3,7 @@ * token properties * * Copyright (C) 2010-2012 wj32 + * Copyright (C) 2017 dmex * * This file is part of Process Hacker. * @@ -21,13 +22,13 @@ */ #include - -#include - #include #include #include #include +#include + +#include typedef struct _ATTRIBUTE_NODE { @@ -424,7 +425,7 @@ INT_PTR CALLBACK PhpTokenPageProc( PhSetControlTheme(groupsLv, L"explorer"); PhSetControlTheme(privilegesLv, L"explorer"); - tokenPageContext->HSplitterContext = PhInitializeHSplitterSupport( + tokenPageContext->HSplitterContext = PhInitializeHSplitter( hwndDlg, tokenPageContext->GroupsListViewHandle, tokenPageContext->PrivilegesListViewHandle @@ -582,19 +583,6 @@ INT_PTR CALLBACK PhpTokenPageProc( ExtendedListView_SortItems(privilegesLv); } - if (ListView_GetItemCount(groupsLv) != 0) - { - ListView_SetColumnWidth(groupsLv, 0, LVSCW_AUTOSIZE); - ExtendedListView_SetColumnWidth(groupsLv, 1, ELVSCW_AUTOSIZE_REMAININGSPACE); - } - - if (ListView_GetItemCount(privilegesLv) != 0) - { - ListView_SetColumnWidth(privilegesLv, 0, LVSCW_AUTOSIZE); - ListView_SetColumnWidth(privilegesLv, 1, LVSCW_AUTOSIZE); - ExtendedListView_SetColumnWidth(privilegesLv, 2, ELVSCW_AUTOSIZE_REMAININGSPACE); - } - NtClose(tokenHandle); } } @@ -603,7 +591,7 @@ INT_PTR CALLBACK PhpTokenPageProc( { if (tokenPageContext->Groups) PhFree(tokenPageContext->Groups); if (tokenPageContext->Privileges) PhFree(tokenPageContext->Privileges); - if (tokenPageContext->HSplitterContext) PhDeleteHSplitterSupportSupport(tokenPageContext->HSplitterContext); + if (tokenPageContext->HSplitterContext) PhDeleteHSplitter(tokenPageContext->HSplitterContext); } break; case WM_COMMAND: @@ -902,6 +890,19 @@ INT_PTR CALLBACK PhpTokenPageProc( { case PSN_QUERYINITIALFOCUS: { + if (ListView_GetItemCount(tokenPageContext->GroupsListViewHandle) != 0) + { + ListView_SetColumnWidth(tokenPageContext->GroupsListViewHandle, 0, LVSCW_AUTOSIZE); + ExtendedListView_SetColumnWidth(tokenPageContext->GroupsListViewHandle, 1, ELVSCW_AUTOSIZE_REMAININGSPACE); + } + + if (ListView_GetItemCount(tokenPageContext->PrivilegesListViewHandle) != 0) + { + ListView_SetColumnWidth(tokenPageContext->PrivilegesListViewHandle, 0, LVSCW_AUTOSIZE); + ListView_SetColumnWidth(tokenPageContext->PrivilegesListViewHandle, 1, LVSCW_AUTOSIZE); + ExtendedListView_SetColumnWidth(tokenPageContext->PrivilegesListViewHandle, 2, ELVSCW_AUTOSIZE_REMAININGSPACE); + } + SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, (LONG_PTR)GetDlgItem(hwndDlg, IDC_SESSIONID)); return TRUE; } @@ -939,24 +940,15 @@ INT_PTR CALLBACK PhpTokenPageProc( break; case WM_SIZE: PhHSplitterHandleWmSize(tokenPageContext->HSplitterContext, LOWORD(lParam), HIWORD(lParam)); - return 0; + break; case WM_LBUTTONDOWN: PhHSplitterHandleLButtonDown(tokenPageContext->HSplitterContext, hwndDlg, wParam, lParam); - return 0; + break; case WM_LBUTTONUP: PhHSplitterHandleLButtonUp(tokenPageContext->HSplitterContext, hwndDlg, wParam, lParam); - return 0; + break; case WM_MOUSEMOVE: PhHSplitterHandleMouseMove(tokenPageContext->HSplitterContext, hwndDlg, wParam, lParam); - return 0; - case WM_NCMOUSELEAVE: - { - //if (context->Hot) - { - //context->Hot = FALSE; - //RedrawWindow(hWnd, NULL, NULL, RDW_FRAME | RDW_INVALIDATE); - } - } break; } diff --git a/tools/peview/prpsh.c b/tools/peview/prpsh.c index 14e7557875e1..ab84021aa15b 100644 --- a/tools/peview/prpsh.c +++ b/tools/peview/prpsh.c @@ -232,7 +232,7 @@ BOOLEAN PhpInitializePropSheetLayoutStage1( _In_ HWND hwnd ) { - if (!Context->LayoutInitialized) + if (!PropSheetContext->LayoutInitialized) { HWND tabControlHandle; PPH_LAYOUT_ITEM tabControlItem; From 10d4224ca301571beeaa49035037cb0d92bef979 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 26 Apr 2017 15:48:45 +1000 Subject: [PATCH 0013/2058] NetworkTools: Fix layout --- plugins/NetworkTools/main.c | 2 +- plugins/NetworkTools/ping.c | 7 +++++-- plugins/NetworkTools/tracert.c | 6 +++++- plugins/NetworkTools/whois.c | 9 ++++++--- 4 files changed, 17 insertions(+), 7 deletions(-) diff --git a/plugins/NetworkTools/main.c b/plugins/NetworkTools/main.c index 8134d8ed4f8c..9dfaf8fc6fc9 100644 --- a/plugins/NetworkTools/main.c +++ b/plugins/NetworkTools/main.c @@ -645,7 +645,7 @@ LOGICAL DllMain( { IntegerSettingType, SETTING_NAME_PING_MINIMUM_SCALING, L"1F4" }, // 500ms minimum scaling { IntegerSettingType, SETTING_NAME_PING_SIZE, L"20" }, // 32 byte packet { IntegerPairSettingType, SETTING_NAME_TRACERT_WINDOW_POSITION, L"0,0" }, - { ScalableIntegerPairSettingType, SETTING_NAME_TRACERT_WINDOW_SIZE, L"@96|600,365" }, + { ScalableIntegerPairSettingType, SETTING_NAME_TRACERT_WINDOW_SIZE, L"@96|850,490" }, { StringSettingType, SETTING_NAME_TRACERT_LIST_COLUMNS, L"" }, { StringSettingType, SETTING_NAME_TRACERT_HISTORY, L"" }, { IntegerSettingType, SETTING_NAME_TRACERT_MAX_HOPS, L"30" }, diff --git a/plugins/NetworkTools/ping.c b/plugins/NetworkTools/ping.c index a971a9c83a86..eb9224c79872 100644 --- a/plugins/NetworkTools/ping.c +++ b/plugins/NetworkTools/ping.c @@ -290,7 +290,6 @@ INT_PTR CALLBACK NetworkPingWndProc( // in removing the flicker from the graphs the group boxes will now flicker. // It's a good tradeoff since no one stares at the group boxes. PhSetWindowStyle(hwndDlg, WS_CLIPCHILDREN, WS_CLIPCHILDREN); - PhCenterWindow(hwndDlg, GetParent(hwndDlg)); context->WindowHandle = hwndDlg; context->StatusHandle = GetDlgItem(hwndDlg, IDC_MAINTEXT); @@ -326,7 +325,11 @@ INT_PTR CALLBACK NetworkPingWndProc( PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_ANON_ADDR), NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_LEFT); panelItem = PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_PING_LAYOUT), NULL, PH_ANCHOR_ALL); PhAddLayoutItemEx(&context->LayoutManager, context->PingGraphHandle, NULL, PH_ANCHOR_ALL, panelItem->Margin); - PhLoadWindowPlacementFromSetting(SETTING_NAME_PING_WINDOW_POSITION, SETTING_NAME_PING_WINDOW_SIZE, hwndDlg); + + if (PhGetIntegerPairSetting(SETTING_NAME_PING_WINDOW_POSITION).X != 0) + PhLoadWindowPlacementFromSetting(SETTING_NAME_PING_WINDOW_POSITION, SETTING_NAME_PING_WINDOW_SIZE, hwndDlg); + else + PhCenterWindow(hwndDlg, PhMainWndHandle); SetWindowText(hwndDlg, PhaFormatString(L"Ping %s", context->IpAddressString)->Buffer); SetWindowText(context->StatusHandle, PhaFormatString(L"Pinging %s with %lu bytes of data...", diff --git a/plugins/NetworkTools/tracert.c b/plugins/NetworkTools/tracert.c index b1c63a06a26f..0484e9bc1055 100644 --- a/plugins/NetworkTools/tracert.c +++ b/plugins/NetworkTools/tracert.c @@ -588,7 +588,11 @@ INT_PTR CALLBACK TracertDlgProc( PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_STATUS), NULL, PH_ANCHOR_TOP | PH_ANCHOR_LEFT | PH_ANCHOR_RIGHT | PH_LAYOUT_FORCE_INVALIDATE); PhAddLayoutItem(&context->LayoutManager, context->TreeNewHandle, NULL, PH_ANCHOR_ALL); PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDCANCEL), NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_RIGHT); - PhLoadWindowPlacementFromSetting(SETTING_NAME_TRACERT_WINDOW_POSITION, SETTING_NAME_TRACERT_WINDOW_SIZE, hwndDlg); + + if (PhGetIntegerPairSetting(SETTING_NAME_TRACERT_WINDOW_POSITION).X != 0) + PhLoadWindowPlacementFromSetting(SETTING_NAME_TRACERT_WINDOW_POSITION, SETTING_NAME_TRACERT_WINDOW_SIZE, hwndDlg); + else + PhCenterWindow(hwndDlg, PhMainWndHandle); PhReferenceObject(context); diff --git a/plugins/NetworkTools/whois.c b/plugins/NetworkTools/whois.c index 4755af27061f..4a2b968ffe26 100644 --- a/plugins/NetworkTools/whois.c +++ b/plugins/NetworkTools/whois.c @@ -397,7 +397,6 @@ INT_PTR CALLBACK NetworkOutputDlgProc( HANDLE dialogThread; SetWindowText(hwndDlg, PhaFormatString(L"Whois %s...", context->IpAddressString)->Buffer); - PhCenterWindow(hwndDlg, PhMainWndHandle); context->WindowHandle = hwndDlg; context->RichEditHandle = GetDlgItem(hwndDlg, IDC_NETOUTPUTEDIT); @@ -412,8 +411,12 @@ INT_PTR CALLBACK NetworkOutputDlgProc( context->FontHandle = PhCreateCommonFont(-11, FW_MEDIUM, context->RichEditHandle); PhInitializeLayoutManager(&context->LayoutManager, hwndDlg); - PhAddLayoutItem(&context->LayoutManager, context->RichEditHandle, NULL, PH_ANCHOR_ALL); - PhLoadWindowPlacementFromSetting(SETTING_NAME_WHOIS_WINDOW_POSITION, SETTING_NAME_WHOIS_WINDOW_SIZE, hwndDlg); + PhAddLayoutItem(&context->LayoutManager, context->RichEditHandle, NULL, PH_ANCHOR_ALL); + + if (PhGetIntegerPairSetting(SETTING_NAME_WHOIS_WINDOW_POSITION).X != 0) + PhLoadWindowPlacementFromSetting(SETTING_NAME_WHOIS_WINDOW_POSITION, SETTING_NAME_WHOIS_WINDOW_SIZE, hwndDlg); + else + PhCenterWindow(hwndDlg, PhMainWndHandle); if (dialogThread = PhCreateThread(0, NetworkWhoisThreadStart, (PVOID)context)) NtClose(dialogThread); From 9766f20c37e9ac2db2e2b6173adb54fb5d54f945 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 26 Apr 2017 16:16:58 +1000 Subject: [PATCH 0014/2058] Fix token properties splitter min/max resize --- ProcessHacker/splitter.c | 81 +++++++++++++++++++++------------------- 1 file changed, 42 insertions(+), 39 deletions(-) diff --git a/ProcessHacker/splitter.c b/ProcessHacker/splitter.c index 4f0352f7e1aa..01532f810794 100644 --- a/ProcessHacker/splitter.c +++ b/ProcessHacker/splitter.c @@ -26,6 +26,8 @@ #include #include +#define SPLITTER_PADDING 6 +#define SPLITTER_MIN_HEIGHT 200 static INT nSplitterPos = 250; static INT SplitterOffset = -4; @@ -63,7 +65,8 @@ VOID PhHSplitterHandleWmSize( ) { // HACK: Use the PH layout manager as the 'splitter' control by abusing layout margins. -#define SPLITTER_PADDING 6 + // TODO: Check min_height and adjust splitter position if invisible. + // Set the bottom margin of the top control. Context->Topitem->Margin.bottom = Height - nSplitterPos - SPLITTER_PADDING; // Set the top margin of the bottom control. @@ -95,10 +98,10 @@ VOID PhHSplitterHandleLButtonDown( // Adjust the coordinates (start from 0,0). OffsetRect(&rect, -rect.left, -rect.top); - if (pt.y < 0) - pt.y = 0; - if (pt.y > rect.bottom - 4) - pt.y = rect.bottom - 4; + if (pt.y < Context->Topitem->OrigRect.top * 2) + pt.y = Context->Topitem->OrigRect.top * 2; + if (pt.y > Context->Bottomitem->Rect.bottom - SPLITTER_MIN_HEIGHT) + pt.y = Context->Bottomitem->Rect.bottom - SPLITTER_MIN_HEIGHT; Context->DragMode = TRUE; @@ -137,10 +140,10 @@ VOID PhHSplitterHandleLButtonUp( // Adjust the coordinates (start from 0,0). OffsetRect(&rect, -rect.left, -rect.top); - if (pt.y < 0) - pt.y = 0; - if (pt.y > rect.bottom - 4) - pt.y = rect.bottom - 4; + if (pt.y < Context->Topitem->OrigRect.top * 2) + pt.y = Context->Topitem->OrigRect.top * 2; + if (pt.y > Context->Bottomitem->Rect.bottom - SPLITTER_MIN_HEIGHT) + pt.y = Context->Bottomitem->Rect.bottom - SPLITTER_MIN_HEIGHT; hdc = GetWindowDC(hwnd); DrawXorBar(hdc, 1, SplitterOffset - 2, rect.right - 2, 4); @@ -177,50 +180,50 @@ VOID PhHSplitterHandleMouseMove( RECT windowRect; POINT windowPoint; - //if (Context->DragMode == FALSE) - // return; - windowPoint.x = GET_X_LPARAM(lParam); windowPoint.y = GET_Y_LPARAM(lParam); GetWindowRect(hwnd, &windowRect); ClientToScreen(hwnd, &windowPoint); - windowPoint.x -= windowRect.left; - windowPoint.y -= windowRect.top; - - OffsetRect(&windowRect, -windowRect.left, -windowRect.top); + if (Context->DragMode) + { + windowPoint.x -= windowRect.left; + windowPoint.y -= windowRect.top; - if (windowPoint.y < 0) - windowPoint.y = 0; - if (windowPoint.y > windowRect.bottom - 4) - windowPoint.y = windowRect.bottom - 4; + OffsetRect(&windowRect, -windowRect.left, -windowRect.top); - if (windowPoint.y != SplitterOffset) - { - hdc = GetWindowDC(hwnd); + if (windowPoint.y < Context->Topitem->OrigRect.top * 2) + windowPoint.y = Context->Topitem->OrigRect.top * 2; + if (windowPoint.y > Context->Bottomitem->Rect.bottom - SPLITTER_MIN_HEIGHT) + windowPoint.y = Context->Bottomitem->Rect.bottom - SPLITTER_MIN_HEIGHT; - if (wParam & MK_LBUTTON) + if (windowPoint.y != SplitterOffset) { - DrawXorBar(hdc, 1, SplitterOffset - 2, windowRect.right - 2, 4); - DrawXorBar(hdc, 1, windowPoint.y - 2, windowRect.right - 2, 4); - } - else - { - TRACKMOUSEEVENT trackMouseEvent; + hdc = GetWindowDC(hwnd); - trackMouseEvent.cbSize = sizeof(TRACKMOUSEEVENT); - trackMouseEvent.dwFlags = TME_LEAVE; - trackMouseEvent.hwndTrack = hwnd; - trackMouseEvent.dwHoverTime = 0; + if (wParam & MK_LBUTTON) + { + DrawXorBar(hdc, 1, SplitterOffset - 2, windowRect.right - 2, 4); + DrawXorBar(hdc, 1, windowPoint.y - 2, windowRect.right - 2, 4); + } + else + { + TRACKMOUSEEVENT trackMouseEvent; - SetCursor(LoadCursor(NULL, IDC_SIZENS)); + trackMouseEvent.cbSize = sizeof(TRACKMOUSEEVENT); + trackMouseEvent.dwFlags = TME_LEAVE; + trackMouseEvent.hwndTrack = hwnd; + trackMouseEvent.dwHoverTime = 0; - TrackMouseEvent(&trackMouseEvent); - } + SetCursor(LoadCursor(NULL, IDC_SIZENS)); - ReleaseDC(hwnd, hdc); - SplitterOffset = windowPoint.y; + TrackMouseEvent(&trackMouseEvent); + } + + ReleaseDC(hwnd, hdc); + SplitterOffset = windowPoint.y; + } } } From 2c3dfa9cc2d18535a0813de1b845905a7abb89d2 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 26 Apr 2017 16:40:10 +1000 Subject: [PATCH 0015/2058] Update splitter control --- ProcessHacker/splitter.c | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/ProcessHacker/splitter.c b/ProcessHacker/splitter.c index 01532f810794..55c28b97785a 100644 --- a/ProcessHacker/splitter.c +++ b/ProcessHacker/splitter.c @@ -28,8 +28,6 @@ #define SPLITTER_PADDING 6 #define SPLITTER_MIN_HEIGHT 200 -static INT nSplitterPos = 250; -static INT SplitterOffset = -4; VOID DrawXorBar(HDC hdc, INT x1, INT y1, INT width, INT height); @@ -45,6 +43,9 @@ PPH_HSPLITTER_CONTEXT PhInitializeHSplitter( memset(context, 0, sizeof(PH_HSPLITTER_CONTEXT)); PhInitializeLayoutManager(&context->LayoutManager, Parent); + + context->SplitterOffset = -4; + context->SplitterPosition = 250; context->Topitem = PhAddLayoutItem(&context->LayoutManager, TopChild, NULL, PH_ANCHOR_ALL); context->Bottomitem = PhAddLayoutItem(&context->LayoutManager, BottomChild, NULL, PH_ANCHOR_ALL); @@ -65,12 +66,12 @@ VOID PhHSplitterHandleWmSize( ) { // HACK: Use the PH layout manager as the 'splitter' control by abusing layout margins. - // TODO: Check min_height and adjust splitter position if invisible. + // TODO: Check min_height and adjust second control if invisible. // Set the bottom margin of the top control. - Context->Topitem->Margin.bottom = Height - nSplitterPos - SPLITTER_PADDING; + Context->Topitem->Margin.bottom = Height - Context->SplitterPosition - SPLITTER_PADDING; // Set the top margin of the bottom control. - Context->Bottomitem->Margin.top = nSplitterPos + SPLITTER_PADDING * 2; + Context->Bottomitem->Margin.top = Context->SplitterPosition + SPLITTER_PADDING * 2; PhLayoutManagerLayout(&Context->LayoutManager); } @@ -104,14 +105,13 @@ VOID PhHSplitterHandleLButtonDown( pt.y = Context->Bottomitem->Rect.bottom - SPLITTER_MIN_HEIGHT; Context->DragMode = TRUE; - SetCapture(hwnd); hdc = GetWindowDC(hwnd); DrawXorBar(hdc, 1, pt.y - 2, rect.right - 2, 4); ReleaseDC(hwnd, hdc); - SplitterOffset = pt.y; + Context->SplitterOffset = pt.y; } VOID PhHSplitterHandleLButtonUp( @@ -128,7 +128,7 @@ VOID PhHSplitterHandleLButtonUp( pt.x = GET_X_LPARAM(lParam); pt.y = GET_Y_LPARAM(lParam); - if (Context->DragMode == FALSE) + if (!Context->DragMode) return; GetWindowRect(hwnd, &rect); @@ -146,22 +146,20 @@ VOID PhHSplitterHandleLButtonUp( pt.y = Context->Bottomitem->Rect.bottom - SPLITTER_MIN_HEIGHT; hdc = GetWindowDC(hwnd); - DrawXorBar(hdc, 1, SplitterOffset - 2, rect.right - 2, 4); + DrawXorBar(hdc, 1, Context->SplitterOffset - 2, rect.right - 2, 4); ReleaseDC(hwnd, hdc); - SplitterOffset = pt.y; + Context->SplitterOffset = pt.y; Context->DragMode = FALSE; GetWindowRect(hwnd, &rect); - pt.x += rect.left; pt.y += rect.top; - ScreenToClient(hwnd, &pt); GetClientRect(hwnd, &rect); - nSplitterPos = pt.y; + Context->SplitterPosition = pt.y; // position the child controls PhHSplitterHandleWmSize(Context, rect.right, rect.bottom); @@ -187,7 +185,7 @@ VOID PhHSplitterHandleMouseMove( ClientToScreen(hwnd, &windowPoint); if (Context->DragMode) - { + { windowPoint.x -= windowRect.left; windowPoint.y -= windowRect.top; @@ -198,13 +196,13 @@ VOID PhHSplitterHandleMouseMove( if (windowPoint.y > Context->Bottomitem->Rect.bottom - SPLITTER_MIN_HEIGHT) windowPoint.y = Context->Bottomitem->Rect.bottom - SPLITTER_MIN_HEIGHT; - if (windowPoint.y != SplitterOffset) + if (windowPoint.y != Context->SplitterOffset) { hdc = GetWindowDC(hwnd); if (wParam & MK_LBUTTON) { - DrawXorBar(hdc, 1, SplitterOffset - 2, windowRect.right - 2, 4); + DrawXorBar(hdc, 1, Context->SplitterOffset - 2, windowRect.right - 2, 4); DrawXorBar(hdc, 1, windowPoint.y - 2, windowRect.right - 2, 4); } else @@ -222,7 +220,7 @@ VOID PhHSplitterHandleMouseMove( } ReleaseDC(hwnd, hdc); - SplitterOffset = windowPoint.y; + Context->SplitterOffset = windowPoint.y; } } } From f98ce0ad557add098347de553475571860211f60 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 26 Apr 2017 17:24:40 +1000 Subject: [PATCH 0016/2058] CustomSetupTool: Add settings file upgrade, Fix uinstall cleanup --- .../CustomSetupTool/CustomSetupTool/appsup.c | 2 +- .../CustomSetupTool/include/setup.h | 4 + tools/CustomSetupTool/CustomSetupTool/page4.c | 1 + tools/CustomSetupTool/CustomSetupTool/setup.c | 81 +++++++++++++++++-- .../CustomSetupTool/uninstall.c | 3 + 5 files changed, 85 insertions(+), 6 deletions(-) diff --git a/tools/CustomSetupTool/CustomSetupTool/appsup.c b/tools/CustomSetupTool/CustomSetupTool/appsup.c index 0de46b959b1b..fa09d200d337 100644 --- a/tools/CustomSetupTool/CustomSetupTool/appsup.c +++ b/tools/CustomSetupTool/CustomSetupTool/appsup.c @@ -630,7 +630,7 @@ BOOLEAN RemoveDirectoryPath(_In_ PWSTR DirPath) FindClose(findHandle); // Delete the parent directory - SetupDeleteDirectoryFile(DirPath); + RemoveDirectory(DirPath); PhDereferenceObject(findPath); return TRUE; diff --git a/tools/CustomSetupTool/CustomSetupTool/include/setup.h b/tools/CustomSetupTool/CustomSetupTool/include/setup.h index 6bfa3a0ad149..bca1fad59bc9 100644 --- a/tools/CustomSetupTool/CustomSetupTool/include/setup.h +++ b/tools/CustomSetupTool/CustomSetupTool/include/setup.h @@ -165,6 +165,10 @@ VOID SetupCreateUninstallFile( VOID ); +VOID SetupDeleteUninstallFile( + VOID + ); + BOOLEAN SetupExecuteProcessHacker( _In_ HWND Parent ); diff --git a/tools/CustomSetupTool/CustomSetupTool/page4.c b/tools/CustomSetupTool/CustomSetupTool/page4.c index 0fa1f085be1e..236086b28f38 100644 --- a/tools/CustomSetupTool/CustomSetupTool/page4.c +++ b/tools/CustomSetupTool/CustomSetupTool/page4.c @@ -45,6 +45,7 @@ NTSTATUS SetupProgressThread( if (!CreateDirectoryPath(PhGetString(SetupInstallPath))) goto CleanupExit; + // Upgrade the 2.x settings file. SetupUpgradeSettingsFile(); // Remove the previous installation. diff --git a/tools/CustomSetupTool/CustomSetupTool/setup.c b/tools/CustomSetupTool/CustomSetupTool/setup.c index d32e501f5282..9309fa223e2f 100644 --- a/tools/CustomSetupTool/CustomSetupTool/setup.c +++ b/tools/CustomSetupTool/CustomSetupTool/setup.c @@ -190,6 +190,77 @@ VOID SetupCreateUninstallFile( PhDereferenceObject(uninstallFilePath); } +VOID SetupDeleteUninstallFile( + VOID + ) +{ + PPH_STRING uninstallFilePath; + + // NtCurrentPeb()->ProcessParameters->ImagePathName.Buffer + uninstallFilePath = PhConcatStrings2(PhGetString(SetupInstallPath), L"\\processhacker-setup.exe"); + + if (RtlDoesFileExists_U(uninstallFilePath->Buffer)) + { + ULONG indexOfFileName = -1; + GUID randomGuid; + PPH_STRING setupTempPath = NULL; + PPH_STRING randomGuidString = NULL; + PPH_STRING fullSetupPath = NULL; + PPH_STRING tempFilePath = NULL; + + setupTempPath = PhCreateStringEx(NULL, GetTempPath(0, NULL) * sizeof(WCHAR)); + if (PhIsNullOrEmptyString(setupTempPath)) + goto CleanupExit; + if (GetTempPath((ULONG)setupTempPath->Length / sizeof(WCHAR), setupTempPath->Buffer) == 0) + goto CleanupExit; + if (PhIsNullOrEmptyString(setupTempPath)) + goto CleanupExit; + + // Generate random guid for our directory path. + PhGenerateGuid(&randomGuid); + + if (randomGuidString = PhFormatGuid(&randomGuid)) + { + PPH_STRING guidSubString; + + // Strip the left and right curly brackets. + guidSubString = PhSubstring(randomGuidString, 1, randomGuidString->Length / sizeof(WCHAR) - 2); + PhMoveReference(&randomGuidString, guidSubString); + } + + // Append the tempath to our string: %TEMP%RandomString\\processhacker-setup.exe + // Example: C:\\Users\\dmex\\AppData\\Temp\\processhacker-setup.exe + tempFilePath = PhFormatString( + L"%s%s\\processhacker-setup.exe", + PhGetStringOrEmpty(setupTempPath), + PhGetStringOrEmpty(randomGuidString) + ); + if (PhIsNullOrEmptyString(tempFilePath)) + goto CleanupExit; + + // Create the directory if it does not exist. + if (fullSetupPath = PhGetFullPath(PhGetString(tempFilePath), &indexOfFileName)) + { + PPH_STRING directoryPath; + + if (indexOfFileName == -1) + goto CleanupExit; + + if (directoryPath = PhSubstring(fullSetupPath, 0, indexOfFileName)) + { + SHCreateDirectoryEx(NULL, directoryPath->Buffer, NULL); + PhDereferenceObject(directoryPath); + } + } + + MoveFile(uninstallFilePath->Buffer, fullSetupPath->Buffer); + } + +CleanupExit: + + PhDereferenceObject(uninstallFilePath); +} + VOID SetupInstallKph( VOID ) @@ -485,11 +556,11 @@ VOID SetupUpgradeSettingsFile( settingsFilePath = PhGetKnownLocation(CSIDL_APPDATA, L"\\Process Hacker\\settings.xml"); oldSettingsFileName = PhGetKnownLocation(CSIDL_APPDATA, L"\\Process Hacker 2\\settings.xml"); - if (!RtlDoesFileExists_U(settingsFilePath->Buffer)) - { - CopyFile(oldSettingsFileName->Buffer, settingsFilePath->Buffer, FALSE); - } - + if (RtlDoesFileExists_U(settingsFilePath->Buffer)) + SetupDeleteDirectoryFile(settingsFilePath->Buffer); + + CopyFile(oldSettingsFileName->Buffer, settingsFilePath->Buffer, FALSE); + PhDereferenceObject(oldSettingsFileName); PhDereferenceObject(settingsFilePath); } \ No newline at end of file diff --git a/tools/CustomSetupTool/CustomSetupTool/uninstall.c b/tools/CustomSetupTool/CustomSetupTool/uninstall.c index f2d5124f120a..da0493de2d9b 100644 --- a/tools/CustomSetupTool/CustomSetupTool/uninstall.c +++ b/tools/CustomSetupTool/CustomSetupTool/uninstall.c @@ -66,6 +66,9 @@ NTSTATUS SetupUninstallBuild( // Remove autorun and shortcuts. SetupDeleteWindowsOptions(); + // Remove the uninstaller. + SetupDeleteUninstallFile(); + // Remove the previous installation. if (!RemoveDirectoryPath(PhGetString(SetupInstallPath))) goto CleanupExit; From 6d4dd79b303000900e10958f1792f6b21dfe5e0d Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 26 Apr 2017 18:17:06 +1000 Subject: [PATCH 0017/2058] peview: Improve flags layout --- tools/peview/peview.rc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/peview/peview.rc b/tools/peview/peview.rc index 6f48fb7e7d01..28530525caa9 100644 --- a/tools/peview/peview.rc +++ b/tools/peview/peview.rc @@ -133,7 +133,7 @@ BEGIN LTEXT "Static",IDC_SUBSYSTEMVERSION,78,122,215,8 CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,156,286,116 LTEXT "Sections:",IDC_STATIC,7,146,30,8 - EDITTEXT IDC_CHARACTERISTICS,76,133,217,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + EDITTEXT IDC_CHARACTERISTICS,76,133,217,23,ES_MULTILINE | ES_READONLY | NOT WS_BORDER LTEXT "Time stamp:",IDC_STATIC,7,68,40,8 LTEXT "Static",IDC_TIMESTAMP,78,68,215,8 LTEXT "Entry point:",IDC_STATIC,7,90,39,8 From 178cd0ed539a1ae385cd5e717277743d08aa7e0e Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 27 Apr 2017 13:19:38 +1000 Subject: [PATCH 0018/2058] peview: Fix file encoding, Fix long library name text clipping --- tools/peview/peprp.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/peview/peprp.c b/tools/peview/peprp.c index 7228b6a4ed84..22512aeac285 100644 --- a/tools/peview/peprp.c +++ b/tools/peview/peprp.c @@ -572,6 +572,8 @@ INT_PTR CALLBACK PvpPeGeneralDlgProc( PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL); PvAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_FILE), dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); + PvAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_NAME), + dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); PvAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_CHARACTERISTICS), dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); PvAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_LIST), From 10ba1babb7b28050170207a4ef3ca47edec412af Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 27 Apr 2017 13:54:50 +1000 Subject: [PATCH 0019/2058] Update git config --- .gitattributes | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitattributes b/.gitattributes index 7d0255299ac0..b895d0391026 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,5 +1,5 @@ # Auto detect text files -* text=auto +* text=crlf # Custom for Visual Studio *.cs diff=csharp From d497e61800dcb36a34208d8e3bd72ce556c84afa Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 27 Apr 2017 13:56:14 +1000 Subject: [PATCH 0020/2058] DotNetTools: Autosize appdomains column --- plugins/DotNetTools/perfpage.c | 1907 ++++++++++++++++---------------- 1 file changed, 958 insertions(+), 949 deletions(-) diff --git a/plugins/DotNetTools/perfpage.c b/plugins/DotNetTools/perfpage.c index a86c0a565b99..c5cf54c72bcf 100644 --- a/plugins/DotNetTools/perfpage.c +++ b/plugins/DotNetTools/perfpage.c @@ -1,950 +1,959 @@ -/* - * Process Hacker .NET Tools - - * .NET Performance property page - * - * Copyright (C) 2011-2015 wj32 - * Copyright (C) 2015 dmex - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - - -#include "dn.h" -#include "clr\perfcounterdefs.h" - -typedef enum _DOTNET_CATEGORY -{ - // .NET CLR Exceptions (Runtime statistics on CLR exception handling) - DOTNET_CATEGORY_EXCEPTIONS, - - // .NET CLR Interop (Stats for CLR interop) - DOTNET_CATEGORY_INTEROP, - - // .NET CLR Jit (Stats for CLR Jit) - DOTNET_CATEGORY_JIT, - - // .NET CLR Loading (Statistics for CLR Class Loader) - DOTNET_CATEGORY_LOADING, - - // .NET CLR LocksAndThreads (Stats for CLR Locks and Threads) - DOTNET_CATEGORY_LOCKSANDTHREADS, - - // .NET CLR Memory (Counters for CLR Garbage Collected heap) - DOTNET_CATEGORY_MEMORY, - - // .NET CLR Remoting (Stats for CLR Remoting) - DOTNET_CATEGORY_REMOTING, - - // .NET CLR Security (Stats for CLR Security) - DOTNET_CATEGORY_SECURITY -} DOTNET_CATEGORY; - -typedef struct _PERFPAGE_CONTEXT -{ - HWND WindowHandle; - PPH_PROCESS_ITEM ProcessItem; - BOOLEAN Enabled; - - HWND AppDomainsLv; - HWND CountersLv; - HWND CategoriesCb; - - BOOLEAN ControlBlockValid; - BOOLEAN ClrV4; - BOOLEAN IsWow64; - BOOLEAN ShowByteSize; - DOTNET_CATEGORY CategoryIndex; - HANDLE ProcessHandle; - HANDLE BlockTableHandle; - PVOID BlockTableAddress; - - PH_CALLBACK_REGISTRATION ProcessesUpdatedCallbackRegistration; -} PERFPAGE_CONTEXT, *PPERFPAGE_CONTEXT; - -static PWSTR DotNetCategoryStrings[] = -{ - L".NET CLR Exceptions", - L".NET CLR Interop", - L".NET CLR Jit", - L".NET CLR Loading", - L".NET CLR LocksAndThreads", - L".NET CLR Memory", - L".NET CLR Remoting", - L".NET CLR Security" -}; - -PPH_STRING FormatByteValue( - _In_ PPERFPAGE_CONTEXT Context, - _In_ ULONG64 Value - ) -{ - if (Context->ShowByteSize) - return PhaFormatUInt64(Value, TRUE); - - return PhaFormatSize(Value, -1); -} - -VOID NTAPI ProcessesUpdatedCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - PPERFPAGE_CONTEXT context = Context; - - if (context->WindowHandle) - { - PostMessage(context->WindowHandle, MSG_UPDATE, 0, 0); - } -} - -VOID UpdateCategoryValues( - _In_ HWND hwndDlg, - _In_ PPERFPAGE_CONTEXT Context - ) -{ - ListView_DeleteAllItems(Context->CountersLv); - - switch (Context->CategoryIndex) - { - case DOTNET_CATEGORY_EXCEPTIONS: - { - // This counter displays the total number of exceptions thrown since the start of the application. These include both .NET exceptions and unmanaged exceptions that get converted into .NET exceptions e.g. null pointer reference exception in unmanaged code would get re-thrown in managed code as a .NET System.NullReferenceException; this counter includes both handled and unhandled exceptions.Exceptions that are re-thrown would get counted again. Exceptions should only occur in rare situations and not in the normal control flow of the program. - PhAddListViewItem(Context->CountersLv, MAXINT, L"# of Exceps Thrown", NULL); - PhAddListViewItem(Context->CountersLv, MAXINT, L"# of Filters Executed", NULL); - PhAddListViewItem(Context->CountersLv, MAXINT, L"# of Finallys Executed", NULL); - - // Reserved for future use. - //PhAddListViewItem(Context->CountersLv, MAXINT, L" Delta from throw to catch site on stack", NULL); - - // # of Exceps Thrown / sec - // This counter displays the number of exceptions thrown per second.These include both.NET exceptions and unmanaged exceptions that get converted into.NET exceptions e.g.null pointer reference exception in unmanaged code would get re - thrown in managed code as a.NET System.NullReferenceException; this counter includes both handled and unhandled exceptions.Exceptions should only occur in rare situations and not in the normal control flow of the program; this counter was designed as an indicator of potential performance problems due to large(> 100s) rate of exceptions thrown.This counter is not an average over time; it displays the difference between the values observed in the last two samples divided by the duration of the sample interval. - - // # of Filters / sec - // This counter displays the number of.NET exception filters executed per second.An exception filter evaluates whether an exception should be handled or not.This counter tracks the rate of exception filters evaluated; irrespective of whether the exception was handled or not.This counter is not an average over time; it displays the difference between the values observed in the last two samples divided by the duration of the sample interval. - - // # of Finallys / sec - // This counter displays the number of finally blocks executed per second.A finally block is guaranteed to be executed regardless of how the try block was exited.Only the finally blocks that are executed for an exception are counted; finally blocks on normal code paths are not counted by this counter.This counter is not an average over time; it displays the difference between the values observed in the last two samples divided by the duration of the sample interval. - - // Throw To Catch Depth / sec - // This counter displays the number of stack frames traversed from the frame that threw the.NET exception to the frame that handled the exception per second.This counter resets to 0 when an exception handler is entered; so nested exceptions would show the handler to handler stack depth.This counter is not an average over time; it displays the difference between the values observed in the last two samples divided by the duration of the sample interval.* / - } - break; - case DOTNET_CATEGORY_INTEROP: - { - // This counter displays the current number of Com-Callable-Wrappers (CCWs). A CCW is a proxy for the .NET managed object being referenced from unmanaged COM client(s). This counter was designed to indicate the number of managed objects being referenced by unmanaged COM code. - PhAddListViewItem(Context->CountersLv, MAXINT, L"# of CCWs", NULL); - - // This counter displays the current number of stubs created by the CLR. Stubs are responsible for marshalling arguments and return values from managed to unmanaged code and vice versa; during a COM Interop call or PInvoke call. - PhAddListViewItem(Context->CountersLv, MAXINT, L"# of Stubs", NULL); - - // This counter displays the total number of times arguments and return values have been marshaled from managed to unmanaged code and vice versa since the start of the application. This counter is not incremented if the stubs are inlined. (Stubs are responsible for marshalling arguments and return values). Stubs usually get inlined if the marshalling overhead is small. - PhAddListViewItem(Context->CountersLv, MAXINT, L"# of Marshalling", NULL); - - // Reserved for future use. - PhAddListViewItem(Context->CountersLv, MAXINT, L"# of TLB imports / sec", NULL); - - // Reserved for future use. - PhAddListViewItem(Context->CountersLv, MAXINT, L"# of TLB exports / sec", NULL); - } - break; - case DOTNET_CATEGORY_JIT: - { - // This counter displays the total number of methods compiled Just-In-Time (JIT) by the CLR JIT compiler since the start of the application. This counter does not include the pre-jitted methods. - PhAddListViewItem(Context->CountersLv, MAXINT, L"# of Methods Jitted", NULL); - - // This counter displays the total IL bytes jitted since the start of the application. This counter is exactly equivalent to the "Total # of IL Bytes Jitted" counter. - PhAddListViewItem(Context->CountersLv, MAXINT, L"# of IL Bytes Jitted", NULL); - - // This counter displays the total IL bytes jitted since the start of the application. This counter is exactly equivalent to the "# of IL Bytes Jitted" counter. - PhAddListViewItem(Context->CountersLv, MAXINT, L"Total # of IL Bytes Jitted", NULL); - - // This counter displays the peak number of methods the JIT compiler has failed to JIT since the start of the application. This failure can occur if the IL cannot be verified or if there was an internal error in the JIT compiler. - PhAddListViewItem(Context->CountersLv, MAXINT, L"Jit Failures", NULL); - - // This counter displays the percentage of elapsed time spent in JIT compilation since the last JIT compilation phase. This counter is updated at the end of every JIT compilation phase. A JIT compilation phase is the phase when a method and its dependencies are being compiled. - PhAddListViewItem(Context->CountersLv, MAXINT, L"% Time in Jit", NULL); - - // IL Bytes Jitted / sec - // This counter displays the rate at which IL bytes are jitted per second. This counter is not an average over time; it displays the difference between the values observed in the last two samples divided by the duration of the sample interval. - } - break; - case DOTNET_CATEGORY_LOADING: - { - // This counter displays the current number of classes loaded in all Assemblies. - PhAddListViewItem(Context->CountersLv, MAXINT, L"Current Classes Loaded", NULL); - - // This counter displays the cumulative number of classes loaded in all Assemblies since the start of this application. - PhAddListViewItem(Context->CountersLv, MAXINT, L"Total Classes Loaded", NULL); - - // This counter displays the current number of AppDomains loaded in this application. AppDomains (application domains) provide a secure and versatile unit of processing that the CLR can use to provide isolation between applications running in the same process. - PhAddListViewItem(Context->CountersLv, MAXINT, L"Current Appdomains", NULL); - - // This counter displays the peak number of AppDomains loaded since the start of this application. AppDomains (application domains) provide a secure and versatile unit of processing that the CLR can use to provide isolation between applications running in the same process. - PhAddListViewItem(Context->CountersLv, MAXINT, L"Total Appdomains", NULL); - - // This counter displays the current number of Assemblies loaded across all AppDomains in this application. If the Assembly is loaded as domain - neutral from multiple AppDomains then this counter is incremented once only. Assemblies can be loaded as domain - neutral when their code can be shared by all AppDomains or they can be loaded as domain - specific when their code is private to the AppDomain. - PhAddListViewItem(Context->CountersLv, MAXINT, L"Current Assemblies", NULL); - - // This counter displays the total number of Assemblies loaded since the start of this application. If the Assembly is loaded as domain - neutral from multiple AppDomains then this counter is incremented once only. Assemblies can be loaded as domain - neutral when their code can be shared by all AppDomains or they can be loaded as domain - specific when their code is private to the AppDomain. - PhAddListViewItem(Context->CountersLv, MAXINT, L"Total Assemblies", NULL); - - // Reserved for future use. - PhAddListViewItem(Context->CountersLv, MAXINT, L"Assembly Search Length", NULL); - - // This counter displays the peak number of classes that have failed to load since the start of the application.These load failures could be due to many reasons like inadequate security or illegal format.Full details can be found in the profiling services help. - PhAddListViewItem(Context->CountersLv, MAXINT, L"Total # of Load Failures", NULL); - - // This counter displays the current size(in bytes) of the memory committed by the class loader across all AppDomains. (Committed memory is the physical memory for which space has been reserved on the disk paging file.) - PhAddListViewItem(Context->CountersLv, MAXINT, L"Bytes in Loader Heap", NULL); - - // This counter displays the total number of AppDomains unloaded since the start of the application. If an AppDomain is loaded and unloaded multiple times this counter would count each of those unloads as separate. - PhAddListViewItem(Context->CountersLv, MAXINT, L"Total Appdomains Unloaded", NULL); - - // Reserved for future use. - //PhAddListViewItem(Context->CountersLv, MAXINT, L"% Time Loading", NULL); - - // Rate of Load Failures - // This counter displays the number of classes that failed to load per second. This counter is not an average over time; it displays the difference between the values observed in the last two samples divided by the duration of the sample interval. These load failures could be due to many reasons like inadequate security or illegal format. Full details can be found in the profiling services help. - - // Rate of appdomains unloaded - // This counter displays the number of AppDomains unloaded per second.This counter is not an average over time; it displays the difference between the values observed in the last two samples divided by the duration of the sample interval. - - // Rate of Classes Loaded - // This counter displays the number of classes loaded per second in all Assemblies.This counter is not an average over time; it displays the difference between the values observed in the last two samples divided by the duration of the sample interval. - - // Rate of appdomains - // This counter displays the number of AppDomains loaded per second.AppDomains(application domains) provide a secure and versatile unit of processing that the CLR can use to provide isolation between applications running in the same process.This counter is not an average over time; it displays the difference between the values observed in the last two samples divided by the duration of the sample interval. - - // Rate of Assemblies - // This counter displays the number of Assemblies loaded across all AppDomains per second.If the Assembly is loaded as domain - neutral from multiple AppDomains then this counter is incremented once only.Assemblies can be loaded as domain - neutral when their code can be shared by all AppDomains or they can be loaded as domain - specific when their code is private to the AppDomain.This counter is not an average over time; it displays the difference between the values observed in the last two samples divided by the duration of the sample interval. - } - break; - case DOTNET_CATEGORY_LOCKSANDTHREADS: - { - // This counter displays the total number of times threads in the CLR have attempted to acquire a managed lock unsuccessfully. Managed locks can be acquired in many ways; by the "lock" statement in C# or by calling System.Monitor.Enter or by using MethodImplOptions.Synchronized custom attribute. - PhAddListViewItem(Context->CountersLv, MAXINT, L"Total # of Contentions", NULL); - - // This counter displays the total number of threads currently waiting to acquire some managed lock in the application. This counter is not an average over time; it displays the last observed value. - PhAddListViewItem(Context->CountersLv, MAXINT, L"Current Queue Length", NULL); - - // This counter displays the total number of threads that waited to acquire some managed lock since the start of the application. - PhAddListViewItem(Context->CountersLv, MAXINT, L"Queue Length Peak", NULL); - - // This counter displays the number of current.NET thread objects in the application.A.NET thread object is created either by new System.Threading.Thread or when an unmanaged thread enters the managed environment. This counters maintains the count of both running and stopped threads. This counter is not an average over time; it just displays the last observed value. - PhAddListViewItem(Context->CountersLv, MAXINT, L"# of Current Logical Threads", NULL); - - // This counter displays the number of native OS threads created and owned by the CLR to act as underlying threads for .NET thread objects. This counters value does not include the threads used by the CLR in its internal operations; it is a subset of the threads in the OS process. - PhAddListViewItem(Context->CountersLv, MAXINT, L"# of Current Physical Threads", NULL); - - // This counter displays the number of threads that are currently recognized by the CLR; they have a corresponding .NET thread object associated with them. These threads are not created by the CLR; they are created outside the CLR but have since run inside the CLR at least once. Only unique threads are tracked; threads with same thread ID re-entering the CLR or recreated after thread exit are not counted twice. - PhAddListViewItem(Context->CountersLv, MAXINT, L"# of Current Recognized Threads", NULL); - - // This counter displays the total number of threads that have been recognized by the CLR since the start of this application; these threads have a corresponding .NET thread object associated with them. These threads are not created by the CLR; they are created outside the CLR but have since run inside the CLR at least once. Only unique threads are tracked; threads with same thread ID re-entering the CLR or recreated after thread exit are not counted twice. - PhAddListViewItem(Context->CountersLv, MAXINT, L"# of Total Recognized Threads", NULL); - - // Contention Rate / sec - // Rate at which threads in the runtime attempt to acquire a managed lock unsuccessfully.Managed locks can be acquired in many ways; by the "lock" statement in C# or by calling System.Monitor.Enter or by using MethodImplOptions.Synchronized custom attribute. - - // Queue Length / sec - // This counter displays the number of threads per second waiting to acquire some lock in the application. This counter is not an average over time; it displays the difference between the values observed in the last two samples divided by the duration of the sample interval. - - // rate of recognized threads / sec - // This counter displays the number of threads per second that have been recognized by the CLR; these threads have a corresponding .NET thread object associated with them. These threads are not created by the CLR; they are created outside the CLR but have since run inside the CLR at least once. Only unique threads are tracked; threads with same thread ID re-entering the CLR or recreated after thread exit are not counted twice. This counter is not an average over time; it displays the difference between the values observed in the last two samples divided by the duration of the sample interval. - } - break; - case DOTNET_CATEGORY_MEMORY: - { - // This counter displays the number of times the generation 0 objects (youngest; most recently allocated) are garbage collected (Gen 0 GC) since the start of the application. Gen 0 GC occurs when the available memory in generation 0 is not sufficient to satisfy an allocation request. This counter is incremented at the end of a Gen 0 GC. Higher generation GCs include all lower generation GCs.This counter is explicitly incremented when a higher generation (Gen 1 or Gen 2) GC occurs. _Global_ counter value is not accurate and should be ignored. This counter displays the last observed value. - PhAddListViewItem(Context->CountersLv, MAXINT, L"# Gen 0 Collections", NULL); - - // This counter displays the number of times the generation 1 objects are garbage collected since the start of the application. The counter is incremented at the end of a Gen 1 GC. Higher generation GCs include all lower generation GCs. This counter is explicitly incremented when a higher generation (Gen 2) GC occurs. _Global_ counter value is not accurate and should be ignored. This counter displays the last observed value. - PhAddListViewItem(Context->CountersLv, MAXINT, L"# Gen 1 Collections", NULL); - - // This counter displays the number of times the generation 2 objects(older) are garbage collected since the start of the application.The counter is incremented at the end of a Gen 2 GC(also called full GC)._Global_ counter value is not accurate and should be ignored.This counter displays the last observed value. - PhAddListViewItem(Context->CountersLv, MAXINT, L"# Gen 2 Collections", NULL); - - // This counter displays the bytes of memory that survive garbage collection(GC) and are promoted from generation 0 to generation 1; objects that are promoted just because they are waiting to be finalized are not included in this counter.This counter displays the value observed at the end of the last GC; its not a cumulative counter. - PhAddListViewItem(Context->CountersLv, MAXINT, L"Promoted Memory from Gen 0", NULL); - - // This counter displays the bytes of memory that survive garbage collection(GC) and are promoted from generation 1 to generation 2; objects that are promoted just because they are waiting to be finalized are not included in this counter.This counter displays the value observed at the end of the last GC; its not a cumulative counter.This counter is reset to 0 if the last GC was a Gen 0 GC only. - PhAddListViewItem(Context->CountersLv, MAXINT, L"Promoted Memory from Gen 1", NULL); - - // This counter displays the bytes of memory that are promoted from generation 0 to generation 1 just because they are waiting to be finalized.This counter displays the value observed at the end of the last GC; its not a cumulative counter. - PhAddListViewItem(Context->CountersLv, MAXINT, L"Promoted Finalization-Memory from Gen 0", NULL); - - // Reserved for future use. - PhAddListViewItem(Context->CountersLv, MAXINT, L"Process ID", NULL); - - // This counter displays the maximum bytes that can be allocated in generation 0 (Gen 0); its does not indicate the current number of bytes allocated in Gen 0. A Gen 0 GC is triggered when the allocations since the last GC exceed this size.The Gen 0 size is tuned by the Garbage Collector and can change during the execution of the application.At the end of a Gen 0 collection the size of the Gen 0 heap is infact 0 bytes; this counter displays the size(in bytes) of allocations that would trigger the next Gen 0 GC.This counter is updated at the end of a GC; its not updated on every allocation. - PhAddListViewItem(Context->CountersLv, MAXINT, L"Gen 0 Heap Size", NULL); - - // This counter displays the current number of bytes in generation 1 (Gen 1); this counter does not display the maximum size of Gen 1. Objects are not directly allocated in this generation; they are promoted from previous Gen 0 GCs.This counter is updated at the end of a GC; its not updated on every allocation. - PhAddListViewItem(Context->CountersLv, MAXINT, L"Gen 1 Heap Size", NULL); - - // This counter displays the current number of bytes in generation 2 (Gen 2).Objects are not directly allocated in this generation; they are promoted from Gen 1 during previous Gen 1 GCs.This counter is updated at the end of a GC; its not updated on every allocation. - PhAddListViewItem(Context->CountersLv, MAXINT, L"Gen 2 Heap Size", NULL); - - // This counter displays the current size of the Large Object Heap in bytes.Objects greater than 20 KBytes are treated as large objects by the Garbage Collector and are directly allocated in a special heap; they are not promoted through the generations.This counter is updated at the end of a GC; its not updated on every allocation. - PhAddListViewItem(Context->CountersLv, MAXINT, L"Large Object Heap Size", NULL); - - // This counter displays the number of garbage collected objects that survive a collection because they are waiting to be finalized.If these objects hold references to other objects then those objects also survive but are not counted by this counter; the "Promoted Finalization-Memory from Gen 0" and "Promoted Finalization-Memory from Gen 1" counters represent all the memory that survived due to finalization.This counter is not a cumulative counter; its updated at the end of every GC with count of the survivors during that particular GC only.This counter was designed to indicate the extra overhead that the application might incur because of finalization. - PhAddListViewItem(Context->CountersLv, MAXINT, L"Finalization Survivors", NULL); - - // This counter displays the current number of GC Handles in use.GCHandles are handles to resources external to the CLR and the managed environment.Handles occupy small amounts of memory in the GCHeap but potentially expensive unmanaged resources. - PhAddListViewItem(Context->CountersLv, MAXINT, L"# GC Handles", NULL); - - // This counter displays the peak number of times a garbage collection was performed because of an explicit call to GC.Collect. Its a good practice to let the GC tune the frequency of its collections. - PhAddListViewItem(Context->CountersLv, MAXINT, L"# Induced GC", NULL); - - // % Time in GC is the percentage of elapsed time that was spent in performing a garbage collection(GC) since the last GC cycle. This counter is usually an indicator of the work done by the Garbage Collector on behalf of the application to collect and compact memory.This counter is updated only at the end of every GC and the counter value reflects the last observed value; its not an average. - PhAddListViewItem(Context->CountersLv, MAXINT, L"% Time in GC", NULL); - - // This counter is the sum of four other counters; Gen 0 Heap Size; Gen 1 Heap Size; Gen 2 Heap Size and the Large Object Heap Size. This counter indicates the current memory allocated in bytes on the GC Heaps. - PhAddListViewItem(Context->CountersLv, MAXINT, L"# Bytes in all Heaps", NULL); - - // This counter displays the amount of virtual memory(in bytes) currently committed by the Garbage Collector. (Committed memory is the physical memory for which space has been reserved on the disk paging file). - PhAddListViewItem(Context->CountersLv, MAXINT, L"# Total Committed Bytes", NULL); - - // This counter displays the amount of virtual memory(in bytes) currently reserved by the Garbage Collector. (Reserved memory is the virtual memory space reserved for the application but no disk or main memory pages have been used.) - PhAddListViewItem(Context->CountersLv, MAXINT, L"# Total Reserved Bytes", NULL); - - // This counter displays the number of pinned objects encountered in the last GC. This counter tracks the pinned objects only in the heaps that were garbage collected e.g. A Gen 0 GC would cause enumeration of pinned objects in the generation 0 heap only. A pinned object is one that the Garbage Collector cannot move in memory. - PhAddListViewItem(Context->CountersLv, MAXINT, L"# of Pinned Objects", NULL); - - // This counter displays the current number of sync blocks in use. Sync blocks are per-object data structures allocated for storing synchronization information. Sync blocks hold weak references to managed objects and need to be scanned by the Garbage Collector. Sync blocks are not limited to storing synchronization information and can also store COM interop metadata. This counter was designed to indicate performance problems with heavy use of synchronization primitives. - PhAddListViewItem(Context->CountersLv, MAXINT, L"# of Sink Blocks in use", NULL); - - // Reserved for future use. - PhAddListViewItem(Context->CountersLv, MAXINT, L"Total Bytes Allocated (since start)", NULL); - - // Reserved for future use. - PhAddListViewItem(Context->CountersLv, MAXINT, L"Total Bytes Allocated for Large Objects (since start)", NULL); - - // Gen 0 Promoted Bytes / Sec - // This counter displays the bytes per second that are promoted from generation 0 (youngest)to generation 1; objects that are promoted just because they are waiting to be finalized are not included in this counter.Memory is promoted when it survives a garbage collection.This counter was designed as an indicator of relatively long - lived objects being created per sec.This counter displays the difference between the values observed in the last two samples divided by the duration of the sample interval. - - // Gen 1 Promoted Bytes / Sec - // This counter displays the bytes per second that are promoted from generation 1 to generation 2 (oldest); objects that are promoted just because they are waiting to be finalized are not included in this counter.Memory is promoted when it survives a garbage collection.Nothing is promoted from generation 2 since it is the oldest.This counter was designed as an indicator of very long - lived objects being created per sec.This counter displays the difference between the values observed in the last two samples divided by the duration of the sample interval. - - // Promoted Finalization - Memory from Gen 1 - // This counter displays the bytes of memory that are promoted from generation 1 to generation 2 just because they are waiting to be finalized.This counter displays the value observed at the end of the last GC; its not a cumulative counter.This counter is reset to 0 if the last GC was a Gen 0 GC only. - - // Allocated Bytes / sec - // This counter displays the rate of bytes per second allocated on the GC Heap.This counter is updated at the end of every GC; not at each allocation.This counter is not an average over time; it displays the difference between the values observed in the last two samples divided by the duration of the sample interval. - } - break; - case DOTNET_CATEGORY_REMOTING: - { - // This counter displays the total number of remote procedure calls invoked since the start of this application. A remote procedure call is a call on any object outside the callers AppDomain. - PhAddListViewItem(Context->CountersLv, MAXINT, L"Total Remote Calls", NULL); - - // This counter displays the total number of remoting channels registered across all AppDomains since the start of the application. Channels are used to transport messages to and from remote objects. - PhAddListViewItem(Context->CountersLv, MAXINT, L"Channels", NULL); - - // This counter displays the total number of remoting proxy objects created in this process since the start of the process. Proxy object acts as a representative of the remote objects and ensures that all calls made on the proxy are forwarded to the correct remote object instance. - PhAddListViewItem(Context->CountersLv, MAXINT, L"Context Proxies", NULL); - - // This counter displays the current number of context-bound classes loaded. Classes that can be bound to a context are called context-bound classes; context-bound classes are marked with Context Attributes which provide usage rules for synchronization; thread affinity; transactions etc. - PhAddListViewItem(Context->CountersLv, MAXINT, L"Context-Bound Classes Loaded", NULL); - - // This counter displays the current number of remoting contexts in the application. A context is a boundary containing a collection of objects with the same usage rules like synchronization; thread affinity; transactions etc. - PhAddListViewItem(Context->CountersLv, MAXINT, L"Contexts", NULL); - - PhAddListViewItem(Context->CountersLv, MAXINT, L"# of context bound objects allocated", NULL); - - // Remote Calls / sec - // This counter displays the number of remote procedure calls invoked per second. A remote procedure call is a call on any object outside the callers AppDomain. This counter is not an average over time; it displays the difference between the values observed in the last two samples divided by the duration of the sample interval. - - // Context - Bound Objects Alloc / sec - // This counter displays the number of context - bound objects allocated per second. Instances of classes that can be bound to a context are called context - bound objects; context - bound classes are marked with Context Attributes which provide usage rules for synchronization; thread affinity; transactions etc.This counter is not an average over time; it displays the difference between the values observed in the last two samples divided by the duration of the sample interval. - } - break; - case DOTNET_CATEGORY_SECURITY: - { - // This counter displays the total number of runtime Code Access Security(CAS) checks performed since the start of the application. Runtime CAS checks are performed when a caller makes a call to a callee demanding a particular permission; the runtime check is made on every call by the caller; the check is done by examining the current thread stack of the caller. This counter used together with "Stack Walk Depth" is indicative of performance penalty for security checks. - PhAddListViewItem(Context->CountersLv, MAXINT, L"Total Runtime Checks", NULL); - - // This counter displays the total number of linktime Code Access Security(CAS) checks since the start of the application. Linktime CAS checks are performed when a caller makes a call to a callee demanding a particular permission at JIT compile time; linktime check is performed once per caller. This count is not indicative of serious performance issues; its indicative of the security system activity. - PhAddListViewItem(Context->CountersLv, MAXINT, L"# Link Time Checks", NULL); - - // This counter displays the percentage of elapsed time spent in performing runtime Code Access Security(CAS) checks since the last such check. CAS allows code to be trusted to varying degrees and enforces these varying levels of trust depending on code identity. This counter is updated at the end of a runtime security check; it represents the last observed value; its not an average. - PhAddListViewItem(Context->CountersLv, MAXINT, L"% Time in RT checks", NULL); - - // This counter displays the depth of the stack during that last runtime Code Access Security check.Runtime Code Access Security check is performed by crawling the stack. This counter is not an average; it just displays the last observed value. - PhAddListViewItem(Context->CountersLv, MAXINT, L"Stack Walk Depth", NULL); - - // % Time Sig.Authenticating - // Reserved for future use. - } - break; - } -} - -VOID AddProcessAppDomains( - _In_ HWND hwndDlg, - _In_ PPERFPAGE_CONTEXT Context - ) -{ - SendMessage(Context->AppDomainsLv, WM_SETREDRAW, FALSE, 0); - ListView_DeleteAllItems(Context->AppDomainsLv); - - if (Context->ClrV4) - { - PPH_LIST processAppDomains = QueryDotNetAppDomainsForPid_V4( - Context->IsWow64, - Context->ProcessHandle, - Context->ProcessItem->ProcessId - ); - - if (processAppDomains) - { - for (ULONG i = 0; i < processAppDomains->Count; i++) - { - PhAddListViewItem(Context->AppDomainsLv, MAXINT, processAppDomains->Items[i], NULL); - PhFree(processAppDomains->Items[i]); - } - - PhDereferenceObject(processAppDomains); - } - } - else - { - PPH_LIST processAppDomains = QueryDotNetAppDomainsForPid_V2( - Context->IsWow64, - Context->ProcessHandle, - Context->ProcessItem->ProcessId - ); - - if (processAppDomains) - { - for (ULONG i = 0; i < processAppDomains->Count; i++) - { - PhAddListViewItem(Context->AppDomainsLv, MAXINT, processAppDomains->Items[i], NULL); - PhFree(processAppDomains->Items[i]); - } - - PhDereferenceObject(processAppDomains); - } - } - - SendMessage(Context->AppDomainsLv, WM_SETREDRAW, TRUE, 0); -} - -VOID UpdateCounterData( - _In_ HWND hwndDlg, - _In_ PPERFPAGE_CONTEXT Context - ) -{ - PVOID perfStatBlock = NULL; - Perf_GC dotNetPerfGC; - Perf_Contexts dotNetPerfContext; - Perf_Interop dotNetPerfInterop; - Perf_Loading dotNetPerfLoading; - Perf_Excep dotNetPerfExcep; - Perf_LocksAndThreads dotNetPerfLocksAndThreads; - Perf_Jit dotNetPerfJit; - Perf_Security dotNetPerfSecurity; - - if (Context->ClrV4) - { - perfStatBlock = GetPerfIpcBlock_V4( - Context->IsWow64, - Context->BlockTableAddress - ); - } - else - { - perfStatBlock = GetPerfIpcBlock_V2( - Context->IsWow64, - Context->BlockTableAddress - ); - } - - if (!perfStatBlock) - return; - - if (Context->IsWow64) - { - PerfCounterIPCControlBlock_Wow64* perfBlock = perfStatBlock; - Perf_GC_Wow64 dotNetPerfGC_Wow64 = perfBlock->GC; - Perf_Loading_Wow64 dotNetPerfLoading_Wow64 = perfBlock->Loading; - Perf_Security_Wow64 dotNetPerfSecurity_Wow64 = perfBlock->Security; - - // Thunk the Wow64 structures into their 64bit versions (or 32bit version on x86). - - dotNetPerfGC.cGenCollections[0] = dotNetPerfGC_Wow64.cGenCollections[0]; - dotNetPerfGC.cGenCollections[1] = dotNetPerfGC_Wow64.cGenCollections[1]; - dotNetPerfGC.cGenCollections[2] = dotNetPerfGC_Wow64.cGenCollections[2]; - dotNetPerfGC.cbPromotedMem[0] = dotNetPerfGC_Wow64.cbPromotedMem[0]; - dotNetPerfGC.cbPromotedMem[1] = dotNetPerfGC_Wow64.cbPromotedMem[1]; - dotNetPerfGC.cbPromotedFinalizationMem = dotNetPerfGC_Wow64.cbPromotedFinalizationMem; - dotNetPerfGC.cProcessID = dotNetPerfGC_Wow64.cProcessID; - dotNetPerfGC.cGenHeapSize[0] = dotNetPerfGC_Wow64.cGenHeapSize[0]; - dotNetPerfGC.cGenHeapSize[1] = dotNetPerfGC_Wow64.cGenHeapSize[1]; - dotNetPerfGC.cGenHeapSize[2] = dotNetPerfGC_Wow64.cGenHeapSize[2]; - dotNetPerfGC.cTotalCommittedBytes = dotNetPerfGC_Wow64.cTotalCommittedBytes; - dotNetPerfGC.cTotalReservedBytes = dotNetPerfGC_Wow64.cTotalReservedBytes; - dotNetPerfGC.cLrgObjSize = dotNetPerfGC_Wow64.cLrgObjSize; - dotNetPerfGC.cSurviveFinalize = dotNetPerfGC_Wow64.cSurviveFinalize; - dotNetPerfGC.cHandles = dotNetPerfGC_Wow64.cHandles; - dotNetPerfGC.cbAlloc = dotNetPerfGC_Wow64.cbAlloc; - dotNetPerfGC.cbLargeAlloc = dotNetPerfGC_Wow64.cbLargeAlloc; - dotNetPerfGC.cInducedGCs = dotNetPerfGC_Wow64.cInducedGCs; - dotNetPerfGC.timeInGC = dotNetPerfGC_Wow64.timeInGC; - dotNetPerfGC.timeInGCBase = dotNetPerfGC_Wow64.timeInGCBase; - dotNetPerfGC.cPinnedObj = dotNetPerfGC_Wow64.cPinnedObj; - dotNetPerfGC.cSinkBlocks = dotNetPerfGC_Wow64.cSinkBlocks; - - dotNetPerfContext = perfBlock->Context; - dotNetPerfInterop = perfBlock->Interop; - - dotNetPerfLoading.cClassesLoaded.Current = dotNetPerfLoading_Wow64.cClassesLoaded.Current; - dotNetPerfLoading.cClassesLoaded.Total = dotNetPerfLoading_Wow64.cClassesLoaded.Total; - dotNetPerfLoading.cAppDomains.Current = dotNetPerfLoading_Wow64.cAppDomains.Current; - dotNetPerfLoading.cAppDomains.Total = dotNetPerfLoading_Wow64.cAppDomains.Total; - dotNetPerfLoading.cAssemblies.Current = dotNetPerfLoading_Wow64.cAssemblies.Current; - dotNetPerfLoading.cAssemblies.Total = dotNetPerfLoading_Wow64.cAssemblies.Total; - dotNetPerfLoading.timeLoading = dotNetPerfLoading_Wow64.timeLoading; - dotNetPerfLoading.cAsmSearchLen = dotNetPerfLoading_Wow64.cAsmSearchLen; - dotNetPerfLoading.cLoadFailures.Total = dotNetPerfLoading_Wow64.cLoadFailures.Total; - dotNetPerfLoading.cbLoaderHeapSize = dotNetPerfLoading_Wow64.cbLoaderHeapSize; - dotNetPerfLoading.cAppDomainsUnloaded = dotNetPerfLoading_Wow64.cAppDomainsUnloaded; - - dotNetPerfExcep = perfBlock->Excep; - dotNetPerfLocksAndThreads = perfBlock->LocksAndThreads; - dotNetPerfJit = perfBlock->Jit; - - dotNetPerfSecurity.cTotalRTChecks = dotNetPerfSecurity_Wow64.cTotalRTChecks; - dotNetPerfSecurity.timeAuthorize = dotNetPerfSecurity_Wow64.timeAuthorize; - dotNetPerfSecurity.cLinkChecks = dotNetPerfSecurity_Wow64.cLinkChecks; - dotNetPerfSecurity.timeRTchecks = dotNetPerfSecurity_Wow64.timeRTchecks; - dotNetPerfSecurity.timeRTchecksBase = dotNetPerfSecurity_Wow64.timeRTchecksBase; - dotNetPerfSecurity.stackWalkDepth = dotNetPerfSecurity_Wow64.stackWalkDepth; - } - else - { - PerfCounterIPCControlBlock* perfBlock = perfStatBlock; - - dotNetPerfGC = perfBlock->GC; - dotNetPerfContext = perfBlock->Context; - dotNetPerfInterop = perfBlock->Interop; - dotNetPerfLoading = perfBlock->Loading; - dotNetPerfExcep = perfBlock->Excep; - dotNetPerfLocksAndThreads = perfBlock->LocksAndThreads; - dotNetPerfJit = perfBlock->Jit; - dotNetPerfSecurity = perfBlock->Security; - } - - switch (Context->CategoryIndex) - { - case DOTNET_CATEGORY_EXCEPTIONS: - { - PhSetListViewSubItem(Context->CountersLv, 0, 1, PhaFormatUInt64(dotNetPerfExcep.cThrown.Total, TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, 1, 1, PhaFormatUInt64(dotNetPerfExcep.cFiltersExecuted, TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, 2, 1, PhaFormatUInt64(dotNetPerfExcep.cFinallysExecuted, TRUE)->Buffer); - //PhSetListViewSubItem(Context->CountersLv, 3, 1, PhaFormatUInt64(dotNetPerfExcep.cThrowToCatchStackDepth, TRUE)->Buffer); - } - break; - case DOTNET_CATEGORY_INTEROP: - { - PhSetListViewSubItem(Context->CountersLv, 0, 1, PhaFormatUInt64(dotNetPerfInterop.cCCW, TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, 1, 1, PhaFormatUInt64(dotNetPerfInterop.cStubs, TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, 2, 1, PhaFormatUInt64(dotNetPerfInterop.cMarshalling, TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, 3, 1, PhaFormatUInt64(dotNetPerfInterop.cTLBImports, TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, 4, 1, PhaFormatUInt64(dotNetPerfInterop.cTLBExports, TRUE)->Buffer); - } - break; - case DOTNET_CATEGORY_JIT: - { - PhSetListViewSubItem(Context->CountersLv, 0, 1, PhaFormatUInt64(dotNetPerfJit.cMethodsJitted, TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, 1, 1, FormatByteValue(Context, dotNetPerfJit.cbILJitted.Current)->Buffer); - PhSetListViewSubItem(Context->CountersLv, 2, 1, FormatByteValue(Context, dotNetPerfJit.cbILJitted.Total)->Buffer); - PhSetListViewSubItem(Context->CountersLv, 3, 1, PhaFormatUInt64(dotNetPerfJit.cJitFailures, TRUE)->Buffer); - - if (dotNetPerfJit.timeInJitBase != 0) - { - PH_FORMAT format; - WCHAR formatBuffer[10]; - - // TODO: TimeInJit is always above 100% for some processes ?? - // SeeAlso: https://github.com/dotnet/coreclr/blob/master/src/gc/gcee.cpp#L324 - PhInitFormatF(&format, (dotNetPerfJit.timeInJit << 8) * 100 / (FLOAT)(dotNetPerfJit.timeInJitBase << 8), 2); - - if (PhFormatToBuffer(&format, 1, formatBuffer, sizeof(formatBuffer), NULL)) - PhSetListViewSubItem(Context->CountersLv, 4, 1, formatBuffer); - } - else - { - PhSetListViewSubItem(Context->CountersLv, 4, 1, L"0.00"); - } - } - break; - case DOTNET_CATEGORY_LOADING: - { - PhSetListViewSubItem(Context->CountersLv, 0, 1, PhaFormatUInt64(dotNetPerfLoading.cClassesLoaded.Current, TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, 1, 1, PhaFormatUInt64(dotNetPerfLoading.cClassesLoaded.Total, TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, 2, 1, PhaFormatUInt64(dotNetPerfLoading.cAppDomains.Current, TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, 3, 1, PhaFormatUInt64(dotNetPerfLoading.cAppDomains.Total, TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, 4, 1, PhaFormatUInt64(dotNetPerfLoading.cAssemblies.Current, TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, 5, 1, PhaFormatUInt64(dotNetPerfLoading.cAssemblies.Total, TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, 6, 1, PhaFormatUInt64(dotNetPerfLoading.cAsmSearchLen, TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, 7, 1, PhaFormatUInt64(dotNetPerfLoading.cLoadFailures.Total, TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, 8, 1, FormatByteValue(Context, dotNetPerfLoading.cbLoaderHeapSize)->Buffer); - PhSetListViewSubItem(Context->CountersLv, 9, 1, PhaFormatUInt64(dotNetPerfLoading.cAppDomainsUnloaded.Total, TRUE)->Buffer); - //PhSetListViewSubItem(Context->CountersLv, 10, 1, PhaFormatUInt64(dotNetPerfLoading.timeLoading, TRUE)->Buffer); - } - break; - case DOTNET_CATEGORY_LOCKSANDTHREADS: - { - PhSetListViewSubItem(Context->CountersLv, 0, 1, PhaFormatUInt64(dotNetPerfLocksAndThreads.cContention.Total, TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, 1, 1, PhaFormatUInt64(dotNetPerfLocksAndThreads.cQueueLength.Current, TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, 2, 1, PhaFormatUInt64(dotNetPerfLocksAndThreads.cQueueLength.Total, TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, 3, 1, PhaFormatUInt64(dotNetPerfLocksAndThreads.cCurrentThreadsLogical, TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, 4, 1, PhaFormatUInt64(dotNetPerfLocksAndThreads.cCurrentThreadsPhysical, TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, 5, 1, PhaFormatUInt64(dotNetPerfLocksAndThreads.cRecognizedThreads.Current, TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, 6, 1, PhaFormatUInt64(dotNetPerfLocksAndThreads.cRecognizedThreads.Total, TRUE)->Buffer); - } - break; - case DOTNET_CATEGORY_MEMORY: - { - PhSetListViewSubItem(Context->CountersLv, 0, 1, PhaFormatUInt64(dotNetPerfGC.cGenCollections[0], TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, 1, 1, PhaFormatUInt64(dotNetPerfGC.cGenCollections[1], TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, 2, 1, PhaFormatUInt64(dotNetPerfGC.cGenCollections[2], TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, 3, 1, FormatByteValue(Context, dotNetPerfGC.cbPromotedMem[0])->Buffer); - PhSetListViewSubItem(Context->CountersLv, 4, 1, FormatByteValue(Context, dotNetPerfGC.cbPromotedMem[1])->Buffer); - PhSetListViewSubItem(Context->CountersLv, 5, 1, FormatByteValue(Context, dotNetPerfGC.cbPromotedFinalizationMem)->Buffer); - PhSetListViewSubItem(Context->CountersLv, 6, 1, PhaFormatUInt64(dotNetPerfGC.cProcessID, FALSE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, 7, 1, FormatByteValue(Context, dotNetPerfGC.cGenHeapSize[0])->Buffer); - PhSetListViewSubItem(Context->CountersLv, 8, 1, FormatByteValue(Context, dotNetPerfGC.cGenHeapSize[1])->Buffer); - PhSetListViewSubItem(Context->CountersLv, 9, 1, FormatByteValue(Context, dotNetPerfGC.cGenHeapSize[2])->Buffer); - PhSetListViewSubItem(Context->CountersLv, 10, 1, FormatByteValue(Context, dotNetPerfGC.cLrgObjSize)->Buffer); - PhSetListViewSubItem(Context->CountersLv, 11, 1, PhaFormatUInt64(dotNetPerfGC.cSurviveFinalize, TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, 12, 1, PhaFormatUInt64(dotNetPerfGC.cHandles, TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, 13, 1, PhaFormatUInt64(dotNetPerfGC.cInducedGCs, TRUE)->Buffer); - - if (dotNetPerfGC.timeInGCBase != 0) - { - PH_FORMAT format; - WCHAR formatBuffer[10]; - - PhInitFormatF(&format, (FLOAT)dotNetPerfGC.timeInGC * 100 / (FLOAT)dotNetPerfGC.timeInGCBase, 2); - - if (PhFormatToBuffer(&format, 1, formatBuffer, sizeof(formatBuffer), NULL)) - PhSetListViewSubItem(Context->CountersLv, 14, 1, formatBuffer); - } - else - { - PhSetListViewSubItem(Context->CountersLv, 14, 1, L"0.00"); - } - - // The CLR source says this value should be "Gen 0 Heap Size; Gen 1 Heap Size; Gen 2 Heap Size and the Large Object Heap Size", - // but Perflib only counts Gen 1, Gen 2 and cLrgObjSize... For now, just do what perflib does. - PhSetListViewSubItem(Context->CountersLv, 15, 1, FormatByteValue(Context, dotNetPerfGC.cGenHeapSize[1] + dotNetPerfGC.cGenHeapSize[2] + dotNetPerfGC.cLrgObjSize)->Buffer); - PhSetListViewSubItem(Context->CountersLv, 16, 1, FormatByteValue(Context, dotNetPerfGC.cTotalCommittedBytes)->Buffer); - PhSetListViewSubItem(Context->CountersLv, 17, 1, FormatByteValue(Context, dotNetPerfGC.cTotalReservedBytes)->Buffer); - PhSetListViewSubItem(Context->CountersLv, 18, 1, PhaFormatUInt64(dotNetPerfGC.cPinnedObj, TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, 19, 1, PhaFormatUInt64(dotNetPerfGC.cSinkBlocks, TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, 20, 1, FormatByteValue(Context, dotNetPerfGC.cbAlloc)->Buffer); - PhSetListViewSubItem(Context->CountersLv, 21, 1, FormatByteValue(Context, dotNetPerfGC.cbLargeAlloc)->Buffer); - } - break; - case DOTNET_CATEGORY_REMOTING: - { - PhSetListViewSubItem(Context->CountersLv, 0, 1, PhaFormatUInt64(dotNetPerfContext.cRemoteCalls.Total, TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, 1, 1, PhaFormatUInt64(dotNetPerfContext.cChannels, TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, 2, 1, PhaFormatUInt64(dotNetPerfContext.cProxies, TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, 3, 1, PhaFormatUInt64(dotNetPerfContext.cClasses, TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, 4, 1, PhaFormatUInt64(dotNetPerfContext.cContexts, TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, 5, 1, PhaFormatUInt64(dotNetPerfContext.cObjAlloc, TRUE)->Buffer); - } - break; - case DOTNET_CATEGORY_SECURITY: - { - PhSetListViewSubItem(Context->CountersLv, 0, 1, PhaFormatUInt64(dotNetPerfSecurity.cTotalRTChecks, TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, 1, 1, PhaFormatUInt64(dotNetPerfSecurity.cLinkChecks, TRUE)->Buffer); - - if (dotNetPerfSecurity.timeRTchecksBase != 0) - { - PH_FORMAT format; - WCHAR formatBuffer[10]; - - PhInitFormatF(&format, (FLOAT)dotNetPerfSecurity.timeRTchecks * 100 / (FLOAT)dotNetPerfSecurity.timeRTchecksBase, 2); - - if (PhFormatToBuffer(&format, 1, formatBuffer, sizeof(formatBuffer), NULL)) - PhSetListViewSubItem(Context->CountersLv, 2, 1, formatBuffer); - } - else - { - PhSetListViewSubItem(Context->CountersLv, 2, 1, L"0.00"); - } - - PhSetListViewSubItem(Context->CountersLv, 3, 1, PhaFormatUInt64(dotNetPerfSecurity.stackWalkDepth, TRUE)->Buffer); - } - break; - } -} - -INT_PTR CALLBACK DotNetPerfPageDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - LPPROPSHEETPAGE propSheetPage; - PPH_PROCESS_PROPPAGECONTEXT propPageContext; - PPH_PROCESS_ITEM processItem; - PPERFPAGE_CONTEXT context; - - if (PhPropPageDlgProcHeader(hwndDlg, uMsg, lParam, &propSheetPage, &propPageContext, &processItem)) - { - context = propPageContext->Context; - } - else - { - return FALSE; - } - - switch (uMsg) - { - case WM_INITDIALOG: - { - context = PhAllocate(sizeof(PERFPAGE_CONTEXT)); - memset(context, 0, sizeof(PERFPAGE_CONTEXT)); - - propPageContext->Context = context; - context->WindowHandle = hwndDlg; - context->ProcessItem = processItem; - context->Enabled = TRUE; - - context->AppDomainsLv = GetDlgItem(hwndDlg, IDC_APPDOMAINS); - context->CountersLv = GetDlgItem(hwndDlg, IDC_COUNTERS); - context->CategoriesCb = GetDlgItem(hwndDlg, IDC_CATEGORIES); - - PhSetListViewStyle(context->AppDomainsLv, FALSE, TRUE); - PhSetControlTheme(context->AppDomainsLv, L"explorer"); - PhAddListViewColumn(context->AppDomainsLv, 0, 0, 0, LVCFMT_LEFT, 300, L"Application domain"); - - PhSetListViewStyle(context->CountersLv, FALSE, TRUE); - PhSetControlTheme(context->CountersLv, L"explorer"); - PhAddListViewColumn(context->CountersLv, 0, 0, 0, LVCFMT_LEFT, 250, L"Counter"); - PhAddListViewColumn(context->CountersLv, 1, 1, 1, LVCFMT_RIGHT, 140, L"Value"); - PhLoadListViewColumnsFromSetting(SETTING_NAME_DOT_NET_COUNTERS_COLUMNS, context->CountersLv); - - if (PhGetIntegerSetting(SETTING_NAME_DOT_NET_SHOW_BYTE_SIZE)) - { - context->ShowByteSize = TRUE; - Button_SetCheck(GetDlgItem(hwndDlg, IDC_DOTNET_PERF_SHOWBYTES), TRUE); - } - - PhAddComboBoxStrings(context->CategoriesCb, DotNetCategoryStrings, ARRAYSIZE(DotNetCategoryStrings)); - context->CategoryIndex = PhGetIntegerSetting(SETTING_NAME_DOT_NET_CATEGORY_INDEX); - ComboBox_SetCurSel(context->CategoriesCb, context->CategoryIndex); - -#ifdef _WIN64 - context->IsWow64 = !!context->ProcessItem->IsWow64; -#else - // HACK: Work-around for Appdomain enumeration on 32bit. - context->IsWow64 = TRUE; -#endif - - if (NT_SUCCESS(PhOpenProcess( - &context->ProcessHandle, - PROCESS_VM_READ | ProcessQueryAccess | PROCESS_DUP_HANDLE | SYNCHRONIZE, - context->ProcessItem->ProcessId - ))) - { - ULONG flags = 0; - - if (NT_SUCCESS(PhGetProcessIsDotNetEx( - context->ProcessItem->ProcessId, - context->ProcessHandle, - context->ProcessItem->IsImmersive == 1 ? 0 : PH_CLR_USE_SECTION_CHECK, - NULL, - &flags - ))) - { - if (flags & PH_CLR_VERSION_4_ABOVE) - { - context->ClrV4 = TRUE; - } - } - - // Skip AppDomain enumeration of 'Modern' .NET applications as they don't expose the CLR 'Private IPC' block. - if (!context->ProcessItem->IsImmersive) - { - AddProcessAppDomains(hwndDlg, context); - } - } - - if (context->ClrV4) - { - if (OpenDotNetPublicControlBlock_V4( - !!context->ProcessItem->IsImmersive, - context->ProcessHandle, - context->ProcessItem->ProcessId, - &context->BlockTableHandle, - &context->BlockTableAddress - )) - { - context->ControlBlockValid = TRUE; - } - } - else - { - if (OpenDotNetPublicControlBlock_V2( - context->ProcessItem->ProcessId, - &context->BlockTableHandle, - &context->BlockTableAddress - )) - { - context->ControlBlockValid = TRUE; - } - } - - if (context->ControlBlockValid) - { - UpdateCategoryValues(hwndDlg, context); - UpdateCounterData(hwndDlg, context); - } - - PhRegisterCallback( - PhGetGeneralCallback(GeneralCallbackProcessesUpdated), - ProcessesUpdatedCallback, - context, - &context->ProcessesUpdatedCallbackRegistration - ); - } - break; - case WM_DESTROY: - { - PhUnregisterCallback( - PhGetGeneralCallback(GeneralCallbackProcessesUpdated), - &context->ProcessesUpdatedCallbackRegistration - ); - - if (context->BlockTableAddress) - { - NtUnmapViewOfSection(NtCurrentProcess(), context->BlockTableAddress); - } - - if (context->BlockTableHandle) - { - NtClose(context->BlockTableHandle); - } - - if (context->ProcessHandle) - { - NtClose(context->ProcessHandle); - } - - PhSaveListViewColumnsToSetting(SETTING_NAME_DOT_NET_COUNTERS_COLUMNS, context->CountersLv); - - PhFree(context); - PhPropPageDlgProcDestroy(hwndDlg); - } - break; - case WM_SHOWWINDOW: - { - PPH_LAYOUT_ITEM dialogItem; - - if (dialogItem = PhBeginPropPageLayout(hwndDlg, propPageContext)) - { - PhAddPropPageLayoutItem(hwndDlg, context->AppDomainsLv, dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); - PhAddPropPageLayoutItem(hwndDlg, context->CategoriesCb, dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); - PhAddPropPageLayoutItem(hwndDlg, context->CountersLv, dialogItem, PH_ANCHOR_ALL); - PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_DOTNET_PERF_SHOWBYTES), dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_BOTTOM); - PhEndPropPageLayout(hwndDlg, propPageContext); - } - } - break; - case WM_COMMAND: - { - switch (GET_WM_COMMAND_ID(wParam, lParam)) - { - case IDC_CATEGORIES: - { - if (GET_WM_COMMAND_CMD(wParam, lParam) == CBN_SELCHANGE) - { - context->CategoryIndex = ComboBox_GetCurSel(context->CategoriesCb); - PhSetIntegerSetting(SETTING_NAME_DOT_NET_CATEGORY_INDEX, context->CategoryIndex); - - if (context->ControlBlockValid) - { - UpdateCategoryValues(hwndDlg, context); - UpdateCounterData(hwndDlg, context); - } - } - } - break; - case IDC_DOTNET_PERF_SHOWBYTES: - { - if (GET_WM_COMMAND_CMD(wParam, lParam) == BN_CLICKED) - { - context->ShowByteSize = !context->ShowByteSize; - PhSetIntegerSetting(SETTING_NAME_DOT_NET_SHOW_BYTE_SIZE, context->ShowByteSize); - - if (context->ControlBlockValid) - { - UpdateCategoryValues(hwndDlg, context); - UpdateCounterData(hwndDlg, context); - } - } - } - break; - } - } - break; - case WM_NOTIFY: - { - LPNMHDR header = (LPNMHDR)lParam; - - switch (header->code) - { - case PSN_SETACTIVE: - context->Enabled = TRUE; - break; - case PSN_KILLACTIVE: - context->Enabled = FALSE; - break; - } - - PhHandleListViewNotifyForCopy(lParam, context->AppDomainsLv); - PhHandleListViewNotifyForCopy(lParam, context->CountersLv); - } - break; - case MSG_UPDATE: - { - if (context->Enabled && context->ControlBlockValid) - { - UpdateCounterData(hwndDlg, context); - } - } - break; - } - - return FALSE; -} - -VOID AddPerfPageToPropContext( - _In_ PPH_PLUGIN_PROCESS_PROPCONTEXT PropContext - ) -{ - PhAddProcessPropPage( - PropContext->PropContext, - PhCreateProcessPropPageContextEx(PluginInstance->DllBase, MAKEINTRESOURCE(IDD_PROCDOTNETPERF), DotNetPerfPageDlgProc, NULL) - ); +/* + * Process Hacker .NET Tools - + * .NET Performance property page + * + * Copyright (C) 2011-2015 wj32 + * Copyright (C) 2015 dmex + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + + +#include "dn.h" +#include "clr\perfcounterdefs.h" + +typedef enum _DOTNET_CATEGORY +{ + // .NET CLR Exceptions (Runtime statistics on CLR exception handling) + DOTNET_CATEGORY_EXCEPTIONS, + + // .NET CLR Interop (Stats for CLR interop) + DOTNET_CATEGORY_INTEROP, + + // .NET CLR Jit (Stats for CLR Jit) + DOTNET_CATEGORY_JIT, + + // .NET CLR Loading (Statistics for CLR Class Loader) + DOTNET_CATEGORY_LOADING, + + // .NET CLR LocksAndThreads (Stats for CLR Locks and Threads) + DOTNET_CATEGORY_LOCKSANDTHREADS, + + // .NET CLR Memory (Counters for CLR Garbage Collected heap) + DOTNET_CATEGORY_MEMORY, + + // .NET CLR Remoting (Stats for CLR Remoting) + DOTNET_CATEGORY_REMOTING, + + // .NET CLR Security (Stats for CLR Security) + DOTNET_CATEGORY_SECURITY +} DOTNET_CATEGORY; + +typedef struct _PERFPAGE_CONTEXT +{ + HWND WindowHandle; + PPH_PROCESS_ITEM ProcessItem; + BOOLEAN Enabled; + + HWND AppDomainsLv; + HWND CountersLv; + HWND CategoriesCb; + + BOOLEAN ControlBlockValid; + BOOLEAN ClrV4; + BOOLEAN IsWow64; + BOOLEAN ShowByteSize; + DOTNET_CATEGORY CategoryIndex; + HANDLE ProcessHandle; + HANDLE BlockTableHandle; + PVOID BlockTableAddress; + + PH_CALLBACK_REGISTRATION ProcessesUpdatedCallbackRegistration; +} PERFPAGE_CONTEXT, *PPERFPAGE_CONTEXT; + +static PWSTR DotNetCategoryStrings[] = +{ + L".NET CLR Exceptions", + L".NET CLR Interop", + L".NET CLR Jit", + L".NET CLR Loading", + L".NET CLR LocksAndThreads", + L".NET CLR Memory", + L".NET CLR Remoting", + L".NET CLR Security" +}; + +PPH_STRING FormatByteValue( + _In_ PPERFPAGE_CONTEXT Context, + _In_ ULONG64 Value + ) +{ + if (Context->ShowByteSize) + return PhaFormatUInt64(Value, TRUE); + + return PhaFormatSize(Value, -1); +} + +VOID NTAPI ProcessesUpdatedCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + PPERFPAGE_CONTEXT context = Context; + + if (context->WindowHandle) + { + PostMessage(context->WindowHandle, MSG_UPDATE, 0, 0); + } +} + +VOID UpdateCategoryValues( + _In_ HWND hwndDlg, + _In_ PPERFPAGE_CONTEXT Context + ) +{ + ListView_DeleteAllItems(Context->CountersLv); + + switch (Context->CategoryIndex) + { + case DOTNET_CATEGORY_EXCEPTIONS: + { + // This counter displays the total number of exceptions thrown since the start of the application. These include both .NET exceptions and unmanaged exceptions that get converted into .NET exceptions e.g. null pointer reference exception in unmanaged code would get re-thrown in managed code as a .NET System.NullReferenceException; this counter includes both handled and unhandled exceptions.Exceptions that are re-thrown would get counted again. Exceptions should only occur in rare situations and not in the normal control flow of the program. + PhAddListViewItem(Context->CountersLv, MAXINT, L"# of Exceps Thrown", NULL); + PhAddListViewItem(Context->CountersLv, MAXINT, L"# of Filters Executed", NULL); + PhAddListViewItem(Context->CountersLv, MAXINT, L"# of Finallys Executed", NULL); + + // Reserved for future use. + //PhAddListViewItem(Context->CountersLv, MAXINT, L" Delta from throw to catch site on stack", NULL); + + // # of Exceps Thrown / sec + // This counter displays the number of exceptions thrown per second.These include both.NET exceptions and unmanaged exceptions that get converted into.NET exceptions e.g.null pointer reference exception in unmanaged code would get re - thrown in managed code as a.NET System.NullReferenceException; this counter includes both handled and unhandled exceptions.Exceptions should only occur in rare situations and not in the normal control flow of the program; this counter was designed as an indicator of potential performance problems due to large(> 100s) rate of exceptions thrown.This counter is not an average over time; it displays the difference between the values observed in the last two samples divided by the duration of the sample interval. + + // # of Filters / sec + // This counter displays the number of.NET exception filters executed per second.An exception filter evaluates whether an exception should be handled or not.This counter tracks the rate of exception filters evaluated; irrespective of whether the exception was handled or not.This counter is not an average over time; it displays the difference between the values observed in the last two samples divided by the duration of the sample interval. + + // # of Finallys / sec + // This counter displays the number of finally blocks executed per second.A finally block is guaranteed to be executed regardless of how the try block was exited.Only the finally blocks that are executed for an exception are counted; finally blocks on normal code paths are not counted by this counter.This counter is not an average over time; it displays the difference between the values observed in the last two samples divided by the duration of the sample interval. + + // Throw To Catch Depth / sec + // This counter displays the number of stack frames traversed from the frame that threw the.NET exception to the frame that handled the exception per second.This counter resets to 0 when an exception handler is entered; so nested exceptions would show the handler to handler stack depth.This counter is not an average over time; it displays the difference between the values observed in the last two samples divided by the duration of the sample interval.* / + } + break; + case DOTNET_CATEGORY_INTEROP: + { + // This counter displays the current number of Com-Callable-Wrappers (CCWs). A CCW is a proxy for the .NET managed object being referenced from unmanaged COM client(s). This counter was designed to indicate the number of managed objects being referenced by unmanaged COM code. + PhAddListViewItem(Context->CountersLv, MAXINT, L"# of CCWs", NULL); + + // This counter displays the current number of stubs created by the CLR. Stubs are responsible for marshalling arguments and return values from managed to unmanaged code and vice versa; during a COM Interop call or PInvoke call. + PhAddListViewItem(Context->CountersLv, MAXINT, L"# of Stubs", NULL); + + // This counter displays the total number of times arguments and return values have been marshaled from managed to unmanaged code and vice versa since the start of the application. This counter is not incremented if the stubs are inlined. (Stubs are responsible for marshalling arguments and return values). Stubs usually get inlined if the marshalling overhead is small. + PhAddListViewItem(Context->CountersLv, MAXINT, L"# of Marshalling", NULL); + + // Reserved for future use. + PhAddListViewItem(Context->CountersLv, MAXINT, L"# of TLB imports / sec", NULL); + + // Reserved for future use. + PhAddListViewItem(Context->CountersLv, MAXINT, L"# of TLB exports / sec", NULL); + } + break; + case DOTNET_CATEGORY_JIT: + { + // This counter displays the total number of methods compiled Just-In-Time (JIT) by the CLR JIT compiler since the start of the application. This counter does not include the pre-jitted methods. + PhAddListViewItem(Context->CountersLv, MAXINT, L"# of Methods Jitted", NULL); + + // This counter displays the total IL bytes jitted since the start of the application. This counter is exactly equivalent to the "Total # of IL Bytes Jitted" counter. + PhAddListViewItem(Context->CountersLv, MAXINT, L"# of IL Bytes Jitted", NULL); + + // This counter displays the total IL bytes jitted since the start of the application. This counter is exactly equivalent to the "# of IL Bytes Jitted" counter. + PhAddListViewItem(Context->CountersLv, MAXINT, L"Total # of IL Bytes Jitted", NULL); + + // This counter displays the peak number of methods the JIT compiler has failed to JIT since the start of the application. This failure can occur if the IL cannot be verified or if there was an internal error in the JIT compiler. + PhAddListViewItem(Context->CountersLv, MAXINT, L"Jit Failures", NULL); + + // This counter displays the percentage of elapsed time spent in JIT compilation since the last JIT compilation phase. This counter is updated at the end of every JIT compilation phase. A JIT compilation phase is the phase when a method and its dependencies are being compiled. + PhAddListViewItem(Context->CountersLv, MAXINT, L"% Time in Jit", NULL); + + // IL Bytes Jitted / sec + // This counter displays the rate at which IL bytes are jitted per second. This counter is not an average over time; it displays the difference between the values observed in the last two samples divided by the duration of the sample interval. + } + break; + case DOTNET_CATEGORY_LOADING: + { + // This counter displays the current number of classes loaded in all Assemblies. + PhAddListViewItem(Context->CountersLv, MAXINT, L"Current Classes Loaded", NULL); + + // This counter displays the cumulative number of classes loaded in all Assemblies since the start of this application. + PhAddListViewItem(Context->CountersLv, MAXINT, L"Total Classes Loaded", NULL); + + // This counter displays the current number of AppDomains loaded in this application. AppDomains (application domains) provide a secure and versatile unit of processing that the CLR can use to provide isolation between applications running in the same process. + PhAddListViewItem(Context->CountersLv, MAXINT, L"Current Appdomains", NULL); + + // This counter displays the peak number of AppDomains loaded since the start of this application. AppDomains (application domains) provide a secure and versatile unit of processing that the CLR can use to provide isolation between applications running in the same process. + PhAddListViewItem(Context->CountersLv, MAXINT, L"Total Appdomains", NULL); + + // This counter displays the current number of Assemblies loaded across all AppDomains in this application. If the Assembly is loaded as domain - neutral from multiple AppDomains then this counter is incremented once only. Assemblies can be loaded as domain - neutral when their code can be shared by all AppDomains or they can be loaded as domain - specific when their code is private to the AppDomain. + PhAddListViewItem(Context->CountersLv, MAXINT, L"Current Assemblies", NULL); + + // This counter displays the total number of Assemblies loaded since the start of this application. If the Assembly is loaded as domain - neutral from multiple AppDomains then this counter is incremented once only. Assemblies can be loaded as domain - neutral when their code can be shared by all AppDomains or they can be loaded as domain - specific when their code is private to the AppDomain. + PhAddListViewItem(Context->CountersLv, MAXINT, L"Total Assemblies", NULL); + + // Reserved for future use. + PhAddListViewItem(Context->CountersLv, MAXINT, L"Assembly Search Length", NULL); + + // This counter displays the peak number of classes that have failed to load since the start of the application.These load failures could be due to many reasons like inadequate security or illegal format.Full details can be found in the profiling services help. + PhAddListViewItem(Context->CountersLv, MAXINT, L"Total # of Load Failures", NULL); + + // This counter displays the current size(in bytes) of the memory committed by the class loader across all AppDomains. (Committed memory is the physical memory for which space has been reserved on the disk paging file.) + PhAddListViewItem(Context->CountersLv, MAXINT, L"Bytes in Loader Heap", NULL); + + // This counter displays the total number of AppDomains unloaded since the start of the application. If an AppDomain is loaded and unloaded multiple times this counter would count each of those unloads as separate. + PhAddListViewItem(Context->CountersLv, MAXINT, L"Total Appdomains Unloaded", NULL); + + // Reserved for future use. + //PhAddListViewItem(Context->CountersLv, MAXINT, L"% Time Loading", NULL); + + // Rate of Load Failures + // This counter displays the number of classes that failed to load per second. This counter is not an average over time; it displays the difference between the values observed in the last two samples divided by the duration of the sample interval. These load failures could be due to many reasons like inadequate security or illegal format. Full details can be found in the profiling services help. + + // Rate of appdomains unloaded + // This counter displays the number of AppDomains unloaded per second.This counter is not an average over time; it displays the difference between the values observed in the last two samples divided by the duration of the sample interval. + + // Rate of Classes Loaded + // This counter displays the number of classes loaded per second in all Assemblies.This counter is not an average over time; it displays the difference between the values observed in the last two samples divided by the duration of the sample interval. + + // Rate of appdomains + // This counter displays the number of AppDomains loaded per second.AppDomains(application domains) provide a secure and versatile unit of processing that the CLR can use to provide isolation between applications running in the same process.This counter is not an average over time; it displays the difference between the values observed in the last two samples divided by the duration of the sample interval. + + // Rate of Assemblies + // This counter displays the number of Assemblies loaded across all AppDomains per second.If the Assembly is loaded as domain - neutral from multiple AppDomains then this counter is incremented once only.Assemblies can be loaded as domain - neutral when their code can be shared by all AppDomains or they can be loaded as domain - specific when their code is private to the AppDomain.This counter is not an average over time; it displays the difference between the values observed in the last two samples divided by the duration of the sample interval. + } + break; + case DOTNET_CATEGORY_LOCKSANDTHREADS: + { + // This counter displays the total number of times threads in the CLR have attempted to acquire a managed lock unsuccessfully. Managed locks can be acquired in many ways; by the "lock" statement in C# or by calling System.Monitor.Enter or by using MethodImplOptions.Synchronized custom attribute. + PhAddListViewItem(Context->CountersLv, MAXINT, L"Total # of Contentions", NULL); + + // This counter displays the total number of threads currently waiting to acquire some managed lock in the application. This counter is not an average over time; it displays the last observed value. + PhAddListViewItem(Context->CountersLv, MAXINT, L"Current Queue Length", NULL); + + // This counter displays the total number of threads that waited to acquire some managed lock since the start of the application. + PhAddListViewItem(Context->CountersLv, MAXINT, L"Queue Length Peak", NULL); + + // This counter displays the number of current.NET thread objects in the application.A.NET thread object is created either by new System.Threading.Thread or when an unmanaged thread enters the managed environment. This counters maintains the count of both running and stopped threads. This counter is not an average over time; it just displays the last observed value. + PhAddListViewItem(Context->CountersLv, MAXINT, L"# of Current Logical Threads", NULL); + + // This counter displays the number of native OS threads created and owned by the CLR to act as underlying threads for .NET thread objects. This counters value does not include the threads used by the CLR in its internal operations; it is a subset of the threads in the OS process. + PhAddListViewItem(Context->CountersLv, MAXINT, L"# of Current Physical Threads", NULL); + + // This counter displays the number of threads that are currently recognized by the CLR; they have a corresponding .NET thread object associated with them. These threads are not created by the CLR; they are created outside the CLR but have since run inside the CLR at least once. Only unique threads are tracked; threads with same thread ID re-entering the CLR or recreated after thread exit are not counted twice. + PhAddListViewItem(Context->CountersLv, MAXINT, L"# of Current Recognized Threads", NULL); + + // This counter displays the total number of threads that have been recognized by the CLR since the start of this application; these threads have a corresponding .NET thread object associated with them. These threads are not created by the CLR; they are created outside the CLR but have since run inside the CLR at least once. Only unique threads are tracked; threads with same thread ID re-entering the CLR or recreated after thread exit are not counted twice. + PhAddListViewItem(Context->CountersLv, MAXINT, L"# of Total Recognized Threads", NULL); + + // Contention Rate / sec + // Rate at which threads in the runtime attempt to acquire a managed lock unsuccessfully.Managed locks can be acquired in many ways; by the "lock" statement in C# or by calling System.Monitor.Enter or by using MethodImplOptions.Synchronized custom attribute. + + // Queue Length / sec + // This counter displays the number of threads per second waiting to acquire some lock in the application. This counter is not an average over time; it displays the difference between the values observed in the last two samples divided by the duration of the sample interval. + + // rate of recognized threads / sec + // This counter displays the number of threads per second that have been recognized by the CLR; these threads have a corresponding .NET thread object associated with them. These threads are not created by the CLR; they are created outside the CLR but have since run inside the CLR at least once. Only unique threads are tracked; threads with same thread ID re-entering the CLR or recreated after thread exit are not counted twice. This counter is not an average over time; it displays the difference between the values observed in the last two samples divided by the duration of the sample interval. + } + break; + case DOTNET_CATEGORY_MEMORY: + { + // This counter displays the number of times the generation 0 objects (youngest; most recently allocated) are garbage collected (Gen 0 GC) since the start of the application. Gen 0 GC occurs when the available memory in generation 0 is not sufficient to satisfy an allocation request. This counter is incremented at the end of a Gen 0 GC. Higher generation GCs include all lower generation GCs.This counter is explicitly incremented when a higher generation (Gen 1 or Gen 2) GC occurs. _Global_ counter value is not accurate and should be ignored. This counter displays the last observed value. + PhAddListViewItem(Context->CountersLv, MAXINT, L"# Gen 0 Collections", NULL); + + // This counter displays the number of times the generation 1 objects are garbage collected since the start of the application. The counter is incremented at the end of a Gen 1 GC. Higher generation GCs include all lower generation GCs. This counter is explicitly incremented when a higher generation (Gen 2) GC occurs. _Global_ counter value is not accurate and should be ignored. This counter displays the last observed value. + PhAddListViewItem(Context->CountersLv, MAXINT, L"# Gen 1 Collections", NULL); + + // This counter displays the number of times the generation 2 objects(older) are garbage collected since the start of the application.The counter is incremented at the end of a Gen 2 GC(also called full GC)._Global_ counter value is not accurate and should be ignored.This counter displays the last observed value. + PhAddListViewItem(Context->CountersLv, MAXINT, L"# Gen 2 Collections", NULL); + + // This counter displays the bytes of memory that survive garbage collection(GC) and are promoted from generation 0 to generation 1; objects that are promoted just because they are waiting to be finalized are not included in this counter.This counter displays the value observed at the end of the last GC; its not a cumulative counter. + PhAddListViewItem(Context->CountersLv, MAXINT, L"Promoted Memory from Gen 0", NULL); + + // This counter displays the bytes of memory that survive garbage collection(GC) and are promoted from generation 1 to generation 2; objects that are promoted just because they are waiting to be finalized are not included in this counter.This counter displays the value observed at the end of the last GC; its not a cumulative counter.This counter is reset to 0 if the last GC was a Gen 0 GC only. + PhAddListViewItem(Context->CountersLv, MAXINT, L"Promoted Memory from Gen 1", NULL); + + // This counter displays the bytes of memory that are promoted from generation 0 to generation 1 just because they are waiting to be finalized.This counter displays the value observed at the end of the last GC; its not a cumulative counter. + PhAddListViewItem(Context->CountersLv, MAXINT, L"Promoted Finalization-Memory from Gen 0", NULL); + + // Reserved for future use. + PhAddListViewItem(Context->CountersLv, MAXINT, L"Process ID", NULL); + + // This counter displays the maximum bytes that can be allocated in generation 0 (Gen 0); its does not indicate the current number of bytes allocated in Gen 0. A Gen 0 GC is triggered when the allocations since the last GC exceed this size.The Gen 0 size is tuned by the Garbage Collector and can change during the execution of the application.At the end of a Gen 0 collection the size of the Gen 0 heap is infact 0 bytes; this counter displays the size(in bytes) of allocations that would trigger the next Gen 0 GC.This counter is updated at the end of a GC; its not updated on every allocation. + PhAddListViewItem(Context->CountersLv, MAXINT, L"Gen 0 Heap Size", NULL); + + // This counter displays the current number of bytes in generation 1 (Gen 1); this counter does not display the maximum size of Gen 1. Objects are not directly allocated in this generation; they are promoted from previous Gen 0 GCs.This counter is updated at the end of a GC; its not updated on every allocation. + PhAddListViewItem(Context->CountersLv, MAXINT, L"Gen 1 Heap Size", NULL); + + // This counter displays the current number of bytes in generation 2 (Gen 2).Objects are not directly allocated in this generation; they are promoted from Gen 1 during previous Gen 1 GCs.This counter is updated at the end of a GC; its not updated on every allocation. + PhAddListViewItem(Context->CountersLv, MAXINT, L"Gen 2 Heap Size", NULL); + + // This counter displays the current size of the Large Object Heap in bytes.Objects greater than 20 KBytes are treated as large objects by the Garbage Collector and are directly allocated in a special heap; they are not promoted through the generations.This counter is updated at the end of a GC; its not updated on every allocation. + PhAddListViewItem(Context->CountersLv, MAXINT, L"Large Object Heap Size", NULL); + + // This counter displays the number of garbage collected objects that survive a collection because they are waiting to be finalized.If these objects hold references to other objects then those objects also survive but are not counted by this counter; the "Promoted Finalization-Memory from Gen 0" and "Promoted Finalization-Memory from Gen 1" counters represent all the memory that survived due to finalization.This counter is not a cumulative counter; its updated at the end of every GC with count of the survivors during that particular GC only.This counter was designed to indicate the extra overhead that the application might incur because of finalization. + PhAddListViewItem(Context->CountersLv, MAXINT, L"Finalization Survivors", NULL); + + // This counter displays the current number of GC Handles in use.GCHandles are handles to resources external to the CLR and the managed environment.Handles occupy small amounts of memory in the GCHeap but potentially expensive unmanaged resources. + PhAddListViewItem(Context->CountersLv, MAXINT, L"# GC Handles", NULL); + + // This counter displays the peak number of times a garbage collection was performed because of an explicit call to GC.Collect. Its a good practice to let the GC tune the frequency of its collections. + PhAddListViewItem(Context->CountersLv, MAXINT, L"# Induced GC", NULL); + + // % Time in GC is the percentage of elapsed time that was spent in performing a garbage collection(GC) since the last GC cycle. This counter is usually an indicator of the work done by the Garbage Collector on behalf of the application to collect and compact memory.This counter is updated only at the end of every GC and the counter value reflects the last observed value; its not an average. + PhAddListViewItem(Context->CountersLv, MAXINT, L"% Time in GC", NULL); + + // This counter is the sum of four other counters; Gen 0 Heap Size; Gen 1 Heap Size; Gen 2 Heap Size and the Large Object Heap Size. This counter indicates the current memory allocated in bytes on the GC Heaps. + PhAddListViewItem(Context->CountersLv, MAXINT, L"# Bytes in all Heaps", NULL); + + // This counter displays the amount of virtual memory(in bytes) currently committed by the Garbage Collector. (Committed memory is the physical memory for which space has been reserved on the disk paging file). + PhAddListViewItem(Context->CountersLv, MAXINT, L"# Total Committed Bytes", NULL); + + // This counter displays the amount of virtual memory(in bytes) currently reserved by the Garbage Collector. (Reserved memory is the virtual memory space reserved for the application but no disk or main memory pages have been used.) + PhAddListViewItem(Context->CountersLv, MAXINT, L"# Total Reserved Bytes", NULL); + + // This counter displays the number of pinned objects encountered in the last GC. This counter tracks the pinned objects only in the heaps that were garbage collected e.g. A Gen 0 GC would cause enumeration of pinned objects in the generation 0 heap only. A pinned object is one that the Garbage Collector cannot move in memory. + PhAddListViewItem(Context->CountersLv, MAXINT, L"# of Pinned Objects", NULL); + + // This counter displays the current number of sync blocks in use. Sync blocks are per-object data structures allocated for storing synchronization information. Sync blocks hold weak references to managed objects and need to be scanned by the Garbage Collector. Sync blocks are not limited to storing synchronization information and can also store COM interop metadata. This counter was designed to indicate performance problems with heavy use of synchronization primitives. + PhAddListViewItem(Context->CountersLv, MAXINT, L"# of Sink Blocks in use", NULL); + + // Reserved for future use. + PhAddListViewItem(Context->CountersLv, MAXINT, L"Total Bytes Allocated (since start)", NULL); + + // Reserved for future use. + PhAddListViewItem(Context->CountersLv, MAXINT, L"Total Bytes Allocated for Large Objects (since start)", NULL); + + // Gen 0 Promoted Bytes / Sec + // This counter displays the bytes per second that are promoted from generation 0 (youngest)to generation 1; objects that are promoted just because they are waiting to be finalized are not included in this counter.Memory is promoted when it survives a garbage collection.This counter was designed as an indicator of relatively long - lived objects being created per sec.This counter displays the difference between the values observed in the last two samples divided by the duration of the sample interval. + + // Gen 1 Promoted Bytes / Sec + // This counter displays the bytes per second that are promoted from generation 1 to generation 2 (oldest); objects that are promoted just because they are waiting to be finalized are not included in this counter.Memory is promoted when it survives a garbage collection.Nothing is promoted from generation 2 since it is the oldest.This counter was designed as an indicator of very long - lived objects being created per sec.This counter displays the difference between the values observed in the last two samples divided by the duration of the sample interval. + + // Promoted Finalization - Memory from Gen 1 + // This counter displays the bytes of memory that are promoted from generation 1 to generation 2 just because they are waiting to be finalized.This counter displays the value observed at the end of the last GC; its not a cumulative counter.This counter is reset to 0 if the last GC was a Gen 0 GC only. + + // Allocated Bytes / sec + // This counter displays the rate of bytes per second allocated on the GC Heap.This counter is updated at the end of every GC; not at each allocation.This counter is not an average over time; it displays the difference between the values observed in the last two samples divided by the duration of the sample interval. + } + break; + case DOTNET_CATEGORY_REMOTING: + { + // This counter displays the total number of remote procedure calls invoked since the start of this application. A remote procedure call is a call on any object outside the callers AppDomain. + PhAddListViewItem(Context->CountersLv, MAXINT, L"Total Remote Calls", NULL); + + // This counter displays the total number of remoting channels registered across all AppDomains since the start of the application. Channels are used to transport messages to and from remote objects. + PhAddListViewItem(Context->CountersLv, MAXINT, L"Channels", NULL); + + // This counter displays the total number of remoting proxy objects created in this process since the start of the process. Proxy object acts as a representative of the remote objects and ensures that all calls made on the proxy are forwarded to the correct remote object instance. + PhAddListViewItem(Context->CountersLv, MAXINT, L"Context Proxies", NULL); + + // This counter displays the current number of context-bound classes loaded. Classes that can be bound to a context are called context-bound classes; context-bound classes are marked with Context Attributes which provide usage rules for synchronization; thread affinity; transactions etc. + PhAddListViewItem(Context->CountersLv, MAXINT, L"Context-Bound Classes Loaded", NULL); + + // This counter displays the current number of remoting contexts in the application. A context is a boundary containing a collection of objects with the same usage rules like synchronization; thread affinity; transactions etc. + PhAddListViewItem(Context->CountersLv, MAXINT, L"Contexts", NULL); + + PhAddListViewItem(Context->CountersLv, MAXINT, L"# of context bound objects allocated", NULL); + + // Remote Calls / sec + // This counter displays the number of remote procedure calls invoked per second. A remote procedure call is a call on any object outside the callers AppDomain. This counter is not an average over time; it displays the difference between the values observed in the last two samples divided by the duration of the sample interval. + + // Context - Bound Objects Alloc / sec + // This counter displays the number of context - bound objects allocated per second. Instances of classes that can be bound to a context are called context - bound objects; context - bound classes are marked with Context Attributes which provide usage rules for synchronization; thread affinity; transactions etc.This counter is not an average over time; it displays the difference between the values observed in the last two samples divided by the duration of the sample interval. + } + break; + case DOTNET_CATEGORY_SECURITY: + { + // This counter displays the total number of runtime Code Access Security(CAS) checks performed since the start of the application. Runtime CAS checks are performed when a caller makes a call to a callee demanding a particular permission; the runtime check is made on every call by the caller; the check is done by examining the current thread stack of the caller. This counter used together with "Stack Walk Depth" is indicative of performance penalty for security checks. + PhAddListViewItem(Context->CountersLv, MAXINT, L"Total Runtime Checks", NULL); + + // This counter displays the total number of linktime Code Access Security(CAS) checks since the start of the application. Linktime CAS checks are performed when a caller makes a call to a callee demanding a particular permission at JIT compile time; linktime check is performed once per caller. This count is not indicative of serious performance issues; its indicative of the security system activity. + PhAddListViewItem(Context->CountersLv, MAXINT, L"# Link Time Checks", NULL); + + // This counter displays the percentage of elapsed time spent in performing runtime Code Access Security(CAS) checks since the last such check. CAS allows code to be trusted to varying degrees and enforces these varying levels of trust depending on code identity. This counter is updated at the end of a runtime security check; it represents the last observed value; its not an average. + PhAddListViewItem(Context->CountersLv, MAXINT, L"% Time in RT checks", NULL); + + // This counter displays the depth of the stack during that last runtime Code Access Security check.Runtime Code Access Security check is performed by crawling the stack. This counter is not an average; it just displays the last observed value. + PhAddListViewItem(Context->CountersLv, MAXINT, L"Stack Walk Depth", NULL); + + // % Time Sig.Authenticating + // Reserved for future use. + } + break; + } +} + +VOID AddProcessAppDomains( + _In_ HWND hwndDlg, + _In_ PPERFPAGE_CONTEXT Context + ) +{ + SendMessage(Context->AppDomainsLv, WM_SETREDRAW, FALSE, 0); + ListView_DeleteAllItems(Context->AppDomainsLv); + + if (Context->ClrV4) + { + PPH_LIST processAppDomains = QueryDotNetAppDomainsForPid_V4( + Context->IsWow64, + Context->ProcessHandle, + Context->ProcessItem->ProcessId + ); + + if (processAppDomains) + { + for (ULONG i = 0; i < processAppDomains->Count; i++) + { + PhAddListViewItem(Context->AppDomainsLv, MAXINT, processAppDomains->Items[i], NULL); + PhFree(processAppDomains->Items[i]); + } + + PhDereferenceObject(processAppDomains); + } + } + else + { + PPH_LIST processAppDomains = QueryDotNetAppDomainsForPid_V2( + Context->IsWow64, + Context->ProcessHandle, + Context->ProcessItem->ProcessId + ); + + if (processAppDomains) + { + for (ULONG i = 0; i < processAppDomains->Count; i++) + { + PhAddListViewItem(Context->AppDomainsLv, MAXINT, processAppDomains->Items[i], NULL); + PhFree(processAppDomains->Items[i]); + } + + PhDereferenceObject(processAppDomains); + } + } + + SendMessage(Context->AppDomainsLv, WM_SETREDRAW, TRUE, 0); +} + +VOID UpdateCounterData( + _In_ HWND hwndDlg, + _In_ PPERFPAGE_CONTEXT Context + ) +{ + PVOID perfStatBlock = NULL; + Perf_GC dotNetPerfGC; + Perf_Contexts dotNetPerfContext; + Perf_Interop dotNetPerfInterop; + Perf_Loading dotNetPerfLoading; + Perf_Excep dotNetPerfExcep; + Perf_LocksAndThreads dotNetPerfLocksAndThreads; + Perf_Jit dotNetPerfJit; + Perf_Security dotNetPerfSecurity; + + if (Context->ClrV4) + { + perfStatBlock = GetPerfIpcBlock_V4( + Context->IsWow64, + Context->BlockTableAddress + ); + } + else + { + perfStatBlock = GetPerfIpcBlock_V2( + Context->IsWow64, + Context->BlockTableAddress + ); + } + + if (!perfStatBlock) + return; + + if (Context->IsWow64) + { + PerfCounterIPCControlBlock_Wow64* perfBlock = perfStatBlock; + Perf_GC_Wow64 dotNetPerfGC_Wow64 = perfBlock->GC; + Perf_Loading_Wow64 dotNetPerfLoading_Wow64 = perfBlock->Loading; + Perf_Security_Wow64 dotNetPerfSecurity_Wow64 = perfBlock->Security; + + // Thunk the Wow64 structures into their 64bit versions (or 32bit version on x86). + + dotNetPerfGC.cGenCollections[0] = dotNetPerfGC_Wow64.cGenCollections[0]; + dotNetPerfGC.cGenCollections[1] = dotNetPerfGC_Wow64.cGenCollections[1]; + dotNetPerfGC.cGenCollections[2] = dotNetPerfGC_Wow64.cGenCollections[2]; + dotNetPerfGC.cbPromotedMem[0] = dotNetPerfGC_Wow64.cbPromotedMem[0]; + dotNetPerfGC.cbPromotedMem[1] = dotNetPerfGC_Wow64.cbPromotedMem[1]; + dotNetPerfGC.cbPromotedFinalizationMem = dotNetPerfGC_Wow64.cbPromotedFinalizationMem; + dotNetPerfGC.cProcessID = dotNetPerfGC_Wow64.cProcessID; + dotNetPerfGC.cGenHeapSize[0] = dotNetPerfGC_Wow64.cGenHeapSize[0]; + dotNetPerfGC.cGenHeapSize[1] = dotNetPerfGC_Wow64.cGenHeapSize[1]; + dotNetPerfGC.cGenHeapSize[2] = dotNetPerfGC_Wow64.cGenHeapSize[2]; + dotNetPerfGC.cTotalCommittedBytes = dotNetPerfGC_Wow64.cTotalCommittedBytes; + dotNetPerfGC.cTotalReservedBytes = dotNetPerfGC_Wow64.cTotalReservedBytes; + dotNetPerfGC.cLrgObjSize = dotNetPerfGC_Wow64.cLrgObjSize; + dotNetPerfGC.cSurviveFinalize = dotNetPerfGC_Wow64.cSurviveFinalize; + dotNetPerfGC.cHandles = dotNetPerfGC_Wow64.cHandles; + dotNetPerfGC.cbAlloc = dotNetPerfGC_Wow64.cbAlloc; + dotNetPerfGC.cbLargeAlloc = dotNetPerfGC_Wow64.cbLargeAlloc; + dotNetPerfGC.cInducedGCs = dotNetPerfGC_Wow64.cInducedGCs; + dotNetPerfGC.timeInGC = dotNetPerfGC_Wow64.timeInGC; + dotNetPerfGC.timeInGCBase = dotNetPerfGC_Wow64.timeInGCBase; + dotNetPerfGC.cPinnedObj = dotNetPerfGC_Wow64.cPinnedObj; + dotNetPerfGC.cSinkBlocks = dotNetPerfGC_Wow64.cSinkBlocks; + + dotNetPerfContext = perfBlock->Context; + dotNetPerfInterop = perfBlock->Interop; + + dotNetPerfLoading.cClassesLoaded.Current = dotNetPerfLoading_Wow64.cClassesLoaded.Current; + dotNetPerfLoading.cClassesLoaded.Total = dotNetPerfLoading_Wow64.cClassesLoaded.Total; + dotNetPerfLoading.cAppDomains.Current = dotNetPerfLoading_Wow64.cAppDomains.Current; + dotNetPerfLoading.cAppDomains.Total = dotNetPerfLoading_Wow64.cAppDomains.Total; + dotNetPerfLoading.cAssemblies.Current = dotNetPerfLoading_Wow64.cAssemblies.Current; + dotNetPerfLoading.cAssemblies.Total = dotNetPerfLoading_Wow64.cAssemblies.Total; + dotNetPerfLoading.timeLoading = dotNetPerfLoading_Wow64.timeLoading; + dotNetPerfLoading.cAsmSearchLen = dotNetPerfLoading_Wow64.cAsmSearchLen; + dotNetPerfLoading.cLoadFailures.Total = dotNetPerfLoading_Wow64.cLoadFailures.Total; + dotNetPerfLoading.cbLoaderHeapSize = dotNetPerfLoading_Wow64.cbLoaderHeapSize; + dotNetPerfLoading.cAppDomainsUnloaded = dotNetPerfLoading_Wow64.cAppDomainsUnloaded; + + dotNetPerfExcep = perfBlock->Excep; + dotNetPerfLocksAndThreads = perfBlock->LocksAndThreads; + dotNetPerfJit = perfBlock->Jit; + + dotNetPerfSecurity.cTotalRTChecks = dotNetPerfSecurity_Wow64.cTotalRTChecks; + dotNetPerfSecurity.timeAuthorize = dotNetPerfSecurity_Wow64.timeAuthorize; + dotNetPerfSecurity.cLinkChecks = dotNetPerfSecurity_Wow64.cLinkChecks; + dotNetPerfSecurity.timeRTchecks = dotNetPerfSecurity_Wow64.timeRTchecks; + dotNetPerfSecurity.timeRTchecksBase = dotNetPerfSecurity_Wow64.timeRTchecksBase; + dotNetPerfSecurity.stackWalkDepth = dotNetPerfSecurity_Wow64.stackWalkDepth; + } + else + { + PerfCounterIPCControlBlock* perfBlock = perfStatBlock; + + dotNetPerfGC = perfBlock->GC; + dotNetPerfContext = perfBlock->Context; + dotNetPerfInterop = perfBlock->Interop; + dotNetPerfLoading = perfBlock->Loading; + dotNetPerfExcep = perfBlock->Excep; + dotNetPerfLocksAndThreads = perfBlock->LocksAndThreads; + dotNetPerfJit = perfBlock->Jit; + dotNetPerfSecurity = perfBlock->Security; + } + + switch (Context->CategoryIndex) + { + case DOTNET_CATEGORY_EXCEPTIONS: + { + PhSetListViewSubItem(Context->CountersLv, 0, 1, PhaFormatUInt64(dotNetPerfExcep.cThrown.Total, TRUE)->Buffer); + PhSetListViewSubItem(Context->CountersLv, 1, 1, PhaFormatUInt64(dotNetPerfExcep.cFiltersExecuted, TRUE)->Buffer); + PhSetListViewSubItem(Context->CountersLv, 2, 1, PhaFormatUInt64(dotNetPerfExcep.cFinallysExecuted, TRUE)->Buffer); + //PhSetListViewSubItem(Context->CountersLv, 3, 1, PhaFormatUInt64(dotNetPerfExcep.cThrowToCatchStackDepth, TRUE)->Buffer); + } + break; + case DOTNET_CATEGORY_INTEROP: + { + PhSetListViewSubItem(Context->CountersLv, 0, 1, PhaFormatUInt64(dotNetPerfInterop.cCCW, TRUE)->Buffer); + PhSetListViewSubItem(Context->CountersLv, 1, 1, PhaFormatUInt64(dotNetPerfInterop.cStubs, TRUE)->Buffer); + PhSetListViewSubItem(Context->CountersLv, 2, 1, PhaFormatUInt64(dotNetPerfInterop.cMarshalling, TRUE)->Buffer); + PhSetListViewSubItem(Context->CountersLv, 3, 1, PhaFormatUInt64(dotNetPerfInterop.cTLBImports, TRUE)->Buffer); + PhSetListViewSubItem(Context->CountersLv, 4, 1, PhaFormatUInt64(dotNetPerfInterop.cTLBExports, TRUE)->Buffer); + } + break; + case DOTNET_CATEGORY_JIT: + { + PhSetListViewSubItem(Context->CountersLv, 0, 1, PhaFormatUInt64(dotNetPerfJit.cMethodsJitted, TRUE)->Buffer); + PhSetListViewSubItem(Context->CountersLv, 1, 1, FormatByteValue(Context, dotNetPerfJit.cbILJitted.Current)->Buffer); + PhSetListViewSubItem(Context->CountersLv, 2, 1, FormatByteValue(Context, dotNetPerfJit.cbILJitted.Total)->Buffer); + PhSetListViewSubItem(Context->CountersLv, 3, 1, PhaFormatUInt64(dotNetPerfJit.cJitFailures, TRUE)->Buffer); + + if (dotNetPerfJit.timeInJitBase != 0) + { + PH_FORMAT format; + WCHAR formatBuffer[10]; + + // TODO: TimeInJit is always above 100% for some processes ?? + // SeeAlso: https://github.com/dotnet/coreclr/blob/master/src/gc/gcee.cpp#L324 + PhInitFormatF(&format, (dotNetPerfJit.timeInJit << 8) * 100 / (FLOAT)(dotNetPerfJit.timeInJitBase << 8), 2); + + if (PhFormatToBuffer(&format, 1, formatBuffer, sizeof(formatBuffer), NULL)) + PhSetListViewSubItem(Context->CountersLv, 4, 1, formatBuffer); + } + else + { + PhSetListViewSubItem(Context->CountersLv, 4, 1, L"0.00"); + } + } + break; + case DOTNET_CATEGORY_LOADING: + { + PhSetListViewSubItem(Context->CountersLv, 0, 1, PhaFormatUInt64(dotNetPerfLoading.cClassesLoaded.Current, TRUE)->Buffer); + PhSetListViewSubItem(Context->CountersLv, 1, 1, PhaFormatUInt64(dotNetPerfLoading.cClassesLoaded.Total, TRUE)->Buffer); + PhSetListViewSubItem(Context->CountersLv, 2, 1, PhaFormatUInt64(dotNetPerfLoading.cAppDomains.Current, TRUE)->Buffer); + PhSetListViewSubItem(Context->CountersLv, 3, 1, PhaFormatUInt64(dotNetPerfLoading.cAppDomains.Total, TRUE)->Buffer); + PhSetListViewSubItem(Context->CountersLv, 4, 1, PhaFormatUInt64(dotNetPerfLoading.cAssemblies.Current, TRUE)->Buffer); + PhSetListViewSubItem(Context->CountersLv, 5, 1, PhaFormatUInt64(dotNetPerfLoading.cAssemblies.Total, TRUE)->Buffer); + PhSetListViewSubItem(Context->CountersLv, 6, 1, PhaFormatUInt64(dotNetPerfLoading.cAsmSearchLen, TRUE)->Buffer); + PhSetListViewSubItem(Context->CountersLv, 7, 1, PhaFormatUInt64(dotNetPerfLoading.cLoadFailures.Total, TRUE)->Buffer); + PhSetListViewSubItem(Context->CountersLv, 8, 1, FormatByteValue(Context, dotNetPerfLoading.cbLoaderHeapSize)->Buffer); + PhSetListViewSubItem(Context->CountersLv, 9, 1, PhaFormatUInt64(dotNetPerfLoading.cAppDomainsUnloaded.Total, TRUE)->Buffer); + //PhSetListViewSubItem(Context->CountersLv, 10, 1, PhaFormatUInt64(dotNetPerfLoading.timeLoading, TRUE)->Buffer); + } + break; + case DOTNET_CATEGORY_LOCKSANDTHREADS: + { + PhSetListViewSubItem(Context->CountersLv, 0, 1, PhaFormatUInt64(dotNetPerfLocksAndThreads.cContention.Total, TRUE)->Buffer); + PhSetListViewSubItem(Context->CountersLv, 1, 1, PhaFormatUInt64(dotNetPerfLocksAndThreads.cQueueLength.Current, TRUE)->Buffer); + PhSetListViewSubItem(Context->CountersLv, 2, 1, PhaFormatUInt64(dotNetPerfLocksAndThreads.cQueueLength.Total, TRUE)->Buffer); + PhSetListViewSubItem(Context->CountersLv, 3, 1, PhaFormatUInt64(dotNetPerfLocksAndThreads.cCurrentThreadsLogical, TRUE)->Buffer); + PhSetListViewSubItem(Context->CountersLv, 4, 1, PhaFormatUInt64(dotNetPerfLocksAndThreads.cCurrentThreadsPhysical, TRUE)->Buffer); + PhSetListViewSubItem(Context->CountersLv, 5, 1, PhaFormatUInt64(dotNetPerfLocksAndThreads.cRecognizedThreads.Current, TRUE)->Buffer); + PhSetListViewSubItem(Context->CountersLv, 6, 1, PhaFormatUInt64(dotNetPerfLocksAndThreads.cRecognizedThreads.Total, TRUE)->Buffer); + } + break; + case DOTNET_CATEGORY_MEMORY: + { + PhSetListViewSubItem(Context->CountersLv, 0, 1, PhaFormatUInt64(dotNetPerfGC.cGenCollections[0], TRUE)->Buffer); + PhSetListViewSubItem(Context->CountersLv, 1, 1, PhaFormatUInt64(dotNetPerfGC.cGenCollections[1], TRUE)->Buffer); + PhSetListViewSubItem(Context->CountersLv, 2, 1, PhaFormatUInt64(dotNetPerfGC.cGenCollections[2], TRUE)->Buffer); + PhSetListViewSubItem(Context->CountersLv, 3, 1, FormatByteValue(Context, dotNetPerfGC.cbPromotedMem[0])->Buffer); + PhSetListViewSubItem(Context->CountersLv, 4, 1, FormatByteValue(Context, dotNetPerfGC.cbPromotedMem[1])->Buffer); + PhSetListViewSubItem(Context->CountersLv, 5, 1, FormatByteValue(Context, dotNetPerfGC.cbPromotedFinalizationMem)->Buffer); + PhSetListViewSubItem(Context->CountersLv, 6, 1, PhaFormatUInt64(dotNetPerfGC.cProcessID, FALSE)->Buffer); + PhSetListViewSubItem(Context->CountersLv, 7, 1, FormatByteValue(Context, dotNetPerfGC.cGenHeapSize[0])->Buffer); + PhSetListViewSubItem(Context->CountersLv, 8, 1, FormatByteValue(Context, dotNetPerfGC.cGenHeapSize[1])->Buffer); + PhSetListViewSubItem(Context->CountersLv, 9, 1, FormatByteValue(Context, dotNetPerfGC.cGenHeapSize[2])->Buffer); + PhSetListViewSubItem(Context->CountersLv, 10, 1, FormatByteValue(Context, dotNetPerfGC.cLrgObjSize)->Buffer); + PhSetListViewSubItem(Context->CountersLv, 11, 1, PhaFormatUInt64(dotNetPerfGC.cSurviveFinalize, TRUE)->Buffer); + PhSetListViewSubItem(Context->CountersLv, 12, 1, PhaFormatUInt64(dotNetPerfGC.cHandles, TRUE)->Buffer); + PhSetListViewSubItem(Context->CountersLv, 13, 1, PhaFormatUInt64(dotNetPerfGC.cInducedGCs, TRUE)->Buffer); + + if (dotNetPerfGC.timeInGCBase != 0) + { + PH_FORMAT format; + WCHAR formatBuffer[10]; + + PhInitFormatF(&format, (FLOAT)dotNetPerfGC.timeInGC * 100 / (FLOAT)dotNetPerfGC.timeInGCBase, 2); + + if (PhFormatToBuffer(&format, 1, formatBuffer, sizeof(formatBuffer), NULL)) + PhSetListViewSubItem(Context->CountersLv, 14, 1, formatBuffer); + } + else + { + PhSetListViewSubItem(Context->CountersLv, 14, 1, L"0.00"); + } + + // The CLR source says this value should be "Gen 0 Heap Size; Gen 1 Heap Size; Gen 2 Heap Size and the Large Object Heap Size", + // but Perflib only counts Gen 1, Gen 2 and cLrgObjSize... For now, just do what perflib does. + PhSetListViewSubItem(Context->CountersLv, 15, 1, FormatByteValue(Context, dotNetPerfGC.cGenHeapSize[1] + dotNetPerfGC.cGenHeapSize[2] + dotNetPerfGC.cLrgObjSize)->Buffer); + PhSetListViewSubItem(Context->CountersLv, 16, 1, FormatByteValue(Context, dotNetPerfGC.cTotalCommittedBytes)->Buffer); + PhSetListViewSubItem(Context->CountersLv, 17, 1, FormatByteValue(Context, dotNetPerfGC.cTotalReservedBytes)->Buffer); + PhSetListViewSubItem(Context->CountersLv, 18, 1, PhaFormatUInt64(dotNetPerfGC.cPinnedObj, TRUE)->Buffer); + PhSetListViewSubItem(Context->CountersLv, 19, 1, PhaFormatUInt64(dotNetPerfGC.cSinkBlocks, TRUE)->Buffer); + PhSetListViewSubItem(Context->CountersLv, 20, 1, FormatByteValue(Context, dotNetPerfGC.cbAlloc)->Buffer); + PhSetListViewSubItem(Context->CountersLv, 21, 1, FormatByteValue(Context, dotNetPerfGC.cbLargeAlloc)->Buffer); + } + break; + case DOTNET_CATEGORY_REMOTING: + { + PhSetListViewSubItem(Context->CountersLv, 0, 1, PhaFormatUInt64(dotNetPerfContext.cRemoteCalls.Total, TRUE)->Buffer); + PhSetListViewSubItem(Context->CountersLv, 1, 1, PhaFormatUInt64(dotNetPerfContext.cChannels, TRUE)->Buffer); + PhSetListViewSubItem(Context->CountersLv, 2, 1, PhaFormatUInt64(dotNetPerfContext.cProxies, TRUE)->Buffer); + PhSetListViewSubItem(Context->CountersLv, 3, 1, PhaFormatUInt64(dotNetPerfContext.cClasses, TRUE)->Buffer); + PhSetListViewSubItem(Context->CountersLv, 4, 1, PhaFormatUInt64(dotNetPerfContext.cContexts, TRUE)->Buffer); + PhSetListViewSubItem(Context->CountersLv, 5, 1, PhaFormatUInt64(dotNetPerfContext.cObjAlloc, TRUE)->Buffer); + } + break; + case DOTNET_CATEGORY_SECURITY: + { + PhSetListViewSubItem(Context->CountersLv, 0, 1, PhaFormatUInt64(dotNetPerfSecurity.cTotalRTChecks, TRUE)->Buffer); + PhSetListViewSubItem(Context->CountersLv, 1, 1, PhaFormatUInt64(dotNetPerfSecurity.cLinkChecks, TRUE)->Buffer); + + if (dotNetPerfSecurity.timeRTchecksBase != 0) + { + PH_FORMAT format; + WCHAR formatBuffer[10]; + + PhInitFormatF(&format, (FLOAT)dotNetPerfSecurity.timeRTchecks * 100 / (FLOAT)dotNetPerfSecurity.timeRTchecksBase, 2); + + if (PhFormatToBuffer(&format, 1, formatBuffer, sizeof(formatBuffer), NULL)) + PhSetListViewSubItem(Context->CountersLv, 2, 1, formatBuffer); + } + else + { + PhSetListViewSubItem(Context->CountersLv, 2, 1, L"0.00"); + } + + PhSetListViewSubItem(Context->CountersLv, 3, 1, PhaFormatUInt64(dotNetPerfSecurity.stackWalkDepth, TRUE)->Buffer); + } + break; + } +} + +INT_PTR CALLBACK DotNetPerfPageDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + LPPROPSHEETPAGE propSheetPage; + PPH_PROCESS_PROPPAGECONTEXT propPageContext; + PPH_PROCESS_ITEM processItem; + PPERFPAGE_CONTEXT context; + + if (PhPropPageDlgProcHeader(hwndDlg, uMsg, lParam, &propSheetPage, &propPageContext, &processItem)) + { + context = propPageContext->Context; + } + else + { + return FALSE; + } + + switch (uMsg) + { + case WM_INITDIALOG: + { + context = PhAllocate(sizeof(PERFPAGE_CONTEXT)); + memset(context, 0, sizeof(PERFPAGE_CONTEXT)); + + propPageContext->Context = context; + context->WindowHandle = hwndDlg; + context->ProcessItem = processItem; + context->Enabled = TRUE; + + context->AppDomainsLv = GetDlgItem(hwndDlg, IDC_APPDOMAINS); + context->CountersLv = GetDlgItem(hwndDlg, IDC_COUNTERS); + context->CategoriesCb = GetDlgItem(hwndDlg, IDC_CATEGORIES); + + PhSetListViewStyle(context->AppDomainsLv, FALSE, TRUE); + PhSetControlTheme(context->AppDomainsLv, L"explorer"); + PhAddListViewColumn(context->AppDomainsLv, 0, 0, 0, LVCFMT_LEFT, 300, L"Application domain"); + PhSetExtendedListView(context->AppDomainsLv); + + PhSetListViewStyle(context->CountersLv, FALSE, TRUE); + PhSetControlTheme(context->CountersLv, L"explorer"); + PhAddListViewColumn(context->CountersLv, 0, 0, 0, LVCFMT_LEFT, 250, L"Counter"); + PhAddListViewColumn(context->CountersLv, 1, 1, 1, LVCFMT_RIGHT, 140, L"Value"); + PhSetExtendedListView(context->CountersLv); + PhLoadListViewColumnsFromSetting(SETTING_NAME_DOT_NET_COUNTERS_COLUMNS, context->CountersLv); + + if (PhGetIntegerSetting(SETTING_NAME_DOT_NET_SHOW_BYTE_SIZE)) + { + context->ShowByteSize = TRUE; + Button_SetCheck(GetDlgItem(hwndDlg, IDC_DOTNET_PERF_SHOWBYTES), TRUE); + } + + PhAddComboBoxStrings(context->CategoriesCb, DotNetCategoryStrings, ARRAYSIZE(DotNetCategoryStrings)); + context->CategoryIndex = PhGetIntegerSetting(SETTING_NAME_DOT_NET_CATEGORY_INDEX); + ComboBox_SetCurSel(context->CategoriesCb, context->CategoryIndex); + +#ifdef _WIN64 + context->IsWow64 = !!context->ProcessItem->IsWow64; +#else + // HACK: Work-around for Appdomain enumeration on 32bit. + context->IsWow64 = TRUE; +#endif + + if (NT_SUCCESS(PhOpenProcess( + &context->ProcessHandle, + PROCESS_VM_READ | ProcessQueryAccess | PROCESS_DUP_HANDLE | SYNCHRONIZE, + context->ProcessItem->ProcessId + ))) + { + ULONG flags = 0; + + if (NT_SUCCESS(PhGetProcessIsDotNetEx( + context->ProcessItem->ProcessId, + context->ProcessHandle, + context->ProcessItem->IsImmersive == 1 ? 0 : PH_CLR_USE_SECTION_CHECK, + NULL, + &flags + ))) + { + if (flags & PH_CLR_VERSION_4_ABOVE) + { + context->ClrV4 = TRUE; + } + } + + // Skip AppDomain enumeration of 'Modern' .NET applications as they don't expose the CLR 'Private IPC' block. + if (!context->ProcessItem->IsImmersive) + { + AddProcessAppDomains(hwndDlg, context); + } + } + + if (context->ClrV4) + { + if (OpenDotNetPublicControlBlock_V4( + !!context->ProcessItem->IsImmersive, + context->ProcessHandle, + context->ProcessItem->ProcessId, + &context->BlockTableHandle, + &context->BlockTableAddress + )) + { + context->ControlBlockValid = TRUE; + } + } + else + { + if (OpenDotNetPublicControlBlock_V2( + context->ProcessItem->ProcessId, + &context->BlockTableHandle, + &context->BlockTableAddress + )) + { + context->ControlBlockValid = TRUE; + } + } + + if (context->ControlBlockValid) + { + UpdateCategoryValues(hwndDlg, context); + UpdateCounterData(hwndDlg, context); + } + + PhRegisterCallback( + PhGetGeneralCallback(GeneralCallbackProcessesUpdated), + ProcessesUpdatedCallback, + context, + &context->ProcessesUpdatedCallbackRegistration + ); + } + break; + case WM_DESTROY: + { + PhUnregisterCallback( + PhGetGeneralCallback(GeneralCallbackProcessesUpdated), + &context->ProcessesUpdatedCallbackRegistration + ); + + if (context->BlockTableAddress) + { + NtUnmapViewOfSection(NtCurrentProcess(), context->BlockTableAddress); + } + + if (context->BlockTableHandle) + { + NtClose(context->BlockTableHandle); + } + + if (context->ProcessHandle) + { + NtClose(context->ProcessHandle); + } + + PhSaveListViewColumnsToSetting(SETTING_NAME_DOT_NET_COUNTERS_COLUMNS, context->CountersLv); + + PhFree(context); + PhPropPageDlgProcDestroy(hwndDlg); + } + break; + case WM_SHOWWINDOW: + { + PPH_LAYOUT_ITEM dialogItem; + + if (dialogItem = PhBeginPropPageLayout(hwndDlg, propPageContext)) + { + PhAddPropPageLayoutItem(hwndDlg, context->AppDomainsLv, dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); + PhAddPropPageLayoutItem(hwndDlg, context->CategoriesCb, dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); + PhAddPropPageLayoutItem(hwndDlg, context->CountersLv, dialogItem, PH_ANCHOR_ALL); + PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_DOTNET_PERF_SHOWBYTES), dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_BOTTOM); + PhEndPropPageLayout(hwndDlg, propPageContext); + } + + ExtendedListView_SetColumnWidth(context->AppDomainsLv, 0, ELVSCW_AUTOSIZE_REMAININGSPACE); + } + break; + case WM_COMMAND: + { + switch (GET_WM_COMMAND_ID(wParam, lParam)) + { + case IDC_CATEGORIES: + { + if (GET_WM_COMMAND_CMD(wParam, lParam) == CBN_SELCHANGE) + { + context->CategoryIndex = ComboBox_GetCurSel(context->CategoriesCb); + PhSetIntegerSetting(SETTING_NAME_DOT_NET_CATEGORY_INDEX, context->CategoryIndex); + + if (context->ControlBlockValid) + { + UpdateCategoryValues(hwndDlg, context); + UpdateCounterData(hwndDlg, context); + } + } + } + break; + case IDC_DOTNET_PERF_SHOWBYTES: + { + if (GET_WM_COMMAND_CMD(wParam, lParam) == BN_CLICKED) + { + context->ShowByteSize = !context->ShowByteSize; + PhSetIntegerSetting(SETTING_NAME_DOT_NET_SHOW_BYTE_SIZE, context->ShowByteSize); + + if (context->ControlBlockValid) + { + UpdateCategoryValues(hwndDlg, context); + UpdateCounterData(hwndDlg, context); + } + } + } + break; + } + } + break; + case WM_NOTIFY: + { + LPNMHDR header = (LPNMHDR)lParam; + + switch (header->code) + { + case PSN_SETACTIVE: + context->Enabled = TRUE; + break; + case PSN_KILLACTIVE: + context->Enabled = FALSE; + break; + } + + PhHandleListViewNotifyForCopy(lParam, context->AppDomainsLv); + PhHandleListViewNotifyForCopy(lParam, context->CountersLv); + } + break; + case MSG_UPDATE: + { + if (context->Enabled && context->ControlBlockValid) + { + UpdateCounterData(hwndDlg, context); + } + } + break; + case WM_SIZE: + { + ExtendedListView_SetColumnWidth(context->AppDomainsLv, 0, ELVSCW_AUTOSIZE_REMAININGSPACE); + } + break; + } + + return FALSE; +} + +VOID AddPerfPageToPropContext( + _In_ PPH_PLUGIN_PROCESS_PROPCONTEXT PropContext + ) +{ + PhAddProcessPropPage( + PropContext->PropContext, + PhCreateProcessPropPageContextEx(PluginInstance->DllBase, MAKEINTRESOURCE(IDD_PROCDOTNETPERF), DotNetPerfPageDlgProc, NULL) + ); } \ No newline at end of file From 1e841be0d6756f0bb632dbb268017b0a9f84e7bb Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 27 Apr 2017 17:41:08 +1000 Subject: [PATCH 0021/2058] phlib: Fix delay load structure type and checks --- phlib/include/mapimg.h | 4 +- phlib/mapimg.c | 2804 ++++++++++++++++++++-------------------- 2 files changed, 1403 insertions(+), 1405 deletions(-) diff --git a/phlib/include/mapimg.h b/phlib/include/mapimg.h index dca55b9b2274..306704dfb44c 100644 --- a/phlib/include/mapimg.h +++ b/phlib/include/mapimg.h @@ -203,7 +203,7 @@ typedef struct _PH_MAPPED_IMAGE_IMPORTS union { PIMAGE_IMPORT_DESCRIPTOR DescriptorTable; - PVOID DelayDescriptorTable; + PIMAGE_DELAYLOAD_DESCRIPTOR DelayDescriptorTable; }; } PH_MAPPED_IMAGE_IMPORTS, *PPH_MAPPED_IMAGE_IMPORTS; @@ -217,7 +217,7 @@ typedef struct _PH_MAPPED_IMAGE_IMPORT_DLL union { PIMAGE_IMPORT_DESCRIPTOR Descriptor; - PVOID DelayDescriptor; + PIMAGE_DELAYLOAD_DESCRIPTOR DelayDescriptor; }; PVOID *LookupTable; } PH_MAPPED_IMAGE_IMPORT_DLL, *PPH_MAPPED_IMAGE_IMPORT_DLL; diff --git a/phlib/mapimg.c b/phlib/mapimg.c index 05d179f6bcf4..4366e633d1df 100644 --- a/phlib/mapimg.c +++ b/phlib/mapimg.c @@ -1,1404 +1,1402 @@ -/* - * Process Hacker - - * mapped image - * - * Copyright (C) 2010 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -/* - * This file contains functions to load and retrieve information for image files (exe, dll). The - * file format for image files is explained in the PE/COFF specification located at: - * - * http://www.microsoft.com/whdc/system/platform/firmware/PECOFF.mspx - */ - -#include -#include - -#include - -VOID PhpMappedImageProbe( - _In_ PPH_MAPPED_IMAGE MappedImage, - _In_ PVOID Address, - _In_ SIZE_T Length - ); - -ULONG PhpLookupMappedImageExportName( - _In_ PPH_MAPPED_IMAGE_EXPORTS Exports, - _In_ PSTR Name - ); - -NTSTATUS PhInitializeMappedImage( - _Out_ PPH_MAPPED_IMAGE MappedImage, - _In_ PVOID ViewBase, - _In_ SIZE_T Size - ) -{ - PIMAGE_DOS_HEADER dosHeader; - ULONG ntHeadersOffset; - - MappedImage->ViewBase = ViewBase; - MappedImage->Size = Size; - - dosHeader = (PIMAGE_DOS_HEADER)ViewBase; - - __try - { - PhpMappedImageProbe(MappedImage, dosHeader, sizeof(IMAGE_DOS_HEADER)); - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - return GetExceptionCode(); - } - - // Check the initial MZ. - - if (dosHeader->e_magic != IMAGE_DOS_SIGNATURE) - return STATUS_INVALID_IMAGE_NOT_MZ; - - // Get a pointer to the NT headers and probe it. - - ntHeadersOffset = (ULONG)dosHeader->e_lfanew; - - if (ntHeadersOffset == 0) - return STATUS_INVALID_IMAGE_FORMAT; - if (ntHeadersOffset >= 0x10000000 || ntHeadersOffset >= Size) - return STATUS_INVALID_IMAGE_FORMAT; - - MappedImage->NtHeaders = (PIMAGE_NT_HEADERS)PTR_ADD_OFFSET(ViewBase, ntHeadersOffset); - - __try - { - PhpMappedImageProbe( - MappedImage, - MappedImage->NtHeaders, - FIELD_OFFSET(IMAGE_NT_HEADERS, OptionalHeader) - ); - PhpMappedImageProbe( - MappedImage, - MappedImage->NtHeaders, - FIELD_OFFSET(IMAGE_NT_HEADERS, OptionalHeader) + - MappedImage->NtHeaders->FileHeader.SizeOfOptionalHeader + - MappedImage->NtHeaders->FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER) - ); - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - return GetExceptionCode(); - } - - // Check the signature and verify the magic. - - if (MappedImage->NtHeaders->Signature != IMAGE_NT_SIGNATURE) - return STATUS_INVALID_IMAGE_FORMAT; - - MappedImage->Magic = MappedImage->NtHeaders->OptionalHeader.Magic; - - if ( - MappedImage->Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC && - MappedImage->Magic != IMAGE_NT_OPTIONAL_HDR64_MAGIC - ) - return STATUS_INVALID_IMAGE_FORMAT; - - // Get a pointer to the first section. - - MappedImage->NumberOfSections = MappedImage->NtHeaders->FileHeader.NumberOfSections; - - MappedImage->Sections = (PIMAGE_SECTION_HEADER)( - ((PCHAR)&MappedImage->NtHeaders->OptionalHeader) + - MappedImage->NtHeaders->FileHeader.SizeOfOptionalHeader - ); - - return STATUS_SUCCESS; -} - -NTSTATUS PhLoadMappedImage( - _In_opt_ PWSTR FileName, - _In_opt_ HANDLE FileHandle, - _In_ BOOLEAN ReadOnly, - _Out_ PPH_MAPPED_IMAGE MappedImage - ) -{ - NTSTATUS status; - - status = PhMapViewOfEntireFile( - FileName, - FileHandle, - ReadOnly, - &MappedImage->ViewBase, - &MappedImage->Size - ); - - if (NT_SUCCESS(status)) - { - status = PhInitializeMappedImage( - MappedImage, - MappedImage->ViewBase, - MappedImage->Size - ); - - if (!NT_SUCCESS(status)) - { - NtUnmapViewOfSection(NtCurrentProcess(), MappedImage->ViewBase); - } - } - - return status; -} - -NTSTATUS PhUnloadMappedImage( - _Inout_ PPH_MAPPED_IMAGE MappedImage - ) -{ - return NtUnmapViewOfSection( - NtCurrentProcess(), - MappedImage->ViewBase - ); -} - -NTSTATUS PhMapViewOfEntireFile( - _In_opt_ PWSTR FileName, - _In_opt_ HANDLE FileHandle, - _In_ BOOLEAN ReadOnly, - _Out_ PVOID *ViewBase, - _Out_ PSIZE_T Size - ) -{ - NTSTATUS status; - BOOLEAN openedFile = FALSE; - LARGE_INTEGER size; - HANDLE sectionHandle = NULL; - SIZE_T viewSize; - PVOID viewBase; - - if (!FileName && !FileHandle) - return STATUS_INVALID_PARAMETER_MIX; - - // Open the file if we weren't supplied a file handle. - if (!FileHandle) - { - status = PhCreateFileWin32( - &FileHandle, - FileName, - ((FILE_READ_ATTRIBUTES | FILE_READ_DATA) | - (!ReadOnly ? (FILE_APPEND_DATA | FILE_WRITE_ATTRIBUTES | FILE_WRITE_DATA) : 0)) | SYNCHRONIZE, - 0, - FILE_SHARE_READ, - FILE_OPEN, - FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT - ); - - if (!NT_SUCCESS(status)) - return status; - - openedFile = TRUE; - } - - // Get the file size and create the section. - - status = PhGetFileSize(FileHandle, &size); - - if (!NT_SUCCESS(status)) - goto CleanupExit; - - status = NtCreateSection( - §ionHandle, - SECTION_ALL_ACCESS, - NULL, - &size, - ReadOnly ? PAGE_READONLY : PAGE_READWRITE, - SEC_COMMIT, - FileHandle - ); - - if (!NT_SUCCESS(status)) - goto CleanupExit; - - // Map the section. - - viewSize = (SIZE_T)size.QuadPart; - viewBase = NULL; - - status = NtMapViewOfSection( - sectionHandle, - NtCurrentProcess(), - &viewBase, - 0, - 0, - NULL, - &viewSize, - ViewShare, - 0, - ReadOnly ? PAGE_READONLY : PAGE_READWRITE - ); - - if (!NT_SUCCESS(status)) - goto CleanupExit; - - *ViewBase = viewBase; - *Size = (SIZE_T)size.QuadPart; - -CleanupExit: - if (sectionHandle) - NtClose(sectionHandle); - if (openedFile) - NtClose(FileHandle); - - return status; -} - -VOID PhpMappedImageProbe( - _In_ PPH_MAPPED_IMAGE MappedImage, - _In_ PVOID Address, - _In_ SIZE_T Length - ) -{ - PhProbeAddress(Address, Length, MappedImage->ViewBase, MappedImage->Size, 1); -} - -PIMAGE_SECTION_HEADER PhMappedImageRvaToSection( - _In_ PPH_MAPPED_IMAGE MappedImage, - _In_ ULONG Rva - ) -{ - ULONG i; - - for (i = 0; i < MappedImage->NumberOfSections; i++) - { - if ( - (Rva >= MappedImage->Sections[i].VirtualAddress) && - (Rva < MappedImage->Sections[i].VirtualAddress + MappedImage->Sections[i].SizeOfRawData) - ) - { - return &MappedImage->Sections[i]; - } - } - - return NULL; -} - -PVOID PhMappedImageRvaToVa( - _In_ PPH_MAPPED_IMAGE MappedImage, - _In_ ULONG Rva, - _Out_opt_ PIMAGE_SECTION_HEADER *Section - ) -{ - PIMAGE_SECTION_HEADER section; - - section = PhMappedImageRvaToSection(MappedImage, Rva); - - if (!section) - return NULL; - - if (Section) - *Section = section; - - return (PVOID)( - (ULONG_PTR)MappedImage->ViewBase + - (Rva - section->VirtualAddress) + - section->PointerToRawData - ); -} - -BOOLEAN PhGetMappedImageSectionName( - _In_ PIMAGE_SECTION_HEADER Section, - _Out_writes_opt_z_(Count) PSTR Buffer, - _In_ ULONG Count, - _Out_opt_ PULONG ReturnCount - ) -{ - BOOLEAN result; - SIZE_T returnCount; - - result = PhCopyBytesZ( - Section->Name, - IMAGE_SIZEOF_SHORT_NAME, - Buffer, - Count, - &returnCount - ); - - if (ReturnCount) - *ReturnCount = (ULONG)returnCount; - - return result; -} - -NTSTATUS PhGetMappedImageDataEntry( - _In_ PPH_MAPPED_IMAGE MappedImage, - _In_ ULONG Index, - _Out_ PIMAGE_DATA_DIRECTORY *Entry - ) -{ - if (MappedImage->Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) - { - PIMAGE_OPTIONAL_HEADER32 optionalHeader; - - optionalHeader = (PIMAGE_OPTIONAL_HEADER32)&MappedImage->NtHeaders->OptionalHeader; - - if (Index >= optionalHeader->NumberOfRvaAndSizes) - return STATUS_INVALID_PARAMETER_2; - - *Entry = &optionalHeader->DataDirectory[Index]; - } - else if (MappedImage->Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) - { - PIMAGE_OPTIONAL_HEADER64 optionalHeader; - - optionalHeader = (PIMAGE_OPTIONAL_HEADER64)&MappedImage->NtHeaders->OptionalHeader; - - if (Index >= optionalHeader->NumberOfRvaAndSizes) - return STATUS_INVALID_PARAMETER_2; - - *Entry = &optionalHeader->DataDirectory[Index]; - } - else - { - return STATUS_INVALID_PARAMETER; - } - - return STATUS_SUCCESS; -} - -FORCEINLINE NTSTATUS PhpGetMappedImageLoadConfig( - _In_ PPH_MAPPED_IMAGE MappedImage, - _In_ USHORT Magic, - _In_ ULONG ProbeLength, - _Out_ PVOID *LoadConfig - ) -{ - NTSTATUS status; - PIMAGE_DATA_DIRECTORY entry; - PVOID loadConfig; - - if (MappedImage->Magic != Magic) - return STATUS_INVALID_PARAMETER; - - status = PhGetMappedImageDataEntry(MappedImage, IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG, &entry); - - if (!NT_SUCCESS(status)) - return status; - - loadConfig = PhMappedImageRvaToVa(MappedImage, entry->VirtualAddress, NULL); - - if (!loadConfig) - return STATUS_INVALID_PARAMETER; - - __try - { - PhpMappedImageProbe(MappedImage, loadConfig, ProbeLength); - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - return GetExceptionCode(); - } - - *LoadConfig = loadConfig; - - return STATUS_SUCCESS; -} - -NTSTATUS PhGetMappedImageLoadConfig32( - _In_ PPH_MAPPED_IMAGE MappedImage, - _Out_ PIMAGE_LOAD_CONFIG_DIRECTORY32 *LoadConfig - ) -{ - return PhpGetMappedImageLoadConfig( - MappedImage, - IMAGE_NT_OPTIONAL_HDR32_MAGIC, - sizeof(IMAGE_LOAD_CONFIG_DIRECTORY32), - LoadConfig - ); -} - -NTSTATUS PhGetMappedImageLoadConfig64( - _In_ PPH_MAPPED_IMAGE MappedImage, - _Out_ PIMAGE_LOAD_CONFIG_DIRECTORY64 *LoadConfig - ) -{ - return PhpGetMappedImageLoadConfig( - MappedImage, - IMAGE_NT_OPTIONAL_HDR64_MAGIC, - sizeof(IMAGE_LOAD_CONFIG_DIRECTORY64), - LoadConfig - ); -} - -NTSTATUS PhLoadRemoteMappedImage( - _In_ HANDLE ProcessHandle, - _In_ PVOID ViewBase, - _Out_ PPH_REMOTE_MAPPED_IMAGE RemoteMappedImage - ) -{ - NTSTATUS status; - IMAGE_DOS_HEADER dosHeader; - ULONG ntHeadersOffset; - IMAGE_NT_HEADERS32 ntHeaders; - ULONG ntHeadersSize; - - RemoteMappedImage->ViewBase = ViewBase; - - status = NtReadVirtualMemory( - ProcessHandle, - ViewBase, - &dosHeader, - sizeof(IMAGE_DOS_HEADER), - NULL - ); - - if (!NT_SUCCESS(status)) - return status; - - // Check the initial MZ. - - if (dosHeader.e_magic != IMAGE_DOS_SIGNATURE) - return STATUS_INVALID_IMAGE_NOT_MZ; - - // Get a pointer to the NT headers and read it in for some basic information. - - ntHeadersOffset = (ULONG)dosHeader.e_lfanew; - - if (ntHeadersOffset == 0 || ntHeadersOffset >= 0x10000000) - return STATUS_INVALID_IMAGE_FORMAT; - - status = NtReadVirtualMemory( - ProcessHandle, - PTR_ADD_OFFSET(ViewBase, ntHeadersOffset), - &ntHeaders, - sizeof(IMAGE_NT_HEADERS32), - NULL - ); - - if (!NT_SUCCESS(status)) - return status; - - // Check the signature and verify the magic. - - if (ntHeaders.Signature != IMAGE_NT_SIGNATURE) - return STATUS_INVALID_IMAGE_FORMAT; - - RemoteMappedImage->Magic = ntHeaders.OptionalHeader.Magic; - - if ( - RemoteMappedImage->Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC && - RemoteMappedImage->Magic != IMAGE_NT_OPTIONAL_HDR64_MAGIC - ) - return STATUS_INVALID_IMAGE_FORMAT; - - // Get the real size and read in the whole thing. - - RemoteMappedImage->NumberOfSections = ntHeaders.FileHeader.NumberOfSections; - ntHeadersSize = FIELD_OFFSET(IMAGE_NT_HEADERS, OptionalHeader) + - ntHeaders.FileHeader.SizeOfOptionalHeader + - RemoteMappedImage->NumberOfSections * sizeof(IMAGE_SECTION_HEADER); - - if (ntHeadersSize > 1024 * 1024) // 1 MB - return STATUS_INVALID_IMAGE_FORMAT; - - RemoteMappedImage->NtHeaders = PhAllocate(ntHeadersSize); - - status = NtReadVirtualMemory( - ProcessHandle, - PTR_ADD_OFFSET(ViewBase, ntHeadersOffset), - RemoteMappedImage->NtHeaders, - ntHeadersSize, - NULL - ); - - if (!NT_SUCCESS(status)) - { - PhFree(RemoteMappedImage->NtHeaders); - return status; - } - - RemoteMappedImage->Sections = (PIMAGE_SECTION_HEADER)( - (PCHAR)RemoteMappedImage->NtHeaders + - FIELD_OFFSET(IMAGE_NT_HEADERS, OptionalHeader) + ntHeaders.FileHeader.SizeOfOptionalHeader - ); - - return STATUS_SUCCESS; -} - -NTSTATUS PhUnloadRemoteMappedImage( - _Inout_ PPH_REMOTE_MAPPED_IMAGE RemoteMappedImage - ) -{ - PhFree(RemoteMappedImage->NtHeaders); - - return STATUS_SUCCESS; -} - -NTSTATUS PhGetMappedImageExports( - _Out_ PPH_MAPPED_IMAGE_EXPORTS Exports, - _In_ PPH_MAPPED_IMAGE MappedImage - ) -{ - NTSTATUS status; - PIMAGE_EXPORT_DIRECTORY exportDirectory; - - Exports->MappedImage = MappedImage; - - // Get a pointer to the export directory. - - status = PhGetMappedImageDataEntry( - MappedImage, - IMAGE_DIRECTORY_ENTRY_EXPORT, - &Exports->DataDirectory - ); - - if (!NT_SUCCESS(status)) - return status; - - exportDirectory = PhMappedImageRvaToVa( - MappedImage, - Exports->DataDirectory->VirtualAddress, - NULL - ); - - if (!exportDirectory) - return STATUS_INVALID_PARAMETER; - - __try - { - PhpMappedImageProbe(MappedImage, exportDirectory, sizeof(IMAGE_EXPORT_DIRECTORY)); - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - return GetExceptionCode(); - } - - Exports->ExportDirectory = exportDirectory; - Exports->NumberOfEntries = exportDirectory->NumberOfFunctions; - - // Get pointers to the various tables and probe them. - - Exports->AddressTable = (PULONG)PhMappedImageRvaToVa( - MappedImage, - exportDirectory->AddressOfFunctions, - NULL - ); - Exports->NamePointerTable = (PULONG)PhMappedImageRvaToVa( - MappedImage, - exportDirectory->AddressOfNames, - NULL - ); - Exports->OrdinalTable = (PUSHORT)PhMappedImageRvaToVa( - MappedImage, - exportDirectory->AddressOfNameOrdinals, - NULL - ); - - if ( - !Exports->AddressTable || - !Exports->NamePointerTable || - !Exports->OrdinalTable - ) - return STATUS_INVALID_PARAMETER; - - __try - { - PhpMappedImageProbe( - MappedImage, - Exports->AddressTable, - exportDirectory->NumberOfFunctions * sizeof(ULONG) - ); - PhpMappedImageProbe( - MappedImage, - Exports->NamePointerTable, - exportDirectory->NumberOfNames * sizeof(ULONG) - ); - PhpMappedImageProbe( - MappedImage, - Exports->OrdinalTable, // ordinal list for named exports - exportDirectory->NumberOfNames * sizeof(USHORT) - ); - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - return GetExceptionCode(); - } - - // The ordinal and name tables are parallel. - // Getting an index into the name table (e.g. by doing a binary - // search) and indexing into the ordinal table will produce the - // ordinal for that name, *unbiased* (unlike in the specification). - // The unbiased ordinal is an index into the address table. - - return STATUS_SUCCESS; -} - -NTSTATUS PhGetMappedImageExportEntry( - _In_ PPH_MAPPED_IMAGE_EXPORTS Exports, - _In_ ULONG Index, - _Out_ PPH_MAPPED_IMAGE_EXPORT_ENTRY Entry - ) -{ - ULONG nameIndex = 0; - BOOLEAN exportByName = FALSE; - PSTR name; - - if (Index >= Exports->ExportDirectory->NumberOfFunctions) - return STATUS_PROCEDURE_NOT_FOUND; - - Entry->Ordinal = (USHORT)Index + (USHORT)Exports->ExportDirectory->Base; - - // look into named exports ordinal list. - for (nameIndex = 0; nameIndex < Exports->ExportDirectory->NumberOfNames; nameIndex++) - { - if (Index == Exports->OrdinalTable[nameIndex]) - { - exportByName = TRUE; - break; - } - } - - - if (exportByName) - { - name = PhMappedImageRvaToVa( - Exports->MappedImage, - Exports->NamePointerTable[nameIndex], - NULL - ); - - if (!name) - return STATUS_INVALID_PARAMETER; - - // TODO: Probe the name. - - Entry->Name = name; - } - else - { - Entry->Name = NULL; - } - - return STATUS_SUCCESS; -} - -NTSTATUS PhGetMappedImageExportFunction( - _In_ PPH_MAPPED_IMAGE_EXPORTS Exports, - _In_opt_ PSTR Name, - _In_opt_ USHORT Ordinal, - _Out_ PPH_MAPPED_IMAGE_EXPORT_FUNCTION Function - ) -{ - ULONG rva; - - if (Name) - { - ULONG index; - - index = PhpLookupMappedImageExportName(Exports, Name); - - if (index == -1) - return STATUS_PROCEDURE_NOT_FOUND; - - Ordinal = Exports->OrdinalTable[index] + (USHORT)Exports->ExportDirectory->Base; - } - - Ordinal -= (USHORT)Exports->ExportDirectory->Base; - - if (Ordinal >= Exports->ExportDirectory->NumberOfFunctions) - return STATUS_PROCEDURE_NOT_FOUND; - - rva = Exports->AddressTable[Ordinal]; - - if ( - (rva >= Exports->DataDirectory->VirtualAddress) && - (rva < Exports->DataDirectory->VirtualAddress + Exports->DataDirectory->Size) - ) - { - // This is a forwarder RVA. - - Function->ForwardedName = PhMappedImageRvaToVa( - Exports->MappedImage, - rva, - NULL - ); - - if (!Function->ForwardedName) - return STATUS_INVALID_PARAMETER; - - // TODO: Probe the name. - - Function->Function = NULL; - } - else - { - Function->Function = PhMappedImageRvaToVa( - Exports->MappedImage, - rva, - NULL - ); - Function->ForwardedName = NULL; - } - - return STATUS_SUCCESS; -} - -NTSTATUS PhGetMappedImageExportFunctionRemote( - _In_ PPH_MAPPED_IMAGE_EXPORTS Exports, - _In_opt_ PSTR Name, - _In_opt_ USHORT Ordinal, - _In_ PVOID RemoteBase, - _Out_ PVOID *Function - ) -{ - ULONG rva; - - if (Name) - { - ULONG index; - - index = PhpLookupMappedImageExportName(Exports, Name); - - if (index == -1) - return STATUS_PROCEDURE_NOT_FOUND; - - Ordinal = Exports->OrdinalTable[index] + (USHORT)Exports->ExportDirectory->Base; - } - - Ordinal -= (USHORT)Exports->ExportDirectory->Base; - - if (Ordinal >= Exports->ExportDirectory->NumberOfFunctions) - return STATUS_PROCEDURE_NOT_FOUND; - - rva = Exports->AddressTable[Ordinal]; - - if ( - (rva >= Exports->DataDirectory->VirtualAddress) && - (rva < Exports->DataDirectory->VirtualAddress + Exports->DataDirectory->Size) - ) - { - // This is a forwarder RVA. Not supported for remote lookup. - return STATUS_NOT_SUPPORTED; - } - else - { - *Function = PTR_ADD_OFFSET(RemoteBase, rva); - } - - return STATUS_SUCCESS; -} - -ULONG PhpLookupMappedImageExportName( - _In_ PPH_MAPPED_IMAGE_EXPORTS Exports, - _In_ PSTR Name - ) -{ - LONG low; - LONG high; - LONG i; - - if (Exports->ExportDirectory->NumberOfNames == 0) - return -1; - - low = 0; - high = Exports->ExportDirectory->NumberOfNames - 1; - - do - { - PSTR name; - INT comparison; - - i = (low + high) / 2; - - name = PhMappedImageRvaToVa( - Exports->MappedImage, - Exports->NamePointerTable[i], - NULL - ); - - if (!name) - return -1; - - // TODO: Probe the name. - - comparison = strcmp(Name, name); - - if (comparison == 0) - return i; - else if (comparison < 0) - high = i - 1; - else - low = i + 1; - } while (low <= high); - - return -1; -} - -NTSTATUS PhGetMappedImageImports( - _Out_ PPH_MAPPED_IMAGE_IMPORTS Imports, - _In_ PPH_MAPPED_IMAGE MappedImage - ) -{ - NTSTATUS status; - PIMAGE_DATA_DIRECTORY dataDirectory; - PIMAGE_IMPORT_DESCRIPTOR descriptor; - ULONG i; - - Imports->MappedImage = MappedImage; - Imports->Flags = 0; - - status = PhGetMappedImageDataEntry( - MappedImage, - IMAGE_DIRECTORY_ENTRY_IMPORT, - &dataDirectory - ); - - if (!NT_SUCCESS(status)) - return status; - - descriptor = PhMappedImageRvaToVa( - MappedImage, - dataDirectory->VirtualAddress, - NULL - ); - - if (!descriptor) - return STATUS_INVALID_PARAMETER; - - Imports->DescriptorTable = descriptor; - - // Do a scan to determine how many import descriptors there are. - - i = 0; - - __try - { - while (TRUE) - { - PhpMappedImageProbe(MappedImage, descriptor, sizeof(IMAGE_IMPORT_DESCRIPTOR)); - - if (descriptor->OriginalFirstThunk == 0 && descriptor->FirstThunk == 0) - break; - - descriptor++; - i++; - } - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - return GetExceptionCode(); - } - - Imports->NumberOfDlls = i; - - return STATUS_SUCCESS; -} - -NTSTATUS PhGetMappedImageImportDll( - _In_ PPH_MAPPED_IMAGE_IMPORTS Imports, - _In_ ULONG Index, - _Out_ PPH_MAPPED_IMAGE_IMPORT_DLL ImportDll - ) -{ - ULONG i; - - if (Index >= Imports->NumberOfDlls) - return STATUS_INVALID_PARAMETER_2; - - ImportDll->MappedImage = Imports->MappedImage; - ImportDll->Flags = Imports->Flags; - - if (!(ImportDll->Flags & PH_MAPPED_IMAGE_DELAY_IMPORTS)) - { - ImportDll->Descriptor = &Imports->DescriptorTable[Index]; - - ImportDll->Name = PhMappedImageRvaToVa( - ImportDll->MappedImage, - ImportDll->Descriptor->Name, - NULL - ); - - if (!ImportDll->Name) - return STATUS_INVALID_PARAMETER; - - // TODO: Probe the name. - - if (ImportDll->Descriptor->OriginalFirstThunk) - { - ImportDll->LookupTable = PhMappedImageRvaToVa( - ImportDll->MappedImage, - ImportDll->Descriptor->OriginalFirstThunk, - NULL - ); - } - else - { - ImportDll->LookupTable = PhMappedImageRvaToVa( - ImportDll->MappedImage, - ImportDll->Descriptor->FirstThunk, - NULL - ); - } - } - else - { - ImportDll->DelayDescriptor = &((PImgDelayDescr)Imports->DelayDescriptorTable)[Index]; - - ImportDll->Name = PhMappedImageRvaToVa( - ImportDll->MappedImage, - ((PImgDelayDescr)ImportDll->DelayDescriptor)->rvaDLLName, - NULL - ); - - if (!ImportDll->Name) - return STATUS_INVALID_PARAMETER; - - // TODO: Probe the name. - - ImportDll->LookupTable = PhMappedImageRvaToVa( - ImportDll->MappedImage, - ((PImgDelayDescr)ImportDll->DelayDescriptor)->rvaINT, - NULL - ); - } - - if (!ImportDll->LookupTable) - return STATUS_INVALID_PARAMETER; - - // Do a scan to determine how many entries there are. - - i = 0; - - if (ImportDll->MappedImage->Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) - { - PULONG entry; - - entry = (PULONG)ImportDll->LookupTable; - - __try - { - while (TRUE) - { - PhpMappedImageProbe( - ImportDll->MappedImage, - entry, - sizeof(ULONG) - ); - - if (*entry == 0) - break; - - entry++; - i++; - } - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - return GetExceptionCode(); - } - } - else if (ImportDll->MappedImage->Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) - { - PULONG64 entry; - - entry = (PULONG64)ImportDll->LookupTable; - - __try - { - while (TRUE) - { - PhpMappedImageProbe( - ImportDll->MappedImage, - entry, - sizeof(ULONG64) - ); - - if (*entry == 0) - break; - - entry++; - i++; - } - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - return GetExceptionCode(); - } - } - else - { - return STATUS_INVALID_PARAMETER; - } - - ImportDll->NumberOfEntries = i; - - return STATUS_SUCCESS; -} - -NTSTATUS PhGetMappedImageImportEntry( - _In_ PPH_MAPPED_IMAGE_IMPORT_DLL ImportDll, - _In_ ULONG Index, - _Out_ PPH_MAPPED_IMAGE_IMPORT_ENTRY Entry - ) -{ - PIMAGE_IMPORT_BY_NAME importByName; - - if (Index >= ImportDll->NumberOfEntries) - return STATUS_INVALID_PARAMETER_2; - - if (ImportDll->MappedImage->Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) - { - ULONG entry; - - entry = ((PULONG)ImportDll->LookupTable)[Index]; - - // Is this entry using an ordinal? - if (entry & IMAGE_ORDINAL_FLAG32) - { - Entry->Name = NULL; - Entry->Ordinal = (USHORT)IMAGE_ORDINAL32(entry); - - return STATUS_SUCCESS; - } - else - { - importByName = PhMappedImageRvaToVa( - ImportDll->MappedImage, - entry, - NULL - ); - } - } - else if (ImportDll->MappedImage->Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) - { - ULONG64 entry; - - entry = ((PULONG64)ImportDll->LookupTable)[Index]; - - // Is this entry using an ordinal? - if (entry & IMAGE_ORDINAL_FLAG64) - { - Entry->Name = NULL; - Entry->Ordinal = (USHORT)IMAGE_ORDINAL64(entry); - - return STATUS_SUCCESS; - } - else - { - importByName = PhMappedImageRvaToVa( - ImportDll->MappedImage, - (ULONG)entry, - NULL - ); - } - } - else - { - return STATUS_INVALID_PARAMETER; - } - - if (!importByName) - return STATUS_INVALID_PARAMETER; - - __try - { - PhpMappedImageProbe( - ImportDll->MappedImage, - importByName, - sizeof(IMAGE_IMPORT_BY_NAME) - ); - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - return GetExceptionCode(); - } - - Entry->Name = (PSTR)importByName->Name; - Entry->NameHint = importByName->Hint; - - // TODO: Probe the name. - - return STATUS_SUCCESS; -} - -NTSTATUS PhGetMappedImageDelayImports( - _Out_ PPH_MAPPED_IMAGE_IMPORTS Imports, - _In_ PPH_MAPPED_IMAGE MappedImage - ) -{ - NTSTATUS status; - PIMAGE_DATA_DIRECTORY dataDirectory; - PImgDelayDescr descriptor; - ULONG i; - - Imports->MappedImage = MappedImage; - Imports->Flags = PH_MAPPED_IMAGE_DELAY_IMPORTS; - - status = PhGetMappedImageDataEntry( - MappedImage, - IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT, - &dataDirectory - ); - - if (!NT_SUCCESS(status)) - return status; - - descriptor = PhMappedImageRvaToVa( - MappedImage, - dataDirectory->VirtualAddress, - NULL - ); - - if (!descriptor) - return STATUS_INVALID_PARAMETER; - - Imports->DelayDescriptorTable = descriptor; - - // Do a scan to determine how many import descriptors there are. - - i = 0; - - __try - { - while (TRUE) - { - PhpMappedImageProbe(MappedImage, descriptor, sizeof(ImgDelayDescr)); - - if (descriptor->rvaIAT == 0 && descriptor->rvaINT == 0) - break; - - descriptor++; - i++; - } - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - return GetExceptionCode(); - } - - Imports->NumberOfDlls = i; - - return STATUS_SUCCESS; -} - -USHORT PhCheckSum( - _In_ ULONG Sum, - _In_reads_(Count) PUSHORT Buffer, - _In_ ULONG Count - ) -{ - while (Count--) - { - Sum += *Buffer++; - Sum = (Sum >> 16) + (Sum & 0xffff); - } - - Sum = (Sum >> 16) + Sum; - - return (USHORT)Sum; -} - -ULONG PhCheckSumMappedImage( - _In_ PPH_MAPPED_IMAGE MappedImage - ) -{ - ULONG checkSum; - USHORT partialSum; - PUSHORT adjust; - - partialSum = PhCheckSum(0, (PUSHORT)MappedImage->ViewBase, (ULONG)(MappedImage->Size + 1) / 2); - - // This is actually the same for 32-bit and 64-bit executables. - adjust = (PUSHORT)&MappedImage->NtHeaders->OptionalHeader.CheckSum; - - // Subtract the existing check sum (with carry). - partialSum -= partialSum < adjust[0]; - partialSum -= adjust[0]; - partialSum -= partialSum < adjust[1]; - partialSum -= adjust[1]; - - checkSum = partialSum + (ULONG)MappedImage->Size; - - return checkSum; -} - -NTSTATUS PhGetMappedImageCfg( - _Out_ PPH_MAPPED_IMAGE_CFG CfgConfig, - _In_ PPH_MAPPED_IMAGE MappedImage - ) -{ - NTSTATUS status; - PIMAGE_LOAD_CONFIG_DIRECTORY64 config64; - - if (!NT_SUCCESS(status = PhGetMappedImageLoadConfig64(MappedImage, &config64))) - return status; - - // Not every load configuration defines CFG characteristics - if (config64->Size < (ULONG)FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY64, GuardFlags)) - return STATUS_INVALID_VIEW_SIZE; - - CfgConfig->MappedImage = MappedImage; - CfgConfig->EntrySize = sizeof(FIELD_OFFSET(IMAGE_CFG_ENTRY, Rva)) + - (ULONG)((config64->GuardFlags & IMAGE_GUARD_CF_FUNCTION_TABLE_SIZE_MASK) >> IMAGE_GUARD_CF_FUNCTION_TABLE_SIZE_SHIFT); - CfgConfig->CfgInstrumented = !!(config64->GuardFlags & IMAGE_GUARD_CF_INSTRUMENTED); - CfgConfig->WriteIntegrityChecks = !!(config64->GuardFlags & IMAGE_GUARD_CFW_INSTRUMENTED); - CfgConfig->CfgFunctionTablePresent = !!(config64->GuardFlags & IMAGE_GUARD_CF_FUNCTION_TABLE_PRESENT); - CfgConfig->SecurityCookieUnused = !!(config64->GuardFlags & IMAGE_GUARD_SECURITY_COOKIE_UNUSED); - CfgConfig->ProtectDelayLoadedIat = !!(config64->GuardFlags & IMAGE_GUARD_PROTECT_DELAYLOAD_IAT); - CfgConfig->DelayLoadInDidatSection = !!(config64->GuardFlags & IMAGE_GUARD_DELAYLOAD_IAT_IN_ITS_OWN_SECTION); - CfgConfig->EnableExportSuppression = !!(config64->GuardFlags & IMAGE_GUARD_CF_ENABLE_EXPORT_SUPPRESSION); - CfgConfig->HasExportSuppressionInfos = !!(config64->GuardFlags & IMAGE_GUARD_CF_EXPORT_SUPPRESSION_INFO_PRESENT); - CfgConfig->CfgLongJumpTablePresent = !!(config64->GuardFlags & IMAGE_GUARD_CF_LONGJUMP_TABLE_PRESENT); - - CfgConfig->NumberOfGuardFunctionEntries = config64->GuardCFFunctionCount; - CfgConfig->GuardFunctionTable = PhMappedImageRvaToVa( - MappedImage, - (ULONG)(config64->GuardCFFunctionTable - MappedImage->NtHeaders->OptionalHeader.ImageBase), - NULL - ); - - if (CfgConfig->GuardFunctionTable && CfgConfig->NumberOfGuardFunctionEntries) - { - __try - { - PhpMappedImageProbe( - MappedImage, - CfgConfig->GuardFunctionTable, - (SIZE_T)(CfgConfig->EntrySize * CfgConfig->NumberOfGuardFunctionEntries) - ); - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - return GetExceptionCode(); - } - } - - CfgConfig->NumberOfGuardAdressIatEntries = 0; - CfgConfig->GuardAdressIatTable = 0; - - if ( - config64->Size >= (ULONG)FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY64, GuardAddressTakenIatEntryTable) + - sizeof(config64->GuardAddressTakenIatEntryTable) + - sizeof(config64->GuardAddressTakenIatEntryCount) - ) - { - CfgConfig->NumberOfGuardAdressIatEntries = config64->GuardAddressTakenIatEntryCount; - CfgConfig->GuardAdressIatTable = PhMappedImageRvaToVa( - MappedImage, - (ULONG)(config64->GuardAddressTakenIatEntryTable - MappedImage->NtHeaders->OptionalHeader.ImageBase), - NULL - ); - - if (CfgConfig->GuardAdressIatTable && CfgConfig->NumberOfGuardAdressIatEntries) - { - __try - { - PhpMappedImageProbe( - MappedImage, - CfgConfig->GuardAdressIatTable, - (SIZE_T)(CfgConfig->EntrySize * CfgConfig->NumberOfGuardAdressIatEntries) - ); - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - return GetExceptionCode(); - } - } - } - - CfgConfig->NumberOfGuardLongJumpEntries = 0; - CfgConfig->GuardLongJumpTable = 0; - - if ( - config64->Size >= (ULONG)FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY64, GuardLongJumpTargetTable) + - sizeof(config64->GuardLongJumpTargetTable) + - sizeof(config64->GuardLongJumpTargetCount) - ) - { - CfgConfig->NumberOfGuardLongJumpEntries = config64->GuardLongJumpTargetCount; - CfgConfig->GuardLongJumpTable = PhMappedImageRvaToVa( - MappedImage, - (ULONG)(config64->GuardLongJumpTargetTable - MappedImage->NtHeaders->OptionalHeader.ImageBase), - NULL - ); - - if (CfgConfig->GuardLongJumpTable && CfgConfig->NumberOfGuardLongJumpEntries) - { - __try - { - PhpMappedImageProbe( - MappedImage, - CfgConfig->GuardLongJumpTable, - (SIZE_T)(CfgConfig->EntrySize * CfgConfig->NumberOfGuardLongJumpEntries) - ); - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - return GetExceptionCode(); - } - } - } - - return STATUS_SUCCESS; -} - -NTSTATUS PhGetMappedImageCfgEntry( - _In_ PPH_MAPPED_IMAGE_CFG CfgConfig, - _In_ ULONGLONG Index, - _In_ CFG_ENTRY_TYPE Type, - _Out_ PIMAGE_CFG_ENTRY Entry - ) -{ - PULONGLONG guardTable; - ULONGLONG numberofGuardEntries; - PIMAGE_CFG_ENTRY cfgMappedEntry; - - switch (Type) - { - case ControlFlowGuardFunction: - { - guardTable = CfgConfig->GuardFunctionTable; - numberofGuardEntries = CfgConfig->NumberOfGuardFunctionEntries; - } - break; - case ControlFlowGuardtakenIatEntry: - { - guardTable = CfgConfig->GuardAdressIatTable; - numberofGuardEntries = CfgConfig->NumberOfGuardAdressIatEntries; - } - break; - case ControlFlowGuardLongJump: - { - guardTable = CfgConfig->GuardLongJumpTable; - numberofGuardEntries = CfgConfig->NumberOfGuardLongJumpEntries; - } - break; - default: - return STATUS_INVALID_PARAMETER_3; - } - - if (!guardTable || Index >= numberofGuardEntries) - return STATUS_PROCEDURE_NOT_FOUND; - - cfgMappedEntry = (PIMAGE_CFG_ENTRY)PTR_ADD_OFFSET(guardTable, Index * CfgConfig->EntrySize); - - Entry->Rva = cfgMappedEntry->Rva; - - // Optional header after the rva entry - if (CfgConfig->EntrySize > sizeof(FIELD_OFFSET(IMAGE_CFG_ENTRY, Rva))) - { - Entry->SuppressedCall = cfgMappedEntry->SuppressedCall; - Entry->Reserved = cfgMappedEntry->Reserved; - } - - return STATUS_SUCCESS; +/* + * Process Hacker - + * mapped image + * + * Copyright (C) 2010 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +/* + * This file contains functions to load and retrieve information for image files (exe, dll). The + * file format for image files is explained in the PE/COFF specification located at: + * + * http://www.microsoft.com/whdc/system/platform/firmware/PECOFF.mspx + */ + +#include +#include + +VOID PhpMappedImageProbe( + _In_ PPH_MAPPED_IMAGE MappedImage, + _In_ PVOID Address, + _In_ SIZE_T Length + ); + +ULONG PhpLookupMappedImageExportName( + _In_ PPH_MAPPED_IMAGE_EXPORTS Exports, + _In_ PSTR Name + ); + +NTSTATUS PhInitializeMappedImage( + _Out_ PPH_MAPPED_IMAGE MappedImage, + _In_ PVOID ViewBase, + _In_ SIZE_T Size + ) +{ + PIMAGE_DOS_HEADER dosHeader; + ULONG ntHeadersOffset; + + MappedImage->ViewBase = ViewBase; + MappedImage->Size = Size; + + dosHeader = (PIMAGE_DOS_HEADER)ViewBase; + + __try + { + PhpMappedImageProbe(MappedImage, dosHeader, sizeof(IMAGE_DOS_HEADER)); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + return GetExceptionCode(); + } + + // Check the initial MZ. + + if (dosHeader->e_magic != IMAGE_DOS_SIGNATURE) + return STATUS_INVALID_IMAGE_NOT_MZ; + + // Get a pointer to the NT headers and probe it. + + ntHeadersOffset = (ULONG)dosHeader->e_lfanew; + + if (ntHeadersOffset == 0) + return STATUS_INVALID_IMAGE_FORMAT; + if (ntHeadersOffset >= 0x10000000 || ntHeadersOffset >= Size) + return STATUS_INVALID_IMAGE_FORMAT; + + MappedImage->NtHeaders = (PIMAGE_NT_HEADERS)PTR_ADD_OFFSET(ViewBase, ntHeadersOffset); + + __try + { + PhpMappedImageProbe( + MappedImage, + MappedImage->NtHeaders, + FIELD_OFFSET(IMAGE_NT_HEADERS, OptionalHeader) + ); + PhpMappedImageProbe( + MappedImage, + MappedImage->NtHeaders, + FIELD_OFFSET(IMAGE_NT_HEADERS, OptionalHeader) + + MappedImage->NtHeaders->FileHeader.SizeOfOptionalHeader + + MappedImage->NtHeaders->FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER) + ); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + return GetExceptionCode(); + } + + // Check the signature and verify the magic. + + if (MappedImage->NtHeaders->Signature != IMAGE_NT_SIGNATURE) + return STATUS_INVALID_IMAGE_FORMAT; + + MappedImage->Magic = MappedImage->NtHeaders->OptionalHeader.Magic; + + if ( + MappedImage->Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC && + MappedImage->Magic != IMAGE_NT_OPTIONAL_HDR64_MAGIC + ) + return STATUS_INVALID_IMAGE_FORMAT; + + // Get a pointer to the first section. + + MappedImage->NumberOfSections = MappedImage->NtHeaders->FileHeader.NumberOfSections; + + MappedImage->Sections = (PIMAGE_SECTION_HEADER)( + ((PCHAR)&MappedImage->NtHeaders->OptionalHeader) + + MappedImage->NtHeaders->FileHeader.SizeOfOptionalHeader + ); + + return STATUS_SUCCESS; +} + +NTSTATUS PhLoadMappedImage( + _In_opt_ PWSTR FileName, + _In_opt_ HANDLE FileHandle, + _In_ BOOLEAN ReadOnly, + _Out_ PPH_MAPPED_IMAGE MappedImage + ) +{ + NTSTATUS status; + + status = PhMapViewOfEntireFile( + FileName, + FileHandle, + ReadOnly, + &MappedImage->ViewBase, + &MappedImage->Size + ); + + if (NT_SUCCESS(status)) + { + status = PhInitializeMappedImage( + MappedImage, + MappedImage->ViewBase, + MappedImage->Size + ); + + if (!NT_SUCCESS(status)) + { + NtUnmapViewOfSection(NtCurrentProcess(), MappedImage->ViewBase); + } + } + + return status; +} + +NTSTATUS PhUnloadMappedImage( + _Inout_ PPH_MAPPED_IMAGE MappedImage + ) +{ + return NtUnmapViewOfSection( + NtCurrentProcess(), + MappedImage->ViewBase + ); +} + +NTSTATUS PhMapViewOfEntireFile( + _In_opt_ PWSTR FileName, + _In_opt_ HANDLE FileHandle, + _In_ BOOLEAN ReadOnly, + _Out_ PVOID *ViewBase, + _Out_ PSIZE_T Size + ) +{ + NTSTATUS status; + BOOLEAN openedFile = FALSE; + LARGE_INTEGER size; + HANDLE sectionHandle = NULL; + SIZE_T viewSize; + PVOID viewBase; + + if (!FileName && !FileHandle) + return STATUS_INVALID_PARAMETER_MIX; + + // Open the file if we weren't supplied a file handle. + if (!FileHandle) + { + status = PhCreateFileWin32( + &FileHandle, + FileName, + ((FILE_READ_ATTRIBUTES | FILE_READ_DATA) | + (!ReadOnly ? (FILE_APPEND_DATA | FILE_WRITE_ATTRIBUTES | FILE_WRITE_DATA) : 0)) | SYNCHRONIZE, + 0, + FILE_SHARE_READ, + FILE_OPEN, + FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT + ); + + if (!NT_SUCCESS(status)) + return status; + + openedFile = TRUE; + } + + // Get the file size and create the section. + + status = PhGetFileSize(FileHandle, &size); + + if (!NT_SUCCESS(status)) + goto CleanupExit; + + status = NtCreateSection( + §ionHandle, + SECTION_ALL_ACCESS, + NULL, + &size, + ReadOnly ? PAGE_READONLY : PAGE_READWRITE, + SEC_COMMIT, + FileHandle + ); + + if (!NT_SUCCESS(status)) + goto CleanupExit; + + // Map the section. + + viewSize = (SIZE_T)size.QuadPart; + viewBase = NULL; + + status = NtMapViewOfSection( + sectionHandle, + NtCurrentProcess(), + &viewBase, + 0, + 0, + NULL, + &viewSize, + ViewShare, + 0, + ReadOnly ? PAGE_READONLY : PAGE_READWRITE + ); + + if (!NT_SUCCESS(status)) + goto CleanupExit; + + *ViewBase = viewBase; + *Size = (SIZE_T)size.QuadPart; + +CleanupExit: + if (sectionHandle) + NtClose(sectionHandle); + if (openedFile) + NtClose(FileHandle); + + return status; +} + +VOID PhpMappedImageProbe( + _In_ PPH_MAPPED_IMAGE MappedImage, + _In_ PVOID Address, + _In_ SIZE_T Length + ) +{ + PhProbeAddress(Address, Length, MappedImage->ViewBase, MappedImage->Size, 1); +} + +PIMAGE_SECTION_HEADER PhMappedImageRvaToSection( + _In_ PPH_MAPPED_IMAGE MappedImage, + _In_ ULONG Rva + ) +{ + ULONG i; + + for (i = 0; i < MappedImage->NumberOfSections; i++) + { + if ( + (Rva >= MappedImage->Sections[i].VirtualAddress) && + (Rva < MappedImage->Sections[i].VirtualAddress + MappedImage->Sections[i].SizeOfRawData) + ) + { + return &MappedImage->Sections[i]; + } + } + + return NULL; +} + +PVOID PhMappedImageRvaToVa( + _In_ PPH_MAPPED_IMAGE MappedImage, + _In_ ULONG Rva, + _Out_opt_ PIMAGE_SECTION_HEADER *Section + ) +{ + PIMAGE_SECTION_HEADER section; + + section = PhMappedImageRvaToSection(MappedImage, Rva); + + if (!section) + return NULL; + + if (Section) + *Section = section; + + return (PVOID)( + (ULONG_PTR)MappedImage->ViewBase + + (Rva - section->VirtualAddress) + + section->PointerToRawData + ); +} + +BOOLEAN PhGetMappedImageSectionName( + _In_ PIMAGE_SECTION_HEADER Section, + _Out_writes_opt_z_(Count) PSTR Buffer, + _In_ ULONG Count, + _Out_opt_ PULONG ReturnCount + ) +{ + BOOLEAN result; + SIZE_T returnCount; + + result = PhCopyBytesZ( + Section->Name, + IMAGE_SIZEOF_SHORT_NAME, + Buffer, + Count, + &returnCount + ); + + if (ReturnCount) + *ReturnCount = (ULONG)returnCount; + + return result; +} + +NTSTATUS PhGetMappedImageDataEntry( + _In_ PPH_MAPPED_IMAGE MappedImage, + _In_ ULONG Index, + _Out_ PIMAGE_DATA_DIRECTORY *Entry + ) +{ + if (MappedImage->Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) + { + PIMAGE_OPTIONAL_HEADER32 optionalHeader; + + optionalHeader = (PIMAGE_OPTIONAL_HEADER32)&MappedImage->NtHeaders->OptionalHeader; + + if (Index >= optionalHeader->NumberOfRvaAndSizes) + return STATUS_INVALID_PARAMETER_2; + + *Entry = &optionalHeader->DataDirectory[Index]; + } + else if (MappedImage->Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) + { + PIMAGE_OPTIONAL_HEADER64 optionalHeader; + + optionalHeader = (PIMAGE_OPTIONAL_HEADER64)&MappedImage->NtHeaders->OptionalHeader; + + if (Index >= optionalHeader->NumberOfRvaAndSizes) + return STATUS_INVALID_PARAMETER_2; + + *Entry = &optionalHeader->DataDirectory[Index]; + } + else + { + return STATUS_INVALID_PARAMETER; + } + + return STATUS_SUCCESS; +} + +FORCEINLINE NTSTATUS PhpGetMappedImageLoadConfig( + _In_ PPH_MAPPED_IMAGE MappedImage, + _In_ USHORT Magic, + _In_ ULONG ProbeLength, + _Out_ PVOID *LoadConfig + ) +{ + NTSTATUS status; + PIMAGE_DATA_DIRECTORY entry; + PVOID loadConfig; + + if (MappedImage->Magic != Magic) + return STATUS_INVALID_PARAMETER; + + status = PhGetMappedImageDataEntry(MappedImage, IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG, &entry); + + if (!NT_SUCCESS(status)) + return status; + + loadConfig = PhMappedImageRvaToVa(MappedImage, entry->VirtualAddress, NULL); + + if (!loadConfig) + return STATUS_INVALID_PARAMETER; + + __try + { + PhpMappedImageProbe(MappedImage, loadConfig, ProbeLength); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + return GetExceptionCode(); + } + + *LoadConfig = loadConfig; + + return STATUS_SUCCESS; +} + +NTSTATUS PhGetMappedImageLoadConfig32( + _In_ PPH_MAPPED_IMAGE MappedImage, + _Out_ PIMAGE_LOAD_CONFIG_DIRECTORY32 *LoadConfig + ) +{ + return PhpGetMappedImageLoadConfig( + MappedImage, + IMAGE_NT_OPTIONAL_HDR32_MAGIC, + sizeof(IMAGE_LOAD_CONFIG_DIRECTORY32), + LoadConfig + ); +} + +NTSTATUS PhGetMappedImageLoadConfig64( + _In_ PPH_MAPPED_IMAGE MappedImage, + _Out_ PIMAGE_LOAD_CONFIG_DIRECTORY64 *LoadConfig + ) +{ + return PhpGetMappedImageLoadConfig( + MappedImage, + IMAGE_NT_OPTIONAL_HDR64_MAGIC, + sizeof(IMAGE_LOAD_CONFIG_DIRECTORY64), + LoadConfig + ); +} + +NTSTATUS PhLoadRemoteMappedImage( + _In_ HANDLE ProcessHandle, + _In_ PVOID ViewBase, + _Out_ PPH_REMOTE_MAPPED_IMAGE RemoteMappedImage + ) +{ + NTSTATUS status; + IMAGE_DOS_HEADER dosHeader; + ULONG ntHeadersOffset; + IMAGE_NT_HEADERS32 ntHeaders; + ULONG ntHeadersSize; + + RemoteMappedImage->ViewBase = ViewBase; + + status = NtReadVirtualMemory( + ProcessHandle, + ViewBase, + &dosHeader, + sizeof(IMAGE_DOS_HEADER), + NULL + ); + + if (!NT_SUCCESS(status)) + return status; + + // Check the initial MZ. + + if (dosHeader.e_magic != IMAGE_DOS_SIGNATURE) + return STATUS_INVALID_IMAGE_NOT_MZ; + + // Get a pointer to the NT headers and read it in for some basic information. + + ntHeadersOffset = (ULONG)dosHeader.e_lfanew; + + if (ntHeadersOffset == 0 || ntHeadersOffset >= 0x10000000) + return STATUS_INVALID_IMAGE_FORMAT; + + status = NtReadVirtualMemory( + ProcessHandle, + PTR_ADD_OFFSET(ViewBase, ntHeadersOffset), + &ntHeaders, + sizeof(IMAGE_NT_HEADERS32), + NULL + ); + + if (!NT_SUCCESS(status)) + return status; + + // Check the signature and verify the magic. + + if (ntHeaders.Signature != IMAGE_NT_SIGNATURE) + return STATUS_INVALID_IMAGE_FORMAT; + + RemoteMappedImage->Magic = ntHeaders.OptionalHeader.Magic; + + if ( + RemoteMappedImage->Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC && + RemoteMappedImage->Magic != IMAGE_NT_OPTIONAL_HDR64_MAGIC + ) + return STATUS_INVALID_IMAGE_FORMAT; + + // Get the real size and read in the whole thing. + + RemoteMappedImage->NumberOfSections = ntHeaders.FileHeader.NumberOfSections; + ntHeadersSize = FIELD_OFFSET(IMAGE_NT_HEADERS, OptionalHeader) + + ntHeaders.FileHeader.SizeOfOptionalHeader + + RemoteMappedImage->NumberOfSections * sizeof(IMAGE_SECTION_HEADER); + + if (ntHeadersSize > 1024 * 1024) // 1 MB + return STATUS_INVALID_IMAGE_FORMAT; + + RemoteMappedImage->NtHeaders = PhAllocate(ntHeadersSize); + + status = NtReadVirtualMemory( + ProcessHandle, + PTR_ADD_OFFSET(ViewBase, ntHeadersOffset), + RemoteMappedImage->NtHeaders, + ntHeadersSize, + NULL + ); + + if (!NT_SUCCESS(status)) + { + PhFree(RemoteMappedImage->NtHeaders); + return status; + } + + RemoteMappedImage->Sections = (PIMAGE_SECTION_HEADER)( + (PCHAR)RemoteMappedImage->NtHeaders + + FIELD_OFFSET(IMAGE_NT_HEADERS, OptionalHeader) + ntHeaders.FileHeader.SizeOfOptionalHeader + ); + + return STATUS_SUCCESS; +} + +NTSTATUS PhUnloadRemoteMappedImage( + _Inout_ PPH_REMOTE_MAPPED_IMAGE RemoteMappedImage + ) +{ + PhFree(RemoteMappedImage->NtHeaders); + + return STATUS_SUCCESS; +} + +NTSTATUS PhGetMappedImageExports( + _Out_ PPH_MAPPED_IMAGE_EXPORTS Exports, + _In_ PPH_MAPPED_IMAGE MappedImage + ) +{ + NTSTATUS status; + PIMAGE_EXPORT_DIRECTORY exportDirectory; + + Exports->MappedImage = MappedImage; + + // Get a pointer to the export directory. + + status = PhGetMappedImageDataEntry( + MappedImage, + IMAGE_DIRECTORY_ENTRY_EXPORT, + &Exports->DataDirectory + ); + + if (!NT_SUCCESS(status)) + return status; + + exportDirectory = PhMappedImageRvaToVa( + MappedImage, + Exports->DataDirectory->VirtualAddress, + NULL + ); + + if (!exportDirectory) + return STATUS_INVALID_PARAMETER; + + __try + { + PhpMappedImageProbe(MappedImage, exportDirectory, sizeof(IMAGE_EXPORT_DIRECTORY)); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + return GetExceptionCode(); + } + + Exports->ExportDirectory = exportDirectory; + Exports->NumberOfEntries = exportDirectory->NumberOfFunctions; + + // Get pointers to the various tables and probe them. + + Exports->AddressTable = (PULONG)PhMappedImageRvaToVa( + MappedImage, + exportDirectory->AddressOfFunctions, + NULL + ); + Exports->NamePointerTable = (PULONG)PhMappedImageRvaToVa( + MappedImage, + exportDirectory->AddressOfNames, + NULL + ); + Exports->OrdinalTable = (PUSHORT)PhMappedImageRvaToVa( + MappedImage, + exportDirectory->AddressOfNameOrdinals, + NULL + ); + + if ( + !Exports->AddressTable || + !Exports->NamePointerTable || + !Exports->OrdinalTable + ) + return STATUS_INVALID_PARAMETER; + + __try + { + PhpMappedImageProbe( + MappedImage, + Exports->AddressTable, + exportDirectory->NumberOfFunctions * sizeof(ULONG) + ); + PhpMappedImageProbe( + MappedImage, + Exports->NamePointerTable, + exportDirectory->NumberOfNames * sizeof(ULONG) + ); + PhpMappedImageProbe( + MappedImage, + Exports->OrdinalTable, // ordinal list for named exports + exportDirectory->NumberOfNames * sizeof(USHORT) + ); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + return GetExceptionCode(); + } + + // The ordinal and name tables are parallel. + // Getting an index into the name table (e.g. by doing a binary + // search) and indexing into the ordinal table will produce the + // ordinal for that name, *unbiased* (unlike in the specification). + // The unbiased ordinal is an index into the address table. + + return STATUS_SUCCESS; +} + +NTSTATUS PhGetMappedImageExportEntry( + _In_ PPH_MAPPED_IMAGE_EXPORTS Exports, + _In_ ULONG Index, + _Out_ PPH_MAPPED_IMAGE_EXPORT_ENTRY Entry + ) +{ + ULONG nameIndex = 0; + BOOLEAN exportByName = FALSE; + PSTR name; + + if (Index >= Exports->ExportDirectory->NumberOfFunctions) + return STATUS_PROCEDURE_NOT_FOUND; + + Entry->Ordinal = (USHORT)Index + (USHORT)Exports->ExportDirectory->Base; + + // look into named exports ordinal list. + for (nameIndex = 0; nameIndex < Exports->ExportDirectory->NumberOfNames; nameIndex++) + { + if (Index == Exports->OrdinalTable[nameIndex]) + { + exportByName = TRUE; + break; + } + } + + + if (exportByName) + { + name = PhMappedImageRvaToVa( + Exports->MappedImage, + Exports->NamePointerTable[nameIndex], + NULL + ); + + if (!name) + return STATUS_INVALID_PARAMETER; + + // TODO: Probe the name. + + Entry->Name = name; + } + else + { + Entry->Name = NULL; + } + + return STATUS_SUCCESS; +} + +NTSTATUS PhGetMappedImageExportFunction( + _In_ PPH_MAPPED_IMAGE_EXPORTS Exports, + _In_opt_ PSTR Name, + _In_opt_ USHORT Ordinal, + _Out_ PPH_MAPPED_IMAGE_EXPORT_FUNCTION Function + ) +{ + ULONG rva; + + if (Name) + { + ULONG index; + + index = PhpLookupMappedImageExportName(Exports, Name); + + if (index == -1) + return STATUS_PROCEDURE_NOT_FOUND; + + Ordinal = Exports->OrdinalTable[index] + (USHORT)Exports->ExportDirectory->Base; + } + + Ordinal -= (USHORT)Exports->ExportDirectory->Base; + + if (Ordinal >= Exports->ExportDirectory->NumberOfFunctions) + return STATUS_PROCEDURE_NOT_FOUND; + + rva = Exports->AddressTable[Ordinal]; + + if ( + (rva >= Exports->DataDirectory->VirtualAddress) && + (rva < Exports->DataDirectory->VirtualAddress + Exports->DataDirectory->Size) + ) + { + // This is a forwarder RVA. + + Function->ForwardedName = PhMappedImageRvaToVa( + Exports->MappedImage, + rva, + NULL + ); + + if (!Function->ForwardedName) + return STATUS_INVALID_PARAMETER; + + // TODO: Probe the name. + + Function->Function = NULL; + } + else + { + Function->Function = PhMappedImageRvaToVa( + Exports->MappedImage, + rva, + NULL + ); + Function->ForwardedName = NULL; + } + + return STATUS_SUCCESS; +} + +NTSTATUS PhGetMappedImageExportFunctionRemote( + _In_ PPH_MAPPED_IMAGE_EXPORTS Exports, + _In_opt_ PSTR Name, + _In_opt_ USHORT Ordinal, + _In_ PVOID RemoteBase, + _Out_ PVOID *Function + ) +{ + ULONG rva; + + if (Name) + { + ULONG index; + + index = PhpLookupMappedImageExportName(Exports, Name); + + if (index == -1) + return STATUS_PROCEDURE_NOT_FOUND; + + Ordinal = Exports->OrdinalTable[index] + (USHORT)Exports->ExportDirectory->Base; + } + + Ordinal -= (USHORT)Exports->ExportDirectory->Base; + + if (Ordinal >= Exports->ExportDirectory->NumberOfFunctions) + return STATUS_PROCEDURE_NOT_FOUND; + + rva = Exports->AddressTable[Ordinal]; + + if ( + (rva >= Exports->DataDirectory->VirtualAddress) && + (rva < Exports->DataDirectory->VirtualAddress + Exports->DataDirectory->Size) + ) + { + // This is a forwarder RVA. Not supported for remote lookup. + return STATUS_NOT_SUPPORTED; + } + else + { + *Function = PTR_ADD_OFFSET(RemoteBase, rva); + } + + return STATUS_SUCCESS; +} + +ULONG PhpLookupMappedImageExportName( + _In_ PPH_MAPPED_IMAGE_EXPORTS Exports, + _In_ PSTR Name + ) +{ + LONG low; + LONG high; + LONG i; + + if (Exports->ExportDirectory->NumberOfNames == 0) + return -1; + + low = 0; + high = Exports->ExportDirectory->NumberOfNames - 1; + + do + { + PSTR name; + INT comparison; + + i = (low + high) / 2; + + name = PhMappedImageRvaToVa( + Exports->MappedImage, + Exports->NamePointerTable[i], + NULL + ); + + if (!name) + return -1; + + // TODO: Probe the name. + + comparison = strcmp(Name, name); + + if (comparison == 0) + return i; + else if (comparison < 0) + high = i - 1; + else + low = i + 1; + } while (low <= high); + + return -1; +} + +NTSTATUS PhGetMappedImageImports( + _Out_ PPH_MAPPED_IMAGE_IMPORTS Imports, + _In_ PPH_MAPPED_IMAGE MappedImage + ) +{ + NTSTATUS status; + PIMAGE_DATA_DIRECTORY dataDirectory; + PIMAGE_IMPORT_DESCRIPTOR descriptor; + ULONG i; + + Imports->MappedImage = MappedImage; + Imports->Flags = 0; + + status = PhGetMappedImageDataEntry( + MappedImage, + IMAGE_DIRECTORY_ENTRY_IMPORT, + &dataDirectory + ); + + if (!NT_SUCCESS(status)) + return status; + + descriptor = PhMappedImageRvaToVa( + MappedImage, + dataDirectory->VirtualAddress, + NULL + ); + + if (!descriptor) + return STATUS_INVALID_PARAMETER; + + Imports->DescriptorTable = descriptor; + + // Do a scan to determine how many import descriptors there are. + + i = 0; + + __try + { + while (TRUE) + { + PhpMappedImageProbe(MappedImage, descriptor, sizeof(IMAGE_IMPORT_DESCRIPTOR)); + + if (descriptor->OriginalFirstThunk == 0 && descriptor->FirstThunk == 0) + break; + + descriptor++; + i++; + } + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + return GetExceptionCode(); + } + + Imports->NumberOfDlls = i; + + return STATUS_SUCCESS; +} + +NTSTATUS PhGetMappedImageImportDll( + _In_ PPH_MAPPED_IMAGE_IMPORTS Imports, + _In_ ULONG Index, + _Out_ PPH_MAPPED_IMAGE_IMPORT_DLL ImportDll + ) +{ + ULONG i; + + if (Index >= Imports->NumberOfDlls) + return STATUS_INVALID_PARAMETER_2; + + ImportDll->MappedImage = Imports->MappedImage; + ImportDll->Flags = Imports->Flags; + + if (!(ImportDll->Flags & PH_MAPPED_IMAGE_DELAY_IMPORTS)) + { + ImportDll->Descriptor = &Imports->DescriptorTable[Index]; + + ImportDll->Name = PhMappedImageRvaToVa( + ImportDll->MappedImage, + ImportDll->Descriptor->Name, + NULL + ); + + if (!ImportDll->Name) + return STATUS_INVALID_PARAMETER; + + // TODO: Probe the name. + + if (ImportDll->Descriptor->OriginalFirstThunk) + { + ImportDll->LookupTable = PhMappedImageRvaToVa( + ImportDll->MappedImage, + ImportDll->Descriptor->OriginalFirstThunk, + NULL + ); + } + else + { + ImportDll->LookupTable = PhMappedImageRvaToVa( + ImportDll->MappedImage, + ImportDll->Descriptor->FirstThunk, + NULL + ); + } + } + else + { + ImportDll->DelayDescriptor = &((PIMAGE_DELAYLOAD_DESCRIPTOR)Imports->DelayDescriptorTable)[Index]; + + ImportDll->Name = PhMappedImageRvaToVa( + ImportDll->MappedImage, + ((PIMAGE_DELAYLOAD_DESCRIPTOR)ImportDll->DelayDescriptor)->DllNameRVA, + NULL + ); + + if (!ImportDll->Name) + return STATUS_INVALID_PARAMETER; + + // TODO: Probe the name. + + ImportDll->LookupTable = PhMappedImageRvaToVa( + ImportDll->MappedImage, + ((PIMAGE_DELAYLOAD_DESCRIPTOR)ImportDll->DelayDescriptor)->ImportNameTableRVA, + NULL + ); + } + + if (!ImportDll->LookupTable) + return STATUS_INVALID_PARAMETER; + + // Do a scan to determine how many entries there are. + + i = 0; + + if (ImportDll->MappedImage->Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) + { + PULONG entry; + + entry = (PULONG)ImportDll->LookupTable; + + __try + { + while (TRUE) + { + PhpMappedImageProbe( + ImportDll->MappedImage, + entry, + sizeof(ULONG) + ); + + if (*entry == 0) + break; + + entry++; + i++; + } + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + return GetExceptionCode(); + } + } + else if (ImportDll->MappedImage->Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) + { + PULONG64 entry; + + entry = (PULONG64)ImportDll->LookupTable; + + __try + { + while (TRUE) + { + PhpMappedImageProbe( + ImportDll->MappedImage, + entry, + sizeof(ULONG64) + ); + + if (*entry == 0) + break; + + entry++; + i++; + } + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + return GetExceptionCode(); + } + } + else + { + return STATUS_INVALID_PARAMETER; + } + + ImportDll->NumberOfEntries = i; + + return STATUS_SUCCESS; +} + +NTSTATUS PhGetMappedImageImportEntry( + _In_ PPH_MAPPED_IMAGE_IMPORT_DLL ImportDll, + _In_ ULONG Index, + _Out_ PPH_MAPPED_IMAGE_IMPORT_ENTRY Entry + ) +{ + PIMAGE_IMPORT_BY_NAME importByName; + + if (Index >= ImportDll->NumberOfEntries) + return STATUS_INVALID_PARAMETER_2; + + if (ImportDll->MappedImage->Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) + { + ULONG entry; + + entry = ((PULONG)ImportDll->LookupTable)[Index]; + + // Is this entry using an ordinal? + if (entry & IMAGE_ORDINAL_FLAG32) + { + Entry->Name = NULL; + Entry->Ordinal = (USHORT)IMAGE_ORDINAL32(entry); + + return STATUS_SUCCESS; + } + else + { + importByName = PhMappedImageRvaToVa( + ImportDll->MappedImage, + entry, + NULL + ); + } + } + else if (ImportDll->MappedImage->Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) + { + ULONG64 entry; + + entry = ((PULONG64)ImportDll->LookupTable)[Index]; + + // Is this entry using an ordinal? + if (entry & IMAGE_ORDINAL_FLAG64) + { + Entry->Name = NULL; + Entry->Ordinal = (USHORT)IMAGE_ORDINAL64(entry); + + return STATUS_SUCCESS; + } + else + { + importByName = PhMappedImageRvaToVa( + ImportDll->MappedImage, + (ULONG)entry, + NULL + ); + } + } + else + { + return STATUS_INVALID_PARAMETER; + } + + if (!importByName) + return STATUS_INVALID_PARAMETER; + + __try + { + PhpMappedImageProbe( + ImportDll->MappedImage, + importByName, + sizeof(IMAGE_IMPORT_BY_NAME) + ); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + return GetExceptionCode(); + } + + Entry->Name = (PSTR)importByName->Name; + Entry->NameHint = importByName->Hint; + + // TODO: Probe the name. + + return STATUS_SUCCESS; +} + +NTSTATUS PhGetMappedImageDelayImports( + _Out_ PPH_MAPPED_IMAGE_IMPORTS Imports, + _In_ PPH_MAPPED_IMAGE MappedImage + ) +{ + NTSTATUS status; + PIMAGE_DATA_DIRECTORY dataDirectory; + PIMAGE_DELAYLOAD_DESCRIPTOR descriptor; + ULONG i; + + Imports->MappedImage = MappedImage; + Imports->Flags = PH_MAPPED_IMAGE_DELAY_IMPORTS; + + status = PhGetMappedImageDataEntry( + MappedImage, + IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT, + &dataDirectory + ); + + if (!NT_SUCCESS(status)) + return status; + + descriptor = PhMappedImageRvaToVa( + MappedImage, + dataDirectory->VirtualAddress, + NULL + ); + + if (!descriptor) + return STATUS_INVALID_PARAMETER; + + Imports->DelayDescriptorTable = descriptor; + + // Do a scan to determine how many import descriptors there are. + + i = 0; + + __try + { + while (TRUE) + { + PhpMappedImageProbe(MappedImage, descriptor, sizeof(PIMAGE_DELAYLOAD_DESCRIPTOR)); + + if (descriptor->ImportAddressTableRVA == 0 && descriptor->ImportNameTableRVA == 0) + break; + + descriptor++; + i++; + } + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + return GetExceptionCode(); + } + + Imports->NumberOfDlls = i; + + return STATUS_SUCCESS; +} + +USHORT PhCheckSum( + _In_ ULONG Sum, + _In_reads_(Count) PUSHORT Buffer, + _In_ ULONG Count + ) +{ + while (Count--) + { + Sum += *Buffer++; + Sum = (Sum >> 16) + (Sum & 0xffff); + } + + Sum = (Sum >> 16) + Sum; + + return (USHORT)Sum; +} + +ULONG PhCheckSumMappedImage( + _In_ PPH_MAPPED_IMAGE MappedImage + ) +{ + ULONG checkSum; + USHORT partialSum; + PUSHORT adjust; + + partialSum = PhCheckSum(0, (PUSHORT)MappedImage->ViewBase, (ULONG)(MappedImage->Size + 1) / 2); + + // This is actually the same for 32-bit and 64-bit executables. + adjust = (PUSHORT)&MappedImage->NtHeaders->OptionalHeader.CheckSum; + + // Subtract the existing check sum (with carry). + partialSum -= partialSum < adjust[0]; + partialSum -= adjust[0]; + partialSum -= partialSum < adjust[1]; + partialSum -= adjust[1]; + + checkSum = partialSum + (ULONG)MappedImage->Size; + + return checkSum; +} + +NTSTATUS PhGetMappedImageCfg( + _Out_ PPH_MAPPED_IMAGE_CFG CfgConfig, + _In_ PPH_MAPPED_IMAGE MappedImage + ) +{ + NTSTATUS status; + PIMAGE_LOAD_CONFIG_DIRECTORY64 config64; + + if (!NT_SUCCESS(status = PhGetMappedImageLoadConfig64(MappedImage, &config64))) + return status; + + // Not every load configuration defines CFG characteristics + if (config64->Size < (ULONG)FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY64, GuardFlags)) + return STATUS_INVALID_VIEW_SIZE; + + CfgConfig->MappedImage = MappedImage; + CfgConfig->EntrySize = sizeof(FIELD_OFFSET(IMAGE_CFG_ENTRY, Rva)) + + (ULONG)((config64->GuardFlags & IMAGE_GUARD_CF_FUNCTION_TABLE_SIZE_MASK) >> IMAGE_GUARD_CF_FUNCTION_TABLE_SIZE_SHIFT); + CfgConfig->CfgInstrumented = !!(config64->GuardFlags & IMAGE_GUARD_CF_INSTRUMENTED); + CfgConfig->WriteIntegrityChecks = !!(config64->GuardFlags & IMAGE_GUARD_CFW_INSTRUMENTED); + CfgConfig->CfgFunctionTablePresent = !!(config64->GuardFlags & IMAGE_GUARD_CF_FUNCTION_TABLE_PRESENT); + CfgConfig->SecurityCookieUnused = !!(config64->GuardFlags & IMAGE_GUARD_SECURITY_COOKIE_UNUSED); + CfgConfig->ProtectDelayLoadedIat = !!(config64->GuardFlags & IMAGE_GUARD_PROTECT_DELAYLOAD_IAT); + CfgConfig->DelayLoadInDidatSection = !!(config64->GuardFlags & IMAGE_GUARD_DELAYLOAD_IAT_IN_ITS_OWN_SECTION); + CfgConfig->EnableExportSuppression = !!(config64->GuardFlags & IMAGE_GUARD_CF_ENABLE_EXPORT_SUPPRESSION); + CfgConfig->HasExportSuppressionInfos = !!(config64->GuardFlags & IMAGE_GUARD_CF_EXPORT_SUPPRESSION_INFO_PRESENT); + CfgConfig->CfgLongJumpTablePresent = !!(config64->GuardFlags & IMAGE_GUARD_CF_LONGJUMP_TABLE_PRESENT); + + CfgConfig->NumberOfGuardFunctionEntries = config64->GuardCFFunctionCount; + CfgConfig->GuardFunctionTable = PhMappedImageRvaToVa( + MappedImage, + (ULONG)(config64->GuardCFFunctionTable - MappedImage->NtHeaders->OptionalHeader.ImageBase), + NULL + ); + + if (CfgConfig->GuardFunctionTable && CfgConfig->NumberOfGuardFunctionEntries) + { + __try + { + PhpMappedImageProbe( + MappedImage, + CfgConfig->GuardFunctionTable, + (SIZE_T)(CfgConfig->EntrySize * CfgConfig->NumberOfGuardFunctionEntries) + ); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + return GetExceptionCode(); + } + } + + CfgConfig->NumberOfGuardAdressIatEntries = 0; + CfgConfig->GuardAdressIatTable = 0; + + if ( + config64->Size >= (ULONG)FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY64, GuardAddressTakenIatEntryTable) + + sizeof(config64->GuardAddressTakenIatEntryTable) + + sizeof(config64->GuardAddressTakenIatEntryCount) + ) + { + CfgConfig->NumberOfGuardAdressIatEntries = config64->GuardAddressTakenIatEntryCount; + CfgConfig->GuardAdressIatTable = PhMappedImageRvaToVa( + MappedImage, + (ULONG)(config64->GuardAddressTakenIatEntryTable - MappedImage->NtHeaders->OptionalHeader.ImageBase), + NULL + ); + + if (CfgConfig->GuardAdressIatTable && CfgConfig->NumberOfGuardAdressIatEntries) + { + __try + { + PhpMappedImageProbe( + MappedImage, + CfgConfig->GuardAdressIatTable, + (SIZE_T)(CfgConfig->EntrySize * CfgConfig->NumberOfGuardAdressIatEntries) + ); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + return GetExceptionCode(); + } + } + } + + CfgConfig->NumberOfGuardLongJumpEntries = 0; + CfgConfig->GuardLongJumpTable = 0; + + if ( + config64->Size >= (ULONG)FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY64, GuardLongJumpTargetTable) + + sizeof(config64->GuardLongJumpTargetTable) + + sizeof(config64->GuardLongJumpTargetCount) + ) + { + CfgConfig->NumberOfGuardLongJumpEntries = config64->GuardLongJumpTargetCount; + CfgConfig->GuardLongJumpTable = PhMappedImageRvaToVa( + MappedImage, + (ULONG)(config64->GuardLongJumpTargetTable - MappedImage->NtHeaders->OptionalHeader.ImageBase), + NULL + ); + + if (CfgConfig->GuardLongJumpTable && CfgConfig->NumberOfGuardLongJumpEntries) + { + __try + { + PhpMappedImageProbe( + MappedImage, + CfgConfig->GuardLongJumpTable, + (SIZE_T)(CfgConfig->EntrySize * CfgConfig->NumberOfGuardLongJumpEntries) + ); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + return GetExceptionCode(); + } + } + } + + return STATUS_SUCCESS; +} + +NTSTATUS PhGetMappedImageCfgEntry( + _In_ PPH_MAPPED_IMAGE_CFG CfgConfig, + _In_ ULONGLONG Index, + _In_ CFG_ENTRY_TYPE Type, + _Out_ PIMAGE_CFG_ENTRY Entry + ) +{ + PULONGLONG guardTable; + ULONGLONG numberofGuardEntries; + PIMAGE_CFG_ENTRY cfgMappedEntry; + + switch (Type) + { + case ControlFlowGuardFunction: + { + guardTable = CfgConfig->GuardFunctionTable; + numberofGuardEntries = CfgConfig->NumberOfGuardFunctionEntries; + } + break; + case ControlFlowGuardtakenIatEntry: + { + guardTable = CfgConfig->GuardAdressIatTable; + numberofGuardEntries = CfgConfig->NumberOfGuardAdressIatEntries; + } + break; + case ControlFlowGuardLongJump: + { + guardTable = CfgConfig->GuardLongJumpTable; + numberofGuardEntries = CfgConfig->NumberOfGuardLongJumpEntries; + } + break; + default: + return STATUS_INVALID_PARAMETER_3; + } + + if (!guardTable || Index >= numberofGuardEntries) + return STATUS_PROCEDURE_NOT_FOUND; + + cfgMappedEntry = (PIMAGE_CFG_ENTRY)PTR_ADD_OFFSET(guardTable, Index * CfgConfig->EntrySize); + + Entry->Rva = cfgMappedEntry->Rva; + + // Optional header after the rva entry + if (CfgConfig->EntrySize > sizeof(FIELD_OFFSET(IMAGE_CFG_ENTRY, Rva))) + { + Entry->SuppressedCall = cfgMappedEntry->SuppressedCall; + Entry->Reserved = cfgMappedEntry->Reserved; + } + + return STATUS_SUCCESS; } \ No newline at end of file From f2b0ce19c67860a0a623a8faf406a3f376567055 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 27 Apr 2017 19:12:40 +1000 Subject: [PATCH 0022/2058] Fix github file encoding issues --- CHANGELOG.txt | 1336 +- COPYRIGHT.txt | 264 +- KProcessHacker/KProcessHacker.vcxproj | 276 +- KProcessHacker/devctrl.c | 1132 +- KProcessHacker/dyndata.c | 334 +- KProcessHacker/dynimp.c | 120 +- KProcessHacker/include/dyndata.h | 94 +- KProcessHacker/include/kph.h | 730 +- KProcessHacker/include/ntfill.h | 702 +- KProcessHacker/main.c | 712 +- KProcessHacker/object.c | 2586 +-- KProcessHacker/process.c | 1140 +- KProcessHacker/qrydrv.c | 476 +- KProcessHacker/resource.rc | 106 +- KProcessHacker/sign.cmd | 14 +- KProcessHacker/thread.c | 1428 +- KProcessHacker/vm.c | 898 +- LICENSE.txt | 1370 +- ProcessHacker/ProcessHacker.manifest | 96 +- ProcessHacker/ProcessHacker.rc | 5264 ++--- ProcessHacker/ProcessHacker.vcxproj | 906 +- ProcessHacker/about.c | 380 +- ProcessHacker/actions.c | 6260 +++--- ProcessHacker/affinity.c | 634 +- ProcessHacker/anawait.c | 2152 +- ProcessHacker/appsup.c | 4414 ++-- ProcessHacker/chcol.c | 850 +- ProcessHacker/chdlg.c | 720 +- ProcessHacker/chproc.c | 632 +- ProcessHacker/cmdmode.c | 904 +- ProcessHacker/colmgr.c | 1420 +- ProcessHacker/dbgcon.c | 3390 +-- ProcessHacker/extmgr.c | 452 +- ProcessHacker/findobj.c | 2036 +- ProcessHacker/gdihndl.c | 764 +- ProcessHacker/hidnproc.c | 2498 +-- ProcessHacker/hndllist.c | 1498 +- ProcessHacker/hndlprp.c | 672 +- ProcessHacker/hndlprv.c | 1440 +- ProcessHacker/hndlstat.c | 480 +- ProcessHacker/include/colmgr.h | 236 +- ProcessHacker/include/extmgr.h | 102 +- ProcessHacker/include/extmgri.h | 122 +- ProcessHacker/include/heapstruct.h | 138 +- ProcessHacker/include/hidnproc.h | 150 +- ProcessHacker/include/mainwndp.h | 1024 +- ProcessHacker/include/memsrch.h | 122 +- ProcessHacker/include/miniinfo.h | 442 +- ProcessHacker/include/miniinfop.h | 808 +- ProcessHacker/include/notifico.h | 342 +- ProcessHacker/include/phapp.h | 1506 +- ProcessHacker/include/phappres.h | 68 +- ProcessHacker/include/phapprev_in.h | 12 +- ProcessHacker/include/phplug.h | 1350 +- ProcessHacker/include/phsvc.h | 476 +- ProcessHacker/include/phsvcapi.h | 620 +- ProcessHacker/include/phsvccl.h | 310 +- ProcessHacker/include/procgrp.h | 62 +- ProcessHacker/include/procprpp.h | 692 +- ProcessHacker/include/settings.h | 458 +- ProcessHacker/include/settingsp.h | 92 +- ProcessHacker/include/sysinfo.h | 326 +- ProcessHacker/include/sysinfop.h | 878 +- ProcessHacker/infodlg.c | 430 +- ProcessHacker/itemtips.c | 1408 +- ProcessHacker/jobprp.c | 1320 +- ProcessHacker/log.c | 480 +- ProcessHacker/logwnd.c | 712 +- ProcessHacker/main.c | 2144 +- ProcessHacker/mainwnd.c | 7282 +++---- ProcessHacker/mdump.c | 932 +- ProcessHacker/memedit.c | 1072 +- ProcessHacker/memlist.c | 1836 +- ProcessHacker/memlists.c | 576 +- ProcessHacker/memprot.c | 324 +- ProcessHacker/memprv.c | 1620 +- ProcessHacker/memrslt.c | 1244 +- ProcessHacker/memsrch.c | 1462 +- ProcessHacker/miniinfo.c | 4546 ++-- ProcessHacker/modlist.c | 2024 +- ProcessHacker/modprv.c | 1178 +- ProcessHacker/mxml/mxml.h | 8 +- ProcessHacker/netlist.c | 1594 +- ProcessHacker/netprv.c | 1992 +- ProcessHacker/netstk.c | 480 +- ProcessHacker/notifico.c | 2690 +-- ProcessHacker/ntobjprp.c | 1514 +- ProcessHacker/options.c | 2530 +-- ProcessHacker/pagfiles.c | 318 +- ProcessHacker/pcre/pcre2_compile.c | 18172 ++++++++-------- ProcessHacker/pcre/pcre2_match.c | 4 +- ProcessHacker/pcre/pcre2posix.c | 4 +- ProcessHacker/phsvc/clapi.c | 2434 +-- ProcessHacker/phsvc/svcapi.c | 2892 +-- ProcessHacker/phsvc/svcapiport.c | 636 +- ProcessHacker/phsvc/svcclient.c | 318 +- ProcessHacker/phsvc/svcmain.c | 222 +- ProcessHacker/plugin.c | 2086 +- ProcessHacker/plugman.c | 890 +- ProcessHacker/procgrp.c | 686 +- ProcessHacker/procprp.c | 1448 +- ProcessHacker/procprv.c | 5958 ++--- ProcessHacker/procrec.c | 524 +- ProcessHacker/proctree.c | 7016 +++--- ProcessHacker/resource.h | 1502 +- ProcessHacker/runas.c | 2334 +- ProcessHacker/sdk/phdk.h | 52 +- ProcessHacker/sdk/readme.txt | 74 +- ProcessHacker/sessmsg.c | 320 +- ProcessHacker/sessprp.c | 474 +- ProcessHacker/sessshad.c | 478 +- ProcessHacker/settings.c | 2396 +- ProcessHacker/srvcr.c | 452 +- ProcessHacker/srvctl.c | 824 +- ProcessHacker/srvlist.c | 1808 +- ProcessHacker/srvprp.c | 1148 +- ProcessHacker/srvprv.c | 2082 +- ProcessHacker/sysinfo.c | 4108 ++-- ProcessHacker/thrdlist.c | 1446 +- ProcessHacker/thrdprv.c | 2230 +- ProcessHacker/thrdstk.c | 1394 +- ProcessHacker/tokprp.c | 3936 ++-- ProcessHacker/version.rc | 70 +- phlib/apiimport.c | 136 +- phlib/basesup.c | 11970 +++++----- phlib/circbuf.c | 44 +- phlib/circbuf_i.h | 242 +- phlib/colorbox.c | 460 +- phlib/cpysave.c | 1148 +- phlib/data.c | 438 +- phlib/dspick.c | 502 +- phlib/emenu.c | 1714 +- phlib/error.c | 184 +- phlib/extlv.c | 1468 +- phlib/fastlock.c | 768 +- phlib/filepool.c | 3022 +-- phlib/format.c | 554 +- phlib/format_i.h | 1136 +- phlib/global.c | 478 +- phlib/graph.c | 2670 +-- phlib/guisup.c | 2748 +-- phlib/handle.c | 2194 +- phlib/hexedit.c | 3736 ++-- phlib/hndlinfo.c | 3552 +-- phlib/icotobmp.c | 384 +- phlib/include/apiimport.h | 172 +- phlib/include/circbuf.h | 52 +- phlib/include/circbuf_h.h | 280 +- phlib/include/colorbox.h | 60 +- phlib/include/cpysave.h | 156 +- phlib/include/dltmgr.h | 70 +- phlib/include/dspick.h | 96 +- phlib/include/emenu.h | 438 +- phlib/include/fastlock.h | 186 +- phlib/include/filepool.h | 392 +- phlib/include/filepoolp.h | 408 +- phlib/include/graph.h | 510 +- phlib/include/guisupp.h | 86 +- phlib/include/handlep.h | 294 +- phlib/include/hexedit.h | 98 +- phlib/include/hexeditp.h | 402 +- phlib/include/kphapi.h | 480 +- phlib/include/kphuser.h | 600 +- phlib/include/ph.h | 22 +- phlib/include/phbase.h | 72 +- phlib/include/phintrnl.h | 98 +- phlib/include/phnet.h | 278 +- phlib/include/phsup.h | 1092 +- phlib/include/queuedlock.h | 698 +- phlib/include/ref.h | 618 +- phlib/include/refp.h | 350 +- phlib/include/secedit.h | 328 +- phlib/include/seceditp.h | 186 +- phlib/include/symprv.h | 606 +- phlib/include/symprvp.h | 338 +- phlib/include/templ.h | 14 +- phlib/include/treenew.h | 1344 +- phlib/include/treenewp.h | 1598 +- phlib/include/verify.h | 154 +- phlib/include/verifyp.h | 236 +- phlib/kph.c | 2204 +- phlib/kphdata.c | 658 +- phlib/maplib.c | 804 +- phlib/md5.c | 450 +- phlib/native.c | 12924 +++++------ phlib/phlib.vcxproj | 496 +- phlib/provider.c | 940 +- phlib/queuedlock.c | 2404 +- phlib/ref.c | 1508 +- phlib/secdata.c | 1576 +- phlib/secedit.c | 1154 +- phlib/sha.c | 344 +- phlib/svcsup.c | 1108 +- phlib/symprv.c | 3520 +-- phlib/sync.c | 992 +- phlib/treenew.c | 13290 +++++------ phlib/verify.c | 1342 +- phlib/workqueue.c | 1012 +- plugins/DotNetTools/CHANGELOG.txt | 50 +- plugins/DotNetTools/DotNetTools.rc | 364 +- plugins/DotNetTools/DotNetTools.vcxproj | 206 +- plugins/DotNetTools/asmpage.c | 2628 +-- plugins/DotNetTools/clr/dbgappdomain.h | 276 +- plugins/DotNetTools/clr/ipcenums.h | 152 +- plugins/DotNetTools/clr/ipcheader.h | 1088 +- plugins/DotNetTools/clr/ipcshared.h | 112 +- plugins/DotNetTools/clr/perfcounterdefs.h | 664 +- plugins/DotNetTools/clretw.h | 292 +- plugins/DotNetTools/clrsup.c | 1150 +- plugins/DotNetTools/clrsup.h | 1290 +- plugins/DotNetTools/counters.c | 1858 +- plugins/DotNetTools/dn.h | 288 +- plugins/DotNetTools/main.c | 670 +- plugins/DotNetTools/resource.h | 52 +- plugins/DotNetTools/stackext.c | 642 +- plugins/DotNetTools/svcext.c | 418 +- plugins/DotNetTools/svcext.h | 172 +- plugins/DotNetTools/treeext.c | 592 +- plugins/ExtendedNotifications/CHANGELOG.txt | 22 +- .../ExtendedNotifications.rc | 428 +- .../ExtendedNotifications.vcxproj | 196 +- plugins/ExtendedNotifications/extnoti.h | 60 +- plugins/ExtendedNotifications/filelog.c | 158 +- .../gntp-send/LICENSE.txt | 50 +- .../ExtendedNotifications/gntp-send/growl.c | 1074 +- .../ExtendedNotifications/gntp-send/growl.h | 66 +- plugins/ExtendedNotifications/gntp-send/md5.h | 52 +- plugins/ExtendedNotifications/gntp-send/tcp.c | 370 +- plugins/ExtendedNotifications/gntp-send/tcp.h | 28 +- plugins/ExtendedNotifications/main.c | 2224 +- plugins/ExtendedNotifications/resource.h | 66 +- plugins/ExtendedServices/CHANGELOG.txt | 76 +- plugins/ExtendedServices/ExtendedServices.rc | 698 +- .../ExtendedServices/ExtendedServices.vcxproj | 148 +- plugins/ExtendedServices/depend.c | 688 +- plugins/ExtendedServices/extsrv.h | 256 +- plugins/ExtendedServices/main.c | 960 +- plugins/ExtendedServices/options.c | 146 +- plugins/ExtendedServices/other.c | 1462 +- plugins/ExtendedServices/recovery.c | 1418 +- plugins/ExtendedServices/resource.h | 146 +- plugins/ExtendedServices/srvprgrs.c | 300 +- plugins/ExtendedServices/trigger.c | 3440 +-- plugins/ExtendedServices/triggpg.c | 364 +- plugins/ExtendedTools/CHANGELOG.txt | 134 +- plugins/ExtendedTools/ExtendedTools.rc | 1086 +- plugins/ExtendedTools/ExtendedTools.vcxproj | 234 +- plugins/ExtendedTools/d3dkmt.h | 992 +- plugins/ExtendedTools/disktab.c | 2344 +- plugins/ExtendedTools/disktabp.h | 348 +- plugins/ExtendedTools/etwdisk.c | 1072 +- plugins/ExtendedTools/etwmini.c | 528 +- plugins/ExtendedTools/etwmini.h | 74 +- plugins/ExtendedTools/etwmon.c | 1124 +- plugins/ExtendedTools/etwmon.h | 280 +- plugins/ExtendedTools/etwprprp.c | 1228 +- plugins/ExtendedTools/etwstat.c | 838 +- plugins/ExtendedTools/etwsys.c | 1622 +- plugins/ExtendedTools/etwsys.h | 180 +- plugins/ExtendedTools/exttools.h | 1098 +- plugins/ExtendedTools/gpumini.c | 258 +- plugins/ExtendedTools/gpumini.h | 40 +- plugins/ExtendedTools/gpumon.c | 1650 +- plugins/ExtendedTools/gpumon.h | 86 +- plugins/ExtendedTools/gpunodes.c | 860 +- plugins/ExtendedTools/gpuprprp.c | 1532 +- plugins/ExtendedTools/gpusys.c | 1444 +- plugins/ExtendedTools/gpusys.h | 158 +- plugins/ExtendedTools/iconext.c | 932 +- plugins/ExtendedTools/main.c | 1232 +- plugins/ExtendedTools/modsrv.c | 346 +- plugins/ExtendedTools/objprp.c | 624 +- plugins/ExtendedTools/options.c | 174 +- plugins/ExtendedTools/procicon.c | 190 +- plugins/ExtendedTools/resource.h | 228 +- plugins/ExtendedTools/thrdact.c | 128 +- plugins/ExtendedTools/treeext.c | 1566 +- plugins/ExtendedTools/unldll.c | 714 +- plugins/ExtendedTools/utils.c | 96 +- plugins/ExtendedTools/wswatch.c | 1142 +- plugins/NetworkTools/CHANGELOG.txt | 64 +- plugins/NetworkTools/NetworkTools.rc | 1446 +- plugins/NetworkTools/NetworkTools.vcxproj | 794 +- plugins/NetworkTools/main.c | 1462 +- plugins/NetworkTools/nettools.h | 660 +- plugins/NetworkTools/options.c | 160 +- plugins/NetworkTools/ping.c | 1218 +- plugins/NetworkTools/resource.h | 564 +- plugins/NetworkTools/tracert.c | 1542 +- plugins/NetworkTools/whois.c | 1206 +- plugins/OnlineChecks/CHANGELOG.txt | 58 +- plugins/OnlineChecks/OnlineChecks.rc | 302 +- plugins/OnlineChecks/OnlineChecks.vcxproj | 200 +- plugins/OnlineChecks/main.c | 1704 +- plugins/OnlineChecks/onlnchk.h | 538 +- plugins/OnlineChecks/resource.h | 42 +- plugins/OnlineChecks/upload.c | 2674 +-- plugins/Plugins.sln | 330 +- plugins/SamplePlugin/SamplePlugin.sln | 52 +- plugins/SamplePlugin/SamplePlugin.vcxproj | 342 +- plugins/SamplePlugin/main.c | 522 +- plugins/SbieSupport/SbieSupport.rc | 292 +- plugins/SbieSupport/SbieSupport.vcxproj | 128 +- plugins/SbieSupport/main.c | 1110 +- plugins/SbieSupport/resource.h | 36 +- plugins/SbieSupport/sbiedll.h | 84 +- plugins/ToolStatus/CHANGELOG.txt | 126 +- plugins/ToolStatus/ToolStatus.rc | 554 +- plugins/ToolStatus/ToolStatus.vcxproj | 230 +- plugins/ToolStatus/customizesb.c | 1264 +- plugins/ToolStatus/customizetb.c | 1884 +- plugins/ToolStatus/filter.c | 1340 +- plugins/ToolStatus/graph.c | 1322 +- plugins/ToolStatus/main.c | 2888 +-- plugins/ToolStatus/options.c | 194 +- plugins/ToolStatus/resource.h | 114 +- plugins/ToolStatus/searchbox.c | 94 +- plugins/ToolStatus/statusbar.c | 1160 +- plugins/ToolStatus/toolbar.c | 1702 +- plugins/ToolStatus/toolstatus.h | 762 +- plugins/Updater/CHANGELOG.txt | 90 +- plugins/Updater/Updater.vcxproj | 198 +- plugins/UserNotes/CHANGELOG.txt | 48 +- plugins/UserNotes/UserNotes.rc | 364 +- plugins/UserNotes/UserNotes.vcxproj | 178 +- plugins/UserNotes/db.c | 894 +- plugins/UserNotes/db.h | 184 +- plugins/UserNotes/main.c | 3782 ++-- plugins/UserNotes/resource.h | 50 +- plugins/WindowExplorer/CHANGELOG.txt | 42 +- plugins/WindowExplorer/WindowExplorer.rc | 616 +- plugins/WindowExplorer/WindowExplorer.vcxproj | 186 +- plugins/WindowExplorer/hook.c | 1018 +- plugins/WindowExplorer/main.c | 650 +- plugins/WindowExplorer/resource.h | 164 +- plugins/WindowExplorer/utils.c | 208 +- plugins/WindowExplorer/wnddlg.c | 2384 +- plugins/WindowExplorer/wndexp.h | 270 +- plugins/WindowExplorer/wndprp.c | 2420 +- plugins/WindowExplorer/wndtree.c | 1142 +- plugins/WindowExplorer/wndtree.h | 196 +- plugins/include/toolstatusintf.h | 98 +- plugins/readme.txt | 4 +- tests/phlib-test/main.c | 32 +- tests/phlib-test/phlib-test.vcxproj | 230 +- tests/phlib-test/t_basesup.c | 704 +- tests/phlib-test/t_format.c | 1022 +- tests/phlib-test/tests.h | 44 +- tools/GenerateZw/GenerateZw.sln | 44 +- tools/GenerateZw/GenerateZw/GenerateZw.csproj | 120 +- tools/fixlib/fixlib.c | 226 +- tools/fixlib/fixlib.vcxproj | 216 +- tools/peview/include/peview.h | 78 +- tools/peview/libprp.c | 362 +- tools/peview/main.c | 256 +- tools/peview/misc.c | 204 +- tools/peview/peprp.c | 2816 +-- tools/peview/peview.manifest | 90 +- tools/peview/peview.rc | 480 +- tools/peview/peview.vcxproj | 440 +- tools/peview/resource.h | 80 +- tools/peview/version.rc | 70 +- 362 files changed, 190721 insertions(+), 190721 deletions(-) diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 493211cc7e7d..a2a8cbddb6e7 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -1,668 +1,668 @@ -Process Hacker - -3.0 - * HIGHLIGHTS: - * New Process Hacker setup. - * New process properties handle search. - * Added F11 hotkey for fullscreen System Information window. - * OTHER CHANGES: -* Updated Updater plugin: - * New design and layout. -* Updated WindowExplorer plugin: - * Added Windows process properties page. - * NOTE: - * Support for Windows XP and Vista has been dropped. For those platforms, use Process Hacker 2.38. - * This release has significant internal code changes. Please make sure all plugins are up-to-date. - -2.39 - * HIGHLIGHTS: - * Improved compatibility with security and anti-cheat software - * Added ability to edit process environment variables - * Fixed .NET process detection - * OTHER CHANGES: - * Improved tooltip information for dllhost.exe - * Removed Terminator - * Updated DotNetTools plugin: - * Fixed .NET assembly tab performance issues - * Added extra .NET memory counters to the .NET performance tab - * Added "Show sizes in bytes" checkbox to the .NET performance tab - * Added right-click menu to the .NET assembly tab - * Updated ExtendedTools plugin: - * Fixed "No process" disk event bug - * Updated HardwareDevices plugin: - * Fixed incorrect drive letters - * Fixed drive letter and panel clipping issue - -2.38 - * HIGHLIGHTS: - * Added labels to indicate the maximum data point in each I/O graph - * Graph grids now scale correctly when resized - * Improved high DPI scaling - * Added exploit mitigation policy information to process properties (Windows 8 and above) - * Added File modified time and File size columns for processes and modules - * Added Key modified time column for services - * Clicking a tray icon now shows the pop-up UI (useful for touch-enabled devices) - * The NetAdapters plugin has been renamed to HardwareDevices - * This plugin shows network adapter and disk drive graphs - * If you are manually upgrading, please delete NetAdapters.dll from the plugins folder - * Updated UserNotes plugin: - * Added "Collapse by default" option for processes - * OTHER CHANGES: - * Added "Start when I log on" option - * Added "Not responding" text to tray icon rich pop-up for programs that are hung - * Added right-click menu and double-click action for environment variables - * Added dialog box to show long command line strings - * Added Time stamp column for processes - * Added -sysinfo command line parameter for opening System Information at startup - * Added 32x32 icons for high DPI displays - * Digital signature verification is now performed with very low I/O priority - * Improved performance when handling a large number of threads, modules or handles - * The pop-up UI no longer displays when double-clicking the tray icon - * Fixed ASLR state being shown as N/A in process properties - * Fixed multi monitor window placement bug - * Fixed handle enumeration bug affecting processes with PID >= 65536 - * Fixed Interrupts being missing from the max CPU usage history - * Updated ToolStatus plugin: - * Added 32x32 icons for high DPI displays - * Fixed status bar crash - * NOTE: - * This release has significant internal code changes. Please make sure all plugins are up-to-date. - -2.37 - * HIGHLIGHTS: - * Updated for Windows 10 - * The "Include CPU (and other) usage of children in collapsed processes" option now aggregates memory and I/O statistics - * Added regex search to "Find Handles or DLLs" - * Added process exit codes to log - * Fixed crash that occurred under some conditions when processes terminated - * OTHER CHANGES: - * Added warning when trying to search for handles when the system has too many handles open - * Upgraded to PCRE2 - * Updated DotNetTools plugin: - * Rewrite of .NET Performance statistics and AppDomain enumeration - * Updated OnlineChecks plugin: - * Fixed virusscan.jotti.org uploader - * Updated NetAdapters plugin: - * Added adapter details window - * Updated ToolStatus plugin: - * Added CPU, Memory and I/O graphs to the toolbar (not enabled by default) - * Added toolbar and status bar customization, as well as a new theme - * Added option to auto-hide the main menu - * Updated UserNotes plugin: - * Added individual process highlighting support - -2.36 - * HIGHLIGHTS: - * New rich pop-up UI when hovering the cursor over a tray icon, showing the most active processes - * Completely new Memory tab for processes, with heap, stack and working set usage - * Process Hacker now takes 32-bit dumps of 32-bit processes on 64-bit Windows - * NOTE: When using the portable (.zip) release, the entire archive must be extracted - * Updated DotNetTools plugin: - * Process Hacker now displays managed stack traces for 32-bit .NET processes on 64-bit Windows - * Fixed inaccurate stack traces when clicking Refresh - * Added AppDomain column for threads in .NET programs - * OTHER CHANGES: - * Added customizable bytes per row setting for memory editor - * Dramatically faster handle listing and search when running without administrative privileges - * Improved accuracy and speed of symbol resolution, especially when new modules are loaded - * Added trigger and delayed start information to service list - * Added file information to service list tooltips - * Balloon tips for process/service notifications are now clickable - * Added handle names for unnamed File objects - * Added I/O Priority to tray icon process menu - * Added warning for users who attempt to start the 32-bit version on 64-bit Windows - * Updated ExtendedServices plugin: - * Added service protection and SID information - * Added auto-elevation when saving recovery information, triggers and other service settings - * Updated ExtendedTools plugin: - * Added tray icon mini info window support - * Improved automatic GPU node selection - * Updated UserNotes plugin: - * Added tray icon mini info window support - * Fixed a bug in phsvc that caused hangs when automatically elevating actions - * Fixed hang when viewing handle security for certain File objects - * Fixed lack of information on startup when using slower refresh intervals - * Fixed Read/Write Address crash - * Fixed service non-polling mode on Windows 8 and above - * Fixed file dialog crash in Windows PE environments - * Fixed string scanning false positive case - * Fixed process window detection for Modern UI apps - * Fixed handle list selection bug when disabling "Hide unnamed handles" - * NOTE: - * This release has significant internal code changes. Please make sure all plugins are up-to-date. - -2.35 - * NEW/IMPROVED: - * Added Load Time and Load Reason columns for modules (Windows 8 and above) - * Added handle names for Job and Section objects - * Added Read/Write Memory for Section objects (in process Handles tab) - * Added CF Guard (Control Flow Guard) column for processes and modules - * Added highlighting for AppContainer DLLs - * Added AppContainer and CF Guard image characteristics to peview - * Added Open Key and Open File Location menu items for services - * Set priority and I/O priority for multiple processes at once - * Support for up to 64 processors when setting process/thread affinity - * Updated ExtendedTools plugin: - * Added Disk and Network graphs for all processes - * Updated UserNotes plugin: - * Added ability to save I/O priority - * FIXED: - * Fixed memory editor copy bug - -2.34 - * NEW/IMPROVED: - * Proper Unicode support - * CPU and GPU graphs are displayed in a grid now (thanks pavel_kv!) - * Start Task Manager now elevates when necessary - * Better names for memory regions in Memory tab (for PEBs, TEBs, thread stacks) - * Added tooltip information for user-mode driver framework (UMDF) host processes - * Added option to reduce row height (set ThinRows to 1 in settings.xml) - * Added NetAdapters plugin: adds graphs for selected network adapters to the System Information window - * Updated ExtendedTools plugin: - * Added GPU graphs for all processes - * Can now use the search box in the Disk tab - * Improved kernel logger handling - * FIXED: - * Fixed touch scrolling - * Fixed EtwRegistration object names for 64-bit Windows 8.1 - * Fixed tray icons being clipped in high DPI environments - * Fixed crash in memory editor - * Fixed multi monitor window placement bug - -2.33 - * NEW/IMPROVED: - * View digital signature information from process properties and peview - * Signatures for Windows 8 apps are now detected - * Improved file, key, process and thread handle properties - * Added DPI Awareness column - * Added new Windows 8.1 process protection information - * KProcessHacker is no longer needed for highlighting of GUI threads - * Added suspend count for threads on Windows 8.1 - * Updated DotNetTools plugin: - * Improved .NET assembly enumeration timeout handling - * FIXED: - * Service start type and error control are never updated if modified outside of Process Hacker - -2.32 - * NOTE: - * All executable files are now signed. - * NEW/IMPROVED: - * Updated for Windows 8.1 - * Added progress display for thread stacks - * Updated ExtendedServices plugin: - * Added new trigger data types - * Updated NetworkTools plugin: - * Updated UI - * Updated OnlineChecks plugin: - * Added file analyzed prompt - * FIXED: - * Fixed handling of long symbol names - * Fixed Run As preventing Windows 8 apps from starting - * Fixed console host information for Windows 8.1 - * Fixed reflected processes not terminating on Windows 8.1 - * Fixed CPU frequency on Windows 8.1 - -2.31 - * NEW/IMPROVED: - * Updated ExtendedServices plugin: - * Fixed some bugs relating to Windows 8 - * Updated OnlineChecks plugin: - * Added upload progress - * Updated UserNotes plugin: - * Fixed bug where process priorities were not actually saved - * FIXED: - * Fixed module list not updating properly - * DLL enumeration crash - -2.30 - * NEW/IMPROVED: - * Added "Icon click toggles visibility" option - * Re-enabled powerful process termination on 32-bit Windows 8 - * Updated UserNotes plugin: - * Added ability to save process priority - * Added "Only for processes with the same command line" option for process comments - * FIXED: - * Fixed crash on CPUs without SSE2 - -2.29 - * NEW/IMPROVED: - * Added App ID column for processes - * Added new ASLR information for Windows 8 - * Added Restart to Boot Options and Hybrid Shutdown menu items for Windows 8 - * Added ability to specify processes by their names and inject and unload DLLs in command line - * Removed 512 character limit when copying text - * Moved Terminator to Miscellaneous menu - * Updated default dbghelp.dll path for Windows SDK v8 - * Updated ExtendedServices plugin: - * Added new triggers for Windows 8 - * Fixed bug when restarting services - * Updated ExtendedTools plugin: - * Improved support for multiple GPUs (again) - * GPU column now respects "Include CPU usage of children" option - * Updated ToolStatus plugin: - * Fixed search box fonts - * Fixed controls not being properly hidden/removed from the window when disabled - * Updated WindowExplorer plugin: - * Fixed window list not displaying Modern UI windows - * FIXED: - * Fixed Load Count column sorting bug - * Fixed signature verification on Windows 8 - * Fixed task scheduler information on Windows 8 - * Fixed drag bug in tree list - * Fixed KProcessHacker bug affecting TmTx objects - * Fixed Run As feature on Windows 8 - * Fixed bug where -settings parameter is not propagated - * Fixed tab key behavior on main window - * Fixed recognition of Modern UI windows - -2.28 - * NEW/IMPROVED: - * peview now resolves .lnk targets - * Fixed Ctrl+A for processes, services and network connections and added Ctrl+A for other windows - * Changed confirmation prompts to select the destructive action by default - * Updated DotNetTools plugin: - * Fixed inaccurate stack traces for certain .NET programs - * Updated ExtendedTools plugin: - * Fixed network graph scaling - * Updated ToolStatus plugin: - * Added search box - * Updated Updater plugin - * FIXED: - * Fixed Verification Status column sorting bug in module list - * Fixed rare System Information crash - * Fixed bug in opening process handles - * Fixed freezing when viewing stack traces of certain system threads - -2.27 - * NEW/IMPROVED: - * Updated OnlineChecks plugin: - * 2012-01-16: Updated VirusTotal uploader and added hash checking - * FIXED: - * Fixed Description column sorting bug - * Fixed notification icon bug - -2.26 - * NEW/IMPROVED: - * Added option to show Commit Charge in system information summary view - * Added -priority and -selectpid command line options - * Updated ExtendedTools plugin: - * Improved support for multiple GPUs - * FIXED: - * Fixed 100% CPU when starting on some machines - -2.25 - * NEW/IMPROVED: - * Improved CPU frequency calculation - * Updated ExtendedTools plugin: - * Added GPU node selection - * Fixed incorrect GPU usage calculation - * FIXED: - * Graph tooltip position with large cursors - * Fixed .NET process detection - * Fixed incorrect values in Bits column - -2.24 - * NOTE: - * This release has significant internal code changes. Please make sure all plugins are up-to-date. - * NEW/IMPROVED: - * Completely new system information window - * Added option to scroll to new processes - * Added option to hide driver services - * Added menu item to copy individual cells - * Improved module scanning - * Added Start Task Manager menu item - * Added Image base to peview - * Updated ExtendedTools plugin: - * Added support for new system information window - * Added Disk, Network and GPU tray icons - * Added support for custom fonts in the Disk tab - * Updated Updater plugin: - * Added download speed - * Added remaining time - * FIXED: - * Fixed retrieval of version information for certain files - * Fixed driver file names on Windows XP - * Fixed Run As Administrator when used with complex commands - -2.23 - * NEW/IMPROVED: - * Added display of token capabilities, user/device claims and security attributes - * Added ability to change token integrity levels - * Added Description column to service list - * Added option to reset all settings - * Made grid color darker - * Enabled multi-selection in the hidden processes window - * Added UserNotes plugin - * Updated ExtendedNotifications plugin: - * Added Growl support - * Updated ExtendedTools plugin: - * Added GPU monitoring - * Added rate columns for disk and network I/O - * FIXED: - * Fixed copying lists when plugin columns are enabled - * Freezing when viewing the tooltip for a process with a very long command line - * Disabled Hidden Processes feature on 64-bit systems - -2.22 - * NEW/IMPROVED: - * Added highlighting for metro style apps - * Added Package Name column - * Added package name to process tooltip - * Improved .NET process detection - * Updated OS Context column for Windows 8 - * Updated ExtendedTools plugin: - * Updated disk monitoring for Windows 8 - * Updated memory list information for Windows 8 - * Updated WindowExplorer plugin: - * Fixed hook support for low integrity processes - * FIXED: - * Fixed memory leaks - * Fixed bug preventing Interrupts/DPCs from being shown as the max. CPU process on 64-bit systems - * Fixed DEP Status column on 64-bit systems - -2.21 - * NEW/IMPROVED: - * Added Private Bytes Delta, ASLR and Subsystem columns - * Added ASLR and Time Stamp columns to modules list - * Added check for debugger in Terminator - * FIXED: - * Fixed Show CPU Below 0.01 not respecting locale - * Fixed copying from network list - -2.20 - * NEW/IMPROVED: - * Added support for managed thread stacks on x64 - * Added column selection for handle list - * Added CPU column to threads list - * Improved module detection - * Added Ideal Processor to Threads tab - * Added pool usage and minimum/maximum working set columns - * Implemented Properties button for Thread handles - * Set descending sort as the default for most numeric columns - * Extended header context menu - * Removed tooltip text truncation - * Improved cycle-based CPU usage calculation - * Set default KProcessHacker security level to only allow connections when Process Hacker is running as administrator. - See README.txt for instructions on how to restore the old behavior. - * Added Updater plugin - * Updated DotNetTools plugin: - * Added managed symbol resolution for thread stacks - * Updated ExtendedTools plugin: - * Added Disk tab - * Added Hard Faults, Hard Faults Delta and Peak Threads columns to process tree list - * Added Firewall Status column - * FIXED: - * Fixed file name resolution bug - * Save settings on shutdown/logoff - * Fixed state highlighting bug - * Fixed command line propagation for -elevate - * Fixed tree list mouse wheel handling - * Fixed saving network list - -2.19 - * NEW/IMPROVED: - * Added cycle-based CPU usage for Windows 7 - * Added Show CPU Below 0.01 - * Added OS Context column - * Rewrote graph drawing code for improved performance - * Optimized retrieval of cycle time and private working set information for Windows 7 - * Added Open File Location to process context menu and reorganized some items - * Added checkboxes to Terminator - * FIXED: - * Crash when sorting by Time Stamp - * GDI handle leak in drag selection - -2.18 - * NEW/IMPROVED: - * Completely rewritten tree list control: - * Process Name column is now fixed to the left - * Tooltips for column headers - * Improved performance - * Bug fixes - * Added more process tree list columns - * Added Time stamp column to network list - * Date/time display is now swapped (so time is shown before date) - * Added W3 terminator test - * Added DotNetTools plugin - * Updated ExtendedServices plugin: - * Disabled editing of required privileges for drivers - * Updated ExtendedTools plugin: - * Added ETW columns for processes and network connections - * Updated OnlineChecks plugin: - * Added Comodo Instant Malware Analysis - * Updated WindowExplorer plugin: - * Fixed hook bugs - * FIXED: - * Fixed Run As This User - * Verification Status sorting - -2.17 - * NEW/IMPROVED: - * Added support for setting page priority - * Added elevation support for setting priority - * Added support for automatically using a settings file in the program directory (e.g. ProcessHacker.exe.settings.xml) - * Improved Run As mechanism - * Updated ExtendedServices plugin: - * Added support for editing triggers - * Added support for editing preshutdown time-out - * Added support for editing required privileges - * Added elevation support for restarting services - * Updated WindowExplorer plugin: - * Added more window properties - * FIXED: - * Handle leak - -2.16 - * NEW/IMPROVED: - * Updated WindowExplorer plugin - * PE viewer: Added version string to CLR tab - * PE viewer: Added display of delay imports - * PE viewer: Added Load Config tab - * Improved wait analysis - * Added arrows to the service list to indicate whether a service is running - * FIXED: - * Fixed the IPv6-related workaround causing crashes - * Incorrect handling of window positions - -2.15 - * NEW/IMPROVED: - * Updated ExtendedServices plugin - * Updated ToolStatus plugin - * Added DEP Status column - * Improved User Name column - * FIXED: - * Image file versions - * Workaround for an IPv6-related bug in Windows XP - * DPCs and Interrupts in System Information tooltips - * File dialog crash on Windows XP - * ExtendedTools plugin: WS Watch refresh bug - -2.14 - * NEW/IMPROVED: - * ExtendedServices plugin: Option to add a Services menu for processes - * Command line support for setting process priority and I/O priority - * Improved termination of explorer.exe - * FIXED: - * Icon should restore the main window if it is minimized - * System Information window crashes - * Hide Processes From Other Users and Hide Signed Processes settings are now saved - * Font selection on Windows XP - * ToolStatus plugin: Always on Top status being reset by Find Window - * Service-related crashes - * WindowExplorer plugin: sorting in tree list - * Process minidump creation with old versions of dbghelp.dll - -2.13 - * NEW/IMPROVED: - * Added copy support to PE viewer - * Added Connect Time, Disconnect Time and Last Input Time to session properties - * Added more working set counters to the Statistics tab - * FIXED: - * Column sort arrows - * CPU usage calculations - -2.12 - * NEW/IMPROVED: - * Updated KProcessHacker for Windows 7 SP1 - * Added elevation support for more actions - * Added ability to disable plugins - * Updated ToolStatus plugin - * Added Remote Control for sessions - * More command line options - * FIXED: - * Memory leaks - * Run As issues with different sessions - -2.11 - * NEW/IMPROVED: - * Added WS Watch and other features to ExtendedTools plugin - * Added WindowExplorer plugin - * Properties for hidden processes - * Improved menus - * Debug console can now be closed without affecting the entire program - * FIXED: - * Always on Top issues - * Hang when setting DEP status of a terminating process - * Encoding bug in NetworkTools plugin - * LSA interfacing issues - * Creating dumps of self - -2.10 - * NEW/IMPROVED: - * KProcessHacker is now signed, so it works on 64-bit systems. Thank you to the ReactOS Foundation. - * Added Run As Limited User - * Added CPU, private bytes and I/O history columns - * Added font selection - * Slightly improved highlighting configuration - * FIXED: - * High DPI support - * Multi-monitor support in graph tooltips - * DEP status retrieval - * ExtendedTools plugin crash - * Notification icon menu crash - * Memory leaks - * Other small bug fixes - -2.9 - * NEW/IMPROVED: - * Added column selection for modules list - * Added wait analysis for 64-bit systems - * Added signature verification for modules - * Added ExtendedTools plugin (Vista and above only) with Disk and Network information - * Updated ExtendedNotifications plugin: added ability to log events to a file - * Updated ExtendedServices plugin: new tab on Vista and above - * Updated ToolStatus plugin: resolves ghost windows to hung windows - * Environment variables and current directory are now correctly shown for WOW64 processes - * I/O priority names are now used instead of numbers - * FIXED: - * Network list bug - * Memory leaks - -2.8 - * NEW/IMPROVED: - * Better service list (including column selection) - * Added Peak Handles - * Process tree sorting is now preserved - * Save works for services and network connections - * Pausing now works correctly with the Network tab - * Added option to display inclusive CPU usages for collapsed processes - * Added CLR tab to peview - * Added ability to destroy heaps - * Improved process tree list appearance - * Certain command line parameters are now propagated - * FIXED: - * Icon handling bugs - * Memory leaks - * Extended tooltips for WOW64 processes - -2.7 - * NEW/IMPROVED: - * Vastly improved startup time and lower memory usage - * Added Cycles and Cycles Delta columns - * Added option to disable address resolution for network connections - * Added Logon Time to session properties - * Added time stamp display to peview - * FIXED: - * ToolStatus layout problems - * .NET highlighting crashes - * Run As on Windows XP - -2.6 - * NEW/IMPROVED: - * Sorting for most lists is now much faster - * Hide Signed Processes option - * Added plugin for uploading files to online virus scanners - * Added Network tools plugin - * Updated ExtendedServices plugin - * PE viewer now verifies checksums - * Performance improvements - * FIXED: - * Fixed service handle leak - -2.5 - * NEW/IMPROVED: - * Unmap section views in Memory tab - * Plugin for extended service information (including recovery information, dependencies and dependents) - * FIXED: - * Critical bug for file dialogs on Windows XP - * Esc couldn't close Service Properties on open - * Small bug fixes - -2.4 - * NEW/IMPROVED: - * Better Run As behaviour - * Show Processes From All Users option - * Can now unmap section views - * Control over thread affinity - * Window Title and Window Status columns - * Plugin for filtering notifications - * Plugin for toolbar and status bar - * Performance improvements - * FIXED: - * Memory leak - * SbieSupport plugin on 64-bit - * Crash when running under certain conditions - * Memory case-insensitive filter - * Process parent association bug - * REMOVED: - * Process database - -2.3 - * NEW/IMPROVED: - * Can add processes to jobs - * Double-clicking in the system information graphs now opens information for the relevant process - * Setting I/O priority doesn't need KProcessHacker anymore - * Elevation for certain actions - * FIXED: - * HKCU key name resolution - * Network connection host resolution - * Information window resizing - * Log clearing - -2.2 - * NEW/IMPROVED: - * Plugins support - * Can now unload 32-bit modules on 64-bit systems - * Tasks are shown in tooltips for taskeng.exe/taskhost.exe processes - * Run As can now start processes elevated - * Handle count by type - * Process priorities in notification icon menu - * CSV export - * Relative start times - * FIXED: - * Run and Run As shortcuts - * Command line handling - * Process tree selection - -2.1 - * NEW/IMPROVED: - * Add Pause key shortcut to pause/resume updates - * Added Ctrl+Tab and Ctrl+Shift+Tab shortcuts - * Grid is a bit darker - * Checks for digital signatures and packing is now off by default and optional - * FIXED: - * MD5 calculation code for files was wrong - * Process record bugs - -2.0 - * First release in the Process Hacker 2.x branch. +Process Hacker + +3.0 + * HIGHLIGHTS: + * New Process Hacker setup. + * New process properties handle search. + * Added F11 hotkey for fullscreen System Information window. + * OTHER CHANGES: +* Updated Updater plugin: + * New design and layout. +* Updated WindowExplorer plugin: + * Added Windows process properties page. + * NOTE: + * Support for Windows XP and Vista has been dropped. For those platforms, use Process Hacker 2.38. + * This release has significant internal code changes. Please make sure all plugins are up-to-date. + +2.39 + * HIGHLIGHTS: + * Improved compatibility with security and anti-cheat software + * Added ability to edit process environment variables + * Fixed .NET process detection + * OTHER CHANGES: + * Improved tooltip information for dllhost.exe + * Removed Terminator + * Updated DotNetTools plugin: + * Fixed .NET assembly tab performance issues + * Added extra .NET memory counters to the .NET performance tab + * Added "Show sizes in bytes" checkbox to the .NET performance tab + * Added right-click menu to the .NET assembly tab + * Updated ExtendedTools plugin: + * Fixed "No process" disk event bug + * Updated HardwareDevices plugin: + * Fixed incorrect drive letters + * Fixed drive letter and panel clipping issue + +2.38 + * HIGHLIGHTS: + * Added labels to indicate the maximum data point in each I/O graph + * Graph grids now scale correctly when resized + * Improved high DPI scaling + * Added exploit mitigation policy information to process properties (Windows 8 and above) + * Added File modified time and File size columns for processes and modules + * Added Key modified time column for services + * Clicking a tray icon now shows the pop-up UI (useful for touch-enabled devices) + * The NetAdapters plugin has been renamed to HardwareDevices + * This plugin shows network adapter and disk drive graphs + * If you are manually upgrading, please delete NetAdapters.dll from the plugins folder + * Updated UserNotes plugin: + * Added "Collapse by default" option for processes + * OTHER CHANGES: + * Added "Start when I log on" option + * Added "Not responding" text to tray icon rich pop-up for programs that are hung + * Added right-click menu and double-click action for environment variables + * Added dialog box to show long command line strings + * Added Time stamp column for processes + * Added -sysinfo command line parameter for opening System Information at startup + * Added 32x32 icons for high DPI displays + * Digital signature verification is now performed with very low I/O priority + * Improved performance when handling a large number of threads, modules or handles + * The pop-up UI no longer displays when double-clicking the tray icon + * Fixed ASLR state being shown as N/A in process properties + * Fixed multi monitor window placement bug + * Fixed handle enumeration bug affecting processes with PID >= 65536 + * Fixed Interrupts being missing from the max CPU usage history + * Updated ToolStatus plugin: + * Added 32x32 icons for high DPI displays + * Fixed status bar crash + * NOTE: + * This release has significant internal code changes. Please make sure all plugins are up-to-date. + +2.37 + * HIGHLIGHTS: + * Updated for Windows 10 + * The "Include CPU (and other) usage of children in collapsed processes" option now aggregates memory and I/O statistics + * Added regex search to "Find Handles or DLLs" + * Added process exit codes to log + * Fixed crash that occurred under some conditions when processes terminated + * OTHER CHANGES: + * Added warning when trying to search for handles when the system has too many handles open + * Upgraded to PCRE2 + * Updated DotNetTools plugin: + * Rewrite of .NET Performance statistics and AppDomain enumeration + * Updated OnlineChecks plugin: + * Fixed virusscan.jotti.org uploader + * Updated NetAdapters plugin: + * Added adapter details window + * Updated ToolStatus plugin: + * Added CPU, Memory and I/O graphs to the toolbar (not enabled by default) + * Added toolbar and status bar customization, as well as a new theme + * Added option to auto-hide the main menu + * Updated UserNotes plugin: + * Added individual process highlighting support + +2.36 + * HIGHLIGHTS: + * New rich pop-up UI when hovering the cursor over a tray icon, showing the most active processes + * Completely new Memory tab for processes, with heap, stack and working set usage + * Process Hacker now takes 32-bit dumps of 32-bit processes on 64-bit Windows + * NOTE: When using the portable (.zip) release, the entire archive must be extracted + * Updated DotNetTools plugin: + * Process Hacker now displays managed stack traces for 32-bit .NET processes on 64-bit Windows + * Fixed inaccurate stack traces when clicking Refresh + * Added AppDomain column for threads in .NET programs + * OTHER CHANGES: + * Added customizable bytes per row setting for memory editor + * Dramatically faster handle listing and search when running without administrative privileges + * Improved accuracy and speed of symbol resolution, especially when new modules are loaded + * Added trigger and delayed start information to service list + * Added file information to service list tooltips + * Balloon tips for process/service notifications are now clickable + * Added handle names for unnamed File objects + * Added I/O Priority to tray icon process menu + * Added warning for users who attempt to start the 32-bit version on 64-bit Windows + * Updated ExtendedServices plugin: + * Added service protection and SID information + * Added auto-elevation when saving recovery information, triggers and other service settings + * Updated ExtendedTools plugin: + * Added tray icon mini info window support + * Improved automatic GPU node selection + * Updated UserNotes plugin: + * Added tray icon mini info window support + * Fixed a bug in phsvc that caused hangs when automatically elevating actions + * Fixed hang when viewing handle security for certain File objects + * Fixed lack of information on startup when using slower refresh intervals + * Fixed Read/Write Address crash + * Fixed service non-polling mode on Windows 8 and above + * Fixed file dialog crash in Windows PE environments + * Fixed string scanning false positive case + * Fixed process window detection for Modern UI apps + * Fixed handle list selection bug when disabling "Hide unnamed handles" + * NOTE: + * This release has significant internal code changes. Please make sure all plugins are up-to-date. + +2.35 + * NEW/IMPROVED: + * Added Load Time and Load Reason columns for modules (Windows 8 and above) + * Added handle names for Job and Section objects + * Added Read/Write Memory for Section objects (in process Handles tab) + * Added CF Guard (Control Flow Guard) column for processes and modules + * Added highlighting for AppContainer DLLs + * Added AppContainer and CF Guard image characteristics to peview + * Added Open Key and Open File Location menu items for services + * Set priority and I/O priority for multiple processes at once + * Support for up to 64 processors when setting process/thread affinity + * Updated ExtendedTools plugin: + * Added Disk and Network graphs for all processes + * Updated UserNotes plugin: + * Added ability to save I/O priority + * FIXED: + * Fixed memory editor copy bug + +2.34 + * NEW/IMPROVED: + * Proper Unicode support + * CPU and GPU graphs are displayed in a grid now (thanks pavel_kv!) + * Start Task Manager now elevates when necessary + * Better names for memory regions in Memory tab (for PEBs, TEBs, thread stacks) + * Added tooltip information for user-mode driver framework (UMDF) host processes + * Added option to reduce row height (set ThinRows to 1 in settings.xml) + * Added NetAdapters plugin: adds graphs for selected network adapters to the System Information window + * Updated ExtendedTools plugin: + * Added GPU graphs for all processes + * Can now use the search box in the Disk tab + * Improved kernel logger handling + * FIXED: + * Fixed touch scrolling + * Fixed EtwRegistration object names for 64-bit Windows 8.1 + * Fixed tray icons being clipped in high DPI environments + * Fixed crash in memory editor + * Fixed multi monitor window placement bug + +2.33 + * NEW/IMPROVED: + * View digital signature information from process properties and peview + * Signatures for Windows 8 apps are now detected + * Improved file, key, process and thread handle properties + * Added DPI Awareness column + * Added new Windows 8.1 process protection information + * KProcessHacker is no longer needed for highlighting of GUI threads + * Added suspend count for threads on Windows 8.1 + * Updated DotNetTools plugin: + * Improved .NET assembly enumeration timeout handling + * FIXED: + * Service start type and error control are never updated if modified outside of Process Hacker + +2.32 + * NOTE: + * All executable files are now signed. + * NEW/IMPROVED: + * Updated for Windows 8.1 + * Added progress display for thread stacks + * Updated ExtendedServices plugin: + * Added new trigger data types + * Updated NetworkTools plugin: + * Updated UI + * Updated OnlineChecks plugin: + * Added file analyzed prompt + * FIXED: + * Fixed handling of long symbol names + * Fixed Run As preventing Windows 8 apps from starting + * Fixed console host information for Windows 8.1 + * Fixed reflected processes not terminating on Windows 8.1 + * Fixed CPU frequency on Windows 8.1 + +2.31 + * NEW/IMPROVED: + * Updated ExtendedServices plugin: + * Fixed some bugs relating to Windows 8 + * Updated OnlineChecks plugin: + * Added upload progress + * Updated UserNotes plugin: + * Fixed bug where process priorities were not actually saved + * FIXED: + * Fixed module list not updating properly + * DLL enumeration crash + +2.30 + * NEW/IMPROVED: + * Added "Icon click toggles visibility" option + * Re-enabled powerful process termination on 32-bit Windows 8 + * Updated UserNotes plugin: + * Added ability to save process priority + * Added "Only for processes with the same command line" option for process comments + * FIXED: + * Fixed crash on CPUs without SSE2 + +2.29 + * NEW/IMPROVED: + * Added App ID column for processes + * Added new ASLR information for Windows 8 + * Added Restart to Boot Options and Hybrid Shutdown menu items for Windows 8 + * Added ability to specify processes by their names and inject and unload DLLs in command line + * Removed 512 character limit when copying text + * Moved Terminator to Miscellaneous menu + * Updated default dbghelp.dll path for Windows SDK v8 + * Updated ExtendedServices plugin: + * Added new triggers for Windows 8 + * Fixed bug when restarting services + * Updated ExtendedTools plugin: + * Improved support for multiple GPUs (again) + * GPU column now respects "Include CPU usage of children" option + * Updated ToolStatus plugin: + * Fixed search box fonts + * Fixed controls not being properly hidden/removed from the window when disabled + * Updated WindowExplorer plugin: + * Fixed window list not displaying Modern UI windows + * FIXED: + * Fixed Load Count column sorting bug + * Fixed signature verification on Windows 8 + * Fixed task scheduler information on Windows 8 + * Fixed drag bug in tree list + * Fixed KProcessHacker bug affecting TmTx objects + * Fixed Run As feature on Windows 8 + * Fixed bug where -settings parameter is not propagated + * Fixed tab key behavior on main window + * Fixed recognition of Modern UI windows + +2.28 + * NEW/IMPROVED: + * peview now resolves .lnk targets + * Fixed Ctrl+A for processes, services and network connections and added Ctrl+A for other windows + * Changed confirmation prompts to select the destructive action by default + * Updated DotNetTools plugin: + * Fixed inaccurate stack traces for certain .NET programs + * Updated ExtendedTools plugin: + * Fixed network graph scaling + * Updated ToolStatus plugin: + * Added search box + * Updated Updater plugin + * FIXED: + * Fixed Verification Status column sorting bug in module list + * Fixed rare System Information crash + * Fixed bug in opening process handles + * Fixed freezing when viewing stack traces of certain system threads + +2.27 + * NEW/IMPROVED: + * Updated OnlineChecks plugin: + * 2012-01-16: Updated VirusTotal uploader and added hash checking + * FIXED: + * Fixed Description column sorting bug + * Fixed notification icon bug + +2.26 + * NEW/IMPROVED: + * Added option to show Commit Charge in system information summary view + * Added -priority and -selectpid command line options + * Updated ExtendedTools plugin: + * Improved support for multiple GPUs + * FIXED: + * Fixed 100% CPU when starting on some machines + +2.25 + * NEW/IMPROVED: + * Improved CPU frequency calculation + * Updated ExtendedTools plugin: + * Added GPU node selection + * Fixed incorrect GPU usage calculation + * FIXED: + * Graph tooltip position with large cursors + * Fixed .NET process detection + * Fixed incorrect values in Bits column + +2.24 + * NOTE: + * This release has significant internal code changes. Please make sure all plugins are up-to-date. + * NEW/IMPROVED: + * Completely new system information window + * Added option to scroll to new processes + * Added option to hide driver services + * Added menu item to copy individual cells + * Improved module scanning + * Added Start Task Manager menu item + * Added Image base to peview + * Updated ExtendedTools plugin: + * Added support for new system information window + * Added Disk, Network and GPU tray icons + * Added support for custom fonts in the Disk tab + * Updated Updater plugin: + * Added download speed + * Added remaining time + * FIXED: + * Fixed retrieval of version information for certain files + * Fixed driver file names on Windows XP + * Fixed Run As Administrator when used with complex commands + +2.23 + * NEW/IMPROVED: + * Added display of token capabilities, user/device claims and security attributes + * Added ability to change token integrity levels + * Added Description column to service list + * Added option to reset all settings + * Made grid color darker + * Enabled multi-selection in the hidden processes window + * Added UserNotes plugin + * Updated ExtendedNotifications plugin: + * Added Growl support + * Updated ExtendedTools plugin: + * Added GPU monitoring + * Added rate columns for disk and network I/O + * FIXED: + * Fixed copying lists when plugin columns are enabled + * Freezing when viewing the tooltip for a process with a very long command line + * Disabled Hidden Processes feature on 64-bit systems + +2.22 + * NEW/IMPROVED: + * Added highlighting for metro style apps + * Added Package Name column + * Added package name to process tooltip + * Improved .NET process detection + * Updated OS Context column for Windows 8 + * Updated ExtendedTools plugin: + * Updated disk monitoring for Windows 8 + * Updated memory list information for Windows 8 + * Updated WindowExplorer plugin: + * Fixed hook support for low integrity processes + * FIXED: + * Fixed memory leaks + * Fixed bug preventing Interrupts/DPCs from being shown as the max. CPU process on 64-bit systems + * Fixed DEP Status column on 64-bit systems + +2.21 + * NEW/IMPROVED: + * Added Private Bytes Delta, ASLR and Subsystem columns + * Added ASLR and Time Stamp columns to modules list + * Added check for debugger in Terminator + * FIXED: + * Fixed Show CPU Below 0.01 not respecting locale + * Fixed copying from network list + +2.20 + * NEW/IMPROVED: + * Added support for managed thread stacks on x64 + * Added column selection for handle list + * Added CPU column to threads list + * Improved module detection + * Added Ideal Processor to Threads tab + * Added pool usage and minimum/maximum working set columns + * Implemented Properties button for Thread handles + * Set descending sort as the default for most numeric columns + * Extended header context menu + * Removed tooltip text truncation + * Improved cycle-based CPU usage calculation + * Set default KProcessHacker security level to only allow connections when Process Hacker is running as administrator. + See README.txt for instructions on how to restore the old behavior. + * Added Updater plugin + * Updated DotNetTools plugin: + * Added managed symbol resolution for thread stacks + * Updated ExtendedTools plugin: + * Added Disk tab + * Added Hard Faults, Hard Faults Delta and Peak Threads columns to process tree list + * Added Firewall Status column + * FIXED: + * Fixed file name resolution bug + * Save settings on shutdown/logoff + * Fixed state highlighting bug + * Fixed command line propagation for -elevate + * Fixed tree list mouse wheel handling + * Fixed saving network list + +2.19 + * NEW/IMPROVED: + * Added cycle-based CPU usage for Windows 7 + * Added Show CPU Below 0.01 + * Added OS Context column + * Rewrote graph drawing code for improved performance + * Optimized retrieval of cycle time and private working set information for Windows 7 + * Added Open File Location to process context menu and reorganized some items + * Added checkboxes to Terminator + * FIXED: + * Crash when sorting by Time Stamp + * GDI handle leak in drag selection + +2.18 + * NEW/IMPROVED: + * Completely rewritten tree list control: + * Process Name column is now fixed to the left + * Tooltips for column headers + * Improved performance + * Bug fixes + * Added more process tree list columns + * Added Time stamp column to network list + * Date/time display is now swapped (so time is shown before date) + * Added W3 terminator test + * Added DotNetTools plugin + * Updated ExtendedServices plugin: + * Disabled editing of required privileges for drivers + * Updated ExtendedTools plugin: + * Added ETW columns for processes and network connections + * Updated OnlineChecks plugin: + * Added Comodo Instant Malware Analysis + * Updated WindowExplorer plugin: + * Fixed hook bugs + * FIXED: + * Fixed Run As This User + * Verification Status sorting + +2.17 + * NEW/IMPROVED: + * Added support for setting page priority + * Added elevation support for setting priority + * Added support for automatically using a settings file in the program directory (e.g. ProcessHacker.exe.settings.xml) + * Improved Run As mechanism + * Updated ExtendedServices plugin: + * Added support for editing triggers + * Added support for editing preshutdown time-out + * Added support for editing required privileges + * Added elevation support for restarting services + * Updated WindowExplorer plugin: + * Added more window properties + * FIXED: + * Handle leak + +2.16 + * NEW/IMPROVED: + * Updated WindowExplorer plugin + * PE viewer: Added version string to CLR tab + * PE viewer: Added display of delay imports + * PE viewer: Added Load Config tab + * Improved wait analysis + * Added arrows to the service list to indicate whether a service is running + * FIXED: + * Fixed the IPv6-related workaround causing crashes + * Incorrect handling of window positions + +2.15 + * NEW/IMPROVED: + * Updated ExtendedServices plugin + * Updated ToolStatus plugin + * Added DEP Status column + * Improved User Name column + * FIXED: + * Image file versions + * Workaround for an IPv6-related bug in Windows XP + * DPCs and Interrupts in System Information tooltips + * File dialog crash on Windows XP + * ExtendedTools plugin: WS Watch refresh bug + +2.14 + * NEW/IMPROVED: + * ExtendedServices plugin: Option to add a Services menu for processes + * Command line support for setting process priority and I/O priority + * Improved termination of explorer.exe + * FIXED: + * Icon should restore the main window if it is minimized + * System Information window crashes + * Hide Processes From Other Users and Hide Signed Processes settings are now saved + * Font selection on Windows XP + * ToolStatus plugin: Always on Top status being reset by Find Window + * Service-related crashes + * WindowExplorer plugin: sorting in tree list + * Process minidump creation with old versions of dbghelp.dll + +2.13 + * NEW/IMPROVED: + * Added copy support to PE viewer + * Added Connect Time, Disconnect Time and Last Input Time to session properties + * Added more working set counters to the Statistics tab + * FIXED: + * Column sort arrows + * CPU usage calculations + +2.12 + * NEW/IMPROVED: + * Updated KProcessHacker for Windows 7 SP1 + * Added elevation support for more actions + * Added ability to disable plugins + * Updated ToolStatus plugin + * Added Remote Control for sessions + * More command line options + * FIXED: + * Memory leaks + * Run As issues with different sessions + +2.11 + * NEW/IMPROVED: + * Added WS Watch and other features to ExtendedTools plugin + * Added WindowExplorer plugin + * Properties for hidden processes + * Improved menus + * Debug console can now be closed without affecting the entire program + * FIXED: + * Always on Top issues + * Hang when setting DEP status of a terminating process + * Encoding bug in NetworkTools plugin + * LSA interfacing issues + * Creating dumps of self + +2.10 + * NEW/IMPROVED: + * KProcessHacker is now signed, so it works on 64-bit systems. Thank you to the ReactOS Foundation. + * Added Run As Limited User + * Added CPU, private bytes and I/O history columns + * Added font selection + * Slightly improved highlighting configuration + * FIXED: + * High DPI support + * Multi-monitor support in graph tooltips + * DEP status retrieval + * ExtendedTools plugin crash + * Notification icon menu crash + * Memory leaks + * Other small bug fixes + +2.9 + * NEW/IMPROVED: + * Added column selection for modules list + * Added wait analysis for 64-bit systems + * Added signature verification for modules + * Added ExtendedTools plugin (Vista and above only) with Disk and Network information + * Updated ExtendedNotifications plugin: added ability to log events to a file + * Updated ExtendedServices plugin: new tab on Vista and above + * Updated ToolStatus plugin: resolves ghost windows to hung windows + * Environment variables and current directory are now correctly shown for WOW64 processes + * I/O priority names are now used instead of numbers + * FIXED: + * Network list bug + * Memory leaks + +2.8 + * NEW/IMPROVED: + * Better service list (including column selection) + * Added Peak Handles + * Process tree sorting is now preserved + * Save works for services and network connections + * Pausing now works correctly with the Network tab + * Added option to display inclusive CPU usages for collapsed processes + * Added CLR tab to peview + * Added ability to destroy heaps + * Improved process tree list appearance + * Certain command line parameters are now propagated + * FIXED: + * Icon handling bugs + * Memory leaks + * Extended tooltips for WOW64 processes + +2.7 + * NEW/IMPROVED: + * Vastly improved startup time and lower memory usage + * Added Cycles and Cycles Delta columns + * Added option to disable address resolution for network connections + * Added Logon Time to session properties + * Added time stamp display to peview + * FIXED: + * ToolStatus layout problems + * .NET highlighting crashes + * Run As on Windows XP + +2.6 + * NEW/IMPROVED: + * Sorting for most lists is now much faster + * Hide Signed Processes option + * Added plugin for uploading files to online virus scanners + * Added Network tools plugin + * Updated ExtendedServices plugin + * PE viewer now verifies checksums + * Performance improvements + * FIXED: + * Fixed service handle leak + +2.5 + * NEW/IMPROVED: + * Unmap section views in Memory tab + * Plugin for extended service information (including recovery information, dependencies and dependents) + * FIXED: + * Critical bug for file dialogs on Windows XP + * Esc couldn't close Service Properties on open + * Small bug fixes + +2.4 + * NEW/IMPROVED: + * Better Run As behaviour + * Show Processes From All Users option + * Can now unmap section views + * Control over thread affinity + * Window Title and Window Status columns + * Plugin for filtering notifications + * Plugin for toolbar and status bar + * Performance improvements + * FIXED: + * Memory leak + * SbieSupport plugin on 64-bit + * Crash when running under certain conditions + * Memory case-insensitive filter + * Process parent association bug + * REMOVED: + * Process database + +2.3 + * NEW/IMPROVED: + * Can add processes to jobs + * Double-clicking in the system information graphs now opens information for the relevant process + * Setting I/O priority doesn't need KProcessHacker anymore + * Elevation for certain actions + * FIXED: + * HKCU key name resolution + * Network connection host resolution + * Information window resizing + * Log clearing + +2.2 + * NEW/IMPROVED: + * Plugins support + * Can now unload 32-bit modules on 64-bit systems + * Tasks are shown in tooltips for taskeng.exe/taskhost.exe processes + * Run As can now start processes elevated + * Handle count by type + * Process priorities in notification icon menu + * CSV export + * Relative start times + * FIXED: + * Run and Run As shortcuts + * Command line handling + * Process tree selection + +2.1 + * NEW/IMPROVED: + * Add Pause key shortcut to pause/resume updates + * Added Ctrl+Tab and Ctrl+Shift+Tab shortcuts + * Grid is a bit darker + * Checks for digital signatures and packing is now off by default and optional + * FIXED: + * MD5 calculation code for files was wrong + * Process record bugs + +2.0 + * First release in the Process Hacker 2.x branch. diff --git a/COPYRIGHT.txt b/COPYRIGHT.txt index 2fa97372f513..5469a3bafbe6 100644 --- a/COPYRIGHT.txt +++ b/COPYRIGHT.txt @@ -1,132 +1,132 @@ -== Process Hacker == -Process Hacker is licensed under the GNU GPL v3, with exceptions. A full -copy of the license is provided in LICENSE.txt. - - Copyright (C) 2009-2016 wj32 and various authors - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -== Mini-XML == -Process Hacker uses Mini-XML licensed under the following terms: - - The Mini-XML library and included programs are provided under the - terms of the GNU Library General Public License (LGPL) with the - following exceptions: - - 1. Static linking of applications to the Mini-XML library - does not constitute a derivative work and does not require - the author to provide source code for the application, use - the shared Mini-XML libraries, or link their applications - against a user-supplied version of Mini-XML. - - If you link the application to a modified version of - Mini-XML, then the changes to Mini-XML must be provided - under the terms of the LGPL in sections 1, 2, and 4. - - 2. You do not have to provide a copy of the Mini-XML license - with programs that are linked to the Mini-XML library, nor - do you have to identify the Mini-XML license in your - program or documentation as required by section 6 of the - LGPL. - -== PCRE == -Process Hacker uses Perl-Compatible Regular Expressions licensed under the -following terms: - - PCRE is a library of functions to support regular expressions whose syntax - and semantics are as close as possible to those of the Perl 5 language. - - Release 8 of PCRE is distributed under the terms of the "BSD" licence, as - specified below. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - * Neither the name of the University of Cambridge nor the name of Google - Inc. nor the names of their contributors may be used to endorse or - promote products derived from this software without specific prior - written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - POSSIBILITY OF SUCH DAMAGE. - -== MD5 == -Process Hacker uses a MD5 implementation licensed under the following terms: - - MD5 hash implementation and interface functions - Copyright (c) 2003-2005, Jouni Malinen - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License version 2 as - published by the Free Software Foundation. - -== SHA == -Process Hacker uses a SHA implementation licensed under the following terms: - - Copyright 2004 Filip Navara - Based on public domain SHA code by Steve Reid - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - -== Natural order string comparison == -Process Hacker uses "strnatcmp.c" licensed under the following terms: - - strnatcmp.c -- Perform 'natural order' comparisons of strings in C. - Copyright (C) 2000, 2004 by Martin Pool - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - This code has been modified for Process Hacker. +== Process Hacker == +Process Hacker is licensed under the GNU GPL v3, with exceptions. A full +copy of the license is provided in LICENSE.txt. + + Copyright (C) 2009-2016 wj32 and various authors + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +== Mini-XML == +Process Hacker uses Mini-XML licensed under the following terms: + + The Mini-XML library and included programs are provided under the + terms of the GNU Library General Public License (LGPL) with the + following exceptions: + + 1. Static linking of applications to the Mini-XML library + does not constitute a derivative work and does not require + the author to provide source code for the application, use + the shared Mini-XML libraries, or link their applications + against a user-supplied version of Mini-XML. + + If you link the application to a modified version of + Mini-XML, then the changes to Mini-XML must be provided + under the terms of the LGPL in sections 1, 2, and 4. + + 2. You do not have to provide a copy of the Mini-XML license + with programs that are linked to the Mini-XML library, nor + do you have to identify the Mini-XML license in your + program or documentation as required by section 6 of the + LGPL. + +== PCRE == +Process Hacker uses Perl-Compatible Regular Expressions licensed under the +following terms: + + PCRE is a library of functions to support regular expressions whose syntax + and semantics are as close as possible to those of the Perl 5 language. + + Release 8 of PCRE is distributed under the terms of the "BSD" licence, as + specified below. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of the University of Cambridge nor the name of Google + Inc. nor the names of their contributors may be used to endorse or + promote products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + +== MD5 == +Process Hacker uses a MD5 implementation licensed under the following terms: + + MD5 hash implementation and interface functions + Copyright (c) 2003-2005, Jouni Malinen + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License version 2 as + published by the Free Software Foundation. + +== SHA == +Process Hacker uses a SHA implementation licensed under the following terms: + + Copyright 2004 Filip Navara + Based on public domain SHA code by Steve Reid + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + +== Natural order string comparison == +Process Hacker uses "strnatcmp.c" licensed under the following terms: + + strnatcmp.c -- Perform 'natural order' comparisons of strings in C. + Copyright (C) 2000, 2004 by Martin Pool + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + This code has been modified for Process Hacker. diff --git a/KProcessHacker/KProcessHacker.vcxproj b/KProcessHacker/KProcessHacker.vcxproj index 98820bf88ad9..87fb632baad2 100644 --- a/KProcessHacker/KProcessHacker.vcxproj +++ b/KProcessHacker/KProcessHacker.vcxproj @@ -1,139 +1,139 @@ - - - - - Win8 Debug - Win32 - - - Win8 Release - Win32 - - - Win8 Debug - x64 - - - Win8 Release - x64 - - - - {F4853009-C5D2-4A25-BE4D-BB0D9F84E2FF} - {dd38f7fc-d7bd-488b-9242-7d8754cde80d} - v4.5 - 11.0 - Win8 Debug - Win32 - - - KProcessHacker - $(VCTargetsPath11) - - - WindowsKernelModeDriver8.0 - Driver - WDM - - - - Windows8 - true - - - Windows8 - false - - - Windows8 - true - - - Windows8 - false - - - - - - - - - - DbgengKernelDebugger - - - $(ProjectDir)bin\$(Configuration) $(PlatformArchitecture)\ - $(ProjectDir)obj\$(Configuration) $(PlatformArchitecture)\ - kprocesshacker - - - $(ProjectDir)bin\$(Configuration) $(PlatformArchitecture)\ - $(ProjectDir)obj\$(Configuration) $(PlatformArchitecture)\ - kprocesshacker - - - $(ProjectDir)bin\$(Configuration) $(PlatformArchitecture)\ - $(ProjectDir)obj\$(Configuration) $(PlatformArchitecture)\ - kprocesshacker - - - $(ProjectDir)bin\$(Configuration) $(PlatformArchitecture)\ - $(ProjectDir)obj\$(Configuration) $(PlatformArchitecture)\ - kprocesshacker - - - - ../phnt/include;../phlib/include;include;$(IntDir);%(AdditionalIncludeDirectories) - KPH_CONFIG_CLEAN;_X86_=1;i386=1;STD_CALL;%(PreprocessorDefinitions) - Level3 - - - - - ../phnt/include;../phlib/include;include;$(IntDir);%(AdditionalIncludeDirectories) - KPH_CONFIG_CLEAN;_X86_=1;i386=1;STD_CALL;%(PreprocessorDefinitions) - Level3 - - - - - ../phnt/include;../phlib/include;include;$(IntDir);%(AdditionalIncludeDirectories) - KPH_CONFIG_CLEAN;_WIN64;_AMD64_;AMD64;%(PreprocessorDefinitions) - Level3 - - - - - ../phnt/include;../phlib/include;include;$(IntDir);%(AdditionalIncludeDirectories) - KPH_CONFIG_CLEAN;_WIN64;_AMD64_;AMD64;%(PreprocessorDefinitions) - Level3 - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + Win8 Debug + Win32 + + + Win8 Release + Win32 + + + Win8 Debug + x64 + + + Win8 Release + x64 + + + + {F4853009-C5D2-4A25-BE4D-BB0D9F84E2FF} + {dd38f7fc-d7bd-488b-9242-7d8754cde80d} + v4.5 + 11.0 + Win8 Debug + Win32 + + + KProcessHacker + $(VCTargetsPath11) + + + WindowsKernelModeDriver8.0 + Driver + WDM + + + + Windows8 + true + + + Windows8 + false + + + Windows8 + true + + + Windows8 + false + + + + + + + + + + DbgengKernelDebugger + + + $(ProjectDir)bin\$(Configuration) $(PlatformArchitecture)\ + $(ProjectDir)obj\$(Configuration) $(PlatformArchitecture)\ + kprocesshacker + + + $(ProjectDir)bin\$(Configuration) $(PlatformArchitecture)\ + $(ProjectDir)obj\$(Configuration) $(PlatformArchitecture)\ + kprocesshacker + + + $(ProjectDir)bin\$(Configuration) $(PlatformArchitecture)\ + $(ProjectDir)obj\$(Configuration) $(PlatformArchitecture)\ + kprocesshacker + + + $(ProjectDir)bin\$(Configuration) $(PlatformArchitecture)\ + $(ProjectDir)obj\$(Configuration) $(PlatformArchitecture)\ + kprocesshacker + + + + ../phnt/include;../phlib/include;include;$(IntDir);%(AdditionalIncludeDirectories) + KPH_CONFIG_CLEAN;_X86_=1;i386=1;STD_CALL;%(PreprocessorDefinitions) + Level3 + + + + + ../phnt/include;../phlib/include;include;$(IntDir);%(AdditionalIncludeDirectories) + KPH_CONFIG_CLEAN;_X86_=1;i386=1;STD_CALL;%(PreprocessorDefinitions) + Level3 + + + + + ../phnt/include;../phlib/include;include;$(IntDir);%(AdditionalIncludeDirectories) + KPH_CONFIG_CLEAN;_WIN64;_AMD64_;AMD64;%(PreprocessorDefinitions) + Level3 + + + + + ../phnt/include;../phlib/include;include;$(IntDir);%(AdditionalIncludeDirectories) + KPH_CONFIG_CLEAN;_WIN64;_AMD64_;AMD64;%(PreprocessorDefinitions) + Level3 + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/KProcessHacker/devctrl.c b/KProcessHacker/devctrl.c index f6a048fae306..50a4a645fd28 100644 --- a/KProcessHacker/devctrl.c +++ b/KProcessHacker/devctrl.c @@ -1,566 +1,566 @@ -/* - * KProcessHacker - * - * Copyright (C) 2010-2016 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include - -NTSTATUS KphDispatchDeviceControl( - __in PDEVICE_OBJECT DeviceObject, - __in PIRP Irp - ) -{ - NTSTATUS status; - PIO_STACK_LOCATION stackLocation; - PFILE_OBJECT fileObject; - PKPH_CLIENT client; - PVOID originalInput; - ULONG inputLength; - ULONG ioControlCode; - KPROCESSOR_MODE accessMode; - UCHAR capturedInput[16 * sizeof(ULONG_PTR)]; - PVOID capturedInputPointer; - -#define VERIFY_INPUT_LENGTH \ - do { \ - /* Ensure at compile time that our local buffer fits this particular call. */ \ - C_ASSERT(sizeof(*input) <= sizeof(capturedInput)); \ - \ - if (inputLength != sizeof(*input)) \ - { \ - status = STATUS_INFO_LENGTH_MISMATCH; \ - goto ControlEnd; \ - } \ - } while (0) - - stackLocation = IoGetCurrentIrpStackLocation(Irp); - fileObject = stackLocation->FileObject; - client = fileObject->FsContext; - - originalInput = stackLocation->Parameters.DeviceIoControl.Type3InputBuffer; - inputLength = stackLocation->Parameters.DeviceIoControl.InputBufferLength; - ioControlCode = stackLocation->Parameters.DeviceIoControl.IoControlCode; - accessMode = Irp->RequestorMode; - - // Make sure we have a client object. - if (!client) - { - status = STATUS_INTERNAL_ERROR; - goto ControlEnd; - } - - // Enforce signature requirement if necessary. - if ((ioControlCode != KPH_GETFEATURES && ioControlCode != KPH_VERIFYCLIENT) && - (KphParameters.SecurityLevel == KphSecuritySignatureCheck || - KphParameters.SecurityLevel == KphSecuritySignatureAndPrivilegeCheck) && - !client->VerificationSucceeded) - { - status = STATUS_ACCESS_DENIED; - goto ControlEnd; - } - - // Make sure we actually have input if the input length is non-zero. - if (inputLength != 0 && !originalInput) - { - status = STATUS_INVALID_BUFFER_SIZE; - goto ControlEnd; - } - - // Make sure the caller isn't giving us a huge buffer. If they are, it can't be correct because - // we have a compile-time check that makes sure our buffer can store the arguments for all the - // calls. - if (inputLength > sizeof(capturedInput)) - { - status = STATUS_INVALID_BUFFER_SIZE; - goto ControlEnd; - } - - // Probe and capture the input buffer. - if (accessMode != KernelMode) - { - __try - { - ProbeForRead(originalInput, inputLength, sizeof(UCHAR)); - memcpy(capturedInput, originalInput, inputLength); - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - status = GetExceptionCode(); - goto ControlEnd; - } - } - else - { - memcpy(capturedInput, originalInput, inputLength); - } - - capturedInputPointer = capturedInput; // avoid casting below - - switch (ioControlCode) - { - case KPH_GETFEATURES: - { - struct - { - PULONG Features; - } *input = capturedInputPointer; - - VERIFY_INPUT_LENGTH; - - status = KpiGetFeatures( - input->Features, - accessMode - ); - } - break; - case KPH_VERIFYCLIENT: - { - struct - { - PVOID CodeAddress; - PVOID Signature; - ULONG SignatureSize; - } *input = capturedInputPointer; - - VERIFY_INPUT_LENGTH; - - if (accessMode == UserMode) - { - status = KpiVerifyClient( - input->CodeAddress, - input->Signature, - input->SignatureSize, - client - ); - } - else - { - status = STATUS_UNSUCCESSFUL; - } - } - break; - case KPH_RETRIEVEKEY: - { - struct - { - KPH_KEY_LEVEL KeyLevel; - } *input = capturedInputPointer; - - VERIFY_INPUT_LENGTH; - - if (accessMode == UserMode) - { - status = KphRetrieveKeyViaApc( - client, - input->KeyLevel, - Irp - ); - } - else - { - status = STATUS_UNSUCCESSFUL; - } - } - break; - case KPH_OPENPROCESS: - { - struct - { - PHANDLE ProcessHandle; - ACCESS_MASK DesiredAccess; - PCLIENT_ID ClientId; - KPH_KEY Key; - } *input = capturedInputPointer; - - VERIFY_INPUT_LENGTH; - - status = KpiOpenProcess( - input->ProcessHandle, - input->DesiredAccess, - input->ClientId, - input->Key, - client, - accessMode - ); - } - break; - case KPH_OPENPROCESSTOKEN: - { - struct - { - HANDLE ProcessHandle; - ACCESS_MASK DesiredAccess; - PHANDLE TokenHandle; - KPH_KEY Key; - } *input = capturedInputPointer; - - VERIFY_INPUT_LENGTH; - - status = KpiOpenProcessToken( - input->ProcessHandle, - input->DesiredAccess, - input->TokenHandle, - input->Key, - client, - accessMode - ); - } - break; - case KPH_OPENPROCESSJOB: - { - struct - { - HANDLE ProcessHandle; - ACCESS_MASK DesiredAccess; - PHANDLE JobHandle; - } *input = capturedInputPointer; - - VERIFY_INPUT_LENGTH; - - status = KpiOpenProcessJob( - input->ProcessHandle, - input->DesiredAccess, - input->JobHandle, - accessMode - ); - } - break; - case KPH_TERMINATEPROCESS: - { - struct - { - HANDLE ProcessHandle; - NTSTATUS ExitStatus; - KPH_KEY Key; - } *input = capturedInputPointer; - - VERIFY_INPUT_LENGTH; - - status = KpiTerminateProcess( - input->ProcessHandle, - input->ExitStatus, - input->Key, - client, - accessMode - ); - } - break; - case KPH_READVIRTUALMEMORYUNSAFE: - { - struct - { - HANDLE ProcessHandle; - PVOID BaseAddress; - PVOID Buffer; - SIZE_T BufferSize; - PSIZE_T NumberOfBytesRead; - KPH_KEY Key; - } *input = capturedInputPointer; - - VERIFY_INPUT_LENGTH; - - status = KpiReadVirtualMemoryUnsafe( - input->ProcessHandle, - input->BaseAddress, - input->Buffer, - input->BufferSize, - input->NumberOfBytesRead, - input->Key, - client, - accessMode - ); - } - break; - case KPH_QUERYINFORMATIONPROCESS: - { - struct - { - HANDLE ProcessHandle; - KPH_PROCESS_INFORMATION_CLASS ProcessInformationClass; - PVOID ProcessInformation; - ULONG ProcessInformationLength; - PULONG ReturnLength; - } *input = capturedInputPointer; - - VERIFY_INPUT_LENGTH; - - status = KpiQueryInformationProcess( - input->ProcessHandle, - input->ProcessInformationClass, - input->ProcessInformation, - input->ProcessInformationLength, - input->ReturnLength, - accessMode - ); - } - break; - case KPH_SETINFORMATIONPROCESS: - { - struct - { - HANDLE ProcessHandle; - KPH_PROCESS_INFORMATION_CLASS ProcessInformationClass; - PVOID ProcessInformation; - ULONG ProcessInformationLength; - } *input = capturedInputPointer; - - VERIFY_INPUT_LENGTH; - - status = KpiSetInformationProcess( - input->ProcessHandle, - input->ProcessInformationClass, - input->ProcessInformation, - input->ProcessInformationLength, - accessMode - ); - } - break; - case KPH_OPENTHREAD: - { - struct - { - PHANDLE ThreadHandle; - ACCESS_MASK DesiredAccess; - PCLIENT_ID ClientId; - KPH_KEY Key; - } *input = capturedInputPointer; - - VERIFY_INPUT_LENGTH; - - status = KpiOpenThread( - input->ThreadHandle, - input->DesiredAccess, - input->ClientId, - input->Key, - client, - accessMode - ); - } - break; - case KPH_OPENTHREADPROCESS: - { - struct - { - HANDLE ThreadHandle; - ACCESS_MASK DesiredAccess; - PHANDLE ProcessHandle; - } *input = capturedInputPointer; - - VERIFY_INPUT_LENGTH; - - status = KpiOpenThreadProcess( - input->ThreadHandle, - input->DesiredAccess, - input->ProcessHandle, - accessMode - ); - } - break; - case KPH_CAPTURESTACKBACKTRACETHREAD: - { - struct - { - HANDLE ThreadHandle; - ULONG FramesToSkip; - ULONG FramesToCapture; - PVOID *BackTrace; - PULONG CapturedFrames; - PULONG BackTraceHash; - } *input = capturedInputPointer; - - VERIFY_INPUT_LENGTH; - - status = KpiCaptureStackBackTraceThread( - input->ThreadHandle, - input->FramesToSkip, - input->FramesToCapture, - input->BackTrace, - input->CapturedFrames, - input->BackTraceHash, - accessMode - ); - } - break; - case KPH_QUERYINFORMATIONTHREAD: - { - struct - { - HANDLE ThreadHandle; - KPH_THREAD_INFORMATION_CLASS ThreadInformationClass; - PVOID ThreadInformation; - ULONG ThreadInformationLength; - PULONG ReturnLength; - } *input = capturedInputPointer; - - VERIFY_INPUT_LENGTH; - - status = KpiQueryInformationThread( - input->ThreadHandle, - input->ThreadInformationClass, - input->ThreadInformation, - input->ThreadInformationLength, - input->ReturnLength, - accessMode - ); - } - break; - case KPH_SETINFORMATIONTHREAD: - { - struct - { - HANDLE ThreadHandle; - KPH_THREAD_INFORMATION_CLASS ThreadInformationClass; - PVOID ThreadInformation; - ULONG ThreadInformationLength; - } *input = capturedInputPointer; - - VERIFY_INPUT_LENGTH; - - status = KpiSetInformationThread( - input->ThreadHandle, - input->ThreadInformationClass, - input->ThreadInformation, - input->ThreadInformationLength, - accessMode - ); - } - break; - case KPH_ENUMERATEPROCESSHANDLES: - { - struct - { - HANDLE ProcessHandle; - PVOID Buffer; - ULONG BufferLength; - PULONG ReturnLength; - } *input = capturedInputPointer; - - VERIFY_INPUT_LENGTH; - - status = KpiEnumerateProcessHandles( - input->ProcessHandle, - input->Buffer, - input->BufferLength, - input->ReturnLength, - accessMode - ); - } - break; - case KPH_QUERYINFORMATIONOBJECT: - { - struct - { - HANDLE ProcessHandle; - HANDLE Handle; - KPH_OBJECT_INFORMATION_CLASS ObjectInformationClass; - PVOID ObjectInformation; - ULONG ObjectInformationLength; - PULONG ReturnLength; - } *input = capturedInputPointer; - - VERIFY_INPUT_LENGTH; - - status = KpiQueryInformationObject( - input->ProcessHandle, - input->Handle, - input->ObjectInformationClass, - input->ObjectInformation, - input->ObjectInformationLength, - input->ReturnLength, - accessMode - ); - } - break; - case KPH_SETINFORMATIONOBJECT: - { - struct - { - HANDLE ProcessHandle; - HANDLE Handle; - KPH_OBJECT_INFORMATION_CLASS ObjectInformationClass; - PVOID ObjectInformation; - ULONG ObjectInformationLength; - } *input = capturedInputPointer; - - VERIFY_INPUT_LENGTH; - - status = KpiSetInformationObject( - input->ProcessHandle, - input->Handle, - input->ObjectInformationClass, - input->ObjectInformation, - input->ObjectInformationLength, - accessMode - ); - } - break; - case KPH_OPENDRIVER: - { - struct - { - PHANDLE DriverHandle; - ACCESS_MASK DesiredAccess; - POBJECT_ATTRIBUTES ObjectAttributes; - } *input = capturedInputPointer; - - VERIFY_INPUT_LENGTH; - - status = KpiOpenDriver( - input->DriverHandle, - input->DesiredAccess, - input->ObjectAttributes, - accessMode - ); - } - break; - case KPH_QUERYINFORMATIONDRIVER: - { - struct - { - HANDLE DriverHandle; - DRIVER_INFORMATION_CLASS DriverInformationClass; - PVOID DriverInformation; - ULONG DriverInformationLength; - PULONG ReturnLength; - } *input = capturedInputPointer; - - VERIFY_INPUT_LENGTH; - - status = KpiQueryInformationDriver( - input->DriverHandle, - input->DriverInformationClass, - input->DriverInformation, - input->DriverInformationLength, - input->ReturnLength, - accessMode - ); - } - break; - default: - status = STATUS_INVALID_DEVICE_REQUEST; - break; - } - -ControlEnd: - Irp->IoStatus.Status = status; - Irp->IoStatus.Information = 0; - IoCompleteRequest(Irp, IO_NO_INCREMENT); - - return status; -} +/* + * KProcessHacker + * + * Copyright (C) 2010-2016 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include + +NTSTATUS KphDispatchDeviceControl( + __in PDEVICE_OBJECT DeviceObject, + __in PIRP Irp + ) +{ + NTSTATUS status; + PIO_STACK_LOCATION stackLocation; + PFILE_OBJECT fileObject; + PKPH_CLIENT client; + PVOID originalInput; + ULONG inputLength; + ULONG ioControlCode; + KPROCESSOR_MODE accessMode; + UCHAR capturedInput[16 * sizeof(ULONG_PTR)]; + PVOID capturedInputPointer; + +#define VERIFY_INPUT_LENGTH \ + do { \ + /* Ensure at compile time that our local buffer fits this particular call. */ \ + C_ASSERT(sizeof(*input) <= sizeof(capturedInput)); \ + \ + if (inputLength != sizeof(*input)) \ + { \ + status = STATUS_INFO_LENGTH_MISMATCH; \ + goto ControlEnd; \ + } \ + } while (0) + + stackLocation = IoGetCurrentIrpStackLocation(Irp); + fileObject = stackLocation->FileObject; + client = fileObject->FsContext; + + originalInput = stackLocation->Parameters.DeviceIoControl.Type3InputBuffer; + inputLength = stackLocation->Parameters.DeviceIoControl.InputBufferLength; + ioControlCode = stackLocation->Parameters.DeviceIoControl.IoControlCode; + accessMode = Irp->RequestorMode; + + // Make sure we have a client object. + if (!client) + { + status = STATUS_INTERNAL_ERROR; + goto ControlEnd; + } + + // Enforce signature requirement if necessary. + if ((ioControlCode != KPH_GETFEATURES && ioControlCode != KPH_VERIFYCLIENT) && + (KphParameters.SecurityLevel == KphSecuritySignatureCheck || + KphParameters.SecurityLevel == KphSecuritySignatureAndPrivilegeCheck) && + !client->VerificationSucceeded) + { + status = STATUS_ACCESS_DENIED; + goto ControlEnd; + } + + // Make sure we actually have input if the input length is non-zero. + if (inputLength != 0 && !originalInput) + { + status = STATUS_INVALID_BUFFER_SIZE; + goto ControlEnd; + } + + // Make sure the caller isn't giving us a huge buffer. If they are, it can't be correct because + // we have a compile-time check that makes sure our buffer can store the arguments for all the + // calls. + if (inputLength > sizeof(capturedInput)) + { + status = STATUS_INVALID_BUFFER_SIZE; + goto ControlEnd; + } + + // Probe and capture the input buffer. + if (accessMode != KernelMode) + { + __try + { + ProbeForRead(originalInput, inputLength, sizeof(UCHAR)); + memcpy(capturedInput, originalInput, inputLength); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + status = GetExceptionCode(); + goto ControlEnd; + } + } + else + { + memcpy(capturedInput, originalInput, inputLength); + } + + capturedInputPointer = capturedInput; // avoid casting below + + switch (ioControlCode) + { + case KPH_GETFEATURES: + { + struct + { + PULONG Features; + } *input = capturedInputPointer; + + VERIFY_INPUT_LENGTH; + + status = KpiGetFeatures( + input->Features, + accessMode + ); + } + break; + case KPH_VERIFYCLIENT: + { + struct + { + PVOID CodeAddress; + PVOID Signature; + ULONG SignatureSize; + } *input = capturedInputPointer; + + VERIFY_INPUT_LENGTH; + + if (accessMode == UserMode) + { + status = KpiVerifyClient( + input->CodeAddress, + input->Signature, + input->SignatureSize, + client + ); + } + else + { + status = STATUS_UNSUCCESSFUL; + } + } + break; + case KPH_RETRIEVEKEY: + { + struct + { + KPH_KEY_LEVEL KeyLevel; + } *input = capturedInputPointer; + + VERIFY_INPUT_LENGTH; + + if (accessMode == UserMode) + { + status = KphRetrieveKeyViaApc( + client, + input->KeyLevel, + Irp + ); + } + else + { + status = STATUS_UNSUCCESSFUL; + } + } + break; + case KPH_OPENPROCESS: + { + struct + { + PHANDLE ProcessHandle; + ACCESS_MASK DesiredAccess; + PCLIENT_ID ClientId; + KPH_KEY Key; + } *input = capturedInputPointer; + + VERIFY_INPUT_LENGTH; + + status = KpiOpenProcess( + input->ProcessHandle, + input->DesiredAccess, + input->ClientId, + input->Key, + client, + accessMode + ); + } + break; + case KPH_OPENPROCESSTOKEN: + { + struct + { + HANDLE ProcessHandle; + ACCESS_MASK DesiredAccess; + PHANDLE TokenHandle; + KPH_KEY Key; + } *input = capturedInputPointer; + + VERIFY_INPUT_LENGTH; + + status = KpiOpenProcessToken( + input->ProcessHandle, + input->DesiredAccess, + input->TokenHandle, + input->Key, + client, + accessMode + ); + } + break; + case KPH_OPENPROCESSJOB: + { + struct + { + HANDLE ProcessHandle; + ACCESS_MASK DesiredAccess; + PHANDLE JobHandle; + } *input = capturedInputPointer; + + VERIFY_INPUT_LENGTH; + + status = KpiOpenProcessJob( + input->ProcessHandle, + input->DesiredAccess, + input->JobHandle, + accessMode + ); + } + break; + case KPH_TERMINATEPROCESS: + { + struct + { + HANDLE ProcessHandle; + NTSTATUS ExitStatus; + KPH_KEY Key; + } *input = capturedInputPointer; + + VERIFY_INPUT_LENGTH; + + status = KpiTerminateProcess( + input->ProcessHandle, + input->ExitStatus, + input->Key, + client, + accessMode + ); + } + break; + case KPH_READVIRTUALMEMORYUNSAFE: + { + struct + { + HANDLE ProcessHandle; + PVOID BaseAddress; + PVOID Buffer; + SIZE_T BufferSize; + PSIZE_T NumberOfBytesRead; + KPH_KEY Key; + } *input = capturedInputPointer; + + VERIFY_INPUT_LENGTH; + + status = KpiReadVirtualMemoryUnsafe( + input->ProcessHandle, + input->BaseAddress, + input->Buffer, + input->BufferSize, + input->NumberOfBytesRead, + input->Key, + client, + accessMode + ); + } + break; + case KPH_QUERYINFORMATIONPROCESS: + { + struct + { + HANDLE ProcessHandle; + KPH_PROCESS_INFORMATION_CLASS ProcessInformationClass; + PVOID ProcessInformation; + ULONG ProcessInformationLength; + PULONG ReturnLength; + } *input = capturedInputPointer; + + VERIFY_INPUT_LENGTH; + + status = KpiQueryInformationProcess( + input->ProcessHandle, + input->ProcessInformationClass, + input->ProcessInformation, + input->ProcessInformationLength, + input->ReturnLength, + accessMode + ); + } + break; + case KPH_SETINFORMATIONPROCESS: + { + struct + { + HANDLE ProcessHandle; + KPH_PROCESS_INFORMATION_CLASS ProcessInformationClass; + PVOID ProcessInformation; + ULONG ProcessInformationLength; + } *input = capturedInputPointer; + + VERIFY_INPUT_LENGTH; + + status = KpiSetInformationProcess( + input->ProcessHandle, + input->ProcessInformationClass, + input->ProcessInformation, + input->ProcessInformationLength, + accessMode + ); + } + break; + case KPH_OPENTHREAD: + { + struct + { + PHANDLE ThreadHandle; + ACCESS_MASK DesiredAccess; + PCLIENT_ID ClientId; + KPH_KEY Key; + } *input = capturedInputPointer; + + VERIFY_INPUT_LENGTH; + + status = KpiOpenThread( + input->ThreadHandle, + input->DesiredAccess, + input->ClientId, + input->Key, + client, + accessMode + ); + } + break; + case KPH_OPENTHREADPROCESS: + { + struct + { + HANDLE ThreadHandle; + ACCESS_MASK DesiredAccess; + PHANDLE ProcessHandle; + } *input = capturedInputPointer; + + VERIFY_INPUT_LENGTH; + + status = KpiOpenThreadProcess( + input->ThreadHandle, + input->DesiredAccess, + input->ProcessHandle, + accessMode + ); + } + break; + case KPH_CAPTURESTACKBACKTRACETHREAD: + { + struct + { + HANDLE ThreadHandle; + ULONG FramesToSkip; + ULONG FramesToCapture; + PVOID *BackTrace; + PULONG CapturedFrames; + PULONG BackTraceHash; + } *input = capturedInputPointer; + + VERIFY_INPUT_LENGTH; + + status = KpiCaptureStackBackTraceThread( + input->ThreadHandle, + input->FramesToSkip, + input->FramesToCapture, + input->BackTrace, + input->CapturedFrames, + input->BackTraceHash, + accessMode + ); + } + break; + case KPH_QUERYINFORMATIONTHREAD: + { + struct + { + HANDLE ThreadHandle; + KPH_THREAD_INFORMATION_CLASS ThreadInformationClass; + PVOID ThreadInformation; + ULONG ThreadInformationLength; + PULONG ReturnLength; + } *input = capturedInputPointer; + + VERIFY_INPUT_LENGTH; + + status = KpiQueryInformationThread( + input->ThreadHandle, + input->ThreadInformationClass, + input->ThreadInformation, + input->ThreadInformationLength, + input->ReturnLength, + accessMode + ); + } + break; + case KPH_SETINFORMATIONTHREAD: + { + struct + { + HANDLE ThreadHandle; + KPH_THREAD_INFORMATION_CLASS ThreadInformationClass; + PVOID ThreadInformation; + ULONG ThreadInformationLength; + } *input = capturedInputPointer; + + VERIFY_INPUT_LENGTH; + + status = KpiSetInformationThread( + input->ThreadHandle, + input->ThreadInformationClass, + input->ThreadInformation, + input->ThreadInformationLength, + accessMode + ); + } + break; + case KPH_ENUMERATEPROCESSHANDLES: + { + struct + { + HANDLE ProcessHandle; + PVOID Buffer; + ULONG BufferLength; + PULONG ReturnLength; + } *input = capturedInputPointer; + + VERIFY_INPUT_LENGTH; + + status = KpiEnumerateProcessHandles( + input->ProcessHandle, + input->Buffer, + input->BufferLength, + input->ReturnLength, + accessMode + ); + } + break; + case KPH_QUERYINFORMATIONOBJECT: + { + struct + { + HANDLE ProcessHandle; + HANDLE Handle; + KPH_OBJECT_INFORMATION_CLASS ObjectInformationClass; + PVOID ObjectInformation; + ULONG ObjectInformationLength; + PULONG ReturnLength; + } *input = capturedInputPointer; + + VERIFY_INPUT_LENGTH; + + status = KpiQueryInformationObject( + input->ProcessHandle, + input->Handle, + input->ObjectInformationClass, + input->ObjectInformation, + input->ObjectInformationLength, + input->ReturnLength, + accessMode + ); + } + break; + case KPH_SETINFORMATIONOBJECT: + { + struct + { + HANDLE ProcessHandle; + HANDLE Handle; + KPH_OBJECT_INFORMATION_CLASS ObjectInformationClass; + PVOID ObjectInformation; + ULONG ObjectInformationLength; + } *input = capturedInputPointer; + + VERIFY_INPUT_LENGTH; + + status = KpiSetInformationObject( + input->ProcessHandle, + input->Handle, + input->ObjectInformationClass, + input->ObjectInformation, + input->ObjectInformationLength, + accessMode + ); + } + break; + case KPH_OPENDRIVER: + { + struct + { + PHANDLE DriverHandle; + ACCESS_MASK DesiredAccess; + POBJECT_ATTRIBUTES ObjectAttributes; + } *input = capturedInputPointer; + + VERIFY_INPUT_LENGTH; + + status = KpiOpenDriver( + input->DriverHandle, + input->DesiredAccess, + input->ObjectAttributes, + accessMode + ); + } + break; + case KPH_QUERYINFORMATIONDRIVER: + { + struct + { + HANDLE DriverHandle; + DRIVER_INFORMATION_CLASS DriverInformationClass; + PVOID DriverInformation; + ULONG DriverInformationLength; + PULONG ReturnLength; + } *input = capturedInputPointer; + + VERIFY_INPUT_LENGTH; + + status = KpiQueryInformationDriver( + input->DriverHandle, + input->DriverInformationClass, + input->DriverInformation, + input->DriverInformationLength, + input->ReturnLength, + accessMode + ); + } + break; + default: + status = STATUS_INVALID_DEVICE_REQUEST; + break; + } + +ControlEnd: + Irp->IoStatus.Status = status; + Irp->IoStatus.Information = 0; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + return status; +} diff --git a/KProcessHacker/dyndata.c b/KProcessHacker/dyndata.c index 616e3aa7125c..40d4cfe5d470 100644 --- a/KProcessHacker/dyndata.c +++ b/KProcessHacker/dyndata.c @@ -1,167 +1,167 @@ -/* - * KProcessHacker - * - * Copyright (C) 2010-2016 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include -#define _DYNDATA_PRIVATE -#include - -#define C_2sTo4(x) ((unsigned int)(signed short)(x)) - -NTSTATUS KphpLoadDynamicConfiguration( - __in PVOID Buffer, - __in ULONG Length - ); - -#ifdef ALLOC_PRAGMA -#pragma alloc_text(PAGE, KphDynamicDataInitialization) -#pragma alloc_text(PAGE, KphReadDynamicDataParameters) -#pragma alloc_text(PAGE, KphpLoadDynamicConfiguration) -#endif - -NTSTATUS KphDynamicDataInitialization( - VOID - ) -{ - NTSTATUS status = STATUS_SUCCESS; - - PAGED_CODE(); - - // Get Windows version information. - - KphDynOsVersionInfo.dwOSVersionInfoSize = sizeof(RTL_OSVERSIONINFOEXW); - status = RtlGetVersion((PRTL_OSVERSIONINFOW)&KphDynOsVersionInfo); - - return status; -} - -NTSTATUS KphReadDynamicDataParameters( - __in_opt HANDLE KeyHandle - ) -{ - NTSTATUS status; - UNICODE_STRING valueName; - PKEY_VALUE_PARTIAL_INFORMATION info; - ULONG resultLength; - - PAGED_CODE(); - - if (!KeyHandle) - return STATUS_UNSUCCESSFUL; - - RtlInitUnicodeString(&valueName, L"DynamicConfiguration"); - - status = ZwQueryValueKey( - KeyHandle, - &valueName, - KeyValuePartialInformation, - NULL, - 0, - &resultLength - ); - - if (status != STATUS_BUFFER_OVERFLOW && status != STATUS_BUFFER_TOO_SMALL) - { - // Unexpected status; fail now. - return STATUS_UNSUCCESSFUL; - } - - info = ExAllocatePoolWithTag(PagedPool, resultLength, 'ThpK'); - - if (!info) - return STATUS_INSUFFICIENT_RESOURCES; - - status = ZwQueryValueKey( - KeyHandle, - &valueName, - KeyValuePartialInformation, - info, - resultLength, - &resultLength - ); - - if (NT_SUCCESS(status)) - { - if (info->Type == REG_BINARY) - status = KphpLoadDynamicConfiguration(info->Data, info->DataLength); - else - status = STATUS_OBJECT_TYPE_MISMATCH; - - if (!NT_SUCCESS(status)) - dprintf("Unable to load dynamic configuration: 0x%x\n", status); - } - - ExFreePoolWithTag(info, 'ThpK'); - - return status; -} - -NTSTATUS KphpLoadDynamicConfiguration( - __in PVOID Buffer, - __in ULONG Length - ) -{ - PKPH_DYN_CONFIGURATION config; - ULONG i; - PKPH_DYN_PACKAGE package; - - PAGED_CODE(); - - config = Buffer; - - if (Length < FIELD_OFFSET(KPH_DYN_CONFIGURATION, Packages)) - return STATUS_INVALID_PARAMETER; - if (config->Version != KPH_DYN_CONFIGURATION_VERSION) - return STATUS_INVALID_PARAMETER; - if (config->NumberOfPackages > KPH_DYN_MAXIMUM_PACKAGES) - return STATUS_INVALID_PARAMETER; - if (Length < FIELD_OFFSET(KPH_DYN_CONFIGURATION, Packages) + config->NumberOfPackages * sizeof(KPH_DYN_PACKAGE)) - return STATUS_INVALID_PARAMETER; - - dprintf("Loading dynamic configuration with %u package(s)\n", config->NumberOfPackages); - - for (i = 0; i < config->NumberOfPackages; i++) - { - package = &config->Packages[i]; - - if (package->MajorVersion == KphDynOsVersionInfo.dwMajorVersion && - package->MinorVersion == KphDynOsVersionInfo.dwMinorVersion && - (package->ServicePackMajor == (USHORT)-1 || package->ServicePackMajor == KphDynOsVersionInfo.wServicePackMajor) && - (package->BuildNumber == (USHORT)-1 || package->BuildNumber == KphDynOsVersionInfo.dwBuildNumber)) - { - dprintf("Found matching package at index %u for Windows %u.%u\n", i, package->MajorVersion, package->MinorVersion); - - KphDynNtVersion = package->ResultingNtVersion; - - KphDynEgeGuid = C_2sTo4(package->StructData.EgeGuid); - KphDynEpObjectTable = C_2sTo4(package->StructData.EpObjectTable); - KphDynEreGuidEntry = C_2sTo4(package->StructData.EreGuidEntry); - KphDynHtHandleContentionEvent = C_2sTo4(package->StructData.HtHandleContentionEvent); - KphDynOtName = C_2sTo4(package->StructData.OtName); - KphDynOtIndex = C_2sTo4(package->StructData.OtIndex); - KphDynObDecodeShift = C_2sTo4(package->StructData.ObDecodeShift); - KphDynObAttributesShift = C_2sTo4(package->StructData.ObAttributesShift); - - return STATUS_SUCCESS; - } - } - - return STATUS_NOT_FOUND; -} +/* + * KProcessHacker + * + * Copyright (C) 2010-2016 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include +#define _DYNDATA_PRIVATE +#include + +#define C_2sTo4(x) ((unsigned int)(signed short)(x)) + +NTSTATUS KphpLoadDynamicConfiguration( + __in PVOID Buffer, + __in ULONG Length + ); + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGE, KphDynamicDataInitialization) +#pragma alloc_text(PAGE, KphReadDynamicDataParameters) +#pragma alloc_text(PAGE, KphpLoadDynamicConfiguration) +#endif + +NTSTATUS KphDynamicDataInitialization( + VOID + ) +{ + NTSTATUS status = STATUS_SUCCESS; + + PAGED_CODE(); + + // Get Windows version information. + + KphDynOsVersionInfo.dwOSVersionInfoSize = sizeof(RTL_OSVERSIONINFOEXW); + status = RtlGetVersion((PRTL_OSVERSIONINFOW)&KphDynOsVersionInfo); + + return status; +} + +NTSTATUS KphReadDynamicDataParameters( + __in_opt HANDLE KeyHandle + ) +{ + NTSTATUS status; + UNICODE_STRING valueName; + PKEY_VALUE_PARTIAL_INFORMATION info; + ULONG resultLength; + + PAGED_CODE(); + + if (!KeyHandle) + return STATUS_UNSUCCESSFUL; + + RtlInitUnicodeString(&valueName, L"DynamicConfiguration"); + + status = ZwQueryValueKey( + KeyHandle, + &valueName, + KeyValuePartialInformation, + NULL, + 0, + &resultLength + ); + + if (status != STATUS_BUFFER_OVERFLOW && status != STATUS_BUFFER_TOO_SMALL) + { + // Unexpected status; fail now. + return STATUS_UNSUCCESSFUL; + } + + info = ExAllocatePoolWithTag(PagedPool, resultLength, 'ThpK'); + + if (!info) + return STATUS_INSUFFICIENT_RESOURCES; + + status = ZwQueryValueKey( + KeyHandle, + &valueName, + KeyValuePartialInformation, + info, + resultLength, + &resultLength + ); + + if (NT_SUCCESS(status)) + { + if (info->Type == REG_BINARY) + status = KphpLoadDynamicConfiguration(info->Data, info->DataLength); + else + status = STATUS_OBJECT_TYPE_MISMATCH; + + if (!NT_SUCCESS(status)) + dprintf("Unable to load dynamic configuration: 0x%x\n", status); + } + + ExFreePoolWithTag(info, 'ThpK'); + + return status; +} + +NTSTATUS KphpLoadDynamicConfiguration( + __in PVOID Buffer, + __in ULONG Length + ) +{ + PKPH_DYN_CONFIGURATION config; + ULONG i; + PKPH_DYN_PACKAGE package; + + PAGED_CODE(); + + config = Buffer; + + if (Length < FIELD_OFFSET(KPH_DYN_CONFIGURATION, Packages)) + return STATUS_INVALID_PARAMETER; + if (config->Version != KPH_DYN_CONFIGURATION_VERSION) + return STATUS_INVALID_PARAMETER; + if (config->NumberOfPackages > KPH_DYN_MAXIMUM_PACKAGES) + return STATUS_INVALID_PARAMETER; + if (Length < FIELD_OFFSET(KPH_DYN_CONFIGURATION, Packages) + config->NumberOfPackages * sizeof(KPH_DYN_PACKAGE)) + return STATUS_INVALID_PARAMETER; + + dprintf("Loading dynamic configuration with %u package(s)\n", config->NumberOfPackages); + + for (i = 0; i < config->NumberOfPackages; i++) + { + package = &config->Packages[i]; + + if (package->MajorVersion == KphDynOsVersionInfo.dwMajorVersion && + package->MinorVersion == KphDynOsVersionInfo.dwMinorVersion && + (package->ServicePackMajor == (USHORT)-1 || package->ServicePackMajor == KphDynOsVersionInfo.wServicePackMajor) && + (package->BuildNumber == (USHORT)-1 || package->BuildNumber == KphDynOsVersionInfo.dwBuildNumber)) + { + dprintf("Found matching package at index %u for Windows %u.%u\n", i, package->MajorVersion, package->MinorVersion); + + KphDynNtVersion = package->ResultingNtVersion; + + KphDynEgeGuid = C_2sTo4(package->StructData.EgeGuid); + KphDynEpObjectTable = C_2sTo4(package->StructData.EpObjectTable); + KphDynEreGuidEntry = C_2sTo4(package->StructData.EreGuidEntry); + KphDynHtHandleContentionEvent = C_2sTo4(package->StructData.HtHandleContentionEvent); + KphDynOtName = C_2sTo4(package->StructData.OtName); + KphDynOtIndex = C_2sTo4(package->StructData.OtIndex); + KphDynObDecodeShift = C_2sTo4(package->StructData.ObDecodeShift); + KphDynObAttributesShift = C_2sTo4(package->StructData.ObAttributesShift); + + return STATUS_SUCCESS; + } + } + + return STATUS_NOT_FOUND; +} diff --git a/KProcessHacker/dynimp.c b/KProcessHacker/dynimp.c index 979364464879..d432611a3ca8 100644 --- a/KProcessHacker/dynimp.c +++ b/KProcessHacker/dynimp.c @@ -1,60 +1,60 @@ -/* - * KProcessHacker - * - * Copyright (C) 2010-2016 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include -#include - -#ifdef ALLOC_PRAGMA -#pragma alloc_text(PAGE, KphGetSystemRoutineAddress) -#pragma alloc_text(PAGE, KphDynamicImport) -#endif - -/** - * Dynamically imports routines. - */ -VOID KphDynamicImport( - VOID - ) -{ - PAGED_CODE(); - NOTHING; -} - -/** - * Retrieves the address of a function exported by NTOS or HAL. - * - * \param SystemRoutineName The name of the function. - * - * \return The address of the function, or NULL if the function could - * not be found. - */ -PVOID KphGetSystemRoutineAddress( - __in PWSTR SystemRoutineName - ) -{ - UNICODE_STRING systemRoutineName; - - PAGED_CODE(); - - RtlInitUnicodeString(&systemRoutineName, SystemRoutineName); - - return MmGetSystemRoutineAddress(&systemRoutineName); -} +/* + * KProcessHacker + * + * Copyright (C) 2010-2016 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include +#include + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGE, KphGetSystemRoutineAddress) +#pragma alloc_text(PAGE, KphDynamicImport) +#endif + +/** + * Dynamically imports routines. + */ +VOID KphDynamicImport( + VOID + ) +{ + PAGED_CODE(); + NOTHING; +} + +/** + * Retrieves the address of a function exported by NTOS or HAL. + * + * \param SystemRoutineName The name of the function. + * + * \return The address of the function, or NULL if the function could + * not be found. + */ +PVOID KphGetSystemRoutineAddress( + __in PWSTR SystemRoutineName + ) +{ + UNICODE_STRING systemRoutineName; + + PAGED_CODE(); + + RtlInitUnicodeString(&systemRoutineName, SystemRoutineName); + + return MmGetSystemRoutineAddress(&systemRoutineName); +} diff --git a/KProcessHacker/include/dyndata.h b/KProcessHacker/include/dyndata.h index a9ba65dec015..d31f0f0e10e7 100644 --- a/KProcessHacker/include/dyndata.h +++ b/KProcessHacker/include/dyndata.h @@ -1,47 +1,47 @@ -#ifndef DYNDATA_H -#define DYNDATA_H - -#ifdef EXT -#undef EXT -#endif - -#ifdef _DYNDATA_PRIVATE -#define EXT -#define OFFDEFAULT = -1 -#else -#define EXT extern -#define OFFDEFAULT -#endif - -EXT ULONG KphDynNtVersion; -EXT RTL_OSVERSIONINFOEXW KphDynOsVersionInfo; - -// Structures -// Ege: ETW_GUID_ENTRY -// Ep: EPROCESS -// Ere: ETW_REG_ENTRY -// Et: ETHREAD -// Ht: HANDLE_TABLE -// Oh: OBJECT_HEADER -// Ot: OBJECT_TYPE -// Oti: OBJECT_TYPE_INITIALIZER, offset measured from an OBJECT_TYPE -// ObDecodeShift: shift value in ObpDecodeObject -// ObAttributesShift: shift value in ObpGetHandleAttributes -EXT ULONG KphDynEgeGuid OFFDEFAULT; -EXT ULONG KphDynEpObjectTable OFFDEFAULT; -EXT ULONG KphDynEreGuidEntry OFFDEFAULT; -EXT ULONG KphDynHtHandleContentionEvent OFFDEFAULT; -EXT ULONG KphDynOtName OFFDEFAULT; -EXT ULONG KphDynOtIndex OFFDEFAULT; -EXT ULONG KphDynObDecodeShift OFFDEFAULT; -EXT ULONG KphDynObAttributesShift OFFDEFAULT; - -NTSTATUS KphDynamicDataInitialization( - VOID - ); - -NTSTATUS KphReadDynamicDataParameters( - __in_opt HANDLE KeyHandle - ); - -#endif +#ifndef DYNDATA_H +#define DYNDATA_H + +#ifdef EXT +#undef EXT +#endif + +#ifdef _DYNDATA_PRIVATE +#define EXT +#define OFFDEFAULT = -1 +#else +#define EXT extern +#define OFFDEFAULT +#endif + +EXT ULONG KphDynNtVersion; +EXT RTL_OSVERSIONINFOEXW KphDynOsVersionInfo; + +// Structures +// Ege: ETW_GUID_ENTRY +// Ep: EPROCESS +// Ere: ETW_REG_ENTRY +// Et: ETHREAD +// Ht: HANDLE_TABLE +// Oh: OBJECT_HEADER +// Ot: OBJECT_TYPE +// Oti: OBJECT_TYPE_INITIALIZER, offset measured from an OBJECT_TYPE +// ObDecodeShift: shift value in ObpDecodeObject +// ObAttributesShift: shift value in ObpGetHandleAttributes +EXT ULONG KphDynEgeGuid OFFDEFAULT; +EXT ULONG KphDynEpObjectTable OFFDEFAULT; +EXT ULONG KphDynEreGuidEntry OFFDEFAULT; +EXT ULONG KphDynHtHandleContentionEvent OFFDEFAULT; +EXT ULONG KphDynOtName OFFDEFAULT; +EXT ULONG KphDynOtIndex OFFDEFAULT; +EXT ULONG KphDynObDecodeShift OFFDEFAULT; +EXT ULONG KphDynObAttributesShift OFFDEFAULT; + +NTSTATUS KphDynamicDataInitialization( + VOID + ); + +NTSTATUS KphReadDynamicDataParameters( + __in_opt HANDLE KeyHandle + ); + +#endif diff --git a/KProcessHacker/include/kph.h b/KProcessHacker/include/kph.h index 1d196675dfd0..8ee115f9b7ab 100644 --- a/KProcessHacker/include/kph.h +++ b/KProcessHacker/include/kph.h @@ -1,365 +1,365 @@ -#ifndef KPH_H -#define KPH_H - -#include -#define PHNT_MODE PHNT_MODE_KERNEL -#include -#include -#include -#include - -// Debugging - -#ifdef DBG -#define dprintf(Format, ...) DbgPrint("KProcessHacker: " Format, __VA_ARGS__) -#else -#define dprintf -#endif - -typedef struct _KPH_CLIENT -{ - struct - { - ULONG VerificationPerformed : 1; - ULONG VerificationSucceeded : 1; - ULONG KeysGenerated : 1; - ULONG SpareBits : 29; - }; - FAST_MUTEX StateMutex; - NTSTATUS VerificationStatus; - PVOID VerifiedProcess; // EPROCESS (for equality checking only - do not access contents) - HANDLE VerifiedProcessId; - PVOID VerifiedRangeBase; - SIZE_T VerifiedRangeSize; - // Level 1 and 2 secret keys - FAST_MUTEX KeyBackoffMutex; - KPH_KEY L1Key; - KPH_KEY L2Key; -} KPH_CLIENT, *PKPH_CLIENT; - -typedef struct _KPH_PARAMETERS -{ - KPH_SECURITY_LEVEL SecurityLevel; -} KPH_PARAMETERS, *PKPH_PARAMETERS; - -// main - -extern ULONG KphFeatures; -extern KPH_PARAMETERS KphParameters; - -NTSTATUS KpiGetFeatures( - __out PULONG Features, - __in KPROCESSOR_MODE AccessMode - ); - -// devctrl - -__drv_dispatchType(IRP_MJ_DEVICE_CONTROL) DRIVER_DISPATCH KphDispatchDeviceControl; - -NTSTATUS KphDispatchDeviceControl( - __in PDEVICE_OBJECT DeviceObject, - __in PIRP Irp - ); - -// dynimp - -VOID KphDynamicImport( - VOID - ); - -PVOID KphGetSystemRoutineAddress( - __in PWSTR SystemRoutineName - ); - -// object - -PHANDLE_TABLE KphReferenceProcessHandleTable( - __in PEPROCESS Process - ); - -VOID KphDereferenceProcessHandleTable( - __in PEPROCESS Process - ); - -VOID KphUnlockHandleTableEntry( - __in PHANDLE_TABLE HandleTable, - __in PHANDLE_TABLE_ENTRY HandleTableEntry - ); - -NTSTATUS KpiEnumerateProcessHandles( - __in HANDLE ProcessHandle, - __out_bcount(BufferLength) PVOID Buffer, - __in_opt ULONG BufferLength, - __out_opt PULONG ReturnLength, - __in KPROCESSOR_MODE AccessMode - ); - -NTSTATUS KphQueryNameObject( - __in PVOID Object, - __out_bcount(BufferLength) POBJECT_NAME_INFORMATION Buffer, - __in ULONG BufferLength, - __out PULONG ReturnLength - ); - -NTSTATUS KphQueryNameFileObject( - __in PFILE_OBJECT FileObject, - __out_bcount(BufferLength) POBJECT_NAME_INFORMATION Buffer, - __in ULONG BufferLength, - __out PULONG ReturnLength - ); - -NTSTATUS KpiQueryInformationObject( - __in HANDLE ProcessHandle, - __in HANDLE Handle, - __in KPH_OBJECT_INFORMATION_CLASS ObjectInformationClass, - __out_bcount(ObjectInformationLength) PVOID ObjectInformation, - __in ULONG ObjectInformationLength, - __out_opt PULONG ReturnLength, - __in KPROCESSOR_MODE AccessMode - ); - -NTSTATUS KpiSetInformationObject( - __in HANDLE ProcessHandle, - __in HANDLE Handle, - __in KPH_OBJECT_INFORMATION_CLASS ObjectInformationClass, - __in_bcount(ObjectInformationLength) PVOID ObjectInformation, - __in ULONG ObjectInformationLength, - __in KPROCESSOR_MODE AccessMode - ); - -NTSTATUS KphOpenNamedObject( - __out PHANDLE ObjectHandle, - __in ACCESS_MASK DesiredAccess, - __in POBJECT_ATTRIBUTES ObjectAttributes, - __in POBJECT_TYPE ObjectType, - __in KPROCESSOR_MODE AccessMode - ); - -// process - -NTSTATUS KpiOpenProcess( - __out PHANDLE ProcessHandle, - __in ACCESS_MASK DesiredAccess, - __in PCLIENT_ID ClientId, - __in_opt KPH_KEY Key, - __in PKPH_CLIENT Client, - __in KPROCESSOR_MODE AccessMode - ); - -NTSTATUS KpiOpenProcessToken( - __in HANDLE ProcessHandle, - __in ACCESS_MASK DesiredAccess, - __out PHANDLE TokenHandle, - __in_opt KPH_KEY Key, - __in PKPH_CLIENT Client, - __in KPROCESSOR_MODE AccessMode - ); - -NTSTATUS KpiOpenProcessJob( - __in HANDLE ProcessHandle, - __in ACCESS_MASK DesiredAccess, - __out PHANDLE JobHandle, - __in KPROCESSOR_MODE AccessMode - ); - -NTSTATUS KpiTerminateProcess( - __in HANDLE ProcessHandle, - __in NTSTATUS ExitStatus, - __in_opt KPH_KEY Key, - __in PKPH_CLIENT Client, - __in KPROCESSOR_MODE AccessMode - ); - -NTSTATUS KpiQueryInformationProcess( - __in HANDLE ProcessHandle, - __in KPH_PROCESS_INFORMATION_CLASS ProcessInformationClass, - __out_bcount(ProcessInformationLength) PVOID ProcessInformation, - __in ULONG ProcessInformationLength, - __out_opt PULONG ReturnLength, - __in KPROCESSOR_MODE AccessMode - ); - -NTSTATUS KpiSetInformationProcess( - __in HANDLE ProcessHandle, - __in KPH_PROCESS_INFORMATION_CLASS ProcessInformationClass, - __in_bcount(ProcessInformationLength) PVOID ProcessInformation, - __in ULONG ProcessInformationLength, - __in KPROCESSOR_MODE AccessMode - ); - -// qrydrv - -NTSTATUS KpiOpenDriver( - __out PHANDLE DriverHandle, - __in ACCESS_MASK DesiredAccess, - __in POBJECT_ATTRIBUTES ObjectAttributes, - __in KPROCESSOR_MODE AccessMode - ); - -NTSTATUS KpiQueryInformationDriver( - __in HANDLE DriverHandle, - __in DRIVER_INFORMATION_CLASS DriverInformationClass, - __out_bcount(DriverInformationLength) PVOID DriverInformation, - __in ULONG DriverInformationLength, - __out_opt PULONG ReturnLength, - __in KPROCESSOR_MODE AccessMode - ); - -// thread - -NTSTATUS KpiOpenThread( - __out PHANDLE ThreadHandle, - __in ACCESS_MASK DesiredAccess, - __in PCLIENT_ID ClientId, - __in_opt KPH_KEY Key, - __in PKPH_CLIENT Client, - __in KPROCESSOR_MODE AccessMode - ); - -NTSTATUS KpiOpenThreadProcess( - __in HANDLE ThreadHandle, - __in ACCESS_MASK DesiredAccess, - __out PHANDLE ProcessHandle, - __in KPROCESSOR_MODE AccessMode - ); - -ULONG KphCaptureStackBackTrace( - __in ULONG FramesToSkip, - __in ULONG FramesToCapture, - __in_opt ULONG Flags, - __out_ecount(FramesToCapture) PVOID *BackTrace, - __out_opt PULONG BackTraceHash - ); - -NTSTATUS KphCaptureStackBackTraceThread( - __in PETHREAD Thread, - __in ULONG FramesToSkip, - __in ULONG FramesToCapture, - __out_ecount(FramesToCapture) PVOID *BackTrace, - __out_opt PULONG CapturedFrames, - __out_opt PULONG BackTraceHash, - __in KPROCESSOR_MODE AccessMode - ); - -NTSTATUS KpiCaptureStackBackTraceThread( - __in HANDLE ThreadHandle, - __in ULONG FramesToSkip, - __in ULONG FramesToCapture, - __out_ecount(FramesToCapture) PVOID *BackTrace, - __out_opt PULONG CapturedFrames, - __out_opt PULONG BackTraceHash, - __in KPROCESSOR_MODE AccessMode - ); - -NTSTATUS KpiQueryInformationThread( - __in HANDLE ThreadHandle, - __in KPH_THREAD_INFORMATION_CLASS ThreadInformationClass, - __out_bcount(ProcessInformationLength) PVOID ThreadInformation, - __in ULONG ThreadInformationLength, - __out_opt PULONG ReturnLength, - __in KPROCESSOR_MODE AccessMode - ); - -NTSTATUS KpiSetInformationThread( - __in HANDLE ThreadHandle, - __in KPH_THREAD_INFORMATION_CLASS ThreadInformationClass, - __in_bcount(ThreadInformationLength) PVOID ThreadInformation, - __in ULONG ThreadInformationLength, - __in KPROCESSOR_MODE AccessMode - ); - -// util - -VOID KphFreeCapturedUnicodeString( - __in PUNICODE_STRING CapturedUnicodeString - ); - -NTSTATUS KphCaptureUnicodeString( - __in PUNICODE_STRING UnicodeString, - __out PUNICODE_STRING CapturedUnicodeString - ); - -NTSTATUS KphEnumerateSystemModules( - __out PRTL_PROCESS_MODULES *Modules - ); - -NTSTATUS KphValidateAddressForSystemModules( - __in PVOID Address, - __in SIZE_T Length - ); - -NTSTATUS KphGetProcessMappedFileName( - __in HANDLE ProcessHandle, - __in PVOID BaseAddress, - __out PUNICODE_STRING *FileName - ); - -// verify - -NTSTATUS KphHashFile( - __in PUNICODE_STRING FileName, - __out PVOID *Hash, - __out PULONG HashSize - ); - -NTSTATUS KphVerifyFile( - __in PUNICODE_STRING FileName, - __in_bcount(SignatureSize) PUCHAR Signature, - __in ULONG SignatureSize - ); - -VOID KphVerifyClient( - __inout PKPH_CLIENT Client, - __in PVOID CodeAddress, - __in_bcount(SignatureSize) PUCHAR Signature, - __in ULONG SignatureSize - ); - -NTSTATUS KpiVerifyClient( - __in PVOID CodeAddress, - __in_bcount(SignatureSize) PUCHAR Signature, - __in ULONG SignatureSize, - __in PKPH_CLIENT Client - ); - -VOID KphGenerateKeysClient( - __inout PKPH_CLIENT Client - ); - -NTSTATUS KphRetrieveKeyViaApc( - __inout PKPH_CLIENT Client, - __in KPH_KEY_LEVEL KeyLevel, - __inout PIRP Irp - ); - -NTSTATUS KphValidateKey( - __in KPH_KEY_LEVEL RequiredKeyLevel, - __in_opt KPH_KEY Key, - __in PKPH_CLIENT Client, - __in KPROCESSOR_MODE AccessMode - ); - -// vm - -NTSTATUS KphCopyVirtualMemory( - __in PEPROCESS FromProcess, - __in PVOID FromAddress, - __in PEPROCESS ToProcess, - __in PVOID ToAddress, - __in SIZE_T BufferLength, - __in KPROCESSOR_MODE AccessMode, - __out PSIZE_T ReturnLength - ); - -NTSTATUS KpiReadVirtualMemoryUnsafe( - __in_opt HANDLE ProcessHandle, - __in PVOID BaseAddress, - __out_bcount(BufferSize) PVOID Buffer, - __in SIZE_T BufferSize, - __out_opt PSIZE_T NumberOfBytesRead, - __in_opt KPH_KEY Key, - __in PKPH_CLIENT Client, - __in KPROCESSOR_MODE AccessMode - ); - -#endif +#ifndef KPH_H +#define KPH_H + +#include +#define PHNT_MODE PHNT_MODE_KERNEL +#include +#include +#include +#include + +// Debugging + +#ifdef DBG +#define dprintf(Format, ...) DbgPrint("KProcessHacker: " Format, __VA_ARGS__) +#else +#define dprintf +#endif + +typedef struct _KPH_CLIENT +{ + struct + { + ULONG VerificationPerformed : 1; + ULONG VerificationSucceeded : 1; + ULONG KeysGenerated : 1; + ULONG SpareBits : 29; + }; + FAST_MUTEX StateMutex; + NTSTATUS VerificationStatus; + PVOID VerifiedProcess; // EPROCESS (for equality checking only - do not access contents) + HANDLE VerifiedProcessId; + PVOID VerifiedRangeBase; + SIZE_T VerifiedRangeSize; + // Level 1 and 2 secret keys + FAST_MUTEX KeyBackoffMutex; + KPH_KEY L1Key; + KPH_KEY L2Key; +} KPH_CLIENT, *PKPH_CLIENT; + +typedef struct _KPH_PARAMETERS +{ + KPH_SECURITY_LEVEL SecurityLevel; +} KPH_PARAMETERS, *PKPH_PARAMETERS; + +// main + +extern ULONG KphFeatures; +extern KPH_PARAMETERS KphParameters; + +NTSTATUS KpiGetFeatures( + __out PULONG Features, + __in KPROCESSOR_MODE AccessMode + ); + +// devctrl + +__drv_dispatchType(IRP_MJ_DEVICE_CONTROL) DRIVER_DISPATCH KphDispatchDeviceControl; + +NTSTATUS KphDispatchDeviceControl( + __in PDEVICE_OBJECT DeviceObject, + __in PIRP Irp + ); + +// dynimp + +VOID KphDynamicImport( + VOID + ); + +PVOID KphGetSystemRoutineAddress( + __in PWSTR SystemRoutineName + ); + +// object + +PHANDLE_TABLE KphReferenceProcessHandleTable( + __in PEPROCESS Process + ); + +VOID KphDereferenceProcessHandleTable( + __in PEPROCESS Process + ); + +VOID KphUnlockHandleTableEntry( + __in PHANDLE_TABLE HandleTable, + __in PHANDLE_TABLE_ENTRY HandleTableEntry + ); + +NTSTATUS KpiEnumerateProcessHandles( + __in HANDLE ProcessHandle, + __out_bcount(BufferLength) PVOID Buffer, + __in_opt ULONG BufferLength, + __out_opt PULONG ReturnLength, + __in KPROCESSOR_MODE AccessMode + ); + +NTSTATUS KphQueryNameObject( + __in PVOID Object, + __out_bcount(BufferLength) POBJECT_NAME_INFORMATION Buffer, + __in ULONG BufferLength, + __out PULONG ReturnLength + ); + +NTSTATUS KphQueryNameFileObject( + __in PFILE_OBJECT FileObject, + __out_bcount(BufferLength) POBJECT_NAME_INFORMATION Buffer, + __in ULONG BufferLength, + __out PULONG ReturnLength + ); + +NTSTATUS KpiQueryInformationObject( + __in HANDLE ProcessHandle, + __in HANDLE Handle, + __in KPH_OBJECT_INFORMATION_CLASS ObjectInformationClass, + __out_bcount(ObjectInformationLength) PVOID ObjectInformation, + __in ULONG ObjectInformationLength, + __out_opt PULONG ReturnLength, + __in KPROCESSOR_MODE AccessMode + ); + +NTSTATUS KpiSetInformationObject( + __in HANDLE ProcessHandle, + __in HANDLE Handle, + __in KPH_OBJECT_INFORMATION_CLASS ObjectInformationClass, + __in_bcount(ObjectInformationLength) PVOID ObjectInformation, + __in ULONG ObjectInformationLength, + __in KPROCESSOR_MODE AccessMode + ); + +NTSTATUS KphOpenNamedObject( + __out PHANDLE ObjectHandle, + __in ACCESS_MASK DesiredAccess, + __in POBJECT_ATTRIBUTES ObjectAttributes, + __in POBJECT_TYPE ObjectType, + __in KPROCESSOR_MODE AccessMode + ); + +// process + +NTSTATUS KpiOpenProcess( + __out PHANDLE ProcessHandle, + __in ACCESS_MASK DesiredAccess, + __in PCLIENT_ID ClientId, + __in_opt KPH_KEY Key, + __in PKPH_CLIENT Client, + __in KPROCESSOR_MODE AccessMode + ); + +NTSTATUS KpiOpenProcessToken( + __in HANDLE ProcessHandle, + __in ACCESS_MASK DesiredAccess, + __out PHANDLE TokenHandle, + __in_opt KPH_KEY Key, + __in PKPH_CLIENT Client, + __in KPROCESSOR_MODE AccessMode + ); + +NTSTATUS KpiOpenProcessJob( + __in HANDLE ProcessHandle, + __in ACCESS_MASK DesiredAccess, + __out PHANDLE JobHandle, + __in KPROCESSOR_MODE AccessMode + ); + +NTSTATUS KpiTerminateProcess( + __in HANDLE ProcessHandle, + __in NTSTATUS ExitStatus, + __in_opt KPH_KEY Key, + __in PKPH_CLIENT Client, + __in KPROCESSOR_MODE AccessMode + ); + +NTSTATUS KpiQueryInformationProcess( + __in HANDLE ProcessHandle, + __in KPH_PROCESS_INFORMATION_CLASS ProcessInformationClass, + __out_bcount(ProcessInformationLength) PVOID ProcessInformation, + __in ULONG ProcessInformationLength, + __out_opt PULONG ReturnLength, + __in KPROCESSOR_MODE AccessMode + ); + +NTSTATUS KpiSetInformationProcess( + __in HANDLE ProcessHandle, + __in KPH_PROCESS_INFORMATION_CLASS ProcessInformationClass, + __in_bcount(ProcessInformationLength) PVOID ProcessInformation, + __in ULONG ProcessInformationLength, + __in KPROCESSOR_MODE AccessMode + ); + +// qrydrv + +NTSTATUS KpiOpenDriver( + __out PHANDLE DriverHandle, + __in ACCESS_MASK DesiredAccess, + __in POBJECT_ATTRIBUTES ObjectAttributes, + __in KPROCESSOR_MODE AccessMode + ); + +NTSTATUS KpiQueryInformationDriver( + __in HANDLE DriverHandle, + __in DRIVER_INFORMATION_CLASS DriverInformationClass, + __out_bcount(DriverInformationLength) PVOID DriverInformation, + __in ULONG DriverInformationLength, + __out_opt PULONG ReturnLength, + __in KPROCESSOR_MODE AccessMode + ); + +// thread + +NTSTATUS KpiOpenThread( + __out PHANDLE ThreadHandle, + __in ACCESS_MASK DesiredAccess, + __in PCLIENT_ID ClientId, + __in_opt KPH_KEY Key, + __in PKPH_CLIENT Client, + __in KPROCESSOR_MODE AccessMode + ); + +NTSTATUS KpiOpenThreadProcess( + __in HANDLE ThreadHandle, + __in ACCESS_MASK DesiredAccess, + __out PHANDLE ProcessHandle, + __in KPROCESSOR_MODE AccessMode + ); + +ULONG KphCaptureStackBackTrace( + __in ULONG FramesToSkip, + __in ULONG FramesToCapture, + __in_opt ULONG Flags, + __out_ecount(FramesToCapture) PVOID *BackTrace, + __out_opt PULONG BackTraceHash + ); + +NTSTATUS KphCaptureStackBackTraceThread( + __in PETHREAD Thread, + __in ULONG FramesToSkip, + __in ULONG FramesToCapture, + __out_ecount(FramesToCapture) PVOID *BackTrace, + __out_opt PULONG CapturedFrames, + __out_opt PULONG BackTraceHash, + __in KPROCESSOR_MODE AccessMode + ); + +NTSTATUS KpiCaptureStackBackTraceThread( + __in HANDLE ThreadHandle, + __in ULONG FramesToSkip, + __in ULONG FramesToCapture, + __out_ecount(FramesToCapture) PVOID *BackTrace, + __out_opt PULONG CapturedFrames, + __out_opt PULONG BackTraceHash, + __in KPROCESSOR_MODE AccessMode + ); + +NTSTATUS KpiQueryInformationThread( + __in HANDLE ThreadHandle, + __in KPH_THREAD_INFORMATION_CLASS ThreadInformationClass, + __out_bcount(ProcessInformationLength) PVOID ThreadInformation, + __in ULONG ThreadInformationLength, + __out_opt PULONG ReturnLength, + __in KPROCESSOR_MODE AccessMode + ); + +NTSTATUS KpiSetInformationThread( + __in HANDLE ThreadHandle, + __in KPH_THREAD_INFORMATION_CLASS ThreadInformationClass, + __in_bcount(ThreadInformationLength) PVOID ThreadInformation, + __in ULONG ThreadInformationLength, + __in KPROCESSOR_MODE AccessMode + ); + +// util + +VOID KphFreeCapturedUnicodeString( + __in PUNICODE_STRING CapturedUnicodeString + ); + +NTSTATUS KphCaptureUnicodeString( + __in PUNICODE_STRING UnicodeString, + __out PUNICODE_STRING CapturedUnicodeString + ); + +NTSTATUS KphEnumerateSystemModules( + __out PRTL_PROCESS_MODULES *Modules + ); + +NTSTATUS KphValidateAddressForSystemModules( + __in PVOID Address, + __in SIZE_T Length + ); + +NTSTATUS KphGetProcessMappedFileName( + __in HANDLE ProcessHandle, + __in PVOID BaseAddress, + __out PUNICODE_STRING *FileName + ); + +// verify + +NTSTATUS KphHashFile( + __in PUNICODE_STRING FileName, + __out PVOID *Hash, + __out PULONG HashSize + ); + +NTSTATUS KphVerifyFile( + __in PUNICODE_STRING FileName, + __in_bcount(SignatureSize) PUCHAR Signature, + __in ULONG SignatureSize + ); + +VOID KphVerifyClient( + __inout PKPH_CLIENT Client, + __in PVOID CodeAddress, + __in_bcount(SignatureSize) PUCHAR Signature, + __in ULONG SignatureSize + ); + +NTSTATUS KpiVerifyClient( + __in PVOID CodeAddress, + __in_bcount(SignatureSize) PUCHAR Signature, + __in ULONG SignatureSize, + __in PKPH_CLIENT Client + ); + +VOID KphGenerateKeysClient( + __inout PKPH_CLIENT Client + ); + +NTSTATUS KphRetrieveKeyViaApc( + __inout PKPH_CLIENT Client, + __in KPH_KEY_LEVEL KeyLevel, + __inout PIRP Irp + ); + +NTSTATUS KphValidateKey( + __in KPH_KEY_LEVEL RequiredKeyLevel, + __in_opt KPH_KEY Key, + __in PKPH_CLIENT Client, + __in KPROCESSOR_MODE AccessMode + ); + +// vm + +NTSTATUS KphCopyVirtualMemory( + __in PEPROCESS FromProcess, + __in PVOID FromAddress, + __in PEPROCESS ToProcess, + __in PVOID ToAddress, + __in SIZE_T BufferLength, + __in KPROCESSOR_MODE AccessMode, + __out PSIZE_T ReturnLength + ); + +NTSTATUS KpiReadVirtualMemoryUnsafe( + __in_opt HANDLE ProcessHandle, + __in PVOID BaseAddress, + __out_bcount(BufferSize) PVOID Buffer, + __in SIZE_T BufferSize, + __out_opt PSIZE_T NumberOfBytesRead, + __in_opt KPH_KEY Key, + __in PKPH_CLIENT Client, + __in KPROCESSOR_MODE AccessMode + ); + +#endif diff --git a/KProcessHacker/include/ntfill.h b/KProcessHacker/include/ntfill.h index f430f49983e5..865bbe877cb1 100644 --- a/KProcessHacker/include/ntfill.h +++ b/KProcessHacker/include/ntfill.h @@ -1,351 +1,351 @@ -#ifndef NTFILL_H -#define NTFILL_H - -extern ULONG KphDynNtVersion; -extern ULONG KphDynObDecodeShift; -extern ULONG KphDynObAttributesShift; - -// EX - -typedef struct _EX_PUSH_LOCK_WAIT_BLOCK *PEX_PUSH_LOCK_WAIT_BLOCK; - -NTKERNELAPI -VOID -FASTCALL -ExfUnblockPushLock( - __inout PEX_PUSH_LOCK PushLock, - __inout_opt PEX_PUSH_LOCK_WAIT_BLOCK WaitBlock - ); - -typedef struct _HANDLE_TABLE_ENTRY -{ - union - { - PVOID Object; - ULONG ObAttributes; - ULONG_PTR Value; - }; - union - { - ACCESS_MASK GrantedAccess; - LONG NextFreeTableEntry; - }; -} HANDLE_TABLE_ENTRY, *PHANDLE_TABLE_ENTRY; - -typedef struct _HANDLE_TABLE HANDLE_TABLE, *PHANDLE_TABLE; - -typedef BOOLEAN (NTAPI *PEX_ENUM_HANDLE_CALLBACK_61)( - __inout PHANDLE_TABLE_ENTRY HandleTableEntry, - __in HANDLE Handle, - __in PVOID Context - ); - -// since WIN8 -typedef BOOLEAN (NTAPI *PEX_ENUM_HANDLE_CALLBACK)( - __in PHANDLE_TABLE HandleTable, - __inout PHANDLE_TABLE_ENTRY HandleTableEntry, - __in HANDLE Handle, - __in PVOID Context - ); - -NTKERNELAPI -BOOLEAN -NTAPI -ExEnumHandleTable( - __in PHANDLE_TABLE HandleTable, - __in PEX_ENUM_HANDLE_CALLBACK EnumHandleProcedure, - __inout PVOID Context, - __out_opt PHANDLE Handle - ); - -NTSYSCALLAPI -NTSTATUS -NTAPI -ZwQuerySystemInformation( - __in SYSTEM_INFORMATION_CLASS SystemInformationClass, - __out_bcount_opt(SystemInformationLength) PVOID SystemInformation, - __in ULONG SystemInformationLength, - __out_opt PULONG ReturnLength - ); - -// IO - -extern POBJECT_TYPE *IoDriverObjectType; - -// KE - -typedef enum _KAPC_ENVIRONMENT -{ - OriginalApcEnvironment, - AttachedApcEnvironment, - CurrentApcEnvironment, - InsertApcEnvironment -} KAPC_ENVIRONMENT, *PKAPC_ENVIRONMENT; - -typedef VOID (NTAPI *PKNORMAL_ROUTINE)( - __in PVOID NormalContext, - __in PVOID SystemArgument1, - __in PVOID SystemArgument2 - ); - -typedef VOID KKERNEL_ROUTINE( - __in PRKAPC Apc, - __inout PKNORMAL_ROUTINE *NormalRoutine, - __inout PVOID *NormalContext, - __inout PVOID *SystemArgument1, - __inout PVOID *SystemArgument2 - ); - -typedef KKERNEL_ROUTINE (NTAPI *PKKERNEL_ROUTINE); - -typedef VOID (NTAPI *PKRUNDOWN_ROUTINE)( - __in PRKAPC Apc - ); - -NTKERNELAPI -VOID -NTAPI -KeInitializeApc( - __out PRKAPC Apc, - __in PRKTHREAD Thread, - __in KAPC_ENVIRONMENT Environment, - __in PKKERNEL_ROUTINE KernelRoutine, - __in_opt PKRUNDOWN_ROUTINE RundownRoutine, - __in_opt PKNORMAL_ROUTINE NormalRoutine, - __in_opt KPROCESSOR_MODE ProcessorMode, - __in_opt PVOID NormalContext - ); - -NTKERNELAPI -BOOLEAN -NTAPI -KeInsertQueueApc( - __inout PRKAPC Apc, - __in_opt PVOID SystemArgument1, - __in_opt PVOID SystemArgument2, - __in KPRIORITY Increment - ); - -// MM - -NTSYSCALLAPI -NTSTATUS -NTAPI -ZwQueryVirtualMemory( - __in HANDLE ProcessHandle, - __in PVOID BaseAddress, - __in MEMORY_INFORMATION_CLASS MemoryInformationClass, - __out_bcount(MemoryInformationLength) PVOID MemoryInformation, - __in SIZE_T MemoryInformationLength, - __out_opt PSIZE_T ReturnLength - ); - -// OB - -// These definitions are no longer correct, but they produce correct results. - -#define OBJ_PROTECT_CLOSE 0x00000001 -#define OBJ_HANDLE_ATTRIBUTES (OBJ_PROTECT_CLOSE | OBJ_INHERIT | OBJ_AUDIT_OBJECT_CLOSE) - -// This attribute is now stored in the GrantedAccess field. -#define ObpAccessProtectCloseBit 0x2000000 - -#define ObpDecodeGrantedAccess(Access) \ - ((Access) & ~ObpAccessProtectCloseBit) - -FORCEINLINE PVOID ObpDecodeObject(PVOID Object) -{ -#ifdef _M_X64 - if (KphDynNtVersion >= PHNT_WIN8) - { - if (KphDynObDecodeShift != -1) - return (PVOID)(((LONG_PTR)Object >> KphDynObDecodeShift) & ~(ULONG_PTR)0xf); - else - return NULL; - } - else - { - return (PVOID)((ULONG_PTR)Object & ~OBJ_HANDLE_ATTRIBUTES); - } -#else - return (PVOID)((ULONG_PTR)Object & ~OBJ_HANDLE_ATTRIBUTES); -#endif -} - -FORCEINLINE ULONG ObpGetHandleAttributes(PHANDLE_TABLE_ENTRY HandleTableEntry) -{ -#ifdef _M_X64 - if (KphDynNtVersion >= PHNT_WIN8) - { - if (KphDynObAttributesShift != -1) - return (ULONG)(HandleTableEntry->Value >> KphDynObAttributesShift) & 0x3; - else - return 0; - } - else - { - return (HandleTableEntry->ObAttributes & (OBJ_INHERIT | OBJ_AUDIT_OBJECT_CLOSE)) | - ((HandleTableEntry->GrantedAccess & ObpAccessProtectCloseBit) ? OBJ_PROTECT_CLOSE : 0); - } -#else - return (HandleTableEntry->ObAttributes & (OBJ_INHERIT | OBJ_AUDIT_OBJECT_CLOSE)) | - ((HandleTableEntry->GrantedAccess & ObpAccessProtectCloseBit) ? OBJ_PROTECT_CLOSE : 0); -#endif -} - -typedef struct _OBJECT_CREATE_INFORMATION OBJECT_CREATE_INFORMATION, *POBJECT_CREATE_INFORMATION; - -// This is incorrect as of Windows 8.1, but the size of the structure is still correct. -typedef struct _OBJECT_HEADER -{ - LONG PointerCount; - union - { - LONG HandleCount; - PVOID NextToFree; - }; - POBJECT_TYPE Type; - UCHAR NameInfoOffset; - UCHAR HandleInfoOffset; - UCHAR QuotaInfoOffset; - UCHAR Flags; - union - { - POBJECT_CREATE_INFORMATION ObjectCreateInfo; - PVOID QuotaBlockCharged; - }; - PVOID SecurityDescriptor; - QUAD Body; -} OBJECT_HEADER, *POBJECT_HEADER; - -#define OBJECT_TO_OBJECT_HEADER(Object) CONTAINING_RECORD((Object), OBJECT_HEADER, Body) - -NTKERNELAPI -POBJECT_TYPE -NTAPI -ObGetObjectType( - __in PVOID Object - ); - -NTKERNELAPI -NTSTATUS -NTAPI -ObOpenObjectByName( - __in POBJECT_ATTRIBUTES ObjectAttributes, - __in POBJECT_TYPE ObjectType, - __in KPROCESSOR_MODE PreviousMode, - __in_opt PACCESS_STATE AccessState, - __in_opt ACCESS_MASK DesiredAccess, - __in PVOID ParseContext, - __out PHANDLE Handle - ); - -NTKERNELAPI -NTSTATUS -NTAPI -ObSetHandleAttributes( - __in HANDLE Handle, - __in POBJECT_HANDLE_FLAG_INFORMATION HandleFlags, - __in KPROCESSOR_MODE PreviousMode - ); - -NTKERNELAPI -NTSTATUS -ObCloseHandle( - __in HANDLE Handle, - __in KPROCESSOR_MODE PreviousMode - ); - -// PS - -NTSYSCALLAPI -NTSTATUS -NTAPI -ZwQueryInformationProcess( - __in HANDLE ProcessHandle, - __in PROCESSINFOCLASS ProcessInformationClass, - __out_bcount(ProcessInformationLength) PVOID ProcessInformation, - __in ULONG ProcessInformationLength, - __out_opt PULONG ReturnLength - ); - -NTSYSCALLAPI -NTSTATUS -NTAPI -ZwSetInformationProcess( - __in HANDLE ProcessHandle, - __in PROCESSINFOCLASS ProcessInformationClass, - __in_bcount(ProcessInformationLength) PVOID ProcessInformation, - __in ULONG ProcessInformationLength - ); - -NTSYSCALLAPI -NTSTATUS -NTAPI -ZwQueryInformationThread( - __in HANDLE ThreadHandle, - __in THREADINFOCLASS ThreadInformationClass, - __out_bcount(ThreadInformationLength) PVOID ThreadInformation, - __in ULONG ThreadInformationLength, - __out_opt PULONG ReturnLength - ); - -NTKERNELAPI -NTSTATUS -NTAPI -PsLookupProcessThreadByCid( - __in PCLIENT_ID ClientId, - __out_opt PEPROCESS *Process, - __out PETHREAD *Thread - ); - -NTKERNELAPI -PVOID -NTAPI -PsGetThreadWin32Thread( - __in PETHREAD Thread - ); - -typedef struct _EJOB *PEJOB; - -extern POBJECT_TYPE *PsJobType; - -NTKERNELAPI -PEJOB -NTAPI -PsGetProcessJob( - __in PEPROCESS Process - ); - -NTKERNELAPI -NTSTATUS -NTAPI -PsAcquireProcessExitSynchronization( - __in PEPROCESS Process - ); - -NTKERNELAPI -VOID -NTAPI -PsReleaseProcessExitSynchronization( - __in PEPROCESS Process - ); - -// RTL - -// Sensible limit that may or may not correspond to the actual Windows value. -#define MAX_STACK_DEPTH 256 - -#define RTL_WALK_USER_MODE_STACK 0x00000001 -#define RTL_WALK_VALID_FLAGS 0x00000001 - -NTSYSAPI -ULONG -NTAPI -RtlWalkFrameChain( - __out PVOID *Callers, - __in ULONG Count, - __in ULONG Flags - ); - -#endif +#ifndef NTFILL_H +#define NTFILL_H + +extern ULONG KphDynNtVersion; +extern ULONG KphDynObDecodeShift; +extern ULONG KphDynObAttributesShift; + +// EX + +typedef struct _EX_PUSH_LOCK_WAIT_BLOCK *PEX_PUSH_LOCK_WAIT_BLOCK; + +NTKERNELAPI +VOID +FASTCALL +ExfUnblockPushLock( + __inout PEX_PUSH_LOCK PushLock, + __inout_opt PEX_PUSH_LOCK_WAIT_BLOCK WaitBlock + ); + +typedef struct _HANDLE_TABLE_ENTRY +{ + union + { + PVOID Object; + ULONG ObAttributes; + ULONG_PTR Value; + }; + union + { + ACCESS_MASK GrantedAccess; + LONG NextFreeTableEntry; + }; +} HANDLE_TABLE_ENTRY, *PHANDLE_TABLE_ENTRY; + +typedef struct _HANDLE_TABLE HANDLE_TABLE, *PHANDLE_TABLE; + +typedef BOOLEAN (NTAPI *PEX_ENUM_HANDLE_CALLBACK_61)( + __inout PHANDLE_TABLE_ENTRY HandleTableEntry, + __in HANDLE Handle, + __in PVOID Context + ); + +// since WIN8 +typedef BOOLEAN (NTAPI *PEX_ENUM_HANDLE_CALLBACK)( + __in PHANDLE_TABLE HandleTable, + __inout PHANDLE_TABLE_ENTRY HandleTableEntry, + __in HANDLE Handle, + __in PVOID Context + ); + +NTKERNELAPI +BOOLEAN +NTAPI +ExEnumHandleTable( + __in PHANDLE_TABLE HandleTable, + __in PEX_ENUM_HANDLE_CALLBACK EnumHandleProcedure, + __inout PVOID Context, + __out_opt PHANDLE Handle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwQuerySystemInformation( + __in SYSTEM_INFORMATION_CLASS SystemInformationClass, + __out_bcount_opt(SystemInformationLength) PVOID SystemInformation, + __in ULONG SystemInformationLength, + __out_opt PULONG ReturnLength + ); + +// IO + +extern POBJECT_TYPE *IoDriverObjectType; + +// KE + +typedef enum _KAPC_ENVIRONMENT +{ + OriginalApcEnvironment, + AttachedApcEnvironment, + CurrentApcEnvironment, + InsertApcEnvironment +} KAPC_ENVIRONMENT, *PKAPC_ENVIRONMENT; + +typedef VOID (NTAPI *PKNORMAL_ROUTINE)( + __in PVOID NormalContext, + __in PVOID SystemArgument1, + __in PVOID SystemArgument2 + ); + +typedef VOID KKERNEL_ROUTINE( + __in PRKAPC Apc, + __inout PKNORMAL_ROUTINE *NormalRoutine, + __inout PVOID *NormalContext, + __inout PVOID *SystemArgument1, + __inout PVOID *SystemArgument2 + ); + +typedef KKERNEL_ROUTINE (NTAPI *PKKERNEL_ROUTINE); + +typedef VOID (NTAPI *PKRUNDOWN_ROUTINE)( + __in PRKAPC Apc + ); + +NTKERNELAPI +VOID +NTAPI +KeInitializeApc( + __out PRKAPC Apc, + __in PRKTHREAD Thread, + __in KAPC_ENVIRONMENT Environment, + __in PKKERNEL_ROUTINE KernelRoutine, + __in_opt PKRUNDOWN_ROUTINE RundownRoutine, + __in_opt PKNORMAL_ROUTINE NormalRoutine, + __in_opt KPROCESSOR_MODE ProcessorMode, + __in_opt PVOID NormalContext + ); + +NTKERNELAPI +BOOLEAN +NTAPI +KeInsertQueueApc( + __inout PRKAPC Apc, + __in_opt PVOID SystemArgument1, + __in_opt PVOID SystemArgument2, + __in KPRIORITY Increment + ); + +// MM + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwQueryVirtualMemory( + __in HANDLE ProcessHandle, + __in PVOID BaseAddress, + __in MEMORY_INFORMATION_CLASS MemoryInformationClass, + __out_bcount(MemoryInformationLength) PVOID MemoryInformation, + __in SIZE_T MemoryInformationLength, + __out_opt PSIZE_T ReturnLength + ); + +// OB + +// These definitions are no longer correct, but they produce correct results. + +#define OBJ_PROTECT_CLOSE 0x00000001 +#define OBJ_HANDLE_ATTRIBUTES (OBJ_PROTECT_CLOSE | OBJ_INHERIT | OBJ_AUDIT_OBJECT_CLOSE) + +// This attribute is now stored in the GrantedAccess field. +#define ObpAccessProtectCloseBit 0x2000000 + +#define ObpDecodeGrantedAccess(Access) \ + ((Access) & ~ObpAccessProtectCloseBit) + +FORCEINLINE PVOID ObpDecodeObject(PVOID Object) +{ +#ifdef _M_X64 + if (KphDynNtVersion >= PHNT_WIN8) + { + if (KphDynObDecodeShift != -1) + return (PVOID)(((LONG_PTR)Object >> KphDynObDecodeShift) & ~(ULONG_PTR)0xf); + else + return NULL; + } + else + { + return (PVOID)((ULONG_PTR)Object & ~OBJ_HANDLE_ATTRIBUTES); + } +#else + return (PVOID)((ULONG_PTR)Object & ~OBJ_HANDLE_ATTRIBUTES); +#endif +} + +FORCEINLINE ULONG ObpGetHandleAttributes(PHANDLE_TABLE_ENTRY HandleTableEntry) +{ +#ifdef _M_X64 + if (KphDynNtVersion >= PHNT_WIN8) + { + if (KphDynObAttributesShift != -1) + return (ULONG)(HandleTableEntry->Value >> KphDynObAttributesShift) & 0x3; + else + return 0; + } + else + { + return (HandleTableEntry->ObAttributes & (OBJ_INHERIT | OBJ_AUDIT_OBJECT_CLOSE)) | + ((HandleTableEntry->GrantedAccess & ObpAccessProtectCloseBit) ? OBJ_PROTECT_CLOSE : 0); + } +#else + return (HandleTableEntry->ObAttributes & (OBJ_INHERIT | OBJ_AUDIT_OBJECT_CLOSE)) | + ((HandleTableEntry->GrantedAccess & ObpAccessProtectCloseBit) ? OBJ_PROTECT_CLOSE : 0); +#endif +} + +typedef struct _OBJECT_CREATE_INFORMATION OBJECT_CREATE_INFORMATION, *POBJECT_CREATE_INFORMATION; + +// This is incorrect as of Windows 8.1, but the size of the structure is still correct. +typedef struct _OBJECT_HEADER +{ + LONG PointerCount; + union + { + LONG HandleCount; + PVOID NextToFree; + }; + POBJECT_TYPE Type; + UCHAR NameInfoOffset; + UCHAR HandleInfoOffset; + UCHAR QuotaInfoOffset; + UCHAR Flags; + union + { + POBJECT_CREATE_INFORMATION ObjectCreateInfo; + PVOID QuotaBlockCharged; + }; + PVOID SecurityDescriptor; + QUAD Body; +} OBJECT_HEADER, *POBJECT_HEADER; + +#define OBJECT_TO_OBJECT_HEADER(Object) CONTAINING_RECORD((Object), OBJECT_HEADER, Body) + +NTKERNELAPI +POBJECT_TYPE +NTAPI +ObGetObjectType( + __in PVOID Object + ); + +NTKERNELAPI +NTSTATUS +NTAPI +ObOpenObjectByName( + __in POBJECT_ATTRIBUTES ObjectAttributes, + __in POBJECT_TYPE ObjectType, + __in KPROCESSOR_MODE PreviousMode, + __in_opt PACCESS_STATE AccessState, + __in_opt ACCESS_MASK DesiredAccess, + __in PVOID ParseContext, + __out PHANDLE Handle + ); + +NTKERNELAPI +NTSTATUS +NTAPI +ObSetHandleAttributes( + __in HANDLE Handle, + __in POBJECT_HANDLE_FLAG_INFORMATION HandleFlags, + __in KPROCESSOR_MODE PreviousMode + ); + +NTKERNELAPI +NTSTATUS +ObCloseHandle( + __in HANDLE Handle, + __in KPROCESSOR_MODE PreviousMode + ); + +// PS + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwQueryInformationProcess( + __in HANDLE ProcessHandle, + __in PROCESSINFOCLASS ProcessInformationClass, + __out_bcount(ProcessInformationLength) PVOID ProcessInformation, + __in ULONG ProcessInformationLength, + __out_opt PULONG ReturnLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwSetInformationProcess( + __in HANDLE ProcessHandle, + __in PROCESSINFOCLASS ProcessInformationClass, + __in_bcount(ProcessInformationLength) PVOID ProcessInformation, + __in ULONG ProcessInformationLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwQueryInformationThread( + __in HANDLE ThreadHandle, + __in THREADINFOCLASS ThreadInformationClass, + __out_bcount(ThreadInformationLength) PVOID ThreadInformation, + __in ULONG ThreadInformationLength, + __out_opt PULONG ReturnLength + ); + +NTKERNELAPI +NTSTATUS +NTAPI +PsLookupProcessThreadByCid( + __in PCLIENT_ID ClientId, + __out_opt PEPROCESS *Process, + __out PETHREAD *Thread + ); + +NTKERNELAPI +PVOID +NTAPI +PsGetThreadWin32Thread( + __in PETHREAD Thread + ); + +typedef struct _EJOB *PEJOB; + +extern POBJECT_TYPE *PsJobType; + +NTKERNELAPI +PEJOB +NTAPI +PsGetProcessJob( + __in PEPROCESS Process + ); + +NTKERNELAPI +NTSTATUS +NTAPI +PsAcquireProcessExitSynchronization( + __in PEPROCESS Process + ); + +NTKERNELAPI +VOID +NTAPI +PsReleaseProcessExitSynchronization( + __in PEPROCESS Process + ); + +// RTL + +// Sensible limit that may or may not correspond to the actual Windows value. +#define MAX_STACK_DEPTH 256 + +#define RTL_WALK_USER_MODE_STACK 0x00000001 +#define RTL_WALK_VALID_FLAGS 0x00000001 + +NTSYSAPI +ULONG +NTAPI +RtlWalkFrameChain( + __out PVOID *Callers, + __in ULONG Count, + __in ULONG Flags + ); + +#endif diff --git a/KProcessHacker/main.c b/KProcessHacker/main.c index d4eef0fc45b1..31623234b278 100644 --- a/KProcessHacker/main.c +++ b/KProcessHacker/main.c @@ -1,356 +1,356 @@ -/* - * KProcessHacker - * - * Copyright (C) 2010-2016 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include -#include - -DRIVER_INITIALIZE DriverEntry; -DRIVER_UNLOAD DriverUnload; -__drv_dispatchType(IRP_MJ_CREATE) DRIVER_DISPATCH KphDispatchCreate; -__drv_dispatchType(IRP_MJ_CLOSE) DRIVER_DISPATCH KphDispatchClose; - -ULONG KphpReadIntegerParameter( - __in_opt HANDLE KeyHandle, - __in PUNICODE_STRING ValueName, - __in ULONG DefaultValue - ); - -NTSTATUS KphpReadDriverParameters( - __in PUNICODE_STRING RegistryPath - ); - -#ifdef ALLOC_PRAGMA -#pragma alloc_text(PAGE, DriverEntry) -#pragma alloc_text(PAGE, DriverUnload) -#pragma alloc_text(PAGE, KphpReadIntegerParameter) -#pragma alloc_text(PAGE, KphpReadDriverParameters) -#pragma alloc_text(PAGE, KpiGetFeatures) -#endif - -PDRIVER_OBJECT KphDriverObject; -PDEVICE_OBJECT KphDeviceObject; -ULONG KphFeatures; -KPH_PARAMETERS KphParameters; - -NTSTATUS DriverEntry( - __in PDRIVER_OBJECT DriverObject, - __in PUNICODE_STRING RegistryPath - ) -{ - NTSTATUS status; - UNICODE_STRING deviceName; - PDEVICE_OBJECT deviceObject; - - PAGED_CODE(); - - KphDriverObject = DriverObject; - - if (!NT_SUCCESS(status = KphDynamicDataInitialization())) - return status; - - KphDynamicImport(); - - if (!NT_SUCCESS(status = KphpReadDriverParameters(RegistryPath))) - return status; - - // Create the device. - - RtlInitUnicodeString(&deviceName, KPH_DEVICE_NAME); - - status = IoCreateDevice( - DriverObject, - 0, - &deviceName, - FILE_DEVICE_UNKNOWN, - FILE_DEVICE_SECURE_OPEN, - FALSE, - &deviceObject - ); - - if (!NT_SUCCESS(status)) - return status; - - KphDeviceObject = deviceObject; - - // Set up I/O. - - DriverObject->MajorFunction[IRP_MJ_CREATE] = KphDispatchCreate; - DriverObject->MajorFunction[IRP_MJ_CLOSE] = KphDispatchClose; - DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = KphDispatchDeviceControl; - DriverObject->DriverUnload = DriverUnload; - - deviceObject->Flags &= ~DO_DEVICE_INITIALIZING; - - dprintf("Driver loaded\n"); - - return status; -} - -VOID DriverUnload( - __in PDRIVER_OBJECT DriverObject - ) -{ - PAGED_CODE(); - - IoDeleteDevice(KphDeviceObject); - - dprintf("Driver unloaded\n"); -} - -NTSTATUS KphDispatchCreate( - __in PDEVICE_OBJECT DeviceObject, - __in PIRP Irp - ) -{ - NTSTATUS status = STATUS_SUCCESS; - PIO_STACK_LOCATION stackLocation; - PFILE_OBJECT fileObject; - PIO_SECURITY_CONTEXT securityContext; - PKPH_CLIENT client; - - stackLocation = IoGetCurrentIrpStackLocation(Irp); - fileObject = stackLocation->FileObject; - securityContext = stackLocation->Parameters.Create.SecurityContext; - - dprintf("Client (PID %Iu) is connecting\n", PsGetCurrentProcessId()); - - if (KphParameters.SecurityLevel == KphSecurityPrivilegeCheck || - KphParameters.SecurityLevel == KphSecuritySignatureAndPrivilegeCheck) - { - UCHAR requiredPrivilegesBuffer[FIELD_OFFSET(PRIVILEGE_SET, Privilege) + sizeof(LUID_AND_ATTRIBUTES)]; - PPRIVILEGE_SET requiredPrivileges; - - // Check for SeDebugPrivilege. - - requiredPrivileges = (PPRIVILEGE_SET)requiredPrivilegesBuffer; - requiredPrivileges->PrivilegeCount = 1; - requiredPrivileges->Control = PRIVILEGE_SET_ALL_NECESSARY; - requiredPrivileges->Privilege[0].Luid.LowPart = SE_DEBUG_PRIVILEGE; - requiredPrivileges->Privilege[0].Luid.HighPart = 0; - requiredPrivileges->Privilege[0].Attributes = 0; - - if (!SePrivilegeCheck( - requiredPrivileges, - &securityContext->AccessState->SubjectSecurityContext, - Irp->RequestorMode - )) - { - status = STATUS_PRIVILEGE_NOT_HELD; - dprintf("Client (PID %Iu) was rejected\n", PsGetCurrentProcessId()); - } - } - - if (NT_SUCCESS(status)) - { - client = ExAllocatePoolWithTag(PagedPool, sizeof(KPH_CLIENT), 'ChpK'); - - if (client) - { - memset(client, 0, sizeof(KPH_CLIENT)); - - ExInitializeFastMutex(&client->StateMutex); - ExInitializeFastMutex(&client->KeyBackoffMutex); - - fileObject->FsContext = client; - } - else - { - dprintf("Unable to allocate memory for client (PID %Iu)\n", PsGetCurrentProcessId()); - status = STATUS_INSUFFICIENT_RESOURCES; - } - } - - Irp->IoStatus.Status = status; - Irp->IoStatus.Information = 0; - IoCompleteRequest(Irp, IO_NO_INCREMENT); - - return status; -} - -NTSTATUS KphDispatchClose( - __in PDEVICE_OBJECT DeviceObject, - __in PIRP Irp - ) -{ - NTSTATUS status = STATUS_SUCCESS; - PIO_STACK_LOCATION stackLocation; - PFILE_OBJECT fileObject; - PKPH_CLIENT client; - - stackLocation = IoGetCurrentIrpStackLocation(Irp); - fileObject = stackLocation->FileObject; - client = fileObject->FsContext; - - if (client) - { - ExFreePoolWithTag(client, 'ChpK'); - } - - Irp->IoStatus.Status = status; - Irp->IoStatus.Information = 0; - IoCompleteRequest(Irp, IO_NO_INCREMENT); - - return status; -} - -/** - * Reads an integer (REG_DWORD) parameter from the registry. - * - * \param KeyHandle A handle to the Parameters key. If NULL, the function - * fails immediately and returns \a DefaultValue. - * \param ValueName The name of the parameter. - * \param DefaultValue The value that is returned if the function fails - * to retrieve the parameter from the registry. - * - * \return The parameter value, or \a DefaultValue if the function failed. - */ -ULONG KphpReadIntegerParameter( - __in_opt HANDLE KeyHandle, - __in PUNICODE_STRING ValueName, - __in ULONG DefaultValue - ) -{ - NTSTATUS status; - UCHAR buffer[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data) + sizeof(ULONG)]; - PKEY_VALUE_PARTIAL_INFORMATION info; - ULONG resultLength; - - PAGED_CODE(); - - if (!KeyHandle) - return DefaultValue; - - info = (PKEY_VALUE_PARTIAL_INFORMATION)buffer; - - status = ZwQueryValueKey( - KeyHandle, - ValueName, - KeyValuePartialInformation, - info, - sizeof(buffer), - &resultLength - ); - - if (info->Type != REG_DWORD) - status = STATUS_OBJECT_TYPE_MISMATCH; - - if (!NT_SUCCESS(status)) - { - dprintf("Unable to query parameter %.*S: 0x%x\n", ValueName->Length / sizeof(WCHAR), ValueName->Buffer, status); - return DefaultValue; - } - - return *(PULONG)info->Data; -} - -/** - * Reads the driver parameters. - * - * \param RegistryPath The registry path of the driver. - */ -NTSTATUS KphpReadDriverParameters( - __in PUNICODE_STRING RegistryPath - ) -{ - NTSTATUS status; - HANDLE parametersKeyHandle; - UNICODE_STRING parametersString; - UNICODE_STRING parametersKeyName; - OBJECT_ATTRIBUTES objectAttributes; - UNICODE_STRING valueName; - - PAGED_CODE(); - - // Open the Parameters key. - - RtlInitUnicodeString(¶metersString, L"\\Parameters"); - - parametersKeyName.Length = RegistryPath->Length + parametersString.Length; - parametersKeyName.MaximumLength = parametersKeyName.Length; - parametersKeyName.Buffer = ExAllocatePoolWithTag(PagedPool, parametersKeyName.MaximumLength, 'ThpK'); - - if (!parametersKeyName.Buffer) - return STATUS_INSUFFICIENT_RESOURCES; - - memcpy(parametersKeyName.Buffer, RegistryPath->Buffer, RegistryPath->Length); - memcpy(¶metersKeyName.Buffer[RegistryPath->Length / sizeof(WCHAR)], parametersString.Buffer, parametersString.Length); - - InitializeObjectAttributes( - &objectAttributes, - ¶metersKeyName, - OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, - NULL, - NULL - ); - status = ZwOpenKey( - ¶metersKeyHandle, - KEY_READ, - &objectAttributes - ); - ExFreePoolWithTag(parametersKeyName.Buffer, 'ThpK'); - - if (!NT_SUCCESS(status)) - { - dprintf("Unable to open Parameters key: 0x%x\n", status); - status = STATUS_SUCCESS; - parametersKeyHandle = NULL; - // Continue so we can set up defaults. - } - - // Read in the parameters. - - RtlInitUnicodeString(&valueName, L"SecurityLevel"); - KphParameters.SecurityLevel = KphpReadIntegerParameter(parametersKeyHandle, &valueName, KphSecurityPrivilegeCheck); - - KphReadDynamicDataParameters(parametersKeyHandle); - - if (parametersKeyHandle) - ZwClose(parametersKeyHandle); - - return status; -} - -NTSTATUS KpiGetFeatures( - __out PULONG Features, - __in KPROCESSOR_MODE AccessMode - ) -{ - PAGED_CODE(); - - if (AccessMode != KernelMode) - { - __try - { - ProbeForWrite(Features, sizeof(ULONG), sizeof(ULONG)); - *Features = KphFeatures; - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - return GetExceptionCode(); - } - } - else - { - *Features = KphFeatures; - } - - return STATUS_SUCCESS; -} +/* + * KProcessHacker + * + * Copyright (C) 2010-2016 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include +#include + +DRIVER_INITIALIZE DriverEntry; +DRIVER_UNLOAD DriverUnload; +__drv_dispatchType(IRP_MJ_CREATE) DRIVER_DISPATCH KphDispatchCreate; +__drv_dispatchType(IRP_MJ_CLOSE) DRIVER_DISPATCH KphDispatchClose; + +ULONG KphpReadIntegerParameter( + __in_opt HANDLE KeyHandle, + __in PUNICODE_STRING ValueName, + __in ULONG DefaultValue + ); + +NTSTATUS KphpReadDriverParameters( + __in PUNICODE_STRING RegistryPath + ); + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGE, DriverEntry) +#pragma alloc_text(PAGE, DriverUnload) +#pragma alloc_text(PAGE, KphpReadIntegerParameter) +#pragma alloc_text(PAGE, KphpReadDriverParameters) +#pragma alloc_text(PAGE, KpiGetFeatures) +#endif + +PDRIVER_OBJECT KphDriverObject; +PDEVICE_OBJECT KphDeviceObject; +ULONG KphFeatures; +KPH_PARAMETERS KphParameters; + +NTSTATUS DriverEntry( + __in PDRIVER_OBJECT DriverObject, + __in PUNICODE_STRING RegistryPath + ) +{ + NTSTATUS status; + UNICODE_STRING deviceName; + PDEVICE_OBJECT deviceObject; + + PAGED_CODE(); + + KphDriverObject = DriverObject; + + if (!NT_SUCCESS(status = KphDynamicDataInitialization())) + return status; + + KphDynamicImport(); + + if (!NT_SUCCESS(status = KphpReadDriverParameters(RegistryPath))) + return status; + + // Create the device. + + RtlInitUnicodeString(&deviceName, KPH_DEVICE_NAME); + + status = IoCreateDevice( + DriverObject, + 0, + &deviceName, + FILE_DEVICE_UNKNOWN, + FILE_DEVICE_SECURE_OPEN, + FALSE, + &deviceObject + ); + + if (!NT_SUCCESS(status)) + return status; + + KphDeviceObject = deviceObject; + + // Set up I/O. + + DriverObject->MajorFunction[IRP_MJ_CREATE] = KphDispatchCreate; + DriverObject->MajorFunction[IRP_MJ_CLOSE] = KphDispatchClose; + DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = KphDispatchDeviceControl; + DriverObject->DriverUnload = DriverUnload; + + deviceObject->Flags &= ~DO_DEVICE_INITIALIZING; + + dprintf("Driver loaded\n"); + + return status; +} + +VOID DriverUnload( + __in PDRIVER_OBJECT DriverObject + ) +{ + PAGED_CODE(); + + IoDeleteDevice(KphDeviceObject); + + dprintf("Driver unloaded\n"); +} + +NTSTATUS KphDispatchCreate( + __in PDEVICE_OBJECT DeviceObject, + __in PIRP Irp + ) +{ + NTSTATUS status = STATUS_SUCCESS; + PIO_STACK_LOCATION stackLocation; + PFILE_OBJECT fileObject; + PIO_SECURITY_CONTEXT securityContext; + PKPH_CLIENT client; + + stackLocation = IoGetCurrentIrpStackLocation(Irp); + fileObject = stackLocation->FileObject; + securityContext = stackLocation->Parameters.Create.SecurityContext; + + dprintf("Client (PID %Iu) is connecting\n", PsGetCurrentProcessId()); + + if (KphParameters.SecurityLevel == KphSecurityPrivilegeCheck || + KphParameters.SecurityLevel == KphSecuritySignatureAndPrivilegeCheck) + { + UCHAR requiredPrivilegesBuffer[FIELD_OFFSET(PRIVILEGE_SET, Privilege) + sizeof(LUID_AND_ATTRIBUTES)]; + PPRIVILEGE_SET requiredPrivileges; + + // Check for SeDebugPrivilege. + + requiredPrivileges = (PPRIVILEGE_SET)requiredPrivilegesBuffer; + requiredPrivileges->PrivilegeCount = 1; + requiredPrivileges->Control = PRIVILEGE_SET_ALL_NECESSARY; + requiredPrivileges->Privilege[0].Luid.LowPart = SE_DEBUG_PRIVILEGE; + requiredPrivileges->Privilege[0].Luid.HighPart = 0; + requiredPrivileges->Privilege[0].Attributes = 0; + + if (!SePrivilegeCheck( + requiredPrivileges, + &securityContext->AccessState->SubjectSecurityContext, + Irp->RequestorMode + )) + { + status = STATUS_PRIVILEGE_NOT_HELD; + dprintf("Client (PID %Iu) was rejected\n", PsGetCurrentProcessId()); + } + } + + if (NT_SUCCESS(status)) + { + client = ExAllocatePoolWithTag(PagedPool, sizeof(KPH_CLIENT), 'ChpK'); + + if (client) + { + memset(client, 0, sizeof(KPH_CLIENT)); + + ExInitializeFastMutex(&client->StateMutex); + ExInitializeFastMutex(&client->KeyBackoffMutex); + + fileObject->FsContext = client; + } + else + { + dprintf("Unable to allocate memory for client (PID %Iu)\n", PsGetCurrentProcessId()); + status = STATUS_INSUFFICIENT_RESOURCES; + } + } + + Irp->IoStatus.Status = status; + Irp->IoStatus.Information = 0; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + return status; +} + +NTSTATUS KphDispatchClose( + __in PDEVICE_OBJECT DeviceObject, + __in PIRP Irp + ) +{ + NTSTATUS status = STATUS_SUCCESS; + PIO_STACK_LOCATION stackLocation; + PFILE_OBJECT fileObject; + PKPH_CLIENT client; + + stackLocation = IoGetCurrentIrpStackLocation(Irp); + fileObject = stackLocation->FileObject; + client = fileObject->FsContext; + + if (client) + { + ExFreePoolWithTag(client, 'ChpK'); + } + + Irp->IoStatus.Status = status; + Irp->IoStatus.Information = 0; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + return status; +} + +/** + * Reads an integer (REG_DWORD) parameter from the registry. + * + * \param KeyHandle A handle to the Parameters key. If NULL, the function + * fails immediately and returns \a DefaultValue. + * \param ValueName The name of the parameter. + * \param DefaultValue The value that is returned if the function fails + * to retrieve the parameter from the registry. + * + * \return The parameter value, or \a DefaultValue if the function failed. + */ +ULONG KphpReadIntegerParameter( + __in_opt HANDLE KeyHandle, + __in PUNICODE_STRING ValueName, + __in ULONG DefaultValue + ) +{ + NTSTATUS status; + UCHAR buffer[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data) + sizeof(ULONG)]; + PKEY_VALUE_PARTIAL_INFORMATION info; + ULONG resultLength; + + PAGED_CODE(); + + if (!KeyHandle) + return DefaultValue; + + info = (PKEY_VALUE_PARTIAL_INFORMATION)buffer; + + status = ZwQueryValueKey( + KeyHandle, + ValueName, + KeyValuePartialInformation, + info, + sizeof(buffer), + &resultLength + ); + + if (info->Type != REG_DWORD) + status = STATUS_OBJECT_TYPE_MISMATCH; + + if (!NT_SUCCESS(status)) + { + dprintf("Unable to query parameter %.*S: 0x%x\n", ValueName->Length / sizeof(WCHAR), ValueName->Buffer, status); + return DefaultValue; + } + + return *(PULONG)info->Data; +} + +/** + * Reads the driver parameters. + * + * \param RegistryPath The registry path of the driver. + */ +NTSTATUS KphpReadDriverParameters( + __in PUNICODE_STRING RegistryPath + ) +{ + NTSTATUS status; + HANDLE parametersKeyHandle; + UNICODE_STRING parametersString; + UNICODE_STRING parametersKeyName; + OBJECT_ATTRIBUTES objectAttributes; + UNICODE_STRING valueName; + + PAGED_CODE(); + + // Open the Parameters key. + + RtlInitUnicodeString(¶metersString, L"\\Parameters"); + + parametersKeyName.Length = RegistryPath->Length + parametersString.Length; + parametersKeyName.MaximumLength = parametersKeyName.Length; + parametersKeyName.Buffer = ExAllocatePoolWithTag(PagedPool, parametersKeyName.MaximumLength, 'ThpK'); + + if (!parametersKeyName.Buffer) + return STATUS_INSUFFICIENT_RESOURCES; + + memcpy(parametersKeyName.Buffer, RegistryPath->Buffer, RegistryPath->Length); + memcpy(¶metersKeyName.Buffer[RegistryPath->Length / sizeof(WCHAR)], parametersString.Buffer, parametersString.Length); + + InitializeObjectAttributes( + &objectAttributes, + ¶metersKeyName, + OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, + NULL, + NULL + ); + status = ZwOpenKey( + ¶metersKeyHandle, + KEY_READ, + &objectAttributes + ); + ExFreePoolWithTag(parametersKeyName.Buffer, 'ThpK'); + + if (!NT_SUCCESS(status)) + { + dprintf("Unable to open Parameters key: 0x%x\n", status); + status = STATUS_SUCCESS; + parametersKeyHandle = NULL; + // Continue so we can set up defaults. + } + + // Read in the parameters. + + RtlInitUnicodeString(&valueName, L"SecurityLevel"); + KphParameters.SecurityLevel = KphpReadIntegerParameter(parametersKeyHandle, &valueName, KphSecurityPrivilegeCheck); + + KphReadDynamicDataParameters(parametersKeyHandle); + + if (parametersKeyHandle) + ZwClose(parametersKeyHandle); + + return status; +} + +NTSTATUS KpiGetFeatures( + __out PULONG Features, + __in KPROCESSOR_MODE AccessMode + ) +{ + PAGED_CODE(); + + if (AccessMode != KernelMode) + { + __try + { + ProbeForWrite(Features, sizeof(ULONG), sizeof(ULONG)); + *Features = KphFeatures; + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + return GetExceptionCode(); + } + } + else + { + *Features = KphFeatures; + } + + return STATUS_SUCCESS; +} diff --git a/KProcessHacker/object.c b/KProcessHacker/object.c index 65e30548cfb3..f272a16f9826 100644 --- a/KProcessHacker/object.c +++ b/KProcessHacker/object.c @@ -1,1293 +1,1293 @@ -/* - * KProcessHacker - * - * Copyright (C) 2010-2016 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include -#include - -#ifdef _X86_ -#define KERNEL_HANDLE_BIT (0x80000000) -#else -#define KERNEL_HANDLE_BIT (0xffffffff80000000) -#endif - -#define IsKernelHandle(Handle) ((LONG_PTR)(Handle) < 0) -#define MakeKernelHandle(Handle) ((HANDLE)((ULONG_PTR)(Handle) | KERNEL_HANDLE_BIT)) - -typedef struct _KPHP_ENUMERATE_PROCESS_HANDLES_CONTEXT -{ - PVOID Buffer; - PVOID BufferLimit; - PVOID CurrentEntry; - ULONG Count; - NTSTATUS Status; -} KPHP_ENUMERATE_PROCESS_HANDLES_CONTEXT, *PKPHP_ENUMERATE_PROCESS_HANDLES_CONTEXT; - -BOOLEAN KphpEnumerateProcessHandlesEnumCallback61( - __inout PHANDLE_TABLE_ENTRY HandleTableEntry, - __in HANDLE Handle, - __in PVOID Context - ); - -BOOLEAN KphpEnumerateProcessHandlesEnumCallback( - __in PHANDLE_TABLE HandleTable, - __inout PHANDLE_TABLE_ENTRY HandleTableEntry, - __in HANDLE Handle, - __in PVOID Context - ); - -#ifdef ALLOC_PRAGMA -#pragma alloc_text(PAGE, KphReferenceProcessHandleTable) -#pragma alloc_text(PAGE, KphDereferenceProcessHandleTable) -#pragma alloc_text(PAGE, KphUnlockHandleTableEntry) -#pragma alloc_text(PAGE, KphpEnumerateProcessHandlesEnumCallback61) -#pragma alloc_text(PAGE, KphpEnumerateProcessHandlesEnumCallback) -#pragma alloc_text(PAGE, KpiEnumerateProcessHandles) -#pragma alloc_text(PAGE, KphQueryNameObject) -#pragma alloc_text(PAGE, KphQueryNameFileObject) -#pragma alloc_text(PAGE, KpiQueryInformationObject) -#pragma alloc_text(PAGE, KpiSetInformationObject) -#pragma alloc_text(PAGE, KphOpenNamedObject) -#endif - -/** - * Gets a pointer to the handle table of a process. - * - * \param Process A process object. - * - * \return A pointer to the handle table, or NULL if the process is terminating or the request is - * not supported. You must call KphDereferenceProcessHandleTable() when the handle table is no - * longer needed. - */ -PHANDLE_TABLE KphReferenceProcessHandleTable( - __in PEPROCESS Process - ) -{ - PHANDLE_TABLE handleTable = NULL; - - PAGED_CODE(); - - // Fail if we don't have an offset. - if (KphDynEpObjectTable == -1) - return NULL; - - // Prevent the process from terminating and get its handle table. - if (NT_SUCCESS(PsAcquireProcessExitSynchronization(Process))) - { - handleTable = *(PHANDLE_TABLE *)((ULONG_PTR)Process + KphDynEpObjectTable); - - if (!handleTable) - PsReleaseProcessExitSynchronization(Process); - } - - return handleTable; -} - -/** - * Dereferences the handle table of a process. - * - * \param Process A process object. - */ -VOID KphDereferenceProcessHandleTable( - __in PEPROCESS Process - ) -{ - PAGED_CODE(); - - PsReleaseProcessExitSynchronization(Process); -} - -VOID KphUnlockHandleTableEntry( - __in PHANDLE_TABLE HandleTable, - __in PHANDLE_TABLE_ENTRY HandleTableEntry - ) -{ - PEX_PUSH_LOCK handleContentionEvent; - - PAGED_CODE(); - - // Set the unlocked bit. - -#ifdef _M_X64 - InterlockedExchangeAdd64(&HandleTableEntry->Value, 1); -#else - InterlockedExchangeAdd(&HandleTableEntry->Value, 1); -#endif - - // Allow waiters to wake up. - - handleContentionEvent = (PEX_PUSH_LOCK)((ULONG_PTR)HandleTable + KphDynHtHandleContentionEvent); - - if (*(PULONG_PTR)handleContentionEvent != 0) - ExfUnblockPushLock(handleContentionEvent, NULL); -} - -BOOLEAN KphpEnumerateProcessHandlesEnumCallback61( - __inout PHANDLE_TABLE_ENTRY HandleTableEntry, - __in HANDLE Handle, - __in PVOID Context - ) -{ - PKPHP_ENUMERATE_PROCESS_HANDLES_CONTEXT context = Context; - KPH_PROCESS_HANDLE handleInfo; - POBJECT_HEADER objectHeader; - POBJECT_TYPE objectType; - PKPH_PROCESS_HANDLE entryInBuffer; - - PAGED_CODE(); - - objectHeader = ObpDecodeObject(HandleTableEntry->Object); - handleInfo.Handle = Handle; - handleInfo.Object = objectHeader ? &objectHeader->Body : NULL; - handleInfo.GrantedAccess = ObpDecodeGrantedAccess(HandleTableEntry->GrantedAccess); - handleInfo.ObjectTypeIndex = -1; - handleInfo.Reserved1 = 0; - handleInfo.HandleAttributes = ObpGetHandleAttributes(HandleTableEntry); - handleInfo.Reserved2 = 0; - - if (handleInfo.Object) - { - objectType = ObGetObjectType(handleInfo.Object); - - if (objectType && KphDynOtIndex != -1) - handleInfo.ObjectTypeIndex = (USHORT)*(PUCHAR)((ULONG_PTR)objectType + KphDynOtIndex); - } - - // Advance the current entry pointer regardless of whether the information will be written; this - // will allow the parent function to report the correct return length. - entryInBuffer = context->CurrentEntry; - context->CurrentEntry = (PVOID)((ULONG_PTR)context->CurrentEntry + sizeof(KPH_PROCESS_HANDLE)); - context->Count++; - - // Only write if we have not exceeded the buffer length. Also check for a potential overflow (if - // the process has an extremely large number of handles, the buffer pointer may wrap). - if ( - (ULONG_PTR)entryInBuffer >= (ULONG_PTR)context->Buffer && - (ULONG_PTR)entryInBuffer + sizeof(KPH_PROCESS_HANDLE) <= (ULONG_PTR)context->BufferLimit - ) - { - __try - { - *entryInBuffer = handleInfo; - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - // Report an error. - if (context->Status == STATUS_SUCCESS) - context->Status = GetExceptionCode(); - } - } - else - { - // Report that the buffer is too small. - if (context->Status == STATUS_SUCCESS) - context->Status = STATUS_BUFFER_TOO_SMALL; - } - - return FALSE; -} - -BOOLEAN KphpEnumerateProcessHandlesEnumCallback( - __in PHANDLE_TABLE HandleTable, - __inout PHANDLE_TABLE_ENTRY HandleTableEntry, - __in HANDLE Handle, - __in PVOID Context - ) -{ - BOOLEAN result; - - PAGED_CODE(); - - result = KphpEnumerateProcessHandlesEnumCallback61(HandleTableEntry, Handle, Context); - KphUnlockHandleTableEntry(HandleTable, HandleTableEntry); - - return result; -} - -/** - * Enumerates the handles of a process. - * - * \param ProcessHandle A handle to a process. - * \param Buffer The buffer in which the handle information will be stored. - * \param BufferLength The number of bytes available in \a Buffer. - * \param ReturnLength A variable which receives the number of bytes required to be available in - * \a Buffer. - * \param AccessMode The mode in which to perform access checks. - */ -NTSTATUS KpiEnumerateProcessHandles( - __in HANDLE ProcessHandle, - __out_bcount(BufferLength) PVOID Buffer, - __in_opt ULONG BufferLength, - __out_opt PULONG ReturnLength, - __in KPROCESSOR_MODE AccessMode - ) -{ - NTSTATUS status; - BOOLEAN result; - PEPROCESS process; - PHANDLE_TABLE handleTable; - KPHP_ENUMERATE_PROCESS_HANDLES_CONTEXT context; - - PAGED_CODE(); - - if (KphDynNtVersion >= PHNT_WIN8 && KphDynHtHandleContentionEvent == -1) - { - return STATUS_NOT_SUPPORTED; - } - - if (AccessMode != KernelMode) - { - __try - { - ProbeForWrite(Buffer, BufferLength, sizeof(ULONG)); - - if (ReturnLength) - ProbeForWrite(ReturnLength, sizeof(ULONG), sizeof(ULONG)); - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - return GetExceptionCode(); - } - } - - // Reference the process object. - status = ObReferenceObjectByHandle( - ProcessHandle, - 0, - *PsProcessType, - AccessMode, - &process, - NULL - ); - - if (!NT_SUCCESS(status)) - return status; - - // Get its handle table. - handleTable = KphReferenceProcessHandleTable(process); - - if (!handleTable) - { - ObDereferenceObject(process); - return STATUS_UNSUCCESSFUL; - } - - // Initialize the enumeration context. - context.Buffer = Buffer; - context.BufferLimit = (PVOID)((ULONG_PTR)Buffer + BufferLength); - context.CurrentEntry = ((PKPH_PROCESS_HANDLE_INFORMATION)Buffer)->Handles; - context.Count = 0; - context.Status = STATUS_SUCCESS; - - // Enumerate the handles. - - if (KphDynNtVersion >= PHNT_WIN8) - { - result = ExEnumHandleTable( - handleTable, - KphpEnumerateProcessHandlesEnumCallback, - &context, - NULL - ); - } - else - { - result = ExEnumHandleTable( - handleTable, - (PEX_ENUM_HANDLE_CALLBACK)KphpEnumerateProcessHandlesEnumCallback61, - &context, - NULL - ); - } - - KphDereferenceProcessHandleTable(process); - ObDereferenceObject(process); - - // Write the number of handles if we can. - if (BufferLength >= FIELD_OFFSET(KPH_PROCESS_HANDLE_INFORMATION, Handles)) - { - if (AccessMode != KernelMode) - { - __try - { - ((PKPH_PROCESS_HANDLE_INFORMATION)Buffer)->HandleCount = context.Count; - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - return GetExceptionCode(); - } - } - else - { - ((PKPH_PROCESS_HANDLE_INFORMATION)Buffer)->HandleCount = context.Count; - } - } - - // Supply the return length if the caller wanted it. - if (ReturnLength) - { - ULONG returnLength; - - // Note: if the CurrentEntry pointer wrapped, this will give the wrong return length. - returnLength = (ULONG)((ULONG_PTR)context.CurrentEntry - (ULONG_PTR)Buffer); - - if (AccessMode != KernelMode) - { - __try - { - *ReturnLength = returnLength; - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - return GetExceptionCode(); - } - } - else - { - *ReturnLength = returnLength; - } - } - - return context.Status; -} - -/** - * Queries the name of an object. - * - * \param Object A pointer to an object. - * \param Buffer The buffer in which the object name will be stored. - * \param BufferLength The number of bytes available in \a Buffer. - * \param ReturnLength A variable which receives the number of bytes required to be available in - * \a Buffer. - */ -NTSTATUS KphQueryNameObject( - __in PVOID Object, - __out_bcount(BufferLength) POBJECT_NAME_INFORMATION Buffer, - __in ULONG BufferLength, - __out PULONG ReturnLength - ) -{ - NTSTATUS status; - POBJECT_TYPE objectType; - - PAGED_CODE(); - - objectType = ObGetObjectType(Object); - - // Check if we are going to hang when querying the object, and use - // the special file object query function if needed. - if (objectType == *IoFileObjectType && - (((PFILE_OBJECT)Object)->Busy || ((PFILE_OBJECT)Object)->Waiters)) - { - status = KphQueryNameFileObject(Object, Buffer, BufferLength, ReturnLength); - dprintf("KphQueryNameFileObject: status 0x%x\n", status); - } - else - { - status = ObQueryNameString(Object, Buffer, BufferLength, ReturnLength); - dprintf("ObQueryNameString: status 0x%x\n", status); - } - - // Make the error returns consistent. - if (status == STATUS_BUFFER_OVERFLOW) // returned by I/O subsystem - status = STATUS_BUFFER_TOO_SMALL; - if (status == STATUS_INFO_LENGTH_MISMATCH) // returned by ObQueryNameString - status = STATUS_BUFFER_TOO_SMALL; - - if (NT_SUCCESS(status)) - dprintf("KphQueryNameObject: %.*S\n", Buffer->Name.Length / sizeof(WCHAR), Buffer->Name.Buffer); - else - dprintf("KphQueryNameObject: status 0x%x\n", status); - - return status; -} - -/** - * Queries the name of a file object. - * - * \param FileObject A pointer to a file object. - * \param Buffer The buffer in which the object name will be stored. - * \param BufferLength The number of bytes available in \a Buffer. - * \param ReturnLength A variable which receives the number of bytes required to be available in - * \a Buffer. - */ -NTSTATUS KphQueryNameFileObject( - __in PFILE_OBJECT FileObject, - __out_bcount(BufferLength) POBJECT_NAME_INFORMATION Buffer, - __in ULONG BufferLength, - __out PULONG ReturnLength - ) -{ - NTSTATUS status = STATUS_SUCCESS; - ULONG returnLength; - PCHAR objectName; - ULONG usedLength; - ULONG subNameLength; - PFILE_OBJECT relatedFileObject; - - PAGED_CODE(); - - // We need at least the size of OBJECT_NAME_INFORMATION to continue. - if (BufferLength < sizeof(OBJECT_NAME_INFORMATION)) - { - *ReturnLength = sizeof(OBJECT_NAME_INFORMATION); - - return STATUS_BUFFER_TOO_SMALL; - } - - // Assume failure. - Buffer->Name.Length = 0; - // We will place the object name directly after the UNICODE_STRING structure in the buffer. - Buffer->Name.Buffer = (PWSTR)((ULONG_PTR)Buffer + sizeof(OBJECT_NAME_INFORMATION)); - // Retain a local pointer to the object name so we can manipulate the pointer. - objectName = (PCHAR)Buffer->Name.Buffer; - // A variable that keeps track of how much space we have used. - usedLength = sizeof(OBJECT_NAME_INFORMATION); - - // Check if the file object has an associated device (e.g. "\Device\NamedPipe", "\Device\Mup"). - // We can use the user-supplied buffer for this since if the buffer isn't big enough, we can't - // proceed anyway (we are going to use the name). - if (FileObject->DeviceObject) - { - status = ObQueryNameString( - FileObject->DeviceObject, - Buffer, - BufferLength, - &returnLength - ); - - if (!NT_SUCCESS(status)) - { - if (status == STATUS_INFO_LENGTH_MISMATCH) - status = STATUS_BUFFER_TOO_SMALL; - - *ReturnLength = returnLength; - - return status; - } - - // The UNICODE_STRING in the buffer is now filled in. We will append to the object name - // later, so we need to fix the object name pointer by adding the length, in bytes, of the - // device name string we just got. - objectName += Buffer->Name.Length; - usedLength += Buffer->Name.Length; - } - - // Check if the file object has a file name component. If not, we can't do anything else, so we - // just return the name we have already. - if (!FileObject->FileName.Buffer) - { - *ReturnLength = usedLength; - - return STATUS_SUCCESS; - } - - // The file object has a name. We need to walk up the file object chain and append the names of - // the related file objects in reverse order. This means we need to calculate the total length - // first. - - relatedFileObject = FileObject; - subNameLength = 0; - - do - { - subNameLength += relatedFileObject->FileName.Length; - - // Avoid infinite loops. - if (relatedFileObject == relatedFileObject->RelatedFileObject) - break; - - relatedFileObject = relatedFileObject->RelatedFileObject; - } while (relatedFileObject); - - usedLength += subNameLength; - - // Check if we have enough space to write the whole thing. - if (usedLength > BufferLength) - { - *ReturnLength = usedLength; - - return STATUS_BUFFER_TOO_SMALL; - } - - // We're ready to begin copying the names. - - // Add the name length because we're copying in reverse order. - objectName += subNameLength; - - relatedFileObject = FileObject; - - do - { - objectName -= relatedFileObject->FileName.Length; - memcpy(objectName, relatedFileObject->FileName.Buffer, relatedFileObject->FileName.Length); - - // Avoid infinite loops. - if (relatedFileObject == relatedFileObject->RelatedFileObject) - break; - - relatedFileObject = relatedFileObject->RelatedFileObject; - } while (relatedFileObject); - - // Update the length. - Buffer->Name.Length += (USHORT)subNameLength; - - // Pass the return length back. - *ReturnLength = usedLength; - - return STATUS_SUCCESS; -} - -/** - * Queries object information. - * - * \param ProcessHandle A handle to a process. - * \param Handle A handle which is present in the process referenced by \a ProcessHandle. - * \param ObjectInformationClass The type of information to retrieve. - * \param ObjectInformation The buffer in which the information will be stored. - * \param ObjectInformationLength The number of bytes available in \a ObjectInformation. - * \param ReturnLength A variable which receives the number of bytes required to be available in - * \a ObjectInformation. - * \param AccessMode The mode in which to perform access checks. - */ -NTSTATUS KpiQueryInformationObject( - __in HANDLE ProcessHandle, - __in HANDLE Handle, - __in KPH_OBJECT_INFORMATION_CLASS ObjectInformationClass, - __out_bcount(ObjectInformationLength) PVOID ObjectInformation, - __in ULONG ObjectInformationLength, - __out_opt PULONG ReturnLength, - __in KPROCESSOR_MODE AccessMode - ) -{ - NTSTATUS status; - PEPROCESS process; - KPROCESSOR_MODE referenceMode; - KAPC_STATE apcState; - ULONG returnLength; - - PAGED_CODE(); - - if (AccessMode != KernelMode) - { - __try - { - ProbeForWrite(ObjectInformation, ObjectInformationLength, sizeof(ULONG)); - - if (ReturnLength) - ProbeForWrite(ReturnLength, sizeof(ULONG), sizeof(ULONG)); - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - return GetExceptionCode(); - } - } - - status = ObReferenceObjectByHandle( - ProcessHandle, - 0, - *PsProcessType, - AccessMode, - &process, - NULL - ); - - if (!NT_SUCCESS(status)) - return status; - - if (process == PsInitialSystemProcess) - { - // A check was added in Windows 7 - if we're attached to the System process, the handle must - // be a kernel handle. - Handle = MakeKernelHandle(Handle); - referenceMode = KernelMode; - } - else - { - // Make sure the handle isn't a kernel handle if we're not attached to the System process. - // This means we can avoid referencing then opening the objects later when calling - // ZwQueryObject, etc. - if (IsKernelHandle(Handle)) - { - ObDereferenceObject(process); - return STATUS_INVALID_HANDLE; - } - - referenceMode = AccessMode; - } - - switch (ObjectInformationClass) - { - case KphObjectBasicInformation: - { - OBJECT_BASIC_INFORMATION basicInfo; - - KeStackAttachProcess(process, &apcState); - status = ZwQueryObject( - Handle, - ObjectBasicInformation, - &basicInfo, - sizeof(OBJECT_BASIC_INFORMATION), - NULL - ); - KeUnstackDetachProcess(&apcState); - - if (NT_SUCCESS(status)) - { - if (ObjectInformationLength == sizeof(OBJECT_BASIC_INFORMATION)) - { - __try - { - *(POBJECT_BASIC_INFORMATION)ObjectInformation = basicInfo; - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - status = GetExceptionCode(); - } - } - else - { - status = STATUS_INFO_LENGTH_MISMATCH; - } - } - - returnLength = sizeof(OBJECT_BASIC_INFORMATION); - } - break; - case KphObjectNameInformation: - { - PVOID object; - ULONG allocateSize; - POBJECT_NAME_INFORMATION nameInfo; - - returnLength = sizeof(OBJECT_NAME_INFORMATION); - - // Attach to the process a get a pointer to the object. - KeStackAttachProcess(process, &apcState); - status = ObReferenceObjectByHandle( - Handle, - 0, - NULL, - referenceMode, - &object, - NULL - ); - KeUnstackDetachProcess(&apcState); - - if (NT_SUCCESS(status)) - { - allocateSize = ObjectInformationLength; - - if (allocateSize < sizeof(OBJECT_NAME_INFORMATION)) // make sure we never try to allocate 0 bytes - allocateSize = sizeof(OBJECT_NAME_INFORMATION); - - nameInfo = ExAllocatePoolWithQuotaTag(PagedPool, allocateSize, 'QhpK'); - - if (nameInfo) - { - // Make sure we don't leak any data. - memset(nameInfo, 0, ObjectInformationLength); - - status = KphQueryNameObject( - object, - nameInfo, - ObjectInformationLength, - &returnLength - ); - dprintf("KpiQueryInformationObject: called KphQueryNameObject: Handle: 0x%Ix, ObjectInformationLength: %u, returnLength: %u\n", - Handle, ObjectInformationLength, returnLength); - - if (NT_SUCCESS(status)) - { - // Fix up the buffer pointer. - if (nameInfo->Name.Buffer) - nameInfo->Name.Buffer = (PVOID)((ULONG_PTR)nameInfo->Name.Buffer - (ULONG_PTR)nameInfo + (ULONG_PTR)ObjectInformation); - - __try - { - memcpy(ObjectInformation, nameInfo, ObjectInformationLength); - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - status = GetExceptionCode(); - } - } - - ExFreePoolWithTag(nameInfo, 'QhpK'); - } - else - { - status = STATUS_INSUFFICIENT_RESOURCES; - } - - ObDereferenceObject(object); - } - } - break; - case KphObjectTypeInformation: - { - ULONG allocateSize; - POBJECT_TYPE_INFORMATION typeInfo; - - returnLength = sizeof(OBJECT_TYPE_INFORMATION); - allocateSize = ObjectInformationLength; - - if (allocateSize < sizeof(OBJECT_TYPE_INFORMATION)) - allocateSize = sizeof(OBJECT_TYPE_INFORMATION); - - // ObQueryTypeInfo uses ObjectType->Name.MaximumLength instead of - // ObjectType->Name.Length + sizeof(WCHAR) to calculate the required buffer size. In - // Windows 8, certain object types (e.g. TmTx) do NOT include the null terminator in - // MaximumLength, which causes ObQueryTypeInfo to overrun the given buffer. To work - // around this bug, we add some (generous) padding to our allocation. - allocateSize += sizeof(ULONGLONG); - - typeInfo = ExAllocatePoolWithQuotaTag(PagedPool, allocateSize, 'QhpK'); - - if (typeInfo) - { - memset(typeInfo, 0, ObjectInformationLength); - - KeStackAttachProcess(process, &apcState); - status = ZwQueryObject( - Handle, - ObjectTypeInformation, - typeInfo, - ObjectInformationLength, - &returnLength - ); - KeUnstackDetachProcess(&apcState); - - if (NT_SUCCESS(status)) - { - // Fix up the buffer pointer. - if (typeInfo->TypeName.Buffer) - typeInfo->TypeName.Buffer = (PVOID)((ULONG_PTR)typeInfo->TypeName.Buffer - (ULONG_PTR)typeInfo + (ULONG_PTR)ObjectInformation); - - __try - { - memcpy(ObjectInformation, typeInfo, ObjectInformationLength); - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - status = GetExceptionCode(); - } - } - - ExFreePoolWithTag(typeInfo, 'QhpK'); - } - else - { - status = STATUS_INSUFFICIENT_RESOURCES; - } - } - break; - case KphObjectHandleFlagInformation: - { - OBJECT_HANDLE_FLAG_INFORMATION handleFlagInfo; - - KeStackAttachProcess(process, &apcState); - status = ZwQueryObject( - Handle, - ObjectHandleFlagInformation, - &handleFlagInfo, - sizeof(OBJECT_HANDLE_FLAG_INFORMATION), - NULL - ); - KeUnstackDetachProcess(&apcState); - - if (NT_SUCCESS(status)) - { - if (ObjectInformationLength == sizeof(OBJECT_HANDLE_FLAG_INFORMATION)) - { - __try - { - *(POBJECT_HANDLE_FLAG_INFORMATION)ObjectInformation = handleFlagInfo; - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - status = GetExceptionCode(); - } - } - else - { - status = STATUS_INFO_LENGTH_MISMATCH; - } - } - - returnLength = sizeof(OBJECT_HANDLE_FLAG_INFORMATION); - } - break; - case KphObjectProcessBasicInformation: - { - PROCESS_BASIC_INFORMATION basicInfo; - - KeStackAttachProcess(process, &apcState); - status = ZwQueryInformationProcess( - Handle, - ProcessBasicInformation, - &basicInfo, - sizeof(PROCESS_BASIC_INFORMATION), - NULL - ); - KeUnstackDetachProcess(&apcState); - - if (NT_SUCCESS(status)) - { - if (ObjectInformationLength == sizeof(PROCESS_BASIC_INFORMATION)) - { - __try - { - *(PPROCESS_BASIC_INFORMATION)ObjectInformation = basicInfo; - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - status = GetExceptionCode(); - } - } - else - { - status = STATUS_INFO_LENGTH_MISMATCH; - } - } - - returnLength = sizeof(PROCESS_BASIC_INFORMATION); - } - break; - case KphObjectThreadBasicInformation: - { - THREAD_BASIC_INFORMATION basicInfo; - - KeStackAttachProcess(process, &apcState); - status = ZwQueryInformationThread( - Handle, - ThreadBasicInformation, - &basicInfo, - sizeof(THREAD_BASIC_INFORMATION), - NULL - ); - KeUnstackDetachProcess(&apcState); - - if (NT_SUCCESS(status)) - { - if (ObjectInformationLength == sizeof(THREAD_BASIC_INFORMATION)) - { - __try - { - *(PTHREAD_BASIC_INFORMATION)ObjectInformation = basicInfo; - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - status = GetExceptionCode(); - } - } - else - { - status = STATUS_INFO_LENGTH_MISMATCH; - } - } - - returnLength = sizeof(THREAD_BASIC_INFORMATION); - } - break; - case KphObjectEtwRegBasicInformation: - { - PVOID etwReg; - PVOID objectType; - PUNICODE_STRING objectTypeName; - UNICODE_STRING etwRegistrationName; - PVOID guidEntry; - ETWREG_BASIC_INFORMATION basicInfo; - - // Check dynamic data requirements. - if (KphDynEgeGuid != -1 && - KphDynEreGuidEntry != -1 && - KphDynOtName != -1) - { - // Attach to the process and get a pointer to the object. We don't have a pointer to - // the EtwRegistration object type, so we'll just have to check the type name. - - KeStackAttachProcess(process, &apcState); - status = ObReferenceObjectByHandle( - Handle, - 0, - NULL, - referenceMode, - &etwReg, - NULL - ); - KeUnstackDetachProcess(&apcState); - - if (NT_SUCCESS(status)) - { - // Check the type name. - - objectType = ObGetObjectType(etwReg); - - if (objectType) - { - objectTypeName = (PUNICODE_STRING)((ULONG_PTR)objectType + KphDynOtName); - RtlInitUnicodeString(&etwRegistrationName, L"EtwRegistration"); - - if (!RtlEqualUnicodeString(objectTypeName, &etwRegistrationName, FALSE)) - { - status = STATUS_OBJECT_TYPE_MISMATCH; - } - } - else - { - status = STATUS_NOT_SUPPORTED; - } - - if (NT_SUCCESS(status)) - { - guidEntry = *(PVOID *)((ULONG_PTR)etwReg + KphDynEreGuidEntry); - - if (guidEntry) - basicInfo.Guid = *(GUID *)((ULONG_PTR)guidEntry + KphDynEgeGuid); - else - memset(&basicInfo.Guid, 0, sizeof(GUID)); - - basicInfo.SessionId = 0; // not implemented - - if (ObjectInformationLength == sizeof(ETWREG_BASIC_INFORMATION)) - { - __try - { - *(PETWREG_BASIC_INFORMATION)ObjectInformation = basicInfo; - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - status = GetExceptionCode(); - } - } - else - { - status = STATUS_INFO_LENGTH_MISMATCH; - } - } - - ObDereferenceObject(etwReg); - } - } - else - { - status = STATUS_NOT_SUPPORTED; - } - - returnLength = sizeof(ETWREG_BASIC_INFORMATION); - } - break; - case KphObjectFileObjectInformation: - { - PFILE_OBJECT fileObject; - KPH_FILE_OBJECT_INFORMATION objectInfo; - - KeStackAttachProcess(process, &apcState); - status = ObReferenceObjectByHandle( - Handle, - 0, - *IoFileObjectType, - referenceMode, - &fileObject, - NULL - ); - KeUnstackDetachProcess(&apcState); - - if (NT_SUCCESS(status)) - { - objectInfo.LockOperation = fileObject->LockOperation; - objectInfo.DeletePending = fileObject->DeletePending; - objectInfo.ReadAccess = fileObject->ReadAccess; - objectInfo.WriteAccess = fileObject->WriteAccess; - objectInfo.DeleteAccess = fileObject->DeleteAccess; - objectInfo.SharedRead = fileObject->SharedRead; - objectInfo.SharedWrite = fileObject->SharedWrite; - objectInfo.SharedDelete = fileObject->SharedDelete; - objectInfo.CurrentByteOffset = fileObject->CurrentByteOffset; - objectInfo.Flags = fileObject->Flags; - - if (ObjectInformationLength == sizeof(KPH_FILE_OBJECT_INFORMATION)) - { - __try - { - *(PKPH_FILE_OBJECT_INFORMATION)ObjectInformation = objectInfo; - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - status = GetExceptionCode(); - } - } - else - { - status = STATUS_INFO_LENGTH_MISMATCH; - } - - ObDereferenceObject(fileObject); - } - - returnLength = sizeof(KPH_FILE_OBJECT_INFORMATION); - } - break; - case KphObjectFileObjectDriver: - { - PFILE_OBJECT fileObject; - HANDLE driverHandle; - - if (ObjectInformationLength == sizeof(KPH_FILE_OBJECT_DRIVER)) - { - KeStackAttachProcess(process, &apcState); - status = ObReferenceObjectByHandle( - Handle, - 0, - *IoFileObjectType, - referenceMode, - &fileObject, - NULL - ); - KeUnstackDetachProcess(&apcState); - - if (NT_SUCCESS(status)) - { - if (fileObject->DeviceObject && fileObject->DeviceObject->DriverObject) - { - status = ObOpenObjectByPointer( - fileObject->DeviceObject->DriverObject, - 0, - NULL, - SYNCHRONIZE, - *IoDriverObjectType, - AccessMode, - &driverHandle - ); - } - else - { - driverHandle = NULL; - } - - if (NT_SUCCESS(status)) - { - __try - { - ((PKPH_FILE_OBJECT_DRIVER)ObjectInformation)->DriverHandle = driverHandle; - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - status = GetExceptionCode(); - } - } - - ObDereferenceObject(fileObject); - } - } - else - { - status = STATUS_INFO_LENGTH_MISMATCH; - } - } - break; - default: - status = STATUS_INVALID_INFO_CLASS; - returnLength = 0; - break; - } - - ObDereferenceObject(process); - - if (ReturnLength) - { - if (AccessMode != KernelMode) - { - __try - { - *ReturnLength = returnLength; - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - NOTHING; - } - } - else - { - *ReturnLength = returnLength; - } - } - - return status; -} - -/** - * Sets object information. - * - * \param ProcessHandle A handle to a process. - * \param Handle A handle which is present in the process referenced by \a ProcessHandle. - * \param ObjectInformationClass The type of information to set. - * \param ObjectInformation A buffer which contains the information to set. - * \param ObjectInformationLength The number of bytes present in \a ObjectInformation. - * \param AccessMode The mode in which to perform access checks. - */ -NTSTATUS KpiSetInformationObject( - __in HANDLE ProcessHandle, - __in HANDLE Handle, - __in KPH_OBJECT_INFORMATION_CLASS ObjectInformationClass, - __in_bcount(ObjectInformationLength) PVOID ObjectInformation, - __in ULONG ObjectInformationLength, - __in KPROCESSOR_MODE AccessMode - ) -{ - NTSTATUS status; - PEPROCESS process; - KAPC_STATE apcState; - - PAGED_CODE(); - - if (AccessMode != KernelMode) - { - ULONG alignment; - - switch (ObjectInformationClass) - { - case KphObjectHandleFlagInformation: - alignment = sizeof(BOOLEAN); - break; - default: - alignment = sizeof(ULONG); - break; - } - - __try - { - ProbeForRead(ObjectInformation, ObjectInformationLength, alignment); - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - return GetExceptionCode(); - } - } - - status = ObReferenceObjectByHandle( - ProcessHandle, - 0, - *PsProcessType, - AccessMode, - &process, - NULL - ); - - if (!NT_SUCCESS(status)) - return status; - - if (process == PsInitialSystemProcess) - { - Handle = MakeKernelHandle(Handle); - } - else - { - if (IsKernelHandle(Handle)) - { - ObDereferenceObject(process); - return STATUS_INVALID_HANDLE; - } - } - - switch (ObjectInformationClass) - { - case KphObjectHandleFlagInformation: - { - OBJECT_HANDLE_FLAG_INFORMATION handleFlagInfo; - - if (ObjectInformationLength == sizeof(OBJECT_HANDLE_FLAG_INFORMATION)) - { - __try - { - handleFlagInfo = *(POBJECT_HANDLE_FLAG_INFORMATION)ObjectInformation; - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - status = GetExceptionCode(); - } - } - else - { - status = STATUS_INFO_LENGTH_MISMATCH; - } - - if (NT_SUCCESS(status)) - { - KeStackAttachProcess(process, &apcState); - status = ObSetHandleAttributes(Handle, &handleFlagInfo, KernelMode); - KeUnstackDetachProcess(&apcState); - } - } - break; - default: - status = STATUS_INVALID_INFO_CLASS; - break; - } - - ObDereferenceObject(process); - - return status; -} - -NTSTATUS KphOpenNamedObject( - __out PHANDLE ObjectHandle, - __in ACCESS_MASK DesiredAccess, - __in POBJECT_ATTRIBUTES ObjectAttributes, - __in POBJECT_TYPE ObjectType, - __in KPROCESSOR_MODE AccessMode - ) -{ - NTSTATUS status; - HANDLE objectHandle; - - PAGED_CODE(); - - // Open the object. - status = ObOpenObjectByName( - ObjectAttributes, - ObjectType, - AccessMode, - NULL, - DesiredAccess, - NULL, - &objectHandle - ); - - // Pass the handle back. - if (AccessMode != KernelMode) - { - __try - { - *ObjectHandle = objectHandle; - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - status = GetExceptionCode(); - } - } - else - { - *ObjectHandle = objectHandle; - } - - return status; -} +/* + * KProcessHacker + * + * Copyright (C) 2010-2016 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include +#include + +#ifdef _X86_ +#define KERNEL_HANDLE_BIT (0x80000000) +#else +#define KERNEL_HANDLE_BIT (0xffffffff80000000) +#endif + +#define IsKernelHandle(Handle) ((LONG_PTR)(Handle) < 0) +#define MakeKernelHandle(Handle) ((HANDLE)((ULONG_PTR)(Handle) | KERNEL_HANDLE_BIT)) + +typedef struct _KPHP_ENUMERATE_PROCESS_HANDLES_CONTEXT +{ + PVOID Buffer; + PVOID BufferLimit; + PVOID CurrentEntry; + ULONG Count; + NTSTATUS Status; +} KPHP_ENUMERATE_PROCESS_HANDLES_CONTEXT, *PKPHP_ENUMERATE_PROCESS_HANDLES_CONTEXT; + +BOOLEAN KphpEnumerateProcessHandlesEnumCallback61( + __inout PHANDLE_TABLE_ENTRY HandleTableEntry, + __in HANDLE Handle, + __in PVOID Context + ); + +BOOLEAN KphpEnumerateProcessHandlesEnumCallback( + __in PHANDLE_TABLE HandleTable, + __inout PHANDLE_TABLE_ENTRY HandleTableEntry, + __in HANDLE Handle, + __in PVOID Context + ); + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGE, KphReferenceProcessHandleTable) +#pragma alloc_text(PAGE, KphDereferenceProcessHandleTable) +#pragma alloc_text(PAGE, KphUnlockHandleTableEntry) +#pragma alloc_text(PAGE, KphpEnumerateProcessHandlesEnumCallback61) +#pragma alloc_text(PAGE, KphpEnumerateProcessHandlesEnumCallback) +#pragma alloc_text(PAGE, KpiEnumerateProcessHandles) +#pragma alloc_text(PAGE, KphQueryNameObject) +#pragma alloc_text(PAGE, KphQueryNameFileObject) +#pragma alloc_text(PAGE, KpiQueryInformationObject) +#pragma alloc_text(PAGE, KpiSetInformationObject) +#pragma alloc_text(PAGE, KphOpenNamedObject) +#endif + +/** + * Gets a pointer to the handle table of a process. + * + * \param Process A process object. + * + * \return A pointer to the handle table, or NULL if the process is terminating or the request is + * not supported. You must call KphDereferenceProcessHandleTable() when the handle table is no + * longer needed. + */ +PHANDLE_TABLE KphReferenceProcessHandleTable( + __in PEPROCESS Process + ) +{ + PHANDLE_TABLE handleTable = NULL; + + PAGED_CODE(); + + // Fail if we don't have an offset. + if (KphDynEpObjectTable == -1) + return NULL; + + // Prevent the process from terminating and get its handle table. + if (NT_SUCCESS(PsAcquireProcessExitSynchronization(Process))) + { + handleTable = *(PHANDLE_TABLE *)((ULONG_PTR)Process + KphDynEpObjectTable); + + if (!handleTable) + PsReleaseProcessExitSynchronization(Process); + } + + return handleTable; +} + +/** + * Dereferences the handle table of a process. + * + * \param Process A process object. + */ +VOID KphDereferenceProcessHandleTable( + __in PEPROCESS Process + ) +{ + PAGED_CODE(); + + PsReleaseProcessExitSynchronization(Process); +} + +VOID KphUnlockHandleTableEntry( + __in PHANDLE_TABLE HandleTable, + __in PHANDLE_TABLE_ENTRY HandleTableEntry + ) +{ + PEX_PUSH_LOCK handleContentionEvent; + + PAGED_CODE(); + + // Set the unlocked bit. + +#ifdef _M_X64 + InterlockedExchangeAdd64(&HandleTableEntry->Value, 1); +#else + InterlockedExchangeAdd(&HandleTableEntry->Value, 1); +#endif + + // Allow waiters to wake up. + + handleContentionEvent = (PEX_PUSH_LOCK)((ULONG_PTR)HandleTable + KphDynHtHandleContentionEvent); + + if (*(PULONG_PTR)handleContentionEvent != 0) + ExfUnblockPushLock(handleContentionEvent, NULL); +} + +BOOLEAN KphpEnumerateProcessHandlesEnumCallback61( + __inout PHANDLE_TABLE_ENTRY HandleTableEntry, + __in HANDLE Handle, + __in PVOID Context + ) +{ + PKPHP_ENUMERATE_PROCESS_HANDLES_CONTEXT context = Context; + KPH_PROCESS_HANDLE handleInfo; + POBJECT_HEADER objectHeader; + POBJECT_TYPE objectType; + PKPH_PROCESS_HANDLE entryInBuffer; + + PAGED_CODE(); + + objectHeader = ObpDecodeObject(HandleTableEntry->Object); + handleInfo.Handle = Handle; + handleInfo.Object = objectHeader ? &objectHeader->Body : NULL; + handleInfo.GrantedAccess = ObpDecodeGrantedAccess(HandleTableEntry->GrantedAccess); + handleInfo.ObjectTypeIndex = -1; + handleInfo.Reserved1 = 0; + handleInfo.HandleAttributes = ObpGetHandleAttributes(HandleTableEntry); + handleInfo.Reserved2 = 0; + + if (handleInfo.Object) + { + objectType = ObGetObjectType(handleInfo.Object); + + if (objectType && KphDynOtIndex != -1) + handleInfo.ObjectTypeIndex = (USHORT)*(PUCHAR)((ULONG_PTR)objectType + KphDynOtIndex); + } + + // Advance the current entry pointer regardless of whether the information will be written; this + // will allow the parent function to report the correct return length. + entryInBuffer = context->CurrentEntry; + context->CurrentEntry = (PVOID)((ULONG_PTR)context->CurrentEntry + sizeof(KPH_PROCESS_HANDLE)); + context->Count++; + + // Only write if we have not exceeded the buffer length. Also check for a potential overflow (if + // the process has an extremely large number of handles, the buffer pointer may wrap). + if ( + (ULONG_PTR)entryInBuffer >= (ULONG_PTR)context->Buffer && + (ULONG_PTR)entryInBuffer + sizeof(KPH_PROCESS_HANDLE) <= (ULONG_PTR)context->BufferLimit + ) + { + __try + { + *entryInBuffer = handleInfo; + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + // Report an error. + if (context->Status == STATUS_SUCCESS) + context->Status = GetExceptionCode(); + } + } + else + { + // Report that the buffer is too small. + if (context->Status == STATUS_SUCCESS) + context->Status = STATUS_BUFFER_TOO_SMALL; + } + + return FALSE; +} + +BOOLEAN KphpEnumerateProcessHandlesEnumCallback( + __in PHANDLE_TABLE HandleTable, + __inout PHANDLE_TABLE_ENTRY HandleTableEntry, + __in HANDLE Handle, + __in PVOID Context + ) +{ + BOOLEAN result; + + PAGED_CODE(); + + result = KphpEnumerateProcessHandlesEnumCallback61(HandleTableEntry, Handle, Context); + KphUnlockHandleTableEntry(HandleTable, HandleTableEntry); + + return result; +} + +/** + * Enumerates the handles of a process. + * + * \param ProcessHandle A handle to a process. + * \param Buffer The buffer in which the handle information will be stored. + * \param BufferLength The number of bytes available in \a Buffer. + * \param ReturnLength A variable which receives the number of bytes required to be available in + * \a Buffer. + * \param AccessMode The mode in which to perform access checks. + */ +NTSTATUS KpiEnumerateProcessHandles( + __in HANDLE ProcessHandle, + __out_bcount(BufferLength) PVOID Buffer, + __in_opt ULONG BufferLength, + __out_opt PULONG ReturnLength, + __in KPROCESSOR_MODE AccessMode + ) +{ + NTSTATUS status; + BOOLEAN result; + PEPROCESS process; + PHANDLE_TABLE handleTable; + KPHP_ENUMERATE_PROCESS_HANDLES_CONTEXT context; + + PAGED_CODE(); + + if (KphDynNtVersion >= PHNT_WIN8 && KphDynHtHandleContentionEvent == -1) + { + return STATUS_NOT_SUPPORTED; + } + + if (AccessMode != KernelMode) + { + __try + { + ProbeForWrite(Buffer, BufferLength, sizeof(ULONG)); + + if (ReturnLength) + ProbeForWrite(ReturnLength, sizeof(ULONG), sizeof(ULONG)); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + return GetExceptionCode(); + } + } + + // Reference the process object. + status = ObReferenceObjectByHandle( + ProcessHandle, + 0, + *PsProcessType, + AccessMode, + &process, + NULL + ); + + if (!NT_SUCCESS(status)) + return status; + + // Get its handle table. + handleTable = KphReferenceProcessHandleTable(process); + + if (!handleTable) + { + ObDereferenceObject(process); + return STATUS_UNSUCCESSFUL; + } + + // Initialize the enumeration context. + context.Buffer = Buffer; + context.BufferLimit = (PVOID)((ULONG_PTR)Buffer + BufferLength); + context.CurrentEntry = ((PKPH_PROCESS_HANDLE_INFORMATION)Buffer)->Handles; + context.Count = 0; + context.Status = STATUS_SUCCESS; + + // Enumerate the handles. + + if (KphDynNtVersion >= PHNT_WIN8) + { + result = ExEnumHandleTable( + handleTable, + KphpEnumerateProcessHandlesEnumCallback, + &context, + NULL + ); + } + else + { + result = ExEnumHandleTable( + handleTable, + (PEX_ENUM_HANDLE_CALLBACK)KphpEnumerateProcessHandlesEnumCallback61, + &context, + NULL + ); + } + + KphDereferenceProcessHandleTable(process); + ObDereferenceObject(process); + + // Write the number of handles if we can. + if (BufferLength >= FIELD_OFFSET(KPH_PROCESS_HANDLE_INFORMATION, Handles)) + { + if (AccessMode != KernelMode) + { + __try + { + ((PKPH_PROCESS_HANDLE_INFORMATION)Buffer)->HandleCount = context.Count; + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + return GetExceptionCode(); + } + } + else + { + ((PKPH_PROCESS_HANDLE_INFORMATION)Buffer)->HandleCount = context.Count; + } + } + + // Supply the return length if the caller wanted it. + if (ReturnLength) + { + ULONG returnLength; + + // Note: if the CurrentEntry pointer wrapped, this will give the wrong return length. + returnLength = (ULONG)((ULONG_PTR)context.CurrentEntry - (ULONG_PTR)Buffer); + + if (AccessMode != KernelMode) + { + __try + { + *ReturnLength = returnLength; + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + return GetExceptionCode(); + } + } + else + { + *ReturnLength = returnLength; + } + } + + return context.Status; +} + +/** + * Queries the name of an object. + * + * \param Object A pointer to an object. + * \param Buffer The buffer in which the object name will be stored. + * \param BufferLength The number of bytes available in \a Buffer. + * \param ReturnLength A variable which receives the number of bytes required to be available in + * \a Buffer. + */ +NTSTATUS KphQueryNameObject( + __in PVOID Object, + __out_bcount(BufferLength) POBJECT_NAME_INFORMATION Buffer, + __in ULONG BufferLength, + __out PULONG ReturnLength + ) +{ + NTSTATUS status; + POBJECT_TYPE objectType; + + PAGED_CODE(); + + objectType = ObGetObjectType(Object); + + // Check if we are going to hang when querying the object, and use + // the special file object query function if needed. + if (objectType == *IoFileObjectType && + (((PFILE_OBJECT)Object)->Busy || ((PFILE_OBJECT)Object)->Waiters)) + { + status = KphQueryNameFileObject(Object, Buffer, BufferLength, ReturnLength); + dprintf("KphQueryNameFileObject: status 0x%x\n", status); + } + else + { + status = ObQueryNameString(Object, Buffer, BufferLength, ReturnLength); + dprintf("ObQueryNameString: status 0x%x\n", status); + } + + // Make the error returns consistent. + if (status == STATUS_BUFFER_OVERFLOW) // returned by I/O subsystem + status = STATUS_BUFFER_TOO_SMALL; + if (status == STATUS_INFO_LENGTH_MISMATCH) // returned by ObQueryNameString + status = STATUS_BUFFER_TOO_SMALL; + + if (NT_SUCCESS(status)) + dprintf("KphQueryNameObject: %.*S\n", Buffer->Name.Length / sizeof(WCHAR), Buffer->Name.Buffer); + else + dprintf("KphQueryNameObject: status 0x%x\n", status); + + return status; +} + +/** + * Queries the name of a file object. + * + * \param FileObject A pointer to a file object. + * \param Buffer The buffer in which the object name will be stored. + * \param BufferLength The number of bytes available in \a Buffer. + * \param ReturnLength A variable which receives the number of bytes required to be available in + * \a Buffer. + */ +NTSTATUS KphQueryNameFileObject( + __in PFILE_OBJECT FileObject, + __out_bcount(BufferLength) POBJECT_NAME_INFORMATION Buffer, + __in ULONG BufferLength, + __out PULONG ReturnLength + ) +{ + NTSTATUS status = STATUS_SUCCESS; + ULONG returnLength; + PCHAR objectName; + ULONG usedLength; + ULONG subNameLength; + PFILE_OBJECT relatedFileObject; + + PAGED_CODE(); + + // We need at least the size of OBJECT_NAME_INFORMATION to continue. + if (BufferLength < sizeof(OBJECT_NAME_INFORMATION)) + { + *ReturnLength = sizeof(OBJECT_NAME_INFORMATION); + + return STATUS_BUFFER_TOO_SMALL; + } + + // Assume failure. + Buffer->Name.Length = 0; + // We will place the object name directly after the UNICODE_STRING structure in the buffer. + Buffer->Name.Buffer = (PWSTR)((ULONG_PTR)Buffer + sizeof(OBJECT_NAME_INFORMATION)); + // Retain a local pointer to the object name so we can manipulate the pointer. + objectName = (PCHAR)Buffer->Name.Buffer; + // A variable that keeps track of how much space we have used. + usedLength = sizeof(OBJECT_NAME_INFORMATION); + + // Check if the file object has an associated device (e.g. "\Device\NamedPipe", "\Device\Mup"). + // We can use the user-supplied buffer for this since if the buffer isn't big enough, we can't + // proceed anyway (we are going to use the name). + if (FileObject->DeviceObject) + { + status = ObQueryNameString( + FileObject->DeviceObject, + Buffer, + BufferLength, + &returnLength + ); + + if (!NT_SUCCESS(status)) + { + if (status == STATUS_INFO_LENGTH_MISMATCH) + status = STATUS_BUFFER_TOO_SMALL; + + *ReturnLength = returnLength; + + return status; + } + + // The UNICODE_STRING in the buffer is now filled in. We will append to the object name + // later, so we need to fix the object name pointer by adding the length, in bytes, of the + // device name string we just got. + objectName += Buffer->Name.Length; + usedLength += Buffer->Name.Length; + } + + // Check if the file object has a file name component. If not, we can't do anything else, so we + // just return the name we have already. + if (!FileObject->FileName.Buffer) + { + *ReturnLength = usedLength; + + return STATUS_SUCCESS; + } + + // The file object has a name. We need to walk up the file object chain and append the names of + // the related file objects in reverse order. This means we need to calculate the total length + // first. + + relatedFileObject = FileObject; + subNameLength = 0; + + do + { + subNameLength += relatedFileObject->FileName.Length; + + // Avoid infinite loops. + if (relatedFileObject == relatedFileObject->RelatedFileObject) + break; + + relatedFileObject = relatedFileObject->RelatedFileObject; + } while (relatedFileObject); + + usedLength += subNameLength; + + // Check if we have enough space to write the whole thing. + if (usedLength > BufferLength) + { + *ReturnLength = usedLength; + + return STATUS_BUFFER_TOO_SMALL; + } + + // We're ready to begin copying the names. + + // Add the name length because we're copying in reverse order. + objectName += subNameLength; + + relatedFileObject = FileObject; + + do + { + objectName -= relatedFileObject->FileName.Length; + memcpy(objectName, relatedFileObject->FileName.Buffer, relatedFileObject->FileName.Length); + + // Avoid infinite loops. + if (relatedFileObject == relatedFileObject->RelatedFileObject) + break; + + relatedFileObject = relatedFileObject->RelatedFileObject; + } while (relatedFileObject); + + // Update the length. + Buffer->Name.Length += (USHORT)subNameLength; + + // Pass the return length back. + *ReturnLength = usedLength; + + return STATUS_SUCCESS; +} + +/** + * Queries object information. + * + * \param ProcessHandle A handle to a process. + * \param Handle A handle which is present in the process referenced by \a ProcessHandle. + * \param ObjectInformationClass The type of information to retrieve. + * \param ObjectInformation The buffer in which the information will be stored. + * \param ObjectInformationLength The number of bytes available in \a ObjectInformation. + * \param ReturnLength A variable which receives the number of bytes required to be available in + * \a ObjectInformation. + * \param AccessMode The mode in which to perform access checks. + */ +NTSTATUS KpiQueryInformationObject( + __in HANDLE ProcessHandle, + __in HANDLE Handle, + __in KPH_OBJECT_INFORMATION_CLASS ObjectInformationClass, + __out_bcount(ObjectInformationLength) PVOID ObjectInformation, + __in ULONG ObjectInformationLength, + __out_opt PULONG ReturnLength, + __in KPROCESSOR_MODE AccessMode + ) +{ + NTSTATUS status; + PEPROCESS process; + KPROCESSOR_MODE referenceMode; + KAPC_STATE apcState; + ULONG returnLength; + + PAGED_CODE(); + + if (AccessMode != KernelMode) + { + __try + { + ProbeForWrite(ObjectInformation, ObjectInformationLength, sizeof(ULONG)); + + if (ReturnLength) + ProbeForWrite(ReturnLength, sizeof(ULONG), sizeof(ULONG)); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + return GetExceptionCode(); + } + } + + status = ObReferenceObjectByHandle( + ProcessHandle, + 0, + *PsProcessType, + AccessMode, + &process, + NULL + ); + + if (!NT_SUCCESS(status)) + return status; + + if (process == PsInitialSystemProcess) + { + // A check was added in Windows 7 - if we're attached to the System process, the handle must + // be a kernel handle. + Handle = MakeKernelHandle(Handle); + referenceMode = KernelMode; + } + else + { + // Make sure the handle isn't a kernel handle if we're not attached to the System process. + // This means we can avoid referencing then opening the objects later when calling + // ZwQueryObject, etc. + if (IsKernelHandle(Handle)) + { + ObDereferenceObject(process); + return STATUS_INVALID_HANDLE; + } + + referenceMode = AccessMode; + } + + switch (ObjectInformationClass) + { + case KphObjectBasicInformation: + { + OBJECT_BASIC_INFORMATION basicInfo; + + KeStackAttachProcess(process, &apcState); + status = ZwQueryObject( + Handle, + ObjectBasicInformation, + &basicInfo, + sizeof(OBJECT_BASIC_INFORMATION), + NULL + ); + KeUnstackDetachProcess(&apcState); + + if (NT_SUCCESS(status)) + { + if (ObjectInformationLength == sizeof(OBJECT_BASIC_INFORMATION)) + { + __try + { + *(POBJECT_BASIC_INFORMATION)ObjectInformation = basicInfo; + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + status = GetExceptionCode(); + } + } + else + { + status = STATUS_INFO_LENGTH_MISMATCH; + } + } + + returnLength = sizeof(OBJECT_BASIC_INFORMATION); + } + break; + case KphObjectNameInformation: + { + PVOID object; + ULONG allocateSize; + POBJECT_NAME_INFORMATION nameInfo; + + returnLength = sizeof(OBJECT_NAME_INFORMATION); + + // Attach to the process a get a pointer to the object. + KeStackAttachProcess(process, &apcState); + status = ObReferenceObjectByHandle( + Handle, + 0, + NULL, + referenceMode, + &object, + NULL + ); + KeUnstackDetachProcess(&apcState); + + if (NT_SUCCESS(status)) + { + allocateSize = ObjectInformationLength; + + if (allocateSize < sizeof(OBJECT_NAME_INFORMATION)) // make sure we never try to allocate 0 bytes + allocateSize = sizeof(OBJECT_NAME_INFORMATION); + + nameInfo = ExAllocatePoolWithQuotaTag(PagedPool, allocateSize, 'QhpK'); + + if (nameInfo) + { + // Make sure we don't leak any data. + memset(nameInfo, 0, ObjectInformationLength); + + status = KphQueryNameObject( + object, + nameInfo, + ObjectInformationLength, + &returnLength + ); + dprintf("KpiQueryInformationObject: called KphQueryNameObject: Handle: 0x%Ix, ObjectInformationLength: %u, returnLength: %u\n", + Handle, ObjectInformationLength, returnLength); + + if (NT_SUCCESS(status)) + { + // Fix up the buffer pointer. + if (nameInfo->Name.Buffer) + nameInfo->Name.Buffer = (PVOID)((ULONG_PTR)nameInfo->Name.Buffer - (ULONG_PTR)nameInfo + (ULONG_PTR)ObjectInformation); + + __try + { + memcpy(ObjectInformation, nameInfo, ObjectInformationLength); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + status = GetExceptionCode(); + } + } + + ExFreePoolWithTag(nameInfo, 'QhpK'); + } + else + { + status = STATUS_INSUFFICIENT_RESOURCES; + } + + ObDereferenceObject(object); + } + } + break; + case KphObjectTypeInformation: + { + ULONG allocateSize; + POBJECT_TYPE_INFORMATION typeInfo; + + returnLength = sizeof(OBJECT_TYPE_INFORMATION); + allocateSize = ObjectInformationLength; + + if (allocateSize < sizeof(OBJECT_TYPE_INFORMATION)) + allocateSize = sizeof(OBJECT_TYPE_INFORMATION); + + // ObQueryTypeInfo uses ObjectType->Name.MaximumLength instead of + // ObjectType->Name.Length + sizeof(WCHAR) to calculate the required buffer size. In + // Windows 8, certain object types (e.g. TmTx) do NOT include the null terminator in + // MaximumLength, which causes ObQueryTypeInfo to overrun the given buffer. To work + // around this bug, we add some (generous) padding to our allocation. + allocateSize += sizeof(ULONGLONG); + + typeInfo = ExAllocatePoolWithQuotaTag(PagedPool, allocateSize, 'QhpK'); + + if (typeInfo) + { + memset(typeInfo, 0, ObjectInformationLength); + + KeStackAttachProcess(process, &apcState); + status = ZwQueryObject( + Handle, + ObjectTypeInformation, + typeInfo, + ObjectInformationLength, + &returnLength + ); + KeUnstackDetachProcess(&apcState); + + if (NT_SUCCESS(status)) + { + // Fix up the buffer pointer. + if (typeInfo->TypeName.Buffer) + typeInfo->TypeName.Buffer = (PVOID)((ULONG_PTR)typeInfo->TypeName.Buffer - (ULONG_PTR)typeInfo + (ULONG_PTR)ObjectInformation); + + __try + { + memcpy(ObjectInformation, typeInfo, ObjectInformationLength); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + status = GetExceptionCode(); + } + } + + ExFreePoolWithTag(typeInfo, 'QhpK'); + } + else + { + status = STATUS_INSUFFICIENT_RESOURCES; + } + } + break; + case KphObjectHandleFlagInformation: + { + OBJECT_HANDLE_FLAG_INFORMATION handleFlagInfo; + + KeStackAttachProcess(process, &apcState); + status = ZwQueryObject( + Handle, + ObjectHandleFlagInformation, + &handleFlagInfo, + sizeof(OBJECT_HANDLE_FLAG_INFORMATION), + NULL + ); + KeUnstackDetachProcess(&apcState); + + if (NT_SUCCESS(status)) + { + if (ObjectInformationLength == sizeof(OBJECT_HANDLE_FLAG_INFORMATION)) + { + __try + { + *(POBJECT_HANDLE_FLAG_INFORMATION)ObjectInformation = handleFlagInfo; + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + status = GetExceptionCode(); + } + } + else + { + status = STATUS_INFO_LENGTH_MISMATCH; + } + } + + returnLength = sizeof(OBJECT_HANDLE_FLAG_INFORMATION); + } + break; + case KphObjectProcessBasicInformation: + { + PROCESS_BASIC_INFORMATION basicInfo; + + KeStackAttachProcess(process, &apcState); + status = ZwQueryInformationProcess( + Handle, + ProcessBasicInformation, + &basicInfo, + sizeof(PROCESS_BASIC_INFORMATION), + NULL + ); + KeUnstackDetachProcess(&apcState); + + if (NT_SUCCESS(status)) + { + if (ObjectInformationLength == sizeof(PROCESS_BASIC_INFORMATION)) + { + __try + { + *(PPROCESS_BASIC_INFORMATION)ObjectInformation = basicInfo; + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + status = GetExceptionCode(); + } + } + else + { + status = STATUS_INFO_LENGTH_MISMATCH; + } + } + + returnLength = sizeof(PROCESS_BASIC_INFORMATION); + } + break; + case KphObjectThreadBasicInformation: + { + THREAD_BASIC_INFORMATION basicInfo; + + KeStackAttachProcess(process, &apcState); + status = ZwQueryInformationThread( + Handle, + ThreadBasicInformation, + &basicInfo, + sizeof(THREAD_BASIC_INFORMATION), + NULL + ); + KeUnstackDetachProcess(&apcState); + + if (NT_SUCCESS(status)) + { + if (ObjectInformationLength == sizeof(THREAD_BASIC_INFORMATION)) + { + __try + { + *(PTHREAD_BASIC_INFORMATION)ObjectInformation = basicInfo; + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + status = GetExceptionCode(); + } + } + else + { + status = STATUS_INFO_LENGTH_MISMATCH; + } + } + + returnLength = sizeof(THREAD_BASIC_INFORMATION); + } + break; + case KphObjectEtwRegBasicInformation: + { + PVOID etwReg; + PVOID objectType; + PUNICODE_STRING objectTypeName; + UNICODE_STRING etwRegistrationName; + PVOID guidEntry; + ETWREG_BASIC_INFORMATION basicInfo; + + // Check dynamic data requirements. + if (KphDynEgeGuid != -1 && + KphDynEreGuidEntry != -1 && + KphDynOtName != -1) + { + // Attach to the process and get a pointer to the object. We don't have a pointer to + // the EtwRegistration object type, so we'll just have to check the type name. + + KeStackAttachProcess(process, &apcState); + status = ObReferenceObjectByHandle( + Handle, + 0, + NULL, + referenceMode, + &etwReg, + NULL + ); + KeUnstackDetachProcess(&apcState); + + if (NT_SUCCESS(status)) + { + // Check the type name. + + objectType = ObGetObjectType(etwReg); + + if (objectType) + { + objectTypeName = (PUNICODE_STRING)((ULONG_PTR)objectType + KphDynOtName); + RtlInitUnicodeString(&etwRegistrationName, L"EtwRegistration"); + + if (!RtlEqualUnicodeString(objectTypeName, &etwRegistrationName, FALSE)) + { + status = STATUS_OBJECT_TYPE_MISMATCH; + } + } + else + { + status = STATUS_NOT_SUPPORTED; + } + + if (NT_SUCCESS(status)) + { + guidEntry = *(PVOID *)((ULONG_PTR)etwReg + KphDynEreGuidEntry); + + if (guidEntry) + basicInfo.Guid = *(GUID *)((ULONG_PTR)guidEntry + KphDynEgeGuid); + else + memset(&basicInfo.Guid, 0, sizeof(GUID)); + + basicInfo.SessionId = 0; // not implemented + + if (ObjectInformationLength == sizeof(ETWREG_BASIC_INFORMATION)) + { + __try + { + *(PETWREG_BASIC_INFORMATION)ObjectInformation = basicInfo; + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + status = GetExceptionCode(); + } + } + else + { + status = STATUS_INFO_LENGTH_MISMATCH; + } + } + + ObDereferenceObject(etwReg); + } + } + else + { + status = STATUS_NOT_SUPPORTED; + } + + returnLength = sizeof(ETWREG_BASIC_INFORMATION); + } + break; + case KphObjectFileObjectInformation: + { + PFILE_OBJECT fileObject; + KPH_FILE_OBJECT_INFORMATION objectInfo; + + KeStackAttachProcess(process, &apcState); + status = ObReferenceObjectByHandle( + Handle, + 0, + *IoFileObjectType, + referenceMode, + &fileObject, + NULL + ); + KeUnstackDetachProcess(&apcState); + + if (NT_SUCCESS(status)) + { + objectInfo.LockOperation = fileObject->LockOperation; + objectInfo.DeletePending = fileObject->DeletePending; + objectInfo.ReadAccess = fileObject->ReadAccess; + objectInfo.WriteAccess = fileObject->WriteAccess; + objectInfo.DeleteAccess = fileObject->DeleteAccess; + objectInfo.SharedRead = fileObject->SharedRead; + objectInfo.SharedWrite = fileObject->SharedWrite; + objectInfo.SharedDelete = fileObject->SharedDelete; + objectInfo.CurrentByteOffset = fileObject->CurrentByteOffset; + objectInfo.Flags = fileObject->Flags; + + if (ObjectInformationLength == sizeof(KPH_FILE_OBJECT_INFORMATION)) + { + __try + { + *(PKPH_FILE_OBJECT_INFORMATION)ObjectInformation = objectInfo; + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + status = GetExceptionCode(); + } + } + else + { + status = STATUS_INFO_LENGTH_MISMATCH; + } + + ObDereferenceObject(fileObject); + } + + returnLength = sizeof(KPH_FILE_OBJECT_INFORMATION); + } + break; + case KphObjectFileObjectDriver: + { + PFILE_OBJECT fileObject; + HANDLE driverHandle; + + if (ObjectInformationLength == sizeof(KPH_FILE_OBJECT_DRIVER)) + { + KeStackAttachProcess(process, &apcState); + status = ObReferenceObjectByHandle( + Handle, + 0, + *IoFileObjectType, + referenceMode, + &fileObject, + NULL + ); + KeUnstackDetachProcess(&apcState); + + if (NT_SUCCESS(status)) + { + if (fileObject->DeviceObject && fileObject->DeviceObject->DriverObject) + { + status = ObOpenObjectByPointer( + fileObject->DeviceObject->DriverObject, + 0, + NULL, + SYNCHRONIZE, + *IoDriverObjectType, + AccessMode, + &driverHandle + ); + } + else + { + driverHandle = NULL; + } + + if (NT_SUCCESS(status)) + { + __try + { + ((PKPH_FILE_OBJECT_DRIVER)ObjectInformation)->DriverHandle = driverHandle; + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + status = GetExceptionCode(); + } + } + + ObDereferenceObject(fileObject); + } + } + else + { + status = STATUS_INFO_LENGTH_MISMATCH; + } + } + break; + default: + status = STATUS_INVALID_INFO_CLASS; + returnLength = 0; + break; + } + + ObDereferenceObject(process); + + if (ReturnLength) + { + if (AccessMode != KernelMode) + { + __try + { + *ReturnLength = returnLength; + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + NOTHING; + } + } + else + { + *ReturnLength = returnLength; + } + } + + return status; +} + +/** + * Sets object information. + * + * \param ProcessHandle A handle to a process. + * \param Handle A handle which is present in the process referenced by \a ProcessHandle. + * \param ObjectInformationClass The type of information to set. + * \param ObjectInformation A buffer which contains the information to set. + * \param ObjectInformationLength The number of bytes present in \a ObjectInformation. + * \param AccessMode The mode in which to perform access checks. + */ +NTSTATUS KpiSetInformationObject( + __in HANDLE ProcessHandle, + __in HANDLE Handle, + __in KPH_OBJECT_INFORMATION_CLASS ObjectInformationClass, + __in_bcount(ObjectInformationLength) PVOID ObjectInformation, + __in ULONG ObjectInformationLength, + __in KPROCESSOR_MODE AccessMode + ) +{ + NTSTATUS status; + PEPROCESS process; + KAPC_STATE apcState; + + PAGED_CODE(); + + if (AccessMode != KernelMode) + { + ULONG alignment; + + switch (ObjectInformationClass) + { + case KphObjectHandleFlagInformation: + alignment = sizeof(BOOLEAN); + break; + default: + alignment = sizeof(ULONG); + break; + } + + __try + { + ProbeForRead(ObjectInformation, ObjectInformationLength, alignment); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + return GetExceptionCode(); + } + } + + status = ObReferenceObjectByHandle( + ProcessHandle, + 0, + *PsProcessType, + AccessMode, + &process, + NULL + ); + + if (!NT_SUCCESS(status)) + return status; + + if (process == PsInitialSystemProcess) + { + Handle = MakeKernelHandle(Handle); + } + else + { + if (IsKernelHandle(Handle)) + { + ObDereferenceObject(process); + return STATUS_INVALID_HANDLE; + } + } + + switch (ObjectInformationClass) + { + case KphObjectHandleFlagInformation: + { + OBJECT_HANDLE_FLAG_INFORMATION handleFlagInfo; + + if (ObjectInformationLength == sizeof(OBJECT_HANDLE_FLAG_INFORMATION)) + { + __try + { + handleFlagInfo = *(POBJECT_HANDLE_FLAG_INFORMATION)ObjectInformation; + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + status = GetExceptionCode(); + } + } + else + { + status = STATUS_INFO_LENGTH_MISMATCH; + } + + if (NT_SUCCESS(status)) + { + KeStackAttachProcess(process, &apcState); + status = ObSetHandleAttributes(Handle, &handleFlagInfo, KernelMode); + KeUnstackDetachProcess(&apcState); + } + } + break; + default: + status = STATUS_INVALID_INFO_CLASS; + break; + } + + ObDereferenceObject(process); + + return status; +} + +NTSTATUS KphOpenNamedObject( + __out PHANDLE ObjectHandle, + __in ACCESS_MASK DesiredAccess, + __in POBJECT_ATTRIBUTES ObjectAttributes, + __in POBJECT_TYPE ObjectType, + __in KPROCESSOR_MODE AccessMode + ) +{ + NTSTATUS status; + HANDLE objectHandle; + + PAGED_CODE(); + + // Open the object. + status = ObOpenObjectByName( + ObjectAttributes, + ObjectType, + AccessMode, + NULL, + DesiredAccess, + NULL, + &objectHandle + ); + + // Pass the handle back. + if (AccessMode != KernelMode) + { + __try + { + *ObjectHandle = objectHandle; + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + status = GetExceptionCode(); + } + } + else + { + *ObjectHandle = objectHandle; + } + + return status; +} diff --git a/KProcessHacker/process.c b/KProcessHacker/process.c index bdb27261fa3b..c0aa6d1b63d2 100644 --- a/KProcessHacker/process.c +++ b/KProcessHacker/process.c @@ -1,570 +1,570 @@ -/* - * KProcessHacker - * - * Copyright (C) 2010-2016 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include -#include - -#ifdef ALLOC_PRAGMA -#pragma alloc_text(PAGE, KpiOpenProcess) -#pragma alloc_text(PAGE, KpiOpenProcessToken) -#pragma alloc_text(PAGE, KpiOpenProcessJob) -#pragma alloc_text(PAGE, KpiTerminateProcess) -#pragma alloc_text(PAGE, KpiQueryInformationProcess) -#pragma alloc_text(PAGE, KpiSetInformationProcess) -#endif - -/** - * Opens a process. - * - * \param ProcessHandle A variable which receives the process handle. - * \param DesiredAccess The desired access to the process. - * \param ClientId The identifier of a process or thread. If \a UniqueThread is present, the process - * of the identified thread will be opened. If \a UniqueProcess is present, the identified process - * will be opened. - * \param Key An access key. - * \li If a L2 key is provided, no access checks are performed. - * \li If a L1 key is provided, only read access is permitted but no additional access checks are - * performed. - * \li If no valid key is provided, the function fails. - * \param Client The client that initiated the request. - * \param AccessMode The mode in which to perform access checks. - */ -NTSTATUS KpiOpenProcess( - __out PHANDLE ProcessHandle, - __in ACCESS_MASK DesiredAccess, - __in PCLIENT_ID ClientId, - __in_opt KPH_KEY Key, - __in PKPH_CLIENT Client, - __in KPROCESSOR_MODE AccessMode - ) -{ - NTSTATUS status; - CLIENT_ID clientId; - PEPROCESS process; - PETHREAD thread; - KPH_KEY_LEVEL requiredKeyLevel; - HANDLE processHandle; - - PAGED_CODE(); - - if (AccessMode != KernelMode) - { - __try - { - ProbeForWrite(ProcessHandle, sizeof(HANDLE), sizeof(HANDLE)); - ProbeForRead(ClientId, sizeof(CLIENT_ID), sizeof(ULONG)); - clientId = *ClientId; - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - return GetExceptionCode(); - } - } - else - { - clientId = *ClientId; - } - - // Use the thread ID if it was specified. - if (clientId.UniqueThread) - { - status = PsLookupProcessThreadByCid(&clientId, &process, &thread); - - if (NT_SUCCESS(status)) - { - // We don't actually need the thread. - ObDereferenceObject(thread); - } - } - else - { - status = PsLookupProcessByProcessId(clientId.UniqueProcess, &process); - } - - if (!NT_SUCCESS(status)) - return status; - - requiredKeyLevel = KphKeyLevel1; - - if ((DesiredAccess & KPH_PROCESS_READ_ACCESS) != DesiredAccess) - requiredKeyLevel = KphKeyLevel2; - - if (NT_SUCCESS(status = KphValidateKey(requiredKeyLevel, Key, Client, AccessMode))) - { - // Always open in KernelMode to skip ordinary access checks. - status = ObOpenObjectByPointer( - process, - 0, - NULL, - DesiredAccess, - *PsProcessType, - KernelMode, - &processHandle - ); - } - - ObDereferenceObject(process); - - if (NT_SUCCESS(status)) - { - if (AccessMode != KernelMode) - { - __try - { - *ProcessHandle = processHandle; - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - status = GetExceptionCode(); - } - } - else - { - *ProcessHandle = processHandle; - } - } - - return status; -} - -/** - * Opens the token of a process. - * - * \param ProcessHandle A handle to a process. - * \param DesiredAccess The desired access to the token. - * \param TokenHandle A variable which receives the token handle. - * \param Key An access key. - * \li If a L2 key is provided, no access checks are performed. - * \li If a L1 key is provided, only read access is permitted but no additional access checks are - * performed. - * \li If no valid key is provided, the function fails. - * \param Client The client that initiated the request. - * \param AccessMode The mode in which to perform access checks. - */ -NTSTATUS KpiOpenProcessToken( - __in HANDLE ProcessHandle, - __in ACCESS_MASK DesiredAccess, - __out PHANDLE TokenHandle, - __in_opt KPH_KEY Key, - __in PKPH_CLIENT Client, - __in KPROCESSOR_MODE AccessMode - ) -{ - NTSTATUS status; - PEPROCESS process; - PACCESS_TOKEN primaryToken; - KPH_KEY_LEVEL requiredKeyLevel; - HANDLE tokenHandle; - - PAGED_CODE(); - - if (AccessMode != KernelMode) - { - __try - { - ProbeForWrite(TokenHandle, sizeof(HANDLE), sizeof(HANDLE)); - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - return GetExceptionCode(); - } - } - - status = ObReferenceObjectByHandle( - ProcessHandle, - 0, - *PsProcessType, - AccessMode, - &process, - NULL - ); - - if (!NT_SUCCESS(status)) - return status; - - if (primaryToken = PsReferencePrimaryToken(process)) - { - requiredKeyLevel = KphKeyLevel1; - - if ((DesiredAccess & KPH_TOKEN_READ_ACCESS) != DesiredAccess) - requiredKeyLevel = KphKeyLevel2; - - if (NT_SUCCESS(status = KphValidateKey(requiredKeyLevel, Key, Client, AccessMode))) - { - status = ObOpenObjectByPointer( - primaryToken, - 0, - NULL, - DesiredAccess, - *SeTokenObjectType, - KernelMode, - &tokenHandle - ); - } - - PsDereferencePrimaryToken(primaryToken); - } - else - { - status = STATUS_NO_TOKEN; - } - - ObDereferenceObject(process); - - if (NT_SUCCESS(status)) - { - if (AccessMode != KernelMode) - { - __try - { - *TokenHandle = tokenHandle; - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - status = GetExceptionCode(); - } - } - else - { - *TokenHandle = tokenHandle; - } - } - - return status; -} - -/** - * Opens the job object of a process. - * - * \param ProcessHandle A handle to a process. - * \param DesiredAccess The desired access to the job. - * \param JobHandle A variable which receives the job object handle. - * \param AccessMode The mode in which to perform access checks. - */ -NTSTATUS KpiOpenProcessJob( - __in HANDLE ProcessHandle, - __in ACCESS_MASK DesiredAccess, - __out PHANDLE JobHandle, - __in KPROCESSOR_MODE AccessMode - ) -{ - NTSTATUS status; - PEPROCESS process; - PEJOB job; - HANDLE jobHandle = NULL; - - PAGED_CODE(); - - if (AccessMode != KernelMode) - { - __try - { - ProbeForWrite(JobHandle, sizeof(HANDLE), sizeof(HANDLE)); - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - return GetExceptionCode(); - } - } - - status = ObReferenceObjectByHandle( - ProcessHandle, - 0, - *PsProcessType, - AccessMode, - &process, - NULL - ); - - if (!NT_SUCCESS(status)) - return status; - - job = PsGetProcessJob(process); - - if (job) - { - status = ObOpenObjectByPointer( - job, - 0, - NULL, - DesiredAccess, - *PsJobType, - AccessMode, - &jobHandle - ); - } - else - { - status = STATUS_NOT_FOUND; - } - - ObDereferenceObject(process); - - if (NT_SUCCESS(status)) - { - if (AccessMode != KernelMode) - { - __try - { - *JobHandle = jobHandle; - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - status = GetExceptionCode(); - } - } - else - { - *JobHandle = jobHandle; - } - } - - return status; -} - -/** - * Terminates a process. - * - * \param ProcessHandle A handle to a process. - * \param ExitStatus A status value which indicates why the process is being terminated. - * \param Key An access key. - * \li If a L2 key is provided, no access checks are performed. - * \li If no valid L2 key is provided, the function fails. - * \param Client The client that initiated the request. - * \param AccessMode The mode in which to perform access checks. - */ -NTSTATUS KpiTerminateProcess( - __in HANDLE ProcessHandle, - __in NTSTATUS ExitStatus, - __in_opt KPH_KEY Key, - __in PKPH_CLIENT Client, - __in KPROCESSOR_MODE AccessMode - ) -{ - NTSTATUS status; - PEPROCESS process; - - PAGED_CODE(); - - if (!NT_SUCCESS(status = KphValidateKey(KphKeyLevel2, Key, Client, AccessMode))) - return status; - - status = ObReferenceObjectByHandle( - ProcessHandle, - 0, - *PsProcessType, - AccessMode, - &process, - NULL - ); - - if (!NT_SUCCESS(status)) - return status; - - if (process != PsGetCurrentProcess()) - { - HANDLE newProcessHandle; - - // Re-open the process to get a kernel handle. - if (NT_SUCCESS(status = ObOpenObjectByPointer( - process, - OBJ_KERNEL_HANDLE, - NULL, - PROCESS_TERMINATE, - *PsProcessType, - KernelMode, - &newProcessHandle - ))) - { - status = ZwTerminateProcess(newProcessHandle, ExitStatus); - ZwClose(newProcessHandle); - } - } - else - { - status = STATUS_CANT_TERMINATE_SELF; - } - - ObDereferenceObject(process); - - return status; -} - -/** - * Queries process information. - * - * \param ProcessHandle A handle to a process. - * \param ProcessInformationClass The type of information to query. - * \param ProcessInformation The buffer in which the information will be stored. - * \param ProcessInformationLength The number of bytes available in \a ProcessInformation. - * \param ReturnLength A variable which receives the number of bytes required to be available in - * \a ProcessInformation. - * \param AccessMode The mode in which to perform access checks. - */ -NTSTATUS KpiQueryInformationProcess( - __in HANDLE ProcessHandle, - __in KPH_PROCESS_INFORMATION_CLASS ProcessInformationClass, - __out_bcount(ProcessInformationLength) PVOID ProcessInformation, - __in ULONG ProcessInformationLength, - __out_opt PULONG ReturnLength, - __in KPROCESSOR_MODE AccessMode - ) -{ - NTSTATUS status; - PEPROCESS process; - ULONG returnLength; - - PAGED_CODE(); - - if (AccessMode != KernelMode) - { - ULONG alignment; - - switch (ProcessInformationClass) - { - default: - alignment = sizeof(ULONG); - break; - } - - __try - { - ProbeForWrite(ProcessInformation, ProcessInformationLength, alignment); - - if (ReturnLength) - ProbeForWrite(ReturnLength, sizeof(ULONG), sizeof(ULONG)); - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - return GetExceptionCode(); - } - } - - status = ObReferenceObjectByHandle( - ProcessHandle, - PROCESS_QUERY_INFORMATION, - *PsProcessType, - AccessMode, - &process, - NULL - ); - - if (!NT_SUCCESS(status)) - return status; - - switch (ProcessInformationClass) - { - default: - status = STATUS_INVALID_INFO_CLASS; - returnLength = 0; - break; - } - - ObDereferenceObject(process); - - if (ReturnLength) - { - if (AccessMode != KernelMode) - { - __try - { - *ReturnLength = returnLength; - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - NOTHING; - } - } - else - { - *ReturnLength = returnLength; - } - } - - return status; -} - -/** - * Sets process information. - * - * \param ProcessHandle A handle to a process. - * \param ProcessInformationClass The type of information to set. - * \param ProcessInformation A buffer which contains the information to set. - * \param ProcessInformationLength The number of bytes present in \a ProcessInformation. - * \param AccessMode The mode in which to perform access checks. - */ -NTSTATUS KpiSetInformationProcess( - __in HANDLE ProcessHandle, - __in KPH_PROCESS_INFORMATION_CLASS ProcessInformationClass, - __in_bcount(ProcessInformationLength) PVOID ProcessInformation, - __in ULONG ProcessInformationLength, - __in KPROCESSOR_MODE AccessMode - ) -{ - NTSTATUS status; - PEPROCESS process; - - PAGED_CODE(); - - if (AccessMode != KernelMode) - { - ULONG alignment; - - switch (ProcessInformationClass) - { - default: - alignment = sizeof(ULONG); - break; - } - - __try - { - ProbeForRead(ProcessInformation, ProcessInformationLength, alignment); - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - return GetExceptionCode(); - } - } - - status = ObReferenceObjectByHandle( - ProcessHandle, - PROCESS_SET_INFORMATION, - *PsProcessType, - AccessMode, - &process, - NULL - ); - - if (!NT_SUCCESS(status)) - return status; - - switch (ProcessInformationClass) - { - default: - status = STATUS_INVALID_INFO_CLASS; - break; - } - - ObDereferenceObject(process); - - return status; -} +/* + * KProcessHacker + * + * Copyright (C) 2010-2016 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include +#include + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGE, KpiOpenProcess) +#pragma alloc_text(PAGE, KpiOpenProcessToken) +#pragma alloc_text(PAGE, KpiOpenProcessJob) +#pragma alloc_text(PAGE, KpiTerminateProcess) +#pragma alloc_text(PAGE, KpiQueryInformationProcess) +#pragma alloc_text(PAGE, KpiSetInformationProcess) +#endif + +/** + * Opens a process. + * + * \param ProcessHandle A variable which receives the process handle. + * \param DesiredAccess The desired access to the process. + * \param ClientId The identifier of a process or thread. If \a UniqueThread is present, the process + * of the identified thread will be opened. If \a UniqueProcess is present, the identified process + * will be opened. + * \param Key An access key. + * \li If a L2 key is provided, no access checks are performed. + * \li If a L1 key is provided, only read access is permitted but no additional access checks are + * performed. + * \li If no valid key is provided, the function fails. + * \param Client The client that initiated the request. + * \param AccessMode The mode in which to perform access checks. + */ +NTSTATUS KpiOpenProcess( + __out PHANDLE ProcessHandle, + __in ACCESS_MASK DesiredAccess, + __in PCLIENT_ID ClientId, + __in_opt KPH_KEY Key, + __in PKPH_CLIENT Client, + __in KPROCESSOR_MODE AccessMode + ) +{ + NTSTATUS status; + CLIENT_ID clientId; + PEPROCESS process; + PETHREAD thread; + KPH_KEY_LEVEL requiredKeyLevel; + HANDLE processHandle; + + PAGED_CODE(); + + if (AccessMode != KernelMode) + { + __try + { + ProbeForWrite(ProcessHandle, sizeof(HANDLE), sizeof(HANDLE)); + ProbeForRead(ClientId, sizeof(CLIENT_ID), sizeof(ULONG)); + clientId = *ClientId; + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + return GetExceptionCode(); + } + } + else + { + clientId = *ClientId; + } + + // Use the thread ID if it was specified. + if (clientId.UniqueThread) + { + status = PsLookupProcessThreadByCid(&clientId, &process, &thread); + + if (NT_SUCCESS(status)) + { + // We don't actually need the thread. + ObDereferenceObject(thread); + } + } + else + { + status = PsLookupProcessByProcessId(clientId.UniqueProcess, &process); + } + + if (!NT_SUCCESS(status)) + return status; + + requiredKeyLevel = KphKeyLevel1; + + if ((DesiredAccess & KPH_PROCESS_READ_ACCESS) != DesiredAccess) + requiredKeyLevel = KphKeyLevel2; + + if (NT_SUCCESS(status = KphValidateKey(requiredKeyLevel, Key, Client, AccessMode))) + { + // Always open in KernelMode to skip ordinary access checks. + status = ObOpenObjectByPointer( + process, + 0, + NULL, + DesiredAccess, + *PsProcessType, + KernelMode, + &processHandle + ); + } + + ObDereferenceObject(process); + + if (NT_SUCCESS(status)) + { + if (AccessMode != KernelMode) + { + __try + { + *ProcessHandle = processHandle; + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + status = GetExceptionCode(); + } + } + else + { + *ProcessHandle = processHandle; + } + } + + return status; +} + +/** + * Opens the token of a process. + * + * \param ProcessHandle A handle to a process. + * \param DesiredAccess The desired access to the token. + * \param TokenHandle A variable which receives the token handle. + * \param Key An access key. + * \li If a L2 key is provided, no access checks are performed. + * \li If a L1 key is provided, only read access is permitted but no additional access checks are + * performed. + * \li If no valid key is provided, the function fails. + * \param Client The client that initiated the request. + * \param AccessMode The mode in which to perform access checks. + */ +NTSTATUS KpiOpenProcessToken( + __in HANDLE ProcessHandle, + __in ACCESS_MASK DesiredAccess, + __out PHANDLE TokenHandle, + __in_opt KPH_KEY Key, + __in PKPH_CLIENT Client, + __in KPROCESSOR_MODE AccessMode + ) +{ + NTSTATUS status; + PEPROCESS process; + PACCESS_TOKEN primaryToken; + KPH_KEY_LEVEL requiredKeyLevel; + HANDLE tokenHandle; + + PAGED_CODE(); + + if (AccessMode != KernelMode) + { + __try + { + ProbeForWrite(TokenHandle, sizeof(HANDLE), sizeof(HANDLE)); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + return GetExceptionCode(); + } + } + + status = ObReferenceObjectByHandle( + ProcessHandle, + 0, + *PsProcessType, + AccessMode, + &process, + NULL + ); + + if (!NT_SUCCESS(status)) + return status; + + if (primaryToken = PsReferencePrimaryToken(process)) + { + requiredKeyLevel = KphKeyLevel1; + + if ((DesiredAccess & KPH_TOKEN_READ_ACCESS) != DesiredAccess) + requiredKeyLevel = KphKeyLevel2; + + if (NT_SUCCESS(status = KphValidateKey(requiredKeyLevel, Key, Client, AccessMode))) + { + status = ObOpenObjectByPointer( + primaryToken, + 0, + NULL, + DesiredAccess, + *SeTokenObjectType, + KernelMode, + &tokenHandle + ); + } + + PsDereferencePrimaryToken(primaryToken); + } + else + { + status = STATUS_NO_TOKEN; + } + + ObDereferenceObject(process); + + if (NT_SUCCESS(status)) + { + if (AccessMode != KernelMode) + { + __try + { + *TokenHandle = tokenHandle; + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + status = GetExceptionCode(); + } + } + else + { + *TokenHandle = tokenHandle; + } + } + + return status; +} + +/** + * Opens the job object of a process. + * + * \param ProcessHandle A handle to a process. + * \param DesiredAccess The desired access to the job. + * \param JobHandle A variable which receives the job object handle. + * \param AccessMode The mode in which to perform access checks. + */ +NTSTATUS KpiOpenProcessJob( + __in HANDLE ProcessHandle, + __in ACCESS_MASK DesiredAccess, + __out PHANDLE JobHandle, + __in KPROCESSOR_MODE AccessMode + ) +{ + NTSTATUS status; + PEPROCESS process; + PEJOB job; + HANDLE jobHandle = NULL; + + PAGED_CODE(); + + if (AccessMode != KernelMode) + { + __try + { + ProbeForWrite(JobHandle, sizeof(HANDLE), sizeof(HANDLE)); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + return GetExceptionCode(); + } + } + + status = ObReferenceObjectByHandle( + ProcessHandle, + 0, + *PsProcessType, + AccessMode, + &process, + NULL + ); + + if (!NT_SUCCESS(status)) + return status; + + job = PsGetProcessJob(process); + + if (job) + { + status = ObOpenObjectByPointer( + job, + 0, + NULL, + DesiredAccess, + *PsJobType, + AccessMode, + &jobHandle + ); + } + else + { + status = STATUS_NOT_FOUND; + } + + ObDereferenceObject(process); + + if (NT_SUCCESS(status)) + { + if (AccessMode != KernelMode) + { + __try + { + *JobHandle = jobHandle; + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + status = GetExceptionCode(); + } + } + else + { + *JobHandle = jobHandle; + } + } + + return status; +} + +/** + * Terminates a process. + * + * \param ProcessHandle A handle to a process. + * \param ExitStatus A status value which indicates why the process is being terminated. + * \param Key An access key. + * \li If a L2 key is provided, no access checks are performed. + * \li If no valid L2 key is provided, the function fails. + * \param Client The client that initiated the request. + * \param AccessMode The mode in which to perform access checks. + */ +NTSTATUS KpiTerminateProcess( + __in HANDLE ProcessHandle, + __in NTSTATUS ExitStatus, + __in_opt KPH_KEY Key, + __in PKPH_CLIENT Client, + __in KPROCESSOR_MODE AccessMode + ) +{ + NTSTATUS status; + PEPROCESS process; + + PAGED_CODE(); + + if (!NT_SUCCESS(status = KphValidateKey(KphKeyLevel2, Key, Client, AccessMode))) + return status; + + status = ObReferenceObjectByHandle( + ProcessHandle, + 0, + *PsProcessType, + AccessMode, + &process, + NULL + ); + + if (!NT_SUCCESS(status)) + return status; + + if (process != PsGetCurrentProcess()) + { + HANDLE newProcessHandle; + + // Re-open the process to get a kernel handle. + if (NT_SUCCESS(status = ObOpenObjectByPointer( + process, + OBJ_KERNEL_HANDLE, + NULL, + PROCESS_TERMINATE, + *PsProcessType, + KernelMode, + &newProcessHandle + ))) + { + status = ZwTerminateProcess(newProcessHandle, ExitStatus); + ZwClose(newProcessHandle); + } + } + else + { + status = STATUS_CANT_TERMINATE_SELF; + } + + ObDereferenceObject(process); + + return status; +} + +/** + * Queries process information. + * + * \param ProcessHandle A handle to a process. + * \param ProcessInformationClass The type of information to query. + * \param ProcessInformation The buffer in which the information will be stored. + * \param ProcessInformationLength The number of bytes available in \a ProcessInformation. + * \param ReturnLength A variable which receives the number of bytes required to be available in + * \a ProcessInformation. + * \param AccessMode The mode in which to perform access checks. + */ +NTSTATUS KpiQueryInformationProcess( + __in HANDLE ProcessHandle, + __in KPH_PROCESS_INFORMATION_CLASS ProcessInformationClass, + __out_bcount(ProcessInformationLength) PVOID ProcessInformation, + __in ULONG ProcessInformationLength, + __out_opt PULONG ReturnLength, + __in KPROCESSOR_MODE AccessMode + ) +{ + NTSTATUS status; + PEPROCESS process; + ULONG returnLength; + + PAGED_CODE(); + + if (AccessMode != KernelMode) + { + ULONG alignment; + + switch (ProcessInformationClass) + { + default: + alignment = sizeof(ULONG); + break; + } + + __try + { + ProbeForWrite(ProcessInformation, ProcessInformationLength, alignment); + + if (ReturnLength) + ProbeForWrite(ReturnLength, sizeof(ULONG), sizeof(ULONG)); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + return GetExceptionCode(); + } + } + + status = ObReferenceObjectByHandle( + ProcessHandle, + PROCESS_QUERY_INFORMATION, + *PsProcessType, + AccessMode, + &process, + NULL + ); + + if (!NT_SUCCESS(status)) + return status; + + switch (ProcessInformationClass) + { + default: + status = STATUS_INVALID_INFO_CLASS; + returnLength = 0; + break; + } + + ObDereferenceObject(process); + + if (ReturnLength) + { + if (AccessMode != KernelMode) + { + __try + { + *ReturnLength = returnLength; + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + NOTHING; + } + } + else + { + *ReturnLength = returnLength; + } + } + + return status; +} + +/** + * Sets process information. + * + * \param ProcessHandle A handle to a process. + * \param ProcessInformationClass The type of information to set. + * \param ProcessInformation A buffer which contains the information to set. + * \param ProcessInformationLength The number of bytes present in \a ProcessInformation. + * \param AccessMode The mode in which to perform access checks. + */ +NTSTATUS KpiSetInformationProcess( + __in HANDLE ProcessHandle, + __in KPH_PROCESS_INFORMATION_CLASS ProcessInformationClass, + __in_bcount(ProcessInformationLength) PVOID ProcessInformation, + __in ULONG ProcessInformationLength, + __in KPROCESSOR_MODE AccessMode + ) +{ + NTSTATUS status; + PEPROCESS process; + + PAGED_CODE(); + + if (AccessMode != KernelMode) + { + ULONG alignment; + + switch (ProcessInformationClass) + { + default: + alignment = sizeof(ULONG); + break; + } + + __try + { + ProbeForRead(ProcessInformation, ProcessInformationLength, alignment); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + return GetExceptionCode(); + } + } + + status = ObReferenceObjectByHandle( + ProcessHandle, + PROCESS_SET_INFORMATION, + *PsProcessType, + AccessMode, + &process, + NULL + ); + + if (!NT_SUCCESS(status)) + return status; + + switch (ProcessInformationClass) + { + default: + status = STATUS_INVALID_INFO_CLASS; + break; + } + + ObDereferenceObject(process); + + return status; +} diff --git a/KProcessHacker/qrydrv.c b/KProcessHacker/qrydrv.c index 3ecfb6197f00..d2cb31b8ba18 100644 --- a/KProcessHacker/qrydrv.c +++ b/KProcessHacker/qrydrv.c @@ -1,238 +1,238 @@ -/* - * KProcessHacker - * - * Copyright (C) 2010-2016 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include - -VOID KphpCopyInfoUnicodeString( - __out PVOID Information, - __in_opt PUNICODE_STRING UnicodeString - ); - -#ifdef ALLOC_PRAGMA -#pragma alloc_text(PAGE, KpiOpenDriver) -#pragma alloc_text(PAGE, KpiQueryInformationDriver) -#pragma alloc_text(PAGE, KphpCopyInfoUnicodeString) -#endif - -NTSTATUS KpiOpenDriver( - __out PHANDLE DriverHandle, - __in ACCESS_MASK DesiredAccess, - __in POBJECT_ATTRIBUTES ObjectAttributes, - __in KPROCESSOR_MODE AccessMode - ) -{ - PAGED_CODE(); - - return KphOpenNamedObject( - DriverHandle, - DesiredAccess, - ObjectAttributes, - *IoDriverObjectType, - AccessMode - ); -} - -NTSTATUS KpiQueryInformationDriver( - __in HANDLE DriverHandle, - __in DRIVER_INFORMATION_CLASS DriverInformationClass, - __out_bcount(DriverInformationLength) PVOID DriverInformation, - __in ULONG DriverInformationLength, - __out_opt PULONG ReturnLength, - __in KPROCESSOR_MODE AccessMode - ) -{ - NTSTATUS status = STATUS_SUCCESS; - PDRIVER_OBJECT driverObject; - - PAGED_CODE(); - - if (AccessMode != KernelMode) - { - __try - { - ProbeForWrite(DriverInformation, DriverInformationLength, 1); - - if (ReturnLength) - ProbeForWrite(ReturnLength, sizeof(ULONG), 1); - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - return GetExceptionCode(); - } - } - - status = ObReferenceObjectByHandle( - DriverHandle, - 0, - *IoDriverObjectType, - AccessMode, - &driverObject, - NULL - ); - - if (!NT_SUCCESS(status)) - return status; - - __try - { - switch (DriverInformationClass) - { - // Basic information such as flags, driver base and driver size. - case DriverBasicInformation: - { - if (DriverInformationLength == sizeof(DRIVER_BASIC_INFORMATION)) - { - PDRIVER_BASIC_INFORMATION basicInfo; - - basicInfo = (PDRIVER_BASIC_INFORMATION)DriverInformation; - basicInfo->Flags = driverObject->Flags; - basicInfo->DriverStart = driverObject->DriverStart; - basicInfo->DriverSize = driverObject->DriverSize; - } - else - { - status = STATUS_INFO_LENGTH_MISMATCH; - } - - if (ReturnLength) - *ReturnLength = sizeof(DRIVER_BASIC_INFORMATION); - } - break; - - // The name of the driver - e.g. \Driver\Null. - case DriverNameInformation: - { - if (DriverInformation) - { - /* Check buffer length. */ - if (sizeof(UNICODE_STRING) + driverObject->DriverName.Length <= - DriverInformationLength) - { - KphpCopyInfoUnicodeString( - DriverInformation, - &driverObject->DriverName - ); - } - else - { - status = STATUS_BUFFER_TOO_SMALL; - } - } - - if (ReturnLength) - *ReturnLength = sizeof(UNICODE_STRING) + driverObject->DriverName.Length; - } - break; - - // The name of the driver's service key - e.g. \REGISTRY\... - case DriverServiceKeyNameInformation: - { - if (driverObject->DriverExtension) - { - if (DriverInformation) - { - if (sizeof(UNICODE_STRING) + - driverObject->DriverExtension->ServiceKeyName.Length <= - DriverInformationLength) - { - KphpCopyInfoUnicodeString( - DriverInformation, - &driverObject->DriverExtension->ServiceKeyName - ); - } - else - { - status = STATUS_BUFFER_TOO_SMALL; - } - } - - if (ReturnLength) - { - *ReturnLength = sizeof(UNICODE_STRING) + - driverObject->DriverExtension->ServiceKeyName.Length; - } - } - else - { - if (DriverInformation) - { - if (sizeof(UNICODE_STRING) <= DriverInformationLength) - { - // Zero the information buffer. - KphpCopyInfoUnicodeString( - DriverInformation, - NULL - ); - } - else - { - status = STATUS_BUFFER_TOO_SMALL; - } - } - - if (ReturnLength) - *ReturnLength = sizeof(UNICODE_STRING); - } - } - break; - - default: - { - status = STATUS_INVALID_INFO_CLASS; - } - } - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - status = GetExceptionCode(); - } - - ObDereferenceObject(driverObject); - - return status; -} - -VOID KphpCopyInfoUnicodeString( - __out PVOID Information, - __in_opt PUNICODE_STRING UnicodeString - ) -{ - PUNICODE_STRING targetUnicodeString = Information; - PWCHAR targetBuffer; - - PAGED_CODE(); - - if (UnicodeString) - { - targetBuffer = (PWCHAR)((PCHAR)Information + sizeof(UNICODE_STRING)); - - targetUnicodeString->Length = UnicodeString->Length; - targetUnicodeString->MaximumLength = UnicodeString->Length; - targetUnicodeString->Buffer = targetBuffer; - memcpy(targetBuffer, UnicodeString->Buffer, UnicodeString->Length); - } - else - { - targetUnicodeString->Length = 0; - targetUnicodeString->MaximumLength = 0; - targetUnicodeString->Buffer = NULL; - } -} +/* + * KProcessHacker + * + * Copyright (C) 2010-2016 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include + +VOID KphpCopyInfoUnicodeString( + __out PVOID Information, + __in_opt PUNICODE_STRING UnicodeString + ); + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGE, KpiOpenDriver) +#pragma alloc_text(PAGE, KpiQueryInformationDriver) +#pragma alloc_text(PAGE, KphpCopyInfoUnicodeString) +#endif + +NTSTATUS KpiOpenDriver( + __out PHANDLE DriverHandle, + __in ACCESS_MASK DesiredAccess, + __in POBJECT_ATTRIBUTES ObjectAttributes, + __in KPROCESSOR_MODE AccessMode + ) +{ + PAGED_CODE(); + + return KphOpenNamedObject( + DriverHandle, + DesiredAccess, + ObjectAttributes, + *IoDriverObjectType, + AccessMode + ); +} + +NTSTATUS KpiQueryInformationDriver( + __in HANDLE DriverHandle, + __in DRIVER_INFORMATION_CLASS DriverInformationClass, + __out_bcount(DriverInformationLength) PVOID DriverInformation, + __in ULONG DriverInformationLength, + __out_opt PULONG ReturnLength, + __in KPROCESSOR_MODE AccessMode + ) +{ + NTSTATUS status = STATUS_SUCCESS; + PDRIVER_OBJECT driverObject; + + PAGED_CODE(); + + if (AccessMode != KernelMode) + { + __try + { + ProbeForWrite(DriverInformation, DriverInformationLength, 1); + + if (ReturnLength) + ProbeForWrite(ReturnLength, sizeof(ULONG), 1); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + return GetExceptionCode(); + } + } + + status = ObReferenceObjectByHandle( + DriverHandle, + 0, + *IoDriverObjectType, + AccessMode, + &driverObject, + NULL + ); + + if (!NT_SUCCESS(status)) + return status; + + __try + { + switch (DriverInformationClass) + { + // Basic information such as flags, driver base and driver size. + case DriverBasicInformation: + { + if (DriverInformationLength == sizeof(DRIVER_BASIC_INFORMATION)) + { + PDRIVER_BASIC_INFORMATION basicInfo; + + basicInfo = (PDRIVER_BASIC_INFORMATION)DriverInformation; + basicInfo->Flags = driverObject->Flags; + basicInfo->DriverStart = driverObject->DriverStart; + basicInfo->DriverSize = driverObject->DriverSize; + } + else + { + status = STATUS_INFO_LENGTH_MISMATCH; + } + + if (ReturnLength) + *ReturnLength = sizeof(DRIVER_BASIC_INFORMATION); + } + break; + + // The name of the driver - e.g. \Driver\Null. + case DriverNameInformation: + { + if (DriverInformation) + { + /* Check buffer length. */ + if (sizeof(UNICODE_STRING) + driverObject->DriverName.Length <= + DriverInformationLength) + { + KphpCopyInfoUnicodeString( + DriverInformation, + &driverObject->DriverName + ); + } + else + { + status = STATUS_BUFFER_TOO_SMALL; + } + } + + if (ReturnLength) + *ReturnLength = sizeof(UNICODE_STRING) + driverObject->DriverName.Length; + } + break; + + // The name of the driver's service key - e.g. \REGISTRY\... + case DriverServiceKeyNameInformation: + { + if (driverObject->DriverExtension) + { + if (DriverInformation) + { + if (sizeof(UNICODE_STRING) + + driverObject->DriverExtension->ServiceKeyName.Length <= + DriverInformationLength) + { + KphpCopyInfoUnicodeString( + DriverInformation, + &driverObject->DriverExtension->ServiceKeyName + ); + } + else + { + status = STATUS_BUFFER_TOO_SMALL; + } + } + + if (ReturnLength) + { + *ReturnLength = sizeof(UNICODE_STRING) + + driverObject->DriverExtension->ServiceKeyName.Length; + } + } + else + { + if (DriverInformation) + { + if (sizeof(UNICODE_STRING) <= DriverInformationLength) + { + // Zero the information buffer. + KphpCopyInfoUnicodeString( + DriverInformation, + NULL + ); + } + else + { + status = STATUS_BUFFER_TOO_SMALL; + } + } + + if (ReturnLength) + *ReturnLength = sizeof(UNICODE_STRING); + } + } + break; + + default: + { + status = STATUS_INVALID_INFO_CLASS; + } + } + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + status = GetExceptionCode(); + } + + ObDereferenceObject(driverObject); + + return status; +} + +VOID KphpCopyInfoUnicodeString( + __out PVOID Information, + __in_opt PUNICODE_STRING UnicodeString + ) +{ + PUNICODE_STRING targetUnicodeString = Information; + PWCHAR targetBuffer; + + PAGED_CODE(); + + if (UnicodeString) + { + targetBuffer = (PWCHAR)((PCHAR)Information + sizeof(UNICODE_STRING)); + + targetUnicodeString->Length = UnicodeString->Length; + targetUnicodeString->MaximumLength = UnicodeString->Length; + targetUnicodeString->Buffer = targetBuffer; + memcpy(targetBuffer, UnicodeString->Buffer, UnicodeString->Length); + } + else + { + targetUnicodeString->Length = 0; + targetUnicodeString->MaximumLength = 0; + targetUnicodeString->Buffer = NULL; + } +} diff --git a/KProcessHacker/resource.rc b/KProcessHacker/resource.rc index ca42f86d3631..ce831638b987 100644 --- a/KProcessHacker/resource.rc +++ b/KProcessHacker/resource.rc @@ -1,53 +1,53 @@ -#include - -#define VER_COMMA 3,1,0,0 -#define VER_STR "3.1\0" - -#define VER_FILEVERSION VER_COMMA -#define VER_FILEVERSION_STR VER_STR -#define VER_PRODUCTVERSION VER_COMMA -#define VER_PRODUCTVERSION_STR VER_STR - -#ifndef DEBUG -#define VER_DEBUG 0 -#else -#define VER_DEBUG VS_FF_DEBUG -#endif - -#define VER_PRIVATEBUILD 0 -#define VER_PRERELEASE 0 - -#define VER_COMPANYNAME_STR "wj32\0" -#define VER_FILEDESCRIPTION_STR "KProcessHacker\0" -#define VER_LEGALCOPYRIGHT_STR "Licensed under the GNU GPL, v3.\0" -#define VER_ORIGINALFILENAME_STR "kprocesshacker.sys\0" -#define VER_PRODUCTNAME_STR "KProcessHacker\0" - -VS_VERSION_INFO VERSIONINFO -FILEVERSION VER_FILEVERSION -PRODUCTVERSION VER_PRODUCTVERSION -FILEFLAGSMASK VS_FFI_FILEFLAGSMASK -FILEFLAGS (VER_PRIVATEBUILD | VER_PRERELEASE | VER_DEBUG) -FILEOS VOS__WINDOWS32 -FILETYPE VFT_DRV -FILESUBTYPE VFT2_DRV_SYSTEM -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "040904E4" - BEGIN - VALUE "CompanyName", VER_COMPANYNAME_STR - VALUE "FileDescription", VER_FILEDESCRIPTION_STR - VALUE "FileVersion", VER_FILEVERSION_STR - VALUE "LegalCopyright", VER_LEGALCOPYRIGHT_STR - VALUE "OriginalFilename", VER_ORIGINALFILENAME_STR - VALUE "ProductName", VER_PRODUCTNAME_STR - VALUE "ProductVersion", VER_PRODUCTVERSION_STR - END - END - - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x409, 1252 - END -END +#include + +#define VER_COMMA 3,1,0,0 +#define VER_STR "3.1\0" + +#define VER_FILEVERSION VER_COMMA +#define VER_FILEVERSION_STR VER_STR +#define VER_PRODUCTVERSION VER_COMMA +#define VER_PRODUCTVERSION_STR VER_STR + +#ifndef DEBUG +#define VER_DEBUG 0 +#else +#define VER_DEBUG VS_FF_DEBUG +#endif + +#define VER_PRIVATEBUILD 0 +#define VER_PRERELEASE 0 + +#define VER_COMPANYNAME_STR "wj32\0" +#define VER_FILEDESCRIPTION_STR "KProcessHacker\0" +#define VER_LEGALCOPYRIGHT_STR "Licensed under the GNU GPL, v3.\0" +#define VER_ORIGINALFILENAME_STR "kprocesshacker.sys\0" +#define VER_PRODUCTNAME_STR "KProcessHacker\0" + +VS_VERSION_INFO VERSIONINFO +FILEVERSION VER_FILEVERSION +PRODUCTVERSION VER_PRODUCTVERSION +FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +FILEFLAGS (VER_PRIVATEBUILD | VER_PRERELEASE | VER_DEBUG) +FILEOS VOS__WINDOWS32 +FILETYPE VFT_DRV +FILESUBTYPE VFT2_DRV_SYSTEM +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904E4" + BEGIN + VALUE "CompanyName", VER_COMPANYNAME_STR + VALUE "FileDescription", VER_FILEDESCRIPTION_STR + VALUE "FileVersion", VER_FILEVERSION_STR + VALUE "LegalCopyright", VER_LEGALCOPYRIGHT_STR + VALUE "OriginalFilename", VER_ORIGINALFILENAME_STR + VALUE "ProductName", VER_PRODUCTNAME_STR + VALUE "ProductVersion", VER_PRODUCTVERSION_STR + END + END + + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1252 + END +END diff --git a/KProcessHacker/sign.cmd b/KProcessHacker/sign.cmd index fe9c32599e2a..90e2927feed0 100644 --- a/KProcessHacker/sign.cmd +++ b/KProcessHacker/sign.cmd @@ -1,7 +1,7 @@ -@echo off -set PHBASE=.. -set SIGN_TIMESTAMP=1 -copy bin\i386\kprocesshacker.sys bin-signed\i386\kprocesshacker.sys -copy bin\amd64\kprocesshacker.sys bin-signed\amd64\kprocesshacker.sys -call ..\build\internal\sign.cmd bin-signed\i386\kprocesshacker.sys kmcs -call ..\build\internal\sign.cmd bin-signed\amd64\kprocesshacker.sys kmcs +@echo off +set PHBASE=.. +set SIGN_TIMESTAMP=1 +copy bin\i386\kprocesshacker.sys bin-signed\i386\kprocesshacker.sys +copy bin\amd64\kprocesshacker.sys bin-signed\amd64\kprocesshacker.sys +call ..\build\internal\sign.cmd bin-signed\i386\kprocesshacker.sys kmcs +call ..\build\internal\sign.cmd bin-signed\amd64\kprocesshacker.sys kmcs diff --git a/KProcessHacker/thread.c b/KProcessHacker/thread.c index 1ac2b750aab7..da8154c0c5d0 100644 --- a/KProcessHacker/thread.c +++ b/KProcessHacker/thread.c @@ -1,714 +1,714 @@ -/* - * KProcessHacker - * - * Copyright (C) 2010-2016 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include -#include - -typedef struct _CAPTURE_BACKTRACE_THREAD_CONTEXT -{ - BOOLEAN Local; - KAPC Apc; - KEVENT CompletedEvent; - ULONG FramesToSkip; - ULONG FramesToCapture; - PVOID *BackTrace; - ULONG CapturedFrames; - ULONG BackTraceHash; -} CAPTURE_BACKTRACE_THREAD_CONTEXT, *PCAPTURE_BACKTRACE_THREAD_CONTEXT; - -KKERNEL_ROUTINE KphpCaptureStackBackTraceThreadSpecialApc; - -VOID KphpCaptureStackBackTraceThreadSpecialApc( - __in PRKAPC Apc, - __inout PKNORMAL_ROUTINE *NormalRoutine, - __inout PVOID *NormalContext, - __inout PVOID *SystemArgument1, - __inout PVOID *SystemArgument2 - ); - -#ifdef ALLOC_PRAGMA -#pragma alloc_text(PAGE, KpiOpenThread) -#pragma alloc_text(PAGE, KpiOpenThreadProcess) -#pragma alloc_text(PAGE, KphCaptureStackBackTraceThread) -#pragma alloc_text(PAGE, KphpCaptureStackBackTraceThreadSpecialApc) -#pragma alloc_text(PAGE, KpiCaptureStackBackTraceThread) -#pragma alloc_text(PAGE, KpiQueryInformationThread) -#pragma alloc_text(PAGE, KpiSetInformationThread) -#endif - -/** - * Opens a thread. - * - * \param ThreadHandle A variable which receives the thread handle. - * \param DesiredAccess The desired access to the thread. - * \param ClientId The identifier of a thread. \a UniqueThread must be present. If \a UniqueProcess - * is present, the process of the referenced thread will be checked against this identifier. - * \param Key An access key. - * \li If a L2 key is provided, no access checks are performed. - * \li If a L1 key is provided, only read access is permitted but no additional access checks are - * performed. - * \li If no valid key is provided, the function fails. - * \param Client The client that initiated the request. - * \param AccessMode The mode in which to perform access checks. - */ -NTSTATUS KpiOpenThread( - __out PHANDLE ThreadHandle, - __in ACCESS_MASK DesiredAccess, - __in PCLIENT_ID ClientId, - __in_opt KPH_KEY Key, - __in PKPH_CLIENT Client, - __in KPROCESSOR_MODE AccessMode - ) -{ - NTSTATUS status; - CLIENT_ID clientId; - PETHREAD thread; - KPH_KEY_LEVEL requiredKeyLevel; - HANDLE threadHandle; - - PAGED_CODE(); - - if (AccessMode != KernelMode) - { - __try - { - ProbeForWrite(ThreadHandle, sizeof(HANDLE), sizeof(HANDLE)); - ProbeForRead(ClientId, sizeof(CLIENT_ID), sizeof(ULONG)); - clientId = *ClientId; - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - return GetExceptionCode(); - } - } - else - { - clientId = *ClientId; - } - - // Use the process ID if it was specified. - if (clientId.UniqueProcess) - { - status = PsLookupProcessThreadByCid(&clientId, NULL, &thread); - } - else - { - status = PsLookupThreadByThreadId(clientId.UniqueThread, &thread); - } - - if (!NT_SUCCESS(status)) - return status; - - - requiredKeyLevel = KphKeyLevel1; - - if ((DesiredAccess & KPH_THREAD_READ_ACCESS) != DesiredAccess) - requiredKeyLevel = KphKeyLevel2; - - if (NT_SUCCESS(status = KphValidateKey(requiredKeyLevel, Key, Client, AccessMode))) - { - // Always open in KernelMode to skip access checks. - status = ObOpenObjectByPointer( - thread, - 0, - NULL, - DesiredAccess, - *PsThreadType, - KernelMode, - &threadHandle - ); - } - - ObDereferenceObject(thread); - - if (NT_SUCCESS(status)) - { - if (AccessMode != KernelMode) - { - __try - { - *ThreadHandle = threadHandle; - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - status = GetExceptionCode(); - } - } - else - { - *ThreadHandle = threadHandle; - } - } - - return status; -} - -/** - * Opens the process of a thread. - * - * \param ThreadHandle A handle to a thread. - * \param DesiredAccess The desired access to the process. - * \param ProcessHandle A variable which receives the process handle. - * \param AccessMode The mode in which to perform access checks. - */ -NTSTATUS KpiOpenThreadProcess( - __in HANDLE ThreadHandle, - __in ACCESS_MASK DesiredAccess, - __out PHANDLE ProcessHandle, - __in KPROCESSOR_MODE AccessMode - ) -{ - NTSTATUS status; - PETHREAD thread; - PEPROCESS process; - HANDLE processHandle; - - PAGED_CODE(); - - if (AccessMode != KernelMode) - { - __try - { - ProbeForWrite(ProcessHandle, sizeof(HANDLE), sizeof(HANDLE)); - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - return GetExceptionCode(); - } - } - - status = ObReferenceObjectByHandle( - ThreadHandle, - 0, - *PsThreadType, - AccessMode, - &thread, - NULL - ); - - if (!NT_SUCCESS(status)) - return status; - - process = IoThreadToProcess(thread); - - status = ObOpenObjectByPointer( - process, - 0, - NULL, - DesiredAccess, - *PsProcessType, - AccessMode, - &processHandle - ); - - ObDereferenceObject(thread); - - if (NT_SUCCESS(status)) - { - if (AccessMode != KernelMode) - { - __try - { - *ProcessHandle = processHandle; - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - status = GetExceptionCode(); - } - } - else - { - *ProcessHandle = processHandle; - } - } - - return status; -} - -/** - * Captures a stack trace of the current thread. - * - * \param FramesToSkip The number of frames to skip from the bottom of the stack. - * \param FramesToCapture The number of frames to capture. - * \param Flags A combination of the following: - * \li \c RTL_WALK_USER_MODE_STACK The user-mode stack will be retrieved instead of the kernel-mode - * stack. - * \param BackTrace An array in which the stack trace will be stored. - * \param BackTraceHash A variable which receives a hash of the stack trace. - * - * \return The number of frames captured. - */ -ULONG KphCaptureStackBackTrace( - __in ULONG FramesToSkip, - __in ULONG FramesToCapture, - __in_opt ULONG Flags, - __out_ecount(FramesToCapture) PVOID *BackTrace, - __out_opt PULONG BackTraceHash - ) -{ - PVOID backTrace[MAX_STACK_DEPTH]; - ULONG framesFound; - ULONG hash; - ULONG i; - - // Skip the current frame (for this function). - FramesToSkip++; - - // Ensure that we won't overrun the buffer. - if (FramesToCapture + FramesToSkip > MAX_STACK_DEPTH) - return 0; - // Validate the flags. - if ((Flags & RTL_WALK_VALID_FLAGS) != Flags) - return 0; - - // Walk the stack. - framesFound = RtlWalkFrameChain( - backTrace, - FramesToCapture + FramesToSkip, - Flags - ); - // Return nothing if we found fewer frames than we wanted to skip. - if (framesFound <= FramesToSkip) - return 0; - - // Copy over the stack trace. At the same time we calculate the stack trace hash by summing the - // addresses. - for (i = 0, hash = 0; i < FramesToCapture; i++) - { - if (FramesToSkip + i >= framesFound) - break; - - BackTrace[i] = backTrace[FramesToSkip + i]; - hash += PtrToUlong(BackTrace[i]); - } - - if (BackTraceHash) - *BackTraceHash = hash; - - return i; -} - -/** - * Captures the stack trace of a thread. - * - * \param Thread The thread to capture the stack trace of. - * \param FramesToSkip The number of frames to skip from the bottom of the stack. - * \param FramesToCapture The number of frames to capture. - * \param BackTrace An array in which the stack trace will be stored. - * \param CapturedFrames A variable which receives the number of frames captured. - * \param BackTraceHash A variable which receives a hash of the stack trace. - * \param AccessMode The mode in which to perform access checks. - * - * \return The number of frames captured. - */ -NTSTATUS KphCaptureStackBackTraceThread( - __in PETHREAD Thread, - __in ULONG FramesToSkip, - __in ULONG FramesToCapture, - __out_ecount(FramesToCapture) PVOID *BackTrace, - __out_opt PULONG CapturedFrames, - __out_opt PULONG BackTraceHash, - __in KPROCESSOR_MODE AccessMode - ) -{ - NTSTATUS status = STATUS_SUCCESS; - CAPTURE_BACKTRACE_THREAD_CONTEXT context; - ULONG backTraceSize; - PVOID *backTrace; - - PAGED_CODE(); - - // Make sure the caller didn't request too many frames. This also restricts the amount of memory - // we will try to allocate later. - if (FramesToCapture > MAX_STACK_DEPTH) - return STATUS_INVALID_PARAMETER_3; - - backTraceSize = FramesToCapture * sizeof(PVOID); - - if (AccessMode != KernelMode) - { - __try - { - ProbeForWrite(BackTrace, backTraceSize, sizeof(PVOID)); - - if (CapturedFrames) - ProbeForWrite(CapturedFrames, sizeof(ULONG), sizeof(ULONG)); - if (BackTraceHash) - ProbeForWrite(BackTraceHash, sizeof(ULONG), sizeof(ULONG)); - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - return GetExceptionCode(); - } - } - - // If the caller doesn't want to capture anything, return immediately. - if (backTraceSize == 0) - { - if (AccessMode != KernelMode) - { - __try - { - if (CapturedFrames) - *CapturedFrames = 0; - if (BackTraceHash) - *BackTraceHash = 0; - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - status = GetExceptionCode(); - } - } - else - { - if (CapturedFrames) - *CapturedFrames = 0; - if (BackTraceHash) - *BackTraceHash = 0; - } - - return status; - } - - // Allocate storage for the stack trace. - backTrace = ExAllocatePoolWithTag(NonPagedPool, backTraceSize, 'bhpK'); - - if (!backTrace) - return STATUS_INSUFFICIENT_RESOURCES; - - // Initialize the context structure. - context.FramesToSkip = FramesToSkip; - context.FramesToCapture = FramesToCapture; - context.BackTrace = backTrace; - - // Check if we're trying to get a stack trace of the current thread. - // If so, we don't need to insert an APC. - if (Thread == PsGetCurrentThread()) - { - PCAPTURE_BACKTRACE_THREAD_CONTEXT contextPtr = &context; - PVOID dummy = NULL; - KIRQL oldIrql; - - // Raise the IRQL to APC_LEVEL to simulate an APC environment, - // and call the APC routine directly. - - context.Local = TRUE; - KeRaiseIrql(APC_LEVEL, &oldIrql); - KphpCaptureStackBackTraceThreadSpecialApc( - &context.Apc, - NULL, - NULL, - &contextPtr, - &dummy - ); - KeLowerIrql(oldIrql); - } - else - { - context.Local = FALSE; - KeInitializeEvent(&context.CompletedEvent, NotificationEvent, FALSE); - KeInitializeApc( - &context.Apc, - (PKTHREAD)Thread, - OriginalApcEnvironment, - KphpCaptureStackBackTraceThreadSpecialApc, - NULL, - NULL, - KernelMode, - NULL - ); - - if (KeInsertQueueApc(&context.Apc, &context, NULL, 2)) - { - // Wait for the APC to complete. - status = KeWaitForSingleObject( - &context.CompletedEvent, - Executive, - KernelMode, - FALSE, - NULL - ); - } - else - { - status = STATUS_UNSUCCESSFUL; - } - } - - if (NT_SUCCESS(status)) - { - ASSERT(context.CapturedFrames <= FramesToCapture); - - if (AccessMode != KernelMode) - { - __try - { - memcpy(BackTrace, backTrace, context.CapturedFrames * sizeof(PVOID)); - - if (CapturedFrames) - *CapturedFrames = context.CapturedFrames; - if (BackTraceHash) - *BackTraceHash = context.BackTraceHash; - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - status = GetExceptionCode(); - } - } - else - { - memcpy(BackTrace, backTrace, context.CapturedFrames * sizeof(PVOID)); - - if (CapturedFrames) - *CapturedFrames = context.CapturedFrames; - if (BackTraceHash) - *BackTraceHash = context.BackTraceHash; - } - } - - ExFreePoolWithTag(backTrace, 'bhpK'); - - return status; -} - -VOID KphpCaptureStackBackTraceThreadSpecialApc( - __in PRKAPC Apc, - __inout PKNORMAL_ROUTINE *NormalRoutine, - __inout PVOID *NormalContext, - __inout PVOID *SystemArgument1, - __inout PVOID *SystemArgument2 - ) -{ - PCAPTURE_BACKTRACE_THREAD_CONTEXT context = *SystemArgument1; - - PAGED_CODE(); - - context->CapturedFrames = KphCaptureStackBackTrace( - context->FramesToSkip, - context->FramesToCapture, - 0, - context->BackTrace, - &context->BackTraceHash - ); - - if (!context->Local) - { - // Notify the originating thread that we have completed. - KeSetEvent(&context->CompletedEvent, 0, FALSE); - } -} - -/** - * Captures the stack trace of a thread. - * - * \param ThreadHandle A handle to the thread to capture the stack trace of. - * \param FramesToSkip The number of frames to skip from the bottom of the stack. - * \param FramesToCapture The number of frames to capture. - * \param BackTrace An array in which the stack trace will be stored. - * \param CapturedFrames A variable which receives the number of frames captured. - * \param BackTraceHash A variable which receives a hash of the stack trace. - * \param AccessMode The mode in which to perform access checks. - * - * \return The number of frames captured. - */ -NTSTATUS KpiCaptureStackBackTraceThread( - __in HANDLE ThreadHandle, - __in ULONG FramesToSkip, - __in ULONG FramesToCapture, - __out_ecount(FramesToCapture) PVOID *BackTrace, - __out_opt PULONG CapturedFrames, - __out_opt PULONG BackTraceHash, - __in KPROCESSOR_MODE AccessMode - ) -{ - NTSTATUS status = STATUS_SUCCESS; - PETHREAD thread; - - PAGED_CODE(); - - status = ObReferenceObjectByHandle( - ThreadHandle, - 0, - *PsThreadType, - AccessMode, - &thread, - NULL - ); - - if (!NT_SUCCESS(status)) - return status; - - status = KphCaptureStackBackTraceThread( - thread, - FramesToSkip, - FramesToCapture, - BackTrace, - CapturedFrames, - BackTraceHash, - AccessMode - ); - ObDereferenceObject(thread); - - return status; -} - -/** - * Queries thread information. - * - * \param ThreadHandle A handle to a thread. - * \param ThreadInformationClass The type of information to query. - * \param ThreadInformation The buffer in which the information will be stored. - * \param ThreadInformationLength The number of bytes available in \a ThreadInformation. - * \param ReturnLength A variable which receives the number of bytes required to be available in - * \a ThreadInformation. - * \param AccessMode The mode in which to perform access checks. - */ -NTSTATUS KpiQueryInformationThread( - __in HANDLE ThreadHandle, - __in KPH_THREAD_INFORMATION_CLASS ThreadInformationClass, - __out_bcount(ProcessInformationLength) PVOID ThreadInformation, - __in ULONG ThreadInformationLength, - __out_opt PULONG ReturnLength, - __in KPROCESSOR_MODE AccessMode - ) -{ - NTSTATUS status; - PETHREAD thread; - ULONG returnLength; - - PAGED_CODE(); - - if (AccessMode != KernelMode) - { - __try - { - ProbeForWrite(ThreadInformation, ThreadInformationLength, sizeof(ULONG)); - - if (ReturnLength) - ProbeForWrite(ReturnLength, sizeof(ULONG), sizeof(ULONG)); - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - return GetExceptionCode(); - } - } - - status = ObReferenceObjectByHandle( - ThreadHandle, - THREAD_QUERY_INFORMATION, - *PsThreadType, - AccessMode, - &thread, - NULL - ); - - if (!NT_SUCCESS(status)) - return status; - - switch (ThreadInformationClass) - { - default: - status = STATUS_INVALID_INFO_CLASS; - returnLength = 0; - break; - } - - ObDereferenceObject(thread); - - if (ReturnLength) - { - if (AccessMode != KernelMode) - { - __try - { - *ReturnLength = returnLength; - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - NOTHING; - } - } - else - { - *ReturnLength = returnLength; - } - } - - return status; -} - -/** - * Sets thread information. - * - * \param ThreadHandle A handle to a thread. - * \param ThreadInformationClass The type of information to set. - * \param ThreadInformation A buffer which contains the information to set. - * \param ThreadInformationLength The number of bytes present in \a ThreadInformation. - * \param AccessMode The mode in which to perform access checks. - */ -NTSTATUS KpiSetInformationThread( - __in HANDLE ThreadHandle, - __in KPH_THREAD_INFORMATION_CLASS ThreadInformationClass, - __in_bcount(ThreadInformationLength) PVOID ThreadInformation, - __in ULONG ThreadInformationLength, - __in KPROCESSOR_MODE AccessMode - ) -{ - NTSTATUS status; - PETHREAD thread; - - PAGED_CODE(); - - if (AccessMode != KernelMode) - { - __try - { - ProbeForRead(ThreadInformation, ThreadInformationLength, sizeof(ULONG)); - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - return GetExceptionCode(); - } - } - - status = ObReferenceObjectByHandle( - ThreadHandle, - THREAD_SET_INFORMATION, - *PsThreadType, - AccessMode, - &thread, - NULL - ); - - if (!NT_SUCCESS(status)) - return status; - - switch (ThreadInformationClass) - { - default: - status = STATUS_INVALID_INFO_CLASS; - break; - } - - ObDereferenceObject(thread); - - return status; -} +/* + * KProcessHacker + * + * Copyright (C) 2010-2016 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include +#include + +typedef struct _CAPTURE_BACKTRACE_THREAD_CONTEXT +{ + BOOLEAN Local; + KAPC Apc; + KEVENT CompletedEvent; + ULONG FramesToSkip; + ULONG FramesToCapture; + PVOID *BackTrace; + ULONG CapturedFrames; + ULONG BackTraceHash; +} CAPTURE_BACKTRACE_THREAD_CONTEXT, *PCAPTURE_BACKTRACE_THREAD_CONTEXT; + +KKERNEL_ROUTINE KphpCaptureStackBackTraceThreadSpecialApc; + +VOID KphpCaptureStackBackTraceThreadSpecialApc( + __in PRKAPC Apc, + __inout PKNORMAL_ROUTINE *NormalRoutine, + __inout PVOID *NormalContext, + __inout PVOID *SystemArgument1, + __inout PVOID *SystemArgument2 + ); + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGE, KpiOpenThread) +#pragma alloc_text(PAGE, KpiOpenThreadProcess) +#pragma alloc_text(PAGE, KphCaptureStackBackTraceThread) +#pragma alloc_text(PAGE, KphpCaptureStackBackTraceThreadSpecialApc) +#pragma alloc_text(PAGE, KpiCaptureStackBackTraceThread) +#pragma alloc_text(PAGE, KpiQueryInformationThread) +#pragma alloc_text(PAGE, KpiSetInformationThread) +#endif + +/** + * Opens a thread. + * + * \param ThreadHandle A variable which receives the thread handle. + * \param DesiredAccess The desired access to the thread. + * \param ClientId The identifier of a thread. \a UniqueThread must be present. If \a UniqueProcess + * is present, the process of the referenced thread will be checked against this identifier. + * \param Key An access key. + * \li If a L2 key is provided, no access checks are performed. + * \li If a L1 key is provided, only read access is permitted but no additional access checks are + * performed. + * \li If no valid key is provided, the function fails. + * \param Client The client that initiated the request. + * \param AccessMode The mode in which to perform access checks. + */ +NTSTATUS KpiOpenThread( + __out PHANDLE ThreadHandle, + __in ACCESS_MASK DesiredAccess, + __in PCLIENT_ID ClientId, + __in_opt KPH_KEY Key, + __in PKPH_CLIENT Client, + __in KPROCESSOR_MODE AccessMode + ) +{ + NTSTATUS status; + CLIENT_ID clientId; + PETHREAD thread; + KPH_KEY_LEVEL requiredKeyLevel; + HANDLE threadHandle; + + PAGED_CODE(); + + if (AccessMode != KernelMode) + { + __try + { + ProbeForWrite(ThreadHandle, sizeof(HANDLE), sizeof(HANDLE)); + ProbeForRead(ClientId, sizeof(CLIENT_ID), sizeof(ULONG)); + clientId = *ClientId; + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + return GetExceptionCode(); + } + } + else + { + clientId = *ClientId; + } + + // Use the process ID if it was specified. + if (clientId.UniqueProcess) + { + status = PsLookupProcessThreadByCid(&clientId, NULL, &thread); + } + else + { + status = PsLookupThreadByThreadId(clientId.UniqueThread, &thread); + } + + if (!NT_SUCCESS(status)) + return status; + + + requiredKeyLevel = KphKeyLevel1; + + if ((DesiredAccess & KPH_THREAD_READ_ACCESS) != DesiredAccess) + requiredKeyLevel = KphKeyLevel2; + + if (NT_SUCCESS(status = KphValidateKey(requiredKeyLevel, Key, Client, AccessMode))) + { + // Always open in KernelMode to skip access checks. + status = ObOpenObjectByPointer( + thread, + 0, + NULL, + DesiredAccess, + *PsThreadType, + KernelMode, + &threadHandle + ); + } + + ObDereferenceObject(thread); + + if (NT_SUCCESS(status)) + { + if (AccessMode != KernelMode) + { + __try + { + *ThreadHandle = threadHandle; + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + status = GetExceptionCode(); + } + } + else + { + *ThreadHandle = threadHandle; + } + } + + return status; +} + +/** + * Opens the process of a thread. + * + * \param ThreadHandle A handle to a thread. + * \param DesiredAccess The desired access to the process. + * \param ProcessHandle A variable which receives the process handle. + * \param AccessMode The mode in which to perform access checks. + */ +NTSTATUS KpiOpenThreadProcess( + __in HANDLE ThreadHandle, + __in ACCESS_MASK DesiredAccess, + __out PHANDLE ProcessHandle, + __in KPROCESSOR_MODE AccessMode + ) +{ + NTSTATUS status; + PETHREAD thread; + PEPROCESS process; + HANDLE processHandle; + + PAGED_CODE(); + + if (AccessMode != KernelMode) + { + __try + { + ProbeForWrite(ProcessHandle, sizeof(HANDLE), sizeof(HANDLE)); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + return GetExceptionCode(); + } + } + + status = ObReferenceObjectByHandle( + ThreadHandle, + 0, + *PsThreadType, + AccessMode, + &thread, + NULL + ); + + if (!NT_SUCCESS(status)) + return status; + + process = IoThreadToProcess(thread); + + status = ObOpenObjectByPointer( + process, + 0, + NULL, + DesiredAccess, + *PsProcessType, + AccessMode, + &processHandle + ); + + ObDereferenceObject(thread); + + if (NT_SUCCESS(status)) + { + if (AccessMode != KernelMode) + { + __try + { + *ProcessHandle = processHandle; + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + status = GetExceptionCode(); + } + } + else + { + *ProcessHandle = processHandle; + } + } + + return status; +} + +/** + * Captures a stack trace of the current thread. + * + * \param FramesToSkip The number of frames to skip from the bottom of the stack. + * \param FramesToCapture The number of frames to capture. + * \param Flags A combination of the following: + * \li \c RTL_WALK_USER_MODE_STACK The user-mode stack will be retrieved instead of the kernel-mode + * stack. + * \param BackTrace An array in which the stack trace will be stored. + * \param BackTraceHash A variable which receives a hash of the stack trace. + * + * \return The number of frames captured. + */ +ULONG KphCaptureStackBackTrace( + __in ULONG FramesToSkip, + __in ULONG FramesToCapture, + __in_opt ULONG Flags, + __out_ecount(FramesToCapture) PVOID *BackTrace, + __out_opt PULONG BackTraceHash + ) +{ + PVOID backTrace[MAX_STACK_DEPTH]; + ULONG framesFound; + ULONG hash; + ULONG i; + + // Skip the current frame (for this function). + FramesToSkip++; + + // Ensure that we won't overrun the buffer. + if (FramesToCapture + FramesToSkip > MAX_STACK_DEPTH) + return 0; + // Validate the flags. + if ((Flags & RTL_WALK_VALID_FLAGS) != Flags) + return 0; + + // Walk the stack. + framesFound = RtlWalkFrameChain( + backTrace, + FramesToCapture + FramesToSkip, + Flags + ); + // Return nothing if we found fewer frames than we wanted to skip. + if (framesFound <= FramesToSkip) + return 0; + + // Copy over the stack trace. At the same time we calculate the stack trace hash by summing the + // addresses. + for (i = 0, hash = 0; i < FramesToCapture; i++) + { + if (FramesToSkip + i >= framesFound) + break; + + BackTrace[i] = backTrace[FramesToSkip + i]; + hash += PtrToUlong(BackTrace[i]); + } + + if (BackTraceHash) + *BackTraceHash = hash; + + return i; +} + +/** + * Captures the stack trace of a thread. + * + * \param Thread The thread to capture the stack trace of. + * \param FramesToSkip The number of frames to skip from the bottom of the stack. + * \param FramesToCapture The number of frames to capture. + * \param BackTrace An array in which the stack trace will be stored. + * \param CapturedFrames A variable which receives the number of frames captured. + * \param BackTraceHash A variable which receives a hash of the stack trace. + * \param AccessMode The mode in which to perform access checks. + * + * \return The number of frames captured. + */ +NTSTATUS KphCaptureStackBackTraceThread( + __in PETHREAD Thread, + __in ULONG FramesToSkip, + __in ULONG FramesToCapture, + __out_ecount(FramesToCapture) PVOID *BackTrace, + __out_opt PULONG CapturedFrames, + __out_opt PULONG BackTraceHash, + __in KPROCESSOR_MODE AccessMode + ) +{ + NTSTATUS status = STATUS_SUCCESS; + CAPTURE_BACKTRACE_THREAD_CONTEXT context; + ULONG backTraceSize; + PVOID *backTrace; + + PAGED_CODE(); + + // Make sure the caller didn't request too many frames. This also restricts the amount of memory + // we will try to allocate later. + if (FramesToCapture > MAX_STACK_DEPTH) + return STATUS_INVALID_PARAMETER_3; + + backTraceSize = FramesToCapture * sizeof(PVOID); + + if (AccessMode != KernelMode) + { + __try + { + ProbeForWrite(BackTrace, backTraceSize, sizeof(PVOID)); + + if (CapturedFrames) + ProbeForWrite(CapturedFrames, sizeof(ULONG), sizeof(ULONG)); + if (BackTraceHash) + ProbeForWrite(BackTraceHash, sizeof(ULONG), sizeof(ULONG)); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + return GetExceptionCode(); + } + } + + // If the caller doesn't want to capture anything, return immediately. + if (backTraceSize == 0) + { + if (AccessMode != KernelMode) + { + __try + { + if (CapturedFrames) + *CapturedFrames = 0; + if (BackTraceHash) + *BackTraceHash = 0; + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + status = GetExceptionCode(); + } + } + else + { + if (CapturedFrames) + *CapturedFrames = 0; + if (BackTraceHash) + *BackTraceHash = 0; + } + + return status; + } + + // Allocate storage for the stack trace. + backTrace = ExAllocatePoolWithTag(NonPagedPool, backTraceSize, 'bhpK'); + + if (!backTrace) + return STATUS_INSUFFICIENT_RESOURCES; + + // Initialize the context structure. + context.FramesToSkip = FramesToSkip; + context.FramesToCapture = FramesToCapture; + context.BackTrace = backTrace; + + // Check if we're trying to get a stack trace of the current thread. + // If so, we don't need to insert an APC. + if (Thread == PsGetCurrentThread()) + { + PCAPTURE_BACKTRACE_THREAD_CONTEXT contextPtr = &context; + PVOID dummy = NULL; + KIRQL oldIrql; + + // Raise the IRQL to APC_LEVEL to simulate an APC environment, + // and call the APC routine directly. + + context.Local = TRUE; + KeRaiseIrql(APC_LEVEL, &oldIrql); + KphpCaptureStackBackTraceThreadSpecialApc( + &context.Apc, + NULL, + NULL, + &contextPtr, + &dummy + ); + KeLowerIrql(oldIrql); + } + else + { + context.Local = FALSE; + KeInitializeEvent(&context.CompletedEvent, NotificationEvent, FALSE); + KeInitializeApc( + &context.Apc, + (PKTHREAD)Thread, + OriginalApcEnvironment, + KphpCaptureStackBackTraceThreadSpecialApc, + NULL, + NULL, + KernelMode, + NULL + ); + + if (KeInsertQueueApc(&context.Apc, &context, NULL, 2)) + { + // Wait for the APC to complete. + status = KeWaitForSingleObject( + &context.CompletedEvent, + Executive, + KernelMode, + FALSE, + NULL + ); + } + else + { + status = STATUS_UNSUCCESSFUL; + } + } + + if (NT_SUCCESS(status)) + { + ASSERT(context.CapturedFrames <= FramesToCapture); + + if (AccessMode != KernelMode) + { + __try + { + memcpy(BackTrace, backTrace, context.CapturedFrames * sizeof(PVOID)); + + if (CapturedFrames) + *CapturedFrames = context.CapturedFrames; + if (BackTraceHash) + *BackTraceHash = context.BackTraceHash; + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + status = GetExceptionCode(); + } + } + else + { + memcpy(BackTrace, backTrace, context.CapturedFrames * sizeof(PVOID)); + + if (CapturedFrames) + *CapturedFrames = context.CapturedFrames; + if (BackTraceHash) + *BackTraceHash = context.BackTraceHash; + } + } + + ExFreePoolWithTag(backTrace, 'bhpK'); + + return status; +} + +VOID KphpCaptureStackBackTraceThreadSpecialApc( + __in PRKAPC Apc, + __inout PKNORMAL_ROUTINE *NormalRoutine, + __inout PVOID *NormalContext, + __inout PVOID *SystemArgument1, + __inout PVOID *SystemArgument2 + ) +{ + PCAPTURE_BACKTRACE_THREAD_CONTEXT context = *SystemArgument1; + + PAGED_CODE(); + + context->CapturedFrames = KphCaptureStackBackTrace( + context->FramesToSkip, + context->FramesToCapture, + 0, + context->BackTrace, + &context->BackTraceHash + ); + + if (!context->Local) + { + // Notify the originating thread that we have completed. + KeSetEvent(&context->CompletedEvent, 0, FALSE); + } +} + +/** + * Captures the stack trace of a thread. + * + * \param ThreadHandle A handle to the thread to capture the stack trace of. + * \param FramesToSkip The number of frames to skip from the bottom of the stack. + * \param FramesToCapture The number of frames to capture. + * \param BackTrace An array in which the stack trace will be stored. + * \param CapturedFrames A variable which receives the number of frames captured. + * \param BackTraceHash A variable which receives a hash of the stack trace. + * \param AccessMode The mode in which to perform access checks. + * + * \return The number of frames captured. + */ +NTSTATUS KpiCaptureStackBackTraceThread( + __in HANDLE ThreadHandle, + __in ULONG FramesToSkip, + __in ULONG FramesToCapture, + __out_ecount(FramesToCapture) PVOID *BackTrace, + __out_opt PULONG CapturedFrames, + __out_opt PULONG BackTraceHash, + __in KPROCESSOR_MODE AccessMode + ) +{ + NTSTATUS status = STATUS_SUCCESS; + PETHREAD thread; + + PAGED_CODE(); + + status = ObReferenceObjectByHandle( + ThreadHandle, + 0, + *PsThreadType, + AccessMode, + &thread, + NULL + ); + + if (!NT_SUCCESS(status)) + return status; + + status = KphCaptureStackBackTraceThread( + thread, + FramesToSkip, + FramesToCapture, + BackTrace, + CapturedFrames, + BackTraceHash, + AccessMode + ); + ObDereferenceObject(thread); + + return status; +} + +/** + * Queries thread information. + * + * \param ThreadHandle A handle to a thread. + * \param ThreadInformationClass The type of information to query. + * \param ThreadInformation The buffer in which the information will be stored. + * \param ThreadInformationLength The number of bytes available in \a ThreadInformation. + * \param ReturnLength A variable which receives the number of bytes required to be available in + * \a ThreadInformation. + * \param AccessMode The mode in which to perform access checks. + */ +NTSTATUS KpiQueryInformationThread( + __in HANDLE ThreadHandle, + __in KPH_THREAD_INFORMATION_CLASS ThreadInformationClass, + __out_bcount(ProcessInformationLength) PVOID ThreadInformation, + __in ULONG ThreadInformationLength, + __out_opt PULONG ReturnLength, + __in KPROCESSOR_MODE AccessMode + ) +{ + NTSTATUS status; + PETHREAD thread; + ULONG returnLength; + + PAGED_CODE(); + + if (AccessMode != KernelMode) + { + __try + { + ProbeForWrite(ThreadInformation, ThreadInformationLength, sizeof(ULONG)); + + if (ReturnLength) + ProbeForWrite(ReturnLength, sizeof(ULONG), sizeof(ULONG)); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + return GetExceptionCode(); + } + } + + status = ObReferenceObjectByHandle( + ThreadHandle, + THREAD_QUERY_INFORMATION, + *PsThreadType, + AccessMode, + &thread, + NULL + ); + + if (!NT_SUCCESS(status)) + return status; + + switch (ThreadInformationClass) + { + default: + status = STATUS_INVALID_INFO_CLASS; + returnLength = 0; + break; + } + + ObDereferenceObject(thread); + + if (ReturnLength) + { + if (AccessMode != KernelMode) + { + __try + { + *ReturnLength = returnLength; + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + NOTHING; + } + } + else + { + *ReturnLength = returnLength; + } + } + + return status; +} + +/** + * Sets thread information. + * + * \param ThreadHandle A handle to a thread. + * \param ThreadInformationClass The type of information to set. + * \param ThreadInformation A buffer which contains the information to set. + * \param ThreadInformationLength The number of bytes present in \a ThreadInformation. + * \param AccessMode The mode in which to perform access checks. + */ +NTSTATUS KpiSetInformationThread( + __in HANDLE ThreadHandle, + __in KPH_THREAD_INFORMATION_CLASS ThreadInformationClass, + __in_bcount(ThreadInformationLength) PVOID ThreadInformation, + __in ULONG ThreadInformationLength, + __in KPROCESSOR_MODE AccessMode + ) +{ + NTSTATUS status; + PETHREAD thread; + + PAGED_CODE(); + + if (AccessMode != KernelMode) + { + __try + { + ProbeForRead(ThreadInformation, ThreadInformationLength, sizeof(ULONG)); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + return GetExceptionCode(); + } + } + + status = ObReferenceObjectByHandle( + ThreadHandle, + THREAD_SET_INFORMATION, + *PsThreadType, + AccessMode, + &thread, + NULL + ); + + if (!NT_SUCCESS(status)) + return status; + + switch (ThreadInformationClass) + { + default: + status = STATUS_INVALID_INFO_CLASS; + break; + } + + ObDereferenceObject(thread); + + return status; +} diff --git a/KProcessHacker/vm.c b/KProcessHacker/vm.c index 0ffbb578181d..41dc7ef8a85f 100644 --- a/KProcessHacker/vm.c +++ b/KProcessHacker/vm.c @@ -1,449 +1,449 @@ -/* - * KProcessHacker - * - * Copyright (C) 2010-2016 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include - -ULONG KphpGetCopyExceptionInfo( - __in PEXCEPTION_POINTERS ExceptionInfo, - __out PBOOLEAN HaveBadAddress, - __out PULONG_PTR BadAddress - ); - -#ifdef ALLOC_PRAGMA -#pragma alloc_text(PAGE, KphCopyVirtualMemory) -#pragma alloc_text(PAGE, KpiReadVirtualMemoryUnsafe) -#endif - -#define KPH_STACK_COPY_BYTES 0x200 -#define KPH_POOL_COPY_BYTES 0x10000 -#define KPH_MAPPED_COPY_PAGES 14 -#define KPH_POOL_COPY_THRESHOLD 0x3ff - -ULONG KphpGetCopyExceptionInfo( - __in PEXCEPTION_POINTERS ExceptionInfo, - __out PBOOLEAN HaveBadAddress, - __out PULONG_PTR BadAddress - ) -{ - PEXCEPTION_RECORD exceptionRecord; - - *HaveBadAddress = FALSE; - exceptionRecord = ExceptionInfo->ExceptionRecord; - - if ((exceptionRecord->ExceptionCode == STATUS_ACCESS_VIOLATION) || - (exceptionRecord->ExceptionCode == STATUS_GUARD_PAGE_VIOLATION) || - (exceptionRecord->ExceptionCode == STATUS_IN_PAGE_ERROR)) - { - if (exceptionRecord->NumberParameters > 1) - { - /* We have the address. */ - *HaveBadAddress = TRUE; - *BadAddress = exceptionRecord->ExceptionInformation[1]; - } - } - - return EXCEPTION_EXECUTE_HANDLER; -} - -/** - * Copies memory from one process to another. - * - * \param FromProcess The source process. - * \param FromAddress The source address. - * \param ToProcess The target process. - * \param ToAddress The target address. - * \param BufferLength The number of bytes to copy. - * \param AccessMode The mode in which to perform access checks. - * \param ReturnLength A variable which receives the number of bytes copied. - */ -NTSTATUS KphCopyVirtualMemory( - __in PEPROCESS FromProcess, - __in PVOID FromAddress, - __in PEPROCESS ToProcess, - __in PVOID ToAddress, - __in SIZE_T BufferLength, - __in KPROCESSOR_MODE AccessMode, - __out PSIZE_T ReturnLength - ) -{ - UCHAR stackBuffer[KPH_STACK_COPY_BYTES]; - PVOID buffer; - PFN_NUMBER mdlBuffer[(sizeof(MDL) / sizeof(PFN_NUMBER)) + KPH_MAPPED_COPY_PAGES + 1]; - PMDL mdl = (PMDL)mdlBuffer; - PVOID mappedAddress; - SIZE_T mappedTotalSize; - SIZE_T blockSize; - SIZE_T stillToCopy; - KAPC_STATE apcState; - PVOID sourceAddress; - PVOID targetAddress; - BOOLEAN doMappedCopy; - BOOLEAN pagesLocked; - BOOLEAN copyingToTarget = FALSE; - BOOLEAN probing = FALSE; - BOOLEAN mapping = FALSE; - BOOLEAN haveBadAddress; - ULONG_PTR badAddress; - - PAGED_CODE(); - - sourceAddress = FromAddress; - targetAddress = ToAddress; - - // We don't check if buffer == NULL when freeing. If buffer doesn't need to be freed, set to - // stackBuffer, not NULL. - buffer = stackBuffer; - - mappedTotalSize = (KPH_MAPPED_COPY_PAGES - 2) * PAGE_SIZE; - - if (mappedTotalSize > BufferLength) - mappedTotalSize = BufferLength; - - stillToCopy = BufferLength; - blockSize = mappedTotalSize; - - while (stillToCopy) - { - // If we're at the last copy block, copy the remaining bytes instead of the whole block - // size. - if (blockSize > stillToCopy) - blockSize = stillToCopy; - - // Choose the best method based on the number of bytes left to copy. - if (blockSize > KPH_POOL_COPY_THRESHOLD) - { - doMappedCopy = TRUE; - } - else - { - doMappedCopy = FALSE; - - if (blockSize <= KPH_STACK_COPY_BYTES) - { - if (buffer != stackBuffer) - ExFreePoolWithTag(buffer, 'ChpK'); - - buffer = stackBuffer; - } - else - { - // Don't allocate the buffer if we've done so already. Note that the block size - // never increases, so this allocation will always be OK. - if (buffer == stackBuffer) - { - // Keep trying to allocate a buffer. - - while (TRUE) - { - buffer = ExAllocatePoolWithTag(NonPagedPool, blockSize, 'ChpK'); - - // Stop trying if we got a buffer. - if (buffer) - break; - - blockSize /= 2; - - // Use the stack buffer if we can. - if (blockSize <= KPH_STACK_COPY_BYTES) - { - buffer = stackBuffer; - break; - } - } - } - } - } - - // Reset state. - mappedAddress = NULL; - pagesLocked = FALSE; - copyingToTarget = FALSE; - - KeStackAttachProcess(FromProcess, &apcState); - - __try - { - // Probe only if this is the first time. - if (sourceAddress == FromAddress && AccessMode != KernelMode) - { - probing = TRUE; - ProbeForRead(sourceAddress, BufferLength, sizeof(UCHAR)); - probing = FALSE; - } - - if (doMappedCopy) - { - // Initialize the MDL. - MmInitializeMdl(mdl, sourceAddress, blockSize); - MmProbeAndLockPages(mdl, AccessMode, IoReadAccess); - pagesLocked = TRUE; - - // Map the pages. - mappedAddress = MmMapLockedPagesSpecifyCache( - mdl, - KernelMode, - MmCached, - NULL, - FALSE, - HighPagePriority - ); - - if (!mappedAddress) - { - // Insufficient resources; exit. - mapping = TRUE; - ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES); - } - } - else - { - memcpy(buffer, sourceAddress, blockSize); - } - - KeUnstackDetachProcess(&apcState); - - // Attach to the target process and copy the contents out. - KeStackAttachProcess(ToProcess, &apcState); - - // Probe only if this is the first time. - if (targetAddress == ToAddress && AccessMode != KernelMode) - { - probing = TRUE; - ProbeForWrite(targetAddress, BufferLength, sizeof(UCHAR)); - probing = FALSE; - } - - // Copy the data. - copyingToTarget = TRUE; - - if (doMappedCopy) - memcpy(targetAddress, mappedAddress, blockSize); - else - memcpy(targetAddress, buffer, blockSize); - } - __except (KphpGetCopyExceptionInfo( - GetExceptionInformation(), - &haveBadAddress, - &badAddress - )) - { - KeUnstackDetachProcess(&apcState); - - // If we mapped the pages, unmap them. - if (mappedAddress) - MmUnmapLockedPages(mappedAddress, mdl); - - // If we locked the pages, unlock them. - if (pagesLocked) - MmUnlockPages(mdl); - - // If we allocated pool storage, free it. - if (buffer != stackBuffer) - ExFreePoolWithTag(buffer, 'ChpK'); - - // If we failed when probing or mapping, return the error status. - if (probing || mapping) - return GetExceptionCode(); - - // Determine which copy failed. - if (copyingToTarget && haveBadAddress) - { - *ReturnLength = (ULONG)(badAddress - (ULONG_PTR)sourceAddress); - } - else - { - *ReturnLength = BufferLength - stillToCopy; - } - - return STATUS_PARTIAL_COPY; - } - - KeUnstackDetachProcess(&apcState); - - if (doMappedCopy) - { - MmUnmapLockedPages(mappedAddress, mdl); - MmUnlockPages(mdl); - } - - stillToCopy -= blockSize; - sourceAddress = (PVOID)((ULONG_PTR)sourceAddress + blockSize); - targetAddress = (PVOID)((ULONG_PTR)targetAddress + blockSize); - } - - if (buffer != stackBuffer) - ExFreePoolWithTag(buffer, 'ChpK'); - - *ReturnLength = BufferLength; - - return STATUS_SUCCESS; -} - -/** - * Copies process or kernel memory into the current process. - * - * \param ProcessHandle A handle to a process. The handle must have PROCESS_VM_READ access. This - * parameter may be NULL if \a BaseAddress lies above the user-mode range. - * \param BaseAddress The address from which memory is to be copied. - * \param Buffer A buffer which receives the copied memory. - * \param BufferSize The number of bytes to copy. - * \param NumberOfBytesRead A variable which receives the number of bytes copied to the buffer. - * \param Key An access key. If no valid L2 key is provided, the function fails. - * \param Client The client that initiated the request. - * \param AccessMode The mode in which to perform access checks. - */ -NTSTATUS KpiReadVirtualMemoryUnsafe( - __in_opt HANDLE ProcessHandle, - __in PVOID BaseAddress, - __out_bcount(BufferSize) PVOID Buffer, - __in SIZE_T BufferSize, - __out_opt PSIZE_T NumberOfBytesRead, - __in_opt KPH_KEY Key, - __in PKPH_CLIENT Client, - __in KPROCESSOR_MODE AccessMode - ) -{ - NTSTATUS status; - PEPROCESS process; - SIZE_T numberOfBytesRead; - - PAGED_CODE(); - - if (!NT_SUCCESS(status = KphValidateKey(KphKeyLevel2, Key, Client, AccessMode))) - return status; - - if (AccessMode != KernelMode) - { - if ( - (ULONG_PTR)BaseAddress + BufferSize < (ULONG_PTR)BaseAddress || - (ULONG_PTR)Buffer + BufferSize < (ULONG_PTR)Buffer || - (ULONG_PTR)Buffer + BufferSize > (ULONG_PTR)MmHighestUserAddress - ) - { - return STATUS_ACCESS_VIOLATION; - } - - if (NumberOfBytesRead) - { - __try - { - ProbeForWrite(NumberOfBytesRead, sizeof(SIZE_T), sizeof(SIZE_T)); - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - return GetExceptionCode(); - } - } - } - - if (BufferSize != 0) - { - // Select the appropriate copy method. - if ((ULONG_PTR)BaseAddress + BufferSize > (ULONG_PTR)MmHighestUserAddress) - { - ULONG_PTR page; - ULONG_PTR pageEnd; - - status = KphValidateAddressForSystemModules(BaseAddress, BufferSize); - - if (!NT_SUCCESS(status)) - return status; - - // Kernel memory copy (unsafe) - - page = (ULONG_PTR)BaseAddress & ~(PAGE_SIZE - 1); - pageEnd = ((ULONG_PTR)BaseAddress + BufferSize - 1) & ~(PAGE_SIZE - 1); - - __try - { - // This will obviously fail if any of the pages aren't resident. - for (; page <= pageEnd; page += PAGE_SIZE) - { - if (!MmIsAddressValid((PVOID)page)) - ExRaiseStatus(STATUS_ACCESS_VIOLATION); - } - - memcpy(Buffer, BaseAddress, BufferSize); - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - return GetExceptionCode(); - } - - numberOfBytesRead = BufferSize; - status = STATUS_SUCCESS; - } - else - { - // User memory copy (safe) - - status = ObReferenceObjectByHandle( - ProcessHandle, - PROCESS_VM_READ, - *PsProcessType, - AccessMode, - &process, - NULL - ); - - if (NT_SUCCESS(status)) - { - status = KphCopyVirtualMemory( - process, - BaseAddress, - PsGetCurrentProcess(), - Buffer, - BufferSize, - AccessMode, - &numberOfBytesRead - ); - ObDereferenceObject(process); - } - } - } - else - { - numberOfBytesRead = 0; - status = STATUS_SUCCESS; - } - - if (NumberOfBytesRead) - { - if (AccessMode != KernelMode) - { - __try - { - *NumberOfBytesRead = numberOfBytesRead; - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - // Don't mess with the status. - NOTHING; - } - } - else - { - *NumberOfBytesRead = numberOfBytesRead; - } - } - - return status; -} +/* + * KProcessHacker + * + * Copyright (C) 2010-2016 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include + +ULONG KphpGetCopyExceptionInfo( + __in PEXCEPTION_POINTERS ExceptionInfo, + __out PBOOLEAN HaveBadAddress, + __out PULONG_PTR BadAddress + ); + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGE, KphCopyVirtualMemory) +#pragma alloc_text(PAGE, KpiReadVirtualMemoryUnsafe) +#endif + +#define KPH_STACK_COPY_BYTES 0x200 +#define KPH_POOL_COPY_BYTES 0x10000 +#define KPH_MAPPED_COPY_PAGES 14 +#define KPH_POOL_COPY_THRESHOLD 0x3ff + +ULONG KphpGetCopyExceptionInfo( + __in PEXCEPTION_POINTERS ExceptionInfo, + __out PBOOLEAN HaveBadAddress, + __out PULONG_PTR BadAddress + ) +{ + PEXCEPTION_RECORD exceptionRecord; + + *HaveBadAddress = FALSE; + exceptionRecord = ExceptionInfo->ExceptionRecord; + + if ((exceptionRecord->ExceptionCode == STATUS_ACCESS_VIOLATION) || + (exceptionRecord->ExceptionCode == STATUS_GUARD_PAGE_VIOLATION) || + (exceptionRecord->ExceptionCode == STATUS_IN_PAGE_ERROR)) + { + if (exceptionRecord->NumberParameters > 1) + { + /* We have the address. */ + *HaveBadAddress = TRUE; + *BadAddress = exceptionRecord->ExceptionInformation[1]; + } + } + + return EXCEPTION_EXECUTE_HANDLER; +} + +/** + * Copies memory from one process to another. + * + * \param FromProcess The source process. + * \param FromAddress The source address. + * \param ToProcess The target process. + * \param ToAddress The target address. + * \param BufferLength The number of bytes to copy. + * \param AccessMode The mode in which to perform access checks. + * \param ReturnLength A variable which receives the number of bytes copied. + */ +NTSTATUS KphCopyVirtualMemory( + __in PEPROCESS FromProcess, + __in PVOID FromAddress, + __in PEPROCESS ToProcess, + __in PVOID ToAddress, + __in SIZE_T BufferLength, + __in KPROCESSOR_MODE AccessMode, + __out PSIZE_T ReturnLength + ) +{ + UCHAR stackBuffer[KPH_STACK_COPY_BYTES]; + PVOID buffer; + PFN_NUMBER mdlBuffer[(sizeof(MDL) / sizeof(PFN_NUMBER)) + KPH_MAPPED_COPY_PAGES + 1]; + PMDL mdl = (PMDL)mdlBuffer; + PVOID mappedAddress; + SIZE_T mappedTotalSize; + SIZE_T blockSize; + SIZE_T stillToCopy; + KAPC_STATE apcState; + PVOID sourceAddress; + PVOID targetAddress; + BOOLEAN doMappedCopy; + BOOLEAN pagesLocked; + BOOLEAN copyingToTarget = FALSE; + BOOLEAN probing = FALSE; + BOOLEAN mapping = FALSE; + BOOLEAN haveBadAddress; + ULONG_PTR badAddress; + + PAGED_CODE(); + + sourceAddress = FromAddress; + targetAddress = ToAddress; + + // We don't check if buffer == NULL when freeing. If buffer doesn't need to be freed, set to + // stackBuffer, not NULL. + buffer = stackBuffer; + + mappedTotalSize = (KPH_MAPPED_COPY_PAGES - 2) * PAGE_SIZE; + + if (mappedTotalSize > BufferLength) + mappedTotalSize = BufferLength; + + stillToCopy = BufferLength; + blockSize = mappedTotalSize; + + while (stillToCopy) + { + // If we're at the last copy block, copy the remaining bytes instead of the whole block + // size. + if (blockSize > stillToCopy) + blockSize = stillToCopy; + + // Choose the best method based on the number of bytes left to copy. + if (blockSize > KPH_POOL_COPY_THRESHOLD) + { + doMappedCopy = TRUE; + } + else + { + doMappedCopy = FALSE; + + if (blockSize <= KPH_STACK_COPY_BYTES) + { + if (buffer != stackBuffer) + ExFreePoolWithTag(buffer, 'ChpK'); + + buffer = stackBuffer; + } + else + { + // Don't allocate the buffer if we've done so already. Note that the block size + // never increases, so this allocation will always be OK. + if (buffer == stackBuffer) + { + // Keep trying to allocate a buffer. + + while (TRUE) + { + buffer = ExAllocatePoolWithTag(NonPagedPool, blockSize, 'ChpK'); + + // Stop trying if we got a buffer. + if (buffer) + break; + + blockSize /= 2; + + // Use the stack buffer if we can. + if (blockSize <= KPH_STACK_COPY_BYTES) + { + buffer = stackBuffer; + break; + } + } + } + } + } + + // Reset state. + mappedAddress = NULL; + pagesLocked = FALSE; + copyingToTarget = FALSE; + + KeStackAttachProcess(FromProcess, &apcState); + + __try + { + // Probe only if this is the first time. + if (sourceAddress == FromAddress && AccessMode != KernelMode) + { + probing = TRUE; + ProbeForRead(sourceAddress, BufferLength, sizeof(UCHAR)); + probing = FALSE; + } + + if (doMappedCopy) + { + // Initialize the MDL. + MmInitializeMdl(mdl, sourceAddress, blockSize); + MmProbeAndLockPages(mdl, AccessMode, IoReadAccess); + pagesLocked = TRUE; + + // Map the pages. + mappedAddress = MmMapLockedPagesSpecifyCache( + mdl, + KernelMode, + MmCached, + NULL, + FALSE, + HighPagePriority + ); + + if (!mappedAddress) + { + // Insufficient resources; exit. + mapping = TRUE; + ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES); + } + } + else + { + memcpy(buffer, sourceAddress, blockSize); + } + + KeUnstackDetachProcess(&apcState); + + // Attach to the target process and copy the contents out. + KeStackAttachProcess(ToProcess, &apcState); + + // Probe only if this is the first time. + if (targetAddress == ToAddress && AccessMode != KernelMode) + { + probing = TRUE; + ProbeForWrite(targetAddress, BufferLength, sizeof(UCHAR)); + probing = FALSE; + } + + // Copy the data. + copyingToTarget = TRUE; + + if (doMappedCopy) + memcpy(targetAddress, mappedAddress, blockSize); + else + memcpy(targetAddress, buffer, blockSize); + } + __except (KphpGetCopyExceptionInfo( + GetExceptionInformation(), + &haveBadAddress, + &badAddress + )) + { + KeUnstackDetachProcess(&apcState); + + // If we mapped the pages, unmap them. + if (mappedAddress) + MmUnmapLockedPages(mappedAddress, mdl); + + // If we locked the pages, unlock them. + if (pagesLocked) + MmUnlockPages(mdl); + + // If we allocated pool storage, free it. + if (buffer != stackBuffer) + ExFreePoolWithTag(buffer, 'ChpK'); + + // If we failed when probing or mapping, return the error status. + if (probing || mapping) + return GetExceptionCode(); + + // Determine which copy failed. + if (copyingToTarget && haveBadAddress) + { + *ReturnLength = (ULONG)(badAddress - (ULONG_PTR)sourceAddress); + } + else + { + *ReturnLength = BufferLength - stillToCopy; + } + + return STATUS_PARTIAL_COPY; + } + + KeUnstackDetachProcess(&apcState); + + if (doMappedCopy) + { + MmUnmapLockedPages(mappedAddress, mdl); + MmUnlockPages(mdl); + } + + stillToCopy -= blockSize; + sourceAddress = (PVOID)((ULONG_PTR)sourceAddress + blockSize); + targetAddress = (PVOID)((ULONG_PTR)targetAddress + blockSize); + } + + if (buffer != stackBuffer) + ExFreePoolWithTag(buffer, 'ChpK'); + + *ReturnLength = BufferLength; + + return STATUS_SUCCESS; +} + +/** + * Copies process or kernel memory into the current process. + * + * \param ProcessHandle A handle to a process. The handle must have PROCESS_VM_READ access. This + * parameter may be NULL if \a BaseAddress lies above the user-mode range. + * \param BaseAddress The address from which memory is to be copied. + * \param Buffer A buffer which receives the copied memory. + * \param BufferSize The number of bytes to copy. + * \param NumberOfBytesRead A variable which receives the number of bytes copied to the buffer. + * \param Key An access key. If no valid L2 key is provided, the function fails. + * \param Client The client that initiated the request. + * \param AccessMode The mode in which to perform access checks. + */ +NTSTATUS KpiReadVirtualMemoryUnsafe( + __in_opt HANDLE ProcessHandle, + __in PVOID BaseAddress, + __out_bcount(BufferSize) PVOID Buffer, + __in SIZE_T BufferSize, + __out_opt PSIZE_T NumberOfBytesRead, + __in_opt KPH_KEY Key, + __in PKPH_CLIENT Client, + __in KPROCESSOR_MODE AccessMode + ) +{ + NTSTATUS status; + PEPROCESS process; + SIZE_T numberOfBytesRead; + + PAGED_CODE(); + + if (!NT_SUCCESS(status = KphValidateKey(KphKeyLevel2, Key, Client, AccessMode))) + return status; + + if (AccessMode != KernelMode) + { + if ( + (ULONG_PTR)BaseAddress + BufferSize < (ULONG_PTR)BaseAddress || + (ULONG_PTR)Buffer + BufferSize < (ULONG_PTR)Buffer || + (ULONG_PTR)Buffer + BufferSize > (ULONG_PTR)MmHighestUserAddress + ) + { + return STATUS_ACCESS_VIOLATION; + } + + if (NumberOfBytesRead) + { + __try + { + ProbeForWrite(NumberOfBytesRead, sizeof(SIZE_T), sizeof(SIZE_T)); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + return GetExceptionCode(); + } + } + } + + if (BufferSize != 0) + { + // Select the appropriate copy method. + if ((ULONG_PTR)BaseAddress + BufferSize > (ULONG_PTR)MmHighestUserAddress) + { + ULONG_PTR page; + ULONG_PTR pageEnd; + + status = KphValidateAddressForSystemModules(BaseAddress, BufferSize); + + if (!NT_SUCCESS(status)) + return status; + + // Kernel memory copy (unsafe) + + page = (ULONG_PTR)BaseAddress & ~(PAGE_SIZE - 1); + pageEnd = ((ULONG_PTR)BaseAddress + BufferSize - 1) & ~(PAGE_SIZE - 1); + + __try + { + // This will obviously fail if any of the pages aren't resident. + for (; page <= pageEnd; page += PAGE_SIZE) + { + if (!MmIsAddressValid((PVOID)page)) + ExRaiseStatus(STATUS_ACCESS_VIOLATION); + } + + memcpy(Buffer, BaseAddress, BufferSize); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + return GetExceptionCode(); + } + + numberOfBytesRead = BufferSize; + status = STATUS_SUCCESS; + } + else + { + // User memory copy (safe) + + status = ObReferenceObjectByHandle( + ProcessHandle, + PROCESS_VM_READ, + *PsProcessType, + AccessMode, + &process, + NULL + ); + + if (NT_SUCCESS(status)) + { + status = KphCopyVirtualMemory( + process, + BaseAddress, + PsGetCurrentProcess(), + Buffer, + BufferSize, + AccessMode, + &numberOfBytesRead + ); + ObDereferenceObject(process); + } + } + } + else + { + numberOfBytesRead = 0; + status = STATUS_SUCCESS; + } + + if (NumberOfBytesRead) + { + if (AccessMode != KernelMode) + { + __try + { + *NumberOfBytesRead = numberOfBytesRead; + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + // Don't mess with the status. + NOTHING; + } + } + else + { + *NumberOfBytesRead = numberOfBytesRead; + } + } + + return status; +} diff --git a/LICENSE.txt b/LICENSE.txt index 4e402de2cfe4..201de86e9f7e 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,685 +1,685 @@ -Process Hacker is distributed under the GNU GPL version 3, with the -following exception: - - Permission is granted to dynamically (but not statically) link this - program with independent modules, regardless of the license terms of - these independent modules, provided that this program is not modified - in any way. An independent module is a module which is not derived - from or based on this program. If you modify this program, this - additional permission no longer applies unless authorized by the - copyright holders. - - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - Copyright (C) - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -. +Process Hacker is distributed under the GNU GPL version 3, with the +following exception: + + Permission is granted to dynamically (but not statically) link this + program with independent modules, regardless of the license terms of + these independent modules, provided that this program is not modified + in any way. An independent module is a module which is not derived + from or based on this program. If you modify this program, this + additional permission no longer applies unless authorized by the + copyright holders. + + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/ProcessHacker/ProcessHacker.manifest b/ProcessHacker/ProcessHacker.manifest index 3bc4a2568dd8..1a214566dc7e 100644 --- a/ProcessHacker/ProcessHacker.manifest +++ b/ProcessHacker/ProcessHacker.manifest @@ -1,49 +1,49 @@ - - - - Process Hacker - - - - - - - - - - - - - - - - - - - - - - - - true - - - true - - - true - - + + + + Process Hacker + + + + + + + + + + + + + + + + + + + + + + + + true + + + true + + + true + + \ No newline at end of file diff --git a/ProcessHacker/ProcessHacker.rc b/ProcessHacker/ProcessHacker.rc index 74667f423a66..4bc346f7cf65 100644 --- a/ProcessHacker/ProcessHacker.rc +++ b/ProcessHacker/ProcessHacker.rc @@ -1,2632 +1,2632 @@ -// Microsoft Visual C++ generated resource script. -// -#include "resource.h" - -#define APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// -#include "winres.h" -#include "include/phappres.h" -///////////////////////////////////////////////////////////////////////////// -#undef APSTUDIO_READONLY_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -// English (Australia) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENA) -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_AUS -#pragma code_page(1252) - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -1 TEXTINCLUDE -BEGIN - "resource.h\0" -END - -2 TEXTINCLUDE -BEGIN - "#include ""winres.h""\r\n" - "#include ""include/phappres.h""\0" -END - -3 TEXTINCLUDE -BEGIN - "\r\n" - "\0" -END - -#endif // APSTUDIO_INVOKED - - -///////////////////////////////////////////////////////////////////////////// -// -// Icon -// - -// Icon with lowest ID value placed first to ensure application icon -// remains consistent on all systems. -IDI_PROCESSHACKER ICON "ProcessHacker.ico" - -IDI_PHAPPLICATION ICON "resources\\application.ico" - -IDI_COG ICON "resources\\cog.ico" - -IDI_PHAPPLICATIONGO ICON "resources\\application_go.ico" - -IDI_COGGO ICON "resources\\cog_go.ico" - -IDI_PIN ICON "resources\\pin.ico" - -IDI_FOLDER ICON "resources\\folder.ico" - -IDI_PENCIL ICON "resources\\pencil.ico" - -IDI_MAGNIFIER ICON "resources\\magnifier.ico" - - -///////////////////////////////////////////////////////////////////////////// -// -// Menu -// - -IDR_MAINWND MENU -BEGIN - POPUP "&Hacker" - BEGIN - MENUITEM "&Run...\aCtrl+R", ID_HACKER_RUN - MENUITEM "Run as administrator...", ID_HACKER_RUNASADMINISTRATOR - MENUITEM "Run as &limited user...", ID_HACKER_RUNASLIMITEDUSER - MENUITEM "Run &as...\aCtrl+Shift+R", ID_HACKER_RUNAS - MENUITEM "Show &details for all processes", ID_HACKER_SHOWDETAILSFORALLPROCESSES - MENUITEM SEPARATOR - MENUITEM "&Save...\aCtrl+S", ID_HACKER_SAVE - MENUITEM "&Find handles or DLLs...\aCtrl+F", ID_HACKER_FINDHANDLESORDLLS - MENUITEM "&Options...", ID_HACKER_OPTIONS - MENUITEM "&Plugins...", ID_HACKER_PLUGINS - MENUITEM SEPARATOR - POPUP "&Computer" - BEGIN - MENUITEM "&Lock", ID_COMPUTER_LOCK - MENUITEM "Log o&ff", ID_COMPUTER_LOGOFF - MENUITEM SEPARATOR - MENUITEM "&Sleep", ID_COMPUTER_SLEEP - MENUITEM "&Hibernate", ID_COMPUTER_HIBERNATE - MENUITEM SEPARATOR - MENUITEM "R&estart", ID_COMPUTER_RESTART - MENUITEM "Restart to boot options", ID_COMPUTER_RESTARTBOOTOPTIONS - MENUITEM "Shu&t down", ID_COMPUTER_SHUTDOWN - MENUITEM "H&ybrid shut down", ID_COMPUTER_SHUTDOWNHYBRID - END - MENUITEM "E&xit", ID_HACKER_EXIT - END - POPUP "&View" - BEGIN - MENUITEM "System &information\aCtrl+I", ID_VIEW_SYSTEMINFORMATION - POPUP "&Tray icons" - BEGIN - MENUITEM "CPU history", ID_TRAYICONS_CPUHISTORY - MENUITEM "CPU usage", ID_TRAYICONS_CPUUSAGE - MENUITEM "I/O history", ID_TRAYICONS_IOHISTORY - MENUITEM "Commit charge history", ID_TRAYICONS_COMMITHISTORY - MENUITEM "Physical memory history", ID_TRAYICONS_PHYSICALMEMORYHISTORY - END - MENUITEM SEPARATOR - MENUITEM "
", ID_VIEW_SECTIONPLACEHOLDER - MENUITEM SEPARATOR - MENUITEM "&Always on top", ID_VIEW_ALWAYSONTOP - POPUP "&Opacity" - BEGIN - MENUITEM "10%", ID_OPACITY_10 - MENUITEM "20%", ID_OPACITY_20 - MENUITEM "30%", ID_OPACITY_30 - MENUITEM "40%", ID_OPACITY_40 - MENUITEM "50%", ID_OPACITY_50 - MENUITEM "60%", ID_OPACITY_60 - MENUITEM "70%", ID_OPACITY_70 - MENUITEM "80%", ID_OPACITY_80 - MENUITEM "90%", ID_OPACITY_90 - MENUITEM "Opaque", ID_OPACITY_OPAQUE - END - MENUITEM SEPARATOR - MENUITEM "&Refresh\aF5", ID_VIEW_REFRESH - POPUP "Refresh i&nterval" - BEGIN - MENUITEM "Fast (0.5s)", ID_UPDATEINTERVAL_FAST - MENUITEM "Normal (1s)", ID_UPDATEINTERVAL_NORMAL - MENUITEM "Below normal (2s)", ID_UPDATEINTERVAL_BELOWNORMAL - MENUITEM "Slow (5s)", ID_UPDATEINTERVAL_SLOW - MENUITEM "Very slow (10s)", ID_UPDATEINTERVAL_VERYSLOW - END - MENUITEM "Refresh a&utomatically\aF6", ID_VIEW_UPDATEAUTOMATICALLY - END - POPUP "&Tools" - BEGIN - MENUITEM "Create service...", ID_TOOLS_CREATESERVICE - MENUITEM "Hidden processes", ID_TOOLS_HIDDENPROCESSES - MENUITEM "Inspect executable file...", ID_TOOLS_INSPECTEXECUTABLEFILE - MENUITEM "Pagefiles", ID_TOOLS_PAGEFILES - MENUITEM "Start Task Manager", ID_TOOLS_STARTTASKMANAGER - END - POPUP "&Users" - BEGIN - MENUITEM "Dummy", ID_USERS_DUMMY - END - POPUP "H&elp" - BEGIN - MENUITEM "&Log\aCtrl+L", ID_HELP_LOG - MENUITEM "&Donate", ID_HELP_DONATE - MENUITEM "Debu&g console", ID_HELP_DEBUGCONSOLE - MENUITEM "&About", ID_HELP_ABOUT - END -END - -IDR_THREAD MENU -BEGIN - POPUP "Thread" - BEGIN - MENUITEM "&Inspect\aEnter", ID_THREAD_INSPECT - MENUITEM "T&erminate\aDel", ID_THREAD_TERMINATE - MENUITEM "&Suspend", ID_THREAD_SUSPEND - MENUITEM "Res&ume", ID_THREAD_RESUME - MENUITEM SEPARATOR - MENUITEM "&Affinity", ID_THREAD_AFFINITY - MENUITEM "Per&missions", ID_THREAD_PERMISSIONS - MENUITEM "&Token", ID_THREAD_TOKEN - POPUP "Analy&ze" - BEGIN - MENUITEM "Wait", ID_ANALYZE_WAIT - END - POPUP "&Priority" - BEGIN - MENUITEM "Time critical", ID_PRIORITY_TIMECRITICAL - MENUITEM "Highest", ID_PRIORITY_HIGHEST - MENUITEM "Above normal", ID_PRIORITY_ABOVENORMAL - MENUITEM "Normal", ID_PRIORITY_NORMAL - MENUITEM "Below normal", ID_PRIORITY_BELOWNORMAL - MENUITEM "Lowest", ID_PRIORITY_LOWEST - MENUITEM "Idle", ID_PRIORITY_IDLE - END - POPUP "I/O priority" - BEGIN - MENUITEM "High", ID_IOPRIORITY_HIGH - MENUITEM "Normal", ID_IOPRIORITY_NORMAL - MENUITEM "Low", ID_IOPRIORITY_LOW - MENUITEM "Very low", ID_IOPRIORITY_VERYLOW - END - POPUP "Page priority" - BEGIN - MENUITEM "Normal", ID_PAGEPRIORITY_NORMAL - MENUITEM "Below normal", ID_PAGEPRIORITY_BELOWNORMAL - MENUITEM "Medium", ID_PAGEPRIORITY_MEDIUM - MENUITEM "Low", ID_PAGEPRIORITY_LOW - MENUITEM "Very low", ID_PAGEPRIORITY_VERYLOW - END - MENUITEM SEPARATOR - MENUITEM "&Copy\aCtrl+C", ID_THREAD_COPY - END -END - -IDR_HANDLE MENU -BEGIN - POPUP "Handle" - BEGIN - MENUITEM "C&lose\aDel", ID_HANDLE_CLOSE - MENUITEM "&Protected", ID_HANDLE_PROTECTED - MENUITEM "&Inherit", ID_HANDLE_INHERIT - MENUITEM SEPARATOR - MENUITEM "&Copy\aCtrl+C", ID_HANDLE_COPY - MENUITEM "Prope&rties\aEnter", ID_HANDLE_PROPERTIES - END -END - -IDR_MODULE MENU -BEGIN - POPUP "Module" - BEGIN - MENUITEM "&Unload\aDel", ID_MODULE_UNLOAD - MENUITEM SEPARATOR - MENUITEM "&Inspect\aEnter", ID_MODULE_INSPECT - MENUITEM "&Search online\aCtrl+M", ID_MODULE_SEARCHONLINE - MENUITEM "Open &file location\aCtrl+Enter", ID_MODULE_OPENFILELOCATION - MENUITEM "P&roperties", ID_MODULE_PROPERTIES - MENUITEM "&Copy\aCtrl+C", ID_MODULE_COPY - END -END - -IDR_COMPUTER MENU -BEGIN - POPUP "Computer" - BEGIN - MENUITEM "&Lock", ID_COMPUTER_LOCK - MENUITEM "Log o&ff", ID_COMPUTER_LOGOFF - MENUITEM SEPARATOR - MENUITEM "&Sleep", ID_COMPUTER_SLEEP - MENUITEM "&Hibernate", ID_COMPUTER_HIBERNATE - MENUITEM SEPARATOR - MENUITEM "R&estart", ID_COMPUTER_RESTART - MENUITEM "Restart to boot &options", ID_COMPUTER_RESTARTBOOTOPTIONS - MENUITEM "Shu&t down", ID_COMPUTER_SHUTDOWN - MENUITEM "H&ybrid shut down", ID_COMPUTER_SHUTDOWNHYBRID - END -END - -IDR_PROCESS MENU -BEGIN - POPUP "Process" - BEGIN - MENUITEM "T&erminate\aDel", ID_PROCESS_TERMINATE - MENUITEM "Terminate tree\aShift+Del", ID_PROCESS_TERMINATETREE - MENUITEM "&Suspend", ID_PROCESS_SUSPEND - MENUITEM "Res&ume", ID_PROCESS_RESUME - MENUITEM "Res&tart", ID_PROCESS_RESTART - MENUITEM SEPARATOR - MENUITEM "Create dump file...", ID_PROCESS_CREATEDUMPFILE - MENUITEM "Debug", ID_PROCESS_DEBUG - MENUITEM "Virtualization", ID_PROCESS_VIRTUALIZATION - MENUITEM SEPARATOR - MENUITEM "&Affinity", ID_PROCESS_AFFINITY - POPUP "&Priority" - BEGIN - MENUITEM "Real time", ID_PRIORITY_REALTIME - MENUITEM "High", ID_PRIORITY_HIGH - MENUITEM "Above normal", ID_PRIORITY_ABOVENORMAL - MENUITEM "Normal", ID_PRIORITY_NORMAL - MENUITEM "Below normal", ID_PRIORITY_BELOWNORMAL - MENUITEM "Idle", ID_PRIORITY_IDLE - END - POPUP "&I/O priority" - BEGIN - MENUITEM "High", ID_IOPRIORITY_HIGH - MENUITEM "Normal", ID_IOPRIORITY_NORMAL - MENUITEM "Low", ID_IOPRIORITY_LOW - MENUITEM "Very low", ID_IOPRIORITY_VERYLOW - END - POPUP "&Miscellaneous" - BEGIN - MENUITEM "Detach from debugger", ID_MISCELLANEOUS_DETACHFROMDEBUGGER - MENUITEM "GDI handles", ID_MISCELLANEOUS_GDIHANDLES - MENUITEM "Inject DLL...", ID_MISCELLANEOUS_INJECTDLL - POPUP "Page priority" - BEGIN - MENUITEM "Normal", ID_PAGEPRIORITY_NORMAL - MENUITEM "Below normal", ID_PAGEPRIORITY_BELOWNORMAL - MENUITEM "Medium", ID_PAGEPRIORITY_MEDIUM - MENUITEM "Low", ID_PAGEPRIORITY_LOW - MENUITEM "Very low", ID_PAGEPRIORITY_VERYLOW - END - MENUITEM "Reduce working set", ID_MISCELLANEOUS_REDUCEWORKINGSET - MENUITEM "Run as...", ID_MISCELLANEOUS_RUNAS - MENUITEM "Run as this user...", ID_MISCELLANEOUS_RUNASTHISUSER - END - POPUP "&Window" - BEGIN - MENUITEM "Bring to front", ID_WINDOW_BRINGTOFRONT - MENUITEM "Restore", ID_WINDOW_RESTORE - MENUITEM "Minimize", ID_WINDOW_MINIMIZE - MENUITEM "Maximize", ID_WINDOW_MAXIMIZE - MENUITEM SEPARATOR - MENUITEM "Close", ID_WINDOW_CLOSE - END - MENUITEM SEPARATOR - MENUITEM "Search online\aCtrl+M", ID_PROCESS_SEARCHONLINE - MENUITEM "Open &file location\aCtrl+Enter", ID_PROCESS_OPENFILELOCATION - MENUITEM "P&roperties\aEnter", ID_PROCESS_PROPERTIES - MENUITEM "&Copy\aCtrl+C", ID_PROCESS_COPY - END -END - -IDR_SERVICE MENU -BEGIN - POPUP "Service" - BEGIN - MENUITEM "&Go to process", ID_SERVICE_GOTOPROCESS - MENUITEM "&Start", ID_SERVICE_START - MENUITEM "C&ontinue", ID_SERVICE_CONTINUE - MENUITEM "&Pause", ID_SERVICE_PAUSE - MENUITEM "S&top", ID_SERVICE_STOP - MENUITEM "&Delete\aDel", ID_SERVICE_DELETE - MENUITEM SEPARATOR - MENUITEM "Open &key", ID_SERVICE_OPENKEY - MENUITEM "Open &file location\aCtrl+Enter", ID_SERVICE_OPENFILELOCATION - MENUITEM "P&roperties\aEnter", ID_SERVICE_PROPERTIES - MENUITEM "&Copy\aCtrl+C", ID_SERVICE_COPY - END -END - -IDR_PRIVILEGE MENU -BEGIN - POPUP "Privilege" - BEGIN - MENUITEM "&Enable", ID_PRIVILEGE_ENABLE - MENUITEM "&Disable", ID_PRIVILEGE_DISABLE - MENUITEM "&Remove", ID_PRIVILEGE_REMOVE - MENUITEM SEPARATOR - MENUITEM "&Copy\aCtrl+C", ID_PRIVILEGE_COPY - END -END - -IDR_FINDOBJ MENU -BEGIN - POPUP "Object" - BEGIN - MENUITEM "C&lose\aDel", ID_OBJECT_CLOSE - MENUITEM SEPARATOR - MENUITEM "Go to owning &process", ID_OBJECT_GOTOOWNINGPROCESS - MENUITEM "Prope&rties", ID_OBJECT_PROPERTIES - MENUITEM "&Copy\aCtrl+C", ID_OBJECT_COPY - END -END - -IDR_USER MENU -BEGIN - POPUP "User" - BEGIN - MENUITEM "&Connect", ID_USER_CONNECT - MENUITEM "&Disconnect", ID_USER_DISCONNECT - MENUITEM "&Logoff", ID_USER_LOGOFF - MENUITEM "Rem&ote control", ID_USER_REMOTECONTROL - MENUITEM "Send &message...", ID_USER_SENDMESSAGE - MENUITEM "P&roperties", ID_USER_PROPERTIES - END -END - -IDR_NETWORK MENU -BEGIN - POPUP "Network" - BEGIN - MENUITEM "&Go to process\aEnter", ID_NETWORK_GOTOPROCESS - MENUITEM "Go to service", ID_NETWORK_GOTOSERVICE - MENUITEM "View &stack", ID_NETWORK_VIEWSTACK - MENUITEM "C&lose", ID_NETWORK_CLOSE - MENUITEM SEPARATOR - MENUITEM "&Copy\aCtrl+C", ID_NETWORK_COPY - END -END - -IDR_ICON MENU -BEGIN - POPUP "Icon" - BEGIN - MENUITEM "&Show/Hide Process Hacker", ID_ICON_SHOWHIDEPROCESSHACKER - MENUITEM "System &information", ID_ICON_SYSTEMINFORMATION - POPUP "N&otifications" - BEGIN - MENUITEM "Enable all", ID_NOTIFICATIONS_ENABLEALL - MENUITEM "Disable all", ID_NOTIFICATIONS_DISABLEALL - MENUITEM SEPARATOR - MENUITEM "New processes", ID_NOTIFICATIONS_NEWPROCESSES - MENUITEM "Terminated processes", ID_NOTIFICATIONS_TERMINATEDPROCESSES - MENUITEM "New services", ID_NOTIFICATIONS_NEWSERVICES - MENUITEM "Started services", ID_NOTIFICATIONS_STARTEDSERVICES - MENUITEM "Stopped services", ID_NOTIFICATIONS_STOPPEDSERVICES - MENUITEM "Deleted services", ID_NOTIFICATIONS_DELETEDSERVICES - END - POPUP "&Processes" - BEGIN - MENUITEM "Dummy", ID_PROCESSES_DUMMY - END - MENUITEM SEPARATOR - POPUP "&Computer" - BEGIN - MENUITEM "&Lock", ID_COMPUTER_LOCK - MENUITEM "Log o&ff", ID_COMPUTER_LOGOFF - MENUITEM SEPARATOR - MENUITEM "&Sleep", ID_COMPUTER_SLEEP - MENUITEM "&Hibernate", ID_COMPUTER_HIBERNATE - MENUITEM SEPARATOR - MENUITEM "R&estart", ID_COMPUTER_RESTART - MENUITEM "Restart to boot options", ID_COMPUTER_RESTARTBOOTOPTIONS - MENUITEM "Shu&t down", ID_COMPUTER_SHUTDOWN - MENUITEM "H&ybrid shut down", ID_COMPUTER_SHUTDOWNHYBRID - END - MENUITEM "E&xit", ID_ICON_EXIT - END -END - -IDR_MEMORY MENU -BEGIN - POPUP "Memory" - BEGIN - MENUITEM "&Read/Write memory", ID_MEMORY_READWRITEMEMORY - MENUITEM "&Save...", ID_MEMORY_SAVE - MENUITEM "Change &protection...", ID_MEMORY_CHANGEPROTECTION - MENUITEM "&Free", ID_MEMORY_FREE - MENUITEM "&Decommit", ID_MEMORY_DECOMMIT - MENUITEM SEPARATOR - MENUITEM "Read/Write &address...", ID_MEMORY_READWRITEADDRESS - MENUITEM "&Copy\aCtrl+C", ID_MEMORY_COPY - END -END - -IDR_MEMFILTER MENU -BEGIN - POPUP "Filter" - BEGIN - MENUITEM "Contains...", ID_FILTER_CONTAINS - MENUITEM "Contains (case-insensitive)...", ID_FILTER_CONTAINS_CASEINSENSITIVE - MENUITEM "Regex...", ID_FILTER_REGEX - MENUITEM "Regex (case-insensitive)...", ID_FILTER_REGEX_CASEINSENSITIVE - END -END - -IDR_EMPTYMEMLISTS MENU -BEGIN - POPUP "Empty" - BEGIN - MENUITEM "Empty working sets", ID_EMPTY_EMPTYWORKINGSETS - MENUITEM "Empty modified page list", ID_EMPTY_EMPTYMODIFIEDPAGELIST - MENUITEM "Empty standby list", ID_EMPTY_EMPTYSTANDBYLIST - MENUITEM "Empty priority 0 standby list", ID_EMPTY_EMPTYPRIORITY0STANDBYLIST - END -END - -IDR_MINIINFO MENU -BEGIN - POPUP "Mini Info" - BEGIN - POPUP "&Opacity" - BEGIN - MENUITEM "10%", ID_OPACITY_10 - MENUITEM "20%", ID_OPACITY_20 - MENUITEM "30%", ID_OPACITY_30 - MENUITEM "40%", ID_OPACITY_40 - MENUITEM "50%", ID_OPACITY_50 - MENUITEM "60%", ID_OPACITY_60 - MENUITEM "70%", ID_OPACITY_70 - MENUITEM "80%", ID_OPACITY_80 - MENUITEM "90%", ID_OPACITY_90 - MENUITEM "Opaque", ID_OPACITY_OPAQUE - END - MENUITEM SEPARATOR - MENUITEM "&Refresh\aF5", ID_MINIINFO_REFRESH - MENUITEM "Refresh a&utomatically\aF6", ID_MINIINFO_REFRESHAUTOMATICALLY - END -END - -IDR_MINIINFO_PROCESS MENU -BEGIN - POPUP "Process" - BEGIN - MENUITEM SEPARATOR - MENUITEM "&Go to process", ID_PROCESS_GOTOPROCESS - END -END - -IDR_ENVIRONMENT MENU -BEGIN - POPUP "Environment" - BEGIN - MENUITEM "&Edit", ID_ENVIRONMENT_EDIT - MENUITEM "&Delete\aDel", ID_ENVIRONMENT_DELETE - MENUITEM "&Copy\aCtrl+C", ID_ENVIRONMENT_COPY - END -END - - -///////////////////////////////////////////////////////////////////////////// -// -// Dialog -// - -IDD_PROCGENERAL DIALOGEX 0, 0, 260, 260 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "General" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - PUSHBUTTON "Permissions",IDC_PERMISSIONS,143,197,50,14 - PUSHBUTTON "Terminate",IDC_TERMINATE,197,197,50,14 - GROUPBOX "File",IDC_FILE,7,7,246,79 - ICON "",IDC_FILEICON,14,18,20,20 - EDITTEXT IDC_NAME,44,17,182,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER - EDITTEXT IDC_COMPANYNAME,44,29,183,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER - CONTROL "Company name link",IDC_COMPANYNAME_LINK,"SysLink",LWS_NOPREFIX | NOT WS_VISIBLE | WS_TABSTOP,46,29,183,9 - LTEXT "Version:",IDC_STATIC,15,41,27,8 - EDITTEXT IDC_VERSION,44,41,113,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER - LTEXT "Image file name:",IDC_STATIC,15,55,56,8 - EDITTEXT IDC_FILENAME,15,65,191,12,ES_AUTOHSCROLL | ES_READONLY - PUSHBUTTON "Inspect",IDC_INSPECT,210,64,17,15,BS_ICON - PUSHBUTTON "Open",IDC_OPENFILENAME,230,64,17,15,BS_ICON - GROUPBOX "Process",IDC_PROCESS,7,92,246,161 - LTEXT "Command line:",IDC_STATIC,13,103,50,8 - EDITTEXT IDC_CMDLINE,79,101,147,12,ES_AUTOHSCROLL | ES_READONLY - LTEXT "Current directory:",IDC_STATIC,13,119,60,8 - EDITTEXT IDC_CURDIR,79,117,168,12,ES_AUTOHSCROLL | ES_READONLY - LTEXT "Started:",IDC_STATIC,13,135,28,8 - EDITTEXT IDC_STARTED,79,133,168,12,ES_AUTOHSCROLL | ES_READONLY - LTEXT "PEB address:",IDC_STATIC,13,151,44,8 - EDITTEXT IDC_PEBADDRESS,79,149,101,12,ES_AUTOHSCROLL | ES_READONLY - LTEXT "Image type:",IDC_PROCESSTYPELABEL,185,151,41,8,NOT WS_VISIBLE - LTEXT "32-bit",IDC_PROCESSTYPETEXT,228,151,20,8,NOT WS_VISIBLE - LTEXT "Parent:",IDC_STATIC,13,167,25,8 - EDITTEXT IDC_PARENTPROCESS,79,165,147,12,ES_AUTOHSCROLL | ES_READONLY - PUSHBUTTON "View",IDC_VIEWPARENTPROCESS,230,163,17,15,BS_ICON - LTEXT "Mitigation policies:",IDC_STATIC,13,183,59,8 - EDITTEXT IDC_MITIGATION,79,181,126,12,ES_AUTOHSCROLL | ES_READONLY - PUSHBUTTON "Details",IDC_VIEWMITIGATION,209,180,38,14 - LTEXT "Protection:",IDC_STATIC,13,200,36,8 - EDITTEXT IDC_PROTECTION,51,200,80,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER - PUSHBUTTON "View",IDC_VIEWCOMMANDLINE,230,100,17,15,BS_ICON -END - -IDD_PROCMODULES DIALOGEX 0, 0, 260, 260 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Modules" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - CONTROL "",IDC_LIST,"PhTreeNew",WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP | 0xa,7,7,246,246,WS_EX_CLIENTEDGE -END - -IDD_PROCTHREADS DIALOGEX 0, 0, 260, 260 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Threads" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "Start module:",IDC_STATICBL1,7,170,44,8 - EDITTEXT IDC_STARTMODULE,55,168,177,12,ES_AUTOHSCROLL | ES_READONLY - PUSHBUTTON "Open",IDC_OPENSTARTMODULE,236,166,17,15,BS_ICON | WS_DISABLED - LTEXT "Started:",IDC_STATICBL2,7,184,28,8 - LTEXT "N/A",IDC_STARTED,75,184,178,8 - LTEXT "Kernel time:",IDC_STATICBL3,7,207,40,8 - LTEXT "N/A",IDC_KERNELTIME,75,207,51,8 - LTEXT "User time:",IDC_STATICBL4,7,217,35,8 - LTEXT "N/A",IDC_USERTIME,75,217,51,8 - LTEXT "Context switches:",IDC_STATICBL5,7,228,60,8 - LTEXT "N/A",IDC_CONTEXTSWITCHES,75,228,51,8,SS_ENDELLIPSIS - LTEXT "Cycles:",IDC_STATICBL6,7,239,24,8 - LTEXT "N/A",IDC_CYCLES,41,239,85,8,SS_ENDELLIPSIS - LTEXT "Base priority:",IDC_STATICBL9,136,205,44,8 - LTEXT "Priority:",IDC_STATICBL8,136,195,26,8 - LTEXT "I/O priority:",IDC_STATICBL10,136,216,39,8 - LTEXT "Page priority:",IDC_STATICBL11,136,227,44,8 - LTEXT "State:",IDC_STATICBL7,7,195,21,8 - LTEXT "N/A",IDC_STATE,41,195,85,8,SS_ENDELLIPSIS - LTEXT "N/A",IDC_PRIORITY,195,195,58,8 - LTEXT "N/A",IDC_BASEPRIORITY,195,205,58,8 - LTEXT "N/A",IDC_IOPRIORITY,195,216,58,8 - LTEXT "N/A",IDC_PAGEPRIORITY,195,227,58,8 - CONTROL "",IDC_LIST,"PhTreeNew",WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP | 0x22,7,7,246,156,WS_EX_CLIENTEDGE - LTEXT "Ideal processor:",IDC_STATICBL12,136,239,53,8 - LTEXT "N/A",IDC_IDEALPROCESSOR,195,239,58,8 -END - -IDD_PROCHANDLES DIALOGEX 0, 0, 260, 260 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Handles" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - CONTROL "Hide unnamed handles",IDC_HIDEUNNAMEDHANDLES,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,3,5,88,10 - CONTROL "",IDC_LIST,"PhTreeNew",WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP | 0x2,2,19,256,239,WS_EX_CLIENTEDGE - EDITTEXT IDC_HANDLESEARCH,114,3,144,14,ES_AUTOHSCROLL -END - -IDD_PROCENVIRONMENT DIALOGEX 0, 0, 260, 260 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Environment" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,7,246,227 - PUSHBUTTON "New...",IDC_NEW,93,239,50,14 - PUSHBUTTON "Edit...",IDC_EDIT,148,239,50,14 - PUSHBUTTON "Delete",IDC_DELETE,203,239,50,14 -END - -IDD_THRDSTACK DIALOGEX 0, 0, 261, 228 -STYLE DS_SETFONT | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME -CAPTION "Thread Stack" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,7,7,247,196 - PUSHBUTTON "Copy",IDC_COPY,96,207,50,14 - PUSHBUTTON "Refresh",IDC_REFRESH,150,207,50,14 - PUSHBUTTON "Close",IDOK,204,207,50,14 -END - -IDD_ABOUT DIALOGEX 0, 0, 270, 195 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "About" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - ICON IDI_PROCESSHACKER,IDC_STATIC,16,15,20,20 - LTEXT "Process Hacker",IDC_ABOUT_NAME,45,14,192,8 - LTEXT "Licensed under the GNU GPL, v3.",IDC_STATIC,45,27,193,8 - LTEXT "Copyright (c) 2008-2017 Wen Jia Liu (wj32)",IDC_STATIC,15,40,140,8 - CONTROL "Credits.",IDC_CREDITS,"SysLink",WS_TABSTOP,15,55,248,115 - CONTROL "Process Hacker on SourceForge.net",IDC_LINK_SF, - "SysLink",WS_TABSTOP,7,177,130,11 - PUSHBUTTON "Diagnostics",IDC_DIAGNOSTICS,160,174,50,14 - DEFPUSHBUTTON "OK",IDOK,213,174,50,14 -END - -IDD_SRVLIST DIALOGEX 0, 0, 237, 201 -STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_SYSMENU -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,0,0,237,141 - EDITTEXT IDC_DESCRIPTION,0,144,237,40,ES_MULTILINE | ES_READONLY | NOT WS_BORDER - PUSHBUTTON "&Start",IDC_START,134,187,50,14 - PUSHBUTTON "&Pause",IDC_PAUSE,187,187,50,14 -END - -IDD_SRVGENERAL DIALOGEX 0, 0, 282, 183 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "General" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - EDITTEXT IDC_DESCRIPTION,7,7,268,45,ES_MULTILINE | ES_READONLY | WS_VSCROLL - LTEXT "Type:",IDC_STATIC,7,57,20,8 - COMBOBOX IDC_TYPE,30,56,110,65,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LTEXT "Start type:",IDC_STATIC,147,57,38,8 - COMBOBOX IDC_STARTTYPE,188,56,87,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LTEXT "Error control:",IDC_STATIC,7,75,47,8 - COMBOBOX IDC_ERRORCONTROL,58,73,82,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LTEXT "Group:",IDC_STATIC,147,75,23,8 - EDITTEXT IDC_GROUP,173,74,102,12,ES_AUTOHSCROLL - LTEXT "Binary path:",IDC_STATIC,7,92,40,8 - EDITTEXT IDC_BINARYPATH,58,91,163,12,ES_AUTOHSCROLL - PUSHBUTTON "Browse...",IDC_BROWSE,225,90,50,14 - LTEXT "User account:",IDC_STATIC,7,110,46,8 - EDITTEXT IDC_USERACCOUNT,58,108,217,12,ES_AUTOHSCROLL - LTEXT "Password:",IDC_STATIC,7,127,34,8 - EDITTEXT IDC_PASSWORD,58,125,204,12,ES_PASSWORD | ES_AUTOHSCROLL - CONTROL "",IDC_PASSWORDCHECK,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,266,126,9,10 - LTEXT "Service DLL:",IDC_STATIC,7,144,48,8 - EDITTEXT IDC_SERVICEDLL,58,142,217,12,ES_AUTOHSCROLL | ES_READONLY - CONTROL "Delayed start",IDC_DELAYEDSTART,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,158,59,10 -END - -IDD_HNDLGENERAL DIALOGEX 0, 0, 260, 181 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "General" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - GROUPBOX "Basic information",IDC_BASICINFORMATION,7,7,246,67 - LTEXT "Name:",IDC_STATIC,14,19,22,8 - EDITTEXT IDC_NAME,40,19,206,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER - LTEXT "Type:",IDC_STATIC,14,32,20,8 - EDITTEXT IDC_TYPE,40,32,206,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER - LTEXT "Object address:",IDC_STATIC,14,44,53,8 - EDITTEXT IDC_ADDRESS,71,44,175,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER - LTEXT "Granted access:",IDC_STATIC,14,56,54,8 - EDITTEXT IDC_GRANTED_ACCESS,71,56,175,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER - GROUPBOX "References",IDC_STATIC,7,78,119,39 - LTEXT "References:",IDC_STATIC,14,90,40,8 - LTEXT "Static",IDC_REFERENCES,58,90,41,8 - LTEXT "Handles:",IDC_STATIC,14,101,29,8 - LTEXT "Static",IDC_HANDLES,58,101,40,8 - GROUPBOX "Quota charges",IDC_STATIC,131,78,122,39 - LTEXT "Paged:",IDC_STATIC,138,89,24,8 - LTEXT "Static",IDC_PAGED,182,89,39,8 - LTEXT "Non-paged:",IDC_STATIC,138,100,39,8 - LTEXT "Static",IDC_NONPAGED,182,100,39,8 -END - -IDD_INFORMATION DIALOGEX 0, 0, 317, 184 -STYLE DS_SETFONT | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME -CAPTION "Information" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - EDITTEXT IDC_TEXT,7,7,303,152,ES_MULTILINE | ES_READONLY | WS_VSCROLL - PUSHBUTTON "Save...",IDC_SAVE,154,163,50,14 - PUSHBUTTON "Copy",IDC_COPY,207,163,50,14 - DEFPUSHBUTTON "Close",IDOK,260,163,50,14 -END - -IDD_FINDOBJECTS DIALOGEX 0, 0, 357, 233 -STYLE DS_SETFONT | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME -CAPTION "Find Handles or DLLs" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "Filter:",IDC_STATIC,7,9,20,8 - EDITTEXT IDC_FILTER,32,8,224,14,ES_AUTOHSCROLL - PUSHBUTTON "Find",IDOK,300,7,50,14 - CONTROL "",IDC_RESULTS,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,26,343,200 - CONTROL "&Regex",IDC_REGEX,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,261,9,36,10 -END - -IDD_OBJTOKEN DIALOGEX 0, 0, 260, 260 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Token" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "User:",IDC_STATIC,7,7,18,8 - EDITTEXT IDC_USER,48,7,205,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER - LTEXT "User SID:",IDC_STATIC,7,18,32,8 - EDITTEXT IDC_USERSID,48,18,205,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER - LTEXT "Session:",IDC_STATIC,7,29,28,8 - LTEXT "Unknown",IDC_SESSIONID,38,29,30,8 - LTEXT "Elevated:",IDC_STATIC,85,29,32,8 - LTEXT "Unknown",IDC_ELEVATED,120,29,30,8 - LTEXT "Virtualized:",IDC_STATIC,169,29,36,8 - LTEXT "Unknown",IDC_VIRTUALIZED,209,29,44,8 - LTEXT "App container SID:",IDC_STATIC,7,40,62,8 - EDITTEXT IDC_APPCONTAINERSID,75,40,178,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER - CONTROL "",IDC_GROUPS,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,53,246,112 - CONTROL "",IDC_PRIVILEGES,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,168,246,57 - LTEXT "To view capabilities, claims and other attributes, click Advanced.",IDC_INSTRUCTION,7,228,206,8 - PUSHBUTTON "Integrity",IDC_INTEGRITY,149,239,50,14 - PUSHBUTTON "Advanced",IDC_ADVANCED,203,239,50,14 -END - -IDD_HIDDENPROCESSES DIALOGEX 0, 0, 337, 221 -STYLE DS_SETFONT | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME -CAPTION "Hidden Processes" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "Processes highlighted red are hidden while those highlighted grey have terminated.",IDC_INTRO,7,7,323,12 - CONTROL "",IDC_PROCESSES,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,23,323,162 - RTEXT "",IDC_DESCRIPTION,7,187,323,11 - COMBOBOX IDC_METHOD,7,201,73,30,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP - PUSHBUTTON "Terminate",IDC_TERMINATE,115,200,50,14 - PUSHBUTTON "Save...",IDC_SAVE,170,200,50,14 - PUSHBUTTON "&Scan",IDC_SCAN,225,200,50,14 - DEFPUSHBUTTON "Close",IDOK,280,200,50,14 -END - -IDD_RUNAS DIALOGEX 0, 0, 278, 127 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Run As" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "Enter the command to start as the specified user.",IDC_STATIC,7,7,160,8 - LTEXT "Program:",IDC_STATIC,7,23,30,8 - EDITTEXT IDC_PROGRAM,53,21,163,12,ES_AUTOHSCROLL - PUSHBUTTON "Browse...",IDC_BROWSE,221,20,50,14 - LTEXT "User name:",IDC_STATIC,7,40,38,8 - COMBOBOX IDC_USERNAME,53,38,123,12,CBS_DROPDOWN | CBS_AUTOHSCROLL | CBS_SORT | WS_VSCROLL | WS_TABSTOP - LTEXT "Type:",IDC_STATIC,183,40,20,8 - COMBOBOX IDC_TYPE,207,38,64,30,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP - LTEXT "Password:",IDC_STATIC,7,56,34,8 - EDITTEXT IDC_PASSWORD,53,55,123,12,ES_PASSWORD | ES_AUTOHSCROLL - CONTROL "Toggle elevation",IDC_TOGGLEELEVATION,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,183,56,69,10 - LTEXT "Session ID:",IDC_STATIC,7,73,37,8 - EDITTEXT IDC_SESSIONID,53,72,104,12,ES_AUTOHSCROLL | ES_NUMBER - PUSHBUTTON "...",IDC_SESSIONS,161,71,16,14 - LTEXT "Desktop:",IDC_STATIC,7,90,30,8 - EDITTEXT IDC_DESKTOP,53,88,104,12,ES_AUTOHSCROLL - PUSHBUTTON "...",IDC_DESKTOPS,161,87,16,14 - DEFPUSHBUTTON "OK",IDOK,168,106,50,14 - PUSHBUTTON "Cancel",IDCANCEL,221,106,50,14 -END - -IDD_PROGRESS DIALOGEX 0, 0, 216, 62 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Progress" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - PUSHBUTTON "Cancel",IDCANCEL,159,41,50,14 - CONTROL "",IDC_PROGRESS,"msctls_progress32",0x0,7,23,202,14 - LTEXT "Please wait...",IDC_PROGRESSTEXT,7,7,202,12 -END - -IDD_PAGEFILES DIALOGEX 0, 0, 322, 162 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Pagefiles" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,7,7,308,128 - PUSHBUTTON "Refresh",IDC_REFRESH,211,141,50,14 - DEFPUSHBUTTON "Close",IDOK,265,141,50,14 -END - -IDD_TOKGENERAL DIALOGEX 0, 0, 270, 228 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "General" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - GROUPBOX "Token",IDC_STATIC,7,7,256,132 - LTEXT "User:",IDC_STATIC,15,19,18,8 - EDITTEXT IDC_USER,71,17,185,12,ES_AUTOHSCROLL | ES_READONLY - LTEXT "User SID:",IDC_STATIC,15,36,32,8 - EDITTEXT IDC_USERSID,71,34,185,12,ES_AUTOHSCROLL | ES_READONLY - LTEXT "Owner:",IDC_STATIC,15,53,25,8 - EDITTEXT IDC_OWNER,71,51,185,12,ES_AUTOHSCROLL | ES_READONLY - LTEXT "Primary group:",IDC_STATIC,15,70,49,8 - EDITTEXT IDC_PRIMARYGROUP,71,68,185,12,ES_AUTOHSCROLL | ES_READONLY - LTEXT "Session ID:",IDC_STATIC,15,87,37,8 - EDITTEXT IDC_SESSIONID,71,85,88,12,ES_AUTOHSCROLL | ES_READONLY - LTEXT "Elevated:",IDC_STATIC,15,104,32,8 - EDITTEXT IDC_ELEVATED,71,102,117,12,ES_AUTOHSCROLL | ES_READONLY - LTEXT "Virtualization:",IDC_STATIC,15,121,44,8 - EDITTEXT IDC_VIRTUALIZATION,71,119,185,12,ES_AUTOHSCROLL | ES_READONLY - PUSHBUTTON "Linked token",IDC_LINKEDTOKEN,193,101,63,14 - GROUPBOX "Source",IDC_STATIC,7,143,256,47 - LTEXT "Name:",IDC_STATIC,15,155,22,8 - EDITTEXT IDC_SOURCENAME,71,153,185,12,ES_AUTOHSCROLL | ES_READONLY - LTEXT "LUID:",IDC_STATIC,15,173,19,8 - EDITTEXT IDC_SOURCELUID,71,171,185,12,ES_AUTOHSCROLL | ES_READONLY -END - -IDD_TOKADVANCED DIALOGEX 0, 0, 236, 186 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Advanced" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "Type:",IDC_STATIC,7,8,20,8 - EDITTEXT IDC_TYPE,81,7,116,12,ES_AUTOHSCROLL | ES_READONLY - LTEXT "Impersonation level:",IDC_STATIC,7,26,68,8 - EDITTEXT IDC_IMPERSONATIONLEVEL,81,24,116,12,ES_AUTOHSCROLL | ES_READONLY - LTEXT "Token LUID:",IDC_STATIC,7,43,55,8 - EDITTEXT IDC_TOKENLUID,81,41,116,12,ES_AUTOHSCROLL | ES_READONLY - LTEXT "Authentication LUID:",IDC_STATIC,7,61,68,8 - EDITTEXT IDC_AUTHENTICATIONLUID,81,59,116,12,ES_AUTOHSCROLL | ES_READONLY - LTEXT "Memory used:",IDC_STATIC,7,78,47,8 - EDITTEXT IDC_MEMORYUSED,81,76,116,12,ES_AUTOHSCROLL | ES_READONLY - LTEXT "Memory available:",IDC_STATIC,7,95,60,8 - EDITTEXT IDC_MEMORYAVAILABLE,81,93,116,12,ES_AUTOHSCROLL | ES_READONLY -END - -IDD_OBJJOB DIALOGEX 0, 0, 260, 260 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Job" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "Name:",IDC_STATIC,7,9,22,8 - EDITTEXT IDC_NAME,35,8,164,12,ES_AUTOHSCROLL - PUSHBUTTON "Terminate",IDC_TERMINATE,203,7,50,14 - LTEXT "Processes in job:",IDC_STATIC,7,25,55,8 - CONTROL "",IDC_PROCESSES,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_SORTASCENDING | LVS_ALIGNLEFT | LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,7,38,246,62 - PUSHBUTTON "Add...",IDC_ADD,203,103,50,14 - LTEXT "Limits:",IDC_STATIC,7,117,21,8 - CONTROL "",IDC_LIMITS,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_SORTASCENDING | LVS_ALIGNLEFT | LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,7,129,246,107 - PUSHBUTTON "Advanced",IDC_ADVANCED,203,239,50,14 -END - -IDD_OBJEVENT DIALOGEX 0, 0, 186, 76 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Event" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "Type:",IDC_STATIC,7,7,20,8 - LTEXT "Unknown",IDC_TYPE,42,7,137,8 - LTEXT "Signaled:",IDC_STATIC,7,18,30,8 - LTEXT "Unknown",IDC_SIGNALED,42,18,137,8 - PUSHBUTTON "Set",IDC_SET,7,34,50,14 - PUSHBUTTON "Reset",IDC_RESET,61,34,50,14 - PUSHBUTTON "Pulse",IDC_PULSE,115,34,50,14 -END - -IDD_OBJMUTANT DIALOGEX 0, 0, 186, 76 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Mutant" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "Count:",IDC_STATIC,7,7,23,8 - LTEXT "Unknown",IDC_COUNT,55,7,124,8 - LTEXT "Abandoned:",IDC_STATIC,7,18,40,8 - LTEXT "Unknown",IDC_ABANDONED,55,18,124,8 - LTEXT "Owner:",IDC_OWNERLABEL,7,29,25,8 - LTEXT "Unknown",IDC_OWNER,55,29,124,8 -END - -IDD_OBJSEMAPHORE DIALOGEX 0, 0, 186, 76 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Semaphore" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "Current count:",IDC_STATIC,7,7,50,8 - LTEXT "Unknown",IDC_CURRENTCOUNT,66,7,113,8 - LTEXT "Maximum count:",IDC_STATIC,7,18,54,8 - LTEXT "Unknown",IDC_MAXIMUMCOUNT,66,18,113,8 - PUSHBUTTON "Acquire",IDC_ACQUIRE,7,34,50,14 - PUSHBUTTON "Release",IDC_RELEASE,61,34,50,14 -END - -IDD_OBJTIMER DIALOGEX 0, 0, 186, 76 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Timer" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "Signaled:",-1,7,7,30,8 - LTEXT "Unknown",IDC_SIGNALED,42,7,137,8 - PUSHBUTTON "Cancel",IDC_CANCEL,7,19,50,14 -END - -IDD_JOBSTATISTICS DIALOGEX 0, 0, 259, 186 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Statistics" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - GROUPBOX "General",IDC_STATIC,7,7,133,47 - LTEXT "Active processes",IDC_STATIC,15,18,55,8 - RTEXT "Static",IDC_ZACTIVEPROCESSES_V,99,18,37,8,SS_ENDELLIPSIS - LTEXT "Total processes",IDC_STATIC,15,28,51,8 - RTEXT "Static",IDC_ZTOTALPROCESSES_V,95,29,41,8,SS_ENDELLIPSIS - LTEXT "Terminated processes",IDC_STATIC,15,39,71,8 - RTEXT "Static",IDC_ZTERMINATEDPROCESSES_V,99,39,37,8,SS_ENDELLIPSIS - GROUPBOX "Time",IDC_STATIC,7,57,133,57 - LTEXT "User time",IDC_STATIC,15,68,32,8 - LTEXT "Kernel time",IDC_STATIC,15,79,38,8 - LTEXT "User time (period)",IDC_STATIC,15,89,60,8 - LTEXT "Kernel time (period)",IDC_STATIC,15,99,65,8 - RTEXT "Static",IDC_ZUSERTIME_V,83,68,53,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZKERNELTIME_V,85,79,51,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZUSERTIMEPERIOD_V,87,89,49,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZKERNELTIMEPERIOD_V,87,99,49,8,SS_ENDELLIPSIS - GROUPBOX "Memory",IDC_STATIC,7,118,133,48 - LTEXT "Page faults",IDC_STATIC,15,129,38,8 - LTEXT "Peak process usage",IDC_STATIC,15,140,65,8 - LTEXT "Peak job usage",IDC_STATIC,15,151,52,8 - RTEXT "Static",IDC_ZPAGEFAULTS_V,86,129,50,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZPEAKPROCESSUSAGE_V,85,140,51,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZPEAKJOBUSAGE_V,86,151,50,8,SS_ENDELLIPSIS - GROUPBOX "I/O",IDC_STATIC,146,7,106,75 - LTEXT "Reads",IDC_STATIC,152,17,21,8 - LTEXT "Read bytes",IDC_STATIC,152,27,38,8 - LTEXT "Writes",IDC_STATIC,152,37,22,8 - LTEXT "Write bytes",IDC_STATIC,152,47,38,8 - LTEXT "Other",IDC_STATIC,152,57,20,8 - LTEXT "Other bytes",IDC_STATIC,152,67,40,8 - RTEXT "Static",IDC_ZIOREADS_V,200,17,47,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZIOREADBYTES_V,200,27,47,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZIOWRITES_V,200,37,47,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZIOWRITEBYTES_V,200,47,47,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZIOOTHER_V,200,57,47,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZIOOTHERBYTES_V,200,67,47,8,SS_ENDELLIPSIS -END - -IDD_OBJEVENTPAIR DIALOGEX 0, 0, 186, 76 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Event Pair" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - PUSHBUTTON "Set low",IDC_SETLOW,7,7,50,14 - PUSHBUTTON "Set high",IDC_SETHIGH,61,7,50,14 -END - -IDD_OBJSECTION DIALOGEX 0, 0, 255, 76 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Section" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "Type:",IDC_STATIC,7,7,20,8 - LTEXT "Unknown",IDC_TYPE,43,7,205,8 - LTEXT "Size:",IDC_STATIC,7,18,16,8 - LTEXT "Unknown",IDC_SIZE_,43,18,205,8 - LTEXT "File:",IDC_STATIC,7,29,14,8 - EDITTEXT IDC_FILE,43,29,205,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER -END - -IDD_AFFINITY DIALOGEX 0, 0, 279, 227 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Affinity" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - DEFPUSHBUTTON "OK",IDOK,169,206,50,14 - PUSHBUTTON "Cancel",IDCANCEL,222,206,50,14 - LTEXT "Affinity controls which CPUs threads are allowed to execute on.",IDC_STATIC,7,7,265,11 - CONTROL "CPU 0",IDC_CPU0,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,21,35,10 - CONTROL "CPU 1",IDC_CPU1,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,33,35,10 - CONTROL "CPU 2",IDC_CPU2,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,44,35,10 - CONTROL "CPU 3",IDC_CPU3,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,56,35,10 - CONTROL "CPU 4",IDC_CPU4,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,67,35,10 - CONTROL "CPU 5",IDC_CPU5,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,78,35,10 - CONTROL "CPU 6",IDC_CPU6,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,89,35,10 - CONTROL "CPU 7",IDC_CPU7,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,100,35,10 - CONTROL "CPU 8",IDC_CPU8,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,111,35,10 - CONTROL "CPU 9",IDC_CPU9,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,122,35,10 - CONTROL "CPU 10",IDC_CPU10,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,134,39,10 - CONTROL "CPU 11",IDC_CPU11,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,145,39,10 - CONTROL "CPU 12",IDC_CPU12,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,156,39,10 - CONTROL "CPU 13",IDC_CPU13,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,167,39,10 - CONTROL "CPU 14",IDC_CPU14,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,178,39,10 - CONTROL "CPU 15",IDC_CPU15,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,190,39,10 - CONTROL "CPU 16",IDC_CPU16,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,79,21,39,10 - CONTROL "CPU 17",IDC_CPU17,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,79,33,39,10 - CONTROL "CPU 18",IDC_CPU18,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,79,44,39,10 - CONTROL "CPU 19",IDC_CPU19,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,79,56,39,10 - CONTROL "CPU 20",IDC_CPU20,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,79,67,39,10 - CONTROL "CPU 21",IDC_CPU21,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,79,78,39,10 - CONTROL "CPU 22",IDC_CPU22,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,79,89,39,10 - CONTROL "CPU 23",IDC_CPU23,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,79,100,39,10 - CONTROL "CPU 24",IDC_CPU24,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,79,111,39,10 - CONTROL "CPU 25",IDC_CPU25,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,79,122,39,10 - CONTROL "CPU 26",IDC_CPU26,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,79,134,39,10 - CONTROL "CPU 27",IDC_CPU27,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,79,145,39,10 - CONTROL "CPU 28",IDC_CPU28,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,79,156,39,10 - CONTROL "CPU 29",IDC_CPU29,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,79,167,39,10 - CONTROL "CPU 30",IDC_CPU30,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,79,178,39,10 - CONTROL "CPU 31",IDC_CPU31,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,79,190,39,10 - CONTROL "CPU 32",IDC_CPU32,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,150,21,39,10 - CONTROL "CPU 33",IDC_CPU33,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,150,33,39,10 - CONTROL "CPU 34",IDC_CPU34,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,150,44,39,10 - CONTROL "CPU 35",IDC_CPU35,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,150,56,39,10 - CONTROL "CPU 36",IDC_CPU36,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,150,67,39,10 - CONTROL "CPU 37",IDC_CPU37,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,150,78,39,10 - CONTROL "CPU 38",IDC_CPU38,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,150,89,39,10 - CONTROL "CPU 39",IDC_CPU39,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,150,100,39,10 - CONTROL "CPU 40",IDC_CPU40,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,150,111,39,10 - CONTROL "CPU 41",IDC_CPU41,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,150,122,39,10 - CONTROL "CPU 42",IDC_CPU42,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,150,134,39,10 - CONTROL "CPU 43",IDC_CPU43,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,150,145,39,10 - CONTROL "CPU 44",IDC_CPU44,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,150,156,39,10 - CONTROL "CPU 45",IDC_CPU45,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,150,167,39,10 - CONTROL "CPU 46",IDC_CPU46,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,150,178,39,10 - CONTROL "CPU 47",IDC_CPU47,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,150,190,39,10 - CONTROL "CPU 48",IDC_CPU48,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,224,21,39,10 - CONTROL "CPU 49",IDC_CPU49,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,224,33,39,10 - CONTROL "CPU 50",IDC_CPU50,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,224,44,39,10 - CONTROL "CPU 51",IDC_CPU51,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,224,56,39,10 - CONTROL "CPU 52",IDC_CPU52,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,224,67,39,10 - CONTROL "CPU 53",IDC_CPU53,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,224,78,39,10 - CONTROL "CPU 54",IDC_CPU54,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,224,89,39,10 - CONTROL "CPU 55",IDC_CPU55,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,224,100,39,10 - CONTROL "CPU 56",IDC_CPU56,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,224,111,39,10 - CONTROL "CPU 57",IDC_CPU57,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,224,122,39,10 - CONTROL "CPU 58",IDC_CPU58,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,224,134,39,10 - CONTROL "CPU 59",IDC_CPU59,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,224,145,39,10 - CONTROL "CPU 60",IDC_CPU60,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,224,156,39,10 - CONTROL "CPU 61",IDC_CPU61,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,224,167,39,10 - CONTROL "CPU 62",IDC_CPU62,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,224,178,39,10 - CONTROL "CPU 63",IDC_CPU63,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,224,190,39,10 - PUSHBUTTON "Select all",IDC_SELECTALL,7,206,50,14 - PUSHBUTTON "Deselect all",IDC_DESELECTALL,60,206,50,14 -END - -IDD_SYSINFO DIALOGEX 0, 0, 423, 247 -STYLE DS_SETFONT | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME -EXSTYLE WS_EX_APPWINDOW -CAPTION "System Information" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "Click a graph to view details for that section.",IDC_INSTRUCTION,7,228,144,8 - CONTROL "Always on &top",IDC_ALWAYSONTOP,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,297,228,63,10 - DEFPUSHBUTTON "Close",IDOK,366,226,50,14 -END - -IDD_EDITMESSAGE DIALOGEX 0, 0, 282, 163 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Message" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "Title:",IDC_STATIC,7,8,17,8 - EDITTEXT IDC_TITLE,52,7,223,12,ES_AUTOHSCROLL - LTEXT "Text:",IDC_STATIC,7,24,18,8 - EDITTEXT IDC_TEXT,52,23,223,79,ES_MULTILINE | ES_AUTOVSCROLL | ES_WANTRETURN | WS_VSCROLL - LTEXT "Icon:",IDC_STATIC,7,107,18,8 - COMBOBOX IDC_TYPE,52,105,80,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LTEXT "Timeout (s):",IDC_STATIC,7,123,40,8 - EDITTEXT IDC_TIMEOUT,52,122,43,12,ES_AUTOHSCROLL - DEFPUSHBUTTON "OK",IDOK,172,142,50,14 - PUSHBUTTON "Cancel",IDCANCEL,225,142,50,14 -END - -IDD_SESSION DIALOGEX 0, 0, 201, 149 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Session Properties" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - DEFPUSHBUTTON "Close",IDOK,144,128,50,14 - LTEXT "User name:",IDC_STATIC,7,7,38,8 - LTEXT "Session ID:",IDC_STATIC,7,18,37,8 - LTEXT "State:",IDC_STATIC,7,29,21,8 - LTEXT "Client name:",IDC_STATIC,7,84,41,8 - LTEXT "Client address:",IDC_STATIC,7,95,49,8 - LTEXT "Client display:",IDC_STATIC,7,106,46,8 - LTEXT "N/A",IDC_USERNAME,66,7,128,8 - LTEXT "N/A",IDC_SESSIONID,66,18,128,8 - LTEXT "N/A",IDC_STATE,66,29,128,8 - LTEXT "N/A",IDC_CLIENTNAME,66,84,128,8 - LTEXT "N/A",IDC_CLIENTADDRESS,66,95,128,8 - LTEXT "N/A",IDC_CLIENTDISPLAY,66,106,128,8 - LTEXT "Logon time:",IDC_STATIC,7,40,38,8 - LTEXT "N/A",IDC_LOGONTIME,66,40,128,8 - LTEXT "Connect time:",IDC_STATIC,7,51,46,8 - LTEXT "Disconnect time:",IDC_STATIC,7,62,54,8 - LTEXT "Last input time:",IDC_STATIC,7,73,50,8 - LTEXT "N/A",IDC_CONNECTTIME,66,51,128,8 - LTEXT "N/A",IDC_DISCONNECTTIME,66,62,128,8 - LTEXT "N/A",IDC_LASTINPUTTIME,66,74,128,8 -END - -IDD_PROCMEMORY DIALOGEX 0, 0, 260, 260 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Memory" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - PUSHBUTTON "Strings...",IDC_STRINGS,150,7,50,14 - PUSHBUTTON "Refresh",IDC_REFRESH,203,7,50,14 - CONTROL "",IDC_LIST,"PhTreeNew",WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP | 0xa,7,26,246,227,WS_EX_CLIENTEDGE - CONTROL "Hide free regions",IDC_HIDEFREEREGIONS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,9,71,10 -END - -IDD_CHOOSE DIALOGEX 0, 0, 199, 73 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Dialog" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "Text:",IDC_MESSAGE,7,7,185,8,SS_ENDELLIPSIS - COMBOBOX IDC_CHOICE,7,20,185,30,CBS_DROPDOWNLIST | CBS_AUTOHSCROLL | NOT WS_VISIBLE | WS_VSCROLL | WS_TABSTOP - CONTROL "Option",IDC_OPTION,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,39,185,10 - DEFPUSHBUTTON "OK",IDOK,89,52,50,14 - PUSHBUTTON "Cancel",IDCANCEL,142,52,50,14 - COMBOBOX IDC_CHOICEUSER,7,20,185,30,CBS_DROPDOWN | CBS_AUTOHSCROLL | CBS_SORT | NOT WS_VISIBLE | WS_VSCROLL | WS_TABSTOP - EDITTEXT IDC_CHOICESIMPLE,7,20,185,13,ES_PASSWORD | ES_AUTOHSCROLL | NOT WS_VISIBLE -END - -IDD_OPTGENERAL DIALOGEX 0, 0, 250, 154 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "General" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "Search engine:",IDC_STATIC,7,8,49,8 - EDITTEXT IDC_SEARCHENGINE,61,7,182,12,ES_AUTOHSCROLL - LTEXT "PE viewer:",IDC_STATIC,7,23,35,8 - EDITTEXT IDC_PEVIEWER,61,22,182,12,ES_AUTOHSCROLL - LTEXT "Max. size unit:",IDC_STATIC,7,38,49,8 - COMBOBOX IDC_MAXSIZEUNIT,61,37,39,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LTEXT "Icon processes:",IDC_STATIC,7,55,52,8 - EDITTEXT IDC_ICONPROCESSES,61,53,40,12,ES_AUTOHSCROLL | ES_NUMBER - CONTROL "Allow only one instance",IDC_ALLOWONLYONEINSTANCE, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,71,91,10 - CONTROL "Hide when closed",IDC_HIDEONCLOSE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,83,71,10 - CONTROL "Hide when minimized",IDC_HIDEONMINIMIZE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,95,81,10 - CONTROL "Start hidden",IDC_STARTHIDDEN,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,119,55,10 - CONTROL "Collapse services on start",IDC_COLLAPSESERVICES,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,122,71,98,10 - CONTROL "Single-click tray icons",IDC_ICONSINGLECLICK,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,122,83,83,10 - CONTROL "Icon click toggles visibility",IDC_ICONTOGGLESVISIBILITY, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,122,95,97,10 - CONTROL "Enable plugins",IDC_ENABLEPLUGINS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,122,107,61,10 - PUSHBUTTON "Font...",IDC_FONT,7,133,50,14 - CONTROL "Start when I log on",IDC_STARTATLOGON,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,107,77,10 -END - -IDD_OPTHIGHLIGHTING DIALOGEX 0, 0, 250, 174 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Highlighting" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "Highlighting duration:",IDC_STATIC,7,8,70,8 - EDITTEXT IDC_HIGHLIGHTINGDURATION,79,7,40,12,ES_AUTOHSCROLL | ES_NUMBER - LTEXT "New objects:",IDC_STATIC,7,25,44,8 - CONTROL "New objects",IDC_NEWOBJECTS,"PhColorBox",WS_CLIPSIBLINGS | WS_TABSTOP,57,23,33,13 - LTEXT "Removed objects:",IDC_STATIC,127,25,60,8 - CONTROL "Removed objects",IDC_REMOVEDOBJECTS,"PhColorBox",WS_CLIPSIBLINGS | WS_TABSTOP,193,23,33,13 - CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | LVS_NOCOLUMNHEADER | WS_BORDER | WS_TABSTOP,7,41,236,107 - LTEXT "Double-click an item to change it.",IDC_STATIC,7,156,106,8 - PUSHBUTTON "Enable all",IDC_ENABLEALL,140,153,50,14 - PUSHBUTTON "Disable all",IDC_DISABLEALL,193,153,50,14 -END - -IDD_CHOOSECOLUMNS DIALOGEX 0, 0, 381, 207 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Choose Columns" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "Select the columns that will appear in the list.",IDC_MESSAGE,7,7,367,10 - LTEXT "Inactive columns:",IDC_STATIC,7,21,57,8 - LISTBOX IDC_INACTIVE,7,31,129,150,LBS_SORT | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP - PUSHBUTTON "Show >",IDC_SHOW,139,86,50,14 - PUSHBUTTON "< Hide",IDC_HIDE,139,103,50,14 - LISTBOX IDC_ACTIVE,192,31,129,150,LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP - PUSHBUTTON "Move up",IDC_MOVEUP,324,31,50,14 - PUSHBUTTON "Move down",IDC_MOVEDOWN,324,48,50,14 - DEFPUSHBUTTON "OK",IDOK,272,186,50,14 - PUSHBUTTON "Cancel",IDCANCEL,324,186,50,14 - LTEXT "Active columns:",IDC_STATIC,192,21,51,8 -END - -IDD_NETSTACK DIALOGEX 0, 0, 261, 228 -STYLE DS_SETFONT | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME -CAPTION "Network Stack" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,7,7,247,196 - PUSHBUTTON "Close",IDOK,204,207,50,14 -END - -IDD_CREATESERVICE DIALOGEX 0, 0, 287, 133 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Create Service" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "Name:",IDC_STATIC,7,8,22,8 - EDITTEXT IDC_NAME,61,7,219,12,ES_AUTOHSCROLL - LTEXT "Display name:",IDC_STATIC,7,24,46,8 - EDITTEXT IDC_DISPLAYNAME,61,23,219,12,ES_AUTOHSCROLL - LTEXT "Type:",IDC_STATIC,7,41,20,8 - COMBOBOX IDC_TYPE,61,39,97,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LTEXT "Start type:",IDC_STATIC,7,58,38,8 - COMBOBOX IDC_STARTTYPE,61,56,97,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LTEXT "Error control:",IDC_STATIC,7,75,45,8 - COMBOBOX IDC_ERRORCONTROL,61,73,97,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LTEXT "Binary path:",IDC_STATIC,7,91,40,8 - EDITTEXT IDC_BINARYPATH,61,90,165,12,ES_AUTOHSCROLL - PUSHBUTTON "Browse...",IDC_BROWSE,230,89,50,14 - DEFPUSHBUTTON "OK",IDOK,176,112,50,14 - PUSHBUTTON "Cancel",IDCANCEL,230,112,50,14 -END - -IDD_PROCPERFORMANCE DIALOGEX 0, 0, 260, 260 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Performance" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - GROUPBOX "CPU",IDC_GROUPCPU,7,7,246,74,0,WS_EX_TRANSPARENT - GROUPBOX "Private bytes",IDC_GROUPPRIVATEBYTES,7,86,246,77,0,WS_EX_TRANSPARENT - GROUPBOX "I/O",IDC_GROUPIO,7,164,246,89,0,WS_EX_TRANSPARENT - CONTROL "",IDC_CPU,"PhGraph",WS_CLIPSIBLINGS,105,42,50,14 - CONTROL "",IDC_PRIVATEBYTES,"PhGraph",WS_CLIPSIBLINGS,105,122,50,14 - CONTROL "",IDC_IO,"PhGraph",WS_CLIPSIBLINGS,105,204,50,14 -END - -IDD_PROCSTATISTICS DIALOGEX 0, 0, 260, 260 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Statistics" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - GROUPBOX "CPU",IDC_STATIC,7,7,119,64 - GROUPBOX "I/O",IDC_STATIC,131,7,122,83 - LTEXT "Priority",IDC_STATIC,14,17,24,8 - LTEXT "Cycles",IDC_STATIC,14,27,22,8 - LTEXT "Kernel time",IDC_STATIC,14,37,38,8 - LTEXT "User time",IDC_STATIC,14,47,32,8 - LTEXT "Total time",IDC_STATIC,14,57,34,8 - RTEXT "Static",IDC_ZPRIORITY_V,59,17,61,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZCYCLES_V,43,27,77,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZKERNELTIME_V,59,37,61,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZUSERTIME_V,59,47,61,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZTOTALTIME_V,59,57,61,8,SS_ENDELLIPSIS - GROUPBOX "Memory",IDC_STATIC,7,74,120,128 - LTEXT "Private bytes",IDC_STATIC,14,84,44,8 - LTEXT "Working set",IDC_STATIC,14,136,40,8 - LTEXT "Peak working set",IDC_STATIC,14,178,57,8 - LTEXT "Virtual size",IDC_STATIC,14,105,36,8 - LTEXT "Peak virtual size",IDC_STATIC,14,115,53,8 - LTEXT "Peak private bytes",IDC_STATIC,14,95,61,8 - LTEXT "Page faults",IDC_STATIC,14,125,38,8 - LTEXT "Page priority",IDC_STATIC,14,188,42,8 - RTEXT "Static",IDC_ZPRIVATEBYTES_V,72,84,48,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZWORKINGSET_V,72,136,48,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZPEAKWORKINGSET_V,78,178,42,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZVIRTUALSIZE_V,72,105,48,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZPEAKVIRTUALSIZE_V,72,115,48,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZPEAKPRIVATEBYTES_V,80,95,40,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZPAGEFAULTS_V,72,125,48,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZPAGEPRIORITY_V,72,188,48,8,SS_ENDELLIPSIS - LTEXT "Reads",IDC_STATIC,138,17,21,8 - LTEXT "Read bytes",IDC_STATIC,138,27,38,8 - LTEXT "Writes",IDC_STATIC,138,37,22,8 - LTEXT "Write bytes",IDC_STATIC,138,47,38,8 - LTEXT "Other",IDC_STATIC,138,57,20,8 - LTEXT "Other bytes",IDC_STATIC,138,67,40,8 - LTEXT "I/O priority",IDC_STATIC,138,77,36,8 - RTEXT "Static",IDC_ZIOREADS_V,184,17,63,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZIOREADBYTES_V,184,27,63,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZIOWRITES_V,184,37,63,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZIOWRITEBYTES_V,184,47,63,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZIOOTHER_V,184,57,63,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZIOOTHERBYTES_V,184,67,63,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZIOPRIORITY_V,184,77,63,8,SS_ENDELLIPSIS - GROUPBOX "Other",IDC_STATIC,131,92,122,70 - LTEXT "Handles",IDC_STATIC,138,102,26,8 - LTEXT "GDI handles",IDC_STATIC,138,122,40,8 - LTEXT "USER handles",IDC_STATIC,138,132,46,8 - RTEXT "Static",IDC_ZHANDLES_V,193,102,54,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZGDIHANDLES_V,193,122,54,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZUSERHANDLES_V,193,132,54,8,SS_ENDELLIPSIS - PUSHBUTTON "Details",IDC_DETAILS,137,143,50,14 - LTEXT "Peak handles",IDC_STATIC,138,112,44,8 - RTEXT "Static",IDC_ZPEAKHANDLES_V,192,112,55,8,SS_ENDELLIPSIS - LTEXT "Private WS",IDC_STATIC,22,147,36,8 - LTEXT "Shareable WS",IDC_STATIC,22,157,46,8 - LTEXT "Shared WS",IDC_STATIC,22,167,36,8 - RTEXT "Static",IDC_ZPRIVATEWS_V,78,147,42,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZSHAREABLEWS_V,78,157,42,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZSHAREDWS_V,78,167,42,8,SS_ENDELLIPSIS -END - -IDD_OPTADVANCED DIALOGEX 0, 0, 250, 150 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Advanced" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - CONTROL "Enable warnings",IDC_ENABLEWARNINGS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,7,68,10 - CONTROL "Enable kernel-mode driver",IDC_ENABLEKERNELMODEDRIVER, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,19,99,10 - CONTROL "Hide unnamed handles",IDC_HIDEUNNAMEDHANDLES,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,31,88,10 - CONTROL "Check images for digital signatures and packing",IDC_ENABLESTAGE2, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,43,167,10 - CONTROL "Resolve addresses for network connections",IDC_ENABLENETWORKRESOLVE, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,55,155,10 - CONTROL "Include CPU (and other) usage of children in collapsed processes",IDC_PROPAGATECPUUSAGE, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,67,223,10 - CONTROL "Show tooltips instantly",IDC_ENABLEINSTANTTOOLTIPS, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,79,88,10 - CONTROL "Enable cycle-based CPU usage",IDC_ENABLECYCLECPUUSAGE, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,91,114,10 - CONTROL "Replace Task Manager with Process Hacker",IDC_REPLACETASKMANAGER, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,105,154,10 - PUSHBUTTON "Change...",IDC_CHANGE,161,103,62,14 - LTEXT "History sample count:",IDC_SAMPLECOUNTLABEL,7,121,70,8 - EDITTEXT IDC_SAMPLECOUNT,82,120,39,12,ES_AUTOHSCROLL | ES_NUMBER - CONTROL "Automatic",IDC_SAMPLECOUNTAUTOMATIC,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,126,121,48,10 -END - -IDD_GDIHANDLES DIALOGEX 0, 0, 351, 307 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "GDI Handles" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,7,337,275 - PUSHBUTTON "Refresh",IDC_REFRESH,240,286,50,14 - DEFPUSHBUTTON "Close",IDOK,294,286,50,14 -END - -IDD_LOG DIALOGEX 0, 0, 313, 303 -STYLE DS_SETFONT | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME -EXSTYLE WS_EX_APPWINDOW -CAPTION "Log" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | LVS_OWNERDATA | LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,7,7,299,272 - PUSHBUTTON "Clear",IDC_CLEAR,7,282,50,14 - CONTROL "Auto-scroll",IDC_AUTOSCROLL,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,61,284,50,10 - PUSHBUTTON "Save...",IDC_SAVE,148,282,50,14 - PUSHBUTTON "Copy",IDC_COPY,202,282,50,14 - DEFPUSHBUTTON "Close",IDOK,256,282,50,14 -END - -IDD_OPTSYMBOLS DIALOGEX 0, 0, 250, 75 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Symbols" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "Dbghelp.dll path:",IDC_STATIC,7,9,56,8 - EDITTEXT IDC_DBGHELPPATH,66,8,123,12,ES_AUTOHSCROLL - PUSHBUTTON "Browse...",IDC_BROWSE,193,7,50,14 - LTEXT "Search path:",IDC_STATIC,7,24,42,8 - EDITTEXT IDC_DBGHELPSEARCHPATH,66,23,177,12,ES_AUTOHSCROLL - CONTROL "Undecorate symbols",IDC_UNDECORATESYMBOLS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,38,81,10 -END - -IDD_MEMEDIT DIALOGEX 0, 0, 441, 269 -STYLE DS_SETFONT | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME -EXSTYLE WS_EX_APPWINDOW -CAPTION "Memory" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - CONTROL "",IDC_MEMORY,"PhHexEdit",WS_CLIPSIBLINGS | WS_VSCROLL | WS_TABSTOP,7,7,427,239 - PUSHBUTTON "Re-read",IDC_REREAD,7,248,50,14 - PUSHBUTTON "Write",IDC_WRITE,60,248,50,14 - PUSHBUTTON "Go to...",IDC_GOTO,112,248,50,14 - PUSHBUTTON "Save...",IDC_SAVE,331,248,50,14 - PUSHBUTTON "Close",IDOK,384,248,50,14 - COMBOBOX IDC_BYTESPERROW,164,249,86,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP -END - -IDD_MEMPROTECT DIALOGEX 0, 0, 270, 171 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Memory Protection" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - EDITTEXT IDC_INTRO,7,7,256,122,ES_MULTILINE | ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER - LTEXT "New value:",IDC_STATIC,120,136,37,8 - EDITTEXT IDC_VALUE,161,135,102,12,ES_AUTOHSCROLL - DEFPUSHBUTTON "OK",IDOK,161,150,50,14 - PUSHBUTTON "Cancel",IDCANCEL,213,150,50,14 -END - -IDD_MEMRESULTS DIALOGEX 0, 0, 313, 266 -STYLE DS_SETFONT | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME -CAPTION "Results" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "Results.",IDC_INTRO,7,9,299,8 - CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | LVS_OWNERDATA | LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,7,21,299,221 - PUSHBUTTON "Filter",IDC_FILTER,7,245,50,14 - PUSHBUTTON "Save...",IDC_SAVE,149,245,50,14 - PUSHBUTTON "Copy",IDC_COPY,203,245,50,14 - DEFPUSHBUTTON "Close",IDOK,256,245,50,14 -END - -IDD_MEMSTRING DIALOGEX 0, 0, 241, 86 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "String Search" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "Minimum length:",IDC_STATIC,7,8,54,8 - EDITTEXT IDC_MINIMUMLENGTH,67,7,51,12,ES_AUTOHSCROLL - CONTROL "Detect Unicode",IDC_DETECTUNICODE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,22,65,10 - LTEXT "Search in the following types of memory regions:",IDC_STATIC,7,36,157,8 - CONTROL "Private",IDC_PRIVATE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,49,39,10 - CONTROL "Image",IDC_IMAGE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,55,49,36,10 - CONTROL "Mapped",IDC_MAPPED,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,101,49,41,10 - DEFPUSHBUTTON "OK",IDOK,131,65,50,14 - PUSHBUTTON "Cancel",IDCANCEL,184,65,50,14 -END - -IDD_OPTGRAPHS DIALOGEX 0, 0, 250, 156 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Graphs" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - CONTROL "Show text",IDC_SHOWTEXT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,7,49,10 - CONTROL "Use old colors (black background)",IDC_USEOLDCOLORS, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,19,123,10 - CONTROL "Show commit charge instead of physical memory in summary view",IDC_SHOWCOMMITINSUMMARY, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,31,227,10 - LTEXT "CPU kernel:",IDC_STATIC,7,48,39,8 - CONTROL "CPU kernel",IDC_CPUKERNEL,"PhColorBox",WS_CLIPSIBLINGS | WS_TABSTOP,73,46,33,13 - LTEXT "CPU user:",IDC_STATIC,7,65,34,8 - CONTROL "CPU user",IDC_CPUUSER,"PhColorBox",WS_CLIPSIBLINGS | WS_TABSTOP,73,63,33,13 - LTEXT "I/O R+O:",IDC_STATIC,7,82,32,8 - CONTROL "I/O R+O",IDC_IORO,"PhColorBox",WS_CLIPSIBLINGS | WS_TABSTOP,73,80,33,13 - LTEXT "I/O W:",IDC_STATIC,7,98,23,8 - CONTROL "I/O W",IDC_IOW,"PhColorBox",WS_CLIPSIBLINGS | WS_TABSTOP,73,97,33,13 - LTEXT "Private bytes:",IDC_STATIC,7,115,46,8 - CONTROL "Private bytes",IDC_PRIVATE,"PhColorBox",WS_CLIPSIBLINGS | WS_TABSTOP,73,113,33,13 - LTEXT "Physical memory:",IDC_STATIC,7,131,56,8 - CONTROL "Physical memory",IDC_PHYSICAL,"PhColorBox",WS_CLIPSIBLINGS | WS_TABSTOP,73,129,33,13 -END - -IDD_PLUGINS DIALOGEX 0, 0, 291, 272 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Plugins" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,7,277,119 - GROUPBOX "Plugin",IDC_STATIC,7,129,277,118 - LTEXT "Name:",IDC_STATIC,15,141,22,8 - EDITTEXT IDC_NAME,71,141,104,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER - LTEXT "Internal name:",IDC_STATIC,15,152,49,8 - EDITTEXT IDC_INTERNALNAME,71,152,203,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER - LTEXT "Author:",IDC_STATIC,15,163,26,8 - EDITTEXT IDC_AUTHOR,71,163,203,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER - LTEXT "URL:",IDC_STATIC,15,174,16,8 - EDITTEXT IDC_URL,71,174,174,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER - CONTROL "Open",IDC_OPENURL,"SysLink",WS_TABSTOP,250,174,26,10 - LTEXT "File name:",IDC_STATIC,15,185,34,8 - EDITTEXT IDC_FILENAME,71,185,203,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER - LTEXT "Version:",IDC_STATIC,183,141,27,8 - EDITTEXT IDC_VERSION,215,141,59,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER - LTEXT "Description:",IDC_STATIC,15,196,39,8 - EDITTEXT IDC_DESCRIPTION,14,208,211,34,ES_MULTILINE | ES_READONLY - PUSHBUTTON "Disable",IDC_DISABLE,230,211,50,14 - PUSHBUTTON "Options...",IDC_OPTIONS,230,228,50,14 - PUSHBUTTON "Clean up",IDC_CLEANUP,7,251,50,14 - LTEXT "Changes may require a restart to take effect.",IDC_INSTRUCTION,82,254,148,8,NOT WS_VISIBLE - DEFPUSHBUTTON "Close",IDOK,234,251,50,14 -END - -IDD_HANDLESTATS DIALOGEX 0, 0, 219, 175 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Handle Statistics" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,7,205,143 - DEFPUSHBUTTON "Close",IDOK,162,154,50,14 -END - -IDD_PROCRECORD DIALOGEX 0, 0, 260, 202 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Process Record" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "Name:",IDC_STATIC,7,9,22,8 - EDITTEXT IDC_PROCESSNAME,39,9,214,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER - LTEXT "Parent:",IDC_STATIC,7,21,25,8 - EDITTEXT IDC_PARENT,39,21,214,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER - GROUPBOX "File",IDC_FILE,7,38,246,79 - ICON "",IDC_FILEICON,14,49,20,20 - EDITTEXT IDC_NAME,44,48,182,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER - EDITTEXT IDC_COMPANYNAME,44,60,183,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER - LTEXT "Version:",IDC_STATIC,15,72,27,8 - EDITTEXT IDC_VERSION,44,72,183,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER - LTEXT "Image file name:",IDC_STATIC,15,86,56,8 - EDITTEXT IDC_FILENAME,15,96,211,12,ES_AUTOHSCROLL | ES_READONLY - PUSHBUTTON "Open",IDC_OPENFILENAME,230,95,17,15,BS_ICON - LTEXT "Command line:",IDC_STATIC,7,123,50,8 - EDITTEXT IDC_CMDLINE,65,121,188,12,ES_AUTOHSCROLL | ES_READONLY - LTEXT "Started:",IDC_STATIC,7,139,28,8 - EDITTEXT IDC_STARTED,65,137,188,12,ES_AUTOHSCROLL | ES_READONLY - LTEXT "Terminated:",IDC_STATIC,7,155,40,8 - EDITTEXT IDC_TERMINATED,65,153,188,12,ES_AUTOHSCROLL | ES_READONLY - LTEXT "Session ID:",IDC_STATIC,7,170,37,8 - LTEXT "Static",IDC_SESSIONID,50,170,19,8 - PUSHBUTTON "Properties",IDC_PROPERTIES,150,181,50,14 - DEFPUSHBUTTON "Close",IDOK,203,181,50,14 -END - -IDD_CHOOSEPROCESS DIALOGEX 0, 0, 317, 239 -STYLE DS_SETFONT | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME -CAPTION "Select a Process" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "Select a process from the list below.",IDC_MESSAGE,7,7,303,8,SS_ENDELLIPSIS - CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,21,303,193 - PUSHBUTTON "Refresh",IDC_REFRESH,7,218,50,14 - DEFPUSHBUTTON "OK",IDOK,205,218,50,14 - PUSHBUTTON "Cancel",IDCANCEL,260,218,50,14 -END - -IDD_PROCSERVICES DIALOGEX 0, 0, 260, 261 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Services" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "Services",IDC_SERVICES_LAYOUT,7,7,246,247,NOT WS_VISIBLE | WS_BORDER -END - -IDD_SHADOWSESSION DIALOGEX 0, 0, 228, 84 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Remote Control" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "To end the remote control session, press this key and the modifiers selected below:",IDC_STATIC,7,7,214,19 - COMBOBOX IDC_VIRTUALKEY,7,27,74,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - CONTROL "Shift",IDC_SHIFT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,47,31,10 - CONTROL "Ctrl",IDC_CTRL,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,49,47,27,10 - CONTROL "Alt",IDC_ALT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,89,47,25,10 - DEFPUSHBUTTON "OK",IDOK,117,63,50,14 - PUSHBUTTON "Cancel",IDCANCEL,171,63,50,14 -END - -IDD_TOKCAPABILITIES DIALOGEX 0, 0, 270, 228 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Capabilities" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,7,256,214 -END - -IDD_TOKATTRIBUTES DIALOGEX 0, 0, 270, 228 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Attributes" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - CONTROL "",IDC_LIST,"PhTreeNew",WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP | 0x32,7,7,256,214,WS_EX_CLIENTEDGE -END - -IDD_SYSINFO_CPU DIALOGEX 0, 0, 316, 195 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_CAPTION | WS_SYSMENU -EXSTYLE WS_EX_CONTROLPARENT -CAPTION "CPU" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - RTEXT "CPU name",IDC_CPUNAME,41,4,274,16,SS_WORDELLIPSIS - LTEXT "CPU",IDC_TITLE,0,0,37,21 - LTEXT "Panel layout",IDC_LAYOUT,0,105,315,88,NOT WS_VISIBLE - LTEXT "Graph layout",IDC_GRAPH_LAYOUT,0,22,315,82,NOT WS_VISIBLE -END - -IDD_SYSINFO_CPUPANEL DIALOGEX 0, 0, 237, 86 -STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU -EXSTYLE WS_EX_CONTROLPARENT -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "Utilization:",IDC_STATIC,0,3,34,8 - LTEXT "Speed:",IDC_STATIC,108,3,24,8 - LTEXT "Static",IDC_UTILIZATION,40,0,62,15 - LTEXT "Static",IDC_SPEED,137,0,100,15 - GROUPBOX "System",IDC_STATIC,0,17,97,55 - LTEXT "Processes",IDC_STATIC,7,28,33,8 - LTEXT "Threads",IDC_STATIC,7,38,27,8 - LTEXT "Handles",IDC_STATIC,7,48,26,8 - LTEXT "Uptime",IDC_STATIC,7,58,23,8 - RTEXT "Static",IDC_ZPROCESSES_V,45,28,46,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZTHREADS_V,45,38,46,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZHANDLES_V,45,48,46,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZUPTIME_V,46,58,45,8,SS_ENDELLIPSIS - CONTROL "&Show one graph per CPU",IDC_ONEGRAPHPERCPU,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,0,76,96,10 - GROUPBOX "CPU",IDC_STATIC,101,17,136,55 - LTEXT "Context switches delta",IDC_STATIC,109,28,76,8 - LTEXT "Interrupts delta",IDC_STATIC,109,38,52,8 - LTEXT "DPCs delta",IDC_STATIC,109,48,36,8 - LTEXT "System calls delta",IDC_STATIC,109,58,60,8 - RTEXT "Static",IDC_ZCONTEXTSWITCHESDELTA_V,191,28,40,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZINTERRUPTSDELTA_V,185,39,46,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZDPCSDELTA_V,181,48,50,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZSYSTEMCALLSDELTA_V,179,59,52,8,SS_ENDELLIPSIS -END - -IDD_SYSINFO_MEMPANEL DIALOGEX 0, 0, 358, 171 -STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU -EXSTYLE WS_EX_CONTROLPARENT -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - GROUPBOX "Commit charge",IDC_STATIC,0,0,108,44 - LTEXT "Current",IDC_STATIC,7,11,26,8 - LTEXT "Peak",IDC_STATIC,7,21,16,8 - LTEXT "Limit",IDC_STATIC,7,31,15,8 - RTEXT "Static",IDC_ZCOMMITCURRENT_V,45,11,56,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZCOMMITPEAK_V,41,21,60,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZCOMMITLIMIT_V,40,31,61,8,SS_ENDELLIPSIS - GROUPBOX "Physical memory",IDC_STATIC,112,0,118,73 - LTEXT "Current",IDC_STATIC,120,11,26,8 - LTEXT "Cache WS",IDC_STATIC,120,41,34,8 - RTEXT "Static",IDC_ZPHYSICALCURRENT_V,165,11,57,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZPHYSICALTOTAL_V,167,21,55,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZPHYSICALCACHEWS_V,159,41,63,8,SS_ENDELLIPSIS - LTEXT "Total",IDC_STATIC,120,21,17,8 - LTEXT "Kernel WS",IDC_STATIC,120,51,34,8 - RTEXT "Static",IDC_ZPHYSICALKERNELWS_V,167,51,55,8,SS_ENDELLIPSIS - LTEXT "Driver WS",IDC_STATIC,120,61,33,8 - RTEXT "Static",IDC_ZPHYSICALDRIVERWS_V,163,61,59,8,SS_ENDELLIPSIS - GROUPBOX "Paged pool",IDC_STATIC,0,47,108,64 - LTEXT "Working set",IDC_STATIC,7,58,40,8 - LTEXT "Limit",IDC_STATIC,7,78,15,8 - RTEXT "Static",IDC_ZPAGEDWORKINGSET_V,54,58,47,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZPAGEDVIRTUALSIZE_V,52,68,49,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZPAGEDLIMIT_V,48,78,53,8,SS_ENDELLIPSIS - LTEXT "Virtual size",IDC_STATIC,7,68,36,8 - LTEXT "Allocs delta",IDC_STATIC,7,88,38,8 - RTEXT "Static",IDC_ZPAGEDALLOCSDELTA_V,53,88,48,8,SS_ENDELLIPSIS - LTEXT "Frees delta",IDC_STATIC,7,98,38,8 - RTEXT "Static",IDC_ZPAGEDFREESDELTA_V,51,98,50,8,SS_ENDELLIPSIS - GROUPBOX "Non-paged pool",IDC_STATIC,0,114,108,55 - LTEXT "Usage",IDC_STATIC,7,125,21,8 - LTEXT "Allocs delta",IDC_STATIC,7,145,38,8 - RTEXT "Static",IDC_ZNONPAGEDUSAGE_V,54,125,47,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZNONPAGEDLIMIT_V,52,135,49,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZNONPAGEDALLOCSDELTA_V,56,145,45,8,SS_ENDELLIPSIS - LTEXT "Limit",IDC_STATIC,7,135,15,8 - LTEXT "Frees delta",IDC_STATIC,7,155,38,8 - RTEXT "Static",IDC_ZNONPAGEDFREESDELTA_V,56,155,45,8,SS_ENDELLIPSIS - GROUPBOX "Memory lists",IDC_STATIC,234,0,123,169 - LTEXT "Zeroed",IDC_STATIC,242,11,24,8 - LTEXT "Modified",IDC_STATIC,242,31,28,8 - RTEXT "Static",IDC_ZLISTZEROED_V,304,11,47,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZLISTFREE_V,302,21,49,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZLISTMODIFIED_V,298,31,53,8,SS_ENDELLIPSIS - LTEXT "Free",IDC_STATIC,242,21,16,8 - LTEXT "Modified no-write",IDC_STATIC,242,41,56,8 - RTEXT "Static",IDC_ZLISTMODIFIEDNOWRITE_V,303,41,48,8,SS_ENDELLIPSIS - LTEXT "Standby",IDC_STATIC,242,61,28,8 - LTEXT "Priority 0",IDC_STATIC,251,71,30,8 - LTEXT "Priority 1",IDC_STATIC,251,80,30,8 - LTEXT "Priority 2",IDC_STATIC,251,90,30,8 - LTEXT "Priority 3",IDC_STATIC,251,100,30,8 - LTEXT "Priority 4",IDC_STATIC,251,110,30,8 - LTEXT "Priority 5",IDC_STATIC,251,120,30,8 - LTEXT "Priority 6",IDC_STATIC,251,130,30,8 - LTEXT "Priority 7",IDC_STATIC,251,140,30,8 - RTEXT "Static",IDC_ZLISTSTANDBY_V,303,61,48,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZLISTSTANDBY0_V,303,71,48,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZLISTSTANDBY1_V,303,80,48,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZLISTSTANDBY2_V,303,90,48,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZLISTSTANDBY3_V,303,100,48,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZLISTSTANDBY4_V,303,110,48,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZLISTSTANDBY5_V,303,120,48,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZLISTSTANDBY6_V,303,130,48,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZLISTSTANDBY7_V,303,140,48,8,SS_ENDELLIPSIS - GROUPBOX "Paging",IDC_STATIC,112,75,118,55 - LTEXT "Page faults delta",IDC_STATIC,120,86,57,8 - LTEXT "Pagefile writes delta",IDC_STATIC,120,106,68,8 - RTEXT "Static",IDC_ZPAGINGPAGEFAULTSDELTA_V,183,86,39,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZPAGINGPAGEREADSDELTA_V,179,96,43,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZPAGINGPAGEFILEWRITESDELTA_V,189,106,33,8,SS_ENDELLIPSIS - LTEXT "Page reads delta",IDC_STATIC,120,96,58,8 - LTEXT "Mapped writes delta",IDC_STATIC,120,116,68,8 - RTEXT "Static",IDC_ZPAGINGMAPPEDWRITESDELTA_V,191,116,31,8,SS_ENDELLIPSIS - LTEXT "Modified pagefile",IDC_STATIC,242,51,55,8 - RTEXT "Static",IDC_ZLISTMODIFIEDPAGEFILE_V,303,51,48,8,SS_ENDELLIPSIS - PUSHBUTTON "&More",IDC_MORE,242,152,50,14 - RTEXT "Static",IDC_ZPHYSICALRESERVED_V,167,31,55,8,SS_ENDELLIPSIS - LTEXT "Reserved",IDC_STATIC,120,31,32,8 -END - -IDD_SYSINFO_MEM DIALOGEX 0, 0, 316, 250 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_CAPTION | WS_SYSMENU -EXSTYLE WS_EX_CONTROLPARENT -CAPTION "Memory" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "Memory",IDC_TITLE,0,0,110,21 - LTEXT "Panel layout",IDC_LAYOUT,0,74,315,175,NOT WS_VISIBLE - LTEXT "Graph layout",IDC_GRAPH_LAYOUT,0,22,315,51,NOT WS_VISIBLE - RTEXT "Total physical",IDC_TOTALPHYSICAL,127,4,188,16,SS_WORDELLIPSIS - LTEXT "Commit charge:",IDC_COMMIT_L,111,1,52,8 - LTEXT "Physical memory:",IDC_PHYSICAL_L,111,7,56,8 -END - -IDD_SYSINFO_IO DIALOGEX 0, 0, 316, 187 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_CAPTION | WS_SYSMENU -CAPTION "I/O" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "I/O",IDC_TITLE,0,0,110,21 - LTEXT "Panel layout",IDC_LAYOUT,0,109,315,78,NOT WS_VISIBLE - LTEXT "Graph layout",IDC_GRAPH_LAYOUT,0,22,315,84,NOT WS_VISIBLE -END - -IDD_SYSINFO_IOPANEL DIALOGEX 0, 0, 276, 75 -STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - GROUPBOX "I/O deltas",IDC_STATIC,0,0,133,74 - LTEXT "Reads delta",IDC_STATIC,7,11,40,8 - LTEXT "Read bytes delta",IDC_STATIC,7,21,56,8 - LTEXT "Writes delta",IDC_STATIC,7,31,40,8 - LTEXT "Write bytes delta",IDC_STATIC,7,41,57,8 - RTEXT "Static",IDC_ZREADSDELTA_V,59,11,67,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZREADBYTESDELTA_V,75,21,51,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZWRITESDELTA_V,57,31,69,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZWRITEBYTESDELTA_V,73,41,53,8,SS_ENDELLIPSIS - LTEXT "Other delta",IDC_STATIC,7,51,38,8 - LTEXT "Other bytes delta",IDC_STATIC,7,61,58,8 - RTEXT "Static",IDC_ZOTHERDELTA_V,67,51,59,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZOTHERBYTESDELTA_V,81,61,45,8,SS_ENDELLIPSIS - GROUPBOX "I/O totals",IDC_STATIC,137,0,133,74 - LTEXT "Reads",IDC_STATIC,145,11,21,8 - LTEXT "Read bytes",IDC_STATIC,145,21,38,8 - LTEXT "Writes",IDC_STATIC,145,31,22,8 - LTEXT "Write bytes",IDC_STATIC,145,41,38,8 - RTEXT "Static",IDC_ZREADS_V,197,11,67,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZREADBYTES_V,192,21,72,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZWRITES_V,195,31,69,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZWRITEBYTES_V,190,41,74,8,SS_ENDELLIPSIS - LTEXT "Other",IDC_STATIC,145,51,20,8 - LTEXT "Other bytes",IDC_STATIC,145,61,40,8 - RTEXT "Static",IDC_ZOTHER_V,191,51,73,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZOTHERBYTES_V,192,61,72,8,SS_ENDELLIPSIS -END - -IDD_MEMLISTS DIALOGEX 0, 0, 228, 195 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU -EXSTYLE WS_EX_TOPMOST -CAPTION "Memory Lists" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - DEFPUSHBUTTON "Close",IDOK,171,174,50,14 - LTEXT "Zeroed",IDC_STATIC,7,7,24,8 - LTEXT "Free",IDC_STATIC,7,17,16,8 - LTEXT "Modified",IDC_STATIC,7,28,28,8 - LTEXT "Modified no-write",IDC_STATIC,7,39,56,8 - LTEXT "Bad",IDC_STATIC,7,60,13,8 - LTEXT "Standby",IDC_STATIC,7,72,28,8 - LTEXT "Priority 0",IDC_STATIC,23,83,30,8 - LTEXT "Priority 1",IDC_STATIC,23,94,30,8 - LTEXT "Priority 2",IDC_STATIC,23,105,30,8 - LTEXT "Priority 3",IDC_STATIC,23,116,30,8 - LTEXT "Priority 4",IDC_STATIC,23,128,30,8 - LTEXT "Priority 5",IDC_STATIC,23,139,30,8 - LTEXT "Priority 6",IDC_STATIC,23,150,30,8 - LTEXT "Priority 7",IDC_STATIC,23,161,30,8 - RTEXT "Static",IDC_ZLISTZEROED_V,73,7,59,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZLISTFREE_V,73,17,59,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZLISTMODIFIED_V,73,28,59,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZLISTMODIFIEDNOWRITE_V,73,39,59,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZLISTBAD_V,73,60,59,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZLISTSTANDBY_V,73,72,59,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZLISTSTANDBY0_V,73,83,59,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZLISTSTANDBY1_V,73,94,59,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZLISTSTANDBY2_V,73,105,59,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZLISTSTANDBY3_V,73,116,59,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZLISTSTANDBY4_V,73,128,59,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZLISTSTANDBY5_V,73,139,59,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZLISTSTANDBY6_V,73,150,59,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZLISTSTANDBY7_V,73,161,59,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZLISTREPURPOSED_V,162,72,59,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZLISTREPURPOSED0_V,162,84,59,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZLISTREPURPOSED1_V,162,95,59,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZLISTREPURPOSED2_V,162,106,59,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZLISTREPURPOSED3_V,162,117,59,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZLISTREPURPOSED4_V,162,128,59,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZLISTREPURPOSED5_V,162,139,59,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZLISTREPURPOSED6_V,162,150,59,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZLISTREPURPOSED7_V,162,161,59,8,SS_ENDELLIPSIS - RTEXT "(Repurposed)",IDC_STATIC,162,60,59,8 - PUSHBUTTON "&Empty",IDC_EMPTY,117,174,50,14 - LTEXT "Modified pagefile",IDC_STATIC,7,49,55,8 - RTEXT "Static",IDC_ZLISTMODIFIEDPAGEFILE_V,73,49,59,8,SS_ENDELLIPSIS -END - -IDD_CONTAINER DIALOGEX 0, 0, 316, 182 -STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_SYSMENU -EXSTYLE WS_EX_CONTROLPARENT -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN -END - -IDD_SYSINFO_MEMPANELXP DIALOGEX 0, 0, 230, 171 -STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU -EXSTYLE WS_EX_CONTROLPARENT -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - GROUPBOX "Commit charge",-1,0,0,108,44 - LTEXT "Current",-1,7,11,26,8 - LTEXT "Peak",-1,7,21,16,8 - LTEXT "Limit",-1,7,31,15,8 - RTEXT "Static",IDC_ZCOMMITCURRENT_V,45,11,56,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZCOMMITPEAK_V,41,21,60,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZCOMMITLIMIT_V,40,31,61,8,SS_ENDELLIPSIS - GROUPBOX "Physical memory",-1,112,0,118,64 - LTEXT "Current",-1,120,11,26,8 - LTEXT "Cache WS",-1,120,31,34,8 - RTEXT "Static",IDC_ZPHYSICALCURRENT_V,165,11,57,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZPHYSICALTOTAL_V,167,21,55,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZPHYSICALCACHEWS_V,159,31,63,8,SS_ENDELLIPSIS - LTEXT "Total",-1,120,21,17,8 - LTEXT "Kernel WS",-1,120,41,34,8 - RTEXT "Static",IDC_ZPHYSICALKERNELWS_V,167,41,55,8,SS_ENDELLIPSIS - LTEXT "Driver WS",-1,120,51,33,8 - RTEXT "Static",IDC_ZPHYSICALDRIVERWS_V,163,51,59,8,SS_ENDELLIPSIS - GROUPBOX "Paged pool",-1,0,47,108,64 - LTEXT "Working set",-1,7,58,40,8 - LTEXT "Limit",-1,7,78,15,8 - RTEXT "Static",IDC_ZPAGEDWORKINGSET_V,54,58,47,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZPAGEDVIRTUALSIZE_V,52,68,49,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZPAGEDLIMIT_V,48,78,53,8,SS_ENDELLIPSIS - LTEXT "Virtual size",-1,7,68,36,8 - LTEXT "Allocs delta",-1,7,88,38,8 - RTEXT "Static",IDC_ZPAGEDALLOCSDELTA_V,53,88,48,8,SS_ENDELLIPSIS - LTEXT "Frees delta",-1,7,98,38,8 - RTEXT "Static",IDC_ZPAGEDFREESDELTA_V,51,98,50,8,SS_ENDELLIPSIS - GROUPBOX "Non-paged pool",-1,0,114,108,55 - LTEXT "Usage",-1,7,125,21,8 - LTEXT "Allocs delta",-1,7,145,38,8 - RTEXT "Static",IDC_ZNONPAGEDUSAGE_V,54,125,47,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZNONPAGEDLIMIT_V,52,135,49,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZNONPAGEDALLOCSDELTA_V,56,145,45,8,SS_ENDELLIPSIS - LTEXT "Limit",-1,7,135,15,8 - LTEXT "Frees delta",-1,7,155,38,8 - RTEXT "Static",IDC_ZNONPAGEDFREESDELTA_V,56,155,45,8,SS_ENDELLIPSIS - GROUPBOX "Paging",-1,112,67,118,55 - LTEXT "Page faults delta",-1,120,78,57,8 - LTEXT "Pagefile writes delta",-1,120,98,68,8 - RTEXT "Static",IDC_ZPAGINGPAGEFAULTSDELTA_V,183,78,39,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZPAGINGPAGEREADSDELTA_V,179,88,43,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZPAGINGPAGEFILEWRITESDELTA_V,189,98,33,8,SS_ENDELLIPSIS - LTEXT "Page reads delta",-1,120,88,58,8 - LTEXT "Mapped writes delta",-1,120,108,68,8 - RTEXT "Static",IDC_ZPAGINGMAPPEDWRITESDELTA_V,191,108,31,8,SS_ENDELLIPSIS -END - -IDD_MINIINFO DIALOGEX 0, 0, 217, 150 -STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "Content layout",IDC_LAYOUT,4,3,210,128,NOT WS_VISIBLE - CONTROL "Section",IDC_SECTION,"Static",SS_LEFTNOWORDWRAP | SS_NOTIFY | SS_ENDELLIPSIS | WS_GROUP,4,134,177,13 - PUSHBUTTON "Options",IDC_OPTIONS,183,133,15,14,BS_ICON - CONTROL "Pin",IDC_PIN,"Button",BS_AUTOCHECKBOX | BS_ICON | BS_PUSHLIKE | WS_TABSTOP,199,133,15,14 -END - -IDD_MINIINFO_LIST DIALOGEX 0, 0, 217, 141 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "CPU" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - CONTROL "",IDC_LIST,"PhTreeNew",WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP | 0x82,0,0,217,140,WS_EX_CLIENTEDGE -END - -IDD_MITIGATION DIALOGEX 0, 0, 277, 217 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Mitigation Policies" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,7,263,108 - LTEXT "Description:",IDC_DESCRIPTIONLABEL,7,118,38,8 - EDITTEXT IDC_DESCRIPTION,7,129,263,62,ES_MULTILINE | ES_READONLY | WS_VSCROLL - DEFPUSHBUTTON "OK",IDOK,220,196,50,14 -END - -IDD_EDITENV DIALOGEX 0, 0, 311, 177 -STYLE DS_SETFONT | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME -CAPTION "Edit Environment Variable" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "Name:",IDC_STATIC,7,8,21,8 - EDITTEXT IDC_NAME,38,7,266,12,ES_AUTOHSCROLL - LTEXT "Value:",IDC_STATIC,7,25,21,8 - EDITTEXT IDC_VALUE,38,24,266,128,ES_MULTILINE | WS_VSCROLL - DEFPUSHBUTTON "OK",IDOK,200,156,50,14 - PUSHBUTTON "Cancel",IDCANCEL,254,156,50,14 -END - - -///////////////////////////////////////////////////////////////////////////// -// -// DESIGNINFO -// - -#ifdef APSTUDIO_INVOKED -GUIDELINES DESIGNINFO -BEGIN - IDD_PROCGENERAL, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 253 - TOPMARGIN, 7 - BOTTOMMARGIN, 253 - END - - IDD_PROCMODULES, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 253 - TOPMARGIN, 7 - BOTTOMMARGIN, 253 - END - - IDD_PROCTHREADS, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 253 - TOPMARGIN, 7 - BOTTOMMARGIN, 253 - END - - IDD_PROCHANDLES, DIALOG - BEGIN - LEFTMARGIN, 2 - RIGHTMARGIN, 258 - TOPMARGIN, 3 - BOTTOMMARGIN, 258 - END - - IDD_PROCENVIRONMENT, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 253 - TOPMARGIN, 7 - BOTTOMMARGIN, 253 - END - - IDD_THRDSTACK, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 254 - TOPMARGIN, 7 - BOTTOMMARGIN, 221 - END - - IDD_ABOUT, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 263 - TOPMARGIN, 7 - BOTTOMMARGIN, 188 - END - - IDD_SRVLIST, DIALOG - BEGIN - END - - IDD_SRVGENERAL, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 275 - TOPMARGIN, 7 - BOTTOMMARGIN, 176 - END - - IDD_HNDLGENERAL, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 253 - TOPMARGIN, 7 - BOTTOMMARGIN, 174 - END - - IDD_INFORMATION, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 310 - TOPMARGIN, 7 - BOTTOMMARGIN, 177 - END - - IDD_FINDOBJECTS, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 350 - TOPMARGIN, 7 - BOTTOMMARGIN, 226 - END - - IDD_OBJTOKEN, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 253 - TOPMARGIN, 7 - BOTTOMMARGIN, 253 - END - - IDD_HIDDENPROCESSES, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 330 - TOPMARGIN, 7 - BOTTOMMARGIN, 214 - END - - IDD_RUNAS, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 271 - TOPMARGIN, 7 - BOTTOMMARGIN, 120 - END - - IDD_PROGRESS, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 209 - TOPMARGIN, 7 - BOTTOMMARGIN, 55 - END - - IDD_PAGEFILES, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 315 - TOPMARGIN, 7 - BOTTOMMARGIN, 155 - END - - IDD_TOKGENERAL, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 263 - TOPMARGIN, 7 - BOTTOMMARGIN, 221 - END - - IDD_TOKADVANCED, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 229 - TOPMARGIN, 7 - BOTTOMMARGIN, 179 - END - - IDD_OBJJOB, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 253 - TOPMARGIN, 7 - BOTTOMMARGIN, 253 - END - - IDD_OBJEVENT, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 179 - TOPMARGIN, 7 - BOTTOMMARGIN, 69 - END - - IDD_OBJMUTANT, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 179 - TOPMARGIN, 7 - BOTTOMMARGIN, 69 - END - - IDD_OBJSEMAPHORE, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 179 - TOPMARGIN, 7 - BOTTOMMARGIN, 69 - END - - IDD_OBJTIMER, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 179 - TOPMARGIN, 7 - BOTTOMMARGIN, 69 - END - - IDD_JOBSTATISTICS, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 252 - TOPMARGIN, 7 - BOTTOMMARGIN, 179 - END - - IDD_OBJEVENTPAIR, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 179 - TOPMARGIN, 7 - BOTTOMMARGIN, 69 - END - - IDD_OBJSECTION, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 248 - TOPMARGIN, 7 - BOTTOMMARGIN, 69 - END - - IDD_AFFINITY, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 272 - TOPMARGIN, 7 - BOTTOMMARGIN, 220 - END - - IDD_SYSINFO, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 416 - TOPMARGIN, 7 - BOTTOMMARGIN, 240 - END - - IDD_EDITMESSAGE, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 275 - TOPMARGIN, 7 - BOTTOMMARGIN, 156 - END - - IDD_SESSION, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 194 - TOPMARGIN, 7 - BOTTOMMARGIN, 142 - END - - IDD_PROCMEMORY, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 253 - TOPMARGIN, 7 - BOTTOMMARGIN, 253 - END - - IDD_CHOOSE, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 192 - TOPMARGIN, 7 - BOTTOMMARGIN, 66 - END - - IDD_OPTGENERAL, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 243 - TOPMARGIN, 7 - BOTTOMMARGIN, 147 - END - - IDD_OPTHIGHLIGHTING, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 243 - TOPMARGIN, 7 - BOTTOMMARGIN, 167 - END - - IDD_CHOOSECOLUMNS, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 374 - TOPMARGIN, 7 - BOTTOMMARGIN, 200 - END - - IDD_NETSTACK, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 254 - TOPMARGIN, 7 - BOTTOMMARGIN, 221 - END - - IDD_CREATESERVICE, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 280 - TOPMARGIN, 7 - BOTTOMMARGIN, 126 - END - - IDD_PROCPERFORMANCE, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 253 - TOPMARGIN, 7 - BOTTOMMARGIN, 253 - END - - IDD_PROCSTATISTICS, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 253 - TOPMARGIN, 7 - BOTTOMMARGIN, 253 - END - - IDD_OPTADVANCED, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 243 - TOPMARGIN, 7 - BOTTOMMARGIN, 143 - END - - IDD_GDIHANDLES, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 344 - TOPMARGIN, 7 - BOTTOMMARGIN, 300 - END - - IDD_LOG, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 306 - TOPMARGIN, 7 - BOTTOMMARGIN, 296 - END - - IDD_OPTSYMBOLS, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 243 - TOPMARGIN, 7 - BOTTOMMARGIN, 68 - END - - IDD_MEMEDIT, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 434 - TOPMARGIN, 7 - BOTTOMMARGIN, 262 - END - - IDD_MEMPROTECT, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 263 - TOPMARGIN, 7 - BOTTOMMARGIN, 164 - END - - IDD_MEMRESULTS, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 306 - TOPMARGIN, 7 - BOTTOMMARGIN, 259 - END - - IDD_MEMSTRING, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 234 - TOPMARGIN, 7 - BOTTOMMARGIN, 79 - END - - IDD_OPTGRAPHS, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 243 - TOPMARGIN, 7 - BOTTOMMARGIN, 149 - END - - IDD_PLUGINS, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 284 - TOPMARGIN, 7 - BOTTOMMARGIN, 265 - END - - IDD_HANDLESTATS, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 212 - TOPMARGIN, 7 - BOTTOMMARGIN, 168 - END - - IDD_PROCRECORD, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 253 - TOPMARGIN, 7 - BOTTOMMARGIN, 195 - END - - IDD_CHOOSEPROCESS, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 310 - TOPMARGIN, 7 - BOTTOMMARGIN, 232 - END - - IDD_PROCSERVICES, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 253 - TOPMARGIN, 7 - BOTTOMMARGIN, 254 - END - - IDD_SHADOWSESSION, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 221 - TOPMARGIN, 7 - BOTTOMMARGIN, 77 - END - - IDD_TOKCAPABILITIES, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 263 - TOPMARGIN, 7 - BOTTOMMARGIN, 221 - END - - IDD_TOKATTRIBUTES, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 263 - TOPMARGIN, 7 - BOTTOMMARGIN, 221 - END - - IDD_SYSINFO_CPU, DIALOG - BEGIN - BOTTOMMARGIN, 193 - END - - IDD_SYSINFO_CPUPANEL, DIALOG - BEGIN - BOTTOMMARGIN, 85 - END - - IDD_SYSINFO_MEMPANEL, DIALOG - BEGIN - END - - IDD_SYSINFO_MEM, DIALOG - BEGIN - BOTTOMMARGIN, 247 - END - - IDD_SYSINFO_IO, DIALOG - BEGIN - END - - IDD_SYSINFO_IOPANEL, DIALOG - BEGIN - BOTTOMMARGIN, 74 - END - - IDD_MEMLISTS, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 221 - TOPMARGIN, 7 - BOTTOMMARGIN, 188 - END - - IDD_CONTAINER, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 309 - TOPMARGIN, 7 - BOTTOMMARGIN, 175 - END - - IDD_SYSINFO_MEMPANELXP, DIALOG - BEGIN - END - - IDD_MINIINFO, DIALOG - BEGIN - LEFTMARGIN, 4 - RIGHTMARGIN, 214 - TOPMARGIN, 3 - BOTTOMMARGIN, 147 - END - - IDD_MINIINFO_LIST, DIALOG - BEGIN - END - - IDD_MITIGATION, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 270 - TOPMARGIN, 7 - BOTTOMMARGIN, 210 - END - - IDD_EDITENV, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 304 - TOPMARGIN, 7 - BOTTOMMARGIN, 170 - END -END -#endif // APSTUDIO_INVOKED - - -///////////////////////////////////////////////////////////////////////////// -// -// Accelerator -// - -IDR_MAINWND_ACCEL ACCELERATORS -BEGIN - VK_ESCAPE, ID_ESC_EXIT, VIRTKEY, NOINVERT - "F", ID_HACKER_FINDHANDLESORDLLS, VIRTKEY, CONTROL, NOINVERT - "R", ID_HACKER_RUN, VIRTKEY, CONTROL, NOINVERT - "R", ID_HACKER_RUNAS, VIRTKEY, SHIFT, CONTROL, NOINVERT - "S", ID_HACKER_SAVE, VIRTKEY, CONTROL, NOINVERT - "L", ID_HELP_LOG, VIRTKEY, CONTROL, NOINVERT - "M", ID_PROCESS_SEARCHONLINE, VIRTKEY, CONTROL, NOINVERT - VK_TAB, ID_TAB_NEXT, VIRTKEY, CONTROL, NOINVERT - VK_TAB, ID_TAB_PREV, VIRTKEY, SHIFT, CONTROL, NOINVERT - VK_F5, ID_VIEW_REFRESH, VIRTKEY, NOINVERT - "I", ID_VIEW_SYSTEMINFORMATION, VIRTKEY, CONTROL, NOINVERT - VK_PAUSE, ID_VIEW_UPDATEAUTOMATICALLY, VIRTKEY, NOINVERT - VK_F6, ID_VIEW_UPDATEAUTOMATICALLY, VIRTKEY, NOINVERT -END - -IDR_SYSINFO_ACCEL ACCELERATORS -BEGIN - "1", ID_DIGIT1, VIRTKEY, NOINVERT - "2", ID_DIGIT2, VIRTKEY, NOINVERT - "3", ID_DIGIT3, VIRTKEY, NOINVERT - "4", ID_DIGIT4, VIRTKEY, NOINVERT - "5", ID_DIGIT5, VIRTKEY, NOINVERT - "6", ID_DIGIT6, VIRTKEY, NOINVERT - "7", ID_DIGIT7, VIRTKEY, NOINVERT - "8", ID_DIGIT8, VIRTKEY, NOINVERT - "9", ID_DIGIT9, VIRTKEY, NOINVERT - "B", IDC_BACK, VIRTKEY, ALT, NOINVERT - VK_BACK, IDC_BACK, VIRTKEY, NOINVERT - VK_F6, IDC_PAUSE, VIRTKEY, NOINVERT - VK_PAUSE, IDC_PAUSE, VIRTKEY, NOINVERT - VK_F5, IDC_REFRESH, VIRTKEY, NOINVERT - VK_F11, IDC_MAXSCREEN, VIRTKEY, NOINVERT -END - - -///////////////////////////////////////////////////////////////////////////// -// -// Bitmap -// - -IDB_CROSS BITMAP "resources\\cross.bmp" - -IDB_TICK BITMAP "resources\\tick.bmp" - -IDB_SEARCH_ACTIVE_BMP BITMAP "resources\\active_search.bmp" - -IDB_SEARCH_INACTIVE_BMP BITMAP "resources\\inactive_search.bmp" - - -///////////////////////////////////////////////////////////////////////////// -// -// RT_MANIFEST -// - -IDR_RT_MANIFEST RT_MANIFEST "ProcessHacker.manifest" - - -///////////////////////////////////////////////////////////////////////////// -// -// AFX_DIALOG_LAYOUT -// - -IDD_FINDOBJECTS AFX_DIALOG_LAYOUT -BEGIN - 0 -END - -IDD_OPTADVANCED AFX_DIALOG_LAYOUT -BEGIN - 0 -END - -IDD_SYSINFO_MEMPANEL AFX_DIALOG_LAYOUT -BEGIN - 0 -END - -IDD_ABOUT AFX_DIALOG_LAYOUT -BEGIN - 0 -END - -IDD_PROCGENERAL AFX_DIALOG_LAYOUT -BEGIN - 0 -END - -IDD_MITIGATION AFX_DIALOG_LAYOUT -BEGIN - 0 -END - -IDD_INFORMATION AFX_DIALOG_LAYOUT -BEGIN - 0 -END - -IDD_OPTGENERAL AFX_DIALOG_LAYOUT -BEGIN - 0 -END - -IDD_MINIINFO AFX_DIALOG_LAYOUT -BEGIN - 0 -END - -IDD_PROCTHREADS AFX_DIALOG_LAYOUT -BEGIN - 0 -END - -IDD_PROCRECORD AFX_DIALOG_LAYOUT -BEGIN - 0 -END - -IDD_PROCENVIRONMENT AFX_DIALOG_LAYOUT -BEGIN - 0 -END - -IDD_EDITENV AFX_DIALOG_LAYOUT -BEGIN - 0 -END - -IDD_PROCHANDLES AFX_DIALOG_LAYOUT -BEGIN - 0 -END - -IDD_OBJTOKEN AFX_DIALOG_LAYOUT -BEGIN - 0 -END - - -///////////////////////////////////////////////////////////////////////////// -// -// PNG -// - -IDB_SEARCH_ACTIVE PNG "resources\\active_search.png" - -IDB_SEARCH_INACTIVE PNG "resources\\inactive_search.png" - -#endif // English (Australia) resources -///////////////////////////////////////////////////////////////////////////// - - - -#ifndef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// - - -///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED - +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "winres.h" +#include "include/phappres.h" +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (Australia) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENA) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_AUS +#pragma code_page(1252) + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""winres.h""\r\n" + "#include ""include/phappres.h""\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_PROCESSHACKER ICON "ProcessHacker.ico" + +IDI_PHAPPLICATION ICON "resources\\application.ico" + +IDI_COG ICON "resources\\cog.ico" + +IDI_PHAPPLICATIONGO ICON "resources\\application_go.ico" + +IDI_COGGO ICON "resources\\cog_go.ico" + +IDI_PIN ICON "resources\\pin.ico" + +IDI_FOLDER ICON "resources\\folder.ico" + +IDI_PENCIL ICON "resources\\pencil.ico" + +IDI_MAGNIFIER ICON "resources\\magnifier.ico" + + +///////////////////////////////////////////////////////////////////////////// +// +// Menu +// + +IDR_MAINWND MENU +BEGIN + POPUP "&Hacker" + BEGIN + MENUITEM "&Run...\aCtrl+R", ID_HACKER_RUN + MENUITEM "Run as administrator...", ID_HACKER_RUNASADMINISTRATOR + MENUITEM "Run as &limited user...", ID_HACKER_RUNASLIMITEDUSER + MENUITEM "Run &as...\aCtrl+Shift+R", ID_HACKER_RUNAS + MENUITEM "Show &details for all processes", ID_HACKER_SHOWDETAILSFORALLPROCESSES + MENUITEM SEPARATOR + MENUITEM "&Save...\aCtrl+S", ID_HACKER_SAVE + MENUITEM "&Find handles or DLLs...\aCtrl+F", ID_HACKER_FINDHANDLESORDLLS + MENUITEM "&Options...", ID_HACKER_OPTIONS + MENUITEM "&Plugins...", ID_HACKER_PLUGINS + MENUITEM SEPARATOR + POPUP "&Computer" + BEGIN + MENUITEM "&Lock", ID_COMPUTER_LOCK + MENUITEM "Log o&ff", ID_COMPUTER_LOGOFF + MENUITEM SEPARATOR + MENUITEM "&Sleep", ID_COMPUTER_SLEEP + MENUITEM "&Hibernate", ID_COMPUTER_HIBERNATE + MENUITEM SEPARATOR + MENUITEM "R&estart", ID_COMPUTER_RESTART + MENUITEM "Restart to boot options", ID_COMPUTER_RESTARTBOOTOPTIONS + MENUITEM "Shu&t down", ID_COMPUTER_SHUTDOWN + MENUITEM "H&ybrid shut down", ID_COMPUTER_SHUTDOWNHYBRID + END + MENUITEM "E&xit", ID_HACKER_EXIT + END + POPUP "&View" + BEGIN + MENUITEM "System &information\aCtrl+I", ID_VIEW_SYSTEMINFORMATION + POPUP "&Tray icons" + BEGIN + MENUITEM "CPU history", ID_TRAYICONS_CPUHISTORY + MENUITEM "CPU usage", ID_TRAYICONS_CPUUSAGE + MENUITEM "I/O history", ID_TRAYICONS_IOHISTORY + MENUITEM "Commit charge history", ID_TRAYICONS_COMMITHISTORY + MENUITEM "Physical memory history", ID_TRAYICONS_PHYSICALMEMORYHISTORY + END + MENUITEM SEPARATOR + MENUITEM "
", ID_VIEW_SECTIONPLACEHOLDER + MENUITEM SEPARATOR + MENUITEM "&Always on top", ID_VIEW_ALWAYSONTOP + POPUP "&Opacity" + BEGIN + MENUITEM "10%", ID_OPACITY_10 + MENUITEM "20%", ID_OPACITY_20 + MENUITEM "30%", ID_OPACITY_30 + MENUITEM "40%", ID_OPACITY_40 + MENUITEM "50%", ID_OPACITY_50 + MENUITEM "60%", ID_OPACITY_60 + MENUITEM "70%", ID_OPACITY_70 + MENUITEM "80%", ID_OPACITY_80 + MENUITEM "90%", ID_OPACITY_90 + MENUITEM "Opaque", ID_OPACITY_OPAQUE + END + MENUITEM SEPARATOR + MENUITEM "&Refresh\aF5", ID_VIEW_REFRESH + POPUP "Refresh i&nterval" + BEGIN + MENUITEM "Fast (0.5s)", ID_UPDATEINTERVAL_FAST + MENUITEM "Normal (1s)", ID_UPDATEINTERVAL_NORMAL + MENUITEM "Below normal (2s)", ID_UPDATEINTERVAL_BELOWNORMAL + MENUITEM "Slow (5s)", ID_UPDATEINTERVAL_SLOW + MENUITEM "Very slow (10s)", ID_UPDATEINTERVAL_VERYSLOW + END + MENUITEM "Refresh a&utomatically\aF6", ID_VIEW_UPDATEAUTOMATICALLY + END + POPUP "&Tools" + BEGIN + MENUITEM "Create service...", ID_TOOLS_CREATESERVICE + MENUITEM "Hidden processes", ID_TOOLS_HIDDENPROCESSES + MENUITEM "Inspect executable file...", ID_TOOLS_INSPECTEXECUTABLEFILE + MENUITEM "Pagefiles", ID_TOOLS_PAGEFILES + MENUITEM "Start Task Manager", ID_TOOLS_STARTTASKMANAGER + END + POPUP "&Users" + BEGIN + MENUITEM "Dummy", ID_USERS_DUMMY + END + POPUP "H&elp" + BEGIN + MENUITEM "&Log\aCtrl+L", ID_HELP_LOG + MENUITEM "&Donate", ID_HELP_DONATE + MENUITEM "Debu&g console", ID_HELP_DEBUGCONSOLE + MENUITEM "&About", ID_HELP_ABOUT + END +END + +IDR_THREAD MENU +BEGIN + POPUP "Thread" + BEGIN + MENUITEM "&Inspect\aEnter", ID_THREAD_INSPECT + MENUITEM "T&erminate\aDel", ID_THREAD_TERMINATE + MENUITEM "&Suspend", ID_THREAD_SUSPEND + MENUITEM "Res&ume", ID_THREAD_RESUME + MENUITEM SEPARATOR + MENUITEM "&Affinity", ID_THREAD_AFFINITY + MENUITEM "Per&missions", ID_THREAD_PERMISSIONS + MENUITEM "&Token", ID_THREAD_TOKEN + POPUP "Analy&ze" + BEGIN + MENUITEM "Wait", ID_ANALYZE_WAIT + END + POPUP "&Priority" + BEGIN + MENUITEM "Time critical", ID_PRIORITY_TIMECRITICAL + MENUITEM "Highest", ID_PRIORITY_HIGHEST + MENUITEM "Above normal", ID_PRIORITY_ABOVENORMAL + MENUITEM "Normal", ID_PRIORITY_NORMAL + MENUITEM "Below normal", ID_PRIORITY_BELOWNORMAL + MENUITEM "Lowest", ID_PRIORITY_LOWEST + MENUITEM "Idle", ID_PRIORITY_IDLE + END + POPUP "I/O priority" + BEGIN + MENUITEM "High", ID_IOPRIORITY_HIGH + MENUITEM "Normal", ID_IOPRIORITY_NORMAL + MENUITEM "Low", ID_IOPRIORITY_LOW + MENUITEM "Very low", ID_IOPRIORITY_VERYLOW + END + POPUP "Page priority" + BEGIN + MENUITEM "Normal", ID_PAGEPRIORITY_NORMAL + MENUITEM "Below normal", ID_PAGEPRIORITY_BELOWNORMAL + MENUITEM "Medium", ID_PAGEPRIORITY_MEDIUM + MENUITEM "Low", ID_PAGEPRIORITY_LOW + MENUITEM "Very low", ID_PAGEPRIORITY_VERYLOW + END + MENUITEM SEPARATOR + MENUITEM "&Copy\aCtrl+C", ID_THREAD_COPY + END +END + +IDR_HANDLE MENU +BEGIN + POPUP "Handle" + BEGIN + MENUITEM "C&lose\aDel", ID_HANDLE_CLOSE + MENUITEM "&Protected", ID_HANDLE_PROTECTED + MENUITEM "&Inherit", ID_HANDLE_INHERIT + MENUITEM SEPARATOR + MENUITEM "&Copy\aCtrl+C", ID_HANDLE_COPY + MENUITEM "Prope&rties\aEnter", ID_HANDLE_PROPERTIES + END +END + +IDR_MODULE MENU +BEGIN + POPUP "Module" + BEGIN + MENUITEM "&Unload\aDel", ID_MODULE_UNLOAD + MENUITEM SEPARATOR + MENUITEM "&Inspect\aEnter", ID_MODULE_INSPECT + MENUITEM "&Search online\aCtrl+M", ID_MODULE_SEARCHONLINE + MENUITEM "Open &file location\aCtrl+Enter", ID_MODULE_OPENFILELOCATION + MENUITEM "P&roperties", ID_MODULE_PROPERTIES + MENUITEM "&Copy\aCtrl+C", ID_MODULE_COPY + END +END + +IDR_COMPUTER MENU +BEGIN + POPUP "Computer" + BEGIN + MENUITEM "&Lock", ID_COMPUTER_LOCK + MENUITEM "Log o&ff", ID_COMPUTER_LOGOFF + MENUITEM SEPARATOR + MENUITEM "&Sleep", ID_COMPUTER_SLEEP + MENUITEM "&Hibernate", ID_COMPUTER_HIBERNATE + MENUITEM SEPARATOR + MENUITEM "R&estart", ID_COMPUTER_RESTART + MENUITEM "Restart to boot &options", ID_COMPUTER_RESTARTBOOTOPTIONS + MENUITEM "Shu&t down", ID_COMPUTER_SHUTDOWN + MENUITEM "H&ybrid shut down", ID_COMPUTER_SHUTDOWNHYBRID + END +END + +IDR_PROCESS MENU +BEGIN + POPUP "Process" + BEGIN + MENUITEM "T&erminate\aDel", ID_PROCESS_TERMINATE + MENUITEM "Terminate tree\aShift+Del", ID_PROCESS_TERMINATETREE + MENUITEM "&Suspend", ID_PROCESS_SUSPEND + MENUITEM "Res&ume", ID_PROCESS_RESUME + MENUITEM "Res&tart", ID_PROCESS_RESTART + MENUITEM SEPARATOR + MENUITEM "Create dump file...", ID_PROCESS_CREATEDUMPFILE + MENUITEM "Debug", ID_PROCESS_DEBUG + MENUITEM "Virtualization", ID_PROCESS_VIRTUALIZATION + MENUITEM SEPARATOR + MENUITEM "&Affinity", ID_PROCESS_AFFINITY + POPUP "&Priority" + BEGIN + MENUITEM "Real time", ID_PRIORITY_REALTIME + MENUITEM "High", ID_PRIORITY_HIGH + MENUITEM "Above normal", ID_PRIORITY_ABOVENORMAL + MENUITEM "Normal", ID_PRIORITY_NORMAL + MENUITEM "Below normal", ID_PRIORITY_BELOWNORMAL + MENUITEM "Idle", ID_PRIORITY_IDLE + END + POPUP "&I/O priority" + BEGIN + MENUITEM "High", ID_IOPRIORITY_HIGH + MENUITEM "Normal", ID_IOPRIORITY_NORMAL + MENUITEM "Low", ID_IOPRIORITY_LOW + MENUITEM "Very low", ID_IOPRIORITY_VERYLOW + END + POPUP "&Miscellaneous" + BEGIN + MENUITEM "Detach from debugger", ID_MISCELLANEOUS_DETACHFROMDEBUGGER + MENUITEM "GDI handles", ID_MISCELLANEOUS_GDIHANDLES + MENUITEM "Inject DLL...", ID_MISCELLANEOUS_INJECTDLL + POPUP "Page priority" + BEGIN + MENUITEM "Normal", ID_PAGEPRIORITY_NORMAL + MENUITEM "Below normal", ID_PAGEPRIORITY_BELOWNORMAL + MENUITEM "Medium", ID_PAGEPRIORITY_MEDIUM + MENUITEM "Low", ID_PAGEPRIORITY_LOW + MENUITEM "Very low", ID_PAGEPRIORITY_VERYLOW + END + MENUITEM "Reduce working set", ID_MISCELLANEOUS_REDUCEWORKINGSET + MENUITEM "Run as...", ID_MISCELLANEOUS_RUNAS + MENUITEM "Run as this user...", ID_MISCELLANEOUS_RUNASTHISUSER + END + POPUP "&Window" + BEGIN + MENUITEM "Bring to front", ID_WINDOW_BRINGTOFRONT + MENUITEM "Restore", ID_WINDOW_RESTORE + MENUITEM "Minimize", ID_WINDOW_MINIMIZE + MENUITEM "Maximize", ID_WINDOW_MAXIMIZE + MENUITEM SEPARATOR + MENUITEM "Close", ID_WINDOW_CLOSE + END + MENUITEM SEPARATOR + MENUITEM "Search online\aCtrl+M", ID_PROCESS_SEARCHONLINE + MENUITEM "Open &file location\aCtrl+Enter", ID_PROCESS_OPENFILELOCATION + MENUITEM "P&roperties\aEnter", ID_PROCESS_PROPERTIES + MENUITEM "&Copy\aCtrl+C", ID_PROCESS_COPY + END +END + +IDR_SERVICE MENU +BEGIN + POPUP "Service" + BEGIN + MENUITEM "&Go to process", ID_SERVICE_GOTOPROCESS + MENUITEM "&Start", ID_SERVICE_START + MENUITEM "C&ontinue", ID_SERVICE_CONTINUE + MENUITEM "&Pause", ID_SERVICE_PAUSE + MENUITEM "S&top", ID_SERVICE_STOP + MENUITEM "&Delete\aDel", ID_SERVICE_DELETE + MENUITEM SEPARATOR + MENUITEM "Open &key", ID_SERVICE_OPENKEY + MENUITEM "Open &file location\aCtrl+Enter", ID_SERVICE_OPENFILELOCATION + MENUITEM "P&roperties\aEnter", ID_SERVICE_PROPERTIES + MENUITEM "&Copy\aCtrl+C", ID_SERVICE_COPY + END +END + +IDR_PRIVILEGE MENU +BEGIN + POPUP "Privilege" + BEGIN + MENUITEM "&Enable", ID_PRIVILEGE_ENABLE + MENUITEM "&Disable", ID_PRIVILEGE_DISABLE + MENUITEM "&Remove", ID_PRIVILEGE_REMOVE + MENUITEM SEPARATOR + MENUITEM "&Copy\aCtrl+C", ID_PRIVILEGE_COPY + END +END + +IDR_FINDOBJ MENU +BEGIN + POPUP "Object" + BEGIN + MENUITEM "C&lose\aDel", ID_OBJECT_CLOSE + MENUITEM SEPARATOR + MENUITEM "Go to owning &process", ID_OBJECT_GOTOOWNINGPROCESS + MENUITEM "Prope&rties", ID_OBJECT_PROPERTIES + MENUITEM "&Copy\aCtrl+C", ID_OBJECT_COPY + END +END + +IDR_USER MENU +BEGIN + POPUP "User" + BEGIN + MENUITEM "&Connect", ID_USER_CONNECT + MENUITEM "&Disconnect", ID_USER_DISCONNECT + MENUITEM "&Logoff", ID_USER_LOGOFF + MENUITEM "Rem&ote control", ID_USER_REMOTECONTROL + MENUITEM "Send &message...", ID_USER_SENDMESSAGE + MENUITEM "P&roperties", ID_USER_PROPERTIES + END +END + +IDR_NETWORK MENU +BEGIN + POPUP "Network" + BEGIN + MENUITEM "&Go to process\aEnter", ID_NETWORK_GOTOPROCESS + MENUITEM "Go to service", ID_NETWORK_GOTOSERVICE + MENUITEM "View &stack", ID_NETWORK_VIEWSTACK + MENUITEM "C&lose", ID_NETWORK_CLOSE + MENUITEM SEPARATOR + MENUITEM "&Copy\aCtrl+C", ID_NETWORK_COPY + END +END + +IDR_ICON MENU +BEGIN + POPUP "Icon" + BEGIN + MENUITEM "&Show/Hide Process Hacker", ID_ICON_SHOWHIDEPROCESSHACKER + MENUITEM "System &information", ID_ICON_SYSTEMINFORMATION + POPUP "N&otifications" + BEGIN + MENUITEM "Enable all", ID_NOTIFICATIONS_ENABLEALL + MENUITEM "Disable all", ID_NOTIFICATIONS_DISABLEALL + MENUITEM SEPARATOR + MENUITEM "New processes", ID_NOTIFICATIONS_NEWPROCESSES + MENUITEM "Terminated processes", ID_NOTIFICATIONS_TERMINATEDPROCESSES + MENUITEM "New services", ID_NOTIFICATIONS_NEWSERVICES + MENUITEM "Started services", ID_NOTIFICATIONS_STARTEDSERVICES + MENUITEM "Stopped services", ID_NOTIFICATIONS_STOPPEDSERVICES + MENUITEM "Deleted services", ID_NOTIFICATIONS_DELETEDSERVICES + END + POPUP "&Processes" + BEGIN + MENUITEM "Dummy", ID_PROCESSES_DUMMY + END + MENUITEM SEPARATOR + POPUP "&Computer" + BEGIN + MENUITEM "&Lock", ID_COMPUTER_LOCK + MENUITEM "Log o&ff", ID_COMPUTER_LOGOFF + MENUITEM SEPARATOR + MENUITEM "&Sleep", ID_COMPUTER_SLEEP + MENUITEM "&Hibernate", ID_COMPUTER_HIBERNATE + MENUITEM SEPARATOR + MENUITEM "R&estart", ID_COMPUTER_RESTART + MENUITEM "Restart to boot options", ID_COMPUTER_RESTARTBOOTOPTIONS + MENUITEM "Shu&t down", ID_COMPUTER_SHUTDOWN + MENUITEM "H&ybrid shut down", ID_COMPUTER_SHUTDOWNHYBRID + END + MENUITEM "E&xit", ID_ICON_EXIT + END +END + +IDR_MEMORY MENU +BEGIN + POPUP "Memory" + BEGIN + MENUITEM "&Read/Write memory", ID_MEMORY_READWRITEMEMORY + MENUITEM "&Save...", ID_MEMORY_SAVE + MENUITEM "Change &protection...", ID_MEMORY_CHANGEPROTECTION + MENUITEM "&Free", ID_MEMORY_FREE + MENUITEM "&Decommit", ID_MEMORY_DECOMMIT + MENUITEM SEPARATOR + MENUITEM "Read/Write &address...", ID_MEMORY_READWRITEADDRESS + MENUITEM "&Copy\aCtrl+C", ID_MEMORY_COPY + END +END + +IDR_MEMFILTER MENU +BEGIN + POPUP "Filter" + BEGIN + MENUITEM "Contains...", ID_FILTER_CONTAINS + MENUITEM "Contains (case-insensitive)...", ID_FILTER_CONTAINS_CASEINSENSITIVE + MENUITEM "Regex...", ID_FILTER_REGEX + MENUITEM "Regex (case-insensitive)...", ID_FILTER_REGEX_CASEINSENSITIVE + END +END + +IDR_EMPTYMEMLISTS MENU +BEGIN + POPUP "Empty" + BEGIN + MENUITEM "Empty working sets", ID_EMPTY_EMPTYWORKINGSETS + MENUITEM "Empty modified page list", ID_EMPTY_EMPTYMODIFIEDPAGELIST + MENUITEM "Empty standby list", ID_EMPTY_EMPTYSTANDBYLIST + MENUITEM "Empty priority 0 standby list", ID_EMPTY_EMPTYPRIORITY0STANDBYLIST + END +END + +IDR_MINIINFO MENU +BEGIN + POPUP "Mini Info" + BEGIN + POPUP "&Opacity" + BEGIN + MENUITEM "10%", ID_OPACITY_10 + MENUITEM "20%", ID_OPACITY_20 + MENUITEM "30%", ID_OPACITY_30 + MENUITEM "40%", ID_OPACITY_40 + MENUITEM "50%", ID_OPACITY_50 + MENUITEM "60%", ID_OPACITY_60 + MENUITEM "70%", ID_OPACITY_70 + MENUITEM "80%", ID_OPACITY_80 + MENUITEM "90%", ID_OPACITY_90 + MENUITEM "Opaque", ID_OPACITY_OPAQUE + END + MENUITEM SEPARATOR + MENUITEM "&Refresh\aF5", ID_MINIINFO_REFRESH + MENUITEM "Refresh a&utomatically\aF6", ID_MINIINFO_REFRESHAUTOMATICALLY + END +END + +IDR_MINIINFO_PROCESS MENU +BEGIN + POPUP "Process" + BEGIN + MENUITEM SEPARATOR + MENUITEM "&Go to process", ID_PROCESS_GOTOPROCESS + END +END + +IDR_ENVIRONMENT MENU +BEGIN + POPUP "Environment" + BEGIN + MENUITEM "&Edit", ID_ENVIRONMENT_EDIT + MENUITEM "&Delete\aDel", ID_ENVIRONMENT_DELETE + MENUITEM "&Copy\aCtrl+C", ID_ENVIRONMENT_COPY + END +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_PROCGENERAL DIALOGEX 0, 0, 260, 260 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "General" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + PUSHBUTTON "Permissions",IDC_PERMISSIONS,143,197,50,14 + PUSHBUTTON "Terminate",IDC_TERMINATE,197,197,50,14 + GROUPBOX "File",IDC_FILE,7,7,246,79 + ICON "",IDC_FILEICON,14,18,20,20 + EDITTEXT IDC_NAME,44,17,182,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + EDITTEXT IDC_COMPANYNAME,44,29,183,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + CONTROL "Company name link",IDC_COMPANYNAME_LINK,"SysLink",LWS_NOPREFIX | NOT WS_VISIBLE | WS_TABSTOP,46,29,183,9 + LTEXT "Version:",IDC_STATIC,15,41,27,8 + EDITTEXT IDC_VERSION,44,41,113,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + LTEXT "Image file name:",IDC_STATIC,15,55,56,8 + EDITTEXT IDC_FILENAME,15,65,191,12,ES_AUTOHSCROLL | ES_READONLY + PUSHBUTTON "Inspect",IDC_INSPECT,210,64,17,15,BS_ICON + PUSHBUTTON "Open",IDC_OPENFILENAME,230,64,17,15,BS_ICON + GROUPBOX "Process",IDC_PROCESS,7,92,246,161 + LTEXT "Command line:",IDC_STATIC,13,103,50,8 + EDITTEXT IDC_CMDLINE,79,101,147,12,ES_AUTOHSCROLL | ES_READONLY + LTEXT "Current directory:",IDC_STATIC,13,119,60,8 + EDITTEXT IDC_CURDIR,79,117,168,12,ES_AUTOHSCROLL | ES_READONLY + LTEXT "Started:",IDC_STATIC,13,135,28,8 + EDITTEXT IDC_STARTED,79,133,168,12,ES_AUTOHSCROLL | ES_READONLY + LTEXT "PEB address:",IDC_STATIC,13,151,44,8 + EDITTEXT IDC_PEBADDRESS,79,149,101,12,ES_AUTOHSCROLL | ES_READONLY + LTEXT "Image type:",IDC_PROCESSTYPELABEL,185,151,41,8,NOT WS_VISIBLE + LTEXT "32-bit",IDC_PROCESSTYPETEXT,228,151,20,8,NOT WS_VISIBLE + LTEXT "Parent:",IDC_STATIC,13,167,25,8 + EDITTEXT IDC_PARENTPROCESS,79,165,147,12,ES_AUTOHSCROLL | ES_READONLY + PUSHBUTTON "View",IDC_VIEWPARENTPROCESS,230,163,17,15,BS_ICON + LTEXT "Mitigation policies:",IDC_STATIC,13,183,59,8 + EDITTEXT IDC_MITIGATION,79,181,126,12,ES_AUTOHSCROLL | ES_READONLY + PUSHBUTTON "Details",IDC_VIEWMITIGATION,209,180,38,14 + LTEXT "Protection:",IDC_STATIC,13,200,36,8 + EDITTEXT IDC_PROTECTION,51,200,80,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + PUSHBUTTON "View",IDC_VIEWCOMMANDLINE,230,100,17,15,BS_ICON +END + +IDD_PROCMODULES DIALOGEX 0, 0, 260, 260 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Modules" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + CONTROL "",IDC_LIST,"PhTreeNew",WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP | 0xa,7,7,246,246,WS_EX_CLIENTEDGE +END + +IDD_PROCTHREADS DIALOGEX 0, 0, 260, 260 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Threads" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "Start module:",IDC_STATICBL1,7,170,44,8 + EDITTEXT IDC_STARTMODULE,55,168,177,12,ES_AUTOHSCROLL | ES_READONLY + PUSHBUTTON "Open",IDC_OPENSTARTMODULE,236,166,17,15,BS_ICON | WS_DISABLED + LTEXT "Started:",IDC_STATICBL2,7,184,28,8 + LTEXT "N/A",IDC_STARTED,75,184,178,8 + LTEXT "Kernel time:",IDC_STATICBL3,7,207,40,8 + LTEXT "N/A",IDC_KERNELTIME,75,207,51,8 + LTEXT "User time:",IDC_STATICBL4,7,217,35,8 + LTEXT "N/A",IDC_USERTIME,75,217,51,8 + LTEXT "Context switches:",IDC_STATICBL5,7,228,60,8 + LTEXT "N/A",IDC_CONTEXTSWITCHES,75,228,51,8,SS_ENDELLIPSIS + LTEXT "Cycles:",IDC_STATICBL6,7,239,24,8 + LTEXT "N/A",IDC_CYCLES,41,239,85,8,SS_ENDELLIPSIS + LTEXT "Base priority:",IDC_STATICBL9,136,205,44,8 + LTEXT "Priority:",IDC_STATICBL8,136,195,26,8 + LTEXT "I/O priority:",IDC_STATICBL10,136,216,39,8 + LTEXT "Page priority:",IDC_STATICBL11,136,227,44,8 + LTEXT "State:",IDC_STATICBL7,7,195,21,8 + LTEXT "N/A",IDC_STATE,41,195,85,8,SS_ENDELLIPSIS + LTEXT "N/A",IDC_PRIORITY,195,195,58,8 + LTEXT "N/A",IDC_BASEPRIORITY,195,205,58,8 + LTEXT "N/A",IDC_IOPRIORITY,195,216,58,8 + LTEXT "N/A",IDC_PAGEPRIORITY,195,227,58,8 + CONTROL "",IDC_LIST,"PhTreeNew",WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP | 0x22,7,7,246,156,WS_EX_CLIENTEDGE + LTEXT "Ideal processor:",IDC_STATICBL12,136,239,53,8 + LTEXT "N/A",IDC_IDEALPROCESSOR,195,239,58,8 +END + +IDD_PROCHANDLES DIALOGEX 0, 0, 260, 260 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Handles" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + CONTROL "Hide unnamed handles",IDC_HIDEUNNAMEDHANDLES,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,3,5,88,10 + CONTROL "",IDC_LIST,"PhTreeNew",WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP | 0x2,2,19,256,239,WS_EX_CLIENTEDGE + EDITTEXT IDC_HANDLESEARCH,114,3,144,14,ES_AUTOHSCROLL +END + +IDD_PROCENVIRONMENT DIALOGEX 0, 0, 260, 260 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Environment" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,7,246,227 + PUSHBUTTON "New...",IDC_NEW,93,239,50,14 + PUSHBUTTON "Edit...",IDC_EDIT,148,239,50,14 + PUSHBUTTON "Delete",IDC_DELETE,203,239,50,14 +END + +IDD_THRDSTACK DIALOGEX 0, 0, 261, 228 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME +CAPTION "Thread Stack" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,7,7,247,196 + PUSHBUTTON "Copy",IDC_COPY,96,207,50,14 + PUSHBUTTON "Refresh",IDC_REFRESH,150,207,50,14 + PUSHBUTTON "Close",IDOK,204,207,50,14 +END + +IDD_ABOUT DIALOGEX 0, 0, 270, 195 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "About" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + ICON IDI_PROCESSHACKER,IDC_STATIC,16,15,20,20 + LTEXT "Process Hacker",IDC_ABOUT_NAME,45,14,192,8 + LTEXT "Licensed under the GNU GPL, v3.",IDC_STATIC,45,27,193,8 + LTEXT "Copyright (c) 2008-2017 Wen Jia Liu (wj32)",IDC_STATIC,15,40,140,8 + CONTROL "Credits.",IDC_CREDITS,"SysLink",WS_TABSTOP,15,55,248,115 + CONTROL "Process Hacker on SourceForge.net",IDC_LINK_SF, + "SysLink",WS_TABSTOP,7,177,130,11 + PUSHBUTTON "Diagnostics",IDC_DIAGNOSTICS,160,174,50,14 + DEFPUSHBUTTON "OK",IDOK,213,174,50,14 +END + +IDD_SRVLIST DIALOGEX 0, 0, 237, 201 +STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_SYSMENU +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,0,0,237,141 + EDITTEXT IDC_DESCRIPTION,0,144,237,40,ES_MULTILINE | ES_READONLY | NOT WS_BORDER + PUSHBUTTON "&Start",IDC_START,134,187,50,14 + PUSHBUTTON "&Pause",IDC_PAUSE,187,187,50,14 +END + +IDD_SRVGENERAL DIALOGEX 0, 0, 282, 183 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "General" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + EDITTEXT IDC_DESCRIPTION,7,7,268,45,ES_MULTILINE | ES_READONLY | WS_VSCROLL + LTEXT "Type:",IDC_STATIC,7,57,20,8 + COMBOBOX IDC_TYPE,30,56,110,65,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + LTEXT "Start type:",IDC_STATIC,147,57,38,8 + COMBOBOX IDC_STARTTYPE,188,56,87,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + LTEXT "Error control:",IDC_STATIC,7,75,47,8 + COMBOBOX IDC_ERRORCONTROL,58,73,82,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + LTEXT "Group:",IDC_STATIC,147,75,23,8 + EDITTEXT IDC_GROUP,173,74,102,12,ES_AUTOHSCROLL + LTEXT "Binary path:",IDC_STATIC,7,92,40,8 + EDITTEXT IDC_BINARYPATH,58,91,163,12,ES_AUTOHSCROLL + PUSHBUTTON "Browse...",IDC_BROWSE,225,90,50,14 + LTEXT "User account:",IDC_STATIC,7,110,46,8 + EDITTEXT IDC_USERACCOUNT,58,108,217,12,ES_AUTOHSCROLL + LTEXT "Password:",IDC_STATIC,7,127,34,8 + EDITTEXT IDC_PASSWORD,58,125,204,12,ES_PASSWORD | ES_AUTOHSCROLL + CONTROL "",IDC_PASSWORDCHECK,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,266,126,9,10 + LTEXT "Service DLL:",IDC_STATIC,7,144,48,8 + EDITTEXT IDC_SERVICEDLL,58,142,217,12,ES_AUTOHSCROLL | ES_READONLY + CONTROL "Delayed start",IDC_DELAYEDSTART,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,158,59,10 +END + +IDD_HNDLGENERAL DIALOGEX 0, 0, 260, 181 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "General" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + GROUPBOX "Basic information",IDC_BASICINFORMATION,7,7,246,67 + LTEXT "Name:",IDC_STATIC,14,19,22,8 + EDITTEXT IDC_NAME,40,19,206,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + LTEXT "Type:",IDC_STATIC,14,32,20,8 + EDITTEXT IDC_TYPE,40,32,206,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + LTEXT "Object address:",IDC_STATIC,14,44,53,8 + EDITTEXT IDC_ADDRESS,71,44,175,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + LTEXT "Granted access:",IDC_STATIC,14,56,54,8 + EDITTEXT IDC_GRANTED_ACCESS,71,56,175,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + GROUPBOX "References",IDC_STATIC,7,78,119,39 + LTEXT "References:",IDC_STATIC,14,90,40,8 + LTEXT "Static",IDC_REFERENCES,58,90,41,8 + LTEXT "Handles:",IDC_STATIC,14,101,29,8 + LTEXT "Static",IDC_HANDLES,58,101,40,8 + GROUPBOX "Quota charges",IDC_STATIC,131,78,122,39 + LTEXT "Paged:",IDC_STATIC,138,89,24,8 + LTEXT "Static",IDC_PAGED,182,89,39,8 + LTEXT "Non-paged:",IDC_STATIC,138,100,39,8 + LTEXT "Static",IDC_NONPAGED,182,100,39,8 +END + +IDD_INFORMATION DIALOGEX 0, 0, 317, 184 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME +CAPTION "Information" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + EDITTEXT IDC_TEXT,7,7,303,152,ES_MULTILINE | ES_READONLY | WS_VSCROLL + PUSHBUTTON "Save...",IDC_SAVE,154,163,50,14 + PUSHBUTTON "Copy",IDC_COPY,207,163,50,14 + DEFPUSHBUTTON "Close",IDOK,260,163,50,14 +END + +IDD_FINDOBJECTS DIALOGEX 0, 0, 357, 233 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME +CAPTION "Find Handles or DLLs" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "Filter:",IDC_STATIC,7,9,20,8 + EDITTEXT IDC_FILTER,32,8,224,14,ES_AUTOHSCROLL + PUSHBUTTON "Find",IDOK,300,7,50,14 + CONTROL "",IDC_RESULTS,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,26,343,200 + CONTROL "&Regex",IDC_REGEX,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,261,9,36,10 +END + +IDD_OBJTOKEN DIALOGEX 0, 0, 260, 260 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Token" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "User:",IDC_STATIC,7,7,18,8 + EDITTEXT IDC_USER,48,7,205,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + LTEXT "User SID:",IDC_STATIC,7,18,32,8 + EDITTEXT IDC_USERSID,48,18,205,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + LTEXT "Session:",IDC_STATIC,7,29,28,8 + LTEXT "Unknown",IDC_SESSIONID,38,29,30,8 + LTEXT "Elevated:",IDC_STATIC,85,29,32,8 + LTEXT "Unknown",IDC_ELEVATED,120,29,30,8 + LTEXT "Virtualized:",IDC_STATIC,169,29,36,8 + LTEXT "Unknown",IDC_VIRTUALIZED,209,29,44,8 + LTEXT "App container SID:",IDC_STATIC,7,40,62,8 + EDITTEXT IDC_APPCONTAINERSID,75,40,178,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + CONTROL "",IDC_GROUPS,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,53,246,112 + CONTROL "",IDC_PRIVILEGES,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,168,246,57 + LTEXT "To view capabilities, claims and other attributes, click Advanced.",IDC_INSTRUCTION,7,228,206,8 + PUSHBUTTON "Integrity",IDC_INTEGRITY,149,239,50,14 + PUSHBUTTON "Advanced",IDC_ADVANCED,203,239,50,14 +END + +IDD_HIDDENPROCESSES DIALOGEX 0, 0, 337, 221 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME +CAPTION "Hidden Processes" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "Processes highlighted red are hidden while those highlighted grey have terminated.",IDC_INTRO,7,7,323,12 + CONTROL "",IDC_PROCESSES,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,23,323,162 + RTEXT "",IDC_DESCRIPTION,7,187,323,11 + COMBOBOX IDC_METHOD,7,201,73,30,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Terminate",IDC_TERMINATE,115,200,50,14 + PUSHBUTTON "Save...",IDC_SAVE,170,200,50,14 + PUSHBUTTON "&Scan",IDC_SCAN,225,200,50,14 + DEFPUSHBUTTON "Close",IDOK,280,200,50,14 +END + +IDD_RUNAS DIALOGEX 0, 0, 278, 127 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Run As" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "Enter the command to start as the specified user.",IDC_STATIC,7,7,160,8 + LTEXT "Program:",IDC_STATIC,7,23,30,8 + EDITTEXT IDC_PROGRAM,53,21,163,12,ES_AUTOHSCROLL + PUSHBUTTON "Browse...",IDC_BROWSE,221,20,50,14 + LTEXT "User name:",IDC_STATIC,7,40,38,8 + COMBOBOX IDC_USERNAME,53,38,123,12,CBS_DROPDOWN | CBS_AUTOHSCROLL | CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "Type:",IDC_STATIC,183,40,20,8 + COMBOBOX IDC_TYPE,207,38,64,30,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "Password:",IDC_STATIC,7,56,34,8 + EDITTEXT IDC_PASSWORD,53,55,123,12,ES_PASSWORD | ES_AUTOHSCROLL + CONTROL "Toggle elevation",IDC_TOGGLEELEVATION,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,183,56,69,10 + LTEXT "Session ID:",IDC_STATIC,7,73,37,8 + EDITTEXT IDC_SESSIONID,53,72,104,12,ES_AUTOHSCROLL | ES_NUMBER + PUSHBUTTON "...",IDC_SESSIONS,161,71,16,14 + LTEXT "Desktop:",IDC_STATIC,7,90,30,8 + EDITTEXT IDC_DESKTOP,53,88,104,12,ES_AUTOHSCROLL + PUSHBUTTON "...",IDC_DESKTOPS,161,87,16,14 + DEFPUSHBUTTON "OK",IDOK,168,106,50,14 + PUSHBUTTON "Cancel",IDCANCEL,221,106,50,14 +END + +IDD_PROGRESS DIALOGEX 0, 0, 216, 62 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Progress" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + PUSHBUTTON "Cancel",IDCANCEL,159,41,50,14 + CONTROL "",IDC_PROGRESS,"msctls_progress32",0x0,7,23,202,14 + LTEXT "Please wait...",IDC_PROGRESSTEXT,7,7,202,12 +END + +IDD_PAGEFILES DIALOGEX 0, 0, 322, 162 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Pagefiles" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,7,7,308,128 + PUSHBUTTON "Refresh",IDC_REFRESH,211,141,50,14 + DEFPUSHBUTTON "Close",IDOK,265,141,50,14 +END + +IDD_TOKGENERAL DIALOGEX 0, 0, 270, 228 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "General" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + GROUPBOX "Token",IDC_STATIC,7,7,256,132 + LTEXT "User:",IDC_STATIC,15,19,18,8 + EDITTEXT IDC_USER,71,17,185,12,ES_AUTOHSCROLL | ES_READONLY + LTEXT "User SID:",IDC_STATIC,15,36,32,8 + EDITTEXT IDC_USERSID,71,34,185,12,ES_AUTOHSCROLL | ES_READONLY + LTEXT "Owner:",IDC_STATIC,15,53,25,8 + EDITTEXT IDC_OWNER,71,51,185,12,ES_AUTOHSCROLL | ES_READONLY + LTEXT "Primary group:",IDC_STATIC,15,70,49,8 + EDITTEXT IDC_PRIMARYGROUP,71,68,185,12,ES_AUTOHSCROLL | ES_READONLY + LTEXT "Session ID:",IDC_STATIC,15,87,37,8 + EDITTEXT IDC_SESSIONID,71,85,88,12,ES_AUTOHSCROLL | ES_READONLY + LTEXT "Elevated:",IDC_STATIC,15,104,32,8 + EDITTEXT IDC_ELEVATED,71,102,117,12,ES_AUTOHSCROLL | ES_READONLY + LTEXT "Virtualization:",IDC_STATIC,15,121,44,8 + EDITTEXT IDC_VIRTUALIZATION,71,119,185,12,ES_AUTOHSCROLL | ES_READONLY + PUSHBUTTON "Linked token",IDC_LINKEDTOKEN,193,101,63,14 + GROUPBOX "Source",IDC_STATIC,7,143,256,47 + LTEXT "Name:",IDC_STATIC,15,155,22,8 + EDITTEXT IDC_SOURCENAME,71,153,185,12,ES_AUTOHSCROLL | ES_READONLY + LTEXT "LUID:",IDC_STATIC,15,173,19,8 + EDITTEXT IDC_SOURCELUID,71,171,185,12,ES_AUTOHSCROLL | ES_READONLY +END + +IDD_TOKADVANCED DIALOGEX 0, 0, 236, 186 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Advanced" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "Type:",IDC_STATIC,7,8,20,8 + EDITTEXT IDC_TYPE,81,7,116,12,ES_AUTOHSCROLL | ES_READONLY + LTEXT "Impersonation level:",IDC_STATIC,7,26,68,8 + EDITTEXT IDC_IMPERSONATIONLEVEL,81,24,116,12,ES_AUTOHSCROLL | ES_READONLY + LTEXT "Token LUID:",IDC_STATIC,7,43,55,8 + EDITTEXT IDC_TOKENLUID,81,41,116,12,ES_AUTOHSCROLL | ES_READONLY + LTEXT "Authentication LUID:",IDC_STATIC,7,61,68,8 + EDITTEXT IDC_AUTHENTICATIONLUID,81,59,116,12,ES_AUTOHSCROLL | ES_READONLY + LTEXT "Memory used:",IDC_STATIC,7,78,47,8 + EDITTEXT IDC_MEMORYUSED,81,76,116,12,ES_AUTOHSCROLL | ES_READONLY + LTEXT "Memory available:",IDC_STATIC,7,95,60,8 + EDITTEXT IDC_MEMORYAVAILABLE,81,93,116,12,ES_AUTOHSCROLL | ES_READONLY +END + +IDD_OBJJOB DIALOGEX 0, 0, 260, 260 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Job" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "Name:",IDC_STATIC,7,9,22,8 + EDITTEXT IDC_NAME,35,8,164,12,ES_AUTOHSCROLL + PUSHBUTTON "Terminate",IDC_TERMINATE,203,7,50,14 + LTEXT "Processes in job:",IDC_STATIC,7,25,55,8 + CONTROL "",IDC_PROCESSES,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_SORTASCENDING | LVS_ALIGNLEFT | LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,7,38,246,62 + PUSHBUTTON "Add...",IDC_ADD,203,103,50,14 + LTEXT "Limits:",IDC_STATIC,7,117,21,8 + CONTROL "",IDC_LIMITS,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_SORTASCENDING | LVS_ALIGNLEFT | LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,7,129,246,107 + PUSHBUTTON "Advanced",IDC_ADVANCED,203,239,50,14 +END + +IDD_OBJEVENT DIALOGEX 0, 0, 186, 76 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Event" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "Type:",IDC_STATIC,7,7,20,8 + LTEXT "Unknown",IDC_TYPE,42,7,137,8 + LTEXT "Signaled:",IDC_STATIC,7,18,30,8 + LTEXT "Unknown",IDC_SIGNALED,42,18,137,8 + PUSHBUTTON "Set",IDC_SET,7,34,50,14 + PUSHBUTTON "Reset",IDC_RESET,61,34,50,14 + PUSHBUTTON "Pulse",IDC_PULSE,115,34,50,14 +END + +IDD_OBJMUTANT DIALOGEX 0, 0, 186, 76 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Mutant" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "Count:",IDC_STATIC,7,7,23,8 + LTEXT "Unknown",IDC_COUNT,55,7,124,8 + LTEXT "Abandoned:",IDC_STATIC,7,18,40,8 + LTEXT "Unknown",IDC_ABANDONED,55,18,124,8 + LTEXT "Owner:",IDC_OWNERLABEL,7,29,25,8 + LTEXT "Unknown",IDC_OWNER,55,29,124,8 +END + +IDD_OBJSEMAPHORE DIALOGEX 0, 0, 186, 76 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Semaphore" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "Current count:",IDC_STATIC,7,7,50,8 + LTEXT "Unknown",IDC_CURRENTCOUNT,66,7,113,8 + LTEXT "Maximum count:",IDC_STATIC,7,18,54,8 + LTEXT "Unknown",IDC_MAXIMUMCOUNT,66,18,113,8 + PUSHBUTTON "Acquire",IDC_ACQUIRE,7,34,50,14 + PUSHBUTTON "Release",IDC_RELEASE,61,34,50,14 +END + +IDD_OBJTIMER DIALOGEX 0, 0, 186, 76 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Timer" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "Signaled:",-1,7,7,30,8 + LTEXT "Unknown",IDC_SIGNALED,42,7,137,8 + PUSHBUTTON "Cancel",IDC_CANCEL,7,19,50,14 +END + +IDD_JOBSTATISTICS DIALOGEX 0, 0, 259, 186 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Statistics" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + GROUPBOX "General",IDC_STATIC,7,7,133,47 + LTEXT "Active processes",IDC_STATIC,15,18,55,8 + RTEXT "Static",IDC_ZACTIVEPROCESSES_V,99,18,37,8,SS_ENDELLIPSIS + LTEXT "Total processes",IDC_STATIC,15,28,51,8 + RTEXT "Static",IDC_ZTOTALPROCESSES_V,95,29,41,8,SS_ENDELLIPSIS + LTEXT "Terminated processes",IDC_STATIC,15,39,71,8 + RTEXT "Static",IDC_ZTERMINATEDPROCESSES_V,99,39,37,8,SS_ENDELLIPSIS + GROUPBOX "Time",IDC_STATIC,7,57,133,57 + LTEXT "User time",IDC_STATIC,15,68,32,8 + LTEXT "Kernel time",IDC_STATIC,15,79,38,8 + LTEXT "User time (period)",IDC_STATIC,15,89,60,8 + LTEXT "Kernel time (period)",IDC_STATIC,15,99,65,8 + RTEXT "Static",IDC_ZUSERTIME_V,83,68,53,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZKERNELTIME_V,85,79,51,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZUSERTIMEPERIOD_V,87,89,49,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZKERNELTIMEPERIOD_V,87,99,49,8,SS_ENDELLIPSIS + GROUPBOX "Memory",IDC_STATIC,7,118,133,48 + LTEXT "Page faults",IDC_STATIC,15,129,38,8 + LTEXT "Peak process usage",IDC_STATIC,15,140,65,8 + LTEXT "Peak job usage",IDC_STATIC,15,151,52,8 + RTEXT "Static",IDC_ZPAGEFAULTS_V,86,129,50,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZPEAKPROCESSUSAGE_V,85,140,51,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZPEAKJOBUSAGE_V,86,151,50,8,SS_ENDELLIPSIS + GROUPBOX "I/O",IDC_STATIC,146,7,106,75 + LTEXT "Reads",IDC_STATIC,152,17,21,8 + LTEXT "Read bytes",IDC_STATIC,152,27,38,8 + LTEXT "Writes",IDC_STATIC,152,37,22,8 + LTEXT "Write bytes",IDC_STATIC,152,47,38,8 + LTEXT "Other",IDC_STATIC,152,57,20,8 + LTEXT "Other bytes",IDC_STATIC,152,67,40,8 + RTEXT "Static",IDC_ZIOREADS_V,200,17,47,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZIOREADBYTES_V,200,27,47,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZIOWRITES_V,200,37,47,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZIOWRITEBYTES_V,200,47,47,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZIOOTHER_V,200,57,47,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZIOOTHERBYTES_V,200,67,47,8,SS_ENDELLIPSIS +END + +IDD_OBJEVENTPAIR DIALOGEX 0, 0, 186, 76 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Event Pair" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + PUSHBUTTON "Set low",IDC_SETLOW,7,7,50,14 + PUSHBUTTON "Set high",IDC_SETHIGH,61,7,50,14 +END + +IDD_OBJSECTION DIALOGEX 0, 0, 255, 76 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Section" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "Type:",IDC_STATIC,7,7,20,8 + LTEXT "Unknown",IDC_TYPE,43,7,205,8 + LTEXT "Size:",IDC_STATIC,7,18,16,8 + LTEXT "Unknown",IDC_SIZE_,43,18,205,8 + LTEXT "File:",IDC_STATIC,7,29,14,8 + EDITTEXT IDC_FILE,43,29,205,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER +END + +IDD_AFFINITY DIALOGEX 0, 0, 279, 227 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Affinity" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + DEFPUSHBUTTON "OK",IDOK,169,206,50,14 + PUSHBUTTON "Cancel",IDCANCEL,222,206,50,14 + LTEXT "Affinity controls which CPUs threads are allowed to execute on.",IDC_STATIC,7,7,265,11 + CONTROL "CPU 0",IDC_CPU0,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,21,35,10 + CONTROL "CPU 1",IDC_CPU1,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,33,35,10 + CONTROL "CPU 2",IDC_CPU2,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,44,35,10 + CONTROL "CPU 3",IDC_CPU3,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,56,35,10 + CONTROL "CPU 4",IDC_CPU4,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,67,35,10 + CONTROL "CPU 5",IDC_CPU5,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,78,35,10 + CONTROL "CPU 6",IDC_CPU6,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,89,35,10 + CONTROL "CPU 7",IDC_CPU7,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,100,35,10 + CONTROL "CPU 8",IDC_CPU8,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,111,35,10 + CONTROL "CPU 9",IDC_CPU9,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,122,35,10 + CONTROL "CPU 10",IDC_CPU10,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,134,39,10 + CONTROL "CPU 11",IDC_CPU11,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,145,39,10 + CONTROL "CPU 12",IDC_CPU12,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,156,39,10 + CONTROL "CPU 13",IDC_CPU13,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,167,39,10 + CONTROL "CPU 14",IDC_CPU14,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,178,39,10 + CONTROL "CPU 15",IDC_CPU15,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,190,39,10 + CONTROL "CPU 16",IDC_CPU16,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,79,21,39,10 + CONTROL "CPU 17",IDC_CPU17,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,79,33,39,10 + CONTROL "CPU 18",IDC_CPU18,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,79,44,39,10 + CONTROL "CPU 19",IDC_CPU19,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,79,56,39,10 + CONTROL "CPU 20",IDC_CPU20,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,79,67,39,10 + CONTROL "CPU 21",IDC_CPU21,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,79,78,39,10 + CONTROL "CPU 22",IDC_CPU22,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,79,89,39,10 + CONTROL "CPU 23",IDC_CPU23,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,79,100,39,10 + CONTROL "CPU 24",IDC_CPU24,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,79,111,39,10 + CONTROL "CPU 25",IDC_CPU25,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,79,122,39,10 + CONTROL "CPU 26",IDC_CPU26,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,79,134,39,10 + CONTROL "CPU 27",IDC_CPU27,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,79,145,39,10 + CONTROL "CPU 28",IDC_CPU28,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,79,156,39,10 + CONTROL "CPU 29",IDC_CPU29,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,79,167,39,10 + CONTROL "CPU 30",IDC_CPU30,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,79,178,39,10 + CONTROL "CPU 31",IDC_CPU31,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,79,190,39,10 + CONTROL "CPU 32",IDC_CPU32,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,150,21,39,10 + CONTROL "CPU 33",IDC_CPU33,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,150,33,39,10 + CONTROL "CPU 34",IDC_CPU34,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,150,44,39,10 + CONTROL "CPU 35",IDC_CPU35,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,150,56,39,10 + CONTROL "CPU 36",IDC_CPU36,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,150,67,39,10 + CONTROL "CPU 37",IDC_CPU37,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,150,78,39,10 + CONTROL "CPU 38",IDC_CPU38,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,150,89,39,10 + CONTROL "CPU 39",IDC_CPU39,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,150,100,39,10 + CONTROL "CPU 40",IDC_CPU40,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,150,111,39,10 + CONTROL "CPU 41",IDC_CPU41,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,150,122,39,10 + CONTROL "CPU 42",IDC_CPU42,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,150,134,39,10 + CONTROL "CPU 43",IDC_CPU43,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,150,145,39,10 + CONTROL "CPU 44",IDC_CPU44,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,150,156,39,10 + CONTROL "CPU 45",IDC_CPU45,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,150,167,39,10 + CONTROL "CPU 46",IDC_CPU46,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,150,178,39,10 + CONTROL "CPU 47",IDC_CPU47,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,150,190,39,10 + CONTROL "CPU 48",IDC_CPU48,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,224,21,39,10 + CONTROL "CPU 49",IDC_CPU49,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,224,33,39,10 + CONTROL "CPU 50",IDC_CPU50,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,224,44,39,10 + CONTROL "CPU 51",IDC_CPU51,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,224,56,39,10 + CONTROL "CPU 52",IDC_CPU52,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,224,67,39,10 + CONTROL "CPU 53",IDC_CPU53,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,224,78,39,10 + CONTROL "CPU 54",IDC_CPU54,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,224,89,39,10 + CONTROL "CPU 55",IDC_CPU55,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,224,100,39,10 + CONTROL "CPU 56",IDC_CPU56,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,224,111,39,10 + CONTROL "CPU 57",IDC_CPU57,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,224,122,39,10 + CONTROL "CPU 58",IDC_CPU58,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,224,134,39,10 + CONTROL "CPU 59",IDC_CPU59,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,224,145,39,10 + CONTROL "CPU 60",IDC_CPU60,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,224,156,39,10 + CONTROL "CPU 61",IDC_CPU61,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,224,167,39,10 + CONTROL "CPU 62",IDC_CPU62,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,224,178,39,10 + CONTROL "CPU 63",IDC_CPU63,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,224,190,39,10 + PUSHBUTTON "Select all",IDC_SELECTALL,7,206,50,14 + PUSHBUTTON "Deselect all",IDC_DESELECTALL,60,206,50,14 +END + +IDD_SYSINFO DIALOGEX 0, 0, 423, 247 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME +EXSTYLE WS_EX_APPWINDOW +CAPTION "System Information" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "Click a graph to view details for that section.",IDC_INSTRUCTION,7,228,144,8 + CONTROL "Always on &top",IDC_ALWAYSONTOP,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,297,228,63,10 + DEFPUSHBUTTON "Close",IDOK,366,226,50,14 +END + +IDD_EDITMESSAGE DIALOGEX 0, 0, 282, 163 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Message" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "Title:",IDC_STATIC,7,8,17,8 + EDITTEXT IDC_TITLE,52,7,223,12,ES_AUTOHSCROLL + LTEXT "Text:",IDC_STATIC,7,24,18,8 + EDITTEXT IDC_TEXT,52,23,223,79,ES_MULTILINE | ES_AUTOVSCROLL | ES_WANTRETURN | WS_VSCROLL + LTEXT "Icon:",IDC_STATIC,7,107,18,8 + COMBOBOX IDC_TYPE,52,105,80,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + LTEXT "Timeout (s):",IDC_STATIC,7,123,40,8 + EDITTEXT IDC_TIMEOUT,52,122,43,12,ES_AUTOHSCROLL + DEFPUSHBUTTON "OK",IDOK,172,142,50,14 + PUSHBUTTON "Cancel",IDCANCEL,225,142,50,14 +END + +IDD_SESSION DIALOGEX 0, 0, 201, 149 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Session Properties" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + DEFPUSHBUTTON "Close",IDOK,144,128,50,14 + LTEXT "User name:",IDC_STATIC,7,7,38,8 + LTEXT "Session ID:",IDC_STATIC,7,18,37,8 + LTEXT "State:",IDC_STATIC,7,29,21,8 + LTEXT "Client name:",IDC_STATIC,7,84,41,8 + LTEXT "Client address:",IDC_STATIC,7,95,49,8 + LTEXT "Client display:",IDC_STATIC,7,106,46,8 + LTEXT "N/A",IDC_USERNAME,66,7,128,8 + LTEXT "N/A",IDC_SESSIONID,66,18,128,8 + LTEXT "N/A",IDC_STATE,66,29,128,8 + LTEXT "N/A",IDC_CLIENTNAME,66,84,128,8 + LTEXT "N/A",IDC_CLIENTADDRESS,66,95,128,8 + LTEXT "N/A",IDC_CLIENTDISPLAY,66,106,128,8 + LTEXT "Logon time:",IDC_STATIC,7,40,38,8 + LTEXT "N/A",IDC_LOGONTIME,66,40,128,8 + LTEXT "Connect time:",IDC_STATIC,7,51,46,8 + LTEXT "Disconnect time:",IDC_STATIC,7,62,54,8 + LTEXT "Last input time:",IDC_STATIC,7,73,50,8 + LTEXT "N/A",IDC_CONNECTTIME,66,51,128,8 + LTEXT "N/A",IDC_DISCONNECTTIME,66,62,128,8 + LTEXT "N/A",IDC_LASTINPUTTIME,66,74,128,8 +END + +IDD_PROCMEMORY DIALOGEX 0, 0, 260, 260 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Memory" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + PUSHBUTTON "Strings...",IDC_STRINGS,150,7,50,14 + PUSHBUTTON "Refresh",IDC_REFRESH,203,7,50,14 + CONTROL "",IDC_LIST,"PhTreeNew",WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP | 0xa,7,26,246,227,WS_EX_CLIENTEDGE + CONTROL "Hide free regions",IDC_HIDEFREEREGIONS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,9,71,10 +END + +IDD_CHOOSE DIALOGEX 0, 0, 199, 73 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Dialog" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "Text:",IDC_MESSAGE,7,7,185,8,SS_ENDELLIPSIS + COMBOBOX IDC_CHOICE,7,20,185,30,CBS_DROPDOWNLIST | CBS_AUTOHSCROLL | NOT WS_VISIBLE | WS_VSCROLL | WS_TABSTOP + CONTROL "Option",IDC_OPTION,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,39,185,10 + DEFPUSHBUTTON "OK",IDOK,89,52,50,14 + PUSHBUTTON "Cancel",IDCANCEL,142,52,50,14 + COMBOBOX IDC_CHOICEUSER,7,20,185,30,CBS_DROPDOWN | CBS_AUTOHSCROLL | CBS_SORT | NOT WS_VISIBLE | WS_VSCROLL | WS_TABSTOP + EDITTEXT IDC_CHOICESIMPLE,7,20,185,13,ES_PASSWORD | ES_AUTOHSCROLL | NOT WS_VISIBLE +END + +IDD_OPTGENERAL DIALOGEX 0, 0, 250, 154 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "General" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "Search engine:",IDC_STATIC,7,8,49,8 + EDITTEXT IDC_SEARCHENGINE,61,7,182,12,ES_AUTOHSCROLL + LTEXT "PE viewer:",IDC_STATIC,7,23,35,8 + EDITTEXT IDC_PEVIEWER,61,22,182,12,ES_AUTOHSCROLL + LTEXT "Max. size unit:",IDC_STATIC,7,38,49,8 + COMBOBOX IDC_MAXSIZEUNIT,61,37,39,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + LTEXT "Icon processes:",IDC_STATIC,7,55,52,8 + EDITTEXT IDC_ICONPROCESSES,61,53,40,12,ES_AUTOHSCROLL | ES_NUMBER + CONTROL "Allow only one instance",IDC_ALLOWONLYONEINSTANCE, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,71,91,10 + CONTROL "Hide when closed",IDC_HIDEONCLOSE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,83,71,10 + CONTROL "Hide when minimized",IDC_HIDEONMINIMIZE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,95,81,10 + CONTROL "Start hidden",IDC_STARTHIDDEN,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,119,55,10 + CONTROL "Collapse services on start",IDC_COLLAPSESERVICES,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,122,71,98,10 + CONTROL "Single-click tray icons",IDC_ICONSINGLECLICK,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,122,83,83,10 + CONTROL "Icon click toggles visibility",IDC_ICONTOGGLESVISIBILITY, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,122,95,97,10 + CONTROL "Enable plugins",IDC_ENABLEPLUGINS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,122,107,61,10 + PUSHBUTTON "Font...",IDC_FONT,7,133,50,14 + CONTROL "Start when I log on",IDC_STARTATLOGON,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,107,77,10 +END + +IDD_OPTHIGHLIGHTING DIALOGEX 0, 0, 250, 174 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Highlighting" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "Highlighting duration:",IDC_STATIC,7,8,70,8 + EDITTEXT IDC_HIGHLIGHTINGDURATION,79,7,40,12,ES_AUTOHSCROLL | ES_NUMBER + LTEXT "New objects:",IDC_STATIC,7,25,44,8 + CONTROL "New objects",IDC_NEWOBJECTS,"PhColorBox",WS_CLIPSIBLINGS | WS_TABSTOP,57,23,33,13 + LTEXT "Removed objects:",IDC_STATIC,127,25,60,8 + CONTROL "Removed objects",IDC_REMOVEDOBJECTS,"PhColorBox",WS_CLIPSIBLINGS | WS_TABSTOP,193,23,33,13 + CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | LVS_NOCOLUMNHEADER | WS_BORDER | WS_TABSTOP,7,41,236,107 + LTEXT "Double-click an item to change it.",IDC_STATIC,7,156,106,8 + PUSHBUTTON "Enable all",IDC_ENABLEALL,140,153,50,14 + PUSHBUTTON "Disable all",IDC_DISABLEALL,193,153,50,14 +END + +IDD_CHOOSECOLUMNS DIALOGEX 0, 0, 381, 207 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Choose Columns" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "Select the columns that will appear in the list.",IDC_MESSAGE,7,7,367,10 + LTEXT "Inactive columns:",IDC_STATIC,7,21,57,8 + LISTBOX IDC_INACTIVE,7,31,129,150,LBS_SORT | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Show >",IDC_SHOW,139,86,50,14 + PUSHBUTTON "< Hide",IDC_HIDE,139,103,50,14 + LISTBOX IDC_ACTIVE,192,31,129,150,LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Move up",IDC_MOVEUP,324,31,50,14 + PUSHBUTTON "Move down",IDC_MOVEDOWN,324,48,50,14 + DEFPUSHBUTTON "OK",IDOK,272,186,50,14 + PUSHBUTTON "Cancel",IDCANCEL,324,186,50,14 + LTEXT "Active columns:",IDC_STATIC,192,21,51,8 +END + +IDD_NETSTACK DIALOGEX 0, 0, 261, 228 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME +CAPTION "Network Stack" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,7,7,247,196 + PUSHBUTTON "Close",IDOK,204,207,50,14 +END + +IDD_CREATESERVICE DIALOGEX 0, 0, 287, 133 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Create Service" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "Name:",IDC_STATIC,7,8,22,8 + EDITTEXT IDC_NAME,61,7,219,12,ES_AUTOHSCROLL + LTEXT "Display name:",IDC_STATIC,7,24,46,8 + EDITTEXT IDC_DISPLAYNAME,61,23,219,12,ES_AUTOHSCROLL + LTEXT "Type:",IDC_STATIC,7,41,20,8 + COMBOBOX IDC_TYPE,61,39,97,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + LTEXT "Start type:",IDC_STATIC,7,58,38,8 + COMBOBOX IDC_STARTTYPE,61,56,97,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + LTEXT "Error control:",IDC_STATIC,7,75,45,8 + COMBOBOX IDC_ERRORCONTROL,61,73,97,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + LTEXT "Binary path:",IDC_STATIC,7,91,40,8 + EDITTEXT IDC_BINARYPATH,61,90,165,12,ES_AUTOHSCROLL + PUSHBUTTON "Browse...",IDC_BROWSE,230,89,50,14 + DEFPUSHBUTTON "OK",IDOK,176,112,50,14 + PUSHBUTTON "Cancel",IDCANCEL,230,112,50,14 +END + +IDD_PROCPERFORMANCE DIALOGEX 0, 0, 260, 260 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Performance" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + GROUPBOX "CPU",IDC_GROUPCPU,7,7,246,74,0,WS_EX_TRANSPARENT + GROUPBOX "Private bytes",IDC_GROUPPRIVATEBYTES,7,86,246,77,0,WS_EX_TRANSPARENT + GROUPBOX "I/O",IDC_GROUPIO,7,164,246,89,0,WS_EX_TRANSPARENT + CONTROL "",IDC_CPU,"PhGraph",WS_CLIPSIBLINGS,105,42,50,14 + CONTROL "",IDC_PRIVATEBYTES,"PhGraph",WS_CLIPSIBLINGS,105,122,50,14 + CONTROL "",IDC_IO,"PhGraph",WS_CLIPSIBLINGS,105,204,50,14 +END + +IDD_PROCSTATISTICS DIALOGEX 0, 0, 260, 260 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Statistics" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + GROUPBOX "CPU",IDC_STATIC,7,7,119,64 + GROUPBOX "I/O",IDC_STATIC,131,7,122,83 + LTEXT "Priority",IDC_STATIC,14,17,24,8 + LTEXT "Cycles",IDC_STATIC,14,27,22,8 + LTEXT "Kernel time",IDC_STATIC,14,37,38,8 + LTEXT "User time",IDC_STATIC,14,47,32,8 + LTEXT "Total time",IDC_STATIC,14,57,34,8 + RTEXT "Static",IDC_ZPRIORITY_V,59,17,61,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZCYCLES_V,43,27,77,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZKERNELTIME_V,59,37,61,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZUSERTIME_V,59,47,61,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZTOTALTIME_V,59,57,61,8,SS_ENDELLIPSIS + GROUPBOX "Memory",IDC_STATIC,7,74,120,128 + LTEXT "Private bytes",IDC_STATIC,14,84,44,8 + LTEXT "Working set",IDC_STATIC,14,136,40,8 + LTEXT "Peak working set",IDC_STATIC,14,178,57,8 + LTEXT "Virtual size",IDC_STATIC,14,105,36,8 + LTEXT "Peak virtual size",IDC_STATIC,14,115,53,8 + LTEXT "Peak private bytes",IDC_STATIC,14,95,61,8 + LTEXT "Page faults",IDC_STATIC,14,125,38,8 + LTEXT "Page priority",IDC_STATIC,14,188,42,8 + RTEXT "Static",IDC_ZPRIVATEBYTES_V,72,84,48,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZWORKINGSET_V,72,136,48,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZPEAKWORKINGSET_V,78,178,42,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZVIRTUALSIZE_V,72,105,48,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZPEAKVIRTUALSIZE_V,72,115,48,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZPEAKPRIVATEBYTES_V,80,95,40,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZPAGEFAULTS_V,72,125,48,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZPAGEPRIORITY_V,72,188,48,8,SS_ENDELLIPSIS + LTEXT "Reads",IDC_STATIC,138,17,21,8 + LTEXT "Read bytes",IDC_STATIC,138,27,38,8 + LTEXT "Writes",IDC_STATIC,138,37,22,8 + LTEXT "Write bytes",IDC_STATIC,138,47,38,8 + LTEXT "Other",IDC_STATIC,138,57,20,8 + LTEXT "Other bytes",IDC_STATIC,138,67,40,8 + LTEXT "I/O priority",IDC_STATIC,138,77,36,8 + RTEXT "Static",IDC_ZIOREADS_V,184,17,63,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZIOREADBYTES_V,184,27,63,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZIOWRITES_V,184,37,63,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZIOWRITEBYTES_V,184,47,63,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZIOOTHER_V,184,57,63,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZIOOTHERBYTES_V,184,67,63,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZIOPRIORITY_V,184,77,63,8,SS_ENDELLIPSIS + GROUPBOX "Other",IDC_STATIC,131,92,122,70 + LTEXT "Handles",IDC_STATIC,138,102,26,8 + LTEXT "GDI handles",IDC_STATIC,138,122,40,8 + LTEXT "USER handles",IDC_STATIC,138,132,46,8 + RTEXT "Static",IDC_ZHANDLES_V,193,102,54,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZGDIHANDLES_V,193,122,54,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZUSERHANDLES_V,193,132,54,8,SS_ENDELLIPSIS + PUSHBUTTON "Details",IDC_DETAILS,137,143,50,14 + LTEXT "Peak handles",IDC_STATIC,138,112,44,8 + RTEXT "Static",IDC_ZPEAKHANDLES_V,192,112,55,8,SS_ENDELLIPSIS + LTEXT "Private WS",IDC_STATIC,22,147,36,8 + LTEXT "Shareable WS",IDC_STATIC,22,157,46,8 + LTEXT "Shared WS",IDC_STATIC,22,167,36,8 + RTEXT "Static",IDC_ZPRIVATEWS_V,78,147,42,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZSHAREABLEWS_V,78,157,42,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZSHAREDWS_V,78,167,42,8,SS_ENDELLIPSIS +END + +IDD_OPTADVANCED DIALOGEX 0, 0, 250, 150 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Advanced" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + CONTROL "Enable warnings",IDC_ENABLEWARNINGS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,7,68,10 + CONTROL "Enable kernel-mode driver",IDC_ENABLEKERNELMODEDRIVER, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,19,99,10 + CONTROL "Hide unnamed handles",IDC_HIDEUNNAMEDHANDLES,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,31,88,10 + CONTROL "Check images for digital signatures and packing",IDC_ENABLESTAGE2, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,43,167,10 + CONTROL "Resolve addresses for network connections",IDC_ENABLENETWORKRESOLVE, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,55,155,10 + CONTROL "Include CPU (and other) usage of children in collapsed processes",IDC_PROPAGATECPUUSAGE, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,67,223,10 + CONTROL "Show tooltips instantly",IDC_ENABLEINSTANTTOOLTIPS, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,79,88,10 + CONTROL "Enable cycle-based CPU usage",IDC_ENABLECYCLECPUUSAGE, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,91,114,10 + CONTROL "Replace Task Manager with Process Hacker",IDC_REPLACETASKMANAGER, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,105,154,10 + PUSHBUTTON "Change...",IDC_CHANGE,161,103,62,14 + LTEXT "History sample count:",IDC_SAMPLECOUNTLABEL,7,121,70,8 + EDITTEXT IDC_SAMPLECOUNT,82,120,39,12,ES_AUTOHSCROLL | ES_NUMBER + CONTROL "Automatic",IDC_SAMPLECOUNTAUTOMATIC,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,126,121,48,10 +END + +IDD_GDIHANDLES DIALOGEX 0, 0, 351, 307 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "GDI Handles" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,7,337,275 + PUSHBUTTON "Refresh",IDC_REFRESH,240,286,50,14 + DEFPUSHBUTTON "Close",IDOK,294,286,50,14 +END + +IDD_LOG DIALOGEX 0, 0, 313, 303 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME +EXSTYLE WS_EX_APPWINDOW +CAPTION "Log" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | LVS_OWNERDATA | LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,7,7,299,272 + PUSHBUTTON "Clear",IDC_CLEAR,7,282,50,14 + CONTROL "Auto-scroll",IDC_AUTOSCROLL,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,61,284,50,10 + PUSHBUTTON "Save...",IDC_SAVE,148,282,50,14 + PUSHBUTTON "Copy",IDC_COPY,202,282,50,14 + DEFPUSHBUTTON "Close",IDOK,256,282,50,14 +END + +IDD_OPTSYMBOLS DIALOGEX 0, 0, 250, 75 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Symbols" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "Dbghelp.dll path:",IDC_STATIC,7,9,56,8 + EDITTEXT IDC_DBGHELPPATH,66,8,123,12,ES_AUTOHSCROLL + PUSHBUTTON "Browse...",IDC_BROWSE,193,7,50,14 + LTEXT "Search path:",IDC_STATIC,7,24,42,8 + EDITTEXT IDC_DBGHELPSEARCHPATH,66,23,177,12,ES_AUTOHSCROLL + CONTROL "Undecorate symbols",IDC_UNDECORATESYMBOLS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,38,81,10 +END + +IDD_MEMEDIT DIALOGEX 0, 0, 441, 269 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME +EXSTYLE WS_EX_APPWINDOW +CAPTION "Memory" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + CONTROL "",IDC_MEMORY,"PhHexEdit",WS_CLIPSIBLINGS | WS_VSCROLL | WS_TABSTOP,7,7,427,239 + PUSHBUTTON "Re-read",IDC_REREAD,7,248,50,14 + PUSHBUTTON "Write",IDC_WRITE,60,248,50,14 + PUSHBUTTON "Go to...",IDC_GOTO,112,248,50,14 + PUSHBUTTON "Save...",IDC_SAVE,331,248,50,14 + PUSHBUTTON "Close",IDOK,384,248,50,14 + COMBOBOX IDC_BYTESPERROW,164,249,86,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP +END + +IDD_MEMPROTECT DIALOGEX 0, 0, 270, 171 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Memory Protection" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + EDITTEXT IDC_INTRO,7,7,256,122,ES_MULTILINE | ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + LTEXT "New value:",IDC_STATIC,120,136,37,8 + EDITTEXT IDC_VALUE,161,135,102,12,ES_AUTOHSCROLL + DEFPUSHBUTTON "OK",IDOK,161,150,50,14 + PUSHBUTTON "Cancel",IDCANCEL,213,150,50,14 +END + +IDD_MEMRESULTS DIALOGEX 0, 0, 313, 266 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME +CAPTION "Results" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "Results.",IDC_INTRO,7,9,299,8 + CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | LVS_OWNERDATA | LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,7,21,299,221 + PUSHBUTTON "Filter",IDC_FILTER,7,245,50,14 + PUSHBUTTON "Save...",IDC_SAVE,149,245,50,14 + PUSHBUTTON "Copy",IDC_COPY,203,245,50,14 + DEFPUSHBUTTON "Close",IDOK,256,245,50,14 +END + +IDD_MEMSTRING DIALOGEX 0, 0, 241, 86 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "String Search" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "Minimum length:",IDC_STATIC,7,8,54,8 + EDITTEXT IDC_MINIMUMLENGTH,67,7,51,12,ES_AUTOHSCROLL + CONTROL "Detect Unicode",IDC_DETECTUNICODE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,22,65,10 + LTEXT "Search in the following types of memory regions:",IDC_STATIC,7,36,157,8 + CONTROL "Private",IDC_PRIVATE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,49,39,10 + CONTROL "Image",IDC_IMAGE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,55,49,36,10 + CONTROL "Mapped",IDC_MAPPED,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,101,49,41,10 + DEFPUSHBUTTON "OK",IDOK,131,65,50,14 + PUSHBUTTON "Cancel",IDCANCEL,184,65,50,14 +END + +IDD_OPTGRAPHS DIALOGEX 0, 0, 250, 156 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Graphs" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + CONTROL "Show text",IDC_SHOWTEXT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,7,49,10 + CONTROL "Use old colors (black background)",IDC_USEOLDCOLORS, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,19,123,10 + CONTROL "Show commit charge instead of physical memory in summary view",IDC_SHOWCOMMITINSUMMARY, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,31,227,10 + LTEXT "CPU kernel:",IDC_STATIC,7,48,39,8 + CONTROL "CPU kernel",IDC_CPUKERNEL,"PhColorBox",WS_CLIPSIBLINGS | WS_TABSTOP,73,46,33,13 + LTEXT "CPU user:",IDC_STATIC,7,65,34,8 + CONTROL "CPU user",IDC_CPUUSER,"PhColorBox",WS_CLIPSIBLINGS | WS_TABSTOP,73,63,33,13 + LTEXT "I/O R+O:",IDC_STATIC,7,82,32,8 + CONTROL "I/O R+O",IDC_IORO,"PhColorBox",WS_CLIPSIBLINGS | WS_TABSTOP,73,80,33,13 + LTEXT "I/O W:",IDC_STATIC,7,98,23,8 + CONTROL "I/O W",IDC_IOW,"PhColorBox",WS_CLIPSIBLINGS | WS_TABSTOP,73,97,33,13 + LTEXT "Private bytes:",IDC_STATIC,7,115,46,8 + CONTROL "Private bytes",IDC_PRIVATE,"PhColorBox",WS_CLIPSIBLINGS | WS_TABSTOP,73,113,33,13 + LTEXT "Physical memory:",IDC_STATIC,7,131,56,8 + CONTROL "Physical memory",IDC_PHYSICAL,"PhColorBox",WS_CLIPSIBLINGS | WS_TABSTOP,73,129,33,13 +END + +IDD_PLUGINS DIALOGEX 0, 0, 291, 272 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Plugins" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,7,277,119 + GROUPBOX "Plugin",IDC_STATIC,7,129,277,118 + LTEXT "Name:",IDC_STATIC,15,141,22,8 + EDITTEXT IDC_NAME,71,141,104,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + LTEXT "Internal name:",IDC_STATIC,15,152,49,8 + EDITTEXT IDC_INTERNALNAME,71,152,203,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + LTEXT "Author:",IDC_STATIC,15,163,26,8 + EDITTEXT IDC_AUTHOR,71,163,203,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + LTEXT "URL:",IDC_STATIC,15,174,16,8 + EDITTEXT IDC_URL,71,174,174,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + CONTROL "Open",IDC_OPENURL,"SysLink",WS_TABSTOP,250,174,26,10 + LTEXT "File name:",IDC_STATIC,15,185,34,8 + EDITTEXT IDC_FILENAME,71,185,203,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + LTEXT "Version:",IDC_STATIC,183,141,27,8 + EDITTEXT IDC_VERSION,215,141,59,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + LTEXT "Description:",IDC_STATIC,15,196,39,8 + EDITTEXT IDC_DESCRIPTION,14,208,211,34,ES_MULTILINE | ES_READONLY + PUSHBUTTON "Disable",IDC_DISABLE,230,211,50,14 + PUSHBUTTON "Options...",IDC_OPTIONS,230,228,50,14 + PUSHBUTTON "Clean up",IDC_CLEANUP,7,251,50,14 + LTEXT "Changes may require a restart to take effect.",IDC_INSTRUCTION,82,254,148,8,NOT WS_VISIBLE + DEFPUSHBUTTON "Close",IDOK,234,251,50,14 +END + +IDD_HANDLESTATS DIALOGEX 0, 0, 219, 175 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Handle Statistics" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,7,205,143 + DEFPUSHBUTTON "Close",IDOK,162,154,50,14 +END + +IDD_PROCRECORD DIALOGEX 0, 0, 260, 202 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Process Record" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "Name:",IDC_STATIC,7,9,22,8 + EDITTEXT IDC_PROCESSNAME,39,9,214,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + LTEXT "Parent:",IDC_STATIC,7,21,25,8 + EDITTEXT IDC_PARENT,39,21,214,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + GROUPBOX "File",IDC_FILE,7,38,246,79 + ICON "",IDC_FILEICON,14,49,20,20 + EDITTEXT IDC_NAME,44,48,182,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + EDITTEXT IDC_COMPANYNAME,44,60,183,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + LTEXT "Version:",IDC_STATIC,15,72,27,8 + EDITTEXT IDC_VERSION,44,72,183,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + LTEXT "Image file name:",IDC_STATIC,15,86,56,8 + EDITTEXT IDC_FILENAME,15,96,211,12,ES_AUTOHSCROLL | ES_READONLY + PUSHBUTTON "Open",IDC_OPENFILENAME,230,95,17,15,BS_ICON + LTEXT "Command line:",IDC_STATIC,7,123,50,8 + EDITTEXT IDC_CMDLINE,65,121,188,12,ES_AUTOHSCROLL | ES_READONLY + LTEXT "Started:",IDC_STATIC,7,139,28,8 + EDITTEXT IDC_STARTED,65,137,188,12,ES_AUTOHSCROLL | ES_READONLY + LTEXT "Terminated:",IDC_STATIC,7,155,40,8 + EDITTEXT IDC_TERMINATED,65,153,188,12,ES_AUTOHSCROLL | ES_READONLY + LTEXT "Session ID:",IDC_STATIC,7,170,37,8 + LTEXT "Static",IDC_SESSIONID,50,170,19,8 + PUSHBUTTON "Properties",IDC_PROPERTIES,150,181,50,14 + DEFPUSHBUTTON "Close",IDOK,203,181,50,14 +END + +IDD_CHOOSEPROCESS DIALOGEX 0, 0, 317, 239 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME +CAPTION "Select a Process" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "Select a process from the list below.",IDC_MESSAGE,7,7,303,8,SS_ENDELLIPSIS + CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,21,303,193 + PUSHBUTTON "Refresh",IDC_REFRESH,7,218,50,14 + DEFPUSHBUTTON "OK",IDOK,205,218,50,14 + PUSHBUTTON "Cancel",IDCANCEL,260,218,50,14 +END + +IDD_PROCSERVICES DIALOGEX 0, 0, 260, 261 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Services" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "Services",IDC_SERVICES_LAYOUT,7,7,246,247,NOT WS_VISIBLE | WS_BORDER +END + +IDD_SHADOWSESSION DIALOGEX 0, 0, 228, 84 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Remote Control" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "To end the remote control session, press this key and the modifiers selected below:",IDC_STATIC,7,7,214,19 + COMBOBOX IDC_VIRTUALKEY,7,27,74,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + CONTROL "Shift",IDC_SHIFT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,47,31,10 + CONTROL "Ctrl",IDC_CTRL,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,49,47,27,10 + CONTROL "Alt",IDC_ALT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,89,47,25,10 + DEFPUSHBUTTON "OK",IDOK,117,63,50,14 + PUSHBUTTON "Cancel",IDCANCEL,171,63,50,14 +END + +IDD_TOKCAPABILITIES DIALOGEX 0, 0, 270, 228 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Capabilities" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,7,256,214 +END + +IDD_TOKATTRIBUTES DIALOGEX 0, 0, 270, 228 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Attributes" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + CONTROL "",IDC_LIST,"PhTreeNew",WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP | 0x32,7,7,256,214,WS_EX_CLIENTEDGE +END + +IDD_SYSINFO_CPU DIALOGEX 0, 0, 316, 195 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_CAPTION | WS_SYSMENU +EXSTYLE WS_EX_CONTROLPARENT +CAPTION "CPU" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + RTEXT "CPU name",IDC_CPUNAME,41,4,274,16,SS_WORDELLIPSIS + LTEXT "CPU",IDC_TITLE,0,0,37,21 + LTEXT "Panel layout",IDC_LAYOUT,0,105,315,88,NOT WS_VISIBLE + LTEXT "Graph layout",IDC_GRAPH_LAYOUT,0,22,315,82,NOT WS_VISIBLE +END + +IDD_SYSINFO_CPUPANEL DIALOGEX 0, 0, 237, 86 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "Utilization:",IDC_STATIC,0,3,34,8 + LTEXT "Speed:",IDC_STATIC,108,3,24,8 + LTEXT "Static",IDC_UTILIZATION,40,0,62,15 + LTEXT "Static",IDC_SPEED,137,0,100,15 + GROUPBOX "System",IDC_STATIC,0,17,97,55 + LTEXT "Processes",IDC_STATIC,7,28,33,8 + LTEXT "Threads",IDC_STATIC,7,38,27,8 + LTEXT "Handles",IDC_STATIC,7,48,26,8 + LTEXT "Uptime",IDC_STATIC,7,58,23,8 + RTEXT "Static",IDC_ZPROCESSES_V,45,28,46,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZTHREADS_V,45,38,46,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZHANDLES_V,45,48,46,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZUPTIME_V,46,58,45,8,SS_ENDELLIPSIS + CONTROL "&Show one graph per CPU",IDC_ONEGRAPHPERCPU,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,0,76,96,10 + GROUPBOX "CPU",IDC_STATIC,101,17,136,55 + LTEXT "Context switches delta",IDC_STATIC,109,28,76,8 + LTEXT "Interrupts delta",IDC_STATIC,109,38,52,8 + LTEXT "DPCs delta",IDC_STATIC,109,48,36,8 + LTEXT "System calls delta",IDC_STATIC,109,58,60,8 + RTEXT "Static",IDC_ZCONTEXTSWITCHESDELTA_V,191,28,40,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZINTERRUPTSDELTA_V,185,39,46,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZDPCSDELTA_V,181,48,50,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZSYSTEMCALLSDELTA_V,179,59,52,8,SS_ENDELLIPSIS +END + +IDD_SYSINFO_MEMPANEL DIALOGEX 0, 0, 358, 171 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + GROUPBOX "Commit charge",IDC_STATIC,0,0,108,44 + LTEXT "Current",IDC_STATIC,7,11,26,8 + LTEXT "Peak",IDC_STATIC,7,21,16,8 + LTEXT "Limit",IDC_STATIC,7,31,15,8 + RTEXT "Static",IDC_ZCOMMITCURRENT_V,45,11,56,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZCOMMITPEAK_V,41,21,60,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZCOMMITLIMIT_V,40,31,61,8,SS_ENDELLIPSIS + GROUPBOX "Physical memory",IDC_STATIC,112,0,118,73 + LTEXT "Current",IDC_STATIC,120,11,26,8 + LTEXT "Cache WS",IDC_STATIC,120,41,34,8 + RTEXT "Static",IDC_ZPHYSICALCURRENT_V,165,11,57,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZPHYSICALTOTAL_V,167,21,55,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZPHYSICALCACHEWS_V,159,41,63,8,SS_ENDELLIPSIS + LTEXT "Total",IDC_STATIC,120,21,17,8 + LTEXT "Kernel WS",IDC_STATIC,120,51,34,8 + RTEXT "Static",IDC_ZPHYSICALKERNELWS_V,167,51,55,8,SS_ENDELLIPSIS + LTEXT "Driver WS",IDC_STATIC,120,61,33,8 + RTEXT "Static",IDC_ZPHYSICALDRIVERWS_V,163,61,59,8,SS_ENDELLIPSIS + GROUPBOX "Paged pool",IDC_STATIC,0,47,108,64 + LTEXT "Working set",IDC_STATIC,7,58,40,8 + LTEXT "Limit",IDC_STATIC,7,78,15,8 + RTEXT "Static",IDC_ZPAGEDWORKINGSET_V,54,58,47,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZPAGEDVIRTUALSIZE_V,52,68,49,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZPAGEDLIMIT_V,48,78,53,8,SS_ENDELLIPSIS + LTEXT "Virtual size",IDC_STATIC,7,68,36,8 + LTEXT "Allocs delta",IDC_STATIC,7,88,38,8 + RTEXT "Static",IDC_ZPAGEDALLOCSDELTA_V,53,88,48,8,SS_ENDELLIPSIS + LTEXT "Frees delta",IDC_STATIC,7,98,38,8 + RTEXT "Static",IDC_ZPAGEDFREESDELTA_V,51,98,50,8,SS_ENDELLIPSIS + GROUPBOX "Non-paged pool",IDC_STATIC,0,114,108,55 + LTEXT "Usage",IDC_STATIC,7,125,21,8 + LTEXT "Allocs delta",IDC_STATIC,7,145,38,8 + RTEXT "Static",IDC_ZNONPAGEDUSAGE_V,54,125,47,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZNONPAGEDLIMIT_V,52,135,49,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZNONPAGEDALLOCSDELTA_V,56,145,45,8,SS_ENDELLIPSIS + LTEXT "Limit",IDC_STATIC,7,135,15,8 + LTEXT "Frees delta",IDC_STATIC,7,155,38,8 + RTEXT "Static",IDC_ZNONPAGEDFREESDELTA_V,56,155,45,8,SS_ENDELLIPSIS + GROUPBOX "Memory lists",IDC_STATIC,234,0,123,169 + LTEXT "Zeroed",IDC_STATIC,242,11,24,8 + LTEXT "Modified",IDC_STATIC,242,31,28,8 + RTEXT "Static",IDC_ZLISTZEROED_V,304,11,47,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZLISTFREE_V,302,21,49,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZLISTMODIFIED_V,298,31,53,8,SS_ENDELLIPSIS + LTEXT "Free",IDC_STATIC,242,21,16,8 + LTEXT "Modified no-write",IDC_STATIC,242,41,56,8 + RTEXT "Static",IDC_ZLISTMODIFIEDNOWRITE_V,303,41,48,8,SS_ENDELLIPSIS + LTEXT "Standby",IDC_STATIC,242,61,28,8 + LTEXT "Priority 0",IDC_STATIC,251,71,30,8 + LTEXT "Priority 1",IDC_STATIC,251,80,30,8 + LTEXT "Priority 2",IDC_STATIC,251,90,30,8 + LTEXT "Priority 3",IDC_STATIC,251,100,30,8 + LTEXT "Priority 4",IDC_STATIC,251,110,30,8 + LTEXT "Priority 5",IDC_STATIC,251,120,30,8 + LTEXT "Priority 6",IDC_STATIC,251,130,30,8 + LTEXT "Priority 7",IDC_STATIC,251,140,30,8 + RTEXT "Static",IDC_ZLISTSTANDBY_V,303,61,48,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZLISTSTANDBY0_V,303,71,48,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZLISTSTANDBY1_V,303,80,48,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZLISTSTANDBY2_V,303,90,48,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZLISTSTANDBY3_V,303,100,48,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZLISTSTANDBY4_V,303,110,48,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZLISTSTANDBY5_V,303,120,48,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZLISTSTANDBY6_V,303,130,48,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZLISTSTANDBY7_V,303,140,48,8,SS_ENDELLIPSIS + GROUPBOX "Paging",IDC_STATIC,112,75,118,55 + LTEXT "Page faults delta",IDC_STATIC,120,86,57,8 + LTEXT "Pagefile writes delta",IDC_STATIC,120,106,68,8 + RTEXT "Static",IDC_ZPAGINGPAGEFAULTSDELTA_V,183,86,39,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZPAGINGPAGEREADSDELTA_V,179,96,43,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZPAGINGPAGEFILEWRITESDELTA_V,189,106,33,8,SS_ENDELLIPSIS + LTEXT "Page reads delta",IDC_STATIC,120,96,58,8 + LTEXT "Mapped writes delta",IDC_STATIC,120,116,68,8 + RTEXT "Static",IDC_ZPAGINGMAPPEDWRITESDELTA_V,191,116,31,8,SS_ENDELLIPSIS + LTEXT "Modified pagefile",IDC_STATIC,242,51,55,8 + RTEXT "Static",IDC_ZLISTMODIFIEDPAGEFILE_V,303,51,48,8,SS_ENDELLIPSIS + PUSHBUTTON "&More",IDC_MORE,242,152,50,14 + RTEXT "Static",IDC_ZPHYSICALRESERVED_V,167,31,55,8,SS_ENDELLIPSIS + LTEXT "Reserved",IDC_STATIC,120,31,32,8 +END + +IDD_SYSINFO_MEM DIALOGEX 0, 0, 316, 250 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_CAPTION | WS_SYSMENU +EXSTYLE WS_EX_CONTROLPARENT +CAPTION "Memory" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "Memory",IDC_TITLE,0,0,110,21 + LTEXT "Panel layout",IDC_LAYOUT,0,74,315,175,NOT WS_VISIBLE + LTEXT "Graph layout",IDC_GRAPH_LAYOUT,0,22,315,51,NOT WS_VISIBLE + RTEXT "Total physical",IDC_TOTALPHYSICAL,127,4,188,16,SS_WORDELLIPSIS + LTEXT "Commit charge:",IDC_COMMIT_L,111,1,52,8 + LTEXT "Physical memory:",IDC_PHYSICAL_L,111,7,56,8 +END + +IDD_SYSINFO_IO DIALOGEX 0, 0, 316, 187 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_CAPTION | WS_SYSMENU +CAPTION "I/O" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "I/O",IDC_TITLE,0,0,110,21 + LTEXT "Panel layout",IDC_LAYOUT,0,109,315,78,NOT WS_VISIBLE + LTEXT "Graph layout",IDC_GRAPH_LAYOUT,0,22,315,84,NOT WS_VISIBLE +END + +IDD_SYSINFO_IOPANEL DIALOGEX 0, 0, 276, 75 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + GROUPBOX "I/O deltas",IDC_STATIC,0,0,133,74 + LTEXT "Reads delta",IDC_STATIC,7,11,40,8 + LTEXT "Read bytes delta",IDC_STATIC,7,21,56,8 + LTEXT "Writes delta",IDC_STATIC,7,31,40,8 + LTEXT "Write bytes delta",IDC_STATIC,7,41,57,8 + RTEXT "Static",IDC_ZREADSDELTA_V,59,11,67,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZREADBYTESDELTA_V,75,21,51,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZWRITESDELTA_V,57,31,69,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZWRITEBYTESDELTA_V,73,41,53,8,SS_ENDELLIPSIS + LTEXT "Other delta",IDC_STATIC,7,51,38,8 + LTEXT "Other bytes delta",IDC_STATIC,7,61,58,8 + RTEXT "Static",IDC_ZOTHERDELTA_V,67,51,59,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZOTHERBYTESDELTA_V,81,61,45,8,SS_ENDELLIPSIS + GROUPBOX "I/O totals",IDC_STATIC,137,0,133,74 + LTEXT "Reads",IDC_STATIC,145,11,21,8 + LTEXT "Read bytes",IDC_STATIC,145,21,38,8 + LTEXT "Writes",IDC_STATIC,145,31,22,8 + LTEXT "Write bytes",IDC_STATIC,145,41,38,8 + RTEXT "Static",IDC_ZREADS_V,197,11,67,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZREADBYTES_V,192,21,72,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZWRITES_V,195,31,69,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZWRITEBYTES_V,190,41,74,8,SS_ENDELLIPSIS + LTEXT "Other",IDC_STATIC,145,51,20,8 + LTEXT "Other bytes",IDC_STATIC,145,61,40,8 + RTEXT "Static",IDC_ZOTHER_V,191,51,73,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZOTHERBYTES_V,192,61,72,8,SS_ENDELLIPSIS +END + +IDD_MEMLISTS DIALOGEX 0, 0, 228, 195 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU +EXSTYLE WS_EX_TOPMOST +CAPTION "Memory Lists" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + DEFPUSHBUTTON "Close",IDOK,171,174,50,14 + LTEXT "Zeroed",IDC_STATIC,7,7,24,8 + LTEXT "Free",IDC_STATIC,7,17,16,8 + LTEXT "Modified",IDC_STATIC,7,28,28,8 + LTEXT "Modified no-write",IDC_STATIC,7,39,56,8 + LTEXT "Bad",IDC_STATIC,7,60,13,8 + LTEXT "Standby",IDC_STATIC,7,72,28,8 + LTEXT "Priority 0",IDC_STATIC,23,83,30,8 + LTEXT "Priority 1",IDC_STATIC,23,94,30,8 + LTEXT "Priority 2",IDC_STATIC,23,105,30,8 + LTEXT "Priority 3",IDC_STATIC,23,116,30,8 + LTEXT "Priority 4",IDC_STATIC,23,128,30,8 + LTEXT "Priority 5",IDC_STATIC,23,139,30,8 + LTEXT "Priority 6",IDC_STATIC,23,150,30,8 + LTEXT "Priority 7",IDC_STATIC,23,161,30,8 + RTEXT "Static",IDC_ZLISTZEROED_V,73,7,59,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZLISTFREE_V,73,17,59,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZLISTMODIFIED_V,73,28,59,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZLISTMODIFIEDNOWRITE_V,73,39,59,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZLISTBAD_V,73,60,59,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZLISTSTANDBY_V,73,72,59,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZLISTSTANDBY0_V,73,83,59,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZLISTSTANDBY1_V,73,94,59,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZLISTSTANDBY2_V,73,105,59,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZLISTSTANDBY3_V,73,116,59,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZLISTSTANDBY4_V,73,128,59,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZLISTSTANDBY5_V,73,139,59,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZLISTSTANDBY6_V,73,150,59,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZLISTSTANDBY7_V,73,161,59,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZLISTREPURPOSED_V,162,72,59,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZLISTREPURPOSED0_V,162,84,59,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZLISTREPURPOSED1_V,162,95,59,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZLISTREPURPOSED2_V,162,106,59,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZLISTREPURPOSED3_V,162,117,59,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZLISTREPURPOSED4_V,162,128,59,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZLISTREPURPOSED5_V,162,139,59,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZLISTREPURPOSED6_V,162,150,59,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZLISTREPURPOSED7_V,162,161,59,8,SS_ENDELLIPSIS + RTEXT "(Repurposed)",IDC_STATIC,162,60,59,8 + PUSHBUTTON "&Empty",IDC_EMPTY,117,174,50,14 + LTEXT "Modified pagefile",IDC_STATIC,7,49,55,8 + RTEXT "Static",IDC_ZLISTMODIFIEDPAGEFILE_V,73,49,59,8,SS_ENDELLIPSIS +END + +IDD_CONTAINER DIALOGEX 0, 0, 316, 182 +STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_SYSMENU +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN +END + +IDD_SYSINFO_MEMPANELXP DIALOGEX 0, 0, 230, 171 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + GROUPBOX "Commit charge",-1,0,0,108,44 + LTEXT "Current",-1,7,11,26,8 + LTEXT "Peak",-1,7,21,16,8 + LTEXT "Limit",-1,7,31,15,8 + RTEXT "Static",IDC_ZCOMMITCURRENT_V,45,11,56,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZCOMMITPEAK_V,41,21,60,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZCOMMITLIMIT_V,40,31,61,8,SS_ENDELLIPSIS + GROUPBOX "Physical memory",-1,112,0,118,64 + LTEXT "Current",-1,120,11,26,8 + LTEXT "Cache WS",-1,120,31,34,8 + RTEXT "Static",IDC_ZPHYSICALCURRENT_V,165,11,57,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZPHYSICALTOTAL_V,167,21,55,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZPHYSICALCACHEWS_V,159,31,63,8,SS_ENDELLIPSIS + LTEXT "Total",-1,120,21,17,8 + LTEXT "Kernel WS",-1,120,41,34,8 + RTEXT "Static",IDC_ZPHYSICALKERNELWS_V,167,41,55,8,SS_ENDELLIPSIS + LTEXT "Driver WS",-1,120,51,33,8 + RTEXT "Static",IDC_ZPHYSICALDRIVERWS_V,163,51,59,8,SS_ENDELLIPSIS + GROUPBOX "Paged pool",-1,0,47,108,64 + LTEXT "Working set",-1,7,58,40,8 + LTEXT "Limit",-1,7,78,15,8 + RTEXT "Static",IDC_ZPAGEDWORKINGSET_V,54,58,47,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZPAGEDVIRTUALSIZE_V,52,68,49,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZPAGEDLIMIT_V,48,78,53,8,SS_ENDELLIPSIS + LTEXT "Virtual size",-1,7,68,36,8 + LTEXT "Allocs delta",-1,7,88,38,8 + RTEXT "Static",IDC_ZPAGEDALLOCSDELTA_V,53,88,48,8,SS_ENDELLIPSIS + LTEXT "Frees delta",-1,7,98,38,8 + RTEXT "Static",IDC_ZPAGEDFREESDELTA_V,51,98,50,8,SS_ENDELLIPSIS + GROUPBOX "Non-paged pool",-1,0,114,108,55 + LTEXT "Usage",-1,7,125,21,8 + LTEXT "Allocs delta",-1,7,145,38,8 + RTEXT "Static",IDC_ZNONPAGEDUSAGE_V,54,125,47,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZNONPAGEDLIMIT_V,52,135,49,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZNONPAGEDALLOCSDELTA_V,56,145,45,8,SS_ENDELLIPSIS + LTEXT "Limit",-1,7,135,15,8 + LTEXT "Frees delta",-1,7,155,38,8 + RTEXT "Static",IDC_ZNONPAGEDFREESDELTA_V,56,155,45,8,SS_ENDELLIPSIS + GROUPBOX "Paging",-1,112,67,118,55 + LTEXT "Page faults delta",-1,120,78,57,8 + LTEXT "Pagefile writes delta",-1,120,98,68,8 + RTEXT "Static",IDC_ZPAGINGPAGEFAULTSDELTA_V,183,78,39,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZPAGINGPAGEREADSDELTA_V,179,88,43,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZPAGINGPAGEFILEWRITESDELTA_V,189,98,33,8,SS_ENDELLIPSIS + LTEXT "Page reads delta",-1,120,88,58,8 + LTEXT "Mapped writes delta",-1,120,108,68,8 + RTEXT "Static",IDC_ZPAGINGMAPPEDWRITESDELTA_V,191,108,31,8,SS_ENDELLIPSIS +END + +IDD_MINIINFO DIALOGEX 0, 0, 217, 150 +STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "Content layout",IDC_LAYOUT,4,3,210,128,NOT WS_VISIBLE + CONTROL "Section",IDC_SECTION,"Static",SS_LEFTNOWORDWRAP | SS_NOTIFY | SS_ENDELLIPSIS | WS_GROUP,4,134,177,13 + PUSHBUTTON "Options",IDC_OPTIONS,183,133,15,14,BS_ICON + CONTROL "Pin",IDC_PIN,"Button",BS_AUTOCHECKBOX | BS_ICON | BS_PUSHLIKE | WS_TABSTOP,199,133,15,14 +END + +IDD_MINIINFO_LIST DIALOGEX 0, 0, 217, 141 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "CPU" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + CONTROL "",IDC_LIST,"PhTreeNew",WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP | 0x82,0,0,217,140,WS_EX_CLIENTEDGE +END + +IDD_MITIGATION DIALOGEX 0, 0, 277, 217 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Mitigation Policies" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,7,263,108 + LTEXT "Description:",IDC_DESCRIPTIONLABEL,7,118,38,8 + EDITTEXT IDC_DESCRIPTION,7,129,263,62,ES_MULTILINE | ES_READONLY | WS_VSCROLL + DEFPUSHBUTTON "OK",IDOK,220,196,50,14 +END + +IDD_EDITENV DIALOGEX 0, 0, 311, 177 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME +CAPTION "Edit Environment Variable" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "Name:",IDC_STATIC,7,8,21,8 + EDITTEXT IDC_NAME,38,7,266,12,ES_AUTOHSCROLL + LTEXT "Value:",IDC_STATIC,7,25,21,8 + EDITTEXT IDC_VALUE,38,24,266,128,ES_MULTILINE | WS_VSCROLL + DEFPUSHBUTTON "OK",IDOK,200,156,50,14 + PUSHBUTTON "Cancel",IDCANCEL,254,156,50,14 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_PROCGENERAL, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 253 + TOPMARGIN, 7 + BOTTOMMARGIN, 253 + END + + IDD_PROCMODULES, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 253 + TOPMARGIN, 7 + BOTTOMMARGIN, 253 + END + + IDD_PROCTHREADS, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 253 + TOPMARGIN, 7 + BOTTOMMARGIN, 253 + END + + IDD_PROCHANDLES, DIALOG + BEGIN + LEFTMARGIN, 2 + RIGHTMARGIN, 258 + TOPMARGIN, 3 + BOTTOMMARGIN, 258 + END + + IDD_PROCENVIRONMENT, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 253 + TOPMARGIN, 7 + BOTTOMMARGIN, 253 + END + + IDD_THRDSTACK, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 254 + TOPMARGIN, 7 + BOTTOMMARGIN, 221 + END + + IDD_ABOUT, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 263 + TOPMARGIN, 7 + BOTTOMMARGIN, 188 + END + + IDD_SRVLIST, DIALOG + BEGIN + END + + IDD_SRVGENERAL, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 275 + TOPMARGIN, 7 + BOTTOMMARGIN, 176 + END + + IDD_HNDLGENERAL, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 253 + TOPMARGIN, 7 + BOTTOMMARGIN, 174 + END + + IDD_INFORMATION, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 310 + TOPMARGIN, 7 + BOTTOMMARGIN, 177 + END + + IDD_FINDOBJECTS, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 350 + TOPMARGIN, 7 + BOTTOMMARGIN, 226 + END + + IDD_OBJTOKEN, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 253 + TOPMARGIN, 7 + BOTTOMMARGIN, 253 + END + + IDD_HIDDENPROCESSES, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 330 + TOPMARGIN, 7 + BOTTOMMARGIN, 214 + END + + IDD_RUNAS, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 271 + TOPMARGIN, 7 + BOTTOMMARGIN, 120 + END + + IDD_PROGRESS, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 209 + TOPMARGIN, 7 + BOTTOMMARGIN, 55 + END + + IDD_PAGEFILES, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 315 + TOPMARGIN, 7 + BOTTOMMARGIN, 155 + END + + IDD_TOKGENERAL, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 263 + TOPMARGIN, 7 + BOTTOMMARGIN, 221 + END + + IDD_TOKADVANCED, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 229 + TOPMARGIN, 7 + BOTTOMMARGIN, 179 + END + + IDD_OBJJOB, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 253 + TOPMARGIN, 7 + BOTTOMMARGIN, 253 + END + + IDD_OBJEVENT, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 179 + TOPMARGIN, 7 + BOTTOMMARGIN, 69 + END + + IDD_OBJMUTANT, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 179 + TOPMARGIN, 7 + BOTTOMMARGIN, 69 + END + + IDD_OBJSEMAPHORE, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 179 + TOPMARGIN, 7 + BOTTOMMARGIN, 69 + END + + IDD_OBJTIMER, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 179 + TOPMARGIN, 7 + BOTTOMMARGIN, 69 + END + + IDD_JOBSTATISTICS, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 252 + TOPMARGIN, 7 + BOTTOMMARGIN, 179 + END + + IDD_OBJEVENTPAIR, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 179 + TOPMARGIN, 7 + BOTTOMMARGIN, 69 + END + + IDD_OBJSECTION, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 248 + TOPMARGIN, 7 + BOTTOMMARGIN, 69 + END + + IDD_AFFINITY, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 272 + TOPMARGIN, 7 + BOTTOMMARGIN, 220 + END + + IDD_SYSINFO, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 416 + TOPMARGIN, 7 + BOTTOMMARGIN, 240 + END + + IDD_EDITMESSAGE, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 275 + TOPMARGIN, 7 + BOTTOMMARGIN, 156 + END + + IDD_SESSION, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 194 + TOPMARGIN, 7 + BOTTOMMARGIN, 142 + END + + IDD_PROCMEMORY, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 253 + TOPMARGIN, 7 + BOTTOMMARGIN, 253 + END + + IDD_CHOOSE, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 192 + TOPMARGIN, 7 + BOTTOMMARGIN, 66 + END + + IDD_OPTGENERAL, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 243 + TOPMARGIN, 7 + BOTTOMMARGIN, 147 + END + + IDD_OPTHIGHLIGHTING, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 243 + TOPMARGIN, 7 + BOTTOMMARGIN, 167 + END + + IDD_CHOOSECOLUMNS, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 374 + TOPMARGIN, 7 + BOTTOMMARGIN, 200 + END + + IDD_NETSTACK, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 254 + TOPMARGIN, 7 + BOTTOMMARGIN, 221 + END + + IDD_CREATESERVICE, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 280 + TOPMARGIN, 7 + BOTTOMMARGIN, 126 + END + + IDD_PROCPERFORMANCE, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 253 + TOPMARGIN, 7 + BOTTOMMARGIN, 253 + END + + IDD_PROCSTATISTICS, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 253 + TOPMARGIN, 7 + BOTTOMMARGIN, 253 + END + + IDD_OPTADVANCED, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 243 + TOPMARGIN, 7 + BOTTOMMARGIN, 143 + END + + IDD_GDIHANDLES, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 344 + TOPMARGIN, 7 + BOTTOMMARGIN, 300 + END + + IDD_LOG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 306 + TOPMARGIN, 7 + BOTTOMMARGIN, 296 + END + + IDD_OPTSYMBOLS, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 243 + TOPMARGIN, 7 + BOTTOMMARGIN, 68 + END + + IDD_MEMEDIT, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 434 + TOPMARGIN, 7 + BOTTOMMARGIN, 262 + END + + IDD_MEMPROTECT, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 263 + TOPMARGIN, 7 + BOTTOMMARGIN, 164 + END + + IDD_MEMRESULTS, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 306 + TOPMARGIN, 7 + BOTTOMMARGIN, 259 + END + + IDD_MEMSTRING, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 234 + TOPMARGIN, 7 + BOTTOMMARGIN, 79 + END + + IDD_OPTGRAPHS, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 243 + TOPMARGIN, 7 + BOTTOMMARGIN, 149 + END + + IDD_PLUGINS, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 284 + TOPMARGIN, 7 + BOTTOMMARGIN, 265 + END + + IDD_HANDLESTATS, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 212 + TOPMARGIN, 7 + BOTTOMMARGIN, 168 + END + + IDD_PROCRECORD, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 253 + TOPMARGIN, 7 + BOTTOMMARGIN, 195 + END + + IDD_CHOOSEPROCESS, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 310 + TOPMARGIN, 7 + BOTTOMMARGIN, 232 + END + + IDD_PROCSERVICES, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 253 + TOPMARGIN, 7 + BOTTOMMARGIN, 254 + END + + IDD_SHADOWSESSION, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 221 + TOPMARGIN, 7 + BOTTOMMARGIN, 77 + END + + IDD_TOKCAPABILITIES, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 263 + TOPMARGIN, 7 + BOTTOMMARGIN, 221 + END + + IDD_TOKATTRIBUTES, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 263 + TOPMARGIN, 7 + BOTTOMMARGIN, 221 + END + + IDD_SYSINFO_CPU, DIALOG + BEGIN + BOTTOMMARGIN, 193 + END + + IDD_SYSINFO_CPUPANEL, DIALOG + BEGIN + BOTTOMMARGIN, 85 + END + + IDD_SYSINFO_MEMPANEL, DIALOG + BEGIN + END + + IDD_SYSINFO_MEM, DIALOG + BEGIN + BOTTOMMARGIN, 247 + END + + IDD_SYSINFO_IO, DIALOG + BEGIN + END + + IDD_SYSINFO_IOPANEL, DIALOG + BEGIN + BOTTOMMARGIN, 74 + END + + IDD_MEMLISTS, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 221 + TOPMARGIN, 7 + BOTTOMMARGIN, 188 + END + + IDD_CONTAINER, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 309 + TOPMARGIN, 7 + BOTTOMMARGIN, 175 + END + + IDD_SYSINFO_MEMPANELXP, DIALOG + BEGIN + END + + IDD_MINIINFO, DIALOG + BEGIN + LEFTMARGIN, 4 + RIGHTMARGIN, 214 + TOPMARGIN, 3 + BOTTOMMARGIN, 147 + END + + IDD_MINIINFO_LIST, DIALOG + BEGIN + END + + IDD_MITIGATION, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 270 + TOPMARGIN, 7 + BOTTOMMARGIN, 210 + END + + IDD_EDITENV, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 304 + TOPMARGIN, 7 + BOTTOMMARGIN, 170 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Accelerator +// + +IDR_MAINWND_ACCEL ACCELERATORS +BEGIN + VK_ESCAPE, ID_ESC_EXIT, VIRTKEY, NOINVERT + "F", ID_HACKER_FINDHANDLESORDLLS, VIRTKEY, CONTROL, NOINVERT + "R", ID_HACKER_RUN, VIRTKEY, CONTROL, NOINVERT + "R", ID_HACKER_RUNAS, VIRTKEY, SHIFT, CONTROL, NOINVERT + "S", ID_HACKER_SAVE, VIRTKEY, CONTROL, NOINVERT + "L", ID_HELP_LOG, VIRTKEY, CONTROL, NOINVERT + "M", ID_PROCESS_SEARCHONLINE, VIRTKEY, CONTROL, NOINVERT + VK_TAB, ID_TAB_NEXT, VIRTKEY, CONTROL, NOINVERT + VK_TAB, ID_TAB_PREV, VIRTKEY, SHIFT, CONTROL, NOINVERT + VK_F5, ID_VIEW_REFRESH, VIRTKEY, NOINVERT + "I", ID_VIEW_SYSTEMINFORMATION, VIRTKEY, CONTROL, NOINVERT + VK_PAUSE, ID_VIEW_UPDATEAUTOMATICALLY, VIRTKEY, NOINVERT + VK_F6, ID_VIEW_UPDATEAUTOMATICALLY, VIRTKEY, NOINVERT +END + +IDR_SYSINFO_ACCEL ACCELERATORS +BEGIN + "1", ID_DIGIT1, VIRTKEY, NOINVERT + "2", ID_DIGIT2, VIRTKEY, NOINVERT + "3", ID_DIGIT3, VIRTKEY, NOINVERT + "4", ID_DIGIT4, VIRTKEY, NOINVERT + "5", ID_DIGIT5, VIRTKEY, NOINVERT + "6", ID_DIGIT6, VIRTKEY, NOINVERT + "7", ID_DIGIT7, VIRTKEY, NOINVERT + "8", ID_DIGIT8, VIRTKEY, NOINVERT + "9", ID_DIGIT9, VIRTKEY, NOINVERT + "B", IDC_BACK, VIRTKEY, ALT, NOINVERT + VK_BACK, IDC_BACK, VIRTKEY, NOINVERT + VK_F6, IDC_PAUSE, VIRTKEY, NOINVERT + VK_PAUSE, IDC_PAUSE, VIRTKEY, NOINVERT + VK_F5, IDC_REFRESH, VIRTKEY, NOINVERT + VK_F11, IDC_MAXSCREEN, VIRTKEY, NOINVERT +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Bitmap +// + +IDB_CROSS BITMAP "resources\\cross.bmp" + +IDB_TICK BITMAP "resources\\tick.bmp" + +IDB_SEARCH_ACTIVE_BMP BITMAP "resources\\active_search.bmp" + +IDB_SEARCH_INACTIVE_BMP BITMAP "resources\\inactive_search.bmp" + + +///////////////////////////////////////////////////////////////////////////// +// +// RT_MANIFEST +// + +IDR_RT_MANIFEST RT_MANIFEST "ProcessHacker.manifest" + + +///////////////////////////////////////////////////////////////////////////// +// +// AFX_DIALOG_LAYOUT +// + +IDD_FINDOBJECTS AFX_DIALOG_LAYOUT +BEGIN + 0 +END + +IDD_OPTADVANCED AFX_DIALOG_LAYOUT +BEGIN + 0 +END + +IDD_SYSINFO_MEMPANEL AFX_DIALOG_LAYOUT +BEGIN + 0 +END + +IDD_ABOUT AFX_DIALOG_LAYOUT +BEGIN + 0 +END + +IDD_PROCGENERAL AFX_DIALOG_LAYOUT +BEGIN + 0 +END + +IDD_MITIGATION AFX_DIALOG_LAYOUT +BEGIN + 0 +END + +IDD_INFORMATION AFX_DIALOG_LAYOUT +BEGIN + 0 +END + +IDD_OPTGENERAL AFX_DIALOG_LAYOUT +BEGIN + 0 +END + +IDD_MINIINFO AFX_DIALOG_LAYOUT +BEGIN + 0 +END + +IDD_PROCTHREADS AFX_DIALOG_LAYOUT +BEGIN + 0 +END + +IDD_PROCRECORD AFX_DIALOG_LAYOUT +BEGIN + 0 +END + +IDD_PROCENVIRONMENT AFX_DIALOG_LAYOUT +BEGIN + 0 +END + +IDD_EDITENV AFX_DIALOG_LAYOUT +BEGIN + 0 +END + +IDD_PROCHANDLES AFX_DIALOG_LAYOUT +BEGIN + 0 +END + +IDD_OBJTOKEN AFX_DIALOG_LAYOUT +BEGIN + 0 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// PNG +// + +IDB_SEARCH_ACTIVE PNG "resources\\active_search.png" + +IDB_SEARCH_INACTIVE PNG "resources\\inactive_search.png" + +#endif // English (Australia) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/ProcessHacker/ProcessHacker.vcxproj b/ProcessHacker/ProcessHacker.vcxproj index dc1045b9f277..8f2a2bbc1f1f 100644 --- a/ProcessHacker/ProcessHacker.vcxproj +++ b/ProcessHacker/ProcessHacker.vcxproj @@ -1,454 +1,454 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {0271DD27-6707-4290-8DFE-285702B7115D} - ProcessHacker - Win32Proj - 10.0.15063.0 - - - - Application - Unicode - true - v141 - - - Application - Unicode - v141 - - - Application - Unicode - true - v141 - - - Application - Unicode - v141 - - - - - - - - - - - - - - - - - - - $(SolutionDir)bin\$(Configuration)$(PlatformArchitecture)\ - $(ProjectDir)obj\$(Configuration)$(PlatformArchitecture)\ - false - $(SolutionDir)bin\$(Configuration)$(PlatformArchitecture)\ - $(ProjectDir)obj\$(Configuration)$(PlatformArchitecture)\ - false - $(SolutionDir)bin\$(Configuration)$(PlatformArchitecture)\ - $(ProjectDir)obj\$(Configuration)$(PlatformArchitecture)\ - false - $(SolutionDir)bin\$(Configuration)$(PlatformArchitecture)\ - $(ProjectDir)obj\$(Configuration)$(PlatformArchitecture)\ - false - false - false - false - false - - - - Disabled - ..\phnt\include;..\phlib\include;include;%(AdditionalIncludeDirectories) - _PHLIB_;_PHAPP_;_WINDOWS;WIN32;DEBUG;%(PreprocessorDefinitions) - EnableFastChecks - MultiThreadedDebug - Level3 - ProgramDatabase - StdCall - true - true - - - aclui.lib;comctl32.lib;iphlpapi.lib;noarg.obj;noenv.obj;ntdll.lib;phlib.lib;uxtheme.lib;version.lib;windowscodecs.lib;winsta.lib;ws2_32.lib;%(AdditionalDependencies) - true - Windows - MachineX86 - 6.01 - ..\phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) - ProcessHacker.def - aclui.dll;iphlpapi.dll;ws2_32.dll;%(DelayLoadDLLs) - - - ..\tools\CustomBuildTool\bin\Release\CustomBuildTool.exe -updaterev - Generating revision number... - - - - - - - - - - - Disabled - ..\phnt\include;..\phlib\include;include;%(AdditionalIncludeDirectories) - _PHLIB_;_PHAPP_;_WINDOWS;WIN64;DEBUG;%(PreprocessorDefinitions) - EnableFastChecks - MultiThreadedDebug - Level3 - ProgramDatabase - StdCall - true - true - - - aclui.lib;comctl32.lib;iphlpapi.lib;noarg.obj;noenv.obj;ntdll.lib;phlib.lib;uxtheme.lib;version.lib;windowscodecs.lib;winsta.lib;ws2_32.lib;%(AdditionalDependencies) - true - Windows - MachineX64 - 6.01 - ..\phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) - ProcessHacker.def - aclui.dll;iphlpapi.dll;ws2_32.dll;%(DelayLoadDLLs) - - - ..\tools\CustomBuildTool\bin\Release\CustomBuildTool.exe -updaterev - Generating revision number... - - - - - - - - - - - MaxSpeed - true - ..\phnt\include;..\phlib\include;include;%(AdditionalIncludeDirectories) - _PHLIB_;_PHAPP_;_WINDOWS;WIN32;NDEBUG;%(PreprocessorDefinitions) - true - MultiThreaded - false - true - Level3 - ProgramDatabase - StdCall - true - true - StreamingSIMDExtensions - - - aclui.lib;comctl32.lib;iphlpapi.lib;noarg.obj;noenv.obj;ntdll.lib;phlib.lib;uxtheme.lib;version.lib;windowscodecs.lib;winsta.lib;ws2_32.lib;%(AdditionalDependencies) - true - Windows - true - true - MachineX86 - true - 6.01 - ..\phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) - ProcessHacker.def - aclui.dll;iphlpapi.dll;ws2_32.dll;%(DelayLoadDLLs) - - - ..\tools\CustomBuildTool\bin\Release\CustomBuildTool.exe -updaterev - Generating revision number... - - - - - - - - - - - MaxSpeed - true - ..\phnt\include;..\phlib\include;include;%(AdditionalIncludeDirectories) - _PHLIB_;_PHAPP_;_WINDOWS;WIN64;NDEBUG;%(PreprocessorDefinitions) - true - MultiThreaded - false - true - Level3 - ProgramDatabase - StdCall - true - true - - - aclui.lib;comctl32.lib;iphlpapi.lib;noarg.obj;noenv.obj;ntdll.lib;phlib.lib;uxtheme.lib;version.lib;windowscodecs.lib;winsta.lib;ws2_32.lib;%(AdditionalDependencies) - true - Windows - true - true - MachineX64 - true - 6.01 - ..\phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) - ProcessHacker.def - aclui.dll;iphlpapi.dll;ws2_32.dll;%(DelayLoadDLLs) - - - ..\tools\CustomBuildTool\bin\Release\CustomBuildTool.exe -updaterev - Generating revision number... - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Designer - - - - - - - - - - - - - - - + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {0271DD27-6707-4290-8DFE-285702B7115D} + ProcessHacker + Win32Proj + 10.0.15063.0 + + + + Application + Unicode + true + v141 + + + Application + Unicode + v141 + + + Application + Unicode + true + v141 + + + Application + Unicode + v141 + + + + + + + + + + + + + + + + + + + $(SolutionDir)bin\$(Configuration)$(PlatformArchitecture)\ + $(ProjectDir)obj\$(Configuration)$(PlatformArchitecture)\ + false + $(SolutionDir)bin\$(Configuration)$(PlatformArchitecture)\ + $(ProjectDir)obj\$(Configuration)$(PlatformArchitecture)\ + false + $(SolutionDir)bin\$(Configuration)$(PlatformArchitecture)\ + $(ProjectDir)obj\$(Configuration)$(PlatformArchitecture)\ + false + $(SolutionDir)bin\$(Configuration)$(PlatformArchitecture)\ + $(ProjectDir)obj\$(Configuration)$(PlatformArchitecture)\ + false + false + false + false + false + + + + Disabled + ..\phnt\include;..\phlib\include;include;%(AdditionalIncludeDirectories) + _PHLIB_;_PHAPP_;_WINDOWS;WIN32;DEBUG;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + Level3 + ProgramDatabase + StdCall + true + true + + + aclui.lib;comctl32.lib;iphlpapi.lib;noarg.obj;noenv.obj;ntdll.lib;phlib.lib;uxtheme.lib;version.lib;windowscodecs.lib;winsta.lib;ws2_32.lib;%(AdditionalDependencies) + true + Windows + MachineX86 + 6.01 + ..\phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) + ProcessHacker.def + aclui.dll;iphlpapi.dll;ws2_32.dll;%(DelayLoadDLLs) + + + ..\tools\CustomBuildTool\bin\Release\CustomBuildTool.exe -updaterev + Generating revision number... + + + + + + + + + + + Disabled + ..\phnt\include;..\phlib\include;include;%(AdditionalIncludeDirectories) + _PHLIB_;_PHAPP_;_WINDOWS;WIN64;DEBUG;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + Level3 + ProgramDatabase + StdCall + true + true + + + aclui.lib;comctl32.lib;iphlpapi.lib;noarg.obj;noenv.obj;ntdll.lib;phlib.lib;uxtheme.lib;version.lib;windowscodecs.lib;winsta.lib;ws2_32.lib;%(AdditionalDependencies) + true + Windows + MachineX64 + 6.01 + ..\phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) + ProcessHacker.def + aclui.dll;iphlpapi.dll;ws2_32.dll;%(DelayLoadDLLs) + + + ..\tools\CustomBuildTool\bin\Release\CustomBuildTool.exe -updaterev + Generating revision number... + + + + + + + + + + + MaxSpeed + true + ..\phnt\include;..\phlib\include;include;%(AdditionalIncludeDirectories) + _PHLIB_;_PHAPP_;_WINDOWS;WIN32;NDEBUG;%(PreprocessorDefinitions) + true + MultiThreaded + false + true + Level3 + ProgramDatabase + StdCall + true + true + StreamingSIMDExtensions + + + aclui.lib;comctl32.lib;iphlpapi.lib;noarg.obj;noenv.obj;ntdll.lib;phlib.lib;uxtheme.lib;version.lib;windowscodecs.lib;winsta.lib;ws2_32.lib;%(AdditionalDependencies) + true + Windows + true + true + MachineX86 + true + 6.01 + ..\phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) + ProcessHacker.def + aclui.dll;iphlpapi.dll;ws2_32.dll;%(DelayLoadDLLs) + + + ..\tools\CustomBuildTool\bin\Release\CustomBuildTool.exe -updaterev + Generating revision number... + + + + + + + + + + + MaxSpeed + true + ..\phnt\include;..\phlib\include;include;%(AdditionalIncludeDirectories) + _PHLIB_;_PHAPP_;_WINDOWS;WIN64;NDEBUG;%(PreprocessorDefinitions) + true + MultiThreaded + false + true + Level3 + ProgramDatabase + StdCall + true + true + + + aclui.lib;comctl32.lib;iphlpapi.lib;noarg.obj;noenv.obj;ntdll.lib;phlib.lib;uxtheme.lib;version.lib;windowscodecs.lib;winsta.lib;ws2_32.lib;%(AdditionalDependencies) + true + Windows + true + true + MachineX64 + true + 6.01 + ..\phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) + ProcessHacker.def + aclui.dll;iphlpapi.dll;ws2_32.dll;%(DelayLoadDLLs) + + + ..\tools\CustomBuildTool\bin\Release\CustomBuildTool.exe -updaterev + Generating revision number... + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Designer + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ProcessHacker/about.c b/ProcessHacker/about.c index fd9872cc7edf..834b055bd054 100644 --- a/ProcessHacker/about.c +++ b/ProcessHacker/about.c @@ -1,190 +1,190 @@ -/* - * Process Hacker - - * about dialog - * - * Copyright (C) 2010-2016 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -static INT_PTR CALLBACK PhpAboutDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - switch (uMsg) - { - case WM_INITDIALOG: - { - PPH_STRING appName; - - PhCenterWindow(hwndDlg, GetParent(hwndDlg)); - -#if (PHAPP_VERSION_REVISION != 0) - appName = PhFormatString( - L"Process Hacker %u.%u.%u", - PHAPP_VERSION_MAJOR, - PHAPP_VERSION_MINOR, - PHAPP_VERSION_REVISION - ); -#else - appName = PhFormatString( - L"Process Hacker %u.%u", - PHAPP_VERSION_MAJOR, - PHAPP_VERSION_MINOR - ); -#endif - - SetDlgItemText(hwndDlg, IDC_ABOUT_NAME, appName->Buffer); - PhDereferenceObject(appName); - - SetDlgItemText(hwndDlg, IDC_CREDITS, - L" Installer by XhmikosR\n" - L"Thanks to:\n" - L" dmex\n" - L" Donors - thank you for your support!\n" - L" Sysinternals Forums\n" - L" ReactOS\n" - L"Process Hacker uses the following components:\n" - L" Mini-XML by Michael Sweet\n" - L" PCRE\n" - L" MD5 code by Jouni Malinen\n" - L" SHA1 code by Filip Navara, based on code by Steve Reid\n" - L" Silk icons\n" - L" Farm-fresh web icons\n" - ); - - SendMessage(hwndDlg, WM_NEXTDLGCTL, (LPARAM)GetDlgItem(hwndDlg, IDOK), TRUE); - } - break; - case WM_COMMAND: - { - switch (LOWORD(wParam)) - { - case IDCANCEL: - case IDOK: - EndDialog(hwndDlg, IDOK); - break; - case IDC_DIAGNOSTICS: - { - PhShowInformationDialog(hwndDlg, PH_AUTO_T(PH_STRING, PhGetDiagnosticsString())->Buffer, 0); - } - break; - } - } - break; - case WM_NOTIFY: - { - LPNMHDR header = (LPNMHDR)lParam; - - switch (header->code) - { - case NM_CLICK: - { - switch (header->idFrom) - { - case IDC_CREDITS: - case IDC_LINK_SF: - PhShellExecute(hwndDlg, ((PNMLINK)header)->item.szUrl, NULL); - break; - } - } - break; - } - } - break; - } - - return FALSE; -} - -VOID PhShowAboutDialog( - _In_ HWND ParentWindowHandle - ) -{ - DialogBox( - PhInstanceHandle, - MAKEINTRESOURCE(IDD_ABOUT), - ParentWindowHandle, - PhpAboutDlgProc - ); -} - -FORCEINLINE ULONG PhpGetObjectTypeObjectCount( - _In_ PPH_OBJECT_TYPE ObjectType - ) -{ - PH_OBJECT_TYPE_INFORMATION info; - - PhGetObjectTypeInformation(ObjectType, &info); - - return info.NumberOfObjects; -} - -PPH_STRING PhGetDiagnosticsString( - VOID - ) -{ - PH_STRING_BUILDER stringBuilder; - - PhInitializeStringBuilder(&stringBuilder, 50); - - PhAppendFormatStringBuilder(&stringBuilder, L"OBJECT INFORMATION\r\n"); - -#define OBJECT_TYPE_COUNT(Type) PhAppendFormatStringBuilder(&stringBuilder, \ - L#Type L": %u objects\r\n", PhpGetObjectTypeObjectCount(Type)) - - // ref - OBJECT_TYPE_COUNT(PhObjectTypeObject); - - // basesup - OBJECT_TYPE_COUNT(PhStringType); - OBJECT_TYPE_COUNT(PhBytesType); - OBJECT_TYPE_COUNT(PhListType); - OBJECT_TYPE_COUNT(PhPointerListType); - OBJECT_TYPE_COUNT(PhHashtableType); - OBJECT_TYPE_COUNT(PhFileStreamType); - - // ph - OBJECT_TYPE_COUNT(PhSymbolProviderType); - OBJECT_TYPE_COUNT(PhProcessItemType); - OBJECT_TYPE_COUNT(PhServiceItemType); - OBJECT_TYPE_COUNT(PhNetworkItemType); - OBJECT_TYPE_COUNT(PhModuleProviderType); - OBJECT_TYPE_COUNT(PhModuleItemType); - OBJECT_TYPE_COUNT(PhThreadProviderType); - OBJECT_TYPE_COUNT(PhThreadItemType); - OBJECT_TYPE_COUNT(PhHandleProviderType); - OBJECT_TYPE_COUNT(PhHandleItemType); - OBJECT_TYPE_COUNT(PhMemoryItemType); - - return PhFinalStringBuilderString(&stringBuilder); -} +/* + * Process Hacker - + * about dialog + * + * Copyright (C) 2010-2016 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +static INT_PTR CALLBACK PhpAboutDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + switch (uMsg) + { + case WM_INITDIALOG: + { + PPH_STRING appName; + + PhCenterWindow(hwndDlg, GetParent(hwndDlg)); + +#if (PHAPP_VERSION_REVISION != 0) + appName = PhFormatString( + L"Process Hacker %u.%u.%u", + PHAPP_VERSION_MAJOR, + PHAPP_VERSION_MINOR, + PHAPP_VERSION_REVISION + ); +#else + appName = PhFormatString( + L"Process Hacker %u.%u", + PHAPP_VERSION_MAJOR, + PHAPP_VERSION_MINOR + ); +#endif + + SetDlgItemText(hwndDlg, IDC_ABOUT_NAME, appName->Buffer); + PhDereferenceObject(appName); + + SetDlgItemText(hwndDlg, IDC_CREDITS, + L" Installer by XhmikosR\n" + L"Thanks to:\n" + L" dmex\n" + L" Donors - thank you for your support!\n" + L" Sysinternals Forums\n" + L" ReactOS\n" + L"Process Hacker uses the following components:\n" + L" Mini-XML by Michael Sweet\n" + L" PCRE\n" + L" MD5 code by Jouni Malinen\n" + L" SHA1 code by Filip Navara, based on code by Steve Reid\n" + L" Silk icons\n" + L" Farm-fresh web icons\n" + ); + + SendMessage(hwndDlg, WM_NEXTDLGCTL, (LPARAM)GetDlgItem(hwndDlg, IDOK), TRUE); + } + break; + case WM_COMMAND: + { + switch (LOWORD(wParam)) + { + case IDCANCEL: + case IDOK: + EndDialog(hwndDlg, IDOK); + break; + case IDC_DIAGNOSTICS: + { + PhShowInformationDialog(hwndDlg, PH_AUTO_T(PH_STRING, PhGetDiagnosticsString())->Buffer, 0); + } + break; + } + } + break; + case WM_NOTIFY: + { + LPNMHDR header = (LPNMHDR)lParam; + + switch (header->code) + { + case NM_CLICK: + { + switch (header->idFrom) + { + case IDC_CREDITS: + case IDC_LINK_SF: + PhShellExecute(hwndDlg, ((PNMLINK)header)->item.szUrl, NULL); + break; + } + } + break; + } + } + break; + } + + return FALSE; +} + +VOID PhShowAboutDialog( + _In_ HWND ParentWindowHandle + ) +{ + DialogBox( + PhInstanceHandle, + MAKEINTRESOURCE(IDD_ABOUT), + ParentWindowHandle, + PhpAboutDlgProc + ); +} + +FORCEINLINE ULONG PhpGetObjectTypeObjectCount( + _In_ PPH_OBJECT_TYPE ObjectType + ) +{ + PH_OBJECT_TYPE_INFORMATION info; + + PhGetObjectTypeInformation(ObjectType, &info); + + return info.NumberOfObjects; +} + +PPH_STRING PhGetDiagnosticsString( + VOID + ) +{ + PH_STRING_BUILDER stringBuilder; + + PhInitializeStringBuilder(&stringBuilder, 50); + + PhAppendFormatStringBuilder(&stringBuilder, L"OBJECT INFORMATION\r\n"); + +#define OBJECT_TYPE_COUNT(Type) PhAppendFormatStringBuilder(&stringBuilder, \ + L#Type L": %u objects\r\n", PhpGetObjectTypeObjectCount(Type)) + + // ref + OBJECT_TYPE_COUNT(PhObjectTypeObject); + + // basesup + OBJECT_TYPE_COUNT(PhStringType); + OBJECT_TYPE_COUNT(PhBytesType); + OBJECT_TYPE_COUNT(PhListType); + OBJECT_TYPE_COUNT(PhPointerListType); + OBJECT_TYPE_COUNT(PhHashtableType); + OBJECT_TYPE_COUNT(PhFileStreamType); + + // ph + OBJECT_TYPE_COUNT(PhSymbolProviderType); + OBJECT_TYPE_COUNT(PhProcessItemType); + OBJECT_TYPE_COUNT(PhServiceItemType); + OBJECT_TYPE_COUNT(PhNetworkItemType); + OBJECT_TYPE_COUNT(PhModuleProviderType); + OBJECT_TYPE_COUNT(PhModuleItemType); + OBJECT_TYPE_COUNT(PhThreadProviderType); + OBJECT_TYPE_COUNT(PhThreadItemType); + OBJECT_TYPE_COUNT(PhHandleProviderType); + OBJECT_TYPE_COUNT(PhHandleItemType); + OBJECT_TYPE_COUNT(PhMemoryItemType); + + return PhFinalStringBuilderString(&stringBuilder); +} diff --git a/ProcessHacker/actions.c b/ProcessHacker/actions.c index 36eaf7a16d21..fbec1593805a 100644 --- a/ProcessHacker/actions.c +++ b/ProcessHacker/actions.c @@ -1,3130 +1,3130 @@ -/* - * Process Hacker - - * UI actions - * - * Copyright (C) 2010-2016 wj32 - * Copyright (C) 2017 dmex - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -/* - * These are a set of consistent functions which will perform actions on objects such as processes, - * threads and services, while displaying any necessary prompts and error messages. Automatic - * elevation can also easily be added if necessary. - */ - -#include -#include - -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -typedef DWORD (WINAPI *_SetTcpEntry)( - _In_ PMIB_TCPROW pTcpRow - ); - -static PWSTR DangerousProcesses[] = -{ - L"csrss.exe", L"dwm.exe", L"logonui.exe", L"lsass.exe", L"lsm.exe", - L"services.exe", L"smss.exe", L"wininit.exe", L"winlogon.exe" -}; - -static PPH_STRING DebuggerCommand = NULL; -static PH_INITONCE DebuggerCommandInitOnce = PH_INITONCE_INIT; -static ULONG PhSvcReferenceCount = 0; -static PH_PHSVC_MODE PhSvcCurrentMode; -static PH_QUEUED_LOCK PhSvcStartLock = PH_QUEUED_LOCK_INIT; - -HRESULT CALLBACK PhpElevateActionCallbackProc( - _In_ HWND hwnd, - _In_ UINT uNotification, - _In_ WPARAM wParam, - _In_ LPARAM lParam, - _In_ LONG_PTR dwRefData - ) -{ - switch (uNotification) - { - case TDN_CREATED: - SendMessage(hwnd, TDM_SET_BUTTON_ELEVATION_REQUIRED_STATE, IDYES, TRUE); - break; - } - - return S_OK; -} - -BOOLEAN PhpShowElevatePrompt( - _In_ HWND hWnd, - _In_ PWSTR Message, - _In_ NTSTATUS Status, - _Out_ PINT Button - ) -{ - TASKDIALOGCONFIG config = { sizeof(config) }; - TASKDIALOG_BUTTON buttons[1]; - INT button; - - // Currently the error dialog box is similar to the one displayed - // when you try to label a drive in Windows Explorer. It's much better - // than the clunky dialog in PH 1.x. - - config.hwndParent = hWnd; - config.hInstance = PhInstanceHandle; - config.dwFlags = IsWindowVisible(hWnd) ? TDF_POSITION_RELATIVE_TO_WINDOW : 0; - config.pszWindowTitle = L"Process Hacker"; - config.pszMainIcon = TD_ERROR_ICON; - config.pszMainInstruction = PhaConcatStrings2(Message, L".")->Buffer; - config.pszContent = L"You will need to provide administrator permission. " - L"Click Continue to complete this operation."; - config.dwCommonButtons = TDCBF_CANCEL_BUTTON; - - buttons[0].nButtonID = IDYES; - buttons[0].pszButtonText = L"Continue"; - - config.cButtons = 1; - config.pButtons = buttons; - config.nDefaultButton = IDYES; - - config.pfCallback = PhpElevateActionCallbackProc; - - if (TaskDialogIndirect( - &config, - &button, - NULL, - NULL - ) == S_OK) - { - *Button = button; - return TRUE; - } - else - { - return FALSE; - } -} - -/** - * Shows an error, prompts for elevation, and executes a command. - * - * \param hWnd The window to display user interface components on. - * \param Message A message describing the operation that failed. - * \param Status A NTSTATUS value. - * \param Command The arguments to pass to the new instance of - * the application, if required. - * \param Success A variable which receives TRUE if the elevated - * action succeeded or FALSE if the action failed. - * - * \return TRUE if the user was prompted for elevation, otherwise - * FALSE, in which case you need to show your own error message. - */ -BOOLEAN PhpShowErrorAndElevateAction( - _In_ HWND hWnd, - _In_ PWSTR Message, - _In_ NTSTATUS Status, - _In_ PWSTR Command, - _Out_ PBOOLEAN Success - ) -{ - PH_ACTION_ELEVATION_LEVEL elevationLevel; - INT button = IDNO; - - if (!( - Status == STATUS_ACCESS_DENIED || - Status == STATUS_PRIVILEGE_NOT_HELD || - (NT_NTWIN32(Status) && WIN32_FROM_NTSTATUS(Status) == ERROR_ACCESS_DENIED) - )) - return FALSE; - - if (!WINDOWS_HAS_UAC || PhGetOwnTokenAttributes().Elevated) - return FALSE; - - elevationLevel = PhGetIntegerSetting(L"ElevationLevel"); - - if (elevationLevel == NeverElevateAction) - return FALSE; - - if (elevationLevel == PromptElevateAction) - { - if (!PhpShowElevatePrompt(hWnd, Message, Status, &button)) - return FALSE; - } - - if (elevationLevel == AlwaysElevateAction || button == IDYES) - { - NTSTATUS status; - HANDLE processHandle; - LARGE_INTEGER timeout; - PROCESS_BASIC_INFORMATION basicInfo; - - if (PhShellProcessHacker( - hWnd, - Command, - SW_SHOW, - PH_SHELL_EXECUTE_ADMIN, - PH_SHELL_APP_PROPAGATE_PARAMETERS, - 0, - &processHandle - )) - { - timeout.QuadPart = -10 * PH_TIMEOUT_SEC; - status = NtWaitForSingleObject(processHandle, FALSE, &timeout); - - if ( - status == STATUS_WAIT_0 && - NT_SUCCESS(status = PhGetProcessBasicInformation(processHandle, &basicInfo)) - ) - { - status = basicInfo.ExitStatus; - } - - NtClose(processHandle); - - if (NT_SUCCESS(status)) - { - *Success = TRUE; - } - else - { - *Success = FALSE; - PhShowStatus(hWnd, Message, status, 0); - } - } - } - - return TRUE; -} - -/** - * Shows an error, prompts for elevation, and connects to phsvc. - * - * \param hWnd The window to display user interface components on. - * \param Message A message describing the operation that failed. - * \param Status A NTSTATUS value. - * \param Connected A variable which receives TRUE if the user - * elevated the action and phsvc was started, or FALSE if the user - * cancelled elevation. If the value is TRUE, you need to - * perform any necessary phsvc calls and use PhUiDisconnectFromPhSvc() - * to disconnect from phsvc. - * - * \return TRUE if the user was prompted for elevation, otherwise - * FALSE, in which case you need to show your own error message. - */ -BOOLEAN PhpShowErrorAndConnectToPhSvc( - _In_ HWND hWnd, - _In_ PWSTR Message, - _In_ NTSTATUS Status, - _Out_ PBOOLEAN Connected - ) -{ - PH_ACTION_ELEVATION_LEVEL elevationLevel; - INT button = IDNO; - - *Connected = FALSE; - - if (!( - Status == STATUS_ACCESS_DENIED || - Status == STATUS_PRIVILEGE_NOT_HELD || - (NT_NTWIN32(Status) && WIN32_FROM_NTSTATUS(Status) == ERROR_ACCESS_DENIED) - )) - return FALSE; - - if (!WINDOWS_HAS_UAC || PhGetOwnTokenAttributes().Elevated) - return FALSE; - - elevationLevel = PhGetIntegerSetting(L"ElevationLevel"); - - if (elevationLevel == NeverElevateAction) - return FALSE; - - // Try to connect now so we can avoid prompting the user. - if (PhUiConnectToPhSvc(hWnd, TRUE)) - { - *Connected = TRUE; - return TRUE; - } - - if (elevationLevel == PromptElevateAction) - { - if (!PhpShowElevatePrompt(hWnd, Message, Status, &button)) - return FALSE; - } - - if (elevationLevel == AlwaysElevateAction || button == IDYES) - { - *Connected = PhUiConnectToPhSvc(hWnd, FALSE); - } - - return TRUE; -} - -/** - * Connects to phsvc. - * - * \param hWnd The window to display user interface components on. - * \param ConnectOnly TRUE to only try to connect to phsvc, otherwise - * FALSE to try to elevate and start phsvc if the initial connection - * attempt failed. - */ -BOOLEAN PhUiConnectToPhSvc( - _In_opt_ HWND hWnd, - _In_ BOOLEAN ConnectOnly - ) -{ - return PhUiConnectToPhSvcEx(hWnd, ElevatedPhSvcMode, ConnectOnly); -} - -VOID PhpGetPhSvcPortName( - _In_ PH_PHSVC_MODE Mode, - _Out_ PUNICODE_STRING PortName - ) -{ - switch (Mode) - { - case ElevatedPhSvcMode: - if (!PhIsExecutingInWow64()) - RtlInitUnicodeString(PortName, PHSVC_PORT_NAME); - else - RtlInitUnicodeString(PortName, PHSVC_WOW64_PORT_NAME); - break; - case Wow64PhSvcMode: - RtlInitUnicodeString(PortName, PHSVC_WOW64_PORT_NAME); - break; - default: - PhRaiseStatus(STATUS_INVALID_PARAMETER); - break; - } -} - -BOOLEAN PhpStartPhSvcProcess( - _In_opt_ HWND hWnd, - _In_ PH_PHSVC_MODE Mode - ) -{ - switch (Mode) - { - case ElevatedPhSvcMode: - if (PhShellProcessHacker( - hWnd, - L"-phsvc", - SW_HIDE, - PH_SHELL_EXECUTE_ADMIN, - PH_SHELL_APP_PROPAGATE_PARAMETERS, - 0, - NULL - )) - { - return TRUE; - } - - break; - case Wow64PhSvcMode: - { - static PWSTR relativeFileNames[] = - { - L"\\x86\\ProcessHacker.exe", - L"\\..\\x86\\ProcessHacker.exe", -#ifdef DEBUG - L"\\..\\Debug32\\ProcessHacker.exe", -#endif - L"\\..\\Release32\\ProcessHacker.exe" - }; - - ULONG i; - - for (i = 0; i < sizeof(relativeFileNames) / sizeof(PWSTR); i++) - { - PPH_STRING fileName; - - fileName = PhConcatStrings2(PhApplicationDirectory->Buffer, relativeFileNames[i]); - PhMoveReference(&fileName, PhGetFullPath(fileName->Buffer, NULL)); - - if (fileName && RtlDoesFileExists_U(fileName->Buffer)) - { - if (PhShellProcessHackerEx( - hWnd, - fileName->Buffer, - L"-phsvc", - SW_HIDE, - 0, - PH_SHELL_APP_PROPAGATE_PARAMETERS, - 0, - NULL - )) - { - PhDereferenceObject(fileName); - return TRUE; - } - } - - PhClearReference(&fileName); - } - } - break; - } - - return FALSE; -} - -/** - * Connects to phsvc. - * - * \param hWnd The window to display user interface components on. - * \param Mode The type of phsvc instance to connect to. - * \param ConnectOnly TRUE to only try to connect to phsvc, otherwise - * FALSE to try to elevate and start phsvc if the initial connection - * attempt failed. - */ -BOOLEAN PhUiConnectToPhSvcEx( - _In_opt_ HWND hWnd, - _In_ PH_PHSVC_MODE Mode, - _In_ BOOLEAN ConnectOnly - ) -{ - NTSTATUS status; - BOOLEAN started; - UNICODE_STRING portName; - - if (_InterlockedIncrementNoZero(&PhSvcReferenceCount)) - { - if (PhSvcCurrentMode == Mode) - { - started = TRUE; - } - else - { - _InterlockedDecrement(&PhSvcReferenceCount); - started = FALSE; - } - } - else - { - PhAcquireQueuedLockExclusive(&PhSvcStartLock); - - if (PhSvcReferenceCount == 0) - { - started = FALSE; - PhpGetPhSvcPortName(Mode, &portName); - - // Try to connect first, then start the server if we failed. - status = PhSvcConnectToServer(&portName, 0); - - if (NT_SUCCESS(status)) - { - started = TRUE; - PhSvcCurrentMode = Mode; - _InterlockedIncrement(&PhSvcReferenceCount); - } - else if (!ConnectOnly) - { - // Prompt for elevation, and then try to connect to the server. - - if (PhpStartPhSvcProcess(hWnd, Mode)) - started = TRUE; - - if (started) - { - ULONG attempts = 10; - LARGE_INTEGER interval; - - // Try to connect several times because the server may take - // a while to initialize. - do - { - status = PhSvcConnectToServer(&portName, 0); - - if (NT_SUCCESS(status)) - break; - - interval.QuadPart = -50 * PH_TIMEOUT_MS; - NtDelayExecution(FALSE, &interval); - } while (--attempts != 0); - - // Increment the reference count even if we failed. - // We don't want to prompt the user again. - - PhSvcCurrentMode = Mode; - _InterlockedIncrement(&PhSvcReferenceCount); - } - } - } - else - { - if (PhSvcCurrentMode == Mode) - { - started = TRUE; - _InterlockedIncrement(&PhSvcReferenceCount); - } - else - { - started = FALSE; - } - } - - PhReleaseQueuedLockExclusive(&PhSvcStartLock); - } - - return started; -} - -/** - * Disconnects from phsvc. - */ -VOID PhUiDisconnectFromPhSvc( - VOID - ) -{ - PhAcquireQueuedLockExclusive(&PhSvcStartLock); - - if (_InterlockedDecrement(&PhSvcReferenceCount) == 0) - { - PhSvcDisconnectFromServer(); - } - - PhReleaseQueuedLockExclusive(&PhSvcStartLock); -} - -BOOLEAN PhUiLockComputer( - _In_ HWND hWnd - ) -{ - if (LockWorkStation()) - return TRUE; - else - PhShowStatus(hWnd, L"Unable to lock the computer", 0, GetLastError()); - - return FALSE; -} - -BOOLEAN PhUiLogoffComputer( - _In_ HWND hWnd - ) -{ - if (ExitWindowsEx(EWX_LOGOFF, 0)) - return TRUE; - else - PhShowStatus(hWnd, L"Unable to log off the computer", 0, GetLastError()); - - return FALSE; -} - -BOOLEAN PhUiSleepComputer( - _In_ HWND hWnd - ) -{ - NTSTATUS status; - - if (NT_SUCCESS(status = NtInitiatePowerAction( - PowerActionSleep, - PowerSystemSleeping1, - 0, - FALSE - ))) - return TRUE; - else - PhShowStatus(hWnd, L"Unable to sleep the computer", status, 0); - - return FALSE; -} - -BOOLEAN PhUiHibernateComputer( - _In_ HWND hWnd - ) -{ - NTSTATUS status; - - if (NT_SUCCESS(status = NtInitiatePowerAction( - PowerActionHibernate, - PowerSystemSleeping1, - 0, - FALSE - ))) - return TRUE; - else - PhShowStatus(hWnd, L"Unable to hibernate the computer", status, 0); - - return FALSE; -} - -BOOLEAN PhUiRestartComputer( - _In_ HWND hWnd, - _In_ ULONG Flags - ) -{ - if (!PhGetIntegerSetting(L"EnableWarnings") || PhShowConfirmMessage( - hWnd, - L"restart", - L"the computer", - NULL, - FALSE - )) - { - if (ExitWindowsEx(EWX_REBOOT | Flags, 0)) - return TRUE; - else - PhShowStatus(hWnd, L"Unable to restart the computer", 0, GetLastError()); - } - - return FALSE; -} - -BOOLEAN PhUiShutdownComputer( - _In_ HWND hWnd, - _In_ ULONG Flags - ) -{ - if (!PhGetIntegerSetting(L"EnableWarnings") || PhShowConfirmMessage( - hWnd, - L"shut down", - L"the computer", - NULL, - FALSE - )) - { - if (ExitWindowsEx(EWX_POWEROFF | Flags, 0)) - { - return TRUE; - } - else if (ExitWindowsEx(EWX_SHUTDOWN | Flags, 0)) - { - return TRUE; - } - else - { - PhShowStatus(hWnd, L"Unable to shut down the computer", 0, GetLastError()); - } - } - - return FALSE; -} - -BOOLEAN PhUiConnectSession( - _In_ HWND hWnd, - _In_ ULONG SessionId - ) -{ - BOOLEAN success = FALSE; - PPH_STRING selectedChoice = NULL; - PPH_STRING oldSelectedChoice = NULL; - - // Try once with no password. - if (WinStationConnectW(NULL, SessionId, -1, L"", TRUE)) - return TRUE; - - while (PhaChoiceDialog( - hWnd, - L"Connect to session", - L"Password:", - NULL, - 0, - NULL, - PH_CHOICE_DIALOG_PASSWORD, - &selectedChoice, - NULL, - NULL - )) - { - if (oldSelectedChoice) - { - RtlSecureZeroMemory(oldSelectedChoice->Buffer, oldSelectedChoice->Length); - PhDereferenceObject(oldSelectedChoice); - } - - oldSelectedChoice = selectedChoice; - - if (WinStationConnectW(NULL, SessionId, -1, selectedChoice->Buffer, TRUE)) - { - success = TRUE; - break; - } - else - { - if (!PhShowContinueStatus(hWnd, L"Unable to connect to the session", 0, GetLastError())) - break; - } - } - - if (oldSelectedChoice) - { - RtlSecureZeroMemory(oldSelectedChoice->Buffer, oldSelectedChoice->Length); - PhDereferenceObject(oldSelectedChoice); - } - - return success; -} - -BOOLEAN PhUiDisconnectSession( - _In_ HWND hWnd, - _In_ ULONG SessionId - ) -{ - if (WinStationDisconnect(NULL, SessionId, FALSE)) - return TRUE; - else - PhShowStatus(hWnd, L"Unable to disconnect the session", 0, GetLastError()); - - return FALSE; -} - -BOOLEAN PhUiLogoffSession( - _In_ HWND hWnd, - _In_ ULONG SessionId - ) -{ - if (!PhGetIntegerSetting(L"EnableWarnings") || PhShowConfirmMessage( - hWnd, - L"logoff", - L"the user", - NULL, - FALSE - )) - { - if (WinStationReset(NULL, SessionId, FALSE)) - return TRUE; - else - PhShowStatus(hWnd, L"Unable to logoff the session", 0, GetLastError()); - } - - return FALSE; -} - -/** - * Determines if a process is a system process. - * - * \param ProcessId The PID of the process to check. - */ -static BOOLEAN PhpIsDangerousProcess( - _In_ HANDLE ProcessId - ) -{ - NTSTATUS status; - HANDLE processHandle; - PPH_STRING fileName; - PPH_STRING systemDirectory; - ULONG i; - - if (ProcessId == SYSTEM_PROCESS_ID) - return TRUE; - - if (WINDOWS_HAS_IMAGE_FILE_NAME_BY_PROCESS_ID) - { - status = PhGetProcessImageFileNameByProcessId(ProcessId, &fileName); - } - else - { - if (!NT_SUCCESS(status = PhOpenProcess( - &processHandle, - ProcessQueryAccess, - ProcessId - ))) - return FALSE; - - status = PhGetProcessImageFileName(processHandle, &fileName); - NtClose(processHandle); - } - - if (!NT_SUCCESS(status)) - return FALSE; - - PhMoveReference(&fileName, PhGetFileName(fileName)); - PH_AUTO(fileName); - - systemDirectory = PH_AUTO(PhGetSystemDirectory()); - - for (i = 0; i < sizeof(DangerousProcesses) / sizeof(PWSTR); i++) - { - PPH_STRING fullName; - - fullName = PhaConcatStrings(3, systemDirectory->Buffer, L"\\", DangerousProcesses[i]); - - if (PhEqualString(fileName, fullName, TRUE)) - return TRUE; - } - - return FALSE; -} - -/** - * Checks if the user wants to proceed with an operation. - * - * \param hWnd A handle to the parent window. - * \param Verb A verb describing the action. - * \param Message A message containing additional information - * about the action. - * \param WarnOnlyIfDangerous TRUE to skip the confirmation - * dialog if none of the processes are system processes, - * FALSE to always show the confirmation dialog. - * \param Processes An array of pointers to process items. - * \param NumberOfProcesses The number of process items. - * - * \return TRUE if the user wants to proceed with the operation, - * otherwise FALSE. - */ -static BOOLEAN PhpShowContinueMessageProcesses( - _In_ HWND hWnd, - _In_ PWSTR Verb, - _In_opt_ PWSTR Message, - _In_ BOOLEAN WarnOnlyIfDangerous, - _In_ PPH_PROCESS_ITEM *Processes, - _In_ ULONG NumberOfProcesses - ) -{ - PWSTR object; - ULONG i; - BOOLEAN critical = FALSE; - BOOLEAN dangerous = FALSE; - BOOLEAN cont = FALSE; - - if (NumberOfProcesses == 0) - return FALSE; - - for (i = 0; i < NumberOfProcesses; i++) - { - HANDLE processHandle; - ULONG breakOnTermination; - - breakOnTermination = 0; - - if (NT_SUCCESS(PhOpenProcess(&processHandle, PROCESS_QUERY_INFORMATION, Processes[i]->ProcessId))) - { - NtQueryInformationProcess(processHandle, ProcessBreakOnTermination, &breakOnTermination, sizeof(ULONG), NULL); - NtClose(processHandle); - } - - if (breakOnTermination != 0) - { - critical = TRUE; - dangerous = TRUE; - break; - } - - if (PhpIsDangerousProcess(Processes[i]->ProcessId)) - { - dangerous = TRUE; - break; - } - } - - if (WarnOnlyIfDangerous && !dangerous) - return TRUE; - - if (PhGetIntegerSetting(L"EnableWarnings")) - { - if (NumberOfProcesses == 1) - { - object = Processes[0]->ProcessName->Buffer; - } - else if (NumberOfProcesses == 2) - { - object = PhaConcatStrings( - 3, - Processes[0]->ProcessName->Buffer, - L" and ", - Processes[1]->ProcessName->Buffer - )->Buffer; - } - else - { - object = L"the selected processes"; - } - - if (!dangerous) - { - cont = PhShowConfirmMessage( - hWnd, - Verb, - object, - Message, - FALSE - ); - } - else if (!critical) - { - cont = PhShowConfirmMessage( - hWnd, - Verb, - object, - PhaConcatStrings( - 3, - L"You are about to ", - Verb, - L" one or more system processes." - )->Buffer, - TRUE - ); - } - else - { - PPH_STRING message; - - if (PhEqualStringZ(Verb, L"terminate", FALSE)) - { - message = PhaConcatStrings( - 3, - L"You are about to ", - Verb, - L" one or more critical processes. This will shut down the operating system immediately." - ); - } - else - { - message = PhaConcatStrings( - 3, - L"You are about to ", - Verb, - L" one or more critical processes." - ); - } - - cont = PhShowConfirmMessage( - hWnd, - Verb, - object, - message->Buffer, - TRUE - ); - } - } - else - { - cont = TRUE; - } - - return cont; -} - -/** - * Shows an error message to the user and checks - * if the user wants to continue. - * - * \param hWnd A handle to the parent window. - * \param Verb A verb describing the action which - * resulted in an error. - * \param Process The process item which the action - * was performed on. - * \param Status A NT status value representing the - * error. - * \param Win32Result A Win32 error code representing - * the error. - * - * \return TRUE if the user wants to continue, otherwise - * FALSE. The result is typically only useful when - * executing an action on multiple processes. - */ -static BOOLEAN PhpShowErrorProcess( - _In_ HWND hWnd, - _In_ PWSTR Verb, - _In_ PPH_PROCESS_ITEM Process, - _In_ NTSTATUS Status, - _In_opt_ ULONG Win32Result - ) -{ - if (!PH_IS_FAKE_PROCESS_ID(Process->ProcessId)) - { - return PhShowContinueStatus( - hWnd, - PhaFormatString( - L"Unable to %s %s (PID %u)", - Verb, - Process->ProcessName->Buffer, - HandleToUlong(Process->ProcessId) - )->Buffer, - Status, - Win32Result - ); - } - else - { - return PhShowContinueStatus( - hWnd, - PhaFormatString( - L"Unable to %s %s", - Verb, - Process->ProcessName->Buffer - )->Buffer, - Status, - Win32Result - ); - } -} - -BOOLEAN PhUiTerminateProcesses( - _In_ HWND hWnd, - _In_ PPH_PROCESS_ITEM *Processes, - _In_ ULONG NumberOfProcesses - ) -{ - BOOLEAN success = TRUE; - BOOLEAN cancelled = FALSE; - ULONG i; - - if (!PhpShowContinueMessageProcesses( - hWnd, - L"terminate", - L"Terminating a process will cause unsaved data to be lost.", - FALSE, - Processes, - NumberOfProcesses - )) - return FALSE; - - for (i = 0; i < NumberOfProcesses; i++) - { - NTSTATUS status; - HANDLE processHandle; - - if (NT_SUCCESS(status = PhOpenProcess( - &processHandle, - PROCESS_TERMINATE, - Processes[i]->ProcessId - ))) - { - // An exit status of 1 is used here for compatibility reasons: - // 1. Both Task Manager and Process Explorer use 1. - // 2. winlogon tries to restart explorer.exe if the exit status is not 1. - - status = PhTerminateProcess(processHandle, 1); - NtClose(processHandle); - } - - if (!NT_SUCCESS(status)) - { - BOOLEAN connected; - - success = FALSE; - - if (!cancelled && PhpShowErrorAndConnectToPhSvc( - hWnd, - PhaConcatStrings2(L"Unable to terminate ", Processes[i]->ProcessName->Buffer)->Buffer, - status, - &connected - )) - { - if (connected) - { - if (NT_SUCCESS(status = PhSvcCallControlProcess(Processes[i]->ProcessId, PhSvcControlProcessTerminate, 0))) - success = TRUE; - else - PhpShowErrorProcess(hWnd, L"terminate", Processes[i], status, 0); - - PhUiDisconnectFromPhSvc(); - } - else - { - cancelled = TRUE; - } - } - else - { - if (!PhpShowErrorProcess(hWnd, L"terminate", Processes[i], status, 0)) - break; - } - } - } - - return success; -} - -BOOLEAN PhpUiTerminateTreeProcess( - _In_ HWND hWnd, - _In_ PPH_PROCESS_ITEM Process, - _In_ PVOID Processes, - _Inout_ PBOOLEAN Success - ) -{ - NTSTATUS status; - PSYSTEM_PROCESS_INFORMATION process; - HANDLE processHandle; - PPH_PROCESS_ITEM processItem; - - // Note: - // FALSE should be written to Success if any part of the operation failed. - // The return value of this function indicates whether to continue with - // the operation (FALSE if user cancelled). - - // Terminate the process. - - if (NT_SUCCESS(status = PhOpenProcess( - &processHandle, - PROCESS_TERMINATE, - Process->ProcessId - ))) - { - status = PhTerminateProcess(processHandle, 1); - NtClose(processHandle); - } - - if (!NT_SUCCESS(status)) - { - *Success = FALSE; - - if (!PhpShowErrorProcess(hWnd, L"terminate", Process, status, 0)) - return FALSE; - } - - // Terminate the process' children. - - process = PH_FIRST_PROCESS(Processes); - - do - { - if (process->UniqueProcessId != Process->ProcessId && - process->InheritedFromUniqueProcessId == Process->ProcessId) - { - if (processItem = PhReferenceProcessItem(process->UniqueProcessId)) - { - // Check the creation time to make sure it is a descendant. - if (processItem->CreateTime.QuadPart >= Process->CreateTime.QuadPart) - { - if (!PhpUiTerminateTreeProcess(hWnd, processItem, Processes, Success)) - { - PhDereferenceObject(processItem); - return FALSE; - } - } - - PhDereferenceObject(processItem); - } - } - } while (process = PH_NEXT_PROCESS(process)); - - return TRUE; -} - -BOOLEAN PhUiTerminateTreeProcess( - _In_ HWND hWnd, - _In_ PPH_PROCESS_ITEM Process - ) -{ - NTSTATUS status; - BOOLEAN success = TRUE; - BOOLEAN cont = FALSE; - PVOID processes; - - if (PhGetIntegerSetting(L"EnableWarnings")) - { - cont = PhShowConfirmMessage( - hWnd, - L"terminate", - PhaConcatStrings2(Process->ProcessName->Buffer, L" and its descendants")->Buffer, - L"Terminating a process tree will cause the process and its descendants to be terminated.", - FALSE - ); - } - else - { - cont = TRUE; - } - - if (!cont) - return FALSE; - - if (!NT_SUCCESS(status = PhEnumProcesses(&processes))) - { - PhShowStatus(hWnd, L"Unable to enumerate processes", status, 0); - return FALSE; - } - - PhpUiTerminateTreeProcess(hWnd, Process, processes, &success); - PhFree(processes); - - return success; -} - -BOOLEAN PhUiSuspendProcesses( - _In_ HWND hWnd, - _In_ PPH_PROCESS_ITEM *Processes, - _In_ ULONG NumberOfProcesses - ) -{ - BOOLEAN success = TRUE; - BOOLEAN cancelled = FALSE; - ULONG i; - - if (!PhpShowContinueMessageProcesses( - hWnd, - L"suspend", - NULL, - TRUE, - Processes, - NumberOfProcesses - )) - return FALSE; - - for (i = 0; i < NumberOfProcesses; i++) - { - NTSTATUS status; - HANDLE processHandle; - - if (NT_SUCCESS(status = PhOpenProcess( - &processHandle, - PROCESS_SUSPEND_RESUME, - Processes[i]->ProcessId - ))) - { - status = NtSuspendProcess(processHandle); - NtClose(processHandle); - } - - if (!NT_SUCCESS(status)) - { - BOOLEAN connected; - - success = FALSE; - - if (!cancelled && PhpShowErrorAndConnectToPhSvc( - hWnd, - PhaConcatStrings2(L"Unable to suspend ", Processes[i]->ProcessName->Buffer)->Buffer, - status, - &connected - )) - { - if (connected) - { - if (NT_SUCCESS(status = PhSvcCallControlProcess(Processes[i]->ProcessId, PhSvcControlProcessSuspend, 0))) - success = TRUE; - else - PhpShowErrorProcess(hWnd, L"suspend", Processes[i], status, 0); - - PhUiDisconnectFromPhSvc(); - } - else - { - cancelled = TRUE; - } - } - else - { - if (!PhpShowErrorProcess(hWnd, L"suspend", Processes[i], status, 0)) - break; - } - } - } - - return success; -} - -BOOLEAN PhUiResumeProcesses( - _In_ HWND hWnd, - _In_ PPH_PROCESS_ITEM *Processes, - _In_ ULONG NumberOfProcesses - ) -{ - BOOLEAN success = TRUE; - BOOLEAN cancelled = FALSE; - ULONG i; - - if (!PhpShowContinueMessageProcesses( - hWnd, - L"resume", - NULL, - TRUE, - Processes, - NumberOfProcesses - )) - return FALSE; - - for (i = 0; i < NumberOfProcesses; i++) - { - NTSTATUS status; - HANDLE processHandle; - - if (NT_SUCCESS(status = PhOpenProcess( - &processHandle, - PROCESS_SUSPEND_RESUME, - Processes[i]->ProcessId - ))) - { - status = NtResumeProcess(processHandle); - NtClose(processHandle); - } - - if (!NT_SUCCESS(status)) - { - BOOLEAN connected; - - success = FALSE; - - if (!cancelled && PhpShowErrorAndConnectToPhSvc( - hWnd, - PhaConcatStrings2(L"Unable to resume ", Processes[i]->ProcessName->Buffer)->Buffer, - status, - &connected - )) - { - if (connected) - { - if (NT_SUCCESS(status = PhSvcCallControlProcess(Processes[i]->ProcessId, PhSvcControlProcessResume, 0))) - success = TRUE; - else - PhpShowErrorProcess(hWnd, L"resume", Processes[i], status, 0); - - PhUiDisconnectFromPhSvc(); - } - else - { - cancelled = TRUE; - } - } - else - { - if (!PhpShowErrorProcess(hWnd, L"resume", Processes[i], status, 0)) - break; - } - } - } - - return success; -} - -BOOLEAN PhUiRestartProcess( - _In_ HWND hWnd, - _In_ PPH_PROCESS_ITEM Process - ) -{ - NTSTATUS status; - BOOLEAN cont = FALSE; - HANDLE processHandle = NULL; - PPH_STRING commandLine; - PPH_STRING currentDirectory; - - if (PhGetIntegerSetting(L"EnableWarnings")) - { - cont = PhShowConfirmMessage( - hWnd, - L"restart", - Process->ProcessName->Buffer, - L"The process will be restarted with the same command line and " - L"working directory, but if it is running under a different user it " - L"will be restarted under the current user.", - FALSE - ); - } - else - { - cont = TRUE; - } - - if (!cont) - return FALSE; - - // Open the process and get the command line and current directory. - - if (!NT_SUCCESS(status = PhOpenProcess( - &processHandle, - ProcessQueryAccess | PROCESS_VM_READ, - Process->ProcessId - ))) - goto ErrorExit; - - if (!NT_SUCCESS(status = PhGetProcessCommandLine( - processHandle, - &commandLine - ))) - goto ErrorExit; - - PH_AUTO(commandLine); - - if (!NT_SUCCESS(status = PhGetProcessPebString( - processHandle, - PhpoCurrentDirectory, - ¤tDirectory - ))) - goto ErrorExit; - - PH_AUTO(currentDirectory); - - NtClose(processHandle); - processHandle = NULL; - - // Open the process and terminate it. - - if (!NT_SUCCESS(status = PhOpenProcess( - &processHandle, - PROCESS_TERMINATE, - Process->ProcessId - ))) - goto ErrorExit; - - if (!NT_SUCCESS(status = PhTerminateProcess( - processHandle, - 1 - ))) - goto ErrorExit; - - NtClose(processHandle); - processHandle = NULL; - - // Start the process. - - status = PhCreateProcessWin32( - PhGetString(Process->FileName), // we didn't wait for S1 processing - commandLine->Buffer, - NULL, - currentDirectory->Buffer, - 0, - NULL, - NULL, - NULL - ); - -ErrorExit: - if (processHandle) - NtClose(processHandle); - - if (!NT_SUCCESS(status)) - { - PhpShowErrorProcess(hWnd, L"restart", Process, status, 0); - return FALSE; - } - - return TRUE; -} - -// Contributed by evilpie (#2981421) -BOOLEAN PhUiDebugProcess( - _In_ HWND hWnd, - _In_ PPH_PROCESS_ITEM Process - ) -{ - NTSTATUS status; - BOOLEAN cont = FALSE; - PH_STRING_BUILDER commandLineBuilder; - - if (PhGetIntegerSetting(L"EnableWarnings")) - { - cont = PhShowConfirmMessage( - hWnd, - L"debug", - Process->ProcessName->Buffer, - L"Debugging a process may result in loss of data.", - FALSE - ); - } - else - { - cont = TRUE; - } - - if (!cont) - return FALSE; - - if (PhBeginInitOnce(&DebuggerCommandInitOnce)) - { - static PH_STRINGREF aeDebugKeyName = PH_STRINGREF_INIT(L"Software\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug"); - - HANDLE keyHandle; - PPH_STRING debugger; - PH_STRINGREF commandPart; - PH_STRINGREF dummy; - - if (NT_SUCCESS(PhOpenKey( - &keyHandle, - KEY_READ, - PH_KEY_LOCAL_MACHINE, - &aeDebugKeyName, - 0 - ))) - { - if (debugger = PH_AUTO(PhQueryRegistryString(keyHandle, L"Debugger"))) - { - if (PhSplitStringRefAtChar(&debugger->sr, '"', &dummy, &commandPart) && - PhSplitStringRefAtChar(&commandPart, '"', &commandPart, &dummy)) - { - DebuggerCommand = PhCreateString2(&commandPart); - } - } - - NtClose(keyHandle); - } - - PhEndInitOnce(&DebuggerCommandInitOnce); - } - - if (!DebuggerCommand) - { - PhShowError(hWnd, L"Unable to locate the debugger."); - return FALSE; - } - - PhInitializeStringBuilder(&commandLineBuilder, DebuggerCommand->Length + 30); - - PhAppendCharStringBuilder(&commandLineBuilder, '"'); - PhAppendStringBuilder(&commandLineBuilder, &DebuggerCommand->sr); - PhAppendCharStringBuilder(&commandLineBuilder, '"'); - PhAppendFormatStringBuilder(&commandLineBuilder, L" -p %u", HandleToUlong(Process->ProcessId)); - - status = PhCreateProcessWin32( - NULL, - commandLineBuilder.String->Buffer, - NULL, - NULL, - 0, - NULL, - NULL, - NULL - ); - - PhDeleteStringBuilder(&commandLineBuilder); - - if (!NT_SUCCESS(status)) - { - PhpShowErrorProcess(hWnd, L"debug", Process, status, 0); - return FALSE; - } - - return TRUE; -} - -BOOLEAN PhUiReduceWorkingSetProcesses( - _In_ HWND hWnd, - _In_ PPH_PROCESS_ITEM *Processes, - _In_ ULONG NumberOfProcesses - ) -{ - BOOLEAN success = TRUE; - ULONG i; - - for (i = 0; i < NumberOfProcesses; i++) - { - NTSTATUS status; - HANDLE processHandle; - - if (NT_SUCCESS(status = PhOpenProcess( - &processHandle, - PROCESS_SET_QUOTA, - Processes[i]->ProcessId - ))) - { - QUOTA_LIMITS quotaLimits; - - memset("aLimits, 0, sizeof(QUOTA_LIMITS)); - quotaLimits.MinimumWorkingSetSize = -1; - quotaLimits.MaximumWorkingSetSize = -1; - - status = NtSetInformationProcess( - processHandle, - ProcessQuotaLimits, - "aLimits, - sizeof(QUOTA_LIMITS) - ); - - NtClose(processHandle); - } - - if (!NT_SUCCESS(status)) - { - success = FALSE; - - if (!PhpShowErrorProcess(hWnd, L"reduce the working set of", Processes[i], status, 0)) - break; - } - } - - return success; -} - -BOOLEAN PhUiSetVirtualizationProcess( - _In_ HWND hWnd, - _In_ PPH_PROCESS_ITEM Process, - _In_ BOOLEAN Enable - ) -{ - NTSTATUS status; - BOOLEAN cont = FALSE; - HANDLE processHandle; - HANDLE tokenHandle; - - if (PhGetIntegerSetting(L"EnableWarnings")) - { - cont = PhShowConfirmMessage( - hWnd, - L"set", - L"virtualization for the process", - L"Enabling or disabling virtualization for a process may " - L"alter its functionality and produce undesirable effects.", - FALSE - ); - } - else - { - cont = TRUE; - } - - if (!cont) - return FALSE; - - if (NT_SUCCESS(status = PhOpenProcess( - &processHandle, - ProcessQueryAccess, - Process->ProcessId - ))) - { - if (NT_SUCCESS(status = PhOpenProcessToken( - processHandle, - TOKEN_WRITE, - &tokenHandle - ))) - { - status = PhSetTokenIsVirtualizationEnabled(tokenHandle, Enable); - NtClose(tokenHandle); - } - - NtClose(processHandle); - } - - if (!NT_SUCCESS(status)) - { - PhpShowErrorProcess(hWnd, L"set virtualization for", Process, status, 0); - return FALSE; - } - - return TRUE; -} - -BOOLEAN PhUiDetachFromDebuggerProcess( - _In_ HWND hWnd, - _In_ PPH_PROCESS_ITEM Process - ) -{ - NTSTATUS status; - HANDLE processHandle; - HANDLE debugObjectHandle; - - if (NT_SUCCESS(status = PhOpenProcess( - &processHandle, - PROCESS_QUERY_INFORMATION | PROCESS_SUSPEND_RESUME, - Process->ProcessId - ))) - { - if (NT_SUCCESS(status = PhGetProcessDebugObject( - processHandle, - &debugObjectHandle - ))) - { - ULONG flags; - - // Disable kill-on-close. - flags = 0; - NtSetInformationDebugObject( - debugObjectHandle, - DebugObjectFlags, - &flags, - sizeof(ULONG), - NULL - ); - - status = NtRemoveProcessDebug(processHandle, debugObjectHandle); - - NtClose(debugObjectHandle); - } - - NtClose(processHandle); - } - - if (status == STATUS_PORT_NOT_SET) - { - PhShowInformation(hWnd, L"The process is not being debugged."); - return FALSE; - } - - if (!NT_SUCCESS(status)) - { - PhpShowErrorProcess(hWnd, L"detach debugger from", Process, status, 0); - return FALSE; - } - - return TRUE; -} - -BOOLEAN PhUiInjectDllProcess( - _In_ HWND hWnd, - _In_ PPH_PROCESS_ITEM Process - ) -{ - static PH_FILETYPE_FILTER filters[] = - { - { L"DLL files (*.dll)", L"*.dll" }, - { L"All files (*.*)", L"*.*" } - }; - - NTSTATUS status; - PVOID fileDialog; - PPH_STRING fileName; - HANDLE processHandle; - - fileDialog = PhCreateOpenFileDialog(); - PhSetFileDialogFilter(fileDialog, filters, sizeof(filters) / sizeof(PH_FILETYPE_FILTER)); - - if (!PhShowFileDialog(hWnd, fileDialog)) - { - PhFreeFileDialog(fileDialog); - return FALSE; - } - - fileName = PH_AUTO(PhGetFileDialogFileName(fileDialog)); - PhFreeFileDialog(fileDialog); - - if (NT_SUCCESS(status = PhOpenProcess( - &processHandle, - ProcessQueryAccess | PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | - PROCESS_VM_READ | PROCESS_VM_WRITE, - Process->ProcessId - ))) - { - LARGE_INTEGER timeout; - - timeout.QuadPart = -5 * PH_TIMEOUT_SEC; - status = PhInjectDllProcess( - processHandle, - fileName->Buffer, - &timeout - ); - - NtClose(processHandle); - } - - if (!NT_SUCCESS(status)) - { - PhpShowErrorProcess(hWnd, L"inject the DLL into", Process, status, 0); - return FALSE; - } - - return TRUE; -} - -BOOLEAN PhUiSetIoPriorityProcesses( - _In_ HWND hWnd, - _In_ PPH_PROCESS_ITEM *Processes, - _In_ ULONG NumberOfProcesses, - _In_ IO_PRIORITY_HINT IoPriority - ) -{ - BOOLEAN success = TRUE; - BOOLEAN cancelled = FALSE; - ULONG i; - - for (i = 0; i < NumberOfProcesses; i++) - { - NTSTATUS status; - HANDLE processHandle; - - if (NT_SUCCESS(status = PhOpenProcess( - &processHandle, - PROCESS_SET_INFORMATION, - Processes[i]->ProcessId - ))) - { - if (Processes[i]->ProcessId != SYSTEM_PROCESS_ID) - { - status = PhSetProcessIoPriority(processHandle, IoPriority); - } - else - { - // See comment in PhUiSetPriorityProcesses. - status = STATUS_UNSUCCESSFUL; - } - - NtClose(processHandle); - } - - if (!NT_SUCCESS(status)) - { - BOOLEAN connected; - - success = FALSE; - - // The operation may have failed due to the lack of SeIncreaseBasePriorityPrivilege. - if (!cancelled && PhpShowErrorAndConnectToPhSvc( - hWnd, - PhaConcatStrings2(L"Unable to set the I/O priority of ", Processes[i]->ProcessName->Buffer)->Buffer, - status, - &connected - )) - { - if (connected) - { - if (NT_SUCCESS(status = PhSvcCallControlProcess(Processes[i]->ProcessId, PhSvcControlProcessIoPriority, IoPriority))) - success = TRUE; - else - PhpShowErrorProcess(hWnd, L"set the I/O priority of", Processes[i], status, 0); - - PhUiDisconnectFromPhSvc(); - } - else - { - cancelled = TRUE; - } - } - else - { - if (!PhpShowErrorProcess(hWnd, L"set the I/O priority of", Processes[i], status, 0)) - break; - } - } - } - - return success; -} - -BOOLEAN PhUiSetPagePriorityProcess( - _In_ HWND hWnd, - _In_ PPH_PROCESS_ITEM Process, - _In_ ULONG PagePriority - ) -{ - NTSTATUS status; - HANDLE processHandle; - - if (NT_SUCCESS(status = PhOpenProcess( - &processHandle, - PROCESS_SET_INFORMATION, - Process->ProcessId - ))) - { - if (Process->ProcessId != SYSTEM_PROCESS_ID) - { - status = NtSetInformationProcess( - processHandle, - ProcessPagePriority, - &PagePriority, - sizeof(ULONG) - ); - } - else - { - // See comment in PhUiSetPriorityProcesses. - status = STATUS_UNSUCCESSFUL; - } - - NtClose(processHandle); - } - - if (!NT_SUCCESS(status)) - { - PhpShowErrorProcess(hWnd, L"set the page priority of", Process, status, 0); - return FALSE; - } - - return TRUE; -} - -BOOLEAN PhUiSetPriorityProcesses( - _In_ HWND hWnd, - _In_ PPH_PROCESS_ITEM *Processes, - _In_ ULONG NumberOfProcesses, - _In_ ULONG PriorityClass - ) -{ - BOOLEAN success = TRUE; - BOOLEAN cancelled = FALSE; - ULONG i; - - for (i = 0; i < NumberOfProcesses; i++) - { - NTSTATUS status; - HANDLE processHandle; - PROCESS_PRIORITY_CLASS priorityClass; - - if (NT_SUCCESS(status = PhOpenProcess( - &processHandle, - PROCESS_SET_INFORMATION, - Processes[i]->ProcessId - ))) - { - if (Processes[i]->ProcessId != SYSTEM_PROCESS_ID) - { - priorityClass.Foreground = FALSE; - priorityClass.PriorityClass = (UCHAR)PriorityClass; - status = NtSetInformationProcess(processHandle, ProcessPriorityClass, &priorityClass, sizeof(PROCESS_PRIORITY_CLASS)); - } - else - { - // Changing the priority of System can lead to a BSOD on some versions of Windows, - // so disallow this. - status = STATUS_UNSUCCESSFUL; - } - - NtClose(processHandle); - } - - if (!NT_SUCCESS(status)) - { - BOOLEAN connected; - - success = FALSE; - - // The operation may have failed due to the lack of SeIncreaseBasePriorityPrivilege. - if (!cancelled && PhpShowErrorAndConnectToPhSvc( - hWnd, - PhaConcatStrings2(L"Unable to set the priority of ", Processes[i]->ProcessName->Buffer)->Buffer, - status, - &connected - )) - { - if (connected) - { - if (NT_SUCCESS(status = PhSvcCallControlProcess(Processes[i]->ProcessId, PhSvcControlProcessPriority, PriorityClass))) - success = TRUE; - else - PhpShowErrorProcess(hWnd, L"set the priority of", Processes[i], status, 0); - - PhUiDisconnectFromPhSvc(); - } - else - { - cancelled = TRUE; - } - } - else - { - if (!PhpShowErrorProcess(hWnd, L"set the priority of", Processes[i], status, 0)) - break; - } - } - } - - return success; -} - -static VOID PhpShowErrorService( - _In_ HWND hWnd, - _In_ PWSTR Verb, - _In_ PPH_SERVICE_ITEM Service, - _In_ NTSTATUS Status, - _In_opt_ ULONG Win32Result - ) -{ - PhShowStatus( - hWnd, - PhaFormatString( - L"Unable to %s %s", - Verb, - Service->Name->Buffer - )->Buffer, - Status, - Win32Result - ); -} - -BOOLEAN PhUiStartService( - _In_ HWND hWnd, - _In_ PPH_SERVICE_ITEM Service - ) -{ - SC_HANDLE serviceHandle; - BOOLEAN success = FALSE; - - serviceHandle = PhOpenService(Service->Name->Buffer, SERVICE_START); - - if (serviceHandle) - { - if (StartService(serviceHandle, 0, NULL)) - success = TRUE; - - CloseServiceHandle(serviceHandle); - } - - if (!success) - { - NTSTATUS status; - BOOLEAN connected; - - status = PhGetLastWin32ErrorAsNtStatus(); - - if (PhpShowErrorAndConnectToPhSvc( - hWnd, - PhaConcatStrings2(L"Unable to start ", Service->Name->Buffer)->Buffer, - status, - &connected - )) - { - if (connected) - { - if (NT_SUCCESS(status = PhSvcCallControlService(Service->Name->Buffer, PhSvcControlServiceStart))) - success = TRUE; - else - PhpShowErrorService(hWnd, L"start", Service, status, 0); - - PhUiDisconnectFromPhSvc(); - } - } - else - { - PhpShowErrorService(hWnd, L"start", Service, status, 0); - } - } - - return success; -} - -BOOLEAN PhUiContinueService( - _In_ HWND hWnd, - _In_ PPH_SERVICE_ITEM Service - ) -{ - SC_HANDLE serviceHandle; - BOOLEAN success = FALSE; - - serviceHandle = PhOpenService(Service->Name->Buffer, SERVICE_PAUSE_CONTINUE); - - if (serviceHandle) - { - SERVICE_STATUS serviceStatus; - - if (ControlService(serviceHandle, SERVICE_CONTROL_CONTINUE, &serviceStatus)) - success = TRUE; - - CloseServiceHandle(serviceHandle); - } - - if (!success) - { - NTSTATUS status; - BOOLEAN connected; - - status = PhGetLastWin32ErrorAsNtStatus(); - - if (PhpShowErrorAndConnectToPhSvc( - hWnd, - PhaConcatStrings2(L"Unable to continue ", Service->Name->Buffer)->Buffer, - status, - &connected - )) - { - if (connected) - { - if (NT_SUCCESS(status = PhSvcCallControlService(Service->Name->Buffer, PhSvcControlServiceContinue))) - success = TRUE; - else - PhpShowErrorService(hWnd, L"continue", Service, status, 0); - - PhUiDisconnectFromPhSvc(); - } - } - else - { - PhpShowErrorService(hWnd, L"continue", Service, status, 0); - } - } - - return success; -} - -BOOLEAN PhUiPauseService( - _In_ HWND hWnd, - _In_ PPH_SERVICE_ITEM Service - ) -{ - SC_HANDLE serviceHandle; - BOOLEAN success = FALSE; - - serviceHandle = PhOpenService(Service->Name->Buffer, SERVICE_PAUSE_CONTINUE); - - if (serviceHandle) - { - SERVICE_STATUS serviceStatus; - - if (ControlService(serviceHandle, SERVICE_CONTROL_PAUSE, &serviceStatus)) - success = TRUE; - - CloseServiceHandle(serviceHandle); - } - - if (!success) - { - NTSTATUS status; - BOOLEAN connected; - - status = PhGetLastWin32ErrorAsNtStatus(); - - if (PhpShowErrorAndConnectToPhSvc( - hWnd, - PhaConcatStrings2(L"Unable to pause ", Service->Name->Buffer)->Buffer, - status, - &connected - )) - { - if (connected) - { - if (NT_SUCCESS(status = PhSvcCallControlService(Service->Name->Buffer, PhSvcControlServicePause))) - success = TRUE; - else - PhpShowErrorService(hWnd, L"pause", Service, status, 0); - - PhUiDisconnectFromPhSvc(); - } - } - else - { - PhpShowErrorService(hWnd, L"pause", Service, status, 0); - } - } - - return success; -} - -BOOLEAN PhUiStopService( - _In_ HWND hWnd, - _In_ PPH_SERVICE_ITEM Service - ) -{ - SC_HANDLE serviceHandle; - BOOLEAN success = FALSE; - - serviceHandle = PhOpenService(Service->Name->Buffer, SERVICE_STOP); - - if (serviceHandle) - { - SERVICE_STATUS serviceStatus; - - if (ControlService(serviceHandle, SERVICE_CONTROL_STOP, &serviceStatus)) - success = TRUE; - - CloseServiceHandle(serviceHandle); - } - - if (!success) - { - NTSTATUS status; - BOOLEAN connected; - - status = PhGetLastWin32ErrorAsNtStatus(); - - if (PhpShowErrorAndConnectToPhSvc( - hWnd, - PhaConcatStrings2(L"Unable to stop ", Service->Name->Buffer)->Buffer, - status, - &connected - )) - { - if (connected) - { - if (NT_SUCCESS(status = PhSvcCallControlService(Service->Name->Buffer, PhSvcControlServiceStop))) - success = TRUE; - else - PhpShowErrorService(hWnd, L"stop", Service, status, 0); - - PhUiDisconnectFromPhSvc(); - } - } - else - { - PhpShowErrorService(hWnd, L"stop", Service, status, 0); - } - } - - return success; -} - -BOOLEAN PhUiDeleteService( - _In_ HWND hWnd, - _In_ PPH_SERVICE_ITEM Service - ) -{ - SC_HANDLE serviceHandle; - BOOLEAN success = FALSE; - - // Warnings cannot be disabled for service deletion. - if (!PhShowConfirmMessage( - hWnd, - L"delete", - Service->Name->Buffer, - L"Deleting a service can prevent the system from starting " - L"or functioning properly.", - TRUE - )) - return FALSE; - - serviceHandle = PhOpenService(Service->Name->Buffer, DELETE); - - if (serviceHandle) - { - if (DeleteService(serviceHandle)) - success = TRUE; - - CloseServiceHandle(serviceHandle); - } - - if (!success) - { - NTSTATUS status; - BOOLEAN connected; - - status = PhGetLastWin32ErrorAsNtStatus(); - - if (PhpShowErrorAndConnectToPhSvc( - hWnd, - PhaConcatStrings2(L"Unable to delete ", Service->Name->Buffer)->Buffer, - status, - &connected - )) - { - if (connected) - { - if (NT_SUCCESS(status = PhSvcCallControlService(Service->Name->Buffer, PhSvcControlServiceDelete))) - success = TRUE; - else - PhpShowErrorService(hWnd, L"delete", Service, status, 0); - - PhUiDisconnectFromPhSvc(); - } - } - else - { - PhpShowErrorService(hWnd, L"delete", Service, status, 0); - } - } - - return success; -} - -BOOLEAN PhUiCloseConnections( - _In_ HWND hWnd, - _In_ PPH_NETWORK_ITEM *Connections, - _In_ ULONG NumberOfConnections - ) -{ - - BOOLEAN success = TRUE; - BOOLEAN cancelled = FALSE; - ULONG result; - ULONG i; - _SetTcpEntry SetTcpEntry_I; - MIB_TCPROW tcpRow; - - SetTcpEntry_I = PhGetModuleProcAddress(L"iphlpapi.dll", "SetTcpEntry"); - - if (!SetTcpEntry_I) - { - PhShowError( - hWnd, - L"This feature is not supported by your operating system." - ); - return FALSE; - } - - for (i = 0; i < NumberOfConnections; i++) - { - if ( - Connections[i]->ProtocolType != PH_TCP4_NETWORK_PROTOCOL || - Connections[i]->State != MIB_TCP_STATE_ESTAB - ) - continue; - - tcpRow.dwState = MIB_TCP_STATE_DELETE_TCB; - tcpRow.dwLocalAddr = Connections[i]->LocalEndpoint.Address.Ipv4; - tcpRow.dwLocalPort = _byteswap_ushort((USHORT)Connections[i]->LocalEndpoint.Port); - tcpRow.dwRemoteAddr = Connections[i]->RemoteEndpoint.Address.Ipv4; - tcpRow.dwRemotePort = _byteswap_ushort((USHORT)Connections[i]->RemoteEndpoint.Port); - - if ((result = SetTcpEntry_I(&tcpRow)) != 0) - { - NTSTATUS status; - BOOLEAN connected; - - success = FALSE; - - // SetTcpEntry returns ERROR_MR_MID_NOT_FOUND for access denied errors for some reason. - if (result == ERROR_MR_MID_NOT_FOUND) - result = ERROR_ACCESS_DENIED; - - if (!cancelled && PhpShowErrorAndConnectToPhSvc( - hWnd, - L"Unable to close the TCP connection", - NTSTATUS_FROM_WIN32(result), - &connected - )) - { - if (connected) - { - if (NT_SUCCESS(status = PhSvcCallSetTcpEntry(&tcpRow))) - success = TRUE; - else - PhShowStatus(hWnd, L"Unable to close the TCP connection", status, 0); - - PhUiDisconnectFromPhSvc(); - } - else - { - cancelled = TRUE; - } - } - else - { - if (PhShowMessage( - hWnd, - MB_ICONERROR | MB_OKCANCEL, - L"Unable to close the TCP connection (from %s:%u). " - L"Make sure Process Hacker is running with administrative privileges.", - Connections[i]->LocalAddressString, - Connections[i]->LocalEndpoint.Port - ) != IDOK) - break; - } - } - } - - return success; -} - -static BOOLEAN PhpShowContinueMessageThreads( - _In_ HWND hWnd, - _In_ PWSTR Verb, - _In_ PWSTR Message, - _In_ BOOLEAN Warning, - _In_ PPH_THREAD_ITEM *Threads, - _In_ ULONG NumberOfThreads - ) -{ - PWSTR object; - BOOLEAN cont = FALSE; - - if (NumberOfThreads == 0) - return FALSE; - - if (PhGetIntegerSetting(L"EnableWarnings")) - { - if (NumberOfThreads == 1) - { - object = L"the selected thread"; - } - else - { - object = L"the selected threads"; - } - - cont = PhShowConfirmMessage( - hWnd, - Verb, - object, - Message, - Warning - ); - } - else - { - cont = TRUE; - } - - return cont; -} - -static BOOLEAN PhpShowErrorThread( - _In_ HWND hWnd, - _In_ PWSTR Verb, - _In_ PPH_THREAD_ITEM Thread, - _In_ NTSTATUS Status, - _In_opt_ ULONG Win32Result - ) -{ - return PhShowContinueStatus( - hWnd, - PhaFormatString( - L"Unable to %s thread %u", - Verb, - HandleToUlong(Thread->ThreadId) - )->Buffer, - Status, - Win32Result - ); -} - -BOOLEAN PhUiTerminateThreads( - _In_ HWND hWnd, - _In_ PPH_THREAD_ITEM *Threads, - _In_ ULONG NumberOfThreads - ) -{ - BOOLEAN success = TRUE; - BOOLEAN cancelled = FALSE; - ULONG i; - - if (!PhpShowContinueMessageThreads( - hWnd, - L"terminate", - L"Terminating a thread may cause the process to stop working.", - FALSE, - Threads, - NumberOfThreads - )) - return FALSE; - - for (i = 0; i < NumberOfThreads; i++) - { - NTSTATUS status; - HANDLE threadHandle; - - if (NT_SUCCESS(status = PhOpenThread( - &threadHandle, - THREAD_TERMINATE, - Threads[i]->ThreadId - ))) - { - status = NtTerminateThread(threadHandle, STATUS_SUCCESS); - NtClose(threadHandle); - } - - if (!NT_SUCCESS(status)) - { - BOOLEAN connected; - - success = FALSE; - - if (!cancelled && PhpShowErrorAndConnectToPhSvc( - hWnd, - PhaFormatString(L"Unable to terminate thread %u", HandleToUlong(Threads[i]->ThreadId))->Buffer, - status, - &connected - )) - { - if (connected) - { - if (NT_SUCCESS(status = PhSvcCallControlThread(Threads[i]->ThreadId, PhSvcControlThreadTerminate, 0))) - success = TRUE; - else - PhpShowErrorThread(hWnd, L"terminate", Threads[i], status, 0); - - PhUiDisconnectFromPhSvc(); - } - else - { - cancelled = TRUE; - } - } - else - { - if (!PhpShowErrorThread(hWnd, L"terminate", Threads[i], status, 0)) - break; - } - } - } - - return success; -} - -BOOLEAN PhUiSuspendThreads( - _In_ HWND hWnd, - _In_ PPH_THREAD_ITEM *Threads, - _In_ ULONG NumberOfThreads - ) -{ - BOOLEAN success = TRUE; - BOOLEAN cancelled = FALSE; - ULONG i; - - for (i = 0; i < NumberOfThreads; i++) - { - NTSTATUS status; - HANDLE threadHandle; - - if (NT_SUCCESS(status = PhOpenThread( - &threadHandle, - THREAD_SUSPEND_RESUME, - Threads[i]->ThreadId - ))) - { - status = NtSuspendThread(threadHandle, NULL); - NtClose(threadHandle); - } - - if (!NT_SUCCESS(status)) - { - BOOLEAN connected; - - success = FALSE; - - if (!cancelled && PhpShowErrorAndConnectToPhSvc( - hWnd, - PhaFormatString(L"Unable to suspend thread %u", HandleToUlong(Threads[i]->ThreadId))->Buffer, - status, - &connected - )) - { - if (connected) - { - if (NT_SUCCESS(status = PhSvcCallControlThread(Threads[i]->ThreadId, PhSvcControlThreadSuspend, 0))) - success = TRUE; - else - PhpShowErrorThread(hWnd, L"suspend", Threads[i], status, 0); - - PhUiDisconnectFromPhSvc(); - } - else - { - cancelled = TRUE; - } - } - else - { - if (!PhpShowErrorThread(hWnd, L"suspend", Threads[i], status, 0)) - break; - } - } - } - - return success; -} - -BOOLEAN PhUiResumeThreads( - _In_ HWND hWnd, - _In_ PPH_THREAD_ITEM *Threads, - _In_ ULONG NumberOfThreads - ) -{ - BOOLEAN success = TRUE; - BOOLEAN cancelled = FALSE; - ULONG i; - - for (i = 0; i < NumberOfThreads; i++) - { - NTSTATUS status; - HANDLE threadHandle; - - if (NT_SUCCESS(status = PhOpenThread( - &threadHandle, - THREAD_SUSPEND_RESUME, - Threads[i]->ThreadId - ))) - { - status = NtResumeThread(threadHandle, NULL); - NtClose(threadHandle); - } - - if (!NT_SUCCESS(status)) - { - BOOLEAN connected; - - success = FALSE; - - if (!cancelled && PhpShowErrorAndConnectToPhSvc( - hWnd, - PhaFormatString(L"Unable to resume thread %u", HandleToUlong(Threads[i]->ThreadId))->Buffer, - status, - &connected - )) - { - if (connected) - { - if (NT_SUCCESS(status = PhSvcCallControlThread(Threads[i]->ThreadId, PhSvcControlThreadResume, 0))) - success = TRUE; - else - PhpShowErrorThread(hWnd, L"resume", Threads[i], status, 0); - - PhUiDisconnectFromPhSvc(); - } - else - { - cancelled = TRUE; - } - } - else - { - if (!PhpShowErrorThread(hWnd, L"resume", Threads[i], status, 0)) - break; - } - } - } - - return success; -} - -BOOLEAN PhUiSetPriorityThread( - _In_ HWND hWnd, - _In_ PPH_THREAD_ITEM Thread, - _In_ LONG Increment - ) -{ - NTSTATUS status; - HANDLE threadHandle; - - // Special saturation values - if (Increment == THREAD_PRIORITY_TIME_CRITICAL) - Increment = THREAD_BASE_PRIORITY_LOWRT + 1; - else if (Increment == THREAD_PRIORITY_IDLE) - Increment = THREAD_BASE_PRIORITY_IDLE - 1; - - if (NT_SUCCESS(status = PhOpenThread( - &threadHandle, - ThreadSetAccess, - Thread->ThreadId - ))) - { - status = NtSetInformationThread(threadHandle, ThreadBasePriority, &Increment, sizeof(LONG)); - NtClose(threadHandle); - } - - if (!NT_SUCCESS(status)) - { - PhpShowErrorThread(hWnd, L"set the priority of", Thread, status, 0); - return FALSE; - } - - return TRUE; -} - -BOOLEAN PhUiSetIoPriorityThread( - _In_ HWND hWnd, - _In_ PPH_THREAD_ITEM Thread, - _In_ IO_PRIORITY_HINT IoPriority - ) -{ - NTSTATUS status; - BOOLEAN success = TRUE; - HANDLE threadHandle; - - if (NT_SUCCESS(status = PhOpenThread( - &threadHandle, - THREAD_SET_INFORMATION, - Thread->ThreadId - ))) - { - status = PhSetThreadIoPriority(threadHandle, IoPriority); - NtClose(threadHandle); - } - - if (!NT_SUCCESS(status)) - { - BOOLEAN connected; - - success = FALSE; - - // The operation may have failed due to the lack of SeIncreaseBasePriorityPrivilege. - if (PhpShowErrorAndConnectToPhSvc( - hWnd, - PhaFormatString(L"Unable to set the I/O priority of thread %u", HandleToUlong(Thread->ThreadId))->Buffer, - status, - &connected - )) - { - if (connected) - { - if (NT_SUCCESS(status = PhSvcCallControlThread(Thread->ThreadId, PhSvcControlThreadIoPriority, IoPriority))) - success = TRUE; - else - PhpShowErrorThread(hWnd, L"set the I/O priority of", Thread, status, 0); - - PhUiDisconnectFromPhSvc(); - } - } - else - { - PhpShowErrorThread(hWnd, L"set the I/O priority of", Thread, status, 0); - } - } - - return success; -} - -BOOLEAN PhUiSetPagePriorityThread( - _In_ HWND hWnd, - _In_ PPH_THREAD_ITEM Thread, - _In_ ULONG PagePriority - ) -{ - NTSTATUS status; - HANDLE threadHandle; - - if (NT_SUCCESS(status = PhOpenThread( - &threadHandle, - THREAD_SET_INFORMATION, - Thread->ThreadId - ))) - { - status = NtSetInformationThread( - threadHandle, - ThreadPagePriority, - &PagePriority, - sizeof(ULONG) - ); - NtClose(threadHandle); - } - - if (!NT_SUCCESS(status)) - { - PhpShowErrorThread(hWnd, L"set the page priority of", Thread, status, 0); - return FALSE; - } - - return TRUE; -} - -BOOLEAN PhUiUnloadModule( - _In_ HWND hWnd, - _In_ HANDLE ProcessId, - _In_ PPH_MODULE_ITEM Module - ) -{ - NTSTATUS status; - BOOLEAN cont = FALSE; - HANDLE processHandle; - - if (PhGetIntegerSetting(L"EnableWarnings")) - { - PWSTR verb; - PWSTR message; - - switch (Module->Type) - { - case PH_MODULE_TYPE_MODULE: - case PH_MODULE_TYPE_WOW64_MODULE: - verb = L"unload"; - message = L"Unloading a module may cause the process to crash."; - - if (WindowsVersion >= WINDOWS_8) - message = L"Unloading a module may cause the process to crash. NOTE: This feature may not work correctly on your version of Windows."; - - break; - case PH_MODULE_TYPE_KERNEL_MODULE: - verb = L"unload"; - message = L"Unloading a driver may cause system instability."; - break; - case PH_MODULE_TYPE_MAPPED_FILE: - case PH_MODULE_TYPE_MAPPED_IMAGE: - verb = L"unmap"; - message = L"Unmapping a section view may cause the process to crash."; - break; - default: - return FALSE; - } - - cont = PhShowConfirmMessage( - hWnd, - verb, - Module->Name->Buffer, - message, - TRUE - ); - } - else - { - cont = TRUE; - } - - if (!cont) - return FALSE; - - switch (Module->Type) - { - case PH_MODULE_TYPE_MODULE: - case PH_MODULE_TYPE_WOW64_MODULE: - if (NT_SUCCESS(status = PhOpenProcess( - &processHandle, - ProcessQueryAccess | PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | - PROCESS_VM_READ | PROCESS_VM_WRITE, - ProcessId - ))) - { - LARGE_INTEGER timeout; - - timeout.QuadPart = -5 * PH_TIMEOUT_SEC; - status = PhUnloadDllProcess( - processHandle, - Module->BaseAddress, - &timeout - ); - - NtClose(processHandle); - } - - if (status == STATUS_DLL_NOT_FOUND) - { - PhShowError(hWnd, L"Unable to find the module to unload."); - return FALSE; - } - - if (!NT_SUCCESS(status)) - { - PhShowStatus( - hWnd, - PhaConcatStrings2(L"Unable to unload ", Module->Name->Buffer)->Buffer, - status, - 0 - ); - return FALSE; - } - - break; - - case PH_MODULE_TYPE_KERNEL_MODULE: - status = PhUnloadDriver(Module->BaseAddress, Module->Name->Buffer); - - if (!NT_SUCCESS(status)) - { - BOOLEAN success = FALSE; - BOOLEAN connected; - - if (PhpShowErrorAndConnectToPhSvc( - hWnd, - PhaConcatStrings2(L"Unable to unload ", Module->Name->Buffer)->Buffer, - status, - &connected - )) - { - if (connected) - { - if (NT_SUCCESS(status = PhSvcCallUnloadDriver(Module->BaseAddress, Module->Name->Buffer))) - success = TRUE; - else - PhShowStatus(hWnd, PhaConcatStrings2(L"Unable to unload ", Module->Name->Buffer)->Buffer, status, 0); - - PhUiDisconnectFromPhSvc(); - } - } - else - { - PhShowStatus( - hWnd, - PhaConcatStrings( - 3, - L"Unable to unload ", - Module->Name->Buffer, - L". Make sure Process Hacker is running with " - L"administrative privileges. Error" - )->Buffer, - status, - 0 - ); - return FALSE; - } - - return success; - } - - break; - - case PH_MODULE_TYPE_MAPPED_FILE: - case PH_MODULE_TYPE_MAPPED_IMAGE: - if (NT_SUCCESS(status = PhOpenProcess( - &processHandle, - PROCESS_VM_OPERATION, - ProcessId - ))) - { - status = NtUnmapViewOfSection(processHandle, Module->BaseAddress); - NtClose(processHandle); - } - - if (!NT_SUCCESS(status)) - { - PhShowStatus( - hWnd, - PhaFormatString(L"Unable to unmap the section view at 0x%Ix", Module->BaseAddress)->Buffer, - status, - 0 - ); - return FALSE; - } - - break; - - default: - return FALSE; - } - - return TRUE; -} - -BOOLEAN PhUiFreeMemory( - _In_ HWND hWnd, - _In_ HANDLE ProcessId, - _In_ PPH_MEMORY_ITEM MemoryItem, - _In_ BOOLEAN Free - ) -{ - NTSTATUS status; - BOOLEAN cont = FALSE; - HANDLE processHandle; - - if (PhGetIntegerSetting(L"EnableWarnings")) - { - PWSTR verb; - PWSTR message; - - if (!(MemoryItem->Type & (MEM_MAPPED | MEM_IMAGE))) - { - if (Free) - { - verb = L"free"; - message = L"Freeing memory regions may cause the process to crash."; - } - else - { - verb = L"decommit"; - message = L"Decommitting memory regions may cause the process to crash."; - } - } - else - { - verb = L"unmap"; - message = L"Unmapping a section view may cause the process to crash."; - } - - cont = PhShowConfirmMessage( - hWnd, - verb, - L"the memory region", - message, - TRUE - ); - } - else - { - cont = TRUE; - } - - if (!cont) - return FALSE; - - if (NT_SUCCESS(status = PhOpenProcess( - &processHandle, - PROCESS_VM_OPERATION, - ProcessId - ))) - { - PVOID baseAddress; - SIZE_T regionSize; - - baseAddress = MemoryItem->BaseAddress; - - if (!(MemoryItem->Type & (MEM_MAPPED | MEM_IMAGE))) - { - // The size needs to be 0 if we're freeing. - if (Free) - regionSize = 0; - else - regionSize = MemoryItem->RegionSize; - - status = NtFreeVirtualMemory( - processHandle, - &baseAddress, - ®ionSize, - Free ? MEM_RELEASE : MEM_DECOMMIT - ); - } - else - { - status = NtUnmapViewOfSection(processHandle, baseAddress); - } - - NtClose(processHandle); - } - - if (!NT_SUCCESS(status)) - { - PWSTR message; - - if (!(MemoryItem->Type & (MEM_MAPPED | MEM_IMAGE))) - { - if (Free) - message = L"Unable to free the memory region"; - else - message = L"Unable to decommit the memory region"; - } - else - { - message = L"Unable to unmap the section view"; - } - - PhShowStatus( - hWnd, - message, - status, - 0 - ); - return FALSE; - } - - return TRUE; -} - -static BOOLEAN PhpShowErrorHandle( - _In_ HWND hWnd, - _In_ PWSTR Verb, - _In_ PPH_HANDLE_ITEM Handle, - _In_ NTSTATUS Status, - _In_opt_ ULONG Win32Result - ) -{ - if (!PhIsNullOrEmptyString(Handle->BestObjectName)) - { - return PhShowContinueStatus( - hWnd, - PhaFormatString( - L"Unable to %s handle \"%s\" (0x%Ix)", - Verb, - Handle->BestObjectName->Buffer, - HandleToUlong(Handle->Handle) - )->Buffer, - Status, - Win32Result - ); - } - else - { - return PhShowContinueStatus( - hWnd, - PhaFormatString( - L"Unable to %s handle 0x%Ix", - Verb, - HandleToUlong(Handle->Handle) - )->Buffer, - Status, - Win32Result - ); - } -} - -BOOLEAN PhUiCloseHandles( - _In_ HWND hWnd, - _In_ HANDLE ProcessId, - _In_ PPH_HANDLE_ITEM *Handles, - _In_ ULONG NumberOfHandles, - _In_ BOOLEAN Warn - ) -{ - NTSTATUS status; - BOOLEAN cont = FALSE; - BOOLEAN success = TRUE; - HANDLE processHandle; - - if (NumberOfHandles == 0) - return FALSE; - - if (Warn && PhGetIntegerSetting(L"EnableWarnings")) - { - cont = PhShowConfirmMessage( - hWnd, - L"close", - NumberOfHandles == 1 ? L"the selected handle" : L"the selected handles", - L"Closing handles may cause system instability and data corruption.", - FALSE - ); - } - else - { - cont = TRUE; - } - - if (!cont) - return FALSE; - - if (NT_SUCCESS(status = PhOpenProcess( - &processHandle, - PROCESS_DUP_HANDLE, - ProcessId - ))) - { - ULONG i; - - for (i = 0; i < NumberOfHandles; i++) - { - status = NtDuplicateObject( - processHandle, - Handles[i]->Handle, - NULL, - NULL, - 0, - 0, - DUPLICATE_CLOSE_SOURCE - ); - - if (!NT_SUCCESS(status)) - { - success = FALSE; - - if (!PhpShowErrorHandle( - hWnd, - L"close", - Handles[i], - status, - 0 - )) - break; - } - } - - NtClose(processHandle); - } - else - { - PhShowStatus(hWnd, L"Unable to open the process", status, 0); - return FALSE; - } - - return success; -} - -BOOLEAN PhUiSetAttributesHandle( - _In_ HWND hWnd, - _In_ HANDLE ProcessId, - _In_ PPH_HANDLE_ITEM Handle, - _In_ ULONG Attributes - ) -{ - NTSTATUS status; - HANDLE processHandle; - - if (!KphIsConnected()) - { - PhShowError(hWnd, PH_KPH_ERROR_MESSAGE); - return FALSE; - } - - if (NT_SUCCESS(status = PhOpenProcess( - &processHandle, - ProcessQueryAccess, - ProcessId - ))) - { - OBJECT_HANDLE_FLAG_INFORMATION handleFlagInfo; - - handleFlagInfo.Inherit = !!(Attributes & OBJ_INHERIT); - handleFlagInfo.ProtectFromClose = !!(Attributes & OBJ_PROTECT_CLOSE); - - status = KphSetInformationObject( - processHandle, - Handle->Handle, - KphObjectHandleFlagInformation, - &handleFlagInfo, - sizeof(OBJECT_HANDLE_FLAG_INFORMATION) - ); - - NtClose(processHandle); - } - - if (!NT_SUCCESS(status)) - { - PhpShowErrorHandle(hWnd, L"set attributes of", Handle, status, 0); - return FALSE; - } - - return TRUE; -} +/* + * Process Hacker - + * UI actions + * + * Copyright (C) 2010-2016 wj32 + * Copyright (C) 2017 dmex + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +/* + * These are a set of consistent functions which will perform actions on objects such as processes, + * threads and services, while displaying any necessary prompts and error messages. Automatic + * elevation can also easily be added if necessary. + */ + +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef DWORD (WINAPI *_SetTcpEntry)( + _In_ PMIB_TCPROW pTcpRow + ); + +static PWSTR DangerousProcesses[] = +{ + L"csrss.exe", L"dwm.exe", L"logonui.exe", L"lsass.exe", L"lsm.exe", + L"services.exe", L"smss.exe", L"wininit.exe", L"winlogon.exe" +}; + +static PPH_STRING DebuggerCommand = NULL; +static PH_INITONCE DebuggerCommandInitOnce = PH_INITONCE_INIT; +static ULONG PhSvcReferenceCount = 0; +static PH_PHSVC_MODE PhSvcCurrentMode; +static PH_QUEUED_LOCK PhSvcStartLock = PH_QUEUED_LOCK_INIT; + +HRESULT CALLBACK PhpElevateActionCallbackProc( + _In_ HWND hwnd, + _In_ UINT uNotification, + _In_ WPARAM wParam, + _In_ LPARAM lParam, + _In_ LONG_PTR dwRefData + ) +{ + switch (uNotification) + { + case TDN_CREATED: + SendMessage(hwnd, TDM_SET_BUTTON_ELEVATION_REQUIRED_STATE, IDYES, TRUE); + break; + } + + return S_OK; +} + +BOOLEAN PhpShowElevatePrompt( + _In_ HWND hWnd, + _In_ PWSTR Message, + _In_ NTSTATUS Status, + _Out_ PINT Button + ) +{ + TASKDIALOGCONFIG config = { sizeof(config) }; + TASKDIALOG_BUTTON buttons[1]; + INT button; + + // Currently the error dialog box is similar to the one displayed + // when you try to label a drive in Windows Explorer. It's much better + // than the clunky dialog in PH 1.x. + + config.hwndParent = hWnd; + config.hInstance = PhInstanceHandle; + config.dwFlags = IsWindowVisible(hWnd) ? TDF_POSITION_RELATIVE_TO_WINDOW : 0; + config.pszWindowTitle = L"Process Hacker"; + config.pszMainIcon = TD_ERROR_ICON; + config.pszMainInstruction = PhaConcatStrings2(Message, L".")->Buffer; + config.pszContent = L"You will need to provide administrator permission. " + L"Click Continue to complete this operation."; + config.dwCommonButtons = TDCBF_CANCEL_BUTTON; + + buttons[0].nButtonID = IDYES; + buttons[0].pszButtonText = L"Continue"; + + config.cButtons = 1; + config.pButtons = buttons; + config.nDefaultButton = IDYES; + + config.pfCallback = PhpElevateActionCallbackProc; + + if (TaskDialogIndirect( + &config, + &button, + NULL, + NULL + ) == S_OK) + { + *Button = button; + return TRUE; + } + else + { + return FALSE; + } +} + +/** + * Shows an error, prompts for elevation, and executes a command. + * + * \param hWnd The window to display user interface components on. + * \param Message A message describing the operation that failed. + * \param Status A NTSTATUS value. + * \param Command The arguments to pass to the new instance of + * the application, if required. + * \param Success A variable which receives TRUE if the elevated + * action succeeded or FALSE if the action failed. + * + * \return TRUE if the user was prompted for elevation, otherwise + * FALSE, in which case you need to show your own error message. + */ +BOOLEAN PhpShowErrorAndElevateAction( + _In_ HWND hWnd, + _In_ PWSTR Message, + _In_ NTSTATUS Status, + _In_ PWSTR Command, + _Out_ PBOOLEAN Success + ) +{ + PH_ACTION_ELEVATION_LEVEL elevationLevel; + INT button = IDNO; + + if (!( + Status == STATUS_ACCESS_DENIED || + Status == STATUS_PRIVILEGE_NOT_HELD || + (NT_NTWIN32(Status) && WIN32_FROM_NTSTATUS(Status) == ERROR_ACCESS_DENIED) + )) + return FALSE; + + if (!WINDOWS_HAS_UAC || PhGetOwnTokenAttributes().Elevated) + return FALSE; + + elevationLevel = PhGetIntegerSetting(L"ElevationLevel"); + + if (elevationLevel == NeverElevateAction) + return FALSE; + + if (elevationLevel == PromptElevateAction) + { + if (!PhpShowElevatePrompt(hWnd, Message, Status, &button)) + return FALSE; + } + + if (elevationLevel == AlwaysElevateAction || button == IDYES) + { + NTSTATUS status; + HANDLE processHandle; + LARGE_INTEGER timeout; + PROCESS_BASIC_INFORMATION basicInfo; + + if (PhShellProcessHacker( + hWnd, + Command, + SW_SHOW, + PH_SHELL_EXECUTE_ADMIN, + PH_SHELL_APP_PROPAGATE_PARAMETERS, + 0, + &processHandle + )) + { + timeout.QuadPart = -10 * PH_TIMEOUT_SEC; + status = NtWaitForSingleObject(processHandle, FALSE, &timeout); + + if ( + status == STATUS_WAIT_0 && + NT_SUCCESS(status = PhGetProcessBasicInformation(processHandle, &basicInfo)) + ) + { + status = basicInfo.ExitStatus; + } + + NtClose(processHandle); + + if (NT_SUCCESS(status)) + { + *Success = TRUE; + } + else + { + *Success = FALSE; + PhShowStatus(hWnd, Message, status, 0); + } + } + } + + return TRUE; +} + +/** + * Shows an error, prompts for elevation, and connects to phsvc. + * + * \param hWnd The window to display user interface components on. + * \param Message A message describing the operation that failed. + * \param Status A NTSTATUS value. + * \param Connected A variable which receives TRUE if the user + * elevated the action and phsvc was started, or FALSE if the user + * cancelled elevation. If the value is TRUE, you need to + * perform any necessary phsvc calls and use PhUiDisconnectFromPhSvc() + * to disconnect from phsvc. + * + * \return TRUE if the user was prompted for elevation, otherwise + * FALSE, in which case you need to show your own error message. + */ +BOOLEAN PhpShowErrorAndConnectToPhSvc( + _In_ HWND hWnd, + _In_ PWSTR Message, + _In_ NTSTATUS Status, + _Out_ PBOOLEAN Connected + ) +{ + PH_ACTION_ELEVATION_LEVEL elevationLevel; + INT button = IDNO; + + *Connected = FALSE; + + if (!( + Status == STATUS_ACCESS_DENIED || + Status == STATUS_PRIVILEGE_NOT_HELD || + (NT_NTWIN32(Status) && WIN32_FROM_NTSTATUS(Status) == ERROR_ACCESS_DENIED) + )) + return FALSE; + + if (!WINDOWS_HAS_UAC || PhGetOwnTokenAttributes().Elevated) + return FALSE; + + elevationLevel = PhGetIntegerSetting(L"ElevationLevel"); + + if (elevationLevel == NeverElevateAction) + return FALSE; + + // Try to connect now so we can avoid prompting the user. + if (PhUiConnectToPhSvc(hWnd, TRUE)) + { + *Connected = TRUE; + return TRUE; + } + + if (elevationLevel == PromptElevateAction) + { + if (!PhpShowElevatePrompt(hWnd, Message, Status, &button)) + return FALSE; + } + + if (elevationLevel == AlwaysElevateAction || button == IDYES) + { + *Connected = PhUiConnectToPhSvc(hWnd, FALSE); + } + + return TRUE; +} + +/** + * Connects to phsvc. + * + * \param hWnd The window to display user interface components on. + * \param ConnectOnly TRUE to only try to connect to phsvc, otherwise + * FALSE to try to elevate and start phsvc if the initial connection + * attempt failed. + */ +BOOLEAN PhUiConnectToPhSvc( + _In_opt_ HWND hWnd, + _In_ BOOLEAN ConnectOnly + ) +{ + return PhUiConnectToPhSvcEx(hWnd, ElevatedPhSvcMode, ConnectOnly); +} + +VOID PhpGetPhSvcPortName( + _In_ PH_PHSVC_MODE Mode, + _Out_ PUNICODE_STRING PortName + ) +{ + switch (Mode) + { + case ElevatedPhSvcMode: + if (!PhIsExecutingInWow64()) + RtlInitUnicodeString(PortName, PHSVC_PORT_NAME); + else + RtlInitUnicodeString(PortName, PHSVC_WOW64_PORT_NAME); + break; + case Wow64PhSvcMode: + RtlInitUnicodeString(PortName, PHSVC_WOW64_PORT_NAME); + break; + default: + PhRaiseStatus(STATUS_INVALID_PARAMETER); + break; + } +} + +BOOLEAN PhpStartPhSvcProcess( + _In_opt_ HWND hWnd, + _In_ PH_PHSVC_MODE Mode + ) +{ + switch (Mode) + { + case ElevatedPhSvcMode: + if (PhShellProcessHacker( + hWnd, + L"-phsvc", + SW_HIDE, + PH_SHELL_EXECUTE_ADMIN, + PH_SHELL_APP_PROPAGATE_PARAMETERS, + 0, + NULL + )) + { + return TRUE; + } + + break; + case Wow64PhSvcMode: + { + static PWSTR relativeFileNames[] = + { + L"\\x86\\ProcessHacker.exe", + L"\\..\\x86\\ProcessHacker.exe", +#ifdef DEBUG + L"\\..\\Debug32\\ProcessHacker.exe", +#endif + L"\\..\\Release32\\ProcessHacker.exe" + }; + + ULONG i; + + for (i = 0; i < sizeof(relativeFileNames) / sizeof(PWSTR); i++) + { + PPH_STRING fileName; + + fileName = PhConcatStrings2(PhApplicationDirectory->Buffer, relativeFileNames[i]); + PhMoveReference(&fileName, PhGetFullPath(fileName->Buffer, NULL)); + + if (fileName && RtlDoesFileExists_U(fileName->Buffer)) + { + if (PhShellProcessHackerEx( + hWnd, + fileName->Buffer, + L"-phsvc", + SW_HIDE, + 0, + PH_SHELL_APP_PROPAGATE_PARAMETERS, + 0, + NULL + )) + { + PhDereferenceObject(fileName); + return TRUE; + } + } + + PhClearReference(&fileName); + } + } + break; + } + + return FALSE; +} + +/** + * Connects to phsvc. + * + * \param hWnd The window to display user interface components on. + * \param Mode The type of phsvc instance to connect to. + * \param ConnectOnly TRUE to only try to connect to phsvc, otherwise + * FALSE to try to elevate and start phsvc if the initial connection + * attempt failed. + */ +BOOLEAN PhUiConnectToPhSvcEx( + _In_opt_ HWND hWnd, + _In_ PH_PHSVC_MODE Mode, + _In_ BOOLEAN ConnectOnly + ) +{ + NTSTATUS status; + BOOLEAN started; + UNICODE_STRING portName; + + if (_InterlockedIncrementNoZero(&PhSvcReferenceCount)) + { + if (PhSvcCurrentMode == Mode) + { + started = TRUE; + } + else + { + _InterlockedDecrement(&PhSvcReferenceCount); + started = FALSE; + } + } + else + { + PhAcquireQueuedLockExclusive(&PhSvcStartLock); + + if (PhSvcReferenceCount == 0) + { + started = FALSE; + PhpGetPhSvcPortName(Mode, &portName); + + // Try to connect first, then start the server if we failed. + status = PhSvcConnectToServer(&portName, 0); + + if (NT_SUCCESS(status)) + { + started = TRUE; + PhSvcCurrentMode = Mode; + _InterlockedIncrement(&PhSvcReferenceCount); + } + else if (!ConnectOnly) + { + // Prompt for elevation, and then try to connect to the server. + + if (PhpStartPhSvcProcess(hWnd, Mode)) + started = TRUE; + + if (started) + { + ULONG attempts = 10; + LARGE_INTEGER interval; + + // Try to connect several times because the server may take + // a while to initialize. + do + { + status = PhSvcConnectToServer(&portName, 0); + + if (NT_SUCCESS(status)) + break; + + interval.QuadPart = -50 * PH_TIMEOUT_MS; + NtDelayExecution(FALSE, &interval); + } while (--attempts != 0); + + // Increment the reference count even if we failed. + // We don't want to prompt the user again. + + PhSvcCurrentMode = Mode; + _InterlockedIncrement(&PhSvcReferenceCount); + } + } + } + else + { + if (PhSvcCurrentMode == Mode) + { + started = TRUE; + _InterlockedIncrement(&PhSvcReferenceCount); + } + else + { + started = FALSE; + } + } + + PhReleaseQueuedLockExclusive(&PhSvcStartLock); + } + + return started; +} + +/** + * Disconnects from phsvc. + */ +VOID PhUiDisconnectFromPhSvc( + VOID + ) +{ + PhAcquireQueuedLockExclusive(&PhSvcStartLock); + + if (_InterlockedDecrement(&PhSvcReferenceCount) == 0) + { + PhSvcDisconnectFromServer(); + } + + PhReleaseQueuedLockExclusive(&PhSvcStartLock); +} + +BOOLEAN PhUiLockComputer( + _In_ HWND hWnd + ) +{ + if (LockWorkStation()) + return TRUE; + else + PhShowStatus(hWnd, L"Unable to lock the computer", 0, GetLastError()); + + return FALSE; +} + +BOOLEAN PhUiLogoffComputer( + _In_ HWND hWnd + ) +{ + if (ExitWindowsEx(EWX_LOGOFF, 0)) + return TRUE; + else + PhShowStatus(hWnd, L"Unable to log off the computer", 0, GetLastError()); + + return FALSE; +} + +BOOLEAN PhUiSleepComputer( + _In_ HWND hWnd + ) +{ + NTSTATUS status; + + if (NT_SUCCESS(status = NtInitiatePowerAction( + PowerActionSleep, + PowerSystemSleeping1, + 0, + FALSE + ))) + return TRUE; + else + PhShowStatus(hWnd, L"Unable to sleep the computer", status, 0); + + return FALSE; +} + +BOOLEAN PhUiHibernateComputer( + _In_ HWND hWnd + ) +{ + NTSTATUS status; + + if (NT_SUCCESS(status = NtInitiatePowerAction( + PowerActionHibernate, + PowerSystemSleeping1, + 0, + FALSE + ))) + return TRUE; + else + PhShowStatus(hWnd, L"Unable to hibernate the computer", status, 0); + + return FALSE; +} + +BOOLEAN PhUiRestartComputer( + _In_ HWND hWnd, + _In_ ULONG Flags + ) +{ + if (!PhGetIntegerSetting(L"EnableWarnings") || PhShowConfirmMessage( + hWnd, + L"restart", + L"the computer", + NULL, + FALSE + )) + { + if (ExitWindowsEx(EWX_REBOOT | Flags, 0)) + return TRUE; + else + PhShowStatus(hWnd, L"Unable to restart the computer", 0, GetLastError()); + } + + return FALSE; +} + +BOOLEAN PhUiShutdownComputer( + _In_ HWND hWnd, + _In_ ULONG Flags + ) +{ + if (!PhGetIntegerSetting(L"EnableWarnings") || PhShowConfirmMessage( + hWnd, + L"shut down", + L"the computer", + NULL, + FALSE + )) + { + if (ExitWindowsEx(EWX_POWEROFF | Flags, 0)) + { + return TRUE; + } + else if (ExitWindowsEx(EWX_SHUTDOWN | Flags, 0)) + { + return TRUE; + } + else + { + PhShowStatus(hWnd, L"Unable to shut down the computer", 0, GetLastError()); + } + } + + return FALSE; +} + +BOOLEAN PhUiConnectSession( + _In_ HWND hWnd, + _In_ ULONG SessionId + ) +{ + BOOLEAN success = FALSE; + PPH_STRING selectedChoice = NULL; + PPH_STRING oldSelectedChoice = NULL; + + // Try once with no password. + if (WinStationConnectW(NULL, SessionId, -1, L"", TRUE)) + return TRUE; + + while (PhaChoiceDialog( + hWnd, + L"Connect to session", + L"Password:", + NULL, + 0, + NULL, + PH_CHOICE_DIALOG_PASSWORD, + &selectedChoice, + NULL, + NULL + )) + { + if (oldSelectedChoice) + { + RtlSecureZeroMemory(oldSelectedChoice->Buffer, oldSelectedChoice->Length); + PhDereferenceObject(oldSelectedChoice); + } + + oldSelectedChoice = selectedChoice; + + if (WinStationConnectW(NULL, SessionId, -1, selectedChoice->Buffer, TRUE)) + { + success = TRUE; + break; + } + else + { + if (!PhShowContinueStatus(hWnd, L"Unable to connect to the session", 0, GetLastError())) + break; + } + } + + if (oldSelectedChoice) + { + RtlSecureZeroMemory(oldSelectedChoice->Buffer, oldSelectedChoice->Length); + PhDereferenceObject(oldSelectedChoice); + } + + return success; +} + +BOOLEAN PhUiDisconnectSession( + _In_ HWND hWnd, + _In_ ULONG SessionId + ) +{ + if (WinStationDisconnect(NULL, SessionId, FALSE)) + return TRUE; + else + PhShowStatus(hWnd, L"Unable to disconnect the session", 0, GetLastError()); + + return FALSE; +} + +BOOLEAN PhUiLogoffSession( + _In_ HWND hWnd, + _In_ ULONG SessionId + ) +{ + if (!PhGetIntegerSetting(L"EnableWarnings") || PhShowConfirmMessage( + hWnd, + L"logoff", + L"the user", + NULL, + FALSE + )) + { + if (WinStationReset(NULL, SessionId, FALSE)) + return TRUE; + else + PhShowStatus(hWnd, L"Unable to logoff the session", 0, GetLastError()); + } + + return FALSE; +} + +/** + * Determines if a process is a system process. + * + * \param ProcessId The PID of the process to check. + */ +static BOOLEAN PhpIsDangerousProcess( + _In_ HANDLE ProcessId + ) +{ + NTSTATUS status; + HANDLE processHandle; + PPH_STRING fileName; + PPH_STRING systemDirectory; + ULONG i; + + if (ProcessId == SYSTEM_PROCESS_ID) + return TRUE; + + if (WINDOWS_HAS_IMAGE_FILE_NAME_BY_PROCESS_ID) + { + status = PhGetProcessImageFileNameByProcessId(ProcessId, &fileName); + } + else + { + if (!NT_SUCCESS(status = PhOpenProcess( + &processHandle, + ProcessQueryAccess, + ProcessId + ))) + return FALSE; + + status = PhGetProcessImageFileName(processHandle, &fileName); + NtClose(processHandle); + } + + if (!NT_SUCCESS(status)) + return FALSE; + + PhMoveReference(&fileName, PhGetFileName(fileName)); + PH_AUTO(fileName); + + systemDirectory = PH_AUTO(PhGetSystemDirectory()); + + for (i = 0; i < sizeof(DangerousProcesses) / sizeof(PWSTR); i++) + { + PPH_STRING fullName; + + fullName = PhaConcatStrings(3, systemDirectory->Buffer, L"\\", DangerousProcesses[i]); + + if (PhEqualString(fileName, fullName, TRUE)) + return TRUE; + } + + return FALSE; +} + +/** + * Checks if the user wants to proceed with an operation. + * + * \param hWnd A handle to the parent window. + * \param Verb A verb describing the action. + * \param Message A message containing additional information + * about the action. + * \param WarnOnlyIfDangerous TRUE to skip the confirmation + * dialog if none of the processes are system processes, + * FALSE to always show the confirmation dialog. + * \param Processes An array of pointers to process items. + * \param NumberOfProcesses The number of process items. + * + * \return TRUE if the user wants to proceed with the operation, + * otherwise FALSE. + */ +static BOOLEAN PhpShowContinueMessageProcesses( + _In_ HWND hWnd, + _In_ PWSTR Verb, + _In_opt_ PWSTR Message, + _In_ BOOLEAN WarnOnlyIfDangerous, + _In_ PPH_PROCESS_ITEM *Processes, + _In_ ULONG NumberOfProcesses + ) +{ + PWSTR object; + ULONG i; + BOOLEAN critical = FALSE; + BOOLEAN dangerous = FALSE; + BOOLEAN cont = FALSE; + + if (NumberOfProcesses == 0) + return FALSE; + + for (i = 0; i < NumberOfProcesses; i++) + { + HANDLE processHandle; + ULONG breakOnTermination; + + breakOnTermination = 0; + + if (NT_SUCCESS(PhOpenProcess(&processHandle, PROCESS_QUERY_INFORMATION, Processes[i]->ProcessId))) + { + NtQueryInformationProcess(processHandle, ProcessBreakOnTermination, &breakOnTermination, sizeof(ULONG), NULL); + NtClose(processHandle); + } + + if (breakOnTermination != 0) + { + critical = TRUE; + dangerous = TRUE; + break; + } + + if (PhpIsDangerousProcess(Processes[i]->ProcessId)) + { + dangerous = TRUE; + break; + } + } + + if (WarnOnlyIfDangerous && !dangerous) + return TRUE; + + if (PhGetIntegerSetting(L"EnableWarnings")) + { + if (NumberOfProcesses == 1) + { + object = Processes[0]->ProcessName->Buffer; + } + else if (NumberOfProcesses == 2) + { + object = PhaConcatStrings( + 3, + Processes[0]->ProcessName->Buffer, + L" and ", + Processes[1]->ProcessName->Buffer + )->Buffer; + } + else + { + object = L"the selected processes"; + } + + if (!dangerous) + { + cont = PhShowConfirmMessage( + hWnd, + Verb, + object, + Message, + FALSE + ); + } + else if (!critical) + { + cont = PhShowConfirmMessage( + hWnd, + Verb, + object, + PhaConcatStrings( + 3, + L"You are about to ", + Verb, + L" one or more system processes." + )->Buffer, + TRUE + ); + } + else + { + PPH_STRING message; + + if (PhEqualStringZ(Verb, L"terminate", FALSE)) + { + message = PhaConcatStrings( + 3, + L"You are about to ", + Verb, + L" one or more critical processes. This will shut down the operating system immediately." + ); + } + else + { + message = PhaConcatStrings( + 3, + L"You are about to ", + Verb, + L" one or more critical processes." + ); + } + + cont = PhShowConfirmMessage( + hWnd, + Verb, + object, + message->Buffer, + TRUE + ); + } + } + else + { + cont = TRUE; + } + + return cont; +} + +/** + * Shows an error message to the user and checks + * if the user wants to continue. + * + * \param hWnd A handle to the parent window. + * \param Verb A verb describing the action which + * resulted in an error. + * \param Process The process item which the action + * was performed on. + * \param Status A NT status value representing the + * error. + * \param Win32Result A Win32 error code representing + * the error. + * + * \return TRUE if the user wants to continue, otherwise + * FALSE. The result is typically only useful when + * executing an action on multiple processes. + */ +static BOOLEAN PhpShowErrorProcess( + _In_ HWND hWnd, + _In_ PWSTR Verb, + _In_ PPH_PROCESS_ITEM Process, + _In_ NTSTATUS Status, + _In_opt_ ULONG Win32Result + ) +{ + if (!PH_IS_FAKE_PROCESS_ID(Process->ProcessId)) + { + return PhShowContinueStatus( + hWnd, + PhaFormatString( + L"Unable to %s %s (PID %u)", + Verb, + Process->ProcessName->Buffer, + HandleToUlong(Process->ProcessId) + )->Buffer, + Status, + Win32Result + ); + } + else + { + return PhShowContinueStatus( + hWnd, + PhaFormatString( + L"Unable to %s %s", + Verb, + Process->ProcessName->Buffer + )->Buffer, + Status, + Win32Result + ); + } +} + +BOOLEAN PhUiTerminateProcesses( + _In_ HWND hWnd, + _In_ PPH_PROCESS_ITEM *Processes, + _In_ ULONG NumberOfProcesses + ) +{ + BOOLEAN success = TRUE; + BOOLEAN cancelled = FALSE; + ULONG i; + + if (!PhpShowContinueMessageProcesses( + hWnd, + L"terminate", + L"Terminating a process will cause unsaved data to be lost.", + FALSE, + Processes, + NumberOfProcesses + )) + return FALSE; + + for (i = 0; i < NumberOfProcesses; i++) + { + NTSTATUS status; + HANDLE processHandle; + + if (NT_SUCCESS(status = PhOpenProcess( + &processHandle, + PROCESS_TERMINATE, + Processes[i]->ProcessId + ))) + { + // An exit status of 1 is used here for compatibility reasons: + // 1. Both Task Manager and Process Explorer use 1. + // 2. winlogon tries to restart explorer.exe if the exit status is not 1. + + status = PhTerminateProcess(processHandle, 1); + NtClose(processHandle); + } + + if (!NT_SUCCESS(status)) + { + BOOLEAN connected; + + success = FALSE; + + if (!cancelled && PhpShowErrorAndConnectToPhSvc( + hWnd, + PhaConcatStrings2(L"Unable to terminate ", Processes[i]->ProcessName->Buffer)->Buffer, + status, + &connected + )) + { + if (connected) + { + if (NT_SUCCESS(status = PhSvcCallControlProcess(Processes[i]->ProcessId, PhSvcControlProcessTerminate, 0))) + success = TRUE; + else + PhpShowErrorProcess(hWnd, L"terminate", Processes[i], status, 0); + + PhUiDisconnectFromPhSvc(); + } + else + { + cancelled = TRUE; + } + } + else + { + if (!PhpShowErrorProcess(hWnd, L"terminate", Processes[i], status, 0)) + break; + } + } + } + + return success; +} + +BOOLEAN PhpUiTerminateTreeProcess( + _In_ HWND hWnd, + _In_ PPH_PROCESS_ITEM Process, + _In_ PVOID Processes, + _Inout_ PBOOLEAN Success + ) +{ + NTSTATUS status; + PSYSTEM_PROCESS_INFORMATION process; + HANDLE processHandle; + PPH_PROCESS_ITEM processItem; + + // Note: + // FALSE should be written to Success if any part of the operation failed. + // The return value of this function indicates whether to continue with + // the operation (FALSE if user cancelled). + + // Terminate the process. + + if (NT_SUCCESS(status = PhOpenProcess( + &processHandle, + PROCESS_TERMINATE, + Process->ProcessId + ))) + { + status = PhTerminateProcess(processHandle, 1); + NtClose(processHandle); + } + + if (!NT_SUCCESS(status)) + { + *Success = FALSE; + + if (!PhpShowErrorProcess(hWnd, L"terminate", Process, status, 0)) + return FALSE; + } + + // Terminate the process' children. + + process = PH_FIRST_PROCESS(Processes); + + do + { + if (process->UniqueProcessId != Process->ProcessId && + process->InheritedFromUniqueProcessId == Process->ProcessId) + { + if (processItem = PhReferenceProcessItem(process->UniqueProcessId)) + { + // Check the creation time to make sure it is a descendant. + if (processItem->CreateTime.QuadPart >= Process->CreateTime.QuadPart) + { + if (!PhpUiTerminateTreeProcess(hWnd, processItem, Processes, Success)) + { + PhDereferenceObject(processItem); + return FALSE; + } + } + + PhDereferenceObject(processItem); + } + } + } while (process = PH_NEXT_PROCESS(process)); + + return TRUE; +} + +BOOLEAN PhUiTerminateTreeProcess( + _In_ HWND hWnd, + _In_ PPH_PROCESS_ITEM Process + ) +{ + NTSTATUS status; + BOOLEAN success = TRUE; + BOOLEAN cont = FALSE; + PVOID processes; + + if (PhGetIntegerSetting(L"EnableWarnings")) + { + cont = PhShowConfirmMessage( + hWnd, + L"terminate", + PhaConcatStrings2(Process->ProcessName->Buffer, L" and its descendants")->Buffer, + L"Terminating a process tree will cause the process and its descendants to be terminated.", + FALSE + ); + } + else + { + cont = TRUE; + } + + if (!cont) + return FALSE; + + if (!NT_SUCCESS(status = PhEnumProcesses(&processes))) + { + PhShowStatus(hWnd, L"Unable to enumerate processes", status, 0); + return FALSE; + } + + PhpUiTerminateTreeProcess(hWnd, Process, processes, &success); + PhFree(processes); + + return success; +} + +BOOLEAN PhUiSuspendProcesses( + _In_ HWND hWnd, + _In_ PPH_PROCESS_ITEM *Processes, + _In_ ULONG NumberOfProcesses + ) +{ + BOOLEAN success = TRUE; + BOOLEAN cancelled = FALSE; + ULONG i; + + if (!PhpShowContinueMessageProcesses( + hWnd, + L"suspend", + NULL, + TRUE, + Processes, + NumberOfProcesses + )) + return FALSE; + + for (i = 0; i < NumberOfProcesses; i++) + { + NTSTATUS status; + HANDLE processHandle; + + if (NT_SUCCESS(status = PhOpenProcess( + &processHandle, + PROCESS_SUSPEND_RESUME, + Processes[i]->ProcessId + ))) + { + status = NtSuspendProcess(processHandle); + NtClose(processHandle); + } + + if (!NT_SUCCESS(status)) + { + BOOLEAN connected; + + success = FALSE; + + if (!cancelled && PhpShowErrorAndConnectToPhSvc( + hWnd, + PhaConcatStrings2(L"Unable to suspend ", Processes[i]->ProcessName->Buffer)->Buffer, + status, + &connected + )) + { + if (connected) + { + if (NT_SUCCESS(status = PhSvcCallControlProcess(Processes[i]->ProcessId, PhSvcControlProcessSuspend, 0))) + success = TRUE; + else + PhpShowErrorProcess(hWnd, L"suspend", Processes[i], status, 0); + + PhUiDisconnectFromPhSvc(); + } + else + { + cancelled = TRUE; + } + } + else + { + if (!PhpShowErrorProcess(hWnd, L"suspend", Processes[i], status, 0)) + break; + } + } + } + + return success; +} + +BOOLEAN PhUiResumeProcesses( + _In_ HWND hWnd, + _In_ PPH_PROCESS_ITEM *Processes, + _In_ ULONG NumberOfProcesses + ) +{ + BOOLEAN success = TRUE; + BOOLEAN cancelled = FALSE; + ULONG i; + + if (!PhpShowContinueMessageProcesses( + hWnd, + L"resume", + NULL, + TRUE, + Processes, + NumberOfProcesses + )) + return FALSE; + + for (i = 0; i < NumberOfProcesses; i++) + { + NTSTATUS status; + HANDLE processHandle; + + if (NT_SUCCESS(status = PhOpenProcess( + &processHandle, + PROCESS_SUSPEND_RESUME, + Processes[i]->ProcessId + ))) + { + status = NtResumeProcess(processHandle); + NtClose(processHandle); + } + + if (!NT_SUCCESS(status)) + { + BOOLEAN connected; + + success = FALSE; + + if (!cancelled && PhpShowErrorAndConnectToPhSvc( + hWnd, + PhaConcatStrings2(L"Unable to resume ", Processes[i]->ProcessName->Buffer)->Buffer, + status, + &connected + )) + { + if (connected) + { + if (NT_SUCCESS(status = PhSvcCallControlProcess(Processes[i]->ProcessId, PhSvcControlProcessResume, 0))) + success = TRUE; + else + PhpShowErrorProcess(hWnd, L"resume", Processes[i], status, 0); + + PhUiDisconnectFromPhSvc(); + } + else + { + cancelled = TRUE; + } + } + else + { + if (!PhpShowErrorProcess(hWnd, L"resume", Processes[i], status, 0)) + break; + } + } + } + + return success; +} + +BOOLEAN PhUiRestartProcess( + _In_ HWND hWnd, + _In_ PPH_PROCESS_ITEM Process + ) +{ + NTSTATUS status; + BOOLEAN cont = FALSE; + HANDLE processHandle = NULL; + PPH_STRING commandLine; + PPH_STRING currentDirectory; + + if (PhGetIntegerSetting(L"EnableWarnings")) + { + cont = PhShowConfirmMessage( + hWnd, + L"restart", + Process->ProcessName->Buffer, + L"The process will be restarted with the same command line and " + L"working directory, but if it is running under a different user it " + L"will be restarted under the current user.", + FALSE + ); + } + else + { + cont = TRUE; + } + + if (!cont) + return FALSE; + + // Open the process and get the command line and current directory. + + if (!NT_SUCCESS(status = PhOpenProcess( + &processHandle, + ProcessQueryAccess | PROCESS_VM_READ, + Process->ProcessId + ))) + goto ErrorExit; + + if (!NT_SUCCESS(status = PhGetProcessCommandLine( + processHandle, + &commandLine + ))) + goto ErrorExit; + + PH_AUTO(commandLine); + + if (!NT_SUCCESS(status = PhGetProcessPebString( + processHandle, + PhpoCurrentDirectory, + ¤tDirectory + ))) + goto ErrorExit; + + PH_AUTO(currentDirectory); + + NtClose(processHandle); + processHandle = NULL; + + // Open the process and terminate it. + + if (!NT_SUCCESS(status = PhOpenProcess( + &processHandle, + PROCESS_TERMINATE, + Process->ProcessId + ))) + goto ErrorExit; + + if (!NT_SUCCESS(status = PhTerminateProcess( + processHandle, + 1 + ))) + goto ErrorExit; + + NtClose(processHandle); + processHandle = NULL; + + // Start the process. + + status = PhCreateProcessWin32( + PhGetString(Process->FileName), // we didn't wait for S1 processing + commandLine->Buffer, + NULL, + currentDirectory->Buffer, + 0, + NULL, + NULL, + NULL + ); + +ErrorExit: + if (processHandle) + NtClose(processHandle); + + if (!NT_SUCCESS(status)) + { + PhpShowErrorProcess(hWnd, L"restart", Process, status, 0); + return FALSE; + } + + return TRUE; +} + +// Contributed by evilpie (#2981421) +BOOLEAN PhUiDebugProcess( + _In_ HWND hWnd, + _In_ PPH_PROCESS_ITEM Process + ) +{ + NTSTATUS status; + BOOLEAN cont = FALSE; + PH_STRING_BUILDER commandLineBuilder; + + if (PhGetIntegerSetting(L"EnableWarnings")) + { + cont = PhShowConfirmMessage( + hWnd, + L"debug", + Process->ProcessName->Buffer, + L"Debugging a process may result in loss of data.", + FALSE + ); + } + else + { + cont = TRUE; + } + + if (!cont) + return FALSE; + + if (PhBeginInitOnce(&DebuggerCommandInitOnce)) + { + static PH_STRINGREF aeDebugKeyName = PH_STRINGREF_INIT(L"Software\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug"); + + HANDLE keyHandle; + PPH_STRING debugger; + PH_STRINGREF commandPart; + PH_STRINGREF dummy; + + if (NT_SUCCESS(PhOpenKey( + &keyHandle, + KEY_READ, + PH_KEY_LOCAL_MACHINE, + &aeDebugKeyName, + 0 + ))) + { + if (debugger = PH_AUTO(PhQueryRegistryString(keyHandle, L"Debugger"))) + { + if (PhSplitStringRefAtChar(&debugger->sr, '"', &dummy, &commandPart) && + PhSplitStringRefAtChar(&commandPart, '"', &commandPart, &dummy)) + { + DebuggerCommand = PhCreateString2(&commandPart); + } + } + + NtClose(keyHandle); + } + + PhEndInitOnce(&DebuggerCommandInitOnce); + } + + if (!DebuggerCommand) + { + PhShowError(hWnd, L"Unable to locate the debugger."); + return FALSE; + } + + PhInitializeStringBuilder(&commandLineBuilder, DebuggerCommand->Length + 30); + + PhAppendCharStringBuilder(&commandLineBuilder, '"'); + PhAppendStringBuilder(&commandLineBuilder, &DebuggerCommand->sr); + PhAppendCharStringBuilder(&commandLineBuilder, '"'); + PhAppendFormatStringBuilder(&commandLineBuilder, L" -p %u", HandleToUlong(Process->ProcessId)); + + status = PhCreateProcessWin32( + NULL, + commandLineBuilder.String->Buffer, + NULL, + NULL, + 0, + NULL, + NULL, + NULL + ); + + PhDeleteStringBuilder(&commandLineBuilder); + + if (!NT_SUCCESS(status)) + { + PhpShowErrorProcess(hWnd, L"debug", Process, status, 0); + return FALSE; + } + + return TRUE; +} + +BOOLEAN PhUiReduceWorkingSetProcesses( + _In_ HWND hWnd, + _In_ PPH_PROCESS_ITEM *Processes, + _In_ ULONG NumberOfProcesses + ) +{ + BOOLEAN success = TRUE; + ULONG i; + + for (i = 0; i < NumberOfProcesses; i++) + { + NTSTATUS status; + HANDLE processHandle; + + if (NT_SUCCESS(status = PhOpenProcess( + &processHandle, + PROCESS_SET_QUOTA, + Processes[i]->ProcessId + ))) + { + QUOTA_LIMITS quotaLimits; + + memset("aLimits, 0, sizeof(QUOTA_LIMITS)); + quotaLimits.MinimumWorkingSetSize = -1; + quotaLimits.MaximumWorkingSetSize = -1; + + status = NtSetInformationProcess( + processHandle, + ProcessQuotaLimits, + "aLimits, + sizeof(QUOTA_LIMITS) + ); + + NtClose(processHandle); + } + + if (!NT_SUCCESS(status)) + { + success = FALSE; + + if (!PhpShowErrorProcess(hWnd, L"reduce the working set of", Processes[i], status, 0)) + break; + } + } + + return success; +} + +BOOLEAN PhUiSetVirtualizationProcess( + _In_ HWND hWnd, + _In_ PPH_PROCESS_ITEM Process, + _In_ BOOLEAN Enable + ) +{ + NTSTATUS status; + BOOLEAN cont = FALSE; + HANDLE processHandle; + HANDLE tokenHandle; + + if (PhGetIntegerSetting(L"EnableWarnings")) + { + cont = PhShowConfirmMessage( + hWnd, + L"set", + L"virtualization for the process", + L"Enabling or disabling virtualization for a process may " + L"alter its functionality and produce undesirable effects.", + FALSE + ); + } + else + { + cont = TRUE; + } + + if (!cont) + return FALSE; + + if (NT_SUCCESS(status = PhOpenProcess( + &processHandle, + ProcessQueryAccess, + Process->ProcessId + ))) + { + if (NT_SUCCESS(status = PhOpenProcessToken( + processHandle, + TOKEN_WRITE, + &tokenHandle + ))) + { + status = PhSetTokenIsVirtualizationEnabled(tokenHandle, Enable); + NtClose(tokenHandle); + } + + NtClose(processHandle); + } + + if (!NT_SUCCESS(status)) + { + PhpShowErrorProcess(hWnd, L"set virtualization for", Process, status, 0); + return FALSE; + } + + return TRUE; +} + +BOOLEAN PhUiDetachFromDebuggerProcess( + _In_ HWND hWnd, + _In_ PPH_PROCESS_ITEM Process + ) +{ + NTSTATUS status; + HANDLE processHandle; + HANDLE debugObjectHandle; + + if (NT_SUCCESS(status = PhOpenProcess( + &processHandle, + PROCESS_QUERY_INFORMATION | PROCESS_SUSPEND_RESUME, + Process->ProcessId + ))) + { + if (NT_SUCCESS(status = PhGetProcessDebugObject( + processHandle, + &debugObjectHandle + ))) + { + ULONG flags; + + // Disable kill-on-close. + flags = 0; + NtSetInformationDebugObject( + debugObjectHandle, + DebugObjectFlags, + &flags, + sizeof(ULONG), + NULL + ); + + status = NtRemoveProcessDebug(processHandle, debugObjectHandle); + + NtClose(debugObjectHandle); + } + + NtClose(processHandle); + } + + if (status == STATUS_PORT_NOT_SET) + { + PhShowInformation(hWnd, L"The process is not being debugged."); + return FALSE; + } + + if (!NT_SUCCESS(status)) + { + PhpShowErrorProcess(hWnd, L"detach debugger from", Process, status, 0); + return FALSE; + } + + return TRUE; +} + +BOOLEAN PhUiInjectDllProcess( + _In_ HWND hWnd, + _In_ PPH_PROCESS_ITEM Process + ) +{ + static PH_FILETYPE_FILTER filters[] = + { + { L"DLL files (*.dll)", L"*.dll" }, + { L"All files (*.*)", L"*.*" } + }; + + NTSTATUS status; + PVOID fileDialog; + PPH_STRING fileName; + HANDLE processHandle; + + fileDialog = PhCreateOpenFileDialog(); + PhSetFileDialogFilter(fileDialog, filters, sizeof(filters) / sizeof(PH_FILETYPE_FILTER)); + + if (!PhShowFileDialog(hWnd, fileDialog)) + { + PhFreeFileDialog(fileDialog); + return FALSE; + } + + fileName = PH_AUTO(PhGetFileDialogFileName(fileDialog)); + PhFreeFileDialog(fileDialog); + + if (NT_SUCCESS(status = PhOpenProcess( + &processHandle, + ProcessQueryAccess | PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | + PROCESS_VM_READ | PROCESS_VM_WRITE, + Process->ProcessId + ))) + { + LARGE_INTEGER timeout; + + timeout.QuadPart = -5 * PH_TIMEOUT_SEC; + status = PhInjectDllProcess( + processHandle, + fileName->Buffer, + &timeout + ); + + NtClose(processHandle); + } + + if (!NT_SUCCESS(status)) + { + PhpShowErrorProcess(hWnd, L"inject the DLL into", Process, status, 0); + return FALSE; + } + + return TRUE; +} + +BOOLEAN PhUiSetIoPriorityProcesses( + _In_ HWND hWnd, + _In_ PPH_PROCESS_ITEM *Processes, + _In_ ULONG NumberOfProcesses, + _In_ IO_PRIORITY_HINT IoPriority + ) +{ + BOOLEAN success = TRUE; + BOOLEAN cancelled = FALSE; + ULONG i; + + for (i = 0; i < NumberOfProcesses; i++) + { + NTSTATUS status; + HANDLE processHandle; + + if (NT_SUCCESS(status = PhOpenProcess( + &processHandle, + PROCESS_SET_INFORMATION, + Processes[i]->ProcessId + ))) + { + if (Processes[i]->ProcessId != SYSTEM_PROCESS_ID) + { + status = PhSetProcessIoPriority(processHandle, IoPriority); + } + else + { + // See comment in PhUiSetPriorityProcesses. + status = STATUS_UNSUCCESSFUL; + } + + NtClose(processHandle); + } + + if (!NT_SUCCESS(status)) + { + BOOLEAN connected; + + success = FALSE; + + // The operation may have failed due to the lack of SeIncreaseBasePriorityPrivilege. + if (!cancelled && PhpShowErrorAndConnectToPhSvc( + hWnd, + PhaConcatStrings2(L"Unable to set the I/O priority of ", Processes[i]->ProcessName->Buffer)->Buffer, + status, + &connected + )) + { + if (connected) + { + if (NT_SUCCESS(status = PhSvcCallControlProcess(Processes[i]->ProcessId, PhSvcControlProcessIoPriority, IoPriority))) + success = TRUE; + else + PhpShowErrorProcess(hWnd, L"set the I/O priority of", Processes[i], status, 0); + + PhUiDisconnectFromPhSvc(); + } + else + { + cancelled = TRUE; + } + } + else + { + if (!PhpShowErrorProcess(hWnd, L"set the I/O priority of", Processes[i], status, 0)) + break; + } + } + } + + return success; +} + +BOOLEAN PhUiSetPagePriorityProcess( + _In_ HWND hWnd, + _In_ PPH_PROCESS_ITEM Process, + _In_ ULONG PagePriority + ) +{ + NTSTATUS status; + HANDLE processHandle; + + if (NT_SUCCESS(status = PhOpenProcess( + &processHandle, + PROCESS_SET_INFORMATION, + Process->ProcessId + ))) + { + if (Process->ProcessId != SYSTEM_PROCESS_ID) + { + status = NtSetInformationProcess( + processHandle, + ProcessPagePriority, + &PagePriority, + sizeof(ULONG) + ); + } + else + { + // See comment in PhUiSetPriorityProcesses. + status = STATUS_UNSUCCESSFUL; + } + + NtClose(processHandle); + } + + if (!NT_SUCCESS(status)) + { + PhpShowErrorProcess(hWnd, L"set the page priority of", Process, status, 0); + return FALSE; + } + + return TRUE; +} + +BOOLEAN PhUiSetPriorityProcesses( + _In_ HWND hWnd, + _In_ PPH_PROCESS_ITEM *Processes, + _In_ ULONG NumberOfProcesses, + _In_ ULONG PriorityClass + ) +{ + BOOLEAN success = TRUE; + BOOLEAN cancelled = FALSE; + ULONG i; + + for (i = 0; i < NumberOfProcesses; i++) + { + NTSTATUS status; + HANDLE processHandle; + PROCESS_PRIORITY_CLASS priorityClass; + + if (NT_SUCCESS(status = PhOpenProcess( + &processHandle, + PROCESS_SET_INFORMATION, + Processes[i]->ProcessId + ))) + { + if (Processes[i]->ProcessId != SYSTEM_PROCESS_ID) + { + priorityClass.Foreground = FALSE; + priorityClass.PriorityClass = (UCHAR)PriorityClass; + status = NtSetInformationProcess(processHandle, ProcessPriorityClass, &priorityClass, sizeof(PROCESS_PRIORITY_CLASS)); + } + else + { + // Changing the priority of System can lead to a BSOD on some versions of Windows, + // so disallow this. + status = STATUS_UNSUCCESSFUL; + } + + NtClose(processHandle); + } + + if (!NT_SUCCESS(status)) + { + BOOLEAN connected; + + success = FALSE; + + // The operation may have failed due to the lack of SeIncreaseBasePriorityPrivilege. + if (!cancelled && PhpShowErrorAndConnectToPhSvc( + hWnd, + PhaConcatStrings2(L"Unable to set the priority of ", Processes[i]->ProcessName->Buffer)->Buffer, + status, + &connected + )) + { + if (connected) + { + if (NT_SUCCESS(status = PhSvcCallControlProcess(Processes[i]->ProcessId, PhSvcControlProcessPriority, PriorityClass))) + success = TRUE; + else + PhpShowErrorProcess(hWnd, L"set the priority of", Processes[i], status, 0); + + PhUiDisconnectFromPhSvc(); + } + else + { + cancelled = TRUE; + } + } + else + { + if (!PhpShowErrorProcess(hWnd, L"set the priority of", Processes[i], status, 0)) + break; + } + } + } + + return success; +} + +static VOID PhpShowErrorService( + _In_ HWND hWnd, + _In_ PWSTR Verb, + _In_ PPH_SERVICE_ITEM Service, + _In_ NTSTATUS Status, + _In_opt_ ULONG Win32Result + ) +{ + PhShowStatus( + hWnd, + PhaFormatString( + L"Unable to %s %s", + Verb, + Service->Name->Buffer + )->Buffer, + Status, + Win32Result + ); +} + +BOOLEAN PhUiStartService( + _In_ HWND hWnd, + _In_ PPH_SERVICE_ITEM Service + ) +{ + SC_HANDLE serviceHandle; + BOOLEAN success = FALSE; + + serviceHandle = PhOpenService(Service->Name->Buffer, SERVICE_START); + + if (serviceHandle) + { + if (StartService(serviceHandle, 0, NULL)) + success = TRUE; + + CloseServiceHandle(serviceHandle); + } + + if (!success) + { + NTSTATUS status; + BOOLEAN connected; + + status = PhGetLastWin32ErrorAsNtStatus(); + + if (PhpShowErrorAndConnectToPhSvc( + hWnd, + PhaConcatStrings2(L"Unable to start ", Service->Name->Buffer)->Buffer, + status, + &connected + )) + { + if (connected) + { + if (NT_SUCCESS(status = PhSvcCallControlService(Service->Name->Buffer, PhSvcControlServiceStart))) + success = TRUE; + else + PhpShowErrorService(hWnd, L"start", Service, status, 0); + + PhUiDisconnectFromPhSvc(); + } + } + else + { + PhpShowErrorService(hWnd, L"start", Service, status, 0); + } + } + + return success; +} + +BOOLEAN PhUiContinueService( + _In_ HWND hWnd, + _In_ PPH_SERVICE_ITEM Service + ) +{ + SC_HANDLE serviceHandle; + BOOLEAN success = FALSE; + + serviceHandle = PhOpenService(Service->Name->Buffer, SERVICE_PAUSE_CONTINUE); + + if (serviceHandle) + { + SERVICE_STATUS serviceStatus; + + if (ControlService(serviceHandle, SERVICE_CONTROL_CONTINUE, &serviceStatus)) + success = TRUE; + + CloseServiceHandle(serviceHandle); + } + + if (!success) + { + NTSTATUS status; + BOOLEAN connected; + + status = PhGetLastWin32ErrorAsNtStatus(); + + if (PhpShowErrorAndConnectToPhSvc( + hWnd, + PhaConcatStrings2(L"Unable to continue ", Service->Name->Buffer)->Buffer, + status, + &connected + )) + { + if (connected) + { + if (NT_SUCCESS(status = PhSvcCallControlService(Service->Name->Buffer, PhSvcControlServiceContinue))) + success = TRUE; + else + PhpShowErrorService(hWnd, L"continue", Service, status, 0); + + PhUiDisconnectFromPhSvc(); + } + } + else + { + PhpShowErrorService(hWnd, L"continue", Service, status, 0); + } + } + + return success; +} + +BOOLEAN PhUiPauseService( + _In_ HWND hWnd, + _In_ PPH_SERVICE_ITEM Service + ) +{ + SC_HANDLE serviceHandle; + BOOLEAN success = FALSE; + + serviceHandle = PhOpenService(Service->Name->Buffer, SERVICE_PAUSE_CONTINUE); + + if (serviceHandle) + { + SERVICE_STATUS serviceStatus; + + if (ControlService(serviceHandle, SERVICE_CONTROL_PAUSE, &serviceStatus)) + success = TRUE; + + CloseServiceHandle(serviceHandle); + } + + if (!success) + { + NTSTATUS status; + BOOLEAN connected; + + status = PhGetLastWin32ErrorAsNtStatus(); + + if (PhpShowErrorAndConnectToPhSvc( + hWnd, + PhaConcatStrings2(L"Unable to pause ", Service->Name->Buffer)->Buffer, + status, + &connected + )) + { + if (connected) + { + if (NT_SUCCESS(status = PhSvcCallControlService(Service->Name->Buffer, PhSvcControlServicePause))) + success = TRUE; + else + PhpShowErrorService(hWnd, L"pause", Service, status, 0); + + PhUiDisconnectFromPhSvc(); + } + } + else + { + PhpShowErrorService(hWnd, L"pause", Service, status, 0); + } + } + + return success; +} + +BOOLEAN PhUiStopService( + _In_ HWND hWnd, + _In_ PPH_SERVICE_ITEM Service + ) +{ + SC_HANDLE serviceHandle; + BOOLEAN success = FALSE; + + serviceHandle = PhOpenService(Service->Name->Buffer, SERVICE_STOP); + + if (serviceHandle) + { + SERVICE_STATUS serviceStatus; + + if (ControlService(serviceHandle, SERVICE_CONTROL_STOP, &serviceStatus)) + success = TRUE; + + CloseServiceHandle(serviceHandle); + } + + if (!success) + { + NTSTATUS status; + BOOLEAN connected; + + status = PhGetLastWin32ErrorAsNtStatus(); + + if (PhpShowErrorAndConnectToPhSvc( + hWnd, + PhaConcatStrings2(L"Unable to stop ", Service->Name->Buffer)->Buffer, + status, + &connected + )) + { + if (connected) + { + if (NT_SUCCESS(status = PhSvcCallControlService(Service->Name->Buffer, PhSvcControlServiceStop))) + success = TRUE; + else + PhpShowErrorService(hWnd, L"stop", Service, status, 0); + + PhUiDisconnectFromPhSvc(); + } + } + else + { + PhpShowErrorService(hWnd, L"stop", Service, status, 0); + } + } + + return success; +} + +BOOLEAN PhUiDeleteService( + _In_ HWND hWnd, + _In_ PPH_SERVICE_ITEM Service + ) +{ + SC_HANDLE serviceHandle; + BOOLEAN success = FALSE; + + // Warnings cannot be disabled for service deletion. + if (!PhShowConfirmMessage( + hWnd, + L"delete", + Service->Name->Buffer, + L"Deleting a service can prevent the system from starting " + L"or functioning properly.", + TRUE + )) + return FALSE; + + serviceHandle = PhOpenService(Service->Name->Buffer, DELETE); + + if (serviceHandle) + { + if (DeleteService(serviceHandle)) + success = TRUE; + + CloseServiceHandle(serviceHandle); + } + + if (!success) + { + NTSTATUS status; + BOOLEAN connected; + + status = PhGetLastWin32ErrorAsNtStatus(); + + if (PhpShowErrorAndConnectToPhSvc( + hWnd, + PhaConcatStrings2(L"Unable to delete ", Service->Name->Buffer)->Buffer, + status, + &connected + )) + { + if (connected) + { + if (NT_SUCCESS(status = PhSvcCallControlService(Service->Name->Buffer, PhSvcControlServiceDelete))) + success = TRUE; + else + PhpShowErrorService(hWnd, L"delete", Service, status, 0); + + PhUiDisconnectFromPhSvc(); + } + } + else + { + PhpShowErrorService(hWnd, L"delete", Service, status, 0); + } + } + + return success; +} + +BOOLEAN PhUiCloseConnections( + _In_ HWND hWnd, + _In_ PPH_NETWORK_ITEM *Connections, + _In_ ULONG NumberOfConnections + ) +{ + + BOOLEAN success = TRUE; + BOOLEAN cancelled = FALSE; + ULONG result; + ULONG i; + _SetTcpEntry SetTcpEntry_I; + MIB_TCPROW tcpRow; + + SetTcpEntry_I = PhGetModuleProcAddress(L"iphlpapi.dll", "SetTcpEntry"); + + if (!SetTcpEntry_I) + { + PhShowError( + hWnd, + L"This feature is not supported by your operating system." + ); + return FALSE; + } + + for (i = 0; i < NumberOfConnections; i++) + { + if ( + Connections[i]->ProtocolType != PH_TCP4_NETWORK_PROTOCOL || + Connections[i]->State != MIB_TCP_STATE_ESTAB + ) + continue; + + tcpRow.dwState = MIB_TCP_STATE_DELETE_TCB; + tcpRow.dwLocalAddr = Connections[i]->LocalEndpoint.Address.Ipv4; + tcpRow.dwLocalPort = _byteswap_ushort((USHORT)Connections[i]->LocalEndpoint.Port); + tcpRow.dwRemoteAddr = Connections[i]->RemoteEndpoint.Address.Ipv4; + tcpRow.dwRemotePort = _byteswap_ushort((USHORT)Connections[i]->RemoteEndpoint.Port); + + if ((result = SetTcpEntry_I(&tcpRow)) != 0) + { + NTSTATUS status; + BOOLEAN connected; + + success = FALSE; + + // SetTcpEntry returns ERROR_MR_MID_NOT_FOUND for access denied errors for some reason. + if (result == ERROR_MR_MID_NOT_FOUND) + result = ERROR_ACCESS_DENIED; + + if (!cancelled && PhpShowErrorAndConnectToPhSvc( + hWnd, + L"Unable to close the TCP connection", + NTSTATUS_FROM_WIN32(result), + &connected + )) + { + if (connected) + { + if (NT_SUCCESS(status = PhSvcCallSetTcpEntry(&tcpRow))) + success = TRUE; + else + PhShowStatus(hWnd, L"Unable to close the TCP connection", status, 0); + + PhUiDisconnectFromPhSvc(); + } + else + { + cancelled = TRUE; + } + } + else + { + if (PhShowMessage( + hWnd, + MB_ICONERROR | MB_OKCANCEL, + L"Unable to close the TCP connection (from %s:%u). " + L"Make sure Process Hacker is running with administrative privileges.", + Connections[i]->LocalAddressString, + Connections[i]->LocalEndpoint.Port + ) != IDOK) + break; + } + } + } + + return success; +} + +static BOOLEAN PhpShowContinueMessageThreads( + _In_ HWND hWnd, + _In_ PWSTR Verb, + _In_ PWSTR Message, + _In_ BOOLEAN Warning, + _In_ PPH_THREAD_ITEM *Threads, + _In_ ULONG NumberOfThreads + ) +{ + PWSTR object; + BOOLEAN cont = FALSE; + + if (NumberOfThreads == 0) + return FALSE; + + if (PhGetIntegerSetting(L"EnableWarnings")) + { + if (NumberOfThreads == 1) + { + object = L"the selected thread"; + } + else + { + object = L"the selected threads"; + } + + cont = PhShowConfirmMessage( + hWnd, + Verb, + object, + Message, + Warning + ); + } + else + { + cont = TRUE; + } + + return cont; +} + +static BOOLEAN PhpShowErrorThread( + _In_ HWND hWnd, + _In_ PWSTR Verb, + _In_ PPH_THREAD_ITEM Thread, + _In_ NTSTATUS Status, + _In_opt_ ULONG Win32Result + ) +{ + return PhShowContinueStatus( + hWnd, + PhaFormatString( + L"Unable to %s thread %u", + Verb, + HandleToUlong(Thread->ThreadId) + )->Buffer, + Status, + Win32Result + ); +} + +BOOLEAN PhUiTerminateThreads( + _In_ HWND hWnd, + _In_ PPH_THREAD_ITEM *Threads, + _In_ ULONG NumberOfThreads + ) +{ + BOOLEAN success = TRUE; + BOOLEAN cancelled = FALSE; + ULONG i; + + if (!PhpShowContinueMessageThreads( + hWnd, + L"terminate", + L"Terminating a thread may cause the process to stop working.", + FALSE, + Threads, + NumberOfThreads + )) + return FALSE; + + for (i = 0; i < NumberOfThreads; i++) + { + NTSTATUS status; + HANDLE threadHandle; + + if (NT_SUCCESS(status = PhOpenThread( + &threadHandle, + THREAD_TERMINATE, + Threads[i]->ThreadId + ))) + { + status = NtTerminateThread(threadHandle, STATUS_SUCCESS); + NtClose(threadHandle); + } + + if (!NT_SUCCESS(status)) + { + BOOLEAN connected; + + success = FALSE; + + if (!cancelled && PhpShowErrorAndConnectToPhSvc( + hWnd, + PhaFormatString(L"Unable to terminate thread %u", HandleToUlong(Threads[i]->ThreadId))->Buffer, + status, + &connected + )) + { + if (connected) + { + if (NT_SUCCESS(status = PhSvcCallControlThread(Threads[i]->ThreadId, PhSvcControlThreadTerminate, 0))) + success = TRUE; + else + PhpShowErrorThread(hWnd, L"terminate", Threads[i], status, 0); + + PhUiDisconnectFromPhSvc(); + } + else + { + cancelled = TRUE; + } + } + else + { + if (!PhpShowErrorThread(hWnd, L"terminate", Threads[i], status, 0)) + break; + } + } + } + + return success; +} + +BOOLEAN PhUiSuspendThreads( + _In_ HWND hWnd, + _In_ PPH_THREAD_ITEM *Threads, + _In_ ULONG NumberOfThreads + ) +{ + BOOLEAN success = TRUE; + BOOLEAN cancelled = FALSE; + ULONG i; + + for (i = 0; i < NumberOfThreads; i++) + { + NTSTATUS status; + HANDLE threadHandle; + + if (NT_SUCCESS(status = PhOpenThread( + &threadHandle, + THREAD_SUSPEND_RESUME, + Threads[i]->ThreadId + ))) + { + status = NtSuspendThread(threadHandle, NULL); + NtClose(threadHandle); + } + + if (!NT_SUCCESS(status)) + { + BOOLEAN connected; + + success = FALSE; + + if (!cancelled && PhpShowErrorAndConnectToPhSvc( + hWnd, + PhaFormatString(L"Unable to suspend thread %u", HandleToUlong(Threads[i]->ThreadId))->Buffer, + status, + &connected + )) + { + if (connected) + { + if (NT_SUCCESS(status = PhSvcCallControlThread(Threads[i]->ThreadId, PhSvcControlThreadSuspend, 0))) + success = TRUE; + else + PhpShowErrorThread(hWnd, L"suspend", Threads[i], status, 0); + + PhUiDisconnectFromPhSvc(); + } + else + { + cancelled = TRUE; + } + } + else + { + if (!PhpShowErrorThread(hWnd, L"suspend", Threads[i], status, 0)) + break; + } + } + } + + return success; +} + +BOOLEAN PhUiResumeThreads( + _In_ HWND hWnd, + _In_ PPH_THREAD_ITEM *Threads, + _In_ ULONG NumberOfThreads + ) +{ + BOOLEAN success = TRUE; + BOOLEAN cancelled = FALSE; + ULONG i; + + for (i = 0; i < NumberOfThreads; i++) + { + NTSTATUS status; + HANDLE threadHandle; + + if (NT_SUCCESS(status = PhOpenThread( + &threadHandle, + THREAD_SUSPEND_RESUME, + Threads[i]->ThreadId + ))) + { + status = NtResumeThread(threadHandle, NULL); + NtClose(threadHandle); + } + + if (!NT_SUCCESS(status)) + { + BOOLEAN connected; + + success = FALSE; + + if (!cancelled && PhpShowErrorAndConnectToPhSvc( + hWnd, + PhaFormatString(L"Unable to resume thread %u", HandleToUlong(Threads[i]->ThreadId))->Buffer, + status, + &connected + )) + { + if (connected) + { + if (NT_SUCCESS(status = PhSvcCallControlThread(Threads[i]->ThreadId, PhSvcControlThreadResume, 0))) + success = TRUE; + else + PhpShowErrorThread(hWnd, L"resume", Threads[i], status, 0); + + PhUiDisconnectFromPhSvc(); + } + else + { + cancelled = TRUE; + } + } + else + { + if (!PhpShowErrorThread(hWnd, L"resume", Threads[i], status, 0)) + break; + } + } + } + + return success; +} + +BOOLEAN PhUiSetPriorityThread( + _In_ HWND hWnd, + _In_ PPH_THREAD_ITEM Thread, + _In_ LONG Increment + ) +{ + NTSTATUS status; + HANDLE threadHandle; + + // Special saturation values + if (Increment == THREAD_PRIORITY_TIME_CRITICAL) + Increment = THREAD_BASE_PRIORITY_LOWRT + 1; + else if (Increment == THREAD_PRIORITY_IDLE) + Increment = THREAD_BASE_PRIORITY_IDLE - 1; + + if (NT_SUCCESS(status = PhOpenThread( + &threadHandle, + ThreadSetAccess, + Thread->ThreadId + ))) + { + status = NtSetInformationThread(threadHandle, ThreadBasePriority, &Increment, sizeof(LONG)); + NtClose(threadHandle); + } + + if (!NT_SUCCESS(status)) + { + PhpShowErrorThread(hWnd, L"set the priority of", Thread, status, 0); + return FALSE; + } + + return TRUE; +} + +BOOLEAN PhUiSetIoPriorityThread( + _In_ HWND hWnd, + _In_ PPH_THREAD_ITEM Thread, + _In_ IO_PRIORITY_HINT IoPriority + ) +{ + NTSTATUS status; + BOOLEAN success = TRUE; + HANDLE threadHandle; + + if (NT_SUCCESS(status = PhOpenThread( + &threadHandle, + THREAD_SET_INFORMATION, + Thread->ThreadId + ))) + { + status = PhSetThreadIoPriority(threadHandle, IoPriority); + NtClose(threadHandle); + } + + if (!NT_SUCCESS(status)) + { + BOOLEAN connected; + + success = FALSE; + + // The operation may have failed due to the lack of SeIncreaseBasePriorityPrivilege. + if (PhpShowErrorAndConnectToPhSvc( + hWnd, + PhaFormatString(L"Unable to set the I/O priority of thread %u", HandleToUlong(Thread->ThreadId))->Buffer, + status, + &connected + )) + { + if (connected) + { + if (NT_SUCCESS(status = PhSvcCallControlThread(Thread->ThreadId, PhSvcControlThreadIoPriority, IoPriority))) + success = TRUE; + else + PhpShowErrorThread(hWnd, L"set the I/O priority of", Thread, status, 0); + + PhUiDisconnectFromPhSvc(); + } + } + else + { + PhpShowErrorThread(hWnd, L"set the I/O priority of", Thread, status, 0); + } + } + + return success; +} + +BOOLEAN PhUiSetPagePriorityThread( + _In_ HWND hWnd, + _In_ PPH_THREAD_ITEM Thread, + _In_ ULONG PagePriority + ) +{ + NTSTATUS status; + HANDLE threadHandle; + + if (NT_SUCCESS(status = PhOpenThread( + &threadHandle, + THREAD_SET_INFORMATION, + Thread->ThreadId + ))) + { + status = NtSetInformationThread( + threadHandle, + ThreadPagePriority, + &PagePriority, + sizeof(ULONG) + ); + NtClose(threadHandle); + } + + if (!NT_SUCCESS(status)) + { + PhpShowErrorThread(hWnd, L"set the page priority of", Thread, status, 0); + return FALSE; + } + + return TRUE; +} + +BOOLEAN PhUiUnloadModule( + _In_ HWND hWnd, + _In_ HANDLE ProcessId, + _In_ PPH_MODULE_ITEM Module + ) +{ + NTSTATUS status; + BOOLEAN cont = FALSE; + HANDLE processHandle; + + if (PhGetIntegerSetting(L"EnableWarnings")) + { + PWSTR verb; + PWSTR message; + + switch (Module->Type) + { + case PH_MODULE_TYPE_MODULE: + case PH_MODULE_TYPE_WOW64_MODULE: + verb = L"unload"; + message = L"Unloading a module may cause the process to crash."; + + if (WindowsVersion >= WINDOWS_8) + message = L"Unloading a module may cause the process to crash. NOTE: This feature may not work correctly on your version of Windows."; + + break; + case PH_MODULE_TYPE_KERNEL_MODULE: + verb = L"unload"; + message = L"Unloading a driver may cause system instability."; + break; + case PH_MODULE_TYPE_MAPPED_FILE: + case PH_MODULE_TYPE_MAPPED_IMAGE: + verb = L"unmap"; + message = L"Unmapping a section view may cause the process to crash."; + break; + default: + return FALSE; + } + + cont = PhShowConfirmMessage( + hWnd, + verb, + Module->Name->Buffer, + message, + TRUE + ); + } + else + { + cont = TRUE; + } + + if (!cont) + return FALSE; + + switch (Module->Type) + { + case PH_MODULE_TYPE_MODULE: + case PH_MODULE_TYPE_WOW64_MODULE: + if (NT_SUCCESS(status = PhOpenProcess( + &processHandle, + ProcessQueryAccess | PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | + PROCESS_VM_READ | PROCESS_VM_WRITE, + ProcessId + ))) + { + LARGE_INTEGER timeout; + + timeout.QuadPart = -5 * PH_TIMEOUT_SEC; + status = PhUnloadDllProcess( + processHandle, + Module->BaseAddress, + &timeout + ); + + NtClose(processHandle); + } + + if (status == STATUS_DLL_NOT_FOUND) + { + PhShowError(hWnd, L"Unable to find the module to unload."); + return FALSE; + } + + if (!NT_SUCCESS(status)) + { + PhShowStatus( + hWnd, + PhaConcatStrings2(L"Unable to unload ", Module->Name->Buffer)->Buffer, + status, + 0 + ); + return FALSE; + } + + break; + + case PH_MODULE_TYPE_KERNEL_MODULE: + status = PhUnloadDriver(Module->BaseAddress, Module->Name->Buffer); + + if (!NT_SUCCESS(status)) + { + BOOLEAN success = FALSE; + BOOLEAN connected; + + if (PhpShowErrorAndConnectToPhSvc( + hWnd, + PhaConcatStrings2(L"Unable to unload ", Module->Name->Buffer)->Buffer, + status, + &connected + )) + { + if (connected) + { + if (NT_SUCCESS(status = PhSvcCallUnloadDriver(Module->BaseAddress, Module->Name->Buffer))) + success = TRUE; + else + PhShowStatus(hWnd, PhaConcatStrings2(L"Unable to unload ", Module->Name->Buffer)->Buffer, status, 0); + + PhUiDisconnectFromPhSvc(); + } + } + else + { + PhShowStatus( + hWnd, + PhaConcatStrings( + 3, + L"Unable to unload ", + Module->Name->Buffer, + L". Make sure Process Hacker is running with " + L"administrative privileges. Error" + )->Buffer, + status, + 0 + ); + return FALSE; + } + + return success; + } + + break; + + case PH_MODULE_TYPE_MAPPED_FILE: + case PH_MODULE_TYPE_MAPPED_IMAGE: + if (NT_SUCCESS(status = PhOpenProcess( + &processHandle, + PROCESS_VM_OPERATION, + ProcessId + ))) + { + status = NtUnmapViewOfSection(processHandle, Module->BaseAddress); + NtClose(processHandle); + } + + if (!NT_SUCCESS(status)) + { + PhShowStatus( + hWnd, + PhaFormatString(L"Unable to unmap the section view at 0x%Ix", Module->BaseAddress)->Buffer, + status, + 0 + ); + return FALSE; + } + + break; + + default: + return FALSE; + } + + return TRUE; +} + +BOOLEAN PhUiFreeMemory( + _In_ HWND hWnd, + _In_ HANDLE ProcessId, + _In_ PPH_MEMORY_ITEM MemoryItem, + _In_ BOOLEAN Free + ) +{ + NTSTATUS status; + BOOLEAN cont = FALSE; + HANDLE processHandle; + + if (PhGetIntegerSetting(L"EnableWarnings")) + { + PWSTR verb; + PWSTR message; + + if (!(MemoryItem->Type & (MEM_MAPPED | MEM_IMAGE))) + { + if (Free) + { + verb = L"free"; + message = L"Freeing memory regions may cause the process to crash."; + } + else + { + verb = L"decommit"; + message = L"Decommitting memory regions may cause the process to crash."; + } + } + else + { + verb = L"unmap"; + message = L"Unmapping a section view may cause the process to crash."; + } + + cont = PhShowConfirmMessage( + hWnd, + verb, + L"the memory region", + message, + TRUE + ); + } + else + { + cont = TRUE; + } + + if (!cont) + return FALSE; + + if (NT_SUCCESS(status = PhOpenProcess( + &processHandle, + PROCESS_VM_OPERATION, + ProcessId + ))) + { + PVOID baseAddress; + SIZE_T regionSize; + + baseAddress = MemoryItem->BaseAddress; + + if (!(MemoryItem->Type & (MEM_MAPPED | MEM_IMAGE))) + { + // The size needs to be 0 if we're freeing. + if (Free) + regionSize = 0; + else + regionSize = MemoryItem->RegionSize; + + status = NtFreeVirtualMemory( + processHandle, + &baseAddress, + ®ionSize, + Free ? MEM_RELEASE : MEM_DECOMMIT + ); + } + else + { + status = NtUnmapViewOfSection(processHandle, baseAddress); + } + + NtClose(processHandle); + } + + if (!NT_SUCCESS(status)) + { + PWSTR message; + + if (!(MemoryItem->Type & (MEM_MAPPED | MEM_IMAGE))) + { + if (Free) + message = L"Unable to free the memory region"; + else + message = L"Unable to decommit the memory region"; + } + else + { + message = L"Unable to unmap the section view"; + } + + PhShowStatus( + hWnd, + message, + status, + 0 + ); + return FALSE; + } + + return TRUE; +} + +static BOOLEAN PhpShowErrorHandle( + _In_ HWND hWnd, + _In_ PWSTR Verb, + _In_ PPH_HANDLE_ITEM Handle, + _In_ NTSTATUS Status, + _In_opt_ ULONG Win32Result + ) +{ + if (!PhIsNullOrEmptyString(Handle->BestObjectName)) + { + return PhShowContinueStatus( + hWnd, + PhaFormatString( + L"Unable to %s handle \"%s\" (0x%Ix)", + Verb, + Handle->BestObjectName->Buffer, + HandleToUlong(Handle->Handle) + )->Buffer, + Status, + Win32Result + ); + } + else + { + return PhShowContinueStatus( + hWnd, + PhaFormatString( + L"Unable to %s handle 0x%Ix", + Verb, + HandleToUlong(Handle->Handle) + )->Buffer, + Status, + Win32Result + ); + } +} + +BOOLEAN PhUiCloseHandles( + _In_ HWND hWnd, + _In_ HANDLE ProcessId, + _In_ PPH_HANDLE_ITEM *Handles, + _In_ ULONG NumberOfHandles, + _In_ BOOLEAN Warn + ) +{ + NTSTATUS status; + BOOLEAN cont = FALSE; + BOOLEAN success = TRUE; + HANDLE processHandle; + + if (NumberOfHandles == 0) + return FALSE; + + if (Warn && PhGetIntegerSetting(L"EnableWarnings")) + { + cont = PhShowConfirmMessage( + hWnd, + L"close", + NumberOfHandles == 1 ? L"the selected handle" : L"the selected handles", + L"Closing handles may cause system instability and data corruption.", + FALSE + ); + } + else + { + cont = TRUE; + } + + if (!cont) + return FALSE; + + if (NT_SUCCESS(status = PhOpenProcess( + &processHandle, + PROCESS_DUP_HANDLE, + ProcessId + ))) + { + ULONG i; + + for (i = 0; i < NumberOfHandles; i++) + { + status = NtDuplicateObject( + processHandle, + Handles[i]->Handle, + NULL, + NULL, + 0, + 0, + DUPLICATE_CLOSE_SOURCE + ); + + if (!NT_SUCCESS(status)) + { + success = FALSE; + + if (!PhpShowErrorHandle( + hWnd, + L"close", + Handles[i], + status, + 0 + )) + break; + } + } + + NtClose(processHandle); + } + else + { + PhShowStatus(hWnd, L"Unable to open the process", status, 0); + return FALSE; + } + + return success; +} + +BOOLEAN PhUiSetAttributesHandle( + _In_ HWND hWnd, + _In_ HANDLE ProcessId, + _In_ PPH_HANDLE_ITEM Handle, + _In_ ULONG Attributes + ) +{ + NTSTATUS status; + HANDLE processHandle; + + if (!KphIsConnected()) + { + PhShowError(hWnd, PH_KPH_ERROR_MESSAGE); + return FALSE; + } + + if (NT_SUCCESS(status = PhOpenProcess( + &processHandle, + ProcessQueryAccess, + ProcessId + ))) + { + OBJECT_HANDLE_FLAG_INFORMATION handleFlagInfo; + + handleFlagInfo.Inherit = !!(Attributes & OBJ_INHERIT); + handleFlagInfo.ProtectFromClose = !!(Attributes & OBJ_PROTECT_CLOSE); + + status = KphSetInformationObject( + processHandle, + Handle->Handle, + KphObjectHandleFlagInformation, + &handleFlagInfo, + sizeof(OBJECT_HANDLE_FLAG_INFORMATION) + ); + + NtClose(processHandle); + } + + if (!NT_SUCCESS(status)) + { + PhpShowErrorHandle(hWnd, L"set attributes of", Handle, status, 0); + return FALSE; + } + + return TRUE; +} diff --git a/ProcessHacker/affinity.c b/ProcessHacker/affinity.c index 9515cb6933ee..d019c3e2ac65 100644 --- a/ProcessHacker/affinity.c +++ b/ProcessHacker/affinity.c @@ -1,317 +1,317 @@ -/* - * Process Hacker - - * process affinity editor - * - * Copyright (C) 2010-2015 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -/* - * The affinity dialog was originally created to support the modification - * of process affinity masks, but now supports modifying thread affinity - * and generic masks. - */ - -#include - -#include - -#include -#include - -typedef struct _AFFINITY_DIALOG_CONTEXT -{ - PPH_PROCESS_ITEM ProcessItem; - PPH_THREAD_ITEM ThreadItem; - ULONG_PTR AffinityMask; - ULONG_PTR NewAffinityMask; -} AFFINITY_DIALOG_CONTEXT, *PAFFINITY_DIALOG_CONTEXT; - -INT_PTR CALLBACK PhpProcessAffinityDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -VOID PhShowProcessAffinityDialog( - _In_ HWND ParentWindowHandle, - _In_opt_ PPH_PROCESS_ITEM ProcessItem, - _In_opt_ PPH_THREAD_ITEM ThreadItem - ) -{ - AFFINITY_DIALOG_CONTEXT context; - - assert(!!ProcessItem != !!ThreadItem); // make sure we have one and not the other - - context.ProcessItem = ProcessItem; - context.ThreadItem = ThreadItem; - - DialogBoxParam( - PhInstanceHandle, - MAKEINTRESOURCE(IDD_AFFINITY), - ParentWindowHandle, - PhpProcessAffinityDlgProc, - (LPARAM)&context - ); -} - -BOOLEAN PhShowProcessAffinityDialog2( - _In_ HWND ParentWindowHandle, - _In_ ULONG_PTR AffinityMask, - _Out_ PULONG_PTR NewAffinityMask - ) -{ - AFFINITY_DIALOG_CONTEXT context; - - context.ProcessItem = NULL; - context.ThreadItem = NULL; - context.AffinityMask = AffinityMask; - - if (DialogBoxParam( - PhInstanceHandle, - MAKEINTRESOURCE(IDD_AFFINITY), - ParentWindowHandle, - PhpProcessAffinityDlgProc, - (LPARAM)&context - ) == IDOK) - { - *NewAffinityMask = context.NewAffinityMask; - - return TRUE; - } - else - { - return FALSE; - } -} - -static INT_PTR CALLBACK PhpProcessAffinityDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - switch (uMsg) - { - case WM_INITDIALOG: - { - NTSTATUS status; - PAFFINITY_DIALOG_CONTEXT context = (PAFFINITY_DIALOG_CONTEXT)lParam; - SYSTEM_BASIC_INFORMATION systemBasicInfo; - ULONG_PTR systemAffinityMask; - ULONG_PTR affinityMask; - ULONG i; - - SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)context); - PhCenterWindow(hwndDlg, GetParent(hwndDlg)); - - systemAffinityMask = 0; - - if (context->ProcessItem) - { - HANDLE processHandle; - PROCESS_BASIC_INFORMATION basicInfo; - - if (NT_SUCCESS(status = PhOpenProcess( - &processHandle, - ProcessQueryAccess, - context->ProcessItem->ProcessId - ))) - { - status = PhGetProcessBasicInformation(processHandle, &basicInfo); - - if (NT_SUCCESS(status)) - affinityMask = basicInfo.AffinityMask; - - NtClose(processHandle); - } - } - else if (context->ThreadItem) - { - HANDLE threadHandle; - THREAD_BASIC_INFORMATION basicInfo; - HANDLE processHandle; - PROCESS_BASIC_INFORMATION processBasicInfo; - - if (NT_SUCCESS(status = PhOpenThread( - &threadHandle, - ThreadQueryAccess, - context->ThreadItem->ThreadId - ))) - { - status = PhGetThreadBasicInformation(threadHandle, &basicInfo); - - if (NT_SUCCESS(status)) - { - affinityMask = basicInfo.AffinityMask; - - // A thread's affinity mask is restricted by the process affinity mask, - // so use that as the system affinity mask. - - if (NT_SUCCESS(PhOpenProcess( - &processHandle, - ProcessQueryAccess, - basicInfo.ClientId.UniqueProcess - ))) - { - if (NT_SUCCESS(PhGetProcessBasicInformation(processHandle, &processBasicInfo))) - systemAffinityMask = processBasicInfo.AffinityMask; - - NtClose(processHandle); - } - } - - NtClose(threadHandle); - } - } - else - { - affinityMask = context->AffinityMask; - status = STATUS_SUCCESS; - } - - if (NT_SUCCESS(status) && systemAffinityMask == 0) - { - status = NtQuerySystemInformation( - SystemBasicInformation, - &systemBasicInfo, - sizeof(SYSTEM_BASIC_INFORMATION), - NULL - ); - - if (NT_SUCCESS(status)) - systemAffinityMask = systemBasicInfo.ActiveProcessorsAffinityMask; - } - - if (!NT_SUCCESS(status)) - { - PhShowStatus(hwndDlg, L"Unable to retrieve the affinity", status, 0); - EndDialog(hwndDlg, IDCANCEL); - break; - } - - // Disable the CPU checkboxes which aren't part of the system affinity mask, - // and check the CPU checkboxes which are part of the affinity mask. - - for (i = 0; i < 8 * 8; i++) - { - if ((i < sizeof(ULONG_PTR) * 8) && ((systemAffinityMask >> i) & 0x1)) - { - if ((affinityMask >> i) & 0x1) - { - Button_SetCheck(GetDlgItem(hwndDlg, IDC_CPU0 + i), BST_CHECKED); - } - } - else - { - EnableWindow(GetDlgItem(hwndDlg, IDC_CPU0 + i), FALSE); - } - } - } - break; - case WM_DESTROY: - { - RemoveProp(hwndDlg, PhMakeContextAtom()); - } - break; - case WM_COMMAND: - { - switch (LOWORD(wParam)) - { - case IDCANCEL: - EndDialog(hwndDlg, IDCANCEL); - break; - case IDOK: - { - NTSTATUS status; - PAFFINITY_DIALOG_CONTEXT context = (PAFFINITY_DIALOG_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom()); - ULONG i; - ULONG_PTR affinityMask; - - // Work out the affinity mask. - - affinityMask = 0; - - for (i = 0; i < sizeof(ULONG_PTR) * 8; i++) - { - if (Button_GetCheck(GetDlgItem(hwndDlg, IDC_CPU0 + i)) == BST_CHECKED) - affinityMask |= (ULONG_PTR)1 << i; - } - - if (context->ProcessItem) - { - HANDLE processHandle; - - if (NT_SUCCESS(status = PhOpenProcess( - &processHandle, - PROCESS_SET_INFORMATION, - context->ProcessItem->ProcessId - ))) - { - status = PhSetProcessAffinityMask(processHandle, affinityMask); - NtClose(processHandle); - } - } - else if (context->ThreadItem) - { - HANDLE threadHandle; - - if (NT_SUCCESS(status = PhOpenThread( - &threadHandle, - ThreadSetAccess, - context->ThreadItem->ThreadId - ))) - { - status = PhSetThreadAffinityMask(threadHandle, affinityMask); - NtClose(threadHandle); - } - } - else - { - context->NewAffinityMask = affinityMask; - status = STATUS_SUCCESS; - } - - if (NT_SUCCESS(status)) - EndDialog(hwndDlg, IDOK); - else - PhShowStatus(hwndDlg, L"Unable to set the affinity", status, 0); - } - break; - case IDC_SELECTALL: - case IDC_DESELECTALL: - { - ULONG i; - - for (i = 0; i < sizeof(ULONG_PTR) * 8; i++) - { - HWND checkBox = GetDlgItem(hwndDlg, IDC_CPU0 + i); - - if (IsWindowEnabled(checkBox)) - Button_SetCheck(checkBox, LOWORD(wParam) == IDC_SELECTALL ? BST_CHECKED : BST_UNCHECKED); - } - } - break; - } - } - break; - } - - return FALSE; -} +/* + * Process Hacker - + * process affinity editor + * + * Copyright (C) 2010-2015 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +/* + * The affinity dialog was originally created to support the modification + * of process affinity masks, but now supports modifying thread affinity + * and generic masks. + */ + +#include + +#include + +#include +#include + +typedef struct _AFFINITY_DIALOG_CONTEXT +{ + PPH_PROCESS_ITEM ProcessItem; + PPH_THREAD_ITEM ThreadItem; + ULONG_PTR AffinityMask; + ULONG_PTR NewAffinityMask; +} AFFINITY_DIALOG_CONTEXT, *PAFFINITY_DIALOG_CONTEXT; + +INT_PTR CALLBACK PhpProcessAffinityDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +VOID PhShowProcessAffinityDialog( + _In_ HWND ParentWindowHandle, + _In_opt_ PPH_PROCESS_ITEM ProcessItem, + _In_opt_ PPH_THREAD_ITEM ThreadItem + ) +{ + AFFINITY_DIALOG_CONTEXT context; + + assert(!!ProcessItem != !!ThreadItem); // make sure we have one and not the other + + context.ProcessItem = ProcessItem; + context.ThreadItem = ThreadItem; + + DialogBoxParam( + PhInstanceHandle, + MAKEINTRESOURCE(IDD_AFFINITY), + ParentWindowHandle, + PhpProcessAffinityDlgProc, + (LPARAM)&context + ); +} + +BOOLEAN PhShowProcessAffinityDialog2( + _In_ HWND ParentWindowHandle, + _In_ ULONG_PTR AffinityMask, + _Out_ PULONG_PTR NewAffinityMask + ) +{ + AFFINITY_DIALOG_CONTEXT context; + + context.ProcessItem = NULL; + context.ThreadItem = NULL; + context.AffinityMask = AffinityMask; + + if (DialogBoxParam( + PhInstanceHandle, + MAKEINTRESOURCE(IDD_AFFINITY), + ParentWindowHandle, + PhpProcessAffinityDlgProc, + (LPARAM)&context + ) == IDOK) + { + *NewAffinityMask = context.NewAffinityMask; + + return TRUE; + } + else + { + return FALSE; + } +} + +static INT_PTR CALLBACK PhpProcessAffinityDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + switch (uMsg) + { + case WM_INITDIALOG: + { + NTSTATUS status; + PAFFINITY_DIALOG_CONTEXT context = (PAFFINITY_DIALOG_CONTEXT)lParam; + SYSTEM_BASIC_INFORMATION systemBasicInfo; + ULONG_PTR systemAffinityMask; + ULONG_PTR affinityMask; + ULONG i; + + SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)context); + PhCenterWindow(hwndDlg, GetParent(hwndDlg)); + + systemAffinityMask = 0; + + if (context->ProcessItem) + { + HANDLE processHandle; + PROCESS_BASIC_INFORMATION basicInfo; + + if (NT_SUCCESS(status = PhOpenProcess( + &processHandle, + ProcessQueryAccess, + context->ProcessItem->ProcessId + ))) + { + status = PhGetProcessBasicInformation(processHandle, &basicInfo); + + if (NT_SUCCESS(status)) + affinityMask = basicInfo.AffinityMask; + + NtClose(processHandle); + } + } + else if (context->ThreadItem) + { + HANDLE threadHandle; + THREAD_BASIC_INFORMATION basicInfo; + HANDLE processHandle; + PROCESS_BASIC_INFORMATION processBasicInfo; + + if (NT_SUCCESS(status = PhOpenThread( + &threadHandle, + ThreadQueryAccess, + context->ThreadItem->ThreadId + ))) + { + status = PhGetThreadBasicInformation(threadHandle, &basicInfo); + + if (NT_SUCCESS(status)) + { + affinityMask = basicInfo.AffinityMask; + + // A thread's affinity mask is restricted by the process affinity mask, + // so use that as the system affinity mask. + + if (NT_SUCCESS(PhOpenProcess( + &processHandle, + ProcessQueryAccess, + basicInfo.ClientId.UniqueProcess + ))) + { + if (NT_SUCCESS(PhGetProcessBasicInformation(processHandle, &processBasicInfo))) + systemAffinityMask = processBasicInfo.AffinityMask; + + NtClose(processHandle); + } + } + + NtClose(threadHandle); + } + } + else + { + affinityMask = context->AffinityMask; + status = STATUS_SUCCESS; + } + + if (NT_SUCCESS(status) && systemAffinityMask == 0) + { + status = NtQuerySystemInformation( + SystemBasicInformation, + &systemBasicInfo, + sizeof(SYSTEM_BASIC_INFORMATION), + NULL + ); + + if (NT_SUCCESS(status)) + systemAffinityMask = systemBasicInfo.ActiveProcessorsAffinityMask; + } + + if (!NT_SUCCESS(status)) + { + PhShowStatus(hwndDlg, L"Unable to retrieve the affinity", status, 0); + EndDialog(hwndDlg, IDCANCEL); + break; + } + + // Disable the CPU checkboxes which aren't part of the system affinity mask, + // and check the CPU checkboxes which are part of the affinity mask. + + for (i = 0; i < 8 * 8; i++) + { + if ((i < sizeof(ULONG_PTR) * 8) && ((systemAffinityMask >> i) & 0x1)) + { + if ((affinityMask >> i) & 0x1) + { + Button_SetCheck(GetDlgItem(hwndDlg, IDC_CPU0 + i), BST_CHECKED); + } + } + else + { + EnableWindow(GetDlgItem(hwndDlg, IDC_CPU0 + i), FALSE); + } + } + } + break; + case WM_DESTROY: + { + RemoveProp(hwndDlg, PhMakeContextAtom()); + } + break; + case WM_COMMAND: + { + switch (LOWORD(wParam)) + { + case IDCANCEL: + EndDialog(hwndDlg, IDCANCEL); + break; + case IDOK: + { + NTSTATUS status; + PAFFINITY_DIALOG_CONTEXT context = (PAFFINITY_DIALOG_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom()); + ULONG i; + ULONG_PTR affinityMask; + + // Work out the affinity mask. + + affinityMask = 0; + + for (i = 0; i < sizeof(ULONG_PTR) * 8; i++) + { + if (Button_GetCheck(GetDlgItem(hwndDlg, IDC_CPU0 + i)) == BST_CHECKED) + affinityMask |= (ULONG_PTR)1 << i; + } + + if (context->ProcessItem) + { + HANDLE processHandle; + + if (NT_SUCCESS(status = PhOpenProcess( + &processHandle, + PROCESS_SET_INFORMATION, + context->ProcessItem->ProcessId + ))) + { + status = PhSetProcessAffinityMask(processHandle, affinityMask); + NtClose(processHandle); + } + } + else if (context->ThreadItem) + { + HANDLE threadHandle; + + if (NT_SUCCESS(status = PhOpenThread( + &threadHandle, + ThreadSetAccess, + context->ThreadItem->ThreadId + ))) + { + status = PhSetThreadAffinityMask(threadHandle, affinityMask); + NtClose(threadHandle); + } + } + else + { + context->NewAffinityMask = affinityMask; + status = STATUS_SUCCESS; + } + + if (NT_SUCCESS(status)) + EndDialog(hwndDlg, IDOK); + else + PhShowStatus(hwndDlg, L"Unable to set the affinity", status, 0); + } + break; + case IDC_SELECTALL: + case IDC_DESELECTALL: + { + ULONG i; + + for (i = 0; i < sizeof(ULONG_PTR) * 8; i++) + { + HWND checkBox = GetDlgItem(hwndDlg, IDC_CPU0 + i); + + if (IsWindowEnabled(checkBox)) + Button_SetCheck(checkBox, LOWORD(wParam) == IDC_SELECTALL ? BST_CHECKED : BST_UNCHECKED); + } + } + break; + } + } + break; + } + + return FALSE; +} diff --git a/ProcessHacker/anawait.c b/ProcessHacker/anawait.c index 63f355a0e008..bc7c2af90f70 100644 --- a/ProcessHacker/anawait.c +++ b/ProcessHacker/anawait.c @@ -1,1076 +1,1076 @@ -/* - * Process Hacker - - * thread wait analysis - * - * Copyright (C) 2010-2011 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -/* - * There are two ways of seeing what a thread is waiting on. The first method - * is to walk the stack of a thread and read the arguments to whatever system - * call it is blocking on; this only works on x86 because on x64 the arguments - * are passed in registers (at least the first four are). The second method - * involves using the ThreadLastSystemCall info class for NtQueryInformationThread - * to retrieve the first argument to the system call the thread is blocking on. - * This is obviously only useful for NtWaitForSingleObject. - * - * There are other methods for specific scenarios, like USER messages and ALPC - * calls. - */ - -#include - -#include -#include - -#include - -typedef HWND (WINAPI *_GetSendMessageReceiver)( - _In_ HANDLE ThreadId - ); - -typedef NTSTATUS (NTAPI *_NtAlpcQueryInformation)( - _In_ HANDLE PortHandle, - _In_ ALPC_PORT_INFORMATION_CLASS PortInformationClass, - _Out_writes_bytes_(Length) PVOID PortInformation, - _In_ ULONG Length, - _Out_opt_ PULONG ReturnLength - ); - -typedef struct _ANALYZE_WAIT_CONTEXT -{ - BOOLEAN Found; - BOOLEAN IsWow64; - HANDLE ProcessId; - HANDLE ThreadId; - HANDLE ProcessHandle; - - PPH_SYMBOL_PROVIDER SymbolProvider; - PH_STRING_BUILDER StringBuilder; - - PVOID PrevParams[4]; -} ANALYZE_WAIT_CONTEXT, *PANALYZE_WAIT_CONTEXT; - -VOID PhpAnalyzeWaitPassive( - _In_ HWND hWnd, - _In_ HANDLE ProcessId, - _In_ HANDLE ThreadId - ); - -BOOLEAN NTAPI PhpWalkThreadStackAnalyzeCallback( - _In_ PPH_THREAD_STACK_FRAME StackFrame, - _In_opt_ PVOID Context - ); - -VOID PhpAnalyzeWaitFallbacks( - _In_ PANALYZE_WAIT_CONTEXT Context - ); - -VOID PhpInitializeServiceNumbers( - VOID - ); - -PPH_STRING PhpaGetHandleString( - _In_ HANDLE ProcessHandle, - _In_ HANDLE Handle - ); - -VOID PhpGetWfmoInformation( - _In_ HANDLE ProcessHandle, - _In_ BOOLEAN IsWow64, - _In_ ULONG NumberOfHandles, - _In_ PHANDLE AddressOfHandles, - _In_ WAIT_TYPE WaitType, - _In_ BOOLEAN Alertable, - _Inout_ PPH_STRING_BUILDER StringBuilder - ); - -PPH_STRING PhpaGetSendMessageReceiver( - _In_ HANDLE ThreadId - ); - -PPH_STRING PhpaGetAlpcInformation( - _In_ HANDLE ThreadId - ); - -static PH_INITONCE ServiceNumbersInitOnce = PH_INITONCE_INIT; -static USHORT NumberForWfso = -1; -static USHORT NumberForWfmo = -1; -static USHORT NumberForRf = -1; - -VOID PhUiAnalyzeWaitThread( - _In_ HWND hWnd, - _In_ HANDLE ProcessId, - _In_ HANDLE ThreadId, - _In_ PPH_SYMBOL_PROVIDER SymbolProvider - ) -{ - NTSTATUS status; - HANDLE threadHandle; -#ifdef _WIN64 - HANDLE processHandle; - BOOLEAN isWow64; -#endif - CLIENT_ID clientId; - ANALYZE_WAIT_CONTEXT context; - -#ifdef _WIN64 - // Determine if the process is WOW64. If not, we use the passive method. - - if (!NT_SUCCESS(status = PhOpenProcess(&processHandle, ProcessQueryAccess, ProcessId))) - { - PhShowStatus(hWnd, L"Unable to open the process", status, 0); - return; - } - - if (!NT_SUCCESS(status = PhGetProcessIsWow64(processHandle, &isWow64)) || !isWow64) - { - PhpAnalyzeWaitPassive(hWnd, ProcessId, ThreadId); - return; - } - - NtClose(processHandle); -#endif - - if (!NT_SUCCESS(status = PhOpenThread( - &threadHandle, - ThreadQueryAccess | THREAD_GET_CONTEXT | THREAD_SUSPEND_RESUME, - ThreadId - ))) - { - PhShowStatus(hWnd, L"Unable to open the thread", status, 0); - return; - } - - context.ProcessId = ProcessId; - context.ThreadId = ThreadId; - - context.ProcessHandle = SymbolProvider->ProcessHandle; - context.SymbolProvider = SymbolProvider; - PhInitializeStringBuilder(&context.StringBuilder, 100); - - clientId.UniqueProcess = ProcessId; - clientId.UniqueThread = ThreadId; - - PhWalkThreadStack( - threadHandle, - SymbolProvider->ProcessHandle, - &clientId, - SymbolProvider, - PH_WALK_I386_STACK, - PhpWalkThreadStackAnalyzeCallback, - &context - ); - NtClose(threadHandle); - - PhpAnalyzeWaitFallbacks(&context); - - if (context.Found) - { - PhShowInformationDialog(hWnd, context.StringBuilder.String->Buffer, 0); - } - else - { - PhShowInformation(hWnd, L"The thread does not appear to be waiting."); - } - - PhDeleteStringBuilder(&context.StringBuilder); -} - -VOID PhpAnalyzeWaitPassive( - _In_ HWND hWnd, - _In_ HANDLE ProcessId, - _In_ HANDLE ThreadId - ) -{ - NTSTATUS status; - HANDLE processHandle; - HANDLE threadHandle; - THREAD_LAST_SYSCALL_INFORMATION lastSystemCall; - PH_STRING_BUILDER stringBuilder; - PPH_STRING string; - - PhpInitializeServiceNumbers(); - - if (!NT_SUCCESS(status = PhOpenThread(&threadHandle, THREAD_GET_CONTEXT, ThreadId))) - { - PhShowStatus(hWnd, L"Unable to open the thread", status, 0); - return; - } - - if (!NT_SUCCESS(status = NtQueryInformationThread( - threadHandle, - ThreadLastSystemCall, - &lastSystemCall, - sizeof(THREAD_LAST_SYSCALL_INFORMATION), - NULL - ))) - { - NtClose(threadHandle); - PhShowInformation(hWnd, L"Unable to determine whether the thread is waiting."); - return; - } - - if (!NT_SUCCESS(status = PhOpenProcess(&processHandle, PROCESS_DUP_HANDLE, ProcessId))) - { - NtClose(threadHandle); - PhShowStatus(hWnd, L"Unable to open the process", status, 0); - return; - } - - PhInitializeStringBuilder(&stringBuilder, 100); - - if (lastSystemCall.SystemCallNumber == NumberForWfso) - { - string = PhpaGetHandleString(processHandle, lastSystemCall.FirstArgument); - - PhAppendFormatStringBuilder(&stringBuilder, L"Thread is waiting for:\r\n"); - PhAppendStringBuilder(&stringBuilder, &string->sr); - } - else if (lastSystemCall.SystemCallNumber == NumberForWfmo) - { - PhAppendFormatStringBuilder(&stringBuilder, L"Thread is waiting for multiple (%u) objects.", PtrToUlong(lastSystemCall.FirstArgument)); - } - else if (lastSystemCall.SystemCallNumber == NumberForRf) - { - string = PhpaGetHandleString(processHandle, lastSystemCall.FirstArgument); - - PhAppendFormatStringBuilder(&stringBuilder, L"Thread is waiting for file I/O:\r\n"); - PhAppendStringBuilder(&stringBuilder, &string->sr); - } - else - { - string = PhpaGetSendMessageReceiver(ThreadId); - - if (string) - { - PhAppendStringBuilder2(&stringBuilder, L"Thread is sending a USER message:\r\n"); - PhAppendStringBuilder(&stringBuilder, &string->sr); - } - else - { - string = PhpaGetAlpcInformation(ThreadId); - - if (string) - { - PhAppendStringBuilder2(&stringBuilder, L"Thread is waiting for an ALPC port:\r\n"); - PhAppendStringBuilder(&stringBuilder, &string->sr); - } - } - } - - if (stringBuilder.String->Length == 0) - PhAppendStringBuilder2(&stringBuilder, L"Unable to determine why the thread is waiting."); - - PhShowInformationDialog(hWnd, stringBuilder.String->Buffer, 0); - - PhDeleteStringBuilder(&stringBuilder); - NtClose(processHandle); - NtClose(threadHandle); -} - -static BOOLEAN NTAPI PhpWalkThreadStackAnalyzeCallback( - _In_ PPH_THREAD_STACK_FRAME StackFrame, - _In_opt_ PVOID Context - ) -{ - PANALYZE_WAIT_CONTEXT context = (PANALYZE_WAIT_CONTEXT)Context; - PPH_STRING name; - - name = PhGetSymbolFromAddress( - context->SymbolProvider, - (ULONG64)StackFrame->PcAddress, - NULL, - NULL, - NULL, - NULL - ); - - if (!name) - return TRUE; - - context->Found = TRUE; - -#define FUNC_MATCH(Name) PhStartsWithString2(name, L##Name, TRUE) -#define NT_FUNC_MATCH(Name) ( \ - PhStartsWithString2(name, L"ntdll.dll!Nt" L##Name, TRUE) || \ - PhStartsWithString2(name, L"ntdll.dll!Zw" L##Name, TRUE) \ - ) - - if (!name) - { - // Dummy - } - else if (FUNC_MATCH("kernel32.dll!Sleep")) - { - PhAppendFormatStringBuilder( - &context->StringBuilder, - L"Thread is sleeping. Timeout: %u milliseconds.", - PtrToUlong(StackFrame->Params[0]) - ); - } - else if (NT_FUNC_MATCH("DelayExecution")) - { - BOOLEAN alertable = !!StackFrame->Params[0]; - PVOID timeoutAddress = StackFrame->Params[1]; - LARGE_INTEGER timeout; - - if (NT_SUCCESS(NtReadVirtualMemory( - context->ProcessHandle, - timeoutAddress, - &timeout, - sizeof(LARGE_INTEGER), - NULL - ))) - { - if (timeout.QuadPart < 0) - { - PhAppendFormatStringBuilder( - &context->StringBuilder, - L"Thread is sleeping. Timeout: %I64u milliseconds.", - -timeout.QuadPart / PH_TIMEOUT_MS - ); - } - else - { - // TODO - } - } - else - { - PhAppendStringBuilder2( - &context->StringBuilder, - L"Thread is sleeping." - ); - } - } - else if (NT_FUNC_MATCH("DeviceIoControlFile")) - { - HANDLE handle = (HANDLE)StackFrame->Params[0]; - - PhAppendStringBuilder2( - &context->StringBuilder, - L"Thread is waiting for an I/O control request:\r\n" - ); - PhAppendStringBuilder( - &context->StringBuilder, - &PhpaGetHandleString(context->ProcessHandle, handle)->sr - ); - } - else if (NT_FUNC_MATCH("FsControlFile")) - { - HANDLE handle = StackFrame->Params[0]; - - PhAppendStringBuilder2( - &context->StringBuilder, - L"Thread is waiting for a FS control request:\r\n" - ); - PhAppendStringBuilder( - &context->StringBuilder, - &PhpaGetHandleString(context->ProcessHandle, handle)->sr - ); - } - else if (NT_FUNC_MATCH("QueryObject")) - { - HANDLE handle = StackFrame->Params[0]; - - // Use the KiFastSystemCall args if the handle we have is wrong. - if ((ULONG_PTR)handle % 4 != 0 || !handle) - handle = context->PrevParams[1]; - - PhAppendStringBuilder2( - &context->StringBuilder, - L"Thread is querying an object:\r\n" - ); - PhAppendStringBuilder( - &context->StringBuilder, - &PhpaGetHandleString(context->ProcessHandle, handle)->sr - ); - } - else if (NT_FUNC_MATCH("ReadFile") || NT_FUNC_MATCH("WriteFile")) - { - HANDLE handle = StackFrame->Params[0]; - - PhAppendStringBuilder2( - &context->StringBuilder, - L"Thread is waiting for file I/O:\r\n" - ); - PhAppendStringBuilder( - &context->StringBuilder, - &PhpaGetHandleString(context->ProcessHandle, handle)->sr - ); - } - else if (NT_FUNC_MATCH("RemoveIoCompletion")) - { - HANDLE handle = StackFrame->Params[0]; - - PhAppendStringBuilder2( - &context->StringBuilder, - L"Thread is waiting for an I/O completion port:\r\n" - ); - PhAppendStringBuilder( - &context->StringBuilder, - &PhpaGetHandleString(context->ProcessHandle, handle)->sr - ); - } - else if ( - NT_FUNC_MATCH("ReplyWaitReceivePort") || - NT_FUNC_MATCH("RequestWaitReplyPort") || - NT_FUNC_MATCH("AlpcSendWaitReceivePort") - ) - { - HANDLE handle = StackFrame->Params[0]; - PPH_STRING alpcInfo; - - PhAppendStringBuilder2( - &context->StringBuilder, - WindowsVersion >= WINDOWS_VISTA ? L"Thread is waiting for an ALPC port:\r\n" : L"Thread is waiting for a LPC port:\r\n" - ); - PhAppendStringBuilder( - &context->StringBuilder, - &PhpaGetHandleString(context->ProcessHandle, handle)->sr - ); - - if (alpcInfo = PhpaGetAlpcInformation(context->ThreadId)) - { - PhAppendStringBuilder2( - &context->StringBuilder, - L"\r\n" - ); - PhAppendStringBuilder( - &context->StringBuilder, - &alpcInfo->sr - ); - } - } - else if ( - NT_FUNC_MATCH("SetHighWaitLowEventPair") || - NT_FUNC_MATCH("SetLowWaitHighEventPair") || - NT_FUNC_MATCH("WaitHighEventPair") || - NT_FUNC_MATCH("WaitLowEventPair") - ) - { - HANDLE handle = StackFrame->Params[0]; - - if ((ULONG_PTR)handle % 4 != 0 || !handle) - handle = context->PrevParams[1]; - - PhAppendFormatStringBuilder( - &context->StringBuilder, - L"Thread is waiting (%s) for an event pair:\r\n", - name->Buffer - ); - PhAppendStringBuilder( - &context->StringBuilder, - &PhpaGetHandleString(context->ProcessHandle, handle)->sr - ); - } - else if ( - FUNC_MATCH("user32.dll!NtUserGetMessage") || - FUNC_MATCH("user32.dll!NtUserWaitMessage") - ) - { - PhAppendStringBuilder2( - &context->StringBuilder, - L"Thread is waiting for a USER message.\r\n" - ); - } - else if (FUNC_MATCH("user32.dll!NtUserMessageCall")) - { - PPH_STRING receiverString; - - PhAppendStringBuilder2( - &context->StringBuilder, - L"Thread is sending a USER message:\r\n" - ); - - receiverString = PhpaGetSendMessageReceiver(context->ThreadId); - - if (receiverString) - { - PhAppendStringBuilder(&context->StringBuilder, &receiverString->sr); - PhAppendStringBuilder2(&context->StringBuilder, L"\r\n"); - } - else - { - PhAppendStringBuilder2(&context->StringBuilder, L"Unknown.\r\n"); - } - } - else if (NT_FUNC_MATCH("WaitForDebugEvent")) - { - HANDLE handle = StackFrame->Params[0]; - - PhAppendStringBuilder2( - &context->StringBuilder, - L"Thread is waiting for a debug event:\r\n" - ); - PhAppendStringBuilder( - &context->StringBuilder, - &PhpaGetHandleString(context->ProcessHandle, handle)->sr - ); - } - else if ( - NT_FUNC_MATCH("WaitForKeyedEvent") || - NT_FUNC_MATCH("ReleaseKeyedEvent") - ) - { - HANDLE handle = StackFrame->Params[0]; - PVOID key = StackFrame->Params[1]; - - PhAppendFormatStringBuilder( - &context->StringBuilder, - L"Thread is waiting (%s) for a keyed event (key 0x%Ix):\r\n", - name->Buffer, - key - ); - PhAppendStringBuilder( - &context->StringBuilder, - &PhpaGetHandleString(context->ProcessHandle, handle)->sr - ); - } - else if ( - NT_FUNC_MATCH("WaitForMultipleObjects") || - FUNC_MATCH("kernel32.dll!WaitForMultipleObjects") - ) - { - ULONG numberOfHandles = PtrToUlong(StackFrame->Params[0]); - PVOID addressOfHandles = StackFrame->Params[1]; - WAIT_TYPE waitType = (WAIT_TYPE)StackFrame->Params[2]; - BOOLEAN alertable = !!StackFrame->Params[3]; - - if (numberOfHandles > MAXIMUM_WAIT_OBJECTS) - { - numberOfHandles = PtrToUlong(context->PrevParams[1]); - addressOfHandles = context->PrevParams[2]; - waitType = (WAIT_TYPE)context->PrevParams[3]; - alertable = FALSE; - } - - PhpGetWfmoInformation( - context->ProcessHandle, - TRUE, // on x64 this function is only called for WOW64 processes - numberOfHandles, - addressOfHandles, - waitType, - alertable, - &context->StringBuilder - ); - } - else if ( - NT_FUNC_MATCH("WaitForSingleObject") || - FUNC_MATCH("kernel32.dll!WaitForSingleObject") - ) - { - HANDLE handle = StackFrame->Params[0]; - BOOLEAN alertable = !!StackFrame->Params[1]; - - if ((ULONG_PTR)handle % 4 != 0 || !handle) - { - handle = context->PrevParams[1]; - alertable = !!context->PrevParams[2]; - } - - PhAppendFormatStringBuilder( - &context->StringBuilder, - L"Thread is waiting (%s) for:\r\n", - alertable ? L"alertable" : L"non-alertable" - ); - PhAppendStringBuilder( - &context->StringBuilder, - &PhpaGetHandleString(context->ProcessHandle, handle)->sr - ); - } - else if (NT_FUNC_MATCH("WaitForWorkViaWorkerFactory")) - { - HANDLE handle = StackFrame->Params[0]; - - PhAppendStringBuilder2( - &context->StringBuilder, - L"Thread is waiting for work from a worker factory:\r\n" - ); - PhAppendStringBuilder( - &context->StringBuilder, - &PhpaGetHandleString(context->ProcessHandle, handle)->sr - ); - } - else - { - context->Found = FALSE; - } - - PhDereferenceObject(name); - memcpy(&context->PrevParams, StackFrame->Params, sizeof(StackFrame->Params)); - - return !context->Found; -} - -static VOID PhpAnalyzeWaitFallbacks( - _In_ PANALYZE_WAIT_CONTEXT Context - ) -{ - PPH_STRING info; - - // We didn't detect NtUserMessageCall, but this may still apply due to another - // win32k system call (e.g. from EnableWindow). - if (!Context->Found && (info = PhpaGetSendMessageReceiver(Context->ThreadId))) - { - PhAppendStringBuilder2( - &Context->StringBuilder, - L"Thread is sending a USER message:\r\n" - ); - PhAppendStringBuilder(&Context->StringBuilder, &info->sr); - PhAppendStringBuilder2(&Context->StringBuilder, L"\r\n"); - - Context->Found = TRUE; - } - - // Nt(Alpc)ConnectPort doesn't get detected anywhere else. - if (!Context->Found && (info = PhpaGetAlpcInformation(Context->ThreadId))) - { - PhAppendStringBuilder2( - &Context->StringBuilder, - L"Thread is waiting for an ALPC port:\r\n" - ); - PhAppendStringBuilder(&Context->StringBuilder, &info->sr); - PhAppendStringBuilder2(&Context->StringBuilder, L"\r\n"); - - Context->Found = TRUE; - } -} - -static BOOLEAN PhpWaitUntilThreadIsWaiting( - _In_ HANDLE ThreadHandle - ) -{ - ULONG attempts; - BOOLEAN isWaiting = FALSE; - THREAD_BASIC_INFORMATION basicInfo; - - if (!NT_SUCCESS(PhGetThreadBasicInformation(ThreadHandle, &basicInfo))) - return FALSE; - - for (attempts = 0; attempts < 5; attempts++) - { - PVOID processes; - PSYSTEM_PROCESS_INFORMATION processInfo; - ULONG i; - LARGE_INTEGER interval; - - interval.QuadPart = -100 * PH_TIMEOUT_MS; - NtDelayExecution(FALSE, &interval); - - if (!NT_SUCCESS(PhEnumProcesses(&processes))) - break; - - processInfo = PhFindProcessInformation(processes, basicInfo.ClientId.UniqueProcess); - - if (processInfo) - { - for (i = 0; i < processInfo->NumberOfThreads; i++) - { - if ( - processInfo->Threads[i].ClientId.UniqueThread == basicInfo.ClientId.UniqueThread && - processInfo->Threads[i].ThreadState == Waiting && - (processInfo->Threads[i].WaitReason == UserRequest || - processInfo->Threads[i].WaitReason == Executive) - ) - { - isWaiting = TRUE; - break; - } - } - } - - PhFree(processes); - - if (isWaiting) - break; - - interval.QuadPart = -500 * PH_TIMEOUT_MS; - NtDelayExecution(FALSE, &interval); - } - - return isWaiting; -} - -static VOID PhpGetThreadLastSystemCallNumber( - _In_ HANDLE ThreadHandle, - _Out_ PUSHORT LastSystemCallNumber - ) -{ - THREAD_LAST_SYSCALL_INFORMATION lastSystemCall; - - if (NT_SUCCESS(NtQueryInformationThread( - ThreadHandle, - ThreadLastSystemCall, - &lastSystemCall, - sizeof(THREAD_LAST_SYSCALL_INFORMATION), - NULL - ))) - { - *LastSystemCallNumber = lastSystemCall.SystemCallNumber; - } -} - -static NTSTATUS PhpWfsoThreadStart( - _In_ PVOID Parameter - ) -{ - HANDLE eventHandle; - LARGE_INTEGER timeout; - - eventHandle = Parameter; - - timeout.QuadPart = -5 * PH_TIMEOUT_SEC; - NtWaitForSingleObject(eventHandle, FALSE, &timeout); - - return STATUS_SUCCESS; -} - -static NTSTATUS PhpWfmoThreadStart( - _In_ PVOID Parameter - ) -{ - HANDLE eventHandle; - LARGE_INTEGER timeout; - - eventHandle = Parameter; - - timeout.QuadPart = -5 * PH_TIMEOUT_SEC; - NtWaitForMultipleObjects(1, &eventHandle, WaitAll, FALSE, &timeout); - - return STATUS_SUCCESS; -} - -static NTSTATUS PhpRfThreadStart( - _In_ PVOID Parameter - ) -{ - HANDLE fileHandle; - IO_STATUS_BLOCK isb; - ULONG data; - - fileHandle = Parameter; - - NtReadFile(fileHandle, NULL, NULL, NULL, &isb, &data, sizeof(ULONG), NULL, NULL); - - return STATUS_SUCCESS; -} - -static VOID PhpInitializeServiceNumbers( - VOID - ) -{ - if (PhBeginInitOnce(&ServiceNumbersInitOnce)) - { - NTSTATUS status; - HANDLE eventHandle; - HANDLE threadHandle; - HANDLE pipeReadHandle; - HANDLE pipeWriteHandle; - - // The ThreadLastSystemCall info class only works when the thread is in the Waiting - // state. We'll create a thread which blocks on an event object we create, then wait - // until it is in the Waiting state. Only then can we query the thread using - // ThreadLastSystemCall. - - // NtWaitForSingleObject - - status = NtCreateEvent(&eventHandle, EVENT_ALL_ACCESS, NULL, NotificationEvent, FALSE); - - if (NT_SUCCESS(status)) - { - if (threadHandle = PhCreateThread(0, PhpWfsoThreadStart, eventHandle)) - { - if (PhpWaitUntilThreadIsWaiting(threadHandle)) - { - PhpGetThreadLastSystemCallNumber(threadHandle, &NumberForWfso); - } - - // Allow the thread to exit. - NtSetEvent(eventHandle, NULL); - NtClose(threadHandle); - } - - NtClose(eventHandle); - } - - // NtWaitForMultipleObjects - - status = NtCreateEvent(&eventHandle, EVENT_ALL_ACCESS, NULL, NotificationEvent, FALSE); - - if (NT_SUCCESS(status)) - { - if (threadHandle = PhCreateThread(0, PhpWfmoThreadStart, eventHandle)) - { - if (PhpWaitUntilThreadIsWaiting(threadHandle)) - { - PhpGetThreadLastSystemCallNumber(threadHandle, &NumberForWfmo); - } - - NtSetEvent(eventHandle, NULL); - NtClose(threadHandle); - } - - NtClose(eventHandle); - } - - // NtReadFile - - if (CreatePipe(&pipeReadHandle, &pipeWriteHandle, NULL, 0)) - { - if (threadHandle = PhCreateThread(0, PhpRfThreadStart, pipeReadHandle)) - { - ULONG data = 0; - IO_STATUS_BLOCK isb; - - if (PhpWaitUntilThreadIsWaiting(threadHandle)) - { - PhpGetThreadLastSystemCallNumber(threadHandle, &NumberForRf); - } - - NtWriteFile(pipeWriteHandle, NULL, NULL, NULL, &isb, &data, sizeof(data), NULL, NULL); - NtClose(threadHandle); - } - - NtClose(pipeReadHandle); - NtClose(pipeWriteHandle); - } - - PhEndInitOnce(&ServiceNumbersInitOnce); - } -} - -static PPH_STRING PhpaGetHandleString( - _In_ HANDLE ProcessHandle, - _In_ HANDLE Handle - ) -{ - PPH_STRING typeName = NULL; - PPH_STRING name = NULL; - PPH_STRING result; - - PhGetHandleInformation( - ProcessHandle, - Handle, - -1, - NULL, - &typeName, - NULL, - &name - ); - PH_AUTO(typeName); - PH_AUTO(name); - - if (typeName && name) - { - result = PhaFormatString( - L"Handle 0x%Ix (%s): %s", - Handle, - typeName->Buffer, - !PhIsNullOrEmptyString(name) ? name->Buffer : L"(unnamed object)" - ); - } - else - { - result = PhaFormatString( - L"Handle 0x%Ix: (error querying handle)", - Handle - ); - } - - return result; -} - -static VOID PhpGetWfmoInformation( - _In_ HANDLE ProcessHandle, - _In_ BOOLEAN IsWow64, - _In_ ULONG NumberOfHandles, - _In_ PHANDLE AddressOfHandles, - _In_ WAIT_TYPE WaitType, - _In_ BOOLEAN Alertable, - _Inout_ PPH_STRING_BUILDER StringBuilder - ) -{ - NTSTATUS status; - HANDLE handles[MAXIMUM_WAIT_OBJECTS]; - ULONG i; - - status = STATUS_SUCCESS; - - if (NumberOfHandles <= MAXIMUM_WAIT_OBJECTS) - { -#ifdef _WIN64 - if (IsWow64) - { - ULONG handles32[MAXIMUM_WAIT_OBJECTS]; - - if (NT_SUCCESS(status = NtReadVirtualMemory( - ProcessHandle, - AddressOfHandles, - handles32, - NumberOfHandles * sizeof(ULONG), - NULL - ))) - { - for (i = 0; i < NumberOfHandles; i++) - handles[i] = UlongToHandle(handles32[i]); - } - } - else - { -#endif - status = NtReadVirtualMemory( - ProcessHandle, - AddressOfHandles, - handles, - NumberOfHandles * sizeof(HANDLE), - NULL - ); -#ifdef _WIN64 - } -#endif - - if (NT_SUCCESS(status)) - { - PhAppendFormatStringBuilder( - StringBuilder, - L"Thread is waiting (%s, %s) for:\r\n", - Alertable ? L"alertable" : L"non-alertable", - WaitType == WaitAll ? L"wait all" : L"wait any" - ); - - for (i = 0; i < NumberOfHandles; i++) - { - PhAppendStringBuilder( - StringBuilder, - &PhpaGetHandleString(ProcessHandle, handles[i])->sr - ); - PhAppendStringBuilder2( - StringBuilder, - L"\r\n" - ); - } - } - } - - if (!NT_SUCCESS(status) || NumberOfHandles > MAXIMUM_WAIT_OBJECTS) - { - PhAppendStringBuilder2( - StringBuilder, - L"Thread is waiting for multiple objects." - ); - } -} - -static PPH_STRING PhpaGetSendMessageReceiver( - _In_ HANDLE ThreadId - ) -{ - static _GetSendMessageReceiver GetSendMessageReceiver_I; - - HWND windowHandle; - ULONG threadId; - ULONG processId; - CLIENT_ID clientId; - PPH_STRING clientIdName; - WCHAR windowClass[64]; - PPH_STRING windowText; - - // GetSendMessageReceiver is an undocumented function exported by - // user32.dll. It retrieves the handle of the window which a thread - // is sending a message to. - - if (!GetSendMessageReceiver_I) - GetSendMessageReceiver_I = PhGetModuleProcAddress(L"user32.dll", "GetSendMessageReceiver"); - - if (!GetSendMessageReceiver_I) - return NULL; - - windowHandle = GetSendMessageReceiver_I(ThreadId); - - if (!windowHandle) - return NULL; - - threadId = GetWindowThreadProcessId(windowHandle, &processId); - - clientId.UniqueProcess = UlongToHandle(processId); - clientId.UniqueThread = UlongToHandle(threadId); - clientIdName = PH_AUTO(PhGetClientIdName(&clientId)); - - if (!GetClassName(windowHandle, windowClass, sizeof(windowClass) / sizeof(WCHAR))) - windowClass[0] = 0; - - windowText = PH_AUTO(PhGetWindowText(windowHandle)); - - return PhaFormatString(L"Window 0x%Ix (%s): %s \"%s\"", windowHandle, clientIdName->Buffer, windowClass, PhGetStringOrEmpty(windowText)); -} - -static PPH_STRING PhpaGetAlpcInformation( - _In_ HANDLE ThreadId - ) -{ - static _NtAlpcQueryInformation NtAlpcQueryInformation_I; - - NTSTATUS status; - PPH_STRING string = NULL; - HANDLE threadHandle; - PALPC_SERVER_INFORMATION serverInfo; - ULONG bufferLength; - - if (!NtAlpcQueryInformation_I) - NtAlpcQueryInformation_I = PhGetModuleProcAddress(L"ntdll.dll", "NtAlpcQueryInformation"); - - if (!NtAlpcQueryInformation_I) - return NULL; - - if (!NT_SUCCESS(PhOpenThread(&threadHandle, THREAD_QUERY_INFORMATION, ThreadId))) - return NULL; - - bufferLength = 0x110; - serverInfo = PhAllocate(bufferLength); - serverInfo->In.ThreadHandle = threadHandle; - - status = NtAlpcQueryInformation_I(NULL, AlpcServerInformation, serverInfo, bufferLength, &bufferLength); - - if (status == STATUS_INFO_LENGTH_MISMATCH) - { - PhFree(serverInfo); - serverInfo = PhAllocate(bufferLength); - serverInfo->In.ThreadHandle = threadHandle; - - status = NtAlpcQueryInformation_I(NULL, AlpcServerInformation, serverInfo, bufferLength, &bufferLength); - } - - if (NT_SUCCESS(status) && serverInfo->Out.ThreadBlocked) - { - CLIENT_ID clientId; - PPH_STRING clientIdName; - - clientId.UniqueProcess = serverInfo->Out.ConnectedProcessId; - clientId.UniqueThread = NULL; - clientIdName = PH_AUTO(PhGetClientIdName(&clientId)); - - string = PhaFormatString(L"ALPC Port: %.*s (%s)", serverInfo->Out.ConnectionPortName.Length / 2, serverInfo->Out.ConnectionPortName.Buffer, clientIdName->Buffer); - } - - PhFree(serverInfo); - NtClose(threadHandle); - - return string; -} +/* + * Process Hacker - + * thread wait analysis + * + * Copyright (C) 2010-2011 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +/* + * There are two ways of seeing what a thread is waiting on. The first method + * is to walk the stack of a thread and read the arguments to whatever system + * call it is blocking on; this only works on x86 because on x64 the arguments + * are passed in registers (at least the first four are). The second method + * involves using the ThreadLastSystemCall info class for NtQueryInformationThread + * to retrieve the first argument to the system call the thread is blocking on. + * This is obviously only useful for NtWaitForSingleObject. + * + * There are other methods for specific scenarios, like USER messages and ALPC + * calls. + */ + +#include + +#include +#include + +#include + +typedef HWND (WINAPI *_GetSendMessageReceiver)( + _In_ HANDLE ThreadId + ); + +typedef NTSTATUS (NTAPI *_NtAlpcQueryInformation)( + _In_ HANDLE PortHandle, + _In_ ALPC_PORT_INFORMATION_CLASS PortInformationClass, + _Out_writes_bytes_(Length) PVOID PortInformation, + _In_ ULONG Length, + _Out_opt_ PULONG ReturnLength + ); + +typedef struct _ANALYZE_WAIT_CONTEXT +{ + BOOLEAN Found; + BOOLEAN IsWow64; + HANDLE ProcessId; + HANDLE ThreadId; + HANDLE ProcessHandle; + + PPH_SYMBOL_PROVIDER SymbolProvider; + PH_STRING_BUILDER StringBuilder; + + PVOID PrevParams[4]; +} ANALYZE_WAIT_CONTEXT, *PANALYZE_WAIT_CONTEXT; + +VOID PhpAnalyzeWaitPassive( + _In_ HWND hWnd, + _In_ HANDLE ProcessId, + _In_ HANDLE ThreadId + ); + +BOOLEAN NTAPI PhpWalkThreadStackAnalyzeCallback( + _In_ PPH_THREAD_STACK_FRAME StackFrame, + _In_opt_ PVOID Context + ); + +VOID PhpAnalyzeWaitFallbacks( + _In_ PANALYZE_WAIT_CONTEXT Context + ); + +VOID PhpInitializeServiceNumbers( + VOID + ); + +PPH_STRING PhpaGetHandleString( + _In_ HANDLE ProcessHandle, + _In_ HANDLE Handle + ); + +VOID PhpGetWfmoInformation( + _In_ HANDLE ProcessHandle, + _In_ BOOLEAN IsWow64, + _In_ ULONG NumberOfHandles, + _In_ PHANDLE AddressOfHandles, + _In_ WAIT_TYPE WaitType, + _In_ BOOLEAN Alertable, + _Inout_ PPH_STRING_BUILDER StringBuilder + ); + +PPH_STRING PhpaGetSendMessageReceiver( + _In_ HANDLE ThreadId + ); + +PPH_STRING PhpaGetAlpcInformation( + _In_ HANDLE ThreadId + ); + +static PH_INITONCE ServiceNumbersInitOnce = PH_INITONCE_INIT; +static USHORT NumberForWfso = -1; +static USHORT NumberForWfmo = -1; +static USHORT NumberForRf = -1; + +VOID PhUiAnalyzeWaitThread( + _In_ HWND hWnd, + _In_ HANDLE ProcessId, + _In_ HANDLE ThreadId, + _In_ PPH_SYMBOL_PROVIDER SymbolProvider + ) +{ + NTSTATUS status; + HANDLE threadHandle; +#ifdef _WIN64 + HANDLE processHandle; + BOOLEAN isWow64; +#endif + CLIENT_ID clientId; + ANALYZE_WAIT_CONTEXT context; + +#ifdef _WIN64 + // Determine if the process is WOW64. If not, we use the passive method. + + if (!NT_SUCCESS(status = PhOpenProcess(&processHandle, ProcessQueryAccess, ProcessId))) + { + PhShowStatus(hWnd, L"Unable to open the process", status, 0); + return; + } + + if (!NT_SUCCESS(status = PhGetProcessIsWow64(processHandle, &isWow64)) || !isWow64) + { + PhpAnalyzeWaitPassive(hWnd, ProcessId, ThreadId); + return; + } + + NtClose(processHandle); +#endif + + if (!NT_SUCCESS(status = PhOpenThread( + &threadHandle, + ThreadQueryAccess | THREAD_GET_CONTEXT | THREAD_SUSPEND_RESUME, + ThreadId + ))) + { + PhShowStatus(hWnd, L"Unable to open the thread", status, 0); + return; + } + + context.ProcessId = ProcessId; + context.ThreadId = ThreadId; + + context.ProcessHandle = SymbolProvider->ProcessHandle; + context.SymbolProvider = SymbolProvider; + PhInitializeStringBuilder(&context.StringBuilder, 100); + + clientId.UniqueProcess = ProcessId; + clientId.UniqueThread = ThreadId; + + PhWalkThreadStack( + threadHandle, + SymbolProvider->ProcessHandle, + &clientId, + SymbolProvider, + PH_WALK_I386_STACK, + PhpWalkThreadStackAnalyzeCallback, + &context + ); + NtClose(threadHandle); + + PhpAnalyzeWaitFallbacks(&context); + + if (context.Found) + { + PhShowInformationDialog(hWnd, context.StringBuilder.String->Buffer, 0); + } + else + { + PhShowInformation(hWnd, L"The thread does not appear to be waiting."); + } + + PhDeleteStringBuilder(&context.StringBuilder); +} + +VOID PhpAnalyzeWaitPassive( + _In_ HWND hWnd, + _In_ HANDLE ProcessId, + _In_ HANDLE ThreadId + ) +{ + NTSTATUS status; + HANDLE processHandle; + HANDLE threadHandle; + THREAD_LAST_SYSCALL_INFORMATION lastSystemCall; + PH_STRING_BUILDER stringBuilder; + PPH_STRING string; + + PhpInitializeServiceNumbers(); + + if (!NT_SUCCESS(status = PhOpenThread(&threadHandle, THREAD_GET_CONTEXT, ThreadId))) + { + PhShowStatus(hWnd, L"Unable to open the thread", status, 0); + return; + } + + if (!NT_SUCCESS(status = NtQueryInformationThread( + threadHandle, + ThreadLastSystemCall, + &lastSystemCall, + sizeof(THREAD_LAST_SYSCALL_INFORMATION), + NULL + ))) + { + NtClose(threadHandle); + PhShowInformation(hWnd, L"Unable to determine whether the thread is waiting."); + return; + } + + if (!NT_SUCCESS(status = PhOpenProcess(&processHandle, PROCESS_DUP_HANDLE, ProcessId))) + { + NtClose(threadHandle); + PhShowStatus(hWnd, L"Unable to open the process", status, 0); + return; + } + + PhInitializeStringBuilder(&stringBuilder, 100); + + if (lastSystemCall.SystemCallNumber == NumberForWfso) + { + string = PhpaGetHandleString(processHandle, lastSystemCall.FirstArgument); + + PhAppendFormatStringBuilder(&stringBuilder, L"Thread is waiting for:\r\n"); + PhAppendStringBuilder(&stringBuilder, &string->sr); + } + else if (lastSystemCall.SystemCallNumber == NumberForWfmo) + { + PhAppendFormatStringBuilder(&stringBuilder, L"Thread is waiting for multiple (%u) objects.", PtrToUlong(lastSystemCall.FirstArgument)); + } + else if (lastSystemCall.SystemCallNumber == NumberForRf) + { + string = PhpaGetHandleString(processHandle, lastSystemCall.FirstArgument); + + PhAppendFormatStringBuilder(&stringBuilder, L"Thread is waiting for file I/O:\r\n"); + PhAppendStringBuilder(&stringBuilder, &string->sr); + } + else + { + string = PhpaGetSendMessageReceiver(ThreadId); + + if (string) + { + PhAppendStringBuilder2(&stringBuilder, L"Thread is sending a USER message:\r\n"); + PhAppendStringBuilder(&stringBuilder, &string->sr); + } + else + { + string = PhpaGetAlpcInformation(ThreadId); + + if (string) + { + PhAppendStringBuilder2(&stringBuilder, L"Thread is waiting for an ALPC port:\r\n"); + PhAppendStringBuilder(&stringBuilder, &string->sr); + } + } + } + + if (stringBuilder.String->Length == 0) + PhAppendStringBuilder2(&stringBuilder, L"Unable to determine why the thread is waiting."); + + PhShowInformationDialog(hWnd, stringBuilder.String->Buffer, 0); + + PhDeleteStringBuilder(&stringBuilder); + NtClose(processHandle); + NtClose(threadHandle); +} + +static BOOLEAN NTAPI PhpWalkThreadStackAnalyzeCallback( + _In_ PPH_THREAD_STACK_FRAME StackFrame, + _In_opt_ PVOID Context + ) +{ + PANALYZE_WAIT_CONTEXT context = (PANALYZE_WAIT_CONTEXT)Context; + PPH_STRING name; + + name = PhGetSymbolFromAddress( + context->SymbolProvider, + (ULONG64)StackFrame->PcAddress, + NULL, + NULL, + NULL, + NULL + ); + + if (!name) + return TRUE; + + context->Found = TRUE; + +#define FUNC_MATCH(Name) PhStartsWithString2(name, L##Name, TRUE) +#define NT_FUNC_MATCH(Name) ( \ + PhStartsWithString2(name, L"ntdll.dll!Nt" L##Name, TRUE) || \ + PhStartsWithString2(name, L"ntdll.dll!Zw" L##Name, TRUE) \ + ) + + if (!name) + { + // Dummy + } + else if (FUNC_MATCH("kernel32.dll!Sleep")) + { + PhAppendFormatStringBuilder( + &context->StringBuilder, + L"Thread is sleeping. Timeout: %u milliseconds.", + PtrToUlong(StackFrame->Params[0]) + ); + } + else if (NT_FUNC_MATCH("DelayExecution")) + { + BOOLEAN alertable = !!StackFrame->Params[0]; + PVOID timeoutAddress = StackFrame->Params[1]; + LARGE_INTEGER timeout; + + if (NT_SUCCESS(NtReadVirtualMemory( + context->ProcessHandle, + timeoutAddress, + &timeout, + sizeof(LARGE_INTEGER), + NULL + ))) + { + if (timeout.QuadPart < 0) + { + PhAppendFormatStringBuilder( + &context->StringBuilder, + L"Thread is sleeping. Timeout: %I64u milliseconds.", + -timeout.QuadPart / PH_TIMEOUT_MS + ); + } + else + { + // TODO + } + } + else + { + PhAppendStringBuilder2( + &context->StringBuilder, + L"Thread is sleeping." + ); + } + } + else if (NT_FUNC_MATCH("DeviceIoControlFile")) + { + HANDLE handle = (HANDLE)StackFrame->Params[0]; + + PhAppendStringBuilder2( + &context->StringBuilder, + L"Thread is waiting for an I/O control request:\r\n" + ); + PhAppendStringBuilder( + &context->StringBuilder, + &PhpaGetHandleString(context->ProcessHandle, handle)->sr + ); + } + else if (NT_FUNC_MATCH("FsControlFile")) + { + HANDLE handle = StackFrame->Params[0]; + + PhAppendStringBuilder2( + &context->StringBuilder, + L"Thread is waiting for a FS control request:\r\n" + ); + PhAppendStringBuilder( + &context->StringBuilder, + &PhpaGetHandleString(context->ProcessHandle, handle)->sr + ); + } + else if (NT_FUNC_MATCH("QueryObject")) + { + HANDLE handle = StackFrame->Params[0]; + + // Use the KiFastSystemCall args if the handle we have is wrong. + if ((ULONG_PTR)handle % 4 != 0 || !handle) + handle = context->PrevParams[1]; + + PhAppendStringBuilder2( + &context->StringBuilder, + L"Thread is querying an object:\r\n" + ); + PhAppendStringBuilder( + &context->StringBuilder, + &PhpaGetHandleString(context->ProcessHandle, handle)->sr + ); + } + else if (NT_FUNC_MATCH("ReadFile") || NT_FUNC_MATCH("WriteFile")) + { + HANDLE handle = StackFrame->Params[0]; + + PhAppendStringBuilder2( + &context->StringBuilder, + L"Thread is waiting for file I/O:\r\n" + ); + PhAppendStringBuilder( + &context->StringBuilder, + &PhpaGetHandleString(context->ProcessHandle, handle)->sr + ); + } + else if (NT_FUNC_MATCH("RemoveIoCompletion")) + { + HANDLE handle = StackFrame->Params[0]; + + PhAppendStringBuilder2( + &context->StringBuilder, + L"Thread is waiting for an I/O completion port:\r\n" + ); + PhAppendStringBuilder( + &context->StringBuilder, + &PhpaGetHandleString(context->ProcessHandle, handle)->sr + ); + } + else if ( + NT_FUNC_MATCH("ReplyWaitReceivePort") || + NT_FUNC_MATCH("RequestWaitReplyPort") || + NT_FUNC_MATCH("AlpcSendWaitReceivePort") + ) + { + HANDLE handle = StackFrame->Params[0]; + PPH_STRING alpcInfo; + + PhAppendStringBuilder2( + &context->StringBuilder, + WindowsVersion >= WINDOWS_VISTA ? L"Thread is waiting for an ALPC port:\r\n" : L"Thread is waiting for a LPC port:\r\n" + ); + PhAppendStringBuilder( + &context->StringBuilder, + &PhpaGetHandleString(context->ProcessHandle, handle)->sr + ); + + if (alpcInfo = PhpaGetAlpcInformation(context->ThreadId)) + { + PhAppendStringBuilder2( + &context->StringBuilder, + L"\r\n" + ); + PhAppendStringBuilder( + &context->StringBuilder, + &alpcInfo->sr + ); + } + } + else if ( + NT_FUNC_MATCH("SetHighWaitLowEventPair") || + NT_FUNC_MATCH("SetLowWaitHighEventPair") || + NT_FUNC_MATCH("WaitHighEventPair") || + NT_FUNC_MATCH("WaitLowEventPair") + ) + { + HANDLE handle = StackFrame->Params[0]; + + if ((ULONG_PTR)handle % 4 != 0 || !handle) + handle = context->PrevParams[1]; + + PhAppendFormatStringBuilder( + &context->StringBuilder, + L"Thread is waiting (%s) for an event pair:\r\n", + name->Buffer + ); + PhAppendStringBuilder( + &context->StringBuilder, + &PhpaGetHandleString(context->ProcessHandle, handle)->sr + ); + } + else if ( + FUNC_MATCH("user32.dll!NtUserGetMessage") || + FUNC_MATCH("user32.dll!NtUserWaitMessage") + ) + { + PhAppendStringBuilder2( + &context->StringBuilder, + L"Thread is waiting for a USER message.\r\n" + ); + } + else if (FUNC_MATCH("user32.dll!NtUserMessageCall")) + { + PPH_STRING receiverString; + + PhAppendStringBuilder2( + &context->StringBuilder, + L"Thread is sending a USER message:\r\n" + ); + + receiverString = PhpaGetSendMessageReceiver(context->ThreadId); + + if (receiverString) + { + PhAppendStringBuilder(&context->StringBuilder, &receiverString->sr); + PhAppendStringBuilder2(&context->StringBuilder, L"\r\n"); + } + else + { + PhAppendStringBuilder2(&context->StringBuilder, L"Unknown.\r\n"); + } + } + else if (NT_FUNC_MATCH("WaitForDebugEvent")) + { + HANDLE handle = StackFrame->Params[0]; + + PhAppendStringBuilder2( + &context->StringBuilder, + L"Thread is waiting for a debug event:\r\n" + ); + PhAppendStringBuilder( + &context->StringBuilder, + &PhpaGetHandleString(context->ProcessHandle, handle)->sr + ); + } + else if ( + NT_FUNC_MATCH("WaitForKeyedEvent") || + NT_FUNC_MATCH("ReleaseKeyedEvent") + ) + { + HANDLE handle = StackFrame->Params[0]; + PVOID key = StackFrame->Params[1]; + + PhAppendFormatStringBuilder( + &context->StringBuilder, + L"Thread is waiting (%s) for a keyed event (key 0x%Ix):\r\n", + name->Buffer, + key + ); + PhAppendStringBuilder( + &context->StringBuilder, + &PhpaGetHandleString(context->ProcessHandle, handle)->sr + ); + } + else if ( + NT_FUNC_MATCH("WaitForMultipleObjects") || + FUNC_MATCH("kernel32.dll!WaitForMultipleObjects") + ) + { + ULONG numberOfHandles = PtrToUlong(StackFrame->Params[0]); + PVOID addressOfHandles = StackFrame->Params[1]; + WAIT_TYPE waitType = (WAIT_TYPE)StackFrame->Params[2]; + BOOLEAN alertable = !!StackFrame->Params[3]; + + if (numberOfHandles > MAXIMUM_WAIT_OBJECTS) + { + numberOfHandles = PtrToUlong(context->PrevParams[1]); + addressOfHandles = context->PrevParams[2]; + waitType = (WAIT_TYPE)context->PrevParams[3]; + alertable = FALSE; + } + + PhpGetWfmoInformation( + context->ProcessHandle, + TRUE, // on x64 this function is only called for WOW64 processes + numberOfHandles, + addressOfHandles, + waitType, + alertable, + &context->StringBuilder + ); + } + else if ( + NT_FUNC_MATCH("WaitForSingleObject") || + FUNC_MATCH("kernel32.dll!WaitForSingleObject") + ) + { + HANDLE handle = StackFrame->Params[0]; + BOOLEAN alertable = !!StackFrame->Params[1]; + + if ((ULONG_PTR)handle % 4 != 0 || !handle) + { + handle = context->PrevParams[1]; + alertable = !!context->PrevParams[2]; + } + + PhAppendFormatStringBuilder( + &context->StringBuilder, + L"Thread is waiting (%s) for:\r\n", + alertable ? L"alertable" : L"non-alertable" + ); + PhAppendStringBuilder( + &context->StringBuilder, + &PhpaGetHandleString(context->ProcessHandle, handle)->sr + ); + } + else if (NT_FUNC_MATCH("WaitForWorkViaWorkerFactory")) + { + HANDLE handle = StackFrame->Params[0]; + + PhAppendStringBuilder2( + &context->StringBuilder, + L"Thread is waiting for work from a worker factory:\r\n" + ); + PhAppendStringBuilder( + &context->StringBuilder, + &PhpaGetHandleString(context->ProcessHandle, handle)->sr + ); + } + else + { + context->Found = FALSE; + } + + PhDereferenceObject(name); + memcpy(&context->PrevParams, StackFrame->Params, sizeof(StackFrame->Params)); + + return !context->Found; +} + +static VOID PhpAnalyzeWaitFallbacks( + _In_ PANALYZE_WAIT_CONTEXT Context + ) +{ + PPH_STRING info; + + // We didn't detect NtUserMessageCall, but this may still apply due to another + // win32k system call (e.g. from EnableWindow). + if (!Context->Found && (info = PhpaGetSendMessageReceiver(Context->ThreadId))) + { + PhAppendStringBuilder2( + &Context->StringBuilder, + L"Thread is sending a USER message:\r\n" + ); + PhAppendStringBuilder(&Context->StringBuilder, &info->sr); + PhAppendStringBuilder2(&Context->StringBuilder, L"\r\n"); + + Context->Found = TRUE; + } + + // Nt(Alpc)ConnectPort doesn't get detected anywhere else. + if (!Context->Found && (info = PhpaGetAlpcInformation(Context->ThreadId))) + { + PhAppendStringBuilder2( + &Context->StringBuilder, + L"Thread is waiting for an ALPC port:\r\n" + ); + PhAppendStringBuilder(&Context->StringBuilder, &info->sr); + PhAppendStringBuilder2(&Context->StringBuilder, L"\r\n"); + + Context->Found = TRUE; + } +} + +static BOOLEAN PhpWaitUntilThreadIsWaiting( + _In_ HANDLE ThreadHandle + ) +{ + ULONG attempts; + BOOLEAN isWaiting = FALSE; + THREAD_BASIC_INFORMATION basicInfo; + + if (!NT_SUCCESS(PhGetThreadBasicInformation(ThreadHandle, &basicInfo))) + return FALSE; + + for (attempts = 0; attempts < 5; attempts++) + { + PVOID processes; + PSYSTEM_PROCESS_INFORMATION processInfo; + ULONG i; + LARGE_INTEGER interval; + + interval.QuadPart = -100 * PH_TIMEOUT_MS; + NtDelayExecution(FALSE, &interval); + + if (!NT_SUCCESS(PhEnumProcesses(&processes))) + break; + + processInfo = PhFindProcessInformation(processes, basicInfo.ClientId.UniqueProcess); + + if (processInfo) + { + for (i = 0; i < processInfo->NumberOfThreads; i++) + { + if ( + processInfo->Threads[i].ClientId.UniqueThread == basicInfo.ClientId.UniqueThread && + processInfo->Threads[i].ThreadState == Waiting && + (processInfo->Threads[i].WaitReason == UserRequest || + processInfo->Threads[i].WaitReason == Executive) + ) + { + isWaiting = TRUE; + break; + } + } + } + + PhFree(processes); + + if (isWaiting) + break; + + interval.QuadPart = -500 * PH_TIMEOUT_MS; + NtDelayExecution(FALSE, &interval); + } + + return isWaiting; +} + +static VOID PhpGetThreadLastSystemCallNumber( + _In_ HANDLE ThreadHandle, + _Out_ PUSHORT LastSystemCallNumber + ) +{ + THREAD_LAST_SYSCALL_INFORMATION lastSystemCall; + + if (NT_SUCCESS(NtQueryInformationThread( + ThreadHandle, + ThreadLastSystemCall, + &lastSystemCall, + sizeof(THREAD_LAST_SYSCALL_INFORMATION), + NULL + ))) + { + *LastSystemCallNumber = lastSystemCall.SystemCallNumber; + } +} + +static NTSTATUS PhpWfsoThreadStart( + _In_ PVOID Parameter + ) +{ + HANDLE eventHandle; + LARGE_INTEGER timeout; + + eventHandle = Parameter; + + timeout.QuadPart = -5 * PH_TIMEOUT_SEC; + NtWaitForSingleObject(eventHandle, FALSE, &timeout); + + return STATUS_SUCCESS; +} + +static NTSTATUS PhpWfmoThreadStart( + _In_ PVOID Parameter + ) +{ + HANDLE eventHandle; + LARGE_INTEGER timeout; + + eventHandle = Parameter; + + timeout.QuadPart = -5 * PH_TIMEOUT_SEC; + NtWaitForMultipleObjects(1, &eventHandle, WaitAll, FALSE, &timeout); + + return STATUS_SUCCESS; +} + +static NTSTATUS PhpRfThreadStart( + _In_ PVOID Parameter + ) +{ + HANDLE fileHandle; + IO_STATUS_BLOCK isb; + ULONG data; + + fileHandle = Parameter; + + NtReadFile(fileHandle, NULL, NULL, NULL, &isb, &data, sizeof(ULONG), NULL, NULL); + + return STATUS_SUCCESS; +} + +static VOID PhpInitializeServiceNumbers( + VOID + ) +{ + if (PhBeginInitOnce(&ServiceNumbersInitOnce)) + { + NTSTATUS status; + HANDLE eventHandle; + HANDLE threadHandle; + HANDLE pipeReadHandle; + HANDLE pipeWriteHandle; + + // The ThreadLastSystemCall info class only works when the thread is in the Waiting + // state. We'll create a thread which blocks on an event object we create, then wait + // until it is in the Waiting state. Only then can we query the thread using + // ThreadLastSystemCall. + + // NtWaitForSingleObject + + status = NtCreateEvent(&eventHandle, EVENT_ALL_ACCESS, NULL, NotificationEvent, FALSE); + + if (NT_SUCCESS(status)) + { + if (threadHandle = PhCreateThread(0, PhpWfsoThreadStart, eventHandle)) + { + if (PhpWaitUntilThreadIsWaiting(threadHandle)) + { + PhpGetThreadLastSystemCallNumber(threadHandle, &NumberForWfso); + } + + // Allow the thread to exit. + NtSetEvent(eventHandle, NULL); + NtClose(threadHandle); + } + + NtClose(eventHandle); + } + + // NtWaitForMultipleObjects + + status = NtCreateEvent(&eventHandle, EVENT_ALL_ACCESS, NULL, NotificationEvent, FALSE); + + if (NT_SUCCESS(status)) + { + if (threadHandle = PhCreateThread(0, PhpWfmoThreadStart, eventHandle)) + { + if (PhpWaitUntilThreadIsWaiting(threadHandle)) + { + PhpGetThreadLastSystemCallNumber(threadHandle, &NumberForWfmo); + } + + NtSetEvent(eventHandle, NULL); + NtClose(threadHandle); + } + + NtClose(eventHandle); + } + + // NtReadFile + + if (CreatePipe(&pipeReadHandle, &pipeWriteHandle, NULL, 0)) + { + if (threadHandle = PhCreateThread(0, PhpRfThreadStart, pipeReadHandle)) + { + ULONG data = 0; + IO_STATUS_BLOCK isb; + + if (PhpWaitUntilThreadIsWaiting(threadHandle)) + { + PhpGetThreadLastSystemCallNumber(threadHandle, &NumberForRf); + } + + NtWriteFile(pipeWriteHandle, NULL, NULL, NULL, &isb, &data, sizeof(data), NULL, NULL); + NtClose(threadHandle); + } + + NtClose(pipeReadHandle); + NtClose(pipeWriteHandle); + } + + PhEndInitOnce(&ServiceNumbersInitOnce); + } +} + +static PPH_STRING PhpaGetHandleString( + _In_ HANDLE ProcessHandle, + _In_ HANDLE Handle + ) +{ + PPH_STRING typeName = NULL; + PPH_STRING name = NULL; + PPH_STRING result; + + PhGetHandleInformation( + ProcessHandle, + Handle, + -1, + NULL, + &typeName, + NULL, + &name + ); + PH_AUTO(typeName); + PH_AUTO(name); + + if (typeName && name) + { + result = PhaFormatString( + L"Handle 0x%Ix (%s): %s", + Handle, + typeName->Buffer, + !PhIsNullOrEmptyString(name) ? name->Buffer : L"(unnamed object)" + ); + } + else + { + result = PhaFormatString( + L"Handle 0x%Ix: (error querying handle)", + Handle + ); + } + + return result; +} + +static VOID PhpGetWfmoInformation( + _In_ HANDLE ProcessHandle, + _In_ BOOLEAN IsWow64, + _In_ ULONG NumberOfHandles, + _In_ PHANDLE AddressOfHandles, + _In_ WAIT_TYPE WaitType, + _In_ BOOLEAN Alertable, + _Inout_ PPH_STRING_BUILDER StringBuilder + ) +{ + NTSTATUS status; + HANDLE handles[MAXIMUM_WAIT_OBJECTS]; + ULONG i; + + status = STATUS_SUCCESS; + + if (NumberOfHandles <= MAXIMUM_WAIT_OBJECTS) + { +#ifdef _WIN64 + if (IsWow64) + { + ULONG handles32[MAXIMUM_WAIT_OBJECTS]; + + if (NT_SUCCESS(status = NtReadVirtualMemory( + ProcessHandle, + AddressOfHandles, + handles32, + NumberOfHandles * sizeof(ULONG), + NULL + ))) + { + for (i = 0; i < NumberOfHandles; i++) + handles[i] = UlongToHandle(handles32[i]); + } + } + else + { +#endif + status = NtReadVirtualMemory( + ProcessHandle, + AddressOfHandles, + handles, + NumberOfHandles * sizeof(HANDLE), + NULL + ); +#ifdef _WIN64 + } +#endif + + if (NT_SUCCESS(status)) + { + PhAppendFormatStringBuilder( + StringBuilder, + L"Thread is waiting (%s, %s) for:\r\n", + Alertable ? L"alertable" : L"non-alertable", + WaitType == WaitAll ? L"wait all" : L"wait any" + ); + + for (i = 0; i < NumberOfHandles; i++) + { + PhAppendStringBuilder( + StringBuilder, + &PhpaGetHandleString(ProcessHandle, handles[i])->sr + ); + PhAppendStringBuilder2( + StringBuilder, + L"\r\n" + ); + } + } + } + + if (!NT_SUCCESS(status) || NumberOfHandles > MAXIMUM_WAIT_OBJECTS) + { + PhAppendStringBuilder2( + StringBuilder, + L"Thread is waiting for multiple objects." + ); + } +} + +static PPH_STRING PhpaGetSendMessageReceiver( + _In_ HANDLE ThreadId + ) +{ + static _GetSendMessageReceiver GetSendMessageReceiver_I; + + HWND windowHandle; + ULONG threadId; + ULONG processId; + CLIENT_ID clientId; + PPH_STRING clientIdName; + WCHAR windowClass[64]; + PPH_STRING windowText; + + // GetSendMessageReceiver is an undocumented function exported by + // user32.dll. It retrieves the handle of the window which a thread + // is sending a message to. + + if (!GetSendMessageReceiver_I) + GetSendMessageReceiver_I = PhGetModuleProcAddress(L"user32.dll", "GetSendMessageReceiver"); + + if (!GetSendMessageReceiver_I) + return NULL; + + windowHandle = GetSendMessageReceiver_I(ThreadId); + + if (!windowHandle) + return NULL; + + threadId = GetWindowThreadProcessId(windowHandle, &processId); + + clientId.UniqueProcess = UlongToHandle(processId); + clientId.UniqueThread = UlongToHandle(threadId); + clientIdName = PH_AUTO(PhGetClientIdName(&clientId)); + + if (!GetClassName(windowHandle, windowClass, sizeof(windowClass) / sizeof(WCHAR))) + windowClass[0] = 0; + + windowText = PH_AUTO(PhGetWindowText(windowHandle)); + + return PhaFormatString(L"Window 0x%Ix (%s): %s \"%s\"", windowHandle, clientIdName->Buffer, windowClass, PhGetStringOrEmpty(windowText)); +} + +static PPH_STRING PhpaGetAlpcInformation( + _In_ HANDLE ThreadId + ) +{ + static _NtAlpcQueryInformation NtAlpcQueryInformation_I; + + NTSTATUS status; + PPH_STRING string = NULL; + HANDLE threadHandle; + PALPC_SERVER_INFORMATION serverInfo; + ULONG bufferLength; + + if (!NtAlpcQueryInformation_I) + NtAlpcQueryInformation_I = PhGetModuleProcAddress(L"ntdll.dll", "NtAlpcQueryInformation"); + + if (!NtAlpcQueryInformation_I) + return NULL; + + if (!NT_SUCCESS(PhOpenThread(&threadHandle, THREAD_QUERY_INFORMATION, ThreadId))) + return NULL; + + bufferLength = 0x110; + serverInfo = PhAllocate(bufferLength); + serverInfo->In.ThreadHandle = threadHandle; + + status = NtAlpcQueryInformation_I(NULL, AlpcServerInformation, serverInfo, bufferLength, &bufferLength); + + if (status == STATUS_INFO_LENGTH_MISMATCH) + { + PhFree(serverInfo); + serverInfo = PhAllocate(bufferLength); + serverInfo->In.ThreadHandle = threadHandle; + + status = NtAlpcQueryInformation_I(NULL, AlpcServerInformation, serverInfo, bufferLength, &bufferLength); + } + + if (NT_SUCCESS(status) && serverInfo->Out.ThreadBlocked) + { + CLIENT_ID clientId; + PPH_STRING clientIdName; + + clientId.UniqueProcess = serverInfo->Out.ConnectedProcessId; + clientId.UniqueThread = NULL; + clientIdName = PH_AUTO(PhGetClientIdName(&clientId)); + + string = PhaFormatString(L"ALPC Port: %.*s (%s)", serverInfo->Out.ConnectionPortName.Length / 2, serverInfo->Out.ConnectionPortName.Buffer, clientIdName->Buffer); + } + + PhFree(serverInfo); + NtClose(threadHandle); + + return string; +} diff --git a/ProcessHacker/appsup.c b/ProcessHacker/appsup.c index fa61833b5fda..1d09f88b4014 100644 --- a/ProcessHacker/appsup.c +++ b/ProcessHacker/appsup.c @@ -1,2207 +1,2207 @@ -/* - * Process Hacker - - * application support functions - * - * Copyright (C) 2010-2016 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include - -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "mxml/mxml.h" -#include "pcre/pcre2.h" - -typedef LONG (WINAPI *_GetPackageFullName)( - _In_ HANDLE hProcess, - _Inout_ UINT32 *packageFullNameLength, - _Out_opt_ PWSTR packageFullName - ); - -typedef LONG (WINAPI *_GetPackagePath)( - _In_ PACKAGE_ID *packageId, - _Reserved_ UINT32 reserved, - _Inout_ UINT32 *pathLength, - _Out_opt_ PWSTR path - ); - -typedef LONG (WINAPI *_PackageIdFromFullName)( - _In_ PCWSTR packageFullName, - _In_ UINT32 flags, - _Inout_ UINT32 *bufferLength, - _Out_opt_ BYTE *buffer - ); - -GUID XP_CONTEXT_GUID = { 0xbeb1b341, 0x6837, 0x4c83, { 0x83, 0x66, 0x2b, 0x45, 0x1e, 0x7c, 0xe6, 0x9b } }; -GUID VISTA_CONTEXT_GUID = { 0xe2011457, 0x1546, 0x43c5, { 0xa5, 0xfe, 0x00, 0x8d, 0xee, 0xe3, 0xd3, 0xf0 } }; -GUID WIN7_CONTEXT_GUID = { 0x35138b9a, 0x5d96, 0x4fbd, { 0x8e, 0x2d, 0xa2, 0x44, 0x02, 0x25, 0xf9, 0x3a } }; -GUID WIN8_CONTEXT_GUID = { 0x4a2f28e3, 0x53b9, 0x4441, { 0xba, 0x9c, 0xd6, 0x9d, 0x4a, 0x4a, 0x6e, 0x38 } }; -GUID WINBLUE_CONTEXT_GUID = { 0x1f676c76, 0x80e1, 0x4239, { 0x95, 0xbb, 0x83, 0xd0, 0xf6, 0xd0, 0xda, 0x78 } }; -GUID WINTHRESHOLD_CONTEXT_GUID = { 0x8e0f7a12, 0xbfb3, 0x4fe8, { 0xb9, 0xa5, 0x48, 0xfd, 0x50, 0xa1, 0x5a, 0x9a } }; - -/** - * Determines whether a process is suspended. - * - * \param Process The SYSTEM_PROCESS_INFORMATION structure - * of the process. - */ -BOOLEAN PhGetProcessIsSuspended( - _In_ PSYSTEM_PROCESS_INFORMATION Process - ) -{ - ULONG i; - - for (i = 0; i < Process->NumberOfThreads; i++) - { - if ( - Process->Threads[i].ThreadState != Waiting || - Process->Threads[i].WaitReason != Suspended - ) - return FALSE; - } - - return Process->NumberOfThreads != 0; -} - -/** - * Determines the OS compatibility context of a process. - * - * \param ProcessHandle A handle to a process. - * \param Guid A variable which receives a GUID identifying an - * operating system version. - */ -NTSTATUS PhGetProcessSwitchContext( - _In_ HANDLE ProcessHandle, - _Out_ PGUID Guid - ) -{ - NTSTATUS status; - PROCESS_BASIC_INFORMATION basicInfo; -#ifdef _WIN64 - PVOID peb32; - ULONG data32; -#endif - PVOID data; - - // Reverse-engineered from WdcGetProcessSwitchContext (wdc.dll). - // On Windows 8, the function is now SdbGetAppCompatData (apphelp.dll). - // On Windows 10, the function is again WdcGetProcessSwitchContext. - -#ifdef _WIN64 - if (NT_SUCCESS(PhGetProcessPeb32(ProcessHandle, &peb32)) && peb32) - { - if (WindowsVersion >= WINDOWS_8) - { - if (!NT_SUCCESS(status = NtReadVirtualMemory( - ProcessHandle, - PTR_ADD_OFFSET(peb32, FIELD_OFFSET(PEB32, pShimData)), - &data32, - sizeof(ULONG), - NULL - ))) - return status; - } - else - { - if (!NT_SUCCESS(status = NtReadVirtualMemory( - ProcessHandle, - PTR_ADD_OFFSET(peb32, FIELD_OFFSET(PEB32, pContextData)), - &data32, - sizeof(ULONG), - NULL - ))) - return status; - } - - data = UlongToPtr(data32); - } - else - { -#endif - if (!NT_SUCCESS(status = PhGetProcessBasicInformation(ProcessHandle, &basicInfo))) - return status; - - if (WindowsVersion >= WINDOWS_8) - { - if (!NT_SUCCESS(status = NtReadVirtualMemory( - ProcessHandle, - PTR_ADD_OFFSET(basicInfo.PebBaseAddress, FIELD_OFFSET(PEB, pShimData)), - &data, - sizeof(PVOID), - NULL - ))) - return status; - } - else - { - if (!NT_SUCCESS(status = NtReadVirtualMemory( - ProcessHandle, - PTR_ADD_OFFSET(basicInfo.PebBaseAddress, FIELD_OFFSET(PEB, pContextData)), - &data, - sizeof(PVOID), - NULL - ))) - return status; - } -#ifdef _WIN64 - } -#endif - - if (!data) - return STATUS_UNSUCCESSFUL; // no compatibility context data - - if (WindowsVersion >= WINDOWS_10) - { - if (!NT_SUCCESS(status = NtReadVirtualMemory( - ProcessHandle, - PTR_ADD_OFFSET(data, 2040 + 24), // Magic value from SbReadProcContextByHandle - Guid, - sizeof(GUID), - NULL - ))) - return status; - } - else if (WindowsVersion >= WINDOWS_8_1) - { - if (!NT_SUCCESS(status = NtReadVirtualMemory( - ProcessHandle, - PTR_ADD_OFFSET(data, 2040 + 16), // Magic value from SbReadProcContextByHandle - Guid, - sizeof(GUID), - NULL - ))) - return status; - } - else if (WindowsVersion >= WINDOWS_8) - { - if (!NT_SUCCESS(status = NtReadVirtualMemory( - ProcessHandle, - PTR_ADD_OFFSET(data, 2040), // Magic value from SbReadProcContextByHandle - Guid, - sizeof(GUID), - NULL - ))) - return status; - } - else - { - if (!NT_SUCCESS(status = NtReadVirtualMemory( - ProcessHandle, - PTR_ADD_OFFSET(data, 32), // Magic value from WdcGetProcessSwitchContext - Guid, - sizeof(GUID), - NULL - ))) - return status; - } - - return STATUS_SUCCESS; -} - -PPH_STRING PhGetProcessPackageFullName( - _In_ HANDLE ProcessHandle - ) -{ - static _GetPackageFullName getPackageFullName = NULL; - - LONG result; - PPH_STRING name; - ULONG nameLength; - - if (!getPackageFullName) - getPackageFullName = PhGetModuleProcAddress(L"kernel32.dll", "GetPackageFullName"); - if (!getPackageFullName) - return NULL; - - nameLength = 101; - name = PhCreateStringEx(NULL, (nameLength - 1) * 2); - - result = getPackageFullName(ProcessHandle, &nameLength, name->Buffer); - - if (result == ERROR_INSUFFICIENT_BUFFER) - { - PhDereferenceObject(name); - name = PhCreateStringEx(NULL, (nameLength - 1) * 2); - - result = getPackageFullName(ProcessHandle, &nameLength, name->Buffer); - } - - if (result == ERROR_SUCCESS) - { - PhTrimToNullTerminatorString(name); - return name; - } - else - { - PhDereferenceObject(name); - return NULL; - } -} - -PACKAGE_ID *PhPackageIdFromFullName( - _In_ PWSTR PackageFullName - ) -{ - static _PackageIdFromFullName packageIdFromFullName = NULL; - - LONG result; - PVOID packageIdBuffer; - ULONG packageIdBufferSize; - - if (!packageIdFromFullName) - packageIdFromFullName = PhGetModuleProcAddress(L"kernel32.dll", "PackageIdFromFullName"); - if (!packageIdFromFullName) - return NULL; - - packageIdBufferSize = 100; - packageIdBuffer = PhAllocate(packageIdBufferSize); - - result = packageIdFromFullName(PackageFullName, PACKAGE_INFORMATION_BASIC, &packageIdBufferSize, (PBYTE)packageIdBuffer); - - if (result == ERROR_INSUFFICIENT_BUFFER) - { - PhFree(packageIdBuffer); - packageIdBuffer = PhAllocate(packageIdBufferSize); - - result = packageIdFromFullName(PackageFullName, PACKAGE_INFORMATION_BASIC, &packageIdBufferSize, (PBYTE)packageIdBuffer); - } - - if (result == ERROR_SUCCESS) - { - return packageIdBuffer; - } - else - { - PhFree(packageIdBuffer); - return NULL; - } -} - -PPH_STRING PhGetPackagePath( - _In_ PACKAGE_ID *PackageId - ) -{ - static _GetPackagePath getPackagePath = NULL; - - LONG result; - PPH_STRING path; - ULONG pathLength; - - if (!getPackagePath) - getPackagePath = PhGetModuleProcAddress(L"kernel32.dll", "GetPackagePath"); - if (!getPackagePath) - return NULL; - - pathLength = 101; - path = PhCreateStringEx(NULL, (pathLength - 1) * 2); - - result = getPackagePath(PackageId, 0, &pathLength, path->Buffer); - - if (result == ERROR_INSUFFICIENT_BUFFER) - { - PhDereferenceObject(path); - path = PhCreateStringEx(NULL, (pathLength - 1) * 2); - - result = getPackagePath(PackageId, 0, &pathLength, path->Buffer); - } - - if (result == ERROR_SUCCESS) - { - PhTrimToNullTerminatorString(path); - return path; - } - else - { - PhDereferenceObject(path); - return NULL; - } -} - -/** - * Determines the type of a process based on its image file name. - * - * \param ProcessHandle A handle to a process. - * \param KnownProcessType A variable which receives the process - * type. - */ -NTSTATUS PhGetProcessKnownType( - _In_ HANDLE ProcessHandle, - _Out_ PH_KNOWN_PROCESS_TYPE *KnownProcessType - ) -{ - NTSTATUS status; - PH_KNOWN_PROCESS_TYPE knownProcessType; - PROCESS_BASIC_INFORMATION basicInfo; - PH_STRINGREF systemRootPrefix; - PPH_STRING fileName; - PPH_STRING newFileName; - PH_STRINGREF name; -#ifdef _WIN64 - BOOLEAN isWow64 = FALSE; -#endif - - if (!NT_SUCCESS(status = PhGetProcessBasicInformation( - ProcessHandle, - &basicInfo - ))) - return status; - - if (basicInfo.UniqueProcessId == SYSTEM_PROCESS_ID) - { - *KnownProcessType = SystemProcessType; - return STATUS_SUCCESS; - } - - PhGetSystemRoot(&systemRootPrefix); - - if (!NT_SUCCESS(status = PhGetProcessImageFileName( - ProcessHandle, - &fileName - ))) - { - return status; - } - - newFileName = PhGetFileName(fileName); - PhDereferenceObject(fileName); - name = newFileName->sr; - - knownProcessType = UnknownProcessType; - - if (PhStartsWithStringRef(&name, &systemRootPrefix, TRUE)) - { - // Skip the system root, and we now have three cases: - // 1. \\xyz.exe - Windows executable. - // 2. \\System32\\xyz.exe - system32 executable. - // 3. \\SysWow64\\xyz.exe - system32 executable + WOW64. - PhSkipStringRef(&name, systemRootPrefix.Length); - - if (PhEqualStringRef2(&name, L"\\explorer.exe", TRUE)) - { - knownProcessType = ExplorerProcessType; - } - else if ( - PhStartsWithStringRef2(&name, L"\\System32", TRUE) -#ifdef _WIN64 - || (PhStartsWithStringRef2(&name, L"\\SysWow64", TRUE) && (isWow64 = TRUE, TRUE)) // ugly but necessary -#endif - ) - { - // SysTem32 and SysWow64 are both 8 characters long. - PhSkipStringRef(&name, 9 * sizeof(WCHAR)); - - if (FALSE) - ; // Dummy - else if (PhEqualStringRef2(&name, L"\\smss.exe", TRUE)) - knownProcessType = SessionManagerProcessType; - else if (PhEqualStringRef2(&name, L"\\csrss.exe", TRUE)) - knownProcessType = WindowsSubsystemProcessType; - else if (PhEqualStringRef2(&name, L"\\wininit.exe", TRUE)) - knownProcessType = WindowsStartupProcessType; - else if (PhEqualStringRef2(&name, L"\\services.exe", TRUE)) - knownProcessType = ServiceControlManagerProcessType; - else if (PhEqualStringRef2(&name, L"\\lsass.exe", TRUE)) - knownProcessType = LocalSecurityAuthorityProcessType; - else if (PhEqualStringRef2(&name, L"\\lsm.exe", TRUE)) - knownProcessType = LocalSessionManagerProcessType; - else if (PhEqualStringRef2(&name, L"\\winlogon.exe", TRUE)) - knownProcessType = WindowsLogonProcessType; - else if (PhEqualStringRef2(&name, L"\\svchost.exe", TRUE)) - knownProcessType = ServiceHostProcessType; - else if (PhEqualStringRef2(&name, L"\\rundll32.exe", TRUE)) - knownProcessType = RunDllAsAppProcessType; - else if (PhEqualStringRef2(&name, L"\\dllhost.exe", TRUE)) - knownProcessType = ComSurrogateProcessType; - else if (PhEqualStringRef2(&name, L"\\taskeng.exe", TRUE)) - knownProcessType = TaskHostProcessType; - else if (PhEqualStringRef2(&name, L"\\taskhost.exe", TRUE)) - knownProcessType = TaskHostProcessType; - else if (PhEqualStringRef2(&name, L"\\taskhostex.exe", TRUE)) - knownProcessType = TaskHostProcessType; - else if (PhEqualStringRef2(&name, L"\\taskhostw.exe", TRUE)) - knownProcessType = TaskHostProcessType; - else if (PhEqualStringRef2(&name, L"\\wudfhost.exe", TRUE)) - knownProcessType = UmdfHostProcessType; - } - } - - PhDereferenceObject(newFileName); - -#ifdef _WIN64 - if (isWow64) - knownProcessType |= KnownProcessWow64; -#endif - - *KnownProcessType = knownProcessType; - - return status; -} - -static BOOLEAN NTAPI PhpSvchostCommandLineCallback( - _In_opt_ PPH_COMMAND_LINE_OPTION Option, - _In_opt_ PPH_STRING Value, - _In_opt_ PVOID Context - ) -{ - PPH_KNOWN_PROCESS_COMMAND_LINE knownCommandLine = Context; - - if (Option && Option->Id == 1) - { - PhSwapReference(&knownCommandLine->ServiceHost.GroupName, Value); - } - - return TRUE; -} - -BOOLEAN PhaGetProcessKnownCommandLine( - _In_ PPH_STRING CommandLine, - _In_ PH_KNOWN_PROCESS_TYPE KnownProcessType, - _Out_ PPH_KNOWN_PROCESS_COMMAND_LINE KnownCommandLine - ) -{ - switch (KnownProcessType & KnownProcessTypeMask) - { - case ServiceHostProcessType: - { - // svchost.exe -k - - static PH_COMMAND_LINE_OPTION options[] = - { - { 1, L"k", MandatoryArgumentType } - }; - - KnownCommandLine->ServiceHost.GroupName = NULL; - - PhParseCommandLine( - &CommandLine->sr, - options, - sizeof(options) / sizeof(PH_COMMAND_LINE_OPTION), - PH_COMMAND_LINE_IGNORE_UNKNOWN_OPTIONS, - PhpSvchostCommandLineCallback, - KnownCommandLine - ); - - if (KnownCommandLine->ServiceHost.GroupName) - { - PH_AUTO(KnownCommandLine->ServiceHost.GroupName); - return TRUE; - } - else - { - return FALSE; - } - } - break; - case RunDllAsAppProcessType: - { - // rundll32.exe , ... - - SIZE_T i; - PH_STRINGREF dllNamePart; - PH_STRINGREF procedureNamePart; - PPH_STRING dllName; - PPH_STRING procedureName; - - i = 0; - - // Get the rundll32.exe part. - - dllName = PhParseCommandLinePart(&CommandLine->sr, &i); - - if (!dllName) - return FALSE; - - PhDereferenceObject(dllName); - - // Get the DLL name part. - - while (i < CommandLine->Length / 2 && CommandLine->Buffer[i] == ' ') - i++; - - dllName = PhParseCommandLinePart(&CommandLine->sr, &i); - - if (!dllName) - return FALSE; - - PH_AUTO(dllName); - - // The procedure name begins after the last comma. - - if (!PhSplitStringRefAtLastChar(&dllName->sr, ',', &dllNamePart, &procedureNamePart)) - return FALSE; - - dllName = PH_AUTO(PhCreateString2(&dllNamePart)); - procedureName = PH_AUTO(PhCreateString2(&procedureNamePart)); - - // If the DLL name isn't an absolute path, assume it's in system32. - // TODO: Use a proper search function. - - if (RtlDetermineDosPathNameType_U(dllName->Buffer) == RtlPathTypeRelative) - { - dllName = PhaConcatStrings( - 3, - PH_AUTO_T(PH_STRING, PhGetSystemDirectory())->Buffer, - L"\\", - dllName->Buffer - ); - } - - KnownCommandLine->RunDllAsApp.FileName = dllName; - KnownCommandLine->RunDllAsApp.ProcedureName = procedureName; - } - break; - case ComSurrogateProcessType: - { - // dllhost.exe /processid: - - static PH_STRINGREF inprocServer32Name = PH_STRINGREF_INIT(L"InprocServer32"); - - SIZE_T i; - ULONG_PTR indexOfProcessId; - PPH_STRING argPart; - PPH_STRING guidString; - UNICODE_STRING guidStringUs; - GUID guid; - HANDLE rootKeyHandle; - HANDLE inprocServer32KeyHandle; - PPH_STRING fileName; - - i = 0; - - // Get the dllhost.exe part. - - argPart = PhParseCommandLinePart(&CommandLine->sr, &i); - - if (!argPart) - return FALSE; - - PhDereferenceObject(argPart); - - // Get the argument part. - - while (i < (ULONG)CommandLine->Length / 2 && CommandLine->Buffer[i] == ' ') - i++; - - argPart = PhParseCommandLinePart(&CommandLine->sr, &i); - - if (!argPart) - return FALSE; - - PH_AUTO(argPart); - - // Find "/processid:"; the GUID is just after that. - - _wcsupr(argPart->Buffer); - indexOfProcessId = PhFindStringInString(argPart, 0, L"/PROCESSID:"); - - if (indexOfProcessId == -1) - return FALSE; - - guidString = PhaSubstring( - argPart, - indexOfProcessId + 11, - (ULONG)argPart->Length / 2 - indexOfProcessId - 11 - ); - PhStringRefToUnicodeString(&guidString->sr, &guidStringUs); - - if (!NT_SUCCESS(RtlGUIDFromString( - &guidStringUs, - &guid - ))) - return FALSE; - - KnownCommandLine->ComSurrogate.Guid = guid; - KnownCommandLine->ComSurrogate.Name = NULL; - KnownCommandLine->ComSurrogate.FileName = NULL; - - // Lookup the GUID in the registry to determine the name and file name. - - if (NT_SUCCESS(PhOpenKey( - &rootKeyHandle, - KEY_READ, - PH_KEY_CLASSES_ROOT, - &PhaConcatStrings2(L"CLSID\\", guidString->Buffer)->sr, - 0 - ))) - { - KnownCommandLine->ComSurrogate.Name = - PH_AUTO(PhQueryRegistryString(rootKeyHandle, NULL)); - - if (NT_SUCCESS(PhOpenKey( - &inprocServer32KeyHandle, - KEY_READ, - rootKeyHandle, - &inprocServer32Name, - 0 - ))) - { - KnownCommandLine->ComSurrogate.FileName = - PH_AUTO(PhQueryRegistryString(inprocServer32KeyHandle, NULL)); - - if (fileName = PH_AUTO(PhExpandEnvironmentStrings( - &KnownCommandLine->ComSurrogate.FileName->sr - ))) - { - KnownCommandLine->ComSurrogate.FileName = fileName; - } - - NtClose(inprocServer32KeyHandle); - } - - NtClose(rootKeyHandle); - } - else if (NT_SUCCESS(PhOpenKey( - &rootKeyHandle, - KEY_READ, - PH_KEY_CLASSES_ROOT, - &PhaConcatStrings2(L"AppID\\", guidString->Buffer)->sr, - 0 - ))) - { - KnownCommandLine->ComSurrogate.Name = - PH_AUTO(PhQueryRegistryString(rootKeyHandle, NULL)); - NtClose(rootKeyHandle); - } - } - break; - default: - return FALSE; - } - - return TRUE; -} - -VOID PhEnumChildWindows( - _In_opt_ HWND hWnd, - _In_ ULONG Limit, - _In_ WNDENUMPROC Callback, - _In_ LPARAM lParam - ) -{ - HWND childWindow = NULL; - ULONG i = 0; - - while (i < Limit && (childWindow = FindWindowEx(hWnd, childWindow, NULL, NULL))) - { - if (!Callback(childWindow, lParam)) - return; - - i++; - } -} - -typedef struct _GET_PROCESS_MAIN_WINDOW_CONTEXT -{ - HWND Window; - HWND ImmersiveWindow; - HANDLE ProcessId; - BOOLEAN IsImmersive; -} GET_PROCESS_MAIN_WINDOW_CONTEXT, *PGET_PROCESS_MAIN_WINDOW_CONTEXT; - -BOOL CALLBACK PhpGetProcessMainWindowEnumWindowsProc( - _In_ HWND hwnd, - _In_ LPARAM lParam - ) -{ - PGET_PROCESS_MAIN_WINDOW_CONTEXT context = (PGET_PROCESS_MAIN_WINDOW_CONTEXT)lParam; - ULONG processId; - HWND parentWindow; - WINDOWINFO windowInfo; - - if (!IsWindowVisible(hwnd)) - return TRUE; - - GetWindowThreadProcessId(hwnd, &processId); - - if (UlongToHandle(processId) == context->ProcessId && - !((parentWindow = GetParent(hwnd)) && IsWindowVisible(parentWindow)) && // skip windows with a visible parent - PhGetWindowTextEx(hwnd, PH_GET_WINDOW_TEXT_INTERNAL | PH_GET_WINDOW_TEXT_LENGTH_ONLY, NULL) != 0) // skip windows with no title - { - if (!context->ImmersiveWindow && context->IsImmersive && - GetProp(hwnd, L"Windows.ImmersiveShell.IdentifyAsMainCoreWindow")) - { - context->ImmersiveWindow = hwnd; - } - - windowInfo.cbSize = sizeof(WINDOWINFO); - - if (!context->Window && GetWindowInfo(hwnd, &windowInfo) && (windowInfo.dwStyle & WS_DLGFRAME)) - { - context->Window = hwnd; - - // If we're not looking at an immersive process, there's no need to search any more windows. - if (!context->IsImmersive) - return FALSE; - } - } - - return TRUE; -} - -HWND PhGetProcessMainWindow( - _In_ HANDLE ProcessId, - _In_opt_ HANDLE ProcessHandle - ) -{ - GET_PROCESS_MAIN_WINDOW_CONTEXT context; - HANDLE processHandle = NULL; - - memset(&context, 0, sizeof(GET_PROCESS_MAIN_WINDOW_CONTEXT)); - context.ProcessId = ProcessId; - - if (ProcessHandle) - processHandle = ProcessHandle; - else - PhOpenProcess(&processHandle, ProcessQueryAccess, ProcessId); - - if (processHandle && IsImmersiveProcess_I) - context.IsImmersive = IsImmersiveProcess_I(processHandle); - - PhEnumChildWindows(NULL, 0x800, PhpGetProcessMainWindowEnumWindowsProc, (LPARAM)&context); - - if (!ProcessHandle && processHandle) - NtClose(processHandle); - - return context.ImmersiveWindow ? context.ImmersiveWindow : context.Window; -} - -PPH_STRING PhGetServiceRelevantFileName( - _In_ PPH_STRINGREF ServiceName, - _In_ SC_HANDLE ServiceHandle - ) -{ - PPH_STRING fileName = NULL; - LPQUERY_SERVICE_CONFIG config; - - if (config = PhGetServiceConfig(ServiceHandle)) - { - PhGetServiceDllParameter(ServiceName, &fileName); - - if (!fileName) - { - PPH_STRING commandLine; - - commandLine = PhCreateString(config->lpBinaryPathName); - - if (config->dwServiceType & SERVICE_WIN32) - { - PH_STRINGREF dummyFileName; - PH_STRINGREF dummyArguments; - - PhParseCommandLineFuzzy(&commandLine->sr, &dummyFileName, &dummyArguments, &fileName); - - if (!fileName) - PhSwapReference(&fileName, commandLine); - } - else - { - fileName = PhGetFileName(commandLine); - } - - PhDereferenceObject(commandLine); - } - - PhFree(config); - } - - return fileName; -} - -PPH_STRING PhEscapeStringForDelimiter( - _In_ PPH_STRING String, - _In_ WCHAR Delimiter - ) -{ - PH_STRING_BUILDER stringBuilder; - SIZE_T length; - SIZE_T i; - WCHAR temp[2]; - - length = String->Length / 2; - PhInitializeStringBuilder(&stringBuilder, String->Length / 2 * 3); - - temp[0] = '\\'; - - for (i = 0; i < length; i++) - { - if (String->Buffer[i] == '\\' || String->Buffer[i] == Delimiter) - { - temp[1] = String->Buffer[i]; - PhAppendStringBuilderEx(&stringBuilder, temp, 4); - } - else - { - PhAppendCharStringBuilder(&stringBuilder, String->Buffer[i]); - } - } - - return PhFinalStringBuilderString(&stringBuilder); -} - -PPH_STRING PhUnescapeStringForDelimiter( - _In_ PPH_STRING String, - _In_ WCHAR Delimiter - ) -{ - PH_STRING_BUILDER stringBuilder; - SIZE_T length; - SIZE_T i; - - length = String->Length / 2; - PhInitializeStringBuilder(&stringBuilder, String->Length / 2 * 3); - - for (i = 0; i < length; i++) - { - if (String->Buffer[i] == '\\') - { - if (i != length - 1) - { - PhAppendCharStringBuilder(&stringBuilder, String->Buffer[i + 1]); - i++; - } - else - { - // Trailing backslash. Just ignore it. - break; - } - } - else - { - PhAppendCharStringBuilder(&stringBuilder, String->Buffer[i]); - } - } - - return PhFinalStringBuilderString(&stringBuilder); -} - -PPH_STRING PhGetOpaqueXmlNodeText( - _In_ mxml_node_t *node - ) -{ - if (node->child && node->child->type == MXML_OPAQUE && node->child->value.opaque) - { - return PhConvertUtf8ToUtf16(node->child->value.opaque); - } - else - { - return PhReferenceEmptyString(); - } -} - -VOID PhSearchOnlineString( - _In_ HWND hWnd, - _In_ PWSTR String - ) -{ - PhShellExecuteUserString(hWnd, L"SearchEngine", String, TRUE, NULL); -} - -VOID PhShellExecuteUserString( - _In_ HWND hWnd, - _In_ PWSTR Setting, - _In_ PWSTR String, - _In_ BOOLEAN UseShellExecute, - _In_opt_ PWSTR ErrorMessage - ) -{ - static PH_STRINGREF replacementToken = PH_STRINGREF_INIT(L"%s"); - - PPH_STRING executeString; - PH_STRINGREF stringBefore; - PH_STRINGREF stringMiddle; - PH_STRINGREF stringAfter; - PPH_STRING ntMessage; - - executeString = PhGetStringSetting(Setting); - - // Make sure the user executable string is absolute. We can't use RtlDetermineDosPathNameType_U - // here because the string may be a URL. - if (PhFindCharInString(executeString, 0, ':') == -1) - PhMoveReference(&executeString, PhConcatStringRef2(&PhApplicationDirectory->sr, &executeString->sr)); - - // Replace the token with the string, or use the original string if the token is not present. - if (PhSplitStringRefAtString(&executeString->sr, &replacementToken, FALSE, &stringBefore, &stringAfter)) - { - PhInitializeStringRef(&stringMiddle, String); - PhMoveReference(&executeString, PhConcatStringRef3(&stringBefore, &stringMiddle, &stringAfter)); - } - - if (UseShellExecute) - { - PhShellExecute(hWnd, executeString->Buffer, NULL); - } - else - { - NTSTATUS status; - - status = PhCreateProcessWin32(NULL, executeString->Buffer, NULL, NULL, 0, NULL, NULL, NULL); - - if (!NT_SUCCESS(status)) - { - if (ErrorMessage) - { - ntMessage = PhGetNtMessage(status); - PhShowError(hWnd, L"Unable to execute the command: %s\n%s", PhGetStringOrDefault(ntMessage, L"An unknown error occurred."), ErrorMessage); - PhDereferenceObject(ntMessage); - } - else - { - PhShowStatus(hWnd, L"Unable to execute the command", status, 0); - } - } - } - - PhDereferenceObject(executeString); -} - -VOID PhLoadSymbolProviderOptions( - _Inout_ PPH_SYMBOL_PROVIDER SymbolProvider - ) -{ - PPH_STRING searchPath; - - PhSetOptionsSymbolProvider( - SYMOPT_UNDNAME, - PhGetIntegerSetting(L"DbgHelpUndecorate") ? SYMOPT_UNDNAME : 0 - ); - - searchPath = PhGetStringSetting(L"DbgHelpSearchPath"); - - if (searchPath->Length != 0) - PhSetSearchPathSymbolProvider(SymbolProvider, searchPath->Buffer); - - PhDereferenceObject(searchPath); -} - -PWSTR PhMakeContextAtom( - VOID - ) -{ - PH_DEFINE_MAKE_ATOM(L"PH2_Context"); -} - -/** - * Copies a string into a NMLVGETINFOTIP structure. - * - * \param GetInfoTip The NMLVGETINFOTIP structure. - * \param Tip The string to copy. - * - * \remarks The text is truncated if it is too long. - */ -VOID PhCopyListViewInfoTip( - _Inout_ LPNMLVGETINFOTIP GetInfoTip, - _In_ PPH_STRINGREF Tip - ) -{ - ULONG copyIndex; - ULONG bufferRemaining; - ULONG copyLength; - - if (GetInfoTip->dwFlags == 0) - { - copyIndex = (ULONG)PhCountStringZ(GetInfoTip->pszText) + 1; // plus one for newline - - if (GetInfoTip->cchTextMax - copyIndex < 2) // need at least two bytes - return; - - bufferRemaining = GetInfoTip->cchTextMax - copyIndex - 1; - GetInfoTip->pszText[copyIndex - 1] = '\n'; - } - else - { - copyIndex = 0; - bufferRemaining = GetInfoTip->cchTextMax; - } - - copyLength = min((ULONG)Tip->Length / 2, bufferRemaining - 1); - memcpy( - &GetInfoTip->pszText[copyIndex], - Tip->Buffer, - copyLength * 2 - ); - GetInfoTip->pszText[copyIndex + copyLength] = 0; -} - -VOID PhCopyListView( - _In_ HWND ListViewHandle - ) -{ - PPH_STRING text; - - text = PhGetListViewText(ListViewHandle); - PhSetClipboardString(ListViewHandle, &text->sr); - PhDereferenceObject(text); -} - -VOID PhHandleListViewNotifyForCopy( - _In_ LPARAM lParam, - _In_ HWND ListViewHandle - ) -{ - PhHandleListViewNotifyBehaviors(lParam, ListViewHandle, PH_LIST_VIEW_CTRL_C_BEHAVIOR); -} - -VOID PhHandleListViewNotifyBehaviors( - _In_ LPARAM lParam, - _In_ HWND ListViewHandle, - _In_ ULONG Behaviors - ) -{ - if (((LPNMHDR)lParam)->hwndFrom == ListViewHandle && ((LPNMHDR)lParam)->code == LVN_KEYDOWN) - { - LPNMLVKEYDOWN keyDown = (LPNMLVKEYDOWN)lParam; - - switch (keyDown->wVKey) - { - case 'C': - if (Behaviors & PH_LIST_VIEW_CTRL_C_BEHAVIOR) - { - if (GetKeyState(VK_CONTROL) < 0) - PhCopyListView(ListViewHandle); - } - break; - case 'A': - if (Behaviors & PH_LIST_VIEW_CTRL_A_BEHAVIOR) - { - if (GetKeyState(VK_CONTROL) < 0) - PhSetStateAllListViewItems(ListViewHandle, LVIS_SELECTED, LVIS_SELECTED); - } - break; - } - } -} - -BOOLEAN PhGetListViewContextMenuPoint( - _In_ HWND ListViewHandle, - _Out_ PPOINT Point - ) -{ - INT selectedIndex; - RECT bounds; - RECT clientRect; - - // The user pressed a key to display the context menu. - // Suggest where the context menu should display. - - if ((selectedIndex = ListView_GetNextItem(ListViewHandle, -1, LVNI_SELECTED)) != -1) - { - if (ListView_GetItemRect(ListViewHandle, selectedIndex, &bounds, LVIR_BOUNDS)) - { - Point->x = bounds.left + PhSmallIconSize.X / 2; - Point->y = bounds.top + PhSmallIconSize.Y / 2; - - GetClientRect(ListViewHandle, &clientRect); - - if (Point->x < 0 || Point->y < 0 || Point->x >= clientRect.right || Point->y >= clientRect.bottom) - { - // The menu is going to be outside of the control. Just put it at the top-left. - Point->x = 0; - Point->y = 0; - } - - ClientToScreen(ListViewHandle, Point); - - return TRUE; - } - } - - Point->x = 0; - Point->y = 0; - ClientToScreen(ListViewHandle, Point); - - return FALSE; -} - -HFONT PhDuplicateFontWithNewWeight( - _In_ HFONT Font, - _In_ LONG NewWeight - ) -{ - LOGFONT logFont; - - if (GetObject(Font, sizeof(LOGFONT), &logFont)) - { - logFont.lfWeight = NewWeight; - return CreateFontIndirect(&logFont); - } - else - { - return NULL; - } -} - -VOID PhSetWindowOpacity( - _In_ HWND WindowHandle, - _In_ ULONG OpacityPercent - ) -{ - if (OpacityPercent == 0) - { - // Make things a bit faster by removing the WS_EX_LAYERED bit. - PhSetWindowExStyle(WindowHandle, WS_EX_LAYERED, 0); - RedrawWindow(WindowHandle, NULL, NULL, RDW_ERASE | RDW_INVALIDATE | RDW_FRAME | RDW_ALLCHILDREN); - return; - } - - PhSetWindowExStyle(WindowHandle, WS_EX_LAYERED, WS_EX_LAYERED); - - // Disallow opacity values of less than 10%. - OpacityPercent = min(OpacityPercent, 90); - - // The opacity value is backwards - 0 means opaque, 100 means transparent. - SetLayeredWindowAttributes( - WindowHandle, - 0, - (BYTE)(255 * (100 - OpacityPercent) / 100), - LWA_ALPHA - ); -} - -VOID PhLoadWindowPlacementFromSetting( - _In_opt_ PWSTR PositionSettingName, - _In_opt_ PWSTR SizeSettingName, - _In_ HWND WindowHandle - ) -{ - PH_RECTANGLE windowRectangle; - - if (PositionSettingName && SizeSettingName) - { - RECT rectForAdjust; - - windowRectangle.Position = PhGetIntegerPairSetting(PositionSettingName); - windowRectangle.Size = PhGetScalableIntegerPairSetting(SizeSettingName, TRUE).Pair; - PhAdjustRectangleToWorkingArea(NULL, &windowRectangle); - - // Let the window adjust for the minimum size if needed. - rectForAdjust = PhRectangleToRect(windowRectangle); - SendMessage(WindowHandle, WM_SIZING, WMSZ_BOTTOMRIGHT, (LPARAM)&rectForAdjust); - windowRectangle = PhRectToRectangle(rectForAdjust); - - MoveWindow(WindowHandle, windowRectangle.Left, windowRectangle.Top, - windowRectangle.Width, windowRectangle.Height, FALSE); - } - else - { - PH_INTEGER_PAIR position; - PH_INTEGER_PAIR size; - ULONG flags; - - flags = SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOREDRAW | SWP_NOSIZE | SWP_NOZORDER; - - if (PositionSettingName) - { - position = PhGetIntegerPairSetting(PositionSettingName); - flags &= ~SWP_NOMOVE; - } - else - { - position.X = 0; - position.Y = 0; - } - - if (SizeSettingName) - { - size = PhGetScalableIntegerPairSetting(SizeSettingName, TRUE).Pair; - flags &= ~SWP_NOSIZE; - } - else - { - size.X = 16; - size.Y = 16; - } - - SetWindowPos(WindowHandle, NULL, position.X, position.Y, size.X, size.Y, flags); - } -} - -VOID PhSaveWindowPlacementToSetting( - _In_opt_ PWSTR PositionSettingName, - _In_opt_ PWSTR SizeSettingName, - _In_ HWND WindowHandle - ) -{ - WINDOWPLACEMENT placement = { sizeof(placement) }; - PH_RECTANGLE windowRectangle; - MONITORINFO monitorInfo = { sizeof(MONITORINFO) }; - - GetWindowPlacement(WindowHandle, &placement); - windowRectangle = PhRectToRectangle(placement.rcNormalPosition); - - // The rectangle is in workspace coordinates. Convert the values back to screen coordinates. - if (GetMonitorInfo(MonitorFromRect(&placement.rcNormalPosition, MONITOR_DEFAULTTOPRIMARY), &monitorInfo)) - { - windowRectangle.Left += monitorInfo.rcWork.left - monitorInfo.rcMonitor.left; - windowRectangle.Top += monitorInfo.rcWork.top - monitorInfo.rcMonitor.top; - } - - if (PositionSettingName) - PhSetIntegerPairSetting(PositionSettingName, windowRectangle.Position); - if (SizeSettingName) - PhSetScalableIntegerPairSetting2(SizeSettingName, windowRectangle.Size); -} - -VOID PhLoadListViewColumnsFromSetting( - _In_ PWSTR Name, - _In_ HWND ListViewHandle - ) -{ - PPH_STRING string; - - string = PhGetStringSetting(Name); - PhLoadListViewColumnSettings(ListViewHandle, string); - PhDereferenceObject(string); -} - -VOID PhSaveListViewColumnsToSetting( - _In_ PWSTR Name, - _In_ HWND ListViewHandle - ) -{ - PPH_STRING string; - - string = PhSaveListViewColumnSettings(ListViewHandle); - PhSetStringSetting2(Name, &string->sr); - PhDereferenceObject(string); -} - -PPH_STRING PhGetPhVersion( - VOID - ) -{ - PH_FORMAT format[5]; - - PhInitFormatU(&format[0], PHAPP_VERSION_MAJOR); - PhInitFormatC(&format[1], '.'); - PhInitFormatU(&format[2], PHAPP_VERSION_MINOR); - PhInitFormatC(&format[3], '.'); - PhInitFormatU(&format[4], PHAPP_VERSION_REVISION); - - return PhFormat(format, 5, 16); -} - -VOID PhGetPhVersionNumbers( - _Out_opt_ PULONG MajorVersion, - _Out_opt_ PULONG MinorVersion, - _Reserved_ PULONG Reserved, - _Out_opt_ PULONG RevisionNumber - ) -{ - if (MajorVersion) - *MajorVersion = PHAPP_VERSION_MAJOR; - if (MinorVersion) - *MinorVersion = PHAPP_VERSION_MINOR; - if (RevisionNumber) - *RevisionNumber = PHAPP_VERSION_REVISION; -} - -VOID PhWritePhTextHeader( - _Inout_ PPH_FILE_STREAM FileStream - ) -{ - PPH_STRING version; - LARGE_INTEGER time; - SYSTEMTIME systemTime; - PPH_STRING dateString; - PPH_STRING timeString; - - PhWriteStringAsUtf8FileStream2(FileStream, L"Process Hacker "); - - if (version = PhGetPhVersion()) - { - PhWriteStringAsUtf8FileStream(FileStream, &version->sr); - PhDereferenceObject(version); - } - - PhWriteStringFormatAsUtf8FileStream(FileStream, L"\r\nWindows NT %u.%u", PhOsVersion.dwMajorVersion, PhOsVersion.dwMinorVersion); - - if (PhOsVersion.szCSDVersion[0] != 0) - PhWriteStringFormatAsUtf8FileStream(FileStream, L" %s", PhOsVersion.szCSDVersion); - -#ifdef _WIN64 - PhWriteStringAsUtf8FileStream2(FileStream, L" (64-bit)"); -#else - PhWriteStringAsUtf8FileStream2(FileStream, L" (32-bit)"); -#endif - - PhQuerySystemTime(&time); - PhLargeIntegerToLocalSystemTime(&systemTime, &time); - - dateString = PhFormatDate(&systemTime, NULL); - timeString = PhFormatTime(&systemTime, NULL); - PhWriteStringFormatAsUtf8FileStream(FileStream, L"\r\n%s %s\r\n\r\n", dateString->Buffer, timeString->Buffer); - PhDereferenceObject(dateString); - PhDereferenceObject(timeString); -} - -BOOLEAN PhShellProcessHacker( - _In_opt_ HWND hWnd, - _In_opt_ PWSTR Parameters, - _In_ ULONG ShowWindowType, - _In_ ULONG Flags, - _In_ ULONG AppFlags, - _In_opt_ ULONG Timeout, - _Out_opt_ PHANDLE ProcessHandle - ) -{ - return PhShellProcessHackerEx( - hWnd, - NULL, - Parameters, - ShowWindowType, - Flags, - AppFlags, - Timeout, - ProcessHandle - ); -} - -VOID PhpAppendCommandLineArgument( - _Inout_ PPH_STRING_BUILDER StringBuilder, - _In_ PWSTR Name, - _In_ PPH_STRINGREF Value - ) -{ - PPH_STRING temp; - - PhAppendStringBuilder2(StringBuilder, L" -"); - PhAppendStringBuilder2(StringBuilder, Name); - PhAppendStringBuilder2(StringBuilder, L" \""); - temp = PhEscapeCommandLinePart(Value); - PhAppendStringBuilder(StringBuilder, &temp->sr); - PhDereferenceObject(temp); - PhAppendCharStringBuilder(StringBuilder, '\"'); -} - -BOOLEAN PhShellProcessHackerEx( - _In_opt_ HWND hWnd, - _In_opt_ PWSTR FileName, - _In_opt_ PWSTR Parameters, - _In_ ULONG ShowWindowType, - _In_ ULONG Flags, - _In_ ULONG AppFlags, - _In_opt_ ULONG Timeout, - _Out_opt_ PHANDLE ProcessHandle - ) -{ - BOOLEAN result; - PH_STRING_BUILDER sb; - PWSTR parameters; - - if (AppFlags & PH_SHELL_APP_PROPAGATE_PARAMETERS) - { - PhInitializeStringBuilder(&sb, 128); - - // Propagate parameters. - - if (PhStartupParameters.NoSettings) - { - PhAppendStringBuilder2(&sb, L" -nosettings"); - } - else if (PhStartupParameters.SettingsFileName && (PhSettingsFileName || (AppFlags & PH_SHELL_APP_PROPAGATE_PARAMETERS_FORCE_SETTINGS))) - { - PPH_STRINGREF fileName; - - if (PhSettingsFileName) - fileName = &PhSettingsFileName->sr; - else - fileName = &PhStartupParameters.SettingsFileName->sr; - - PhpAppendCommandLineArgument(&sb, L"settings", fileName); - } - - if (PhStartupParameters.NoKph) - PhAppendStringBuilder2(&sb, L" -nokph"); - if (PhStartupParameters.InstallKph) - PhAppendStringBuilder2(&sb, L" -installkph"); - if (PhStartupParameters.UninstallKph) - PhAppendStringBuilder2(&sb, L" -uninstallkph"); - if (PhStartupParameters.Debug) - PhAppendStringBuilder2(&sb, L" -debug"); - if (PhStartupParameters.NoPlugins) - PhAppendStringBuilder2(&sb, L" -noplugins"); - if (PhStartupParameters.NewInstance) - PhAppendStringBuilder2(&sb, L" -newinstance"); - - if (PhStartupParameters.SelectPid != 0) - PhAppendFormatStringBuilder(&sb, L" -selectpid %u", PhStartupParameters.SelectPid); - - if (PhStartupParameters.PriorityClass != 0) - { - CHAR value = 0; - - switch (PhStartupParameters.PriorityClass) - { - case PROCESS_PRIORITY_CLASS_REALTIME: - value = L'r'; - break; - case PROCESS_PRIORITY_CLASS_HIGH: - value = L'h'; - break; - case PROCESS_PRIORITY_CLASS_NORMAL: - value = L'n'; - break; - case PROCESS_PRIORITY_CLASS_IDLE: - value = L'l'; - break; - } - - if (value != 0) - { - PhAppendStringBuilder2(&sb, L" -priority "); - PhAppendCharStringBuilder(&sb, value); - } - } - - if (PhStartupParameters.PluginParameters) - { - ULONG i; - - for (i = 0; i < PhStartupParameters.PluginParameters->Count; i++) - { - PPH_STRING value = PhStartupParameters.PluginParameters->Items[i]; - PhpAppendCommandLineArgument(&sb, L"plugin", &value->sr); - } - } - - if (PhStartupParameters.SelectTab) - PhpAppendCommandLineArgument(&sb, L"selecttab", &PhStartupParameters.SelectTab->sr); - - if (!(AppFlags & PH_SHELL_APP_PROPAGATE_PARAMETERS_IGNORE_VISIBILITY)) - { - if (PhStartupParameters.ShowVisible) - PhAppendStringBuilder2(&sb, L" -v"); - if (PhStartupParameters.ShowHidden) - PhAppendStringBuilder2(&sb, L" -hide"); - } - - // Add user-specified parameters last so they can override the propagated parameters. - if (Parameters) - { - PhAppendCharStringBuilder(&sb, ' '); - PhAppendStringBuilder2(&sb, Parameters); - } - - if (sb.String->Length != 0 && sb.String->Buffer[0] == ' ') - parameters = sb.String->Buffer + 1; - else - parameters = sb.String->Buffer; - } - else - { - parameters = Parameters; - } - - result = PhShellExecuteEx( - hWnd, - FileName ? FileName : PhApplicationFileName->Buffer, - parameters, - ShowWindowType, - Flags, - Timeout, - ProcessHandle - ); - - if (AppFlags & PH_SHELL_APP_PROPAGATE_PARAMETERS) - PhDeleteStringBuilder(&sb); - - return result; -} - -BOOLEAN PhCreateProcessIgnoreIfeoDebugger( - _In_ PWSTR FileName - ) -{ - BOOLEAN result; - BOOL (NTAPI *debugSetProcessKillOnExit)(BOOL); - BOOL (NTAPI *debugActiveProcessStop)(DWORD); - BOOLEAN originalValue; - STARTUPINFO startupInfo; - PROCESS_INFORMATION processInfo; - - if (!(debugSetProcessKillOnExit = PhGetModuleProcAddress(L"kernel32.dll", "DebugSetProcessKillOnExit")) || - !(debugActiveProcessStop = PhGetModuleProcAddress(L"kernel32.dll", "DebugActiveProcessStop"))) - return FALSE; - - result = FALSE; - - // This is NOT thread-safe. - originalValue = NtCurrentPeb()->ReadImageFileExecOptions; - NtCurrentPeb()->ReadImageFileExecOptions = FALSE; - - memset(&startupInfo, 0, sizeof(STARTUPINFO)); - startupInfo.cb = sizeof(STARTUPINFO); - memset(&processInfo, 0, sizeof(PROCESS_INFORMATION)); - - // The combination of ReadImageFileExecOptions = FALSE and the DEBUG_PROCESS flag - // allows us to skip the Debugger IFEO value. - if (CreateProcess(FileName, NULL, NULL, NULL, FALSE, DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS, NULL, NULL, &startupInfo, &processInfo)) - { - // Stop debugging the process now. - debugSetProcessKillOnExit(FALSE); - debugActiveProcessStop(processInfo.dwProcessId); - result = TRUE; - } - - if (processInfo.hProcess) - NtClose(processInfo.hProcess); - if (processInfo.hThread) - NtClose(processInfo.hThread); - - NtCurrentPeb()->ReadImageFileExecOptions = originalValue; - - return result; -} - -VOID PhInitializeTreeNewColumnMenu( - _Inout_ PPH_TN_COLUMN_MENU_DATA Data - ) -{ - PhInitializeTreeNewColumnMenuEx(Data, 0); -} - -VOID PhInitializeTreeNewColumnMenuEx( - _Inout_ PPH_TN_COLUMN_MENU_DATA Data, - _In_ ULONG Flags - ) -{ - PPH_EMENU_ITEM resetSortMenuItem = NULL; - PPH_EMENU_ITEM sizeColumnToFitMenuItem; - PPH_EMENU_ITEM sizeAllColumnsToFitMenuItem; - PPH_EMENU_ITEM hideColumnMenuItem; - PPH_EMENU_ITEM chooseColumnsMenuItem; - ULONG minimumNumberOfColumns; - - Data->Menu = PhCreateEMenu(); - Data->Selection = NULL; - Data->ProcessedId = 0; - - sizeColumnToFitMenuItem = PhCreateEMenuItem(0, PH_TN_COLUMN_MENU_SIZE_COLUMN_TO_FIT_ID, L"Size column to fit", NULL, NULL); - sizeAllColumnsToFitMenuItem = PhCreateEMenuItem(0, PH_TN_COLUMN_MENU_SIZE_ALL_COLUMNS_TO_FIT_ID, L"Size all columns to fit", NULL, NULL); - - if (!(Flags & PH_TN_COLUMN_MENU_NO_VISIBILITY)) - { - hideColumnMenuItem = PhCreateEMenuItem(0, PH_TN_COLUMN_MENU_HIDE_COLUMN_ID, L"Hide column", NULL, NULL); - chooseColumnsMenuItem = PhCreateEMenuItem(0, PH_TN_COLUMN_MENU_CHOOSE_COLUMNS_ID, L"Choose columns...", NULL, NULL); - } - - if (Flags & PH_TN_COLUMN_MENU_SHOW_RESET_SORT) - { - ULONG sortColumn; - PH_SORT_ORDER sortOrder; - - TreeNew_GetSort(Data->TreeNewHandle, &sortColumn, &sortOrder); - - if (sortOrder != Data->DefaultSortOrder || (Data->DefaultSortOrder != NoSortOrder && sortColumn != Data->DefaultSortColumn)) - resetSortMenuItem = PhCreateEMenuItem(0, PH_TN_COLUMN_MENU_RESET_SORT_ID, L"Reset sort", NULL, NULL); - } - - PhInsertEMenuItem(Data->Menu, sizeColumnToFitMenuItem, -1); - PhInsertEMenuItem(Data->Menu, sizeAllColumnsToFitMenuItem, -1); - - if (!(Flags & PH_TN_COLUMN_MENU_NO_VISIBILITY)) - { - PhInsertEMenuItem(Data->Menu, hideColumnMenuItem, -1); - - if (resetSortMenuItem) - PhInsertEMenuItem(Data->Menu, resetSortMenuItem, -1); - - PhInsertEMenuItem(Data->Menu, PhCreateEMenuItem(PH_EMENU_SEPARATOR, 0, L"", NULL, NULL), -1); - PhInsertEMenuItem(Data->Menu, chooseColumnsMenuItem, -1); - - if (TreeNew_GetFixedColumn(Data->TreeNewHandle)) - minimumNumberOfColumns = 2; // don't allow user to remove all normal columns (the fixed column can never be removed) - else - minimumNumberOfColumns = 1; - - if (!Data->MouseEvent || !Data->MouseEvent->Column || - Data->MouseEvent->Column->Fixed || // don't allow the fixed column to be hidden - TreeNew_GetVisibleColumnCount(Data->TreeNewHandle) < minimumNumberOfColumns + 1 - ) - { - hideColumnMenuItem->Flags |= PH_EMENU_DISABLED; - } - } - else - { - if (resetSortMenuItem) - PhInsertEMenuItem(Data->Menu, resetSortMenuItem, -1); - } - - if (!Data->MouseEvent || !Data->MouseEvent->Column) - { - sizeColumnToFitMenuItem->Flags |= PH_EMENU_DISABLED; - } -} - -VOID PhpEnsureValidSortColumnTreeNew( - _Inout_ HWND TreeNewHandle, - _In_ ULONG DefaultSortColumn, - _In_ PH_SORT_ORDER DefaultSortOrder - ) -{ - ULONG sortColumn; - PH_SORT_ORDER sortOrder; - - // Make sure the column we're sorting by is actually visible, and if not, don't sort anymore. - - TreeNew_GetSort(TreeNewHandle, &sortColumn, &sortOrder); - - if (sortOrder != NoSortOrder) - { - PH_TREENEW_COLUMN column; - - TreeNew_GetColumn(TreeNewHandle, sortColumn, &column); - - if (!column.Visible) - { - if (DefaultSortOrder != NoSortOrder) - { - // Make sure the default sort column is visible. - TreeNew_GetColumn(TreeNewHandle, DefaultSortColumn, &column); - - if (!column.Visible) - { - ULONG maxId; - ULONG id; - BOOLEAN found; - - // Use the first visible column. - maxId = TreeNew_GetMaxId(TreeNewHandle); - id = 0; - found = FALSE; - - while (id <= maxId) - { - if (TreeNew_GetColumn(TreeNewHandle, id, &column)) - { - if (column.Visible) - { - DefaultSortColumn = id; - found = TRUE; - break; - } - } - - id++; - } - - if (!found) - { - DefaultSortColumn = 0; - DefaultSortOrder = NoSortOrder; - } - } - } - - TreeNew_SetSort(TreeNewHandle, DefaultSortColumn, DefaultSortOrder); - } - } -} - -BOOLEAN PhHandleTreeNewColumnMenu( - _Inout_ PPH_TN_COLUMN_MENU_DATA Data - ) -{ - if (!Data->Selection) - return FALSE; - - switch (Data->Selection->Id) - { - case PH_TN_COLUMN_MENU_RESET_SORT_ID: - { - TreeNew_SetSort(Data->TreeNewHandle, Data->DefaultSortColumn, Data->DefaultSortOrder); - } - break; - case PH_TN_COLUMN_MENU_SIZE_COLUMN_TO_FIT_ID: - { - if (Data->MouseEvent && Data->MouseEvent->Column) - { - TreeNew_AutoSizeColumn(Data->TreeNewHandle, Data->MouseEvent->Column->Id, 0); - } - } - break; - case PH_TN_COLUMN_MENU_SIZE_ALL_COLUMNS_TO_FIT_ID: - { - ULONG maxId; - ULONG id; - - maxId = TreeNew_GetMaxId(Data->TreeNewHandle); - id = 0; - - while (id <= maxId) - { - TreeNew_AutoSizeColumn(Data->TreeNewHandle, id, 0); - id++; - } - } - break; - case PH_TN_COLUMN_MENU_HIDE_COLUMN_ID: - { - PH_TREENEW_COLUMN column; - - if (Data->MouseEvent && Data->MouseEvent->Column && !Data->MouseEvent->Column->Fixed) - { - column.Id = Data->MouseEvent->Column->Id; - column.Visible = FALSE; - TreeNew_SetColumn(Data->TreeNewHandle, TN_COLUMN_FLAG_VISIBLE, &column); - PhpEnsureValidSortColumnTreeNew(Data->TreeNewHandle, Data->DefaultSortColumn, Data->DefaultSortOrder); - InvalidateRect(Data->TreeNewHandle, NULL, FALSE); - } - } - break; - case PH_TN_COLUMN_MENU_CHOOSE_COLUMNS_ID: - { - PhShowChooseColumnsDialog(Data->TreeNewHandle, Data->TreeNewHandle, PH_CONTROL_TYPE_TREE_NEW); - PhpEnsureValidSortColumnTreeNew(Data->TreeNewHandle, Data->DefaultSortColumn, Data->DefaultSortOrder); - } - break; - default: - return FALSE; - } - - Data->ProcessedId = Data->Selection->Id; - - return TRUE; -} - -VOID PhDeleteTreeNewColumnMenu( - _In_ PPH_TN_COLUMN_MENU_DATA Data - ) -{ - if (Data->Menu) - { - PhDestroyEMenu(Data->Menu); - Data->Menu = NULL; - } -} - -VOID PhInitializeTreeNewFilterSupport( - _Out_ PPH_TN_FILTER_SUPPORT Support, - _In_ HWND TreeNewHandle, - _In_ PPH_LIST NodeList - ) -{ - Support->FilterList = NULL; - Support->TreeNewHandle = TreeNewHandle; - Support->NodeList = NodeList; -} - -VOID PhDeleteTreeNewFilterSupport( - _In_ PPH_TN_FILTER_SUPPORT Support - ) -{ - PhDereferenceObject(Support->FilterList); -} - -PPH_TN_FILTER_ENTRY PhAddTreeNewFilter( - _In_ PPH_TN_FILTER_SUPPORT Support, - _In_ PPH_TN_FILTER_FUNCTION Filter, - _In_opt_ PVOID Context - ) -{ - PPH_TN_FILTER_ENTRY entry; - - entry = PhAllocate(sizeof(PH_TN_FILTER_ENTRY)); - entry->Filter = Filter; - entry->Context = Context; - - if (!Support->FilterList) - Support->FilterList = PhCreateList(2); - - PhAddItemList(Support->FilterList, entry); - - return entry; -} - -VOID PhRemoveTreeNewFilter( - _In_ PPH_TN_FILTER_SUPPORT Support, - _In_ PPH_TN_FILTER_ENTRY Entry - ) -{ - ULONG index; - - if (!Support->FilterList) - return; - - index = PhFindItemList(Support->FilterList, Entry); - - if (index != -1) - { - PhRemoveItemList(Support->FilterList, index); - PhFree(Entry); - } -} - -BOOLEAN PhApplyTreeNewFiltersToNode( - _In_ PPH_TN_FILTER_SUPPORT Support, - _In_ PPH_TREENEW_NODE Node - ) -{ - BOOLEAN show; - ULONG i; - - show = TRUE; - - if (Support->FilterList) - { - for (i = 0; i < Support->FilterList->Count; i++) - { - PPH_TN_FILTER_ENTRY entry; - - entry = Support->FilterList->Items[i]; - - if (!entry->Filter(Node, entry->Context)) - { - show = FALSE; - break; - } - } - } - - return show; -} - -VOID PhApplyTreeNewFilters( - _In_ PPH_TN_FILTER_SUPPORT Support - ) -{ - ULONG i; - - for (i = 0; i < Support->NodeList->Count; i++) - { - PPH_TREENEW_NODE node; - - node = Support->NodeList->Items[i]; - node->Visible = PhApplyTreeNewFiltersToNode(Support, node); - - if (!node->Visible && node->Selected) - { - node->Selected = FALSE; - } - } - - TreeNew_NodesStructured(Support->TreeNewHandle); -} - -VOID NTAPI PhpCopyCellEMenuItemDeleteFunction( - _In_ struct _PH_EMENU_ITEM *Item - ) -{ - PPH_COPY_CELL_CONTEXT context; - - context = Item->Context; - PhDereferenceObject(context->MenuItemText); - PhFree(context); -} - -BOOLEAN PhInsertCopyCellEMenuItem( - _In_ struct _PH_EMENU_ITEM *Menu, - _In_ ULONG InsertAfterId, - _In_ HWND TreeNewHandle, - _In_ PPH_TREENEW_COLUMN Column - ) -{ - PPH_EMENU_ITEM parentItem; - ULONG indexInParent; - PPH_COPY_CELL_CONTEXT context; - PH_STRINGREF columnText; - PPH_STRING escapedText; - PPH_STRING menuItemText; - PPH_EMENU_ITEM copyCellItem; - - if (!Column) - return FALSE; - - if (!PhFindEMenuItemEx(Menu, 0, NULL, InsertAfterId, &parentItem, &indexInParent)) - return FALSE; - - indexInParent++; - - context = PhAllocate(sizeof(PH_COPY_CELL_CONTEXT)); - context->TreeNewHandle = TreeNewHandle; - context->Id = Column->Id; - - PhInitializeStringRef(&columnText, Column->Text); - escapedText = PhEscapeStringForMenuPrefix(&columnText); - menuItemText = PhFormatString(L"Copy \"%s\"", escapedText->Buffer); - PhDereferenceObject(escapedText); - copyCellItem = PhCreateEMenuItem(0, ID_COPY_CELL, menuItemText->Buffer, NULL, context); - copyCellItem->DeleteFunction = PhpCopyCellEMenuItemDeleteFunction; - context->MenuItemText = menuItemText; - - if (Column->CustomDraw) - copyCellItem->Flags |= PH_EMENU_DISABLED; - - PhInsertEMenuItem(parentItem, copyCellItem, indexInParent); - - return TRUE; -} - -BOOLEAN PhHandleCopyCellEMenuItem( - _In_ struct _PH_EMENU_ITEM *SelectedItem - ) -{ - PPH_COPY_CELL_CONTEXT context; - PH_STRING_BUILDER stringBuilder; - ULONG count; - ULONG selectedCount; - ULONG i; - PPH_TREENEW_NODE node; - PH_TREENEW_GET_CELL_TEXT getCellText; - - if (!SelectedItem) - return FALSE; - if (SelectedItem->Id != ID_COPY_CELL) - return FALSE; - - context = SelectedItem->Context; - - PhInitializeStringBuilder(&stringBuilder, 0x100); - count = TreeNew_GetFlatNodeCount(context->TreeNewHandle); - selectedCount = 0; - - for (i = 0; i < count; i++) - { - node = TreeNew_GetFlatNode(context->TreeNewHandle, i); - - if (node && node->Selected) - { - selectedCount++; - - getCellText.Flags = 0; - getCellText.Node = node; - getCellText.Id = context->Id; - PhInitializeEmptyStringRef(&getCellText.Text); - TreeNew_GetCellText(context->TreeNewHandle, &getCellText); - - PhAppendStringBuilder(&stringBuilder, &getCellText.Text); - PhAppendStringBuilder2(&stringBuilder, L"\r\n"); - } - } - - if (stringBuilder.String->Length != 0 && selectedCount == 1) - PhRemoveEndStringBuilder(&stringBuilder, 2); - - PhSetClipboardString(context->TreeNewHandle, &stringBuilder.String->sr); - PhDeleteStringBuilder(&stringBuilder); - - return TRUE; -} - -BOOLEAN PhpSelectFavoriteInRegedit( - _In_ HWND RegeditWindow, - _In_ PPH_STRINGREF FavoriteName, - _In_ BOOLEAN UsePhSvc - ) -{ - HMENU menu; - HMENU favoritesMenu; - ULONG count; - ULONG i; - ULONG id = -1; - - if (!(menu = GetMenu(RegeditWindow))) - return FALSE; - - // Cause the Registry Editor to refresh the Favorites menu. - if (UsePhSvc) - PhSvcCallSendMessage(RegeditWindow, WM_MENUSELECT, MAKEWPARAM(3, MF_POPUP), (LPARAM)menu); - else - SendMessage(RegeditWindow, WM_MENUSELECT, MAKEWPARAM(3, MF_POPUP), (LPARAM)menu); - - if (!(favoritesMenu = GetSubMenu(menu, 3))) - return FALSE; - - // Find our entry. - - count = GetMenuItemCount(favoritesMenu); - - if (count == -1) - return FALSE; - if (count > 1000) - count = 1000; - - for (i = 3; i < count; i++) - { - MENUITEMINFO info = { sizeof(MENUITEMINFO) }; - WCHAR buffer[32]; - - info.fMask = MIIM_ID | MIIM_STRING; - info.dwTypeData = buffer; - info.cch = sizeof(buffer) / sizeof(WCHAR); - GetMenuItemInfo(favoritesMenu, i, TRUE, &info); - - if (info.cch == FavoriteName->Length / 2) - { - PH_STRINGREF text; - - text.Buffer = buffer; - text.Length = info.cch * 2; - - if (PhEqualStringRef(&text, FavoriteName, TRUE)) - { - id = info.wID; - break; - } - } - } - - if (id == -1) - return FALSE; - - // Activate our entry. - if (UsePhSvc) - PhSvcCallSendMessage(RegeditWindow, WM_COMMAND, MAKEWPARAM(id, 0), 0); - else - SendMessage(RegeditWindow, WM_COMMAND, MAKEWPARAM(id, 0), 0); - - // "Close" the Favorites menu and restore normal status bar text. - if (UsePhSvc) - PhSvcCallPostMessage(RegeditWindow, WM_MENUSELECT, MAKEWPARAM(0, 0xffff), 0); - else - PostMessage(RegeditWindow, WM_MENUSELECT, MAKEWPARAM(0, 0xffff), 0); - - // Bring regedit to the top. - if (IsIconic(RegeditWindow)) - { - ShowWindow(RegeditWindow, SW_RESTORE); - SetForegroundWindow(RegeditWindow); - } - else - { - SetForegroundWindow(RegeditWindow); - } - - return TRUE; -} - -/** - * Opens a key in the Registry Editor. If the Registry Editor is already open, - * the specified key is selected in the Registry Editor. - * - * \param hWnd A handle to the parent window. - * \param KeyName The key name to open. - */ -BOOLEAN PhShellOpenKey2( - _In_ HWND hWnd, - _In_ PPH_STRING KeyName - ) -{ - static PH_STRINGREF favoritesKeyName = PH_STRINGREF_INIT(L"Software\\Microsoft\\Windows\\CurrentVersion\\Applets\\Regedit\\Favorites"); - - BOOLEAN result = FALSE; - HWND regeditWindow; - HANDLE favoritesKeyHandle; - WCHAR favoriteName[32]; - UNICODE_STRING valueName; - PH_STRINGREF valueNameSr; - PPH_STRING expandedKeyName; - - regeditWindow = FindWindow(L"RegEdit_RegEdit", NULL); - - if (!regeditWindow) - { - PhShellOpenKey(hWnd, KeyName); - return TRUE; - } - - if (!PhGetOwnTokenAttributes().Elevated) - { - if (!PhUiConnectToPhSvc(hWnd, FALSE)) - return FALSE; - } - - // Create our entry in Favorites. - - if (!NT_SUCCESS(PhCreateKey( - &favoritesKeyHandle, - KEY_WRITE, - PH_KEY_CURRENT_USER, - &favoritesKeyName, - 0, - 0, - NULL - ))) - goto CleanupExit; - - memcpy(favoriteName, L"A_ProcessHacker", 15 * sizeof(WCHAR)); - PhGenerateRandomAlphaString(&favoriteName[15], 16); - RtlInitUnicodeString(&valueName, favoriteName); - PhUnicodeStringToStringRef(&valueName, &valueNameSr); - - expandedKeyName = PhExpandKeyName(KeyName, TRUE); - NtSetValueKey(favoritesKeyHandle, &valueName, 0, REG_SZ, expandedKeyName->Buffer, (ULONG)expandedKeyName->Length + 2); - PhDereferenceObject(expandedKeyName); - - // Select our entry in regedit. - result = PhpSelectFavoriteInRegedit(regeditWindow, &valueNameSr, !PhGetOwnTokenAttributes().Elevated); - - NtDeleteValueKey(favoritesKeyHandle, &valueName); - NtClose(favoritesKeyHandle); - -CleanupExit: - if (!PhGetOwnTokenAttributes().Elevated) - PhUiDisconnectFromPhSvc(); - - return result; -} - -PPH_STRING PhPcre2GetErrorMessage( - _In_ INT ErrorCode - ) -{ - PPH_STRING buffer; - SIZE_T bufferLength; - INT_PTR returnLength; - - bufferLength = 128 * sizeof(WCHAR); - buffer = PhCreateStringEx(NULL, bufferLength); - - while (TRUE) - { - if ((returnLength = pcre2_get_error_message(ErrorCode, buffer->Buffer, bufferLength / sizeof(WCHAR) + 1)) >= 0) - break; - - PhDereferenceObject(buffer); - bufferLength *= 2; - - if (bufferLength > 0x1000 * sizeof(WCHAR)) - break; - - buffer = PhCreateStringEx(NULL, bufferLength); - } - - if (returnLength < 0) - return NULL; - - buffer->Length = returnLength * sizeof(WCHAR); - return buffer; -} +/* + * Process Hacker - + * application support functions + * + * Copyright (C) 2010-2016 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "mxml/mxml.h" +#include "pcre/pcre2.h" + +typedef LONG (WINAPI *_GetPackageFullName)( + _In_ HANDLE hProcess, + _Inout_ UINT32 *packageFullNameLength, + _Out_opt_ PWSTR packageFullName + ); + +typedef LONG (WINAPI *_GetPackagePath)( + _In_ PACKAGE_ID *packageId, + _Reserved_ UINT32 reserved, + _Inout_ UINT32 *pathLength, + _Out_opt_ PWSTR path + ); + +typedef LONG (WINAPI *_PackageIdFromFullName)( + _In_ PCWSTR packageFullName, + _In_ UINT32 flags, + _Inout_ UINT32 *bufferLength, + _Out_opt_ BYTE *buffer + ); + +GUID XP_CONTEXT_GUID = { 0xbeb1b341, 0x6837, 0x4c83, { 0x83, 0x66, 0x2b, 0x45, 0x1e, 0x7c, 0xe6, 0x9b } }; +GUID VISTA_CONTEXT_GUID = { 0xe2011457, 0x1546, 0x43c5, { 0xa5, 0xfe, 0x00, 0x8d, 0xee, 0xe3, 0xd3, 0xf0 } }; +GUID WIN7_CONTEXT_GUID = { 0x35138b9a, 0x5d96, 0x4fbd, { 0x8e, 0x2d, 0xa2, 0x44, 0x02, 0x25, 0xf9, 0x3a } }; +GUID WIN8_CONTEXT_GUID = { 0x4a2f28e3, 0x53b9, 0x4441, { 0xba, 0x9c, 0xd6, 0x9d, 0x4a, 0x4a, 0x6e, 0x38 } }; +GUID WINBLUE_CONTEXT_GUID = { 0x1f676c76, 0x80e1, 0x4239, { 0x95, 0xbb, 0x83, 0xd0, 0xf6, 0xd0, 0xda, 0x78 } }; +GUID WINTHRESHOLD_CONTEXT_GUID = { 0x8e0f7a12, 0xbfb3, 0x4fe8, { 0xb9, 0xa5, 0x48, 0xfd, 0x50, 0xa1, 0x5a, 0x9a } }; + +/** + * Determines whether a process is suspended. + * + * \param Process The SYSTEM_PROCESS_INFORMATION structure + * of the process. + */ +BOOLEAN PhGetProcessIsSuspended( + _In_ PSYSTEM_PROCESS_INFORMATION Process + ) +{ + ULONG i; + + for (i = 0; i < Process->NumberOfThreads; i++) + { + if ( + Process->Threads[i].ThreadState != Waiting || + Process->Threads[i].WaitReason != Suspended + ) + return FALSE; + } + + return Process->NumberOfThreads != 0; +} + +/** + * Determines the OS compatibility context of a process. + * + * \param ProcessHandle A handle to a process. + * \param Guid A variable which receives a GUID identifying an + * operating system version. + */ +NTSTATUS PhGetProcessSwitchContext( + _In_ HANDLE ProcessHandle, + _Out_ PGUID Guid + ) +{ + NTSTATUS status; + PROCESS_BASIC_INFORMATION basicInfo; +#ifdef _WIN64 + PVOID peb32; + ULONG data32; +#endif + PVOID data; + + // Reverse-engineered from WdcGetProcessSwitchContext (wdc.dll). + // On Windows 8, the function is now SdbGetAppCompatData (apphelp.dll). + // On Windows 10, the function is again WdcGetProcessSwitchContext. + +#ifdef _WIN64 + if (NT_SUCCESS(PhGetProcessPeb32(ProcessHandle, &peb32)) && peb32) + { + if (WindowsVersion >= WINDOWS_8) + { + if (!NT_SUCCESS(status = NtReadVirtualMemory( + ProcessHandle, + PTR_ADD_OFFSET(peb32, FIELD_OFFSET(PEB32, pShimData)), + &data32, + sizeof(ULONG), + NULL + ))) + return status; + } + else + { + if (!NT_SUCCESS(status = NtReadVirtualMemory( + ProcessHandle, + PTR_ADD_OFFSET(peb32, FIELD_OFFSET(PEB32, pContextData)), + &data32, + sizeof(ULONG), + NULL + ))) + return status; + } + + data = UlongToPtr(data32); + } + else + { +#endif + if (!NT_SUCCESS(status = PhGetProcessBasicInformation(ProcessHandle, &basicInfo))) + return status; + + if (WindowsVersion >= WINDOWS_8) + { + if (!NT_SUCCESS(status = NtReadVirtualMemory( + ProcessHandle, + PTR_ADD_OFFSET(basicInfo.PebBaseAddress, FIELD_OFFSET(PEB, pShimData)), + &data, + sizeof(PVOID), + NULL + ))) + return status; + } + else + { + if (!NT_SUCCESS(status = NtReadVirtualMemory( + ProcessHandle, + PTR_ADD_OFFSET(basicInfo.PebBaseAddress, FIELD_OFFSET(PEB, pContextData)), + &data, + sizeof(PVOID), + NULL + ))) + return status; + } +#ifdef _WIN64 + } +#endif + + if (!data) + return STATUS_UNSUCCESSFUL; // no compatibility context data + + if (WindowsVersion >= WINDOWS_10) + { + if (!NT_SUCCESS(status = NtReadVirtualMemory( + ProcessHandle, + PTR_ADD_OFFSET(data, 2040 + 24), // Magic value from SbReadProcContextByHandle + Guid, + sizeof(GUID), + NULL + ))) + return status; + } + else if (WindowsVersion >= WINDOWS_8_1) + { + if (!NT_SUCCESS(status = NtReadVirtualMemory( + ProcessHandle, + PTR_ADD_OFFSET(data, 2040 + 16), // Magic value from SbReadProcContextByHandle + Guid, + sizeof(GUID), + NULL + ))) + return status; + } + else if (WindowsVersion >= WINDOWS_8) + { + if (!NT_SUCCESS(status = NtReadVirtualMemory( + ProcessHandle, + PTR_ADD_OFFSET(data, 2040), // Magic value from SbReadProcContextByHandle + Guid, + sizeof(GUID), + NULL + ))) + return status; + } + else + { + if (!NT_SUCCESS(status = NtReadVirtualMemory( + ProcessHandle, + PTR_ADD_OFFSET(data, 32), // Magic value from WdcGetProcessSwitchContext + Guid, + sizeof(GUID), + NULL + ))) + return status; + } + + return STATUS_SUCCESS; +} + +PPH_STRING PhGetProcessPackageFullName( + _In_ HANDLE ProcessHandle + ) +{ + static _GetPackageFullName getPackageFullName = NULL; + + LONG result; + PPH_STRING name; + ULONG nameLength; + + if (!getPackageFullName) + getPackageFullName = PhGetModuleProcAddress(L"kernel32.dll", "GetPackageFullName"); + if (!getPackageFullName) + return NULL; + + nameLength = 101; + name = PhCreateStringEx(NULL, (nameLength - 1) * 2); + + result = getPackageFullName(ProcessHandle, &nameLength, name->Buffer); + + if (result == ERROR_INSUFFICIENT_BUFFER) + { + PhDereferenceObject(name); + name = PhCreateStringEx(NULL, (nameLength - 1) * 2); + + result = getPackageFullName(ProcessHandle, &nameLength, name->Buffer); + } + + if (result == ERROR_SUCCESS) + { + PhTrimToNullTerminatorString(name); + return name; + } + else + { + PhDereferenceObject(name); + return NULL; + } +} + +PACKAGE_ID *PhPackageIdFromFullName( + _In_ PWSTR PackageFullName + ) +{ + static _PackageIdFromFullName packageIdFromFullName = NULL; + + LONG result; + PVOID packageIdBuffer; + ULONG packageIdBufferSize; + + if (!packageIdFromFullName) + packageIdFromFullName = PhGetModuleProcAddress(L"kernel32.dll", "PackageIdFromFullName"); + if (!packageIdFromFullName) + return NULL; + + packageIdBufferSize = 100; + packageIdBuffer = PhAllocate(packageIdBufferSize); + + result = packageIdFromFullName(PackageFullName, PACKAGE_INFORMATION_BASIC, &packageIdBufferSize, (PBYTE)packageIdBuffer); + + if (result == ERROR_INSUFFICIENT_BUFFER) + { + PhFree(packageIdBuffer); + packageIdBuffer = PhAllocate(packageIdBufferSize); + + result = packageIdFromFullName(PackageFullName, PACKAGE_INFORMATION_BASIC, &packageIdBufferSize, (PBYTE)packageIdBuffer); + } + + if (result == ERROR_SUCCESS) + { + return packageIdBuffer; + } + else + { + PhFree(packageIdBuffer); + return NULL; + } +} + +PPH_STRING PhGetPackagePath( + _In_ PACKAGE_ID *PackageId + ) +{ + static _GetPackagePath getPackagePath = NULL; + + LONG result; + PPH_STRING path; + ULONG pathLength; + + if (!getPackagePath) + getPackagePath = PhGetModuleProcAddress(L"kernel32.dll", "GetPackagePath"); + if (!getPackagePath) + return NULL; + + pathLength = 101; + path = PhCreateStringEx(NULL, (pathLength - 1) * 2); + + result = getPackagePath(PackageId, 0, &pathLength, path->Buffer); + + if (result == ERROR_INSUFFICIENT_BUFFER) + { + PhDereferenceObject(path); + path = PhCreateStringEx(NULL, (pathLength - 1) * 2); + + result = getPackagePath(PackageId, 0, &pathLength, path->Buffer); + } + + if (result == ERROR_SUCCESS) + { + PhTrimToNullTerminatorString(path); + return path; + } + else + { + PhDereferenceObject(path); + return NULL; + } +} + +/** + * Determines the type of a process based on its image file name. + * + * \param ProcessHandle A handle to a process. + * \param KnownProcessType A variable which receives the process + * type. + */ +NTSTATUS PhGetProcessKnownType( + _In_ HANDLE ProcessHandle, + _Out_ PH_KNOWN_PROCESS_TYPE *KnownProcessType + ) +{ + NTSTATUS status; + PH_KNOWN_PROCESS_TYPE knownProcessType; + PROCESS_BASIC_INFORMATION basicInfo; + PH_STRINGREF systemRootPrefix; + PPH_STRING fileName; + PPH_STRING newFileName; + PH_STRINGREF name; +#ifdef _WIN64 + BOOLEAN isWow64 = FALSE; +#endif + + if (!NT_SUCCESS(status = PhGetProcessBasicInformation( + ProcessHandle, + &basicInfo + ))) + return status; + + if (basicInfo.UniqueProcessId == SYSTEM_PROCESS_ID) + { + *KnownProcessType = SystemProcessType; + return STATUS_SUCCESS; + } + + PhGetSystemRoot(&systemRootPrefix); + + if (!NT_SUCCESS(status = PhGetProcessImageFileName( + ProcessHandle, + &fileName + ))) + { + return status; + } + + newFileName = PhGetFileName(fileName); + PhDereferenceObject(fileName); + name = newFileName->sr; + + knownProcessType = UnknownProcessType; + + if (PhStartsWithStringRef(&name, &systemRootPrefix, TRUE)) + { + // Skip the system root, and we now have three cases: + // 1. \\xyz.exe - Windows executable. + // 2. \\System32\\xyz.exe - system32 executable. + // 3. \\SysWow64\\xyz.exe - system32 executable + WOW64. + PhSkipStringRef(&name, systemRootPrefix.Length); + + if (PhEqualStringRef2(&name, L"\\explorer.exe", TRUE)) + { + knownProcessType = ExplorerProcessType; + } + else if ( + PhStartsWithStringRef2(&name, L"\\System32", TRUE) +#ifdef _WIN64 + || (PhStartsWithStringRef2(&name, L"\\SysWow64", TRUE) && (isWow64 = TRUE, TRUE)) // ugly but necessary +#endif + ) + { + // SysTem32 and SysWow64 are both 8 characters long. + PhSkipStringRef(&name, 9 * sizeof(WCHAR)); + + if (FALSE) + ; // Dummy + else if (PhEqualStringRef2(&name, L"\\smss.exe", TRUE)) + knownProcessType = SessionManagerProcessType; + else if (PhEqualStringRef2(&name, L"\\csrss.exe", TRUE)) + knownProcessType = WindowsSubsystemProcessType; + else if (PhEqualStringRef2(&name, L"\\wininit.exe", TRUE)) + knownProcessType = WindowsStartupProcessType; + else if (PhEqualStringRef2(&name, L"\\services.exe", TRUE)) + knownProcessType = ServiceControlManagerProcessType; + else if (PhEqualStringRef2(&name, L"\\lsass.exe", TRUE)) + knownProcessType = LocalSecurityAuthorityProcessType; + else if (PhEqualStringRef2(&name, L"\\lsm.exe", TRUE)) + knownProcessType = LocalSessionManagerProcessType; + else if (PhEqualStringRef2(&name, L"\\winlogon.exe", TRUE)) + knownProcessType = WindowsLogonProcessType; + else if (PhEqualStringRef2(&name, L"\\svchost.exe", TRUE)) + knownProcessType = ServiceHostProcessType; + else if (PhEqualStringRef2(&name, L"\\rundll32.exe", TRUE)) + knownProcessType = RunDllAsAppProcessType; + else if (PhEqualStringRef2(&name, L"\\dllhost.exe", TRUE)) + knownProcessType = ComSurrogateProcessType; + else if (PhEqualStringRef2(&name, L"\\taskeng.exe", TRUE)) + knownProcessType = TaskHostProcessType; + else if (PhEqualStringRef2(&name, L"\\taskhost.exe", TRUE)) + knownProcessType = TaskHostProcessType; + else if (PhEqualStringRef2(&name, L"\\taskhostex.exe", TRUE)) + knownProcessType = TaskHostProcessType; + else if (PhEqualStringRef2(&name, L"\\taskhostw.exe", TRUE)) + knownProcessType = TaskHostProcessType; + else if (PhEqualStringRef2(&name, L"\\wudfhost.exe", TRUE)) + knownProcessType = UmdfHostProcessType; + } + } + + PhDereferenceObject(newFileName); + +#ifdef _WIN64 + if (isWow64) + knownProcessType |= KnownProcessWow64; +#endif + + *KnownProcessType = knownProcessType; + + return status; +} + +static BOOLEAN NTAPI PhpSvchostCommandLineCallback( + _In_opt_ PPH_COMMAND_LINE_OPTION Option, + _In_opt_ PPH_STRING Value, + _In_opt_ PVOID Context + ) +{ + PPH_KNOWN_PROCESS_COMMAND_LINE knownCommandLine = Context; + + if (Option && Option->Id == 1) + { + PhSwapReference(&knownCommandLine->ServiceHost.GroupName, Value); + } + + return TRUE; +} + +BOOLEAN PhaGetProcessKnownCommandLine( + _In_ PPH_STRING CommandLine, + _In_ PH_KNOWN_PROCESS_TYPE KnownProcessType, + _Out_ PPH_KNOWN_PROCESS_COMMAND_LINE KnownCommandLine + ) +{ + switch (KnownProcessType & KnownProcessTypeMask) + { + case ServiceHostProcessType: + { + // svchost.exe -k + + static PH_COMMAND_LINE_OPTION options[] = + { + { 1, L"k", MandatoryArgumentType } + }; + + KnownCommandLine->ServiceHost.GroupName = NULL; + + PhParseCommandLine( + &CommandLine->sr, + options, + sizeof(options) / sizeof(PH_COMMAND_LINE_OPTION), + PH_COMMAND_LINE_IGNORE_UNKNOWN_OPTIONS, + PhpSvchostCommandLineCallback, + KnownCommandLine + ); + + if (KnownCommandLine->ServiceHost.GroupName) + { + PH_AUTO(KnownCommandLine->ServiceHost.GroupName); + return TRUE; + } + else + { + return FALSE; + } + } + break; + case RunDllAsAppProcessType: + { + // rundll32.exe , ... + + SIZE_T i; + PH_STRINGREF dllNamePart; + PH_STRINGREF procedureNamePart; + PPH_STRING dllName; + PPH_STRING procedureName; + + i = 0; + + // Get the rundll32.exe part. + + dllName = PhParseCommandLinePart(&CommandLine->sr, &i); + + if (!dllName) + return FALSE; + + PhDereferenceObject(dllName); + + // Get the DLL name part. + + while (i < CommandLine->Length / 2 && CommandLine->Buffer[i] == ' ') + i++; + + dllName = PhParseCommandLinePart(&CommandLine->sr, &i); + + if (!dllName) + return FALSE; + + PH_AUTO(dllName); + + // The procedure name begins after the last comma. + + if (!PhSplitStringRefAtLastChar(&dllName->sr, ',', &dllNamePart, &procedureNamePart)) + return FALSE; + + dllName = PH_AUTO(PhCreateString2(&dllNamePart)); + procedureName = PH_AUTO(PhCreateString2(&procedureNamePart)); + + // If the DLL name isn't an absolute path, assume it's in system32. + // TODO: Use a proper search function. + + if (RtlDetermineDosPathNameType_U(dllName->Buffer) == RtlPathTypeRelative) + { + dllName = PhaConcatStrings( + 3, + PH_AUTO_T(PH_STRING, PhGetSystemDirectory())->Buffer, + L"\\", + dllName->Buffer + ); + } + + KnownCommandLine->RunDllAsApp.FileName = dllName; + KnownCommandLine->RunDllAsApp.ProcedureName = procedureName; + } + break; + case ComSurrogateProcessType: + { + // dllhost.exe /processid: + + static PH_STRINGREF inprocServer32Name = PH_STRINGREF_INIT(L"InprocServer32"); + + SIZE_T i; + ULONG_PTR indexOfProcessId; + PPH_STRING argPart; + PPH_STRING guidString; + UNICODE_STRING guidStringUs; + GUID guid; + HANDLE rootKeyHandle; + HANDLE inprocServer32KeyHandle; + PPH_STRING fileName; + + i = 0; + + // Get the dllhost.exe part. + + argPart = PhParseCommandLinePart(&CommandLine->sr, &i); + + if (!argPart) + return FALSE; + + PhDereferenceObject(argPart); + + // Get the argument part. + + while (i < (ULONG)CommandLine->Length / 2 && CommandLine->Buffer[i] == ' ') + i++; + + argPart = PhParseCommandLinePart(&CommandLine->sr, &i); + + if (!argPart) + return FALSE; + + PH_AUTO(argPart); + + // Find "/processid:"; the GUID is just after that. + + _wcsupr(argPart->Buffer); + indexOfProcessId = PhFindStringInString(argPart, 0, L"/PROCESSID:"); + + if (indexOfProcessId == -1) + return FALSE; + + guidString = PhaSubstring( + argPart, + indexOfProcessId + 11, + (ULONG)argPart->Length / 2 - indexOfProcessId - 11 + ); + PhStringRefToUnicodeString(&guidString->sr, &guidStringUs); + + if (!NT_SUCCESS(RtlGUIDFromString( + &guidStringUs, + &guid + ))) + return FALSE; + + KnownCommandLine->ComSurrogate.Guid = guid; + KnownCommandLine->ComSurrogate.Name = NULL; + KnownCommandLine->ComSurrogate.FileName = NULL; + + // Lookup the GUID in the registry to determine the name and file name. + + if (NT_SUCCESS(PhOpenKey( + &rootKeyHandle, + KEY_READ, + PH_KEY_CLASSES_ROOT, + &PhaConcatStrings2(L"CLSID\\", guidString->Buffer)->sr, + 0 + ))) + { + KnownCommandLine->ComSurrogate.Name = + PH_AUTO(PhQueryRegistryString(rootKeyHandle, NULL)); + + if (NT_SUCCESS(PhOpenKey( + &inprocServer32KeyHandle, + KEY_READ, + rootKeyHandle, + &inprocServer32Name, + 0 + ))) + { + KnownCommandLine->ComSurrogate.FileName = + PH_AUTO(PhQueryRegistryString(inprocServer32KeyHandle, NULL)); + + if (fileName = PH_AUTO(PhExpandEnvironmentStrings( + &KnownCommandLine->ComSurrogate.FileName->sr + ))) + { + KnownCommandLine->ComSurrogate.FileName = fileName; + } + + NtClose(inprocServer32KeyHandle); + } + + NtClose(rootKeyHandle); + } + else if (NT_SUCCESS(PhOpenKey( + &rootKeyHandle, + KEY_READ, + PH_KEY_CLASSES_ROOT, + &PhaConcatStrings2(L"AppID\\", guidString->Buffer)->sr, + 0 + ))) + { + KnownCommandLine->ComSurrogate.Name = + PH_AUTO(PhQueryRegistryString(rootKeyHandle, NULL)); + NtClose(rootKeyHandle); + } + } + break; + default: + return FALSE; + } + + return TRUE; +} + +VOID PhEnumChildWindows( + _In_opt_ HWND hWnd, + _In_ ULONG Limit, + _In_ WNDENUMPROC Callback, + _In_ LPARAM lParam + ) +{ + HWND childWindow = NULL; + ULONG i = 0; + + while (i < Limit && (childWindow = FindWindowEx(hWnd, childWindow, NULL, NULL))) + { + if (!Callback(childWindow, lParam)) + return; + + i++; + } +} + +typedef struct _GET_PROCESS_MAIN_WINDOW_CONTEXT +{ + HWND Window; + HWND ImmersiveWindow; + HANDLE ProcessId; + BOOLEAN IsImmersive; +} GET_PROCESS_MAIN_WINDOW_CONTEXT, *PGET_PROCESS_MAIN_WINDOW_CONTEXT; + +BOOL CALLBACK PhpGetProcessMainWindowEnumWindowsProc( + _In_ HWND hwnd, + _In_ LPARAM lParam + ) +{ + PGET_PROCESS_MAIN_WINDOW_CONTEXT context = (PGET_PROCESS_MAIN_WINDOW_CONTEXT)lParam; + ULONG processId; + HWND parentWindow; + WINDOWINFO windowInfo; + + if (!IsWindowVisible(hwnd)) + return TRUE; + + GetWindowThreadProcessId(hwnd, &processId); + + if (UlongToHandle(processId) == context->ProcessId && + !((parentWindow = GetParent(hwnd)) && IsWindowVisible(parentWindow)) && // skip windows with a visible parent + PhGetWindowTextEx(hwnd, PH_GET_WINDOW_TEXT_INTERNAL | PH_GET_WINDOW_TEXT_LENGTH_ONLY, NULL) != 0) // skip windows with no title + { + if (!context->ImmersiveWindow && context->IsImmersive && + GetProp(hwnd, L"Windows.ImmersiveShell.IdentifyAsMainCoreWindow")) + { + context->ImmersiveWindow = hwnd; + } + + windowInfo.cbSize = sizeof(WINDOWINFO); + + if (!context->Window && GetWindowInfo(hwnd, &windowInfo) && (windowInfo.dwStyle & WS_DLGFRAME)) + { + context->Window = hwnd; + + // If we're not looking at an immersive process, there's no need to search any more windows. + if (!context->IsImmersive) + return FALSE; + } + } + + return TRUE; +} + +HWND PhGetProcessMainWindow( + _In_ HANDLE ProcessId, + _In_opt_ HANDLE ProcessHandle + ) +{ + GET_PROCESS_MAIN_WINDOW_CONTEXT context; + HANDLE processHandle = NULL; + + memset(&context, 0, sizeof(GET_PROCESS_MAIN_WINDOW_CONTEXT)); + context.ProcessId = ProcessId; + + if (ProcessHandle) + processHandle = ProcessHandle; + else + PhOpenProcess(&processHandle, ProcessQueryAccess, ProcessId); + + if (processHandle && IsImmersiveProcess_I) + context.IsImmersive = IsImmersiveProcess_I(processHandle); + + PhEnumChildWindows(NULL, 0x800, PhpGetProcessMainWindowEnumWindowsProc, (LPARAM)&context); + + if (!ProcessHandle && processHandle) + NtClose(processHandle); + + return context.ImmersiveWindow ? context.ImmersiveWindow : context.Window; +} + +PPH_STRING PhGetServiceRelevantFileName( + _In_ PPH_STRINGREF ServiceName, + _In_ SC_HANDLE ServiceHandle + ) +{ + PPH_STRING fileName = NULL; + LPQUERY_SERVICE_CONFIG config; + + if (config = PhGetServiceConfig(ServiceHandle)) + { + PhGetServiceDllParameter(ServiceName, &fileName); + + if (!fileName) + { + PPH_STRING commandLine; + + commandLine = PhCreateString(config->lpBinaryPathName); + + if (config->dwServiceType & SERVICE_WIN32) + { + PH_STRINGREF dummyFileName; + PH_STRINGREF dummyArguments; + + PhParseCommandLineFuzzy(&commandLine->sr, &dummyFileName, &dummyArguments, &fileName); + + if (!fileName) + PhSwapReference(&fileName, commandLine); + } + else + { + fileName = PhGetFileName(commandLine); + } + + PhDereferenceObject(commandLine); + } + + PhFree(config); + } + + return fileName; +} + +PPH_STRING PhEscapeStringForDelimiter( + _In_ PPH_STRING String, + _In_ WCHAR Delimiter + ) +{ + PH_STRING_BUILDER stringBuilder; + SIZE_T length; + SIZE_T i; + WCHAR temp[2]; + + length = String->Length / 2; + PhInitializeStringBuilder(&stringBuilder, String->Length / 2 * 3); + + temp[0] = '\\'; + + for (i = 0; i < length; i++) + { + if (String->Buffer[i] == '\\' || String->Buffer[i] == Delimiter) + { + temp[1] = String->Buffer[i]; + PhAppendStringBuilderEx(&stringBuilder, temp, 4); + } + else + { + PhAppendCharStringBuilder(&stringBuilder, String->Buffer[i]); + } + } + + return PhFinalStringBuilderString(&stringBuilder); +} + +PPH_STRING PhUnescapeStringForDelimiter( + _In_ PPH_STRING String, + _In_ WCHAR Delimiter + ) +{ + PH_STRING_BUILDER stringBuilder; + SIZE_T length; + SIZE_T i; + + length = String->Length / 2; + PhInitializeStringBuilder(&stringBuilder, String->Length / 2 * 3); + + for (i = 0; i < length; i++) + { + if (String->Buffer[i] == '\\') + { + if (i != length - 1) + { + PhAppendCharStringBuilder(&stringBuilder, String->Buffer[i + 1]); + i++; + } + else + { + // Trailing backslash. Just ignore it. + break; + } + } + else + { + PhAppendCharStringBuilder(&stringBuilder, String->Buffer[i]); + } + } + + return PhFinalStringBuilderString(&stringBuilder); +} + +PPH_STRING PhGetOpaqueXmlNodeText( + _In_ mxml_node_t *node + ) +{ + if (node->child && node->child->type == MXML_OPAQUE && node->child->value.opaque) + { + return PhConvertUtf8ToUtf16(node->child->value.opaque); + } + else + { + return PhReferenceEmptyString(); + } +} + +VOID PhSearchOnlineString( + _In_ HWND hWnd, + _In_ PWSTR String + ) +{ + PhShellExecuteUserString(hWnd, L"SearchEngine", String, TRUE, NULL); +} + +VOID PhShellExecuteUserString( + _In_ HWND hWnd, + _In_ PWSTR Setting, + _In_ PWSTR String, + _In_ BOOLEAN UseShellExecute, + _In_opt_ PWSTR ErrorMessage + ) +{ + static PH_STRINGREF replacementToken = PH_STRINGREF_INIT(L"%s"); + + PPH_STRING executeString; + PH_STRINGREF stringBefore; + PH_STRINGREF stringMiddle; + PH_STRINGREF stringAfter; + PPH_STRING ntMessage; + + executeString = PhGetStringSetting(Setting); + + // Make sure the user executable string is absolute. We can't use RtlDetermineDosPathNameType_U + // here because the string may be a URL. + if (PhFindCharInString(executeString, 0, ':') == -1) + PhMoveReference(&executeString, PhConcatStringRef2(&PhApplicationDirectory->sr, &executeString->sr)); + + // Replace the token with the string, or use the original string if the token is not present. + if (PhSplitStringRefAtString(&executeString->sr, &replacementToken, FALSE, &stringBefore, &stringAfter)) + { + PhInitializeStringRef(&stringMiddle, String); + PhMoveReference(&executeString, PhConcatStringRef3(&stringBefore, &stringMiddle, &stringAfter)); + } + + if (UseShellExecute) + { + PhShellExecute(hWnd, executeString->Buffer, NULL); + } + else + { + NTSTATUS status; + + status = PhCreateProcessWin32(NULL, executeString->Buffer, NULL, NULL, 0, NULL, NULL, NULL); + + if (!NT_SUCCESS(status)) + { + if (ErrorMessage) + { + ntMessage = PhGetNtMessage(status); + PhShowError(hWnd, L"Unable to execute the command: %s\n%s", PhGetStringOrDefault(ntMessage, L"An unknown error occurred."), ErrorMessage); + PhDereferenceObject(ntMessage); + } + else + { + PhShowStatus(hWnd, L"Unable to execute the command", status, 0); + } + } + } + + PhDereferenceObject(executeString); +} + +VOID PhLoadSymbolProviderOptions( + _Inout_ PPH_SYMBOL_PROVIDER SymbolProvider + ) +{ + PPH_STRING searchPath; + + PhSetOptionsSymbolProvider( + SYMOPT_UNDNAME, + PhGetIntegerSetting(L"DbgHelpUndecorate") ? SYMOPT_UNDNAME : 0 + ); + + searchPath = PhGetStringSetting(L"DbgHelpSearchPath"); + + if (searchPath->Length != 0) + PhSetSearchPathSymbolProvider(SymbolProvider, searchPath->Buffer); + + PhDereferenceObject(searchPath); +} + +PWSTR PhMakeContextAtom( + VOID + ) +{ + PH_DEFINE_MAKE_ATOM(L"PH2_Context"); +} + +/** + * Copies a string into a NMLVGETINFOTIP structure. + * + * \param GetInfoTip The NMLVGETINFOTIP structure. + * \param Tip The string to copy. + * + * \remarks The text is truncated if it is too long. + */ +VOID PhCopyListViewInfoTip( + _Inout_ LPNMLVGETINFOTIP GetInfoTip, + _In_ PPH_STRINGREF Tip + ) +{ + ULONG copyIndex; + ULONG bufferRemaining; + ULONG copyLength; + + if (GetInfoTip->dwFlags == 0) + { + copyIndex = (ULONG)PhCountStringZ(GetInfoTip->pszText) + 1; // plus one for newline + + if (GetInfoTip->cchTextMax - copyIndex < 2) // need at least two bytes + return; + + bufferRemaining = GetInfoTip->cchTextMax - copyIndex - 1; + GetInfoTip->pszText[copyIndex - 1] = '\n'; + } + else + { + copyIndex = 0; + bufferRemaining = GetInfoTip->cchTextMax; + } + + copyLength = min((ULONG)Tip->Length / 2, bufferRemaining - 1); + memcpy( + &GetInfoTip->pszText[copyIndex], + Tip->Buffer, + copyLength * 2 + ); + GetInfoTip->pszText[copyIndex + copyLength] = 0; +} + +VOID PhCopyListView( + _In_ HWND ListViewHandle + ) +{ + PPH_STRING text; + + text = PhGetListViewText(ListViewHandle); + PhSetClipboardString(ListViewHandle, &text->sr); + PhDereferenceObject(text); +} + +VOID PhHandleListViewNotifyForCopy( + _In_ LPARAM lParam, + _In_ HWND ListViewHandle + ) +{ + PhHandleListViewNotifyBehaviors(lParam, ListViewHandle, PH_LIST_VIEW_CTRL_C_BEHAVIOR); +} + +VOID PhHandleListViewNotifyBehaviors( + _In_ LPARAM lParam, + _In_ HWND ListViewHandle, + _In_ ULONG Behaviors + ) +{ + if (((LPNMHDR)lParam)->hwndFrom == ListViewHandle && ((LPNMHDR)lParam)->code == LVN_KEYDOWN) + { + LPNMLVKEYDOWN keyDown = (LPNMLVKEYDOWN)lParam; + + switch (keyDown->wVKey) + { + case 'C': + if (Behaviors & PH_LIST_VIEW_CTRL_C_BEHAVIOR) + { + if (GetKeyState(VK_CONTROL) < 0) + PhCopyListView(ListViewHandle); + } + break; + case 'A': + if (Behaviors & PH_LIST_VIEW_CTRL_A_BEHAVIOR) + { + if (GetKeyState(VK_CONTROL) < 0) + PhSetStateAllListViewItems(ListViewHandle, LVIS_SELECTED, LVIS_SELECTED); + } + break; + } + } +} + +BOOLEAN PhGetListViewContextMenuPoint( + _In_ HWND ListViewHandle, + _Out_ PPOINT Point + ) +{ + INT selectedIndex; + RECT bounds; + RECT clientRect; + + // The user pressed a key to display the context menu. + // Suggest where the context menu should display. + + if ((selectedIndex = ListView_GetNextItem(ListViewHandle, -1, LVNI_SELECTED)) != -1) + { + if (ListView_GetItemRect(ListViewHandle, selectedIndex, &bounds, LVIR_BOUNDS)) + { + Point->x = bounds.left + PhSmallIconSize.X / 2; + Point->y = bounds.top + PhSmallIconSize.Y / 2; + + GetClientRect(ListViewHandle, &clientRect); + + if (Point->x < 0 || Point->y < 0 || Point->x >= clientRect.right || Point->y >= clientRect.bottom) + { + // The menu is going to be outside of the control. Just put it at the top-left. + Point->x = 0; + Point->y = 0; + } + + ClientToScreen(ListViewHandle, Point); + + return TRUE; + } + } + + Point->x = 0; + Point->y = 0; + ClientToScreen(ListViewHandle, Point); + + return FALSE; +} + +HFONT PhDuplicateFontWithNewWeight( + _In_ HFONT Font, + _In_ LONG NewWeight + ) +{ + LOGFONT logFont; + + if (GetObject(Font, sizeof(LOGFONT), &logFont)) + { + logFont.lfWeight = NewWeight; + return CreateFontIndirect(&logFont); + } + else + { + return NULL; + } +} + +VOID PhSetWindowOpacity( + _In_ HWND WindowHandle, + _In_ ULONG OpacityPercent + ) +{ + if (OpacityPercent == 0) + { + // Make things a bit faster by removing the WS_EX_LAYERED bit. + PhSetWindowExStyle(WindowHandle, WS_EX_LAYERED, 0); + RedrawWindow(WindowHandle, NULL, NULL, RDW_ERASE | RDW_INVALIDATE | RDW_FRAME | RDW_ALLCHILDREN); + return; + } + + PhSetWindowExStyle(WindowHandle, WS_EX_LAYERED, WS_EX_LAYERED); + + // Disallow opacity values of less than 10%. + OpacityPercent = min(OpacityPercent, 90); + + // The opacity value is backwards - 0 means opaque, 100 means transparent. + SetLayeredWindowAttributes( + WindowHandle, + 0, + (BYTE)(255 * (100 - OpacityPercent) / 100), + LWA_ALPHA + ); +} + +VOID PhLoadWindowPlacementFromSetting( + _In_opt_ PWSTR PositionSettingName, + _In_opt_ PWSTR SizeSettingName, + _In_ HWND WindowHandle + ) +{ + PH_RECTANGLE windowRectangle; + + if (PositionSettingName && SizeSettingName) + { + RECT rectForAdjust; + + windowRectangle.Position = PhGetIntegerPairSetting(PositionSettingName); + windowRectangle.Size = PhGetScalableIntegerPairSetting(SizeSettingName, TRUE).Pair; + PhAdjustRectangleToWorkingArea(NULL, &windowRectangle); + + // Let the window adjust for the minimum size if needed. + rectForAdjust = PhRectangleToRect(windowRectangle); + SendMessage(WindowHandle, WM_SIZING, WMSZ_BOTTOMRIGHT, (LPARAM)&rectForAdjust); + windowRectangle = PhRectToRectangle(rectForAdjust); + + MoveWindow(WindowHandle, windowRectangle.Left, windowRectangle.Top, + windowRectangle.Width, windowRectangle.Height, FALSE); + } + else + { + PH_INTEGER_PAIR position; + PH_INTEGER_PAIR size; + ULONG flags; + + flags = SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOREDRAW | SWP_NOSIZE | SWP_NOZORDER; + + if (PositionSettingName) + { + position = PhGetIntegerPairSetting(PositionSettingName); + flags &= ~SWP_NOMOVE; + } + else + { + position.X = 0; + position.Y = 0; + } + + if (SizeSettingName) + { + size = PhGetScalableIntegerPairSetting(SizeSettingName, TRUE).Pair; + flags &= ~SWP_NOSIZE; + } + else + { + size.X = 16; + size.Y = 16; + } + + SetWindowPos(WindowHandle, NULL, position.X, position.Y, size.X, size.Y, flags); + } +} + +VOID PhSaveWindowPlacementToSetting( + _In_opt_ PWSTR PositionSettingName, + _In_opt_ PWSTR SizeSettingName, + _In_ HWND WindowHandle + ) +{ + WINDOWPLACEMENT placement = { sizeof(placement) }; + PH_RECTANGLE windowRectangle; + MONITORINFO monitorInfo = { sizeof(MONITORINFO) }; + + GetWindowPlacement(WindowHandle, &placement); + windowRectangle = PhRectToRectangle(placement.rcNormalPosition); + + // The rectangle is in workspace coordinates. Convert the values back to screen coordinates. + if (GetMonitorInfo(MonitorFromRect(&placement.rcNormalPosition, MONITOR_DEFAULTTOPRIMARY), &monitorInfo)) + { + windowRectangle.Left += monitorInfo.rcWork.left - monitorInfo.rcMonitor.left; + windowRectangle.Top += monitorInfo.rcWork.top - monitorInfo.rcMonitor.top; + } + + if (PositionSettingName) + PhSetIntegerPairSetting(PositionSettingName, windowRectangle.Position); + if (SizeSettingName) + PhSetScalableIntegerPairSetting2(SizeSettingName, windowRectangle.Size); +} + +VOID PhLoadListViewColumnsFromSetting( + _In_ PWSTR Name, + _In_ HWND ListViewHandle + ) +{ + PPH_STRING string; + + string = PhGetStringSetting(Name); + PhLoadListViewColumnSettings(ListViewHandle, string); + PhDereferenceObject(string); +} + +VOID PhSaveListViewColumnsToSetting( + _In_ PWSTR Name, + _In_ HWND ListViewHandle + ) +{ + PPH_STRING string; + + string = PhSaveListViewColumnSettings(ListViewHandle); + PhSetStringSetting2(Name, &string->sr); + PhDereferenceObject(string); +} + +PPH_STRING PhGetPhVersion( + VOID + ) +{ + PH_FORMAT format[5]; + + PhInitFormatU(&format[0], PHAPP_VERSION_MAJOR); + PhInitFormatC(&format[1], '.'); + PhInitFormatU(&format[2], PHAPP_VERSION_MINOR); + PhInitFormatC(&format[3], '.'); + PhInitFormatU(&format[4], PHAPP_VERSION_REVISION); + + return PhFormat(format, 5, 16); +} + +VOID PhGetPhVersionNumbers( + _Out_opt_ PULONG MajorVersion, + _Out_opt_ PULONG MinorVersion, + _Reserved_ PULONG Reserved, + _Out_opt_ PULONG RevisionNumber + ) +{ + if (MajorVersion) + *MajorVersion = PHAPP_VERSION_MAJOR; + if (MinorVersion) + *MinorVersion = PHAPP_VERSION_MINOR; + if (RevisionNumber) + *RevisionNumber = PHAPP_VERSION_REVISION; +} + +VOID PhWritePhTextHeader( + _Inout_ PPH_FILE_STREAM FileStream + ) +{ + PPH_STRING version; + LARGE_INTEGER time; + SYSTEMTIME systemTime; + PPH_STRING dateString; + PPH_STRING timeString; + + PhWriteStringAsUtf8FileStream2(FileStream, L"Process Hacker "); + + if (version = PhGetPhVersion()) + { + PhWriteStringAsUtf8FileStream(FileStream, &version->sr); + PhDereferenceObject(version); + } + + PhWriteStringFormatAsUtf8FileStream(FileStream, L"\r\nWindows NT %u.%u", PhOsVersion.dwMajorVersion, PhOsVersion.dwMinorVersion); + + if (PhOsVersion.szCSDVersion[0] != 0) + PhWriteStringFormatAsUtf8FileStream(FileStream, L" %s", PhOsVersion.szCSDVersion); + +#ifdef _WIN64 + PhWriteStringAsUtf8FileStream2(FileStream, L" (64-bit)"); +#else + PhWriteStringAsUtf8FileStream2(FileStream, L" (32-bit)"); +#endif + + PhQuerySystemTime(&time); + PhLargeIntegerToLocalSystemTime(&systemTime, &time); + + dateString = PhFormatDate(&systemTime, NULL); + timeString = PhFormatTime(&systemTime, NULL); + PhWriteStringFormatAsUtf8FileStream(FileStream, L"\r\n%s %s\r\n\r\n", dateString->Buffer, timeString->Buffer); + PhDereferenceObject(dateString); + PhDereferenceObject(timeString); +} + +BOOLEAN PhShellProcessHacker( + _In_opt_ HWND hWnd, + _In_opt_ PWSTR Parameters, + _In_ ULONG ShowWindowType, + _In_ ULONG Flags, + _In_ ULONG AppFlags, + _In_opt_ ULONG Timeout, + _Out_opt_ PHANDLE ProcessHandle + ) +{ + return PhShellProcessHackerEx( + hWnd, + NULL, + Parameters, + ShowWindowType, + Flags, + AppFlags, + Timeout, + ProcessHandle + ); +} + +VOID PhpAppendCommandLineArgument( + _Inout_ PPH_STRING_BUILDER StringBuilder, + _In_ PWSTR Name, + _In_ PPH_STRINGREF Value + ) +{ + PPH_STRING temp; + + PhAppendStringBuilder2(StringBuilder, L" -"); + PhAppendStringBuilder2(StringBuilder, Name); + PhAppendStringBuilder2(StringBuilder, L" \""); + temp = PhEscapeCommandLinePart(Value); + PhAppendStringBuilder(StringBuilder, &temp->sr); + PhDereferenceObject(temp); + PhAppendCharStringBuilder(StringBuilder, '\"'); +} + +BOOLEAN PhShellProcessHackerEx( + _In_opt_ HWND hWnd, + _In_opt_ PWSTR FileName, + _In_opt_ PWSTR Parameters, + _In_ ULONG ShowWindowType, + _In_ ULONG Flags, + _In_ ULONG AppFlags, + _In_opt_ ULONG Timeout, + _Out_opt_ PHANDLE ProcessHandle + ) +{ + BOOLEAN result; + PH_STRING_BUILDER sb; + PWSTR parameters; + + if (AppFlags & PH_SHELL_APP_PROPAGATE_PARAMETERS) + { + PhInitializeStringBuilder(&sb, 128); + + // Propagate parameters. + + if (PhStartupParameters.NoSettings) + { + PhAppendStringBuilder2(&sb, L" -nosettings"); + } + else if (PhStartupParameters.SettingsFileName && (PhSettingsFileName || (AppFlags & PH_SHELL_APP_PROPAGATE_PARAMETERS_FORCE_SETTINGS))) + { + PPH_STRINGREF fileName; + + if (PhSettingsFileName) + fileName = &PhSettingsFileName->sr; + else + fileName = &PhStartupParameters.SettingsFileName->sr; + + PhpAppendCommandLineArgument(&sb, L"settings", fileName); + } + + if (PhStartupParameters.NoKph) + PhAppendStringBuilder2(&sb, L" -nokph"); + if (PhStartupParameters.InstallKph) + PhAppendStringBuilder2(&sb, L" -installkph"); + if (PhStartupParameters.UninstallKph) + PhAppendStringBuilder2(&sb, L" -uninstallkph"); + if (PhStartupParameters.Debug) + PhAppendStringBuilder2(&sb, L" -debug"); + if (PhStartupParameters.NoPlugins) + PhAppendStringBuilder2(&sb, L" -noplugins"); + if (PhStartupParameters.NewInstance) + PhAppendStringBuilder2(&sb, L" -newinstance"); + + if (PhStartupParameters.SelectPid != 0) + PhAppendFormatStringBuilder(&sb, L" -selectpid %u", PhStartupParameters.SelectPid); + + if (PhStartupParameters.PriorityClass != 0) + { + CHAR value = 0; + + switch (PhStartupParameters.PriorityClass) + { + case PROCESS_PRIORITY_CLASS_REALTIME: + value = L'r'; + break; + case PROCESS_PRIORITY_CLASS_HIGH: + value = L'h'; + break; + case PROCESS_PRIORITY_CLASS_NORMAL: + value = L'n'; + break; + case PROCESS_PRIORITY_CLASS_IDLE: + value = L'l'; + break; + } + + if (value != 0) + { + PhAppendStringBuilder2(&sb, L" -priority "); + PhAppendCharStringBuilder(&sb, value); + } + } + + if (PhStartupParameters.PluginParameters) + { + ULONG i; + + for (i = 0; i < PhStartupParameters.PluginParameters->Count; i++) + { + PPH_STRING value = PhStartupParameters.PluginParameters->Items[i]; + PhpAppendCommandLineArgument(&sb, L"plugin", &value->sr); + } + } + + if (PhStartupParameters.SelectTab) + PhpAppendCommandLineArgument(&sb, L"selecttab", &PhStartupParameters.SelectTab->sr); + + if (!(AppFlags & PH_SHELL_APP_PROPAGATE_PARAMETERS_IGNORE_VISIBILITY)) + { + if (PhStartupParameters.ShowVisible) + PhAppendStringBuilder2(&sb, L" -v"); + if (PhStartupParameters.ShowHidden) + PhAppendStringBuilder2(&sb, L" -hide"); + } + + // Add user-specified parameters last so they can override the propagated parameters. + if (Parameters) + { + PhAppendCharStringBuilder(&sb, ' '); + PhAppendStringBuilder2(&sb, Parameters); + } + + if (sb.String->Length != 0 && sb.String->Buffer[0] == ' ') + parameters = sb.String->Buffer + 1; + else + parameters = sb.String->Buffer; + } + else + { + parameters = Parameters; + } + + result = PhShellExecuteEx( + hWnd, + FileName ? FileName : PhApplicationFileName->Buffer, + parameters, + ShowWindowType, + Flags, + Timeout, + ProcessHandle + ); + + if (AppFlags & PH_SHELL_APP_PROPAGATE_PARAMETERS) + PhDeleteStringBuilder(&sb); + + return result; +} + +BOOLEAN PhCreateProcessIgnoreIfeoDebugger( + _In_ PWSTR FileName + ) +{ + BOOLEAN result; + BOOL (NTAPI *debugSetProcessKillOnExit)(BOOL); + BOOL (NTAPI *debugActiveProcessStop)(DWORD); + BOOLEAN originalValue; + STARTUPINFO startupInfo; + PROCESS_INFORMATION processInfo; + + if (!(debugSetProcessKillOnExit = PhGetModuleProcAddress(L"kernel32.dll", "DebugSetProcessKillOnExit")) || + !(debugActiveProcessStop = PhGetModuleProcAddress(L"kernel32.dll", "DebugActiveProcessStop"))) + return FALSE; + + result = FALSE; + + // This is NOT thread-safe. + originalValue = NtCurrentPeb()->ReadImageFileExecOptions; + NtCurrentPeb()->ReadImageFileExecOptions = FALSE; + + memset(&startupInfo, 0, sizeof(STARTUPINFO)); + startupInfo.cb = sizeof(STARTUPINFO); + memset(&processInfo, 0, sizeof(PROCESS_INFORMATION)); + + // The combination of ReadImageFileExecOptions = FALSE and the DEBUG_PROCESS flag + // allows us to skip the Debugger IFEO value. + if (CreateProcess(FileName, NULL, NULL, NULL, FALSE, DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS, NULL, NULL, &startupInfo, &processInfo)) + { + // Stop debugging the process now. + debugSetProcessKillOnExit(FALSE); + debugActiveProcessStop(processInfo.dwProcessId); + result = TRUE; + } + + if (processInfo.hProcess) + NtClose(processInfo.hProcess); + if (processInfo.hThread) + NtClose(processInfo.hThread); + + NtCurrentPeb()->ReadImageFileExecOptions = originalValue; + + return result; +} + +VOID PhInitializeTreeNewColumnMenu( + _Inout_ PPH_TN_COLUMN_MENU_DATA Data + ) +{ + PhInitializeTreeNewColumnMenuEx(Data, 0); +} + +VOID PhInitializeTreeNewColumnMenuEx( + _Inout_ PPH_TN_COLUMN_MENU_DATA Data, + _In_ ULONG Flags + ) +{ + PPH_EMENU_ITEM resetSortMenuItem = NULL; + PPH_EMENU_ITEM sizeColumnToFitMenuItem; + PPH_EMENU_ITEM sizeAllColumnsToFitMenuItem; + PPH_EMENU_ITEM hideColumnMenuItem; + PPH_EMENU_ITEM chooseColumnsMenuItem; + ULONG minimumNumberOfColumns; + + Data->Menu = PhCreateEMenu(); + Data->Selection = NULL; + Data->ProcessedId = 0; + + sizeColumnToFitMenuItem = PhCreateEMenuItem(0, PH_TN_COLUMN_MENU_SIZE_COLUMN_TO_FIT_ID, L"Size column to fit", NULL, NULL); + sizeAllColumnsToFitMenuItem = PhCreateEMenuItem(0, PH_TN_COLUMN_MENU_SIZE_ALL_COLUMNS_TO_FIT_ID, L"Size all columns to fit", NULL, NULL); + + if (!(Flags & PH_TN_COLUMN_MENU_NO_VISIBILITY)) + { + hideColumnMenuItem = PhCreateEMenuItem(0, PH_TN_COLUMN_MENU_HIDE_COLUMN_ID, L"Hide column", NULL, NULL); + chooseColumnsMenuItem = PhCreateEMenuItem(0, PH_TN_COLUMN_MENU_CHOOSE_COLUMNS_ID, L"Choose columns...", NULL, NULL); + } + + if (Flags & PH_TN_COLUMN_MENU_SHOW_RESET_SORT) + { + ULONG sortColumn; + PH_SORT_ORDER sortOrder; + + TreeNew_GetSort(Data->TreeNewHandle, &sortColumn, &sortOrder); + + if (sortOrder != Data->DefaultSortOrder || (Data->DefaultSortOrder != NoSortOrder && sortColumn != Data->DefaultSortColumn)) + resetSortMenuItem = PhCreateEMenuItem(0, PH_TN_COLUMN_MENU_RESET_SORT_ID, L"Reset sort", NULL, NULL); + } + + PhInsertEMenuItem(Data->Menu, sizeColumnToFitMenuItem, -1); + PhInsertEMenuItem(Data->Menu, sizeAllColumnsToFitMenuItem, -1); + + if (!(Flags & PH_TN_COLUMN_MENU_NO_VISIBILITY)) + { + PhInsertEMenuItem(Data->Menu, hideColumnMenuItem, -1); + + if (resetSortMenuItem) + PhInsertEMenuItem(Data->Menu, resetSortMenuItem, -1); + + PhInsertEMenuItem(Data->Menu, PhCreateEMenuItem(PH_EMENU_SEPARATOR, 0, L"", NULL, NULL), -1); + PhInsertEMenuItem(Data->Menu, chooseColumnsMenuItem, -1); + + if (TreeNew_GetFixedColumn(Data->TreeNewHandle)) + minimumNumberOfColumns = 2; // don't allow user to remove all normal columns (the fixed column can never be removed) + else + minimumNumberOfColumns = 1; + + if (!Data->MouseEvent || !Data->MouseEvent->Column || + Data->MouseEvent->Column->Fixed || // don't allow the fixed column to be hidden + TreeNew_GetVisibleColumnCount(Data->TreeNewHandle) < minimumNumberOfColumns + 1 + ) + { + hideColumnMenuItem->Flags |= PH_EMENU_DISABLED; + } + } + else + { + if (resetSortMenuItem) + PhInsertEMenuItem(Data->Menu, resetSortMenuItem, -1); + } + + if (!Data->MouseEvent || !Data->MouseEvent->Column) + { + sizeColumnToFitMenuItem->Flags |= PH_EMENU_DISABLED; + } +} + +VOID PhpEnsureValidSortColumnTreeNew( + _Inout_ HWND TreeNewHandle, + _In_ ULONG DefaultSortColumn, + _In_ PH_SORT_ORDER DefaultSortOrder + ) +{ + ULONG sortColumn; + PH_SORT_ORDER sortOrder; + + // Make sure the column we're sorting by is actually visible, and if not, don't sort anymore. + + TreeNew_GetSort(TreeNewHandle, &sortColumn, &sortOrder); + + if (sortOrder != NoSortOrder) + { + PH_TREENEW_COLUMN column; + + TreeNew_GetColumn(TreeNewHandle, sortColumn, &column); + + if (!column.Visible) + { + if (DefaultSortOrder != NoSortOrder) + { + // Make sure the default sort column is visible. + TreeNew_GetColumn(TreeNewHandle, DefaultSortColumn, &column); + + if (!column.Visible) + { + ULONG maxId; + ULONG id; + BOOLEAN found; + + // Use the first visible column. + maxId = TreeNew_GetMaxId(TreeNewHandle); + id = 0; + found = FALSE; + + while (id <= maxId) + { + if (TreeNew_GetColumn(TreeNewHandle, id, &column)) + { + if (column.Visible) + { + DefaultSortColumn = id; + found = TRUE; + break; + } + } + + id++; + } + + if (!found) + { + DefaultSortColumn = 0; + DefaultSortOrder = NoSortOrder; + } + } + } + + TreeNew_SetSort(TreeNewHandle, DefaultSortColumn, DefaultSortOrder); + } + } +} + +BOOLEAN PhHandleTreeNewColumnMenu( + _Inout_ PPH_TN_COLUMN_MENU_DATA Data + ) +{ + if (!Data->Selection) + return FALSE; + + switch (Data->Selection->Id) + { + case PH_TN_COLUMN_MENU_RESET_SORT_ID: + { + TreeNew_SetSort(Data->TreeNewHandle, Data->DefaultSortColumn, Data->DefaultSortOrder); + } + break; + case PH_TN_COLUMN_MENU_SIZE_COLUMN_TO_FIT_ID: + { + if (Data->MouseEvent && Data->MouseEvent->Column) + { + TreeNew_AutoSizeColumn(Data->TreeNewHandle, Data->MouseEvent->Column->Id, 0); + } + } + break; + case PH_TN_COLUMN_MENU_SIZE_ALL_COLUMNS_TO_FIT_ID: + { + ULONG maxId; + ULONG id; + + maxId = TreeNew_GetMaxId(Data->TreeNewHandle); + id = 0; + + while (id <= maxId) + { + TreeNew_AutoSizeColumn(Data->TreeNewHandle, id, 0); + id++; + } + } + break; + case PH_TN_COLUMN_MENU_HIDE_COLUMN_ID: + { + PH_TREENEW_COLUMN column; + + if (Data->MouseEvent && Data->MouseEvent->Column && !Data->MouseEvent->Column->Fixed) + { + column.Id = Data->MouseEvent->Column->Id; + column.Visible = FALSE; + TreeNew_SetColumn(Data->TreeNewHandle, TN_COLUMN_FLAG_VISIBLE, &column); + PhpEnsureValidSortColumnTreeNew(Data->TreeNewHandle, Data->DefaultSortColumn, Data->DefaultSortOrder); + InvalidateRect(Data->TreeNewHandle, NULL, FALSE); + } + } + break; + case PH_TN_COLUMN_MENU_CHOOSE_COLUMNS_ID: + { + PhShowChooseColumnsDialog(Data->TreeNewHandle, Data->TreeNewHandle, PH_CONTROL_TYPE_TREE_NEW); + PhpEnsureValidSortColumnTreeNew(Data->TreeNewHandle, Data->DefaultSortColumn, Data->DefaultSortOrder); + } + break; + default: + return FALSE; + } + + Data->ProcessedId = Data->Selection->Id; + + return TRUE; +} + +VOID PhDeleteTreeNewColumnMenu( + _In_ PPH_TN_COLUMN_MENU_DATA Data + ) +{ + if (Data->Menu) + { + PhDestroyEMenu(Data->Menu); + Data->Menu = NULL; + } +} + +VOID PhInitializeTreeNewFilterSupport( + _Out_ PPH_TN_FILTER_SUPPORT Support, + _In_ HWND TreeNewHandle, + _In_ PPH_LIST NodeList + ) +{ + Support->FilterList = NULL; + Support->TreeNewHandle = TreeNewHandle; + Support->NodeList = NodeList; +} + +VOID PhDeleteTreeNewFilterSupport( + _In_ PPH_TN_FILTER_SUPPORT Support + ) +{ + PhDereferenceObject(Support->FilterList); +} + +PPH_TN_FILTER_ENTRY PhAddTreeNewFilter( + _In_ PPH_TN_FILTER_SUPPORT Support, + _In_ PPH_TN_FILTER_FUNCTION Filter, + _In_opt_ PVOID Context + ) +{ + PPH_TN_FILTER_ENTRY entry; + + entry = PhAllocate(sizeof(PH_TN_FILTER_ENTRY)); + entry->Filter = Filter; + entry->Context = Context; + + if (!Support->FilterList) + Support->FilterList = PhCreateList(2); + + PhAddItemList(Support->FilterList, entry); + + return entry; +} + +VOID PhRemoveTreeNewFilter( + _In_ PPH_TN_FILTER_SUPPORT Support, + _In_ PPH_TN_FILTER_ENTRY Entry + ) +{ + ULONG index; + + if (!Support->FilterList) + return; + + index = PhFindItemList(Support->FilterList, Entry); + + if (index != -1) + { + PhRemoveItemList(Support->FilterList, index); + PhFree(Entry); + } +} + +BOOLEAN PhApplyTreeNewFiltersToNode( + _In_ PPH_TN_FILTER_SUPPORT Support, + _In_ PPH_TREENEW_NODE Node + ) +{ + BOOLEAN show; + ULONG i; + + show = TRUE; + + if (Support->FilterList) + { + for (i = 0; i < Support->FilterList->Count; i++) + { + PPH_TN_FILTER_ENTRY entry; + + entry = Support->FilterList->Items[i]; + + if (!entry->Filter(Node, entry->Context)) + { + show = FALSE; + break; + } + } + } + + return show; +} + +VOID PhApplyTreeNewFilters( + _In_ PPH_TN_FILTER_SUPPORT Support + ) +{ + ULONG i; + + for (i = 0; i < Support->NodeList->Count; i++) + { + PPH_TREENEW_NODE node; + + node = Support->NodeList->Items[i]; + node->Visible = PhApplyTreeNewFiltersToNode(Support, node); + + if (!node->Visible && node->Selected) + { + node->Selected = FALSE; + } + } + + TreeNew_NodesStructured(Support->TreeNewHandle); +} + +VOID NTAPI PhpCopyCellEMenuItemDeleteFunction( + _In_ struct _PH_EMENU_ITEM *Item + ) +{ + PPH_COPY_CELL_CONTEXT context; + + context = Item->Context; + PhDereferenceObject(context->MenuItemText); + PhFree(context); +} + +BOOLEAN PhInsertCopyCellEMenuItem( + _In_ struct _PH_EMENU_ITEM *Menu, + _In_ ULONG InsertAfterId, + _In_ HWND TreeNewHandle, + _In_ PPH_TREENEW_COLUMN Column + ) +{ + PPH_EMENU_ITEM parentItem; + ULONG indexInParent; + PPH_COPY_CELL_CONTEXT context; + PH_STRINGREF columnText; + PPH_STRING escapedText; + PPH_STRING menuItemText; + PPH_EMENU_ITEM copyCellItem; + + if (!Column) + return FALSE; + + if (!PhFindEMenuItemEx(Menu, 0, NULL, InsertAfterId, &parentItem, &indexInParent)) + return FALSE; + + indexInParent++; + + context = PhAllocate(sizeof(PH_COPY_CELL_CONTEXT)); + context->TreeNewHandle = TreeNewHandle; + context->Id = Column->Id; + + PhInitializeStringRef(&columnText, Column->Text); + escapedText = PhEscapeStringForMenuPrefix(&columnText); + menuItemText = PhFormatString(L"Copy \"%s\"", escapedText->Buffer); + PhDereferenceObject(escapedText); + copyCellItem = PhCreateEMenuItem(0, ID_COPY_CELL, menuItemText->Buffer, NULL, context); + copyCellItem->DeleteFunction = PhpCopyCellEMenuItemDeleteFunction; + context->MenuItemText = menuItemText; + + if (Column->CustomDraw) + copyCellItem->Flags |= PH_EMENU_DISABLED; + + PhInsertEMenuItem(parentItem, copyCellItem, indexInParent); + + return TRUE; +} + +BOOLEAN PhHandleCopyCellEMenuItem( + _In_ struct _PH_EMENU_ITEM *SelectedItem + ) +{ + PPH_COPY_CELL_CONTEXT context; + PH_STRING_BUILDER stringBuilder; + ULONG count; + ULONG selectedCount; + ULONG i; + PPH_TREENEW_NODE node; + PH_TREENEW_GET_CELL_TEXT getCellText; + + if (!SelectedItem) + return FALSE; + if (SelectedItem->Id != ID_COPY_CELL) + return FALSE; + + context = SelectedItem->Context; + + PhInitializeStringBuilder(&stringBuilder, 0x100); + count = TreeNew_GetFlatNodeCount(context->TreeNewHandle); + selectedCount = 0; + + for (i = 0; i < count; i++) + { + node = TreeNew_GetFlatNode(context->TreeNewHandle, i); + + if (node && node->Selected) + { + selectedCount++; + + getCellText.Flags = 0; + getCellText.Node = node; + getCellText.Id = context->Id; + PhInitializeEmptyStringRef(&getCellText.Text); + TreeNew_GetCellText(context->TreeNewHandle, &getCellText); + + PhAppendStringBuilder(&stringBuilder, &getCellText.Text); + PhAppendStringBuilder2(&stringBuilder, L"\r\n"); + } + } + + if (stringBuilder.String->Length != 0 && selectedCount == 1) + PhRemoveEndStringBuilder(&stringBuilder, 2); + + PhSetClipboardString(context->TreeNewHandle, &stringBuilder.String->sr); + PhDeleteStringBuilder(&stringBuilder); + + return TRUE; +} + +BOOLEAN PhpSelectFavoriteInRegedit( + _In_ HWND RegeditWindow, + _In_ PPH_STRINGREF FavoriteName, + _In_ BOOLEAN UsePhSvc + ) +{ + HMENU menu; + HMENU favoritesMenu; + ULONG count; + ULONG i; + ULONG id = -1; + + if (!(menu = GetMenu(RegeditWindow))) + return FALSE; + + // Cause the Registry Editor to refresh the Favorites menu. + if (UsePhSvc) + PhSvcCallSendMessage(RegeditWindow, WM_MENUSELECT, MAKEWPARAM(3, MF_POPUP), (LPARAM)menu); + else + SendMessage(RegeditWindow, WM_MENUSELECT, MAKEWPARAM(3, MF_POPUP), (LPARAM)menu); + + if (!(favoritesMenu = GetSubMenu(menu, 3))) + return FALSE; + + // Find our entry. + + count = GetMenuItemCount(favoritesMenu); + + if (count == -1) + return FALSE; + if (count > 1000) + count = 1000; + + for (i = 3; i < count; i++) + { + MENUITEMINFO info = { sizeof(MENUITEMINFO) }; + WCHAR buffer[32]; + + info.fMask = MIIM_ID | MIIM_STRING; + info.dwTypeData = buffer; + info.cch = sizeof(buffer) / sizeof(WCHAR); + GetMenuItemInfo(favoritesMenu, i, TRUE, &info); + + if (info.cch == FavoriteName->Length / 2) + { + PH_STRINGREF text; + + text.Buffer = buffer; + text.Length = info.cch * 2; + + if (PhEqualStringRef(&text, FavoriteName, TRUE)) + { + id = info.wID; + break; + } + } + } + + if (id == -1) + return FALSE; + + // Activate our entry. + if (UsePhSvc) + PhSvcCallSendMessage(RegeditWindow, WM_COMMAND, MAKEWPARAM(id, 0), 0); + else + SendMessage(RegeditWindow, WM_COMMAND, MAKEWPARAM(id, 0), 0); + + // "Close" the Favorites menu and restore normal status bar text. + if (UsePhSvc) + PhSvcCallPostMessage(RegeditWindow, WM_MENUSELECT, MAKEWPARAM(0, 0xffff), 0); + else + PostMessage(RegeditWindow, WM_MENUSELECT, MAKEWPARAM(0, 0xffff), 0); + + // Bring regedit to the top. + if (IsIconic(RegeditWindow)) + { + ShowWindow(RegeditWindow, SW_RESTORE); + SetForegroundWindow(RegeditWindow); + } + else + { + SetForegroundWindow(RegeditWindow); + } + + return TRUE; +} + +/** + * Opens a key in the Registry Editor. If the Registry Editor is already open, + * the specified key is selected in the Registry Editor. + * + * \param hWnd A handle to the parent window. + * \param KeyName The key name to open. + */ +BOOLEAN PhShellOpenKey2( + _In_ HWND hWnd, + _In_ PPH_STRING KeyName + ) +{ + static PH_STRINGREF favoritesKeyName = PH_STRINGREF_INIT(L"Software\\Microsoft\\Windows\\CurrentVersion\\Applets\\Regedit\\Favorites"); + + BOOLEAN result = FALSE; + HWND regeditWindow; + HANDLE favoritesKeyHandle; + WCHAR favoriteName[32]; + UNICODE_STRING valueName; + PH_STRINGREF valueNameSr; + PPH_STRING expandedKeyName; + + regeditWindow = FindWindow(L"RegEdit_RegEdit", NULL); + + if (!regeditWindow) + { + PhShellOpenKey(hWnd, KeyName); + return TRUE; + } + + if (!PhGetOwnTokenAttributes().Elevated) + { + if (!PhUiConnectToPhSvc(hWnd, FALSE)) + return FALSE; + } + + // Create our entry in Favorites. + + if (!NT_SUCCESS(PhCreateKey( + &favoritesKeyHandle, + KEY_WRITE, + PH_KEY_CURRENT_USER, + &favoritesKeyName, + 0, + 0, + NULL + ))) + goto CleanupExit; + + memcpy(favoriteName, L"A_ProcessHacker", 15 * sizeof(WCHAR)); + PhGenerateRandomAlphaString(&favoriteName[15], 16); + RtlInitUnicodeString(&valueName, favoriteName); + PhUnicodeStringToStringRef(&valueName, &valueNameSr); + + expandedKeyName = PhExpandKeyName(KeyName, TRUE); + NtSetValueKey(favoritesKeyHandle, &valueName, 0, REG_SZ, expandedKeyName->Buffer, (ULONG)expandedKeyName->Length + 2); + PhDereferenceObject(expandedKeyName); + + // Select our entry in regedit. + result = PhpSelectFavoriteInRegedit(regeditWindow, &valueNameSr, !PhGetOwnTokenAttributes().Elevated); + + NtDeleteValueKey(favoritesKeyHandle, &valueName); + NtClose(favoritesKeyHandle); + +CleanupExit: + if (!PhGetOwnTokenAttributes().Elevated) + PhUiDisconnectFromPhSvc(); + + return result; +} + +PPH_STRING PhPcre2GetErrorMessage( + _In_ INT ErrorCode + ) +{ + PPH_STRING buffer; + SIZE_T bufferLength; + INT_PTR returnLength; + + bufferLength = 128 * sizeof(WCHAR); + buffer = PhCreateStringEx(NULL, bufferLength); + + while (TRUE) + { + if ((returnLength = pcre2_get_error_message(ErrorCode, buffer->Buffer, bufferLength / sizeof(WCHAR) + 1)) >= 0) + break; + + PhDereferenceObject(buffer); + bufferLength *= 2; + + if (bufferLength > 0x1000 * sizeof(WCHAR)) + break; + + buffer = PhCreateStringEx(NULL, bufferLength); + } + + if (returnLength < 0) + return NULL; + + buffer->Length = returnLength * sizeof(WCHAR); + return buffer; +} diff --git a/ProcessHacker/chcol.c b/ProcessHacker/chcol.c index 58f06e824743..5774a3a54550 100644 --- a/ProcessHacker/chcol.c +++ b/ProcessHacker/chcol.c @@ -1,425 +1,425 @@ -/* - * Process Hacker - - * column chooser - * - * Copyright (C) 2010 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include - -#include - -#include - -typedef struct _COLUMNS_DIALOG_CONTEXT -{ - HWND ControlHandle; - ULONG Type; - PPH_LIST Columns; - - HWND InactiveList; - HWND ActiveList; -} COLUMNS_DIALOG_CONTEXT, *PCOLUMNS_DIALOG_CONTEXT; - -INT_PTR CALLBACK PhpColumnsDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -VOID PhShowChooseColumnsDialog( - _In_ HWND ParentWindowHandle, - _In_ HWND ControlHandle, - _In_ ULONG Type - ) -{ - COLUMNS_DIALOG_CONTEXT context; - - context.ControlHandle = ControlHandle; - context.Type = Type; - - if (Type == PH_CONTROL_TYPE_TREE_NEW) - context.Columns = PhCreateList(TreeNew_GetColumnCount(ControlHandle)); - else - return; - - DialogBoxParam( - PhInstanceHandle, - MAKEINTRESOURCE(IDD_CHOOSECOLUMNS), - ParentWindowHandle, - PhpColumnsDlgProc, - (LPARAM)&context - ); - - PhDereferenceObject(context.Columns); -} - -static int __cdecl PhpColumnsCompareDisplayIndexTn( - _In_ const void *elem1, - _In_ const void *elem2 - ) -{ - PPH_TREENEW_COLUMN column1 = *(PPH_TREENEW_COLUMN *)elem1; - PPH_TREENEW_COLUMN column2 = *(PPH_TREENEW_COLUMN *)elem2; - - return uintcmp(column1->DisplayIndex, column2->DisplayIndex); -} - -_Success_(return != -1) -static ULONG IndexOfStringInList( - _In_ PPH_LIST List, - _In_ PWSTR String - ) -{ - ULONG i; - - for (i = 0; i < List->Count; i++) - { - if (PhEqualString2(List->Items[i], String, FALSE)) - return i; - } - - return -1; -} - -INT_PTR CALLBACK PhpColumnsDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - PCOLUMNS_DIALOG_CONTEXT context = NULL; - - if (uMsg == WM_INITDIALOG) - { - context = (PCOLUMNS_DIALOG_CONTEXT)lParam; - SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)context); - } - else - { - context = (PCOLUMNS_DIALOG_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom()); - } - - if (!context) - return FALSE; - - switch (uMsg) - { - case WM_INITDIALOG: - { - ULONG count; - ULONG total; - ULONG i; - PPH_LIST displayOrderList = NULL; - - context->InactiveList = GetDlgItem(hwndDlg, IDC_INACTIVE); - context->ActiveList = GetDlgItem(hwndDlg, IDC_ACTIVE); - PhCenterWindow(hwndDlg, GetParent(hwndDlg)); - - if (context->Type == PH_CONTROL_TYPE_TREE_NEW) - { - PH_TREENEW_COLUMN column; - - count = 0; - total = TreeNew_GetColumnCount(context->ControlHandle); - i = 0; - - displayOrderList = PhCreateList(total); - - while (count < total) - { - if (TreeNew_GetColumn(context->ControlHandle, i, &column)) - { - PPH_TREENEW_COLUMN copy; - - if (column.Fixed) - { - i++; - total--; - continue; - } - - copy = PhAllocateCopy(&column, sizeof(PH_TREENEW_COLUMN)); - PhAddItemList(context->Columns, copy); - count++; - - if (column.Visible) - { - PhAddItemList(displayOrderList, copy); - } - else - { - ListBox_AddString(context->InactiveList, column.Text); - } - } - - i++; - } - - qsort(displayOrderList->Items, displayOrderList->Count, sizeof(PVOID), PhpColumnsCompareDisplayIndexTn); - } - - if (displayOrderList) - { - for (i = 0; i < displayOrderList->Count; i++) - { - if (context->Type == PH_CONTROL_TYPE_TREE_NEW) - { - PPH_TREENEW_COLUMN copy = displayOrderList->Items[i]; - - ListBox_AddString(context->ActiveList, copy->Text); - } - } - - PhDereferenceObject(displayOrderList); - } - - SendMessage(hwndDlg, WM_COMMAND, MAKEWPARAM(IDC_INACTIVE, LBN_SELCHANGE), (LPARAM)context->InactiveList); - SendMessage(hwndDlg, WM_COMMAND, MAKEWPARAM(IDC_ACTIVE, LBN_SELCHANGE), (LPARAM)context->ActiveList); - } - break; - case WM_DESTROY: - { - ULONG i; - - for (i = 0; i < context->Columns->Count; i++) - PhFree(context->Columns->Items[i]); - - RemoveProp(hwndDlg, PhMakeContextAtom()); - } - break; - case WM_COMMAND: - { - switch (LOWORD(wParam)) - { - case IDCANCEL: - EndDialog(hwndDlg, IDCANCEL); - break; - case IDOK: - { -#define ORDER_LIMIT 100 - PPH_LIST activeList; - ULONG activeCount; - ULONG i; - INT orderArray[ORDER_LIMIT]; - INT maxOrder; - - memset(orderArray, 0, sizeof(orderArray)); - maxOrder = 0; - - activeCount = ListBox_GetCount(context->ActiveList); - activeList = PhCreateList(activeCount); - - for (i = 0; i < activeCount; i++) - PhAddItemList(activeList, PhGetListBoxString(context->ActiveList, i)); - - if (context->Type == PH_CONTROL_TYPE_TREE_NEW) - { - // Apply visiblity settings and build the order array. - - TreeNew_SetRedraw(context->ControlHandle, FALSE); - - for (i = 0; i < context->Columns->Count; i++) - { - PPH_TREENEW_COLUMN column = context->Columns->Items[i]; - ULONG index; - - index = IndexOfStringInList(activeList, column->Text); - column->Visible = index != -1; - - TreeNew_SetColumn(context->ControlHandle, TN_COLUMN_FLAG_VISIBLE, column); - - if (column->Visible && index < ORDER_LIMIT) - { - orderArray[index] = column->Id; - - if ((ULONG)maxOrder < index + 1) - maxOrder = index + 1; - } - } - - // Apply display order. - TreeNew_SetColumnOrderArray(context->ControlHandle, maxOrder, orderArray); - - TreeNew_SetRedraw(context->ControlHandle, TRUE); - - PhDereferenceObject(activeList); - - InvalidateRect(context->ControlHandle, NULL, FALSE); - } - - EndDialog(hwndDlg, IDOK); - } - break; - case IDC_INACTIVE: - { - switch (HIWORD(wParam)) - { - case LBN_DBLCLK: - { - SendMessage(hwndDlg, WM_COMMAND, IDC_SHOW, 0); - } - break; - case LBN_SELCHANGE: - { - INT sel = ListBox_GetCurSel(context->InactiveList); - - EnableWindow(GetDlgItem(hwndDlg, IDC_SHOW), sel != -1); - } - break; - } - } - break; - case IDC_ACTIVE: - { - switch (HIWORD(wParam)) - { - case LBN_DBLCLK: - { - SendMessage(hwndDlg, WM_COMMAND, IDC_HIDE, 0); - } - break; - case LBN_SELCHANGE: - { - INT sel = ListBox_GetCurSel(context->ActiveList); - INT count = ListBox_GetCount(context->ActiveList); - - EnableWindow(GetDlgItem(hwndDlg, IDC_HIDE), sel != -1 && count != 1); - EnableWindow(GetDlgItem(hwndDlg, IDC_MOVEUP), sel != 0 && sel != -1); - EnableWindow(GetDlgItem(hwndDlg, IDC_MOVEDOWN), sel != count - 1 && sel != -1); - } - break; - } - } - break; - case IDC_SHOW: - { - INT sel; - INT count; - PPH_STRING string; - - sel = ListBox_GetCurSel(context->InactiveList); - count = ListBox_GetCount(context->InactiveList); - - if (string = PhGetListBoxString(context->InactiveList, sel)) - { - ListBox_DeleteString(context->InactiveList, sel); - ListBox_AddString(context->ActiveList, string->Buffer); - PhDereferenceObject(string); - - count--; - - if (sel >= count - 1) - sel = count - 1; - - ListBox_SetCurSel(context->InactiveList, sel); - - SendMessage(hwndDlg, WM_COMMAND, MAKEWPARAM(IDC_INACTIVE, LBN_SELCHANGE), (LPARAM)context->InactiveList); - SendMessage(hwndDlg, WM_COMMAND, MAKEWPARAM(IDC_ACTIVE, LBN_SELCHANGE), (LPARAM)context->ActiveList); - } - } - break; - case IDC_HIDE: - { - INT sel; - INT count; - PPH_STRING string; - - sel = ListBox_GetCurSel(context->ActiveList); - count = ListBox_GetCount(context->ActiveList); - - if (count != 1) - { - if (string = PhGetListBoxString(context->ActiveList, sel)) - { - ListBox_DeleteString(context->ActiveList, sel); - ListBox_AddString(context->InactiveList, string->Buffer); - PhDereferenceObject(string); - - count--; - - if (sel >= count - 1) - sel = count - 1; - - ListBox_SetCurSel(context->ActiveList, sel); - - SendMessage(hwndDlg, WM_COMMAND, MAKEWPARAM(IDC_INACTIVE, LBN_SELCHANGE), (LPARAM)context->InactiveList); - SendMessage(hwndDlg, WM_COMMAND, MAKEWPARAM(IDC_ACTIVE, LBN_SELCHANGE), (LPARAM)context->ActiveList); - } - } - } - break; - case IDC_MOVEUP: - { - INT sel; - INT count; - PPH_STRING string; - - sel = ListBox_GetCurSel(context->ActiveList); - count = ListBox_GetCount(context->ActiveList); - - if (sel != 0) - { - if (string = PhGetListBoxString(context->ActiveList, sel)) - { - ListBox_DeleteString(context->ActiveList, sel); - ListBox_InsertString(context->ActiveList, sel - 1, string->Buffer); - PhDereferenceObject(string); - - sel -= 1; - ListBox_SetCurSel(context->ActiveList, sel); - EnableWindow(GetDlgItem(hwndDlg, IDC_MOVEUP), sel != 0); - EnableWindow(GetDlgItem(hwndDlg, IDC_MOVEDOWN), sel != count - 1); - } - } - } - break; - case IDC_MOVEDOWN: - { - INT sel; - INT count; - PPH_STRING string; - - sel = ListBox_GetCurSel(context->ActiveList); - count = ListBox_GetCount(context->ActiveList); - - if (sel != count - 1) - { - if (string = PhGetListBoxString(context->ActiveList, sel)) - { - ListBox_DeleteString(context->ActiveList, sel); - ListBox_InsertString(context->ActiveList, sel + 1, string->Buffer); - PhDereferenceObject(string); - - sel += 1; - ListBox_SetCurSel(context->ActiveList, sel); - EnableWindow(GetDlgItem(hwndDlg, IDC_MOVEUP), sel != 0); - EnableWindow(GetDlgItem(hwndDlg, IDC_MOVEDOWN), sel != count - 1); - } - } - } - break; - } - } - break; - } - - return FALSE; -} +/* + * Process Hacker - + * column chooser + * + * Copyright (C) 2010 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include + +#include + +#include + +typedef struct _COLUMNS_DIALOG_CONTEXT +{ + HWND ControlHandle; + ULONG Type; + PPH_LIST Columns; + + HWND InactiveList; + HWND ActiveList; +} COLUMNS_DIALOG_CONTEXT, *PCOLUMNS_DIALOG_CONTEXT; + +INT_PTR CALLBACK PhpColumnsDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +VOID PhShowChooseColumnsDialog( + _In_ HWND ParentWindowHandle, + _In_ HWND ControlHandle, + _In_ ULONG Type + ) +{ + COLUMNS_DIALOG_CONTEXT context; + + context.ControlHandle = ControlHandle; + context.Type = Type; + + if (Type == PH_CONTROL_TYPE_TREE_NEW) + context.Columns = PhCreateList(TreeNew_GetColumnCount(ControlHandle)); + else + return; + + DialogBoxParam( + PhInstanceHandle, + MAKEINTRESOURCE(IDD_CHOOSECOLUMNS), + ParentWindowHandle, + PhpColumnsDlgProc, + (LPARAM)&context + ); + + PhDereferenceObject(context.Columns); +} + +static int __cdecl PhpColumnsCompareDisplayIndexTn( + _In_ const void *elem1, + _In_ const void *elem2 + ) +{ + PPH_TREENEW_COLUMN column1 = *(PPH_TREENEW_COLUMN *)elem1; + PPH_TREENEW_COLUMN column2 = *(PPH_TREENEW_COLUMN *)elem2; + + return uintcmp(column1->DisplayIndex, column2->DisplayIndex); +} + +_Success_(return != -1) +static ULONG IndexOfStringInList( + _In_ PPH_LIST List, + _In_ PWSTR String + ) +{ + ULONG i; + + for (i = 0; i < List->Count; i++) + { + if (PhEqualString2(List->Items[i], String, FALSE)) + return i; + } + + return -1; +} + +INT_PTR CALLBACK PhpColumnsDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + PCOLUMNS_DIALOG_CONTEXT context = NULL; + + if (uMsg == WM_INITDIALOG) + { + context = (PCOLUMNS_DIALOG_CONTEXT)lParam; + SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)context); + } + else + { + context = (PCOLUMNS_DIALOG_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom()); + } + + if (!context) + return FALSE; + + switch (uMsg) + { + case WM_INITDIALOG: + { + ULONG count; + ULONG total; + ULONG i; + PPH_LIST displayOrderList = NULL; + + context->InactiveList = GetDlgItem(hwndDlg, IDC_INACTIVE); + context->ActiveList = GetDlgItem(hwndDlg, IDC_ACTIVE); + PhCenterWindow(hwndDlg, GetParent(hwndDlg)); + + if (context->Type == PH_CONTROL_TYPE_TREE_NEW) + { + PH_TREENEW_COLUMN column; + + count = 0; + total = TreeNew_GetColumnCount(context->ControlHandle); + i = 0; + + displayOrderList = PhCreateList(total); + + while (count < total) + { + if (TreeNew_GetColumn(context->ControlHandle, i, &column)) + { + PPH_TREENEW_COLUMN copy; + + if (column.Fixed) + { + i++; + total--; + continue; + } + + copy = PhAllocateCopy(&column, sizeof(PH_TREENEW_COLUMN)); + PhAddItemList(context->Columns, copy); + count++; + + if (column.Visible) + { + PhAddItemList(displayOrderList, copy); + } + else + { + ListBox_AddString(context->InactiveList, column.Text); + } + } + + i++; + } + + qsort(displayOrderList->Items, displayOrderList->Count, sizeof(PVOID), PhpColumnsCompareDisplayIndexTn); + } + + if (displayOrderList) + { + for (i = 0; i < displayOrderList->Count; i++) + { + if (context->Type == PH_CONTROL_TYPE_TREE_NEW) + { + PPH_TREENEW_COLUMN copy = displayOrderList->Items[i]; + + ListBox_AddString(context->ActiveList, copy->Text); + } + } + + PhDereferenceObject(displayOrderList); + } + + SendMessage(hwndDlg, WM_COMMAND, MAKEWPARAM(IDC_INACTIVE, LBN_SELCHANGE), (LPARAM)context->InactiveList); + SendMessage(hwndDlg, WM_COMMAND, MAKEWPARAM(IDC_ACTIVE, LBN_SELCHANGE), (LPARAM)context->ActiveList); + } + break; + case WM_DESTROY: + { + ULONG i; + + for (i = 0; i < context->Columns->Count; i++) + PhFree(context->Columns->Items[i]); + + RemoveProp(hwndDlg, PhMakeContextAtom()); + } + break; + case WM_COMMAND: + { + switch (LOWORD(wParam)) + { + case IDCANCEL: + EndDialog(hwndDlg, IDCANCEL); + break; + case IDOK: + { +#define ORDER_LIMIT 100 + PPH_LIST activeList; + ULONG activeCount; + ULONG i; + INT orderArray[ORDER_LIMIT]; + INT maxOrder; + + memset(orderArray, 0, sizeof(orderArray)); + maxOrder = 0; + + activeCount = ListBox_GetCount(context->ActiveList); + activeList = PhCreateList(activeCount); + + for (i = 0; i < activeCount; i++) + PhAddItemList(activeList, PhGetListBoxString(context->ActiveList, i)); + + if (context->Type == PH_CONTROL_TYPE_TREE_NEW) + { + // Apply visiblity settings and build the order array. + + TreeNew_SetRedraw(context->ControlHandle, FALSE); + + for (i = 0; i < context->Columns->Count; i++) + { + PPH_TREENEW_COLUMN column = context->Columns->Items[i]; + ULONG index; + + index = IndexOfStringInList(activeList, column->Text); + column->Visible = index != -1; + + TreeNew_SetColumn(context->ControlHandle, TN_COLUMN_FLAG_VISIBLE, column); + + if (column->Visible && index < ORDER_LIMIT) + { + orderArray[index] = column->Id; + + if ((ULONG)maxOrder < index + 1) + maxOrder = index + 1; + } + } + + // Apply display order. + TreeNew_SetColumnOrderArray(context->ControlHandle, maxOrder, orderArray); + + TreeNew_SetRedraw(context->ControlHandle, TRUE); + + PhDereferenceObject(activeList); + + InvalidateRect(context->ControlHandle, NULL, FALSE); + } + + EndDialog(hwndDlg, IDOK); + } + break; + case IDC_INACTIVE: + { + switch (HIWORD(wParam)) + { + case LBN_DBLCLK: + { + SendMessage(hwndDlg, WM_COMMAND, IDC_SHOW, 0); + } + break; + case LBN_SELCHANGE: + { + INT sel = ListBox_GetCurSel(context->InactiveList); + + EnableWindow(GetDlgItem(hwndDlg, IDC_SHOW), sel != -1); + } + break; + } + } + break; + case IDC_ACTIVE: + { + switch (HIWORD(wParam)) + { + case LBN_DBLCLK: + { + SendMessage(hwndDlg, WM_COMMAND, IDC_HIDE, 0); + } + break; + case LBN_SELCHANGE: + { + INT sel = ListBox_GetCurSel(context->ActiveList); + INT count = ListBox_GetCount(context->ActiveList); + + EnableWindow(GetDlgItem(hwndDlg, IDC_HIDE), sel != -1 && count != 1); + EnableWindow(GetDlgItem(hwndDlg, IDC_MOVEUP), sel != 0 && sel != -1); + EnableWindow(GetDlgItem(hwndDlg, IDC_MOVEDOWN), sel != count - 1 && sel != -1); + } + break; + } + } + break; + case IDC_SHOW: + { + INT sel; + INT count; + PPH_STRING string; + + sel = ListBox_GetCurSel(context->InactiveList); + count = ListBox_GetCount(context->InactiveList); + + if (string = PhGetListBoxString(context->InactiveList, sel)) + { + ListBox_DeleteString(context->InactiveList, sel); + ListBox_AddString(context->ActiveList, string->Buffer); + PhDereferenceObject(string); + + count--; + + if (sel >= count - 1) + sel = count - 1; + + ListBox_SetCurSel(context->InactiveList, sel); + + SendMessage(hwndDlg, WM_COMMAND, MAKEWPARAM(IDC_INACTIVE, LBN_SELCHANGE), (LPARAM)context->InactiveList); + SendMessage(hwndDlg, WM_COMMAND, MAKEWPARAM(IDC_ACTIVE, LBN_SELCHANGE), (LPARAM)context->ActiveList); + } + } + break; + case IDC_HIDE: + { + INT sel; + INT count; + PPH_STRING string; + + sel = ListBox_GetCurSel(context->ActiveList); + count = ListBox_GetCount(context->ActiveList); + + if (count != 1) + { + if (string = PhGetListBoxString(context->ActiveList, sel)) + { + ListBox_DeleteString(context->ActiveList, sel); + ListBox_AddString(context->InactiveList, string->Buffer); + PhDereferenceObject(string); + + count--; + + if (sel >= count - 1) + sel = count - 1; + + ListBox_SetCurSel(context->ActiveList, sel); + + SendMessage(hwndDlg, WM_COMMAND, MAKEWPARAM(IDC_INACTIVE, LBN_SELCHANGE), (LPARAM)context->InactiveList); + SendMessage(hwndDlg, WM_COMMAND, MAKEWPARAM(IDC_ACTIVE, LBN_SELCHANGE), (LPARAM)context->ActiveList); + } + } + } + break; + case IDC_MOVEUP: + { + INT sel; + INT count; + PPH_STRING string; + + sel = ListBox_GetCurSel(context->ActiveList); + count = ListBox_GetCount(context->ActiveList); + + if (sel != 0) + { + if (string = PhGetListBoxString(context->ActiveList, sel)) + { + ListBox_DeleteString(context->ActiveList, sel); + ListBox_InsertString(context->ActiveList, sel - 1, string->Buffer); + PhDereferenceObject(string); + + sel -= 1; + ListBox_SetCurSel(context->ActiveList, sel); + EnableWindow(GetDlgItem(hwndDlg, IDC_MOVEUP), sel != 0); + EnableWindow(GetDlgItem(hwndDlg, IDC_MOVEDOWN), sel != count - 1); + } + } + } + break; + case IDC_MOVEDOWN: + { + INT sel; + INT count; + PPH_STRING string; + + sel = ListBox_GetCurSel(context->ActiveList); + count = ListBox_GetCount(context->ActiveList); + + if (sel != count - 1) + { + if (string = PhGetListBoxString(context->ActiveList, sel)) + { + ListBox_DeleteString(context->ActiveList, sel); + ListBox_InsertString(context->ActiveList, sel + 1, string->Buffer); + PhDereferenceObject(string); + + sel += 1; + ListBox_SetCurSel(context->ActiveList, sel); + EnableWindow(GetDlgItem(hwndDlg, IDC_MOVEUP), sel != 0); + EnableWindow(GetDlgItem(hwndDlg, IDC_MOVEDOWN), sel != count - 1); + } + } + } + break; + } + } + break; + } + + return FALSE; +} diff --git a/ProcessHacker/chdlg.c b/ProcessHacker/chdlg.c index 97c4bdac6eee..bb4683bc5d0e 100644 --- a/ProcessHacker/chdlg.c +++ b/ProcessHacker/chdlg.c @@ -1,360 +1,360 @@ -/* - * Process Hacker - - * choice dialog - * - * Copyright (C) 2010-2013 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include - -#include - -#include - -typedef struct _CHOICE_DIALOG_CONTEXT -{ - PWSTR Title; - PWSTR Message; - PWSTR *Choices; - ULONG NumberOfChoices; - PWSTR Option; - ULONG Flags; - PPH_STRING *SelectedChoice; - PBOOLEAN SelectedOption; - PWSTR SavedChoicesSettingName; - - HWND ComboBoxHandle; -} CHOICE_DIALOG_CONTEXT, *PCHOICE_DIALOG_CONTEXT; - -INT_PTR CALLBACK PhpChoiceDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -/** - * Prompts the user for input. - * - * \remarks If \c PH_CHOICE_DIALOG_PASSWORD is specified, the string - * returned in \a SelectedChoice is NOT auto-dereferenced. - */ -BOOLEAN PhaChoiceDialog( - _In_ HWND ParentWindowHandle, - _In_ PWSTR Title, - _In_ PWSTR Message, - _In_opt_ PWSTR *Choices, - _In_opt_ ULONG NumberOfChoices, - _In_opt_ PWSTR Option, - _In_ ULONG Flags, - _Inout_ PPH_STRING *SelectedChoice, - _Inout_opt_ PBOOLEAN SelectedOption, - _In_opt_ PWSTR SavedChoicesSettingName - ) -{ - CHOICE_DIALOG_CONTEXT context; - - context.Title = Title; - context.Message = Message; - context.Choices = Choices; - context.NumberOfChoices = NumberOfChoices; - context.Option = Option; - context.Flags = Flags; - context.SelectedChoice = SelectedChoice; - context.SelectedOption = SelectedOption; - context.SavedChoicesSettingName = SavedChoicesSettingName; - - return DialogBoxParam( - PhInstanceHandle, - MAKEINTRESOURCE(IDD_CHOOSE), - ParentWindowHandle, - PhpChoiceDlgProc, - (LPARAM)&context - ) == IDOK; -} - -INT_PTR CALLBACK PhpChoiceDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - switch (uMsg) - { - case WM_INITDIALOG: - { - PCHOICE_DIALOG_CONTEXT context = (PCHOICE_DIALOG_CONTEXT)lParam; - ULONG type; - SIZE_T i; - HWND comboBoxHandle; - HWND checkBoxHandle; - RECT checkBoxRect; - RECT rect; - ULONG diff; - - SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)context); - PhCenterWindow(hwndDlg, GetParent(hwndDlg)); - - SetWindowText(hwndDlg, context->Title); - SetWindowText(GetDlgItem(hwndDlg, IDC_MESSAGE), context->Message); - - type = context->Flags & PH_CHOICE_DIALOG_TYPE_MASK; - - // Select the control to show, depending on the type. This is - // because it is impossible to change the style of the combo box - // after it is created. - switch (type) - { - case PH_CHOICE_DIALOG_USER_CHOICE: - comboBoxHandle = GetDlgItem(hwndDlg, IDC_CHOICEUSER); - ShowWindow(GetDlgItem(hwndDlg, IDC_CHOICEUSER), SW_SHOW); - break; - case PH_CHOICE_DIALOG_PASSWORD: - comboBoxHandle = GetDlgItem(hwndDlg, IDC_CHOICESIMPLE); - ShowWindow(GetDlgItem(hwndDlg, IDC_CHOICESIMPLE), SW_SHOW); - - // Disable combo box features since it isn't a combo box. - context->SavedChoicesSettingName = NULL; - break; - case PH_CHOICE_DIALOG_CHOICE: - default: - comboBoxHandle = GetDlgItem(hwndDlg, IDC_CHOICE); - ShowWindow(GetDlgItem(hwndDlg, IDC_CHOICE), SW_SHOW); - break; - } - - context->ComboBoxHandle = comboBoxHandle; - - checkBoxHandle = GetDlgItem(hwndDlg, IDC_OPTION); - - if (type == PH_CHOICE_DIALOG_PASSWORD) - { - // Nothing - } - else if (type == PH_CHOICE_DIALOG_USER_CHOICE && context->SavedChoicesSettingName) - { - PPH_STRING savedChoices = PhGetStringSetting(context->SavedChoicesSettingName); - ULONG_PTR indexOfDelim; - PPH_STRING savedChoice; - - i = 0; - - // Split the saved choices using the delimiter. - while (i < savedChoices->Length / 2) - { - // BUG BUG BUG - what if the user saves "\s"? - indexOfDelim = PhFindStringInString(savedChoices, i, L"\\s"); - - if (indexOfDelim == -1) - indexOfDelim = savedChoices->Length / 2; - - savedChoice = PhSubstring(savedChoices, i, indexOfDelim - i); - - if (savedChoice->Length != 0) - { - PPH_STRING unescaped; - - unescaped = PhUnescapeStringForDelimiter(savedChoice, '\\'); - ComboBox_InsertString(comboBoxHandle, -1, unescaped->Buffer); - PhDereferenceObject(unescaped); - } - - PhDereferenceObject(savedChoice); - - i = indexOfDelim + 2; - } - - PhDereferenceObject(savedChoices); - } - else - { - for (i = 0; i < context->NumberOfChoices; i++) - { - ComboBox_AddString(comboBoxHandle, context->Choices[i]); - } - - context->SavedChoicesSettingName = NULL; // make sure we don't try to save the choices - } - - if (type == PH_CHOICE_DIALOG_PASSWORD) - { - if (*context->SelectedChoice) - SetWindowText(comboBoxHandle, (*context->SelectedChoice)->Buffer); - - Edit_SetSel(comboBoxHandle, 0, -1); - } - else if (type == PH_CHOICE_DIALOG_USER_CHOICE || type == PH_CHOICE_DIALOG_CHOICE) - { - // If we failed to choose a default choice based on what was specified, - // select the first one if possible, or set the text directly. - if (!(*context->SelectedChoice) || PhSelectComboBoxString( - comboBoxHandle, (*context->SelectedChoice)->Buffer, FALSE) == CB_ERR) - { - if (type == PH_CHOICE_DIALOG_USER_CHOICE && *context->SelectedChoice) - { - SetWindowText(comboBoxHandle, (*context->SelectedChoice)->Buffer); - } - else if (type == PH_CHOICE_DIALOG_CHOICE && context->NumberOfChoices != 0) - { - ComboBox_SetCurSel(comboBoxHandle, 0); - } - } - - if (type == PH_CHOICE_DIALOG_USER_CHOICE) - ComboBox_SetEditSel(comboBoxHandle, 0, -1); - } - - if (context->Option) - { - SetWindowText(checkBoxHandle, context->Option); - - if (context->SelectedOption) - Button_SetCheck(checkBoxHandle, *context->SelectedOption ? BST_CHECKED : BST_UNCHECKED); - } - else - { - // Hide the check box and move the buttons up. - - ShowWindow(checkBoxHandle, SW_HIDE); - GetWindowRect(checkBoxHandle, &checkBoxRect); - MapWindowPoints(NULL, hwndDlg, (POINT *)&checkBoxRect, 2); - GetWindowRect(GetDlgItem(hwndDlg, IDOK), &rect); - MapWindowPoints(NULL, hwndDlg, (POINT *)&rect, 2); - diff = rect.top - checkBoxRect.top; - - // OK - rect.top -= diff; - rect.bottom -= diff; - SetWindowPos(GetDlgItem(hwndDlg, IDOK), NULL, rect.left, rect.top, - rect.right - rect.left, rect.bottom - rect.top, - SWP_NOACTIVATE | SWP_NOZORDER); - - // Cancel - GetWindowRect(GetDlgItem(hwndDlg, IDCANCEL), &rect); - MapWindowPoints(NULL, hwndDlg, (POINT *)&rect, 2); - rect.top -= diff; - rect.bottom -= diff; - SetWindowPos(GetDlgItem(hwndDlg, IDCANCEL), NULL, rect.left, rect.top, - rect.right - rect.left, rect.bottom - rect.top, - SWP_NOACTIVATE | SWP_NOZORDER); - - // Window - GetWindowRect(hwndDlg, &rect); - rect.bottom -= diff; - SetWindowPos(hwndDlg, NULL, rect.left, rect.top, - rect.right - rect.left, rect.bottom - rect.top, - SWP_NOACTIVATE | SWP_NOZORDER); - } - - SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)comboBoxHandle, TRUE); - } - break; - case WM_DESTROY: - { - RemoveProp(hwndDlg, PhMakeContextAtom()); - } - break; - case WM_COMMAND: - { - switch (LOWORD(wParam)) - { - case IDCANCEL: - EndDialog(hwndDlg, IDCANCEL); - break; - case IDOK: - { - PCHOICE_DIALOG_CONTEXT context = (PCHOICE_DIALOG_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom()); - PPH_STRING selectedChoice; - - if ((context->Flags & PH_CHOICE_DIALOG_TYPE_MASK) != PH_CHOICE_DIALOG_PASSWORD) - { - selectedChoice = PH_AUTO(PhGetWindowText(context->ComboBoxHandle)); - *context->SelectedChoice = selectedChoice; - } - else - { - // Password values are never auto-dereferenced. - selectedChoice = PhGetWindowText(context->ComboBoxHandle); - *context->SelectedChoice = selectedChoice; - } - - if (context->Option && context->SelectedOption) - *context->SelectedOption = Button_GetCheck(GetDlgItem(hwndDlg, IDC_OPTION)) == BST_CHECKED; - - if (context->SavedChoicesSettingName) - { - PH_STRING_BUILDER savedChoices; - ULONG i; - ULONG choicesToSave = PH_CHOICE_DIALOG_SAVED_CHOICES; - PPH_STRING choice; - PPH_STRING escaped; - - PhInitializeStringBuilder(&savedChoices, 100); - - // Push the selected choice to the top, then save the others. - - if (selectedChoice->Length != 0) - { - escaped = PhEscapeStringForDelimiter(selectedChoice, '\\'); - PhAppendStringBuilder(&savedChoices, &escaped->sr); - PhDereferenceObject(escaped); - PhAppendStringBuilder2(&savedChoices, L"\\s"); - } - - for (i = 1; i < choicesToSave; i++) - { - choice = PhGetComboBoxString(context->ComboBoxHandle, i - 1); - - if (!choice) - break; - - // Don't save the choice if it's the same as the one - // entered by the user (since we already saved it above). - if (PhEqualString(choice, selectedChoice, FALSE)) - { - PhDereferenceObject(choice); - choicesToSave++; // useless for now, but may be needed in the future - continue; - } - - escaped = PhEscapeStringForDelimiter(choice, '\\'); - PhAppendStringBuilder(&savedChoices, &escaped->sr); - PhDereferenceObject(escaped); - PhDereferenceObject(choice); - - PhAppendStringBuilder2(&savedChoices, L"\\s"); - } - - if (PhEndsWithString2(savedChoices.String, L"\\s", FALSE)) - PhRemoveEndStringBuilder(&savedChoices, 2); - - PhSetStringSetting2(context->SavedChoicesSettingName, &savedChoices.String->sr); - PhDeleteStringBuilder(&savedChoices); - } - - EndDialog(hwndDlg, IDOK); - } - break; - } - } - break; - } - - return FALSE; -} +/* + * Process Hacker - + * choice dialog + * + * Copyright (C) 2010-2013 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include + +#include + +#include + +typedef struct _CHOICE_DIALOG_CONTEXT +{ + PWSTR Title; + PWSTR Message; + PWSTR *Choices; + ULONG NumberOfChoices; + PWSTR Option; + ULONG Flags; + PPH_STRING *SelectedChoice; + PBOOLEAN SelectedOption; + PWSTR SavedChoicesSettingName; + + HWND ComboBoxHandle; +} CHOICE_DIALOG_CONTEXT, *PCHOICE_DIALOG_CONTEXT; + +INT_PTR CALLBACK PhpChoiceDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +/** + * Prompts the user for input. + * + * \remarks If \c PH_CHOICE_DIALOG_PASSWORD is specified, the string + * returned in \a SelectedChoice is NOT auto-dereferenced. + */ +BOOLEAN PhaChoiceDialog( + _In_ HWND ParentWindowHandle, + _In_ PWSTR Title, + _In_ PWSTR Message, + _In_opt_ PWSTR *Choices, + _In_opt_ ULONG NumberOfChoices, + _In_opt_ PWSTR Option, + _In_ ULONG Flags, + _Inout_ PPH_STRING *SelectedChoice, + _Inout_opt_ PBOOLEAN SelectedOption, + _In_opt_ PWSTR SavedChoicesSettingName + ) +{ + CHOICE_DIALOG_CONTEXT context; + + context.Title = Title; + context.Message = Message; + context.Choices = Choices; + context.NumberOfChoices = NumberOfChoices; + context.Option = Option; + context.Flags = Flags; + context.SelectedChoice = SelectedChoice; + context.SelectedOption = SelectedOption; + context.SavedChoicesSettingName = SavedChoicesSettingName; + + return DialogBoxParam( + PhInstanceHandle, + MAKEINTRESOURCE(IDD_CHOOSE), + ParentWindowHandle, + PhpChoiceDlgProc, + (LPARAM)&context + ) == IDOK; +} + +INT_PTR CALLBACK PhpChoiceDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + switch (uMsg) + { + case WM_INITDIALOG: + { + PCHOICE_DIALOG_CONTEXT context = (PCHOICE_DIALOG_CONTEXT)lParam; + ULONG type; + SIZE_T i; + HWND comboBoxHandle; + HWND checkBoxHandle; + RECT checkBoxRect; + RECT rect; + ULONG diff; + + SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)context); + PhCenterWindow(hwndDlg, GetParent(hwndDlg)); + + SetWindowText(hwndDlg, context->Title); + SetWindowText(GetDlgItem(hwndDlg, IDC_MESSAGE), context->Message); + + type = context->Flags & PH_CHOICE_DIALOG_TYPE_MASK; + + // Select the control to show, depending on the type. This is + // because it is impossible to change the style of the combo box + // after it is created. + switch (type) + { + case PH_CHOICE_DIALOG_USER_CHOICE: + comboBoxHandle = GetDlgItem(hwndDlg, IDC_CHOICEUSER); + ShowWindow(GetDlgItem(hwndDlg, IDC_CHOICEUSER), SW_SHOW); + break; + case PH_CHOICE_DIALOG_PASSWORD: + comboBoxHandle = GetDlgItem(hwndDlg, IDC_CHOICESIMPLE); + ShowWindow(GetDlgItem(hwndDlg, IDC_CHOICESIMPLE), SW_SHOW); + + // Disable combo box features since it isn't a combo box. + context->SavedChoicesSettingName = NULL; + break; + case PH_CHOICE_DIALOG_CHOICE: + default: + comboBoxHandle = GetDlgItem(hwndDlg, IDC_CHOICE); + ShowWindow(GetDlgItem(hwndDlg, IDC_CHOICE), SW_SHOW); + break; + } + + context->ComboBoxHandle = comboBoxHandle; + + checkBoxHandle = GetDlgItem(hwndDlg, IDC_OPTION); + + if (type == PH_CHOICE_DIALOG_PASSWORD) + { + // Nothing + } + else if (type == PH_CHOICE_DIALOG_USER_CHOICE && context->SavedChoicesSettingName) + { + PPH_STRING savedChoices = PhGetStringSetting(context->SavedChoicesSettingName); + ULONG_PTR indexOfDelim; + PPH_STRING savedChoice; + + i = 0; + + // Split the saved choices using the delimiter. + while (i < savedChoices->Length / 2) + { + // BUG BUG BUG - what if the user saves "\s"? + indexOfDelim = PhFindStringInString(savedChoices, i, L"\\s"); + + if (indexOfDelim == -1) + indexOfDelim = savedChoices->Length / 2; + + savedChoice = PhSubstring(savedChoices, i, indexOfDelim - i); + + if (savedChoice->Length != 0) + { + PPH_STRING unescaped; + + unescaped = PhUnescapeStringForDelimiter(savedChoice, '\\'); + ComboBox_InsertString(comboBoxHandle, -1, unescaped->Buffer); + PhDereferenceObject(unescaped); + } + + PhDereferenceObject(savedChoice); + + i = indexOfDelim + 2; + } + + PhDereferenceObject(savedChoices); + } + else + { + for (i = 0; i < context->NumberOfChoices; i++) + { + ComboBox_AddString(comboBoxHandle, context->Choices[i]); + } + + context->SavedChoicesSettingName = NULL; // make sure we don't try to save the choices + } + + if (type == PH_CHOICE_DIALOG_PASSWORD) + { + if (*context->SelectedChoice) + SetWindowText(comboBoxHandle, (*context->SelectedChoice)->Buffer); + + Edit_SetSel(comboBoxHandle, 0, -1); + } + else if (type == PH_CHOICE_DIALOG_USER_CHOICE || type == PH_CHOICE_DIALOG_CHOICE) + { + // If we failed to choose a default choice based on what was specified, + // select the first one if possible, or set the text directly. + if (!(*context->SelectedChoice) || PhSelectComboBoxString( + comboBoxHandle, (*context->SelectedChoice)->Buffer, FALSE) == CB_ERR) + { + if (type == PH_CHOICE_DIALOG_USER_CHOICE && *context->SelectedChoice) + { + SetWindowText(comboBoxHandle, (*context->SelectedChoice)->Buffer); + } + else if (type == PH_CHOICE_DIALOG_CHOICE && context->NumberOfChoices != 0) + { + ComboBox_SetCurSel(comboBoxHandle, 0); + } + } + + if (type == PH_CHOICE_DIALOG_USER_CHOICE) + ComboBox_SetEditSel(comboBoxHandle, 0, -1); + } + + if (context->Option) + { + SetWindowText(checkBoxHandle, context->Option); + + if (context->SelectedOption) + Button_SetCheck(checkBoxHandle, *context->SelectedOption ? BST_CHECKED : BST_UNCHECKED); + } + else + { + // Hide the check box and move the buttons up. + + ShowWindow(checkBoxHandle, SW_HIDE); + GetWindowRect(checkBoxHandle, &checkBoxRect); + MapWindowPoints(NULL, hwndDlg, (POINT *)&checkBoxRect, 2); + GetWindowRect(GetDlgItem(hwndDlg, IDOK), &rect); + MapWindowPoints(NULL, hwndDlg, (POINT *)&rect, 2); + diff = rect.top - checkBoxRect.top; + + // OK + rect.top -= diff; + rect.bottom -= diff; + SetWindowPos(GetDlgItem(hwndDlg, IDOK), NULL, rect.left, rect.top, + rect.right - rect.left, rect.bottom - rect.top, + SWP_NOACTIVATE | SWP_NOZORDER); + + // Cancel + GetWindowRect(GetDlgItem(hwndDlg, IDCANCEL), &rect); + MapWindowPoints(NULL, hwndDlg, (POINT *)&rect, 2); + rect.top -= diff; + rect.bottom -= diff; + SetWindowPos(GetDlgItem(hwndDlg, IDCANCEL), NULL, rect.left, rect.top, + rect.right - rect.left, rect.bottom - rect.top, + SWP_NOACTIVATE | SWP_NOZORDER); + + // Window + GetWindowRect(hwndDlg, &rect); + rect.bottom -= diff; + SetWindowPos(hwndDlg, NULL, rect.left, rect.top, + rect.right - rect.left, rect.bottom - rect.top, + SWP_NOACTIVATE | SWP_NOZORDER); + } + + SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)comboBoxHandle, TRUE); + } + break; + case WM_DESTROY: + { + RemoveProp(hwndDlg, PhMakeContextAtom()); + } + break; + case WM_COMMAND: + { + switch (LOWORD(wParam)) + { + case IDCANCEL: + EndDialog(hwndDlg, IDCANCEL); + break; + case IDOK: + { + PCHOICE_DIALOG_CONTEXT context = (PCHOICE_DIALOG_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom()); + PPH_STRING selectedChoice; + + if ((context->Flags & PH_CHOICE_DIALOG_TYPE_MASK) != PH_CHOICE_DIALOG_PASSWORD) + { + selectedChoice = PH_AUTO(PhGetWindowText(context->ComboBoxHandle)); + *context->SelectedChoice = selectedChoice; + } + else + { + // Password values are never auto-dereferenced. + selectedChoice = PhGetWindowText(context->ComboBoxHandle); + *context->SelectedChoice = selectedChoice; + } + + if (context->Option && context->SelectedOption) + *context->SelectedOption = Button_GetCheck(GetDlgItem(hwndDlg, IDC_OPTION)) == BST_CHECKED; + + if (context->SavedChoicesSettingName) + { + PH_STRING_BUILDER savedChoices; + ULONG i; + ULONG choicesToSave = PH_CHOICE_DIALOG_SAVED_CHOICES; + PPH_STRING choice; + PPH_STRING escaped; + + PhInitializeStringBuilder(&savedChoices, 100); + + // Push the selected choice to the top, then save the others. + + if (selectedChoice->Length != 0) + { + escaped = PhEscapeStringForDelimiter(selectedChoice, '\\'); + PhAppendStringBuilder(&savedChoices, &escaped->sr); + PhDereferenceObject(escaped); + PhAppendStringBuilder2(&savedChoices, L"\\s"); + } + + for (i = 1; i < choicesToSave; i++) + { + choice = PhGetComboBoxString(context->ComboBoxHandle, i - 1); + + if (!choice) + break; + + // Don't save the choice if it's the same as the one + // entered by the user (since we already saved it above). + if (PhEqualString(choice, selectedChoice, FALSE)) + { + PhDereferenceObject(choice); + choicesToSave++; // useless for now, but may be needed in the future + continue; + } + + escaped = PhEscapeStringForDelimiter(choice, '\\'); + PhAppendStringBuilder(&savedChoices, &escaped->sr); + PhDereferenceObject(escaped); + PhDereferenceObject(choice); + + PhAppendStringBuilder2(&savedChoices, L"\\s"); + } + + if (PhEndsWithString2(savedChoices.String, L"\\s", FALSE)) + PhRemoveEndStringBuilder(&savedChoices, 2); + + PhSetStringSetting2(context->SavedChoicesSettingName, &savedChoices.String->sr); + PhDeleteStringBuilder(&savedChoices); + } + + EndDialog(hwndDlg, IDOK); + } + break; + } + } + break; + } + + return FALSE; +} diff --git a/ProcessHacker/chproc.c b/ProcessHacker/chproc.c index ef2b32659a40..fd0578842349 100644 --- a/ProcessHacker/chproc.c +++ b/ProcessHacker/chproc.c @@ -1,316 +1,316 @@ -/* - * Process Hacker - - * choose process dialog - * - * Copyright (C) 2010 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include - -#include - -typedef struct _CHOOSE_PROCESS_DIALOG_CONTEXT -{ - PWSTR Message; - HANDLE ProcessId; - - PH_LAYOUT_MANAGER LayoutManager; - RECT MinimumSize; - HIMAGELIST ImageList; - HWND ListViewHandle; -} CHOOSE_PROCESS_DIALOG_CONTEXT, *PCHOOSE_PROCESS_DIALOG_CONTEXT; - -INT_PTR CALLBACK PhpChooseProcessDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -BOOLEAN PhShowChooseProcessDialog( - _In_ HWND ParentWindowHandle, - _In_ PWSTR Message, - _Out_ PHANDLE ProcessId - ) -{ - CHOOSE_PROCESS_DIALOG_CONTEXT context; - - context.Message = Message; - context.ProcessId = NULL; - - if (DialogBoxParam( - PhInstanceHandle, - MAKEINTRESOURCE(IDD_CHOOSEPROCESS), - ParentWindowHandle, - PhpChooseProcessDlgProc, - (LPARAM)&context - ) == IDOK) - { - *ProcessId = context.ProcessId; - - return TRUE; - } - else - { - return FALSE; - } -} - -static VOID PhpRefreshProcessList( - _In_ HWND hwndDlg, - _In_ PCHOOSE_PROCESS_DIALOG_CONTEXT Context - ) -{ - NTSTATUS status; - HWND lvHandle; - PVOID processes; - PSYSTEM_PROCESS_INFORMATION process; - - lvHandle = Context->ListViewHandle; - - if (!NT_SUCCESS(status = PhEnumProcesses(&processes))) - { - PhShowStatus(hwndDlg, L"Unable to enumerate processes", status, 0); - return; - } - - ExtendedListView_SetRedraw(lvHandle, FALSE); - - ListView_DeleteAllItems(lvHandle); - ImageList_RemoveAll(Context->ImageList); - - process = PH_FIRST_PROCESS(processes); - - do - { - INT lvItemIndex; - PPH_STRING name; - HANDLE processHandle; - PPH_STRING fileName = NULL; - HICON icon = NULL; - WCHAR processIdString[PH_INT32_STR_LEN_1]; - PPH_STRING userName = NULL; - INT imageIndex; - - if (process->UniqueProcessId != SYSTEM_IDLE_PROCESS_ID) - name = PhCreateStringFromUnicodeString(&process->ImageName); - else - name = PhCreateString(SYSTEM_IDLE_PROCESS_NAME); - - lvItemIndex = PhAddListViewItem(lvHandle, MAXINT, name->Buffer, process->UniqueProcessId); - PhDereferenceObject(name); - - if (NT_SUCCESS(PhOpenProcess(&processHandle, ProcessQueryAccess, process->UniqueProcessId))) - { - HANDLE tokenHandle; - PTOKEN_USER user; - - if (!WINDOWS_HAS_IMAGE_FILE_NAME_BY_PROCESS_ID && process->UniqueProcessId != SYSTEM_PROCESS_ID) - PhGetProcessImageFileName(processHandle, &fileName); - - if (NT_SUCCESS(PhOpenProcessToken(processHandle, TOKEN_QUERY, &tokenHandle))) - { - if (NT_SUCCESS(PhGetTokenUser(tokenHandle, &user))) - { - userName = PhGetSidFullName(user->User.Sid, TRUE, NULL); - PhFree(user); - } - - NtClose(tokenHandle); - } - - NtClose(processHandle); - } - - if (process->UniqueProcessId == SYSTEM_IDLE_PROCESS_ID && !userName && PhLocalSystemName) - PhSetReference(&userName, PhLocalSystemName); - - if (WINDOWS_HAS_IMAGE_FILE_NAME_BY_PROCESS_ID && process->UniqueProcessId != SYSTEM_PROCESS_ID) - PhGetProcessImageFileNameByProcessId(process->UniqueProcessId, &fileName); - - if (process->UniqueProcessId == SYSTEM_PROCESS_ID) - fileName = PhGetKernelFileName(); - - if (fileName) - PhMoveReference(&fileName, PhGetFileName(fileName)); - - icon = PhGetFileShellIcon(PhGetString(fileName), L".exe", FALSE); - - // Icon - if (icon) - { - imageIndex = ImageList_AddIcon(Context->ImageList, icon); - PhSetListViewItemImageIndex(Context->ListViewHandle, lvItemIndex, imageIndex); - DestroyIcon(icon); - } - - // PID - PhPrintUInt32(processIdString, HandleToUlong(process->UniqueProcessId)); - PhSetListViewSubItem(Context->ListViewHandle, lvItemIndex, 1, processIdString); - - // User Name - PhSetListViewSubItem(Context->ListViewHandle, lvItemIndex, 2, PhGetString(userName)); - - if (userName) PhDereferenceObject(userName); - if (fileName) PhDereferenceObject(fileName); - } while (process = PH_NEXT_PROCESS(process)); - - PhFree(processes); - - ExtendedListView_SortItems(lvHandle); - ExtendedListView_SetRedraw(lvHandle, TRUE); -} - -INT_PTR CALLBACK PhpChooseProcessDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - PCHOOSE_PROCESS_DIALOG_CONTEXT context = NULL; - - if (uMsg == WM_INITDIALOG) - { - context = (PCHOOSE_PROCESS_DIALOG_CONTEXT)lParam; - SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)context); - } - else - { - context = (PCHOOSE_PROCESS_DIALOG_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom()); - - if (uMsg == WM_DESTROY) - { - RemoveProp(hwndDlg, PhMakeContextAtom()); - } - } - - if (!context) - return FALSE; - - switch (uMsg) - { - case WM_INITDIALOG: - { - HWND lvHandle; - - PhCenterWindow(hwndDlg, GetParent(hwndDlg)); - - SetDlgItemText(hwndDlg, IDC_MESSAGE, context->Message); - - PhInitializeLayoutManager(&context->LayoutManager, hwndDlg); - PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_MESSAGE), NULL, - PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT | PH_LAYOUT_FORCE_INVALIDATE); - PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_LIST), NULL, - PH_ANCHOR_ALL); - PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDOK), NULL, - PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); - PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDCANCEL), NULL, - PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); - PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_REFRESH), NULL, - PH_ANCHOR_BOTTOM | PH_ANCHOR_LEFT); - PhLayoutManagerLayout(&context->LayoutManager); - - context->MinimumSize.left = 0; - context->MinimumSize.top = 0; - context->MinimumSize.right = 280; - context->MinimumSize.bottom = 170; - MapDialogRect(hwndDlg, &context->MinimumSize); - - context->ListViewHandle = lvHandle = GetDlgItem(hwndDlg, IDC_LIST); - context->ImageList = ImageList_Create(PhSmallIconSize.X, PhSmallIconSize.Y, ILC_COLOR32 | ILC_MASK, 0, 40); - - PhSetListViewStyle(lvHandle, FALSE, TRUE); - PhSetControlTheme(lvHandle, L"explorer"); - PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 180, L"Name"); - PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 60, L"PID"); - PhAddListViewColumn(lvHandle, 2, 2, 2, LVCFMT_LEFT, 160, L"User name"); - PhSetExtendedListView(lvHandle); - - ListView_SetImageList(lvHandle, context->ImageList, LVSIL_SMALL); - - PhpRefreshProcessList(hwndDlg, context); - - EnableWindow(GetDlgItem(hwndDlg, IDOK), FALSE); - } - break; - case WM_DESTROY: - { - ImageList_Destroy(context->ImageList); - PhDeleteLayoutManager(&context->LayoutManager); - } - break; - case WM_COMMAND: - { - switch (LOWORD(wParam)) - { - case IDCANCEL: - { - EndDialog(hwndDlg, IDCANCEL); - } - break; - case IDOK: - { - if (ListView_GetSelectedCount(context->ListViewHandle) == 1) - { - context->ProcessId = (HANDLE)PhGetSelectedListViewItemParam(context->ListViewHandle); - EndDialog(hwndDlg, IDOK); - } - } - break; - case IDC_REFRESH: - { - PhpRefreshProcessList(hwndDlg, context); - } - break; - } - } - break; - case WM_NOTIFY: - { - LPNMHDR header = (LPNMHDR)lParam; - - switch (header->code) - { - case LVN_ITEMCHANGED: - { - EnableWindow(GetDlgItem(hwndDlg, IDOK), ListView_GetSelectedCount(context->ListViewHandle) == 1); - } - break; - case NM_DBLCLK: - { - SendMessage(hwndDlg, WM_COMMAND, IDOK, 0); - } - break; - } - } - break; - case WM_SIZE: - { - PhLayoutManagerLayout(&context->LayoutManager); - } - break; - case WM_SIZING: - { - PhResizingMinimumSize((PRECT)lParam, wParam, context->MinimumSize.right, context->MinimumSize.bottom); - } - break; - } - - return FALSE; -} +/* + * Process Hacker - + * choose process dialog + * + * Copyright (C) 2010 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include + +#include + +typedef struct _CHOOSE_PROCESS_DIALOG_CONTEXT +{ + PWSTR Message; + HANDLE ProcessId; + + PH_LAYOUT_MANAGER LayoutManager; + RECT MinimumSize; + HIMAGELIST ImageList; + HWND ListViewHandle; +} CHOOSE_PROCESS_DIALOG_CONTEXT, *PCHOOSE_PROCESS_DIALOG_CONTEXT; + +INT_PTR CALLBACK PhpChooseProcessDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +BOOLEAN PhShowChooseProcessDialog( + _In_ HWND ParentWindowHandle, + _In_ PWSTR Message, + _Out_ PHANDLE ProcessId + ) +{ + CHOOSE_PROCESS_DIALOG_CONTEXT context; + + context.Message = Message; + context.ProcessId = NULL; + + if (DialogBoxParam( + PhInstanceHandle, + MAKEINTRESOURCE(IDD_CHOOSEPROCESS), + ParentWindowHandle, + PhpChooseProcessDlgProc, + (LPARAM)&context + ) == IDOK) + { + *ProcessId = context.ProcessId; + + return TRUE; + } + else + { + return FALSE; + } +} + +static VOID PhpRefreshProcessList( + _In_ HWND hwndDlg, + _In_ PCHOOSE_PROCESS_DIALOG_CONTEXT Context + ) +{ + NTSTATUS status; + HWND lvHandle; + PVOID processes; + PSYSTEM_PROCESS_INFORMATION process; + + lvHandle = Context->ListViewHandle; + + if (!NT_SUCCESS(status = PhEnumProcesses(&processes))) + { + PhShowStatus(hwndDlg, L"Unable to enumerate processes", status, 0); + return; + } + + ExtendedListView_SetRedraw(lvHandle, FALSE); + + ListView_DeleteAllItems(lvHandle); + ImageList_RemoveAll(Context->ImageList); + + process = PH_FIRST_PROCESS(processes); + + do + { + INT lvItemIndex; + PPH_STRING name; + HANDLE processHandle; + PPH_STRING fileName = NULL; + HICON icon = NULL; + WCHAR processIdString[PH_INT32_STR_LEN_1]; + PPH_STRING userName = NULL; + INT imageIndex; + + if (process->UniqueProcessId != SYSTEM_IDLE_PROCESS_ID) + name = PhCreateStringFromUnicodeString(&process->ImageName); + else + name = PhCreateString(SYSTEM_IDLE_PROCESS_NAME); + + lvItemIndex = PhAddListViewItem(lvHandle, MAXINT, name->Buffer, process->UniqueProcessId); + PhDereferenceObject(name); + + if (NT_SUCCESS(PhOpenProcess(&processHandle, ProcessQueryAccess, process->UniqueProcessId))) + { + HANDLE tokenHandle; + PTOKEN_USER user; + + if (!WINDOWS_HAS_IMAGE_FILE_NAME_BY_PROCESS_ID && process->UniqueProcessId != SYSTEM_PROCESS_ID) + PhGetProcessImageFileName(processHandle, &fileName); + + if (NT_SUCCESS(PhOpenProcessToken(processHandle, TOKEN_QUERY, &tokenHandle))) + { + if (NT_SUCCESS(PhGetTokenUser(tokenHandle, &user))) + { + userName = PhGetSidFullName(user->User.Sid, TRUE, NULL); + PhFree(user); + } + + NtClose(tokenHandle); + } + + NtClose(processHandle); + } + + if (process->UniqueProcessId == SYSTEM_IDLE_PROCESS_ID && !userName && PhLocalSystemName) + PhSetReference(&userName, PhLocalSystemName); + + if (WINDOWS_HAS_IMAGE_FILE_NAME_BY_PROCESS_ID && process->UniqueProcessId != SYSTEM_PROCESS_ID) + PhGetProcessImageFileNameByProcessId(process->UniqueProcessId, &fileName); + + if (process->UniqueProcessId == SYSTEM_PROCESS_ID) + fileName = PhGetKernelFileName(); + + if (fileName) + PhMoveReference(&fileName, PhGetFileName(fileName)); + + icon = PhGetFileShellIcon(PhGetString(fileName), L".exe", FALSE); + + // Icon + if (icon) + { + imageIndex = ImageList_AddIcon(Context->ImageList, icon); + PhSetListViewItemImageIndex(Context->ListViewHandle, lvItemIndex, imageIndex); + DestroyIcon(icon); + } + + // PID + PhPrintUInt32(processIdString, HandleToUlong(process->UniqueProcessId)); + PhSetListViewSubItem(Context->ListViewHandle, lvItemIndex, 1, processIdString); + + // User Name + PhSetListViewSubItem(Context->ListViewHandle, lvItemIndex, 2, PhGetString(userName)); + + if (userName) PhDereferenceObject(userName); + if (fileName) PhDereferenceObject(fileName); + } while (process = PH_NEXT_PROCESS(process)); + + PhFree(processes); + + ExtendedListView_SortItems(lvHandle); + ExtendedListView_SetRedraw(lvHandle, TRUE); +} + +INT_PTR CALLBACK PhpChooseProcessDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + PCHOOSE_PROCESS_DIALOG_CONTEXT context = NULL; + + if (uMsg == WM_INITDIALOG) + { + context = (PCHOOSE_PROCESS_DIALOG_CONTEXT)lParam; + SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)context); + } + else + { + context = (PCHOOSE_PROCESS_DIALOG_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom()); + + if (uMsg == WM_DESTROY) + { + RemoveProp(hwndDlg, PhMakeContextAtom()); + } + } + + if (!context) + return FALSE; + + switch (uMsg) + { + case WM_INITDIALOG: + { + HWND lvHandle; + + PhCenterWindow(hwndDlg, GetParent(hwndDlg)); + + SetDlgItemText(hwndDlg, IDC_MESSAGE, context->Message); + + PhInitializeLayoutManager(&context->LayoutManager, hwndDlg); + PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_MESSAGE), NULL, + PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT | PH_LAYOUT_FORCE_INVALIDATE); + PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_LIST), NULL, + PH_ANCHOR_ALL); + PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDOK), NULL, + PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); + PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDCANCEL), NULL, + PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); + PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_REFRESH), NULL, + PH_ANCHOR_BOTTOM | PH_ANCHOR_LEFT); + PhLayoutManagerLayout(&context->LayoutManager); + + context->MinimumSize.left = 0; + context->MinimumSize.top = 0; + context->MinimumSize.right = 280; + context->MinimumSize.bottom = 170; + MapDialogRect(hwndDlg, &context->MinimumSize); + + context->ListViewHandle = lvHandle = GetDlgItem(hwndDlg, IDC_LIST); + context->ImageList = ImageList_Create(PhSmallIconSize.X, PhSmallIconSize.Y, ILC_COLOR32 | ILC_MASK, 0, 40); + + PhSetListViewStyle(lvHandle, FALSE, TRUE); + PhSetControlTheme(lvHandle, L"explorer"); + PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 180, L"Name"); + PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 60, L"PID"); + PhAddListViewColumn(lvHandle, 2, 2, 2, LVCFMT_LEFT, 160, L"User name"); + PhSetExtendedListView(lvHandle); + + ListView_SetImageList(lvHandle, context->ImageList, LVSIL_SMALL); + + PhpRefreshProcessList(hwndDlg, context); + + EnableWindow(GetDlgItem(hwndDlg, IDOK), FALSE); + } + break; + case WM_DESTROY: + { + ImageList_Destroy(context->ImageList); + PhDeleteLayoutManager(&context->LayoutManager); + } + break; + case WM_COMMAND: + { + switch (LOWORD(wParam)) + { + case IDCANCEL: + { + EndDialog(hwndDlg, IDCANCEL); + } + break; + case IDOK: + { + if (ListView_GetSelectedCount(context->ListViewHandle) == 1) + { + context->ProcessId = (HANDLE)PhGetSelectedListViewItemParam(context->ListViewHandle); + EndDialog(hwndDlg, IDOK); + } + } + break; + case IDC_REFRESH: + { + PhpRefreshProcessList(hwndDlg, context); + } + break; + } + } + break; + case WM_NOTIFY: + { + LPNMHDR header = (LPNMHDR)lParam; + + switch (header->code) + { + case LVN_ITEMCHANGED: + { + EnableWindow(GetDlgItem(hwndDlg, IDOK), ListView_GetSelectedCount(context->ListViewHandle) == 1); + } + break; + case NM_DBLCLK: + { + SendMessage(hwndDlg, WM_COMMAND, IDOK, 0); + } + break; + } + } + break; + case WM_SIZE: + { + PhLayoutManagerLayout(&context->LayoutManager); + } + break; + case WM_SIZING: + { + PhResizingMinimumSize((PRECT)lParam, wParam, context->MinimumSize.right, context->MinimumSize.bottom); + } + break; + } + + return FALSE; +} diff --git a/ProcessHacker/cmdmode.c b/ProcessHacker/cmdmode.c index c47b048ecef2..481e03937358 100644 --- a/ProcessHacker/cmdmode.c +++ b/ProcessHacker/cmdmode.c @@ -1,452 +1,452 @@ -/* - * Process Hacker - - * command line action mode - * - * Copyright (C) 2010-2012 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include - -#include - -NTSTATUS PhpGetDllBaseRemote( - _In_ HANDLE ProcessHandle, - _In_ PPH_STRINGREF BaseDllName, - _Out_ PVOID *DllBase - ); - -static HWND CommandModeWindowHandle; - -#define PH_COMMAND_OPTION_HWND 1 - -BOOLEAN NTAPI PhpCommandModeOptionCallback( - _In_opt_ PPH_COMMAND_LINE_OPTION Option, - _In_opt_ PPH_STRING Value, - _In_opt_ PVOID Context - ) -{ - ULONG64 integer; - - if (Option) - { - switch (Option->Id) - { - case PH_COMMAND_OPTION_HWND: - if (PhStringToInteger64(&Value->sr, 10, &integer)) - CommandModeWindowHandle = (HWND)integer; - break; - } - } - - return TRUE; -} - -NTSTATUS PhCommandModeStart( - VOID - ) -{ - static PH_COMMAND_LINE_OPTION options[] = - { - { PH_COMMAND_OPTION_HWND, L"hwnd", MandatoryArgumentType } - }; - NTSTATUS status = STATUS_SUCCESS; - PH_STRINGREF commandLine; - - PhUnicodeStringToStringRef(&NtCurrentPeb()->ProcessParameters->CommandLine, &commandLine); - - PhParseCommandLine( - &commandLine, - options, - sizeof(options) / sizeof(PH_COMMAND_LINE_OPTION), - PH_COMMAND_LINE_IGNORE_UNKNOWN_OPTIONS, - PhpCommandModeOptionCallback, - NULL - ); - - if (PhEqualString2(PhStartupParameters.CommandType, L"process", TRUE)) - { - SIZE_T i; - SIZE_T processIdLength; - HANDLE processId; - HANDLE processHandle; - - if (!PhStartupParameters.CommandObject) - return STATUS_INVALID_PARAMETER; - - processIdLength = PhStartupParameters.CommandObject->Length / 2; - - for (i = 0; i < processIdLength; i++) - { - if (!PhIsDigitCharacter(PhStartupParameters.CommandObject->Buffer[i])) - break; - } - - if (i == processIdLength) - { - ULONG64 processId64; - - if (!PhStringToInteger64(&PhStartupParameters.CommandObject->sr, 10, &processId64)) - return STATUS_INVALID_PARAMETER; - - processId = (HANDLE)processId64; - } - else - { - PVOID processes; - PSYSTEM_PROCESS_INFORMATION process; - - if (!NT_SUCCESS(status = PhEnumProcesses(&processes))) - return status; - - if (!(process = PhFindProcessInformationByImageName(processes, &PhStartupParameters.CommandObject->sr))) - { - PhFree(processes); - return STATUS_NOT_FOUND; - } - - processId = process->UniqueProcessId; - PhFree(processes); - } - - if (PhEqualString2(PhStartupParameters.CommandAction, L"terminate", TRUE)) - { - if (NT_SUCCESS(status = PhOpenProcessPublic(&processHandle, PROCESS_TERMINATE, processId))) - { - status = NtTerminateProcess(processHandle, STATUS_SUCCESS); - NtClose(processHandle); - } - } - else if (PhEqualString2(PhStartupParameters.CommandAction, L"suspend", TRUE)) - { - if (NT_SUCCESS(status = PhOpenProcessPublic(&processHandle, PROCESS_SUSPEND_RESUME, processId))) - { - status = NtSuspendProcess(processHandle); - NtClose(processHandle); - } - } - else if (PhEqualString2(PhStartupParameters.CommandAction, L"resume", TRUE)) - { - if (NT_SUCCESS(status = PhOpenProcessPublic(&processHandle, PROCESS_SUSPEND_RESUME, processId))) - { - status = NtResumeProcess(processHandle); - NtClose(processHandle); - } - } - else if (PhEqualString2(PhStartupParameters.CommandAction, L"priority", TRUE)) - { - UCHAR priority; - - if (!PhStartupParameters.CommandValue) - return STATUS_INVALID_PARAMETER; - - if (PhEqualString2(PhStartupParameters.CommandValue, L"idle", TRUE)) - priority = PROCESS_PRIORITY_CLASS_IDLE; - else if (PhEqualString2(PhStartupParameters.CommandValue, L"normal", TRUE)) - priority = PROCESS_PRIORITY_CLASS_NORMAL; - else if (PhEqualString2(PhStartupParameters.CommandValue, L"high", TRUE)) - priority = PROCESS_PRIORITY_CLASS_HIGH; - else if (PhEqualString2(PhStartupParameters.CommandValue, L"realtime", TRUE)) - priority = PROCESS_PRIORITY_CLASS_REALTIME; - else if (PhEqualString2(PhStartupParameters.CommandValue, L"abovenormal", TRUE)) - priority = PROCESS_PRIORITY_CLASS_ABOVE_NORMAL; - else if (PhEqualString2(PhStartupParameters.CommandValue, L"belownormal", TRUE)) - priority = PROCESS_PRIORITY_CLASS_BELOW_NORMAL; - else - return STATUS_INVALID_PARAMETER; - - if (NT_SUCCESS(status = PhOpenProcessPublic(&processHandle, PROCESS_SET_INFORMATION, processId))) - { - PROCESS_PRIORITY_CLASS priorityClass; - priorityClass.Foreground = FALSE; - priorityClass.PriorityClass = priority; - status = NtSetInformationProcess(processHandle, ProcessPriorityClass, &priorityClass, sizeof(PROCESS_PRIORITY_CLASS)); - NtClose(processHandle); - } - } - else if (PhEqualString2(PhStartupParameters.CommandAction, L"iopriority", TRUE)) - { - ULONG ioPriority; - - if (!PhStartupParameters.CommandValue) - return STATUS_INVALID_PARAMETER; - - if (PhEqualString2(PhStartupParameters.CommandValue, L"verylow", TRUE)) - ioPriority = 0; - else if (PhEqualString2(PhStartupParameters.CommandValue, L"low", TRUE)) - ioPriority = 1; - else if (PhEqualString2(PhStartupParameters.CommandValue, L"normal", TRUE)) - ioPriority = 2; - else if (PhEqualString2(PhStartupParameters.CommandValue, L"high", TRUE)) - ioPriority = 3; - else - return STATUS_INVALID_PARAMETER; - - if (NT_SUCCESS(status = PhOpenProcessPublic(&processHandle, PROCESS_SET_INFORMATION, processId))) - { - status = PhSetProcessIoPriority(processHandle, ioPriority); - NtClose(processHandle); - } - } - else if (PhEqualString2(PhStartupParameters.CommandAction, L"pagepriority", TRUE)) - { - ULONG64 pagePriority64; - ULONG pagePriority; - - if (!PhStartupParameters.CommandValue) - return STATUS_INVALID_PARAMETER; - - PhStringToInteger64(&PhStartupParameters.CommandValue->sr, 10, &pagePriority64); - pagePriority = (ULONG)pagePriority64; - - if (NT_SUCCESS(status = PhOpenProcessPublic(&processHandle, PROCESS_SET_INFORMATION, processId))) - { - status = NtSetInformationProcess( - processHandle, - ProcessPagePriority, - &pagePriority, - sizeof(ULONG) - ); - NtClose(processHandle); - } - } - else if (PhEqualString2(PhStartupParameters.CommandAction, L"injectdll", TRUE)) - { - if (!PhStartupParameters.CommandValue) - return STATUS_INVALID_PARAMETER; - - if (NT_SUCCESS(status = PhOpenProcessPublic( - &processHandle, - ProcessQueryAccess | PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE, - processId - ))) - { - LARGE_INTEGER timeout; - - timeout.QuadPart = -5 * PH_TIMEOUT_SEC; - status = PhInjectDllProcess( - processHandle, - PhStartupParameters.CommandValue->Buffer, - &timeout - ); - NtClose(processHandle); - } - } - else if (PhEqualString2(PhStartupParameters.CommandAction, L"unloaddll", TRUE)) - { - if (!PhStartupParameters.CommandValue) - return STATUS_INVALID_PARAMETER; - - if (NT_SUCCESS(status = PhOpenProcessPublic( - &processHandle, - ProcessQueryAccess | PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE, - processId - ))) - { - PVOID baseAddress; - - if (NT_SUCCESS(status = PhpGetDllBaseRemote( - processHandle, - &PhStartupParameters.CommandValue->sr, - &baseAddress - ))) - { - LARGE_INTEGER timeout; - - timeout.QuadPart = -5 * PH_TIMEOUT_SEC; - status = PhUnloadDllProcess( - processHandle, - baseAddress, - &timeout - ); - } - - NtClose(processHandle); - } - } - } - else if (PhEqualString2(PhStartupParameters.CommandType, L"service", TRUE)) - { - SC_HANDLE serviceHandle; - SERVICE_STATUS serviceStatus; - - if (!PhStartupParameters.CommandObject) - return STATUS_INVALID_PARAMETER; - - if (PhEqualString2(PhStartupParameters.CommandAction, L"start", TRUE)) - { - if (!(serviceHandle = PhOpenService( - PhStartupParameters.CommandObject->Buffer, - SERVICE_START - ))) - return PhGetLastWin32ErrorAsNtStatus(); - - if (!StartService(serviceHandle, 0, NULL)) - status = PhGetLastWin32ErrorAsNtStatus(); - - CloseServiceHandle(serviceHandle); - } - else if (PhEqualString2(PhStartupParameters.CommandAction, L"continue", TRUE)) - { - if (!(serviceHandle = PhOpenService( - PhStartupParameters.CommandObject->Buffer, - SERVICE_PAUSE_CONTINUE - ))) - return PhGetLastWin32ErrorAsNtStatus(); - - if (!ControlService(serviceHandle, SERVICE_CONTROL_CONTINUE, &serviceStatus)) - status = PhGetLastWin32ErrorAsNtStatus(); - - CloseServiceHandle(serviceHandle); - } - else if (PhEqualString2(PhStartupParameters.CommandAction, L"pause", TRUE)) - { - if (!(serviceHandle = PhOpenService( - PhStartupParameters.CommandObject->Buffer, - SERVICE_PAUSE_CONTINUE - ))) - return PhGetLastWin32ErrorAsNtStatus(); - - if (!ControlService(serviceHandle, SERVICE_CONTROL_PAUSE, &serviceStatus)) - status = PhGetLastWin32ErrorAsNtStatus(); - - CloseServiceHandle(serviceHandle); - } - else if (PhEqualString2(PhStartupParameters.CommandAction, L"stop", TRUE)) - { - if (!(serviceHandle = PhOpenService( - PhStartupParameters.CommandObject->Buffer, - SERVICE_STOP - ))) - return PhGetLastWin32ErrorAsNtStatus(); - - if (!ControlService(serviceHandle, SERVICE_CONTROL_STOP, &serviceStatus)) - status = PhGetLastWin32ErrorAsNtStatus(); - - CloseServiceHandle(serviceHandle); - } - else if (PhEqualString2(PhStartupParameters.CommandAction, L"delete", TRUE)) - { - if (!(serviceHandle = PhOpenService( - PhStartupParameters.CommandObject->Buffer, - DELETE - ))) - return PhGetLastWin32ErrorAsNtStatus(); - - if (!DeleteService(serviceHandle)) - status = PhGetLastWin32ErrorAsNtStatus(); - - CloseServiceHandle(serviceHandle); - } - } - else if (PhEqualString2(PhStartupParameters.CommandType, L"thread", TRUE)) - { - ULONG64 threadId64; - HANDLE threadId; - HANDLE threadHandle; - - if (!PhStartupParameters.CommandObject) - return STATUS_INVALID_PARAMETER; - - if (!PhStringToInteger64(&PhStartupParameters.CommandObject->sr, 10, &threadId64)) - return STATUS_INVALID_PARAMETER; - - threadId = (HANDLE)threadId64; - - if (PhEqualString2(PhStartupParameters.CommandAction, L"terminate", TRUE)) - { - if (NT_SUCCESS(status = PhOpenThreadPublic(&threadHandle, THREAD_TERMINATE, threadId))) - { - status = NtTerminateThread(threadHandle, STATUS_SUCCESS); - NtClose(threadHandle); - } - } - else if (PhEqualString2(PhStartupParameters.CommandAction, L"suspend", TRUE)) - { - if (NT_SUCCESS(status = PhOpenThreadPublic(&threadHandle, THREAD_SUSPEND_RESUME, threadId))) - { - status = NtSuspendThread(threadHandle, NULL); - NtClose(threadHandle); - } - } - else if (PhEqualString2(PhStartupParameters.CommandAction, L"resume", TRUE)) - { - if (NT_SUCCESS(status = PhOpenThreadPublic(&threadHandle, THREAD_SUSPEND_RESUME, threadId))) - { - status = NtResumeThread(threadHandle, NULL); - NtClose(threadHandle); - } - } - } - - return status; -} - -typedef struct _GET_DLL_BASE_REMOTE_CONTEXT -{ - PH_STRINGREF BaseDllName; - PVOID DllBase; -} GET_DLL_BASE_REMOTE_CONTEXT, *PGET_DLL_BASE_REMOTE_CONTEXT; - -static BOOLEAN PhpGetDllBaseRemoteCallback( - _In_ PLDR_DATA_TABLE_ENTRY Module, - _In_opt_ PVOID Context - ) -{ - PGET_DLL_BASE_REMOTE_CONTEXT context = Context; - PH_STRINGREF baseDllName; - - PhUnicodeStringToStringRef(&Module->BaseDllName, &baseDllName); - - if (PhEqualStringRef(&baseDllName, &context->BaseDllName, TRUE)) - { - context->DllBase = Module->DllBase; - return FALSE; - } - - return TRUE; -} - -NTSTATUS PhpGetDllBaseRemote( - _In_ HANDLE ProcessHandle, - _In_ PPH_STRINGREF BaseDllName, - _Out_ PVOID *DllBase - ) -{ - NTSTATUS status; - GET_DLL_BASE_REMOTE_CONTEXT context; -#ifdef _WIN64 - BOOLEAN isWow64 = FALSE; -#endif - - context.BaseDllName = *BaseDllName; - context.DllBase = NULL; - -#ifdef _WIN64 - PhGetProcessIsWow64(ProcessHandle, &isWow64); - - if (isWow64) - status = PhEnumProcessModules32(ProcessHandle, PhpGetDllBaseRemoteCallback, &context); - if (!context.DllBase) -#endif - status = PhEnumProcessModules(ProcessHandle, PhpGetDllBaseRemoteCallback, &context); - - if (NT_SUCCESS(status)) - *DllBase = context.DllBase; - - return status; -} +/* + * Process Hacker - + * command line action mode + * + * Copyright (C) 2010-2012 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include + +#include + +NTSTATUS PhpGetDllBaseRemote( + _In_ HANDLE ProcessHandle, + _In_ PPH_STRINGREF BaseDllName, + _Out_ PVOID *DllBase + ); + +static HWND CommandModeWindowHandle; + +#define PH_COMMAND_OPTION_HWND 1 + +BOOLEAN NTAPI PhpCommandModeOptionCallback( + _In_opt_ PPH_COMMAND_LINE_OPTION Option, + _In_opt_ PPH_STRING Value, + _In_opt_ PVOID Context + ) +{ + ULONG64 integer; + + if (Option) + { + switch (Option->Id) + { + case PH_COMMAND_OPTION_HWND: + if (PhStringToInteger64(&Value->sr, 10, &integer)) + CommandModeWindowHandle = (HWND)integer; + break; + } + } + + return TRUE; +} + +NTSTATUS PhCommandModeStart( + VOID + ) +{ + static PH_COMMAND_LINE_OPTION options[] = + { + { PH_COMMAND_OPTION_HWND, L"hwnd", MandatoryArgumentType } + }; + NTSTATUS status = STATUS_SUCCESS; + PH_STRINGREF commandLine; + + PhUnicodeStringToStringRef(&NtCurrentPeb()->ProcessParameters->CommandLine, &commandLine); + + PhParseCommandLine( + &commandLine, + options, + sizeof(options) / sizeof(PH_COMMAND_LINE_OPTION), + PH_COMMAND_LINE_IGNORE_UNKNOWN_OPTIONS, + PhpCommandModeOptionCallback, + NULL + ); + + if (PhEqualString2(PhStartupParameters.CommandType, L"process", TRUE)) + { + SIZE_T i; + SIZE_T processIdLength; + HANDLE processId; + HANDLE processHandle; + + if (!PhStartupParameters.CommandObject) + return STATUS_INVALID_PARAMETER; + + processIdLength = PhStartupParameters.CommandObject->Length / 2; + + for (i = 0; i < processIdLength; i++) + { + if (!PhIsDigitCharacter(PhStartupParameters.CommandObject->Buffer[i])) + break; + } + + if (i == processIdLength) + { + ULONG64 processId64; + + if (!PhStringToInteger64(&PhStartupParameters.CommandObject->sr, 10, &processId64)) + return STATUS_INVALID_PARAMETER; + + processId = (HANDLE)processId64; + } + else + { + PVOID processes; + PSYSTEM_PROCESS_INFORMATION process; + + if (!NT_SUCCESS(status = PhEnumProcesses(&processes))) + return status; + + if (!(process = PhFindProcessInformationByImageName(processes, &PhStartupParameters.CommandObject->sr))) + { + PhFree(processes); + return STATUS_NOT_FOUND; + } + + processId = process->UniqueProcessId; + PhFree(processes); + } + + if (PhEqualString2(PhStartupParameters.CommandAction, L"terminate", TRUE)) + { + if (NT_SUCCESS(status = PhOpenProcessPublic(&processHandle, PROCESS_TERMINATE, processId))) + { + status = NtTerminateProcess(processHandle, STATUS_SUCCESS); + NtClose(processHandle); + } + } + else if (PhEqualString2(PhStartupParameters.CommandAction, L"suspend", TRUE)) + { + if (NT_SUCCESS(status = PhOpenProcessPublic(&processHandle, PROCESS_SUSPEND_RESUME, processId))) + { + status = NtSuspendProcess(processHandle); + NtClose(processHandle); + } + } + else if (PhEqualString2(PhStartupParameters.CommandAction, L"resume", TRUE)) + { + if (NT_SUCCESS(status = PhOpenProcessPublic(&processHandle, PROCESS_SUSPEND_RESUME, processId))) + { + status = NtResumeProcess(processHandle); + NtClose(processHandle); + } + } + else if (PhEqualString2(PhStartupParameters.CommandAction, L"priority", TRUE)) + { + UCHAR priority; + + if (!PhStartupParameters.CommandValue) + return STATUS_INVALID_PARAMETER; + + if (PhEqualString2(PhStartupParameters.CommandValue, L"idle", TRUE)) + priority = PROCESS_PRIORITY_CLASS_IDLE; + else if (PhEqualString2(PhStartupParameters.CommandValue, L"normal", TRUE)) + priority = PROCESS_PRIORITY_CLASS_NORMAL; + else if (PhEqualString2(PhStartupParameters.CommandValue, L"high", TRUE)) + priority = PROCESS_PRIORITY_CLASS_HIGH; + else if (PhEqualString2(PhStartupParameters.CommandValue, L"realtime", TRUE)) + priority = PROCESS_PRIORITY_CLASS_REALTIME; + else if (PhEqualString2(PhStartupParameters.CommandValue, L"abovenormal", TRUE)) + priority = PROCESS_PRIORITY_CLASS_ABOVE_NORMAL; + else if (PhEqualString2(PhStartupParameters.CommandValue, L"belownormal", TRUE)) + priority = PROCESS_PRIORITY_CLASS_BELOW_NORMAL; + else + return STATUS_INVALID_PARAMETER; + + if (NT_SUCCESS(status = PhOpenProcessPublic(&processHandle, PROCESS_SET_INFORMATION, processId))) + { + PROCESS_PRIORITY_CLASS priorityClass; + priorityClass.Foreground = FALSE; + priorityClass.PriorityClass = priority; + status = NtSetInformationProcess(processHandle, ProcessPriorityClass, &priorityClass, sizeof(PROCESS_PRIORITY_CLASS)); + NtClose(processHandle); + } + } + else if (PhEqualString2(PhStartupParameters.CommandAction, L"iopriority", TRUE)) + { + ULONG ioPriority; + + if (!PhStartupParameters.CommandValue) + return STATUS_INVALID_PARAMETER; + + if (PhEqualString2(PhStartupParameters.CommandValue, L"verylow", TRUE)) + ioPriority = 0; + else if (PhEqualString2(PhStartupParameters.CommandValue, L"low", TRUE)) + ioPriority = 1; + else if (PhEqualString2(PhStartupParameters.CommandValue, L"normal", TRUE)) + ioPriority = 2; + else if (PhEqualString2(PhStartupParameters.CommandValue, L"high", TRUE)) + ioPriority = 3; + else + return STATUS_INVALID_PARAMETER; + + if (NT_SUCCESS(status = PhOpenProcessPublic(&processHandle, PROCESS_SET_INFORMATION, processId))) + { + status = PhSetProcessIoPriority(processHandle, ioPriority); + NtClose(processHandle); + } + } + else if (PhEqualString2(PhStartupParameters.CommandAction, L"pagepriority", TRUE)) + { + ULONG64 pagePriority64; + ULONG pagePriority; + + if (!PhStartupParameters.CommandValue) + return STATUS_INVALID_PARAMETER; + + PhStringToInteger64(&PhStartupParameters.CommandValue->sr, 10, &pagePriority64); + pagePriority = (ULONG)pagePriority64; + + if (NT_SUCCESS(status = PhOpenProcessPublic(&processHandle, PROCESS_SET_INFORMATION, processId))) + { + status = NtSetInformationProcess( + processHandle, + ProcessPagePriority, + &pagePriority, + sizeof(ULONG) + ); + NtClose(processHandle); + } + } + else if (PhEqualString2(PhStartupParameters.CommandAction, L"injectdll", TRUE)) + { + if (!PhStartupParameters.CommandValue) + return STATUS_INVALID_PARAMETER; + + if (NT_SUCCESS(status = PhOpenProcessPublic( + &processHandle, + ProcessQueryAccess | PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE, + processId + ))) + { + LARGE_INTEGER timeout; + + timeout.QuadPart = -5 * PH_TIMEOUT_SEC; + status = PhInjectDllProcess( + processHandle, + PhStartupParameters.CommandValue->Buffer, + &timeout + ); + NtClose(processHandle); + } + } + else if (PhEqualString2(PhStartupParameters.CommandAction, L"unloaddll", TRUE)) + { + if (!PhStartupParameters.CommandValue) + return STATUS_INVALID_PARAMETER; + + if (NT_SUCCESS(status = PhOpenProcessPublic( + &processHandle, + ProcessQueryAccess | PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE, + processId + ))) + { + PVOID baseAddress; + + if (NT_SUCCESS(status = PhpGetDllBaseRemote( + processHandle, + &PhStartupParameters.CommandValue->sr, + &baseAddress + ))) + { + LARGE_INTEGER timeout; + + timeout.QuadPart = -5 * PH_TIMEOUT_SEC; + status = PhUnloadDllProcess( + processHandle, + baseAddress, + &timeout + ); + } + + NtClose(processHandle); + } + } + } + else if (PhEqualString2(PhStartupParameters.CommandType, L"service", TRUE)) + { + SC_HANDLE serviceHandle; + SERVICE_STATUS serviceStatus; + + if (!PhStartupParameters.CommandObject) + return STATUS_INVALID_PARAMETER; + + if (PhEqualString2(PhStartupParameters.CommandAction, L"start", TRUE)) + { + if (!(serviceHandle = PhOpenService( + PhStartupParameters.CommandObject->Buffer, + SERVICE_START + ))) + return PhGetLastWin32ErrorAsNtStatus(); + + if (!StartService(serviceHandle, 0, NULL)) + status = PhGetLastWin32ErrorAsNtStatus(); + + CloseServiceHandle(serviceHandle); + } + else if (PhEqualString2(PhStartupParameters.CommandAction, L"continue", TRUE)) + { + if (!(serviceHandle = PhOpenService( + PhStartupParameters.CommandObject->Buffer, + SERVICE_PAUSE_CONTINUE + ))) + return PhGetLastWin32ErrorAsNtStatus(); + + if (!ControlService(serviceHandle, SERVICE_CONTROL_CONTINUE, &serviceStatus)) + status = PhGetLastWin32ErrorAsNtStatus(); + + CloseServiceHandle(serviceHandle); + } + else if (PhEqualString2(PhStartupParameters.CommandAction, L"pause", TRUE)) + { + if (!(serviceHandle = PhOpenService( + PhStartupParameters.CommandObject->Buffer, + SERVICE_PAUSE_CONTINUE + ))) + return PhGetLastWin32ErrorAsNtStatus(); + + if (!ControlService(serviceHandle, SERVICE_CONTROL_PAUSE, &serviceStatus)) + status = PhGetLastWin32ErrorAsNtStatus(); + + CloseServiceHandle(serviceHandle); + } + else if (PhEqualString2(PhStartupParameters.CommandAction, L"stop", TRUE)) + { + if (!(serviceHandle = PhOpenService( + PhStartupParameters.CommandObject->Buffer, + SERVICE_STOP + ))) + return PhGetLastWin32ErrorAsNtStatus(); + + if (!ControlService(serviceHandle, SERVICE_CONTROL_STOP, &serviceStatus)) + status = PhGetLastWin32ErrorAsNtStatus(); + + CloseServiceHandle(serviceHandle); + } + else if (PhEqualString2(PhStartupParameters.CommandAction, L"delete", TRUE)) + { + if (!(serviceHandle = PhOpenService( + PhStartupParameters.CommandObject->Buffer, + DELETE + ))) + return PhGetLastWin32ErrorAsNtStatus(); + + if (!DeleteService(serviceHandle)) + status = PhGetLastWin32ErrorAsNtStatus(); + + CloseServiceHandle(serviceHandle); + } + } + else if (PhEqualString2(PhStartupParameters.CommandType, L"thread", TRUE)) + { + ULONG64 threadId64; + HANDLE threadId; + HANDLE threadHandle; + + if (!PhStartupParameters.CommandObject) + return STATUS_INVALID_PARAMETER; + + if (!PhStringToInteger64(&PhStartupParameters.CommandObject->sr, 10, &threadId64)) + return STATUS_INVALID_PARAMETER; + + threadId = (HANDLE)threadId64; + + if (PhEqualString2(PhStartupParameters.CommandAction, L"terminate", TRUE)) + { + if (NT_SUCCESS(status = PhOpenThreadPublic(&threadHandle, THREAD_TERMINATE, threadId))) + { + status = NtTerminateThread(threadHandle, STATUS_SUCCESS); + NtClose(threadHandle); + } + } + else if (PhEqualString2(PhStartupParameters.CommandAction, L"suspend", TRUE)) + { + if (NT_SUCCESS(status = PhOpenThreadPublic(&threadHandle, THREAD_SUSPEND_RESUME, threadId))) + { + status = NtSuspendThread(threadHandle, NULL); + NtClose(threadHandle); + } + } + else if (PhEqualString2(PhStartupParameters.CommandAction, L"resume", TRUE)) + { + if (NT_SUCCESS(status = PhOpenThreadPublic(&threadHandle, THREAD_SUSPEND_RESUME, threadId))) + { + status = NtResumeThread(threadHandle, NULL); + NtClose(threadHandle); + } + } + } + + return status; +} + +typedef struct _GET_DLL_BASE_REMOTE_CONTEXT +{ + PH_STRINGREF BaseDllName; + PVOID DllBase; +} GET_DLL_BASE_REMOTE_CONTEXT, *PGET_DLL_BASE_REMOTE_CONTEXT; + +static BOOLEAN PhpGetDllBaseRemoteCallback( + _In_ PLDR_DATA_TABLE_ENTRY Module, + _In_opt_ PVOID Context + ) +{ + PGET_DLL_BASE_REMOTE_CONTEXT context = Context; + PH_STRINGREF baseDllName; + + PhUnicodeStringToStringRef(&Module->BaseDllName, &baseDllName); + + if (PhEqualStringRef(&baseDllName, &context->BaseDllName, TRUE)) + { + context->DllBase = Module->DllBase; + return FALSE; + } + + return TRUE; +} + +NTSTATUS PhpGetDllBaseRemote( + _In_ HANDLE ProcessHandle, + _In_ PPH_STRINGREF BaseDllName, + _Out_ PVOID *DllBase + ) +{ + NTSTATUS status; + GET_DLL_BASE_REMOTE_CONTEXT context; +#ifdef _WIN64 + BOOLEAN isWow64 = FALSE; +#endif + + context.BaseDllName = *BaseDllName; + context.DllBase = NULL; + +#ifdef _WIN64 + PhGetProcessIsWow64(ProcessHandle, &isWow64); + + if (isWow64) + status = PhEnumProcessModules32(ProcessHandle, PhpGetDllBaseRemoteCallback, &context); + if (!context.DllBase) +#endif + status = PhEnumProcessModules(ProcessHandle, PhpGetDllBaseRemoteCallback, &context); + + if (NT_SUCCESS(status)) + *DllBase = context.DllBase; + + return status; +} diff --git a/ProcessHacker/colmgr.c b/ProcessHacker/colmgr.c index ba95bbcad89f..3f4aafb68c40 100644 --- a/ProcessHacker/colmgr.c +++ b/ProcessHacker/colmgr.c @@ -1,710 +1,710 @@ -/* - * Process Hacker - - * tree new column manager - * - * Copyright (C) 2011-2016 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include -#include - -#include -#include - -typedef struct _PH_CM_SORT_CONTEXT -{ - PPH_PLUGIN_TREENEW_SORT_FUNCTION SortFunction; - ULONG SubId; - PVOID Context; - PPH_CM_POST_SORT_FUNCTION PostSortFunction; - PH_SORT_ORDER SortOrder; -} PH_CM_SORT_CONTEXT, *PPH_CM_SORT_CONTEXT; - -VOID PhCmInitializeManager( - _Out_ PPH_CM_MANAGER Manager, - _In_ HWND Handle, - _In_ ULONG MinId, - _In_ PPH_CM_POST_SORT_FUNCTION PostSortFunction - ) -{ - Manager->Handle = Handle; - Manager->MinId = MinId; - Manager->NextId = MinId; - Manager->PostSortFunction = PostSortFunction; - InitializeListHead(&Manager->ColumnListHead); - Manager->NotifyList = NULL; -} - -VOID PhCmDeleteManager( - _In_ PPH_CM_MANAGER Manager - ) -{ - PLIST_ENTRY listEntry; - PPH_CM_COLUMN column; - - listEntry = Manager->ColumnListHead.Flink; - - while (listEntry != &Manager->ColumnListHead) - { - column = CONTAINING_RECORD(listEntry, PH_CM_COLUMN, ListEntry); - listEntry = listEntry->Flink; - - PhFree(column); - } - - if (Manager->NotifyList) - PhDereferenceObject(Manager->NotifyList); -} - -PPH_CM_COLUMN PhCmCreateColumn( - _Inout_ PPH_CM_MANAGER Manager, - _In_ PPH_TREENEW_COLUMN Column, - _In_ struct _PH_PLUGIN *Plugin, - _In_ ULONG SubId, - _In_opt_ PVOID Context, - _In_ PVOID SortFunction - ) -{ - PPH_CM_COLUMN column; - PH_TREENEW_COLUMN tnColumn; - - column = PhAllocate(sizeof(PH_CM_COLUMN)); - memset(column, 0, sizeof(PH_CM_COLUMN)); - column->Id = Manager->NextId++; - column->Plugin = Plugin; - column->SubId = SubId; - column->Context = Context; - column->SortFunction = SortFunction; - InsertTailList(&Manager->ColumnListHead, &column->ListEntry); - - memset(&tnColumn, 0, sizeof(PH_TREENEW_COLUMN)); - tnColumn.Id = column->Id; - tnColumn.Context = column; - tnColumn.Visible = Column->Visible; - tnColumn.CustomDraw = Column->CustomDraw; - tnColumn.SortDescending = Column->SortDescending; - tnColumn.Text = Column->Text; - tnColumn.Width = Column->Width; - tnColumn.Alignment = Column->Alignment; - tnColumn.DisplayIndex = Column->Visible ? Column->DisplayIndex : -1; - tnColumn.TextFlags = Column->TextFlags; - TreeNew_AddColumn(Manager->Handle, &tnColumn); - - return column; -} - -PPH_CM_COLUMN PhCmFindColumn( - _In_ PPH_CM_MANAGER Manager, - _In_ PPH_STRINGREF PluginName, - _In_ ULONG SubId - ) -{ - PLIST_ENTRY listEntry; - PPH_CM_COLUMN column; - - listEntry = Manager->ColumnListHead.Flink; - - while (listEntry != &Manager->ColumnListHead) - { - column = CONTAINING_RECORD(listEntry, PH_CM_COLUMN, ListEntry); - - if (column->SubId == SubId && PhEqualStringRef(PluginName, &column->Plugin->AppContext.AppName, FALSE)) - return column; - - listEntry = listEntry->Flink; - } - - return NULL; -} - -VOID PhCmSetNotifyPlugin( - _In_ PPH_CM_MANAGER Manager, - _In_ struct _PH_PLUGIN *Plugin - ) -{ - if (!Manager->NotifyList) - { - Manager->NotifyList = PhCreateList(8); - } - else - { - if (PhFindItemList(Manager->NotifyList, Plugin) != -1) - return; - } - - PhAddItemList(Manager->NotifyList, Plugin); -} - -BOOLEAN PhCmForwardMessage( - _In_ HWND hwnd, - _In_ PH_TREENEW_MESSAGE Message, - _In_opt_ PVOID Parameter1, - _In_opt_ PVOID Parameter2, - _In_ PPH_CM_MANAGER Manager - ) -{ - PH_PLUGIN_TREENEW_MESSAGE pluginMessage; - PPH_PLUGIN plugin; - - if (Message == TreeNewDestroying) - return FALSE; - - switch (Message) - { - case TreeNewGetCellText: - { - PPH_TREENEW_GET_CELL_TEXT getCellText = Parameter1; - PH_TREENEW_COLUMN tnColumn; - PPH_CM_COLUMN column; - - if (getCellText->Id < Manager->MinId) - return FALSE; - - if (!TreeNew_GetColumn(hwnd, getCellText->Id, &tnColumn)) - return FALSE; - - column = tnColumn.Context; - pluginMessage.SubId = column->SubId; - pluginMessage.Context = column->Context; - plugin = column->Plugin; - } - break; - case TreeNewCustomDraw: - { - PPH_TREENEW_CUSTOM_DRAW customDraw = Parameter1; - PPH_CM_COLUMN column; - - if (customDraw->Column->Id < Manager->MinId) - return FALSE; - - column = customDraw->Column->Context; - pluginMessage.SubId = column->SubId; - pluginMessage.Context = column->Context; - plugin = column->Plugin; - } - break; - case TreeNewColumnResized: - { - PPH_TREENEW_COLUMN tlColumn = Parameter1; - PPH_CM_COLUMN column; - - if (tlColumn->Id < Manager->MinId) - return FALSE; - - column = tlColumn->Context; - pluginMessage.SubId = column->SubId; - pluginMessage.Context = column->Context; - plugin = column->Plugin; - } - break; - default: - { - // Some plugins want to be notified about all messages. - if (Manager->NotifyList) - { - ULONG i; - - for (i = 0; i < Manager->NotifyList->Count; i++) - { - plugin = Manager->NotifyList->Items[i]; - - pluginMessage.TreeNewHandle = hwnd; - pluginMessage.Message = Message; - pluginMessage.Parameter1 = Parameter1; - pluginMessage.Parameter2 = Parameter2; - pluginMessage.SubId = 0; - pluginMessage.Context = NULL; - - PhInvokeCallback(PhGetPluginCallback(plugin, PluginCallbackTreeNewMessage), &pluginMessage); - } - } - } - return FALSE; - } - - pluginMessage.TreeNewHandle = hwnd; - pluginMessage.Message = Message; - pluginMessage.Parameter1 = Parameter1; - pluginMessage.Parameter2 = Parameter2; - - PhInvokeCallback(PhGetPluginCallback(plugin, PluginCallbackTreeNewMessage), &pluginMessage); - - return TRUE; -} - -static int __cdecl PhCmpSortFunction( - _In_ void *context, - _In_ const void *elem1, - _In_ const void *elem2 - ) -{ - PPH_CM_SORT_CONTEXT sortContext = context; - PVOID node1 = *(PVOID *)elem1; - PVOID node2 = *(PVOID *)elem2; - LONG result; - - result = sortContext->SortFunction(node1, node2, sortContext->SubId, sortContext->Context); - - return sortContext->PostSortFunction(result, node1, node2, sortContext->SortOrder); -} - -BOOLEAN PhCmForwardSort( - _In_ PPH_TREENEW_NODE *Nodes, - _In_ ULONG NumberOfNodes, - _In_ ULONG SortColumn, - _In_ PH_SORT_ORDER SortOrder, - _In_ PPH_CM_MANAGER Manager - ) -{ - PH_TREENEW_COLUMN tnColumn; - PPH_CM_COLUMN column; - PH_CM_SORT_CONTEXT sortContext; - - if (SortColumn < Manager->MinId) - return FALSE; - - if (!TreeNew_GetColumn(Manager->Handle, SortColumn, &tnColumn)) - return TRUE; - - column = tnColumn.Context; - - if (!column->SortFunction) - return TRUE; - - sortContext.SortFunction = column->SortFunction; - sortContext.SubId = column->SubId; - sortContext.Context = column->Context; - sortContext.PostSortFunction = Manager->PostSortFunction; - sortContext.SortOrder = SortOrder; - qsort_s(Nodes, NumberOfNodes, sizeof(PVOID), PhCmpSortFunction, &sortContext); - - return TRUE; -} - -BOOLEAN PhCmLoadSettings( - _In_ HWND TreeNewHandle, - _In_ PPH_STRINGREF Settings - ) -{ - return PhCmLoadSettingsEx(TreeNewHandle, NULL, 0, Settings, NULL); -} - -BOOLEAN PhCmLoadSettingsEx( - _In_ HWND TreeNewHandle, - _In_opt_ PPH_CM_MANAGER Manager, - _In_ ULONG Flags, - _In_ PPH_STRINGREF Settings, - _In_opt_ PPH_STRINGREF SortSettings - ) -{ - BOOLEAN result = FALSE; - PH_STRINGREF scalePart; - PH_STRINGREF columnPart; - PH_STRINGREF remainingColumnPart; - PH_STRINGREF valuePart; - PH_STRINGREF subPart; - ULONG64 integer; - ULONG scale; - ULONG total; - BOOLEAN hasFixedColumn; - ULONG count; - ULONG i; - PPH_HASHTABLE columnHashtable; - PH_HASHTABLE_ENUM_CONTEXT enumContext; - PPH_KEY_VALUE_PAIR pair; - LONG orderArray[PH_CM_ORDER_LIMIT]; - LONG maxOrder; - - if (Settings->Length != 0) - { - columnHashtable = PhCreateSimpleHashtable(20); - - remainingColumnPart = *Settings; - - if (remainingColumnPart.Length != 0 && remainingColumnPart.Buffer[0] == '@') - { - PhSkipStringRef(&remainingColumnPart, sizeof(WCHAR)); - PhSplitStringRefAtChar(&remainingColumnPart, '|', &scalePart, &remainingColumnPart); - - if (scalePart.Length == 0 || !PhStringToInteger64(&scalePart, 10, &integer)) - goto CleanupExit; - - scale = (ULONG)integer; - } - else - { - scale = PhGlobalDpi; - } - - while (remainingColumnPart.Length != 0) - { - PPH_TREENEW_COLUMN column; - ULONG id; - ULONG displayIndex; - ULONG width; - - PhSplitStringRefAtChar(&remainingColumnPart, '|', &columnPart, &remainingColumnPart); - - if (columnPart.Length != 0) - { - // Id - - PhSplitStringRefAtChar(&columnPart, ',', &valuePart, &columnPart); - - if (valuePart.Length == 0) - goto CleanupExit; - - if (valuePart.Buffer[0] == '+') - { - PH_STRINGREF pluginName; - ULONG subId; - PPH_CM_COLUMN cmColumn; - - // This is a plugin-owned column. - - if (!Manager) - continue; - if (!PhEmParseCompoundId(&valuePart, &pluginName, &subId)) - continue; - - cmColumn = PhCmFindColumn(Manager, &pluginName, subId); - - if (!cmColumn) - continue; // can't find the column, skip this part - - id = cmColumn->Id; - } - else - { - if (!PhStringToInteger64(&valuePart, 10, &integer)) - goto CleanupExit; - - id = (ULONG)integer; - } - - // Display Index - - PhSplitStringRefAtChar(&columnPart, ',', &valuePart, &columnPart); - - if (!(Flags & PH_CM_COLUMN_WIDTHS_ONLY)) - { - if (valuePart.Length == 0 || !PhStringToInteger64(&valuePart, 10, &integer)) - goto CleanupExit; - - displayIndex = (ULONG)integer; - } - else - { - if (valuePart.Length != 0) - goto CleanupExit; - - displayIndex = -1; - } - - // Width - - if (columnPart.Length == 0 || !PhStringToInteger64(&columnPart, 10, &integer)) - goto CleanupExit; - - width = (ULONG)integer; - - if (scale != PhGlobalDpi && scale != 0) - width = PhMultiplyDivide(width, PhGlobalDpi, scale); - - column = PhAllocate(sizeof(PH_TREENEW_COLUMN)); - column->Id = id; - column->DisplayIndex = displayIndex; - column->Width = width; - PhAddItemSimpleHashtable(columnHashtable, UlongToPtr(column->Id), column); - } - } - - TreeNew_SetRedraw(TreeNewHandle, FALSE); - - // Set visibility and width. - - i = 0; - count = 0; - total = TreeNew_GetColumnCount(TreeNewHandle); - hasFixedColumn = !!TreeNew_GetFixedColumn(TreeNewHandle); - memset(orderArray, 0, sizeof(orderArray)); - maxOrder = 0; - - while (count < total) - { - PH_TREENEW_COLUMN setColumn; - PPH_TREENEW_COLUMN *columnPtr; - - if (TreeNew_GetColumn(TreeNewHandle, i, &setColumn)) - { - columnPtr = (PPH_TREENEW_COLUMN *)PhFindItemSimpleHashtable(columnHashtable, UlongToPtr(i)); - - if (!(Flags & PH_CM_COLUMN_WIDTHS_ONLY)) - { - if (columnPtr) - { - setColumn.Visible = TRUE; - setColumn.Width = (*columnPtr)->Width; - TreeNew_SetColumn(TreeNewHandle, TN_COLUMN_FLAG_VISIBLE | TN_COLUMN_WIDTH, &setColumn); - - if (!setColumn.Fixed) - { - // For compatibility reasons, normal columns have their display indicies stored - // one higher than usual (so they start from 1, not 0). Fix that here. - if (hasFixedColumn && (*columnPtr)->DisplayIndex != 0) - (*columnPtr)->DisplayIndex--; - - if ((*columnPtr)->DisplayIndex < PH_CM_ORDER_LIMIT) - { - orderArray[(*columnPtr)->DisplayIndex] = i; - - if ((ULONG)maxOrder < (*columnPtr)->DisplayIndex + 1) - maxOrder = (*columnPtr)->DisplayIndex + 1; - } - } - } - else if (!setColumn.Fixed) // never hide the fixed column - { - setColumn.Visible = FALSE; - TreeNew_SetColumn(TreeNewHandle, TN_COLUMN_FLAG_VISIBLE, &setColumn); - } - } - else - { - if (columnPtr) - { - setColumn.Width = (*columnPtr)->Width; - TreeNew_SetColumn(TreeNewHandle, TN_COLUMN_WIDTH, &setColumn); - } - } - - count++; - } - - i++; - } - - if (!(Flags & PH_CM_COLUMN_WIDTHS_ONLY)) - { - // Set the order array. - TreeNew_SetColumnOrderArray(TreeNewHandle, maxOrder, orderArray); - } - - TreeNew_SetRedraw(TreeNewHandle, TRUE); - - result = TRUE; - -CleanupExit: - PhBeginEnumHashtable(columnHashtable, &enumContext); - - while (pair = PhNextEnumHashtable(&enumContext)) - PhFree(pair->Value); - - PhDereferenceObject(columnHashtable); - } - - // Load sort settings. - - if (SortSettings && SortSettings->Length != 0) - { - PhSplitStringRefAtChar(SortSettings, ',', &valuePart, &subPart); - - if (valuePart.Length != 0 && subPart.Length != 0) - { - ULONG sortColumn; - PH_SORT_ORDER sortOrder; - - sortColumn = -1; - - if (valuePart.Buffer[0] == '+') - { - PH_STRINGREF pluginName; - ULONG subId; - PPH_CM_COLUMN cmColumn; - - if ( - Manager && - PhEmParseCompoundId(&valuePart, &pluginName, &subId) && - (cmColumn = PhCmFindColumn(Manager, &pluginName, subId)) - ) - { - sortColumn = cmColumn->Id; - } - } - else - { - PhStringToInteger64(&valuePart, 10, &integer); - sortColumn = (ULONG)integer; - } - - PhStringToInteger64(&subPart, 10, &integer); - sortOrder = (PH_SORT_ORDER)integer; - - if (sortColumn != -1 && sortOrder <= DescendingSortOrder) - { - TreeNew_SetSort(TreeNewHandle, sortColumn, sortOrder); - } - } - } - - return result; -} - -PPH_STRING PhCmSaveSettings( - _In_ HWND TreeNewHandle - ) -{ - return PhCmSaveSettingsEx(TreeNewHandle, NULL, 0, NULL); -} - -PPH_STRING PhCmSaveSettingsEx( - _In_ HWND TreeNewHandle, - _In_opt_ PPH_CM_MANAGER Manager, - _In_ ULONG Flags, - _Out_opt_ PPH_STRING *SortSettings - ) -{ - PH_STRING_BUILDER stringBuilder; - ULONG i = 0; - ULONG count = 0; - ULONG total; - ULONG increment; - PH_TREENEW_COLUMN column; - - total = TreeNew_GetColumnCount(TreeNewHandle); - - if (TreeNew_GetFixedColumn(TreeNewHandle)) - increment = 1; // the first normal column should have a display index that starts with 1, for compatibility - else - increment = 0; - - PhInitializeStringBuilder(&stringBuilder, 100); - - PhAppendFormatStringBuilder(&stringBuilder, L"@%u|", PhGlobalDpi); - - while (count < total) - { - if (TreeNew_GetColumn(TreeNewHandle, i, &column)) - { - if (!(Flags & PH_CM_COLUMN_WIDTHS_ONLY)) - { - if (column.Visible) - { - if (!Manager || i < Manager->MinId) - { - PhAppendFormatStringBuilder( - &stringBuilder, - L"%u,%u,%u|", - i, - column.Fixed ? 0 : column.DisplayIndex + increment, - column.Width - ); - } - else - { - PPH_CM_COLUMN cmColumn; - - cmColumn = column.Context; - PhAppendFormatStringBuilder( - &stringBuilder, - L"+%s+%u,%u,%u|", - cmColumn->Plugin->Name.Buffer, - cmColumn->SubId, - column.DisplayIndex + increment, - column.Width - ); - } - } - } - else - { - if (!Manager || i < Manager->MinId) - { - PhAppendFormatStringBuilder( - &stringBuilder, - L"%u,,%u|", - i, - column.Width - ); - } - else - { - PPH_CM_COLUMN cmColumn; - - cmColumn = column.Context; - PhAppendFormatStringBuilder( - &stringBuilder, - L"+%s+%u,,%u|", - cmColumn->Plugin->Name.Buffer, - cmColumn->SubId, - column.Width - ); - } - } - - count++; - } - - i++; - } - - if (stringBuilder.String->Length != 0) - PhRemoveEndStringBuilder(&stringBuilder, 1); - - if (SortSettings) - { - ULONG sortColumn; - PH_SORT_ORDER sortOrder; - - if (TreeNew_GetSort(TreeNewHandle, &sortColumn, &sortOrder)) - { - if (sortOrder != NoSortOrder) - { - if (!Manager || sortColumn < Manager->MinId) - { - *SortSettings = PhFormatString(L"%u,%u", sortColumn, sortOrder); - } - else - { - PH_TREENEW_COLUMN column; - PPH_CM_COLUMN cmColumn; - - if (TreeNew_GetColumn(TreeNewHandle, sortColumn, &column)) - { - cmColumn = column.Context; - *SortSettings = PhFormatString(L"+%s+%u,%u", cmColumn->Plugin->Name.Buffer, cmColumn->SubId, sortOrder); - } - else - { - *SortSettings = PhReferenceEmptyString(); - } - } - } - else - { - *SortSettings = PhCreateString(L"0,0"); - } - } - else - { - *SortSettings = PhReferenceEmptyString(); - } - } - - return PhFinalStringBuilderString(&stringBuilder); -} +/* + * Process Hacker - + * tree new column manager + * + * Copyright (C) 2011-2016 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include +#include + +#include +#include + +typedef struct _PH_CM_SORT_CONTEXT +{ + PPH_PLUGIN_TREENEW_SORT_FUNCTION SortFunction; + ULONG SubId; + PVOID Context; + PPH_CM_POST_SORT_FUNCTION PostSortFunction; + PH_SORT_ORDER SortOrder; +} PH_CM_SORT_CONTEXT, *PPH_CM_SORT_CONTEXT; + +VOID PhCmInitializeManager( + _Out_ PPH_CM_MANAGER Manager, + _In_ HWND Handle, + _In_ ULONG MinId, + _In_ PPH_CM_POST_SORT_FUNCTION PostSortFunction + ) +{ + Manager->Handle = Handle; + Manager->MinId = MinId; + Manager->NextId = MinId; + Manager->PostSortFunction = PostSortFunction; + InitializeListHead(&Manager->ColumnListHead); + Manager->NotifyList = NULL; +} + +VOID PhCmDeleteManager( + _In_ PPH_CM_MANAGER Manager + ) +{ + PLIST_ENTRY listEntry; + PPH_CM_COLUMN column; + + listEntry = Manager->ColumnListHead.Flink; + + while (listEntry != &Manager->ColumnListHead) + { + column = CONTAINING_RECORD(listEntry, PH_CM_COLUMN, ListEntry); + listEntry = listEntry->Flink; + + PhFree(column); + } + + if (Manager->NotifyList) + PhDereferenceObject(Manager->NotifyList); +} + +PPH_CM_COLUMN PhCmCreateColumn( + _Inout_ PPH_CM_MANAGER Manager, + _In_ PPH_TREENEW_COLUMN Column, + _In_ struct _PH_PLUGIN *Plugin, + _In_ ULONG SubId, + _In_opt_ PVOID Context, + _In_ PVOID SortFunction + ) +{ + PPH_CM_COLUMN column; + PH_TREENEW_COLUMN tnColumn; + + column = PhAllocate(sizeof(PH_CM_COLUMN)); + memset(column, 0, sizeof(PH_CM_COLUMN)); + column->Id = Manager->NextId++; + column->Plugin = Plugin; + column->SubId = SubId; + column->Context = Context; + column->SortFunction = SortFunction; + InsertTailList(&Manager->ColumnListHead, &column->ListEntry); + + memset(&tnColumn, 0, sizeof(PH_TREENEW_COLUMN)); + tnColumn.Id = column->Id; + tnColumn.Context = column; + tnColumn.Visible = Column->Visible; + tnColumn.CustomDraw = Column->CustomDraw; + tnColumn.SortDescending = Column->SortDescending; + tnColumn.Text = Column->Text; + tnColumn.Width = Column->Width; + tnColumn.Alignment = Column->Alignment; + tnColumn.DisplayIndex = Column->Visible ? Column->DisplayIndex : -1; + tnColumn.TextFlags = Column->TextFlags; + TreeNew_AddColumn(Manager->Handle, &tnColumn); + + return column; +} + +PPH_CM_COLUMN PhCmFindColumn( + _In_ PPH_CM_MANAGER Manager, + _In_ PPH_STRINGREF PluginName, + _In_ ULONG SubId + ) +{ + PLIST_ENTRY listEntry; + PPH_CM_COLUMN column; + + listEntry = Manager->ColumnListHead.Flink; + + while (listEntry != &Manager->ColumnListHead) + { + column = CONTAINING_RECORD(listEntry, PH_CM_COLUMN, ListEntry); + + if (column->SubId == SubId && PhEqualStringRef(PluginName, &column->Plugin->AppContext.AppName, FALSE)) + return column; + + listEntry = listEntry->Flink; + } + + return NULL; +} + +VOID PhCmSetNotifyPlugin( + _In_ PPH_CM_MANAGER Manager, + _In_ struct _PH_PLUGIN *Plugin + ) +{ + if (!Manager->NotifyList) + { + Manager->NotifyList = PhCreateList(8); + } + else + { + if (PhFindItemList(Manager->NotifyList, Plugin) != -1) + return; + } + + PhAddItemList(Manager->NotifyList, Plugin); +} + +BOOLEAN PhCmForwardMessage( + _In_ HWND hwnd, + _In_ PH_TREENEW_MESSAGE Message, + _In_opt_ PVOID Parameter1, + _In_opt_ PVOID Parameter2, + _In_ PPH_CM_MANAGER Manager + ) +{ + PH_PLUGIN_TREENEW_MESSAGE pluginMessage; + PPH_PLUGIN plugin; + + if (Message == TreeNewDestroying) + return FALSE; + + switch (Message) + { + case TreeNewGetCellText: + { + PPH_TREENEW_GET_CELL_TEXT getCellText = Parameter1; + PH_TREENEW_COLUMN tnColumn; + PPH_CM_COLUMN column; + + if (getCellText->Id < Manager->MinId) + return FALSE; + + if (!TreeNew_GetColumn(hwnd, getCellText->Id, &tnColumn)) + return FALSE; + + column = tnColumn.Context; + pluginMessage.SubId = column->SubId; + pluginMessage.Context = column->Context; + plugin = column->Plugin; + } + break; + case TreeNewCustomDraw: + { + PPH_TREENEW_CUSTOM_DRAW customDraw = Parameter1; + PPH_CM_COLUMN column; + + if (customDraw->Column->Id < Manager->MinId) + return FALSE; + + column = customDraw->Column->Context; + pluginMessage.SubId = column->SubId; + pluginMessage.Context = column->Context; + plugin = column->Plugin; + } + break; + case TreeNewColumnResized: + { + PPH_TREENEW_COLUMN tlColumn = Parameter1; + PPH_CM_COLUMN column; + + if (tlColumn->Id < Manager->MinId) + return FALSE; + + column = tlColumn->Context; + pluginMessage.SubId = column->SubId; + pluginMessage.Context = column->Context; + plugin = column->Plugin; + } + break; + default: + { + // Some plugins want to be notified about all messages. + if (Manager->NotifyList) + { + ULONG i; + + for (i = 0; i < Manager->NotifyList->Count; i++) + { + plugin = Manager->NotifyList->Items[i]; + + pluginMessage.TreeNewHandle = hwnd; + pluginMessage.Message = Message; + pluginMessage.Parameter1 = Parameter1; + pluginMessage.Parameter2 = Parameter2; + pluginMessage.SubId = 0; + pluginMessage.Context = NULL; + + PhInvokeCallback(PhGetPluginCallback(plugin, PluginCallbackTreeNewMessage), &pluginMessage); + } + } + } + return FALSE; + } + + pluginMessage.TreeNewHandle = hwnd; + pluginMessage.Message = Message; + pluginMessage.Parameter1 = Parameter1; + pluginMessage.Parameter2 = Parameter2; + + PhInvokeCallback(PhGetPluginCallback(plugin, PluginCallbackTreeNewMessage), &pluginMessage); + + return TRUE; +} + +static int __cdecl PhCmpSortFunction( + _In_ void *context, + _In_ const void *elem1, + _In_ const void *elem2 + ) +{ + PPH_CM_SORT_CONTEXT sortContext = context; + PVOID node1 = *(PVOID *)elem1; + PVOID node2 = *(PVOID *)elem2; + LONG result; + + result = sortContext->SortFunction(node1, node2, sortContext->SubId, sortContext->Context); + + return sortContext->PostSortFunction(result, node1, node2, sortContext->SortOrder); +} + +BOOLEAN PhCmForwardSort( + _In_ PPH_TREENEW_NODE *Nodes, + _In_ ULONG NumberOfNodes, + _In_ ULONG SortColumn, + _In_ PH_SORT_ORDER SortOrder, + _In_ PPH_CM_MANAGER Manager + ) +{ + PH_TREENEW_COLUMN tnColumn; + PPH_CM_COLUMN column; + PH_CM_SORT_CONTEXT sortContext; + + if (SortColumn < Manager->MinId) + return FALSE; + + if (!TreeNew_GetColumn(Manager->Handle, SortColumn, &tnColumn)) + return TRUE; + + column = tnColumn.Context; + + if (!column->SortFunction) + return TRUE; + + sortContext.SortFunction = column->SortFunction; + sortContext.SubId = column->SubId; + sortContext.Context = column->Context; + sortContext.PostSortFunction = Manager->PostSortFunction; + sortContext.SortOrder = SortOrder; + qsort_s(Nodes, NumberOfNodes, sizeof(PVOID), PhCmpSortFunction, &sortContext); + + return TRUE; +} + +BOOLEAN PhCmLoadSettings( + _In_ HWND TreeNewHandle, + _In_ PPH_STRINGREF Settings + ) +{ + return PhCmLoadSettingsEx(TreeNewHandle, NULL, 0, Settings, NULL); +} + +BOOLEAN PhCmLoadSettingsEx( + _In_ HWND TreeNewHandle, + _In_opt_ PPH_CM_MANAGER Manager, + _In_ ULONG Flags, + _In_ PPH_STRINGREF Settings, + _In_opt_ PPH_STRINGREF SortSettings + ) +{ + BOOLEAN result = FALSE; + PH_STRINGREF scalePart; + PH_STRINGREF columnPart; + PH_STRINGREF remainingColumnPart; + PH_STRINGREF valuePart; + PH_STRINGREF subPart; + ULONG64 integer; + ULONG scale; + ULONG total; + BOOLEAN hasFixedColumn; + ULONG count; + ULONG i; + PPH_HASHTABLE columnHashtable; + PH_HASHTABLE_ENUM_CONTEXT enumContext; + PPH_KEY_VALUE_PAIR pair; + LONG orderArray[PH_CM_ORDER_LIMIT]; + LONG maxOrder; + + if (Settings->Length != 0) + { + columnHashtable = PhCreateSimpleHashtable(20); + + remainingColumnPart = *Settings; + + if (remainingColumnPart.Length != 0 && remainingColumnPart.Buffer[0] == '@') + { + PhSkipStringRef(&remainingColumnPart, sizeof(WCHAR)); + PhSplitStringRefAtChar(&remainingColumnPart, '|', &scalePart, &remainingColumnPart); + + if (scalePart.Length == 0 || !PhStringToInteger64(&scalePart, 10, &integer)) + goto CleanupExit; + + scale = (ULONG)integer; + } + else + { + scale = PhGlobalDpi; + } + + while (remainingColumnPart.Length != 0) + { + PPH_TREENEW_COLUMN column; + ULONG id; + ULONG displayIndex; + ULONG width; + + PhSplitStringRefAtChar(&remainingColumnPart, '|', &columnPart, &remainingColumnPart); + + if (columnPart.Length != 0) + { + // Id + + PhSplitStringRefAtChar(&columnPart, ',', &valuePart, &columnPart); + + if (valuePart.Length == 0) + goto CleanupExit; + + if (valuePart.Buffer[0] == '+') + { + PH_STRINGREF pluginName; + ULONG subId; + PPH_CM_COLUMN cmColumn; + + // This is a plugin-owned column. + + if (!Manager) + continue; + if (!PhEmParseCompoundId(&valuePart, &pluginName, &subId)) + continue; + + cmColumn = PhCmFindColumn(Manager, &pluginName, subId); + + if (!cmColumn) + continue; // can't find the column, skip this part + + id = cmColumn->Id; + } + else + { + if (!PhStringToInteger64(&valuePart, 10, &integer)) + goto CleanupExit; + + id = (ULONG)integer; + } + + // Display Index + + PhSplitStringRefAtChar(&columnPart, ',', &valuePart, &columnPart); + + if (!(Flags & PH_CM_COLUMN_WIDTHS_ONLY)) + { + if (valuePart.Length == 0 || !PhStringToInteger64(&valuePart, 10, &integer)) + goto CleanupExit; + + displayIndex = (ULONG)integer; + } + else + { + if (valuePart.Length != 0) + goto CleanupExit; + + displayIndex = -1; + } + + // Width + + if (columnPart.Length == 0 || !PhStringToInteger64(&columnPart, 10, &integer)) + goto CleanupExit; + + width = (ULONG)integer; + + if (scale != PhGlobalDpi && scale != 0) + width = PhMultiplyDivide(width, PhGlobalDpi, scale); + + column = PhAllocate(sizeof(PH_TREENEW_COLUMN)); + column->Id = id; + column->DisplayIndex = displayIndex; + column->Width = width; + PhAddItemSimpleHashtable(columnHashtable, UlongToPtr(column->Id), column); + } + } + + TreeNew_SetRedraw(TreeNewHandle, FALSE); + + // Set visibility and width. + + i = 0; + count = 0; + total = TreeNew_GetColumnCount(TreeNewHandle); + hasFixedColumn = !!TreeNew_GetFixedColumn(TreeNewHandle); + memset(orderArray, 0, sizeof(orderArray)); + maxOrder = 0; + + while (count < total) + { + PH_TREENEW_COLUMN setColumn; + PPH_TREENEW_COLUMN *columnPtr; + + if (TreeNew_GetColumn(TreeNewHandle, i, &setColumn)) + { + columnPtr = (PPH_TREENEW_COLUMN *)PhFindItemSimpleHashtable(columnHashtable, UlongToPtr(i)); + + if (!(Flags & PH_CM_COLUMN_WIDTHS_ONLY)) + { + if (columnPtr) + { + setColumn.Visible = TRUE; + setColumn.Width = (*columnPtr)->Width; + TreeNew_SetColumn(TreeNewHandle, TN_COLUMN_FLAG_VISIBLE | TN_COLUMN_WIDTH, &setColumn); + + if (!setColumn.Fixed) + { + // For compatibility reasons, normal columns have their display indicies stored + // one higher than usual (so they start from 1, not 0). Fix that here. + if (hasFixedColumn && (*columnPtr)->DisplayIndex != 0) + (*columnPtr)->DisplayIndex--; + + if ((*columnPtr)->DisplayIndex < PH_CM_ORDER_LIMIT) + { + orderArray[(*columnPtr)->DisplayIndex] = i; + + if ((ULONG)maxOrder < (*columnPtr)->DisplayIndex + 1) + maxOrder = (*columnPtr)->DisplayIndex + 1; + } + } + } + else if (!setColumn.Fixed) // never hide the fixed column + { + setColumn.Visible = FALSE; + TreeNew_SetColumn(TreeNewHandle, TN_COLUMN_FLAG_VISIBLE, &setColumn); + } + } + else + { + if (columnPtr) + { + setColumn.Width = (*columnPtr)->Width; + TreeNew_SetColumn(TreeNewHandle, TN_COLUMN_WIDTH, &setColumn); + } + } + + count++; + } + + i++; + } + + if (!(Flags & PH_CM_COLUMN_WIDTHS_ONLY)) + { + // Set the order array. + TreeNew_SetColumnOrderArray(TreeNewHandle, maxOrder, orderArray); + } + + TreeNew_SetRedraw(TreeNewHandle, TRUE); + + result = TRUE; + +CleanupExit: + PhBeginEnumHashtable(columnHashtable, &enumContext); + + while (pair = PhNextEnumHashtable(&enumContext)) + PhFree(pair->Value); + + PhDereferenceObject(columnHashtable); + } + + // Load sort settings. + + if (SortSettings && SortSettings->Length != 0) + { + PhSplitStringRefAtChar(SortSettings, ',', &valuePart, &subPart); + + if (valuePart.Length != 0 && subPart.Length != 0) + { + ULONG sortColumn; + PH_SORT_ORDER sortOrder; + + sortColumn = -1; + + if (valuePart.Buffer[0] == '+') + { + PH_STRINGREF pluginName; + ULONG subId; + PPH_CM_COLUMN cmColumn; + + if ( + Manager && + PhEmParseCompoundId(&valuePart, &pluginName, &subId) && + (cmColumn = PhCmFindColumn(Manager, &pluginName, subId)) + ) + { + sortColumn = cmColumn->Id; + } + } + else + { + PhStringToInteger64(&valuePart, 10, &integer); + sortColumn = (ULONG)integer; + } + + PhStringToInteger64(&subPart, 10, &integer); + sortOrder = (PH_SORT_ORDER)integer; + + if (sortColumn != -1 && sortOrder <= DescendingSortOrder) + { + TreeNew_SetSort(TreeNewHandle, sortColumn, sortOrder); + } + } + } + + return result; +} + +PPH_STRING PhCmSaveSettings( + _In_ HWND TreeNewHandle + ) +{ + return PhCmSaveSettingsEx(TreeNewHandle, NULL, 0, NULL); +} + +PPH_STRING PhCmSaveSettingsEx( + _In_ HWND TreeNewHandle, + _In_opt_ PPH_CM_MANAGER Manager, + _In_ ULONG Flags, + _Out_opt_ PPH_STRING *SortSettings + ) +{ + PH_STRING_BUILDER stringBuilder; + ULONG i = 0; + ULONG count = 0; + ULONG total; + ULONG increment; + PH_TREENEW_COLUMN column; + + total = TreeNew_GetColumnCount(TreeNewHandle); + + if (TreeNew_GetFixedColumn(TreeNewHandle)) + increment = 1; // the first normal column should have a display index that starts with 1, for compatibility + else + increment = 0; + + PhInitializeStringBuilder(&stringBuilder, 100); + + PhAppendFormatStringBuilder(&stringBuilder, L"@%u|", PhGlobalDpi); + + while (count < total) + { + if (TreeNew_GetColumn(TreeNewHandle, i, &column)) + { + if (!(Flags & PH_CM_COLUMN_WIDTHS_ONLY)) + { + if (column.Visible) + { + if (!Manager || i < Manager->MinId) + { + PhAppendFormatStringBuilder( + &stringBuilder, + L"%u,%u,%u|", + i, + column.Fixed ? 0 : column.DisplayIndex + increment, + column.Width + ); + } + else + { + PPH_CM_COLUMN cmColumn; + + cmColumn = column.Context; + PhAppendFormatStringBuilder( + &stringBuilder, + L"+%s+%u,%u,%u|", + cmColumn->Plugin->Name.Buffer, + cmColumn->SubId, + column.DisplayIndex + increment, + column.Width + ); + } + } + } + else + { + if (!Manager || i < Manager->MinId) + { + PhAppendFormatStringBuilder( + &stringBuilder, + L"%u,,%u|", + i, + column.Width + ); + } + else + { + PPH_CM_COLUMN cmColumn; + + cmColumn = column.Context; + PhAppendFormatStringBuilder( + &stringBuilder, + L"+%s+%u,,%u|", + cmColumn->Plugin->Name.Buffer, + cmColumn->SubId, + column.Width + ); + } + } + + count++; + } + + i++; + } + + if (stringBuilder.String->Length != 0) + PhRemoveEndStringBuilder(&stringBuilder, 1); + + if (SortSettings) + { + ULONG sortColumn; + PH_SORT_ORDER sortOrder; + + if (TreeNew_GetSort(TreeNewHandle, &sortColumn, &sortOrder)) + { + if (sortOrder != NoSortOrder) + { + if (!Manager || sortColumn < Manager->MinId) + { + *SortSettings = PhFormatString(L"%u,%u", sortColumn, sortOrder); + } + else + { + PH_TREENEW_COLUMN column; + PPH_CM_COLUMN cmColumn; + + if (TreeNew_GetColumn(TreeNewHandle, sortColumn, &column)) + { + cmColumn = column.Context; + *SortSettings = PhFormatString(L"+%s+%u,%u", cmColumn->Plugin->Name.Buffer, cmColumn->SubId, sortOrder); + } + else + { + *SortSettings = PhReferenceEmptyString(); + } + } + } + else + { + *SortSettings = PhCreateString(L"0,0"); + } + } + else + { + *SortSettings = PhReferenceEmptyString(); + } + } + + return PhFinalStringBuilderString(&stringBuilder); +} diff --git a/ProcessHacker/dbgcon.c b/ProcessHacker/dbgcon.c index d327bb58c58b..7708ddbae347 100644 --- a/ProcessHacker/dbgcon.c +++ b/ProcessHacker/dbgcon.c @@ -1,1695 +1,1695 @@ -/* - * Process Hacker - - * debug console - * - * Copyright (C) 2010-2011 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -/* - * This is a simple debugging console which is able to explore phlib's - * systems easily. Commands are provided to debug reference counting - * problems and memory usage, as well as to do general performance testing. - */ - -#include - -#include -#include -#include -#include -#include - -#include -#include -#include - -typedef struct _STRING_TABLE_ENTRY -{ - PPH_STRING String; - ULONG_PTR Count; -} STRING_TABLE_ENTRY, *PSTRING_TABLE_ENTRY; - -BOOL ConsoleHandlerRoutine( - _In_ DWORD dwCtrlType - ); - -VOID PhpPrintHashtableStatistics( - _In_ PPH_HASHTABLE Hashtable - ); - -NTSTATUS PhpDebugConsoleThreadStart( - _In_ PVOID Parameter - ); - -extern PH_FREE_LIST PhObjectSmallFreeList; - -static HANDLE DebugConsoleThreadHandle; -static PPH_SYMBOL_PROVIDER DebugConsoleSymbolProvider; - -static PPH_HASHTABLE ObjectListSnapshot = NULL; -#ifdef DEBUG -static PPH_LIST NewObjectList = NULL; -static PH_QUEUED_LOCK NewObjectListLock; -#endif - -static BOOLEAN ShowAllLeaks = FALSE; -static BOOLEAN InLeakDetection = FALSE; -static ULONG NumberOfLeaks; -static ULONG NumberOfLeaksShown; - -VOID PhShowDebugConsole( - VOID - ) -{ - if (AllocConsole()) - { - HMENU menu; - - // Disable the close button because it's impossible to handle - // those events. - menu = GetSystemMenu(GetConsoleWindow(), FALSE); - EnableMenuItem(menu, SC_CLOSE, MF_GRAYED | MF_DISABLED); - DeleteMenu(menu, SC_CLOSE, 0); - - // Set a handler so we can catch Ctrl+C and Ctrl+Break. - SetConsoleCtrlHandler(ConsoleHandlerRoutine, TRUE); - - freopen("CONOUT$", "w", stdout); - freopen("CONOUT$", "w", stderr); - freopen("CONIN$", "r", stdin); - DebugConsoleThreadHandle = PhCreateThread(0, PhpDebugConsoleThreadStart, NULL); - } - else - { - HWND consoleWindow; - - consoleWindow = GetConsoleWindow(); - - // Console window already exists, so bring it to the top. - if (IsIconic(consoleWindow)) - ShowWindow(consoleWindow, SW_RESTORE); - else - BringWindowToTop(consoleWindow); - - return; - } -} - -VOID PhCloseDebugConsole( - VOID - ) -{ - freopen("NUL", "w", stdout); - freopen("NUL", "w", stderr); - freopen("NUL", "r", stdin); - - FreeConsole(); -} - -static BOOL ConsoleHandlerRoutine( - _In_ DWORD dwCtrlType - ) -{ - switch (dwCtrlType) - { - case CTRL_C_EVENT: - case CTRL_BREAK_EVENT: - case CTRL_CLOSE_EVENT: - PhCloseDebugConsole(); - return TRUE; - } - - return FALSE; -} - -static BOOLEAN NTAPI PhpLoadCurrentProcessSymbolsCallback( - _In_ PPH_MODULE_INFO Module, - _In_opt_ PVOID Context - ) -{ - PhLoadModuleSymbolProvider((PPH_SYMBOL_PROVIDER)Context, Module->FileName->Buffer, - (ULONG64)Module->BaseAddress, Module->Size); - - return TRUE; -} - -static PWSTR PhpGetSymbolForAddress( - _In_ PVOID Address - ) -{ - return PH_AUTO_T(PH_STRING, PhGetSymbolFromAddress( - DebugConsoleSymbolProvider, (ULONG64)Address, NULL, NULL, NULL, NULL - ))->Buffer; -} - -static VOID PhpPrintObjectInfo( - _In_ PPH_OBJECT_HEADER ObjectHeader, - _In_ LONG RefToSubtract - ) -{ - PVOID object; - PPH_OBJECT_TYPE objectType; - WCHAR c = ' '; - - object = PhObjectHeaderToObject(ObjectHeader); - wprintf(L"%Ix", (ULONG_PTR)object); - objectType = PhGetObjectType(object); - - wprintf(L"\t% 20s", objectType->Name); - - if (ObjectHeader->Flags & PH_OBJECT_FROM_SMALL_FREE_LIST) - c = 'f'; - else if (ObjectHeader->Flags & PH_OBJECT_FROM_TYPE_FREE_LIST) - c = 'F'; - - wprintf(L"\t%4d %c", ObjectHeader->RefCount - RefToSubtract, c); - - if (!objectType) - { - // Dummy - } - else if (objectType == PhObjectTypeObject) - { - wprintf(L"\t%.32s", ((PPH_OBJECT_TYPE)object)->Name); - } - else if (objectType == PhStringType) - { - wprintf(L"\t%.32s", ((PPH_STRING)object)->Buffer); - } - else if (objectType == PhBytesType) - { - wprintf(L"\t%.32S", ((PPH_BYTES)object)->Buffer); - } - else if (objectType == PhListType) - { - wprintf(L"\tCount: %u", ((PPH_LIST)object)->Count); - } - else if (objectType == PhPointerListType) - { - wprintf(L"\tCount: %u", ((PPH_POINTER_LIST)object)->Count); - } - else if (objectType == PhHashtableType) - { - wprintf(L"\tCount: %u", ((PPH_HASHTABLE)object)->Count); - } - else if (objectType == PhProcessItemType) - { - wprintf( - L"\t%.28s (%d)", - ((PPH_PROCESS_ITEM)object)->ProcessName->Buffer, - HandleToLong(((PPH_PROCESS_ITEM)object)->ProcessId) - ); - } - else if (objectType == PhServiceItemType) - { - wprintf(L"\t%s", ((PPH_SERVICE_ITEM)object)->Name->Buffer); - } - else if (objectType == PhThreadItemType) - { - wprintf(L"\tTID: %u", HandleToUlong(((PPH_THREAD_ITEM)object)->ThreadId)); - } - - wprintf(L"\n"); -} - -static VOID PhpDumpObjectInfo( - _In_ PPH_OBJECT_HEADER ObjectHeader - ) -{ - PVOID object; - PPH_OBJECT_TYPE objectType; - - object = PhObjectHeaderToObject(ObjectHeader); - objectType = PhGetObjectType(object); - - __try - { - wprintf(L"Type: %s\n", objectType->Name); - wprintf(L"Reference count: %d\n", ObjectHeader->RefCount); - wprintf(L"Flags: %x\n", ObjectHeader->Flags); - - if (objectType == PhObjectTypeObject) - { - wprintf(L"Name: %s\n", ((PPH_OBJECT_TYPE)object)->Name); - wprintf(L"Number of objects: %u\n", ((PPH_OBJECT_TYPE)object)->NumberOfObjects); - wprintf(L"Flags: %u\n", ((PPH_OBJECT_TYPE)object)->Flags); - wprintf(L"Type index: %u\n", ((PPH_OBJECT_TYPE)object)->TypeIndex); - wprintf(L"Free list count: %u\n", ((PPH_OBJECT_TYPE)object)->FreeList.Count); - } - else if (objectType == PhStringType) - { - wprintf(L"%s\n", ((PPH_STRING)object)->Buffer); - } - else if (objectType == PhBytesType) - { - wprintf(L"%S\n", ((PPH_BYTES)object)->Buffer); - } - else if (objectType == PhHashtableType) - { - PhpPrintHashtableStatistics((PPH_HASHTABLE)object); - } - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - wprintf(L"Error.\n"); - } -} - -static VOID PhpPrintHashtableStatistics( - _In_ PPH_HASHTABLE Hashtable - ) -{ - ULONG i; - ULONG expectedLookupMisses = 0; - - wprintf(L"Count: %u\n", Hashtable->Count); - wprintf(L"Allocated buckets: %u\n", Hashtable->AllocatedBuckets); - wprintf(L"Allocated entries: %u\n", Hashtable->AllocatedEntries); - wprintf(L"Next free entry: %d\n", Hashtable->FreeEntry); - wprintf(L"Next usable entry: %d\n", Hashtable->NextEntry); - - wprintf(L"Equal function: %s\n", PhpGetSymbolForAddress(Hashtable->EqualFunction)); - wprintf(L"Hash function: %s\n", PhpGetSymbolForAddress(Hashtable->HashFunction)); - - wprintf(L"\nBuckets:\n"); - - for (i = 0; i < Hashtable->AllocatedBuckets; i++) - { - ULONG index; - ULONG count = 0; - - // Count the number of entries in this bucket. - - index = Hashtable->Buckets[i]; - - while (index != -1) - { - index = PH_HASHTABLE_GET_ENTRY(Hashtable, index)->Next; - count++; - } - - if (count != 0) - { - expectedLookupMisses += count - 1; - } - - if (count != 0) - { - wprintf(L"%lu: ", i); - - // Print out the entry indicies. - - index = Hashtable->Buckets[i]; - - while (index != -1) - { - wprintf(L"%lu", index); - - index = PH_HASHTABLE_GET_ENTRY(Hashtable, index)->Next; - count--; - - if (count != 0) - wprintf(L", "); - } - - wprintf(L"\n"); - } - else - { - //wprintf(L"%u: (empty)\n"); - } - } - - wprintf(L"\nExpected lookup misses: %lu\n", expectedLookupMisses); -} - -#ifdef DEBUG -static VOID PhpDebugCreateObjectHook( - _In_ PVOID Object, - _In_ SIZE_T Size, - _In_ ULONG Flags, - _In_ PPH_OBJECT_TYPE ObjectType - ) -{ - PhAcquireQueuedLockExclusive(&NewObjectListLock); - - if (NewObjectList) - { - PhReferenceObject(Object); - PhAddItemList(NewObjectList, Object); - } - - PhReleaseQueuedLockExclusive(&NewObjectListLock); -} -#endif - -#ifdef DEBUG -static VOID PhpDeleteNewObjectList( - VOID - ) -{ - if (NewObjectList) - { - ULONG i; - - for (i = 0; i < NewObjectList->Count; i++) - PhDereferenceObject(NewObjectList->Items[i]); - - PhDereferenceObject(NewObjectList); - NewObjectList = NULL; - } -} -#endif - -static BOOLEAN PhpStringHashtableEqualFunction( - _In_ PVOID Entry1, - _In_ PVOID Entry2 - ) -{ - PSTRING_TABLE_ENTRY entry1 = Entry1; - PSTRING_TABLE_ENTRY entry2 = Entry2; - - return PhEqualString(entry1->String, entry2->String, FALSE); -} - -static ULONG PhpStringHashtableHashFunction( - _In_ PVOID Entry - ) -{ - PSTRING_TABLE_ENTRY entry = Entry; - - return PhHashBytes((PUCHAR)entry->String->Buffer, entry->String->Length); -} - -static int __cdecl PhpStringEntryCompareByCount( - _In_ const void *elem1, - _In_ const void *elem2 - ) -{ - PSTRING_TABLE_ENTRY entry1 = *(PSTRING_TABLE_ENTRY *)elem1; - PSTRING_TABLE_ENTRY entry2 = *(PSTRING_TABLE_ENTRY *)elem2; - - return uintptrcmp(entry2->Count, entry1->Count); -} - -static NTSTATUS PhpLeakEnumerationRoutine( - _In_ LONG Reserved, - _In_ PVOID HeapHandle, - _In_ PVOID BaseAddress, - _In_ SIZE_T BlockSize, - _In_ ULONG StackTraceDepth, - _In_ PVOID *StackTrace - ) -{ - ULONG i; - - if (!InLeakDetection) - return 0; - - if (!HeapHandle) // means no more entries - return 0; - - if (ShowAllLeaks || HeapHandle == PhHeapHandle) - { - wprintf(L"Leak at 0x%Ix (%Iu bytes). Stack trace:\n", (ULONG_PTR)BaseAddress, BlockSize); - - for (i = 0; i < StackTraceDepth; i++) - { - PPH_STRING symbol; - - symbol = PhGetSymbolFromAddress(DebugConsoleSymbolProvider, (ULONG64)StackTrace[i], NULL, NULL, NULL, NULL); - - if (symbol) - wprintf(L"\t%s\n", symbol->Buffer); - else - wprintf(L"\t?\n"); - - PhDereferenceObject(symbol); - } - - NumberOfLeaksShown++; - } - - NumberOfLeaks++; - - return 0; -} - -typedef struct _STOPWATCH -{ - LARGE_INTEGER StartCounter; - LARGE_INTEGER EndCounter; - LARGE_INTEGER Frequency; -} STOPWATCH, *PSTOPWATCH; - -static VOID PhInitializeStopwatch( - _Out_ PSTOPWATCH Stopwatch - ) -{ - Stopwatch->StartCounter.QuadPart = 0; - Stopwatch->EndCounter.QuadPart = 0; -} - -static VOID PhStartStopwatch( - _Inout_ PSTOPWATCH Stopwatch - ) -{ - NtQueryPerformanceCounter(&Stopwatch->StartCounter, &Stopwatch->Frequency); -} - -static VOID PhStopStopwatch( - _Inout_ PSTOPWATCH Stopwatch - ) -{ - NtQueryPerformanceCounter(&Stopwatch->EndCounter, NULL); -} - -static ULONG PhGetMillisecondsStopwatch( - _In_ PSTOPWATCH Stopwatch - ) -{ - LARGE_INTEGER countsPerMs; - - countsPerMs = Stopwatch->Frequency; - countsPerMs.QuadPart /= 1000; - - return (ULONG)((Stopwatch->EndCounter.QuadPart - Stopwatch->StartCounter.QuadPart) / - countsPerMs.QuadPart); -} - -typedef VOID (FASTCALL *PPHF_RW_LOCK_FUNCTION)( - _In_ PVOID Parameter - ); - -typedef struct _RW_TEST_CONTEXT -{ - PWSTR Name; - - PPHF_RW_LOCK_FUNCTION AcquireExclusive; - PPHF_RW_LOCK_FUNCTION AcquireShared; - PPHF_RW_LOCK_FUNCTION ReleaseExclusive; - PPHF_RW_LOCK_FUNCTION ReleaseShared; - - PVOID Parameter; -} RW_TEST_CONTEXT, *PRW_TEST_CONTEXT; - -static PH_BARRIER RwStartBarrier; -static LONG RwReadersActive; -static LONG RwWritersActive; - -static NTSTATUS PhpRwLockTestThreadStart( - _In_ PVOID Parameter - ) -{ -#define RW_ITERS 10000 -#define RW_READ_ITERS 100 -#define RW_WRITE_ITERS 10 -#define RW_READ_SPIN_ITERS 60 -#define RW_WRITE_SPIN_ITERS 200 - - RW_TEST_CONTEXT context = *(PRW_TEST_CONTEXT)Parameter; - ULONG i; - ULONG j; - ULONG k; - ULONG m; - - PhWaitForBarrier(&RwStartBarrier, FALSE); - - for (i = 0; i < RW_ITERS; i++) - { - for (j = 0; j < RW_READ_ITERS; j++) - { - // Read zone - - context.AcquireShared(context.Parameter); - _InterlockedIncrement(&RwReadersActive); - - for (m = 0; m < RW_READ_SPIN_ITERS; m++) - YieldProcessor(); - - if (RwWritersActive != 0) - { - wprintf(L"[fail]: writers active in read zone!\n"); - NtWaitForSingleObject(NtCurrentProcess(), FALSE, NULL); - } - - _InterlockedDecrement(&RwReadersActive); - context.ReleaseShared(context.Parameter); - - // Spin for a while - - for (m = 0; m < 10; m++) - YieldProcessor(); - - if (j == RW_READ_ITERS / 2) - { - // Write zone - - for (k = 0; k < RW_WRITE_ITERS; k++) - { - context.AcquireExclusive(context.Parameter); - _InterlockedIncrement(&RwWritersActive); - - for (m = 0; m < RW_WRITE_SPIN_ITERS; m++) - YieldProcessor(); - - if (RwReadersActive != 0) - { - wprintf(L"[fail]: readers active in write zone!\n"); - NtWaitForSingleObject(NtCurrentProcess(), FALSE, NULL); - } - - _InterlockedDecrement(&RwWritersActive); - context.ReleaseExclusive(context.Parameter); - } - } - } - } - - return STATUS_SUCCESS; -} - -static VOID PhpTestRwLock( - _In_ PRW_TEST_CONTEXT Context - ) -{ -#define RW_PROCESSORS 4 - - STOPWATCH stopwatch; - ULONG i; - HANDLE threadHandles[RW_PROCESSORS]; - - // Dummy - - Context->AcquireExclusive(Context->Parameter); - Context->ReleaseExclusive(Context->Parameter); - Context->AcquireShared(Context->Parameter); - Context->ReleaseShared(Context->Parameter); - - // Null test - - PhStartStopwatch(&stopwatch); - - for (i = 0; i < 2000000; i++) - { - Context->AcquireExclusive(Context->Parameter); - Context->ReleaseExclusive(Context->Parameter); - Context->AcquireShared(Context->Parameter); - Context->ReleaseShared(Context->Parameter); - } - - PhStopStopwatch(&stopwatch); - - wprintf(L"[null] %s: %ums\n", Context->Name, PhGetMillisecondsStopwatch(&stopwatch)); - - // Stress test - - PhInitializeBarrier(&RwStartBarrier, RW_PROCESSORS + 1); - RwReadersActive = 0; - RwWritersActive = 0; - - for (i = 0; i < RW_PROCESSORS; i++) - { - threadHandles[i] = PhCreateThread(0, PhpRwLockTestThreadStart, Context); - } - - PhWaitForBarrier(&RwStartBarrier, FALSE); - PhStartStopwatch(&stopwatch); - NtWaitForMultipleObjects(RW_PROCESSORS, threadHandles, WaitAll, FALSE, NULL); - PhStopStopwatch(&stopwatch); - - for (i = 0; i < RW_PROCESSORS; i++) - NtClose(threadHandles[i]); - - wprintf(L"[strs] %s: %ums\n", Context->Name, PhGetMillisecondsStopwatch(&stopwatch)); -} - -VOID FASTCALL PhfAcquireCriticalSection( - _In_ PRTL_CRITICAL_SECTION CriticalSection - ) -{ - RtlEnterCriticalSection(CriticalSection); -} - -VOID FASTCALL PhfReleaseCriticalSection( - _In_ PRTL_CRITICAL_SECTION CriticalSection - ) -{ - RtlLeaveCriticalSection(CriticalSection); -} - -VOID FASTCALL PhfReleaseQueuedLockExclusiveUsingInline( - _In_ PPH_QUEUED_LOCK QueuedLock - ) -{ - PhReleaseQueuedLockExclusive(QueuedLock); -} - -NTSTATUS PhpDebugConsoleThreadStart( - _In_ PVOID Parameter - ) -{ - PH_AUTO_POOL autoPool; - BOOLEAN exit = FALSE; - - PhInitializeAutoPool(&autoPool); - - DebugConsoleSymbolProvider = PhCreateSymbolProvider(NtCurrentProcessId()); - - { - WCHAR buffer[512]; - UNICODE_STRING name = RTL_CONSTANT_STRING(L"_NT_SYMBOL_PATH"); - UNICODE_STRING var; - PPH_STRING newSearchPath; - - var.Buffer = buffer; - var.MaximumLength = sizeof(buffer); - - if (!NT_SUCCESS(RtlQueryEnvironmentVariable_U(NULL, &name, &var))) - buffer[0] = 0; - - newSearchPath = PhFormatString(L"%s;%s", buffer, PhApplicationDirectory->Buffer); - PhSetSearchPathSymbolProvider(DebugConsoleSymbolProvider, newSearchPath->Buffer); - PhDereferenceObject(newSearchPath); - } - - PhEnumGenericModules(NtCurrentProcessId(), NtCurrentProcess(), - 0, PhpLoadCurrentProcessSymbolsCallback, DebugConsoleSymbolProvider); - -#ifdef DEBUG - PhInitializeQueuedLock(&NewObjectListLock); - PhDbgCreateObjectHook = PhpDebugCreateObjectHook; -#endif - - wprintf(L"Press Ctrl+C or type \"exit\" to close the debug console. Type \"help\" for a list of commands.\n"); - - while (!exit) - { - static PWSTR delims = L" \t"; - static PWSTR commandDebugOnly = L"This command is not available on non-debug builds.\n"; - - WCHAR line[201]; - ULONG inputLength; - PWSTR context; - PWSTR command; - - wprintf(L"dbg>"); - - if (!fgetws(line, sizeof(line) / 2 - 1, stdin)) - break; - - // Remove the terminating new line character. - - inputLength = (ULONG)PhCountStringZ(line); - - if (inputLength != 0) - line[inputLength - 1] = 0; - - context = NULL; - command = wcstok_s(line, delims, &context); - - if (!command) - { - continue; - } - else if (PhEqualStringZ(command, L"help", TRUE)) - { - wprintf( - L"Commands:\n" - L"exit\n" - L"testperf\n" - L"testlocks\n" - L"stats\n" - L"objects [type-name-filter]\n" - L"objtrace object-address\n" - L"objmksnap\n" - L"objcmpsnap\n" - L"objmknew\n" - L"objdelnew\n" - L"objviewnew\n" - L"dumpobj\n" - L"dumpautopool\n" - L"threads\n" - L"provthreads\n" - L"workqueues\n" - L"procrecords\n" - L"procitem\n" - L"uniquestr\n" - L"enableleakdetect\n" - L"leakdetect\n" - L"mem\n" - ); - } - else if (PhEqualStringZ(command, L"exit", TRUE)) - { - PhCloseDebugConsole(); - exit = TRUE; - } - else if (PhEqualStringZ(command, L"testperf", TRUE)) - { - STOPWATCH stopwatch; - ULONG i; - PPH_STRING testString; - RTL_CRITICAL_SECTION testCriticalSection; - PH_FAST_LOCK testFastLock; - PH_QUEUED_LOCK testQueuedLock; - - // Control (string reference counting) - - testString = PhCreateString(L""); - PhReferenceObject(testString); - PhDereferenceObject(testString); - PhStartStopwatch(&stopwatch); - - for (i = 0; i < 10000000; i++) - { - PhReferenceObject(testString); - PhDereferenceObject(testString); - } - - PhStopStopwatch(&stopwatch); - PhDereferenceObject(testString); - - wprintf(L"Referencing: %ums\n", PhGetMillisecondsStopwatch(&stopwatch)); - - // Critical section - - RtlInitializeCriticalSection(&testCriticalSection); - RtlEnterCriticalSection(&testCriticalSection); - RtlLeaveCriticalSection(&testCriticalSection); - PhStartStopwatch(&stopwatch); - - for (i = 0; i < 10000000; i++) - { - RtlEnterCriticalSection(&testCriticalSection); - RtlLeaveCriticalSection(&testCriticalSection); - } - - PhStopStopwatch(&stopwatch); - RtlDeleteCriticalSection(&testCriticalSection); - - wprintf(L"Critical section: %ums\n", PhGetMillisecondsStopwatch(&stopwatch)); - - // Fast lock - - PhInitializeFastLock(&testFastLock); - PhAcquireFastLockExclusive(&testFastLock); - PhReleaseFastLockExclusive(&testFastLock); - PhStartStopwatch(&stopwatch); - - for (i = 0; i < 10000000; i++) - { - PhAcquireFastLockExclusive(&testFastLock); - PhReleaseFastLockExclusive(&testFastLock); - } - - PhStopStopwatch(&stopwatch); - PhDeleteFastLock(&testFastLock); - - wprintf(L"Fast lock: %ums\n", PhGetMillisecondsStopwatch(&stopwatch)); - - // Queued lock - - PhInitializeQueuedLock(&testQueuedLock); - PhAcquireQueuedLockExclusive(&testQueuedLock); - PhReleaseQueuedLockExclusive(&testQueuedLock); - PhStartStopwatch(&stopwatch); - - for (i = 0; i < 10000000; i++) - { - PhAcquireQueuedLockExclusive(&testQueuedLock); - PhReleaseQueuedLockExclusive(&testQueuedLock); - } - - PhStopStopwatch(&stopwatch); - - wprintf(L"Queued lock: %ums\n", PhGetMillisecondsStopwatch(&stopwatch)); - } - else if (PhEqualStringZ(command, L"testlocks", TRUE)) - { - RW_TEST_CONTEXT testContext; - PH_FAST_LOCK fastLock; - PH_QUEUED_LOCK queuedLock; - RTL_CRITICAL_SECTION criticalSection; - - testContext.Name = L"FastLock"; - testContext.AcquireExclusive = PhfAcquireFastLockExclusive; - testContext.AcquireShared = PhfAcquireFastLockShared; - testContext.ReleaseExclusive = PhfReleaseFastLockExclusive; - testContext.ReleaseShared = PhfReleaseFastLockShared; - testContext.Parameter = &fastLock; - PhInitializeFastLock(&fastLock); - PhpTestRwLock(&testContext); - PhDeleteFastLock(&fastLock); - - testContext.Name = L"QueuedLock"; - testContext.AcquireExclusive = PhfAcquireQueuedLockExclusive; - testContext.AcquireShared = PhfAcquireQueuedLockShared; - testContext.ReleaseExclusive = PhfReleaseQueuedLockExclusive; - testContext.ReleaseShared = PhfReleaseQueuedLockShared; - testContext.Parameter = &queuedLock; - PhInitializeQueuedLock(&queuedLock); - PhpTestRwLock(&testContext); - - testContext.Name = L"CriticalSection"; - testContext.AcquireExclusive = PhfAcquireCriticalSection; - testContext.AcquireShared = PhfAcquireCriticalSection; - testContext.ReleaseExclusive = PhfReleaseCriticalSection; - testContext.ReleaseShared = PhfReleaseCriticalSection; - testContext.Parameter = &criticalSection; - RtlInitializeCriticalSection(&criticalSection); - PhpTestRwLock(&testContext); - RtlDeleteCriticalSection(&criticalSection); - - testContext.Name = L"QueuedLockMutex"; - testContext.AcquireExclusive = PhfAcquireQueuedLockExclusive; - testContext.AcquireShared = PhfAcquireQueuedLockExclusive; - testContext.ReleaseExclusive = PhfReleaseQueuedLockExclusive; - testContext.ReleaseShared = PhfReleaseQueuedLockExclusive; - testContext.Parameter = &queuedLock; - PhInitializeQueuedLock(&queuedLock); - PhpTestRwLock(&testContext); - } - else if (PhEqualStringZ(command, L"stats", TRUE)) - { -#ifdef DEBUG - wprintf(L"Object small free list count: %u\n", PhObjectSmallFreeList.Count); - wprintf(L"Statistics:\n"); -#define PRINT_STATISTIC(Name) wprintf(L#Name L": %u\n", PhLibStatisticsBlock.Name); - - PRINT_STATISTIC(BaseThreadsCreated); - PRINT_STATISTIC(BaseThreadsCreateFailed); - PRINT_STATISTIC(BaseStringBuildersCreated); - PRINT_STATISTIC(BaseStringBuildersResized); - PRINT_STATISTIC(RefObjectsCreated); - PRINT_STATISTIC(RefObjectsDestroyed); - PRINT_STATISTIC(RefObjectsAllocated); - PRINT_STATISTIC(RefObjectsFreed); - PRINT_STATISTIC(RefObjectsAllocatedFromSmallFreeList); - PRINT_STATISTIC(RefObjectsFreedToSmallFreeList); - PRINT_STATISTIC(RefObjectsAllocatedFromTypeFreeList); - PRINT_STATISTIC(RefObjectsFreedToTypeFreeList); - PRINT_STATISTIC(RefObjectsDeleteDeferred); - PRINT_STATISTIC(RefAutoPoolsCreated); - PRINT_STATISTIC(RefAutoPoolsDestroyed); - PRINT_STATISTIC(RefAutoPoolsDynamicAllocated); - PRINT_STATISTIC(RefAutoPoolsDynamicResized); - PRINT_STATISTIC(QlBlockSpins); - PRINT_STATISTIC(QlBlockWaits); - PRINT_STATISTIC(QlAcquireExclusiveBlocks); - PRINT_STATISTIC(QlAcquireSharedBlocks); - PRINT_STATISTIC(WqWorkQueueThreadsCreated); - PRINT_STATISTIC(WqWorkQueueThreadsCreateFailed); - PRINT_STATISTIC(WqWorkItemsQueued); - -#else - wprintf(commandDebugOnly); -#endif - } - else if (PhEqualStringZ(command, L"objects", TRUE)) - { -#ifdef DEBUG - PWSTR typeFilter = wcstok_s(NULL, delims, &context); - PLIST_ENTRY currentEntry; - ULONG totalNumberOfObjects = 0; - //SIZE_T totalNumberOfBytes = 0; - - if (typeFilter) - _wcslwr(typeFilter); - - PhAcquireQueuedLockShared(&PhDbgObjectListLock); - - currentEntry = PhDbgObjectListHead.Flink; - - while (currentEntry != &PhDbgObjectListHead) - { - PPH_OBJECT_HEADER objectHeader; - WCHAR typeName[32]; - - objectHeader = CONTAINING_RECORD(currentEntry, PH_OBJECT_HEADER, ObjectListEntry); - - // Make sure the object isn't being destroyed. - if (!PhReferenceObjectSafe(PhObjectHeaderToObject(objectHeader))) - { - currentEntry = currentEntry->Flink; - continue; - } - - totalNumberOfObjects++; - //totalNumberOfBytes += objectHeader->Size; - - if (typeFilter) - { - wcscpy_s(typeName, sizeof(typeName) / 2, PhGetObjectType(PhObjectHeaderToObject(objectHeader))->Name); - _wcslwr(typeName); - } - - if ( - !typeFilter || - (typeFilter && wcsstr(typeName, typeFilter)) - ) - { - PhpPrintObjectInfo(objectHeader, 1); - } - - currentEntry = currentEntry->Flink; - PhDereferenceObjectDeferDelete(PhObjectHeaderToObject(objectHeader)); - } - - PhReleaseQueuedLockShared(&PhDbgObjectListLock); - - wprintf(L"\n"); - wprintf(L"Total number: %lu\n", totalNumberOfObjects); - /*wprintf(L"Total size (excl. header): %s\n", - ((PPH_STRING)PH_AUTO(PhFormatSize(totalNumberOfBytes, 1)))->Buffer);*/ - wprintf(L"Total overhead (header): %s\n", - ((PPH_STRING)PH_AUTO( - PhFormatSize(PhAddObjectHeaderSize(0) * totalNumberOfObjects, 1) - ))->Buffer); -#else - wprintf(commandDebugOnly); -#endif - } - else if (PhEqualStringZ(command, L"objtrace", TRUE)) - { -#ifdef DEBUG - PWSTR objectAddress = wcstok_s(NULL, delims, &context); - PH_STRINGREF objectAddressString; - ULONG64 address; - - if (!objectAddress) - { - wprintf(L"Missing object address.\n"); - goto EndCommand; - } - - PhInitializeStringRef(&objectAddressString, objectAddress); - - if (PhStringToInteger64(&objectAddressString, 16, &address)) - { - PPH_OBJECT_HEADER objectHeader = (PPH_OBJECT_HEADER)PhObjectToObjectHeader((PVOID)address); - PVOID stackBackTrace[16]; - ULONG i; - - // The address may not be valid. - __try - { - memcpy(stackBackTrace, objectHeader->StackBackTrace, 16 * sizeof(PVOID)); - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - PPH_STRING message; - - message = PH_AUTO(PhGetNtMessage(GetExceptionCode())); - wprintf(L"Error: %s\n", PhGetString(message)); - - goto EndCommand; - } - - for (i = 0; i < 16; i++) - { - if (!stackBackTrace[i]) - break; - - wprintf(L"%s\n", PhpGetSymbolForAddress(stackBackTrace[i])); - } - } - else - { - wprintf(L"Invalid object address.\n"); - } -#else - wprintf(commandDebugOnly); -#endif - } - else if (PhEqualStringZ(command, L"objmksnap", TRUE)) - { -#ifdef DEBUG - PLIST_ENTRY currentEntry; - - if (ObjectListSnapshot) - { - PhDereferenceObject(ObjectListSnapshot); - ObjectListSnapshot = NULL; - } - - ObjectListSnapshot = PhCreateSimpleHashtable(100); - - PhAcquireQueuedLockShared(&PhDbgObjectListLock); - - currentEntry = PhDbgObjectListHead.Flink; - - while (currentEntry != &PhDbgObjectListHead) - { - PPH_OBJECT_HEADER objectHeader; - - objectHeader = CONTAINING_RECORD(currentEntry, PH_OBJECT_HEADER, ObjectListEntry); - currentEntry = currentEntry->Flink; - - if (PhObjectHeaderToObject(objectHeader) != ObjectListSnapshot) - PhAddItemSimpleHashtable(ObjectListSnapshot, objectHeader, NULL); - } - - PhReleaseQueuedLockShared(&PhDbgObjectListLock); -#else - wprintf(commandDebugOnly); -#endif - } - else if (PhEqualStringZ(command, L"objcmpsnap", TRUE)) - { -#ifdef DEBUG - PLIST_ENTRY currentEntry; - PPH_LIST newObjects; - ULONG i; - - if (!ObjectListSnapshot) - { - wprintf(L"No snapshot.\n"); - goto EndCommand; - } - - newObjects = PhCreateList(10); - - PhAcquireQueuedLockShared(&PhDbgObjectListLock); - - currentEntry = PhDbgObjectListHead.Flink; - - while (currentEntry != &PhDbgObjectListHead) - { - PPH_OBJECT_HEADER objectHeader; - - objectHeader = CONTAINING_RECORD(currentEntry, PH_OBJECT_HEADER, ObjectListEntry); - currentEntry = currentEntry->Flink; - - if ( - PhObjectHeaderToObject(objectHeader) != ObjectListSnapshot && - PhObjectHeaderToObject(objectHeader) != newObjects - ) - { - if (!PhFindItemSimpleHashtable(ObjectListSnapshot, objectHeader)) - { - if (PhReferenceObjectSafe(PhObjectHeaderToObject(objectHeader))) - PhAddItemList(newObjects, objectHeader); - } - } - } - - PhReleaseQueuedLockShared(&PhDbgObjectListLock); - - for (i = 0; i < newObjects->Count; i++) - { - PPH_OBJECT_HEADER objectHeader = newObjects->Items[i]; - - PhpPrintObjectInfo(objectHeader, 1); - - PhDereferenceObject(PhObjectHeaderToObject(objectHeader)); - } - - PhDereferenceObject(newObjects); -#else - wprintf(commandDebugOnly); -#endif - } - else if (PhEqualStringZ(command, L"objmknew", TRUE)) - { -#ifdef DEBUG - PhAcquireQueuedLockExclusive(&NewObjectListLock); - PhpDeleteNewObjectList(); - PhReleaseQueuedLockExclusive(&NewObjectListLock); - - // Creation needs to be done outside of the lock, - // otherwise a deadlock will occur. - NewObjectList = PhCreateList(100); -#else - wprintf(commandDebugOnly); -#endif - } - else if (PhEqualStringZ(command, L"objdelnew", TRUE)) - { -#ifdef DEBUG - PhAcquireQueuedLockExclusive(&NewObjectListLock); - PhpDeleteNewObjectList(); - PhReleaseQueuedLockExclusive(&NewObjectListLock); -#else - wprintf(commandDebugOnly); -#endif - } - else if (PhEqualStringZ(command, L"objviewnew", TRUE)) - { -#ifdef DEBUG - ULONG i; - - PhAcquireQueuedLockExclusive(&NewObjectListLock); - - if (!NewObjectList) - { - wprintf(L"Object creation hooking not active.\n"); - PhReleaseQueuedLockExclusive(&NewObjectListLock); - goto EndCommand; - } - - for (i = 0; i < NewObjectList->Count; i++) - { - PhpPrintObjectInfo(PhObjectToObjectHeader(NewObjectList->Items[i]), 1); - } - - PhReleaseQueuedLockExclusive(&NewObjectListLock); -#else - wprintf(commandDebugOnly); -#endif - } - else if (PhEqualStringZ(command, L"dumpobj", TRUE)) - { - PWSTR addressString = wcstok_s(NULL, delims, &context); - PH_STRINGREF addressStringRef; - ULONG64 address; - - if (!addressString) - goto EndCommand; - - PhInitializeStringRef(&addressStringRef, addressString); - - if (PhStringToInteger64(&addressStringRef, 16, &address)) - { - PhpDumpObjectInfo((PPH_OBJECT_HEADER)PhObjectToObjectHeader((PVOID)address)); - } - } - else if (PhEqualStringZ(command, L"dumpautopool", TRUE)) - { - PWSTR addressString = wcstok_s(NULL, delims, &context); - PH_STRINGREF addressStringRef; - ULONG64 address; - - if (!addressString) - goto EndCommand; - - PhInitializeStringRef(&addressStringRef, addressString); - - if (PhStringToInteger64(&addressStringRef, 16, &address)) - { - PPH_AUTO_POOL userAutoPool = (PPH_AUTO_POOL)address; - ULONG i; - - __try - { - wprintf(L"Static count: %u\n", userAutoPool->StaticCount); - wprintf(L"Dynamic count: %u\n", userAutoPool->DynamicCount); - wprintf(L"Dynamic allocated: %u\n", userAutoPool->DynamicAllocated); - - wprintf(L"Static objects:\n"); - - for (i = 0; i < userAutoPool->StaticCount; i++) - PhpPrintObjectInfo(PhObjectToObjectHeader(userAutoPool->StaticObjects[i]), 0); - - wprintf(L"Dynamic objects:\n"); - - for (i = 0; i < userAutoPool->DynamicCount; i++) - PhpPrintObjectInfo(PhObjectToObjectHeader(userAutoPool->DynamicObjects[i]), 0); - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - goto EndCommand; - } - } - } - else if (PhEqualStringZ(command, L"threads", TRUE)) - { -#ifdef DEBUG - PLIST_ENTRY currentEntry; - - PhAcquireQueuedLockShared(&PhDbgThreadListLock); - - currentEntry = PhDbgThreadListHead.Flink; - - while (currentEntry != &PhDbgThreadListHead) - { - PPHP_BASE_THREAD_DBG dbg; - - dbg = CONTAINING_RECORD(currentEntry, PHP_BASE_THREAD_DBG, ListEntry); - - wprintf(L"Thread %u\n", HandleToUlong(dbg->ClientId.UniqueThread)); - wprintf(L"\tStart Address: %s\n", PhpGetSymbolForAddress(dbg->StartAddress)); - wprintf(L"\tParameter: %Ix\n", (ULONG_PTR)dbg->Parameter); - wprintf(L"\tCurrent auto-pool: %Ix\n", (ULONG_PTR)dbg->CurrentAutoPool); - - currentEntry = currentEntry->Flink; - } - - PhReleaseQueuedLockShared(&PhDbgThreadListLock); -#else - wprintf(commandDebugOnly); -#endif - } - else if (PhEqualStringZ(command, L"provthreads", TRUE)) - { -#ifdef DEBUG - ULONG i; - - if (PhDbgProviderList) - { - PhAcquireQueuedLockShared(&PhDbgProviderListLock); - - for (i = 0; i < PhDbgProviderList->Count; i++) - { - PPH_PROVIDER_THREAD providerThread = PhDbgProviderList->Items[i]; - THREAD_BASIC_INFORMATION basicInfo; - PLIST_ENTRY providerEntry; - - if (providerThread->ThreadHandle) - { - PhGetThreadBasicInformation(providerThread->ThreadHandle, &basicInfo); - wprintf(L"Thread %u\n", HandleToUlong(basicInfo.ClientId.UniqueThread)); - } - else - { - wprintf(L"Thread not running\n"); - } - - PhAcquireQueuedLockExclusive(&providerThread->Lock); - - providerEntry = providerThread->ListHead.Flink; - - while (providerEntry != &providerThread->ListHead) - { - PPH_PROVIDER_REGISTRATION registration; - - registration = CONTAINING_RECORD(providerEntry, PH_PROVIDER_REGISTRATION, ListEntry); - - wprintf(L"\tProvider registration at %Ix\n", (ULONG_PTR)registration); - wprintf(L"\t\tEnabled: %s\n", registration->Enabled ? L"Yes" : L"No"); - wprintf(L"\t\tFunction: %s\n", PhpGetSymbolForAddress(registration->Function)); - - if (registration->Object) - { - wprintf(L"\t\tObject:\n"); - PhpPrintObjectInfo(PhObjectToObjectHeader(registration->Object), 0); - } - - providerEntry = providerEntry->Flink; - } - - PhReleaseQueuedLockExclusive(&providerThread->Lock); - - wprintf(L"\n"); - } - - PhReleaseQueuedLockShared(&PhDbgProviderListLock); - } -#else - wprintf(commandDebugOnly); -#endif - } - else if (PhEqualStringZ(command, L"workqueues", TRUE)) - { -#ifdef DEBUG - ULONG i; - - if (PhDbgWorkQueueList) - { - PhAcquireQueuedLockShared(&PhDbgWorkQueueListLock); - - for (i = 0; i < PhDbgWorkQueueList->Count; i++) - { - PPH_WORK_QUEUE workQueue = PhDbgWorkQueueList->Items[i]; - PLIST_ENTRY workQueueItemEntry; - - wprintf(L"Work queue at %s\n", PhpGetSymbolForAddress(workQueue)); - wprintf(L"Maximum threads: %u\n", workQueue->MaximumThreads); - wprintf(L"Minimum threads: %u\n", workQueue->MinimumThreads); - wprintf(L"No work timeout: %d\n", workQueue->NoWorkTimeout); - - wprintf(L"Current threads: %u\n", workQueue->CurrentThreads); - wprintf(L"Busy count: %u\n", workQueue->BusyCount); - - PhAcquireQueuedLockExclusive(&workQueue->QueueLock); - - // List the items backwards. - workQueueItemEntry = workQueue->QueueListHead.Blink; - - while (workQueueItemEntry != &workQueue->QueueListHead) - { - PPH_WORK_QUEUE_ITEM workQueueItem; - - workQueueItem = CONTAINING_RECORD(workQueueItemEntry, PH_WORK_QUEUE_ITEM, ListEntry); - - wprintf(L"\tWork queue item at %Ix\n", (ULONG_PTR)workQueueItem); - wprintf(L"\t\tFunction: %s\n", PhpGetSymbolForAddress(workQueueItem->Function)); - wprintf(L"\t\tContext: %Ix\n", (ULONG_PTR)workQueueItem->Context); - - workQueueItemEntry = workQueueItemEntry->Blink; - } - - PhReleaseQueuedLockExclusive(&workQueue->QueueLock); - - wprintf(L"\n"); - } - - PhReleaseQueuedLockShared(&PhDbgWorkQueueListLock); - } -#else - wprintf(commandDebugOnly); -#endif - } - else if (PhEqualStringZ(command, L"procrecords", TRUE)) - { - PPH_PROCESS_RECORD record; - ULONG i; - SYSTEMTIME systemTime; - PPH_PROCESS_RECORD startRecord; - - PhAcquireQueuedLockShared(&PhProcessRecordListLock); - - for (i = 0; i < PhProcessRecordList->Count; i++) - { - record = (PPH_PROCESS_RECORD)PhProcessRecordList->Items[i]; - - PhLargeIntegerToLocalSystemTime(&systemTime, &record->CreateTime); - wprintf(L"Records for %s %s:\n", - ((PPH_STRING)PH_AUTO(PhFormatDate(&systemTime, NULL)))->Buffer, - ((PPH_STRING)PH_AUTO(PhFormatTime(&systemTime, NULL)))->Buffer - ); - - startRecord = record; - - do - { - wprintf(L"\tRecord at %Ix: %s (%u) (refs: %d)\n", (ULONG_PTR)record, record->ProcessName->Buffer, HandleToUlong(record->ProcessId), record->RefCount); - - if (record->FileName) - wprintf(L"\t\t%s\n", record->FileName->Buffer); - - record = CONTAINING_RECORD(record->ListEntry.Flink, PH_PROCESS_RECORD, ListEntry); - } while (record != startRecord); - } - - PhReleaseQueuedLockShared(&PhProcessRecordListLock); - } - else if (PhEqualStringZ(command, L"procitem", TRUE)) - { - PWSTR filterString; - PH_STRINGREF filterRef; - ULONG64 filter64; - LONG_PTR processIdFilter = -9; // can't use -2, -1 or 0 because they're all used for process IDs - ULONG_PTR processAddressFilter = 0; - PWSTR imageNameFilter = NULL; - BOOLEAN showAll = FALSE; - PPH_PROCESS_ITEM *processes; - ULONG numberOfProcesses; - ULONG i; - - filterString = wcstok_s(NULL, delims, &context); - - if (filterString) - { - PhInitializeStringRef(&filterRef, filterString); - - if (PhStringToInteger64(&filterRef, 10, &filter64)) - processIdFilter = (LONG_PTR)filter64; - if (PhStringToInteger64(&filterRef, 16, &filter64)) - processAddressFilter = (ULONG_PTR)filter64; - - imageNameFilter = filterString; - } - else - { - showAll = TRUE; - } - - PhEnumProcessItems(&processes, &numberOfProcesses); - - for (i = 0; i < numberOfProcesses; i++) - { - PPH_PROCESS_ITEM process = processes[i]; - - if ( - showAll || - (processIdFilter != -9 && (LONG_PTR)process->ProcessId == processIdFilter) || - (processAddressFilter != 0 && (ULONG_PTR)process == processAddressFilter) || - (imageNameFilter && PhMatchWildcards(imageNameFilter, process->ProcessName->Buffer, TRUE)) - ) - { - wprintf(L"Process item at %Ix: %s (%u)\n", (ULONG_PTR)process, process->ProcessName->Buffer, HandleToUlong(process->ProcessId)); - wprintf(L"\tRecord at %Ix\n", (ULONG_PTR)process->Record); - wprintf(L"\tQuery handle %Ix\n", (ULONG_PTR)process->QueryHandle); - wprintf(L"\tFile name at %Ix: %s\n", (ULONG_PTR)process->FileName, PhGetStringOrDefault(process->FileName, L"(null)")); - wprintf(L"\tCommand line at %Ix: %s\n", (ULONG_PTR)process->CommandLine, PhGetStringOrDefault(process->CommandLine, L"(null)")); - wprintf(L"\tFlags: %u\n", process->Flags); - wprintf(L"\n"); - } - } - - PhDereferenceObjects(processes, numberOfProcesses); - } - else if (PhEqualStringZ(command, L"uniquestr", TRUE)) - { -#ifdef DEBUG - PLIST_ENTRY currentEntry; - PPH_HASHTABLE hashtable; - PPH_LIST list; - PSTRING_TABLE_ENTRY stringEntry; - ULONG enumerationKey; - ULONG i; - - hashtable = PhCreateHashtable( - sizeof(STRING_TABLE_ENTRY), - PhpStringHashtableEqualFunction, - PhpStringHashtableHashFunction, - 1024 - ); - - PhAcquireQueuedLockShared(&PhDbgObjectListLock); - - currentEntry = PhDbgObjectListHead.Flink; - - while (currentEntry != &PhDbgObjectListHead) - { - PPH_OBJECT_HEADER objectHeader; - PPH_STRING string; - STRING_TABLE_ENTRY localStringEntry; - BOOLEAN added; - - objectHeader = CONTAINING_RECORD(currentEntry, PH_OBJECT_HEADER, ObjectListEntry); - currentEntry = currentEntry->Flink; - string = PhObjectHeaderToObject(objectHeader); - - // Make sure this is a string. - if (PhGetObjectType(string) != PhStringType) - continue; - - // Make sure the object isn't being destroyed. - if (!PhReferenceObjectSafe(string)) - continue; - - localStringEntry.String = string; - stringEntry = PhAddEntryHashtableEx(hashtable, &localStringEntry, &added); - - if (added) - { - stringEntry->Count = 1; - PhReferenceObject(string); - } - else - { - stringEntry->Count++; - } - - PhDereferenceObjectDeferDelete(string); - } - - PhReleaseQueuedLockShared(&PhDbgObjectListLock); - - // Sort the string entries by count. - - list = PhCreateList(hashtable->Count); - - enumerationKey = 0; - - while (PhEnumHashtable(hashtable, &stringEntry, &enumerationKey)) - { - PhAddItemList(list, stringEntry); - } - - qsort(list->Items, list->Count, sizeof(PSTRING_TABLE_ENTRY), PhpStringEntryCompareByCount); - - // Display... - - for (i = 0; i < 40 && i < list->Count; i++) - { - stringEntry = list->Items[i]; - wprintf(L"%Iu\t%.64s\n", stringEntry->Count, stringEntry->String->Buffer); - } - - wprintf(L"\nTotal unique strings: %u\n", list->Count); - - // Cleanup - - for (i = 0; i < list->Count; i++) - { - stringEntry = list->Items[i]; - PhDereferenceObject(stringEntry->String); - } - - PhDereferenceObject(list); - PhDereferenceObject(hashtable); -#else - wprintf(commandDebugOnly); -#endif - } - else if (PhEqualStringZ(command, L"enableleakdetect", TRUE)) - { - HEAP_DEBUGGING_INFORMATION debuggingInfo; - - memset(&debuggingInfo, 0, sizeof(HEAP_DEBUGGING_INFORMATION)); - debuggingInfo.StackTraceDepth = 32; - debuggingInfo.HeapLeakEnumerationRoutine = PhpLeakEnumerationRoutine; - - if (!NT_SUCCESS(RtlSetHeapInformation(NULL, HeapDebuggingInformation, &debuggingInfo, sizeof(HEAP_DEBUGGING_INFORMATION)))) - { - wprintf(L"Unable to initialize heap debugging. Make sure that you are using Windows 7 or above."); - } - } - else if (PhEqualStringZ(command, L"leakdetect", TRUE)) - { - VOID (NTAPI *rtlDetectHeapLeaks)(VOID); - PWSTR options = wcstok_s(NULL, delims, &context); - - rtlDetectHeapLeaks = PhGetModuleProcAddress(L"ntdll.dll", "RtlDetectHeapLeaks"); - - if (!(NtCurrentPeb()->NtGlobalFlag & FLG_USER_STACK_TRACE_DB)) - { - wprintf(L"Warning: user-mode stack trace database is not enabled. Stack traces will not be displayed.\n"); - } - - ShowAllLeaks = FALSE; - - if (options) - { - if (PhEqualStringZ(options, L"all", TRUE)) - ShowAllLeaks = TRUE; - } - - if (rtlDetectHeapLeaks) - { - InLeakDetection = TRUE; - NumberOfLeaks = 0; - NumberOfLeaksShown = 0; - rtlDetectHeapLeaks(); - InLeakDetection = FALSE; - - wprintf(L"\nNumber of leaks: %lu (%lu displayed)\n", NumberOfLeaks, NumberOfLeaksShown); - } - } - else if (PhEqualStringZ(command, L"mem", TRUE)) - { - PWSTR addressString; - PWSTR bytesString; - PH_STRINGREF addressStringRef; - PH_STRINGREF bytesStringRef; - ULONG64 address64; - ULONG64 numberOfBytes64; - PUCHAR address; - ULONG numberOfBytes; - ULONG blockSize; - UCHAR buffer[16]; - ULONG i; - - addressString = wcstok_s(NULL, delims, &context); - - if (!addressString) - goto PrintMemUsage; - - bytesString = wcstok_s(NULL, delims, &context); - - if (!bytesString) - { - bytesString = L"16"; - } - - PhInitializeStringRef(&addressStringRef, addressString); - PhInitializeStringRef(&bytesStringRef, bytesString); - - if (PhStringToInteger64(&addressStringRef, 16, &address64) && PhStringToInteger64(&bytesStringRef, 10, &numberOfBytes64)) - { - address = (PUCHAR)address64; - numberOfBytes = (ULONG)numberOfBytes64; - - if (numberOfBytes > 256) - { - wprintf(L"Number of bytes must be 256 or smaller.\n"); - goto EndCommand; - } - - blockSize = sizeof(buffer); - - while (numberOfBytes != 0) - { - if (blockSize > numberOfBytes) - blockSize = numberOfBytes; - - __try - { - memcpy(buffer, address, blockSize); - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - wprintf(L"Error reading address near %Ix.\n", (ULONG_PTR)address); - goto EndCommand; - } - - // Print hex dump - for (i = 0; i < blockSize; i++) - wprintf(L"%02x ", buffer[i]); - - // Fill remaining space (for last, possibly partial block) - for (; i < sizeof(buffer); i++) - wprintf(L" "); - - wprintf(L" "); - - // Print ASCII dump - for (i = 0; i < blockSize; i++) - putwchar((ULONG)(buffer[i] - ' ') <= (ULONG)('~' - ' ') ? buffer[i] : '.'); - - wprintf(L"\n"); - - address += blockSize; - numberOfBytes -= blockSize; - } - } - - goto EndCommand; -PrintMemUsage: - wprintf(L"Usage: mem address [numberOfBytes]\n"); - wprintf(L"Example: mem 12345678 16\n"); - } - else - { - wprintf(L"Unrecognized command.\n"); - goto EndCommand; // get rid of the compiler warning about the label being unreferenced - } - -EndCommand: - PhDrainAutoPool(&autoPool); - } - - PhDereferenceObject(DebugConsoleSymbolProvider); - - PhDeleteAutoPool(&autoPool); - - return STATUS_SUCCESS; -} +/* + * Process Hacker - + * debug console + * + * Copyright (C) 2010-2011 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +/* + * This is a simple debugging console which is able to explore phlib's + * systems easily. Commands are provided to debug reference counting + * problems and memory usage, as well as to do general performance testing. + */ + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +typedef struct _STRING_TABLE_ENTRY +{ + PPH_STRING String; + ULONG_PTR Count; +} STRING_TABLE_ENTRY, *PSTRING_TABLE_ENTRY; + +BOOL ConsoleHandlerRoutine( + _In_ DWORD dwCtrlType + ); + +VOID PhpPrintHashtableStatistics( + _In_ PPH_HASHTABLE Hashtable + ); + +NTSTATUS PhpDebugConsoleThreadStart( + _In_ PVOID Parameter + ); + +extern PH_FREE_LIST PhObjectSmallFreeList; + +static HANDLE DebugConsoleThreadHandle; +static PPH_SYMBOL_PROVIDER DebugConsoleSymbolProvider; + +static PPH_HASHTABLE ObjectListSnapshot = NULL; +#ifdef DEBUG +static PPH_LIST NewObjectList = NULL; +static PH_QUEUED_LOCK NewObjectListLock; +#endif + +static BOOLEAN ShowAllLeaks = FALSE; +static BOOLEAN InLeakDetection = FALSE; +static ULONG NumberOfLeaks; +static ULONG NumberOfLeaksShown; + +VOID PhShowDebugConsole( + VOID + ) +{ + if (AllocConsole()) + { + HMENU menu; + + // Disable the close button because it's impossible to handle + // those events. + menu = GetSystemMenu(GetConsoleWindow(), FALSE); + EnableMenuItem(menu, SC_CLOSE, MF_GRAYED | MF_DISABLED); + DeleteMenu(menu, SC_CLOSE, 0); + + // Set a handler so we can catch Ctrl+C and Ctrl+Break. + SetConsoleCtrlHandler(ConsoleHandlerRoutine, TRUE); + + freopen("CONOUT$", "w", stdout); + freopen("CONOUT$", "w", stderr); + freopen("CONIN$", "r", stdin); + DebugConsoleThreadHandle = PhCreateThread(0, PhpDebugConsoleThreadStart, NULL); + } + else + { + HWND consoleWindow; + + consoleWindow = GetConsoleWindow(); + + // Console window already exists, so bring it to the top. + if (IsIconic(consoleWindow)) + ShowWindow(consoleWindow, SW_RESTORE); + else + BringWindowToTop(consoleWindow); + + return; + } +} + +VOID PhCloseDebugConsole( + VOID + ) +{ + freopen("NUL", "w", stdout); + freopen("NUL", "w", stderr); + freopen("NUL", "r", stdin); + + FreeConsole(); +} + +static BOOL ConsoleHandlerRoutine( + _In_ DWORD dwCtrlType + ) +{ + switch (dwCtrlType) + { + case CTRL_C_EVENT: + case CTRL_BREAK_EVENT: + case CTRL_CLOSE_EVENT: + PhCloseDebugConsole(); + return TRUE; + } + + return FALSE; +} + +static BOOLEAN NTAPI PhpLoadCurrentProcessSymbolsCallback( + _In_ PPH_MODULE_INFO Module, + _In_opt_ PVOID Context + ) +{ + PhLoadModuleSymbolProvider((PPH_SYMBOL_PROVIDER)Context, Module->FileName->Buffer, + (ULONG64)Module->BaseAddress, Module->Size); + + return TRUE; +} + +static PWSTR PhpGetSymbolForAddress( + _In_ PVOID Address + ) +{ + return PH_AUTO_T(PH_STRING, PhGetSymbolFromAddress( + DebugConsoleSymbolProvider, (ULONG64)Address, NULL, NULL, NULL, NULL + ))->Buffer; +} + +static VOID PhpPrintObjectInfo( + _In_ PPH_OBJECT_HEADER ObjectHeader, + _In_ LONG RefToSubtract + ) +{ + PVOID object; + PPH_OBJECT_TYPE objectType; + WCHAR c = ' '; + + object = PhObjectHeaderToObject(ObjectHeader); + wprintf(L"%Ix", (ULONG_PTR)object); + objectType = PhGetObjectType(object); + + wprintf(L"\t% 20s", objectType->Name); + + if (ObjectHeader->Flags & PH_OBJECT_FROM_SMALL_FREE_LIST) + c = 'f'; + else if (ObjectHeader->Flags & PH_OBJECT_FROM_TYPE_FREE_LIST) + c = 'F'; + + wprintf(L"\t%4d %c", ObjectHeader->RefCount - RefToSubtract, c); + + if (!objectType) + { + // Dummy + } + else if (objectType == PhObjectTypeObject) + { + wprintf(L"\t%.32s", ((PPH_OBJECT_TYPE)object)->Name); + } + else if (objectType == PhStringType) + { + wprintf(L"\t%.32s", ((PPH_STRING)object)->Buffer); + } + else if (objectType == PhBytesType) + { + wprintf(L"\t%.32S", ((PPH_BYTES)object)->Buffer); + } + else if (objectType == PhListType) + { + wprintf(L"\tCount: %u", ((PPH_LIST)object)->Count); + } + else if (objectType == PhPointerListType) + { + wprintf(L"\tCount: %u", ((PPH_POINTER_LIST)object)->Count); + } + else if (objectType == PhHashtableType) + { + wprintf(L"\tCount: %u", ((PPH_HASHTABLE)object)->Count); + } + else if (objectType == PhProcessItemType) + { + wprintf( + L"\t%.28s (%d)", + ((PPH_PROCESS_ITEM)object)->ProcessName->Buffer, + HandleToLong(((PPH_PROCESS_ITEM)object)->ProcessId) + ); + } + else if (objectType == PhServiceItemType) + { + wprintf(L"\t%s", ((PPH_SERVICE_ITEM)object)->Name->Buffer); + } + else if (objectType == PhThreadItemType) + { + wprintf(L"\tTID: %u", HandleToUlong(((PPH_THREAD_ITEM)object)->ThreadId)); + } + + wprintf(L"\n"); +} + +static VOID PhpDumpObjectInfo( + _In_ PPH_OBJECT_HEADER ObjectHeader + ) +{ + PVOID object; + PPH_OBJECT_TYPE objectType; + + object = PhObjectHeaderToObject(ObjectHeader); + objectType = PhGetObjectType(object); + + __try + { + wprintf(L"Type: %s\n", objectType->Name); + wprintf(L"Reference count: %d\n", ObjectHeader->RefCount); + wprintf(L"Flags: %x\n", ObjectHeader->Flags); + + if (objectType == PhObjectTypeObject) + { + wprintf(L"Name: %s\n", ((PPH_OBJECT_TYPE)object)->Name); + wprintf(L"Number of objects: %u\n", ((PPH_OBJECT_TYPE)object)->NumberOfObjects); + wprintf(L"Flags: %u\n", ((PPH_OBJECT_TYPE)object)->Flags); + wprintf(L"Type index: %u\n", ((PPH_OBJECT_TYPE)object)->TypeIndex); + wprintf(L"Free list count: %u\n", ((PPH_OBJECT_TYPE)object)->FreeList.Count); + } + else if (objectType == PhStringType) + { + wprintf(L"%s\n", ((PPH_STRING)object)->Buffer); + } + else if (objectType == PhBytesType) + { + wprintf(L"%S\n", ((PPH_BYTES)object)->Buffer); + } + else if (objectType == PhHashtableType) + { + PhpPrintHashtableStatistics((PPH_HASHTABLE)object); + } + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + wprintf(L"Error.\n"); + } +} + +static VOID PhpPrintHashtableStatistics( + _In_ PPH_HASHTABLE Hashtable + ) +{ + ULONG i; + ULONG expectedLookupMisses = 0; + + wprintf(L"Count: %u\n", Hashtable->Count); + wprintf(L"Allocated buckets: %u\n", Hashtable->AllocatedBuckets); + wprintf(L"Allocated entries: %u\n", Hashtable->AllocatedEntries); + wprintf(L"Next free entry: %d\n", Hashtable->FreeEntry); + wprintf(L"Next usable entry: %d\n", Hashtable->NextEntry); + + wprintf(L"Equal function: %s\n", PhpGetSymbolForAddress(Hashtable->EqualFunction)); + wprintf(L"Hash function: %s\n", PhpGetSymbolForAddress(Hashtable->HashFunction)); + + wprintf(L"\nBuckets:\n"); + + for (i = 0; i < Hashtable->AllocatedBuckets; i++) + { + ULONG index; + ULONG count = 0; + + // Count the number of entries in this bucket. + + index = Hashtable->Buckets[i]; + + while (index != -1) + { + index = PH_HASHTABLE_GET_ENTRY(Hashtable, index)->Next; + count++; + } + + if (count != 0) + { + expectedLookupMisses += count - 1; + } + + if (count != 0) + { + wprintf(L"%lu: ", i); + + // Print out the entry indicies. + + index = Hashtable->Buckets[i]; + + while (index != -1) + { + wprintf(L"%lu", index); + + index = PH_HASHTABLE_GET_ENTRY(Hashtable, index)->Next; + count--; + + if (count != 0) + wprintf(L", "); + } + + wprintf(L"\n"); + } + else + { + //wprintf(L"%u: (empty)\n"); + } + } + + wprintf(L"\nExpected lookup misses: %lu\n", expectedLookupMisses); +} + +#ifdef DEBUG +static VOID PhpDebugCreateObjectHook( + _In_ PVOID Object, + _In_ SIZE_T Size, + _In_ ULONG Flags, + _In_ PPH_OBJECT_TYPE ObjectType + ) +{ + PhAcquireQueuedLockExclusive(&NewObjectListLock); + + if (NewObjectList) + { + PhReferenceObject(Object); + PhAddItemList(NewObjectList, Object); + } + + PhReleaseQueuedLockExclusive(&NewObjectListLock); +} +#endif + +#ifdef DEBUG +static VOID PhpDeleteNewObjectList( + VOID + ) +{ + if (NewObjectList) + { + ULONG i; + + for (i = 0; i < NewObjectList->Count; i++) + PhDereferenceObject(NewObjectList->Items[i]); + + PhDereferenceObject(NewObjectList); + NewObjectList = NULL; + } +} +#endif + +static BOOLEAN PhpStringHashtableEqualFunction( + _In_ PVOID Entry1, + _In_ PVOID Entry2 + ) +{ + PSTRING_TABLE_ENTRY entry1 = Entry1; + PSTRING_TABLE_ENTRY entry2 = Entry2; + + return PhEqualString(entry1->String, entry2->String, FALSE); +} + +static ULONG PhpStringHashtableHashFunction( + _In_ PVOID Entry + ) +{ + PSTRING_TABLE_ENTRY entry = Entry; + + return PhHashBytes((PUCHAR)entry->String->Buffer, entry->String->Length); +} + +static int __cdecl PhpStringEntryCompareByCount( + _In_ const void *elem1, + _In_ const void *elem2 + ) +{ + PSTRING_TABLE_ENTRY entry1 = *(PSTRING_TABLE_ENTRY *)elem1; + PSTRING_TABLE_ENTRY entry2 = *(PSTRING_TABLE_ENTRY *)elem2; + + return uintptrcmp(entry2->Count, entry1->Count); +} + +static NTSTATUS PhpLeakEnumerationRoutine( + _In_ LONG Reserved, + _In_ PVOID HeapHandle, + _In_ PVOID BaseAddress, + _In_ SIZE_T BlockSize, + _In_ ULONG StackTraceDepth, + _In_ PVOID *StackTrace + ) +{ + ULONG i; + + if (!InLeakDetection) + return 0; + + if (!HeapHandle) // means no more entries + return 0; + + if (ShowAllLeaks || HeapHandle == PhHeapHandle) + { + wprintf(L"Leak at 0x%Ix (%Iu bytes). Stack trace:\n", (ULONG_PTR)BaseAddress, BlockSize); + + for (i = 0; i < StackTraceDepth; i++) + { + PPH_STRING symbol; + + symbol = PhGetSymbolFromAddress(DebugConsoleSymbolProvider, (ULONG64)StackTrace[i], NULL, NULL, NULL, NULL); + + if (symbol) + wprintf(L"\t%s\n", symbol->Buffer); + else + wprintf(L"\t?\n"); + + PhDereferenceObject(symbol); + } + + NumberOfLeaksShown++; + } + + NumberOfLeaks++; + + return 0; +} + +typedef struct _STOPWATCH +{ + LARGE_INTEGER StartCounter; + LARGE_INTEGER EndCounter; + LARGE_INTEGER Frequency; +} STOPWATCH, *PSTOPWATCH; + +static VOID PhInitializeStopwatch( + _Out_ PSTOPWATCH Stopwatch + ) +{ + Stopwatch->StartCounter.QuadPart = 0; + Stopwatch->EndCounter.QuadPart = 0; +} + +static VOID PhStartStopwatch( + _Inout_ PSTOPWATCH Stopwatch + ) +{ + NtQueryPerformanceCounter(&Stopwatch->StartCounter, &Stopwatch->Frequency); +} + +static VOID PhStopStopwatch( + _Inout_ PSTOPWATCH Stopwatch + ) +{ + NtQueryPerformanceCounter(&Stopwatch->EndCounter, NULL); +} + +static ULONG PhGetMillisecondsStopwatch( + _In_ PSTOPWATCH Stopwatch + ) +{ + LARGE_INTEGER countsPerMs; + + countsPerMs = Stopwatch->Frequency; + countsPerMs.QuadPart /= 1000; + + return (ULONG)((Stopwatch->EndCounter.QuadPart - Stopwatch->StartCounter.QuadPart) / + countsPerMs.QuadPart); +} + +typedef VOID (FASTCALL *PPHF_RW_LOCK_FUNCTION)( + _In_ PVOID Parameter + ); + +typedef struct _RW_TEST_CONTEXT +{ + PWSTR Name; + + PPHF_RW_LOCK_FUNCTION AcquireExclusive; + PPHF_RW_LOCK_FUNCTION AcquireShared; + PPHF_RW_LOCK_FUNCTION ReleaseExclusive; + PPHF_RW_LOCK_FUNCTION ReleaseShared; + + PVOID Parameter; +} RW_TEST_CONTEXT, *PRW_TEST_CONTEXT; + +static PH_BARRIER RwStartBarrier; +static LONG RwReadersActive; +static LONG RwWritersActive; + +static NTSTATUS PhpRwLockTestThreadStart( + _In_ PVOID Parameter + ) +{ +#define RW_ITERS 10000 +#define RW_READ_ITERS 100 +#define RW_WRITE_ITERS 10 +#define RW_READ_SPIN_ITERS 60 +#define RW_WRITE_SPIN_ITERS 200 + + RW_TEST_CONTEXT context = *(PRW_TEST_CONTEXT)Parameter; + ULONG i; + ULONG j; + ULONG k; + ULONG m; + + PhWaitForBarrier(&RwStartBarrier, FALSE); + + for (i = 0; i < RW_ITERS; i++) + { + for (j = 0; j < RW_READ_ITERS; j++) + { + // Read zone + + context.AcquireShared(context.Parameter); + _InterlockedIncrement(&RwReadersActive); + + for (m = 0; m < RW_READ_SPIN_ITERS; m++) + YieldProcessor(); + + if (RwWritersActive != 0) + { + wprintf(L"[fail]: writers active in read zone!\n"); + NtWaitForSingleObject(NtCurrentProcess(), FALSE, NULL); + } + + _InterlockedDecrement(&RwReadersActive); + context.ReleaseShared(context.Parameter); + + // Spin for a while + + for (m = 0; m < 10; m++) + YieldProcessor(); + + if (j == RW_READ_ITERS / 2) + { + // Write zone + + for (k = 0; k < RW_WRITE_ITERS; k++) + { + context.AcquireExclusive(context.Parameter); + _InterlockedIncrement(&RwWritersActive); + + for (m = 0; m < RW_WRITE_SPIN_ITERS; m++) + YieldProcessor(); + + if (RwReadersActive != 0) + { + wprintf(L"[fail]: readers active in write zone!\n"); + NtWaitForSingleObject(NtCurrentProcess(), FALSE, NULL); + } + + _InterlockedDecrement(&RwWritersActive); + context.ReleaseExclusive(context.Parameter); + } + } + } + } + + return STATUS_SUCCESS; +} + +static VOID PhpTestRwLock( + _In_ PRW_TEST_CONTEXT Context + ) +{ +#define RW_PROCESSORS 4 + + STOPWATCH stopwatch; + ULONG i; + HANDLE threadHandles[RW_PROCESSORS]; + + // Dummy + + Context->AcquireExclusive(Context->Parameter); + Context->ReleaseExclusive(Context->Parameter); + Context->AcquireShared(Context->Parameter); + Context->ReleaseShared(Context->Parameter); + + // Null test + + PhStartStopwatch(&stopwatch); + + for (i = 0; i < 2000000; i++) + { + Context->AcquireExclusive(Context->Parameter); + Context->ReleaseExclusive(Context->Parameter); + Context->AcquireShared(Context->Parameter); + Context->ReleaseShared(Context->Parameter); + } + + PhStopStopwatch(&stopwatch); + + wprintf(L"[null] %s: %ums\n", Context->Name, PhGetMillisecondsStopwatch(&stopwatch)); + + // Stress test + + PhInitializeBarrier(&RwStartBarrier, RW_PROCESSORS + 1); + RwReadersActive = 0; + RwWritersActive = 0; + + for (i = 0; i < RW_PROCESSORS; i++) + { + threadHandles[i] = PhCreateThread(0, PhpRwLockTestThreadStart, Context); + } + + PhWaitForBarrier(&RwStartBarrier, FALSE); + PhStartStopwatch(&stopwatch); + NtWaitForMultipleObjects(RW_PROCESSORS, threadHandles, WaitAll, FALSE, NULL); + PhStopStopwatch(&stopwatch); + + for (i = 0; i < RW_PROCESSORS; i++) + NtClose(threadHandles[i]); + + wprintf(L"[strs] %s: %ums\n", Context->Name, PhGetMillisecondsStopwatch(&stopwatch)); +} + +VOID FASTCALL PhfAcquireCriticalSection( + _In_ PRTL_CRITICAL_SECTION CriticalSection + ) +{ + RtlEnterCriticalSection(CriticalSection); +} + +VOID FASTCALL PhfReleaseCriticalSection( + _In_ PRTL_CRITICAL_SECTION CriticalSection + ) +{ + RtlLeaveCriticalSection(CriticalSection); +} + +VOID FASTCALL PhfReleaseQueuedLockExclusiveUsingInline( + _In_ PPH_QUEUED_LOCK QueuedLock + ) +{ + PhReleaseQueuedLockExclusive(QueuedLock); +} + +NTSTATUS PhpDebugConsoleThreadStart( + _In_ PVOID Parameter + ) +{ + PH_AUTO_POOL autoPool; + BOOLEAN exit = FALSE; + + PhInitializeAutoPool(&autoPool); + + DebugConsoleSymbolProvider = PhCreateSymbolProvider(NtCurrentProcessId()); + + { + WCHAR buffer[512]; + UNICODE_STRING name = RTL_CONSTANT_STRING(L"_NT_SYMBOL_PATH"); + UNICODE_STRING var; + PPH_STRING newSearchPath; + + var.Buffer = buffer; + var.MaximumLength = sizeof(buffer); + + if (!NT_SUCCESS(RtlQueryEnvironmentVariable_U(NULL, &name, &var))) + buffer[0] = 0; + + newSearchPath = PhFormatString(L"%s;%s", buffer, PhApplicationDirectory->Buffer); + PhSetSearchPathSymbolProvider(DebugConsoleSymbolProvider, newSearchPath->Buffer); + PhDereferenceObject(newSearchPath); + } + + PhEnumGenericModules(NtCurrentProcessId(), NtCurrentProcess(), + 0, PhpLoadCurrentProcessSymbolsCallback, DebugConsoleSymbolProvider); + +#ifdef DEBUG + PhInitializeQueuedLock(&NewObjectListLock); + PhDbgCreateObjectHook = PhpDebugCreateObjectHook; +#endif + + wprintf(L"Press Ctrl+C or type \"exit\" to close the debug console. Type \"help\" for a list of commands.\n"); + + while (!exit) + { + static PWSTR delims = L" \t"; + static PWSTR commandDebugOnly = L"This command is not available on non-debug builds.\n"; + + WCHAR line[201]; + ULONG inputLength; + PWSTR context; + PWSTR command; + + wprintf(L"dbg>"); + + if (!fgetws(line, sizeof(line) / 2 - 1, stdin)) + break; + + // Remove the terminating new line character. + + inputLength = (ULONG)PhCountStringZ(line); + + if (inputLength != 0) + line[inputLength - 1] = 0; + + context = NULL; + command = wcstok_s(line, delims, &context); + + if (!command) + { + continue; + } + else if (PhEqualStringZ(command, L"help", TRUE)) + { + wprintf( + L"Commands:\n" + L"exit\n" + L"testperf\n" + L"testlocks\n" + L"stats\n" + L"objects [type-name-filter]\n" + L"objtrace object-address\n" + L"objmksnap\n" + L"objcmpsnap\n" + L"objmknew\n" + L"objdelnew\n" + L"objviewnew\n" + L"dumpobj\n" + L"dumpautopool\n" + L"threads\n" + L"provthreads\n" + L"workqueues\n" + L"procrecords\n" + L"procitem\n" + L"uniquestr\n" + L"enableleakdetect\n" + L"leakdetect\n" + L"mem\n" + ); + } + else if (PhEqualStringZ(command, L"exit", TRUE)) + { + PhCloseDebugConsole(); + exit = TRUE; + } + else if (PhEqualStringZ(command, L"testperf", TRUE)) + { + STOPWATCH stopwatch; + ULONG i; + PPH_STRING testString; + RTL_CRITICAL_SECTION testCriticalSection; + PH_FAST_LOCK testFastLock; + PH_QUEUED_LOCK testQueuedLock; + + // Control (string reference counting) + + testString = PhCreateString(L""); + PhReferenceObject(testString); + PhDereferenceObject(testString); + PhStartStopwatch(&stopwatch); + + for (i = 0; i < 10000000; i++) + { + PhReferenceObject(testString); + PhDereferenceObject(testString); + } + + PhStopStopwatch(&stopwatch); + PhDereferenceObject(testString); + + wprintf(L"Referencing: %ums\n", PhGetMillisecondsStopwatch(&stopwatch)); + + // Critical section + + RtlInitializeCriticalSection(&testCriticalSection); + RtlEnterCriticalSection(&testCriticalSection); + RtlLeaveCriticalSection(&testCriticalSection); + PhStartStopwatch(&stopwatch); + + for (i = 0; i < 10000000; i++) + { + RtlEnterCriticalSection(&testCriticalSection); + RtlLeaveCriticalSection(&testCriticalSection); + } + + PhStopStopwatch(&stopwatch); + RtlDeleteCriticalSection(&testCriticalSection); + + wprintf(L"Critical section: %ums\n", PhGetMillisecondsStopwatch(&stopwatch)); + + // Fast lock + + PhInitializeFastLock(&testFastLock); + PhAcquireFastLockExclusive(&testFastLock); + PhReleaseFastLockExclusive(&testFastLock); + PhStartStopwatch(&stopwatch); + + for (i = 0; i < 10000000; i++) + { + PhAcquireFastLockExclusive(&testFastLock); + PhReleaseFastLockExclusive(&testFastLock); + } + + PhStopStopwatch(&stopwatch); + PhDeleteFastLock(&testFastLock); + + wprintf(L"Fast lock: %ums\n", PhGetMillisecondsStopwatch(&stopwatch)); + + // Queued lock + + PhInitializeQueuedLock(&testQueuedLock); + PhAcquireQueuedLockExclusive(&testQueuedLock); + PhReleaseQueuedLockExclusive(&testQueuedLock); + PhStartStopwatch(&stopwatch); + + for (i = 0; i < 10000000; i++) + { + PhAcquireQueuedLockExclusive(&testQueuedLock); + PhReleaseQueuedLockExclusive(&testQueuedLock); + } + + PhStopStopwatch(&stopwatch); + + wprintf(L"Queued lock: %ums\n", PhGetMillisecondsStopwatch(&stopwatch)); + } + else if (PhEqualStringZ(command, L"testlocks", TRUE)) + { + RW_TEST_CONTEXT testContext; + PH_FAST_LOCK fastLock; + PH_QUEUED_LOCK queuedLock; + RTL_CRITICAL_SECTION criticalSection; + + testContext.Name = L"FastLock"; + testContext.AcquireExclusive = PhfAcquireFastLockExclusive; + testContext.AcquireShared = PhfAcquireFastLockShared; + testContext.ReleaseExclusive = PhfReleaseFastLockExclusive; + testContext.ReleaseShared = PhfReleaseFastLockShared; + testContext.Parameter = &fastLock; + PhInitializeFastLock(&fastLock); + PhpTestRwLock(&testContext); + PhDeleteFastLock(&fastLock); + + testContext.Name = L"QueuedLock"; + testContext.AcquireExclusive = PhfAcquireQueuedLockExclusive; + testContext.AcquireShared = PhfAcquireQueuedLockShared; + testContext.ReleaseExclusive = PhfReleaseQueuedLockExclusive; + testContext.ReleaseShared = PhfReleaseQueuedLockShared; + testContext.Parameter = &queuedLock; + PhInitializeQueuedLock(&queuedLock); + PhpTestRwLock(&testContext); + + testContext.Name = L"CriticalSection"; + testContext.AcquireExclusive = PhfAcquireCriticalSection; + testContext.AcquireShared = PhfAcquireCriticalSection; + testContext.ReleaseExclusive = PhfReleaseCriticalSection; + testContext.ReleaseShared = PhfReleaseCriticalSection; + testContext.Parameter = &criticalSection; + RtlInitializeCriticalSection(&criticalSection); + PhpTestRwLock(&testContext); + RtlDeleteCriticalSection(&criticalSection); + + testContext.Name = L"QueuedLockMutex"; + testContext.AcquireExclusive = PhfAcquireQueuedLockExclusive; + testContext.AcquireShared = PhfAcquireQueuedLockExclusive; + testContext.ReleaseExclusive = PhfReleaseQueuedLockExclusive; + testContext.ReleaseShared = PhfReleaseQueuedLockExclusive; + testContext.Parameter = &queuedLock; + PhInitializeQueuedLock(&queuedLock); + PhpTestRwLock(&testContext); + } + else if (PhEqualStringZ(command, L"stats", TRUE)) + { +#ifdef DEBUG + wprintf(L"Object small free list count: %u\n", PhObjectSmallFreeList.Count); + wprintf(L"Statistics:\n"); +#define PRINT_STATISTIC(Name) wprintf(L#Name L": %u\n", PhLibStatisticsBlock.Name); + + PRINT_STATISTIC(BaseThreadsCreated); + PRINT_STATISTIC(BaseThreadsCreateFailed); + PRINT_STATISTIC(BaseStringBuildersCreated); + PRINT_STATISTIC(BaseStringBuildersResized); + PRINT_STATISTIC(RefObjectsCreated); + PRINT_STATISTIC(RefObjectsDestroyed); + PRINT_STATISTIC(RefObjectsAllocated); + PRINT_STATISTIC(RefObjectsFreed); + PRINT_STATISTIC(RefObjectsAllocatedFromSmallFreeList); + PRINT_STATISTIC(RefObjectsFreedToSmallFreeList); + PRINT_STATISTIC(RefObjectsAllocatedFromTypeFreeList); + PRINT_STATISTIC(RefObjectsFreedToTypeFreeList); + PRINT_STATISTIC(RefObjectsDeleteDeferred); + PRINT_STATISTIC(RefAutoPoolsCreated); + PRINT_STATISTIC(RefAutoPoolsDestroyed); + PRINT_STATISTIC(RefAutoPoolsDynamicAllocated); + PRINT_STATISTIC(RefAutoPoolsDynamicResized); + PRINT_STATISTIC(QlBlockSpins); + PRINT_STATISTIC(QlBlockWaits); + PRINT_STATISTIC(QlAcquireExclusiveBlocks); + PRINT_STATISTIC(QlAcquireSharedBlocks); + PRINT_STATISTIC(WqWorkQueueThreadsCreated); + PRINT_STATISTIC(WqWorkQueueThreadsCreateFailed); + PRINT_STATISTIC(WqWorkItemsQueued); + +#else + wprintf(commandDebugOnly); +#endif + } + else if (PhEqualStringZ(command, L"objects", TRUE)) + { +#ifdef DEBUG + PWSTR typeFilter = wcstok_s(NULL, delims, &context); + PLIST_ENTRY currentEntry; + ULONG totalNumberOfObjects = 0; + //SIZE_T totalNumberOfBytes = 0; + + if (typeFilter) + _wcslwr(typeFilter); + + PhAcquireQueuedLockShared(&PhDbgObjectListLock); + + currentEntry = PhDbgObjectListHead.Flink; + + while (currentEntry != &PhDbgObjectListHead) + { + PPH_OBJECT_HEADER objectHeader; + WCHAR typeName[32]; + + objectHeader = CONTAINING_RECORD(currentEntry, PH_OBJECT_HEADER, ObjectListEntry); + + // Make sure the object isn't being destroyed. + if (!PhReferenceObjectSafe(PhObjectHeaderToObject(objectHeader))) + { + currentEntry = currentEntry->Flink; + continue; + } + + totalNumberOfObjects++; + //totalNumberOfBytes += objectHeader->Size; + + if (typeFilter) + { + wcscpy_s(typeName, sizeof(typeName) / 2, PhGetObjectType(PhObjectHeaderToObject(objectHeader))->Name); + _wcslwr(typeName); + } + + if ( + !typeFilter || + (typeFilter && wcsstr(typeName, typeFilter)) + ) + { + PhpPrintObjectInfo(objectHeader, 1); + } + + currentEntry = currentEntry->Flink; + PhDereferenceObjectDeferDelete(PhObjectHeaderToObject(objectHeader)); + } + + PhReleaseQueuedLockShared(&PhDbgObjectListLock); + + wprintf(L"\n"); + wprintf(L"Total number: %lu\n", totalNumberOfObjects); + /*wprintf(L"Total size (excl. header): %s\n", + ((PPH_STRING)PH_AUTO(PhFormatSize(totalNumberOfBytes, 1)))->Buffer);*/ + wprintf(L"Total overhead (header): %s\n", + ((PPH_STRING)PH_AUTO( + PhFormatSize(PhAddObjectHeaderSize(0) * totalNumberOfObjects, 1) + ))->Buffer); +#else + wprintf(commandDebugOnly); +#endif + } + else if (PhEqualStringZ(command, L"objtrace", TRUE)) + { +#ifdef DEBUG + PWSTR objectAddress = wcstok_s(NULL, delims, &context); + PH_STRINGREF objectAddressString; + ULONG64 address; + + if (!objectAddress) + { + wprintf(L"Missing object address.\n"); + goto EndCommand; + } + + PhInitializeStringRef(&objectAddressString, objectAddress); + + if (PhStringToInteger64(&objectAddressString, 16, &address)) + { + PPH_OBJECT_HEADER objectHeader = (PPH_OBJECT_HEADER)PhObjectToObjectHeader((PVOID)address); + PVOID stackBackTrace[16]; + ULONG i; + + // The address may not be valid. + __try + { + memcpy(stackBackTrace, objectHeader->StackBackTrace, 16 * sizeof(PVOID)); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + PPH_STRING message; + + message = PH_AUTO(PhGetNtMessage(GetExceptionCode())); + wprintf(L"Error: %s\n", PhGetString(message)); + + goto EndCommand; + } + + for (i = 0; i < 16; i++) + { + if (!stackBackTrace[i]) + break; + + wprintf(L"%s\n", PhpGetSymbolForAddress(stackBackTrace[i])); + } + } + else + { + wprintf(L"Invalid object address.\n"); + } +#else + wprintf(commandDebugOnly); +#endif + } + else if (PhEqualStringZ(command, L"objmksnap", TRUE)) + { +#ifdef DEBUG + PLIST_ENTRY currentEntry; + + if (ObjectListSnapshot) + { + PhDereferenceObject(ObjectListSnapshot); + ObjectListSnapshot = NULL; + } + + ObjectListSnapshot = PhCreateSimpleHashtable(100); + + PhAcquireQueuedLockShared(&PhDbgObjectListLock); + + currentEntry = PhDbgObjectListHead.Flink; + + while (currentEntry != &PhDbgObjectListHead) + { + PPH_OBJECT_HEADER objectHeader; + + objectHeader = CONTAINING_RECORD(currentEntry, PH_OBJECT_HEADER, ObjectListEntry); + currentEntry = currentEntry->Flink; + + if (PhObjectHeaderToObject(objectHeader) != ObjectListSnapshot) + PhAddItemSimpleHashtable(ObjectListSnapshot, objectHeader, NULL); + } + + PhReleaseQueuedLockShared(&PhDbgObjectListLock); +#else + wprintf(commandDebugOnly); +#endif + } + else if (PhEqualStringZ(command, L"objcmpsnap", TRUE)) + { +#ifdef DEBUG + PLIST_ENTRY currentEntry; + PPH_LIST newObjects; + ULONG i; + + if (!ObjectListSnapshot) + { + wprintf(L"No snapshot.\n"); + goto EndCommand; + } + + newObjects = PhCreateList(10); + + PhAcquireQueuedLockShared(&PhDbgObjectListLock); + + currentEntry = PhDbgObjectListHead.Flink; + + while (currentEntry != &PhDbgObjectListHead) + { + PPH_OBJECT_HEADER objectHeader; + + objectHeader = CONTAINING_RECORD(currentEntry, PH_OBJECT_HEADER, ObjectListEntry); + currentEntry = currentEntry->Flink; + + if ( + PhObjectHeaderToObject(objectHeader) != ObjectListSnapshot && + PhObjectHeaderToObject(objectHeader) != newObjects + ) + { + if (!PhFindItemSimpleHashtable(ObjectListSnapshot, objectHeader)) + { + if (PhReferenceObjectSafe(PhObjectHeaderToObject(objectHeader))) + PhAddItemList(newObjects, objectHeader); + } + } + } + + PhReleaseQueuedLockShared(&PhDbgObjectListLock); + + for (i = 0; i < newObjects->Count; i++) + { + PPH_OBJECT_HEADER objectHeader = newObjects->Items[i]; + + PhpPrintObjectInfo(objectHeader, 1); + + PhDereferenceObject(PhObjectHeaderToObject(objectHeader)); + } + + PhDereferenceObject(newObjects); +#else + wprintf(commandDebugOnly); +#endif + } + else if (PhEqualStringZ(command, L"objmknew", TRUE)) + { +#ifdef DEBUG + PhAcquireQueuedLockExclusive(&NewObjectListLock); + PhpDeleteNewObjectList(); + PhReleaseQueuedLockExclusive(&NewObjectListLock); + + // Creation needs to be done outside of the lock, + // otherwise a deadlock will occur. + NewObjectList = PhCreateList(100); +#else + wprintf(commandDebugOnly); +#endif + } + else if (PhEqualStringZ(command, L"objdelnew", TRUE)) + { +#ifdef DEBUG + PhAcquireQueuedLockExclusive(&NewObjectListLock); + PhpDeleteNewObjectList(); + PhReleaseQueuedLockExclusive(&NewObjectListLock); +#else + wprintf(commandDebugOnly); +#endif + } + else if (PhEqualStringZ(command, L"objviewnew", TRUE)) + { +#ifdef DEBUG + ULONG i; + + PhAcquireQueuedLockExclusive(&NewObjectListLock); + + if (!NewObjectList) + { + wprintf(L"Object creation hooking not active.\n"); + PhReleaseQueuedLockExclusive(&NewObjectListLock); + goto EndCommand; + } + + for (i = 0; i < NewObjectList->Count; i++) + { + PhpPrintObjectInfo(PhObjectToObjectHeader(NewObjectList->Items[i]), 1); + } + + PhReleaseQueuedLockExclusive(&NewObjectListLock); +#else + wprintf(commandDebugOnly); +#endif + } + else if (PhEqualStringZ(command, L"dumpobj", TRUE)) + { + PWSTR addressString = wcstok_s(NULL, delims, &context); + PH_STRINGREF addressStringRef; + ULONG64 address; + + if (!addressString) + goto EndCommand; + + PhInitializeStringRef(&addressStringRef, addressString); + + if (PhStringToInteger64(&addressStringRef, 16, &address)) + { + PhpDumpObjectInfo((PPH_OBJECT_HEADER)PhObjectToObjectHeader((PVOID)address)); + } + } + else if (PhEqualStringZ(command, L"dumpautopool", TRUE)) + { + PWSTR addressString = wcstok_s(NULL, delims, &context); + PH_STRINGREF addressStringRef; + ULONG64 address; + + if (!addressString) + goto EndCommand; + + PhInitializeStringRef(&addressStringRef, addressString); + + if (PhStringToInteger64(&addressStringRef, 16, &address)) + { + PPH_AUTO_POOL userAutoPool = (PPH_AUTO_POOL)address; + ULONG i; + + __try + { + wprintf(L"Static count: %u\n", userAutoPool->StaticCount); + wprintf(L"Dynamic count: %u\n", userAutoPool->DynamicCount); + wprintf(L"Dynamic allocated: %u\n", userAutoPool->DynamicAllocated); + + wprintf(L"Static objects:\n"); + + for (i = 0; i < userAutoPool->StaticCount; i++) + PhpPrintObjectInfo(PhObjectToObjectHeader(userAutoPool->StaticObjects[i]), 0); + + wprintf(L"Dynamic objects:\n"); + + for (i = 0; i < userAutoPool->DynamicCount; i++) + PhpPrintObjectInfo(PhObjectToObjectHeader(userAutoPool->DynamicObjects[i]), 0); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + goto EndCommand; + } + } + } + else if (PhEqualStringZ(command, L"threads", TRUE)) + { +#ifdef DEBUG + PLIST_ENTRY currentEntry; + + PhAcquireQueuedLockShared(&PhDbgThreadListLock); + + currentEntry = PhDbgThreadListHead.Flink; + + while (currentEntry != &PhDbgThreadListHead) + { + PPHP_BASE_THREAD_DBG dbg; + + dbg = CONTAINING_RECORD(currentEntry, PHP_BASE_THREAD_DBG, ListEntry); + + wprintf(L"Thread %u\n", HandleToUlong(dbg->ClientId.UniqueThread)); + wprintf(L"\tStart Address: %s\n", PhpGetSymbolForAddress(dbg->StartAddress)); + wprintf(L"\tParameter: %Ix\n", (ULONG_PTR)dbg->Parameter); + wprintf(L"\tCurrent auto-pool: %Ix\n", (ULONG_PTR)dbg->CurrentAutoPool); + + currentEntry = currentEntry->Flink; + } + + PhReleaseQueuedLockShared(&PhDbgThreadListLock); +#else + wprintf(commandDebugOnly); +#endif + } + else if (PhEqualStringZ(command, L"provthreads", TRUE)) + { +#ifdef DEBUG + ULONG i; + + if (PhDbgProviderList) + { + PhAcquireQueuedLockShared(&PhDbgProviderListLock); + + for (i = 0; i < PhDbgProviderList->Count; i++) + { + PPH_PROVIDER_THREAD providerThread = PhDbgProviderList->Items[i]; + THREAD_BASIC_INFORMATION basicInfo; + PLIST_ENTRY providerEntry; + + if (providerThread->ThreadHandle) + { + PhGetThreadBasicInformation(providerThread->ThreadHandle, &basicInfo); + wprintf(L"Thread %u\n", HandleToUlong(basicInfo.ClientId.UniqueThread)); + } + else + { + wprintf(L"Thread not running\n"); + } + + PhAcquireQueuedLockExclusive(&providerThread->Lock); + + providerEntry = providerThread->ListHead.Flink; + + while (providerEntry != &providerThread->ListHead) + { + PPH_PROVIDER_REGISTRATION registration; + + registration = CONTAINING_RECORD(providerEntry, PH_PROVIDER_REGISTRATION, ListEntry); + + wprintf(L"\tProvider registration at %Ix\n", (ULONG_PTR)registration); + wprintf(L"\t\tEnabled: %s\n", registration->Enabled ? L"Yes" : L"No"); + wprintf(L"\t\tFunction: %s\n", PhpGetSymbolForAddress(registration->Function)); + + if (registration->Object) + { + wprintf(L"\t\tObject:\n"); + PhpPrintObjectInfo(PhObjectToObjectHeader(registration->Object), 0); + } + + providerEntry = providerEntry->Flink; + } + + PhReleaseQueuedLockExclusive(&providerThread->Lock); + + wprintf(L"\n"); + } + + PhReleaseQueuedLockShared(&PhDbgProviderListLock); + } +#else + wprintf(commandDebugOnly); +#endif + } + else if (PhEqualStringZ(command, L"workqueues", TRUE)) + { +#ifdef DEBUG + ULONG i; + + if (PhDbgWorkQueueList) + { + PhAcquireQueuedLockShared(&PhDbgWorkQueueListLock); + + for (i = 0; i < PhDbgWorkQueueList->Count; i++) + { + PPH_WORK_QUEUE workQueue = PhDbgWorkQueueList->Items[i]; + PLIST_ENTRY workQueueItemEntry; + + wprintf(L"Work queue at %s\n", PhpGetSymbolForAddress(workQueue)); + wprintf(L"Maximum threads: %u\n", workQueue->MaximumThreads); + wprintf(L"Minimum threads: %u\n", workQueue->MinimumThreads); + wprintf(L"No work timeout: %d\n", workQueue->NoWorkTimeout); + + wprintf(L"Current threads: %u\n", workQueue->CurrentThreads); + wprintf(L"Busy count: %u\n", workQueue->BusyCount); + + PhAcquireQueuedLockExclusive(&workQueue->QueueLock); + + // List the items backwards. + workQueueItemEntry = workQueue->QueueListHead.Blink; + + while (workQueueItemEntry != &workQueue->QueueListHead) + { + PPH_WORK_QUEUE_ITEM workQueueItem; + + workQueueItem = CONTAINING_RECORD(workQueueItemEntry, PH_WORK_QUEUE_ITEM, ListEntry); + + wprintf(L"\tWork queue item at %Ix\n", (ULONG_PTR)workQueueItem); + wprintf(L"\t\tFunction: %s\n", PhpGetSymbolForAddress(workQueueItem->Function)); + wprintf(L"\t\tContext: %Ix\n", (ULONG_PTR)workQueueItem->Context); + + workQueueItemEntry = workQueueItemEntry->Blink; + } + + PhReleaseQueuedLockExclusive(&workQueue->QueueLock); + + wprintf(L"\n"); + } + + PhReleaseQueuedLockShared(&PhDbgWorkQueueListLock); + } +#else + wprintf(commandDebugOnly); +#endif + } + else if (PhEqualStringZ(command, L"procrecords", TRUE)) + { + PPH_PROCESS_RECORD record; + ULONG i; + SYSTEMTIME systemTime; + PPH_PROCESS_RECORD startRecord; + + PhAcquireQueuedLockShared(&PhProcessRecordListLock); + + for (i = 0; i < PhProcessRecordList->Count; i++) + { + record = (PPH_PROCESS_RECORD)PhProcessRecordList->Items[i]; + + PhLargeIntegerToLocalSystemTime(&systemTime, &record->CreateTime); + wprintf(L"Records for %s %s:\n", + ((PPH_STRING)PH_AUTO(PhFormatDate(&systemTime, NULL)))->Buffer, + ((PPH_STRING)PH_AUTO(PhFormatTime(&systemTime, NULL)))->Buffer + ); + + startRecord = record; + + do + { + wprintf(L"\tRecord at %Ix: %s (%u) (refs: %d)\n", (ULONG_PTR)record, record->ProcessName->Buffer, HandleToUlong(record->ProcessId), record->RefCount); + + if (record->FileName) + wprintf(L"\t\t%s\n", record->FileName->Buffer); + + record = CONTAINING_RECORD(record->ListEntry.Flink, PH_PROCESS_RECORD, ListEntry); + } while (record != startRecord); + } + + PhReleaseQueuedLockShared(&PhProcessRecordListLock); + } + else if (PhEqualStringZ(command, L"procitem", TRUE)) + { + PWSTR filterString; + PH_STRINGREF filterRef; + ULONG64 filter64; + LONG_PTR processIdFilter = -9; // can't use -2, -1 or 0 because they're all used for process IDs + ULONG_PTR processAddressFilter = 0; + PWSTR imageNameFilter = NULL; + BOOLEAN showAll = FALSE; + PPH_PROCESS_ITEM *processes; + ULONG numberOfProcesses; + ULONG i; + + filterString = wcstok_s(NULL, delims, &context); + + if (filterString) + { + PhInitializeStringRef(&filterRef, filterString); + + if (PhStringToInteger64(&filterRef, 10, &filter64)) + processIdFilter = (LONG_PTR)filter64; + if (PhStringToInteger64(&filterRef, 16, &filter64)) + processAddressFilter = (ULONG_PTR)filter64; + + imageNameFilter = filterString; + } + else + { + showAll = TRUE; + } + + PhEnumProcessItems(&processes, &numberOfProcesses); + + for (i = 0; i < numberOfProcesses; i++) + { + PPH_PROCESS_ITEM process = processes[i]; + + if ( + showAll || + (processIdFilter != -9 && (LONG_PTR)process->ProcessId == processIdFilter) || + (processAddressFilter != 0 && (ULONG_PTR)process == processAddressFilter) || + (imageNameFilter && PhMatchWildcards(imageNameFilter, process->ProcessName->Buffer, TRUE)) + ) + { + wprintf(L"Process item at %Ix: %s (%u)\n", (ULONG_PTR)process, process->ProcessName->Buffer, HandleToUlong(process->ProcessId)); + wprintf(L"\tRecord at %Ix\n", (ULONG_PTR)process->Record); + wprintf(L"\tQuery handle %Ix\n", (ULONG_PTR)process->QueryHandle); + wprintf(L"\tFile name at %Ix: %s\n", (ULONG_PTR)process->FileName, PhGetStringOrDefault(process->FileName, L"(null)")); + wprintf(L"\tCommand line at %Ix: %s\n", (ULONG_PTR)process->CommandLine, PhGetStringOrDefault(process->CommandLine, L"(null)")); + wprintf(L"\tFlags: %u\n", process->Flags); + wprintf(L"\n"); + } + } + + PhDereferenceObjects(processes, numberOfProcesses); + } + else if (PhEqualStringZ(command, L"uniquestr", TRUE)) + { +#ifdef DEBUG + PLIST_ENTRY currentEntry; + PPH_HASHTABLE hashtable; + PPH_LIST list; + PSTRING_TABLE_ENTRY stringEntry; + ULONG enumerationKey; + ULONG i; + + hashtable = PhCreateHashtable( + sizeof(STRING_TABLE_ENTRY), + PhpStringHashtableEqualFunction, + PhpStringHashtableHashFunction, + 1024 + ); + + PhAcquireQueuedLockShared(&PhDbgObjectListLock); + + currentEntry = PhDbgObjectListHead.Flink; + + while (currentEntry != &PhDbgObjectListHead) + { + PPH_OBJECT_HEADER objectHeader; + PPH_STRING string; + STRING_TABLE_ENTRY localStringEntry; + BOOLEAN added; + + objectHeader = CONTAINING_RECORD(currentEntry, PH_OBJECT_HEADER, ObjectListEntry); + currentEntry = currentEntry->Flink; + string = PhObjectHeaderToObject(objectHeader); + + // Make sure this is a string. + if (PhGetObjectType(string) != PhStringType) + continue; + + // Make sure the object isn't being destroyed. + if (!PhReferenceObjectSafe(string)) + continue; + + localStringEntry.String = string; + stringEntry = PhAddEntryHashtableEx(hashtable, &localStringEntry, &added); + + if (added) + { + stringEntry->Count = 1; + PhReferenceObject(string); + } + else + { + stringEntry->Count++; + } + + PhDereferenceObjectDeferDelete(string); + } + + PhReleaseQueuedLockShared(&PhDbgObjectListLock); + + // Sort the string entries by count. + + list = PhCreateList(hashtable->Count); + + enumerationKey = 0; + + while (PhEnumHashtable(hashtable, &stringEntry, &enumerationKey)) + { + PhAddItemList(list, stringEntry); + } + + qsort(list->Items, list->Count, sizeof(PSTRING_TABLE_ENTRY), PhpStringEntryCompareByCount); + + // Display... + + for (i = 0; i < 40 && i < list->Count; i++) + { + stringEntry = list->Items[i]; + wprintf(L"%Iu\t%.64s\n", stringEntry->Count, stringEntry->String->Buffer); + } + + wprintf(L"\nTotal unique strings: %u\n", list->Count); + + // Cleanup + + for (i = 0; i < list->Count; i++) + { + stringEntry = list->Items[i]; + PhDereferenceObject(stringEntry->String); + } + + PhDereferenceObject(list); + PhDereferenceObject(hashtable); +#else + wprintf(commandDebugOnly); +#endif + } + else if (PhEqualStringZ(command, L"enableleakdetect", TRUE)) + { + HEAP_DEBUGGING_INFORMATION debuggingInfo; + + memset(&debuggingInfo, 0, sizeof(HEAP_DEBUGGING_INFORMATION)); + debuggingInfo.StackTraceDepth = 32; + debuggingInfo.HeapLeakEnumerationRoutine = PhpLeakEnumerationRoutine; + + if (!NT_SUCCESS(RtlSetHeapInformation(NULL, HeapDebuggingInformation, &debuggingInfo, sizeof(HEAP_DEBUGGING_INFORMATION)))) + { + wprintf(L"Unable to initialize heap debugging. Make sure that you are using Windows 7 or above."); + } + } + else if (PhEqualStringZ(command, L"leakdetect", TRUE)) + { + VOID (NTAPI *rtlDetectHeapLeaks)(VOID); + PWSTR options = wcstok_s(NULL, delims, &context); + + rtlDetectHeapLeaks = PhGetModuleProcAddress(L"ntdll.dll", "RtlDetectHeapLeaks"); + + if (!(NtCurrentPeb()->NtGlobalFlag & FLG_USER_STACK_TRACE_DB)) + { + wprintf(L"Warning: user-mode stack trace database is not enabled. Stack traces will not be displayed.\n"); + } + + ShowAllLeaks = FALSE; + + if (options) + { + if (PhEqualStringZ(options, L"all", TRUE)) + ShowAllLeaks = TRUE; + } + + if (rtlDetectHeapLeaks) + { + InLeakDetection = TRUE; + NumberOfLeaks = 0; + NumberOfLeaksShown = 0; + rtlDetectHeapLeaks(); + InLeakDetection = FALSE; + + wprintf(L"\nNumber of leaks: %lu (%lu displayed)\n", NumberOfLeaks, NumberOfLeaksShown); + } + } + else if (PhEqualStringZ(command, L"mem", TRUE)) + { + PWSTR addressString; + PWSTR bytesString; + PH_STRINGREF addressStringRef; + PH_STRINGREF bytesStringRef; + ULONG64 address64; + ULONG64 numberOfBytes64; + PUCHAR address; + ULONG numberOfBytes; + ULONG blockSize; + UCHAR buffer[16]; + ULONG i; + + addressString = wcstok_s(NULL, delims, &context); + + if (!addressString) + goto PrintMemUsage; + + bytesString = wcstok_s(NULL, delims, &context); + + if (!bytesString) + { + bytesString = L"16"; + } + + PhInitializeStringRef(&addressStringRef, addressString); + PhInitializeStringRef(&bytesStringRef, bytesString); + + if (PhStringToInteger64(&addressStringRef, 16, &address64) && PhStringToInteger64(&bytesStringRef, 10, &numberOfBytes64)) + { + address = (PUCHAR)address64; + numberOfBytes = (ULONG)numberOfBytes64; + + if (numberOfBytes > 256) + { + wprintf(L"Number of bytes must be 256 or smaller.\n"); + goto EndCommand; + } + + blockSize = sizeof(buffer); + + while (numberOfBytes != 0) + { + if (blockSize > numberOfBytes) + blockSize = numberOfBytes; + + __try + { + memcpy(buffer, address, blockSize); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + wprintf(L"Error reading address near %Ix.\n", (ULONG_PTR)address); + goto EndCommand; + } + + // Print hex dump + for (i = 0; i < blockSize; i++) + wprintf(L"%02x ", buffer[i]); + + // Fill remaining space (for last, possibly partial block) + for (; i < sizeof(buffer); i++) + wprintf(L" "); + + wprintf(L" "); + + // Print ASCII dump + for (i = 0; i < blockSize; i++) + putwchar((ULONG)(buffer[i] - ' ') <= (ULONG)('~' - ' ') ? buffer[i] : '.'); + + wprintf(L"\n"); + + address += blockSize; + numberOfBytes -= blockSize; + } + } + + goto EndCommand; +PrintMemUsage: + wprintf(L"Usage: mem address [numberOfBytes]\n"); + wprintf(L"Example: mem 12345678 16\n"); + } + else + { + wprintf(L"Unrecognized command.\n"); + goto EndCommand; // get rid of the compiler warning about the label being unreferenced + } + +EndCommand: + PhDrainAutoPool(&autoPool); + } + + PhDereferenceObject(DebugConsoleSymbolProvider); + + PhDeleteAutoPool(&autoPool); + + return STATUS_SUCCESS; +} diff --git a/ProcessHacker/extmgr.c b/ProcessHacker/extmgr.c index 8d93706205d5..d86051f0bb61 100644 --- a/ProcessHacker/extmgr.c +++ b/ProcessHacker/extmgr.c @@ -1,226 +1,226 @@ -/* - * Process Hacker - - * extension manager - * - * Copyright (C) 2011 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -/* - * The extension manager provides support for generic extensions. It sits directly - * underneath the plugin manager, and has no knowledge of plugin details (how they are - * loaded, plugin information, etc.). - */ - -#include -#include - -LIST_ENTRY PhEmAppContextListHead = { &PhEmAppContextListHead, &PhEmAppContextListHead }; -ULONG PhEmAppContextCount = 0; -PH_EM_OBJECT_TYPE_STATE PhEmObjectTypeState[EmMaximumObjectType] = { 0 }; - -/** - * Initializes the extension manager module. - */ -VOID PhEmInitialization( - VOID - ) -{ - ULONG i; - - for (i = 0; i < EmMaximumObjectType; i++) - { - InitializeListHead(&PhEmObjectTypeState[i].ExtensionListHead); - } -} - -/** - * Initializes an extension application context. - * - * \param AppContext The application context. - * \param AppName The application name. - */ -VOID PhEmInitializeAppContext( - _Out_ PPH_EM_APP_CONTEXT AppContext, - _In_ PPH_STRINGREF AppName - ) -{ - AppContext->AppName = *AppName; - memset(AppContext->Extensions, 0, sizeof(AppContext->Extensions)); - - InsertTailList(&PhEmAppContextListHead, &AppContext->ListEntry); - PhEmAppContextCount++; -} - -/** - * Sets the object extension size and callbacks for an object type. - * - * \param AppContext The application context. - * \param ObjectType The type of object for which the extension is being registered. - * \param ExtensionSize The size of the extension, in bytes. - * \param CreateCallback The object creation callback. - * \param DeleteCallback The object deletion callback. - */ -VOID PhEmSetObjectExtension( - _Inout_ PPH_EM_APP_CONTEXT AppContext, - _In_ PH_EM_OBJECT_TYPE ObjectType, - _In_ SIZE_T ExtensionSize, - _In_opt_ PPH_EM_OBJECT_CALLBACK CreateCallback, - _In_opt_ PPH_EM_OBJECT_CALLBACK DeleteCallback - ) -{ - PPH_EM_OBJECT_TYPE_STATE objectTypeState; - PPH_EM_OBJECT_EXTENSION objectExtension; - - objectTypeState = &PhEmObjectTypeState[ObjectType]; - objectExtension = AppContext->Extensions[ObjectType]; - - if (!objectExtension) - { - objectExtension = PhAllocate(sizeof(PH_EM_OBJECT_EXTENSION)); - memset(objectExtension, 0, sizeof(PH_EM_OBJECT_EXTENSION)); - InsertTailList(&objectTypeState->ExtensionListHead, &objectExtension->ListEntry); - AppContext->Extensions[ObjectType] = objectExtension; - - objectExtension->ExtensionSize = ExtensionSize; - objectExtension->ExtensionOffset = objectTypeState->ExtensionOffset; - - objectTypeState->ExtensionOffset += ExtensionSize; - } - - objectExtension->Callbacks[EmObjectCreate] = CreateCallback; - objectExtension->Callbacks[EmObjectDelete] = DeleteCallback; -} - -/** - * Gets the object extension for an object. - * - * \param AppContext The application context. - * \param ObjectType The type of object for which an extension has been registered. - * \param Object The object. - */ -PVOID PhEmGetObjectExtension( - _In_ PPH_EM_APP_CONTEXT AppContext, - _In_ PH_EM_OBJECT_TYPE ObjectType, - _In_ PVOID Object - ) -{ - PPH_EM_OBJECT_EXTENSION objectExtension; - - objectExtension = AppContext->Extensions[ObjectType]; - - if (!objectExtension) - return NULL; - - return (PCHAR)Object + PhEmObjectTypeState[ObjectType].InitialSize + objectExtension->ExtensionOffset; -} - -/** - * Determines the size of an object, including extensions. - * - * \param ObjectType The object type. - * \param InitialSize The initial size of the object. - */ -SIZE_T PhEmGetObjectSize( - _In_ PH_EM_OBJECT_TYPE ObjectType, - _In_ SIZE_T InitialSize - ) -{ - PhEmObjectTypeState[ObjectType].InitialSize = InitialSize; - - return InitialSize + PhEmObjectTypeState[ObjectType].ExtensionOffset; -} - -/** - * Invokes callbacks for an object operation. - * - * \param ObjectType The object type. - * \param Object The object. - * \param Operation The operation being performed. - */ -VOID PhEmCallObjectOperation( - _In_ PH_EM_OBJECT_TYPE ObjectType, - _In_ PVOID Object, - _In_ PH_EM_OBJECT_OPERATION Operation - ) -{ - PPH_EM_OBJECT_TYPE_STATE objectTypeState; - PLIST_ENTRY listEntry; - PPH_EM_OBJECT_EXTENSION objectExtension; - - if (PhEmAppContextCount == 0) - return; - - objectTypeState = &PhEmObjectTypeState[ObjectType]; - - listEntry = objectTypeState->ExtensionListHead.Flink; - - while (listEntry != &objectTypeState->ExtensionListHead) - { - objectExtension = CONTAINING_RECORD(listEntry, PH_EM_OBJECT_EXTENSION, ListEntry); - - if (objectExtension->Callbacks[Operation]) - { - objectExtension->Callbacks[Operation]( - Object, - ObjectType, - (PCHAR)Object + objectTypeState->InitialSize + objectExtension->ExtensionOffset - ); - } - - listEntry = listEntry->Flink; - } -} - -/** - * Parses an application name and sub-ID pair. - * - * \param CompoundId The compound identifier. - * \param AppName A variable which receives the application name. - * \param SubId A variable which receives the sub-ID. - */ -BOOLEAN PhEmParseCompoundId( - _In_ PPH_STRINGREF CompoundId, - _Out_ PPH_STRINGREF AppName, - _Out_ PULONG SubId - ) -{ - PH_STRINGREF firstPart; - PH_STRINGREF secondPart; - ULONG64 integer; - - firstPart = *CompoundId; - - if (firstPart.Length == 0) - return FALSE; - if (firstPart.Buffer[0] != '+') - return FALSE; - - PhSkipStringRef(&firstPart, sizeof(WCHAR)); - PhSplitStringRefAtChar(&firstPart, '+', &firstPart, &secondPart); - - if (firstPart.Length == 0 || secondPart.Length == 0) - return FALSE; - - if (!PhStringToInteger64(&secondPart, 10, &integer)) - return FALSE; - - *AppName = firstPart; - *SubId = (ULONG)integer; - - return TRUE; -} +/* + * Process Hacker - + * extension manager + * + * Copyright (C) 2011 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +/* + * The extension manager provides support for generic extensions. It sits directly + * underneath the plugin manager, and has no knowledge of plugin details (how they are + * loaded, plugin information, etc.). + */ + +#include +#include + +LIST_ENTRY PhEmAppContextListHead = { &PhEmAppContextListHead, &PhEmAppContextListHead }; +ULONG PhEmAppContextCount = 0; +PH_EM_OBJECT_TYPE_STATE PhEmObjectTypeState[EmMaximumObjectType] = { 0 }; + +/** + * Initializes the extension manager module. + */ +VOID PhEmInitialization( + VOID + ) +{ + ULONG i; + + for (i = 0; i < EmMaximumObjectType; i++) + { + InitializeListHead(&PhEmObjectTypeState[i].ExtensionListHead); + } +} + +/** + * Initializes an extension application context. + * + * \param AppContext The application context. + * \param AppName The application name. + */ +VOID PhEmInitializeAppContext( + _Out_ PPH_EM_APP_CONTEXT AppContext, + _In_ PPH_STRINGREF AppName + ) +{ + AppContext->AppName = *AppName; + memset(AppContext->Extensions, 0, sizeof(AppContext->Extensions)); + + InsertTailList(&PhEmAppContextListHead, &AppContext->ListEntry); + PhEmAppContextCount++; +} + +/** + * Sets the object extension size and callbacks for an object type. + * + * \param AppContext The application context. + * \param ObjectType The type of object for which the extension is being registered. + * \param ExtensionSize The size of the extension, in bytes. + * \param CreateCallback The object creation callback. + * \param DeleteCallback The object deletion callback. + */ +VOID PhEmSetObjectExtension( + _Inout_ PPH_EM_APP_CONTEXT AppContext, + _In_ PH_EM_OBJECT_TYPE ObjectType, + _In_ SIZE_T ExtensionSize, + _In_opt_ PPH_EM_OBJECT_CALLBACK CreateCallback, + _In_opt_ PPH_EM_OBJECT_CALLBACK DeleteCallback + ) +{ + PPH_EM_OBJECT_TYPE_STATE objectTypeState; + PPH_EM_OBJECT_EXTENSION objectExtension; + + objectTypeState = &PhEmObjectTypeState[ObjectType]; + objectExtension = AppContext->Extensions[ObjectType]; + + if (!objectExtension) + { + objectExtension = PhAllocate(sizeof(PH_EM_OBJECT_EXTENSION)); + memset(objectExtension, 0, sizeof(PH_EM_OBJECT_EXTENSION)); + InsertTailList(&objectTypeState->ExtensionListHead, &objectExtension->ListEntry); + AppContext->Extensions[ObjectType] = objectExtension; + + objectExtension->ExtensionSize = ExtensionSize; + objectExtension->ExtensionOffset = objectTypeState->ExtensionOffset; + + objectTypeState->ExtensionOffset += ExtensionSize; + } + + objectExtension->Callbacks[EmObjectCreate] = CreateCallback; + objectExtension->Callbacks[EmObjectDelete] = DeleteCallback; +} + +/** + * Gets the object extension for an object. + * + * \param AppContext The application context. + * \param ObjectType The type of object for which an extension has been registered. + * \param Object The object. + */ +PVOID PhEmGetObjectExtension( + _In_ PPH_EM_APP_CONTEXT AppContext, + _In_ PH_EM_OBJECT_TYPE ObjectType, + _In_ PVOID Object + ) +{ + PPH_EM_OBJECT_EXTENSION objectExtension; + + objectExtension = AppContext->Extensions[ObjectType]; + + if (!objectExtension) + return NULL; + + return (PCHAR)Object + PhEmObjectTypeState[ObjectType].InitialSize + objectExtension->ExtensionOffset; +} + +/** + * Determines the size of an object, including extensions. + * + * \param ObjectType The object type. + * \param InitialSize The initial size of the object. + */ +SIZE_T PhEmGetObjectSize( + _In_ PH_EM_OBJECT_TYPE ObjectType, + _In_ SIZE_T InitialSize + ) +{ + PhEmObjectTypeState[ObjectType].InitialSize = InitialSize; + + return InitialSize + PhEmObjectTypeState[ObjectType].ExtensionOffset; +} + +/** + * Invokes callbacks for an object operation. + * + * \param ObjectType The object type. + * \param Object The object. + * \param Operation The operation being performed. + */ +VOID PhEmCallObjectOperation( + _In_ PH_EM_OBJECT_TYPE ObjectType, + _In_ PVOID Object, + _In_ PH_EM_OBJECT_OPERATION Operation + ) +{ + PPH_EM_OBJECT_TYPE_STATE objectTypeState; + PLIST_ENTRY listEntry; + PPH_EM_OBJECT_EXTENSION objectExtension; + + if (PhEmAppContextCount == 0) + return; + + objectTypeState = &PhEmObjectTypeState[ObjectType]; + + listEntry = objectTypeState->ExtensionListHead.Flink; + + while (listEntry != &objectTypeState->ExtensionListHead) + { + objectExtension = CONTAINING_RECORD(listEntry, PH_EM_OBJECT_EXTENSION, ListEntry); + + if (objectExtension->Callbacks[Operation]) + { + objectExtension->Callbacks[Operation]( + Object, + ObjectType, + (PCHAR)Object + objectTypeState->InitialSize + objectExtension->ExtensionOffset + ); + } + + listEntry = listEntry->Flink; + } +} + +/** + * Parses an application name and sub-ID pair. + * + * \param CompoundId The compound identifier. + * \param AppName A variable which receives the application name. + * \param SubId A variable which receives the sub-ID. + */ +BOOLEAN PhEmParseCompoundId( + _In_ PPH_STRINGREF CompoundId, + _Out_ PPH_STRINGREF AppName, + _Out_ PULONG SubId + ) +{ + PH_STRINGREF firstPart; + PH_STRINGREF secondPart; + ULONG64 integer; + + firstPart = *CompoundId; + + if (firstPart.Length == 0) + return FALSE; + if (firstPart.Buffer[0] != '+') + return FALSE; + + PhSkipStringRef(&firstPart, sizeof(WCHAR)); + PhSplitStringRefAtChar(&firstPart, '+', &firstPart, &secondPart); + + if (firstPart.Length == 0 || secondPart.Length == 0) + return FALSE; + + if (!PhStringToInteger64(&secondPart, 10, &integer)) + return FALSE; + + *AppName = firstPart; + *SubId = (ULONG)integer; + + return TRUE; +} diff --git a/ProcessHacker/findobj.c b/ProcessHacker/findobj.c index 182f4055e882..926cc9549c2a 100644 --- a/ProcessHacker/findobj.c +++ b/ProcessHacker/findobj.c @@ -1,1018 +1,1018 @@ -/* - * Process Hacker - - * object search - * - * Copyright (C) 2010-2016 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include - -#include - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "pcre/pcre2.h" - -#define WM_PH_SEARCH_UPDATE (WM_APP + 801) -#define WM_PH_SEARCH_FINISHED (WM_APP + 802) - -typedef enum _PHP_OBJECT_RESULT_TYPE -{ - HandleSearchResult, - ModuleSearchResult, - MappedFileSearchResult -} PHP_OBJECT_RESULT_TYPE; - -typedef struct _PHP_OBJECT_SEARCH_RESULT -{ - HANDLE ProcessId; - PHP_OBJECT_RESULT_TYPE ResultType; - - HANDLE Handle; - PPH_STRING TypeName; - PPH_STRING Name; - PPH_STRING ProcessName; - - WCHAR HandleString[PH_PTR_STR_LEN_1]; - - SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX Info; -} PHP_OBJECT_SEARCH_RESULT, *PPHP_OBJECT_SEARCH_RESULT; - -INT_PTR CALLBACK PhpFindObjectsDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -NTSTATUS PhpFindObjectsThreadStart( - _In_ PVOID Parameter - ); - -HWND PhFindObjectsWindowHandle = NULL; -HWND PhFindObjectsListViewHandle = NULL; -static PH_LAYOUT_MANAGER WindowLayoutManager; -static RECT MinimumSize; - -static HANDLE SearchThreadHandle = NULL; -static BOOLEAN SearchStop; -static PPH_STRING SearchString; -static pcre2_code *SearchRegexCompiledExpression; -static pcre2_match_data *SearchRegexMatchData; -static PPH_LIST SearchResults = NULL; -static ULONG SearchResultsAddIndex; -static PH_QUEUED_LOCK SearchResultsLock = PH_QUEUED_LOCK_INIT; - -static ULONG64 SearchPointer; -static BOOLEAN UseSearchPointer; - -VOID PhShowFindObjectsDialog( - VOID - ) -{ - if (!PhFindObjectsWindowHandle) - { - PhFindObjectsWindowHandle = CreateDialog( - PhInstanceHandle, - MAKEINTRESOURCE(IDD_FINDOBJECTS), - PhMainWndHandle, - PhpFindObjectsDlgProc - ); - } - - if (!IsWindowVisible(PhFindObjectsWindowHandle)) - ShowWindow(PhFindObjectsWindowHandle, SW_SHOW); - - SetForegroundWindow(PhFindObjectsWindowHandle); -} - -VOID PhpInitializeFindObjMenu( - _In_ PPH_EMENU Menu, - _In_ PPHP_OBJECT_SEARCH_RESULT *Results, - _In_ ULONG NumberOfResults - ) -{ - BOOLEAN allCanBeClosed = TRUE; - ULONG i; - - if (NumberOfResults == 1) - { - PH_HANDLE_ITEM_INFO info; - - info.ProcessId = Results[0]->ProcessId; - info.Handle = Results[0]->Handle; - info.TypeName = Results[0]->TypeName; - info.BestObjectName = Results[0]->Name; - PhInsertHandleObjectPropertiesEMenuItems(Menu, ID_OBJECT_PROPERTIES, FALSE, &info); - } - else - { - PhSetFlagsAllEMenuItems(Menu, PH_EMENU_DISABLED, PH_EMENU_DISABLED); - PhEnableEMenuItem(Menu, ID_OBJECT_COPY, TRUE); - } - - for (i = 0; i < NumberOfResults; i++) - { - if (Results[i]->ResultType != HandleSearchResult) - { - allCanBeClosed = FALSE; - break; - } - } - - PhEnableEMenuItem(Menu, ID_OBJECT_CLOSE, allCanBeClosed); -} - -INT NTAPI PhpObjectProcessCompareFunction( - _In_ PVOID Item1, - _In_ PVOID Item2, - _In_opt_ PVOID Context - ) -{ - PPHP_OBJECT_SEARCH_RESULT item1 = Item1; - PPHP_OBJECT_SEARCH_RESULT item2 = Item2; - INT result; - - result = PhCompareStringWithNull(item1->ProcessName, item2->ProcessName, TRUE); - - if (result != 0) - return result; - else - return uintptrcmp((ULONG_PTR)item1->ProcessId, (ULONG_PTR)item2->ProcessId); -} - -INT NTAPI PhpObjectTypeCompareFunction( - _In_ PVOID Item1, - _In_ PVOID Item2, - _In_opt_ PVOID Context - ) -{ - PPHP_OBJECT_SEARCH_RESULT item1 = Item1; - PPHP_OBJECT_SEARCH_RESULT item2 = Item2; - - return PhCompareString(item1->TypeName, item2->TypeName, TRUE); -} - -INT NTAPI PhpObjectNameCompareFunction( - _In_ PVOID Item1, - _In_ PVOID Item2, - _In_opt_ PVOID Context - ) -{ - PPHP_OBJECT_SEARCH_RESULT item1 = Item1; - PPHP_OBJECT_SEARCH_RESULT item2 = Item2; - - return PhCompareString(item1->Name, item2->Name, TRUE); -} - -INT NTAPI PhpObjectHandleCompareFunction( - _In_ PVOID Item1, - _In_ PVOID Item2, - _In_opt_ PVOID Context - ) -{ - PPHP_OBJECT_SEARCH_RESULT item1 = Item1; - PPHP_OBJECT_SEARCH_RESULT item2 = Item2; - - return uintptrcmp((ULONG_PTR)item1->Handle, (ULONG_PTR)item2->Handle); -} - -static INT_PTR CALLBACK PhpFindObjectsDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - switch (uMsg) - { - case WM_INITDIALOG: - { - HWND lvHandle; - - PhCenterWindow(hwndDlg, GetParent(hwndDlg)); - PhFindObjectsListViewHandle = lvHandle = GetDlgItem(hwndDlg, IDC_RESULTS); - - PhCreateSearchControl(hwndDlg, GetDlgItem(hwndDlg, IDC_FILTER), NULL); - - PhInitializeLayoutManager(&WindowLayoutManager, hwndDlg); - PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDC_FILTER), - NULL, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); - PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDC_REGEX), - NULL, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); - PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDOK), - NULL, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); - PhAddLayoutItem(&WindowLayoutManager, lvHandle, - NULL, PH_ANCHOR_ALL); - - MinimumSize.left = 0; - MinimumSize.top = 0; - MinimumSize.right = 150; - MinimumSize.bottom = 100; - MapDialogRect(hwndDlg, &MinimumSize); - - PhRegisterDialog(hwndDlg); - - PhLoadWindowPlacementFromSetting(L"FindObjWindowPosition", L"FindObjWindowSize", hwndDlg); - - PhSetListViewStyle(lvHandle, TRUE, TRUE); - PhSetControlTheme(lvHandle, L"explorer"); - PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 100, L"Process"); - PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 100, L"Type"); - PhAddListViewColumn(lvHandle, 2, 2, 2, LVCFMT_LEFT, 200, L"Name"); - PhAddListViewColumn(lvHandle, 3, 3, 3, LVCFMT_LEFT, 80, L"Handle"); - - PhSetExtendedListView(lvHandle); - ExtendedListView_SetSortFast(lvHandle, TRUE); - ExtendedListView_SetCompareFunction(lvHandle, 0, PhpObjectProcessCompareFunction); - ExtendedListView_SetCompareFunction(lvHandle, 1, PhpObjectTypeCompareFunction); - ExtendedListView_SetCompareFunction(lvHandle, 2, PhpObjectNameCompareFunction); - ExtendedListView_SetCompareFunction(lvHandle, 3, PhpObjectHandleCompareFunction); - PhLoadListViewColumnsFromSetting(L"FindObjListViewColumns", lvHandle); - - Button_SetCheck(GetDlgItem(hwndDlg, IDC_REGEX), PhGetIntegerSetting(L"FindObjRegex") ? BST_CHECKED : BST_UNCHECKED); - } - break; - case WM_DESTROY: - { - PhSetIntegerSetting(L"FindObjRegex", Button_GetCheck(GetDlgItem(hwndDlg, IDC_REGEX)) == BST_CHECKED); - PhSaveWindowPlacementToSetting(L"FindObjWindowPosition", L"FindObjWindowSize", hwndDlg); - PhSaveListViewColumnsToSetting(L"FindObjListViewColumns", PhFindObjectsListViewHandle); - } - break; - case WM_SHOWWINDOW: - { - SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hwndDlg, IDC_FILTER), TRUE); - Edit_SetSel(GetDlgItem(hwndDlg, IDC_FILTER), 0, -1); - } - break; - case WM_CLOSE: - { - ShowWindow(hwndDlg, SW_HIDE); - // IMPORTANT - // Set the result to 0 so the default dialog message - // handler doesn't invoke IDCANCEL, which will send - // WM_CLOSE, creating an infinite loop. - SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, 0); - } - return TRUE; - case WM_SETCURSOR: - { - if (SearchThreadHandle) - { - SetCursor(LoadCursor(NULL, IDC_WAIT)); - SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, TRUE); - return TRUE; - } - } - break; - case WM_COMMAND: - { - switch (LOWORD(wParam)) - { - case IDOK: - { - // Don't continue if the user requested cancellation. - if (SearchStop) - break; - - if (!SearchThreadHandle) - { - ULONG i; - - PhMoveReference(&SearchString, PhGetWindowText(GetDlgItem(hwndDlg, IDC_FILTER))); - - if (SearchRegexCompiledExpression) - { - pcre2_code_free(SearchRegexCompiledExpression); - SearchRegexCompiledExpression = NULL; - } - - if (SearchRegexMatchData) - { - pcre2_match_data_free(SearchRegexMatchData); - SearchRegexMatchData = NULL; - } - - if (Button_GetCheck(GetDlgItem(hwndDlg, IDC_REGEX)) == BST_CHECKED) - { - int errorCode; - PCRE2_SIZE errorOffset; - - SearchRegexCompiledExpression = pcre2_compile( - SearchString->Buffer, - SearchString->Length / sizeof(WCHAR), - PCRE2_CASELESS | PCRE2_DOTALL, - &errorCode, - &errorOffset, - NULL - ); - - if (!SearchRegexCompiledExpression) - { - PhShowError(hwndDlg, L"Unable to compile the regular expression: \"%s\" at position %zu.", - PhGetStringOrDefault(PH_AUTO(PhPcre2GetErrorMessage(errorCode)), L"Unknown error"), - errorOffset - ); - break; - } - - SearchRegexMatchData = pcre2_match_data_create_from_pattern(SearchRegexCompiledExpression, NULL); - } - - // Clean up previous results. - - ListView_DeleteAllItems(PhFindObjectsListViewHandle); - - if (SearchResults) - { - for (i = 0; i < SearchResults->Count; i++) - { - PPHP_OBJECT_SEARCH_RESULT searchResult = SearchResults->Items[i]; - - PhDereferenceObject(searchResult->TypeName); - PhDereferenceObject(searchResult->Name); - - if (searchResult->ProcessName) - PhDereferenceObject(searchResult->ProcessName); - - PhFree(searchResult); - } - - PhDereferenceObject(SearchResults); - } - - // Start the search. - - SearchResults = PhCreateList(128); - SearchResultsAddIndex = 0; - - SearchThreadHandle = PhCreateThread(0, PhpFindObjectsThreadStart, NULL); - - if (!SearchThreadHandle) - { - PhClearReference(&SearchResults); - break; - } - - SetDlgItemText(hwndDlg, IDOK, L"Cancel"); - - SetCursor(LoadCursor(NULL, IDC_WAIT)); - } - else - { - SearchStop = TRUE; - EnableWindow(GetDlgItem(hwndDlg, IDOK), FALSE); - } - } - break; - case IDCANCEL: - { - SendMessage(hwndDlg, WM_CLOSE, 0, 0); - } - break; - case ID_OBJECT_CLOSE: - { - PPHP_OBJECT_SEARCH_RESULT *results; - ULONG numberOfResults; - ULONG i; - - PhGetSelectedListViewItemParams( - PhFindObjectsListViewHandle, - &results, - &numberOfResults - ); - - if (numberOfResults != 0 && PhShowConfirmMessage( - hwndDlg, - L"close", - numberOfResults == 1 ? L"the selected handle" : L"the selected handles", - L"Closing handles may cause system instability and data corruption.", - FALSE - )) - { - for (i = 0; i < numberOfResults; i++) - { - NTSTATUS status; - HANDLE processHandle; - - if (results[i]->ResultType != HandleSearchResult) - continue; - - if (NT_SUCCESS(status = PhOpenProcess( - &processHandle, - PROCESS_DUP_HANDLE, - results[i]->ProcessId - ))) - { - if (NT_SUCCESS(status = NtDuplicateObject( - processHandle, - results[i]->Handle, - NULL, - NULL, - 0, - 0, - DUPLICATE_CLOSE_SOURCE - ))) - { - PhRemoveListViewItem(PhFindObjectsListViewHandle, - PhFindListViewItemByParam(PhFindObjectsListViewHandle, 0, results[i])); - } - - NtClose(processHandle); - } - - if (!NT_SUCCESS(status)) - { - if (!PhShowContinueStatus(hwndDlg, - PhaFormatString(L"Unable to close \"%s\"", results[i]->Name->Buffer)->Buffer, - status, - 0 - )) - break; - } - } - } - - PhFree(results); - } - break; - case ID_HANDLE_OBJECTPROPERTIES1: - case ID_HANDLE_OBJECTPROPERTIES2: - { - PPHP_OBJECT_SEARCH_RESULT result = - PhGetSelectedListViewItemParam(PhFindObjectsListViewHandle); - - if (result) - { - PH_HANDLE_ITEM_INFO info; - - info.ProcessId = result->ProcessId; - info.Handle = result->Handle; - info.TypeName = result->TypeName; - info.BestObjectName = result->Name; - - if (LOWORD(wParam) == ID_HANDLE_OBJECTPROPERTIES1) - PhShowHandleObjectProperties1(hwndDlg, &info); - else - PhShowHandleObjectProperties2(hwndDlg, &info); - } - } - break; - case ID_OBJECT_GOTOOWNINGPROCESS: - { - PPHP_OBJECT_SEARCH_RESULT result = - PhGetSelectedListViewItemParam(PhFindObjectsListViewHandle); - - if (result) - { - PPH_PROCESS_NODE processNode; - - if (processNode = PhFindProcessNode(result->ProcessId)) - { - ProcessHacker_SelectTabPage(PhMainWndHandle, 0); - ProcessHacker_SelectProcessNode(PhMainWndHandle, processNode); - ProcessHacker_ToggleVisible(PhMainWndHandle, TRUE); - } - } - } - break; - case ID_OBJECT_PROPERTIES: - { - PPHP_OBJECT_SEARCH_RESULT result = - PhGetSelectedListViewItemParam(PhFindObjectsListViewHandle); - - if (result) - { - if (result->ResultType == HandleSearchResult) - { - PPH_HANDLE_ITEM handleItem; - - handleItem = PhCreateHandleItem(&result->Info); - - handleItem->BestObjectName = handleItem->ObjectName = result->Name; - PhReferenceObjectEx(result->Name, 2); - - handleItem->TypeName = result->TypeName; - PhReferenceObject(result->TypeName); - - PhShowHandleProperties( - hwndDlg, - result->ProcessId, - handleItem - ); - PhDereferenceObject(handleItem); - } - else - { - // DLL or Mapped File. Just show file properties. - PhShellProperties(hwndDlg, result->Name->Buffer); - } - } - } - break; - case ID_OBJECT_COPY: - { - PhCopyListView(PhFindObjectsListViewHandle); - } - break; - } - } - break; - case WM_NOTIFY: - { - LPNMHDR header = (LPNMHDR)lParam; - - switch (header->code) - { - case NM_DBLCLK: - { - if (header->hwndFrom == PhFindObjectsListViewHandle) - { - SendMessage(hwndDlg, WM_COMMAND, ID_OBJECT_PROPERTIES, 0); - } - } - break; - case LVN_KEYDOWN: - { - if (header->hwndFrom == PhFindObjectsListViewHandle) - { - LPNMLVKEYDOWN keyDown = (LPNMLVKEYDOWN)header; - - switch (keyDown->wVKey) - { - case 'C': - if (GetKeyState(VK_CONTROL) < 0) - SendMessage(hwndDlg, WM_COMMAND, ID_OBJECT_COPY, 0); - break; - case 'A': - if (GetKeyState(VK_CONTROL) < 0) - PhSetStateAllListViewItems(PhFindObjectsListViewHandle, LVIS_SELECTED, LVIS_SELECTED); - break; - case VK_DELETE: - SendMessage(hwndDlg, WM_COMMAND, ID_OBJECT_CLOSE, 0); - break; - } - } - } - break; - } - } - break; - case WM_CONTEXTMENU: - { - if ((HWND)wParam == PhFindObjectsListViewHandle) - { - POINT point; - PPHP_OBJECT_SEARCH_RESULT *results; - ULONG numberOfResults; - - point.x = (SHORT)LOWORD(lParam); - point.y = (SHORT)HIWORD(lParam); - - if (point.x == -1 && point.y == -1) - PhGetListViewContextMenuPoint((HWND)wParam, &point); - - PhGetSelectedListViewItemParams(PhFindObjectsListViewHandle, &results, &numberOfResults); - - if (numberOfResults != 0) - { - PPH_EMENU menu; - - menu = PhCreateEMenu(); - PhLoadResourceEMenuItem(menu, PhInstanceHandle, MAKEINTRESOURCE(IDR_FINDOBJ), 0); - PhSetFlagsEMenuItem(menu, ID_OBJECT_PROPERTIES, PH_EMENU_DEFAULT, PH_EMENU_DEFAULT); - - PhpInitializeFindObjMenu(menu, results, numberOfResults); - PhShowEMenu( - menu, - hwndDlg, - PH_EMENU_SHOW_SEND_COMMAND | PH_EMENU_SHOW_LEFTRIGHT, - PH_ALIGN_LEFT | PH_ALIGN_TOP, - point.x, - point.y - ); - PhDestroyEMenu(menu); - } - - PhFree(results); - } - } - break; - case WM_SIZE: - { - PhLayoutManagerLayout(&WindowLayoutManager); - } - break; - case WM_SIZING: - { - PhResizingMinimumSize((PRECT)lParam, wParam, MinimumSize.right, MinimumSize.bottom); - } - break; - case WM_PH_SEARCH_UPDATE: - { - HWND lvHandle; - ULONG i; - - lvHandle = GetDlgItem(hwndDlg, IDC_RESULTS); - - ExtendedListView_SetRedraw(lvHandle, FALSE); - - PhAcquireQueuedLockExclusive(&SearchResultsLock); - - for (i = SearchResultsAddIndex; i < SearchResults->Count; i++) - { - PPHP_OBJECT_SEARCH_RESULT searchResult = SearchResults->Items[i]; - CLIENT_ID clientId; - PPH_PROCESS_ITEM processItem; - PPH_STRING clientIdName; - INT lvItemIndex; - - clientId.UniqueProcess = searchResult->ProcessId; - clientId.UniqueThread = NULL; - - processItem = PhReferenceProcessItem(clientId.UniqueProcess); - clientIdName = PhGetClientIdNameEx(&clientId, processItem ? processItem->ProcessName : NULL); - - lvItemIndex = PhAddListViewItem( - lvHandle, - MAXINT, - clientIdName->Buffer, - searchResult - ); - - PhDereferenceObject(clientIdName); - - if (processItem) - { - PhSetReference(&searchResult->ProcessName, processItem->ProcessName); - PhDereferenceObject(processItem); - } - else - { - searchResult->ProcessName = NULL; - } - - PhSetListViewSubItem(lvHandle, lvItemIndex, 1, searchResult->TypeName->Buffer); - PhSetListViewSubItem(lvHandle, lvItemIndex, 2, searchResult->Name->Buffer); - PhSetListViewSubItem(lvHandle, lvItemIndex, 3, searchResult->HandleString); - } - - SearchResultsAddIndex = i; - - PhReleaseQueuedLockExclusive(&SearchResultsLock); - - ExtendedListView_SetRedraw(lvHandle, TRUE); - } - break; - case WM_PH_SEARCH_FINISHED: - { - NTSTATUS handleSearchStatus = (NTSTATUS)wParam; - - // Add any un-added items. - SendMessage(hwndDlg, WM_PH_SEARCH_UPDATE, 0, 0); - - NtWaitForSingleObject(SearchThreadHandle, FALSE, NULL); - NtClose(SearchThreadHandle); - SearchThreadHandle = NULL; - SearchStop = FALSE; - - ExtendedListView_SortItems(GetDlgItem(hwndDlg, IDC_RESULTS)); - - SetDlgItemText(hwndDlg, IDOK, L"Find"); - EnableWindow(GetDlgItem(hwndDlg, IDOK), TRUE); - - SetCursor(LoadCursor(NULL, IDC_ARROW)); - - if (handleSearchStatus == STATUS_INSUFFICIENT_RESOURCES) - { - PhShowWarning( - hwndDlg, - L"Unable to search for handles because the total number of handles on the system is too large. " - L"Please check if there are any processes with an extremely large number of handles open." - ); - } - } - break; - } - - return FALSE; -} - -static BOOLEAN MatchSearchString( - _In_ PPH_STRINGREF Input - ) -{ - if (SearchRegexCompiledExpression && SearchRegexMatchData) - { - return pcre2_match( - SearchRegexCompiledExpression, - Input->Buffer, - Input->Length / sizeof(WCHAR), - 0, - 0, - SearchRegexMatchData, - NULL - ) >= 0; - } - else - { - return PhFindStringInStringRef(Input, &SearchString->sr, TRUE) != -1; - } -} - -typedef struct _SEARCH_HANDLE_CONTEXT -{ - BOOLEAN NeedToFree; - PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX HandleInfo; - HANDLE ProcessHandle; -} SEARCH_HANDLE_CONTEXT, *PSEARCH_HANDLE_CONTEXT; - -static NTSTATUS NTAPI SearchHandleFunction( - _In_ PVOID Parameter - ) -{ - PSEARCH_HANDLE_CONTEXT context = Parameter; - PPH_STRING typeName; - PPH_STRING bestObjectName; - - if (!SearchStop && NT_SUCCESS(PhGetHandleInformation( - context->ProcessHandle, - (HANDLE)context->HandleInfo->HandleValue, - context->HandleInfo->ObjectTypeIndex, - NULL, - &typeName, - NULL, - &bestObjectName - ))) - { - PPH_STRING upperBestObjectName; - - upperBestObjectName = PhDuplicateString(bestObjectName); - _wcsupr(upperBestObjectName->Buffer); - - if (MatchSearchString(&upperBestObjectName->sr) || - (UseSearchPointer && context->HandleInfo->Object == (PVOID)SearchPointer)) - { - PPHP_OBJECT_SEARCH_RESULT searchResult; - - searchResult = PhAllocate(sizeof(PHP_OBJECT_SEARCH_RESULT)); - searchResult->ProcessId = (HANDLE)context->HandleInfo->UniqueProcessId; - searchResult->ResultType = HandleSearchResult; - searchResult->Handle = (HANDLE)context->HandleInfo->HandleValue; - searchResult->TypeName = typeName; - searchResult->Name = bestObjectName; - PhPrintPointer(searchResult->HandleString, (PVOID)searchResult->Handle); - searchResult->Info = *context->HandleInfo; - - PhAcquireQueuedLockExclusive(&SearchResultsLock); - - PhAddItemList(SearchResults, searchResult); - - // Update the search results in batches of 40. - if (SearchResults->Count % 40 == 0) - PostMessage(PhFindObjectsWindowHandle, WM_PH_SEARCH_UPDATE, 0, 0); - - PhReleaseQueuedLockExclusive(&SearchResultsLock); - } - else - { - PhDereferenceObject(typeName); - PhDereferenceObject(bestObjectName); - } - - PhDereferenceObject(upperBestObjectName); - } - - if (context->NeedToFree) - PhFree(context); - - return STATUS_SUCCESS; -} - -static BOOLEAN NTAPI EnumModulesCallback( - _In_ PPH_MODULE_INFO Module, - _In_opt_ PVOID Context - ) -{ - PPH_STRING upperFileName; - - upperFileName = PhDuplicateString(Module->FileName); - _wcsupr(upperFileName->Buffer); - - if (MatchSearchString(&upperFileName->sr) || - (UseSearchPointer && Module->BaseAddress == (PVOID)SearchPointer)) - { - PPHP_OBJECT_SEARCH_RESULT searchResult; - PWSTR typeName; - - switch (Module->Type) - { - case PH_MODULE_TYPE_MAPPED_FILE: - typeName = L"Mapped file"; - break; - case PH_MODULE_TYPE_MAPPED_IMAGE: - typeName = L"Mapped image"; - break; - default: - typeName = L"DLL"; - break; - } - - searchResult = PhAllocate(sizeof(PHP_OBJECT_SEARCH_RESULT)); - searchResult->ProcessId = (HANDLE)Context; - searchResult->ResultType = (Module->Type == PH_MODULE_TYPE_MAPPED_FILE || Module->Type == PH_MODULE_TYPE_MAPPED_IMAGE) ? MappedFileSearchResult : ModuleSearchResult; - searchResult->Handle = (HANDLE)Module->BaseAddress; - searchResult->TypeName = PhCreateString(typeName); - PhSetReference(&searchResult->Name, Module->FileName); - PhPrintPointer(searchResult->HandleString, Module->BaseAddress); - memset(&searchResult->Info, 0, sizeof(SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX)); - - PhAcquireQueuedLockExclusive(&SearchResultsLock); - - PhAddItemList(SearchResults, searchResult); - - // Update the search results in batches of 40. - if (SearchResults->Count % 40 == 0) - PostMessage(PhFindObjectsWindowHandle, WM_PH_SEARCH_UPDATE, 0, 0); - - PhReleaseQueuedLockExclusive(&SearchResultsLock); - } - - PhDereferenceObject(upperFileName); - - return TRUE; -} - -static NTSTATUS PhpFindObjectsThreadStart( - _In_ PVOID Parameter - ) -{ - NTSTATUS status = STATUS_SUCCESS; - PSYSTEM_HANDLE_INFORMATION_EX handles; - PPH_HASHTABLE processHandleHashtable; - PVOID processes; - PSYSTEM_PROCESS_INFORMATION process; - ULONG i; - - // Refuse to search with no filter. - if (SearchString->Length == 0) - goto Exit; - - // Try to get a search pointer from the search string. - UseSearchPointer = PhStringToInteger64(&SearchString->sr, 0, &SearchPointer); - - _wcsupr(SearchString->Buffer); - - if (NT_SUCCESS(status = PhEnumHandlesEx(&handles))) - { - static PH_INITONCE initOnce = PH_INITONCE_INIT; - static ULONG fileObjectTypeIndex = -1; - - BOOLEAN useWorkQueue = FALSE; - PH_WORK_QUEUE workQueue; - processHandleHashtable = PhCreateSimpleHashtable(8); - - if (!KphIsConnected() && WindowsVersion >= WINDOWS_VISTA) - { - useWorkQueue = TRUE; - PhInitializeWorkQueue(&workQueue, 1, 20, 1000); - - if (PhBeginInitOnce(&initOnce)) - { - UNICODE_STRING fileTypeName; - - RtlInitUnicodeString(&fileTypeName, L"File"); - fileObjectTypeIndex = PhGetObjectTypeNumber(&fileTypeName); - PhEndInitOnce(&initOnce); - } - } - - for (i = 0; i < handles->NumberOfHandles; i++) - { - PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX handleInfo = &handles->Handles[i]; - PVOID *processHandlePtr; - HANDLE processHandle; - - if (SearchStop) - break; - - // Open a handle to the process if we don't already have one. - - processHandlePtr = PhFindItemSimpleHashtable( - processHandleHashtable, - (PVOID)handleInfo->UniqueProcessId - ); - - if (processHandlePtr) - { - processHandle = (HANDLE)*processHandlePtr; - } - else - { - if (NT_SUCCESS(PhOpenProcess( - &processHandle, - PROCESS_DUP_HANDLE, - (HANDLE)handleInfo->UniqueProcessId - ))) - { - PhAddItemSimpleHashtable( - processHandleHashtable, - (PVOID)handleInfo->UniqueProcessId, - processHandle - ); - } - else - { - continue; - } - } - - if (useWorkQueue && handleInfo->ObjectTypeIndex == (USHORT)fileObjectTypeIndex) - { - PSEARCH_HANDLE_CONTEXT searchHandleContext; - - searchHandleContext = PhAllocate(sizeof(SEARCH_HANDLE_CONTEXT)); - searchHandleContext->NeedToFree = TRUE; - searchHandleContext->HandleInfo = handleInfo; - searchHandleContext->ProcessHandle = processHandle; - PhQueueItemWorkQueue(&workQueue, SearchHandleFunction, searchHandleContext); - } - else - { - SEARCH_HANDLE_CONTEXT searchHandleContext; - - searchHandleContext.NeedToFree = FALSE; - searchHandleContext.HandleInfo = handleInfo; - searchHandleContext.ProcessHandle = processHandle; - SearchHandleFunction(&searchHandleContext); - } - } - - if (useWorkQueue) - { - PhWaitForWorkQueue(&workQueue); - PhDeleteWorkQueue(&workQueue); - } - - { - PPH_KEY_VALUE_PAIR entry; - - i = 0; - - while (PhEnumHashtable(processHandleHashtable, &entry, &i)) - NtClose((HANDLE)entry->Value); - } - - PhDereferenceObject(processHandleHashtable); - PhFree(handles); - } - - if (NT_SUCCESS(PhEnumProcesses(&processes))) - { - process = PH_FIRST_PROCESS(processes); - - do - { - PhEnumGenericModules( - process->UniqueProcessId, - NULL, - PH_ENUM_GENERIC_MAPPED_FILES | PH_ENUM_GENERIC_MAPPED_IMAGES, - EnumModulesCallback, - (PVOID)process->UniqueProcessId - ); - } while (process = PH_NEXT_PROCESS(process)); - - PhFree(processes); - } - -Exit: - PostMessage(PhFindObjectsWindowHandle, WM_PH_SEARCH_FINISHED, status, 0); - - return STATUS_SUCCESS; -} +/* + * Process Hacker - + * object search + * + * Copyright (C) 2010-2016 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "pcre/pcre2.h" + +#define WM_PH_SEARCH_UPDATE (WM_APP + 801) +#define WM_PH_SEARCH_FINISHED (WM_APP + 802) + +typedef enum _PHP_OBJECT_RESULT_TYPE +{ + HandleSearchResult, + ModuleSearchResult, + MappedFileSearchResult +} PHP_OBJECT_RESULT_TYPE; + +typedef struct _PHP_OBJECT_SEARCH_RESULT +{ + HANDLE ProcessId; + PHP_OBJECT_RESULT_TYPE ResultType; + + HANDLE Handle; + PPH_STRING TypeName; + PPH_STRING Name; + PPH_STRING ProcessName; + + WCHAR HandleString[PH_PTR_STR_LEN_1]; + + SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX Info; +} PHP_OBJECT_SEARCH_RESULT, *PPHP_OBJECT_SEARCH_RESULT; + +INT_PTR CALLBACK PhpFindObjectsDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +NTSTATUS PhpFindObjectsThreadStart( + _In_ PVOID Parameter + ); + +HWND PhFindObjectsWindowHandle = NULL; +HWND PhFindObjectsListViewHandle = NULL; +static PH_LAYOUT_MANAGER WindowLayoutManager; +static RECT MinimumSize; + +static HANDLE SearchThreadHandle = NULL; +static BOOLEAN SearchStop; +static PPH_STRING SearchString; +static pcre2_code *SearchRegexCompiledExpression; +static pcre2_match_data *SearchRegexMatchData; +static PPH_LIST SearchResults = NULL; +static ULONG SearchResultsAddIndex; +static PH_QUEUED_LOCK SearchResultsLock = PH_QUEUED_LOCK_INIT; + +static ULONG64 SearchPointer; +static BOOLEAN UseSearchPointer; + +VOID PhShowFindObjectsDialog( + VOID + ) +{ + if (!PhFindObjectsWindowHandle) + { + PhFindObjectsWindowHandle = CreateDialog( + PhInstanceHandle, + MAKEINTRESOURCE(IDD_FINDOBJECTS), + PhMainWndHandle, + PhpFindObjectsDlgProc + ); + } + + if (!IsWindowVisible(PhFindObjectsWindowHandle)) + ShowWindow(PhFindObjectsWindowHandle, SW_SHOW); + + SetForegroundWindow(PhFindObjectsWindowHandle); +} + +VOID PhpInitializeFindObjMenu( + _In_ PPH_EMENU Menu, + _In_ PPHP_OBJECT_SEARCH_RESULT *Results, + _In_ ULONG NumberOfResults + ) +{ + BOOLEAN allCanBeClosed = TRUE; + ULONG i; + + if (NumberOfResults == 1) + { + PH_HANDLE_ITEM_INFO info; + + info.ProcessId = Results[0]->ProcessId; + info.Handle = Results[0]->Handle; + info.TypeName = Results[0]->TypeName; + info.BestObjectName = Results[0]->Name; + PhInsertHandleObjectPropertiesEMenuItems(Menu, ID_OBJECT_PROPERTIES, FALSE, &info); + } + else + { + PhSetFlagsAllEMenuItems(Menu, PH_EMENU_DISABLED, PH_EMENU_DISABLED); + PhEnableEMenuItem(Menu, ID_OBJECT_COPY, TRUE); + } + + for (i = 0; i < NumberOfResults; i++) + { + if (Results[i]->ResultType != HandleSearchResult) + { + allCanBeClosed = FALSE; + break; + } + } + + PhEnableEMenuItem(Menu, ID_OBJECT_CLOSE, allCanBeClosed); +} + +INT NTAPI PhpObjectProcessCompareFunction( + _In_ PVOID Item1, + _In_ PVOID Item2, + _In_opt_ PVOID Context + ) +{ + PPHP_OBJECT_SEARCH_RESULT item1 = Item1; + PPHP_OBJECT_SEARCH_RESULT item2 = Item2; + INT result; + + result = PhCompareStringWithNull(item1->ProcessName, item2->ProcessName, TRUE); + + if (result != 0) + return result; + else + return uintptrcmp((ULONG_PTR)item1->ProcessId, (ULONG_PTR)item2->ProcessId); +} + +INT NTAPI PhpObjectTypeCompareFunction( + _In_ PVOID Item1, + _In_ PVOID Item2, + _In_opt_ PVOID Context + ) +{ + PPHP_OBJECT_SEARCH_RESULT item1 = Item1; + PPHP_OBJECT_SEARCH_RESULT item2 = Item2; + + return PhCompareString(item1->TypeName, item2->TypeName, TRUE); +} + +INT NTAPI PhpObjectNameCompareFunction( + _In_ PVOID Item1, + _In_ PVOID Item2, + _In_opt_ PVOID Context + ) +{ + PPHP_OBJECT_SEARCH_RESULT item1 = Item1; + PPHP_OBJECT_SEARCH_RESULT item2 = Item2; + + return PhCompareString(item1->Name, item2->Name, TRUE); +} + +INT NTAPI PhpObjectHandleCompareFunction( + _In_ PVOID Item1, + _In_ PVOID Item2, + _In_opt_ PVOID Context + ) +{ + PPHP_OBJECT_SEARCH_RESULT item1 = Item1; + PPHP_OBJECT_SEARCH_RESULT item2 = Item2; + + return uintptrcmp((ULONG_PTR)item1->Handle, (ULONG_PTR)item2->Handle); +} + +static INT_PTR CALLBACK PhpFindObjectsDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + switch (uMsg) + { + case WM_INITDIALOG: + { + HWND lvHandle; + + PhCenterWindow(hwndDlg, GetParent(hwndDlg)); + PhFindObjectsListViewHandle = lvHandle = GetDlgItem(hwndDlg, IDC_RESULTS); + + PhCreateSearchControl(hwndDlg, GetDlgItem(hwndDlg, IDC_FILTER), NULL); + + PhInitializeLayoutManager(&WindowLayoutManager, hwndDlg); + PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDC_FILTER), + NULL, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); + PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDC_REGEX), + NULL, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); + PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDOK), + NULL, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); + PhAddLayoutItem(&WindowLayoutManager, lvHandle, + NULL, PH_ANCHOR_ALL); + + MinimumSize.left = 0; + MinimumSize.top = 0; + MinimumSize.right = 150; + MinimumSize.bottom = 100; + MapDialogRect(hwndDlg, &MinimumSize); + + PhRegisterDialog(hwndDlg); + + PhLoadWindowPlacementFromSetting(L"FindObjWindowPosition", L"FindObjWindowSize", hwndDlg); + + PhSetListViewStyle(lvHandle, TRUE, TRUE); + PhSetControlTheme(lvHandle, L"explorer"); + PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 100, L"Process"); + PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 100, L"Type"); + PhAddListViewColumn(lvHandle, 2, 2, 2, LVCFMT_LEFT, 200, L"Name"); + PhAddListViewColumn(lvHandle, 3, 3, 3, LVCFMT_LEFT, 80, L"Handle"); + + PhSetExtendedListView(lvHandle); + ExtendedListView_SetSortFast(lvHandle, TRUE); + ExtendedListView_SetCompareFunction(lvHandle, 0, PhpObjectProcessCompareFunction); + ExtendedListView_SetCompareFunction(lvHandle, 1, PhpObjectTypeCompareFunction); + ExtendedListView_SetCompareFunction(lvHandle, 2, PhpObjectNameCompareFunction); + ExtendedListView_SetCompareFunction(lvHandle, 3, PhpObjectHandleCompareFunction); + PhLoadListViewColumnsFromSetting(L"FindObjListViewColumns", lvHandle); + + Button_SetCheck(GetDlgItem(hwndDlg, IDC_REGEX), PhGetIntegerSetting(L"FindObjRegex") ? BST_CHECKED : BST_UNCHECKED); + } + break; + case WM_DESTROY: + { + PhSetIntegerSetting(L"FindObjRegex", Button_GetCheck(GetDlgItem(hwndDlg, IDC_REGEX)) == BST_CHECKED); + PhSaveWindowPlacementToSetting(L"FindObjWindowPosition", L"FindObjWindowSize", hwndDlg); + PhSaveListViewColumnsToSetting(L"FindObjListViewColumns", PhFindObjectsListViewHandle); + } + break; + case WM_SHOWWINDOW: + { + SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hwndDlg, IDC_FILTER), TRUE); + Edit_SetSel(GetDlgItem(hwndDlg, IDC_FILTER), 0, -1); + } + break; + case WM_CLOSE: + { + ShowWindow(hwndDlg, SW_HIDE); + // IMPORTANT + // Set the result to 0 so the default dialog message + // handler doesn't invoke IDCANCEL, which will send + // WM_CLOSE, creating an infinite loop. + SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, 0); + } + return TRUE; + case WM_SETCURSOR: + { + if (SearchThreadHandle) + { + SetCursor(LoadCursor(NULL, IDC_WAIT)); + SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, TRUE); + return TRUE; + } + } + break; + case WM_COMMAND: + { + switch (LOWORD(wParam)) + { + case IDOK: + { + // Don't continue if the user requested cancellation. + if (SearchStop) + break; + + if (!SearchThreadHandle) + { + ULONG i; + + PhMoveReference(&SearchString, PhGetWindowText(GetDlgItem(hwndDlg, IDC_FILTER))); + + if (SearchRegexCompiledExpression) + { + pcre2_code_free(SearchRegexCompiledExpression); + SearchRegexCompiledExpression = NULL; + } + + if (SearchRegexMatchData) + { + pcre2_match_data_free(SearchRegexMatchData); + SearchRegexMatchData = NULL; + } + + if (Button_GetCheck(GetDlgItem(hwndDlg, IDC_REGEX)) == BST_CHECKED) + { + int errorCode; + PCRE2_SIZE errorOffset; + + SearchRegexCompiledExpression = pcre2_compile( + SearchString->Buffer, + SearchString->Length / sizeof(WCHAR), + PCRE2_CASELESS | PCRE2_DOTALL, + &errorCode, + &errorOffset, + NULL + ); + + if (!SearchRegexCompiledExpression) + { + PhShowError(hwndDlg, L"Unable to compile the regular expression: \"%s\" at position %zu.", + PhGetStringOrDefault(PH_AUTO(PhPcre2GetErrorMessage(errorCode)), L"Unknown error"), + errorOffset + ); + break; + } + + SearchRegexMatchData = pcre2_match_data_create_from_pattern(SearchRegexCompiledExpression, NULL); + } + + // Clean up previous results. + + ListView_DeleteAllItems(PhFindObjectsListViewHandle); + + if (SearchResults) + { + for (i = 0; i < SearchResults->Count; i++) + { + PPHP_OBJECT_SEARCH_RESULT searchResult = SearchResults->Items[i]; + + PhDereferenceObject(searchResult->TypeName); + PhDereferenceObject(searchResult->Name); + + if (searchResult->ProcessName) + PhDereferenceObject(searchResult->ProcessName); + + PhFree(searchResult); + } + + PhDereferenceObject(SearchResults); + } + + // Start the search. + + SearchResults = PhCreateList(128); + SearchResultsAddIndex = 0; + + SearchThreadHandle = PhCreateThread(0, PhpFindObjectsThreadStart, NULL); + + if (!SearchThreadHandle) + { + PhClearReference(&SearchResults); + break; + } + + SetDlgItemText(hwndDlg, IDOK, L"Cancel"); + + SetCursor(LoadCursor(NULL, IDC_WAIT)); + } + else + { + SearchStop = TRUE; + EnableWindow(GetDlgItem(hwndDlg, IDOK), FALSE); + } + } + break; + case IDCANCEL: + { + SendMessage(hwndDlg, WM_CLOSE, 0, 0); + } + break; + case ID_OBJECT_CLOSE: + { + PPHP_OBJECT_SEARCH_RESULT *results; + ULONG numberOfResults; + ULONG i; + + PhGetSelectedListViewItemParams( + PhFindObjectsListViewHandle, + &results, + &numberOfResults + ); + + if (numberOfResults != 0 && PhShowConfirmMessage( + hwndDlg, + L"close", + numberOfResults == 1 ? L"the selected handle" : L"the selected handles", + L"Closing handles may cause system instability and data corruption.", + FALSE + )) + { + for (i = 0; i < numberOfResults; i++) + { + NTSTATUS status; + HANDLE processHandle; + + if (results[i]->ResultType != HandleSearchResult) + continue; + + if (NT_SUCCESS(status = PhOpenProcess( + &processHandle, + PROCESS_DUP_HANDLE, + results[i]->ProcessId + ))) + { + if (NT_SUCCESS(status = NtDuplicateObject( + processHandle, + results[i]->Handle, + NULL, + NULL, + 0, + 0, + DUPLICATE_CLOSE_SOURCE + ))) + { + PhRemoveListViewItem(PhFindObjectsListViewHandle, + PhFindListViewItemByParam(PhFindObjectsListViewHandle, 0, results[i])); + } + + NtClose(processHandle); + } + + if (!NT_SUCCESS(status)) + { + if (!PhShowContinueStatus(hwndDlg, + PhaFormatString(L"Unable to close \"%s\"", results[i]->Name->Buffer)->Buffer, + status, + 0 + )) + break; + } + } + } + + PhFree(results); + } + break; + case ID_HANDLE_OBJECTPROPERTIES1: + case ID_HANDLE_OBJECTPROPERTIES2: + { + PPHP_OBJECT_SEARCH_RESULT result = + PhGetSelectedListViewItemParam(PhFindObjectsListViewHandle); + + if (result) + { + PH_HANDLE_ITEM_INFO info; + + info.ProcessId = result->ProcessId; + info.Handle = result->Handle; + info.TypeName = result->TypeName; + info.BestObjectName = result->Name; + + if (LOWORD(wParam) == ID_HANDLE_OBJECTPROPERTIES1) + PhShowHandleObjectProperties1(hwndDlg, &info); + else + PhShowHandleObjectProperties2(hwndDlg, &info); + } + } + break; + case ID_OBJECT_GOTOOWNINGPROCESS: + { + PPHP_OBJECT_SEARCH_RESULT result = + PhGetSelectedListViewItemParam(PhFindObjectsListViewHandle); + + if (result) + { + PPH_PROCESS_NODE processNode; + + if (processNode = PhFindProcessNode(result->ProcessId)) + { + ProcessHacker_SelectTabPage(PhMainWndHandle, 0); + ProcessHacker_SelectProcessNode(PhMainWndHandle, processNode); + ProcessHacker_ToggleVisible(PhMainWndHandle, TRUE); + } + } + } + break; + case ID_OBJECT_PROPERTIES: + { + PPHP_OBJECT_SEARCH_RESULT result = + PhGetSelectedListViewItemParam(PhFindObjectsListViewHandle); + + if (result) + { + if (result->ResultType == HandleSearchResult) + { + PPH_HANDLE_ITEM handleItem; + + handleItem = PhCreateHandleItem(&result->Info); + + handleItem->BestObjectName = handleItem->ObjectName = result->Name; + PhReferenceObjectEx(result->Name, 2); + + handleItem->TypeName = result->TypeName; + PhReferenceObject(result->TypeName); + + PhShowHandleProperties( + hwndDlg, + result->ProcessId, + handleItem + ); + PhDereferenceObject(handleItem); + } + else + { + // DLL or Mapped File. Just show file properties. + PhShellProperties(hwndDlg, result->Name->Buffer); + } + } + } + break; + case ID_OBJECT_COPY: + { + PhCopyListView(PhFindObjectsListViewHandle); + } + break; + } + } + break; + case WM_NOTIFY: + { + LPNMHDR header = (LPNMHDR)lParam; + + switch (header->code) + { + case NM_DBLCLK: + { + if (header->hwndFrom == PhFindObjectsListViewHandle) + { + SendMessage(hwndDlg, WM_COMMAND, ID_OBJECT_PROPERTIES, 0); + } + } + break; + case LVN_KEYDOWN: + { + if (header->hwndFrom == PhFindObjectsListViewHandle) + { + LPNMLVKEYDOWN keyDown = (LPNMLVKEYDOWN)header; + + switch (keyDown->wVKey) + { + case 'C': + if (GetKeyState(VK_CONTROL) < 0) + SendMessage(hwndDlg, WM_COMMAND, ID_OBJECT_COPY, 0); + break; + case 'A': + if (GetKeyState(VK_CONTROL) < 0) + PhSetStateAllListViewItems(PhFindObjectsListViewHandle, LVIS_SELECTED, LVIS_SELECTED); + break; + case VK_DELETE: + SendMessage(hwndDlg, WM_COMMAND, ID_OBJECT_CLOSE, 0); + break; + } + } + } + break; + } + } + break; + case WM_CONTEXTMENU: + { + if ((HWND)wParam == PhFindObjectsListViewHandle) + { + POINT point; + PPHP_OBJECT_SEARCH_RESULT *results; + ULONG numberOfResults; + + point.x = (SHORT)LOWORD(lParam); + point.y = (SHORT)HIWORD(lParam); + + if (point.x == -1 && point.y == -1) + PhGetListViewContextMenuPoint((HWND)wParam, &point); + + PhGetSelectedListViewItemParams(PhFindObjectsListViewHandle, &results, &numberOfResults); + + if (numberOfResults != 0) + { + PPH_EMENU menu; + + menu = PhCreateEMenu(); + PhLoadResourceEMenuItem(menu, PhInstanceHandle, MAKEINTRESOURCE(IDR_FINDOBJ), 0); + PhSetFlagsEMenuItem(menu, ID_OBJECT_PROPERTIES, PH_EMENU_DEFAULT, PH_EMENU_DEFAULT); + + PhpInitializeFindObjMenu(menu, results, numberOfResults); + PhShowEMenu( + menu, + hwndDlg, + PH_EMENU_SHOW_SEND_COMMAND | PH_EMENU_SHOW_LEFTRIGHT, + PH_ALIGN_LEFT | PH_ALIGN_TOP, + point.x, + point.y + ); + PhDestroyEMenu(menu); + } + + PhFree(results); + } + } + break; + case WM_SIZE: + { + PhLayoutManagerLayout(&WindowLayoutManager); + } + break; + case WM_SIZING: + { + PhResizingMinimumSize((PRECT)lParam, wParam, MinimumSize.right, MinimumSize.bottom); + } + break; + case WM_PH_SEARCH_UPDATE: + { + HWND lvHandle; + ULONG i; + + lvHandle = GetDlgItem(hwndDlg, IDC_RESULTS); + + ExtendedListView_SetRedraw(lvHandle, FALSE); + + PhAcquireQueuedLockExclusive(&SearchResultsLock); + + for (i = SearchResultsAddIndex; i < SearchResults->Count; i++) + { + PPHP_OBJECT_SEARCH_RESULT searchResult = SearchResults->Items[i]; + CLIENT_ID clientId; + PPH_PROCESS_ITEM processItem; + PPH_STRING clientIdName; + INT lvItemIndex; + + clientId.UniqueProcess = searchResult->ProcessId; + clientId.UniqueThread = NULL; + + processItem = PhReferenceProcessItem(clientId.UniqueProcess); + clientIdName = PhGetClientIdNameEx(&clientId, processItem ? processItem->ProcessName : NULL); + + lvItemIndex = PhAddListViewItem( + lvHandle, + MAXINT, + clientIdName->Buffer, + searchResult + ); + + PhDereferenceObject(clientIdName); + + if (processItem) + { + PhSetReference(&searchResult->ProcessName, processItem->ProcessName); + PhDereferenceObject(processItem); + } + else + { + searchResult->ProcessName = NULL; + } + + PhSetListViewSubItem(lvHandle, lvItemIndex, 1, searchResult->TypeName->Buffer); + PhSetListViewSubItem(lvHandle, lvItemIndex, 2, searchResult->Name->Buffer); + PhSetListViewSubItem(lvHandle, lvItemIndex, 3, searchResult->HandleString); + } + + SearchResultsAddIndex = i; + + PhReleaseQueuedLockExclusive(&SearchResultsLock); + + ExtendedListView_SetRedraw(lvHandle, TRUE); + } + break; + case WM_PH_SEARCH_FINISHED: + { + NTSTATUS handleSearchStatus = (NTSTATUS)wParam; + + // Add any un-added items. + SendMessage(hwndDlg, WM_PH_SEARCH_UPDATE, 0, 0); + + NtWaitForSingleObject(SearchThreadHandle, FALSE, NULL); + NtClose(SearchThreadHandle); + SearchThreadHandle = NULL; + SearchStop = FALSE; + + ExtendedListView_SortItems(GetDlgItem(hwndDlg, IDC_RESULTS)); + + SetDlgItemText(hwndDlg, IDOK, L"Find"); + EnableWindow(GetDlgItem(hwndDlg, IDOK), TRUE); + + SetCursor(LoadCursor(NULL, IDC_ARROW)); + + if (handleSearchStatus == STATUS_INSUFFICIENT_RESOURCES) + { + PhShowWarning( + hwndDlg, + L"Unable to search for handles because the total number of handles on the system is too large. " + L"Please check if there are any processes with an extremely large number of handles open." + ); + } + } + break; + } + + return FALSE; +} + +static BOOLEAN MatchSearchString( + _In_ PPH_STRINGREF Input + ) +{ + if (SearchRegexCompiledExpression && SearchRegexMatchData) + { + return pcre2_match( + SearchRegexCompiledExpression, + Input->Buffer, + Input->Length / sizeof(WCHAR), + 0, + 0, + SearchRegexMatchData, + NULL + ) >= 0; + } + else + { + return PhFindStringInStringRef(Input, &SearchString->sr, TRUE) != -1; + } +} + +typedef struct _SEARCH_HANDLE_CONTEXT +{ + BOOLEAN NeedToFree; + PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX HandleInfo; + HANDLE ProcessHandle; +} SEARCH_HANDLE_CONTEXT, *PSEARCH_HANDLE_CONTEXT; + +static NTSTATUS NTAPI SearchHandleFunction( + _In_ PVOID Parameter + ) +{ + PSEARCH_HANDLE_CONTEXT context = Parameter; + PPH_STRING typeName; + PPH_STRING bestObjectName; + + if (!SearchStop && NT_SUCCESS(PhGetHandleInformation( + context->ProcessHandle, + (HANDLE)context->HandleInfo->HandleValue, + context->HandleInfo->ObjectTypeIndex, + NULL, + &typeName, + NULL, + &bestObjectName + ))) + { + PPH_STRING upperBestObjectName; + + upperBestObjectName = PhDuplicateString(bestObjectName); + _wcsupr(upperBestObjectName->Buffer); + + if (MatchSearchString(&upperBestObjectName->sr) || + (UseSearchPointer && context->HandleInfo->Object == (PVOID)SearchPointer)) + { + PPHP_OBJECT_SEARCH_RESULT searchResult; + + searchResult = PhAllocate(sizeof(PHP_OBJECT_SEARCH_RESULT)); + searchResult->ProcessId = (HANDLE)context->HandleInfo->UniqueProcessId; + searchResult->ResultType = HandleSearchResult; + searchResult->Handle = (HANDLE)context->HandleInfo->HandleValue; + searchResult->TypeName = typeName; + searchResult->Name = bestObjectName; + PhPrintPointer(searchResult->HandleString, (PVOID)searchResult->Handle); + searchResult->Info = *context->HandleInfo; + + PhAcquireQueuedLockExclusive(&SearchResultsLock); + + PhAddItemList(SearchResults, searchResult); + + // Update the search results in batches of 40. + if (SearchResults->Count % 40 == 0) + PostMessage(PhFindObjectsWindowHandle, WM_PH_SEARCH_UPDATE, 0, 0); + + PhReleaseQueuedLockExclusive(&SearchResultsLock); + } + else + { + PhDereferenceObject(typeName); + PhDereferenceObject(bestObjectName); + } + + PhDereferenceObject(upperBestObjectName); + } + + if (context->NeedToFree) + PhFree(context); + + return STATUS_SUCCESS; +} + +static BOOLEAN NTAPI EnumModulesCallback( + _In_ PPH_MODULE_INFO Module, + _In_opt_ PVOID Context + ) +{ + PPH_STRING upperFileName; + + upperFileName = PhDuplicateString(Module->FileName); + _wcsupr(upperFileName->Buffer); + + if (MatchSearchString(&upperFileName->sr) || + (UseSearchPointer && Module->BaseAddress == (PVOID)SearchPointer)) + { + PPHP_OBJECT_SEARCH_RESULT searchResult; + PWSTR typeName; + + switch (Module->Type) + { + case PH_MODULE_TYPE_MAPPED_FILE: + typeName = L"Mapped file"; + break; + case PH_MODULE_TYPE_MAPPED_IMAGE: + typeName = L"Mapped image"; + break; + default: + typeName = L"DLL"; + break; + } + + searchResult = PhAllocate(sizeof(PHP_OBJECT_SEARCH_RESULT)); + searchResult->ProcessId = (HANDLE)Context; + searchResult->ResultType = (Module->Type == PH_MODULE_TYPE_MAPPED_FILE || Module->Type == PH_MODULE_TYPE_MAPPED_IMAGE) ? MappedFileSearchResult : ModuleSearchResult; + searchResult->Handle = (HANDLE)Module->BaseAddress; + searchResult->TypeName = PhCreateString(typeName); + PhSetReference(&searchResult->Name, Module->FileName); + PhPrintPointer(searchResult->HandleString, Module->BaseAddress); + memset(&searchResult->Info, 0, sizeof(SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX)); + + PhAcquireQueuedLockExclusive(&SearchResultsLock); + + PhAddItemList(SearchResults, searchResult); + + // Update the search results in batches of 40. + if (SearchResults->Count % 40 == 0) + PostMessage(PhFindObjectsWindowHandle, WM_PH_SEARCH_UPDATE, 0, 0); + + PhReleaseQueuedLockExclusive(&SearchResultsLock); + } + + PhDereferenceObject(upperFileName); + + return TRUE; +} + +static NTSTATUS PhpFindObjectsThreadStart( + _In_ PVOID Parameter + ) +{ + NTSTATUS status = STATUS_SUCCESS; + PSYSTEM_HANDLE_INFORMATION_EX handles; + PPH_HASHTABLE processHandleHashtable; + PVOID processes; + PSYSTEM_PROCESS_INFORMATION process; + ULONG i; + + // Refuse to search with no filter. + if (SearchString->Length == 0) + goto Exit; + + // Try to get a search pointer from the search string. + UseSearchPointer = PhStringToInteger64(&SearchString->sr, 0, &SearchPointer); + + _wcsupr(SearchString->Buffer); + + if (NT_SUCCESS(status = PhEnumHandlesEx(&handles))) + { + static PH_INITONCE initOnce = PH_INITONCE_INIT; + static ULONG fileObjectTypeIndex = -1; + + BOOLEAN useWorkQueue = FALSE; + PH_WORK_QUEUE workQueue; + processHandleHashtable = PhCreateSimpleHashtable(8); + + if (!KphIsConnected() && WindowsVersion >= WINDOWS_VISTA) + { + useWorkQueue = TRUE; + PhInitializeWorkQueue(&workQueue, 1, 20, 1000); + + if (PhBeginInitOnce(&initOnce)) + { + UNICODE_STRING fileTypeName; + + RtlInitUnicodeString(&fileTypeName, L"File"); + fileObjectTypeIndex = PhGetObjectTypeNumber(&fileTypeName); + PhEndInitOnce(&initOnce); + } + } + + for (i = 0; i < handles->NumberOfHandles; i++) + { + PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX handleInfo = &handles->Handles[i]; + PVOID *processHandlePtr; + HANDLE processHandle; + + if (SearchStop) + break; + + // Open a handle to the process if we don't already have one. + + processHandlePtr = PhFindItemSimpleHashtable( + processHandleHashtable, + (PVOID)handleInfo->UniqueProcessId + ); + + if (processHandlePtr) + { + processHandle = (HANDLE)*processHandlePtr; + } + else + { + if (NT_SUCCESS(PhOpenProcess( + &processHandle, + PROCESS_DUP_HANDLE, + (HANDLE)handleInfo->UniqueProcessId + ))) + { + PhAddItemSimpleHashtable( + processHandleHashtable, + (PVOID)handleInfo->UniqueProcessId, + processHandle + ); + } + else + { + continue; + } + } + + if (useWorkQueue && handleInfo->ObjectTypeIndex == (USHORT)fileObjectTypeIndex) + { + PSEARCH_HANDLE_CONTEXT searchHandleContext; + + searchHandleContext = PhAllocate(sizeof(SEARCH_HANDLE_CONTEXT)); + searchHandleContext->NeedToFree = TRUE; + searchHandleContext->HandleInfo = handleInfo; + searchHandleContext->ProcessHandle = processHandle; + PhQueueItemWorkQueue(&workQueue, SearchHandleFunction, searchHandleContext); + } + else + { + SEARCH_HANDLE_CONTEXT searchHandleContext; + + searchHandleContext.NeedToFree = FALSE; + searchHandleContext.HandleInfo = handleInfo; + searchHandleContext.ProcessHandle = processHandle; + SearchHandleFunction(&searchHandleContext); + } + } + + if (useWorkQueue) + { + PhWaitForWorkQueue(&workQueue); + PhDeleteWorkQueue(&workQueue); + } + + { + PPH_KEY_VALUE_PAIR entry; + + i = 0; + + while (PhEnumHashtable(processHandleHashtable, &entry, &i)) + NtClose((HANDLE)entry->Value); + } + + PhDereferenceObject(processHandleHashtable); + PhFree(handles); + } + + if (NT_SUCCESS(PhEnumProcesses(&processes))) + { + process = PH_FIRST_PROCESS(processes); + + do + { + PhEnumGenericModules( + process->UniqueProcessId, + NULL, + PH_ENUM_GENERIC_MAPPED_FILES | PH_ENUM_GENERIC_MAPPED_IMAGES, + EnumModulesCallback, + (PVOID)process->UniqueProcessId + ); + } while (process = PH_NEXT_PROCESS(process)); + + PhFree(processes); + } + +Exit: + PostMessage(PhFindObjectsWindowHandle, WM_PH_SEARCH_FINISHED, status, 0); + + return STATUS_SUCCESS; +} diff --git a/ProcessHacker/gdihndl.c b/ProcessHacker/gdihndl.c index 69184df2e480..c8d192d049a0 100644 --- a/ProcessHacker/gdihndl.c +++ b/ProcessHacker/gdihndl.c @@ -1,382 +1,382 @@ -/* - * Process Hacker - - * GDI handles dialog - * - * Copyright (C) 2010 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include - -#include - -#include - -typedef struct _GDI_HANDLES_CONTEXT -{ - PPH_PROCESS_ITEM ProcessItem; - PPH_LIST List; -} GDI_HANDLES_CONTEXT, *PGDI_HANDLES_CONTEXT; - -typedef struct _PH_GDI_HANDLE_ITEM -{ - PGDI_HANDLE_ENTRY Entry; - ULONG Handle; - PVOID Object; - PWSTR TypeName; - PPH_STRING Information; -} PH_GDI_HANDLE_ITEM, *PPH_GDI_HANDLE_ITEM; - -INT_PTR CALLBACK PhpGdiHandlesDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -VOID PhShowGdiHandlesDialog( - _In_ HWND ParentWindowHandle, - _In_ PPH_PROCESS_ITEM ProcessItem - ) -{ - GDI_HANDLES_CONTEXT context; - ULONG i; - - context.ProcessItem = ProcessItem; - context.List = PhCreateList(20); - - DialogBoxParam( - PhInstanceHandle, - MAKEINTRESOURCE(IDD_GDIHANDLES), - ParentWindowHandle, - PhpGdiHandlesDlgProc, - (LPARAM)&context - ); - - for (i = 0; i < context.List->Count; i++) - { - PPH_GDI_HANDLE_ITEM gdiHandleItem = context.List->Items[i]; - - if (gdiHandleItem->Information) - PhDereferenceObject(gdiHandleItem->Information); - - PhFree(context.List->Items[i]); - } - - PhDereferenceObject(context.List); -} - -PWSTR PhpGetGdiHandleTypeName( - _In_ ULONG Unique - ) -{ - switch (GDI_CLIENT_TYPE_FROM_UNIQUE(Unique)) - { - case GDI_CLIENT_ALTDC_TYPE: - return L"Alt. DC"; - case GDI_CLIENT_BITMAP_TYPE: - return L"Bitmap"; - case GDI_CLIENT_BRUSH_TYPE: - return L"Brush"; - case GDI_CLIENT_CLIENTOBJ_TYPE: - return L"Client Object"; - case GDI_CLIENT_DIBSECTION_TYPE: - return L"DIB Section"; - case GDI_CLIENT_DC_TYPE: - return L"DC"; - case GDI_CLIENT_EXTPEN_TYPE: - return L"ExtPen"; - case GDI_CLIENT_FONT_TYPE: - return L"Font"; - case GDI_CLIENT_METADC16_TYPE: - return L"Metafile DC"; - case GDI_CLIENT_METAFILE_TYPE: - return L"Enhanced Metafile"; - case GDI_CLIENT_METAFILE16_TYPE: - return L"Metafile"; - case GDI_CLIENT_PALETTE_TYPE: - return L"Palette"; - case GDI_CLIENT_PEN_TYPE: - return L"Pen"; - case GDI_CLIENT_REGION_TYPE: - return L"Region"; - default: - return NULL; - } -} - -PPH_STRING PhpGetGdiHandleInformation( - _In_ ULONG Handle - ) -{ - HGDIOBJ handle; - - handle = (HGDIOBJ)UlongToPtr(Handle); - - switch (GDI_CLIENT_TYPE_FROM_HANDLE(Handle)) - { - case GDI_CLIENT_BITMAP_TYPE: - case GDI_CLIENT_DIBSECTION_TYPE: - { - BITMAP bitmap; - - if (GetObject(handle, sizeof(BITMAP), &bitmap)) - { - return PhFormatString( - L"Width: %u, Height: %u, Depth: %u", - bitmap.bmWidth, - bitmap.bmHeight, - bitmap.bmBitsPixel - ); - } - } - break; - case GDI_CLIENT_BRUSH_TYPE: - { - LOGBRUSH brush; - - if (GetObject(handle, sizeof(LOGBRUSH), &brush)) - { - return PhFormatString( - L"Style: %u, Color: 0x%08x, Hatch: 0x%Ix", - brush.lbStyle, - _byteswap_ulong(brush.lbColor), - brush.lbHatch - ); - } - } - break; - case GDI_CLIENT_EXTPEN_TYPE: - { - EXTLOGPEN pen; - - if (GetObject(handle, sizeof(EXTLOGPEN), &pen)) - { - return PhFormatString( - L"Style: 0x%x, Width: %u, Color: 0x%08x", - pen.elpPenStyle, - pen.elpWidth, - _byteswap_ulong(pen.elpColor) - ); - } - } - break; - case GDI_CLIENT_FONT_TYPE: - { - LOGFONT font; - - if (GetObject(handle, sizeof(LOGFONT), &font)) - { - return PhFormatString( - L"Face: %s, Height: %d", - font.lfFaceName, - font.lfHeight - ); - } - } - break; - case GDI_CLIENT_PALETTE_TYPE: - { - USHORT count; - - if (GetObject(handle, sizeof(USHORT), &count)) - { - return PhFormatString( - L"Entries: %u", - (ULONG)count - ); - } - } - break; - case GDI_CLIENT_PEN_TYPE: - { - LOGPEN pen; - - if (GetObject(handle, sizeof(LOGPEN), &pen)) - { - return PhFormatString( - L"Style: %u, Width: %u, Color: 0x%08x", - pen.lopnStyle, - pen.lopnWidth.x, - _byteswap_ulong(pen.lopnColor) - ); - } - } - break; - } - - return NULL; -} - -VOID PhpRefreshGdiHandles( - _In_ HWND hwndDlg, - _In_ PGDI_HANDLES_CONTEXT Context - ) -{ - HWND lvHandle; - ULONG i; - PGDI_SHARED_MEMORY gdiShared; - USHORT processId; - PGDI_HANDLE_ENTRY handle; - PPH_GDI_HANDLE_ITEM gdiHandleItem; - - lvHandle = GetDlgItem(hwndDlg, IDC_LIST); - - ExtendedListView_SetRedraw(lvHandle, FALSE); - ListView_DeleteAllItems(lvHandle); - - for (i = 0; i < Context->List->Count; i++) - { - gdiHandleItem = Context->List->Items[i]; - - if (gdiHandleItem->Information) - PhDereferenceObject(gdiHandleItem->Information); - - PhFree(Context->List->Items[i]); - } - - PhClearList(Context->List); - - gdiShared = (PGDI_SHARED_MEMORY)NtCurrentPeb()->GdiSharedHandleTable; - processId = (USHORT)Context->ProcessItem->ProcessId; - - for (i = 0; i < GDI_MAX_HANDLE_COUNT; i++) - { - PWSTR typeName; - INT lvItemIndex; - WCHAR pointer[PH_PTR_STR_LEN_1]; - - handle = &gdiShared->Handles[i]; - - if (handle->Owner.ProcessId != processId) - continue; - - typeName = PhpGetGdiHandleTypeName(handle->Unique); - - if (!typeName) - continue; - - gdiHandleItem = PhAllocate(sizeof(PH_GDI_HANDLE_ITEM)); - gdiHandleItem->Entry = handle; - gdiHandleItem->Handle = GDI_MAKE_HANDLE(i, handle->Unique); - gdiHandleItem->Object = handle->Object; - gdiHandleItem->TypeName = typeName; - gdiHandleItem->Information = PhpGetGdiHandleInformation(gdiHandleItem->Handle); - PhAddItemList(Context->List, gdiHandleItem); - - lvItemIndex = PhAddListViewItem(lvHandle, MAXINT, gdiHandleItem->TypeName, gdiHandleItem); - PhPrintPointer(pointer, UlongToPtr(gdiHandleItem->Handle)); - PhSetListViewSubItem(lvHandle, lvItemIndex, 1, pointer); - PhPrintPointer(pointer, gdiHandleItem->Object); - PhSetListViewSubItem(lvHandle, lvItemIndex, 2, pointer); - PhSetListViewSubItem(lvHandle, lvItemIndex, 3, PhGetString(gdiHandleItem->Information)); - } - - ExtendedListView_SortItems(lvHandle); - ExtendedListView_SetRedraw(lvHandle, TRUE); -} - -INT NTAPI PhpGdiHandleHandleCompareFunction( - _In_ PVOID Item1, - _In_ PVOID Item2, - _In_opt_ PVOID Context - ) -{ - PPH_GDI_HANDLE_ITEM item1 = Item1; - PPH_GDI_HANDLE_ITEM item2 = Item2; - - return uintcmp(item1->Handle, item2->Handle); -} - -INT NTAPI PhpGdiHandleObjectCompareFunction( - _In_ PVOID Item1, - _In_ PVOID Item2, - _In_opt_ PVOID Context - ) -{ - PPH_GDI_HANDLE_ITEM item1 = Item1; - PPH_GDI_HANDLE_ITEM item2 = Item2; - - return uintptrcmp((ULONG_PTR)item1->Object, (ULONG_PTR)item2->Object); -} - -INT_PTR CALLBACK PhpGdiHandlesDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - switch (uMsg) - { - case WM_INITDIALOG: - { - PGDI_HANDLES_CONTEXT context = (PGDI_HANDLES_CONTEXT)lParam; - HWND lvHandle; - - PhCenterWindow(hwndDlg, GetParent(hwndDlg)); - - SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)context); - - lvHandle = GetDlgItem(hwndDlg, IDC_LIST); - - PhSetListViewStyle(lvHandle, FALSE, TRUE); - PhSetControlTheme(lvHandle, L"explorer"); - PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 100, L"Type"); - PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 80, L"Handle"); - PhAddListViewColumn(lvHandle, 2, 2, 2, LVCFMT_LEFT, 102, L"Object"); - PhAddListViewColumn(lvHandle, 3, 3, 3, LVCFMT_LEFT, 200, L"Information"); - - PhSetExtendedListView(lvHandle); - ExtendedListView_SetCompareFunction(lvHandle, 1, PhpGdiHandleHandleCompareFunction); - ExtendedListView_SetCompareFunction(lvHandle, 2, PhpGdiHandleObjectCompareFunction); - ExtendedListView_AddFallbackColumn(lvHandle, 0); - ExtendedListView_AddFallbackColumn(lvHandle, 1); - - PhpRefreshGdiHandles(hwndDlg, context); - } - break; - case WM_DESTROY: - { - RemoveProp(hwndDlg, PhMakeContextAtom()); - } - break; - case WM_COMMAND: - { - switch (LOWORD(wParam)) - { - case IDCANCEL: - case IDOK: - EndDialog(hwndDlg, IDOK); - break; - case IDC_REFRESH: - { - PhpRefreshGdiHandles(hwndDlg, (PGDI_HANDLES_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom())); - } - break; - } - } - break; - case WM_NOTIFY: - { - PhHandleListViewNotifyForCopy(lParam, GetDlgItem(hwndDlg, IDC_LIST)); - } - break; - } - - return FALSE; -} +/* + * Process Hacker - + * GDI handles dialog + * + * Copyright (C) 2010 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include + +#include + +#include + +typedef struct _GDI_HANDLES_CONTEXT +{ + PPH_PROCESS_ITEM ProcessItem; + PPH_LIST List; +} GDI_HANDLES_CONTEXT, *PGDI_HANDLES_CONTEXT; + +typedef struct _PH_GDI_HANDLE_ITEM +{ + PGDI_HANDLE_ENTRY Entry; + ULONG Handle; + PVOID Object; + PWSTR TypeName; + PPH_STRING Information; +} PH_GDI_HANDLE_ITEM, *PPH_GDI_HANDLE_ITEM; + +INT_PTR CALLBACK PhpGdiHandlesDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +VOID PhShowGdiHandlesDialog( + _In_ HWND ParentWindowHandle, + _In_ PPH_PROCESS_ITEM ProcessItem + ) +{ + GDI_HANDLES_CONTEXT context; + ULONG i; + + context.ProcessItem = ProcessItem; + context.List = PhCreateList(20); + + DialogBoxParam( + PhInstanceHandle, + MAKEINTRESOURCE(IDD_GDIHANDLES), + ParentWindowHandle, + PhpGdiHandlesDlgProc, + (LPARAM)&context + ); + + for (i = 0; i < context.List->Count; i++) + { + PPH_GDI_HANDLE_ITEM gdiHandleItem = context.List->Items[i]; + + if (gdiHandleItem->Information) + PhDereferenceObject(gdiHandleItem->Information); + + PhFree(context.List->Items[i]); + } + + PhDereferenceObject(context.List); +} + +PWSTR PhpGetGdiHandleTypeName( + _In_ ULONG Unique + ) +{ + switch (GDI_CLIENT_TYPE_FROM_UNIQUE(Unique)) + { + case GDI_CLIENT_ALTDC_TYPE: + return L"Alt. DC"; + case GDI_CLIENT_BITMAP_TYPE: + return L"Bitmap"; + case GDI_CLIENT_BRUSH_TYPE: + return L"Brush"; + case GDI_CLIENT_CLIENTOBJ_TYPE: + return L"Client Object"; + case GDI_CLIENT_DIBSECTION_TYPE: + return L"DIB Section"; + case GDI_CLIENT_DC_TYPE: + return L"DC"; + case GDI_CLIENT_EXTPEN_TYPE: + return L"ExtPen"; + case GDI_CLIENT_FONT_TYPE: + return L"Font"; + case GDI_CLIENT_METADC16_TYPE: + return L"Metafile DC"; + case GDI_CLIENT_METAFILE_TYPE: + return L"Enhanced Metafile"; + case GDI_CLIENT_METAFILE16_TYPE: + return L"Metafile"; + case GDI_CLIENT_PALETTE_TYPE: + return L"Palette"; + case GDI_CLIENT_PEN_TYPE: + return L"Pen"; + case GDI_CLIENT_REGION_TYPE: + return L"Region"; + default: + return NULL; + } +} + +PPH_STRING PhpGetGdiHandleInformation( + _In_ ULONG Handle + ) +{ + HGDIOBJ handle; + + handle = (HGDIOBJ)UlongToPtr(Handle); + + switch (GDI_CLIENT_TYPE_FROM_HANDLE(Handle)) + { + case GDI_CLIENT_BITMAP_TYPE: + case GDI_CLIENT_DIBSECTION_TYPE: + { + BITMAP bitmap; + + if (GetObject(handle, sizeof(BITMAP), &bitmap)) + { + return PhFormatString( + L"Width: %u, Height: %u, Depth: %u", + bitmap.bmWidth, + bitmap.bmHeight, + bitmap.bmBitsPixel + ); + } + } + break; + case GDI_CLIENT_BRUSH_TYPE: + { + LOGBRUSH brush; + + if (GetObject(handle, sizeof(LOGBRUSH), &brush)) + { + return PhFormatString( + L"Style: %u, Color: 0x%08x, Hatch: 0x%Ix", + brush.lbStyle, + _byteswap_ulong(brush.lbColor), + brush.lbHatch + ); + } + } + break; + case GDI_CLIENT_EXTPEN_TYPE: + { + EXTLOGPEN pen; + + if (GetObject(handle, sizeof(EXTLOGPEN), &pen)) + { + return PhFormatString( + L"Style: 0x%x, Width: %u, Color: 0x%08x", + pen.elpPenStyle, + pen.elpWidth, + _byteswap_ulong(pen.elpColor) + ); + } + } + break; + case GDI_CLIENT_FONT_TYPE: + { + LOGFONT font; + + if (GetObject(handle, sizeof(LOGFONT), &font)) + { + return PhFormatString( + L"Face: %s, Height: %d", + font.lfFaceName, + font.lfHeight + ); + } + } + break; + case GDI_CLIENT_PALETTE_TYPE: + { + USHORT count; + + if (GetObject(handle, sizeof(USHORT), &count)) + { + return PhFormatString( + L"Entries: %u", + (ULONG)count + ); + } + } + break; + case GDI_CLIENT_PEN_TYPE: + { + LOGPEN pen; + + if (GetObject(handle, sizeof(LOGPEN), &pen)) + { + return PhFormatString( + L"Style: %u, Width: %u, Color: 0x%08x", + pen.lopnStyle, + pen.lopnWidth.x, + _byteswap_ulong(pen.lopnColor) + ); + } + } + break; + } + + return NULL; +} + +VOID PhpRefreshGdiHandles( + _In_ HWND hwndDlg, + _In_ PGDI_HANDLES_CONTEXT Context + ) +{ + HWND lvHandle; + ULONG i; + PGDI_SHARED_MEMORY gdiShared; + USHORT processId; + PGDI_HANDLE_ENTRY handle; + PPH_GDI_HANDLE_ITEM gdiHandleItem; + + lvHandle = GetDlgItem(hwndDlg, IDC_LIST); + + ExtendedListView_SetRedraw(lvHandle, FALSE); + ListView_DeleteAllItems(lvHandle); + + for (i = 0; i < Context->List->Count; i++) + { + gdiHandleItem = Context->List->Items[i]; + + if (gdiHandleItem->Information) + PhDereferenceObject(gdiHandleItem->Information); + + PhFree(Context->List->Items[i]); + } + + PhClearList(Context->List); + + gdiShared = (PGDI_SHARED_MEMORY)NtCurrentPeb()->GdiSharedHandleTable; + processId = (USHORT)Context->ProcessItem->ProcessId; + + for (i = 0; i < GDI_MAX_HANDLE_COUNT; i++) + { + PWSTR typeName; + INT lvItemIndex; + WCHAR pointer[PH_PTR_STR_LEN_1]; + + handle = &gdiShared->Handles[i]; + + if (handle->Owner.ProcessId != processId) + continue; + + typeName = PhpGetGdiHandleTypeName(handle->Unique); + + if (!typeName) + continue; + + gdiHandleItem = PhAllocate(sizeof(PH_GDI_HANDLE_ITEM)); + gdiHandleItem->Entry = handle; + gdiHandleItem->Handle = GDI_MAKE_HANDLE(i, handle->Unique); + gdiHandleItem->Object = handle->Object; + gdiHandleItem->TypeName = typeName; + gdiHandleItem->Information = PhpGetGdiHandleInformation(gdiHandleItem->Handle); + PhAddItemList(Context->List, gdiHandleItem); + + lvItemIndex = PhAddListViewItem(lvHandle, MAXINT, gdiHandleItem->TypeName, gdiHandleItem); + PhPrintPointer(pointer, UlongToPtr(gdiHandleItem->Handle)); + PhSetListViewSubItem(lvHandle, lvItemIndex, 1, pointer); + PhPrintPointer(pointer, gdiHandleItem->Object); + PhSetListViewSubItem(lvHandle, lvItemIndex, 2, pointer); + PhSetListViewSubItem(lvHandle, lvItemIndex, 3, PhGetString(gdiHandleItem->Information)); + } + + ExtendedListView_SortItems(lvHandle); + ExtendedListView_SetRedraw(lvHandle, TRUE); +} + +INT NTAPI PhpGdiHandleHandleCompareFunction( + _In_ PVOID Item1, + _In_ PVOID Item2, + _In_opt_ PVOID Context + ) +{ + PPH_GDI_HANDLE_ITEM item1 = Item1; + PPH_GDI_HANDLE_ITEM item2 = Item2; + + return uintcmp(item1->Handle, item2->Handle); +} + +INT NTAPI PhpGdiHandleObjectCompareFunction( + _In_ PVOID Item1, + _In_ PVOID Item2, + _In_opt_ PVOID Context + ) +{ + PPH_GDI_HANDLE_ITEM item1 = Item1; + PPH_GDI_HANDLE_ITEM item2 = Item2; + + return uintptrcmp((ULONG_PTR)item1->Object, (ULONG_PTR)item2->Object); +} + +INT_PTR CALLBACK PhpGdiHandlesDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + switch (uMsg) + { + case WM_INITDIALOG: + { + PGDI_HANDLES_CONTEXT context = (PGDI_HANDLES_CONTEXT)lParam; + HWND lvHandle; + + PhCenterWindow(hwndDlg, GetParent(hwndDlg)); + + SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)context); + + lvHandle = GetDlgItem(hwndDlg, IDC_LIST); + + PhSetListViewStyle(lvHandle, FALSE, TRUE); + PhSetControlTheme(lvHandle, L"explorer"); + PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 100, L"Type"); + PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 80, L"Handle"); + PhAddListViewColumn(lvHandle, 2, 2, 2, LVCFMT_LEFT, 102, L"Object"); + PhAddListViewColumn(lvHandle, 3, 3, 3, LVCFMT_LEFT, 200, L"Information"); + + PhSetExtendedListView(lvHandle); + ExtendedListView_SetCompareFunction(lvHandle, 1, PhpGdiHandleHandleCompareFunction); + ExtendedListView_SetCompareFunction(lvHandle, 2, PhpGdiHandleObjectCompareFunction); + ExtendedListView_AddFallbackColumn(lvHandle, 0); + ExtendedListView_AddFallbackColumn(lvHandle, 1); + + PhpRefreshGdiHandles(hwndDlg, context); + } + break; + case WM_DESTROY: + { + RemoveProp(hwndDlg, PhMakeContextAtom()); + } + break; + case WM_COMMAND: + { + switch (LOWORD(wParam)) + { + case IDCANCEL: + case IDOK: + EndDialog(hwndDlg, IDOK); + break; + case IDC_REFRESH: + { + PhpRefreshGdiHandles(hwndDlg, (PGDI_HANDLES_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom())); + } + break; + } + } + break; + case WM_NOTIFY: + { + PhHandleListViewNotifyForCopy(lParam, GetDlgItem(hwndDlg, IDC_LIST)); + } + break; + } + + return FALSE; +} diff --git a/ProcessHacker/hidnproc.c b/ProcessHacker/hidnproc.c index f28d5d5e260d..926b16cb00eb 100644 --- a/ProcessHacker/hidnproc.c +++ b/ProcessHacker/hidnproc.c @@ -1,1249 +1,1249 @@ -/* - * Process Hacker - - * hidden processes detection - * - * Copyright (C) 2010-2013 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -/* - * There are two methods of hidden process detection implemented in this module. - * - * Brute Force. This attempts to open all possible PIDs within a certain range - * in order to find processes which have been unlinked from the active process - * list (EPROCESS.ActiveProcessLinks). This method is not effective when - * either NtOpenProcess is hooked or PsLookupProcessByProcessId is hooked - * (KProcessHacker cannot bypass this). - * - * CSR Handles. This enumerates handles in all running CSR processes, and works - * even when a process has been unlinked from the active process list and - * has been removed from the client ID table (PspCidTable). However, the method - * does not detect native executables since CSR is not notified about them. - * Some rootkits hook NtQuerySystemInformation in order to modify the returned - * handle information; Process Hacker bypasses this by using KProcessHacker, - * which calls ExEnumHandleTable directly. Note that both process and thread - * handles are examined. - */ - -#include -#include - -#include -#include - -#include - -#include -#include -#include - -INT_PTR CALLBACK PhpHiddenProcessesDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -COLORREF NTAPI PhpHiddenProcessesColorFunction( - _In_ INT Index, - _In_ PVOID Param, - _In_opt_ PVOID Context - ); - -BOOLEAN NTAPI PhpHiddenProcessesCallback( - _In_ PPH_HIDDEN_PROCESS_ENTRY Process, - _In_opt_ PVOID Context - ); - -PPH_PROCESS_ITEM PhpCreateProcessItemForHiddenProcess( - _In_ PPH_HIDDEN_PROCESS_ENTRY Entry - ); - -HWND PhHiddenProcessesWindowHandle = NULL; -HWND PhHiddenProcessesListViewHandle = NULL; -static PH_LAYOUT_MANAGER WindowLayoutManager; -static RECT MinimumSize; - -static PH_HIDDEN_PROCESS_METHOD ProcessesMethod; -static PPH_LIST ProcessesList = NULL; -static ULONG NumberOfHiddenProcesses; -static ULONG NumberOfTerminatedProcesses; - -VOID PhShowHiddenProcessesDialog( - VOID - ) -{ - if (!KphIsConnected()) - { - PhShowWarning( - PhMainWndHandle, - L"Hidden process detection cannot function properly without KProcessHacker. " - L"Make sure Process Hacker is running with administrative privileges." - ); - } - - if (!PhHiddenProcessesWindowHandle) - { - PhHiddenProcessesWindowHandle = CreateDialog( - PhInstanceHandle, - MAKEINTRESOURCE(IDD_HIDDENPROCESSES), - PhMainWndHandle, - PhpHiddenProcessesDlgProc - ); - } - - if (!IsWindowVisible(PhHiddenProcessesWindowHandle)) - ShowWindow(PhHiddenProcessesWindowHandle, SW_SHOW); - else - SetForegroundWindow(PhHiddenProcessesWindowHandle); -} - -static INT_PTR CALLBACK PhpHiddenProcessesDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - switch (uMsg) - { - case WM_INITDIALOG: - { - HWND lvHandle; - - PhCenterWindow(hwndDlg, GetParent(hwndDlg)); - PhHiddenProcessesListViewHandle = lvHandle = GetDlgItem(hwndDlg, IDC_PROCESSES); - - PhInitializeLayoutManager(&WindowLayoutManager, hwndDlg); - PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDC_INTRO), - NULL, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT | PH_LAYOUT_FORCE_INVALIDATE); - PhAddLayoutItem(&WindowLayoutManager, lvHandle, - NULL, PH_ANCHOR_ALL); - PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDC_DESCRIPTION), - NULL, PH_ANCHOR_LEFT | PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM | PH_LAYOUT_FORCE_INVALIDATE); - PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDC_METHOD), - NULL, PH_ANCHOR_LEFT | PH_ANCHOR_BOTTOM); - PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDC_TERMINATE), - NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); - PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDC_SAVE), - NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); - PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDC_SCAN), - NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); - PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDOK), - NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); - - MinimumSize.left = 0; - MinimumSize.top = 0; - MinimumSize.right = 330; - MinimumSize.bottom = 140; - MapDialogRect(hwndDlg, &MinimumSize); - - PhRegisterDialog(hwndDlg); - - PhLoadWindowPlacementFromSetting(L"HiddenProcessesWindowPosition", L"HiddenProcessesWindowSize", hwndDlg); - - PhSetListViewStyle(lvHandle, TRUE, TRUE); - PhSetControlTheme(lvHandle, L"explorer"); - PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 320, L"Process"); - PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 60, L"PID"); - - PhSetExtendedListView(lvHandle); - PhLoadListViewColumnsFromSetting(L"HiddenProcessesListViewColumns", lvHandle); - ExtendedListView_AddFallbackColumn(lvHandle, 0); - ExtendedListView_AddFallbackColumn(lvHandle, 1); - ExtendedListView_SetItemColorFunction(lvHandle, PhpHiddenProcessesColorFunction); - - ComboBox_AddString(GetDlgItem(hwndDlg, IDC_METHOD), L"Brute force"); - ComboBox_AddString(GetDlgItem(hwndDlg, IDC_METHOD), L"CSR handles"); - PhSelectComboBoxString(GetDlgItem(hwndDlg, IDC_METHOD), L"CSR handles", FALSE); - - EnableWindow(GetDlgItem(hwndDlg, IDC_TERMINATE), FALSE); - } - break; - case WM_DESTROY: - { - PhSaveWindowPlacementToSetting(L"HiddenProcessesWindowPosition", L"HiddenProcessesWindowSize", hwndDlg); - PhSaveListViewColumnsToSetting(L"HiddenProcessesListViewColumns", PhHiddenProcessesListViewHandle); - } - break; - case WM_CLOSE: - { - // Hide, don't close. - ShowWindow(hwndDlg, SW_HIDE); - SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, 0); - } - return TRUE; - case WM_COMMAND: - { - switch (LOWORD(wParam)) - { - case IDCANCEL: - case IDOK: - { - SendMessage(hwndDlg, WM_CLOSE, 0, 0); - } - break; - case IDC_SCAN: - { - NTSTATUS status; - PPH_STRING method; - - method = PH_AUTO(PhGetWindowText(GetDlgItem(hwndDlg, IDC_METHOD))); - - if (ProcessesList) - { - ULONG i; - - for (i = 0; i < ProcessesList->Count; i++) - { - PPH_HIDDEN_PROCESS_ENTRY entry = ProcessesList->Items[i]; - - if (entry->FileName) - PhDereferenceObject(entry->FileName); - - PhFree(entry); - } - - PhDereferenceObject(ProcessesList); - } - - ProcessesList = PhCreateList(40); - - ProcessesMethod = - PhEqualString2(method, L"Brute force", TRUE) ? - BruteForceScanMethod : - CsrHandlesScanMethod; - NumberOfHiddenProcesses = 0; - NumberOfTerminatedProcesses = 0; - - ExtendedListView_SetRedraw(PhHiddenProcessesListViewHandle, FALSE); - ListView_DeleteAllItems(PhHiddenProcessesListViewHandle); - status = PhEnumHiddenProcesses( - ProcessesMethod, - PhpHiddenProcessesCallback, - NULL - ); - ExtendedListView_SortItems(PhHiddenProcessesListViewHandle); - ExtendedListView_SetRedraw(PhHiddenProcessesListViewHandle, TRUE); - - if (NT_SUCCESS(status)) - { - SetDlgItemText(hwndDlg, IDC_DESCRIPTION, - PhaFormatString(L"%u hidden process(es), %u terminated process(es).", - NumberOfHiddenProcesses, NumberOfTerminatedProcesses)->Buffer - ); - InvalidateRect(GetDlgItem(hwndDlg, IDC_DESCRIPTION), NULL, TRUE); - } - else - { - PhShowStatus(hwndDlg, L"Unable to perform the scan", status, 0); - } - } - break; - case IDC_TERMINATE: - { - PPH_HIDDEN_PROCESS_ENTRY *entries; - ULONG numberOfEntries; - ULONG i; - - PhGetSelectedListViewItemParams(PhHiddenProcessesListViewHandle, &entries, &numberOfEntries); - - if (numberOfEntries != 0) - { - if (!PhGetIntegerSetting(L"EnableWarnings") || - PhShowConfirmMessage( - hwndDlg, - L"terminate", - L"the selected process(es)", - L"Terminating a hidden process may cause the system to become unstable " - L"or crash.", - TRUE - )) - { - NTSTATUS status; - HANDLE processHandle; - BOOLEAN refresh; - - refresh = FALSE; - - for (i = 0; i < numberOfEntries; i++) - { - if (ProcessesMethod == BruteForceScanMethod) - { - status = PhOpenProcess( - &processHandle, - PROCESS_TERMINATE, - entries[i]->ProcessId - ); - } - else - { - status = PhOpenProcessByCsrHandles( - &processHandle, - PROCESS_TERMINATE, - entries[i]->ProcessId - ); - } - - if (NT_SUCCESS(status)) - { - status = PhTerminateProcess(processHandle, STATUS_SUCCESS); - NtClose(processHandle); - - if (NT_SUCCESS(status)) - refresh = TRUE; - } - else - { - PhShowStatus(hwndDlg, L"Unable to terminate the process", status, 0); - } - } - - if (refresh) - { - LARGE_INTEGER interval; - - // Sleep for a bit before continuing. It seems to help avoid - // BSODs. - interval.QuadPart = -250 * PH_TIMEOUT_MS; - NtDelayExecution(FALSE, &interval); - SendMessage(hwndDlg, WM_COMMAND, IDC_SCAN, 0); - } - } - } - - PhFree(entries); - } - break; - case IDC_SAVE: - { - static PH_FILETYPE_FILTER filters[] = - { - { L"Text files (*.txt)", L"*.txt" }, - { L"All files (*.*)", L"*.*" } - }; - PVOID fileDialog; - - fileDialog = PhCreateSaveFileDialog(); - - PhSetFileDialogFilter(fileDialog, filters, sizeof(filters) / sizeof(PH_FILETYPE_FILTER)); - PhSetFileDialogFileName(fileDialog, L"Hidden Processes.txt"); - - if (PhShowFileDialog(hwndDlg, fileDialog)) - { - NTSTATUS status; - PPH_STRING fileName; - PPH_FILE_STREAM fileStream; - - fileName = PH_AUTO(PhGetFileDialogFileName(fileDialog)); - - if (NT_SUCCESS(status = PhCreateFileStream( - &fileStream, - fileName->Buffer, - FILE_GENERIC_WRITE, - FILE_SHARE_READ, - FILE_OVERWRITE_IF, - 0 - ))) - { - PhWriteStringAsUtf8FileStream(fileStream, &PhUnicodeByteOrderMark); - PhWritePhTextHeader(fileStream); - PhWriteStringAsUtf8FileStream2(fileStream, L"Method: "); - PhWriteStringAsUtf8FileStream2(fileStream, - ProcessesMethod == BruteForceScanMethod ? L"Brute Force\r\n" : L"CSR Handles\r\n"); - PhWriteStringFormatAsUtf8FileStream( - fileStream, - L"Hidden: %u\r\nTerminated: %u\r\n\r\n", - NumberOfHiddenProcesses, - NumberOfTerminatedProcesses - ); - - if (ProcessesList) - { - ULONG i; - - for (i = 0; i < ProcessesList->Count; i++) - { - PPH_HIDDEN_PROCESS_ENTRY entry = ProcessesList->Items[i]; - - if (entry->Type == HiddenProcess) - PhWriteStringAsUtf8FileStream2(fileStream, L"[HIDDEN] "); - else if (entry->Type == TerminatedProcess) - PhWriteStringAsUtf8FileStream2(fileStream, L"[Terminated] "); - else if (entry->Type != NormalProcess) - continue; - - PhWriteStringFormatAsUtf8FileStream( - fileStream, - L"%s (%u)\r\n", - entry->FileName->Buffer, - HandleToUlong(entry->ProcessId) - ); - } - } - - PhDereferenceObject(fileStream); - } - - if (!NT_SUCCESS(status)) - PhShowStatus(hwndDlg, L"Unable to create the file", status, 0); - } - - PhFreeFileDialog(fileDialog); - } - break; - } - } - break; - case WM_NOTIFY: - { - LPNMHDR header = (LPNMHDR)lParam; - - PhHandleListViewNotifyBehaviors(lParam, PhHiddenProcessesListViewHandle, PH_LIST_VIEW_DEFAULT_1_BEHAVIORS); - - switch (header->code) - { - case LVN_ITEMCHANGED: - { - if (header->hwndFrom == PhHiddenProcessesListViewHandle) - { - EnableWindow( - GetDlgItem(hwndDlg, IDC_TERMINATE), - ListView_GetSelectedCount(PhHiddenProcessesListViewHandle) > 0 - ); - } - } - break; - case NM_DBLCLK: - { - if (header->hwndFrom == PhHiddenProcessesListViewHandle) - { - PPH_HIDDEN_PROCESS_ENTRY entry; - - entry = PhGetSelectedListViewItemParam(PhHiddenProcessesListViewHandle); - - if (entry) - { - PPH_PROCESS_ITEM processItem; - - if (processItem = PhpCreateProcessItemForHiddenProcess(entry)) - { - ProcessHacker_ShowProcessProperties(PhMainWndHandle, processItem); - PhDereferenceObject(processItem); - } - else - { - PhShowError(hwndDlg, L"Unable to create a process structure for the selected process."); - } - } - } - } - break; - } - } - break; - case WM_SIZE: - { - PhLayoutManagerLayout(&WindowLayoutManager); - } - break; - case WM_SIZING: - { - PhResizingMinimumSize((PRECT)lParam, wParam, MinimumSize.right, MinimumSize.bottom); - } - break; - case WM_CTLCOLORSTATIC: - { - if ((HWND)lParam == GetDlgItem(hwndDlg, IDC_DESCRIPTION)) - { - if (NumberOfHiddenProcesses != 0) - { - SetTextColor((HDC)wParam, RGB(0xff, 0x00, 0x00)); - } - - SetBkColor((HDC)wParam, GetSysColor(COLOR_3DFACE)); - - return (INT_PTR)GetSysColorBrush(COLOR_3DFACE); - } - } - break; - } - - REFLECT_MESSAGE_DLG(hwndDlg, PhHiddenProcessesListViewHandle, uMsg, wParam, lParam); - - return FALSE; -} - -static COLORREF NTAPI PhpHiddenProcessesColorFunction( - _In_ INT Index, - _In_ PVOID Param, - _In_opt_ PVOID Context - ) -{ - PPH_HIDDEN_PROCESS_ENTRY entry = Param; - - switch (entry->Type) - { - case UnknownProcess: - case HiddenProcess: - return RGB(0xff, 0x00, 0x00); - case TerminatedProcess: - return RGB(0x77, 0x77, 0x77); - } - - return GetSysColor(COLOR_WINDOW); -} - -static BOOLEAN NTAPI PhpHiddenProcessesCallback( - _In_ PPH_HIDDEN_PROCESS_ENTRY Process, - _In_opt_ PVOID Context - ) -{ - PPH_HIDDEN_PROCESS_ENTRY entry; - INT lvItemIndex; - WCHAR pidString[PH_INT32_STR_LEN_1]; - - entry = PhAllocateCopy(Process, sizeof(PH_HIDDEN_PROCESS_ENTRY)); - - if (entry->FileName) - PhReferenceObject(entry->FileName); - - PhAddItemList(ProcessesList, entry); - - lvItemIndex = PhAddListViewItem(PhHiddenProcessesListViewHandle, MAXINT, - PhGetStringOrDefault(entry->FileName, L"(unknown)"), entry); - PhPrintUInt32(pidString, HandleToUlong(entry->ProcessId)); - PhSetListViewSubItem(PhHiddenProcessesListViewHandle, lvItemIndex, 1, pidString); - - if (entry->Type == HiddenProcess) - NumberOfHiddenProcesses++; - else if (entry->Type == TerminatedProcess) - NumberOfTerminatedProcesses++; - - return TRUE; -} - -static PPH_PROCESS_ITEM PhpCreateProcessItemForHiddenProcess( - _In_ PPH_HIDDEN_PROCESS_ENTRY Entry - ) -{ - NTSTATUS status; - PPH_PROCESS_ITEM processItem; - PPH_PROCESS_ITEM idleProcessItem; - HANDLE processHandle; - PROCESS_BASIC_INFORMATION basicInfo; - KERNEL_USER_TIMES times; - PROCESS_PRIORITY_CLASS priorityClass; - ULONG handleCount; - HANDLE processHandle2; - - if (Entry->Type == NormalProcess) - { - processItem = PhReferenceProcessItem(Entry->ProcessId); - - if (processItem) - return processItem; - } - - processItem = PhCreateProcessItem(Entry->ProcessId); - - // Mark the process as terminated if necessary. - if (Entry->Type == TerminatedProcess) - processItem->State |= PH_PROCESS_ITEM_REMOVED; - - // We need a process record. Just use the record of System Idle Process. - if (idleProcessItem = PhReferenceProcessItem(SYSTEM_IDLE_PROCESS_ID)) - { - processItem->Record = idleProcessItem->Record; - PhReferenceProcessRecord(processItem->Record); - } - else - { - PhDereferenceObject(processItem); - return NULL; - } - - // Set up the file name and process name. - - PhSwapReference(&processItem->FileName, Entry->FileName); - - if (processItem->FileName) - { - processItem->ProcessName = PhGetBaseName(processItem->FileName); - } - else - { - processItem->ProcessName = PhCreateString(L"Unknown"); - } - - if (ProcessesMethod == BruteForceScanMethod) - { - status = PhOpenProcess( - &processHandle, - ProcessQueryAccess, - Entry->ProcessId - ); - } - else - { - status = PhOpenProcessByCsrHandles( - &processHandle, - ProcessQueryAccess, - Entry->ProcessId - ); - } - - if (NT_SUCCESS(status)) - { - // Basic information and not-so-dynamic information - - processItem->QueryHandle = processHandle; - - if (NT_SUCCESS(PhGetProcessBasicInformation(processHandle, &basicInfo))) - { - processItem->ParentProcessId = basicInfo.InheritedFromUniqueProcessId; - processItem->BasePriority = basicInfo.BasePriority; - } - - PhGetProcessSessionId(processHandle, &processItem->SessionId); - - PhPrintUInt32(processItem->ParentProcessIdString, HandleToUlong(processItem->ParentProcessId)); - PhPrintUInt32(processItem->SessionIdString, processItem->SessionId); - - if (NT_SUCCESS(PhGetProcessTimes(processHandle, ×))) - { - processItem->CreateTime = times.CreateTime; - processItem->KernelTime = times.KernelTime; - processItem->UserTime = times.UserTime; - } - - // TODO: Token information? - - if (NT_SUCCESS(NtQueryInformationProcess( - processHandle, - ProcessPriorityClass, - &priorityClass, - sizeof(PROCESS_PRIORITY_CLASS), - NULL - ))) - { - processItem->PriorityClass = priorityClass.PriorityClass; - } - - if (NT_SUCCESS(NtQueryInformationProcess( - processHandle, - ProcessHandleCount, - &handleCount, - sizeof(ULONG), - NULL - ))) - { - processItem->NumberOfHandles = handleCount; - } - } - - // Stage 1 - // Some copy and paste magic here... - - if (processItem->FileName) - { - // Small icon, large icon. - ExtractIconEx( - processItem->FileName->Buffer, - 0, - &processItem->LargeIcon, - &processItem->SmallIcon, - 1 - ); - - // Version info. - PhInitializeImageVersionInfo(&processItem->VersionInfo, processItem->FileName->Buffer); - } - - // Use the default EXE icon if we didn't get the file's icon. - { - if (!processItem->SmallIcon || !processItem->LargeIcon) - { - if (processItem->SmallIcon) - { - DestroyIcon(processItem->SmallIcon); - processItem->SmallIcon = NULL; - } - else if (processItem->LargeIcon) - { - DestroyIcon(processItem->LargeIcon); - processItem->LargeIcon = NULL; - } - - PhGetStockApplicationIcon(&processItem->SmallIcon, &processItem->LargeIcon); - processItem->SmallIcon = CopyIcon(processItem->SmallIcon); - processItem->LargeIcon = CopyIcon(processItem->LargeIcon); - } - } - - // Command line - - status = PhOpenProcess( - &processHandle2, - ProcessQueryAccess | PROCESS_VM_READ, - Entry->ProcessId - ); - - if (NT_SUCCESS(status)) - { - PPH_STRING commandLine; - ULONG i; - - if (NT_SUCCESS(status = PhGetProcessCommandLine(processHandle2, &commandLine))) - { - // Some command lines (e.g. from taskeng.exe) have nulls in them. - // Since Windows can't display them, we'll replace them with - // spaces. - for (i = 0; i < (ULONG)commandLine->Length / 2; i++) - { - if (commandLine->Buffer[i] == 0) - commandLine->Buffer[i] = ' '; - } - } - - if (NT_SUCCESS(status)) - { - processItem->CommandLine = commandLine; - } - - NtClose(processHandle2); - } - - // TODO: Other stage 1 tasks. - - PhSetEvent(&processItem->Stage1Event); - - return processItem; -} - -NTSTATUS PhpEnumHiddenProcessesBruteForce( - _In_ PPH_ENUM_HIDDEN_PROCESSES_CALLBACK Callback, - _In_opt_ PVOID Context - ) -{ - NTSTATUS status; - PVOID processes; - PSYSTEM_PROCESS_INFORMATION process; - PPH_LIST pids; - ULONG pid; - BOOLEAN stop = FALSE; - - if (!NT_SUCCESS(status = PhEnumProcesses(&processes))) - return status; - - pids = PhCreateList(40); - - process = PH_FIRST_PROCESS(processes); - - do - { - PhAddItemList(pids, process->UniqueProcessId); - } while (process = PH_NEXT_PROCESS(process)); - - PhFree(processes); - - for (pid = 8; pid <= 65536; pid += 4) - { - NTSTATUS status2; - HANDLE processHandle; - PH_HIDDEN_PROCESS_ENTRY entry; - KERNEL_USER_TIMES times; - PPH_STRING fileName; - - status2 = PhOpenProcess( - &processHandle, - ProcessQueryAccess, - UlongToHandle(pid) - ); - - if (NT_SUCCESS(status2)) - { - entry.ProcessId = UlongToHandle(pid); - - if (NT_SUCCESS(status2 = PhGetProcessTimes( - processHandle, - × - )) && - NT_SUCCESS(status2 = PhGetProcessImageFileName( - processHandle, - &fileName - ))) - { - entry.FileName = PhGetFileName(fileName); - PhDereferenceObject(fileName); - - if (times.ExitTime.QuadPart != 0) - entry.Type = TerminatedProcess; - else if (PhFindItemList(pids, UlongToHandle(pid)) != -1) - entry.Type = NormalProcess; - else - entry.Type = HiddenProcess; - - if (!Callback(&entry, Context)) - stop = TRUE; - - PhDereferenceObject(entry.FileName); - } - - NtClose(processHandle); - } - - // Use an alternative method if we don't have sufficient access. - if (status2 == STATUS_ACCESS_DENIED && WindowsVersion >= WINDOWS_VISTA) - { - if (NT_SUCCESS(status2 = PhGetProcessImageFileNameByProcessId(UlongToHandle(pid), &fileName))) - { - entry.ProcessId = UlongToHandle(pid); - entry.FileName = PhGetFileName(fileName); - PhDereferenceObject(fileName); - - if (PhFindItemList(pids, UlongToHandle(pid)) != -1) - entry.Type = NormalProcess; - else - entry.Type = HiddenProcess; - - if (!Callback(&entry, Context)) - stop = TRUE; - - PhDereferenceObject(entry.FileName); - } - } - - if (status2 == STATUS_INVALID_CID || status2 == STATUS_INVALID_PARAMETER) - status2 = STATUS_SUCCESS; - - if (!NT_SUCCESS(status2)) - { - entry.ProcessId = UlongToHandle(pid); - entry.FileName = NULL; - entry.Type = UnknownProcess; - - if (!Callback(&entry, Context)) - stop = TRUE; - } - - if (stop) - break; - } - - PhDereferenceObject(pids); - - return status; -} - -typedef struct _CSR_HANDLES_CONTEXT -{ - PPH_ENUM_HIDDEN_PROCESSES_CALLBACK Callback; - PVOID Context; - PPH_LIST Pids; -} CSR_HANDLES_CONTEXT, *PCSR_HANDLES_CONTEXT; - -static BOOLEAN NTAPI PhpCsrProcessHandlesCallback( - _In_ PPH_CSR_HANDLE_INFO Handle, - _In_opt_ PVOID Context - ) -{ - NTSTATUS status; - BOOLEAN cont = TRUE; - PCSR_HANDLES_CONTEXT context = Context; - HANDLE processHandle; - KERNEL_USER_TIMES times; - PPH_STRING fileName; - PH_HIDDEN_PROCESS_ENTRY entry; - - entry.ProcessId = Handle->ProcessId; - - if (NT_SUCCESS(status = PhOpenProcessByCsrHandle( - &processHandle, - ProcessQueryAccess, - Handle - ))) - { - if (NT_SUCCESS(status = PhGetProcessTimes( - processHandle, - × - )) && - NT_SUCCESS(status = PhGetProcessImageFileName( - processHandle, - &fileName - ))) - { - entry.FileName = PhGetFileName(fileName); - PhDereferenceObject(fileName); - - if (times.ExitTime.QuadPart != 0) - entry.Type = TerminatedProcess; - else if (PhFindItemList(context->Pids, Handle->ProcessId) != -1) - entry.Type = NormalProcess; - else - entry.Type = HiddenProcess; - - if (!context->Callback(&entry, context->Context)) - cont = FALSE; - - PhDereferenceObject(entry.FileName); - } - - NtClose(processHandle); - } - - if (!NT_SUCCESS(status)) - { - entry.FileName = NULL; - entry.Type = UnknownProcess; - - if (!context->Callback(&entry, context->Context)) - cont = FALSE; - } - - return cont; -} - -NTSTATUS PhpEnumHiddenProcessesCsrHandles( - _In_ PPH_ENUM_HIDDEN_PROCESSES_CALLBACK Callback, - _In_opt_ PVOID Context - ) -{ - NTSTATUS status; - PVOID processes; - PSYSTEM_PROCESS_INFORMATION process; - PPH_LIST pids; - CSR_HANDLES_CONTEXT context; - - if (!NT_SUCCESS(status = PhEnumProcesses(&processes))) - return status; - - pids = PhCreateList(40); - - process = PH_FIRST_PROCESS(processes); - - do - { - PhAddItemList(pids, process->UniqueProcessId); - } while (process = PH_NEXT_PROCESS(process)); - - PhFree(processes); - - context.Callback = Callback; - context.Context = Context; - context.Pids = pids; - - status = PhEnumCsrProcessHandles(PhpCsrProcessHandlesCallback, &context); - - PhDereferenceObject(pids); - - return status; -} - -NTSTATUS PhEnumHiddenProcesses( - _In_ PH_HIDDEN_PROCESS_METHOD Method, - _In_ PPH_ENUM_HIDDEN_PROCESSES_CALLBACK Callback, - _In_opt_ PVOID Context - ) -{ - if (Method == BruteForceScanMethod) - { - return PhpEnumHiddenProcessesBruteForce( - Callback, - Context - ); - } - else - { - return PhpEnumHiddenProcessesCsrHandles( - Callback, - Context - ); - } -} - -NTSTATUS PhpOpenCsrProcesses( - _Out_ PHANDLE *ProcessHandles, - _Out_ PULONG NumberOfProcessHandles - ) -{ - NTSTATUS status; - PVOID processes; - PSYSTEM_PROCESS_INFORMATION process; - PPH_LIST processHandleList; - - if (!NT_SUCCESS(status = PhEnumProcesses(&processes))) - return status; - - processHandleList = PhCreateList(8); - - process = PH_FIRST_PROCESS(processes); - - do - { - HANDLE processHandle; - PH_KNOWN_PROCESS_TYPE knownProcessType; - - if (NT_SUCCESS(PhOpenProcess( - &processHandle, - ProcessQueryAccess | PROCESS_DUP_HANDLE, - process->UniqueProcessId - ))) - { - if (NT_SUCCESS(PhGetProcessKnownType( - processHandle, - &knownProcessType - )) && - (knownProcessType & KnownProcessTypeMask) == WindowsSubsystemProcessType) - { - PhAddItemList(processHandleList, processHandle); - } - else - { - NtClose(processHandle); - } - } - } while (process = PH_NEXT_PROCESS(process)); - - PhFree(processes); - - *ProcessHandles = PhAllocateCopy(processHandleList->Items, processHandleList->Count * sizeof(HANDLE)); - *NumberOfProcessHandles = processHandleList->Count; - - PhDereferenceObject(processHandleList); - - return status; -} - -NTSTATUS PhpGetCsrHandleProcessId( - _Inout_ PPH_CSR_HANDLE_INFO Handle - ) -{ - NTSTATUS status; - PROCESS_BASIC_INFORMATION processBasicInfo; - THREAD_BASIC_INFORMATION threadBasicInfo; - - Handle->IsThreadHandle = FALSE; - Handle->ProcessId = NULL; - - // Assume the handle is a process handle, and get the - // process ID. - - status = KphQueryInformationObject( - Handle->CsrProcessHandle, - Handle->Handle, - KphObjectProcessBasicInformation, - &processBasicInfo, - sizeof(PROCESS_BASIC_INFORMATION), - NULL - ); - - if (NT_SUCCESS(status)) - { - Handle->ProcessId = processBasicInfo.UniqueProcessId; - } - else - { - // We failed to get the process ID. Assume the handle - // is a thread handle, and get the process ID. - - status = KphQueryInformationObject( - Handle->CsrProcessHandle, - Handle->Handle, - KphObjectThreadBasicInformation, - &threadBasicInfo, - sizeof(THREAD_BASIC_INFORMATION), - NULL - ); - - if (NT_SUCCESS(status)) - { - Handle->ProcessId = threadBasicInfo.ClientId.UniqueProcess; - Handle->IsThreadHandle = TRUE; - } - } - - return status; -} - -NTSTATUS PhEnumCsrProcessHandles( - _In_ PPH_ENUM_CSR_PROCESS_HANDLES_CALLBACK Callback, - _In_opt_ PVOID Context - ) -{ - NTSTATUS status; - PHANDLE csrProcessHandles; - ULONG numberOfCsrProcessHandles; - ULONG i; - BOOLEAN stop = FALSE; - PPH_LIST pids; - - if (!NT_SUCCESS(status = PhpOpenCsrProcesses( - &csrProcessHandles, - &numberOfCsrProcessHandles - ))) - return status; - - pids = PhCreateList(40); - - for (i = 0; i < numberOfCsrProcessHandles; i++) - { - PKPH_PROCESS_HANDLE_INFORMATION handles; - ULONG j; - - if (stop) - break; - - if (NT_SUCCESS(KphEnumerateProcessHandles2(csrProcessHandles[i], &handles))) - { - for (j = 0; j < handles->HandleCount; j++) - { - PH_CSR_HANDLE_INFO handle; - - handle.CsrProcessHandle = csrProcessHandles[i]; - handle.Handle = handles->Handles[j].Handle; - - // Get the process ID associated with the handle. - // This call will fail if the handle is not a - // process or thread handle. - if (!NT_SUCCESS(PhpGetCsrHandleProcessId(&handle))) - continue; - - // Avoid duplicate PIDs. - if (PhFindItemList(pids, handle.ProcessId) != -1) - continue; - - PhAddItemList(pids, handle.ProcessId); - - if (!Callback(&handle, Context)) - { - stop = TRUE; - break; - } - } - - PhFree(handles); - } - } - - PhDereferenceObject(pids); - - for (i = 0; i < numberOfCsrProcessHandles; i++) - NtClose(csrProcessHandles[i]); - - PhFree(csrProcessHandles); - - return status; -} - -NTSTATUS PhOpenProcessByCsrHandle( - _Out_ PHANDLE ProcessHandle, - _In_ ACCESS_MASK DesiredAccess, - _In_ PPH_CSR_HANDLE_INFO Handle - ) -{ - NTSTATUS status; - - if (!Handle->IsThreadHandle) - { - status = NtDuplicateObject( - Handle->CsrProcessHandle, - Handle->Handle, - NtCurrentProcess(), - ProcessHandle, - DesiredAccess, - 0, - 0 - ); - } - else - { - HANDLE threadHandle; - - if (!NT_SUCCESS(status = NtDuplicateObject( - Handle->CsrProcessHandle, - Handle->Handle, - NtCurrentProcess(), - &threadHandle, - ThreadQueryAccess, - 0, - 0 - ))) - return status; - - status = KphOpenThreadProcess( - threadHandle, - DesiredAccess, - ProcessHandle - ); - NtClose(threadHandle); - } - - return status; -} - -typedef struct _OPEN_PROCESS_BY_CSR_CONTEXT -{ - NTSTATUS Status; - PHANDLE ProcessHandle; - ACCESS_MASK DesiredAccess; - HANDLE ProcessId; -} OPEN_PROCESS_BY_CSR_CONTEXT, *POPEN_PROCESS_BY_CSR_CONTEXT; - -static BOOLEAN NTAPI PhpOpenProcessByCsrHandlesCallback( - _In_ PPH_CSR_HANDLE_INFO Handle, - _In_opt_ PVOID Context - ) -{ - POPEN_PROCESS_BY_CSR_CONTEXT context = Context; - - if (Handle->ProcessId == context->ProcessId) - { - context->Status = PhOpenProcessByCsrHandle( - context->ProcessHandle, - context->DesiredAccess, - Handle - ); - - return FALSE; - } - - return TRUE; -} - -NTSTATUS PhOpenProcessByCsrHandles( - _Out_ PHANDLE ProcessHandle, - _In_ ACCESS_MASK DesiredAccess, - _In_ HANDLE ProcessId - ) -{ - NTSTATUS status; - OPEN_PROCESS_BY_CSR_CONTEXT context; - - context.Status = STATUS_INVALID_CID; - context.ProcessHandle = ProcessHandle; - context.DesiredAccess = DesiredAccess; - context.ProcessId = ProcessId; - - if (!NT_SUCCESS(status = PhEnumCsrProcessHandles( - PhpOpenProcessByCsrHandlesCallback, - &context - ))) - return status; - - return context.Status; -} +/* + * Process Hacker - + * hidden processes detection + * + * Copyright (C) 2010-2013 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +/* + * There are two methods of hidden process detection implemented in this module. + * + * Brute Force. This attempts to open all possible PIDs within a certain range + * in order to find processes which have been unlinked from the active process + * list (EPROCESS.ActiveProcessLinks). This method is not effective when + * either NtOpenProcess is hooked or PsLookupProcessByProcessId is hooked + * (KProcessHacker cannot bypass this). + * + * CSR Handles. This enumerates handles in all running CSR processes, and works + * even when a process has been unlinked from the active process list and + * has been removed from the client ID table (PspCidTable). However, the method + * does not detect native executables since CSR is not notified about them. + * Some rootkits hook NtQuerySystemInformation in order to modify the returned + * handle information; Process Hacker bypasses this by using KProcessHacker, + * which calls ExEnumHandleTable directly. Note that both process and thread + * handles are examined. + */ + +#include +#include + +#include +#include + +#include + +#include +#include +#include + +INT_PTR CALLBACK PhpHiddenProcessesDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +COLORREF NTAPI PhpHiddenProcessesColorFunction( + _In_ INT Index, + _In_ PVOID Param, + _In_opt_ PVOID Context + ); + +BOOLEAN NTAPI PhpHiddenProcessesCallback( + _In_ PPH_HIDDEN_PROCESS_ENTRY Process, + _In_opt_ PVOID Context + ); + +PPH_PROCESS_ITEM PhpCreateProcessItemForHiddenProcess( + _In_ PPH_HIDDEN_PROCESS_ENTRY Entry + ); + +HWND PhHiddenProcessesWindowHandle = NULL; +HWND PhHiddenProcessesListViewHandle = NULL; +static PH_LAYOUT_MANAGER WindowLayoutManager; +static RECT MinimumSize; + +static PH_HIDDEN_PROCESS_METHOD ProcessesMethod; +static PPH_LIST ProcessesList = NULL; +static ULONG NumberOfHiddenProcesses; +static ULONG NumberOfTerminatedProcesses; + +VOID PhShowHiddenProcessesDialog( + VOID + ) +{ + if (!KphIsConnected()) + { + PhShowWarning( + PhMainWndHandle, + L"Hidden process detection cannot function properly without KProcessHacker. " + L"Make sure Process Hacker is running with administrative privileges." + ); + } + + if (!PhHiddenProcessesWindowHandle) + { + PhHiddenProcessesWindowHandle = CreateDialog( + PhInstanceHandle, + MAKEINTRESOURCE(IDD_HIDDENPROCESSES), + PhMainWndHandle, + PhpHiddenProcessesDlgProc + ); + } + + if (!IsWindowVisible(PhHiddenProcessesWindowHandle)) + ShowWindow(PhHiddenProcessesWindowHandle, SW_SHOW); + else + SetForegroundWindow(PhHiddenProcessesWindowHandle); +} + +static INT_PTR CALLBACK PhpHiddenProcessesDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + switch (uMsg) + { + case WM_INITDIALOG: + { + HWND lvHandle; + + PhCenterWindow(hwndDlg, GetParent(hwndDlg)); + PhHiddenProcessesListViewHandle = lvHandle = GetDlgItem(hwndDlg, IDC_PROCESSES); + + PhInitializeLayoutManager(&WindowLayoutManager, hwndDlg); + PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDC_INTRO), + NULL, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT | PH_LAYOUT_FORCE_INVALIDATE); + PhAddLayoutItem(&WindowLayoutManager, lvHandle, + NULL, PH_ANCHOR_ALL); + PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDC_DESCRIPTION), + NULL, PH_ANCHOR_LEFT | PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM | PH_LAYOUT_FORCE_INVALIDATE); + PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDC_METHOD), + NULL, PH_ANCHOR_LEFT | PH_ANCHOR_BOTTOM); + PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDC_TERMINATE), + NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); + PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDC_SAVE), + NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); + PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDC_SCAN), + NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); + PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDOK), + NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); + + MinimumSize.left = 0; + MinimumSize.top = 0; + MinimumSize.right = 330; + MinimumSize.bottom = 140; + MapDialogRect(hwndDlg, &MinimumSize); + + PhRegisterDialog(hwndDlg); + + PhLoadWindowPlacementFromSetting(L"HiddenProcessesWindowPosition", L"HiddenProcessesWindowSize", hwndDlg); + + PhSetListViewStyle(lvHandle, TRUE, TRUE); + PhSetControlTheme(lvHandle, L"explorer"); + PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 320, L"Process"); + PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 60, L"PID"); + + PhSetExtendedListView(lvHandle); + PhLoadListViewColumnsFromSetting(L"HiddenProcessesListViewColumns", lvHandle); + ExtendedListView_AddFallbackColumn(lvHandle, 0); + ExtendedListView_AddFallbackColumn(lvHandle, 1); + ExtendedListView_SetItemColorFunction(lvHandle, PhpHiddenProcessesColorFunction); + + ComboBox_AddString(GetDlgItem(hwndDlg, IDC_METHOD), L"Brute force"); + ComboBox_AddString(GetDlgItem(hwndDlg, IDC_METHOD), L"CSR handles"); + PhSelectComboBoxString(GetDlgItem(hwndDlg, IDC_METHOD), L"CSR handles", FALSE); + + EnableWindow(GetDlgItem(hwndDlg, IDC_TERMINATE), FALSE); + } + break; + case WM_DESTROY: + { + PhSaveWindowPlacementToSetting(L"HiddenProcessesWindowPosition", L"HiddenProcessesWindowSize", hwndDlg); + PhSaveListViewColumnsToSetting(L"HiddenProcessesListViewColumns", PhHiddenProcessesListViewHandle); + } + break; + case WM_CLOSE: + { + // Hide, don't close. + ShowWindow(hwndDlg, SW_HIDE); + SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, 0); + } + return TRUE; + case WM_COMMAND: + { + switch (LOWORD(wParam)) + { + case IDCANCEL: + case IDOK: + { + SendMessage(hwndDlg, WM_CLOSE, 0, 0); + } + break; + case IDC_SCAN: + { + NTSTATUS status; + PPH_STRING method; + + method = PH_AUTO(PhGetWindowText(GetDlgItem(hwndDlg, IDC_METHOD))); + + if (ProcessesList) + { + ULONG i; + + for (i = 0; i < ProcessesList->Count; i++) + { + PPH_HIDDEN_PROCESS_ENTRY entry = ProcessesList->Items[i]; + + if (entry->FileName) + PhDereferenceObject(entry->FileName); + + PhFree(entry); + } + + PhDereferenceObject(ProcessesList); + } + + ProcessesList = PhCreateList(40); + + ProcessesMethod = + PhEqualString2(method, L"Brute force", TRUE) ? + BruteForceScanMethod : + CsrHandlesScanMethod; + NumberOfHiddenProcesses = 0; + NumberOfTerminatedProcesses = 0; + + ExtendedListView_SetRedraw(PhHiddenProcessesListViewHandle, FALSE); + ListView_DeleteAllItems(PhHiddenProcessesListViewHandle); + status = PhEnumHiddenProcesses( + ProcessesMethod, + PhpHiddenProcessesCallback, + NULL + ); + ExtendedListView_SortItems(PhHiddenProcessesListViewHandle); + ExtendedListView_SetRedraw(PhHiddenProcessesListViewHandle, TRUE); + + if (NT_SUCCESS(status)) + { + SetDlgItemText(hwndDlg, IDC_DESCRIPTION, + PhaFormatString(L"%u hidden process(es), %u terminated process(es).", + NumberOfHiddenProcesses, NumberOfTerminatedProcesses)->Buffer + ); + InvalidateRect(GetDlgItem(hwndDlg, IDC_DESCRIPTION), NULL, TRUE); + } + else + { + PhShowStatus(hwndDlg, L"Unable to perform the scan", status, 0); + } + } + break; + case IDC_TERMINATE: + { + PPH_HIDDEN_PROCESS_ENTRY *entries; + ULONG numberOfEntries; + ULONG i; + + PhGetSelectedListViewItemParams(PhHiddenProcessesListViewHandle, &entries, &numberOfEntries); + + if (numberOfEntries != 0) + { + if (!PhGetIntegerSetting(L"EnableWarnings") || + PhShowConfirmMessage( + hwndDlg, + L"terminate", + L"the selected process(es)", + L"Terminating a hidden process may cause the system to become unstable " + L"or crash.", + TRUE + )) + { + NTSTATUS status; + HANDLE processHandle; + BOOLEAN refresh; + + refresh = FALSE; + + for (i = 0; i < numberOfEntries; i++) + { + if (ProcessesMethod == BruteForceScanMethod) + { + status = PhOpenProcess( + &processHandle, + PROCESS_TERMINATE, + entries[i]->ProcessId + ); + } + else + { + status = PhOpenProcessByCsrHandles( + &processHandle, + PROCESS_TERMINATE, + entries[i]->ProcessId + ); + } + + if (NT_SUCCESS(status)) + { + status = PhTerminateProcess(processHandle, STATUS_SUCCESS); + NtClose(processHandle); + + if (NT_SUCCESS(status)) + refresh = TRUE; + } + else + { + PhShowStatus(hwndDlg, L"Unable to terminate the process", status, 0); + } + } + + if (refresh) + { + LARGE_INTEGER interval; + + // Sleep for a bit before continuing. It seems to help avoid + // BSODs. + interval.QuadPart = -250 * PH_TIMEOUT_MS; + NtDelayExecution(FALSE, &interval); + SendMessage(hwndDlg, WM_COMMAND, IDC_SCAN, 0); + } + } + } + + PhFree(entries); + } + break; + case IDC_SAVE: + { + static PH_FILETYPE_FILTER filters[] = + { + { L"Text files (*.txt)", L"*.txt" }, + { L"All files (*.*)", L"*.*" } + }; + PVOID fileDialog; + + fileDialog = PhCreateSaveFileDialog(); + + PhSetFileDialogFilter(fileDialog, filters, sizeof(filters) / sizeof(PH_FILETYPE_FILTER)); + PhSetFileDialogFileName(fileDialog, L"Hidden Processes.txt"); + + if (PhShowFileDialog(hwndDlg, fileDialog)) + { + NTSTATUS status; + PPH_STRING fileName; + PPH_FILE_STREAM fileStream; + + fileName = PH_AUTO(PhGetFileDialogFileName(fileDialog)); + + if (NT_SUCCESS(status = PhCreateFileStream( + &fileStream, + fileName->Buffer, + FILE_GENERIC_WRITE, + FILE_SHARE_READ, + FILE_OVERWRITE_IF, + 0 + ))) + { + PhWriteStringAsUtf8FileStream(fileStream, &PhUnicodeByteOrderMark); + PhWritePhTextHeader(fileStream); + PhWriteStringAsUtf8FileStream2(fileStream, L"Method: "); + PhWriteStringAsUtf8FileStream2(fileStream, + ProcessesMethod == BruteForceScanMethod ? L"Brute Force\r\n" : L"CSR Handles\r\n"); + PhWriteStringFormatAsUtf8FileStream( + fileStream, + L"Hidden: %u\r\nTerminated: %u\r\n\r\n", + NumberOfHiddenProcesses, + NumberOfTerminatedProcesses + ); + + if (ProcessesList) + { + ULONG i; + + for (i = 0; i < ProcessesList->Count; i++) + { + PPH_HIDDEN_PROCESS_ENTRY entry = ProcessesList->Items[i]; + + if (entry->Type == HiddenProcess) + PhWriteStringAsUtf8FileStream2(fileStream, L"[HIDDEN] "); + else if (entry->Type == TerminatedProcess) + PhWriteStringAsUtf8FileStream2(fileStream, L"[Terminated] "); + else if (entry->Type != NormalProcess) + continue; + + PhWriteStringFormatAsUtf8FileStream( + fileStream, + L"%s (%u)\r\n", + entry->FileName->Buffer, + HandleToUlong(entry->ProcessId) + ); + } + } + + PhDereferenceObject(fileStream); + } + + if (!NT_SUCCESS(status)) + PhShowStatus(hwndDlg, L"Unable to create the file", status, 0); + } + + PhFreeFileDialog(fileDialog); + } + break; + } + } + break; + case WM_NOTIFY: + { + LPNMHDR header = (LPNMHDR)lParam; + + PhHandleListViewNotifyBehaviors(lParam, PhHiddenProcessesListViewHandle, PH_LIST_VIEW_DEFAULT_1_BEHAVIORS); + + switch (header->code) + { + case LVN_ITEMCHANGED: + { + if (header->hwndFrom == PhHiddenProcessesListViewHandle) + { + EnableWindow( + GetDlgItem(hwndDlg, IDC_TERMINATE), + ListView_GetSelectedCount(PhHiddenProcessesListViewHandle) > 0 + ); + } + } + break; + case NM_DBLCLK: + { + if (header->hwndFrom == PhHiddenProcessesListViewHandle) + { + PPH_HIDDEN_PROCESS_ENTRY entry; + + entry = PhGetSelectedListViewItemParam(PhHiddenProcessesListViewHandle); + + if (entry) + { + PPH_PROCESS_ITEM processItem; + + if (processItem = PhpCreateProcessItemForHiddenProcess(entry)) + { + ProcessHacker_ShowProcessProperties(PhMainWndHandle, processItem); + PhDereferenceObject(processItem); + } + else + { + PhShowError(hwndDlg, L"Unable to create a process structure for the selected process."); + } + } + } + } + break; + } + } + break; + case WM_SIZE: + { + PhLayoutManagerLayout(&WindowLayoutManager); + } + break; + case WM_SIZING: + { + PhResizingMinimumSize((PRECT)lParam, wParam, MinimumSize.right, MinimumSize.bottom); + } + break; + case WM_CTLCOLORSTATIC: + { + if ((HWND)lParam == GetDlgItem(hwndDlg, IDC_DESCRIPTION)) + { + if (NumberOfHiddenProcesses != 0) + { + SetTextColor((HDC)wParam, RGB(0xff, 0x00, 0x00)); + } + + SetBkColor((HDC)wParam, GetSysColor(COLOR_3DFACE)); + + return (INT_PTR)GetSysColorBrush(COLOR_3DFACE); + } + } + break; + } + + REFLECT_MESSAGE_DLG(hwndDlg, PhHiddenProcessesListViewHandle, uMsg, wParam, lParam); + + return FALSE; +} + +static COLORREF NTAPI PhpHiddenProcessesColorFunction( + _In_ INT Index, + _In_ PVOID Param, + _In_opt_ PVOID Context + ) +{ + PPH_HIDDEN_PROCESS_ENTRY entry = Param; + + switch (entry->Type) + { + case UnknownProcess: + case HiddenProcess: + return RGB(0xff, 0x00, 0x00); + case TerminatedProcess: + return RGB(0x77, 0x77, 0x77); + } + + return GetSysColor(COLOR_WINDOW); +} + +static BOOLEAN NTAPI PhpHiddenProcessesCallback( + _In_ PPH_HIDDEN_PROCESS_ENTRY Process, + _In_opt_ PVOID Context + ) +{ + PPH_HIDDEN_PROCESS_ENTRY entry; + INT lvItemIndex; + WCHAR pidString[PH_INT32_STR_LEN_1]; + + entry = PhAllocateCopy(Process, sizeof(PH_HIDDEN_PROCESS_ENTRY)); + + if (entry->FileName) + PhReferenceObject(entry->FileName); + + PhAddItemList(ProcessesList, entry); + + lvItemIndex = PhAddListViewItem(PhHiddenProcessesListViewHandle, MAXINT, + PhGetStringOrDefault(entry->FileName, L"(unknown)"), entry); + PhPrintUInt32(pidString, HandleToUlong(entry->ProcessId)); + PhSetListViewSubItem(PhHiddenProcessesListViewHandle, lvItemIndex, 1, pidString); + + if (entry->Type == HiddenProcess) + NumberOfHiddenProcesses++; + else if (entry->Type == TerminatedProcess) + NumberOfTerminatedProcesses++; + + return TRUE; +} + +static PPH_PROCESS_ITEM PhpCreateProcessItemForHiddenProcess( + _In_ PPH_HIDDEN_PROCESS_ENTRY Entry + ) +{ + NTSTATUS status; + PPH_PROCESS_ITEM processItem; + PPH_PROCESS_ITEM idleProcessItem; + HANDLE processHandle; + PROCESS_BASIC_INFORMATION basicInfo; + KERNEL_USER_TIMES times; + PROCESS_PRIORITY_CLASS priorityClass; + ULONG handleCount; + HANDLE processHandle2; + + if (Entry->Type == NormalProcess) + { + processItem = PhReferenceProcessItem(Entry->ProcessId); + + if (processItem) + return processItem; + } + + processItem = PhCreateProcessItem(Entry->ProcessId); + + // Mark the process as terminated if necessary. + if (Entry->Type == TerminatedProcess) + processItem->State |= PH_PROCESS_ITEM_REMOVED; + + // We need a process record. Just use the record of System Idle Process. + if (idleProcessItem = PhReferenceProcessItem(SYSTEM_IDLE_PROCESS_ID)) + { + processItem->Record = idleProcessItem->Record; + PhReferenceProcessRecord(processItem->Record); + } + else + { + PhDereferenceObject(processItem); + return NULL; + } + + // Set up the file name and process name. + + PhSwapReference(&processItem->FileName, Entry->FileName); + + if (processItem->FileName) + { + processItem->ProcessName = PhGetBaseName(processItem->FileName); + } + else + { + processItem->ProcessName = PhCreateString(L"Unknown"); + } + + if (ProcessesMethod == BruteForceScanMethod) + { + status = PhOpenProcess( + &processHandle, + ProcessQueryAccess, + Entry->ProcessId + ); + } + else + { + status = PhOpenProcessByCsrHandles( + &processHandle, + ProcessQueryAccess, + Entry->ProcessId + ); + } + + if (NT_SUCCESS(status)) + { + // Basic information and not-so-dynamic information + + processItem->QueryHandle = processHandle; + + if (NT_SUCCESS(PhGetProcessBasicInformation(processHandle, &basicInfo))) + { + processItem->ParentProcessId = basicInfo.InheritedFromUniqueProcessId; + processItem->BasePriority = basicInfo.BasePriority; + } + + PhGetProcessSessionId(processHandle, &processItem->SessionId); + + PhPrintUInt32(processItem->ParentProcessIdString, HandleToUlong(processItem->ParentProcessId)); + PhPrintUInt32(processItem->SessionIdString, processItem->SessionId); + + if (NT_SUCCESS(PhGetProcessTimes(processHandle, ×))) + { + processItem->CreateTime = times.CreateTime; + processItem->KernelTime = times.KernelTime; + processItem->UserTime = times.UserTime; + } + + // TODO: Token information? + + if (NT_SUCCESS(NtQueryInformationProcess( + processHandle, + ProcessPriorityClass, + &priorityClass, + sizeof(PROCESS_PRIORITY_CLASS), + NULL + ))) + { + processItem->PriorityClass = priorityClass.PriorityClass; + } + + if (NT_SUCCESS(NtQueryInformationProcess( + processHandle, + ProcessHandleCount, + &handleCount, + sizeof(ULONG), + NULL + ))) + { + processItem->NumberOfHandles = handleCount; + } + } + + // Stage 1 + // Some copy and paste magic here... + + if (processItem->FileName) + { + // Small icon, large icon. + ExtractIconEx( + processItem->FileName->Buffer, + 0, + &processItem->LargeIcon, + &processItem->SmallIcon, + 1 + ); + + // Version info. + PhInitializeImageVersionInfo(&processItem->VersionInfo, processItem->FileName->Buffer); + } + + // Use the default EXE icon if we didn't get the file's icon. + { + if (!processItem->SmallIcon || !processItem->LargeIcon) + { + if (processItem->SmallIcon) + { + DestroyIcon(processItem->SmallIcon); + processItem->SmallIcon = NULL; + } + else if (processItem->LargeIcon) + { + DestroyIcon(processItem->LargeIcon); + processItem->LargeIcon = NULL; + } + + PhGetStockApplicationIcon(&processItem->SmallIcon, &processItem->LargeIcon); + processItem->SmallIcon = CopyIcon(processItem->SmallIcon); + processItem->LargeIcon = CopyIcon(processItem->LargeIcon); + } + } + + // Command line + + status = PhOpenProcess( + &processHandle2, + ProcessQueryAccess | PROCESS_VM_READ, + Entry->ProcessId + ); + + if (NT_SUCCESS(status)) + { + PPH_STRING commandLine; + ULONG i; + + if (NT_SUCCESS(status = PhGetProcessCommandLine(processHandle2, &commandLine))) + { + // Some command lines (e.g. from taskeng.exe) have nulls in them. + // Since Windows can't display them, we'll replace them with + // spaces. + for (i = 0; i < (ULONG)commandLine->Length / 2; i++) + { + if (commandLine->Buffer[i] == 0) + commandLine->Buffer[i] = ' '; + } + } + + if (NT_SUCCESS(status)) + { + processItem->CommandLine = commandLine; + } + + NtClose(processHandle2); + } + + // TODO: Other stage 1 tasks. + + PhSetEvent(&processItem->Stage1Event); + + return processItem; +} + +NTSTATUS PhpEnumHiddenProcessesBruteForce( + _In_ PPH_ENUM_HIDDEN_PROCESSES_CALLBACK Callback, + _In_opt_ PVOID Context + ) +{ + NTSTATUS status; + PVOID processes; + PSYSTEM_PROCESS_INFORMATION process; + PPH_LIST pids; + ULONG pid; + BOOLEAN stop = FALSE; + + if (!NT_SUCCESS(status = PhEnumProcesses(&processes))) + return status; + + pids = PhCreateList(40); + + process = PH_FIRST_PROCESS(processes); + + do + { + PhAddItemList(pids, process->UniqueProcessId); + } while (process = PH_NEXT_PROCESS(process)); + + PhFree(processes); + + for (pid = 8; pid <= 65536; pid += 4) + { + NTSTATUS status2; + HANDLE processHandle; + PH_HIDDEN_PROCESS_ENTRY entry; + KERNEL_USER_TIMES times; + PPH_STRING fileName; + + status2 = PhOpenProcess( + &processHandle, + ProcessQueryAccess, + UlongToHandle(pid) + ); + + if (NT_SUCCESS(status2)) + { + entry.ProcessId = UlongToHandle(pid); + + if (NT_SUCCESS(status2 = PhGetProcessTimes( + processHandle, + × + )) && + NT_SUCCESS(status2 = PhGetProcessImageFileName( + processHandle, + &fileName + ))) + { + entry.FileName = PhGetFileName(fileName); + PhDereferenceObject(fileName); + + if (times.ExitTime.QuadPart != 0) + entry.Type = TerminatedProcess; + else if (PhFindItemList(pids, UlongToHandle(pid)) != -1) + entry.Type = NormalProcess; + else + entry.Type = HiddenProcess; + + if (!Callback(&entry, Context)) + stop = TRUE; + + PhDereferenceObject(entry.FileName); + } + + NtClose(processHandle); + } + + // Use an alternative method if we don't have sufficient access. + if (status2 == STATUS_ACCESS_DENIED && WindowsVersion >= WINDOWS_VISTA) + { + if (NT_SUCCESS(status2 = PhGetProcessImageFileNameByProcessId(UlongToHandle(pid), &fileName))) + { + entry.ProcessId = UlongToHandle(pid); + entry.FileName = PhGetFileName(fileName); + PhDereferenceObject(fileName); + + if (PhFindItemList(pids, UlongToHandle(pid)) != -1) + entry.Type = NormalProcess; + else + entry.Type = HiddenProcess; + + if (!Callback(&entry, Context)) + stop = TRUE; + + PhDereferenceObject(entry.FileName); + } + } + + if (status2 == STATUS_INVALID_CID || status2 == STATUS_INVALID_PARAMETER) + status2 = STATUS_SUCCESS; + + if (!NT_SUCCESS(status2)) + { + entry.ProcessId = UlongToHandle(pid); + entry.FileName = NULL; + entry.Type = UnknownProcess; + + if (!Callback(&entry, Context)) + stop = TRUE; + } + + if (stop) + break; + } + + PhDereferenceObject(pids); + + return status; +} + +typedef struct _CSR_HANDLES_CONTEXT +{ + PPH_ENUM_HIDDEN_PROCESSES_CALLBACK Callback; + PVOID Context; + PPH_LIST Pids; +} CSR_HANDLES_CONTEXT, *PCSR_HANDLES_CONTEXT; + +static BOOLEAN NTAPI PhpCsrProcessHandlesCallback( + _In_ PPH_CSR_HANDLE_INFO Handle, + _In_opt_ PVOID Context + ) +{ + NTSTATUS status; + BOOLEAN cont = TRUE; + PCSR_HANDLES_CONTEXT context = Context; + HANDLE processHandle; + KERNEL_USER_TIMES times; + PPH_STRING fileName; + PH_HIDDEN_PROCESS_ENTRY entry; + + entry.ProcessId = Handle->ProcessId; + + if (NT_SUCCESS(status = PhOpenProcessByCsrHandle( + &processHandle, + ProcessQueryAccess, + Handle + ))) + { + if (NT_SUCCESS(status = PhGetProcessTimes( + processHandle, + × + )) && + NT_SUCCESS(status = PhGetProcessImageFileName( + processHandle, + &fileName + ))) + { + entry.FileName = PhGetFileName(fileName); + PhDereferenceObject(fileName); + + if (times.ExitTime.QuadPart != 0) + entry.Type = TerminatedProcess; + else if (PhFindItemList(context->Pids, Handle->ProcessId) != -1) + entry.Type = NormalProcess; + else + entry.Type = HiddenProcess; + + if (!context->Callback(&entry, context->Context)) + cont = FALSE; + + PhDereferenceObject(entry.FileName); + } + + NtClose(processHandle); + } + + if (!NT_SUCCESS(status)) + { + entry.FileName = NULL; + entry.Type = UnknownProcess; + + if (!context->Callback(&entry, context->Context)) + cont = FALSE; + } + + return cont; +} + +NTSTATUS PhpEnumHiddenProcessesCsrHandles( + _In_ PPH_ENUM_HIDDEN_PROCESSES_CALLBACK Callback, + _In_opt_ PVOID Context + ) +{ + NTSTATUS status; + PVOID processes; + PSYSTEM_PROCESS_INFORMATION process; + PPH_LIST pids; + CSR_HANDLES_CONTEXT context; + + if (!NT_SUCCESS(status = PhEnumProcesses(&processes))) + return status; + + pids = PhCreateList(40); + + process = PH_FIRST_PROCESS(processes); + + do + { + PhAddItemList(pids, process->UniqueProcessId); + } while (process = PH_NEXT_PROCESS(process)); + + PhFree(processes); + + context.Callback = Callback; + context.Context = Context; + context.Pids = pids; + + status = PhEnumCsrProcessHandles(PhpCsrProcessHandlesCallback, &context); + + PhDereferenceObject(pids); + + return status; +} + +NTSTATUS PhEnumHiddenProcesses( + _In_ PH_HIDDEN_PROCESS_METHOD Method, + _In_ PPH_ENUM_HIDDEN_PROCESSES_CALLBACK Callback, + _In_opt_ PVOID Context + ) +{ + if (Method == BruteForceScanMethod) + { + return PhpEnumHiddenProcessesBruteForce( + Callback, + Context + ); + } + else + { + return PhpEnumHiddenProcessesCsrHandles( + Callback, + Context + ); + } +} + +NTSTATUS PhpOpenCsrProcesses( + _Out_ PHANDLE *ProcessHandles, + _Out_ PULONG NumberOfProcessHandles + ) +{ + NTSTATUS status; + PVOID processes; + PSYSTEM_PROCESS_INFORMATION process; + PPH_LIST processHandleList; + + if (!NT_SUCCESS(status = PhEnumProcesses(&processes))) + return status; + + processHandleList = PhCreateList(8); + + process = PH_FIRST_PROCESS(processes); + + do + { + HANDLE processHandle; + PH_KNOWN_PROCESS_TYPE knownProcessType; + + if (NT_SUCCESS(PhOpenProcess( + &processHandle, + ProcessQueryAccess | PROCESS_DUP_HANDLE, + process->UniqueProcessId + ))) + { + if (NT_SUCCESS(PhGetProcessKnownType( + processHandle, + &knownProcessType + )) && + (knownProcessType & KnownProcessTypeMask) == WindowsSubsystemProcessType) + { + PhAddItemList(processHandleList, processHandle); + } + else + { + NtClose(processHandle); + } + } + } while (process = PH_NEXT_PROCESS(process)); + + PhFree(processes); + + *ProcessHandles = PhAllocateCopy(processHandleList->Items, processHandleList->Count * sizeof(HANDLE)); + *NumberOfProcessHandles = processHandleList->Count; + + PhDereferenceObject(processHandleList); + + return status; +} + +NTSTATUS PhpGetCsrHandleProcessId( + _Inout_ PPH_CSR_HANDLE_INFO Handle + ) +{ + NTSTATUS status; + PROCESS_BASIC_INFORMATION processBasicInfo; + THREAD_BASIC_INFORMATION threadBasicInfo; + + Handle->IsThreadHandle = FALSE; + Handle->ProcessId = NULL; + + // Assume the handle is a process handle, and get the + // process ID. + + status = KphQueryInformationObject( + Handle->CsrProcessHandle, + Handle->Handle, + KphObjectProcessBasicInformation, + &processBasicInfo, + sizeof(PROCESS_BASIC_INFORMATION), + NULL + ); + + if (NT_SUCCESS(status)) + { + Handle->ProcessId = processBasicInfo.UniqueProcessId; + } + else + { + // We failed to get the process ID. Assume the handle + // is a thread handle, and get the process ID. + + status = KphQueryInformationObject( + Handle->CsrProcessHandle, + Handle->Handle, + KphObjectThreadBasicInformation, + &threadBasicInfo, + sizeof(THREAD_BASIC_INFORMATION), + NULL + ); + + if (NT_SUCCESS(status)) + { + Handle->ProcessId = threadBasicInfo.ClientId.UniqueProcess; + Handle->IsThreadHandle = TRUE; + } + } + + return status; +} + +NTSTATUS PhEnumCsrProcessHandles( + _In_ PPH_ENUM_CSR_PROCESS_HANDLES_CALLBACK Callback, + _In_opt_ PVOID Context + ) +{ + NTSTATUS status; + PHANDLE csrProcessHandles; + ULONG numberOfCsrProcessHandles; + ULONG i; + BOOLEAN stop = FALSE; + PPH_LIST pids; + + if (!NT_SUCCESS(status = PhpOpenCsrProcesses( + &csrProcessHandles, + &numberOfCsrProcessHandles + ))) + return status; + + pids = PhCreateList(40); + + for (i = 0; i < numberOfCsrProcessHandles; i++) + { + PKPH_PROCESS_HANDLE_INFORMATION handles; + ULONG j; + + if (stop) + break; + + if (NT_SUCCESS(KphEnumerateProcessHandles2(csrProcessHandles[i], &handles))) + { + for (j = 0; j < handles->HandleCount; j++) + { + PH_CSR_HANDLE_INFO handle; + + handle.CsrProcessHandle = csrProcessHandles[i]; + handle.Handle = handles->Handles[j].Handle; + + // Get the process ID associated with the handle. + // This call will fail if the handle is not a + // process or thread handle. + if (!NT_SUCCESS(PhpGetCsrHandleProcessId(&handle))) + continue; + + // Avoid duplicate PIDs. + if (PhFindItemList(pids, handle.ProcessId) != -1) + continue; + + PhAddItemList(pids, handle.ProcessId); + + if (!Callback(&handle, Context)) + { + stop = TRUE; + break; + } + } + + PhFree(handles); + } + } + + PhDereferenceObject(pids); + + for (i = 0; i < numberOfCsrProcessHandles; i++) + NtClose(csrProcessHandles[i]); + + PhFree(csrProcessHandles); + + return status; +} + +NTSTATUS PhOpenProcessByCsrHandle( + _Out_ PHANDLE ProcessHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ PPH_CSR_HANDLE_INFO Handle + ) +{ + NTSTATUS status; + + if (!Handle->IsThreadHandle) + { + status = NtDuplicateObject( + Handle->CsrProcessHandle, + Handle->Handle, + NtCurrentProcess(), + ProcessHandle, + DesiredAccess, + 0, + 0 + ); + } + else + { + HANDLE threadHandle; + + if (!NT_SUCCESS(status = NtDuplicateObject( + Handle->CsrProcessHandle, + Handle->Handle, + NtCurrentProcess(), + &threadHandle, + ThreadQueryAccess, + 0, + 0 + ))) + return status; + + status = KphOpenThreadProcess( + threadHandle, + DesiredAccess, + ProcessHandle + ); + NtClose(threadHandle); + } + + return status; +} + +typedef struct _OPEN_PROCESS_BY_CSR_CONTEXT +{ + NTSTATUS Status; + PHANDLE ProcessHandle; + ACCESS_MASK DesiredAccess; + HANDLE ProcessId; +} OPEN_PROCESS_BY_CSR_CONTEXT, *POPEN_PROCESS_BY_CSR_CONTEXT; + +static BOOLEAN NTAPI PhpOpenProcessByCsrHandlesCallback( + _In_ PPH_CSR_HANDLE_INFO Handle, + _In_opt_ PVOID Context + ) +{ + POPEN_PROCESS_BY_CSR_CONTEXT context = Context; + + if (Handle->ProcessId == context->ProcessId) + { + context->Status = PhOpenProcessByCsrHandle( + context->ProcessHandle, + context->DesiredAccess, + Handle + ); + + return FALSE; + } + + return TRUE; +} + +NTSTATUS PhOpenProcessByCsrHandles( + _Out_ PHANDLE ProcessHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ HANDLE ProcessId + ) +{ + NTSTATUS status; + OPEN_PROCESS_BY_CSR_CONTEXT context; + + context.Status = STATUS_INVALID_CID; + context.ProcessHandle = ProcessHandle; + context.DesiredAccess = DesiredAccess; + context.ProcessId = ProcessId; + + if (!NT_SUCCESS(status = PhEnumCsrProcessHandles( + PhpOpenProcessByCsrHandlesCallback, + &context + ))) + return status; + + return context.Status; +} diff --git a/ProcessHacker/hndllist.c b/ProcessHacker/hndllist.c index 110316c924ed..517f838e79ee 100644 --- a/ProcessHacker/hndllist.c +++ b/ProcessHacker/hndllist.c @@ -1,749 +1,749 @@ -/* - * Process Hacker - - * handle list - * - * Copyright (C) 2011-2013 wj32 - * Copyright (C) 2017 dmex - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include -#include - -#include -#include - -#include -#include -#include -#include - -BOOLEAN PhpHandleNodeHashtableEqualFunction( - _In_ PVOID Entry1, - _In_ PVOID Entry2 - ); - -ULONG PhpHandleNodeHashtableHashFunction( - _In_ PVOID Entry - ); - -VOID PhpDestroyHandleNode( - _In_ PPH_HANDLE_NODE HandleNode - ); - -VOID PhpRemoveHandleNode( - _In_ PPH_HANDLE_NODE HandleNode, - _In_ PPH_HANDLE_LIST_CONTEXT Context - ); - -LONG PhpHandleTreeNewPostSortFunction( - _In_ LONG Result, - _In_ PVOID Node1, - _In_ PVOID Node2, - _In_ PH_SORT_ORDER SortOrder - ); - -BOOLEAN NTAPI PhpHandleTreeNewCallback( - _In_ HWND hwnd, - _In_ PH_TREENEW_MESSAGE Message, - _In_opt_ PVOID Parameter1, - _In_opt_ PVOID Parameter2, - _In_opt_ PVOID Context - ); - -VOID PhInitializeHandleList( - _In_ HWND ParentWindowHandle, - _In_ HWND TreeNewHandle, - _Out_ PPH_HANDLE_LIST_CONTEXT Context - ) -{ - HWND hwnd; - - memset(Context, 0, sizeof(PH_HANDLE_LIST_CONTEXT)); - Context->EnableStateHighlighting = TRUE; - - Context->NodeHashtable = PhCreateHashtable( - sizeof(PPH_HANDLE_NODE), - PhpHandleNodeHashtableEqualFunction, - PhpHandleNodeHashtableHashFunction, - 100 - ); - Context->NodeList = PhCreateList(100); - - Context->ParentWindowHandle = ParentWindowHandle; - Context->TreeNewHandle = TreeNewHandle; - hwnd = TreeNewHandle; - PhSetControlTheme(hwnd, L"explorer"); - - TreeNew_SetCallback(hwnd, PhpHandleTreeNewCallback, Context); - - TreeNew_SetRedraw(hwnd, FALSE); - - // Default columns - PhAddTreeNewColumn(hwnd, PHHNTLC_TYPE, TRUE, L"Type", 100, PH_ALIGN_LEFT, 0, 0); - PhAddTreeNewColumn(hwnd, PHHNTLC_NAME, TRUE, L"Name", 200, PH_ALIGN_LEFT, 1, 0); - PhAddTreeNewColumn(hwnd, PHHNTLC_GRANTEDACCESSSYMBOLIC, TRUE, L"Granted access (symbolic)", 140, PH_ALIGN_LEFT, 2, 0); - - PhAddTreeNewColumn(hwnd, PHHNTLC_HANDLE, FALSE, L"Handle", 80, PH_ALIGN_LEFT, -1, 0); - PhAddTreeNewColumn(hwnd, PHHNTLC_OBJECTADDRESS, FALSE, L"Object address", 80, PH_ALIGN_LEFT, -1, 0); - PhAddTreeNewColumnEx(hwnd, PHHNTLC_ATTRIBUTES, FALSE, L"Attributes", 120, PH_ALIGN_LEFT, -1, 0, TRUE); - PhAddTreeNewColumn(hwnd, PHHNTLC_GRANTEDACCESS, FALSE, L"Granted access", 80, PH_ALIGN_LEFT, -1, 0); - PhAddTreeNewColumn(hwnd, PHHNTLC_ORIGINALNAME, FALSE, L"Original name", 200, PH_ALIGN_LEFT, -1, 0); - PhAddTreeNewColumnEx(hwnd, PHHNTLC_FILESHAREACCESS, FALSE, L"File share access", 50, PH_ALIGN_LEFT, -1, 0, TRUE); - - TreeNew_SetRedraw(hwnd, TRUE); - - TreeNew_SetSort(hwnd, 0, AscendingSortOrder); - - PhCmInitializeManager(&Context->Cm, hwnd, PHHNTLC_MAXIMUM, PhpHandleTreeNewPostSortFunction); - - PhInitializeTreeNewFilterSupport(&Context->TreeFilterSupport, hwnd, Context->NodeList); -} - -VOID PhDeleteHandleList( - _In_ PPH_HANDLE_LIST_CONTEXT Context - ) -{ - ULONG i; - - PhCmDeleteManager(&Context->Cm); - - for (i = 0; i < Context->NodeList->Count; i++) - PhpDestroyHandleNode(Context->NodeList->Items[i]); - - PhDereferenceObject(Context->NodeHashtable); - PhDereferenceObject(Context->NodeList); -} - -BOOLEAN PhpHandleNodeHashtableEqualFunction( - _In_ PVOID Entry1, - _In_ PVOID Entry2 - ) -{ - PPH_HANDLE_NODE handleNode1 = *(PPH_HANDLE_NODE *)Entry1; - PPH_HANDLE_NODE handleNode2 = *(PPH_HANDLE_NODE *)Entry2; - - return handleNode1->Handle == handleNode2->Handle; -} - -ULONG PhpHandleNodeHashtableHashFunction( - _In_ PVOID Entry - ) -{ - return HandleToUlong((*(PPH_HANDLE_NODE *)Entry)->Handle) / 4; -} - -VOID PhLoadSettingsHandleList( - _Inout_ PPH_HANDLE_LIST_CONTEXT Context - ) -{ - PPH_STRING settings; - PPH_STRING sortSettings; - - settings = PhGetStringSetting(L"HandleTreeListColumns"); - sortSettings = PhGetStringSetting(L"HandleTreeListSort"); - PhCmLoadSettingsEx(Context->TreeNewHandle, &Context->Cm, 0, &settings->sr, &sortSettings->sr); - PhDereferenceObject(settings); - PhDereferenceObject(sortSettings); -} - -VOID PhSaveSettingsHandleList( - _Inout_ PPH_HANDLE_LIST_CONTEXT Context - ) -{ - PPH_STRING settings; - PPH_STRING sortSettings; - - settings = PhCmSaveSettingsEx(Context->TreeNewHandle, &Context->Cm, 0, &sortSettings); - PhSetStringSetting2(L"HandleTreeListColumns", &settings->sr); - PhSetStringSetting2(L"HandleTreeListSort", &sortSettings->sr); - PhDereferenceObject(settings); - PhDereferenceObject(sortSettings); -} - -VOID PhSetOptionsHandleList( - _Inout_ PPH_HANDLE_LIST_CONTEXT Context, - _In_ BOOLEAN HideUnnamedHandles - ) -{ - if (Context->HideUnnamedHandles != HideUnnamedHandles) - { - Context->HideUnnamedHandles = HideUnnamedHandles; - } -} - -PPH_HANDLE_NODE PhAddHandleNode( - _Inout_ PPH_HANDLE_LIST_CONTEXT Context, - _In_ PPH_HANDLE_ITEM HandleItem, - _In_ ULONG RunId - ) -{ - PPH_HANDLE_NODE handleNode; - - handleNode = PhAllocate(PhEmGetObjectSize(EmHandleNodeType, sizeof(PH_HANDLE_NODE))); - memset(handleNode, 0, sizeof(PH_HANDLE_NODE)); - PhInitializeTreeNewNode(&handleNode->Node); - - if (Context->EnableStateHighlighting && RunId != 1) - { - PhChangeShStateTn( - &handleNode->Node, - &handleNode->ShState, - &Context->NodeStateList, - NewItemState, - PhCsColorNew, - NULL - ); - } - - handleNode->Handle = HandleItem->Handle; - handleNode->HandleItem = HandleItem; - PhReferenceObject(HandleItem); - - memset(handleNode->TextCache, 0, sizeof(PH_STRINGREF) * PHHNTLC_MAXIMUM); - handleNode->Node.TextCache = handleNode->TextCache; - handleNode->Node.TextCacheSize = PHHNTLC_MAXIMUM; - - PhAddEntryHashtable(Context->NodeHashtable, &handleNode); - PhAddItemList(Context->NodeList, handleNode); - - if (Context->TreeFilterSupport.FilterList) - handleNode->Node.Visible = PhApplyTreeNewFiltersToNode(&Context->TreeFilterSupport, &handleNode->Node); - - PhEmCallObjectOperation(EmHandleNodeType, handleNode, EmObjectCreate); - - TreeNew_NodesStructured(Context->TreeNewHandle); - - return handleNode; -} - -PPH_HANDLE_NODE PhFindHandleNode( - _In_ PPH_HANDLE_LIST_CONTEXT Context, - _In_ HANDLE Handle - ) -{ - PH_HANDLE_NODE lookupHandleNode; - PPH_HANDLE_NODE lookupHandleNodePtr = &lookupHandleNode; - PPH_HANDLE_NODE *handleNode; - - lookupHandleNode.Handle = Handle; - - handleNode = (PPH_HANDLE_NODE *)PhFindEntryHashtable( - Context->NodeHashtable, - &lookupHandleNodePtr - ); - - if (handleNode) - return *handleNode; - else - return NULL; -} - -VOID PhRemoveHandleNode( - _In_ PPH_HANDLE_LIST_CONTEXT Context, - _In_ PPH_HANDLE_NODE HandleNode - ) -{ - // Remove from the hashtable here to avoid problems in case the key is re-used. - PhRemoveEntryHashtable(Context->NodeHashtable, &HandleNode); - - if (Context->EnableStateHighlighting) - { - PhChangeShStateTn( - &HandleNode->Node, - &HandleNode->ShState, - &Context->NodeStateList, - RemovingItemState, - PhCsColorRemoved, - Context->TreeNewHandle - ); - } - else - { - PhpRemoveHandleNode(HandleNode, Context); - } -} - -VOID PhpDestroyHandleNode( - _In_ PPH_HANDLE_NODE HandleNode - ) -{ - PhEmCallObjectOperation(EmHandleNodeType, HandleNode, EmObjectDelete); - - if (HandleNode->GrantedAccessSymbolicText) PhDereferenceObject(HandleNode->GrantedAccessSymbolicText); - - PhDereferenceObject(HandleNode->HandleItem); - - PhFree(HandleNode); -} - -VOID PhpRemoveHandleNode( - _In_ PPH_HANDLE_NODE HandleNode, - _In_ PPH_HANDLE_LIST_CONTEXT Context // PH_TICK_SH_STATE requires this parameter to be after HandleNode - ) -{ - ULONG index; - - // Remove from list and cleanup. - - if ((index = PhFindItemList(Context->NodeList, HandleNode)) != -1) - PhRemoveItemList(Context->NodeList, index); - - PhpDestroyHandleNode(HandleNode); - - TreeNew_NodesStructured(Context->TreeNewHandle); -} - -VOID PhUpdateHandleNode( - _In_ PPH_HANDLE_LIST_CONTEXT Context, - _In_ PPH_HANDLE_NODE HandleNode - ) -{ - memset(HandleNode->TextCache, 0, sizeof(PH_STRINGREF) * PHHNTLC_MAXIMUM); - - PhInvalidateTreeNewNode(&HandleNode->Node, TN_CACHE_COLOR); - TreeNew_NodesStructured(Context->TreeNewHandle); -} - -VOID PhExpandAllHandleNodes( - _In_ PPH_HANDLE_LIST_CONTEXT Context, - _In_ BOOLEAN Expand - ) -{ - ULONG i; - BOOLEAN needsRestructure = FALSE; - - for (i = 0; i < Context->NodeList->Count; i++) - { - PPH_HANDLE_NODE node = Context->NodeList->Items[i]; - - if (node->Node.Expanded != Expand) - { - node->Node.Expanded = Expand; - needsRestructure = TRUE; - } - } - - if (needsRestructure) - TreeNew_NodesStructured(Context->TreeNewHandle); -} - -VOID PhTickHandleNodes( - _In_ PPH_HANDLE_LIST_CONTEXT Context - ) -{ - PH_TICK_SH_STATE_TN(PH_HANDLE_NODE, ShState, Context->NodeStateList, PhpRemoveHandleNode, PhCsHighlightingDuration, Context->TreeNewHandle, TRUE, NULL, Context); -} - -#define SORT_FUNCTION(Column) PhpHandleTreeNewCompare##Column - -#define BEGIN_SORT_FUNCTION(Column) static int __cdecl PhpHandleTreeNewCompare##Column( \ - _In_ void *_context, \ - _In_ const void *_elem1, \ - _In_ const void *_elem2 \ - ) \ -{ \ - PPH_HANDLE_NODE node1 = *(PPH_HANDLE_NODE *)_elem1; \ - PPH_HANDLE_NODE node2 = *(PPH_HANDLE_NODE *)_elem2; \ - PPH_HANDLE_ITEM handleItem1 = node1->HandleItem; \ - PPH_HANDLE_ITEM handleItem2 = node2->HandleItem; \ - PPH_HANDLE_LIST_CONTEXT context = (PPH_HANDLE_LIST_CONTEXT)_context; \ - int sortResult = 0; - -#define END_SORT_FUNCTION \ - if (sortResult == 0) \ - sortResult = uintptrcmp((ULONG_PTR)node1->Handle, (ULONG_PTR)node2->Handle); \ - \ - return PhModifySort(sortResult, context->TreeNewSortOrder); \ -} - -LONG PhpHandleTreeNewPostSortFunction( - _In_ LONG Result, - _In_ PVOID Node1, - _In_ PVOID Node2, - _In_ PH_SORT_ORDER SortOrder - ) -{ - if (Result == 0) - Result = uintptrcmp((ULONG_PTR)((PPH_HANDLE_NODE)Node1)->Handle, (ULONG_PTR)((PPH_HANDLE_NODE)Node2)->Handle); - - return PhModifySort(Result, SortOrder); -} - -BEGIN_SORT_FUNCTION(Type) -{ - sortResult = PhCompareString(handleItem1->TypeName, handleItem2->TypeName, TRUE); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(Name) -{ - sortResult = PhCompareStringWithNull(handleItem1->BestObjectName, handleItem2->BestObjectName, TRUE); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(Handle) -{ - sortResult = uintptrcmp((ULONG_PTR)node1->Handle, (ULONG_PTR)node2->Handle); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(ObjectAddress) -{ - sortResult = uintptrcmp((ULONG_PTR)handleItem1->Object, (ULONG_PTR)handleItem2->Object); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(Attributes) -{ - sortResult = uintcmp(handleItem1->Attributes, handleItem2->Attributes); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(GrantedAccess) -{ - sortResult = uintcmp(handleItem1->GrantedAccess, handleItem2->GrantedAccess); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(OriginalName) -{ - sortResult = PhCompareStringWithNull(handleItem1->ObjectName, handleItem2->ObjectName, TRUE); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(FileShareAccess) -{ - sortResult = uintcmp(handleItem1->FileFlags & (PH_HANDLE_FILE_SHARED_MASK), handleItem2->FileFlags & (PH_HANDLE_FILE_SHARED_MASK)); - - // Make sure all file handles get grouped together regardless of share access. - if (sortResult == 0) - sortResult = intcmp(PhEqualString2(handleItem1->TypeName, L"File", TRUE), PhEqualString2(handleItem2->TypeName, L"File", TRUE)); -} -END_SORT_FUNCTION - -BOOLEAN NTAPI PhpHandleTreeNewCallback( - _In_ HWND hwnd, - _In_ PH_TREENEW_MESSAGE Message, - _In_opt_ PVOID Parameter1, - _In_opt_ PVOID Parameter2, - _In_opt_ PVOID Context - ) -{ - PPH_HANDLE_LIST_CONTEXT context; - PPH_HANDLE_NODE node; - - context = Context; - - if (PhCmForwardMessage(hwnd, Message, Parameter1, Parameter2, &context->Cm)) - return TRUE; - - switch (Message) - { - case TreeNewGetChildren: - { - PPH_TREENEW_GET_CHILDREN getChildren = Parameter1; - - if (!getChildren->Node) - { - static PVOID sortFunctions[] = - { - SORT_FUNCTION(Type), - SORT_FUNCTION(Name), - SORT_FUNCTION(Handle), - SORT_FUNCTION(ObjectAddress), - SORT_FUNCTION(Attributes), - SORT_FUNCTION(GrantedAccess), - SORT_FUNCTION(GrantedAccess), // Granted Access (Symbolic) - SORT_FUNCTION(OriginalName), - SORT_FUNCTION(FileShareAccess) - }; - int (__cdecl *sortFunction)(void *, const void *, const void *); - - if (!PhCmForwardSort( - (PPH_TREENEW_NODE *)context->NodeList->Items, - context->NodeList->Count, - context->TreeNewSortColumn, - context->TreeNewSortOrder, - &context->Cm - )) - { - if (context->TreeNewSortColumn < PHHNTLC_MAXIMUM) - sortFunction = sortFunctions[context->TreeNewSortColumn]; - else - sortFunction = NULL; - } - else - { - sortFunction = NULL; - } - - if (sortFunction) - { - qsort_s(context->NodeList->Items, context->NodeList->Count, sizeof(PVOID), sortFunction, context); - } - - getChildren->Children = (PPH_TREENEW_NODE *)context->NodeList->Items; - getChildren->NumberOfChildren = context->NodeList->Count; - } - } - return TRUE; - case TreeNewIsLeaf: - { - PPH_TREENEW_IS_LEAF isLeaf = Parameter1; - - isLeaf->IsLeaf = TRUE; - } - return TRUE; - case TreeNewGetCellText: - { - PPH_TREENEW_GET_CELL_TEXT getCellText = Parameter1; - PPH_HANDLE_ITEM handleItem; - - node = (PPH_HANDLE_NODE)getCellText->Node; - handleItem = node->HandleItem; - - switch (getCellText->Id) - { - case PHHNTLC_TYPE: - getCellText->Text = handleItem->TypeName->sr; - break; - case PHHNTLC_NAME: - getCellText->Text = PhGetStringRef(handleItem->BestObjectName); - break; - case PHHNTLC_HANDLE: - PhInitializeStringRefLongHint(&getCellText->Text, handleItem->HandleString); - break; - case PHHNTLC_OBJECTADDRESS: - PhInitializeStringRefLongHint(&getCellText->Text, handleItem->ObjectString); - break; - case PHHNTLC_ATTRIBUTES: - switch (handleItem->Attributes & (OBJ_PROTECT_CLOSE | OBJ_INHERIT)) - { - case OBJ_PROTECT_CLOSE: - PhInitializeStringRef(&getCellText->Text, L"Protected"); - break; - case OBJ_INHERIT: - PhInitializeStringRef(&getCellText->Text, L"Inherit"); - break; - case OBJ_PROTECT_CLOSE | OBJ_INHERIT: - PhInitializeStringRef(&getCellText->Text, L"Protected, Inherit"); - break; - } - break; - case PHHNTLC_GRANTEDACCESS: - PhInitializeStringRefLongHint(&getCellText->Text, handleItem->GrantedAccessString); - break; - case PHHNTLC_GRANTEDACCESSSYMBOLIC: - if (handleItem->GrantedAccess != 0) - { - if (!node->GrantedAccessSymbolicText) - { - PPH_ACCESS_ENTRY accessEntries; - ULONG numberOfAccessEntries; - - if (PhGetAccessEntries(handleItem->TypeName->Buffer, &accessEntries, &numberOfAccessEntries)) - { - node->GrantedAccessSymbolicText = PhGetAccessString(handleItem->GrantedAccess, accessEntries, numberOfAccessEntries); - PhFree(accessEntries); - } - else - { - node->GrantedAccessSymbolicText = PhReferenceEmptyString(); - } - } - - if (node->GrantedAccessSymbolicText->Length != 0) - getCellText->Text = node->GrantedAccessSymbolicText->sr; - else - PhInitializeStringRefLongHint(&getCellText->Text, handleItem->GrantedAccessString); - } - break; - case PHHNTLC_ORIGINALNAME: - getCellText->Text = PhGetStringRef(handleItem->ObjectName); - break; - case PHHNTLC_FILESHAREACCESS: - if (handleItem->FileFlags & PH_HANDLE_FILE_SHARED_MASK) - { - node->FileShareAccessText[0] = '-'; - node->FileShareAccessText[1] = '-'; - node->FileShareAccessText[2] = '-'; - node->FileShareAccessText[3] = 0; - - if (handleItem->FileFlags & PH_HANDLE_FILE_SHARED_READ) - node->FileShareAccessText[0] = 'R'; - if (handleItem->FileFlags & PH_HANDLE_FILE_SHARED_WRITE) - node->FileShareAccessText[1] = 'W'; - if (handleItem->FileFlags & PH_HANDLE_FILE_SHARED_DELETE) - node->FileShareAccessText[2] = 'D'; - - PhInitializeStringRef(&getCellText->Text, node->FileShareAccessText); - } - break; - default: - return FALSE; - } - - getCellText->Flags = TN_CACHE; - } - return TRUE; - case TreeNewGetNodeColor: - { - PPH_TREENEW_GET_NODE_COLOR getNodeColor = Parameter1; - PPH_HANDLE_ITEM handleItem; - - node = (PPH_HANDLE_NODE)getNodeColor->Node; - handleItem = node->HandleItem; - - if (!handleItem) - ; // Dummy - else if (PhCsUseColorProtectedHandles && (handleItem->Attributes & OBJ_PROTECT_CLOSE)) - getNodeColor->BackColor = PhCsColorProtectedHandles; - else if (PhCsUseColorInheritHandles && (handleItem->Attributes & OBJ_INHERIT)) - getNodeColor->BackColor = PhCsColorInheritHandles; - - getNodeColor->Flags = TN_CACHE | TN_AUTO_FORECOLOR; - } - return TRUE; - case TreeNewSortChanged: - { - TreeNew_GetSort(hwnd, &context->TreeNewSortColumn, &context->TreeNewSortOrder); - // Force a rebuild to sort the items. - TreeNew_NodesStructured(hwnd); - } - return TRUE; - case TreeNewKeyDown: - { - PPH_TREENEW_KEY_EVENT keyEvent = Parameter1; - - switch (keyEvent->VirtualKey) - { - case 'C': - if (GetKeyState(VK_CONTROL) < 0) - SendMessage(context->ParentWindowHandle, WM_COMMAND, ID_HANDLE_COPY, 0); - break; - case 'A': - if (GetKeyState(VK_CONTROL) < 0) - TreeNew_SelectRange(context->TreeNewHandle, 0, -1); - break; - case VK_DELETE: - // Pass a 1 in lParam to indicate that warnings should be enabled. - SendMessage(context->ParentWindowHandle, WM_COMMAND, ID_HANDLE_CLOSE, 1); - break; - case VK_RETURN: - if (GetKeyState(VK_CONTROL) >= 0) - SendMessage(context->ParentWindowHandle, WM_COMMAND, ID_HANDLE_PROPERTIES, 0); - else - SendMessage(context->ParentWindowHandle, WM_COMMAND, ID_HANDLE_OBJECTPROPERTIES1, 0); - break; - } - } - return TRUE; - case TreeNewHeaderRightClick: - { - PH_TN_COLUMN_MENU_DATA data; - - data.TreeNewHandle = hwnd; - data.MouseEvent = Parameter1; - data.DefaultSortColumn = 0; - data.DefaultSortOrder = AscendingSortOrder; - PhInitializeTreeNewColumnMenu(&data); - - data.Selection = PhShowEMenu(data.Menu, hwnd, PH_EMENU_SHOW_LEFTRIGHT, - PH_ALIGN_LEFT | PH_ALIGN_TOP, data.MouseEvent->ScreenLocation.x, data.MouseEvent->ScreenLocation.y); - PhHandleTreeNewColumnMenu(&data); - PhDeleteTreeNewColumnMenu(&data); - } - return TRUE; - case TreeNewLeftDoubleClick: - { - SendMessage(context->ParentWindowHandle, WM_COMMAND, ID_HANDLE_PROPERTIES, 0); - } - return TRUE; - case TreeNewContextMenu: - { - PPH_TREENEW_CONTEXT_MENU contextMenu = Parameter1; - - SendMessage(context->ParentWindowHandle, WM_COMMAND, ID_SHOWCONTEXTMENU, (LPARAM)contextMenu); - } - return TRUE; - case TreeNewGetDialogCode: - { - PULONG code = Parameter2; - - if (PtrToUlong(Parameter1) == VK_RETURN) - { - *code = DLGC_WANTMESSAGE; - return TRUE; - } - } - return FALSE; - } - - return FALSE; -} - -PPH_HANDLE_ITEM PhGetSelectedHandleItem( - _In_ PPH_HANDLE_LIST_CONTEXT Context - ) -{ - PPH_HANDLE_ITEM handleItem = NULL; - ULONG i; - - for (i = 0; i < Context->NodeList->Count; i++) - { - PPH_HANDLE_NODE node = Context->NodeList->Items[i]; - - if (node->Node.Selected) - { - handleItem = node->HandleItem; - break; - } - } - - return handleItem; -} - -VOID PhGetSelectedHandleItems( - _In_ PPH_HANDLE_LIST_CONTEXT Context, - _Out_ PPH_HANDLE_ITEM **Handles, - _Out_ PULONG NumberOfHandles - ) -{ - PH_ARRAY array; - ULONG i; - - PhInitializeArray(&array, sizeof(PVOID), 2); - - for (i = 0; i < Context->NodeList->Count; i++) - { - PPH_HANDLE_NODE node = Context->NodeList->Items[i]; - - if (node->Node.Selected) - PhAddItemArray(&array, &node->HandleItem); - } - - *NumberOfHandles = (ULONG)array.Count; - *Handles = PhFinalArrayItems(&array); -} - -VOID PhDeselectAllHandleNodes( - _In_ PPH_HANDLE_LIST_CONTEXT Context - ) -{ - TreeNew_DeselectRange(Context->TreeNewHandle, 0, -1); -} +/* + * Process Hacker - + * handle list + * + * Copyright (C) 2011-2013 wj32 + * Copyright (C) 2017 dmex + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include +#include + +#include +#include + +#include +#include +#include +#include + +BOOLEAN PhpHandleNodeHashtableEqualFunction( + _In_ PVOID Entry1, + _In_ PVOID Entry2 + ); + +ULONG PhpHandleNodeHashtableHashFunction( + _In_ PVOID Entry + ); + +VOID PhpDestroyHandleNode( + _In_ PPH_HANDLE_NODE HandleNode + ); + +VOID PhpRemoveHandleNode( + _In_ PPH_HANDLE_NODE HandleNode, + _In_ PPH_HANDLE_LIST_CONTEXT Context + ); + +LONG PhpHandleTreeNewPostSortFunction( + _In_ LONG Result, + _In_ PVOID Node1, + _In_ PVOID Node2, + _In_ PH_SORT_ORDER SortOrder + ); + +BOOLEAN NTAPI PhpHandleTreeNewCallback( + _In_ HWND hwnd, + _In_ PH_TREENEW_MESSAGE Message, + _In_opt_ PVOID Parameter1, + _In_opt_ PVOID Parameter2, + _In_opt_ PVOID Context + ); + +VOID PhInitializeHandleList( + _In_ HWND ParentWindowHandle, + _In_ HWND TreeNewHandle, + _Out_ PPH_HANDLE_LIST_CONTEXT Context + ) +{ + HWND hwnd; + + memset(Context, 0, sizeof(PH_HANDLE_LIST_CONTEXT)); + Context->EnableStateHighlighting = TRUE; + + Context->NodeHashtable = PhCreateHashtable( + sizeof(PPH_HANDLE_NODE), + PhpHandleNodeHashtableEqualFunction, + PhpHandleNodeHashtableHashFunction, + 100 + ); + Context->NodeList = PhCreateList(100); + + Context->ParentWindowHandle = ParentWindowHandle; + Context->TreeNewHandle = TreeNewHandle; + hwnd = TreeNewHandle; + PhSetControlTheme(hwnd, L"explorer"); + + TreeNew_SetCallback(hwnd, PhpHandleTreeNewCallback, Context); + + TreeNew_SetRedraw(hwnd, FALSE); + + // Default columns + PhAddTreeNewColumn(hwnd, PHHNTLC_TYPE, TRUE, L"Type", 100, PH_ALIGN_LEFT, 0, 0); + PhAddTreeNewColumn(hwnd, PHHNTLC_NAME, TRUE, L"Name", 200, PH_ALIGN_LEFT, 1, 0); + PhAddTreeNewColumn(hwnd, PHHNTLC_GRANTEDACCESSSYMBOLIC, TRUE, L"Granted access (symbolic)", 140, PH_ALIGN_LEFT, 2, 0); + + PhAddTreeNewColumn(hwnd, PHHNTLC_HANDLE, FALSE, L"Handle", 80, PH_ALIGN_LEFT, -1, 0); + PhAddTreeNewColumn(hwnd, PHHNTLC_OBJECTADDRESS, FALSE, L"Object address", 80, PH_ALIGN_LEFT, -1, 0); + PhAddTreeNewColumnEx(hwnd, PHHNTLC_ATTRIBUTES, FALSE, L"Attributes", 120, PH_ALIGN_LEFT, -1, 0, TRUE); + PhAddTreeNewColumn(hwnd, PHHNTLC_GRANTEDACCESS, FALSE, L"Granted access", 80, PH_ALIGN_LEFT, -1, 0); + PhAddTreeNewColumn(hwnd, PHHNTLC_ORIGINALNAME, FALSE, L"Original name", 200, PH_ALIGN_LEFT, -1, 0); + PhAddTreeNewColumnEx(hwnd, PHHNTLC_FILESHAREACCESS, FALSE, L"File share access", 50, PH_ALIGN_LEFT, -1, 0, TRUE); + + TreeNew_SetRedraw(hwnd, TRUE); + + TreeNew_SetSort(hwnd, 0, AscendingSortOrder); + + PhCmInitializeManager(&Context->Cm, hwnd, PHHNTLC_MAXIMUM, PhpHandleTreeNewPostSortFunction); + + PhInitializeTreeNewFilterSupport(&Context->TreeFilterSupport, hwnd, Context->NodeList); +} + +VOID PhDeleteHandleList( + _In_ PPH_HANDLE_LIST_CONTEXT Context + ) +{ + ULONG i; + + PhCmDeleteManager(&Context->Cm); + + for (i = 0; i < Context->NodeList->Count; i++) + PhpDestroyHandleNode(Context->NodeList->Items[i]); + + PhDereferenceObject(Context->NodeHashtable); + PhDereferenceObject(Context->NodeList); +} + +BOOLEAN PhpHandleNodeHashtableEqualFunction( + _In_ PVOID Entry1, + _In_ PVOID Entry2 + ) +{ + PPH_HANDLE_NODE handleNode1 = *(PPH_HANDLE_NODE *)Entry1; + PPH_HANDLE_NODE handleNode2 = *(PPH_HANDLE_NODE *)Entry2; + + return handleNode1->Handle == handleNode2->Handle; +} + +ULONG PhpHandleNodeHashtableHashFunction( + _In_ PVOID Entry + ) +{ + return HandleToUlong((*(PPH_HANDLE_NODE *)Entry)->Handle) / 4; +} + +VOID PhLoadSettingsHandleList( + _Inout_ PPH_HANDLE_LIST_CONTEXT Context + ) +{ + PPH_STRING settings; + PPH_STRING sortSettings; + + settings = PhGetStringSetting(L"HandleTreeListColumns"); + sortSettings = PhGetStringSetting(L"HandleTreeListSort"); + PhCmLoadSettingsEx(Context->TreeNewHandle, &Context->Cm, 0, &settings->sr, &sortSettings->sr); + PhDereferenceObject(settings); + PhDereferenceObject(sortSettings); +} + +VOID PhSaveSettingsHandleList( + _Inout_ PPH_HANDLE_LIST_CONTEXT Context + ) +{ + PPH_STRING settings; + PPH_STRING sortSettings; + + settings = PhCmSaveSettingsEx(Context->TreeNewHandle, &Context->Cm, 0, &sortSettings); + PhSetStringSetting2(L"HandleTreeListColumns", &settings->sr); + PhSetStringSetting2(L"HandleTreeListSort", &sortSettings->sr); + PhDereferenceObject(settings); + PhDereferenceObject(sortSettings); +} + +VOID PhSetOptionsHandleList( + _Inout_ PPH_HANDLE_LIST_CONTEXT Context, + _In_ BOOLEAN HideUnnamedHandles + ) +{ + if (Context->HideUnnamedHandles != HideUnnamedHandles) + { + Context->HideUnnamedHandles = HideUnnamedHandles; + } +} + +PPH_HANDLE_NODE PhAddHandleNode( + _Inout_ PPH_HANDLE_LIST_CONTEXT Context, + _In_ PPH_HANDLE_ITEM HandleItem, + _In_ ULONG RunId + ) +{ + PPH_HANDLE_NODE handleNode; + + handleNode = PhAllocate(PhEmGetObjectSize(EmHandleNodeType, sizeof(PH_HANDLE_NODE))); + memset(handleNode, 0, sizeof(PH_HANDLE_NODE)); + PhInitializeTreeNewNode(&handleNode->Node); + + if (Context->EnableStateHighlighting && RunId != 1) + { + PhChangeShStateTn( + &handleNode->Node, + &handleNode->ShState, + &Context->NodeStateList, + NewItemState, + PhCsColorNew, + NULL + ); + } + + handleNode->Handle = HandleItem->Handle; + handleNode->HandleItem = HandleItem; + PhReferenceObject(HandleItem); + + memset(handleNode->TextCache, 0, sizeof(PH_STRINGREF) * PHHNTLC_MAXIMUM); + handleNode->Node.TextCache = handleNode->TextCache; + handleNode->Node.TextCacheSize = PHHNTLC_MAXIMUM; + + PhAddEntryHashtable(Context->NodeHashtable, &handleNode); + PhAddItemList(Context->NodeList, handleNode); + + if (Context->TreeFilterSupport.FilterList) + handleNode->Node.Visible = PhApplyTreeNewFiltersToNode(&Context->TreeFilterSupport, &handleNode->Node); + + PhEmCallObjectOperation(EmHandleNodeType, handleNode, EmObjectCreate); + + TreeNew_NodesStructured(Context->TreeNewHandle); + + return handleNode; +} + +PPH_HANDLE_NODE PhFindHandleNode( + _In_ PPH_HANDLE_LIST_CONTEXT Context, + _In_ HANDLE Handle + ) +{ + PH_HANDLE_NODE lookupHandleNode; + PPH_HANDLE_NODE lookupHandleNodePtr = &lookupHandleNode; + PPH_HANDLE_NODE *handleNode; + + lookupHandleNode.Handle = Handle; + + handleNode = (PPH_HANDLE_NODE *)PhFindEntryHashtable( + Context->NodeHashtable, + &lookupHandleNodePtr + ); + + if (handleNode) + return *handleNode; + else + return NULL; +} + +VOID PhRemoveHandleNode( + _In_ PPH_HANDLE_LIST_CONTEXT Context, + _In_ PPH_HANDLE_NODE HandleNode + ) +{ + // Remove from the hashtable here to avoid problems in case the key is re-used. + PhRemoveEntryHashtable(Context->NodeHashtable, &HandleNode); + + if (Context->EnableStateHighlighting) + { + PhChangeShStateTn( + &HandleNode->Node, + &HandleNode->ShState, + &Context->NodeStateList, + RemovingItemState, + PhCsColorRemoved, + Context->TreeNewHandle + ); + } + else + { + PhpRemoveHandleNode(HandleNode, Context); + } +} + +VOID PhpDestroyHandleNode( + _In_ PPH_HANDLE_NODE HandleNode + ) +{ + PhEmCallObjectOperation(EmHandleNodeType, HandleNode, EmObjectDelete); + + if (HandleNode->GrantedAccessSymbolicText) PhDereferenceObject(HandleNode->GrantedAccessSymbolicText); + + PhDereferenceObject(HandleNode->HandleItem); + + PhFree(HandleNode); +} + +VOID PhpRemoveHandleNode( + _In_ PPH_HANDLE_NODE HandleNode, + _In_ PPH_HANDLE_LIST_CONTEXT Context // PH_TICK_SH_STATE requires this parameter to be after HandleNode + ) +{ + ULONG index; + + // Remove from list and cleanup. + + if ((index = PhFindItemList(Context->NodeList, HandleNode)) != -1) + PhRemoveItemList(Context->NodeList, index); + + PhpDestroyHandleNode(HandleNode); + + TreeNew_NodesStructured(Context->TreeNewHandle); +} + +VOID PhUpdateHandleNode( + _In_ PPH_HANDLE_LIST_CONTEXT Context, + _In_ PPH_HANDLE_NODE HandleNode + ) +{ + memset(HandleNode->TextCache, 0, sizeof(PH_STRINGREF) * PHHNTLC_MAXIMUM); + + PhInvalidateTreeNewNode(&HandleNode->Node, TN_CACHE_COLOR); + TreeNew_NodesStructured(Context->TreeNewHandle); +} + +VOID PhExpandAllHandleNodes( + _In_ PPH_HANDLE_LIST_CONTEXT Context, + _In_ BOOLEAN Expand + ) +{ + ULONG i; + BOOLEAN needsRestructure = FALSE; + + for (i = 0; i < Context->NodeList->Count; i++) + { + PPH_HANDLE_NODE node = Context->NodeList->Items[i]; + + if (node->Node.Expanded != Expand) + { + node->Node.Expanded = Expand; + needsRestructure = TRUE; + } + } + + if (needsRestructure) + TreeNew_NodesStructured(Context->TreeNewHandle); +} + +VOID PhTickHandleNodes( + _In_ PPH_HANDLE_LIST_CONTEXT Context + ) +{ + PH_TICK_SH_STATE_TN(PH_HANDLE_NODE, ShState, Context->NodeStateList, PhpRemoveHandleNode, PhCsHighlightingDuration, Context->TreeNewHandle, TRUE, NULL, Context); +} + +#define SORT_FUNCTION(Column) PhpHandleTreeNewCompare##Column + +#define BEGIN_SORT_FUNCTION(Column) static int __cdecl PhpHandleTreeNewCompare##Column( \ + _In_ void *_context, \ + _In_ const void *_elem1, \ + _In_ const void *_elem2 \ + ) \ +{ \ + PPH_HANDLE_NODE node1 = *(PPH_HANDLE_NODE *)_elem1; \ + PPH_HANDLE_NODE node2 = *(PPH_HANDLE_NODE *)_elem2; \ + PPH_HANDLE_ITEM handleItem1 = node1->HandleItem; \ + PPH_HANDLE_ITEM handleItem2 = node2->HandleItem; \ + PPH_HANDLE_LIST_CONTEXT context = (PPH_HANDLE_LIST_CONTEXT)_context; \ + int sortResult = 0; + +#define END_SORT_FUNCTION \ + if (sortResult == 0) \ + sortResult = uintptrcmp((ULONG_PTR)node1->Handle, (ULONG_PTR)node2->Handle); \ + \ + return PhModifySort(sortResult, context->TreeNewSortOrder); \ +} + +LONG PhpHandleTreeNewPostSortFunction( + _In_ LONG Result, + _In_ PVOID Node1, + _In_ PVOID Node2, + _In_ PH_SORT_ORDER SortOrder + ) +{ + if (Result == 0) + Result = uintptrcmp((ULONG_PTR)((PPH_HANDLE_NODE)Node1)->Handle, (ULONG_PTR)((PPH_HANDLE_NODE)Node2)->Handle); + + return PhModifySort(Result, SortOrder); +} + +BEGIN_SORT_FUNCTION(Type) +{ + sortResult = PhCompareString(handleItem1->TypeName, handleItem2->TypeName, TRUE); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(Name) +{ + sortResult = PhCompareStringWithNull(handleItem1->BestObjectName, handleItem2->BestObjectName, TRUE); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(Handle) +{ + sortResult = uintptrcmp((ULONG_PTR)node1->Handle, (ULONG_PTR)node2->Handle); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(ObjectAddress) +{ + sortResult = uintptrcmp((ULONG_PTR)handleItem1->Object, (ULONG_PTR)handleItem2->Object); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(Attributes) +{ + sortResult = uintcmp(handleItem1->Attributes, handleItem2->Attributes); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(GrantedAccess) +{ + sortResult = uintcmp(handleItem1->GrantedAccess, handleItem2->GrantedAccess); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(OriginalName) +{ + sortResult = PhCompareStringWithNull(handleItem1->ObjectName, handleItem2->ObjectName, TRUE); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(FileShareAccess) +{ + sortResult = uintcmp(handleItem1->FileFlags & (PH_HANDLE_FILE_SHARED_MASK), handleItem2->FileFlags & (PH_HANDLE_FILE_SHARED_MASK)); + + // Make sure all file handles get grouped together regardless of share access. + if (sortResult == 0) + sortResult = intcmp(PhEqualString2(handleItem1->TypeName, L"File", TRUE), PhEqualString2(handleItem2->TypeName, L"File", TRUE)); +} +END_SORT_FUNCTION + +BOOLEAN NTAPI PhpHandleTreeNewCallback( + _In_ HWND hwnd, + _In_ PH_TREENEW_MESSAGE Message, + _In_opt_ PVOID Parameter1, + _In_opt_ PVOID Parameter2, + _In_opt_ PVOID Context + ) +{ + PPH_HANDLE_LIST_CONTEXT context; + PPH_HANDLE_NODE node; + + context = Context; + + if (PhCmForwardMessage(hwnd, Message, Parameter1, Parameter2, &context->Cm)) + return TRUE; + + switch (Message) + { + case TreeNewGetChildren: + { + PPH_TREENEW_GET_CHILDREN getChildren = Parameter1; + + if (!getChildren->Node) + { + static PVOID sortFunctions[] = + { + SORT_FUNCTION(Type), + SORT_FUNCTION(Name), + SORT_FUNCTION(Handle), + SORT_FUNCTION(ObjectAddress), + SORT_FUNCTION(Attributes), + SORT_FUNCTION(GrantedAccess), + SORT_FUNCTION(GrantedAccess), // Granted Access (Symbolic) + SORT_FUNCTION(OriginalName), + SORT_FUNCTION(FileShareAccess) + }; + int (__cdecl *sortFunction)(void *, const void *, const void *); + + if (!PhCmForwardSort( + (PPH_TREENEW_NODE *)context->NodeList->Items, + context->NodeList->Count, + context->TreeNewSortColumn, + context->TreeNewSortOrder, + &context->Cm + )) + { + if (context->TreeNewSortColumn < PHHNTLC_MAXIMUM) + sortFunction = sortFunctions[context->TreeNewSortColumn]; + else + sortFunction = NULL; + } + else + { + sortFunction = NULL; + } + + if (sortFunction) + { + qsort_s(context->NodeList->Items, context->NodeList->Count, sizeof(PVOID), sortFunction, context); + } + + getChildren->Children = (PPH_TREENEW_NODE *)context->NodeList->Items; + getChildren->NumberOfChildren = context->NodeList->Count; + } + } + return TRUE; + case TreeNewIsLeaf: + { + PPH_TREENEW_IS_LEAF isLeaf = Parameter1; + + isLeaf->IsLeaf = TRUE; + } + return TRUE; + case TreeNewGetCellText: + { + PPH_TREENEW_GET_CELL_TEXT getCellText = Parameter1; + PPH_HANDLE_ITEM handleItem; + + node = (PPH_HANDLE_NODE)getCellText->Node; + handleItem = node->HandleItem; + + switch (getCellText->Id) + { + case PHHNTLC_TYPE: + getCellText->Text = handleItem->TypeName->sr; + break; + case PHHNTLC_NAME: + getCellText->Text = PhGetStringRef(handleItem->BestObjectName); + break; + case PHHNTLC_HANDLE: + PhInitializeStringRefLongHint(&getCellText->Text, handleItem->HandleString); + break; + case PHHNTLC_OBJECTADDRESS: + PhInitializeStringRefLongHint(&getCellText->Text, handleItem->ObjectString); + break; + case PHHNTLC_ATTRIBUTES: + switch (handleItem->Attributes & (OBJ_PROTECT_CLOSE | OBJ_INHERIT)) + { + case OBJ_PROTECT_CLOSE: + PhInitializeStringRef(&getCellText->Text, L"Protected"); + break; + case OBJ_INHERIT: + PhInitializeStringRef(&getCellText->Text, L"Inherit"); + break; + case OBJ_PROTECT_CLOSE | OBJ_INHERIT: + PhInitializeStringRef(&getCellText->Text, L"Protected, Inherit"); + break; + } + break; + case PHHNTLC_GRANTEDACCESS: + PhInitializeStringRefLongHint(&getCellText->Text, handleItem->GrantedAccessString); + break; + case PHHNTLC_GRANTEDACCESSSYMBOLIC: + if (handleItem->GrantedAccess != 0) + { + if (!node->GrantedAccessSymbolicText) + { + PPH_ACCESS_ENTRY accessEntries; + ULONG numberOfAccessEntries; + + if (PhGetAccessEntries(handleItem->TypeName->Buffer, &accessEntries, &numberOfAccessEntries)) + { + node->GrantedAccessSymbolicText = PhGetAccessString(handleItem->GrantedAccess, accessEntries, numberOfAccessEntries); + PhFree(accessEntries); + } + else + { + node->GrantedAccessSymbolicText = PhReferenceEmptyString(); + } + } + + if (node->GrantedAccessSymbolicText->Length != 0) + getCellText->Text = node->GrantedAccessSymbolicText->sr; + else + PhInitializeStringRefLongHint(&getCellText->Text, handleItem->GrantedAccessString); + } + break; + case PHHNTLC_ORIGINALNAME: + getCellText->Text = PhGetStringRef(handleItem->ObjectName); + break; + case PHHNTLC_FILESHAREACCESS: + if (handleItem->FileFlags & PH_HANDLE_FILE_SHARED_MASK) + { + node->FileShareAccessText[0] = '-'; + node->FileShareAccessText[1] = '-'; + node->FileShareAccessText[2] = '-'; + node->FileShareAccessText[3] = 0; + + if (handleItem->FileFlags & PH_HANDLE_FILE_SHARED_READ) + node->FileShareAccessText[0] = 'R'; + if (handleItem->FileFlags & PH_HANDLE_FILE_SHARED_WRITE) + node->FileShareAccessText[1] = 'W'; + if (handleItem->FileFlags & PH_HANDLE_FILE_SHARED_DELETE) + node->FileShareAccessText[2] = 'D'; + + PhInitializeStringRef(&getCellText->Text, node->FileShareAccessText); + } + break; + default: + return FALSE; + } + + getCellText->Flags = TN_CACHE; + } + return TRUE; + case TreeNewGetNodeColor: + { + PPH_TREENEW_GET_NODE_COLOR getNodeColor = Parameter1; + PPH_HANDLE_ITEM handleItem; + + node = (PPH_HANDLE_NODE)getNodeColor->Node; + handleItem = node->HandleItem; + + if (!handleItem) + ; // Dummy + else if (PhCsUseColorProtectedHandles && (handleItem->Attributes & OBJ_PROTECT_CLOSE)) + getNodeColor->BackColor = PhCsColorProtectedHandles; + else if (PhCsUseColorInheritHandles && (handleItem->Attributes & OBJ_INHERIT)) + getNodeColor->BackColor = PhCsColorInheritHandles; + + getNodeColor->Flags = TN_CACHE | TN_AUTO_FORECOLOR; + } + return TRUE; + case TreeNewSortChanged: + { + TreeNew_GetSort(hwnd, &context->TreeNewSortColumn, &context->TreeNewSortOrder); + // Force a rebuild to sort the items. + TreeNew_NodesStructured(hwnd); + } + return TRUE; + case TreeNewKeyDown: + { + PPH_TREENEW_KEY_EVENT keyEvent = Parameter1; + + switch (keyEvent->VirtualKey) + { + case 'C': + if (GetKeyState(VK_CONTROL) < 0) + SendMessage(context->ParentWindowHandle, WM_COMMAND, ID_HANDLE_COPY, 0); + break; + case 'A': + if (GetKeyState(VK_CONTROL) < 0) + TreeNew_SelectRange(context->TreeNewHandle, 0, -1); + break; + case VK_DELETE: + // Pass a 1 in lParam to indicate that warnings should be enabled. + SendMessage(context->ParentWindowHandle, WM_COMMAND, ID_HANDLE_CLOSE, 1); + break; + case VK_RETURN: + if (GetKeyState(VK_CONTROL) >= 0) + SendMessage(context->ParentWindowHandle, WM_COMMAND, ID_HANDLE_PROPERTIES, 0); + else + SendMessage(context->ParentWindowHandle, WM_COMMAND, ID_HANDLE_OBJECTPROPERTIES1, 0); + break; + } + } + return TRUE; + case TreeNewHeaderRightClick: + { + PH_TN_COLUMN_MENU_DATA data; + + data.TreeNewHandle = hwnd; + data.MouseEvent = Parameter1; + data.DefaultSortColumn = 0; + data.DefaultSortOrder = AscendingSortOrder; + PhInitializeTreeNewColumnMenu(&data); + + data.Selection = PhShowEMenu(data.Menu, hwnd, PH_EMENU_SHOW_LEFTRIGHT, + PH_ALIGN_LEFT | PH_ALIGN_TOP, data.MouseEvent->ScreenLocation.x, data.MouseEvent->ScreenLocation.y); + PhHandleTreeNewColumnMenu(&data); + PhDeleteTreeNewColumnMenu(&data); + } + return TRUE; + case TreeNewLeftDoubleClick: + { + SendMessage(context->ParentWindowHandle, WM_COMMAND, ID_HANDLE_PROPERTIES, 0); + } + return TRUE; + case TreeNewContextMenu: + { + PPH_TREENEW_CONTEXT_MENU contextMenu = Parameter1; + + SendMessage(context->ParentWindowHandle, WM_COMMAND, ID_SHOWCONTEXTMENU, (LPARAM)contextMenu); + } + return TRUE; + case TreeNewGetDialogCode: + { + PULONG code = Parameter2; + + if (PtrToUlong(Parameter1) == VK_RETURN) + { + *code = DLGC_WANTMESSAGE; + return TRUE; + } + } + return FALSE; + } + + return FALSE; +} + +PPH_HANDLE_ITEM PhGetSelectedHandleItem( + _In_ PPH_HANDLE_LIST_CONTEXT Context + ) +{ + PPH_HANDLE_ITEM handleItem = NULL; + ULONG i; + + for (i = 0; i < Context->NodeList->Count; i++) + { + PPH_HANDLE_NODE node = Context->NodeList->Items[i]; + + if (node->Node.Selected) + { + handleItem = node->HandleItem; + break; + } + } + + return handleItem; +} + +VOID PhGetSelectedHandleItems( + _In_ PPH_HANDLE_LIST_CONTEXT Context, + _Out_ PPH_HANDLE_ITEM **Handles, + _Out_ PULONG NumberOfHandles + ) +{ + PH_ARRAY array; + ULONG i; + + PhInitializeArray(&array, sizeof(PVOID), 2); + + for (i = 0; i < Context->NodeList->Count; i++) + { + PPH_HANDLE_NODE node = Context->NodeList->Items[i]; + + if (node->Node.Selected) + PhAddItemArray(&array, &node->HandleItem); + } + + *NumberOfHandles = (ULONG)array.Count; + *Handles = PhFinalArrayItems(&array); +} + +VOID PhDeselectAllHandleNodes( + _In_ PPH_HANDLE_LIST_CONTEXT Context + ) +{ + TreeNew_DeselectRange(Context->TreeNewHandle, 0, -1); +} diff --git a/ProcessHacker/hndlprp.c b/ProcessHacker/hndlprp.c index 4c1123c36cf2..339a95476d44 100644 --- a/ProcessHacker/hndlprp.c +++ b/ProcessHacker/hndlprp.c @@ -1,336 +1,336 @@ -/* - * Process Hacker - - * handle properties - * - * Copyright (C) 2010-2013 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include - -#include -#include -#include - -#include -#include - -typedef struct _HANDLE_PROPERTIES_CONTEXT -{ - HANDLE ProcessId; - PPH_HANDLE_ITEM HandleItem; -} HANDLE_PROPERTIES_CONTEXT, *PHANDLE_PROPERTIES_CONTEXT; - -INT_PTR CALLBACK PhpHandleGeneralDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -static NTSTATUS PhpDuplicateHandleFromProcess( - _Out_ PHANDLE Handle, - _In_ ACCESS_MASK DesiredAccess, - _In_opt_ PVOID Context - ) -{ - NTSTATUS status; - PHANDLE_PROPERTIES_CONTEXT context = Context; - HANDLE processHandle; - - if (!NT_SUCCESS(status = PhOpenProcess( - &processHandle, - PROCESS_DUP_HANDLE, - context->ProcessId - ))) - return status; - - status = NtDuplicateObject( - processHandle, - context->HandleItem->Handle, - NtCurrentProcess(), - Handle, - DesiredAccess, - 0, - 0 - ); - NtClose(processHandle); - - return status; -} - -VOID PhShowHandleProperties( - _In_ HWND ParentWindowHandle, - _In_ HANDLE ProcessId, - _In_ PPH_HANDLE_ITEM HandleItem - ) -{ - PROPSHEETHEADER propSheetHeader = { sizeof(propSheetHeader) }; - PROPSHEETPAGE propSheetPage; - HPROPSHEETPAGE pages[16]; - HANDLE_PROPERTIES_CONTEXT context; - PH_STD_OBJECT_SECURITY stdObjectSecurity; - PPH_ACCESS_ENTRY accessEntries; - ULONG numberOfAccessEntries; - - context.ProcessId = ProcessId; - context.HandleItem = HandleItem; - - propSheetHeader.dwFlags = - PSH_NOAPPLYNOW | - PSH_NOCONTEXTHELP | - PSH_PROPTITLE; - propSheetHeader.hwndParent = ParentWindowHandle; - propSheetHeader.pszCaption = L"Handle"; - propSheetHeader.nPages = 0; - propSheetHeader.nStartPage = 0; - propSheetHeader.phpage = pages; - - // General page - memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); - propSheetPage.dwSize = sizeof(PROPSHEETPAGE); - propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_HNDLGENERAL); - propSheetPage.pfnDlgProc = PhpHandleGeneralDlgProc; - propSheetPage.lParam = (LPARAM)&context; - pages[propSheetHeader.nPages++] = CreatePropertySheetPage(&propSheetPage); - - // Object-specific page - if (!HandleItem->TypeName) - { - // Dummy - } - else if (PhEqualString2(HandleItem->TypeName, L"Event", TRUE)) - { - pages[propSheetHeader.nPages++] = PhCreateEventPage( - PhpDuplicateHandleFromProcess, - &context - ); - } - else if (PhEqualString2(HandleItem->TypeName, L"EventPair", TRUE)) - { - pages[propSheetHeader.nPages++] = PhCreateEventPairPage( - PhpDuplicateHandleFromProcess, - &context - ); - } - else if (PhEqualString2(HandleItem->TypeName, L"Job", TRUE)) - { - pages[propSheetHeader.nPages++] = PhCreateJobPage( - PhpDuplicateHandleFromProcess, - &context, - NULL - ); - } - else if (PhEqualString2(HandleItem->TypeName, L"Mutant", TRUE)) - { - pages[propSheetHeader.nPages++] = PhCreateMutantPage( - PhpDuplicateHandleFromProcess, - &context - ); - } - else if (PhEqualString2(HandleItem->TypeName, L"Section", TRUE)) - { - pages[propSheetHeader.nPages++] = PhCreateSectionPage( - PhpDuplicateHandleFromProcess, - &context - ); - } - else if (PhEqualString2(HandleItem->TypeName, L"Semaphore", TRUE)) - { - pages[propSheetHeader.nPages++] = PhCreateSemaphorePage( - PhpDuplicateHandleFromProcess, - &context - ); - } - else if (PhEqualString2(HandleItem->TypeName, L"Timer", TRUE)) - { - pages[propSheetHeader.nPages++] = PhCreateTimerPage( - PhpDuplicateHandleFromProcess, - &context - ); - } - else if (PhEqualString2(HandleItem->TypeName, L"Token", TRUE)) - { - pages[propSheetHeader.nPages++] = PhCreateTokenPage( - PhpDuplicateHandleFromProcess, - &context, - NULL - ); - } - - // Security page - stdObjectSecurity.OpenObject = PhpDuplicateHandleFromProcess; - stdObjectSecurity.ObjectType = HandleItem->TypeName->Buffer; - stdObjectSecurity.Context = &context; - - if (PhGetAccessEntries(HandleItem->TypeName->Buffer, &accessEntries, &numberOfAccessEntries)) - { - pages[propSheetHeader.nPages++] = PhCreateSecurityPage( - PhGetStringOrEmpty(HandleItem->BestObjectName), - PhStdGetObjectSecurity, - PhStdSetObjectSecurity, - &stdObjectSecurity, - accessEntries, - numberOfAccessEntries - ); - PhFree(accessEntries); - } - - if (PhPluginsEnabled) - { - PH_PLUGIN_OBJECT_PROPERTIES objectProperties; - PH_PLUGIN_HANDLE_PROPERTIES_CONTEXT propertiesContext; - - propertiesContext.ProcessId = ProcessId; - propertiesContext.HandleItem = HandleItem; - - objectProperties.Parameter = &propertiesContext; - objectProperties.NumberOfPages = propSheetHeader.nPages; - objectProperties.MaximumNumberOfPages = sizeof(pages) / sizeof(HPROPSHEETPAGE); - objectProperties.Pages = pages; - - PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackHandlePropertiesInitializing), &objectProperties); - - propSheetHeader.nPages = objectProperties.NumberOfPages; - } - - PhModalPropertySheet(&propSheetHeader); -} - -INT_PTR CALLBACK PhpHandleGeneralDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - switch (uMsg) - { - case WM_INITDIALOG: - { - LPPROPSHEETPAGE propSheetPage = (LPPROPSHEETPAGE)lParam; - PHANDLE_PROPERTIES_CONTEXT context = (PHANDLE_PROPERTIES_CONTEXT)propSheetPage->lParam; - PPH_ACCESS_ENTRY accessEntries; - ULONG numberOfAccessEntries; - HANDLE processHandle; - OBJECT_BASIC_INFORMATION basicInfo; - BOOLEAN haveBasicInfo = FALSE; - - // HACK - PhCenterWindow(GetParent(hwndDlg), GetParent(GetParent(hwndDlg))); - - SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)context); - - SetDlgItemText(hwndDlg, IDC_NAME, PhGetString(context->HandleItem->BestObjectName)); - SetDlgItemText(hwndDlg, IDC_TYPE, context->HandleItem->TypeName->Buffer); - SetDlgItemText(hwndDlg, IDC_ADDRESS, context->HandleItem->ObjectString); - - if (PhGetAccessEntries( - context->HandleItem->TypeName->Buffer, - &accessEntries, - &numberOfAccessEntries - )) - { - PPH_STRING accessString; - PPH_STRING grantedAccessString; - - accessString = PH_AUTO(PhGetAccessString( - context->HandleItem->GrantedAccess, - accessEntries, - numberOfAccessEntries - )); - - if (accessString->Length != 0) - { - grantedAccessString = PhaFormatString( - L"%s (%s)", - context->HandleItem->GrantedAccessString, - accessString->Buffer - ); - SetDlgItemText(hwndDlg, IDC_GRANTED_ACCESS, grantedAccessString->Buffer); - } - else - { - SetDlgItemText(hwndDlg, IDC_GRANTED_ACCESS, context->HandleItem->GrantedAccessString); - } - - PhFree(accessEntries); - } - else - { - SetDlgItemText(hwndDlg, IDC_GRANTED_ACCESS, context->HandleItem->GrantedAccessString); - } - - if (NT_SUCCESS(PhOpenProcess( - &processHandle, - PROCESS_DUP_HANDLE, - context->ProcessId - ))) - { - if (NT_SUCCESS(PhGetHandleInformation( - processHandle, - context->HandleItem->Handle, - -1, - &basicInfo, - NULL, - NULL, - NULL - ))) - { - SetDlgItemInt(hwndDlg, IDC_REFERENCES, basicInfo.PointerCount, FALSE); - SetDlgItemInt(hwndDlg, IDC_HANDLES, basicInfo.HandleCount, FALSE); - SetDlgItemInt(hwndDlg, IDC_PAGED, basicInfo.PagedPoolCharge, FALSE); - SetDlgItemInt(hwndDlg, IDC_NONPAGED, basicInfo.NonPagedPoolCharge, FALSE); - - haveBasicInfo = TRUE; - } - - NtClose(processHandle); - } - - if (!haveBasicInfo) - { - SetDlgItemText(hwndDlg, IDC_REFERENCES, L"Unknown"); - SetDlgItemText(hwndDlg, IDC_HANDLES, L"Unknown"); - SetDlgItemText(hwndDlg, IDC_PAGED, L"Unknown"); - SetDlgItemText(hwndDlg, IDC_NONPAGED, L"Unknown"); - } - } - break; - case WM_DESTROY: - { - RemoveProp(hwndDlg, PhMakeContextAtom()); - } - break; - case WM_NOTIFY: - { - LPNMHDR header = (LPNMHDR)lParam; - - switch (header->code) - { - case PSN_QUERYINITIALFOCUS: - { - SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, (LONG_PTR)GetDlgItem(hwndDlg, IDC_BASICINFORMATION)); - } - return TRUE; - } - } - break; - } - - return FALSE; -} +/* + * Process Hacker - + * handle properties + * + * Copyright (C) 2010-2013 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include + +#include +#include +#include + +#include +#include + +typedef struct _HANDLE_PROPERTIES_CONTEXT +{ + HANDLE ProcessId; + PPH_HANDLE_ITEM HandleItem; +} HANDLE_PROPERTIES_CONTEXT, *PHANDLE_PROPERTIES_CONTEXT; + +INT_PTR CALLBACK PhpHandleGeneralDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +static NTSTATUS PhpDuplicateHandleFromProcess( + _Out_ PHANDLE Handle, + _In_ ACCESS_MASK DesiredAccess, + _In_opt_ PVOID Context + ) +{ + NTSTATUS status; + PHANDLE_PROPERTIES_CONTEXT context = Context; + HANDLE processHandle; + + if (!NT_SUCCESS(status = PhOpenProcess( + &processHandle, + PROCESS_DUP_HANDLE, + context->ProcessId + ))) + return status; + + status = NtDuplicateObject( + processHandle, + context->HandleItem->Handle, + NtCurrentProcess(), + Handle, + DesiredAccess, + 0, + 0 + ); + NtClose(processHandle); + + return status; +} + +VOID PhShowHandleProperties( + _In_ HWND ParentWindowHandle, + _In_ HANDLE ProcessId, + _In_ PPH_HANDLE_ITEM HandleItem + ) +{ + PROPSHEETHEADER propSheetHeader = { sizeof(propSheetHeader) }; + PROPSHEETPAGE propSheetPage; + HPROPSHEETPAGE pages[16]; + HANDLE_PROPERTIES_CONTEXT context; + PH_STD_OBJECT_SECURITY stdObjectSecurity; + PPH_ACCESS_ENTRY accessEntries; + ULONG numberOfAccessEntries; + + context.ProcessId = ProcessId; + context.HandleItem = HandleItem; + + propSheetHeader.dwFlags = + PSH_NOAPPLYNOW | + PSH_NOCONTEXTHELP | + PSH_PROPTITLE; + propSheetHeader.hwndParent = ParentWindowHandle; + propSheetHeader.pszCaption = L"Handle"; + propSheetHeader.nPages = 0; + propSheetHeader.nStartPage = 0; + propSheetHeader.phpage = pages; + + // General page + memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); + propSheetPage.dwSize = sizeof(PROPSHEETPAGE); + propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_HNDLGENERAL); + propSheetPage.pfnDlgProc = PhpHandleGeneralDlgProc; + propSheetPage.lParam = (LPARAM)&context; + pages[propSheetHeader.nPages++] = CreatePropertySheetPage(&propSheetPage); + + // Object-specific page + if (!HandleItem->TypeName) + { + // Dummy + } + else if (PhEqualString2(HandleItem->TypeName, L"Event", TRUE)) + { + pages[propSheetHeader.nPages++] = PhCreateEventPage( + PhpDuplicateHandleFromProcess, + &context + ); + } + else if (PhEqualString2(HandleItem->TypeName, L"EventPair", TRUE)) + { + pages[propSheetHeader.nPages++] = PhCreateEventPairPage( + PhpDuplicateHandleFromProcess, + &context + ); + } + else if (PhEqualString2(HandleItem->TypeName, L"Job", TRUE)) + { + pages[propSheetHeader.nPages++] = PhCreateJobPage( + PhpDuplicateHandleFromProcess, + &context, + NULL + ); + } + else if (PhEqualString2(HandleItem->TypeName, L"Mutant", TRUE)) + { + pages[propSheetHeader.nPages++] = PhCreateMutantPage( + PhpDuplicateHandleFromProcess, + &context + ); + } + else if (PhEqualString2(HandleItem->TypeName, L"Section", TRUE)) + { + pages[propSheetHeader.nPages++] = PhCreateSectionPage( + PhpDuplicateHandleFromProcess, + &context + ); + } + else if (PhEqualString2(HandleItem->TypeName, L"Semaphore", TRUE)) + { + pages[propSheetHeader.nPages++] = PhCreateSemaphorePage( + PhpDuplicateHandleFromProcess, + &context + ); + } + else if (PhEqualString2(HandleItem->TypeName, L"Timer", TRUE)) + { + pages[propSheetHeader.nPages++] = PhCreateTimerPage( + PhpDuplicateHandleFromProcess, + &context + ); + } + else if (PhEqualString2(HandleItem->TypeName, L"Token", TRUE)) + { + pages[propSheetHeader.nPages++] = PhCreateTokenPage( + PhpDuplicateHandleFromProcess, + &context, + NULL + ); + } + + // Security page + stdObjectSecurity.OpenObject = PhpDuplicateHandleFromProcess; + stdObjectSecurity.ObjectType = HandleItem->TypeName->Buffer; + stdObjectSecurity.Context = &context; + + if (PhGetAccessEntries(HandleItem->TypeName->Buffer, &accessEntries, &numberOfAccessEntries)) + { + pages[propSheetHeader.nPages++] = PhCreateSecurityPage( + PhGetStringOrEmpty(HandleItem->BestObjectName), + PhStdGetObjectSecurity, + PhStdSetObjectSecurity, + &stdObjectSecurity, + accessEntries, + numberOfAccessEntries + ); + PhFree(accessEntries); + } + + if (PhPluginsEnabled) + { + PH_PLUGIN_OBJECT_PROPERTIES objectProperties; + PH_PLUGIN_HANDLE_PROPERTIES_CONTEXT propertiesContext; + + propertiesContext.ProcessId = ProcessId; + propertiesContext.HandleItem = HandleItem; + + objectProperties.Parameter = &propertiesContext; + objectProperties.NumberOfPages = propSheetHeader.nPages; + objectProperties.MaximumNumberOfPages = sizeof(pages) / sizeof(HPROPSHEETPAGE); + objectProperties.Pages = pages; + + PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackHandlePropertiesInitializing), &objectProperties); + + propSheetHeader.nPages = objectProperties.NumberOfPages; + } + + PhModalPropertySheet(&propSheetHeader); +} + +INT_PTR CALLBACK PhpHandleGeneralDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + switch (uMsg) + { + case WM_INITDIALOG: + { + LPPROPSHEETPAGE propSheetPage = (LPPROPSHEETPAGE)lParam; + PHANDLE_PROPERTIES_CONTEXT context = (PHANDLE_PROPERTIES_CONTEXT)propSheetPage->lParam; + PPH_ACCESS_ENTRY accessEntries; + ULONG numberOfAccessEntries; + HANDLE processHandle; + OBJECT_BASIC_INFORMATION basicInfo; + BOOLEAN haveBasicInfo = FALSE; + + // HACK + PhCenterWindow(GetParent(hwndDlg), GetParent(GetParent(hwndDlg))); + + SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)context); + + SetDlgItemText(hwndDlg, IDC_NAME, PhGetString(context->HandleItem->BestObjectName)); + SetDlgItemText(hwndDlg, IDC_TYPE, context->HandleItem->TypeName->Buffer); + SetDlgItemText(hwndDlg, IDC_ADDRESS, context->HandleItem->ObjectString); + + if (PhGetAccessEntries( + context->HandleItem->TypeName->Buffer, + &accessEntries, + &numberOfAccessEntries + )) + { + PPH_STRING accessString; + PPH_STRING grantedAccessString; + + accessString = PH_AUTO(PhGetAccessString( + context->HandleItem->GrantedAccess, + accessEntries, + numberOfAccessEntries + )); + + if (accessString->Length != 0) + { + grantedAccessString = PhaFormatString( + L"%s (%s)", + context->HandleItem->GrantedAccessString, + accessString->Buffer + ); + SetDlgItemText(hwndDlg, IDC_GRANTED_ACCESS, grantedAccessString->Buffer); + } + else + { + SetDlgItemText(hwndDlg, IDC_GRANTED_ACCESS, context->HandleItem->GrantedAccessString); + } + + PhFree(accessEntries); + } + else + { + SetDlgItemText(hwndDlg, IDC_GRANTED_ACCESS, context->HandleItem->GrantedAccessString); + } + + if (NT_SUCCESS(PhOpenProcess( + &processHandle, + PROCESS_DUP_HANDLE, + context->ProcessId + ))) + { + if (NT_SUCCESS(PhGetHandleInformation( + processHandle, + context->HandleItem->Handle, + -1, + &basicInfo, + NULL, + NULL, + NULL + ))) + { + SetDlgItemInt(hwndDlg, IDC_REFERENCES, basicInfo.PointerCount, FALSE); + SetDlgItemInt(hwndDlg, IDC_HANDLES, basicInfo.HandleCount, FALSE); + SetDlgItemInt(hwndDlg, IDC_PAGED, basicInfo.PagedPoolCharge, FALSE); + SetDlgItemInt(hwndDlg, IDC_NONPAGED, basicInfo.NonPagedPoolCharge, FALSE); + + haveBasicInfo = TRUE; + } + + NtClose(processHandle); + } + + if (!haveBasicInfo) + { + SetDlgItemText(hwndDlg, IDC_REFERENCES, L"Unknown"); + SetDlgItemText(hwndDlg, IDC_HANDLES, L"Unknown"); + SetDlgItemText(hwndDlg, IDC_PAGED, L"Unknown"); + SetDlgItemText(hwndDlg, IDC_NONPAGED, L"Unknown"); + } + } + break; + case WM_DESTROY: + { + RemoveProp(hwndDlg, PhMakeContextAtom()); + } + break; + case WM_NOTIFY: + { + LPNMHDR header = (LPNMHDR)lParam; + + switch (header->code) + { + case PSN_QUERYINITIALFOCUS: + { + SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, (LONG_PTR)GetDlgItem(hwndDlg, IDC_BASICINFORMATION)); + } + return TRUE; + } + } + break; + } + + return FALSE; +} diff --git a/ProcessHacker/hndlprv.c b/ProcessHacker/hndlprv.c index 97819bd18658..5a21fe2d26f7 100644 --- a/ProcessHacker/hndlprv.c +++ b/ProcessHacker/hndlprv.c @@ -1,720 +1,720 @@ -/* - * Process Hacker - - * handle provider - * - * Copyright (C) 2010-2015 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include -#include - -#include -#include -#include - -#include - -typedef struct _PHP_CREATE_HANDLE_ITEM_CONTEXT -{ - PPH_HANDLE_PROVIDER Provider; - PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX Handle; -} PHP_CREATE_HANDLE_ITEM_CONTEXT, *PPHP_CREATE_HANDLE_ITEM_CONTEXT; - -VOID NTAPI PhpHandleProviderDeleteProcedure( - _In_ PVOID Object, - _In_ ULONG Flags - ); - -VOID NTAPI PhpHandleItemDeleteProcedure( - _In_ PVOID Object, - _In_ ULONG Flags - ); - -PPH_OBJECT_TYPE PhHandleProviderType; -PPH_OBJECT_TYPE PhHandleItemType; - -BOOLEAN PhHandleProviderInitialization( - VOID - ) -{ - PhHandleProviderType = PhCreateObjectType(L"HandleProvider", 0, PhpHandleProviderDeleteProcedure); - PhHandleItemType = PhCreateObjectType(L"HandleItem", 0, PhpHandleItemDeleteProcedure); - - return TRUE; -} - -PPH_HANDLE_PROVIDER PhCreateHandleProvider( - _In_ HANDLE ProcessId - ) -{ - PPH_HANDLE_PROVIDER handleProvider; - - handleProvider = PhCreateObject( - PhEmGetObjectSize(EmHandleProviderType, sizeof(PH_HANDLE_PROVIDER)), - PhHandleProviderType - ); - - handleProvider->HandleHashSetSize = 128; - handleProvider->HandleHashSet = PhCreateHashSet(handleProvider->HandleHashSetSize); - handleProvider->HandleHashSetCount = 0; - PhInitializeQueuedLock(&handleProvider->HandleHashSetLock); - - PhInitializeCallback(&handleProvider->HandleAddedEvent); - PhInitializeCallback(&handleProvider->HandleModifiedEvent); - PhInitializeCallback(&handleProvider->HandleRemovedEvent); - PhInitializeCallback(&handleProvider->UpdatedEvent); - - handleProvider->ProcessId = ProcessId; - handleProvider->ProcessHandle = NULL; - - handleProvider->RunStatus = PhOpenProcess( - &handleProvider->ProcessHandle, - PROCESS_DUP_HANDLE, - ProcessId - ); - - handleProvider->TempListHashtable = PhCreateSimpleHashtable(20); - - PhEmCallObjectOperation(EmHandleProviderType, handleProvider, EmObjectCreate); - - return handleProvider; -} - -VOID PhpHandleProviderDeleteProcedure( - _In_ PVOID Object, - _In_ ULONG Flags - ) -{ - PPH_HANDLE_PROVIDER handleProvider = (PPH_HANDLE_PROVIDER)Object; - - PhEmCallObjectOperation(EmHandleProviderType, handleProvider, EmObjectDelete); - - // Dereference all handle items (we referenced them - // when we added them to the hashtable). - PhDereferenceAllHandleItems(handleProvider); - - PhFree(handleProvider->HandleHashSet); - PhDeleteCallback(&handleProvider->HandleAddedEvent); - PhDeleteCallback(&handleProvider->HandleModifiedEvent); - PhDeleteCallback(&handleProvider->HandleRemovedEvent); - - if (handleProvider->ProcessHandle) NtClose(handleProvider->ProcessHandle); - - PhDereferenceObject(handleProvider->TempListHashtable); -} - -PPH_HANDLE_ITEM PhCreateHandleItem( - _In_opt_ PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX Handle - ) -{ - PPH_HANDLE_ITEM handleItem; - - handleItem = PhCreateObject( - PhEmGetObjectSize(EmHandleItemType, sizeof(PH_HANDLE_ITEM)), - PhHandleItemType - ); - memset(handleItem, 0, sizeof(PH_HANDLE_ITEM)); - - if (Handle) - { - handleItem->Handle = (HANDLE)Handle->HandleValue; - PhPrintPointer(handleItem->HandleString, (PVOID)handleItem->Handle); - handleItem->Object = Handle->Object; - PhPrintPointer(handleItem->ObjectString, handleItem->Object); - handleItem->Attributes = Handle->HandleAttributes; - handleItem->GrantedAccess = (ACCESS_MASK)Handle->GrantedAccess; - PhPrintPointer(handleItem->GrantedAccessString, UlongToPtr(handleItem->GrantedAccess)); - } - - PhEmCallObjectOperation(EmHandleItemType, handleItem, EmObjectCreate); - - return handleItem; -} - -VOID PhpHandleItemDeleteProcedure( - _In_ PVOID Object, - _In_ ULONG Flags - ) -{ - PPH_HANDLE_ITEM handleItem = (PPH_HANDLE_ITEM)Object; - - PhEmCallObjectOperation(EmHandleItemType, handleItem, EmObjectDelete); - - if (handleItem->TypeName) PhDereferenceObject(handleItem->TypeName); - if (handleItem->ObjectName) PhDereferenceObject(handleItem->ObjectName); - if (handleItem->BestObjectName) PhDereferenceObject(handleItem->BestObjectName); -} - -FORCEINLINE BOOLEAN PhCompareHandleItem( - _In_ PPH_HANDLE_ITEM Value1, - _In_ PPH_HANDLE_ITEM Value2 - ) -{ - return Value1->Handle == Value2->Handle; -} - -FORCEINLINE ULONG PhHashHandleItem( - _In_ PPH_HANDLE_ITEM Value - ) -{ - return HandleToUlong(Value->Handle) / 4; -} - -PPH_HANDLE_ITEM PhpLookupHandleItem( - _In_ PPH_HANDLE_PROVIDER HandleProvider, - _In_ HANDLE Handle - ) -{ - PH_HANDLE_ITEM lookupHandleItem; - PPH_HASH_ENTRY entry; - PPH_HANDLE_ITEM handleItem; - - lookupHandleItem.Handle = Handle; - entry = PhFindEntryHashSet( - HandleProvider->HandleHashSet, - HandleProvider->HandleHashSetSize, - PhHashHandleItem(&lookupHandleItem) - ); - - for (; entry; entry = entry->Next) - { - handleItem = CONTAINING_RECORD(entry, PH_HANDLE_ITEM, HashEntry); - - if (PhCompareHandleItem(&lookupHandleItem, handleItem)) - return handleItem; - } - - return NULL; -} - -PPH_HANDLE_ITEM PhReferenceHandleItem( - _In_ PPH_HANDLE_PROVIDER HandleProvider, - _In_ HANDLE Handle - ) -{ - PPH_HANDLE_ITEM handleItem; - - PhAcquireQueuedLockShared(&HandleProvider->HandleHashSetLock); - - handleItem = PhpLookupHandleItem(HandleProvider, Handle); - - if (handleItem) - PhReferenceObject(handleItem); - - PhReleaseQueuedLockShared(&HandleProvider->HandleHashSetLock); - - return handleItem; -} - -VOID PhDereferenceAllHandleItems( - _In_ PPH_HANDLE_PROVIDER HandleProvider - ) -{ - ULONG i; - PPH_HASH_ENTRY entry; - PPH_HANDLE_ITEM handleItem; - - PhAcquireQueuedLockExclusive(&HandleProvider->HandleHashSetLock); - - for (i = 0; i < HandleProvider->HandleHashSetSize; i++) - { - entry = HandleProvider->HandleHashSet[i]; - - while (entry) - { - handleItem = CONTAINING_RECORD(entry, PH_HANDLE_ITEM, HashEntry); - entry = entry->Next; - PhDereferenceObject(handleItem); - } - } - - PhReleaseQueuedLockExclusive(&HandleProvider->HandleHashSetLock); -} - -VOID PhpAddHandleItem( - _In_ PPH_HANDLE_PROVIDER HandleProvider, - _In_ _Assume_refs_(1) PPH_HANDLE_ITEM HandleItem - ) -{ - if (HandleProvider->HandleHashSetSize < HandleProvider->HandleHashSetCount + 1) - { - PhResizeHashSet( - &HandleProvider->HandleHashSet, - &HandleProvider->HandleHashSetSize, - HandleProvider->HandleHashSetSize * 2 - ); - } - - PhAddEntryHashSet( - HandleProvider->HandleHashSet, - HandleProvider->HandleHashSetSize, - &HandleItem->HashEntry, - PhHashHandleItem(HandleItem) - ); - HandleProvider->HandleHashSetCount++; -} - -VOID PhpRemoveHandleItem( - _In_ PPH_HANDLE_PROVIDER HandleProvider, - _In_ PPH_HANDLE_ITEM HandleItem - ) -{ - PhRemoveEntryHashSet(HandleProvider->HandleHashSet, HandleProvider->HandleHashSetSize, &HandleItem->HashEntry); - HandleProvider->HandleHashSetCount--; - PhDereferenceObject(HandleItem); -} - -/** - * Enumerates all handles in a process. - * - * \param ProcessId The ID of the process. - * \param ProcessHandle A handle to the process. - * \param Handles A variable which receives a pointer to a buffer containing - * information about the handles. - * \param FilterNeeded A variable which receives a boolean indicating - * whether the handle information needs to be filtered by process ID. - */ -NTSTATUS PhEnumHandlesGeneric( - _In_ HANDLE ProcessId, - _In_ HANDLE ProcessHandle, - _Out_ PSYSTEM_HANDLE_INFORMATION_EX *Handles, - _Out_ PBOOLEAN FilterNeeded - ) -{ - NTSTATUS status; - - // There are three ways of enumerating handles: - // * When KProcessHacker is available, using KphEnumerateProcessHandles - // is the most efficient method. - // * On Windows XP and later, NtQuerySystemInformation with - // SystemExtendedHandleInformation can be used. - // * Otherwise, NtQuerySystemInformation with SystemHandleInformation - // can be used. - - if (KphIsConnected()) - { - PKPH_PROCESS_HANDLE_INFORMATION handles; - PSYSTEM_HANDLE_INFORMATION_EX convertedHandles; - ULONG i; - - // Enumerate handles using KProcessHacker. Unlike with NtQuerySystemInformation, - // this only enumerates handles for a single process and saves a lot of processing. - - if (NT_SUCCESS(status = KphEnumerateProcessHandles2(ProcessHandle, &handles))) - { - convertedHandles = PhAllocate( - FIELD_OFFSET(SYSTEM_HANDLE_INFORMATION_EX, Handles) + - sizeof(SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX) * handles->HandleCount - ); - - convertedHandles->NumberOfHandles = handles->HandleCount; - - for (i = 0; i < handles->HandleCount; i++) - { - convertedHandles->Handles[i].Object = handles->Handles[i].Object; - convertedHandles->Handles[i].UniqueProcessId = (ULONG_PTR)ProcessId; - convertedHandles->Handles[i].HandleValue = (ULONG_PTR)handles->Handles[i].Handle; - convertedHandles->Handles[i].GrantedAccess = (ULONG)handles->Handles[i].GrantedAccess; - convertedHandles->Handles[i].CreatorBackTraceIndex = 0; - convertedHandles->Handles[i].ObjectTypeIndex = handles->Handles[i].ObjectTypeIndex; - convertedHandles->Handles[i].HandleAttributes = handles->Handles[i].HandleAttributes; - } - - PhFree(handles); - - *Handles = convertedHandles; - *FilterNeeded = FALSE; - - return status; - } - } - - if (WindowsVersion >= WINDOWS_XP) - { - PSYSTEM_HANDLE_INFORMATION_EX handles; - - // Enumerate handles using the new method; no conversion - // necessary. - - if (!NT_SUCCESS(status = PhEnumHandlesEx(&handles))) - return status; - - *Handles = handles; - *FilterNeeded = TRUE; - } - else - { - PSYSTEM_HANDLE_INFORMATION handles; - PSYSTEM_HANDLE_INFORMATION_EX convertedHandles; - ULONG count; - ULONG allocatedCount; - ULONG i; - - // Enumerate handles using the old info class and convert - // the relevant entries to the new format. - - if (!NT_SUCCESS(status = PhEnumHandles(&handles))) - return status; - - count = 0; - allocatedCount = 100; - - convertedHandles = PhAllocate( - FIELD_OFFSET(SYSTEM_HANDLE_INFORMATION_EX, Handles) + - sizeof(SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX) * allocatedCount - ); - - for (i = 0; i < handles->NumberOfHandles; i++) - { - if ((HANDLE)handles->Handles[i].UniqueProcessId != ProcessId) - continue; - - if (count == allocatedCount) - { - allocatedCount *= 2; - convertedHandles = PhReAllocate( - convertedHandles, - FIELD_OFFSET(SYSTEM_HANDLE_INFORMATION_EX, Handles) + - sizeof(SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX) * allocatedCount - ); - } - - convertedHandles->Handles[count].Object = handles->Handles[i].Object; - convertedHandles->Handles[count].UniqueProcessId = (ULONG_PTR)handles->Handles[i].UniqueProcessId; - convertedHandles->Handles[count].HandleValue = (ULONG_PTR)handles->Handles[i].HandleValue; - convertedHandles->Handles[count].GrantedAccess = handles->Handles[i].GrantedAccess; - convertedHandles->Handles[count].CreatorBackTraceIndex = handles->Handles[i].CreatorBackTraceIndex; - convertedHandles->Handles[count].ObjectTypeIndex = handles->Handles[i].ObjectTypeIndex; - convertedHandles->Handles[count].HandleAttributes = (ULONG)handles->Handles[i].HandleAttributes; - - count++; - } - - convertedHandles->NumberOfHandles = count; - - PhFree(handles); - - *Handles = convertedHandles; - *FilterNeeded = FALSE; - } - - return STATUS_SUCCESS; -} - -NTSTATUS PhpCreateHandleItemFunction( - _In_ PVOID Parameter - ) -{ - PPHP_CREATE_HANDLE_ITEM_CONTEXT context = Parameter; - PPH_HANDLE_ITEM handleItem; - - handleItem = PhCreateHandleItem(context->Handle); - - PhGetHandleInformationEx( - context->Provider->ProcessHandle, - handleItem->Handle, - context->Handle->ObjectTypeIndex, - 0, - NULL, - NULL, - &handleItem->TypeName, - &handleItem->ObjectName, - &handleItem->BestObjectName, - NULL - ); - - if (handleItem->TypeName) - { - // Add the handle item to the hashtable. - PhAcquireQueuedLockExclusive(&context->Provider->HandleHashSetLock); - PhpAddHandleItem(context->Provider, handleItem); - PhReleaseQueuedLockExclusive(&context->Provider->HandleHashSetLock); - - // Raise the handle added event. - PhInvokeCallback(&context->Provider->HandleAddedEvent, handleItem); - } - else - { - PhDereferenceObject(handleItem); - } - - PhFree(context); - - return STATUS_SUCCESS; -} - -VOID PhHandleProviderUpdate( - _In_ PVOID Object - ) -{ - static PH_INITONCE initOnce = PH_INITONCE_INIT; - static ULONG fileObjectTypeIndex = -1; - - PPH_HANDLE_PROVIDER handleProvider = (PPH_HANDLE_PROVIDER)Object; - PSYSTEM_HANDLE_INFORMATION_EX handleInfo; - BOOLEAN filterNeeded; - PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX handles; - ULONG numberOfHandles; - ULONG i; - PH_HASHTABLE_ENUM_CONTEXT enumContext; - PPH_KEY_VALUE_PAIR handlePair; - BOOLEAN useWorkQueue = FALSE; - PH_WORK_QUEUE workQueue; - - if (!handleProvider->ProcessHandle) - goto UpdateExit; - - if (!NT_SUCCESS(handleProvider->RunStatus = PhEnumHandlesGeneric( - handleProvider->ProcessId, - handleProvider->ProcessHandle, - &handleInfo, - &filterNeeded - ))) - goto UpdateExit; - - if (!KphIsConnected() && WindowsVersion >= WINDOWS_VISTA) - { - useWorkQueue = TRUE; - PhInitializeWorkQueue(&workQueue, 1, 20, 1000); - - if (PhBeginInitOnce(&initOnce)) - { - UNICODE_STRING fileTypeName; - - RtlInitUnicodeString(&fileTypeName, L"File"); - fileObjectTypeIndex = PhGetObjectTypeNumber(&fileTypeName); - PhEndInitOnce(&initOnce); - } - } - - handles = handleInfo->Handles; - numberOfHandles = (ULONG)handleInfo->NumberOfHandles; - - // Make a list of the relevant handles. - if (filterNeeded) - { - for (i = 0; i < (ULONG)numberOfHandles; i++) - { - PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX handle = &handles[i]; - - if (handle->UniqueProcessId == (ULONG_PTR)handleProvider->ProcessId) - { - PhAddItemSimpleHashtable( - handleProvider->TempListHashtable, - (PVOID)handle->HandleValue, - handle - ); - } - } - } - else - { - for (i = 0; i < (ULONG)numberOfHandles; i++) - { - PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX handle = &handles[i]; - - PhAddItemSimpleHashtable( - handleProvider->TempListHashtable, - (PVOID)handle->HandleValue, - handle - ); - } - } - - // Look for closed handles. - { - PPH_LIST handlesToRemove = NULL; - PPH_HASH_ENTRY entry; - PPH_HANDLE_ITEM handleItem; - PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX *tempHashtableValue; - - for (i = 0; i < handleProvider->HandleHashSetSize; i++) - { - for (entry = handleProvider->HandleHashSet[i]; entry; entry = entry->Next) - { - BOOLEAN found = FALSE; - - handleItem = CONTAINING_RECORD(entry, PH_HANDLE_ITEM, HashEntry); - - // Check if the handle still exists. - - tempHashtableValue = (PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX *)PhFindItemSimpleHashtable( - handleProvider->TempListHashtable, - (PVOID)(handleItem->Handle) - ); - - if (tempHashtableValue) - { - // Also compare the object pointers to make sure a - // different object wasn't re-opened with the same - // handle value. This isn't 100% accurate as pool - // addresses may be re-used, but it works well. - if (handleItem->Object == (*tempHashtableValue)->Object) - { - found = TRUE; - } - } - - if (!found) - { - // Raise the handle removed event. - PhInvokeCallback(&handleProvider->HandleRemovedEvent, handleItem); - - if (!handlesToRemove) - handlesToRemove = PhCreateList(2); - - PhAddItemList(handlesToRemove, handleItem); - } - } - } - - if (handlesToRemove) - { - PhAcquireQueuedLockExclusive(&handleProvider->HandleHashSetLock); - - for (i = 0; i < handlesToRemove->Count; i++) - { - PhpRemoveHandleItem( - handleProvider, - (PPH_HANDLE_ITEM)handlesToRemove->Items[i] - ); - } - - PhReleaseQueuedLockExclusive(&handleProvider->HandleHashSetLock); - PhDereferenceObject(handlesToRemove); - } - } - - // Look for new handles and update existing ones. - - PhBeginEnumHashtable(handleProvider->TempListHashtable, &enumContext); - - while (handlePair = PhNextEnumHashtable(&enumContext)) - { - PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX handle = handlePair->Value; - PPH_HANDLE_ITEM handleItem; - - handleItem = PhpLookupHandleItem(handleProvider, (HANDLE)handle->HandleValue); - - if (!handleItem) - { - // When we don't have KPH, query handle information in parallel to take full advantage of the - // PhCallWithTimeout functionality. - if (useWorkQueue && handle->ObjectTypeIndex == fileObjectTypeIndex) - { - PPHP_CREATE_HANDLE_ITEM_CONTEXT context; - - context = PhAllocate(sizeof(PHP_CREATE_HANDLE_ITEM_CONTEXT)); - context->Provider = handleProvider; - context->Handle = handle; - PhQueueItemWorkQueue(&workQueue, PhpCreateHandleItemFunction, context); - continue; - } - - handleItem = PhCreateHandleItem(handle); - - PhGetHandleInformationEx( - handleProvider->ProcessHandle, - handleItem->Handle, - handle->ObjectTypeIndex, - 0, - NULL, - NULL, - &handleItem->TypeName, - &handleItem->ObjectName, - &handleItem->BestObjectName, - NULL - ); - - // We need at least a type name to continue. - if (!handleItem->TypeName) - { - PhDereferenceObject(handleItem); - continue; - } - - if (PhEqualString2(handleItem->TypeName, L"File", TRUE) && KphIsConnected()) - { - KPH_FILE_OBJECT_INFORMATION objectInfo; - - if (NT_SUCCESS(KphQueryInformationObject( - handleProvider->ProcessHandle, - handleItem->Handle, - KphObjectFileObjectInformation, - &objectInfo, - sizeof(KPH_FILE_OBJECT_INFORMATION), - NULL - ))) - { - if (objectInfo.SharedRead) - handleItem->FileFlags |= PH_HANDLE_FILE_SHARED_READ; - if (objectInfo.SharedWrite) - handleItem->FileFlags |= PH_HANDLE_FILE_SHARED_WRITE; - if (objectInfo.SharedDelete) - handleItem->FileFlags |= PH_HANDLE_FILE_SHARED_DELETE; - } - } - - // Add the handle item to the hashtable. - PhAcquireQueuedLockExclusive(&handleProvider->HandleHashSetLock); - PhpAddHandleItem(handleProvider, handleItem); - PhReleaseQueuedLockExclusive(&handleProvider->HandleHashSetLock); - - // Raise the handle added event. - PhInvokeCallback(&handleProvider->HandleAddedEvent, handleItem); - } - else - { - BOOLEAN modified = FALSE; - - if (handleItem->Attributes != handle->HandleAttributes) - { - handleItem->Attributes = handle->HandleAttributes; - modified = TRUE; - } - - if (modified) - { - // Raise the handle modified event. - PhInvokeCallback(&handleProvider->HandleModifiedEvent, handleItem); - } - } - } - - if (useWorkQueue) - { - PhWaitForWorkQueue(&workQueue); - PhDeleteWorkQueue(&workQueue); - } - - PhFree(handleInfo); - - // Re-create the temporary hashtable if it got too big. - if (handleProvider->TempListHashtable->AllocatedEntries > 8192) - { - PhDereferenceObject(handleProvider->TempListHashtable); - handleProvider->TempListHashtable = PhCreateSimpleHashtable(512); - } - else - { - PhClearHashtable(handleProvider->TempListHashtable); - } - -UpdateExit: - PhInvokeCallback(&handleProvider->UpdatedEvent, NULL); -} +/* + * Process Hacker - + * handle provider + * + * Copyright (C) 2010-2015 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include +#include + +#include +#include +#include + +#include + +typedef struct _PHP_CREATE_HANDLE_ITEM_CONTEXT +{ + PPH_HANDLE_PROVIDER Provider; + PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX Handle; +} PHP_CREATE_HANDLE_ITEM_CONTEXT, *PPHP_CREATE_HANDLE_ITEM_CONTEXT; + +VOID NTAPI PhpHandleProviderDeleteProcedure( + _In_ PVOID Object, + _In_ ULONG Flags + ); + +VOID NTAPI PhpHandleItemDeleteProcedure( + _In_ PVOID Object, + _In_ ULONG Flags + ); + +PPH_OBJECT_TYPE PhHandleProviderType; +PPH_OBJECT_TYPE PhHandleItemType; + +BOOLEAN PhHandleProviderInitialization( + VOID + ) +{ + PhHandleProviderType = PhCreateObjectType(L"HandleProvider", 0, PhpHandleProviderDeleteProcedure); + PhHandleItemType = PhCreateObjectType(L"HandleItem", 0, PhpHandleItemDeleteProcedure); + + return TRUE; +} + +PPH_HANDLE_PROVIDER PhCreateHandleProvider( + _In_ HANDLE ProcessId + ) +{ + PPH_HANDLE_PROVIDER handleProvider; + + handleProvider = PhCreateObject( + PhEmGetObjectSize(EmHandleProviderType, sizeof(PH_HANDLE_PROVIDER)), + PhHandleProviderType + ); + + handleProvider->HandleHashSetSize = 128; + handleProvider->HandleHashSet = PhCreateHashSet(handleProvider->HandleHashSetSize); + handleProvider->HandleHashSetCount = 0; + PhInitializeQueuedLock(&handleProvider->HandleHashSetLock); + + PhInitializeCallback(&handleProvider->HandleAddedEvent); + PhInitializeCallback(&handleProvider->HandleModifiedEvent); + PhInitializeCallback(&handleProvider->HandleRemovedEvent); + PhInitializeCallback(&handleProvider->UpdatedEvent); + + handleProvider->ProcessId = ProcessId; + handleProvider->ProcessHandle = NULL; + + handleProvider->RunStatus = PhOpenProcess( + &handleProvider->ProcessHandle, + PROCESS_DUP_HANDLE, + ProcessId + ); + + handleProvider->TempListHashtable = PhCreateSimpleHashtable(20); + + PhEmCallObjectOperation(EmHandleProviderType, handleProvider, EmObjectCreate); + + return handleProvider; +} + +VOID PhpHandleProviderDeleteProcedure( + _In_ PVOID Object, + _In_ ULONG Flags + ) +{ + PPH_HANDLE_PROVIDER handleProvider = (PPH_HANDLE_PROVIDER)Object; + + PhEmCallObjectOperation(EmHandleProviderType, handleProvider, EmObjectDelete); + + // Dereference all handle items (we referenced them + // when we added them to the hashtable). + PhDereferenceAllHandleItems(handleProvider); + + PhFree(handleProvider->HandleHashSet); + PhDeleteCallback(&handleProvider->HandleAddedEvent); + PhDeleteCallback(&handleProvider->HandleModifiedEvent); + PhDeleteCallback(&handleProvider->HandleRemovedEvent); + + if (handleProvider->ProcessHandle) NtClose(handleProvider->ProcessHandle); + + PhDereferenceObject(handleProvider->TempListHashtable); +} + +PPH_HANDLE_ITEM PhCreateHandleItem( + _In_opt_ PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX Handle + ) +{ + PPH_HANDLE_ITEM handleItem; + + handleItem = PhCreateObject( + PhEmGetObjectSize(EmHandleItemType, sizeof(PH_HANDLE_ITEM)), + PhHandleItemType + ); + memset(handleItem, 0, sizeof(PH_HANDLE_ITEM)); + + if (Handle) + { + handleItem->Handle = (HANDLE)Handle->HandleValue; + PhPrintPointer(handleItem->HandleString, (PVOID)handleItem->Handle); + handleItem->Object = Handle->Object; + PhPrintPointer(handleItem->ObjectString, handleItem->Object); + handleItem->Attributes = Handle->HandleAttributes; + handleItem->GrantedAccess = (ACCESS_MASK)Handle->GrantedAccess; + PhPrintPointer(handleItem->GrantedAccessString, UlongToPtr(handleItem->GrantedAccess)); + } + + PhEmCallObjectOperation(EmHandleItemType, handleItem, EmObjectCreate); + + return handleItem; +} + +VOID PhpHandleItemDeleteProcedure( + _In_ PVOID Object, + _In_ ULONG Flags + ) +{ + PPH_HANDLE_ITEM handleItem = (PPH_HANDLE_ITEM)Object; + + PhEmCallObjectOperation(EmHandleItemType, handleItem, EmObjectDelete); + + if (handleItem->TypeName) PhDereferenceObject(handleItem->TypeName); + if (handleItem->ObjectName) PhDereferenceObject(handleItem->ObjectName); + if (handleItem->BestObjectName) PhDereferenceObject(handleItem->BestObjectName); +} + +FORCEINLINE BOOLEAN PhCompareHandleItem( + _In_ PPH_HANDLE_ITEM Value1, + _In_ PPH_HANDLE_ITEM Value2 + ) +{ + return Value1->Handle == Value2->Handle; +} + +FORCEINLINE ULONG PhHashHandleItem( + _In_ PPH_HANDLE_ITEM Value + ) +{ + return HandleToUlong(Value->Handle) / 4; +} + +PPH_HANDLE_ITEM PhpLookupHandleItem( + _In_ PPH_HANDLE_PROVIDER HandleProvider, + _In_ HANDLE Handle + ) +{ + PH_HANDLE_ITEM lookupHandleItem; + PPH_HASH_ENTRY entry; + PPH_HANDLE_ITEM handleItem; + + lookupHandleItem.Handle = Handle; + entry = PhFindEntryHashSet( + HandleProvider->HandleHashSet, + HandleProvider->HandleHashSetSize, + PhHashHandleItem(&lookupHandleItem) + ); + + for (; entry; entry = entry->Next) + { + handleItem = CONTAINING_RECORD(entry, PH_HANDLE_ITEM, HashEntry); + + if (PhCompareHandleItem(&lookupHandleItem, handleItem)) + return handleItem; + } + + return NULL; +} + +PPH_HANDLE_ITEM PhReferenceHandleItem( + _In_ PPH_HANDLE_PROVIDER HandleProvider, + _In_ HANDLE Handle + ) +{ + PPH_HANDLE_ITEM handleItem; + + PhAcquireQueuedLockShared(&HandleProvider->HandleHashSetLock); + + handleItem = PhpLookupHandleItem(HandleProvider, Handle); + + if (handleItem) + PhReferenceObject(handleItem); + + PhReleaseQueuedLockShared(&HandleProvider->HandleHashSetLock); + + return handleItem; +} + +VOID PhDereferenceAllHandleItems( + _In_ PPH_HANDLE_PROVIDER HandleProvider + ) +{ + ULONG i; + PPH_HASH_ENTRY entry; + PPH_HANDLE_ITEM handleItem; + + PhAcquireQueuedLockExclusive(&HandleProvider->HandleHashSetLock); + + for (i = 0; i < HandleProvider->HandleHashSetSize; i++) + { + entry = HandleProvider->HandleHashSet[i]; + + while (entry) + { + handleItem = CONTAINING_RECORD(entry, PH_HANDLE_ITEM, HashEntry); + entry = entry->Next; + PhDereferenceObject(handleItem); + } + } + + PhReleaseQueuedLockExclusive(&HandleProvider->HandleHashSetLock); +} + +VOID PhpAddHandleItem( + _In_ PPH_HANDLE_PROVIDER HandleProvider, + _In_ _Assume_refs_(1) PPH_HANDLE_ITEM HandleItem + ) +{ + if (HandleProvider->HandleHashSetSize < HandleProvider->HandleHashSetCount + 1) + { + PhResizeHashSet( + &HandleProvider->HandleHashSet, + &HandleProvider->HandleHashSetSize, + HandleProvider->HandleHashSetSize * 2 + ); + } + + PhAddEntryHashSet( + HandleProvider->HandleHashSet, + HandleProvider->HandleHashSetSize, + &HandleItem->HashEntry, + PhHashHandleItem(HandleItem) + ); + HandleProvider->HandleHashSetCount++; +} + +VOID PhpRemoveHandleItem( + _In_ PPH_HANDLE_PROVIDER HandleProvider, + _In_ PPH_HANDLE_ITEM HandleItem + ) +{ + PhRemoveEntryHashSet(HandleProvider->HandleHashSet, HandleProvider->HandleHashSetSize, &HandleItem->HashEntry); + HandleProvider->HandleHashSetCount--; + PhDereferenceObject(HandleItem); +} + +/** + * Enumerates all handles in a process. + * + * \param ProcessId The ID of the process. + * \param ProcessHandle A handle to the process. + * \param Handles A variable which receives a pointer to a buffer containing + * information about the handles. + * \param FilterNeeded A variable which receives a boolean indicating + * whether the handle information needs to be filtered by process ID. + */ +NTSTATUS PhEnumHandlesGeneric( + _In_ HANDLE ProcessId, + _In_ HANDLE ProcessHandle, + _Out_ PSYSTEM_HANDLE_INFORMATION_EX *Handles, + _Out_ PBOOLEAN FilterNeeded + ) +{ + NTSTATUS status; + + // There are three ways of enumerating handles: + // * When KProcessHacker is available, using KphEnumerateProcessHandles + // is the most efficient method. + // * On Windows XP and later, NtQuerySystemInformation with + // SystemExtendedHandleInformation can be used. + // * Otherwise, NtQuerySystemInformation with SystemHandleInformation + // can be used. + + if (KphIsConnected()) + { + PKPH_PROCESS_HANDLE_INFORMATION handles; + PSYSTEM_HANDLE_INFORMATION_EX convertedHandles; + ULONG i; + + // Enumerate handles using KProcessHacker. Unlike with NtQuerySystemInformation, + // this only enumerates handles for a single process and saves a lot of processing. + + if (NT_SUCCESS(status = KphEnumerateProcessHandles2(ProcessHandle, &handles))) + { + convertedHandles = PhAllocate( + FIELD_OFFSET(SYSTEM_HANDLE_INFORMATION_EX, Handles) + + sizeof(SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX) * handles->HandleCount + ); + + convertedHandles->NumberOfHandles = handles->HandleCount; + + for (i = 0; i < handles->HandleCount; i++) + { + convertedHandles->Handles[i].Object = handles->Handles[i].Object; + convertedHandles->Handles[i].UniqueProcessId = (ULONG_PTR)ProcessId; + convertedHandles->Handles[i].HandleValue = (ULONG_PTR)handles->Handles[i].Handle; + convertedHandles->Handles[i].GrantedAccess = (ULONG)handles->Handles[i].GrantedAccess; + convertedHandles->Handles[i].CreatorBackTraceIndex = 0; + convertedHandles->Handles[i].ObjectTypeIndex = handles->Handles[i].ObjectTypeIndex; + convertedHandles->Handles[i].HandleAttributes = handles->Handles[i].HandleAttributes; + } + + PhFree(handles); + + *Handles = convertedHandles; + *FilterNeeded = FALSE; + + return status; + } + } + + if (WindowsVersion >= WINDOWS_XP) + { + PSYSTEM_HANDLE_INFORMATION_EX handles; + + // Enumerate handles using the new method; no conversion + // necessary. + + if (!NT_SUCCESS(status = PhEnumHandlesEx(&handles))) + return status; + + *Handles = handles; + *FilterNeeded = TRUE; + } + else + { + PSYSTEM_HANDLE_INFORMATION handles; + PSYSTEM_HANDLE_INFORMATION_EX convertedHandles; + ULONG count; + ULONG allocatedCount; + ULONG i; + + // Enumerate handles using the old info class and convert + // the relevant entries to the new format. + + if (!NT_SUCCESS(status = PhEnumHandles(&handles))) + return status; + + count = 0; + allocatedCount = 100; + + convertedHandles = PhAllocate( + FIELD_OFFSET(SYSTEM_HANDLE_INFORMATION_EX, Handles) + + sizeof(SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX) * allocatedCount + ); + + for (i = 0; i < handles->NumberOfHandles; i++) + { + if ((HANDLE)handles->Handles[i].UniqueProcessId != ProcessId) + continue; + + if (count == allocatedCount) + { + allocatedCount *= 2; + convertedHandles = PhReAllocate( + convertedHandles, + FIELD_OFFSET(SYSTEM_HANDLE_INFORMATION_EX, Handles) + + sizeof(SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX) * allocatedCount + ); + } + + convertedHandles->Handles[count].Object = handles->Handles[i].Object; + convertedHandles->Handles[count].UniqueProcessId = (ULONG_PTR)handles->Handles[i].UniqueProcessId; + convertedHandles->Handles[count].HandleValue = (ULONG_PTR)handles->Handles[i].HandleValue; + convertedHandles->Handles[count].GrantedAccess = handles->Handles[i].GrantedAccess; + convertedHandles->Handles[count].CreatorBackTraceIndex = handles->Handles[i].CreatorBackTraceIndex; + convertedHandles->Handles[count].ObjectTypeIndex = handles->Handles[i].ObjectTypeIndex; + convertedHandles->Handles[count].HandleAttributes = (ULONG)handles->Handles[i].HandleAttributes; + + count++; + } + + convertedHandles->NumberOfHandles = count; + + PhFree(handles); + + *Handles = convertedHandles; + *FilterNeeded = FALSE; + } + + return STATUS_SUCCESS; +} + +NTSTATUS PhpCreateHandleItemFunction( + _In_ PVOID Parameter + ) +{ + PPHP_CREATE_HANDLE_ITEM_CONTEXT context = Parameter; + PPH_HANDLE_ITEM handleItem; + + handleItem = PhCreateHandleItem(context->Handle); + + PhGetHandleInformationEx( + context->Provider->ProcessHandle, + handleItem->Handle, + context->Handle->ObjectTypeIndex, + 0, + NULL, + NULL, + &handleItem->TypeName, + &handleItem->ObjectName, + &handleItem->BestObjectName, + NULL + ); + + if (handleItem->TypeName) + { + // Add the handle item to the hashtable. + PhAcquireQueuedLockExclusive(&context->Provider->HandleHashSetLock); + PhpAddHandleItem(context->Provider, handleItem); + PhReleaseQueuedLockExclusive(&context->Provider->HandleHashSetLock); + + // Raise the handle added event. + PhInvokeCallback(&context->Provider->HandleAddedEvent, handleItem); + } + else + { + PhDereferenceObject(handleItem); + } + + PhFree(context); + + return STATUS_SUCCESS; +} + +VOID PhHandleProviderUpdate( + _In_ PVOID Object + ) +{ + static PH_INITONCE initOnce = PH_INITONCE_INIT; + static ULONG fileObjectTypeIndex = -1; + + PPH_HANDLE_PROVIDER handleProvider = (PPH_HANDLE_PROVIDER)Object; + PSYSTEM_HANDLE_INFORMATION_EX handleInfo; + BOOLEAN filterNeeded; + PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX handles; + ULONG numberOfHandles; + ULONG i; + PH_HASHTABLE_ENUM_CONTEXT enumContext; + PPH_KEY_VALUE_PAIR handlePair; + BOOLEAN useWorkQueue = FALSE; + PH_WORK_QUEUE workQueue; + + if (!handleProvider->ProcessHandle) + goto UpdateExit; + + if (!NT_SUCCESS(handleProvider->RunStatus = PhEnumHandlesGeneric( + handleProvider->ProcessId, + handleProvider->ProcessHandle, + &handleInfo, + &filterNeeded + ))) + goto UpdateExit; + + if (!KphIsConnected() && WindowsVersion >= WINDOWS_VISTA) + { + useWorkQueue = TRUE; + PhInitializeWorkQueue(&workQueue, 1, 20, 1000); + + if (PhBeginInitOnce(&initOnce)) + { + UNICODE_STRING fileTypeName; + + RtlInitUnicodeString(&fileTypeName, L"File"); + fileObjectTypeIndex = PhGetObjectTypeNumber(&fileTypeName); + PhEndInitOnce(&initOnce); + } + } + + handles = handleInfo->Handles; + numberOfHandles = (ULONG)handleInfo->NumberOfHandles; + + // Make a list of the relevant handles. + if (filterNeeded) + { + for (i = 0; i < (ULONG)numberOfHandles; i++) + { + PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX handle = &handles[i]; + + if (handle->UniqueProcessId == (ULONG_PTR)handleProvider->ProcessId) + { + PhAddItemSimpleHashtable( + handleProvider->TempListHashtable, + (PVOID)handle->HandleValue, + handle + ); + } + } + } + else + { + for (i = 0; i < (ULONG)numberOfHandles; i++) + { + PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX handle = &handles[i]; + + PhAddItemSimpleHashtable( + handleProvider->TempListHashtable, + (PVOID)handle->HandleValue, + handle + ); + } + } + + // Look for closed handles. + { + PPH_LIST handlesToRemove = NULL; + PPH_HASH_ENTRY entry; + PPH_HANDLE_ITEM handleItem; + PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX *tempHashtableValue; + + for (i = 0; i < handleProvider->HandleHashSetSize; i++) + { + for (entry = handleProvider->HandleHashSet[i]; entry; entry = entry->Next) + { + BOOLEAN found = FALSE; + + handleItem = CONTAINING_RECORD(entry, PH_HANDLE_ITEM, HashEntry); + + // Check if the handle still exists. + + tempHashtableValue = (PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX *)PhFindItemSimpleHashtable( + handleProvider->TempListHashtable, + (PVOID)(handleItem->Handle) + ); + + if (tempHashtableValue) + { + // Also compare the object pointers to make sure a + // different object wasn't re-opened with the same + // handle value. This isn't 100% accurate as pool + // addresses may be re-used, but it works well. + if (handleItem->Object == (*tempHashtableValue)->Object) + { + found = TRUE; + } + } + + if (!found) + { + // Raise the handle removed event. + PhInvokeCallback(&handleProvider->HandleRemovedEvent, handleItem); + + if (!handlesToRemove) + handlesToRemove = PhCreateList(2); + + PhAddItemList(handlesToRemove, handleItem); + } + } + } + + if (handlesToRemove) + { + PhAcquireQueuedLockExclusive(&handleProvider->HandleHashSetLock); + + for (i = 0; i < handlesToRemove->Count; i++) + { + PhpRemoveHandleItem( + handleProvider, + (PPH_HANDLE_ITEM)handlesToRemove->Items[i] + ); + } + + PhReleaseQueuedLockExclusive(&handleProvider->HandleHashSetLock); + PhDereferenceObject(handlesToRemove); + } + } + + // Look for new handles and update existing ones. + + PhBeginEnumHashtable(handleProvider->TempListHashtable, &enumContext); + + while (handlePair = PhNextEnumHashtable(&enumContext)) + { + PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX handle = handlePair->Value; + PPH_HANDLE_ITEM handleItem; + + handleItem = PhpLookupHandleItem(handleProvider, (HANDLE)handle->HandleValue); + + if (!handleItem) + { + // When we don't have KPH, query handle information in parallel to take full advantage of the + // PhCallWithTimeout functionality. + if (useWorkQueue && handle->ObjectTypeIndex == fileObjectTypeIndex) + { + PPHP_CREATE_HANDLE_ITEM_CONTEXT context; + + context = PhAllocate(sizeof(PHP_CREATE_HANDLE_ITEM_CONTEXT)); + context->Provider = handleProvider; + context->Handle = handle; + PhQueueItemWorkQueue(&workQueue, PhpCreateHandleItemFunction, context); + continue; + } + + handleItem = PhCreateHandleItem(handle); + + PhGetHandleInformationEx( + handleProvider->ProcessHandle, + handleItem->Handle, + handle->ObjectTypeIndex, + 0, + NULL, + NULL, + &handleItem->TypeName, + &handleItem->ObjectName, + &handleItem->BestObjectName, + NULL + ); + + // We need at least a type name to continue. + if (!handleItem->TypeName) + { + PhDereferenceObject(handleItem); + continue; + } + + if (PhEqualString2(handleItem->TypeName, L"File", TRUE) && KphIsConnected()) + { + KPH_FILE_OBJECT_INFORMATION objectInfo; + + if (NT_SUCCESS(KphQueryInformationObject( + handleProvider->ProcessHandle, + handleItem->Handle, + KphObjectFileObjectInformation, + &objectInfo, + sizeof(KPH_FILE_OBJECT_INFORMATION), + NULL + ))) + { + if (objectInfo.SharedRead) + handleItem->FileFlags |= PH_HANDLE_FILE_SHARED_READ; + if (objectInfo.SharedWrite) + handleItem->FileFlags |= PH_HANDLE_FILE_SHARED_WRITE; + if (objectInfo.SharedDelete) + handleItem->FileFlags |= PH_HANDLE_FILE_SHARED_DELETE; + } + } + + // Add the handle item to the hashtable. + PhAcquireQueuedLockExclusive(&handleProvider->HandleHashSetLock); + PhpAddHandleItem(handleProvider, handleItem); + PhReleaseQueuedLockExclusive(&handleProvider->HandleHashSetLock); + + // Raise the handle added event. + PhInvokeCallback(&handleProvider->HandleAddedEvent, handleItem); + } + else + { + BOOLEAN modified = FALSE; + + if (handleItem->Attributes != handle->HandleAttributes) + { + handleItem->Attributes = handle->HandleAttributes; + modified = TRUE; + } + + if (modified) + { + // Raise the handle modified event. + PhInvokeCallback(&handleProvider->HandleModifiedEvent, handleItem); + } + } + } + + if (useWorkQueue) + { + PhWaitForWorkQueue(&workQueue); + PhDeleteWorkQueue(&workQueue); + } + + PhFree(handleInfo); + + // Re-create the temporary hashtable if it got too big. + if (handleProvider->TempListHashtable->AllocatedEntries > 8192) + { + PhDereferenceObject(handleProvider->TempListHashtable); + handleProvider->TempListHashtable = PhCreateSimpleHashtable(512); + } + else + { + PhClearHashtable(handleProvider->TempListHashtable); + } + +UpdateExit: + PhInvokeCallback(&handleProvider->UpdatedEvent, NULL); +} diff --git a/ProcessHacker/hndlstat.c b/ProcessHacker/hndlstat.c index 810948439965..3835d47f750d 100644 --- a/ProcessHacker/hndlstat.c +++ b/ProcessHacker/hndlstat.c @@ -1,240 +1,240 @@ -/* - * Process Hacker - - * handle statistics window - * - * Copyright (C) 2010 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include - -#include - -#include - -typedef struct _HANDLE_STATISTICS_ENTRY -{ - PPH_STRING Name; - ULONG Count; -} HANDLE_STATISTICS_ENTRY, *PHANDLE_STATISTICS_ENTRY; - -typedef struct _HANDLE_STATISTICS_CONTEXT -{ - HANDLE ProcessId; - HANDLE ProcessHandle; - - PSYSTEM_HANDLE_INFORMATION_EX Handles; - HANDLE_STATISTICS_ENTRY Entries[MAX_OBJECT_TYPE_NUMBER]; -} HANDLE_STATISTICS_CONTEXT, *PHANDLE_STATISTICS_CONTEXT; - -INT_PTR CALLBACK PhpHandleStatisticsDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -VOID PhShowHandleStatisticsDialog( - _In_ HWND ParentWindowHandle, - _In_ HANDLE ProcessId - ) -{ - NTSTATUS status; - HANDLE_STATISTICS_CONTEXT context; - BOOLEAN filterNeeded; - ULONG i; - - context.ProcessId = ProcessId; - - if (!NT_SUCCESS(status = PhOpenProcess( - &context.ProcessHandle, - PROCESS_DUP_HANDLE, - ProcessId - ))) - { - PhShowStatus(ParentWindowHandle, L"Unable to open the process", status, 0); - return; - } - - status = PhEnumHandlesGeneric( - context.ProcessId, - context.ProcessHandle, - &context.Handles, - &filterNeeded - ); - - if (!NT_SUCCESS(status)) - { - NtClose(context.ProcessHandle); - PhShowStatus(ParentWindowHandle, L"Unable to enumerate process handles", status, 0); - return; - } - - memset(&context.Entries, 0, sizeof(context.Entries)); - - DialogBoxParam( - PhInstanceHandle, - MAKEINTRESOURCE(IDD_HANDLESTATS), - ParentWindowHandle, - PhpHandleStatisticsDlgProc, - (LPARAM)&context - ); - - for (i = 0; i < MAX_OBJECT_TYPE_NUMBER; i++) - { - if (context.Entries[i].Name) - PhDereferenceObject(context.Entries[i].Name); - } - - PhFree(context.Handles); - NtClose(context.ProcessHandle); -} - -static INT NTAPI PhpTypeCountCompareFunction( - _In_ PVOID Item1, - _In_ PVOID Item2, - _In_opt_ PVOID Context - ) -{ - PHANDLE_STATISTICS_ENTRY entry1 = Item1; - PHANDLE_STATISTICS_ENTRY entry2 = Item2; - - return uintcmp(entry1->Count, entry2->Count); -} - -INT_PTR CALLBACK PhpHandleStatisticsDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - switch (uMsg) - { - case WM_INITDIALOG: - { - PHANDLE_STATISTICS_CONTEXT context = (PHANDLE_STATISTICS_CONTEXT)lParam; - HANDLE processId; - ULONG_PTR i; - HWND lvHandle; - - processId = context->ProcessId; - - for (i = 0; i < context->Handles->NumberOfHandles; i++) - { - PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX handleInfo; - PHANDLE_STATISTICS_ENTRY entry; - PPH_STRING typeName; - - handleInfo = &context->Handles->Handles[i]; - - if (handleInfo->UniqueProcessId != (ULONG_PTR)processId) - continue; - if (handleInfo->ObjectTypeIndex >= MAX_OBJECT_TYPE_NUMBER) - continue; - - entry = &context->Entries[handleInfo->ObjectTypeIndex]; - - if (!entry->Name) - { - typeName = NULL; - PhGetHandleInformation( - context->ProcessHandle, - (HANDLE)handleInfo->HandleValue, - handleInfo->ObjectTypeIndex, - NULL, - &typeName, - NULL, - NULL - ); - entry->Name = typeName; - } - - entry->Count++; - } - - PhCenterWindow(hwndDlg, GetParent(hwndDlg)); - lvHandle = GetDlgItem(hwndDlg, IDC_LIST); - PhSetListViewStyle(lvHandle, FALSE, TRUE); - PhSetControlTheme(lvHandle, L"explorer"); - PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 140, L"Type"); - PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 100, L"Count"); - - PhSetExtendedListView(lvHandle); - ExtendedListView_SetCompareFunction(lvHandle, 1, PhpTypeCountCompareFunction); - - for (i = 0; i < MAX_OBJECT_TYPE_NUMBER; i++) - { - PHANDLE_STATISTICS_ENTRY entry; - PPH_STRING unknownType; - PPH_STRING countString; - INT lvItemIndex; - - entry = &context->Entries[i]; - - if (entry->Count == 0) - continue; - - unknownType = NULL; - - if (!entry->Name) - unknownType = PhFormatString(L"(unknown: %u)", i); - - countString = PhFormatUInt64(entry->Count, TRUE); - - lvItemIndex = PhAddListViewItem( - lvHandle, - MAXINT, - entry->Name ? entry->Name->Buffer : unknownType->Buffer, - entry - ); - PhSetListViewSubItem(lvHandle, lvItemIndex, 1, countString->Buffer); - - PhDereferenceObject(countString); - - if (unknownType) - PhDereferenceObject(unknownType); - } - - ExtendedListView_SortItems(lvHandle); - } - break; - case WM_DESTROY: - { - // Nothing - } - break; - case WM_COMMAND: - { - switch (LOWORD(wParam)) - { - case IDCANCEL: - case IDOK: - EndDialog(hwndDlg, IDOK); - break; - } - } - break; - case WM_NOTIFY: - { - PhHandleListViewNotifyForCopy(lParam, GetDlgItem(hwndDlg, IDC_LIST)); - } - break; - } - - return FALSE; -} +/* + * Process Hacker - + * handle statistics window + * + * Copyright (C) 2010 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include + +#include + +#include + +typedef struct _HANDLE_STATISTICS_ENTRY +{ + PPH_STRING Name; + ULONG Count; +} HANDLE_STATISTICS_ENTRY, *PHANDLE_STATISTICS_ENTRY; + +typedef struct _HANDLE_STATISTICS_CONTEXT +{ + HANDLE ProcessId; + HANDLE ProcessHandle; + + PSYSTEM_HANDLE_INFORMATION_EX Handles; + HANDLE_STATISTICS_ENTRY Entries[MAX_OBJECT_TYPE_NUMBER]; +} HANDLE_STATISTICS_CONTEXT, *PHANDLE_STATISTICS_CONTEXT; + +INT_PTR CALLBACK PhpHandleStatisticsDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +VOID PhShowHandleStatisticsDialog( + _In_ HWND ParentWindowHandle, + _In_ HANDLE ProcessId + ) +{ + NTSTATUS status; + HANDLE_STATISTICS_CONTEXT context; + BOOLEAN filterNeeded; + ULONG i; + + context.ProcessId = ProcessId; + + if (!NT_SUCCESS(status = PhOpenProcess( + &context.ProcessHandle, + PROCESS_DUP_HANDLE, + ProcessId + ))) + { + PhShowStatus(ParentWindowHandle, L"Unable to open the process", status, 0); + return; + } + + status = PhEnumHandlesGeneric( + context.ProcessId, + context.ProcessHandle, + &context.Handles, + &filterNeeded + ); + + if (!NT_SUCCESS(status)) + { + NtClose(context.ProcessHandle); + PhShowStatus(ParentWindowHandle, L"Unable to enumerate process handles", status, 0); + return; + } + + memset(&context.Entries, 0, sizeof(context.Entries)); + + DialogBoxParam( + PhInstanceHandle, + MAKEINTRESOURCE(IDD_HANDLESTATS), + ParentWindowHandle, + PhpHandleStatisticsDlgProc, + (LPARAM)&context + ); + + for (i = 0; i < MAX_OBJECT_TYPE_NUMBER; i++) + { + if (context.Entries[i].Name) + PhDereferenceObject(context.Entries[i].Name); + } + + PhFree(context.Handles); + NtClose(context.ProcessHandle); +} + +static INT NTAPI PhpTypeCountCompareFunction( + _In_ PVOID Item1, + _In_ PVOID Item2, + _In_opt_ PVOID Context + ) +{ + PHANDLE_STATISTICS_ENTRY entry1 = Item1; + PHANDLE_STATISTICS_ENTRY entry2 = Item2; + + return uintcmp(entry1->Count, entry2->Count); +} + +INT_PTR CALLBACK PhpHandleStatisticsDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + switch (uMsg) + { + case WM_INITDIALOG: + { + PHANDLE_STATISTICS_CONTEXT context = (PHANDLE_STATISTICS_CONTEXT)lParam; + HANDLE processId; + ULONG_PTR i; + HWND lvHandle; + + processId = context->ProcessId; + + for (i = 0; i < context->Handles->NumberOfHandles; i++) + { + PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX handleInfo; + PHANDLE_STATISTICS_ENTRY entry; + PPH_STRING typeName; + + handleInfo = &context->Handles->Handles[i]; + + if (handleInfo->UniqueProcessId != (ULONG_PTR)processId) + continue; + if (handleInfo->ObjectTypeIndex >= MAX_OBJECT_TYPE_NUMBER) + continue; + + entry = &context->Entries[handleInfo->ObjectTypeIndex]; + + if (!entry->Name) + { + typeName = NULL; + PhGetHandleInformation( + context->ProcessHandle, + (HANDLE)handleInfo->HandleValue, + handleInfo->ObjectTypeIndex, + NULL, + &typeName, + NULL, + NULL + ); + entry->Name = typeName; + } + + entry->Count++; + } + + PhCenterWindow(hwndDlg, GetParent(hwndDlg)); + lvHandle = GetDlgItem(hwndDlg, IDC_LIST); + PhSetListViewStyle(lvHandle, FALSE, TRUE); + PhSetControlTheme(lvHandle, L"explorer"); + PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 140, L"Type"); + PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 100, L"Count"); + + PhSetExtendedListView(lvHandle); + ExtendedListView_SetCompareFunction(lvHandle, 1, PhpTypeCountCompareFunction); + + for (i = 0; i < MAX_OBJECT_TYPE_NUMBER; i++) + { + PHANDLE_STATISTICS_ENTRY entry; + PPH_STRING unknownType; + PPH_STRING countString; + INT lvItemIndex; + + entry = &context->Entries[i]; + + if (entry->Count == 0) + continue; + + unknownType = NULL; + + if (!entry->Name) + unknownType = PhFormatString(L"(unknown: %u)", i); + + countString = PhFormatUInt64(entry->Count, TRUE); + + lvItemIndex = PhAddListViewItem( + lvHandle, + MAXINT, + entry->Name ? entry->Name->Buffer : unknownType->Buffer, + entry + ); + PhSetListViewSubItem(lvHandle, lvItemIndex, 1, countString->Buffer); + + PhDereferenceObject(countString); + + if (unknownType) + PhDereferenceObject(unknownType); + } + + ExtendedListView_SortItems(lvHandle); + } + break; + case WM_DESTROY: + { + // Nothing + } + break; + case WM_COMMAND: + { + switch (LOWORD(wParam)) + { + case IDCANCEL: + case IDOK: + EndDialog(hwndDlg, IDOK); + break; + } + } + break; + case WM_NOTIFY: + { + PhHandleListViewNotifyForCopy(lParam, GetDlgItem(hwndDlg, IDC_LIST)); + } + break; + } + + return FALSE; +} diff --git a/ProcessHacker/include/colmgr.h b/ProcessHacker/include/colmgr.h index 92ae8658f634..6d5489889856 100644 --- a/ProcessHacker/include/colmgr.h +++ b/ProcessHacker/include/colmgr.h @@ -1,118 +1,118 @@ -#ifndef PH_COLMGR_H -#define PH_COLMGR_H - -#define PH_CM_ORDER_LIMIT 160 - -// begin_phapppub -typedef LONG (NTAPI *PPH_CM_POST_SORT_FUNCTION)( - _In_ LONG Result, - _In_ PVOID Node1, - _In_ PVOID Node2, - _In_ PH_SORT_ORDER SortOrder - ); -// end_phapppub - -typedef struct _PH_CM_MANAGER -{ - HWND Handle; - ULONG MinId; - ULONG NextId; - PPH_CM_POST_SORT_FUNCTION PostSortFunction; - LIST_ENTRY ColumnListHead; - PPH_LIST NotifyList; -} PH_CM_MANAGER, *PPH_CM_MANAGER; - -typedef struct _PH_CM_COLUMN -{ - LIST_ENTRY ListEntry; - ULONG Id; - struct _PH_PLUGIN *Plugin; - ULONG SubId; - PVOID Context; - PVOID SortFunction; -} PH_CM_COLUMN, *PPH_CM_COLUMN; - -VOID PhCmInitializeManager( - _Out_ PPH_CM_MANAGER Manager, - _In_ HWND Handle, - _In_ ULONG MinId, - _In_ PPH_CM_POST_SORT_FUNCTION PostSortFunction - ); - -VOID PhCmDeleteManager( - _In_ PPH_CM_MANAGER Manager - ); - -PPH_CM_COLUMN PhCmCreateColumn( - _Inout_ PPH_CM_MANAGER Manager, - _In_ PPH_TREENEW_COLUMN Column, - _In_ struct _PH_PLUGIN *Plugin, - _In_ ULONG SubId, - _In_opt_ PVOID Context, - _In_ PVOID SortFunction - ); - -PPH_CM_COLUMN PhCmFindColumn( - _In_ PPH_CM_MANAGER Manager, - _In_ PPH_STRINGREF PluginName, - _In_ ULONG SubId - ); - -VOID PhCmSetNotifyPlugin( - _In_ PPH_CM_MANAGER Manager, - _In_ struct _PH_PLUGIN *Plugin - ); - -BOOLEAN PhCmForwardMessage( - _In_ HWND hwnd, - _In_ PH_TREENEW_MESSAGE Message, - _In_opt_ PVOID Parameter1, - _In_opt_ PVOID Parameter2, - _In_ PPH_CM_MANAGER Manager - ); - -BOOLEAN PhCmForwardSort( - _In_ PPH_TREENEW_NODE *Nodes, - _In_ ULONG NumberOfNodes, - _In_ ULONG SortColumn, - _In_ PH_SORT_ORDER SortOrder, - _In_ PPH_CM_MANAGER Manager - ); - -// begin_phapppub -PHAPPAPI -BOOLEAN -NTAPI -PhCmLoadSettings( - _In_ HWND TreeNewHandle, - _In_ PPH_STRINGREF Settings - ); -// end_phapppub - -#define PH_CM_COLUMN_WIDTHS_ONLY 0x1 - -BOOLEAN PhCmLoadSettingsEx( - _In_ HWND TreeNewHandle, - _In_opt_ PPH_CM_MANAGER Manager, - _In_ ULONG Flags, - _In_ PPH_STRINGREF Settings, - _In_opt_ PPH_STRINGREF SortSettings - ); - -// begin_phapppub -PHAPPAPI -PPH_STRING -NTAPI -PhCmSaveSettings( - _In_ HWND TreeNewHandle - ); -// end_phapppub - -PPH_STRING PhCmSaveSettingsEx( - _In_ HWND TreeNewHandle, - _In_opt_ PPH_CM_MANAGER Manager, - _In_ ULONG Flags, - _Out_opt_ PPH_STRING *SortSettings - ); - -#endif +#ifndef PH_COLMGR_H +#define PH_COLMGR_H + +#define PH_CM_ORDER_LIMIT 160 + +// begin_phapppub +typedef LONG (NTAPI *PPH_CM_POST_SORT_FUNCTION)( + _In_ LONG Result, + _In_ PVOID Node1, + _In_ PVOID Node2, + _In_ PH_SORT_ORDER SortOrder + ); +// end_phapppub + +typedef struct _PH_CM_MANAGER +{ + HWND Handle; + ULONG MinId; + ULONG NextId; + PPH_CM_POST_SORT_FUNCTION PostSortFunction; + LIST_ENTRY ColumnListHead; + PPH_LIST NotifyList; +} PH_CM_MANAGER, *PPH_CM_MANAGER; + +typedef struct _PH_CM_COLUMN +{ + LIST_ENTRY ListEntry; + ULONG Id; + struct _PH_PLUGIN *Plugin; + ULONG SubId; + PVOID Context; + PVOID SortFunction; +} PH_CM_COLUMN, *PPH_CM_COLUMN; + +VOID PhCmInitializeManager( + _Out_ PPH_CM_MANAGER Manager, + _In_ HWND Handle, + _In_ ULONG MinId, + _In_ PPH_CM_POST_SORT_FUNCTION PostSortFunction + ); + +VOID PhCmDeleteManager( + _In_ PPH_CM_MANAGER Manager + ); + +PPH_CM_COLUMN PhCmCreateColumn( + _Inout_ PPH_CM_MANAGER Manager, + _In_ PPH_TREENEW_COLUMN Column, + _In_ struct _PH_PLUGIN *Plugin, + _In_ ULONG SubId, + _In_opt_ PVOID Context, + _In_ PVOID SortFunction + ); + +PPH_CM_COLUMN PhCmFindColumn( + _In_ PPH_CM_MANAGER Manager, + _In_ PPH_STRINGREF PluginName, + _In_ ULONG SubId + ); + +VOID PhCmSetNotifyPlugin( + _In_ PPH_CM_MANAGER Manager, + _In_ struct _PH_PLUGIN *Plugin + ); + +BOOLEAN PhCmForwardMessage( + _In_ HWND hwnd, + _In_ PH_TREENEW_MESSAGE Message, + _In_opt_ PVOID Parameter1, + _In_opt_ PVOID Parameter2, + _In_ PPH_CM_MANAGER Manager + ); + +BOOLEAN PhCmForwardSort( + _In_ PPH_TREENEW_NODE *Nodes, + _In_ ULONG NumberOfNodes, + _In_ ULONG SortColumn, + _In_ PH_SORT_ORDER SortOrder, + _In_ PPH_CM_MANAGER Manager + ); + +// begin_phapppub +PHAPPAPI +BOOLEAN +NTAPI +PhCmLoadSettings( + _In_ HWND TreeNewHandle, + _In_ PPH_STRINGREF Settings + ); +// end_phapppub + +#define PH_CM_COLUMN_WIDTHS_ONLY 0x1 + +BOOLEAN PhCmLoadSettingsEx( + _In_ HWND TreeNewHandle, + _In_opt_ PPH_CM_MANAGER Manager, + _In_ ULONG Flags, + _In_ PPH_STRINGREF Settings, + _In_opt_ PPH_STRINGREF SortSettings + ); + +// begin_phapppub +PHAPPAPI +PPH_STRING +NTAPI +PhCmSaveSettings( + _In_ HWND TreeNewHandle + ); +// end_phapppub + +PPH_STRING PhCmSaveSettingsEx( + _In_ HWND TreeNewHandle, + _In_opt_ PPH_CM_MANAGER Manager, + _In_ ULONG Flags, + _Out_opt_ PPH_STRING *SortSettings + ); + +#endif diff --git a/ProcessHacker/include/extmgr.h b/ProcessHacker/include/extmgr.h index 9e45dc00c35a..321e78d3cbd8 100644 --- a/ProcessHacker/include/extmgr.h +++ b/ProcessHacker/include/extmgr.h @@ -1,51 +1,51 @@ -#ifndef PH_EXTMGR_H -#define PH_EXTMGR_H - -// begin_phapppub -typedef enum _PH_EM_OBJECT_TYPE -{ - EmProcessItemType, - EmProcessNodeType, - EmServiceItemType, - EmServiceNodeType, - EmNetworkItemType, - EmNetworkNodeType, - EmThreadItemType, - EmThreadNodeType, - EmModuleItemType, - EmModuleNodeType, - EmHandleItemType, - EmHandleNodeType, - EmThreadsContextType, - EmModulesContextType, - EmHandlesContextType, - EmThreadProviderType, - EmModuleProviderType, - EmHandleProviderType, - EmMemoryNodeType, - EmMemoryContextType, - EmMaximumObjectType -} PH_EM_OBJECT_TYPE; - -typedef enum _PH_EM_OBJECT_OPERATION -{ - EmObjectCreate, - EmObjectDelete, - EmMaximumObjectOperation -} PH_EM_OBJECT_OPERATION; - -typedef VOID (NTAPI *PPH_EM_OBJECT_CALLBACK)( - _In_ PVOID Object, - _In_ PH_EM_OBJECT_TYPE ObjectType, - _In_ PVOID Extension - ); -// end_phapppub - -typedef struct _PH_EM_APP_CONTEXT -{ - LIST_ENTRY ListEntry; - PH_STRINGREF AppName; - struct _PH_EM_OBJECT_EXTENSION *Extensions[EmMaximumObjectType]; -} PH_EM_APP_CONTEXT, *PPH_EM_APP_CONTEXT; - -#endif +#ifndef PH_EXTMGR_H +#define PH_EXTMGR_H + +// begin_phapppub +typedef enum _PH_EM_OBJECT_TYPE +{ + EmProcessItemType, + EmProcessNodeType, + EmServiceItemType, + EmServiceNodeType, + EmNetworkItemType, + EmNetworkNodeType, + EmThreadItemType, + EmThreadNodeType, + EmModuleItemType, + EmModuleNodeType, + EmHandleItemType, + EmHandleNodeType, + EmThreadsContextType, + EmModulesContextType, + EmHandlesContextType, + EmThreadProviderType, + EmModuleProviderType, + EmHandleProviderType, + EmMemoryNodeType, + EmMemoryContextType, + EmMaximumObjectType +} PH_EM_OBJECT_TYPE; + +typedef enum _PH_EM_OBJECT_OPERATION +{ + EmObjectCreate, + EmObjectDelete, + EmMaximumObjectOperation +} PH_EM_OBJECT_OPERATION; + +typedef VOID (NTAPI *PPH_EM_OBJECT_CALLBACK)( + _In_ PVOID Object, + _In_ PH_EM_OBJECT_TYPE ObjectType, + _In_ PVOID Extension + ); +// end_phapppub + +typedef struct _PH_EM_APP_CONTEXT +{ + LIST_ENTRY ListEntry; + PH_STRINGREF AppName; + struct _PH_EM_OBJECT_EXTENSION *Extensions[EmMaximumObjectType]; +} PH_EM_APP_CONTEXT, *PPH_EM_APP_CONTEXT; + +#endif diff --git a/ProcessHacker/include/extmgri.h b/ProcessHacker/include/extmgri.h index dcbf701b574c..932a8e57f9fa 100644 --- a/ProcessHacker/include/extmgri.h +++ b/ProcessHacker/include/extmgri.h @@ -1,61 +1,61 @@ -#ifndef PH_EXTMGRI_H -#define PH_EXTMGRI_H - -#include - -typedef struct _PH_EM_OBJECT_TYPE_STATE -{ - SIZE_T InitialSize; - SIZE_T ExtensionOffset; - LIST_ENTRY ExtensionListHead; -} PH_EM_OBJECT_TYPE_STATE, *PPH_EM_OBJECT_TYPE_STATE; - -typedef struct _PH_EM_OBJECT_EXTENSION -{ - LIST_ENTRY ListEntry; - SIZE_T ExtensionSize; - SIZE_T ExtensionOffset; - PPH_EM_OBJECT_CALLBACK Callbacks[EmMaximumObjectOperation]; -} PH_EM_OBJECT_EXTENSION, *PPH_EM_OBJECT_EXTENSION; - -VOID PhEmInitialization( - VOID - ); - -VOID PhEmInitializeAppContext( - _Out_ PPH_EM_APP_CONTEXT AppContext, - _In_ PPH_STRINGREF AppName - ); - -VOID PhEmSetObjectExtension( - _Inout_ PPH_EM_APP_CONTEXT AppContext, - _In_ PH_EM_OBJECT_TYPE ObjectType, - _In_ SIZE_T ExtensionSize, - _In_opt_ PPH_EM_OBJECT_CALLBACK CreateCallback, - _In_opt_ PPH_EM_OBJECT_CALLBACK DeleteCallback - ); - -PVOID PhEmGetObjectExtension( - _In_ PPH_EM_APP_CONTEXT AppContext, - _In_ PH_EM_OBJECT_TYPE ObjectType, - _In_ PVOID Object - ); - -SIZE_T PhEmGetObjectSize( - _In_ PH_EM_OBJECT_TYPE ObjectType, - _In_ SIZE_T InitialSize - ); - -VOID PhEmCallObjectOperation( - _In_ PH_EM_OBJECT_TYPE ObjectType, - _In_ PVOID Object, - _In_ PH_EM_OBJECT_OPERATION Operation - ); - -BOOLEAN PhEmParseCompoundId( - _In_ PPH_STRINGREF CompoundId, - _Out_ PPH_STRINGREF AppName, - _Out_ PULONG SubId - ); - -#endif +#ifndef PH_EXTMGRI_H +#define PH_EXTMGRI_H + +#include + +typedef struct _PH_EM_OBJECT_TYPE_STATE +{ + SIZE_T InitialSize; + SIZE_T ExtensionOffset; + LIST_ENTRY ExtensionListHead; +} PH_EM_OBJECT_TYPE_STATE, *PPH_EM_OBJECT_TYPE_STATE; + +typedef struct _PH_EM_OBJECT_EXTENSION +{ + LIST_ENTRY ListEntry; + SIZE_T ExtensionSize; + SIZE_T ExtensionOffset; + PPH_EM_OBJECT_CALLBACK Callbacks[EmMaximumObjectOperation]; +} PH_EM_OBJECT_EXTENSION, *PPH_EM_OBJECT_EXTENSION; + +VOID PhEmInitialization( + VOID + ); + +VOID PhEmInitializeAppContext( + _Out_ PPH_EM_APP_CONTEXT AppContext, + _In_ PPH_STRINGREF AppName + ); + +VOID PhEmSetObjectExtension( + _Inout_ PPH_EM_APP_CONTEXT AppContext, + _In_ PH_EM_OBJECT_TYPE ObjectType, + _In_ SIZE_T ExtensionSize, + _In_opt_ PPH_EM_OBJECT_CALLBACK CreateCallback, + _In_opt_ PPH_EM_OBJECT_CALLBACK DeleteCallback + ); + +PVOID PhEmGetObjectExtension( + _In_ PPH_EM_APP_CONTEXT AppContext, + _In_ PH_EM_OBJECT_TYPE ObjectType, + _In_ PVOID Object + ); + +SIZE_T PhEmGetObjectSize( + _In_ PH_EM_OBJECT_TYPE ObjectType, + _In_ SIZE_T InitialSize + ); + +VOID PhEmCallObjectOperation( + _In_ PH_EM_OBJECT_TYPE ObjectType, + _In_ PVOID Object, + _In_ PH_EM_OBJECT_OPERATION Operation + ); + +BOOLEAN PhEmParseCompoundId( + _In_ PPH_STRINGREF CompoundId, + _Out_ PPH_STRINGREF AppName, + _Out_ PULONG SubId + ); + +#endif diff --git a/ProcessHacker/include/heapstruct.h b/ProcessHacker/include/heapstruct.h index 5ace0d6c9c75..c85b1fb30a42 100644 --- a/ProcessHacker/include/heapstruct.h +++ b/ProcessHacker/include/heapstruct.h @@ -1,69 +1,69 @@ -#ifndef PH_HEAPSTRUCT_H -#define PH_HEAPSTRUCT_H - -// Not the actual structure, but has the same size. -typedef struct _HEAP_ENTRY -{ - PVOID Data1; - PVOID Data2; -} HEAP_ENTRY, *PHEAP_ENTRY; - -#define HEAP_SEGMENT_SIGNATURE 0xffeeffee - -// First few fields of HEAP_SEGMENT, VISTA and above -typedef struct _HEAP_SEGMENT -{ - HEAP_ENTRY HeapEntry; - ULONG SegmentSignature; - ULONG SegmentFlags; - LIST_ENTRY SegmentListEntry; - struct _HEAP *Heap; - - // ... -} HEAP_SEGMENT, *PHEAP_SEGMENT; - -// First few fields of HEAP_SEGMENT, WS03 and below -typedef struct _HEAP_SEGMENT_OLD -{ - HEAP_ENTRY Entry; - ULONG Signature; - ULONG Flags; - struct _HEAP *Heap; - - // ... -} HEAP_SEGMENT_OLD, *PHEAP_SEGMENT_OLD; - -// 32-bit versions - -typedef struct _HEAP_ENTRY32 -{ - WOW64_POINTER(PVOID) Data1; - WOW64_POINTER(PVOID) Data2; -} HEAP_ENTRY32, *PHEAP_ENTRY32; - -typedef struct _HEAP_SEGMENT32 -{ - HEAP_ENTRY32 HeapEntry; - ULONG SegmentSignature; - ULONG SegmentFlags; - LIST_ENTRY32 SegmentListEntry; - WOW64_POINTER(struct _HEAP *) Heap; - - // ... -} HEAP_SEGMENT32, *PHEAP_SEGMENT32; - -typedef struct _HEAP_SEGMENT_OLD32 -{ - HEAP_ENTRY32 Entry; - ULONG Signature; - ULONG Flags; - WOW64_POINTER(struct _HEAP *) Heap; - - // ... -} HEAP_SEGMENT_OLD32, *PHEAP_SEGMENT_OLD32; - -#define HEAP_SEGMENT_MAX_SIZE \ - (max(sizeof(HEAP_SEGMENT), max(sizeof(HEAP_SEGMENT_OLD), \ - max(sizeof(HEAP_SEGMENT32), sizeof(HEAP_SEGMENT_OLD32))))) - -#endif +#ifndef PH_HEAPSTRUCT_H +#define PH_HEAPSTRUCT_H + +// Not the actual structure, but has the same size. +typedef struct _HEAP_ENTRY +{ + PVOID Data1; + PVOID Data2; +} HEAP_ENTRY, *PHEAP_ENTRY; + +#define HEAP_SEGMENT_SIGNATURE 0xffeeffee + +// First few fields of HEAP_SEGMENT, VISTA and above +typedef struct _HEAP_SEGMENT +{ + HEAP_ENTRY HeapEntry; + ULONG SegmentSignature; + ULONG SegmentFlags; + LIST_ENTRY SegmentListEntry; + struct _HEAP *Heap; + + // ... +} HEAP_SEGMENT, *PHEAP_SEGMENT; + +// First few fields of HEAP_SEGMENT, WS03 and below +typedef struct _HEAP_SEGMENT_OLD +{ + HEAP_ENTRY Entry; + ULONG Signature; + ULONG Flags; + struct _HEAP *Heap; + + // ... +} HEAP_SEGMENT_OLD, *PHEAP_SEGMENT_OLD; + +// 32-bit versions + +typedef struct _HEAP_ENTRY32 +{ + WOW64_POINTER(PVOID) Data1; + WOW64_POINTER(PVOID) Data2; +} HEAP_ENTRY32, *PHEAP_ENTRY32; + +typedef struct _HEAP_SEGMENT32 +{ + HEAP_ENTRY32 HeapEntry; + ULONG SegmentSignature; + ULONG SegmentFlags; + LIST_ENTRY32 SegmentListEntry; + WOW64_POINTER(struct _HEAP *) Heap; + + // ... +} HEAP_SEGMENT32, *PHEAP_SEGMENT32; + +typedef struct _HEAP_SEGMENT_OLD32 +{ + HEAP_ENTRY32 Entry; + ULONG Signature; + ULONG Flags; + WOW64_POINTER(struct _HEAP *) Heap; + + // ... +} HEAP_SEGMENT_OLD32, *PHEAP_SEGMENT_OLD32; + +#define HEAP_SEGMENT_MAX_SIZE \ + (max(sizeof(HEAP_SEGMENT), max(sizeof(HEAP_SEGMENT_OLD), \ + max(sizeof(HEAP_SEGMENT32), sizeof(HEAP_SEGMENT_OLD32))))) + +#endif diff --git a/ProcessHacker/include/hidnproc.h b/ProcessHacker/include/hidnproc.h index 916efc0b9d46..471f9f9482ce 100644 --- a/ProcessHacker/include/hidnproc.h +++ b/ProcessHacker/include/hidnproc.h @@ -1,75 +1,75 @@ -#ifndef PH_HIDNPROC_H -#define PH_HIDNPROC_H - -typedef enum _PH_HIDDEN_PROCESS_METHOD -{ - BruteForceScanMethod, - CsrHandlesScanMethod -} PH_HIDDEN_PROCESS_METHOD; - -typedef enum _PH_HIDDEN_PROCESS_TYPE -{ - UnknownProcess, - NormalProcess, - HiddenProcess, - TerminatedProcess -} PH_HIDDEN_PROCESS_TYPE; - -typedef struct _PH_HIDDEN_PROCESS_ENTRY -{ - HANDLE ProcessId; - PPH_STRING FileName; - PH_HIDDEN_PROCESS_TYPE Type; -} PH_HIDDEN_PROCESS_ENTRY, *PPH_HIDDEN_PROCESS_ENTRY; - -typedef struct _PH_CSR_HANDLE_INFO -{ - HANDLE CsrProcessHandle; - HANDLE Handle; - BOOLEAN IsThreadHandle; - - HANDLE ProcessId; -} PH_CSR_HANDLE_INFO, *PPH_CSR_HANDLE_INFO; - -typedef BOOLEAN (NTAPI *PPH_ENUM_HIDDEN_PROCESSES_CALLBACK)( - _In_ PPH_HIDDEN_PROCESS_ENTRY Process, - _In_opt_ PVOID Context - ); - -NTSTATUS -NTAPI -PhEnumHiddenProcesses( - _In_ PH_HIDDEN_PROCESS_METHOD Method, - _In_ PPH_ENUM_HIDDEN_PROCESSES_CALLBACK Callback, - _In_opt_ PVOID Context - ); - -typedef BOOLEAN (NTAPI *PPH_ENUM_CSR_PROCESS_HANDLES_CALLBACK)( - _In_ PPH_CSR_HANDLE_INFO Handle, - _In_opt_ PVOID Context - ); - -NTSTATUS -NTAPI -PhEnumCsrProcessHandles( - _In_ PPH_ENUM_CSR_PROCESS_HANDLES_CALLBACK Callback, - _In_opt_ PVOID Context - ); - -NTSTATUS -NTAPI -PhOpenProcessByCsrHandle( - _Out_ PHANDLE ProcessHandle, - _In_ ACCESS_MASK DesiredAccess, - _In_ PPH_CSR_HANDLE_INFO Handle - ); - -NTSTATUS -NTAPI -PhOpenProcessByCsrHandles( - _Out_ PHANDLE ProcessHandle, - _In_ ACCESS_MASK DesiredAccess, - _In_ HANDLE ProcessId - ); - -#endif +#ifndef PH_HIDNPROC_H +#define PH_HIDNPROC_H + +typedef enum _PH_HIDDEN_PROCESS_METHOD +{ + BruteForceScanMethod, + CsrHandlesScanMethod +} PH_HIDDEN_PROCESS_METHOD; + +typedef enum _PH_HIDDEN_PROCESS_TYPE +{ + UnknownProcess, + NormalProcess, + HiddenProcess, + TerminatedProcess +} PH_HIDDEN_PROCESS_TYPE; + +typedef struct _PH_HIDDEN_PROCESS_ENTRY +{ + HANDLE ProcessId; + PPH_STRING FileName; + PH_HIDDEN_PROCESS_TYPE Type; +} PH_HIDDEN_PROCESS_ENTRY, *PPH_HIDDEN_PROCESS_ENTRY; + +typedef struct _PH_CSR_HANDLE_INFO +{ + HANDLE CsrProcessHandle; + HANDLE Handle; + BOOLEAN IsThreadHandle; + + HANDLE ProcessId; +} PH_CSR_HANDLE_INFO, *PPH_CSR_HANDLE_INFO; + +typedef BOOLEAN (NTAPI *PPH_ENUM_HIDDEN_PROCESSES_CALLBACK)( + _In_ PPH_HIDDEN_PROCESS_ENTRY Process, + _In_opt_ PVOID Context + ); + +NTSTATUS +NTAPI +PhEnumHiddenProcesses( + _In_ PH_HIDDEN_PROCESS_METHOD Method, + _In_ PPH_ENUM_HIDDEN_PROCESSES_CALLBACK Callback, + _In_opt_ PVOID Context + ); + +typedef BOOLEAN (NTAPI *PPH_ENUM_CSR_PROCESS_HANDLES_CALLBACK)( + _In_ PPH_CSR_HANDLE_INFO Handle, + _In_opt_ PVOID Context + ); + +NTSTATUS +NTAPI +PhEnumCsrProcessHandles( + _In_ PPH_ENUM_CSR_PROCESS_HANDLES_CALLBACK Callback, + _In_opt_ PVOID Context + ); + +NTSTATUS +NTAPI +PhOpenProcessByCsrHandle( + _Out_ PHANDLE ProcessHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ PPH_CSR_HANDLE_INFO Handle + ); + +NTSTATUS +NTAPI +PhOpenProcessByCsrHandles( + _Out_ PHANDLE ProcessHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ HANDLE ProcessId + ); + +#endif diff --git a/ProcessHacker/include/mainwndp.h b/ProcessHacker/include/mainwndp.h index 04e1cfd8c8f6..239f6f720bbd 100644 --- a/ProcessHacker/include/mainwndp.h +++ b/ProcessHacker/include/mainwndp.h @@ -1,512 +1,512 @@ -#ifndef PH_MAINWNDP_H -#define PH_MAINWNDP_H - -#define PH_FLUSH_PROCESS_QUERY_DATA_INTERVAL_1 250 -#define PH_FLUSH_PROCESS_QUERY_DATA_INTERVAL_2 750 -#define PH_FLUSH_PROCESS_QUERY_DATA_INTERVAL_LONG_TERM 1000 - -#define TIMER_FLUSH_PROCESS_QUERY_DATA 1 -#define TIMER_ICON_CLICK_ACTIVATE 2 -#define TIMER_ICON_RESTORE_HOVER 3 - -typedef union _PH_MWP_NOTIFICATION_DETAILS -{ - HANDLE ProcessId; - PPH_STRING ServiceName; -} PH_MWP_NOTIFICATION_DETAILS, *PPH_MWP_NOTIFICATION_DETAILS; - -extern PH_PROVIDER_REGISTRATION PhMwpProcessProviderRegistration; -extern PH_PROVIDER_REGISTRATION PhMwpServiceProviderRegistration; -extern PH_PROVIDER_REGISTRATION PhMwpNetworkProviderRegistration; -extern BOOLEAN PhMwpUpdateAutomatically; - -extern ULONG PhMwpNotifyIconNotifyMask; -extern ULONG PhMwpLastNotificationType; -extern PH_MWP_NOTIFICATION_DETAILS PhMwpLastNotificationDetails; - -LRESULT CALLBACK PhMwpWndProc( - _In_ HWND hWnd, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -// Initialization - -BOOLEAN PhMwpInitializeWindowClass( - VOID - ); - -VOID PhMwpInitializeProviders( - VOID - ); - -VOID PhMwpApplyUpdateInterval( - _In_ ULONG Interval - ); - -VOID PhMwpInitializeControls( - VOID - ); - -NTSTATUS PhMwpDelayedLoadFunction( - _In_ PVOID Parameter - ); - -PPH_STRING PhMwpFindDbghelpPath( - VOID - ); - -// Event handlers - -VOID PhMwpOnDestroy( - VOID - ); - -VOID PhMwpOnEndSession( - VOID - ); - -VOID PhMwpOnSettingChange( - VOID - ); - -VOID PhMwpOnCommand( - _In_ ULONG Id - ); - -VOID PhMwpOnShowWindow( - _In_ BOOLEAN Showing, - _In_ ULONG State - ); - -BOOLEAN PhMwpOnSysCommand( - _In_ ULONG Type, - _In_ LONG CursorScreenX, - _In_ LONG CursorScreenY - ); - -VOID PhMwpOnMenuCommand( - _In_ ULONG Index, - _In_ HMENU Menu - ); - -VOID PhMwpOnInitMenuPopup( - _In_ HMENU Menu, - _In_ ULONG Index, - _In_ BOOLEAN IsWindowMenu - ); - -VOID PhMwpOnSize( - VOID - ); - -VOID PhMwpOnSizing( - _In_ ULONG Edge, - _In_ PRECT DragRectangle - ); - -VOID PhMwpOnSetFocus( - VOID - ); - -VOID PhMwpOnTimer( - _In_ ULONG Id - ); - -BOOLEAN PhMwpOnNotify( - _In_ NMHDR *Header, - _Out_ LRESULT *Result - ); - -VOID PhMwpOnWtsSessionChange( - _In_ ULONG Reason, - _In_ ULONG SessionId - ); - -ULONG_PTR PhMwpOnUserMessage( - _In_ ULONG Message, - _In_ ULONG_PTR WParam, - _In_ ULONG_PTR LParam - ); - -// Callbacks - -VOID NTAPI PhMwpNetworkItemAddedHandler( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ); - -VOID NTAPI PhMwpNetworkItemModifiedHandler( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ); - -VOID NTAPI PhMwpNetworkItemRemovedHandler( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ); - -VOID NTAPI PhMwpNetworkItemsUpdatedHandler( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ); - -// Settings - -VOID PhMwpLoadSettings( - VOID - ); - -VOID PhMwpSaveSettings( - VOID - ); - -VOID PhMwpSaveWindowState( - VOID - ); - -// Misc. - -VOID PhMwpSymInitHandler( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ); - -VOID PhMwpUpdateLayoutPadding( - VOID - ); - -VOID PhMwpApplyLayoutPadding( - _Inout_ PRECT Rect, - _In_ PRECT Padding - ); - -VOID PhMwpLayout( - _Inout_ HDWP *DeferHandle - ); - -VOID PhMwpSetupComputerMenu( - _In_ PPH_EMENU_ITEM Root - ); - -BOOLEAN PhMwpExecuteComputerCommand( - _In_ ULONG Id - ); - -VOID PhMwpActivateWindow( - _In_ BOOLEAN Toggle - ); - -// Main menu - -VOID PhMwpInitializeMainMenu( - _In_ HMENU Menu - ); - -VOID PhMwpDispatchMenuCommand( - _In_ HMENU MenuHandle, - _In_ ULONG ItemIndex, - _In_ ULONG ItemId, - _In_ ULONG_PTR ItemData - ); - -ULONG_PTR PhMwpLegacyAddPluginMenuItem( - _In_ PPH_ADD_MENU_ITEM AddMenuItem - ); - -HBITMAP PhMwpGetShieldBitmap( - VOID - ); - -VOID PhMwpInitializeSubMenu( - _In_ PPH_EMENU Menu, - _In_ ULONG Index - ); - -PPH_EMENU_ITEM PhMwpFindTrayIconsMenuItem( - _In_ PPH_EMENU Menu - ); - -VOID PhMwpInitializeSectionMenuItems( - _In_ PPH_EMENU Menu, - _In_ ULONG StartIndex - ); - -// Tab control - -VOID PhMwpLayoutTabControl( - _Inout_ HDWP *DeferHandle - ); - -VOID PhMwpNotifyTabControl( - _In_ NMHDR *Header - ); - -VOID PhMwpSelectionChangedTabControl( - _In_ ULONG OldIndex - ); - -PPH_MAIN_TAB_PAGE PhMwpCreatePage( - _In_ PPH_MAIN_TAB_PAGE Template - ); - -VOID PhMwpSelectPage( - _In_ ULONG Index - ); - -PPH_MAIN_TAB_PAGE PhMwpFindPage( - _In_ PPH_STRINGREF Name - ); - -PPH_MAIN_TAB_PAGE PhMwpCreateInternalPage( - _In_ PWSTR Name, - _In_ ULONG Flags, - _In_ PPH_MAIN_TAB_PAGE_CALLBACK Callback - ); - -VOID PhMwpNotifyAllPages( - _In_ PH_MAIN_TAB_PAGE_MESSAGE Message, - _In_opt_ PVOID Parameter1, - _In_opt_ PVOID Parameter2 - ); - -// Notifications - -VOID PhMwpAddIconProcesses( - _In_ PPH_EMENU_ITEM Menu, - _In_ ULONG NumberOfProcesses - ); - -VOID PhMwpClearLastNotificationDetails( - VOID - ); - -BOOLEAN PhMwpPluginNotifyEvent( - _In_ ULONG Type, - _In_ PVOID Parameter - ); - -// Processes - -extern PPH_MAIN_TAB_PAGE PhMwpProcessesPage; -extern HWND PhMwpProcessTreeNewHandle; -extern HWND PhMwpSelectedProcessWindowHandle; -extern BOOLEAN PhMwpSelectedProcessVirtualizationEnabled; - -BOOLEAN PhMwpProcessesPageCallback( - _In_ struct _PH_MAIN_TAB_PAGE *Page, - _In_ PH_MAIN_TAB_PAGE_MESSAGE Message, - _In_opt_ PVOID Parameter1, - _In_opt_ PVOID Parameter2 - ); - -VOID PhMwpShowProcessProperties( - _In_ PPH_PROCESS_ITEM ProcessItem - ); - -VOID PhMwpToggleCurrentUserProcessTreeFilter( - VOID - ); - -BOOLEAN PhMwpCurrentUserProcessTreeFilter( - _In_ PPH_TREENEW_NODE Node, - _In_opt_ PVOID Context - ); - -VOID PhMwpToggleSignedProcessTreeFilter( - VOID - ); - -BOOLEAN PhMwpSignedProcessTreeFilter( - _In_ PPH_TREENEW_NODE Node, - _In_opt_ PVOID Context - ); - -BOOLEAN PhMwpExecuteProcessPriorityCommand( - _In_ ULONG Id, - _In_ PPH_PROCESS_ITEM *Processes, - _In_ ULONG NumberOfProcesses - ); - -BOOLEAN PhMwpExecuteProcessIoPriorityCommand( - _In_ ULONG Id, - _In_ PPH_PROCESS_ITEM *Processes, - _In_ ULONG NumberOfProcesses - ); - -VOID PhMwpSetProcessMenuPriorityChecks( - _In_ PPH_EMENU Menu, - _In_ HANDLE ProcessId, - _In_ BOOLEAN SetPriority, - _In_ BOOLEAN SetIoPriority, - _In_ BOOLEAN SetPagePriority - ); - -VOID PhMwpInitializeProcessMenu( - _In_ PPH_EMENU Menu, - _In_ PPH_PROCESS_ITEM *Processes, - _In_ ULONG NumberOfProcesses - ); - -VOID NTAPI PhMwpProcessAddedHandler( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ); - -VOID NTAPI PhMwpProcessModifiedHandler( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ); - -VOID NTAPI PhMwpProcessRemovedHandler( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ); - -VOID NTAPI PhMwpProcessesUpdatedHandler( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ); - -VOID PhMwpOnProcessAdded( - _In_ _Assume_refs_(1) PPH_PROCESS_ITEM ProcessItem, - _In_ ULONG RunId - ); - -VOID PhMwpOnProcessModified( - _In_ PPH_PROCESS_ITEM ProcessItem - ); - -VOID PhMwpOnProcessRemoved( - _In_ PPH_PROCESS_ITEM ProcessItem - ); - -VOID PhMwpOnProcessesUpdated( - VOID - ); - -// Services - -extern PPH_MAIN_TAB_PAGE PhMwpServicesPage; -extern HWND PhMwpServiceTreeNewHandle; - -BOOLEAN PhMwpServicesPageCallback( - _In_ struct _PH_MAIN_TAB_PAGE *Page, - _In_ PH_MAIN_TAB_PAGE_MESSAGE Message, - _In_opt_ PVOID Parameter1, - _In_opt_ PVOID Parameter2 - ); - -VOID PhMwpNeedServiceTreeList( - VOID - ); - -VOID PhMwpToggleDriverServiceTreeFilter( - VOID - ); - -BOOLEAN PhMwpDriverServiceTreeFilter( - _In_ PPH_TREENEW_NODE Node, - _In_opt_ PVOID Context - ); - -VOID PhMwpInitializeServiceMenu( - _In_ PPH_EMENU Menu, - _In_ PPH_SERVICE_ITEM *Services, - _In_ ULONG NumberOfServices - ); - -VOID NTAPI PhMwpServiceAddedHandler( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ); - -VOID NTAPI PhMwpServiceModifiedHandler( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ); - -VOID NTAPI PhMwpServiceRemovedHandler( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ); - -VOID NTAPI PhMwpServicesUpdatedHandler( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ); - -VOID PhMwpOnServiceAdded( - _In_ _Assume_refs_(1) PPH_SERVICE_ITEM ServiceItem, - _In_ ULONG RunId - ); - -VOID PhMwpOnServiceModified( - _In_ struct _PH_SERVICE_MODIFIED_DATA *ServiceModifiedData - ); - -VOID PhMwpOnServiceRemoved( - _In_ PPH_SERVICE_ITEM ServiceItem - ); - -VOID PhMwpOnServicesUpdated( - VOID - ); - -// Network - -extern PPH_MAIN_TAB_PAGE PhMwpNetworkPage; -extern HWND PhMwpNetworkTreeNewHandle; - -BOOLEAN PhMwpNetworkPageCallback( - _In_ struct _PH_MAIN_TAB_PAGE *Page, - _In_ PH_MAIN_TAB_PAGE_MESSAGE Message, - _In_opt_ PVOID Parameter1, - _In_opt_ PVOID Parameter2 - ); - -VOID PhMwpNeedNetworkTreeList( - VOID - ); - -BOOLEAN PhMwpCurrentUserNetworkTreeFilter( - _In_ PPH_TREENEW_NODE Node, - _In_opt_ PVOID Context - ); - -BOOLEAN PhMwpSignedNetworkTreeFilter( - _In_ PPH_TREENEW_NODE Node, - _In_opt_ PVOID Context - ); - -VOID PhMwpInitializeNetworkMenu( - _In_ PPH_EMENU Menu, - _In_ PPH_NETWORK_ITEM *NetworkItems, - _In_ ULONG NumberOfNetworkItems - ); - -VOID PhMwpOnNetworkItemAdded( - _In_ ULONG RunId, - _In_ _Assume_refs_(1) PPH_NETWORK_ITEM NetworkItem - ); - -VOID PhMwpOnNetworkItemModified( - _In_ PPH_NETWORK_ITEM NetworkItem - ); - -VOID PhMwpOnNetworkItemRemoved( - _In_ PPH_NETWORK_ITEM NetworkItem - ); - -VOID PhMwpOnNetworkItemsUpdated( - VOID - ); - -// Users - -VOID PhMwpUpdateUsersMenu( - VOID - ); - -#endif +#ifndef PH_MAINWNDP_H +#define PH_MAINWNDP_H + +#define PH_FLUSH_PROCESS_QUERY_DATA_INTERVAL_1 250 +#define PH_FLUSH_PROCESS_QUERY_DATA_INTERVAL_2 750 +#define PH_FLUSH_PROCESS_QUERY_DATA_INTERVAL_LONG_TERM 1000 + +#define TIMER_FLUSH_PROCESS_QUERY_DATA 1 +#define TIMER_ICON_CLICK_ACTIVATE 2 +#define TIMER_ICON_RESTORE_HOVER 3 + +typedef union _PH_MWP_NOTIFICATION_DETAILS +{ + HANDLE ProcessId; + PPH_STRING ServiceName; +} PH_MWP_NOTIFICATION_DETAILS, *PPH_MWP_NOTIFICATION_DETAILS; + +extern PH_PROVIDER_REGISTRATION PhMwpProcessProviderRegistration; +extern PH_PROVIDER_REGISTRATION PhMwpServiceProviderRegistration; +extern PH_PROVIDER_REGISTRATION PhMwpNetworkProviderRegistration; +extern BOOLEAN PhMwpUpdateAutomatically; + +extern ULONG PhMwpNotifyIconNotifyMask; +extern ULONG PhMwpLastNotificationType; +extern PH_MWP_NOTIFICATION_DETAILS PhMwpLastNotificationDetails; + +LRESULT CALLBACK PhMwpWndProc( + _In_ HWND hWnd, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +// Initialization + +BOOLEAN PhMwpInitializeWindowClass( + VOID + ); + +VOID PhMwpInitializeProviders( + VOID + ); + +VOID PhMwpApplyUpdateInterval( + _In_ ULONG Interval + ); + +VOID PhMwpInitializeControls( + VOID + ); + +NTSTATUS PhMwpDelayedLoadFunction( + _In_ PVOID Parameter + ); + +PPH_STRING PhMwpFindDbghelpPath( + VOID + ); + +// Event handlers + +VOID PhMwpOnDestroy( + VOID + ); + +VOID PhMwpOnEndSession( + VOID + ); + +VOID PhMwpOnSettingChange( + VOID + ); + +VOID PhMwpOnCommand( + _In_ ULONG Id + ); + +VOID PhMwpOnShowWindow( + _In_ BOOLEAN Showing, + _In_ ULONG State + ); + +BOOLEAN PhMwpOnSysCommand( + _In_ ULONG Type, + _In_ LONG CursorScreenX, + _In_ LONG CursorScreenY + ); + +VOID PhMwpOnMenuCommand( + _In_ ULONG Index, + _In_ HMENU Menu + ); + +VOID PhMwpOnInitMenuPopup( + _In_ HMENU Menu, + _In_ ULONG Index, + _In_ BOOLEAN IsWindowMenu + ); + +VOID PhMwpOnSize( + VOID + ); + +VOID PhMwpOnSizing( + _In_ ULONG Edge, + _In_ PRECT DragRectangle + ); + +VOID PhMwpOnSetFocus( + VOID + ); + +VOID PhMwpOnTimer( + _In_ ULONG Id + ); + +BOOLEAN PhMwpOnNotify( + _In_ NMHDR *Header, + _Out_ LRESULT *Result + ); + +VOID PhMwpOnWtsSessionChange( + _In_ ULONG Reason, + _In_ ULONG SessionId + ); + +ULONG_PTR PhMwpOnUserMessage( + _In_ ULONG Message, + _In_ ULONG_PTR WParam, + _In_ ULONG_PTR LParam + ); + +// Callbacks + +VOID NTAPI PhMwpNetworkItemAddedHandler( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ); + +VOID NTAPI PhMwpNetworkItemModifiedHandler( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ); + +VOID NTAPI PhMwpNetworkItemRemovedHandler( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ); + +VOID NTAPI PhMwpNetworkItemsUpdatedHandler( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ); + +// Settings + +VOID PhMwpLoadSettings( + VOID + ); + +VOID PhMwpSaveSettings( + VOID + ); + +VOID PhMwpSaveWindowState( + VOID + ); + +// Misc. + +VOID PhMwpSymInitHandler( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ); + +VOID PhMwpUpdateLayoutPadding( + VOID + ); + +VOID PhMwpApplyLayoutPadding( + _Inout_ PRECT Rect, + _In_ PRECT Padding + ); + +VOID PhMwpLayout( + _Inout_ HDWP *DeferHandle + ); + +VOID PhMwpSetupComputerMenu( + _In_ PPH_EMENU_ITEM Root + ); + +BOOLEAN PhMwpExecuteComputerCommand( + _In_ ULONG Id + ); + +VOID PhMwpActivateWindow( + _In_ BOOLEAN Toggle + ); + +// Main menu + +VOID PhMwpInitializeMainMenu( + _In_ HMENU Menu + ); + +VOID PhMwpDispatchMenuCommand( + _In_ HMENU MenuHandle, + _In_ ULONG ItemIndex, + _In_ ULONG ItemId, + _In_ ULONG_PTR ItemData + ); + +ULONG_PTR PhMwpLegacyAddPluginMenuItem( + _In_ PPH_ADD_MENU_ITEM AddMenuItem + ); + +HBITMAP PhMwpGetShieldBitmap( + VOID + ); + +VOID PhMwpInitializeSubMenu( + _In_ PPH_EMENU Menu, + _In_ ULONG Index + ); + +PPH_EMENU_ITEM PhMwpFindTrayIconsMenuItem( + _In_ PPH_EMENU Menu + ); + +VOID PhMwpInitializeSectionMenuItems( + _In_ PPH_EMENU Menu, + _In_ ULONG StartIndex + ); + +// Tab control + +VOID PhMwpLayoutTabControl( + _Inout_ HDWP *DeferHandle + ); + +VOID PhMwpNotifyTabControl( + _In_ NMHDR *Header + ); + +VOID PhMwpSelectionChangedTabControl( + _In_ ULONG OldIndex + ); + +PPH_MAIN_TAB_PAGE PhMwpCreatePage( + _In_ PPH_MAIN_TAB_PAGE Template + ); + +VOID PhMwpSelectPage( + _In_ ULONG Index + ); + +PPH_MAIN_TAB_PAGE PhMwpFindPage( + _In_ PPH_STRINGREF Name + ); + +PPH_MAIN_TAB_PAGE PhMwpCreateInternalPage( + _In_ PWSTR Name, + _In_ ULONG Flags, + _In_ PPH_MAIN_TAB_PAGE_CALLBACK Callback + ); + +VOID PhMwpNotifyAllPages( + _In_ PH_MAIN_TAB_PAGE_MESSAGE Message, + _In_opt_ PVOID Parameter1, + _In_opt_ PVOID Parameter2 + ); + +// Notifications + +VOID PhMwpAddIconProcesses( + _In_ PPH_EMENU_ITEM Menu, + _In_ ULONG NumberOfProcesses + ); + +VOID PhMwpClearLastNotificationDetails( + VOID + ); + +BOOLEAN PhMwpPluginNotifyEvent( + _In_ ULONG Type, + _In_ PVOID Parameter + ); + +// Processes + +extern PPH_MAIN_TAB_PAGE PhMwpProcessesPage; +extern HWND PhMwpProcessTreeNewHandle; +extern HWND PhMwpSelectedProcessWindowHandle; +extern BOOLEAN PhMwpSelectedProcessVirtualizationEnabled; + +BOOLEAN PhMwpProcessesPageCallback( + _In_ struct _PH_MAIN_TAB_PAGE *Page, + _In_ PH_MAIN_TAB_PAGE_MESSAGE Message, + _In_opt_ PVOID Parameter1, + _In_opt_ PVOID Parameter2 + ); + +VOID PhMwpShowProcessProperties( + _In_ PPH_PROCESS_ITEM ProcessItem + ); + +VOID PhMwpToggleCurrentUserProcessTreeFilter( + VOID + ); + +BOOLEAN PhMwpCurrentUserProcessTreeFilter( + _In_ PPH_TREENEW_NODE Node, + _In_opt_ PVOID Context + ); + +VOID PhMwpToggleSignedProcessTreeFilter( + VOID + ); + +BOOLEAN PhMwpSignedProcessTreeFilter( + _In_ PPH_TREENEW_NODE Node, + _In_opt_ PVOID Context + ); + +BOOLEAN PhMwpExecuteProcessPriorityCommand( + _In_ ULONG Id, + _In_ PPH_PROCESS_ITEM *Processes, + _In_ ULONG NumberOfProcesses + ); + +BOOLEAN PhMwpExecuteProcessIoPriorityCommand( + _In_ ULONG Id, + _In_ PPH_PROCESS_ITEM *Processes, + _In_ ULONG NumberOfProcesses + ); + +VOID PhMwpSetProcessMenuPriorityChecks( + _In_ PPH_EMENU Menu, + _In_ HANDLE ProcessId, + _In_ BOOLEAN SetPriority, + _In_ BOOLEAN SetIoPriority, + _In_ BOOLEAN SetPagePriority + ); + +VOID PhMwpInitializeProcessMenu( + _In_ PPH_EMENU Menu, + _In_ PPH_PROCESS_ITEM *Processes, + _In_ ULONG NumberOfProcesses + ); + +VOID NTAPI PhMwpProcessAddedHandler( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ); + +VOID NTAPI PhMwpProcessModifiedHandler( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ); + +VOID NTAPI PhMwpProcessRemovedHandler( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ); + +VOID NTAPI PhMwpProcessesUpdatedHandler( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ); + +VOID PhMwpOnProcessAdded( + _In_ _Assume_refs_(1) PPH_PROCESS_ITEM ProcessItem, + _In_ ULONG RunId + ); + +VOID PhMwpOnProcessModified( + _In_ PPH_PROCESS_ITEM ProcessItem + ); + +VOID PhMwpOnProcessRemoved( + _In_ PPH_PROCESS_ITEM ProcessItem + ); + +VOID PhMwpOnProcessesUpdated( + VOID + ); + +// Services + +extern PPH_MAIN_TAB_PAGE PhMwpServicesPage; +extern HWND PhMwpServiceTreeNewHandle; + +BOOLEAN PhMwpServicesPageCallback( + _In_ struct _PH_MAIN_TAB_PAGE *Page, + _In_ PH_MAIN_TAB_PAGE_MESSAGE Message, + _In_opt_ PVOID Parameter1, + _In_opt_ PVOID Parameter2 + ); + +VOID PhMwpNeedServiceTreeList( + VOID + ); + +VOID PhMwpToggleDriverServiceTreeFilter( + VOID + ); + +BOOLEAN PhMwpDriverServiceTreeFilter( + _In_ PPH_TREENEW_NODE Node, + _In_opt_ PVOID Context + ); + +VOID PhMwpInitializeServiceMenu( + _In_ PPH_EMENU Menu, + _In_ PPH_SERVICE_ITEM *Services, + _In_ ULONG NumberOfServices + ); + +VOID NTAPI PhMwpServiceAddedHandler( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ); + +VOID NTAPI PhMwpServiceModifiedHandler( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ); + +VOID NTAPI PhMwpServiceRemovedHandler( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ); + +VOID NTAPI PhMwpServicesUpdatedHandler( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ); + +VOID PhMwpOnServiceAdded( + _In_ _Assume_refs_(1) PPH_SERVICE_ITEM ServiceItem, + _In_ ULONG RunId + ); + +VOID PhMwpOnServiceModified( + _In_ struct _PH_SERVICE_MODIFIED_DATA *ServiceModifiedData + ); + +VOID PhMwpOnServiceRemoved( + _In_ PPH_SERVICE_ITEM ServiceItem + ); + +VOID PhMwpOnServicesUpdated( + VOID + ); + +// Network + +extern PPH_MAIN_TAB_PAGE PhMwpNetworkPage; +extern HWND PhMwpNetworkTreeNewHandle; + +BOOLEAN PhMwpNetworkPageCallback( + _In_ struct _PH_MAIN_TAB_PAGE *Page, + _In_ PH_MAIN_TAB_PAGE_MESSAGE Message, + _In_opt_ PVOID Parameter1, + _In_opt_ PVOID Parameter2 + ); + +VOID PhMwpNeedNetworkTreeList( + VOID + ); + +BOOLEAN PhMwpCurrentUserNetworkTreeFilter( + _In_ PPH_TREENEW_NODE Node, + _In_opt_ PVOID Context + ); + +BOOLEAN PhMwpSignedNetworkTreeFilter( + _In_ PPH_TREENEW_NODE Node, + _In_opt_ PVOID Context + ); + +VOID PhMwpInitializeNetworkMenu( + _In_ PPH_EMENU Menu, + _In_ PPH_NETWORK_ITEM *NetworkItems, + _In_ ULONG NumberOfNetworkItems + ); + +VOID PhMwpOnNetworkItemAdded( + _In_ ULONG RunId, + _In_ _Assume_refs_(1) PPH_NETWORK_ITEM NetworkItem + ); + +VOID PhMwpOnNetworkItemModified( + _In_ PPH_NETWORK_ITEM NetworkItem + ); + +VOID PhMwpOnNetworkItemRemoved( + _In_ PPH_NETWORK_ITEM NetworkItem + ); + +VOID PhMwpOnNetworkItemsUpdated( + VOID + ); + +// Users + +VOID PhMwpUpdateUsersMenu( + VOID + ); + +#endif diff --git a/ProcessHacker/include/memsrch.h b/ProcessHacker/include/memsrch.h index 76f1318af3f5..5804a8f1f9d9 100644 --- a/ProcessHacker/include/memsrch.h +++ b/ProcessHacker/include/memsrch.h @@ -1,61 +1,61 @@ -#ifndef PH_MEMSRCH_H -#define PH_MEMSRCH_H - -typedef struct _PH_MEMORY_RESULT -{ - LONG RefCount; - PVOID Address; - SIZE_T Length; - PH_STRINGREF Display; -} PH_MEMORY_RESULT, *PPH_MEMORY_RESULT; - -typedef VOID (NTAPI *PPH_MEMORY_RESULT_CALLBACK)( - _In_ _Assume_refs_(1) PPH_MEMORY_RESULT Result, - _In_opt_ PVOID Context - ); - -#define PH_DISPLAY_BUFFER_COUNT (PAGE_SIZE * 2 - 1) - -typedef struct _PH_MEMORY_SEARCH_OPTIONS -{ - BOOLEAN Cancel; - PPH_MEMORY_RESULT_CALLBACK Callback; - PVOID Context; -} PH_MEMORY_SEARCH_OPTIONS, *PPH_MEMORY_SEARCH_OPTIONS; - -typedef struct _PH_MEMORY_STRING_OPTIONS -{ - PH_MEMORY_SEARCH_OPTIONS Header; - - ULONG MinimumLength; - BOOLEAN DetectUnicode; - ULONG MemoryTypeMask; -} PH_MEMORY_STRING_OPTIONS, *PPH_MEMORY_STRING_OPTIONS; - -PVOID PhAllocateForMemorySearch( - _In_ SIZE_T Size - ); - -VOID PhFreeForMemorySearch( - _In_ _Post_invalid_ PVOID Memory - ); - -PVOID PhCreateMemoryResult( - _In_ PVOID Address, - _In_ SIZE_T Length - ); - -VOID PhReferenceMemoryResult( - _In_ PPH_MEMORY_RESULT Result - ); - -VOID PhDereferenceMemoryResult( - _In_ PPH_MEMORY_RESULT Result - ); - -VOID PhDereferenceMemoryResults( - _In_reads_(NumberOfResults) PPH_MEMORY_RESULT *Results, - _In_ ULONG NumberOfResults - ); - -#endif +#ifndef PH_MEMSRCH_H +#define PH_MEMSRCH_H + +typedef struct _PH_MEMORY_RESULT +{ + LONG RefCount; + PVOID Address; + SIZE_T Length; + PH_STRINGREF Display; +} PH_MEMORY_RESULT, *PPH_MEMORY_RESULT; + +typedef VOID (NTAPI *PPH_MEMORY_RESULT_CALLBACK)( + _In_ _Assume_refs_(1) PPH_MEMORY_RESULT Result, + _In_opt_ PVOID Context + ); + +#define PH_DISPLAY_BUFFER_COUNT (PAGE_SIZE * 2 - 1) + +typedef struct _PH_MEMORY_SEARCH_OPTIONS +{ + BOOLEAN Cancel; + PPH_MEMORY_RESULT_CALLBACK Callback; + PVOID Context; +} PH_MEMORY_SEARCH_OPTIONS, *PPH_MEMORY_SEARCH_OPTIONS; + +typedef struct _PH_MEMORY_STRING_OPTIONS +{ + PH_MEMORY_SEARCH_OPTIONS Header; + + ULONG MinimumLength; + BOOLEAN DetectUnicode; + ULONG MemoryTypeMask; +} PH_MEMORY_STRING_OPTIONS, *PPH_MEMORY_STRING_OPTIONS; + +PVOID PhAllocateForMemorySearch( + _In_ SIZE_T Size + ); + +VOID PhFreeForMemorySearch( + _In_ _Post_invalid_ PVOID Memory + ); + +PVOID PhCreateMemoryResult( + _In_ PVOID Address, + _In_ SIZE_T Length + ); + +VOID PhReferenceMemoryResult( + _In_ PPH_MEMORY_RESULT Result + ); + +VOID PhDereferenceMemoryResult( + _In_ PPH_MEMORY_RESULT Result + ); + +VOID PhDereferenceMemoryResults( + _In_reads_(NumberOfResults) PPH_MEMORY_RESULT *Results, + _In_ ULONG NumberOfResults + ); + +#endif diff --git a/ProcessHacker/include/miniinfo.h b/ProcessHacker/include/miniinfo.h index 761cc644beb0..fe95f7b6db4d 100644 --- a/ProcessHacker/include/miniinfo.h +++ b/ProcessHacker/include/miniinfo.h @@ -1,222 +1,222 @@ -#ifndef PH_MINIINFO_H -#define PH_MINIINFO_H - -#include - -// begin_phapppub -// Section - -typedef VOID (NTAPI *PPH_MINIINFO_SET_SECTION_TEXT)( - _In_ struct _PH_MINIINFO_SECTION *Section, - _In_opt_ PPH_STRING Text - ); - -typedef struct _PH_MINIINFO_PARAMETERS -{ - HWND ContainerWindowHandle; - HWND MiniInfoWindowHandle; - - HFONT Font; - HFONT MediumFont; - ULONG FontHeight; - ULONG FontAverageWidth; - ULONG MediumFontHeight; - ULONG MediumFontAverageWidth; - - PPH_MINIINFO_SET_SECTION_TEXT SetSectionText; -} PH_MINIINFO_PARAMETERS, *PPH_MINIINFO_PARAMETERS; - -typedef enum _PH_MINIINFO_SECTION_MESSAGE -{ - MiniInfoCreate, - MiniInfoDestroy, - MiniInfoTick, - MiniInfoSectionChanging, // PPH_MINIINFO_SECTION Parameter1 - MiniInfoShowing, // BOOLEAN Parameter1 (Showing) - MiniInfoCreateDialog, // PPH_MINIINFO_CREATE_DIALOG Parameter1 - MaxMiniInfoMessage -} PH_MINIINFO_SECTION_MESSAGE; - -typedef BOOLEAN (NTAPI *PPH_MINIINFO_SECTION_CALLBACK)( - _In_ struct _PH_MINIINFO_SECTION *Section, - _In_ PH_MINIINFO_SECTION_MESSAGE Message, - _In_opt_ PVOID Parameter1, - _In_opt_ PVOID Parameter2 - ); - -typedef struct _PH_MINIINFO_CREATE_DIALOG -{ - BOOLEAN CustomCreate; - - // Parameters for default create - PVOID Instance; - PWSTR Template; - DLGPROC DialogProc; - PVOID Parameter; -} PH_MINIINFO_CREATE_DIALOG, *PPH_MINIINFO_CREATE_DIALOG; - -#define PH_MINIINFO_SECTION_NO_UPPER_MARGINS 0x1 -// end_phapppub - -// begin_phapppub -typedef struct _PH_MINIINFO_SECTION -{ - // Public - - // Initialization - PH_STRINGREF Name; - ULONG Flags; - PPH_MINIINFO_SECTION_CALLBACK Callback; - PVOID Context; - PVOID Reserved1[3]; - - PPH_MINIINFO_PARAMETERS Parameters; - PVOID Reserved2[3]; -// end_phapppub - - // Private - - struct - { - ULONG SpareFlags : 32; - }; - HWND DialogHandle; - PPH_STRING Text; -// begin_phapppub -} PH_MINIINFO_SECTION, *PPH_MINIINFO_SECTION; -// end_phapppub - -typedef enum _PH_MINIINFO_PIN_TYPE -{ - MiniInfoManualPinType, // User pin - MiniInfoIconPinType, // Notification icon - MiniInfoActivePinType, // Window is active - MiniInfoHoverPinType, // Cursor is over mini info window - MiniInfoChildControlPinType, // Interacting with child control - MaxMiniInfoPinType -} PH_MINIINFO_PIN_TYPE; - -#define PH_MINIINFO_ACTIVATE_WINDOW 0x1 -#define PH_MINIINFO_LOAD_POSITION 0x2 -#define PH_MINIINFO_DONT_CHANGE_SECTION_IF_PINNED 0x4 - -VOID PhPinMiniInformation( - _In_ PH_MINIINFO_PIN_TYPE PinType, - _In_ LONG PinCount, - _In_opt_ ULONG PinDelayMs, - _In_ ULONG Flags, - _In_opt_ PWSTR SectionName, - _In_opt_ PPOINT SourcePoint - ); - -// begin_phapppub -// List section - -typedef enum _PH_MINIINFO_LIST_SECTION_MESSAGE -{ - MiListSectionCreate, - MiListSectionDestroy, - MiListSectionTick, - MiListSectionShowing, // BOOLEAN Parameter1 (Showing) - MiListSectionDialogCreated, // HWND Parameter1 (DialogHandle) - MiListSectionSortProcessList, // PPH_MINIINFO_LIST_SECTION_SORT_LIST Parameter1 - MiListSectionAssignSortData, // PPH_MINIINFO_LIST_SECTION_ASSIGN_SORT_DATA Parameter1 - MiListSectionSortGroupList, // PPH_MINIINFO_LIST_SECTION_SORT_LIST Parameter1 - MiListSectionGetTitleText, // PPH_MINIINFO_LIST_SECTION_GET_TITLE_TEXT Parameter1 - MiListSectionGetUsageText, // PPH_MINIINFO_LIST_SECTION_GET_USAGE_TEXT Parameter1 - MiListSectionInitializeContextMenu, // PPH_MINIINFO_LIST_SECTION_MENU_INFORMATION Parameter1 - MiListSectionHandleContextMenu, // PPH_MINIINFO_LIST_SECTION_MENU_INFORMATION Parameter1 - MaxMiListSectionMessage -} PH_MINIINFO_LIST_SECTION_MESSAGE; - -typedef BOOLEAN (NTAPI *PPH_MINIINFO_LIST_SECTION_CALLBACK)( - _In_ struct _PH_MINIINFO_LIST_SECTION *ListSection, - _In_ PH_MINIINFO_LIST_SECTION_MESSAGE Message, - _In_opt_ PVOID Parameter1, - _In_opt_ PVOID Parameter2 - ); - -// The list section performs the following steps when constructing the list of process groups: -// 1. MiListSectionSortProcessList is sent in order to sort the process list. -// 2. A small number of process groups is created from the first few processes in the sorted list (typically high -// resource consumers). -// 3. MiListSectionAssignSortData is sent for each process group so that the user can assign custom sort data to -// each process group. -// 4. MiListSectionSortGroupList is sent in order to ensure that the process groups are correctly sorted by resource -// usage. -// The user also has access to the sort data when handling MiListSectionGetTitleText and MiListSectionGetUsageText. - -typedef struct _PH_MINIINFO_LIST_SECTION_SORT_DATA -{ - PH_TREENEW_NODE DoNotModify; - ULONGLONG UserData[4]; -} PH_MINIINFO_LIST_SECTION_SORT_DATA, *PPH_MINIINFO_LIST_SECTION_SORT_DATA; - -typedef struct _PH_MINIINFO_LIST_SECTION_ASSIGN_SORT_DATA -{ - PPH_PROCESS_GROUP ProcessGroup; - PPH_MINIINFO_LIST_SECTION_SORT_DATA SortData; -} PH_MINIINFO_LIST_SECTION_ASSIGN_SORT_DATA, *PPH_MINIINFO_LIST_SECTION_ASSIGN_SORT_DATA; - -typedef struct _PH_MINIINFO_LIST_SECTION_SORT_LIST -{ - // MiListSectionSortProcessList: List of PPH_PROCESS_NODE - // MiListSectionSortGroupList: List of PPH_MINIINFO_LIST_SECTION_SORT_DATA - PPH_LIST List; -} PH_MINIINFO_LIST_SECTION_SORT_LIST, *PPH_MINIINFO_LIST_SECTION_SORT_LIST; - -typedef struct _PH_MINIINFO_LIST_SECTION_GET_TITLE_TEXT -{ - PPH_PROCESS_GROUP ProcessGroup; - PPH_MINIINFO_LIST_SECTION_SORT_DATA SortData; - PPH_STRING Title; // Top line (may already contain a string) - PPH_STRING Subtitle; // Bottom line (may already contain a string) - COLORREF TitleColor; - COLORREF SubtitleColor; -} PH_MINIINFO_LIST_SECTION_GET_TITLE_TEXT, *PPH_MINIINFO_LIST_SECTION_GET_TITLE_TEXT; - -typedef struct _PH_MINIINFO_LIST_SECTION_GET_USAGE_TEXT -{ - PPH_PROCESS_GROUP ProcessGroup; - PPH_MINIINFO_LIST_SECTION_SORT_DATA SortData; - PPH_STRING Line1; // Top line - PPH_STRING Line2; // Bottom line - COLORREF Line1Color; - COLORREF Line2Color; -} PH_MINIINFO_LIST_SECTION_GET_USAGE_TEXT, *PPH_MINIINFO_LIST_SECTION_GET_USAGE_TEXT; - -typedef struct _PH_MINIINFO_LIST_SECTION_MENU_INFORMATION -{ - PPH_PROCESS_GROUP ProcessGroup; - PPH_MINIINFO_LIST_SECTION_SORT_DATA SortData; - PPH_TREENEW_CONTEXT_MENU ContextMenu; - struct _PH_EMENU_ITEM *SelectedItem; -} PH_MINIINFO_LIST_SECTION_MENU_INFORMATION, *PPH_MINIINFO_LIST_SECTION_MENU_INFORMATION; -// end_phapppub - -// begin_phapppub -typedef struct _PH_MINIINFO_LIST_SECTION -{ - // Public - - PPH_MINIINFO_SECTION Section; // State - HWND DialogHandle; // State - HWND TreeNewHandle; // State - PVOID Context; // Initialization - PPH_MINIINFO_LIST_SECTION_CALLBACK Callback; // Initialization -// end_phapppub - - // Private - - PH_LAYOUT_MANAGER LayoutManager; - ULONG RunCount; - LONG SuspendUpdate; - PPH_LIST ProcessGroupList; - PPH_LIST NodeList; - HANDLE SelectedRepresentativeProcessId; - LARGE_INTEGER SelectedRepresentativeCreateTime; -// begin_phapppub -} PH_MINIINFO_LIST_SECTION, *PPH_MINIINFO_LIST_SECTION; -// end_phapppub - +#ifndef PH_MINIINFO_H +#define PH_MINIINFO_H + +#include + +// begin_phapppub +// Section + +typedef VOID (NTAPI *PPH_MINIINFO_SET_SECTION_TEXT)( + _In_ struct _PH_MINIINFO_SECTION *Section, + _In_opt_ PPH_STRING Text + ); + +typedef struct _PH_MINIINFO_PARAMETERS +{ + HWND ContainerWindowHandle; + HWND MiniInfoWindowHandle; + + HFONT Font; + HFONT MediumFont; + ULONG FontHeight; + ULONG FontAverageWidth; + ULONG MediumFontHeight; + ULONG MediumFontAverageWidth; + + PPH_MINIINFO_SET_SECTION_TEXT SetSectionText; +} PH_MINIINFO_PARAMETERS, *PPH_MINIINFO_PARAMETERS; + +typedef enum _PH_MINIINFO_SECTION_MESSAGE +{ + MiniInfoCreate, + MiniInfoDestroy, + MiniInfoTick, + MiniInfoSectionChanging, // PPH_MINIINFO_SECTION Parameter1 + MiniInfoShowing, // BOOLEAN Parameter1 (Showing) + MiniInfoCreateDialog, // PPH_MINIINFO_CREATE_DIALOG Parameter1 + MaxMiniInfoMessage +} PH_MINIINFO_SECTION_MESSAGE; + +typedef BOOLEAN (NTAPI *PPH_MINIINFO_SECTION_CALLBACK)( + _In_ struct _PH_MINIINFO_SECTION *Section, + _In_ PH_MINIINFO_SECTION_MESSAGE Message, + _In_opt_ PVOID Parameter1, + _In_opt_ PVOID Parameter2 + ); + +typedef struct _PH_MINIINFO_CREATE_DIALOG +{ + BOOLEAN CustomCreate; + + // Parameters for default create + PVOID Instance; + PWSTR Template; + DLGPROC DialogProc; + PVOID Parameter; +} PH_MINIINFO_CREATE_DIALOG, *PPH_MINIINFO_CREATE_DIALOG; + +#define PH_MINIINFO_SECTION_NO_UPPER_MARGINS 0x1 +// end_phapppub + +// begin_phapppub +typedef struct _PH_MINIINFO_SECTION +{ + // Public + + // Initialization + PH_STRINGREF Name; + ULONG Flags; + PPH_MINIINFO_SECTION_CALLBACK Callback; + PVOID Context; + PVOID Reserved1[3]; + + PPH_MINIINFO_PARAMETERS Parameters; + PVOID Reserved2[3]; +// end_phapppub + + // Private + + struct + { + ULONG SpareFlags : 32; + }; + HWND DialogHandle; + PPH_STRING Text; +// begin_phapppub +} PH_MINIINFO_SECTION, *PPH_MINIINFO_SECTION; +// end_phapppub + +typedef enum _PH_MINIINFO_PIN_TYPE +{ + MiniInfoManualPinType, // User pin + MiniInfoIconPinType, // Notification icon + MiniInfoActivePinType, // Window is active + MiniInfoHoverPinType, // Cursor is over mini info window + MiniInfoChildControlPinType, // Interacting with child control + MaxMiniInfoPinType +} PH_MINIINFO_PIN_TYPE; + +#define PH_MINIINFO_ACTIVATE_WINDOW 0x1 +#define PH_MINIINFO_LOAD_POSITION 0x2 +#define PH_MINIINFO_DONT_CHANGE_SECTION_IF_PINNED 0x4 + +VOID PhPinMiniInformation( + _In_ PH_MINIINFO_PIN_TYPE PinType, + _In_ LONG PinCount, + _In_opt_ ULONG PinDelayMs, + _In_ ULONG Flags, + _In_opt_ PWSTR SectionName, + _In_opt_ PPOINT SourcePoint + ); + +// begin_phapppub +// List section + +typedef enum _PH_MINIINFO_LIST_SECTION_MESSAGE +{ + MiListSectionCreate, + MiListSectionDestroy, + MiListSectionTick, + MiListSectionShowing, // BOOLEAN Parameter1 (Showing) + MiListSectionDialogCreated, // HWND Parameter1 (DialogHandle) + MiListSectionSortProcessList, // PPH_MINIINFO_LIST_SECTION_SORT_LIST Parameter1 + MiListSectionAssignSortData, // PPH_MINIINFO_LIST_SECTION_ASSIGN_SORT_DATA Parameter1 + MiListSectionSortGroupList, // PPH_MINIINFO_LIST_SECTION_SORT_LIST Parameter1 + MiListSectionGetTitleText, // PPH_MINIINFO_LIST_SECTION_GET_TITLE_TEXT Parameter1 + MiListSectionGetUsageText, // PPH_MINIINFO_LIST_SECTION_GET_USAGE_TEXT Parameter1 + MiListSectionInitializeContextMenu, // PPH_MINIINFO_LIST_SECTION_MENU_INFORMATION Parameter1 + MiListSectionHandleContextMenu, // PPH_MINIINFO_LIST_SECTION_MENU_INFORMATION Parameter1 + MaxMiListSectionMessage +} PH_MINIINFO_LIST_SECTION_MESSAGE; + +typedef BOOLEAN (NTAPI *PPH_MINIINFO_LIST_SECTION_CALLBACK)( + _In_ struct _PH_MINIINFO_LIST_SECTION *ListSection, + _In_ PH_MINIINFO_LIST_SECTION_MESSAGE Message, + _In_opt_ PVOID Parameter1, + _In_opt_ PVOID Parameter2 + ); + +// The list section performs the following steps when constructing the list of process groups: +// 1. MiListSectionSortProcessList is sent in order to sort the process list. +// 2. A small number of process groups is created from the first few processes in the sorted list (typically high +// resource consumers). +// 3. MiListSectionAssignSortData is sent for each process group so that the user can assign custom sort data to +// each process group. +// 4. MiListSectionSortGroupList is sent in order to ensure that the process groups are correctly sorted by resource +// usage. +// The user also has access to the sort data when handling MiListSectionGetTitleText and MiListSectionGetUsageText. + +typedef struct _PH_MINIINFO_LIST_SECTION_SORT_DATA +{ + PH_TREENEW_NODE DoNotModify; + ULONGLONG UserData[4]; +} PH_MINIINFO_LIST_SECTION_SORT_DATA, *PPH_MINIINFO_LIST_SECTION_SORT_DATA; + +typedef struct _PH_MINIINFO_LIST_SECTION_ASSIGN_SORT_DATA +{ + PPH_PROCESS_GROUP ProcessGroup; + PPH_MINIINFO_LIST_SECTION_SORT_DATA SortData; +} PH_MINIINFO_LIST_SECTION_ASSIGN_SORT_DATA, *PPH_MINIINFO_LIST_SECTION_ASSIGN_SORT_DATA; + +typedef struct _PH_MINIINFO_LIST_SECTION_SORT_LIST +{ + // MiListSectionSortProcessList: List of PPH_PROCESS_NODE + // MiListSectionSortGroupList: List of PPH_MINIINFO_LIST_SECTION_SORT_DATA + PPH_LIST List; +} PH_MINIINFO_LIST_SECTION_SORT_LIST, *PPH_MINIINFO_LIST_SECTION_SORT_LIST; + +typedef struct _PH_MINIINFO_LIST_SECTION_GET_TITLE_TEXT +{ + PPH_PROCESS_GROUP ProcessGroup; + PPH_MINIINFO_LIST_SECTION_SORT_DATA SortData; + PPH_STRING Title; // Top line (may already contain a string) + PPH_STRING Subtitle; // Bottom line (may already contain a string) + COLORREF TitleColor; + COLORREF SubtitleColor; +} PH_MINIINFO_LIST_SECTION_GET_TITLE_TEXT, *PPH_MINIINFO_LIST_SECTION_GET_TITLE_TEXT; + +typedef struct _PH_MINIINFO_LIST_SECTION_GET_USAGE_TEXT +{ + PPH_PROCESS_GROUP ProcessGroup; + PPH_MINIINFO_LIST_SECTION_SORT_DATA SortData; + PPH_STRING Line1; // Top line + PPH_STRING Line2; // Bottom line + COLORREF Line1Color; + COLORREF Line2Color; +} PH_MINIINFO_LIST_SECTION_GET_USAGE_TEXT, *PPH_MINIINFO_LIST_SECTION_GET_USAGE_TEXT; + +typedef struct _PH_MINIINFO_LIST_SECTION_MENU_INFORMATION +{ + PPH_PROCESS_GROUP ProcessGroup; + PPH_MINIINFO_LIST_SECTION_SORT_DATA SortData; + PPH_TREENEW_CONTEXT_MENU ContextMenu; + struct _PH_EMENU_ITEM *SelectedItem; +} PH_MINIINFO_LIST_SECTION_MENU_INFORMATION, *PPH_MINIINFO_LIST_SECTION_MENU_INFORMATION; +// end_phapppub + +// begin_phapppub +typedef struct _PH_MINIINFO_LIST_SECTION +{ + // Public + + PPH_MINIINFO_SECTION Section; // State + HWND DialogHandle; // State + HWND TreeNewHandle; // State + PVOID Context; // Initialization + PPH_MINIINFO_LIST_SECTION_CALLBACK Callback; // Initialization +// end_phapppub + + // Private + + PH_LAYOUT_MANAGER LayoutManager; + ULONG RunCount; + LONG SuspendUpdate; + PPH_LIST ProcessGroupList; + PPH_LIST NodeList; + HANDLE SelectedRepresentativeProcessId; + LARGE_INTEGER SelectedRepresentativeCreateTime; +// begin_phapppub +} PH_MINIINFO_LIST_SECTION, *PPH_MINIINFO_LIST_SECTION; +// end_phapppub + #endif \ No newline at end of file diff --git a/ProcessHacker/include/miniinfop.h b/ProcessHacker/include/miniinfop.h index eaa9bfa4e153..64e5141ac26a 100644 --- a/ProcessHacker/include/miniinfop.h +++ b/ProcessHacker/include/miniinfop.h @@ -1,405 +1,405 @@ -#ifndef PH_MINIINFOP_H -#define PH_MINIINFOP_H - -// Constants - -#define MIP_CONTAINER_CLASSNAME L"ProcessHackerMiniInfo" - -#define MIP_TIMER_PIN_FIRST 1 -#define MIP_TIMER_PIN_LAST (MIP_TIMER_PIN_FIRST + MaxMiniInfoPinType - 1) - -#define MIP_MSG_FIRST (WM_APP + 150) -#define MIP_MSG_UPDATE (WM_APP + 150) -#define MIP_MSG_LAST (WM_APP + 151) - -#define MIP_UNPIN_CHILD_CONTROL_DELAY 1000 -#define MIP_UNPIN_HOVER_DELAY 250 - -#define MIP_REFRESH_AUTOMATICALLY_PINNED 0x1 -#define MIP_REFRESH_AUTOMATICALLY_UNPINNED 0x2 -#define MIP_REFRESH_AUTOMATICALLY_FLAG(Pinned) \ - ((Pinned) ? MIP_REFRESH_AUTOMATICALLY_PINNED : MIP_REFRESH_AUTOMATICALLY_UNPINNED) - -// Misc. - -#define SET_BUTTON_ICON(hwndDlg, Id, Icon) \ - SendMessage(GetDlgItem(hwndDlg, (Id)), BM_SETIMAGE, IMAGE_ICON, (LPARAM)(Icon)) - -// Dialog procedure - -LRESULT CALLBACK PhMipContainerWndProc( - _In_ HWND hWnd, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -INT_PTR CALLBACK PhMipMiniInfoDialogProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -// Container event handlers - -VOID PhMipContainerOnShowWindow( - _In_ BOOLEAN Showing, - _In_ ULONG State - ); - -VOID PhMipContainerOnActivate( - _In_ ULONG Type, - _In_ BOOLEAN Minimized - ); - -VOID PhMipContainerOnSize( - VOID - ); - -VOID PhMipContainerOnSizing( - _In_ ULONG Edge, - _In_ PRECT DragRectangle - ); - -VOID PhMipContainerOnExitSizeMove( - VOID - ); - -BOOLEAN PhMipContainerOnEraseBkgnd( - _In_ HDC hdc - ); - -VOID PhMipContainerOnTimer( - _In_ ULONG Id - ); - -// Child dialog event handlers - -VOID PhMipOnInitDialog( - VOID - ); - -VOID PhMipOnShowWindow( - _In_ BOOLEAN Showing, - _In_ ULONG State - ); - -VOID PhMipOnCommand( - _In_ ULONG Id, - _In_ ULONG Code - ); - -BOOLEAN PhMipOnNotify( - _In_ NMHDR *Header, - _Out_ LRESULT *Result - ); - -BOOLEAN PhMipOnCtlColorXxx( - _In_ ULONG Message, - _In_ HWND hwnd, - _In_ HDC hdc, - _Out_ HBRUSH *Brush - ); - -BOOLEAN PhMipOnDrawItem( - _In_ ULONG_PTR Id, - _In_ DRAWITEMSTRUCT *DrawItemStruct - ); - -VOID PhMipOnUserMessage( - _In_ ULONG Message, - _In_ ULONG_PTR WParam, - _In_ ULONG_PTR LParam - ); - -// Framework - -typedef enum _PH_MIP_ADJUST_PIN_RESULT -{ - NoAdjustPinResult, - ShowAdjustPinResult, - HideAdjustPinResult -} PH_MIP_ADJUST_PIN_RESULT; - -BOOLEAN NTAPI PhMipMessageLoopFilter( - _In_ PMSG Message, - _In_ PVOID Context - ); - -VOID NTAPI PhMipUpdateHandler( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ); - -PH_MIP_ADJUST_PIN_RESULT PhMipAdjustPin( - _In_ PH_MINIINFO_PIN_TYPE PinType, - _In_ LONG PinCount - ); - -VOID PhMipCalculateWindowRectangle( - _In_ PPOINT SourcePoint, - _Out_ PPH_RECTANGLE WindowRectangle - ); - -VOID PhMipInitializeParameters( - VOID - ); - -PPH_MINIINFO_SECTION PhMipCreateSection( - _In_ PPH_MINIINFO_SECTION Template - ); - -VOID PhMipDestroySection( - _In_ PPH_MINIINFO_SECTION Section - ); - -PPH_MINIINFO_SECTION PhMipFindSection( - _In_ PPH_STRINGREF Name - ); - -PPH_MINIINFO_SECTION PhMipCreateInternalSection( - _In_ PWSTR Name, - _In_ ULONG Flags, - _In_ PPH_MINIINFO_SECTION_CALLBACK Callback - ); - -VOID PhMipCreateSectionDialog( - _In_ PPH_MINIINFO_SECTION Section - ); - -VOID PhMipChangeSection( - _In_ PPH_MINIINFO_SECTION NewSection - ); - -VOID PhMipSetSectionText( - _In_ struct _PH_MINIINFO_SECTION *Section, - _In_opt_ PPH_STRING Text - ); - -VOID PhMipUpdateSectionText( - _In_ PPH_MINIINFO_SECTION Section - ); - -VOID PhMipLayout( - VOID - ); - -VOID PhMipBeginChildControlPin( - VOID - ); - -VOID PhMipEndChildControlPin( - VOID - ); - -VOID PhMipRefresh( - VOID - ); - -VOID PhMipToggleRefreshAutomatically( - VOID - ); - -VOID PhMipSetPinned( - _In_ BOOLEAN Pinned - ); - -VOID PhMipShowSectionMenu( - VOID - ); - -VOID PhMipShowOptionsMenu( - VOID - ); - -LRESULT CALLBACK PhMipSectionControlHookWndProc( - _In_ HWND hwnd, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam, - _In_ UINT_PTR uIdSubclass, - _In_ ULONG_PTR dwRefData - ); - -// List-based section - -#define MIP_MAX_PROCESS_GROUPS 15 -#define MIP_SINGLE_COLUMN_ID 0 - -#define MIP_CELL_PADDING 5 -#define MIP_ICON_PADDING 3 -#define MIP_INNER_PADDING 3 - -typedef struct _PH_MIP_GROUP_NODE -{ - union - { - PH_TREENEW_NODE Node; - PH_MINIINFO_LIST_SECTION_SORT_DATA SortData; - }; - PPH_PROCESS_GROUP ProcessGroup; - HANDLE RepresentativeProcessId; - LARGE_INTEGER RepresentativeCreateTime; - BOOLEAN RepresentativeIsHung; - - PPH_STRING TooltipText; -} PH_MIP_GROUP_NODE, *PPH_MIP_GROUP_NODE; - -PPH_MINIINFO_LIST_SECTION PhMipCreateListSection( - _In_ PWSTR Name, - _In_ ULONG Flags, - _In_ PPH_MINIINFO_LIST_SECTION Template - ); - -PPH_MINIINFO_LIST_SECTION PhMipCreateInternalListSection( - _In_ PWSTR Name, - _In_ ULONG Flags, - _In_ PPH_MINIINFO_LIST_SECTION_CALLBACK Callback - ); - -BOOLEAN PhMipListSectionCallback( - _In_ PPH_MINIINFO_SECTION Section, - _In_ PH_MINIINFO_SECTION_MESSAGE Message, - _In_opt_ PVOID Parameter1, - _In_opt_ PVOID Parameter2 - ); - -INT_PTR CALLBACK PhMipListSectionDialogProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -VOID PhMipListSectionSortFunction( - _In_ PPH_LIST List, - _In_opt_ PVOID Context - ); - -VOID PhMipTickListSection( - _In_ PPH_MINIINFO_LIST_SECTION ListSection - ); - -VOID PhMipClearListSection( - _In_ PPH_MINIINFO_LIST_SECTION ListSection - ); - -LONG PhMipCalculateRowHeight( - VOID - ); - -PPH_MIP_GROUP_NODE PhMipAddGroupNode( - _In_ PPH_MINIINFO_LIST_SECTION ListSection, - _In_ PPH_PROCESS_GROUP ProcessGroup - ); - -VOID PhMipDestroyGroupNode( - _In_ PPH_MIP_GROUP_NODE Node - ); - -BOOLEAN PhMipListSectionTreeNewCallback( - _In_ HWND hwnd, - _In_ PH_TREENEW_MESSAGE Message, - _In_opt_ PVOID Parameter1, - _In_opt_ PVOID Parameter2, - _In_opt_ PVOID Context - ); - -PPH_STRING PhMipGetGroupNodeTooltip( - _In_ PPH_MINIINFO_LIST_SECTION ListSection, - _In_ PPH_MIP_GROUP_NODE Node - ); - -PPH_MIP_GROUP_NODE PhMipGetSelectedGroupNode( - _In_ PPH_MINIINFO_LIST_SECTION ListSection - ); - -VOID PhMipShowListSectionContextMenu( - _In_ PPH_MINIINFO_LIST_SECTION ListSection, - _In_ PPH_TREENEW_CONTEXT_MENU ContextMenu - ); - -VOID PhMipHandleListSectionCommand( - _In_ PPH_MINIINFO_LIST_SECTION ListSection, - _In_ PPH_PROCESS_GROUP ProcessGroup, - _In_ ULONG Id - ); - -// CPU section - -BOOLEAN PhMipCpuListSectionCallback( - _In_ struct _PH_MINIINFO_LIST_SECTION *ListSection, - _In_ PH_MINIINFO_LIST_SECTION_MESSAGE Message, - _In_opt_ PVOID Parameter1, - _In_opt_ PVOID Parameter2 - ); - -int __cdecl PhMipCpuListSectionProcessCompareFunction( - _In_ const void *elem1, - _In_ const void *elem2 - ); - -int __cdecl PhMipCpuListSectionNodeCompareFunction( - _In_ const void *elem1, - _In_ const void *elem2 - ); - -// Commit charge section - -BOOLEAN PhMipCommitListSectionCallback( - _In_ struct _PH_MINIINFO_LIST_SECTION *ListSection, - _In_ PH_MINIINFO_LIST_SECTION_MESSAGE Message, - _In_opt_ PVOID Parameter1, - _In_opt_ PVOID Parameter2 - ); - -int __cdecl PhMipCommitListSectionProcessCompareFunction( - _In_ const void *elem1, - _In_ const void *elem2 - ); - -int __cdecl PhMipCommitListSectionNodeCompareFunction( - _In_ const void *elem1, - _In_ const void *elem2 - ); - -// Physical memory section - -BOOLEAN PhMipPhysicalListSectionCallback( - _In_ struct _PH_MINIINFO_LIST_SECTION *ListSection, - _In_ PH_MINIINFO_LIST_SECTION_MESSAGE Message, - _In_opt_ PVOID Parameter1, - _In_opt_ PVOID Parameter2 - ); - -int __cdecl PhMipPhysicalListSectionProcessCompareFunction( - _In_ const void *elem1, - _In_ const void *elem2 - ); - -int __cdecl PhMipPhysicalListSectionNodeCompareFunction( - _In_ const void *elem1, - _In_ const void *elem2 - ); - -// I/O section - -BOOLEAN PhMipIoListSectionCallback( - _In_ struct _PH_MINIINFO_LIST_SECTION *ListSection, - _In_ PH_MINIINFO_LIST_SECTION_MESSAGE Message, - _In_opt_ PVOID Parameter1, - _In_opt_ PVOID Parameter2 - ); - -int __cdecl PhMipIoListSectionProcessCompareFunction( - _In_ const void *elem1, - _In_ const void *elem2 - ); - -int __cdecl PhMipIoListSectionNodeCompareFunction( - _In_ const void *elem1, - _In_ const void *elem2 - ); - +#ifndef PH_MINIINFOP_H +#define PH_MINIINFOP_H + +// Constants + +#define MIP_CONTAINER_CLASSNAME L"ProcessHackerMiniInfo" + +#define MIP_TIMER_PIN_FIRST 1 +#define MIP_TIMER_PIN_LAST (MIP_TIMER_PIN_FIRST + MaxMiniInfoPinType - 1) + +#define MIP_MSG_FIRST (WM_APP + 150) +#define MIP_MSG_UPDATE (WM_APP + 150) +#define MIP_MSG_LAST (WM_APP + 151) + +#define MIP_UNPIN_CHILD_CONTROL_DELAY 1000 +#define MIP_UNPIN_HOVER_DELAY 250 + +#define MIP_REFRESH_AUTOMATICALLY_PINNED 0x1 +#define MIP_REFRESH_AUTOMATICALLY_UNPINNED 0x2 +#define MIP_REFRESH_AUTOMATICALLY_FLAG(Pinned) \ + ((Pinned) ? MIP_REFRESH_AUTOMATICALLY_PINNED : MIP_REFRESH_AUTOMATICALLY_UNPINNED) + +// Misc. + +#define SET_BUTTON_ICON(hwndDlg, Id, Icon) \ + SendMessage(GetDlgItem(hwndDlg, (Id)), BM_SETIMAGE, IMAGE_ICON, (LPARAM)(Icon)) + +// Dialog procedure + +LRESULT CALLBACK PhMipContainerWndProc( + _In_ HWND hWnd, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +INT_PTR CALLBACK PhMipMiniInfoDialogProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +// Container event handlers + +VOID PhMipContainerOnShowWindow( + _In_ BOOLEAN Showing, + _In_ ULONG State + ); + +VOID PhMipContainerOnActivate( + _In_ ULONG Type, + _In_ BOOLEAN Minimized + ); + +VOID PhMipContainerOnSize( + VOID + ); + +VOID PhMipContainerOnSizing( + _In_ ULONG Edge, + _In_ PRECT DragRectangle + ); + +VOID PhMipContainerOnExitSizeMove( + VOID + ); + +BOOLEAN PhMipContainerOnEraseBkgnd( + _In_ HDC hdc + ); + +VOID PhMipContainerOnTimer( + _In_ ULONG Id + ); + +// Child dialog event handlers + +VOID PhMipOnInitDialog( + VOID + ); + +VOID PhMipOnShowWindow( + _In_ BOOLEAN Showing, + _In_ ULONG State + ); + +VOID PhMipOnCommand( + _In_ ULONG Id, + _In_ ULONG Code + ); + +BOOLEAN PhMipOnNotify( + _In_ NMHDR *Header, + _Out_ LRESULT *Result + ); + +BOOLEAN PhMipOnCtlColorXxx( + _In_ ULONG Message, + _In_ HWND hwnd, + _In_ HDC hdc, + _Out_ HBRUSH *Brush + ); + +BOOLEAN PhMipOnDrawItem( + _In_ ULONG_PTR Id, + _In_ DRAWITEMSTRUCT *DrawItemStruct + ); + +VOID PhMipOnUserMessage( + _In_ ULONG Message, + _In_ ULONG_PTR WParam, + _In_ ULONG_PTR LParam + ); + +// Framework + +typedef enum _PH_MIP_ADJUST_PIN_RESULT +{ + NoAdjustPinResult, + ShowAdjustPinResult, + HideAdjustPinResult +} PH_MIP_ADJUST_PIN_RESULT; + +BOOLEAN NTAPI PhMipMessageLoopFilter( + _In_ PMSG Message, + _In_ PVOID Context + ); + +VOID NTAPI PhMipUpdateHandler( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ); + +PH_MIP_ADJUST_PIN_RESULT PhMipAdjustPin( + _In_ PH_MINIINFO_PIN_TYPE PinType, + _In_ LONG PinCount + ); + +VOID PhMipCalculateWindowRectangle( + _In_ PPOINT SourcePoint, + _Out_ PPH_RECTANGLE WindowRectangle + ); + +VOID PhMipInitializeParameters( + VOID + ); + +PPH_MINIINFO_SECTION PhMipCreateSection( + _In_ PPH_MINIINFO_SECTION Template + ); + +VOID PhMipDestroySection( + _In_ PPH_MINIINFO_SECTION Section + ); + +PPH_MINIINFO_SECTION PhMipFindSection( + _In_ PPH_STRINGREF Name + ); + +PPH_MINIINFO_SECTION PhMipCreateInternalSection( + _In_ PWSTR Name, + _In_ ULONG Flags, + _In_ PPH_MINIINFO_SECTION_CALLBACK Callback + ); + +VOID PhMipCreateSectionDialog( + _In_ PPH_MINIINFO_SECTION Section + ); + +VOID PhMipChangeSection( + _In_ PPH_MINIINFO_SECTION NewSection + ); + +VOID PhMipSetSectionText( + _In_ struct _PH_MINIINFO_SECTION *Section, + _In_opt_ PPH_STRING Text + ); + +VOID PhMipUpdateSectionText( + _In_ PPH_MINIINFO_SECTION Section + ); + +VOID PhMipLayout( + VOID + ); + +VOID PhMipBeginChildControlPin( + VOID + ); + +VOID PhMipEndChildControlPin( + VOID + ); + +VOID PhMipRefresh( + VOID + ); + +VOID PhMipToggleRefreshAutomatically( + VOID + ); + +VOID PhMipSetPinned( + _In_ BOOLEAN Pinned + ); + +VOID PhMipShowSectionMenu( + VOID + ); + +VOID PhMipShowOptionsMenu( + VOID + ); + +LRESULT CALLBACK PhMipSectionControlHookWndProc( + _In_ HWND hwnd, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam, + _In_ UINT_PTR uIdSubclass, + _In_ ULONG_PTR dwRefData + ); + +// List-based section + +#define MIP_MAX_PROCESS_GROUPS 15 +#define MIP_SINGLE_COLUMN_ID 0 + +#define MIP_CELL_PADDING 5 +#define MIP_ICON_PADDING 3 +#define MIP_INNER_PADDING 3 + +typedef struct _PH_MIP_GROUP_NODE +{ + union + { + PH_TREENEW_NODE Node; + PH_MINIINFO_LIST_SECTION_SORT_DATA SortData; + }; + PPH_PROCESS_GROUP ProcessGroup; + HANDLE RepresentativeProcessId; + LARGE_INTEGER RepresentativeCreateTime; + BOOLEAN RepresentativeIsHung; + + PPH_STRING TooltipText; +} PH_MIP_GROUP_NODE, *PPH_MIP_GROUP_NODE; + +PPH_MINIINFO_LIST_SECTION PhMipCreateListSection( + _In_ PWSTR Name, + _In_ ULONG Flags, + _In_ PPH_MINIINFO_LIST_SECTION Template + ); + +PPH_MINIINFO_LIST_SECTION PhMipCreateInternalListSection( + _In_ PWSTR Name, + _In_ ULONG Flags, + _In_ PPH_MINIINFO_LIST_SECTION_CALLBACK Callback + ); + +BOOLEAN PhMipListSectionCallback( + _In_ PPH_MINIINFO_SECTION Section, + _In_ PH_MINIINFO_SECTION_MESSAGE Message, + _In_opt_ PVOID Parameter1, + _In_opt_ PVOID Parameter2 + ); + +INT_PTR CALLBACK PhMipListSectionDialogProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +VOID PhMipListSectionSortFunction( + _In_ PPH_LIST List, + _In_opt_ PVOID Context + ); + +VOID PhMipTickListSection( + _In_ PPH_MINIINFO_LIST_SECTION ListSection + ); + +VOID PhMipClearListSection( + _In_ PPH_MINIINFO_LIST_SECTION ListSection + ); + +LONG PhMipCalculateRowHeight( + VOID + ); + +PPH_MIP_GROUP_NODE PhMipAddGroupNode( + _In_ PPH_MINIINFO_LIST_SECTION ListSection, + _In_ PPH_PROCESS_GROUP ProcessGroup + ); + +VOID PhMipDestroyGroupNode( + _In_ PPH_MIP_GROUP_NODE Node + ); + +BOOLEAN PhMipListSectionTreeNewCallback( + _In_ HWND hwnd, + _In_ PH_TREENEW_MESSAGE Message, + _In_opt_ PVOID Parameter1, + _In_opt_ PVOID Parameter2, + _In_opt_ PVOID Context + ); + +PPH_STRING PhMipGetGroupNodeTooltip( + _In_ PPH_MINIINFO_LIST_SECTION ListSection, + _In_ PPH_MIP_GROUP_NODE Node + ); + +PPH_MIP_GROUP_NODE PhMipGetSelectedGroupNode( + _In_ PPH_MINIINFO_LIST_SECTION ListSection + ); + +VOID PhMipShowListSectionContextMenu( + _In_ PPH_MINIINFO_LIST_SECTION ListSection, + _In_ PPH_TREENEW_CONTEXT_MENU ContextMenu + ); + +VOID PhMipHandleListSectionCommand( + _In_ PPH_MINIINFO_LIST_SECTION ListSection, + _In_ PPH_PROCESS_GROUP ProcessGroup, + _In_ ULONG Id + ); + +// CPU section + +BOOLEAN PhMipCpuListSectionCallback( + _In_ struct _PH_MINIINFO_LIST_SECTION *ListSection, + _In_ PH_MINIINFO_LIST_SECTION_MESSAGE Message, + _In_opt_ PVOID Parameter1, + _In_opt_ PVOID Parameter2 + ); + +int __cdecl PhMipCpuListSectionProcessCompareFunction( + _In_ const void *elem1, + _In_ const void *elem2 + ); + +int __cdecl PhMipCpuListSectionNodeCompareFunction( + _In_ const void *elem1, + _In_ const void *elem2 + ); + +// Commit charge section + +BOOLEAN PhMipCommitListSectionCallback( + _In_ struct _PH_MINIINFO_LIST_SECTION *ListSection, + _In_ PH_MINIINFO_LIST_SECTION_MESSAGE Message, + _In_opt_ PVOID Parameter1, + _In_opt_ PVOID Parameter2 + ); + +int __cdecl PhMipCommitListSectionProcessCompareFunction( + _In_ const void *elem1, + _In_ const void *elem2 + ); + +int __cdecl PhMipCommitListSectionNodeCompareFunction( + _In_ const void *elem1, + _In_ const void *elem2 + ); + +// Physical memory section + +BOOLEAN PhMipPhysicalListSectionCallback( + _In_ struct _PH_MINIINFO_LIST_SECTION *ListSection, + _In_ PH_MINIINFO_LIST_SECTION_MESSAGE Message, + _In_opt_ PVOID Parameter1, + _In_opt_ PVOID Parameter2 + ); + +int __cdecl PhMipPhysicalListSectionProcessCompareFunction( + _In_ const void *elem1, + _In_ const void *elem2 + ); + +int __cdecl PhMipPhysicalListSectionNodeCompareFunction( + _In_ const void *elem1, + _In_ const void *elem2 + ); + +// I/O section + +BOOLEAN PhMipIoListSectionCallback( + _In_ struct _PH_MINIINFO_LIST_SECTION *ListSection, + _In_ PH_MINIINFO_LIST_SECTION_MESSAGE Message, + _In_opt_ PVOID Parameter1, + _In_opt_ PVOID Parameter2 + ); + +int __cdecl PhMipIoListSectionProcessCompareFunction( + _In_ const void *elem1, + _In_ const void *elem2 + ); + +int __cdecl PhMipIoListSectionNodeCompareFunction( + _In_ const void *elem1, + _In_ const void *elem2 + ); + #endif \ No newline at end of file diff --git a/ProcessHacker/include/notifico.h b/ProcessHacker/include/notifico.h index fe0c17781497..b0a8d613c34e 100644 --- a/ProcessHacker/include/notifico.h +++ b/ProcessHacker/include/notifico.h @@ -1,171 +1,171 @@ -#ifndef PH_NOTIFICO_H -#define PH_NOTIFICO_H - -#define PH_ICON_MINIMUM 0x1 -#define PH_ICON_CPU_HISTORY 0x1 -#define PH_ICON_IO_HISTORY 0x2 -#define PH_ICON_COMMIT_HISTORY 0x4 -#define PH_ICON_PHYSICAL_HISTORY 0x8 -#define PH_ICON_CPU_USAGE 0x10 -#define PH_ICON_DEFAULT_MAXIMUM 0x20 -#define PH_ICON_DEFAULT_ALL 0x1f - -#define PH_ICON_LIMIT 0x80000000 -#define PH_ICON_ALL 0xffffffff - -// begin_phapppub -typedef VOID (NTAPI *PPH_NF_UPDATE_REGISTERED_ICON)( - _In_ struct _PH_NF_ICON *Icon - ); - -typedef VOID (NTAPI *PPH_NF_BEGIN_BITMAP)( - _Out_ PULONG Width, - _Out_ PULONG Height, - _Out_ HBITMAP *Bitmap, - _Out_opt_ PVOID *Bits, - _Out_ HDC *Hdc, - _Out_ HBITMAP *OldBitmap - ); - -typedef struct _PH_NF_POINTERS -{ - PPH_NF_UPDATE_REGISTERED_ICON UpdateRegisteredIcon; - PPH_NF_BEGIN_BITMAP BeginBitmap; -} PH_NF_POINTERS, *PPH_NF_POINTERS; - -#define PH_NF_UPDATE_IS_BITMAP 0x1 -#define PH_NF_UPDATE_DESTROY_RESOURCE 0x2 - -typedef VOID (NTAPI *PPH_NF_ICON_UPDATE_CALLBACK)( - _In_ struct _PH_NF_ICON *Icon, - _Out_ PVOID *NewIconOrBitmap, - _Out_ PULONG Flags, - _Out_ PPH_STRING *NewText, - _In_opt_ PVOID Context - ); - -typedef BOOLEAN (NTAPI *PPH_NF_ICON_MESSAGE_CALLBACK)( - _In_ struct _PH_NF_ICON *Icon, - _In_ ULONG_PTR WParam, - _In_ ULONG_PTR LParam, - _In_opt_ PVOID Context - ); - -// Special messages -// The message type is stored in LOWORD(LParam), and the message data is in WParam. - -#define PH_NF_MSG_SHOWMINIINFOSECTION (WM_APP + 1) - -typedef struct _PH_NF_MSG_SHOWMINIINFOSECTION_DATA -{ - PWSTR SectionName; // NULL to leave unchanged -} PH_NF_MSG_SHOWMINIINFOSECTION_DATA, *PPH_NF_MSG_SHOWMINIINFOSECTION_DATA; - -// Structures and internal functions - -#define PH_NF_ICON_UNAVAILABLE 0x1 -#define PH_NF_ICON_SHOW_MINIINFO 0x2 -// end_phapppub - -// begin_phapppub -typedef struct _PH_NF_ICON -{ - // Public - - struct _PH_PLUGIN *Plugin; - ULONG SubId; - PVOID Context; - PPH_NF_POINTERS Pointers; -// end_phapppub - - // Private - - PWSTR Text; - ULONG Flags; - ULONG IconId; - PPH_NF_ICON_UPDATE_CALLBACK UpdateCallback; - PPH_NF_ICON_MESSAGE_CALLBACK MessageCallback; -// begin_phapppub -} PH_NF_ICON, *PPH_NF_ICON; -// end_phapppub - -VOID PhNfLoadStage1( - VOID - ); - -VOID PhNfLoadStage2( - VOID - ); - -VOID PhNfSaveSettings( - VOID - ); - -VOID PhNfUninitialization( - VOID - ); - -VOID PhNfForwardMessage( - _In_ ULONG_PTR WParam, - _In_ ULONG_PTR LParam - ); - -ULONG PhNfGetMaximumIconId( - VOID - ); - -ULONG PhNfTestIconMask( - _In_ ULONG Id - ); - -VOID PhNfSetVisibleIcon( - _In_ ULONG Id, - _In_ BOOLEAN Visible - ); - -BOOLEAN PhNfShowBalloonTip( - _In_opt_ ULONG Id, - _In_ PWSTR Title, - _In_ PWSTR Text, - _In_ ULONG Timeout, - _In_ ULONG Flags - ); - -HICON PhNfBitmapToIcon( - _In_ HBITMAP Bitmap - ); - -PPH_NF_ICON PhNfRegisterIcon( - _In_ struct _PH_PLUGIN *Plugin, - _In_ ULONG SubId, - _In_opt_ PVOID Context, - _In_ PWSTR Text, - _In_ ULONG Flags, - _In_opt_ PPH_NF_ICON_UPDATE_CALLBACK UpdateCallback, - _In_opt_ PPH_NF_ICON_MESSAGE_CALLBACK MessageCallback - ); - -PPH_NF_ICON PhNfGetIconById( - _In_ ULONG Id - ); - -PPH_NF_ICON PhNfFindIcon( - _In_ PPH_STRINGREF PluginName, - _In_ ULONG SubId - ); - -VOID PhNfNotifyMiniInfoPinned( - _In_ BOOLEAN Pinned - ); - -// begin_phapppub -// Public registration data - -typedef struct _PH_NF_ICON_REGISTRATION_DATA -{ - PPH_NF_ICON_UPDATE_CALLBACK UpdateCallback; - PPH_NF_ICON_MESSAGE_CALLBACK MessageCallback; -} PH_NF_ICON_REGISTRATION_DATA, *PPH_NF_ICON_REGISTRATION_DATA; -// end_phapppub - -#endif +#ifndef PH_NOTIFICO_H +#define PH_NOTIFICO_H + +#define PH_ICON_MINIMUM 0x1 +#define PH_ICON_CPU_HISTORY 0x1 +#define PH_ICON_IO_HISTORY 0x2 +#define PH_ICON_COMMIT_HISTORY 0x4 +#define PH_ICON_PHYSICAL_HISTORY 0x8 +#define PH_ICON_CPU_USAGE 0x10 +#define PH_ICON_DEFAULT_MAXIMUM 0x20 +#define PH_ICON_DEFAULT_ALL 0x1f + +#define PH_ICON_LIMIT 0x80000000 +#define PH_ICON_ALL 0xffffffff + +// begin_phapppub +typedef VOID (NTAPI *PPH_NF_UPDATE_REGISTERED_ICON)( + _In_ struct _PH_NF_ICON *Icon + ); + +typedef VOID (NTAPI *PPH_NF_BEGIN_BITMAP)( + _Out_ PULONG Width, + _Out_ PULONG Height, + _Out_ HBITMAP *Bitmap, + _Out_opt_ PVOID *Bits, + _Out_ HDC *Hdc, + _Out_ HBITMAP *OldBitmap + ); + +typedef struct _PH_NF_POINTERS +{ + PPH_NF_UPDATE_REGISTERED_ICON UpdateRegisteredIcon; + PPH_NF_BEGIN_BITMAP BeginBitmap; +} PH_NF_POINTERS, *PPH_NF_POINTERS; + +#define PH_NF_UPDATE_IS_BITMAP 0x1 +#define PH_NF_UPDATE_DESTROY_RESOURCE 0x2 + +typedef VOID (NTAPI *PPH_NF_ICON_UPDATE_CALLBACK)( + _In_ struct _PH_NF_ICON *Icon, + _Out_ PVOID *NewIconOrBitmap, + _Out_ PULONG Flags, + _Out_ PPH_STRING *NewText, + _In_opt_ PVOID Context + ); + +typedef BOOLEAN (NTAPI *PPH_NF_ICON_MESSAGE_CALLBACK)( + _In_ struct _PH_NF_ICON *Icon, + _In_ ULONG_PTR WParam, + _In_ ULONG_PTR LParam, + _In_opt_ PVOID Context + ); + +// Special messages +// The message type is stored in LOWORD(LParam), and the message data is in WParam. + +#define PH_NF_MSG_SHOWMINIINFOSECTION (WM_APP + 1) + +typedef struct _PH_NF_MSG_SHOWMINIINFOSECTION_DATA +{ + PWSTR SectionName; // NULL to leave unchanged +} PH_NF_MSG_SHOWMINIINFOSECTION_DATA, *PPH_NF_MSG_SHOWMINIINFOSECTION_DATA; + +// Structures and internal functions + +#define PH_NF_ICON_UNAVAILABLE 0x1 +#define PH_NF_ICON_SHOW_MINIINFO 0x2 +// end_phapppub + +// begin_phapppub +typedef struct _PH_NF_ICON +{ + // Public + + struct _PH_PLUGIN *Plugin; + ULONG SubId; + PVOID Context; + PPH_NF_POINTERS Pointers; +// end_phapppub + + // Private + + PWSTR Text; + ULONG Flags; + ULONG IconId; + PPH_NF_ICON_UPDATE_CALLBACK UpdateCallback; + PPH_NF_ICON_MESSAGE_CALLBACK MessageCallback; +// begin_phapppub +} PH_NF_ICON, *PPH_NF_ICON; +// end_phapppub + +VOID PhNfLoadStage1( + VOID + ); + +VOID PhNfLoadStage2( + VOID + ); + +VOID PhNfSaveSettings( + VOID + ); + +VOID PhNfUninitialization( + VOID + ); + +VOID PhNfForwardMessage( + _In_ ULONG_PTR WParam, + _In_ ULONG_PTR LParam + ); + +ULONG PhNfGetMaximumIconId( + VOID + ); + +ULONG PhNfTestIconMask( + _In_ ULONG Id + ); + +VOID PhNfSetVisibleIcon( + _In_ ULONG Id, + _In_ BOOLEAN Visible + ); + +BOOLEAN PhNfShowBalloonTip( + _In_opt_ ULONG Id, + _In_ PWSTR Title, + _In_ PWSTR Text, + _In_ ULONG Timeout, + _In_ ULONG Flags + ); + +HICON PhNfBitmapToIcon( + _In_ HBITMAP Bitmap + ); + +PPH_NF_ICON PhNfRegisterIcon( + _In_ struct _PH_PLUGIN *Plugin, + _In_ ULONG SubId, + _In_opt_ PVOID Context, + _In_ PWSTR Text, + _In_ ULONG Flags, + _In_opt_ PPH_NF_ICON_UPDATE_CALLBACK UpdateCallback, + _In_opt_ PPH_NF_ICON_MESSAGE_CALLBACK MessageCallback + ); + +PPH_NF_ICON PhNfGetIconById( + _In_ ULONG Id + ); + +PPH_NF_ICON PhNfFindIcon( + _In_ PPH_STRINGREF PluginName, + _In_ ULONG SubId + ); + +VOID PhNfNotifyMiniInfoPinned( + _In_ BOOLEAN Pinned + ); + +// begin_phapppub +// Public registration data + +typedef struct _PH_NF_ICON_REGISTRATION_DATA +{ + PPH_NF_ICON_UPDATE_CALLBACK UpdateCallback; + PPH_NF_ICON_MESSAGE_CALLBACK MessageCallback; +} PH_NF_ICON_REGISTRATION_DATA, *PPH_NF_ICON_REGISTRATION_DATA; +// end_phapppub + +#endif diff --git a/ProcessHacker/include/phapp.h b/ProcessHacker/include/phapp.h index b9fafef05156..f4ff73920fa5 100644 --- a/ProcessHacker/include/phapp.h +++ b/ProcessHacker/include/phapp.h @@ -1,753 +1,753 @@ -#ifndef PHAPP_H -#define PHAPP_H - -#define PHNT_VERSION PHNT_WIN7 - -#if !defined(_PHAPP_) -#define PHAPPAPI __declspec(dllimport) -#else -#define PHAPPAPI __declspec(dllexport) -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "../resource.h" -#include -#include - -// main - -typedef struct _PH_STARTUP_PARAMETERS -{ - union - { - struct - { - ULONG NoSettings : 1; - ULONG ShowVisible : 1; - ULONG ShowHidden : 1; - ULONG CommandMode : 1; - ULONG NoKph : 1; - ULONG InstallKph : 1; - ULONG UninstallKph : 1; - ULONG Debug : 1; - ULONG ShowOptions : 1; - ULONG PhSvc : 1; - ULONG NoPlugins : 1; - ULONG NewInstance : 1; - ULONG Elevate : 1; - ULONG Silent : 1; - ULONG Help : 1; - ULONG Spare : 17; - }; - ULONG Flags; - }; - - PPH_STRING SettingsFileName; - - HWND WindowHandle; - POINT Point; - - PPH_STRING CommandType; - PPH_STRING CommandObject; - PPH_STRING CommandAction; - PPH_STRING CommandValue; - - PPH_STRING RunAsServiceMode; - - ULONG SelectPid; - ULONG PriorityClass; - - PPH_LIST PluginParameters; - PPH_STRING SelectTab; - PPH_STRING SysInfo; -} PH_STARTUP_PARAMETERS, *PPH_STARTUP_PARAMETERS; - -extern PPH_STRING PhApplicationDirectory; -extern PPH_STRING PhApplicationFileName; -PHAPPAPI extern HFONT PhApplicationFont; // phapppub -extern PPH_STRING PhCurrentUserName; -extern HINSTANCE PhInstanceHandle; -extern PPH_STRING PhLocalSystemName; -extern BOOLEAN PhPluginsEnabled; -extern PPH_STRING PhSettingsFileName; -extern PH_INTEGER_PAIR PhSmallIconSize; -extern PH_INTEGER_PAIR PhLargeIconSize; -extern PH_STARTUP_PARAMETERS PhStartupParameters; - -extern PH_PROVIDER_THREAD PhPrimaryProviderThread; -extern PH_PROVIDER_THREAD PhSecondaryProviderThread; - -#define PH_SCALE_DPI(Value) PhMultiplyDivide(Value, PhGlobalDpi, 96) - -// begin_phapppub -PHAPPAPI -VOID -NTAPI -PhRegisterDialog( - _In_ HWND DialogWindowHandle - ); - -PHAPPAPI -VOID -NTAPI -PhUnregisterDialog( - _In_ HWND DialogWindowHandle - ); - -typedef BOOLEAN (NTAPI *PPH_MESSAGE_LOOP_FILTER)( - _In_ PMSG Message, - _In_ PVOID Context - ); - -typedef struct _PH_MESSAGE_LOOP_FILTER_ENTRY -{ - PPH_MESSAGE_LOOP_FILTER Filter; - PVOID Context; -} PH_MESSAGE_LOOP_FILTER_ENTRY, *PPH_MESSAGE_LOOP_FILTER_ENTRY; - -PHAPPAPI -struct _PH_MESSAGE_LOOP_FILTER_ENTRY * -NTAPI -PhRegisterMessageLoopFilter( - _In_ PPH_MESSAGE_LOOP_FILTER Filter, - _In_opt_ PVOID Context - ); - -PHAPPAPI -VOID -NTAPI -PhUnregisterMessageLoopFilter( - _In_ struct _PH_MESSAGE_LOOP_FILTER_ENTRY *FilterEntry - ); -// end_phapppub - -VOID PhInitializeFont( - _In_ HWND hWnd - ); - -// plugin - -extern PH_AVL_TREE PhPluginsByName; - -VOID PhPluginsInitialization( - VOID - ); - -BOOLEAN PhIsPluginDisabled( - _In_ PPH_STRINGREF BaseName - ); - -VOID PhSetPluginDisabled( - _In_ PPH_STRINGREF BaseName, - _In_ BOOLEAN Disable - ); - -VOID PhLoadPlugins( - VOID - ); - -VOID PhUnloadPlugins( - VOID - ); - -struct _PH_PLUGIN *PhFindPlugin2( - _In_ PPH_STRINGREF Name - ); - -// log - -#define PH_LOG_ENTRY_PROCESS_FIRST 1 -#define PH_LOG_ENTRY_PROCESS_CREATE 1 -#define PH_LOG_ENTRY_PROCESS_DELETE 2 -#define PH_LOG_ENTRY_PROCESS_LAST 2 - -#define PH_LOG_ENTRY_SERVICE_FIRST 3 -#define PH_LOG_ENTRY_SERVICE_CREATE 3 -#define PH_LOG_ENTRY_SERVICE_DELETE 4 -#define PH_LOG_ENTRY_SERVICE_START 5 -#define PH_LOG_ENTRY_SERVICE_STOP 6 -#define PH_LOG_ENTRY_SERVICE_CONTINUE 7 -#define PH_LOG_ENTRY_SERVICE_PAUSE 8 -#define PH_LOG_ENTRY_SERVICE_LAST 8 - -#define PH_LOG_ENTRY_MESSAGE 9 // phapppub - -typedef struct _PH_LOG_ENTRY *PPH_LOG_ENTRY; // phapppub - -typedef struct _PH_LOG_ENTRY -{ - UCHAR Type; - UCHAR Reserved1; - USHORT Flags; - LARGE_INTEGER Time; - union - { - struct - { - HANDLE ProcessId; - PPH_STRING Name; - HANDLE ParentProcessId; - PPH_STRING ParentName; - NTSTATUS ExitStatus; - } Process; - struct - { - PPH_STRING Name; - PPH_STRING DisplayName; - } Service; - PPH_STRING Message; - }; - UCHAR Buffer[1]; -} PH_LOG_ENTRY, *PPH_LOG_ENTRY; - -extern PH_CIRCULAR_BUFFER_PVOID PhLogBuffer; -PHAPPAPI extern PH_CALLBACK PhLoggedCallback; // phapppub - -VOID PhLogInitialization( - VOID - ); - -VOID PhClearLogEntries( - VOID - ); - -VOID PhLogProcessEntry( - _In_ UCHAR Type, - _In_ HANDLE ProcessId, - _In_opt_ HANDLE QueryHandle, - _In_ PPH_STRING Name, - _In_opt_ HANDLE ParentProcessId, - _In_opt_ PPH_STRING ParentName - ); - -VOID PhLogServiceEntry( - _In_ UCHAR Type, - _In_ PPH_STRING Name, - _In_ PPH_STRING DisplayName - ); - -// begin_phapppub -PHAPPAPI -VOID -NTAPI -PhLogMessageEntry( - _In_ UCHAR Type, - _In_ PPH_STRING Message - ); - -PHAPPAPI -PPH_STRING -NTAPI -PhFormatLogEntry( - _In_ PPH_LOG_ENTRY Entry - ); -// end_phapppub - -// dbgcon - -VOID PhShowDebugConsole( - VOID - ); - -// itemtips - -PPH_STRING PhGetProcessTooltipText( - _In_ PPH_PROCESS_ITEM Process, - _Out_opt_ PULONG ValidToTickCount - ); - -PPH_STRING PhGetServiceTooltipText( - _In_ PPH_SERVICE_ITEM Service - ); - -// cmdmode - -NTSTATUS PhCommandModeStart( - VOID - ); - -// anawait - -VOID PhUiAnalyzeWaitThread( - _In_ HWND hWnd, - _In_ HANDLE ProcessId, - _In_ HANDLE ThreadId, - _In_ PPH_SYMBOL_PROVIDER SymbolProvider - ); - -// mdump - -BOOLEAN PhUiCreateDumpFileProcess( - _In_ HWND hWnd, - _In_ PPH_PROCESS_ITEM Process - ); - -// about - -VOID PhShowAboutDialog( - _In_ HWND ParentWindowHandle - ); - -PPH_STRING PhGetDiagnosticsString( - VOID - ); - -// affinity - -VOID PhShowProcessAffinityDialog( - _In_ HWND ParentWindowHandle, - _In_opt_ PPH_PROCESS_ITEM ProcessItem, - _In_opt_ PPH_THREAD_ITEM ThreadItem - ); - -// begin_phapppub -PHAPPAPI -BOOLEAN -NTAPI -PhShowProcessAffinityDialog2( - _In_ HWND ParentWindowHandle, - _In_ ULONG_PTR AffinityMask, - _Out_ PULONG_PTR NewAffinityMask - ); -// end_phapppub - -// chcol - -#define PH_CONTROL_TYPE_TREE_NEW 1 - -VOID PhShowChooseColumnsDialog( - _In_ HWND ParentWindowHandle, - _In_ HWND ControlHandle, - _In_ ULONG Type - ); - -// chdlg - -// begin_phapppub -#define PH_CHOICE_DIALOG_SAVED_CHOICES 10 - -#define PH_CHOICE_DIALOG_CHOICE 0x0 -#define PH_CHOICE_DIALOG_USER_CHOICE 0x1 -#define PH_CHOICE_DIALOG_PASSWORD 0x2 -#define PH_CHOICE_DIALOG_TYPE_MASK 0x3 - -PHAPPAPI -BOOLEAN -NTAPI -PhaChoiceDialog( - _In_ HWND ParentWindowHandle, - _In_ PWSTR Title, - _In_ PWSTR Message, - _In_opt_ PWSTR *Choices, - _In_opt_ ULONG NumberOfChoices, - _In_opt_ PWSTR Option, - _In_ ULONG Flags, - _Inout_ PPH_STRING *SelectedChoice, - _Inout_opt_ PBOOLEAN SelectedOption, - _In_opt_ PWSTR SavedChoicesSettingName - ); -// end_phapppub - -// chproc - -// begin_phapppub -PHAPPAPI -BOOLEAN -NTAPI -PhShowChooseProcessDialog( - _In_ HWND ParentWindowHandle, - _In_ PWSTR Message, - _Out_ PHANDLE ProcessId - ); -// end_phapppub - -// findobj - -VOID PhShowFindObjectsDialog( - VOID - ); - -// gdihndl - -VOID PhShowGdiHandlesDialog( - _In_ HWND ParentWindowHandle, - _In_ PPH_PROCESS_ITEM ProcessItem - ); - -// hidnproc - -VOID PhShowHiddenProcessesDialog( - VOID - ); - -// hndlprp - -VOID PhShowHandleProperties( - _In_ HWND ParentWindowHandle, - _In_ HANDLE ProcessId, - _In_ PPH_HANDLE_ITEM HandleItem - ); - -// hndlstat - -VOID PhShowHandleStatisticsDialog( - _In_ HWND ParentWindowHandle, - _In_ HANDLE ProcessId - ); - -// infodlg - -VOID PhShowInformationDialog( - _In_ HWND ParentWindowHandle, - _In_ PWSTR String, - _Reserved_ ULONG Flags - ); - -// jobprp - -VOID PhShowJobProperties( - _In_ HWND ParentWindowHandle, - _In_ PPH_OPEN_OBJECT OpenObject, - _In_opt_ PVOID Context, - _In_opt_ PWSTR Title - ); - -HPROPSHEETPAGE PhCreateJobPage( - _In_ PPH_OPEN_OBJECT OpenObject, - _In_opt_ PVOID Context, - _In_opt_ DLGPROC HookProc - ); - -// logwnd - -VOID PhShowLogDialog( - VOID - ); - -// memedit - -#define PH_MEMORY_EDITOR_UNMAP_VIEW_OF_SECTION 0x1 - -VOID PhShowMemoryEditorDialog( - _In_ HANDLE ProcessId, - _In_ PVOID BaseAddress, - _In_ SIZE_T RegionSize, - _In_ ULONG SelectOffset, - _In_ ULONG SelectLength, - _In_opt_ PPH_STRING Title, - _In_ ULONG Flags - ); - -// memlists - -VOID PhShowMemoryListsDialog( - _In_ HWND ParentWindowHandle, - _In_opt_ VOID (NTAPI *RegisterDialog)(HWND), - _In_opt_ VOID (NTAPI *UnregisterDialog)(HWND) - ); - -// memprot - -VOID PhShowMemoryProtectDialog( - _In_ HWND ParentWindowHandle, - _In_ PPH_PROCESS_ITEM ProcessItem, - _In_ PPH_MEMORY_ITEM MemoryItem - ); - -// memrslt - -VOID PhShowMemoryResultsDialog( - _In_ HANDLE ProcessId, - _In_ PPH_LIST Results - ); - -// memsrch - -VOID PhShowMemoryStringDialog( - _In_ HWND ParentWindowHandle, - _In_ PPH_PROCESS_ITEM ProcessItem - ); - -// mtgndlg - -VOID PhShowProcessMitigationPolicyDialog( - _In_ HWND ParentWindowHandle, - _In_ struct _PH_PROCESS_MITIGATION_POLICY_ALL_INFORMATION *Information - ); - -// netstk - -VOID PhShowNetworkStackDialog( - _In_ HWND ParentWindowHandle, - _In_ PPH_NETWORK_ITEM NetworkItem - ); - -// ntobjprp - -HPROPSHEETPAGE PhCreateEventPage( - _In_ PPH_OPEN_OBJECT OpenObject, - _In_opt_ PVOID Context - ); - -HPROPSHEETPAGE PhCreateEventPairPage( - _In_ PPH_OPEN_OBJECT OpenObject, - _In_opt_ PVOID Context - ); - -HPROPSHEETPAGE PhCreateMutantPage( - _In_ PPH_OPEN_OBJECT OpenObject, - _In_opt_ PVOID Context - ); - -HPROPSHEETPAGE PhCreateSectionPage( - _In_ PPH_OPEN_OBJECT OpenObject, - _In_opt_ PVOID Context - ); - -HPROPSHEETPAGE PhCreateSemaphorePage( - _In_ PPH_OPEN_OBJECT OpenObject, - _In_opt_ PVOID Context - ); - -HPROPSHEETPAGE PhCreateTimerPage( - _In_ PPH_OPEN_OBJECT OpenObject, - _In_opt_ PVOID Context - ); - -// options - -VOID PhShowOptionsDialog( - _In_ HWND ParentWindowHandle - ); - -// pagfiles - -VOID PhShowPagefilesDialog( - _In_ HWND ParentWindowHandle - ); - -// plugman - -VOID PhShowPluginsDialog( - _In_ HWND ParentWindowHandle - ); - -// procrec - -// begin_phapppub -PHAPPAPI -VOID -NTAPI -PhShowProcessRecordDialog( - _In_ HWND ParentWindowHandle, - _In_ PPH_PROCESS_RECORD Record - ); -// end_phapppub - -// runas - -typedef struct _PH_RUNAS_SERVICE_PARAMETERS -{ - ULONG ProcessId; - PWSTR UserName; - PWSTR Password; - ULONG LogonType; - ULONG SessionId; - PWSTR CurrentDirectory; - PWSTR CommandLine; - PWSTR FileName; - PWSTR DesktopName; - BOOLEAN UseLinkedToken; - PWSTR ServiceName; -} PH_RUNAS_SERVICE_PARAMETERS, *PPH_RUNAS_SERVICE_PARAMETERS; - -VOID PhShowRunAsDialog( - _In_ HWND ParentWindowHandle, - _In_opt_ HANDLE ProcessId - ); - -NTSTATUS PhExecuteRunAsCommand( - _In_ PPH_RUNAS_SERVICE_PARAMETERS Parameters - ); - -// begin_phapppub -PHAPPAPI -NTSTATUS -NTAPI -PhExecuteRunAsCommand2( - _In_ HWND hWnd, - _In_ PWSTR Program, - _In_opt_ PWSTR UserName, - _In_opt_ PWSTR Password, - _In_opt_ ULONG LogonType, - _In_opt_ HANDLE ProcessIdWithToken, - _In_ ULONG SessionId, - _In_ PWSTR DesktopName, - _In_ BOOLEAN UseLinkedToken - ); -// end_phapppub - -NTSTATUS PhRunAsServiceStart( - _In_ PPH_STRING ServiceName - ); - -NTSTATUS PhInvokeRunAsService( - _In_ PPH_RUNAS_SERVICE_PARAMETERS Parameters - ); - -// searchbox - -// begin_phapppub -PHAPPAPI -VOID -NTAPI -PhCreateSearchControl( - _In_ HWND Parent, - _In_ HWND WindowHandle, - _In_ PWSTR BannerText - ); - -PHAPPAPI -HBITMAP -NTAPI -PhLoadPngImageFromResource( - _In_ PVOID DllBase, - _In_ UINT Width, - _In_ UINT Height, - _In_ PCWSTR Name, - _In_ BOOLEAN RGBAImage - ); - -FORCEINLINE -HFONT -PhCreateCommonFont( - _In_ LONG Size, - _In_ INT Weight, - _In_opt_ HWND hwnd - ) -{ - HFONT fontHandle; - LOGFONT logFont; - - if (!SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(LOGFONT), &logFont, 0)) - return NULL; - - fontHandle = CreateFont( - -PhMultiplyDivideSigned(Size, PhGlobalDpi, 72), - 0, - 0, - 0, - Weight, - FALSE, - FALSE, - FALSE, - ANSI_CHARSET, - OUT_DEFAULT_PRECIS, - CLIP_DEFAULT_PRECIS, - CLEARTYPE_QUALITY | ANTIALIASED_QUALITY, - DEFAULT_PITCH, - logFont.lfFaceName - ); - - if (!fontHandle) - return NULL; - - if (hwnd) - SendMessage(hwnd, WM_SETFONT, (WPARAM)fontHandle, TRUE); - - return fontHandle; -} -// end_phapppub - -// sessmsg - -VOID PhShowSessionSendMessageDialog( - _In_ HWND ParentWindowHandle, - _In_ ULONG SessionId - ); - -// sessprp - -VOID PhShowSessionProperties( - _In_ HWND ParentWindowHandle, - _In_ ULONG SessionId - ); - -// sessshad - -VOID PhShowSessionShadowDialog( - _In_ HWND ParentWindowHandle, - _In_ ULONG SessionId - ); - -// srvcr - -VOID PhShowCreateServiceDialog( - _In_ HWND ParentWindowHandle - ); - -// srvctl - -// begin_phapppub -#define WM_PH_SET_LIST_VIEW_SETTINGS (WM_APP + 701) - -PHAPPAPI -HWND -NTAPI -PhCreateServiceListControl( - _In_ HWND ParentWindowHandle, - _In_ PPH_SERVICE_ITEM *Services, - _In_ ULONG NumberOfServices - ); -// end_phapppub - -// srvprp - -VOID PhShowServiceProperties( - _In_ HWND ParentWindowHandle, - _In_ PPH_SERVICE_ITEM ServiceItem - ); - -// thrdstk - -VOID PhShowThreadStackDialog( - _In_ HWND ParentWindowHandle, - _In_ HANDLE ProcessId, - _In_ HANDLE ThreadId, - _In_ PPH_THREAD_PROVIDER ThreadProvider - ); - -// tokprp - -PPH_STRING PhGetGroupAttributesString( - _In_ ULONG Attributes - ); - -PWSTR PhGetPrivilegeAttributesString( - _In_ ULONG Attributes - ); - -VOID PhShowTokenProperties( - _In_ HWND ParentWindowHandle, - _In_ PPH_OPEN_OBJECT OpenObject, - _In_opt_ PVOID Context, - _In_opt_ PWSTR Title - ); - -HPROPSHEETPAGE PhCreateTokenPage( - _In_ PPH_OPEN_OBJECT OpenObject, - _In_opt_ PVOID Context, - _In_opt_ DLGPROC HookProc - ); - -#endif +#ifndef PHAPP_H +#define PHAPP_H + +#define PHNT_VERSION PHNT_WIN7 + +#if !defined(_PHAPP_) +#define PHAPPAPI __declspec(dllimport) +#else +#define PHAPPAPI __declspec(dllexport) +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../resource.h" +#include +#include + +// main + +typedef struct _PH_STARTUP_PARAMETERS +{ + union + { + struct + { + ULONG NoSettings : 1; + ULONG ShowVisible : 1; + ULONG ShowHidden : 1; + ULONG CommandMode : 1; + ULONG NoKph : 1; + ULONG InstallKph : 1; + ULONG UninstallKph : 1; + ULONG Debug : 1; + ULONG ShowOptions : 1; + ULONG PhSvc : 1; + ULONG NoPlugins : 1; + ULONG NewInstance : 1; + ULONG Elevate : 1; + ULONG Silent : 1; + ULONG Help : 1; + ULONG Spare : 17; + }; + ULONG Flags; + }; + + PPH_STRING SettingsFileName; + + HWND WindowHandle; + POINT Point; + + PPH_STRING CommandType; + PPH_STRING CommandObject; + PPH_STRING CommandAction; + PPH_STRING CommandValue; + + PPH_STRING RunAsServiceMode; + + ULONG SelectPid; + ULONG PriorityClass; + + PPH_LIST PluginParameters; + PPH_STRING SelectTab; + PPH_STRING SysInfo; +} PH_STARTUP_PARAMETERS, *PPH_STARTUP_PARAMETERS; + +extern PPH_STRING PhApplicationDirectory; +extern PPH_STRING PhApplicationFileName; +PHAPPAPI extern HFONT PhApplicationFont; // phapppub +extern PPH_STRING PhCurrentUserName; +extern HINSTANCE PhInstanceHandle; +extern PPH_STRING PhLocalSystemName; +extern BOOLEAN PhPluginsEnabled; +extern PPH_STRING PhSettingsFileName; +extern PH_INTEGER_PAIR PhSmallIconSize; +extern PH_INTEGER_PAIR PhLargeIconSize; +extern PH_STARTUP_PARAMETERS PhStartupParameters; + +extern PH_PROVIDER_THREAD PhPrimaryProviderThread; +extern PH_PROVIDER_THREAD PhSecondaryProviderThread; + +#define PH_SCALE_DPI(Value) PhMultiplyDivide(Value, PhGlobalDpi, 96) + +// begin_phapppub +PHAPPAPI +VOID +NTAPI +PhRegisterDialog( + _In_ HWND DialogWindowHandle + ); + +PHAPPAPI +VOID +NTAPI +PhUnregisterDialog( + _In_ HWND DialogWindowHandle + ); + +typedef BOOLEAN (NTAPI *PPH_MESSAGE_LOOP_FILTER)( + _In_ PMSG Message, + _In_ PVOID Context + ); + +typedef struct _PH_MESSAGE_LOOP_FILTER_ENTRY +{ + PPH_MESSAGE_LOOP_FILTER Filter; + PVOID Context; +} PH_MESSAGE_LOOP_FILTER_ENTRY, *PPH_MESSAGE_LOOP_FILTER_ENTRY; + +PHAPPAPI +struct _PH_MESSAGE_LOOP_FILTER_ENTRY * +NTAPI +PhRegisterMessageLoopFilter( + _In_ PPH_MESSAGE_LOOP_FILTER Filter, + _In_opt_ PVOID Context + ); + +PHAPPAPI +VOID +NTAPI +PhUnregisterMessageLoopFilter( + _In_ struct _PH_MESSAGE_LOOP_FILTER_ENTRY *FilterEntry + ); +// end_phapppub + +VOID PhInitializeFont( + _In_ HWND hWnd + ); + +// plugin + +extern PH_AVL_TREE PhPluginsByName; + +VOID PhPluginsInitialization( + VOID + ); + +BOOLEAN PhIsPluginDisabled( + _In_ PPH_STRINGREF BaseName + ); + +VOID PhSetPluginDisabled( + _In_ PPH_STRINGREF BaseName, + _In_ BOOLEAN Disable + ); + +VOID PhLoadPlugins( + VOID + ); + +VOID PhUnloadPlugins( + VOID + ); + +struct _PH_PLUGIN *PhFindPlugin2( + _In_ PPH_STRINGREF Name + ); + +// log + +#define PH_LOG_ENTRY_PROCESS_FIRST 1 +#define PH_LOG_ENTRY_PROCESS_CREATE 1 +#define PH_LOG_ENTRY_PROCESS_DELETE 2 +#define PH_LOG_ENTRY_PROCESS_LAST 2 + +#define PH_LOG_ENTRY_SERVICE_FIRST 3 +#define PH_LOG_ENTRY_SERVICE_CREATE 3 +#define PH_LOG_ENTRY_SERVICE_DELETE 4 +#define PH_LOG_ENTRY_SERVICE_START 5 +#define PH_LOG_ENTRY_SERVICE_STOP 6 +#define PH_LOG_ENTRY_SERVICE_CONTINUE 7 +#define PH_LOG_ENTRY_SERVICE_PAUSE 8 +#define PH_LOG_ENTRY_SERVICE_LAST 8 + +#define PH_LOG_ENTRY_MESSAGE 9 // phapppub + +typedef struct _PH_LOG_ENTRY *PPH_LOG_ENTRY; // phapppub + +typedef struct _PH_LOG_ENTRY +{ + UCHAR Type; + UCHAR Reserved1; + USHORT Flags; + LARGE_INTEGER Time; + union + { + struct + { + HANDLE ProcessId; + PPH_STRING Name; + HANDLE ParentProcessId; + PPH_STRING ParentName; + NTSTATUS ExitStatus; + } Process; + struct + { + PPH_STRING Name; + PPH_STRING DisplayName; + } Service; + PPH_STRING Message; + }; + UCHAR Buffer[1]; +} PH_LOG_ENTRY, *PPH_LOG_ENTRY; + +extern PH_CIRCULAR_BUFFER_PVOID PhLogBuffer; +PHAPPAPI extern PH_CALLBACK PhLoggedCallback; // phapppub + +VOID PhLogInitialization( + VOID + ); + +VOID PhClearLogEntries( + VOID + ); + +VOID PhLogProcessEntry( + _In_ UCHAR Type, + _In_ HANDLE ProcessId, + _In_opt_ HANDLE QueryHandle, + _In_ PPH_STRING Name, + _In_opt_ HANDLE ParentProcessId, + _In_opt_ PPH_STRING ParentName + ); + +VOID PhLogServiceEntry( + _In_ UCHAR Type, + _In_ PPH_STRING Name, + _In_ PPH_STRING DisplayName + ); + +// begin_phapppub +PHAPPAPI +VOID +NTAPI +PhLogMessageEntry( + _In_ UCHAR Type, + _In_ PPH_STRING Message + ); + +PHAPPAPI +PPH_STRING +NTAPI +PhFormatLogEntry( + _In_ PPH_LOG_ENTRY Entry + ); +// end_phapppub + +// dbgcon + +VOID PhShowDebugConsole( + VOID + ); + +// itemtips + +PPH_STRING PhGetProcessTooltipText( + _In_ PPH_PROCESS_ITEM Process, + _Out_opt_ PULONG ValidToTickCount + ); + +PPH_STRING PhGetServiceTooltipText( + _In_ PPH_SERVICE_ITEM Service + ); + +// cmdmode + +NTSTATUS PhCommandModeStart( + VOID + ); + +// anawait + +VOID PhUiAnalyzeWaitThread( + _In_ HWND hWnd, + _In_ HANDLE ProcessId, + _In_ HANDLE ThreadId, + _In_ PPH_SYMBOL_PROVIDER SymbolProvider + ); + +// mdump + +BOOLEAN PhUiCreateDumpFileProcess( + _In_ HWND hWnd, + _In_ PPH_PROCESS_ITEM Process + ); + +// about + +VOID PhShowAboutDialog( + _In_ HWND ParentWindowHandle + ); + +PPH_STRING PhGetDiagnosticsString( + VOID + ); + +// affinity + +VOID PhShowProcessAffinityDialog( + _In_ HWND ParentWindowHandle, + _In_opt_ PPH_PROCESS_ITEM ProcessItem, + _In_opt_ PPH_THREAD_ITEM ThreadItem + ); + +// begin_phapppub +PHAPPAPI +BOOLEAN +NTAPI +PhShowProcessAffinityDialog2( + _In_ HWND ParentWindowHandle, + _In_ ULONG_PTR AffinityMask, + _Out_ PULONG_PTR NewAffinityMask + ); +// end_phapppub + +// chcol + +#define PH_CONTROL_TYPE_TREE_NEW 1 + +VOID PhShowChooseColumnsDialog( + _In_ HWND ParentWindowHandle, + _In_ HWND ControlHandle, + _In_ ULONG Type + ); + +// chdlg + +// begin_phapppub +#define PH_CHOICE_DIALOG_SAVED_CHOICES 10 + +#define PH_CHOICE_DIALOG_CHOICE 0x0 +#define PH_CHOICE_DIALOG_USER_CHOICE 0x1 +#define PH_CHOICE_DIALOG_PASSWORD 0x2 +#define PH_CHOICE_DIALOG_TYPE_MASK 0x3 + +PHAPPAPI +BOOLEAN +NTAPI +PhaChoiceDialog( + _In_ HWND ParentWindowHandle, + _In_ PWSTR Title, + _In_ PWSTR Message, + _In_opt_ PWSTR *Choices, + _In_opt_ ULONG NumberOfChoices, + _In_opt_ PWSTR Option, + _In_ ULONG Flags, + _Inout_ PPH_STRING *SelectedChoice, + _Inout_opt_ PBOOLEAN SelectedOption, + _In_opt_ PWSTR SavedChoicesSettingName + ); +// end_phapppub + +// chproc + +// begin_phapppub +PHAPPAPI +BOOLEAN +NTAPI +PhShowChooseProcessDialog( + _In_ HWND ParentWindowHandle, + _In_ PWSTR Message, + _Out_ PHANDLE ProcessId + ); +// end_phapppub + +// findobj + +VOID PhShowFindObjectsDialog( + VOID + ); + +// gdihndl + +VOID PhShowGdiHandlesDialog( + _In_ HWND ParentWindowHandle, + _In_ PPH_PROCESS_ITEM ProcessItem + ); + +// hidnproc + +VOID PhShowHiddenProcessesDialog( + VOID + ); + +// hndlprp + +VOID PhShowHandleProperties( + _In_ HWND ParentWindowHandle, + _In_ HANDLE ProcessId, + _In_ PPH_HANDLE_ITEM HandleItem + ); + +// hndlstat + +VOID PhShowHandleStatisticsDialog( + _In_ HWND ParentWindowHandle, + _In_ HANDLE ProcessId + ); + +// infodlg + +VOID PhShowInformationDialog( + _In_ HWND ParentWindowHandle, + _In_ PWSTR String, + _Reserved_ ULONG Flags + ); + +// jobprp + +VOID PhShowJobProperties( + _In_ HWND ParentWindowHandle, + _In_ PPH_OPEN_OBJECT OpenObject, + _In_opt_ PVOID Context, + _In_opt_ PWSTR Title + ); + +HPROPSHEETPAGE PhCreateJobPage( + _In_ PPH_OPEN_OBJECT OpenObject, + _In_opt_ PVOID Context, + _In_opt_ DLGPROC HookProc + ); + +// logwnd + +VOID PhShowLogDialog( + VOID + ); + +// memedit + +#define PH_MEMORY_EDITOR_UNMAP_VIEW_OF_SECTION 0x1 + +VOID PhShowMemoryEditorDialog( + _In_ HANDLE ProcessId, + _In_ PVOID BaseAddress, + _In_ SIZE_T RegionSize, + _In_ ULONG SelectOffset, + _In_ ULONG SelectLength, + _In_opt_ PPH_STRING Title, + _In_ ULONG Flags + ); + +// memlists + +VOID PhShowMemoryListsDialog( + _In_ HWND ParentWindowHandle, + _In_opt_ VOID (NTAPI *RegisterDialog)(HWND), + _In_opt_ VOID (NTAPI *UnregisterDialog)(HWND) + ); + +// memprot + +VOID PhShowMemoryProtectDialog( + _In_ HWND ParentWindowHandle, + _In_ PPH_PROCESS_ITEM ProcessItem, + _In_ PPH_MEMORY_ITEM MemoryItem + ); + +// memrslt + +VOID PhShowMemoryResultsDialog( + _In_ HANDLE ProcessId, + _In_ PPH_LIST Results + ); + +// memsrch + +VOID PhShowMemoryStringDialog( + _In_ HWND ParentWindowHandle, + _In_ PPH_PROCESS_ITEM ProcessItem + ); + +// mtgndlg + +VOID PhShowProcessMitigationPolicyDialog( + _In_ HWND ParentWindowHandle, + _In_ struct _PH_PROCESS_MITIGATION_POLICY_ALL_INFORMATION *Information + ); + +// netstk + +VOID PhShowNetworkStackDialog( + _In_ HWND ParentWindowHandle, + _In_ PPH_NETWORK_ITEM NetworkItem + ); + +// ntobjprp + +HPROPSHEETPAGE PhCreateEventPage( + _In_ PPH_OPEN_OBJECT OpenObject, + _In_opt_ PVOID Context + ); + +HPROPSHEETPAGE PhCreateEventPairPage( + _In_ PPH_OPEN_OBJECT OpenObject, + _In_opt_ PVOID Context + ); + +HPROPSHEETPAGE PhCreateMutantPage( + _In_ PPH_OPEN_OBJECT OpenObject, + _In_opt_ PVOID Context + ); + +HPROPSHEETPAGE PhCreateSectionPage( + _In_ PPH_OPEN_OBJECT OpenObject, + _In_opt_ PVOID Context + ); + +HPROPSHEETPAGE PhCreateSemaphorePage( + _In_ PPH_OPEN_OBJECT OpenObject, + _In_opt_ PVOID Context + ); + +HPROPSHEETPAGE PhCreateTimerPage( + _In_ PPH_OPEN_OBJECT OpenObject, + _In_opt_ PVOID Context + ); + +// options + +VOID PhShowOptionsDialog( + _In_ HWND ParentWindowHandle + ); + +// pagfiles + +VOID PhShowPagefilesDialog( + _In_ HWND ParentWindowHandle + ); + +// plugman + +VOID PhShowPluginsDialog( + _In_ HWND ParentWindowHandle + ); + +// procrec + +// begin_phapppub +PHAPPAPI +VOID +NTAPI +PhShowProcessRecordDialog( + _In_ HWND ParentWindowHandle, + _In_ PPH_PROCESS_RECORD Record + ); +// end_phapppub + +// runas + +typedef struct _PH_RUNAS_SERVICE_PARAMETERS +{ + ULONG ProcessId; + PWSTR UserName; + PWSTR Password; + ULONG LogonType; + ULONG SessionId; + PWSTR CurrentDirectory; + PWSTR CommandLine; + PWSTR FileName; + PWSTR DesktopName; + BOOLEAN UseLinkedToken; + PWSTR ServiceName; +} PH_RUNAS_SERVICE_PARAMETERS, *PPH_RUNAS_SERVICE_PARAMETERS; + +VOID PhShowRunAsDialog( + _In_ HWND ParentWindowHandle, + _In_opt_ HANDLE ProcessId + ); + +NTSTATUS PhExecuteRunAsCommand( + _In_ PPH_RUNAS_SERVICE_PARAMETERS Parameters + ); + +// begin_phapppub +PHAPPAPI +NTSTATUS +NTAPI +PhExecuteRunAsCommand2( + _In_ HWND hWnd, + _In_ PWSTR Program, + _In_opt_ PWSTR UserName, + _In_opt_ PWSTR Password, + _In_opt_ ULONG LogonType, + _In_opt_ HANDLE ProcessIdWithToken, + _In_ ULONG SessionId, + _In_ PWSTR DesktopName, + _In_ BOOLEAN UseLinkedToken + ); +// end_phapppub + +NTSTATUS PhRunAsServiceStart( + _In_ PPH_STRING ServiceName + ); + +NTSTATUS PhInvokeRunAsService( + _In_ PPH_RUNAS_SERVICE_PARAMETERS Parameters + ); + +// searchbox + +// begin_phapppub +PHAPPAPI +VOID +NTAPI +PhCreateSearchControl( + _In_ HWND Parent, + _In_ HWND WindowHandle, + _In_ PWSTR BannerText + ); + +PHAPPAPI +HBITMAP +NTAPI +PhLoadPngImageFromResource( + _In_ PVOID DllBase, + _In_ UINT Width, + _In_ UINT Height, + _In_ PCWSTR Name, + _In_ BOOLEAN RGBAImage + ); + +FORCEINLINE +HFONT +PhCreateCommonFont( + _In_ LONG Size, + _In_ INT Weight, + _In_opt_ HWND hwnd + ) +{ + HFONT fontHandle; + LOGFONT logFont; + + if (!SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(LOGFONT), &logFont, 0)) + return NULL; + + fontHandle = CreateFont( + -PhMultiplyDivideSigned(Size, PhGlobalDpi, 72), + 0, + 0, + 0, + Weight, + FALSE, + FALSE, + FALSE, + ANSI_CHARSET, + OUT_DEFAULT_PRECIS, + CLIP_DEFAULT_PRECIS, + CLEARTYPE_QUALITY | ANTIALIASED_QUALITY, + DEFAULT_PITCH, + logFont.lfFaceName + ); + + if (!fontHandle) + return NULL; + + if (hwnd) + SendMessage(hwnd, WM_SETFONT, (WPARAM)fontHandle, TRUE); + + return fontHandle; +} +// end_phapppub + +// sessmsg + +VOID PhShowSessionSendMessageDialog( + _In_ HWND ParentWindowHandle, + _In_ ULONG SessionId + ); + +// sessprp + +VOID PhShowSessionProperties( + _In_ HWND ParentWindowHandle, + _In_ ULONG SessionId + ); + +// sessshad + +VOID PhShowSessionShadowDialog( + _In_ HWND ParentWindowHandle, + _In_ ULONG SessionId + ); + +// srvcr + +VOID PhShowCreateServiceDialog( + _In_ HWND ParentWindowHandle + ); + +// srvctl + +// begin_phapppub +#define WM_PH_SET_LIST_VIEW_SETTINGS (WM_APP + 701) + +PHAPPAPI +HWND +NTAPI +PhCreateServiceListControl( + _In_ HWND ParentWindowHandle, + _In_ PPH_SERVICE_ITEM *Services, + _In_ ULONG NumberOfServices + ); +// end_phapppub + +// srvprp + +VOID PhShowServiceProperties( + _In_ HWND ParentWindowHandle, + _In_ PPH_SERVICE_ITEM ServiceItem + ); + +// thrdstk + +VOID PhShowThreadStackDialog( + _In_ HWND ParentWindowHandle, + _In_ HANDLE ProcessId, + _In_ HANDLE ThreadId, + _In_ PPH_THREAD_PROVIDER ThreadProvider + ); + +// tokprp + +PPH_STRING PhGetGroupAttributesString( + _In_ ULONG Attributes + ); + +PWSTR PhGetPrivilegeAttributesString( + _In_ ULONG Attributes + ); + +VOID PhShowTokenProperties( + _In_ HWND ParentWindowHandle, + _In_ PPH_OPEN_OBJECT OpenObject, + _In_opt_ PVOID Context, + _In_opt_ PWSTR Title + ); + +HPROPSHEETPAGE PhCreateTokenPage( + _In_ PPH_OPEN_OBJECT OpenObject, + _In_opt_ PVOID Context, + _In_opt_ DLGPROC HookProc + ); + +#endif diff --git a/ProcessHacker/include/phappres.h b/ProcessHacker/include/phappres.h index e0ff77b3e913..3f8215df22e9 100644 --- a/ProcessHacker/include/phappres.h +++ b/ProcessHacker/include/phappres.h @@ -1,34 +1,34 @@ -// Notes: -// * Do not use /* comments */ since ISPP is buggy and it will throw an error. - -#ifndef PH_PHAPPRES_H -#define PH_PHAPPRES_H - -#include "phapprev.h" - -#define PHAPP_VERSION_MAJOR 3 -#define PHAPP_VERSION_MINOR 0 -#define PHAPP_VERSION_BUILD 0 - -#if (PHAPP_VERSION_BUILD == 0) -#define TWO_DIGIT_VER 1 -#else -#define THREE_DIGIT_VER 1 -#endif - -#define DO_MAKE_STR(x) #x -#define MAKE_STR(x) DO_MAKE_STR(x) - -#ifndef ISPP_INVOKED - -#if defined(TWO_DIGIT_VER) -#define PHAPP_VERSION_STRING MAKE_STR(PHAPP_VERSION_MAJOR) "." MAKE_STR(PHAPP_VERSION_MINOR) ".0" "." MAKE_STR(PHAPP_VERSION_REVISION) -#elif defined(THREE_DIGIT_VER) -#define PHAPP_VERSION_STRING MAKE_STR(PHAPP_VERSION_MAJOR) "." MAKE_STR(PHAPP_VERSION_MINOR) "." MAKE_STR(PHAPP_VERSION_BUILD) "." MAKE_STR(PHAPP_VERSION_REVISION) -#endif - -#define PHAPP_VERSION_NUMBER PHAPP_VERSION_MAJOR,PHAPP_VERSION_MINOR,PHAPP_VERSION_BUILD,PHAPP_VERSION_REVISION - -#endif // ISPP_INVOKED - -#endif // PHAPPRES_H +// Notes: +// * Do not use /* comments */ since ISPP is buggy and it will throw an error. + +#ifndef PH_PHAPPRES_H +#define PH_PHAPPRES_H + +#include "phapprev.h" + +#define PHAPP_VERSION_MAJOR 3 +#define PHAPP_VERSION_MINOR 0 +#define PHAPP_VERSION_BUILD 0 + +#if (PHAPP_VERSION_BUILD == 0) +#define TWO_DIGIT_VER 1 +#else +#define THREE_DIGIT_VER 1 +#endif + +#define DO_MAKE_STR(x) #x +#define MAKE_STR(x) DO_MAKE_STR(x) + +#ifndef ISPP_INVOKED + +#if defined(TWO_DIGIT_VER) +#define PHAPP_VERSION_STRING MAKE_STR(PHAPP_VERSION_MAJOR) "." MAKE_STR(PHAPP_VERSION_MINOR) ".0" "." MAKE_STR(PHAPP_VERSION_REVISION) +#elif defined(THREE_DIGIT_VER) +#define PHAPP_VERSION_STRING MAKE_STR(PHAPP_VERSION_MAJOR) "." MAKE_STR(PHAPP_VERSION_MINOR) "." MAKE_STR(PHAPP_VERSION_BUILD) "." MAKE_STR(PHAPP_VERSION_REVISION) +#endif + +#define PHAPP_VERSION_NUMBER PHAPP_VERSION_MAJOR,PHAPP_VERSION_MINOR,PHAPP_VERSION_BUILD,PHAPP_VERSION_REVISION + +#endif // ISPP_INVOKED + +#endif // PHAPPRES_H diff --git a/ProcessHacker/include/phapprev_in.h b/ProcessHacker/include/phapprev_in.h index 5f08adeb2006..c1e40313fd88 100644 --- a/ProcessHacker/include/phapprev_in.h +++ b/ProcessHacker/include/phapprev_in.h @@ -1,6 +1,6 @@ -#ifndef PHAPPREV_H -#define PHAPPREV_H - -#define PHAPP_VERSION_REVISION $COMMITS$ - -#endif // PHAPPREV_H +#ifndef PHAPPREV_H +#define PHAPPREV_H + +#define PHAPP_VERSION_REVISION $COMMITS$ + +#endif // PHAPPREV_H diff --git a/ProcessHacker/include/phplug.h b/ProcessHacker/include/phplug.h index ab54b1c22be3..68ea5602ede1 100644 --- a/ProcessHacker/include/phplug.h +++ b/ProcessHacker/include/phplug.h @@ -1,675 +1,675 @@ -#ifndef PH_PHPLUG_H -#define PH_PHPLUG_H - -#include -#include -#include - -// begin_phapppub -// Callbacks - -typedef enum _PH_GENERAL_CALLBACK -{ - GeneralCallbackMainWindowShowing = 0, // INT ShowCommand [main thread] - GeneralCallbackProcessesUpdated = 1, // [main thread] - GeneralCallbackGetProcessHighlightingColor = 2, // PPH_PLUGIN_GET_HIGHLIGHTING_COLOR Data [main thread] - GeneralCallbackGetProcessTooltipText = 3, // PPH_PLUGIN_GET_TOOLTIP_TEXT Data [main thread] - GeneralCallbackProcessPropertiesInitializing = 4, // PPH_PLUGIN_PROCESS_PROPCONTEXT Data [properties thread] - GeneralCallbackMainMenuInitializing = 5, // PPH_PLUGIN_MENU_INFORMATION Data [main thread] - GeneralCallbackNotifyEvent = 6, // PPH_PLUGIN_NOTIFY_EVENT Data [main thread] - GeneralCallbackServicePropertiesInitializing = 7, // PPH_PLUGIN_OBJECT_PROPERTIES Data [properties thread] - GeneralCallbackHandlePropertiesInitializing = 8, // PPH_PLUGIN_OBJECT_PROPERTIES Data [properties thread] - GeneralCallbackProcessMenuInitializing = 9, // PPH_PLUGIN_MENU_INFORMATION Data [main thread] - GeneralCallbackServiceMenuInitializing = 10, // PPH_PLUGIN_MENU_INFORMATION Data [main thread] - GeneralCallbackNetworkMenuInitializing = 11, // PPH_PLUGIN_MENU_INFORMATION Data [main thread] - GeneralCallbackIconMenuInitializing = 12, // PPH_PLUGIN_MENU_INFORMATION Data [main thread] - GeneralCallbackThreadMenuInitializing = 13, // PPH_PLUGIN_MENU_INFORMATION Data [properties thread] - GeneralCallbackModuleMenuInitializing = 14, // PPH_PLUGIN_MENU_INFORMATION Data [properties thread] - GeneralCallbackMemoryMenuInitializing = 15, // PPH_PLUGIN_MENU_INFORMATION Data [properties thread] - GeneralCallbackHandleMenuInitializing = 16, // PPH_PLUGIN_MENU_INFORMATION Data [properties thread] - GeneralCallbackProcessTreeNewInitializing = 17, // PPH_PLUGIN_TREENEW_INFORMATION Data [main thread] - GeneralCallbackServiceTreeNewInitializing = 18, // PPH_PLUGIN_TREENEW_INFORMATION Data [main thread] - GeneralCallbackNetworkTreeNewInitializing = 19, // PPH_PLUGIN_TREENEW_INFORMATION Data [main thread] - GeneralCallbackModuleTreeNewInitializing = 20, // PPH_PLUGIN_TREENEW_INFORMATION Data [properties thread] - GeneralCallbackModuleTreeNewUninitializing = 21, // PPH_PLUGIN_TREENEW_INFORMATION Data [properties thread] - GeneralCallbackThreadTreeNewInitializing = 22, // PPH_PLUGIN_TREENEW_INFORMATION Data [properties thread] - GeneralCallbackThreadTreeNewUninitializing = 23, // PPH_PLUGIN_TREENEW_INFORMATION Data [properties thread] - GeneralCallbackHandleTreeNewInitializing = 24, // PPH_PLUGIN_TREENEW_INFORMATION Data [properties thread] - GeneralCallbackHandleTreeNewUninitializing = 25, // PPH_PLUGIN_TREENEW_INFORMATION Data [properties thread] - GeneralCallbackThreadStackControl = 26, // PPH_PLUGIN_THREAD_STACK_CONTROL Data [properties thread] - GeneralCallbackSystemInformationInitializing = 27, // PPH_PLUGIN_SYSINFO_POINTERS Data [system information thread] - GeneralCallbackMainWindowTabChanged = 28, // INT NewIndex [main thread] - GeneralCallbackMemoryTreeNewInitializing = 29, // PPH_PLUGIN_TREENEW_INFORMATION Data [properties thread] - GeneralCallbackMemoryTreeNewUninitializing = 30, // PPH_PLUGIN_TREENEW_INFORMATION Data [properties thread] - GeneralCallbackMemoryItemListControl = 31, // PPH_PLUGIN_MEMORY_ITEM_LIST_CONTROL Data [properties thread] - GeneralCallbackMiniInformationInitializing = 32, // PPH_PLUGIN_MINIINFO_POINTERS Data [main thread] - GeneralCallbackMiListSectionMenuInitializing = 33, // PPH_PLUGIN_MENU_INFORMATION Data [main thread] - GeneralCallbackMaximum -} PH_GENERAL_CALLBACK, *PPH_GENERAL_CALLBACK; - -typedef enum _PH_PLUGIN_CALLBACK -{ - PluginCallbackLoad = 0, // PPH_LIST Parameters [main thread] // list of strings, might be NULL - PluginCallbackUnload = 1, // [main thread] - PluginCallbackShowOptions = 2, // HWND ParentWindowHandle [main thread] - PluginCallbackMenuItem = 3, // PPH_PLUGIN_MENU_ITEM MenuItem [main/properties thread] - PluginCallbackTreeNewMessage = 4, // PPH_PLUGIN_TREENEW_MESSAGE Message [main/properties thread] - PluginCallbackPhSvcRequest = 5, // PPH_PLUGIN_PHSVC_REQUEST Message [phsvc thread] - PluginCallbackMenuHook = 6, // PH_PLUGIN_MENU_HOOK_INFORMATION MenuHookInfo [menu thread] - PluginCallbackMaximum -} PH_PLUGIN_CALLBACK, *PPH_PLUGIN_CALLBACK; - -typedef struct _PH_PLUGIN_GET_HIGHLIGHTING_COLOR -{ - // Parameter is: - // PPH_PROCESS_ITEM for GeneralCallbackGetProcessHighlightingColor - - PVOID Parameter; - COLORREF BackColor; - BOOLEAN Handled; - BOOLEAN Cache; -} PH_PLUGIN_GET_HIGHLIGHTING_COLOR, *PPH_PLUGIN_GET_HIGHLIGHTING_COLOR; - -typedef struct _PH_PLUGIN_GET_TOOLTIP_TEXT -{ - // Parameter is: - // PPH_PROCESS_ITEM for GeneralCallbackGetProcessTooltipText - - PVOID Parameter; - PPH_STRING_BUILDER StringBuilder; - ULONG ValidForMs; -} PH_PLUGIN_GET_TOOLTIP_TEXT, *PPH_PLUGIN_GET_TOOLTIP_TEXT; - -typedef struct _PH_PLUGIN_PROCESS_PROPCONTEXT -{ - PPH_PROCESS_PROPCONTEXT PropContext; - PPH_PROCESS_ITEM ProcessItem; -} PH_PLUGIN_PROCESS_PROPCONTEXT, *PPH_PLUGIN_PROCESS_PROPCONTEXT; - -typedef struct _PH_PLUGIN_NOTIFY_EVENT -{ - // Parameter is: - // PPH_PROCESS_ITEM for Type = PH_NOTIFY_PROCESS_* - // PPH_SERVICE_ITEM for Type = PH_NOTIFY_SERVICE_* - - ULONG Type; - BOOLEAN Handled; - PVOID Parameter; -} PH_PLUGIN_NOTIFY_EVENT, *PPH_PLUGIN_NOTIFY_EVENT; - -typedef struct _PH_PLUGIN_OBJECT_PROPERTIES -{ - // Parameter is: - // PPH_SERVICE_ITEM for GeneralCallbackServicePropertiesInitializing - // PPH_PLUGIN_HANDLE_PROPERTIES_CONTEXT for GeneralCallbackHandlePropertiesInitializing - - PVOID Parameter; - ULONG NumberOfPages; - ULONG MaximumNumberOfPages; - HPROPSHEETPAGE *Pages; -} PH_PLUGIN_OBJECT_PROPERTIES, *PPH_PLUGIN_OBJECT_PROPERTIES; - -typedef struct _PH_PLUGIN_HANDLE_PROPERTIES_CONTEXT -{ - HANDLE ProcessId; - PPH_HANDLE_ITEM HandleItem; -} PH_PLUGIN_HANDLE_PROPERTIES_CONTEXT, *PPH_PLUGIN_HANDLE_PROPERTIES_CONTEXT; - -typedef struct _PH_EMENU_ITEM *PPH_EMENU_ITEM, *PPH_EMENU; - -#define PH_PLUGIN_MENU_DISALLOW_HOOKS 0x1 - -typedef struct _PH_PLUGIN_MENU_INFORMATION -{ - PPH_EMENU Menu; - HWND OwnerWindow; - - union - { - struct - { - PVOID Reserved[8]; // Reserve space for future expansion of this union - } DoNotUse; - struct - { - ULONG SubMenuIndex; - } MainMenu; - struct - { - PPH_PROCESS_ITEM *Processes; - ULONG NumberOfProcesses; - } Process; - struct - { - PPH_SERVICE_ITEM *Services; - ULONG NumberOfServices; - } Service; - struct - { - PPH_NETWORK_ITEM *NetworkItems; - ULONG NumberOfNetworkItems; - } Network; - struct - { - HANDLE ProcessId; - PPH_THREAD_ITEM *Threads; - ULONG NumberOfThreads; - } Thread; - struct - { - HANDLE ProcessId; - PPH_MODULE_ITEM *Modules; - ULONG NumberOfModules; - } Module; - struct - { - HANDLE ProcessId; - PPH_MEMORY_NODE *MemoryNodes; - ULONG NumberOfMemoryNodes; - } Memory; - struct - { - HANDLE ProcessId; - PPH_HANDLE_ITEM *Handles; - ULONG NumberOfHandles; - } Handle; - struct - { - PPH_STRINGREF SectionName; - PPH_PROCESS_GROUP ProcessGroup; - } MiListSection; - } u; - - ULONG Flags; - PPH_LIST PluginHookList; -} PH_PLUGIN_MENU_INFORMATION, *PPH_PLUGIN_MENU_INFORMATION; - -C_ASSERT(RTL_FIELD_SIZE(PH_PLUGIN_MENU_INFORMATION, u) == RTL_FIELD_SIZE(PH_PLUGIN_MENU_INFORMATION, u.DoNotUse)); - -typedef struct _PH_PLUGIN_MENU_HOOK_INFORMATION -{ - PPH_PLUGIN_MENU_INFORMATION MenuInfo; - PPH_EMENU SelectedItem; - PVOID Context; - BOOLEAN Handled; -} PH_PLUGIN_MENU_HOOK_INFORMATION, *PPH_PLUGIN_MENU_HOOK_INFORMATION; - -typedef struct _PH_PLUGIN_TREENEW_INFORMATION -{ - HWND TreeNewHandle; - PVOID CmData; - PVOID SystemContext; // e.g. PPH_THREADS_CONTEXT -} PH_PLUGIN_TREENEW_INFORMATION, *PPH_PLUGIN_TREENEW_INFORMATION; - -typedef enum _PH_PLUGIN_THREAD_STACK_CONTROL_TYPE -{ - PluginThreadStackInitializing, - PluginThreadStackUninitializing, - PluginThreadStackResolveSymbol, - PluginThreadStackGetTooltip, - PluginThreadStackWalkStack, - PluginThreadStackBeginDefaultWalkStack, - PluginThreadStackEndDefaultWalkStack, - PluginThreadStackMaximum -} PH_PLUGIN_THREAD_STACK_CONTROL_TYPE; - -typedef struct _PH_SYMBOL_PROVIDER *PPH_SYMBOL_PROVIDER; -typedef struct _PH_THREAD_STACK_FRAME *PPH_THREAD_STACK_FRAME; - -typedef BOOLEAN (NTAPI *PPH_PLUGIN_WALK_THREAD_STACK_CALLBACK)( - _In_ PPH_THREAD_STACK_FRAME StackFrame, - _In_opt_ PVOID Context - ); - -typedef struct _PH_PLUGIN_THREAD_STACK_CONTROL -{ - PH_PLUGIN_THREAD_STACK_CONTROL_TYPE Type; - PVOID UniqueKey; - - union - { - struct - { - HANDLE ProcessId; - HANDLE ThreadId; - HANDLE ThreadHandle; - PPH_SYMBOL_PROVIDER SymbolProvider; - BOOLEAN CustomWalk; - } Initializing; - struct - { - PPH_THREAD_STACK_FRAME StackFrame; - PPH_STRING Symbol; - } ResolveSymbol; - struct - { - PPH_THREAD_STACK_FRAME StackFrame; - PPH_STRING_BUILDER StringBuilder; - } GetTooltip; - struct - { - NTSTATUS Status; - HANDLE ThreadHandle; - HANDLE ProcessHandle; - PCLIENT_ID ClientId; - ULONG Flags; - PPH_PLUGIN_WALK_THREAD_STACK_CALLBACK Callback; - PVOID CallbackContext; - } WalkStack; - } u; -} PH_PLUGIN_THREAD_STACK_CONTROL, *PPH_PLUGIN_THREAD_STACK_CONTROL; - -typedef enum _PH_PLUGIN_MEMORY_ITEM_LIST_CONTROL_TYPE -{ - PluginMemoryItemListInitialized, - PluginMemoryItemListMaximum -} PH_PLUGIN_MEMORY_ITEM_LIST_CONTROL_TYPE; - -typedef struct _PH_PLUGIN_MEMORY_ITEM_LIST_CONTROL -{ - PH_PLUGIN_MEMORY_ITEM_LIST_CONTROL_TYPE Type; - - union - { - struct - { - PPH_MEMORY_ITEM_LIST List; - } Initialized; - } u; -} PH_PLUGIN_MEMORY_ITEM_LIST_CONTROL, *PPH_PLUGIN_MEMORY_ITEM_LIST_CONTROL; - -typedef PPH_SYSINFO_SECTION (NTAPI *PPH_SYSINFO_CREATE_SECTION)( - _In_ PPH_SYSINFO_SECTION Template - ); - -typedef PPH_SYSINFO_SECTION (NTAPI *PPH_SYSINFO_FIND_SECTION)( - _In_ PPH_STRINGREF Name - ); - -typedef VOID (NTAPI *PPH_SYSINFO_ENTER_SECTION_VIEW)( - _In_ PPH_SYSINFO_SECTION NewSection - ); - -typedef VOID (NTAPI *PPH_SYSINFO_RESTORE_SUMMARY_VIEW)( - VOID - ); - -typedef struct _PH_PLUGIN_SYSINFO_POINTERS -{ - HWND WindowHandle; - PPH_SYSINFO_CREATE_SECTION CreateSection; - PPH_SYSINFO_FIND_SECTION FindSection; - PPH_SYSINFO_ENTER_SECTION_VIEW EnterSectionView; - PPH_SYSINFO_RESTORE_SUMMARY_VIEW RestoreSummaryView; -} PH_PLUGIN_SYSINFO_POINTERS, *PPH_PLUGIN_SYSINFO_POINTERS; - -typedef PPH_MINIINFO_SECTION (NTAPI *PPH_MINIINFO_CREATE_SECTION)( - _In_ PPH_MINIINFO_SECTION Template - ); - -typedef PPH_MINIINFO_SECTION (NTAPI *PPH_MINIINFO_FIND_SECTION)( - _In_ PPH_STRINGREF Name - ); - -typedef PPH_MINIINFO_LIST_SECTION (NTAPI *PPH_MINIINFO_CREATE_LIST_SECTION)( - _In_ PWSTR Name, - _In_ ULONG Flags, - _In_ PPH_MINIINFO_LIST_SECTION Template - ); - -typedef struct _PH_PLUGIN_MINIINFO_POINTERS -{ - HWND WindowHandle; - PPH_MINIINFO_CREATE_SECTION CreateSection; - PPH_MINIINFO_FIND_SECTION FindSection; - PPH_MINIINFO_CREATE_LIST_SECTION CreateListSection; -} PH_PLUGIN_MINIINFO_POINTERS, *PPH_PLUGIN_MINIINFO_POINTERS; - -typedef struct _PH_PLUGIN_TREENEW_MESSAGE -{ - HWND TreeNewHandle; - PH_TREENEW_MESSAGE Message; - PVOID Parameter1; - PVOID Parameter2; - ULONG SubId; - PVOID Context; -} PH_PLUGIN_TREENEW_MESSAGE, *PPH_PLUGIN_TREENEW_MESSAGE; - -typedef LONG (NTAPI *PPH_PLUGIN_TREENEW_SORT_FUNCTION)( - _In_ PVOID Node1, - _In_ PVOID Node2, - _In_ ULONG SubId, - _In_ PVOID Context - ); - -typedef NTSTATUS (NTAPI *PPHSVC_SERVER_PROBE_BUFFER)( - _In_ PPH_RELATIVE_STRINGREF String, - _In_ ULONG Alignment, - _In_ BOOLEAN AllowNull, - _Out_ PVOID *Pointer - ); - -typedef NTSTATUS (NTAPI *PPHSVC_SERVER_CAPTURE_BUFFER)( - _In_ PPH_RELATIVE_STRINGREF String, - _In_ BOOLEAN AllowNull, - _Out_ PVOID *CapturedBuffer - ); - -typedef NTSTATUS (NTAPI *PPHSVC_SERVER_CAPTURE_STRING)( - _In_ PPH_RELATIVE_STRINGREF String, - _In_ BOOLEAN AllowNull, - _Out_ PPH_STRING *CapturedString - ); - -typedef struct _PH_PLUGIN_PHSVC_REQUEST -{ - ULONG SubId; - NTSTATUS ReturnStatus; - PVOID InBuffer; - ULONG InLength; - PVOID OutBuffer; - ULONG OutLength; - - PPHSVC_SERVER_PROBE_BUFFER ProbeBuffer; - PPHSVC_SERVER_CAPTURE_BUFFER CaptureBuffer; - PPHSVC_SERVER_CAPTURE_STRING CaptureString; -} PH_PLUGIN_PHSVC_REQUEST, *PPH_PLUGIN_PHSVC_REQUEST; - -typedef VOID (NTAPI *PPHSVC_CLIENT_FREE_HEAP)( - _In_ PVOID Memory - ); - -typedef PVOID (NTAPI *PPHSVC_CLIENT_CREATE_STRING)( - _In_opt_ PVOID String, - _In_ SIZE_T Length, - _Out_ PPH_RELATIVE_STRINGREF StringRef - ); - -typedef struct _PH_PLUGIN_PHSVC_CLIENT -{ - HANDLE ServerProcessId; - PPHSVC_CLIENT_FREE_HEAP FreeHeap; - PPHSVC_CLIENT_CREATE_STRING CreateString; -} PH_PLUGIN_PHSVC_CLIENT, *PPH_PLUGIN_PHSVC_CLIENT; - -// Plugin structures - -typedef struct _PH_PLUGIN_INFORMATION -{ - PWSTR DisplayName; - PWSTR Author; - PWSTR Description; - PWSTR Url; - BOOLEAN HasOptions; - BOOLEAN Reserved1[3]; - PVOID Interface; -} PH_PLUGIN_INFORMATION, *PPH_PLUGIN_INFORMATION; - -#define PH_PLUGIN_FLAG_RESERVED 0x1 -// end_phapppub - -// begin_phapppub -typedef struct _PH_PLUGIN -{ - // Public - - PH_AVL_LINKS Links; - - PVOID Reserved; - PVOID DllBase; -// end_phapppub - - // Private - - PPH_STRING FileName; - ULONG Flags; - PH_STRINGREF Name; - PH_PLUGIN_INFORMATION Information; - - PH_CALLBACK Callbacks[PluginCallbackMaximum]; - PH_EM_APP_CONTEXT AppContext; -// begin_phapppub -} PH_PLUGIN, *PPH_PLUGIN; -// end_phapppub - -// begin_phapppub -// Plugin API - -PHAPPAPI -PPH_PLUGIN -NTAPI -PhRegisterPlugin( - _In_ PWSTR Name, - _In_ PVOID DllBase, - _Out_opt_ PPH_PLUGIN_INFORMATION *Information - ); - -PHAPPAPI -PPH_PLUGIN -NTAPI -PhFindPlugin( - _In_ PWSTR Name - ); - -PHAPPAPI -PPH_PLUGIN_INFORMATION -NTAPI -PhGetPluginInformation( - _In_ PPH_PLUGIN Plugin - ); - -PHAPPAPI -PPH_CALLBACK -NTAPI -PhGetPluginCallback( - _In_ PPH_PLUGIN Plugin, - _In_ PH_PLUGIN_CALLBACK Callback - ); - -PHAPPAPI -PPH_CALLBACK -NTAPI -PhGetGeneralCallback( - _In_ PH_GENERAL_CALLBACK Callback - ); - -PHAPPAPI -ULONG -NTAPI -PhPluginReserveIds( - _In_ ULONG Count - ); - -typedef VOID (NTAPI *PPH_PLUGIN_MENU_ITEM_DELETE_FUNCTION)( - _In_ struct _PH_PLUGIN_MENU_ITEM *MenuItem - ); - -typedef struct _PH_PLUGIN_MENU_ITEM -{ - PPH_PLUGIN Plugin; - ULONG Id; - ULONG Reserved1; - PVOID Context; - - HWND OwnerWindow; // valid only when the menu item is chosen - PVOID Reserved2; - PVOID Reserved3; - PPH_PLUGIN_MENU_ITEM_DELETE_FUNCTION DeleteFunction; // valid only for EMENU-based menu items -} PH_PLUGIN_MENU_ITEM, *PPH_PLUGIN_MENU_ITEM; - -// Location -#define PH_MENU_ITEM_LOCATION_VIEW 1 -#define PH_MENU_ITEM_LOCATION_TOOLS 2 - -// Id flags (non-functional) -#define PH_MENU_ITEM_SUB_MENU 0x80000000 -#define PH_MENU_ITEM_RETURN_MENU 0x40000000 -#define PH_MENU_ITEM_VALID_FLAGS 0xc0000000 - -PHAPPAPI -ULONG_PTR -NTAPI -PhPluginAddMenuItem( - _In_ PPH_PLUGIN Plugin, - _In_ ULONG_PTR Location, - _In_opt_ PWSTR InsertAfter, - _In_ ULONG Id, - _In_ PWSTR Text, - _In_opt_ PVOID Context - ); - -typedef struct _PH_PLUGIN_SYSTEM_STATISTICS -{ - PSYSTEM_PERFORMANCE_INFORMATION Performance; - - ULONG NumberOfProcesses; - ULONG NumberOfThreads; - ULONG NumberOfHandles; - - FLOAT CpuKernelUsage; - FLOAT CpuUserUsage; - - PH_UINT64_DELTA IoReadDelta; - PH_UINT64_DELTA IoWriteDelta; - PH_UINT64_DELTA IoOtherDelta; - - ULONG CommitPages; - ULONG PhysicalPages; - - HANDLE MaxCpuProcessId; - HANDLE MaxIoProcessId; - - PPH_CIRCULAR_BUFFER_FLOAT CpuKernelHistory; - PPH_CIRCULAR_BUFFER_FLOAT CpuUserHistory; - PPH_CIRCULAR_BUFFER_FLOAT *CpusKernelHistory; - PPH_CIRCULAR_BUFFER_FLOAT *CpusUserHistory; - PPH_CIRCULAR_BUFFER_ULONG64 IoReadHistory; - PPH_CIRCULAR_BUFFER_ULONG64 IoWriteHistory; - PPH_CIRCULAR_BUFFER_ULONG64 IoOtherHistory; - PPH_CIRCULAR_BUFFER_ULONG CommitHistory; - PPH_CIRCULAR_BUFFER_ULONG PhysicalHistory; - PPH_CIRCULAR_BUFFER_ULONG MaxCpuHistory; // ID of max. CPU process - PPH_CIRCULAR_BUFFER_ULONG MaxIoHistory; // ID of max. I/O process - PPH_CIRCULAR_BUFFER_FLOAT MaxCpuUsageHistory; - PPH_CIRCULAR_BUFFER_ULONG64 MaxIoReadOtherHistory; - PPH_CIRCULAR_BUFFER_ULONG64 MaxIoWriteHistory; -} PH_PLUGIN_SYSTEM_STATISTICS, *PPH_PLUGIN_SYSTEM_STATISTICS; - -PHAPPAPI -VOID -NTAPI -PhPluginGetSystemStatistics( - _Out_ PPH_PLUGIN_SYSTEM_STATISTICS Statistics - ); - -PHAPPAPI -PPH_EMENU_ITEM -NTAPI -PhPluginCreateEMenuItem( - _In_ PPH_PLUGIN Plugin, - _In_ ULONG Flags, - _In_ ULONG Id, - _In_ PWSTR Text, - _In_opt_ PVOID Context - ); - -PHAPPAPI -BOOLEAN -NTAPI -PhPluginAddMenuHook( - _Inout_ PPH_PLUGIN_MENU_INFORMATION MenuInfo, - _In_ PPH_PLUGIN Plugin, - _In_opt_ PVOID Context - ); -// end_phapppub - -VOID -NTAPI -PhPluginInitializeMenuInfo( - _Out_ PPH_PLUGIN_MENU_INFORMATION MenuInfo, - _In_opt_ PPH_EMENU Menu, - _In_ HWND OwnerWindow, - _In_ ULONG Flags - ); - -BOOLEAN -NTAPI -PhPluginTriggerEMenuItem( - _In_ PPH_PLUGIN_MENU_INFORMATION MenuInfo, - _In_ PPH_EMENU_ITEM Item - ); - -// begin_phapppub -PHAPPAPI -BOOLEAN -NTAPI -PhPluginAddTreeNewColumn( - _In_ PPH_PLUGIN Plugin, - _In_ PVOID CmData, - _In_ PPH_TREENEW_COLUMN Column, - _In_ ULONG SubId, - _In_opt_ PVOID Context, - _In_opt_ PPH_PLUGIN_TREENEW_SORT_FUNCTION SortFunction - ); - -PHAPPAPI -VOID -NTAPI -PhPluginSetObjectExtension( - _In_ PPH_PLUGIN Plugin, - _In_ PH_EM_OBJECT_TYPE ObjectType, - _In_ ULONG ExtensionSize, - _In_opt_ PPH_EM_OBJECT_CALLBACK CreateCallback, - _In_opt_ PPH_EM_OBJECT_CALLBACK DeleteCallback - ); - -PHAPPAPI -PVOID -NTAPI -PhPluginGetObjectExtension( - _In_ PPH_PLUGIN Plugin, - _In_ PVOID Object, - _In_ PH_EM_OBJECT_TYPE ObjectType - ); - -PHAPPAPI -struct _PH_NF_ICON * -NTAPI -PhPluginRegisterIcon( - _In_ PPH_PLUGIN Plugin, - _In_ ULONG SubId, - _In_opt_ PVOID Context, - _In_ PWSTR Text, - _In_ ULONG Flags, - _In_ struct _PH_NF_ICON_REGISTRATION_DATA *RegistrationData - ); - -PHAPPAPI -VOID -NTAPI -PhPluginEnableTreeNewNotify( - _In_ PPH_PLUGIN Plugin, - _In_ PVOID CmData - ); - -PHAPPAPI -BOOLEAN -NTAPI -PhPluginQueryPhSvc( - _Out_ PPH_PLUGIN_PHSVC_CLIENT Client - ); - -PHAPPAPI -NTSTATUS -NTAPI -PhPluginCallPhSvc( - _In_ PPH_PLUGIN Plugin, - _In_ ULONG SubId, - _In_reads_bytes_opt_(InLength) PVOID InBuffer, - _In_ ULONG InLength, - _Out_writes_bytes_opt_(OutLength) PVOID OutBuffer, - _In_ ULONG OutLength - ); -// end_phapppub - -#endif +#ifndef PH_PHPLUG_H +#define PH_PHPLUG_H + +#include +#include +#include + +// begin_phapppub +// Callbacks + +typedef enum _PH_GENERAL_CALLBACK +{ + GeneralCallbackMainWindowShowing = 0, // INT ShowCommand [main thread] + GeneralCallbackProcessesUpdated = 1, // [main thread] + GeneralCallbackGetProcessHighlightingColor = 2, // PPH_PLUGIN_GET_HIGHLIGHTING_COLOR Data [main thread] + GeneralCallbackGetProcessTooltipText = 3, // PPH_PLUGIN_GET_TOOLTIP_TEXT Data [main thread] + GeneralCallbackProcessPropertiesInitializing = 4, // PPH_PLUGIN_PROCESS_PROPCONTEXT Data [properties thread] + GeneralCallbackMainMenuInitializing = 5, // PPH_PLUGIN_MENU_INFORMATION Data [main thread] + GeneralCallbackNotifyEvent = 6, // PPH_PLUGIN_NOTIFY_EVENT Data [main thread] + GeneralCallbackServicePropertiesInitializing = 7, // PPH_PLUGIN_OBJECT_PROPERTIES Data [properties thread] + GeneralCallbackHandlePropertiesInitializing = 8, // PPH_PLUGIN_OBJECT_PROPERTIES Data [properties thread] + GeneralCallbackProcessMenuInitializing = 9, // PPH_PLUGIN_MENU_INFORMATION Data [main thread] + GeneralCallbackServiceMenuInitializing = 10, // PPH_PLUGIN_MENU_INFORMATION Data [main thread] + GeneralCallbackNetworkMenuInitializing = 11, // PPH_PLUGIN_MENU_INFORMATION Data [main thread] + GeneralCallbackIconMenuInitializing = 12, // PPH_PLUGIN_MENU_INFORMATION Data [main thread] + GeneralCallbackThreadMenuInitializing = 13, // PPH_PLUGIN_MENU_INFORMATION Data [properties thread] + GeneralCallbackModuleMenuInitializing = 14, // PPH_PLUGIN_MENU_INFORMATION Data [properties thread] + GeneralCallbackMemoryMenuInitializing = 15, // PPH_PLUGIN_MENU_INFORMATION Data [properties thread] + GeneralCallbackHandleMenuInitializing = 16, // PPH_PLUGIN_MENU_INFORMATION Data [properties thread] + GeneralCallbackProcessTreeNewInitializing = 17, // PPH_PLUGIN_TREENEW_INFORMATION Data [main thread] + GeneralCallbackServiceTreeNewInitializing = 18, // PPH_PLUGIN_TREENEW_INFORMATION Data [main thread] + GeneralCallbackNetworkTreeNewInitializing = 19, // PPH_PLUGIN_TREENEW_INFORMATION Data [main thread] + GeneralCallbackModuleTreeNewInitializing = 20, // PPH_PLUGIN_TREENEW_INFORMATION Data [properties thread] + GeneralCallbackModuleTreeNewUninitializing = 21, // PPH_PLUGIN_TREENEW_INFORMATION Data [properties thread] + GeneralCallbackThreadTreeNewInitializing = 22, // PPH_PLUGIN_TREENEW_INFORMATION Data [properties thread] + GeneralCallbackThreadTreeNewUninitializing = 23, // PPH_PLUGIN_TREENEW_INFORMATION Data [properties thread] + GeneralCallbackHandleTreeNewInitializing = 24, // PPH_PLUGIN_TREENEW_INFORMATION Data [properties thread] + GeneralCallbackHandleTreeNewUninitializing = 25, // PPH_PLUGIN_TREENEW_INFORMATION Data [properties thread] + GeneralCallbackThreadStackControl = 26, // PPH_PLUGIN_THREAD_STACK_CONTROL Data [properties thread] + GeneralCallbackSystemInformationInitializing = 27, // PPH_PLUGIN_SYSINFO_POINTERS Data [system information thread] + GeneralCallbackMainWindowTabChanged = 28, // INT NewIndex [main thread] + GeneralCallbackMemoryTreeNewInitializing = 29, // PPH_PLUGIN_TREENEW_INFORMATION Data [properties thread] + GeneralCallbackMemoryTreeNewUninitializing = 30, // PPH_PLUGIN_TREENEW_INFORMATION Data [properties thread] + GeneralCallbackMemoryItemListControl = 31, // PPH_PLUGIN_MEMORY_ITEM_LIST_CONTROL Data [properties thread] + GeneralCallbackMiniInformationInitializing = 32, // PPH_PLUGIN_MINIINFO_POINTERS Data [main thread] + GeneralCallbackMiListSectionMenuInitializing = 33, // PPH_PLUGIN_MENU_INFORMATION Data [main thread] + GeneralCallbackMaximum +} PH_GENERAL_CALLBACK, *PPH_GENERAL_CALLBACK; + +typedef enum _PH_PLUGIN_CALLBACK +{ + PluginCallbackLoad = 0, // PPH_LIST Parameters [main thread] // list of strings, might be NULL + PluginCallbackUnload = 1, // [main thread] + PluginCallbackShowOptions = 2, // HWND ParentWindowHandle [main thread] + PluginCallbackMenuItem = 3, // PPH_PLUGIN_MENU_ITEM MenuItem [main/properties thread] + PluginCallbackTreeNewMessage = 4, // PPH_PLUGIN_TREENEW_MESSAGE Message [main/properties thread] + PluginCallbackPhSvcRequest = 5, // PPH_PLUGIN_PHSVC_REQUEST Message [phsvc thread] + PluginCallbackMenuHook = 6, // PH_PLUGIN_MENU_HOOK_INFORMATION MenuHookInfo [menu thread] + PluginCallbackMaximum +} PH_PLUGIN_CALLBACK, *PPH_PLUGIN_CALLBACK; + +typedef struct _PH_PLUGIN_GET_HIGHLIGHTING_COLOR +{ + // Parameter is: + // PPH_PROCESS_ITEM for GeneralCallbackGetProcessHighlightingColor + + PVOID Parameter; + COLORREF BackColor; + BOOLEAN Handled; + BOOLEAN Cache; +} PH_PLUGIN_GET_HIGHLIGHTING_COLOR, *PPH_PLUGIN_GET_HIGHLIGHTING_COLOR; + +typedef struct _PH_PLUGIN_GET_TOOLTIP_TEXT +{ + // Parameter is: + // PPH_PROCESS_ITEM for GeneralCallbackGetProcessTooltipText + + PVOID Parameter; + PPH_STRING_BUILDER StringBuilder; + ULONG ValidForMs; +} PH_PLUGIN_GET_TOOLTIP_TEXT, *PPH_PLUGIN_GET_TOOLTIP_TEXT; + +typedef struct _PH_PLUGIN_PROCESS_PROPCONTEXT +{ + PPH_PROCESS_PROPCONTEXT PropContext; + PPH_PROCESS_ITEM ProcessItem; +} PH_PLUGIN_PROCESS_PROPCONTEXT, *PPH_PLUGIN_PROCESS_PROPCONTEXT; + +typedef struct _PH_PLUGIN_NOTIFY_EVENT +{ + // Parameter is: + // PPH_PROCESS_ITEM for Type = PH_NOTIFY_PROCESS_* + // PPH_SERVICE_ITEM for Type = PH_NOTIFY_SERVICE_* + + ULONG Type; + BOOLEAN Handled; + PVOID Parameter; +} PH_PLUGIN_NOTIFY_EVENT, *PPH_PLUGIN_NOTIFY_EVENT; + +typedef struct _PH_PLUGIN_OBJECT_PROPERTIES +{ + // Parameter is: + // PPH_SERVICE_ITEM for GeneralCallbackServicePropertiesInitializing + // PPH_PLUGIN_HANDLE_PROPERTIES_CONTEXT for GeneralCallbackHandlePropertiesInitializing + + PVOID Parameter; + ULONG NumberOfPages; + ULONG MaximumNumberOfPages; + HPROPSHEETPAGE *Pages; +} PH_PLUGIN_OBJECT_PROPERTIES, *PPH_PLUGIN_OBJECT_PROPERTIES; + +typedef struct _PH_PLUGIN_HANDLE_PROPERTIES_CONTEXT +{ + HANDLE ProcessId; + PPH_HANDLE_ITEM HandleItem; +} PH_PLUGIN_HANDLE_PROPERTIES_CONTEXT, *PPH_PLUGIN_HANDLE_PROPERTIES_CONTEXT; + +typedef struct _PH_EMENU_ITEM *PPH_EMENU_ITEM, *PPH_EMENU; + +#define PH_PLUGIN_MENU_DISALLOW_HOOKS 0x1 + +typedef struct _PH_PLUGIN_MENU_INFORMATION +{ + PPH_EMENU Menu; + HWND OwnerWindow; + + union + { + struct + { + PVOID Reserved[8]; // Reserve space for future expansion of this union + } DoNotUse; + struct + { + ULONG SubMenuIndex; + } MainMenu; + struct + { + PPH_PROCESS_ITEM *Processes; + ULONG NumberOfProcesses; + } Process; + struct + { + PPH_SERVICE_ITEM *Services; + ULONG NumberOfServices; + } Service; + struct + { + PPH_NETWORK_ITEM *NetworkItems; + ULONG NumberOfNetworkItems; + } Network; + struct + { + HANDLE ProcessId; + PPH_THREAD_ITEM *Threads; + ULONG NumberOfThreads; + } Thread; + struct + { + HANDLE ProcessId; + PPH_MODULE_ITEM *Modules; + ULONG NumberOfModules; + } Module; + struct + { + HANDLE ProcessId; + PPH_MEMORY_NODE *MemoryNodes; + ULONG NumberOfMemoryNodes; + } Memory; + struct + { + HANDLE ProcessId; + PPH_HANDLE_ITEM *Handles; + ULONG NumberOfHandles; + } Handle; + struct + { + PPH_STRINGREF SectionName; + PPH_PROCESS_GROUP ProcessGroup; + } MiListSection; + } u; + + ULONG Flags; + PPH_LIST PluginHookList; +} PH_PLUGIN_MENU_INFORMATION, *PPH_PLUGIN_MENU_INFORMATION; + +C_ASSERT(RTL_FIELD_SIZE(PH_PLUGIN_MENU_INFORMATION, u) == RTL_FIELD_SIZE(PH_PLUGIN_MENU_INFORMATION, u.DoNotUse)); + +typedef struct _PH_PLUGIN_MENU_HOOK_INFORMATION +{ + PPH_PLUGIN_MENU_INFORMATION MenuInfo; + PPH_EMENU SelectedItem; + PVOID Context; + BOOLEAN Handled; +} PH_PLUGIN_MENU_HOOK_INFORMATION, *PPH_PLUGIN_MENU_HOOK_INFORMATION; + +typedef struct _PH_PLUGIN_TREENEW_INFORMATION +{ + HWND TreeNewHandle; + PVOID CmData; + PVOID SystemContext; // e.g. PPH_THREADS_CONTEXT +} PH_PLUGIN_TREENEW_INFORMATION, *PPH_PLUGIN_TREENEW_INFORMATION; + +typedef enum _PH_PLUGIN_THREAD_STACK_CONTROL_TYPE +{ + PluginThreadStackInitializing, + PluginThreadStackUninitializing, + PluginThreadStackResolveSymbol, + PluginThreadStackGetTooltip, + PluginThreadStackWalkStack, + PluginThreadStackBeginDefaultWalkStack, + PluginThreadStackEndDefaultWalkStack, + PluginThreadStackMaximum +} PH_PLUGIN_THREAD_STACK_CONTROL_TYPE; + +typedef struct _PH_SYMBOL_PROVIDER *PPH_SYMBOL_PROVIDER; +typedef struct _PH_THREAD_STACK_FRAME *PPH_THREAD_STACK_FRAME; + +typedef BOOLEAN (NTAPI *PPH_PLUGIN_WALK_THREAD_STACK_CALLBACK)( + _In_ PPH_THREAD_STACK_FRAME StackFrame, + _In_opt_ PVOID Context + ); + +typedef struct _PH_PLUGIN_THREAD_STACK_CONTROL +{ + PH_PLUGIN_THREAD_STACK_CONTROL_TYPE Type; + PVOID UniqueKey; + + union + { + struct + { + HANDLE ProcessId; + HANDLE ThreadId; + HANDLE ThreadHandle; + PPH_SYMBOL_PROVIDER SymbolProvider; + BOOLEAN CustomWalk; + } Initializing; + struct + { + PPH_THREAD_STACK_FRAME StackFrame; + PPH_STRING Symbol; + } ResolveSymbol; + struct + { + PPH_THREAD_STACK_FRAME StackFrame; + PPH_STRING_BUILDER StringBuilder; + } GetTooltip; + struct + { + NTSTATUS Status; + HANDLE ThreadHandle; + HANDLE ProcessHandle; + PCLIENT_ID ClientId; + ULONG Flags; + PPH_PLUGIN_WALK_THREAD_STACK_CALLBACK Callback; + PVOID CallbackContext; + } WalkStack; + } u; +} PH_PLUGIN_THREAD_STACK_CONTROL, *PPH_PLUGIN_THREAD_STACK_CONTROL; + +typedef enum _PH_PLUGIN_MEMORY_ITEM_LIST_CONTROL_TYPE +{ + PluginMemoryItemListInitialized, + PluginMemoryItemListMaximum +} PH_PLUGIN_MEMORY_ITEM_LIST_CONTROL_TYPE; + +typedef struct _PH_PLUGIN_MEMORY_ITEM_LIST_CONTROL +{ + PH_PLUGIN_MEMORY_ITEM_LIST_CONTROL_TYPE Type; + + union + { + struct + { + PPH_MEMORY_ITEM_LIST List; + } Initialized; + } u; +} PH_PLUGIN_MEMORY_ITEM_LIST_CONTROL, *PPH_PLUGIN_MEMORY_ITEM_LIST_CONTROL; + +typedef PPH_SYSINFO_SECTION (NTAPI *PPH_SYSINFO_CREATE_SECTION)( + _In_ PPH_SYSINFO_SECTION Template + ); + +typedef PPH_SYSINFO_SECTION (NTAPI *PPH_SYSINFO_FIND_SECTION)( + _In_ PPH_STRINGREF Name + ); + +typedef VOID (NTAPI *PPH_SYSINFO_ENTER_SECTION_VIEW)( + _In_ PPH_SYSINFO_SECTION NewSection + ); + +typedef VOID (NTAPI *PPH_SYSINFO_RESTORE_SUMMARY_VIEW)( + VOID + ); + +typedef struct _PH_PLUGIN_SYSINFO_POINTERS +{ + HWND WindowHandle; + PPH_SYSINFO_CREATE_SECTION CreateSection; + PPH_SYSINFO_FIND_SECTION FindSection; + PPH_SYSINFO_ENTER_SECTION_VIEW EnterSectionView; + PPH_SYSINFO_RESTORE_SUMMARY_VIEW RestoreSummaryView; +} PH_PLUGIN_SYSINFO_POINTERS, *PPH_PLUGIN_SYSINFO_POINTERS; + +typedef PPH_MINIINFO_SECTION (NTAPI *PPH_MINIINFO_CREATE_SECTION)( + _In_ PPH_MINIINFO_SECTION Template + ); + +typedef PPH_MINIINFO_SECTION (NTAPI *PPH_MINIINFO_FIND_SECTION)( + _In_ PPH_STRINGREF Name + ); + +typedef PPH_MINIINFO_LIST_SECTION (NTAPI *PPH_MINIINFO_CREATE_LIST_SECTION)( + _In_ PWSTR Name, + _In_ ULONG Flags, + _In_ PPH_MINIINFO_LIST_SECTION Template + ); + +typedef struct _PH_PLUGIN_MINIINFO_POINTERS +{ + HWND WindowHandle; + PPH_MINIINFO_CREATE_SECTION CreateSection; + PPH_MINIINFO_FIND_SECTION FindSection; + PPH_MINIINFO_CREATE_LIST_SECTION CreateListSection; +} PH_PLUGIN_MINIINFO_POINTERS, *PPH_PLUGIN_MINIINFO_POINTERS; + +typedef struct _PH_PLUGIN_TREENEW_MESSAGE +{ + HWND TreeNewHandle; + PH_TREENEW_MESSAGE Message; + PVOID Parameter1; + PVOID Parameter2; + ULONG SubId; + PVOID Context; +} PH_PLUGIN_TREENEW_MESSAGE, *PPH_PLUGIN_TREENEW_MESSAGE; + +typedef LONG (NTAPI *PPH_PLUGIN_TREENEW_SORT_FUNCTION)( + _In_ PVOID Node1, + _In_ PVOID Node2, + _In_ ULONG SubId, + _In_ PVOID Context + ); + +typedef NTSTATUS (NTAPI *PPHSVC_SERVER_PROBE_BUFFER)( + _In_ PPH_RELATIVE_STRINGREF String, + _In_ ULONG Alignment, + _In_ BOOLEAN AllowNull, + _Out_ PVOID *Pointer + ); + +typedef NTSTATUS (NTAPI *PPHSVC_SERVER_CAPTURE_BUFFER)( + _In_ PPH_RELATIVE_STRINGREF String, + _In_ BOOLEAN AllowNull, + _Out_ PVOID *CapturedBuffer + ); + +typedef NTSTATUS (NTAPI *PPHSVC_SERVER_CAPTURE_STRING)( + _In_ PPH_RELATIVE_STRINGREF String, + _In_ BOOLEAN AllowNull, + _Out_ PPH_STRING *CapturedString + ); + +typedef struct _PH_PLUGIN_PHSVC_REQUEST +{ + ULONG SubId; + NTSTATUS ReturnStatus; + PVOID InBuffer; + ULONG InLength; + PVOID OutBuffer; + ULONG OutLength; + + PPHSVC_SERVER_PROBE_BUFFER ProbeBuffer; + PPHSVC_SERVER_CAPTURE_BUFFER CaptureBuffer; + PPHSVC_SERVER_CAPTURE_STRING CaptureString; +} PH_PLUGIN_PHSVC_REQUEST, *PPH_PLUGIN_PHSVC_REQUEST; + +typedef VOID (NTAPI *PPHSVC_CLIENT_FREE_HEAP)( + _In_ PVOID Memory + ); + +typedef PVOID (NTAPI *PPHSVC_CLIENT_CREATE_STRING)( + _In_opt_ PVOID String, + _In_ SIZE_T Length, + _Out_ PPH_RELATIVE_STRINGREF StringRef + ); + +typedef struct _PH_PLUGIN_PHSVC_CLIENT +{ + HANDLE ServerProcessId; + PPHSVC_CLIENT_FREE_HEAP FreeHeap; + PPHSVC_CLIENT_CREATE_STRING CreateString; +} PH_PLUGIN_PHSVC_CLIENT, *PPH_PLUGIN_PHSVC_CLIENT; + +// Plugin structures + +typedef struct _PH_PLUGIN_INFORMATION +{ + PWSTR DisplayName; + PWSTR Author; + PWSTR Description; + PWSTR Url; + BOOLEAN HasOptions; + BOOLEAN Reserved1[3]; + PVOID Interface; +} PH_PLUGIN_INFORMATION, *PPH_PLUGIN_INFORMATION; + +#define PH_PLUGIN_FLAG_RESERVED 0x1 +// end_phapppub + +// begin_phapppub +typedef struct _PH_PLUGIN +{ + // Public + + PH_AVL_LINKS Links; + + PVOID Reserved; + PVOID DllBase; +// end_phapppub + + // Private + + PPH_STRING FileName; + ULONG Flags; + PH_STRINGREF Name; + PH_PLUGIN_INFORMATION Information; + + PH_CALLBACK Callbacks[PluginCallbackMaximum]; + PH_EM_APP_CONTEXT AppContext; +// begin_phapppub +} PH_PLUGIN, *PPH_PLUGIN; +// end_phapppub + +// begin_phapppub +// Plugin API + +PHAPPAPI +PPH_PLUGIN +NTAPI +PhRegisterPlugin( + _In_ PWSTR Name, + _In_ PVOID DllBase, + _Out_opt_ PPH_PLUGIN_INFORMATION *Information + ); + +PHAPPAPI +PPH_PLUGIN +NTAPI +PhFindPlugin( + _In_ PWSTR Name + ); + +PHAPPAPI +PPH_PLUGIN_INFORMATION +NTAPI +PhGetPluginInformation( + _In_ PPH_PLUGIN Plugin + ); + +PHAPPAPI +PPH_CALLBACK +NTAPI +PhGetPluginCallback( + _In_ PPH_PLUGIN Plugin, + _In_ PH_PLUGIN_CALLBACK Callback + ); + +PHAPPAPI +PPH_CALLBACK +NTAPI +PhGetGeneralCallback( + _In_ PH_GENERAL_CALLBACK Callback + ); + +PHAPPAPI +ULONG +NTAPI +PhPluginReserveIds( + _In_ ULONG Count + ); + +typedef VOID (NTAPI *PPH_PLUGIN_MENU_ITEM_DELETE_FUNCTION)( + _In_ struct _PH_PLUGIN_MENU_ITEM *MenuItem + ); + +typedef struct _PH_PLUGIN_MENU_ITEM +{ + PPH_PLUGIN Plugin; + ULONG Id; + ULONG Reserved1; + PVOID Context; + + HWND OwnerWindow; // valid only when the menu item is chosen + PVOID Reserved2; + PVOID Reserved3; + PPH_PLUGIN_MENU_ITEM_DELETE_FUNCTION DeleteFunction; // valid only for EMENU-based menu items +} PH_PLUGIN_MENU_ITEM, *PPH_PLUGIN_MENU_ITEM; + +// Location +#define PH_MENU_ITEM_LOCATION_VIEW 1 +#define PH_MENU_ITEM_LOCATION_TOOLS 2 + +// Id flags (non-functional) +#define PH_MENU_ITEM_SUB_MENU 0x80000000 +#define PH_MENU_ITEM_RETURN_MENU 0x40000000 +#define PH_MENU_ITEM_VALID_FLAGS 0xc0000000 + +PHAPPAPI +ULONG_PTR +NTAPI +PhPluginAddMenuItem( + _In_ PPH_PLUGIN Plugin, + _In_ ULONG_PTR Location, + _In_opt_ PWSTR InsertAfter, + _In_ ULONG Id, + _In_ PWSTR Text, + _In_opt_ PVOID Context + ); + +typedef struct _PH_PLUGIN_SYSTEM_STATISTICS +{ + PSYSTEM_PERFORMANCE_INFORMATION Performance; + + ULONG NumberOfProcesses; + ULONG NumberOfThreads; + ULONG NumberOfHandles; + + FLOAT CpuKernelUsage; + FLOAT CpuUserUsage; + + PH_UINT64_DELTA IoReadDelta; + PH_UINT64_DELTA IoWriteDelta; + PH_UINT64_DELTA IoOtherDelta; + + ULONG CommitPages; + ULONG PhysicalPages; + + HANDLE MaxCpuProcessId; + HANDLE MaxIoProcessId; + + PPH_CIRCULAR_BUFFER_FLOAT CpuKernelHistory; + PPH_CIRCULAR_BUFFER_FLOAT CpuUserHistory; + PPH_CIRCULAR_BUFFER_FLOAT *CpusKernelHistory; + PPH_CIRCULAR_BUFFER_FLOAT *CpusUserHistory; + PPH_CIRCULAR_BUFFER_ULONG64 IoReadHistory; + PPH_CIRCULAR_BUFFER_ULONG64 IoWriteHistory; + PPH_CIRCULAR_BUFFER_ULONG64 IoOtherHistory; + PPH_CIRCULAR_BUFFER_ULONG CommitHistory; + PPH_CIRCULAR_BUFFER_ULONG PhysicalHistory; + PPH_CIRCULAR_BUFFER_ULONG MaxCpuHistory; // ID of max. CPU process + PPH_CIRCULAR_BUFFER_ULONG MaxIoHistory; // ID of max. I/O process + PPH_CIRCULAR_BUFFER_FLOAT MaxCpuUsageHistory; + PPH_CIRCULAR_BUFFER_ULONG64 MaxIoReadOtherHistory; + PPH_CIRCULAR_BUFFER_ULONG64 MaxIoWriteHistory; +} PH_PLUGIN_SYSTEM_STATISTICS, *PPH_PLUGIN_SYSTEM_STATISTICS; + +PHAPPAPI +VOID +NTAPI +PhPluginGetSystemStatistics( + _Out_ PPH_PLUGIN_SYSTEM_STATISTICS Statistics + ); + +PHAPPAPI +PPH_EMENU_ITEM +NTAPI +PhPluginCreateEMenuItem( + _In_ PPH_PLUGIN Plugin, + _In_ ULONG Flags, + _In_ ULONG Id, + _In_ PWSTR Text, + _In_opt_ PVOID Context + ); + +PHAPPAPI +BOOLEAN +NTAPI +PhPluginAddMenuHook( + _Inout_ PPH_PLUGIN_MENU_INFORMATION MenuInfo, + _In_ PPH_PLUGIN Plugin, + _In_opt_ PVOID Context + ); +// end_phapppub + +VOID +NTAPI +PhPluginInitializeMenuInfo( + _Out_ PPH_PLUGIN_MENU_INFORMATION MenuInfo, + _In_opt_ PPH_EMENU Menu, + _In_ HWND OwnerWindow, + _In_ ULONG Flags + ); + +BOOLEAN +NTAPI +PhPluginTriggerEMenuItem( + _In_ PPH_PLUGIN_MENU_INFORMATION MenuInfo, + _In_ PPH_EMENU_ITEM Item + ); + +// begin_phapppub +PHAPPAPI +BOOLEAN +NTAPI +PhPluginAddTreeNewColumn( + _In_ PPH_PLUGIN Plugin, + _In_ PVOID CmData, + _In_ PPH_TREENEW_COLUMN Column, + _In_ ULONG SubId, + _In_opt_ PVOID Context, + _In_opt_ PPH_PLUGIN_TREENEW_SORT_FUNCTION SortFunction + ); + +PHAPPAPI +VOID +NTAPI +PhPluginSetObjectExtension( + _In_ PPH_PLUGIN Plugin, + _In_ PH_EM_OBJECT_TYPE ObjectType, + _In_ ULONG ExtensionSize, + _In_opt_ PPH_EM_OBJECT_CALLBACK CreateCallback, + _In_opt_ PPH_EM_OBJECT_CALLBACK DeleteCallback + ); + +PHAPPAPI +PVOID +NTAPI +PhPluginGetObjectExtension( + _In_ PPH_PLUGIN Plugin, + _In_ PVOID Object, + _In_ PH_EM_OBJECT_TYPE ObjectType + ); + +PHAPPAPI +struct _PH_NF_ICON * +NTAPI +PhPluginRegisterIcon( + _In_ PPH_PLUGIN Plugin, + _In_ ULONG SubId, + _In_opt_ PVOID Context, + _In_ PWSTR Text, + _In_ ULONG Flags, + _In_ struct _PH_NF_ICON_REGISTRATION_DATA *RegistrationData + ); + +PHAPPAPI +VOID +NTAPI +PhPluginEnableTreeNewNotify( + _In_ PPH_PLUGIN Plugin, + _In_ PVOID CmData + ); + +PHAPPAPI +BOOLEAN +NTAPI +PhPluginQueryPhSvc( + _Out_ PPH_PLUGIN_PHSVC_CLIENT Client + ); + +PHAPPAPI +NTSTATUS +NTAPI +PhPluginCallPhSvc( + _In_ PPH_PLUGIN Plugin, + _In_ ULONG SubId, + _In_reads_bytes_opt_(InLength) PVOID InBuffer, + _In_ ULONG InLength, + _Out_writes_bytes_opt_(OutLength) PVOID OutBuffer, + _In_ ULONG OutLength + ); +// end_phapppub + +#endif diff --git a/ProcessHacker/include/phsvc.h b/ProcessHacker/include/phsvc.h index 80fe51e05d21..d2f762541a4d 100644 --- a/ProcessHacker/include/phsvc.h +++ b/ProcessHacker/include/phsvc.h @@ -1,238 +1,238 @@ -#ifndef PH_PHSVC_H -#define PH_PHSVC_H - -#include - -#define PHSVC_SHARED_SECTION_SIZE (512 * 1024) - -// svcmain - -typedef struct _PHSVC_STOP -{ - BOOLEAN Stop; - HANDLE Event1; - HANDLE Event2; -} PHSVC_STOP, *PPHSVC_STOP; - -NTSTATUS PhSvcMain( - _In_opt_ PUNICODE_STRING PortName, - _In_opt_ PLARGE_INTEGER Timeout, - _Inout_opt_ PPHSVC_STOP Stop - ); - -VOID PhSvcStop( - _Inout_ PPHSVC_STOP Stop - ); - -// svcclient - -typedef struct _PHSVC_CLIENT -{ - LIST_ENTRY ListEntry; - - PH_EVENT ReadyEvent; - CLIENT_ID ClientId; - HANDLE PortHandle; - PVOID ClientViewBase; - PVOID ClientViewLimit; -} PHSVC_CLIENT, *PPHSVC_CLIENT; - -NTSTATUS PhSvcClientInitialization( - VOID - ); - -PPHSVC_CLIENT PhSvcCreateClient( - _In_opt_ PCLIENT_ID ClientId - ); - -PPHSVC_CLIENT PhSvcReferenceClientByClientId( - _In_ PCLIENT_ID ClientId - ); - -PPHSVC_CLIENT PhSvcGetCurrentClient( - VOID - ); - -BOOLEAN PhSvcAttachClient( - _In_ PPHSVC_CLIENT Client - ); - -VOID PhSvcDetachClient( - _In_ PPHSVC_CLIENT Client - ); - -// svcapiport - -typedef struct _PHSVC_THREAD_CONTEXT -{ - PPHSVC_CLIENT CurrentClient; - PPHSVC_CLIENT OldClient; -} PHSVC_THREAD_CONTEXT, *PPHSVC_THREAD_CONTEXT; - -NTSTATUS PhSvcApiPortInitialization( - _In_ PUNICODE_STRING PortName - ); - -PPHSVC_THREAD_CONTEXT PhSvcGetCurrentThreadContext( - VOID - ); - -VOID PhSvcHandleConnectionRequest( - _In_ PPORT_MESSAGE PortMessage - ); - -// svcapi - -NTSTATUS PhSvcApiInitialization( - VOID - ); - -typedef NTSTATUS (NTAPI *PPHSVC_API_PROCEDURE)( - _In_ PPHSVC_CLIENT Client, - _Inout_ PPHSVC_API_PAYLOAD Payload - ); - -VOID PhSvcDispatchApiCall( - _In_ PPHSVC_CLIENT Client, - _Inout_ PPHSVC_API_PAYLOAD Payload, - _Out_ PHANDLE ReplyPortHandle - ); - -PVOID PhSvcValidateString( - _In_ PPH_RELATIVE_STRINGREF String, - _In_ ULONG Alignment - ); - -NTSTATUS PhSvcProbeBuffer( - _In_ PPH_RELATIVE_STRINGREF String, - _In_ ULONG Alignment, - _In_ BOOLEAN AllowNull, - _Out_ PVOID *Pointer - ); - -NTSTATUS PhSvcCaptureBuffer( - _In_ PPH_RELATIVE_STRINGREF String, - _In_ BOOLEAN AllowNull, - _Out_ PVOID *CapturedBuffer - ); - -NTSTATUS PhSvcCaptureString( - _In_ PPH_RELATIVE_STRINGREF String, - _In_ BOOLEAN AllowNull, - _Out_ PPH_STRING *CapturedString - ); - -NTSTATUS PhSvcCaptureSid( - _In_ PPH_RELATIVE_STRINGREF String, - _In_ BOOLEAN AllowNull, - _Out_ PSID *CapturedSid - ); - -NTSTATUS PhSvcCaptureSecurityDescriptor( - _In_ PPH_RELATIVE_STRINGREF String, - _In_ BOOLEAN AllowNull, - _In_ SECURITY_INFORMATION RequiredInformation, - _Out_ PSECURITY_DESCRIPTOR *CapturedSecurityDescriptor - ); - -NTSTATUS PhSvcApiDefault( - _In_ PPHSVC_CLIENT Client, - _Inout_ PPHSVC_API_PAYLOAD Payload - ); - -NTSTATUS PhSvcApiPlugin( - _In_ PPHSVC_CLIENT Client, - _Inout_ PPHSVC_API_PAYLOAD Payload - ); - -NTSTATUS PhSvcApiExecuteRunAsCommand( - _In_ PPHSVC_CLIENT Client, - _Inout_ PPHSVC_API_PAYLOAD Payload - ); - -NTSTATUS PhSvcApiUnloadDriver( - _In_ PPHSVC_CLIENT Client, - _Inout_ PPHSVC_API_PAYLOAD Payload - ); - -NTSTATUS PhSvcApiControlProcess( - _In_ PPHSVC_CLIENT Client, - _Inout_ PPHSVC_API_PAYLOAD Payload - ); - -NTSTATUS PhSvcApiControlService( - _In_ PPHSVC_CLIENT Client, - _Inout_ PPHSVC_API_PAYLOAD Payload - ); - -NTSTATUS PhSvcApiCreateService( - _In_ PPHSVC_CLIENT Client, - _Inout_ PPHSVC_API_PAYLOAD Payload - ); - -NTSTATUS PhSvcApiChangeServiceConfig( - _In_ PPHSVC_CLIENT Client, - _Inout_ PPHSVC_API_PAYLOAD Payload - ); - -NTSTATUS PhSvcApiChangeServiceConfig2( - _In_ PPHSVC_CLIENT Client, - _Inout_ PPHSVC_API_PAYLOAD Payload - ); - -NTSTATUS PhSvcApiSetTcpEntry( - _In_ PPHSVC_CLIENT Client, - _Inout_ PPHSVC_API_PAYLOAD Payload - ); - -NTSTATUS PhSvcApiControlThread( - _In_ PPHSVC_CLIENT Client, - _Inout_ PPHSVC_API_PAYLOAD Payload - ); - -NTSTATUS PhSvcApiAddAccountRight( - _In_ PPHSVC_CLIENT Client, - _Inout_ PPHSVC_API_PAYLOAD Payload - ); - -NTSTATUS PhSvcApiInvokeRunAsService( - _In_ PPHSVC_CLIENT Client, - _Inout_ PPHSVC_API_PAYLOAD Payload - ); - -NTSTATUS PhSvcApiIssueMemoryListCommand( - _In_ PPHSVC_CLIENT Client, - _Inout_ PPHSVC_API_PAYLOAD Payload - ); - -NTSTATUS PhSvcApiPostMessage( - _In_ PPHSVC_CLIENT Client, - _Inout_ PPHSVC_API_PAYLOAD Payload - ); - -NTSTATUS PhSvcApiSendMessage( - _In_ PPHSVC_CLIENT Client, - _Inout_ PPHSVC_API_PAYLOAD Payload - ); - -NTSTATUS PhSvcApiCreateProcessIgnoreIfeoDebugger( - _In_ PPHSVC_CLIENT Client, - _Inout_ PPHSVC_API_PAYLOAD Payload - ); - -NTSTATUS PhSvcApiSetServiceSecurity( - _In_ PPHSVC_CLIENT Client, - _Inout_ PPHSVC_API_PAYLOAD Payload - ); - -NTSTATUS PhSvcApiLoadDbgHelp( - _In_ PPHSVC_CLIENT Client, - _Inout_ PPHSVC_API_PAYLOAD Payload - ); - -NTSTATUS PhSvcApiWriteMiniDumpProcess( - _In_ PPHSVC_CLIENT Client, - _Inout_ PPHSVC_API_PAYLOAD Payload - ); - -#endif +#ifndef PH_PHSVC_H +#define PH_PHSVC_H + +#include + +#define PHSVC_SHARED_SECTION_SIZE (512 * 1024) + +// svcmain + +typedef struct _PHSVC_STOP +{ + BOOLEAN Stop; + HANDLE Event1; + HANDLE Event2; +} PHSVC_STOP, *PPHSVC_STOP; + +NTSTATUS PhSvcMain( + _In_opt_ PUNICODE_STRING PortName, + _In_opt_ PLARGE_INTEGER Timeout, + _Inout_opt_ PPHSVC_STOP Stop + ); + +VOID PhSvcStop( + _Inout_ PPHSVC_STOP Stop + ); + +// svcclient + +typedef struct _PHSVC_CLIENT +{ + LIST_ENTRY ListEntry; + + PH_EVENT ReadyEvent; + CLIENT_ID ClientId; + HANDLE PortHandle; + PVOID ClientViewBase; + PVOID ClientViewLimit; +} PHSVC_CLIENT, *PPHSVC_CLIENT; + +NTSTATUS PhSvcClientInitialization( + VOID + ); + +PPHSVC_CLIENT PhSvcCreateClient( + _In_opt_ PCLIENT_ID ClientId + ); + +PPHSVC_CLIENT PhSvcReferenceClientByClientId( + _In_ PCLIENT_ID ClientId + ); + +PPHSVC_CLIENT PhSvcGetCurrentClient( + VOID + ); + +BOOLEAN PhSvcAttachClient( + _In_ PPHSVC_CLIENT Client + ); + +VOID PhSvcDetachClient( + _In_ PPHSVC_CLIENT Client + ); + +// svcapiport + +typedef struct _PHSVC_THREAD_CONTEXT +{ + PPHSVC_CLIENT CurrentClient; + PPHSVC_CLIENT OldClient; +} PHSVC_THREAD_CONTEXT, *PPHSVC_THREAD_CONTEXT; + +NTSTATUS PhSvcApiPortInitialization( + _In_ PUNICODE_STRING PortName + ); + +PPHSVC_THREAD_CONTEXT PhSvcGetCurrentThreadContext( + VOID + ); + +VOID PhSvcHandleConnectionRequest( + _In_ PPORT_MESSAGE PortMessage + ); + +// svcapi + +NTSTATUS PhSvcApiInitialization( + VOID + ); + +typedef NTSTATUS (NTAPI *PPHSVC_API_PROCEDURE)( + _In_ PPHSVC_CLIENT Client, + _Inout_ PPHSVC_API_PAYLOAD Payload + ); + +VOID PhSvcDispatchApiCall( + _In_ PPHSVC_CLIENT Client, + _Inout_ PPHSVC_API_PAYLOAD Payload, + _Out_ PHANDLE ReplyPortHandle + ); + +PVOID PhSvcValidateString( + _In_ PPH_RELATIVE_STRINGREF String, + _In_ ULONG Alignment + ); + +NTSTATUS PhSvcProbeBuffer( + _In_ PPH_RELATIVE_STRINGREF String, + _In_ ULONG Alignment, + _In_ BOOLEAN AllowNull, + _Out_ PVOID *Pointer + ); + +NTSTATUS PhSvcCaptureBuffer( + _In_ PPH_RELATIVE_STRINGREF String, + _In_ BOOLEAN AllowNull, + _Out_ PVOID *CapturedBuffer + ); + +NTSTATUS PhSvcCaptureString( + _In_ PPH_RELATIVE_STRINGREF String, + _In_ BOOLEAN AllowNull, + _Out_ PPH_STRING *CapturedString + ); + +NTSTATUS PhSvcCaptureSid( + _In_ PPH_RELATIVE_STRINGREF String, + _In_ BOOLEAN AllowNull, + _Out_ PSID *CapturedSid + ); + +NTSTATUS PhSvcCaptureSecurityDescriptor( + _In_ PPH_RELATIVE_STRINGREF String, + _In_ BOOLEAN AllowNull, + _In_ SECURITY_INFORMATION RequiredInformation, + _Out_ PSECURITY_DESCRIPTOR *CapturedSecurityDescriptor + ); + +NTSTATUS PhSvcApiDefault( + _In_ PPHSVC_CLIENT Client, + _Inout_ PPHSVC_API_PAYLOAD Payload + ); + +NTSTATUS PhSvcApiPlugin( + _In_ PPHSVC_CLIENT Client, + _Inout_ PPHSVC_API_PAYLOAD Payload + ); + +NTSTATUS PhSvcApiExecuteRunAsCommand( + _In_ PPHSVC_CLIENT Client, + _Inout_ PPHSVC_API_PAYLOAD Payload + ); + +NTSTATUS PhSvcApiUnloadDriver( + _In_ PPHSVC_CLIENT Client, + _Inout_ PPHSVC_API_PAYLOAD Payload + ); + +NTSTATUS PhSvcApiControlProcess( + _In_ PPHSVC_CLIENT Client, + _Inout_ PPHSVC_API_PAYLOAD Payload + ); + +NTSTATUS PhSvcApiControlService( + _In_ PPHSVC_CLIENT Client, + _Inout_ PPHSVC_API_PAYLOAD Payload + ); + +NTSTATUS PhSvcApiCreateService( + _In_ PPHSVC_CLIENT Client, + _Inout_ PPHSVC_API_PAYLOAD Payload + ); + +NTSTATUS PhSvcApiChangeServiceConfig( + _In_ PPHSVC_CLIENT Client, + _Inout_ PPHSVC_API_PAYLOAD Payload + ); + +NTSTATUS PhSvcApiChangeServiceConfig2( + _In_ PPHSVC_CLIENT Client, + _Inout_ PPHSVC_API_PAYLOAD Payload + ); + +NTSTATUS PhSvcApiSetTcpEntry( + _In_ PPHSVC_CLIENT Client, + _Inout_ PPHSVC_API_PAYLOAD Payload + ); + +NTSTATUS PhSvcApiControlThread( + _In_ PPHSVC_CLIENT Client, + _Inout_ PPHSVC_API_PAYLOAD Payload + ); + +NTSTATUS PhSvcApiAddAccountRight( + _In_ PPHSVC_CLIENT Client, + _Inout_ PPHSVC_API_PAYLOAD Payload + ); + +NTSTATUS PhSvcApiInvokeRunAsService( + _In_ PPHSVC_CLIENT Client, + _Inout_ PPHSVC_API_PAYLOAD Payload + ); + +NTSTATUS PhSvcApiIssueMemoryListCommand( + _In_ PPHSVC_CLIENT Client, + _Inout_ PPHSVC_API_PAYLOAD Payload + ); + +NTSTATUS PhSvcApiPostMessage( + _In_ PPHSVC_CLIENT Client, + _Inout_ PPHSVC_API_PAYLOAD Payload + ); + +NTSTATUS PhSvcApiSendMessage( + _In_ PPHSVC_CLIENT Client, + _Inout_ PPHSVC_API_PAYLOAD Payload + ); + +NTSTATUS PhSvcApiCreateProcessIgnoreIfeoDebugger( + _In_ PPHSVC_CLIENT Client, + _Inout_ PPHSVC_API_PAYLOAD Payload + ); + +NTSTATUS PhSvcApiSetServiceSecurity( + _In_ PPHSVC_CLIENT Client, + _Inout_ PPHSVC_API_PAYLOAD Payload + ); + +NTSTATUS PhSvcApiLoadDbgHelp( + _In_ PPHSVC_CLIENT Client, + _Inout_ PPHSVC_API_PAYLOAD Payload + ); + +NTSTATUS PhSvcApiWriteMiniDumpProcess( + _In_ PPHSVC_CLIENT Client, + _Inout_ PPHSVC_API_PAYLOAD Payload + ); + +#endif diff --git a/ProcessHacker/include/phsvcapi.h b/ProcessHacker/include/phsvcapi.h index ca4061239101..cb9458073036 100644 --- a/ProcessHacker/include/phsvcapi.h +++ b/ProcessHacker/include/phsvcapi.h @@ -1,310 +1,310 @@ -#ifndef PH_PHSVCAPI_H -#define PH_PHSVCAPI_H - -#define PHSVC_PORT_NAME (L"\\BaseNamedObjects\\PhSvcApiPort") -#define PHSVC_WOW64_PORT_NAME (L"\\BaseNamedObjects\\PhSvcWow64ApiPort") - -typedef enum _PHSVC_API_NUMBER -{ - PhSvcPluginApiNumber = 1, - PhSvcExecuteRunAsCommandApiNumber = 2, - PhSvcUnloadDriverApiNumber = 3, - PhSvcControlProcessApiNumber = 4, - PhSvcControlServiceApiNumber = 5, - PhSvcCreateServiceApiNumber = 6, - PhSvcChangeServiceConfigApiNumber = 7, - PhSvcChangeServiceConfig2ApiNumber = 8, - PhSvcSetTcpEntryApiNumber = 9, - PhSvcControlThreadApiNumber = 10, - PhSvcAddAccountRightApiNumber = 11, - PhSvcInvokeRunAsServiceApiNumber = 12, - PhSvcIssueMemoryListCommandApiNumber = 13, - PhSvcPostMessageApiNumber = 14, - PhSvcSendMessageApiNumber = 15, - PhSvcCreateProcessIgnoreIfeoDebuggerApiNumber = 16, - PhSvcSetServiceSecurityApiNumber = 17, - PhSvcLoadDbgHelpApiNumber = 18, // WOW64 compatible - PhSvcWriteMiniDumpProcessApiNumber = 19, // WOW64 compatible - PhSvcMaximumApiNumber -} PHSVC_API_NUMBER, *PPHSVC_API_NUMBER; - -typedef struct _PHSVC_API_CONNECTINFO -{ - ULONG ServerProcessId; -} PHSVC_API_CONNECTINFO, *PPHSVC_API_CONNECTINFO; - -typedef union _PHSVC_API_PLUGIN -{ - struct - { - PH_RELATIVE_STRINGREF ApiId; - ULONG Data[30]; - } i; - struct - { - ULONG Data[32]; - } o; -} PHSVC_API_PLUGIN, *PPHSVC_API_PLUGIN; - -typedef union _PHSVC_API_EXECUTERUNASCOMMAND -{ - struct - { - ULONG ProcessId; - PH_RELATIVE_STRINGREF UserName; - PH_RELATIVE_STRINGREF Password; - ULONG LogonType; - ULONG SessionId; - PH_RELATIVE_STRINGREF CurrentDirectory; - PH_RELATIVE_STRINGREF CommandLine; - PH_RELATIVE_STRINGREF FileName; - PH_RELATIVE_STRINGREF DesktopName; - BOOLEAN UseLinkedToken; - PH_RELATIVE_STRINGREF ServiceName; - } i; -} PHSVC_API_EXECUTERUNASCOMMAND, *PPHSVC_API_EXECUTERUNASCOMMAND; - -typedef union _PHSVC_API_UNLOADDRIVER -{ - struct - { - PVOID BaseAddress; - PH_RELATIVE_STRINGREF Name; - } i; -} PHSVC_API_UNLOADDRIVER, *PPHSVC_API_UNLOADDRIVER; - -typedef enum _PHSVC_API_CONTROLPROCESS_COMMAND -{ - PhSvcControlProcessTerminate = 1, - PhSvcControlProcessSuspend, - PhSvcControlProcessResume, - PhSvcControlProcessPriority, - PhSvcControlProcessIoPriority -} PHSVC_API_CONTROLPROCESS_COMMAND; - -typedef union _PHSVC_API_CONTROLPROCESS -{ - struct - { - HANDLE ProcessId; - PHSVC_API_CONTROLPROCESS_COMMAND Command; - ULONG Argument; - } i; -} PHSVC_API_CONTROLPROCESS, *PPHSVC_API_CONTROLPROCESS; - -typedef enum _PHSVC_API_CONTROLSERVICE_COMMAND -{ - PhSvcControlServiceStart = 1, - PhSvcControlServiceContinue, - PhSvcControlServicePause, - PhSvcControlServiceStop, - PhSvcControlServiceDelete -} PHSVC_API_CONTROLSERVICE_COMMAND; - -typedef union _PHSVC_API_CONTROLSERVICE -{ - struct - { - PH_RELATIVE_STRINGREF ServiceName; - PHSVC_API_CONTROLSERVICE_COMMAND Command; - } i; -} PHSVC_API_CONTROLSERVICE, *PPHSVC_API_CONTROLSERVICE; - -typedef union _PHSVC_API_CREATESERVICE -{ - struct - { - // ServiceName is the only required string. - PH_RELATIVE_STRINGREF ServiceName; - PH_RELATIVE_STRINGREF DisplayName; - ULONG ServiceType; - ULONG StartType; - ULONG ErrorControl; - PH_RELATIVE_STRINGREF BinaryPathName; - PH_RELATIVE_STRINGREF LoadOrderGroup; - PH_RELATIVE_STRINGREF Dependencies; - PH_RELATIVE_STRINGREF ServiceStartName; - PH_RELATIVE_STRINGREF Password; - BOOLEAN TagIdSpecified; - } i; - struct - { - ULONG TagId; - } o; -} PHSVC_API_CREATESERVICE, *PPHSVC_API_CREATESERVICE; - -typedef union _PHSVC_API_CHANGESERVICECONFIG -{ - struct - { - PH_RELATIVE_STRINGREF ServiceName; - ULONG ServiceType; - ULONG StartType; - ULONG ErrorControl; - PH_RELATIVE_STRINGREF BinaryPathName; - PH_RELATIVE_STRINGREF LoadOrderGroup; - PH_RELATIVE_STRINGREF Dependencies; - PH_RELATIVE_STRINGREF ServiceStartName; - PH_RELATIVE_STRINGREF Password; - PH_RELATIVE_STRINGREF DisplayName; - BOOLEAN TagIdSpecified; - } i; - struct - { - ULONG TagId; - } o; -} PHSVC_API_CHANGESERVICECONFIG, *PPHSVC_API_CHANGESERVICECONFIG; - -typedef union _PHSVC_API_CHANGESERVICECONFIG2 -{ - struct - { - PH_RELATIVE_STRINGREF ServiceName; - ULONG InfoLevel; - PH_RELATIVE_STRINGREF Info; - } i; -} PHSVC_API_CHANGESERVICECONFIG2, *PPHSVC_API_CHANGESERVICECONFIG2; - -typedef union _PHSVC_API_SETTCPENTRY -{ - struct - { - ULONG State; - ULONG LocalAddress; - ULONG LocalPort; - ULONG RemoteAddress; - ULONG RemotePort; - } i; -} PHSVC_API_SETTCPENTRY, *PPHSVC_API_SETTCPENTRY; - -typedef enum _PHSVC_API_CONTROLTHREAD_COMMAND -{ - PhSvcControlThreadTerminate = 1, - PhSvcControlThreadSuspend, - PhSvcControlThreadResume, - PhSvcControlThreadIoPriority -} PHSVC_API_CONTROLTHREAD_COMMAND; - -typedef union _PHSVC_API_CONTROLTHREAD -{ - struct - { - HANDLE ThreadId; - PHSVC_API_CONTROLTHREAD_COMMAND Command; - ULONG Argument; - } i; -} PHSVC_API_CONTROLTHREAD, *PPHSVC_API_CONTROLTHREAD; - -typedef union _PHSVC_API_ADDACCOUNTRIGHT -{ - struct - { - PH_RELATIVE_STRINGREF AccountSid; - PH_RELATIVE_STRINGREF UserRight; - } i; -} PHSVC_API_ADDACCOUNTRIGHT, *PPHSVC_API_ADDACCOUNTRIGHT; - -typedef union _PHSVC_API_ISSUEMEMORYLISTCOMMAND -{ - struct - { - SYSTEM_MEMORY_LIST_COMMAND Command; - } i; -} PHSVC_API_ISSUEMEMORYLISTCOMMAND, *PPHSVC_API_ISSUEMEMORYLISTCOMMAND; - -typedef union _PHSVC_API_POSTMESSAGE -{ - struct - { - HWND hWnd; - UINT Msg; - WPARAM wParam; - LPARAM lParam; - } i; -} PHSVC_API_POSTMESSAGE, *PPHSVC_API_POSTMESSAGE; - -typedef union _PHSVC_API_CREATEPROCESSIGNOREIFEODEBUGGER -{ - struct - { - PH_RELATIVE_STRINGREF FileName; - } i; -} PHSVC_API_CREATEPROCESSIGNOREIFEODEBUGGER, *PPHSVC_API_CREATEPROCESSIGNOREIFEODEBUGGER; - -typedef union _PHSVC_API_SETSERVICESECURITY -{ - struct - { - PH_RELATIVE_STRINGREF ServiceName; - SECURITY_INFORMATION SecurityInformation; - PH_RELATIVE_STRINGREF SecurityDescriptor; - } i; -} PHSVC_API_SETSERVICESECURITY, *PPHSVC_API_SETSERVICESECURITY; - -typedef union _PHSVC_API_LOADDBGHELP -{ - struct - { - PH_RELATIVE_STRINGREF DbgHelpPath; - } i; -} PHSVC_API_LOADDBGHELP, *PPHSVC_API_LOADDBGHELP; - -typedef union _PHSVC_API_WRITEMINIDUMPPROCESS -{ - struct - { - ULONG LocalProcessHandle; - ULONG ProcessId; - ULONG LocalFileHandle; - ULONG DumpType; - } i; -} PHSVC_API_WRITEMINIDUMPPROCESS, *PPHSVC_API_WRITEMINIDUMPPROCESS; - -typedef union _PHSVC_API_PAYLOAD -{ - PHSVC_API_CONNECTINFO ConnectInfo; - struct - { - PHSVC_API_NUMBER ApiNumber; - NTSTATUS ReturnStatus; - - union - { - PHSVC_API_PLUGIN Plugin; - PHSVC_API_EXECUTERUNASCOMMAND ExecuteRunAsCommand; - PHSVC_API_UNLOADDRIVER UnloadDriver; - PHSVC_API_CONTROLPROCESS ControlProcess; - PHSVC_API_CONTROLSERVICE ControlService; - PHSVC_API_CREATESERVICE CreateService; - PHSVC_API_CHANGESERVICECONFIG ChangeServiceConfig; - PHSVC_API_CHANGESERVICECONFIG2 ChangeServiceConfig2; - PHSVC_API_SETTCPENTRY SetTcpEntry; - PHSVC_API_CONTROLTHREAD ControlThread; - PHSVC_API_ADDACCOUNTRIGHT AddAccountRight; - PHSVC_API_ISSUEMEMORYLISTCOMMAND IssueMemoryListCommand; - PHSVC_API_POSTMESSAGE PostMessage; - PHSVC_API_CREATEPROCESSIGNOREIFEODEBUGGER CreateProcessIgnoreIfeoDebugger; - PHSVC_API_SETSERVICESECURITY SetServiceSecurity; - PHSVC_API_LOADDBGHELP LoadDbgHelp; - PHSVC_API_WRITEMINIDUMPPROCESS WriteMiniDumpProcess; - } u; - }; -} PHSVC_API_PAYLOAD, *PPHSVC_API_PAYLOAD; - -typedef struct _PHSVC_API_MSG -{ - PORT_MESSAGE h; - PHSVC_API_PAYLOAD p; -} PHSVC_API_MSG, *PPHSVC_API_MSG; - -typedef struct _PHSVC_API_MSG64 -{ - PORT_MESSAGE64 h; - PHSVC_API_PAYLOAD p; -} PHSVC_API_MSG64, *PPHSVC_API_MSG64; - -C_ASSERT(FIELD_OFFSET(PHSVC_API_PAYLOAD, u) == 8); -C_ASSERT(sizeof(PHSVC_API_MSG) <= PORT_TOTAL_MAXIMUM_MESSAGE_LENGTH); -C_ASSERT(sizeof(PHSVC_API_MSG64) <= PORT_TOTAL_MAXIMUM_MESSAGE_LENGTH); - -#endif +#ifndef PH_PHSVCAPI_H +#define PH_PHSVCAPI_H + +#define PHSVC_PORT_NAME (L"\\BaseNamedObjects\\PhSvcApiPort") +#define PHSVC_WOW64_PORT_NAME (L"\\BaseNamedObjects\\PhSvcWow64ApiPort") + +typedef enum _PHSVC_API_NUMBER +{ + PhSvcPluginApiNumber = 1, + PhSvcExecuteRunAsCommandApiNumber = 2, + PhSvcUnloadDriverApiNumber = 3, + PhSvcControlProcessApiNumber = 4, + PhSvcControlServiceApiNumber = 5, + PhSvcCreateServiceApiNumber = 6, + PhSvcChangeServiceConfigApiNumber = 7, + PhSvcChangeServiceConfig2ApiNumber = 8, + PhSvcSetTcpEntryApiNumber = 9, + PhSvcControlThreadApiNumber = 10, + PhSvcAddAccountRightApiNumber = 11, + PhSvcInvokeRunAsServiceApiNumber = 12, + PhSvcIssueMemoryListCommandApiNumber = 13, + PhSvcPostMessageApiNumber = 14, + PhSvcSendMessageApiNumber = 15, + PhSvcCreateProcessIgnoreIfeoDebuggerApiNumber = 16, + PhSvcSetServiceSecurityApiNumber = 17, + PhSvcLoadDbgHelpApiNumber = 18, // WOW64 compatible + PhSvcWriteMiniDumpProcessApiNumber = 19, // WOW64 compatible + PhSvcMaximumApiNumber +} PHSVC_API_NUMBER, *PPHSVC_API_NUMBER; + +typedef struct _PHSVC_API_CONNECTINFO +{ + ULONG ServerProcessId; +} PHSVC_API_CONNECTINFO, *PPHSVC_API_CONNECTINFO; + +typedef union _PHSVC_API_PLUGIN +{ + struct + { + PH_RELATIVE_STRINGREF ApiId; + ULONG Data[30]; + } i; + struct + { + ULONG Data[32]; + } o; +} PHSVC_API_PLUGIN, *PPHSVC_API_PLUGIN; + +typedef union _PHSVC_API_EXECUTERUNASCOMMAND +{ + struct + { + ULONG ProcessId; + PH_RELATIVE_STRINGREF UserName; + PH_RELATIVE_STRINGREF Password; + ULONG LogonType; + ULONG SessionId; + PH_RELATIVE_STRINGREF CurrentDirectory; + PH_RELATIVE_STRINGREF CommandLine; + PH_RELATIVE_STRINGREF FileName; + PH_RELATIVE_STRINGREF DesktopName; + BOOLEAN UseLinkedToken; + PH_RELATIVE_STRINGREF ServiceName; + } i; +} PHSVC_API_EXECUTERUNASCOMMAND, *PPHSVC_API_EXECUTERUNASCOMMAND; + +typedef union _PHSVC_API_UNLOADDRIVER +{ + struct + { + PVOID BaseAddress; + PH_RELATIVE_STRINGREF Name; + } i; +} PHSVC_API_UNLOADDRIVER, *PPHSVC_API_UNLOADDRIVER; + +typedef enum _PHSVC_API_CONTROLPROCESS_COMMAND +{ + PhSvcControlProcessTerminate = 1, + PhSvcControlProcessSuspend, + PhSvcControlProcessResume, + PhSvcControlProcessPriority, + PhSvcControlProcessIoPriority +} PHSVC_API_CONTROLPROCESS_COMMAND; + +typedef union _PHSVC_API_CONTROLPROCESS +{ + struct + { + HANDLE ProcessId; + PHSVC_API_CONTROLPROCESS_COMMAND Command; + ULONG Argument; + } i; +} PHSVC_API_CONTROLPROCESS, *PPHSVC_API_CONTROLPROCESS; + +typedef enum _PHSVC_API_CONTROLSERVICE_COMMAND +{ + PhSvcControlServiceStart = 1, + PhSvcControlServiceContinue, + PhSvcControlServicePause, + PhSvcControlServiceStop, + PhSvcControlServiceDelete +} PHSVC_API_CONTROLSERVICE_COMMAND; + +typedef union _PHSVC_API_CONTROLSERVICE +{ + struct + { + PH_RELATIVE_STRINGREF ServiceName; + PHSVC_API_CONTROLSERVICE_COMMAND Command; + } i; +} PHSVC_API_CONTROLSERVICE, *PPHSVC_API_CONTROLSERVICE; + +typedef union _PHSVC_API_CREATESERVICE +{ + struct + { + // ServiceName is the only required string. + PH_RELATIVE_STRINGREF ServiceName; + PH_RELATIVE_STRINGREF DisplayName; + ULONG ServiceType; + ULONG StartType; + ULONG ErrorControl; + PH_RELATIVE_STRINGREF BinaryPathName; + PH_RELATIVE_STRINGREF LoadOrderGroup; + PH_RELATIVE_STRINGREF Dependencies; + PH_RELATIVE_STRINGREF ServiceStartName; + PH_RELATIVE_STRINGREF Password; + BOOLEAN TagIdSpecified; + } i; + struct + { + ULONG TagId; + } o; +} PHSVC_API_CREATESERVICE, *PPHSVC_API_CREATESERVICE; + +typedef union _PHSVC_API_CHANGESERVICECONFIG +{ + struct + { + PH_RELATIVE_STRINGREF ServiceName; + ULONG ServiceType; + ULONG StartType; + ULONG ErrorControl; + PH_RELATIVE_STRINGREF BinaryPathName; + PH_RELATIVE_STRINGREF LoadOrderGroup; + PH_RELATIVE_STRINGREF Dependencies; + PH_RELATIVE_STRINGREF ServiceStartName; + PH_RELATIVE_STRINGREF Password; + PH_RELATIVE_STRINGREF DisplayName; + BOOLEAN TagIdSpecified; + } i; + struct + { + ULONG TagId; + } o; +} PHSVC_API_CHANGESERVICECONFIG, *PPHSVC_API_CHANGESERVICECONFIG; + +typedef union _PHSVC_API_CHANGESERVICECONFIG2 +{ + struct + { + PH_RELATIVE_STRINGREF ServiceName; + ULONG InfoLevel; + PH_RELATIVE_STRINGREF Info; + } i; +} PHSVC_API_CHANGESERVICECONFIG2, *PPHSVC_API_CHANGESERVICECONFIG2; + +typedef union _PHSVC_API_SETTCPENTRY +{ + struct + { + ULONG State; + ULONG LocalAddress; + ULONG LocalPort; + ULONG RemoteAddress; + ULONG RemotePort; + } i; +} PHSVC_API_SETTCPENTRY, *PPHSVC_API_SETTCPENTRY; + +typedef enum _PHSVC_API_CONTROLTHREAD_COMMAND +{ + PhSvcControlThreadTerminate = 1, + PhSvcControlThreadSuspend, + PhSvcControlThreadResume, + PhSvcControlThreadIoPriority +} PHSVC_API_CONTROLTHREAD_COMMAND; + +typedef union _PHSVC_API_CONTROLTHREAD +{ + struct + { + HANDLE ThreadId; + PHSVC_API_CONTROLTHREAD_COMMAND Command; + ULONG Argument; + } i; +} PHSVC_API_CONTROLTHREAD, *PPHSVC_API_CONTROLTHREAD; + +typedef union _PHSVC_API_ADDACCOUNTRIGHT +{ + struct + { + PH_RELATIVE_STRINGREF AccountSid; + PH_RELATIVE_STRINGREF UserRight; + } i; +} PHSVC_API_ADDACCOUNTRIGHT, *PPHSVC_API_ADDACCOUNTRIGHT; + +typedef union _PHSVC_API_ISSUEMEMORYLISTCOMMAND +{ + struct + { + SYSTEM_MEMORY_LIST_COMMAND Command; + } i; +} PHSVC_API_ISSUEMEMORYLISTCOMMAND, *PPHSVC_API_ISSUEMEMORYLISTCOMMAND; + +typedef union _PHSVC_API_POSTMESSAGE +{ + struct + { + HWND hWnd; + UINT Msg; + WPARAM wParam; + LPARAM lParam; + } i; +} PHSVC_API_POSTMESSAGE, *PPHSVC_API_POSTMESSAGE; + +typedef union _PHSVC_API_CREATEPROCESSIGNOREIFEODEBUGGER +{ + struct + { + PH_RELATIVE_STRINGREF FileName; + } i; +} PHSVC_API_CREATEPROCESSIGNOREIFEODEBUGGER, *PPHSVC_API_CREATEPROCESSIGNOREIFEODEBUGGER; + +typedef union _PHSVC_API_SETSERVICESECURITY +{ + struct + { + PH_RELATIVE_STRINGREF ServiceName; + SECURITY_INFORMATION SecurityInformation; + PH_RELATIVE_STRINGREF SecurityDescriptor; + } i; +} PHSVC_API_SETSERVICESECURITY, *PPHSVC_API_SETSERVICESECURITY; + +typedef union _PHSVC_API_LOADDBGHELP +{ + struct + { + PH_RELATIVE_STRINGREF DbgHelpPath; + } i; +} PHSVC_API_LOADDBGHELP, *PPHSVC_API_LOADDBGHELP; + +typedef union _PHSVC_API_WRITEMINIDUMPPROCESS +{ + struct + { + ULONG LocalProcessHandle; + ULONG ProcessId; + ULONG LocalFileHandle; + ULONG DumpType; + } i; +} PHSVC_API_WRITEMINIDUMPPROCESS, *PPHSVC_API_WRITEMINIDUMPPROCESS; + +typedef union _PHSVC_API_PAYLOAD +{ + PHSVC_API_CONNECTINFO ConnectInfo; + struct + { + PHSVC_API_NUMBER ApiNumber; + NTSTATUS ReturnStatus; + + union + { + PHSVC_API_PLUGIN Plugin; + PHSVC_API_EXECUTERUNASCOMMAND ExecuteRunAsCommand; + PHSVC_API_UNLOADDRIVER UnloadDriver; + PHSVC_API_CONTROLPROCESS ControlProcess; + PHSVC_API_CONTROLSERVICE ControlService; + PHSVC_API_CREATESERVICE CreateService; + PHSVC_API_CHANGESERVICECONFIG ChangeServiceConfig; + PHSVC_API_CHANGESERVICECONFIG2 ChangeServiceConfig2; + PHSVC_API_SETTCPENTRY SetTcpEntry; + PHSVC_API_CONTROLTHREAD ControlThread; + PHSVC_API_ADDACCOUNTRIGHT AddAccountRight; + PHSVC_API_ISSUEMEMORYLISTCOMMAND IssueMemoryListCommand; + PHSVC_API_POSTMESSAGE PostMessage; + PHSVC_API_CREATEPROCESSIGNOREIFEODEBUGGER CreateProcessIgnoreIfeoDebugger; + PHSVC_API_SETSERVICESECURITY SetServiceSecurity; + PHSVC_API_LOADDBGHELP LoadDbgHelp; + PHSVC_API_WRITEMINIDUMPPROCESS WriteMiniDumpProcess; + } u; + }; +} PHSVC_API_PAYLOAD, *PPHSVC_API_PAYLOAD; + +typedef struct _PHSVC_API_MSG +{ + PORT_MESSAGE h; + PHSVC_API_PAYLOAD p; +} PHSVC_API_MSG, *PPHSVC_API_MSG; + +typedef struct _PHSVC_API_MSG64 +{ + PORT_MESSAGE64 h; + PHSVC_API_PAYLOAD p; +} PHSVC_API_MSG64, *PPHSVC_API_MSG64; + +C_ASSERT(FIELD_OFFSET(PHSVC_API_PAYLOAD, u) == 8); +C_ASSERT(sizeof(PHSVC_API_MSG) <= PORT_TOTAL_MAXIMUM_MESSAGE_LENGTH); +C_ASSERT(sizeof(PHSVC_API_MSG64) <= PORT_TOTAL_MAXIMUM_MESSAGE_LENGTH); + +#endif diff --git a/ProcessHacker/include/phsvccl.h b/ProcessHacker/include/phsvccl.h index 491669865b80..93fe474f2cf2 100644 --- a/ProcessHacker/include/phsvccl.h +++ b/ProcessHacker/include/phsvccl.h @@ -1,155 +1,155 @@ -#ifndef PH_PHSVCCL_H -#define PH_PHSVCCL_H - -#include - -extern HANDLE PhSvcClServerProcessId; - -NTSTATUS PhSvcConnectToServer( - _In_ PUNICODE_STRING PortName, - _In_opt_ SIZE_T PortSectionSize - ); - -VOID PhSvcDisconnectFromServer( - VOID - ); - -VOID PhSvcpFreeHeap( - _In_ PVOID Memory - ); - -PVOID PhSvcpCreateString( - _In_opt_ PVOID String, - _In_ SIZE_T Length, - _Out_ PPH_RELATIVE_STRINGREF StringRef - ); - -NTSTATUS PhSvcCallPlugin( - _In_ PPH_STRINGREF ApiId, - _In_reads_bytes_opt_(InLength) PVOID InBuffer, - _In_ ULONG InLength, - _Out_writes_bytes_opt_(OutLength) PVOID OutBuffer, - _In_ ULONG OutLength - ); - -NTSTATUS PhSvcCallExecuteRunAsCommand( - _In_ PPH_RUNAS_SERVICE_PARAMETERS Parameters - ); - -NTSTATUS PhSvcCallUnloadDriver( - _In_opt_ PVOID BaseAddress, - _In_opt_ PWSTR Name - ); - -NTSTATUS PhSvcCallControlProcess( - _In_ HANDLE ProcessId, - _In_ PHSVC_API_CONTROLPROCESS_COMMAND Command, - _In_ ULONG Argument - ); - -NTSTATUS PhSvcCallControlService( - _In_ PWSTR ServiceName, - _In_ PHSVC_API_CONTROLSERVICE_COMMAND Command - ); - -NTSTATUS PhSvcCallCreateService( - _In_ PWSTR ServiceName, - _In_opt_ PWSTR DisplayName, - _In_ ULONG ServiceType, - _In_ ULONG StartType, - _In_ ULONG ErrorControl, - _In_opt_ PWSTR BinaryPathName, - _In_opt_ PWSTR LoadOrderGroup, - _Out_opt_ PULONG TagId, - _In_opt_ PWSTR Dependencies, - _In_opt_ PWSTR ServiceStartName, - _In_opt_ PWSTR Password - ); - -// begin_phapppub -PHAPPAPI -NTSTATUS PhSvcCallChangeServiceConfig( - _In_ PWSTR ServiceName, - _In_ ULONG ServiceType, - _In_ ULONG StartType, - _In_ ULONG ErrorControl, - _In_opt_ PWSTR BinaryPathName, - _In_opt_ PWSTR LoadOrderGroup, - _Out_opt_ PULONG TagId, - _In_opt_ PWSTR Dependencies, - _In_opt_ PWSTR ServiceStartName, - _In_opt_ PWSTR Password, - _In_opt_ PWSTR DisplayName - ); - -PHAPPAPI -NTSTATUS PhSvcCallChangeServiceConfig2( - _In_ PWSTR ServiceName, - _In_ ULONG InfoLevel, - _In_ PVOID Info - ); -// end_phapppub - -NTSTATUS PhSvcCallSetTcpEntry( - _In_ PVOID TcpRow - ); - -NTSTATUS PhSvcCallControlThread( - _In_ HANDLE ThreadId, - _In_ PHSVC_API_CONTROLTHREAD_COMMAND Command, - _In_ ULONG Argument - ); - -NTSTATUS PhSvcCallAddAccountRight( - _In_ PSID AccountSid, - _In_ PUNICODE_STRING UserRight - ); - -NTSTATUS PhSvcCallInvokeRunAsService( - _In_ PPH_RUNAS_SERVICE_PARAMETERS Parameters - ); - -NTSTATUS PhSvcCallIssueMemoryListCommand( - _In_ SYSTEM_MEMORY_LIST_COMMAND Command - ); - -// begin_phapppub -PHAPPAPI -NTSTATUS PhSvcCallPostMessage( - _In_opt_ HWND hWnd, - _In_ UINT Msg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -PHAPPAPI -NTSTATUS PhSvcCallSendMessage( - _In_opt_ HWND hWnd, - _In_ UINT Msg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); -// end_phapppub - -NTSTATUS PhSvcCallCreateProcessIgnoreIfeoDebugger( - _In_ PWSTR FileName - ); - -NTSTATUS PhSvcCallSetServiceSecurity( - _In_ PWSTR ServiceName, - _In_ SECURITY_INFORMATION SecurityInformation, - _In_ PSECURITY_DESCRIPTOR SecurityDescriptor - ); - -NTSTATUS PhSvcCallLoadDbgHelp( - _In_ PWSTR DbgHelpPath - ); - -NTSTATUS PhSvcCallWriteMiniDumpProcess( - _In_ HANDLE ProcessHandle, - _In_ HANDLE ProcessId, - _In_ HANDLE FileHandle, - _In_ ULONG DumpType - ); - -#endif +#ifndef PH_PHSVCCL_H +#define PH_PHSVCCL_H + +#include + +extern HANDLE PhSvcClServerProcessId; + +NTSTATUS PhSvcConnectToServer( + _In_ PUNICODE_STRING PortName, + _In_opt_ SIZE_T PortSectionSize + ); + +VOID PhSvcDisconnectFromServer( + VOID + ); + +VOID PhSvcpFreeHeap( + _In_ PVOID Memory + ); + +PVOID PhSvcpCreateString( + _In_opt_ PVOID String, + _In_ SIZE_T Length, + _Out_ PPH_RELATIVE_STRINGREF StringRef + ); + +NTSTATUS PhSvcCallPlugin( + _In_ PPH_STRINGREF ApiId, + _In_reads_bytes_opt_(InLength) PVOID InBuffer, + _In_ ULONG InLength, + _Out_writes_bytes_opt_(OutLength) PVOID OutBuffer, + _In_ ULONG OutLength + ); + +NTSTATUS PhSvcCallExecuteRunAsCommand( + _In_ PPH_RUNAS_SERVICE_PARAMETERS Parameters + ); + +NTSTATUS PhSvcCallUnloadDriver( + _In_opt_ PVOID BaseAddress, + _In_opt_ PWSTR Name + ); + +NTSTATUS PhSvcCallControlProcess( + _In_ HANDLE ProcessId, + _In_ PHSVC_API_CONTROLPROCESS_COMMAND Command, + _In_ ULONG Argument + ); + +NTSTATUS PhSvcCallControlService( + _In_ PWSTR ServiceName, + _In_ PHSVC_API_CONTROLSERVICE_COMMAND Command + ); + +NTSTATUS PhSvcCallCreateService( + _In_ PWSTR ServiceName, + _In_opt_ PWSTR DisplayName, + _In_ ULONG ServiceType, + _In_ ULONG StartType, + _In_ ULONG ErrorControl, + _In_opt_ PWSTR BinaryPathName, + _In_opt_ PWSTR LoadOrderGroup, + _Out_opt_ PULONG TagId, + _In_opt_ PWSTR Dependencies, + _In_opt_ PWSTR ServiceStartName, + _In_opt_ PWSTR Password + ); + +// begin_phapppub +PHAPPAPI +NTSTATUS PhSvcCallChangeServiceConfig( + _In_ PWSTR ServiceName, + _In_ ULONG ServiceType, + _In_ ULONG StartType, + _In_ ULONG ErrorControl, + _In_opt_ PWSTR BinaryPathName, + _In_opt_ PWSTR LoadOrderGroup, + _Out_opt_ PULONG TagId, + _In_opt_ PWSTR Dependencies, + _In_opt_ PWSTR ServiceStartName, + _In_opt_ PWSTR Password, + _In_opt_ PWSTR DisplayName + ); + +PHAPPAPI +NTSTATUS PhSvcCallChangeServiceConfig2( + _In_ PWSTR ServiceName, + _In_ ULONG InfoLevel, + _In_ PVOID Info + ); +// end_phapppub + +NTSTATUS PhSvcCallSetTcpEntry( + _In_ PVOID TcpRow + ); + +NTSTATUS PhSvcCallControlThread( + _In_ HANDLE ThreadId, + _In_ PHSVC_API_CONTROLTHREAD_COMMAND Command, + _In_ ULONG Argument + ); + +NTSTATUS PhSvcCallAddAccountRight( + _In_ PSID AccountSid, + _In_ PUNICODE_STRING UserRight + ); + +NTSTATUS PhSvcCallInvokeRunAsService( + _In_ PPH_RUNAS_SERVICE_PARAMETERS Parameters + ); + +NTSTATUS PhSvcCallIssueMemoryListCommand( + _In_ SYSTEM_MEMORY_LIST_COMMAND Command + ); + +// begin_phapppub +PHAPPAPI +NTSTATUS PhSvcCallPostMessage( + _In_opt_ HWND hWnd, + _In_ UINT Msg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +PHAPPAPI +NTSTATUS PhSvcCallSendMessage( + _In_opt_ HWND hWnd, + _In_ UINT Msg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); +// end_phapppub + +NTSTATUS PhSvcCallCreateProcessIgnoreIfeoDebugger( + _In_ PWSTR FileName + ); + +NTSTATUS PhSvcCallSetServiceSecurity( + _In_ PWSTR ServiceName, + _In_ SECURITY_INFORMATION SecurityInformation, + _In_ PSECURITY_DESCRIPTOR SecurityDescriptor + ); + +NTSTATUS PhSvcCallLoadDbgHelp( + _In_ PWSTR DbgHelpPath + ); + +NTSTATUS PhSvcCallWriteMiniDumpProcess( + _In_ HANDLE ProcessHandle, + _In_ HANDLE ProcessId, + _In_ HANDLE FileHandle, + _In_ ULONG DumpType + ); + +#endif diff --git a/ProcessHacker/include/procgrp.h b/ProcessHacker/include/procgrp.h index 02ce0fc4c213..0a6c947654cd 100644 --- a/ProcessHacker/include/procgrp.h +++ b/ProcessHacker/include/procgrp.h @@ -1,32 +1,32 @@ -#ifndef PH_PROCGRP_H -#define PH_PROCGRP_H - -// begin_phapppub -typedef struct _PH_PROCESS_GROUP -{ - PPH_PROCESS_ITEM Representative; // An element of Processes (no extra reference added) - PPH_LIST Processes; // List of PPH_PROCESS_ITEM - HWND WindowHandle; // Window handle of representative -} PH_PROCESS_GROUP, *PPH_PROCESS_GROUP; -// end_phapppub - -typedef VOID (NTAPI *PPH_SORT_LIST_FUNCTION)( - _In_ PPH_LIST List, - _In_opt_ PVOID Context - ); - -#define PH_GROUP_PROCESSES_DONT_GROUP 0x1 -#define PH_GROUP_PROCESSES_FILE_PATH 0x2 - -PPH_LIST PhCreateProcessGroupList( - _In_opt_ PPH_SORT_LIST_FUNCTION SortListFunction, // Sort a list of PPH_PROCESS_NODE - _In_opt_ PVOID Context, - _In_ ULONG MaximumGroups, - _In_ ULONG Flags - ); - -VOID PhFreeProcessGroupList( - _In_ PPH_LIST List - ); - +#ifndef PH_PROCGRP_H +#define PH_PROCGRP_H + +// begin_phapppub +typedef struct _PH_PROCESS_GROUP +{ + PPH_PROCESS_ITEM Representative; // An element of Processes (no extra reference added) + PPH_LIST Processes; // List of PPH_PROCESS_ITEM + HWND WindowHandle; // Window handle of representative +} PH_PROCESS_GROUP, *PPH_PROCESS_GROUP; +// end_phapppub + +typedef VOID (NTAPI *PPH_SORT_LIST_FUNCTION)( + _In_ PPH_LIST List, + _In_opt_ PVOID Context + ); + +#define PH_GROUP_PROCESSES_DONT_GROUP 0x1 +#define PH_GROUP_PROCESSES_FILE_PATH 0x2 + +PPH_LIST PhCreateProcessGroupList( + _In_opt_ PPH_SORT_LIST_FUNCTION SortListFunction, // Sort a list of PPH_PROCESS_NODE + _In_opt_ PVOID Context, + _In_ ULONG MaximumGroups, + _In_ ULONG Flags + ); + +VOID PhFreeProcessGroupList( + _In_ PPH_LIST List + ); + #endif \ No newline at end of file diff --git a/ProcessHacker/include/procprpp.h b/ProcessHacker/include/procprpp.h index 64149e5078b4..3d5538b7d97b 100644 --- a/ProcessHacker/include/procprpp.h +++ b/ProcessHacker/include/procprpp.h @@ -1,346 +1,346 @@ -#ifndef PH_PROCPRPP_H -#define PH_PROCPRPP_H - -#include -#include -#include -#include -#include - -typedef struct _PH_PROCESS_PROPSHEETCONTEXT -{ - PH_LAYOUT_MANAGER LayoutManager; - PPH_LAYOUT_ITEM TabPageItem; - BOOLEAN LayoutInitialized; -} PH_PROCESS_PROPSHEETCONTEXT, *PPH_PROCESS_PROPSHEETCONTEXT; - -VOID NTAPI PhpProcessPropContextDeleteProcedure( - _In_ PVOID Object, - _In_ ULONG Flags - ); - -INT CALLBACK PhpPropSheetProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ LPARAM lParam - ); - -PPH_PROCESS_PROPSHEETCONTEXT PhpGetPropSheetContext( - _In_ HWND hwnd - ); - -LRESULT CALLBACK PhpPropSheetWndProc( - _In_ HWND hwnd, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam, - _In_ UINT_PTR uIdSubclass, - _In_ ULONG_PTR dwRefData - ); - -VOID NTAPI PhpProcessPropPageContextDeleteProcedure( - _In_ PVOID Object, - _In_ ULONG Flags - ); - -INT CALLBACK PhpStandardPropPageProc( - _In_ HWND hwnd, - _In_ UINT uMsg, - _In_ LPPROPSHEETPAGE ppsp - ); - -FORCEINLINE BOOLEAN PhpPropPageDlgProcHeader( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ LPARAM lParam, - _Out_ LPPROPSHEETPAGE *PropSheetPage, - _Out_ PPH_PROCESS_PROPPAGECONTEXT *PropPageContext, - _Out_ PPH_PROCESS_ITEM *ProcessItem - ) -{ - LPPROPSHEETPAGE propSheetPage; - PPH_PROCESS_PROPPAGECONTEXT propPageContext; - - if (uMsg == WM_INITDIALOG) - { - // Save the context. - SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)lParam); - } - - propSheetPage = (LPPROPSHEETPAGE)GetProp(hwndDlg, PhMakeContextAtom()); - - if (!propSheetPage) - return FALSE; - - *PropSheetPage = propSheetPage; - *PropPageContext = propPageContext = (PPH_PROCESS_PROPPAGECONTEXT)propSheetPage->lParam; - *ProcessItem = propPageContext->PropContext->ProcessItem; - - return TRUE; -} - -FORCEINLINE VOID PhpPropPageDlgProcDestroy( - _In_ HWND hwndDlg - ) -{ - RemoveProp(hwndDlg, PhMakeContextAtom()); -} - -#define SET_BUTTON_ICON(Id, Icon) \ - SendMessage(GetDlgItem(hwndDlg, (Id)), BM_SETIMAGE, IMAGE_ICON, (LPARAM)(Icon)) - -INT_PTR CALLBACK PhpProcessGeneralDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -INT_PTR CALLBACK PhpProcessStatisticsDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -INT_PTR CALLBACK PhpProcessPerformanceDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -INT_PTR CALLBACK PhpProcessThreadsDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -NTSTATUS NTAPI PhpOpenProcessTokenForPage( - _Out_ PHANDLE Handle, - _In_ ACCESS_MASK DesiredAccess, - _In_opt_ PVOID Context - ); - -INT_PTR CALLBACK PhpProcessTokenHookProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -INT_PTR CALLBACK PhpProcessModulesDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -INT_PTR CALLBACK PhpProcessMemoryDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -INT_PTR CALLBACK PhpProcessEnvironmentDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -INT_PTR CALLBACK PhpProcessHandlesDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -NTSTATUS NTAPI PhpOpenProcessJobForPage( - _Out_ PHANDLE Handle, - _In_ ACCESS_MASK DesiredAccess, - _In_opt_ PVOID Context - ); - -INT_PTR CALLBACK PhpProcessJobHookProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -INT_PTR CALLBACK PhpProcessServicesDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -extern PH_STRINGREF PhpLoadingText; - -#define WM_PH_THREADS_UPDATED (WM_APP + 200) -#define WM_PH_THREAD_SELECTION_CHANGED (WM_APP + 201) - -// begin_phapppub -typedef struct _PH_THREADS_CONTEXT -{ - PPH_THREAD_PROVIDER Provider; - PH_CALLBACK_REGISTRATION ProviderRegistration; - PH_CALLBACK_REGISTRATION AddedEventRegistration; - PH_CALLBACK_REGISTRATION ModifiedEventRegistration; - PH_CALLBACK_REGISTRATION RemovedEventRegistration; - PH_CALLBACK_REGISTRATION UpdatedEventRegistration; - PH_CALLBACK_REGISTRATION LoadingStateChangedEventRegistration; - - HWND WindowHandle; -// end_phapppub - - union - { - PH_THREAD_LIST_CONTEXT ListContext; - struct - { - HWND Private; // phapppub - HWND TreeNewHandle; // phapppub - } PublicUse; - }; - PH_PROVIDER_EVENT_QUEUE EventQueue; -// begin_phapppub -} PH_THREADS_CONTEXT, *PPH_THREADS_CONTEXT; -// end_phapppub - -#define WM_PH_MODULES_UPDATED (WM_APP + 210) - -// begin_phapppub -typedef struct _PH_MODULES_CONTEXT -{ - PPH_MODULE_PROVIDER Provider; - PH_PROVIDER_REGISTRATION ProviderRegistration; - PH_CALLBACK_REGISTRATION AddedEventRegistration; - PH_CALLBACK_REGISTRATION ModifiedEventRegistration; - PH_CALLBACK_REGISTRATION RemovedEventRegistration; - PH_CALLBACK_REGISTRATION UpdatedEventRegistration; - - HWND WindowHandle; -// end_phapppub - - union - { - PH_MODULE_LIST_CONTEXT ListContext; - struct - { - HWND Private; // phapppub - HWND TreeNewHandle; // phapppub - } PublicUse; - }; - PH_PROVIDER_EVENT_QUEUE EventQueue; - NTSTATUS LastRunStatus; - PPH_STRING ErrorMessage; -// begin_phapppub -} PH_MODULES_CONTEXT, *PPH_MODULES_CONTEXT; -// end_phapppub - -#define WM_PH_HANDLES_UPDATED (WM_APP + 220) - -// begin_phapppub -typedef struct _PH_HANDLES_CONTEXT -{ - PPH_HANDLE_PROVIDER Provider; - PH_PROVIDER_REGISTRATION ProviderRegistration; - PH_CALLBACK_REGISTRATION AddedEventRegistration; - PH_CALLBACK_REGISTRATION ModifiedEventRegistration; - PH_CALLBACK_REGISTRATION RemovedEventRegistration; - PH_CALLBACK_REGISTRATION UpdatedEventRegistration; - - HWND WindowHandle; - HWND SearchboxHandle; -// end_phapppub - - union - { - PH_HANDLE_LIST_CONTEXT ListContext; - struct - { - HWND Private; // phapppub - HWND TreeNewHandle; // phapppub - } PublicUse; - }; - PH_PROVIDER_EVENT_QUEUE EventQueue; - BOOLEAN SelectedHandleProtected; - BOOLEAN SelectedHandleInherit; - NTSTATUS LastRunStatus; - PPH_STRING ErrorMessage; - - PPH_STRING SearchboxText; - PPH_TN_FILTER_ENTRY FilterEntry; -// begin_phapppub -} PH_HANDLES_CONTEXT, *PPH_HANDLES_CONTEXT; -// end_phapppub - -// begin_phapppub -typedef struct _PH_MEMORY_CONTEXT -{ - HANDLE ProcessId; - HWND WindowHandle; -// end_phapppub - - union - { - PH_MEMORY_LIST_CONTEXT ListContext; - struct - { - HWND Private; // phapppub - HWND TreeNewHandle; // phapppub - } PublicUse; - }; - PH_MEMORY_ITEM_LIST MemoryItemList; - BOOLEAN MemoryItemListValid; - NTSTATUS LastRunStatus; - PPH_STRING ErrorMessage; -// begin_phapppub -} PH_MEMORY_CONTEXT, *PPH_MEMORY_CONTEXT; -// end_phapppub - -#define WM_PH_STATISTICS_UPDATE (WM_APP + 231) - -typedef struct _PH_STATISTICS_CONTEXT -{ - PH_CALLBACK_REGISTRATION ProcessesUpdatedRegistration; - - HWND WindowHandle; - BOOLEAN Enabled; - HANDLE ProcessHandle; -} PH_STATISTICS_CONTEXT, *PPH_STATISTICS_CONTEXT; - -#define WM_PH_PERFORMANCE_UPDATE (WM_APP + 241) - -typedef struct _PH_PERFORMANCE_CONTEXT -{ - PH_CALLBACK_REGISTRATION ProcessesUpdatedRegistration; - - HWND WindowHandle; - - PH_GRAPH_STATE CpuGraphState; - PH_GRAPH_STATE PrivateGraphState; - PH_GRAPH_STATE IoGraphState; - - HWND CpuGraphHandle; - HWND PrivateGraphHandle; - HWND IoGraphHandle; -} PH_PERFORMANCE_CONTEXT, *PPH_PERFORMANCE_CONTEXT; - -typedef struct _PH_ENVIRONMENT_ITEM -{ - PPH_STRING Name; - PPH_STRING Value; -} PH_ENVIRONMENT_ITEM, *PPH_ENVIRONMENT_ITEM; - -typedef struct _PH_ENVIRONMENT_CONTEXT -{ - HWND ListViewHandle; - PH_ARRAY Items; -} PH_ENVIRONMENT_CONTEXT, *PPH_ENVIRONMENT_CONTEXT; - -#endif +#ifndef PH_PROCPRPP_H +#define PH_PROCPRPP_H + +#include +#include +#include +#include +#include + +typedef struct _PH_PROCESS_PROPSHEETCONTEXT +{ + PH_LAYOUT_MANAGER LayoutManager; + PPH_LAYOUT_ITEM TabPageItem; + BOOLEAN LayoutInitialized; +} PH_PROCESS_PROPSHEETCONTEXT, *PPH_PROCESS_PROPSHEETCONTEXT; + +VOID NTAPI PhpProcessPropContextDeleteProcedure( + _In_ PVOID Object, + _In_ ULONG Flags + ); + +INT CALLBACK PhpPropSheetProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ LPARAM lParam + ); + +PPH_PROCESS_PROPSHEETCONTEXT PhpGetPropSheetContext( + _In_ HWND hwnd + ); + +LRESULT CALLBACK PhpPropSheetWndProc( + _In_ HWND hwnd, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam, + _In_ UINT_PTR uIdSubclass, + _In_ ULONG_PTR dwRefData + ); + +VOID NTAPI PhpProcessPropPageContextDeleteProcedure( + _In_ PVOID Object, + _In_ ULONG Flags + ); + +INT CALLBACK PhpStandardPropPageProc( + _In_ HWND hwnd, + _In_ UINT uMsg, + _In_ LPPROPSHEETPAGE ppsp + ); + +FORCEINLINE BOOLEAN PhpPropPageDlgProcHeader( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ LPARAM lParam, + _Out_ LPPROPSHEETPAGE *PropSheetPage, + _Out_ PPH_PROCESS_PROPPAGECONTEXT *PropPageContext, + _Out_ PPH_PROCESS_ITEM *ProcessItem + ) +{ + LPPROPSHEETPAGE propSheetPage; + PPH_PROCESS_PROPPAGECONTEXT propPageContext; + + if (uMsg == WM_INITDIALOG) + { + // Save the context. + SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)lParam); + } + + propSheetPage = (LPPROPSHEETPAGE)GetProp(hwndDlg, PhMakeContextAtom()); + + if (!propSheetPage) + return FALSE; + + *PropSheetPage = propSheetPage; + *PropPageContext = propPageContext = (PPH_PROCESS_PROPPAGECONTEXT)propSheetPage->lParam; + *ProcessItem = propPageContext->PropContext->ProcessItem; + + return TRUE; +} + +FORCEINLINE VOID PhpPropPageDlgProcDestroy( + _In_ HWND hwndDlg + ) +{ + RemoveProp(hwndDlg, PhMakeContextAtom()); +} + +#define SET_BUTTON_ICON(Id, Icon) \ + SendMessage(GetDlgItem(hwndDlg, (Id)), BM_SETIMAGE, IMAGE_ICON, (LPARAM)(Icon)) + +INT_PTR CALLBACK PhpProcessGeneralDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +INT_PTR CALLBACK PhpProcessStatisticsDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +INT_PTR CALLBACK PhpProcessPerformanceDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +INT_PTR CALLBACK PhpProcessThreadsDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +NTSTATUS NTAPI PhpOpenProcessTokenForPage( + _Out_ PHANDLE Handle, + _In_ ACCESS_MASK DesiredAccess, + _In_opt_ PVOID Context + ); + +INT_PTR CALLBACK PhpProcessTokenHookProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +INT_PTR CALLBACK PhpProcessModulesDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +INT_PTR CALLBACK PhpProcessMemoryDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +INT_PTR CALLBACK PhpProcessEnvironmentDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +INT_PTR CALLBACK PhpProcessHandlesDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +NTSTATUS NTAPI PhpOpenProcessJobForPage( + _Out_ PHANDLE Handle, + _In_ ACCESS_MASK DesiredAccess, + _In_opt_ PVOID Context + ); + +INT_PTR CALLBACK PhpProcessJobHookProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +INT_PTR CALLBACK PhpProcessServicesDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +extern PH_STRINGREF PhpLoadingText; + +#define WM_PH_THREADS_UPDATED (WM_APP + 200) +#define WM_PH_THREAD_SELECTION_CHANGED (WM_APP + 201) + +// begin_phapppub +typedef struct _PH_THREADS_CONTEXT +{ + PPH_THREAD_PROVIDER Provider; + PH_CALLBACK_REGISTRATION ProviderRegistration; + PH_CALLBACK_REGISTRATION AddedEventRegistration; + PH_CALLBACK_REGISTRATION ModifiedEventRegistration; + PH_CALLBACK_REGISTRATION RemovedEventRegistration; + PH_CALLBACK_REGISTRATION UpdatedEventRegistration; + PH_CALLBACK_REGISTRATION LoadingStateChangedEventRegistration; + + HWND WindowHandle; +// end_phapppub + + union + { + PH_THREAD_LIST_CONTEXT ListContext; + struct + { + HWND Private; // phapppub + HWND TreeNewHandle; // phapppub + } PublicUse; + }; + PH_PROVIDER_EVENT_QUEUE EventQueue; +// begin_phapppub +} PH_THREADS_CONTEXT, *PPH_THREADS_CONTEXT; +// end_phapppub + +#define WM_PH_MODULES_UPDATED (WM_APP + 210) + +// begin_phapppub +typedef struct _PH_MODULES_CONTEXT +{ + PPH_MODULE_PROVIDER Provider; + PH_PROVIDER_REGISTRATION ProviderRegistration; + PH_CALLBACK_REGISTRATION AddedEventRegistration; + PH_CALLBACK_REGISTRATION ModifiedEventRegistration; + PH_CALLBACK_REGISTRATION RemovedEventRegistration; + PH_CALLBACK_REGISTRATION UpdatedEventRegistration; + + HWND WindowHandle; +// end_phapppub + + union + { + PH_MODULE_LIST_CONTEXT ListContext; + struct + { + HWND Private; // phapppub + HWND TreeNewHandle; // phapppub + } PublicUse; + }; + PH_PROVIDER_EVENT_QUEUE EventQueue; + NTSTATUS LastRunStatus; + PPH_STRING ErrorMessage; +// begin_phapppub +} PH_MODULES_CONTEXT, *PPH_MODULES_CONTEXT; +// end_phapppub + +#define WM_PH_HANDLES_UPDATED (WM_APP + 220) + +// begin_phapppub +typedef struct _PH_HANDLES_CONTEXT +{ + PPH_HANDLE_PROVIDER Provider; + PH_PROVIDER_REGISTRATION ProviderRegistration; + PH_CALLBACK_REGISTRATION AddedEventRegistration; + PH_CALLBACK_REGISTRATION ModifiedEventRegistration; + PH_CALLBACK_REGISTRATION RemovedEventRegistration; + PH_CALLBACK_REGISTRATION UpdatedEventRegistration; + + HWND WindowHandle; + HWND SearchboxHandle; +// end_phapppub + + union + { + PH_HANDLE_LIST_CONTEXT ListContext; + struct + { + HWND Private; // phapppub + HWND TreeNewHandle; // phapppub + } PublicUse; + }; + PH_PROVIDER_EVENT_QUEUE EventQueue; + BOOLEAN SelectedHandleProtected; + BOOLEAN SelectedHandleInherit; + NTSTATUS LastRunStatus; + PPH_STRING ErrorMessage; + + PPH_STRING SearchboxText; + PPH_TN_FILTER_ENTRY FilterEntry; +// begin_phapppub +} PH_HANDLES_CONTEXT, *PPH_HANDLES_CONTEXT; +// end_phapppub + +// begin_phapppub +typedef struct _PH_MEMORY_CONTEXT +{ + HANDLE ProcessId; + HWND WindowHandle; +// end_phapppub + + union + { + PH_MEMORY_LIST_CONTEXT ListContext; + struct + { + HWND Private; // phapppub + HWND TreeNewHandle; // phapppub + } PublicUse; + }; + PH_MEMORY_ITEM_LIST MemoryItemList; + BOOLEAN MemoryItemListValid; + NTSTATUS LastRunStatus; + PPH_STRING ErrorMessage; +// begin_phapppub +} PH_MEMORY_CONTEXT, *PPH_MEMORY_CONTEXT; +// end_phapppub + +#define WM_PH_STATISTICS_UPDATE (WM_APP + 231) + +typedef struct _PH_STATISTICS_CONTEXT +{ + PH_CALLBACK_REGISTRATION ProcessesUpdatedRegistration; + + HWND WindowHandle; + BOOLEAN Enabled; + HANDLE ProcessHandle; +} PH_STATISTICS_CONTEXT, *PPH_STATISTICS_CONTEXT; + +#define WM_PH_PERFORMANCE_UPDATE (WM_APP + 241) + +typedef struct _PH_PERFORMANCE_CONTEXT +{ + PH_CALLBACK_REGISTRATION ProcessesUpdatedRegistration; + + HWND WindowHandle; + + PH_GRAPH_STATE CpuGraphState; + PH_GRAPH_STATE PrivateGraphState; + PH_GRAPH_STATE IoGraphState; + + HWND CpuGraphHandle; + HWND PrivateGraphHandle; + HWND IoGraphHandle; +} PH_PERFORMANCE_CONTEXT, *PPH_PERFORMANCE_CONTEXT; + +typedef struct _PH_ENVIRONMENT_ITEM +{ + PPH_STRING Name; + PPH_STRING Value; +} PH_ENVIRONMENT_ITEM, *PPH_ENVIRONMENT_ITEM; + +typedef struct _PH_ENVIRONMENT_CONTEXT +{ + HWND ListViewHandle; + PH_ARRAY Items; +} PH_ENVIRONMENT_CONTEXT, *PPH_ENVIRONMENT_CONTEXT; + +#endif diff --git a/ProcessHacker/include/settings.h b/ProcessHacker/include/settings.h index 476961404c1e..bf0e871bb5c6 100644 --- a/ProcessHacker/include/settings.h +++ b/ProcessHacker/include/settings.h @@ -1,229 +1,229 @@ -#ifndef PH_SETTINGS_H -#define PH_SETTINGS_H - -// begin_phapppub -typedef enum _PH_SETTING_TYPE -{ - StringSettingType, - IntegerSettingType, - IntegerPairSettingType, - ScalableIntegerPairSettingType -} PH_SETTING_TYPE, PPH_SETTING_TYPE; -// end_phapppub - -typedef struct _PH_SETTING -{ - PH_SETTING_TYPE Type; - PH_STRINGREF Name; - PH_STRINGREF DefaultValue; - - union - { - PVOID Pointer; - ULONG Integer; - PH_INTEGER_PAIR IntegerPair; - } u; -} PH_SETTING, *PPH_SETTING; - -VOID PhSettingsInitialization( - VOID - ); - -VOID PhUpdateCachedSettings( - VOID - ); - -// begin_phapppub -_May_raise_ -PHAPPAPI -ULONG -NTAPI -PhGetIntegerSetting( - _In_ PWSTR Name - ); - -_May_raise_ -PHAPPAPI -PH_INTEGER_PAIR -NTAPI -PhGetIntegerPairSetting( - _In_ PWSTR Name - ); - -_May_raise_ -PHAPPAPI -PH_SCALABLE_INTEGER_PAIR -NTAPI -PhGetScalableIntegerPairSetting( - _In_ PWSTR Name, - _In_ BOOLEAN ScaleToCurrent - ); - -_May_raise_ -PHAPPAPI -PPH_STRING -NTAPI -PhGetStringSetting( - _In_ PWSTR Name - ); - -_May_raise_ -PHAPPAPI -VOID -NTAPI -PhSetIntegerSetting( - _In_ PWSTR Name, - _In_ ULONG Value - ); - -_May_raise_ -PHAPPAPI -VOID -NTAPI -PhSetIntegerPairSetting( - _In_ PWSTR Name, - _In_ PH_INTEGER_PAIR Value - ); - -_May_raise_ -PHAPPAPI -VOID -NTAPI -PhSetScalableIntegerPairSetting( - _In_ PWSTR Name, - _In_ PH_SCALABLE_INTEGER_PAIR Value - ); - -_May_raise_ -PHAPPAPI -VOID -NTAPI -PhSetScalableIntegerPairSetting2( - _In_ PWSTR Name, - _In_ PH_INTEGER_PAIR Value - ); - -_May_raise_ -PHAPPAPI -VOID -NTAPI -PhSetStringSetting( - _In_ PWSTR Name, - _In_ PWSTR Value - ); - -_May_raise_ -PHAPPAPI -VOID -NTAPI -PhSetStringSetting2( - _In_ PWSTR Name, - _In_ PPH_STRINGREF Value - ); -// end_phapppub - -VOID PhClearIgnoredSettings( - VOID - ); - -VOID PhConvertIgnoredSettings( - VOID - ); - -NTSTATUS PhLoadSettings( - _In_ PWSTR FileName - ); - -NTSTATUS PhSaveSettings( - _In_ PWSTR FileName - ); - -VOID PhResetSettings( - VOID - ); - -#define PhaGetStringSetting(Name) PH_AUTO_T(PH_STRING, PhGetStringSetting(Name)) // phapppub - -// begin_phapppub -// High-level settings creation - -typedef struct _PH_SETTING_CREATE -{ - PH_SETTING_TYPE Type; - PWSTR Name; - PWSTR DefaultValue; -} PH_SETTING_CREATE, *PPH_SETTING_CREATE; - -PHAPPAPI -VOID -NTAPI -PhAddSettings( - _In_ PPH_SETTING_CREATE Settings, - _In_ ULONG NumberOfSettings - ); -// end_phapppub - -// Cached settings - -#undef EXT - -#ifdef PH_SETTINGS_PRIVATE -#define EXT -#else -#define EXT extern -#endif - -EXT ULONG PhCsCollapseServicesOnStart; -EXT ULONG PhCsForceNoParent; -EXT ULONG PhCsHighlightingDuration; -EXT ULONG PhCsPropagateCpuUsage; -EXT ULONG PhCsScrollToNewProcesses; -EXT ULONG PhCsShowCpuBelow001; -EXT ULONG PhCsUpdateInterval; - -EXT ULONG PhCsColorNew; -EXT ULONG PhCsColorRemoved; -EXT ULONG PhCsUseColorOwnProcesses; -EXT ULONG PhCsColorOwnProcesses; -EXT ULONG PhCsUseColorSystemProcesses; -EXT ULONG PhCsColorSystemProcesses; -EXT ULONG PhCsUseColorServiceProcesses; -EXT ULONG PhCsColorServiceProcesses; -EXT ULONG PhCsUseColorJobProcesses; -EXT ULONG PhCsColorJobProcesses; -EXT ULONG PhCsUseColorWow64Processes; -EXT ULONG PhCsColorWow64Processes; -EXT ULONG PhCsUseColorDebuggedProcesses; -EXT ULONG PhCsColorDebuggedProcesses; -EXT ULONG PhCsUseColorElevatedProcesses; -EXT ULONG PhCsColorElevatedProcesses; -EXT ULONG PhCsUseColorPicoProcesses; -EXT ULONG PhCsColorPicoProcesses; -EXT ULONG PhCsUseColorImmersiveProcesses; -EXT ULONG PhCsColorImmersiveProcesses; -EXT ULONG PhCsUseColorSuspended; -EXT ULONG PhCsColorSuspended; -EXT ULONG PhCsUseColorDotNet; -EXT ULONG PhCsColorDotNet; -EXT ULONG PhCsUseColorPacked; -EXT ULONG PhCsColorPacked; -EXT ULONG PhCsUseColorGuiThreads; -EXT ULONG PhCsColorGuiThreads; -EXT ULONG PhCsUseColorRelocatedModules; -EXT ULONG PhCsColorRelocatedModules; -EXT ULONG PhCsUseColorProtectedHandles; -EXT ULONG PhCsColorProtectedHandles; -EXT ULONG PhCsUseColorInheritHandles; -EXT ULONG PhCsColorInheritHandles; -EXT ULONG PhCsGraphShowText; -EXT ULONG PhCsGraphColorMode; -EXT ULONG PhCsColorCpuKernel; -EXT ULONG PhCsColorCpuUser; -EXT ULONG PhCsColorIoReadOther; -EXT ULONG PhCsColorIoWrite; -EXT ULONG PhCsColorPrivate; -EXT ULONG PhCsColorPhysical; - -#define PH_SET_INTEGER_CACHED_SETTING(Name, Value) (PhSetIntegerSetting(L#Name, PhCs##Name = (Value))) - -#endif +#ifndef PH_SETTINGS_H +#define PH_SETTINGS_H + +// begin_phapppub +typedef enum _PH_SETTING_TYPE +{ + StringSettingType, + IntegerSettingType, + IntegerPairSettingType, + ScalableIntegerPairSettingType +} PH_SETTING_TYPE, PPH_SETTING_TYPE; +// end_phapppub + +typedef struct _PH_SETTING +{ + PH_SETTING_TYPE Type; + PH_STRINGREF Name; + PH_STRINGREF DefaultValue; + + union + { + PVOID Pointer; + ULONG Integer; + PH_INTEGER_PAIR IntegerPair; + } u; +} PH_SETTING, *PPH_SETTING; + +VOID PhSettingsInitialization( + VOID + ); + +VOID PhUpdateCachedSettings( + VOID + ); + +// begin_phapppub +_May_raise_ +PHAPPAPI +ULONG +NTAPI +PhGetIntegerSetting( + _In_ PWSTR Name + ); + +_May_raise_ +PHAPPAPI +PH_INTEGER_PAIR +NTAPI +PhGetIntegerPairSetting( + _In_ PWSTR Name + ); + +_May_raise_ +PHAPPAPI +PH_SCALABLE_INTEGER_PAIR +NTAPI +PhGetScalableIntegerPairSetting( + _In_ PWSTR Name, + _In_ BOOLEAN ScaleToCurrent + ); + +_May_raise_ +PHAPPAPI +PPH_STRING +NTAPI +PhGetStringSetting( + _In_ PWSTR Name + ); + +_May_raise_ +PHAPPAPI +VOID +NTAPI +PhSetIntegerSetting( + _In_ PWSTR Name, + _In_ ULONG Value + ); + +_May_raise_ +PHAPPAPI +VOID +NTAPI +PhSetIntegerPairSetting( + _In_ PWSTR Name, + _In_ PH_INTEGER_PAIR Value + ); + +_May_raise_ +PHAPPAPI +VOID +NTAPI +PhSetScalableIntegerPairSetting( + _In_ PWSTR Name, + _In_ PH_SCALABLE_INTEGER_PAIR Value + ); + +_May_raise_ +PHAPPAPI +VOID +NTAPI +PhSetScalableIntegerPairSetting2( + _In_ PWSTR Name, + _In_ PH_INTEGER_PAIR Value + ); + +_May_raise_ +PHAPPAPI +VOID +NTAPI +PhSetStringSetting( + _In_ PWSTR Name, + _In_ PWSTR Value + ); + +_May_raise_ +PHAPPAPI +VOID +NTAPI +PhSetStringSetting2( + _In_ PWSTR Name, + _In_ PPH_STRINGREF Value + ); +// end_phapppub + +VOID PhClearIgnoredSettings( + VOID + ); + +VOID PhConvertIgnoredSettings( + VOID + ); + +NTSTATUS PhLoadSettings( + _In_ PWSTR FileName + ); + +NTSTATUS PhSaveSettings( + _In_ PWSTR FileName + ); + +VOID PhResetSettings( + VOID + ); + +#define PhaGetStringSetting(Name) PH_AUTO_T(PH_STRING, PhGetStringSetting(Name)) // phapppub + +// begin_phapppub +// High-level settings creation + +typedef struct _PH_SETTING_CREATE +{ + PH_SETTING_TYPE Type; + PWSTR Name; + PWSTR DefaultValue; +} PH_SETTING_CREATE, *PPH_SETTING_CREATE; + +PHAPPAPI +VOID +NTAPI +PhAddSettings( + _In_ PPH_SETTING_CREATE Settings, + _In_ ULONG NumberOfSettings + ); +// end_phapppub + +// Cached settings + +#undef EXT + +#ifdef PH_SETTINGS_PRIVATE +#define EXT +#else +#define EXT extern +#endif + +EXT ULONG PhCsCollapseServicesOnStart; +EXT ULONG PhCsForceNoParent; +EXT ULONG PhCsHighlightingDuration; +EXT ULONG PhCsPropagateCpuUsage; +EXT ULONG PhCsScrollToNewProcesses; +EXT ULONG PhCsShowCpuBelow001; +EXT ULONG PhCsUpdateInterval; + +EXT ULONG PhCsColorNew; +EXT ULONG PhCsColorRemoved; +EXT ULONG PhCsUseColorOwnProcesses; +EXT ULONG PhCsColorOwnProcesses; +EXT ULONG PhCsUseColorSystemProcesses; +EXT ULONG PhCsColorSystemProcesses; +EXT ULONG PhCsUseColorServiceProcesses; +EXT ULONG PhCsColorServiceProcesses; +EXT ULONG PhCsUseColorJobProcesses; +EXT ULONG PhCsColorJobProcesses; +EXT ULONG PhCsUseColorWow64Processes; +EXT ULONG PhCsColorWow64Processes; +EXT ULONG PhCsUseColorDebuggedProcesses; +EXT ULONG PhCsColorDebuggedProcesses; +EXT ULONG PhCsUseColorElevatedProcesses; +EXT ULONG PhCsColorElevatedProcesses; +EXT ULONG PhCsUseColorPicoProcesses; +EXT ULONG PhCsColorPicoProcesses; +EXT ULONG PhCsUseColorImmersiveProcesses; +EXT ULONG PhCsColorImmersiveProcesses; +EXT ULONG PhCsUseColorSuspended; +EXT ULONG PhCsColorSuspended; +EXT ULONG PhCsUseColorDotNet; +EXT ULONG PhCsColorDotNet; +EXT ULONG PhCsUseColorPacked; +EXT ULONG PhCsColorPacked; +EXT ULONG PhCsUseColorGuiThreads; +EXT ULONG PhCsColorGuiThreads; +EXT ULONG PhCsUseColorRelocatedModules; +EXT ULONG PhCsColorRelocatedModules; +EXT ULONG PhCsUseColorProtectedHandles; +EXT ULONG PhCsColorProtectedHandles; +EXT ULONG PhCsUseColorInheritHandles; +EXT ULONG PhCsColorInheritHandles; +EXT ULONG PhCsGraphShowText; +EXT ULONG PhCsGraphColorMode; +EXT ULONG PhCsColorCpuKernel; +EXT ULONG PhCsColorCpuUser; +EXT ULONG PhCsColorIoReadOther; +EXT ULONG PhCsColorIoWrite; +EXT ULONG PhCsColorPrivate; +EXT ULONG PhCsColorPhysical; + +#define PH_SET_INTEGER_CACHED_SETTING(Name, Value) (PhSetIntegerSetting(L#Name, PhCs##Name = (Value))) + +#endif diff --git a/ProcessHacker/include/settingsp.h b/ProcessHacker/include/settingsp.h index 4d8350c8daa4..8b31daaaea08 100644 --- a/ProcessHacker/include/settingsp.h +++ b/ProcessHacker/include/settingsp.h @@ -1,46 +1,46 @@ -#ifndef PH_SETTINGSP_H -#define PH_SETTINGSP_H - -#include - -BOOLEAN NTAPI PhpSettingsHashtableEqualFunction( - _In_ PVOID Entry1, - _In_ PVOID Entry2 - ); - -ULONG NTAPI PhpSettingsHashtableHashFunction( - _In_ PVOID Entry - ); - -VOID PhpAddSetting( - _In_ PH_SETTING_TYPE Type, - _In_ PPH_STRINGREF Name, - _In_ PPH_STRINGREF DefaultValue - ); - -ULONG PhpGetCurrentScale( - VOID - ); - -PPH_STRING PhpSettingToString( - _In_ PH_SETTING_TYPE Type, - _In_ PPH_SETTING Setting - ); - -BOOLEAN PhpSettingFromString( - _In_ PH_SETTING_TYPE Type, - _In_ PPH_STRINGREF StringRef, - _In_opt_ PPH_STRING String, - _Inout_ PPH_SETTING Setting - ); - -VOID PhpFreeSettingValue( - _In_ PH_SETTING_TYPE Type, - _In_ PPH_SETTING Setting - ); - -PVOID PhpLookupSetting( - _In_ PPH_STRINGREF Name - ); - -#endif +#ifndef PH_SETTINGSP_H +#define PH_SETTINGSP_H + +#include + +BOOLEAN NTAPI PhpSettingsHashtableEqualFunction( + _In_ PVOID Entry1, + _In_ PVOID Entry2 + ); + +ULONG NTAPI PhpSettingsHashtableHashFunction( + _In_ PVOID Entry + ); + +VOID PhpAddSetting( + _In_ PH_SETTING_TYPE Type, + _In_ PPH_STRINGREF Name, + _In_ PPH_STRINGREF DefaultValue + ); + +ULONG PhpGetCurrentScale( + VOID + ); + +PPH_STRING PhpSettingToString( + _In_ PH_SETTING_TYPE Type, + _In_ PPH_SETTING Setting + ); + +BOOLEAN PhpSettingFromString( + _In_ PH_SETTING_TYPE Type, + _In_ PPH_STRINGREF StringRef, + _In_opt_ PPH_STRING String, + _Inout_ PPH_SETTING Setting + ); + +VOID PhpFreeSettingValue( + _In_ PH_SETTING_TYPE Type, + _In_ PPH_SETTING Setting + ); + +PVOID PhpLookupSetting( + _In_ PPH_STRINGREF Name + ); + +#endif diff --git a/ProcessHacker/include/sysinfo.h b/ProcessHacker/include/sysinfo.h index 88d2cf5fa8c4..89127b2a383d 100644 --- a/ProcessHacker/include/sysinfo.h +++ b/ProcessHacker/include/sysinfo.h @@ -1,164 +1,164 @@ -#ifndef PH_SYSINFO_H -#define PH_SYSINFO_H - -// begin_phapppub -typedef enum _PH_SYSINFO_VIEW_TYPE -{ - SysInfoSummaryView, - SysInfoSectionView -} PH_SYSINFO_VIEW_TYPE; - -typedef VOID (NTAPI *PPH_SYSINFO_COLOR_SETUP_FUNCTION)( - _Out_ PPH_GRAPH_DRAW_INFO DrawInfo, - _In_ COLORREF Color1, - _In_ COLORREF Color2 - ); - -typedef struct _PH_SYSINFO_PARAMETERS -{ - HWND SysInfoWindowHandle; - HWND ContainerWindowHandle; - - HFONT Font; - HFONT MediumFont; - HFONT LargeFont; - ULONG FontHeight; - ULONG FontAverageWidth; - ULONG MediumFontHeight; - ULONG MediumFontAverageWidth; - COLORREF GraphBackColor; - COLORREF PanelForeColor; - PPH_SYSINFO_COLOR_SETUP_FUNCTION ColorSetupFunction; - - ULONG MinimumGraphHeight; - ULONG SectionViewGraphHeight; - ULONG PanelWidth; -// end_phapppub - - ULONG PanelPadding; - ULONG WindowPadding; - ULONG GraphPadding; - ULONG SmallGraphWidth; - ULONG SmallGraphPadding; - ULONG SeparatorWidth; - ULONG CpuPadding; - ULONG MemoryPadding; -// begin_phapppub -} PH_SYSINFO_PARAMETERS, *PPH_SYSINFO_PARAMETERS; - -typedef enum _PH_SYSINFO_SECTION_MESSAGE -{ - SysInfoCreate, - SysInfoDestroy, - SysInfoTick, - SysInfoViewChanging, // PH_SYSINFO_VIEW_TYPE Parameter1, PPH_SYSINFO_SECTION Parameter2 - SysInfoCreateDialog, // PPH_SYSINFO_CREATE_DIALOG Parameter1 - SysInfoGraphGetDrawInfo, // PPH_GRAPH_DRAW_INFO Parameter1 - SysInfoGraphGetTooltipText, // PPH_SYSINFO_GRAPH_GET_TOOLTIP_TEXT Parameter1 - SysInfoGraphDrawPanel, // PPH_SYSINFO_DRAW_PANEL Parameter1 - MaxSysInfoMessage -} PH_SYSINFO_SECTION_MESSAGE; - -typedef BOOLEAN (NTAPI *PPH_SYSINFO_SECTION_CALLBACK)( - _In_ struct _PH_SYSINFO_SECTION *Section, - _In_ PH_SYSINFO_SECTION_MESSAGE Message, - _In_opt_ PVOID Parameter1, - _In_opt_ PVOID Parameter2 - ); - -typedef struct _PH_SYSINFO_CREATE_DIALOG -{ - BOOLEAN CustomCreate; - - // Parameters for default create - PVOID Instance; - PWSTR Template; - DLGPROC DialogProc; - PVOID Parameter; -} PH_SYSINFO_CREATE_DIALOG, *PPH_SYSINFO_CREATE_DIALOG; - -typedef struct _PH_SYSINFO_GRAPH_GET_TOOLTIP_TEXT -{ - ULONG Index; - PH_STRINGREF Text; -} PH_SYSINFO_GRAPH_GET_TOOLTIP_TEXT, *PPH_SYSINFO_GRAPH_GET_TOOLTIP_TEXT; - -typedef struct _PH_SYSINFO_DRAW_PANEL -{ - HDC hdc; - RECT Rect; - BOOLEAN CustomDraw; - - // Parameters for default draw - PPH_STRING Title; - PPH_STRING SubTitle; - PPH_STRING SubTitleOverflow; -} PH_SYSINFO_DRAW_PANEL, *PPH_SYSINFO_DRAW_PANEL; -// end_phapppub - -// begin_phapppub -typedef struct _PH_SYSINFO_SECTION -{ - // Public - - // Initialization - PH_STRINGREF Name; - ULONG Flags; - PPH_SYSINFO_SECTION_CALLBACK Callback; - PVOID Context; - PVOID Reserved[3]; - - // State - HWND GraphHandle; - PH_GRAPH_STATE GraphState; - PPH_SYSINFO_PARAMETERS Parameters; - PVOID Reserved2[3]; -// end_phapppub - - // Private - - struct - { - ULONG GraphHot : 1; - ULONG PanelHot : 1; - ULONG HasFocus : 1; - ULONG HideFocus : 1; - ULONG SpareFlags : 28; - }; - HWND DialogHandle; - HWND PanelHandle; - ULONG PanelId; -// begin_phapppub -} PH_SYSINFO_SECTION, *PPH_SYSINFO_SECTION; -// end_phapppub - -VOID PhSiNotifyChangeSettings( - VOID - ); - -// begin_phapppub -PHAPPAPI -VOID -NTAPI -PhSiSetColorsGraphDrawInfo( - _Out_ PPH_GRAPH_DRAW_INFO DrawInfo, - _In_ COLORREF Color1, - _In_ COLORREF Color2 - ); - -PHAPPAPI -PPH_STRING -NTAPI -PhSiSizeLabelYFunction( - _In_ PPH_GRAPH_DRAW_INFO DrawInfo, - _In_ ULONG DataIndex, - _In_ FLOAT Value, - _In_ FLOAT Parameter - ); -// end_phapppub - -VOID PhShowSystemInformationDialog( - _In_opt_ PWSTR SectionName - ); - +#ifndef PH_SYSINFO_H +#define PH_SYSINFO_H + +// begin_phapppub +typedef enum _PH_SYSINFO_VIEW_TYPE +{ + SysInfoSummaryView, + SysInfoSectionView +} PH_SYSINFO_VIEW_TYPE; + +typedef VOID (NTAPI *PPH_SYSINFO_COLOR_SETUP_FUNCTION)( + _Out_ PPH_GRAPH_DRAW_INFO DrawInfo, + _In_ COLORREF Color1, + _In_ COLORREF Color2 + ); + +typedef struct _PH_SYSINFO_PARAMETERS +{ + HWND SysInfoWindowHandle; + HWND ContainerWindowHandle; + + HFONT Font; + HFONT MediumFont; + HFONT LargeFont; + ULONG FontHeight; + ULONG FontAverageWidth; + ULONG MediumFontHeight; + ULONG MediumFontAverageWidth; + COLORREF GraphBackColor; + COLORREF PanelForeColor; + PPH_SYSINFO_COLOR_SETUP_FUNCTION ColorSetupFunction; + + ULONG MinimumGraphHeight; + ULONG SectionViewGraphHeight; + ULONG PanelWidth; +// end_phapppub + + ULONG PanelPadding; + ULONG WindowPadding; + ULONG GraphPadding; + ULONG SmallGraphWidth; + ULONG SmallGraphPadding; + ULONG SeparatorWidth; + ULONG CpuPadding; + ULONG MemoryPadding; +// begin_phapppub +} PH_SYSINFO_PARAMETERS, *PPH_SYSINFO_PARAMETERS; + +typedef enum _PH_SYSINFO_SECTION_MESSAGE +{ + SysInfoCreate, + SysInfoDestroy, + SysInfoTick, + SysInfoViewChanging, // PH_SYSINFO_VIEW_TYPE Parameter1, PPH_SYSINFO_SECTION Parameter2 + SysInfoCreateDialog, // PPH_SYSINFO_CREATE_DIALOG Parameter1 + SysInfoGraphGetDrawInfo, // PPH_GRAPH_DRAW_INFO Parameter1 + SysInfoGraphGetTooltipText, // PPH_SYSINFO_GRAPH_GET_TOOLTIP_TEXT Parameter1 + SysInfoGraphDrawPanel, // PPH_SYSINFO_DRAW_PANEL Parameter1 + MaxSysInfoMessage +} PH_SYSINFO_SECTION_MESSAGE; + +typedef BOOLEAN (NTAPI *PPH_SYSINFO_SECTION_CALLBACK)( + _In_ struct _PH_SYSINFO_SECTION *Section, + _In_ PH_SYSINFO_SECTION_MESSAGE Message, + _In_opt_ PVOID Parameter1, + _In_opt_ PVOID Parameter2 + ); + +typedef struct _PH_SYSINFO_CREATE_DIALOG +{ + BOOLEAN CustomCreate; + + // Parameters for default create + PVOID Instance; + PWSTR Template; + DLGPROC DialogProc; + PVOID Parameter; +} PH_SYSINFO_CREATE_DIALOG, *PPH_SYSINFO_CREATE_DIALOG; + +typedef struct _PH_SYSINFO_GRAPH_GET_TOOLTIP_TEXT +{ + ULONG Index; + PH_STRINGREF Text; +} PH_SYSINFO_GRAPH_GET_TOOLTIP_TEXT, *PPH_SYSINFO_GRAPH_GET_TOOLTIP_TEXT; + +typedef struct _PH_SYSINFO_DRAW_PANEL +{ + HDC hdc; + RECT Rect; + BOOLEAN CustomDraw; + + // Parameters for default draw + PPH_STRING Title; + PPH_STRING SubTitle; + PPH_STRING SubTitleOverflow; +} PH_SYSINFO_DRAW_PANEL, *PPH_SYSINFO_DRAW_PANEL; +// end_phapppub + +// begin_phapppub +typedef struct _PH_SYSINFO_SECTION +{ + // Public + + // Initialization + PH_STRINGREF Name; + ULONG Flags; + PPH_SYSINFO_SECTION_CALLBACK Callback; + PVOID Context; + PVOID Reserved[3]; + + // State + HWND GraphHandle; + PH_GRAPH_STATE GraphState; + PPH_SYSINFO_PARAMETERS Parameters; + PVOID Reserved2[3]; +// end_phapppub + + // Private + + struct + { + ULONG GraphHot : 1; + ULONG PanelHot : 1; + ULONG HasFocus : 1; + ULONG HideFocus : 1; + ULONG SpareFlags : 28; + }; + HWND DialogHandle; + HWND PanelHandle; + ULONG PanelId; +// begin_phapppub +} PH_SYSINFO_SECTION, *PPH_SYSINFO_SECTION; +// end_phapppub + +VOID PhSiNotifyChangeSettings( + VOID + ); + +// begin_phapppub +PHAPPAPI +VOID +NTAPI +PhSiSetColorsGraphDrawInfo( + _Out_ PPH_GRAPH_DRAW_INFO DrawInfo, + _In_ COLORREF Color1, + _In_ COLORREF Color2 + ); + +PHAPPAPI +PPH_STRING +NTAPI +PhSiSizeLabelYFunction( + _In_ PPH_GRAPH_DRAW_INFO DrawInfo, + _In_ ULONG DataIndex, + _In_ FLOAT Value, + _In_ FLOAT Parameter + ); +// end_phapppub + +VOID PhShowSystemInformationDialog( + _In_opt_ PWSTR SectionName + ); + #endif \ No newline at end of file diff --git a/ProcessHacker/include/sysinfop.h b/ProcessHacker/include/sysinfop.h index 01897f9ce828..261c23151325 100644 --- a/ProcessHacker/include/sysinfop.h +++ b/ProcessHacker/include/sysinfop.h @@ -1,439 +1,439 @@ -#ifndef PH_SYSINFOP_H -#define PH_SYSINFOP_H - -// Constants - -#define PH_SYSINFO_FADE_ADD 50 -#define PH_SYSINFO_PANEL_PADDING 3 -#define PH_SYSINFO_WINDOW_PADDING 13 -#define PH_SYSINFO_GRAPH_PADDING 9 -#define PH_SYSINFO_SMALL_GRAPH_WIDTH 48 -#define PH_SYSINFO_SMALL_GRAPH_PADDING 5 -#define PH_SYSINFO_SEPARATOR_WIDTH 2 - -#define PH_SYSINFO_CPU_PADDING 5 -#define PH_SYSINFO_MEMORY_PADDING 3 - -#define SI_MSG_SYSINFO_FIRST (WM_APP + 150) -#define SI_MSG_SYSINFO_ACTIVATE (WM_APP + 150) -#define SI_MSG_SYSINFO_UPDATE (WM_APP + 151) -#define SI_MSG_SYSINFO_CHANGE_SETTINGS (WM_APP + 152) -#define SI_MSG_SYSINFO_LAST (WM_APP + 152) - -// Thread & window - -extern HWND PhSipWindow; - -NTSTATUS PhSipSysInfoThreadStart( - _In_ PVOID Parameter - ); - -INT_PTR CALLBACK PhSipSysInfoDialogProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -INT_PTR CALLBACK PhSipContainerDialogProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -// Event handlers - -VOID PhSipOnInitDialog( - VOID - ); - -VOID PhSipOnDestroy( - VOID - ); - -VOID PhSipOnNcDestroy( - VOID - ); - -VOID PhSipOnShowWindow( - _In_ BOOLEAN Showing, - _In_ ULONG State - ); - -BOOLEAN PhSipOnSysCommand( - _In_ ULONG Type, - _In_ LONG CursorScreenX, - _In_ LONG CursorScreenY - ); - -VOID PhSipOnSize( - VOID - ); - -VOID PhSipOnSizing( - _In_ ULONG Edge, - _In_ PRECT DragRectangle - ); - -VOID PhSipOnThemeChanged( - VOID - ); - -VOID PhSipOnCommand( - _In_ ULONG Id, - _In_ ULONG Code - ); - -BOOLEAN PhSipOnNotify( - _In_ NMHDR *Header, - _Out_ LRESULT *Result - ); - -BOOLEAN PhSipOnDrawItem( - _In_ ULONG_PTR Id, - _In_ DRAWITEMSTRUCT *DrawItemStruct - ); - -VOID PhSipOnUserMessage( - _In_ ULONG Message, - _In_ ULONG_PTR WParam, - _In_ ULONG_PTR LParam - ); - -// Framework - -VOID PhSipRegisterDialog( - _In_ HWND DialogWindowHandle - ); - -VOID PhSipUnregisterDialog( - _In_ HWND DialogWindowHandle - ); - -VOID PhSipInitializeParameters( - VOID - ); - -VOID PhSipDeleteParameters( - VOID - ); - -VOID PhSipUpdateColorParameters( - VOID - ); - -PPH_SYSINFO_SECTION PhSipCreateSection( - _In_ PPH_SYSINFO_SECTION Template - ); - -VOID PhSipDestroySection( - _In_ PPH_SYSINFO_SECTION Section - ); - -PPH_SYSINFO_SECTION PhSipFindSection( - _In_ PPH_STRINGREF Name - ); - -PPH_SYSINFO_SECTION PhSipCreateInternalSection( - _In_ PWSTR Name, - _In_ ULONG Flags, - _In_ PPH_SYSINFO_SECTION_CALLBACK Callback - ); - -VOID PhSipDrawRestoreSummaryPanel( - _In_ HDC hdc, - _In_ PRECT Rect - ); - -VOID PhSipDrawSeparator( - _In_ HDC hdc, - _In_ PRECT Rect - ); - -VOID PhSipDrawPanel( - _In_ PPH_SYSINFO_SECTION Section, - _In_ HDC hdc, - _In_ PRECT Rect - ); - -VOID PhSipDefaultDrawPanel( - _In_ PPH_SYSINFO_SECTION Section, - _In_ PPH_SYSINFO_DRAW_PANEL DrawPanel - ); - -VOID PhSipLayoutSummaryView( - VOID - ); - -VOID PhSipLayoutSectionView( - VOID - ); - -VOID PhSipEnterSectionView( - _In_ PPH_SYSINFO_SECTION NewSection - ); - -VOID PhSipEnterSectionViewInner( - _In_ PPH_SYSINFO_SECTION Section, - _In_ BOOLEAN FromSummaryView, - _Inout_ HDWP *DeferHandle, - _Inout_ HDWP *ContainerDeferHandle - ); - -VOID PhSipRestoreSummaryView( - VOID - ); - -VOID PhSipCreateSectionDialog( - _In_ PPH_SYSINFO_SECTION Section - ); - -LRESULT CALLBACK PhSipGraphHookWndProc( - _In_ HWND hwnd, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam, - _In_ UINT_PTR uIdSubclass, - _In_ ULONG_PTR dwRefData - ); - -LRESULT CALLBACK PhSipPanelHookWndProc( - _In_ HWND hwnd, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam, - _In_ UINT_PTR uIdSubclass, - _In_ ULONG_PTR dwRefData - ); - -// Misc. - -VOID PhSipUpdateThemeData( - VOID - ); - -VOID PhSipSetAlwaysOnTop( - VOID - ); - -VOID PhSipSaveWindowState( - VOID - ); - -VOID NTAPI PhSipSysInfoUpdateHandler( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ); - -PPH_STRING PhSipFormatSizeWithPrecision( - _In_ ULONG64 Size, - _In_ USHORT Precision - ); - -// CPU section - -typedef struct _SYSTEM_PROCESSOR_PERFORMANCE_HITCOUNT_WIN8 -{ - ULONG Hits; - UCHAR PercentFrequency; -} SYSTEM_PROCESSOR_PERFORMANCE_HITCOUNT_WIN8, *PSYSTEM_PROCESSOR_PERFORMANCE_HITCOUNT_WIN8; - -BOOLEAN PhSipCpuSectionCallback( - _In_ PPH_SYSINFO_SECTION Section, - _In_ PH_SYSINFO_SECTION_MESSAGE Message, - _In_opt_ PVOID Parameter1, - _In_opt_ PVOID Parameter2 - ); - -VOID PhSipInitializeCpuDialog( - VOID - ); - -VOID PhSipUninitializeCpuDialog( - VOID - ); - -VOID PhSipTickCpuDialog( - VOID - ); - -INT_PTR CALLBACK PhSipCpuDialogProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -INT_PTR CALLBACK PhSipCpuPanelDialogProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -VOID PhSipCreateCpuGraphs( - VOID - ); - -VOID PhSipLayoutCpuGraphs( - VOID - ); - -VOID PhSipSetOneGraphPerCpu( - VOID - ); - -VOID PhSipNotifyCpuGraph( - _In_ ULONG Index, - _In_ NMHDR *Header - ); - -VOID PhSipUpdateCpuGraphs( - VOID - ); - -VOID PhSipUpdateCpuPanel( - VOID - ); - -PPH_PROCESS_RECORD PhSipReferenceMaxCpuRecord( - _In_ LONG Index - ); - -PPH_STRING PhSipGetMaxCpuString( - _In_ LONG Index - ); - -VOID PhSipGetCpuBrandString( - _Out_writes_(49) PWSTR BrandString - ); - -BOOLEAN PhSipGetCpuFrequencyFromDistribution( - _Out_ DOUBLE *Fraction - ); - -NTSTATUS PhSipQueryProcessorPerformanceDistribution( - _Out_ PVOID *Buffer - ); - -// Memory section - -BOOLEAN PhSipMemorySectionCallback( - _In_ PPH_SYSINFO_SECTION Section, - _In_ PH_SYSINFO_SECTION_MESSAGE Message, - _In_opt_ PVOID Parameter1, - _In_opt_ PVOID Parameter2 - ); - -VOID PhSipInitializeMemoryDialog( - VOID - ); - -VOID PhSipUninitializeMemoryDialog( - VOID - ); - -VOID PhSipTickMemoryDialog( - VOID - ); - -INT_PTR CALLBACK PhSipMemoryDialogProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -INT_PTR CALLBACK PhSipMemoryPanelDialogProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -VOID PhSipLayoutMemoryGraphs( - VOID - ); - -VOID PhSipNotifyCommitGraph( - _In_ NMHDR *Header - ); - -VOID PhSipNotifyPhysicalGraph( - _In_ NMHDR *Header - ); - -VOID PhSipUpdateMemoryGraphs( - VOID - ); - -VOID PhSipUpdateMemoryPanel( - VOID - ); - -NTSTATUS PhSipLoadMmAddresses( - _In_ PVOID Parameter - ); - -VOID PhSipGetPoolLimits( - _Out_ PSIZE_T Paged, - _Out_ PSIZE_T NonPaged - ); - -// I/O section - -BOOLEAN PhSipIoSectionCallback( - _In_ PPH_SYSINFO_SECTION Section, - _In_ PH_SYSINFO_SECTION_MESSAGE Message, - _In_opt_ PVOID Parameter1, - _In_opt_ PVOID Parameter2 - ); - -VOID PhSipInitializeIoDialog( - VOID - ); - -VOID PhSipUninitializeIoDialog( - VOID - ); - -VOID PhSipTickIoDialog( - VOID - ); - -INT_PTR CALLBACK PhSipIoDialogProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -INT_PTR CALLBACK PhSipIoPanelDialogProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -VOID PhSipNotifyIoGraph( - _In_ NMHDR *Header - ); - -VOID PhSipUpdateIoGraph( - VOID - ); - -VOID PhSipUpdateIoPanel( - VOID - ); - -PPH_PROCESS_RECORD PhSipReferenceMaxIoRecord( - _In_ LONG Index - ); - -PPH_STRING PhSipGetMaxIoString( - _In_ LONG Index - ); - -#endif +#ifndef PH_SYSINFOP_H +#define PH_SYSINFOP_H + +// Constants + +#define PH_SYSINFO_FADE_ADD 50 +#define PH_SYSINFO_PANEL_PADDING 3 +#define PH_SYSINFO_WINDOW_PADDING 13 +#define PH_SYSINFO_GRAPH_PADDING 9 +#define PH_SYSINFO_SMALL_GRAPH_WIDTH 48 +#define PH_SYSINFO_SMALL_GRAPH_PADDING 5 +#define PH_SYSINFO_SEPARATOR_WIDTH 2 + +#define PH_SYSINFO_CPU_PADDING 5 +#define PH_SYSINFO_MEMORY_PADDING 3 + +#define SI_MSG_SYSINFO_FIRST (WM_APP + 150) +#define SI_MSG_SYSINFO_ACTIVATE (WM_APP + 150) +#define SI_MSG_SYSINFO_UPDATE (WM_APP + 151) +#define SI_MSG_SYSINFO_CHANGE_SETTINGS (WM_APP + 152) +#define SI_MSG_SYSINFO_LAST (WM_APP + 152) + +// Thread & window + +extern HWND PhSipWindow; + +NTSTATUS PhSipSysInfoThreadStart( + _In_ PVOID Parameter + ); + +INT_PTR CALLBACK PhSipSysInfoDialogProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +INT_PTR CALLBACK PhSipContainerDialogProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +// Event handlers + +VOID PhSipOnInitDialog( + VOID + ); + +VOID PhSipOnDestroy( + VOID + ); + +VOID PhSipOnNcDestroy( + VOID + ); + +VOID PhSipOnShowWindow( + _In_ BOOLEAN Showing, + _In_ ULONG State + ); + +BOOLEAN PhSipOnSysCommand( + _In_ ULONG Type, + _In_ LONG CursorScreenX, + _In_ LONG CursorScreenY + ); + +VOID PhSipOnSize( + VOID + ); + +VOID PhSipOnSizing( + _In_ ULONG Edge, + _In_ PRECT DragRectangle + ); + +VOID PhSipOnThemeChanged( + VOID + ); + +VOID PhSipOnCommand( + _In_ ULONG Id, + _In_ ULONG Code + ); + +BOOLEAN PhSipOnNotify( + _In_ NMHDR *Header, + _Out_ LRESULT *Result + ); + +BOOLEAN PhSipOnDrawItem( + _In_ ULONG_PTR Id, + _In_ DRAWITEMSTRUCT *DrawItemStruct + ); + +VOID PhSipOnUserMessage( + _In_ ULONG Message, + _In_ ULONG_PTR WParam, + _In_ ULONG_PTR LParam + ); + +// Framework + +VOID PhSipRegisterDialog( + _In_ HWND DialogWindowHandle + ); + +VOID PhSipUnregisterDialog( + _In_ HWND DialogWindowHandle + ); + +VOID PhSipInitializeParameters( + VOID + ); + +VOID PhSipDeleteParameters( + VOID + ); + +VOID PhSipUpdateColorParameters( + VOID + ); + +PPH_SYSINFO_SECTION PhSipCreateSection( + _In_ PPH_SYSINFO_SECTION Template + ); + +VOID PhSipDestroySection( + _In_ PPH_SYSINFO_SECTION Section + ); + +PPH_SYSINFO_SECTION PhSipFindSection( + _In_ PPH_STRINGREF Name + ); + +PPH_SYSINFO_SECTION PhSipCreateInternalSection( + _In_ PWSTR Name, + _In_ ULONG Flags, + _In_ PPH_SYSINFO_SECTION_CALLBACK Callback + ); + +VOID PhSipDrawRestoreSummaryPanel( + _In_ HDC hdc, + _In_ PRECT Rect + ); + +VOID PhSipDrawSeparator( + _In_ HDC hdc, + _In_ PRECT Rect + ); + +VOID PhSipDrawPanel( + _In_ PPH_SYSINFO_SECTION Section, + _In_ HDC hdc, + _In_ PRECT Rect + ); + +VOID PhSipDefaultDrawPanel( + _In_ PPH_SYSINFO_SECTION Section, + _In_ PPH_SYSINFO_DRAW_PANEL DrawPanel + ); + +VOID PhSipLayoutSummaryView( + VOID + ); + +VOID PhSipLayoutSectionView( + VOID + ); + +VOID PhSipEnterSectionView( + _In_ PPH_SYSINFO_SECTION NewSection + ); + +VOID PhSipEnterSectionViewInner( + _In_ PPH_SYSINFO_SECTION Section, + _In_ BOOLEAN FromSummaryView, + _Inout_ HDWP *DeferHandle, + _Inout_ HDWP *ContainerDeferHandle + ); + +VOID PhSipRestoreSummaryView( + VOID + ); + +VOID PhSipCreateSectionDialog( + _In_ PPH_SYSINFO_SECTION Section + ); + +LRESULT CALLBACK PhSipGraphHookWndProc( + _In_ HWND hwnd, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam, + _In_ UINT_PTR uIdSubclass, + _In_ ULONG_PTR dwRefData + ); + +LRESULT CALLBACK PhSipPanelHookWndProc( + _In_ HWND hwnd, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam, + _In_ UINT_PTR uIdSubclass, + _In_ ULONG_PTR dwRefData + ); + +// Misc. + +VOID PhSipUpdateThemeData( + VOID + ); + +VOID PhSipSetAlwaysOnTop( + VOID + ); + +VOID PhSipSaveWindowState( + VOID + ); + +VOID NTAPI PhSipSysInfoUpdateHandler( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ); + +PPH_STRING PhSipFormatSizeWithPrecision( + _In_ ULONG64 Size, + _In_ USHORT Precision + ); + +// CPU section + +typedef struct _SYSTEM_PROCESSOR_PERFORMANCE_HITCOUNT_WIN8 +{ + ULONG Hits; + UCHAR PercentFrequency; +} SYSTEM_PROCESSOR_PERFORMANCE_HITCOUNT_WIN8, *PSYSTEM_PROCESSOR_PERFORMANCE_HITCOUNT_WIN8; + +BOOLEAN PhSipCpuSectionCallback( + _In_ PPH_SYSINFO_SECTION Section, + _In_ PH_SYSINFO_SECTION_MESSAGE Message, + _In_opt_ PVOID Parameter1, + _In_opt_ PVOID Parameter2 + ); + +VOID PhSipInitializeCpuDialog( + VOID + ); + +VOID PhSipUninitializeCpuDialog( + VOID + ); + +VOID PhSipTickCpuDialog( + VOID + ); + +INT_PTR CALLBACK PhSipCpuDialogProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +INT_PTR CALLBACK PhSipCpuPanelDialogProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +VOID PhSipCreateCpuGraphs( + VOID + ); + +VOID PhSipLayoutCpuGraphs( + VOID + ); + +VOID PhSipSetOneGraphPerCpu( + VOID + ); + +VOID PhSipNotifyCpuGraph( + _In_ ULONG Index, + _In_ NMHDR *Header + ); + +VOID PhSipUpdateCpuGraphs( + VOID + ); + +VOID PhSipUpdateCpuPanel( + VOID + ); + +PPH_PROCESS_RECORD PhSipReferenceMaxCpuRecord( + _In_ LONG Index + ); + +PPH_STRING PhSipGetMaxCpuString( + _In_ LONG Index + ); + +VOID PhSipGetCpuBrandString( + _Out_writes_(49) PWSTR BrandString + ); + +BOOLEAN PhSipGetCpuFrequencyFromDistribution( + _Out_ DOUBLE *Fraction + ); + +NTSTATUS PhSipQueryProcessorPerformanceDistribution( + _Out_ PVOID *Buffer + ); + +// Memory section + +BOOLEAN PhSipMemorySectionCallback( + _In_ PPH_SYSINFO_SECTION Section, + _In_ PH_SYSINFO_SECTION_MESSAGE Message, + _In_opt_ PVOID Parameter1, + _In_opt_ PVOID Parameter2 + ); + +VOID PhSipInitializeMemoryDialog( + VOID + ); + +VOID PhSipUninitializeMemoryDialog( + VOID + ); + +VOID PhSipTickMemoryDialog( + VOID + ); + +INT_PTR CALLBACK PhSipMemoryDialogProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +INT_PTR CALLBACK PhSipMemoryPanelDialogProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +VOID PhSipLayoutMemoryGraphs( + VOID + ); + +VOID PhSipNotifyCommitGraph( + _In_ NMHDR *Header + ); + +VOID PhSipNotifyPhysicalGraph( + _In_ NMHDR *Header + ); + +VOID PhSipUpdateMemoryGraphs( + VOID + ); + +VOID PhSipUpdateMemoryPanel( + VOID + ); + +NTSTATUS PhSipLoadMmAddresses( + _In_ PVOID Parameter + ); + +VOID PhSipGetPoolLimits( + _Out_ PSIZE_T Paged, + _Out_ PSIZE_T NonPaged + ); + +// I/O section + +BOOLEAN PhSipIoSectionCallback( + _In_ PPH_SYSINFO_SECTION Section, + _In_ PH_SYSINFO_SECTION_MESSAGE Message, + _In_opt_ PVOID Parameter1, + _In_opt_ PVOID Parameter2 + ); + +VOID PhSipInitializeIoDialog( + VOID + ); + +VOID PhSipUninitializeIoDialog( + VOID + ); + +VOID PhSipTickIoDialog( + VOID + ); + +INT_PTR CALLBACK PhSipIoDialogProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +INT_PTR CALLBACK PhSipIoPanelDialogProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +VOID PhSipNotifyIoGraph( + _In_ NMHDR *Header + ); + +VOID PhSipUpdateIoGraph( + VOID + ); + +VOID PhSipUpdateIoPanel( + VOID + ); + +PPH_PROCESS_RECORD PhSipReferenceMaxIoRecord( + _In_ LONG Index + ); + +PPH_STRING PhSipGetMaxIoString( + _In_ LONG Index + ); + +#endif diff --git a/ProcessHacker/infodlg.c b/ProcessHacker/infodlg.c index 10584a25dfc1..41947bfe8f86 100644 --- a/ProcessHacker/infodlg.c +++ b/ProcessHacker/infodlg.c @@ -1,215 +1,215 @@ -/* - * Process Hacker - - * information dialog - * - * Copyright (C) 2010 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include - -#include - -typedef struct _INFORMATION_CONTEXT -{ - PWSTR String; - ULONG Flags; -} INFORMATION_CONTEXT, *PINFORMATION_CONTEXT; - -static RECT MinimumSize = { -1, -1, -1, -1 }; - -static INT_PTR CALLBACK PhpInformationDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - switch (uMsg) - { - case WM_INITDIALOG: - { - PINFORMATION_CONTEXT context = (PINFORMATION_CONTEXT)lParam; - PPH_LAYOUT_MANAGER layoutManager; - - PhCenterWindow(hwndDlg, GetParent(hwndDlg)); - - SetDlgItemText(hwndDlg, IDC_TEXT, context->String); - - layoutManager = PhAllocate(sizeof(PH_LAYOUT_MANAGER)); - PhInitializeLayoutManager(layoutManager, hwndDlg); - PhAddLayoutItem(layoutManager, GetDlgItem(hwndDlg, IDC_TEXT), NULL, - PH_ANCHOR_ALL); - PhAddLayoutItem(layoutManager, GetDlgItem(hwndDlg, IDOK), NULL, - PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); - PhAddLayoutItem(layoutManager, GetDlgItem(hwndDlg, IDC_COPY), NULL, - PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); - PhAddLayoutItem(layoutManager, GetDlgItem(hwndDlg, IDC_SAVE), NULL, - PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); - - if (MinimumSize.left == -1) - { - RECT rect; - - rect.left = 0; - rect.top = 0; - rect.right = 200; - rect.bottom = 140; - MapDialogRect(hwndDlg, &rect); - MinimumSize = rect; - MinimumSize.left = 0; - } - - SetProp(hwndDlg, L"LayoutManager", (HANDLE)layoutManager); - SetProp(hwndDlg, L"String", (HANDLE)context->String); - - SendMessage(hwndDlg, WM_NEXTDLGCTL, (LPARAM)GetDlgItem(hwndDlg, IDOK), TRUE); - } - break; - case WM_DESTROY: - { - PPH_LAYOUT_MANAGER layoutManager; - - layoutManager = (PPH_LAYOUT_MANAGER)GetProp(hwndDlg, L"LayoutManager"); - PhDeleteLayoutManager(layoutManager); - PhFree(layoutManager); - RemoveProp(hwndDlg, L"String"); - RemoveProp(hwndDlg, L"LayoutManager"); - } - break; - case WM_COMMAND: - { - switch (LOWORD(wParam)) - { - case IDCANCEL: - case IDOK: - EndDialog(hwndDlg, IDOK); - break; - case IDC_COPY: - { - HWND editControl; - LONG selStart; - LONG selEnd; - PWSTR buffer; - PH_STRINGREF string; - - editControl = GetDlgItem(hwndDlg, IDC_TEXT); - SendMessage(editControl, EM_GETSEL, (WPARAM)&selStart, (LPARAM)&selEnd); - buffer = (PWSTR)GetProp(hwndDlg, L"String"); - - if (selStart == selEnd) - { - // Select and copy the entire string. - PhInitializeStringRefLongHint(&string, buffer); - Edit_SetSel(editControl, 0, -1); - } - else - { - string.Buffer = buffer + selStart; - string.Length = (selEnd - selStart) * 2; - } - - PhSetClipboardString(hwndDlg, &string); - SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)editControl, TRUE); - } - break; - case IDC_SAVE: - { - static PH_FILETYPE_FILTER filters[] = - { - { L"Text files (*.txt)", L"*.txt" }, - { L"All files (*.*)", L"*.*" } - }; - PVOID fileDialog; - - fileDialog = PhCreateSaveFileDialog(); - - PhSetFileDialogFilter(fileDialog, filters, sizeof(filters) / sizeof(PH_FILETYPE_FILTER)); - PhSetFileDialogFileName(fileDialog, L"Information.txt"); - - if (PhShowFileDialog(hwndDlg, fileDialog)) - { - NTSTATUS status; - PPH_STRING fileName; - PPH_FILE_STREAM fileStream; - - fileName = PH_AUTO(PhGetFileDialogFileName(fileDialog)); - - if (NT_SUCCESS(status = PhCreateFileStream( - &fileStream, - fileName->Buffer, - FILE_GENERIC_WRITE, - FILE_SHARE_READ, - FILE_OVERWRITE_IF, - 0 - ))) - { - PH_STRINGREF string; - - PhWriteStringAsUtf8FileStream(fileStream, &PhUnicodeByteOrderMark); - PhInitializeStringRef(&string, (PWSTR)GetProp(hwndDlg, L"String")); - PhWriteStringAsUtf8FileStream(fileStream, &string); - PhDereferenceObject(fileStream); - } - - if (!NT_SUCCESS(status)) - PhShowStatus(hwndDlg, L"Unable to create the file", status, 0); - } - - PhFreeFileDialog(fileDialog); - } - break; - } - } - break; - case WM_SIZE: - { - PPH_LAYOUT_MANAGER layoutManager; - - layoutManager = (PPH_LAYOUT_MANAGER)GetProp(hwndDlg, L"LayoutManager"); - PhLayoutManagerLayout(layoutManager); - } - break; - case WM_SIZING: - { - PhResizingMinimumSize((PRECT)lParam, wParam, MinimumSize.right, MinimumSize.bottom); - } - break; - } - - return FALSE; -} - -VOID PhShowInformationDialog( - _In_ HWND ParentWindowHandle, - _In_ PWSTR String, - _Reserved_ ULONG Flags - ) -{ - INFORMATION_CONTEXT context; - - context.String = String; - context.Flags = Flags; - - DialogBoxParam( - PhInstanceHandle, - MAKEINTRESOURCE(IDD_INFORMATION), - ParentWindowHandle, - PhpInformationDlgProc, - (LPARAM)&context - ); -} +/* + * Process Hacker - + * information dialog + * + * Copyright (C) 2010 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include + +#include + +typedef struct _INFORMATION_CONTEXT +{ + PWSTR String; + ULONG Flags; +} INFORMATION_CONTEXT, *PINFORMATION_CONTEXT; + +static RECT MinimumSize = { -1, -1, -1, -1 }; + +static INT_PTR CALLBACK PhpInformationDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + switch (uMsg) + { + case WM_INITDIALOG: + { + PINFORMATION_CONTEXT context = (PINFORMATION_CONTEXT)lParam; + PPH_LAYOUT_MANAGER layoutManager; + + PhCenterWindow(hwndDlg, GetParent(hwndDlg)); + + SetDlgItemText(hwndDlg, IDC_TEXT, context->String); + + layoutManager = PhAllocate(sizeof(PH_LAYOUT_MANAGER)); + PhInitializeLayoutManager(layoutManager, hwndDlg); + PhAddLayoutItem(layoutManager, GetDlgItem(hwndDlg, IDC_TEXT), NULL, + PH_ANCHOR_ALL); + PhAddLayoutItem(layoutManager, GetDlgItem(hwndDlg, IDOK), NULL, + PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); + PhAddLayoutItem(layoutManager, GetDlgItem(hwndDlg, IDC_COPY), NULL, + PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); + PhAddLayoutItem(layoutManager, GetDlgItem(hwndDlg, IDC_SAVE), NULL, + PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); + + if (MinimumSize.left == -1) + { + RECT rect; + + rect.left = 0; + rect.top = 0; + rect.right = 200; + rect.bottom = 140; + MapDialogRect(hwndDlg, &rect); + MinimumSize = rect; + MinimumSize.left = 0; + } + + SetProp(hwndDlg, L"LayoutManager", (HANDLE)layoutManager); + SetProp(hwndDlg, L"String", (HANDLE)context->String); + + SendMessage(hwndDlg, WM_NEXTDLGCTL, (LPARAM)GetDlgItem(hwndDlg, IDOK), TRUE); + } + break; + case WM_DESTROY: + { + PPH_LAYOUT_MANAGER layoutManager; + + layoutManager = (PPH_LAYOUT_MANAGER)GetProp(hwndDlg, L"LayoutManager"); + PhDeleteLayoutManager(layoutManager); + PhFree(layoutManager); + RemoveProp(hwndDlg, L"String"); + RemoveProp(hwndDlg, L"LayoutManager"); + } + break; + case WM_COMMAND: + { + switch (LOWORD(wParam)) + { + case IDCANCEL: + case IDOK: + EndDialog(hwndDlg, IDOK); + break; + case IDC_COPY: + { + HWND editControl; + LONG selStart; + LONG selEnd; + PWSTR buffer; + PH_STRINGREF string; + + editControl = GetDlgItem(hwndDlg, IDC_TEXT); + SendMessage(editControl, EM_GETSEL, (WPARAM)&selStart, (LPARAM)&selEnd); + buffer = (PWSTR)GetProp(hwndDlg, L"String"); + + if (selStart == selEnd) + { + // Select and copy the entire string. + PhInitializeStringRefLongHint(&string, buffer); + Edit_SetSel(editControl, 0, -1); + } + else + { + string.Buffer = buffer + selStart; + string.Length = (selEnd - selStart) * 2; + } + + PhSetClipboardString(hwndDlg, &string); + SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)editControl, TRUE); + } + break; + case IDC_SAVE: + { + static PH_FILETYPE_FILTER filters[] = + { + { L"Text files (*.txt)", L"*.txt" }, + { L"All files (*.*)", L"*.*" } + }; + PVOID fileDialog; + + fileDialog = PhCreateSaveFileDialog(); + + PhSetFileDialogFilter(fileDialog, filters, sizeof(filters) / sizeof(PH_FILETYPE_FILTER)); + PhSetFileDialogFileName(fileDialog, L"Information.txt"); + + if (PhShowFileDialog(hwndDlg, fileDialog)) + { + NTSTATUS status; + PPH_STRING fileName; + PPH_FILE_STREAM fileStream; + + fileName = PH_AUTO(PhGetFileDialogFileName(fileDialog)); + + if (NT_SUCCESS(status = PhCreateFileStream( + &fileStream, + fileName->Buffer, + FILE_GENERIC_WRITE, + FILE_SHARE_READ, + FILE_OVERWRITE_IF, + 0 + ))) + { + PH_STRINGREF string; + + PhWriteStringAsUtf8FileStream(fileStream, &PhUnicodeByteOrderMark); + PhInitializeStringRef(&string, (PWSTR)GetProp(hwndDlg, L"String")); + PhWriteStringAsUtf8FileStream(fileStream, &string); + PhDereferenceObject(fileStream); + } + + if (!NT_SUCCESS(status)) + PhShowStatus(hwndDlg, L"Unable to create the file", status, 0); + } + + PhFreeFileDialog(fileDialog); + } + break; + } + } + break; + case WM_SIZE: + { + PPH_LAYOUT_MANAGER layoutManager; + + layoutManager = (PPH_LAYOUT_MANAGER)GetProp(hwndDlg, L"LayoutManager"); + PhLayoutManagerLayout(layoutManager); + } + break; + case WM_SIZING: + { + PhResizingMinimumSize((PRECT)lParam, wParam, MinimumSize.right, MinimumSize.bottom); + } + break; + } + + return FALSE; +} + +VOID PhShowInformationDialog( + _In_ HWND ParentWindowHandle, + _In_ PWSTR String, + _Reserved_ ULONG Flags + ) +{ + INFORMATION_CONTEXT context; + + context.String = String; + context.Flags = Flags; + + DialogBoxParam( + PhInstanceHandle, + MAKEINTRESOURCE(IDD_INFORMATION), + ParentWindowHandle, + PhpInformationDlgProc, + (LPARAM)&context + ); +} diff --git a/ProcessHacker/itemtips.c b/ProcessHacker/itemtips.c index 184cdb7c2239..318592248aaf 100644 --- a/ProcessHacker/itemtips.c +++ b/ProcessHacker/itemtips.c @@ -1,704 +1,704 @@ -/* - * Process Hacker - - * item tooltips - * - * Copyright (C) 2010-2015 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include - -#define CINTERFACE -#define COBJMACROS -#include - -#include -#include - -#include -#include -#include - -VOID PhpFillUmdfDrivers( - _In_ PPH_PROCESS_ITEM Process, - _Inout_ PPH_STRING_BUILDER Drivers - ); - -VOID PhpFillRunningTasks( - _In_ PPH_PROCESS_ITEM Process, - _Inout_ PPH_STRING_BUILDER Tasks - ); - -static PH_STRINGREF StandardIndent = PH_STRINGREF_INIT(L" "); - -VOID PhpAppendStringWithLineBreaks( - _Inout_ PPH_STRING_BUILDER StringBuilder, - _In_ PPH_STRINGREF String, - _In_ ULONG CharactersPerLine, - _In_opt_ PPH_STRINGREF IndentAfterFirstLine - ) -{ - PH_STRINGREF line; - SIZE_T bytesPerLine; - BOOLEAN afterFirstLine; - SIZE_T bytesToAppend; - - line = *String; - bytesPerLine = CharactersPerLine * sizeof(WCHAR); - afterFirstLine = FALSE; - - while (line.Length != 0) - { - bytesToAppend = line.Length; - - if (bytesToAppend > bytesPerLine) - bytesToAppend = bytesPerLine; - - if (afterFirstLine) - { - PhAppendCharStringBuilder(StringBuilder, '\n'); - - if (IndentAfterFirstLine) - PhAppendStringBuilder(StringBuilder, IndentAfterFirstLine); - } - - PhAppendStringBuilderEx(StringBuilder, line.Buffer, bytesToAppend); - afterFirstLine = TRUE; - PhSkipStringRef(&line, bytesToAppend); - } -} - -static int __cdecl ServiceForTooltipCompare( - _In_ const void *elem1, - _In_ const void *elem2 - ) -{ - PPH_SERVICE_ITEM serviceItem1 = *(PPH_SERVICE_ITEM *)elem1; - PPH_SERVICE_ITEM serviceItem2 = *(PPH_SERVICE_ITEM *)elem2; - - return PhCompareString(serviceItem1->Name, serviceItem2->Name, TRUE); -} - -PPH_STRING PhGetProcessTooltipText( - _In_ PPH_PROCESS_ITEM Process, - _Out_opt_ PULONG ValidToTickCount - ) -{ - PH_STRING_BUILDER stringBuilder; - ULONG validForMs = 60 * 60 * 1000; // 1 hour - PPH_STRING tempString; - PH_KNOWN_PROCESS_TYPE knownProcessType = UnknownProcessType; - - PhInitializeStringBuilder(&stringBuilder, 200); - - // Command line - - if (Process->CommandLine) - { - tempString = PhEllipsisString(Process->CommandLine, 100 * 10); - - // This is necessary because the tooltip control seems to use some kind of O(n^9999) word-wrapping - // algorithm. - PhpAppendStringWithLineBreaks(&stringBuilder, &tempString->sr, 100, NULL); - PhAppendCharStringBuilder(&stringBuilder, '\n'); - - PhDereferenceObject(tempString); - } - - // File information - - tempString = PhFormatImageVersionInfo( - Process->FileName, - &Process->VersionInfo, - &StandardIndent, - 0 - ); - - if (!PhIsNullOrEmptyString(tempString)) - { - PhAppendStringBuilder2(&stringBuilder, L"File:\n"); - PhAppendStringBuilder(&stringBuilder, &tempString->sr); - PhAppendCharStringBuilder(&stringBuilder, '\n'); - } - - if (tempString) - PhDereferenceObject(tempString); - - // Known command line information - - if (Process->QueryHandle) - PhGetProcessKnownType(Process->QueryHandle, &knownProcessType); - - if (Process->CommandLine && Process->QueryHandle) - { - PH_KNOWN_PROCESS_COMMAND_LINE knownCommandLine; - - if (knownProcessType != UnknownProcessType && PhaGetProcessKnownCommandLine( - Process->CommandLine, - knownProcessType, - &knownCommandLine - )) - { - switch (knownProcessType & KnownProcessTypeMask) - { - case ServiceHostProcessType: - PhAppendStringBuilder2(&stringBuilder, L"Service group name:\n "); - PhAppendStringBuilder(&stringBuilder, &knownCommandLine.ServiceHost.GroupName->sr); - PhAppendCharStringBuilder(&stringBuilder, '\n'); - break; - case RunDllAsAppProcessType: - { - PH_IMAGE_VERSION_INFO versionInfo; - - if (PhInitializeImageVersionInfo( - &versionInfo, - knownCommandLine.RunDllAsApp.FileName->Buffer - )) - { - tempString = PhFormatImageVersionInfo( - knownCommandLine.RunDllAsApp.FileName, - &versionInfo, - &StandardIndent, - 0 - ); - - if (!PhIsNullOrEmptyString(tempString)) - { - PhAppendStringBuilder2(&stringBuilder, L"Run DLL target file:\n"); - PhAppendStringBuilder(&stringBuilder, &tempString->sr); - PhAppendCharStringBuilder(&stringBuilder, '\n'); - } - - if (tempString) - PhDereferenceObject(tempString); - - PhDeleteImageVersionInfo(&versionInfo); - } - } - break; - case ComSurrogateProcessType: - { - PH_IMAGE_VERSION_INFO versionInfo; - PPH_STRING guidString; - - PhAppendStringBuilder2(&stringBuilder, L"COM target:\n"); - - if (knownCommandLine.ComSurrogate.Name) - { - PhAppendStringBuilder(&stringBuilder, &StandardIndent); - PhAppendStringBuilder(&stringBuilder, &knownCommandLine.ComSurrogate.Name->sr); - PhAppendCharStringBuilder(&stringBuilder, '\n'); - } - - if (guidString = PhFormatGuid(&knownCommandLine.ComSurrogate.Guid)) - { - PhAppendStringBuilder(&stringBuilder, &StandardIndent); - PhAppendStringBuilder(&stringBuilder, &guidString->sr); - PhDereferenceObject(guidString); - PhAppendCharStringBuilder(&stringBuilder, '\n'); - } - - if (knownCommandLine.ComSurrogate.FileName && PhInitializeImageVersionInfo( - &versionInfo, - knownCommandLine.ComSurrogate.FileName->Buffer - )) - { - tempString = PhFormatImageVersionInfo( - knownCommandLine.ComSurrogate.FileName, - &versionInfo, - &StandardIndent, - 0 - ); - - if (!PhIsNullOrEmptyString(tempString)) - { - PhAppendStringBuilder2(&stringBuilder, L"COM target file:\n"); - PhAppendStringBuilder(&stringBuilder, &tempString->sr); - PhAppendCharStringBuilder(&stringBuilder, '\n'); - } - - if (tempString) - PhDereferenceObject(tempString); - - PhDeleteImageVersionInfo(&versionInfo); - } - } - break; - } - } - } - - // Services - - if (Process->ServiceList && Process->ServiceList->Count != 0) - { - ULONG enumerationKey = 0; - PPH_SERVICE_ITEM serviceItem; - PPH_LIST serviceList; - ULONG i; - - // Copy the service list into our own list so we can sort it. - - serviceList = PhCreateList(Process->ServiceList->Count); - - PhAcquireQueuedLockShared(&Process->ServiceListLock); - - while (PhEnumPointerList( - Process->ServiceList, - &enumerationKey, - &serviceItem - )) - { - PhReferenceObject(serviceItem); - PhAddItemList(serviceList, serviceItem); - } - - PhReleaseQueuedLockShared(&Process->ServiceListLock); - - qsort(serviceList->Items, serviceList->Count, sizeof(PPH_SERVICE_ITEM), ServiceForTooltipCompare); - - PhAppendStringBuilder2(&stringBuilder, L"Services:\n"); - - // Add the services. - for (i = 0; i < serviceList->Count; i++) - { - serviceItem = serviceList->Items[i]; - - PhAppendStringBuilder(&stringBuilder, &StandardIndent); - PhAppendStringBuilder(&stringBuilder, &serviceItem->Name->sr); - PhAppendStringBuilder2(&stringBuilder, L" ("); - PhAppendStringBuilder(&stringBuilder, &serviceItem->DisplayName->sr); - PhAppendStringBuilder2(&stringBuilder, L")\n"); - } - - PhDereferenceObjects(serviceList->Items, serviceList->Count); - PhDereferenceObject(serviceList); - } - - // Tasks, Drivers - switch (knownProcessType & KnownProcessTypeMask) - { - case TaskHostProcessType: - { - PH_STRING_BUILDER tasks; - - PhInitializeStringBuilder(&tasks, 40); - - PhpFillRunningTasks(Process, &tasks); - - if (tasks.String->Length != 0) - { - PhAppendStringBuilder2(&stringBuilder, L"Tasks:\n"); - PhAppendStringBuilder(&stringBuilder, &tasks.String->sr); - } - - PhDeleteStringBuilder(&tasks); - } - break; - case UmdfHostProcessType: - { - PH_STRING_BUILDER drivers; - - PhInitializeStringBuilder(&drivers, 40); - - PhpFillUmdfDrivers(Process, &drivers); - - if (drivers.String->Length != 0) - { - PhAppendStringBuilder2(&stringBuilder, L"Drivers:\n"); - PhAppendStringBuilder(&stringBuilder, &drivers.String->sr); - } - - PhDeleteStringBuilder(&drivers); - - validForMs = 10 * 1000; // 10 seconds - } - break; - } - - // Plugin - if (PhPluginsEnabled) - { - PH_PLUGIN_GET_TOOLTIP_TEXT getTooltipText; - - getTooltipText.Parameter = Process; - getTooltipText.StringBuilder = &stringBuilder; - getTooltipText.ValidForMs = validForMs; - - PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackGetProcessTooltipText), &getTooltipText); - validForMs = getTooltipText.ValidForMs; - } - - // Notes - - { - PH_STRING_BUILDER notes; - - PhInitializeStringBuilder(¬es, 40); - - if (Process->FileName) - { - if (Process->VerifyResult == VrTrusted) - { - if (!PhIsNullOrEmptyString(Process->VerifySignerName)) - PhAppendFormatStringBuilder(¬es, L" Signer: %s\n", Process->VerifySignerName->Buffer); - else - PhAppendStringBuilder2(¬es, L" Signed.\n"); - } - else if (Process->VerifyResult == VrUnknown) - { - // Nothing - } - else if (Process->VerifyResult != VrNoSignature) - { - PhAppendStringBuilder2(¬es, L" Signature invalid.\n"); - } - } - - if (Process->IsPacked) - { - PhAppendFormatStringBuilder( - ¬es, - L" Image is probably packed (%u imports over %u modules).\n", - Process->ImportFunctions, - Process->ImportModules - ); - } - - if ((ULONG_PTR)Process->ConsoleHostProcessId & ~3) - { - CLIENT_ID clientId; - PWSTR description = L"Console host"; - PPH_STRING clientIdString; - - clientId.UniqueProcess = (HANDLE)((ULONG_PTR)Process->ConsoleHostProcessId & ~3); - clientId.UniqueThread = NULL; - - if ((ULONG_PTR)Process->ConsoleHostProcessId & 2) - description = L"Console application"; - - clientIdString = PhGetClientIdName(&clientId); - PhAppendFormatStringBuilder(¬es, L" %s: %s\n", description, clientIdString->Buffer); - PhDereferenceObject(clientIdString); - } - - if (Process->PackageFullName) - { - PhAppendFormatStringBuilder(¬es, L" Package name: %s\n", Process->PackageFullName->Buffer); - } - - if (Process->IsDotNet) - PhAppendStringBuilder2(¬es, L" Process is managed (.NET).\n"); - if (Process->IsElevated) - PhAppendStringBuilder2(¬es, L" Process is elevated.\n"); - if (Process->IsImmersive) - PhAppendStringBuilder2(¬es, L" Process is a Modern UI app.\n"); - if (Process->IsInJob) - PhAppendStringBuilder2(¬es, L" Process is in a job.\n"); - if (Process->IsWow64) - PhAppendStringBuilder2(¬es, L" Process is 32-bit (WOW64).\n"); - - if (notes.String->Length != 0) - { - PhAppendStringBuilder2(&stringBuilder, L"Notes:\n"); - PhAppendStringBuilder(&stringBuilder, ¬es.String->sr); - } - - PhDeleteStringBuilder(¬es); - } - - if (ValidToTickCount) - *ValidToTickCount = GetTickCount() + validForMs; - - // Remove the trailing newline. - if (stringBuilder.String->Length != 0) - PhRemoveEndStringBuilder(&stringBuilder, 1); - - return PhFinalStringBuilderString(&stringBuilder); -} - -VOID PhpFillUmdfDrivers( - _In_ PPH_PROCESS_ITEM Process, - _Inout_ PPH_STRING_BUILDER Drivers - ) -{ - static PH_STRINGREF activeDevices = PH_STRINGREF_INIT(L"ACTIVE_DEVICES"); - static PH_STRINGREF currentControlSetEnum = PH_STRINGREF_INIT(L"System\\CurrentControlSet\\Enum\\"); - - HANDLE processHandle; - ULONG flags = 0; - PVOID environment; - ULONG environmentLength; - ULONG enumerationKey; - PH_ENVIRONMENT_VARIABLE variable; - - if (!NT_SUCCESS(PhOpenProcess( - &processHandle, - PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, - Process->ProcessId - ))) - return; - -#ifdef _WIN64 - // Just in case. - if (Process->IsWow64) - flags |= PH_GET_PROCESS_ENVIRONMENT_WOW64; -#endif - - if (NT_SUCCESS(PhGetProcessEnvironment( - processHandle, - flags, - &environment, - &environmentLength - ))) - { - enumerationKey = 0; - - while (PhEnumProcessEnvironmentVariables(environment, environmentLength, &enumerationKey, &variable)) - { - PH_STRINGREF part; - PH_STRINGREF remainingPart; - - if (!PhEqualStringRef(&variable.Name, &activeDevices, TRUE)) - continue; - - remainingPart = variable.Value; - - while (remainingPart.Length != 0) - { - PhSplitStringRefAtChar(&remainingPart, ';', &part, &remainingPart); - - if (part.Length != 0) - { - HANDLE driverKeyHandle; - PPH_STRING driverKeyPath; - - driverKeyPath = PhConcatStringRef2(¤tControlSetEnum, &part); - - if (NT_SUCCESS(PhOpenKey( - &driverKeyHandle, - KEY_READ, - PH_KEY_LOCAL_MACHINE, - &driverKeyPath->sr, - 0 - ))) - { - PPH_STRING deviceDesc; - PH_STRINGREF deviceName; - PPH_STRING hardwareId; - - if (deviceDesc = PhQueryRegistryString(driverKeyHandle, L"DeviceDesc")) - { - PH_STRINGREF firstPart; - PH_STRINGREF secondPart; - - if (PhSplitStringRefAtLastChar(&deviceDesc->sr, ';', &firstPart, &secondPart)) - deviceName = secondPart; - else - deviceName = deviceDesc->sr; - } - else - { - PhInitializeStringRef(&deviceName, L"Unknown Device"); - } - - hardwareId = PhQueryRegistryString(driverKeyHandle, L"HardwareID"); - - PhAppendStringBuilder(Drivers, &StandardIndent); - PhAppendStringBuilder(Drivers, &deviceName); - - if (hardwareId) - { - PhTrimToNullTerminatorString(hardwareId); - - if (hardwareId->Length != 0) - { - PhAppendStringBuilder2(Drivers, L" ("); - PhAppendStringBuilder(Drivers, &hardwareId->sr); - PhAppendCharStringBuilder(Drivers, ')'); - } - } - - PhAppendCharStringBuilder(Drivers, '\n'); - - PhClearReference(&hardwareId); - PhClearReference(&deviceDesc); - NtClose(driverKeyHandle); - } - - PhDereferenceObject(driverKeyPath); - } - } - - break; - } - - PhFreePage(environment); - } - - NtClose(processHandle); -} - -VOID PhpFillRunningTasks( - _In_ PPH_PROCESS_ITEM Process, - _Inout_ PPH_STRING_BUILDER Tasks - ) -{ - static CLSID CLSID_TaskScheduler_I = { 0x0f87369f, 0xa4e5, 0x4cfc, { 0xbd, 0x3e, 0x73, 0xe6, 0x15, 0x45, 0x72, 0xdd } }; - static IID IID_ITaskService_I = { 0x2faba4c7, 0x4da9, 0x4013, { 0x96, 0x97, 0x20, 0xcc, 0x3f, 0xd4, 0x0f, 0x85 } }; - - ITaskService *taskService; - - if (SUCCEEDED(CoCreateInstance( - &CLSID_TaskScheduler_I, - NULL, - CLSCTX_INPROC_SERVER, - &IID_ITaskService_I, - &taskService - ))) - { - VARIANT empty = { 0 }; - - if (SUCCEEDED(ITaskService_Connect(taskService, empty, empty, empty, empty))) - { - IRunningTaskCollection *runningTasks; - - if (SUCCEEDED(ITaskService_GetRunningTasks( - taskService, - TASK_ENUM_HIDDEN, - &runningTasks - ))) - { - LONG count; - LONG i; - VARIANT index; - - index.vt = VT_INT; - - if (SUCCEEDED(IRunningTaskCollection_get_Count(runningTasks, &count))) - { - for (i = 1; i <= count; i++) // collections are 1-based - { - IRunningTask *runningTask; - - index.lVal = i; - - if (SUCCEEDED(IRunningTaskCollection_get_Item(runningTasks, index, &runningTask))) - { - ULONG pid; - BSTR action = NULL; - BSTR path = NULL; - - if ( - SUCCEEDED(IRunningTask_get_EnginePID(runningTask, &pid)) && - pid == HandleToUlong(Process->ProcessId) - ) - { - IRunningTask_get_CurrentAction(runningTask, &action); - IRunningTask_get_Path(runningTask, &path); - - PhAppendStringBuilder(Tasks, &StandardIndent); - PhAppendStringBuilder2(Tasks, action ? action : L"Unknown action"); - PhAppendStringBuilder2(Tasks, L" ("); - PhAppendStringBuilder2(Tasks, path ? path : L"Unknown path"); - PhAppendStringBuilder2(Tasks, L")\n"); - - if (action) - SysFreeString(action); - if (path) - SysFreeString(path); - } - - IRunningTask_Release(runningTask); - } - } - } - - IRunningTaskCollection_Release(runningTasks); - } - } - - ITaskService_Release(taskService); - } -} - -PPH_STRING PhGetServiceTooltipText( - _In_ PPH_SERVICE_ITEM Service - ) -{ - PH_STRING_BUILDER stringBuilder; - SC_HANDLE serviceHandle; - - PhInitializeStringBuilder(&stringBuilder, 200); - - if (serviceHandle = PhOpenService(Service->Name->Buffer, SERVICE_QUERY_CONFIG)) - { - PPH_STRING fileName; - PPH_STRING description; - - // File information - - if (fileName = PhGetServiceRelevantFileName(&Service->Name->sr, serviceHandle)) - { - PH_IMAGE_VERSION_INFO versionInfo; - PPH_STRING versionInfoText; - - if (PhInitializeImageVersionInfo( - &versionInfo, - fileName->Buffer - )) - { - versionInfoText = PhFormatImageVersionInfo( - fileName, - &versionInfo, - &StandardIndent, - 0 - ); - - if (!PhIsNullOrEmptyString(versionInfoText)) - { - PhAppendStringBuilder2(&stringBuilder, L"File:\n"); - PhAppendStringBuilder(&stringBuilder, &versionInfoText->sr); - PhAppendCharStringBuilder(&stringBuilder, '\n'); - } - - PhClearReference(&versionInfoText); - PhDeleteImageVersionInfo(&versionInfo); - } - - PhDereferenceObject(fileName); - } - - // Description - - if (description = PhGetServiceDescription(serviceHandle)) - { - PhAppendStringBuilder2(&stringBuilder, L"Description:\n "); - PhAppendStringBuilder(&stringBuilder, &description->sr); - PhAppendCharStringBuilder(&stringBuilder, '\n'); - PhDereferenceObject(description); - } - - CloseServiceHandle(serviceHandle); - } - - // Remove the trailing newline. - if (stringBuilder.String->Length != 0) - PhRemoveEndStringBuilder(&stringBuilder, 1); - - return PhFinalStringBuilderString(&stringBuilder); -} +/* + * Process Hacker - + * item tooltips + * + * Copyright (C) 2010-2015 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include + +#define CINTERFACE +#define COBJMACROS +#include + +#include +#include + +#include +#include +#include + +VOID PhpFillUmdfDrivers( + _In_ PPH_PROCESS_ITEM Process, + _Inout_ PPH_STRING_BUILDER Drivers + ); + +VOID PhpFillRunningTasks( + _In_ PPH_PROCESS_ITEM Process, + _Inout_ PPH_STRING_BUILDER Tasks + ); + +static PH_STRINGREF StandardIndent = PH_STRINGREF_INIT(L" "); + +VOID PhpAppendStringWithLineBreaks( + _Inout_ PPH_STRING_BUILDER StringBuilder, + _In_ PPH_STRINGREF String, + _In_ ULONG CharactersPerLine, + _In_opt_ PPH_STRINGREF IndentAfterFirstLine + ) +{ + PH_STRINGREF line; + SIZE_T bytesPerLine; + BOOLEAN afterFirstLine; + SIZE_T bytesToAppend; + + line = *String; + bytesPerLine = CharactersPerLine * sizeof(WCHAR); + afterFirstLine = FALSE; + + while (line.Length != 0) + { + bytesToAppend = line.Length; + + if (bytesToAppend > bytesPerLine) + bytesToAppend = bytesPerLine; + + if (afterFirstLine) + { + PhAppendCharStringBuilder(StringBuilder, '\n'); + + if (IndentAfterFirstLine) + PhAppendStringBuilder(StringBuilder, IndentAfterFirstLine); + } + + PhAppendStringBuilderEx(StringBuilder, line.Buffer, bytesToAppend); + afterFirstLine = TRUE; + PhSkipStringRef(&line, bytesToAppend); + } +} + +static int __cdecl ServiceForTooltipCompare( + _In_ const void *elem1, + _In_ const void *elem2 + ) +{ + PPH_SERVICE_ITEM serviceItem1 = *(PPH_SERVICE_ITEM *)elem1; + PPH_SERVICE_ITEM serviceItem2 = *(PPH_SERVICE_ITEM *)elem2; + + return PhCompareString(serviceItem1->Name, serviceItem2->Name, TRUE); +} + +PPH_STRING PhGetProcessTooltipText( + _In_ PPH_PROCESS_ITEM Process, + _Out_opt_ PULONG ValidToTickCount + ) +{ + PH_STRING_BUILDER stringBuilder; + ULONG validForMs = 60 * 60 * 1000; // 1 hour + PPH_STRING tempString; + PH_KNOWN_PROCESS_TYPE knownProcessType = UnknownProcessType; + + PhInitializeStringBuilder(&stringBuilder, 200); + + // Command line + + if (Process->CommandLine) + { + tempString = PhEllipsisString(Process->CommandLine, 100 * 10); + + // This is necessary because the tooltip control seems to use some kind of O(n^9999) word-wrapping + // algorithm. + PhpAppendStringWithLineBreaks(&stringBuilder, &tempString->sr, 100, NULL); + PhAppendCharStringBuilder(&stringBuilder, '\n'); + + PhDereferenceObject(tempString); + } + + // File information + + tempString = PhFormatImageVersionInfo( + Process->FileName, + &Process->VersionInfo, + &StandardIndent, + 0 + ); + + if (!PhIsNullOrEmptyString(tempString)) + { + PhAppendStringBuilder2(&stringBuilder, L"File:\n"); + PhAppendStringBuilder(&stringBuilder, &tempString->sr); + PhAppendCharStringBuilder(&stringBuilder, '\n'); + } + + if (tempString) + PhDereferenceObject(tempString); + + // Known command line information + + if (Process->QueryHandle) + PhGetProcessKnownType(Process->QueryHandle, &knownProcessType); + + if (Process->CommandLine && Process->QueryHandle) + { + PH_KNOWN_PROCESS_COMMAND_LINE knownCommandLine; + + if (knownProcessType != UnknownProcessType && PhaGetProcessKnownCommandLine( + Process->CommandLine, + knownProcessType, + &knownCommandLine + )) + { + switch (knownProcessType & KnownProcessTypeMask) + { + case ServiceHostProcessType: + PhAppendStringBuilder2(&stringBuilder, L"Service group name:\n "); + PhAppendStringBuilder(&stringBuilder, &knownCommandLine.ServiceHost.GroupName->sr); + PhAppendCharStringBuilder(&stringBuilder, '\n'); + break; + case RunDllAsAppProcessType: + { + PH_IMAGE_VERSION_INFO versionInfo; + + if (PhInitializeImageVersionInfo( + &versionInfo, + knownCommandLine.RunDllAsApp.FileName->Buffer + )) + { + tempString = PhFormatImageVersionInfo( + knownCommandLine.RunDllAsApp.FileName, + &versionInfo, + &StandardIndent, + 0 + ); + + if (!PhIsNullOrEmptyString(tempString)) + { + PhAppendStringBuilder2(&stringBuilder, L"Run DLL target file:\n"); + PhAppendStringBuilder(&stringBuilder, &tempString->sr); + PhAppendCharStringBuilder(&stringBuilder, '\n'); + } + + if (tempString) + PhDereferenceObject(tempString); + + PhDeleteImageVersionInfo(&versionInfo); + } + } + break; + case ComSurrogateProcessType: + { + PH_IMAGE_VERSION_INFO versionInfo; + PPH_STRING guidString; + + PhAppendStringBuilder2(&stringBuilder, L"COM target:\n"); + + if (knownCommandLine.ComSurrogate.Name) + { + PhAppendStringBuilder(&stringBuilder, &StandardIndent); + PhAppendStringBuilder(&stringBuilder, &knownCommandLine.ComSurrogate.Name->sr); + PhAppendCharStringBuilder(&stringBuilder, '\n'); + } + + if (guidString = PhFormatGuid(&knownCommandLine.ComSurrogate.Guid)) + { + PhAppendStringBuilder(&stringBuilder, &StandardIndent); + PhAppendStringBuilder(&stringBuilder, &guidString->sr); + PhDereferenceObject(guidString); + PhAppendCharStringBuilder(&stringBuilder, '\n'); + } + + if (knownCommandLine.ComSurrogate.FileName && PhInitializeImageVersionInfo( + &versionInfo, + knownCommandLine.ComSurrogate.FileName->Buffer + )) + { + tempString = PhFormatImageVersionInfo( + knownCommandLine.ComSurrogate.FileName, + &versionInfo, + &StandardIndent, + 0 + ); + + if (!PhIsNullOrEmptyString(tempString)) + { + PhAppendStringBuilder2(&stringBuilder, L"COM target file:\n"); + PhAppendStringBuilder(&stringBuilder, &tempString->sr); + PhAppendCharStringBuilder(&stringBuilder, '\n'); + } + + if (tempString) + PhDereferenceObject(tempString); + + PhDeleteImageVersionInfo(&versionInfo); + } + } + break; + } + } + } + + // Services + + if (Process->ServiceList && Process->ServiceList->Count != 0) + { + ULONG enumerationKey = 0; + PPH_SERVICE_ITEM serviceItem; + PPH_LIST serviceList; + ULONG i; + + // Copy the service list into our own list so we can sort it. + + serviceList = PhCreateList(Process->ServiceList->Count); + + PhAcquireQueuedLockShared(&Process->ServiceListLock); + + while (PhEnumPointerList( + Process->ServiceList, + &enumerationKey, + &serviceItem + )) + { + PhReferenceObject(serviceItem); + PhAddItemList(serviceList, serviceItem); + } + + PhReleaseQueuedLockShared(&Process->ServiceListLock); + + qsort(serviceList->Items, serviceList->Count, sizeof(PPH_SERVICE_ITEM), ServiceForTooltipCompare); + + PhAppendStringBuilder2(&stringBuilder, L"Services:\n"); + + // Add the services. + for (i = 0; i < serviceList->Count; i++) + { + serviceItem = serviceList->Items[i]; + + PhAppendStringBuilder(&stringBuilder, &StandardIndent); + PhAppendStringBuilder(&stringBuilder, &serviceItem->Name->sr); + PhAppendStringBuilder2(&stringBuilder, L" ("); + PhAppendStringBuilder(&stringBuilder, &serviceItem->DisplayName->sr); + PhAppendStringBuilder2(&stringBuilder, L")\n"); + } + + PhDereferenceObjects(serviceList->Items, serviceList->Count); + PhDereferenceObject(serviceList); + } + + // Tasks, Drivers + switch (knownProcessType & KnownProcessTypeMask) + { + case TaskHostProcessType: + { + PH_STRING_BUILDER tasks; + + PhInitializeStringBuilder(&tasks, 40); + + PhpFillRunningTasks(Process, &tasks); + + if (tasks.String->Length != 0) + { + PhAppendStringBuilder2(&stringBuilder, L"Tasks:\n"); + PhAppendStringBuilder(&stringBuilder, &tasks.String->sr); + } + + PhDeleteStringBuilder(&tasks); + } + break; + case UmdfHostProcessType: + { + PH_STRING_BUILDER drivers; + + PhInitializeStringBuilder(&drivers, 40); + + PhpFillUmdfDrivers(Process, &drivers); + + if (drivers.String->Length != 0) + { + PhAppendStringBuilder2(&stringBuilder, L"Drivers:\n"); + PhAppendStringBuilder(&stringBuilder, &drivers.String->sr); + } + + PhDeleteStringBuilder(&drivers); + + validForMs = 10 * 1000; // 10 seconds + } + break; + } + + // Plugin + if (PhPluginsEnabled) + { + PH_PLUGIN_GET_TOOLTIP_TEXT getTooltipText; + + getTooltipText.Parameter = Process; + getTooltipText.StringBuilder = &stringBuilder; + getTooltipText.ValidForMs = validForMs; + + PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackGetProcessTooltipText), &getTooltipText); + validForMs = getTooltipText.ValidForMs; + } + + // Notes + + { + PH_STRING_BUILDER notes; + + PhInitializeStringBuilder(¬es, 40); + + if (Process->FileName) + { + if (Process->VerifyResult == VrTrusted) + { + if (!PhIsNullOrEmptyString(Process->VerifySignerName)) + PhAppendFormatStringBuilder(¬es, L" Signer: %s\n", Process->VerifySignerName->Buffer); + else + PhAppendStringBuilder2(¬es, L" Signed.\n"); + } + else if (Process->VerifyResult == VrUnknown) + { + // Nothing + } + else if (Process->VerifyResult != VrNoSignature) + { + PhAppendStringBuilder2(¬es, L" Signature invalid.\n"); + } + } + + if (Process->IsPacked) + { + PhAppendFormatStringBuilder( + ¬es, + L" Image is probably packed (%u imports over %u modules).\n", + Process->ImportFunctions, + Process->ImportModules + ); + } + + if ((ULONG_PTR)Process->ConsoleHostProcessId & ~3) + { + CLIENT_ID clientId; + PWSTR description = L"Console host"; + PPH_STRING clientIdString; + + clientId.UniqueProcess = (HANDLE)((ULONG_PTR)Process->ConsoleHostProcessId & ~3); + clientId.UniqueThread = NULL; + + if ((ULONG_PTR)Process->ConsoleHostProcessId & 2) + description = L"Console application"; + + clientIdString = PhGetClientIdName(&clientId); + PhAppendFormatStringBuilder(¬es, L" %s: %s\n", description, clientIdString->Buffer); + PhDereferenceObject(clientIdString); + } + + if (Process->PackageFullName) + { + PhAppendFormatStringBuilder(¬es, L" Package name: %s\n", Process->PackageFullName->Buffer); + } + + if (Process->IsDotNet) + PhAppendStringBuilder2(¬es, L" Process is managed (.NET).\n"); + if (Process->IsElevated) + PhAppendStringBuilder2(¬es, L" Process is elevated.\n"); + if (Process->IsImmersive) + PhAppendStringBuilder2(¬es, L" Process is a Modern UI app.\n"); + if (Process->IsInJob) + PhAppendStringBuilder2(¬es, L" Process is in a job.\n"); + if (Process->IsWow64) + PhAppendStringBuilder2(¬es, L" Process is 32-bit (WOW64).\n"); + + if (notes.String->Length != 0) + { + PhAppendStringBuilder2(&stringBuilder, L"Notes:\n"); + PhAppendStringBuilder(&stringBuilder, ¬es.String->sr); + } + + PhDeleteStringBuilder(¬es); + } + + if (ValidToTickCount) + *ValidToTickCount = GetTickCount() + validForMs; + + // Remove the trailing newline. + if (stringBuilder.String->Length != 0) + PhRemoveEndStringBuilder(&stringBuilder, 1); + + return PhFinalStringBuilderString(&stringBuilder); +} + +VOID PhpFillUmdfDrivers( + _In_ PPH_PROCESS_ITEM Process, + _Inout_ PPH_STRING_BUILDER Drivers + ) +{ + static PH_STRINGREF activeDevices = PH_STRINGREF_INIT(L"ACTIVE_DEVICES"); + static PH_STRINGREF currentControlSetEnum = PH_STRINGREF_INIT(L"System\\CurrentControlSet\\Enum\\"); + + HANDLE processHandle; + ULONG flags = 0; + PVOID environment; + ULONG environmentLength; + ULONG enumerationKey; + PH_ENVIRONMENT_VARIABLE variable; + + if (!NT_SUCCESS(PhOpenProcess( + &processHandle, + PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, + Process->ProcessId + ))) + return; + +#ifdef _WIN64 + // Just in case. + if (Process->IsWow64) + flags |= PH_GET_PROCESS_ENVIRONMENT_WOW64; +#endif + + if (NT_SUCCESS(PhGetProcessEnvironment( + processHandle, + flags, + &environment, + &environmentLength + ))) + { + enumerationKey = 0; + + while (PhEnumProcessEnvironmentVariables(environment, environmentLength, &enumerationKey, &variable)) + { + PH_STRINGREF part; + PH_STRINGREF remainingPart; + + if (!PhEqualStringRef(&variable.Name, &activeDevices, TRUE)) + continue; + + remainingPart = variable.Value; + + while (remainingPart.Length != 0) + { + PhSplitStringRefAtChar(&remainingPart, ';', &part, &remainingPart); + + if (part.Length != 0) + { + HANDLE driverKeyHandle; + PPH_STRING driverKeyPath; + + driverKeyPath = PhConcatStringRef2(¤tControlSetEnum, &part); + + if (NT_SUCCESS(PhOpenKey( + &driverKeyHandle, + KEY_READ, + PH_KEY_LOCAL_MACHINE, + &driverKeyPath->sr, + 0 + ))) + { + PPH_STRING deviceDesc; + PH_STRINGREF deviceName; + PPH_STRING hardwareId; + + if (deviceDesc = PhQueryRegistryString(driverKeyHandle, L"DeviceDesc")) + { + PH_STRINGREF firstPart; + PH_STRINGREF secondPart; + + if (PhSplitStringRefAtLastChar(&deviceDesc->sr, ';', &firstPart, &secondPart)) + deviceName = secondPart; + else + deviceName = deviceDesc->sr; + } + else + { + PhInitializeStringRef(&deviceName, L"Unknown Device"); + } + + hardwareId = PhQueryRegistryString(driverKeyHandle, L"HardwareID"); + + PhAppendStringBuilder(Drivers, &StandardIndent); + PhAppendStringBuilder(Drivers, &deviceName); + + if (hardwareId) + { + PhTrimToNullTerminatorString(hardwareId); + + if (hardwareId->Length != 0) + { + PhAppendStringBuilder2(Drivers, L" ("); + PhAppendStringBuilder(Drivers, &hardwareId->sr); + PhAppendCharStringBuilder(Drivers, ')'); + } + } + + PhAppendCharStringBuilder(Drivers, '\n'); + + PhClearReference(&hardwareId); + PhClearReference(&deviceDesc); + NtClose(driverKeyHandle); + } + + PhDereferenceObject(driverKeyPath); + } + } + + break; + } + + PhFreePage(environment); + } + + NtClose(processHandle); +} + +VOID PhpFillRunningTasks( + _In_ PPH_PROCESS_ITEM Process, + _Inout_ PPH_STRING_BUILDER Tasks + ) +{ + static CLSID CLSID_TaskScheduler_I = { 0x0f87369f, 0xa4e5, 0x4cfc, { 0xbd, 0x3e, 0x73, 0xe6, 0x15, 0x45, 0x72, 0xdd } }; + static IID IID_ITaskService_I = { 0x2faba4c7, 0x4da9, 0x4013, { 0x96, 0x97, 0x20, 0xcc, 0x3f, 0xd4, 0x0f, 0x85 } }; + + ITaskService *taskService; + + if (SUCCEEDED(CoCreateInstance( + &CLSID_TaskScheduler_I, + NULL, + CLSCTX_INPROC_SERVER, + &IID_ITaskService_I, + &taskService + ))) + { + VARIANT empty = { 0 }; + + if (SUCCEEDED(ITaskService_Connect(taskService, empty, empty, empty, empty))) + { + IRunningTaskCollection *runningTasks; + + if (SUCCEEDED(ITaskService_GetRunningTasks( + taskService, + TASK_ENUM_HIDDEN, + &runningTasks + ))) + { + LONG count; + LONG i; + VARIANT index; + + index.vt = VT_INT; + + if (SUCCEEDED(IRunningTaskCollection_get_Count(runningTasks, &count))) + { + for (i = 1; i <= count; i++) // collections are 1-based + { + IRunningTask *runningTask; + + index.lVal = i; + + if (SUCCEEDED(IRunningTaskCollection_get_Item(runningTasks, index, &runningTask))) + { + ULONG pid; + BSTR action = NULL; + BSTR path = NULL; + + if ( + SUCCEEDED(IRunningTask_get_EnginePID(runningTask, &pid)) && + pid == HandleToUlong(Process->ProcessId) + ) + { + IRunningTask_get_CurrentAction(runningTask, &action); + IRunningTask_get_Path(runningTask, &path); + + PhAppendStringBuilder(Tasks, &StandardIndent); + PhAppendStringBuilder2(Tasks, action ? action : L"Unknown action"); + PhAppendStringBuilder2(Tasks, L" ("); + PhAppendStringBuilder2(Tasks, path ? path : L"Unknown path"); + PhAppendStringBuilder2(Tasks, L")\n"); + + if (action) + SysFreeString(action); + if (path) + SysFreeString(path); + } + + IRunningTask_Release(runningTask); + } + } + } + + IRunningTaskCollection_Release(runningTasks); + } + } + + ITaskService_Release(taskService); + } +} + +PPH_STRING PhGetServiceTooltipText( + _In_ PPH_SERVICE_ITEM Service + ) +{ + PH_STRING_BUILDER stringBuilder; + SC_HANDLE serviceHandle; + + PhInitializeStringBuilder(&stringBuilder, 200); + + if (serviceHandle = PhOpenService(Service->Name->Buffer, SERVICE_QUERY_CONFIG)) + { + PPH_STRING fileName; + PPH_STRING description; + + // File information + + if (fileName = PhGetServiceRelevantFileName(&Service->Name->sr, serviceHandle)) + { + PH_IMAGE_VERSION_INFO versionInfo; + PPH_STRING versionInfoText; + + if (PhInitializeImageVersionInfo( + &versionInfo, + fileName->Buffer + )) + { + versionInfoText = PhFormatImageVersionInfo( + fileName, + &versionInfo, + &StandardIndent, + 0 + ); + + if (!PhIsNullOrEmptyString(versionInfoText)) + { + PhAppendStringBuilder2(&stringBuilder, L"File:\n"); + PhAppendStringBuilder(&stringBuilder, &versionInfoText->sr); + PhAppendCharStringBuilder(&stringBuilder, '\n'); + } + + PhClearReference(&versionInfoText); + PhDeleteImageVersionInfo(&versionInfo); + } + + PhDereferenceObject(fileName); + } + + // Description + + if (description = PhGetServiceDescription(serviceHandle)) + { + PhAppendStringBuilder2(&stringBuilder, L"Description:\n "); + PhAppendStringBuilder(&stringBuilder, &description->sr); + PhAppendCharStringBuilder(&stringBuilder, '\n'); + PhDereferenceObject(description); + } + + CloseServiceHandle(serviceHandle); + } + + // Remove the trailing newline. + if (stringBuilder.String->Length != 0) + PhRemoveEndStringBuilder(&stringBuilder, 1); + + return PhFinalStringBuilderString(&stringBuilder); +} diff --git a/ProcessHacker/jobprp.c b/ProcessHacker/jobprp.c index e43759b49b5e..c3ecb3db161a 100644 --- a/ProcessHacker/jobprp.c +++ b/ProcessHacker/jobprp.c @@ -1,660 +1,660 @@ -/* - * Process Hacker - - * job properties - * - * Copyright (C) 2010 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include - -#include -#include - -#include -#include - -typedef struct _JOB_PAGE_CONTEXT -{ - PPH_OPEN_OBJECT OpenObject; - PVOID Context; - DLGPROC HookProc; -} JOB_PAGE_CONTEXT, *PJOB_PAGE_CONTEXT; - -INT CALLBACK PhpJobPropPageProc( - _In_ HWND hwnd, - _In_ UINT uMsg, - _In_ LPPROPSHEETPAGE ppsp - ); - -INT_PTR CALLBACK PhpJobPageProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -VOID PhpShowJobAdvancedProperties( - _In_ HWND ParentWindowHandle, - _In_ PJOB_PAGE_CONTEXT Context - ); - -INT_PTR CALLBACK PhpJobStatisticsPageProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -VOID PhShowJobProperties( - _In_ HWND ParentWindowHandle, - _In_ PPH_OPEN_OBJECT OpenObject, - _In_opt_ PVOID Context, - _In_opt_ PWSTR Title - ) -{ - PROPSHEETHEADER propSheetHeader = { sizeof(propSheetHeader) }; - HPROPSHEETPAGE pages[1]; - - propSheetHeader.dwFlags = - PSH_NOAPPLYNOW | - PSH_NOCONTEXTHELP | - PSH_PROPTITLE; - propSheetHeader.hwndParent = ParentWindowHandle; - propSheetHeader.pszCaption = Title ? Title : L"Job"; - propSheetHeader.nPages = 1; - propSheetHeader.nStartPage = 0; - propSheetHeader.phpage = pages; - - pages[0] = PhCreateJobPage(OpenObject, Context, NULL); - - PhModalPropertySheet(&propSheetHeader); -} - -HPROPSHEETPAGE PhCreateJobPage( - _In_ PPH_OPEN_OBJECT OpenObject, - _In_opt_ PVOID Context, - _In_opt_ DLGPROC HookProc - ) -{ - HPROPSHEETPAGE propSheetPageHandle; - PROPSHEETPAGE propSheetPage; - PJOB_PAGE_CONTEXT jobPageContext; - - jobPageContext = PhCreateAlloc(sizeof(JOB_PAGE_CONTEXT)); - memset(jobPageContext, 0, sizeof(JOB_PAGE_CONTEXT)); - jobPageContext->OpenObject = OpenObject; - jobPageContext->Context = Context; - jobPageContext->HookProc = HookProc; - - memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); - propSheetPage.dwSize = sizeof(PROPSHEETPAGE); - propSheetPage.dwFlags = PSP_USECALLBACK; - propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_OBJJOB); - propSheetPage.pfnDlgProc = PhpJobPageProc; - propSheetPage.lParam = (LPARAM)jobPageContext; - propSheetPage.pfnCallback = PhpJobPropPageProc; - - propSheetPageHandle = CreatePropertySheetPage(&propSheetPage); - // CreatePropertySheetPage would have sent PSPCB_ADDREF (below), - // which would have added a reference. - PhDereferenceObject(jobPageContext); - - return propSheetPageHandle; -} - -INT CALLBACK PhpJobPropPageProc( - _In_ HWND hwnd, - _In_ UINT uMsg, - _In_ LPPROPSHEETPAGE ppsp - ) -{ - PJOB_PAGE_CONTEXT jobPageContext; - - jobPageContext = (PJOB_PAGE_CONTEXT)ppsp->lParam; - - if (uMsg == PSPCB_ADDREF) - { - PhReferenceObject(jobPageContext); - } - else if (uMsg == PSPCB_RELEASE) - { - PhDereferenceObject(jobPageContext); - } - - return 1; -} - -FORCEINLINE PJOB_PAGE_CONTEXT PhpJobPageHeader( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - return (PJOB_PAGE_CONTEXT)PhpGenericPropertyPageHeader( - hwndDlg, uMsg, wParam, lParam, L"JobPageContext"); -} - -static VOID PhpAddLimit( - _In_ HWND Handle, - _In_ PWSTR Name, - _In_ PWSTR Value - ) -{ - INT lvItemIndex; - - lvItemIndex = PhAddListViewItem(Handle, MAXINT, Name, NULL); - PhSetListViewSubItem(Handle, lvItemIndex, 1, Value); -} - -static VOID PhpAddJobProcesses( - _In_ HWND hwndDlg, - _In_ HANDLE JobHandle - ) -{ - PJOBOBJECT_BASIC_PROCESS_ID_LIST processIdList; - HWND processesLv; - - processesLv = GetDlgItem(hwndDlg, IDC_PROCESSES); - - if (NT_SUCCESS(PhGetJobProcessIdList(JobHandle, &processIdList))) - { - ULONG i; - CLIENT_ID clientId; - PPH_STRING name; - - clientId.UniqueThread = NULL; - - for (i = 0; i < processIdList->NumberOfProcessIdsInList; i++) - { - clientId.UniqueProcess = (HANDLE)processIdList->ProcessIdList[i]; - name = PH_AUTO(PhGetClientIdName(&clientId)); - - PhAddListViewItem(processesLv, MAXINT, PhGetString(name), NULL); - } - - PhFree(processIdList); - } -} - -INT_PTR CALLBACK PhpJobPageProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - PJOB_PAGE_CONTEXT jobPageContext; - - jobPageContext = PhpJobPageHeader(hwndDlg, uMsg, wParam, lParam); - - if (!jobPageContext) - return FALSE; - - if (jobPageContext->HookProc) - { - if (jobPageContext->HookProc(hwndDlg, uMsg, wParam, lParam)) - return TRUE; - } - - switch (uMsg) - { - case WM_INITDIALOG: - { - HANDLE jobHandle; - HWND processesLv; - HWND limitsLv; - - processesLv = GetDlgItem(hwndDlg, IDC_PROCESSES); - limitsLv = GetDlgItem(hwndDlg, IDC_LIMITS); - PhSetListViewStyle(processesLv, FALSE, TRUE); - PhSetListViewStyle(limitsLv, FALSE, TRUE); - PhSetControlTheme(processesLv, L"explorer"); - PhSetControlTheme(limitsLv, L"explorer"); - - PhAddListViewColumn(processesLv, 0, 0, 0, LVCFMT_LEFT, 240, L"Name"); - - PhAddListViewColumn(limitsLv, 0, 0, 0, LVCFMT_LEFT, 120, L"Name"); - PhAddListViewColumn(limitsLv, 1, 1, 1, LVCFMT_LEFT, 160, L"Value"); - PhLoadListViewColumnsFromSetting(L"JobListViewColumns", limitsLv); - - SetDlgItemText(hwndDlg, IDC_NAME, L"Unknown"); - - if (NT_SUCCESS(jobPageContext->OpenObject( - &jobHandle, - JOB_OBJECT_QUERY, - jobPageContext->Context - ))) - { - PPH_STRING jobObjectName = NULL; - JOBOBJECT_EXTENDED_LIMIT_INFORMATION extendedLimits; - JOBOBJECT_BASIC_UI_RESTRICTIONS basicUiRestrictions; - - // Name - - PhGetHandleInformation( - NtCurrentProcess(), - jobHandle, - -1, - NULL, - NULL, - NULL, - &jobObjectName - ); - PH_AUTO(jobObjectName); - - if (jobObjectName && jobObjectName->Length == 0) - jobObjectName = NULL; - - SetDlgItemText(hwndDlg, IDC_NAME, PhGetStringOrDefault(jobObjectName, L"(unnamed job)")); - - // Processes - PhpAddJobProcesses(hwndDlg, jobHandle); - - // Limits - - if (NT_SUCCESS(PhGetJobExtendedLimits(jobHandle, &extendedLimits))) - { - ULONG flags = extendedLimits.BasicLimitInformation.LimitFlags; - - if (flags & JOB_OBJECT_LIMIT_ACTIVE_PROCESS) - { - WCHAR value[PH_INT32_STR_LEN_1]; - PhPrintUInt32(value, extendedLimits.BasicLimitInformation.ActiveProcessLimit); - PhpAddLimit(limitsLv, L"Active processes", value); - } - - if (flags & JOB_OBJECT_LIMIT_AFFINITY) - { - WCHAR value[PH_PTR_STR_LEN_1]; - PhPrintPointer(value, (PVOID)extendedLimits.BasicLimitInformation.Affinity); - PhpAddLimit(limitsLv, L"Affinity", value); - } - - if (flags & JOB_OBJECT_LIMIT_BREAKAWAY_OK) - { - PhpAddLimit(limitsLv, L"Breakaway OK", L"Enabled"); - } - - if (flags & JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION) - { - PhpAddLimit(limitsLv, L"Die on unhandled exception", L"Enabled"); - } - - if (flags & JOB_OBJECT_LIMIT_JOB_MEMORY) - { - PPH_STRING value = PhaFormatSize(extendedLimits.JobMemoryLimit, -1); - PhpAddLimit(limitsLv, L"Job memory", value->Buffer); - } - - if (flags & JOB_OBJECT_LIMIT_JOB_TIME) - { - WCHAR value[PH_TIMESPAN_STR_LEN_1]; - PhPrintTimeSpan(value, extendedLimits.BasicLimitInformation.PerJobUserTimeLimit.QuadPart, - PH_TIMESPAN_DHMS); - PhpAddLimit(limitsLv, L"Job time", value); - } - - if (flags & JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE) - { - PhpAddLimit(limitsLv, L"Kill on job close", L"Enabled"); - } - - if (flags & JOB_OBJECT_LIMIT_PRIORITY_CLASS) - { - PhpAddLimit(limitsLv, L"Priority class", - PhGetProcessPriorityClassString(extendedLimits.BasicLimitInformation.PriorityClass)); - } - - if (flags & JOB_OBJECT_LIMIT_PROCESS_MEMORY) - { - PPH_STRING value = PhaFormatSize(extendedLimits.ProcessMemoryLimit, -1); - PhpAddLimit(limitsLv, L"Process memory", value->Buffer); - } - - if (flags & JOB_OBJECT_LIMIT_PROCESS_TIME) - { - WCHAR value[PH_TIMESPAN_STR_LEN_1]; - PhPrintTimeSpan(value, extendedLimits.BasicLimitInformation.PerProcessUserTimeLimit.QuadPart, - PH_TIMESPAN_DHMS); - PhpAddLimit(limitsLv, L"Process time", value); - } - - if (flags & JOB_OBJECT_LIMIT_SCHEDULING_CLASS) - { - WCHAR value[PH_INT32_STR_LEN_1]; - PhPrintUInt32(value, extendedLimits.BasicLimitInformation.SchedulingClass); - PhpAddLimit(limitsLv, L"Scheduling class", value); - } - - if (flags & JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK) - { - PhpAddLimit(limitsLv, L"Silent breakaway OK", L"Enabled"); - } - - if (flags & JOB_OBJECT_LIMIT_WORKINGSET) - { - PPH_STRING value; - - value = PhaFormatSize(extendedLimits.BasicLimitInformation.MinimumWorkingSetSize, -1); - PhpAddLimit(limitsLv, L"Working set minimum", value->Buffer); - - value = PhaFormatSize(extendedLimits.BasicLimitInformation.MaximumWorkingSetSize, -1); - PhpAddLimit(limitsLv, L"Working set maximum", value->Buffer); - } - } - - if (NT_SUCCESS(PhGetJobBasicUiRestrictions(jobHandle, &basicUiRestrictions))) - { - ULONG flags = basicUiRestrictions.UIRestrictionsClass; - - if (flags & JOB_OBJECT_UILIMIT_DESKTOP) - PhpAddLimit(limitsLv, L"Desktop", L"Limited"); - if (flags & JOB_OBJECT_UILIMIT_DISPLAYSETTINGS) - PhpAddLimit(limitsLv, L"Display settings", L"Limited"); - if (flags & JOB_OBJECT_UILIMIT_EXITWINDOWS) - PhpAddLimit(limitsLv, L"Exit windows", L"Limited"); - if (flags & JOB_OBJECT_UILIMIT_GLOBALATOMS) - PhpAddLimit(limitsLv, L"Global atoms", L"Limited"); - if (flags & JOB_OBJECT_UILIMIT_HANDLES) - PhpAddLimit(limitsLv, L"Handles", L"Limited"); - if (flags & JOB_OBJECT_UILIMIT_READCLIPBOARD) - PhpAddLimit(limitsLv, L"Read clipboard", L"Limited"); - if (flags & JOB_OBJECT_UILIMIT_SYSTEMPARAMETERS) - PhpAddLimit(limitsLv, L"System parameters", L"Limited"); - if (flags & JOB_OBJECT_UILIMIT_WRITECLIPBOARD) - PhpAddLimit(limitsLv, L"Write clipboard", L"Limited"); - } - - NtClose(jobHandle); - } - } - break; - case WM_DESTROY: - PhSaveListViewColumnsToSetting(L"JobListViewColumns", GetDlgItem(hwndDlg, IDC_LIMITS)); - break; - case WM_COMMAND: - { - switch (LOWORD(wParam)) - { - case IDC_TERMINATE: - { - if (PhShowConfirmMessage( - hwndDlg, - L"terminate", - L"the job", - L"Terminating a job will terminate all processes assigned to it.", - TRUE - )) - { - NTSTATUS status; - HANDLE jobHandle; - - if (NT_SUCCESS(status = jobPageContext->OpenObject( - &jobHandle, - JOB_OBJECT_TERMINATE, - jobPageContext->Context - ))) - { - status = NtTerminateJobObject(jobHandle, STATUS_SUCCESS); - NtClose(jobHandle); - } - - if (!NT_SUCCESS(status)) - PhShowStatus(hwndDlg, L"Unable to terminate the job", status, 0); - } - } - break; - case IDC_ADD: - { - NTSTATUS status; - HANDLE processId; - HANDLE processHandle; - HANDLE jobHandle; - - while (PhShowChooseProcessDialog( - hwndDlg, - L"Select a process to add to the job permanently.", - &processId - )) - { - if (NT_SUCCESS(status = PhOpenProcess( - &processHandle, - PROCESS_TERMINATE | PROCESS_SET_QUOTA, - processId - ))) - { - if (NT_SUCCESS(status = jobPageContext->OpenObject( - &jobHandle, - JOB_OBJECT_ASSIGN_PROCESS | JOB_OBJECT_QUERY, - jobPageContext->Context - ))) - { - status = NtAssignProcessToJobObject(jobHandle, processHandle); - - if (NT_SUCCESS(status)) - { - ListView_DeleteAllItems(GetDlgItem(hwndDlg, IDC_PROCESSES)); - PhpAddJobProcesses(hwndDlg, jobHandle); - } - - NtClose(jobHandle); - } - - NtClose(processHandle); - } - - if (NT_SUCCESS(status)) - break; - else - PhShowStatus(hwndDlg, L"Unable to add the process to the job", status, 0); - } - } - break; - case IDC_ADVANCED: - { - PhpShowJobAdvancedProperties(hwndDlg, jobPageContext); - } - break; - } - } - break; - case WM_NOTIFY: - { - PhHandleListViewNotifyBehaviors(lParam, GetDlgItem(hwndDlg, IDC_PROCESSES), PH_LIST_VIEW_DEFAULT_1_BEHAVIORS); - PhHandleListViewNotifyBehaviors(lParam, GetDlgItem(hwndDlg, IDC_LIMITS), PH_LIST_VIEW_DEFAULT_1_BEHAVIORS); - } - break; - } - - return FALSE; -} - -VOID PhpShowJobAdvancedProperties( - _In_ HWND ParentWindowHandle, - _In_ PJOB_PAGE_CONTEXT Context - ) -{ - PROPSHEETHEADER propSheetHeader = { sizeof(propSheetHeader) }; - HPROPSHEETPAGE pages[2]; - PROPSHEETPAGE statisticsPage; - PH_STD_OBJECT_SECURITY stdObjectSecurity; - PPH_ACCESS_ENTRY accessEntries; - ULONG numberOfAccessEntries; - - propSheetHeader.dwFlags = - PSH_NOAPPLYNOW | - PSH_NOCONTEXTHELP | - PSH_PROPTITLE; - propSheetHeader.hwndParent = ParentWindowHandle; - propSheetHeader.pszCaption = L"Job"; - propSheetHeader.nPages = 2; - propSheetHeader.nStartPage = 0; - propSheetHeader.phpage = pages; - - // General - - memset(&statisticsPage, 0, sizeof(PROPSHEETPAGE)); - statisticsPage.dwSize = sizeof(PROPSHEETPAGE); - statisticsPage.pszTemplate = MAKEINTRESOURCE(IDD_JOBSTATISTICS); - statisticsPage.pfnDlgProc = PhpJobStatisticsPageProc; - statisticsPage.lParam = (LPARAM)Context; - pages[0] = CreatePropertySheetPage(&statisticsPage); - - // Security - - stdObjectSecurity.OpenObject = Context->OpenObject; - stdObjectSecurity.ObjectType = L"Job"; - stdObjectSecurity.Context = Context->Context; - - if (PhGetAccessEntries(L"Job", &accessEntries, &numberOfAccessEntries)) - { - pages[1] = PhCreateSecurityPage( - L"Job", - PhStdGetObjectSecurity, - PhStdSetObjectSecurity, - &stdObjectSecurity, - accessEntries, - numberOfAccessEntries - ); - PhFree(accessEntries); - } - - PhModalPropertySheet(&propSheetHeader); -} - -static VOID PhpRefreshJobStatisticsInfo( - _In_ HWND hwndDlg, - _In_ PJOB_PAGE_CONTEXT Context - ) -{ - HANDLE jobHandle = NULL; - JOBOBJECT_BASIC_AND_IO_ACCOUNTING_INFORMATION basicAndIo; - JOBOBJECT_EXTENDED_LIMIT_INFORMATION extendedLimitInfo; - - Context->OpenObject( - &jobHandle, - JOB_OBJECT_QUERY, - Context->Context - ); - - if (jobHandle && NT_SUCCESS(PhGetJobBasicAndIoAccounting( - jobHandle, - &basicAndIo - ))) - { - WCHAR timeSpan[PH_TIMESPAN_STR_LEN_1]; - - SetDlgItemInt(hwndDlg, IDC_ZACTIVEPROCESSES_V, basicAndIo.BasicInfo.ActiveProcesses, FALSE); - SetDlgItemInt(hwndDlg, IDC_ZTOTALPROCESSES_V, basicAndIo.BasicInfo.TotalProcesses, FALSE); - SetDlgItemInt(hwndDlg, IDC_ZTERMINATEDPROCESSES_V, basicAndIo.BasicInfo.TotalTerminatedProcesses, FALSE); - - PhPrintTimeSpan(timeSpan, basicAndIo.BasicInfo.TotalUserTime.QuadPart, PH_TIMESPAN_HMSM); - SetDlgItemText(hwndDlg, IDC_ZUSERTIME_V, timeSpan); - PhPrintTimeSpan(timeSpan, basicAndIo.BasicInfo.TotalKernelTime.QuadPart, PH_TIMESPAN_HMSM); - SetDlgItemText(hwndDlg, IDC_ZKERNELTIME_V, timeSpan); - PhPrintTimeSpan(timeSpan, basicAndIo.BasicInfo.ThisPeriodTotalUserTime.QuadPart, PH_TIMESPAN_HMSM); - SetDlgItemText(hwndDlg, IDC_ZUSERTIMEPERIOD_V, timeSpan); - PhPrintTimeSpan(timeSpan, basicAndIo.BasicInfo.ThisPeriodTotalKernelTime.QuadPart, PH_TIMESPAN_HMSM); - SetDlgItemText(hwndDlg, IDC_ZKERNELTIMEPERIOD_V, timeSpan); - - SetDlgItemText(hwndDlg, IDC_ZPAGEFAULTS_V, PhaFormatUInt64(basicAndIo.BasicInfo.TotalPageFaultCount, TRUE)->Buffer); - - SetDlgItemText(hwndDlg, IDC_ZIOREADS_V, PhaFormatUInt64(basicAndIo.IoInfo.ReadOperationCount, TRUE)->Buffer); - SetDlgItemText(hwndDlg, IDC_ZIOREADBYTES_V, PhaFormatSize(basicAndIo.IoInfo.ReadTransferCount, -1)->Buffer); - SetDlgItemText(hwndDlg, IDC_ZIOWRITES_V, PhaFormatUInt64(basicAndIo.IoInfo.WriteOperationCount, TRUE)->Buffer); - SetDlgItemText(hwndDlg, IDC_ZIOWRITEBYTES_V, PhaFormatSize(basicAndIo.IoInfo.WriteTransferCount, -1)->Buffer); - SetDlgItemText(hwndDlg, IDC_ZIOOTHER_V, PhaFormatUInt64(basicAndIo.IoInfo.OtherOperationCount, TRUE)->Buffer); - SetDlgItemText(hwndDlg, IDC_ZIOOTHERBYTES_V, PhaFormatSize(basicAndIo.IoInfo.OtherTransferCount, -1)->Buffer); - } - else - { - SetDlgItemText(hwndDlg, IDC_ZACTIVEPROCESSES_V, L"Unknown"); - SetDlgItemText(hwndDlg, IDC_ZTOTALPROCESSES_V, L"Unknown"); - SetDlgItemText(hwndDlg, IDC_ZTERMINATEDPROCESSES_V, L"Unknown"); - - SetDlgItemText(hwndDlg, IDC_ZUSERTIME_V, L"Unknown"); - SetDlgItemText(hwndDlg, IDC_ZKERNELTIME_V, L"Unknown"); - SetDlgItemText(hwndDlg, IDC_ZUSERTIMEPERIOD_V, L"Unknown"); - SetDlgItemText(hwndDlg, IDC_ZKERNELTIMEPERIOD_V, L"Unknown"); - - SetDlgItemText(hwndDlg, IDC_ZPAGEFAULTS_V, L"Unknown"); - - SetDlgItemText(hwndDlg, IDC_ZIOREADS_V, L"Unknown"); - SetDlgItemText(hwndDlg, IDC_ZIOREADBYTES_V, L"Unknown"); - SetDlgItemText(hwndDlg, IDC_ZIOWRITES_V, L"Unknown"); - SetDlgItemText(hwndDlg, IDC_ZIOWRITEBYTES_V, L"Unknown"); - SetDlgItemText(hwndDlg, IDC_ZIOOTHER_V, L"Unknown"); - SetDlgItemText(hwndDlg, IDC_ZIOOTHERBYTES_V, L"Unknown"); - } - - if (jobHandle && NT_SUCCESS(PhGetJobExtendedLimits( - jobHandle, - &extendedLimitInfo - ))) - { - SetDlgItemText(hwndDlg, IDC_ZPEAKPROCESSUSAGE_V, PhaFormatSize(extendedLimitInfo.PeakProcessMemoryUsed, -1)->Buffer); - SetDlgItemText(hwndDlg, IDC_ZPEAKJOBUSAGE_V, PhaFormatSize(extendedLimitInfo.PeakJobMemoryUsed, -1)->Buffer); - } - else - { - SetDlgItemText(hwndDlg, IDC_ZPEAKPROCESSUSAGE_V, L"Unknown"); - SetDlgItemText(hwndDlg, IDC_ZPEAKJOBUSAGE_V, L"Unknown"); - } - - if (jobHandle) - NtClose(jobHandle); -} - -INT_PTR CALLBACK PhpJobStatisticsPageProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - PJOB_PAGE_CONTEXT jobPageContext; - - jobPageContext = PhpJobPageHeader(hwndDlg, uMsg, wParam, lParam); - - if (!jobPageContext) - return FALSE; - - switch (uMsg) - { - case WM_INITDIALOG: - { - // HACK - PhCenterWindow(GetParent(hwndDlg), GetParent(GetParent(hwndDlg))); - - PhpRefreshJobStatisticsInfo(hwndDlg, jobPageContext); - SetTimer(hwndDlg, 1, PhGetIntegerSetting(L"UpdateInterval"), NULL); - } - break; - case WM_TIMER: - { - if (wParam == 1) - { - PhpRefreshJobStatisticsInfo(hwndDlg, jobPageContext); - } - } - break; - } - - return FALSE; -} +/* + * Process Hacker - + * job properties + * + * Copyright (C) 2010 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include + +#include +#include + +#include +#include + +typedef struct _JOB_PAGE_CONTEXT +{ + PPH_OPEN_OBJECT OpenObject; + PVOID Context; + DLGPROC HookProc; +} JOB_PAGE_CONTEXT, *PJOB_PAGE_CONTEXT; + +INT CALLBACK PhpJobPropPageProc( + _In_ HWND hwnd, + _In_ UINT uMsg, + _In_ LPPROPSHEETPAGE ppsp + ); + +INT_PTR CALLBACK PhpJobPageProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +VOID PhpShowJobAdvancedProperties( + _In_ HWND ParentWindowHandle, + _In_ PJOB_PAGE_CONTEXT Context + ); + +INT_PTR CALLBACK PhpJobStatisticsPageProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +VOID PhShowJobProperties( + _In_ HWND ParentWindowHandle, + _In_ PPH_OPEN_OBJECT OpenObject, + _In_opt_ PVOID Context, + _In_opt_ PWSTR Title + ) +{ + PROPSHEETHEADER propSheetHeader = { sizeof(propSheetHeader) }; + HPROPSHEETPAGE pages[1]; + + propSheetHeader.dwFlags = + PSH_NOAPPLYNOW | + PSH_NOCONTEXTHELP | + PSH_PROPTITLE; + propSheetHeader.hwndParent = ParentWindowHandle; + propSheetHeader.pszCaption = Title ? Title : L"Job"; + propSheetHeader.nPages = 1; + propSheetHeader.nStartPage = 0; + propSheetHeader.phpage = pages; + + pages[0] = PhCreateJobPage(OpenObject, Context, NULL); + + PhModalPropertySheet(&propSheetHeader); +} + +HPROPSHEETPAGE PhCreateJobPage( + _In_ PPH_OPEN_OBJECT OpenObject, + _In_opt_ PVOID Context, + _In_opt_ DLGPROC HookProc + ) +{ + HPROPSHEETPAGE propSheetPageHandle; + PROPSHEETPAGE propSheetPage; + PJOB_PAGE_CONTEXT jobPageContext; + + jobPageContext = PhCreateAlloc(sizeof(JOB_PAGE_CONTEXT)); + memset(jobPageContext, 0, sizeof(JOB_PAGE_CONTEXT)); + jobPageContext->OpenObject = OpenObject; + jobPageContext->Context = Context; + jobPageContext->HookProc = HookProc; + + memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); + propSheetPage.dwSize = sizeof(PROPSHEETPAGE); + propSheetPage.dwFlags = PSP_USECALLBACK; + propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_OBJJOB); + propSheetPage.pfnDlgProc = PhpJobPageProc; + propSheetPage.lParam = (LPARAM)jobPageContext; + propSheetPage.pfnCallback = PhpJobPropPageProc; + + propSheetPageHandle = CreatePropertySheetPage(&propSheetPage); + // CreatePropertySheetPage would have sent PSPCB_ADDREF (below), + // which would have added a reference. + PhDereferenceObject(jobPageContext); + + return propSheetPageHandle; +} + +INT CALLBACK PhpJobPropPageProc( + _In_ HWND hwnd, + _In_ UINT uMsg, + _In_ LPPROPSHEETPAGE ppsp + ) +{ + PJOB_PAGE_CONTEXT jobPageContext; + + jobPageContext = (PJOB_PAGE_CONTEXT)ppsp->lParam; + + if (uMsg == PSPCB_ADDREF) + { + PhReferenceObject(jobPageContext); + } + else if (uMsg == PSPCB_RELEASE) + { + PhDereferenceObject(jobPageContext); + } + + return 1; +} + +FORCEINLINE PJOB_PAGE_CONTEXT PhpJobPageHeader( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + return (PJOB_PAGE_CONTEXT)PhpGenericPropertyPageHeader( + hwndDlg, uMsg, wParam, lParam, L"JobPageContext"); +} + +static VOID PhpAddLimit( + _In_ HWND Handle, + _In_ PWSTR Name, + _In_ PWSTR Value + ) +{ + INT lvItemIndex; + + lvItemIndex = PhAddListViewItem(Handle, MAXINT, Name, NULL); + PhSetListViewSubItem(Handle, lvItemIndex, 1, Value); +} + +static VOID PhpAddJobProcesses( + _In_ HWND hwndDlg, + _In_ HANDLE JobHandle + ) +{ + PJOBOBJECT_BASIC_PROCESS_ID_LIST processIdList; + HWND processesLv; + + processesLv = GetDlgItem(hwndDlg, IDC_PROCESSES); + + if (NT_SUCCESS(PhGetJobProcessIdList(JobHandle, &processIdList))) + { + ULONG i; + CLIENT_ID clientId; + PPH_STRING name; + + clientId.UniqueThread = NULL; + + for (i = 0; i < processIdList->NumberOfProcessIdsInList; i++) + { + clientId.UniqueProcess = (HANDLE)processIdList->ProcessIdList[i]; + name = PH_AUTO(PhGetClientIdName(&clientId)); + + PhAddListViewItem(processesLv, MAXINT, PhGetString(name), NULL); + } + + PhFree(processIdList); + } +} + +INT_PTR CALLBACK PhpJobPageProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + PJOB_PAGE_CONTEXT jobPageContext; + + jobPageContext = PhpJobPageHeader(hwndDlg, uMsg, wParam, lParam); + + if (!jobPageContext) + return FALSE; + + if (jobPageContext->HookProc) + { + if (jobPageContext->HookProc(hwndDlg, uMsg, wParam, lParam)) + return TRUE; + } + + switch (uMsg) + { + case WM_INITDIALOG: + { + HANDLE jobHandle; + HWND processesLv; + HWND limitsLv; + + processesLv = GetDlgItem(hwndDlg, IDC_PROCESSES); + limitsLv = GetDlgItem(hwndDlg, IDC_LIMITS); + PhSetListViewStyle(processesLv, FALSE, TRUE); + PhSetListViewStyle(limitsLv, FALSE, TRUE); + PhSetControlTheme(processesLv, L"explorer"); + PhSetControlTheme(limitsLv, L"explorer"); + + PhAddListViewColumn(processesLv, 0, 0, 0, LVCFMT_LEFT, 240, L"Name"); + + PhAddListViewColumn(limitsLv, 0, 0, 0, LVCFMT_LEFT, 120, L"Name"); + PhAddListViewColumn(limitsLv, 1, 1, 1, LVCFMT_LEFT, 160, L"Value"); + PhLoadListViewColumnsFromSetting(L"JobListViewColumns", limitsLv); + + SetDlgItemText(hwndDlg, IDC_NAME, L"Unknown"); + + if (NT_SUCCESS(jobPageContext->OpenObject( + &jobHandle, + JOB_OBJECT_QUERY, + jobPageContext->Context + ))) + { + PPH_STRING jobObjectName = NULL; + JOBOBJECT_EXTENDED_LIMIT_INFORMATION extendedLimits; + JOBOBJECT_BASIC_UI_RESTRICTIONS basicUiRestrictions; + + // Name + + PhGetHandleInformation( + NtCurrentProcess(), + jobHandle, + -1, + NULL, + NULL, + NULL, + &jobObjectName + ); + PH_AUTO(jobObjectName); + + if (jobObjectName && jobObjectName->Length == 0) + jobObjectName = NULL; + + SetDlgItemText(hwndDlg, IDC_NAME, PhGetStringOrDefault(jobObjectName, L"(unnamed job)")); + + // Processes + PhpAddJobProcesses(hwndDlg, jobHandle); + + // Limits + + if (NT_SUCCESS(PhGetJobExtendedLimits(jobHandle, &extendedLimits))) + { + ULONG flags = extendedLimits.BasicLimitInformation.LimitFlags; + + if (flags & JOB_OBJECT_LIMIT_ACTIVE_PROCESS) + { + WCHAR value[PH_INT32_STR_LEN_1]; + PhPrintUInt32(value, extendedLimits.BasicLimitInformation.ActiveProcessLimit); + PhpAddLimit(limitsLv, L"Active processes", value); + } + + if (flags & JOB_OBJECT_LIMIT_AFFINITY) + { + WCHAR value[PH_PTR_STR_LEN_1]; + PhPrintPointer(value, (PVOID)extendedLimits.BasicLimitInformation.Affinity); + PhpAddLimit(limitsLv, L"Affinity", value); + } + + if (flags & JOB_OBJECT_LIMIT_BREAKAWAY_OK) + { + PhpAddLimit(limitsLv, L"Breakaway OK", L"Enabled"); + } + + if (flags & JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION) + { + PhpAddLimit(limitsLv, L"Die on unhandled exception", L"Enabled"); + } + + if (flags & JOB_OBJECT_LIMIT_JOB_MEMORY) + { + PPH_STRING value = PhaFormatSize(extendedLimits.JobMemoryLimit, -1); + PhpAddLimit(limitsLv, L"Job memory", value->Buffer); + } + + if (flags & JOB_OBJECT_LIMIT_JOB_TIME) + { + WCHAR value[PH_TIMESPAN_STR_LEN_1]; + PhPrintTimeSpan(value, extendedLimits.BasicLimitInformation.PerJobUserTimeLimit.QuadPart, + PH_TIMESPAN_DHMS); + PhpAddLimit(limitsLv, L"Job time", value); + } + + if (flags & JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE) + { + PhpAddLimit(limitsLv, L"Kill on job close", L"Enabled"); + } + + if (flags & JOB_OBJECT_LIMIT_PRIORITY_CLASS) + { + PhpAddLimit(limitsLv, L"Priority class", + PhGetProcessPriorityClassString(extendedLimits.BasicLimitInformation.PriorityClass)); + } + + if (flags & JOB_OBJECT_LIMIT_PROCESS_MEMORY) + { + PPH_STRING value = PhaFormatSize(extendedLimits.ProcessMemoryLimit, -1); + PhpAddLimit(limitsLv, L"Process memory", value->Buffer); + } + + if (flags & JOB_OBJECT_LIMIT_PROCESS_TIME) + { + WCHAR value[PH_TIMESPAN_STR_LEN_1]; + PhPrintTimeSpan(value, extendedLimits.BasicLimitInformation.PerProcessUserTimeLimit.QuadPart, + PH_TIMESPAN_DHMS); + PhpAddLimit(limitsLv, L"Process time", value); + } + + if (flags & JOB_OBJECT_LIMIT_SCHEDULING_CLASS) + { + WCHAR value[PH_INT32_STR_LEN_1]; + PhPrintUInt32(value, extendedLimits.BasicLimitInformation.SchedulingClass); + PhpAddLimit(limitsLv, L"Scheduling class", value); + } + + if (flags & JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK) + { + PhpAddLimit(limitsLv, L"Silent breakaway OK", L"Enabled"); + } + + if (flags & JOB_OBJECT_LIMIT_WORKINGSET) + { + PPH_STRING value; + + value = PhaFormatSize(extendedLimits.BasicLimitInformation.MinimumWorkingSetSize, -1); + PhpAddLimit(limitsLv, L"Working set minimum", value->Buffer); + + value = PhaFormatSize(extendedLimits.BasicLimitInformation.MaximumWorkingSetSize, -1); + PhpAddLimit(limitsLv, L"Working set maximum", value->Buffer); + } + } + + if (NT_SUCCESS(PhGetJobBasicUiRestrictions(jobHandle, &basicUiRestrictions))) + { + ULONG flags = basicUiRestrictions.UIRestrictionsClass; + + if (flags & JOB_OBJECT_UILIMIT_DESKTOP) + PhpAddLimit(limitsLv, L"Desktop", L"Limited"); + if (flags & JOB_OBJECT_UILIMIT_DISPLAYSETTINGS) + PhpAddLimit(limitsLv, L"Display settings", L"Limited"); + if (flags & JOB_OBJECT_UILIMIT_EXITWINDOWS) + PhpAddLimit(limitsLv, L"Exit windows", L"Limited"); + if (flags & JOB_OBJECT_UILIMIT_GLOBALATOMS) + PhpAddLimit(limitsLv, L"Global atoms", L"Limited"); + if (flags & JOB_OBJECT_UILIMIT_HANDLES) + PhpAddLimit(limitsLv, L"Handles", L"Limited"); + if (flags & JOB_OBJECT_UILIMIT_READCLIPBOARD) + PhpAddLimit(limitsLv, L"Read clipboard", L"Limited"); + if (flags & JOB_OBJECT_UILIMIT_SYSTEMPARAMETERS) + PhpAddLimit(limitsLv, L"System parameters", L"Limited"); + if (flags & JOB_OBJECT_UILIMIT_WRITECLIPBOARD) + PhpAddLimit(limitsLv, L"Write clipboard", L"Limited"); + } + + NtClose(jobHandle); + } + } + break; + case WM_DESTROY: + PhSaveListViewColumnsToSetting(L"JobListViewColumns", GetDlgItem(hwndDlg, IDC_LIMITS)); + break; + case WM_COMMAND: + { + switch (LOWORD(wParam)) + { + case IDC_TERMINATE: + { + if (PhShowConfirmMessage( + hwndDlg, + L"terminate", + L"the job", + L"Terminating a job will terminate all processes assigned to it.", + TRUE + )) + { + NTSTATUS status; + HANDLE jobHandle; + + if (NT_SUCCESS(status = jobPageContext->OpenObject( + &jobHandle, + JOB_OBJECT_TERMINATE, + jobPageContext->Context + ))) + { + status = NtTerminateJobObject(jobHandle, STATUS_SUCCESS); + NtClose(jobHandle); + } + + if (!NT_SUCCESS(status)) + PhShowStatus(hwndDlg, L"Unable to terminate the job", status, 0); + } + } + break; + case IDC_ADD: + { + NTSTATUS status; + HANDLE processId; + HANDLE processHandle; + HANDLE jobHandle; + + while (PhShowChooseProcessDialog( + hwndDlg, + L"Select a process to add to the job permanently.", + &processId + )) + { + if (NT_SUCCESS(status = PhOpenProcess( + &processHandle, + PROCESS_TERMINATE | PROCESS_SET_QUOTA, + processId + ))) + { + if (NT_SUCCESS(status = jobPageContext->OpenObject( + &jobHandle, + JOB_OBJECT_ASSIGN_PROCESS | JOB_OBJECT_QUERY, + jobPageContext->Context + ))) + { + status = NtAssignProcessToJobObject(jobHandle, processHandle); + + if (NT_SUCCESS(status)) + { + ListView_DeleteAllItems(GetDlgItem(hwndDlg, IDC_PROCESSES)); + PhpAddJobProcesses(hwndDlg, jobHandle); + } + + NtClose(jobHandle); + } + + NtClose(processHandle); + } + + if (NT_SUCCESS(status)) + break; + else + PhShowStatus(hwndDlg, L"Unable to add the process to the job", status, 0); + } + } + break; + case IDC_ADVANCED: + { + PhpShowJobAdvancedProperties(hwndDlg, jobPageContext); + } + break; + } + } + break; + case WM_NOTIFY: + { + PhHandleListViewNotifyBehaviors(lParam, GetDlgItem(hwndDlg, IDC_PROCESSES), PH_LIST_VIEW_DEFAULT_1_BEHAVIORS); + PhHandleListViewNotifyBehaviors(lParam, GetDlgItem(hwndDlg, IDC_LIMITS), PH_LIST_VIEW_DEFAULT_1_BEHAVIORS); + } + break; + } + + return FALSE; +} + +VOID PhpShowJobAdvancedProperties( + _In_ HWND ParentWindowHandle, + _In_ PJOB_PAGE_CONTEXT Context + ) +{ + PROPSHEETHEADER propSheetHeader = { sizeof(propSheetHeader) }; + HPROPSHEETPAGE pages[2]; + PROPSHEETPAGE statisticsPage; + PH_STD_OBJECT_SECURITY stdObjectSecurity; + PPH_ACCESS_ENTRY accessEntries; + ULONG numberOfAccessEntries; + + propSheetHeader.dwFlags = + PSH_NOAPPLYNOW | + PSH_NOCONTEXTHELP | + PSH_PROPTITLE; + propSheetHeader.hwndParent = ParentWindowHandle; + propSheetHeader.pszCaption = L"Job"; + propSheetHeader.nPages = 2; + propSheetHeader.nStartPage = 0; + propSheetHeader.phpage = pages; + + // General + + memset(&statisticsPage, 0, sizeof(PROPSHEETPAGE)); + statisticsPage.dwSize = sizeof(PROPSHEETPAGE); + statisticsPage.pszTemplate = MAKEINTRESOURCE(IDD_JOBSTATISTICS); + statisticsPage.pfnDlgProc = PhpJobStatisticsPageProc; + statisticsPage.lParam = (LPARAM)Context; + pages[0] = CreatePropertySheetPage(&statisticsPage); + + // Security + + stdObjectSecurity.OpenObject = Context->OpenObject; + stdObjectSecurity.ObjectType = L"Job"; + stdObjectSecurity.Context = Context->Context; + + if (PhGetAccessEntries(L"Job", &accessEntries, &numberOfAccessEntries)) + { + pages[1] = PhCreateSecurityPage( + L"Job", + PhStdGetObjectSecurity, + PhStdSetObjectSecurity, + &stdObjectSecurity, + accessEntries, + numberOfAccessEntries + ); + PhFree(accessEntries); + } + + PhModalPropertySheet(&propSheetHeader); +} + +static VOID PhpRefreshJobStatisticsInfo( + _In_ HWND hwndDlg, + _In_ PJOB_PAGE_CONTEXT Context + ) +{ + HANDLE jobHandle = NULL; + JOBOBJECT_BASIC_AND_IO_ACCOUNTING_INFORMATION basicAndIo; + JOBOBJECT_EXTENDED_LIMIT_INFORMATION extendedLimitInfo; + + Context->OpenObject( + &jobHandle, + JOB_OBJECT_QUERY, + Context->Context + ); + + if (jobHandle && NT_SUCCESS(PhGetJobBasicAndIoAccounting( + jobHandle, + &basicAndIo + ))) + { + WCHAR timeSpan[PH_TIMESPAN_STR_LEN_1]; + + SetDlgItemInt(hwndDlg, IDC_ZACTIVEPROCESSES_V, basicAndIo.BasicInfo.ActiveProcesses, FALSE); + SetDlgItemInt(hwndDlg, IDC_ZTOTALPROCESSES_V, basicAndIo.BasicInfo.TotalProcesses, FALSE); + SetDlgItemInt(hwndDlg, IDC_ZTERMINATEDPROCESSES_V, basicAndIo.BasicInfo.TotalTerminatedProcesses, FALSE); + + PhPrintTimeSpan(timeSpan, basicAndIo.BasicInfo.TotalUserTime.QuadPart, PH_TIMESPAN_HMSM); + SetDlgItemText(hwndDlg, IDC_ZUSERTIME_V, timeSpan); + PhPrintTimeSpan(timeSpan, basicAndIo.BasicInfo.TotalKernelTime.QuadPart, PH_TIMESPAN_HMSM); + SetDlgItemText(hwndDlg, IDC_ZKERNELTIME_V, timeSpan); + PhPrintTimeSpan(timeSpan, basicAndIo.BasicInfo.ThisPeriodTotalUserTime.QuadPart, PH_TIMESPAN_HMSM); + SetDlgItemText(hwndDlg, IDC_ZUSERTIMEPERIOD_V, timeSpan); + PhPrintTimeSpan(timeSpan, basicAndIo.BasicInfo.ThisPeriodTotalKernelTime.QuadPart, PH_TIMESPAN_HMSM); + SetDlgItemText(hwndDlg, IDC_ZKERNELTIMEPERIOD_V, timeSpan); + + SetDlgItemText(hwndDlg, IDC_ZPAGEFAULTS_V, PhaFormatUInt64(basicAndIo.BasicInfo.TotalPageFaultCount, TRUE)->Buffer); + + SetDlgItemText(hwndDlg, IDC_ZIOREADS_V, PhaFormatUInt64(basicAndIo.IoInfo.ReadOperationCount, TRUE)->Buffer); + SetDlgItemText(hwndDlg, IDC_ZIOREADBYTES_V, PhaFormatSize(basicAndIo.IoInfo.ReadTransferCount, -1)->Buffer); + SetDlgItemText(hwndDlg, IDC_ZIOWRITES_V, PhaFormatUInt64(basicAndIo.IoInfo.WriteOperationCount, TRUE)->Buffer); + SetDlgItemText(hwndDlg, IDC_ZIOWRITEBYTES_V, PhaFormatSize(basicAndIo.IoInfo.WriteTransferCount, -1)->Buffer); + SetDlgItemText(hwndDlg, IDC_ZIOOTHER_V, PhaFormatUInt64(basicAndIo.IoInfo.OtherOperationCount, TRUE)->Buffer); + SetDlgItemText(hwndDlg, IDC_ZIOOTHERBYTES_V, PhaFormatSize(basicAndIo.IoInfo.OtherTransferCount, -1)->Buffer); + } + else + { + SetDlgItemText(hwndDlg, IDC_ZACTIVEPROCESSES_V, L"Unknown"); + SetDlgItemText(hwndDlg, IDC_ZTOTALPROCESSES_V, L"Unknown"); + SetDlgItemText(hwndDlg, IDC_ZTERMINATEDPROCESSES_V, L"Unknown"); + + SetDlgItemText(hwndDlg, IDC_ZUSERTIME_V, L"Unknown"); + SetDlgItemText(hwndDlg, IDC_ZKERNELTIME_V, L"Unknown"); + SetDlgItemText(hwndDlg, IDC_ZUSERTIMEPERIOD_V, L"Unknown"); + SetDlgItemText(hwndDlg, IDC_ZKERNELTIMEPERIOD_V, L"Unknown"); + + SetDlgItemText(hwndDlg, IDC_ZPAGEFAULTS_V, L"Unknown"); + + SetDlgItemText(hwndDlg, IDC_ZIOREADS_V, L"Unknown"); + SetDlgItemText(hwndDlg, IDC_ZIOREADBYTES_V, L"Unknown"); + SetDlgItemText(hwndDlg, IDC_ZIOWRITES_V, L"Unknown"); + SetDlgItemText(hwndDlg, IDC_ZIOWRITEBYTES_V, L"Unknown"); + SetDlgItemText(hwndDlg, IDC_ZIOOTHER_V, L"Unknown"); + SetDlgItemText(hwndDlg, IDC_ZIOOTHERBYTES_V, L"Unknown"); + } + + if (jobHandle && NT_SUCCESS(PhGetJobExtendedLimits( + jobHandle, + &extendedLimitInfo + ))) + { + SetDlgItemText(hwndDlg, IDC_ZPEAKPROCESSUSAGE_V, PhaFormatSize(extendedLimitInfo.PeakProcessMemoryUsed, -1)->Buffer); + SetDlgItemText(hwndDlg, IDC_ZPEAKJOBUSAGE_V, PhaFormatSize(extendedLimitInfo.PeakJobMemoryUsed, -1)->Buffer); + } + else + { + SetDlgItemText(hwndDlg, IDC_ZPEAKPROCESSUSAGE_V, L"Unknown"); + SetDlgItemText(hwndDlg, IDC_ZPEAKJOBUSAGE_V, L"Unknown"); + } + + if (jobHandle) + NtClose(jobHandle); +} + +INT_PTR CALLBACK PhpJobStatisticsPageProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + PJOB_PAGE_CONTEXT jobPageContext; + + jobPageContext = PhpJobPageHeader(hwndDlg, uMsg, wParam, lParam); + + if (!jobPageContext) + return FALSE; + + switch (uMsg) + { + case WM_INITDIALOG: + { + // HACK + PhCenterWindow(GetParent(hwndDlg), GetParent(GetParent(hwndDlg))); + + PhpRefreshJobStatisticsInfo(hwndDlg, jobPageContext); + SetTimer(hwndDlg, 1, PhGetIntegerSetting(L"UpdateInterval"), NULL); + } + break; + case WM_TIMER: + { + if (wParam == 1) + { + PhpRefreshJobStatisticsInfo(hwndDlg, jobPageContext); + } + } + break; + } + + return FALSE; +} diff --git a/ProcessHacker/log.c b/ProcessHacker/log.c index 64e799ae92a0..a57862b1c614 100644 --- a/ProcessHacker/log.c +++ b/ProcessHacker/log.c @@ -1,240 +1,240 @@ -/* - * Process Hacker - - * logging system - * - * Copyright (C) 2010-2016 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include - -#include - -PH_CIRCULAR_BUFFER_PVOID PhLogBuffer; -PHAPPAPI PH_CALLBACK_DECLARE(PhLoggedCallback); - -VOID PhLogInitialization( - VOID - ) -{ - ULONG entries; - - entries = PhGetIntegerSetting(L"LogEntries"); - if (entries > 0x1000) entries = 0x1000; - PhInitializeCircularBuffer_PVOID(&PhLogBuffer, entries); - memset(PhLogBuffer.Data, 0, sizeof(PVOID) * PhLogBuffer.Size); -} - -PPH_LOG_ENTRY PhpCreateLogEntry( - _In_ UCHAR Type - ) -{ - PPH_LOG_ENTRY entry; - - entry = PhAllocate(sizeof(PH_LOG_ENTRY)); - memset(entry, 0, sizeof(PH_LOG_ENTRY)); - - entry->Type = Type; - PhQuerySystemTime(&entry->Time); - - return entry; -} - -VOID PhpFreeLogEntry( - _Inout_ PPH_LOG_ENTRY Entry - ) -{ - if (Entry->Type >= PH_LOG_ENTRY_PROCESS_FIRST && Entry->Type <= PH_LOG_ENTRY_PROCESS_LAST) - { - PhDereferenceObject(Entry->Process.Name); - if (Entry->Process.ParentName) PhDereferenceObject(Entry->Process.ParentName); - } - else if (Entry->Type >= PH_LOG_ENTRY_SERVICE_FIRST && Entry->Type <= PH_LOG_ENTRY_SERVICE_LAST) - { - PhDereferenceObject(Entry->Service.Name); - PhDereferenceObject(Entry->Service.DisplayName); - } - else if (Entry->Type == PH_LOG_ENTRY_MESSAGE) - { - PhDereferenceObject(Entry->Message); - } - - PhFree(Entry); -} - -PPH_LOG_ENTRY PhpCreateProcessLogEntry( - _In_ UCHAR Type, - _In_ HANDLE ProcessId, - _In_opt_ HANDLE QueryHandle, - _In_ PPH_STRING Name, - _In_opt_ HANDLE ParentProcessId, - _In_opt_ PPH_STRING ParentName - ) -{ - PPH_LOG_ENTRY entry; - - entry = PhpCreateLogEntry(Type); - entry->Process.ProcessId = ProcessId; - PhReferenceObject(Name); - entry->Process.Name = Name; - - entry->Process.ParentProcessId = ParentProcessId; - - if (ParentName) - { - PhReferenceObject(ParentName); - entry->Process.ParentName = ParentName; - } - - if (QueryHandle && entry->Type == PH_LOG_ENTRY_PROCESS_DELETE) - { - PROCESS_BASIC_INFORMATION basicInfo; - - if (NT_SUCCESS(PhGetProcessBasicInformation(QueryHandle, &basicInfo))) - { - entry->Process.ExitStatus = basicInfo.ExitStatus; - } - } - - return entry; -} - -PPH_LOG_ENTRY PhpCreateServiceLogEntry( - _In_ UCHAR Type, - _In_ PPH_STRING Name, - _In_ PPH_STRING DisplayName - ) -{ - PPH_LOG_ENTRY entry; - - entry = PhpCreateLogEntry(Type); - PhReferenceObject(Name); - entry->Service.Name = Name; - PhReferenceObject(DisplayName); - entry->Service.DisplayName = DisplayName; - - return entry; -} - -PPH_LOG_ENTRY PhpCreateMessageLogEntry( - _In_ UCHAR Type, - _In_ PPH_STRING Message - ) -{ - PPH_LOG_ENTRY entry; - - entry = PhpCreateLogEntry(Type); - PhReferenceObject(Message); - entry->Message = Message; - - return entry; -} - -VOID PhpLogEntry( - _In_ PPH_LOG_ENTRY Entry - ) -{ - PPH_LOG_ENTRY oldEntry; - - oldEntry = PhAddItemCircularBuffer2_PVOID(&PhLogBuffer, Entry); - - if (oldEntry) - PhpFreeLogEntry(oldEntry); - - PhInvokeCallback(&PhLoggedCallback, Entry); -} - -VOID PhClearLogEntries( - VOID - ) -{ - ULONG i; - - for (i = 0; i < PhLogBuffer.Size; i++) - { - if (PhLogBuffer.Data[i]) - PhpFreeLogEntry(PhLogBuffer.Data[i]); - } - - PhClearCircularBuffer_PVOID(&PhLogBuffer); - memset(PhLogBuffer.Data, 0, sizeof(PVOID) * PhLogBuffer.Size); -} - -VOID PhLogProcessEntry( - _In_ UCHAR Type, - _In_ HANDLE ProcessId, - _In_opt_ HANDLE QueryHandle, - _In_ PPH_STRING Name, - _In_opt_ HANDLE ParentProcessId, - _In_opt_ PPH_STRING ParentName - ) -{ - PhpLogEntry(PhpCreateProcessLogEntry(Type, ProcessId, QueryHandle, Name, ParentProcessId, ParentName)); -} - -VOID PhLogServiceEntry( - _In_ UCHAR Type, - _In_ PPH_STRING Name, - _In_ PPH_STRING DisplayName - ) -{ - PhpLogEntry(PhpCreateServiceLogEntry(Type, Name, DisplayName)); -} - -VOID PhLogMessageEntry( - _In_ UCHAR Type, - _In_ PPH_STRING Message - ) -{ - PhpLogEntry(PhpCreateMessageLogEntry(Type, Message)); -} - -PPH_STRING PhFormatLogEntry( - _In_ PPH_LOG_ENTRY Entry - ) -{ - switch (Entry->Type) - { - case PH_LOG_ENTRY_PROCESS_CREATE: - return PhFormatString( - L"Process created: %s (%u) started by %s (%u)", - Entry->Process.Name->Buffer, - HandleToUlong(Entry->Process.ProcessId), - PhGetStringOrDefault(Entry->Process.ParentName, L"Unknown process"), - HandleToUlong(Entry->Process.ParentProcessId) - ); - case PH_LOG_ENTRY_PROCESS_DELETE: - return PhFormatString(L"Process terminated: %s (%u); exit status 0x%x", Entry->Process.Name->Buffer, HandleToUlong(Entry->Process.ProcessId), Entry->Process.ExitStatus); - case PH_LOG_ENTRY_SERVICE_CREATE: - return PhFormatString(L"Service created: %s (%s)", Entry->Service.Name->Buffer, Entry->Service.DisplayName->Buffer); - case PH_LOG_ENTRY_SERVICE_DELETE: - return PhFormatString(L"Service deleted: %s (%s)", Entry->Service.Name->Buffer, Entry->Service.DisplayName->Buffer); - case PH_LOG_ENTRY_SERVICE_START: - return PhFormatString(L"Service started: %s (%s)", Entry->Service.Name->Buffer, Entry->Service.DisplayName->Buffer); - case PH_LOG_ENTRY_SERVICE_STOP: - return PhFormatString(L"Service stopped: %s (%s)", Entry->Service.Name->Buffer, Entry->Service.DisplayName->Buffer); - case PH_LOG_ENTRY_SERVICE_CONTINUE: - return PhFormatString(L"Service continued: %s (%s)", Entry->Service.Name->Buffer, Entry->Service.DisplayName->Buffer); - case PH_LOG_ENTRY_SERVICE_PAUSE: - return PhFormatString(L"Service paused: %s (%s)", Entry->Service.Name->Buffer, Entry->Service.DisplayName->Buffer); - case PH_LOG_ENTRY_MESSAGE: - PhReferenceObject(Entry->Message); - return Entry->Message; - default: - return PhReferenceEmptyString(); - } -} +/* + * Process Hacker - + * logging system + * + * Copyright (C) 2010-2016 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include + +#include + +PH_CIRCULAR_BUFFER_PVOID PhLogBuffer; +PHAPPAPI PH_CALLBACK_DECLARE(PhLoggedCallback); + +VOID PhLogInitialization( + VOID + ) +{ + ULONG entries; + + entries = PhGetIntegerSetting(L"LogEntries"); + if (entries > 0x1000) entries = 0x1000; + PhInitializeCircularBuffer_PVOID(&PhLogBuffer, entries); + memset(PhLogBuffer.Data, 0, sizeof(PVOID) * PhLogBuffer.Size); +} + +PPH_LOG_ENTRY PhpCreateLogEntry( + _In_ UCHAR Type + ) +{ + PPH_LOG_ENTRY entry; + + entry = PhAllocate(sizeof(PH_LOG_ENTRY)); + memset(entry, 0, sizeof(PH_LOG_ENTRY)); + + entry->Type = Type; + PhQuerySystemTime(&entry->Time); + + return entry; +} + +VOID PhpFreeLogEntry( + _Inout_ PPH_LOG_ENTRY Entry + ) +{ + if (Entry->Type >= PH_LOG_ENTRY_PROCESS_FIRST && Entry->Type <= PH_LOG_ENTRY_PROCESS_LAST) + { + PhDereferenceObject(Entry->Process.Name); + if (Entry->Process.ParentName) PhDereferenceObject(Entry->Process.ParentName); + } + else if (Entry->Type >= PH_LOG_ENTRY_SERVICE_FIRST && Entry->Type <= PH_LOG_ENTRY_SERVICE_LAST) + { + PhDereferenceObject(Entry->Service.Name); + PhDereferenceObject(Entry->Service.DisplayName); + } + else if (Entry->Type == PH_LOG_ENTRY_MESSAGE) + { + PhDereferenceObject(Entry->Message); + } + + PhFree(Entry); +} + +PPH_LOG_ENTRY PhpCreateProcessLogEntry( + _In_ UCHAR Type, + _In_ HANDLE ProcessId, + _In_opt_ HANDLE QueryHandle, + _In_ PPH_STRING Name, + _In_opt_ HANDLE ParentProcessId, + _In_opt_ PPH_STRING ParentName + ) +{ + PPH_LOG_ENTRY entry; + + entry = PhpCreateLogEntry(Type); + entry->Process.ProcessId = ProcessId; + PhReferenceObject(Name); + entry->Process.Name = Name; + + entry->Process.ParentProcessId = ParentProcessId; + + if (ParentName) + { + PhReferenceObject(ParentName); + entry->Process.ParentName = ParentName; + } + + if (QueryHandle && entry->Type == PH_LOG_ENTRY_PROCESS_DELETE) + { + PROCESS_BASIC_INFORMATION basicInfo; + + if (NT_SUCCESS(PhGetProcessBasicInformation(QueryHandle, &basicInfo))) + { + entry->Process.ExitStatus = basicInfo.ExitStatus; + } + } + + return entry; +} + +PPH_LOG_ENTRY PhpCreateServiceLogEntry( + _In_ UCHAR Type, + _In_ PPH_STRING Name, + _In_ PPH_STRING DisplayName + ) +{ + PPH_LOG_ENTRY entry; + + entry = PhpCreateLogEntry(Type); + PhReferenceObject(Name); + entry->Service.Name = Name; + PhReferenceObject(DisplayName); + entry->Service.DisplayName = DisplayName; + + return entry; +} + +PPH_LOG_ENTRY PhpCreateMessageLogEntry( + _In_ UCHAR Type, + _In_ PPH_STRING Message + ) +{ + PPH_LOG_ENTRY entry; + + entry = PhpCreateLogEntry(Type); + PhReferenceObject(Message); + entry->Message = Message; + + return entry; +} + +VOID PhpLogEntry( + _In_ PPH_LOG_ENTRY Entry + ) +{ + PPH_LOG_ENTRY oldEntry; + + oldEntry = PhAddItemCircularBuffer2_PVOID(&PhLogBuffer, Entry); + + if (oldEntry) + PhpFreeLogEntry(oldEntry); + + PhInvokeCallback(&PhLoggedCallback, Entry); +} + +VOID PhClearLogEntries( + VOID + ) +{ + ULONG i; + + for (i = 0; i < PhLogBuffer.Size; i++) + { + if (PhLogBuffer.Data[i]) + PhpFreeLogEntry(PhLogBuffer.Data[i]); + } + + PhClearCircularBuffer_PVOID(&PhLogBuffer); + memset(PhLogBuffer.Data, 0, sizeof(PVOID) * PhLogBuffer.Size); +} + +VOID PhLogProcessEntry( + _In_ UCHAR Type, + _In_ HANDLE ProcessId, + _In_opt_ HANDLE QueryHandle, + _In_ PPH_STRING Name, + _In_opt_ HANDLE ParentProcessId, + _In_opt_ PPH_STRING ParentName + ) +{ + PhpLogEntry(PhpCreateProcessLogEntry(Type, ProcessId, QueryHandle, Name, ParentProcessId, ParentName)); +} + +VOID PhLogServiceEntry( + _In_ UCHAR Type, + _In_ PPH_STRING Name, + _In_ PPH_STRING DisplayName + ) +{ + PhpLogEntry(PhpCreateServiceLogEntry(Type, Name, DisplayName)); +} + +VOID PhLogMessageEntry( + _In_ UCHAR Type, + _In_ PPH_STRING Message + ) +{ + PhpLogEntry(PhpCreateMessageLogEntry(Type, Message)); +} + +PPH_STRING PhFormatLogEntry( + _In_ PPH_LOG_ENTRY Entry + ) +{ + switch (Entry->Type) + { + case PH_LOG_ENTRY_PROCESS_CREATE: + return PhFormatString( + L"Process created: %s (%u) started by %s (%u)", + Entry->Process.Name->Buffer, + HandleToUlong(Entry->Process.ProcessId), + PhGetStringOrDefault(Entry->Process.ParentName, L"Unknown process"), + HandleToUlong(Entry->Process.ParentProcessId) + ); + case PH_LOG_ENTRY_PROCESS_DELETE: + return PhFormatString(L"Process terminated: %s (%u); exit status 0x%x", Entry->Process.Name->Buffer, HandleToUlong(Entry->Process.ProcessId), Entry->Process.ExitStatus); + case PH_LOG_ENTRY_SERVICE_CREATE: + return PhFormatString(L"Service created: %s (%s)", Entry->Service.Name->Buffer, Entry->Service.DisplayName->Buffer); + case PH_LOG_ENTRY_SERVICE_DELETE: + return PhFormatString(L"Service deleted: %s (%s)", Entry->Service.Name->Buffer, Entry->Service.DisplayName->Buffer); + case PH_LOG_ENTRY_SERVICE_START: + return PhFormatString(L"Service started: %s (%s)", Entry->Service.Name->Buffer, Entry->Service.DisplayName->Buffer); + case PH_LOG_ENTRY_SERVICE_STOP: + return PhFormatString(L"Service stopped: %s (%s)", Entry->Service.Name->Buffer, Entry->Service.DisplayName->Buffer); + case PH_LOG_ENTRY_SERVICE_CONTINUE: + return PhFormatString(L"Service continued: %s (%s)", Entry->Service.Name->Buffer, Entry->Service.DisplayName->Buffer); + case PH_LOG_ENTRY_SERVICE_PAUSE: + return PhFormatString(L"Service paused: %s (%s)", Entry->Service.Name->Buffer, Entry->Service.DisplayName->Buffer); + case PH_LOG_ENTRY_MESSAGE: + PhReferenceObject(Entry->Message); + return Entry->Message; + default: + return PhReferenceEmptyString(); + } +} diff --git a/ProcessHacker/logwnd.c b/ProcessHacker/logwnd.c index 4c598eaa8e65..d35acede54ac 100644 --- a/ProcessHacker/logwnd.c +++ b/ProcessHacker/logwnd.c @@ -1,356 +1,356 @@ -/* - * Process Hacker - - * log window - * - * Copyright (C) 2010-2016 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include - -#include - -#include - -#define WM_PH_LOG_UPDATED (WM_APP + 300) - -INT_PTR CALLBACK PhpLogDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -HWND PhLogWindowHandle = NULL; -static PH_LAYOUT_MANAGER WindowLayoutManager; -static RECT MinimumSize; -static HWND ListViewHandle; -static ULONG ListViewCount; -static PH_CALLBACK_REGISTRATION LoggedRegistration; - -VOID PhShowLogDialog( - VOID - ) -{ - if (!PhLogWindowHandle) - { - PhLogWindowHandle = CreateDialog( - PhInstanceHandle, - MAKEINTRESOURCE(IDD_LOG), - PhMainWndHandle, - PhpLogDlgProc - ); - PhRegisterDialog(PhLogWindowHandle); - ShowWindow(PhLogWindowHandle, SW_SHOW); - } - - if (IsIconic(PhLogWindowHandle)) - ShowWindow(PhLogWindowHandle, SW_RESTORE); - else - SetForegroundWindow(PhLogWindowHandle); -} - -static VOID NTAPI LoggedCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - PostMessage(PhLogWindowHandle, WM_PH_LOG_UPDATED, 0, 0); -} - -static VOID PhpUpdateLogList( - VOID - ) -{ - ListViewCount = PhLogBuffer.Count; - ListView_SetItemCountEx(ListViewHandle, ListViewCount, LVSICF_NOSCROLL); - - if (ListViewCount >= 2 && Button_GetCheck(GetDlgItem(PhLogWindowHandle, IDC_AUTOSCROLL)) == BST_CHECKED) - { - if (ListView_IsItemVisible(ListViewHandle, ListViewCount - 2)) - { - ListView_EnsureVisible(ListViewHandle, ListViewCount - 1, FALSE); - } - } -} - -static PPH_STRING PhpGetStringForSelectedLogEntries( - _In_ BOOLEAN All - ) -{ - PH_STRING_BUILDER stringBuilder; - ULONG i; - - if (ListViewCount == 0) - return PhReferenceEmptyString(); - - PhInitializeStringBuilder(&stringBuilder, 0x100); - - i = ListViewCount - 1; - - while (TRUE) - { - PPH_LOG_ENTRY entry; - SYSTEMTIME systemTime; - PPH_STRING temp; - - if (!All) - { - // The list view displays the items in reverse order... - if (!(ListView_GetItemState(ListViewHandle, ListViewCount - i - 1, LVIS_SELECTED) & LVIS_SELECTED)) - { - goto ContinueLoop; - } - } - - entry = PhGetItemCircularBuffer_PVOID(&PhLogBuffer, i); - - if (!entry) - goto ContinueLoop; - - PhLargeIntegerToLocalSystemTime(&systemTime, &entry->Time); - temp = PhFormatDateTime(&systemTime); - PhAppendStringBuilder(&stringBuilder, &temp->sr); - PhDereferenceObject(temp); - PhAppendStringBuilder2(&stringBuilder, L": "); - - temp = PhFormatLogEntry(entry); - PhAppendStringBuilder(&stringBuilder, &temp->sr); - PhDereferenceObject(temp); - PhAppendStringBuilder2(&stringBuilder, L"\r\n"); - -ContinueLoop: - - if (i == 0) - break; - - i--; - } - - return PhFinalStringBuilderString(&stringBuilder); -} - -INT_PTR CALLBACK PhpLogDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - switch (uMsg) - { - case WM_INITDIALOG: - { - ListViewHandle = GetDlgItem(hwndDlg, IDC_LIST); - PhSetListViewStyle(ListViewHandle, FALSE, TRUE); - PhSetControlTheme(ListViewHandle, L"explorer"); - PhAddListViewColumn(ListViewHandle, 0, 0, 0, LVCFMT_LEFT, 140, L"Time"); - PhAddListViewColumn(ListViewHandle, 1, 1, 1, LVCFMT_LEFT, 260, L"Message"); - PhLoadListViewColumnsFromSetting(L"LogListViewColumns", ListViewHandle); - - PhInitializeLayoutManager(&WindowLayoutManager, hwndDlg); - PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDC_LIST), NULL, - PH_ANCHOR_ALL); - PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDOK), NULL, - PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); - PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDC_COPY), NULL, - PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); - PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDC_SAVE), NULL, - PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); - PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDC_AUTOSCROLL), NULL, - PH_ANCHOR_BOTTOM | PH_ANCHOR_LEFT); - PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDC_CLEAR), NULL, - PH_ANCHOR_BOTTOM | PH_ANCHOR_LEFT); - - MinimumSize.left = 0; - MinimumSize.top = 0; - MinimumSize.right = 290; - MinimumSize.bottom = 150; - MapDialogRect(hwndDlg, &MinimumSize); - - PhLoadWindowPlacementFromSetting(L"LogWindowPosition", L"LogWindowSize", hwndDlg); - - Button_SetCheck(GetDlgItem(hwndDlg, IDC_AUTOSCROLL), BST_CHECKED); - - PhRegisterCallback(&PhLoggedCallback, LoggedCallback, NULL, &LoggedRegistration); - PhpUpdateLogList(); - ListView_EnsureVisible(ListViewHandle, ListViewCount - 1, FALSE); - } - break; - case WM_DESTROY: - { - PhSaveListViewColumnsToSetting(L"LogListViewColumns", ListViewHandle); - PhSaveWindowPlacementToSetting(L"LogWindowPosition", L"LogWindowSize", hwndDlg); - - PhDeleteLayoutManager(&WindowLayoutManager); - - PhUnregisterCallback(&PhLoggedCallback, &LoggedRegistration); - PhUnregisterDialog(PhLogWindowHandle); - PhLogWindowHandle = NULL; - } - break; - case WM_COMMAND: - { - switch (LOWORD(wParam)) - { - case IDCANCEL: - case IDOK: - DestroyWindow(hwndDlg); - break; - case IDC_CLEAR: - { - PhClearLogEntries(); - PhpUpdateLogList(); - } - break; - case IDC_COPY: - { - PPH_STRING string; - ULONG selectedCount; - - selectedCount = ListView_GetSelectedCount(ListViewHandle); - - if (selectedCount == 0) - { - // User didn't select anything, so copy all items. - string = PhpGetStringForSelectedLogEntries(TRUE); - PhSetStateAllListViewItems(ListViewHandle, LVIS_SELECTED, LVIS_SELECTED); - } - else - { - string = PhpGetStringForSelectedLogEntries(FALSE); - } - - PhSetClipboardString(hwndDlg, &string->sr); - PhDereferenceObject(string); - - SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)ListViewHandle, TRUE); - } - break; - case IDC_SAVE: - { - static PH_FILETYPE_FILTER filters[] = - { - { L"Text files (*.txt)", L"*.txt" }, - { L"All files (*.*)", L"*.*" } - }; - PVOID fileDialog; - - fileDialog = PhCreateSaveFileDialog(); - - PhSetFileDialogFilter(fileDialog, filters, sizeof(filters) / sizeof(PH_FILETYPE_FILTER)); - PhSetFileDialogFileName(fileDialog, L"Process Hacker Log.txt"); - - if (PhShowFileDialog(hwndDlg, fileDialog)) - { - NTSTATUS status; - PPH_STRING fileName; - PPH_FILE_STREAM fileStream; - PPH_STRING string; - - fileName = PH_AUTO(PhGetFileDialogFileName(fileDialog)); - - if (NT_SUCCESS(status = PhCreateFileStream( - &fileStream, - fileName->Buffer, - FILE_GENERIC_WRITE, - FILE_SHARE_READ, - FILE_OVERWRITE_IF, - 0 - ))) - { - PhWriteStringAsUtf8FileStream(fileStream, &PhUnicodeByteOrderMark); - PhWritePhTextHeader(fileStream); - - string = PhpGetStringForSelectedLogEntries(TRUE); - PhWriteStringAsUtf8FileStreamEx(fileStream, string->Buffer, string->Length); - PhDereferenceObject(string); - - PhDereferenceObject(fileStream); - } - - if (!NT_SUCCESS(status)) - PhShowStatus(hwndDlg, L"Unable to create the file", status, 0); - } - - PhFreeFileDialog(fileDialog); - } - break; - } - } - break; - case WM_NOTIFY: - { - LPNMHDR header = (LPNMHDR)lParam; - - switch (header->code) - { - case LVN_GETDISPINFO: - { - NMLVDISPINFO *dispInfo = (NMLVDISPINFO *)header; - PPH_LOG_ENTRY entry; - - entry = PhGetItemCircularBuffer_PVOID(&PhLogBuffer, ListViewCount - dispInfo->item.iItem - 1); - - if (dispInfo->item.iSubItem == 0) - { - if (dispInfo->item.mask & LVIF_TEXT) - { - SYSTEMTIME systemTime; - PPH_STRING dateTime; - - PhLargeIntegerToLocalSystemTime(&systemTime, &entry->Time); - dateTime = PhFormatDateTime(&systemTime); - wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, dateTime->Buffer, _TRUNCATE); - PhDereferenceObject(dateTime); - } - } - else if (dispInfo->item.iSubItem == 1) - { - if (dispInfo->item.mask & LVIF_TEXT) - { - PPH_STRING string; - - string = PhFormatLogEntry(entry); - wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, string->Buffer, _TRUNCATE); - PhDereferenceObject(string); - } - } - } - break; - } - } - break; - case WM_SIZE: - { - PhLayoutManagerLayout(&WindowLayoutManager); - } - break; - case WM_SIZING: - { - PhResizingMinimumSize((PRECT)lParam, wParam, MinimumSize.right, MinimumSize.bottom); - } - break; - case WM_PH_LOG_UPDATED: - { - PhpUpdateLogList(); - } - break; - } - - return FALSE; -} +/* + * Process Hacker - + * log window + * + * Copyright (C) 2010-2016 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include + +#include + +#include + +#define WM_PH_LOG_UPDATED (WM_APP + 300) + +INT_PTR CALLBACK PhpLogDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +HWND PhLogWindowHandle = NULL; +static PH_LAYOUT_MANAGER WindowLayoutManager; +static RECT MinimumSize; +static HWND ListViewHandle; +static ULONG ListViewCount; +static PH_CALLBACK_REGISTRATION LoggedRegistration; + +VOID PhShowLogDialog( + VOID + ) +{ + if (!PhLogWindowHandle) + { + PhLogWindowHandle = CreateDialog( + PhInstanceHandle, + MAKEINTRESOURCE(IDD_LOG), + PhMainWndHandle, + PhpLogDlgProc + ); + PhRegisterDialog(PhLogWindowHandle); + ShowWindow(PhLogWindowHandle, SW_SHOW); + } + + if (IsIconic(PhLogWindowHandle)) + ShowWindow(PhLogWindowHandle, SW_RESTORE); + else + SetForegroundWindow(PhLogWindowHandle); +} + +static VOID NTAPI LoggedCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + PostMessage(PhLogWindowHandle, WM_PH_LOG_UPDATED, 0, 0); +} + +static VOID PhpUpdateLogList( + VOID + ) +{ + ListViewCount = PhLogBuffer.Count; + ListView_SetItemCountEx(ListViewHandle, ListViewCount, LVSICF_NOSCROLL); + + if (ListViewCount >= 2 && Button_GetCheck(GetDlgItem(PhLogWindowHandle, IDC_AUTOSCROLL)) == BST_CHECKED) + { + if (ListView_IsItemVisible(ListViewHandle, ListViewCount - 2)) + { + ListView_EnsureVisible(ListViewHandle, ListViewCount - 1, FALSE); + } + } +} + +static PPH_STRING PhpGetStringForSelectedLogEntries( + _In_ BOOLEAN All + ) +{ + PH_STRING_BUILDER stringBuilder; + ULONG i; + + if (ListViewCount == 0) + return PhReferenceEmptyString(); + + PhInitializeStringBuilder(&stringBuilder, 0x100); + + i = ListViewCount - 1; + + while (TRUE) + { + PPH_LOG_ENTRY entry; + SYSTEMTIME systemTime; + PPH_STRING temp; + + if (!All) + { + // The list view displays the items in reverse order... + if (!(ListView_GetItemState(ListViewHandle, ListViewCount - i - 1, LVIS_SELECTED) & LVIS_SELECTED)) + { + goto ContinueLoop; + } + } + + entry = PhGetItemCircularBuffer_PVOID(&PhLogBuffer, i); + + if (!entry) + goto ContinueLoop; + + PhLargeIntegerToLocalSystemTime(&systemTime, &entry->Time); + temp = PhFormatDateTime(&systemTime); + PhAppendStringBuilder(&stringBuilder, &temp->sr); + PhDereferenceObject(temp); + PhAppendStringBuilder2(&stringBuilder, L": "); + + temp = PhFormatLogEntry(entry); + PhAppendStringBuilder(&stringBuilder, &temp->sr); + PhDereferenceObject(temp); + PhAppendStringBuilder2(&stringBuilder, L"\r\n"); + +ContinueLoop: + + if (i == 0) + break; + + i--; + } + + return PhFinalStringBuilderString(&stringBuilder); +} + +INT_PTR CALLBACK PhpLogDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + switch (uMsg) + { + case WM_INITDIALOG: + { + ListViewHandle = GetDlgItem(hwndDlg, IDC_LIST); + PhSetListViewStyle(ListViewHandle, FALSE, TRUE); + PhSetControlTheme(ListViewHandle, L"explorer"); + PhAddListViewColumn(ListViewHandle, 0, 0, 0, LVCFMT_LEFT, 140, L"Time"); + PhAddListViewColumn(ListViewHandle, 1, 1, 1, LVCFMT_LEFT, 260, L"Message"); + PhLoadListViewColumnsFromSetting(L"LogListViewColumns", ListViewHandle); + + PhInitializeLayoutManager(&WindowLayoutManager, hwndDlg); + PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDC_LIST), NULL, + PH_ANCHOR_ALL); + PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDOK), NULL, + PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); + PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDC_COPY), NULL, + PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); + PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDC_SAVE), NULL, + PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); + PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDC_AUTOSCROLL), NULL, + PH_ANCHOR_BOTTOM | PH_ANCHOR_LEFT); + PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDC_CLEAR), NULL, + PH_ANCHOR_BOTTOM | PH_ANCHOR_LEFT); + + MinimumSize.left = 0; + MinimumSize.top = 0; + MinimumSize.right = 290; + MinimumSize.bottom = 150; + MapDialogRect(hwndDlg, &MinimumSize); + + PhLoadWindowPlacementFromSetting(L"LogWindowPosition", L"LogWindowSize", hwndDlg); + + Button_SetCheck(GetDlgItem(hwndDlg, IDC_AUTOSCROLL), BST_CHECKED); + + PhRegisterCallback(&PhLoggedCallback, LoggedCallback, NULL, &LoggedRegistration); + PhpUpdateLogList(); + ListView_EnsureVisible(ListViewHandle, ListViewCount - 1, FALSE); + } + break; + case WM_DESTROY: + { + PhSaveListViewColumnsToSetting(L"LogListViewColumns", ListViewHandle); + PhSaveWindowPlacementToSetting(L"LogWindowPosition", L"LogWindowSize", hwndDlg); + + PhDeleteLayoutManager(&WindowLayoutManager); + + PhUnregisterCallback(&PhLoggedCallback, &LoggedRegistration); + PhUnregisterDialog(PhLogWindowHandle); + PhLogWindowHandle = NULL; + } + break; + case WM_COMMAND: + { + switch (LOWORD(wParam)) + { + case IDCANCEL: + case IDOK: + DestroyWindow(hwndDlg); + break; + case IDC_CLEAR: + { + PhClearLogEntries(); + PhpUpdateLogList(); + } + break; + case IDC_COPY: + { + PPH_STRING string; + ULONG selectedCount; + + selectedCount = ListView_GetSelectedCount(ListViewHandle); + + if (selectedCount == 0) + { + // User didn't select anything, so copy all items. + string = PhpGetStringForSelectedLogEntries(TRUE); + PhSetStateAllListViewItems(ListViewHandle, LVIS_SELECTED, LVIS_SELECTED); + } + else + { + string = PhpGetStringForSelectedLogEntries(FALSE); + } + + PhSetClipboardString(hwndDlg, &string->sr); + PhDereferenceObject(string); + + SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)ListViewHandle, TRUE); + } + break; + case IDC_SAVE: + { + static PH_FILETYPE_FILTER filters[] = + { + { L"Text files (*.txt)", L"*.txt" }, + { L"All files (*.*)", L"*.*" } + }; + PVOID fileDialog; + + fileDialog = PhCreateSaveFileDialog(); + + PhSetFileDialogFilter(fileDialog, filters, sizeof(filters) / sizeof(PH_FILETYPE_FILTER)); + PhSetFileDialogFileName(fileDialog, L"Process Hacker Log.txt"); + + if (PhShowFileDialog(hwndDlg, fileDialog)) + { + NTSTATUS status; + PPH_STRING fileName; + PPH_FILE_STREAM fileStream; + PPH_STRING string; + + fileName = PH_AUTO(PhGetFileDialogFileName(fileDialog)); + + if (NT_SUCCESS(status = PhCreateFileStream( + &fileStream, + fileName->Buffer, + FILE_GENERIC_WRITE, + FILE_SHARE_READ, + FILE_OVERWRITE_IF, + 0 + ))) + { + PhWriteStringAsUtf8FileStream(fileStream, &PhUnicodeByteOrderMark); + PhWritePhTextHeader(fileStream); + + string = PhpGetStringForSelectedLogEntries(TRUE); + PhWriteStringAsUtf8FileStreamEx(fileStream, string->Buffer, string->Length); + PhDereferenceObject(string); + + PhDereferenceObject(fileStream); + } + + if (!NT_SUCCESS(status)) + PhShowStatus(hwndDlg, L"Unable to create the file", status, 0); + } + + PhFreeFileDialog(fileDialog); + } + break; + } + } + break; + case WM_NOTIFY: + { + LPNMHDR header = (LPNMHDR)lParam; + + switch (header->code) + { + case LVN_GETDISPINFO: + { + NMLVDISPINFO *dispInfo = (NMLVDISPINFO *)header; + PPH_LOG_ENTRY entry; + + entry = PhGetItemCircularBuffer_PVOID(&PhLogBuffer, ListViewCount - dispInfo->item.iItem - 1); + + if (dispInfo->item.iSubItem == 0) + { + if (dispInfo->item.mask & LVIF_TEXT) + { + SYSTEMTIME systemTime; + PPH_STRING dateTime; + + PhLargeIntegerToLocalSystemTime(&systemTime, &entry->Time); + dateTime = PhFormatDateTime(&systemTime); + wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, dateTime->Buffer, _TRUNCATE); + PhDereferenceObject(dateTime); + } + } + else if (dispInfo->item.iSubItem == 1) + { + if (dispInfo->item.mask & LVIF_TEXT) + { + PPH_STRING string; + + string = PhFormatLogEntry(entry); + wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, string->Buffer, _TRUNCATE); + PhDereferenceObject(string); + } + } + } + break; + } + } + break; + case WM_SIZE: + { + PhLayoutManagerLayout(&WindowLayoutManager); + } + break; + case WM_SIZING: + { + PhResizingMinimumSize((PRECT)lParam, wParam, MinimumSize.right, MinimumSize.bottom); + } + break; + case WM_PH_LOG_UPDATED: + { + PhpUpdateLogList(); + } + break; + } + + return FALSE; +} diff --git a/ProcessHacker/main.c b/ProcessHacker/main.c index ce5c652bb60d..3d8b82255a96 100644 --- a/ProcessHacker/main.c +++ b/ProcessHacker/main.c @@ -1,1072 +1,1072 @@ -/* - * Process Hacker - - * main program - * - * Copyright (C) 2009-2016 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include - -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -LONG PhMainMessageLoop( - VOID - ); - -VOID PhActivatePreviousInstance( - VOID - ); - -VOID PhInitializeCommonControls( - VOID - ); - -VOID PhInitializeKph( - VOID - ); - -BOOLEAN PhInitializeAppSystem( - VOID - ); - -VOID PhpInitializeSettings( - VOID - ); - -VOID PhpProcessStartupParameters( - VOID - ); - -VOID PhpEnablePrivileges( - VOID - ); - -PPH_STRING PhApplicationDirectory; -PPH_STRING PhApplicationFileName; -PHAPPAPI HFONT PhApplicationFont; -PPH_STRING PhCurrentUserName = NULL; -HINSTANCE PhInstanceHandle; -PPH_STRING PhLocalSystemName = NULL; -BOOLEAN PhPluginsEnabled = FALSE; -PPH_STRING PhSettingsFileName = NULL; -PH_INTEGER_PAIR PhSmallIconSize = { 16, 16 }; -PH_INTEGER_PAIR PhLargeIconSize = { 32, 32 }; -PH_STARTUP_PARAMETERS PhStartupParameters; - -PH_PROVIDER_THREAD PhPrimaryProviderThread; -PH_PROVIDER_THREAD PhSecondaryProviderThread; - -static PPH_LIST DialogList = NULL; -static PPH_LIST FilterList = NULL; -static PH_AUTO_POOL BaseAutoPool; - -INT WINAPI wWinMain( - _In_ HINSTANCE hInstance, - _In_opt_ HINSTANCE hPrevInstance, - _In_ PWSTR lpCmdLine, - _In_ INT nCmdShow - ) -{ - LONG result; -#ifdef DEBUG - PHP_BASE_THREAD_DBG dbg; -#endif - HANDLE currentTokenHandle; - - CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE); -#ifndef DEBUG - SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX); -#endif - - PhInstanceHandle = (HINSTANCE)NtCurrentPeb()->ImageBaseAddress; - - if (!NT_SUCCESS(PhInitializePhLib())) - return 1; - if (!PhInitializeAppSystem()) - return 1; - - PhInitializeCommonControls(); - - currentTokenHandle = PhGetOwnTokenAttributes().TokenHandle; - - if (currentTokenHandle) - { - PTOKEN_USER tokenUser; - - if (NT_SUCCESS(PhGetTokenUser(currentTokenHandle, &tokenUser))) - { - PhCurrentUserName = PhGetSidFullName(tokenUser->User.Sid, TRUE, NULL); - PhFree(tokenUser); - } - } - - PhLocalSystemName = PhGetSidFullName(&PhSeLocalSystemSid, TRUE, NULL); - - // There has been a report of the above call failing. - if (!PhLocalSystemName) - PhLocalSystemName = PhCreateString(L"NT AUTHORITY\\SYSTEM"); - - PhApplicationFileName = PhGetApplicationFileName(); - PhApplicationDirectory = PhGetApplicationDirectory(); - - // Just in case - if (!PhApplicationFileName) - PhApplicationFileName = PhCreateString(L"ProcessHacker.exe"); - if (!PhApplicationDirectory) - PhApplicationDirectory = PhReferenceEmptyString(); - - PhpProcessStartupParameters(); - PhSettingsInitialization(); - PhpEnablePrivileges(); - - if (PhStartupParameters.RunAsServiceMode) - { - RtlExitUserProcess(PhRunAsServiceStart(PhStartupParameters.RunAsServiceMode)); - } - - PhpInitializeSettings(); - - // Activate a previous instance if required. - if (PhGetIntegerSetting(L"AllowOnlyOneInstance") && - !PhStartupParameters.NewInstance && - !PhStartupParameters.ShowOptions && - !PhStartupParameters.CommandMode && - !PhStartupParameters.PhSvc) - { - PhActivatePreviousInstance(); - } - - if (PhGetIntegerSetting(L"EnableKph") && !PhStartupParameters.NoKph && !PhStartupParameters.CommandMode && !PhIsExecutingInWow64()) - PhInitializeKph(); - - if (PhStartupParameters.CommandMode && PhStartupParameters.CommandType && PhStartupParameters.CommandAction) - { - NTSTATUS status; - - status = PhCommandModeStart(); - - if (!NT_SUCCESS(status) && !PhStartupParameters.Silent) - { - PhShowStatus(NULL, L"Unable to execute the command", status, 0); - } - - RtlExitUserProcess(status); - } - -#ifdef DEBUG - dbg.ClientId = NtCurrentTeb()->ClientId; - dbg.StartAddress = wWinMain; - dbg.Parameter = NULL; - InsertTailList(&PhDbgThreadListHead, &dbg.ListEntry); - TlsSetValue(PhDbgThreadDbgTlsIndex, &dbg); -#endif - - PhInitializeAutoPool(&BaseAutoPool); - - PhEmInitialization(); - PhGuiSupportInitialization(); - PhTreeNewInitialization(); - PhGraphControlInitialization(); - PhHexEditInitialization(); - PhColorBoxInitialization(); - - PhSmallIconSize.X = GetSystemMetrics(SM_CXSMICON); - PhSmallIconSize.Y = GetSystemMetrics(SM_CYSMICON); - PhLargeIconSize.X = GetSystemMetrics(SM_CXICON); - PhLargeIconSize.Y = GetSystemMetrics(SM_CYICON); - - if (PhStartupParameters.ShowOptions) - { - // Elevated options dialog for changing the value of Replace Task Manager with Process Hacker. - PhShowOptionsDialog(PhStartupParameters.WindowHandle); - RtlExitUserProcess(STATUS_SUCCESS); - } - -#ifndef DEBUG - if (PhIsExecutingInWow64() && !PhStartupParameters.PhSvc) - { - PhShowWarning( - NULL, - L"You are attempting to run the 32-bit version of Process Hacker on 64-bit Windows. " - L"Most features will not work correctly.\n\n" - L"Please run the 64-bit version of Process Hacker instead." - ); - } -#endif - - PhPluginsEnabled = PhGetIntegerSetting(L"EnablePlugins") && !PhStartupParameters.NoPlugins; - - if (PhPluginsEnabled) - { - PhPluginsInitialization(); - PhLoadPlugins(); - } - - if (PhStartupParameters.PhSvc) - { - MSG message; - - // Turn the feedback cursor off. - PostMessage(NULL, WM_NULL, 0, 0); - GetMessage(&message, NULL, 0, 0); - - RtlExitUserProcess(PhSvcMain(NULL, NULL, NULL)); - } - - // Create a mutant for the installer. - { - HANDLE mutantHandle; - OBJECT_ATTRIBUTES oa; - UNICODE_STRING mutantName; - - RtlInitUnicodeString(&mutantName, L"\\BaseNamedObjects\\ProcessHackerMutant"); - InitializeObjectAttributes( - &oa, - &mutantName, - 0, - NULL, - NULL - ); - - NtCreateMutant(&mutantHandle, MUTANT_ALL_ACCESS, &oa, FALSE); - } - - // Set priority. - { - PROCESS_PRIORITY_CLASS priorityClass; - - priorityClass.Foreground = FALSE; - priorityClass.PriorityClass = PROCESS_PRIORITY_CLASS_HIGH; - - if (PhStartupParameters.PriorityClass != 0) - priorityClass.PriorityClass = (UCHAR)PhStartupParameters.PriorityClass; - - NtSetInformationProcess(NtCurrentProcess(), ProcessPriorityClass, &priorityClass, sizeof(PROCESS_PRIORITY_CLASS)); - } - - if (!PhMainWndInitialization(nCmdShow)) - { - PhShowError(NULL, L"Unable to initialize the main window."); - return 1; - } - - PhDrainAutoPool(&BaseAutoPool); - - result = PhMainMessageLoop(); - RtlExitUserProcess(result); -} - -LONG PhMainMessageLoop( - VOID - ) -{ - BOOL result; - MSG message; - HACCEL acceleratorTable; - - acceleratorTable = LoadAccelerators(PhInstanceHandle, MAKEINTRESOURCE(IDR_MAINWND_ACCEL)); - - while (result = GetMessage(&message, NULL, 0, 0)) - { - BOOLEAN processed = FALSE; - ULONG i; - - if (result == -1) - return 1; - - if (FilterList) - { - for (i = 0; i < FilterList->Count; i++) - { - PPH_MESSAGE_LOOP_FILTER_ENTRY entry = FilterList->Items[i]; - - if (entry->Filter(&message, entry->Context)) - { - processed = TRUE; - break; - } - } - } - - if (!processed) - { - if ( - message.hwnd == PhMainWndHandle || - IsChild(PhMainWndHandle, message.hwnd) - ) - { - if (TranslateAccelerator(PhMainWndHandle, acceleratorTable, &message)) - processed = TRUE; - } - - if (DialogList) - { - for (i = 0; i < DialogList->Count; i++) - { - if (IsDialogMessage((HWND)DialogList->Items[i], &message)) - { - processed = TRUE; - break; - } - } - } - } - - if (!processed) - { - TranslateMessage(&message); - DispatchMessage(&message); - } - - PhDrainAutoPool(&BaseAutoPool); - } - - return (LONG)message.wParam; -} - -VOID PhRegisterDialog( - _In_ HWND DialogWindowHandle - ) -{ - if (!DialogList) - DialogList = PhCreateList(2); - - PhAddItemList(DialogList, (PVOID)DialogWindowHandle); -} - -VOID PhUnregisterDialog( - _In_ HWND DialogWindowHandle - ) -{ - ULONG indexOfDialog; - - if (!DialogList) - return; - - indexOfDialog = PhFindItemList(DialogList, (PVOID)DialogWindowHandle); - - if (indexOfDialog != -1) - PhRemoveItemList(DialogList, indexOfDialog); -} - -struct _PH_MESSAGE_LOOP_FILTER_ENTRY *PhRegisterMessageLoopFilter( - _In_ PPH_MESSAGE_LOOP_FILTER Filter, - _In_opt_ PVOID Context - ) -{ - PPH_MESSAGE_LOOP_FILTER_ENTRY entry; - - if (!FilterList) - FilterList = PhCreateList(2); - - entry = PhAllocate(sizeof(PH_MESSAGE_LOOP_FILTER_ENTRY)); - entry->Filter = Filter; - entry->Context = Context; - PhAddItemList(FilterList, entry); - - return entry; -} - -VOID PhUnregisterMessageLoopFilter( - _In_ struct _PH_MESSAGE_LOOP_FILTER_ENTRY *FilterEntry - ) -{ - ULONG indexOfFilter; - - if (!FilterList) - return; - - indexOfFilter = PhFindItemList(FilterList, FilterEntry); - - if (indexOfFilter != -1) - PhRemoveItemList(FilterList, indexOfFilter); - - PhFree(FilterEntry); -} - -VOID PhActivatePreviousInstance( - VOID - ) -{ - HWND hwnd; - - hwnd = FindWindow(PH_MAINWND_CLASSNAME, NULL); - - if (hwnd) - { - ULONG_PTR result; - - SendMessageTimeout(hwnd, WM_PH_ACTIVATE, PhStartupParameters.SelectPid, 0, SMTO_BLOCK, 5000, &result); - - if (result == PH_ACTIVATE_REPLY) - { - SetForegroundWindow(hwnd); - RtlExitUserProcess(STATUS_SUCCESS); - } - } -} - -VOID PhInitializeCommonControls( - VOID - ) -{ - INITCOMMONCONTROLSEX icex; - - icex.dwSize = sizeof(INITCOMMONCONTROLSEX); - icex.dwICC = - ICC_LINK_CLASS | - ICC_LISTVIEW_CLASSES | - ICC_PROGRESS_CLASS | - ICC_TAB_CLASSES - ; - - InitCommonControlsEx(&icex); -} - -HFONT PhpCreateFont( - _In_ PWSTR Name, - _In_ ULONG Size, - _In_ ULONG Weight - ) -{ - return CreateFont( - -(LONG)PhMultiplyDivide(Size, PhGlobalDpi, 72), - 0, - 0, - 0, - Weight, - FALSE, - FALSE, - FALSE, - ANSI_CHARSET, - OUT_DEFAULT_PRECIS, - CLIP_DEFAULT_PRECIS, - DEFAULT_QUALITY, - DEFAULT_PITCH, - Name - ); -} - -VOID PhInitializeFont( - _In_ HWND hWnd - ) -{ - NONCLIENTMETRICS metrics = { sizeof(metrics) }; - BOOLEAN success; - HDC hdc; - - if (hdc = GetDC(hWnd)) - { - PhGlobalDpi = GetDeviceCaps(hdc, LOGPIXELSY); - ReleaseDC(hWnd, hdc); - } - else - { - PhGlobalDpi = 96; - } - - success = !!SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, &metrics, 0); - - if ( - !(PhApplicationFont = PhpCreateFont(L"Microsoft Sans Serif", 8, FW_NORMAL)) && - !(PhApplicationFont = PhpCreateFont(L"Tahoma", 8, FW_NORMAL)) - ) - { - if (success) - PhApplicationFont = CreateFontIndirect(&metrics.lfMessageFont); - else - PhApplicationFont = NULL; - } -} - -PUCHAR PhpReadSignature( - _In_ PWSTR FileName, - _Out_ PULONG SignatureSize - ) -{ - NTSTATUS status; - HANDLE fileHandle; - PUCHAR signature; - ULONG bufferSize; - IO_STATUS_BLOCK iosb; - - if (!NT_SUCCESS(PhCreateFileWin32(&fileHandle, FileName, FILE_GENERIC_READ, FILE_ATTRIBUTE_NORMAL, - FILE_SHARE_READ, FILE_OPEN, FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT))) - { - return NULL; - } - - bufferSize = 1024; - signature = PhAllocate(bufferSize); - - status = NtReadFile(fileHandle, NULL, NULL, NULL, &iosb, signature, bufferSize, NULL, NULL); - NtClose(fileHandle); - - if (NT_SUCCESS(status)) - { - *SignatureSize = (ULONG)iosb.Information; - return signature; - } - else - { - PhFree(signature); - return NULL; - } -} - -VOID PhInitializeKph( - VOID - ) -{ - static PH_STRINGREF kprocesshacker = PH_STRINGREF_INIT(L"kprocesshacker.sys"); - static PH_STRINGREF processhackerSig = PH_STRINGREF_INIT(L"ProcessHacker.sig"); - - PPH_STRING kprocesshackerFileName; - PPH_STRING processhackerSigFileName; - KPH_PARAMETERS parameters; - PUCHAR signature; - ULONG signatureSize; - - if (WindowsVersion < WINDOWS_7) - return; - - kprocesshackerFileName = PhConcatStringRef2(&PhApplicationDirectory->sr, &kprocesshacker); - processhackerSigFileName = PhConcatStringRef2(&PhApplicationDirectory->sr, &processhackerSig); - - parameters.SecurityLevel = KphSecurityPrivilegeCheck; - parameters.CreateDynamicConfiguration = TRUE; - KphConnect2Ex(KPH_DEVICE_SHORT_NAME, kprocesshackerFileName->Buffer, ¶meters); - - if (signature = PhpReadSignature(processhackerSigFileName->Buffer, &signatureSize)) - { - KphVerifyClient(signature, signatureSize); - PhFree(signature); - } - - PhDereferenceObject(kprocesshackerFileName); - PhDereferenceObject(processhackerSigFileName); -} - -BOOLEAN PhInitializeAppSystem( - VOID - ) -{ - PhApplicationName = L"Process Hacker"; - - if (!PhProcessProviderInitialization()) - return FALSE; - if (!PhServiceProviderInitialization()) - return FALSE; - if (!PhNetworkProviderInitialization()) - return FALSE; - if (!PhModuleProviderInitialization()) - return FALSE; - if (!PhThreadProviderInitialization()) - return FALSE; - if (!PhHandleProviderInitialization()) - return FALSE; - if (!PhMemoryProviderInitialization()) - return FALSE; - if (!PhProcessPropInitialization()) - return FALSE; - - PhSetHandleClientIdFunction(PhGetClientIdName); - - return TRUE; -} - -VOID PhpInitializeSettings( - VOID - ) -{ - NTSTATUS status; - - if (!PhStartupParameters.NoSettings) - { - static PH_STRINGREF settingsSuffix = PH_STRINGREF_INIT(L".settings.xml"); - PPH_STRING settingsFileName; - - // There are three possible locations for the settings file: - // 1. The file name given in the command line. - // 2. A file named ProcessHacker.exe.settings.xml in the program directory. (This changes - // based on the executable file name.) - // 3. The default location. - - // 1. File specified in command line - if (PhStartupParameters.SettingsFileName) - { - // Get an absolute path now. - PhSettingsFileName = PhGetFullPath(PhStartupParameters.SettingsFileName->Buffer, NULL); - } - - // 2. File in program directory - if (!PhSettingsFileName) - { - settingsFileName = PhConcatStringRef2(&PhApplicationFileName->sr, &settingsSuffix); - - if (RtlDoesFileExists_U(settingsFileName->Buffer)) - { - PhSettingsFileName = settingsFileName; - } - else - { - PhDereferenceObject(settingsFileName); - } - } - - // 3. Default location - if (!PhSettingsFileName) - { - PhSettingsFileName = PhGetKnownLocation(CSIDL_APPDATA, L"\\Process Hacker\\settings.xml"); - } - - if (PhSettingsFileName) - { - status = PhLoadSettings(PhSettingsFileName->Buffer); - - // If we didn't find the file, it will be created. Otherwise, - // there was probably a parsing error and we don't want to - // change anything. - if (status == STATUS_FILE_CORRUPT_ERROR) - { - if (PhShowMessage( - NULL, - MB_ICONWARNING | MB_YESNO, - L"Process Hacker's settings file is corrupt. Do you want to reset it?\n" - L"If you select No, the settings system will not function properly." - ) == IDYES) - { - HANDLE fileHandle; - IO_STATUS_BLOCK isb; - CHAR data[] = ""; - - // This used to delete the file. But it's better to keep the file there - // and overwrite it with some valid XML, especially with case (2) above. - if (NT_SUCCESS(PhCreateFileWin32( - &fileHandle, - PhSettingsFileName->Buffer, - FILE_GENERIC_WRITE, - 0, - FILE_SHARE_READ | FILE_SHARE_DELETE, - FILE_OVERWRITE, - FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT - ))) - { - NtWriteFile(fileHandle, NULL, NULL, NULL, &isb, data, sizeof(data) - 1, NULL, NULL); - NtClose(fileHandle); - } - } - else - { - // Pretend we don't have a settings store so bad things - // don't happen. - PhDereferenceObject(PhSettingsFileName); - PhSettingsFileName = NULL; - } - } - } - } - - // Apply basic global settings. - PhMaxSizeUnit = PhGetIntegerSetting(L"MaxSizeUnit"); - - if (PhGetIntegerSetting(L"SampleCountAutomatic")) - { - ULONG sampleCount; - - sampleCount = (GetSystemMetrics(SM_CXVIRTUALSCREEN) + 1) / 2; - - if (sampleCount > 2048) - sampleCount = 2048; - - PhSetIntegerSetting(L"SampleCount", sampleCount); - } -} - -#define PH_ARG_SETTINGS 1 -#define PH_ARG_NOSETTINGS 2 -#define PH_ARG_SHOWVISIBLE 3 -#define PH_ARG_SHOWHIDDEN 4 -#define PH_ARG_COMMANDMODE 5 -#define PH_ARG_COMMANDTYPE 6 -#define PH_ARG_COMMANDOBJECT 7 -#define PH_ARG_COMMANDACTION 8 -#define PH_ARG_COMMANDVALUE 9 -#define PH_ARG_RUNASSERVICEMODE 10 -#define PH_ARG_NOKPH 11 -#define PH_ARG_INSTALLKPH 12 -#define PH_ARG_UNINSTALLKPH 13 -#define PH_ARG_DEBUG 14 -#define PH_ARG_HWND 15 -#define PH_ARG_POINT 16 -#define PH_ARG_SHOWOPTIONS 17 -#define PH_ARG_PHSVC 18 -#define PH_ARG_NOPLUGINS 19 -#define PH_ARG_NEWINSTANCE 20 -#define PH_ARG_ELEVATE 21 -#define PH_ARG_SILENT 22 -#define PH_ARG_HELP 23 -#define PH_ARG_SELECTPID 24 -#define PH_ARG_PRIORITY 25 -#define PH_ARG_PLUGIN 26 -#define PH_ARG_SELECTTAB 27 -#define PH_ARG_SYSINFO 28 - -BOOLEAN NTAPI PhpCommandLineOptionCallback( - _In_opt_ PPH_COMMAND_LINE_OPTION Option, - _In_opt_ PPH_STRING Value, - _In_opt_ PVOID Context - ) -{ - ULONG64 integer; - - if (Option) - { - switch (Option->Id) - { - case PH_ARG_SETTINGS: - PhSwapReference(&PhStartupParameters.SettingsFileName, Value); - break; - case PH_ARG_NOSETTINGS: - PhStartupParameters.NoSettings = TRUE; - break; - case PH_ARG_SHOWVISIBLE: - PhStartupParameters.ShowVisible = TRUE; - break; - case PH_ARG_SHOWHIDDEN: - PhStartupParameters.ShowHidden = TRUE; - break; - case PH_ARG_COMMANDMODE: - PhStartupParameters.CommandMode = TRUE; - break; - case PH_ARG_COMMANDTYPE: - PhSwapReference(&PhStartupParameters.CommandType, Value); - break; - case PH_ARG_COMMANDOBJECT: - PhSwapReference(&PhStartupParameters.CommandObject, Value); - break; - case PH_ARG_COMMANDACTION: - PhSwapReference(&PhStartupParameters.CommandAction, Value); - break; - case PH_ARG_COMMANDVALUE: - PhSwapReference(&PhStartupParameters.CommandValue, Value); - break; - case PH_ARG_RUNASSERVICEMODE: - PhSwapReference(&PhStartupParameters.RunAsServiceMode, Value); - break; - case PH_ARG_NOKPH: - PhStartupParameters.NoKph = TRUE; - break; - case PH_ARG_INSTALLKPH: - PhStartupParameters.InstallKph = TRUE; - break; - case PH_ARG_UNINSTALLKPH: - PhStartupParameters.UninstallKph = TRUE; - break; - case PH_ARG_DEBUG: - PhStartupParameters.Debug = TRUE; - break; - case PH_ARG_HWND: - if (PhStringToInteger64(&Value->sr, 16, &integer)) - PhStartupParameters.WindowHandle = (HWND)(ULONG_PTR)integer; - break; - case PH_ARG_POINT: - { - PH_STRINGREF xString; - PH_STRINGREF yString; - - if (PhSplitStringRefAtChar(&Value->sr, ',', &xString, &yString)) - { - LONG64 x; - LONG64 y; - - if (PhStringToInteger64(&xString, 10, &x) && PhStringToInteger64(&yString, 10, &y)) - { - PhStartupParameters.Point.x = (LONG)x; - PhStartupParameters.Point.y = (LONG)y; - } - } - } - break; - case PH_ARG_SHOWOPTIONS: - PhStartupParameters.ShowOptions = TRUE; - break; - case PH_ARG_PHSVC: - PhStartupParameters.PhSvc = TRUE; - break; - case PH_ARG_NOPLUGINS: - PhStartupParameters.NoPlugins = TRUE; - break; - case PH_ARG_NEWINSTANCE: - PhStartupParameters.NewInstance = TRUE; - break; - case PH_ARG_ELEVATE: - PhStartupParameters.Elevate = TRUE; - break; - case PH_ARG_SILENT: - PhStartupParameters.Silent = TRUE; - break; - case PH_ARG_HELP: - PhStartupParameters.Help = TRUE; - break; - case PH_ARG_SELECTPID: - if (PhStringToInteger64(&Value->sr, 0, &integer)) - PhStartupParameters.SelectPid = (ULONG)integer; - break; - case PH_ARG_PRIORITY: - if (PhEqualString2(Value, L"r", TRUE)) - PhStartupParameters.PriorityClass = PROCESS_PRIORITY_CLASS_REALTIME; - else if (PhEqualString2(Value, L"h", TRUE)) - PhStartupParameters.PriorityClass = PROCESS_PRIORITY_CLASS_HIGH; - else if (PhEqualString2(Value, L"n", TRUE)) - PhStartupParameters.PriorityClass = PROCESS_PRIORITY_CLASS_NORMAL; - else if (PhEqualString2(Value, L"l", TRUE)) - PhStartupParameters.PriorityClass = PROCESS_PRIORITY_CLASS_IDLE; - break; - case PH_ARG_PLUGIN: - if (!PhStartupParameters.PluginParameters) - PhStartupParameters.PluginParameters = PhCreateList(3); - PhAddItemList(PhStartupParameters.PluginParameters, PhReferenceObject(Value)); - break; - case PH_ARG_SELECTTAB: - PhSwapReference(&PhStartupParameters.SelectTab, Value); - break; - case PH_ARG_SYSINFO: - PhSwapReference(&PhStartupParameters.SysInfo, Value ? Value : PhReferenceEmptyString()); - break; - } - } - else - { - PPH_STRING upperValue; - - upperValue = PhDuplicateString(Value); - _wcsupr(upperValue->Buffer); - - if (PhFindStringInString(upperValue, 0, L"TASKMGR.EXE") != -1) - { - // User probably has Process Hacker replacing Task Manager. Force - // the main window to start visible. - PhStartupParameters.ShowVisible = TRUE; - } - - PhDereferenceObject(upperValue); - } - - return TRUE; -} - -VOID PhpProcessStartupParameters( - VOID - ) -{ - static PH_COMMAND_LINE_OPTION options[] = - { - { PH_ARG_SETTINGS, L"settings", MandatoryArgumentType }, - { PH_ARG_NOSETTINGS, L"nosettings", NoArgumentType }, - { PH_ARG_SHOWVISIBLE, L"v", NoArgumentType }, - { PH_ARG_SHOWHIDDEN, L"hide", NoArgumentType }, - { PH_ARG_COMMANDMODE, L"c", NoArgumentType }, - { PH_ARG_COMMANDTYPE, L"ctype", MandatoryArgumentType }, - { PH_ARG_COMMANDOBJECT, L"cobject", MandatoryArgumentType }, - { PH_ARG_COMMANDACTION, L"caction", MandatoryArgumentType }, - { PH_ARG_COMMANDVALUE, L"cvalue", MandatoryArgumentType }, - { PH_ARG_RUNASSERVICEMODE, L"ras", MandatoryArgumentType }, - { PH_ARG_NOKPH, L"nokph", NoArgumentType }, - { PH_ARG_INSTALLKPH, L"installkph", NoArgumentType }, - { PH_ARG_UNINSTALLKPH, L"uninstallkph", NoArgumentType }, - { PH_ARG_DEBUG, L"debug", NoArgumentType }, - { PH_ARG_HWND, L"hwnd", MandatoryArgumentType }, - { PH_ARG_POINT, L"point", MandatoryArgumentType }, - { PH_ARG_SHOWOPTIONS, L"showoptions", NoArgumentType }, - { PH_ARG_PHSVC, L"phsvc", NoArgumentType }, - { PH_ARG_NOPLUGINS, L"noplugins", NoArgumentType }, - { PH_ARG_NEWINSTANCE, L"newinstance", NoArgumentType }, - { PH_ARG_ELEVATE, L"elevate", NoArgumentType }, - { PH_ARG_SILENT, L"s", NoArgumentType }, - { PH_ARG_HELP, L"help", NoArgumentType }, - { PH_ARG_SELECTPID, L"selectpid", MandatoryArgumentType }, - { PH_ARG_PRIORITY, L"priority", MandatoryArgumentType }, - { PH_ARG_PLUGIN, L"plugin", MandatoryArgumentType }, - { PH_ARG_SELECTTAB, L"selecttab", MandatoryArgumentType }, - { PH_ARG_SYSINFO, L"sysinfo", OptionalArgumentType } - }; - PH_STRINGREF commandLine; - - PhUnicodeStringToStringRef(&NtCurrentPeb()->ProcessParameters->CommandLine, &commandLine); - - memset(&PhStartupParameters, 0, sizeof(PH_STARTUP_PARAMETERS)); - - if (!PhParseCommandLine( - &commandLine, - options, - sizeof(options) / sizeof(PH_COMMAND_LINE_OPTION), - PH_COMMAND_LINE_IGNORE_UNKNOWN_OPTIONS | PH_COMMAND_LINE_IGNORE_FIRST_PART, - PhpCommandLineOptionCallback, - NULL - ) || PhStartupParameters.Help) - { - PhShowInformation( - NULL, - L"Command line options:\n\n" - L"-c\n" - L"-ctype command-type\n" - L"-cobject command-object\n" - L"-caction command-action\n" - L"-cvalue command-value\n" - L"-debug\n" - L"-elevate\n" - L"-help\n" - L"-hide\n" - L"-installkph\n" - L"-newinstance\n" - L"-nokph\n" - L"-noplugins\n" - L"-nosettings\n" - L"-plugin pluginname:value\n" - L"-priority r|h|n|l\n" - L"-s\n" - L"-selectpid pid-to-select\n" - L"-selecttab name-of-tab-to-select\n" - L"-settings filename\n" - L"-sysinfo [section-name]\n" - L"-uninstallkph\n" - L"-v\n" - ); - - if (PhStartupParameters.Help) - RtlExitUserProcess(STATUS_SUCCESS); - } - - if (PhStartupParameters.InstallKph) - { - NTSTATUS status; - PPH_STRING kprocesshackerFileName; - KPH_PARAMETERS parameters; - - kprocesshackerFileName = PhConcatStrings2(PhApplicationDirectory->Buffer, L"\\kprocesshacker.sys"); - - parameters.SecurityLevel = KphSecuritySignatureCheck; - parameters.CreateDynamicConfiguration = TRUE; - - status = KphInstallEx(KPH_DEVICE_SHORT_NAME, kprocesshackerFileName->Buffer, ¶meters); - - if (!NT_SUCCESS(status) && !PhStartupParameters.Silent) - PhShowStatus(NULL, L"Unable to install KProcessHacker", status, 0); - - RtlExitUserProcess(status); - } - - if (PhStartupParameters.UninstallKph) - { - NTSTATUS status; - - status = KphUninstall(KPH_DEVICE_SHORT_NAME); - - if (!NT_SUCCESS(status) && !PhStartupParameters.Silent) - PhShowStatus(NULL, L"Unable to uninstall KProcessHacker", status, 0); - - RtlExitUserProcess(status); - } - - if (PhStartupParameters.Elevate && !PhGetOwnTokenAttributes().Elevated) - { - PhShellProcessHacker( - NULL, - NULL, - SW_SHOW, - PH_SHELL_EXECUTE_ADMIN, - PH_SHELL_APP_PROPAGATE_PARAMETERS | PH_SHELL_APP_PROPAGATE_PARAMETERS_FORCE_SETTINGS, - 0, - NULL - ); - RtlExitUserProcess(STATUS_SUCCESS); - } - - if (PhStartupParameters.Debug) - { - // The symbol provider won't work if this is chosen. - PhShowDebugConsole(); - } -} - -VOID PhpEnablePrivileges( - VOID - ) -{ - HANDLE tokenHandle; - - if (NT_SUCCESS(NtOpenProcessToken( - NtCurrentProcess(), - TOKEN_ADJUST_PRIVILEGES, - &tokenHandle - ))) - { - CHAR privilegesBuffer[FIELD_OFFSET(TOKEN_PRIVILEGES, Privileges) + sizeof(LUID_AND_ATTRIBUTES) * 8]; - PTOKEN_PRIVILEGES privileges; - ULONG i; - - privileges = (PTOKEN_PRIVILEGES)privilegesBuffer; - privileges->PrivilegeCount = 8; - - for (i = 0; i < privileges->PrivilegeCount; i++) - { - privileges->Privileges[i].Attributes = SE_PRIVILEGE_ENABLED; - privileges->Privileges[i].Luid.HighPart = 0; - } - - privileges->Privileges[0].Luid.LowPart = SE_DEBUG_PRIVILEGE; - privileges->Privileges[1].Luid.LowPart = SE_INC_BASE_PRIORITY_PRIVILEGE; - privileges->Privileges[2].Luid.LowPart = SE_INC_WORKING_SET_PRIVILEGE; - privileges->Privileges[3].Luid.LowPart = SE_LOAD_DRIVER_PRIVILEGE; - privileges->Privileges[4].Luid.LowPart = SE_PROF_SINGLE_PROCESS_PRIVILEGE; - privileges->Privileges[5].Luid.LowPart = SE_RESTORE_PRIVILEGE; - privileges->Privileges[6].Luid.LowPart = SE_SHUTDOWN_PRIVILEGE; - privileges->Privileges[7].Luid.LowPart = SE_TAKE_OWNERSHIP_PRIVILEGE; - - NtAdjustPrivilegesToken( - tokenHandle, - FALSE, - privileges, - 0, - NULL, - NULL - ); - - NtClose(tokenHandle); - } -} +/* + * Process Hacker - + * main program + * + * Copyright (C) 2009-2016 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +LONG PhMainMessageLoop( + VOID + ); + +VOID PhActivatePreviousInstance( + VOID + ); + +VOID PhInitializeCommonControls( + VOID + ); + +VOID PhInitializeKph( + VOID + ); + +BOOLEAN PhInitializeAppSystem( + VOID + ); + +VOID PhpInitializeSettings( + VOID + ); + +VOID PhpProcessStartupParameters( + VOID + ); + +VOID PhpEnablePrivileges( + VOID + ); + +PPH_STRING PhApplicationDirectory; +PPH_STRING PhApplicationFileName; +PHAPPAPI HFONT PhApplicationFont; +PPH_STRING PhCurrentUserName = NULL; +HINSTANCE PhInstanceHandle; +PPH_STRING PhLocalSystemName = NULL; +BOOLEAN PhPluginsEnabled = FALSE; +PPH_STRING PhSettingsFileName = NULL; +PH_INTEGER_PAIR PhSmallIconSize = { 16, 16 }; +PH_INTEGER_PAIR PhLargeIconSize = { 32, 32 }; +PH_STARTUP_PARAMETERS PhStartupParameters; + +PH_PROVIDER_THREAD PhPrimaryProviderThread; +PH_PROVIDER_THREAD PhSecondaryProviderThread; + +static PPH_LIST DialogList = NULL; +static PPH_LIST FilterList = NULL; +static PH_AUTO_POOL BaseAutoPool; + +INT WINAPI wWinMain( + _In_ HINSTANCE hInstance, + _In_opt_ HINSTANCE hPrevInstance, + _In_ PWSTR lpCmdLine, + _In_ INT nCmdShow + ) +{ + LONG result; +#ifdef DEBUG + PHP_BASE_THREAD_DBG dbg; +#endif + HANDLE currentTokenHandle; + + CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE); +#ifndef DEBUG + SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX); +#endif + + PhInstanceHandle = (HINSTANCE)NtCurrentPeb()->ImageBaseAddress; + + if (!NT_SUCCESS(PhInitializePhLib())) + return 1; + if (!PhInitializeAppSystem()) + return 1; + + PhInitializeCommonControls(); + + currentTokenHandle = PhGetOwnTokenAttributes().TokenHandle; + + if (currentTokenHandle) + { + PTOKEN_USER tokenUser; + + if (NT_SUCCESS(PhGetTokenUser(currentTokenHandle, &tokenUser))) + { + PhCurrentUserName = PhGetSidFullName(tokenUser->User.Sid, TRUE, NULL); + PhFree(tokenUser); + } + } + + PhLocalSystemName = PhGetSidFullName(&PhSeLocalSystemSid, TRUE, NULL); + + // There has been a report of the above call failing. + if (!PhLocalSystemName) + PhLocalSystemName = PhCreateString(L"NT AUTHORITY\\SYSTEM"); + + PhApplicationFileName = PhGetApplicationFileName(); + PhApplicationDirectory = PhGetApplicationDirectory(); + + // Just in case + if (!PhApplicationFileName) + PhApplicationFileName = PhCreateString(L"ProcessHacker.exe"); + if (!PhApplicationDirectory) + PhApplicationDirectory = PhReferenceEmptyString(); + + PhpProcessStartupParameters(); + PhSettingsInitialization(); + PhpEnablePrivileges(); + + if (PhStartupParameters.RunAsServiceMode) + { + RtlExitUserProcess(PhRunAsServiceStart(PhStartupParameters.RunAsServiceMode)); + } + + PhpInitializeSettings(); + + // Activate a previous instance if required. + if (PhGetIntegerSetting(L"AllowOnlyOneInstance") && + !PhStartupParameters.NewInstance && + !PhStartupParameters.ShowOptions && + !PhStartupParameters.CommandMode && + !PhStartupParameters.PhSvc) + { + PhActivatePreviousInstance(); + } + + if (PhGetIntegerSetting(L"EnableKph") && !PhStartupParameters.NoKph && !PhStartupParameters.CommandMode && !PhIsExecutingInWow64()) + PhInitializeKph(); + + if (PhStartupParameters.CommandMode && PhStartupParameters.CommandType && PhStartupParameters.CommandAction) + { + NTSTATUS status; + + status = PhCommandModeStart(); + + if (!NT_SUCCESS(status) && !PhStartupParameters.Silent) + { + PhShowStatus(NULL, L"Unable to execute the command", status, 0); + } + + RtlExitUserProcess(status); + } + +#ifdef DEBUG + dbg.ClientId = NtCurrentTeb()->ClientId; + dbg.StartAddress = wWinMain; + dbg.Parameter = NULL; + InsertTailList(&PhDbgThreadListHead, &dbg.ListEntry); + TlsSetValue(PhDbgThreadDbgTlsIndex, &dbg); +#endif + + PhInitializeAutoPool(&BaseAutoPool); + + PhEmInitialization(); + PhGuiSupportInitialization(); + PhTreeNewInitialization(); + PhGraphControlInitialization(); + PhHexEditInitialization(); + PhColorBoxInitialization(); + + PhSmallIconSize.X = GetSystemMetrics(SM_CXSMICON); + PhSmallIconSize.Y = GetSystemMetrics(SM_CYSMICON); + PhLargeIconSize.X = GetSystemMetrics(SM_CXICON); + PhLargeIconSize.Y = GetSystemMetrics(SM_CYICON); + + if (PhStartupParameters.ShowOptions) + { + // Elevated options dialog for changing the value of Replace Task Manager with Process Hacker. + PhShowOptionsDialog(PhStartupParameters.WindowHandle); + RtlExitUserProcess(STATUS_SUCCESS); + } + +#ifndef DEBUG + if (PhIsExecutingInWow64() && !PhStartupParameters.PhSvc) + { + PhShowWarning( + NULL, + L"You are attempting to run the 32-bit version of Process Hacker on 64-bit Windows. " + L"Most features will not work correctly.\n\n" + L"Please run the 64-bit version of Process Hacker instead." + ); + } +#endif + + PhPluginsEnabled = PhGetIntegerSetting(L"EnablePlugins") && !PhStartupParameters.NoPlugins; + + if (PhPluginsEnabled) + { + PhPluginsInitialization(); + PhLoadPlugins(); + } + + if (PhStartupParameters.PhSvc) + { + MSG message; + + // Turn the feedback cursor off. + PostMessage(NULL, WM_NULL, 0, 0); + GetMessage(&message, NULL, 0, 0); + + RtlExitUserProcess(PhSvcMain(NULL, NULL, NULL)); + } + + // Create a mutant for the installer. + { + HANDLE mutantHandle; + OBJECT_ATTRIBUTES oa; + UNICODE_STRING mutantName; + + RtlInitUnicodeString(&mutantName, L"\\BaseNamedObjects\\ProcessHackerMutant"); + InitializeObjectAttributes( + &oa, + &mutantName, + 0, + NULL, + NULL + ); + + NtCreateMutant(&mutantHandle, MUTANT_ALL_ACCESS, &oa, FALSE); + } + + // Set priority. + { + PROCESS_PRIORITY_CLASS priorityClass; + + priorityClass.Foreground = FALSE; + priorityClass.PriorityClass = PROCESS_PRIORITY_CLASS_HIGH; + + if (PhStartupParameters.PriorityClass != 0) + priorityClass.PriorityClass = (UCHAR)PhStartupParameters.PriorityClass; + + NtSetInformationProcess(NtCurrentProcess(), ProcessPriorityClass, &priorityClass, sizeof(PROCESS_PRIORITY_CLASS)); + } + + if (!PhMainWndInitialization(nCmdShow)) + { + PhShowError(NULL, L"Unable to initialize the main window."); + return 1; + } + + PhDrainAutoPool(&BaseAutoPool); + + result = PhMainMessageLoop(); + RtlExitUserProcess(result); +} + +LONG PhMainMessageLoop( + VOID + ) +{ + BOOL result; + MSG message; + HACCEL acceleratorTable; + + acceleratorTable = LoadAccelerators(PhInstanceHandle, MAKEINTRESOURCE(IDR_MAINWND_ACCEL)); + + while (result = GetMessage(&message, NULL, 0, 0)) + { + BOOLEAN processed = FALSE; + ULONG i; + + if (result == -1) + return 1; + + if (FilterList) + { + for (i = 0; i < FilterList->Count; i++) + { + PPH_MESSAGE_LOOP_FILTER_ENTRY entry = FilterList->Items[i]; + + if (entry->Filter(&message, entry->Context)) + { + processed = TRUE; + break; + } + } + } + + if (!processed) + { + if ( + message.hwnd == PhMainWndHandle || + IsChild(PhMainWndHandle, message.hwnd) + ) + { + if (TranslateAccelerator(PhMainWndHandle, acceleratorTable, &message)) + processed = TRUE; + } + + if (DialogList) + { + for (i = 0; i < DialogList->Count; i++) + { + if (IsDialogMessage((HWND)DialogList->Items[i], &message)) + { + processed = TRUE; + break; + } + } + } + } + + if (!processed) + { + TranslateMessage(&message); + DispatchMessage(&message); + } + + PhDrainAutoPool(&BaseAutoPool); + } + + return (LONG)message.wParam; +} + +VOID PhRegisterDialog( + _In_ HWND DialogWindowHandle + ) +{ + if (!DialogList) + DialogList = PhCreateList(2); + + PhAddItemList(DialogList, (PVOID)DialogWindowHandle); +} + +VOID PhUnregisterDialog( + _In_ HWND DialogWindowHandle + ) +{ + ULONG indexOfDialog; + + if (!DialogList) + return; + + indexOfDialog = PhFindItemList(DialogList, (PVOID)DialogWindowHandle); + + if (indexOfDialog != -1) + PhRemoveItemList(DialogList, indexOfDialog); +} + +struct _PH_MESSAGE_LOOP_FILTER_ENTRY *PhRegisterMessageLoopFilter( + _In_ PPH_MESSAGE_LOOP_FILTER Filter, + _In_opt_ PVOID Context + ) +{ + PPH_MESSAGE_LOOP_FILTER_ENTRY entry; + + if (!FilterList) + FilterList = PhCreateList(2); + + entry = PhAllocate(sizeof(PH_MESSAGE_LOOP_FILTER_ENTRY)); + entry->Filter = Filter; + entry->Context = Context; + PhAddItemList(FilterList, entry); + + return entry; +} + +VOID PhUnregisterMessageLoopFilter( + _In_ struct _PH_MESSAGE_LOOP_FILTER_ENTRY *FilterEntry + ) +{ + ULONG indexOfFilter; + + if (!FilterList) + return; + + indexOfFilter = PhFindItemList(FilterList, FilterEntry); + + if (indexOfFilter != -1) + PhRemoveItemList(FilterList, indexOfFilter); + + PhFree(FilterEntry); +} + +VOID PhActivatePreviousInstance( + VOID + ) +{ + HWND hwnd; + + hwnd = FindWindow(PH_MAINWND_CLASSNAME, NULL); + + if (hwnd) + { + ULONG_PTR result; + + SendMessageTimeout(hwnd, WM_PH_ACTIVATE, PhStartupParameters.SelectPid, 0, SMTO_BLOCK, 5000, &result); + + if (result == PH_ACTIVATE_REPLY) + { + SetForegroundWindow(hwnd); + RtlExitUserProcess(STATUS_SUCCESS); + } + } +} + +VOID PhInitializeCommonControls( + VOID + ) +{ + INITCOMMONCONTROLSEX icex; + + icex.dwSize = sizeof(INITCOMMONCONTROLSEX); + icex.dwICC = + ICC_LINK_CLASS | + ICC_LISTVIEW_CLASSES | + ICC_PROGRESS_CLASS | + ICC_TAB_CLASSES + ; + + InitCommonControlsEx(&icex); +} + +HFONT PhpCreateFont( + _In_ PWSTR Name, + _In_ ULONG Size, + _In_ ULONG Weight + ) +{ + return CreateFont( + -(LONG)PhMultiplyDivide(Size, PhGlobalDpi, 72), + 0, + 0, + 0, + Weight, + FALSE, + FALSE, + FALSE, + ANSI_CHARSET, + OUT_DEFAULT_PRECIS, + CLIP_DEFAULT_PRECIS, + DEFAULT_QUALITY, + DEFAULT_PITCH, + Name + ); +} + +VOID PhInitializeFont( + _In_ HWND hWnd + ) +{ + NONCLIENTMETRICS metrics = { sizeof(metrics) }; + BOOLEAN success; + HDC hdc; + + if (hdc = GetDC(hWnd)) + { + PhGlobalDpi = GetDeviceCaps(hdc, LOGPIXELSY); + ReleaseDC(hWnd, hdc); + } + else + { + PhGlobalDpi = 96; + } + + success = !!SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, &metrics, 0); + + if ( + !(PhApplicationFont = PhpCreateFont(L"Microsoft Sans Serif", 8, FW_NORMAL)) && + !(PhApplicationFont = PhpCreateFont(L"Tahoma", 8, FW_NORMAL)) + ) + { + if (success) + PhApplicationFont = CreateFontIndirect(&metrics.lfMessageFont); + else + PhApplicationFont = NULL; + } +} + +PUCHAR PhpReadSignature( + _In_ PWSTR FileName, + _Out_ PULONG SignatureSize + ) +{ + NTSTATUS status; + HANDLE fileHandle; + PUCHAR signature; + ULONG bufferSize; + IO_STATUS_BLOCK iosb; + + if (!NT_SUCCESS(PhCreateFileWin32(&fileHandle, FileName, FILE_GENERIC_READ, FILE_ATTRIBUTE_NORMAL, + FILE_SHARE_READ, FILE_OPEN, FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT))) + { + return NULL; + } + + bufferSize = 1024; + signature = PhAllocate(bufferSize); + + status = NtReadFile(fileHandle, NULL, NULL, NULL, &iosb, signature, bufferSize, NULL, NULL); + NtClose(fileHandle); + + if (NT_SUCCESS(status)) + { + *SignatureSize = (ULONG)iosb.Information; + return signature; + } + else + { + PhFree(signature); + return NULL; + } +} + +VOID PhInitializeKph( + VOID + ) +{ + static PH_STRINGREF kprocesshacker = PH_STRINGREF_INIT(L"kprocesshacker.sys"); + static PH_STRINGREF processhackerSig = PH_STRINGREF_INIT(L"ProcessHacker.sig"); + + PPH_STRING kprocesshackerFileName; + PPH_STRING processhackerSigFileName; + KPH_PARAMETERS parameters; + PUCHAR signature; + ULONG signatureSize; + + if (WindowsVersion < WINDOWS_7) + return; + + kprocesshackerFileName = PhConcatStringRef2(&PhApplicationDirectory->sr, &kprocesshacker); + processhackerSigFileName = PhConcatStringRef2(&PhApplicationDirectory->sr, &processhackerSig); + + parameters.SecurityLevel = KphSecurityPrivilegeCheck; + parameters.CreateDynamicConfiguration = TRUE; + KphConnect2Ex(KPH_DEVICE_SHORT_NAME, kprocesshackerFileName->Buffer, ¶meters); + + if (signature = PhpReadSignature(processhackerSigFileName->Buffer, &signatureSize)) + { + KphVerifyClient(signature, signatureSize); + PhFree(signature); + } + + PhDereferenceObject(kprocesshackerFileName); + PhDereferenceObject(processhackerSigFileName); +} + +BOOLEAN PhInitializeAppSystem( + VOID + ) +{ + PhApplicationName = L"Process Hacker"; + + if (!PhProcessProviderInitialization()) + return FALSE; + if (!PhServiceProviderInitialization()) + return FALSE; + if (!PhNetworkProviderInitialization()) + return FALSE; + if (!PhModuleProviderInitialization()) + return FALSE; + if (!PhThreadProviderInitialization()) + return FALSE; + if (!PhHandleProviderInitialization()) + return FALSE; + if (!PhMemoryProviderInitialization()) + return FALSE; + if (!PhProcessPropInitialization()) + return FALSE; + + PhSetHandleClientIdFunction(PhGetClientIdName); + + return TRUE; +} + +VOID PhpInitializeSettings( + VOID + ) +{ + NTSTATUS status; + + if (!PhStartupParameters.NoSettings) + { + static PH_STRINGREF settingsSuffix = PH_STRINGREF_INIT(L".settings.xml"); + PPH_STRING settingsFileName; + + // There are three possible locations for the settings file: + // 1. The file name given in the command line. + // 2. A file named ProcessHacker.exe.settings.xml in the program directory. (This changes + // based on the executable file name.) + // 3. The default location. + + // 1. File specified in command line + if (PhStartupParameters.SettingsFileName) + { + // Get an absolute path now. + PhSettingsFileName = PhGetFullPath(PhStartupParameters.SettingsFileName->Buffer, NULL); + } + + // 2. File in program directory + if (!PhSettingsFileName) + { + settingsFileName = PhConcatStringRef2(&PhApplicationFileName->sr, &settingsSuffix); + + if (RtlDoesFileExists_U(settingsFileName->Buffer)) + { + PhSettingsFileName = settingsFileName; + } + else + { + PhDereferenceObject(settingsFileName); + } + } + + // 3. Default location + if (!PhSettingsFileName) + { + PhSettingsFileName = PhGetKnownLocation(CSIDL_APPDATA, L"\\Process Hacker\\settings.xml"); + } + + if (PhSettingsFileName) + { + status = PhLoadSettings(PhSettingsFileName->Buffer); + + // If we didn't find the file, it will be created. Otherwise, + // there was probably a parsing error and we don't want to + // change anything. + if (status == STATUS_FILE_CORRUPT_ERROR) + { + if (PhShowMessage( + NULL, + MB_ICONWARNING | MB_YESNO, + L"Process Hacker's settings file is corrupt. Do you want to reset it?\n" + L"If you select No, the settings system will not function properly." + ) == IDYES) + { + HANDLE fileHandle; + IO_STATUS_BLOCK isb; + CHAR data[] = ""; + + // This used to delete the file. But it's better to keep the file there + // and overwrite it with some valid XML, especially with case (2) above. + if (NT_SUCCESS(PhCreateFileWin32( + &fileHandle, + PhSettingsFileName->Buffer, + FILE_GENERIC_WRITE, + 0, + FILE_SHARE_READ | FILE_SHARE_DELETE, + FILE_OVERWRITE, + FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT + ))) + { + NtWriteFile(fileHandle, NULL, NULL, NULL, &isb, data, sizeof(data) - 1, NULL, NULL); + NtClose(fileHandle); + } + } + else + { + // Pretend we don't have a settings store so bad things + // don't happen. + PhDereferenceObject(PhSettingsFileName); + PhSettingsFileName = NULL; + } + } + } + } + + // Apply basic global settings. + PhMaxSizeUnit = PhGetIntegerSetting(L"MaxSizeUnit"); + + if (PhGetIntegerSetting(L"SampleCountAutomatic")) + { + ULONG sampleCount; + + sampleCount = (GetSystemMetrics(SM_CXVIRTUALSCREEN) + 1) / 2; + + if (sampleCount > 2048) + sampleCount = 2048; + + PhSetIntegerSetting(L"SampleCount", sampleCount); + } +} + +#define PH_ARG_SETTINGS 1 +#define PH_ARG_NOSETTINGS 2 +#define PH_ARG_SHOWVISIBLE 3 +#define PH_ARG_SHOWHIDDEN 4 +#define PH_ARG_COMMANDMODE 5 +#define PH_ARG_COMMANDTYPE 6 +#define PH_ARG_COMMANDOBJECT 7 +#define PH_ARG_COMMANDACTION 8 +#define PH_ARG_COMMANDVALUE 9 +#define PH_ARG_RUNASSERVICEMODE 10 +#define PH_ARG_NOKPH 11 +#define PH_ARG_INSTALLKPH 12 +#define PH_ARG_UNINSTALLKPH 13 +#define PH_ARG_DEBUG 14 +#define PH_ARG_HWND 15 +#define PH_ARG_POINT 16 +#define PH_ARG_SHOWOPTIONS 17 +#define PH_ARG_PHSVC 18 +#define PH_ARG_NOPLUGINS 19 +#define PH_ARG_NEWINSTANCE 20 +#define PH_ARG_ELEVATE 21 +#define PH_ARG_SILENT 22 +#define PH_ARG_HELP 23 +#define PH_ARG_SELECTPID 24 +#define PH_ARG_PRIORITY 25 +#define PH_ARG_PLUGIN 26 +#define PH_ARG_SELECTTAB 27 +#define PH_ARG_SYSINFO 28 + +BOOLEAN NTAPI PhpCommandLineOptionCallback( + _In_opt_ PPH_COMMAND_LINE_OPTION Option, + _In_opt_ PPH_STRING Value, + _In_opt_ PVOID Context + ) +{ + ULONG64 integer; + + if (Option) + { + switch (Option->Id) + { + case PH_ARG_SETTINGS: + PhSwapReference(&PhStartupParameters.SettingsFileName, Value); + break; + case PH_ARG_NOSETTINGS: + PhStartupParameters.NoSettings = TRUE; + break; + case PH_ARG_SHOWVISIBLE: + PhStartupParameters.ShowVisible = TRUE; + break; + case PH_ARG_SHOWHIDDEN: + PhStartupParameters.ShowHidden = TRUE; + break; + case PH_ARG_COMMANDMODE: + PhStartupParameters.CommandMode = TRUE; + break; + case PH_ARG_COMMANDTYPE: + PhSwapReference(&PhStartupParameters.CommandType, Value); + break; + case PH_ARG_COMMANDOBJECT: + PhSwapReference(&PhStartupParameters.CommandObject, Value); + break; + case PH_ARG_COMMANDACTION: + PhSwapReference(&PhStartupParameters.CommandAction, Value); + break; + case PH_ARG_COMMANDVALUE: + PhSwapReference(&PhStartupParameters.CommandValue, Value); + break; + case PH_ARG_RUNASSERVICEMODE: + PhSwapReference(&PhStartupParameters.RunAsServiceMode, Value); + break; + case PH_ARG_NOKPH: + PhStartupParameters.NoKph = TRUE; + break; + case PH_ARG_INSTALLKPH: + PhStartupParameters.InstallKph = TRUE; + break; + case PH_ARG_UNINSTALLKPH: + PhStartupParameters.UninstallKph = TRUE; + break; + case PH_ARG_DEBUG: + PhStartupParameters.Debug = TRUE; + break; + case PH_ARG_HWND: + if (PhStringToInteger64(&Value->sr, 16, &integer)) + PhStartupParameters.WindowHandle = (HWND)(ULONG_PTR)integer; + break; + case PH_ARG_POINT: + { + PH_STRINGREF xString; + PH_STRINGREF yString; + + if (PhSplitStringRefAtChar(&Value->sr, ',', &xString, &yString)) + { + LONG64 x; + LONG64 y; + + if (PhStringToInteger64(&xString, 10, &x) && PhStringToInteger64(&yString, 10, &y)) + { + PhStartupParameters.Point.x = (LONG)x; + PhStartupParameters.Point.y = (LONG)y; + } + } + } + break; + case PH_ARG_SHOWOPTIONS: + PhStartupParameters.ShowOptions = TRUE; + break; + case PH_ARG_PHSVC: + PhStartupParameters.PhSvc = TRUE; + break; + case PH_ARG_NOPLUGINS: + PhStartupParameters.NoPlugins = TRUE; + break; + case PH_ARG_NEWINSTANCE: + PhStartupParameters.NewInstance = TRUE; + break; + case PH_ARG_ELEVATE: + PhStartupParameters.Elevate = TRUE; + break; + case PH_ARG_SILENT: + PhStartupParameters.Silent = TRUE; + break; + case PH_ARG_HELP: + PhStartupParameters.Help = TRUE; + break; + case PH_ARG_SELECTPID: + if (PhStringToInteger64(&Value->sr, 0, &integer)) + PhStartupParameters.SelectPid = (ULONG)integer; + break; + case PH_ARG_PRIORITY: + if (PhEqualString2(Value, L"r", TRUE)) + PhStartupParameters.PriorityClass = PROCESS_PRIORITY_CLASS_REALTIME; + else if (PhEqualString2(Value, L"h", TRUE)) + PhStartupParameters.PriorityClass = PROCESS_PRIORITY_CLASS_HIGH; + else if (PhEqualString2(Value, L"n", TRUE)) + PhStartupParameters.PriorityClass = PROCESS_PRIORITY_CLASS_NORMAL; + else if (PhEqualString2(Value, L"l", TRUE)) + PhStartupParameters.PriorityClass = PROCESS_PRIORITY_CLASS_IDLE; + break; + case PH_ARG_PLUGIN: + if (!PhStartupParameters.PluginParameters) + PhStartupParameters.PluginParameters = PhCreateList(3); + PhAddItemList(PhStartupParameters.PluginParameters, PhReferenceObject(Value)); + break; + case PH_ARG_SELECTTAB: + PhSwapReference(&PhStartupParameters.SelectTab, Value); + break; + case PH_ARG_SYSINFO: + PhSwapReference(&PhStartupParameters.SysInfo, Value ? Value : PhReferenceEmptyString()); + break; + } + } + else + { + PPH_STRING upperValue; + + upperValue = PhDuplicateString(Value); + _wcsupr(upperValue->Buffer); + + if (PhFindStringInString(upperValue, 0, L"TASKMGR.EXE") != -1) + { + // User probably has Process Hacker replacing Task Manager. Force + // the main window to start visible. + PhStartupParameters.ShowVisible = TRUE; + } + + PhDereferenceObject(upperValue); + } + + return TRUE; +} + +VOID PhpProcessStartupParameters( + VOID + ) +{ + static PH_COMMAND_LINE_OPTION options[] = + { + { PH_ARG_SETTINGS, L"settings", MandatoryArgumentType }, + { PH_ARG_NOSETTINGS, L"nosettings", NoArgumentType }, + { PH_ARG_SHOWVISIBLE, L"v", NoArgumentType }, + { PH_ARG_SHOWHIDDEN, L"hide", NoArgumentType }, + { PH_ARG_COMMANDMODE, L"c", NoArgumentType }, + { PH_ARG_COMMANDTYPE, L"ctype", MandatoryArgumentType }, + { PH_ARG_COMMANDOBJECT, L"cobject", MandatoryArgumentType }, + { PH_ARG_COMMANDACTION, L"caction", MandatoryArgumentType }, + { PH_ARG_COMMANDVALUE, L"cvalue", MandatoryArgumentType }, + { PH_ARG_RUNASSERVICEMODE, L"ras", MandatoryArgumentType }, + { PH_ARG_NOKPH, L"nokph", NoArgumentType }, + { PH_ARG_INSTALLKPH, L"installkph", NoArgumentType }, + { PH_ARG_UNINSTALLKPH, L"uninstallkph", NoArgumentType }, + { PH_ARG_DEBUG, L"debug", NoArgumentType }, + { PH_ARG_HWND, L"hwnd", MandatoryArgumentType }, + { PH_ARG_POINT, L"point", MandatoryArgumentType }, + { PH_ARG_SHOWOPTIONS, L"showoptions", NoArgumentType }, + { PH_ARG_PHSVC, L"phsvc", NoArgumentType }, + { PH_ARG_NOPLUGINS, L"noplugins", NoArgumentType }, + { PH_ARG_NEWINSTANCE, L"newinstance", NoArgumentType }, + { PH_ARG_ELEVATE, L"elevate", NoArgumentType }, + { PH_ARG_SILENT, L"s", NoArgumentType }, + { PH_ARG_HELP, L"help", NoArgumentType }, + { PH_ARG_SELECTPID, L"selectpid", MandatoryArgumentType }, + { PH_ARG_PRIORITY, L"priority", MandatoryArgumentType }, + { PH_ARG_PLUGIN, L"plugin", MandatoryArgumentType }, + { PH_ARG_SELECTTAB, L"selecttab", MandatoryArgumentType }, + { PH_ARG_SYSINFO, L"sysinfo", OptionalArgumentType } + }; + PH_STRINGREF commandLine; + + PhUnicodeStringToStringRef(&NtCurrentPeb()->ProcessParameters->CommandLine, &commandLine); + + memset(&PhStartupParameters, 0, sizeof(PH_STARTUP_PARAMETERS)); + + if (!PhParseCommandLine( + &commandLine, + options, + sizeof(options) / sizeof(PH_COMMAND_LINE_OPTION), + PH_COMMAND_LINE_IGNORE_UNKNOWN_OPTIONS | PH_COMMAND_LINE_IGNORE_FIRST_PART, + PhpCommandLineOptionCallback, + NULL + ) || PhStartupParameters.Help) + { + PhShowInformation( + NULL, + L"Command line options:\n\n" + L"-c\n" + L"-ctype command-type\n" + L"-cobject command-object\n" + L"-caction command-action\n" + L"-cvalue command-value\n" + L"-debug\n" + L"-elevate\n" + L"-help\n" + L"-hide\n" + L"-installkph\n" + L"-newinstance\n" + L"-nokph\n" + L"-noplugins\n" + L"-nosettings\n" + L"-plugin pluginname:value\n" + L"-priority r|h|n|l\n" + L"-s\n" + L"-selectpid pid-to-select\n" + L"-selecttab name-of-tab-to-select\n" + L"-settings filename\n" + L"-sysinfo [section-name]\n" + L"-uninstallkph\n" + L"-v\n" + ); + + if (PhStartupParameters.Help) + RtlExitUserProcess(STATUS_SUCCESS); + } + + if (PhStartupParameters.InstallKph) + { + NTSTATUS status; + PPH_STRING kprocesshackerFileName; + KPH_PARAMETERS parameters; + + kprocesshackerFileName = PhConcatStrings2(PhApplicationDirectory->Buffer, L"\\kprocesshacker.sys"); + + parameters.SecurityLevel = KphSecuritySignatureCheck; + parameters.CreateDynamicConfiguration = TRUE; + + status = KphInstallEx(KPH_DEVICE_SHORT_NAME, kprocesshackerFileName->Buffer, ¶meters); + + if (!NT_SUCCESS(status) && !PhStartupParameters.Silent) + PhShowStatus(NULL, L"Unable to install KProcessHacker", status, 0); + + RtlExitUserProcess(status); + } + + if (PhStartupParameters.UninstallKph) + { + NTSTATUS status; + + status = KphUninstall(KPH_DEVICE_SHORT_NAME); + + if (!NT_SUCCESS(status) && !PhStartupParameters.Silent) + PhShowStatus(NULL, L"Unable to uninstall KProcessHacker", status, 0); + + RtlExitUserProcess(status); + } + + if (PhStartupParameters.Elevate && !PhGetOwnTokenAttributes().Elevated) + { + PhShellProcessHacker( + NULL, + NULL, + SW_SHOW, + PH_SHELL_EXECUTE_ADMIN, + PH_SHELL_APP_PROPAGATE_PARAMETERS | PH_SHELL_APP_PROPAGATE_PARAMETERS_FORCE_SETTINGS, + 0, + NULL + ); + RtlExitUserProcess(STATUS_SUCCESS); + } + + if (PhStartupParameters.Debug) + { + // The symbol provider won't work if this is chosen. + PhShowDebugConsole(); + } +} + +VOID PhpEnablePrivileges( + VOID + ) +{ + HANDLE tokenHandle; + + if (NT_SUCCESS(NtOpenProcessToken( + NtCurrentProcess(), + TOKEN_ADJUST_PRIVILEGES, + &tokenHandle + ))) + { + CHAR privilegesBuffer[FIELD_OFFSET(TOKEN_PRIVILEGES, Privileges) + sizeof(LUID_AND_ATTRIBUTES) * 8]; + PTOKEN_PRIVILEGES privileges; + ULONG i; + + privileges = (PTOKEN_PRIVILEGES)privilegesBuffer; + privileges->PrivilegeCount = 8; + + for (i = 0; i < privileges->PrivilegeCount; i++) + { + privileges->Privileges[i].Attributes = SE_PRIVILEGE_ENABLED; + privileges->Privileges[i].Luid.HighPart = 0; + } + + privileges->Privileges[0].Luid.LowPart = SE_DEBUG_PRIVILEGE; + privileges->Privileges[1].Luid.LowPart = SE_INC_BASE_PRIORITY_PRIVILEGE; + privileges->Privileges[2].Luid.LowPart = SE_INC_WORKING_SET_PRIVILEGE; + privileges->Privileges[3].Luid.LowPart = SE_LOAD_DRIVER_PRIVILEGE; + privileges->Privileges[4].Luid.LowPart = SE_PROF_SINGLE_PROCESS_PRIVILEGE; + privileges->Privileges[5].Luid.LowPart = SE_RESTORE_PRIVILEGE; + privileges->Privileges[6].Luid.LowPart = SE_SHUTDOWN_PRIVILEGE; + privileges->Privileges[7].Luid.LowPart = SE_TAKE_OWNERSHIP_PRIVILEGE; + + NtAdjustPrivilegesToken( + tokenHandle, + FALSE, + privileges, + 0, + NULL, + NULL + ); + + NtClose(tokenHandle); + } +} diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index 518c71b74c18..033a4850bd32 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -1,3641 +1,3641 @@ -/* - * Process Hacker - - * Main window - * - * Copyright (C) 2009-2016 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#define RUNAS_MODE_ADMIN 1 -#define RUNAS_MODE_LIMITED 2 - -PHAPPAPI HWND PhMainWndHandle; -BOOLEAN PhMainWndExiting = FALSE; -HMENU PhMainWndMenuHandle; - -PH_PROVIDER_REGISTRATION PhMwpProcessProviderRegistration; -PH_PROVIDER_REGISTRATION PhMwpServiceProviderRegistration; -PH_PROVIDER_REGISTRATION PhMwpNetworkProviderRegistration; -BOOLEAN PhMwpUpdateAutomatically = TRUE; - -ULONG PhMwpNotifyIconNotifyMask; -ULONG PhMwpLastNotificationType; -PH_MWP_NOTIFICATION_DETAILS PhMwpLastNotificationDetails; - -static BOOLEAN NeedsMaximize = FALSE; -static BOOLEAN AlwaysOnTop = FALSE; - -static BOOLEAN DelayedLoadCompleted = FALSE; - -static PH_CALLBACK_DECLARE(LayoutPaddingCallback); -static RECT LayoutPadding = { 0, 0, 0, 0 }; -static BOOLEAN LayoutPaddingValid = TRUE; - -static HWND TabControlHandle; -static PPH_LIST PageList; -static PPH_MAIN_TAB_PAGE CurrentPage; -static INT OldTabIndex; -static HFONT CurrentCustomFont; - -static HMENU SubMenuHandles[5]; -static PPH_EMENU SubMenuObjects[5]; -static PPH_LIST LegacyAddMenuItemList; -static BOOLEAN UsersMenuInitialized = FALSE; - -static PH_CALLBACK_REGISTRATION SymInitRegistration; - -static ULONG SelectedRunAsMode; -static ULONG SelectedUserSessionId; - -BOOLEAN PhMainWndInitialization( - _In_ INT ShowCommand - ) -{ - PH_STRING_BUILDER stringBuilder; - PH_RECTANGLE windowRectangle; - - if (PhGetIntegerSetting(L"FirstRun")) - { - PPH_STRING autoDbghelpPath; - - // Try to set up the dbghelp path automatically if this is the first run. - if (autoDbghelpPath = PH_AUTO(PhMwpFindDbghelpPath())) - PhSetStringSetting2(L"DbgHelpPath", &autoDbghelpPath->sr); - - PhSetIntegerSetting(L"FirstRun", FALSE); - } - - // This was added to be able to delay-load dbghelp.dll and symsrv.dll. - PhRegisterCallback(&PhSymInitCallback, PhMwpSymInitHandler, NULL, &SymInitRegistration); - - PhMwpInitializeProviders(); - - if (!PhMwpInitializeWindowClass()) - return FALSE; - - windowRectangle.Position = PhGetIntegerPairSetting(L"MainWindowPosition"); - windowRectangle.Size = PhGetScalableIntegerPairSetting(L"MainWindowSize", TRUE).Pair; - - // Create the window title. - - PhInitializeStringBuilder(&stringBuilder, 100); - PhAppendStringBuilder2(&stringBuilder, L"Process Hacker"); - - if (PhCurrentUserName) - { - PhAppendStringBuilder2(&stringBuilder, L" ["); - PhAppendStringBuilder(&stringBuilder, &PhCurrentUserName->sr); - PhAppendCharStringBuilder(&stringBuilder, ']'); - if (KphIsConnected()) PhAppendCharStringBuilder(&stringBuilder, '+'); - } - - if (WINDOWS_HAS_UAC && PhGetOwnTokenAttributes().ElevationType == TokenElevationTypeFull) - PhAppendStringBuilder2(&stringBuilder, L" (Administrator)"); - - // Create the window. - - PhMainWndHandle = CreateWindow( - PH_MAINWND_CLASSNAME, - stringBuilder.String->Buffer, - WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN, - windowRectangle.Left, - windowRectangle.Top, - windowRectangle.Width, - windowRectangle.Height, - NULL, - NULL, - PhInstanceHandle, - NULL - ); - PhDeleteStringBuilder(&stringBuilder); - PhMainWndMenuHandle = GetMenu(PhMainWndHandle); - - if (!PhMainWndHandle) - return FALSE; - - PhMwpInitializeMainMenu(PhMainWndMenuHandle); - - // Choose a more appropriate rectangle for the window. - PhAdjustRectangleToWorkingArea(PhMainWndHandle, &windowRectangle); - MoveWindow(PhMainWndHandle, windowRectangle.Left, windowRectangle.Top, - windowRectangle.Width, windowRectangle.Height, FALSE); - - // Allow WM_PH_ACTIVATE to pass through UIPI. - if (WINDOWS_HAS_UAC) - ChangeWindowMessageFilter_I(WM_PH_ACTIVATE, MSGFLT_ADD); - - PhMwpOnSettingChange(); - - // Initialize child controls. - PhMwpInitializeControls(); - - PhMwpLoadSettings(); - PhLogInitialization(); - PhQueueItemWorkQueue(PhGetGlobalWorkQueue(), PhMwpDelayedLoadFunction, NULL); - - PhMwpSelectionChangedTabControl(-1); - - // Perform a layout. - PhMwpOnSize(); - - PhStartProviderThread(&PhPrimaryProviderThread); - PhStartProviderThread(&PhSecondaryProviderThread); - - // See PhMwpOnTimer for more details. - if (PhCsUpdateInterval > PH_FLUSH_PROCESS_QUERY_DATA_INTERVAL_1) - SetTimer(PhMainWndHandle, TIMER_FLUSH_PROCESS_QUERY_DATA, PH_FLUSH_PROCESS_QUERY_DATA_INTERVAL_1, NULL); - - UpdateWindow(PhMainWndHandle); - - if ((PhStartupParameters.ShowHidden || PhGetIntegerSetting(L"StartHidden")) && PhNfTestIconMask(PH_ICON_ALL)) - ShowCommand = SW_HIDE; - if (PhStartupParameters.ShowVisible) - ShowCommand = SW_SHOW; - - if (PhGetIntegerSetting(L"MainWindowState") == SW_MAXIMIZE) - { - if (ShowCommand != SW_HIDE) - { - ShowCommand = SW_MAXIMIZE; - } - else - { - // We can't maximize it while having it hidden. Set it as pending. - NeedsMaximize = TRUE; - } - } - - if (PhPluginsEnabled) - PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackMainWindowShowing), IntToPtr(ShowCommand)); - - if (PhStartupParameters.SelectTab) - { - PPH_MAIN_TAB_PAGE page = PhMwpFindPage(&PhStartupParameters.SelectTab->sr); - - if (page) - PhMwpSelectPage(page->Index); - } - - if (PhStartupParameters.SysInfo) - PhShowSystemInformationDialog(PhStartupParameters.SysInfo->Buffer); - - if (ShowCommand != SW_HIDE) - ShowWindow(PhMainWndHandle, ShowCommand); - - if (PhGetIntegerSetting(L"MiniInfoWindowPinned")) - PhPinMiniInformation(MiniInfoManualPinType, 1, 0, PH_MINIINFO_LOAD_POSITION, NULL, NULL); - - return TRUE; -} - -LRESULT CALLBACK PhMwpWndProc( - _In_ HWND hWnd, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - switch (uMsg) - { - case WM_DESTROY: - { - PhMwpOnDestroy(); - } - break; - case WM_ENDSESSION: - { - PhMwpOnEndSession(); - } - break; - case WM_SETTINGCHANGE: - { - PhMwpOnSettingChange(); - } - break; - case WM_COMMAND: - { - PhMwpOnCommand(LOWORD(wParam)); - } - break; - case WM_SHOWWINDOW: - { - PhMwpOnShowWindow(!!wParam, (ULONG)lParam); - } - break; - case WM_SYSCOMMAND: - { - if (PhMwpOnSysCommand((ULONG)wParam, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))) - return 0; - } - break; - case WM_MENUCOMMAND: - { - PhMwpOnMenuCommand((ULONG)wParam, (HMENU)lParam); - } - break; - case WM_INITMENUPOPUP: - { - PhMwpOnInitMenuPopup((HMENU)wParam, LOWORD(lParam), !!HIWORD(lParam)); - } - break; - case WM_SIZE: - { - PhMwpOnSize(); - } - break; - case WM_SIZING: - { - PhMwpOnSizing((ULONG)wParam, (PRECT)lParam); - } - break; - case WM_SETFOCUS: - { - PhMwpOnSetFocus(); - } - break; - case WM_TIMER: - { - PhMwpOnTimer((ULONG)wParam); - } - break; - case WM_NOTIFY: - { - LRESULT result; - - if (PhMwpOnNotify((NMHDR *)lParam, &result)) - return result; - } - break; - case WM_WTSSESSION_CHANGE: - { - PhMwpOnWtsSessionChange((ULONG)wParam, (ULONG)lParam); - } - break; - } - - if (uMsg >= WM_PH_FIRST && uMsg <= WM_PH_LAST) - { - return PhMwpOnUserMessage(uMsg, wParam, lParam); - } - - return DefWindowProc(hWnd, uMsg, wParam, lParam); -} - -BOOLEAN PhMwpInitializeWindowClass( - VOID - ) -{ - WNDCLASSEX wcex; - - memset(&wcex, 0, sizeof(WNDCLASSEX)); - wcex.cbSize = sizeof(WNDCLASSEX); - wcex.style = 0; - wcex.lpfnWndProc = PhMwpWndProc; - wcex.cbClsExtra = 0; - wcex.cbWndExtra = 0; - wcex.hInstance = PhInstanceHandle; - wcex.hIcon = LoadIcon(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER)); - wcex.hCursor = LoadCursor(NULL, IDC_ARROW); - //wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); - wcex.lpszMenuName = MAKEINTRESOURCE(IDR_MAINWND); - wcex.lpszClassName = PH_MAINWND_CLASSNAME; - wcex.hIconSm = (HICON)LoadImage(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER), IMAGE_ICON, 16, 16, 0); - - if (!RegisterClassEx(&wcex)) - return FALSE; - - return TRUE; -} - -VOID PhMwpInitializeProviders( - VOID - ) -{ - ULONG interval; - - interval = PhGetIntegerSetting(L"UpdateInterval"); - - if (interval == 0) - { - interval = 1000; - PH_SET_INTEGER_CACHED_SETTING(UpdateInterval, interval); - } - - PhInitializeProviderThread(&PhPrimaryProviderThread, interval); - PhInitializeProviderThread(&PhSecondaryProviderThread, interval); - - PhRegisterProvider(&PhPrimaryProviderThread, PhProcessProviderUpdate, NULL, &PhMwpProcessProviderRegistration); - PhSetEnabledProvider(&PhMwpProcessProviderRegistration, TRUE); - PhRegisterProvider(&PhPrimaryProviderThread, PhServiceProviderUpdate, NULL, &PhMwpServiceProviderRegistration); - PhSetEnabledProvider(&PhMwpServiceProviderRegistration, TRUE); - PhRegisterProvider(&PhPrimaryProviderThread, PhNetworkProviderUpdate, NULL, &PhMwpNetworkProviderRegistration); -} - -VOID PhMwpApplyUpdateInterval( - _In_ ULONG Interval - ) -{ - PhSetIntervalProviderThread(&PhPrimaryProviderThread, Interval); - PhSetIntervalProviderThread(&PhSecondaryProviderThread, Interval); - - if (Interval > PH_FLUSH_PROCESS_QUERY_DATA_INTERVAL_LONG_TERM) - SetTimer(PhMainWndHandle, TIMER_FLUSH_PROCESS_QUERY_DATA, PH_FLUSH_PROCESS_QUERY_DATA_INTERVAL_LONG_TERM, NULL); - else - KillTimer(PhMainWndHandle, TIMER_FLUSH_PROCESS_QUERY_DATA); // Might not exist -} - -VOID PhMwpInitializeControls( - VOID - ) -{ - ULONG thinRows; - - TabControlHandle = CreateWindow( - WC_TABCONTROL, - NULL, - WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | TCS_MULTILINE, - 0, - 0, - 3, - 3, - PhMainWndHandle, - NULL, - PhInstanceHandle, - NULL - ); - SendMessage(TabControlHandle, WM_SETFONT, (WPARAM)PhApplicationFont, FALSE); - BringWindowToTop(TabControlHandle); - - thinRows = PhGetIntegerSetting(L"ThinRows") ? TN_STYLE_THIN_ROWS : 0; - - PhMwpProcessTreeNewHandle = CreateWindow( - PH_TREENEW_CLASSNAME, - NULL, - WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_BORDER | TN_STYLE_ICONS | TN_STYLE_DOUBLE_BUFFERED | TN_STYLE_ANIMATE_DIVIDER | thinRows, - 0, - 0, - 3, - 3, - PhMainWndHandle, - (HMENU)ID_MAINWND_PROCESSTL, - PhLibImageBase, - NULL - ); - BringWindowToTop(PhMwpProcessTreeNewHandle); - - PhMwpServiceTreeNewHandle = CreateWindow( - PH_TREENEW_CLASSNAME, - NULL, - WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_BORDER | TN_STYLE_ICONS | TN_STYLE_DOUBLE_BUFFERED | thinRows, - 0, - 0, - 3, - 3, - PhMainWndHandle, - (HMENU)ID_MAINWND_SERVICETL, - PhLibImageBase, - NULL - ); - BringWindowToTop(PhMwpServiceTreeNewHandle); - - PhMwpNetworkTreeNewHandle = CreateWindow( - PH_TREENEW_CLASSNAME, - NULL, - WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_BORDER | TN_STYLE_ICONS | TN_STYLE_DOUBLE_BUFFERED | thinRows, - 0, - 0, - 3, - 3, - PhMainWndHandle, - (HMENU)ID_MAINWND_NETWORKTL, - PhLibImageBase, - NULL - ); - BringWindowToTop(PhMwpNetworkTreeNewHandle); - - PageList = PhCreateList(10); - - PhMwpCreateInternalPage(L"Processes", 0, PhMwpProcessesPageCallback); - PhProcessTreeListInitialization(); - PhInitializeProcessTreeList(PhMwpProcessTreeNewHandle); - - PhMwpCreateInternalPage(L"Services", 0, PhMwpServicesPageCallback); - PhServiceTreeListInitialization(); - PhInitializeServiceTreeList(PhMwpServiceTreeNewHandle); - - PhMwpCreateInternalPage(L"Network", 0, PhMwpNetworkPageCallback); - PhNetworkTreeListInitialization(); - PhInitializeNetworkTreeList(PhMwpNetworkTreeNewHandle); - - CurrentPage = PageList->Items[0]; -} - -NTSTATUS PhMwpDelayedLoadFunction( - _In_ PVOID Parameter - ) -{ - // Register for window station notifications. - WinStationRegisterConsoleNotification(NULL, PhMainWndHandle, WNOTIFY_ALL_SESSIONS); - - PhNfLoadStage2(); - - // Make sure we get closed late in the shutdown process. - SetProcessShutdownParameters(0x100, 0); - - DelayedLoadCompleted = TRUE; - //PostMessage(PhMainWndHandle, WM_PH_DELAYED_LOAD_COMPLETED, 0, 0); - - return STATUS_SUCCESS; -} - -PPH_STRING PhMwpFindDbghelpPath( - VOID - ) -{ - static struct - { - ULONG Folder; - PWSTR AppendPath; - } locations[] = - { -#ifdef _WIN64 - { CSIDL_PROGRAM_FILESX86, L"\\Windows Kits\\10\\Debuggers\\x64\\dbghelp.dll" }, - { CSIDL_PROGRAM_FILESX86, L"\\Windows Kits\\8.1\\Debuggers\\x64\\dbghelp.dll" }, - { CSIDL_PROGRAM_FILESX86, L"\\Windows Kits\\8.0\\Debuggers\\x64\\dbghelp.dll" }, - { CSIDL_PROGRAM_FILES, L"\\Debugging Tools for Windows (x64)\\dbghelp.dll" } -#else - { CSIDL_PROGRAM_FILES, L"\\Windows Kits\\10\\Debuggers\\x86\\dbghelp.dll" }, - { CSIDL_PROGRAM_FILES, L"\\Windows Kits\\8.1\\Debuggers\\x86\\dbghelp.dll" }, - { CSIDL_PROGRAM_FILES, L"\\Windows Kits\\8.0\\Debuggers\\x86\\dbghelp.dll" }, - { CSIDL_PROGRAM_FILES, L"\\Debugging Tools for Windows (x86)\\dbghelp.dll" } -#endif - }; - - PPH_STRING path; - ULONG i; - - for (i = 0; i < sizeof(locations) / sizeof(locations[0]); i++) - { - path = PhGetKnownLocation(locations[i].Folder, locations[i].AppendPath); - - if (path) - { - if (RtlDoesFileExists_U(path->Buffer)) - return path; - - PhDereferenceObject(path); - } - } - - return NULL; -} - -VOID PhMwpOnDestroy( - VOID - ) -{ - // Notify pages and plugins that we are shutting down. - - PhMwpNotifyAllPages(MainTabPageDestroy, NULL, NULL); - - if (PhPluginsEnabled) - PhUnloadPlugins(); - - if (!PhMainWndExiting) - ProcessHacker_SaveAllSettings(PhMainWndHandle); - - PhNfUninitialization(); - - PostQuitMessage(0); -} - -VOID PhMwpOnEndSession( - VOID - ) -{ - PhMwpOnDestroy(); -} - -VOID PhMwpOnSettingChange( - VOID - ) -{ - if (PhApplicationFont) - DeleteObject(PhApplicationFont); - - PhInitializeFont(PhMainWndHandle); - - SendMessage(TabControlHandle, WM_SETFONT, (WPARAM)PhApplicationFont, FALSE); -} - -VOID PhMwpOnCommand( - _In_ ULONG Id - ) -{ - switch (Id) - { - case ID_ESC_EXIT: - { - if (PhGetIntegerSetting(L"HideOnClose")) - { - if (PhNfTestIconMask(PH_ICON_ALL)) - ShowWindow(PhMainWndHandle, SW_HIDE); - } - else if (PhGetIntegerSetting(L"CloseOnEscape")) - { - ProcessHacker_Destroy(PhMainWndHandle); - } - } - break; - case ID_HACKER_RUN: - { - if (RunFileDlg) - { - SelectedRunAsMode = 0; - RunFileDlg(PhMainWndHandle, NULL, NULL, NULL, NULL, 0); - } - } - break; - case ID_HACKER_RUNASADMINISTRATOR: - { - if (RunFileDlg) - { - SelectedRunAsMode = RUNAS_MODE_ADMIN; - RunFileDlg( - PhMainWndHandle, - NULL, - NULL, - NULL, - L"Type the name of a program that will be opened under alternate credentials.", - 0 - ); - } - } - break; - case ID_HACKER_RUNASLIMITEDUSER: - { - if (RunFileDlg) - { - SelectedRunAsMode = RUNAS_MODE_LIMITED; - RunFileDlg( - PhMainWndHandle, - NULL, - NULL, - NULL, - L"Type the name of a program that will be opened under standard user privileges.", - 0 - ); - } - } - break; - case ID_HACKER_RUNAS: - { - PhShowRunAsDialog(PhMainWndHandle, NULL); - } - break; - case ID_HACKER_SHOWDETAILSFORALLPROCESSES: - { - ProcessHacker_PrepareForEarlyShutdown(PhMainWndHandle); - - if (PhShellProcessHacker( - PhMainWndHandle, - L"-v", - SW_SHOW, - PH_SHELL_EXECUTE_ADMIN, - PH_SHELL_APP_PROPAGATE_PARAMETERS | PH_SHELL_APP_PROPAGATE_PARAMETERS_IGNORE_VISIBILITY, - 0, - NULL - )) - { - ProcessHacker_Destroy(PhMainWndHandle); - } - else - { - ProcessHacker_CancelEarlyShutdown(PhMainWndHandle); - } - } - break; - case ID_HACKER_SAVE: - { - static PH_FILETYPE_FILTER filters[] = - { - { L"Text files (*.txt;*.log)", L"*.txt;*.log" }, - { L"Comma-separated values (*.csv)", L"*.csv" }, - { L"All files (*.*)", L"*.*" } - }; - PVOID fileDialog = PhCreateSaveFileDialog(); - PH_FORMAT format[3]; - - PhInitFormatS(&format[0], L"Process Hacker "); - PhInitFormatSR(&format[1], CurrentPage->Name); - PhInitFormatS(&format[2], L".txt"); - - PhSetFileDialogFilter(fileDialog, filters, sizeof(filters) / sizeof(PH_FILETYPE_FILTER)); - PhSetFileDialogFileName(fileDialog, PH_AUTO_T(PH_STRING, PhFormat(format, 3, 60))->Buffer); - - if (PhShowFileDialog(PhMainWndHandle, fileDialog)) - { - NTSTATUS status; - PPH_STRING fileName; - ULONG filterIndex; - PPH_FILE_STREAM fileStream; - - fileName = PH_AUTO(PhGetFileDialogFileName(fileDialog)); - filterIndex = PhGetFileDialogFilterIndex(fileDialog); - - if (NT_SUCCESS(status = PhCreateFileStream( - &fileStream, - fileName->Buffer, - FILE_GENERIC_WRITE, - FILE_SHARE_READ, - FILE_OVERWRITE_IF, - 0 - ))) - { - ULONG mode; - PH_MAIN_TAB_PAGE_EXPORT_CONTENT exportContent; - - if (filterIndex == 2) - mode = PH_EXPORT_MODE_CSV; - else - mode = PH_EXPORT_MODE_TABS; - - PhWriteStringAsUtf8FileStream(fileStream, &PhUnicodeByteOrderMark); - PhWritePhTextHeader(fileStream); - - exportContent.FileStream = fileStream; - exportContent.Mode = mode; - CurrentPage->Callback(CurrentPage, MainTabPageExportContent, &exportContent, NULL); - - PhDereferenceObject(fileStream); - } - - if (!NT_SUCCESS(status)) - PhShowStatus(PhMainWndHandle, L"Unable to create the file", status, 0); - } - - PhFreeFileDialog(fileDialog); - } - break; - case ID_HACKER_FINDHANDLESORDLLS: - { - PhShowFindObjectsDialog(); - } - break; - case ID_HACKER_OPTIONS: - { - PhShowOptionsDialog(PhMainWndHandle); - } - break; - case ID_HACKER_PLUGINS: - { - PhShowPluginsDialog(PhMainWndHandle); - } - break; - case ID_COMPUTER_LOCK: - case ID_COMPUTER_LOGOFF: - case ID_COMPUTER_SLEEP: - case ID_COMPUTER_HIBERNATE: - case ID_COMPUTER_RESTART: - case ID_COMPUTER_RESTARTBOOTOPTIONS: - case ID_COMPUTER_SHUTDOWN: - case ID_COMPUTER_SHUTDOWNHYBRID: - PhMwpExecuteComputerCommand(Id); - break; - case ID_HACKER_EXIT: - ProcessHacker_Destroy(PhMainWndHandle); - break; - case ID_VIEW_SYSTEMINFORMATION: - PhShowSystemInformationDialog(NULL); - break; - case ID_TRAYICONS_CPUHISTORY: - case ID_TRAYICONS_CPUUSAGE: - case ID_TRAYICONS_IOHISTORY: - case ID_TRAYICONS_COMMITHISTORY: - case ID_TRAYICONS_PHYSICALMEMORYHISTORY: - { - ULONG i; - - switch (Id) - { - case ID_TRAYICONS_CPUHISTORY: - i = PH_ICON_CPU_HISTORY; - break; - case ID_TRAYICONS_CPUUSAGE: - i = PH_ICON_CPU_USAGE; - break; - case ID_TRAYICONS_IOHISTORY: - i = PH_ICON_IO_HISTORY; - break; - case ID_TRAYICONS_COMMITHISTORY: - i = PH_ICON_COMMIT_HISTORY; - break; - case ID_TRAYICONS_PHYSICALMEMORYHISTORY: - i = PH_ICON_PHYSICAL_HISTORY; - break; - } - - PhNfSetVisibleIcon(i, !PhNfTestIconMask(i)); - } - break; - case ID_VIEW_HIDEPROCESSESFROMOTHERUSERS: - { - PhMwpToggleCurrentUserProcessTreeFilter(); - } - break; - case ID_VIEW_HIDESIGNEDPROCESSES: - { - PhMwpToggleSignedProcessTreeFilter(); - } - break; - case ID_VIEW_SCROLLTONEWPROCESSES: - { - PH_SET_INTEGER_CACHED_SETTING(ScrollToNewProcesses, !PhCsScrollToNewProcesses); - } - break; - case ID_VIEW_SHOWCPUBELOW001: - { - PH_SET_INTEGER_CACHED_SETTING(ShowCpuBelow001, !PhCsShowCpuBelow001); - PhInvalidateAllProcessNodes(); - } - break; - case ID_VIEW_HIDEDRIVERSERVICES: - { - PhMwpToggleDriverServiceTreeFilter(); - } - break; - case ID_VIEW_ALWAYSONTOP: - { - AlwaysOnTop = !AlwaysOnTop; - SetWindowPos(PhMainWndHandle, AlwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST, - 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE); - PhSetIntegerSetting(L"MainWindowAlwaysOnTop", AlwaysOnTop); - } - break; - case ID_OPACITY_10: - case ID_OPACITY_20: - case ID_OPACITY_30: - case ID_OPACITY_40: - case ID_OPACITY_50: - case ID_OPACITY_60: - case ID_OPACITY_70: - case ID_OPACITY_80: - case ID_OPACITY_90: - case ID_OPACITY_OPAQUE: - { - ULONG opacity; - - opacity = PH_ID_TO_OPACITY(Id); - PhSetIntegerSetting(L"MainWindowOpacity", opacity); - PhSetWindowOpacity(PhMainWndHandle, opacity); - } - break; - case ID_VIEW_REFRESH: - { - PhBoostProvider(&PhMwpProcessProviderRegistration, NULL); - PhBoostProvider(&PhMwpServiceProviderRegistration, NULL); - } - break; - case ID_UPDATEINTERVAL_FAST: - case ID_UPDATEINTERVAL_NORMAL: - case ID_UPDATEINTERVAL_BELOWNORMAL: - case ID_UPDATEINTERVAL_SLOW: - case ID_UPDATEINTERVAL_VERYSLOW: - { - ULONG interval; - - switch (Id) - { - case ID_UPDATEINTERVAL_FAST: - interval = 500; - break; - case ID_UPDATEINTERVAL_NORMAL: - interval = 1000; - break; - case ID_UPDATEINTERVAL_BELOWNORMAL: - interval = 2000; - break; - case ID_UPDATEINTERVAL_SLOW: - interval = 5000; - break; - case ID_UPDATEINTERVAL_VERYSLOW: - interval = 10000; - break; - } - - PH_SET_INTEGER_CACHED_SETTING(UpdateInterval, interval); - PhMwpApplyUpdateInterval(interval); - } - break; - case ID_VIEW_UPDATEAUTOMATICALLY: - { - PhMwpUpdateAutomatically = !PhMwpUpdateAutomatically; - PhMwpNotifyAllPages(MainTabPageUpdateAutomaticallyChanged, (PVOID)PhMwpUpdateAutomatically, NULL); - } - break; - case ID_TOOLS_CREATESERVICE: - { - PhShowCreateServiceDialog(PhMainWndHandle); - } - break; - case ID_TOOLS_HIDDENPROCESSES: - { - PhShowHiddenProcessesDialog(); - } - break; - case ID_TOOLS_INSPECTEXECUTABLEFILE: - { - static PH_FILETYPE_FILTER filters[] = - { - { L"Executable files (*.exe;*.dll;*.ocx;*.sys;*.scr;*.cpl)", L"*.exe;*.dll;*.ocx;*.sys;*.scr;*.cpl" }, - { L"All files (*.*)", L"*.*" } - }; - PVOID fileDialog = PhCreateOpenFileDialog(); - - PhSetFileDialogFilter(fileDialog, filters, sizeof(filters) / sizeof(PH_FILETYPE_FILTER)); - - if (PhShowFileDialog(PhMainWndHandle, fileDialog)) - { - PhShellExecuteUserString( - PhMainWndHandle, - L"ProgramInspectExecutables", - PH_AUTO_T(PH_STRING, PhGetFileDialogFileName(fileDialog))->Buffer, - FALSE, - L"Make sure the PE Viewer executable file is present." - ); - } - - PhFreeFileDialog(fileDialog); - } - break; - case ID_TOOLS_PAGEFILES: - { - PhShowPagefilesDialog(PhMainWndHandle); - } - break; - case ID_TOOLS_STARTTASKMANAGER: - { - PPH_STRING systemDirectory; - PPH_STRING taskmgrFileName; - - systemDirectory = PH_AUTO(PhGetSystemDirectory()); - taskmgrFileName = PH_AUTO(PhConcatStrings2(systemDirectory->Buffer, L"\\taskmgr.exe")); - - if (WindowsVersion >= WINDOWS_8 && !PhGetOwnTokenAttributes().Elevated) - { - if (PhUiConnectToPhSvc(PhMainWndHandle, FALSE)) - { - PhSvcCallCreateProcessIgnoreIfeoDebugger(taskmgrFileName->Buffer); - PhUiDisconnectFromPhSvc(); - } - } - else - { - PhCreateProcessIgnoreIfeoDebugger(taskmgrFileName->Buffer); - } - } - break; - case ID_USER_CONNECT: - { - PhUiConnectSession(PhMainWndHandle, SelectedUserSessionId); - } - break; - case ID_USER_DISCONNECT: - { - PhUiDisconnectSession(PhMainWndHandle, SelectedUserSessionId); - } - break; - case ID_USER_LOGOFF: - { - PhUiLogoffSession(PhMainWndHandle, SelectedUserSessionId); - } - break; - case ID_USER_REMOTECONTROL: - { - PhShowSessionShadowDialog(PhMainWndHandle, SelectedUserSessionId); - } - break; - case ID_USER_SENDMESSAGE: - { - PhShowSessionSendMessageDialog(PhMainWndHandle, SelectedUserSessionId); - } - break; - case ID_USER_PROPERTIES: - { - PhShowSessionProperties(PhMainWndHandle, SelectedUserSessionId); - } - break; - case ID_HELP_LOG: - { - PhShowLogDialog(); - } - break; - case ID_HELP_DONATE: - { - PhShellExecute(PhMainWndHandle, L"https://sourceforge.net/project/project_donations.php?group_id=242527", NULL); - } - break; - case ID_HELP_DEBUGCONSOLE: - { - PhShowDebugConsole(); - } - break; - case ID_HELP_ABOUT: - { - PhShowAboutDialog(PhMainWndHandle); - } - break; - case ID_PROCESS_TERMINATE: - { - PPH_PROCESS_ITEM *processes; - ULONG numberOfProcesses; - - PhGetSelectedProcessItems(&processes, &numberOfProcesses); - PhReferenceObjects(processes, numberOfProcesses); - - if (PhUiTerminateProcesses(PhMainWndHandle, processes, numberOfProcesses)) - PhDeselectAllProcessNodes(); - - PhDereferenceObjects(processes, numberOfProcesses); - PhFree(processes); - } - break; - case ID_PROCESS_TERMINATETREE: - { - PPH_PROCESS_ITEM processItem = PhGetSelectedProcessItem(); - - if (processItem) - { - PhReferenceObject(processItem); - - if (PhUiTerminateTreeProcess(PhMainWndHandle, processItem)) - PhDeselectAllProcessNodes(); - - PhDereferenceObject(processItem); - } - } - break; - case ID_PROCESS_SUSPEND: - { - PPH_PROCESS_ITEM *processes; - ULONG numberOfProcesses; - - PhGetSelectedProcessItems(&processes, &numberOfProcesses); - PhReferenceObjects(processes, numberOfProcesses); - PhUiSuspendProcesses(PhMainWndHandle, processes, numberOfProcesses); - PhDereferenceObjects(processes, numberOfProcesses); - PhFree(processes); - } - break; - case ID_PROCESS_RESUME: - { - PPH_PROCESS_ITEM *processes; - ULONG numberOfProcesses; - - PhGetSelectedProcessItems(&processes, &numberOfProcesses); - PhReferenceObjects(processes, numberOfProcesses); - PhUiResumeProcesses(PhMainWndHandle, processes, numberOfProcesses); - PhDereferenceObjects(processes, numberOfProcesses); - PhFree(processes); - } - break; - case ID_PROCESS_RESTART: - { - PPH_PROCESS_ITEM processItem = PhGetSelectedProcessItem(); - - if (processItem) - { - PhReferenceObject(processItem); - - if (PhUiRestartProcess(PhMainWndHandle, processItem)) - PhDeselectAllProcessNodes(); - - PhDereferenceObject(processItem); - } - } - break; - case ID_PROCESS_CREATEDUMPFILE: - { - PPH_PROCESS_ITEM processItem = PhGetSelectedProcessItem(); - - if (processItem) - { - PhReferenceObject(processItem); - PhUiCreateDumpFileProcess(PhMainWndHandle, processItem); - PhDereferenceObject(processItem); - } - } - break; - case ID_PROCESS_DEBUG: - { - PPH_PROCESS_ITEM processItem = PhGetSelectedProcessItem(); - - if (processItem) - { - PhReferenceObject(processItem); - PhUiDebugProcess(PhMainWndHandle, processItem); - PhDereferenceObject(processItem); - } - } - break; - case ID_PROCESS_VIRTUALIZATION: - { - PPH_PROCESS_ITEM processItem = PhGetSelectedProcessItem(); - - if (processItem) - { - PhReferenceObject(processItem); - PhUiSetVirtualizationProcess( - PhMainWndHandle, - processItem, - !PhMwpSelectedProcessVirtualizationEnabled - ); - PhDereferenceObject(processItem); - } - } - break; - case ID_PROCESS_AFFINITY: - { - PPH_PROCESS_ITEM processItem = PhGetSelectedProcessItem(); - - if (processItem) - { - PhReferenceObject(processItem); - PhShowProcessAffinityDialog(PhMainWndHandle, processItem, NULL); - PhDereferenceObject(processItem); - } - } - break; - case ID_MISCELLANEOUS_DETACHFROMDEBUGGER: - { - PPH_PROCESS_ITEM processItem = PhGetSelectedProcessItem(); - - if (processItem) - { - PhReferenceObject(processItem); - PhUiDetachFromDebuggerProcess(PhMainWndHandle, processItem); - PhDereferenceObject(processItem); - } - } - break; - case ID_MISCELLANEOUS_GDIHANDLES: - { - PPH_PROCESS_ITEM processItem = PhGetSelectedProcessItem(); - - if (processItem) - { - PhReferenceObject(processItem); - PhShowGdiHandlesDialog(PhMainWndHandle, processItem); - PhDereferenceObject(processItem); - } - } - break; - case ID_MISCELLANEOUS_INJECTDLL: - { - PPH_PROCESS_ITEM processItem = PhGetSelectedProcessItem(); - - if (processItem) - { - PhReferenceObject(processItem); - PhUiInjectDllProcess(PhMainWndHandle, processItem); - PhDereferenceObject(processItem); - } - } - break; - case ID_PAGEPRIORITY_VERYLOW: - case ID_PAGEPRIORITY_LOW: - case ID_PAGEPRIORITY_MEDIUM: - case ID_PAGEPRIORITY_BELOWNORMAL: - case ID_PAGEPRIORITY_NORMAL: - { - PPH_PROCESS_ITEM processItem = PhGetSelectedProcessItem(); - - if (processItem) - { - ULONG pagePriority; - - switch (Id) - { - case ID_PAGEPRIORITY_VERYLOW: - pagePriority = MEMORY_PRIORITY_VERY_LOW; - break; - case ID_PAGEPRIORITY_LOW: - pagePriority = MEMORY_PRIORITY_LOW; - break; - case ID_PAGEPRIORITY_MEDIUM: - pagePriority = MEMORY_PRIORITY_MEDIUM; - break; - case ID_PAGEPRIORITY_BELOWNORMAL: - pagePriority = MEMORY_PRIORITY_BELOW_NORMAL; - break; - case ID_PAGEPRIORITY_NORMAL: - pagePriority = MEMORY_PRIORITY_NORMAL; - break; - } - - PhReferenceObject(processItem); - PhUiSetPagePriorityProcess(PhMainWndHandle, processItem, pagePriority); - PhDereferenceObject(processItem); - } - } - break; - case ID_MISCELLANEOUS_REDUCEWORKINGSET: - { - PPH_PROCESS_ITEM *processes; - ULONG numberOfProcesses; - - PhGetSelectedProcessItems(&processes, &numberOfProcesses); - PhReferenceObjects(processes, numberOfProcesses); - PhUiReduceWorkingSetProcesses(PhMainWndHandle, processes, numberOfProcesses); - PhDereferenceObjects(processes, numberOfProcesses); - PhFree(processes); - } - break; - case ID_MISCELLANEOUS_RUNAS: - { - PPH_PROCESS_ITEM processItem = PhGetSelectedProcessItem(); - - if (processItem && processItem->FileName) - { - PhSetStringSetting2(L"RunAsProgram", &processItem->FileName->sr); - PhShowRunAsDialog(PhMainWndHandle, NULL); - } - } - break; - case ID_MISCELLANEOUS_RUNASTHISUSER: - { - PPH_PROCESS_ITEM processItem = PhGetSelectedProcessItem(); - - if (processItem) - { - PhShowRunAsDialog(PhMainWndHandle, processItem->ProcessId); - } - } - break; - case ID_PRIORITY_REALTIME: - case ID_PRIORITY_HIGH: - case ID_PRIORITY_ABOVENORMAL: - case ID_PRIORITY_NORMAL: - case ID_PRIORITY_BELOWNORMAL: - case ID_PRIORITY_IDLE: - { - PPH_PROCESS_ITEM *processes; - ULONG numberOfProcesses; - - PhGetSelectedProcessItems(&processes, &numberOfProcesses); - PhReferenceObjects(processes, numberOfProcesses); - PhMwpExecuteProcessPriorityCommand(Id, processes, numberOfProcesses); - PhDereferenceObjects(processes, numberOfProcesses); - PhFree(processes); - } - break; - case ID_IOPRIORITY_VERYLOW: - case ID_IOPRIORITY_LOW: - case ID_IOPRIORITY_NORMAL: - case ID_IOPRIORITY_HIGH: - { - PPH_PROCESS_ITEM *processes; - ULONG numberOfProcesses; - - PhGetSelectedProcessItems(&processes, &numberOfProcesses); - PhReferenceObjects(processes, numberOfProcesses); - PhMwpExecuteProcessIoPriorityCommand(Id, processes, numberOfProcesses); - PhDereferenceObjects(processes, numberOfProcesses); - PhFree(processes); - } - break; - case ID_WINDOW_BRINGTOFRONT: - { - if (IsWindow(PhMwpSelectedProcessWindowHandle)) - { - WINDOWPLACEMENT placement = { sizeof(placement) }; - - GetWindowPlacement(PhMwpSelectedProcessWindowHandle, &placement); - - if (placement.showCmd == SW_MINIMIZE) - ShowWindowAsync(PhMwpSelectedProcessWindowHandle, SW_RESTORE); - else - SetForegroundWindow(PhMwpSelectedProcessWindowHandle); - } - } - break; - case ID_WINDOW_RESTORE: - { - if (IsWindow(PhMwpSelectedProcessWindowHandle)) - { - ShowWindowAsync(PhMwpSelectedProcessWindowHandle, SW_RESTORE); - } - } - break; - case ID_WINDOW_MINIMIZE: - { - if (IsWindow(PhMwpSelectedProcessWindowHandle)) - { - ShowWindowAsync(PhMwpSelectedProcessWindowHandle, SW_MINIMIZE); - } - } - break; - case ID_WINDOW_MAXIMIZE: - { - if (IsWindow(PhMwpSelectedProcessWindowHandle)) - { - ShowWindowAsync(PhMwpSelectedProcessWindowHandle, SW_MAXIMIZE); - } - } - break; - case ID_WINDOW_CLOSE: - { - if (IsWindow(PhMwpSelectedProcessWindowHandle)) - { - PostMessage(PhMwpSelectedProcessWindowHandle, WM_CLOSE, 0, 0); - } - } - break; - case ID_PROCESS_OPENFILELOCATION: - { - PPH_PROCESS_ITEM processItem = PhGetSelectedProcessItem(); - - if (processItem && processItem->FileName) - { - PhReferenceObject(processItem); - PhShellExploreFile(PhMainWndHandle, processItem->FileName->Buffer); - PhDereferenceObject(processItem); - } - } - break; - case ID_PROCESS_SEARCHONLINE: - { - PPH_PROCESS_ITEM processItem = PhGetSelectedProcessItem(); - - if (processItem) - { - PhSearchOnlineString(PhMainWndHandle, processItem->ProcessName->Buffer); - } - } - break; - case ID_PROCESS_PROPERTIES: - { - PPH_PROCESS_ITEM processItem = PhGetSelectedProcessItem(); - - if (processItem) - { - // No reference needed; no messages pumped. - PhMwpShowProcessProperties(processItem); - } - } - break; - case ID_PROCESS_COPY: - { - PhCopyProcessTree(); - } - break; - case ID_SERVICE_GOTOPROCESS: - { - PPH_SERVICE_ITEM serviceItem = PhGetSelectedServiceItem(); - PPH_PROCESS_NODE processNode; - - if (serviceItem) - { - if (processNode = PhFindProcessNode(serviceItem->ProcessId)) - { - PhMwpSelectPage(PhMwpProcessesPage->Index); - SetFocus(PhMwpProcessTreeNewHandle); - PhSelectAndEnsureVisibleProcessNode(processNode); - } - } - } - break; - case ID_SERVICE_START: - { - PPH_SERVICE_ITEM serviceItem = PhGetSelectedServiceItem(); - - if (serviceItem) - { - PhReferenceObject(serviceItem); - PhUiStartService(PhMainWndHandle, serviceItem); - PhDereferenceObject(serviceItem); - } - } - break; - case ID_SERVICE_CONTINUE: - { - PPH_SERVICE_ITEM serviceItem = PhGetSelectedServiceItem(); - - if (serviceItem) - { - PhReferenceObject(serviceItem); - PhUiContinueService(PhMainWndHandle, serviceItem); - PhDereferenceObject(serviceItem); - } - } - break; - case ID_SERVICE_PAUSE: - { - PPH_SERVICE_ITEM serviceItem = PhGetSelectedServiceItem(); - - if (serviceItem) - { - PhReferenceObject(serviceItem); - PhUiPauseService(PhMainWndHandle, serviceItem); - PhDereferenceObject(serviceItem); - } - } - break; - case ID_SERVICE_STOP: - { - PPH_SERVICE_ITEM serviceItem = PhGetSelectedServiceItem(); - - if (serviceItem) - { - PhReferenceObject(serviceItem); - PhUiStopService(PhMainWndHandle, serviceItem); - PhDereferenceObject(serviceItem); - } - } - break; - case ID_SERVICE_DELETE: - { - PPH_SERVICE_ITEM serviceItem = PhGetSelectedServiceItem(); - - if (serviceItem) - { - PhReferenceObject(serviceItem); - - if (PhUiDeleteService(PhMainWndHandle, serviceItem)) - PhDeselectAllServiceNodes(); - - PhDereferenceObject(serviceItem); - } - } - break; - case ID_SERVICE_OPENKEY: - { - static PH_STRINGREF servicesKeyName = PH_STRINGREF_INIT(L"System\\CurrentControlSet\\Services\\"); - static PH_STRINGREF hklm = PH_STRINGREF_INIT(L"HKLM\\"); - - PPH_SERVICE_ITEM serviceItem = PhGetSelectedServiceItem(); - - if (serviceItem) - { - HANDLE keyHandle; - PPH_STRING serviceKeyName = PH_AUTO(PhConcatStringRef2(&servicesKeyName, &serviceItem->Name->sr)); - - if (NT_SUCCESS(PhOpenKey( - &keyHandle, - KEY_READ, - PH_KEY_LOCAL_MACHINE, - &serviceKeyName->sr, - 0 - ))) - { - PPH_STRING hklmServiceKeyName; - - hklmServiceKeyName = PH_AUTO(PhConcatStringRef2(&hklm, &serviceKeyName->sr)); - PhShellOpenKey2(PhMainWndHandle, hklmServiceKeyName); - NtClose(keyHandle); - } - } - } - break; - case ID_SERVICE_OPENFILELOCATION: - { - PPH_SERVICE_ITEM serviceItem = PhGetSelectedServiceItem(); - SC_HANDLE serviceHandle; - - if (serviceItem && (serviceHandle = PhOpenService(serviceItem->Name->Buffer, SERVICE_QUERY_CONFIG))) - { - PPH_STRING fileName; - - if (fileName = PhGetServiceRelevantFileName(&serviceItem->Name->sr, serviceHandle)) - { - PhShellExploreFile(PhMainWndHandle, fileName->Buffer); - PhDereferenceObject(fileName); - } - - CloseServiceHandle(serviceHandle); - } - } - break; - case ID_SERVICE_PROPERTIES: - { - PPH_SERVICE_ITEM serviceItem = PhGetSelectedServiceItem(); - - if (serviceItem) - { - // The object relies on the list view reference, which could - // disappear if we don't reference the object here. - PhReferenceObject(serviceItem); - PhShowServiceProperties(PhMainWndHandle, serviceItem); - PhDereferenceObject(serviceItem); - } - } - break; - case ID_SERVICE_COPY: - { - PhCopyServiceList(); - } - break; - case ID_NETWORK_GOTOPROCESS: - { - PPH_NETWORK_ITEM networkItem = PhGetSelectedNetworkItem(); - PPH_PROCESS_NODE processNode; - - if (networkItem) - { - if (processNode = PhFindProcessNode(networkItem->ProcessId)) - { - PhMwpSelectPage(PhMwpProcessesPage->Index); - SetFocus(PhMwpProcessTreeNewHandle); - PhSelectAndEnsureVisibleProcessNode(processNode); - } - } - } - break; - case ID_NETWORK_GOTOSERVICE: - { - PPH_NETWORK_ITEM networkItem = PhGetSelectedNetworkItem(); - PPH_SERVICE_ITEM serviceItem; - - if (networkItem && networkItem->OwnerName) - { - if (serviceItem = PhReferenceServiceItem(networkItem->OwnerName->Buffer)) - { - PhMwpSelectPage(PhMwpServicesPage->Index); - SetFocus(PhMwpServiceTreeNewHandle); - ProcessHacker_SelectServiceItem(PhMainWndHandle, serviceItem); - - PhDereferenceObject(serviceItem); - } - } - } - break; - case ID_NETWORK_VIEWSTACK: - { - PPH_NETWORK_ITEM networkItem = PhGetSelectedNetworkItem(); - - if (networkItem) - { - PhReferenceObject(networkItem); - PhShowNetworkStackDialog(PhMainWndHandle, networkItem); - PhDereferenceObject(networkItem); - } - } - break; - case ID_NETWORK_CLOSE: - { - PPH_NETWORK_ITEM *networkItems; - ULONG numberOfNetworkItems; - - PhGetSelectedNetworkItems(&networkItems, &numberOfNetworkItems); - PhReferenceObjects(networkItems, numberOfNetworkItems); - - if (PhUiCloseConnections(PhMainWndHandle, networkItems, numberOfNetworkItems)) - PhDeselectAllNetworkNodes(); - - PhDereferenceObjects(networkItems, numberOfNetworkItems); - PhFree(networkItems); - } - break; - case ID_NETWORK_COPY: - { - PhCopyNetworkList(); - } - break; - case ID_TAB_NEXT: - { - ULONG selectedIndex = TabCtrl_GetCurSel(TabControlHandle); - - if (selectedIndex != PageList->Count - 1) - selectedIndex++; - else - selectedIndex = 0; - - PhMwpSelectPage(selectedIndex); - } - break; - case ID_TAB_PREV: - { - ULONG selectedIndex = TabCtrl_GetCurSel(TabControlHandle); - - if (selectedIndex != 0) - selectedIndex--; - else - selectedIndex = PageList->Count - 1; - - PhMwpSelectPage(selectedIndex); - } - break; - } -} - -VOID PhMwpOnShowWindow( - _In_ BOOLEAN Showing, - _In_ ULONG State - ) -{ - if (NeedsMaximize) - { - ShowWindow(PhMainWndHandle, SW_MAXIMIZE); - NeedsMaximize = FALSE; - } -} - -BOOLEAN PhMwpOnSysCommand( - _In_ ULONG Type, - _In_ LONG CursorScreenX, - _In_ LONG CursorScreenY - ) -{ - switch (Type) - { - case SC_CLOSE: - { - if (PhGetIntegerSetting(L"HideOnClose") && PhNfTestIconMask(PH_ICON_ALL)) - { - ShowWindow(PhMainWndHandle, SW_HIDE); - return TRUE; - } - } - break; - case SC_MINIMIZE: - { - // Save the current window state because we may not have a chance to later. - PhMwpSaveWindowState(); - - if (PhGetIntegerSetting(L"HideOnMinimize") && PhNfTestIconMask(PH_ICON_ALL)) - { - ShowWindow(PhMainWndHandle, SW_HIDE); - return TRUE; - } - } - break; - } - - return FALSE; -} - -VOID PhMwpOnMenuCommand( - _In_ ULONG Index, - _In_ HMENU Menu - ) -{ - MENUITEMINFO menuItemInfo; - - menuItemInfo.cbSize = sizeof(MENUITEMINFO); - menuItemInfo.fMask = MIIM_ID | MIIM_DATA; - - if (GetMenuItemInfo(Menu, Index, TRUE, &menuItemInfo)) - { - PhMwpDispatchMenuCommand(Menu, Index, menuItemInfo.wID, menuItemInfo.dwItemData); - } -} - -VOID PhMwpOnInitMenuPopup( - _In_ HMENU Menu, - _In_ ULONG Index, - _In_ BOOLEAN IsWindowMenu - ) -{ - ULONG i; - BOOLEAN found; - MENUINFO menuInfo; - PPH_EMENU menu; - - found = FALSE; - - for (i = 0; i < sizeof(SubMenuHandles) / sizeof(HWND); i++) - { - if (Menu == SubMenuHandles[i]) - { - found = TRUE; - break; - } - } - - if (!found) - return; - - if (Index == 3) - { - // Special case for Users menu. - if (!UsersMenuInitialized) - { - PhMwpUpdateUsersMenu(); - UsersMenuInitialized = TRUE; - } - - return; - } - - // Delete all items in this submenu. - while (DeleteMenu(Menu, 0, MF_BYPOSITION)) ; - - // Delete the previous EMENU for this submenu. - if (SubMenuObjects[Index]) - PhDestroyEMenu(SubMenuObjects[Index]); - - // Make sure the menu style is set correctly. - memset(&menuInfo, 0, sizeof(MENUINFO)); - menuInfo.cbSize = sizeof(MENUINFO); - menuInfo.fMask = MIM_STYLE; - menuInfo.dwStyle = MNS_CHECKORBMP; - SetMenuInfo(Menu, &menuInfo); - - menu = PhCreateEMenu(); - PhLoadResourceEMenuItem(menu, PhInstanceHandle, MAKEINTRESOURCE(IDR_MAINWND), Index); - - PhMwpInitializeSubMenu(menu, Index); - - if (PhPluginsEnabled) - { - PH_PLUGIN_MENU_INFORMATION menuInfo; - - PhPluginInitializeMenuInfo(&menuInfo, menu, PhMainWndHandle, PH_PLUGIN_MENU_DISALLOW_HOOKS); - menuInfo.u.MainMenu.SubMenuIndex = Index; - PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackMainMenuInitializing), &menuInfo); - } - - PhEMenuToHMenu2(Menu, menu, 0, NULL); - SubMenuObjects[Index] = menu; -} - -VOID PhMwpOnSize( - VOID - ) -{ - if (!IsIconic(PhMainWndHandle)) - { - HDWP deferHandle; - - deferHandle = BeginDeferWindowPos(2); - PhMwpLayout(&deferHandle); - EndDeferWindowPos(deferHandle); - } -} - -VOID PhMwpOnSizing( - _In_ ULONG Edge, - _In_ PRECT DragRectangle - ) -{ - PhResizingMinimumSize(DragRectangle, Edge, 400, 340); -} - -VOID PhMwpOnSetFocus( - VOID - ) -{ - if (CurrentPage->WindowHandle) - SetFocus(CurrentPage->WindowHandle); -} - -VOID PhMwpOnTimer( - _In_ ULONG Id - ) -{ - if (Id == TIMER_FLUSH_PROCESS_QUERY_DATA) - { - static ULONG state = 1; - - // If the update interval is too large, the user might have to wait a while before seeing some types of - // process-related data. Here we force an update. - // - // In addition, we force updates shortly after the program starts up to make things appear more quickly. - - switch (state) - { - case 1: - state = 2; - - if (PhCsUpdateInterval > PH_FLUSH_PROCESS_QUERY_DATA_INTERVAL_2) - SetTimer(PhMainWndHandle, TIMER_FLUSH_PROCESS_QUERY_DATA, PH_FLUSH_PROCESS_QUERY_DATA_INTERVAL_2, NULL); - else - KillTimer(PhMainWndHandle, TIMER_FLUSH_PROCESS_QUERY_DATA); - - break; - case 2: - state = 3; - - if (PhCsUpdateInterval > PH_FLUSH_PROCESS_QUERY_DATA_INTERVAL_LONG_TERM) - SetTimer(PhMainWndHandle, TIMER_FLUSH_PROCESS_QUERY_DATA, PH_FLUSH_PROCESS_QUERY_DATA_INTERVAL_LONG_TERM, NULL); - else - KillTimer(PhMainWndHandle, TIMER_FLUSH_PROCESS_QUERY_DATA); - - break; - default: - NOTHING; - break; - } - - PhFlushProcessQueryData(TRUE); - } -} - -BOOLEAN PhMwpOnNotify( - _In_ NMHDR *Header, - _Out_ LRESULT *Result - ) -{ - if (Header->hwndFrom == TabControlHandle) - { - PhMwpNotifyTabControl(Header); - } - else if (Header->code == RFN_VALIDATE) - { - LPNMRUNFILEDLG runFileDlg = (LPNMRUNFILEDLG)Header; - - if (SelectedRunAsMode == RUNAS_MODE_ADMIN) - { - PH_STRINGREF string; - PH_STRINGREF fileName; - PH_STRINGREF arguments; - PPH_STRING fullFileName; - PPH_STRING argumentsString; - - PhInitializeStringRefLongHint(&string, (PWSTR)runFileDlg->lpszFile); - PhParseCommandLineFuzzy(&string, &fileName, &arguments, &fullFileName); - - if (!fullFileName) - fullFileName = PhCreateString2(&fileName); - - argumentsString = PhCreateString2(&arguments); - - if (PhShellExecuteEx(PhMainWndHandle, fullFileName->Buffer, argumentsString->Buffer, - runFileDlg->nShow, PH_SHELL_EXECUTE_ADMIN, 0, NULL)) - { - *Result = RF_CANCEL; - } - else - { - *Result = RF_RETRY; - } - - PhDereferenceObject(fullFileName); - PhDereferenceObject(argumentsString); - - return TRUE; - } - else if (SelectedRunAsMode == RUNAS_MODE_LIMITED) - { - NTSTATUS status; - HANDLE tokenHandle; - HANDLE newTokenHandle; - - if (NT_SUCCESS(status = PhOpenProcessToken( - NtCurrentProcess(), - TOKEN_ASSIGN_PRIMARY | TOKEN_DUPLICATE | TOKEN_QUERY | TOKEN_ADJUST_GROUPS | - TOKEN_ADJUST_DEFAULT | READ_CONTROL | WRITE_DAC, - &tokenHandle - ))) - { - if (NT_SUCCESS(status = PhFilterTokenForLimitedUser( - tokenHandle, - &newTokenHandle - ))) - { - status = PhCreateProcessWin32( - NULL, - (PWSTR)runFileDlg->lpszFile, - NULL, - NULL, - 0, - newTokenHandle, - NULL, - NULL - ); - - NtClose(newTokenHandle); - } - - NtClose(tokenHandle); - } - - if (NT_SUCCESS(status)) - { - *Result = RF_CANCEL; - } - else - { - PhShowStatus(PhMainWndHandle, L"Unable to execute the program", status, 0); - *Result = RF_RETRY; - } - - return TRUE; - } - } - - return FALSE; -} - -VOID PhMwpOnWtsSessionChange( - _In_ ULONG Reason, - _In_ ULONG SessionId - ) -{ - if (Reason == WTS_SESSION_LOGON || Reason == WTS_SESSION_LOGOFF) - { - if (UsersMenuInitialized) - { - PhMwpUpdateUsersMenu(); - } - } -} - -ULONG_PTR PhMwpOnUserMessage( - _In_ ULONG Message, - _In_ ULONG_PTR WParam, - _In_ ULONG_PTR LParam - ) -{ - switch (Message) - { - case WM_PH_ACTIVATE: - { - if (!PhMainWndExiting) - { - if (WParam != 0) - { - PPH_PROCESS_NODE processNode; - - if (processNode = PhFindProcessNode((HANDLE)WParam)) - PhSelectAndEnsureVisibleProcessNode(processNode); - } - - if (!IsWindowVisible(PhMainWndHandle)) - { - ShowWindow(PhMainWndHandle, SW_SHOW); - } - - if (IsIconic(PhMainWndHandle)) - { - ShowWindow(PhMainWndHandle, SW_RESTORE); - } - - return PH_ACTIVATE_REPLY; - } - else - { - return 0; - } - } - break; - case WM_PH_SHOW_PROCESS_PROPERTIES: - { - PhMwpShowProcessProperties((PPH_PROCESS_ITEM)LParam); - } - break; - case WM_PH_DESTROY: - { - DestroyWindow(PhMainWndHandle); - } - break; - case WM_PH_SAVE_ALL_SETTINGS: - { - PhMwpSaveSettings(); - } - break; - case WM_PH_PREPARE_FOR_EARLY_SHUTDOWN: - { - PhMwpSaveSettings(); - PhMainWndExiting = TRUE; - } - break; - case WM_PH_CANCEL_EARLY_SHUTDOWN: - { - PhMainWndExiting = FALSE; - } - break; - case WM_PH_DELAYED_LOAD_COMPLETED: - { - // Nothing - } - break; - case WM_PH_NOTIFY_ICON_MESSAGE: - { - PhNfForwardMessage(WParam, LParam); - } - break; - case WM_PH_TOGGLE_VISIBLE: - { - PhMwpActivateWindow(!WParam); - } - break; - case WM_PH_SHOW_MEMORY_EDITOR: - { - PPH_SHOW_MEMORY_EDITOR showMemoryEditor = (PPH_SHOW_MEMORY_EDITOR)LParam; - - PhShowMemoryEditorDialog( - showMemoryEditor->ProcessId, - showMemoryEditor->BaseAddress, - showMemoryEditor->RegionSize, - showMemoryEditor->SelectOffset, - showMemoryEditor->SelectLength, - showMemoryEditor->Title, - showMemoryEditor->Flags - ); - PhClearReference(&showMemoryEditor->Title); - PhFree(showMemoryEditor); - } - break; - case WM_PH_SHOW_MEMORY_RESULTS: - { - PPH_SHOW_MEMORY_RESULTS showMemoryResults = (PPH_SHOW_MEMORY_RESULTS)LParam; - - PhShowMemoryResultsDialog( - showMemoryResults->ProcessId, - showMemoryResults->Results - ); - PhDereferenceMemoryResults( - (PPH_MEMORY_RESULT *)showMemoryResults->Results->Items, - showMemoryResults->Results->Count - ); - PhDereferenceObject(showMemoryResults->Results); - PhFree(showMemoryResults); - } - break; - case WM_PH_SELECT_TAB_PAGE: - { - ULONG index = (ULONG)WParam; - - PhMwpSelectPage(index); - - if (CurrentPage->WindowHandle) - SetFocus(CurrentPage->WindowHandle); - } - break; - case WM_PH_GET_CALLBACK_LAYOUT_PADDING: - { - return (ULONG_PTR)&LayoutPaddingCallback; - } - break; - case WM_PH_INVALIDATE_LAYOUT_PADDING: - { - LayoutPaddingValid = FALSE; - } - break; - case WM_PH_SELECT_PROCESS_NODE: - { - PhSelectAndEnsureVisibleProcessNode((PPH_PROCESS_NODE)LParam); - } - break; - case WM_PH_SELECT_SERVICE_ITEM: - { - PPH_SERVICE_NODE serviceNode; - - PhMwpNeedServiceTreeList(); - - // For compatibility, LParam is a service item, not node. - if (serviceNode = PhFindServiceNode((PPH_SERVICE_ITEM)LParam)) - { - PhSelectAndEnsureVisibleServiceNode(serviceNode); - } - } - break; - case WM_PH_SELECT_NETWORK_ITEM: - { - PPH_NETWORK_NODE networkNode; - - PhMwpNeedNetworkTreeList(); - - // For compatibility, LParam is a network item, not node. - if (networkNode = PhFindNetworkNode((PPH_NETWORK_ITEM)LParam)) - { - PhSelectAndEnsureVisibleNetworkNode(networkNode); - } - } - break; - case WM_PH_UPDATE_FONT: - { - PPH_STRING fontHexString; - LOGFONT font; - - fontHexString = PhaGetStringSetting(L"Font"); - - if ( - fontHexString->Length / 2 / 2 == sizeof(LOGFONT) && - PhHexStringToBuffer(&fontHexString->sr, (PUCHAR)&font) - ) - { - HFONT newFont; - - newFont = CreateFontIndirect(&font); - - if (newFont) - { - if (CurrentCustomFont) - DeleteObject(CurrentCustomFont); - CurrentCustomFont = newFont; - - PhMwpNotifyAllPages(MainTabPageFontChanged, newFont, NULL); - } - } - } - break; - case WM_PH_GET_FONT: - return SendMessage(PhMwpProcessTreeNewHandle, WM_GETFONT, 0, 0); - case WM_PH_INVOKE: - { - VOID (NTAPI *function)(PVOID); - - function = (PVOID)LParam; - function((PVOID)WParam); - } - break; - case WM_PH_ADD_MENU_ITEM: - { - PPH_ADD_MENU_ITEM addMenuItem = (PPH_ADD_MENU_ITEM)LParam; - - return PhMwpLegacyAddPluginMenuItem(addMenuItem); - } - break; - case WM_PH_CREATE_TAB_PAGE: - { - return (ULONG_PTR)PhMwpCreatePage((PPH_MAIN_TAB_PAGE)LParam); - } - break; - case WM_PH_REFRESH: - { - SendMessage(PhMainWndHandle, WM_COMMAND, ID_VIEW_REFRESH, 0); - } - break; - case WM_PH_GET_UPDATE_AUTOMATICALLY: - { - return PhMwpUpdateAutomatically; - } - break; - case WM_PH_SET_UPDATE_AUTOMATICALLY: - { - if (!!WParam != PhMwpUpdateAutomatically) - { - SendMessage(PhMainWndHandle, WM_COMMAND, ID_VIEW_UPDATEAUTOMATICALLY, 0); - } - } - break; - case WM_PH_ICON_CLICK: - { - PhMwpActivateWindow(!!PhGetIntegerSetting(L"IconTogglesVisibility")); - } - break; - case WM_PH_PROCESS_ADDED: - { - ULONG runId = (ULONG)WParam; - PPH_PROCESS_ITEM processItem = (PPH_PROCESS_ITEM)LParam; - - PhMwpOnProcessAdded(processItem, runId); - } - break; - case WM_PH_PROCESS_MODIFIED: - { - PhMwpOnProcessModified((PPH_PROCESS_ITEM)LParam); - } - break; - case WM_PH_PROCESS_REMOVED: - { - PhMwpOnProcessRemoved((PPH_PROCESS_ITEM)LParam); - } - break; - case WM_PH_PROCESSES_UPDATED: - { - PhMwpOnProcessesUpdated(); - } - break; - case WM_PH_SERVICE_ADDED: - { - ULONG runId = (ULONG)WParam; - PPH_SERVICE_ITEM serviceItem = (PPH_SERVICE_ITEM)LParam; - - PhMwpOnServiceAdded(serviceItem, runId); - } - break; - case WM_PH_SERVICE_MODIFIED: - { - PPH_SERVICE_MODIFIED_DATA serviceModifiedData = (PPH_SERVICE_MODIFIED_DATA)LParam; - - PhMwpOnServiceModified(serviceModifiedData); - PhFree(serviceModifiedData); - } - break; - case WM_PH_SERVICE_REMOVED: - { - PhMwpOnServiceRemoved((PPH_SERVICE_ITEM)LParam); - } - break; - case WM_PH_SERVICES_UPDATED: - { - PhMwpOnServicesUpdated(); - } - break; - case WM_PH_NETWORK_ITEM_ADDED: - { - ULONG runId = (ULONG)WParam; - PPH_NETWORK_ITEM networkItem = (PPH_NETWORK_ITEM)LParam; - - PhMwpOnNetworkItemAdded(runId, networkItem); - } - break; - case WM_PH_NETWORK_ITEM_MODIFIED: - { - PhMwpOnNetworkItemModified((PPH_NETWORK_ITEM)LParam); - } - break; - case WM_PH_NETWORK_ITEM_REMOVED: - { - PhMwpOnNetworkItemRemoved((PPH_NETWORK_ITEM)LParam); - } - break; - case WM_PH_NETWORK_ITEMS_UPDATED: - { - PhMwpOnNetworkItemsUpdated(); - } - break; - } - - return 0; -} - -VOID NTAPI PhMwpNetworkItemAddedHandler( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - PPH_NETWORK_ITEM networkItem = (PPH_NETWORK_ITEM)Parameter; - - PhReferenceObject(networkItem); - PostMessage( - PhMainWndHandle, - WM_PH_NETWORK_ITEM_ADDED, - PhGetRunIdProvider(&PhMwpNetworkProviderRegistration), - (LPARAM)networkItem - ); -} - -VOID NTAPI PhMwpNetworkItemModifiedHandler( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - PPH_NETWORK_ITEM networkItem = (PPH_NETWORK_ITEM)Parameter; - - PostMessage(PhMainWndHandle, WM_PH_NETWORK_ITEM_MODIFIED, 0, (LPARAM)networkItem); -} - -VOID NTAPI PhMwpNetworkItemRemovedHandler( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - PPH_NETWORK_ITEM networkItem = (PPH_NETWORK_ITEM)Parameter; - - PostMessage(PhMainWndHandle, WM_PH_NETWORK_ITEM_REMOVED, 0, (LPARAM)networkItem); -} - -VOID NTAPI PhMwpNetworkItemsUpdatedHandler( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - PostMessage(PhMainWndHandle, WM_PH_NETWORK_ITEMS_UPDATED, 0, 0); -} - -VOID PhMwpLoadSettings( - VOID - ) -{ - ULONG opacity; - PPH_STRING customFont; - - if (PhGetIntegerSetting(L"MainWindowAlwaysOnTop")) - { - AlwaysOnTop = TRUE; - SetWindowPos(PhMainWndHandle, HWND_TOPMOST, 0, 0, 0, 0, - SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOREDRAW | SWP_NOSIZE); - } - - opacity = PhGetIntegerSetting(L"MainWindowOpacity"); - - if (opacity != 0) - PhSetWindowOpacity(PhMainWndHandle, opacity); - - PhStatisticsSampleCount = PhGetIntegerSetting(L"SampleCount"); - PhEnableProcessQueryStage2 = !!PhGetIntegerSetting(L"EnableStage2"); - PhEnablePurgeProcessRecords = !PhGetIntegerSetting(L"NoPurgeProcessRecords"); - PhEnableCycleCpuUsage = !!PhGetIntegerSetting(L"EnableCycleCpuUsage"); - PhEnableServiceNonPoll = !!PhGetIntegerSetting(L"EnableServiceNonPoll"); - PhEnableNetworkProviderResolve = !!PhGetIntegerSetting(L"EnableNetworkResolve"); - - PhNfLoadStage1(); - PhMwpNotifyIconNotifyMask = PhGetIntegerSetting(L"IconNotifyMask"); - - customFont = PhaGetStringSetting(L"Font"); - - if (customFont->Length / 2 / 2 == sizeof(LOGFONT)) - SendMessage(PhMainWndHandle, WM_PH_UPDATE_FONT, 0, 0); - - PhMwpNotifyAllPages(MainTabPageLoadSettings, NULL, NULL); -} - -VOID PhMwpSaveSettings( - VOID - ) -{ - PhMwpNotifyAllPages(MainTabPageSaveSettings, NULL, NULL); - - PhNfSaveSettings(); - PhSetIntegerSetting(L"IconNotifyMask", PhMwpNotifyIconNotifyMask); - - PhSaveWindowPlacementToSetting(L"MainWindowPosition", L"MainWindowSize", PhMainWndHandle); - PhMwpSaveWindowState(); - - if (PhSettingsFileName) - PhSaveSettings(PhSettingsFileName->Buffer); -} - -VOID PhMwpSaveWindowState( - VOID - ) -{ - WINDOWPLACEMENT placement = { sizeof(placement) }; - - GetWindowPlacement(PhMainWndHandle, &placement); - - if (placement.showCmd == SW_NORMAL) - PhSetIntegerSetting(L"MainWindowState", SW_NORMAL); - else if (placement.showCmd == SW_MAXIMIZE) - PhSetIntegerSetting(L"MainWindowState", SW_MAXIMIZE); -} - -VOID PhLoadDbgHelpFromPath( - _In_ PWSTR DbgHelpPath - ) -{ - HMODULE dbghelpModule; - - if (dbghelpModule = LoadLibrary(DbgHelpPath)) - { - PPH_STRING fullDbghelpPath; - ULONG indexOfFileName; - PH_STRINGREF dbghelpFolder; - PPH_STRING symsrvPath; - - fullDbghelpPath = PhGetDllFileName(dbghelpModule, &indexOfFileName); - - if (fullDbghelpPath) - { - if (indexOfFileName != 0) - { - static PH_STRINGREF symsrvString = PH_STRINGREF_INIT(L"\\symsrv.dll"); - - dbghelpFolder.Buffer = fullDbghelpPath->Buffer; - dbghelpFolder.Length = indexOfFileName * sizeof(WCHAR); - - symsrvPath = PhConcatStringRef2(&dbghelpFolder, &symsrvString); - LoadLibrary(symsrvPath->Buffer); - PhDereferenceObject(symsrvPath); - } - - PhDereferenceObject(fullDbghelpPath); - } - } - else - { - dbghelpModule = LoadLibrary(L"dbghelp.dll"); - } - - PhSymbolProviderCompleteInitialization(dbghelpModule); -} - -VOID PhMwpSymInitHandler( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - PPH_STRING dbghelpPath; - - dbghelpPath = PhGetStringSetting(L"DbgHelpPath"); - PhLoadDbgHelpFromPath(dbghelpPath->Buffer); - PhDereferenceObject(dbghelpPath); -} - -VOID PhMwpUpdateLayoutPadding( - VOID - ) -{ - PH_LAYOUT_PADDING_DATA data; - - memset(&data, 0, sizeof(PH_LAYOUT_PADDING_DATA)); - PhInvokeCallback(&LayoutPaddingCallback, &data); - - LayoutPadding = data.Padding; -} - -VOID PhMwpApplyLayoutPadding( - _Inout_ PRECT Rect, - _In_ PRECT Padding - ) -{ - Rect->left += Padding->left; - Rect->top += Padding->top; - Rect->right -= Padding->right; - Rect->bottom -= Padding->bottom; -} - -VOID PhMwpLayout( - _Inout_ HDWP *DeferHandle - ) -{ - RECT rect; - - // Resize the tab control. - // Don't defer the resize. The tab control doesn't repaint properly. - - if (!LayoutPaddingValid) - { - PhMwpUpdateLayoutPadding(); - LayoutPaddingValid = TRUE; - } - - GetClientRect(PhMainWndHandle, &rect); - PhMwpApplyLayoutPadding(&rect, &LayoutPadding); - - SetWindowPos(TabControlHandle, NULL, - rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, - SWP_NOACTIVATE | SWP_NOZORDER); - UpdateWindow(TabControlHandle); - - PhMwpLayoutTabControl(DeferHandle); -} - -VOID PhMwpSetupComputerMenu( - _In_ PPH_EMENU_ITEM Root - ) -{ - PPH_EMENU_ITEM menuItem; - - if (WindowsVersion < WINDOWS_8) - { - if (menuItem = PhFindEMenuItem(Root, PH_EMENU_FIND_DESCEND, NULL, ID_COMPUTER_RESTARTBOOTOPTIONS)) - PhDestroyEMenuItem(menuItem); - if (menuItem = PhFindEMenuItem(Root, PH_EMENU_FIND_DESCEND, NULL, ID_COMPUTER_SHUTDOWNHYBRID)) - PhDestroyEMenuItem(menuItem); - } -} - -BOOLEAN PhMwpExecuteComputerCommand( - _In_ ULONG Id - ) -{ - switch (Id) - { - case ID_COMPUTER_LOCK: - PhUiLockComputer(PhMainWndHandle); - return TRUE; - case ID_COMPUTER_LOGOFF: - PhUiLogoffComputer(PhMainWndHandle); - return TRUE; - case ID_COMPUTER_SLEEP: - PhUiSleepComputer(PhMainWndHandle); - return TRUE; - case ID_COMPUTER_HIBERNATE: - PhUiHibernateComputer(PhMainWndHandle); - return TRUE; - case ID_COMPUTER_RESTART: - PhUiRestartComputer(PhMainWndHandle, 0); - return TRUE; - case ID_COMPUTER_RESTARTBOOTOPTIONS: - PhUiRestartComputer(PhMainWndHandle, EWX_BOOTOPTIONS); - return TRUE; - case ID_COMPUTER_SHUTDOWN: - PhUiShutdownComputer(PhMainWndHandle, 0); - return TRUE; - case ID_COMPUTER_SHUTDOWNHYBRID: - PhUiShutdownComputer(PhMainWndHandle, EWX_HYBRID_SHUTDOWN); - return TRUE; - } - - return FALSE; -} - -VOID PhMwpActivateWindow( - _In_ BOOLEAN Toggle - ) -{ - if (IsIconic(PhMainWndHandle)) - { - ShowWindow(PhMainWndHandle, SW_RESTORE); - SetForegroundWindow(PhMainWndHandle); - } - else if (IsWindowVisible(PhMainWndHandle)) - { - if (Toggle) - ShowWindow(PhMainWndHandle, SW_HIDE); - else - SetForegroundWindow(PhMainWndHandle); - } - else - { - ShowWindow(PhMainWndHandle, SW_SHOW); - SetForegroundWindow(PhMainWndHandle); - } -} - -VOID PhMwpInitializeMainMenu( - _In_ HMENU Menu - ) -{ - MENUINFO menuInfo; - ULONG i; - - menuInfo.cbSize = sizeof(MENUINFO); - menuInfo.fMask = MIM_STYLE; - menuInfo.dwStyle = MNS_NOTIFYBYPOS; - SetMenuInfo(Menu, &menuInfo); - - for (i = 0; i < sizeof(SubMenuHandles) / sizeof(HMENU); i++) - { - SubMenuHandles[i] = GetSubMenu(PhMainWndMenuHandle, i); - } -} - -VOID PhMwpDispatchMenuCommand( - _In_ HMENU MenuHandle, - _In_ ULONG ItemIndex, - _In_ ULONG ItemId, - _In_ ULONG_PTR ItemData - ) -{ - switch (ItemId) - { - case ID_PLUGIN_MENU_ITEM: - { - PPH_EMENU_ITEM menuItem; - PH_PLUGIN_MENU_INFORMATION menuInfo; - - menuItem = (PPH_EMENU_ITEM)ItemData; - - if (menuItem) - { - PhPluginInitializeMenuInfo(&menuInfo, NULL, PhMainWndHandle, 0); - PhPluginTriggerEMenuItem(&menuInfo, menuItem); - } - - return; - } - break; - case ID_TRAYICONS_REGISTERED: - { - PPH_EMENU_ITEM menuItem; - - menuItem = (PPH_EMENU_ITEM)ItemData; - - if (menuItem) - { - PPH_NF_ICON icon; - - icon = menuItem->Context; - PhNfSetVisibleIcon(icon->IconId, !PhNfTestIconMask(icon->IconId)); - } - - return; - } - break; - case ID_USER_CONNECT: - case ID_USER_DISCONNECT: - case ID_USER_LOGOFF: - case ID_USER_REMOTECONTROL: - case ID_USER_SENDMESSAGE: - case ID_USER_PROPERTIES: - { - SelectedUserSessionId = (ULONG)ItemData; - } - break; - } - - SendMessage(PhMainWndHandle, WM_COMMAND, ItemId, 0); -} - -ULONG_PTR PhMwpLegacyAddPluginMenuItem( - _In_ PPH_ADD_MENU_ITEM AddMenuItem - ) -{ - PPH_ADD_MENU_ITEM addMenuItem; - PPH_PLUGIN_MENU_ITEM pluginMenuItem; - - if (!LegacyAddMenuItemList) - LegacyAddMenuItemList = PhCreateList(8); - - addMenuItem = PhAllocateCopy(AddMenuItem, sizeof(PH_ADD_MENU_ITEM)); - PhAddItemList(LegacyAddMenuItemList, addMenuItem); - - pluginMenuItem = PhAllocate(sizeof(PH_PLUGIN_MENU_ITEM)); - memset(pluginMenuItem, 0, sizeof(PH_PLUGIN_MENU_ITEM)); - pluginMenuItem->Plugin = AddMenuItem->Plugin; - pluginMenuItem->Id = AddMenuItem->Id; - pluginMenuItem->Context = AddMenuItem->Context; - - addMenuItem->Context = pluginMenuItem; - - return TRUE; -} - -HBITMAP PhMwpGetShieldBitmap( - VOID - ) -{ - static HBITMAP shieldBitmap = NULL; - - if (!shieldBitmap) - { - HICON shieldIcon; - - if (shieldIcon = PhLoadIcon(NULL, IDI_SHIELD, PH_LOAD_ICON_SIZE_SMALL | PH_LOAD_ICON_STRICT, 0, 0)) - { - shieldBitmap = PhIconToBitmap(shieldIcon, PhSmallIconSize.X, PhSmallIconSize.Y); - DestroyIcon(shieldIcon); - } - } - - return shieldBitmap; -} - -VOID PhMwpInitializeSubMenu( - _In_ PPH_EMENU Menu, - _In_ ULONG Index - ) -{ - PPH_EMENU_ITEM menuItem; - - if (Index == 0) // Hacker - { - // Fix some menu items. - if (PhGetOwnTokenAttributes().Elevated) - { - if (menuItem = PhFindEMenuItem(Menu, 0, NULL, ID_HACKER_RUNASADMINISTRATOR)) - PhDestroyEMenuItem(menuItem); - if (menuItem = PhFindEMenuItem(Menu, 0, NULL, ID_HACKER_SHOWDETAILSFORALLPROCESSES)) - PhDestroyEMenuItem(menuItem); - } - else - { - HBITMAP shieldBitmap; - - if (shieldBitmap = PhMwpGetShieldBitmap()) - { - if (menuItem = PhFindEMenuItem(Menu, 0, NULL, ID_HACKER_SHOWDETAILSFORALLPROCESSES)) - menuItem->Bitmap = shieldBitmap; - } - } - - // Fix up the Computer menu. - PhMwpSetupComputerMenu(Menu); - } - else if (Index == 1) // View - { - PPH_EMENU_ITEM trayIconsMenuItem; - ULONG i; - PPH_EMENU_ITEM menuItem; - ULONG id; - ULONG placeholderIndex; - - trayIconsMenuItem = PhMwpFindTrayIconsMenuItem(Menu); - - if (trayIconsMenuItem) - { - ULONG maximum; - PPH_NF_ICON icon; - - // Add menu items for the registered tray icons. - - id = PH_ICON_DEFAULT_MAXIMUM; - maximum = PhNfGetMaximumIconId(); - - for (; id != maximum; id <<= 1) - { - if (icon = PhNfGetIconById(id)) - { - PhInsertEMenuItem(trayIconsMenuItem, PhCreateEMenuItem(0, ID_TRAYICONS_REGISTERED, icon->Text, NULL, icon), -1); - } - } - - // Update the text and check marks on the menu items. - - for (i = 0; i < trayIconsMenuItem->Items->Count; i++) - { - menuItem = trayIconsMenuItem->Items->Items[i]; - - id = -1; - icon = NULL; - - switch (menuItem->Id) - { - case ID_TRAYICONS_CPUHISTORY: - id = PH_ICON_CPU_HISTORY; - break; - case ID_TRAYICONS_IOHISTORY: - id = PH_ICON_IO_HISTORY; - break; - case ID_TRAYICONS_COMMITHISTORY: - id = PH_ICON_COMMIT_HISTORY; - break; - case ID_TRAYICONS_PHYSICALMEMORYHISTORY: - id = PH_ICON_PHYSICAL_HISTORY; - break; - case ID_TRAYICONS_CPUUSAGE: - id = PH_ICON_CPU_USAGE; - break; - case ID_TRAYICONS_REGISTERED: - icon = menuItem->Context; - id = icon->IconId; - break; - } - - if (id != -1) - { - if (PhNfTestIconMask(id)) - menuItem->Flags |= PH_EMENU_CHECKED; - - if (icon && (icon->Flags & PH_NF_ICON_UNAVAILABLE)) - { - PPH_STRING newText; - - newText = PhaConcatStrings2(icon->Text, L" (Unavailable)"); - PhModifyEMenuItem(menuItem, PH_EMENU_MODIFY_TEXT, PH_EMENU_TEXT_OWNED, - PhAllocateCopy(newText->Buffer, newText->Length + sizeof(WCHAR)), NULL); - } - } - } - } - - if (menuItem = PhFindEMenuItemEx(Menu, 0, NULL, ID_VIEW_SECTIONPLACEHOLDER, NULL, &placeholderIndex)) - { - PhDestroyEMenuItem(menuItem); - PhMwpInitializeSectionMenuItems(Menu, placeholderIndex); - } - - if (AlwaysOnTop && (menuItem = PhFindEMenuItem(Menu, 0, NULL, ID_VIEW_ALWAYSONTOP))) - menuItem->Flags |= PH_EMENU_CHECKED; - - id = PH_OPACITY_TO_ID(PhGetIntegerSetting(L"MainWindowOpacity")); - - if (menuItem = PhFindEMenuItem(Menu, PH_EMENU_FIND_DESCEND, NULL, id)) - menuItem->Flags |= PH_EMENU_CHECKED | PH_EMENU_RADIOCHECK; - - switch (PhGetIntegerSetting(L"UpdateInterval")) - { - case 500: - id = ID_UPDATEINTERVAL_FAST; - break; - case 1000: - id = ID_UPDATEINTERVAL_NORMAL; - break; - case 2000: - id = ID_UPDATEINTERVAL_BELOWNORMAL; - break; - case 5000: - id = ID_UPDATEINTERVAL_SLOW; - break; - case 10000: - id = ID_UPDATEINTERVAL_VERYSLOW; - break; - default: - id = -1; - break; - } - - if (id != -1 && (menuItem = PhFindEMenuItem(Menu, PH_EMENU_FIND_DESCEND, NULL, id))) - menuItem->Flags |= PH_EMENU_CHECKED | PH_EMENU_RADIOCHECK; - - if (PhMwpUpdateAutomatically && (menuItem = PhFindEMenuItem(Menu, 0, NULL, ID_VIEW_UPDATEAUTOMATICALLY))) - menuItem->Flags |= PH_EMENU_CHECKED; - } - else if (Index == 2) // Tools - { -#ifdef _WIN64 - if (menuItem = PhFindEMenuItem(Menu, 0, NULL, ID_TOOLS_HIDDENPROCESSES)) - PhDestroyEMenuItem(menuItem); -#endif - - // Windows 8 Task Manager requires elevation. - if (WindowsVersion >= WINDOWS_8 && !PhGetOwnTokenAttributes().Elevated) - { - HBITMAP shieldBitmap; - - if (shieldBitmap = PhMwpGetShieldBitmap()) - { - if (menuItem = PhFindEMenuItem(Menu, 0, NULL, ID_TOOLS_STARTTASKMANAGER)) - menuItem->Bitmap = shieldBitmap; - } - } - } - - if (LegacyAddMenuItemList) - { - ULONG i; - PPH_ADD_MENU_ITEM addMenuItem; - - for (i = 0; i < LegacyAddMenuItemList->Count; i++) - { - addMenuItem = LegacyAddMenuItemList->Items[i]; - - if (addMenuItem->Location == Index) - { - ULONG insertIndex; - - if (addMenuItem->InsertAfter) - { - for (insertIndex = 0; insertIndex < Menu->Items->Count; insertIndex++) - { - menuItem = Menu->Items->Items[insertIndex]; - - if (!(menuItem->Flags & PH_EMENU_SEPARATOR) && (PhCompareUnicodeStringZIgnoreMenuPrefix( - addMenuItem->InsertAfter, - menuItem->Text, - TRUE, - TRUE - ) == 0)) - { - insertIndex++; - break; - } - } - } - else - { - insertIndex = 0; - } - - if (addMenuItem->Text[0] == '-' && addMenuItem->Text[1] == 0) - PhInsertEMenuItem(Menu, PhCreateEMenuItem(PH_EMENU_SEPARATOR, 0, L"", NULL, NULL), insertIndex); - else - PhInsertEMenuItem(Menu, PhCreateEMenuItem(0, ID_PLUGIN_MENU_ITEM, addMenuItem->Text, NULL, addMenuItem->Context), insertIndex); - } - } - } -} - -PPH_EMENU_ITEM PhMwpFindTrayIconsMenuItem( - _In_ PPH_EMENU Menu - ) -{ - ULONG i; - PPH_EMENU_ITEM menuItem; - - for (i = 0; i < Menu->Items->Count; i++) - { - menuItem = Menu->Items->Items[i]; - - if (PhFindEMenuItem(menuItem, 0, NULL, ID_TRAYICONS_CPUHISTORY)) - return menuItem; - } - - return NULL; -} - -VOID PhMwpInitializeSectionMenuItems( - _In_ PPH_EMENU Menu, - _In_ ULONG StartIndex - ) -{ - if (CurrentPage) - { - PH_MAIN_TAB_PAGE_MENU_INFORMATION menuInfo; - - menuInfo.Menu = Menu; - menuInfo.StartIndex = StartIndex; - - if (!CurrentPage->Callback(CurrentPage, MainTabPageInitializeSectionMenuItems, &menuInfo, NULL)) - { - // Remove the extra separator. - PhRemoveEMenuItem(Menu, NULL, StartIndex); - } - } -} - -VOID PhMwpLayoutTabControl( - _Inout_ HDWP *DeferHandle - ) -{ - RECT rect; - - if (!LayoutPaddingValid) - { - PhMwpUpdateLayoutPadding(); - LayoutPaddingValid = TRUE; - } - - GetClientRect(PhMainWndHandle, &rect); - PhMwpApplyLayoutPadding(&rect, &LayoutPadding); - TabCtrl_AdjustRect(TabControlHandle, FALSE, &rect); - - if (CurrentPage && CurrentPage->WindowHandle) - { - *DeferHandle = DeferWindowPos(*DeferHandle, CurrentPage->WindowHandle, NULL, - rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, - SWP_NOACTIVATE | SWP_NOZORDER); - } -} - -VOID PhMwpNotifyTabControl( - _In_ NMHDR *Header - ) -{ - if (Header->code == TCN_SELCHANGING) - { - OldTabIndex = TabCtrl_GetCurSel(TabControlHandle); - } - else if (Header->code == TCN_SELCHANGE) - { - PhMwpSelectionChangedTabControl(OldTabIndex); - } -} - -VOID PhMwpSelectionChangedTabControl( - _In_ ULONG OldIndex - ) -{ - ULONG selectedIndex; - HDWP deferHandle; - ULONG i; - - selectedIndex = TabCtrl_GetCurSel(TabControlHandle); - - if (selectedIndex == OldIndex) - return; - - deferHandle = BeginDeferWindowPos(3); - - for (i = 0; i < PageList->Count; i++) - { - PPH_MAIN_TAB_PAGE page = PageList->Items[i]; - - page->Selected = page->Index == selectedIndex; - - if (page->Index == selectedIndex) - { - CurrentPage = page; - - // Create the tab page window if it doesn't exist. - if (!page->WindowHandle && !page->CreateWindowCalled) - { - if (page->Callback(page, MainTabPageCreateWindow, &page->WindowHandle, NULL)) - page->CreateWindowCalled = TRUE; - - if (page->WindowHandle) - BringWindowToTop(page->WindowHandle); - if (CurrentCustomFont) - page->Callback(page, MainTabPageFontChanged, CurrentCustomFont, NULL); - } - - page->Callback(page, MainTabPageSelected, (PVOID)TRUE, NULL); - - if (page->WindowHandle) - { - deferHandle = DeferWindowPos(deferHandle, page->WindowHandle, NULL, 0, 0, 0, 0, SWP_SHOWWINDOW_ONLY); - SetFocus(page->WindowHandle); - } - } - else if (page->Index == OldIndex) - { - page->Callback(page, MainTabPageSelected, (PVOID)FALSE, NULL); - - if (page->WindowHandle) - { - deferHandle = DeferWindowPos(deferHandle, page->WindowHandle, NULL, 0, 0, 0, 0, SWP_HIDEWINDOW_ONLY); - } - } - } - - PhMwpLayoutTabControl(&deferHandle); - - EndDeferWindowPos(deferHandle); - - if (PhPluginsEnabled) - PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackMainWindowTabChanged), IntToPtr(selectedIndex)); -} - -PPH_MAIN_TAB_PAGE PhMwpCreatePage( - _In_ PPH_MAIN_TAB_PAGE Template - ) -{ - PPH_MAIN_TAB_PAGE page; - PPH_STRING name; - HDWP deferHandle; - - page = PhAllocate(sizeof(PH_MAIN_TAB_PAGE)); - memset(page, 0, sizeof(PH_MAIN_TAB_PAGE)); - - page->Name = Template->Name; - page->Flags = Template->Flags; - page->Callback = Template->Callback; - page->Context = Template->Context; - - PhAddItemList(PageList, page); - - name = PhCreateString2(&page->Name); - page->Index = PhAddTabControlTab(TabControlHandle, MAXINT, name->Buffer); - PhDereferenceObject(name); - - page->Callback(page, MainTabPageCreate, NULL, NULL); - - // The tab control might need multiple lines, so we need to refresh the layout. - deferHandle = BeginDeferWindowPos(1); - PhMwpLayoutTabControl(&deferHandle); - EndDeferWindowPos(deferHandle); - - return page; -} - -VOID PhMwpSelectPage( - _In_ ULONG Index - ) -{ - INT oldIndex; - - oldIndex = TabCtrl_GetCurSel(TabControlHandle); - TabCtrl_SetCurSel(TabControlHandle, Index); - PhMwpSelectionChangedTabControl(oldIndex); -} - -PPH_MAIN_TAB_PAGE PhMwpFindPage( - _In_ PPH_STRINGREF Name - ) -{ - ULONG i; - - for (i = 0; i < PageList->Count; i++) - { - PPH_MAIN_TAB_PAGE page = PageList->Items[i]; - - if (PhEqualStringRef(&page->Name, Name, TRUE)) - return page; - } - - return NULL; -} - -PPH_MAIN_TAB_PAGE PhMwpCreateInternalPage( - _In_ PWSTR Name, - _In_ ULONG Flags, - _In_ PPH_MAIN_TAB_PAGE_CALLBACK Callback - ) -{ - PH_MAIN_TAB_PAGE page; - - memset(&page, 0, sizeof(PH_MAIN_TAB_PAGE)); - PhInitializeStringRef(&page.Name, Name); - page.Flags = Flags; - page.Callback = Callback; - - return PhMwpCreatePage(&page); -} - -VOID PhMwpNotifyAllPages( - _In_ PH_MAIN_TAB_PAGE_MESSAGE Message, - _In_opt_ PVOID Parameter1, - _In_opt_ PVOID Parameter2 - ) -{ - ULONG i; - PPH_MAIN_TAB_PAGE page; - - for (i = 0; i < PageList->Count; i++) - { - page = PageList->Items[i]; - page->Callback(page, Message, Parameter1, Parameter2); - } -} - -static int __cdecl IconProcessesCpuUsageCompare( - _In_ const void *elem1, - _In_ const void *elem2 - ) -{ - PPH_PROCESS_ITEM processItem1 = *(PPH_PROCESS_ITEM *)elem1; - PPH_PROCESS_ITEM processItem2 = *(PPH_PROCESS_ITEM *)elem2; - - return -singlecmp(processItem1->CpuUsage, processItem2->CpuUsage); -} - -static int __cdecl IconProcessesNameCompare( - _In_ const void *elem1, - _In_ const void *elem2 - ) -{ - PPH_PROCESS_ITEM processItem1 = *(PPH_PROCESS_ITEM *)elem1; - PPH_PROCESS_ITEM processItem2 = *(PPH_PROCESS_ITEM *)elem2; - - return PhCompareString(processItem1->ProcessName, processItem2->ProcessName, TRUE); -} - -VOID PhAddMiniProcessMenuItems( - _Inout_ struct _PH_EMENU_ITEM *Menu, - _In_ HANDLE ProcessId - ) -{ - PPH_EMENU_ITEM priorityMenu; - PPH_EMENU_ITEM ioPriorityMenu = NULL; - PPH_PROCESS_ITEM processItem; - BOOLEAN isSuspended = FALSE; - BOOLEAN isPartiallySuspended = TRUE; - - // Priority - - priorityMenu = PhCreateEMenuItem(0, 0, L"Priority", NULL, ProcessId); - - PhInsertEMenuItem(priorityMenu, PhCreateEMenuItem(0, ID_PRIORITY_REALTIME, L"Real time", NULL, ProcessId), -1); - PhInsertEMenuItem(priorityMenu, PhCreateEMenuItem(0, ID_PRIORITY_HIGH, L"High", NULL, ProcessId), -1); - PhInsertEMenuItem(priorityMenu, PhCreateEMenuItem(0, ID_PRIORITY_ABOVENORMAL, L"Above normal", NULL, ProcessId), -1); - PhInsertEMenuItem(priorityMenu, PhCreateEMenuItem(0, ID_PRIORITY_NORMAL, L"Normal", NULL, ProcessId), -1); - PhInsertEMenuItem(priorityMenu, PhCreateEMenuItem(0, ID_PRIORITY_BELOWNORMAL, L"Below normal", NULL, ProcessId), -1); - PhInsertEMenuItem(priorityMenu, PhCreateEMenuItem(0, ID_PRIORITY_IDLE, L"Idle", NULL, ProcessId), -1); - - // I/O priority - - if (WindowsVersion >= WINDOWS_VISTA) - { - ioPriorityMenu = PhCreateEMenuItem(0, 0, L"I/O priority", NULL, ProcessId); - - PhInsertEMenuItem(ioPriorityMenu, PhCreateEMenuItem(0, ID_IOPRIORITY_HIGH, L"High", NULL, ProcessId), -1); - PhInsertEMenuItem(ioPriorityMenu, PhCreateEMenuItem(0, ID_IOPRIORITY_NORMAL, L"Normal", NULL, ProcessId), -1); - PhInsertEMenuItem(ioPriorityMenu, PhCreateEMenuItem(0, ID_IOPRIORITY_LOW, L"Low", NULL, ProcessId), -1); - PhInsertEMenuItem(ioPriorityMenu, PhCreateEMenuItem(0, ID_IOPRIORITY_VERYLOW, L"Very low", NULL, ProcessId), -1); - } - - // Menu - - PhInsertEMenuItem(Menu, PhCreateEMenuItem(0, ID_PROCESS_TERMINATE, L"T&erminate", NULL, ProcessId), -1); - - if (processItem = PhReferenceProcessItem(ProcessId)) - { - isSuspended = (BOOLEAN)processItem->IsSuspended; - isPartiallySuspended = (BOOLEAN)processItem->IsPartiallySuspended; - PhDereferenceObject(processItem); - } - - if (!isSuspended) - PhInsertEMenuItem(Menu, PhCreateEMenuItem(0, ID_PROCESS_SUSPEND, L"&Suspend", NULL, ProcessId), -1); - if (isPartiallySuspended) - PhInsertEMenuItem(Menu, PhCreateEMenuItem(0, ID_PROCESS_RESUME, L"Res&ume", NULL, ProcessId), -1); - - PhInsertEMenuItem(Menu, priorityMenu, -1); - - if (ioPriorityMenu) - PhInsertEMenuItem(Menu, ioPriorityMenu, -1); - - PhMwpSetProcessMenuPriorityChecks(Menu, ProcessId, TRUE, TRUE, FALSE); - - PhInsertEMenuItem(Menu, PhCreateEMenuItem(0, ID_PROCESS_PROPERTIES, L"P&roperties", NULL, ProcessId), -1); -} - -BOOLEAN PhHandleMiniProcessMenuItem( - _Inout_ struct _PH_EMENU_ITEM *MenuItem - ) -{ - switch (MenuItem->Id) - { - case ID_PROCESS_TERMINATE: - case ID_PROCESS_SUSPEND: - case ID_PROCESS_RESUME: - case ID_PROCESS_PROPERTIES: - { - HANDLE processId = MenuItem->Context; - PPH_PROCESS_ITEM processItem; - - if (processItem = PhReferenceProcessItem(processId)) - { - switch (MenuItem->Id) - { - case ID_PROCESS_TERMINATE: - PhUiTerminateProcesses(PhMainWndHandle, &processItem, 1); - break; - case ID_PROCESS_SUSPEND: - PhUiSuspendProcesses(PhMainWndHandle, &processItem, 1); - break; - case ID_PROCESS_RESUME: - PhUiResumeProcesses(PhMainWndHandle, &processItem, 1); - break; - case ID_PROCESS_PROPERTIES: - ProcessHacker_ShowProcessProperties(PhMainWndHandle, processItem); - break; - } - - PhDereferenceObject(processItem); - } - else - { - PhShowError(PhMainWndHandle, L"The process does not exist."); - } - } - break; - case ID_PRIORITY_REALTIME: - case ID_PRIORITY_HIGH: - case ID_PRIORITY_ABOVENORMAL: - case ID_PRIORITY_NORMAL: - case ID_PRIORITY_BELOWNORMAL: - case ID_PRIORITY_IDLE: - { - HANDLE processId = MenuItem->Context; - PPH_PROCESS_ITEM processItem; - - if (processItem = PhReferenceProcessItem(processId)) - { - PhMwpExecuteProcessPriorityCommand(MenuItem->Id, &processItem, 1); - PhDereferenceObject(processItem); - } - else - { - PhShowError(PhMainWndHandle, L"The process does not exist."); - } - } - break; - case ID_IOPRIORITY_HIGH: - case ID_IOPRIORITY_NORMAL: - case ID_IOPRIORITY_LOW: - case ID_IOPRIORITY_VERYLOW: - { - HANDLE processId = MenuItem->Context; - PPH_PROCESS_ITEM processItem; - - if (processItem = PhReferenceProcessItem(processId)) - { - PhMwpExecuteProcessIoPriorityCommand(MenuItem->Id, &processItem, 1); - PhDereferenceObject(processItem); - } - else - { - PhShowError(PhMainWndHandle, L"The process does not exist."); - } - } - break; - } - - return FALSE; -} - -VOID PhMwpAddIconProcesses( - _In_ PPH_EMENU_ITEM Menu, - _In_ ULONG NumberOfProcesses - ) -{ - ULONG i; - PPH_PROCESS_ITEM *processItems; - ULONG numberOfProcessItems; - PPH_LIST processList; - PPH_PROCESS_ITEM processItem; - - PhEnumProcessItems(&processItems, &numberOfProcessItems); - processList = PhCreateList(numberOfProcessItems); - PhAddItemsList(processList, processItems, numberOfProcessItems); - - // Remove non-real processes. - for (i = 0; i < processList->Count; i++) - { - processItem = processList->Items[i]; - - if (!PH_IS_REAL_PROCESS_ID(processItem->ProcessId)) - { - PhRemoveItemList(processList, i); - i--; - } - } - - // Remove processes with zero CPU usage and those running as other users. - for (i = 0; i < processList->Count && processList->Count > NumberOfProcesses; i++) - { - processItem = processList->Items[i]; - - if ( - processItem->CpuUsage == 0 || - !processItem->UserName || - (PhCurrentUserName && !PhEqualString(processItem->UserName, PhCurrentUserName, TRUE)) - ) - { - PhRemoveItemList(processList, i); - i--; - } - } - - // Sort the processes by CPU usage and remove the extra processes at the end of the list. - qsort(processList->Items, processList->Count, sizeof(PVOID), IconProcessesCpuUsageCompare); - - if (processList->Count > NumberOfProcesses) - { - PhRemoveItemsList(processList, NumberOfProcesses, processList->Count - NumberOfProcesses); - } - - // Lastly, sort by name. - qsort(processList->Items, processList->Count, sizeof(PVOID), IconProcessesNameCompare); - - // Delete all menu items. - PhRemoveAllEMenuItems(Menu); - - // Add the processes. - - for (i = 0; i < processList->Count; i++) - { - PPH_EMENU_ITEM subMenu; - HBITMAP iconBitmap; - CLIENT_ID clientId; - PPH_STRING clientIdName; - PPH_STRING escapedName; - - processItem = processList->Items[i]; - - // Process - - clientId.UniqueProcess = processItem->ProcessId; - clientId.UniqueThread = NULL; - - clientIdName = PH_AUTO(PhGetClientIdName(&clientId)); - escapedName = PH_AUTO(PhEscapeStringForMenuPrefix(&clientIdName->sr)); - - subMenu = PhCreateEMenuItem( - 0, - 0, - escapedName->Buffer, - NULL, - processItem->ProcessId - ); - - if (processItem->SmallIcon) - { - iconBitmap = PhIconToBitmap(processItem->SmallIcon, PhSmallIconSize.X, PhSmallIconSize.Y); - } - else - { - HICON icon; - - PhGetStockApplicationIcon(&icon, NULL); - iconBitmap = PhIconToBitmap(icon, PhSmallIconSize.X, PhSmallIconSize.Y); - } - - subMenu->Bitmap = iconBitmap; - subMenu->Flags |= PH_EMENU_BITMAP_OWNED; // automatically destroy the bitmap when necessary - - PhAddMiniProcessMenuItems(subMenu, processItem->ProcessId); - PhInsertEMenuItem(Menu, subMenu, -1); - } - - PhDereferenceObject(processList); - PhDereferenceObjects(processItems, numberOfProcessItems); - PhFree(processItems); -} - -VOID PhShowIconContextMenu( - _In_ POINT Location - ) -{ - PPH_EMENU menu; - PPH_EMENU_ITEM item; - PH_PLUGIN_MENU_INFORMATION menuInfo; - ULONG numberOfProcesses; - ULONG id; - ULONG i; - - // This function seems to be called recursively under some circumstances. - // To reproduce: - // 1. Hold right mouse button on tray icon, then left click. - // 2. Make the menu disappear by clicking on the menu then clicking somewhere else. - // So, don't store any global state or bad things will happen. - - menu = PhCreateEMenu(); - PhLoadResourceEMenuItem(menu, PhInstanceHandle, MAKEINTRESOURCE(IDR_ICON), 0); - - // Check the Notifications menu items. - for (i = PH_NOTIFY_MINIMUM; i != PH_NOTIFY_MAXIMUM; i <<= 1) - { - if (PhMwpNotifyIconNotifyMask & i) - { - switch (i) - { - case PH_NOTIFY_PROCESS_CREATE: - id = ID_NOTIFICATIONS_NEWPROCESSES; - break; - case PH_NOTIFY_PROCESS_DELETE: - id = ID_NOTIFICATIONS_TERMINATEDPROCESSES; - break; - case PH_NOTIFY_SERVICE_CREATE: - id = ID_NOTIFICATIONS_NEWSERVICES; - break; - case PH_NOTIFY_SERVICE_DELETE: - id = ID_NOTIFICATIONS_DELETEDSERVICES; - break; - case PH_NOTIFY_SERVICE_START: - id = ID_NOTIFICATIONS_STARTEDSERVICES; - break; - case PH_NOTIFY_SERVICE_STOP: - id = ID_NOTIFICATIONS_STOPPEDSERVICES; - break; - } - - PhSetFlagsEMenuItem(menu, id, PH_EMENU_CHECKED, PH_EMENU_CHECKED); - } - } - - // Add processes to the menu. - - numberOfProcesses = PhGetIntegerSetting(L"IconProcesses"); - item = PhFindEMenuItem(menu, 0, L"Processes", 0); - - if (item) - PhMwpAddIconProcesses(item, numberOfProcesses); - - // Fix up the Computer menu. - PhMwpSetupComputerMenu(menu); - - // Give plugins a chance to modify the menu. - - if (PhPluginsEnabled) - { - PhPluginInitializeMenuInfo(&menuInfo, menu, PhMainWndHandle, 0); - PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackIconMenuInitializing), &menuInfo); - } - - SetForegroundWindow(PhMainWndHandle); // window must be foregrounded so menu will disappear properly - item = PhShowEMenu( - menu, - PhMainWndHandle, - PH_EMENU_SHOW_LEFTRIGHT, - PH_ALIGN_LEFT | PH_ALIGN_TOP, - Location.x, - Location.y - ); - - if (item) - { - BOOLEAN handled = FALSE; - - if (PhPluginsEnabled && !handled) - handled = PhPluginTriggerEMenuItem(&menuInfo, item); - - if (!handled) - handled = PhHandleMiniProcessMenuItem(item); - - if (!handled) - handled = PhMwpExecuteComputerCommand(item->Id); - - if (!handled) - { - switch (item->Id) - { - case ID_ICON_SHOWHIDEPROCESSHACKER: - SendMessage(PhMainWndHandle, WM_PH_TOGGLE_VISIBLE, 0, 0); - break; - case ID_ICON_SYSTEMINFORMATION: - SendMessage(PhMainWndHandle, WM_COMMAND, ID_VIEW_SYSTEMINFORMATION, 0); - break; - case ID_NOTIFICATIONS_ENABLEALL: - PhMwpNotifyIconNotifyMask |= PH_NOTIFY_VALID_MASK; - break; - case ID_NOTIFICATIONS_DISABLEALL: - PhMwpNotifyIconNotifyMask &= ~PH_NOTIFY_VALID_MASK; - break; - case ID_NOTIFICATIONS_NEWPROCESSES: - case ID_NOTIFICATIONS_TERMINATEDPROCESSES: - case ID_NOTIFICATIONS_NEWSERVICES: - case ID_NOTIFICATIONS_STARTEDSERVICES: - case ID_NOTIFICATIONS_STOPPEDSERVICES: - case ID_NOTIFICATIONS_DELETEDSERVICES: - { - ULONG bit; - - switch (item->Id) - { - case ID_NOTIFICATIONS_NEWPROCESSES: - bit = PH_NOTIFY_PROCESS_CREATE; - break; - case ID_NOTIFICATIONS_TERMINATEDPROCESSES: - bit = PH_NOTIFY_PROCESS_DELETE; - break; - case ID_NOTIFICATIONS_NEWSERVICES: - bit = PH_NOTIFY_SERVICE_CREATE; - break; - case ID_NOTIFICATIONS_STARTEDSERVICES: - bit = PH_NOTIFY_SERVICE_START; - break; - case ID_NOTIFICATIONS_STOPPEDSERVICES: - bit = PH_NOTIFY_SERVICE_STOP; - break; - case ID_NOTIFICATIONS_DELETEDSERVICES: - bit = PH_NOTIFY_SERVICE_DELETE; - break; - } - - PhMwpNotifyIconNotifyMask ^= bit; - } - break; - case ID_ICON_EXIT: - SendMessage(PhMainWndHandle, WM_COMMAND, ID_HACKER_EXIT, 0); - break; - } - } - } - - PhDestroyEMenu(menu); -} - -VOID PhShowIconNotification( - _In_ PWSTR Title, - _In_ PWSTR Text, - _In_ ULONG Flags - ) -{ - PhNfShowBalloonTip(0, Title, Text, 10, Flags); -} - -VOID PhShowDetailsForIconNotification( - VOID - ) -{ - switch (PhMwpLastNotificationType) - { - case PH_NOTIFY_PROCESS_CREATE: - { - PPH_PROCESS_NODE processNode; - - if (processNode = PhFindProcessNode(PhMwpLastNotificationDetails.ProcessId)) - { - ProcessHacker_SelectTabPage(PhMainWndHandle, PhMwpProcessesPage->Index); - ProcessHacker_SelectProcessNode(PhMainWndHandle, processNode); - ProcessHacker_ToggleVisible(PhMainWndHandle, TRUE); - } - } - break; - case PH_NOTIFY_SERVICE_CREATE: - case PH_NOTIFY_SERVICE_START: - case PH_NOTIFY_SERVICE_STOP: - { - PPH_SERVICE_ITEM serviceItem; - - if (PhMwpLastNotificationDetails.ServiceName && - (serviceItem = PhReferenceServiceItem(PhMwpLastNotificationDetails.ServiceName->Buffer))) - { - ProcessHacker_SelectTabPage(PhMainWndHandle, PhMwpServicesPage->Index); - ProcessHacker_SelectServiceItem(PhMainWndHandle, serviceItem); - ProcessHacker_ToggleVisible(PhMainWndHandle, TRUE); - - PhDereferenceObject(serviceItem); - } - } - break; - } -} - -VOID PhMwpClearLastNotificationDetails( - VOID - ) -{ - if (PhMwpLastNotificationType & - (PH_NOTIFY_SERVICE_CREATE | PH_NOTIFY_SERVICE_DELETE | PH_NOTIFY_SERVICE_START | PH_NOTIFY_SERVICE_STOP)) - { - PhClearReference(&PhMwpLastNotificationDetails.ServiceName); - } - - PhMwpLastNotificationType = 0; - memset(&PhMwpLastNotificationDetails, 0, sizeof(PhMwpLastNotificationDetails)); -} - -BOOLEAN PhMwpPluginNotifyEvent( - _In_ ULONG Type, - _In_ PVOID Parameter - ) -{ - PH_PLUGIN_NOTIFY_EVENT notifyEvent; - - notifyEvent.Type = Type; - notifyEvent.Handled = FALSE; - notifyEvent.Parameter = Parameter; - - PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackNotifyEvent), ¬ifyEvent); - - return notifyEvent.Handled; -} - -VOID PhMwpUpdateUsersMenu( - VOID - ) -{ - HMENU menu; - PSESSIONIDW sessions; - ULONG numberOfSessions; - ULONG i; - ULONG j; - MENUITEMINFO menuItemInfo = { sizeof(MENUITEMINFO) }; - - menu = SubMenuHandles[3]; - - // Delete all items in the Users menu. - while (DeleteMenu(menu, 0, MF_BYPOSITION)) ; - - if (WinStationEnumerateW(NULL, &sessions, &numberOfSessions)) - { - for (i = 0; i < numberOfSessions; i++) - { - HMENU userMenu; - PPH_STRING menuText; - PPH_STRING escapedMenuText; - WINSTATIONINFORMATION winStationInfo; - ULONG returnLength; - ULONG numberOfItems; - - if (!WinStationQueryInformationW( - NULL, - sessions[i].SessionId, - WinStationInformation, - &winStationInfo, - sizeof(WINSTATIONINFORMATION), - &returnLength - )) - { - winStationInfo.Domain[0] = 0; - winStationInfo.UserName[0] = 0; - } - - if (winStationInfo.Domain[0] == 0 || winStationInfo.UserName[0] == 0) - { - // Probably the Services or RDP-Tcp session. - continue; - } - - menuText = PhFormatString( - L"%u: %s\\%s", - sessions[i].SessionId, - winStationInfo.Domain, - winStationInfo.UserName - ); - escapedMenuText = PhEscapeStringForMenuPrefix(&menuText->sr); - PhDereferenceObject(menuText); - - userMenu = GetSubMenu(LoadMenu(PhInstanceHandle, MAKEINTRESOURCE(IDR_USER)), 0); - AppendMenu( - menu, - MF_STRING | MF_POPUP, - (UINT_PTR)userMenu, - escapedMenuText->Buffer - ); - - PhDereferenceObject(escapedMenuText); - - menuItemInfo.fMask = MIIM_DATA; - menuItemInfo.dwItemData = sessions[i].SessionId; - - numberOfItems = GetMenuItemCount(userMenu); - - if (numberOfItems != -1) - { - for (j = 0; j < numberOfItems; j++) - SetMenuItemInfo(userMenu, j, TRUE, &menuItemInfo); - } - } - - WinStationFreeMemory(sessions); - } - - DrawMenuBar(PhMainWndHandle); -} +/* + * Process Hacker - + * Main window + * + * Copyright (C) 2009-2016 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define RUNAS_MODE_ADMIN 1 +#define RUNAS_MODE_LIMITED 2 + +PHAPPAPI HWND PhMainWndHandle; +BOOLEAN PhMainWndExiting = FALSE; +HMENU PhMainWndMenuHandle; + +PH_PROVIDER_REGISTRATION PhMwpProcessProviderRegistration; +PH_PROVIDER_REGISTRATION PhMwpServiceProviderRegistration; +PH_PROVIDER_REGISTRATION PhMwpNetworkProviderRegistration; +BOOLEAN PhMwpUpdateAutomatically = TRUE; + +ULONG PhMwpNotifyIconNotifyMask; +ULONG PhMwpLastNotificationType; +PH_MWP_NOTIFICATION_DETAILS PhMwpLastNotificationDetails; + +static BOOLEAN NeedsMaximize = FALSE; +static BOOLEAN AlwaysOnTop = FALSE; + +static BOOLEAN DelayedLoadCompleted = FALSE; + +static PH_CALLBACK_DECLARE(LayoutPaddingCallback); +static RECT LayoutPadding = { 0, 0, 0, 0 }; +static BOOLEAN LayoutPaddingValid = TRUE; + +static HWND TabControlHandle; +static PPH_LIST PageList; +static PPH_MAIN_TAB_PAGE CurrentPage; +static INT OldTabIndex; +static HFONT CurrentCustomFont; + +static HMENU SubMenuHandles[5]; +static PPH_EMENU SubMenuObjects[5]; +static PPH_LIST LegacyAddMenuItemList; +static BOOLEAN UsersMenuInitialized = FALSE; + +static PH_CALLBACK_REGISTRATION SymInitRegistration; + +static ULONG SelectedRunAsMode; +static ULONG SelectedUserSessionId; + +BOOLEAN PhMainWndInitialization( + _In_ INT ShowCommand + ) +{ + PH_STRING_BUILDER stringBuilder; + PH_RECTANGLE windowRectangle; + + if (PhGetIntegerSetting(L"FirstRun")) + { + PPH_STRING autoDbghelpPath; + + // Try to set up the dbghelp path automatically if this is the first run. + if (autoDbghelpPath = PH_AUTO(PhMwpFindDbghelpPath())) + PhSetStringSetting2(L"DbgHelpPath", &autoDbghelpPath->sr); + + PhSetIntegerSetting(L"FirstRun", FALSE); + } + + // This was added to be able to delay-load dbghelp.dll and symsrv.dll. + PhRegisterCallback(&PhSymInitCallback, PhMwpSymInitHandler, NULL, &SymInitRegistration); + + PhMwpInitializeProviders(); + + if (!PhMwpInitializeWindowClass()) + return FALSE; + + windowRectangle.Position = PhGetIntegerPairSetting(L"MainWindowPosition"); + windowRectangle.Size = PhGetScalableIntegerPairSetting(L"MainWindowSize", TRUE).Pair; + + // Create the window title. + + PhInitializeStringBuilder(&stringBuilder, 100); + PhAppendStringBuilder2(&stringBuilder, L"Process Hacker"); + + if (PhCurrentUserName) + { + PhAppendStringBuilder2(&stringBuilder, L" ["); + PhAppendStringBuilder(&stringBuilder, &PhCurrentUserName->sr); + PhAppendCharStringBuilder(&stringBuilder, ']'); + if (KphIsConnected()) PhAppendCharStringBuilder(&stringBuilder, '+'); + } + + if (WINDOWS_HAS_UAC && PhGetOwnTokenAttributes().ElevationType == TokenElevationTypeFull) + PhAppendStringBuilder2(&stringBuilder, L" (Administrator)"); + + // Create the window. + + PhMainWndHandle = CreateWindow( + PH_MAINWND_CLASSNAME, + stringBuilder.String->Buffer, + WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN, + windowRectangle.Left, + windowRectangle.Top, + windowRectangle.Width, + windowRectangle.Height, + NULL, + NULL, + PhInstanceHandle, + NULL + ); + PhDeleteStringBuilder(&stringBuilder); + PhMainWndMenuHandle = GetMenu(PhMainWndHandle); + + if (!PhMainWndHandle) + return FALSE; + + PhMwpInitializeMainMenu(PhMainWndMenuHandle); + + // Choose a more appropriate rectangle for the window. + PhAdjustRectangleToWorkingArea(PhMainWndHandle, &windowRectangle); + MoveWindow(PhMainWndHandle, windowRectangle.Left, windowRectangle.Top, + windowRectangle.Width, windowRectangle.Height, FALSE); + + // Allow WM_PH_ACTIVATE to pass through UIPI. + if (WINDOWS_HAS_UAC) + ChangeWindowMessageFilter_I(WM_PH_ACTIVATE, MSGFLT_ADD); + + PhMwpOnSettingChange(); + + // Initialize child controls. + PhMwpInitializeControls(); + + PhMwpLoadSettings(); + PhLogInitialization(); + PhQueueItemWorkQueue(PhGetGlobalWorkQueue(), PhMwpDelayedLoadFunction, NULL); + + PhMwpSelectionChangedTabControl(-1); + + // Perform a layout. + PhMwpOnSize(); + + PhStartProviderThread(&PhPrimaryProviderThread); + PhStartProviderThread(&PhSecondaryProviderThread); + + // See PhMwpOnTimer for more details. + if (PhCsUpdateInterval > PH_FLUSH_PROCESS_QUERY_DATA_INTERVAL_1) + SetTimer(PhMainWndHandle, TIMER_FLUSH_PROCESS_QUERY_DATA, PH_FLUSH_PROCESS_QUERY_DATA_INTERVAL_1, NULL); + + UpdateWindow(PhMainWndHandle); + + if ((PhStartupParameters.ShowHidden || PhGetIntegerSetting(L"StartHidden")) && PhNfTestIconMask(PH_ICON_ALL)) + ShowCommand = SW_HIDE; + if (PhStartupParameters.ShowVisible) + ShowCommand = SW_SHOW; + + if (PhGetIntegerSetting(L"MainWindowState") == SW_MAXIMIZE) + { + if (ShowCommand != SW_HIDE) + { + ShowCommand = SW_MAXIMIZE; + } + else + { + // We can't maximize it while having it hidden. Set it as pending. + NeedsMaximize = TRUE; + } + } + + if (PhPluginsEnabled) + PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackMainWindowShowing), IntToPtr(ShowCommand)); + + if (PhStartupParameters.SelectTab) + { + PPH_MAIN_TAB_PAGE page = PhMwpFindPage(&PhStartupParameters.SelectTab->sr); + + if (page) + PhMwpSelectPage(page->Index); + } + + if (PhStartupParameters.SysInfo) + PhShowSystemInformationDialog(PhStartupParameters.SysInfo->Buffer); + + if (ShowCommand != SW_HIDE) + ShowWindow(PhMainWndHandle, ShowCommand); + + if (PhGetIntegerSetting(L"MiniInfoWindowPinned")) + PhPinMiniInformation(MiniInfoManualPinType, 1, 0, PH_MINIINFO_LOAD_POSITION, NULL, NULL); + + return TRUE; +} + +LRESULT CALLBACK PhMwpWndProc( + _In_ HWND hWnd, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + switch (uMsg) + { + case WM_DESTROY: + { + PhMwpOnDestroy(); + } + break; + case WM_ENDSESSION: + { + PhMwpOnEndSession(); + } + break; + case WM_SETTINGCHANGE: + { + PhMwpOnSettingChange(); + } + break; + case WM_COMMAND: + { + PhMwpOnCommand(LOWORD(wParam)); + } + break; + case WM_SHOWWINDOW: + { + PhMwpOnShowWindow(!!wParam, (ULONG)lParam); + } + break; + case WM_SYSCOMMAND: + { + if (PhMwpOnSysCommand((ULONG)wParam, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))) + return 0; + } + break; + case WM_MENUCOMMAND: + { + PhMwpOnMenuCommand((ULONG)wParam, (HMENU)lParam); + } + break; + case WM_INITMENUPOPUP: + { + PhMwpOnInitMenuPopup((HMENU)wParam, LOWORD(lParam), !!HIWORD(lParam)); + } + break; + case WM_SIZE: + { + PhMwpOnSize(); + } + break; + case WM_SIZING: + { + PhMwpOnSizing((ULONG)wParam, (PRECT)lParam); + } + break; + case WM_SETFOCUS: + { + PhMwpOnSetFocus(); + } + break; + case WM_TIMER: + { + PhMwpOnTimer((ULONG)wParam); + } + break; + case WM_NOTIFY: + { + LRESULT result; + + if (PhMwpOnNotify((NMHDR *)lParam, &result)) + return result; + } + break; + case WM_WTSSESSION_CHANGE: + { + PhMwpOnWtsSessionChange((ULONG)wParam, (ULONG)lParam); + } + break; + } + + if (uMsg >= WM_PH_FIRST && uMsg <= WM_PH_LAST) + { + return PhMwpOnUserMessage(uMsg, wParam, lParam); + } + + return DefWindowProc(hWnd, uMsg, wParam, lParam); +} + +BOOLEAN PhMwpInitializeWindowClass( + VOID + ) +{ + WNDCLASSEX wcex; + + memset(&wcex, 0, sizeof(WNDCLASSEX)); + wcex.cbSize = sizeof(WNDCLASSEX); + wcex.style = 0; + wcex.lpfnWndProc = PhMwpWndProc; + wcex.cbClsExtra = 0; + wcex.cbWndExtra = 0; + wcex.hInstance = PhInstanceHandle; + wcex.hIcon = LoadIcon(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER)); + wcex.hCursor = LoadCursor(NULL, IDC_ARROW); + //wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); + wcex.lpszMenuName = MAKEINTRESOURCE(IDR_MAINWND); + wcex.lpszClassName = PH_MAINWND_CLASSNAME; + wcex.hIconSm = (HICON)LoadImage(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER), IMAGE_ICON, 16, 16, 0); + + if (!RegisterClassEx(&wcex)) + return FALSE; + + return TRUE; +} + +VOID PhMwpInitializeProviders( + VOID + ) +{ + ULONG interval; + + interval = PhGetIntegerSetting(L"UpdateInterval"); + + if (interval == 0) + { + interval = 1000; + PH_SET_INTEGER_CACHED_SETTING(UpdateInterval, interval); + } + + PhInitializeProviderThread(&PhPrimaryProviderThread, interval); + PhInitializeProviderThread(&PhSecondaryProviderThread, interval); + + PhRegisterProvider(&PhPrimaryProviderThread, PhProcessProviderUpdate, NULL, &PhMwpProcessProviderRegistration); + PhSetEnabledProvider(&PhMwpProcessProviderRegistration, TRUE); + PhRegisterProvider(&PhPrimaryProviderThread, PhServiceProviderUpdate, NULL, &PhMwpServiceProviderRegistration); + PhSetEnabledProvider(&PhMwpServiceProviderRegistration, TRUE); + PhRegisterProvider(&PhPrimaryProviderThread, PhNetworkProviderUpdate, NULL, &PhMwpNetworkProviderRegistration); +} + +VOID PhMwpApplyUpdateInterval( + _In_ ULONG Interval + ) +{ + PhSetIntervalProviderThread(&PhPrimaryProviderThread, Interval); + PhSetIntervalProviderThread(&PhSecondaryProviderThread, Interval); + + if (Interval > PH_FLUSH_PROCESS_QUERY_DATA_INTERVAL_LONG_TERM) + SetTimer(PhMainWndHandle, TIMER_FLUSH_PROCESS_QUERY_DATA, PH_FLUSH_PROCESS_QUERY_DATA_INTERVAL_LONG_TERM, NULL); + else + KillTimer(PhMainWndHandle, TIMER_FLUSH_PROCESS_QUERY_DATA); // Might not exist +} + +VOID PhMwpInitializeControls( + VOID + ) +{ + ULONG thinRows; + + TabControlHandle = CreateWindow( + WC_TABCONTROL, + NULL, + WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | TCS_MULTILINE, + 0, + 0, + 3, + 3, + PhMainWndHandle, + NULL, + PhInstanceHandle, + NULL + ); + SendMessage(TabControlHandle, WM_SETFONT, (WPARAM)PhApplicationFont, FALSE); + BringWindowToTop(TabControlHandle); + + thinRows = PhGetIntegerSetting(L"ThinRows") ? TN_STYLE_THIN_ROWS : 0; + + PhMwpProcessTreeNewHandle = CreateWindow( + PH_TREENEW_CLASSNAME, + NULL, + WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_BORDER | TN_STYLE_ICONS | TN_STYLE_DOUBLE_BUFFERED | TN_STYLE_ANIMATE_DIVIDER | thinRows, + 0, + 0, + 3, + 3, + PhMainWndHandle, + (HMENU)ID_MAINWND_PROCESSTL, + PhLibImageBase, + NULL + ); + BringWindowToTop(PhMwpProcessTreeNewHandle); + + PhMwpServiceTreeNewHandle = CreateWindow( + PH_TREENEW_CLASSNAME, + NULL, + WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_BORDER | TN_STYLE_ICONS | TN_STYLE_DOUBLE_BUFFERED | thinRows, + 0, + 0, + 3, + 3, + PhMainWndHandle, + (HMENU)ID_MAINWND_SERVICETL, + PhLibImageBase, + NULL + ); + BringWindowToTop(PhMwpServiceTreeNewHandle); + + PhMwpNetworkTreeNewHandle = CreateWindow( + PH_TREENEW_CLASSNAME, + NULL, + WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_BORDER | TN_STYLE_ICONS | TN_STYLE_DOUBLE_BUFFERED | thinRows, + 0, + 0, + 3, + 3, + PhMainWndHandle, + (HMENU)ID_MAINWND_NETWORKTL, + PhLibImageBase, + NULL + ); + BringWindowToTop(PhMwpNetworkTreeNewHandle); + + PageList = PhCreateList(10); + + PhMwpCreateInternalPage(L"Processes", 0, PhMwpProcessesPageCallback); + PhProcessTreeListInitialization(); + PhInitializeProcessTreeList(PhMwpProcessTreeNewHandle); + + PhMwpCreateInternalPage(L"Services", 0, PhMwpServicesPageCallback); + PhServiceTreeListInitialization(); + PhInitializeServiceTreeList(PhMwpServiceTreeNewHandle); + + PhMwpCreateInternalPage(L"Network", 0, PhMwpNetworkPageCallback); + PhNetworkTreeListInitialization(); + PhInitializeNetworkTreeList(PhMwpNetworkTreeNewHandle); + + CurrentPage = PageList->Items[0]; +} + +NTSTATUS PhMwpDelayedLoadFunction( + _In_ PVOID Parameter + ) +{ + // Register for window station notifications. + WinStationRegisterConsoleNotification(NULL, PhMainWndHandle, WNOTIFY_ALL_SESSIONS); + + PhNfLoadStage2(); + + // Make sure we get closed late in the shutdown process. + SetProcessShutdownParameters(0x100, 0); + + DelayedLoadCompleted = TRUE; + //PostMessage(PhMainWndHandle, WM_PH_DELAYED_LOAD_COMPLETED, 0, 0); + + return STATUS_SUCCESS; +} + +PPH_STRING PhMwpFindDbghelpPath( + VOID + ) +{ + static struct + { + ULONG Folder; + PWSTR AppendPath; + } locations[] = + { +#ifdef _WIN64 + { CSIDL_PROGRAM_FILESX86, L"\\Windows Kits\\10\\Debuggers\\x64\\dbghelp.dll" }, + { CSIDL_PROGRAM_FILESX86, L"\\Windows Kits\\8.1\\Debuggers\\x64\\dbghelp.dll" }, + { CSIDL_PROGRAM_FILESX86, L"\\Windows Kits\\8.0\\Debuggers\\x64\\dbghelp.dll" }, + { CSIDL_PROGRAM_FILES, L"\\Debugging Tools for Windows (x64)\\dbghelp.dll" } +#else + { CSIDL_PROGRAM_FILES, L"\\Windows Kits\\10\\Debuggers\\x86\\dbghelp.dll" }, + { CSIDL_PROGRAM_FILES, L"\\Windows Kits\\8.1\\Debuggers\\x86\\dbghelp.dll" }, + { CSIDL_PROGRAM_FILES, L"\\Windows Kits\\8.0\\Debuggers\\x86\\dbghelp.dll" }, + { CSIDL_PROGRAM_FILES, L"\\Debugging Tools for Windows (x86)\\dbghelp.dll" } +#endif + }; + + PPH_STRING path; + ULONG i; + + for (i = 0; i < sizeof(locations) / sizeof(locations[0]); i++) + { + path = PhGetKnownLocation(locations[i].Folder, locations[i].AppendPath); + + if (path) + { + if (RtlDoesFileExists_U(path->Buffer)) + return path; + + PhDereferenceObject(path); + } + } + + return NULL; +} + +VOID PhMwpOnDestroy( + VOID + ) +{ + // Notify pages and plugins that we are shutting down. + + PhMwpNotifyAllPages(MainTabPageDestroy, NULL, NULL); + + if (PhPluginsEnabled) + PhUnloadPlugins(); + + if (!PhMainWndExiting) + ProcessHacker_SaveAllSettings(PhMainWndHandle); + + PhNfUninitialization(); + + PostQuitMessage(0); +} + +VOID PhMwpOnEndSession( + VOID + ) +{ + PhMwpOnDestroy(); +} + +VOID PhMwpOnSettingChange( + VOID + ) +{ + if (PhApplicationFont) + DeleteObject(PhApplicationFont); + + PhInitializeFont(PhMainWndHandle); + + SendMessage(TabControlHandle, WM_SETFONT, (WPARAM)PhApplicationFont, FALSE); +} + +VOID PhMwpOnCommand( + _In_ ULONG Id + ) +{ + switch (Id) + { + case ID_ESC_EXIT: + { + if (PhGetIntegerSetting(L"HideOnClose")) + { + if (PhNfTestIconMask(PH_ICON_ALL)) + ShowWindow(PhMainWndHandle, SW_HIDE); + } + else if (PhGetIntegerSetting(L"CloseOnEscape")) + { + ProcessHacker_Destroy(PhMainWndHandle); + } + } + break; + case ID_HACKER_RUN: + { + if (RunFileDlg) + { + SelectedRunAsMode = 0; + RunFileDlg(PhMainWndHandle, NULL, NULL, NULL, NULL, 0); + } + } + break; + case ID_HACKER_RUNASADMINISTRATOR: + { + if (RunFileDlg) + { + SelectedRunAsMode = RUNAS_MODE_ADMIN; + RunFileDlg( + PhMainWndHandle, + NULL, + NULL, + NULL, + L"Type the name of a program that will be opened under alternate credentials.", + 0 + ); + } + } + break; + case ID_HACKER_RUNASLIMITEDUSER: + { + if (RunFileDlg) + { + SelectedRunAsMode = RUNAS_MODE_LIMITED; + RunFileDlg( + PhMainWndHandle, + NULL, + NULL, + NULL, + L"Type the name of a program that will be opened under standard user privileges.", + 0 + ); + } + } + break; + case ID_HACKER_RUNAS: + { + PhShowRunAsDialog(PhMainWndHandle, NULL); + } + break; + case ID_HACKER_SHOWDETAILSFORALLPROCESSES: + { + ProcessHacker_PrepareForEarlyShutdown(PhMainWndHandle); + + if (PhShellProcessHacker( + PhMainWndHandle, + L"-v", + SW_SHOW, + PH_SHELL_EXECUTE_ADMIN, + PH_SHELL_APP_PROPAGATE_PARAMETERS | PH_SHELL_APP_PROPAGATE_PARAMETERS_IGNORE_VISIBILITY, + 0, + NULL + )) + { + ProcessHacker_Destroy(PhMainWndHandle); + } + else + { + ProcessHacker_CancelEarlyShutdown(PhMainWndHandle); + } + } + break; + case ID_HACKER_SAVE: + { + static PH_FILETYPE_FILTER filters[] = + { + { L"Text files (*.txt;*.log)", L"*.txt;*.log" }, + { L"Comma-separated values (*.csv)", L"*.csv" }, + { L"All files (*.*)", L"*.*" } + }; + PVOID fileDialog = PhCreateSaveFileDialog(); + PH_FORMAT format[3]; + + PhInitFormatS(&format[0], L"Process Hacker "); + PhInitFormatSR(&format[1], CurrentPage->Name); + PhInitFormatS(&format[2], L".txt"); + + PhSetFileDialogFilter(fileDialog, filters, sizeof(filters) / sizeof(PH_FILETYPE_FILTER)); + PhSetFileDialogFileName(fileDialog, PH_AUTO_T(PH_STRING, PhFormat(format, 3, 60))->Buffer); + + if (PhShowFileDialog(PhMainWndHandle, fileDialog)) + { + NTSTATUS status; + PPH_STRING fileName; + ULONG filterIndex; + PPH_FILE_STREAM fileStream; + + fileName = PH_AUTO(PhGetFileDialogFileName(fileDialog)); + filterIndex = PhGetFileDialogFilterIndex(fileDialog); + + if (NT_SUCCESS(status = PhCreateFileStream( + &fileStream, + fileName->Buffer, + FILE_GENERIC_WRITE, + FILE_SHARE_READ, + FILE_OVERWRITE_IF, + 0 + ))) + { + ULONG mode; + PH_MAIN_TAB_PAGE_EXPORT_CONTENT exportContent; + + if (filterIndex == 2) + mode = PH_EXPORT_MODE_CSV; + else + mode = PH_EXPORT_MODE_TABS; + + PhWriteStringAsUtf8FileStream(fileStream, &PhUnicodeByteOrderMark); + PhWritePhTextHeader(fileStream); + + exportContent.FileStream = fileStream; + exportContent.Mode = mode; + CurrentPage->Callback(CurrentPage, MainTabPageExportContent, &exportContent, NULL); + + PhDereferenceObject(fileStream); + } + + if (!NT_SUCCESS(status)) + PhShowStatus(PhMainWndHandle, L"Unable to create the file", status, 0); + } + + PhFreeFileDialog(fileDialog); + } + break; + case ID_HACKER_FINDHANDLESORDLLS: + { + PhShowFindObjectsDialog(); + } + break; + case ID_HACKER_OPTIONS: + { + PhShowOptionsDialog(PhMainWndHandle); + } + break; + case ID_HACKER_PLUGINS: + { + PhShowPluginsDialog(PhMainWndHandle); + } + break; + case ID_COMPUTER_LOCK: + case ID_COMPUTER_LOGOFF: + case ID_COMPUTER_SLEEP: + case ID_COMPUTER_HIBERNATE: + case ID_COMPUTER_RESTART: + case ID_COMPUTER_RESTARTBOOTOPTIONS: + case ID_COMPUTER_SHUTDOWN: + case ID_COMPUTER_SHUTDOWNHYBRID: + PhMwpExecuteComputerCommand(Id); + break; + case ID_HACKER_EXIT: + ProcessHacker_Destroy(PhMainWndHandle); + break; + case ID_VIEW_SYSTEMINFORMATION: + PhShowSystemInformationDialog(NULL); + break; + case ID_TRAYICONS_CPUHISTORY: + case ID_TRAYICONS_CPUUSAGE: + case ID_TRAYICONS_IOHISTORY: + case ID_TRAYICONS_COMMITHISTORY: + case ID_TRAYICONS_PHYSICALMEMORYHISTORY: + { + ULONG i; + + switch (Id) + { + case ID_TRAYICONS_CPUHISTORY: + i = PH_ICON_CPU_HISTORY; + break; + case ID_TRAYICONS_CPUUSAGE: + i = PH_ICON_CPU_USAGE; + break; + case ID_TRAYICONS_IOHISTORY: + i = PH_ICON_IO_HISTORY; + break; + case ID_TRAYICONS_COMMITHISTORY: + i = PH_ICON_COMMIT_HISTORY; + break; + case ID_TRAYICONS_PHYSICALMEMORYHISTORY: + i = PH_ICON_PHYSICAL_HISTORY; + break; + } + + PhNfSetVisibleIcon(i, !PhNfTestIconMask(i)); + } + break; + case ID_VIEW_HIDEPROCESSESFROMOTHERUSERS: + { + PhMwpToggleCurrentUserProcessTreeFilter(); + } + break; + case ID_VIEW_HIDESIGNEDPROCESSES: + { + PhMwpToggleSignedProcessTreeFilter(); + } + break; + case ID_VIEW_SCROLLTONEWPROCESSES: + { + PH_SET_INTEGER_CACHED_SETTING(ScrollToNewProcesses, !PhCsScrollToNewProcesses); + } + break; + case ID_VIEW_SHOWCPUBELOW001: + { + PH_SET_INTEGER_CACHED_SETTING(ShowCpuBelow001, !PhCsShowCpuBelow001); + PhInvalidateAllProcessNodes(); + } + break; + case ID_VIEW_HIDEDRIVERSERVICES: + { + PhMwpToggleDriverServiceTreeFilter(); + } + break; + case ID_VIEW_ALWAYSONTOP: + { + AlwaysOnTop = !AlwaysOnTop; + SetWindowPos(PhMainWndHandle, AlwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST, + 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE); + PhSetIntegerSetting(L"MainWindowAlwaysOnTop", AlwaysOnTop); + } + break; + case ID_OPACITY_10: + case ID_OPACITY_20: + case ID_OPACITY_30: + case ID_OPACITY_40: + case ID_OPACITY_50: + case ID_OPACITY_60: + case ID_OPACITY_70: + case ID_OPACITY_80: + case ID_OPACITY_90: + case ID_OPACITY_OPAQUE: + { + ULONG opacity; + + opacity = PH_ID_TO_OPACITY(Id); + PhSetIntegerSetting(L"MainWindowOpacity", opacity); + PhSetWindowOpacity(PhMainWndHandle, opacity); + } + break; + case ID_VIEW_REFRESH: + { + PhBoostProvider(&PhMwpProcessProviderRegistration, NULL); + PhBoostProvider(&PhMwpServiceProviderRegistration, NULL); + } + break; + case ID_UPDATEINTERVAL_FAST: + case ID_UPDATEINTERVAL_NORMAL: + case ID_UPDATEINTERVAL_BELOWNORMAL: + case ID_UPDATEINTERVAL_SLOW: + case ID_UPDATEINTERVAL_VERYSLOW: + { + ULONG interval; + + switch (Id) + { + case ID_UPDATEINTERVAL_FAST: + interval = 500; + break; + case ID_UPDATEINTERVAL_NORMAL: + interval = 1000; + break; + case ID_UPDATEINTERVAL_BELOWNORMAL: + interval = 2000; + break; + case ID_UPDATEINTERVAL_SLOW: + interval = 5000; + break; + case ID_UPDATEINTERVAL_VERYSLOW: + interval = 10000; + break; + } + + PH_SET_INTEGER_CACHED_SETTING(UpdateInterval, interval); + PhMwpApplyUpdateInterval(interval); + } + break; + case ID_VIEW_UPDATEAUTOMATICALLY: + { + PhMwpUpdateAutomatically = !PhMwpUpdateAutomatically; + PhMwpNotifyAllPages(MainTabPageUpdateAutomaticallyChanged, (PVOID)PhMwpUpdateAutomatically, NULL); + } + break; + case ID_TOOLS_CREATESERVICE: + { + PhShowCreateServiceDialog(PhMainWndHandle); + } + break; + case ID_TOOLS_HIDDENPROCESSES: + { + PhShowHiddenProcessesDialog(); + } + break; + case ID_TOOLS_INSPECTEXECUTABLEFILE: + { + static PH_FILETYPE_FILTER filters[] = + { + { L"Executable files (*.exe;*.dll;*.ocx;*.sys;*.scr;*.cpl)", L"*.exe;*.dll;*.ocx;*.sys;*.scr;*.cpl" }, + { L"All files (*.*)", L"*.*" } + }; + PVOID fileDialog = PhCreateOpenFileDialog(); + + PhSetFileDialogFilter(fileDialog, filters, sizeof(filters) / sizeof(PH_FILETYPE_FILTER)); + + if (PhShowFileDialog(PhMainWndHandle, fileDialog)) + { + PhShellExecuteUserString( + PhMainWndHandle, + L"ProgramInspectExecutables", + PH_AUTO_T(PH_STRING, PhGetFileDialogFileName(fileDialog))->Buffer, + FALSE, + L"Make sure the PE Viewer executable file is present." + ); + } + + PhFreeFileDialog(fileDialog); + } + break; + case ID_TOOLS_PAGEFILES: + { + PhShowPagefilesDialog(PhMainWndHandle); + } + break; + case ID_TOOLS_STARTTASKMANAGER: + { + PPH_STRING systemDirectory; + PPH_STRING taskmgrFileName; + + systemDirectory = PH_AUTO(PhGetSystemDirectory()); + taskmgrFileName = PH_AUTO(PhConcatStrings2(systemDirectory->Buffer, L"\\taskmgr.exe")); + + if (WindowsVersion >= WINDOWS_8 && !PhGetOwnTokenAttributes().Elevated) + { + if (PhUiConnectToPhSvc(PhMainWndHandle, FALSE)) + { + PhSvcCallCreateProcessIgnoreIfeoDebugger(taskmgrFileName->Buffer); + PhUiDisconnectFromPhSvc(); + } + } + else + { + PhCreateProcessIgnoreIfeoDebugger(taskmgrFileName->Buffer); + } + } + break; + case ID_USER_CONNECT: + { + PhUiConnectSession(PhMainWndHandle, SelectedUserSessionId); + } + break; + case ID_USER_DISCONNECT: + { + PhUiDisconnectSession(PhMainWndHandle, SelectedUserSessionId); + } + break; + case ID_USER_LOGOFF: + { + PhUiLogoffSession(PhMainWndHandle, SelectedUserSessionId); + } + break; + case ID_USER_REMOTECONTROL: + { + PhShowSessionShadowDialog(PhMainWndHandle, SelectedUserSessionId); + } + break; + case ID_USER_SENDMESSAGE: + { + PhShowSessionSendMessageDialog(PhMainWndHandle, SelectedUserSessionId); + } + break; + case ID_USER_PROPERTIES: + { + PhShowSessionProperties(PhMainWndHandle, SelectedUserSessionId); + } + break; + case ID_HELP_LOG: + { + PhShowLogDialog(); + } + break; + case ID_HELP_DONATE: + { + PhShellExecute(PhMainWndHandle, L"https://sourceforge.net/project/project_donations.php?group_id=242527", NULL); + } + break; + case ID_HELP_DEBUGCONSOLE: + { + PhShowDebugConsole(); + } + break; + case ID_HELP_ABOUT: + { + PhShowAboutDialog(PhMainWndHandle); + } + break; + case ID_PROCESS_TERMINATE: + { + PPH_PROCESS_ITEM *processes; + ULONG numberOfProcesses; + + PhGetSelectedProcessItems(&processes, &numberOfProcesses); + PhReferenceObjects(processes, numberOfProcesses); + + if (PhUiTerminateProcesses(PhMainWndHandle, processes, numberOfProcesses)) + PhDeselectAllProcessNodes(); + + PhDereferenceObjects(processes, numberOfProcesses); + PhFree(processes); + } + break; + case ID_PROCESS_TERMINATETREE: + { + PPH_PROCESS_ITEM processItem = PhGetSelectedProcessItem(); + + if (processItem) + { + PhReferenceObject(processItem); + + if (PhUiTerminateTreeProcess(PhMainWndHandle, processItem)) + PhDeselectAllProcessNodes(); + + PhDereferenceObject(processItem); + } + } + break; + case ID_PROCESS_SUSPEND: + { + PPH_PROCESS_ITEM *processes; + ULONG numberOfProcesses; + + PhGetSelectedProcessItems(&processes, &numberOfProcesses); + PhReferenceObjects(processes, numberOfProcesses); + PhUiSuspendProcesses(PhMainWndHandle, processes, numberOfProcesses); + PhDereferenceObjects(processes, numberOfProcesses); + PhFree(processes); + } + break; + case ID_PROCESS_RESUME: + { + PPH_PROCESS_ITEM *processes; + ULONG numberOfProcesses; + + PhGetSelectedProcessItems(&processes, &numberOfProcesses); + PhReferenceObjects(processes, numberOfProcesses); + PhUiResumeProcesses(PhMainWndHandle, processes, numberOfProcesses); + PhDereferenceObjects(processes, numberOfProcesses); + PhFree(processes); + } + break; + case ID_PROCESS_RESTART: + { + PPH_PROCESS_ITEM processItem = PhGetSelectedProcessItem(); + + if (processItem) + { + PhReferenceObject(processItem); + + if (PhUiRestartProcess(PhMainWndHandle, processItem)) + PhDeselectAllProcessNodes(); + + PhDereferenceObject(processItem); + } + } + break; + case ID_PROCESS_CREATEDUMPFILE: + { + PPH_PROCESS_ITEM processItem = PhGetSelectedProcessItem(); + + if (processItem) + { + PhReferenceObject(processItem); + PhUiCreateDumpFileProcess(PhMainWndHandle, processItem); + PhDereferenceObject(processItem); + } + } + break; + case ID_PROCESS_DEBUG: + { + PPH_PROCESS_ITEM processItem = PhGetSelectedProcessItem(); + + if (processItem) + { + PhReferenceObject(processItem); + PhUiDebugProcess(PhMainWndHandle, processItem); + PhDereferenceObject(processItem); + } + } + break; + case ID_PROCESS_VIRTUALIZATION: + { + PPH_PROCESS_ITEM processItem = PhGetSelectedProcessItem(); + + if (processItem) + { + PhReferenceObject(processItem); + PhUiSetVirtualizationProcess( + PhMainWndHandle, + processItem, + !PhMwpSelectedProcessVirtualizationEnabled + ); + PhDereferenceObject(processItem); + } + } + break; + case ID_PROCESS_AFFINITY: + { + PPH_PROCESS_ITEM processItem = PhGetSelectedProcessItem(); + + if (processItem) + { + PhReferenceObject(processItem); + PhShowProcessAffinityDialog(PhMainWndHandle, processItem, NULL); + PhDereferenceObject(processItem); + } + } + break; + case ID_MISCELLANEOUS_DETACHFROMDEBUGGER: + { + PPH_PROCESS_ITEM processItem = PhGetSelectedProcessItem(); + + if (processItem) + { + PhReferenceObject(processItem); + PhUiDetachFromDebuggerProcess(PhMainWndHandle, processItem); + PhDereferenceObject(processItem); + } + } + break; + case ID_MISCELLANEOUS_GDIHANDLES: + { + PPH_PROCESS_ITEM processItem = PhGetSelectedProcessItem(); + + if (processItem) + { + PhReferenceObject(processItem); + PhShowGdiHandlesDialog(PhMainWndHandle, processItem); + PhDereferenceObject(processItem); + } + } + break; + case ID_MISCELLANEOUS_INJECTDLL: + { + PPH_PROCESS_ITEM processItem = PhGetSelectedProcessItem(); + + if (processItem) + { + PhReferenceObject(processItem); + PhUiInjectDllProcess(PhMainWndHandle, processItem); + PhDereferenceObject(processItem); + } + } + break; + case ID_PAGEPRIORITY_VERYLOW: + case ID_PAGEPRIORITY_LOW: + case ID_PAGEPRIORITY_MEDIUM: + case ID_PAGEPRIORITY_BELOWNORMAL: + case ID_PAGEPRIORITY_NORMAL: + { + PPH_PROCESS_ITEM processItem = PhGetSelectedProcessItem(); + + if (processItem) + { + ULONG pagePriority; + + switch (Id) + { + case ID_PAGEPRIORITY_VERYLOW: + pagePriority = MEMORY_PRIORITY_VERY_LOW; + break; + case ID_PAGEPRIORITY_LOW: + pagePriority = MEMORY_PRIORITY_LOW; + break; + case ID_PAGEPRIORITY_MEDIUM: + pagePriority = MEMORY_PRIORITY_MEDIUM; + break; + case ID_PAGEPRIORITY_BELOWNORMAL: + pagePriority = MEMORY_PRIORITY_BELOW_NORMAL; + break; + case ID_PAGEPRIORITY_NORMAL: + pagePriority = MEMORY_PRIORITY_NORMAL; + break; + } + + PhReferenceObject(processItem); + PhUiSetPagePriorityProcess(PhMainWndHandle, processItem, pagePriority); + PhDereferenceObject(processItem); + } + } + break; + case ID_MISCELLANEOUS_REDUCEWORKINGSET: + { + PPH_PROCESS_ITEM *processes; + ULONG numberOfProcesses; + + PhGetSelectedProcessItems(&processes, &numberOfProcesses); + PhReferenceObjects(processes, numberOfProcesses); + PhUiReduceWorkingSetProcesses(PhMainWndHandle, processes, numberOfProcesses); + PhDereferenceObjects(processes, numberOfProcesses); + PhFree(processes); + } + break; + case ID_MISCELLANEOUS_RUNAS: + { + PPH_PROCESS_ITEM processItem = PhGetSelectedProcessItem(); + + if (processItem && processItem->FileName) + { + PhSetStringSetting2(L"RunAsProgram", &processItem->FileName->sr); + PhShowRunAsDialog(PhMainWndHandle, NULL); + } + } + break; + case ID_MISCELLANEOUS_RUNASTHISUSER: + { + PPH_PROCESS_ITEM processItem = PhGetSelectedProcessItem(); + + if (processItem) + { + PhShowRunAsDialog(PhMainWndHandle, processItem->ProcessId); + } + } + break; + case ID_PRIORITY_REALTIME: + case ID_PRIORITY_HIGH: + case ID_PRIORITY_ABOVENORMAL: + case ID_PRIORITY_NORMAL: + case ID_PRIORITY_BELOWNORMAL: + case ID_PRIORITY_IDLE: + { + PPH_PROCESS_ITEM *processes; + ULONG numberOfProcesses; + + PhGetSelectedProcessItems(&processes, &numberOfProcesses); + PhReferenceObjects(processes, numberOfProcesses); + PhMwpExecuteProcessPriorityCommand(Id, processes, numberOfProcesses); + PhDereferenceObjects(processes, numberOfProcesses); + PhFree(processes); + } + break; + case ID_IOPRIORITY_VERYLOW: + case ID_IOPRIORITY_LOW: + case ID_IOPRIORITY_NORMAL: + case ID_IOPRIORITY_HIGH: + { + PPH_PROCESS_ITEM *processes; + ULONG numberOfProcesses; + + PhGetSelectedProcessItems(&processes, &numberOfProcesses); + PhReferenceObjects(processes, numberOfProcesses); + PhMwpExecuteProcessIoPriorityCommand(Id, processes, numberOfProcesses); + PhDereferenceObjects(processes, numberOfProcesses); + PhFree(processes); + } + break; + case ID_WINDOW_BRINGTOFRONT: + { + if (IsWindow(PhMwpSelectedProcessWindowHandle)) + { + WINDOWPLACEMENT placement = { sizeof(placement) }; + + GetWindowPlacement(PhMwpSelectedProcessWindowHandle, &placement); + + if (placement.showCmd == SW_MINIMIZE) + ShowWindowAsync(PhMwpSelectedProcessWindowHandle, SW_RESTORE); + else + SetForegroundWindow(PhMwpSelectedProcessWindowHandle); + } + } + break; + case ID_WINDOW_RESTORE: + { + if (IsWindow(PhMwpSelectedProcessWindowHandle)) + { + ShowWindowAsync(PhMwpSelectedProcessWindowHandle, SW_RESTORE); + } + } + break; + case ID_WINDOW_MINIMIZE: + { + if (IsWindow(PhMwpSelectedProcessWindowHandle)) + { + ShowWindowAsync(PhMwpSelectedProcessWindowHandle, SW_MINIMIZE); + } + } + break; + case ID_WINDOW_MAXIMIZE: + { + if (IsWindow(PhMwpSelectedProcessWindowHandle)) + { + ShowWindowAsync(PhMwpSelectedProcessWindowHandle, SW_MAXIMIZE); + } + } + break; + case ID_WINDOW_CLOSE: + { + if (IsWindow(PhMwpSelectedProcessWindowHandle)) + { + PostMessage(PhMwpSelectedProcessWindowHandle, WM_CLOSE, 0, 0); + } + } + break; + case ID_PROCESS_OPENFILELOCATION: + { + PPH_PROCESS_ITEM processItem = PhGetSelectedProcessItem(); + + if (processItem && processItem->FileName) + { + PhReferenceObject(processItem); + PhShellExploreFile(PhMainWndHandle, processItem->FileName->Buffer); + PhDereferenceObject(processItem); + } + } + break; + case ID_PROCESS_SEARCHONLINE: + { + PPH_PROCESS_ITEM processItem = PhGetSelectedProcessItem(); + + if (processItem) + { + PhSearchOnlineString(PhMainWndHandle, processItem->ProcessName->Buffer); + } + } + break; + case ID_PROCESS_PROPERTIES: + { + PPH_PROCESS_ITEM processItem = PhGetSelectedProcessItem(); + + if (processItem) + { + // No reference needed; no messages pumped. + PhMwpShowProcessProperties(processItem); + } + } + break; + case ID_PROCESS_COPY: + { + PhCopyProcessTree(); + } + break; + case ID_SERVICE_GOTOPROCESS: + { + PPH_SERVICE_ITEM serviceItem = PhGetSelectedServiceItem(); + PPH_PROCESS_NODE processNode; + + if (serviceItem) + { + if (processNode = PhFindProcessNode(serviceItem->ProcessId)) + { + PhMwpSelectPage(PhMwpProcessesPage->Index); + SetFocus(PhMwpProcessTreeNewHandle); + PhSelectAndEnsureVisibleProcessNode(processNode); + } + } + } + break; + case ID_SERVICE_START: + { + PPH_SERVICE_ITEM serviceItem = PhGetSelectedServiceItem(); + + if (serviceItem) + { + PhReferenceObject(serviceItem); + PhUiStartService(PhMainWndHandle, serviceItem); + PhDereferenceObject(serviceItem); + } + } + break; + case ID_SERVICE_CONTINUE: + { + PPH_SERVICE_ITEM serviceItem = PhGetSelectedServiceItem(); + + if (serviceItem) + { + PhReferenceObject(serviceItem); + PhUiContinueService(PhMainWndHandle, serviceItem); + PhDereferenceObject(serviceItem); + } + } + break; + case ID_SERVICE_PAUSE: + { + PPH_SERVICE_ITEM serviceItem = PhGetSelectedServiceItem(); + + if (serviceItem) + { + PhReferenceObject(serviceItem); + PhUiPauseService(PhMainWndHandle, serviceItem); + PhDereferenceObject(serviceItem); + } + } + break; + case ID_SERVICE_STOP: + { + PPH_SERVICE_ITEM serviceItem = PhGetSelectedServiceItem(); + + if (serviceItem) + { + PhReferenceObject(serviceItem); + PhUiStopService(PhMainWndHandle, serviceItem); + PhDereferenceObject(serviceItem); + } + } + break; + case ID_SERVICE_DELETE: + { + PPH_SERVICE_ITEM serviceItem = PhGetSelectedServiceItem(); + + if (serviceItem) + { + PhReferenceObject(serviceItem); + + if (PhUiDeleteService(PhMainWndHandle, serviceItem)) + PhDeselectAllServiceNodes(); + + PhDereferenceObject(serviceItem); + } + } + break; + case ID_SERVICE_OPENKEY: + { + static PH_STRINGREF servicesKeyName = PH_STRINGREF_INIT(L"System\\CurrentControlSet\\Services\\"); + static PH_STRINGREF hklm = PH_STRINGREF_INIT(L"HKLM\\"); + + PPH_SERVICE_ITEM serviceItem = PhGetSelectedServiceItem(); + + if (serviceItem) + { + HANDLE keyHandle; + PPH_STRING serviceKeyName = PH_AUTO(PhConcatStringRef2(&servicesKeyName, &serviceItem->Name->sr)); + + if (NT_SUCCESS(PhOpenKey( + &keyHandle, + KEY_READ, + PH_KEY_LOCAL_MACHINE, + &serviceKeyName->sr, + 0 + ))) + { + PPH_STRING hklmServiceKeyName; + + hklmServiceKeyName = PH_AUTO(PhConcatStringRef2(&hklm, &serviceKeyName->sr)); + PhShellOpenKey2(PhMainWndHandle, hklmServiceKeyName); + NtClose(keyHandle); + } + } + } + break; + case ID_SERVICE_OPENFILELOCATION: + { + PPH_SERVICE_ITEM serviceItem = PhGetSelectedServiceItem(); + SC_HANDLE serviceHandle; + + if (serviceItem && (serviceHandle = PhOpenService(serviceItem->Name->Buffer, SERVICE_QUERY_CONFIG))) + { + PPH_STRING fileName; + + if (fileName = PhGetServiceRelevantFileName(&serviceItem->Name->sr, serviceHandle)) + { + PhShellExploreFile(PhMainWndHandle, fileName->Buffer); + PhDereferenceObject(fileName); + } + + CloseServiceHandle(serviceHandle); + } + } + break; + case ID_SERVICE_PROPERTIES: + { + PPH_SERVICE_ITEM serviceItem = PhGetSelectedServiceItem(); + + if (serviceItem) + { + // The object relies on the list view reference, which could + // disappear if we don't reference the object here. + PhReferenceObject(serviceItem); + PhShowServiceProperties(PhMainWndHandle, serviceItem); + PhDereferenceObject(serviceItem); + } + } + break; + case ID_SERVICE_COPY: + { + PhCopyServiceList(); + } + break; + case ID_NETWORK_GOTOPROCESS: + { + PPH_NETWORK_ITEM networkItem = PhGetSelectedNetworkItem(); + PPH_PROCESS_NODE processNode; + + if (networkItem) + { + if (processNode = PhFindProcessNode(networkItem->ProcessId)) + { + PhMwpSelectPage(PhMwpProcessesPage->Index); + SetFocus(PhMwpProcessTreeNewHandle); + PhSelectAndEnsureVisibleProcessNode(processNode); + } + } + } + break; + case ID_NETWORK_GOTOSERVICE: + { + PPH_NETWORK_ITEM networkItem = PhGetSelectedNetworkItem(); + PPH_SERVICE_ITEM serviceItem; + + if (networkItem && networkItem->OwnerName) + { + if (serviceItem = PhReferenceServiceItem(networkItem->OwnerName->Buffer)) + { + PhMwpSelectPage(PhMwpServicesPage->Index); + SetFocus(PhMwpServiceTreeNewHandle); + ProcessHacker_SelectServiceItem(PhMainWndHandle, serviceItem); + + PhDereferenceObject(serviceItem); + } + } + } + break; + case ID_NETWORK_VIEWSTACK: + { + PPH_NETWORK_ITEM networkItem = PhGetSelectedNetworkItem(); + + if (networkItem) + { + PhReferenceObject(networkItem); + PhShowNetworkStackDialog(PhMainWndHandle, networkItem); + PhDereferenceObject(networkItem); + } + } + break; + case ID_NETWORK_CLOSE: + { + PPH_NETWORK_ITEM *networkItems; + ULONG numberOfNetworkItems; + + PhGetSelectedNetworkItems(&networkItems, &numberOfNetworkItems); + PhReferenceObjects(networkItems, numberOfNetworkItems); + + if (PhUiCloseConnections(PhMainWndHandle, networkItems, numberOfNetworkItems)) + PhDeselectAllNetworkNodes(); + + PhDereferenceObjects(networkItems, numberOfNetworkItems); + PhFree(networkItems); + } + break; + case ID_NETWORK_COPY: + { + PhCopyNetworkList(); + } + break; + case ID_TAB_NEXT: + { + ULONG selectedIndex = TabCtrl_GetCurSel(TabControlHandle); + + if (selectedIndex != PageList->Count - 1) + selectedIndex++; + else + selectedIndex = 0; + + PhMwpSelectPage(selectedIndex); + } + break; + case ID_TAB_PREV: + { + ULONG selectedIndex = TabCtrl_GetCurSel(TabControlHandle); + + if (selectedIndex != 0) + selectedIndex--; + else + selectedIndex = PageList->Count - 1; + + PhMwpSelectPage(selectedIndex); + } + break; + } +} + +VOID PhMwpOnShowWindow( + _In_ BOOLEAN Showing, + _In_ ULONG State + ) +{ + if (NeedsMaximize) + { + ShowWindow(PhMainWndHandle, SW_MAXIMIZE); + NeedsMaximize = FALSE; + } +} + +BOOLEAN PhMwpOnSysCommand( + _In_ ULONG Type, + _In_ LONG CursorScreenX, + _In_ LONG CursorScreenY + ) +{ + switch (Type) + { + case SC_CLOSE: + { + if (PhGetIntegerSetting(L"HideOnClose") && PhNfTestIconMask(PH_ICON_ALL)) + { + ShowWindow(PhMainWndHandle, SW_HIDE); + return TRUE; + } + } + break; + case SC_MINIMIZE: + { + // Save the current window state because we may not have a chance to later. + PhMwpSaveWindowState(); + + if (PhGetIntegerSetting(L"HideOnMinimize") && PhNfTestIconMask(PH_ICON_ALL)) + { + ShowWindow(PhMainWndHandle, SW_HIDE); + return TRUE; + } + } + break; + } + + return FALSE; +} + +VOID PhMwpOnMenuCommand( + _In_ ULONG Index, + _In_ HMENU Menu + ) +{ + MENUITEMINFO menuItemInfo; + + menuItemInfo.cbSize = sizeof(MENUITEMINFO); + menuItemInfo.fMask = MIIM_ID | MIIM_DATA; + + if (GetMenuItemInfo(Menu, Index, TRUE, &menuItemInfo)) + { + PhMwpDispatchMenuCommand(Menu, Index, menuItemInfo.wID, menuItemInfo.dwItemData); + } +} + +VOID PhMwpOnInitMenuPopup( + _In_ HMENU Menu, + _In_ ULONG Index, + _In_ BOOLEAN IsWindowMenu + ) +{ + ULONG i; + BOOLEAN found; + MENUINFO menuInfo; + PPH_EMENU menu; + + found = FALSE; + + for (i = 0; i < sizeof(SubMenuHandles) / sizeof(HWND); i++) + { + if (Menu == SubMenuHandles[i]) + { + found = TRUE; + break; + } + } + + if (!found) + return; + + if (Index == 3) + { + // Special case for Users menu. + if (!UsersMenuInitialized) + { + PhMwpUpdateUsersMenu(); + UsersMenuInitialized = TRUE; + } + + return; + } + + // Delete all items in this submenu. + while (DeleteMenu(Menu, 0, MF_BYPOSITION)) ; + + // Delete the previous EMENU for this submenu. + if (SubMenuObjects[Index]) + PhDestroyEMenu(SubMenuObjects[Index]); + + // Make sure the menu style is set correctly. + memset(&menuInfo, 0, sizeof(MENUINFO)); + menuInfo.cbSize = sizeof(MENUINFO); + menuInfo.fMask = MIM_STYLE; + menuInfo.dwStyle = MNS_CHECKORBMP; + SetMenuInfo(Menu, &menuInfo); + + menu = PhCreateEMenu(); + PhLoadResourceEMenuItem(menu, PhInstanceHandle, MAKEINTRESOURCE(IDR_MAINWND), Index); + + PhMwpInitializeSubMenu(menu, Index); + + if (PhPluginsEnabled) + { + PH_PLUGIN_MENU_INFORMATION menuInfo; + + PhPluginInitializeMenuInfo(&menuInfo, menu, PhMainWndHandle, PH_PLUGIN_MENU_DISALLOW_HOOKS); + menuInfo.u.MainMenu.SubMenuIndex = Index; + PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackMainMenuInitializing), &menuInfo); + } + + PhEMenuToHMenu2(Menu, menu, 0, NULL); + SubMenuObjects[Index] = menu; +} + +VOID PhMwpOnSize( + VOID + ) +{ + if (!IsIconic(PhMainWndHandle)) + { + HDWP deferHandle; + + deferHandle = BeginDeferWindowPos(2); + PhMwpLayout(&deferHandle); + EndDeferWindowPos(deferHandle); + } +} + +VOID PhMwpOnSizing( + _In_ ULONG Edge, + _In_ PRECT DragRectangle + ) +{ + PhResizingMinimumSize(DragRectangle, Edge, 400, 340); +} + +VOID PhMwpOnSetFocus( + VOID + ) +{ + if (CurrentPage->WindowHandle) + SetFocus(CurrentPage->WindowHandle); +} + +VOID PhMwpOnTimer( + _In_ ULONG Id + ) +{ + if (Id == TIMER_FLUSH_PROCESS_QUERY_DATA) + { + static ULONG state = 1; + + // If the update interval is too large, the user might have to wait a while before seeing some types of + // process-related data. Here we force an update. + // + // In addition, we force updates shortly after the program starts up to make things appear more quickly. + + switch (state) + { + case 1: + state = 2; + + if (PhCsUpdateInterval > PH_FLUSH_PROCESS_QUERY_DATA_INTERVAL_2) + SetTimer(PhMainWndHandle, TIMER_FLUSH_PROCESS_QUERY_DATA, PH_FLUSH_PROCESS_QUERY_DATA_INTERVAL_2, NULL); + else + KillTimer(PhMainWndHandle, TIMER_FLUSH_PROCESS_QUERY_DATA); + + break; + case 2: + state = 3; + + if (PhCsUpdateInterval > PH_FLUSH_PROCESS_QUERY_DATA_INTERVAL_LONG_TERM) + SetTimer(PhMainWndHandle, TIMER_FLUSH_PROCESS_QUERY_DATA, PH_FLUSH_PROCESS_QUERY_DATA_INTERVAL_LONG_TERM, NULL); + else + KillTimer(PhMainWndHandle, TIMER_FLUSH_PROCESS_QUERY_DATA); + + break; + default: + NOTHING; + break; + } + + PhFlushProcessQueryData(TRUE); + } +} + +BOOLEAN PhMwpOnNotify( + _In_ NMHDR *Header, + _Out_ LRESULT *Result + ) +{ + if (Header->hwndFrom == TabControlHandle) + { + PhMwpNotifyTabControl(Header); + } + else if (Header->code == RFN_VALIDATE) + { + LPNMRUNFILEDLG runFileDlg = (LPNMRUNFILEDLG)Header; + + if (SelectedRunAsMode == RUNAS_MODE_ADMIN) + { + PH_STRINGREF string; + PH_STRINGREF fileName; + PH_STRINGREF arguments; + PPH_STRING fullFileName; + PPH_STRING argumentsString; + + PhInitializeStringRefLongHint(&string, (PWSTR)runFileDlg->lpszFile); + PhParseCommandLineFuzzy(&string, &fileName, &arguments, &fullFileName); + + if (!fullFileName) + fullFileName = PhCreateString2(&fileName); + + argumentsString = PhCreateString2(&arguments); + + if (PhShellExecuteEx(PhMainWndHandle, fullFileName->Buffer, argumentsString->Buffer, + runFileDlg->nShow, PH_SHELL_EXECUTE_ADMIN, 0, NULL)) + { + *Result = RF_CANCEL; + } + else + { + *Result = RF_RETRY; + } + + PhDereferenceObject(fullFileName); + PhDereferenceObject(argumentsString); + + return TRUE; + } + else if (SelectedRunAsMode == RUNAS_MODE_LIMITED) + { + NTSTATUS status; + HANDLE tokenHandle; + HANDLE newTokenHandle; + + if (NT_SUCCESS(status = PhOpenProcessToken( + NtCurrentProcess(), + TOKEN_ASSIGN_PRIMARY | TOKEN_DUPLICATE | TOKEN_QUERY | TOKEN_ADJUST_GROUPS | + TOKEN_ADJUST_DEFAULT | READ_CONTROL | WRITE_DAC, + &tokenHandle + ))) + { + if (NT_SUCCESS(status = PhFilterTokenForLimitedUser( + tokenHandle, + &newTokenHandle + ))) + { + status = PhCreateProcessWin32( + NULL, + (PWSTR)runFileDlg->lpszFile, + NULL, + NULL, + 0, + newTokenHandle, + NULL, + NULL + ); + + NtClose(newTokenHandle); + } + + NtClose(tokenHandle); + } + + if (NT_SUCCESS(status)) + { + *Result = RF_CANCEL; + } + else + { + PhShowStatus(PhMainWndHandle, L"Unable to execute the program", status, 0); + *Result = RF_RETRY; + } + + return TRUE; + } + } + + return FALSE; +} + +VOID PhMwpOnWtsSessionChange( + _In_ ULONG Reason, + _In_ ULONG SessionId + ) +{ + if (Reason == WTS_SESSION_LOGON || Reason == WTS_SESSION_LOGOFF) + { + if (UsersMenuInitialized) + { + PhMwpUpdateUsersMenu(); + } + } +} + +ULONG_PTR PhMwpOnUserMessage( + _In_ ULONG Message, + _In_ ULONG_PTR WParam, + _In_ ULONG_PTR LParam + ) +{ + switch (Message) + { + case WM_PH_ACTIVATE: + { + if (!PhMainWndExiting) + { + if (WParam != 0) + { + PPH_PROCESS_NODE processNode; + + if (processNode = PhFindProcessNode((HANDLE)WParam)) + PhSelectAndEnsureVisibleProcessNode(processNode); + } + + if (!IsWindowVisible(PhMainWndHandle)) + { + ShowWindow(PhMainWndHandle, SW_SHOW); + } + + if (IsIconic(PhMainWndHandle)) + { + ShowWindow(PhMainWndHandle, SW_RESTORE); + } + + return PH_ACTIVATE_REPLY; + } + else + { + return 0; + } + } + break; + case WM_PH_SHOW_PROCESS_PROPERTIES: + { + PhMwpShowProcessProperties((PPH_PROCESS_ITEM)LParam); + } + break; + case WM_PH_DESTROY: + { + DestroyWindow(PhMainWndHandle); + } + break; + case WM_PH_SAVE_ALL_SETTINGS: + { + PhMwpSaveSettings(); + } + break; + case WM_PH_PREPARE_FOR_EARLY_SHUTDOWN: + { + PhMwpSaveSettings(); + PhMainWndExiting = TRUE; + } + break; + case WM_PH_CANCEL_EARLY_SHUTDOWN: + { + PhMainWndExiting = FALSE; + } + break; + case WM_PH_DELAYED_LOAD_COMPLETED: + { + // Nothing + } + break; + case WM_PH_NOTIFY_ICON_MESSAGE: + { + PhNfForwardMessage(WParam, LParam); + } + break; + case WM_PH_TOGGLE_VISIBLE: + { + PhMwpActivateWindow(!WParam); + } + break; + case WM_PH_SHOW_MEMORY_EDITOR: + { + PPH_SHOW_MEMORY_EDITOR showMemoryEditor = (PPH_SHOW_MEMORY_EDITOR)LParam; + + PhShowMemoryEditorDialog( + showMemoryEditor->ProcessId, + showMemoryEditor->BaseAddress, + showMemoryEditor->RegionSize, + showMemoryEditor->SelectOffset, + showMemoryEditor->SelectLength, + showMemoryEditor->Title, + showMemoryEditor->Flags + ); + PhClearReference(&showMemoryEditor->Title); + PhFree(showMemoryEditor); + } + break; + case WM_PH_SHOW_MEMORY_RESULTS: + { + PPH_SHOW_MEMORY_RESULTS showMemoryResults = (PPH_SHOW_MEMORY_RESULTS)LParam; + + PhShowMemoryResultsDialog( + showMemoryResults->ProcessId, + showMemoryResults->Results + ); + PhDereferenceMemoryResults( + (PPH_MEMORY_RESULT *)showMemoryResults->Results->Items, + showMemoryResults->Results->Count + ); + PhDereferenceObject(showMemoryResults->Results); + PhFree(showMemoryResults); + } + break; + case WM_PH_SELECT_TAB_PAGE: + { + ULONG index = (ULONG)WParam; + + PhMwpSelectPage(index); + + if (CurrentPage->WindowHandle) + SetFocus(CurrentPage->WindowHandle); + } + break; + case WM_PH_GET_CALLBACK_LAYOUT_PADDING: + { + return (ULONG_PTR)&LayoutPaddingCallback; + } + break; + case WM_PH_INVALIDATE_LAYOUT_PADDING: + { + LayoutPaddingValid = FALSE; + } + break; + case WM_PH_SELECT_PROCESS_NODE: + { + PhSelectAndEnsureVisibleProcessNode((PPH_PROCESS_NODE)LParam); + } + break; + case WM_PH_SELECT_SERVICE_ITEM: + { + PPH_SERVICE_NODE serviceNode; + + PhMwpNeedServiceTreeList(); + + // For compatibility, LParam is a service item, not node. + if (serviceNode = PhFindServiceNode((PPH_SERVICE_ITEM)LParam)) + { + PhSelectAndEnsureVisibleServiceNode(serviceNode); + } + } + break; + case WM_PH_SELECT_NETWORK_ITEM: + { + PPH_NETWORK_NODE networkNode; + + PhMwpNeedNetworkTreeList(); + + // For compatibility, LParam is a network item, not node. + if (networkNode = PhFindNetworkNode((PPH_NETWORK_ITEM)LParam)) + { + PhSelectAndEnsureVisibleNetworkNode(networkNode); + } + } + break; + case WM_PH_UPDATE_FONT: + { + PPH_STRING fontHexString; + LOGFONT font; + + fontHexString = PhaGetStringSetting(L"Font"); + + if ( + fontHexString->Length / 2 / 2 == sizeof(LOGFONT) && + PhHexStringToBuffer(&fontHexString->sr, (PUCHAR)&font) + ) + { + HFONT newFont; + + newFont = CreateFontIndirect(&font); + + if (newFont) + { + if (CurrentCustomFont) + DeleteObject(CurrentCustomFont); + CurrentCustomFont = newFont; + + PhMwpNotifyAllPages(MainTabPageFontChanged, newFont, NULL); + } + } + } + break; + case WM_PH_GET_FONT: + return SendMessage(PhMwpProcessTreeNewHandle, WM_GETFONT, 0, 0); + case WM_PH_INVOKE: + { + VOID (NTAPI *function)(PVOID); + + function = (PVOID)LParam; + function((PVOID)WParam); + } + break; + case WM_PH_ADD_MENU_ITEM: + { + PPH_ADD_MENU_ITEM addMenuItem = (PPH_ADD_MENU_ITEM)LParam; + + return PhMwpLegacyAddPluginMenuItem(addMenuItem); + } + break; + case WM_PH_CREATE_TAB_PAGE: + { + return (ULONG_PTR)PhMwpCreatePage((PPH_MAIN_TAB_PAGE)LParam); + } + break; + case WM_PH_REFRESH: + { + SendMessage(PhMainWndHandle, WM_COMMAND, ID_VIEW_REFRESH, 0); + } + break; + case WM_PH_GET_UPDATE_AUTOMATICALLY: + { + return PhMwpUpdateAutomatically; + } + break; + case WM_PH_SET_UPDATE_AUTOMATICALLY: + { + if (!!WParam != PhMwpUpdateAutomatically) + { + SendMessage(PhMainWndHandle, WM_COMMAND, ID_VIEW_UPDATEAUTOMATICALLY, 0); + } + } + break; + case WM_PH_ICON_CLICK: + { + PhMwpActivateWindow(!!PhGetIntegerSetting(L"IconTogglesVisibility")); + } + break; + case WM_PH_PROCESS_ADDED: + { + ULONG runId = (ULONG)WParam; + PPH_PROCESS_ITEM processItem = (PPH_PROCESS_ITEM)LParam; + + PhMwpOnProcessAdded(processItem, runId); + } + break; + case WM_PH_PROCESS_MODIFIED: + { + PhMwpOnProcessModified((PPH_PROCESS_ITEM)LParam); + } + break; + case WM_PH_PROCESS_REMOVED: + { + PhMwpOnProcessRemoved((PPH_PROCESS_ITEM)LParam); + } + break; + case WM_PH_PROCESSES_UPDATED: + { + PhMwpOnProcessesUpdated(); + } + break; + case WM_PH_SERVICE_ADDED: + { + ULONG runId = (ULONG)WParam; + PPH_SERVICE_ITEM serviceItem = (PPH_SERVICE_ITEM)LParam; + + PhMwpOnServiceAdded(serviceItem, runId); + } + break; + case WM_PH_SERVICE_MODIFIED: + { + PPH_SERVICE_MODIFIED_DATA serviceModifiedData = (PPH_SERVICE_MODIFIED_DATA)LParam; + + PhMwpOnServiceModified(serviceModifiedData); + PhFree(serviceModifiedData); + } + break; + case WM_PH_SERVICE_REMOVED: + { + PhMwpOnServiceRemoved((PPH_SERVICE_ITEM)LParam); + } + break; + case WM_PH_SERVICES_UPDATED: + { + PhMwpOnServicesUpdated(); + } + break; + case WM_PH_NETWORK_ITEM_ADDED: + { + ULONG runId = (ULONG)WParam; + PPH_NETWORK_ITEM networkItem = (PPH_NETWORK_ITEM)LParam; + + PhMwpOnNetworkItemAdded(runId, networkItem); + } + break; + case WM_PH_NETWORK_ITEM_MODIFIED: + { + PhMwpOnNetworkItemModified((PPH_NETWORK_ITEM)LParam); + } + break; + case WM_PH_NETWORK_ITEM_REMOVED: + { + PhMwpOnNetworkItemRemoved((PPH_NETWORK_ITEM)LParam); + } + break; + case WM_PH_NETWORK_ITEMS_UPDATED: + { + PhMwpOnNetworkItemsUpdated(); + } + break; + } + + return 0; +} + +VOID NTAPI PhMwpNetworkItemAddedHandler( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + PPH_NETWORK_ITEM networkItem = (PPH_NETWORK_ITEM)Parameter; + + PhReferenceObject(networkItem); + PostMessage( + PhMainWndHandle, + WM_PH_NETWORK_ITEM_ADDED, + PhGetRunIdProvider(&PhMwpNetworkProviderRegistration), + (LPARAM)networkItem + ); +} + +VOID NTAPI PhMwpNetworkItemModifiedHandler( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + PPH_NETWORK_ITEM networkItem = (PPH_NETWORK_ITEM)Parameter; + + PostMessage(PhMainWndHandle, WM_PH_NETWORK_ITEM_MODIFIED, 0, (LPARAM)networkItem); +} + +VOID NTAPI PhMwpNetworkItemRemovedHandler( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + PPH_NETWORK_ITEM networkItem = (PPH_NETWORK_ITEM)Parameter; + + PostMessage(PhMainWndHandle, WM_PH_NETWORK_ITEM_REMOVED, 0, (LPARAM)networkItem); +} + +VOID NTAPI PhMwpNetworkItemsUpdatedHandler( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + PostMessage(PhMainWndHandle, WM_PH_NETWORK_ITEMS_UPDATED, 0, 0); +} + +VOID PhMwpLoadSettings( + VOID + ) +{ + ULONG opacity; + PPH_STRING customFont; + + if (PhGetIntegerSetting(L"MainWindowAlwaysOnTop")) + { + AlwaysOnTop = TRUE; + SetWindowPos(PhMainWndHandle, HWND_TOPMOST, 0, 0, 0, 0, + SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOREDRAW | SWP_NOSIZE); + } + + opacity = PhGetIntegerSetting(L"MainWindowOpacity"); + + if (opacity != 0) + PhSetWindowOpacity(PhMainWndHandle, opacity); + + PhStatisticsSampleCount = PhGetIntegerSetting(L"SampleCount"); + PhEnableProcessQueryStage2 = !!PhGetIntegerSetting(L"EnableStage2"); + PhEnablePurgeProcessRecords = !PhGetIntegerSetting(L"NoPurgeProcessRecords"); + PhEnableCycleCpuUsage = !!PhGetIntegerSetting(L"EnableCycleCpuUsage"); + PhEnableServiceNonPoll = !!PhGetIntegerSetting(L"EnableServiceNonPoll"); + PhEnableNetworkProviderResolve = !!PhGetIntegerSetting(L"EnableNetworkResolve"); + + PhNfLoadStage1(); + PhMwpNotifyIconNotifyMask = PhGetIntegerSetting(L"IconNotifyMask"); + + customFont = PhaGetStringSetting(L"Font"); + + if (customFont->Length / 2 / 2 == sizeof(LOGFONT)) + SendMessage(PhMainWndHandle, WM_PH_UPDATE_FONT, 0, 0); + + PhMwpNotifyAllPages(MainTabPageLoadSettings, NULL, NULL); +} + +VOID PhMwpSaveSettings( + VOID + ) +{ + PhMwpNotifyAllPages(MainTabPageSaveSettings, NULL, NULL); + + PhNfSaveSettings(); + PhSetIntegerSetting(L"IconNotifyMask", PhMwpNotifyIconNotifyMask); + + PhSaveWindowPlacementToSetting(L"MainWindowPosition", L"MainWindowSize", PhMainWndHandle); + PhMwpSaveWindowState(); + + if (PhSettingsFileName) + PhSaveSettings(PhSettingsFileName->Buffer); +} + +VOID PhMwpSaveWindowState( + VOID + ) +{ + WINDOWPLACEMENT placement = { sizeof(placement) }; + + GetWindowPlacement(PhMainWndHandle, &placement); + + if (placement.showCmd == SW_NORMAL) + PhSetIntegerSetting(L"MainWindowState", SW_NORMAL); + else if (placement.showCmd == SW_MAXIMIZE) + PhSetIntegerSetting(L"MainWindowState", SW_MAXIMIZE); +} + +VOID PhLoadDbgHelpFromPath( + _In_ PWSTR DbgHelpPath + ) +{ + HMODULE dbghelpModule; + + if (dbghelpModule = LoadLibrary(DbgHelpPath)) + { + PPH_STRING fullDbghelpPath; + ULONG indexOfFileName; + PH_STRINGREF dbghelpFolder; + PPH_STRING symsrvPath; + + fullDbghelpPath = PhGetDllFileName(dbghelpModule, &indexOfFileName); + + if (fullDbghelpPath) + { + if (indexOfFileName != 0) + { + static PH_STRINGREF symsrvString = PH_STRINGREF_INIT(L"\\symsrv.dll"); + + dbghelpFolder.Buffer = fullDbghelpPath->Buffer; + dbghelpFolder.Length = indexOfFileName * sizeof(WCHAR); + + symsrvPath = PhConcatStringRef2(&dbghelpFolder, &symsrvString); + LoadLibrary(symsrvPath->Buffer); + PhDereferenceObject(symsrvPath); + } + + PhDereferenceObject(fullDbghelpPath); + } + } + else + { + dbghelpModule = LoadLibrary(L"dbghelp.dll"); + } + + PhSymbolProviderCompleteInitialization(dbghelpModule); +} + +VOID PhMwpSymInitHandler( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + PPH_STRING dbghelpPath; + + dbghelpPath = PhGetStringSetting(L"DbgHelpPath"); + PhLoadDbgHelpFromPath(dbghelpPath->Buffer); + PhDereferenceObject(dbghelpPath); +} + +VOID PhMwpUpdateLayoutPadding( + VOID + ) +{ + PH_LAYOUT_PADDING_DATA data; + + memset(&data, 0, sizeof(PH_LAYOUT_PADDING_DATA)); + PhInvokeCallback(&LayoutPaddingCallback, &data); + + LayoutPadding = data.Padding; +} + +VOID PhMwpApplyLayoutPadding( + _Inout_ PRECT Rect, + _In_ PRECT Padding + ) +{ + Rect->left += Padding->left; + Rect->top += Padding->top; + Rect->right -= Padding->right; + Rect->bottom -= Padding->bottom; +} + +VOID PhMwpLayout( + _Inout_ HDWP *DeferHandle + ) +{ + RECT rect; + + // Resize the tab control. + // Don't defer the resize. The tab control doesn't repaint properly. + + if (!LayoutPaddingValid) + { + PhMwpUpdateLayoutPadding(); + LayoutPaddingValid = TRUE; + } + + GetClientRect(PhMainWndHandle, &rect); + PhMwpApplyLayoutPadding(&rect, &LayoutPadding); + + SetWindowPos(TabControlHandle, NULL, + rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, + SWP_NOACTIVATE | SWP_NOZORDER); + UpdateWindow(TabControlHandle); + + PhMwpLayoutTabControl(DeferHandle); +} + +VOID PhMwpSetupComputerMenu( + _In_ PPH_EMENU_ITEM Root + ) +{ + PPH_EMENU_ITEM menuItem; + + if (WindowsVersion < WINDOWS_8) + { + if (menuItem = PhFindEMenuItem(Root, PH_EMENU_FIND_DESCEND, NULL, ID_COMPUTER_RESTARTBOOTOPTIONS)) + PhDestroyEMenuItem(menuItem); + if (menuItem = PhFindEMenuItem(Root, PH_EMENU_FIND_DESCEND, NULL, ID_COMPUTER_SHUTDOWNHYBRID)) + PhDestroyEMenuItem(menuItem); + } +} + +BOOLEAN PhMwpExecuteComputerCommand( + _In_ ULONG Id + ) +{ + switch (Id) + { + case ID_COMPUTER_LOCK: + PhUiLockComputer(PhMainWndHandle); + return TRUE; + case ID_COMPUTER_LOGOFF: + PhUiLogoffComputer(PhMainWndHandle); + return TRUE; + case ID_COMPUTER_SLEEP: + PhUiSleepComputer(PhMainWndHandle); + return TRUE; + case ID_COMPUTER_HIBERNATE: + PhUiHibernateComputer(PhMainWndHandle); + return TRUE; + case ID_COMPUTER_RESTART: + PhUiRestartComputer(PhMainWndHandle, 0); + return TRUE; + case ID_COMPUTER_RESTARTBOOTOPTIONS: + PhUiRestartComputer(PhMainWndHandle, EWX_BOOTOPTIONS); + return TRUE; + case ID_COMPUTER_SHUTDOWN: + PhUiShutdownComputer(PhMainWndHandle, 0); + return TRUE; + case ID_COMPUTER_SHUTDOWNHYBRID: + PhUiShutdownComputer(PhMainWndHandle, EWX_HYBRID_SHUTDOWN); + return TRUE; + } + + return FALSE; +} + +VOID PhMwpActivateWindow( + _In_ BOOLEAN Toggle + ) +{ + if (IsIconic(PhMainWndHandle)) + { + ShowWindow(PhMainWndHandle, SW_RESTORE); + SetForegroundWindow(PhMainWndHandle); + } + else if (IsWindowVisible(PhMainWndHandle)) + { + if (Toggle) + ShowWindow(PhMainWndHandle, SW_HIDE); + else + SetForegroundWindow(PhMainWndHandle); + } + else + { + ShowWindow(PhMainWndHandle, SW_SHOW); + SetForegroundWindow(PhMainWndHandle); + } +} + +VOID PhMwpInitializeMainMenu( + _In_ HMENU Menu + ) +{ + MENUINFO menuInfo; + ULONG i; + + menuInfo.cbSize = sizeof(MENUINFO); + menuInfo.fMask = MIM_STYLE; + menuInfo.dwStyle = MNS_NOTIFYBYPOS; + SetMenuInfo(Menu, &menuInfo); + + for (i = 0; i < sizeof(SubMenuHandles) / sizeof(HMENU); i++) + { + SubMenuHandles[i] = GetSubMenu(PhMainWndMenuHandle, i); + } +} + +VOID PhMwpDispatchMenuCommand( + _In_ HMENU MenuHandle, + _In_ ULONG ItemIndex, + _In_ ULONG ItemId, + _In_ ULONG_PTR ItemData + ) +{ + switch (ItemId) + { + case ID_PLUGIN_MENU_ITEM: + { + PPH_EMENU_ITEM menuItem; + PH_PLUGIN_MENU_INFORMATION menuInfo; + + menuItem = (PPH_EMENU_ITEM)ItemData; + + if (menuItem) + { + PhPluginInitializeMenuInfo(&menuInfo, NULL, PhMainWndHandle, 0); + PhPluginTriggerEMenuItem(&menuInfo, menuItem); + } + + return; + } + break; + case ID_TRAYICONS_REGISTERED: + { + PPH_EMENU_ITEM menuItem; + + menuItem = (PPH_EMENU_ITEM)ItemData; + + if (menuItem) + { + PPH_NF_ICON icon; + + icon = menuItem->Context; + PhNfSetVisibleIcon(icon->IconId, !PhNfTestIconMask(icon->IconId)); + } + + return; + } + break; + case ID_USER_CONNECT: + case ID_USER_DISCONNECT: + case ID_USER_LOGOFF: + case ID_USER_REMOTECONTROL: + case ID_USER_SENDMESSAGE: + case ID_USER_PROPERTIES: + { + SelectedUserSessionId = (ULONG)ItemData; + } + break; + } + + SendMessage(PhMainWndHandle, WM_COMMAND, ItemId, 0); +} + +ULONG_PTR PhMwpLegacyAddPluginMenuItem( + _In_ PPH_ADD_MENU_ITEM AddMenuItem + ) +{ + PPH_ADD_MENU_ITEM addMenuItem; + PPH_PLUGIN_MENU_ITEM pluginMenuItem; + + if (!LegacyAddMenuItemList) + LegacyAddMenuItemList = PhCreateList(8); + + addMenuItem = PhAllocateCopy(AddMenuItem, sizeof(PH_ADD_MENU_ITEM)); + PhAddItemList(LegacyAddMenuItemList, addMenuItem); + + pluginMenuItem = PhAllocate(sizeof(PH_PLUGIN_MENU_ITEM)); + memset(pluginMenuItem, 0, sizeof(PH_PLUGIN_MENU_ITEM)); + pluginMenuItem->Plugin = AddMenuItem->Plugin; + pluginMenuItem->Id = AddMenuItem->Id; + pluginMenuItem->Context = AddMenuItem->Context; + + addMenuItem->Context = pluginMenuItem; + + return TRUE; +} + +HBITMAP PhMwpGetShieldBitmap( + VOID + ) +{ + static HBITMAP shieldBitmap = NULL; + + if (!shieldBitmap) + { + HICON shieldIcon; + + if (shieldIcon = PhLoadIcon(NULL, IDI_SHIELD, PH_LOAD_ICON_SIZE_SMALL | PH_LOAD_ICON_STRICT, 0, 0)) + { + shieldBitmap = PhIconToBitmap(shieldIcon, PhSmallIconSize.X, PhSmallIconSize.Y); + DestroyIcon(shieldIcon); + } + } + + return shieldBitmap; +} + +VOID PhMwpInitializeSubMenu( + _In_ PPH_EMENU Menu, + _In_ ULONG Index + ) +{ + PPH_EMENU_ITEM menuItem; + + if (Index == 0) // Hacker + { + // Fix some menu items. + if (PhGetOwnTokenAttributes().Elevated) + { + if (menuItem = PhFindEMenuItem(Menu, 0, NULL, ID_HACKER_RUNASADMINISTRATOR)) + PhDestroyEMenuItem(menuItem); + if (menuItem = PhFindEMenuItem(Menu, 0, NULL, ID_HACKER_SHOWDETAILSFORALLPROCESSES)) + PhDestroyEMenuItem(menuItem); + } + else + { + HBITMAP shieldBitmap; + + if (shieldBitmap = PhMwpGetShieldBitmap()) + { + if (menuItem = PhFindEMenuItem(Menu, 0, NULL, ID_HACKER_SHOWDETAILSFORALLPROCESSES)) + menuItem->Bitmap = shieldBitmap; + } + } + + // Fix up the Computer menu. + PhMwpSetupComputerMenu(Menu); + } + else if (Index == 1) // View + { + PPH_EMENU_ITEM trayIconsMenuItem; + ULONG i; + PPH_EMENU_ITEM menuItem; + ULONG id; + ULONG placeholderIndex; + + trayIconsMenuItem = PhMwpFindTrayIconsMenuItem(Menu); + + if (trayIconsMenuItem) + { + ULONG maximum; + PPH_NF_ICON icon; + + // Add menu items for the registered tray icons. + + id = PH_ICON_DEFAULT_MAXIMUM; + maximum = PhNfGetMaximumIconId(); + + for (; id != maximum; id <<= 1) + { + if (icon = PhNfGetIconById(id)) + { + PhInsertEMenuItem(trayIconsMenuItem, PhCreateEMenuItem(0, ID_TRAYICONS_REGISTERED, icon->Text, NULL, icon), -1); + } + } + + // Update the text and check marks on the menu items. + + for (i = 0; i < trayIconsMenuItem->Items->Count; i++) + { + menuItem = trayIconsMenuItem->Items->Items[i]; + + id = -1; + icon = NULL; + + switch (menuItem->Id) + { + case ID_TRAYICONS_CPUHISTORY: + id = PH_ICON_CPU_HISTORY; + break; + case ID_TRAYICONS_IOHISTORY: + id = PH_ICON_IO_HISTORY; + break; + case ID_TRAYICONS_COMMITHISTORY: + id = PH_ICON_COMMIT_HISTORY; + break; + case ID_TRAYICONS_PHYSICALMEMORYHISTORY: + id = PH_ICON_PHYSICAL_HISTORY; + break; + case ID_TRAYICONS_CPUUSAGE: + id = PH_ICON_CPU_USAGE; + break; + case ID_TRAYICONS_REGISTERED: + icon = menuItem->Context; + id = icon->IconId; + break; + } + + if (id != -1) + { + if (PhNfTestIconMask(id)) + menuItem->Flags |= PH_EMENU_CHECKED; + + if (icon && (icon->Flags & PH_NF_ICON_UNAVAILABLE)) + { + PPH_STRING newText; + + newText = PhaConcatStrings2(icon->Text, L" (Unavailable)"); + PhModifyEMenuItem(menuItem, PH_EMENU_MODIFY_TEXT, PH_EMENU_TEXT_OWNED, + PhAllocateCopy(newText->Buffer, newText->Length + sizeof(WCHAR)), NULL); + } + } + } + } + + if (menuItem = PhFindEMenuItemEx(Menu, 0, NULL, ID_VIEW_SECTIONPLACEHOLDER, NULL, &placeholderIndex)) + { + PhDestroyEMenuItem(menuItem); + PhMwpInitializeSectionMenuItems(Menu, placeholderIndex); + } + + if (AlwaysOnTop && (menuItem = PhFindEMenuItem(Menu, 0, NULL, ID_VIEW_ALWAYSONTOP))) + menuItem->Flags |= PH_EMENU_CHECKED; + + id = PH_OPACITY_TO_ID(PhGetIntegerSetting(L"MainWindowOpacity")); + + if (menuItem = PhFindEMenuItem(Menu, PH_EMENU_FIND_DESCEND, NULL, id)) + menuItem->Flags |= PH_EMENU_CHECKED | PH_EMENU_RADIOCHECK; + + switch (PhGetIntegerSetting(L"UpdateInterval")) + { + case 500: + id = ID_UPDATEINTERVAL_FAST; + break; + case 1000: + id = ID_UPDATEINTERVAL_NORMAL; + break; + case 2000: + id = ID_UPDATEINTERVAL_BELOWNORMAL; + break; + case 5000: + id = ID_UPDATEINTERVAL_SLOW; + break; + case 10000: + id = ID_UPDATEINTERVAL_VERYSLOW; + break; + default: + id = -1; + break; + } + + if (id != -1 && (menuItem = PhFindEMenuItem(Menu, PH_EMENU_FIND_DESCEND, NULL, id))) + menuItem->Flags |= PH_EMENU_CHECKED | PH_EMENU_RADIOCHECK; + + if (PhMwpUpdateAutomatically && (menuItem = PhFindEMenuItem(Menu, 0, NULL, ID_VIEW_UPDATEAUTOMATICALLY))) + menuItem->Flags |= PH_EMENU_CHECKED; + } + else if (Index == 2) // Tools + { +#ifdef _WIN64 + if (menuItem = PhFindEMenuItem(Menu, 0, NULL, ID_TOOLS_HIDDENPROCESSES)) + PhDestroyEMenuItem(menuItem); +#endif + + // Windows 8 Task Manager requires elevation. + if (WindowsVersion >= WINDOWS_8 && !PhGetOwnTokenAttributes().Elevated) + { + HBITMAP shieldBitmap; + + if (shieldBitmap = PhMwpGetShieldBitmap()) + { + if (menuItem = PhFindEMenuItem(Menu, 0, NULL, ID_TOOLS_STARTTASKMANAGER)) + menuItem->Bitmap = shieldBitmap; + } + } + } + + if (LegacyAddMenuItemList) + { + ULONG i; + PPH_ADD_MENU_ITEM addMenuItem; + + for (i = 0; i < LegacyAddMenuItemList->Count; i++) + { + addMenuItem = LegacyAddMenuItemList->Items[i]; + + if (addMenuItem->Location == Index) + { + ULONG insertIndex; + + if (addMenuItem->InsertAfter) + { + for (insertIndex = 0; insertIndex < Menu->Items->Count; insertIndex++) + { + menuItem = Menu->Items->Items[insertIndex]; + + if (!(menuItem->Flags & PH_EMENU_SEPARATOR) && (PhCompareUnicodeStringZIgnoreMenuPrefix( + addMenuItem->InsertAfter, + menuItem->Text, + TRUE, + TRUE + ) == 0)) + { + insertIndex++; + break; + } + } + } + else + { + insertIndex = 0; + } + + if (addMenuItem->Text[0] == '-' && addMenuItem->Text[1] == 0) + PhInsertEMenuItem(Menu, PhCreateEMenuItem(PH_EMENU_SEPARATOR, 0, L"", NULL, NULL), insertIndex); + else + PhInsertEMenuItem(Menu, PhCreateEMenuItem(0, ID_PLUGIN_MENU_ITEM, addMenuItem->Text, NULL, addMenuItem->Context), insertIndex); + } + } + } +} + +PPH_EMENU_ITEM PhMwpFindTrayIconsMenuItem( + _In_ PPH_EMENU Menu + ) +{ + ULONG i; + PPH_EMENU_ITEM menuItem; + + for (i = 0; i < Menu->Items->Count; i++) + { + menuItem = Menu->Items->Items[i]; + + if (PhFindEMenuItem(menuItem, 0, NULL, ID_TRAYICONS_CPUHISTORY)) + return menuItem; + } + + return NULL; +} + +VOID PhMwpInitializeSectionMenuItems( + _In_ PPH_EMENU Menu, + _In_ ULONG StartIndex + ) +{ + if (CurrentPage) + { + PH_MAIN_TAB_PAGE_MENU_INFORMATION menuInfo; + + menuInfo.Menu = Menu; + menuInfo.StartIndex = StartIndex; + + if (!CurrentPage->Callback(CurrentPage, MainTabPageInitializeSectionMenuItems, &menuInfo, NULL)) + { + // Remove the extra separator. + PhRemoveEMenuItem(Menu, NULL, StartIndex); + } + } +} + +VOID PhMwpLayoutTabControl( + _Inout_ HDWP *DeferHandle + ) +{ + RECT rect; + + if (!LayoutPaddingValid) + { + PhMwpUpdateLayoutPadding(); + LayoutPaddingValid = TRUE; + } + + GetClientRect(PhMainWndHandle, &rect); + PhMwpApplyLayoutPadding(&rect, &LayoutPadding); + TabCtrl_AdjustRect(TabControlHandle, FALSE, &rect); + + if (CurrentPage && CurrentPage->WindowHandle) + { + *DeferHandle = DeferWindowPos(*DeferHandle, CurrentPage->WindowHandle, NULL, + rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, + SWP_NOACTIVATE | SWP_NOZORDER); + } +} + +VOID PhMwpNotifyTabControl( + _In_ NMHDR *Header + ) +{ + if (Header->code == TCN_SELCHANGING) + { + OldTabIndex = TabCtrl_GetCurSel(TabControlHandle); + } + else if (Header->code == TCN_SELCHANGE) + { + PhMwpSelectionChangedTabControl(OldTabIndex); + } +} + +VOID PhMwpSelectionChangedTabControl( + _In_ ULONG OldIndex + ) +{ + ULONG selectedIndex; + HDWP deferHandle; + ULONG i; + + selectedIndex = TabCtrl_GetCurSel(TabControlHandle); + + if (selectedIndex == OldIndex) + return; + + deferHandle = BeginDeferWindowPos(3); + + for (i = 0; i < PageList->Count; i++) + { + PPH_MAIN_TAB_PAGE page = PageList->Items[i]; + + page->Selected = page->Index == selectedIndex; + + if (page->Index == selectedIndex) + { + CurrentPage = page; + + // Create the tab page window if it doesn't exist. + if (!page->WindowHandle && !page->CreateWindowCalled) + { + if (page->Callback(page, MainTabPageCreateWindow, &page->WindowHandle, NULL)) + page->CreateWindowCalled = TRUE; + + if (page->WindowHandle) + BringWindowToTop(page->WindowHandle); + if (CurrentCustomFont) + page->Callback(page, MainTabPageFontChanged, CurrentCustomFont, NULL); + } + + page->Callback(page, MainTabPageSelected, (PVOID)TRUE, NULL); + + if (page->WindowHandle) + { + deferHandle = DeferWindowPos(deferHandle, page->WindowHandle, NULL, 0, 0, 0, 0, SWP_SHOWWINDOW_ONLY); + SetFocus(page->WindowHandle); + } + } + else if (page->Index == OldIndex) + { + page->Callback(page, MainTabPageSelected, (PVOID)FALSE, NULL); + + if (page->WindowHandle) + { + deferHandle = DeferWindowPos(deferHandle, page->WindowHandle, NULL, 0, 0, 0, 0, SWP_HIDEWINDOW_ONLY); + } + } + } + + PhMwpLayoutTabControl(&deferHandle); + + EndDeferWindowPos(deferHandle); + + if (PhPluginsEnabled) + PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackMainWindowTabChanged), IntToPtr(selectedIndex)); +} + +PPH_MAIN_TAB_PAGE PhMwpCreatePage( + _In_ PPH_MAIN_TAB_PAGE Template + ) +{ + PPH_MAIN_TAB_PAGE page; + PPH_STRING name; + HDWP deferHandle; + + page = PhAllocate(sizeof(PH_MAIN_TAB_PAGE)); + memset(page, 0, sizeof(PH_MAIN_TAB_PAGE)); + + page->Name = Template->Name; + page->Flags = Template->Flags; + page->Callback = Template->Callback; + page->Context = Template->Context; + + PhAddItemList(PageList, page); + + name = PhCreateString2(&page->Name); + page->Index = PhAddTabControlTab(TabControlHandle, MAXINT, name->Buffer); + PhDereferenceObject(name); + + page->Callback(page, MainTabPageCreate, NULL, NULL); + + // The tab control might need multiple lines, so we need to refresh the layout. + deferHandle = BeginDeferWindowPos(1); + PhMwpLayoutTabControl(&deferHandle); + EndDeferWindowPos(deferHandle); + + return page; +} + +VOID PhMwpSelectPage( + _In_ ULONG Index + ) +{ + INT oldIndex; + + oldIndex = TabCtrl_GetCurSel(TabControlHandle); + TabCtrl_SetCurSel(TabControlHandle, Index); + PhMwpSelectionChangedTabControl(oldIndex); +} + +PPH_MAIN_TAB_PAGE PhMwpFindPage( + _In_ PPH_STRINGREF Name + ) +{ + ULONG i; + + for (i = 0; i < PageList->Count; i++) + { + PPH_MAIN_TAB_PAGE page = PageList->Items[i]; + + if (PhEqualStringRef(&page->Name, Name, TRUE)) + return page; + } + + return NULL; +} + +PPH_MAIN_TAB_PAGE PhMwpCreateInternalPage( + _In_ PWSTR Name, + _In_ ULONG Flags, + _In_ PPH_MAIN_TAB_PAGE_CALLBACK Callback + ) +{ + PH_MAIN_TAB_PAGE page; + + memset(&page, 0, sizeof(PH_MAIN_TAB_PAGE)); + PhInitializeStringRef(&page.Name, Name); + page.Flags = Flags; + page.Callback = Callback; + + return PhMwpCreatePage(&page); +} + +VOID PhMwpNotifyAllPages( + _In_ PH_MAIN_TAB_PAGE_MESSAGE Message, + _In_opt_ PVOID Parameter1, + _In_opt_ PVOID Parameter2 + ) +{ + ULONG i; + PPH_MAIN_TAB_PAGE page; + + for (i = 0; i < PageList->Count; i++) + { + page = PageList->Items[i]; + page->Callback(page, Message, Parameter1, Parameter2); + } +} + +static int __cdecl IconProcessesCpuUsageCompare( + _In_ const void *elem1, + _In_ const void *elem2 + ) +{ + PPH_PROCESS_ITEM processItem1 = *(PPH_PROCESS_ITEM *)elem1; + PPH_PROCESS_ITEM processItem2 = *(PPH_PROCESS_ITEM *)elem2; + + return -singlecmp(processItem1->CpuUsage, processItem2->CpuUsage); +} + +static int __cdecl IconProcessesNameCompare( + _In_ const void *elem1, + _In_ const void *elem2 + ) +{ + PPH_PROCESS_ITEM processItem1 = *(PPH_PROCESS_ITEM *)elem1; + PPH_PROCESS_ITEM processItem2 = *(PPH_PROCESS_ITEM *)elem2; + + return PhCompareString(processItem1->ProcessName, processItem2->ProcessName, TRUE); +} + +VOID PhAddMiniProcessMenuItems( + _Inout_ struct _PH_EMENU_ITEM *Menu, + _In_ HANDLE ProcessId + ) +{ + PPH_EMENU_ITEM priorityMenu; + PPH_EMENU_ITEM ioPriorityMenu = NULL; + PPH_PROCESS_ITEM processItem; + BOOLEAN isSuspended = FALSE; + BOOLEAN isPartiallySuspended = TRUE; + + // Priority + + priorityMenu = PhCreateEMenuItem(0, 0, L"Priority", NULL, ProcessId); + + PhInsertEMenuItem(priorityMenu, PhCreateEMenuItem(0, ID_PRIORITY_REALTIME, L"Real time", NULL, ProcessId), -1); + PhInsertEMenuItem(priorityMenu, PhCreateEMenuItem(0, ID_PRIORITY_HIGH, L"High", NULL, ProcessId), -1); + PhInsertEMenuItem(priorityMenu, PhCreateEMenuItem(0, ID_PRIORITY_ABOVENORMAL, L"Above normal", NULL, ProcessId), -1); + PhInsertEMenuItem(priorityMenu, PhCreateEMenuItem(0, ID_PRIORITY_NORMAL, L"Normal", NULL, ProcessId), -1); + PhInsertEMenuItem(priorityMenu, PhCreateEMenuItem(0, ID_PRIORITY_BELOWNORMAL, L"Below normal", NULL, ProcessId), -1); + PhInsertEMenuItem(priorityMenu, PhCreateEMenuItem(0, ID_PRIORITY_IDLE, L"Idle", NULL, ProcessId), -1); + + // I/O priority + + if (WindowsVersion >= WINDOWS_VISTA) + { + ioPriorityMenu = PhCreateEMenuItem(0, 0, L"I/O priority", NULL, ProcessId); + + PhInsertEMenuItem(ioPriorityMenu, PhCreateEMenuItem(0, ID_IOPRIORITY_HIGH, L"High", NULL, ProcessId), -1); + PhInsertEMenuItem(ioPriorityMenu, PhCreateEMenuItem(0, ID_IOPRIORITY_NORMAL, L"Normal", NULL, ProcessId), -1); + PhInsertEMenuItem(ioPriorityMenu, PhCreateEMenuItem(0, ID_IOPRIORITY_LOW, L"Low", NULL, ProcessId), -1); + PhInsertEMenuItem(ioPriorityMenu, PhCreateEMenuItem(0, ID_IOPRIORITY_VERYLOW, L"Very low", NULL, ProcessId), -1); + } + + // Menu + + PhInsertEMenuItem(Menu, PhCreateEMenuItem(0, ID_PROCESS_TERMINATE, L"T&erminate", NULL, ProcessId), -1); + + if (processItem = PhReferenceProcessItem(ProcessId)) + { + isSuspended = (BOOLEAN)processItem->IsSuspended; + isPartiallySuspended = (BOOLEAN)processItem->IsPartiallySuspended; + PhDereferenceObject(processItem); + } + + if (!isSuspended) + PhInsertEMenuItem(Menu, PhCreateEMenuItem(0, ID_PROCESS_SUSPEND, L"&Suspend", NULL, ProcessId), -1); + if (isPartiallySuspended) + PhInsertEMenuItem(Menu, PhCreateEMenuItem(0, ID_PROCESS_RESUME, L"Res&ume", NULL, ProcessId), -1); + + PhInsertEMenuItem(Menu, priorityMenu, -1); + + if (ioPriorityMenu) + PhInsertEMenuItem(Menu, ioPriorityMenu, -1); + + PhMwpSetProcessMenuPriorityChecks(Menu, ProcessId, TRUE, TRUE, FALSE); + + PhInsertEMenuItem(Menu, PhCreateEMenuItem(0, ID_PROCESS_PROPERTIES, L"P&roperties", NULL, ProcessId), -1); +} + +BOOLEAN PhHandleMiniProcessMenuItem( + _Inout_ struct _PH_EMENU_ITEM *MenuItem + ) +{ + switch (MenuItem->Id) + { + case ID_PROCESS_TERMINATE: + case ID_PROCESS_SUSPEND: + case ID_PROCESS_RESUME: + case ID_PROCESS_PROPERTIES: + { + HANDLE processId = MenuItem->Context; + PPH_PROCESS_ITEM processItem; + + if (processItem = PhReferenceProcessItem(processId)) + { + switch (MenuItem->Id) + { + case ID_PROCESS_TERMINATE: + PhUiTerminateProcesses(PhMainWndHandle, &processItem, 1); + break; + case ID_PROCESS_SUSPEND: + PhUiSuspendProcesses(PhMainWndHandle, &processItem, 1); + break; + case ID_PROCESS_RESUME: + PhUiResumeProcesses(PhMainWndHandle, &processItem, 1); + break; + case ID_PROCESS_PROPERTIES: + ProcessHacker_ShowProcessProperties(PhMainWndHandle, processItem); + break; + } + + PhDereferenceObject(processItem); + } + else + { + PhShowError(PhMainWndHandle, L"The process does not exist."); + } + } + break; + case ID_PRIORITY_REALTIME: + case ID_PRIORITY_HIGH: + case ID_PRIORITY_ABOVENORMAL: + case ID_PRIORITY_NORMAL: + case ID_PRIORITY_BELOWNORMAL: + case ID_PRIORITY_IDLE: + { + HANDLE processId = MenuItem->Context; + PPH_PROCESS_ITEM processItem; + + if (processItem = PhReferenceProcessItem(processId)) + { + PhMwpExecuteProcessPriorityCommand(MenuItem->Id, &processItem, 1); + PhDereferenceObject(processItem); + } + else + { + PhShowError(PhMainWndHandle, L"The process does not exist."); + } + } + break; + case ID_IOPRIORITY_HIGH: + case ID_IOPRIORITY_NORMAL: + case ID_IOPRIORITY_LOW: + case ID_IOPRIORITY_VERYLOW: + { + HANDLE processId = MenuItem->Context; + PPH_PROCESS_ITEM processItem; + + if (processItem = PhReferenceProcessItem(processId)) + { + PhMwpExecuteProcessIoPriorityCommand(MenuItem->Id, &processItem, 1); + PhDereferenceObject(processItem); + } + else + { + PhShowError(PhMainWndHandle, L"The process does not exist."); + } + } + break; + } + + return FALSE; +} + +VOID PhMwpAddIconProcesses( + _In_ PPH_EMENU_ITEM Menu, + _In_ ULONG NumberOfProcesses + ) +{ + ULONG i; + PPH_PROCESS_ITEM *processItems; + ULONG numberOfProcessItems; + PPH_LIST processList; + PPH_PROCESS_ITEM processItem; + + PhEnumProcessItems(&processItems, &numberOfProcessItems); + processList = PhCreateList(numberOfProcessItems); + PhAddItemsList(processList, processItems, numberOfProcessItems); + + // Remove non-real processes. + for (i = 0; i < processList->Count; i++) + { + processItem = processList->Items[i]; + + if (!PH_IS_REAL_PROCESS_ID(processItem->ProcessId)) + { + PhRemoveItemList(processList, i); + i--; + } + } + + // Remove processes with zero CPU usage and those running as other users. + for (i = 0; i < processList->Count && processList->Count > NumberOfProcesses; i++) + { + processItem = processList->Items[i]; + + if ( + processItem->CpuUsage == 0 || + !processItem->UserName || + (PhCurrentUserName && !PhEqualString(processItem->UserName, PhCurrentUserName, TRUE)) + ) + { + PhRemoveItemList(processList, i); + i--; + } + } + + // Sort the processes by CPU usage and remove the extra processes at the end of the list. + qsort(processList->Items, processList->Count, sizeof(PVOID), IconProcessesCpuUsageCompare); + + if (processList->Count > NumberOfProcesses) + { + PhRemoveItemsList(processList, NumberOfProcesses, processList->Count - NumberOfProcesses); + } + + // Lastly, sort by name. + qsort(processList->Items, processList->Count, sizeof(PVOID), IconProcessesNameCompare); + + // Delete all menu items. + PhRemoveAllEMenuItems(Menu); + + // Add the processes. + + for (i = 0; i < processList->Count; i++) + { + PPH_EMENU_ITEM subMenu; + HBITMAP iconBitmap; + CLIENT_ID clientId; + PPH_STRING clientIdName; + PPH_STRING escapedName; + + processItem = processList->Items[i]; + + // Process + + clientId.UniqueProcess = processItem->ProcessId; + clientId.UniqueThread = NULL; + + clientIdName = PH_AUTO(PhGetClientIdName(&clientId)); + escapedName = PH_AUTO(PhEscapeStringForMenuPrefix(&clientIdName->sr)); + + subMenu = PhCreateEMenuItem( + 0, + 0, + escapedName->Buffer, + NULL, + processItem->ProcessId + ); + + if (processItem->SmallIcon) + { + iconBitmap = PhIconToBitmap(processItem->SmallIcon, PhSmallIconSize.X, PhSmallIconSize.Y); + } + else + { + HICON icon; + + PhGetStockApplicationIcon(&icon, NULL); + iconBitmap = PhIconToBitmap(icon, PhSmallIconSize.X, PhSmallIconSize.Y); + } + + subMenu->Bitmap = iconBitmap; + subMenu->Flags |= PH_EMENU_BITMAP_OWNED; // automatically destroy the bitmap when necessary + + PhAddMiniProcessMenuItems(subMenu, processItem->ProcessId); + PhInsertEMenuItem(Menu, subMenu, -1); + } + + PhDereferenceObject(processList); + PhDereferenceObjects(processItems, numberOfProcessItems); + PhFree(processItems); +} + +VOID PhShowIconContextMenu( + _In_ POINT Location + ) +{ + PPH_EMENU menu; + PPH_EMENU_ITEM item; + PH_PLUGIN_MENU_INFORMATION menuInfo; + ULONG numberOfProcesses; + ULONG id; + ULONG i; + + // This function seems to be called recursively under some circumstances. + // To reproduce: + // 1. Hold right mouse button on tray icon, then left click. + // 2. Make the menu disappear by clicking on the menu then clicking somewhere else. + // So, don't store any global state or bad things will happen. + + menu = PhCreateEMenu(); + PhLoadResourceEMenuItem(menu, PhInstanceHandle, MAKEINTRESOURCE(IDR_ICON), 0); + + // Check the Notifications menu items. + for (i = PH_NOTIFY_MINIMUM; i != PH_NOTIFY_MAXIMUM; i <<= 1) + { + if (PhMwpNotifyIconNotifyMask & i) + { + switch (i) + { + case PH_NOTIFY_PROCESS_CREATE: + id = ID_NOTIFICATIONS_NEWPROCESSES; + break; + case PH_NOTIFY_PROCESS_DELETE: + id = ID_NOTIFICATIONS_TERMINATEDPROCESSES; + break; + case PH_NOTIFY_SERVICE_CREATE: + id = ID_NOTIFICATIONS_NEWSERVICES; + break; + case PH_NOTIFY_SERVICE_DELETE: + id = ID_NOTIFICATIONS_DELETEDSERVICES; + break; + case PH_NOTIFY_SERVICE_START: + id = ID_NOTIFICATIONS_STARTEDSERVICES; + break; + case PH_NOTIFY_SERVICE_STOP: + id = ID_NOTIFICATIONS_STOPPEDSERVICES; + break; + } + + PhSetFlagsEMenuItem(menu, id, PH_EMENU_CHECKED, PH_EMENU_CHECKED); + } + } + + // Add processes to the menu. + + numberOfProcesses = PhGetIntegerSetting(L"IconProcesses"); + item = PhFindEMenuItem(menu, 0, L"Processes", 0); + + if (item) + PhMwpAddIconProcesses(item, numberOfProcesses); + + // Fix up the Computer menu. + PhMwpSetupComputerMenu(menu); + + // Give plugins a chance to modify the menu. + + if (PhPluginsEnabled) + { + PhPluginInitializeMenuInfo(&menuInfo, menu, PhMainWndHandle, 0); + PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackIconMenuInitializing), &menuInfo); + } + + SetForegroundWindow(PhMainWndHandle); // window must be foregrounded so menu will disappear properly + item = PhShowEMenu( + menu, + PhMainWndHandle, + PH_EMENU_SHOW_LEFTRIGHT, + PH_ALIGN_LEFT | PH_ALIGN_TOP, + Location.x, + Location.y + ); + + if (item) + { + BOOLEAN handled = FALSE; + + if (PhPluginsEnabled && !handled) + handled = PhPluginTriggerEMenuItem(&menuInfo, item); + + if (!handled) + handled = PhHandleMiniProcessMenuItem(item); + + if (!handled) + handled = PhMwpExecuteComputerCommand(item->Id); + + if (!handled) + { + switch (item->Id) + { + case ID_ICON_SHOWHIDEPROCESSHACKER: + SendMessage(PhMainWndHandle, WM_PH_TOGGLE_VISIBLE, 0, 0); + break; + case ID_ICON_SYSTEMINFORMATION: + SendMessage(PhMainWndHandle, WM_COMMAND, ID_VIEW_SYSTEMINFORMATION, 0); + break; + case ID_NOTIFICATIONS_ENABLEALL: + PhMwpNotifyIconNotifyMask |= PH_NOTIFY_VALID_MASK; + break; + case ID_NOTIFICATIONS_DISABLEALL: + PhMwpNotifyIconNotifyMask &= ~PH_NOTIFY_VALID_MASK; + break; + case ID_NOTIFICATIONS_NEWPROCESSES: + case ID_NOTIFICATIONS_TERMINATEDPROCESSES: + case ID_NOTIFICATIONS_NEWSERVICES: + case ID_NOTIFICATIONS_STARTEDSERVICES: + case ID_NOTIFICATIONS_STOPPEDSERVICES: + case ID_NOTIFICATIONS_DELETEDSERVICES: + { + ULONG bit; + + switch (item->Id) + { + case ID_NOTIFICATIONS_NEWPROCESSES: + bit = PH_NOTIFY_PROCESS_CREATE; + break; + case ID_NOTIFICATIONS_TERMINATEDPROCESSES: + bit = PH_NOTIFY_PROCESS_DELETE; + break; + case ID_NOTIFICATIONS_NEWSERVICES: + bit = PH_NOTIFY_SERVICE_CREATE; + break; + case ID_NOTIFICATIONS_STARTEDSERVICES: + bit = PH_NOTIFY_SERVICE_START; + break; + case ID_NOTIFICATIONS_STOPPEDSERVICES: + bit = PH_NOTIFY_SERVICE_STOP; + break; + case ID_NOTIFICATIONS_DELETEDSERVICES: + bit = PH_NOTIFY_SERVICE_DELETE; + break; + } + + PhMwpNotifyIconNotifyMask ^= bit; + } + break; + case ID_ICON_EXIT: + SendMessage(PhMainWndHandle, WM_COMMAND, ID_HACKER_EXIT, 0); + break; + } + } + } + + PhDestroyEMenu(menu); +} + +VOID PhShowIconNotification( + _In_ PWSTR Title, + _In_ PWSTR Text, + _In_ ULONG Flags + ) +{ + PhNfShowBalloonTip(0, Title, Text, 10, Flags); +} + +VOID PhShowDetailsForIconNotification( + VOID + ) +{ + switch (PhMwpLastNotificationType) + { + case PH_NOTIFY_PROCESS_CREATE: + { + PPH_PROCESS_NODE processNode; + + if (processNode = PhFindProcessNode(PhMwpLastNotificationDetails.ProcessId)) + { + ProcessHacker_SelectTabPage(PhMainWndHandle, PhMwpProcessesPage->Index); + ProcessHacker_SelectProcessNode(PhMainWndHandle, processNode); + ProcessHacker_ToggleVisible(PhMainWndHandle, TRUE); + } + } + break; + case PH_NOTIFY_SERVICE_CREATE: + case PH_NOTIFY_SERVICE_START: + case PH_NOTIFY_SERVICE_STOP: + { + PPH_SERVICE_ITEM serviceItem; + + if (PhMwpLastNotificationDetails.ServiceName && + (serviceItem = PhReferenceServiceItem(PhMwpLastNotificationDetails.ServiceName->Buffer))) + { + ProcessHacker_SelectTabPage(PhMainWndHandle, PhMwpServicesPage->Index); + ProcessHacker_SelectServiceItem(PhMainWndHandle, serviceItem); + ProcessHacker_ToggleVisible(PhMainWndHandle, TRUE); + + PhDereferenceObject(serviceItem); + } + } + break; + } +} + +VOID PhMwpClearLastNotificationDetails( + VOID + ) +{ + if (PhMwpLastNotificationType & + (PH_NOTIFY_SERVICE_CREATE | PH_NOTIFY_SERVICE_DELETE | PH_NOTIFY_SERVICE_START | PH_NOTIFY_SERVICE_STOP)) + { + PhClearReference(&PhMwpLastNotificationDetails.ServiceName); + } + + PhMwpLastNotificationType = 0; + memset(&PhMwpLastNotificationDetails, 0, sizeof(PhMwpLastNotificationDetails)); +} + +BOOLEAN PhMwpPluginNotifyEvent( + _In_ ULONG Type, + _In_ PVOID Parameter + ) +{ + PH_PLUGIN_NOTIFY_EVENT notifyEvent; + + notifyEvent.Type = Type; + notifyEvent.Handled = FALSE; + notifyEvent.Parameter = Parameter; + + PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackNotifyEvent), ¬ifyEvent); + + return notifyEvent.Handled; +} + +VOID PhMwpUpdateUsersMenu( + VOID + ) +{ + HMENU menu; + PSESSIONIDW sessions; + ULONG numberOfSessions; + ULONG i; + ULONG j; + MENUITEMINFO menuItemInfo = { sizeof(MENUITEMINFO) }; + + menu = SubMenuHandles[3]; + + // Delete all items in the Users menu. + while (DeleteMenu(menu, 0, MF_BYPOSITION)) ; + + if (WinStationEnumerateW(NULL, &sessions, &numberOfSessions)) + { + for (i = 0; i < numberOfSessions; i++) + { + HMENU userMenu; + PPH_STRING menuText; + PPH_STRING escapedMenuText; + WINSTATIONINFORMATION winStationInfo; + ULONG returnLength; + ULONG numberOfItems; + + if (!WinStationQueryInformationW( + NULL, + sessions[i].SessionId, + WinStationInformation, + &winStationInfo, + sizeof(WINSTATIONINFORMATION), + &returnLength + )) + { + winStationInfo.Domain[0] = 0; + winStationInfo.UserName[0] = 0; + } + + if (winStationInfo.Domain[0] == 0 || winStationInfo.UserName[0] == 0) + { + // Probably the Services or RDP-Tcp session. + continue; + } + + menuText = PhFormatString( + L"%u: %s\\%s", + sessions[i].SessionId, + winStationInfo.Domain, + winStationInfo.UserName + ); + escapedMenuText = PhEscapeStringForMenuPrefix(&menuText->sr); + PhDereferenceObject(menuText); + + userMenu = GetSubMenu(LoadMenu(PhInstanceHandle, MAKEINTRESOURCE(IDR_USER)), 0); + AppendMenu( + menu, + MF_STRING | MF_POPUP, + (UINT_PTR)userMenu, + escapedMenuText->Buffer + ); + + PhDereferenceObject(escapedMenuText); + + menuItemInfo.fMask = MIIM_DATA; + menuItemInfo.dwItemData = sessions[i].SessionId; + + numberOfItems = GetMenuItemCount(userMenu); + + if (numberOfItems != -1) + { + for (j = 0; j < numberOfItems; j++) + SetMenuItemInfo(userMenu, j, TRUE, &menuItemInfo); + } + } + + WinStationFreeMemory(sessions); + } + + DrawMenuBar(PhMainWndHandle); +} diff --git a/ProcessHacker/mdump.c b/ProcessHacker/mdump.c index 25fa6284c8e6..92e88db305eb 100644 --- a/ProcessHacker/mdump.c +++ b/ProcessHacker/mdump.c @@ -1,466 +1,466 @@ -/* - * Process Hacker - - * minidump writer - * - * Copyright (C) 2010-2015 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include - -#include - -#include - -#include -#include -#include -#include - -#define WM_PH_MINIDUMP_STATUS_UPDATE (WM_APP + 301) - -#define PH_MINIDUMP_STATUS_UPDATE 1 -#define PH_MINIDUMP_COMPLETED 2 -#define PH_MINIDUMP_ERROR 3 - -typedef struct _PROCESS_MINIDUMP_CONTEXT -{ - HANDLE ProcessId; - PWSTR FileName; - MINIDUMP_TYPE DumpType; - BOOLEAN IsWow64; - - HANDLE ProcessHandle; - HANDLE FileHandle; - - HWND WindowHandle; - HANDLE ThreadHandle; - BOOLEAN Stop; - BOOLEAN Succeeded; - - ULONG LastTickCount; -} PROCESS_MINIDUMP_CONTEXT, *PPROCESS_MINIDUMP_CONTEXT; - -BOOLEAN PhpCreateProcessMiniDumpWithProgress( - _In_ HWND hWnd, - _In_ HANDLE ProcessId, - _In_ PWSTR FileName, - _In_ MINIDUMP_TYPE DumpType - ); - -INT_PTR CALLBACK PhpProcessMiniDumpDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -BOOLEAN PhUiCreateDumpFileProcess( - _In_ HWND hWnd, - _In_ PPH_PROCESS_ITEM Process - ) -{ - static PH_FILETYPE_FILTER filters[] = - { - { L"Dump files (*.dmp)", L"*.dmp" }, - { L"All files (*.*)", L"*.*" } - }; - PVOID fileDialog; - PPH_STRING fileName; - - fileDialog = PhCreateSaveFileDialog(); - PhSetFileDialogFilter(fileDialog, filters, sizeof(filters) / sizeof(PH_FILETYPE_FILTER)); - PhSetFileDialogFileName(fileDialog, PhaConcatStrings2(Process->ProcessName->Buffer, L".dmp")->Buffer); - - if (!PhShowFileDialog(hWnd, fileDialog)) - { - PhFreeFileDialog(fileDialog); - return FALSE; - } - - fileName = PH_AUTO(PhGetFileDialogFileName(fileDialog)); - PhFreeFileDialog(fileDialog); - - return PhpCreateProcessMiniDumpWithProgress( - hWnd, - Process->ProcessId, - fileName->Buffer, - // task manager uses these flags - MiniDumpWithFullMemory | - MiniDumpWithHandleData | - MiniDumpWithUnloadedModules | - MiniDumpWithFullMemoryInfo | - MiniDumpWithThreadInfo - ); -} - -BOOLEAN PhpCreateProcessMiniDumpWithProgress( - _In_ HWND hWnd, - _In_ HANDLE ProcessId, - _In_ PWSTR FileName, - _In_ MINIDUMP_TYPE DumpType - ) -{ - NTSTATUS status; - PROCESS_MINIDUMP_CONTEXT context; - - memset(&context, 0, sizeof(PROCESS_MINIDUMP_CONTEXT)); - context.ProcessId = ProcessId; - context.FileName = FileName; - context.DumpType = DumpType; - - if (!NT_SUCCESS(status = PhOpenProcess( - &context.ProcessHandle, - PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, - ProcessId - ))) - { - PhShowStatus(hWnd, L"Unable to open the process", status, 0); - return FALSE; - } - -#ifdef _WIN64 - PhGetProcessIsWow64(context.ProcessHandle, &context.IsWow64); -#endif - - status = PhCreateFileWin32( - &context.FileHandle, - FileName, - FILE_GENERIC_WRITE | DELETE, - 0, - 0, - FILE_OVERWRITE_IF, - FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT - ); - - if (!NT_SUCCESS(status)) - { - PhShowStatus(hWnd, L"Unable to access the dump file", status, 0); - NtClose(context.ProcessHandle); - return FALSE; - } - - DialogBoxParam( - PhInstanceHandle, - MAKEINTRESOURCE(IDD_PROGRESS), - hWnd, - PhpProcessMiniDumpDlgProc, - (LPARAM)&context - ); - - NtClose(context.FileHandle); - NtClose(context.ProcessHandle); - - return context.Succeeded; -} - -static BOOL CALLBACK PhpProcessMiniDumpCallback( - _In_ PVOID CallbackParam, - _In_ const PMINIDUMP_CALLBACK_INPUT CallbackInput, - _Inout_ PMINIDUMP_CALLBACK_OUTPUT CallbackOutput - ) -{ - PPROCESS_MINIDUMP_CONTEXT context = CallbackParam; - PPH_STRING message = NULL; - - // Don't try to send status updates if we're creating a dump of the current process. - if (context->ProcessId == NtCurrentProcessId()) - return TRUE; - - // MiniDumpWriteDump seems to get bored of calling the callback - // after it begins dumping the process handles. The code is - // still here in case they fix this problem in the future. - - switch (CallbackInput->CallbackType) - { - case CancelCallback: - { - if (context->Stop) - CallbackOutput->Cancel = TRUE; - } - break; - case ModuleCallback: - { - message = PhFormatString(L"Processing module %s...", CallbackInput->Module.FullPath); - } - break; - case ThreadCallback: - { - message = PhFormatString(L"Processing thread %u...", CallbackInput->Thread.ThreadId); - } - break; - } - - if (message) - { - SendMessage( - context->WindowHandle, - WM_PH_MINIDUMP_STATUS_UPDATE, - PH_MINIDUMP_STATUS_UPDATE, - (LPARAM)message->Buffer - ); - PhDereferenceObject(message); - } - - return TRUE; -} - -NTSTATUS PhpProcessMiniDumpThreadStart( - _In_ PVOID Parameter - ) -{ - PPROCESS_MINIDUMP_CONTEXT context = Parameter; - MINIDUMP_CALLBACK_INFORMATION callbackInfo; - - callbackInfo.CallbackRoutine = PhpProcessMiniDumpCallback; - callbackInfo.CallbackParam = context; - -#ifdef _WIN64 - if (context->IsWow64) - { - if (PhUiConnectToPhSvcEx(NULL, Wow64PhSvcMode, FALSE)) - { - NTSTATUS status; - PPH_STRING dbgHelpPath; - - dbgHelpPath = PhGetStringSetting(L"DbgHelpPath"); - PhSvcCallLoadDbgHelp(dbgHelpPath->Buffer); - PhDereferenceObject(dbgHelpPath); - - if (NT_SUCCESS(status = PhSvcCallWriteMiniDumpProcess( - context->ProcessHandle, - context->ProcessId, - context->FileHandle, - context->DumpType - ))) - { - context->Succeeded = TRUE; - } - else - { - // We may have an old version of dbghelp - in that case, try using minimal dump flags. - if (status == STATUS_INVALID_PARAMETER && NT_SUCCESS(status = PhSvcCallWriteMiniDumpProcess( - context->ProcessHandle, - context->ProcessId, - context->FileHandle, - MiniDumpWithFullMemory | MiniDumpWithHandleData - ))) - { - context->Succeeded = TRUE; - } - else - { - SendMessage( - context->WindowHandle, - WM_PH_MINIDUMP_STATUS_UPDATE, - PH_MINIDUMP_ERROR, - (LPARAM)PhNtStatusToDosError(status) - ); - } - } - - PhUiDisconnectFromPhSvc(); - - goto Completed; - } - else - { - if (PhShowMessage( - context->WindowHandle, - MB_YESNO | MB_ICONWARNING, - L"The process is 32-bit, but the 32-bit version of Process Hacker could not be located. " - L"A 64-bit dump will be created instead. Do you want to continue?" - ) == IDNO) - { - FILE_DISPOSITION_INFORMATION dispositionInfo; - IO_STATUS_BLOCK isb; - - dispositionInfo.DeleteFile = TRUE; - NtSetInformationFile( - context->FileHandle, - &isb, - &dispositionInfo, - sizeof(FILE_DISPOSITION_INFORMATION), - FileDispositionInformation - ); - - goto Completed; - } - } - } -#endif - - if (PhWriteMiniDumpProcess( - context->ProcessHandle, - context->ProcessId, - context->FileHandle, - context->DumpType, - NULL, - NULL, - &callbackInfo - )) - { - context->Succeeded = TRUE; - } - else - { - // We may have an old version of dbghelp - in that case, try using minimal dump flags. - if (GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER) && PhWriteMiniDumpProcess( - context->ProcessHandle, - context->ProcessId, - context->FileHandle, - MiniDumpWithFullMemory | MiniDumpWithHandleData, - NULL, - NULL, - &callbackInfo - )) - { - context->Succeeded = TRUE; - } - else - { - SendMessage( - context->WindowHandle, - WM_PH_MINIDUMP_STATUS_UPDATE, - PH_MINIDUMP_ERROR, - (LPARAM)GetLastError() - ); - } - } - -#ifdef _WIN64 -Completed: -#endif - SendMessage( - context->WindowHandle, - WM_PH_MINIDUMP_STATUS_UPDATE, - PH_MINIDUMP_COMPLETED, - 0 - ); - - return STATUS_SUCCESS; -} - -INT_PTR CALLBACK PhpProcessMiniDumpDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - switch (uMsg) - { - case WM_INITDIALOG: - { - PPROCESS_MINIDUMP_CONTEXT context = (PPROCESS_MINIDUMP_CONTEXT)lParam; - - PhCenterWindow(hwndDlg, GetParent(hwndDlg)); - SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)context); - - SetDlgItemText(hwndDlg, IDC_PROGRESSTEXT, L"Creating the dump file..."); - - PhSetWindowStyle(GetDlgItem(hwndDlg, IDC_PROGRESS), PBS_MARQUEE, PBS_MARQUEE); - SendMessage(GetDlgItem(hwndDlg, IDC_PROGRESS), PBM_SETMARQUEE, TRUE, 75); - - context->WindowHandle = hwndDlg; - context->ThreadHandle = PhCreateThread(0, PhpProcessMiniDumpThreadStart, context); - - if (!context->ThreadHandle) - { - PhShowStatus(hwndDlg, L"Unable to create the minidump thread", 0, GetLastError()); - EndDialog(hwndDlg, IDCANCEL); - } - - SetTimer(hwndDlg, 1, 500, NULL); - } - break; - case WM_DESTROY: - { - PPROCESS_MINIDUMP_CONTEXT context; - - context = (PPROCESS_MINIDUMP_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom()); - - NtClose(context->ThreadHandle); - - RemoveProp(hwndDlg, PhMakeContextAtom()); - } - break; - case WM_COMMAND: - { - switch (LOWORD(wParam)) - { - case IDCANCEL: - { - PPROCESS_MINIDUMP_CONTEXT context = - (PPROCESS_MINIDUMP_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom()); - - EnableWindow(GetDlgItem(hwndDlg, IDCANCEL), FALSE); - context->Stop = TRUE; - } - break; - } - } - break; - case WM_TIMER: - { - if (wParam == 1) - { - PPROCESS_MINIDUMP_CONTEXT context = - (PPROCESS_MINIDUMP_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom()); - ULONG currentTickCount; - - currentTickCount = GetTickCount(); - - if (currentTickCount - context->LastTickCount >= 2000) - { - // No status message update for 2 seconds. - - SetDlgItemText(hwndDlg, IDC_PROGRESSTEXT, - (PWSTR)L"Creating the dump file..."); - InvalidateRect(GetDlgItem(hwndDlg, IDC_PROGRESSTEXT), NULL, FALSE); - - context->LastTickCount = currentTickCount; - } - } - } - break; - case WM_PH_MINIDUMP_STATUS_UPDATE: - { - PPROCESS_MINIDUMP_CONTEXT context; - - context = (PPROCESS_MINIDUMP_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom()); - - switch (wParam) - { - case PH_MINIDUMP_STATUS_UPDATE: - SetDlgItemText(hwndDlg, IDC_PROGRESSTEXT, (PWSTR)lParam); - InvalidateRect(GetDlgItem(hwndDlg, IDC_PROGRESSTEXT), NULL, FALSE); - context->LastTickCount = GetTickCount(); - break; - case PH_MINIDUMP_ERROR: - PhShowStatus(hwndDlg, L"Unable to create the minidump", 0, (ULONG)lParam); - break; - case PH_MINIDUMP_COMPLETED: - EndDialog(hwndDlg, IDOK); - break; - } - } - break; - } - - return FALSE; -} +/* + * Process Hacker - + * minidump writer + * + * Copyright (C) 2010-2015 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include + +#include + +#include + +#include +#include +#include +#include + +#define WM_PH_MINIDUMP_STATUS_UPDATE (WM_APP + 301) + +#define PH_MINIDUMP_STATUS_UPDATE 1 +#define PH_MINIDUMP_COMPLETED 2 +#define PH_MINIDUMP_ERROR 3 + +typedef struct _PROCESS_MINIDUMP_CONTEXT +{ + HANDLE ProcessId; + PWSTR FileName; + MINIDUMP_TYPE DumpType; + BOOLEAN IsWow64; + + HANDLE ProcessHandle; + HANDLE FileHandle; + + HWND WindowHandle; + HANDLE ThreadHandle; + BOOLEAN Stop; + BOOLEAN Succeeded; + + ULONG LastTickCount; +} PROCESS_MINIDUMP_CONTEXT, *PPROCESS_MINIDUMP_CONTEXT; + +BOOLEAN PhpCreateProcessMiniDumpWithProgress( + _In_ HWND hWnd, + _In_ HANDLE ProcessId, + _In_ PWSTR FileName, + _In_ MINIDUMP_TYPE DumpType + ); + +INT_PTR CALLBACK PhpProcessMiniDumpDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +BOOLEAN PhUiCreateDumpFileProcess( + _In_ HWND hWnd, + _In_ PPH_PROCESS_ITEM Process + ) +{ + static PH_FILETYPE_FILTER filters[] = + { + { L"Dump files (*.dmp)", L"*.dmp" }, + { L"All files (*.*)", L"*.*" } + }; + PVOID fileDialog; + PPH_STRING fileName; + + fileDialog = PhCreateSaveFileDialog(); + PhSetFileDialogFilter(fileDialog, filters, sizeof(filters) / sizeof(PH_FILETYPE_FILTER)); + PhSetFileDialogFileName(fileDialog, PhaConcatStrings2(Process->ProcessName->Buffer, L".dmp")->Buffer); + + if (!PhShowFileDialog(hWnd, fileDialog)) + { + PhFreeFileDialog(fileDialog); + return FALSE; + } + + fileName = PH_AUTO(PhGetFileDialogFileName(fileDialog)); + PhFreeFileDialog(fileDialog); + + return PhpCreateProcessMiniDumpWithProgress( + hWnd, + Process->ProcessId, + fileName->Buffer, + // task manager uses these flags + MiniDumpWithFullMemory | + MiniDumpWithHandleData | + MiniDumpWithUnloadedModules | + MiniDumpWithFullMemoryInfo | + MiniDumpWithThreadInfo + ); +} + +BOOLEAN PhpCreateProcessMiniDumpWithProgress( + _In_ HWND hWnd, + _In_ HANDLE ProcessId, + _In_ PWSTR FileName, + _In_ MINIDUMP_TYPE DumpType + ) +{ + NTSTATUS status; + PROCESS_MINIDUMP_CONTEXT context; + + memset(&context, 0, sizeof(PROCESS_MINIDUMP_CONTEXT)); + context.ProcessId = ProcessId; + context.FileName = FileName; + context.DumpType = DumpType; + + if (!NT_SUCCESS(status = PhOpenProcess( + &context.ProcessHandle, + PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, + ProcessId + ))) + { + PhShowStatus(hWnd, L"Unable to open the process", status, 0); + return FALSE; + } + +#ifdef _WIN64 + PhGetProcessIsWow64(context.ProcessHandle, &context.IsWow64); +#endif + + status = PhCreateFileWin32( + &context.FileHandle, + FileName, + FILE_GENERIC_WRITE | DELETE, + 0, + 0, + FILE_OVERWRITE_IF, + FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT + ); + + if (!NT_SUCCESS(status)) + { + PhShowStatus(hWnd, L"Unable to access the dump file", status, 0); + NtClose(context.ProcessHandle); + return FALSE; + } + + DialogBoxParam( + PhInstanceHandle, + MAKEINTRESOURCE(IDD_PROGRESS), + hWnd, + PhpProcessMiniDumpDlgProc, + (LPARAM)&context + ); + + NtClose(context.FileHandle); + NtClose(context.ProcessHandle); + + return context.Succeeded; +} + +static BOOL CALLBACK PhpProcessMiniDumpCallback( + _In_ PVOID CallbackParam, + _In_ const PMINIDUMP_CALLBACK_INPUT CallbackInput, + _Inout_ PMINIDUMP_CALLBACK_OUTPUT CallbackOutput + ) +{ + PPROCESS_MINIDUMP_CONTEXT context = CallbackParam; + PPH_STRING message = NULL; + + // Don't try to send status updates if we're creating a dump of the current process. + if (context->ProcessId == NtCurrentProcessId()) + return TRUE; + + // MiniDumpWriteDump seems to get bored of calling the callback + // after it begins dumping the process handles. The code is + // still here in case they fix this problem in the future. + + switch (CallbackInput->CallbackType) + { + case CancelCallback: + { + if (context->Stop) + CallbackOutput->Cancel = TRUE; + } + break; + case ModuleCallback: + { + message = PhFormatString(L"Processing module %s...", CallbackInput->Module.FullPath); + } + break; + case ThreadCallback: + { + message = PhFormatString(L"Processing thread %u...", CallbackInput->Thread.ThreadId); + } + break; + } + + if (message) + { + SendMessage( + context->WindowHandle, + WM_PH_MINIDUMP_STATUS_UPDATE, + PH_MINIDUMP_STATUS_UPDATE, + (LPARAM)message->Buffer + ); + PhDereferenceObject(message); + } + + return TRUE; +} + +NTSTATUS PhpProcessMiniDumpThreadStart( + _In_ PVOID Parameter + ) +{ + PPROCESS_MINIDUMP_CONTEXT context = Parameter; + MINIDUMP_CALLBACK_INFORMATION callbackInfo; + + callbackInfo.CallbackRoutine = PhpProcessMiniDumpCallback; + callbackInfo.CallbackParam = context; + +#ifdef _WIN64 + if (context->IsWow64) + { + if (PhUiConnectToPhSvcEx(NULL, Wow64PhSvcMode, FALSE)) + { + NTSTATUS status; + PPH_STRING dbgHelpPath; + + dbgHelpPath = PhGetStringSetting(L"DbgHelpPath"); + PhSvcCallLoadDbgHelp(dbgHelpPath->Buffer); + PhDereferenceObject(dbgHelpPath); + + if (NT_SUCCESS(status = PhSvcCallWriteMiniDumpProcess( + context->ProcessHandle, + context->ProcessId, + context->FileHandle, + context->DumpType + ))) + { + context->Succeeded = TRUE; + } + else + { + // We may have an old version of dbghelp - in that case, try using minimal dump flags. + if (status == STATUS_INVALID_PARAMETER && NT_SUCCESS(status = PhSvcCallWriteMiniDumpProcess( + context->ProcessHandle, + context->ProcessId, + context->FileHandle, + MiniDumpWithFullMemory | MiniDumpWithHandleData + ))) + { + context->Succeeded = TRUE; + } + else + { + SendMessage( + context->WindowHandle, + WM_PH_MINIDUMP_STATUS_UPDATE, + PH_MINIDUMP_ERROR, + (LPARAM)PhNtStatusToDosError(status) + ); + } + } + + PhUiDisconnectFromPhSvc(); + + goto Completed; + } + else + { + if (PhShowMessage( + context->WindowHandle, + MB_YESNO | MB_ICONWARNING, + L"The process is 32-bit, but the 32-bit version of Process Hacker could not be located. " + L"A 64-bit dump will be created instead. Do you want to continue?" + ) == IDNO) + { + FILE_DISPOSITION_INFORMATION dispositionInfo; + IO_STATUS_BLOCK isb; + + dispositionInfo.DeleteFile = TRUE; + NtSetInformationFile( + context->FileHandle, + &isb, + &dispositionInfo, + sizeof(FILE_DISPOSITION_INFORMATION), + FileDispositionInformation + ); + + goto Completed; + } + } + } +#endif + + if (PhWriteMiniDumpProcess( + context->ProcessHandle, + context->ProcessId, + context->FileHandle, + context->DumpType, + NULL, + NULL, + &callbackInfo + )) + { + context->Succeeded = TRUE; + } + else + { + // We may have an old version of dbghelp - in that case, try using minimal dump flags. + if (GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER) && PhWriteMiniDumpProcess( + context->ProcessHandle, + context->ProcessId, + context->FileHandle, + MiniDumpWithFullMemory | MiniDumpWithHandleData, + NULL, + NULL, + &callbackInfo + )) + { + context->Succeeded = TRUE; + } + else + { + SendMessage( + context->WindowHandle, + WM_PH_MINIDUMP_STATUS_UPDATE, + PH_MINIDUMP_ERROR, + (LPARAM)GetLastError() + ); + } + } + +#ifdef _WIN64 +Completed: +#endif + SendMessage( + context->WindowHandle, + WM_PH_MINIDUMP_STATUS_UPDATE, + PH_MINIDUMP_COMPLETED, + 0 + ); + + return STATUS_SUCCESS; +} + +INT_PTR CALLBACK PhpProcessMiniDumpDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + switch (uMsg) + { + case WM_INITDIALOG: + { + PPROCESS_MINIDUMP_CONTEXT context = (PPROCESS_MINIDUMP_CONTEXT)lParam; + + PhCenterWindow(hwndDlg, GetParent(hwndDlg)); + SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)context); + + SetDlgItemText(hwndDlg, IDC_PROGRESSTEXT, L"Creating the dump file..."); + + PhSetWindowStyle(GetDlgItem(hwndDlg, IDC_PROGRESS), PBS_MARQUEE, PBS_MARQUEE); + SendMessage(GetDlgItem(hwndDlg, IDC_PROGRESS), PBM_SETMARQUEE, TRUE, 75); + + context->WindowHandle = hwndDlg; + context->ThreadHandle = PhCreateThread(0, PhpProcessMiniDumpThreadStart, context); + + if (!context->ThreadHandle) + { + PhShowStatus(hwndDlg, L"Unable to create the minidump thread", 0, GetLastError()); + EndDialog(hwndDlg, IDCANCEL); + } + + SetTimer(hwndDlg, 1, 500, NULL); + } + break; + case WM_DESTROY: + { + PPROCESS_MINIDUMP_CONTEXT context; + + context = (PPROCESS_MINIDUMP_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom()); + + NtClose(context->ThreadHandle); + + RemoveProp(hwndDlg, PhMakeContextAtom()); + } + break; + case WM_COMMAND: + { + switch (LOWORD(wParam)) + { + case IDCANCEL: + { + PPROCESS_MINIDUMP_CONTEXT context = + (PPROCESS_MINIDUMP_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom()); + + EnableWindow(GetDlgItem(hwndDlg, IDCANCEL), FALSE); + context->Stop = TRUE; + } + break; + } + } + break; + case WM_TIMER: + { + if (wParam == 1) + { + PPROCESS_MINIDUMP_CONTEXT context = + (PPROCESS_MINIDUMP_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom()); + ULONG currentTickCount; + + currentTickCount = GetTickCount(); + + if (currentTickCount - context->LastTickCount >= 2000) + { + // No status message update for 2 seconds. + + SetDlgItemText(hwndDlg, IDC_PROGRESSTEXT, + (PWSTR)L"Creating the dump file..."); + InvalidateRect(GetDlgItem(hwndDlg, IDC_PROGRESSTEXT), NULL, FALSE); + + context->LastTickCount = currentTickCount; + } + } + } + break; + case WM_PH_MINIDUMP_STATUS_UPDATE: + { + PPROCESS_MINIDUMP_CONTEXT context; + + context = (PPROCESS_MINIDUMP_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom()); + + switch (wParam) + { + case PH_MINIDUMP_STATUS_UPDATE: + SetDlgItemText(hwndDlg, IDC_PROGRESSTEXT, (PWSTR)lParam); + InvalidateRect(GetDlgItem(hwndDlg, IDC_PROGRESSTEXT), NULL, FALSE); + context->LastTickCount = GetTickCount(); + break; + case PH_MINIDUMP_ERROR: + PhShowStatus(hwndDlg, L"Unable to create the minidump", 0, (ULONG)lParam); + break; + case PH_MINIDUMP_COMPLETED: + EndDialog(hwndDlg, IDOK); + break; + } + } + break; + } + + return FALSE; +} diff --git a/ProcessHacker/memedit.c b/ProcessHacker/memedit.c index b5c78285c8c3..4cf0897ad7e9 100644 --- a/ProcessHacker/memedit.c +++ b/ProcessHacker/memedit.c @@ -1,536 +1,536 @@ -/* - * Process Hacker - - * memory editor window - * - * Copyright (C) 2010-2016 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include - -#include - -#include - -#include -#include -#include - -#define WM_PH_SELECT_OFFSET (WM_APP + 300) - -typedef struct _MEMORY_EDITOR_CONTEXT -{ - PH_AVL_LINKS Links; - union - { - struct - { - HANDLE ProcessId; - PVOID BaseAddress; - SIZE_T RegionSize; - }; - ULONG_PTR Key[3]; - }; - HANDLE ProcessHandle; - HWND WindowHandle; - PH_LAYOUT_MANAGER LayoutManager; - HWND HexEditHandle; - PUCHAR Buffer; - ULONG SelectOffset; - PPH_STRING Title; - ULONG Flags; - - BOOLEAN LoadCompleted; - BOOLEAN WriteAccess; -} MEMORY_EDITOR_CONTEXT, *PMEMORY_EDITOR_CONTEXT; - -INT NTAPI PhpMemoryEditorCompareFunction( - _In_ PPH_AVL_LINKS Links1, - _In_ PPH_AVL_LINKS Links2 - ); - -INT_PTR CALLBACK PhpMemoryEditorDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -PH_AVL_TREE PhMemoryEditorSet = PH_AVL_TREE_INIT(PhpMemoryEditorCompareFunction); -static RECT MinimumSize = { -1, -1, -1, -1 }; - -VOID PhShowMemoryEditorDialog( - _In_ HANDLE ProcessId, - _In_ PVOID BaseAddress, - _In_ SIZE_T RegionSize, - _In_ ULONG SelectOffset, - _In_ ULONG SelectLength, - _In_opt_ PPH_STRING Title, - _In_ ULONG Flags - ) -{ - PMEMORY_EDITOR_CONTEXT context; - MEMORY_EDITOR_CONTEXT lookupContext; - PPH_AVL_LINKS links; - - lookupContext.ProcessId = ProcessId; - lookupContext.BaseAddress = BaseAddress; - lookupContext.RegionSize = RegionSize; - - links = PhFindElementAvlTree(&PhMemoryEditorSet, &lookupContext.Links); - - if (!links) - { - context = PhAllocate(sizeof(MEMORY_EDITOR_CONTEXT)); - memset(context, 0, sizeof(MEMORY_EDITOR_CONTEXT)); - - context->ProcessId = ProcessId; - context->BaseAddress = BaseAddress; - context->RegionSize = RegionSize; - context->SelectOffset = SelectOffset; - PhSwapReference(&context->Title, Title); - context->Flags = Flags; - - context->WindowHandle = CreateDialogParam( - PhInstanceHandle, - MAKEINTRESOURCE(IDD_MEMEDIT), - NULL, - PhpMemoryEditorDlgProc, - (LPARAM)context - ); - - if (!context->LoadCompleted) - { - DestroyWindow(context->WindowHandle); - return; - } - - if (SelectOffset != -1) - PostMessage(context->WindowHandle, WM_PH_SELECT_OFFSET, SelectOffset, SelectLength); - - PhRegisterDialog(context->WindowHandle); - PhAddElementAvlTree(&PhMemoryEditorSet, &context->Links); - - ShowWindow(context->WindowHandle, SW_SHOW); - SetForegroundWindow(context->WindowHandle); - } - else - { - context = CONTAINING_RECORD(links, MEMORY_EDITOR_CONTEXT, Links); - - if (IsIconic(context->WindowHandle)) - ShowWindow(context->WindowHandle, SW_RESTORE); - else - SetForegroundWindow(context->WindowHandle); - - if (SelectOffset != -1) - PostMessage(context->WindowHandle, WM_PH_SELECT_OFFSET, SelectOffset, SelectLength); - - // Just in case. - if ((Flags & PH_MEMORY_EDITOR_UNMAP_VIEW_OF_SECTION) && ProcessId == NtCurrentProcessId()) - NtUnmapViewOfSection(NtCurrentProcess(), BaseAddress); - } -} - -INT NTAPI PhpMemoryEditorCompareFunction( - _In_ PPH_AVL_LINKS Links1, - _In_ PPH_AVL_LINKS Links2 - ) -{ - PMEMORY_EDITOR_CONTEXT context1 = CONTAINING_RECORD(Links1, MEMORY_EDITOR_CONTEXT, Links); - PMEMORY_EDITOR_CONTEXT context2 = CONTAINING_RECORD(Links2, MEMORY_EDITOR_CONTEXT, Links); - - return memcmp(context1->Key, context2->Key, sizeof(context1->Key)); -} - -INT_PTR CALLBACK PhpMemoryEditorDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - PMEMORY_EDITOR_CONTEXT context; - - if (uMsg != WM_INITDIALOG) - { - context = GetProp(hwndDlg, PhMakeContextAtom()); - } - else - { - context = (PMEMORY_EDITOR_CONTEXT)lParam; - SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)context); - } - - if (!context) - return FALSE; - - switch (uMsg) - { - case WM_INITDIALOG: - { - NTSTATUS status; - - if (context->Title) - { - SetWindowText(hwndDlg, context->Title->Buffer); - } - else - { - PPH_PROCESS_ITEM processItem; - - if (processItem = PhReferenceProcessItem(context->ProcessId)) - { - SetWindowText(hwndDlg, PhaFormatString(L"%s (%u) (0x%Ix - 0x%Ix)", - processItem->ProcessName->Buffer, HandleToUlong(context->ProcessId), - context->BaseAddress, (ULONG_PTR)context->BaseAddress + context->RegionSize)->Buffer); - PhDereferenceObject(processItem); - } - } - - PhInitializeLayoutManager(&context->LayoutManager, hwndDlg); - - if (context->RegionSize > 1024 * 1024 * 1024) // 1 GB - { - PhShowError(NULL, L"Unable to edit the memory region because it is too large."); - return TRUE; - } - - if (!NT_SUCCESS(status = PhOpenProcess( - &context->ProcessHandle, - PROCESS_VM_READ, - context->ProcessId - ))) - { - PhShowStatus(NULL, L"Unable to open the process", status, 0); - return TRUE; - } - - context->Buffer = PhAllocatePage(context->RegionSize, NULL); - - if (!context->Buffer) - { - PhShowError(NULL, L"Unable to allocate memory for the buffer."); - return TRUE; - } - - if (!NT_SUCCESS(status = NtReadVirtualMemory( - context->ProcessHandle, - context->BaseAddress, - context->Buffer, - context->RegionSize, - NULL - ))) - { - PhShowStatus(NULL, L"Unable to read memory", status, 0); - return TRUE; - } - - PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDOK), NULL, - PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); - PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_SAVE), NULL, - PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); - PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_BYTESPERROW), NULL, - PH_ANCHOR_BOTTOM | PH_ANCHOR_LEFT); - PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_GOTO), NULL, - PH_ANCHOR_BOTTOM | PH_ANCHOR_LEFT); - PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_WRITE), NULL, - PH_ANCHOR_BOTTOM | PH_ANCHOR_LEFT); - PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_REREAD), NULL, - PH_ANCHOR_BOTTOM | PH_ANCHOR_LEFT); - - if (MinimumSize.left == -1) - { - RECT rect; - - rect.left = 0; - rect.top = 0; - rect.right = 290; - rect.bottom = 140; - MapDialogRect(hwndDlg, &rect); - MinimumSize = rect; - MinimumSize.left = 0; - } - - context->HexEditHandle = GetDlgItem(hwndDlg, IDC_MEMORY); - PhAddLayoutItem(&context->LayoutManager, context->HexEditHandle, NULL, PH_ANCHOR_ALL); - HexEdit_SetBuffer(context->HexEditHandle, context->Buffer, (ULONG)context->RegionSize); - - { - PH_RECTANGLE windowRectangle; - - windowRectangle.Position = PhGetIntegerPairSetting(L"MemEditPosition"); - windowRectangle.Size = PhGetScalableIntegerPairSetting(L"MemEditSize", TRUE).Pair; - PhAdjustRectangleToWorkingArea(NULL, &windowRectangle); - - MoveWindow(hwndDlg, windowRectangle.Left, windowRectangle.Top, - windowRectangle.Width, windowRectangle.Height, FALSE); - - // Implement cascading by saving an offsetted rectangle. - windowRectangle.Left += 20; - windowRectangle.Top += 20; - - PhSetIntegerPairSetting(L"MemEditPosition", windowRectangle.Position); - PhSetScalableIntegerPairSetting2(L"MemEditSize", windowRectangle.Size); - } - - { - PWSTR bytesPerRowStrings[7]; - ULONG i; - ULONG bytesPerRow; - - for (i = 0; i < sizeof(bytesPerRowStrings) / sizeof(PWSTR); i++) - bytesPerRowStrings[i] = PhaFormatString(L"%u bytes per row", 1 << (2 + i))->Buffer; - - PhAddComboBoxStrings(GetDlgItem(hwndDlg, IDC_BYTESPERROW), - bytesPerRowStrings, sizeof(bytesPerRowStrings) / sizeof(PWSTR)); - - bytesPerRow = PhGetIntegerSetting(L"MemEditBytesPerRow"); - - if (bytesPerRow >= 4) - { - HexEdit_SetBytesPerRow(context->HexEditHandle, bytesPerRow); - PhSelectComboBoxString(GetDlgItem(hwndDlg, IDC_BYTESPERROW), - PhaFormatString(L"%u bytes per row", bytesPerRow)->Buffer, FALSE); - } - } - - context->LoadCompleted = TRUE; - } - break; - case WM_DESTROY: - { - if (context->LoadCompleted) - { - PhSaveWindowPlacementToSetting(L"MemEditPosition", L"MemEditSize", hwndDlg); - PhRemoveElementAvlTree(&PhMemoryEditorSet, &context->Links); - PhUnregisterDialog(hwndDlg); - } - - RemoveProp(hwndDlg, PhMakeContextAtom()); - - PhDeleteLayoutManager(&context->LayoutManager); - - if (context->Buffer) PhFreePage(context->Buffer); - if (context->ProcessHandle) NtClose(context->ProcessHandle); - PhClearReference(&context->Title); - - if ((context->Flags & PH_MEMORY_EDITOR_UNMAP_VIEW_OF_SECTION) && context->ProcessId == NtCurrentProcessId()) - NtUnmapViewOfSection(NtCurrentProcess(), context->BaseAddress); - - PhFree(context); - } - break; - case WM_SHOWWINDOW: - { - SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)context->HexEditHandle, TRUE); - } - break; - case WM_COMMAND: - { - switch (LOWORD(wParam)) - { - case IDCANCEL: - case IDOK: - DestroyWindow(hwndDlg); - break; - case IDC_SAVE: - { - static PH_FILETYPE_FILTER filters[] = - { - { L"Binary files (*.bin)", L"*.bin" }, - { L"All files (*.*)", L"*.*" } - }; - PVOID fileDialog; - PPH_PROCESS_ITEM processItem; - - fileDialog = PhCreateSaveFileDialog(); - - PhSetFileDialogFilter(fileDialog, filters, sizeof(filters) / sizeof(PH_FILETYPE_FILTER)); - - if (!context->Title && (processItem = PhReferenceProcessItem(context->ProcessId))) - { - PhSetFileDialogFileName(fileDialog, - PhaFormatString(L"%s_0x%Ix-0x%Ix.bin", processItem->ProcessName->Buffer, - context->BaseAddress, context->RegionSize)->Buffer); - PhDereferenceObject(processItem); - } - else - { - PhSetFileDialogFileName(fileDialog, L"Memory.bin"); - } - - if (PhShowFileDialog(hwndDlg, fileDialog)) - { - NTSTATUS status; - PPH_STRING fileName; - PPH_FILE_STREAM fileStream; - - fileName = PH_AUTO(PhGetFileDialogFileName(fileDialog)); - - if (NT_SUCCESS(status = PhCreateFileStream( - &fileStream, - fileName->Buffer, - FILE_GENERIC_WRITE, - FILE_SHARE_READ, - FILE_OVERWRITE_IF, - 0 - ))) - { - status = PhWriteFileStream(fileStream, context->Buffer, (ULONG)context->RegionSize); - PhDereferenceObject(fileStream); - } - - if (!NT_SUCCESS(status)) - PhShowStatus(hwndDlg, L"Unable to create the file", status, 0); - } - - PhFreeFileDialog(fileDialog); - } - break; - case IDC_GOTO: - { - PPH_STRING selectedChoice = NULL; - - while (PhaChoiceDialog( - hwndDlg, - L"Go to Offset", - L"Enter an offset:", - NULL, - 0, - NULL, - PH_CHOICE_DIALOG_USER_CHOICE, - &selectedChoice, - NULL, - L"MemEditGotoChoices" - )) - { - ULONG64 offset; - - if (selectedChoice->Length == 0) - continue; - - if (PhStringToInteger64(&selectedChoice->sr, 0, &offset)) - { - if (offset >= context->RegionSize) - { - PhShowError(hwndDlg, L"The offset is too large."); - continue; - } - - SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)context->HexEditHandle, TRUE); - HexEdit_SetSel(context->HexEditHandle, (LONG)offset, (LONG)offset); - break; - } - } - } - break; - case IDC_WRITE: - { - NTSTATUS status; - - if (!context->WriteAccess) - { - HANDLE processHandle; - - if (!NT_SUCCESS(status = PhOpenProcess( - &processHandle, - PROCESS_VM_READ | PROCESS_VM_WRITE, - context->ProcessId - ))) - { - PhShowStatus(hwndDlg, L"Unable to open the process", status, 0); - break; - } - - if (context->ProcessHandle) NtClose(context->ProcessHandle); - context->ProcessHandle = processHandle; - context->WriteAccess = TRUE; - } - - if (!NT_SUCCESS(status = NtWriteVirtualMemory( - context->ProcessHandle, - context->BaseAddress, - context->Buffer, - context->RegionSize, - NULL - ))) - { - PhShowStatus(hwndDlg, L"Unable to write memory", status, 0); - } - } - break; - case IDC_REREAD: - { - NTSTATUS status; - - if (!NT_SUCCESS(status = NtReadVirtualMemory( - context->ProcessHandle, - context->BaseAddress, - context->Buffer, - context->RegionSize, - NULL - ))) - { - PhShowStatus(hwndDlg, L"Unable to read memory", status, 0); - } - - InvalidateRect(context->HexEditHandle, NULL, TRUE); - } - break; - case IDC_BYTESPERROW: - if (HIWORD(wParam) == CBN_SELCHANGE) - { - PPH_STRING bytesPerRowString = PhaGetDlgItemText(hwndDlg, IDC_BYTESPERROW); - PH_STRINGREF firstPart; - PH_STRINGREF secondPart; - ULONG64 bytesPerRow64; - - if (PhSplitStringRefAtChar(&bytesPerRowString->sr, ' ', &firstPart, &secondPart)) - { - if (PhStringToInteger64(&firstPart, 10, &bytesPerRow64)) - { - PhSetIntegerSetting(L"MemEditBytesPerRow", (ULONG)bytesPerRow64); - HexEdit_SetBytesPerRow(context->HexEditHandle, (ULONG)bytesPerRow64); - SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)context->HexEditHandle, TRUE); - } - } - } - break; - } - } - break; - case WM_SIZE: - { - PhLayoutManagerLayout(&context->LayoutManager); - } - break; - case WM_SIZING: - { - PhResizingMinimumSize((PRECT)lParam, wParam, MinimumSize.right, MinimumSize.bottom); - } - break; - case WM_PH_SELECT_OFFSET: - { - HexEdit_SetEditMode(context->HexEditHandle, EDIT_ASCII); - HexEdit_SetSel(context->HexEditHandle, (ULONG)wParam, (ULONG)wParam + (ULONG)lParam); - } - break; - } - - return FALSE; -} +/* + * Process Hacker - + * memory editor window + * + * Copyright (C) 2010-2016 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include + +#include + +#include + +#include +#include +#include + +#define WM_PH_SELECT_OFFSET (WM_APP + 300) + +typedef struct _MEMORY_EDITOR_CONTEXT +{ + PH_AVL_LINKS Links; + union + { + struct + { + HANDLE ProcessId; + PVOID BaseAddress; + SIZE_T RegionSize; + }; + ULONG_PTR Key[3]; + }; + HANDLE ProcessHandle; + HWND WindowHandle; + PH_LAYOUT_MANAGER LayoutManager; + HWND HexEditHandle; + PUCHAR Buffer; + ULONG SelectOffset; + PPH_STRING Title; + ULONG Flags; + + BOOLEAN LoadCompleted; + BOOLEAN WriteAccess; +} MEMORY_EDITOR_CONTEXT, *PMEMORY_EDITOR_CONTEXT; + +INT NTAPI PhpMemoryEditorCompareFunction( + _In_ PPH_AVL_LINKS Links1, + _In_ PPH_AVL_LINKS Links2 + ); + +INT_PTR CALLBACK PhpMemoryEditorDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +PH_AVL_TREE PhMemoryEditorSet = PH_AVL_TREE_INIT(PhpMemoryEditorCompareFunction); +static RECT MinimumSize = { -1, -1, -1, -1 }; + +VOID PhShowMemoryEditorDialog( + _In_ HANDLE ProcessId, + _In_ PVOID BaseAddress, + _In_ SIZE_T RegionSize, + _In_ ULONG SelectOffset, + _In_ ULONG SelectLength, + _In_opt_ PPH_STRING Title, + _In_ ULONG Flags + ) +{ + PMEMORY_EDITOR_CONTEXT context; + MEMORY_EDITOR_CONTEXT lookupContext; + PPH_AVL_LINKS links; + + lookupContext.ProcessId = ProcessId; + lookupContext.BaseAddress = BaseAddress; + lookupContext.RegionSize = RegionSize; + + links = PhFindElementAvlTree(&PhMemoryEditorSet, &lookupContext.Links); + + if (!links) + { + context = PhAllocate(sizeof(MEMORY_EDITOR_CONTEXT)); + memset(context, 0, sizeof(MEMORY_EDITOR_CONTEXT)); + + context->ProcessId = ProcessId; + context->BaseAddress = BaseAddress; + context->RegionSize = RegionSize; + context->SelectOffset = SelectOffset; + PhSwapReference(&context->Title, Title); + context->Flags = Flags; + + context->WindowHandle = CreateDialogParam( + PhInstanceHandle, + MAKEINTRESOURCE(IDD_MEMEDIT), + NULL, + PhpMemoryEditorDlgProc, + (LPARAM)context + ); + + if (!context->LoadCompleted) + { + DestroyWindow(context->WindowHandle); + return; + } + + if (SelectOffset != -1) + PostMessage(context->WindowHandle, WM_PH_SELECT_OFFSET, SelectOffset, SelectLength); + + PhRegisterDialog(context->WindowHandle); + PhAddElementAvlTree(&PhMemoryEditorSet, &context->Links); + + ShowWindow(context->WindowHandle, SW_SHOW); + SetForegroundWindow(context->WindowHandle); + } + else + { + context = CONTAINING_RECORD(links, MEMORY_EDITOR_CONTEXT, Links); + + if (IsIconic(context->WindowHandle)) + ShowWindow(context->WindowHandle, SW_RESTORE); + else + SetForegroundWindow(context->WindowHandle); + + if (SelectOffset != -1) + PostMessage(context->WindowHandle, WM_PH_SELECT_OFFSET, SelectOffset, SelectLength); + + // Just in case. + if ((Flags & PH_MEMORY_EDITOR_UNMAP_VIEW_OF_SECTION) && ProcessId == NtCurrentProcessId()) + NtUnmapViewOfSection(NtCurrentProcess(), BaseAddress); + } +} + +INT NTAPI PhpMemoryEditorCompareFunction( + _In_ PPH_AVL_LINKS Links1, + _In_ PPH_AVL_LINKS Links2 + ) +{ + PMEMORY_EDITOR_CONTEXT context1 = CONTAINING_RECORD(Links1, MEMORY_EDITOR_CONTEXT, Links); + PMEMORY_EDITOR_CONTEXT context2 = CONTAINING_RECORD(Links2, MEMORY_EDITOR_CONTEXT, Links); + + return memcmp(context1->Key, context2->Key, sizeof(context1->Key)); +} + +INT_PTR CALLBACK PhpMemoryEditorDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + PMEMORY_EDITOR_CONTEXT context; + + if (uMsg != WM_INITDIALOG) + { + context = GetProp(hwndDlg, PhMakeContextAtom()); + } + else + { + context = (PMEMORY_EDITOR_CONTEXT)lParam; + SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)context); + } + + if (!context) + return FALSE; + + switch (uMsg) + { + case WM_INITDIALOG: + { + NTSTATUS status; + + if (context->Title) + { + SetWindowText(hwndDlg, context->Title->Buffer); + } + else + { + PPH_PROCESS_ITEM processItem; + + if (processItem = PhReferenceProcessItem(context->ProcessId)) + { + SetWindowText(hwndDlg, PhaFormatString(L"%s (%u) (0x%Ix - 0x%Ix)", + processItem->ProcessName->Buffer, HandleToUlong(context->ProcessId), + context->BaseAddress, (ULONG_PTR)context->BaseAddress + context->RegionSize)->Buffer); + PhDereferenceObject(processItem); + } + } + + PhInitializeLayoutManager(&context->LayoutManager, hwndDlg); + + if (context->RegionSize > 1024 * 1024 * 1024) // 1 GB + { + PhShowError(NULL, L"Unable to edit the memory region because it is too large."); + return TRUE; + } + + if (!NT_SUCCESS(status = PhOpenProcess( + &context->ProcessHandle, + PROCESS_VM_READ, + context->ProcessId + ))) + { + PhShowStatus(NULL, L"Unable to open the process", status, 0); + return TRUE; + } + + context->Buffer = PhAllocatePage(context->RegionSize, NULL); + + if (!context->Buffer) + { + PhShowError(NULL, L"Unable to allocate memory for the buffer."); + return TRUE; + } + + if (!NT_SUCCESS(status = NtReadVirtualMemory( + context->ProcessHandle, + context->BaseAddress, + context->Buffer, + context->RegionSize, + NULL + ))) + { + PhShowStatus(NULL, L"Unable to read memory", status, 0); + return TRUE; + } + + PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDOK), NULL, + PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); + PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_SAVE), NULL, + PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); + PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_BYTESPERROW), NULL, + PH_ANCHOR_BOTTOM | PH_ANCHOR_LEFT); + PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_GOTO), NULL, + PH_ANCHOR_BOTTOM | PH_ANCHOR_LEFT); + PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_WRITE), NULL, + PH_ANCHOR_BOTTOM | PH_ANCHOR_LEFT); + PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_REREAD), NULL, + PH_ANCHOR_BOTTOM | PH_ANCHOR_LEFT); + + if (MinimumSize.left == -1) + { + RECT rect; + + rect.left = 0; + rect.top = 0; + rect.right = 290; + rect.bottom = 140; + MapDialogRect(hwndDlg, &rect); + MinimumSize = rect; + MinimumSize.left = 0; + } + + context->HexEditHandle = GetDlgItem(hwndDlg, IDC_MEMORY); + PhAddLayoutItem(&context->LayoutManager, context->HexEditHandle, NULL, PH_ANCHOR_ALL); + HexEdit_SetBuffer(context->HexEditHandle, context->Buffer, (ULONG)context->RegionSize); + + { + PH_RECTANGLE windowRectangle; + + windowRectangle.Position = PhGetIntegerPairSetting(L"MemEditPosition"); + windowRectangle.Size = PhGetScalableIntegerPairSetting(L"MemEditSize", TRUE).Pair; + PhAdjustRectangleToWorkingArea(NULL, &windowRectangle); + + MoveWindow(hwndDlg, windowRectangle.Left, windowRectangle.Top, + windowRectangle.Width, windowRectangle.Height, FALSE); + + // Implement cascading by saving an offsetted rectangle. + windowRectangle.Left += 20; + windowRectangle.Top += 20; + + PhSetIntegerPairSetting(L"MemEditPosition", windowRectangle.Position); + PhSetScalableIntegerPairSetting2(L"MemEditSize", windowRectangle.Size); + } + + { + PWSTR bytesPerRowStrings[7]; + ULONG i; + ULONG bytesPerRow; + + for (i = 0; i < sizeof(bytesPerRowStrings) / sizeof(PWSTR); i++) + bytesPerRowStrings[i] = PhaFormatString(L"%u bytes per row", 1 << (2 + i))->Buffer; + + PhAddComboBoxStrings(GetDlgItem(hwndDlg, IDC_BYTESPERROW), + bytesPerRowStrings, sizeof(bytesPerRowStrings) / sizeof(PWSTR)); + + bytesPerRow = PhGetIntegerSetting(L"MemEditBytesPerRow"); + + if (bytesPerRow >= 4) + { + HexEdit_SetBytesPerRow(context->HexEditHandle, bytesPerRow); + PhSelectComboBoxString(GetDlgItem(hwndDlg, IDC_BYTESPERROW), + PhaFormatString(L"%u bytes per row", bytesPerRow)->Buffer, FALSE); + } + } + + context->LoadCompleted = TRUE; + } + break; + case WM_DESTROY: + { + if (context->LoadCompleted) + { + PhSaveWindowPlacementToSetting(L"MemEditPosition", L"MemEditSize", hwndDlg); + PhRemoveElementAvlTree(&PhMemoryEditorSet, &context->Links); + PhUnregisterDialog(hwndDlg); + } + + RemoveProp(hwndDlg, PhMakeContextAtom()); + + PhDeleteLayoutManager(&context->LayoutManager); + + if (context->Buffer) PhFreePage(context->Buffer); + if (context->ProcessHandle) NtClose(context->ProcessHandle); + PhClearReference(&context->Title); + + if ((context->Flags & PH_MEMORY_EDITOR_UNMAP_VIEW_OF_SECTION) && context->ProcessId == NtCurrentProcessId()) + NtUnmapViewOfSection(NtCurrentProcess(), context->BaseAddress); + + PhFree(context); + } + break; + case WM_SHOWWINDOW: + { + SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)context->HexEditHandle, TRUE); + } + break; + case WM_COMMAND: + { + switch (LOWORD(wParam)) + { + case IDCANCEL: + case IDOK: + DestroyWindow(hwndDlg); + break; + case IDC_SAVE: + { + static PH_FILETYPE_FILTER filters[] = + { + { L"Binary files (*.bin)", L"*.bin" }, + { L"All files (*.*)", L"*.*" } + }; + PVOID fileDialog; + PPH_PROCESS_ITEM processItem; + + fileDialog = PhCreateSaveFileDialog(); + + PhSetFileDialogFilter(fileDialog, filters, sizeof(filters) / sizeof(PH_FILETYPE_FILTER)); + + if (!context->Title && (processItem = PhReferenceProcessItem(context->ProcessId))) + { + PhSetFileDialogFileName(fileDialog, + PhaFormatString(L"%s_0x%Ix-0x%Ix.bin", processItem->ProcessName->Buffer, + context->BaseAddress, context->RegionSize)->Buffer); + PhDereferenceObject(processItem); + } + else + { + PhSetFileDialogFileName(fileDialog, L"Memory.bin"); + } + + if (PhShowFileDialog(hwndDlg, fileDialog)) + { + NTSTATUS status; + PPH_STRING fileName; + PPH_FILE_STREAM fileStream; + + fileName = PH_AUTO(PhGetFileDialogFileName(fileDialog)); + + if (NT_SUCCESS(status = PhCreateFileStream( + &fileStream, + fileName->Buffer, + FILE_GENERIC_WRITE, + FILE_SHARE_READ, + FILE_OVERWRITE_IF, + 0 + ))) + { + status = PhWriteFileStream(fileStream, context->Buffer, (ULONG)context->RegionSize); + PhDereferenceObject(fileStream); + } + + if (!NT_SUCCESS(status)) + PhShowStatus(hwndDlg, L"Unable to create the file", status, 0); + } + + PhFreeFileDialog(fileDialog); + } + break; + case IDC_GOTO: + { + PPH_STRING selectedChoice = NULL; + + while (PhaChoiceDialog( + hwndDlg, + L"Go to Offset", + L"Enter an offset:", + NULL, + 0, + NULL, + PH_CHOICE_DIALOG_USER_CHOICE, + &selectedChoice, + NULL, + L"MemEditGotoChoices" + )) + { + ULONG64 offset; + + if (selectedChoice->Length == 0) + continue; + + if (PhStringToInteger64(&selectedChoice->sr, 0, &offset)) + { + if (offset >= context->RegionSize) + { + PhShowError(hwndDlg, L"The offset is too large."); + continue; + } + + SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)context->HexEditHandle, TRUE); + HexEdit_SetSel(context->HexEditHandle, (LONG)offset, (LONG)offset); + break; + } + } + } + break; + case IDC_WRITE: + { + NTSTATUS status; + + if (!context->WriteAccess) + { + HANDLE processHandle; + + if (!NT_SUCCESS(status = PhOpenProcess( + &processHandle, + PROCESS_VM_READ | PROCESS_VM_WRITE, + context->ProcessId + ))) + { + PhShowStatus(hwndDlg, L"Unable to open the process", status, 0); + break; + } + + if (context->ProcessHandle) NtClose(context->ProcessHandle); + context->ProcessHandle = processHandle; + context->WriteAccess = TRUE; + } + + if (!NT_SUCCESS(status = NtWriteVirtualMemory( + context->ProcessHandle, + context->BaseAddress, + context->Buffer, + context->RegionSize, + NULL + ))) + { + PhShowStatus(hwndDlg, L"Unable to write memory", status, 0); + } + } + break; + case IDC_REREAD: + { + NTSTATUS status; + + if (!NT_SUCCESS(status = NtReadVirtualMemory( + context->ProcessHandle, + context->BaseAddress, + context->Buffer, + context->RegionSize, + NULL + ))) + { + PhShowStatus(hwndDlg, L"Unable to read memory", status, 0); + } + + InvalidateRect(context->HexEditHandle, NULL, TRUE); + } + break; + case IDC_BYTESPERROW: + if (HIWORD(wParam) == CBN_SELCHANGE) + { + PPH_STRING bytesPerRowString = PhaGetDlgItemText(hwndDlg, IDC_BYTESPERROW); + PH_STRINGREF firstPart; + PH_STRINGREF secondPart; + ULONG64 bytesPerRow64; + + if (PhSplitStringRefAtChar(&bytesPerRowString->sr, ' ', &firstPart, &secondPart)) + { + if (PhStringToInteger64(&firstPart, 10, &bytesPerRow64)) + { + PhSetIntegerSetting(L"MemEditBytesPerRow", (ULONG)bytesPerRow64); + HexEdit_SetBytesPerRow(context->HexEditHandle, (ULONG)bytesPerRow64); + SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)context->HexEditHandle, TRUE); + } + } + } + break; + } + } + break; + case WM_SIZE: + { + PhLayoutManagerLayout(&context->LayoutManager); + } + break; + case WM_SIZING: + { + PhResizingMinimumSize((PRECT)lParam, wParam, MinimumSize.right, MinimumSize.bottom); + } + break; + case WM_PH_SELECT_OFFSET: + { + HexEdit_SetEditMode(context->HexEditHandle, EDIT_ASCII); + HexEdit_SetSel(context->HexEditHandle, (ULONG)wParam, (ULONG)wParam + (ULONG)lParam); + } + break; + } + + return FALSE; +} diff --git a/ProcessHacker/memlist.c b/ProcessHacker/memlist.c index cc36d29727cf..4e5d9373c741 100644 --- a/ProcessHacker/memlist.c +++ b/ProcessHacker/memlist.c @@ -1,918 +1,918 @@ -/* - * Process Hacker - - * memory region list - * - * Copyright (C) 2015 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include -#include - -#include - -#include -#include -#include -#include - -VOID PhpClearMemoryList( - _Inout_ PPH_MEMORY_LIST_CONTEXT Context - ); - -VOID PhpDestroyMemoryNode( - _In_ PPH_MEMORY_NODE MemoryNode - ); - -LONG PhpMemoryTreeNewPostSortFunction( - _In_ LONG Result, - _In_ PVOID Node1, - _In_ PVOID Node2, - _In_ PH_SORT_ORDER SortOrder - ); - -BOOLEAN NTAPI PhpMemoryTreeNewCallback( - _In_ HWND hwnd, - _In_ PH_TREENEW_MESSAGE Message, - _In_opt_ PVOID Parameter1, - _In_opt_ PVOID Parameter2, - _In_opt_ PVOID Context - ); - -VOID PhInitializeMemoryList( - _In_ HWND ParentWindowHandle, - _In_ HWND TreeNewHandle, - _Out_ PPH_MEMORY_LIST_CONTEXT Context - ) -{ - HWND hwnd; - - memset(Context, 0, sizeof(PH_MEMORY_LIST_CONTEXT)); - - Context->AllocationBaseNodeList = PhCreateList(100); - Context->RegionNodeList = PhCreateList(400); - - Context->ParentWindowHandle = ParentWindowHandle; - Context->TreeNewHandle = TreeNewHandle; - hwnd = TreeNewHandle; - PhSetControlTheme(hwnd, L"explorer"); - - TreeNew_SetCallback(hwnd, PhpMemoryTreeNewCallback, Context); - - TreeNew_SetRedraw(hwnd, FALSE); - - // Default columns - PhAddTreeNewColumn(hwnd, PHMMTLC_BASEADDRESS, TRUE, L"Base address", 120, PH_ALIGN_LEFT, -2, 0); - PhAddTreeNewColumn(hwnd, PHMMTLC_TYPE, TRUE, L"Type", 90, PH_ALIGN_LEFT, 0, 0); - PhAddTreeNewColumnEx(hwnd, PHMMTLC_SIZE, TRUE, L"Size", 80, PH_ALIGN_RIGHT, 1, DT_RIGHT, TRUE); - PhAddTreeNewColumn(hwnd, PHMMTLC_PROTECTION, TRUE, L"Protection", 60, PH_ALIGN_LEFT, 2, 0); - PhAddTreeNewColumn(hwnd, PHMMTLC_USE, TRUE, L"Use", 200, PH_ALIGN_LEFT, 3, 0); - PhAddTreeNewColumnEx(hwnd, PHMMTLC_TOTALWS, TRUE, L"Total WS", 80, PH_ALIGN_RIGHT, 4, DT_RIGHT, TRUE); - PhAddTreeNewColumnEx(hwnd, PHMMTLC_PRIVATEWS, TRUE, L"Private WS", 80, PH_ALIGN_RIGHT, 5, DT_RIGHT, TRUE); - PhAddTreeNewColumnEx(hwnd, PHMMTLC_SHAREABLEWS, TRUE, L"Shareable WS", 80, PH_ALIGN_RIGHT, 6, DT_RIGHT, TRUE); - PhAddTreeNewColumnEx(hwnd, PHMMTLC_SHAREDWS, TRUE, L"Shared WS", 80, PH_ALIGN_RIGHT, 7, DT_RIGHT, TRUE); - PhAddTreeNewColumnEx(hwnd, PHMMTLC_LOCKEDWS, TRUE, L"Locked WS", 80, PH_ALIGN_RIGHT, 8, DT_RIGHT, TRUE); - - PhAddTreeNewColumnEx(hwnd, PHMMTLC_COMMITTED, FALSE, L"Committed", 80, PH_ALIGN_RIGHT, 9, DT_RIGHT, TRUE); - PhAddTreeNewColumnEx(hwnd, PHMMTLC_PRIVATE, FALSE, L"Private", 80, PH_ALIGN_RIGHT, 10, DT_RIGHT, TRUE); - - TreeNew_SetRedraw(hwnd, TRUE); - - TreeNew_SetTriState(hwnd, TRUE); - TreeNew_SetSort(hwnd, 0, NoSortOrder); - - PhCmInitializeManager(&Context->Cm, hwnd, PHMMTLC_MAXIMUM, PhpMemoryTreeNewPostSortFunction); -} - -VOID PhpClearMemoryList( - _Inout_ PPH_MEMORY_LIST_CONTEXT Context - ) -{ - ULONG i; - - for (i = 0; i < Context->AllocationBaseNodeList->Count; i++) - PhpDestroyMemoryNode(Context->AllocationBaseNodeList->Items[i]); - for (i = 0; i < Context->RegionNodeList->Count; i++) - PhpDestroyMemoryNode(Context->RegionNodeList->Items[i]); - - PhClearList(Context->AllocationBaseNodeList); - PhClearList(Context->RegionNodeList); -} - -VOID PhDeleteMemoryList( - _In_ PPH_MEMORY_LIST_CONTEXT Context - ) -{ - PhCmDeleteManager(&Context->Cm); - - PhpClearMemoryList(Context); - PhDereferenceObject(Context->AllocationBaseNodeList); - PhDereferenceObject(Context->RegionNodeList); -} - -VOID PhLoadSettingsMemoryList( - _Inout_ PPH_MEMORY_LIST_CONTEXT Context - ) -{ - PPH_STRING settings; - PPH_STRING sortSettings; - - settings = PhGetStringSetting(L"MemoryTreeListColumns"); - sortSettings = PhGetStringSetting(L"MemoryTreeListSort"); - PhCmLoadSettingsEx(Context->TreeNewHandle, &Context->Cm, 0, &settings->sr, &sortSettings->sr); - PhDereferenceObject(settings); - PhDereferenceObject(sortSettings); -} - -VOID PhSaveSettingsMemoryList( - _Inout_ PPH_MEMORY_LIST_CONTEXT Context - ) -{ - PPH_STRING settings; - PPH_STRING sortSettings; - - settings = PhCmSaveSettingsEx(Context->TreeNewHandle, &Context->Cm, 0, &sortSettings); - PhSetStringSetting2(L"MemoryTreeListColumns", &settings->sr); - PhSetStringSetting2(L"MemoryTreeListSort", &sortSettings->sr); - PhDereferenceObject(settings); - PhDereferenceObject(sortSettings); -} - -VOID PhSetOptionsMemoryList( - _Inout_ PPH_MEMORY_LIST_CONTEXT Context, - _In_ BOOLEAN HideFreeRegions - ) -{ - ULONG i; - ULONG k; - BOOLEAN modified; - - if (Context->HideFreeRegions != HideFreeRegions) - { - PPH_LIST lists[2]; - - Context->HideFreeRegions = HideFreeRegions; - modified = FALSE; - lists[0] = Context->AllocationBaseNodeList; - lists[1] = Context->RegionNodeList; - - for (k = 0; k < 2; k++) - { - for (i = 0; i < lists[k]->Count; i++) - { - PPH_MEMORY_NODE node = lists[k]->Items[i]; - BOOLEAN visible; - - visible = TRUE; - - if (HideFreeRegions && (node->MemoryItem->State & MEM_FREE)) - visible = FALSE; - - if (node->Node.Visible != visible) - { - node->Node.Visible = visible; - modified = TRUE; - - if (!visible) - node->Node.Selected = FALSE; - } - } - } - - if (modified) - { - TreeNew_NodesStructured(Context->TreeNewHandle); - } - } -} - -VOID PhpDestroyMemoryNode( - _In_ PPH_MEMORY_NODE MemoryNode - ) -{ - PhEmCallObjectOperation(EmMemoryNodeType, MemoryNode, EmObjectDelete); - - PhClearReference(&MemoryNode->SizeText); - PhClearReference(&MemoryNode->UseText); - PhClearReference(&MemoryNode->TotalWsText); - PhClearReference(&MemoryNode->PrivateWsText); - PhClearReference(&MemoryNode->ShareableWsText); - PhClearReference(&MemoryNode->SharedWsText); - PhClearReference(&MemoryNode->LockedWsText); - PhClearReference(&MemoryNode->CommittedText); - PhClearReference(&MemoryNode->PrivateText); - - PhClearReference(&MemoryNode->Children); - PhDereferenceObject(MemoryNode->MemoryItem); - - PhFree(MemoryNode); -} - -PPH_MEMORY_NODE PhpAddAllocationBaseNode( - _Inout_ PPH_MEMORY_LIST_CONTEXT Context, - _In_ PVOID AllocationBase - ) -{ - PPH_MEMORY_NODE memoryNode; - PPH_MEMORY_ITEM memoryItem; - - memoryNode = PhAllocate(PhEmGetObjectSize(EmMemoryNodeType, sizeof(PH_MEMORY_NODE))); - memset(memoryNode, 0, sizeof(PH_MEMORY_NODE)); - PhInitializeTreeNewNode(&memoryNode->Node); - memoryNode->Node.Expanded = FALSE; - - memoryNode->IsAllocationBase = TRUE; - memoryItem = PhCreateMemoryItem(); - memoryNode->MemoryItem = memoryItem; - - memoryItem->BaseAddress = AllocationBase; - memoryItem->AllocationBase = AllocationBase; - - memoryNode->Children = PhCreateList(1); - - memset(memoryNode->TextCache, 0, sizeof(PH_STRINGREF) * PHMMTLC_MAXIMUM); - memoryNode->Node.TextCache = memoryNode->TextCache; - memoryNode->Node.TextCacheSize = PHMMTLC_MAXIMUM; - - PhAddItemList(Context->AllocationBaseNodeList, memoryNode); - - PhEmCallObjectOperation(EmMemoryNodeType, memoryNode, EmObjectCreate); - - return memoryNode; -} - -PPH_MEMORY_NODE PhpAddRegionNode( - _Inout_ PPH_MEMORY_LIST_CONTEXT Context, - _In_ PPH_MEMORY_ITEM MemoryItem - ) -{ - PPH_MEMORY_NODE memoryNode; - - memoryNode = PhAllocate(PhEmGetObjectSize(EmMemoryNodeType, sizeof(PH_MEMORY_NODE))); - memset(memoryNode, 0, sizeof(PH_MEMORY_NODE)); - PhInitializeTreeNewNode(&memoryNode->Node); - - memoryNode->IsAllocationBase = FALSE; - memoryNode->MemoryItem = MemoryItem; - PhReferenceObject(MemoryItem); - - memset(memoryNode->TextCache, 0, sizeof(PH_STRINGREF) * PHMMTLC_MAXIMUM); - memoryNode->Node.TextCache = memoryNode->TextCache; - memoryNode->Node.TextCacheSize = PHMMTLC_MAXIMUM; - - PhAddItemList(Context->RegionNodeList, memoryNode); - - PhEmCallObjectOperation(EmMemoryNodeType, memoryNode, EmObjectCreate); - - return memoryNode; -} - -VOID PhpCopyMemoryRegionTypeInfo( - _In_ PPH_MEMORY_ITEM Source, - _Inout_ PPH_MEMORY_ITEM Destination - ) -{ - if (Destination->RegionType == CustomRegion) - PhClearReference(&Destination->u.Custom.Text); - else if (Destination->RegionType == MappedFileRegion) - PhClearReference(&Destination->u.MappedFile.FileName); - - Destination->RegionType = Source->RegionType; - Destination->u = Source->u; - - if (Destination->RegionType == CustomRegion) - PhReferenceObject(Destination->u.Custom.Text); - else if (Destination->RegionType == MappedFileRegion) - PhReferenceObject(Destination->u.MappedFile.FileName); -} - -VOID PhReplaceMemoryList( - _Inout_ PPH_MEMORY_LIST_CONTEXT Context, - _In_opt_ PPH_MEMORY_ITEM_LIST List - ) -{ - PLIST_ENTRY listEntry; - PPH_MEMORY_NODE allocationBaseNode = NULL; - - PhpClearMemoryList(Context); - - if (!List) - { - TreeNew_NodesStructured(Context->TreeNewHandle); - return; - } - - for (listEntry = List->ListHead.Flink; listEntry != &List->ListHead; listEntry = listEntry->Flink) - { - PPH_MEMORY_ITEM memoryItem = CONTAINING_RECORD(listEntry, PH_MEMORY_ITEM, ListEntry); - PPH_MEMORY_NODE memoryNode; - - if (memoryItem->AllocationBaseItem == memoryItem) - allocationBaseNode = PhpAddAllocationBaseNode(Context, memoryItem->AllocationBase); - - memoryNode = PhpAddRegionNode(Context, memoryItem); - - if (Context->HideFreeRegions && (memoryItem->State & MEM_FREE)) - memoryNode->Node.Visible = FALSE; - - if (allocationBaseNode && memoryItem->AllocationBase == allocationBaseNode->MemoryItem->BaseAddress) - { - if (!(memoryItem->State & MEM_FREE)) - { - memoryNode->Parent = allocationBaseNode; - PhAddItemList(allocationBaseNode->Children, memoryNode); - } - - // Aggregate various statistics. - allocationBaseNode->MemoryItem->RegionSize += memoryItem->RegionSize; - allocationBaseNode->MemoryItem->CommittedSize += memoryItem->CommittedSize; - allocationBaseNode->MemoryItem->PrivateSize += memoryItem->PrivateSize; - allocationBaseNode->MemoryItem->TotalWorkingSetPages += memoryItem->TotalWorkingSetPages; - allocationBaseNode->MemoryItem->PrivateWorkingSetPages += memoryItem->PrivateWorkingSetPages; - allocationBaseNode->MemoryItem->SharedWorkingSetPages += memoryItem->SharedWorkingSetPages; - allocationBaseNode->MemoryItem->ShareableWorkingSetPages += memoryItem->ShareableWorkingSetPages; - allocationBaseNode->MemoryItem->LockedWorkingSetPages += memoryItem->LockedWorkingSetPages; - - if (memoryItem->AllocationBaseItem == memoryItem) - { - if (memoryItem->State & MEM_FREE) - allocationBaseNode->MemoryItem->State = MEM_FREE; - - allocationBaseNode->MemoryItem->Protect = memoryItem->AllocationProtect; - PhGetMemoryProtectionString(allocationBaseNode->MemoryItem->Protect, allocationBaseNode->ProtectionText); - allocationBaseNode->MemoryItem->Type = memoryItem->Type; - - if (memoryItem->RegionType != CustomRegion || memoryItem->u.Custom.PropertyOfAllocationBase) - PhpCopyMemoryRegionTypeInfo(memoryItem, allocationBaseNode->MemoryItem); - - if (Context->HideFreeRegions && (allocationBaseNode->MemoryItem->State & MEM_FREE)) - allocationBaseNode->Node.Visible = FALSE; - } - else - { - if (memoryItem->RegionType == UnknownRegion) - PhpCopyMemoryRegionTypeInfo(allocationBaseNode->MemoryItem, memoryItem); - } - } - - PhGetMemoryProtectionString(memoryItem->Protect, memoryNode->ProtectionText); - } - - TreeNew_NodesStructured(Context->TreeNewHandle); -} - -VOID PhUpdateMemoryNode( - _In_ PPH_MEMORY_LIST_CONTEXT Context, - _In_ PPH_MEMORY_NODE MemoryNode - ) -{ - PhGetMemoryProtectionString(MemoryNode->MemoryItem->Protect, MemoryNode->ProtectionText); - memset(MemoryNode->TextCache, 0, sizeof(PH_STRINGREF) * PHMMTLC_MAXIMUM); - TreeNew_InvalidateNode(Context->TreeNewHandle, &MemoryNode->Node); -} - -PPH_STRING PhpGetMemoryRegionUseText( - _In_ PPH_MEMORY_ITEM MemoryItem - ) -{ - PH_MEMORY_REGION_TYPE type = MemoryItem->RegionType; - - switch (type) - { - case UnknownRegion: - return PhReferenceEmptyString(); - case CustomRegion: - PhReferenceObject(MemoryItem->u.Custom.Text); - return MemoryItem->u.Custom.Text; - case UnusableRegion: - return PhReferenceEmptyString(); - case MappedFileRegion: - PhReferenceObject(MemoryItem->u.MappedFile.FileName); - return MemoryItem->u.MappedFile.FileName; - case UserSharedDataRegion: - return PhCreateString(L"USER_SHARED_DATA"); - case PebRegion: - case Peb32Region: - return PhFormatString(L"PEB%s", type == Peb32Region ? L" 32-bit" : L""); - case TebRegion: - case Teb32Region: - return PhFormatString(L"TEB%s (thread %u)", - type == Teb32Region ? L" 32-bit" : L"", HandleToUlong(MemoryItem->u.Teb.ThreadId)); - case StackRegion: - case Stack32Region: - return PhFormatString(L"Stack%s (thread %u)", - type == Stack32Region ? L" 32-bit" : L"", HandleToUlong(MemoryItem->u.Stack.ThreadId)); - case HeapRegion: - case Heap32Region: - return PhFormatString(L"Heap%s (ID %u)", - type == Heap32Region ? L" 32-bit" : L"", (ULONG)MemoryItem->u.Heap.Index + 1); - case HeapSegmentRegion: - case HeapSegment32Region: - return PhFormatString(L"Heap segment%s (ID %u)", - type == HeapSegment32Region ? L" 32-bit" : L"", (ULONG)MemoryItem->u.HeapSegment.HeapItem->u.Heap.Index + 1); - case CfgBitmapRegion: - return PhFormatString(L"CFG Bitmap"); - default: - return PhReferenceEmptyString(); - } -} - -VOID PhpUpdateMemoryNodeUseText( - _Inout_ PPH_MEMORY_NODE MemoryNode - ) -{ - if (!MemoryNode->UseText) - MemoryNode->UseText = PhpGetMemoryRegionUseText(MemoryNode->MemoryItem); -} - -PPH_STRING PhpFormatSizeIfNonZero( - _In_ ULONG64 Size - ) -{ - if (Size != 0) - return PhFormatSize(Size, -1); - else - return NULL; -} - -#define SORT_FUNCTION(Column) PhpMemoryTreeNewCompare##Column - -#define BEGIN_SORT_FUNCTION(Column) static int __cdecl PhpMemoryTreeNewCompare##Column( \ - _In_ void *_context, \ - _In_ const void *_elem1, \ - _In_ const void *_elem2 \ - ) \ -{ \ - PPH_MEMORY_NODE node1 = *(PPH_MEMORY_NODE *)_elem1; \ - PPH_MEMORY_NODE node2 = *(PPH_MEMORY_NODE *)_elem2; \ - PPH_MEMORY_ITEM memoryItem1 = node1->MemoryItem; \ - PPH_MEMORY_ITEM memoryItem2 = node2->MemoryItem; \ - int sortResult = 0; - -#define END_SORT_FUNCTION \ - if (sortResult == 0) \ - sortResult = uintptrcmp((ULONG_PTR)memoryItem1->BaseAddress, (ULONG_PTR)memoryItem2->BaseAddress); \ - \ - return PhModifySort(sortResult, ((PPH_MEMORY_LIST_CONTEXT)_context)->TreeNewSortOrder); \ -} - -LONG PhpMemoryTreeNewPostSortFunction( - _In_ LONG Result, - _In_ PVOID Node1, - _In_ PVOID Node2, - _In_ PH_SORT_ORDER SortOrder - ) -{ - if (Result == 0) - Result = uintptrcmp((ULONG_PTR)((PPH_MEMORY_NODE)Node1)->MemoryItem->BaseAddress, (ULONG_PTR)((PPH_MEMORY_NODE)Node2)->MemoryItem->BaseAddress); - - return PhModifySort(Result, SortOrder); -} - -BEGIN_SORT_FUNCTION(BaseAddress) -{ - sortResult = uintptrcmp((ULONG_PTR)memoryItem1->BaseAddress, (ULONG_PTR)memoryItem2->BaseAddress); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(Type) -{ - sortResult = uintcmp(memoryItem1->Type | memoryItem1->State, memoryItem2->Type | memoryItem2->State); - - if (sortResult == 0) - sortResult = intcmp(memoryItem1->RegionType, memoryItem2->RegionType); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(Size) -{ - sortResult = uintptrcmp(memoryItem1->RegionSize, memoryItem2->RegionSize); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(Protection) -{ - sortResult = PhCompareStringZ(node1->ProtectionText, node2->ProtectionText, FALSE); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(Use) -{ - PhpUpdateMemoryNodeUseText(node1); - PhpUpdateMemoryNodeUseText(node2); - sortResult = PhCompareStringWithNull(node1->UseText, node2->UseText, TRUE); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(TotalWs) -{ - sortResult = uintptrcmp(memoryItem1->TotalWorkingSetPages, memoryItem2->TotalWorkingSetPages); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(PrivateWs) -{ - sortResult = uintptrcmp(memoryItem1->PrivateWorkingSetPages, memoryItem2->PrivateWorkingSetPages); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(ShareableWs) -{ - sortResult = uintptrcmp(memoryItem1->ShareableWorkingSetPages, memoryItem2->ShareableWorkingSetPages); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(SharedWs) -{ - sortResult = uintptrcmp(memoryItem1->SharedWorkingSetPages, memoryItem2->SharedWorkingSetPages); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(LockedWs) -{ - sortResult = uintptrcmp(memoryItem1->LockedWorkingSetPages, memoryItem2->LockedWorkingSetPages); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(Committed) -{ - sortResult = uintptrcmp(memoryItem1->CommittedSize, memoryItem2->CommittedSize); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(Private) -{ - sortResult = uintptrcmp(memoryItem1->PrivateSize, memoryItem2->PrivateSize); -} -END_SORT_FUNCTION - -BOOLEAN NTAPI PhpMemoryTreeNewCallback( - _In_ HWND hwnd, - _In_ PH_TREENEW_MESSAGE Message, - _In_opt_ PVOID Parameter1, - _In_opt_ PVOID Parameter2, - _In_opt_ PVOID Context - ) -{ - PPH_MEMORY_LIST_CONTEXT context; - PPH_MEMORY_NODE node; - - context = Context; - - if (PhCmForwardMessage(hwnd, Message, Parameter1, Parameter2, &context->Cm)) - return TRUE; - - switch (Message) - { - case TreeNewGetChildren: - { - PPH_TREENEW_GET_CHILDREN getChildren = Parameter1; - - node = (PPH_MEMORY_NODE)getChildren->Node; - - if (context->TreeNewSortOrder == NoSortOrder) - { - if (!node) - { - getChildren->Children = (PPH_TREENEW_NODE *)context->AllocationBaseNodeList->Items; - getChildren->NumberOfChildren = context->AllocationBaseNodeList->Count; - } - else - { - getChildren->Children = (PPH_TREENEW_NODE *)node->Children->Items; - getChildren->NumberOfChildren = node->Children->Count; - } - } - else - { - if (!node) - { - static PVOID sortFunctions[] = - { - SORT_FUNCTION(BaseAddress), - SORT_FUNCTION(Type), - SORT_FUNCTION(Size), - SORT_FUNCTION(Protection), - SORT_FUNCTION(Use), - SORT_FUNCTION(TotalWs), - SORT_FUNCTION(PrivateWs), - SORT_FUNCTION(ShareableWs), - SORT_FUNCTION(SharedWs), - SORT_FUNCTION(LockedWs), - SORT_FUNCTION(Committed), - SORT_FUNCTION(Private) - }; - int (__cdecl *sortFunction)(void *, const void *, const void *); - - if (!PhCmForwardSort( - (PPH_TREENEW_NODE *)context->RegionNodeList->Items, - context->RegionNodeList->Count, - context->TreeNewSortColumn, - context->TreeNewSortOrder, - &context->Cm - )) - { - if (context->TreeNewSortColumn < PHMMTLC_MAXIMUM) - sortFunction = sortFunctions[context->TreeNewSortColumn]; - else - sortFunction = NULL; - } - else - { - sortFunction = NULL; - } - - if (sortFunction) - { - qsort_s(context->RegionNodeList->Items, context->RegionNodeList->Count, sizeof(PVOID), sortFunction, context); - } - - getChildren->Children = (PPH_TREENEW_NODE *)context->RegionNodeList->Items; - getChildren->NumberOfChildren = context->RegionNodeList->Count; - } - } - } - return TRUE; - case TreeNewIsLeaf: - { - PPH_TREENEW_IS_LEAF isLeaf = Parameter1; - - node = (PPH_MEMORY_NODE)isLeaf->Node; - - if (context->TreeNewSortOrder == NoSortOrder) - isLeaf->IsLeaf = !node->Children || node->Children->Count == 0; - else - isLeaf->IsLeaf = TRUE; - } - return TRUE; - case TreeNewGetCellText: - { - PPH_TREENEW_GET_CELL_TEXT getCellText = Parameter1; - PPH_MEMORY_ITEM memoryItem; - - node = (PPH_MEMORY_NODE)getCellText->Node; - memoryItem = node->MemoryItem; - - switch (getCellText->Id) - { - case PHMMTLC_BASEADDRESS: - PhPrintPointer(node->BaseAddressText, memoryItem->BaseAddress); - PhInitializeStringRefLongHint(&getCellText->Text, node->BaseAddressText); - break; - case PHMMTLC_TYPE: - if (memoryItem->State & MEM_FREE) - { - if (memoryItem->RegionType == UnusableRegion) - PhInitializeStringRef(&getCellText->Text, L"Free (Unusable)"); - else - PhInitializeStringRef(&getCellText->Text, L"Free"); - } - else if (node->IsAllocationBase) - { - PhInitializeStringRefLongHint(&getCellText->Text, PhGetMemoryTypeString(memoryItem->Type)); - } - else - { - PH_FORMAT format[3]; - SIZE_T returnLength; - - PhInitFormatS(&format[0], PhGetMemoryTypeString(memoryItem->Type)); - PhInitFormatS(&format[1], L": "); - PhInitFormatS(&format[2], PhGetMemoryStateString(memoryItem->State)); - - if (PhFormatToBuffer(format, 3, node->TypeText, sizeof(node->TypeText), &returnLength)) - { - getCellText->Text.Buffer = node->TypeText; - getCellText->Text.Length = returnLength - sizeof(WCHAR); - } - } - break; - case PHMMTLC_SIZE: - PhMoveReference(&node->SizeText, PhFormatSize(memoryItem->RegionSize, -1)); - getCellText->Text = PhGetStringRef(node->SizeText); - break; - case PHMMTLC_PROTECTION: - PhInitializeStringRefLongHint(&getCellText->Text, node->ProtectionText); - break; - case PHMMTLC_USE: - PhpUpdateMemoryNodeUseText(node); - getCellText->Text = PhGetStringRef(node->UseText); - break; - case PHMMTLC_TOTALWS: - PhMoveReference(&node->TotalWsText, PhpFormatSizeIfNonZero((ULONG64)memoryItem->TotalWorkingSetPages * PAGE_SIZE)); - getCellText->Text = PhGetStringRef(node->TotalWsText); - break; - case PHMMTLC_PRIVATEWS: - PhMoveReference(&node->PrivateWsText, PhpFormatSizeIfNonZero((ULONG64)memoryItem->PrivateWorkingSetPages * PAGE_SIZE)); - getCellText->Text = PhGetStringRef(node->PrivateWsText); - break; - case PHMMTLC_SHAREABLEWS: - PhMoveReference(&node->ShareableWsText, PhpFormatSizeIfNonZero((ULONG64)memoryItem->ShareableWorkingSetPages * PAGE_SIZE)); - getCellText->Text = PhGetStringRef(node->ShareableWsText); - break; - case PHMMTLC_SHAREDWS: - PhMoveReference(&node->SharedWsText, PhpFormatSizeIfNonZero((ULONG64)memoryItem->SharedWorkingSetPages * PAGE_SIZE)); - getCellText->Text = PhGetStringRef(node->SharedWsText); - break; - case PHMMTLC_LOCKEDWS: - PhMoveReference(&node->LockedWsText, PhpFormatSizeIfNonZero((ULONG64)memoryItem->LockedWorkingSetPages * PAGE_SIZE)); - getCellText->Text = PhGetStringRef(node->LockedWsText); - break; - case PHMMTLC_COMMITTED: - PhMoveReference(&node->CommittedText, PhpFormatSizeIfNonZero(memoryItem->CommittedSize)); - getCellText->Text = PhGetStringRef(node->CommittedText); - break; - case PHMMTLC_PRIVATE: - PhMoveReference(&node->PrivateText, PhpFormatSizeIfNonZero(memoryItem->PrivateSize)); - getCellText->Text = PhGetStringRef(node->PrivateText); - break; - default: - return FALSE; - } - - getCellText->Flags = TN_CACHE; - } - return TRUE; - case TreeNewGetNodeColor: - { - //PPH_TREENEW_GET_NODE_COLOR getNodeColor = Parameter1; - //PPH_MEMORY_ITEM memoryItem; - - //node = (PPH_MEMORY_NODE)getNodeColor->Node; - //memoryItem = node->MemoryItem; - - //if (!memoryItem) - // ; // Dummy - //else if (PhCsUseColorRelocatedModules && (memoryItem->Protect & PAGE_EXECUTE_WRITECOPY)) - // getNodeColor->BackColor = PhCsColorRelocatedModules; - //else if (PhCsUseColorRelocatedModules && (memoryItem->Protect & PAGE_EXECUTE_READWRITE)) - // getNodeColor->BackColor = PhCsColorRelocatedModules; - //else if (PhCsUseColorSystemProcesses && (memoryItem->Type & MEM_PRIVATE)) - // getNodeColor->BackColor = PhCsColorSystemProcesses; - - //getNodeColor->Flags = TN_CACHE | TN_AUTO_FORECOLOR; - } - return TRUE; - case TreeNewSortChanged: - { - TreeNew_GetSort(hwnd, &context->TreeNewSortColumn, &context->TreeNewSortOrder); - // Force a rebuild to sort the items. - TreeNew_NodesStructured(hwnd); - } - return TRUE; - case TreeNewKeyDown: - { - PPH_TREENEW_KEY_EVENT keyEvent = Parameter1; - - switch (keyEvent->VirtualKey) - { - case 'C': - if (GetKeyState(VK_CONTROL) < 0) - SendMessage(context->ParentWindowHandle, WM_COMMAND, ID_MEMORY_COPY, 0); - break; - case 'A': - if (GetKeyState(VK_CONTROL) < 0) - TreeNew_SelectRange(context->TreeNewHandle, 0, -1); - break; - case VK_RETURN: - SendMessage(context->ParentWindowHandle, WM_COMMAND, ID_MEMORY_READWRITEMEMORY, 0); - break; - case VK_F5: - SendMessage(context->ParentWindowHandle, WM_COMMAND, IDC_REFRESH, 0); - break; - } - } - return TRUE; - case TreeNewHeaderRightClick: - { - PH_TN_COLUMN_MENU_DATA data; - - data.TreeNewHandle = hwnd; - data.MouseEvent = Parameter1; - data.DefaultSortColumn = 0; - data.DefaultSortOrder = NoSortOrder; - PhInitializeTreeNewColumnMenuEx(&data, PH_TN_COLUMN_MENU_SHOW_RESET_SORT); - - data.Selection = PhShowEMenu(data.Menu, hwnd, PH_EMENU_SHOW_LEFTRIGHT, - PH_ALIGN_LEFT | PH_ALIGN_TOP, data.MouseEvent->ScreenLocation.x, data.MouseEvent->ScreenLocation.y); - PhHandleTreeNewColumnMenu(&data); - PhDeleteTreeNewColumnMenu(&data); - } - return TRUE; - case TreeNewLeftDoubleClick: - { - PPH_TREENEW_MOUSE_EVENT mouseEvent = Parameter1; - - node = (PPH_MEMORY_NODE)mouseEvent->Node; - - if (node && node->IsAllocationBase) - TreeNew_SetNodeExpanded(hwnd, node, !node->Node.Expanded); - else - SendMessage(context->ParentWindowHandle, WM_COMMAND, ID_MEMORY_READWRITEMEMORY, 0); - } - return TRUE; - case TreeNewContextMenu: - { - PPH_TREENEW_CONTEXT_MENU contextMenu = Parameter1; - - SendMessage(context->ParentWindowHandle, WM_COMMAND, ID_SHOWCONTEXTMENU, (LPARAM)contextMenu); - } - return TRUE; - case TreeNewGetDialogCode: - { - PULONG code = Parameter2; - - if (PtrToUlong(Parameter1) == VK_RETURN) - { - *code = DLGC_WANTMESSAGE; - return TRUE; - } - } - return FALSE; - } - - return FALSE; -} - -PPH_MEMORY_NODE PhGetSelectedMemoryNode( - _In_ PPH_MEMORY_LIST_CONTEXT Context - ) -{ - ULONG i; - - if (Context->TreeNewSortOrder == NoSortOrder) - { - for (i = 0; i < Context->AllocationBaseNodeList->Count; i++) - { - PPH_MEMORY_NODE node = Context->AllocationBaseNodeList->Items[i]; - - if (node->Node.Selected) - return node; - } - } - - for (i = 0; i < Context->RegionNodeList->Count; i++) - { - PPH_MEMORY_NODE node = Context->RegionNodeList->Items[i]; - - if (node->Node.Selected) - return node; - } - - return NULL; -} - -VOID PhGetSelectedMemoryNodes( - _In_ PPH_MEMORY_LIST_CONTEXT Context, - _Out_ PPH_MEMORY_NODE **MemoryNodes, - _Out_ PULONG NumberOfMemoryNodes - ) -{ - PH_ARRAY array; - ULONG i; - - PhInitializeArray(&array, sizeof(PVOID), 2); - - if (Context->TreeNewSortOrder == NoSortOrder) - { - for (i = 0; i < Context->AllocationBaseNodeList->Count; i++) - { - PPH_MEMORY_NODE node = Context->AllocationBaseNodeList->Items[i]; - - if (node->Node.Selected) - PhAddItemArray(&array, &node); - } - } - - for (i = 0; i < Context->RegionNodeList->Count; i++) - { - PPH_MEMORY_NODE node = Context->RegionNodeList->Items[i]; - - if (node->Node.Selected) - PhAddItemArray(&array, &node); - } - - *NumberOfMemoryNodes = (ULONG)array.Count; - *MemoryNodes = PhFinalArrayItems(&array); -} - -VOID PhDeselectAllMemoryNodes( - _In_ PPH_MEMORY_LIST_CONTEXT Context - ) -{ - TreeNew_DeselectRange(Context->TreeNewHandle, 0, -1); -} +/* + * Process Hacker - + * memory region list + * + * Copyright (C) 2015 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include +#include + +#include + +#include +#include +#include +#include + +VOID PhpClearMemoryList( + _Inout_ PPH_MEMORY_LIST_CONTEXT Context + ); + +VOID PhpDestroyMemoryNode( + _In_ PPH_MEMORY_NODE MemoryNode + ); + +LONG PhpMemoryTreeNewPostSortFunction( + _In_ LONG Result, + _In_ PVOID Node1, + _In_ PVOID Node2, + _In_ PH_SORT_ORDER SortOrder + ); + +BOOLEAN NTAPI PhpMemoryTreeNewCallback( + _In_ HWND hwnd, + _In_ PH_TREENEW_MESSAGE Message, + _In_opt_ PVOID Parameter1, + _In_opt_ PVOID Parameter2, + _In_opt_ PVOID Context + ); + +VOID PhInitializeMemoryList( + _In_ HWND ParentWindowHandle, + _In_ HWND TreeNewHandle, + _Out_ PPH_MEMORY_LIST_CONTEXT Context + ) +{ + HWND hwnd; + + memset(Context, 0, sizeof(PH_MEMORY_LIST_CONTEXT)); + + Context->AllocationBaseNodeList = PhCreateList(100); + Context->RegionNodeList = PhCreateList(400); + + Context->ParentWindowHandle = ParentWindowHandle; + Context->TreeNewHandle = TreeNewHandle; + hwnd = TreeNewHandle; + PhSetControlTheme(hwnd, L"explorer"); + + TreeNew_SetCallback(hwnd, PhpMemoryTreeNewCallback, Context); + + TreeNew_SetRedraw(hwnd, FALSE); + + // Default columns + PhAddTreeNewColumn(hwnd, PHMMTLC_BASEADDRESS, TRUE, L"Base address", 120, PH_ALIGN_LEFT, -2, 0); + PhAddTreeNewColumn(hwnd, PHMMTLC_TYPE, TRUE, L"Type", 90, PH_ALIGN_LEFT, 0, 0); + PhAddTreeNewColumnEx(hwnd, PHMMTLC_SIZE, TRUE, L"Size", 80, PH_ALIGN_RIGHT, 1, DT_RIGHT, TRUE); + PhAddTreeNewColumn(hwnd, PHMMTLC_PROTECTION, TRUE, L"Protection", 60, PH_ALIGN_LEFT, 2, 0); + PhAddTreeNewColumn(hwnd, PHMMTLC_USE, TRUE, L"Use", 200, PH_ALIGN_LEFT, 3, 0); + PhAddTreeNewColumnEx(hwnd, PHMMTLC_TOTALWS, TRUE, L"Total WS", 80, PH_ALIGN_RIGHT, 4, DT_RIGHT, TRUE); + PhAddTreeNewColumnEx(hwnd, PHMMTLC_PRIVATEWS, TRUE, L"Private WS", 80, PH_ALIGN_RIGHT, 5, DT_RIGHT, TRUE); + PhAddTreeNewColumnEx(hwnd, PHMMTLC_SHAREABLEWS, TRUE, L"Shareable WS", 80, PH_ALIGN_RIGHT, 6, DT_RIGHT, TRUE); + PhAddTreeNewColumnEx(hwnd, PHMMTLC_SHAREDWS, TRUE, L"Shared WS", 80, PH_ALIGN_RIGHT, 7, DT_RIGHT, TRUE); + PhAddTreeNewColumnEx(hwnd, PHMMTLC_LOCKEDWS, TRUE, L"Locked WS", 80, PH_ALIGN_RIGHT, 8, DT_RIGHT, TRUE); + + PhAddTreeNewColumnEx(hwnd, PHMMTLC_COMMITTED, FALSE, L"Committed", 80, PH_ALIGN_RIGHT, 9, DT_RIGHT, TRUE); + PhAddTreeNewColumnEx(hwnd, PHMMTLC_PRIVATE, FALSE, L"Private", 80, PH_ALIGN_RIGHT, 10, DT_RIGHT, TRUE); + + TreeNew_SetRedraw(hwnd, TRUE); + + TreeNew_SetTriState(hwnd, TRUE); + TreeNew_SetSort(hwnd, 0, NoSortOrder); + + PhCmInitializeManager(&Context->Cm, hwnd, PHMMTLC_MAXIMUM, PhpMemoryTreeNewPostSortFunction); +} + +VOID PhpClearMemoryList( + _Inout_ PPH_MEMORY_LIST_CONTEXT Context + ) +{ + ULONG i; + + for (i = 0; i < Context->AllocationBaseNodeList->Count; i++) + PhpDestroyMemoryNode(Context->AllocationBaseNodeList->Items[i]); + for (i = 0; i < Context->RegionNodeList->Count; i++) + PhpDestroyMemoryNode(Context->RegionNodeList->Items[i]); + + PhClearList(Context->AllocationBaseNodeList); + PhClearList(Context->RegionNodeList); +} + +VOID PhDeleteMemoryList( + _In_ PPH_MEMORY_LIST_CONTEXT Context + ) +{ + PhCmDeleteManager(&Context->Cm); + + PhpClearMemoryList(Context); + PhDereferenceObject(Context->AllocationBaseNodeList); + PhDereferenceObject(Context->RegionNodeList); +} + +VOID PhLoadSettingsMemoryList( + _Inout_ PPH_MEMORY_LIST_CONTEXT Context + ) +{ + PPH_STRING settings; + PPH_STRING sortSettings; + + settings = PhGetStringSetting(L"MemoryTreeListColumns"); + sortSettings = PhGetStringSetting(L"MemoryTreeListSort"); + PhCmLoadSettingsEx(Context->TreeNewHandle, &Context->Cm, 0, &settings->sr, &sortSettings->sr); + PhDereferenceObject(settings); + PhDereferenceObject(sortSettings); +} + +VOID PhSaveSettingsMemoryList( + _Inout_ PPH_MEMORY_LIST_CONTEXT Context + ) +{ + PPH_STRING settings; + PPH_STRING sortSettings; + + settings = PhCmSaveSettingsEx(Context->TreeNewHandle, &Context->Cm, 0, &sortSettings); + PhSetStringSetting2(L"MemoryTreeListColumns", &settings->sr); + PhSetStringSetting2(L"MemoryTreeListSort", &sortSettings->sr); + PhDereferenceObject(settings); + PhDereferenceObject(sortSettings); +} + +VOID PhSetOptionsMemoryList( + _Inout_ PPH_MEMORY_LIST_CONTEXT Context, + _In_ BOOLEAN HideFreeRegions + ) +{ + ULONG i; + ULONG k; + BOOLEAN modified; + + if (Context->HideFreeRegions != HideFreeRegions) + { + PPH_LIST lists[2]; + + Context->HideFreeRegions = HideFreeRegions; + modified = FALSE; + lists[0] = Context->AllocationBaseNodeList; + lists[1] = Context->RegionNodeList; + + for (k = 0; k < 2; k++) + { + for (i = 0; i < lists[k]->Count; i++) + { + PPH_MEMORY_NODE node = lists[k]->Items[i]; + BOOLEAN visible; + + visible = TRUE; + + if (HideFreeRegions && (node->MemoryItem->State & MEM_FREE)) + visible = FALSE; + + if (node->Node.Visible != visible) + { + node->Node.Visible = visible; + modified = TRUE; + + if (!visible) + node->Node.Selected = FALSE; + } + } + } + + if (modified) + { + TreeNew_NodesStructured(Context->TreeNewHandle); + } + } +} + +VOID PhpDestroyMemoryNode( + _In_ PPH_MEMORY_NODE MemoryNode + ) +{ + PhEmCallObjectOperation(EmMemoryNodeType, MemoryNode, EmObjectDelete); + + PhClearReference(&MemoryNode->SizeText); + PhClearReference(&MemoryNode->UseText); + PhClearReference(&MemoryNode->TotalWsText); + PhClearReference(&MemoryNode->PrivateWsText); + PhClearReference(&MemoryNode->ShareableWsText); + PhClearReference(&MemoryNode->SharedWsText); + PhClearReference(&MemoryNode->LockedWsText); + PhClearReference(&MemoryNode->CommittedText); + PhClearReference(&MemoryNode->PrivateText); + + PhClearReference(&MemoryNode->Children); + PhDereferenceObject(MemoryNode->MemoryItem); + + PhFree(MemoryNode); +} + +PPH_MEMORY_NODE PhpAddAllocationBaseNode( + _Inout_ PPH_MEMORY_LIST_CONTEXT Context, + _In_ PVOID AllocationBase + ) +{ + PPH_MEMORY_NODE memoryNode; + PPH_MEMORY_ITEM memoryItem; + + memoryNode = PhAllocate(PhEmGetObjectSize(EmMemoryNodeType, sizeof(PH_MEMORY_NODE))); + memset(memoryNode, 0, sizeof(PH_MEMORY_NODE)); + PhInitializeTreeNewNode(&memoryNode->Node); + memoryNode->Node.Expanded = FALSE; + + memoryNode->IsAllocationBase = TRUE; + memoryItem = PhCreateMemoryItem(); + memoryNode->MemoryItem = memoryItem; + + memoryItem->BaseAddress = AllocationBase; + memoryItem->AllocationBase = AllocationBase; + + memoryNode->Children = PhCreateList(1); + + memset(memoryNode->TextCache, 0, sizeof(PH_STRINGREF) * PHMMTLC_MAXIMUM); + memoryNode->Node.TextCache = memoryNode->TextCache; + memoryNode->Node.TextCacheSize = PHMMTLC_MAXIMUM; + + PhAddItemList(Context->AllocationBaseNodeList, memoryNode); + + PhEmCallObjectOperation(EmMemoryNodeType, memoryNode, EmObjectCreate); + + return memoryNode; +} + +PPH_MEMORY_NODE PhpAddRegionNode( + _Inout_ PPH_MEMORY_LIST_CONTEXT Context, + _In_ PPH_MEMORY_ITEM MemoryItem + ) +{ + PPH_MEMORY_NODE memoryNode; + + memoryNode = PhAllocate(PhEmGetObjectSize(EmMemoryNodeType, sizeof(PH_MEMORY_NODE))); + memset(memoryNode, 0, sizeof(PH_MEMORY_NODE)); + PhInitializeTreeNewNode(&memoryNode->Node); + + memoryNode->IsAllocationBase = FALSE; + memoryNode->MemoryItem = MemoryItem; + PhReferenceObject(MemoryItem); + + memset(memoryNode->TextCache, 0, sizeof(PH_STRINGREF) * PHMMTLC_MAXIMUM); + memoryNode->Node.TextCache = memoryNode->TextCache; + memoryNode->Node.TextCacheSize = PHMMTLC_MAXIMUM; + + PhAddItemList(Context->RegionNodeList, memoryNode); + + PhEmCallObjectOperation(EmMemoryNodeType, memoryNode, EmObjectCreate); + + return memoryNode; +} + +VOID PhpCopyMemoryRegionTypeInfo( + _In_ PPH_MEMORY_ITEM Source, + _Inout_ PPH_MEMORY_ITEM Destination + ) +{ + if (Destination->RegionType == CustomRegion) + PhClearReference(&Destination->u.Custom.Text); + else if (Destination->RegionType == MappedFileRegion) + PhClearReference(&Destination->u.MappedFile.FileName); + + Destination->RegionType = Source->RegionType; + Destination->u = Source->u; + + if (Destination->RegionType == CustomRegion) + PhReferenceObject(Destination->u.Custom.Text); + else if (Destination->RegionType == MappedFileRegion) + PhReferenceObject(Destination->u.MappedFile.FileName); +} + +VOID PhReplaceMemoryList( + _Inout_ PPH_MEMORY_LIST_CONTEXT Context, + _In_opt_ PPH_MEMORY_ITEM_LIST List + ) +{ + PLIST_ENTRY listEntry; + PPH_MEMORY_NODE allocationBaseNode = NULL; + + PhpClearMemoryList(Context); + + if (!List) + { + TreeNew_NodesStructured(Context->TreeNewHandle); + return; + } + + for (listEntry = List->ListHead.Flink; listEntry != &List->ListHead; listEntry = listEntry->Flink) + { + PPH_MEMORY_ITEM memoryItem = CONTAINING_RECORD(listEntry, PH_MEMORY_ITEM, ListEntry); + PPH_MEMORY_NODE memoryNode; + + if (memoryItem->AllocationBaseItem == memoryItem) + allocationBaseNode = PhpAddAllocationBaseNode(Context, memoryItem->AllocationBase); + + memoryNode = PhpAddRegionNode(Context, memoryItem); + + if (Context->HideFreeRegions && (memoryItem->State & MEM_FREE)) + memoryNode->Node.Visible = FALSE; + + if (allocationBaseNode && memoryItem->AllocationBase == allocationBaseNode->MemoryItem->BaseAddress) + { + if (!(memoryItem->State & MEM_FREE)) + { + memoryNode->Parent = allocationBaseNode; + PhAddItemList(allocationBaseNode->Children, memoryNode); + } + + // Aggregate various statistics. + allocationBaseNode->MemoryItem->RegionSize += memoryItem->RegionSize; + allocationBaseNode->MemoryItem->CommittedSize += memoryItem->CommittedSize; + allocationBaseNode->MemoryItem->PrivateSize += memoryItem->PrivateSize; + allocationBaseNode->MemoryItem->TotalWorkingSetPages += memoryItem->TotalWorkingSetPages; + allocationBaseNode->MemoryItem->PrivateWorkingSetPages += memoryItem->PrivateWorkingSetPages; + allocationBaseNode->MemoryItem->SharedWorkingSetPages += memoryItem->SharedWorkingSetPages; + allocationBaseNode->MemoryItem->ShareableWorkingSetPages += memoryItem->ShareableWorkingSetPages; + allocationBaseNode->MemoryItem->LockedWorkingSetPages += memoryItem->LockedWorkingSetPages; + + if (memoryItem->AllocationBaseItem == memoryItem) + { + if (memoryItem->State & MEM_FREE) + allocationBaseNode->MemoryItem->State = MEM_FREE; + + allocationBaseNode->MemoryItem->Protect = memoryItem->AllocationProtect; + PhGetMemoryProtectionString(allocationBaseNode->MemoryItem->Protect, allocationBaseNode->ProtectionText); + allocationBaseNode->MemoryItem->Type = memoryItem->Type; + + if (memoryItem->RegionType != CustomRegion || memoryItem->u.Custom.PropertyOfAllocationBase) + PhpCopyMemoryRegionTypeInfo(memoryItem, allocationBaseNode->MemoryItem); + + if (Context->HideFreeRegions && (allocationBaseNode->MemoryItem->State & MEM_FREE)) + allocationBaseNode->Node.Visible = FALSE; + } + else + { + if (memoryItem->RegionType == UnknownRegion) + PhpCopyMemoryRegionTypeInfo(allocationBaseNode->MemoryItem, memoryItem); + } + } + + PhGetMemoryProtectionString(memoryItem->Protect, memoryNode->ProtectionText); + } + + TreeNew_NodesStructured(Context->TreeNewHandle); +} + +VOID PhUpdateMemoryNode( + _In_ PPH_MEMORY_LIST_CONTEXT Context, + _In_ PPH_MEMORY_NODE MemoryNode + ) +{ + PhGetMemoryProtectionString(MemoryNode->MemoryItem->Protect, MemoryNode->ProtectionText); + memset(MemoryNode->TextCache, 0, sizeof(PH_STRINGREF) * PHMMTLC_MAXIMUM); + TreeNew_InvalidateNode(Context->TreeNewHandle, &MemoryNode->Node); +} + +PPH_STRING PhpGetMemoryRegionUseText( + _In_ PPH_MEMORY_ITEM MemoryItem + ) +{ + PH_MEMORY_REGION_TYPE type = MemoryItem->RegionType; + + switch (type) + { + case UnknownRegion: + return PhReferenceEmptyString(); + case CustomRegion: + PhReferenceObject(MemoryItem->u.Custom.Text); + return MemoryItem->u.Custom.Text; + case UnusableRegion: + return PhReferenceEmptyString(); + case MappedFileRegion: + PhReferenceObject(MemoryItem->u.MappedFile.FileName); + return MemoryItem->u.MappedFile.FileName; + case UserSharedDataRegion: + return PhCreateString(L"USER_SHARED_DATA"); + case PebRegion: + case Peb32Region: + return PhFormatString(L"PEB%s", type == Peb32Region ? L" 32-bit" : L""); + case TebRegion: + case Teb32Region: + return PhFormatString(L"TEB%s (thread %u)", + type == Teb32Region ? L" 32-bit" : L"", HandleToUlong(MemoryItem->u.Teb.ThreadId)); + case StackRegion: + case Stack32Region: + return PhFormatString(L"Stack%s (thread %u)", + type == Stack32Region ? L" 32-bit" : L"", HandleToUlong(MemoryItem->u.Stack.ThreadId)); + case HeapRegion: + case Heap32Region: + return PhFormatString(L"Heap%s (ID %u)", + type == Heap32Region ? L" 32-bit" : L"", (ULONG)MemoryItem->u.Heap.Index + 1); + case HeapSegmentRegion: + case HeapSegment32Region: + return PhFormatString(L"Heap segment%s (ID %u)", + type == HeapSegment32Region ? L" 32-bit" : L"", (ULONG)MemoryItem->u.HeapSegment.HeapItem->u.Heap.Index + 1); + case CfgBitmapRegion: + return PhFormatString(L"CFG Bitmap"); + default: + return PhReferenceEmptyString(); + } +} + +VOID PhpUpdateMemoryNodeUseText( + _Inout_ PPH_MEMORY_NODE MemoryNode + ) +{ + if (!MemoryNode->UseText) + MemoryNode->UseText = PhpGetMemoryRegionUseText(MemoryNode->MemoryItem); +} + +PPH_STRING PhpFormatSizeIfNonZero( + _In_ ULONG64 Size + ) +{ + if (Size != 0) + return PhFormatSize(Size, -1); + else + return NULL; +} + +#define SORT_FUNCTION(Column) PhpMemoryTreeNewCompare##Column + +#define BEGIN_SORT_FUNCTION(Column) static int __cdecl PhpMemoryTreeNewCompare##Column( \ + _In_ void *_context, \ + _In_ const void *_elem1, \ + _In_ const void *_elem2 \ + ) \ +{ \ + PPH_MEMORY_NODE node1 = *(PPH_MEMORY_NODE *)_elem1; \ + PPH_MEMORY_NODE node2 = *(PPH_MEMORY_NODE *)_elem2; \ + PPH_MEMORY_ITEM memoryItem1 = node1->MemoryItem; \ + PPH_MEMORY_ITEM memoryItem2 = node2->MemoryItem; \ + int sortResult = 0; + +#define END_SORT_FUNCTION \ + if (sortResult == 0) \ + sortResult = uintptrcmp((ULONG_PTR)memoryItem1->BaseAddress, (ULONG_PTR)memoryItem2->BaseAddress); \ + \ + return PhModifySort(sortResult, ((PPH_MEMORY_LIST_CONTEXT)_context)->TreeNewSortOrder); \ +} + +LONG PhpMemoryTreeNewPostSortFunction( + _In_ LONG Result, + _In_ PVOID Node1, + _In_ PVOID Node2, + _In_ PH_SORT_ORDER SortOrder + ) +{ + if (Result == 0) + Result = uintptrcmp((ULONG_PTR)((PPH_MEMORY_NODE)Node1)->MemoryItem->BaseAddress, (ULONG_PTR)((PPH_MEMORY_NODE)Node2)->MemoryItem->BaseAddress); + + return PhModifySort(Result, SortOrder); +} + +BEGIN_SORT_FUNCTION(BaseAddress) +{ + sortResult = uintptrcmp((ULONG_PTR)memoryItem1->BaseAddress, (ULONG_PTR)memoryItem2->BaseAddress); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(Type) +{ + sortResult = uintcmp(memoryItem1->Type | memoryItem1->State, memoryItem2->Type | memoryItem2->State); + + if (sortResult == 0) + sortResult = intcmp(memoryItem1->RegionType, memoryItem2->RegionType); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(Size) +{ + sortResult = uintptrcmp(memoryItem1->RegionSize, memoryItem2->RegionSize); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(Protection) +{ + sortResult = PhCompareStringZ(node1->ProtectionText, node2->ProtectionText, FALSE); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(Use) +{ + PhpUpdateMemoryNodeUseText(node1); + PhpUpdateMemoryNodeUseText(node2); + sortResult = PhCompareStringWithNull(node1->UseText, node2->UseText, TRUE); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(TotalWs) +{ + sortResult = uintptrcmp(memoryItem1->TotalWorkingSetPages, memoryItem2->TotalWorkingSetPages); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(PrivateWs) +{ + sortResult = uintptrcmp(memoryItem1->PrivateWorkingSetPages, memoryItem2->PrivateWorkingSetPages); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(ShareableWs) +{ + sortResult = uintptrcmp(memoryItem1->ShareableWorkingSetPages, memoryItem2->ShareableWorkingSetPages); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(SharedWs) +{ + sortResult = uintptrcmp(memoryItem1->SharedWorkingSetPages, memoryItem2->SharedWorkingSetPages); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(LockedWs) +{ + sortResult = uintptrcmp(memoryItem1->LockedWorkingSetPages, memoryItem2->LockedWorkingSetPages); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(Committed) +{ + sortResult = uintptrcmp(memoryItem1->CommittedSize, memoryItem2->CommittedSize); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(Private) +{ + sortResult = uintptrcmp(memoryItem1->PrivateSize, memoryItem2->PrivateSize); +} +END_SORT_FUNCTION + +BOOLEAN NTAPI PhpMemoryTreeNewCallback( + _In_ HWND hwnd, + _In_ PH_TREENEW_MESSAGE Message, + _In_opt_ PVOID Parameter1, + _In_opt_ PVOID Parameter2, + _In_opt_ PVOID Context + ) +{ + PPH_MEMORY_LIST_CONTEXT context; + PPH_MEMORY_NODE node; + + context = Context; + + if (PhCmForwardMessage(hwnd, Message, Parameter1, Parameter2, &context->Cm)) + return TRUE; + + switch (Message) + { + case TreeNewGetChildren: + { + PPH_TREENEW_GET_CHILDREN getChildren = Parameter1; + + node = (PPH_MEMORY_NODE)getChildren->Node; + + if (context->TreeNewSortOrder == NoSortOrder) + { + if (!node) + { + getChildren->Children = (PPH_TREENEW_NODE *)context->AllocationBaseNodeList->Items; + getChildren->NumberOfChildren = context->AllocationBaseNodeList->Count; + } + else + { + getChildren->Children = (PPH_TREENEW_NODE *)node->Children->Items; + getChildren->NumberOfChildren = node->Children->Count; + } + } + else + { + if (!node) + { + static PVOID sortFunctions[] = + { + SORT_FUNCTION(BaseAddress), + SORT_FUNCTION(Type), + SORT_FUNCTION(Size), + SORT_FUNCTION(Protection), + SORT_FUNCTION(Use), + SORT_FUNCTION(TotalWs), + SORT_FUNCTION(PrivateWs), + SORT_FUNCTION(ShareableWs), + SORT_FUNCTION(SharedWs), + SORT_FUNCTION(LockedWs), + SORT_FUNCTION(Committed), + SORT_FUNCTION(Private) + }; + int (__cdecl *sortFunction)(void *, const void *, const void *); + + if (!PhCmForwardSort( + (PPH_TREENEW_NODE *)context->RegionNodeList->Items, + context->RegionNodeList->Count, + context->TreeNewSortColumn, + context->TreeNewSortOrder, + &context->Cm + )) + { + if (context->TreeNewSortColumn < PHMMTLC_MAXIMUM) + sortFunction = sortFunctions[context->TreeNewSortColumn]; + else + sortFunction = NULL; + } + else + { + sortFunction = NULL; + } + + if (sortFunction) + { + qsort_s(context->RegionNodeList->Items, context->RegionNodeList->Count, sizeof(PVOID), sortFunction, context); + } + + getChildren->Children = (PPH_TREENEW_NODE *)context->RegionNodeList->Items; + getChildren->NumberOfChildren = context->RegionNodeList->Count; + } + } + } + return TRUE; + case TreeNewIsLeaf: + { + PPH_TREENEW_IS_LEAF isLeaf = Parameter1; + + node = (PPH_MEMORY_NODE)isLeaf->Node; + + if (context->TreeNewSortOrder == NoSortOrder) + isLeaf->IsLeaf = !node->Children || node->Children->Count == 0; + else + isLeaf->IsLeaf = TRUE; + } + return TRUE; + case TreeNewGetCellText: + { + PPH_TREENEW_GET_CELL_TEXT getCellText = Parameter1; + PPH_MEMORY_ITEM memoryItem; + + node = (PPH_MEMORY_NODE)getCellText->Node; + memoryItem = node->MemoryItem; + + switch (getCellText->Id) + { + case PHMMTLC_BASEADDRESS: + PhPrintPointer(node->BaseAddressText, memoryItem->BaseAddress); + PhInitializeStringRefLongHint(&getCellText->Text, node->BaseAddressText); + break; + case PHMMTLC_TYPE: + if (memoryItem->State & MEM_FREE) + { + if (memoryItem->RegionType == UnusableRegion) + PhInitializeStringRef(&getCellText->Text, L"Free (Unusable)"); + else + PhInitializeStringRef(&getCellText->Text, L"Free"); + } + else if (node->IsAllocationBase) + { + PhInitializeStringRefLongHint(&getCellText->Text, PhGetMemoryTypeString(memoryItem->Type)); + } + else + { + PH_FORMAT format[3]; + SIZE_T returnLength; + + PhInitFormatS(&format[0], PhGetMemoryTypeString(memoryItem->Type)); + PhInitFormatS(&format[1], L": "); + PhInitFormatS(&format[2], PhGetMemoryStateString(memoryItem->State)); + + if (PhFormatToBuffer(format, 3, node->TypeText, sizeof(node->TypeText), &returnLength)) + { + getCellText->Text.Buffer = node->TypeText; + getCellText->Text.Length = returnLength - sizeof(WCHAR); + } + } + break; + case PHMMTLC_SIZE: + PhMoveReference(&node->SizeText, PhFormatSize(memoryItem->RegionSize, -1)); + getCellText->Text = PhGetStringRef(node->SizeText); + break; + case PHMMTLC_PROTECTION: + PhInitializeStringRefLongHint(&getCellText->Text, node->ProtectionText); + break; + case PHMMTLC_USE: + PhpUpdateMemoryNodeUseText(node); + getCellText->Text = PhGetStringRef(node->UseText); + break; + case PHMMTLC_TOTALWS: + PhMoveReference(&node->TotalWsText, PhpFormatSizeIfNonZero((ULONG64)memoryItem->TotalWorkingSetPages * PAGE_SIZE)); + getCellText->Text = PhGetStringRef(node->TotalWsText); + break; + case PHMMTLC_PRIVATEWS: + PhMoveReference(&node->PrivateWsText, PhpFormatSizeIfNonZero((ULONG64)memoryItem->PrivateWorkingSetPages * PAGE_SIZE)); + getCellText->Text = PhGetStringRef(node->PrivateWsText); + break; + case PHMMTLC_SHAREABLEWS: + PhMoveReference(&node->ShareableWsText, PhpFormatSizeIfNonZero((ULONG64)memoryItem->ShareableWorkingSetPages * PAGE_SIZE)); + getCellText->Text = PhGetStringRef(node->ShareableWsText); + break; + case PHMMTLC_SHAREDWS: + PhMoveReference(&node->SharedWsText, PhpFormatSizeIfNonZero((ULONG64)memoryItem->SharedWorkingSetPages * PAGE_SIZE)); + getCellText->Text = PhGetStringRef(node->SharedWsText); + break; + case PHMMTLC_LOCKEDWS: + PhMoveReference(&node->LockedWsText, PhpFormatSizeIfNonZero((ULONG64)memoryItem->LockedWorkingSetPages * PAGE_SIZE)); + getCellText->Text = PhGetStringRef(node->LockedWsText); + break; + case PHMMTLC_COMMITTED: + PhMoveReference(&node->CommittedText, PhpFormatSizeIfNonZero(memoryItem->CommittedSize)); + getCellText->Text = PhGetStringRef(node->CommittedText); + break; + case PHMMTLC_PRIVATE: + PhMoveReference(&node->PrivateText, PhpFormatSizeIfNonZero(memoryItem->PrivateSize)); + getCellText->Text = PhGetStringRef(node->PrivateText); + break; + default: + return FALSE; + } + + getCellText->Flags = TN_CACHE; + } + return TRUE; + case TreeNewGetNodeColor: + { + //PPH_TREENEW_GET_NODE_COLOR getNodeColor = Parameter1; + //PPH_MEMORY_ITEM memoryItem; + + //node = (PPH_MEMORY_NODE)getNodeColor->Node; + //memoryItem = node->MemoryItem; + + //if (!memoryItem) + // ; // Dummy + //else if (PhCsUseColorRelocatedModules && (memoryItem->Protect & PAGE_EXECUTE_WRITECOPY)) + // getNodeColor->BackColor = PhCsColorRelocatedModules; + //else if (PhCsUseColorRelocatedModules && (memoryItem->Protect & PAGE_EXECUTE_READWRITE)) + // getNodeColor->BackColor = PhCsColorRelocatedModules; + //else if (PhCsUseColorSystemProcesses && (memoryItem->Type & MEM_PRIVATE)) + // getNodeColor->BackColor = PhCsColorSystemProcesses; + + //getNodeColor->Flags = TN_CACHE | TN_AUTO_FORECOLOR; + } + return TRUE; + case TreeNewSortChanged: + { + TreeNew_GetSort(hwnd, &context->TreeNewSortColumn, &context->TreeNewSortOrder); + // Force a rebuild to sort the items. + TreeNew_NodesStructured(hwnd); + } + return TRUE; + case TreeNewKeyDown: + { + PPH_TREENEW_KEY_EVENT keyEvent = Parameter1; + + switch (keyEvent->VirtualKey) + { + case 'C': + if (GetKeyState(VK_CONTROL) < 0) + SendMessage(context->ParentWindowHandle, WM_COMMAND, ID_MEMORY_COPY, 0); + break; + case 'A': + if (GetKeyState(VK_CONTROL) < 0) + TreeNew_SelectRange(context->TreeNewHandle, 0, -1); + break; + case VK_RETURN: + SendMessage(context->ParentWindowHandle, WM_COMMAND, ID_MEMORY_READWRITEMEMORY, 0); + break; + case VK_F5: + SendMessage(context->ParentWindowHandle, WM_COMMAND, IDC_REFRESH, 0); + break; + } + } + return TRUE; + case TreeNewHeaderRightClick: + { + PH_TN_COLUMN_MENU_DATA data; + + data.TreeNewHandle = hwnd; + data.MouseEvent = Parameter1; + data.DefaultSortColumn = 0; + data.DefaultSortOrder = NoSortOrder; + PhInitializeTreeNewColumnMenuEx(&data, PH_TN_COLUMN_MENU_SHOW_RESET_SORT); + + data.Selection = PhShowEMenu(data.Menu, hwnd, PH_EMENU_SHOW_LEFTRIGHT, + PH_ALIGN_LEFT | PH_ALIGN_TOP, data.MouseEvent->ScreenLocation.x, data.MouseEvent->ScreenLocation.y); + PhHandleTreeNewColumnMenu(&data); + PhDeleteTreeNewColumnMenu(&data); + } + return TRUE; + case TreeNewLeftDoubleClick: + { + PPH_TREENEW_MOUSE_EVENT mouseEvent = Parameter1; + + node = (PPH_MEMORY_NODE)mouseEvent->Node; + + if (node && node->IsAllocationBase) + TreeNew_SetNodeExpanded(hwnd, node, !node->Node.Expanded); + else + SendMessage(context->ParentWindowHandle, WM_COMMAND, ID_MEMORY_READWRITEMEMORY, 0); + } + return TRUE; + case TreeNewContextMenu: + { + PPH_TREENEW_CONTEXT_MENU contextMenu = Parameter1; + + SendMessage(context->ParentWindowHandle, WM_COMMAND, ID_SHOWCONTEXTMENU, (LPARAM)contextMenu); + } + return TRUE; + case TreeNewGetDialogCode: + { + PULONG code = Parameter2; + + if (PtrToUlong(Parameter1) == VK_RETURN) + { + *code = DLGC_WANTMESSAGE; + return TRUE; + } + } + return FALSE; + } + + return FALSE; +} + +PPH_MEMORY_NODE PhGetSelectedMemoryNode( + _In_ PPH_MEMORY_LIST_CONTEXT Context + ) +{ + ULONG i; + + if (Context->TreeNewSortOrder == NoSortOrder) + { + for (i = 0; i < Context->AllocationBaseNodeList->Count; i++) + { + PPH_MEMORY_NODE node = Context->AllocationBaseNodeList->Items[i]; + + if (node->Node.Selected) + return node; + } + } + + for (i = 0; i < Context->RegionNodeList->Count; i++) + { + PPH_MEMORY_NODE node = Context->RegionNodeList->Items[i]; + + if (node->Node.Selected) + return node; + } + + return NULL; +} + +VOID PhGetSelectedMemoryNodes( + _In_ PPH_MEMORY_LIST_CONTEXT Context, + _Out_ PPH_MEMORY_NODE **MemoryNodes, + _Out_ PULONG NumberOfMemoryNodes + ) +{ + PH_ARRAY array; + ULONG i; + + PhInitializeArray(&array, sizeof(PVOID), 2); + + if (Context->TreeNewSortOrder == NoSortOrder) + { + for (i = 0; i < Context->AllocationBaseNodeList->Count; i++) + { + PPH_MEMORY_NODE node = Context->AllocationBaseNodeList->Items[i]; + + if (node->Node.Selected) + PhAddItemArray(&array, &node); + } + } + + for (i = 0; i < Context->RegionNodeList->Count; i++) + { + PPH_MEMORY_NODE node = Context->RegionNodeList->Items[i]; + + if (node->Node.Selected) + PhAddItemArray(&array, &node); + } + + *NumberOfMemoryNodes = (ULONG)array.Count; + *MemoryNodes = PhFinalArrayItems(&array); +} + +VOID PhDeselectAllMemoryNodes( + _In_ PPH_MEMORY_LIST_CONTEXT Context + ) +{ + TreeNew_DeselectRange(Context->TreeNewHandle, 0, -1); +} diff --git a/ProcessHacker/memlists.c b/ProcessHacker/memlists.c index c1abb62565b2..732e15b07729 100644 --- a/ProcessHacker/memlists.c +++ b/ProcessHacker/memlists.c @@ -1,288 +1,288 @@ -/* - * Process Hacker - - * memory list information - * - * Copyright (C) 2010-2011 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include - -#include - -#include -#include -#include - -#define MSG_UPDATE (WM_APP + 1) - -INT_PTR CALLBACK PhpMemoryListsDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -HWND PhMemoryListsWindowHandle = NULL; -static VOID (NTAPI *UnregisterDialogFunction)(HWND); -static PH_CALLBACK_REGISTRATION ProcessesUpdatedRegistration; - -VOID PhShowMemoryListsDialog( - _In_ HWND ParentWindowHandle, - _In_opt_ VOID (NTAPI *RegisterDialog)(HWND), - _In_opt_ VOID (NTAPI *UnregisterDialog)(HWND) - ) -{ - if (!PhMemoryListsWindowHandle) - { - PhMemoryListsWindowHandle = CreateDialog( - PhInstanceHandle, - MAKEINTRESOURCE(IDD_MEMLISTS), - ParentWindowHandle, - PhpMemoryListsDlgProc - ); - RegisterDialog(PhMemoryListsWindowHandle); - UnregisterDialogFunction = UnregisterDialog; - } - - if (!IsWindowVisible(PhMemoryListsWindowHandle)) - ShowWindow(PhMemoryListsWindowHandle, SW_SHOW); - else if (IsIconic(PhMemoryListsWindowHandle)) - ShowWindow(PhMemoryListsWindowHandle, SW_RESTORE); - else - SetForegroundWindow(PhMemoryListsWindowHandle); -} - -static VOID NTAPI ProcessesUpdatedCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - PostMessage(PhMemoryListsWindowHandle, MSG_UPDATE, 0, 0); -} - -static VOID PhpUpdateMemoryListInfo( - _In_ HWND hwndDlg - ) -{ - SYSTEM_MEMORY_LIST_INFORMATION memoryListInfo; - - if (NT_SUCCESS(NtQuerySystemInformation( - SystemMemoryListInformation, - &memoryListInfo, - sizeof(SYSTEM_MEMORY_LIST_INFORMATION), - NULL - ))) - { - ULONG_PTR standbyPageCount; - ULONG_PTR repurposedPageCount; - ULONG i; - - standbyPageCount = 0; - repurposedPageCount = 0; - - for (i = 0; i < 8; i++) - { - standbyPageCount += memoryListInfo.PageCountByPriority[i]; - repurposedPageCount += memoryListInfo.RepurposedPagesByPriority[i]; - } - - SetDlgItemText(hwndDlg, IDC_ZLISTZEROED_V, PhaFormatSize((ULONG64)memoryListInfo.ZeroPageCount * PAGE_SIZE, -1)->Buffer); - SetDlgItemText(hwndDlg, IDC_ZLISTFREE_V, PhaFormatSize((ULONG64)memoryListInfo.FreePageCount * PAGE_SIZE, -1)->Buffer); - SetDlgItemText(hwndDlg, IDC_ZLISTMODIFIED_V, PhaFormatSize((ULONG64)memoryListInfo.ModifiedPageCount * PAGE_SIZE, -1)->Buffer); - SetDlgItemText(hwndDlg, IDC_ZLISTMODIFIEDNOWRITE_V, PhaFormatSize((ULONG64)memoryListInfo.ModifiedNoWritePageCount * PAGE_SIZE, -1)->Buffer); - SetDlgItemText(hwndDlg, IDC_ZLISTBAD_V, PhaFormatSize((ULONG64)memoryListInfo.BadPageCount * PAGE_SIZE, -1)->Buffer); - SetDlgItemText(hwndDlg, IDC_ZLISTSTANDBY_V, PhaFormatSize((ULONG64)standbyPageCount * PAGE_SIZE, -1)->Buffer); - SetDlgItemText(hwndDlg, IDC_ZLISTSTANDBY0_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[0] * PAGE_SIZE, -1)->Buffer); - SetDlgItemText(hwndDlg, IDC_ZLISTSTANDBY1_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[1] * PAGE_SIZE, -1)->Buffer); - SetDlgItemText(hwndDlg, IDC_ZLISTSTANDBY2_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[2] * PAGE_SIZE, -1)->Buffer); - SetDlgItemText(hwndDlg, IDC_ZLISTSTANDBY3_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[3] * PAGE_SIZE, -1)->Buffer); - SetDlgItemText(hwndDlg, IDC_ZLISTSTANDBY4_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[4] * PAGE_SIZE, -1)->Buffer); - SetDlgItemText(hwndDlg, IDC_ZLISTSTANDBY5_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[5] * PAGE_SIZE, -1)->Buffer); - SetDlgItemText(hwndDlg, IDC_ZLISTSTANDBY6_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[6] * PAGE_SIZE, -1)->Buffer); - SetDlgItemText(hwndDlg, IDC_ZLISTSTANDBY7_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[7] * PAGE_SIZE, -1)->Buffer); - SetDlgItemText(hwndDlg, IDC_ZLISTREPURPOSED_V, PhaFormatSize((ULONG64)repurposedPageCount * PAGE_SIZE, -1)->Buffer); - SetDlgItemText(hwndDlg, IDC_ZLISTREPURPOSED0_V, PhaFormatSize((ULONG64)memoryListInfo.RepurposedPagesByPriority[0] * PAGE_SIZE, -1)->Buffer); - SetDlgItemText(hwndDlg, IDC_ZLISTREPURPOSED1_V, PhaFormatSize((ULONG64)memoryListInfo.RepurposedPagesByPriority[1] * PAGE_SIZE, -1)->Buffer); - SetDlgItemText(hwndDlg, IDC_ZLISTREPURPOSED2_V, PhaFormatSize((ULONG64)memoryListInfo.RepurposedPagesByPriority[2] * PAGE_SIZE, -1)->Buffer); - SetDlgItemText(hwndDlg, IDC_ZLISTREPURPOSED3_V, PhaFormatSize((ULONG64)memoryListInfo.RepurposedPagesByPriority[3] * PAGE_SIZE, -1)->Buffer); - SetDlgItemText(hwndDlg, IDC_ZLISTREPURPOSED4_V, PhaFormatSize((ULONG64)memoryListInfo.RepurposedPagesByPriority[4] * PAGE_SIZE, -1)->Buffer); - SetDlgItemText(hwndDlg, IDC_ZLISTREPURPOSED5_V, PhaFormatSize((ULONG64)memoryListInfo.RepurposedPagesByPriority[5] * PAGE_SIZE, -1)->Buffer); - SetDlgItemText(hwndDlg, IDC_ZLISTREPURPOSED6_V, PhaFormatSize((ULONG64)memoryListInfo.RepurposedPagesByPriority[6] * PAGE_SIZE, -1)->Buffer); - SetDlgItemText(hwndDlg, IDC_ZLISTREPURPOSED7_V, PhaFormatSize((ULONG64)memoryListInfo.RepurposedPagesByPriority[7] * PAGE_SIZE, -1)->Buffer); - - if (WindowsVersion >= WINDOWS_8) - SetDlgItemText(hwndDlg, IDC_ZLISTMODIFIEDPAGEFILE_V, PhaFormatSize((ULONG64)memoryListInfo.ModifiedPageCountPageFile * PAGE_SIZE, -1)->Buffer); - else - SetDlgItemText(hwndDlg, IDC_ZLISTMODIFIEDPAGEFILE_V, L"N/A"); - } - else - { - SetDlgItemText(hwndDlg, IDC_ZLISTZEROED_V, L"Unknown"); - SetDlgItemText(hwndDlg, IDC_ZLISTFREE_V, L"Unknown"); - SetDlgItemText(hwndDlg, IDC_ZLISTMODIFIED_V, L"Unknown"); - SetDlgItemText(hwndDlg, IDC_ZLISTMODIFIEDNOWRITE_V, L"Unknown"); - SetDlgItemText(hwndDlg, IDC_ZLISTMODIFIEDPAGEFILE_V, L"Unknown"); - SetDlgItemText(hwndDlg, IDC_ZLISTBAD_V, L"Unknown"); - SetDlgItemText(hwndDlg, IDC_ZLISTSTANDBY_V, L"Unknown"); - SetDlgItemText(hwndDlg, IDC_ZLISTSTANDBY0_V, L"Unknown"); - SetDlgItemText(hwndDlg, IDC_ZLISTSTANDBY1_V, L"Unknown"); - SetDlgItemText(hwndDlg, IDC_ZLISTSTANDBY2_V, L"Unknown"); - SetDlgItemText(hwndDlg, IDC_ZLISTSTANDBY3_V, L"Unknown"); - SetDlgItemText(hwndDlg, IDC_ZLISTSTANDBY4_V, L"Unknown"); - SetDlgItemText(hwndDlg, IDC_ZLISTSTANDBY5_V, L"Unknown"); - SetDlgItemText(hwndDlg, IDC_ZLISTSTANDBY6_V, L"Unknown"); - SetDlgItemText(hwndDlg, IDC_ZLISTSTANDBY7_V, L"Unknown"); - SetDlgItemText(hwndDlg, IDC_ZLISTREPURPOSED_V, L"Unknown"); - SetDlgItemText(hwndDlg, IDC_ZLISTREPURPOSED0_V, L"Unknown"); - SetDlgItemText(hwndDlg, IDC_ZLISTREPURPOSED1_V, L"Unknown"); - SetDlgItemText(hwndDlg, IDC_ZLISTREPURPOSED2_V, L"Unknown"); - SetDlgItemText(hwndDlg, IDC_ZLISTREPURPOSED3_V, L"Unknown"); - SetDlgItemText(hwndDlg, IDC_ZLISTREPURPOSED4_V, L"Unknown"); - SetDlgItemText(hwndDlg, IDC_ZLISTREPURPOSED5_V, L"Unknown"); - SetDlgItemText(hwndDlg, IDC_ZLISTREPURPOSED6_V, L"Unknown"); - SetDlgItemText(hwndDlg, IDC_ZLISTREPURPOSED7_V, L"Unknown"); - } -} - -INT_PTR CALLBACK PhpMemoryListsDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - switch (uMsg) - { - case WM_INITDIALOG: - { - PhRegisterCallback(&PhProcessesUpdatedEvent, ProcessesUpdatedCallback, NULL, &ProcessesUpdatedRegistration); - PhpUpdateMemoryListInfo(hwndDlg); - - PhLoadWindowPlacementFromSetting(L"MemoryListsWindowPosition", NULL, hwndDlg); - PhRegisterDialog(hwndDlg); - } - break; - case WM_DESTROY: - { - PhUnregisterDialog(hwndDlg); - PhSaveWindowPlacementToSetting(L"MemoryListsWindowPosition", NULL, hwndDlg); - - PhUnregisterCallback(&PhProcessesUpdatedEvent, &ProcessesUpdatedRegistration); - - UnregisterDialogFunction(hwndDlg); - PhMemoryListsWindowHandle = NULL; - } - break; - case WM_COMMAND: - { - switch (LOWORD(wParam)) - { - case IDCANCEL: - case IDOK: - DestroyWindow(hwndDlg); - break; - case IDC_EMPTY: - { - PPH_EMENU menu; - RECT buttonRect; - POINT point; - PPH_EMENU_ITEM selectedItem; - SYSTEM_MEMORY_LIST_COMMAND command = -1; - - menu = PhCreateEMenu(); - PhLoadResourceEMenuItem(menu, PhInstanceHandle, MAKEINTRESOURCE(IDR_EMPTYMEMLISTS), 0); - - GetClientRect(GetDlgItem(hwndDlg, IDC_EMPTY), &buttonRect); - point.x = 0; - point.y = buttonRect.bottom; - - ClientToScreen(GetDlgItem(hwndDlg, IDC_EMPTY), &point); - selectedItem = PhShowEMenu(menu, hwndDlg, PH_EMENU_SHOW_LEFTRIGHT, - PH_ALIGN_LEFT | PH_ALIGN_TOP, point.x, point.y); - - if (selectedItem) - { - switch (selectedItem->Id) - { - case ID_EMPTY_EMPTYWORKINGSETS: - command = MemoryEmptyWorkingSets; - break; - case ID_EMPTY_EMPTYMODIFIEDPAGELIST: - command = MemoryFlushModifiedList; - break; - case ID_EMPTY_EMPTYSTANDBYLIST: - command = MemoryPurgeStandbyList; - break; - case ID_EMPTY_EMPTYPRIORITY0STANDBYLIST: - command = MemoryPurgeLowPriorityStandbyList; - break; - } - } - - if (command != -1) - { - NTSTATUS status; - - SetCursor(LoadCursor(NULL, IDC_WAIT)); - status = NtSetSystemInformation( - SystemMemoryListInformation, - &command, - sizeof(SYSTEM_MEMORY_LIST_COMMAND) - ); - SetCursor(LoadCursor(NULL, IDC_ARROW)); - - if (status == STATUS_PRIVILEGE_NOT_HELD) - { - if (!PhGetOwnTokenAttributes().Elevated) - { - if (PhUiConnectToPhSvc(hwndDlg, FALSE)) - { - SetCursor(LoadCursor(NULL, IDC_WAIT)); - status = PhSvcCallIssueMemoryListCommand(command); - SetCursor(LoadCursor(NULL, IDC_ARROW)); - PhUiDisconnectFromPhSvc(); - } - else - { - // User cancelled eleavtion. - status = STATUS_SUCCESS; - } - } - } - - if (!NT_SUCCESS(status)) - { - PhShowStatus(hwndDlg, L"Unable to execute the memory list command", status, 0); - } - } - - PhDestroyEMenu(menu); - } - break; - } - } - break; - case MSG_UPDATE: - { - PhpUpdateMemoryListInfo(hwndDlg); - } - break; - } - - return FALSE; -} +/* + * Process Hacker - + * memory list information + * + * Copyright (C) 2010-2011 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include + +#include + +#include +#include +#include + +#define MSG_UPDATE (WM_APP + 1) + +INT_PTR CALLBACK PhpMemoryListsDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +HWND PhMemoryListsWindowHandle = NULL; +static VOID (NTAPI *UnregisterDialogFunction)(HWND); +static PH_CALLBACK_REGISTRATION ProcessesUpdatedRegistration; + +VOID PhShowMemoryListsDialog( + _In_ HWND ParentWindowHandle, + _In_opt_ VOID (NTAPI *RegisterDialog)(HWND), + _In_opt_ VOID (NTAPI *UnregisterDialog)(HWND) + ) +{ + if (!PhMemoryListsWindowHandle) + { + PhMemoryListsWindowHandle = CreateDialog( + PhInstanceHandle, + MAKEINTRESOURCE(IDD_MEMLISTS), + ParentWindowHandle, + PhpMemoryListsDlgProc + ); + RegisterDialog(PhMemoryListsWindowHandle); + UnregisterDialogFunction = UnregisterDialog; + } + + if (!IsWindowVisible(PhMemoryListsWindowHandle)) + ShowWindow(PhMemoryListsWindowHandle, SW_SHOW); + else if (IsIconic(PhMemoryListsWindowHandle)) + ShowWindow(PhMemoryListsWindowHandle, SW_RESTORE); + else + SetForegroundWindow(PhMemoryListsWindowHandle); +} + +static VOID NTAPI ProcessesUpdatedCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + PostMessage(PhMemoryListsWindowHandle, MSG_UPDATE, 0, 0); +} + +static VOID PhpUpdateMemoryListInfo( + _In_ HWND hwndDlg + ) +{ + SYSTEM_MEMORY_LIST_INFORMATION memoryListInfo; + + if (NT_SUCCESS(NtQuerySystemInformation( + SystemMemoryListInformation, + &memoryListInfo, + sizeof(SYSTEM_MEMORY_LIST_INFORMATION), + NULL + ))) + { + ULONG_PTR standbyPageCount; + ULONG_PTR repurposedPageCount; + ULONG i; + + standbyPageCount = 0; + repurposedPageCount = 0; + + for (i = 0; i < 8; i++) + { + standbyPageCount += memoryListInfo.PageCountByPriority[i]; + repurposedPageCount += memoryListInfo.RepurposedPagesByPriority[i]; + } + + SetDlgItemText(hwndDlg, IDC_ZLISTZEROED_V, PhaFormatSize((ULONG64)memoryListInfo.ZeroPageCount * PAGE_SIZE, -1)->Buffer); + SetDlgItemText(hwndDlg, IDC_ZLISTFREE_V, PhaFormatSize((ULONG64)memoryListInfo.FreePageCount * PAGE_SIZE, -1)->Buffer); + SetDlgItemText(hwndDlg, IDC_ZLISTMODIFIED_V, PhaFormatSize((ULONG64)memoryListInfo.ModifiedPageCount * PAGE_SIZE, -1)->Buffer); + SetDlgItemText(hwndDlg, IDC_ZLISTMODIFIEDNOWRITE_V, PhaFormatSize((ULONG64)memoryListInfo.ModifiedNoWritePageCount * PAGE_SIZE, -1)->Buffer); + SetDlgItemText(hwndDlg, IDC_ZLISTBAD_V, PhaFormatSize((ULONG64)memoryListInfo.BadPageCount * PAGE_SIZE, -1)->Buffer); + SetDlgItemText(hwndDlg, IDC_ZLISTSTANDBY_V, PhaFormatSize((ULONG64)standbyPageCount * PAGE_SIZE, -1)->Buffer); + SetDlgItemText(hwndDlg, IDC_ZLISTSTANDBY0_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[0] * PAGE_SIZE, -1)->Buffer); + SetDlgItemText(hwndDlg, IDC_ZLISTSTANDBY1_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[1] * PAGE_SIZE, -1)->Buffer); + SetDlgItemText(hwndDlg, IDC_ZLISTSTANDBY2_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[2] * PAGE_SIZE, -1)->Buffer); + SetDlgItemText(hwndDlg, IDC_ZLISTSTANDBY3_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[3] * PAGE_SIZE, -1)->Buffer); + SetDlgItemText(hwndDlg, IDC_ZLISTSTANDBY4_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[4] * PAGE_SIZE, -1)->Buffer); + SetDlgItemText(hwndDlg, IDC_ZLISTSTANDBY5_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[5] * PAGE_SIZE, -1)->Buffer); + SetDlgItemText(hwndDlg, IDC_ZLISTSTANDBY6_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[6] * PAGE_SIZE, -1)->Buffer); + SetDlgItemText(hwndDlg, IDC_ZLISTSTANDBY7_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[7] * PAGE_SIZE, -1)->Buffer); + SetDlgItemText(hwndDlg, IDC_ZLISTREPURPOSED_V, PhaFormatSize((ULONG64)repurposedPageCount * PAGE_SIZE, -1)->Buffer); + SetDlgItemText(hwndDlg, IDC_ZLISTREPURPOSED0_V, PhaFormatSize((ULONG64)memoryListInfo.RepurposedPagesByPriority[0] * PAGE_SIZE, -1)->Buffer); + SetDlgItemText(hwndDlg, IDC_ZLISTREPURPOSED1_V, PhaFormatSize((ULONG64)memoryListInfo.RepurposedPagesByPriority[1] * PAGE_SIZE, -1)->Buffer); + SetDlgItemText(hwndDlg, IDC_ZLISTREPURPOSED2_V, PhaFormatSize((ULONG64)memoryListInfo.RepurposedPagesByPriority[2] * PAGE_SIZE, -1)->Buffer); + SetDlgItemText(hwndDlg, IDC_ZLISTREPURPOSED3_V, PhaFormatSize((ULONG64)memoryListInfo.RepurposedPagesByPriority[3] * PAGE_SIZE, -1)->Buffer); + SetDlgItemText(hwndDlg, IDC_ZLISTREPURPOSED4_V, PhaFormatSize((ULONG64)memoryListInfo.RepurposedPagesByPriority[4] * PAGE_SIZE, -1)->Buffer); + SetDlgItemText(hwndDlg, IDC_ZLISTREPURPOSED5_V, PhaFormatSize((ULONG64)memoryListInfo.RepurposedPagesByPriority[5] * PAGE_SIZE, -1)->Buffer); + SetDlgItemText(hwndDlg, IDC_ZLISTREPURPOSED6_V, PhaFormatSize((ULONG64)memoryListInfo.RepurposedPagesByPriority[6] * PAGE_SIZE, -1)->Buffer); + SetDlgItemText(hwndDlg, IDC_ZLISTREPURPOSED7_V, PhaFormatSize((ULONG64)memoryListInfo.RepurposedPagesByPriority[7] * PAGE_SIZE, -1)->Buffer); + + if (WindowsVersion >= WINDOWS_8) + SetDlgItemText(hwndDlg, IDC_ZLISTMODIFIEDPAGEFILE_V, PhaFormatSize((ULONG64)memoryListInfo.ModifiedPageCountPageFile * PAGE_SIZE, -1)->Buffer); + else + SetDlgItemText(hwndDlg, IDC_ZLISTMODIFIEDPAGEFILE_V, L"N/A"); + } + else + { + SetDlgItemText(hwndDlg, IDC_ZLISTZEROED_V, L"Unknown"); + SetDlgItemText(hwndDlg, IDC_ZLISTFREE_V, L"Unknown"); + SetDlgItemText(hwndDlg, IDC_ZLISTMODIFIED_V, L"Unknown"); + SetDlgItemText(hwndDlg, IDC_ZLISTMODIFIEDNOWRITE_V, L"Unknown"); + SetDlgItemText(hwndDlg, IDC_ZLISTMODIFIEDPAGEFILE_V, L"Unknown"); + SetDlgItemText(hwndDlg, IDC_ZLISTBAD_V, L"Unknown"); + SetDlgItemText(hwndDlg, IDC_ZLISTSTANDBY_V, L"Unknown"); + SetDlgItemText(hwndDlg, IDC_ZLISTSTANDBY0_V, L"Unknown"); + SetDlgItemText(hwndDlg, IDC_ZLISTSTANDBY1_V, L"Unknown"); + SetDlgItemText(hwndDlg, IDC_ZLISTSTANDBY2_V, L"Unknown"); + SetDlgItemText(hwndDlg, IDC_ZLISTSTANDBY3_V, L"Unknown"); + SetDlgItemText(hwndDlg, IDC_ZLISTSTANDBY4_V, L"Unknown"); + SetDlgItemText(hwndDlg, IDC_ZLISTSTANDBY5_V, L"Unknown"); + SetDlgItemText(hwndDlg, IDC_ZLISTSTANDBY6_V, L"Unknown"); + SetDlgItemText(hwndDlg, IDC_ZLISTSTANDBY7_V, L"Unknown"); + SetDlgItemText(hwndDlg, IDC_ZLISTREPURPOSED_V, L"Unknown"); + SetDlgItemText(hwndDlg, IDC_ZLISTREPURPOSED0_V, L"Unknown"); + SetDlgItemText(hwndDlg, IDC_ZLISTREPURPOSED1_V, L"Unknown"); + SetDlgItemText(hwndDlg, IDC_ZLISTREPURPOSED2_V, L"Unknown"); + SetDlgItemText(hwndDlg, IDC_ZLISTREPURPOSED3_V, L"Unknown"); + SetDlgItemText(hwndDlg, IDC_ZLISTREPURPOSED4_V, L"Unknown"); + SetDlgItemText(hwndDlg, IDC_ZLISTREPURPOSED5_V, L"Unknown"); + SetDlgItemText(hwndDlg, IDC_ZLISTREPURPOSED6_V, L"Unknown"); + SetDlgItemText(hwndDlg, IDC_ZLISTREPURPOSED7_V, L"Unknown"); + } +} + +INT_PTR CALLBACK PhpMemoryListsDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + switch (uMsg) + { + case WM_INITDIALOG: + { + PhRegisterCallback(&PhProcessesUpdatedEvent, ProcessesUpdatedCallback, NULL, &ProcessesUpdatedRegistration); + PhpUpdateMemoryListInfo(hwndDlg); + + PhLoadWindowPlacementFromSetting(L"MemoryListsWindowPosition", NULL, hwndDlg); + PhRegisterDialog(hwndDlg); + } + break; + case WM_DESTROY: + { + PhUnregisterDialog(hwndDlg); + PhSaveWindowPlacementToSetting(L"MemoryListsWindowPosition", NULL, hwndDlg); + + PhUnregisterCallback(&PhProcessesUpdatedEvent, &ProcessesUpdatedRegistration); + + UnregisterDialogFunction(hwndDlg); + PhMemoryListsWindowHandle = NULL; + } + break; + case WM_COMMAND: + { + switch (LOWORD(wParam)) + { + case IDCANCEL: + case IDOK: + DestroyWindow(hwndDlg); + break; + case IDC_EMPTY: + { + PPH_EMENU menu; + RECT buttonRect; + POINT point; + PPH_EMENU_ITEM selectedItem; + SYSTEM_MEMORY_LIST_COMMAND command = -1; + + menu = PhCreateEMenu(); + PhLoadResourceEMenuItem(menu, PhInstanceHandle, MAKEINTRESOURCE(IDR_EMPTYMEMLISTS), 0); + + GetClientRect(GetDlgItem(hwndDlg, IDC_EMPTY), &buttonRect); + point.x = 0; + point.y = buttonRect.bottom; + + ClientToScreen(GetDlgItem(hwndDlg, IDC_EMPTY), &point); + selectedItem = PhShowEMenu(menu, hwndDlg, PH_EMENU_SHOW_LEFTRIGHT, + PH_ALIGN_LEFT | PH_ALIGN_TOP, point.x, point.y); + + if (selectedItem) + { + switch (selectedItem->Id) + { + case ID_EMPTY_EMPTYWORKINGSETS: + command = MemoryEmptyWorkingSets; + break; + case ID_EMPTY_EMPTYMODIFIEDPAGELIST: + command = MemoryFlushModifiedList; + break; + case ID_EMPTY_EMPTYSTANDBYLIST: + command = MemoryPurgeStandbyList; + break; + case ID_EMPTY_EMPTYPRIORITY0STANDBYLIST: + command = MemoryPurgeLowPriorityStandbyList; + break; + } + } + + if (command != -1) + { + NTSTATUS status; + + SetCursor(LoadCursor(NULL, IDC_WAIT)); + status = NtSetSystemInformation( + SystemMemoryListInformation, + &command, + sizeof(SYSTEM_MEMORY_LIST_COMMAND) + ); + SetCursor(LoadCursor(NULL, IDC_ARROW)); + + if (status == STATUS_PRIVILEGE_NOT_HELD) + { + if (!PhGetOwnTokenAttributes().Elevated) + { + if (PhUiConnectToPhSvc(hwndDlg, FALSE)) + { + SetCursor(LoadCursor(NULL, IDC_WAIT)); + status = PhSvcCallIssueMemoryListCommand(command); + SetCursor(LoadCursor(NULL, IDC_ARROW)); + PhUiDisconnectFromPhSvc(); + } + else + { + // User cancelled eleavtion. + status = STATUS_SUCCESS; + } + } + } + + if (!NT_SUCCESS(status)) + { + PhShowStatus(hwndDlg, L"Unable to execute the memory list command", status, 0); + } + } + + PhDestroyEMenu(menu); + } + break; + } + } + break; + case MSG_UPDATE: + { + PhpUpdateMemoryListInfo(hwndDlg); + } + break; + } + + return FALSE; +} diff --git a/ProcessHacker/memprot.c b/ProcessHacker/memprot.c index d52168c948c2..5feec758b8b9 100644 --- a/ProcessHacker/memprot.c +++ b/ProcessHacker/memprot.c @@ -1,162 +1,162 @@ -/* - * Process Hacker - - * memory protection window - * - * Copyright (C) 2010 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include - -#include - -#include -#include - -typedef struct _MEMORY_PROTECT_CONTEXT -{ - PPH_PROCESS_ITEM ProcessItem; - PPH_MEMORY_ITEM MemoryItem; -} MEMORY_PROTECT_CONTEXT, *PMEMORY_PROTECT_CONTEXT; - -INT_PTR CALLBACK PhpMemoryProtectDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -VOID PhShowMemoryProtectDialog( - _In_ HWND ParentWindowHandle, - _In_ PPH_PROCESS_ITEM ProcessItem, - _In_ PPH_MEMORY_ITEM MemoryItem - ) -{ - MEMORY_PROTECT_CONTEXT context; - - context.ProcessItem = ProcessItem; - context.MemoryItem = MemoryItem; - - DialogBoxParam( - PhInstanceHandle, - MAKEINTRESOURCE(IDD_MEMPROTECT), - ParentWindowHandle, - PhpMemoryProtectDlgProc, - (LPARAM)&context - ); -} - -static INT_PTR CALLBACK PhpMemoryProtectDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - switch (uMsg) - { - case WM_INITDIALOG: - { - SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)lParam); - - PhCenterWindow(hwndDlg, GetParent(hwndDlg)); - - SetDlgItemText(hwndDlg, IDC_INTRO, - L"Possible values:\r\n" - L"\r\n" - L"0x01 - PAGE_NOACCESS\r\n" - L"0x02 - PAGE_READONLY\r\n" - L"0x04 - PAGE_READWRITE\r\n" - L"0x08 - PAGE_WRITECOPY\r\n" - L"0x10 - PAGE_EXECUTE\r\n" - L"0x20 - PAGE_EXECUTE_READ\r\n" - L"0x40 - PAGE_EXECUTE_READWRITE\r\n" - L"0x80 - PAGE_EXECUTE_WRITECOPY\r\n" - L"Modifiers:\r\n" - L"0x100 - PAGE_GUARD\r\n" - L"0x200 - PAGE_NOCACHE\r\n" - L"0x400 - PAGE_WRITECOMBINE\r\n" - ); - - SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hwndDlg, IDC_VALUE), TRUE); - } - break; - case WM_DESTROY: - { - RemoveProp(hwndDlg, PhMakeContextAtom()); - } - break; - case WM_COMMAND: - { - switch (LOWORD(wParam)) - { - case IDCANCEL: - EndDialog(hwndDlg, IDCANCEL); - break; - case IDOK: - { - NTSTATUS status; - PMEMORY_PROTECT_CONTEXT context = (PMEMORY_PROTECT_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom()); - HANDLE processHandle; - ULONG64 protect; - - PhStringToInteger64(&PhaGetDlgItemText(hwndDlg, IDC_VALUE)->sr, 0, &protect); - - if (NT_SUCCESS(status = PhOpenProcess( - &processHandle, - PROCESS_VM_OPERATION, - context->ProcessItem->ProcessId - ))) - { - PVOID baseAddress; - SIZE_T regionSize; - ULONG oldProtect; - - baseAddress = context->MemoryItem->BaseAddress; - regionSize = context->MemoryItem->RegionSize; - - status = NtProtectVirtualMemory( - processHandle, - &baseAddress, - ®ionSize, - (ULONG)protect, - &oldProtect - ); - - if (NT_SUCCESS(status)) - context->MemoryItem->Protect = (ULONG)protect; - } - - if (NT_SUCCESS(status)) - { - EndDialog(hwndDlg, IDOK); - } - else - { - PhShowStatus(hwndDlg, L"Unable to change memory protection", status, 0); - SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hwndDlg, IDC_VALUE), TRUE); - Edit_SetSel(GetDlgItem(hwndDlg, IDC_VALUE), 0, -1); - } - } - break; - } - } - break; - } - - return FALSE; -} +/* + * Process Hacker - + * memory protection window + * + * Copyright (C) 2010 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include + +#include + +#include +#include + +typedef struct _MEMORY_PROTECT_CONTEXT +{ + PPH_PROCESS_ITEM ProcessItem; + PPH_MEMORY_ITEM MemoryItem; +} MEMORY_PROTECT_CONTEXT, *PMEMORY_PROTECT_CONTEXT; + +INT_PTR CALLBACK PhpMemoryProtectDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +VOID PhShowMemoryProtectDialog( + _In_ HWND ParentWindowHandle, + _In_ PPH_PROCESS_ITEM ProcessItem, + _In_ PPH_MEMORY_ITEM MemoryItem + ) +{ + MEMORY_PROTECT_CONTEXT context; + + context.ProcessItem = ProcessItem; + context.MemoryItem = MemoryItem; + + DialogBoxParam( + PhInstanceHandle, + MAKEINTRESOURCE(IDD_MEMPROTECT), + ParentWindowHandle, + PhpMemoryProtectDlgProc, + (LPARAM)&context + ); +} + +static INT_PTR CALLBACK PhpMemoryProtectDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + switch (uMsg) + { + case WM_INITDIALOG: + { + SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)lParam); + + PhCenterWindow(hwndDlg, GetParent(hwndDlg)); + + SetDlgItemText(hwndDlg, IDC_INTRO, + L"Possible values:\r\n" + L"\r\n" + L"0x01 - PAGE_NOACCESS\r\n" + L"0x02 - PAGE_READONLY\r\n" + L"0x04 - PAGE_READWRITE\r\n" + L"0x08 - PAGE_WRITECOPY\r\n" + L"0x10 - PAGE_EXECUTE\r\n" + L"0x20 - PAGE_EXECUTE_READ\r\n" + L"0x40 - PAGE_EXECUTE_READWRITE\r\n" + L"0x80 - PAGE_EXECUTE_WRITECOPY\r\n" + L"Modifiers:\r\n" + L"0x100 - PAGE_GUARD\r\n" + L"0x200 - PAGE_NOCACHE\r\n" + L"0x400 - PAGE_WRITECOMBINE\r\n" + ); + + SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hwndDlg, IDC_VALUE), TRUE); + } + break; + case WM_DESTROY: + { + RemoveProp(hwndDlg, PhMakeContextAtom()); + } + break; + case WM_COMMAND: + { + switch (LOWORD(wParam)) + { + case IDCANCEL: + EndDialog(hwndDlg, IDCANCEL); + break; + case IDOK: + { + NTSTATUS status; + PMEMORY_PROTECT_CONTEXT context = (PMEMORY_PROTECT_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom()); + HANDLE processHandle; + ULONG64 protect; + + PhStringToInteger64(&PhaGetDlgItemText(hwndDlg, IDC_VALUE)->sr, 0, &protect); + + if (NT_SUCCESS(status = PhOpenProcess( + &processHandle, + PROCESS_VM_OPERATION, + context->ProcessItem->ProcessId + ))) + { + PVOID baseAddress; + SIZE_T regionSize; + ULONG oldProtect; + + baseAddress = context->MemoryItem->BaseAddress; + regionSize = context->MemoryItem->RegionSize; + + status = NtProtectVirtualMemory( + processHandle, + &baseAddress, + ®ionSize, + (ULONG)protect, + &oldProtect + ); + + if (NT_SUCCESS(status)) + context->MemoryItem->Protect = (ULONG)protect; + } + + if (NT_SUCCESS(status)) + { + EndDialog(hwndDlg, IDOK); + } + else + { + PhShowStatus(hwndDlg, L"Unable to change memory protection", status, 0); + SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hwndDlg, IDC_VALUE), TRUE); + Edit_SetSel(GetDlgItem(hwndDlg, IDC_VALUE), 0, -1); + } + } + break; + } + } + break; + } + + return FALSE; +} diff --git a/ProcessHacker/memprv.c b/ProcessHacker/memprv.c index 35e10d10ff50..14e9ca24bc42 100644 --- a/ProcessHacker/memprv.c +++ b/ProcessHacker/memprv.c @@ -1,810 +1,810 @@ -/* - * Process Hacker - - * memory provider - * - * Copyright (C) 2010-2015 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include -#include - -#include - -#define MAX_HEAPS 1000 -#define WS_REQUEST_COUNT (PAGE_SIZE / sizeof(MEMORY_WORKING_SET_EX_INFORMATION)) - -VOID PhpMemoryItemDeleteProcedure( - _In_ PVOID Object, - _In_ ULONG Flags - ); - -PPH_OBJECT_TYPE PhMemoryItemType; - -BOOLEAN PhMemoryProviderInitialization( - VOID - ) -{ - PhMemoryItemType = PhCreateObjectType(L"MemoryItem", 0, PhpMemoryItemDeleteProcedure); - - return TRUE; -} - -VOID PhGetMemoryProtectionString( - _In_ ULONG Protection, - _Out_writes_(17) PWSTR String - ) -{ - PWSTR string; - PH_STRINGREF base; - - if (!Protection) - { - String[0] = 0; - return; - } - - if (Protection & PAGE_NOACCESS) - PhInitializeStringRef(&base, L"NA"); - else if (Protection & PAGE_READONLY) - PhInitializeStringRef(&base, L"R"); - else if (Protection & PAGE_READWRITE) - PhInitializeStringRef(&base, L"RW"); - else if (Protection & PAGE_WRITECOPY) - PhInitializeStringRef(&base, L"WC"); - else if (Protection & PAGE_EXECUTE) - PhInitializeStringRef(&base, L"X"); - else if (Protection & PAGE_EXECUTE_READ) - PhInitializeStringRef(&base, L"RX"); - else if (Protection & PAGE_EXECUTE_READWRITE) - PhInitializeStringRef(&base, L"RWX"); - else if (Protection & PAGE_EXECUTE_WRITECOPY) - PhInitializeStringRef(&base, L"WCX"); - else - PhInitializeStringRef(&base, L"?"); - - string = String; - - memcpy(string, base.Buffer, base.Length); - string += base.Length / sizeof(WCHAR); - - if (Protection & PAGE_GUARD) - { - memcpy(string, L"+G", 2 * 2); - string += 2; - } - - if (Protection & PAGE_NOCACHE) - { - memcpy(string, L"+NC", 3 * 2); - string += 3; - } - - if (Protection & PAGE_WRITECOMBINE) - { - memcpy(string, L"+WCM", 4 * 2); - string += 4; - } - - *string = 0; -} - -PWSTR PhGetMemoryStateString( - _In_ ULONG State - ) -{ - if (State & MEM_COMMIT) - return L"Commit"; - else if (State & MEM_RESERVE) - return L"Reserved"; - else if (State & MEM_FREE) - return L"Free"; - else - return L"Unknown"; -} - -PWSTR PhGetMemoryTypeString( - _In_ ULONG Type - ) -{ - if (Type & MEM_PRIVATE) - return L"Private"; - else if (Type & MEM_MAPPED) - return L"Mapped"; - else if (Type & MEM_IMAGE) - return L"Image"; - else - return L"Unknown"; -} - -PPH_MEMORY_ITEM PhCreateMemoryItem( - VOID - ) -{ - PPH_MEMORY_ITEM memoryItem; - - memoryItem = PhCreateObject(sizeof(PH_MEMORY_ITEM), PhMemoryItemType); - memset(memoryItem, 0, sizeof(PH_MEMORY_ITEM)); - - return memoryItem; -} - -VOID PhpMemoryItemDeleteProcedure( - _In_ PVOID Object, - _In_ ULONG Flags - ) -{ - PPH_MEMORY_ITEM memoryItem = Object; - - switch (memoryItem->RegionType) - { - case CustomRegion: - PhClearReference(&memoryItem->u.Custom.Text); - break; - case MappedFileRegion: - PhClearReference(&memoryItem->u.MappedFile.FileName); - break; - } -} - -static LONG NTAPI PhpMemoryItemCompareFunction( - _In_ PPH_AVL_LINKS Links1, - _In_ PPH_AVL_LINKS Links2 - ) -{ - PPH_MEMORY_ITEM memoryItem1 = CONTAINING_RECORD(Links1, PH_MEMORY_ITEM, Links); - PPH_MEMORY_ITEM memoryItem2 = CONTAINING_RECORD(Links2, PH_MEMORY_ITEM, Links); - - return uintptrcmp((ULONG_PTR)memoryItem1->BaseAddress, (ULONG_PTR)memoryItem2->BaseAddress); -} - -VOID PhDeleteMemoryItemList( - _In_ PPH_MEMORY_ITEM_LIST List - ) -{ - PLIST_ENTRY listEntry; - PPH_MEMORY_ITEM memoryItem; - - listEntry = List->ListHead.Flink; - - while (listEntry != &List->ListHead) - { - memoryItem = CONTAINING_RECORD(listEntry, PH_MEMORY_ITEM, ListEntry); - listEntry = listEntry->Flink; - - PhDereferenceObject(memoryItem); - } -} - -PPH_MEMORY_ITEM PhLookupMemoryItemList( - _In_ PPH_MEMORY_ITEM_LIST List, - _In_ PVOID Address - ) -{ - PH_MEMORY_ITEM lookupMemoryItem; - PPH_AVL_LINKS links; - PPH_MEMORY_ITEM memoryItem; - - // Do an approximate search on the set to locate the memory item with the largest - // base address that is still smaller than the given address. - lookupMemoryItem.BaseAddress = Address; - links = PhUpperDualBoundElementAvlTree(&List->Set, &lookupMemoryItem.Links); - - if (links) - { - memoryItem = CONTAINING_RECORD(links, PH_MEMORY_ITEM, Links); - - if ((ULONG_PTR)Address < (ULONG_PTR)memoryItem->BaseAddress + memoryItem->RegionSize) - return memoryItem; - } - - return NULL; -} - -PPH_MEMORY_ITEM PhpSetMemoryRegionType( - _In_ PPH_MEMORY_ITEM_LIST List, - _In_ PVOID Address, - _In_ BOOLEAN GoToAllocationBase, - _In_ PH_MEMORY_REGION_TYPE RegionType - ) -{ - PPH_MEMORY_ITEM memoryItem; - - memoryItem = PhLookupMemoryItemList(List, Address); - - if (!memoryItem) - return NULL; - - if (GoToAllocationBase && memoryItem->AllocationBaseItem) - memoryItem = memoryItem->AllocationBaseItem; - - if (memoryItem->RegionType != UnknownRegion) - return NULL; - - memoryItem->RegionType = RegionType; - - return memoryItem; -} - -NTSTATUS PhpUpdateMemoryRegionTypes( - _In_ PPH_MEMORY_ITEM_LIST List, - _In_ HANDLE ProcessHandle - ) -{ - NTSTATUS status; - PVOID processes; - PSYSTEM_PROCESS_INFORMATION process; - ULONG i; -#ifdef _WIN64 - BOOLEAN isWow64 = FALSE; -#endif - PPH_MEMORY_ITEM memoryItem; - PLIST_ENTRY listEntry; - - if (!NT_SUCCESS(status = PhEnumProcessesEx(&processes, SystemExtendedProcessInformation))) - return status; - - process = PhFindProcessInformation(processes, List->ProcessId); - - if (!process) - { - PhFree(processes); - return STATUS_NOT_FOUND; - } - - // USER_SHARED_DATA - PhpSetMemoryRegionType(List, USER_SHARED_DATA, TRUE, UserSharedDataRegion); - - // PEB, heap - { - PROCESS_BASIC_INFORMATION basicInfo; - ULONG numberOfHeaps; - PVOID processHeapsPtr; - PVOID *processHeaps; - ULONG i; -#ifdef _WIN64 - PVOID peb32; - ULONG processHeapsPtr32; - ULONG *processHeaps32; -#endif - - if (NT_SUCCESS(PhGetProcessBasicInformation(ProcessHandle, &basicInfo)) && basicInfo.PebBaseAddress != 0) - { - PhpSetMemoryRegionType(List, basicInfo.PebBaseAddress, TRUE, PebRegion); - - if (NT_SUCCESS(NtReadVirtualMemory(ProcessHandle, - PTR_ADD_OFFSET(basicInfo.PebBaseAddress, FIELD_OFFSET(PEB, NumberOfHeaps)), - &numberOfHeaps, sizeof(ULONG), NULL)) && numberOfHeaps < MAX_HEAPS) - { - processHeaps = PhAllocate(numberOfHeaps * sizeof(PVOID)); - - if (NT_SUCCESS(NtReadVirtualMemory(ProcessHandle, - PTR_ADD_OFFSET(basicInfo.PebBaseAddress, FIELD_OFFSET(PEB, ProcessHeaps)), - &processHeapsPtr, sizeof(PVOID), NULL)) && - NT_SUCCESS(NtReadVirtualMemory(ProcessHandle, - processHeapsPtr, - processHeaps, numberOfHeaps * sizeof(PVOID), NULL))) - { - for (i = 0; i < numberOfHeaps; i++) - { - if (memoryItem = PhpSetMemoryRegionType(List, processHeaps[i], TRUE, HeapRegion)) - memoryItem->u.Heap.Index = i; - } - } - - PhFree(processHeaps); - } - } -#ifdef _WIN64 - - if (NT_SUCCESS(PhGetProcessPeb32(ProcessHandle, &peb32)) && peb32 != 0) - { - isWow64 = TRUE; - PhpSetMemoryRegionType(List, peb32, TRUE, Peb32Region); - - if (NT_SUCCESS(NtReadVirtualMemory(ProcessHandle, - PTR_ADD_OFFSET(peb32, FIELD_OFFSET(PEB32, NumberOfHeaps)), - &numberOfHeaps, sizeof(ULONG), NULL)) && numberOfHeaps < MAX_HEAPS) - { - processHeaps32 = PhAllocate(numberOfHeaps * sizeof(ULONG)); - - if (NT_SUCCESS(NtReadVirtualMemory(ProcessHandle, - PTR_ADD_OFFSET(peb32, FIELD_OFFSET(PEB32, ProcessHeaps)), - &processHeapsPtr32, sizeof(ULONG), NULL)) && - NT_SUCCESS(NtReadVirtualMemory(ProcessHandle, - UlongToPtr(processHeapsPtr32), - processHeaps32, numberOfHeaps * sizeof(ULONG), NULL))) - { - for (i = 0; i < numberOfHeaps; i++) - { - if (memoryItem = PhpSetMemoryRegionType(List, UlongToPtr(processHeaps32[i]), TRUE, Heap32Region)) - memoryItem->u.Heap.Index = i; - } - } - - PhFree(processHeaps32); - } - } -#endif - } - - // TEB, stack - for (i = 0; i < process->NumberOfThreads; i++) - { - PSYSTEM_EXTENDED_THREAD_INFORMATION thread = (PSYSTEM_EXTENDED_THREAD_INFORMATION)process->Threads + i; - - if (WindowsVersion < WINDOWS_VISTA) - { - HANDLE threadHandle; - THREAD_BASIC_INFORMATION basicInfo; - - if (NT_SUCCESS(PhOpenThread(&threadHandle, ThreadQueryAccess, thread->ThreadInfo.ClientId.UniqueThread))) - { - if (NT_SUCCESS(PhGetThreadBasicInformation(threadHandle, &basicInfo))) - thread->TebBase = basicInfo.TebBaseAddress; - - NtClose(threadHandle); - } - } - - if (thread->TebBase) - { - NT_TIB ntTib; - SIZE_T bytesRead; - - if (memoryItem = PhpSetMemoryRegionType(List, thread->TebBase, TRUE, TebRegion)) - memoryItem->u.Teb.ThreadId = thread->ThreadInfo.ClientId.UniqueThread; - - if (NT_SUCCESS(NtReadVirtualMemory(ProcessHandle, thread->TebBase, &ntTib, sizeof(NT_TIB), &bytesRead)) && - bytesRead == sizeof(NT_TIB)) - { - if ((ULONG_PTR)ntTib.StackLimit < (ULONG_PTR)ntTib.StackBase) - { - if (memoryItem = PhpSetMemoryRegionType(List, ntTib.StackLimit, TRUE, StackRegion)) - memoryItem->u.Stack.ThreadId = thread->ThreadInfo.ClientId.UniqueThread; - } -#ifdef _WIN64 - - if (isWow64 && ntTib.ExceptionList) - { - ULONG teb32 = PtrToUlong(ntTib.ExceptionList); - NT_TIB32 ntTib32; - - // 64-bit and 32-bit TEBs usually share the same memory region, so don't do anything for the 32-bit - // TEB. - - if (NT_SUCCESS(NtReadVirtualMemory(ProcessHandle, UlongToPtr(teb32), &ntTib32, sizeof(NT_TIB32), &bytesRead)) && - bytesRead == sizeof(NT_TIB32)) - { - if (ntTib32.StackLimit < ntTib32.StackBase) - { - if (memoryItem = PhpSetMemoryRegionType(List, UlongToPtr(ntTib32.StackLimit), TRUE, Stack32Region)) - memoryItem->u.Stack.ThreadId = thread->ThreadInfo.ClientId.UniqueThread; - } - } - } -#endif - } - } - } - - // Mapped file, heap segment, unusable - for (listEntry = List->ListHead.Flink; listEntry != &List->ListHead; listEntry = listEntry->Flink) - { - memoryItem = CONTAINING_RECORD(listEntry, PH_MEMORY_ITEM, ListEntry); - - if (memoryItem->RegionType != UnknownRegion) - continue; - - if ((memoryItem->Type & (MEM_MAPPED | MEM_IMAGE)) && memoryItem->AllocationBaseItem == memoryItem) - { - PPH_STRING fileName; - - if (NT_SUCCESS(PhGetProcessMappedFileName(ProcessHandle, memoryItem->BaseAddress, &fileName))) - { - PPH_STRING newFileName = PhResolveDevicePrefix(fileName); - - if (newFileName) - PhMoveReference(&fileName, newFileName); - - memoryItem->RegionType = MappedFileRegion; - memoryItem->u.MappedFile.FileName = fileName; - continue; - } - } - - if (memoryItem->State & MEM_COMMIT) - { - UCHAR buffer[HEAP_SEGMENT_MAX_SIZE]; - - if (NT_SUCCESS(NtReadVirtualMemory(ProcessHandle, memoryItem->BaseAddress, - buffer, sizeof(buffer), NULL))) - { - PVOID candidateHeap = NULL; - ULONG candidateHeap32 = 0; - PPH_MEMORY_ITEM heapMemoryItem; - - if (WindowsVersion >= WINDOWS_VISTA) - { - PHEAP_SEGMENT heapSegment = (PHEAP_SEGMENT)buffer; - PHEAP_SEGMENT32 heapSegment32 = (PHEAP_SEGMENT32)buffer; - - if (heapSegment->SegmentSignature == HEAP_SEGMENT_SIGNATURE) - candidateHeap = heapSegment->Heap; - if (heapSegment32->SegmentSignature == HEAP_SEGMENT_SIGNATURE) - candidateHeap32 = heapSegment32->Heap; - } - else - { - PHEAP_SEGMENT_OLD heapSegment = (PHEAP_SEGMENT_OLD)buffer; - PHEAP_SEGMENT_OLD32 heapSegment32 = (PHEAP_SEGMENT_OLD32)buffer; - - if (heapSegment->Signature == HEAP_SEGMENT_SIGNATURE) - candidateHeap = heapSegment->Heap; - if (heapSegment32->Signature == HEAP_SEGMENT_SIGNATURE) - candidateHeap32 = heapSegment32->Heap; - } - - if (candidateHeap) - { - heapMemoryItem = PhLookupMemoryItemList(List, candidateHeap); - - if (heapMemoryItem && heapMemoryItem->BaseAddress == candidateHeap && - heapMemoryItem->RegionType == HeapRegion) - { - memoryItem->RegionType = HeapSegmentRegion; - memoryItem->u.HeapSegment.HeapItem = heapMemoryItem; - continue; - } - } - else if (candidateHeap32) - { - heapMemoryItem = PhLookupMemoryItemList(List, UlongToPtr(candidateHeap32)); - - if (heapMemoryItem && heapMemoryItem->BaseAddress == UlongToPtr(candidateHeap32) && - heapMemoryItem->RegionType == Heap32Region) - { - memoryItem->RegionType = HeapSegment32Region; - memoryItem->u.HeapSegment.HeapItem = heapMemoryItem; - continue; - } - } - } - } - } - -#ifdef _WIN64 - // CFG bitmaps for 64-bit processes - if (!isWow64) - { - LDR_INIT_BLOCK ldrInitBlock = { 0 }; - PVOID ldrInitBlockBaseAddress = NULL; - PPH_MEMORY_ITEM cfgBitmapMemoryItem; - PPH_STRING ntdllFileName; - - ntdllFileName = PhConcatStrings2(USER_SHARED_DATA->NtSystemRoot, L"\\System32\\ntdll.dll"); - status = PhGetProcedureAddressRemote( - ProcessHandle, - ntdllFileName->Buffer, - "LdrSystemDllInitBlock", - 0, - &ldrInitBlockBaseAddress, - NULL - ); - - if (NT_SUCCESS(status) && ldrInitBlockBaseAddress) - { - status = NtReadVirtualMemory( - ProcessHandle, - ldrInitBlockBaseAddress, - &ldrInitBlock, - sizeof(LDR_INIT_BLOCK), - NULL - ); - } - - PhDereferenceObject(ntdllFileName); - - if (NT_SUCCESS(status)) - { - PVOID cfgBitmapAddress = NULL; - - // TODO: Remove this code once most users have updated their machines. - if (ldrInitBlock.Size == sizeof(LDR_INIT_BLOCK)) - cfgBitmapAddress = ldrInitBlock.CfgBitmapAddress; // 15063 - else if (ldrInitBlock.Size == 128) - cfgBitmapAddress = ldrInitBlock.Unknown1[11]; // 14393 - - if (cfgBitmapAddress && (cfgBitmapMemoryItem = PhLookupMemoryItemList(List, cfgBitmapAddress))) - { - PLIST_ENTRY listEntry = &cfgBitmapMemoryItem->ListEntry; - PPH_MEMORY_ITEM memoryItem = CONTAINING_RECORD(listEntry, PH_MEMORY_ITEM, ListEntry); - - // Tagging memory items - while (memoryItem->AllocationBaseItem == cfgBitmapMemoryItem) - { - // NB : we could do a finer tagging since each MEM_COMMIT memory - // map is the CFG bitmap of a loaded module. However that would - // imply to heavily rely on reverse-engineer results, and might be - // brittle to changes made by Windows dev teams. - memoryItem->RegionType = CfgBitmapRegion; - - listEntry = listEntry->Flink; - memoryItem = CONTAINING_RECORD(listEntry, PH_MEMORY_ITEM, ListEntry); - } - } - } - } -#endif - - PhFree(processes); - - return STATUS_SUCCESS; -} - -NTSTATUS PhpUpdateMemoryWsCounters( - _In_ PPH_MEMORY_ITEM_LIST List, - _In_ HANDLE ProcessHandle - ) -{ - PLIST_ENTRY listEntry; - PMEMORY_WORKING_SET_EX_INFORMATION info; - - info = PhAllocatePage(WS_REQUEST_COUNT * sizeof(MEMORY_WORKING_SET_EX_INFORMATION), NULL); - - if (!info) - return STATUS_NO_MEMORY; - - for (listEntry = List->ListHead.Flink; listEntry != &List->ListHead; listEntry = listEntry->Flink) - { - PPH_MEMORY_ITEM memoryItem = CONTAINING_RECORD(listEntry, PH_MEMORY_ITEM, ListEntry); - ULONG_PTR virtualAddress; - SIZE_T remainingPages; - SIZE_T requestPages; - SIZE_T i; - - if (!(memoryItem->State & MEM_COMMIT)) - continue; - - virtualAddress = (ULONG_PTR)memoryItem->BaseAddress; - remainingPages = memoryItem->RegionSize / PAGE_SIZE; - - while (remainingPages != 0) - { - requestPages = min(remainingPages, WS_REQUEST_COUNT); - - for (i = 0; i < requestPages; i++) - { - info[i].VirtualAddress = (PVOID)virtualAddress; - virtualAddress += PAGE_SIZE; - } - - if (NT_SUCCESS(NtQueryVirtualMemory( - ProcessHandle, - NULL, - MemoryWorkingSetExInformation, - info, - requestPages * sizeof(MEMORY_WORKING_SET_EX_INFORMATION), - NULL - ))) - { - for (i = 0; i < requestPages; i++) - { - PMEMORY_WORKING_SET_EX_BLOCK block = &info[i].u1.VirtualAttributes; - - if (block->Valid) - { - memoryItem->TotalWorkingSetPages++; - - if (block->ShareCount > 1) - memoryItem->SharedWorkingSetPages++; - if (block->ShareCount == 0) - memoryItem->PrivateWorkingSetPages++; - if (block->Shared) - memoryItem->ShareableWorkingSetPages++; - if (block->Locked) - memoryItem->LockedWorkingSetPages++; - } - } - } - - remainingPages -= requestPages; - } - } - - PhFreePage(info); - - return STATUS_SUCCESS; -} - -NTSTATUS PhpUpdateMemoryWsCountersOld( - _In_ PPH_MEMORY_ITEM_LIST List, - _In_ HANDLE ProcessHandle - ) -{ - NTSTATUS status; - PMEMORY_WORKING_SET_INFORMATION info; - PPH_MEMORY_ITEM memoryItem = NULL; - ULONG_PTR i; - - if (!NT_SUCCESS(status = PhGetProcessWorkingSetInformation(ProcessHandle, &info))) - return status; - - for (i = 0; i < info->NumberOfEntries; i++) - { - PMEMORY_WORKING_SET_BLOCK block = &info->WorkingSetInfo[i]; - ULONG_PTR virtualAddress = block->VirtualPage * PAGE_SIZE; - - if (!memoryItem || virtualAddress < (ULONG_PTR)memoryItem->BaseAddress || - virtualAddress >= (ULONG_PTR)memoryItem->BaseAddress + memoryItem->RegionSize) - { - memoryItem = PhLookupMemoryItemList(List, (PVOID)virtualAddress); - } - - if (memoryItem) - { - memoryItem->TotalWorkingSetPages++; - - if (block->ShareCount > 1) - memoryItem->SharedWorkingSetPages++; - if (block->ShareCount == 0) - memoryItem->PrivateWorkingSetPages++; - if (block->Shared) - memoryItem->ShareableWorkingSetPages++; - } - } - - PhFree(info); - - return STATUS_SUCCESS; -} - -NTSTATUS PhQueryMemoryItemList( - _In_ HANDLE ProcessId, - _In_ ULONG Flags, - _Out_ PPH_MEMORY_ITEM_LIST List - ) -{ - NTSTATUS status; - HANDLE processHandle; - ULONG_PTR allocationGranularity; - PVOID baseAddress = (PVOID)0; - MEMORY_BASIC_INFORMATION basicInfo; - PPH_MEMORY_ITEM allocationBaseItem = NULL; - PPH_MEMORY_ITEM previousMemoryItem = NULL; - - if (!NT_SUCCESS(status = PhOpenProcess( - &processHandle, - PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, - ProcessId - ))) - { - if (!NT_SUCCESS(status = PhOpenProcess( - &processHandle, - PROCESS_QUERY_INFORMATION, - ProcessId - ))) - { - return status; - } - } - - List->ProcessId = ProcessId; - PhInitializeAvlTree(&List->Set, PhpMemoryItemCompareFunction); - InitializeListHead(&List->ListHead); - - allocationGranularity = PhSystemBasicInformation.AllocationGranularity; - - while (NT_SUCCESS(NtQueryVirtualMemory( - processHandle, - baseAddress, - MemoryBasicInformation, - &basicInfo, - sizeof(MEMORY_BASIC_INFORMATION), - NULL - ))) - { - PPH_MEMORY_ITEM memoryItem; - - if (basicInfo.State & MEM_FREE) - { - if (Flags & PH_QUERY_MEMORY_IGNORE_FREE) - goto ContinueLoop; - - basicInfo.AllocationBase = basicInfo.BaseAddress; - } - - memoryItem = PhCreateMemoryItem(); - memoryItem->BasicInfo = basicInfo; - - if (basicInfo.AllocationBase == basicInfo.BaseAddress) - allocationBaseItem = memoryItem; - if (allocationBaseItem && basicInfo.AllocationBase == allocationBaseItem->BaseAddress) - memoryItem->AllocationBaseItem = allocationBaseItem; - - if (basicInfo.State & MEM_COMMIT) - { - memoryItem->CommittedSize = memoryItem->RegionSize; - - if (basicInfo.Type & MEM_PRIVATE) - memoryItem->PrivateSize = memoryItem->RegionSize; - } - - PhAddElementAvlTree(&List->Set, &memoryItem->Links); - InsertTailList(&List->ListHead, &memoryItem->ListEntry); - - if (basicInfo.State & MEM_FREE) - { - if ((ULONG_PTR)basicInfo.BaseAddress & (allocationGranularity - 1)) - { - ULONG_PTR nextAllocationBase; - ULONG_PTR potentialUnusableSize; - - // Split this free region into an unusable and a (possibly empty) usable region. - - nextAllocationBase = ALIGN_UP_BY(basicInfo.BaseAddress, allocationGranularity); - potentialUnusableSize = nextAllocationBase - (ULONG_PTR)basicInfo.BaseAddress; - - memoryItem->RegionType = UnusableRegion; - - // VMMap does this, but is it correct? - //if (previousMemoryItem && (previousMemoryItem->State & MEM_COMMIT)) - // memoryItem->CommittedSize = min(potentialUnusableSize, basicInfo.RegionSize); - - if (nextAllocationBase < (ULONG_PTR)basicInfo.BaseAddress + basicInfo.RegionSize) - { - PPH_MEMORY_ITEM otherMemoryItem; - - memoryItem->RegionSize = potentialUnusableSize; - - otherMemoryItem = PhCreateMemoryItem(); - otherMemoryItem->BasicInfo = basicInfo; - otherMemoryItem->BaseAddress = (PVOID)nextAllocationBase; - otherMemoryItem->AllocationBase = otherMemoryItem->BaseAddress; - otherMemoryItem->RegionSize = basicInfo.RegionSize - potentialUnusableSize; - otherMemoryItem->AllocationBaseItem = otherMemoryItem; - - PhAddElementAvlTree(&List->Set, &otherMemoryItem->Links); - InsertTailList(&List->ListHead, &otherMemoryItem->ListEntry); - - previousMemoryItem = otherMemoryItem; - goto ContinueLoop; - } - } - } - - previousMemoryItem = memoryItem; - -ContinueLoop: - baseAddress = PTR_ADD_OFFSET(baseAddress, basicInfo.RegionSize); - } - - if (Flags & PH_QUERY_MEMORY_REGION_TYPE) - PhpUpdateMemoryRegionTypes(List, processHandle); - - if (Flags & PH_QUERY_MEMORY_WS_COUNTERS) - { - if (WindowsVersion >= WINDOWS_SERVER_2003) - PhpUpdateMemoryWsCounters(List, processHandle); - else - PhpUpdateMemoryWsCountersOld(List, processHandle); - } - - NtClose(processHandle); - - return STATUS_SUCCESS; -} +/* + * Process Hacker - + * memory provider + * + * Copyright (C) 2010-2015 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include +#include + +#include + +#define MAX_HEAPS 1000 +#define WS_REQUEST_COUNT (PAGE_SIZE / sizeof(MEMORY_WORKING_SET_EX_INFORMATION)) + +VOID PhpMemoryItemDeleteProcedure( + _In_ PVOID Object, + _In_ ULONG Flags + ); + +PPH_OBJECT_TYPE PhMemoryItemType; + +BOOLEAN PhMemoryProviderInitialization( + VOID + ) +{ + PhMemoryItemType = PhCreateObjectType(L"MemoryItem", 0, PhpMemoryItemDeleteProcedure); + + return TRUE; +} + +VOID PhGetMemoryProtectionString( + _In_ ULONG Protection, + _Out_writes_(17) PWSTR String + ) +{ + PWSTR string; + PH_STRINGREF base; + + if (!Protection) + { + String[0] = 0; + return; + } + + if (Protection & PAGE_NOACCESS) + PhInitializeStringRef(&base, L"NA"); + else if (Protection & PAGE_READONLY) + PhInitializeStringRef(&base, L"R"); + else if (Protection & PAGE_READWRITE) + PhInitializeStringRef(&base, L"RW"); + else if (Protection & PAGE_WRITECOPY) + PhInitializeStringRef(&base, L"WC"); + else if (Protection & PAGE_EXECUTE) + PhInitializeStringRef(&base, L"X"); + else if (Protection & PAGE_EXECUTE_READ) + PhInitializeStringRef(&base, L"RX"); + else if (Protection & PAGE_EXECUTE_READWRITE) + PhInitializeStringRef(&base, L"RWX"); + else if (Protection & PAGE_EXECUTE_WRITECOPY) + PhInitializeStringRef(&base, L"WCX"); + else + PhInitializeStringRef(&base, L"?"); + + string = String; + + memcpy(string, base.Buffer, base.Length); + string += base.Length / sizeof(WCHAR); + + if (Protection & PAGE_GUARD) + { + memcpy(string, L"+G", 2 * 2); + string += 2; + } + + if (Protection & PAGE_NOCACHE) + { + memcpy(string, L"+NC", 3 * 2); + string += 3; + } + + if (Protection & PAGE_WRITECOMBINE) + { + memcpy(string, L"+WCM", 4 * 2); + string += 4; + } + + *string = 0; +} + +PWSTR PhGetMemoryStateString( + _In_ ULONG State + ) +{ + if (State & MEM_COMMIT) + return L"Commit"; + else if (State & MEM_RESERVE) + return L"Reserved"; + else if (State & MEM_FREE) + return L"Free"; + else + return L"Unknown"; +} + +PWSTR PhGetMemoryTypeString( + _In_ ULONG Type + ) +{ + if (Type & MEM_PRIVATE) + return L"Private"; + else if (Type & MEM_MAPPED) + return L"Mapped"; + else if (Type & MEM_IMAGE) + return L"Image"; + else + return L"Unknown"; +} + +PPH_MEMORY_ITEM PhCreateMemoryItem( + VOID + ) +{ + PPH_MEMORY_ITEM memoryItem; + + memoryItem = PhCreateObject(sizeof(PH_MEMORY_ITEM), PhMemoryItemType); + memset(memoryItem, 0, sizeof(PH_MEMORY_ITEM)); + + return memoryItem; +} + +VOID PhpMemoryItemDeleteProcedure( + _In_ PVOID Object, + _In_ ULONG Flags + ) +{ + PPH_MEMORY_ITEM memoryItem = Object; + + switch (memoryItem->RegionType) + { + case CustomRegion: + PhClearReference(&memoryItem->u.Custom.Text); + break; + case MappedFileRegion: + PhClearReference(&memoryItem->u.MappedFile.FileName); + break; + } +} + +static LONG NTAPI PhpMemoryItemCompareFunction( + _In_ PPH_AVL_LINKS Links1, + _In_ PPH_AVL_LINKS Links2 + ) +{ + PPH_MEMORY_ITEM memoryItem1 = CONTAINING_RECORD(Links1, PH_MEMORY_ITEM, Links); + PPH_MEMORY_ITEM memoryItem2 = CONTAINING_RECORD(Links2, PH_MEMORY_ITEM, Links); + + return uintptrcmp((ULONG_PTR)memoryItem1->BaseAddress, (ULONG_PTR)memoryItem2->BaseAddress); +} + +VOID PhDeleteMemoryItemList( + _In_ PPH_MEMORY_ITEM_LIST List + ) +{ + PLIST_ENTRY listEntry; + PPH_MEMORY_ITEM memoryItem; + + listEntry = List->ListHead.Flink; + + while (listEntry != &List->ListHead) + { + memoryItem = CONTAINING_RECORD(listEntry, PH_MEMORY_ITEM, ListEntry); + listEntry = listEntry->Flink; + + PhDereferenceObject(memoryItem); + } +} + +PPH_MEMORY_ITEM PhLookupMemoryItemList( + _In_ PPH_MEMORY_ITEM_LIST List, + _In_ PVOID Address + ) +{ + PH_MEMORY_ITEM lookupMemoryItem; + PPH_AVL_LINKS links; + PPH_MEMORY_ITEM memoryItem; + + // Do an approximate search on the set to locate the memory item with the largest + // base address that is still smaller than the given address. + lookupMemoryItem.BaseAddress = Address; + links = PhUpperDualBoundElementAvlTree(&List->Set, &lookupMemoryItem.Links); + + if (links) + { + memoryItem = CONTAINING_RECORD(links, PH_MEMORY_ITEM, Links); + + if ((ULONG_PTR)Address < (ULONG_PTR)memoryItem->BaseAddress + memoryItem->RegionSize) + return memoryItem; + } + + return NULL; +} + +PPH_MEMORY_ITEM PhpSetMemoryRegionType( + _In_ PPH_MEMORY_ITEM_LIST List, + _In_ PVOID Address, + _In_ BOOLEAN GoToAllocationBase, + _In_ PH_MEMORY_REGION_TYPE RegionType + ) +{ + PPH_MEMORY_ITEM memoryItem; + + memoryItem = PhLookupMemoryItemList(List, Address); + + if (!memoryItem) + return NULL; + + if (GoToAllocationBase && memoryItem->AllocationBaseItem) + memoryItem = memoryItem->AllocationBaseItem; + + if (memoryItem->RegionType != UnknownRegion) + return NULL; + + memoryItem->RegionType = RegionType; + + return memoryItem; +} + +NTSTATUS PhpUpdateMemoryRegionTypes( + _In_ PPH_MEMORY_ITEM_LIST List, + _In_ HANDLE ProcessHandle + ) +{ + NTSTATUS status; + PVOID processes; + PSYSTEM_PROCESS_INFORMATION process; + ULONG i; +#ifdef _WIN64 + BOOLEAN isWow64 = FALSE; +#endif + PPH_MEMORY_ITEM memoryItem; + PLIST_ENTRY listEntry; + + if (!NT_SUCCESS(status = PhEnumProcessesEx(&processes, SystemExtendedProcessInformation))) + return status; + + process = PhFindProcessInformation(processes, List->ProcessId); + + if (!process) + { + PhFree(processes); + return STATUS_NOT_FOUND; + } + + // USER_SHARED_DATA + PhpSetMemoryRegionType(List, USER_SHARED_DATA, TRUE, UserSharedDataRegion); + + // PEB, heap + { + PROCESS_BASIC_INFORMATION basicInfo; + ULONG numberOfHeaps; + PVOID processHeapsPtr; + PVOID *processHeaps; + ULONG i; +#ifdef _WIN64 + PVOID peb32; + ULONG processHeapsPtr32; + ULONG *processHeaps32; +#endif + + if (NT_SUCCESS(PhGetProcessBasicInformation(ProcessHandle, &basicInfo)) && basicInfo.PebBaseAddress != 0) + { + PhpSetMemoryRegionType(List, basicInfo.PebBaseAddress, TRUE, PebRegion); + + if (NT_SUCCESS(NtReadVirtualMemory(ProcessHandle, + PTR_ADD_OFFSET(basicInfo.PebBaseAddress, FIELD_OFFSET(PEB, NumberOfHeaps)), + &numberOfHeaps, sizeof(ULONG), NULL)) && numberOfHeaps < MAX_HEAPS) + { + processHeaps = PhAllocate(numberOfHeaps * sizeof(PVOID)); + + if (NT_SUCCESS(NtReadVirtualMemory(ProcessHandle, + PTR_ADD_OFFSET(basicInfo.PebBaseAddress, FIELD_OFFSET(PEB, ProcessHeaps)), + &processHeapsPtr, sizeof(PVOID), NULL)) && + NT_SUCCESS(NtReadVirtualMemory(ProcessHandle, + processHeapsPtr, + processHeaps, numberOfHeaps * sizeof(PVOID), NULL))) + { + for (i = 0; i < numberOfHeaps; i++) + { + if (memoryItem = PhpSetMemoryRegionType(List, processHeaps[i], TRUE, HeapRegion)) + memoryItem->u.Heap.Index = i; + } + } + + PhFree(processHeaps); + } + } +#ifdef _WIN64 + + if (NT_SUCCESS(PhGetProcessPeb32(ProcessHandle, &peb32)) && peb32 != 0) + { + isWow64 = TRUE; + PhpSetMemoryRegionType(List, peb32, TRUE, Peb32Region); + + if (NT_SUCCESS(NtReadVirtualMemory(ProcessHandle, + PTR_ADD_OFFSET(peb32, FIELD_OFFSET(PEB32, NumberOfHeaps)), + &numberOfHeaps, sizeof(ULONG), NULL)) && numberOfHeaps < MAX_HEAPS) + { + processHeaps32 = PhAllocate(numberOfHeaps * sizeof(ULONG)); + + if (NT_SUCCESS(NtReadVirtualMemory(ProcessHandle, + PTR_ADD_OFFSET(peb32, FIELD_OFFSET(PEB32, ProcessHeaps)), + &processHeapsPtr32, sizeof(ULONG), NULL)) && + NT_SUCCESS(NtReadVirtualMemory(ProcessHandle, + UlongToPtr(processHeapsPtr32), + processHeaps32, numberOfHeaps * sizeof(ULONG), NULL))) + { + for (i = 0; i < numberOfHeaps; i++) + { + if (memoryItem = PhpSetMemoryRegionType(List, UlongToPtr(processHeaps32[i]), TRUE, Heap32Region)) + memoryItem->u.Heap.Index = i; + } + } + + PhFree(processHeaps32); + } + } +#endif + } + + // TEB, stack + for (i = 0; i < process->NumberOfThreads; i++) + { + PSYSTEM_EXTENDED_THREAD_INFORMATION thread = (PSYSTEM_EXTENDED_THREAD_INFORMATION)process->Threads + i; + + if (WindowsVersion < WINDOWS_VISTA) + { + HANDLE threadHandle; + THREAD_BASIC_INFORMATION basicInfo; + + if (NT_SUCCESS(PhOpenThread(&threadHandle, ThreadQueryAccess, thread->ThreadInfo.ClientId.UniqueThread))) + { + if (NT_SUCCESS(PhGetThreadBasicInformation(threadHandle, &basicInfo))) + thread->TebBase = basicInfo.TebBaseAddress; + + NtClose(threadHandle); + } + } + + if (thread->TebBase) + { + NT_TIB ntTib; + SIZE_T bytesRead; + + if (memoryItem = PhpSetMemoryRegionType(List, thread->TebBase, TRUE, TebRegion)) + memoryItem->u.Teb.ThreadId = thread->ThreadInfo.ClientId.UniqueThread; + + if (NT_SUCCESS(NtReadVirtualMemory(ProcessHandle, thread->TebBase, &ntTib, sizeof(NT_TIB), &bytesRead)) && + bytesRead == sizeof(NT_TIB)) + { + if ((ULONG_PTR)ntTib.StackLimit < (ULONG_PTR)ntTib.StackBase) + { + if (memoryItem = PhpSetMemoryRegionType(List, ntTib.StackLimit, TRUE, StackRegion)) + memoryItem->u.Stack.ThreadId = thread->ThreadInfo.ClientId.UniqueThread; + } +#ifdef _WIN64 + + if (isWow64 && ntTib.ExceptionList) + { + ULONG teb32 = PtrToUlong(ntTib.ExceptionList); + NT_TIB32 ntTib32; + + // 64-bit and 32-bit TEBs usually share the same memory region, so don't do anything for the 32-bit + // TEB. + + if (NT_SUCCESS(NtReadVirtualMemory(ProcessHandle, UlongToPtr(teb32), &ntTib32, sizeof(NT_TIB32), &bytesRead)) && + bytesRead == sizeof(NT_TIB32)) + { + if (ntTib32.StackLimit < ntTib32.StackBase) + { + if (memoryItem = PhpSetMemoryRegionType(List, UlongToPtr(ntTib32.StackLimit), TRUE, Stack32Region)) + memoryItem->u.Stack.ThreadId = thread->ThreadInfo.ClientId.UniqueThread; + } + } + } +#endif + } + } + } + + // Mapped file, heap segment, unusable + for (listEntry = List->ListHead.Flink; listEntry != &List->ListHead; listEntry = listEntry->Flink) + { + memoryItem = CONTAINING_RECORD(listEntry, PH_MEMORY_ITEM, ListEntry); + + if (memoryItem->RegionType != UnknownRegion) + continue; + + if ((memoryItem->Type & (MEM_MAPPED | MEM_IMAGE)) && memoryItem->AllocationBaseItem == memoryItem) + { + PPH_STRING fileName; + + if (NT_SUCCESS(PhGetProcessMappedFileName(ProcessHandle, memoryItem->BaseAddress, &fileName))) + { + PPH_STRING newFileName = PhResolveDevicePrefix(fileName); + + if (newFileName) + PhMoveReference(&fileName, newFileName); + + memoryItem->RegionType = MappedFileRegion; + memoryItem->u.MappedFile.FileName = fileName; + continue; + } + } + + if (memoryItem->State & MEM_COMMIT) + { + UCHAR buffer[HEAP_SEGMENT_MAX_SIZE]; + + if (NT_SUCCESS(NtReadVirtualMemory(ProcessHandle, memoryItem->BaseAddress, + buffer, sizeof(buffer), NULL))) + { + PVOID candidateHeap = NULL; + ULONG candidateHeap32 = 0; + PPH_MEMORY_ITEM heapMemoryItem; + + if (WindowsVersion >= WINDOWS_VISTA) + { + PHEAP_SEGMENT heapSegment = (PHEAP_SEGMENT)buffer; + PHEAP_SEGMENT32 heapSegment32 = (PHEAP_SEGMENT32)buffer; + + if (heapSegment->SegmentSignature == HEAP_SEGMENT_SIGNATURE) + candidateHeap = heapSegment->Heap; + if (heapSegment32->SegmentSignature == HEAP_SEGMENT_SIGNATURE) + candidateHeap32 = heapSegment32->Heap; + } + else + { + PHEAP_SEGMENT_OLD heapSegment = (PHEAP_SEGMENT_OLD)buffer; + PHEAP_SEGMENT_OLD32 heapSegment32 = (PHEAP_SEGMENT_OLD32)buffer; + + if (heapSegment->Signature == HEAP_SEGMENT_SIGNATURE) + candidateHeap = heapSegment->Heap; + if (heapSegment32->Signature == HEAP_SEGMENT_SIGNATURE) + candidateHeap32 = heapSegment32->Heap; + } + + if (candidateHeap) + { + heapMemoryItem = PhLookupMemoryItemList(List, candidateHeap); + + if (heapMemoryItem && heapMemoryItem->BaseAddress == candidateHeap && + heapMemoryItem->RegionType == HeapRegion) + { + memoryItem->RegionType = HeapSegmentRegion; + memoryItem->u.HeapSegment.HeapItem = heapMemoryItem; + continue; + } + } + else if (candidateHeap32) + { + heapMemoryItem = PhLookupMemoryItemList(List, UlongToPtr(candidateHeap32)); + + if (heapMemoryItem && heapMemoryItem->BaseAddress == UlongToPtr(candidateHeap32) && + heapMemoryItem->RegionType == Heap32Region) + { + memoryItem->RegionType = HeapSegment32Region; + memoryItem->u.HeapSegment.HeapItem = heapMemoryItem; + continue; + } + } + } + } + } + +#ifdef _WIN64 + // CFG bitmaps for 64-bit processes + if (!isWow64) + { + LDR_INIT_BLOCK ldrInitBlock = { 0 }; + PVOID ldrInitBlockBaseAddress = NULL; + PPH_MEMORY_ITEM cfgBitmapMemoryItem; + PPH_STRING ntdllFileName; + + ntdllFileName = PhConcatStrings2(USER_SHARED_DATA->NtSystemRoot, L"\\System32\\ntdll.dll"); + status = PhGetProcedureAddressRemote( + ProcessHandle, + ntdllFileName->Buffer, + "LdrSystemDllInitBlock", + 0, + &ldrInitBlockBaseAddress, + NULL + ); + + if (NT_SUCCESS(status) && ldrInitBlockBaseAddress) + { + status = NtReadVirtualMemory( + ProcessHandle, + ldrInitBlockBaseAddress, + &ldrInitBlock, + sizeof(LDR_INIT_BLOCK), + NULL + ); + } + + PhDereferenceObject(ntdllFileName); + + if (NT_SUCCESS(status)) + { + PVOID cfgBitmapAddress = NULL; + + // TODO: Remove this code once most users have updated their machines. + if (ldrInitBlock.Size == sizeof(LDR_INIT_BLOCK)) + cfgBitmapAddress = ldrInitBlock.CfgBitmapAddress; // 15063 + else if (ldrInitBlock.Size == 128) + cfgBitmapAddress = ldrInitBlock.Unknown1[11]; // 14393 + + if (cfgBitmapAddress && (cfgBitmapMemoryItem = PhLookupMemoryItemList(List, cfgBitmapAddress))) + { + PLIST_ENTRY listEntry = &cfgBitmapMemoryItem->ListEntry; + PPH_MEMORY_ITEM memoryItem = CONTAINING_RECORD(listEntry, PH_MEMORY_ITEM, ListEntry); + + // Tagging memory items + while (memoryItem->AllocationBaseItem == cfgBitmapMemoryItem) + { + // NB : we could do a finer tagging since each MEM_COMMIT memory + // map is the CFG bitmap of a loaded module. However that would + // imply to heavily rely on reverse-engineer results, and might be + // brittle to changes made by Windows dev teams. + memoryItem->RegionType = CfgBitmapRegion; + + listEntry = listEntry->Flink; + memoryItem = CONTAINING_RECORD(listEntry, PH_MEMORY_ITEM, ListEntry); + } + } + } + } +#endif + + PhFree(processes); + + return STATUS_SUCCESS; +} + +NTSTATUS PhpUpdateMemoryWsCounters( + _In_ PPH_MEMORY_ITEM_LIST List, + _In_ HANDLE ProcessHandle + ) +{ + PLIST_ENTRY listEntry; + PMEMORY_WORKING_SET_EX_INFORMATION info; + + info = PhAllocatePage(WS_REQUEST_COUNT * sizeof(MEMORY_WORKING_SET_EX_INFORMATION), NULL); + + if (!info) + return STATUS_NO_MEMORY; + + for (listEntry = List->ListHead.Flink; listEntry != &List->ListHead; listEntry = listEntry->Flink) + { + PPH_MEMORY_ITEM memoryItem = CONTAINING_RECORD(listEntry, PH_MEMORY_ITEM, ListEntry); + ULONG_PTR virtualAddress; + SIZE_T remainingPages; + SIZE_T requestPages; + SIZE_T i; + + if (!(memoryItem->State & MEM_COMMIT)) + continue; + + virtualAddress = (ULONG_PTR)memoryItem->BaseAddress; + remainingPages = memoryItem->RegionSize / PAGE_SIZE; + + while (remainingPages != 0) + { + requestPages = min(remainingPages, WS_REQUEST_COUNT); + + for (i = 0; i < requestPages; i++) + { + info[i].VirtualAddress = (PVOID)virtualAddress; + virtualAddress += PAGE_SIZE; + } + + if (NT_SUCCESS(NtQueryVirtualMemory( + ProcessHandle, + NULL, + MemoryWorkingSetExInformation, + info, + requestPages * sizeof(MEMORY_WORKING_SET_EX_INFORMATION), + NULL + ))) + { + for (i = 0; i < requestPages; i++) + { + PMEMORY_WORKING_SET_EX_BLOCK block = &info[i].u1.VirtualAttributes; + + if (block->Valid) + { + memoryItem->TotalWorkingSetPages++; + + if (block->ShareCount > 1) + memoryItem->SharedWorkingSetPages++; + if (block->ShareCount == 0) + memoryItem->PrivateWorkingSetPages++; + if (block->Shared) + memoryItem->ShareableWorkingSetPages++; + if (block->Locked) + memoryItem->LockedWorkingSetPages++; + } + } + } + + remainingPages -= requestPages; + } + } + + PhFreePage(info); + + return STATUS_SUCCESS; +} + +NTSTATUS PhpUpdateMemoryWsCountersOld( + _In_ PPH_MEMORY_ITEM_LIST List, + _In_ HANDLE ProcessHandle + ) +{ + NTSTATUS status; + PMEMORY_WORKING_SET_INFORMATION info; + PPH_MEMORY_ITEM memoryItem = NULL; + ULONG_PTR i; + + if (!NT_SUCCESS(status = PhGetProcessWorkingSetInformation(ProcessHandle, &info))) + return status; + + for (i = 0; i < info->NumberOfEntries; i++) + { + PMEMORY_WORKING_SET_BLOCK block = &info->WorkingSetInfo[i]; + ULONG_PTR virtualAddress = block->VirtualPage * PAGE_SIZE; + + if (!memoryItem || virtualAddress < (ULONG_PTR)memoryItem->BaseAddress || + virtualAddress >= (ULONG_PTR)memoryItem->BaseAddress + memoryItem->RegionSize) + { + memoryItem = PhLookupMemoryItemList(List, (PVOID)virtualAddress); + } + + if (memoryItem) + { + memoryItem->TotalWorkingSetPages++; + + if (block->ShareCount > 1) + memoryItem->SharedWorkingSetPages++; + if (block->ShareCount == 0) + memoryItem->PrivateWorkingSetPages++; + if (block->Shared) + memoryItem->ShareableWorkingSetPages++; + } + } + + PhFree(info); + + return STATUS_SUCCESS; +} + +NTSTATUS PhQueryMemoryItemList( + _In_ HANDLE ProcessId, + _In_ ULONG Flags, + _Out_ PPH_MEMORY_ITEM_LIST List + ) +{ + NTSTATUS status; + HANDLE processHandle; + ULONG_PTR allocationGranularity; + PVOID baseAddress = (PVOID)0; + MEMORY_BASIC_INFORMATION basicInfo; + PPH_MEMORY_ITEM allocationBaseItem = NULL; + PPH_MEMORY_ITEM previousMemoryItem = NULL; + + if (!NT_SUCCESS(status = PhOpenProcess( + &processHandle, + PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, + ProcessId + ))) + { + if (!NT_SUCCESS(status = PhOpenProcess( + &processHandle, + PROCESS_QUERY_INFORMATION, + ProcessId + ))) + { + return status; + } + } + + List->ProcessId = ProcessId; + PhInitializeAvlTree(&List->Set, PhpMemoryItemCompareFunction); + InitializeListHead(&List->ListHead); + + allocationGranularity = PhSystemBasicInformation.AllocationGranularity; + + while (NT_SUCCESS(NtQueryVirtualMemory( + processHandle, + baseAddress, + MemoryBasicInformation, + &basicInfo, + sizeof(MEMORY_BASIC_INFORMATION), + NULL + ))) + { + PPH_MEMORY_ITEM memoryItem; + + if (basicInfo.State & MEM_FREE) + { + if (Flags & PH_QUERY_MEMORY_IGNORE_FREE) + goto ContinueLoop; + + basicInfo.AllocationBase = basicInfo.BaseAddress; + } + + memoryItem = PhCreateMemoryItem(); + memoryItem->BasicInfo = basicInfo; + + if (basicInfo.AllocationBase == basicInfo.BaseAddress) + allocationBaseItem = memoryItem; + if (allocationBaseItem && basicInfo.AllocationBase == allocationBaseItem->BaseAddress) + memoryItem->AllocationBaseItem = allocationBaseItem; + + if (basicInfo.State & MEM_COMMIT) + { + memoryItem->CommittedSize = memoryItem->RegionSize; + + if (basicInfo.Type & MEM_PRIVATE) + memoryItem->PrivateSize = memoryItem->RegionSize; + } + + PhAddElementAvlTree(&List->Set, &memoryItem->Links); + InsertTailList(&List->ListHead, &memoryItem->ListEntry); + + if (basicInfo.State & MEM_FREE) + { + if ((ULONG_PTR)basicInfo.BaseAddress & (allocationGranularity - 1)) + { + ULONG_PTR nextAllocationBase; + ULONG_PTR potentialUnusableSize; + + // Split this free region into an unusable and a (possibly empty) usable region. + + nextAllocationBase = ALIGN_UP_BY(basicInfo.BaseAddress, allocationGranularity); + potentialUnusableSize = nextAllocationBase - (ULONG_PTR)basicInfo.BaseAddress; + + memoryItem->RegionType = UnusableRegion; + + // VMMap does this, but is it correct? + //if (previousMemoryItem && (previousMemoryItem->State & MEM_COMMIT)) + // memoryItem->CommittedSize = min(potentialUnusableSize, basicInfo.RegionSize); + + if (nextAllocationBase < (ULONG_PTR)basicInfo.BaseAddress + basicInfo.RegionSize) + { + PPH_MEMORY_ITEM otherMemoryItem; + + memoryItem->RegionSize = potentialUnusableSize; + + otherMemoryItem = PhCreateMemoryItem(); + otherMemoryItem->BasicInfo = basicInfo; + otherMemoryItem->BaseAddress = (PVOID)nextAllocationBase; + otherMemoryItem->AllocationBase = otherMemoryItem->BaseAddress; + otherMemoryItem->RegionSize = basicInfo.RegionSize - potentialUnusableSize; + otherMemoryItem->AllocationBaseItem = otherMemoryItem; + + PhAddElementAvlTree(&List->Set, &otherMemoryItem->Links); + InsertTailList(&List->ListHead, &otherMemoryItem->ListEntry); + + previousMemoryItem = otherMemoryItem; + goto ContinueLoop; + } + } + } + + previousMemoryItem = memoryItem; + +ContinueLoop: + baseAddress = PTR_ADD_OFFSET(baseAddress, basicInfo.RegionSize); + } + + if (Flags & PH_QUERY_MEMORY_REGION_TYPE) + PhpUpdateMemoryRegionTypes(List, processHandle); + + if (Flags & PH_QUERY_MEMORY_WS_COUNTERS) + { + if (WindowsVersion >= WINDOWS_SERVER_2003) + PhpUpdateMemoryWsCounters(List, processHandle); + else + PhpUpdateMemoryWsCountersOld(List, processHandle); + } + + NtClose(processHandle); + + return STATUS_SUCCESS; +} diff --git a/ProcessHacker/memrslt.c b/ProcessHacker/memrslt.c index c9c7bb79a94b..36d36deaf05e 100644 --- a/ProcessHacker/memrslt.c +++ b/ProcessHacker/memrslt.c @@ -1,622 +1,622 @@ -/* - * Process Hacker - - * memory search results - * - * Copyright (C) 2010-2016 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include - -#include - -#include - -#include -#include -#include -#include - -#include "pcre/pcre2.h" - -#define FILTER_CONTAINS 1 -#define FILTER_CONTAINS_IGNORECASE 2 -#define FILTER_REGEX 3 -#define FILTER_REGEX_IGNORECASE 4 - -typedef struct _MEMORY_RESULTS_CONTEXT -{ - HANDLE ProcessId; - PPH_LIST Results; - - PH_LAYOUT_MANAGER LayoutManager; -} MEMORY_RESULTS_CONTEXT, *PMEMORY_RESULTS_CONTEXT; - -INT_PTR CALLBACK PhpMemoryResultsDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -static RECT MinimumSize = { -1, -1, -1, -1 }; - -VOID PhShowMemoryResultsDialog( - _In_ HANDLE ProcessId, - _In_ PPH_LIST Results - ) -{ - HWND windowHandle; - PMEMORY_RESULTS_CONTEXT context; - ULONG i; - - context = PhAllocate(sizeof(MEMORY_RESULTS_CONTEXT)); - context->ProcessId = ProcessId; - context->Results = Results; - - PhReferenceObject(Results); - - for (i = 0; i < Results->Count; i++) - PhReferenceMemoryResult(Results->Items[i]); - - windowHandle = CreateDialogParam( - PhInstanceHandle, - MAKEINTRESOURCE(IDD_MEMRESULTS), - NULL, - PhpMemoryResultsDlgProc, - (LPARAM)context - ); - ShowWindow(windowHandle, SW_SHOW); -} - -static PPH_STRING PhpGetStringForSelectedResults( - _In_ HWND ListViewHandle, - _In_ PPH_LIST Results, - _In_ BOOLEAN All - ) -{ - PH_STRING_BUILDER stringBuilder; - ULONG i; - - PhInitializeStringBuilder(&stringBuilder, 0x100); - - for (i = 0; i < Results->Count; i++) - { - PPH_MEMORY_RESULT result; - - if (!All) - { - if (!(ListView_GetItemState(ListViewHandle, i, LVIS_SELECTED) & LVIS_SELECTED)) - continue; - } - - result = Results->Items[i]; - - PhAppendFormatStringBuilder(&stringBuilder, L"0x%Ix (%u): %s\r\n", result->Address, result->Length, - result->Display.Buffer ? result->Display.Buffer : L""); - } - - return PhFinalStringBuilderString(&stringBuilder); -} - -static VOID FilterResults( - _In_ HWND hwndDlg, - _In_ PMEMORY_RESULTS_CONTEXT Context, - _In_ ULONG Type - ) -{ - PPH_STRING selectedChoice = NULL; - PPH_LIST results; - pcre2_code *compiledExpression; - pcre2_match_data *matchData; - - results = Context->Results; - - SetCursor(LoadCursor(NULL, IDC_WAIT)); - - while (PhaChoiceDialog( - hwndDlg, - L"Filter", - L"Enter the filter pattern:", - NULL, - 0, - NULL, - PH_CHOICE_DIALOG_USER_CHOICE, - &selectedChoice, - NULL, - L"MemFilterChoices" - )) - { - PPH_LIST newResults = NULL; - ULONG i; - - if (Type == FILTER_CONTAINS || Type == FILTER_CONTAINS_IGNORECASE) - { - newResults = PhCreateList(1024); - - if (Type == FILTER_CONTAINS) - { - for (i = 0; i < results->Count; i++) - { - PPH_MEMORY_RESULT result = results->Items[i]; - - if (wcsstr(result->Display.Buffer, selectedChoice->Buffer)) - { - PhReferenceMemoryResult(result); - PhAddItemList(newResults, result); - } - } - } - else - { - PPH_STRING upperChoice; - - upperChoice = PhaUpperString(selectedChoice); - - for (i = 0; i < results->Count; i++) - { - PPH_MEMORY_RESULT result = results->Items[i]; - PWSTR upperDisplay; - - upperDisplay = PhAllocateForMemorySearch(result->Display.Length + sizeof(WCHAR)); - // Copy the null terminator as well. - memcpy(upperDisplay, result->Display.Buffer, result->Display.Length + sizeof(WCHAR)); - - _wcsupr(upperDisplay); - - if (wcsstr(upperDisplay, upperChoice->Buffer)) - { - PhReferenceMemoryResult(result); - PhAddItemList(newResults, result); - } - - PhFreeForMemorySearch(upperDisplay); - } - } - } - else if (Type == FILTER_REGEX || Type == FILTER_REGEX_IGNORECASE) - { - int errorCode; - PCRE2_SIZE errorOffset; - - compiledExpression = pcre2_compile( - selectedChoice->Buffer, - selectedChoice->Length / sizeof(WCHAR), - (Type == FILTER_REGEX_IGNORECASE ? PCRE2_CASELESS : 0) | PCRE2_DOTALL, - &errorCode, - &errorOffset, - NULL - ); - - if (!compiledExpression) - { - PhShowError(hwndDlg, L"Unable to compile the regular expression: \"%s\" at position %zu.", - PhGetStringOrDefault(PH_AUTO(PhPcre2GetErrorMessage(errorCode)), L"Unknown error"), - errorOffset - ); - continue; - } - - matchData = pcre2_match_data_create_from_pattern(compiledExpression, NULL); - - newResults = PhCreateList(1024); - - for (i = 0; i < results->Count; i++) - { - PPH_MEMORY_RESULT result = results->Items[i]; - - if (pcre2_match( - compiledExpression, - result->Display.Buffer, - result->Display.Length / sizeof(WCHAR), - 0, - 0, - matchData, - NULL - ) >= 0) - { - PhReferenceMemoryResult(result); - PhAddItemList(newResults, result); - } - } - - pcre2_match_data_free(matchData); - pcre2_code_free(compiledExpression); - } - - if (newResults) - { - PhShowMemoryResultsDialog(Context->ProcessId, newResults); - PhDereferenceMemoryResults((PPH_MEMORY_RESULT *)newResults->Items, newResults->Count); - PhDereferenceObject(newResults); - break; - } - } - - SetCursor(LoadCursor(NULL, IDC_ARROW)); -} - -INT_PTR CALLBACK PhpMemoryResultsDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - PMEMORY_RESULTS_CONTEXT context; - - if (uMsg != WM_INITDIALOG) - { - context = GetProp(hwndDlg, PhMakeContextAtom()); - } - else - { - context = (PMEMORY_RESULTS_CONTEXT)lParam; - SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)context); - } - - if (!context) - return FALSE; - - switch (uMsg) - { - case WM_INITDIALOG: - { - HWND lvHandle; - - PhRegisterDialog(hwndDlg); - - { - PPH_PROCESS_ITEM processItem; - - if (processItem = PhReferenceProcessItem(context->ProcessId)) - { - SetWindowText(hwndDlg, PhaFormatString(L"Results - %s (%u)", - processItem->ProcessName->Buffer, HandleToUlong(processItem->ProcessId))->Buffer); - PhDereferenceObject(processItem); - } - } - - lvHandle = GetDlgItem(hwndDlg, IDC_LIST); - PhSetListViewStyle(lvHandle, FALSE, TRUE); - PhSetControlTheme(lvHandle, L"explorer"); - PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 120, L"Address"); - PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 80, L"Length"); - PhAddListViewColumn(lvHandle, 2, 2, 2, LVCFMT_LEFT, 200, L"Result"); - - PhLoadListViewColumnsFromSetting(L"MemResultsListViewColumns", lvHandle); - - PhInitializeLayoutManager(&context->LayoutManager, hwndDlg); - PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_LIST), NULL, - PH_ANCHOR_ALL); - PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDOK), NULL, - PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); - PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_COPY), NULL, - PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); - PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_SAVE), NULL, - PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); - PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_FILTER), NULL, - PH_ANCHOR_BOTTOM | PH_ANCHOR_LEFT); - - if (MinimumSize.left == -1) - { - RECT rect; - - rect.left = 0; - rect.top = 0; - rect.right = 250; - rect.bottom = 180; - MapDialogRect(hwndDlg, &rect); - MinimumSize = rect; - MinimumSize.left = 0; - } - - ListView_SetItemCount(lvHandle, context->Results->Count); - - SetDlgItemText(hwndDlg, IDC_INTRO, PhaFormatString(L"%s results.", - PhaFormatUInt64(context->Results->Count, TRUE)->Buffer)->Buffer); - - { - PH_RECTANGLE windowRectangle; - - windowRectangle.Position = PhGetIntegerPairSetting(L"MemResultsPosition"); - windowRectangle.Size = PhGetScalableIntegerPairSetting(L"MemResultsSize", TRUE).Pair; - PhAdjustRectangleToWorkingArea(NULL, &windowRectangle); - - MoveWindow(hwndDlg, windowRectangle.Left, windowRectangle.Top, - windowRectangle.Width, windowRectangle.Height, FALSE); - - // Implement cascading by saving an offsetted rectangle. - windowRectangle.Left += 20; - windowRectangle.Top += 20; - - PhSetIntegerPairSetting(L"MemResultsPosition", windowRectangle.Position); - PhSetScalableIntegerPairSetting2(L"MemResultsSize", windowRectangle.Size); - } - } - break; - case WM_DESTROY: - { - PhSaveWindowPlacementToSetting(L"MemResultsPosition", L"MemResultsSize", hwndDlg); - PhSaveListViewColumnsToSetting(L"MemResultsListViewColumns", GetDlgItem(hwndDlg, IDC_LIST)); - - PhDeleteLayoutManager(&context->LayoutManager); - PhUnregisterDialog(hwndDlg); - RemoveProp(hwndDlg, PhMakeContextAtom()); - - PhDereferenceMemoryResults((PPH_MEMORY_RESULT *)context->Results->Items, context->Results->Count); - PhDereferenceObject(context->Results); - PhFree(context); - } - break; - case WM_COMMAND: - { - switch (LOWORD(wParam)) - { - case IDCANCEL: - case IDOK: - DestroyWindow(hwndDlg); - break; - case IDC_COPY: - { - HWND lvHandle; - PPH_STRING string; - ULONG selectedCount; - - lvHandle = GetDlgItem(hwndDlg, IDC_LIST); - selectedCount = ListView_GetSelectedCount(lvHandle); - - if (selectedCount == 0) - { - // User didn't select anything, so copy all items. - string = PhpGetStringForSelectedResults(lvHandle, context->Results, TRUE); - PhSetStateAllListViewItems(lvHandle, LVIS_SELECTED, LVIS_SELECTED); - } - else - { - string = PhpGetStringForSelectedResults(lvHandle, context->Results, FALSE); - } - - PhSetClipboardString(hwndDlg, &string->sr); - PhDereferenceObject(string); - - SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)lvHandle, TRUE); - } - break; - case IDC_SAVE: - { - static PH_FILETYPE_FILTER filters[] = - { - { L"Text files (*.txt)", L"*.txt" }, - { L"All files (*.*)", L"*.*" } - }; - PVOID fileDialog; - - fileDialog = PhCreateSaveFileDialog(); - - PhSetFileDialogFilter(fileDialog, filters, sizeof(filters) / sizeof(PH_FILETYPE_FILTER)); - PhSetFileDialogFileName(fileDialog, L"Search results.txt"); - - if (PhShowFileDialog(hwndDlg, fileDialog)) - { - NTSTATUS status; - PPH_STRING fileName; - PPH_FILE_STREAM fileStream; - PPH_STRING string; - - fileName = PH_AUTO(PhGetFileDialogFileName(fileDialog)); - - if (NT_SUCCESS(status = PhCreateFileStream( - &fileStream, - fileName->Buffer, - FILE_GENERIC_WRITE, - FILE_SHARE_READ, - FILE_OVERWRITE_IF, - 0 - ))) - { - PhWriteStringAsUtf8FileStream(fileStream, &PhUnicodeByteOrderMark); - PhWritePhTextHeader(fileStream); - - string = PhpGetStringForSelectedResults(GetDlgItem(hwndDlg, IDC_LIST), context->Results, TRUE); - PhWriteStringAsUtf8FileStreamEx(fileStream, string->Buffer, string->Length); - PhDereferenceObject(string); - - PhDereferenceObject(fileStream); - } - - if (!NT_SUCCESS(status)) - PhShowStatus(hwndDlg, L"Unable to create the file", status, 0); - } - - PhFreeFileDialog(fileDialog); - } - break; - case IDC_FILTER: - { - PPH_EMENU menu; - RECT buttonRect; - POINT point; - PPH_EMENU_ITEM selectedItem; - ULONG filterType = 0; - - menu = PhCreateEMenu(); - PhLoadResourceEMenuItem(menu, PhInstanceHandle, MAKEINTRESOURCE(IDR_MEMFILTER), 0); - - GetClientRect(GetDlgItem(hwndDlg, IDC_FILTER), &buttonRect); - point.x = 0; - point.y = buttonRect.bottom; - - ClientToScreen(GetDlgItem(hwndDlg, IDC_FILTER), &point); - selectedItem = PhShowEMenu(menu, hwndDlg, PH_EMENU_SHOW_LEFTRIGHT, - PH_ALIGN_LEFT | PH_ALIGN_TOP, point.x, point.y); - - if (selectedItem) - { - switch (selectedItem->Id) - { - case ID_FILTER_CONTAINS: - filterType = FILTER_CONTAINS; - break; - case ID_FILTER_CONTAINS_CASEINSENSITIVE: - filterType = FILTER_CONTAINS_IGNORECASE; - break; - case ID_FILTER_REGEX: - filterType = FILTER_REGEX; - break; - case ID_FILTER_REGEX_CASEINSENSITIVE: - filterType = FILTER_REGEX_IGNORECASE; - break; - } - } - - if (filterType != 0) - FilterResults(hwndDlg, context, filterType); - - PhDestroyEMenu(menu); - } - break; - } - } - break; - case WM_NOTIFY: - { - LPNMHDR header = (LPNMHDR)lParam; - HWND lvHandle; - - lvHandle = GetDlgItem(hwndDlg, IDC_LIST); - PhHandleListViewNotifyForCopy(lParam, lvHandle); - - switch (header->code) - { - case LVN_GETDISPINFO: - { - NMLVDISPINFO *dispInfo = (NMLVDISPINFO *)header; - - if (dispInfo->item.mask & LVIF_TEXT) - { - PPH_MEMORY_RESULT result = context->Results->Items[dispInfo->item.iItem]; - - switch (dispInfo->item.iSubItem) - { - case 0: - { - WCHAR addressString[PH_PTR_STR_LEN_1]; - - PhPrintPointer(addressString, result->Address); - wcsncpy_s( - dispInfo->item.pszText, - dispInfo->item.cchTextMax, - addressString, - _TRUNCATE - ); - } - break; - case 1: - { - WCHAR lengthString[PH_INT32_STR_LEN_1]; - - PhPrintUInt32(lengthString, (ULONG)result->Length); - wcsncpy_s( - dispInfo->item.pszText, - dispInfo->item.cchTextMax, - lengthString, - _TRUNCATE - ); - } - break; - case 2: - wcsncpy_s( - dispInfo->item.pszText, - dispInfo->item.cchTextMax, - result->Display.Buffer, - _TRUNCATE - ); - break; - } - } - } - break; - case NM_DBLCLK: - { - if (header->hwndFrom == lvHandle) - { - INT index; - - if ((index = ListView_GetNextItem( - lvHandle, - -1, - LVNI_SELECTED - )) != -1) - { - NTSTATUS status; - PPH_MEMORY_RESULT result = context->Results->Items[index]; - HANDLE processHandle; - MEMORY_BASIC_INFORMATION basicInfo; - PPH_SHOW_MEMORY_EDITOR showMemoryEditor; - - if (NT_SUCCESS(status = PhOpenProcess( - &processHandle, - PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, - context->ProcessId - ))) - { - if (NT_SUCCESS(status = NtQueryVirtualMemory( - processHandle, - result->Address, - MemoryBasicInformation, - &basicInfo, - sizeof(MEMORY_BASIC_INFORMATION), - NULL - ))) - { - showMemoryEditor = PhAllocate(sizeof(PH_SHOW_MEMORY_EDITOR)); - memset(showMemoryEditor, 0, sizeof(PH_SHOW_MEMORY_EDITOR)); - showMemoryEditor->ProcessId = context->ProcessId; - showMemoryEditor->BaseAddress = basicInfo.BaseAddress; - showMemoryEditor->RegionSize = basicInfo.RegionSize; - showMemoryEditor->SelectOffset = (ULONG)((ULONG_PTR)result->Address - (ULONG_PTR)basicInfo.BaseAddress); - showMemoryEditor->SelectLength = (ULONG)result->Length; - ProcessHacker_ShowMemoryEditor(PhMainWndHandle, showMemoryEditor); - } - - NtClose(processHandle); - } - - if (!NT_SUCCESS(status)) - PhShowStatus(hwndDlg, L"Unable to edit memory", status, 0); - } - } - } - break; - } - } - break; - case WM_SIZE: - { - PhLayoutManagerLayout(&context->LayoutManager); - } - break; - case WM_SIZING: - { - PhResizingMinimumSize((PRECT)lParam, wParam, MinimumSize.right, MinimumSize.bottom); - } - break; - } - - return FALSE; -} +/* + * Process Hacker - + * memory search results + * + * Copyright (C) 2010-2016 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include + +#include + +#include + +#include +#include +#include +#include + +#include "pcre/pcre2.h" + +#define FILTER_CONTAINS 1 +#define FILTER_CONTAINS_IGNORECASE 2 +#define FILTER_REGEX 3 +#define FILTER_REGEX_IGNORECASE 4 + +typedef struct _MEMORY_RESULTS_CONTEXT +{ + HANDLE ProcessId; + PPH_LIST Results; + + PH_LAYOUT_MANAGER LayoutManager; +} MEMORY_RESULTS_CONTEXT, *PMEMORY_RESULTS_CONTEXT; + +INT_PTR CALLBACK PhpMemoryResultsDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +static RECT MinimumSize = { -1, -1, -1, -1 }; + +VOID PhShowMemoryResultsDialog( + _In_ HANDLE ProcessId, + _In_ PPH_LIST Results + ) +{ + HWND windowHandle; + PMEMORY_RESULTS_CONTEXT context; + ULONG i; + + context = PhAllocate(sizeof(MEMORY_RESULTS_CONTEXT)); + context->ProcessId = ProcessId; + context->Results = Results; + + PhReferenceObject(Results); + + for (i = 0; i < Results->Count; i++) + PhReferenceMemoryResult(Results->Items[i]); + + windowHandle = CreateDialogParam( + PhInstanceHandle, + MAKEINTRESOURCE(IDD_MEMRESULTS), + NULL, + PhpMemoryResultsDlgProc, + (LPARAM)context + ); + ShowWindow(windowHandle, SW_SHOW); +} + +static PPH_STRING PhpGetStringForSelectedResults( + _In_ HWND ListViewHandle, + _In_ PPH_LIST Results, + _In_ BOOLEAN All + ) +{ + PH_STRING_BUILDER stringBuilder; + ULONG i; + + PhInitializeStringBuilder(&stringBuilder, 0x100); + + for (i = 0; i < Results->Count; i++) + { + PPH_MEMORY_RESULT result; + + if (!All) + { + if (!(ListView_GetItemState(ListViewHandle, i, LVIS_SELECTED) & LVIS_SELECTED)) + continue; + } + + result = Results->Items[i]; + + PhAppendFormatStringBuilder(&stringBuilder, L"0x%Ix (%u): %s\r\n", result->Address, result->Length, + result->Display.Buffer ? result->Display.Buffer : L""); + } + + return PhFinalStringBuilderString(&stringBuilder); +} + +static VOID FilterResults( + _In_ HWND hwndDlg, + _In_ PMEMORY_RESULTS_CONTEXT Context, + _In_ ULONG Type + ) +{ + PPH_STRING selectedChoice = NULL; + PPH_LIST results; + pcre2_code *compiledExpression; + pcre2_match_data *matchData; + + results = Context->Results; + + SetCursor(LoadCursor(NULL, IDC_WAIT)); + + while (PhaChoiceDialog( + hwndDlg, + L"Filter", + L"Enter the filter pattern:", + NULL, + 0, + NULL, + PH_CHOICE_DIALOG_USER_CHOICE, + &selectedChoice, + NULL, + L"MemFilterChoices" + )) + { + PPH_LIST newResults = NULL; + ULONG i; + + if (Type == FILTER_CONTAINS || Type == FILTER_CONTAINS_IGNORECASE) + { + newResults = PhCreateList(1024); + + if (Type == FILTER_CONTAINS) + { + for (i = 0; i < results->Count; i++) + { + PPH_MEMORY_RESULT result = results->Items[i]; + + if (wcsstr(result->Display.Buffer, selectedChoice->Buffer)) + { + PhReferenceMemoryResult(result); + PhAddItemList(newResults, result); + } + } + } + else + { + PPH_STRING upperChoice; + + upperChoice = PhaUpperString(selectedChoice); + + for (i = 0; i < results->Count; i++) + { + PPH_MEMORY_RESULT result = results->Items[i]; + PWSTR upperDisplay; + + upperDisplay = PhAllocateForMemorySearch(result->Display.Length + sizeof(WCHAR)); + // Copy the null terminator as well. + memcpy(upperDisplay, result->Display.Buffer, result->Display.Length + sizeof(WCHAR)); + + _wcsupr(upperDisplay); + + if (wcsstr(upperDisplay, upperChoice->Buffer)) + { + PhReferenceMemoryResult(result); + PhAddItemList(newResults, result); + } + + PhFreeForMemorySearch(upperDisplay); + } + } + } + else if (Type == FILTER_REGEX || Type == FILTER_REGEX_IGNORECASE) + { + int errorCode; + PCRE2_SIZE errorOffset; + + compiledExpression = pcre2_compile( + selectedChoice->Buffer, + selectedChoice->Length / sizeof(WCHAR), + (Type == FILTER_REGEX_IGNORECASE ? PCRE2_CASELESS : 0) | PCRE2_DOTALL, + &errorCode, + &errorOffset, + NULL + ); + + if (!compiledExpression) + { + PhShowError(hwndDlg, L"Unable to compile the regular expression: \"%s\" at position %zu.", + PhGetStringOrDefault(PH_AUTO(PhPcre2GetErrorMessage(errorCode)), L"Unknown error"), + errorOffset + ); + continue; + } + + matchData = pcre2_match_data_create_from_pattern(compiledExpression, NULL); + + newResults = PhCreateList(1024); + + for (i = 0; i < results->Count; i++) + { + PPH_MEMORY_RESULT result = results->Items[i]; + + if (pcre2_match( + compiledExpression, + result->Display.Buffer, + result->Display.Length / sizeof(WCHAR), + 0, + 0, + matchData, + NULL + ) >= 0) + { + PhReferenceMemoryResult(result); + PhAddItemList(newResults, result); + } + } + + pcre2_match_data_free(matchData); + pcre2_code_free(compiledExpression); + } + + if (newResults) + { + PhShowMemoryResultsDialog(Context->ProcessId, newResults); + PhDereferenceMemoryResults((PPH_MEMORY_RESULT *)newResults->Items, newResults->Count); + PhDereferenceObject(newResults); + break; + } + } + + SetCursor(LoadCursor(NULL, IDC_ARROW)); +} + +INT_PTR CALLBACK PhpMemoryResultsDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + PMEMORY_RESULTS_CONTEXT context; + + if (uMsg != WM_INITDIALOG) + { + context = GetProp(hwndDlg, PhMakeContextAtom()); + } + else + { + context = (PMEMORY_RESULTS_CONTEXT)lParam; + SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)context); + } + + if (!context) + return FALSE; + + switch (uMsg) + { + case WM_INITDIALOG: + { + HWND lvHandle; + + PhRegisterDialog(hwndDlg); + + { + PPH_PROCESS_ITEM processItem; + + if (processItem = PhReferenceProcessItem(context->ProcessId)) + { + SetWindowText(hwndDlg, PhaFormatString(L"Results - %s (%u)", + processItem->ProcessName->Buffer, HandleToUlong(processItem->ProcessId))->Buffer); + PhDereferenceObject(processItem); + } + } + + lvHandle = GetDlgItem(hwndDlg, IDC_LIST); + PhSetListViewStyle(lvHandle, FALSE, TRUE); + PhSetControlTheme(lvHandle, L"explorer"); + PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 120, L"Address"); + PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 80, L"Length"); + PhAddListViewColumn(lvHandle, 2, 2, 2, LVCFMT_LEFT, 200, L"Result"); + + PhLoadListViewColumnsFromSetting(L"MemResultsListViewColumns", lvHandle); + + PhInitializeLayoutManager(&context->LayoutManager, hwndDlg); + PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_LIST), NULL, + PH_ANCHOR_ALL); + PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDOK), NULL, + PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); + PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_COPY), NULL, + PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); + PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_SAVE), NULL, + PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); + PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_FILTER), NULL, + PH_ANCHOR_BOTTOM | PH_ANCHOR_LEFT); + + if (MinimumSize.left == -1) + { + RECT rect; + + rect.left = 0; + rect.top = 0; + rect.right = 250; + rect.bottom = 180; + MapDialogRect(hwndDlg, &rect); + MinimumSize = rect; + MinimumSize.left = 0; + } + + ListView_SetItemCount(lvHandle, context->Results->Count); + + SetDlgItemText(hwndDlg, IDC_INTRO, PhaFormatString(L"%s results.", + PhaFormatUInt64(context->Results->Count, TRUE)->Buffer)->Buffer); + + { + PH_RECTANGLE windowRectangle; + + windowRectangle.Position = PhGetIntegerPairSetting(L"MemResultsPosition"); + windowRectangle.Size = PhGetScalableIntegerPairSetting(L"MemResultsSize", TRUE).Pair; + PhAdjustRectangleToWorkingArea(NULL, &windowRectangle); + + MoveWindow(hwndDlg, windowRectangle.Left, windowRectangle.Top, + windowRectangle.Width, windowRectangle.Height, FALSE); + + // Implement cascading by saving an offsetted rectangle. + windowRectangle.Left += 20; + windowRectangle.Top += 20; + + PhSetIntegerPairSetting(L"MemResultsPosition", windowRectangle.Position); + PhSetScalableIntegerPairSetting2(L"MemResultsSize", windowRectangle.Size); + } + } + break; + case WM_DESTROY: + { + PhSaveWindowPlacementToSetting(L"MemResultsPosition", L"MemResultsSize", hwndDlg); + PhSaveListViewColumnsToSetting(L"MemResultsListViewColumns", GetDlgItem(hwndDlg, IDC_LIST)); + + PhDeleteLayoutManager(&context->LayoutManager); + PhUnregisterDialog(hwndDlg); + RemoveProp(hwndDlg, PhMakeContextAtom()); + + PhDereferenceMemoryResults((PPH_MEMORY_RESULT *)context->Results->Items, context->Results->Count); + PhDereferenceObject(context->Results); + PhFree(context); + } + break; + case WM_COMMAND: + { + switch (LOWORD(wParam)) + { + case IDCANCEL: + case IDOK: + DestroyWindow(hwndDlg); + break; + case IDC_COPY: + { + HWND lvHandle; + PPH_STRING string; + ULONG selectedCount; + + lvHandle = GetDlgItem(hwndDlg, IDC_LIST); + selectedCount = ListView_GetSelectedCount(lvHandle); + + if (selectedCount == 0) + { + // User didn't select anything, so copy all items. + string = PhpGetStringForSelectedResults(lvHandle, context->Results, TRUE); + PhSetStateAllListViewItems(lvHandle, LVIS_SELECTED, LVIS_SELECTED); + } + else + { + string = PhpGetStringForSelectedResults(lvHandle, context->Results, FALSE); + } + + PhSetClipboardString(hwndDlg, &string->sr); + PhDereferenceObject(string); + + SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)lvHandle, TRUE); + } + break; + case IDC_SAVE: + { + static PH_FILETYPE_FILTER filters[] = + { + { L"Text files (*.txt)", L"*.txt" }, + { L"All files (*.*)", L"*.*" } + }; + PVOID fileDialog; + + fileDialog = PhCreateSaveFileDialog(); + + PhSetFileDialogFilter(fileDialog, filters, sizeof(filters) / sizeof(PH_FILETYPE_FILTER)); + PhSetFileDialogFileName(fileDialog, L"Search results.txt"); + + if (PhShowFileDialog(hwndDlg, fileDialog)) + { + NTSTATUS status; + PPH_STRING fileName; + PPH_FILE_STREAM fileStream; + PPH_STRING string; + + fileName = PH_AUTO(PhGetFileDialogFileName(fileDialog)); + + if (NT_SUCCESS(status = PhCreateFileStream( + &fileStream, + fileName->Buffer, + FILE_GENERIC_WRITE, + FILE_SHARE_READ, + FILE_OVERWRITE_IF, + 0 + ))) + { + PhWriteStringAsUtf8FileStream(fileStream, &PhUnicodeByteOrderMark); + PhWritePhTextHeader(fileStream); + + string = PhpGetStringForSelectedResults(GetDlgItem(hwndDlg, IDC_LIST), context->Results, TRUE); + PhWriteStringAsUtf8FileStreamEx(fileStream, string->Buffer, string->Length); + PhDereferenceObject(string); + + PhDereferenceObject(fileStream); + } + + if (!NT_SUCCESS(status)) + PhShowStatus(hwndDlg, L"Unable to create the file", status, 0); + } + + PhFreeFileDialog(fileDialog); + } + break; + case IDC_FILTER: + { + PPH_EMENU menu; + RECT buttonRect; + POINT point; + PPH_EMENU_ITEM selectedItem; + ULONG filterType = 0; + + menu = PhCreateEMenu(); + PhLoadResourceEMenuItem(menu, PhInstanceHandle, MAKEINTRESOURCE(IDR_MEMFILTER), 0); + + GetClientRect(GetDlgItem(hwndDlg, IDC_FILTER), &buttonRect); + point.x = 0; + point.y = buttonRect.bottom; + + ClientToScreen(GetDlgItem(hwndDlg, IDC_FILTER), &point); + selectedItem = PhShowEMenu(menu, hwndDlg, PH_EMENU_SHOW_LEFTRIGHT, + PH_ALIGN_LEFT | PH_ALIGN_TOP, point.x, point.y); + + if (selectedItem) + { + switch (selectedItem->Id) + { + case ID_FILTER_CONTAINS: + filterType = FILTER_CONTAINS; + break; + case ID_FILTER_CONTAINS_CASEINSENSITIVE: + filterType = FILTER_CONTAINS_IGNORECASE; + break; + case ID_FILTER_REGEX: + filterType = FILTER_REGEX; + break; + case ID_FILTER_REGEX_CASEINSENSITIVE: + filterType = FILTER_REGEX_IGNORECASE; + break; + } + } + + if (filterType != 0) + FilterResults(hwndDlg, context, filterType); + + PhDestroyEMenu(menu); + } + break; + } + } + break; + case WM_NOTIFY: + { + LPNMHDR header = (LPNMHDR)lParam; + HWND lvHandle; + + lvHandle = GetDlgItem(hwndDlg, IDC_LIST); + PhHandleListViewNotifyForCopy(lParam, lvHandle); + + switch (header->code) + { + case LVN_GETDISPINFO: + { + NMLVDISPINFO *dispInfo = (NMLVDISPINFO *)header; + + if (dispInfo->item.mask & LVIF_TEXT) + { + PPH_MEMORY_RESULT result = context->Results->Items[dispInfo->item.iItem]; + + switch (dispInfo->item.iSubItem) + { + case 0: + { + WCHAR addressString[PH_PTR_STR_LEN_1]; + + PhPrintPointer(addressString, result->Address); + wcsncpy_s( + dispInfo->item.pszText, + dispInfo->item.cchTextMax, + addressString, + _TRUNCATE + ); + } + break; + case 1: + { + WCHAR lengthString[PH_INT32_STR_LEN_1]; + + PhPrintUInt32(lengthString, (ULONG)result->Length); + wcsncpy_s( + dispInfo->item.pszText, + dispInfo->item.cchTextMax, + lengthString, + _TRUNCATE + ); + } + break; + case 2: + wcsncpy_s( + dispInfo->item.pszText, + dispInfo->item.cchTextMax, + result->Display.Buffer, + _TRUNCATE + ); + break; + } + } + } + break; + case NM_DBLCLK: + { + if (header->hwndFrom == lvHandle) + { + INT index; + + if ((index = ListView_GetNextItem( + lvHandle, + -1, + LVNI_SELECTED + )) != -1) + { + NTSTATUS status; + PPH_MEMORY_RESULT result = context->Results->Items[index]; + HANDLE processHandle; + MEMORY_BASIC_INFORMATION basicInfo; + PPH_SHOW_MEMORY_EDITOR showMemoryEditor; + + if (NT_SUCCESS(status = PhOpenProcess( + &processHandle, + PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, + context->ProcessId + ))) + { + if (NT_SUCCESS(status = NtQueryVirtualMemory( + processHandle, + result->Address, + MemoryBasicInformation, + &basicInfo, + sizeof(MEMORY_BASIC_INFORMATION), + NULL + ))) + { + showMemoryEditor = PhAllocate(sizeof(PH_SHOW_MEMORY_EDITOR)); + memset(showMemoryEditor, 0, sizeof(PH_SHOW_MEMORY_EDITOR)); + showMemoryEditor->ProcessId = context->ProcessId; + showMemoryEditor->BaseAddress = basicInfo.BaseAddress; + showMemoryEditor->RegionSize = basicInfo.RegionSize; + showMemoryEditor->SelectOffset = (ULONG)((ULONG_PTR)result->Address - (ULONG_PTR)basicInfo.BaseAddress); + showMemoryEditor->SelectLength = (ULONG)result->Length; + ProcessHacker_ShowMemoryEditor(PhMainWndHandle, showMemoryEditor); + } + + NtClose(processHandle); + } + + if (!NT_SUCCESS(status)) + PhShowStatus(hwndDlg, L"Unable to edit memory", status, 0); + } + } + } + break; + } + } + break; + case WM_SIZE: + { + PhLayoutManagerLayout(&context->LayoutManager); + } + break; + case WM_SIZING: + { + PhResizingMinimumSize((PRECT)lParam, wParam, MinimumSize.right, MinimumSize.bottom); + } + break; + } + + return FALSE; +} diff --git a/ProcessHacker/memsrch.c b/ProcessHacker/memsrch.c index a417630d5686..41c2b0c8876e 100644 --- a/ProcessHacker/memsrch.c +++ b/ProcessHacker/memsrch.c @@ -1,731 +1,731 @@ -/* - * Process Hacker - - * memory searchers - * - * Copyright (C) 2010 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include - -#include - -#include -#include -#include - -#define WM_PH_MEMORY_STATUS_UPDATE (WM_APP + 301) - -#define PH_SEARCH_UPDATE 1 -#define PH_SEARCH_COMPLETED 2 - -typedef struct _MEMORY_STRING_CONTEXT -{ - HANDLE ProcessId; - HANDLE ProcessHandle; - ULONG MinimumLength; - BOOLEAN DetectUnicode; - BOOLEAN Private; - BOOLEAN Image; - BOOLEAN Mapped; - - HWND WindowHandle; - HANDLE ThreadHandle; - PH_MEMORY_STRING_OPTIONS Options; - PPH_LIST Results; -} MEMORY_STRING_CONTEXT, *PMEMORY_STRING_CONTEXT; - -INT_PTR CALLBACK PhpMemoryStringDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -INT_PTR CALLBACK PhpMemoryStringProgressDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -PVOID PhMemorySearchHeap = NULL; -LONG PhMemorySearchHeapRefCount = 0; -PH_QUEUED_LOCK PhMemorySearchHeapLock = PH_QUEUED_LOCK_INIT; - -PVOID PhAllocateForMemorySearch( - _In_ SIZE_T Size - ) -{ - PVOID memory; - - PhAcquireQueuedLockExclusive(&PhMemorySearchHeapLock); - - if (!PhMemorySearchHeap) - { - assert(PhMemorySearchHeapRefCount == 0); - PhMemorySearchHeap = RtlCreateHeap( - HEAP_GROWABLE | HEAP_CLASS_1, - NULL, - 8192 * 1024, // 8 MB - 2048 * 1024, // 2 MB - NULL, - NULL - ); - } - - if (PhMemorySearchHeap) - { - // Don't use HEAP_NO_SERIALIZE - it's very slow on Vista and above. - memory = RtlAllocateHeap(PhMemorySearchHeap, 0, Size); - - if (memory) - PhMemorySearchHeapRefCount++; - } - else - { - memory = NULL; - } - - PhReleaseQueuedLockExclusive(&PhMemorySearchHeapLock); - - return memory; -} - -VOID PhFreeForMemorySearch( - _In_ _Post_invalid_ PVOID Memory - ) -{ - PhAcquireQueuedLockExclusive(&PhMemorySearchHeapLock); - - RtlFreeHeap(PhMemorySearchHeap, 0, Memory); - - if (--PhMemorySearchHeapRefCount == 0) - { - RtlDestroyHeap(PhMemorySearchHeap); - PhMemorySearchHeap = NULL; - } - - PhReleaseQueuedLockExclusive(&PhMemorySearchHeapLock); -} - -PVOID PhCreateMemoryResult( - _In_ PVOID Address, - _In_ SIZE_T Length - ) -{ - PPH_MEMORY_RESULT result; - - result = PhAllocateForMemorySearch(sizeof(PH_MEMORY_RESULT)); - - if (!result) - return NULL; - - result->RefCount = 1; - result->Address = Address; - result->Length = Length; - result->Display.Length = 0; - result->Display.Buffer = NULL; - - return result; -} - -VOID PhReferenceMemoryResult( - _In_ PPH_MEMORY_RESULT Result - ) -{ - _InterlockedIncrement(&Result->RefCount); -} - -VOID PhDereferenceMemoryResult( - _In_ PPH_MEMORY_RESULT Result - ) -{ - if (_InterlockedDecrement(&Result->RefCount) == 0) - { - if (Result->Display.Buffer) - PhFreeForMemorySearch(Result->Display.Buffer); - - PhFreeForMemorySearch(Result); - } -} - -VOID PhDereferenceMemoryResults( - _In_reads_(NumberOfResults) PPH_MEMORY_RESULT *Results, - _In_ ULONG NumberOfResults - ) -{ - ULONG i; - - for (i = 0; i < NumberOfResults; i++) - PhDereferenceMemoryResult(Results[i]); -} - -VOID PhSearchMemoryString( - _In_ HANDLE ProcessHandle, - _In_ PPH_MEMORY_STRING_OPTIONS Options - ) -{ - ULONG minimumLength; - BOOLEAN detectUnicode; - ULONG memoryTypeMask; - PVOID baseAddress; - MEMORY_BASIC_INFORMATION basicInfo; - PUCHAR buffer; - SIZE_T bufferSize; - PWSTR displayBuffer; - SIZE_T displayBufferCount; - - minimumLength = Options->MinimumLength; - detectUnicode = Options->DetectUnicode; - memoryTypeMask = Options->MemoryTypeMask; - - if (minimumLength < 4) - return; - - baseAddress = (PVOID)0; - - bufferSize = PAGE_SIZE * 64; - buffer = PhAllocatePage(bufferSize, NULL); - - if (!buffer) - return; - - displayBufferCount = PH_DISPLAY_BUFFER_COUNT; - displayBuffer = PhAllocatePage((displayBufferCount + 1) * sizeof(WCHAR), NULL); - - if (!displayBuffer) - { - PhFreePage(buffer); - return; - } - - while (NT_SUCCESS(NtQueryVirtualMemory( - ProcessHandle, - baseAddress, - MemoryBasicInformation, - &basicInfo, - sizeof(MEMORY_BASIC_INFORMATION), - NULL - ))) - { - ULONG_PTR offset; - SIZE_T readSize; - - if (Options->Header.Cancel) - break; - if (basicInfo.State != MEM_COMMIT) - goto ContinueLoop; - if ((basicInfo.Type & memoryTypeMask) == 0) - goto ContinueLoop; - if (basicInfo.Protect == PAGE_NOACCESS) - goto ContinueLoop; - if (basicInfo.Protect & PAGE_GUARD) - goto ContinueLoop; - - readSize = basicInfo.RegionSize; - - if (basicInfo.RegionSize > bufferSize) - { - // Don't allocate a huge buffer though. - if (basicInfo.RegionSize <= 16 * 1024 * 1024) // 16 MB - { - PhFreePage(buffer); - bufferSize = basicInfo.RegionSize; - buffer = PhAllocatePage(bufferSize, NULL); - - if (!buffer) - break; - } - else - { - readSize = bufferSize; - } - } - - for (offset = 0; offset < basicInfo.RegionSize; offset += readSize) - { - ULONG_PTR i; - UCHAR byte; // current byte - UCHAR byte1; // previous byte - UCHAR byte2; // byte before previous byte - BOOLEAN printable; - BOOLEAN printable1; - BOOLEAN printable2; - ULONG length; - - if (!NT_SUCCESS(NtReadVirtualMemory( - ProcessHandle, - PTR_ADD_OFFSET(baseAddress, offset), - buffer, - readSize, - NULL - ))) - continue; - - byte1 = 0; - byte2 = 0; - printable1 = FALSE; - printable2 = FALSE; - length = 0; - - for (i = 0; i < readSize; i++) - { - byte = buffer[i]; - printable = PhCharIsPrintable[byte]; - - // To find strings Process Hacker uses a state table. - // * byte2 - byte before previous byte - // * byte1 - previous byte - // * byte - current byte - // * length - length of current string run - // - // The states are described below. - // - // [byte2] [byte1] [byte] ... - // [char] means printable, [oth] means non-printable. - // - // 1. [char] [char] [char] ... - // (we're in a non-wide sequence) - // -> append char. - // 2. [char] [char] [oth] ... - // (we reached the end of a non-wide sequence, or we need to start a wide sequence) - // -> if current string is big enough, create result (non-wide). - // otherwise if byte = null, reset to new string with byte1 as first character. - // otherwise if byte != null, reset to new string. - // 3. [char] [oth] [char] ... - // (we're in a wide sequence) - // -> (byte1 should = null) append char. - // 4. [char] [oth] [oth] ... - // (we reached the end of a wide sequence) - // -> (byte1 should = null) if the current string is big enough, create result (wide). - // otherwise, reset to new string. - // 5. [oth] [char] [char] ... - // (we reached the end of a wide sequence, or we need to start a non-wide sequence) - // -> (excluding byte1) if the current string is big enough, create result (wide). - // otherwise, reset to new string with byte1 as first character and byte as - // second character. - // 6. [oth] [char] [oth] ... - // (we're in a wide sequence) - // -> (byte2 and byte should = null) do nothing. - // 7. [oth] [oth] [char] ... - // (we're starting a sequence, but we don't know if it's a wide or non-wide sequence) - // -> append char. - // 8. [oth] [oth] [oth] ... - // (nothing) - // -> do nothing. - - if (printable2 && printable1 && printable) - { - if (length < displayBufferCount) - displayBuffer[length] = byte; - - length++; - } - else if (printable2 && printable1 && !printable) - { - if (length >= minimumLength) - { - goto CreateResult; - } - else if (byte == 0) - { - length = 1; - displayBuffer[0] = byte1; - } - else - { - length = 0; - } - } - else if (printable2 && !printable1 && printable) - { - if (byte1 == 0) - { - if (length < displayBufferCount) - displayBuffer[length] = byte; - - length++; - } - } - else if (printable2 && !printable1 && !printable) - { - if (length >= minimumLength) - { - goto CreateResult; - } - else - { - length = 0; - } - } - else if (!printable2 && printable1 && printable) - { - if (length >= minimumLength + 1) // length - 1 >= minimumLength but avoiding underflow - { - length--; // exclude byte1 - goto CreateResult; - } - else - { - length = 2; - displayBuffer[0] = byte1; - displayBuffer[1] = byte; - } - } - else if (!printable2 && printable1 && !printable) - { - // Nothing - } - else if (!printable2 && !printable1 && printable) - { - if (length < displayBufferCount) - displayBuffer[length] = byte; - - length++; - } - else if (!printable2 && !printable1 && !printable) - { - // Nothing - } - - goto AfterCreateResult; - -CreateResult: - { - PPH_MEMORY_RESULT result; - ULONG lengthInBytes; - ULONG bias; - BOOLEAN isWide; - ULONG displayLength; - - lengthInBytes = length; - bias = 0; - isWide = FALSE; - - if (printable1 == printable) // determine if string was wide (refer to state table, 4 and 5) - { - isWide = TRUE; - lengthInBytes *= 2; - } - - if (printable) // byte1 excluded (refer to state table, 5) - { - bias = 1; - } - - if (!(isWide && !detectUnicode) && (result = PhCreateMemoryResult( - PTR_ADD_OFFSET(baseAddress, i - bias - lengthInBytes), - lengthInBytes - ))) - { - displayLength = (ULONG)(min(length, displayBufferCount) * sizeof(WCHAR)); - - if (result->Display.Buffer = PhAllocateForMemorySearch(displayLength + sizeof(WCHAR))) - { - memcpy(result->Display.Buffer, displayBuffer, displayLength); - result->Display.Buffer[displayLength / sizeof(WCHAR)] = 0; - result->Display.Length = displayLength; - } - - Options->Header.Callback( - result, - Options->Header.Context - ); - } - - length = 0; - } -AfterCreateResult: - - byte2 = byte1; - byte1 = byte; - printable2 = printable1; - printable1 = printable; - } - } - -ContinueLoop: - baseAddress = PTR_ADD_OFFSET(baseAddress, basicInfo.RegionSize); - } - - if (buffer) - PhFreePage(buffer); -} - -VOID PhShowMemoryStringDialog( - _In_ HWND ParentWindowHandle, - _In_ PPH_PROCESS_ITEM ProcessItem - ) -{ - NTSTATUS status; - HANDLE processHandle; - MEMORY_STRING_CONTEXT context; - PPH_SHOW_MEMORY_RESULTS showMemoryResults; - - if (!NT_SUCCESS(status = PhOpenProcess( - &processHandle, - PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, - ProcessItem->ProcessId - ))) - { - PhShowStatus(ParentWindowHandle, L"Unable to open the process", status, 0); - return; - } - - memset(&context, 0, sizeof(MEMORY_STRING_CONTEXT)); - context.ProcessId = ProcessItem->ProcessId; - context.ProcessHandle = processHandle; - - if (DialogBoxParam( - PhInstanceHandle, - MAKEINTRESOURCE(IDD_MEMSTRING), - ParentWindowHandle, - PhpMemoryStringDlgProc, - (LPARAM)&context - ) != IDOK) - { - NtClose(processHandle); - return; - } - - context.Results = PhCreateList(1024); - - if (DialogBoxParam( - PhInstanceHandle, - MAKEINTRESOURCE(IDD_PROGRESS), - ParentWindowHandle, - PhpMemoryStringProgressDlgProc, - (LPARAM)&context - ) == IDOK) - { - showMemoryResults = PhAllocate(sizeof(PH_SHOW_MEMORY_RESULTS)); - showMemoryResults->ProcessId = ProcessItem->ProcessId; - showMemoryResults->Results = context.Results; - - PhReferenceObject(context.Results); - ProcessHacker_ShowMemoryResults( - PhMainWndHandle, - showMemoryResults - ); - } - - PhDereferenceObject(context.Results); - NtClose(processHandle); -} - -INT_PTR CALLBACK PhpMemoryStringDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - switch (uMsg) - { - case WM_INITDIALOG: - { - PhCenterWindow(hwndDlg, GetParent(hwndDlg)); - SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)lParam); - - SetDlgItemText(hwndDlg, IDC_MINIMUMLENGTH, L"10"); - Button_SetCheck(GetDlgItem(hwndDlg, IDC_DETECTUNICODE), BST_CHECKED); - Button_SetCheck(GetDlgItem(hwndDlg, IDC_PRIVATE), BST_CHECKED); - } - break; - case WM_DESTROY: - { - RemoveProp(hwndDlg, PhMakeContextAtom()); - } - break; - case WM_COMMAND: - { - switch (LOWORD(wParam)) - { - case IDCANCEL: - EndDialog(hwndDlg, IDCANCEL); - break; - case IDOK: - { - PMEMORY_STRING_CONTEXT context = (PMEMORY_STRING_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom()); - ULONG64 minimumLength = 10; - - PhStringToInteger64(&PhaGetDlgItemText(hwndDlg, IDC_MINIMUMLENGTH)->sr, 0, &minimumLength); - - if (minimumLength < 4) - { - PhShowError(hwndDlg, L"The minimum length must be at least 4."); - break; - } - - context->MinimumLength = (ULONG)minimumLength; - context->DetectUnicode = Button_GetCheck(GetDlgItem(hwndDlg, IDC_DETECTUNICODE)) == BST_CHECKED; - context->Private = Button_GetCheck(GetDlgItem(hwndDlg, IDC_PRIVATE)) == BST_CHECKED; - context->Image = Button_GetCheck(GetDlgItem(hwndDlg, IDC_IMAGE)) == BST_CHECKED; - context->Mapped = Button_GetCheck(GetDlgItem(hwndDlg, IDC_MAPPED)) == BST_CHECKED; - - EndDialog(hwndDlg, IDOK); - } - break; - } - } - break; - } - - return FALSE; -} - -static BOOL NTAPI PhpMemoryStringResultCallback( - _In_ _Assume_refs_(1) PPH_MEMORY_RESULT Result, - _In_opt_ PVOID Context - ) -{ - PMEMORY_STRING_CONTEXT context = Context; - - PhAddItemList(context->Results, Result); - - return TRUE; -} - -NTSTATUS PhpMemoryStringThreadStart( - _In_ PVOID Parameter - ) -{ - PMEMORY_STRING_CONTEXT context = Parameter; - - context->Options.Header.Callback = PhpMemoryStringResultCallback; - context->Options.Header.Context = context; - context->Options.MinimumLength = context->MinimumLength; - context->Options.DetectUnicode = context->DetectUnicode; - - if (context->Private) - context->Options.MemoryTypeMask |= MEM_PRIVATE; - if (context->Image) - context->Options.MemoryTypeMask |= MEM_IMAGE; - if (context->Mapped) - context->Options.MemoryTypeMask |= MEM_MAPPED; - - PhSearchMemoryString(context->ProcessHandle, &context->Options); - - SendMessage( - context->WindowHandle, - WM_PH_MEMORY_STATUS_UPDATE, - PH_SEARCH_COMPLETED, - 0 - ); - - return STATUS_SUCCESS; -} - -INT_PTR CALLBACK PhpMemoryStringProgressDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - switch (uMsg) - { - case WM_INITDIALOG: - { - PMEMORY_STRING_CONTEXT context = (PMEMORY_STRING_CONTEXT)lParam; - - PhCenterWindow(hwndDlg, GetParent(hwndDlg)); - SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)context); - - SetDlgItemText(hwndDlg, IDC_PROGRESSTEXT, L"Searching..."); - - PhSetWindowStyle(GetDlgItem(hwndDlg, IDC_PROGRESS), PBS_MARQUEE, PBS_MARQUEE); - SendMessage(GetDlgItem(hwndDlg, IDC_PROGRESS), PBM_SETMARQUEE, TRUE, 75); - - context->WindowHandle = hwndDlg; - context->ThreadHandle = PhCreateThread(0, PhpMemoryStringThreadStart, context); - - if (!context->ThreadHandle) - { - PhShowStatus(hwndDlg, L"Unable to create the search thread", 0, GetLastError()); - EndDialog(hwndDlg, IDCANCEL); - return FALSE; - } - - SetTimer(hwndDlg, 1, 500, NULL); - } - break; - case WM_DESTROY: - { - PMEMORY_STRING_CONTEXT context; - - context = (PMEMORY_STRING_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom()); - - if (context->ThreadHandle) - NtClose(context->ThreadHandle); - - RemoveProp(hwndDlg, PhMakeContextAtom()); - } - break; - case WM_COMMAND: - { - switch (LOWORD(wParam)) - { - case IDCANCEL: - { - PMEMORY_STRING_CONTEXT context = - (PMEMORY_STRING_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom()); - - EnableWindow(GetDlgItem(hwndDlg, IDCANCEL), FALSE); - context->Options.Header.Cancel = TRUE; - } - break; - } - } - break; - case WM_TIMER: - { - if (wParam == 1) - { - PMEMORY_STRING_CONTEXT context = - (PMEMORY_STRING_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom()); - PPH_STRING progressText; - PPH_STRING numberText; - - numberText = PhFormatUInt64(context->Results->Count, TRUE); - progressText = PhFormatString(L"%s strings found...", numberText->Buffer); - PhDereferenceObject(numberText); - SetDlgItemText(hwndDlg, IDC_PROGRESSTEXT, progressText->Buffer); - PhDereferenceObject(progressText); - InvalidateRect(GetDlgItem(hwndDlg, IDC_PROGRESSTEXT), NULL, FALSE); - } - } - break; - case WM_PH_MEMORY_STATUS_UPDATE: - { - PMEMORY_STRING_CONTEXT context; - - context = (PMEMORY_STRING_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom()); - - switch (wParam) - { - case PH_SEARCH_COMPLETED: - EndDialog(hwndDlg, IDOK); - break; - } - } - break; - } - - return FALSE; -} +/* + * Process Hacker - + * memory searchers + * + * Copyright (C) 2010 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include + +#include + +#include +#include +#include + +#define WM_PH_MEMORY_STATUS_UPDATE (WM_APP + 301) + +#define PH_SEARCH_UPDATE 1 +#define PH_SEARCH_COMPLETED 2 + +typedef struct _MEMORY_STRING_CONTEXT +{ + HANDLE ProcessId; + HANDLE ProcessHandle; + ULONG MinimumLength; + BOOLEAN DetectUnicode; + BOOLEAN Private; + BOOLEAN Image; + BOOLEAN Mapped; + + HWND WindowHandle; + HANDLE ThreadHandle; + PH_MEMORY_STRING_OPTIONS Options; + PPH_LIST Results; +} MEMORY_STRING_CONTEXT, *PMEMORY_STRING_CONTEXT; + +INT_PTR CALLBACK PhpMemoryStringDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +INT_PTR CALLBACK PhpMemoryStringProgressDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +PVOID PhMemorySearchHeap = NULL; +LONG PhMemorySearchHeapRefCount = 0; +PH_QUEUED_LOCK PhMemorySearchHeapLock = PH_QUEUED_LOCK_INIT; + +PVOID PhAllocateForMemorySearch( + _In_ SIZE_T Size + ) +{ + PVOID memory; + + PhAcquireQueuedLockExclusive(&PhMemorySearchHeapLock); + + if (!PhMemorySearchHeap) + { + assert(PhMemorySearchHeapRefCount == 0); + PhMemorySearchHeap = RtlCreateHeap( + HEAP_GROWABLE | HEAP_CLASS_1, + NULL, + 8192 * 1024, // 8 MB + 2048 * 1024, // 2 MB + NULL, + NULL + ); + } + + if (PhMemorySearchHeap) + { + // Don't use HEAP_NO_SERIALIZE - it's very slow on Vista and above. + memory = RtlAllocateHeap(PhMemorySearchHeap, 0, Size); + + if (memory) + PhMemorySearchHeapRefCount++; + } + else + { + memory = NULL; + } + + PhReleaseQueuedLockExclusive(&PhMemorySearchHeapLock); + + return memory; +} + +VOID PhFreeForMemorySearch( + _In_ _Post_invalid_ PVOID Memory + ) +{ + PhAcquireQueuedLockExclusive(&PhMemorySearchHeapLock); + + RtlFreeHeap(PhMemorySearchHeap, 0, Memory); + + if (--PhMemorySearchHeapRefCount == 0) + { + RtlDestroyHeap(PhMemorySearchHeap); + PhMemorySearchHeap = NULL; + } + + PhReleaseQueuedLockExclusive(&PhMemorySearchHeapLock); +} + +PVOID PhCreateMemoryResult( + _In_ PVOID Address, + _In_ SIZE_T Length + ) +{ + PPH_MEMORY_RESULT result; + + result = PhAllocateForMemorySearch(sizeof(PH_MEMORY_RESULT)); + + if (!result) + return NULL; + + result->RefCount = 1; + result->Address = Address; + result->Length = Length; + result->Display.Length = 0; + result->Display.Buffer = NULL; + + return result; +} + +VOID PhReferenceMemoryResult( + _In_ PPH_MEMORY_RESULT Result + ) +{ + _InterlockedIncrement(&Result->RefCount); +} + +VOID PhDereferenceMemoryResult( + _In_ PPH_MEMORY_RESULT Result + ) +{ + if (_InterlockedDecrement(&Result->RefCount) == 0) + { + if (Result->Display.Buffer) + PhFreeForMemorySearch(Result->Display.Buffer); + + PhFreeForMemorySearch(Result); + } +} + +VOID PhDereferenceMemoryResults( + _In_reads_(NumberOfResults) PPH_MEMORY_RESULT *Results, + _In_ ULONG NumberOfResults + ) +{ + ULONG i; + + for (i = 0; i < NumberOfResults; i++) + PhDereferenceMemoryResult(Results[i]); +} + +VOID PhSearchMemoryString( + _In_ HANDLE ProcessHandle, + _In_ PPH_MEMORY_STRING_OPTIONS Options + ) +{ + ULONG minimumLength; + BOOLEAN detectUnicode; + ULONG memoryTypeMask; + PVOID baseAddress; + MEMORY_BASIC_INFORMATION basicInfo; + PUCHAR buffer; + SIZE_T bufferSize; + PWSTR displayBuffer; + SIZE_T displayBufferCount; + + minimumLength = Options->MinimumLength; + detectUnicode = Options->DetectUnicode; + memoryTypeMask = Options->MemoryTypeMask; + + if (minimumLength < 4) + return; + + baseAddress = (PVOID)0; + + bufferSize = PAGE_SIZE * 64; + buffer = PhAllocatePage(bufferSize, NULL); + + if (!buffer) + return; + + displayBufferCount = PH_DISPLAY_BUFFER_COUNT; + displayBuffer = PhAllocatePage((displayBufferCount + 1) * sizeof(WCHAR), NULL); + + if (!displayBuffer) + { + PhFreePage(buffer); + return; + } + + while (NT_SUCCESS(NtQueryVirtualMemory( + ProcessHandle, + baseAddress, + MemoryBasicInformation, + &basicInfo, + sizeof(MEMORY_BASIC_INFORMATION), + NULL + ))) + { + ULONG_PTR offset; + SIZE_T readSize; + + if (Options->Header.Cancel) + break; + if (basicInfo.State != MEM_COMMIT) + goto ContinueLoop; + if ((basicInfo.Type & memoryTypeMask) == 0) + goto ContinueLoop; + if (basicInfo.Protect == PAGE_NOACCESS) + goto ContinueLoop; + if (basicInfo.Protect & PAGE_GUARD) + goto ContinueLoop; + + readSize = basicInfo.RegionSize; + + if (basicInfo.RegionSize > bufferSize) + { + // Don't allocate a huge buffer though. + if (basicInfo.RegionSize <= 16 * 1024 * 1024) // 16 MB + { + PhFreePage(buffer); + bufferSize = basicInfo.RegionSize; + buffer = PhAllocatePage(bufferSize, NULL); + + if (!buffer) + break; + } + else + { + readSize = bufferSize; + } + } + + for (offset = 0; offset < basicInfo.RegionSize; offset += readSize) + { + ULONG_PTR i; + UCHAR byte; // current byte + UCHAR byte1; // previous byte + UCHAR byte2; // byte before previous byte + BOOLEAN printable; + BOOLEAN printable1; + BOOLEAN printable2; + ULONG length; + + if (!NT_SUCCESS(NtReadVirtualMemory( + ProcessHandle, + PTR_ADD_OFFSET(baseAddress, offset), + buffer, + readSize, + NULL + ))) + continue; + + byte1 = 0; + byte2 = 0; + printable1 = FALSE; + printable2 = FALSE; + length = 0; + + for (i = 0; i < readSize; i++) + { + byte = buffer[i]; + printable = PhCharIsPrintable[byte]; + + // To find strings Process Hacker uses a state table. + // * byte2 - byte before previous byte + // * byte1 - previous byte + // * byte - current byte + // * length - length of current string run + // + // The states are described below. + // + // [byte2] [byte1] [byte] ... + // [char] means printable, [oth] means non-printable. + // + // 1. [char] [char] [char] ... + // (we're in a non-wide sequence) + // -> append char. + // 2. [char] [char] [oth] ... + // (we reached the end of a non-wide sequence, or we need to start a wide sequence) + // -> if current string is big enough, create result (non-wide). + // otherwise if byte = null, reset to new string with byte1 as first character. + // otherwise if byte != null, reset to new string. + // 3. [char] [oth] [char] ... + // (we're in a wide sequence) + // -> (byte1 should = null) append char. + // 4. [char] [oth] [oth] ... + // (we reached the end of a wide sequence) + // -> (byte1 should = null) if the current string is big enough, create result (wide). + // otherwise, reset to new string. + // 5. [oth] [char] [char] ... + // (we reached the end of a wide sequence, or we need to start a non-wide sequence) + // -> (excluding byte1) if the current string is big enough, create result (wide). + // otherwise, reset to new string with byte1 as first character and byte as + // second character. + // 6. [oth] [char] [oth] ... + // (we're in a wide sequence) + // -> (byte2 and byte should = null) do nothing. + // 7. [oth] [oth] [char] ... + // (we're starting a sequence, but we don't know if it's a wide or non-wide sequence) + // -> append char. + // 8. [oth] [oth] [oth] ... + // (nothing) + // -> do nothing. + + if (printable2 && printable1 && printable) + { + if (length < displayBufferCount) + displayBuffer[length] = byte; + + length++; + } + else if (printable2 && printable1 && !printable) + { + if (length >= minimumLength) + { + goto CreateResult; + } + else if (byte == 0) + { + length = 1; + displayBuffer[0] = byte1; + } + else + { + length = 0; + } + } + else if (printable2 && !printable1 && printable) + { + if (byte1 == 0) + { + if (length < displayBufferCount) + displayBuffer[length] = byte; + + length++; + } + } + else if (printable2 && !printable1 && !printable) + { + if (length >= minimumLength) + { + goto CreateResult; + } + else + { + length = 0; + } + } + else if (!printable2 && printable1 && printable) + { + if (length >= minimumLength + 1) // length - 1 >= minimumLength but avoiding underflow + { + length--; // exclude byte1 + goto CreateResult; + } + else + { + length = 2; + displayBuffer[0] = byte1; + displayBuffer[1] = byte; + } + } + else if (!printable2 && printable1 && !printable) + { + // Nothing + } + else if (!printable2 && !printable1 && printable) + { + if (length < displayBufferCount) + displayBuffer[length] = byte; + + length++; + } + else if (!printable2 && !printable1 && !printable) + { + // Nothing + } + + goto AfterCreateResult; + +CreateResult: + { + PPH_MEMORY_RESULT result; + ULONG lengthInBytes; + ULONG bias; + BOOLEAN isWide; + ULONG displayLength; + + lengthInBytes = length; + bias = 0; + isWide = FALSE; + + if (printable1 == printable) // determine if string was wide (refer to state table, 4 and 5) + { + isWide = TRUE; + lengthInBytes *= 2; + } + + if (printable) // byte1 excluded (refer to state table, 5) + { + bias = 1; + } + + if (!(isWide && !detectUnicode) && (result = PhCreateMemoryResult( + PTR_ADD_OFFSET(baseAddress, i - bias - lengthInBytes), + lengthInBytes + ))) + { + displayLength = (ULONG)(min(length, displayBufferCount) * sizeof(WCHAR)); + + if (result->Display.Buffer = PhAllocateForMemorySearch(displayLength + sizeof(WCHAR))) + { + memcpy(result->Display.Buffer, displayBuffer, displayLength); + result->Display.Buffer[displayLength / sizeof(WCHAR)] = 0; + result->Display.Length = displayLength; + } + + Options->Header.Callback( + result, + Options->Header.Context + ); + } + + length = 0; + } +AfterCreateResult: + + byte2 = byte1; + byte1 = byte; + printable2 = printable1; + printable1 = printable; + } + } + +ContinueLoop: + baseAddress = PTR_ADD_OFFSET(baseAddress, basicInfo.RegionSize); + } + + if (buffer) + PhFreePage(buffer); +} + +VOID PhShowMemoryStringDialog( + _In_ HWND ParentWindowHandle, + _In_ PPH_PROCESS_ITEM ProcessItem + ) +{ + NTSTATUS status; + HANDLE processHandle; + MEMORY_STRING_CONTEXT context; + PPH_SHOW_MEMORY_RESULTS showMemoryResults; + + if (!NT_SUCCESS(status = PhOpenProcess( + &processHandle, + PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, + ProcessItem->ProcessId + ))) + { + PhShowStatus(ParentWindowHandle, L"Unable to open the process", status, 0); + return; + } + + memset(&context, 0, sizeof(MEMORY_STRING_CONTEXT)); + context.ProcessId = ProcessItem->ProcessId; + context.ProcessHandle = processHandle; + + if (DialogBoxParam( + PhInstanceHandle, + MAKEINTRESOURCE(IDD_MEMSTRING), + ParentWindowHandle, + PhpMemoryStringDlgProc, + (LPARAM)&context + ) != IDOK) + { + NtClose(processHandle); + return; + } + + context.Results = PhCreateList(1024); + + if (DialogBoxParam( + PhInstanceHandle, + MAKEINTRESOURCE(IDD_PROGRESS), + ParentWindowHandle, + PhpMemoryStringProgressDlgProc, + (LPARAM)&context + ) == IDOK) + { + showMemoryResults = PhAllocate(sizeof(PH_SHOW_MEMORY_RESULTS)); + showMemoryResults->ProcessId = ProcessItem->ProcessId; + showMemoryResults->Results = context.Results; + + PhReferenceObject(context.Results); + ProcessHacker_ShowMemoryResults( + PhMainWndHandle, + showMemoryResults + ); + } + + PhDereferenceObject(context.Results); + NtClose(processHandle); +} + +INT_PTR CALLBACK PhpMemoryStringDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + switch (uMsg) + { + case WM_INITDIALOG: + { + PhCenterWindow(hwndDlg, GetParent(hwndDlg)); + SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)lParam); + + SetDlgItemText(hwndDlg, IDC_MINIMUMLENGTH, L"10"); + Button_SetCheck(GetDlgItem(hwndDlg, IDC_DETECTUNICODE), BST_CHECKED); + Button_SetCheck(GetDlgItem(hwndDlg, IDC_PRIVATE), BST_CHECKED); + } + break; + case WM_DESTROY: + { + RemoveProp(hwndDlg, PhMakeContextAtom()); + } + break; + case WM_COMMAND: + { + switch (LOWORD(wParam)) + { + case IDCANCEL: + EndDialog(hwndDlg, IDCANCEL); + break; + case IDOK: + { + PMEMORY_STRING_CONTEXT context = (PMEMORY_STRING_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom()); + ULONG64 minimumLength = 10; + + PhStringToInteger64(&PhaGetDlgItemText(hwndDlg, IDC_MINIMUMLENGTH)->sr, 0, &minimumLength); + + if (minimumLength < 4) + { + PhShowError(hwndDlg, L"The minimum length must be at least 4."); + break; + } + + context->MinimumLength = (ULONG)minimumLength; + context->DetectUnicode = Button_GetCheck(GetDlgItem(hwndDlg, IDC_DETECTUNICODE)) == BST_CHECKED; + context->Private = Button_GetCheck(GetDlgItem(hwndDlg, IDC_PRIVATE)) == BST_CHECKED; + context->Image = Button_GetCheck(GetDlgItem(hwndDlg, IDC_IMAGE)) == BST_CHECKED; + context->Mapped = Button_GetCheck(GetDlgItem(hwndDlg, IDC_MAPPED)) == BST_CHECKED; + + EndDialog(hwndDlg, IDOK); + } + break; + } + } + break; + } + + return FALSE; +} + +static BOOL NTAPI PhpMemoryStringResultCallback( + _In_ _Assume_refs_(1) PPH_MEMORY_RESULT Result, + _In_opt_ PVOID Context + ) +{ + PMEMORY_STRING_CONTEXT context = Context; + + PhAddItemList(context->Results, Result); + + return TRUE; +} + +NTSTATUS PhpMemoryStringThreadStart( + _In_ PVOID Parameter + ) +{ + PMEMORY_STRING_CONTEXT context = Parameter; + + context->Options.Header.Callback = PhpMemoryStringResultCallback; + context->Options.Header.Context = context; + context->Options.MinimumLength = context->MinimumLength; + context->Options.DetectUnicode = context->DetectUnicode; + + if (context->Private) + context->Options.MemoryTypeMask |= MEM_PRIVATE; + if (context->Image) + context->Options.MemoryTypeMask |= MEM_IMAGE; + if (context->Mapped) + context->Options.MemoryTypeMask |= MEM_MAPPED; + + PhSearchMemoryString(context->ProcessHandle, &context->Options); + + SendMessage( + context->WindowHandle, + WM_PH_MEMORY_STATUS_UPDATE, + PH_SEARCH_COMPLETED, + 0 + ); + + return STATUS_SUCCESS; +} + +INT_PTR CALLBACK PhpMemoryStringProgressDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + switch (uMsg) + { + case WM_INITDIALOG: + { + PMEMORY_STRING_CONTEXT context = (PMEMORY_STRING_CONTEXT)lParam; + + PhCenterWindow(hwndDlg, GetParent(hwndDlg)); + SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)context); + + SetDlgItemText(hwndDlg, IDC_PROGRESSTEXT, L"Searching..."); + + PhSetWindowStyle(GetDlgItem(hwndDlg, IDC_PROGRESS), PBS_MARQUEE, PBS_MARQUEE); + SendMessage(GetDlgItem(hwndDlg, IDC_PROGRESS), PBM_SETMARQUEE, TRUE, 75); + + context->WindowHandle = hwndDlg; + context->ThreadHandle = PhCreateThread(0, PhpMemoryStringThreadStart, context); + + if (!context->ThreadHandle) + { + PhShowStatus(hwndDlg, L"Unable to create the search thread", 0, GetLastError()); + EndDialog(hwndDlg, IDCANCEL); + return FALSE; + } + + SetTimer(hwndDlg, 1, 500, NULL); + } + break; + case WM_DESTROY: + { + PMEMORY_STRING_CONTEXT context; + + context = (PMEMORY_STRING_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom()); + + if (context->ThreadHandle) + NtClose(context->ThreadHandle); + + RemoveProp(hwndDlg, PhMakeContextAtom()); + } + break; + case WM_COMMAND: + { + switch (LOWORD(wParam)) + { + case IDCANCEL: + { + PMEMORY_STRING_CONTEXT context = + (PMEMORY_STRING_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom()); + + EnableWindow(GetDlgItem(hwndDlg, IDCANCEL), FALSE); + context->Options.Header.Cancel = TRUE; + } + break; + } + } + break; + case WM_TIMER: + { + if (wParam == 1) + { + PMEMORY_STRING_CONTEXT context = + (PMEMORY_STRING_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom()); + PPH_STRING progressText; + PPH_STRING numberText; + + numberText = PhFormatUInt64(context->Results->Count, TRUE); + progressText = PhFormatString(L"%s strings found...", numberText->Buffer); + PhDereferenceObject(numberText); + SetDlgItemText(hwndDlg, IDC_PROGRESSTEXT, progressText->Buffer); + PhDereferenceObject(progressText); + InvalidateRect(GetDlgItem(hwndDlg, IDC_PROGRESSTEXT), NULL, FALSE); + } + } + break; + case WM_PH_MEMORY_STATUS_UPDATE: + { + PMEMORY_STRING_CONTEXT context; + + context = (PMEMORY_STRING_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom()); + + switch (wParam) + { + case PH_SEARCH_COMPLETED: + EndDialog(hwndDlg, IDOK); + break; + } + } + break; + } + + return FALSE; +} diff --git a/ProcessHacker/miniinfo.c b/ProcessHacker/miniinfo.c index 2ff47409664f..743efd387a2b 100644 --- a/ProcessHacker/miniinfo.c +++ b/ProcessHacker/miniinfo.c @@ -1,2273 +1,2273 @@ -/* - * Process Hacker - - * mini information window - * - * Copyright (C) 2015-2016 wj32 - * Copyright (C) 2017 dmex - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -static HWND PhMipContainerWindow = NULL; -static POINT PhMipSourcePoint; -static LONG PhMipPinCounts[MaxMiniInfoPinType]; -static LONG PhMipMaxPinCounts[] = -{ - 1, // MiniInfoManualPinType - 1, // MiniInfoIconPinType - 1, // MiniInfoActivePinType - 1, // MiniInfoHoverPinType - 1, // MiniInfoChildControlPinType -}; -C_ASSERT(sizeof(PhMipMaxPinCounts) / sizeof(LONG) == MaxMiniInfoPinType); -static LONG PhMipDelayedPinAdjustments[MaxMiniInfoPinType]; -static PPH_MESSAGE_LOOP_FILTER_ENTRY PhMipMessageLoopFilterEntry; -static HWND PhMipLastTrackedWindow; -static HWND PhMipLastNcTrackedWindow; -static ULONG PhMipRefreshAutomatically; -static BOOLEAN PhMipPinned; - -static HWND PhMipWindow = NULL; -static PH_LAYOUT_MANAGER PhMipLayoutManager; -static RECT MinimumSize; -static PH_CALLBACK_REGISTRATION ProcessesUpdatedRegistration; -static PH_STRINGREF DownArrowPrefix = PH_STRINGREF_INIT(L"\u25be "); - -static PPH_LIST SectionList; -static PH_MINIINFO_PARAMETERS CurrentParameters; -static PPH_MINIINFO_SECTION CurrentSection; - -VOID PhPinMiniInformation( - _In_ PH_MINIINFO_PIN_TYPE PinType, - _In_ LONG PinCount, - _In_opt_ ULONG PinDelayMs, - _In_ ULONG Flags, - _In_opt_ PWSTR SectionName, - _In_opt_ PPOINT SourcePoint - ) -{ - PH_MIP_ADJUST_PIN_RESULT adjustPinResult; - - if (PinDelayMs && PinCount < 0) - { - PhMipDelayedPinAdjustments[PinType] = PinCount; - SetTimer(PhMipContainerWindow, MIP_TIMER_PIN_FIRST + PinType, PinDelayMs, NULL); - return; - } - else - { - PhMipDelayedPinAdjustments[PinType] = 0; - KillTimer(PhMipContainerWindow, MIP_TIMER_PIN_FIRST + PinType); - } - - adjustPinResult = PhMipAdjustPin(PinType, PinCount); - - if (adjustPinResult == ShowAdjustPinResult) - { - PH_RECTANGLE windowRectangle; - ULONG opacity; - - if (SourcePoint) - PhMipSourcePoint = *SourcePoint; - - if (!PhMipContainerWindow) - { - WNDCLASSEX wcex; - - memset(&wcex, 0, sizeof(WNDCLASSEX)); - wcex.cbSize = sizeof(WNDCLASSEX); - wcex.style = 0; - wcex.lpfnWndProc = PhMipContainerWndProc; - wcex.cbClsExtra = 0; - wcex.cbWndExtra = 0; - wcex.hInstance = PhInstanceHandle; - wcex.hIcon = LoadIcon(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER)); - wcex.hCursor = LoadCursor(NULL, IDC_ARROW); - wcex.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1); - wcex.lpszClassName = MIP_CONTAINER_CLASSNAME; - wcex.hIconSm = (HICON)LoadImage(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER), IMAGE_ICON, 16, 16, 0); - RegisterClassEx(&wcex); - - PhMipContainerWindow = CreateWindow( - MIP_CONTAINER_CLASSNAME, - L"Process Hacker", - WS_BORDER | WS_THICKFRAME | WS_POPUP, - 0, - 0, - 400, - 400, - NULL, - NULL, - PhInstanceHandle, - NULL - ); - PhSetWindowExStyle(PhMipContainerWindow, WS_EX_TOOLWINDOW, WS_EX_TOOLWINDOW); - PhMipWindow = CreateDialog( - PhInstanceHandle, - MAKEINTRESOURCE(IDD_MINIINFO), - PhMipContainerWindow, - PhMipMiniInfoDialogProc - ); - ShowWindow(PhMipWindow, SW_SHOW); - - if (PhGetIntegerSetting(L"MiniInfoWindowPinned")) - PhMipSetPinned(TRUE); - - PhMipRefreshAutomatically = PhGetIntegerSetting(L"MiniInfoWindowRefreshAutomatically"); - - opacity = PhGetIntegerSetting(L"MiniInfoWindowOpacity"); - - if (opacity != 0) - PhSetWindowOpacity(PhMipContainerWindow, opacity); - - MinimumSize.left = 0; - MinimumSize.top = 0; - MinimumSize.right = 210; - MinimumSize.bottom = 60; - MapDialogRect(PhMipWindow, &MinimumSize); - } - - if (!(Flags & PH_MINIINFO_LOAD_POSITION)) - { - PhMipCalculateWindowRectangle(&PhMipSourcePoint, &windowRectangle); - SetWindowPos( - PhMipContainerWindow, - HWND_TOPMOST, - windowRectangle.Left, - windowRectangle.Top, - windowRectangle.Width, - windowRectangle.Height, - SWP_NOACTIVATE - ); - } - else - { - PhLoadWindowPlacementFromSetting(L"MiniInfoWindowPosition", L"MiniInfoWindowSize", PhMipContainerWindow); - SetWindowPos(PhMipContainerWindow, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE); - } - - ShowWindow(PhMipContainerWindow, (Flags & PH_MINIINFO_ACTIVATE_WINDOW) ? SW_SHOW : SW_SHOWNOACTIVATE); - } - else if (adjustPinResult == HideAdjustPinResult) - { - if (PhMipContainerWindow) - ShowWindow(PhMipContainerWindow, SW_HIDE); - } - else - { - if ((Flags & PH_MINIINFO_ACTIVATE_WINDOW) && IsWindowVisible(PhMipContainerWindow)) - SetActiveWindow(PhMipContainerWindow); - } - - if (Flags & PH_MINIINFO_ACTIVATE_WINDOW) - SetForegroundWindow(PhMipContainerWindow); - - if (SectionName && (!PhMipPinned || !(Flags & PH_MINIINFO_DONT_CHANGE_SECTION_IF_PINNED))) - { - PH_STRINGREF sectionName; - PPH_MINIINFO_SECTION section; - - PhInitializeStringRefLongHint(§ionName, SectionName); - - if (section = PhMipFindSection(§ionName)) - PhMipChangeSection(section); - } -} - -LRESULT CALLBACK PhMipContainerWndProc( - _In_ HWND hWnd, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - switch (uMsg) - { - case WM_SHOWWINDOW: - { - PhMipContainerOnShowWindow(!!wParam, (ULONG)lParam); - } - break; - case WM_ACTIVATE: - { - PhMipContainerOnActivate(LOWORD(wParam), !!HIWORD(wParam)); - } - break; - case WM_SIZE: - { - PhMipContainerOnSize(); - } - break; - case WM_SIZING: - { - PhMipContainerOnSizing((ULONG)wParam, (PRECT)lParam); - } - break; - case WM_EXITSIZEMOVE: - { - PhMipContainerOnExitSizeMove(); - } - break; - case WM_CLOSE: - { - // Hide, don't close. - ShowWindow(hWnd, SW_HIDE); - SetWindowLongPtr(hWnd, DWLP_MSGRESULT, 0); - } - return TRUE; - case WM_ERASEBKGND: - { - if (PhMipContainerOnEraseBkgnd((HDC)wParam)) - return TRUE; - } - break; - case WM_TIMER: - { - PhMipContainerOnTimer((ULONG)wParam); - } - break; - } - - return DefWindowProc(hWnd, uMsg, wParam, lParam); -} - -INT_PTR CALLBACK PhMipMiniInfoDialogProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - switch (uMsg) - { - case WM_INITDIALOG: - { - PhMipWindow = hwndDlg; - PhMipOnInitDialog(); - } - break; - case WM_SHOWWINDOW: - { - PhMipOnShowWindow(!!wParam, (ULONG)lParam); - } - break; - case WM_COMMAND: - { - PhMipOnCommand(LOWORD(wParam), HIWORD(wParam)); - } - break; - case WM_NOTIFY: - { - LRESULT result; - - if (PhMipOnNotify((NMHDR *)lParam, &result)) - { - SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, result); - return TRUE; - } - } - break; - case WM_CTLCOLORBTN: - case WM_CTLCOLORDLG: - case WM_CTLCOLORSTATIC: - { - HBRUSH brush; - - if (PhMipOnCtlColorXxx(uMsg, (HWND)lParam, (HDC)wParam, &brush)) - return (INT_PTR)brush; - } - break; - case WM_DRAWITEM: - { - if (PhMipOnDrawItem(wParam, (DRAWITEMSTRUCT *)lParam)) - return TRUE; - } - break; - } - - if (uMsg >= MIP_MSG_FIRST && uMsg <= MIP_MSG_LAST) - { - PhMipOnUserMessage(uMsg, wParam, lParam); - } - - return FALSE; -} - -VOID PhMipContainerOnShowWindow( - _In_ BOOLEAN Showing, - _In_ ULONG State - ) -{ - ULONG i; - PPH_MINIINFO_SECTION section; - - if (Showing) - { - PostMessage(PhMipWindow, MIP_MSG_UPDATE, 0, 0); - - PhMipMessageLoopFilterEntry = PhRegisterMessageLoopFilter(PhMipMessageLoopFilter, NULL); - - PhRegisterCallback( - &PhProcessesUpdatedEvent, - PhMipUpdateHandler, - NULL, - &ProcessesUpdatedRegistration - ); - - PhMipContainerOnSize(); - } - else - { - ULONG i; - - for (i = 0; i < MaxMiniInfoPinType; i++) - PhMipPinCounts[i] = 0; - - Button_SetCheck(GetDlgItem(PhMipWindow, IDC_PIN), BST_UNCHECKED); - PhMipSetPinned(FALSE); - PhSetIntegerSetting(L"MiniInfoWindowPinned", FALSE); - - PhUnregisterCallback( - &PhProcessesUpdatedEvent, - &ProcessesUpdatedRegistration - ); - - if (PhMipMessageLoopFilterEntry) - { - PhUnregisterMessageLoopFilter(PhMipMessageLoopFilterEntry); - PhMipMessageLoopFilterEntry = NULL; - } - - PhSaveWindowPlacementToSetting(L"MiniInfoWindowPosition", L"MiniInfoWindowSize", PhMipContainerWindow); - } - - if (SectionList) - { - for (i = 0; i < SectionList->Count; i++) - { - section = SectionList->Items[i]; - section->Callback(section, MiniInfoShowing, (PVOID)Showing, NULL); - } - } -} - -VOID PhMipContainerOnActivate( - _In_ ULONG Type, - _In_ BOOLEAN Minimized - ) -{ - if (Type == WA_ACTIVE || Type == WA_CLICKACTIVE) - { - PhPinMiniInformation(MiniInfoActivePinType, 1, 0, 0, NULL, NULL); - } - else if (Type == WA_INACTIVE) - { - PhPinMiniInformation(MiniInfoActivePinType, -1, 0, 0, NULL, NULL); - } -} - -VOID PhMipContainerOnSize( - VOID - ) -{ - if (PhMipWindow) - { - InvalidateRect(PhMipContainerWindow, NULL, FALSE); - PhMipLayout(); - } -} - -VOID PhMipContainerOnSizing( - _In_ ULONG Edge, - _In_ PRECT DragRectangle - ) -{ - PhResizingMinimumSize(DragRectangle, Edge, MinimumSize.right, MinimumSize.bottom); -} - -VOID PhMipContainerOnExitSizeMove( - VOID - ) -{ - PhSaveWindowPlacementToSetting(L"MiniInfoWindowPosition", L"MiniInfoWindowSize", PhMipContainerWindow); -} - -BOOLEAN PhMipContainerOnEraseBkgnd( - _In_ HDC hdc - ) -{ - return FALSE; -} - -VOID PhMipContainerOnTimer( - _In_ ULONG Id - ) -{ - if (Id >= MIP_TIMER_PIN_FIRST && Id <= MIP_TIMER_PIN_LAST) - { - PH_MINIINFO_PIN_TYPE pinType = Id - MIP_TIMER_PIN_FIRST; - - // PhPinMiniInformation kills the timer for us. - PhPinMiniInformation(pinType, PhMipDelayedPinAdjustments[pinType], 0, 0, NULL, NULL); - } -} - -VOID PhMipOnInitDialog( - VOID - ) -{ - HICON cog; - HICON pin; - - cog = PH_LOAD_SHARED_ICON_SMALL(MAKEINTRESOURCE(IDI_COG)); - SET_BUTTON_ICON(PhMipWindow, IDC_OPTIONS, cog); - - pin = PH_LOAD_SHARED_ICON_SMALL(MAKEINTRESOURCE(IDI_PIN)); - SET_BUTTON_ICON(PhMipWindow, IDC_PIN, pin); - - PhInitializeLayoutManager(&PhMipLayoutManager, PhMipWindow); - PhAddLayoutItem(&PhMipLayoutManager, GetDlgItem(PhMipWindow, IDC_LAYOUT), NULL, - PH_ANCHOR_ALL); - PhAddLayoutItem(&PhMipLayoutManager, GetDlgItem(PhMipWindow, IDC_SECTION), NULL, - PH_ANCHOR_LEFT | PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM | PH_LAYOUT_FORCE_INVALIDATE); - PhAddLayoutItem(&PhMipLayoutManager, GetDlgItem(PhMipWindow, IDC_OPTIONS), NULL, - PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); - PhAddLayoutItem(&PhMipLayoutManager, GetDlgItem(PhMipWindow, IDC_PIN), NULL, - PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); - - SetWindowSubclass(GetDlgItem(PhMipWindow, IDC_SECTION), PhMipSectionControlHookWndProc, 0, 0); - - Button_SetCheck(GetDlgItem(PhMipWindow, IDC_PIN), !!PhGetIntegerSetting(L"MiniInfoWindowPinned")); -} - -VOID PhMipOnShowWindow( - _In_ BOOLEAN Showing, - _In_ ULONG State - ) -{ - if (SectionList) - return; - - SectionList = PhCreateList(8); - PhMipInitializeParameters(); - - SendMessage(GetDlgItem(PhMipWindow, IDC_SECTION), WM_SETFONT, (WPARAM)CurrentParameters.MediumFont, FALSE); - - PhMipCreateInternalListSection(L"CPU", 0, PhMipCpuListSectionCallback); - PhMipCreateInternalListSection(L"Commit charge", 0, PhMipCommitListSectionCallback); - PhMipCreateInternalListSection(L"Physical memory", 0, PhMipPhysicalListSectionCallback); - PhMipCreateInternalListSection(L"I/O", 0, PhMipIoListSectionCallback); - - if (PhPluginsEnabled) - { - PH_PLUGIN_MINIINFO_POINTERS pointers; - - pointers.WindowHandle = PhMipContainerWindow; - pointers.CreateSection = PhMipCreateSection; - pointers.FindSection = PhMipFindSection; - pointers.CreateListSection = PhMipCreateListSection; - PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackMiniInformationInitializing), &pointers); - } - - PhMipChangeSection(SectionList->Items[0]); -} - -VOID PhMipOnCommand( - _In_ ULONG Id, - _In_ ULONG Code - ) -{ - switch (Id) - { - case IDC_SECTION: - switch (Code) - { - case STN_CLICKED: - PhMipShowSectionMenu(); - break; - } - break; - case IDC_OPTIONS: - PhMipShowOptionsMenu(); - break; - case IDC_PIN: - { - BOOLEAN pinned; - - pinned = Button_GetCheck(GetDlgItem(PhMipWindow, IDC_PIN)) == BST_CHECKED; - PhPinMiniInformation(MiniInfoManualPinType, pinned ? 1 : -1, 0, 0, NULL, NULL); - PhMipSetPinned(pinned); - PhSetIntegerSetting(L"MiniInfoWindowPinned", pinned); - } - break; - } -} - -BOOLEAN PhMipOnNotify( - _In_ NMHDR *Header, - _Out_ LRESULT *Result - ) -{ - return FALSE; -} - -BOOLEAN PhMipOnCtlColorXxx( - _In_ ULONG Message, - _In_ HWND hwnd, - _In_ HDC hdc, - _Out_ HBRUSH *Brush - ) -{ - return FALSE; -} - -BOOLEAN PhMipOnDrawItem( - _In_ ULONG_PTR Id, - _In_ DRAWITEMSTRUCT *DrawItemStruct - ) -{ - return FALSE; -} - -VOID PhMipOnUserMessage( - _In_ ULONG Message, - _In_ ULONG_PTR WParam, - _In_ ULONG_PTR LParam - ) -{ - switch (Message) - { - case MIP_MSG_UPDATE: - { - ULONG i; - PPH_MINIINFO_SECTION section; - - if (SectionList) - { - for (i = 0; i < SectionList->Count; i++) - { - section = SectionList->Items[i]; - section->Callback(section, MiniInfoTick, NULL, NULL); - } - } - } - break; - } -} - -BOOLEAN PhMipMessageLoopFilter( - _In_ PMSG Message, - _In_ PVOID Context - ) -{ - if (Message->hwnd == PhMipContainerWindow || IsChild(PhMipContainerWindow, Message->hwnd)) - { - if (Message->message == WM_MOUSEMOVE || Message->message == WM_NCMOUSEMOVE) - { - TRACKMOUSEEVENT trackMouseEvent; - - trackMouseEvent.cbSize = sizeof(TRACKMOUSEEVENT); - trackMouseEvent.dwFlags = TME_LEAVE | (Message->message == WM_NCMOUSEMOVE ? TME_NONCLIENT : 0); - trackMouseEvent.hwndTrack = Message->hwnd; - trackMouseEvent.dwHoverTime = 0; - TrackMouseEvent(&trackMouseEvent); - - if (Message->message == WM_MOUSEMOVE) - PhMipLastTrackedWindow = Message->hwnd; - else - PhMipLastNcTrackedWindow = Message->hwnd; - - PhPinMiniInformation(MiniInfoHoverPinType, 1, 0, 0, NULL, NULL); - } - else if (Message->message == WM_MOUSELEAVE && Message->hwnd == PhMipLastTrackedWindow) - { - PhPinMiniInformation(MiniInfoHoverPinType, -1, MIP_UNPIN_HOVER_DELAY, 0, NULL, NULL); - } - else if (Message->message == WM_NCMOUSELEAVE && Message->hwnd == PhMipLastNcTrackedWindow) - { - PhPinMiniInformation(MiniInfoHoverPinType, -1, MIP_UNPIN_HOVER_DELAY, 0, NULL, NULL); - } - else if (Message->message == WM_KEYDOWN) - { - switch (Message->wParam) - { - case VK_F5: - PhMipRefresh(); - break; - case VK_F6: - case VK_PAUSE: - PhMipToggleRefreshAutomatically(); - break; - } - } - } - - return FALSE; -} - -VOID NTAPI PhMipUpdateHandler( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - if (PhMipRefreshAutomatically & MIP_REFRESH_AUTOMATICALLY_FLAG(PhMipPinned)) - PostMessage(PhMipWindow, MIP_MSG_UPDATE, 0, 0); -} - -PH_MIP_ADJUST_PIN_RESULT PhMipAdjustPin( - _In_ PH_MINIINFO_PIN_TYPE PinType, - _In_ LONG PinCount - ) -{ - LONG oldTotalPinCount; - LONG oldPinCount; - LONG newPinCount; - ULONG i; - - oldTotalPinCount = 0; - - for (i = 0; i < MaxMiniInfoPinType; i++) - oldTotalPinCount += PhMipPinCounts[i]; - - oldPinCount = PhMipPinCounts[PinType]; - newPinCount = max(oldPinCount + PinCount, 0); - newPinCount = min(newPinCount, PhMipMaxPinCounts[PinType]); - PhMipPinCounts[PinType] = newPinCount; - - if (oldTotalPinCount == 0 && newPinCount > oldPinCount) - return ShowAdjustPinResult; - else if (oldTotalPinCount > 0 && oldTotalPinCount - oldPinCount + newPinCount == 0) - return HideAdjustPinResult; - else - return NoAdjustPinResult; -} - -VOID PhMipCalculateWindowRectangle( - _In_ PPOINT SourcePoint, - _Out_ PPH_RECTANGLE WindowRectangle - ) -{ - RECT windowRect; - PH_RECTANGLE windowRectangle; - PH_RECTANGLE point; - MONITORINFO monitorInfo = { sizeof(monitorInfo) }; - - PhLoadWindowPlacementFromSetting(NULL, L"MiniInfoWindowSize", PhMipContainerWindow); - GetWindowRect(PhMipContainerWindow, &windowRect); - SendMessage(PhMipContainerWindow, WM_SIZING, WMSZ_BOTTOMRIGHT, (LPARAM)&windowRect); // Adjust for the minimum size. - windowRectangle = PhRectToRectangle(windowRect); - - point.Left = SourcePoint->x; - point.Top = SourcePoint->y; - point.Width = 0; - point.Height = 0; - PhCenterRectangle(&windowRectangle, &point); - - if (GetMonitorInfo( - MonitorFromPoint(*SourcePoint, MONITOR_DEFAULTTOPRIMARY), - &monitorInfo - )) - { - PH_RECTANGLE bounds; - - if (memcmp(&monitorInfo.rcWork, &monitorInfo.rcMonitor, sizeof(RECT)) == 0) - { - HWND trayWindow; - RECT taskbarRect; - - // The taskbar probably has auto-hide enabled. We need to adjust for that. - if ((trayWindow = FindWindow(L"Shell_TrayWnd", NULL)) && - GetMonitorInfo(MonitorFromWindow(trayWindow, MONITOR_DEFAULTTOPRIMARY), &monitorInfo) && // Just in case - GetWindowRect(trayWindow, &taskbarRect)) - { - LONG monitorMidX = (monitorInfo.rcMonitor.left + monitorInfo.rcMonitor.right) / 2; - LONG monitorMidY = (monitorInfo.rcMonitor.top + monitorInfo.rcMonitor.bottom) / 2; - - if (taskbarRect.right < monitorMidX) - { - // Left - monitorInfo.rcWork.left += taskbarRect.right - taskbarRect.left; - } - else if (taskbarRect.bottom < monitorMidY) - { - // Top - monitorInfo.rcWork.top += taskbarRect.bottom - taskbarRect.top; - } - else if (taskbarRect.left > monitorMidX) - { - // Right - monitorInfo.rcWork.right -= taskbarRect.right - taskbarRect.left; - } - else if (taskbarRect.top > monitorMidY) - { - // Bottom - monitorInfo.rcWork.bottom -= taskbarRect.bottom - taskbarRect.top; - } - } - } - - bounds = PhRectToRectangle(monitorInfo.rcWork); - - PhAdjustRectangleToBounds(&windowRectangle, &bounds); - } - - *WindowRectangle = windowRectangle; -} - -VOID PhMipInitializeParameters( - VOID - ) -{ - LOGFONT logFont; - HDC hdc; - TEXTMETRIC textMetrics; - HFONT originalFont; - - memset(&CurrentParameters, 0, sizeof(PH_MINIINFO_PARAMETERS)); - - CurrentParameters.ContainerWindowHandle = PhMipContainerWindow; - CurrentParameters.MiniInfoWindowHandle = PhMipWindow; - - if (SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(LOGFONT), &logFont, 0)) - { - CurrentParameters.Font = CreateFontIndirect(&logFont); - } - else - { - CurrentParameters.Font = PhApplicationFont; - GetObject(PhApplicationFont, sizeof(LOGFONT), &logFont); - } - - hdc = GetDC(PhMipWindow); - - logFont.lfHeight -= PhMultiplyDivide(2, GetDeviceCaps(hdc, LOGPIXELSY), 72); - CurrentParameters.MediumFont = CreateFontIndirect(&logFont); - - originalFont = SelectObject(hdc, CurrentParameters.Font); - GetTextMetrics(hdc, &textMetrics); - CurrentParameters.FontHeight = textMetrics.tmHeight; - CurrentParameters.FontAverageWidth = textMetrics.tmAveCharWidth; - - SelectObject(hdc, CurrentParameters.MediumFont); - GetTextMetrics(hdc, &textMetrics); - CurrentParameters.MediumFontHeight = textMetrics.tmHeight; - CurrentParameters.MediumFontAverageWidth = textMetrics.tmAveCharWidth; - - CurrentParameters.SetSectionText = PhMipSetSectionText; - - SelectObject(hdc, originalFont); - ReleaseDC(PhMipWindow, hdc); -} - -PPH_MINIINFO_SECTION PhMipCreateSection( - _In_ PPH_MINIINFO_SECTION Template - ) -{ - PPH_MINIINFO_SECTION section; - - section = PhAllocate(sizeof(PH_MINIINFO_SECTION)); - memset(section, 0, sizeof(PH_MINIINFO_SECTION)); - - section->Name = Template->Name; - section->Flags = Template->Flags; - section->Callback = Template->Callback; - section->Context = Template->Context; - section->Parameters = &CurrentParameters; - - PhAddItemList(SectionList, section); - - section->Callback(section, MiniInfoCreate, NULL, NULL); - - return section; -} - -VOID PhMipDestroySection( - _In_ PPH_MINIINFO_SECTION Section - ) -{ - Section->Callback(Section, MiniInfoDestroy, NULL, NULL); - - PhClearReference(&Section->Text); - PhFree(Section); -} - -PPH_MINIINFO_SECTION PhMipFindSection( - _In_ PPH_STRINGREF Name - ) -{ - ULONG i; - PPH_MINIINFO_SECTION section; - - for (i = 0; i < SectionList->Count; i++) - { - section = SectionList->Items[i]; - - if (PhEqualStringRef(§ion->Name, Name, TRUE)) - return section; - } - - return NULL; -} - -PPH_MINIINFO_SECTION PhMipCreateInternalSection( - _In_ PWSTR Name, - _In_ ULONG Flags, - _In_ PPH_MINIINFO_SECTION_CALLBACK Callback - ) -{ - PH_MINIINFO_SECTION section; - - memset(§ion, 0, sizeof(PH_MINIINFO_SECTION)); - PhInitializeStringRef(§ion.Name, Name); - section.Flags = Flags; - section.Callback = Callback; - - return PhMipCreateSection(§ion); -} - -VOID PhMipCreateSectionDialog( - _In_ PPH_MINIINFO_SECTION Section - ) -{ - PH_MINIINFO_CREATE_DIALOG createDialog; - - memset(&createDialog, 0, sizeof(PH_MINIINFO_CREATE_DIALOG)); - - if (Section->Callback(Section, MiniInfoCreateDialog, &createDialog, NULL)) - { - if (!createDialog.CustomCreate) - { - Section->DialogHandle = PhCreateDialogFromTemplate( - PhMipWindow, - DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD, - createDialog.Instance, - createDialog.Template, - createDialog.DialogProc, - createDialog.Parameter - ); - } - } -} - -VOID PhMipChangeSection( - _In_ PPH_MINIINFO_SECTION NewSection - ) -{ - PPH_MINIINFO_SECTION oldSection; - - if (NewSection == CurrentSection) - return; - - oldSection = CurrentSection; - CurrentSection = NewSection; - - if (oldSection) - { - oldSection->Callback(oldSection, MiniInfoSectionChanging, CurrentSection, NULL); - - if (oldSection->DialogHandle) - ShowWindow(oldSection->DialogHandle, SW_HIDE); - } - - if (!NewSection->DialogHandle) - PhMipCreateSectionDialog(NewSection); - if (NewSection->DialogHandle) - ShowWindow(NewSection->DialogHandle, SW_SHOW); - - PhMipUpdateSectionText(NewSection); - PhMipLayout(); - - NewSection->Callback(NewSection, MiniInfoTick, NULL, NULL); -} - -VOID PhMipSetSectionText( - _In_ struct _PH_MINIINFO_SECTION *Section, - _In_opt_ PPH_STRING Text - ) -{ - PhSwapReference(&Section->Text, Text); - - if (Section == CurrentSection) - PhMipUpdateSectionText(Section); -} - -VOID PhMipUpdateSectionText( - _In_ PPH_MINIINFO_SECTION Section - ) -{ - if (Section->Text) - { - SetDlgItemText(PhMipWindow, IDC_SECTION, - PH_AUTO_T(PH_STRING, PhConcatStringRef2(&DownArrowPrefix, &Section->Text->sr))->Buffer); - } - else - { - SetDlgItemText(PhMipWindow, IDC_SECTION, - PH_AUTO_T(PH_STRING, PhConcatStringRef2(&DownArrowPrefix, &Section->Name))->Buffer); - } -} - -VOID PhMipLayout( - VOID - ) -{ - RECT clientRect; - RECT rect; - - GetClientRect(PhMipContainerWindow, &clientRect); - MoveWindow( - PhMipWindow, - clientRect.left, clientRect.top, - clientRect.right - clientRect.left, clientRect.bottom - clientRect.top, - FALSE - ); - - PhLayoutManagerLayout(&PhMipLayoutManager); - - GetWindowRect(GetDlgItem(PhMipWindow, IDC_LAYOUT), &rect); - MapWindowPoints(NULL, PhMipWindow, (POINT *)&rect, 2); - - if (CurrentSection && CurrentSection->DialogHandle) - { - if (CurrentSection->Flags & PH_MINIINFO_SECTION_NO_UPPER_MARGINS) - { - rect.left = 0; - rect.top = 0; - rect.right = clientRect.right; - } - else - { - LONG leftDistance = rect.left - clientRect.left; - LONG rightDistance = clientRect.right - rect.right; - LONG minDistance; - - if (leftDistance != rightDistance) - { - // HACK: Enforce symmetry. Sometimes these are off by a pixel. - minDistance = min(leftDistance, rightDistance); - rect.left = clientRect.left + minDistance; - rect.right = clientRect.right - minDistance; - } - } - - MoveWindow( - CurrentSection->DialogHandle, - rect.left, rect.top, - rect.right - rect.left, rect.bottom - rect.top, - TRUE - ); - } - - GetWindowRect(GetDlgItem(PhMipWindow, IDC_PIN), &rect); - MapWindowPoints(NULL, PhMipWindow, (POINT *)&rect, 2); -} - -VOID PhMipBeginChildControlPin( - VOID - ) -{ - PhPinMiniInformation(MiniInfoChildControlPinType, 1, 0, 0, NULL, NULL); -} - -VOID PhMipEndChildControlPin( - VOID - ) -{ - PhPinMiniInformation(MiniInfoChildControlPinType, -1, MIP_UNPIN_CHILD_CONTROL_DELAY, 0, NULL, NULL); - PostMessage(PhMipWindow, WM_MOUSEMOVE, 0, 0); // Re-evaluate hover pin -} - -VOID PhMipRefresh( - VOID - ) -{ - if (PhMipPinned) - ProcessHacker_Refresh(PhMainWndHandle); - - PostMessage(PhMipWindow, MIP_MSG_UPDATE, 0, 0); -} - -VOID PhMipToggleRefreshAutomatically( - VOID - ) -{ - PhMipRefreshAutomatically ^= MIP_REFRESH_AUTOMATICALLY_FLAG(PhMipPinned); - PhSetIntegerSetting(L"MiniInfoWindowRefreshAutomatically", PhMipRefreshAutomatically); -} - -VOID PhMipSetPinned( - _In_ BOOLEAN Pinned - ) -{ - PhSetWindowStyle(PhMipContainerWindow, WS_DLGFRAME | WS_SYSMENU, Pinned ? (WS_DLGFRAME | WS_SYSMENU) : 0); - SetWindowPos(PhMipContainerWindow, NULL, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED); - PhMipPinned = Pinned; - - PhNfNotifyMiniInfoPinned(Pinned); -} - -VOID PhMipShowSectionMenu( - VOID - ) -{ - PPH_EMENU menu; - ULONG i; - PPH_MINIINFO_SECTION section; - PPH_EMENU_ITEM menuItem; - POINT point; - - PhMipBeginChildControlPin(); - menu = PhCreateEMenu(); - - for (i = 0; i < SectionList->Count; i++) - { - section = SectionList->Items[i]; - menuItem = PhCreateEMenuItem( - (section == CurrentSection ? (PH_EMENU_CHECKED | PH_EMENU_RADIOCHECK) : 0), - 0, - PH_AUTO_T(PH_STRING, PhCreateString2(§ion->Name))->Buffer, - NULL, - section - ); - PhInsertEMenuItem(menu, menuItem, -1); - } - - GetCursorPos(&point); - menuItem = PhShowEMenu(menu, PhMipWindow, PH_EMENU_SHOW_LEFTRIGHT, - PH_ALIGN_LEFT | PH_ALIGN_TOP, point.x, point.y); - - if (menuItem) - { - PhMipChangeSection(menuItem->Context); - } - - PhDestroyEMenu(menu); - PhMipEndChildControlPin(); -} - -VOID PhMipShowOptionsMenu( - VOID - ) -{ - PPH_EMENU menu; - PPH_EMENU_ITEM menuItem; - ULONG id; - RECT rect; - - PhMipBeginChildControlPin(); - menu = PhCreateEMenu(); - PhLoadResourceEMenuItem(menu, PhInstanceHandle, MAKEINTRESOURCE(IDR_MINIINFO), 0); - - // Opacity - - id = PH_OPACITY_TO_ID(PhGetIntegerSetting(L"MiniInfoWindowOpacity")); - - if (menuItem = PhFindEMenuItem(menu, PH_EMENU_FIND_DESCEND, NULL, id)) - menuItem->Flags |= PH_EMENU_CHECKED | PH_EMENU_RADIOCHECK; - - // Refresh Automatically - - if (PhMipRefreshAutomatically & MIP_REFRESH_AUTOMATICALLY_FLAG(PhMipPinned)) - PhSetFlagsEMenuItem(menu, ID_MINIINFO_REFRESHAUTOMATICALLY, PH_EMENU_CHECKED, PH_EMENU_CHECKED); - - // Show the menu. - - GetWindowRect(GetDlgItem(PhMipWindow, IDC_OPTIONS), &rect); - menuItem = PhShowEMenu(menu, PhMipWindow, PH_EMENU_SHOW_LEFTRIGHT, - PH_ALIGN_LEFT | PH_ALIGN_BOTTOM, rect.left, rect.top); - - if (menuItem) - { - switch (menuItem->Id) - { - case ID_OPACITY_10: - case ID_OPACITY_20: - case ID_OPACITY_30: - case ID_OPACITY_40: - case ID_OPACITY_50: - case ID_OPACITY_60: - case ID_OPACITY_70: - case ID_OPACITY_80: - case ID_OPACITY_90: - case ID_OPACITY_OPAQUE: - { - ULONG opacity; - - opacity = PH_ID_TO_OPACITY(menuItem->Id); - PhSetIntegerSetting(L"MiniInfoWindowOpacity", opacity); - PhSetWindowOpacity(PhMipContainerWindow, opacity); - } - break; - case ID_MINIINFO_REFRESH: - PhMipRefresh(); - break; - case ID_MINIINFO_REFRESHAUTOMATICALLY: - PhMipToggleRefreshAutomatically(); - break; - } - } - - PhDestroyEMenu(menu); - PhMipEndChildControlPin(); -} - -LRESULT CALLBACK PhMipSectionControlHookWndProc( - _In_ HWND hwnd, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam, - _In_ UINT_PTR uIdSubclass, - _In_ ULONG_PTR dwRefData - ) -{ - switch (uMsg) - { - case WM_DESTROY: - RemoveWindowSubclass(hwnd, PhMipSectionControlHookWndProc, uIdSubclass); - break; - case WM_SETCURSOR: - { - SetCursor(LoadCursor(NULL, IDC_HAND)); - } - return TRUE; - } - - return DefSubclassProc(hwnd, uMsg, wParam, lParam); -} - -PPH_MINIINFO_LIST_SECTION PhMipCreateListSection( - _In_ PWSTR Name, - _In_ ULONG Flags, - _In_ PPH_MINIINFO_LIST_SECTION Template - ) -{ - PPH_MINIINFO_LIST_SECTION listSection; - PH_MINIINFO_SECTION section; - - listSection = PhAllocate(sizeof(PH_MINIINFO_LIST_SECTION)); - memset(listSection, 0, sizeof(PH_MINIINFO_LIST_SECTION)); - - listSection->Context = Template->Context; - listSection->Callback = Template->Callback; - - memset(§ion, 0, sizeof(PH_MINIINFO_SECTION)); - PhInitializeStringRef(§ion.Name, Name); - section.Flags = PH_MINIINFO_SECTION_NO_UPPER_MARGINS; - section.Callback = PhMipListSectionCallback; - section.Context = listSection; - listSection->Section = PhMipCreateSection(§ion); - - return listSection; -} - -PPH_MINIINFO_LIST_SECTION PhMipCreateInternalListSection( - _In_ PWSTR Name, - _In_ ULONG Flags, - _In_ PPH_MINIINFO_LIST_SECTION_CALLBACK Callback - ) -{ - PH_MINIINFO_LIST_SECTION listSection; - - memset(&listSection, 0, sizeof(PH_MINIINFO_LIST_SECTION)); - listSection.Callback = Callback; - - return PhMipCreateListSection(Name, Flags, &listSection); -} - -BOOLEAN PhMipListSectionCallback( - _In_ PPH_MINIINFO_SECTION Section, - _In_ PH_MINIINFO_SECTION_MESSAGE Message, - _In_opt_ PVOID Parameter1, - _In_opt_ PVOID Parameter2 - ) -{ - PPH_MINIINFO_LIST_SECTION listSection = Section->Context; - - switch (Message) - { - case MiniInfoCreate: - { - listSection->NodeList = PhCreateList(2); - listSection->Callback(listSection, MiListSectionCreate, NULL, NULL); - } - break; - case MiniInfoDestroy: - { - listSection->Callback(listSection, MiListSectionDestroy, NULL, NULL); - - PhMipClearListSection(listSection); - PhDereferenceObject(listSection->NodeList); - PhFree(listSection); - } - break; - case MiniInfoTick: - if (listSection->SuspendUpdate == 0) - PhMipTickListSection(listSection); - break; - case MiniInfoShowing: - { - listSection->Callback(listSection, MiListSectionShowing, Parameter1, Parameter2); - - if (!Parameter1) // Showing - { - // We don't want to hold process item references while the mini info window - // is hidden. - PhMipClearListSection(listSection); - TreeNew_NodesStructured(listSection->TreeNewHandle); - } - } - break; - case MiniInfoCreateDialog: - { - PPH_MINIINFO_CREATE_DIALOG createDialog = Parameter1; - - createDialog->Instance = PhInstanceHandle; - createDialog->Template = MAKEINTRESOURCE(IDD_MINIINFO_LIST); - createDialog->DialogProc = PhMipListSectionDialogProc; - createDialog->Parameter = listSection; - } - return TRUE; - } - - return FALSE; -} - -INT_PTR CALLBACK PhMipListSectionDialogProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - PPH_MINIINFO_LIST_SECTION listSection = (PPH_MINIINFO_LIST_SECTION)GetProp(hwndDlg, PhMakeContextAtom()); - - switch (uMsg) - { - case WM_INITDIALOG: - { - PPH_LAYOUT_ITEM layoutItem; - - listSection = (PPH_MINIINFO_LIST_SECTION)lParam; - SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)listSection); - - listSection->DialogHandle = hwndDlg; - listSection->TreeNewHandle = GetDlgItem(hwndDlg, IDC_LIST); - - PhInitializeLayoutManager(&listSection->LayoutManager, hwndDlg); - layoutItem = PhAddLayoutItem(&listSection->LayoutManager, listSection->TreeNewHandle, NULL, PH_ANCHOR_ALL); - - // Use negative margins to maximize our use of the window area. - layoutItem->Margin.left = -1; - layoutItem->Margin.top = -1; - layoutItem->Margin.right = -1; - - PhSetControlTheme(listSection->TreeNewHandle, L"explorer"); - TreeNew_SetCallback(listSection->TreeNewHandle, PhMipListSectionTreeNewCallback, listSection); - TreeNew_SetRowHeight(listSection->TreeNewHandle, PhMipCalculateRowHeight()); - PhAddTreeNewColumnEx2(listSection->TreeNewHandle, MIP_SINGLE_COLUMN_ID, TRUE, L"Process", 1, - PH_ALIGN_LEFT, 0, 0, TN_COLUMN_FLAG_CUSTOMDRAW); - - listSection->Callback(listSection, MiListSectionDialogCreated, hwndDlg, NULL); - PhMipTickListSection(listSection); - } - break; - case WM_DESTROY: - { - PhDeleteLayoutManager(&listSection->LayoutManager); - RemoveProp(hwndDlg, PhMakeContextAtom()); - } - break; - case WM_SIZE: - { - PhLayoutManagerLayout(&listSection->LayoutManager); - TreeNew_AutoSizeColumn(listSection->TreeNewHandle, MIP_SINGLE_COLUMN_ID, TN_AUTOSIZE_REMAINING_SPACE); - } - break; - } - - return FALSE; -} - -VOID PhMipListSectionSortFunction( - _In_ PPH_LIST List, - _In_opt_ PVOID Context - ) -{ - PPH_MINIINFO_LIST_SECTION listSection = Context; - PH_MINIINFO_LIST_SECTION_SORT_LIST sortList; - - sortList.List = List; - listSection->Callback(listSection, MiListSectionSortProcessList, &sortList, NULL); -} - -VOID PhMipTickListSection( - _In_ PPH_MINIINFO_LIST_SECTION ListSection - ) -{ - ULONG i; - PPH_MIP_GROUP_NODE node; - PH_MINIINFO_LIST_SECTION_ASSIGN_SORT_DATA assignSortData; - - PhMipClearListSection(ListSection); - - ListSection->ProcessGroupList = PhCreateProcessGroupList( - PhMipListSectionSortFunction, - ListSection, - MIP_MAX_PROCESS_GROUPS, - 0 - ); - - if (!ListSection->ProcessGroupList) - return; - - for (i = 0; i < ListSection->ProcessGroupList->Count; i++) - { - node = PhMipAddGroupNode(ListSection, ListSection->ProcessGroupList->Items[i]); - - if (node->RepresentativeProcessId == ListSection->SelectedRepresentativeProcessId && - node->RepresentativeCreateTime.QuadPart == ListSection->SelectedRepresentativeCreateTime.QuadPart) - { - node->Node.Selected = TRUE; - } - - assignSortData.ProcessGroup = node->ProcessGroup; - assignSortData.SortData = &node->SortData; - ListSection->Callback(ListSection, MiListSectionAssignSortData, &assignSortData, NULL); - } - - TreeNew_NodesStructured(ListSection->TreeNewHandle); - TreeNew_AutoSizeColumn(ListSection->TreeNewHandle, MIP_SINGLE_COLUMN_ID, TN_AUTOSIZE_REMAINING_SPACE); - - ListSection->Callback(ListSection, MiListSectionTick, NULL, NULL); -} - -VOID PhMipClearListSection( - _In_ PPH_MINIINFO_LIST_SECTION ListSection - ) -{ - ULONG i; - - if (ListSection->ProcessGroupList) - { - PhFreeProcessGroupList(ListSection->ProcessGroupList); - ListSection->ProcessGroupList = NULL; - } - - for (i = 0; i < ListSection->NodeList->Count; i++) - PhMipDestroyGroupNode(ListSection->NodeList->Items[i]); - - PhClearList(ListSection->NodeList); -} - -LONG PhMipCalculateRowHeight( - VOID - ) -{ - LONG iconHeight; - LONG titleAndSubtitleHeight; - - iconHeight = MIP_ICON_PADDING + PhLargeIconSize.Y + MIP_CELL_PADDING; - titleAndSubtitleHeight = - MIP_CELL_PADDING * 2 + CurrentParameters.FontHeight + MIP_INNER_PADDING + CurrentParameters.FontHeight; - - return max(iconHeight, titleAndSubtitleHeight); -} - -PPH_MIP_GROUP_NODE PhMipAddGroupNode( - _In_ PPH_MINIINFO_LIST_SECTION ListSection, - _In_ PPH_PROCESS_GROUP ProcessGroup - ) -{ - // This is an undocumented function exported by user32.dll that - // retrieves the hung window represented by a ghost window. - static HWND (WINAPI *HungWindowFromGhostWindow_I)( - _In_ HWND hWnd - ); - - PPH_MIP_GROUP_NODE node; - - node = PhAllocate(sizeof(PH_MIP_GROUP_NODE)); - memset(node, 0, sizeof(PH_MIP_GROUP_NODE)); - - PhInitializeTreeNewNode(&node->Node); - node->ProcessGroup = ProcessGroup; - node->RepresentativeProcessId = ProcessGroup->Representative->ProcessId; - node->RepresentativeCreateTime = ProcessGroup->Representative->CreateTime; - node->RepresentativeIsHung = ProcessGroup->WindowHandle && IsHungAppWindow(ProcessGroup->WindowHandle); - - if (node->RepresentativeIsHung) - { - if (!HungWindowFromGhostWindow_I) - HungWindowFromGhostWindow_I = PhGetModuleProcAddress(L"user32.dll", "HungWindowFromGhostWindow"); - - // Make sure this is a real hung window, not a ghost window. - if (HungWindowFromGhostWindow_I && HungWindowFromGhostWindow_I(ProcessGroup->WindowHandle)) - node->RepresentativeIsHung = FALSE; - } - - PhAddItemList(ListSection->NodeList, node); - - return node; -} - -VOID PhMipDestroyGroupNode( - _In_ PPH_MIP_GROUP_NODE Node - ) -{ - PhClearReference(&Node->TooltipText); - PhFree(Node); -} - -BOOLEAN PhMipListSectionTreeNewCallback( - _In_ HWND hwnd, - _In_ PH_TREENEW_MESSAGE Message, - _In_opt_ PVOID Parameter1, - _In_opt_ PVOID Parameter2, - _In_opt_ PVOID Context - ) -{ - PPH_MINIINFO_LIST_SECTION listSection = Context; - - switch (Message) - { - case TreeNewGetChildren: - { - PPH_TREENEW_GET_CHILDREN getChildren = Parameter1; - PH_MINIINFO_LIST_SECTION_SORT_LIST sortList; - - if (!getChildren->Node) - { - getChildren->Children = (PPH_TREENEW_NODE *)listSection->NodeList->Items; - getChildren->NumberOfChildren = listSection->NodeList->Count; - - sortList.List = listSection->NodeList; - listSection->Callback(listSection, MiListSectionSortGroupList, &sortList, NULL); - } - } - return TRUE; - case TreeNewIsLeaf: - { - PPH_TREENEW_IS_LEAF isLeaf = Parameter1; - isLeaf->IsLeaf = TRUE; - } - return TRUE; - case TreeNewCustomDraw: - { - PPH_TREENEW_CUSTOM_DRAW customDraw = Parameter1; - PPH_MIP_GROUP_NODE node = (PPH_MIP_GROUP_NODE)customDraw->Node; - PPH_PROCESS_ITEM processItem = node->ProcessGroup->Representative; - HDC hdc = customDraw->Dc; - RECT rect = customDraw->CellRect; - ULONG baseTextFlags = DT_NOPREFIX | DT_VCENTER | DT_SINGLELINE; - HICON icon; - COLORREF originalTextColor; - RECT topRect; - RECT bottomRect; - PH_MINIINFO_LIST_SECTION_GET_USAGE_TEXT getUsageText; - ULONG usageTextTopWidth = 0; - ULONG usageTextBottomWidth = 0; - PH_MINIINFO_LIST_SECTION_GET_TITLE_TEXT getTitleText; - - rect.left += MIP_ICON_PADDING; - rect.top += MIP_ICON_PADDING; - rect.right -= MIP_CELL_PADDING; - rect.bottom -= MIP_CELL_PADDING; - - if (processItem->LargeIcon) - icon = processItem->LargeIcon; - else - PhGetStockApplicationIcon(NULL, &icon); - - DrawIconEx(hdc, rect.left, rect.top, icon, PhLargeIconSize.X, PhLargeIconSize.Y, - 0, NULL, DI_NORMAL); - rect.left += (MIP_CELL_PADDING - MIP_ICON_PADDING) + PhLargeIconSize.X + MIP_CELL_PADDING; - rect.top += MIP_CELL_PADDING - MIP_ICON_PADDING; - SelectObject(hdc, CurrentParameters.Font); - - // This color changes depending on whether the node is selected, etc. - originalTextColor = GetTextColor(hdc); - - // Usage text - - topRect = rect; - topRect.bottom = topRect.top + CurrentParameters.FontHeight; - bottomRect = rect; - bottomRect.top = bottomRect.bottom - CurrentParameters.FontHeight; - - getUsageText.ProcessGroup = node->ProcessGroup; - getUsageText.SortData = &node->SortData; - getUsageText.Line1 = NULL; - getUsageText.Line2 = NULL; - getUsageText.Line1Color = originalTextColor; - getUsageText.Line2Color = originalTextColor; - - if (listSection->Callback(listSection, MiListSectionGetUsageText, &getUsageText, NULL)) - { - PH_STRINGREF text; - RECT textRect; - SIZE textSize; - - // Top - text = PhGetStringRef(getUsageText.Line1); - GetTextExtentPoint32(hdc, text.Buffer, (ULONG)text.Length / 2, &textSize); - usageTextTopWidth = textSize.cx; - textRect = topRect; - textRect.left = textRect.right - textSize.cx; - SetTextColor(hdc, getUsageText.Line1Color); - DrawText(hdc, text.Buffer, (ULONG)text.Length / 2, &textRect, baseTextFlags | DT_RIGHT); - PhClearReference(&getUsageText.Line1); - - // Bottom - text = PhGetStringRef(getUsageText.Line2); - GetTextExtentPoint32(hdc, text.Buffer, (ULONG)text.Length / 2, &textSize); - usageTextBottomWidth = textSize.cx; - textRect = bottomRect; - textRect.left = textRect.right - textSize.cx; - SetTextColor(hdc, getUsageText.Line2Color); - DrawText(hdc, text.Buffer, (ULONG)text.Length / 2, &textRect, baseTextFlags | DT_RIGHT); - PhClearReference(&getUsageText.Line2); - } - - // Title, subtitle - - getTitleText.ProcessGroup = node->ProcessGroup; - getTitleText.SortData = &node->SortData; - - if (!PhIsNullOrEmptyString(processItem->VersionInfo.FileDescription)) - PhSetReference(&getTitleText.Title, processItem->VersionInfo.FileDescription); - else - PhSetReference(&getTitleText.Title, processItem->ProcessName); - - if (node->ProcessGroup->Processes->Count == 1) - { - PhSetReference(&getTitleText.Subtitle, processItem->ProcessName); - } - else - { - getTitleText.Subtitle = PhFormatString( - L"%s (%u processes)", - processItem->ProcessName->Buffer, - node->ProcessGroup->Processes->Count - ); - } - - getTitleText.TitleColor = originalTextColor; - getTitleText.SubtitleColor = GetSysColor(COLOR_GRAYTEXT); - - // Special text for hung windows - if (node->RepresentativeIsHung) - { - static PH_STRINGREF hungPrefix = PH_STRINGREF_INIT(L"(Not responding) "); - - PhMoveReference(&getTitleText.Title, PhConcatStringRef2(&hungPrefix, &getTitleText.Title->sr)); - getTitleText.TitleColor = RGB(0xff, 0x00, 0x00); - } - - listSection->Callback(listSection, MiListSectionGetTitleText, &getTitleText, NULL); - - if (!PhIsNullOrEmptyString(getTitleText.Title)) - { - RECT textRect; - - textRect = topRect; - textRect.right -= usageTextTopWidth + MIP_INNER_PADDING; - SetTextColor(hdc, getTitleText.TitleColor); - DrawText( - hdc, - getTitleText.Title->Buffer, - (ULONG)getTitleText.Title->Length / 2, - &textRect, - baseTextFlags | DT_END_ELLIPSIS - ); - } - - if (!PhIsNullOrEmptyString(getTitleText.Subtitle)) - { - RECT textRect; - - textRect = bottomRect; - textRect.right -= usageTextBottomWidth + MIP_INNER_PADDING; - SetTextColor(hdc, getTitleText.SubtitleColor); - DrawText( - hdc, - getTitleText.Subtitle->Buffer, - (ULONG)getTitleText.Subtitle->Length / 2, - &textRect, - baseTextFlags | DT_END_ELLIPSIS - ); - } - - PhClearReference(&getTitleText.Title); - PhClearReference(&getTitleText.Subtitle); - } - return TRUE; - case TreeNewGetCellTooltip: - { - PPH_TREENEW_GET_CELL_TOOLTIP getCellTooltip = Parameter1; - PPH_MIP_GROUP_NODE node = (PPH_MIP_GROUP_NODE)getCellTooltip->Node; - ULONG tickCount; - - tickCount = GetTickCount(); - - // This is useless most of the time because the tooltip doesn't display unless the window is active. - // TODO: Find a way to make the tooltip display all the time. - - if (!node->TooltipText) - node->TooltipText = PhMipGetGroupNodeTooltip(listSection, node); - - if (!PhIsNullOrEmptyString(node->TooltipText)) - { - getCellTooltip->Text = node->TooltipText->sr; - getCellTooltip->Unfolding = FALSE; - getCellTooltip->MaximumWidth = -1; - } - else - { - return FALSE; - } - } - return TRUE; - case TreeNewSelectionChanged: - { - ULONG i; - PPH_MIP_GROUP_NODE node; - - listSection->SelectedRepresentativeProcessId = NULL; - listSection->SelectedRepresentativeCreateTime.QuadPart = 0; - - for (i = 0; i < listSection->NodeList->Count; i++) - { - node = listSection->NodeList->Items[i]; - - if (node->Node.Selected) - { - listSection->SelectedRepresentativeProcessId = node->RepresentativeProcessId; - listSection->SelectedRepresentativeCreateTime = node->RepresentativeCreateTime; - break; - } - } - } - break; - case TreeNewKeyDown: - { - PPH_TREENEW_KEY_EVENT keyEvent = Parameter1; - PPH_MIP_GROUP_NODE node; - - listSection->SuspendUpdate++; - - switch (keyEvent->VirtualKey) - { - case VK_DELETE: - if (node = PhMipGetSelectedGroupNode(listSection)) - PhUiTerminateProcesses(listSection->DialogHandle, &node->ProcessGroup->Representative, 1); - break; - case VK_RETURN: - if (node = PhMipGetSelectedGroupNode(listSection)) - { - if (GetKeyState(VK_CONTROL) >= 0) - { - PhMipHandleListSectionCommand(listSection, node->ProcessGroup, ID_PROCESS_GOTOPROCESS); - } - else - { - if (node->ProcessGroup->Representative->FileName) - PhShellExploreFile(listSection->DialogHandle, node->ProcessGroup->Representative->FileName->Buffer); - } - } - break; - } - - listSection->SuspendUpdate--; - } - return TRUE; - case TreeNewLeftDoubleClick: - { - PPH_TREENEW_MOUSE_EVENT mouseEvent = Parameter1; - PPH_MIP_GROUP_NODE node = (PPH_MIP_GROUP_NODE)mouseEvent->Node; - - if (node) - { - listSection->SuspendUpdate++; - PhMipHandleListSectionCommand(listSection, node->ProcessGroup, ID_PROCESS_GOTOPROCESS); - listSection->SuspendUpdate--; - } - } - break; - case TreeNewContextMenu: - { - PPH_TREENEW_CONTEXT_MENU contextMenu = Parameter1; - - // Prevent the node list from being updated (otherwise any nodes we're using might be destroyed while we're - // in a modal message loop). - listSection->SuspendUpdate++; - PhMipBeginChildControlPin(); - PhMipShowListSectionContextMenu(listSection, contextMenu); - PhMipEndChildControlPin(); - listSection->SuspendUpdate--; - } - break; - } - - return FALSE; -} - -PPH_STRING PhMipGetGroupNodeTooltip( - _In_ PPH_MINIINFO_LIST_SECTION ListSection, - _In_ PPH_MIP_GROUP_NODE Node - ) -{ - PH_STRING_BUILDER sb; - - PhInitializeStringBuilder(&sb, 100); - - // TODO - - return PhFinalStringBuilderString(&sb); -} - -PPH_MIP_GROUP_NODE PhMipGetSelectedGroupNode( - _In_ PPH_MINIINFO_LIST_SECTION ListSection - ) -{ - ULONG i; - PPH_MIP_GROUP_NODE node; - - for (i = 0; i < ListSection->NodeList->Count; i++) - { - node = ListSection->NodeList->Items[i]; - - if (node->Node.Selected) - return node; - } - - return NULL; -} - -VOID PhMipShowListSectionContextMenu( - _In_ PPH_MINIINFO_LIST_SECTION ListSection, - _In_ PPH_TREENEW_CONTEXT_MENU ContextMenu - ) -{ - PPH_MIP_GROUP_NODE selectedNode; - PPH_EMENU menu; - PPH_EMENU_ITEM item; - PH_MINIINFO_LIST_SECTION_MENU_INFORMATION menuInfo; - PH_PLUGIN_MENU_INFORMATION pluginMenuInfo; - - selectedNode = PhMipGetSelectedGroupNode(ListSection); - - if (!selectedNode) - return; - - menu = PhCreateEMenu(); - // TODO: If there are multiple processes, then create submenus for each process. - PhAddMiniProcessMenuItems(menu, ListSection->SelectedRepresentativeProcessId); - PhLoadResourceEMenuItem(menu, PhInstanceHandle, MAKEINTRESOURCE(IDR_MINIINFO_PROCESS), 0); - PhSetFlagsEMenuItem(menu, ID_PROCESS_GOTOPROCESS, PH_EMENU_DEFAULT, PH_EMENU_DEFAULT); - - if (selectedNode->ProcessGroup->Processes->Count != 1) - { - if (item = PhFindEMenuItem(menu, 0, NULL, ID_PROCESS_GOTOPROCESS)) - PhModifyEMenuItem(item, PH_EMENU_MODIFY_TEXT, 0, L"&Go to processes", NULL); - } - - memset(&menuInfo, 0, sizeof(PH_MINIINFO_LIST_SECTION_MENU_INFORMATION)); - menuInfo.ProcessGroup = selectedNode->ProcessGroup; - menuInfo.SortData = &selectedNode->SortData; - menuInfo.ContextMenu = ContextMenu; - ListSection->Callback(ListSection, MiListSectionInitializeContextMenu, &menuInfo, NULL); - - if (PhPluginsEnabled) - { - PhPluginInitializeMenuInfo(&pluginMenuInfo, menu, ListSection->DialogHandle, 0); - pluginMenuInfo.Menu = menu; - pluginMenuInfo.OwnerWindow = PhMipWindow; - pluginMenuInfo.u.MiListSection.SectionName = &ListSection->Section->Name; - pluginMenuInfo.u.MiListSection.ProcessGroup = selectedNode->ProcessGroup; - - PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackMiListSectionMenuInitializing), &pluginMenuInfo); - } - - item = PhShowEMenu( - menu, - PhMipWindow, - PH_EMENU_SHOW_LEFTRIGHT, - PH_ALIGN_LEFT | PH_ALIGN_TOP, - ContextMenu->Location.x, - ContextMenu->Location.y - ); - - if (item) - { - BOOLEAN handled = FALSE; - - if (!handled && PhPluginsEnabled) - handled = PhPluginTriggerEMenuItem(&pluginMenuInfo, item); - - if (!handled) - { - menuInfo.SelectedItem = item; - handled = ListSection->Callback(ListSection, MiListSectionHandleContextMenu, &menuInfo, NULL); - } - - if (!handled) - PhHandleMiniProcessMenuItem(item); - - if (!handled) - PhMipHandleListSectionCommand(ListSection, selectedNode->ProcessGroup, item->Id); - } - - PhDestroyEMenu(menu); -} - -VOID PhMipHandleListSectionCommand( - _In_ PPH_MINIINFO_LIST_SECTION ListSection, - _In_ PPH_PROCESS_GROUP ProcessGroup, - _In_ ULONG Id - ) -{ - switch (Id) - { - case ID_PROCESS_GOTOPROCESS: - { - PPH_LIST nodes; - ULONG i; - - nodes = PhCreateList(ProcessGroup->Processes->Count); - - for (i = 0; i < ProcessGroup->Processes->Count; i++) - { - PPH_PROCESS_NODE node; - - if (node = PhFindProcessNode(((PPH_PROCESS_ITEM)ProcessGroup->Processes->Items[i])->ProcessId)) - PhAddItemList(nodes, node); - } - - PhPinMiniInformation(MiniInfoIconPinType, -1, 0, 0, NULL, NULL); - PhPinMiniInformation(MiniInfoActivePinType, -1, 0, 0, NULL, NULL); - PhPinMiniInformation(MiniInfoHoverPinType, -1, 0, 0, NULL, NULL); - - ProcessHacker_ToggleVisible(PhMainWndHandle, TRUE); - ProcessHacker_SelectTabPage(PhMainWndHandle, 0); - PhSelectAndEnsureVisibleProcessNodes((PPH_PROCESS_NODE *)nodes->Items, nodes->Count); - PhDereferenceObject(nodes); - } - break; - } -} - -BOOLEAN PhMipCpuListSectionCallback( - _In_ struct _PH_MINIINFO_LIST_SECTION *ListSection, - _In_ PH_MINIINFO_LIST_SECTION_MESSAGE Message, - _In_opt_ PVOID Parameter1, - _In_opt_ PVOID Parameter2 - ) -{ - switch (Message) - { - case MiListSectionTick: - ListSection->Section->Parameters->SetSectionText(ListSection->Section, - PhaFormatString(L"CPU %.2f%%", (PhCpuUserUsage + PhCpuKernelUsage) * 100)); - break; - case MiListSectionSortProcessList: - { - PPH_MINIINFO_LIST_SECTION_SORT_LIST sortList = Parameter1; - - qsort(sortList->List->Items, sortList->List->Count, - sizeof(PPH_PROCESS_NODE), PhMipCpuListSectionProcessCompareFunction); - } - return TRUE; - case MiListSectionAssignSortData: - { - PPH_MINIINFO_LIST_SECTION_ASSIGN_SORT_DATA assignSortData = Parameter1; - PPH_LIST processes = assignSortData->ProcessGroup->Processes; - FLOAT cpuUsage = 0; - ULONG i; - - for (i = 0; i < processes->Count; i++) - cpuUsage += ((PPH_PROCESS_ITEM)processes->Items[i])->CpuUsage; - - *(PFLOAT)assignSortData->SortData->UserData = cpuUsage; - } - return TRUE; - case MiListSectionSortGroupList: - { - PPH_MINIINFO_LIST_SECTION_SORT_LIST sortList = Parameter1; - - qsort(sortList->List->Items, sortList->List->Count, - sizeof(PPH_MINIINFO_LIST_SECTION_SORT_DATA), PhMipCpuListSectionNodeCompareFunction); - } - return TRUE; - case MiListSectionGetUsageText: - { - PPH_MINIINFO_LIST_SECTION_GET_USAGE_TEXT getUsageText = Parameter1; - PPH_LIST processes = getUsageText->ProcessGroup->Processes; - FLOAT cpuUsage = *(PFLOAT)getUsageText->SortData->UserData * 100; - PPH_STRING cpuUsageText; - - if (cpuUsage >= 0.01) - cpuUsageText = PhFormatString(L"%.2f%%", cpuUsage); - else if (cpuUsage != 0) - cpuUsageText = PhCreateString(L"< 0.01%"); - else - cpuUsageText = NULL; - - PhMoveReference(&getUsageText->Line1, cpuUsageText); - } - return TRUE; - } - - return FALSE; -} - -int __cdecl PhMipCpuListSectionProcessCompareFunction( - _In_ const void *elem1, - _In_ const void *elem2 - ) -{ - int result; - PPH_PROCESS_NODE node1 = *(PPH_PROCESS_NODE *)elem1; - PPH_PROCESS_NODE node2 = *(PPH_PROCESS_NODE *)elem2; - - result = singlecmp(node2->ProcessItem->CpuUsage, node1->ProcessItem->CpuUsage); - - if (result == 0) - result = uint64cmp(node2->ProcessItem->UserTime.QuadPart, node1->ProcessItem->UserTime.QuadPart); - - return result; -} - -int __cdecl PhMipCpuListSectionNodeCompareFunction( - _In_ const void *elem1, - _In_ const void *elem2 - ) -{ - PPH_MINIINFO_LIST_SECTION_SORT_DATA data1 = *(PPH_MINIINFO_LIST_SECTION_SORT_DATA *)elem1; - PPH_MINIINFO_LIST_SECTION_SORT_DATA data2 = *(PPH_MINIINFO_LIST_SECTION_SORT_DATA *)elem2; - - return singlecmp(*(PFLOAT)data2->UserData, *(PFLOAT)data1->UserData); -} - -BOOLEAN PhMipCommitListSectionCallback( - _In_ struct _PH_MINIINFO_LIST_SECTION *ListSection, - _In_ PH_MINIINFO_LIST_SECTION_MESSAGE Message, - _In_opt_ PVOID Parameter1, - _In_opt_ PVOID Parameter2 - ) -{ - switch (Message) - { - case MiListSectionTick: - { - PH_FORMAT format[5]; - DOUBLE commitFraction = (DOUBLE)PhPerfInformation.CommittedPages / PhPerfInformation.CommitLimit; - - PhInitFormatS(&format[0], L"Commit "); - PhInitFormatSize(&format[1], UInt32x32To64(PhPerfInformation.CommittedPages, PAGE_SIZE)); - PhInitFormatS(&format[2], L" ("); - PhInitFormatF(&format[3], commitFraction * 100, 2); - PhInitFormatS(&format[4], L"%)"); - ListSection->Section->Parameters->SetSectionText(ListSection->Section, - PH_AUTO(PhFormat(format, 5, 96))); - } - break; - case MiListSectionSortProcessList: - { - PPH_MINIINFO_LIST_SECTION_SORT_LIST sortList = Parameter1; - - qsort(sortList->List->Items, sortList->List->Count, - sizeof(PPH_PROCESS_NODE), PhMipCommitListSectionProcessCompareFunction); - } - return TRUE; - case MiListSectionAssignSortData: - { - PPH_MINIINFO_LIST_SECTION_ASSIGN_SORT_DATA assignSortData = Parameter1; - PPH_LIST processes = assignSortData->ProcessGroup->Processes; - ULONG64 privateBytes = 0; - ULONG i; - - for (i = 0; i < processes->Count; i++) - privateBytes += ((PPH_PROCESS_ITEM)processes->Items[i])->VmCounters.PagefileUsage; - - *(PULONG64)assignSortData->SortData->UserData = privateBytes; - } - return TRUE; - case MiListSectionSortGroupList: - { - PPH_MINIINFO_LIST_SECTION_SORT_LIST sortList = Parameter1; - - qsort(sortList->List->Items, sortList->List->Count, - sizeof(PPH_MINIINFO_LIST_SECTION_SORT_DATA), PhMipCommitListSectionNodeCompareFunction); - } - return TRUE; - case MiListSectionGetUsageText: - { - PPH_MINIINFO_LIST_SECTION_GET_USAGE_TEXT getUsageText = Parameter1; - PPH_LIST processes = getUsageText->ProcessGroup->Processes; - ULONG64 privateBytes = *(PULONG64)getUsageText->SortData->UserData; - - PhMoveReference(&getUsageText->Line1, PhFormatSize(privateBytes, -1)); - PhMoveReference(&getUsageText->Line2, PhCreateString(L"Private bytes")); - getUsageText->Line2Color = GetSysColor(COLOR_GRAYTEXT); - } - return TRUE; - } - - return FALSE; -} - -int __cdecl PhMipCommitListSectionProcessCompareFunction( - _In_ const void *elem1, - _In_ const void *elem2 - ) -{ - PPH_PROCESS_NODE node1 = *(PPH_PROCESS_NODE *)elem1; - PPH_PROCESS_NODE node2 = *(PPH_PROCESS_NODE *)elem2; - - return uintptrcmp(node2->ProcessItem->VmCounters.PagefileUsage, node1->ProcessItem->VmCounters.PagefileUsage); -} - -int __cdecl PhMipCommitListSectionNodeCompareFunction( - _In_ const void *elem1, - _In_ const void *elem2 - ) -{ - PPH_MINIINFO_LIST_SECTION_SORT_DATA data1 = *(PPH_MINIINFO_LIST_SECTION_SORT_DATA *)elem1; - PPH_MINIINFO_LIST_SECTION_SORT_DATA data2 = *(PPH_MINIINFO_LIST_SECTION_SORT_DATA *)elem2; - - return uint64cmp(*(PULONG64)data2->UserData, *(PULONG64)data1->UserData); -} - -BOOLEAN PhMipPhysicalListSectionCallback( - _In_ struct _PH_MINIINFO_LIST_SECTION *ListSection, - _In_ PH_MINIINFO_LIST_SECTION_MESSAGE Message, - _In_opt_ PVOID Parameter1, - _In_opt_ PVOID Parameter2 - ) -{ - switch (Message) - { - case MiListSectionTick: - { - PH_FORMAT format[5]; - ULONG physicalUsage = PhSystemBasicInformation.NumberOfPhysicalPages - PhPerfInformation.AvailablePages; - FLOAT physicalFraction = (FLOAT)physicalUsage / PhSystemBasicInformation.NumberOfPhysicalPages; - - PhInitFormatS(&format[0], L"Physical "); - PhInitFormatSize(&format[1], UInt32x32To64(physicalUsage, PAGE_SIZE)); - PhInitFormatS(&format[2], L" ("); - PhInitFormatF(&format[3], physicalFraction * 100, 2); - PhInitFormatS(&format[4], L"%)"); - ListSection->Section->Parameters->SetSectionText(ListSection->Section, - PH_AUTO(PhFormat(format, 5, 96))); - } - break; - case MiListSectionSortProcessList: - { - PPH_MINIINFO_LIST_SECTION_SORT_LIST sortList = Parameter1; - - qsort(sortList->List->Items, sortList->List->Count, - sizeof(PPH_PROCESS_NODE), PhMipPhysicalListSectionProcessCompareFunction); - } - return TRUE; - case MiListSectionAssignSortData: - { - PPH_MINIINFO_LIST_SECTION_ASSIGN_SORT_DATA assignSortData = Parameter1; - PPH_LIST processes = assignSortData->ProcessGroup->Processes; - ULONG64 workingSet = 0; - ULONG i; - - for (i = 0; i < processes->Count; i++) - workingSet += ((PPH_PROCESS_ITEM)processes->Items[i])->VmCounters.WorkingSetSize; - - *(PULONG64)assignSortData->SortData->UserData = workingSet; - } - return TRUE; - case MiListSectionSortGroupList: - { - PPH_MINIINFO_LIST_SECTION_SORT_LIST sortList = Parameter1; - - qsort(sortList->List->Items, sortList->List->Count, - sizeof(PPH_MINIINFO_LIST_SECTION_SORT_DATA), PhMipPhysicalListSectionNodeCompareFunction); - } - return TRUE; - case MiListSectionGetUsageText: - { - PPH_MINIINFO_LIST_SECTION_GET_USAGE_TEXT getUsageText = Parameter1; - PPH_LIST processes = getUsageText->ProcessGroup->Processes; - ULONG64 privateBytes = *(PULONG64)getUsageText->SortData->UserData; - - PhMoveReference(&getUsageText->Line1, PhFormatSize(privateBytes, -1)); - PhMoveReference(&getUsageText->Line2, PhCreateString(L"Working set")); - getUsageText->Line2Color = GetSysColor(COLOR_GRAYTEXT); - } - return TRUE; - } - - return FALSE; -} - -int __cdecl PhMipPhysicalListSectionProcessCompareFunction( - _In_ const void *elem1, - _In_ const void *elem2 - ) -{ - PPH_PROCESS_NODE node1 = *(PPH_PROCESS_NODE *)elem1; - PPH_PROCESS_NODE node2 = *(PPH_PROCESS_NODE *)elem2; - - return uintptrcmp(node2->ProcessItem->VmCounters.WorkingSetSize, node1->ProcessItem->VmCounters.WorkingSetSize); -} - -int __cdecl PhMipPhysicalListSectionNodeCompareFunction( - _In_ const void *elem1, - _In_ const void *elem2 - ) -{ - PPH_MINIINFO_LIST_SECTION_SORT_DATA data1 = *(PPH_MINIINFO_LIST_SECTION_SORT_DATA *)elem1; - PPH_MINIINFO_LIST_SECTION_SORT_DATA data2 = *(PPH_MINIINFO_LIST_SECTION_SORT_DATA *)elem2; - - return uint64cmp(*(PULONG64)data2->UserData, *(PULONG64)data1->UserData); -} - -BOOLEAN PhMipIoListSectionCallback( - _In_ struct _PH_MINIINFO_LIST_SECTION *ListSection, - _In_ PH_MINIINFO_LIST_SECTION_MESSAGE Message, - _In_opt_ PVOID Parameter1, - _In_opt_ PVOID Parameter2 - ) -{ - switch (Message) - { - case MiListSectionTick: - { - PH_FORMAT format[6]; - - PhInitFormatS(&format[0], L"I/O R: "); - PhInitFormatSize(&format[1], PhIoReadDelta.Delta); - format[1].Type |= FormatUsePrecision; - format[1].Precision = 0; - PhInitFormatS(&format[2], L" W: "); - PhInitFormatSize(&format[3], PhIoWriteDelta.Delta); - format[3].Type |= FormatUsePrecision; - format[3].Precision = 0; - PhInitFormatS(&format[4], L" O: "); - PhInitFormatSize(&format[5], PhIoOtherDelta.Delta); - format[5].Type |= FormatUsePrecision; - format[5].Precision = 0; - ListSection->Section->Parameters->SetSectionText(ListSection->Section, - PH_AUTO(PhFormat(format, 6, 80))); - } - break; - case MiListSectionSortProcessList: - { - PPH_MINIINFO_LIST_SECTION_SORT_LIST sortList = Parameter1; - - qsort(sortList->List->Items, sortList->List->Count, - sizeof(PPH_PROCESS_NODE), PhMipIoListSectionProcessCompareFunction); - } - return TRUE; - case MiListSectionAssignSortData: - { - PPH_MINIINFO_LIST_SECTION_ASSIGN_SORT_DATA assignSortData = Parameter1; - PPH_LIST processes = assignSortData->ProcessGroup->Processes; - ULONG64 ioReadOtherDelta = 0; - ULONG64 ioWriteDelta = 0; - ULONG i; - - for (i = 0; i < processes->Count; i++) - { - PPH_PROCESS_ITEM processItem = processes->Items[i]; - ioReadOtherDelta += processItem->IoReadDelta.Delta; - ioWriteDelta += processItem->IoWriteDelta.Delta; - ioReadOtherDelta += processItem->IoOtherDelta.Delta; - } - - assignSortData->SortData->UserData[0] = ioReadOtherDelta; - assignSortData->SortData->UserData[1] = ioWriteDelta; - } - return TRUE; - case MiListSectionSortGroupList: - { - PPH_MINIINFO_LIST_SECTION_SORT_LIST sortList = Parameter1; - - qsort(sortList->List->Items, sortList->List->Count, - sizeof(PPH_MINIINFO_LIST_SECTION_SORT_DATA), PhMipIoListSectionNodeCompareFunction); - } - return TRUE; - case MiListSectionGetUsageText: - { - PPH_MINIINFO_LIST_SECTION_GET_USAGE_TEXT getUsageText = Parameter1; - PPH_LIST processes = getUsageText->ProcessGroup->Processes; - ULONG64 ioReadOtherDelta = getUsageText->SortData->UserData[0]; - ULONG64 ioWriteDelta = getUsageText->SortData->UserData[1]; - PH_FORMAT format[1]; - - PhInitFormatSize(&format[0], ioReadOtherDelta + ioWriteDelta); - PhMoveReference(&getUsageText->Line1, PhFormat(format, 1, 16)); - } - return TRUE; - } - - return FALSE; -} - -int __cdecl PhMipIoListSectionProcessCompareFunction( - _In_ const void *elem1, - _In_ const void *elem2 - ) -{ - int result; - PPH_PROCESS_NODE node1 = *(PPH_PROCESS_NODE *)elem1; - PPH_PROCESS_NODE node2 = *(PPH_PROCESS_NODE *)elem2; - ULONG64 delta1 = node1->ProcessItem->IoReadDelta.Delta + node1->ProcessItem->IoWriteDelta.Delta + node1->ProcessItem->IoOtherDelta.Delta; - ULONG64 delta2 = node2->ProcessItem->IoReadDelta.Delta + node2->ProcessItem->IoWriteDelta.Delta + node2->ProcessItem->IoOtherDelta.Delta; - ULONG64 value1 = node1->ProcessItem->IoReadDelta.Value + node1->ProcessItem->IoWriteDelta.Value + node1->ProcessItem->IoOtherDelta.Value; - ULONG64 value2 = node2->ProcessItem->IoReadDelta.Value + node2->ProcessItem->IoWriteDelta.Value + node2->ProcessItem->IoOtherDelta.Value; - - result = uint64cmp(delta2, delta1); - - if (result == 0) - result = uint64cmp(value2, value1); - - return result; -} - -int __cdecl PhMipIoListSectionNodeCompareFunction( - _In_ const void *elem1, - _In_ const void *elem2 - ) -{ - PPH_MINIINFO_LIST_SECTION_SORT_DATA data1 = *(PPH_MINIINFO_LIST_SECTION_SORT_DATA *)elem1; - PPH_MINIINFO_LIST_SECTION_SORT_DATA data2 = *(PPH_MINIINFO_LIST_SECTION_SORT_DATA *)elem2; - - return uint64cmp(data2->UserData[0] + data2->UserData[1], data1->UserData[0] + data1->UserData[1]); -} +/* + * Process Hacker - + * mini information window + * + * Copyright (C) 2015-2016 wj32 + * Copyright (C) 2017 dmex + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +static HWND PhMipContainerWindow = NULL; +static POINT PhMipSourcePoint; +static LONG PhMipPinCounts[MaxMiniInfoPinType]; +static LONG PhMipMaxPinCounts[] = +{ + 1, // MiniInfoManualPinType + 1, // MiniInfoIconPinType + 1, // MiniInfoActivePinType + 1, // MiniInfoHoverPinType + 1, // MiniInfoChildControlPinType +}; +C_ASSERT(sizeof(PhMipMaxPinCounts) / sizeof(LONG) == MaxMiniInfoPinType); +static LONG PhMipDelayedPinAdjustments[MaxMiniInfoPinType]; +static PPH_MESSAGE_LOOP_FILTER_ENTRY PhMipMessageLoopFilterEntry; +static HWND PhMipLastTrackedWindow; +static HWND PhMipLastNcTrackedWindow; +static ULONG PhMipRefreshAutomatically; +static BOOLEAN PhMipPinned; + +static HWND PhMipWindow = NULL; +static PH_LAYOUT_MANAGER PhMipLayoutManager; +static RECT MinimumSize; +static PH_CALLBACK_REGISTRATION ProcessesUpdatedRegistration; +static PH_STRINGREF DownArrowPrefix = PH_STRINGREF_INIT(L"\u25be "); + +static PPH_LIST SectionList; +static PH_MINIINFO_PARAMETERS CurrentParameters; +static PPH_MINIINFO_SECTION CurrentSection; + +VOID PhPinMiniInformation( + _In_ PH_MINIINFO_PIN_TYPE PinType, + _In_ LONG PinCount, + _In_opt_ ULONG PinDelayMs, + _In_ ULONG Flags, + _In_opt_ PWSTR SectionName, + _In_opt_ PPOINT SourcePoint + ) +{ + PH_MIP_ADJUST_PIN_RESULT adjustPinResult; + + if (PinDelayMs && PinCount < 0) + { + PhMipDelayedPinAdjustments[PinType] = PinCount; + SetTimer(PhMipContainerWindow, MIP_TIMER_PIN_FIRST + PinType, PinDelayMs, NULL); + return; + } + else + { + PhMipDelayedPinAdjustments[PinType] = 0; + KillTimer(PhMipContainerWindow, MIP_TIMER_PIN_FIRST + PinType); + } + + adjustPinResult = PhMipAdjustPin(PinType, PinCount); + + if (adjustPinResult == ShowAdjustPinResult) + { + PH_RECTANGLE windowRectangle; + ULONG opacity; + + if (SourcePoint) + PhMipSourcePoint = *SourcePoint; + + if (!PhMipContainerWindow) + { + WNDCLASSEX wcex; + + memset(&wcex, 0, sizeof(WNDCLASSEX)); + wcex.cbSize = sizeof(WNDCLASSEX); + wcex.style = 0; + wcex.lpfnWndProc = PhMipContainerWndProc; + wcex.cbClsExtra = 0; + wcex.cbWndExtra = 0; + wcex.hInstance = PhInstanceHandle; + wcex.hIcon = LoadIcon(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER)); + wcex.hCursor = LoadCursor(NULL, IDC_ARROW); + wcex.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1); + wcex.lpszClassName = MIP_CONTAINER_CLASSNAME; + wcex.hIconSm = (HICON)LoadImage(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER), IMAGE_ICON, 16, 16, 0); + RegisterClassEx(&wcex); + + PhMipContainerWindow = CreateWindow( + MIP_CONTAINER_CLASSNAME, + L"Process Hacker", + WS_BORDER | WS_THICKFRAME | WS_POPUP, + 0, + 0, + 400, + 400, + NULL, + NULL, + PhInstanceHandle, + NULL + ); + PhSetWindowExStyle(PhMipContainerWindow, WS_EX_TOOLWINDOW, WS_EX_TOOLWINDOW); + PhMipWindow = CreateDialog( + PhInstanceHandle, + MAKEINTRESOURCE(IDD_MINIINFO), + PhMipContainerWindow, + PhMipMiniInfoDialogProc + ); + ShowWindow(PhMipWindow, SW_SHOW); + + if (PhGetIntegerSetting(L"MiniInfoWindowPinned")) + PhMipSetPinned(TRUE); + + PhMipRefreshAutomatically = PhGetIntegerSetting(L"MiniInfoWindowRefreshAutomatically"); + + opacity = PhGetIntegerSetting(L"MiniInfoWindowOpacity"); + + if (opacity != 0) + PhSetWindowOpacity(PhMipContainerWindow, opacity); + + MinimumSize.left = 0; + MinimumSize.top = 0; + MinimumSize.right = 210; + MinimumSize.bottom = 60; + MapDialogRect(PhMipWindow, &MinimumSize); + } + + if (!(Flags & PH_MINIINFO_LOAD_POSITION)) + { + PhMipCalculateWindowRectangle(&PhMipSourcePoint, &windowRectangle); + SetWindowPos( + PhMipContainerWindow, + HWND_TOPMOST, + windowRectangle.Left, + windowRectangle.Top, + windowRectangle.Width, + windowRectangle.Height, + SWP_NOACTIVATE + ); + } + else + { + PhLoadWindowPlacementFromSetting(L"MiniInfoWindowPosition", L"MiniInfoWindowSize", PhMipContainerWindow); + SetWindowPos(PhMipContainerWindow, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE); + } + + ShowWindow(PhMipContainerWindow, (Flags & PH_MINIINFO_ACTIVATE_WINDOW) ? SW_SHOW : SW_SHOWNOACTIVATE); + } + else if (adjustPinResult == HideAdjustPinResult) + { + if (PhMipContainerWindow) + ShowWindow(PhMipContainerWindow, SW_HIDE); + } + else + { + if ((Flags & PH_MINIINFO_ACTIVATE_WINDOW) && IsWindowVisible(PhMipContainerWindow)) + SetActiveWindow(PhMipContainerWindow); + } + + if (Flags & PH_MINIINFO_ACTIVATE_WINDOW) + SetForegroundWindow(PhMipContainerWindow); + + if (SectionName && (!PhMipPinned || !(Flags & PH_MINIINFO_DONT_CHANGE_SECTION_IF_PINNED))) + { + PH_STRINGREF sectionName; + PPH_MINIINFO_SECTION section; + + PhInitializeStringRefLongHint(§ionName, SectionName); + + if (section = PhMipFindSection(§ionName)) + PhMipChangeSection(section); + } +} + +LRESULT CALLBACK PhMipContainerWndProc( + _In_ HWND hWnd, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + switch (uMsg) + { + case WM_SHOWWINDOW: + { + PhMipContainerOnShowWindow(!!wParam, (ULONG)lParam); + } + break; + case WM_ACTIVATE: + { + PhMipContainerOnActivate(LOWORD(wParam), !!HIWORD(wParam)); + } + break; + case WM_SIZE: + { + PhMipContainerOnSize(); + } + break; + case WM_SIZING: + { + PhMipContainerOnSizing((ULONG)wParam, (PRECT)lParam); + } + break; + case WM_EXITSIZEMOVE: + { + PhMipContainerOnExitSizeMove(); + } + break; + case WM_CLOSE: + { + // Hide, don't close. + ShowWindow(hWnd, SW_HIDE); + SetWindowLongPtr(hWnd, DWLP_MSGRESULT, 0); + } + return TRUE; + case WM_ERASEBKGND: + { + if (PhMipContainerOnEraseBkgnd((HDC)wParam)) + return TRUE; + } + break; + case WM_TIMER: + { + PhMipContainerOnTimer((ULONG)wParam); + } + break; + } + + return DefWindowProc(hWnd, uMsg, wParam, lParam); +} + +INT_PTR CALLBACK PhMipMiniInfoDialogProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + switch (uMsg) + { + case WM_INITDIALOG: + { + PhMipWindow = hwndDlg; + PhMipOnInitDialog(); + } + break; + case WM_SHOWWINDOW: + { + PhMipOnShowWindow(!!wParam, (ULONG)lParam); + } + break; + case WM_COMMAND: + { + PhMipOnCommand(LOWORD(wParam), HIWORD(wParam)); + } + break; + case WM_NOTIFY: + { + LRESULT result; + + if (PhMipOnNotify((NMHDR *)lParam, &result)) + { + SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, result); + return TRUE; + } + } + break; + case WM_CTLCOLORBTN: + case WM_CTLCOLORDLG: + case WM_CTLCOLORSTATIC: + { + HBRUSH brush; + + if (PhMipOnCtlColorXxx(uMsg, (HWND)lParam, (HDC)wParam, &brush)) + return (INT_PTR)brush; + } + break; + case WM_DRAWITEM: + { + if (PhMipOnDrawItem(wParam, (DRAWITEMSTRUCT *)lParam)) + return TRUE; + } + break; + } + + if (uMsg >= MIP_MSG_FIRST && uMsg <= MIP_MSG_LAST) + { + PhMipOnUserMessage(uMsg, wParam, lParam); + } + + return FALSE; +} + +VOID PhMipContainerOnShowWindow( + _In_ BOOLEAN Showing, + _In_ ULONG State + ) +{ + ULONG i; + PPH_MINIINFO_SECTION section; + + if (Showing) + { + PostMessage(PhMipWindow, MIP_MSG_UPDATE, 0, 0); + + PhMipMessageLoopFilterEntry = PhRegisterMessageLoopFilter(PhMipMessageLoopFilter, NULL); + + PhRegisterCallback( + &PhProcessesUpdatedEvent, + PhMipUpdateHandler, + NULL, + &ProcessesUpdatedRegistration + ); + + PhMipContainerOnSize(); + } + else + { + ULONG i; + + for (i = 0; i < MaxMiniInfoPinType; i++) + PhMipPinCounts[i] = 0; + + Button_SetCheck(GetDlgItem(PhMipWindow, IDC_PIN), BST_UNCHECKED); + PhMipSetPinned(FALSE); + PhSetIntegerSetting(L"MiniInfoWindowPinned", FALSE); + + PhUnregisterCallback( + &PhProcessesUpdatedEvent, + &ProcessesUpdatedRegistration + ); + + if (PhMipMessageLoopFilterEntry) + { + PhUnregisterMessageLoopFilter(PhMipMessageLoopFilterEntry); + PhMipMessageLoopFilterEntry = NULL; + } + + PhSaveWindowPlacementToSetting(L"MiniInfoWindowPosition", L"MiniInfoWindowSize", PhMipContainerWindow); + } + + if (SectionList) + { + for (i = 0; i < SectionList->Count; i++) + { + section = SectionList->Items[i]; + section->Callback(section, MiniInfoShowing, (PVOID)Showing, NULL); + } + } +} + +VOID PhMipContainerOnActivate( + _In_ ULONG Type, + _In_ BOOLEAN Minimized + ) +{ + if (Type == WA_ACTIVE || Type == WA_CLICKACTIVE) + { + PhPinMiniInformation(MiniInfoActivePinType, 1, 0, 0, NULL, NULL); + } + else if (Type == WA_INACTIVE) + { + PhPinMiniInformation(MiniInfoActivePinType, -1, 0, 0, NULL, NULL); + } +} + +VOID PhMipContainerOnSize( + VOID + ) +{ + if (PhMipWindow) + { + InvalidateRect(PhMipContainerWindow, NULL, FALSE); + PhMipLayout(); + } +} + +VOID PhMipContainerOnSizing( + _In_ ULONG Edge, + _In_ PRECT DragRectangle + ) +{ + PhResizingMinimumSize(DragRectangle, Edge, MinimumSize.right, MinimumSize.bottom); +} + +VOID PhMipContainerOnExitSizeMove( + VOID + ) +{ + PhSaveWindowPlacementToSetting(L"MiniInfoWindowPosition", L"MiniInfoWindowSize", PhMipContainerWindow); +} + +BOOLEAN PhMipContainerOnEraseBkgnd( + _In_ HDC hdc + ) +{ + return FALSE; +} + +VOID PhMipContainerOnTimer( + _In_ ULONG Id + ) +{ + if (Id >= MIP_TIMER_PIN_FIRST && Id <= MIP_TIMER_PIN_LAST) + { + PH_MINIINFO_PIN_TYPE pinType = Id - MIP_TIMER_PIN_FIRST; + + // PhPinMiniInformation kills the timer for us. + PhPinMiniInformation(pinType, PhMipDelayedPinAdjustments[pinType], 0, 0, NULL, NULL); + } +} + +VOID PhMipOnInitDialog( + VOID + ) +{ + HICON cog; + HICON pin; + + cog = PH_LOAD_SHARED_ICON_SMALL(MAKEINTRESOURCE(IDI_COG)); + SET_BUTTON_ICON(PhMipWindow, IDC_OPTIONS, cog); + + pin = PH_LOAD_SHARED_ICON_SMALL(MAKEINTRESOURCE(IDI_PIN)); + SET_BUTTON_ICON(PhMipWindow, IDC_PIN, pin); + + PhInitializeLayoutManager(&PhMipLayoutManager, PhMipWindow); + PhAddLayoutItem(&PhMipLayoutManager, GetDlgItem(PhMipWindow, IDC_LAYOUT), NULL, + PH_ANCHOR_ALL); + PhAddLayoutItem(&PhMipLayoutManager, GetDlgItem(PhMipWindow, IDC_SECTION), NULL, + PH_ANCHOR_LEFT | PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM | PH_LAYOUT_FORCE_INVALIDATE); + PhAddLayoutItem(&PhMipLayoutManager, GetDlgItem(PhMipWindow, IDC_OPTIONS), NULL, + PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); + PhAddLayoutItem(&PhMipLayoutManager, GetDlgItem(PhMipWindow, IDC_PIN), NULL, + PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); + + SetWindowSubclass(GetDlgItem(PhMipWindow, IDC_SECTION), PhMipSectionControlHookWndProc, 0, 0); + + Button_SetCheck(GetDlgItem(PhMipWindow, IDC_PIN), !!PhGetIntegerSetting(L"MiniInfoWindowPinned")); +} + +VOID PhMipOnShowWindow( + _In_ BOOLEAN Showing, + _In_ ULONG State + ) +{ + if (SectionList) + return; + + SectionList = PhCreateList(8); + PhMipInitializeParameters(); + + SendMessage(GetDlgItem(PhMipWindow, IDC_SECTION), WM_SETFONT, (WPARAM)CurrentParameters.MediumFont, FALSE); + + PhMipCreateInternalListSection(L"CPU", 0, PhMipCpuListSectionCallback); + PhMipCreateInternalListSection(L"Commit charge", 0, PhMipCommitListSectionCallback); + PhMipCreateInternalListSection(L"Physical memory", 0, PhMipPhysicalListSectionCallback); + PhMipCreateInternalListSection(L"I/O", 0, PhMipIoListSectionCallback); + + if (PhPluginsEnabled) + { + PH_PLUGIN_MINIINFO_POINTERS pointers; + + pointers.WindowHandle = PhMipContainerWindow; + pointers.CreateSection = PhMipCreateSection; + pointers.FindSection = PhMipFindSection; + pointers.CreateListSection = PhMipCreateListSection; + PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackMiniInformationInitializing), &pointers); + } + + PhMipChangeSection(SectionList->Items[0]); +} + +VOID PhMipOnCommand( + _In_ ULONG Id, + _In_ ULONG Code + ) +{ + switch (Id) + { + case IDC_SECTION: + switch (Code) + { + case STN_CLICKED: + PhMipShowSectionMenu(); + break; + } + break; + case IDC_OPTIONS: + PhMipShowOptionsMenu(); + break; + case IDC_PIN: + { + BOOLEAN pinned; + + pinned = Button_GetCheck(GetDlgItem(PhMipWindow, IDC_PIN)) == BST_CHECKED; + PhPinMiniInformation(MiniInfoManualPinType, pinned ? 1 : -1, 0, 0, NULL, NULL); + PhMipSetPinned(pinned); + PhSetIntegerSetting(L"MiniInfoWindowPinned", pinned); + } + break; + } +} + +BOOLEAN PhMipOnNotify( + _In_ NMHDR *Header, + _Out_ LRESULT *Result + ) +{ + return FALSE; +} + +BOOLEAN PhMipOnCtlColorXxx( + _In_ ULONG Message, + _In_ HWND hwnd, + _In_ HDC hdc, + _Out_ HBRUSH *Brush + ) +{ + return FALSE; +} + +BOOLEAN PhMipOnDrawItem( + _In_ ULONG_PTR Id, + _In_ DRAWITEMSTRUCT *DrawItemStruct + ) +{ + return FALSE; +} + +VOID PhMipOnUserMessage( + _In_ ULONG Message, + _In_ ULONG_PTR WParam, + _In_ ULONG_PTR LParam + ) +{ + switch (Message) + { + case MIP_MSG_UPDATE: + { + ULONG i; + PPH_MINIINFO_SECTION section; + + if (SectionList) + { + for (i = 0; i < SectionList->Count; i++) + { + section = SectionList->Items[i]; + section->Callback(section, MiniInfoTick, NULL, NULL); + } + } + } + break; + } +} + +BOOLEAN PhMipMessageLoopFilter( + _In_ PMSG Message, + _In_ PVOID Context + ) +{ + if (Message->hwnd == PhMipContainerWindow || IsChild(PhMipContainerWindow, Message->hwnd)) + { + if (Message->message == WM_MOUSEMOVE || Message->message == WM_NCMOUSEMOVE) + { + TRACKMOUSEEVENT trackMouseEvent; + + trackMouseEvent.cbSize = sizeof(TRACKMOUSEEVENT); + trackMouseEvent.dwFlags = TME_LEAVE | (Message->message == WM_NCMOUSEMOVE ? TME_NONCLIENT : 0); + trackMouseEvent.hwndTrack = Message->hwnd; + trackMouseEvent.dwHoverTime = 0; + TrackMouseEvent(&trackMouseEvent); + + if (Message->message == WM_MOUSEMOVE) + PhMipLastTrackedWindow = Message->hwnd; + else + PhMipLastNcTrackedWindow = Message->hwnd; + + PhPinMiniInformation(MiniInfoHoverPinType, 1, 0, 0, NULL, NULL); + } + else if (Message->message == WM_MOUSELEAVE && Message->hwnd == PhMipLastTrackedWindow) + { + PhPinMiniInformation(MiniInfoHoverPinType, -1, MIP_UNPIN_HOVER_DELAY, 0, NULL, NULL); + } + else if (Message->message == WM_NCMOUSELEAVE && Message->hwnd == PhMipLastNcTrackedWindow) + { + PhPinMiniInformation(MiniInfoHoverPinType, -1, MIP_UNPIN_HOVER_DELAY, 0, NULL, NULL); + } + else if (Message->message == WM_KEYDOWN) + { + switch (Message->wParam) + { + case VK_F5: + PhMipRefresh(); + break; + case VK_F6: + case VK_PAUSE: + PhMipToggleRefreshAutomatically(); + break; + } + } + } + + return FALSE; +} + +VOID NTAPI PhMipUpdateHandler( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + if (PhMipRefreshAutomatically & MIP_REFRESH_AUTOMATICALLY_FLAG(PhMipPinned)) + PostMessage(PhMipWindow, MIP_MSG_UPDATE, 0, 0); +} + +PH_MIP_ADJUST_PIN_RESULT PhMipAdjustPin( + _In_ PH_MINIINFO_PIN_TYPE PinType, + _In_ LONG PinCount + ) +{ + LONG oldTotalPinCount; + LONG oldPinCount; + LONG newPinCount; + ULONG i; + + oldTotalPinCount = 0; + + for (i = 0; i < MaxMiniInfoPinType; i++) + oldTotalPinCount += PhMipPinCounts[i]; + + oldPinCount = PhMipPinCounts[PinType]; + newPinCount = max(oldPinCount + PinCount, 0); + newPinCount = min(newPinCount, PhMipMaxPinCounts[PinType]); + PhMipPinCounts[PinType] = newPinCount; + + if (oldTotalPinCount == 0 && newPinCount > oldPinCount) + return ShowAdjustPinResult; + else if (oldTotalPinCount > 0 && oldTotalPinCount - oldPinCount + newPinCount == 0) + return HideAdjustPinResult; + else + return NoAdjustPinResult; +} + +VOID PhMipCalculateWindowRectangle( + _In_ PPOINT SourcePoint, + _Out_ PPH_RECTANGLE WindowRectangle + ) +{ + RECT windowRect; + PH_RECTANGLE windowRectangle; + PH_RECTANGLE point; + MONITORINFO monitorInfo = { sizeof(monitorInfo) }; + + PhLoadWindowPlacementFromSetting(NULL, L"MiniInfoWindowSize", PhMipContainerWindow); + GetWindowRect(PhMipContainerWindow, &windowRect); + SendMessage(PhMipContainerWindow, WM_SIZING, WMSZ_BOTTOMRIGHT, (LPARAM)&windowRect); // Adjust for the minimum size. + windowRectangle = PhRectToRectangle(windowRect); + + point.Left = SourcePoint->x; + point.Top = SourcePoint->y; + point.Width = 0; + point.Height = 0; + PhCenterRectangle(&windowRectangle, &point); + + if (GetMonitorInfo( + MonitorFromPoint(*SourcePoint, MONITOR_DEFAULTTOPRIMARY), + &monitorInfo + )) + { + PH_RECTANGLE bounds; + + if (memcmp(&monitorInfo.rcWork, &monitorInfo.rcMonitor, sizeof(RECT)) == 0) + { + HWND trayWindow; + RECT taskbarRect; + + // The taskbar probably has auto-hide enabled. We need to adjust for that. + if ((trayWindow = FindWindow(L"Shell_TrayWnd", NULL)) && + GetMonitorInfo(MonitorFromWindow(trayWindow, MONITOR_DEFAULTTOPRIMARY), &monitorInfo) && // Just in case + GetWindowRect(trayWindow, &taskbarRect)) + { + LONG monitorMidX = (monitorInfo.rcMonitor.left + monitorInfo.rcMonitor.right) / 2; + LONG monitorMidY = (monitorInfo.rcMonitor.top + monitorInfo.rcMonitor.bottom) / 2; + + if (taskbarRect.right < monitorMidX) + { + // Left + monitorInfo.rcWork.left += taskbarRect.right - taskbarRect.left; + } + else if (taskbarRect.bottom < monitorMidY) + { + // Top + monitorInfo.rcWork.top += taskbarRect.bottom - taskbarRect.top; + } + else if (taskbarRect.left > monitorMidX) + { + // Right + monitorInfo.rcWork.right -= taskbarRect.right - taskbarRect.left; + } + else if (taskbarRect.top > monitorMidY) + { + // Bottom + monitorInfo.rcWork.bottom -= taskbarRect.bottom - taskbarRect.top; + } + } + } + + bounds = PhRectToRectangle(monitorInfo.rcWork); + + PhAdjustRectangleToBounds(&windowRectangle, &bounds); + } + + *WindowRectangle = windowRectangle; +} + +VOID PhMipInitializeParameters( + VOID + ) +{ + LOGFONT logFont; + HDC hdc; + TEXTMETRIC textMetrics; + HFONT originalFont; + + memset(&CurrentParameters, 0, sizeof(PH_MINIINFO_PARAMETERS)); + + CurrentParameters.ContainerWindowHandle = PhMipContainerWindow; + CurrentParameters.MiniInfoWindowHandle = PhMipWindow; + + if (SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(LOGFONT), &logFont, 0)) + { + CurrentParameters.Font = CreateFontIndirect(&logFont); + } + else + { + CurrentParameters.Font = PhApplicationFont; + GetObject(PhApplicationFont, sizeof(LOGFONT), &logFont); + } + + hdc = GetDC(PhMipWindow); + + logFont.lfHeight -= PhMultiplyDivide(2, GetDeviceCaps(hdc, LOGPIXELSY), 72); + CurrentParameters.MediumFont = CreateFontIndirect(&logFont); + + originalFont = SelectObject(hdc, CurrentParameters.Font); + GetTextMetrics(hdc, &textMetrics); + CurrentParameters.FontHeight = textMetrics.tmHeight; + CurrentParameters.FontAverageWidth = textMetrics.tmAveCharWidth; + + SelectObject(hdc, CurrentParameters.MediumFont); + GetTextMetrics(hdc, &textMetrics); + CurrentParameters.MediumFontHeight = textMetrics.tmHeight; + CurrentParameters.MediumFontAverageWidth = textMetrics.tmAveCharWidth; + + CurrentParameters.SetSectionText = PhMipSetSectionText; + + SelectObject(hdc, originalFont); + ReleaseDC(PhMipWindow, hdc); +} + +PPH_MINIINFO_SECTION PhMipCreateSection( + _In_ PPH_MINIINFO_SECTION Template + ) +{ + PPH_MINIINFO_SECTION section; + + section = PhAllocate(sizeof(PH_MINIINFO_SECTION)); + memset(section, 0, sizeof(PH_MINIINFO_SECTION)); + + section->Name = Template->Name; + section->Flags = Template->Flags; + section->Callback = Template->Callback; + section->Context = Template->Context; + section->Parameters = &CurrentParameters; + + PhAddItemList(SectionList, section); + + section->Callback(section, MiniInfoCreate, NULL, NULL); + + return section; +} + +VOID PhMipDestroySection( + _In_ PPH_MINIINFO_SECTION Section + ) +{ + Section->Callback(Section, MiniInfoDestroy, NULL, NULL); + + PhClearReference(&Section->Text); + PhFree(Section); +} + +PPH_MINIINFO_SECTION PhMipFindSection( + _In_ PPH_STRINGREF Name + ) +{ + ULONG i; + PPH_MINIINFO_SECTION section; + + for (i = 0; i < SectionList->Count; i++) + { + section = SectionList->Items[i]; + + if (PhEqualStringRef(§ion->Name, Name, TRUE)) + return section; + } + + return NULL; +} + +PPH_MINIINFO_SECTION PhMipCreateInternalSection( + _In_ PWSTR Name, + _In_ ULONG Flags, + _In_ PPH_MINIINFO_SECTION_CALLBACK Callback + ) +{ + PH_MINIINFO_SECTION section; + + memset(§ion, 0, sizeof(PH_MINIINFO_SECTION)); + PhInitializeStringRef(§ion.Name, Name); + section.Flags = Flags; + section.Callback = Callback; + + return PhMipCreateSection(§ion); +} + +VOID PhMipCreateSectionDialog( + _In_ PPH_MINIINFO_SECTION Section + ) +{ + PH_MINIINFO_CREATE_DIALOG createDialog; + + memset(&createDialog, 0, sizeof(PH_MINIINFO_CREATE_DIALOG)); + + if (Section->Callback(Section, MiniInfoCreateDialog, &createDialog, NULL)) + { + if (!createDialog.CustomCreate) + { + Section->DialogHandle = PhCreateDialogFromTemplate( + PhMipWindow, + DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD, + createDialog.Instance, + createDialog.Template, + createDialog.DialogProc, + createDialog.Parameter + ); + } + } +} + +VOID PhMipChangeSection( + _In_ PPH_MINIINFO_SECTION NewSection + ) +{ + PPH_MINIINFO_SECTION oldSection; + + if (NewSection == CurrentSection) + return; + + oldSection = CurrentSection; + CurrentSection = NewSection; + + if (oldSection) + { + oldSection->Callback(oldSection, MiniInfoSectionChanging, CurrentSection, NULL); + + if (oldSection->DialogHandle) + ShowWindow(oldSection->DialogHandle, SW_HIDE); + } + + if (!NewSection->DialogHandle) + PhMipCreateSectionDialog(NewSection); + if (NewSection->DialogHandle) + ShowWindow(NewSection->DialogHandle, SW_SHOW); + + PhMipUpdateSectionText(NewSection); + PhMipLayout(); + + NewSection->Callback(NewSection, MiniInfoTick, NULL, NULL); +} + +VOID PhMipSetSectionText( + _In_ struct _PH_MINIINFO_SECTION *Section, + _In_opt_ PPH_STRING Text + ) +{ + PhSwapReference(&Section->Text, Text); + + if (Section == CurrentSection) + PhMipUpdateSectionText(Section); +} + +VOID PhMipUpdateSectionText( + _In_ PPH_MINIINFO_SECTION Section + ) +{ + if (Section->Text) + { + SetDlgItemText(PhMipWindow, IDC_SECTION, + PH_AUTO_T(PH_STRING, PhConcatStringRef2(&DownArrowPrefix, &Section->Text->sr))->Buffer); + } + else + { + SetDlgItemText(PhMipWindow, IDC_SECTION, + PH_AUTO_T(PH_STRING, PhConcatStringRef2(&DownArrowPrefix, &Section->Name))->Buffer); + } +} + +VOID PhMipLayout( + VOID + ) +{ + RECT clientRect; + RECT rect; + + GetClientRect(PhMipContainerWindow, &clientRect); + MoveWindow( + PhMipWindow, + clientRect.left, clientRect.top, + clientRect.right - clientRect.left, clientRect.bottom - clientRect.top, + FALSE + ); + + PhLayoutManagerLayout(&PhMipLayoutManager); + + GetWindowRect(GetDlgItem(PhMipWindow, IDC_LAYOUT), &rect); + MapWindowPoints(NULL, PhMipWindow, (POINT *)&rect, 2); + + if (CurrentSection && CurrentSection->DialogHandle) + { + if (CurrentSection->Flags & PH_MINIINFO_SECTION_NO_UPPER_MARGINS) + { + rect.left = 0; + rect.top = 0; + rect.right = clientRect.right; + } + else + { + LONG leftDistance = rect.left - clientRect.left; + LONG rightDistance = clientRect.right - rect.right; + LONG minDistance; + + if (leftDistance != rightDistance) + { + // HACK: Enforce symmetry. Sometimes these are off by a pixel. + minDistance = min(leftDistance, rightDistance); + rect.left = clientRect.left + minDistance; + rect.right = clientRect.right - minDistance; + } + } + + MoveWindow( + CurrentSection->DialogHandle, + rect.left, rect.top, + rect.right - rect.left, rect.bottom - rect.top, + TRUE + ); + } + + GetWindowRect(GetDlgItem(PhMipWindow, IDC_PIN), &rect); + MapWindowPoints(NULL, PhMipWindow, (POINT *)&rect, 2); +} + +VOID PhMipBeginChildControlPin( + VOID + ) +{ + PhPinMiniInformation(MiniInfoChildControlPinType, 1, 0, 0, NULL, NULL); +} + +VOID PhMipEndChildControlPin( + VOID + ) +{ + PhPinMiniInformation(MiniInfoChildControlPinType, -1, MIP_UNPIN_CHILD_CONTROL_DELAY, 0, NULL, NULL); + PostMessage(PhMipWindow, WM_MOUSEMOVE, 0, 0); // Re-evaluate hover pin +} + +VOID PhMipRefresh( + VOID + ) +{ + if (PhMipPinned) + ProcessHacker_Refresh(PhMainWndHandle); + + PostMessage(PhMipWindow, MIP_MSG_UPDATE, 0, 0); +} + +VOID PhMipToggleRefreshAutomatically( + VOID + ) +{ + PhMipRefreshAutomatically ^= MIP_REFRESH_AUTOMATICALLY_FLAG(PhMipPinned); + PhSetIntegerSetting(L"MiniInfoWindowRefreshAutomatically", PhMipRefreshAutomatically); +} + +VOID PhMipSetPinned( + _In_ BOOLEAN Pinned + ) +{ + PhSetWindowStyle(PhMipContainerWindow, WS_DLGFRAME | WS_SYSMENU, Pinned ? (WS_DLGFRAME | WS_SYSMENU) : 0); + SetWindowPos(PhMipContainerWindow, NULL, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED); + PhMipPinned = Pinned; + + PhNfNotifyMiniInfoPinned(Pinned); +} + +VOID PhMipShowSectionMenu( + VOID + ) +{ + PPH_EMENU menu; + ULONG i; + PPH_MINIINFO_SECTION section; + PPH_EMENU_ITEM menuItem; + POINT point; + + PhMipBeginChildControlPin(); + menu = PhCreateEMenu(); + + for (i = 0; i < SectionList->Count; i++) + { + section = SectionList->Items[i]; + menuItem = PhCreateEMenuItem( + (section == CurrentSection ? (PH_EMENU_CHECKED | PH_EMENU_RADIOCHECK) : 0), + 0, + PH_AUTO_T(PH_STRING, PhCreateString2(§ion->Name))->Buffer, + NULL, + section + ); + PhInsertEMenuItem(menu, menuItem, -1); + } + + GetCursorPos(&point); + menuItem = PhShowEMenu(menu, PhMipWindow, PH_EMENU_SHOW_LEFTRIGHT, + PH_ALIGN_LEFT | PH_ALIGN_TOP, point.x, point.y); + + if (menuItem) + { + PhMipChangeSection(menuItem->Context); + } + + PhDestroyEMenu(menu); + PhMipEndChildControlPin(); +} + +VOID PhMipShowOptionsMenu( + VOID + ) +{ + PPH_EMENU menu; + PPH_EMENU_ITEM menuItem; + ULONG id; + RECT rect; + + PhMipBeginChildControlPin(); + menu = PhCreateEMenu(); + PhLoadResourceEMenuItem(menu, PhInstanceHandle, MAKEINTRESOURCE(IDR_MINIINFO), 0); + + // Opacity + + id = PH_OPACITY_TO_ID(PhGetIntegerSetting(L"MiniInfoWindowOpacity")); + + if (menuItem = PhFindEMenuItem(menu, PH_EMENU_FIND_DESCEND, NULL, id)) + menuItem->Flags |= PH_EMENU_CHECKED | PH_EMENU_RADIOCHECK; + + // Refresh Automatically + + if (PhMipRefreshAutomatically & MIP_REFRESH_AUTOMATICALLY_FLAG(PhMipPinned)) + PhSetFlagsEMenuItem(menu, ID_MINIINFO_REFRESHAUTOMATICALLY, PH_EMENU_CHECKED, PH_EMENU_CHECKED); + + // Show the menu. + + GetWindowRect(GetDlgItem(PhMipWindow, IDC_OPTIONS), &rect); + menuItem = PhShowEMenu(menu, PhMipWindow, PH_EMENU_SHOW_LEFTRIGHT, + PH_ALIGN_LEFT | PH_ALIGN_BOTTOM, rect.left, rect.top); + + if (menuItem) + { + switch (menuItem->Id) + { + case ID_OPACITY_10: + case ID_OPACITY_20: + case ID_OPACITY_30: + case ID_OPACITY_40: + case ID_OPACITY_50: + case ID_OPACITY_60: + case ID_OPACITY_70: + case ID_OPACITY_80: + case ID_OPACITY_90: + case ID_OPACITY_OPAQUE: + { + ULONG opacity; + + opacity = PH_ID_TO_OPACITY(menuItem->Id); + PhSetIntegerSetting(L"MiniInfoWindowOpacity", opacity); + PhSetWindowOpacity(PhMipContainerWindow, opacity); + } + break; + case ID_MINIINFO_REFRESH: + PhMipRefresh(); + break; + case ID_MINIINFO_REFRESHAUTOMATICALLY: + PhMipToggleRefreshAutomatically(); + break; + } + } + + PhDestroyEMenu(menu); + PhMipEndChildControlPin(); +} + +LRESULT CALLBACK PhMipSectionControlHookWndProc( + _In_ HWND hwnd, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam, + _In_ UINT_PTR uIdSubclass, + _In_ ULONG_PTR dwRefData + ) +{ + switch (uMsg) + { + case WM_DESTROY: + RemoveWindowSubclass(hwnd, PhMipSectionControlHookWndProc, uIdSubclass); + break; + case WM_SETCURSOR: + { + SetCursor(LoadCursor(NULL, IDC_HAND)); + } + return TRUE; + } + + return DefSubclassProc(hwnd, uMsg, wParam, lParam); +} + +PPH_MINIINFO_LIST_SECTION PhMipCreateListSection( + _In_ PWSTR Name, + _In_ ULONG Flags, + _In_ PPH_MINIINFO_LIST_SECTION Template + ) +{ + PPH_MINIINFO_LIST_SECTION listSection; + PH_MINIINFO_SECTION section; + + listSection = PhAllocate(sizeof(PH_MINIINFO_LIST_SECTION)); + memset(listSection, 0, sizeof(PH_MINIINFO_LIST_SECTION)); + + listSection->Context = Template->Context; + listSection->Callback = Template->Callback; + + memset(§ion, 0, sizeof(PH_MINIINFO_SECTION)); + PhInitializeStringRef(§ion.Name, Name); + section.Flags = PH_MINIINFO_SECTION_NO_UPPER_MARGINS; + section.Callback = PhMipListSectionCallback; + section.Context = listSection; + listSection->Section = PhMipCreateSection(§ion); + + return listSection; +} + +PPH_MINIINFO_LIST_SECTION PhMipCreateInternalListSection( + _In_ PWSTR Name, + _In_ ULONG Flags, + _In_ PPH_MINIINFO_LIST_SECTION_CALLBACK Callback + ) +{ + PH_MINIINFO_LIST_SECTION listSection; + + memset(&listSection, 0, sizeof(PH_MINIINFO_LIST_SECTION)); + listSection.Callback = Callback; + + return PhMipCreateListSection(Name, Flags, &listSection); +} + +BOOLEAN PhMipListSectionCallback( + _In_ PPH_MINIINFO_SECTION Section, + _In_ PH_MINIINFO_SECTION_MESSAGE Message, + _In_opt_ PVOID Parameter1, + _In_opt_ PVOID Parameter2 + ) +{ + PPH_MINIINFO_LIST_SECTION listSection = Section->Context; + + switch (Message) + { + case MiniInfoCreate: + { + listSection->NodeList = PhCreateList(2); + listSection->Callback(listSection, MiListSectionCreate, NULL, NULL); + } + break; + case MiniInfoDestroy: + { + listSection->Callback(listSection, MiListSectionDestroy, NULL, NULL); + + PhMipClearListSection(listSection); + PhDereferenceObject(listSection->NodeList); + PhFree(listSection); + } + break; + case MiniInfoTick: + if (listSection->SuspendUpdate == 0) + PhMipTickListSection(listSection); + break; + case MiniInfoShowing: + { + listSection->Callback(listSection, MiListSectionShowing, Parameter1, Parameter2); + + if (!Parameter1) // Showing + { + // We don't want to hold process item references while the mini info window + // is hidden. + PhMipClearListSection(listSection); + TreeNew_NodesStructured(listSection->TreeNewHandle); + } + } + break; + case MiniInfoCreateDialog: + { + PPH_MINIINFO_CREATE_DIALOG createDialog = Parameter1; + + createDialog->Instance = PhInstanceHandle; + createDialog->Template = MAKEINTRESOURCE(IDD_MINIINFO_LIST); + createDialog->DialogProc = PhMipListSectionDialogProc; + createDialog->Parameter = listSection; + } + return TRUE; + } + + return FALSE; +} + +INT_PTR CALLBACK PhMipListSectionDialogProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + PPH_MINIINFO_LIST_SECTION listSection = (PPH_MINIINFO_LIST_SECTION)GetProp(hwndDlg, PhMakeContextAtom()); + + switch (uMsg) + { + case WM_INITDIALOG: + { + PPH_LAYOUT_ITEM layoutItem; + + listSection = (PPH_MINIINFO_LIST_SECTION)lParam; + SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)listSection); + + listSection->DialogHandle = hwndDlg; + listSection->TreeNewHandle = GetDlgItem(hwndDlg, IDC_LIST); + + PhInitializeLayoutManager(&listSection->LayoutManager, hwndDlg); + layoutItem = PhAddLayoutItem(&listSection->LayoutManager, listSection->TreeNewHandle, NULL, PH_ANCHOR_ALL); + + // Use negative margins to maximize our use of the window area. + layoutItem->Margin.left = -1; + layoutItem->Margin.top = -1; + layoutItem->Margin.right = -1; + + PhSetControlTheme(listSection->TreeNewHandle, L"explorer"); + TreeNew_SetCallback(listSection->TreeNewHandle, PhMipListSectionTreeNewCallback, listSection); + TreeNew_SetRowHeight(listSection->TreeNewHandle, PhMipCalculateRowHeight()); + PhAddTreeNewColumnEx2(listSection->TreeNewHandle, MIP_SINGLE_COLUMN_ID, TRUE, L"Process", 1, + PH_ALIGN_LEFT, 0, 0, TN_COLUMN_FLAG_CUSTOMDRAW); + + listSection->Callback(listSection, MiListSectionDialogCreated, hwndDlg, NULL); + PhMipTickListSection(listSection); + } + break; + case WM_DESTROY: + { + PhDeleteLayoutManager(&listSection->LayoutManager); + RemoveProp(hwndDlg, PhMakeContextAtom()); + } + break; + case WM_SIZE: + { + PhLayoutManagerLayout(&listSection->LayoutManager); + TreeNew_AutoSizeColumn(listSection->TreeNewHandle, MIP_SINGLE_COLUMN_ID, TN_AUTOSIZE_REMAINING_SPACE); + } + break; + } + + return FALSE; +} + +VOID PhMipListSectionSortFunction( + _In_ PPH_LIST List, + _In_opt_ PVOID Context + ) +{ + PPH_MINIINFO_LIST_SECTION listSection = Context; + PH_MINIINFO_LIST_SECTION_SORT_LIST sortList; + + sortList.List = List; + listSection->Callback(listSection, MiListSectionSortProcessList, &sortList, NULL); +} + +VOID PhMipTickListSection( + _In_ PPH_MINIINFO_LIST_SECTION ListSection + ) +{ + ULONG i; + PPH_MIP_GROUP_NODE node; + PH_MINIINFO_LIST_SECTION_ASSIGN_SORT_DATA assignSortData; + + PhMipClearListSection(ListSection); + + ListSection->ProcessGroupList = PhCreateProcessGroupList( + PhMipListSectionSortFunction, + ListSection, + MIP_MAX_PROCESS_GROUPS, + 0 + ); + + if (!ListSection->ProcessGroupList) + return; + + for (i = 0; i < ListSection->ProcessGroupList->Count; i++) + { + node = PhMipAddGroupNode(ListSection, ListSection->ProcessGroupList->Items[i]); + + if (node->RepresentativeProcessId == ListSection->SelectedRepresentativeProcessId && + node->RepresentativeCreateTime.QuadPart == ListSection->SelectedRepresentativeCreateTime.QuadPart) + { + node->Node.Selected = TRUE; + } + + assignSortData.ProcessGroup = node->ProcessGroup; + assignSortData.SortData = &node->SortData; + ListSection->Callback(ListSection, MiListSectionAssignSortData, &assignSortData, NULL); + } + + TreeNew_NodesStructured(ListSection->TreeNewHandle); + TreeNew_AutoSizeColumn(ListSection->TreeNewHandle, MIP_SINGLE_COLUMN_ID, TN_AUTOSIZE_REMAINING_SPACE); + + ListSection->Callback(ListSection, MiListSectionTick, NULL, NULL); +} + +VOID PhMipClearListSection( + _In_ PPH_MINIINFO_LIST_SECTION ListSection + ) +{ + ULONG i; + + if (ListSection->ProcessGroupList) + { + PhFreeProcessGroupList(ListSection->ProcessGroupList); + ListSection->ProcessGroupList = NULL; + } + + for (i = 0; i < ListSection->NodeList->Count; i++) + PhMipDestroyGroupNode(ListSection->NodeList->Items[i]); + + PhClearList(ListSection->NodeList); +} + +LONG PhMipCalculateRowHeight( + VOID + ) +{ + LONG iconHeight; + LONG titleAndSubtitleHeight; + + iconHeight = MIP_ICON_PADDING + PhLargeIconSize.Y + MIP_CELL_PADDING; + titleAndSubtitleHeight = + MIP_CELL_PADDING * 2 + CurrentParameters.FontHeight + MIP_INNER_PADDING + CurrentParameters.FontHeight; + + return max(iconHeight, titleAndSubtitleHeight); +} + +PPH_MIP_GROUP_NODE PhMipAddGroupNode( + _In_ PPH_MINIINFO_LIST_SECTION ListSection, + _In_ PPH_PROCESS_GROUP ProcessGroup + ) +{ + // This is an undocumented function exported by user32.dll that + // retrieves the hung window represented by a ghost window. + static HWND (WINAPI *HungWindowFromGhostWindow_I)( + _In_ HWND hWnd + ); + + PPH_MIP_GROUP_NODE node; + + node = PhAllocate(sizeof(PH_MIP_GROUP_NODE)); + memset(node, 0, sizeof(PH_MIP_GROUP_NODE)); + + PhInitializeTreeNewNode(&node->Node); + node->ProcessGroup = ProcessGroup; + node->RepresentativeProcessId = ProcessGroup->Representative->ProcessId; + node->RepresentativeCreateTime = ProcessGroup->Representative->CreateTime; + node->RepresentativeIsHung = ProcessGroup->WindowHandle && IsHungAppWindow(ProcessGroup->WindowHandle); + + if (node->RepresentativeIsHung) + { + if (!HungWindowFromGhostWindow_I) + HungWindowFromGhostWindow_I = PhGetModuleProcAddress(L"user32.dll", "HungWindowFromGhostWindow"); + + // Make sure this is a real hung window, not a ghost window. + if (HungWindowFromGhostWindow_I && HungWindowFromGhostWindow_I(ProcessGroup->WindowHandle)) + node->RepresentativeIsHung = FALSE; + } + + PhAddItemList(ListSection->NodeList, node); + + return node; +} + +VOID PhMipDestroyGroupNode( + _In_ PPH_MIP_GROUP_NODE Node + ) +{ + PhClearReference(&Node->TooltipText); + PhFree(Node); +} + +BOOLEAN PhMipListSectionTreeNewCallback( + _In_ HWND hwnd, + _In_ PH_TREENEW_MESSAGE Message, + _In_opt_ PVOID Parameter1, + _In_opt_ PVOID Parameter2, + _In_opt_ PVOID Context + ) +{ + PPH_MINIINFO_LIST_SECTION listSection = Context; + + switch (Message) + { + case TreeNewGetChildren: + { + PPH_TREENEW_GET_CHILDREN getChildren = Parameter1; + PH_MINIINFO_LIST_SECTION_SORT_LIST sortList; + + if (!getChildren->Node) + { + getChildren->Children = (PPH_TREENEW_NODE *)listSection->NodeList->Items; + getChildren->NumberOfChildren = listSection->NodeList->Count; + + sortList.List = listSection->NodeList; + listSection->Callback(listSection, MiListSectionSortGroupList, &sortList, NULL); + } + } + return TRUE; + case TreeNewIsLeaf: + { + PPH_TREENEW_IS_LEAF isLeaf = Parameter1; + isLeaf->IsLeaf = TRUE; + } + return TRUE; + case TreeNewCustomDraw: + { + PPH_TREENEW_CUSTOM_DRAW customDraw = Parameter1; + PPH_MIP_GROUP_NODE node = (PPH_MIP_GROUP_NODE)customDraw->Node; + PPH_PROCESS_ITEM processItem = node->ProcessGroup->Representative; + HDC hdc = customDraw->Dc; + RECT rect = customDraw->CellRect; + ULONG baseTextFlags = DT_NOPREFIX | DT_VCENTER | DT_SINGLELINE; + HICON icon; + COLORREF originalTextColor; + RECT topRect; + RECT bottomRect; + PH_MINIINFO_LIST_SECTION_GET_USAGE_TEXT getUsageText; + ULONG usageTextTopWidth = 0; + ULONG usageTextBottomWidth = 0; + PH_MINIINFO_LIST_SECTION_GET_TITLE_TEXT getTitleText; + + rect.left += MIP_ICON_PADDING; + rect.top += MIP_ICON_PADDING; + rect.right -= MIP_CELL_PADDING; + rect.bottom -= MIP_CELL_PADDING; + + if (processItem->LargeIcon) + icon = processItem->LargeIcon; + else + PhGetStockApplicationIcon(NULL, &icon); + + DrawIconEx(hdc, rect.left, rect.top, icon, PhLargeIconSize.X, PhLargeIconSize.Y, + 0, NULL, DI_NORMAL); + rect.left += (MIP_CELL_PADDING - MIP_ICON_PADDING) + PhLargeIconSize.X + MIP_CELL_PADDING; + rect.top += MIP_CELL_PADDING - MIP_ICON_PADDING; + SelectObject(hdc, CurrentParameters.Font); + + // This color changes depending on whether the node is selected, etc. + originalTextColor = GetTextColor(hdc); + + // Usage text + + topRect = rect; + topRect.bottom = topRect.top + CurrentParameters.FontHeight; + bottomRect = rect; + bottomRect.top = bottomRect.bottom - CurrentParameters.FontHeight; + + getUsageText.ProcessGroup = node->ProcessGroup; + getUsageText.SortData = &node->SortData; + getUsageText.Line1 = NULL; + getUsageText.Line2 = NULL; + getUsageText.Line1Color = originalTextColor; + getUsageText.Line2Color = originalTextColor; + + if (listSection->Callback(listSection, MiListSectionGetUsageText, &getUsageText, NULL)) + { + PH_STRINGREF text; + RECT textRect; + SIZE textSize; + + // Top + text = PhGetStringRef(getUsageText.Line1); + GetTextExtentPoint32(hdc, text.Buffer, (ULONG)text.Length / 2, &textSize); + usageTextTopWidth = textSize.cx; + textRect = topRect; + textRect.left = textRect.right - textSize.cx; + SetTextColor(hdc, getUsageText.Line1Color); + DrawText(hdc, text.Buffer, (ULONG)text.Length / 2, &textRect, baseTextFlags | DT_RIGHT); + PhClearReference(&getUsageText.Line1); + + // Bottom + text = PhGetStringRef(getUsageText.Line2); + GetTextExtentPoint32(hdc, text.Buffer, (ULONG)text.Length / 2, &textSize); + usageTextBottomWidth = textSize.cx; + textRect = bottomRect; + textRect.left = textRect.right - textSize.cx; + SetTextColor(hdc, getUsageText.Line2Color); + DrawText(hdc, text.Buffer, (ULONG)text.Length / 2, &textRect, baseTextFlags | DT_RIGHT); + PhClearReference(&getUsageText.Line2); + } + + // Title, subtitle + + getTitleText.ProcessGroup = node->ProcessGroup; + getTitleText.SortData = &node->SortData; + + if (!PhIsNullOrEmptyString(processItem->VersionInfo.FileDescription)) + PhSetReference(&getTitleText.Title, processItem->VersionInfo.FileDescription); + else + PhSetReference(&getTitleText.Title, processItem->ProcessName); + + if (node->ProcessGroup->Processes->Count == 1) + { + PhSetReference(&getTitleText.Subtitle, processItem->ProcessName); + } + else + { + getTitleText.Subtitle = PhFormatString( + L"%s (%u processes)", + processItem->ProcessName->Buffer, + node->ProcessGroup->Processes->Count + ); + } + + getTitleText.TitleColor = originalTextColor; + getTitleText.SubtitleColor = GetSysColor(COLOR_GRAYTEXT); + + // Special text for hung windows + if (node->RepresentativeIsHung) + { + static PH_STRINGREF hungPrefix = PH_STRINGREF_INIT(L"(Not responding) "); + + PhMoveReference(&getTitleText.Title, PhConcatStringRef2(&hungPrefix, &getTitleText.Title->sr)); + getTitleText.TitleColor = RGB(0xff, 0x00, 0x00); + } + + listSection->Callback(listSection, MiListSectionGetTitleText, &getTitleText, NULL); + + if (!PhIsNullOrEmptyString(getTitleText.Title)) + { + RECT textRect; + + textRect = topRect; + textRect.right -= usageTextTopWidth + MIP_INNER_PADDING; + SetTextColor(hdc, getTitleText.TitleColor); + DrawText( + hdc, + getTitleText.Title->Buffer, + (ULONG)getTitleText.Title->Length / 2, + &textRect, + baseTextFlags | DT_END_ELLIPSIS + ); + } + + if (!PhIsNullOrEmptyString(getTitleText.Subtitle)) + { + RECT textRect; + + textRect = bottomRect; + textRect.right -= usageTextBottomWidth + MIP_INNER_PADDING; + SetTextColor(hdc, getTitleText.SubtitleColor); + DrawText( + hdc, + getTitleText.Subtitle->Buffer, + (ULONG)getTitleText.Subtitle->Length / 2, + &textRect, + baseTextFlags | DT_END_ELLIPSIS + ); + } + + PhClearReference(&getTitleText.Title); + PhClearReference(&getTitleText.Subtitle); + } + return TRUE; + case TreeNewGetCellTooltip: + { + PPH_TREENEW_GET_CELL_TOOLTIP getCellTooltip = Parameter1; + PPH_MIP_GROUP_NODE node = (PPH_MIP_GROUP_NODE)getCellTooltip->Node; + ULONG tickCount; + + tickCount = GetTickCount(); + + // This is useless most of the time because the tooltip doesn't display unless the window is active. + // TODO: Find a way to make the tooltip display all the time. + + if (!node->TooltipText) + node->TooltipText = PhMipGetGroupNodeTooltip(listSection, node); + + if (!PhIsNullOrEmptyString(node->TooltipText)) + { + getCellTooltip->Text = node->TooltipText->sr; + getCellTooltip->Unfolding = FALSE; + getCellTooltip->MaximumWidth = -1; + } + else + { + return FALSE; + } + } + return TRUE; + case TreeNewSelectionChanged: + { + ULONG i; + PPH_MIP_GROUP_NODE node; + + listSection->SelectedRepresentativeProcessId = NULL; + listSection->SelectedRepresentativeCreateTime.QuadPart = 0; + + for (i = 0; i < listSection->NodeList->Count; i++) + { + node = listSection->NodeList->Items[i]; + + if (node->Node.Selected) + { + listSection->SelectedRepresentativeProcessId = node->RepresentativeProcessId; + listSection->SelectedRepresentativeCreateTime = node->RepresentativeCreateTime; + break; + } + } + } + break; + case TreeNewKeyDown: + { + PPH_TREENEW_KEY_EVENT keyEvent = Parameter1; + PPH_MIP_GROUP_NODE node; + + listSection->SuspendUpdate++; + + switch (keyEvent->VirtualKey) + { + case VK_DELETE: + if (node = PhMipGetSelectedGroupNode(listSection)) + PhUiTerminateProcesses(listSection->DialogHandle, &node->ProcessGroup->Representative, 1); + break; + case VK_RETURN: + if (node = PhMipGetSelectedGroupNode(listSection)) + { + if (GetKeyState(VK_CONTROL) >= 0) + { + PhMipHandleListSectionCommand(listSection, node->ProcessGroup, ID_PROCESS_GOTOPROCESS); + } + else + { + if (node->ProcessGroup->Representative->FileName) + PhShellExploreFile(listSection->DialogHandle, node->ProcessGroup->Representative->FileName->Buffer); + } + } + break; + } + + listSection->SuspendUpdate--; + } + return TRUE; + case TreeNewLeftDoubleClick: + { + PPH_TREENEW_MOUSE_EVENT mouseEvent = Parameter1; + PPH_MIP_GROUP_NODE node = (PPH_MIP_GROUP_NODE)mouseEvent->Node; + + if (node) + { + listSection->SuspendUpdate++; + PhMipHandleListSectionCommand(listSection, node->ProcessGroup, ID_PROCESS_GOTOPROCESS); + listSection->SuspendUpdate--; + } + } + break; + case TreeNewContextMenu: + { + PPH_TREENEW_CONTEXT_MENU contextMenu = Parameter1; + + // Prevent the node list from being updated (otherwise any nodes we're using might be destroyed while we're + // in a modal message loop). + listSection->SuspendUpdate++; + PhMipBeginChildControlPin(); + PhMipShowListSectionContextMenu(listSection, contextMenu); + PhMipEndChildControlPin(); + listSection->SuspendUpdate--; + } + break; + } + + return FALSE; +} + +PPH_STRING PhMipGetGroupNodeTooltip( + _In_ PPH_MINIINFO_LIST_SECTION ListSection, + _In_ PPH_MIP_GROUP_NODE Node + ) +{ + PH_STRING_BUILDER sb; + + PhInitializeStringBuilder(&sb, 100); + + // TODO + + return PhFinalStringBuilderString(&sb); +} + +PPH_MIP_GROUP_NODE PhMipGetSelectedGroupNode( + _In_ PPH_MINIINFO_LIST_SECTION ListSection + ) +{ + ULONG i; + PPH_MIP_GROUP_NODE node; + + for (i = 0; i < ListSection->NodeList->Count; i++) + { + node = ListSection->NodeList->Items[i]; + + if (node->Node.Selected) + return node; + } + + return NULL; +} + +VOID PhMipShowListSectionContextMenu( + _In_ PPH_MINIINFO_LIST_SECTION ListSection, + _In_ PPH_TREENEW_CONTEXT_MENU ContextMenu + ) +{ + PPH_MIP_GROUP_NODE selectedNode; + PPH_EMENU menu; + PPH_EMENU_ITEM item; + PH_MINIINFO_LIST_SECTION_MENU_INFORMATION menuInfo; + PH_PLUGIN_MENU_INFORMATION pluginMenuInfo; + + selectedNode = PhMipGetSelectedGroupNode(ListSection); + + if (!selectedNode) + return; + + menu = PhCreateEMenu(); + // TODO: If there are multiple processes, then create submenus for each process. + PhAddMiniProcessMenuItems(menu, ListSection->SelectedRepresentativeProcessId); + PhLoadResourceEMenuItem(menu, PhInstanceHandle, MAKEINTRESOURCE(IDR_MINIINFO_PROCESS), 0); + PhSetFlagsEMenuItem(menu, ID_PROCESS_GOTOPROCESS, PH_EMENU_DEFAULT, PH_EMENU_DEFAULT); + + if (selectedNode->ProcessGroup->Processes->Count != 1) + { + if (item = PhFindEMenuItem(menu, 0, NULL, ID_PROCESS_GOTOPROCESS)) + PhModifyEMenuItem(item, PH_EMENU_MODIFY_TEXT, 0, L"&Go to processes", NULL); + } + + memset(&menuInfo, 0, sizeof(PH_MINIINFO_LIST_SECTION_MENU_INFORMATION)); + menuInfo.ProcessGroup = selectedNode->ProcessGroup; + menuInfo.SortData = &selectedNode->SortData; + menuInfo.ContextMenu = ContextMenu; + ListSection->Callback(ListSection, MiListSectionInitializeContextMenu, &menuInfo, NULL); + + if (PhPluginsEnabled) + { + PhPluginInitializeMenuInfo(&pluginMenuInfo, menu, ListSection->DialogHandle, 0); + pluginMenuInfo.Menu = menu; + pluginMenuInfo.OwnerWindow = PhMipWindow; + pluginMenuInfo.u.MiListSection.SectionName = &ListSection->Section->Name; + pluginMenuInfo.u.MiListSection.ProcessGroup = selectedNode->ProcessGroup; + + PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackMiListSectionMenuInitializing), &pluginMenuInfo); + } + + item = PhShowEMenu( + menu, + PhMipWindow, + PH_EMENU_SHOW_LEFTRIGHT, + PH_ALIGN_LEFT | PH_ALIGN_TOP, + ContextMenu->Location.x, + ContextMenu->Location.y + ); + + if (item) + { + BOOLEAN handled = FALSE; + + if (!handled && PhPluginsEnabled) + handled = PhPluginTriggerEMenuItem(&pluginMenuInfo, item); + + if (!handled) + { + menuInfo.SelectedItem = item; + handled = ListSection->Callback(ListSection, MiListSectionHandleContextMenu, &menuInfo, NULL); + } + + if (!handled) + PhHandleMiniProcessMenuItem(item); + + if (!handled) + PhMipHandleListSectionCommand(ListSection, selectedNode->ProcessGroup, item->Id); + } + + PhDestroyEMenu(menu); +} + +VOID PhMipHandleListSectionCommand( + _In_ PPH_MINIINFO_LIST_SECTION ListSection, + _In_ PPH_PROCESS_GROUP ProcessGroup, + _In_ ULONG Id + ) +{ + switch (Id) + { + case ID_PROCESS_GOTOPROCESS: + { + PPH_LIST nodes; + ULONG i; + + nodes = PhCreateList(ProcessGroup->Processes->Count); + + for (i = 0; i < ProcessGroup->Processes->Count; i++) + { + PPH_PROCESS_NODE node; + + if (node = PhFindProcessNode(((PPH_PROCESS_ITEM)ProcessGroup->Processes->Items[i])->ProcessId)) + PhAddItemList(nodes, node); + } + + PhPinMiniInformation(MiniInfoIconPinType, -1, 0, 0, NULL, NULL); + PhPinMiniInformation(MiniInfoActivePinType, -1, 0, 0, NULL, NULL); + PhPinMiniInformation(MiniInfoHoverPinType, -1, 0, 0, NULL, NULL); + + ProcessHacker_ToggleVisible(PhMainWndHandle, TRUE); + ProcessHacker_SelectTabPage(PhMainWndHandle, 0); + PhSelectAndEnsureVisibleProcessNodes((PPH_PROCESS_NODE *)nodes->Items, nodes->Count); + PhDereferenceObject(nodes); + } + break; + } +} + +BOOLEAN PhMipCpuListSectionCallback( + _In_ struct _PH_MINIINFO_LIST_SECTION *ListSection, + _In_ PH_MINIINFO_LIST_SECTION_MESSAGE Message, + _In_opt_ PVOID Parameter1, + _In_opt_ PVOID Parameter2 + ) +{ + switch (Message) + { + case MiListSectionTick: + ListSection->Section->Parameters->SetSectionText(ListSection->Section, + PhaFormatString(L"CPU %.2f%%", (PhCpuUserUsage + PhCpuKernelUsage) * 100)); + break; + case MiListSectionSortProcessList: + { + PPH_MINIINFO_LIST_SECTION_SORT_LIST sortList = Parameter1; + + qsort(sortList->List->Items, sortList->List->Count, + sizeof(PPH_PROCESS_NODE), PhMipCpuListSectionProcessCompareFunction); + } + return TRUE; + case MiListSectionAssignSortData: + { + PPH_MINIINFO_LIST_SECTION_ASSIGN_SORT_DATA assignSortData = Parameter1; + PPH_LIST processes = assignSortData->ProcessGroup->Processes; + FLOAT cpuUsage = 0; + ULONG i; + + for (i = 0; i < processes->Count; i++) + cpuUsage += ((PPH_PROCESS_ITEM)processes->Items[i])->CpuUsage; + + *(PFLOAT)assignSortData->SortData->UserData = cpuUsage; + } + return TRUE; + case MiListSectionSortGroupList: + { + PPH_MINIINFO_LIST_SECTION_SORT_LIST sortList = Parameter1; + + qsort(sortList->List->Items, sortList->List->Count, + sizeof(PPH_MINIINFO_LIST_SECTION_SORT_DATA), PhMipCpuListSectionNodeCompareFunction); + } + return TRUE; + case MiListSectionGetUsageText: + { + PPH_MINIINFO_LIST_SECTION_GET_USAGE_TEXT getUsageText = Parameter1; + PPH_LIST processes = getUsageText->ProcessGroup->Processes; + FLOAT cpuUsage = *(PFLOAT)getUsageText->SortData->UserData * 100; + PPH_STRING cpuUsageText; + + if (cpuUsage >= 0.01) + cpuUsageText = PhFormatString(L"%.2f%%", cpuUsage); + else if (cpuUsage != 0) + cpuUsageText = PhCreateString(L"< 0.01%"); + else + cpuUsageText = NULL; + + PhMoveReference(&getUsageText->Line1, cpuUsageText); + } + return TRUE; + } + + return FALSE; +} + +int __cdecl PhMipCpuListSectionProcessCompareFunction( + _In_ const void *elem1, + _In_ const void *elem2 + ) +{ + int result; + PPH_PROCESS_NODE node1 = *(PPH_PROCESS_NODE *)elem1; + PPH_PROCESS_NODE node2 = *(PPH_PROCESS_NODE *)elem2; + + result = singlecmp(node2->ProcessItem->CpuUsage, node1->ProcessItem->CpuUsage); + + if (result == 0) + result = uint64cmp(node2->ProcessItem->UserTime.QuadPart, node1->ProcessItem->UserTime.QuadPart); + + return result; +} + +int __cdecl PhMipCpuListSectionNodeCompareFunction( + _In_ const void *elem1, + _In_ const void *elem2 + ) +{ + PPH_MINIINFO_LIST_SECTION_SORT_DATA data1 = *(PPH_MINIINFO_LIST_SECTION_SORT_DATA *)elem1; + PPH_MINIINFO_LIST_SECTION_SORT_DATA data2 = *(PPH_MINIINFO_LIST_SECTION_SORT_DATA *)elem2; + + return singlecmp(*(PFLOAT)data2->UserData, *(PFLOAT)data1->UserData); +} + +BOOLEAN PhMipCommitListSectionCallback( + _In_ struct _PH_MINIINFO_LIST_SECTION *ListSection, + _In_ PH_MINIINFO_LIST_SECTION_MESSAGE Message, + _In_opt_ PVOID Parameter1, + _In_opt_ PVOID Parameter2 + ) +{ + switch (Message) + { + case MiListSectionTick: + { + PH_FORMAT format[5]; + DOUBLE commitFraction = (DOUBLE)PhPerfInformation.CommittedPages / PhPerfInformation.CommitLimit; + + PhInitFormatS(&format[0], L"Commit "); + PhInitFormatSize(&format[1], UInt32x32To64(PhPerfInformation.CommittedPages, PAGE_SIZE)); + PhInitFormatS(&format[2], L" ("); + PhInitFormatF(&format[3], commitFraction * 100, 2); + PhInitFormatS(&format[4], L"%)"); + ListSection->Section->Parameters->SetSectionText(ListSection->Section, + PH_AUTO(PhFormat(format, 5, 96))); + } + break; + case MiListSectionSortProcessList: + { + PPH_MINIINFO_LIST_SECTION_SORT_LIST sortList = Parameter1; + + qsort(sortList->List->Items, sortList->List->Count, + sizeof(PPH_PROCESS_NODE), PhMipCommitListSectionProcessCompareFunction); + } + return TRUE; + case MiListSectionAssignSortData: + { + PPH_MINIINFO_LIST_SECTION_ASSIGN_SORT_DATA assignSortData = Parameter1; + PPH_LIST processes = assignSortData->ProcessGroup->Processes; + ULONG64 privateBytes = 0; + ULONG i; + + for (i = 0; i < processes->Count; i++) + privateBytes += ((PPH_PROCESS_ITEM)processes->Items[i])->VmCounters.PagefileUsage; + + *(PULONG64)assignSortData->SortData->UserData = privateBytes; + } + return TRUE; + case MiListSectionSortGroupList: + { + PPH_MINIINFO_LIST_SECTION_SORT_LIST sortList = Parameter1; + + qsort(sortList->List->Items, sortList->List->Count, + sizeof(PPH_MINIINFO_LIST_SECTION_SORT_DATA), PhMipCommitListSectionNodeCompareFunction); + } + return TRUE; + case MiListSectionGetUsageText: + { + PPH_MINIINFO_LIST_SECTION_GET_USAGE_TEXT getUsageText = Parameter1; + PPH_LIST processes = getUsageText->ProcessGroup->Processes; + ULONG64 privateBytes = *(PULONG64)getUsageText->SortData->UserData; + + PhMoveReference(&getUsageText->Line1, PhFormatSize(privateBytes, -1)); + PhMoveReference(&getUsageText->Line2, PhCreateString(L"Private bytes")); + getUsageText->Line2Color = GetSysColor(COLOR_GRAYTEXT); + } + return TRUE; + } + + return FALSE; +} + +int __cdecl PhMipCommitListSectionProcessCompareFunction( + _In_ const void *elem1, + _In_ const void *elem2 + ) +{ + PPH_PROCESS_NODE node1 = *(PPH_PROCESS_NODE *)elem1; + PPH_PROCESS_NODE node2 = *(PPH_PROCESS_NODE *)elem2; + + return uintptrcmp(node2->ProcessItem->VmCounters.PagefileUsage, node1->ProcessItem->VmCounters.PagefileUsage); +} + +int __cdecl PhMipCommitListSectionNodeCompareFunction( + _In_ const void *elem1, + _In_ const void *elem2 + ) +{ + PPH_MINIINFO_LIST_SECTION_SORT_DATA data1 = *(PPH_MINIINFO_LIST_SECTION_SORT_DATA *)elem1; + PPH_MINIINFO_LIST_SECTION_SORT_DATA data2 = *(PPH_MINIINFO_LIST_SECTION_SORT_DATA *)elem2; + + return uint64cmp(*(PULONG64)data2->UserData, *(PULONG64)data1->UserData); +} + +BOOLEAN PhMipPhysicalListSectionCallback( + _In_ struct _PH_MINIINFO_LIST_SECTION *ListSection, + _In_ PH_MINIINFO_LIST_SECTION_MESSAGE Message, + _In_opt_ PVOID Parameter1, + _In_opt_ PVOID Parameter2 + ) +{ + switch (Message) + { + case MiListSectionTick: + { + PH_FORMAT format[5]; + ULONG physicalUsage = PhSystemBasicInformation.NumberOfPhysicalPages - PhPerfInformation.AvailablePages; + FLOAT physicalFraction = (FLOAT)physicalUsage / PhSystemBasicInformation.NumberOfPhysicalPages; + + PhInitFormatS(&format[0], L"Physical "); + PhInitFormatSize(&format[1], UInt32x32To64(physicalUsage, PAGE_SIZE)); + PhInitFormatS(&format[2], L" ("); + PhInitFormatF(&format[3], physicalFraction * 100, 2); + PhInitFormatS(&format[4], L"%)"); + ListSection->Section->Parameters->SetSectionText(ListSection->Section, + PH_AUTO(PhFormat(format, 5, 96))); + } + break; + case MiListSectionSortProcessList: + { + PPH_MINIINFO_LIST_SECTION_SORT_LIST sortList = Parameter1; + + qsort(sortList->List->Items, sortList->List->Count, + sizeof(PPH_PROCESS_NODE), PhMipPhysicalListSectionProcessCompareFunction); + } + return TRUE; + case MiListSectionAssignSortData: + { + PPH_MINIINFO_LIST_SECTION_ASSIGN_SORT_DATA assignSortData = Parameter1; + PPH_LIST processes = assignSortData->ProcessGroup->Processes; + ULONG64 workingSet = 0; + ULONG i; + + for (i = 0; i < processes->Count; i++) + workingSet += ((PPH_PROCESS_ITEM)processes->Items[i])->VmCounters.WorkingSetSize; + + *(PULONG64)assignSortData->SortData->UserData = workingSet; + } + return TRUE; + case MiListSectionSortGroupList: + { + PPH_MINIINFO_LIST_SECTION_SORT_LIST sortList = Parameter1; + + qsort(sortList->List->Items, sortList->List->Count, + sizeof(PPH_MINIINFO_LIST_SECTION_SORT_DATA), PhMipPhysicalListSectionNodeCompareFunction); + } + return TRUE; + case MiListSectionGetUsageText: + { + PPH_MINIINFO_LIST_SECTION_GET_USAGE_TEXT getUsageText = Parameter1; + PPH_LIST processes = getUsageText->ProcessGroup->Processes; + ULONG64 privateBytes = *(PULONG64)getUsageText->SortData->UserData; + + PhMoveReference(&getUsageText->Line1, PhFormatSize(privateBytes, -1)); + PhMoveReference(&getUsageText->Line2, PhCreateString(L"Working set")); + getUsageText->Line2Color = GetSysColor(COLOR_GRAYTEXT); + } + return TRUE; + } + + return FALSE; +} + +int __cdecl PhMipPhysicalListSectionProcessCompareFunction( + _In_ const void *elem1, + _In_ const void *elem2 + ) +{ + PPH_PROCESS_NODE node1 = *(PPH_PROCESS_NODE *)elem1; + PPH_PROCESS_NODE node2 = *(PPH_PROCESS_NODE *)elem2; + + return uintptrcmp(node2->ProcessItem->VmCounters.WorkingSetSize, node1->ProcessItem->VmCounters.WorkingSetSize); +} + +int __cdecl PhMipPhysicalListSectionNodeCompareFunction( + _In_ const void *elem1, + _In_ const void *elem2 + ) +{ + PPH_MINIINFO_LIST_SECTION_SORT_DATA data1 = *(PPH_MINIINFO_LIST_SECTION_SORT_DATA *)elem1; + PPH_MINIINFO_LIST_SECTION_SORT_DATA data2 = *(PPH_MINIINFO_LIST_SECTION_SORT_DATA *)elem2; + + return uint64cmp(*(PULONG64)data2->UserData, *(PULONG64)data1->UserData); +} + +BOOLEAN PhMipIoListSectionCallback( + _In_ struct _PH_MINIINFO_LIST_SECTION *ListSection, + _In_ PH_MINIINFO_LIST_SECTION_MESSAGE Message, + _In_opt_ PVOID Parameter1, + _In_opt_ PVOID Parameter2 + ) +{ + switch (Message) + { + case MiListSectionTick: + { + PH_FORMAT format[6]; + + PhInitFormatS(&format[0], L"I/O R: "); + PhInitFormatSize(&format[1], PhIoReadDelta.Delta); + format[1].Type |= FormatUsePrecision; + format[1].Precision = 0; + PhInitFormatS(&format[2], L" W: "); + PhInitFormatSize(&format[3], PhIoWriteDelta.Delta); + format[3].Type |= FormatUsePrecision; + format[3].Precision = 0; + PhInitFormatS(&format[4], L" O: "); + PhInitFormatSize(&format[5], PhIoOtherDelta.Delta); + format[5].Type |= FormatUsePrecision; + format[5].Precision = 0; + ListSection->Section->Parameters->SetSectionText(ListSection->Section, + PH_AUTO(PhFormat(format, 6, 80))); + } + break; + case MiListSectionSortProcessList: + { + PPH_MINIINFO_LIST_SECTION_SORT_LIST sortList = Parameter1; + + qsort(sortList->List->Items, sortList->List->Count, + sizeof(PPH_PROCESS_NODE), PhMipIoListSectionProcessCompareFunction); + } + return TRUE; + case MiListSectionAssignSortData: + { + PPH_MINIINFO_LIST_SECTION_ASSIGN_SORT_DATA assignSortData = Parameter1; + PPH_LIST processes = assignSortData->ProcessGroup->Processes; + ULONG64 ioReadOtherDelta = 0; + ULONG64 ioWriteDelta = 0; + ULONG i; + + for (i = 0; i < processes->Count; i++) + { + PPH_PROCESS_ITEM processItem = processes->Items[i]; + ioReadOtherDelta += processItem->IoReadDelta.Delta; + ioWriteDelta += processItem->IoWriteDelta.Delta; + ioReadOtherDelta += processItem->IoOtherDelta.Delta; + } + + assignSortData->SortData->UserData[0] = ioReadOtherDelta; + assignSortData->SortData->UserData[1] = ioWriteDelta; + } + return TRUE; + case MiListSectionSortGroupList: + { + PPH_MINIINFO_LIST_SECTION_SORT_LIST sortList = Parameter1; + + qsort(sortList->List->Items, sortList->List->Count, + sizeof(PPH_MINIINFO_LIST_SECTION_SORT_DATA), PhMipIoListSectionNodeCompareFunction); + } + return TRUE; + case MiListSectionGetUsageText: + { + PPH_MINIINFO_LIST_SECTION_GET_USAGE_TEXT getUsageText = Parameter1; + PPH_LIST processes = getUsageText->ProcessGroup->Processes; + ULONG64 ioReadOtherDelta = getUsageText->SortData->UserData[0]; + ULONG64 ioWriteDelta = getUsageText->SortData->UserData[1]; + PH_FORMAT format[1]; + + PhInitFormatSize(&format[0], ioReadOtherDelta + ioWriteDelta); + PhMoveReference(&getUsageText->Line1, PhFormat(format, 1, 16)); + } + return TRUE; + } + + return FALSE; +} + +int __cdecl PhMipIoListSectionProcessCompareFunction( + _In_ const void *elem1, + _In_ const void *elem2 + ) +{ + int result; + PPH_PROCESS_NODE node1 = *(PPH_PROCESS_NODE *)elem1; + PPH_PROCESS_NODE node2 = *(PPH_PROCESS_NODE *)elem2; + ULONG64 delta1 = node1->ProcessItem->IoReadDelta.Delta + node1->ProcessItem->IoWriteDelta.Delta + node1->ProcessItem->IoOtherDelta.Delta; + ULONG64 delta2 = node2->ProcessItem->IoReadDelta.Delta + node2->ProcessItem->IoWriteDelta.Delta + node2->ProcessItem->IoOtherDelta.Delta; + ULONG64 value1 = node1->ProcessItem->IoReadDelta.Value + node1->ProcessItem->IoWriteDelta.Value + node1->ProcessItem->IoOtherDelta.Value; + ULONG64 value2 = node2->ProcessItem->IoReadDelta.Value + node2->ProcessItem->IoWriteDelta.Value + node2->ProcessItem->IoOtherDelta.Value; + + result = uint64cmp(delta2, delta1); + + if (result == 0) + result = uint64cmp(value2, value1); + + return result; +} + +int __cdecl PhMipIoListSectionNodeCompareFunction( + _In_ const void *elem1, + _In_ const void *elem2 + ) +{ + PPH_MINIINFO_LIST_SECTION_SORT_DATA data1 = *(PPH_MINIINFO_LIST_SECTION_SORT_DATA *)elem1; + PPH_MINIINFO_LIST_SECTION_SORT_DATA data2 = *(PPH_MINIINFO_LIST_SECTION_SORT_DATA *)elem2; + + return uint64cmp(data2->UserData[0] + data2->UserData[1], data1->UserData[0] + data1->UserData[1]); +} diff --git a/ProcessHacker/modlist.c b/ProcessHacker/modlist.c index 45df208186d0..3cca62efabd0 100644 --- a/ProcessHacker/modlist.c +++ b/ProcessHacker/modlist.c @@ -1,1012 +1,1012 @@ -/* - * Process Hacker - - * module list - * - * Copyright (C) 2010-2016 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include -#include - -#include -#include - -#include -#include -#include -#include - -BOOLEAN PhpModuleNodeHashtableEqualFunction( - _In_ PVOID Entry1, - _In_ PVOID Entry2 - ); - -ULONG PhpModuleNodeHashtableHashFunction( - _In_ PVOID Entry - ); - -VOID PhpDestroyModuleNode( - _In_ PPH_MODULE_NODE ModuleNode - ); - -VOID PhpRemoveModuleNode( - _In_ PPH_MODULE_NODE ModuleNode, - _In_ PPH_MODULE_LIST_CONTEXT Context - ); - -LONG PhpModuleTreeNewPostSortFunction( - _In_ LONG Result, - _In_ PVOID Node1, - _In_ PVOID Node2, - _In_ PH_SORT_ORDER SortOrder - ); - -BOOLEAN NTAPI PhpModuleTreeNewCallback( - _In_ HWND hwnd, - _In_ PH_TREENEW_MESSAGE Message, - _In_opt_ PVOID Parameter1, - _In_opt_ PVOID Parameter2, - _In_opt_ PVOID Context - ); - -VOID PhInitializeModuleList( - _In_ HWND ParentWindowHandle, - _In_ HWND TreeNewHandle, - _Out_ PPH_MODULE_LIST_CONTEXT Context - ) -{ - HWND hwnd; - - memset(Context, 0, sizeof(PH_MODULE_LIST_CONTEXT)); - Context->EnableStateHighlighting = TRUE; - - Context->NodeHashtable = PhCreateHashtable( - sizeof(PPH_MODULE_NODE), - PhpModuleNodeHashtableEqualFunction, - PhpModuleNodeHashtableHashFunction, - 100 - ); - Context->NodeList = PhCreateList(100); - - Context->ParentWindowHandle = ParentWindowHandle; - Context->TreeNewHandle = TreeNewHandle; - hwnd = TreeNewHandle; - PhSetControlTheme(hwnd, L"explorer"); - - TreeNew_SetCallback(hwnd, PhpModuleTreeNewCallback, Context); - - TreeNew_SetRedraw(hwnd, FALSE); - - // Default columns - PhAddTreeNewColumn(hwnd, PHMOTLC_NAME, TRUE, L"Name", 100, PH_ALIGN_LEFT, -2, 0); - PhAddTreeNewColumn(hwnd, PHMOTLC_BASEADDRESS, TRUE, L"Base address", 80, PH_ALIGN_RIGHT, 0, DT_RIGHT); - PhAddTreeNewColumnEx(hwnd, PHMOTLC_SIZE, TRUE, L"Size", 60, PH_ALIGN_RIGHT, 1, DT_RIGHT, TRUE); - PhAddTreeNewColumn(hwnd, PHMOTLC_DESCRIPTION, TRUE, L"Description", 160, PH_ALIGN_LEFT, 2, 0); - - PhAddTreeNewColumn(hwnd, PHMOTLC_COMPANYNAME, FALSE, L"Company name", 180, PH_ALIGN_LEFT, -1, 0); - PhAddTreeNewColumn(hwnd, PHMOTLC_VERSION, FALSE, L"Version", 100, PH_ALIGN_LEFT, -1, 0); - PhAddTreeNewColumn(hwnd, PHMOTLC_FILENAME, FALSE, L"File name", 180, PH_ALIGN_LEFT, -1, DT_PATH_ELLIPSIS); - - PhAddTreeNewColumn(hwnd, PHMOTLC_TYPE, FALSE, L"Type", 80, PH_ALIGN_LEFT, -1, 0); - PhAddTreeNewColumnEx(hwnd, PHMOTLC_LOADCOUNT, FALSE, L"Load count", 40, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); - PhAddTreeNewColumn(hwnd, PHMOTLC_VERIFICATIONSTATUS, FALSE, L"Verification status", 70, PH_ALIGN_LEFT, -1, 0); - PhAddTreeNewColumn(hwnd, PHMOTLC_VERIFIEDSIGNER, FALSE, L"Verified signer", 100, PH_ALIGN_LEFT, -1, 0); - PhAddTreeNewColumnEx(hwnd, PHMOTLC_ASLR, FALSE, L"ASLR", 50, PH_ALIGN_LEFT, -1, 0, TRUE); - PhAddTreeNewColumnEx(hwnd, PHMOTLC_TIMESTAMP, FALSE, L"Time stamp", 100, PH_ALIGN_LEFT, -1, 0, TRUE); - PhAddTreeNewColumnEx(hwnd, PHMOTLC_CFGUARD, FALSE, L"CF Guard", 70, PH_ALIGN_LEFT, -1, 0, TRUE); - PhAddTreeNewColumnEx(hwnd, PHMOTLC_LOADTIME, FALSE, L"Load time", 100, PH_ALIGN_LEFT, -1, 0, TRUE); - PhAddTreeNewColumn(hwnd, PHMOTLC_LOADREASON, FALSE, L"Load reason", 80, PH_ALIGN_LEFT, -1, 0); - PhAddTreeNewColumnEx(hwnd, PHMOTLC_FILEMODIFIEDTIME, FALSE, L"File modified time", 140, PH_ALIGN_LEFT, -1, 0, TRUE); - PhAddTreeNewColumnEx(hwnd, PHMOTLC_FILESIZE, FALSE, L"File size", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); - - TreeNew_SetRedraw(hwnd, TRUE); - - TreeNew_SetTriState(hwnd, TRUE); - TreeNew_SetSort(hwnd, 0, NoSortOrder); - - PhCmInitializeManager(&Context->Cm, hwnd, PHMOTLC_MAXIMUM, PhpModuleTreeNewPostSortFunction); -} - -VOID PhDeleteModuleList( - _In_ PPH_MODULE_LIST_CONTEXT Context - ) -{ - ULONG i; - - if (Context->BoldFont) - DeleteObject(Context->BoldFont); - - PhCmDeleteManager(&Context->Cm); - - for (i = 0; i < Context->NodeList->Count; i++) - PhpDestroyModuleNode(Context->NodeList->Items[i]); - - PhDereferenceObject(Context->NodeHashtable); - PhDereferenceObject(Context->NodeList); -} - -BOOLEAN PhpModuleNodeHashtableEqualFunction( - _In_ PVOID Entry1, - _In_ PVOID Entry2 - ) -{ - PPH_MODULE_NODE moduleNode1 = *(PPH_MODULE_NODE *)Entry1; - PPH_MODULE_NODE moduleNode2 = *(PPH_MODULE_NODE *)Entry2; - - return moduleNode1->ModuleItem == moduleNode2->ModuleItem; -} - -ULONG PhpModuleNodeHashtableHashFunction( - _In_ PVOID Entry - ) -{ - return PhHashIntPtr((ULONG_PTR)(*(PPH_MODULE_NODE *)Entry)->ModuleItem); -} - -VOID PhLoadSettingsModuleList( - _Inout_ PPH_MODULE_LIST_CONTEXT Context - ) -{ - PPH_STRING settings; - PPH_STRING sortSettings; - - settings = PhGetStringSetting(L"ModuleTreeListColumns"); - sortSettings = PhGetStringSetting(L"ModuleTreeListSort"); - PhCmLoadSettingsEx(Context->TreeNewHandle, &Context->Cm, 0, &settings->sr, &sortSettings->sr); - PhDereferenceObject(settings); - PhDereferenceObject(sortSettings); -} - -VOID PhSaveSettingsModuleList( - _Inout_ PPH_MODULE_LIST_CONTEXT Context - ) -{ - PPH_STRING settings; - PPH_STRING sortSettings; - - settings = PhCmSaveSettingsEx(Context->TreeNewHandle, &Context->Cm, 0, &sortSettings); - PhSetStringSetting2(L"ModuleTreeListColumns", &settings->sr); - PhSetStringSetting2(L"ModuleTreeListSort", &sortSettings->sr); - PhDereferenceObject(settings); - PhDereferenceObject(sortSettings); -} - -PPH_MODULE_NODE PhAddModuleNode( - _Inout_ PPH_MODULE_LIST_CONTEXT Context, - _In_ PPH_MODULE_ITEM ModuleItem, - _In_ ULONG RunId - ) -{ - PPH_MODULE_NODE moduleNode; - - moduleNode = PhAllocate(PhEmGetObjectSize(EmModuleNodeType, sizeof(PH_MODULE_NODE))); - memset(moduleNode, 0, sizeof(PH_MODULE_NODE)); - PhInitializeTreeNewNode(&moduleNode->Node); - - if (Context->EnableStateHighlighting && RunId != 1) - { - PhChangeShStateTn( - &moduleNode->Node, - &moduleNode->ShState, - &Context->NodeStateList, - NewItemState, - PhCsColorNew, - NULL - ); - } - - moduleNode->ModuleItem = ModuleItem; - PhReferenceObject(ModuleItem); - - memset(moduleNode->TextCache, 0, sizeof(PH_STRINGREF) * PHMOTLC_MAXIMUM); - moduleNode->Node.TextCache = moduleNode->TextCache; - moduleNode->Node.TextCacheSize = PHMOTLC_MAXIMUM; - - PhAddEntryHashtable(Context->NodeHashtable, &moduleNode); - PhAddItemList(Context->NodeList, moduleNode); - - PhEmCallObjectOperation(EmModuleNodeType, moduleNode, EmObjectCreate); - - TreeNew_NodesStructured(Context->TreeNewHandle); - - return moduleNode; -} - -PPH_MODULE_NODE PhFindModuleNode( - _In_ PPH_MODULE_LIST_CONTEXT Context, - _In_ PPH_MODULE_ITEM ModuleItem - ) -{ - PH_MODULE_NODE lookupModuleNode; - PPH_MODULE_NODE lookupModuleNodePtr = &lookupModuleNode; - PPH_MODULE_NODE *moduleNode; - - lookupModuleNode.ModuleItem = ModuleItem; - - moduleNode = (PPH_MODULE_NODE *)PhFindEntryHashtable( - Context->NodeHashtable, - &lookupModuleNodePtr - ); - - if (moduleNode) - return *moduleNode; - else - return NULL; -} - -VOID PhRemoveModuleNode( - _In_ PPH_MODULE_LIST_CONTEXT Context, - _In_ PPH_MODULE_NODE ModuleNode - ) -{ - // Remove from the hashtable here to avoid problems in case the key is re-used. - PhRemoveEntryHashtable(Context->NodeHashtable, &ModuleNode); - - if (Context->EnableStateHighlighting) - { - PhChangeShStateTn( - &ModuleNode->Node, - &ModuleNode->ShState, - &Context->NodeStateList, - RemovingItemState, - PhCsColorRemoved, - Context->TreeNewHandle - ); - } - else - { - PhpRemoveModuleNode(ModuleNode, Context); - } -} - -VOID PhpDestroyModuleNode( - _In_ PPH_MODULE_NODE ModuleNode - ) -{ - PhEmCallObjectOperation(EmModuleNodeType, ModuleNode, EmObjectDelete); - - PhClearReference(&ModuleNode->TooltipText); - - PhClearReference(&ModuleNode->SizeText); - PhClearReference(&ModuleNode->TimeStampText); - PhClearReference(&ModuleNode->LoadTimeText); - PhClearReference(&ModuleNode->FileModifiedTimeText); - PhClearReference(&ModuleNode->FileSizeText); - - PhDereferenceObject(ModuleNode->ModuleItem); - - PhFree(ModuleNode); -} - -VOID PhpRemoveModuleNode( - _In_ PPH_MODULE_NODE ModuleNode, - _In_ PPH_MODULE_LIST_CONTEXT Context // PH_TICK_SH_STATE requires this parameter to be after ModuleNode - ) -{ - ULONG index; - - // Remove from list and cleanup. - - if ((index = PhFindItemList(Context->NodeList, ModuleNode)) != -1) - PhRemoveItemList(Context->NodeList, index); - - PhpDestroyModuleNode(ModuleNode); - - TreeNew_NodesStructured(Context->TreeNewHandle); -} - -VOID PhUpdateModuleNode( - _In_ PPH_MODULE_LIST_CONTEXT Context, - _In_ PPH_MODULE_NODE ModuleNode - ) -{ - memset(ModuleNode->TextCache, 0, sizeof(PH_STRINGREF) * PHMOTLC_MAXIMUM); - PhClearReference(&ModuleNode->TooltipText); - - ModuleNode->ValidMask = 0; - PhInvalidateTreeNewNode(&ModuleNode->Node, TN_CACHE_COLOR); - TreeNew_NodesStructured(Context->TreeNewHandle); -} - -VOID PhTickModuleNodes( - _In_ PPH_MODULE_LIST_CONTEXT Context - ) -{ - PH_TICK_SH_STATE_TN(PH_MODULE_NODE, ShState, Context->NodeStateList, PhpRemoveModuleNode, PhCsHighlightingDuration, Context->TreeNewHandle, TRUE, NULL, Context); -} - -#define SORT_FUNCTION(Column) PhpModuleTreeNewCompare##Column - -#define BEGIN_SORT_FUNCTION(Column) static int __cdecl PhpModuleTreeNewCompare##Column( \ - _In_ void *_context, \ - _In_ const void *_elem1, \ - _In_ const void *_elem2 \ - ) \ -{ \ - PPH_MODULE_NODE node1 = *(PPH_MODULE_NODE *)_elem1; \ - PPH_MODULE_NODE node2 = *(PPH_MODULE_NODE *)_elem2; \ - PPH_MODULE_ITEM moduleItem1 = node1->ModuleItem; \ - PPH_MODULE_ITEM moduleItem2 = node2->ModuleItem; \ - int sortResult = 0; - -#define END_SORT_FUNCTION \ - if (sortResult == 0) \ - sortResult = uintptrcmp((ULONG_PTR)moduleItem1->BaseAddress, (ULONG_PTR)moduleItem2->BaseAddress); \ - \ - return PhModifySort(sortResult, ((PPH_MODULE_LIST_CONTEXT)_context)->TreeNewSortOrder); \ -} - -LONG PhpModuleTreeNewPostSortFunction( - _In_ LONG Result, - _In_ PVOID Node1, - _In_ PVOID Node2, - _In_ PH_SORT_ORDER SortOrder - ) -{ - if (Result == 0) - Result = uintptrcmp((ULONG_PTR)((PPH_MODULE_NODE)Node1)->ModuleItem->BaseAddress, (ULONG_PTR)((PPH_MODULE_NODE)Node2)->ModuleItem->BaseAddress); - - return PhModifySort(Result, SortOrder); -} - -BEGIN_SORT_FUNCTION(TriState) -{ - if (moduleItem1->IsFirst) - { - sortResult = -1; - } - else if (moduleItem2->IsFirst) - { - sortResult = 1; - } - else - { - sortResult = PhCompareString(moduleItem1->Name, moduleItem2->Name, TRUE); // fall back to sorting by name - } -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(Name) -{ - sortResult = PhCompareString(moduleItem1->Name, moduleItem2->Name, TRUE); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(BaseAddress) -{ - sortResult = uintptrcmp((ULONG_PTR)moduleItem1->BaseAddress, (ULONG_PTR)moduleItem2->BaseAddress); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(Size) -{ - sortResult = uintcmp(moduleItem1->Size, moduleItem2->Size); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(Description) -{ - sortResult = PhCompareStringWithNull(moduleItem1->VersionInfo.FileDescription, moduleItem2->VersionInfo.FileDescription, TRUE); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(CompanyName) -{ - sortResult = PhCompareStringWithNull(moduleItem1->VersionInfo.CompanyName, moduleItem2->VersionInfo.CompanyName, TRUE); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(Version) -{ - sortResult = PhCompareStringWithNull(moduleItem1->VersionInfo.FileVersion, moduleItem2->VersionInfo.FileVersion, TRUE); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(FileName) -{ - sortResult = PhCompareStringWithNull(moduleItem1->FileName, moduleItem2->FileName, TRUE); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(Type) -{ - sortResult = uintcmp(moduleItem1->Type, moduleItem2->Type); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(LoadCount) -{ - sortResult = uintcmp(moduleItem1->LoadCount, moduleItem2->LoadCount); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(VerificationStatus) -{ - sortResult = intcmp(moduleItem1->VerifyResult, moduleItem2->VerifyResult); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(VerifiedSigner) -{ - sortResult = PhCompareStringWithNull( - moduleItem1->VerifySignerName, - moduleItem2->VerifySignerName, - TRUE - ); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(Aslr) -{ - sortResult = intcmp( - moduleItem1->ImageDllCharacteristics & IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE, - moduleItem2->ImageDllCharacteristics & IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE - ); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(TimeStamp) -{ - sortResult = uintcmp(moduleItem1->ImageTimeDateStamp, moduleItem2->ImageTimeDateStamp); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(CfGuard) -{ - sortResult = intcmp( - moduleItem1->ImageDllCharacteristics & IMAGE_DLLCHARACTERISTICS_GUARD_CF, - moduleItem2->ImageDllCharacteristics & IMAGE_DLLCHARACTERISTICS_GUARD_CF - ); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(LoadTime) -{ - sortResult = uint64cmp(moduleItem1->LoadTime.QuadPart, moduleItem2->LoadTime.QuadPart); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(LoadReason) -{ - sortResult = uintcmp(moduleItem1->LoadReason, moduleItem2->LoadReason); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(FileModifiedTime) -{ - sortResult = int64cmp(moduleItem1->FileLastWriteTime.QuadPart, moduleItem2->FileLastWriteTime.QuadPart); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(FileSize) -{ - sortResult = int64cmp(moduleItem1->FileEndOfFile.QuadPart, moduleItem2->FileEndOfFile.QuadPart); -} -END_SORT_FUNCTION - -BOOLEAN NTAPI PhpModuleTreeNewCallback( - _In_ HWND hwnd, - _In_ PH_TREENEW_MESSAGE Message, - _In_opt_ PVOID Parameter1, - _In_opt_ PVOID Parameter2, - _In_opt_ PVOID Context - ) -{ - PPH_MODULE_LIST_CONTEXT context; - PPH_MODULE_NODE node; - - context = Context; - - if (PhCmForwardMessage(hwnd, Message, Parameter1, Parameter2, &context->Cm)) - return TRUE; - - switch (Message) - { - case TreeNewGetChildren: - { - PPH_TREENEW_GET_CHILDREN getChildren = Parameter1; - - if (!getChildren->Node) - { - static PVOID sortFunctions[] = - { - SORT_FUNCTION(Name), - SORT_FUNCTION(BaseAddress), - SORT_FUNCTION(Size), - SORT_FUNCTION(Description), - SORT_FUNCTION(CompanyName), - SORT_FUNCTION(Version), - SORT_FUNCTION(FileName), - SORT_FUNCTION(Type), - SORT_FUNCTION(LoadCount), - SORT_FUNCTION(VerificationStatus), - SORT_FUNCTION(VerifiedSigner), - SORT_FUNCTION(Aslr), - SORT_FUNCTION(TimeStamp), - SORT_FUNCTION(CfGuard), - SORT_FUNCTION(LoadTime), - SORT_FUNCTION(LoadReason), - SORT_FUNCTION(FileModifiedTime), - SORT_FUNCTION(FileSize) - }; - int (__cdecl *sortFunction)(void *, const void *, const void *); - - if (context->TreeNewSortOrder == NoSortOrder) - { - sortFunction = SORT_FUNCTION(TriState); - } - else - { - if (!PhCmForwardSort( - (PPH_TREENEW_NODE *)context->NodeList->Items, - context->NodeList->Count, - context->TreeNewSortColumn, - context->TreeNewSortOrder, - &context->Cm - )) - { - if (context->TreeNewSortColumn < PHMOTLC_MAXIMUM) - sortFunction = sortFunctions[context->TreeNewSortColumn]; - else - sortFunction = NULL; - } - else - { - sortFunction = NULL; - } - } - - if (sortFunction) - { - qsort_s(context->NodeList->Items, context->NodeList->Count, sizeof(PVOID), sortFunction, context); - } - - getChildren->Children = (PPH_TREENEW_NODE *)context->NodeList->Items; - getChildren->NumberOfChildren = context->NodeList->Count; - } - } - return TRUE; - case TreeNewIsLeaf: - { - PPH_TREENEW_IS_LEAF isLeaf = Parameter1; - - isLeaf->IsLeaf = TRUE; - } - return TRUE; - case TreeNewGetCellText: - { - PPH_TREENEW_GET_CELL_TEXT getCellText = Parameter1; - PPH_MODULE_ITEM moduleItem; - - node = (PPH_MODULE_NODE)getCellText->Node; - moduleItem = node->ModuleItem; - - switch (getCellText->Id) - { - case PHMOTLC_NAME: - getCellText->Text = moduleItem->Name->sr; - break; - case PHMOTLC_BASEADDRESS: - PhInitializeStringRefLongHint(&getCellText->Text, moduleItem->BaseAddressString); - break; - case PHMOTLC_SIZE: - if (!node->SizeText) - node->SizeText = PhFormatSize(moduleItem->Size, -1); - getCellText->Text = PhGetStringRef(node->SizeText); - break; - case PHMOTLC_DESCRIPTION: - getCellText->Text = PhGetStringRef(moduleItem->VersionInfo.FileDescription); - break; - case PHMOTLC_COMPANYNAME: - getCellText->Text = PhGetStringRef(moduleItem->VersionInfo.CompanyName); - break; - case PHMOTLC_VERSION: - getCellText->Text = PhGetStringRef(moduleItem->VersionInfo.FileVersion); - break; - case PHMOTLC_FILENAME: - getCellText->Text = PhGetStringRef(moduleItem->FileName); - break; - case PHMOTLC_TYPE: - { - PWSTR typeString; - - switch (moduleItem->Type) - { - case PH_MODULE_TYPE_MODULE: - typeString = L"DLL"; - break; - case PH_MODULE_TYPE_MAPPED_FILE: - typeString = L"Mapped file"; - break; - case PH_MODULE_TYPE_MAPPED_IMAGE: - typeString = L"Mapped image"; - break; - case PH_MODULE_TYPE_WOW64_MODULE: - typeString = L"WOW64 DLL"; - break; - case PH_MODULE_TYPE_KERNEL_MODULE: - typeString = L"Kernel module"; - break; - default: - typeString = L"Unknown"; - break; - } - - PhInitializeStringRefLongHint(&getCellText->Text, typeString); - } - break; - case PHMOTLC_LOADCOUNT: - if (moduleItem->Type == PH_MODULE_TYPE_MODULE || moduleItem->Type == PH_MODULE_TYPE_KERNEL_MODULE || - moduleItem->Type == PH_MODULE_TYPE_WOW64_MODULE) - { - if (moduleItem->LoadCount != (USHORT)-1) - { - PhPrintInt32(node->LoadCountText, moduleItem->LoadCount); - PhInitializeStringRefLongHint(&getCellText->Text, node->LoadCountText); - } - else - { - PhInitializeStringRef(&getCellText->Text, L"Static"); - } - } - else - { - PhInitializeEmptyStringRef(&getCellText->Text); - } - break; - case PHMOTLC_VERIFICATIONSTATUS: - if (moduleItem->Type == PH_MODULE_TYPE_MODULE || moduleItem->Type == PH_MODULE_TYPE_KERNEL_MODULE || - moduleItem->Type == PH_MODULE_TYPE_WOW64_MODULE || moduleItem->Type == PH_MODULE_TYPE_MAPPED_IMAGE) - { - PhInitializeStringRef(&getCellText->Text, - moduleItem->VerifyResult == VrTrusted ? L"Trusted" : L"Not trusted"); - } - else - { - PhInitializeEmptyStringRef(&getCellText->Text); - } - break; - case PHMOTLC_VERIFIEDSIGNER: - getCellText->Text = PhGetStringRef(moduleItem->VerifySignerName); - break; - case PHMOTLC_ASLR: - if (WindowsVersion >= WINDOWS_VISTA) - { - if (moduleItem->ImageDllCharacteristics & IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE) - PhInitializeStringRef(&getCellText->Text, L"ASLR"); - } - else - { - PhInitializeStringRef(&getCellText->Text, L"N/A"); - } - break; - case PHMOTLC_TIMESTAMP: - { - LARGE_INTEGER time; - SYSTEMTIME systemTime; - - if (moduleItem->ImageTimeDateStamp != 0) - { - RtlSecondsSince1970ToTime(moduleItem->ImageTimeDateStamp, &time); - PhLargeIntegerToLocalSystemTime(&systemTime, &time); - PhMoveReference(&node->TimeStampText, PhFormatDateTime(&systemTime)); - getCellText->Text = node->TimeStampText->sr; - } - else - { - PhInitializeEmptyStringRef(&getCellText->Text); - } - } - break; - case PHMOTLC_CFGUARD: - if (WindowsVersion >= WINDOWS_8_1) - { - if (moduleItem->ImageDllCharacteristics & IMAGE_DLLCHARACTERISTICS_GUARD_CF) - PhInitializeStringRef(&getCellText->Text, L"CF Guard"); - } - else - { - PhInitializeStringRef(&getCellText->Text, L"N/A"); - } - break; - case PHMOTLC_LOADTIME: - { - SYSTEMTIME systemTime; - - if (moduleItem->LoadTime.QuadPart != 0) - { - PhLargeIntegerToLocalSystemTime(&systemTime, &moduleItem->LoadTime); - PhMoveReference(&node->LoadTimeText, PhFormatDateTime(&systemTime)); - getCellText->Text = node->LoadTimeText->sr; - } - else - { - PhInitializeEmptyStringRef(&getCellText->Text); - } - } - break; - case PHMOTLC_LOADREASON: - { - PWSTR string = L""; - - if (moduleItem->Type == PH_MODULE_TYPE_MODULE || moduleItem->Type == PH_MODULE_TYPE_WOW64_MODULE) - { - switch (moduleItem->LoadReason) - { - case LoadReasonStaticDependency: - string = L"Static dependency"; - break; - case LoadReasonStaticForwarderDependency: - string = L"Static forwarder dependency"; - break; - case LoadReasonDynamicForwarderDependency: - string = L"Dynamic forwarder dependency"; - break; - case LoadReasonDelayloadDependency: - string = L"Delay load dependency"; - break; - case LoadReasonDynamicLoad: - string = L"Dynamic"; - break; - case LoadReasonAsImageLoad: - string = L"As image"; - break; - case LoadReasonAsDataLoad: - string = L"As data"; - break; - default: - if (WindowsVersion >= WINDOWS_8) - string = L"Unknown"; - else - string = L"N/A"; - break; - } - } - - PhInitializeStringRefLongHint(&getCellText->Text, string); - } - break; - case PHMOTLC_FILEMODIFIEDTIME: - if (moduleItem->FileLastWriteTime.QuadPart != 0) - { - SYSTEMTIME systemTime; - - PhLargeIntegerToLocalSystemTime(&systemTime, &moduleItem->FileLastWriteTime); - PhMoveReference(&node->FileModifiedTimeText, PhFormatDateTime(&systemTime)); - getCellText->Text = node->FileModifiedTimeText->sr; - } - break; - case PHMOTLC_FILESIZE: - if (moduleItem->FileEndOfFile.QuadPart != -1) - { - PhMoveReference(&node->FileSizeText, PhFormatSize(moduleItem->FileEndOfFile.QuadPart, -1)); - getCellText->Text = node->FileSizeText->sr; - } - break; - default: - return FALSE; - } - - getCellText->Flags = TN_CACHE; - } - return TRUE; - case TreeNewGetNodeColor: - { - PPH_TREENEW_GET_NODE_COLOR getNodeColor = Parameter1; - PPH_MODULE_ITEM moduleItem; - - node = (PPH_MODULE_NODE)getNodeColor->Node; - moduleItem = node->ModuleItem; - - if (!moduleItem) - ; // Dummy - else if (PhCsUseColorDotNet && (moduleItem->Flags & LDRP_COR_IMAGE)) - getNodeColor->BackColor = PhCsColorDotNet; - else if (PhCsUseColorImmersiveProcesses && (moduleItem->ImageDllCharacteristics & IMAGE_DLLCHARACTERISTICS_APPCONTAINER)) - getNodeColor->BackColor = PhCsColorImmersiveProcesses; - else if (PhCsUseColorRelocatedModules && (moduleItem->Flags & LDRP_IMAGE_NOT_AT_BASE)) - getNodeColor->BackColor = PhCsColorRelocatedModules; - - getNodeColor->Flags = TN_CACHE | TN_AUTO_FORECOLOR; - } - return TRUE; - case TreeNewGetNodeFont: - { - PPH_TREENEW_GET_NODE_FONT getNodeFont = Parameter1; - - node = (PPH_MODULE_NODE)getNodeFont->Node; - - // Make the executable file module item bold. - if (node->ModuleItem->IsFirst) - { - if (!context->BoldFont) - context->BoldFont = PhDuplicateFontWithNewWeight((HFONT)SendMessage(hwnd, WM_GETFONT, 0, 0), FW_BOLD); - - getNodeFont->Font = context->BoldFont ? context->BoldFont : NULL; - getNodeFont->Flags = TN_CACHE; - return TRUE; - } - } - break; - case TreeNewGetCellTooltip: - { - PPH_TREENEW_GET_CELL_TOOLTIP getCellTooltip = Parameter1; - - node = (PPH_MODULE_NODE)getCellTooltip->Node; - - if (getCellTooltip->Column->Id != 0) - return FALSE; - - if (!node->TooltipText) - { - node->TooltipText = PhFormatImageVersionInfo( - node->ModuleItem->FileName, - &node->ModuleItem->VersionInfo, - NULL, - 0 - ); - - // Make sure we don't try to create the tooltip text again. - if (!node->TooltipText) - node->TooltipText = PhReferenceEmptyString(); - } - - if (!PhIsNullOrEmptyString(node->TooltipText)) - { - getCellTooltip->Text = node->TooltipText->sr; - getCellTooltip->Unfolding = FALSE; - getCellTooltip->Font = NULL; // use default font - getCellTooltip->MaximumWidth = 550; - } - else - { - return FALSE; - } - } - return TRUE; - case TreeNewSortChanged: - { - TreeNew_GetSort(hwnd, &context->TreeNewSortColumn, &context->TreeNewSortOrder); - // Force a rebuild to sort the items. - TreeNew_NodesStructured(hwnd); - } - return TRUE; - case TreeNewKeyDown: - { - PPH_TREENEW_KEY_EVENT keyEvent = Parameter1; - - switch (keyEvent->VirtualKey) - { - case 'C': - if (GetKeyState(VK_CONTROL) < 0) - SendMessage(context->ParentWindowHandle, WM_COMMAND, ID_MODULE_COPY, 0); - break; - case 'A': - if (GetKeyState(VK_CONTROL) < 0) - TreeNew_SelectRange(context->TreeNewHandle, 0, -1); - break; - case 'M': - if (GetKeyState(VK_CONTROL) < 0) - SendMessage(context->ParentWindowHandle, WM_COMMAND, ID_MODULE_SEARCHONLINE, 0); - break; - case VK_DELETE: - SendMessage(context->ParentWindowHandle, WM_COMMAND, ID_MODULE_UNLOAD, 0); - break; - case VK_RETURN: - if (GetKeyState(VK_CONTROL) >= 0) - SendMessage(context->ParentWindowHandle, WM_COMMAND, ID_MODULE_INSPECT, 0); - else - SendMessage(context->ParentWindowHandle, WM_COMMAND, ID_MODULE_OPENFILELOCATION, 0); - break; - } - } - return TRUE; - case TreeNewHeaderRightClick: - { - PH_TN_COLUMN_MENU_DATA data; - - data.TreeNewHandle = hwnd; - data.MouseEvent = Parameter1; - data.DefaultSortColumn = 0; - data.DefaultSortOrder = NoSortOrder; - PhInitializeTreeNewColumnMenuEx(&data, PH_TN_COLUMN_MENU_SHOW_RESET_SORT); - - data.Selection = PhShowEMenu(data.Menu, hwnd, PH_EMENU_SHOW_LEFTRIGHT, - PH_ALIGN_LEFT | PH_ALIGN_TOP, data.MouseEvent->ScreenLocation.x, data.MouseEvent->ScreenLocation.y); - PhHandleTreeNewColumnMenu(&data); - PhDeleteTreeNewColumnMenu(&data); - } - return TRUE; - case TreeNewLeftDoubleClick: - { - SendMessage(context->ParentWindowHandle, WM_COMMAND, ID_MODULE_INSPECT, 0); - } - return TRUE; - case TreeNewContextMenu: - { - PPH_TREENEW_CONTEXT_MENU contextMenu = Parameter1; - - SendMessage(context->ParentWindowHandle, WM_COMMAND, ID_SHOWCONTEXTMENU, (LPARAM)contextMenu); - } - return TRUE; - case TreeNewGetDialogCode: - { - PULONG code = Parameter2; - - if (PtrToUlong(Parameter1) == VK_RETURN) - { - *code = DLGC_WANTMESSAGE; - return TRUE; - } - } - return FALSE; - } - - return FALSE; -} - -PPH_MODULE_ITEM PhGetSelectedModuleItem( - _In_ PPH_MODULE_LIST_CONTEXT Context - ) -{ - PPH_MODULE_ITEM moduleItem = NULL; - ULONG i; - - for (i = 0; i < Context->NodeList->Count; i++) - { - PPH_MODULE_NODE node = Context->NodeList->Items[i]; - - if (node->Node.Selected) - { - moduleItem = node->ModuleItem; - break; - } - } - - return moduleItem; -} - -VOID PhGetSelectedModuleItems( - _In_ PPH_MODULE_LIST_CONTEXT Context, - _Out_ PPH_MODULE_ITEM **Modules, - _Out_ PULONG NumberOfModules - ) -{ - PH_ARRAY array; - ULONG i; - - PhInitializeArray(&array, sizeof(PVOID), 2); - - for (i = 0; i < Context->NodeList->Count; i++) - { - PPH_MODULE_NODE node = Context->NodeList->Items[i]; - - if (node->Node.Selected) - PhAddItemArray(&array, &node->ModuleItem); - } - - *NumberOfModules = (ULONG)array.Count; - *Modules = PhFinalArrayItems(&array); -} - -VOID PhDeselectAllModuleNodes( - _In_ PPH_MODULE_LIST_CONTEXT Context - ) -{ - TreeNew_DeselectRange(Context->TreeNewHandle, 0, -1); -} +/* + * Process Hacker - + * module list + * + * Copyright (C) 2010-2016 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include +#include + +#include +#include + +#include +#include +#include +#include + +BOOLEAN PhpModuleNodeHashtableEqualFunction( + _In_ PVOID Entry1, + _In_ PVOID Entry2 + ); + +ULONG PhpModuleNodeHashtableHashFunction( + _In_ PVOID Entry + ); + +VOID PhpDestroyModuleNode( + _In_ PPH_MODULE_NODE ModuleNode + ); + +VOID PhpRemoveModuleNode( + _In_ PPH_MODULE_NODE ModuleNode, + _In_ PPH_MODULE_LIST_CONTEXT Context + ); + +LONG PhpModuleTreeNewPostSortFunction( + _In_ LONG Result, + _In_ PVOID Node1, + _In_ PVOID Node2, + _In_ PH_SORT_ORDER SortOrder + ); + +BOOLEAN NTAPI PhpModuleTreeNewCallback( + _In_ HWND hwnd, + _In_ PH_TREENEW_MESSAGE Message, + _In_opt_ PVOID Parameter1, + _In_opt_ PVOID Parameter2, + _In_opt_ PVOID Context + ); + +VOID PhInitializeModuleList( + _In_ HWND ParentWindowHandle, + _In_ HWND TreeNewHandle, + _Out_ PPH_MODULE_LIST_CONTEXT Context + ) +{ + HWND hwnd; + + memset(Context, 0, sizeof(PH_MODULE_LIST_CONTEXT)); + Context->EnableStateHighlighting = TRUE; + + Context->NodeHashtable = PhCreateHashtable( + sizeof(PPH_MODULE_NODE), + PhpModuleNodeHashtableEqualFunction, + PhpModuleNodeHashtableHashFunction, + 100 + ); + Context->NodeList = PhCreateList(100); + + Context->ParentWindowHandle = ParentWindowHandle; + Context->TreeNewHandle = TreeNewHandle; + hwnd = TreeNewHandle; + PhSetControlTheme(hwnd, L"explorer"); + + TreeNew_SetCallback(hwnd, PhpModuleTreeNewCallback, Context); + + TreeNew_SetRedraw(hwnd, FALSE); + + // Default columns + PhAddTreeNewColumn(hwnd, PHMOTLC_NAME, TRUE, L"Name", 100, PH_ALIGN_LEFT, -2, 0); + PhAddTreeNewColumn(hwnd, PHMOTLC_BASEADDRESS, TRUE, L"Base address", 80, PH_ALIGN_RIGHT, 0, DT_RIGHT); + PhAddTreeNewColumnEx(hwnd, PHMOTLC_SIZE, TRUE, L"Size", 60, PH_ALIGN_RIGHT, 1, DT_RIGHT, TRUE); + PhAddTreeNewColumn(hwnd, PHMOTLC_DESCRIPTION, TRUE, L"Description", 160, PH_ALIGN_LEFT, 2, 0); + + PhAddTreeNewColumn(hwnd, PHMOTLC_COMPANYNAME, FALSE, L"Company name", 180, PH_ALIGN_LEFT, -1, 0); + PhAddTreeNewColumn(hwnd, PHMOTLC_VERSION, FALSE, L"Version", 100, PH_ALIGN_LEFT, -1, 0); + PhAddTreeNewColumn(hwnd, PHMOTLC_FILENAME, FALSE, L"File name", 180, PH_ALIGN_LEFT, -1, DT_PATH_ELLIPSIS); + + PhAddTreeNewColumn(hwnd, PHMOTLC_TYPE, FALSE, L"Type", 80, PH_ALIGN_LEFT, -1, 0); + PhAddTreeNewColumnEx(hwnd, PHMOTLC_LOADCOUNT, FALSE, L"Load count", 40, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); + PhAddTreeNewColumn(hwnd, PHMOTLC_VERIFICATIONSTATUS, FALSE, L"Verification status", 70, PH_ALIGN_LEFT, -1, 0); + PhAddTreeNewColumn(hwnd, PHMOTLC_VERIFIEDSIGNER, FALSE, L"Verified signer", 100, PH_ALIGN_LEFT, -1, 0); + PhAddTreeNewColumnEx(hwnd, PHMOTLC_ASLR, FALSE, L"ASLR", 50, PH_ALIGN_LEFT, -1, 0, TRUE); + PhAddTreeNewColumnEx(hwnd, PHMOTLC_TIMESTAMP, FALSE, L"Time stamp", 100, PH_ALIGN_LEFT, -1, 0, TRUE); + PhAddTreeNewColumnEx(hwnd, PHMOTLC_CFGUARD, FALSE, L"CF Guard", 70, PH_ALIGN_LEFT, -1, 0, TRUE); + PhAddTreeNewColumnEx(hwnd, PHMOTLC_LOADTIME, FALSE, L"Load time", 100, PH_ALIGN_LEFT, -1, 0, TRUE); + PhAddTreeNewColumn(hwnd, PHMOTLC_LOADREASON, FALSE, L"Load reason", 80, PH_ALIGN_LEFT, -1, 0); + PhAddTreeNewColumnEx(hwnd, PHMOTLC_FILEMODIFIEDTIME, FALSE, L"File modified time", 140, PH_ALIGN_LEFT, -1, 0, TRUE); + PhAddTreeNewColumnEx(hwnd, PHMOTLC_FILESIZE, FALSE, L"File size", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); + + TreeNew_SetRedraw(hwnd, TRUE); + + TreeNew_SetTriState(hwnd, TRUE); + TreeNew_SetSort(hwnd, 0, NoSortOrder); + + PhCmInitializeManager(&Context->Cm, hwnd, PHMOTLC_MAXIMUM, PhpModuleTreeNewPostSortFunction); +} + +VOID PhDeleteModuleList( + _In_ PPH_MODULE_LIST_CONTEXT Context + ) +{ + ULONG i; + + if (Context->BoldFont) + DeleteObject(Context->BoldFont); + + PhCmDeleteManager(&Context->Cm); + + for (i = 0; i < Context->NodeList->Count; i++) + PhpDestroyModuleNode(Context->NodeList->Items[i]); + + PhDereferenceObject(Context->NodeHashtable); + PhDereferenceObject(Context->NodeList); +} + +BOOLEAN PhpModuleNodeHashtableEqualFunction( + _In_ PVOID Entry1, + _In_ PVOID Entry2 + ) +{ + PPH_MODULE_NODE moduleNode1 = *(PPH_MODULE_NODE *)Entry1; + PPH_MODULE_NODE moduleNode2 = *(PPH_MODULE_NODE *)Entry2; + + return moduleNode1->ModuleItem == moduleNode2->ModuleItem; +} + +ULONG PhpModuleNodeHashtableHashFunction( + _In_ PVOID Entry + ) +{ + return PhHashIntPtr((ULONG_PTR)(*(PPH_MODULE_NODE *)Entry)->ModuleItem); +} + +VOID PhLoadSettingsModuleList( + _Inout_ PPH_MODULE_LIST_CONTEXT Context + ) +{ + PPH_STRING settings; + PPH_STRING sortSettings; + + settings = PhGetStringSetting(L"ModuleTreeListColumns"); + sortSettings = PhGetStringSetting(L"ModuleTreeListSort"); + PhCmLoadSettingsEx(Context->TreeNewHandle, &Context->Cm, 0, &settings->sr, &sortSettings->sr); + PhDereferenceObject(settings); + PhDereferenceObject(sortSettings); +} + +VOID PhSaveSettingsModuleList( + _Inout_ PPH_MODULE_LIST_CONTEXT Context + ) +{ + PPH_STRING settings; + PPH_STRING sortSettings; + + settings = PhCmSaveSettingsEx(Context->TreeNewHandle, &Context->Cm, 0, &sortSettings); + PhSetStringSetting2(L"ModuleTreeListColumns", &settings->sr); + PhSetStringSetting2(L"ModuleTreeListSort", &sortSettings->sr); + PhDereferenceObject(settings); + PhDereferenceObject(sortSettings); +} + +PPH_MODULE_NODE PhAddModuleNode( + _Inout_ PPH_MODULE_LIST_CONTEXT Context, + _In_ PPH_MODULE_ITEM ModuleItem, + _In_ ULONG RunId + ) +{ + PPH_MODULE_NODE moduleNode; + + moduleNode = PhAllocate(PhEmGetObjectSize(EmModuleNodeType, sizeof(PH_MODULE_NODE))); + memset(moduleNode, 0, sizeof(PH_MODULE_NODE)); + PhInitializeTreeNewNode(&moduleNode->Node); + + if (Context->EnableStateHighlighting && RunId != 1) + { + PhChangeShStateTn( + &moduleNode->Node, + &moduleNode->ShState, + &Context->NodeStateList, + NewItemState, + PhCsColorNew, + NULL + ); + } + + moduleNode->ModuleItem = ModuleItem; + PhReferenceObject(ModuleItem); + + memset(moduleNode->TextCache, 0, sizeof(PH_STRINGREF) * PHMOTLC_MAXIMUM); + moduleNode->Node.TextCache = moduleNode->TextCache; + moduleNode->Node.TextCacheSize = PHMOTLC_MAXIMUM; + + PhAddEntryHashtable(Context->NodeHashtable, &moduleNode); + PhAddItemList(Context->NodeList, moduleNode); + + PhEmCallObjectOperation(EmModuleNodeType, moduleNode, EmObjectCreate); + + TreeNew_NodesStructured(Context->TreeNewHandle); + + return moduleNode; +} + +PPH_MODULE_NODE PhFindModuleNode( + _In_ PPH_MODULE_LIST_CONTEXT Context, + _In_ PPH_MODULE_ITEM ModuleItem + ) +{ + PH_MODULE_NODE lookupModuleNode; + PPH_MODULE_NODE lookupModuleNodePtr = &lookupModuleNode; + PPH_MODULE_NODE *moduleNode; + + lookupModuleNode.ModuleItem = ModuleItem; + + moduleNode = (PPH_MODULE_NODE *)PhFindEntryHashtable( + Context->NodeHashtable, + &lookupModuleNodePtr + ); + + if (moduleNode) + return *moduleNode; + else + return NULL; +} + +VOID PhRemoveModuleNode( + _In_ PPH_MODULE_LIST_CONTEXT Context, + _In_ PPH_MODULE_NODE ModuleNode + ) +{ + // Remove from the hashtable here to avoid problems in case the key is re-used. + PhRemoveEntryHashtable(Context->NodeHashtable, &ModuleNode); + + if (Context->EnableStateHighlighting) + { + PhChangeShStateTn( + &ModuleNode->Node, + &ModuleNode->ShState, + &Context->NodeStateList, + RemovingItemState, + PhCsColorRemoved, + Context->TreeNewHandle + ); + } + else + { + PhpRemoveModuleNode(ModuleNode, Context); + } +} + +VOID PhpDestroyModuleNode( + _In_ PPH_MODULE_NODE ModuleNode + ) +{ + PhEmCallObjectOperation(EmModuleNodeType, ModuleNode, EmObjectDelete); + + PhClearReference(&ModuleNode->TooltipText); + + PhClearReference(&ModuleNode->SizeText); + PhClearReference(&ModuleNode->TimeStampText); + PhClearReference(&ModuleNode->LoadTimeText); + PhClearReference(&ModuleNode->FileModifiedTimeText); + PhClearReference(&ModuleNode->FileSizeText); + + PhDereferenceObject(ModuleNode->ModuleItem); + + PhFree(ModuleNode); +} + +VOID PhpRemoveModuleNode( + _In_ PPH_MODULE_NODE ModuleNode, + _In_ PPH_MODULE_LIST_CONTEXT Context // PH_TICK_SH_STATE requires this parameter to be after ModuleNode + ) +{ + ULONG index; + + // Remove from list and cleanup. + + if ((index = PhFindItemList(Context->NodeList, ModuleNode)) != -1) + PhRemoveItemList(Context->NodeList, index); + + PhpDestroyModuleNode(ModuleNode); + + TreeNew_NodesStructured(Context->TreeNewHandle); +} + +VOID PhUpdateModuleNode( + _In_ PPH_MODULE_LIST_CONTEXT Context, + _In_ PPH_MODULE_NODE ModuleNode + ) +{ + memset(ModuleNode->TextCache, 0, sizeof(PH_STRINGREF) * PHMOTLC_MAXIMUM); + PhClearReference(&ModuleNode->TooltipText); + + ModuleNode->ValidMask = 0; + PhInvalidateTreeNewNode(&ModuleNode->Node, TN_CACHE_COLOR); + TreeNew_NodesStructured(Context->TreeNewHandle); +} + +VOID PhTickModuleNodes( + _In_ PPH_MODULE_LIST_CONTEXT Context + ) +{ + PH_TICK_SH_STATE_TN(PH_MODULE_NODE, ShState, Context->NodeStateList, PhpRemoveModuleNode, PhCsHighlightingDuration, Context->TreeNewHandle, TRUE, NULL, Context); +} + +#define SORT_FUNCTION(Column) PhpModuleTreeNewCompare##Column + +#define BEGIN_SORT_FUNCTION(Column) static int __cdecl PhpModuleTreeNewCompare##Column( \ + _In_ void *_context, \ + _In_ const void *_elem1, \ + _In_ const void *_elem2 \ + ) \ +{ \ + PPH_MODULE_NODE node1 = *(PPH_MODULE_NODE *)_elem1; \ + PPH_MODULE_NODE node2 = *(PPH_MODULE_NODE *)_elem2; \ + PPH_MODULE_ITEM moduleItem1 = node1->ModuleItem; \ + PPH_MODULE_ITEM moduleItem2 = node2->ModuleItem; \ + int sortResult = 0; + +#define END_SORT_FUNCTION \ + if (sortResult == 0) \ + sortResult = uintptrcmp((ULONG_PTR)moduleItem1->BaseAddress, (ULONG_PTR)moduleItem2->BaseAddress); \ + \ + return PhModifySort(sortResult, ((PPH_MODULE_LIST_CONTEXT)_context)->TreeNewSortOrder); \ +} + +LONG PhpModuleTreeNewPostSortFunction( + _In_ LONG Result, + _In_ PVOID Node1, + _In_ PVOID Node2, + _In_ PH_SORT_ORDER SortOrder + ) +{ + if (Result == 0) + Result = uintptrcmp((ULONG_PTR)((PPH_MODULE_NODE)Node1)->ModuleItem->BaseAddress, (ULONG_PTR)((PPH_MODULE_NODE)Node2)->ModuleItem->BaseAddress); + + return PhModifySort(Result, SortOrder); +} + +BEGIN_SORT_FUNCTION(TriState) +{ + if (moduleItem1->IsFirst) + { + sortResult = -1; + } + else if (moduleItem2->IsFirst) + { + sortResult = 1; + } + else + { + sortResult = PhCompareString(moduleItem1->Name, moduleItem2->Name, TRUE); // fall back to sorting by name + } +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(Name) +{ + sortResult = PhCompareString(moduleItem1->Name, moduleItem2->Name, TRUE); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(BaseAddress) +{ + sortResult = uintptrcmp((ULONG_PTR)moduleItem1->BaseAddress, (ULONG_PTR)moduleItem2->BaseAddress); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(Size) +{ + sortResult = uintcmp(moduleItem1->Size, moduleItem2->Size); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(Description) +{ + sortResult = PhCompareStringWithNull(moduleItem1->VersionInfo.FileDescription, moduleItem2->VersionInfo.FileDescription, TRUE); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(CompanyName) +{ + sortResult = PhCompareStringWithNull(moduleItem1->VersionInfo.CompanyName, moduleItem2->VersionInfo.CompanyName, TRUE); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(Version) +{ + sortResult = PhCompareStringWithNull(moduleItem1->VersionInfo.FileVersion, moduleItem2->VersionInfo.FileVersion, TRUE); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(FileName) +{ + sortResult = PhCompareStringWithNull(moduleItem1->FileName, moduleItem2->FileName, TRUE); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(Type) +{ + sortResult = uintcmp(moduleItem1->Type, moduleItem2->Type); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(LoadCount) +{ + sortResult = uintcmp(moduleItem1->LoadCount, moduleItem2->LoadCount); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(VerificationStatus) +{ + sortResult = intcmp(moduleItem1->VerifyResult, moduleItem2->VerifyResult); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(VerifiedSigner) +{ + sortResult = PhCompareStringWithNull( + moduleItem1->VerifySignerName, + moduleItem2->VerifySignerName, + TRUE + ); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(Aslr) +{ + sortResult = intcmp( + moduleItem1->ImageDllCharacteristics & IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE, + moduleItem2->ImageDllCharacteristics & IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE + ); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(TimeStamp) +{ + sortResult = uintcmp(moduleItem1->ImageTimeDateStamp, moduleItem2->ImageTimeDateStamp); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(CfGuard) +{ + sortResult = intcmp( + moduleItem1->ImageDllCharacteristics & IMAGE_DLLCHARACTERISTICS_GUARD_CF, + moduleItem2->ImageDllCharacteristics & IMAGE_DLLCHARACTERISTICS_GUARD_CF + ); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(LoadTime) +{ + sortResult = uint64cmp(moduleItem1->LoadTime.QuadPart, moduleItem2->LoadTime.QuadPart); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(LoadReason) +{ + sortResult = uintcmp(moduleItem1->LoadReason, moduleItem2->LoadReason); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(FileModifiedTime) +{ + sortResult = int64cmp(moduleItem1->FileLastWriteTime.QuadPart, moduleItem2->FileLastWriteTime.QuadPart); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(FileSize) +{ + sortResult = int64cmp(moduleItem1->FileEndOfFile.QuadPart, moduleItem2->FileEndOfFile.QuadPart); +} +END_SORT_FUNCTION + +BOOLEAN NTAPI PhpModuleTreeNewCallback( + _In_ HWND hwnd, + _In_ PH_TREENEW_MESSAGE Message, + _In_opt_ PVOID Parameter1, + _In_opt_ PVOID Parameter2, + _In_opt_ PVOID Context + ) +{ + PPH_MODULE_LIST_CONTEXT context; + PPH_MODULE_NODE node; + + context = Context; + + if (PhCmForwardMessage(hwnd, Message, Parameter1, Parameter2, &context->Cm)) + return TRUE; + + switch (Message) + { + case TreeNewGetChildren: + { + PPH_TREENEW_GET_CHILDREN getChildren = Parameter1; + + if (!getChildren->Node) + { + static PVOID sortFunctions[] = + { + SORT_FUNCTION(Name), + SORT_FUNCTION(BaseAddress), + SORT_FUNCTION(Size), + SORT_FUNCTION(Description), + SORT_FUNCTION(CompanyName), + SORT_FUNCTION(Version), + SORT_FUNCTION(FileName), + SORT_FUNCTION(Type), + SORT_FUNCTION(LoadCount), + SORT_FUNCTION(VerificationStatus), + SORT_FUNCTION(VerifiedSigner), + SORT_FUNCTION(Aslr), + SORT_FUNCTION(TimeStamp), + SORT_FUNCTION(CfGuard), + SORT_FUNCTION(LoadTime), + SORT_FUNCTION(LoadReason), + SORT_FUNCTION(FileModifiedTime), + SORT_FUNCTION(FileSize) + }; + int (__cdecl *sortFunction)(void *, const void *, const void *); + + if (context->TreeNewSortOrder == NoSortOrder) + { + sortFunction = SORT_FUNCTION(TriState); + } + else + { + if (!PhCmForwardSort( + (PPH_TREENEW_NODE *)context->NodeList->Items, + context->NodeList->Count, + context->TreeNewSortColumn, + context->TreeNewSortOrder, + &context->Cm + )) + { + if (context->TreeNewSortColumn < PHMOTLC_MAXIMUM) + sortFunction = sortFunctions[context->TreeNewSortColumn]; + else + sortFunction = NULL; + } + else + { + sortFunction = NULL; + } + } + + if (sortFunction) + { + qsort_s(context->NodeList->Items, context->NodeList->Count, sizeof(PVOID), sortFunction, context); + } + + getChildren->Children = (PPH_TREENEW_NODE *)context->NodeList->Items; + getChildren->NumberOfChildren = context->NodeList->Count; + } + } + return TRUE; + case TreeNewIsLeaf: + { + PPH_TREENEW_IS_LEAF isLeaf = Parameter1; + + isLeaf->IsLeaf = TRUE; + } + return TRUE; + case TreeNewGetCellText: + { + PPH_TREENEW_GET_CELL_TEXT getCellText = Parameter1; + PPH_MODULE_ITEM moduleItem; + + node = (PPH_MODULE_NODE)getCellText->Node; + moduleItem = node->ModuleItem; + + switch (getCellText->Id) + { + case PHMOTLC_NAME: + getCellText->Text = moduleItem->Name->sr; + break; + case PHMOTLC_BASEADDRESS: + PhInitializeStringRefLongHint(&getCellText->Text, moduleItem->BaseAddressString); + break; + case PHMOTLC_SIZE: + if (!node->SizeText) + node->SizeText = PhFormatSize(moduleItem->Size, -1); + getCellText->Text = PhGetStringRef(node->SizeText); + break; + case PHMOTLC_DESCRIPTION: + getCellText->Text = PhGetStringRef(moduleItem->VersionInfo.FileDescription); + break; + case PHMOTLC_COMPANYNAME: + getCellText->Text = PhGetStringRef(moduleItem->VersionInfo.CompanyName); + break; + case PHMOTLC_VERSION: + getCellText->Text = PhGetStringRef(moduleItem->VersionInfo.FileVersion); + break; + case PHMOTLC_FILENAME: + getCellText->Text = PhGetStringRef(moduleItem->FileName); + break; + case PHMOTLC_TYPE: + { + PWSTR typeString; + + switch (moduleItem->Type) + { + case PH_MODULE_TYPE_MODULE: + typeString = L"DLL"; + break; + case PH_MODULE_TYPE_MAPPED_FILE: + typeString = L"Mapped file"; + break; + case PH_MODULE_TYPE_MAPPED_IMAGE: + typeString = L"Mapped image"; + break; + case PH_MODULE_TYPE_WOW64_MODULE: + typeString = L"WOW64 DLL"; + break; + case PH_MODULE_TYPE_KERNEL_MODULE: + typeString = L"Kernel module"; + break; + default: + typeString = L"Unknown"; + break; + } + + PhInitializeStringRefLongHint(&getCellText->Text, typeString); + } + break; + case PHMOTLC_LOADCOUNT: + if (moduleItem->Type == PH_MODULE_TYPE_MODULE || moduleItem->Type == PH_MODULE_TYPE_KERNEL_MODULE || + moduleItem->Type == PH_MODULE_TYPE_WOW64_MODULE) + { + if (moduleItem->LoadCount != (USHORT)-1) + { + PhPrintInt32(node->LoadCountText, moduleItem->LoadCount); + PhInitializeStringRefLongHint(&getCellText->Text, node->LoadCountText); + } + else + { + PhInitializeStringRef(&getCellText->Text, L"Static"); + } + } + else + { + PhInitializeEmptyStringRef(&getCellText->Text); + } + break; + case PHMOTLC_VERIFICATIONSTATUS: + if (moduleItem->Type == PH_MODULE_TYPE_MODULE || moduleItem->Type == PH_MODULE_TYPE_KERNEL_MODULE || + moduleItem->Type == PH_MODULE_TYPE_WOW64_MODULE || moduleItem->Type == PH_MODULE_TYPE_MAPPED_IMAGE) + { + PhInitializeStringRef(&getCellText->Text, + moduleItem->VerifyResult == VrTrusted ? L"Trusted" : L"Not trusted"); + } + else + { + PhInitializeEmptyStringRef(&getCellText->Text); + } + break; + case PHMOTLC_VERIFIEDSIGNER: + getCellText->Text = PhGetStringRef(moduleItem->VerifySignerName); + break; + case PHMOTLC_ASLR: + if (WindowsVersion >= WINDOWS_VISTA) + { + if (moduleItem->ImageDllCharacteristics & IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE) + PhInitializeStringRef(&getCellText->Text, L"ASLR"); + } + else + { + PhInitializeStringRef(&getCellText->Text, L"N/A"); + } + break; + case PHMOTLC_TIMESTAMP: + { + LARGE_INTEGER time; + SYSTEMTIME systemTime; + + if (moduleItem->ImageTimeDateStamp != 0) + { + RtlSecondsSince1970ToTime(moduleItem->ImageTimeDateStamp, &time); + PhLargeIntegerToLocalSystemTime(&systemTime, &time); + PhMoveReference(&node->TimeStampText, PhFormatDateTime(&systemTime)); + getCellText->Text = node->TimeStampText->sr; + } + else + { + PhInitializeEmptyStringRef(&getCellText->Text); + } + } + break; + case PHMOTLC_CFGUARD: + if (WindowsVersion >= WINDOWS_8_1) + { + if (moduleItem->ImageDllCharacteristics & IMAGE_DLLCHARACTERISTICS_GUARD_CF) + PhInitializeStringRef(&getCellText->Text, L"CF Guard"); + } + else + { + PhInitializeStringRef(&getCellText->Text, L"N/A"); + } + break; + case PHMOTLC_LOADTIME: + { + SYSTEMTIME systemTime; + + if (moduleItem->LoadTime.QuadPart != 0) + { + PhLargeIntegerToLocalSystemTime(&systemTime, &moduleItem->LoadTime); + PhMoveReference(&node->LoadTimeText, PhFormatDateTime(&systemTime)); + getCellText->Text = node->LoadTimeText->sr; + } + else + { + PhInitializeEmptyStringRef(&getCellText->Text); + } + } + break; + case PHMOTLC_LOADREASON: + { + PWSTR string = L""; + + if (moduleItem->Type == PH_MODULE_TYPE_MODULE || moduleItem->Type == PH_MODULE_TYPE_WOW64_MODULE) + { + switch (moduleItem->LoadReason) + { + case LoadReasonStaticDependency: + string = L"Static dependency"; + break; + case LoadReasonStaticForwarderDependency: + string = L"Static forwarder dependency"; + break; + case LoadReasonDynamicForwarderDependency: + string = L"Dynamic forwarder dependency"; + break; + case LoadReasonDelayloadDependency: + string = L"Delay load dependency"; + break; + case LoadReasonDynamicLoad: + string = L"Dynamic"; + break; + case LoadReasonAsImageLoad: + string = L"As image"; + break; + case LoadReasonAsDataLoad: + string = L"As data"; + break; + default: + if (WindowsVersion >= WINDOWS_8) + string = L"Unknown"; + else + string = L"N/A"; + break; + } + } + + PhInitializeStringRefLongHint(&getCellText->Text, string); + } + break; + case PHMOTLC_FILEMODIFIEDTIME: + if (moduleItem->FileLastWriteTime.QuadPart != 0) + { + SYSTEMTIME systemTime; + + PhLargeIntegerToLocalSystemTime(&systemTime, &moduleItem->FileLastWriteTime); + PhMoveReference(&node->FileModifiedTimeText, PhFormatDateTime(&systemTime)); + getCellText->Text = node->FileModifiedTimeText->sr; + } + break; + case PHMOTLC_FILESIZE: + if (moduleItem->FileEndOfFile.QuadPart != -1) + { + PhMoveReference(&node->FileSizeText, PhFormatSize(moduleItem->FileEndOfFile.QuadPart, -1)); + getCellText->Text = node->FileSizeText->sr; + } + break; + default: + return FALSE; + } + + getCellText->Flags = TN_CACHE; + } + return TRUE; + case TreeNewGetNodeColor: + { + PPH_TREENEW_GET_NODE_COLOR getNodeColor = Parameter1; + PPH_MODULE_ITEM moduleItem; + + node = (PPH_MODULE_NODE)getNodeColor->Node; + moduleItem = node->ModuleItem; + + if (!moduleItem) + ; // Dummy + else if (PhCsUseColorDotNet && (moduleItem->Flags & LDRP_COR_IMAGE)) + getNodeColor->BackColor = PhCsColorDotNet; + else if (PhCsUseColorImmersiveProcesses && (moduleItem->ImageDllCharacteristics & IMAGE_DLLCHARACTERISTICS_APPCONTAINER)) + getNodeColor->BackColor = PhCsColorImmersiveProcesses; + else if (PhCsUseColorRelocatedModules && (moduleItem->Flags & LDRP_IMAGE_NOT_AT_BASE)) + getNodeColor->BackColor = PhCsColorRelocatedModules; + + getNodeColor->Flags = TN_CACHE | TN_AUTO_FORECOLOR; + } + return TRUE; + case TreeNewGetNodeFont: + { + PPH_TREENEW_GET_NODE_FONT getNodeFont = Parameter1; + + node = (PPH_MODULE_NODE)getNodeFont->Node; + + // Make the executable file module item bold. + if (node->ModuleItem->IsFirst) + { + if (!context->BoldFont) + context->BoldFont = PhDuplicateFontWithNewWeight((HFONT)SendMessage(hwnd, WM_GETFONT, 0, 0), FW_BOLD); + + getNodeFont->Font = context->BoldFont ? context->BoldFont : NULL; + getNodeFont->Flags = TN_CACHE; + return TRUE; + } + } + break; + case TreeNewGetCellTooltip: + { + PPH_TREENEW_GET_CELL_TOOLTIP getCellTooltip = Parameter1; + + node = (PPH_MODULE_NODE)getCellTooltip->Node; + + if (getCellTooltip->Column->Id != 0) + return FALSE; + + if (!node->TooltipText) + { + node->TooltipText = PhFormatImageVersionInfo( + node->ModuleItem->FileName, + &node->ModuleItem->VersionInfo, + NULL, + 0 + ); + + // Make sure we don't try to create the tooltip text again. + if (!node->TooltipText) + node->TooltipText = PhReferenceEmptyString(); + } + + if (!PhIsNullOrEmptyString(node->TooltipText)) + { + getCellTooltip->Text = node->TooltipText->sr; + getCellTooltip->Unfolding = FALSE; + getCellTooltip->Font = NULL; // use default font + getCellTooltip->MaximumWidth = 550; + } + else + { + return FALSE; + } + } + return TRUE; + case TreeNewSortChanged: + { + TreeNew_GetSort(hwnd, &context->TreeNewSortColumn, &context->TreeNewSortOrder); + // Force a rebuild to sort the items. + TreeNew_NodesStructured(hwnd); + } + return TRUE; + case TreeNewKeyDown: + { + PPH_TREENEW_KEY_EVENT keyEvent = Parameter1; + + switch (keyEvent->VirtualKey) + { + case 'C': + if (GetKeyState(VK_CONTROL) < 0) + SendMessage(context->ParentWindowHandle, WM_COMMAND, ID_MODULE_COPY, 0); + break; + case 'A': + if (GetKeyState(VK_CONTROL) < 0) + TreeNew_SelectRange(context->TreeNewHandle, 0, -1); + break; + case 'M': + if (GetKeyState(VK_CONTROL) < 0) + SendMessage(context->ParentWindowHandle, WM_COMMAND, ID_MODULE_SEARCHONLINE, 0); + break; + case VK_DELETE: + SendMessage(context->ParentWindowHandle, WM_COMMAND, ID_MODULE_UNLOAD, 0); + break; + case VK_RETURN: + if (GetKeyState(VK_CONTROL) >= 0) + SendMessage(context->ParentWindowHandle, WM_COMMAND, ID_MODULE_INSPECT, 0); + else + SendMessage(context->ParentWindowHandle, WM_COMMAND, ID_MODULE_OPENFILELOCATION, 0); + break; + } + } + return TRUE; + case TreeNewHeaderRightClick: + { + PH_TN_COLUMN_MENU_DATA data; + + data.TreeNewHandle = hwnd; + data.MouseEvent = Parameter1; + data.DefaultSortColumn = 0; + data.DefaultSortOrder = NoSortOrder; + PhInitializeTreeNewColumnMenuEx(&data, PH_TN_COLUMN_MENU_SHOW_RESET_SORT); + + data.Selection = PhShowEMenu(data.Menu, hwnd, PH_EMENU_SHOW_LEFTRIGHT, + PH_ALIGN_LEFT | PH_ALIGN_TOP, data.MouseEvent->ScreenLocation.x, data.MouseEvent->ScreenLocation.y); + PhHandleTreeNewColumnMenu(&data); + PhDeleteTreeNewColumnMenu(&data); + } + return TRUE; + case TreeNewLeftDoubleClick: + { + SendMessage(context->ParentWindowHandle, WM_COMMAND, ID_MODULE_INSPECT, 0); + } + return TRUE; + case TreeNewContextMenu: + { + PPH_TREENEW_CONTEXT_MENU contextMenu = Parameter1; + + SendMessage(context->ParentWindowHandle, WM_COMMAND, ID_SHOWCONTEXTMENU, (LPARAM)contextMenu); + } + return TRUE; + case TreeNewGetDialogCode: + { + PULONG code = Parameter2; + + if (PtrToUlong(Parameter1) == VK_RETURN) + { + *code = DLGC_WANTMESSAGE; + return TRUE; + } + } + return FALSE; + } + + return FALSE; +} + +PPH_MODULE_ITEM PhGetSelectedModuleItem( + _In_ PPH_MODULE_LIST_CONTEXT Context + ) +{ + PPH_MODULE_ITEM moduleItem = NULL; + ULONG i; + + for (i = 0; i < Context->NodeList->Count; i++) + { + PPH_MODULE_NODE node = Context->NodeList->Items[i]; + + if (node->Node.Selected) + { + moduleItem = node->ModuleItem; + break; + } + } + + return moduleItem; +} + +VOID PhGetSelectedModuleItems( + _In_ PPH_MODULE_LIST_CONTEXT Context, + _Out_ PPH_MODULE_ITEM **Modules, + _Out_ PULONG NumberOfModules + ) +{ + PH_ARRAY array; + ULONG i; + + PhInitializeArray(&array, sizeof(PVOID), 2); + + for (i = 0; i < Context->NodeList->Count; i++) + { + PPH_MODULE_NODE node = Context->NodeList->Items[i]; + + if (node->Node.Selected) + PhAddItemArray(&array, &node->ModuleItem); + } + + *NumberOfModules = (ULONG)array.Count; + *Modules = PhFinalArrayItems(&array); +} + +VOID PhDeselectAllModuleNodes( + _In_ PPH_MODULE_LIST_CONTEXT Context + ) +{ + TreeNew_DeselectRange(Context->TreeNewHandle, 0, -1); +} diff --git a/ProcessHacker/modprv.c b/ProcessHacker/modprv.c index f3483ad3ef41..30c04ac6af7b 100644 --- a/ProcessHacker/modprv.c +++ b/ProcessHacker/modprv.c @@ -1,589 +1,589 @@ -/* - * Process Hacker - - * module provider - * - * Copyright (C) 2009-2016 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include -#include - -#include -#include -#include - -#include -#include - -typedef struct _PH_MODULE_QUERY_DATA -{ - SLIST_ENTRY ListEntry; - PPH_MODULE_PROVIDER ModuleProvider; - PPH_MODULE_ITEM ModuleItem; - - VERIFY_RESULT VerifyResult; - PPH_STRING VerifySignerName; -} PH_MODULE_QUERY_DATA, *PPH_MODULE_QUERY_DATA; - -VOID NTAPI PhpModuleProviderDeleteProcedure( - _In_ PVOID Object, - _In_ ULONG Flags - ); - -VOID NTAPI PhpModuleItemDeleteProcedure( - _In_ PVOID Object, - _In_ ULONG Flags - ); - -BOOLEAN NTAPI PhpModuleHashtableEqualFunction( - _In_ PVOID Entry1, - _In_ PVOID Entry2 - ); - -ULONG NTAPI PhpModuleHashtableHashFunction( - _In_ PVOID Entry - ); - -PPH_OBJECT_TYPE PhModuleProviderType; -PPH_OBJECT_TYPE PhModuleItemType; - -BOOLEAN PhModuleProviderInitialization( - VOID - ) -{ - PhModuleProviderType = PhCreateObjectType(L"ModuleProvider", 0, PhpModuleProviderDeleteProcedure); - PhModuleItemType = PhCreateObjectType(L"ModuleItem", 0, PhpModuleItemDeleteProcedure); - - return TRUE; -} - -PPH_MODULE_PROVIDER PhCreateModuleProvider( - _In_ HANDLE ProcessId - ) -{ - NTSTATUS status; - PPH_MODULE_PROVIDER moduleProvider; - - moduleProvider = PhCreateObject( - PhEmGetObjectSize(EmModuleProviderType, sizeof(PH_MODULE_PROVIDER)), - PhModuleProviderType - ); - - moduleProvider->ModuleHashtable = PhCreateHashtable( - sizeof(PPH_MODULE_ITEM), - PhpModuleHashtableEqualFunction, - PhpModuleHashtableHashFunction, - 20 - ); - PhInitializeFastLock(&moduleProvider->ModuleHashtableLock); - - PhInitializeCallback(&moduleProvider->ModuleAddedEvent); - PhInitializeCallback(&moduleProvider->ModuleModifiedEvent); - PhInitializeCallback(&moduleProvider->ModuleRemovedEvent); - PhInitializeCallback(&moduleProvider->UpdatedEvent); - - moduleProvider->ProcessId = ProcessId; - moduleProvider->ProcessHandle = NULL; - moduleProvider->PackageFullName = NULL; - moduleProvider->RunStatus = STATUS_SUCCESS; - - // It doesn't matter if we can't get a process handle. - - // Try to get a handle with query information + vm read access. - if (!NT_SUCCESS(status = PhOpenProcess( - &moduleProvider->ProcessHandle, - PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, - ProcessId - ))) - { - if (WINDOWS_HAS_LIMITED_ACCESS) - { - // Try to get a handle with query limited information + vm read access. - status = PhOpenProcess( - &moduleProvider->ProcessHandle, - PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_VM_READ, - ProcessId - ); - } - - moduleProvider->RunStatus = status; - } - - if (moduleProvider->ProcessHandle) - moduleProvider->PackageFullName = PhGetProcessPackageFullName(moduleProvider->ProcessHandle); - - RtlInitializeSListHead(&moduleProvider->QueryListHead); - - PhEmCallObjectOperation(EmModuleProviderType, moduleProvider, EmObjectCreate); - - return moduleProvider; -} - -VOID PhpModuleProviderDeleteProcedure( - _In_ PVOID Object, - _In_ ULONG Flags - ) -{ - PPH_MODULE_PROVIDER moduleProvider = (PPH_MODULE_PROVIDER)Object; - - PhEmCallObjectOperation(EmModuleProviderType, moduleProvider, EmObjectDelete); - - // Dereference all module items (we referenced them - // when we added them to the hashtable). - PhDereferenceAllModuleItems(moduleProvider); - - PhDereferenceObject(moduleProvider->ModuleHashtable); - PhDeleteFastLock(&moduleProvider->ModuleHashtableLock); - PhDeleteCallback(&moduleProvider->ModuleAddedEvent); - PhDeleteCallback(&moduleProvider->ModuleModifiedEvent); - PhDeleteCallback(&moduleProvider->ModuleRemovedEvent); - PhDeleteCallback(&moduleProvider->UpdatedEvent); - - // Destroy all queue items. - { - PSLIST_ENTRY entry; - PPH_MODULE_QUERY_DATA data; - - entry = RtlInterlockedFlushSList(&moduleProvider->QueryListHead); - - while (entry) - { - data = CONTAINING_RECORD(entry, PH_MODULE_QUERY_DATA, ListEntry); - entry = entry->Next; - - if (data->VerifySignerName) PhDereferenceObject(data->VerifySignerName); - PhDereferenceObject(data->ModuleItem); - PhFree(data); - } - } - - if (moduleProvider->PackageFullName) PhDereferenceObject(moduleProvider->PackageFullName); - if (moduleProvider->ProcessHandle) NtClose(moduleProvider->ProcessHandle); -} - -PPH_MODULE_ITEM PhCreateModuleItem( - VOID - ) -{ - PPH_MODULE_ITEM moduleItem; - - moduleItem = PhCreateObject( - PhEmGetObjectSize(EmModuleItemType, sizeof(PH_MODULE_ITEM)), - PhModuleItemType - ); - memset(moduleItem, 0, sizeof(PH_MODULE_ITEM)); - PhEmCallObjectOperation(EmModuleItemType, moduleItem, EmObjectCreate); - - return moduleItem; -} - -VOID PhpModuleItemDeleteProcedure( - _In_ PVOID Object, - _In_ ULONG Flags - ) -{ - PPH_MODULE_ITEM moduleItem = (PPH_MODULE_ITEM)Object; - - PhEmCallObjectOperation(EmModuleItemType, moduleItem, EmObjectDelete); - - if (moduleItem->Name) PhDereferenceObject(moduleItem->Name); - if (moduleItem->FileName) PhDereferenceObject(moduleItem->FileName); - if (moduleItem->VerifySignerName) PhDereferenceObject(moduleItem->VerifySignerName); - PhDeleteImageVersionInfo(&moduleItem->VersionInfo); -} - -BOOLEAN NTAPI PhpModuleHashtableEqualFunction( - _In_ PVOID Entry1, - _In_ PVOID Entry2 - ) -{ - return - (*(PPH_MODULE_ITEM *)Entry1)->BaseAddress == - (*(PPH_MODULE_ITEM *)Entry2)->BaseAddress; -} - -ULONG NTAPI PhpModuleHashtableHashFunction( - _In_ PVOID Entry - ) -{ - PVOID baseAddress = (*(PPH_MODULE_ITEM *)Entry)->BaseAddress; - - return PhHashIntPtr((ULONG_PTR)baseAddress); -} - -PPH_MODULE_ITEM PhReferenceModuleItem( - _In_ PPH_MODULE_PROVIDER ModuleProvider, - _In_ PVOID BaseAddress - ) -{ - PH_MODULE_ITEM lookupModuleItem; - PPH_MODULE_ITEM lookupModuleItemPtr = &lookupModuleItem; - PPH_MODULE_ITEM *moduleItemPtr; - PPH_MODULE_ITEM moduleItem; - - lookupModuleItem.BaseAddress = BaseAddress; - - PhAcquireFastLockShared(&ModuleProvider->ModuleHashtableLock); - - moduleItemPtr = (PPH_MODULE_ITEM *)PhFindEntryHashtable( - ModuleProvider->ModuleHashtable, - &lookupModuleItemPtr - ); - - if (moduleItemPtr) - { - moduleItem = *moduleItemPtr; - PhReferenceObject(moduleItem); - } - else - { - moduleItem = NULL; - } - - PhReleaseFastLockShared(&ModuleProvider->ModuleHashtableLock); - - return moduleItem; -} - -VOID PhDereferenceAllModuleItems( - _In_ PPH_MODULE_PROVIDER ModuleProvider - ) -{ - ULONG enumerationKey = 0; - PPH_MODULE_ITEM *moduleItem; - - PhAcquireFastLockExclusive(&ModuleProvider->ModuleHashtableLock); - - while (PhEnumHashtable(ModuleProvider->ModuleHashtable, (PVOID *)&moduleItem, &enumerationKey)) - { - PhDereferenceObject(*moduleItem); - } - - PhReleaseFastLockExclusive(&ModuleProvider->ModuleHashtableLock); -} - -VOID PhpRemoveModuleItem( - _In_ PPH_MODULE_PROVIDER ModuleProvider, - _In_ PPH_MODULE_ITEM ModuleItem - ) -{ - PhRemoveEntryHashtable(ModuleProvider->ModuleHashtable, &ModuleItem); - PhDereferenceObject(ModuleItem); -} - -NTSTATUS PhpModuleQueryWorker( - _In_ PVOID Parameter - ) -{ - PPH_MODULE_QUERY_DATA data = (PPH_MODULE_QUERY_DATA)Parameter; - - data->VerifyResult = PhVerifyFileCached( - data->ModuleItem->FileName, - PhGetString(data->ModuleProvider->PackageFullName), - &data->VerifySignerName, - FALSE - ); - - RtlInterlockedPushEntrySList(&data->ModuleProvider->QueryListHead, &data->ListEntry); - - PhDereferenceObject(data->ModuleProvider); - - return STATUS_SUCCESS; -} - -VOID PhpQueueModuleQuery( - _In_ PPH_MODULE_PROVIDER ModuleProvider, - _In_ PPH_MODULE_ITEM ModuleItem - ) -{ - PPH_MODULE_QUERY_DATA data; - PH_WORK_QUEUE_ENVIRONMENT environment; - - if (!PhEnableProcessQueryStage2) - return; - - data = PhAllocate(sizeof(PH_MODULE_QUERY_DATA)); - memset(data, 0, sizeof(PH_MODULE_QUERY_DATA)); - data->ModuleProvider = ModuleProvider; - data->ModuleItem = ModuleItem; - - PhReferenceObject(ModuleProvider); - PhReferenceObject(ModuleItem); - - PhInitializeWorkQueueEnvironment(&environment); - environment.BasePriority = THREAD_PRIORITY_BELOW_NORMAL; - environment.IoPriority = IoPriorityLow; - environment.PagePriority = MEMORY_PRIORITY_LOW; - - PhQueueItemWorkQueueEx(PhGetGlobalWorkQueue(), PhpModuleQueryWorker, data, NULL, &environment); -} - -static BOOLEAN NTAPI EnumModulesCallback( - _In_ PPH_MODULE_INFO Module, - _In_opt_ PVOID Context - ) -{ - PPH_MODULE_INFO copy; - - copy = PhAllocateCopy(Module, sizeof(PH_MODULE_INFO)); - PhReferenceObject(copy->Name); - PhReferenceObject(copy->FileName); - - PhAddItemList((PPH_LIST)Context, copy); - - return TRUE; -} - -VOID PhModuleProviderUpdate( - _In_ PVOID Object - ) -{ - PPH_MODULE_PROVIDER moduleProvider = (PPH_MODULE_PROVIDER)Object; - PPH_LIST modules; - ULONG i; - - // If we didn't get a handle when we created the provider, - // abort (unless this is the System process - in that case - // we don't need a handle). - if (!moduleProvider->ProcessHandle && moduleProvider->ProcessId != SYSTEM_PROCESS_ID) - goto UpdateExit; - - modules = PhCreateList(20); - - moduleProvider->RunStatus = PhEnumGenericModules( - moduleProvider->ProcessId, - moduleProvider->ProcessHandle, - PH_ENUM_GENERIC_MAPPED_FILES | PH_ENUM_GENERIC_MAPPED_IMAGES, - EnumModulesCallback, - modules - ); - - // Look for removed modules. - { - PPH_LIST modulesToRemove = NULL; - ULONG enumerationKey = 0; - PPH_MODULE_ITEM *moduleItem; - - while (PhEnumHashtable(moduleProvider->ModuleHashtable, (PVOID *)&moduleItem, &enumerationKey)) - { - BOOLEAN found = FALSE; - - // Check if the module still exists. - for (i = 0; i < modules->Count; i++) - { - PPH_MODULE_INFO module = modules->Items[i]; - - if ((*moduleItem)->BaseAddress == module->BaseAddress && - PhEqualString((*moduleItem)->FileName, module->FileName, TRUE)) - { - found = TRUE; - break; - } - } - - if (!found) - { - // Raise the module removed event. - PhInvokeCallback(&moduleProvider->ModuleRemovedEvent, *moduleItem); - - if (!modulesToRemove) - modulesToRemove = PhCreateList(2); - - PhAddItemList(modulesToRemove, *moduleItem); - } - } - - if (modulesToRemove) - { - PhAcquireFastLockExclusive(&moduleProvider->ModuleHashtableLock); - - for (i = 0; i < modulesToRemove->Count; i++) - { - PhpRemoveModuleItem( - moduleProvider, - (PPH_MODULE_ITEM)modulesToRemove->Items[i] - ); - } - - PhReleaseFastLockExclusive(&moduleProvider->ModuleHashtableLock); - PhDereferenceObject(modulesToRemove); - } - } - - // Go through the queued thread query data. - { - PSLIST_ENTRY entry; - PPH_MODULE_QUERY_DATA data; - - entry = RtlInterlockedFlushSList(&moduleProvider->QueryListHead); - - while (entry) - { - data = CONTAINING_RECORD(entry, PH_MODULE_QUERY_DATA, ListEntry); - entry = entry->Next; - - data->ModuleItem->VerifyResult = data->VerifyResult; - data->ModuleItem->VerifySignerName = data->VerifySignerName; - data->ModuleItem->JustProcessed = TRUE; - - PhDereferenceObject(data->ModuleItem); - PhFree(data); - } - } - - // Look for new modules. - for (i = 0; i < modules->Count; i++) - { - PPH_MODULE_INFO module = modules->Items[i]; - PPH_MODULE_ITEM moduleItem; - - moduleItem = PhReferenceModuleItem(moduleProvider, module->BaseAddress); - - if (!moduleItem) - { - FILE_NETWORK_OPEN_INFORMATION networkOpenInfo; - - moduleItem = PhCreateModuleItem(); - - moduleItem->BaseAddress = module->BaseAddress; - PhPrintPointer(moduleItem->BaseAddressString, moduleItem->BaseAddress); - moduleItem->Size = module->Size; - moduleItem->Flags = module->Flags; - moduleItem->Type = module->Type; - moduleItem->LoadReason = module->LoadReason; - moduleItem->LoadCount = module->LoadCount; - moduleItem->LoadTime = module->LoadTime; - - moduleItem->Name = module->Name; - PhReferenceObject(moduleItem->Name); - moduleItem->FileName = module->FileName; - PhReferenceObject(moduleItem->FileName); - - PhInitializeImageVersionInfo(&moduleItem->VersionInfo, moduleItem->FileName->Buffer); - - moduleItem->IsFirst = i == 0; - - // Fix up the load count. If this is not an ordinary DLL or kernel module, set the load count to 0. - if (moduleItem->Type != PH_MODULE_TYPE_MODULE && - moduleItem->Type != PH_MODULE_TYPE_WOW64_MODULE && - moduleItem->Type != PH_MODULE_TYPE_KERNEL_MODULE) - { - moduleItem->LoadCount = 0; - } - - if (moduleItem->Type == PH_MODULE_TYPE_MODULE || - moduleItem->Type == PH_MODULE_TYPE_WOW64_MODULE || - moduleItem->Type == PH_MODULE_TYPE_MAPPED_IMAGE) - { - PH_REMOTE_MAPPED_IMAGE remoteMappedImage; - - // Note: - // On Windows 7 the LDRP_IMAGE_NOT_AT_BASE flag doesn't appear to be used - // anymore. Instead we'll check ImageBase in the image headers. We read this in - // from the process' memory because: - // - // 1. It (should be) faster than opening the file and mapping it in, and - // 2. It contains the correct original image base relocated by ASLR, if present. - - moduleItem->Flags &= ~LDRP_IMAGE_NOT_AT_BASE; - - if (NT_SUCCESS(PhLoadRemoteMappedImage(moduleProvider->ProcessHandle, moduleItem->BaseAddress, &remoteMappedImage))) - { - moduleItem->ImageTimeDateStamp = remoteMappedImage.NtHeaders->FileHeader.TimeDateStamp; - moduleItem->ImageCharacteristics = remoteMappedImage.NtHeaders->FileHeader.Characteristics; - - if (remoteMappedImage.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) - { - if ((ULONG_PTR)((PIMAGE_OPTIONAL_HEADER32)&remoteMappedImage.NtHeaders->OptionalHeader)->ImageBase != (ULONG_PTR)moduleItem->BaseAddress) - moduleItem->Flags |= LDRP_IMAGE_NOT_AT_BASE; - - moduleItem->ImageDllCharacteristics = ((PIMAGE_OPTIONAL_HEADER32)&remoteMappedImage.NtHeaders->OptionalHeader)->DllCharacteristics; - } - else if (remoteMappedImage.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) - { - if ((ULONG_PTR)((PIMAGE_OPTIONAL_HEADER64)&remoteMappedImage.NtHeaders->OptionalHeader)->ImageBase != (ULONG_PTR)moduleItem->BaseAddress) - moduleItem->Flags |= LDRP_IMAGE_NOT_AT_BASE; - - moduleItem->ImageDllCharacteristics = ((PIMAGE_OPTIONAL_HEADER64)&remoteMappedImage.NtHeaders->OptionalHeader)->DllCharacteristics; - } - - PhUnloadRemoteMappedImage(&remoteMappedImage); - } - } - - if (NT_SUCCESS(PhQueryFullAttributesFileWin32(moduleItem->FileName->Buffer, &networkOpenInfo))) - { - moduleItem->FileLastWriteTime = networkOpenInfo.LastWriteTime; - moduleItem->FileEndOfFile = networkOpenInfo.EndOfFile; - } - else - { - moduleItem->FileEndOfFile.QuadPart = -1; - } - - if (moduleItem->Type == PH_MODULE_TYPE_MODULE || moduleItem->Type == PH_MODULE_TYPE_KERNEL_MODULE || - moduleItem->Type == PH_MODULE_TYPE_WOW64_MODULE || moduleItem->Type == PH_MODULE_TYPE_MAPPED_IMAGE) - { - // See if the file has already been verified; if not, queue for verification. - - moduleItem->VerifyResult = PhVerifyFileCached(moduleItem->FileName, NULL, &moduleItem->VerifySignerName, TRUE); - - if (moduleItem->VerifyResult == VrUnknown) - PhpQueueModuleQuery(moduleProvider, moduleItem); - } - - // Add the module item to the hashtable. - PhAcquireFastLockExclusive(&moduleProvider->ModuleHashtableLock); - PhAddEntryHashtable(moduleProvider->ModuleHashtable, &moduleItem); - PhReleaseFastLockExclusive(&moduleProvider->ModuleHashtableLock); - - // Raise the module added event. - PhInvokeCallback(&moduleProvider->ModuleAddedEvent, moduleItem); - } - else - { - BOOLEAN modified = FALSE; - - if (moduleItem->JustProcessed) - modified = TRUE; - - moduleItem->JustProcessed = FALSE; - - if (modified) - PhInvokeCallback(&moduleProvider->ModuleModifiedEvent, moduleItem); - - PhDereferenceObject(moduleItem); - } - } - - // Free the modules list. - - for (i = 0; i < modules->Count; i++) - { - PPH_MODULE_INFO module = modules->Items[i]; - - PhDereferenceObject(module->Name); - PhDereferenceObject(module->FileName); - PhFree(module); - } - - PhDereferenceObject(modules); - -UpdateExit: - PhInvokeCallback(&moduleProvider->UpdatedEvent, NULL); -} +/* + * Process Hacker - + * module provider + * + * Copyright (C) 2009-2016 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include +#include + +#include +#include +#include + +#include +#include + +typedef struct _PH_MODULE_QUERY_DATA +{ + SLIST_ENTRY ListEntry; + PPH_MODULE_PROVIDER ModuleProvider; + PPH_MODULE_ITEM ModuleItem; + + VERIFY_RESULT VerifyResult; + PPH_STRING VerifySignerName; +} PH_MODULE_QUERY_DATA, *PPH_MODULE_QUERY_DATA; + +VOID NTAPI PhpModuleProviderDeleteProcedure( + _In_ PVOID Object, + _In_ ULONG Flags + ); + +VOID NTAPI PhpModuleItemDeleteProcedure( + _In_ PVOID Object, + _In_ ULONG Flags + ); + +BOOLEAN NTAPI PhpModuleHashtableEqualFunction( + _In_ PVOID Entry1, + _In_ PVOID Entry2 + ); + +ULONG NTAPI PhpModuleHashtableHashFunction( + _In_ PVOID Entry + ); + +PPH_OBJECT_TYPE PhModuleProviderType; +PPH_OBJECT_TYPE PhModuleItemType; + +BOOLEAN PhModuleProviderInitialization( + VOID + ) +{ + PhModuleProviderType = PhCreateObjectType(L"ModuleProvider", 0, PhpModuleProviderDeleteProcedure); + PhModuleItemType = PhCreateObjectType(L"ModuleItem", 0, PhpModuleItemDeleteProcedure); + + return TRUE; +} + +PPH_MODULE_PROVIDER PhCreateModuleProvider( + _In_ HANDLE ProcessId + ) +{ + NTSTATUS status; + PPH_MODULE_PROVIDER moduleProvider; + + moduleProvider = PhCreateObject( + PhEmGetObjectSize(EmModuleProviderType, sizeof(PH_MODULE_PROVIDER)), + PhModuleProviderType + ); + + moduleProvider->ModuleHashtable = PhCreateHashtable( + sizeof(PPH_MODULE_ITEM), + PhpModuleHashtableEqualFunction, + PhpModuleHashtableHashFunction, + 20 + ); + PhInitializeFastLock(&moduleProvider->ModuleHashtableLock); + + PhInitializeCallback(&moduleProvider->ModuleAddedEvent); + PhInitializeCallback(&moduleProvider->ModuleModifiedEvent); + PhInitializeCallback(&moduleProvider->ModuleRemovedEvent); + PhInitializeCallback(&moduleProvider->UpdatedEvent); + + moduleProvider->ProcessId = ProcessId; + moduleProvider->ProcessHandle = NULL; + moduleProvider->PackageFullName = NULL; + moduleProvider->RunStatus = STATUS_SUCCESS; + + // It doesn't matter if we can't get a process handle. + + // Try to get a handle with query information + vm read access. + if (!NT_SUCCESS(status = PhOpenProcess( + &moduleProvider->ProcessHandle, + PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, + ProcessId + ))) + { + if (WINDOWS_HAS_LIMITED_ACCESS) + { + // Try to get a handle with query limited information + vm read access. + status = PhOpenProcess( + &moduleProvider->ProcessHandle, + PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_VM_READ, + ProcessId + ); + } + + moduleProvider->RunStatus = status; + } + + if (moduleProvider->ProcessHandle) + moduleProvider->PackageFullName = PhGetProcessPackageFullName(moduleProvider->ProcessHandle); + + RtlInitializeSListHead(&moduleProvider->QueryListHead); + + PhEmCallObjectOperation(EmModuleProviderType, moduleProvider, EmObjectCreate); + + return moduleProvider; +} + +VOID PhpModuleProviderDeleteProcedure( + _In_ PVOID Object, + _In_ ULONG Flags + ) +{ + PPH_MODULE_PROVIDER moduleProvider = (PPH_MODULE_PROVIDER)Object; + + PhEmCallObjectOperation(EmModuleProviderType, moduleProvider, EmObjectDelete); + + // Dereference all module items (we referenced them + // when we added them to the hashtable). + PhDereferenceAllModuleItems(moduleProvider); + + PhDereferenceObject(moduleProvider->ModuleHashtable); + PhDeleteFastLock(&moduleProvider->ModuleHashtableLock); + PhDeleteCallback(&moduleProvider->ModuleAddedEvent); + PhDeleteCallback(&moduleProvider->ModuleModifiedEvent); + PhDeleteCallback(&moduleProvider->ModuleRemovedEvent); + PhDeleteCallback(&moduleProvider->UpdatedEvent); + + // Destroy all queue items. + { + PSLIST_ENTRY entry; + PPH_MODULE_QUERY_DATA data; + + entry = RtlInterlockedFlushSList(&moduleProvider->QueryListHead); + + while (entry) + { + data = CONTAINING_RECORD(entry, PH_MODULE_QUERY_DATA, ListEntry); + entry = entry->Next; + + if (data->VerifySignerName) PhDereferenceObject(data->VerifySignerName); + PhDereferenceObject(data->ModuleItem); + PhFree(data); + } + } + + if (moduleProvider->PackageFullName) PhDereferenceObject(moduleProvider->PackageFullName); + if (moduleProvider->ProcessHandle) NtClose(moduleProvider->ProcessHandle); +} + +PPH_MODULE_ITEM PhCreateModuleItem( + VOID + ) +{ + PPH_MODULE_ITEM moduleItem; + + moduleItem = PhCreateObject( + PhEmGetObjectSize(EmModuleItemType, sizeof(PH_MODULE_ITEM)), + PhModuleItemType + ); + memset(moduleItem, 0, sizeof(PH_MODULE_ITEM)); + PhEmCallObjectOperation(EmModuleItemType, moduleItem, EmObjectCreate); + + return moduleItem; +} + +VOID PhpModuleItemDeleteProcedure( + _In_ PVOID Object, + _In_ ULONG Flags + ) +{ + PPH_MODULE_ITEM moduleItem = (PPH_MODULE_ITEM)Object; + + PhEmCallObjectOperation(EmModuleItemType, moduleItem, EmObjectDelete); + + if (moduleItem->Name) PhDereferenceObject(moduleItem->Name); + if (moduleItem->FileName) PhDereferenceObject(moduleItem->FileName); + if (moduleItem->VerifySignerName) PhDereferenceObject(moduleItem->VerifySignerName); + PhDeleteImageVersionInfo(&moduleItem->VersionInfo); +} + +BOOLEAN NTAPI PhpModuleHashtableEqualFunction( + _In_ PVOID Entry1, + _In_ PVOID Entry2 + ) +{ + return + (*(PPH_MODULE_ITEM *)Entry1)->BaseAddress == + (*(PPH_MODULE_ITEM *)Entry2)->BaseAddress; +} + +ULONG NTAPI PhpModuleHashtableHashFunction( + _In_ PVOID Entry + ) +{ + PVOID baseAddress = (*(PPH_MODULE_ITEM *)Entry)->BaseAddress; + + return PhHashIntPtr((ULONG_PTR)baseAddress); +} + +PPH_MODULE_ITEM PhReferenceModuleItem( + _In_ PPH_MODULE_PROVIDER ModuleProvider, + _In_ PVOID BaseAddress + ) +{ + PH_MODULE_ITEM lookupModuleItem; + PPH_MODULE_ITEM lookupModuleItemPtr = &lookupModuleItem; + PPH_MODULE_ITEM *moduleItemPtr; + PPH_MODULE_ITEM moduleItem; + + lookupModuleItem.BaseAddress = BaseAddress; + + PhAcquireFastLockShared(&ModuleProvider->ModuleHashtableLock); + + moduleItemPtr = (PPH_MODULE_ITEM *)PhFindEntryHashtable( + ModuleProvider->ModuleHashtable, + &lookupModuleItemPtr + ); + + if (moduleItemPtr) + { + moduleItem = *moduleItemPtr; + PhReferenceObject(moduleItem); + } + else + { + moduleItem = NULL; + } + + PhReleaseFastLockShared(&ModuleProvider->ModuleHashtableLock); + + return moduleItem; +} + +VOID PhDereferenceAllModuleItems( + _In_ PPH_MODULE_PROVIDER ModuleProvider + ) +{ + ULONG enumerationKey = 0; + PPH_MODULE_ITEM *moduleItem; + + PhAcquireFastLockExclusive(&ModuleProvider->ModuleHashtableLock); + + while (PhEnumHashtable(ModuleProvider->ModuleHashtable, (PVOID *)&moduleItem, &enumerationKey)) + { + PhDereferenceObject(*moduleItem); + } + + PhReleaseFastLockExclusive(&ModuleProvider->ModuleHashtableLock); +} + +VOID PhpRemoveModuleItem( + _In_ PPH_MODULE_PROVIDER ModuleProvider, + _In_ PPH_MODULE_ITEM ModuleItem + ) +{ + PhRemoveEntryHashtable(ModuleProvider->ModuleHashtable, &ModuleItem); + PhDereferenceObject(ModuleItem); +} + +NTSTATUS PhpModuleQueryWorker( + _In_ PVOID Parameter + ) +{ + PPH_MODULE_QUERY_DATA data = (PPH_MODULE_QUERY_DATA)Parameter; + + data->VerifyResult = PhVerifyFileCached( + data->ModuleItem->FileName, + PhGetString(data->ModuleProvider->PackageFullName), + &data->VerifySignerName, + FALSE + ); + + RtlInterlockedPushEntrySList(&data->ModuleProvider->QueryListHead, &data->ListEntry); + + PhDereferenceObject(data->ModuleProvider); + + return STATUS_SUCCESS; +} + +VOID PhpQueueModuleQuery( + _In_ PPH_MODULE_PROVIDER ModuleProvider, + _In_ PPH_MODULE_ITEM ModuleItem + ) +{ + PPH_MODULE_QUERY_DATA data; + PH_WORK_QUEUE_ENVIRONMENT environment; + + if (!PhEnableProcessQueryStage2) + return; + + data = PhAllocate(sizeof(PH_MODULE_QUERY_DATA)); + memset(data, 0, sizeof(PH_MODULE_QUERY_DATA)); + data->ModuleProvider = ModuleProvider; + data->ModuleItem = ModuleItem; + + PhReferenceObject(ModuleProvider); + PhReferenceObject(ModuleItem); + + PhInitializeWorkQueueEnvironment(&environment); + environment.BasePriority = THREAD_PRIORITY_BELOW_NORMAL; + environment.IoPriority = IoPriorityLow; + environment.PagePriority = MEMORY_PRIORITY_LOW; + + PhQueueItemWorkQueueEx(PhGetGlobalWorkQueue(), PhpModuleQueryWorker, data, NULL, &environment); +} + +static BOOLEAN NTAPI EnumModulesCallback( + _In_ PPH_MODULE_INFO Module, + _In_opt_ PVOID Context + ) +{ + PPH_MODULE_INFO copy; + + copy = PhAllocateCopy(Module, sizeof(PH_MODULE_INFO)); + PhReferenceObject(copy->Name); + PhReferenceObject(copy->FileName); + + PhAddItemList((PPH_LIST)Context, copy); + + return TRUE; +} + +VOID PhModuleProviderUpdate( + _In_ PVOID Object + ) +{ + PPH_MODULE_PROVIDER moduleProvider = (PPH_MODULE_PROVIDER)Object; + PPH_LIST modules; + ULONG i; + + // If we didn't get a handle when we created the provider, + // abort (unless this is the System process - in that case + // we don't need a handle). + if (!moduleProvider->ProcessHandle && moduleProvider->ProcessId != SYSTEM_PROCESS_ID) + goto UpdateExit; + + modules = PhCreateList(20); + + moduleProvider->RunStatus = PhEnumGenericModules( + moduleProvider->ProcessId, + moduleProvider->ProcessHandle, + PH_ENUM_GENERIC_MAPPED_FILES | PH_ENUM_GENERIC_MAPPED_IMAGES, + EnumModulesCallback, + modules + ); + + // Look for removed modules. + { + PPH_LIST modulesToRemove = NULL; + ULONG enumerationKey = 0; + PPH_MODULE_ITEM *moduleItem; + + while (PhEnumHashtable(moduleProvider->ModuleHashtable, (PVOID *)&moduleItem, &enumerationKey)) + { + BOOLEAN found = FALSE; + + // Check if the module still exists. + for (i = 0; i < modules->Count; i++) + { + PPH_MODULE_INFO module = modules->Items[i]; + + if ((*moduleItem)->BaseAddress == module->BaseAddress && + PhEqualString((*moduleItem)->FileName, module->FileName, TRUE)) + { + found = TRUE; + break; + } + } + + if (!found) + { + // Raise the module removed event. + PhInvokeCallback(&moduleProvider->ModuleRemovedEvent, *moduleItem); + + if (!modulesToRemove) + modulesToRemove = PhCreateList(2); + + PhAddItemList(modulesToRemove, *moduleItem); + } + } + + if (modulesToRemove) + { + PhAcquireFastLockExclusive(&moduleProvider->ModuleHashtableLock); + + for (i = 0; i < modulesToRemove->Count; i++) + { + PhpRemoveModuleItem( + moduleProvider, + (PPH_MODULE_ITEM)modulesToRemove->Items[i] + ); + } + + PhReleaseFastLockExclusive(&moduleProvider->ModuleHashtableLock); + PhDereferenceObject(modulesToRemove); + } + } + + // Go through the queued thread query data. + { + PSLIST_ENTRY entry; + PPH_MODULE_QUERY_DATA data; + + entry = RtlInterlockedFlushSList(&moduleProvider->QueryListHead); + + while (entry) + { + data = CONTAINING_RECORD(entry, PH_MODULE_QUERY_DATA, ListEntry); + entry = entry->Next; + + data->ModuleItem->VerifyResult = data->VerifyResult; + data->ModuleItem->VerifySignerName = data->VerifySignerName; + data->ModuleItem->JustProcessed = TRUE; + + PhDereferenceObject(data->ModuleItem); + PhFree(data); + } + } + + // Look for new modules. + for (i = 0; i < modules->Count; i++) + { + PPH_MODULE_INFO module = modules->Items[i]; + PPH_MODULE_ITEM moduleItem; + + moduleItem = PhReferenceModuleItem(moduleProvider, module->BaseAddress); + + if (!moduleItem) + { + FILE_NETWORK_OPEN_INFORMATION networkOpenInfo; + + moduleItem = PhCreateModuleItem(); + + moduleItem->BaseAddress = module->BaseAddress; + PhPrintPointer(moduleItem->BaseAddressString, moduleItem->BaseAddress); + moduleItem->Size = module->Size; + moduleItem->Flags = module->Flags; + moduleItem->Type = module->Type; + moduleItem->LoadReason = module->LoadReason; + moduleItem->LoadCount = module->LoadCount; + moduleItem->LoadTime = module->LoadTime; + + moduleItem->Name = module->Name; + PhReferenceObject(moduleItem->Name); + moduleItem->FileName = module->FileName; + PhReferenceObject(moduleItem->FileName); + + PhInitializeImageVersionInfo(&moduleItem->VersionInfo, moduleItem->FileName->Buffer); + + moduleItem->IsFirst = i == 0; + + // Fix up the load count. If this is not an ordinary DLL or kernel module, set the load count to 0. + if (moduleItem->Type != PH_MODULE_TYPE_MODULE && + moduleItem->Type != PH_MODULE_TYPE_WOW64_MODULE && + moduleItem->Type != PH_MODULE_TYPE_KERNEL_MODULE) + { + moduleItem->LoadCount = 0; + } + + if (moduleItem->Type == PH_MODULE_TYPE_MODULE || + moduleItem->Type == PH_MODULE_TYPE_WOW64_MODULE || + moduleItem->Type == PH_MODULE_TYPE_MAPPED_IMAGE) + { + PH_REMOTE_MAPPED_IMAGE remoteMappedImage; + + // Note: + // On Windows 7 the LDRP_IMAGE_NOT_AT_BASE flag doesn't appear to be used + // anymore. Instead we'll check ImageBase in the image headers. We read this in + // from the process' memory because: + // + // 1. It (should be) faster than opening the file and mapping it in, and + // 2. It contains the correct original image base relocated by ASLR, if present. + + moduleItem->Flags &= ~LDRP_IMAGE_NOT_AT_BASE; + + if (NT_SUCCESS(PhLoadRemoteMappedImage(moduleProvider->ProcessHandle, moduleItem->BaseAddress, &remoteMappedImage))) + { + moduleItem->ImageTimeDateStamp = remoteMappedImage.NtHeaders->FileHeader.TimeDateStamp; + moduleItem->ImageCharacteristics = remoteMappedImage.NtHeaders->FileHeader.Characteristics; + + if (remoteMappedImage.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) + { + if ((ULONG_PTR)((PIMAGE_OPTIONAL_HEADER32)&remoteMappedImage.NtHeaders->OptionalHeader)->ImageBase != (ULONG_PTR)moduleItem->BaseAddress) + moduleItem->Flags |= LDRP_IMAGE_NOT_AT_BASE; + + moduleItem->ImageDllCharacteristics = ((PIMAGE_OPTIONAL_HEADER32)&remoteMappedImage.NtHeaders->OptionalHeader)->DllCharacteristics; + } + else if (remoteMappedImage.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) + { + if ((ULONG_PTR)((PIMAGE_OPTIONAL_HEADER64)&remoteMappedImage.NtHeaders->OptionalHeader)->ImageBase != (ULONG_PTR)moduleItem->BaseAddress) + moduleItem->Flags |= LDRP_IMAGE_NOT_AT_BASE; + + moduleItem->ImageDllCharacteristics = ((PIMAGE_OPTIONAL_HEADER64)&remoteMappedImage.NtHeaders->OptionalHeader)->DllCharacteristics; + } + + PhUnloadRemoteMappedImage(&remoteMappedImage); + } + } + + if (NT_SUCCESS(PhQueryFullAttributesFileWin32(moduleItem->FileName->Buffer, &networkOpenInfo))) + { + moduleItem->FileLastWriteTime = networkOpenInfo.LastWriteTime; + moduleItem->FileEndOfFile = networkOpenInfo.EndOfFile; + } + else + { + moduleItem->FileEndOfFile.QuadPart = -1; + } + + if (moduleItem->Type == PH_MODULE_TYPE_MODULE || moduleItem->Type == PH_MODULE_TYPE_KERNEL_MODULE || + moduleItem->Type == PH_MODULE_TYPE_WOW64_MODULE || moduleItem->Type == PH_MODULE_TYPE_MAPPED_IMAGE) + { + // See if the file has already been verified; if not, queue for verification. + + moduleItem->VerifyResult = PhVerifyFileCached(moduleItem->FileName, NULL, &moduleItem->VerifySignerName, TRUE); + + if (moduleItem->VerifyResult == VrUnknown) + PhpQueueModuleQuery(moduleProvider, moduleItem); + } + + // Add the module item to the hashtable. + PhAcquireFastLockExclusive(&moduleProvider->ModuleHashtableLock); + PhAddEntryHashtable(moduleProvider->ModuleHashtable, &moduleItem); + PhReleaseFastLockExclusive(&moduleProvider->ModuleHashtableLock); + + // Raise the module added event. + PhInvokeCallback(&moduleProvider->ModuleAddedEvent, moduleItem); + } + else + { + BOOLEAN modified = FALSE; + + if (moduleItem->JustProcessed) + modified = TRUE; + + moduleItem->JustProcessed = FALSE; + + if (modified) + PhInvokeCallback(&moduleProvider->ModuleModifiedEvent, moduleItem); + + PhDereferenceObject(moduleItem); + } + } + + // Free the modules list. + + for (i = 0; i < modules->Count; i++) + { + PPH_MODULE_INFO module = modules->Items[i]; + + PhDereferenceObject(module->Name); + PhDereferenceObject(module->FileName); + PhFree(module); + } + + PhDereferenceObject(modules); + +UpdateExit: + PhInvokeCallback(&moduleProvider->UpdatedEvent, NULL); +} diff --git a/ProcessHacker/mxml/mxml.h b/ProcessHacker/mxml/mxml.h index 6e8015874882..91c382291be7 100644 --- a/ProcessHacker/mxml/mxml.h +++ b/ProcessHacker/mxml/mxml.h @@ -32,10 +32,10 @@ # include # include -#ifdef _PHAPP_ -#define PHMXMLAPI __declspec(dllexport) -#else -#define PHMXMLAPI +#ifdef _PHAPP_ +#define PHMXMLAPI __declspec(dllexport) +#else +#define PHMXMLAPI #endif /* diff --git a/ProcessHacker/netlist.c b/ProcessHacker/netlist.c index 4ccd7eac42b1..6efb1357d811 100644 --- a/ProcessHacker/netlist.c +++ b/ProcessHacker/netlist.c @@ -1,797 +1,797 @@ -/* - * Process Hacker - - * network list - * - * Copyright (C) 2011-2015 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include -#include - -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -BOOLEAN PhpNetworkNodeHashtableEqualFunction( - _In_ PVOID Entry1, - _In_ PVOID Entry2 - ); - -ULONG PhpNetworkNodeHashtableHashFunction( - _In_ PVOID Entry - ); - -VOID PhpRemoveNetworkNode( - _In_ PPH_NETWORK_NODE NetworkNode - ); - -LONG PhpNetworkTreeNewPostSortFunction( - _In_ LONG Result, - _In_ PVOID Node1, - _In_ PVOID Node2, - _In_ PH_SORT_ORDER SortOrder - ); - -BOOLEAN NTAPI PhpNetworkTreeNewCallback( - _In_ HWND hwnd, - _In_ PH_TREENEW_MESSAGE Message, - _In_opt_ PVOID Parameter1, - _In_opt_ PVOID Parameter2, - _In_opt_ PVOID Context - ); - -PPH_STRING PhpGetNetworkItemProcessName( - _In_ PPH_NETWORK_ITEM NetworkItem - ); - -static HWND NetworkTreeListHandle; -static ULONG NetworkTreeListSortColumn; -static PH_SORT_ORDER NetworkTreeListSortOrder; -static PH_CM_MANAGER NetworkTreeListCm; - -static PPH_HASHTABLE NetworkNodeHashtable; // hashtable of all nodes -static PPH_LIST NetworkNodeList; // list of all nodes -static LONG NextUniqueId = 1; - -BOOLEAN PhNetworkTreeListStateHighlighting = TRUE; -static PPH_POINTER_LIST NetworkNodeStateList = NULL; // list of nodes which need to be processed - -static PH_TN_FILTER_SUPPORT FilterSupport; - -VOID PhNetworkTreeListInitialization( - VOID - ) -{ - NetworkNodeHashtable = PhCreateHashtable( - sizeof(PPH_NETWORK_NODE), - PhpNetworkNodeHashtableEqualFunction, - PhpNetworkNodeHashtableHashFunction, - 100 - ); - NetworkNodeList = PhCreateList(100); -} - -BOOLEAN PhpNetworkNodeHashtableEqualFunction( - _In_ PVOID Entry1, - _In_ PVOID Entry2 - ) -{ - PPH_NETWORK_NODE networkNode1 = *(PPH_NETWORK_NODE *)Entry1; - PPH_NETWORK_NODE networkNode2 = *(PPH_NETWORK_NODE *)Entry2; - - return networkNode1->NetworkItem == networkNode2->NetworkItem; -} - -ULONG PhpNetworkNodeHashtableHashFunction( - _In_ PVOID Entry - ) -{ - return PhHashIntPtr((ULONG_PTR)(*(PPH_NETWORK_NODE *)Entry)->NetworkItem); -} - -VOID PhInitializeNetworkTreeList( - _In_ HWND hwnd - ) -{ - NetworkTreeListHandle = hwnd; - PhSetControlTheme(NetworkTreeListHandle, L"explorer"); - SendMessage(TreeNew_GetTooltips(NetworkTreeListHandle), TTM_SETDELAYTIME, TTDT_AUTOPOP, MAXSHORT); - - TreeNew_SetCallback(hwnd, PhpNetworkTreeNewCallback, NULL); - - TreeNew_SetRedraw(hwnd, FALSE); - - // Default columns - PhAddTreeNewColumn(hwnd, PHNETLC_PROCESS, TRUE, L"Name", 100, PH_ALIGN_LEFT, 0, 0); - PhAddTreeNewColumn(hwnd, PHNETLC_LOCALADDRESS, TRUE, L"Local address", 120, PH_ALIGN_LEFT, 1, 0); - PhAddTreeNewColumn(hwnd, PHNETLC_LOCALPORT, TRUE, L"Local port", 50, PH_ALIGN_RIGHT, 2, DT_RIGHT); - PhAddTreeNewColumn(hwnd, PHNETLC_REMOTEADDRESS, TRUE, L"Remote address", 120, PH_ALIGN_LEFT, 3, 0); - PhAddTreeNewColumn(hwnd, PHNETLC_REMOTEPORT, TRUE, L"Remote port", 50, PH_ALIGN_RIGHT, 4, DT_RIGHT); - PhAddTreeNewColumn(hwnd, PHNETLC_PROTOCOL, TRUE, L"Protocol", 45, PH_ALIGN_LEFT, 5, 0); - PhAddTreeNewColumn(hwnd, PHNETLC_STATE, TRUE, L"State", 70, PH_ALIGN_LEFT, 6, 0); - PhAddTreeNewColumn(hwnd, PHNETLC_OWNER, WINDOWS_HAS_SERVICE_TAGS, L"Owner", 80, PH_ALIGN_LEFT, 7, 0); - PhAddTreeNewColumnEx(hwnd, PHNETLC_TIMESTAMP, FALSE, L"Time stamp", 100, PH_ALIGN_LEFT, -1, 0, TRUE); - PhAddTreeNewColumn(hwnd, PHNETLC_LOCALHOSTNAME, FALSE, L"Local hostname", 120, PH_ALIGN_LEFT, -1, 0); - PhAddTreeNewColumn(hwnd, PHNETLC_REMOTEHOSTNAME, FALSE, L"Remote hostname", 120, PH_ALIGN_LEFT, -1, 0); - - TreeNew_SetRedraw(hwnd, TRUE); - - TreeNew_SetSort(hwnd, 0, AscendingSortOrder); - - PhCmInitializeManager(&NetworkTreeListCm, hwnd, PHNETLC_MAXIMUM, PhpNetworkTreeNewPostSortFunction); - - if (PhPluginsEnabled) - { - PH_PLUGIN_TREENEW_INFORMATION treeNewInfo; - - treeNewInfo.TreeNewHandle = hwnd; - treeNewInfo.CmData = &NetworkTreeListCm; - PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackNetworkTreeNewInitializing), &treeNewInfo); - } - - PhInitializeTreeNewFilterSupport(&FilterSupport, hwnd, NetworkNodeList); -} - -VOID PhLoadSettingsNetworkTreeList( - VOID - ) -{ - PPH_STRING settings; - PPH_STRING sortSettings; - - settings = PhGetStringSetting(L"NetworkTreeListColumns"); - sortSettings = PhGetStringSetting(L"NetworkTreeListSort"); - PhCmLoadSettingsEx(NetworkTreeListHandle, &NetworkTreeListCm, 0, &settings->sr, &sortSettings->sr); - PhDereferenceObject(settings); - PhDereferenceObject(sortSettings); -} - -VOID PhSaveSettingsNetworkTreeList( - VOID - ) -{ - PPH_STRING settings; - PPH_STRING sortSettings; - - settings = PhCmSaveSettingsEx(NetworkTreeListHandle, &NetworkTreeListCm, 0, &sortSettings); - PhSetStringSetting2(L"NetworkTreeListColumns", &settings->sr); - PhSetStringSetting2(L"NetworkTreeListSort", &sortSettings->sr); - PhDereferenceObject(settings); - PhDereferenceObject(sortSettings); -} - -struct _PH_TN_FILTER_SUPPORT *PhGetFilterSupportNetworkTreeList( - VOID - ) -{ - return &FilterSupport; -} - -PPH_NETWORK_NODE PhAddNetworkNode( - _In_ PPH_NETWORK_ITEM NetworkItem, - _In_ ULONG RunId - ) -{ - PPH_NETWORK_NODE networkNode; - - networkNode = PhAllocate(PhEmGetObjectSize(EmNetworkNodeType, sizeof(PH_NETWORK_NODE))); - memset(networkNode, 0, sizeof(PH_NETWORK_NODE)); - PhInitializeTreeNewNode(&networkNode->Node); - - if (PhNetworkTreeListStateHighlighting && RunId != 1) - { - PhChangeShStateTn( - &networkNode->Node, - &networkNode->ShState, - &NetworkNodeStateList, - NewItemState, - PhCsColorNew, - NULL - ); - } - - networkNode->NetworkItem = NetworkItem; - PhReferenceObject(NetworkItem); - networkNode->UniqueId = NextUniqueId++; // used to stabilize sorting - - memset(networkNode->TextCache, 0, sizeof(PH_STRINGREF) * PHNETLC_MAXIMUM); - networkNode->Node.TextCache = networkNode->TextCache; - networkNode->Node.TextCacheSize = PHNETLC_MAXIMUM; - - networkNode->ProcessNameText = PhpGetNetworkItemProcessName(NetworkItem); - - PhAddEntryHashtable(NetworkNodeHashtable, &networkNode); - PhAddItemList(NetworkNodeList, networkNode); - - if (FilterSupport.NodeList) - networkNode->Node.Visible = PhApplyTreeNewFiltersToNode(&FilterSupport, &networkNode->Node); - - PhEmCallObjectOperation(EmNetworkNodeType, networkNode, EmObjectCreate); - - TreeNew_NodesStructured(NetworkTreeListHandle); - - return networkNode; -} - -PPH_NETWORK_NODE PhFindNetworkNode( - _In_ PPH_NETWORK_ITEM NetworkItem - ) -{ - PH_NETWORK_NODE lookupNetworkNode; - PPH_NETWORK_NODE lookupNetworkNodePtr = &lookupNetworkNode; - PPH_NETWORK_NODE *networkNode; - - lookupNetworkNode.NetworkItem = NetworkItem; - - networkNode = (PPH_NETWORK_NODE *)PhFindEntryHashtable( - NetworkNodeHashtable, - &lookupNetworkNodePtr - ); - - if (networkNode) - return *networkNode; - else - return NULL; -} - -VOID PhRemoveNetworkNode( - _In_ PPH_NETWORK_NODE NetworkNode - ) -{ - // Remove from the hashtable here to avoid problems in case the key is re-used. - PhRemoveEntryHashtable(NetworkNodeHashtable, &NetworkNode); - - if (PhNetworkTreeListStateHighlighting) - { - PhChangeShStateTn( - &NetworkNode->Node, - &NetworkNode->ShState, - &NetworkNodeStateList, - RemovingItemState, - PhCsColorRemoved, - NetworkTreeListHandle - ); - } - else - { - PhpRemoveNetworkNode(NetworkNode); - } -} - -VOID PhpRemoveNetworkNode( - _In_ PPH_NETWORK_NODE NetworkNode - ) -{ - ULONG index; - - PhEmCallObjectOperation(EmNetworkNodeType, NetworkNode, EmObjectDelete); - - // Remove from list and cleanup. - - if ((index = PhFindItemList(NetworkNodeList, NetworkNode)) != -1) - PhRemoveItemList(NetworkNodeList, index); - - if (NetworkNode->ProcessNameText) PhDereferenceObject(NetworkNode->ProcessNameText); - if (NetworkNode->TimeStampText) PhDereferenceObject(NetworkNode->TimeStampText); - if (NetworkNode->TooltipText) PhDereferenceObject(NetworkNode->TooltipText); - - PhDereferenceObject(NetworkNode->NetworkItem); - - PhFree(NetworkNode); - - TreeNew_NodesStructured(NetworkTreeListHandle); -} - -VOID PhUpdateNetworkNode( - _In_ PPH_NETWORK_NODE NetworkNode - ) -{ - memset(NetworkNode->TextCache, 0, sizeof(PH_STRINGREF) * PHNETLC_MAXIMUM); - PhClearReference(&NetworkNode->TooltipText); - - PhInvalidateTreeNewNode(&NetworkNode->Node, TN_CACHE_ICON); - TreeNew_NodesStructured(NetworkTreeListHandle); -} - -VOID PhTickNetworkNodes( - VOID - ) -{ - if (NetworkTreeListSortOrder != NoSortOrder && NetworkTreeListSortColumn >= PHNETLC_MAXIMUM) - { - // Sorting is on, but it's not one of our columns. Force a rebuild. (If it was one of our - // columns, the restructure would have been handled in PhUpdateNetworkNode.) - TreeNew_NodesStructured(NetworkTreeListHandle); - } - - PH_TICK_SH_STATE_TN(PH_NETWORK_NODE, ShState, NetworkNodeStateList, PhpRemoveNetworkNode, PhCsHighlightingDuration, NetworkTreeListHandle, TRUE, NULL); -} - -#define SORT_FUNCTION(Column) PhpNetworkTreeNewCompare##Column - -#define BEGIN_SORT_FUNCTION(Column) static int __cdecl PhpNetworkTreeNewCompare##Column( \ - _In_ const void *_elem1, \ - _In_ const void *_elem2 \ - ) \ -{ \ - PPH_NETWORK_NODE node1 = *(PPH_NETWORK_NODE *)_elem1; \ - PPH_NETWORK_NODE node2 = *(PPH_NETWORK_NODE *)_elem2; \ - PPH_NETWORK_ITEM networkItem1 = node1->NetworkItem; \ - PPH_NETWORK_ITEM networkItem2 = node2->NetworkItem; \ - int sortResult = 0; - -#define END_SORT_FUNCTION \ - if (sortResult == 0) \ - sortResult = intcmp(node1->UniqueId, node2->UniqueId); \ - \ - return PhModifySort(sortResult, NetworkTreeListSortOrder); \ -} - -LONG PhpNetworkTreeNewPostSortFunction( - _In_ LONG Result, - _In_ PVOID Node1, - _In_ PVOID Node2, - _In_ PH_SORT_ORDER SortOrder - ) -{ - if (Result == 0) - Result = intcmp(((PPH_NETWORK_NODE)Node1)->UniqueId, ((PPH_NETWORK_NODE)Node2)->UniqueId); - - return PhModifySort(Result, SortOrder); -} - -BEGIN_SORT_FUNCTION(Process) -{ - sortResult = PhCompareString(node1->ProcessNameText, node2->ProcessNameText, TRUE); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(LocalAddress) -{ - sortResult = PhCompareStringZ(networkItem1->LocalAddressString, networkItem2->LocalAddressString, TRUE); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(LocalHostname) -{ - sortResult = PhCompareStringWithNull(networkItem1->LocalHostString, networkItem2->LocalHostString, TRUE); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(LocalPort) -{ - sortResult = uintcmp(networkItem1->LocalEndpoint.Port, networkItem2->LocalEndpoint.Port); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(RemoteAddress) -{ - sortResult = PhCompareStringZ(networkItem1->RemoteAddressString, networkItem2->RemoteAddressString, TRUE); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(RemoteHostname) -{ - sortResult = PhCompareStringWithNull(networkItem1->RemoteHostString, networkItem2->RemoteHostString, TRUE); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(RemotePort) -{ - sortResult = uintcmp(networkItem1->RemoteEndpoint.Port, networkItem2->RemoteEndpoint.Port); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(Protocol) -{ - sortResult = uintcmp(networkItem1->ProtocolType, networkItem2->ProtocolType); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(State) -{ - sortResult = uintcmp(networkItem1->State, networkItem2->State); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(Owner) -{ - sortResult = PhCompareStringWithNull(networkItem1->OwnerName, networkItem2->OwnerName, TRUE); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(TimeStamp) -{ - sortResult = uint64cmp(networkItem1->CreateTime.QuadPart, networkItem2->CreateTime.QuadPart); -} -END_SORT_FUNCTION - -BOOLEAN NTAPI PhpNetworkTreeNewCallback( - _In_ HWND hwnd, - _In_ PH_TREENEW_MESSAGE Message, - _In_opt_ PVOID Parameter1, - _In_opt_ PVOID Parameter2, - _In_opt_ PVOID Context - ) -{ - PPH_NETWORK_NODE node; - - if (PhCmForwardMessage(hwnd, Message, Parameter1, Parameter2, &NetworkTreeListCm)) - return TRUE; - - switch (Message) - { - case TreeNewGetChildren: - { - PPH_TREENEW_GET_CHILDREN getChildren = Parameter1; - - if (!getChildren->Node) - { - static PVOID sortFunctions[] = - { - SORT_FUNCTION(Process), - SORT_FUNCTION(LocalAddress), - SORT_FUNCTION(LocalHostname), - SORT_FUNCTION(LocalPort), - SORT_FUNCTION(RemoteAddress), - SORT_FUNCTION(RemoteHostname), - SORT_FUNCTION(RemotePort), - SORT_FUNCTION(Protocol), - SORT_FUNCTION(State), - SORT_FUNCTION(Owner), - SORT_FUNCTION(TimeStamp) - }; - int (__cdecl *sortFunction)(const void *, const void *); - - if (!PhCmForwardSort( - (PPH_TREENEW_NODE *)NetworkNodeList->Items, - NetworkNodeList->Count, - NetworkTreeListSortColumn, - NetworkTreeListSortOrder, - &NetworkTreeListCm - )) - { - if (NetworkTreeListSortColumn < PHNETLC_MAXIMUM) - sortFunction = sortFunctions[NetworkTreeListSortColumn]; - else - sortFunction = NULL; - - if (sortFunction) - { - qsort(NetworkNodeList->Items, NetworkNodeList->Count, sizeof(PVOID), sortFunction); - } - } - - getChildren->Children = (PPH_TREENEW_NODE *)NetworkNodeList->Items; - getChildren->NumberOfChildren = NetworkNodeList->Count; - } - } - return TRUE; - case TreeNewIsLeaf: - { - PPH_TREENEW_IS_LEAF isLeaf = Parameter1; - - isLeaf->IsLeaf = TRUE; - } - return TRUE; - case TreeNewGetCellText: - { - PPH_TREENEW_GET_CELL_TEXT getCellText = Parameter1; - PPH_NETWORK_ITEM networkItem; - - node = (PPH_NETWORK_NODE)getCellText->Node; - networkItem = node->NetworkItem; - - switch (getCellText->Id) - { - case PHNETLC_PROCESS: - getCellText->Text = node->ProcessNameText->sr; - break; - case PHNETLC_LOCALADDRESS: - PhInitializeStringRefLongHint(&getCellText->Text, networkItem->LocalAddressString); - break; - case PHNETLC_LOCALHOSTNAME: - getCellText->Text = PhGetStringRef(networkItem->LocalHostString); - break; - case PHNETLC_LOCALPORT: - PhInitializeStringRefLongHint(&getCellText->Text, networkItem->LocalPortString); - break; - case PHNETLC_REMOTEADDRESS: - PhInitializeStringRefLongHint(&getCellText->Text, networkItem->RemoteAddressString); - break; - case PHNETLC_REMOTEHOSTNAME: - getCellText->Text = PhGetStringRef(networkItem->RemoteHostString); - break; - case PHNETLC_REMOTEPORT: - PhInitializeStringRefLongHint(&getCellText->Text, networkItem->RemotePortString); - break; - case PHNETLC_PROTOCOL: - PhInitializeStringRefLongHint(&getCellText->Text, PhGetProtocolTypeName(networkItem->ProtocolType)); - break; - case PHNETLC_STATE: - if (networkItem->ProtocolType & PH_TCP_PROTOCOL_TYPE) - PhInitializeStringRefLongHint(&getCellText->Text, PhGetTcpStateName(networkItem->State)); - else - PhInitializeEmptyStringRef(&getCellText->Text); - break; - case PHNETLC_OWNER: - if (WINDOWS_HAS_SERVICE_TAGS) - getCellText->Text = PhGetStringRef(networkItem->OwnerName); - else - PhInitializeStringRef(&getCellText->Text, L"N/A"); // make sure the user knows this column doesn't work on XP - break; - case PHNETLC_TIMESTAMP: - { - SYSTEMTIME systemTime; - - if (networkItem->CreateTime.QuadPart != 0) - { - PhLargeIntegerToLocalSystemTime(&systemTime, &networkItem->CreateTime); - PhMoveReference(&node->TimeStampText, PhFormatDateTime(&systemTime)); - getCellText->Text = node->TimeStampText->sr; - } - else - { - PhInitializeEmptyStringRef(&getCellText->Text); - } - } - break; - default: - return FALSE; - } - - getCellText->Flags = TN_CACHE; - } - return TRUE; - case TreeNewGetNodeIcon: - { - PPH_TREENEW_GET_NODE_ICON getNodeIcon = Parameter1; - - node = (PPH_NETWORK_NODE)getNodeIcon->Node; - - if (node->NetworkItem->ProcessIconValid) - { - // TODO: Check if the icon handle is actually valid, since the process item - // might get destroyed while the network node is still valid. - getNodeIcon->Icon = node->NetworkItem->ProcessIcon; - } - else - { - PhGetStockApplicationIcon(&getNodeIcon->Icon, NULL); - } - - getNodeIcon->Flags = TN_CACHE; - } - return TRUE; - case TreeNewGetCellTooltip: - { - PPH_TREENEW_GET_CELL_TOOLTIP getCellTooltip = Parameter1; - PPH_PROCESS_ITEM processItem; - - node = (PPH_NETWORK_NODE)getCellTooltip->Node; - - if (getCellTooltip->Column->Id != 0) - return FALSE; - - if (!node->TooltipText) - { - if (processItem = PhReferenceProcessItem(node->NetworkItem->ProcessId)) - { - node->TooltipText = PhGetProcessTooltipText(processItem, NULL); - PhDereferenceObject(processItem); - } - } - - if (!PhIsNullOrEmptyString(node->TooltipText)) - { - getCellTooltip->Text = node->TooltipText->sr; - getCellTooltip->Unfolding = FALSE; - getCellTooltip->MaximumWidth = -1; - } - else - { - return FALSE; - } - } - return TRUE; - case TreeNewSortChanged: - { - TreeNew_GetSort(hwnd, &NetworkTreeListSortColumn, &NetworkTreeListSortOrder); - // Force a rebuild to sort the items. - TreeNew_NodesStructured(hwnd); - } - return TRUE; - case TreeNewKeyDown: - { - PPH_TREENEW_KEY_EVENT keyEvent = Parameter1; - - switch (keyEvent->VirtualKey) - { - case 'C': - if (GetKeyState(VK_CONTROL) < 0) - SendMessage(PhMainWndHandle, WM_COMMAND, ID_NETWORK_COPY, 0); - break; - case 'A': - if (GetKeyState(VK_CONTROL) < 0) - TreeNew_SelectRange(NetworkTreeListHandle, 0, -1); - break; - case VK_RETURN: - SendMessage(PhMainWndHandle, WM_COMMAND, ID_NETWORK_GOTOPROCESS, 0); - break; - } - } - return TRUE; - case TreeNewHeaderRightClick: - { - PH_TN_COLUMN_MENU_DATA data; - - data.TreeNewHandle = hwnd; - data.MouseEvent = Parameter1; - data.DefaultSortColumn = 0; - data.DefaultSortOrder = AscendingSortOrder; - PhInitializeTreeNewColumnMenu(&data); - - data.Selection = PhShowEMenu(data.Menu, hwnd, PH_EMENU_SHOW_LEFTRIGHT, - PH_ALIGN_LEFT | PH_ALIGN_TOP, data.MouseEvent->ScreenLocation.x, data.MouseEvent->ScreenLocation.y); - PhHandleTreeNewColumnMenu(&data); - PhDeleteTreeNewColumnMenu(&data); - } - return TRUE; - case TreeNewLeftDoubleClick: - { - SendMessage(PhMainWndHandle, WM_COMMAND, ID_NETWORK_GOTOPROCESS, 0); - } - return TRUE; - case TreeNewContextMenu: - { - PPH_TREENEW_CONTEXT_MENU contextMenu = Parameter1; - - PhShowNetworkContextMenu(contextMenu); - } - return TRUE; - } - - return FALSE; -} - -PPH_STRING PhpGetNetworkItemProcessName( - _In_ PPH_NETWORK_ITEM NetworkItem - ) -{ - PH_FORMAT format[4]; - - if (!NetworkItem->ProcessId) - return PhCreateString(L"Waiting connections"); - - PhInitFormatS(&format[1], L" ("); - PhInitFormatU(&format[2], HandleToUlong(NetworkItem->ProcessId)); - PhInitFormatC(&format[3], ')'); - - if (NetworkItem->ProcessName) - PhInitFormatSR(&format[0], NetworkItem->ProcessName->sr); - else - PhInitFormatS(&format[0], L"Unknown process"); - - return PhFormat(format, 4, 96); -} - -PPH_NETWORK_ITEM PhGetSelectedNetworkItem( - VOID - ) -{ - PPH_NETWORK_ITEM networkItem = NULL; - ULONG i; - - for (i = 0; i < NetworkNodeList->Count; i++) - { - PPH_NETWORK_NODE node = NetworkNodeList->Items[i]; - - if (node->Node.Selected) - { - networkItem = node->NetworkItem; - break; - } - } - - return networkItem; -} - -VOID PhGetSelectedNetworkItems( - _Out_ PPH_NETWORK_ITEM **NetworkItems, - _Out_ PULONG NumberOfNetworkItems - ) -{ - PH_ARRAY array; - ULONG i; - - PhInitializeArray(&array, sizeof(PVOID), 2); - - for (i = 0; i < NetworkNodeList->Count; i++) - { - PPH_NETWORK_NODE node = NetworkNodeList->Items[i]; - - if (node->Node.Selected) - PhAddItemArray(&array, &node->NetworkItem); - } - - *NumberOfNetworkItems = (ULONG)array.Count; - *NetworkItems = PhFinalArrayItems(&array); -} - -VOID PhDeselectAllNetworkNodes( - VOID - ) -{ - TreeNew_DeselectRange(NetworkTreeListHandle, 0, -1); -} - -VOID PhSelectAndEnsureVisibleNetworkNode( - _In_ PPH_NETWORK_NODE NetworkNode - ) -{ - PhDeselectAllNetworkNodes(); - - if (!NetworkNode->Node.Visible) - return; - - TreeNew_SetFocusNode(NetworkTreeListHandle, &NetworkNode->Node); - TreeNew_SetMarkNode(NetworkTreeListHandle, &NetworkNode->Node); - TreeNew_SelectRange(NetworkTreeListHandle, NetworkNode->Node.Index, NetworkNode->Node.Index); - TreeNew_EnsureVisible(NetworkTreeListHandle, &NetworkNode->Node); -} - -VOID PhCopyNetworkList( - VOID - ) -{ - PPH_STRING text; - - text = PhGetTreeNewText(NetworkTreeListHandle, 0); - PhSetClipboardString(NetworkTreeListHandle, &text->sr); - PhDereferenceObject(text); -} - -VOID PhWriteNetworkList( - _Inout_ PPH_FILE_STREAM FileStream, - _In_ ULONG Mode - ) -{ - PPH_LIST lines; - ULONG i; - - lines = PhGetGenericTreeNewLines(NetworkTreeListHandle, Mode); - - for (i = 0; i < lines->Count; i++) - { - PPH_STRING line; - - line = lines->Items[i]; - PhWriteStringAsUtf8FileStream(FileStream, &line->sr); - PhDereferenceObject(line); - PhWriteStringAsUtf8FileStream2(FileStream, L"\r\n"); - } - - PhDereferenceObject(lines); -} +/* + * Process Hacker - + * network list + * + * Copyright (C) 2011-2015 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +BOOLEAN PhpNetworkNodeHashtableEqualFunction( + _In_ PVOID Entry1, + _In_ PVOID Entry2 + ); + +ULONG PhpNetworkNodeHashtableHashFunction( + _In_ PVOID Entry + ); + +VOID PhpRemoveNetworkNode( + _In_ PPH_NETWORK_NODE NetworkNode + ); + +LONG PhpNetworkTreeNewPostSortFunction( + _In_ LONG Result, + _In_ PVOID Node1, + _In_ PVOID Node2, + _In_ PH_SORT_ORDER SortOrder + ); + +BOOLEAN NTAPI PhpNetworkTreeNewCallback( + _In_ HWND hwnd, + _In_ PH_TREENEW_MESSAGE Message, + _In_opt_ PVOID Parameter1, + _In_opt_ PVOID Parameter2, + _In_opt_ PVOID Context + ); + +PPH_STRING PhpGetNetworkItemProcessName( + _In_ PPH_NETWORK_ITEM NetworkItem + ); + +static HWND NetworkTreeListHandle; +static ULONG NetworkTreeListSortColumn; +static PH_SORT_ORDER NetworkTreeListSortOrder; +static PH_CM_MANAGER NetworkTreeListCm; + +static PPH_HASHTABLE NetworkNodeHashtable; // hashtable of all nodes +static PPH_LIST NetworkNodeList; // list of all nodes +static LONG NextUniqueId = 1; + +BOOLEAN PhNetworkTreeListStateHighlighting = TRUE; +static PPH_POINTER_LIST NetworkNodeStateList = NULL; // list of nodes which need to be processed + +static PH_TN_FILTER_SUPPORT FilterSupport; + +VOID PhNetworkTreeListInitialization( + VOID + ) +{ + NetworkNodeHashtable = PhCreateHashtable( + sizeof(PPH_NETWORK_NODE), + PhpNetworkNodeHashtableEqualFunction, + PhpNetworkNodeHashtableHashFunction, + 100 + ); + NetworkNodeList = PhCreateList(100); +} + +BOOLEAN PhpNetworkNodeHashtableEqualFunction( + _In_ PVOID Entry1, + _In_ PVOID Entry2 + ) +{ + PPH_NETWORK_NODE networkNode1 = *(PPH_NETWORK_NODE *)Entry1; + PPH_NETWORK_NODE networkNode2 = *(PPH_NETWORK_NODE *)Entry2; + + return networkNode1->NetworkItem == networkNode2->NetworkItem; +} + +ULONG PhpNetworkNodeHashtableHashFunction( + _In_ PVOID Entry + ) +{ + return PhHashIntPtr((ULONG_PTR)(*(PPH_NETWORK_NODE *)Entry)->NetworkItem); +} + +VOID PhInitializeNetworkTreeList( + _In_ HWND hwnd + ) +{ + NetworkTreeListHandle = hwnd; + PhSetControlTheme(NetworkTreeListHandle, L"explorer"); + SendMessage(TreeNew_GetTooltips(NetworkTreeListHandle), TTM_SETDELAYTIME, TTDT_AUTOPOP, MAXSHORT); + + TreeNew_SetCallback(hwnd, PhpNetworkTreeNewCallback, NULL); + + TreeNew_SetRedraw(hwnd, FALSE); + + // Default columns + PhAddTreeNewColumn(hwnd, PHNETLC_PROCESS, TRUE, L"Name", 100, PH_ALIGN_LEFT, 0, 0); + PhAddTreeNewColumn(hwnd, PHNETLC_LOCALADDRESS, TRUE, L"Local address", 120, PH_ALIGN_LEFT, 1, 0); + PhAddTreeNewColumn(hwnd, PHNETLC_LOCALPORT, TRUE, L"Local port", 50, PH_ALIGN_RIGHT, 2, DT_RIGHT); + PhAddTreeNewColumn(hwnd, PHNETLC_REMOTEADDRESS, TRUE, L"Remote address", 120, PH_ALIGN_LEFT, 3, 0); + PhAddTreeNewColumn(hwnd, PHNETLC_REMOTEPORT, TRUE, L"Remote port", 50, PH_ALIGN_RIGHT, 4, DT_RIGHT); + PhAddTreeNewColumn(hwnd, PHNETLC_PROTOCOL, TRUE, L"Protocol", 45, PH_ALIGN_LEFT, 5, 0); + PhAddTreeNewColumn(hwnd, PHNETLC_STATE, TRUE, L"State", 70, PH_ALIGN_LEFT, 6, 0); + PhAddTreeNewColumn(hwnd, PHNETLC_OWNER, WINDOWS_HAS_SERVICE_TAGS, L"Owner", 80, PH_ALIGN_LEFT, 7, 0); + PhAddTreeNewColumnEx(hwnd, PHNETLC_TIMESTAMP, FALSE, L"Time stamp", 100, PH_ALIGN_LEFT, -1, 0, TRUE); + PhAddTreeNewColumn(hwnd, PHNETLC_LOCALHOSTNAME, FALSE, L"Local hostname", 120, PH_ALIGN_LEFT, -1, 0); + PhAddTreeNewColumn(hwnd, PHNETLC_REMOTEHOSTNAME, FALSE, L"Remote hostname", 120, PH_ALIGN_LEFT, -1, 0); + + TreeNew_SetRedraw(hwnd, TRUE); + + TreeNew_SetSort(hwnd, 0, AscendingSortOrder); + + PhCmInitializeManager(&NetworkTreeListCm, hwnd, PHNETLC_MAXIMUM, PhpNetworkTreeNewPostSortFunction); + + if (PhPluginsEnabled) + { + PH_PLUGIN_TREENEW_INFORMATION treeNewInfo; + + treeNewInfo.TreeNewHandle = hwnd; + treeNewInfo.CmData = &NetworkTreeListCm; + PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackNetworkTreeNewInitializing), &treeNewInfo); + } + + PhInitializeTreeNewFilterSupport(&FilterSupport, hwnd, NetworkNodeList); +} + +VOID PhLoadSettingsNetworkTreeList( + VOID + ) +{ + PPH_STRING settings; + PPH_STRING sortSettings; + + settings = PhGetStringSetting(L"NetworkTreeListColumns"); + sortSettings = PhGetStringSetting(L"NetworkTreeListSort"); + PhCmLoadSettingsEx(NetworkTreeListHandle, &NetworkTreeListCm, 0, &settings->sr, &sortSettings->sr); + PhDereferenceObject(settings); + PhDereferenceObject(sortSettings); +} + +VOID PhSaveSettingsNetworkTreeList( + VOID + ) +{ + PPH_STRING settings; + PPH_STRING sortSettings; + + settings = PhCmSaveSettingsEx(NetworkTreeListHandle, &NetworkTreeListCm, 0, &sortSettings); + PhSetStringSetting2(L"NetworkTreeListColumns", &settings->sr); + PhSetStringSetting2(L"NetworkTreeListSort", &sortSettings->sr); + PhDereferenceObject(settings); + PhDereferenceObject(sortSettings); +} + +struct _PH_TN_FILTER_SUPPORT *PhGetFilterSupportNetworkTreeList( + VOID + ) +{ + return &FilterSupport; +} + +PPH_NETWORK_NODE PhAddNetworkNode( + _In_ PPH_NETWORK_ITEM NetworkItem, + _In_ ULONG RunId + ) +{ + PPH_NETWORK_NODE networkNode; + + networkNode = PhAllocate(PhEmGetObjectSize(EmNetworkNodeType, sizeof(PH_NETWORK_NODE))); + memset(networkNode, 0, sizeof(PH_NETWORK_NODE)); + PhInitializeTreeNewNode(&networkNode->Node); + + if (PhNetworkTreeListStateHighlighting && RunId != 1) + { + PhChangeShStateTn( + &networkNode->Node, + &networkNode->ShState, + &NetworkNodeStateList, + NewItemState, + PhCsColorNew, + NULL + ); + } + + networkNode->NetworkItem = NetworkItem; + PhReferenceObject(NetworkItem); + networkNode->UniqueId = NextUniqueId++; // used to stabilize sorting + + memset(networkNode->TextCache, 0, sizeof(PH_STRINGREF) * PHNETLC_MAXIMUM); + networkNode->Node.TextCache = networkNode->TextCache; + networkNode->Node.TextCacheSize = PHNETLC_MAXIMUM; + + networkNode->ProcessNameText = PhpGetNetworkItemProcessName(NetworkItem); + + PhAddEntryHashtable(NetworkNodeHashtable, &networkNode); + PhAddItemList(NetworkNodeList, networkNode); + + if (FilterSupport.NodeList) + networkNode->Node.Visible = PhApplyTreeNewFiltersToNode(&FilterSupport, &networkNode->Node); + + PhEmCallObjectOperation(EmNetworkNodeType, networkNode, EmObjectCreate); + + TreeNew_NodesStructured(NetworkTreeListHandle); + + return networkNode; +} + +PPH_NETWORK_NODE PhFindNetworkNode( + _In_ PPH_NETWORK_ITEM NetworkItem + ) +{ + PH_NETWORK_NODE lookupNetworkNode; + PPH_NETWORK_NODE lookupNetworkNodePtr = &lookupNetworkNode; + PPH_NETWORK_NODE *networkNode; + + lookupNetworkNode.NetworkItem = NetworkItem; + + networkNode = (PPH_NETWORK_NODE *)PhFindEntryHashtable( + NetworkNodeHashtable, + &lookupNetworkNodePtr + ); + + if (networkNode) + return *networkNode; + else + return NULL; +} + +VOID PhRemoveNetworkNode( + _In_ PPH_NETWORK_NODE NetworkNode + ) +{ + // Remove from the hashtable here to avoid problems in case the key is re-used. + PhRemoveEntryHashtable(NetworkNodeHashtable, &NetworkNode); + + if (PhNetworkTreeListStateHighlighting) + { + PhChangeShStateTn( + &NetworkNode->Node, + &NetworkNode->ShState, + &NetworkNodeStateList, + RemovingItemState, + PhCsColorRemoved, + NetworkTreeListHandle + ); + } + else + { + PhpRemoveNetworkNode(NetworkNode); + } +} + +VOID PhpRemoveNetworkNode( + _In_ PPH_NETWORK_NODE NetworkNode + ) +{ + ULONG index; + + PhEmCallObjectOperation(EmNetworkNodeType, NetworkNode, EmObjectDelete); + + // Remove from list and cleanup. + + if ((index = PhFindItemList(NetworkNodeList, NetworkNode)) != -1) + PhRemoveItemList(NetworkNodeList, index); + + if (NetworkNode->ProcessNameText) PhDereferenceObject(NetworkNode->ProcessNameText); + if (NetworkNode->TimeStampText) PhDereferenceObject(NetworkNode->TimeStampText); + if (NetworkNode->TooltipText) PhDereferenceObject(NetworkNode->TooltipText); + + PhDereferenceObject(NetworkNode->NetworkItem); + + PhFree(NetworkNode); + + TreeNew_NodesStructured(NetworkTreeListHandle); +} + +VOID PhUpdateNetworkNode( + _In_ PPH_NETWORK_NODE NetworkNode + ) +{ + memset(NetworkNode->TextCache, 0, sizeof(PH_STRINGREF) * PHNETLC_MAXIMUM); + PhClearReference(&NetworkNode->TooltipText); + + PhInvalidateTreeNewNode(&NetworkNode->Node, TN_CACHE_ICON); + TreeNew_NodesStructured(NetworkTreeListHandle); +} + +VOID PhTickNetworkNodes( + VOID + ) +{ + if (NetworkTreeListSortOrder != NoSortOrder && NetworkTreeListSortColumn >= PHNETLC_MAXIMUM) + { + // Sorting is on, but it's not one of our columns. Force a rebuild. (If it was one of our + // columns, the restructure would have been handled in PhUpdateNetworkNode.) + TreeNew_NodesStructured(NetworkTreeListHandle); + } + + PH_TICK_SH_STATE_TN(PH_NETWORK_NODE, ShState, NetworkNodeStateList, PhpRemoveNetworkNode, PhCsHighlightingDuration, NetworkTreeListHandle, TRUE, NULL); +} + +#define SORT_FUNCTION(Column) PhpNetworkTreeNewCompare##Column + +#define BEGIN_SORT_FUNCTION(Column) static int __cdecl PhpNetworkTreeNewCompare##Column( \ + _In_ const void *_elem1, \ + _In_ const void *_elem2 \ + ) \ +{ \ + PPH_NETWORK_NODE node1 = *(PPH_NETWORK_NODE *)_elem1; \ + PPH_NETWORK_NODE node2 = *(PPH_NETWORK_NODE *)_elem2; \ + PPH_NETWORK_ITEM networkItem1 = node1->NetworkItem; \ + PPH_NETWORK_ITEM networkItem2 = node2->NetworkItem; \ + int sortResult = 0; + +#define END_SORT_FUNCTION \ + if (sortResult == 0) \ + sortResult = intcmp(node1->UniqueId, node2->UniqueId); \ + \ + return PhModifySort(sortResult, NetworkTreeListSortOrder); \ +} + +LONG PhpNetworkTreeNewPostSortFunction( + _In_ LONG Result, + _In_ PVOID Node1, + _In_ PVOID Node2, + _In_ PH_SORT_ORDER SortOrder + ) +{ + if (Result == 0) + Result = intcmp(((PPH_NETWORK_NODE)Node1)->UniqueId, ((PPH_NETWORK_NODE)Node2)->UniqueId); + + return PhModifySort(Result, SortOrder); +} + +BEGIN_SORT_FUNCTION(Process) +{ + sortResult = PhCompareString(node1->ProcessNameText, node2->ProcessNameText, TRUE); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(LocalAddress) +{ + sortResult = PhCompareStringZ(networkItem1->LocalAddressString, networkItem2->LocalAddressString, TRUE); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(LocalHostname) +{ + sortResult = PhCompareStringWithNull(networkItem1->LocalHostString, networkItem2->LocalHostString, TRUE); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(LocalPort) +{ + sortResult = uintcmp(networkItem1->LocalEndpoint.Port, networkItem2->LocalEndpoint.Port); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(RemoteAddress) +{ + sortResult = PhCompareStringZ(networkItem1->RemoteAddressString, networkItem2->RemoteAddressString, TRUE); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(RemoteHostname) +{ + sortResult = PhCompareStringWithNull(networkItem1->RemoteHostString, networkItem2->RemoteHostString, TRUE); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(RemotePort) +{ + sortResult = uintcmp(networkItem1->RemoteEndpoint.Port, networkItem2->RemoteEndpoint.Port); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(Protocol) +{ + sortResult = uintcmp(networkItem1->ProtocolType, networkItem2->ProtocolType); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(State) +{ + sortResult = uintcmp(networkItem1->State, networkItem2->State); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(Owner) +{ + sortResult = PhCompareStringWithNull(networkItem1->OwnerName, networkItem2->OwnerName, TRUE); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(TimeStamp) +{ + sortResult = uint64cmp(networkItem1->CreateTime.QuadPart, networkItem2->CreateTime.QuadPart); +} +END_SORT_FUNCTION + +BOOLEAN NTAPI PhpNetworkTreeNewCallback( + _In_ HWND hwnd, + _In_ PH_TREENEW_MESSAGE Message, + _In_opt_ PVOID Parameter1, + _In_opt_ PVOID Parameter2, + _In_opt_ PVOID Context + ) +{ + PPH_NETWORK_NODE node; + + if (PhCmForwardMessage(hwnd, Message, Parameter1, Parameter2, &NetworkTreeListCm)) + return TRUE; + + switch (Message) + { + case TreeNewGetChildren: + { + PPH_TREENEW_GET_CHILDREN getChildren = Parameter1; + + if (!getChildren->Node) + { + static PVOID sortFunctions[] = + { + SORT_FUNCTION(Process), + SORT_FUNCTION(LocalAddress), + SORT_FUNCTION(LocalHostname), + SORT_FUNCTION(LocalPort), + SORT_FUNCTION(RemoteAddress), + SORT_FUNCTION(RemoteHostname), + SORT_FUNCTION(RemotePort), + SORT_FUNCTION(Protocol), + SORT_FUNCTION(State), + SORT_FUNCTION(Owner), + SORT_FUNCTION(TimeStamp) + }; + int (__cdecl *sortFunction)(const void *, const void *); + + if (!PhCmForwardSort( + (PPH_TREENEW_NODE *)NetworkNodeList->Items, + NetworkNodeList->Count, + NetworkTreeListSortColumn, + NetworkTreeListSortOrder, + &NetworkTreeListCm + )) + { + if (NetworkTreeListSortColumn < PHNETLC_MAXIMUM) + sortFunction = sortFunctions[NetworkTreeListSortColumn]; + else + sortFunction = NULL; + + if (sortFunction) + { + qsort(NetworkNodeList->Items, NetworkNodeList->Count, sizeof(PVOID), sortFunction); + } + } + + getChildren->Children = (PPH_TREENEW_NODE *)NetworkNodeList->Items; + getChildren->NumberOfChildren = NetworkNodeList->Count; + } + } + return TRUE; + case TreeNewIsLeaf: + { + PPH_TREENEW_IS_LEAF isLeaf = Parameter1; + + isLeaf->IsLeaf = TRUE; + } + return TRUE; + case TreeNewGetCellText: + { + PPH_TREENEW_GET_CELL_TEXT getCellText = Parameter1; + PPH_NETWORK_ITEM networkItem; + + node = (PPH_NETWORK_NODE)getCellText->Node; + networkItem = node->NetworkItem; + + switch (getCellText->Id) + { + case PHNETLC_PROCESS: + getCellText->Text = node->ProcessNameText->sr; + break; + case PHNETLC_LOCALADDRESS: + PhInitializeStringRefLongHint(&getCellText->Text, networkItem->LocalAddressString); + break; + case PHNETLC_LOCALHOSTNAME: + getCellText->Text = PhGetStringRef(networkItem->LocalHostString); + break; + case PHNETLC_LOCALPORT: + PhInitializeStringRefLongHint(&getCellText->Text, networkItem->LocalPortString); + break; + case PHNETLC_REMOTEADDRESS: + PhInitializeStringRefLongHint(&getCellText->Text, networkItem->RemoteAddressString); + break; + case PHNETLC_REMOTEHOSTNAME: + getCellText->Text = PhGetStringRef(networkItem->RemoteHostString); + break; + case PHNETLC_REMOTEPORT: + PhInitializeStringRefLongHint(&getCellText->Text, networkItem->RemotePortString); + break; + case PHNETLC_PROTOCOL: + PhInitializeStringRefLongHint(&getCellText->Text, PhGetProtocolTypeName(networkItem->ProtocolType)); + break; + case PHNETLC_STATE: + if (networkItem->ProtocolType & PH_TCP_PROTOCOL_TYPE) + PhInitializeStringRefLongHint(&getCellText->Text, PhGetTcpStateName(networkItem->State)); + else + PhInitializeEmptyStringRef(&getCellText->Text); + break; + case PHNETLC_OWNER: + if (WINDOWS_HAS_SERVICE_TAGS) + getCellText->Text = PhGetStringRef(networkItem->OwnerName); + else + PhInitializeStringRef(&getCellText->Text, L"N/A"); // make sure the user knows this column doesn't work on XP + break; + case PHNETLC_TIMESTAMP: + { + SYSTEMTIME systemTime; + + if (networkItem->CreateTime.QuadPart != 0) + { + PhLargeIntegerToLocalSystemTime(&systemTime, &networkItem->CreateTime); + PhMoveReference(&node->TimeStampText, PhFormatDateTime(&systemTime)); + getCellText->Text = node->TimeStampText->sr; + } + else + { + PhInitializeEmptyStringRef(&getCellText->Text); + } + } + break; + default: + return FALSE; + } + + getCellText->Flags = TN_CACHE; + } + return TRUE; + case TreeNewGetNodeIcon: + { + PPH_TREENEW_GET_NODE_ICON getNodeIcon = Parameter1; + + node = (PPH_NETWORK_NODE)getNodeIcon->Node; + + if (node->NetworkItem->ProcessIconValid) + { + // TODO: Check if the icon handle is actually valid, since the process item + // might get destroyed while the network node is still valid. + getNodeIcon->Icon = node->NetworkItem->ProcessIcon; + } + else + { + PhGetStockApplicationIcon(&getNodeIcon->Icon, NULL); + } + + getNodeIcon->Flags = TN_CACHE; + } + return TRUE; + case TreeNewGetCellTooltip: + { + PPH_TREENEW_GET_CELL_TOOLTIP getCellTooltip = Parameter1; + PPH_PROCESS_ITEM processItem; + + node = (PPH_NETWORK_NODE)getCellTooltip->Node; + + if (getCellTooltip->Column->Id != 0) + return FALSE; + + if (!node->TooltipText) + { + if (processItem = PhReferenceProcessItem(node->NetworkItem->ProcessId)) + { + node->TooltipText = PhGetProcessTooltipText(processItem, NULL); + PhDereferenceObject(processItem); + } + } + + if (!PhIsNullOrEmptyString(node->TooltipText)) + { + getCellTooltip->Text = node->TooltipText->sr; + getCellTooltip->Unfolding = FALSE; + getCellTooltip->MaximumWidth = -1; + } + else + { + return FALSE; + } + } + return TRUE; + case TreeNewSortChanged: + { + TreeNew_GetSort(hwnd, &NetworkTreeListSortColumn, &NetworkTreeListSortOrder); + // Force a rebuild to sort the items. + TreeNew_NodesStructured(hwnd); + } + return TRUE; + case TreeNewKeyDown: + { + PPH_TREENEW_KEY_EVENT keyEvent = Parameter1; + + switch (keyEvent->VirtualKey) + { + case 'C': + if (GetKeyState(VK_CONTROL) < 0) + SendMessage(PhMainWndHandle, WM_COMMAND, ID_NETWORK_COPY, 0); + break; + case 'A': + if (GetKeyState(VK_CONTROL) < 0) + TreeNew_SelectRange(NetworkTreeListHandle, 0, -1); + break; + case VK_RETURN: + SendMessage(PhMainWndHandle, WM_COMMAND, ID_NETWORK_GOTOPROCESS, 0); + break; + } + } + return TRUE; + case TreeNewHeaderRightClick: + { + PH_TN_COLUMN_MENU_DATA data; + + data.TreeNewHandle = hwnd; + data.MouseEvent = Parameter1; + data.DefaultSortColumn = 0; + data.DefaultSortOrder = AscendingSortOrder; + PhInitializeTreeNewColumnMenu(&data); + + data.Selection = PhShowEMenu(data.Menu, hwnd, PH_EMENU_SHOW_LEFTRIGHT, + PH_ALIGN_LEFT | PH_ALIGN_TOP, data.MouseEvent->ScreenLocation.x, data.MouseEvent->ScreenLocation.y); + PhHandleTreeNewColumnMenu(&data); + PhDeleteTreeNewColumnMenu(&data); + } + return TRUE; + case TreeNewLeftDoubleClick: + { + SendMessage(PhMainWndHandle, WM_COMMAND, ID_NETWORK_GOTOPROCESS, 0); + } + return TRUE; + case TreeNewContextMenu: + { + PPH_TREENEW_CONTEXT_MENU contextMenu = Parameter1; + + PhShowNetworkContextMenu(contextMenu); + } + return TRUE; + } + + return FALSE; +} + +PPH_STRING PhpGetNetworkItemProcessName( + _In_ PPH_NETWORK_ITEM NetworkItem + ) +{ + PH_FORMAT format[4]; + + if (!NetworkItem->ProcessId) + return PhCreateString(L"Waiting connections"); + + PhInitFormatS(&format[1], L" ("); + PhInitFormatU(&format[2], HandleToUlong(NetworkItem->ProcessId)); + PhInitFormatC(&format[3], ')'); + + if (NetworkItem->ProcessName) + PhInitFormatSR(&format[0], NetworkItem->ProcessName->sr); + else + PhInitFormatS(&format[0], L"Unknown process"); + + return PhFormat(format, 4, 96); +} + +PPH_NETWORK_ITEM PhGetSelectedNetworkItem( + VOID + ) +{ + PPH_NETWORK_ITEM networkItem = NULL; + ULONG i; + + for (i = 0; i < NetworkNodeList->Count; i++) + { + PPH_NETWORK_NODE node = NetworkNodeList->Items[i]; + + if (node->Node.Selected) + { + networkItem = node->NetworkItem; + break; + } + } + + return networkItem; +} + +VOID PhGetSelectedNetworkItems( + _Out_ PPH_NETWORK_ITEM **NetworkItems, + _Out_ PULONG NumberOfNetworkItems + ) +{ + PH_ARRAY array; + ULONG i; + + PhInitializeArray(&array, sizeof(PVOID), 2); + + for (i = 0; i < NetworkNodeList->Count; i++) + { + PPH_NETWORK_NODE node = NetworkNodeList->Items[i]; + + if (node->Node.Selected) + PhAddItemArray(&array, &node->NetworkItem); + } + + *NumberOfNetworkItems = (ULONG)array.Count; + *NetworkItems = PhFinalArrayItems(&array); +} + +VOID PhDeselectAllNetworkNodes( + VOID + ) +{ + TreeNew_DeselectRange(NetworkTreeListHandle, 0, -1); +} + +VOID PhSelectAndEnsureVisibleNetworkNode( + _In_ PPH_NETWORK_NODE NetworkNode + ) +{ + PhDeselectAllNetworkNodes(); + + if (!NetworkNode->Node.Visible) + return; + + TreeNew_SetFocusNode(NetworkTreeListHandle, &NetworkNode->Node); + TreeNew_SetMarkNode(NetworkTreeListHandle, &NetworkNode->Node); + TreeNew_SelectRange(NetworkTreeListHandle, NetworkNode->Node.Index, NetworkNode->Node.Index); + TreeNew_EnsureVisible(NetworkTreeListHandle, &NetworkNode->Node); +} + +VOID PhCopyNetworkList( + VOID + ) +{ + PPH_STRING text; + + text = PhGetTreeNewText(NetworkTreeListHandle, 0); + PhSetClipboardString(NetworkTreeListHandle, &text->sr); + PhDereferenceObject(text); +} + +VOID PhWriteNetworkList( + _Inout_ PPH_FILE_STREAM FileStream, + _In_ ULONG Mode + ) +{ + PPH_LIST lines; + ULONG i; + + lines = PhGetGenericTreeNewLines(NetworkTreeListHandle, Mode); + + for (i = 0; i < lines->Count; i++) + { + PPH_STRING line; + + line = lines->Items[i]; + PhWriteStringAsUtf8FileStream(FileStream, &line->sr); + PhDereferenceObject(line); + PhWriteStringAsUtf8FileStream2(FileStream, L"\r\n"); + } + + PhDereferenceObject(lines); +} diff --git a/ProcessHacker/netprv.c b/ProcessHacker/netprv.c index 9d79ec30219c..d3cc1187db6a 100644 --- a/ProcessHacker/netprv.c +++ b/ProcessHacker/netprv.c @@ -1,996 +1,996 @@ -/* - * Process Hacker - - * network provider - * - * Copyright (C) 2010 wj32 - * Copyright (C) 2010 evilpie - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include -#include - -#include -#include -#include - -#include -#include - -#include -#include - -typedef struct _PH_NETWORK_CONNECTION -{ - ULONG ProtocolType; - PH_IP_ENDPOINT LocalEndpoint; - PH_IP_ENDPOINT RemoteEndpoint; - ULONG State; - HANDLE ProcessId; - LARGE_INTEGER CreateTime; - ULONGLONG OwnerInfo[PH_NETWORK_OWNER_INFO_SIZE]; -} PH_NETWORK_CONNECTION, *PPH_NETWORK_CONNECTION; - -typedef struct _PH_NETWORK_ITEM_QUERY_DATA -{ - SLIST_ENTRY ListEntry; - PPH_NETWORK_ITEM NetworkItem; - - PH_IP_ADDRESS Address; - BOOLEAN Remote; - PPH_STRING HostString; -} PH_NETWORK_ITEM_QUERY_DATA, *PPH_NETWORK_ITEM_QUERY_DATA; - -typedef struct _PHP_RESOLVE_CACHE_ITEM -{ - PH_IP_ADDRESS Address; - PPH_STRING HostString; -} PHP_RESOLVE_CACHE_ITEM, *PPHP_RESOLVE_CACHE_ITEM; - -VOID NTAPI PhpNetworkItemDeleteProcedure( - _In_ PVOID Object, - _In_ ULONG Flags - ); - -BOOLEAN PhpNetworkHashtableEqualFunction( - _In_ PVOID Entry1, - _In_ PVOID Entry2 - ); - -ULONG NTAPI PhpNetworkHashtableHashFunction( - _In_ PVOID Entry - ); - -BOOLEAN PhpResolveCacheHashtableEqualFunction( - _In_ PVOID Entry1, - _In_ PVOID Entry2 - ); - -ULONG NTAPI PhpResolveCacheHashtableHashFunction( - _In_ PVOID Entry - ); - -BOOLEAN PhGetNetworkConnections( - _Out_ PPH_NETWORK_CONNECTION *Connections, - _Out_ PULONG NumberOfConnections - ); - -PPH_OBJECT_TYPE PhNetworkItemType; - -PPH_HASHTABLE PhNetworkHashtable; -PH_QUEUED_LOCK PhNetworkHashtableLock = PH_QUEUED_LOCK_INIT; - -PHAPPAPI PH_CALLBACK_DECLARE(PhNetworkItemAddedEvent); -PHAPPAPI PH_CALLBACK_DECLARE(PhNetworkItemModifiedEvent); -PHAPPAPI PH_CALLBACK_DECLARE(PhNetworkItemRemovedEvent); -PHAPPAPI PH_CALLBACK_DECLARE(PhNetworkItemsUpdatedEvent); - -PH_INITONCE PhNetworkProviderWorkQueueInitOnce = PH_INITONCE_INIT; -PH_WORK_QUEUE PhNetworkProviderWorkQueue; -SLIST_HEADER PhNetworkItemQueryListHead; - -BOOLEAN PhEnableNetworkProviderResolve = TRUE; -static BOOLEAN NetworkImportDone = FALSE; -static PPH_HASHTABLE PhpResolveCacheHashtable; -static PH_QUEUED_LOCK PhpResolveCacheHashtableLock = PH_QUEUED_LOCK_INIT; - -BOOLEAN PhNetworkProviderInitialization( - VOID - ) -{ - PhNetworkItemType = PhCreateObjectType(L"NetworkItem", 0, PhpNetworkItemDeleteProcedure); - PhNetworkHashtable = PhCreateHashtable( - sizeof(PPH_NETWORK_ITEM), - PhpNetworkHashtableEqualFunction, - PhpNetworkHashtableHashFunction, - 40 - ); - - RtlInitializeSListHead(&PhNetworkItemQueryListHead); - - PhpResolveCacheHashtable = PhCreateHashtable( - sizeof(PHP_RESOLVE_CACHE_ITEM), - PhpResolveCacheHashtableEqualFunction, - PhpResolveCacheHashtableHashFunction, - 20 - ); - - return TRUE; -} - -PPH_NETWORK_ITEM PhCreateNetworkItem( - VOID - ) -{ - PPH_NETWORK_ITEM networkItem; - - networkItem = PhCreateObject( - PhEmGetObjectSize(EmNetworkItemType, sizeof(PH_NETWORK_ITEM)), - PhNetworkItemType - ); - memset(networkItem, 0, sizeof(PH_NETWORK_ITEM)); - PhEmCallObjectOperation(EmNetworkItemType, networkItem, EmObjectCreate); - - return networkItem; -} - -VOID NTAPI PhpNetworkItemDeleteProcedure( - _In_ PVOID Object, - _In_ ULONG Flags - ) -{ - PPH_NETWORK_ITEM networkItem = (PPH_NETWORK_ITEM)Object; - - PhEmCallObjectOperation(EmNetworkItemType, networkItem, EmObjectDelete); - - if (networkItem->ProcessName) - PhDereferenceObject(networkItem->ProcessName); - if (networkItem->OwnerName) - PhDereferenceObject(networkItem->OwnerName); - if (networkItem->LocalHostString) - PhDereferenceObject(networkItem->LocalHostString); - if (networkItem->RemoteHostString) - PhDereferenceObject(networkItem->RemoteHostString); -} - -BOOLEAN PhpNetworkHashtableEqualFunction( - _In_ PVOID Entry1, - _In_ PVOID Entry2 - ) -{ - PPH_NETWORK_ITEM networkItem1 = *(PPH_NETWORK_ITEM *)Entry1; - PPH_NETWORK_ITEM networkItem2 = *(PPH_NETWORK_ITEM *)Entry2; - - return - networkItem1->ProtocolType == networkItem2->ProtocolType && - PhEqualIpEndpoint(&networkItem1->LocalEndpoint, &networkItem2->LocalEndpoint) && - PhEqualIpEndpoint(&networkItem1->RemoteEndpoint, &networkItem2->RemoteEndpoint) && - networkItem1->ProcessId == networkItem2->ProcessId; -} - -ULONG NTAPI PhpNetworkHashtableHashFunction( - _In_ PVOID Entry - ) -{ - PPH_NETWORK_ITEM networkItem = *(PPH_NETWORK_ITEM *)Entry; - - return - networkItem->ProtocolType ^ - PhHashIpEndpoint(&networkItem->LocalEndpoint) ^ - PhHashIpEndpoint(&networkItem->RemoteEndpoint) ^ - HandleToUlong(networkItem->ProcessId); -} - -PPH_NETWORK_ITEM PhReferenceNetworkItem( - _In_ ULONG ProtocolType, - _In_ PPH_IP_ENDPOINT LocalEndpoint, - _In_ PPH_IP_ENDPOINT RemoteEndpoint, - _In_ HANDLE ProcessId - ) -{ - PH_NETWORK_ITEM lookupNetworkItem; - PPH_NETWORK_ITEM lookupNetworkItemPtr = &lookupNetworkItem; - PPH_NETWORK_ITEM *networkItemPtr; - PPH_NETWORK_ITEM networkItem; - - lookupNetworkItem.ProtocolType = ProtocolType; - lookupNetworkItem.LocalEndpoint = *LocalEndpoint; - lookupNetworkItem.RemoteEndpoint = *RemoteEndpoint; - lookupNetworkItem.ProcessId = ProcessId; - - PhAcquireQueuedLockShared(&PhNetworkHashtableLock); - - networkItemPtr = (PPH_NETWORK_ITEM *)PhFindEntryHashtable( - PhNetworkHashtable, - &lookupNetworkItemPtr - ); - - if (networkItemPtr) - { - networkItem = *networkItemPtr; - PhReferenceObject(networkItem); - } - else - { - networkItem = NULL; - } - - PhReleaseQueuedLockShared(&PhNetworkHashtableLock); - - return networkItem; -} - -VOID PhpRemoveNetworkItem( - _In_ PPH_NETWORK_ITEM NetworkItem - ) -{ - PhRemoveEntryHashtable(PhNetworkHashtable, &NetworkItem); - PhDereferenceObject(NetworkItem); -} - -BOOLEAN PhpResolveCacheHashtableEqualFunction( - _In_ PVOID Entry1, - _In_ PVOID Entry2 - ) -{ - PPHP_RESOLVE_CACHE_ITEM cacheItem1 = *(PPHP_RESOLVE_CACHE_ITEM *)Entry1; - PPHP_RESOLVE_CACHE_ITEM cacheItem2 = *(PPHP_RESOLVE_CACHE_ITEM *)Entry2; - - return PhEqualIpAddress(&cacheItem1->Address, &cacheItem2->Address); -} - -ULONG NTAPI PhpResolveCacheHashtableHashFunction( - _In_ PVOID Entry - ) -{ - PPHP_RESOLVE_CACHE_ITEM cacheItem = *(PPHP_RESOLVE_CACHE_ITEM *)Entry; - - return PhHashIpAddress(&cacheItem->Address); -} - -PPHP_RESOLVE_CACHE_ITEM PhpLookupResolveCacheItem( - _In_ PPH_IP_ADDRESS Address - ) -{ - PHP_RESOLVE_CACHE_ITEM lookupCacheItem; - PPHP_RESOLVE_CACHE_ITEM lookupCacheItemPtr = &lookupCacheItem; - PPHP_RESOLVE_CACHE_ITEM *cacheItemPtr; - - // Construct a temporary cache item for the lookup. - lookupCacheItem.Address = *Address; - - cacheItemPtr = (PPHP_RESOLVE_CACHE_ITEM *)PhFindEntryHashtable( - PhpResolveCacheHashtable, - &lookupCacheItemPtr - ); - - if (cacheItemPtr) - return *cacheItemPtr; - else - return NULL; -} - -PPH_STRING PhGetHostNameFromAddress( - _In_ PPH_IP_ADDRESS Address - ) -{ - struct sockaddr_in ipv4Address; - struct sockaddr_in6 ipv6Address; - struct sockaddr *address; - socklen_t length; - PPH_STRING hostName; - - if (Address->Type == PH_IPV4_NETWORK_TYPE) - { - ipv4Address.sin_family = AF_INET; - ipv4Address.sin_port = 0; - ipv4Address.sin_addr = Address->InAddr; - address = (struct sockaddr *)&ipv4Address; - length = sizeof(ipv4Address); - } - else if (Address->Type == PH_IPV6_NETWORK_TYPE) - { - ipv6Address.sin6_family = AF_INET6; - ipv6Address.sin6_port = 0; - ipv6Address.sin6_flowinfo = 0; - ipv6Address.sin6_addr = Address->In6Addr; - ipv6Address.sin6_scope_id = 0; - address = (struct sockaddr *)&ipv6Address; - length = sizeof(ipv6Address); - } - else - { - return NULL; - } - - hostName = PhCreateStringEx(NULL, 128); - - if (GetNameInfoW( - address, - length, - hostName->Buffer, - (ULONG)hostName->Length / 2 + 1, - NULL, - 0, - NI_NAMEREQD - ) != 0) - { - // Try with the maximum host name size. - PhDereferenceObject(hostName); - hostName = PhCreateStringEx(NULL, NI_MAXHOST * 2); - - if (GetNameInfoW( - address, - length, - hostName->Buffer, - (ULONG)hostName->Length / 2 + 1, - NULL, - 0, - NI_NAMEREQD - ) != 0) - { - PhDereferenceObject(hostName); - - return NULL; - } - } - - PhTrimToNullTerminatorString(hostName); - - return hostName; -} - -NTSTATUS PhpNetworkItemQueryWorker( - _In_ PVOID Parameter - ) -{ - PPH_NETWORK_ITEM_QUERY_DATA data = (PPH_NETWORK_ITEM_QUERY_DATA)Parameter; - PPH_STRING hostString; - PPHP_RESOLVE_CACHE_ITEM cacheItem; - - // Last minute check of the cache. - - PhAcquireQueuedLockShared(&PhpResolveCacheHashtableLock); - cacheItem = PhpLookupResolveCacheItem(&data->Address); - PhReleaseQueuedLockShared(&PhpResolveCacheHashtableLock); - - if (!cacheItem) - { - hostString = PhGetHostNameFromAddress(&data->Address); - - if (hostString) - { - data->HostString = hostString; - - // Update the cache. - - PhAcquireQueuedLockExclusive(&PhpResolveCacheHashtableLock); - - cacheItem = PhpLookupResolveCacheItem(&data->Address); - - if (!cacheItem) - { - cacheItem = PhAllocate(sizeof(PHP_RESOLVE_CACHE_ITEM)); - cacheItem->Address = data->Address; - cacheItem->HostString = hostString; - PhReferenceObject(hostString); - - PhAddEntryHashtable(PhpResolveCacheHashtable, &cacheItem); - } - - PhReleaseQueuedLockExclusive(&PhpResolveCacheHashtableLock); - } - } - else - { - PhReferenceObject(cacheItem->HostString); - data->HostString = cacheItem->HostString; - } - - RtlInterlockedPushEntrySList(&PhNetworkItemQueryListHead, &data->ListEntry); - - return STATUS_SUCCESS; -} - -VOID PhpQueueNetworkItemQuery( - _In_ PPH_NETWORK_ITEM NetworkItem, - _In_ BOOLEAN Remote - ) -{ - PPH_NETWORK_ITEM_QUERY_DATA data; - - if (!PhEnableNetworkProviderResolve) - return; - - data = PhAllocate(sizeof(PH_NETWORK_ITEM_QUERY_DATA)); - memset(data, 0, sizeof(PH_NETWORK_ITEM_QUERY_DATA)); - data->NetworkItem = NetworkItem; - data->Remote = Remote; - - if (Remote) - data->Address = NetworkItem->RemoteEndpoint.Address; - else - data->Address = NetworkItem->LocalEndpoint.Address; - - PhReferenceObject(NetworkItem); - - if (PhBeginInitOnce(&PhNetworkProviderWorkQueueInitOnce)) - { - PhInitializeWorkQueue(&PhNetworkProviderWorkQueue, 0, 3, 500); - PhEndInitOnce(&PhNetworkProviderWorkQueueInitOnce); - } - - PhQueueItemWorkQueue(&PhNetworkProviderWorkQueue, PhpNetworkItemQueryWorker, data); -} - -VOID PhpUpdateNetworkItemOwner( - _In_ PPH_NETWORK_ITEM NetworkItem, - _In_ PPH_PROCESS_ITEM ProcessItem - ) -{ - if (*(PULONG64)NetworkItem->OwnerInfo) - { - PVOID serviceTag; - PPH_STRING serviceName; - - // May change in the future... - serviceTag = UlongToPtr(*(PULONG)NetworkItem->OwnerInfo); - serviceName = PhGetServiceNameFromTag(NetworkItem->ProcessId, serviceTag); - - if (serviceName) - PhMoveReference(&NetworkItem->OwnerName, serviceName); - } -} - -VOID PhNetworkProviderUpdate( - _In_ PVOID Object - ) -{ - PPH_NETWORK_CONNECTION connections; - ULONG numberOfConnections; - ULONG i; - - if (!NetworkImportDone) - { - WSADATA wsaData; - - // Make sure WSA is initialized. - WSAStartup(WINSOCK_VERSION, &wsaData); - NetworkImportDone = TRUE; - } - - if (!PhGetNetworkConnections(&connections, &numberOfConnections)) - return; - - { - PPH_LIST connectionsToRemove = NULL; - PH_HASHTABLE_ENUM_CONTEXT enumContext; - PPH_NETWORK_ITEM *networkItem; - - PhBeginEnumHashtable(PhNetworkHashtable, &enumContext); - - while (networkItem = PhNextEnumHashtable(&enumContext)) - { - BOOLEAN found = FALSE; - - for (i = 0; i < numberOfConnections; i++) - { - if ( - (*networkItem)->ProtocolType == connections[i].ProtocolType && - PhEqualIpEndpoint(&(*networkItem)->LocalEndpoint, &connections[i].LocalEndpoint) && - PhEqualIpEndpoint(&(*networkItem)->RemoteEndpoint, &connections[i].RemoteEndpoint) && - (*networkItem)->ProcessId == connections[i].ProcessId - ) - { - found = TRUE; - break; - } - } - - if (!found) - { - PhInvokeCallback(&PhNetworkItemRemovedEvent, *networkItem); - - if (!connectionsToRemove) - connectionsToRemove = PhCreateList(2); - - PhAddItemList(connectionsToRemove, *networkItem); - } - } - - if (connectionsToRemove) - { - PhAcquireQueuedLockExclusive(&PhNetworkHashtableLock); - - for (i = 0; i < connectionsToRemove->Count; i++) - { - PhpRemoveNetworkItem(connectionsToRemove->Items[i]); - } - - PhReleaseQueuedLockExclusive(&PhNetworkHashtableLock); - PhDereferenceObject(connectionsToRemove); - } - } - - // Go through the queued network item query data. - { - PSLIST_ENTRY entry; - PPH_NETWORK_ITEM_QUERY_DATA data; - - entry = RtlInterlockedFlushSList(&PhNetworkItemQueryListHead); - - while (entry) - { - data = CONTAINING_RECORD(entry, PH_NETWORK_ITEM_QUERY_DATA, ListEntry); - entry = entry->Next; - - if (data->Remote) - PhMoveReference(&data->NetworkItem->RemoteHostString, data->HostString); - else - PhMoveReference(&data->NetworkItem->LocalHostString, data->HostString); - - data->NetworkItem->JustResolved = TRUE; - - PhDereferenceObject(data->NetworkItem); - PhFree(data); - } - } - - for (i = 0; i < numberOfConnections; i++) - { - PPH_NETWORK_ITEM networkItem; - - // Try to find the connection in our hashtable. - networkItem = PhReferenceNetworkItem( - connections[i].ProtocolType, - &connections[i].LocalEndpoint, - &connections[i].RemoteEndpoint, - connections[i].ProcessId - ); - - if (!networkItem) - { - PPHP_RESOLVE_CACHE_ITEM cacheItem; - PPH_PROCESS_ITEM processItem; - - // Network item not found, create it. - - networkItem = PhCreateNetworkItem(); - - // Fill in basic information. - networkItem->ProtocolType = connections[i].ProtocolType; - networkItem->LocalEndpoint = connections[i].LocalEndpoint; - networkItem->RemoteEndpoint = connections[i].RemoteEndpoint; - networkItem->State = connections[i].State; - networkItem->ProcessId = connections[i].ProcessId; - networkItem->CreateTime = connections[i].CreateTime; - memcpy(networkItem->OwnerInfo, connections[i].OwnerInfo, sizeof(ULONGLONG) * PH_NETWORK_OWNER_INFO_SIZE); - - // Format various strings. - - if (networkItem->LocalEndpoint.Address.Type == PH_IPV4_NETWORK_TYPE) - RtlIpv4AddressToString(&networkItem->LocalEndpoint.Address.InAddr, networkItem->LocalAddressString); - else - RtlIpv6AddressToString(&networkItem->LocalEndpoint.Address.In6Addr, networkItem->LocalAddressString); - - PhPrintUInt32(networkItem->LocalPortString, networkItem->LocalEndpoint.Port); - - if ( - networkItem->RemoteEndpoint.Address.Type == PH_IPV4_NETWORK_TYPE && - networkItem->RemoteEndpoint.Address.Ipv4 != 0 - ) - { - RtlIpv4AddressToString(&networkItem->RemoteEndpoint.Address.InAddr, networkItem->RemoteAddressString); - } - else if ( - networkItem->RemoteEndpoint.Address.Type == PH_IPV6_NETWORK_TYPE && - !PhIsNullIpAddress(&networkItem->RemoteEndpoint.Address) - ) - { - RtlIpv6AddressToString(&networkItem->RemoteEndpoint.Address.In6Addr, networkItem->RemoteAddressString); - } - - if (networkItem->RemoteEndpoint.Address.Type != 0 && networkItem->RemoteEndpoint.Port != 0) - PhPrintUInt32(networkItem->RemotePortString, networkItem->RemoteEndpoint.Port); - - // Get host names. - - // Local - { - PhAcquireQueuedLockShared(&PhpResolveCacheHashtableLock); - cacheItem = PhpLookupResolveCacheItem(&networkItem->LocalEndpoint.Address); - PhReleaseQueuedLockShared(&PhpResolveCacheHashtableLock); - - if (cacheItem) - { - PhReferenceObject(cacheItem->HostString); - networkItem->LocalHostString = cacheItem->HostString; - } - else - { - PhpQueueNetworkItemQuery(networkItem, FALSE); - } - } - - // Remote - if (!PhIsNullIpAddress(&networkItem->RemoteEndpoint.Address)) - { - PhAcquireQueuedLockShared(&PhpResolveCacheHashtableLock); - cacheItem = PhpLookupResolveCacheItem(&networkItem->RemoteEndpoint.Address); - PhReleaseQueuedLockShared(&PhpResolveCacheHashtableLock); - - if (cacheItem) - { - PhReferenceObject(cacheItem->HostString); - networkItem->RemoteHostString = cacheItem->HostString; - } - else - { - PhpQueueNetworkItemQuery(networkItem, TRUE); - } - } - - // Get process information. - if (processItem = PhReferenceProcessItem(networkItem->ProcessId)) - { - networkItem->ProcessName = processItem->ProcessName; - PhReferenceObject(processItem->ProcessName); - PhpUpdateNetworkItemOwner(networkItem, processItem); - - if (PhTestEvent(&processItem->Stage1Event)) - { - networkItem->ProcessIcon = processItem->SmallIcon; - networkItem->ProcessIconValid = TRUE; - } - - PhDereferenceObject(processItem); - } - - // Add the network item to the hashtable. - PhAcquireQueuedLockExclusive(&PhNetworkHashtableLock); - PhAddEntryHashtable(PhNetworkHashtable, &networkItem); - PhReleaseQueuedLockExclusive(&PhNetworkHashtableLock); - - // Raise the network item added event. - PhInvokeCallback(&PhNetworkItemAddedEvent, networkItem); - } - else - { - BOOLEAN modified = FALSE; - PPH_PROCESS_ITEM processItem; - - if (networkItem->JustResolved) - modified = TRUE; - - if (networkItem->State != connections[i].State) - { - networkItem->State = connections[i].State; - modified = TRUE; - } - - if (!networkItem->ProcessName || !networkItem->ProcessIconValid) - { - if (processItem = PhReferenceProcessItem(networkItem->ProcessId)) - { - if (!networkItem->ProcessName) - { - networkItem->ProcessName = processItem->ProcessName; - PhReferenceObject(processItem->ProcessName); - PhpUpdateNetworkItemOwner(networkItem, processItem); - modified = TRUE; - } - - if (!networkItem->ProcessIconValid && PhTestEvent(&processItem->Stage1Event)) - { - networkItem->ProcessIcon = processItem->SmallIcon; - networkItem->ProcessIconValid = TRUE; - modified = TRUE; - } - - PhDereferenceObject(processItem); - } - } - - networkItem->JustResolved = FALSE; - - if (modified) - { - // Raise the network item modified event. - PhInvokeCallback(&PhNetworkItemModifiedEvent, networkItem); - } - - PhDereferenceObject(networkItem); - } - } - - PhFree(connections); - - PhInvokeCallback(&PhNetworkItemsUpdatedEvent, NULL); -} - -PWSTR PhGetProtocolTypeName( - _In_ ULONG ProtocolType - ) -{ - switch (ProtocolType) - { - case PH_TCP4_NETWORK_PROTOCOL: - return L"TCP"; - case PH_TCP6_NETWORK_PROTOCOL: - return L"TCP6"; - case PH_UDP4_NETWORK_PROTOCOL: - return L"UDP"; - case PH_UDP6_NETWORK_PROTOCOL: - return L"UDP6"; - default: - return L"Unknown"; - } -} - -PWSTR PhGetTcpStateName( - _In_ ULONG State - ) -{ - switch (State) - { - case MIB_TCP_STATE_CLOSED: - return L"Closed"; - case MIB_TCP_STATE_LISTEN: - return L"Listen"; - case MIB_TCP_STATE_SYN_SENT: - return L"SYN sent"; - case MIB_TCP_STATE_SYN_RCVD: - return L"SYN received"; - case MIB_TCP_STATE_ESTAB: - return L"Established"; - case MIB_TCP_STATE_FIN_WAIT1: - return L"FIN wait 1"; - case MIB_TCP_STATE_FIN_WAIT2: - return L"FIN wait 2"; - case MIB_TCP_STATE_CLOSE_WAIT: - return L"Close wait"; - case MIB_TCP_STATE_CLOSING: - return L"Closing"; - case MIB_TCP_STATE_LAST_ACK: - return L"Last ACK"; - case MIB_TCP_STATE_TIME_WAIT: - return L"Time wait"; - case MIB_TCP_STATE_DELETE_TCB: - return L"Delete TCB"; - default: - return L"Unknown"; - } -} - -BOOLEAN PhGetNetworkConnections( - _Out_ PPH_NETWORK_CONNECTION *Connections, - _Out_ PULONG NumberOfConnections - ) -{ - PVOID table; - DWORD tableSize; - PMIB_TCPTABLE_OWNER_MODULE tcp4Table; - PMIB_UDPTABLE_OWNER_MODULE udp4Table; - PMIB_TCP6TABLE_OWNER_MODULE tcp6Table; - PMIB_UDP6TABLE_OWNER_MODULE udp6Table; - ULONG count = 0; - ULONG i; - ULONG index = 0; - PPH_NETWORK_CONNECTION connections; - - // TCP IPv4 - - tableSize = 0; - GetExtendedTcpTable(NULL, &tableSize, FALSE, AF_INET, TCP_TABLE_OWNER_MODULE_ALL, 0); - table = PhAllocate(tableSize); - - if (GetExtendedTcpTable(table, &tableSize, FALSE, AF_INET, TCP_TABLE_OWNER_MODULE_ALL, 0) == 0) - { - tcp4Table = table; - count += tcp4Table->dwNumEntries; - } - else - { - PhFree(table); - tcp4Table = NULL; - } - - // TCP IPv6 - - tableSize = 0; - GetExtendedTcpTable(NULL, &tableSize, FALSE, AF_INET6, TCP_TABLE_OWNER_MODULE_ALL, 0); - - // Note: On Windows XP, GetExtendedTcpTable had a bug where it calculated the required buffer size - // for IPv6 TCP_TABLE_OWNER_MODULE_ALL requests incorrectly, causing it to return the wrong size - // and overrun the provided buffer instead of returning an error. The size should be: - // = FIELD_OFFSET(MIB_TCP6TABLE_OWNER_MODULE, table) + sizeof(MIB_TCP6ROW_OWNER_MODULE) * (number of entries) - // However, the function calculated it as: - // = FIELD_OFFSET(MIB_TCP6TABLE_OWNER_MODULE, table) + sizeof(MIB_TCP6ROW_OWNER_PID) * (number of entries) - // A workaround is implemented below. - if (WindowsVersion <= WINDOWS_XP && tableSize >= (ULONG)FIELD_OFFSET(MIB_TCP6TABLE_OWNER_MODULE, table)) // make sure we don't wrap around - { - tableSize = FIELD_OFFSET(MIB_TCP6TABLE_OWNER_MODULE, table) + - (tableSize - FIELD_OFFSET(MIB_TCP6TABLE_OWNER_MODULE, table)) / sizeof(MIB_TCP6ROW_OWNER_PID) * sizeof(MIB_TCP6ROW_OWNER_MODULE); - } - - table = PhAllocate(tableSize); - - if (GetExtendedTcpTable(table, &tableSize, FALSE, AF_INET6, TCP_TABLE_OWNER_MODULE_ALL, 0) == 0) - { - tcp6Table = table; - count += tcp6Table->dwNumEntries; - } - else - { - PhFree(table); - tcp6Table = NULL; - } - - // UDP IPv4 - - tableSize = 0; - GetExtendedUdpTable(NULL, &tableSize, FALSE, AF_INET, UDP_TABLE_OWNER_MODULE, 0); - table = PhAllocate(tableSize); - - if (GetExtendedUdpTable(table, &tableSize, FALSE, AF_INET, UDP_TABLE_OWNER_MODULE, 0) == 0) - { - udp4Table = table; - count += udp4Table->dwNumEntries; - } - else - { - PhFree(table); - udp4Table = NULL; - } - - // UDP IPv6 - - tableSize = 0; - GetExtendedUdpTable(NULL, &tableSize, FALSE, AF_INET6, UDP_TABLE_OWNER_MODULE, 0); - table = PhAllocate(tableSize); - - if (GetExtendedUdpTable(table, &tableSize, FALSE, AF_INET6, UDP_TABLE_OWNER_MODULE, 0) == 0) - { - udp6Table = table; - count += udp6Table->dwNumEntries; - } - else - { - PhFree(table); - udp6Table = NULL; - } - - connections = PhAllocate(sizeof(PH_NETWORK_CONNECTION) * count); - memset(connections, 0, sizeof(PH_NETWORK_CONNECTION) * count); - - if (tcp4Table) - { - for (i = 0; i < tcp4Table->dwNumEntries; i++) - { - connections[index].ProtocolType = PH_TCP4_NETWORK_PROTOCOL; - - connections[index].LocalEndpoint.Address.Type = PH_IPV4_NETWORK_TYPE; - connections[index].LocalEndpoint.Address.Ipv4 = tcp4Table->table[i].dwLocalAddr; - connections[index].LocalEndpoint.Port = _byteswap_ushort((USHORT)tcp4Table->table[i].dwLocalPort); - - connections[index].RemoteEndpoint.Address.Type = PH_IPV4_NETWORK_TYPE; - connections[index].RemoteEndpoint.Address.Ipv4 = tcp4Table->table[i].dwRemoteAddr; - connections[index].RemoteEndpoint.Port = _byteswap_ushort((USHORT)tcp4Table->table[i].dwRemotePort); - - connections[index].State = tcp4Table->table[i].dwState; - connections[index].ProcessId = UlongToHandle(tcp4Table->table[i].dwOwningPid); - connections[index].CreateTime = tcp4Table->table[i].liCreateTimestamp; - memcpy( - connections[index].OwnerInfo, - tcp4Table->table[i].OwningModuleInfo, - sizeof(ULONGLONG) * min(PH_NETWORK_OWNER_INFO_SIZE, TCPIP_OWNING_MODULE_SIZE) - ); - - index++; - } - - PhFree(tcp4Table); - } - - if (tcp6Table) - { - for (i = 0; i < tcp6Table->dwNumEntries; i++) - { - connections[index].ProtocolType = PH_TCP6_NETWORK_PROTOCOL; - - connections[index].LocalEndpoint.Address.Type = PH_IPV6_NETWORK_TYPE; - memcpy(connections[index].LocalEndpoint.Address.Ipv6, tcp6Table->table[i].ucLocalAddr, 16); - connections[index].LocalEndpoint.Port = _byteswap_ushort((USHORT)tcp6Table->table[i].dwLocalPort); - - connections[index].RemoteEndpoint.Address.Type = PH_IPV6_NETWORK_TYPE; - memcpy(connections[index].RemoteEndpoint.Address.Ipv6, tcp6Table->table[i].ucRemoteAddr, 16); - connections[index].RemoteEndpoint.Port = _byteswap_ushort((USHORT)tcp6Table->table[i].dwRemotePort); - - connections[index].State = tcp6Table->table[i].dwState; - connections[index].ProcessId = UlongToHandle(tcp6Table->table[i].dwOwningPid); - connections[index].CreateTime = tcp6Table->table[i].liCreateTimestamp; - memcpy( - connections[index].OwnerInfo, - tcp6Table->table[i].OwningModuleInfo, - sizeof(ULONGLONG) * min(PH_NETWORK_OWNER_INFO_SIZE, TCPIP_OWNING_MODULE_SIZE) - ); - - index++; - } - - PhFree(tcp6Table); - } - - if (udp4Table) - { - for (i = 0; i < udp4Table->dwNumEntries; i++) - { - connections[index].ProtocolType = PH_UDP4_NETWORK_PROTOCOL; - - connections[index].LocalEndpoint.Address.Type = PH_IPV4_NETWORK_TYPE; - connections[index].LocalEndpoint.Address.Ipv4 = udp4Table->table[i].dwLocalAddr; - connections[index].LocalEndpoint.Port = _byteswap_ushort((USHORT)udp4Table->table[i].dwLocalPort); - - connections[index].RemoteEndpoint.Address.Type = 0; - - connections[index].State = 0; - connections[index].ProcessId = UlongToHandle(udp4Table->table[i].dwOwningPid); - connections[index].CreateTime = udp4Table->table[i].liCreateTimestamp; - memcpy( - connections[index].OwnerInfo, - udp4Table->table[i].OwningModuleInfo, - sizeof(ULONGLONG) * min(PH_NETWORK_OWNER_INFO_SIZE, TCPIP_OWNING_MODULE_SIZE) - ); - - index++; - } - - PhFree(udp4Table); - } - - if (udp6Table) - { - for (i = 0; i < udp6Table->dwNumEntries; i++) - { - connections[index].ProtocolType = PH_UDP6_NETWORK_PROTOCOL; - - connections[index].LocalEndpoint.Address.Type = PH_IPV6_NETWORK_TYPE; - memcpy(connections[index].LocalEndpoint.Address.Ipv6, udp6Table->table[i].ucLocalAddr, 16); - connections[index].LocalEndpoint.Port = _byteswap_ushort((USHORT)udp6Table->table[i].dwLocalPort); - - connections[index].RemoteEndpoint.Address.Type = 0; - - connections[index].State = 0; - connections[index].ProcessId = UlongToHandle(udp6Table->table[i].dwOwningPid); - connections[index].CreateTime = udp6Table->table[i].liCreateTimestamp; - memcpy( - connections[index].OwnerInfo, - udp6Table->table[i].OwningModuleInfo, - sizeof(ULONGLONG) * min(PH_NETWORK_OWNER_INFO_SIZE, TCPIP_OWNING_MODULE_SIZE) - ); - - index++; - } - - PhFree(udp6Table); - } - - *NumberOfConnections = count; - *Connections = connections; - - return TRUE; -} +/* + * Process Hacker - + * network provider + * + * Copyright (C) 2010 wj32 + * Copyright (C) 2010 evilpie + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +typedef struct _PH_NETWORK_CONNECTION +{ + ULONG ProtocolType; + PH_IP_ENDPOINT LocalEndpoint; + PH_IP_ENDPOINT RemoteEndpoint; + ULONG State; + HANDLE ProcessId; + LARGE_INTEGER CreateTime; + ULONGLONG OwnerInfo[PH_NETWORK_OWNER_INFO_SIZE]; +} PH_NETWORK_CONNECTION, *PPH_NETWORK_CONNECTION; + +typedef struct _PH_NETWORK_ITEM_QUERY_DATA +{ + SLIST_ENTRY ListEntry; + PPH_NETWORK_ITEM NetworkItem; + + PH_IP_ADDRESS Address; + BOOLEAN Remote; + PPH_STRING HostString; +} PH_NETWORK_ITEM_QUERY_DATA, *PPH_NETWORK_ITEM_QUERY_DATA; + +typedef struct _PHP_RESOLVE_CACHE_ITEM +{ + PH_IP_ADDRESS Address; + PPH_STRING HostString; +} PHP_RESOLVE_CACHE_ITEM, *PPHP_RESOLVE_CACHE_ITEM; + +VOID NTAPI PhpNetworkItemDeleteProcedure( + _In_ PVOID Object, + _In_ ULONG Flags + ); + +BOOLEAN PhpNetworkHashtableEqualFunction( + _In_ PVOID Entry1, + _In_ PVOID Entry2 + ); + +ULONG NTAPI PhpNetworkHashtableHashFunction( + _In_ PVOID Entry + ); + +BOOLEAN PhpResolveCacheHashtableEqualFunction( + _In_ PVOID Entry1, + _In_ PVOID Entry2 + ); + +ULONG NTAPI PhpResolveCacheHashtableHashFunction( + _In_ PVOID Entry + ); + +BOOLEAN PhGetNetworkConnections( + _Out_ PPH_NETWORK_CONNECTION *Connections, + _Out_ PULONG NumberOfConnections + ); + +PPH_OBJECT_TYPE PhNetworkItemType; + +PPH_HASHTABLE PhNetworkHashtable; +PH_QUEUED_LOCK PhNetworkHashtableLock = PH_QUEUED_LOCK_INIT; + +PHAPPAPI PH_CALLBACK_DECLARE(PhNetworkItemAddedEvent); +PHAPPAPI PH_CALLBACK_DECLARE(PhNetworkItemModifiedEvent); +PHAPPAPI PH_CALLBACK_DECLARE(PhNetworkItemRemovedEvent); +PHAPPAPI PH_CALLBACK_DECLARE(PhNetworkItemsUpdatedEvent); + +PH_INITONCE PhNetworkProviderWorkQueueInitOnce = PH_INITONCE_INIT; +PH_WORK_QUEUE PhNetworkProviderWorkQueue; +SLIST_HEADER PhNetworkItemQueryListHead; + +BOOLEAN PhEnableNetworkProviderResolve = TRUE; +static BOOLEAN NetworkImportDone = FALSE; +static PPH_HASHTABLE PhpResolveCacheHashtable; +static PH_QUEUED_LOCK PhpResolveCacheHashtableLock = PH_QUEUED_LOCK_INIT; + +BOOLEAN PhNetworkProviderInitialization( + VOID + ) +{ + PhNetworkItemType = PhCreateObjectType(L"NetworkItem", 0, PhpNetworkItemDeleteProcedure); + PhNetworkHashtable = PhCreateHashtable( + sizeof(PPH_NETWORK_ITEM), + PhpNetworkHashtableEqualFunction, + PhpNetworkHashtableHashFunction, + 40 + ); + + RtlInitializeSListHead(&PhNetworkItemQueryListHead); + + PhpResolveCacheHashtable = PhCreateHashtable( + sizeof(PHP_RESOLVE_CACHE_ITEM), + PhpResolveCacheHashtableEqualFunction, + PhpResolveCacheHashtableHashFunction, + 20 + ); + + return TRUE; +} + +PPH_NETWORK_ITEM PhCreateNetworkItem( + VOID + ) +{ + PPH_NETWORK_ITEM networkItem; + + networkItem = PhCreateObject( + PhEmGetObjectSize(EmNetworkItemType, sizeof(PH_NETWORK_ITEM)), + PhNetworkItemType + ); + memset(networkItem, 0, sizeof(PH_NETWORK_ITEM)); + PhEmCallObjectOperation(EmNetworkItemType, networkItem, EmObjectCreate); + + return networkItem; +} + +VOID NTAPI PhpNetworkItemDeleteProcedure( + _In_ PVOID Object, + _In_ ULONG Flags + ) +{ + PPH_NETWORK_ITEM networkItem = (PPH_NETWORK_ITEM)Object; + + PhEmCallObjectOperation(EmNetworkItemType, networkItem, EmObjectDelete); + + if (networkItem->ProcessName) + PhDereferenceObject(networkItem->ProcessName); + if (networkItem->OwnerName) + PhDereferenceObject(networkItem->OwnerName); + if (networkItem->LocalHostString) + PhDereferenceObject(networkItem->LocalHostString); + if (networkItem->RemoteHostString) + PhDereferenceObject(networkItem->RemoteHostString); +} + +BOOLEAN PhpNetworkHashtableEqualFunction( + _In_ PVOID Entry1, + _In_ PVOID Entry2 + ) +{ + PPH_NETWORK_ITEM networkItem1 = *(PPH_NETWORK_ITEM *)Entry1; + PPH_NETWORK_ITEM networkItem2 = *(PPH_NETWORK_ITEM *)Entry2; + + return + networkItem1->ProtocolType == networkItem2->ProtocolType && + PhEqualIpEndpoint(&networkItem1->LocalEndpoint, &networkItem2->LocalEndpoint) && + PhEqualIpEndpoint(&networkItem1->RemoteEndpoint, &networkItem2->RemoteEndpoint) && + networkItem1->ProcessId == networkItem2->ProcessId; +} + +ULONG NTAPI PhpNetworkHashtableHashFunction( + _In_ PVOID Entry + ) +{ + PPH_NETWORK_ITEM networkItem = *(PPH_NETWORK_ITEM *)Entry; + + return + networkItem->ProtocolType ^ + PhHashIpEndpoint(&networkItem->LocalEndpoint) ^ + PhHashIpEndpoint(&networkItem->RemoteEndpoint) ^ + HandleToUlong(networkItem->ProcessId); +} + +PPH_NETWORK_ITEM PhReferenceNetworkItem( + _In_ ULONG ProtocolType, + _In_ PPH_IP_ENDPOINT LocalEndpoint, + _In_ PPH_IP_ENDPOINT RemoteEndpoint, + _In_ HANDLE ProcessId + ) +{ + PH_NETWORK_ITEM lookupNetworkItem; + PPH_NETWORK_ITEM lookupNetworkItemPtr = &lookupNetworkItem; + PPH_NETWORK_ITEM *networkItemPtr; + PPH_NETWORK_ITEM networkItem; + + lookupNetworkItem.ProtocolType = ProtocolType; + lookupNetworkItem.LocalEndpoint = *LocalEndpoint; + lookupNetworkItem.RemoteEndpoint = *RemoteEndpoint; + lookupNetworkItem.ProcessId = ProcessId; + + PhAcquireQueuedLockShared(&PhNetworkHashtableLock); + + networkItemPtr = (PPH_NETWORK_ITEM *)PhFindEntryHashtable( + PhNetworkHashtable, + &lookupNetworkItemPtr + ); + + if (networkItemPtr) + { + networkItem = *networkItemPtr; + PhReferenceObject(networkItem); + } + else + { + networkItem = NULL; + } + + PhReleaseQueuedLockShared(&PhNetworkHashtableLock); + + return networkItem; +} + +VOID PhpRemoveNetworkItem( + _In_ PPH_NETWORK_ITEM NetworkItem + ) +{ + PhRemoveEntryHashtable(PhNetworkHashtable, &NetworkItem); + PhDereferenceObject(NetworkItem); +} + +BOOLEAN PhpResolveCacheHashtableEqualFunction( + _In_ PVOID Entry1, + _In_ PVOID Entry2 + ) +{ + PPHP_RESOLVE_CACHE_ITEM cacheItem1 = *(PPHP_RESOLVE_CACHE_ITEM *)Entry1; + PPHP_RESOLVE_CACHE_ITEM cacheItem2 = *(PPHP_RESOLVE_CACHE_ITEM *)Entry2; + + return PhEqualIpAddress(&cacheItem1->Address, &cacheItem2->Address); +} + +ULONG NTAPI PhpResolveCacheHashtableHashFunction( + _In_ PVOID Entry + ) +{ + PPHP_RESOLVE_CACHE_ITEM cacheItem = *(PPHP_RESOLVE_CACHE_ITEM *)Entry; + + return PhHashIpAddress(&cacheItem->Address); +} + +PPHP_RESOLVE_CACHE_ITEM PhpLookupResolveCacheItem( + _In_ PPH_IP_ADDRESS Address + ) +{ + PHP_RESOLVE_CACHE_ITEM lookupCacheItem; + PPHP_RESOLVE_CACHE_ITEM lookupCacheItemPtr = &lookupCacheItem; + PPHP_RESOLVE_CACHE_ITEM *cacheItemPtr; + + // Construct a temporary cache item for the lookup. + lookupCacheItem.Address = *Address; + + cacheItemPtr = (PPHP_RESOLVE_CACHE_ITEM *)PhFindEntryHashtable( + PhpResolveCacheHashtable, + &lookupCacheItemPtr + ); + + if (cacheItemPtr) + return *cacheItemPtr; + else + return NULL; +} + +PPH_STRING PhGetHostNameFromAddress( + _In_ PPH_IP_ADDRESS Address + ) +{ + struct sockaddr_in ipv4Address; + struct sockaddr_in6 ipv6Address; + struct sockaddr *address; + socklen_t length; + PPH_STRING hostName; + + if (Address->Type == PH_IPV4_NETWORK_TYPE) + { + ipv4Address.sin_family = AF_INET; + ipv4Address.sin_port = 0; + ipv4Address.sin_addr = Address->InAddr; + address = (struct sockaddr *)&ipv4Address; + length = sizeof(ipv4Address); + } + else if (Address->Type == PH_IPV6_NETWORK_TYPE) + { + ipv6Address.sin6_family = AF_INET6; + ipv6Address.sin6_port = 0; + ipv6Address.sin6_flowinfo = 0; + ipv6Address.sin6_addr = Address->In6Addr; + ipv6Address.sin6_scope_id = 0; + address = (struct sockaddr *)&ipv6Address; + length = sizeof(ipv6Address); + } + else + { + return NULL; + } + + hostName = PhCreateStringEx(NULL, 128); + + if (GetNameInfoW( + address, + length, + hostName->Buffer, + (ULONG)hostName->Length / 2 + 1, + NULL, + 0, + NI_NAMEREQD + ) != 0) + { + // Try with the maximum host name size. + PhDereferenceObject(hostName); + hostName = PhCreateStringEx(NULL, NI_MAXHOST * 2); + + if (GetNameInfoW( + address, + length, + hostName->Buffer, + (ULONG)hostName->Length / 2 + 1, + NULL, + 0, + NI_NAMEREQD + ) != 0) + { + PhDereferenceObject(hostName); + + return NULL; + } + } + + PhTrimToNullTerminatorString(hostName); + + return hostName; +} + +NTSTATUS PhpNetworkItemQueryWorker( + _In_ PVOID Parameter + ) +{ + PPH_NETWORK_ITEM_QUERY_DATA data = (PPH_NETWORK_ITEM_QUERY_DATA)Parameter; + PPH_STRING hostString; + PPHP_RESOLVE_CACHE_ITEM cacheItem; + + // Last minute check of the cache. + + PhAcquireQueuedLockShared(&PhpResolveCacheHashtableLock); + cacheItem = PhpLookupResolveCacheItem(&data->Address); + PhReleaseQueuedLockShared(&PhpResolveCacheHashtableLock); + + if (!cacheItem) + { + hostString = PhGetHostNameFromAddress(&data->Address); + + if (hostString) + { + data->HostString = hostString; + + // Update the cache. + + PhAcquireQueuedLockExclusive(&PhpResolveCacheHashtableLock); + + cacheItem = PhpLookupResolveCacheItem(&data->Address); + + if (!cacheItem) + { + cacheItem = PhAllocate(sizeof(PHP_RESOLVE_CACHE_ITEM)); + cacheItem->Address = data->Address; + cacheItem->HostString = hostString; + PhReferenceObject(hostString); + + PhAddEntryHashtable(PhpResolveCacheHashtable, &cacheItem); + } + + PhReleaseQueuedLockExclusive(&PhpResolveCacheHashtableLock); + } + } + else + { + PhReferenceObject(cacheItem->HostString); + data->HostString = cacheItem->HostString; + } + + RtlInterlockedPushEntrySList(&PhNetworkItemQueryListHead, &data->ListEntry); + + return STATUS_SUCCESS; +} + +VOID PhpQueueNetworkItemQuery( + _In_ PPH_NETWORK_ITEM NetworkItem, + _In_ BOOLEAN Remote + ) +{ + PPH_NETWORK_ITEM_QUERY_DATA data; + + if (!PhEnableNetworkProviderResolve) + return; + + data = PhAllocate(sizeof(PH_NETWORK_ITEM_QUERY_DATA)); + memset(data, 0, sizeof(PH_NETWORK_ITEM_QUERY_DATA)); + data->NetworkItem = NetworkItem; + data->Remote = Remote; + + if (Remote) + data->Address = NetworkItem->RemoteEndpoint.Address; + else + data->Address = NetworkItem->LocalEndpoint.Address; + + PhReferenceObject(NetworkItem); + + if (PhBeginInitOnce(&PhNetworkProviderWorkQueueInitOnce)) + { + PhInitializeWorkQueue(&PhNetworkProviderWorkQueue, 0, 3, 500); + PhEndInitOnce(&PhNetworkProviderWorkQueueInitOnce); + } + + PhQueueItemWorkQueue(&PhNetworkProviderWorkQueue, PhpNetworkItemQueryWorker, data); +} + +VOID PhpUpdateNetworkItemOwner( + _In_ PPH_NETWORK_ITEM NetworkItem, + _In_ PPH_PROCESS_ITEM ProcessItem + ) +{ + if (*(PULONG64)NetworkItem->OwnerInfo) + { + PVOID serviceTag; + PPH_STRING serviceName; + + // May change in the future... + serviceTag = UlongToPtr(*(PULONG)NetworkItem->OwnerInfo); + serviceName = PhGetServiceNameFromTag(NetworkItem->ProcessId, serviceTag); + + if (serviceName) + PhMoveReference(&NetworkItem->OwnerName, serviceName); + } +} + +VOID PhNetworkProviderUpdate( + _In_ PVOID Object + ) +{ + PPH_NETWORK_CONNECTION connections; + ULONG numberOfConnections; + ULONG i; + + if (!NetworkImportDone) + { + WSADATA wsaData; + + // Make sure WSA is initialized. + WSAStartup(WINSOCK_VERSION, &wsaData); + NetworkImportDone = TRUE; + } + + if (!PhGetNetworkConnections(&connections, &numberOfConnections)) + return; + + { + PPH_LIST connectionsToRemove = NULL; + PH_HASHTABLE_ENUM_CONTEXT enumContext; + PPH_NETWORK_ITEM *networkItem; + + PhBeginEnumHashtable(PhNetworkHashtable, &enumContext); + + while (networkItem = PhNextEnumHashtable(&enumContext)) + { + BOOLEAN found = FALSE; + + for (i = 0; i < numberOfConnections; i++) + { + if ( + (*networkItem)->ProtocolType == connections[i].ProtocolType && + PhEqualIpEndpoint(&(*networkItem)->LocalEndpoint, &connections[i].LocalEndpoint) && + PhEqualIpEndpoint(&(*networkItem)->RemoteEndpoint, &connections[i].RemoteEndpoint) && + (*networkItem)->ProcessId == connections[i].ProcessId + ) + { + found = TRUE; + break; + } + } + + if (!found) + { + PhInvokeCallback(&PhNetworkItemRemovedEvent, *networkItem); + + if (!connectionsToRemove) + connectionsToRemove = PhCreateList(2); + + PhAddItemList(connectionsToRemove, *networkItem); + } + } + + if (connectionsToRemove) + { + PhAcquireQueuedLockExclusive(&PhNetworkHashtableLock); + + for (i = 0; i < connectionsToRemove->Count; i++) + { + PhpRemoveNetworkItem(connectionsToRemove->Items[i]); + } + + PhReleaseQueuedLockExclusive(&PhNetworkHashtableLock); + PhDereferenceObject(connectionsToRemove); + } + } + + // Go through the queued network item query data. + { + PSLIST_ENTRY entry; + PPH_NETWORK_ITEM_QUERY_DATA data; + + entry = RtlInterlockedFlushSList(&PhNetworkItemQueryListHead); + + while (entry) + { + data = CONTAINING_RECORD(entry, PH_NETWORK_ITEM_QUERY_DATA, ListEntry); + entry = entry->Next; + + if (data->Remote) + PhMoveReference(&data->NetworkItem->RemoteHostString, data->HostString); + else + PhMoveReference(&data->NetworkItem->LocalHostString, data->HostString); + + data->NetworkItem->JustResolved = TRUE; + + PhDereferenceObject(data->NetworkItem); + PhFree(data); + } + } + + for (i = 0; i < numberOfConnections; i++) + { + PPH_NETWORK_ITEM networkItem; + + // Try to find the connection in our hashtable. + networkItem = PhReferenceNetworkItem( + connections[i].ProtocolType, + &connections[i].LocalEndpoint, + &connections[i].RemoteEndpoint, + connections[i].ProcessId + ); + + if (!networkItem) + { + PPHP_RESOLVE_CACHE_ITEM cacheItem; + PPH_PROCESS_ITEM processItem; + + // Network item not found, create it. + + networkItem = PhCreateNetworkItem(); + + // Fill in basic information. + networkItem->ProtocolType = connections[i].ProtocolType; + networkItem->LocalEndpoint = connections[i].LocalEndpoint; + networkItem->RemoteEndpoint = connections[i].RemoteEndpoint; + networkItem->State = connections[i].State; + networkItem->ProcessId = connections[i].ProcessId; + networkItem->CreateTime = connections[i].CreateTime; + memcpy(networkItem->OwnerInfo, connections[i].OwnerInfo, sizeof(ULONGLONG) * PH_NETWORK_OWNER_INFO_SIZE); + + // Format various strings. + + if (networkItem->LocalEndpoint.Address.Type == PH_IPV4_NETWORK_TYPE) + RtlIpv4AddressToString(&networkItem->LocalEndpoint.Address.InAddr, networkItem->LocalAddressString); + else + RtlIpv6AddressToString(&networkItem->LocalEndpoint.Address.In6Addr, networkItem->LocalAddressString); + + PhPrintUInt32(networkItem->LocalPortString, networkItem->LocalEndpoint.Port); + + if ( + networkItem->RemoteEndpoint.Address.Type == PH_IPV4_NETWORK_TYPE && + networkItem->RemoteEndpoint.Address.Ipv4 != 0 + ) + { + RtlIpv4AddressToString(&networkItem->RemoteEndpoint.Address.InAddr, networkItem->RemoteAddressString); + } + else if ( + networkItem->RemoteEndpoint.Address.Type == PH_IPV6_NETWORK_TYPE && + !PhIsNullIpAddress(&networkItem->RemoteEndpoint.Address) + ) + { + RtlIpv6AddressToString(&networkItem->RemoteEndpoint.Address.In6Addr, networkItem->RemoteAddressString); + } + + if (networkItem->RemoteEndpoint.Address.Type != 0 && networkItem->RemoteEndpoint.Port != 0) + PhPrintUInt32(networkItem->RemotePortString, networkItem->RemoteEndpoint.Port); + + // Get host names. + + // Local + { + PhAcquireQueuedLockShared(&PhpResolveCacheHashtableLock); + cacheItem = PhpLookupResolveCacheItem(&networkItem->LocalEndpoint.Address); + PhReleaseQueuedLockShared(&PhpResolveCacheHashtableLock); + + if (cacheItem) + { + PhReferenceObject(cacheItem->HostString); + networkItem->LocalHostString = cacheItem->HostString; + } + else + { + PhpQueueNetworkItemQuery(networkItem, FALSE); + } + } + + // Remote + if (!PhIsNullIpAddress(&networkItem->RemoteEndpoint.Address)) + { + PhAcquireQueuedLockShared(&PhpResolveCacheHashtableLock); + cacheItem = PhpLookupResolveCacheItem(&networkItem->RemoteEndpoint.Address); + PhReleaseQueuedLockShared(&PhpResolveCacheHashtableLock); + + if (cacheItem) + { + PhReferenceObject(cacheItem->HostString); + networkItem->RemoteHostString = cacheItem->HostString; + } + else + { + PhpQueueNetworkItemQuery(networkItem, TRUE); + } + } + + // Get process information. + if (processItem = PhReferenceProcessItem(networkItem->ProcessId)) + { + networkItem->ProcessName = processItem->ProcessName; + PhReferenceObject(processItem->ProcessName); + PhpUpdateNetworkItemOwner(networkItem, processItem); + + if (PhTestEvent(&processItem->Stage1Event)) + { + networkItem->ProcessIcon = processItem->SmallIcon; + networkItem->ProcessIconValid = TRUE; + } + + PhDereferenceObject(processItem); + } + + // Add the network item to the hashtable. + PhAcquireQueuedLockExclusive(&PhNetworkHashtableLock); + PhAddEntryHashtable(PhNetworkHashtable, &networkItem); + PhReleaseQueuedLockExclusive(&PhNetworkHashtableLock); + + // Raise the network item added event. + PhInvokeCallback(&PhNetworkItemAddedEvent, networkItem); + } + else + { + BOOLEAN modified = FALSE; + PPH_PROCESS_ITEM processItem; + + if (networkItem->JustResolved) + modified = TRUE; + + if (networkItem->State != connections[i].State) + { + networkItem->State = connections[i].State; + modified = TRUE; + } + + if (!networkItem->ProcessName || !networkItem->ProcessIconValid) + { + if (processItem = PhReferenceProcessItem(networkItem->ProcessId)) + { + if (!networkItem->ProcessName) + { + networkItem->ProcessName = processItem->ProcessName; + PhReferenceObject(processItem->ProcessName); + PhpUpdateNetworkItemOwner(networkItem, processItem); + modified = TRUE; + } + + if (!networkItem->ProcessIconValid && PhTestEvent(&processItem->Stage1Event)) + { + networkItem->ProcessIcon = processItem->SmallIcon; + networkItem->ProcessIconValid = TRUE; + modified = TRUE; + } + + PhDereferenceObject(processItem); + } + } + + networkItem->JustResolved = FALSE; + + if (modified) + { + // Raise the network item modified event. + PhInvokeCallback(&PhNetworkItemModifiedEvent, networkItem); + } + + PhDereferenceObject(networkItem); + } + } + + PhFree(connections); + + PhInvokeCallback(&PhNetworkItemsUpdatedEvent, NULL); +} + +PWSTR PhGetProtocolTypeName( + _In_ ULONG ProtocolType + ) +{ + switch (ProtocolType) + { + case PH_TCP4_NETWORK_PROTOCOL: + return L"TCP"; + case PH_TCP6_NETWORK_PROTOCOL: + return L"TCP6"; + case PH_UDP4_NETWORK_PROTOCOL: + return L"UDP"; + case PH_UDP6_NETWORK_PROTOCOL: + return L"UDP6"; + default: + return L"Unknown"; + } +} + +PWSTR PhGetTcpStateName( + _In_ ULONG State + ) +{ + switch (State) + { + case MIB_TCP_STATE_CLOSED: + return L"Closed"; + case MIB_TCP_STATE_LISTEN: + return L"Listen"; + case MIB_TCP_STATE_SYN_SENT: + return L"SYN sent"; + case MIB_TCP_STATE_SYN_RCVD: + return L"SYN received"; + case MIB_TCP_STATE_ESTAB: + return L"Established"; + case MIB_TCP_STATE_FIN_WAIT1: + return L"FIN wait 1"; + case MIB_TCP_STATE_FIN_WAIT2: + return L"FIN wait 2"; + case MIB_TCP_STATE_CLOSE_WAIT: + return L"Close wait"; + case MIB_TCP_STATE_CLOSING: + return L"Closing"; + case MIB_TCP_STATE_LAST_ACK: + return L"Last ACK"; + case MIB_TCP_STATE_TIME_WAIT: + return L"Time wait"; + case MIB_TCP_STATE_DELETE_TCB: + return L"Delete TCB"; + default: + return L"Unknown"; + } +} + +BOOLEAN PhGetNetworkConnections( + _Out_ PPH_NETWORK_CONNECTION *Connections, + _Out_ PULONG NumberOfConnections + ) +{ + PVOID table; + DWORD tableSize; + PMIB_TCPTABLE_OWNER_MODULE tcp4Table; + PMIB_UDPTABLE_OWNER_MODULE udp4Table; + PMIB_TCP6TABLE_OWNER_MODULE tcp6Table; + PMIB_UDP6TABLE_OWNER_MODULE udp6Table; + ULONG count = 0; + ULONG i; + ULONG index = 0; + PPH_NETWORK_CONNECTION connections; + + // TCP IPv4 + + tableSize = 0; + GetExtendedTcpTable(NULL, &tableSize, FALSE, AF_INET, TCP_TABLE_OWNER_MODULE_ALL, 0); + table = PhAllocate(tableSize); + + if (GetExtendedTcpTable(table, &tableSize, FALSE, AF_INET, TCP_TABLE_OWNER_MODULE_ALL, 0) == 0) + { + tcp4Table = table; + count += tcp4Table->dwNumEntries; + } + else + { + PhFree(table); + tcp4Table = NULL; + } + + // TCP IPv6 + + tableSize = 0; + GetExtendedTcpTable(NULL, &tableSize, FALSE, AF_INET6, TCP_TABLE_OWNER_MODULE_ALL, 0); + + // Note: On Windows XP, GetExtendedTcpTable had a bug where it calculated the required buffer size + // for IPv6 TCP_TABLE_OWNER_MODULE_ALL requests incorrectly, causing it to return the wrong size + // and overrun the provided buffer instead of returning an error. The size should be: + // = FIELD_OFFSET(MIB_TCP6TABLE_OWNER_MODULE, table) + sizeof(MIB_TCP6ROW_OWNER_MODULE) * (number of entries) + // However, the function calculated it as: + // = FIELD_OFFSET(MIB_TCP6TABLE_OWNER_MODULE, table) + sizeof(MIB_TCP6ROW_OWNER_PID) * (number of entries) + // A workaround is implemented below. + if (WindowsVersion <= WINDOWS_XP && tableSize >= (ULONG)FIELD_OFFSET(MIB_TCP6TABLE_OWNER_MODULE, table)) // make sure we don't wrap around + { + tableSize = FIELD_OFFSET(MIB_TCP6TABLE_OWNER_MODULE, table) + + (tableSize - FIELD_OFFSET(MIB_TCP6TABLE_OWNER_MODULE, table)) / sizeof(MIB_TCP6ROW_OWNER_PID) * sizeof(MIB_TCP6ROW_OWNER_MODULE); + } + + table = PhAllocate(tableSize); + + if (GetExtendedTcpTable(table, &tableSize, FALSE, AF_INET6, TCP_TABLE_OWNER_MODULE_ALL, 0) == 0) + { + tcp6Table = table; + count += tcp6Table->dwNumEntries; + } + else + { + PhFree(table); + tcp6Table = NULL; + } + + // UDP IPv4 + + tableSize = 0; + GetExtendedUdpTable(NULL, &tableSize, FALSE, AF_INET, UDP_TABLE_OWNER_MODULE, 0); + table = PhAllocate(tableSize); + + if (GetExtendedUdpTable(table, &tableSize, FALSE, AF_INET, UDP_TABLE_OWNER_MODULE, 0) == 0) + { + udp4Table = table; + count += udp4Table->dwNumEntries; + } + else + { + PhFree(table); + udp4Table = NULL; + } + + // UDP IPv6 + + tableSize = 0; + GetExtendedUdpTable(NULL, &tableSize, FALSE, AF_INET6, UDP_TABLE_OWNER_MODULE, 0); + table = PhAllocate(tableSize); + + if (GetExtendedUdpTable(table, &tableSize, FALSE, AF_INET6, UDP_TABLE_OWNER_MODULE, 0) == 0) + { + udp6Table = table; + count += udp6Table->dwNumEntries; + } + else + { + PhFree(table); + udp6Table = NULL; + } + + connections = PhAllocate(sizeof(PH_NETWORK_CONNECTION) * count); + memset(connections, 0, sizeof(PH_NETWORK_CONNECTION) * count); + + if (tcp4Table) + { + for (i = 0; i < tcp4Table->dwNumEntries; i++) + { + connections[index].ProtocolType = PH_TCP4_NETWORK_PROTOCOL; + + connections[index].LocalEndpoint.Address.Type = PH_IPV4_NETWORK_TYPE; + connections[index].LocalEndpoint.Address.Ipv4 = tcp4Table->table[i].dwLocalAddr; + connections[index].LocalEndpoint.Port = _byteswap_ushort((USHORT)tcp4Table->table[i].dwLocalPort); + + connections[index].RemoteEndpoint.Address.Type = PH_IPV4_NETWORK_TYPE; + connections[index].RemoteEndpoint.Address.Ipv4 = tcp4Table->table[i].dwRemoteAddr; + connections[index].RemoteEndpoint.Port = _byteswap_ushort((USHORT)tcp4Table->table[i].dwRemotePort); + + connections[index].State = tcp4Table->table[i].dwState; + connections[index].ProcessId = UlongToHandle(tcp4Table->table[i].dwOwningPid); + connections[index].CreateTime = tcp4Table->table[i].liCreateTimestamp; + memcpy( + connections[index].OwnerInfo, + tcp4Table->table[i].OwningModuleInfo, + sizeof(ULONGLONG) * min(PH_NETWORK_OWNER_INFO_SIZE, TCPIP_OWNING_MODULE_SIZE) + ); + + index++; + } + + PhFree(tcp4Table); + } + + if (tcp6Table) + { + for (i = 0; i < tcp6Table->dwNumEntries; i++) + { + connections[index].ProtocolType = PH_TCP6_NETWORK_PROTOCOL; + + connections[index].LocalEndpoint.Address.Type = PH_IPV6_NETWORK_TYPE; + memcpy(connections[index].LocalEndpoint.Address.Ipv6, tcp6Table->table[i].ucLocalAddr, 16); + connections[index].LocalEndpoint.Port = _byteswap_ushort((USHORT)tcp6Table->table[i].dwLocalPort); + + connections[index].RemoteEndpoint.Address.Type = PH_IPV6_NETWORK_TYPE; + memcpy(connections[index].RemoteEndpoint.Address.Ipv6, tcp6Table->table[i].ucRemoteAddr, 16); + connections[index].RemoteEndpoint.Port = _byteswap_ushort((USHORT)tcp6Table->table[i].dwRemotePort); + + connections[index].State = tcp6Table->table[i].dwState; + connections[index].ProcessId = UlongToHandle(tcp6Table->table[i].dwOwningPid); + connections[index].CreateTime = tcp6Table->table[i].liCreateTimestamp; + memcpy( + connections[index].OwnerInfo, + tcp6Table->table[i].OwningModuleInfo, + sizeof(ULONGLONG) * min(PH_NETWORK_OWNER_INFO_SIZE, TCPIP_OWNING_MODULE_SIZE) + ); + + index++; + } + + PhFree(tcp6Table); + } + + if (udp4Table) + { + for (i = 0; i < udp4Table->dwNumEntries; i++) + { + connections[index].ProtocolType = PH_UDP4_NETWORK_PROTOCOL; + + connections[index].LocalEndpoint.Address.Type = PH_IPV4_NETWORK_TYPE; + connections[index].LocalEndpoint.Address.Ipv4 = udp4Table->table[i].dwLocalAddr; + connections[index].LocalEndpoint.Port = _byteswap_ushort((USHORT)udp4Table->table[i].dwLocalPort); + + connections[index].RemoteEndpoint.Address.Type = 0; + + connections[index].State = 0; + connections[index].ProcessId = UlongToHandle(udp4Table->table[i].dwOwningPid); + connections[index].CreateTime = udp4Table->table[i].liCreateTimestamp; + memcpy( + connections[index].OwnerInfo, + udp4Table->table[i].OwningModuleInfo, + sizeof(ULONGLONG) * min(PH_NETWORK_OWNER_INFO_SIZE, TCPIP_OWNING_MODULE_SIZE) + ); + + index++; + } + + PhFree(udp4Table); + } + + if (udp6Table) + { + for (i = 0; i < udp6Table->dwNumEntries; i++) + { + connections[index].ProtocolType = PH_UDP6_NETWORK_PROTOCOL; + + connections[index].LocalEndpoint.Address.Type = PH_IPV6_NETWORK_TYPE; + memcpy(connections[index].LocalEndpoint.Address.Ipv6, udp6Table->table[i].ucLocalAddr, 16); + connections[index].LocalEndpoint.Port = _byteswap_ushort((USHORT)udp6Table->table[i].dwLocalPort); + + connections[index].RemoteEndpoint.Address.Type = 0; + + connections[index].State = 0; + connections[index].ProcessId = UlongToHandle(udp6Table->table[i].dwOwningPid); + connections[index].CreateTime = udp6Table->table[i].liCreateTimestamp; + memcpy( + connections[index].OwnerInfo, + udp6Table->table[i].OwningModuleInfo, + sizeof(ULONGLONG) * min(PH_NETWORK_OWNER_INFO_SIZE, TCPIP_OWNING_MODULE_SIZE) + ); + + index++; + } + + PhFree(udp6Table); + } + + *NumberOfConnections = count; + *Connections = connections; + + return TRUE; +} diff --git a/ProcessHacker/netstk.c b/ProcessHacker/netstk.c index 2fda236e61d0..2e89b091a71a 100644 --- a/ProcessHacker/netstk.c +++ b/ProcessHacker/netstk.c @@ -1,240 +1,240 @@ -/* - * Process Hacker - - * network stack viewer - * - * Copyright (C) 2010 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include - -#include - -#include - -typedef struct NETWORK_STACK_CONTEXT -{ - HWND ListViewHandle; - PPH_NETWORK_ITEM NetworkItem; - PPH_SYMBOL_PROVIDER SymbolProvider; - HANDLE LoadingProcessId; -} NETWORK_STACK_CONTEXT, *PNETWORK_STACK_CONTEXT; - -INT_PTR CALLBACK PhpNetworkStackDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -static RECT MinimumSize = { -1, -1, -1, -1 }; - -static BOOLEAN LoadSymbolsEnumGenericModulesCallback( - _In_ PPH_MODULE_INFO Module, - _In_opt_ PVOID Context - ) -{ - PNETWORK_STACK_CONTEXT context = Context; - PPH_SYMBOL_PROVIDER symbolProvider = context->SymbolProvider; - - // If we're loading kernel module symbols for a process other than - // System, ignore modules which are in user space. This may happen - // in Windows 7. - if ( - context->LoadingProcessId == SYSTEM_PROCESS_ID && - context->NetworkItem->ProcessId != SYSTEM_PROCESS_ID && - (ULONG_PTR)Module->BaseAddress <= PhSystemBasicInformation.MaximumUserModeAddress - ) - return TRUE; - - PhLoadModuleSymbolProvider( - symbolProvider, - Module->FileName->Buffer, - (ULONG64)Module->BaseAddress, - Module->Size - ); - - return TRUE; -} - -VOID PhShowNetworkStackDialog( - _In_ HWND ParentWindowHandle, - _In_ PPH_NETWORK_ITEM NetworkItem - ) -{ - NETWORK_STACK_CONTEXT networkStackContext; - - networkStackContext.NetworkItem = NetworkItem; - networkStackContext.SymbolProvider = PhCreateSymbolProvider(NetworkItem->ProcessId); - - if (networkStackContext.SymbolProvider->IsRealHandle) - { - // Load symbols for the process. - networkStackContext.LoadingProcessId = NetworkItem->ProcessId; - PhEnumGenericModules( - NetworkItem->ProcessId, - networkStackContext.SymbolProvider->ProcessHandle, - 0, - LoadSymbolsEnumGenericModulesCallback, - &networkStackContext - ); - // Load symbols for kernel-mode. - networkStackContext.LoadingProcessId = SYSTEM_PROCESS_ID; - PhEnumGenericModules( - SYSTEM_PROCESS_ID, - NULL, - 0, - LoadSymbolsEnumGenericModulesCallback, - &networkStackContext - ); - } - else - { - PhDereferenceObject(networkStackContext.SymbolProvider); - PhShowError(ParentWindowHandle, L"Unable to open the process."); - return; - } - - DialogBoxParam( - PhInstanceHandle, - MAKEINTRESOURCE(IDD_NETSTACK), - ParentWindowHandle, - PhpNetworkStackDlgProc, - (LPARAM)&networkStackContext - ); - - PhDereferenceObject(networkStackContext.SymbolProvider); -} - -static INT_PTR CALLBACK PhpNetworkStackDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - switch (uMsg) - { - case WM_INITDIALOG: - { - PNETWORK_STACK_CONTEXT networkStackContext; - HWND lvHandle; - PPH_LAYOUT_MANAGER layoutManager; - PVOID address; - ULONG i; - - PhCenterWindow(hwndDlg, GetParent(hwndDlg)); - - networkStackContext = (PNETWORK_STACK_CONTEXT)lParam; - SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)networkStackContext); - - lvHandle = GetDlgItem(hwndDlg, IDC_LIST); - PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 350, L"Name"); - PhSetListViewStyle(lvHandle, FALSE, TRUE); - PhSetControlTheme(lvHandle, L"explorer"); - - networkStackContext->ListViewHandle = lvHandle; - - layoutManager = PhAllocate(sizeof(PH_LAYOUT_MANAGER)); - PhInitializeLayoutManager(layoutManager, hwndDlg); - SetProp(hwndDlg, L"LayoutManager", (HANDLE)layoutManager); - - PhAddLayoutItem(layoutManager, lvHandle, NULL, - PH_ANCHOR_ALL); - PhAddLayoutItem(layoutManager, GetDlgItem(hwndDlg, IDOK), - NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); - - if (MinimumSize.left == -1) - { - RECT rect; - - rect.left = 0; - rect.top = 0; - rect.right = 190; - rect.bottom = 120; - MapDialogRect(hwndDlg, &rect); - MinimumSize = rect; - MinimumSize.left = 0; - } - - for (i = 0; i < PH_NETWORK_OWNER_INFO_SIZE; i++) - { - PPH_STRING name; - - address = *(PVOID *)&networkStackContext->NetworkItem->OwnerInfo[i]; - - if ((ULONG_PTR)address < PAGE_SIZE) // stop at an invalid address - break; - - name = PhGetSymbolFromAddress( - networkStackContext->SymbolProvider, - (ULONG64)address, - NULL, - NULL, - NULL, - NULL - ); - PhAddListViewItem(lvHandle, MAXINT, name->Buffer, NULL); - PhDereferenceObject(name); - } - } - break; - case WM_DESTROY: - { - PPH_LAYOUT_MANAGER layoutManager; - PNETWORK_STACK_CONTEXT networkStackContext; - - layoutManager = (PPH_LAYOUT_MANAGER)GetProp(hwndDlg, L"LayoutManager"); - PhDeleteLayoutManager(layoutManager); - PhFree(layoutManager); - - networkStackContext = (PNETWORK_STACK_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom()); - - RemoveProp(hwndDlg, PhMakeContextAtom()); - RemoveProp(hwndDlg, L"LayoutManager"); - } - break; - case WM_COMMAND: - { - INT id = LOWORD(wParam); - - switch (id) - { - case IDCANCEL: // Esc and X button to close - case IDOK: - EndDialog(hwndDlg, IDOK); - break; - } - } - break; - case WM_SIZE: - { - PPH_LAYOUT_MANAGER layoutManager; - - layoutManager = (PPH_LAYOUT_MANAGER)GetProp(hwndDlg, L"LayoutManager"); - PhLayoutManagerLayout(layoutManager); - } - break; - case WM_SIZING: - { - PhResizingMinimumSize((PRECT)lParam, wParam, MinimumSize.right, MinimumSize.bottom); - } - break; - } - - return FALSE; -} +/* + * Process Hacker - + * network stack viewer + * + * Copyright (C) 2010 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include + +#include + +#include + +typedef struct NETWORK_STACK_CONTEXT +{ + HWND ListViewHandle; + PPH_NETWORK_ITEM NetworkItem; + PPH_SYMBOL_PROVIDER SymbolProvider; + HANDLE LoadingProcessId; +} NETWORK_STACK_CONTEXT, *PNETWORK_STACK_CONTEXT; + +INT_PTR CALLBACK PhpNetworkStackDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +static RECT MinimumSize = { -1, -1, -1, -1 }; + +static BOOLEAN LoadSymbolsEnumGenericModulesCallback( + _In_ PPH_MODULE_INFO Module, + _In_opt_ PVOID Context + ) +{ + PNETWORK_STACK_CONTEXT context = Context; + PPH_SYMBOL_PROVIDER symbolProvider = context->SymbolProvider; + + // If we're loading kernel module symbols for a process other than + // System, ignore modules which are in user space. This may happen + // in Windows 7. + if ( + context->LoadingProcessId == SYSTEM_PROCESS_ID && + context->NetworkItem->ProcessId != SYSTEM_PROCESS_ID && + (ULONG_PTR)Module->BaseAddress <= PhSystemBasicInformation.MaximumUserModeAddress + ) + return TRUE; + + PhLoadModuleSymbolProvider( + symbolProvider, + Module->FileName->Buffer, + (ULONG64)Module->BaseAddress, + Module->Size + ); + + return TRUE; +} + +VOID PhShowNetworkStackDialog( + _In_ HWND ParentWindowHandle, + _In_ PPH_NETWORK_ITEM NetworkItem + ) +{ + NETWORK_STACK_CONTEXT networkStackContext; + + networkStackContext.NetworkItem = NetworkItem; + networkStackContext.SymbolProvider = PhCreateSymbolProvider(NetworkItem->ProcessId); + + if (networkStackContext.SymbolProvider->IsRealHandle) + { + // Load symbols for the process. + networkStackContext.LoadingProcessId = NetworkItem->ProcessId; + PhEnumGenericModules( + NetworkItem->ProcessId, + networkStackContext.SymbolProvider->ProcessHandle, + 0, + LoadSymbolsEnumGenericModulesCallback, + &networkStackContext + ); + // Load symbols for kernel-mode. + networkStackContext.LoadingProcessId = SYSTEM_PROCESS_ID; + PhEnumGenericModules( + SYSTEM_PROCESS_ID, + NULL, + 0, + LoadSymbolsEnumGenericModulesCallback, + &networkStackContext + ); + } + else + { + PhDereferenceObject(networkStackContext.SymbolProvider); + PhShowError(ParentWindowHandle, L"Unable to open the process."); + return; + } + + DialogBoxParam( + PhInstanceHandle, + MAKEINTRESOURCE(IDD_NETSTACK), + ParentWindowHandle, + PhpNetworkStackDlgProc, + (LPARAM)&networkStackContext + ); + + PhDereferenceObject(networkStackContext.SymbolProvider); +} + +static INT_PTR CALLBACK PhpNetworkStackDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + switch (uMsg) + { + case WM_INITDIALOG: + { + PNETWORK_STACK_CONTEXT networkStackContext; + HWND lvHandle; + PPH_LAYOUT_MANAGER layoutManager; + PVOID address; + ULONG i; + + PhCenterWindow(hwndDlg, GetParent(hwndDlg)); + + networkStackContext = (PNETWORK_STACK_CONTEXT)lParam; + SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)networkStackContext); + + lvHandle = GetDlgItem(hwndDlg, IDC_LIST); + PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 350, L"Name"); + PhSetListViewStyle(lvHandle, FALSE, TRUE); + PhSetControlTheme(lvHandle, L"explorer"); + + networkStackContext->ListViewHandle = lvHandle; + + layoutManager = PhAllocate(sizeof(PH_LAYOUT_MANAGER)); + PhInitializeLayoutManager(layoutManager, hwndDlg); + SetProp(hwndDlg, L"LayoutManager", (HANDLE)layoutManager); + + PhAddLayoutItem(layoutManager, lvHandle, NULL, + PH_ANCHOR_ALL); + PhAddLayoutItem(layoutManager, GetDlgItem(hwndDlg, IDOK), + NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); + + if (MinimumSize.left == -1) + { + RECT rect; + + rect.left = 0; + rect.top = 0; + rect.right = 190; + rect.bottom = 120; + MapDialogRect(hwndDlg, &rect); + MinimumSize = rect; + MinimumSize.left = 0; + } + + for (i = 0; i < PH_NETWORK_OWNER_INFO_SIZE; i++) + { + PPH_STRING name; + + address = *(PVOID *)&networkStackContext->NetworkItem->OwnerInfo[i]; + + if ((ULONG_PTR)address < PAGE_SIZE) // stop at an invalid address + break; + + name = PhGetSymbolFromAddress( + networkStackContext->SymbolProvider, + (ULONG64)address, + NULL, + NULL, + NULL, + NULL + ); + PhAddListViewItem(lvHandle, MAXINT, name->Buffer, NULL); + PhDereferenceObject(name); + } + } + break; + case WM_DESTROY: + { + PPH_LAYOUT_MANAGER layoutManager; + PNETWORK_STACK_CONTEXT networkStackContext; + + layoutManager = (PPH_LAYOUT_MANAGER)GetProp(hwndDlg, L"LayoutManager"); + PhDeleteLayoutManager(layoutManager); + PhFree(layoutManager); + + networkStackContext = (PNETWORK_STACK_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom()); + + RemoveProp(hwndDlg, PhMakeContextAtom()); + RemoveProp(hwndDlg, L"LayoutManager"); + } + break; + case WM_COMMAND: + { + INT id = LOWORD(wParam); + + switch (id) + { + case IDCANCEL: // Esc and X button to close + case IDOK: + EndDialog(hwndDlg, IDOK); + break; + } + } + break; + case WM_SIZE: + { + PPH_LAYOUT_MANAGER layoutManager; + + layoutManager = (PPH_LAYOUT_MANAGER)GetProp(hwndDlg, L"LayoutManager"); + PhLayoutManagerLayout(layoutManager); + } + break; + case WM_SIZING: + { + PhResizingMinimumSize((PRECT)lParam, wParam, MinimumSize.right, MinimumSize.bottom); + } + break; + } + + return FALSE; +} diff --git a/ProcessHacker/notifico.c b/ProcessHacker/notifico.c index f7e842a2d6cf..ccaedd1c3915 100644 --- a/ProcessHacker/notifico.c +++ b/ProcessHacker/notifico.c @@ -1,1345 +1,1345 @@ -/* - * Process Hacker - - * notification icon manager - * - * Copyright (C) 2011-2016 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include -#include - -#include -#include - -#include -#include -#include -#include -#include -#include - -#include -#include - -BOOLEAN PhNfTerminating = FALSE; -ULONG PhNfIconMask; -ULONG PhNfIconNotifyMask; -ULONG PhNfMaximumIconId = PH_ICON_DEFAULT_MAXIMUM; -PPH_NF_ICON PhNfRegisteredIcons[32] = { 0 }; -PPH_STRING PhNfIconTextCache[32] = { 0 }; -BOOLEAN PhNfMiniInfoEnabled; -BOOLEAN PhNfMiniInfoPinned; - -PH_NF_POINTERS PhNfpPointers; -PH_CALLBACK_REGISTRATION PhNfpProcessesUpdatedRegistration; -PH_NF_BITMAP PhNfpDefaultBitmapContext = { 0 }; -PH_NF_BITMAP PhNfpBlackBitmapContext = { 0 }; -HBITMAP PhNfpBlackBitmap = NULL; -HICON PhNfpBlackIcon = NULL; - -static POINT IconClickLocation; -static PH_NF_MSG_SHOWMINIINFOSECTION_DATA IconClickShowMiniInfoSectionData; -static BOOLEAN IconClickUpDueToDown; -static BOOLEAN IconDisableHover; - -VOID PhNfLoadStage1( - VOID - ) -{ - PPH_STRING iconList; - PH_STRINGREF part; - PH_STRINGREF remainingPart; - - PhNfpPointers.UpdateRegisteredIcon = PhNfpUpdateRegisteredIcon; - PhNfpPointers.BeginBitmap = PhNfpBeginBitmap; - - // Load settings for default icons. - PhNfIconMask = PhGetIntegerSetting(L"IconMask"); - - // Load settings for registered icons. - - iconList = PhGetStringSetting(L"IconMaskList"); - remainingPart = iconList->sr; - - while (remainingPart.Length != 0) - { - PhSplitStringRefAtChar(&remainingPart, '|', &part, &remainingPart); - - if (part.Length != 0) - { - PH_STRINGREF pluginName; - ULONG subId; - PPH_NF_ICON icon; - - if (PhEmParseCompoundId(&part, &pluginName, &subId) && - (icon = PhNfFindIcon(&pluginName, subId))) - { - PhNfIconMask |= icon->IconId; - } - } - } - - PhDereferenceObject(iconList); -} - -VOID PhNfLoadStage2( - VOID - ) -{ - ULONG i; - - PhNfMiniInfoEnabled = WindowsVersion >= WINDOWS_VISTA && !!PhGetIntegerSetting(L"MiniInfoWindowEnabled"); - - for (i = PH_ICON_MINIMUM; i != PhNfMaximumIconId; i <<= 1) - { - if (PhNfIconMask & i) - PhNfpAddNotifyIcon(i); - } - - PhRegisterCallback( - &PhProcessesUpdatedEvent, - PhNfpProcessesUpdatedHandler, - NULL, - &PhNfpProcessesUpdatedRegistration - ); -} - -VOID PhNfSaveSettings( - VOID - ) -{ - ULONG registeredIconMask; - - PhSetIntegerSetting(L"IconMask", PhNfIconMask & PH_ICON_DEFAULT_ALL); - - registeredIconMask = PhNfIconMask & ~PH_ICON_DEFAULT_ALL; - - if (registeredIconMask != 0) - { - PH_STRING_BUILDER iconListBuilder; - ULONG i; - - PhInitializeStringBuilder(&iconListBuilder, 60); - - for (i = 0; i < sizeof(PhNfRegisteredIcons) / sizeof(PPH_NF_ICON); i++) - { - if (PhNfRegisteredIcons[i]) - { - if (registeredIconMask & PhNfRegisteredIcons[i]->IconId) - { - PhAppendFormatStringBuilder( - &iconListBuilder, - L"+%s+%u|", - PhNfRegisteredIcons[i]->Plugin->Name.Buffer, - PhNfRegisteredIcons[i]->SubId - ); - } - } - } - - if (iconListBuilder.String->Length != 0) - PhRemoveEndStringBuilder(&iconListBuilder, 1); - - PhSetStringSetting2(L"IconMaskList", &iconListBuilder.String->sr); - PhDeleteStringBuilder(&iconListBuilder); - } - else - { - PhSetStringSetting(L"IconMaskList", L""); - } -} - -VOID PhNfUninitialization( - VOID - ) -{ - ULONG i; - - // Remove all icons to prevent them hanging around after we exit. - - PhNfTerminating = TRUE; // prevent further icon updating - - for (i = PH_ICON_MINIMUM; i != PhNfMaximumIconId; i <<= 1) - { - if (PhNfIconMask & i) - PhNfpRemoveNotifyIcon(i); - } -} - -VOID PhNfForwardMessage( - _In_ ULONG_PTR WParam, - _In_ ULONG_PTR LParam - ) -{ - ULONG iconIndex = HIWORD(LParam); - PPH_NF_ICON registeredIcon = NULL; - - if (iconIndex < sizeof(PhNfRegisteredIcons) / sizeof(PPH_NF_ICON) && PhNfRegisteredIcons[iconIndex]) - { - registeredIcon = PhNfRegisteredIcons[iconIndex]; - - if (registeredIcon->MessageCallback) - { - if (registeredIcon->MessageCallback( - registeredIcon, - WParam, - LParam, - registeredIcon->Context - )) - { - return; - } - } - } - - switch (LOWORD(LParam)) - { - case WM_LBUTTONDOWN: - { - if (PhGetIntegerSetting(L"IconSingleClick")) - { - ProcessHacker_IconClick(PhMainWndHandle); - PhNfpDisableHover(); - } - else - { - IconClickUpDueToDown = TRUE; - } - } - break; - case WM_LBUTTONUP: - { - if (!PhGetIntegerSetting(L"IconSingleClick") && PhNfMiniInfoEnabled && IconClickUpDueToDown) - { - PH_NF_MSG_SHOWMINIINFOSECTION_DATA showMiniInfoSectionData; - - if (PhNfpGetShowMiniInfoSectionData(iconIndex, registeredIcon, &showMiniInfoSectionData)) - { - GetCursorPos(&IconClickLocation); - - if (IconClickShowMiniInfoSectionData.SectionName) - { - PhFree(IconClickShowMiniInfoSectionData.SectionName); - IconClickShowMiniInfoSectionData.SectionName = NULL; - } - - if (showMiniInfoSectionData.SectionName) - { - IconClickShowMiniInfoSectionData.SectionName = PhDuplicateStringZ(showMiniInfoSectionData.SectionName); - } - - SetTimer(PhMainWndHandle, TIMER_ICON_CLICK_ACTIVATE, GetDoubleClickTime() + NFP_ICON_CLICK_ACTIVATE_DELAY, PhNfpIconClickActivateTimerProc); - } - else - { - KillTimer(PhMainWndHandle, TIMER_ICON_CLICK_ACTIVATE); - } - } - } - break; - case WM_LBUTTONDBLCLK: - { - if (!PhGetIntegerSetting(L"IconSingleClick")) - { - if (PhNfMiniInfoEnabled) - { - // We will get another WM_LBUTTONUP message corresponding to the double-click, - // and we need to make sure that it doesn't start the activation timer again. - KillTimer(PhMainWndHandle, TIMER_ICON_CLICK_ACTIVATE); - IconClickUpDueToDown = FALSE; - PhNfpDisableHover(); - } - - ProcessHacker_IconClick(PhMainWndHandle); - } - } - break; - case WM_RBUTTONUP: - case WM_CONTEXTMENU: - { - POINT location; - - if (!PhGetIntegerSetting(L"IconSingleClick") && PhNfMiniInfoEnabled) - KillTimer(PhMainWndHandle, TIMER_ICON_CLICK_ACTIVATE); - - PhPinMiniInformation(MiniInfoIconPinType, -1, 0, 0, NULL, NULL); - GetCursorPos(&location); - PhShowIconContextMenu(location); - } - break; - case NIN_KEYSELECT: - // HACK: explorer seems to send two NIN_KEYSELECT messages when the user selects the icon and presses ENTER. - if (GetForegroundWindow() != PhMainWndHandle) - ProcessHacker_IconClick(PhMainWndHandle); - break; - case NIN_BALLOONUSERCLICK: - PhShowDetailsForIconNotification(); - break; - case NIN_POPUPOPEN: - { - PH_NF_MSG_SHOWMINIINFOSECTION_DATA showMiniInfoSectionData; - POINT location; - - if (PhNfMiniInfoEnabled && !IconDisableHover && PhNfpGetShowMiniInfoSectionData(iconIndex, registeredIcon, &showMiniInfoSectionData)) - { - GetCursorPos(&location); - PhPinMiniInformation(MiniInfoIconPinType, 1, 0, PH_MINIINFO_DONT_CHANGE_SECTION_IF_PINNED, - showMiniInfoSectionData.SectionName, &location); - } - } - break; - case NIN_POPUPCLOSE: - PhPinMiniInformation(MiniInfoIconPinType, -1, 350, 0, NULL, NULL); - break; - } -} - -ULONG PhNfGetMaximumIconId( - VOID - ) -{ - return PhNfMaximumIconId; -} - -ULONG PhNfTestIconMask( - _In_ ULONG Id - ) -{ - return PhNfIconMask & Id; -} - -VOID PhNfSetVisibleIcon( - _In_ ULONG Id, - _In_ BOOLEAN Visible - ) -{ - if (Visible) - { - PhNfIconMask |= Id; - PhNfpAddNotifyIcon(Id); - } - else - { - PhNfIconMask &= ~Id; - PhNfpRemoveNotifyIcon(Id); - } -} - -BOOLEAN PhNfShowBalloonTip( - _In_opt_ ULONG Id, - _In_ PWSTR Title, - _In_ PWSTR Text, - _In_ ULONG Timeout, - _In_ ULONG Flags - ) -{ - NOTIFYICONDATA notifyIcon = { NOTIFYICONDATA_V3_SIZE }; - - if (Id == 0) - { - // Choose the first visible icon. - Id = PhNfIconMask; - } - - if (!_BitScanForward(&Id, Id)) - return FALSE; - - notifyIcon.hWnd = PhMainWndHandle; - notifyIcon.uID = Id; - notifyIcon.uFlags = NIF_INFO; - wcsncpy_s(notifyIcon.szInfoTitle, sizeof(notifyIcon.szInfoTitle) / sizeof(WCHAR), Title, _TRUNCATE); - wcsncpy_s(notifyIcon.szInfo, sizeof(notifyIcon.szInfo) / sizeof(WCHAR), Text, _TRUNCATE); - notifyIcon.uTimeout = Timeout; - notifyIcon.dwInfoFlags = Flags; - - Shell_NotifyIcon(NIM_MODIFY, ¬ifyIcon); - - return TRUE; -} - -HICON PhNfBitmapToIcon( - _In_ HBITMAP Bitmap - ) -{ - ICONINFO iconInfo; - - PhNfpGetBlackIcon(); - - iconInfo.fIcon = TRUE; - iconInfo.xHotspot = 0; - iconInfo.yHotspot = 0; - iconInfo.hbmMask = PhNfpBlackBitmap; - iconInfo.hbmColor = Bitmap; - - return CreateIconIndirect(&iconInfo); -} - -PPH_NF_ICON PhNfRegisterIcon( - _In_ struct _PH_PLUGIN *Plugin, - _In_ ULONG SubId, - _In_opt_ PVOID Context, - _In_ PWSTR Text, - _In_ ULONG Flags, - _In_opt_ PPH_NF_ICON_UPDATE_CALLBACK UpdateCallback, - _In_opt_ PPH_NF_ICON_MESSAGE_CALLBACK MessageCallback - ) -{ - PPH_NF_ICON icon; - ULONG iconId; - ULONG iconIndex; - - if (PhNfMaximumIconId == PH_ICON_LIMIT) - { - // No room for any more icons. - return NULL; - } - - iconId = PhNfMaximumIconId; - - if (!_BitScanReverse(&iconIndex, iconId) || - iconIndex >= sizeof(PhNfRegisteredIcons) / sizeof(PPH_NF_ICON)) - { - // Should never happen. - return NULL; - } - - PhNfMaximumIconId <<= 1; - - icon = PhAllocate(sizeof(PH_NF_ICON)); - icon->Plugin = Plugin; - icon->SubId = SubId; - icon->Context = Context; - icon->Pointers = &PhNfpPointers; - icon->Text = Text; - icon->Flags = Flags; - icon->IconId = iconId; - icon->UpdateCallback = UpdateCallback; - icon->MessageCallback = MessageCallback; - - PhNfRegisteredIcons[iconIndex] = icon; - - return icon; -} - -PPH_NF_ICON PhNfGetIconById( - _In_ ULONG Id - ) -{ - ULONG iconIndex; - - if (!_BitScanReverse(&iconIndex, Id)) - return NULL; - - return PhNfRegisteredIcons[iconIndex]; -} - -PPH_NF_ICON PhNfFindIcon( - _In_ PPH_STRINGREF PluginName, - _In_ ULONG SubId - ) -{ - ULONG i; - - for (i = 0; i < sizeof(PhNfRegisteredIcons) / sizeof(PPH_NF_ICON); i++) - { - if (PhNfRegisteredIcons[i]) - { - if (PhNfRegisteredIcons[i]->SubId == SubId && - PhEqualStringRef(PluginName, &PhNfRegisteredIcons[i]->Plugin->AppContext.AppName, FALSE)) - { - return PhNfRegisteredIcons[i]; - } - } - } - - return NULL; -} - -VOID PhNfNotifyMiniInfoPinned( - _In_ BOOLEAN Pinned - ) -{ - ULONG i; - ULONG id; - - if (PhNfMiniInfoPinned != Pinned) - { - PhNfMiniInfoPinned = Pinned; - - // Go through every icon and set/clear the NIF_SHOWTIP flag depending on whether the mini info window is - // pinned. If it's pinned then we want to show normal tooltips, because the section doesn't change - // automatically when the cursor hovers over an icon. - for (i = 0; i < sizeof(PhNfRegisteredIcons) / sizeof(PPH_NF_ICON); i++) - { - id = 1 << i; - - if (PhNfIconMask & id) - { - PhNfpModifyNotifyIcon(id, NIF_TIP, PhNfIconTextCache[i], NULL); - } - } - } -} - -HICON PhNfpGetBlackIcon( - VOID - ) -{ - if (!PhNfpBlackIcon) - { - ULONG width; - ULONG height; - PVOID bits; - HDC hdc; - HBITMAP oldBitmap; - ICONINFO iconInfo; - - PhNfpBeginBitmap2(&PhNfpBlackBitmapContext, &width, &height, &PhNfpBlackBitmap, &bits, &hdc, &oldBitmap); - memset(bits, 0, width * height * sizeof(ULONG)); - - iconInfo.fIcon = TRUE; - iconInfo.xHotspot = 0; - iconInfo.yHotspot = 0; - iconInfo.hbmMask = PhNfpBlackBitmap; - iconInfo.hbmColor = PhNfpBlackBitmap; - PhNfpBlackIcon = CreateIconIndirect(&iconInfo); - - SelectObject(hdc, oldBitmap); - } - - return PhNfpBlackIcon; -} - -BOOLEAN PhNfpAddNotifyIcon( - _In_ ULONG Id - ) -{ - NOTIFYICONDATA notifyIcon = { sizeof(NOTIFYICONDATA) }; - PPH_NF_ICON icon; - - if (PhNfTerminating) - return FALSE; - if ((icon = PhNfGetIconById(Id)) && (icon->Flags & PH_NF_ICON_UNAVAILABLE)) - return FALSE; - - // The IDs we pass to explorer are bit indicies, not the normal mask values. - - if (!_BitScanForward(&Id, Id)) - return FALSE; - - notifyIcon.hWnd = PhMainWndHandle; - notifyIcon.uID = Id; - notifyIcon.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP; - notifyIcon.uCallbackMessage = WM_PH_NOTIFY_ICON_MESSAGE; - wcsncpy_s( - notifyIcon.szTip, sizeof(notifyIcon.szTip) / sizeof(WCHAR), - PhGetStringOrDefault(PhNfIconTextCache[Id], PhApplicationName), - _TRUNCATE - ); - notifyIcon.hIcon = PhNfpGetBlackIcon(); - - if (!PhNfMiniInfoEnabled || PhNfMiniInfoPinned || (icon && !(icon->Flags & PH_NF_ICON_SHOW_MINIINFO))) - notifyIcon.uFlags |= NIF_SHOWTIP; - - Shell_NotifyIcon(NIM_ADD, ¬ifyIcon); - - if (WindowsVersion >= WINDOWS_VISTA) - { - notifyIcon.uVersion = NOTIFYICON_VERSION_4; - Shell_NotifyIcon(NIM_SETVERSION, ¬ifyIcon); - } - - return TRUE; -} - -BOOLEAN PhNfpRemoveNotifyIcon( - _In_ ULONG Id - ) -{ - NOTIFYICONDATA notifyIcon = { sizeof(NOTIFYICONDATA) }; - PPH_NF_ICON icon; - - if ((icon = PhNfGetIconById(Id)) && (icon->Flags & PH_NF_ICON_UNAVAILABLE)) - return FALSE; - - if (!_BitScanForward(&Id, Id)) - return FALSE; - - notifyIcon.hWnd = PhMainWndHandle; - notifyIcon.uID = Id; - - Shell_NotifyIcon(NIM_DELETE, ¬ifyIcon); - - return TRUE; -} - -BOOLEAN PhNfpModifyNotifyIcon( - _In_ ULONG Id, - _In_ ULONG Flags, - _In_opt_ PPH_STRING Text, - _In_opt_ HICON Icon - ) -{ - NOTIFYICONDATA notifyIcon = { sizeof(NOTIFYICONDATA) }; - PPH_NF_ICON icon; - ULONG notifyId; - - if (PhNfTerminating) - return FALSE; - if ((icon = PhNfGetIconById(Id)) && (icon->Flags & PH_NF_ICON_UNAVAILABLE)) - return FALSE; - - if (!_BitScanForward(¬ifyId, Id)) - return FALSE; - - notifyIcon.hWnd = PhMainWndHandle; - notifyIcon.uID = notifyId; - notifyIcon.uFlags = Flags; - - if (Flags & NIF_TIP) - { - PhSwapReference(&PhNfIconTextCache[notifyId], Text); - wcsncpy_s( - notifyIcon.szTip, - sizeof(notifyIcon.szTip) / sizeof(WCHAR), - PhGetStringOrDefault(Text, PhApplicationName), - _TRUNCATE - ); - } - - notifyIcon.hIcon = Icon; - - if (!PhNfMiniInfoEnabled || PhNfMiniInfoPinned || (icon && !(icon->Flags & PH_NF_ICON_SHOW_MINIINFO))) - notifyIcon.uFlags |= NIF_SHOWTIP; - - if (!Shell_NotifyIcon(NIM_MODIFY, ¬ifyIcon)) - { - // Explorer probably died and we lost our icon. Try to add the icon, and try again. - PhNfpAddNotifyIcon(Id); - Shell_NotifyIcon(NIM_MODIFY, ¬ifyIcon); - } - - return TRUE; -} - -VOID PhNfpProcessesUpdatedHandler( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - ULONG registeredIconMask; - - // We do icon updating on the provider thread so we don't block the main GUI when - // explorer is not responding. - - if (PhNfIconMask & PH_ICON_CPU_HISTORY) - PhNfpUpdateIconCpuHistory(); - if (PhNfIconMask & PH_ICON_IO_HISTORY) - PhNfpUpdateIconIoHistory(); - if (PhNfIconMask & PH_ICON_COMMIT_HISTORY) - PhNfpUpdateIconCommitHistory(); - if (PhNfIconMask & PH_ICON_PHYSICAL_HISTORY) - PhNfpUpdateIconPhysicalHistory(); - if (PhNfIconMask & PH_ICON_CPU_USAGE) - PhNfpUpdateIconCpuUsage(); - - registeredIconMask = PhNfIconMask & ~PH_ICON_DEFAULT_ALL; - - if (registeredIconMask != 0) - { - ULONG i; - - for (i = 0; i < sizeof(PhNfRegisteredIcons) / sizeof(PPH_NF_ICON); i++) - { - if (PhNfRegisteredIcons[i] && (registeredIconMask & PhNfRegisteredIcons[i]->IconId)) - { - PhNfpUpdateRegisteredIcon(PhNfRegisteredIcons[i]); - } - } - } -} - -VOID PhNfpUpdateRegisteredIcon( - _In_ PPH_NF_ICON Icon - ) -{ - PVOID newIconOrBitmap; - ULONG updateFlags; - PPH_STRING newText; - HICON newIcon; - ULONG flags; - - if (!Icon->UpdateCallback) - return; - - newIconOrBitmap = NULL; - newText = NULL; - newIcon = NULL; - flags = 0; - - Icon->UpdateCallback( - Icon, - &newIconOrBitmap, - &updateFlags, - &newText, - Icon->Context - ); - - if (newIconOrBitmap) - { - if (updateFlags & PH_NF_UPDATE_IS_BITMAP) - newIcon = PhNfBitmapToIcon(newIconOrBitmap); - else - newIcon = newIconOrBitmap; - - flags |= NIF_ICON; - } - - if (newText) - flags |= NIF_TIP; - - if (flags != 0) - PhNfpModifyNotifyIcon(Icon->IconId, flags, newText, newIcon); - - if (newIcon && (updateFlags & PH_NF_UPDATE_IS_BITMAP)) - DestroyIcon(newIcon); - - if (newIconOrBitmap && (updateFlags & PH_NF_UPDATE_DESTROY_RESOURCE)) - { - if (updateFlags & PH_NF_UPDATE_IS_BITMAP) - DeleteObject(newIconOrBitmap); - else - DestroyIcon(newIconOrBitmap); - } - - if (newText) - PhDereferenceObject(newText); -} - -VOID PhNfpBeginBitmap( - _Out_ PULONG Width, - _Out_ PULONG Height, - _Out_ HBITMAP *Bitmap, - _Out_opt_ PVOID *Bits, - _Out_ HDC *Hdc, - _Out_ HBITMAP *OldBitmap - ) -{ - PhNfpBeginBitmap2(&PhNfpDefaultBitmapContext, Width, Height, Bitmap, Bits, Hdc, OldBitmap); -} - -VOID PhNfpBeginBitmap2( - _Inout_ PPH_NF_BITMAP Context, - _Out_ PULONG Width, - _Out_ PULONG Height, - _Out_ HBITMAP *Bitmap, - _Out_opt_ PVOID *Bits, - _Out_ HDC *Hdc, - _Out_ HBITMAP *OldBitmap - ) -{ - if (!Context->Initialized) - { - HDC screenHdc; - - screenHdc = GetDC(NULL); - Context->Hdc = CreateCompatibleDC(screenHdc); - - memset(&Context->Header, 0, sizeof(BITMAPINFOHEADER)); - Context->Header.biSize = sizeof(BITMAPINFOHEADER); - Context->Header.biWidth = PhSmallIconSize.X; - Context->Header.biHeight = PhSmallIconSize.Y; - Context->Header.biPlanes = 1; - Context->Header.biBitCount = 32; - Context->Bitmap = CreateDIBSection(screenHdc, (BITMAPINFO *)&Context->Header, DIB_RGB_COLORS, &Context->Bits, NULL, 0); - - ReleaseDC(NULL, screenHdc); - - Context->Initialized = TRUE; - } - - *Width = PhSmallIconSize.X; - *Height = PhSmallIconSize.Y; - *Bitmap = Context->Bitmap; - if (Bits) *Bits = Context->Bits; - *Hdc = Context->Hdc; - *OldBitmap = SelectObject(Context->Hdc, Context->Bitmap); -} - -VOID PhNfpUpdateIconCpuHistory( - VOID - ) -{ - static PH_GRAPH_DRAW_INFO drawInfo = - { - 16, - 16, - PH_GRAPH_USE_LINE_2, - 2, - RGB(0x00, 0x00, 0x00), - - 16, - NULL, - NULL, - 0, - 0, - 0, - 0 - }; - ULONG maxDataCount; - ULONG lineDataCount; - PFLOAT lineData1; - PFLOAT lineData2; - HBITMAP bitmap; - PVOID bits; - HDC hdc; - HBITMAP oldBitmap; - HICON icon; - HANDLE maxCpuProcessId; - PPH_PROCESS_ITEM maxCpuProcessItem; - PH_FORMAT format[8]; - PPH_STRING text; - - // Icon - - PhNfpBeginBitmap(&drawInfo.Width, &drawInfo.Height, &bitmap, &bits, &hdc, &oldBitmap); - maxDataCount = drawInfo.Width / 2 + 1; - lineData1 = _alloca(maxDataCount * sizeof(FLOAT)); - lineData2 = _alloca(maxDataCount * sizeof(FLOAT)); - - lineDataCount = min(maxDataCount, PhCpuKernelHistory.Count); - PhCopyCircularBuffer_FLOAT(&PhCpuKernelHistory, lineData1, lineDataCount); - PhCopyCircularBuffer_FLOAT(&PhCpuUserHistory, lineData2, lineDataCount); - - drawInfo.LineDataCount = lineDataCount; - drawInfo.LineData1 = lineData1; - drawInfo.LineData2 = lineData2; - drawInfo.LineColor1 = PhCsColorCpuKernel; - drawInfo.LineColor2 = PhCsColorCpuUser; - drawInfo.LineBackColor1 = PhHalveColorBrightness(PhCsColorCpuKernel); - drawInfo.LineBackColor2 = PhHalveColorBrightness(PhCsColorCpuUser); - - if (bits) - PhDrawGraphDirect(hdc, bits, &drawInfo); - - SelectObject(hdc, oldBitmap); - icon = PhNfBitmapToIcon(bitmap); - - // Text - - if (PhMaxCpuHistory.Count != 0) - maxCpuProcessId = UlongToHandle(PhGetItemCircularBuffer_ULONG(&PhMaxCpuHistory, 0)); - else - maxCpuProcessId = NULL; - - if (maxCpuProcessId) - maxCpuProcessItem = PhReferenceProcessItem(maxCpuProcessId); - else - maxCpuProcessItem = NULL; - - PhInitFormatS(&format[0], L"CPU Usage: "); - PhInitFormatF(&format[1], (PhCpuKernelUsage + PhCpuUserUsage) * 100, 2); - PhInitFormatC(&format[2], '%'); - - if (maxCpuProcessItem) - { - PhInitFormatC(&format[3], '\n'); - PhInitFormatSR(&format[4], maxCpuProcessItem->ProcessName->sr); - PhInitFormatS(&format[5], L": "); - PhInitFormatF(&format[6], maxCpuProcessItem->CpuUsage * 100, 2); - PhInitFormatC(&format[7], '%'); - } - - text = PhFormat(format, maxCpuProcessItem ? 8 : 3, 128); - if (maxCpuProcessItem) PhDereferenceObject(maxCpuProcessItem); - - PhNfpModifyNotifyIcon(PH_ICON_CPU_HISTORY, NIF_TIP | NIF_ICON, text, icon); - - DestroyIcon(icon); - PhDereferenceObject(text); -} - -VOID PhNfpUpdateIconIoHistory( - VOID - ) -{ - static PH_GRAPH_DRAW_INFO drawInfo = - { - 16, - 16, - PH_GRAPH_USE_LINE_2, - 2, - RGB(0x00, 0x00, 0x00), - - 16, - NULL, - NULL, - 0, - 0, - 0, - 0 - }; - ULONG maxDataCount; - ULONG lineDataCount; - PFLOAT lineData1; - PFLOAT lineData2; - FLOAT max; - ULONG i; - HBITMAP bitmap; - PVOID bits; - HDC hdc; - HBITMAP oldBitmap; - HICON icon; - HANDLE maxIoProcessId; - PPH_PROCESS_ITEM maxIoProcessItem; - PH_FORMAT format[8]; - PPH_STRING text; - - // Icon - - PhNfpBeginBitmap(&drawInfo.Width, &drawInfo.Height, &bitmap, &bits, &hdc, &oldBitmap); - maxDataCount = drawInfo.Width / 2 + 1; - lineData1 = _alloca(maxDataCount * sizeof(FLOAT)); - lineData2 = _alloca(maxDataCount * sizeof(FLOAT)); - - lineDataCount = min(maxDataCount, PhIoReadHistory.Count); - max = 1024 * 1024; // minimum scaling of 1 MB. - - for (i = 0; i < lineDataCount; i++) - { - lineData1[i] = - (FLOAT)PhGetItemCircularBuffer_ULONG64(&PhIoReadHistory, i) + - (FLOAT)PhGetItemCircularBuffer_ULONG64(&PhIoOtherHistory, i); - lineData2[i] = - (FLOAT)PhGetItemCircularBuffer_ULONG64(&PhIoWriteHistory, i); - - if (max < lineData1[i] + lineData2[i]) - max = lineData1[i] + lineData2[i]; - } - - PhDivideSinglesBySingle(lineData1, max, lineDataCount); - PhDivideSinglesBySingle(lineData2, max, lineDataCount); - - drawInfo.LineDataCount = lineDataCount; - drawInfo.LineData1 = lineData1; - drawInfo.LineData2 = lineData2; - drawInfo.LineColor1 = PhCsColorIoReadOther; - drawInfo.LineColor2 = PhCsColorIoWrite; - drawInfo.LineBackColor1 = PhHalveColorBrightness(PhCsColorIoReadOther); - drawInfo.LineBackColor2 = PhHalveColorBrightness(PhCsColorIoWrite); - - if (bits) - PhDrawGraphDirect(hdc, bits, &drawInfo); - - SelectObject(hdc, oldBitmap); - icon = PhNfBitmapToIcon(bitmap); - - // Text - - if (PhMaxIoHistory.Count != 0) - maxIoProcessId = UlongToHandle(PhGetItemCircularBuffer_ULONG(&PhMaxIoHistory, 0)); - else - maxIoProcessId = NULL; - - if (maxIoProcessId) - maxIoProcessItem = PhReferenceProcessItem(maxIoProcessId); - else - maxIoProcessItem = NULL; - - PhInitFormatS(&format[0], L"I/O\nR: "); - PhInitFormatSize(&format[1], PhIoReadDelta.Delta); - PhInitFormatS(&format[2], L"\nW: "); - PhInitFormatSize(&format[3], PhIoWriteDelta.Delta); - PhInitFormatS(&format[4], L"\nO: "); - PhInitFormatSize(&format[5], PhIoOtherDelta.Delta); - - if (maxIoProcessItem) - { - PhInitFormatC(&format[6], '\n'); - PhInitFormatSR(&format[7], maxIoProcessItem->ProcessName->sr); - } - - text = PhFormat(format, maxIoProcessItem ? 8 : 6, 128); - if (maxIoProcessItem) PhDereferenceObject(maxIoProcessItem); - - PhNfpModifyNotifyIcon(PH_ICON_IO_HISTORY, NIF_TIP | NIF_ICON, text, icon); - - DestroyIcon(icon); - PhDereferenceObject(text); -} - -VOID PhNfpUpdateIconCommitHistory( - VOID - ) -{ - static PH_GRAPH_DRAW_INFO drawInfo = - { - 16, - 16, - 0, - 2, - RGB(0x00, 0x00, 0x00), - - 16, - NULL, - NULL, - 0, - 0, - 0, - 0 - }; - ULONG maxDataCount; - ULONG lineDataCount; - PFLOAT lineData1; - ULONG i; - HBITMAP bitmap; - PVOID bits; - HDC hdc; - HBITMAP oldBitmap; - HICON icon; - DOUBLE commitFraction; - PH_FORMAT format[5]; - PPH_STRING text; - - // Icon - - PhNfpBeginBitmap(&drawInfo.Width, &drawInfo.Height, &bitmap, &bits, &hdc, &oldBitmap); - maxDataCount = drawInfo.Width / 2 + 1; - lineData1 = _alloca(maxDataCount * sizeof(FLOAT)); - - lineDataCount = min(maxDataCount, PhCommitHistory.Count); - - for (i = 0; i < lineDataCount; i++) - lineData1[i] = (FLOAT)PhGetItemCircularBuffer_ULONG(&PhCommitHistory, i); - - PhDivideSinglesBySingle(lineData1, (FLOAT)PhPerfInformation.CommitLimit, lineDataCount); - - drawInfo.LineDataCount = lineDataCount; - drawInfo.LineData1 = lineData1; - drawInfo.LineColor1 = PhCsColorPrivate; - drawInfo.LineBackColor1 = PhHalveColorBrightness(PhCsColorPrivate); - - if (bits) - PhDrawGraphDirect(hdc, bits, &drawInfo); - - SelectObject(hdc, oldBitmap); - icon = PhNfBitmapToIcon(bitmap); - - // Text - - commitFraction = (DOUBLE)PhPerfInformation.CommittedPages / PhPerfInformation.CommitLimit; - - PhInitFormatS(&format[0], L"Commit: "); - PhInitFormatSize(&format[1], UInt32x32To64(PhPerfInformation.CommittedPages, PAGE_SIZE)); - PhInitFormatS(&format[2], L" ("); - PhInitFormatF(&format[3], commitFraction * 100, 2); - PhInitFormatS(&format[4], L"%)"); - - text = PhFormat(format, 5, 96); - - PhNfpModifyNotifyIcon(PH_ICON_COMMIT_HISTORY, NIF_TIP | NIF_ICON, text, icon); - - DestroyIcon(icon); - PhDereferenceObject(text); -} - -VOID PhNfpUpdateIconPhysicalHistory( - VOID - ) -{ - static PH_GRAPH_DRAW_INFO drawInfo = - { - 16, - 16, - 0, - 2, - RGB(0x00, 0x00, 0x00), - - 16, - NULL, - NULL, - 0, - 0, - 0, - 0 - }; - ULONG maxDataCount; - ULONG lineDataCount; - PFLOAT lineData1; - ULONG i; - HBITMAP bitmap; - PVOID bits; - HDC hdc; - HBITMAP oldBitmap; - HICON icon; - ULONG physicalUsage; - FLOAT physicalFraction; - PH_FORMAT format[5]; - PPH_STRING text; - - // Icon - - PhNfpBeginBitmap(&drawInfo.Width, &drawInfo.Height, &bitmap, &bits, &hdc, &oldBitmap); - maxDataCount = drawInfo.Width / 2 + 1; - lineData1 = _alloca(maxDataCount * sizeof(FLOAT)); - - lineDataCount = min(maxDataCount, PhCommitHistory.Count); - - for (i = 0; i < lineDataCount; i++) - lineData1[i] = (FLOAT)PhGetItemCircularBuffer_ULONG(&PhPhysicalHistory, i); - - PhDivideSinglesBySingle(lineData1, (FLOAT)PhSystemBasicInformation.NumberOfPhysicalPages, lineDataCount); - - drawInfo.LineDataCount = lineDataCount; - drawInfo.LineData1 = lineData1; - drawInfo.LineColor1 = PhCsColorPhysical; - drawInfo.LineBackColor1 = PhHalveColorBrightness(PhCsColorPhysical); - - if (bits) - PhDrawGraphDirect(hdc, bits, &drawInfo); - - SelectObject(hdc, oldBitmap); - icon = PhNfBitmapToIcon(bitmap); - - // Text - - physicalUsage = PhSystemBasicInformation.NumberOfPhysicalPages - PhPerfInformation.AvailablePages; - physicalFraction = (FLOAT)physicalUsage / PhSystemBasicInformation.NumberOfPhysicalPages; - - PhInitFormatS(&format[0], L"Physical memory: "); - PhInitFormatSize(&format[1], UInt32x32To64(physicalUsage, PAGE_SIZE)); - PhInitFormatS(&format[2], L" ("); - PhInitFormatF(&format[3], physicalFraction * 100, 2); - PhInitFormatS(&format[4], L"%)"); - - text = PhFormat(format, 5, 96); - - PhNfpModifyNotifyIcon(PH_ICON_PHYSICAL_HISTORY, NIF_TIP | NIF_ICON, text, icon); - - DestroyIcon(icon); - PhDereferenceObject(text); -} - -VOID PhNfpUpdateIconCpuUsage( - VOID - ) -{ - ULONG width; - ULONG height; - HBITMAP bitmap; - HDC hdc; - HBITMAP oldBitmap; - HICON icon; - HANDLE maxCpuProcessId; - PPH_PROCESS_ITEM maxCpuProcessItem; - PPH_STRING maxCpuText = NULL; - PPH_STRING text; - - // Icon - - PhNfpBeginBitmap(&width, &height, &bitmap, NULL, &hdc, &oldBitmap); - - // This stuff is copied from CpuUsageIcon.cs (PH 1.x). - { - COLORREF kColor = PhCsColorCpuKernel; - COLORREF uColor = PhCsColorCpuUser; - COLORREF kbColor = PhHalveColorBrightness(PhCsColorCpuKernel); - COLORREF ubColor = PhHalveColorBrightness(PhCsColorCpuUser); - FLOAT k = PhCpuKernelUsage; - FLOAT u = PhCpuUserUsage; - LONG kl = (LONG)(k * height); - LONG ul = (LONG)(u * height); - RECT rect; - HBRUSH dcBrush; - HBRUSH dcPen; - POINT points[2]; - - dcBrush = GetStockObject(DC_BRUSH); - dcPen = GetStockObject(DC_PEN); - rect.left = 0; - rect.top = 0; - rect.right = width; - rect.bottom = height; - SetDCBrushColor(hdc, RGB(0x00, 0x00, 0x00)); - FillRect(hdc, &rect, dcBrush); - - // Draw the base line. - if (kl + ul == 0) - { - SelectObject(hdc, dcPen); - SetDCPenColor(hdc, uColor); - points[0].x = 0; - points[0].y = height - 1; - points[1].x = width; - points[1].y = height - 1; - Polyline(hdc, points, 2); - } - else - { - rect.left = 0; - rect.top = height - ul - kl; - rect.right = width; - rect.bottom = height - kl; - SetDCBrushColor(hdc, ubColor); - FillRect(hdc, &rect, dcBrush); - - points[0].x = 0; - points[0].y = height - 1 - ul - kl; - if (points[0].y < 0) points[0].y = 0; - points[1].x = width; - points[1].y = points[0].y; - SelectObject(hdc, dcPen); - SetDCPenColor(hdc, uColor); - Polyline(hdc, points, 2); - - if (kl != 0) - { - rect.left = 0; - rect.top = height - kl; - rect.right = width; - rect.bottom = height; - SetDCBrushColor(hdc, kbColor); - FillRect(hdc, &rect, dcBrush); - - points[0].x = 0; - points[0].y = height - 1 - kl; - if (points[0].y < 0) points[0].y = 0; - points[1].x = width; - points[1].y = points[0].y; - SelectObject(hdc, dcPen); - SetDCPenColor(hdc, kColor); - Polyline(hdc, points, 2); - } - } - } - - SelectObject(hdc, oldBitmap); - icon = PhNfBitmapToIcon(bitmap); - - // Text - - if (PhMaxCpuHistory.Count != 0) - maxCpuProcessId = UlongToHandle(PhGetItemCircularBuffer_ULONG(&PhMaxCpuHistory, 0)); - else - maxCpuProcessId = NULL; - - if (maxCpuProcessId) - { - if (maxCpuProcessItem = PhReferenceProcessItem(maxCpuProcessId)) - { - maxCpuText = PhFormatString( - L"\n%s: %.2f%%", - maxCpuProcessItem->ProcessName->Buffer, - maxCpuProcessItem->CpuUsage * 100 - ); - PhDereferenceObject(maxCpuProcessItem); - } - } - - text = PhFormatString(L"CPU usage: %.2f%%%s", (PhCpuKernelUsage + PhCpuUserUsage) * 100, PhGetStringOrEmpty(maxCpuText)); - if (maxCpuText) PhDereferenceObject(maxCpuText); - - PhNfpModifyNotifyIcon(PH_ICON_CPU_USAGE, NIF_TIP | NIF_ICON, text, icon); - - DestroyIcon(icon); - PhDereferenceObject(text); -} - -BOOLEAN PhNfpGetShowMiniInfoSectionData( - _In_ ULONG IconIndex, - _In_ PPH_NF_ICON RegisteredIcon, - _Out_ PPH_NF_MSG_SHOWMINIINFOSECTION_DATA Data - ) -{ - BOOLEAN showMiniInfo = FALSE; - - if (RegisteredIcon) - { - Data->SectionName = NULL; - - if (RegisteredIcon->Flags & PH_NF_ICON_SHOW_MINIINFO) - { - if (RegisteredIcon->MessageCallback) - { - RegisteredIcon->MessageCallback( - RegisteredIcon, - (ULONG_PTR)Data, - MAKELPARAM(PH_NF_MSG_SHOWMINIINFOSECTION, 0), - RegisteredIcon->Context - ); - } - - showMiniInfo = TRUE; - } - } - else - { - switch (1 << IconIndex) - { - case PH_ICON_CPU_HISTORY: - case PH_ICON_CPU_USAGE: - Data->SectionName = L"CPU"; - break; - case PH_ICON_IO_HISTORY: - Data->SectionName = L"I/O"; - break; - case PH_ICON_COMMIT_HISTORY: - Data->SectionName = L"Commit charge"; - break; - case PH_ICON_PHYSICAL_HISTORY: - Data->SectionName = L"Physical memory"; - break; - } - - showMiniInfo = TRUE; - } - - return showMiniInfo; -} - -VOID PhNfpIconClickActivateTimerProc( - _In_ HWND hwnd, - _In_ UINT uMsg, - _In_ UINT_PTR idEvent, - _In_ DWORD dwTime - ) -{ - PhPinMiniInformation(MiniInfoActivePinType, 1, 0, - PH_MINIINFO_ACTIVATE_WINDOW | PH_MINIINFO_DONT_CHANGE_SECTION_IF_PINNED, - IconClickShowMiniInfoSectionData.SectionName, &IconClickLocation); - KillTimer(PhMainWndHandle, TIMER_ICON_CLICK_ACTIVATE); -} - -VOID PhNfpDisableHover( - VOID - ) -{ - IconDisableHover = TRUE; - SetTimer(PhMainWndHandle, TIMER_ICON_RESTORE_HOVER, NFP_ICON_RESTORE_HOVER_DELAY, PhNfpIconRestoreHoverTimerProc); -} - -VOID PhNfpIconRestoreHoverTimerProc( - _In_ HWND hwnd, - _In_ UINT uMsg, - _In_ UINT_PTR idEvent, - _In_ DWORD dwTime - ) -{ - IconDisableHover = FALSE; - KillTimer(PhMainWndHandle, TIMER_ICON_RESTORE_HOVER); -} +/* + * Process Hacker - + * notification icon manager + * + * Copyright (C) 2011-2016 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +BOOLEAN PhNfTerminating = FALSE; +ULONG PhNfIconMask; +ULONG PhNfIconNotifyMask; +ULONG PhNfMaximumIconId = PH_ICON_DEFAULT_MAXIMUM; +PPH_NF_ICON PhNfRegisteredIcons[32] = { 0 }; +PPH_STRING PhNfIconTextCache[32] = { 0 }; +BOOLEAN PhNfMiniInfoEnabled; +BOOLEAN PhNfMiniInfoPinned; + +PH_NF_POINTERS PhNfpPointers; +PH_CALLBACK_REGISTRATION PhNfpProcessesUpdatedRegistration; +PH_NF_BITMAP PhNfpDefaultBitmapContext = { 0 }; +PH_NF_BITMAP PhNfpBlackBitmapContext = { 0 }; +HBITMAP PhNfpBlackBitmap = NULL; +HICON PhNfpBlackIcon = NULL; + +static POINT IconClickLocation; +static PH_NF_MSG_SHOWMINIINFOSECTION_DATA IconClickShowMiniInfoSectionData; +static BOOLEAN IconClickUpDueToDown; +static BOOLEAN IconDisableHover; + +VOID PhNfLoadStage1( + VOID + ) +{ + PPH_STRING iconList; + PH_STRINGREF part; + PH_STRINGREF remainingPart; + + PhNfpPointers.UpdateRegisteredIcon = PhNfpUpdateRegisteredIcon; + PhNfpPointers.BeginBitmap = PhNfpBeginBitmap; + + // Load settings for default icons. + PhNfIconMask = PhGetIntegerSetting(L"IconMask"); + + // Load settings for registered icons. + + iconList = PhGetStringSetting(L"IconMaskList"); + remainingPart = iconList->sr; + + while (remainingPart.Length != 0) + { + PhSplitStringRefAtChar(&remainingPart, '|', &part, &remainingPart); + + if (part.Length != 0) + { + PH_STRINGREF pluginName; + ULONG subId; + PPH_NF_ICON icon; + + if (PhEmParseCompoundId(&part, &pluginName, &subId) && + (icon = PhNfFindIcon(&pluginName, subId))) + { + PhNfIconMask |= icon->IconId; + } + } + } + + PhDereferenceObject(iconList); +} + +VOID PhNfLoadStage2( + VOID + ) +{ + ULONG i; + + PhNfMiniInfoEnabled = WindowsVersion >= WINDOWS_VISTA && !!PhGetIntegerSetting(L"MiniInfoWindowEnabled"); + + for (i = PH_ICON_MINIMUM; i != PhNfMaximumIconId; i <<= 1) + { + if (PhNfIconMask & i) + PhNfpAddNotifyIcon(i); + } + + PhRegisterCallback( + &PhProcessesUpdatedEvent, + PhNfpProcessesUpdatedHandler, + NULL, + &PhNfpProcessesUpdatedRegistration + ); +} + +VOID PhNfSaveSettings( + VOID + ) +{ + ULONG registeredIconMask; + + PhSetIntegerSetting(L"IconMask", PhNfIconMask & PH_ICON_DEFAULT_ALL); + + registeredIconMask = PhNfIconMask & ~PH_ICON_DEFAULT_ALL; + + if (registeredIconMask != 0) + { + PH_STRING_BUILDER iconListBuilder; + ULONG i; + + PhInitializeStringBuilder(&iconListBuilder, 60); + + for (i = 0; i < sizeof(PhNfRegisteredIcons) / sizeof(PPH_NF_ICON); i++) + { + if (PhNfRegisteredIcons[i]) + { + if (registeredIconMask & PhNfRegisteredIcons[i]->IconId) + { + PhAppendFormatStringBuilder( + &iconListBuilder, + L"+%s+%u|", + PhNfRegisteredIcons[i]->Plugin->Name.Buffer, + PhNfRegisteredIcons[i]->SubId + ); + } + } + } + + if (iconListBuilder.String->Length != 0) + PhRemoveEndStringBuilder(&iconListBuilder, 1); + + PhSetStringSetting2(L"IconMaskList", &iconListBuilder.String->sr); + PhDeleteStringBuilder(&iconListBuilder); + } + else + { + PhSetStringSetting(L"IconMaskList", L""); + } +} + +VOID PhNfUninitialization( + VOID + ) +{ + ULONG i; + + // Remove all icons to prevent them hanging around after we exit. + + PhNfTerminating = TRUE; // prevent further icon updating + + for (i = PH_ICON_MINIMUM; i != PhNfMaximumIconId; i <<= 1) + { + if (PhNfIconMask & i) + PhNfpRemoveNotifyIcon(i); + } +} + +VOID PhNfForwardMessage( + _In_ ULONG_PTR WParam, + _In_ ULONG_PTR LParam + ) +{ + ULONG iconIndex = HIWORD(LParam); + PPH_NF_ICON registeredIcon = NULL; + + if (iconIndex < sizeof(PhNfRegisteredIcons) / sizeof(PPH_NF_ICON) && PhNfRegisteredIcons[iconIndex]) + { + registeredIcon = PhNfRegisteredIcons[iconIndex]; + + if (registeredIcon->MessageCallback) + { + if (registeredIcon->MessageCallback( + registeredIcon, + WParam, + LParam, + registeredIcon->Context + )) + { + return; + } + } + } + + switch (LOWORD(LParam)) + { + case WM_LBUTTONDOWN: + { + if (PhGetIntegerSetting(L"IconSingleClick")) + { + ProcessHacker_IconClick(PhMainWndHandle); + PhNfpDisableHover(); + } + else + { + IconClickUpDueToDown = TRUE; + } + } + break; + case WM_LBUTTONUP: + { + if (!PhGetIntegerSetting(L"IconSingleClick") && PhNfMiniInfoEnabled && IconClickUpDueToDown) + { + PH_NF_MSG_SHOWMINIINFOSECTION_DATA showMiniInfoSectionData; + + if (PhNfpGetShowMiniInfoSectionData(iconIndex, registeredIcon, &showMiniInfoSectionData)) + { + GetCursorPos(&IconClickLocation); + + if (IconClickShowMiniInfoSectionData.SectionName) + { + PhFree(IconClickShowMiniInfoSectionData.SectionName); + IconClickShowMiniInfoSectionData.SectionName = NULL; + } + + if (showMiniInfoSectionData.SectionName) + { + IconClickShowMiniInfoSectionData.SectionName = PhDuplicateStringZ(showMiniInfoSectionData.SectionName); + } + + SetTimer(PhMainWndHandle, TIMER_ICON_CLICK_ACTIVATE, GetDoubleClickTime() + NFP_ICON_CLICK_ACTIVATE_DELAY, PhNfpIconClickActivateTimerProc); + } + else + { + KillTimer(PhMainWndHandle, TIMER_ICON_CLICK_ACTIVATE); + } + } + } + break; + case WM_LBUTTONDBLCLK: + { + if (!PhGetIntegerSetting(L"IconSingleClick")) + { + if (PhNfMiniInfoEnabled) + { + // We will get another WM_LBUTTONUP message corresponding to the double-click, + // and we need to make sure that it doesn't start the activation timer again. + KillTimer(PhMainWndHandle, TIMER_ICON_CLICK_ACTIVATE); + IconClickUpDueToDown = FALSE; + PhNfpDisableHover(); + } + + ProcessHacker_IconClick(PhMainWndHandle); + } + } + break; + case WM_RBUTTONUP: + case WM_CONTEXTMENU: + { + POINT location; + + if (!PhGetIntegerSetting(L"IconSingleClick") && PhNfMiniInfoEnabled) + KillTimer(PhMainWndHandle, TIMER_ICON_CLICK_ACTIVATE); + + PhPinMiniInformation(MiniInfoIconPinType, -1, 0, 0, NULL, NULL); + GetCursorPos(&location); + PhShowIconContextMenu(location); + } + break; + case NIN_KEYSELECT: + // HACK: explorer seems to send two NIN_KEYSELECT messages when the user selects the icon and presses ENTER. + if (GetForegroundWindow() != PhMainWndHandle) + ProcessHacker_IconClick(PhMainWndHandle); + break; + case NIN_BALLOONUSERCLICK: + PhShowDetailsForIconNotification(); + break; + case NIN_POPUPOPEN: + { + PH_NF_MSG_SHOWMINIINFOSECTION_DATA showMiniInfoSectionData; + POINT location; + + if (PhNfMiniInfoEnabled && !IconDisableHover && PhNfpGetShowMiniInfoSectionData(iconIndex, registeredIcon, &showMiniInfoSectionData)) + { + GetCursorPos(&location); + PhPinMiniInformation(MiniInfoIconPinType, 1, 0, PH_MINIINFO_DONT_CHANGE_SECTION_IF_PINNED, + showMiniInfoSectionData.SectionName, &location); + } + } + break; + case NIN_POPUPCLOSE: + PhPinMiniInformation(MiniInfoIconPinType, -1, 350, 0, NULL, NULL); + break; + } +} + +ULONG PhNfGetMaximumIconId( + VOID + ) +{ + return PhNfMaximumIconId; +} + +ULONG PhNfTestIconMask( + _In_ ULONG Id + ) +{ + return PhNfIconMask & Id; +} + +VOID PhNfSetVisibleIcon( + _In_ ULONG Id, + _In_ BOOLEAN Visible + ) +{ + if (Visible) + { + PhNfIconMask |= Id; + PhNfpAddNotifyIcon(Id); + } + else + { + PhNfIconMask &= ~Id; + PhNfpRemoveNotifyIcon(Id); + } +} + +BOOLEAN PhNfShowBalloonTip( + _In_opt_ ULONG Id, + _In_ PWSTR Title, + _In_ PWSTR Text, + _In_ ULONG Timeout, + _In_ ULONG Flags + ) +{ + NOTIFYICONDATA notifyIcon = { NOTIFYICONDATA_V3_SIZE }; + + if (Id == 0) + { + // Choose the first visible icon. + Id = PhNfIconMask; + } + + if (!_BitScanForward(&Id, Id)) + return FALSE; + + notifyIcon.hWnd = PhMainWndHandle; + notifyIcon.uID = Id; + notifyIcon.uFlags = NIF_INFO; + wcsncpy_s(notifyIcon.szInfoTitle, sizeof(notifyIcon.szInfoTitle) / sizeof(WCHAR), Title, _TRUNCATE); + wcsncpy_s(notifyIcon.szInfo, sizeof(notifyIcon.szInfo) / sizeof(WCHAR), Text, _TRUNCATE); + notifyIcon.uTimeout = Timeout; + notifyIcon.dwInfoFlags = Flags; + + Shell_NotifyIcon(NIM_MODIFY, ¬ifyIcon); + + return TRUE; +} + +HICON PhNfBitmapToIcon( + _In_ HBITMAP Bitmap + ) +{ + ICONINFO iconInfo; + + PhNfpGetBlackIcon(); + + iconInfo.fIcon = TRUE; + iconInfo.xHotspot = 0; + iconInfo.yHotspot = 0; + iconInfo.hbmMask = PhNfpBlackBitmap; + iconInfo.hbmColor = Bitmap; + + return CreateIconIndirect(&iconInfo); +} + +PPH_NF_ICON PhNfRegisterIcon( + _In_ struct _PH_PLUGIN *Plugin, + _In_ ULONG SubId, + _In_opt_ PVOID Context, + _In_ PWSTR Text, + _In_ ULONG Flags, + _In_opt_ PPH_NF_ICON_UPDATE_CALLBACK UpdateCallback, + _In_opt_ PPH_NF_ICON_MESSAGE_CALLBACK MessageCallback + ) +{ + PPH_NF_ICON icon; + ULONG iconId; + ULONG iconIndex; + + if (PhNfMaximumIconId == PH_ICON_LIMIT) + { + // No room for any more icons. + return NULL; + } + + iconId = PhNfMaximumIconId; + + if (!_BitScanReverse(&iconIndex, iconId) || + iconIndex >= sizeof(PhNfRegisteredIcons) / sizeof(PPH_NF_ICON)) + { + // Should never happen. + return NULL; + } + + PhNfMaximumIconId <<= 1; + + icon = PhAllocate(sizeof(PH_NF_ICON)); + icon->Plugin = Plugin; + icon->SubId = SubId; + icon->Context = Context; + icon->Pointers = &PhNfpPointers; + icon->Text = Text; + icon->Flags = Flags; + icon->IconId = iconId; + icon->UpdateCallback = UpdateCallback; + icon->MessageCallback = MessageCallback; + + PhNfRegisteredIcons[iconIndex] = icon; + + return icon; +} + +PPH_NF_ICON PhNfGetIconById( + _In_ ULONG Id + ) +{ + ULONG iconIndex; + + if (!_BitScanReverse(&iconIndex, Id)) + return NULL; + + return PhNfRegisteredIcons[iconIndex]; +} + +PPH_NF_ICON PhNfFindIcon( + _In_ PPH_STRINGREF PluginName, + _In_ ULONG SubId + ) +{ + ULONG i; + + for (i = 0; i < sizeof(PhNfRegisteredIcons) / sizeof(PPH_NF_ICON); i++) + { + if (PhNfRegisteredIcons[i]) + { + if (PhNfRegisteredIcons[i]->SubId == SubId && + PhEqualStringRef(PluginName, &PhNfRegisteredIcons[i]->Plugin->AppContext.AppName, FALSE)) + { + return PhNfRegisteredIcons[i]; + } + } + } + + return NULL; +} + +VOID PhNfNotifyMiniInfoPinned( + _In_ BOOLEAN Pinned + ) +{ + ULONG i; + ULONG id; + + if (PhNfMiniInfoPinned != Pinned) + { + PhNfMiniInfoPinned = Pinned; + + // Go through every icon and set/clear the NIF_SHOWTIP flag depending on whether the mini info window is + // pinned. If it's pinned then we want to show normal tooltips, because the section doesn't change + // automatically when the cursor hovers over an icon. + for (i = 0; i < sizeof(PhNfRegisteredIcons) / sizeof(PPH_NF_ICON); i++) + { + id = 1 << i; + + if (PhNfIconMask & id) + { + PhNfpModifyNotifyIcon(id, NIF_TIP, PhNfIconTextCache[i], NULL); + } + } + } +} + +HICON PhNfpGetBlackIcon( + VOID + ) +{ + if (!PhNfpBlackIcon) + { + ULONG width; + ULONG height; + PVOID bits; + HDC hdc; + HBITMAP oldBitmap; + ICONINFO iconInfo; + + PhNfpBeginBitmap2(&PhNfpBlackBitmapContext, &width, &height, &PhNfpBlackBitmap, &bits, &hdc, &oldBitmap); + memset(bits, 0, width * height * sizeof(ULONG)); + + iconInfo.fIcon = TRUE; + iconInfo.xHotspot = 0; + iconInfo.yHotspot = 0; + iconInfo.hbmMask = PhNfpBlackBitmap; + iconInfo.hbmColor = PhNfpBlackBitmap; + PhNfpBlackIcon = CreateIconIndirect(&iconInfo); + + SelectObject(hdc, oldBitmap); + } + + return PhNfpBlackIcon; +} + +BOOLEAN PhNfpAddNotifyIcon( + _In_ ULONG Id + ) +{ + NOTIFYICONDATA notifyIcon = { sizeof(NOTIFYICONDATA) }; + PPH_NF_ICON icon; + + if (PhNfTerminating) + return FALSE; + if ((icon = PhNfGetIconById(Id)) && (icon->Flags & PH_NF_ICON_UNAVAILABLE)) + return FALSE; + + // The IDs we pass to explorer are bit indicies, not the normal mask values. + + if (!_BitScanForward(&Id, Id)) + return FALSE; + + notifyIcon.hWnd = PhMainWndHandle; + notifyIcon.uID = Id; + notifyIcon.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP; + notifyIcon.uCallbackMessage = WM_PH_NOTIFY_ICON_MESSAGE; + wcsncpy_s( + notifyIcon.szTip, sizeof(notifyIcon.szTip) / sizeof(WCHAR), + PhGetStringOrDefault(PhNfIconTextCache[Id], PhApplicationName), + _TRUNCATE + ); + notifyIcon.hIcon = PhNfpGetBlackIcon(); + + if (!PhNfMiniInfoEnabled || PhNfMiniInfoPinned || (icon && !(icon->Flags & PH_NF_ICON_SHOW_MINIINFO))) + notifyIcon.uFlags |= NIF_SHOWTIP; + + Shell_NotifyIcon(NIM_ADD, ¬ifyIcon); + + if (WindowsVersion >= WINDOWS_VISTA) + { + notifyIcon.uVersion = NOTIFYICON_VERSION_4; + Shell_NotifyIcon(NIM_SETVERSION, ¬ifyIcon); + } + + return TRUE; +} + +BOOLEAN PhNfpRemoveNotifyIcon( + _In_ ULONG Id + ) +{ + NOTIFYICONDATA notifyIcon = { sizeof(NOTIFYICONDATA) }; + PPH_NF_ICON icon; + + if ((icon = PhNfGetIconById(Id)) && (icon->Flags & PH_NF_ICON_UNAVAILABLE)) + return FALSE; + + if (!_BitScanForward(&Id, Id)) + return FALSE; + + notifyIcon.hWnd = PhMainWndHandle; + notifyIcon.uID = Id; + + Shell_NotifyIcon(NIM_DELETE, ¬ifyIcon); + + return TRUE; +} + +BOOLEAN PhNfpModifyNotifyIcon( + _In_ ULONG Id, + _In_ ULONG Flags, + _In_opt_ PPH_STRING Text, + _In_opt_ HICON Icon + ) +{ + NOTIFYICONDATA notifyIcon = { sizeof(NOTIFYICONDATA) }; + PPH_NF_ICON icon; + ULONG notifyId; + + if (PhNfTerminating) + return FALSE; + if ((icon = PhNfGetIconById(Id)) && (icon->Flags & PH_NF_ICON_UNAVAILABLE)) + return FALSE; + + if (!_BitScanForward(¬ifyId, Id)) + return FALSE; + + notifyIcon.hWnd = PhMainWndHandle; + notifyIcon.uID = notifyId; + notifyIcon.uFlags = Flags; + + if (Flags & NIF_TIP) + { + PhSwapReference(&PhNfIconTextCache[notifyId], Text); + wcsncpy_s( + notifyIcon.szTip, + sizeof(notifyIcon.szTip) / sizeof(WCHAR), + PhGetStringOrDefault(Text, PhApplicationName), + _TRUNCATE + ); + } + + notifyIcon.hIcon = Icon; + + if (!PhNfMiniInfoEnabled || PhNfMiniInfoPinned || (icon && !(icon->Flags & PH_NF_ICON_SHOW_MINIINFO))) + notifyIcon.uFlags |= NIF_SHOWTIP; + + if (!Shell_NotifyIcon(NIM_MODIFY, ¬ifyIcon)) + { + // Explorer probably died and we lost our icon. Try to add the icon, and try again. + PhNfpAddNotifyIcon(Id); + Shell_NotifyIcon(NIM_MODIFY, ¬ifyIcon); + } + + return TRUE; +} + +VOID PhNfpProcessesUpdatedHandler( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + ULONG registeredIconMask; + + // We do icon updating on the provider thread so we don't block the main GUI when + // explorer is not responding. + + if (PhNfIconMask & PH_ICON_CPU_HISTORY) + PhNfpUpdateIconCpuHistory(); + if (PhNfIconMask & PH_ICON_IO_HISTORY) + PhNfpUpdateIconIoHistory(); + if (PhNfIconMask & PH_ICON_COMMIT_HISTORY) + PhNfpUpdateIconCommitHistory(); + if (PhNfIconMask & PH_ICON_PHYSICAL_HISTORY) + PhNfpUpdateIconPhysicalHistory(); + if (PhNfIconMask & PH_ICON_CPU_USAGE) + PhNfpUpdateIconCpuUsage(); + + registeredIconMask = PhNfIconMask & ~PH_ICON_DEFAULT_ALL; + + if (registeredIconMask != 0) + { + ULONG i; + + for (i = 0; i < sizeof(PhNfRegisteredIcons) / sizeof(PPH_NF_ICON); i++) + { + if (PhNfRegisteredIcons[i] && (registeredIconMask & PhNfRegisteredIcons[i]->IconId)) + { + PhNfpUpdateRegisteredIcon(PhNfRegisteredIcons[i]); + } + } + } +} + +VOID PhNfpUpdateRegisteredIcon( + _In_ PPH_NF_ICON Icon + ) +{ + PVOID newIconOrBitmap; + ULONG updateFlags; + PPH_STRING newText; + HICON newIcon; + ULONG flags; + + if (!Icon->UpdateCallback) + return; + + newIconOrBitmap = NULL; + newText = NULL; + newIcon = NULL; + flags = 0; + + Icon->UpdateCallback( + Icon, + &newIconOrBitmap, + &updateFlags, + &newText, + Icon->Context + ); + + if (newIconOrBitmap) + { + if (updateFlags & PH_NF_UPDATE_IS_BITMAP) + newIcon = PhNfBitmapToIcon(newIconOrBitmap); + else + newIcon = newIconOrBitmap; + + flags |= NIF_ICON; + } + + if (newText) + flags |= NIF_TIP; + + if (flags != 0) + PhNfpModifyNotifyIcon(Icon->IconId, flags, newText, newIcon); + + if (newIcon && (updateFlags & PH_NF_UPDATE_IS_BITMAP)) + DestroyIcon(newIcon); + + if (newIconOrBitmap && (updateFlags & PH_NF_UPDATE_DESTROY_RESOURCE)) + { + if (updateFlags & PH_NF_UPDATE_IS_BITMAP) + DeleteObject(newIconOrBitmap); + else + DestroyIcon(newIconOrBitmap); + } + + if (newText) + PhDereferenceObject(newText); +} + +VOID PhNfpBeginBitmap( + _Out_ PULONG Width, + _Out_ PULONG Height, + _Out_ HBITMAP *Bitmap, + _Out_opt_ PVOID *Bits, + _Out_ HDC *Hdc, + _Out_ HBITMAP *OldBitmap + ) +{ + PhNfpBeginBitmap2(&PhNfpDefaultBitmapContext, Width, Height, Bitmap, Bits, Hdc, OldBitmap); +} + +VOID PhNfpBeginBitmap2( + _Inout_ PPH_NF_BITMAP Context, + _Out_ PULONG Width, + _Out_ PULONG Height, + _Out_ HBITMAP *Bitmap, + _Out_opt_ PVOID *Bits, + _Out_ HDC *Hdc, + _Out_ HBITMAP *OldBitmap + ) +{ + if (!Context->Initialized) + { + HDC screenHdc; + + screenHdc = GetDC(NULL); + Context->Hdc = CreateCompatibleDC(screenHdc); + + memset(&Context->Header, 0, sizeof(BITMAPINFOHEADER)); + Context->Header.biSize = sizeof(BITMAPINFOHEADER); + Context->Header.biWidth = PhSmallIconSize.X; + Context->Header.biHeight = PhSmallIconSize.Y; + Context->Header.biPlanes = 1; + Context->Header.biBitCount = 32; + Context->Bitmap = CreateDIBSection(screenHdc, (BITMAPINFO *)&Context->Header, DIB_RGB_COLORS, &Context->Bits, NULL, 0); + + ReleaseDC(NULL, screenHdc); + + Context->Initialized = TRUE; + } + + *Width = PhSmallIconSize.X; + *Height = PhSmallIconSize.Y; + *Bitmap = Context->Bitmap; + if (Bits) *Bits = Context->Bits; + *Hdc = Context->Hdc; + *OldBitmap = SelectObject(Context->Hdc, Context->Bitmap); +} + +VOID PhNfpUpdateIconCpuHistory( + VOID + ) +{ + static PH_GRAPH_DRAW_INFO drawInfo = + { + 16, + 16, + PH_GRAPH_USE_LINE_2, + 2, + RGB(0x00, 0x00, 0x00), + + 16, + NULL, + NULL, + 0, + 0, + 0, + 0 + }; + ULONG maxDataCount; + ULONG lineDataCount; + PFLOAT lineData1; + PFLOAT lineData2; + HBITMAP bitmap; + PVOID bits; + HDC hdc; + HBITMAP oldBitmap; + HICON icon; + HANDLE maxCpuProcessId; + PPH_PROCESS_ITEM maxCpuProcessItem; + PH_FORMAT format[8]; + PPH_STRING text; + + // Icon + + PhNfpBeginBitmap(&drawInfo.Width, &drawInfo.Height, &bitmap, &bits, &hdc, &oldBitmap); + maxDataCount = drawInfo.Width / 2 + 1; + lineData1 = _alloca(maxDataCount * sizeof(FLOAT)); + lineData2 = _alloca(maxDataCount * sizeof(FLOAT)); + + lineDataCount = min(maxDataCount, PhCpuKernelHistory.Count); + PhCopyCircularBuffer_FLOAT(&PhCpuKernelHistory, lineData1, lineDataCount); + PhCopyCircularBuffer_FLOAT(&PhCpuUserHistory, lineData2, lineDataCount); + + drawInfo.LineDataCount = lineDataCount; + drawInfo.LineData1 = lineData1; + drawInfo.LineData2 = lineData2; + drawInfo.LineColor1 = PhCsColorCpuKernel; + drawInfo.LineColor2 = PhCsColorCpuUser; + drawInfo.LineBackColor1 = PhHalveColorBrightness(PhCsColorCpuKernel); + drawInfo.LineBackColor2 = PhHalveColorBrightness(PhCsColorCpuUser); + + if (bits) + PhDrawGraphDirect(hdc, bits, &drawInfo); + + SelectObject(hdc, oldBitmap); + icon = PhNfBitmapToIcon(bitmap); + + // Text + + if (PhMaxCpuHistory.Count != 0) + maxCpuProcessId = UlongToHandle(PhGetItemCircularBuffer_ULONG(&PhMaxCpuHistory, 0)); + else + maxCpuProcessId = NULL; + + if (maxCpuProcessId) + maxCpuProcessItem = PhReferenceProcessItem(maxCpuProcessId); + else + maxCpuProcessItem = NULL; + + PhInitFormatS(&format[0], L"CPU Usage: "); + PhInitFormatF(&format[1], (PhCpuKernelUsage + PhCpuUserUsage) * 100, 2); + PhInitFormatC(&format[2], '%'); + + if (maxCpuProcessItem) + { + PhInitFormatC(&format[3], '\n'); + PhInitFormatSR(&format[4], maxCpuProcessItem->ProcessName->sr); + PhInitFormatS(&format[5], L": "); + PhInitFormatF(&format[6], maxCpuProcessItem->CpuUsage * 100, 2); + PhInitFormatC(&format[7], '%'); + } + + text = PhFormat(format, maxCpuProcessItem ? 8 : 3, 128); + if (maxCpuProcessItem) PhDereferenceObject(maxCpuProcessItem); + + PhNfpModifyNotifyIcon(PH_ICON_CPU_HISTORY, NIF_TIP | NIF_ICON, text, icon); + + DestroyIcon(icon); + PhDereferenceObject(text); +} + +VOID PhNfpUpdateIconIoHistory( + VOID + ) +{ + static PH_GRAPH_DRAW_INFO drawInfo = + { + 16, + 16, + PH_GRAPH_USE_LINE_2, + 2, + RGB(0x00, 0x00, 0x00), + + 16, + NULL, + NULL, + 0, + 0, + 0, + 0 + }; + ULONG maxDataCount; + ULONG lineDataCount; + PFLOAT lineData1; + PFLOAT lineData2; + FLOAT max; + ULONG i; + HBITMAP bitmap; + PVOID bits; + HDC hdc; + HBITMAP oldBitmap; + HICON icon; + HANDLE maxIoProcessId; + PPH_PROCESS_ITEM maxIoProcessItem; + PH_FORMAT format[8]; + PPH_STRING text; + + // Icon + + PhNfpBeginBitmap(&drawInfo.Width, &drawInfo.Height, &bitmap, &bits, &hdc, &oldBitmap); + maxDataCount = drawInfo.Width / 2 + 1; + lineData1 = _alloca(maxDataCount * sizeof(FLOAT)); + lineData2 = _alloca(maxDataCount * sizeof(FLOAT)); + + lineDataCount = min(maxDataCount, PhIoReadHistory.Count); + max = 1024 * 1024; // minimum scaling of 1 MB. + + for (i = 0; i < lineDataCount; i++) + { + lineData1[i] = + (FLOAT)PhGetItemCircularBuffer_ULONG64(&PhIoReadHistory, i) + + (FLOAT)PhGetItemCircularBuffer_ULONG64(&PhIoOtherHistory, i); + lineData2[i] = + (FLOAT)PhGetItemCircularBuffer_ULONG64(&PhIoWriteHistory, i); + + if (max < lineData1[i] + lineData2[i]) + max = lineData1[i] + lineData2[i]; + } + + PhDivideSinglesBySingle(lineData1, max, lineDataCount); + PhDivideSinglesBySingle(lineData2, max, lineDataCount); + + drawInfo.LineDataCount = lineDataCount; + drawInfo.LineData1 = lineData1; + drawInfo.LineData2 = lineData2; + drawInfo.LineColor1 = PhCsColorIoReadOther; + drawInfo.LineColor2 = PhCsColorIoWrite; + drawInfo.LineBackColor1 = PhHalveColorBrightness(PhCsColorIoReadOther); + drawInfo.LineBackColor2 = PhHalveColorBrightness(PhCsColorIoWrite); + + if (bits) + PhDrawGraphDirect(hdc, bits, &drawInfo); + + SelectObject(hdc, oldBitmap); + icon = PhNfBitmapToIcon(bitmap); + + // Text + + if (PhMaxIoHistory.Count != 0) + maxIoProcessId = UlongToHandle(PhGetItemCircularBuffer_ULONG(&PhMaxIoHistory, 0)); + else + maxIoProcessId = NULL; + + if (maxIoProcessId) + maxIoProcessItem = PhReferenceProcessItem(maxIoProcessId); + else + maxIoProcessItem = NULL; + + PhInitFormatS(&format[0], L"I/O\nR: "); + PhInitFormatSize(&format[1], PhIoReadDelta.Delta); + PhInitFormatS(&format[2], L"\nW: "); + PhInitFormatSize(&format[3], PhIoWriteDelta.Delta); + PhInitFormatS(&format[4], L"\nO: "); + PhInitFormatSize(&format[5], PhIoOtherDelta.Delta); + + if (maxIoProcessItem) + { + PhInitFormatC(&format[6], '\n'); + PhInitFormatSR(&format[7], maxIoProcessItem->ProcessName->sr); + } + + text = PhFormat(format, maxIoProcessItem ? 8 : 6, 128); + if (maxIoProcessItem) PhDereferenceObject(maxIoProcessItem); + + PhNfpModifyNotifyIcon(PH_ICON_IO_HISTORY, NIF_TIP | NIF_ICON, text, icon); + + DestroyIcon(icon); + PhDereferenceObject(text); +} + +VOID PhNfpUpdateIconCommitHistory( + VOID + ) +{ + static PH_GRAPH_DRAW_INFO drawInfo = + { + 16, + 16, + 0, + 2, + RGB(0x00, 0x00, 0x00), + + 16, + NULL, + NULL, + 0, + 0, + 0, + 0 + }; + ULONG maxDataCount; + ULONG lineDataCount; + PFLOAT lineData1; + ULONG i; + HBITMAP bitmap; + PVOID bits; + HDC hdc; + HBITMAP oldBitmap; + HICON icon; + DOUBLE commitFraction; + PH_FORMAT format[5]; + PPH_STRING text; + + // Icon + + PhNfpBeginBitmap(&drawInfo.Width, &drawInfo.Height, &bitmap, &bits, &hdc, &oldBitmap); + maxDataCount = drawInfo.Width / 2 + 1; + lineData1 = _alloca(maxDataCount * sizeof(FLOAT)); + + lineDataCount = min(maxDataCount, PhCommitHistory.Count); + + for (i = 0; i < lineDataCount; i++) + lineData1[i] = (FLOAT)PhGetItemCircularBuffer_ULONG(&PhCommitHistory, i); + + PhDivideSinglesBySingle(lineData1, (FLOAT)PhPerfInformation.CommitLimit, lineDataCount); + + drawInfo.LineDataCount = lineDataCount; + drawInfo.LineData1 = lineData1; + drawInfo.LineColor1 = PhCsColorPrivate; + drawInfo.LineBackColor1 = PhHalveColorBrightness(PhCsColorPrivate); + + if (bits) + PhDrawGraphDirect(hdc, bits, &drawInfo); + + SelectObject(hdc, oldBitmap); + icon = PhNfBitmapToIcon(bitmap); + + // Text + + commitFraction = (DOUBLE)PhPerfInformation.CommittedPages / PhPerfInformation.CommitLimit; + + PhInitFormatS(&format[0], L"Commit: "); + PhInitFormatSize(&format[1], UInt32x32To64(PhPerfInformation.CommittedPages, PAGE_SIZE)); + PhInitFormatS(&format[2], L" ("); + PhInitFormatF(&format[3], commitFraction * 100, 2); + PhInitFormatS(&format[4], L"%)"); + + text = PhFormat(format, 5, 96); + + PhNfpModifyNotifyIcon(PH_ICON_COMMIT_HISTORY, NIF_TIP | NIF_ICON, text, icon); + + DestroyIcon(icon); + PhDereferenceObject(text); +} + +VOID PhNfpUpdateIconPhysicalHistory( + VOID + ) +{ + static PH_GRAPH_DRAW_INFO drawInfo = + { + 16, + 16, + 0, + 2, + RGB(0x00, 0x00, 0x00), + + 16, + NULL, + NULL, + 0, + 0, + 0, + 0 + }; + ULONG maxDataCount; + ULONG lineDataCount; + PFLOAT lineData1; + ULONG i; + HBITMAP bitmap; + PVOID bits; + HDC hdc; + HBITMAP oldBitmap; + HICON icon; + ULONG physicalUsage; + FLOAT physicalFraction; + PH_FORMAT format[5]; + PPH_STRING text; + + // Icon + + PhNfpBeginBitmap(&drawInfo.Width, &drawInfo.Height, &bitmap, &bits, &hdc, &oldBitmap); + maxDataCount = drawInfo.Width / 2 + 1; + lineData1 = _alloca(maxDataCount * sizeof(FLOAT)); + + lineDataCount = min(maxDataCount, PhCommitHistory.Count); + + for (i = 0; i < lineDataCount; i++) + lineData1[i] = (FLOAT)PhGetItemCircularBuffer_ULONG(&PhPhysicalHistory, i); + + PhDivideSinglesBySingle(lineData1, (FLOAT)PhSystemBasicInformation.NumberOfPhysicalPages, lineDataCount); + + drawInfo.LineDataCount = lineDataCount; + drawInfo.LineData1 = lineData1; + drawInfo.LineColor1 = PhCsColorPhysical; + drawInfo.LineBackColor1 = PhHalveColorBrightness(PhCsColorPhysical); + + if (bits) + PhDrawGraphDirect(hdc, bits, &drawInfo); + + SelectObject(hdc, oldBitmap); + icon = PhNfBitmapToIcon(bitmap); + + // Text + + physicalUsage = PhSystemBasicInformation.NumberOfPhysicalPages - PhPerfInformation.AvailablePages; + physicalFraction = (FLOAT)physicalUsage / PhSystemBasicInformation.NumberOfPhysicalPages; + + PhInitFormatS(&format[0], L"Physical memory: "); + PhInitFormatSize(&format[1], UInt32x32To64(physicalUsage, PAGE_SIZE)); + PhInitFormatS(&format[2], L" ("); + PhInitFormatF(&format[3], physicalFraction * 100, 2); + PhInitFormatS(&format[4], L"%)"); + + text = PhFormat(format, 5, 96); + + PhNfpModifyNotifyIcon(PH_ICON_PHYSICAL_HISTORY, NIF_TIP | NIF_ICON, text, icon); + + DestroyIcon(icon); + PhDereferenceObject(text); +} + +VOID PhNfpUpdateIconCpuUsage( + VOID + ) +{ + ULONG width; + ULONG height; + HBITMAP bitmap; + HDC hdc; + HBITMAP oldBitmap; + HICON icon; + HANDLE maxCpuProcessId; + PPH_PROCESS_ITEM maxCpuProcessItem; + PPH_STRING maxCpuText = NULL; + PPH_STRING text; + + // Icon + + PhNfpBeginBitmap(&width, &height, &bitmap, NULL, &hdc, &oldBitmap); + + // This stuff is copied from CpuUsageIcon.cs (PH 1.x). + { + COLORREF kColor = PhCsColorCpuKernel; + COLORREF uColor = PhCsColorCpuUser; + COLORREF kbColor = PhHalveColorBrightness(PhCsColorCpuKernel); + COLORREF ubColor = PhHalveColorBrightness(PhCsColorCpuUser); + FLOAT k = PhCpuKernelUsage; + FLOAT u = PhCpuUserUsage; + LONG kl = (LONG)(k * height); + LONG ul = (LONG)(u * height); + RECT rect; + HBRUSH dcBrush; + HBRUSH dcPen; + POINT points[2]; + + dcBrush = GetStockObject(DC_BRUSH); + dcPen = GetStockObject(DC_PEN); + rect.left = 0; + rect.top = 0; + rect.right = width; + rect.bottom = height; + SetDCBrushColor(hdc, RGB(0x00, 0x00, 0x00)); + FillRect(hdc, &rect, dcBrush); + + // Draw the base line. + if (kl + ul == 0) + { + SelectObject(hdc, dcPen); + SetDCPenColor(hdc, uColor); + points[0].x = 0; + points[0].y = height - 1; + points[1].x = width; + points[1].y = height - 1; + Polyline(hdc, points, 2); + } + else + { + rect.left = 0; + rect.top = height - ul - kl; + rect.right = width; + rect.bottom = height - kl; + SetDCBrushColor(hdc, ubColor); + FillRect(hdc, &rect, dcBrush); + + points[0].x = 0; + points[0].y = height - 1 - ul - kl; + if (points[0].y < 0) points[0].y = 0; + points[1].x = width; + points[1].y = points[0].y; + SelectObject(hdc, dcPen); + SetDCPenColor(hdc, uColor); + Polyline(hdc, points, 2); + + if (kl != 0) + { + rect.left = 0; + rect.top = height - kl; + rect.right = width; + rect.bottom = height; + SetDCBrushColor(hdc, kbColor); + FillRect(hdc, &rect, dcBrush); + + points[0].x = 0; + points[0].y = height - 1 - kl; + if (points[0].y < 0) points[0].y = 0; + points[1].x = width; + points[1].y = points[0].y; + SelectObject(hdc, dcPen); + SetDCPenColor(hdc, kColor); + Polyline(hdc, points, 2); + } + } + } + + SelectObject(hdc, oldBitmap); + icon = PhNfBitmapToIcon(bitmap); + + // Text + + if (PhMaxCpuHistory.Count != 0) + maxCpuProcessId = UlongToHandle(PhGetItemCircularBuffer_ULONG(&PhMaxCpuHistory, 0)); + else + maxCpuProcessId = NULL; + + if (maxCpuProcessId) + { + if (maxCpuProcessItem = PhReferenceProcessItem(maxCpuProcessId)) + { + maxCpuText = PhFormatString( + L"\n%s: %.2f%%", + maxCpuProcessItem->ProcessName->Buffer, + maxCpuProcessItem->CpuUsage * 100 + ); + PhDereferenceObject(maxCpuProcessItem); + } + } + + text = PhFormatString(L"CPU usage: %.2f%%%s", (PhCpuKernelUsage + PhCpuUserUsage) * 100, PhGetStringOrEmpty(maxCpuText)); + if (maxCpuText) PhDereferenceObject(maxCpuText); + + PhNfpModifyNotifyIcon(PH_ICON_CPU_USAGE, NIF_TIP | NIF_ICON, text, icon); + + DestroyIcon(icon); + PhDereferenceObject(text); +} + +BOOLEAN PhNfpGetShowMiniInfoSectionData( + _In_ ULONG IconIndex, + _In_ PPH_NF_ICON RegisteredIcon, + _Out_ PPH_NF_MSG_SHOWMINIINFOSECTION_DATA Data + ) +{ + BOOLEAN showMiniInfo = FALSE; + + if (RegisteredIcon) + { + Data->SectionName = NULL; + + if (RegisteredIcon->Flags & PH_NF_ICON_SHOW_MINIINFO) + { + if (RegisteredIcon->MessageCallback) + { + RegisteredIcon->MessageCallback( + RegisteredIcon, + (ULONG_PTR)Data, + MAKELPARAM(PH_NF_MSG_SHOWMINIINFOSECTION, 0), + RegisteredIcon->Context + ); + } + + showMiniInfo = TRUE; + } + } + else + { + switch (1 << IconIndex) + { + case PH_ICON_CPU_HISTORY: + case PH_ICON_CPU_USAGE: + Data->SectionName = L"CPU"; + break; + case PH_ICON_IO_HISTORY: + Data->SectionName = L"I/O"; + break; + case PH_ICON_COMMIT_HISTORY: + Data->SectionName = L"Commit charge"; + break; + case PH_ICON_PHYSICAL_HISTORY: + Data->SectionName = L"Physical memory"; + break; + } + + showMiniInfo = TRUE; + } + + return showMiniInfo; +} + +VOID PhNfpIconClickActivateTimerProc( + _In_ HWND hwnd, + _In_ UINT uMsg, + _In_ UINT_PTR idEvent, + _In_ DWORD dwTime + ) +{ + PhPinMiniInformation(MiniInfoActivePinType, 1, 0, + PH_MINIINFO_ACTIVATE_WINDOW | PH_MINIINFO_DONT_CHANGE_SECTION_IF_PINNED, + IconClickShowMiniInfoSectionData.SectionName, &IconClickLocation); + KillTimer(PhMainWndHandle, TIMER_ICON_CLICK_ACTIVATE); +} + +VOID PhNfpDisableHover( + VOID + ) +{ + IconDisableHover = TRUE; + SetTimer(PhMainWndHandle, TIMER_ICON_RESTORE_HOVER, NFP_ICON_RESTORE_HOVER_DELAY, PhNfpIconRestoreHoverTimerProc); +} + +VOID PhNfpIconRestoreHoverTimerProc( + _In_ HWND hwnd, + _In_ UINT uMsg, + _In_ UINT_PTR idEvent, + _In_ DWORD dwTime + ) +{ + IconDisableHover = FALSE; + KillTimer(PhMainWndHandle, TIMER_ICON_RESTORE_HOVER); +} diff --git a/ProcessHacker/ntobjprp.c b/ProcessHacker/ntobjprp.c index 344d607ca98a..3864cfc5fd41 100644 --- a/ProcessHacker/ntobjprp.c +++ b/ProcessHacker/ntobjprp.c @@ -1,757 +1,757 @@ -/* - * Process Hacker - - * properties for NT objects - * - * Copyright (C) 2010 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include - -#include - -#include - -typedef struct _COMMON_PAGE_CONTEXT -{ - PPH_OPEN_OBJECT OpenObject; - PVOID Context; -} COMMON_PAGE_CONTEXT, *PCOMMON_PAGE_CONTEXT; - -HPROPSHEETPAGE PhpCommonCreatePage( - _In_ PPH_OPEN_OBJECT OpenObject, - _In_opt_ PVOID Context, - _In_ PWSTR Template, - _In_ DLGPROC DlgProc - ); - -INT CALLBACK PhpCommonPropPageProc( - _In_ HWND hwnd, - _In_ UINT uMsg, - _In_ LPPROPSHEETPAGE ppsp - ); - -INT_PTR CALLBACK PhpEventPageProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -INT_PTR CALLBACK PhpEventPairPageProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -INT_PTR CALLBACK PhpMutantPageProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -INT_PTR CALLBACK PhpSectionPageProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -INT_PTR CALLBACK PhpSemaphorePageProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -INT_PTR CALLBACK PhpTimerPageProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -static HPROPSHEETPAGE PhpCommonCreatePage( - _In_ PPH_OPEN_OBJECT OpenObject, - _In_opt_ PVOID Context, - _In_ PWSTR Template, - _In_ DLGPROC DlgProc - ) -{ - HPROPSHEETPAGE propSheetPageHandle; - PROPSHEETPAGE propSheetPage; - PCOMMON_PAGE_CONTEXT pageContext; - - pageContext = PhCreateAlloc(sizeof(COMMON_PAGE_CONTEXT)); - memset(pageContext, 0, sizeof(COMMON_PAGE_CONTEXT)); - pageContext->OpenObject = OpenObject; - pageContext->Context = Context; - - memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); - propSheetPage.dwSize = sizeof(PROPSHEETPAGE); - propSheetPage.dwFlags = PSP_USECALLBACK; - propSheetPage.pszTemplate = Template; - propSheetPage.pfnDlgProc = DlgProc; - propSheetPage.lParam = (LPARAM)pageContext; - propSheetPage.pfnCallback = PhpCommonPropPageProc; - - propSheetPageHandle = CreatePropertySheetPage(&propSheetPage); - // CreatePropertySheetPage would have sent PSPCB_ADDREF (below), - // which would have added a reference. - PhDereferenceObject(pageContext); - - return propSheetPageHandle; -} - -INT CALLBACK PhpCommonPropPageProc( - _In_ HWND hwnd, - _In_ UINT uMsg, - _In_ LPPROPSHEETPAGE ppsp - ) -{ - PCOMMON_PAGE_CONTEXT pageContext; - - pageContext = (PCOMMON_PAGE_CONTEXT)ppsp->lParam; - - if (uMsg == PSPCB_ADDREF) - { - PhReferenceObject(pageContext); - } - else if (uMsg == PSPCB_RELEASE) - { - PhDereferenceObject(pageContext); - } - - return 1; -} - -FORCEINLINE PCOMMON_PAGE_CONTEXT PhpCommonPageHeader( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - return (PCOMMON_PAGE_CONTEXT)PhpGenericPropertyPageHeader( - hwndDlg, uMsg, wParam, lParam, L"PageContext"); -} - -HPROPSHEETPAGE PhCreateEventPage( - _In_ PPH_OPEN_OBJECT OpenObject, - _In_opt_ PVOID Context - ) -{ - return PhpCommonCreatePage( - OpenObject, - Context, - MAKEINTRESOURCE(IDD_OBJEVENT), - PhpEventPageProc - ); -} - -static VOID PhpRefreshEventPageInfo( - _In_ HWND hwndDlg, - _In_ PCOMMON_PAGE_CONTEXT PageContext - ) -{ - HANDLE eventHandle; - - if (NT_SUCCESS(PageContext->OpenObject( - &eventHandle, - EVENT_QUERY_STATE, - PageContext->Context - ))) - { - EVENT_BASIC_INFORMATION basicInfo; - PWSTR eventType = L"Unknown"; - PWSTR eventState = L"Unknown"; - - if (NT_SUCCESS(PhGetEventBasicInformation(eventHandle, &basicInfo))) - { - switch (basicInfo.EventType) - { - case NotificationEvent: - eventType = L"Notification"; - break; - case SynchronizationEvent: - eventType = L"Synchronization"; - break; - } - - eventState = basicInfo.EventState > 0 ? L"True" : L"False"; - } - - SetDlgItemText(hwndDlg, IDC_TYPE, eventType); - SetDlgItemText(hwndDlg, IDC_SIGNALED, eventState); - - NtClose(eventHandle); - } -} - -INT_PTR CALLBACK PhpEventPageProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - PCOMMON_PAGE_CONTEXT pageContext; - - pageContext = PhpCommonPageHeader(hwndDlg, uMsg, wParam, lParam); - - if (!pageContext) - return FALSE; - - switch (uMsg) - { - case WM_INITDIALOG: - { - PhpRefreshEventPageInfo(hwndDlg, pageContext); - } - break; - case WM_COMMAND: - { - switch (LOWORD(wParam)) - { - case IDC_SET: - case IDC_RESET: - case IDC_PULSE: - { - NTSTATUS status; - HANDLE eventHandle; - - if (NT_SUCCESS(status = pageContext->OpenObject( - &eventHandle, - EVENT_MODIFY_STATE, - pageContext->Context - ))) - { - switch (LOWORD(wParam)) - { - case IDC_SET: - NtSetEvent(eventHandle, NULL); - break; - case IDC_RESET: - NtResetEvent(eventHandle, NULL); - break; - case IDC_PULSE: - NtPulseEvent(eventHandle, NULL); - break; - } - - NtClose(eventHandle); - } - - PhpRefreshEventPageInfo(hwndDlg, pageContext); - - if (!NT_SUCCESS(status)) - PhShowStatus(hwndDlg, L"Unable to open the event", status, 0); - } - break; - } - } - break; - } - - return FALSE; -} - -HPROPSHEETPAGE PhCreateEventPairPage( - _In_ PPH_OPEN_OBJECT OpenObject, - _In_opt_ PVOID Context - ) -{ - return PhpCommonCreatePage( - OpenObject, - Context, - MAKEINTRESOURCE(IDD_OBJEVENTPAIR), - PhpEventPairPageProc - ); -} - -INT_PTR CALLBACK PhpEventPairPageProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - PCOMMON_PAGE_CONTEXT pageContext; - - pageContext = PhpCommonPageHeader(hwndDlg, uMsg, wParam, lParam); - - if (!pageContext) - return FALSE; - - switch (uMsg) - { - case WM_INITDIALOG: - { - // Nothing - } - break; - case WM_COMMAND: - { - switch (LOWORD(wParam)) - { - case IDC_SETLOW: - case IDC_SETHIGH: - { - NTSTATUS status; - HANDLE eventPairHandle; - - if (NT_SUCCESS(status = pageContext->OpenObject( - &eventPairHandle, - EVENT_PAIR_ALL_ACCESS, - pageContext->Context - ))) - { - switch (LOWORD(wParam)) - { - case IDC_SETLOW: - NtSetLowEventPair(eventPairHandle); - break; - case IDC_SETHIGH: - NtSetHighEventPair(eventPairHandle); - break; - } - - NtClose(eventPairHandle); - } - - if (!NT_SUCCESS(status)) - PhShowStatus(hwndDlg, L"Unable to open the event pair", status, 0); - } - break; - } - } - break; - } - - return FALSE; -} - -HPROPSHEETPAGE PhCreateMutantPage( - _In_ PPH_OPEN_OBJECT OpenObject, - _In_opt_ PVOID Context - ) -{ - return PhpCommonCreatePage( - OpenObject, - Context, - MAKEINTRESOURCE(IDD_OBJMUTANT), - PhpMutantPageProc - ); -} - -static VOID PhpRefreshMutantPageInfo( - _In_ HWND hwndDlg, - _In_ PCOMMON_PAGE_CONTEXT PageContext - ) -{ - HANDLE mutantHandle; - - if (NT_SUCCESS(PageContext->OpenObject( - &mutantHandle, - SEMAPHORE_QUERY_STATE, - PageContext->Context - ))) - { - MUTANT_BASIC_INFORMATION basicInfo; - MUTANT_OWNER_INFORMATION ownerInfo; - - if (NT_SUCCESS(PhGetMutantBasicInformation(mutantHandle, &basicInfo))) - { - SetDlgItemInt(hwndDlg, IDC_COUNT, basicInfo.CurrentCount, TRUE); - SetDlgItemText(hwndDlg, IDC_ABANDONED, basicInfo.AbandonedState ? L"True" : L"False"); - } - else - { - SetDlgItemText(hwndDlg, IDC_COUNT, L"Unknown"); - SetDlgItemText(hwndDlg, IDC_ABANDONED, L"Unknown"); - } - - if ( - WindowsVersion >= WINDOWS_VISTA && - NT_SUCCESS(PhGetMutantOwnerInformation(mutantHandle, &ownerInfo)) - ) - { - PPH_STRING name; - - if (ownerInfo.ClientId.UniqueProcess != NULL) - { - name = PhGetClientIdName(&ownerInfo.ClientId); - SetDlgItemText(hwndDlg, IDC_OWNER, name->Buffer); - PhDereferenceObject(name); - } - else - { - SetDlgItemText(hwndDlg, IDC_OWNER, L"N/A"); - } - } - else - { - SetDlgItemText(hwndDlg, IDC_OWNER, L"Unknown"); - } - - NtClose(mutantHandle); - } -} - -INT_PTR CALLBACK PhpMutantPageProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - PCOMMON_PAGE_CONTEXT pageContext; - - pageContext = PhpCommonPageHeader(hwndDlg, uMsg, wParam, lParam); - - if (!pageContext) - return FALSE; - - switch (uMsg) - { - case WM_INITDIALOG: - { - if (WindowsVersion < WINDOWS_VISTA) - { - EnableWindow(GetDlgItem(hwndDlg, IDC_OWNERLABEL), FALSE); - EnableWindow(GetDlgItem(hwndDlg, IDC_OWNER), FALSE); - } - - PhpRefreshMutantPageInfo(hwndDlg, pageContext); - } - break; - } - - return FALSE; -} - -HPROPSHEETPAGE PhCreateSectionPage( - _In_ PPH_OPEN_OBJECT OpenObject, - _In_opt_ PVOID Context - ) -{ - return PhpCommonCreatePage( - OpenObject, - Context, - MAKEINTRESOURCE(IDD_OBJSECTION), - PhpSectionPageProc - ); -} - -static VOID PhpRefreshSectionPageInfo( - _In_ HWND hwndDlg, - _In_ PCOMMON_PAGE_CONTEXT PageContext - ) -{ - HANDLE sectionHandle; - SECTION_BASIC_INFORMATION basicInfo; - PWSTR sectionType = L"Unknown"; - PPH_STRING sectionSize = NULL; - PPH_STRING fileName = NULL; - - if (!NT_SUCCESS(PageContext->OpenObject( - §ionHandle, - SECTION_QUERY | SECTION_MAP_READ, - PageContext->Context - ))) - { - if (!NT_SUCCESS(PageContext->OpenObject( - §ionHandle, - SECTION_QUERY | SECTION_MAP_READ, - PageContext->Context - ))) - { - return; - } - } - - if (NT_SUCCESS(PhGetSectionBasicInformation(sectionHandle, &basicInfo))) - { - if (basicInfo.AllocationAttributes & SEC_COMMIT) - sectionType = L"Commit"; - else if (basicInfo.AllocationAttributes & SEC_FILE) - sectionType = L"File"; - else if (basicInfo.AllocationAttributes & SEC_IMAGE) - sectionType = L"Image"; - else if (basicInfo.AllocationAttributes & SEC_RESERVE) - sectionType = L"Reserve"; - - sectionSize = PhaFormatSize(basicInfo.MaximumSize.QuadPart, -1); - } - - if (NT_SUCCESS(PhGetSectionFileName(sectionHandle, &fileName))) - { - PPH_STRING newFileName; - - PH_AUTO(fileName); - - if (newFileName = PhResolveDevicePrefix(fileName)) - fileName = PH_AUTO(newFileName); - } - - SetDlgItemText(hwndDlg, IDC_TYPE, sectionType); - SetDlgItemText(hwndDlg, IDC_SIZE_, PhGetStringOrDefault(sectionSize, L"Unknown")); - SetDlgItemText(hwndDlg, IDC_FILE, PhGetStringOrDefault(fileName, L"N/A")); - - NtClose(sectionHandle); -} - -INT_PTR CALLBACK PhpSectionPageProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - PCOMMON_PAGE_CONTEXT pageContext; - - pageContext = PhpCommonPageHeader(hwndDlg, uMsg, wParam, lParam); - - if (!pageContext) - return FALSE; - - switch (uMsg) - { - case WM_INITDIALOG: - { - PhpRefreshSectionPageInfo(hwndDlg, pageContext); - } - break; - } - - return FALSE; -} - -HPROPSHEETPAGE PhCreateSemaphorePage( - _In_ PPH_OPEN_OBJECT OpenObject, - _In_opt_ PVOID Context - ) -{ - return PhpCommonCreatePage( - OpenObject, - Context, - MAKEINTRESOURCE(IDD_OBJSEMAPHORE), - PhpSemaphorePageProc - ); -} - -static VOID PhpRefreshSemaphorePageInfo( - _In_ HWND hwndDlg, - _In_ PCOMMON_PAGE_CONTEXT PageContext - ) -{ - HANDLE semaphoreHandle; - - if (NT_SUCCESS(PageContext->OpenObject( - &semaphoreHandle, - SEMAPHORE_QUERY_STATE, - PageContext->Context - ))) - { - SEMAPHORE_BASIC_INFORMATION basicInfo; - - if (NT_SUCCESS(PhGetSemaphoreBasicInformation(semaphoreHandle, &basicInfo))) - { - SetDlgItemInt(hwndDlg, IDC_CURRENTCOUNT, basicInfo.CurrentCount, TRUE); - SetDlgItemInt(hwndDlg, IDC_MAXIMUMCOUNT, basicInfo.MaximumCount, TRUE); - } - else - { - SetDlgItemText(hwndDlg, IDC_CURRENTCOUNT, L"Unknown"); - SetDlgItemText(hwndDlg, IDC_MAXIMUMCOUNT, L"Unknown"); - } - - NtClose(semaphoreHandle); - } -} - -INT_PTR CALLBACK PhpSemaphorePageProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - PCOMMON_PAGE_CONTEXT pageContext; - - pageContext = PhpCommonPageHeader(hwndDlg, uMsg, wParam, lParam); - - if (!pageContext) - return FALSE; - - switch (uMsg) - { - case WM_INITDIALOG: - { - PhpRefreshSemaphorePageInfo(hwndDlg, pageContext); - } - break; - case WM_COMMAND: - { - switch (LOWORD(wParam)) - { - case IDC_ACQUIRE: - case IDC_RELEASE: - { - NTSTATUS status; - HANDLE semaphoreHandle; - - if (NT_SUCCESS(status = pageContext->OpenObject( - &semaphoreHandle, - LOWORD(wParam) == IDC_ACQUIRE ? SYNCHRONIZE : SEMAPHORE_MODIFY_STATE, - pageContext->Context - ))) - { - switch (LOWORD(wParam)) - { - case IDC_ACQUIRE: - { - LARGE_INTEGER timeout; - - timeout.QuadPart = 0; - NtWaitForSingleObject(semaphoreHandle, FALSE, &timeout); - } - break; - case IDC_RELEASE: - NtReleaseSemaphore(semaphoreHandle, 1, NULL); - break; - } - - NtClose(semaphoreHandle); - } - - PhpRefreshSemaphorePageInfo(hwndDlg, pageContext); - - if (!NT_SUCCESS(status)) - PhShowStatus(hwndDlg, L"Unable to open the semaphore", status, 0); - } - break; - } - } - break; - } - - return FALSE; -} - -HPROPSHEETPAGE PhCreateTimerPage( - _In_ PPH_OPEN_OBJECT OpenObject, - _In_opt_ PVOID Context - ) -{ - return PhpCommonCreatePage( - OpenObject, - Context, - MAKEINTRESOURCE(IDD_OBJTIMER), - PhpTimerPageProc - ); -} - -static VOID PhpRefreshTimerPageInfo( - _In_ HWND hwndDlg, - _In_ PCOMMON_PAGE_CONTEXT PageContext - ) -{ - HANDLE timerHandle; - - if (NT_SUCCESS(PageContext->OpenObject( - &timerHandle, - TIMER_QUERY_STATE, - PageContext->Context - ))) - { - TIMER_BASIC_INFORMATION basicInfo; - - if (NT_SUCCESS(PhGetTimerBasicInformation(timerHandle, &basicInfo))) - { - SetDlgItemText(hwndDlg, IDC_SIGNALED, basicInfo.TimerState ? L"True" : L"False"); - } - else - { - SetDlgItemText(hwndDlg, IDC_SIGNALED, L"Unknown"); - } - - NtClose(timerHandle); - } -} - -INT_PTR CALLBACK PhpTimerPageProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - PCOMMON_PAGE_CONTEXT pageContext; - - pageContext = PhpCommonPageHeader(hwndDlg, uMsg, wParam, lParam); - - if (!pageContext) - return FALSE; - - switch (uMsg) - { - case WM_INITDIALOG: - { - PhpRefreshTimerPageInfo(hwndDlg, pageContext); - } - break; - case WM_COMMAND: - { - switch (LOWORD(wParam)) - { - case IDC_CANCEL: - { - NTSTATUS status; - HANDLE timerHandle; - - if (NT_SUCCESS(status = pageContext->OpenObject( - &timerHandle, - TIMER_MODIFY_STATE, - pageContext->Context - ))) - { - switch (LOWORD(wParam)) - { - case IDC_CANCEL: - NtCancelTimer(timerHandle, NULL); - break; - } - - NtClose(timerHandle); - } - - PhpRefreshTimerPageInfo(hwndDlg, pageContext); - - if (!NT_SUCCESS(status)) - PhShowStatus(hwndDlg, L"Unable to open the timer", status, 0); - } - break; - } - } - break; - } - - return FALSE; -} +/* + * Process Hacker - + * properties for NT objects + * + * Copyright (C) 2010 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include + +#include + +#include + +typedef struct _COMMON_PAGE_CONTEXT +{ + PPH_OPEN_OBJECT OpenObject; + PVOID Context; +} COMMON_PAGE_CONTEXT, *PCOMMON_PAGE_CONTEXT; + +HPROPSHEETPAGE PhpCommonCreatePage( + _In_ PPH_OPEN_OBJECT OpenObject, + _In_opt_ PVOID Context, + _In_ PWSTR Template, + _In_ DLGPROC DlgProc + ); + +INT CALLBACK PhpCommonPropPageProc( + _In_ HWND hwnd, + _In_ UINT uMsg, + _In_ LPPROPSHEETPAGE ppsp + ); + +INT_PTR CALLBACK PhpEventPageProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +INT_PTR CALLBACK PhpEventPairPageProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +INT_PTR CALLBACK PhpMutantPageProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +INT_PTR CALLBACK PhpSectionPageProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +INT_PTR CALLBACK PhpSemaphorePageProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +INT_PTR CALLBACK PhpTimerPageProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +static HPROPSHEETPAGE PhpCommonCreatePage( + _In_ PPH_OPEN_OBJECT OpenObject, + _In_opt_ PVOID Context, + _In_ PWSTR Template, + _In_ DLGPROC DlgProc + ) +{ + HPROPSHEETPAGE propSheetPageHandle; + PROPSHEETPAGE propSheetPage; + PCOMMON_PAGE_CONTEXT pageContext; + + pageContext = PhCreateAlloc(sizeof(COMMON_PAGE_CONTEXT)); + memset(pageContext, 0, sizeof(COMMON_PAGE_CONTEXT)); + pageContext->OpenObject = OpenObject; + pageContext->Context = Context; + + memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); + propSheetPage.dwSize = sizeof(PROPSHEETPAGE); + propSheetPage.dwFlags = PSP_USECALLBACK; + propSheetPage.pszTemplate = Template; + propSheetPage.pfnDlgProc = DlgProc; + propSheetPage.lParam = (LPARAM)pageContext; + propSheetPage.pfnCallback = PhpCommonPropPageProc; + + propSheetPageHandle = CreatePropertySheetPage(&propSheetPage); + // CreatePropertySheetPage would have sent PSPCB_ADDREF (below), + // which would have added a reference. + PhDereferenceObject(pageContext); + + return propSheetPageHandle; +} + +INT CALLBACK PhpCommonPropPageProc( + _In_ HWND hwnd, + _In_ UINT uMsg, + _In_ LPPROPSHEETPAGE ppsp + ) +{ + PCOMMON_PAGE_CONTEXT pageContext; + + pageContext = (PCOMMON_PAGE_CONTEXT)ppsp->lParam; + + if (uMsg == PSPCB_ADDREF) + { + PhReferenceObject(pageContext); + } + else if (uMsg == PSPCB_RELEASE) + { + PhDereferenceObject(pageContext); + } + + return 1; +} + +FORCEINLINE PCOMMON_PAGE_CONTEXT PhpCommonPageHeader( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + return (PCOMMON_PAGE_CONTEXT)PhpGenericPropertyPageHeader( + hwndDlg, uMsg, wParam, lParam, L"PageContext"); +} + +HPROPSHEETPAGE PhCreateEventPage( + _In_ PPH_OPEN_OBJECT OpenObject, + _In_opt_ PVOID Context + ) +{ + return PhpCommonCreatePage( + OpenObject, + Context, + MAKEINTRESOURCE(IDD_OBJEVENT), + PhpEventPageProc + ); +} + +static VOID PhpRefreshEventPageInfo( + _In_ HWND hwndDlg, + _In_ PCOMMON_PAGE_CONTEXT PageContext + ) +{ + HANDLE eventHandle; + + if (NT_SUCCESS(PageContext->OpenObject( + &eventHandle, + EVENT_QUERY_STATE, + PageContext->Context + ))) + { + EVENT_BASIC_INFORMATION basicInfo; + PWSTR eventType = L"Unknown"; + PWSTR eventState = L"Unknown"; + + if (NT_SUCCESS(PhGetEventBasicInformation(eventHandle, &basicInfo))) + { + switch (basicInfo.EventType) + { + case NotificationEvent: + eventType = L"Notification"; + break; + case SynchronizationEvent: + eventType = L"Synchronization"; + break; + } + + eventState = basicInfo.EventState > 0 ? L"True" : L"False"; + } + + SetDlgItemText(hwndDlg, IDC_TYPE, eventType); + SetDlgItemText(hwndDlg, IDC_SIGNALED, eventState); + + NtClose(eventHandle); + } +} + +INT_PTR CALLBACK PhpEventPageProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + PCOMMON_PAGE_CONTEXT pageContext; + + pageContext = PhpCommonPageHeader(hwndDlg, uMsg, wParam, lParam); + + if (!pageContext) + return FALSE; + + switch (uMsg) + { + case WM_INITDIALOG: + { + PhpRefreshEventPageInfo(hwndDlg, pageContext); + } + break; + case WM_COMMAND: + { + switch (LOWORD(wParam)) + { + case IDC_SET: + case IDC_RESET: + case IDC_PULSE: + { + NTSTATUS status; + HANDLE eventHandle; + + if (NT_SUCCESS(status = pageContext->OpenObject( + &eventHandle, + EVENT_MODIFY_STATE, + pageContext->Context + ))) + { + switch (LOWORD(wParam)) + { + case IDC_SET: + NtSetEvent(eventHandle, NULL); + break; + case IDC_RESET: + NtResetEvent(eventHandle, NULL); + break; + case IDC_PULSE: + NtPulseEvent(eventHandle, NULL); + break; + } + + NtClose(eventHandle); + } + + PhpRefreshEventPageInfo(hwndDlg, pageContext); + + if (!NT_SUCCESS(status)) + PhShowStatus(hwndDlg, L"Unable to open the event", status, 0); + } + break; + } + } + break; + } + + return FALSE; +} + +HPROPSHEETPAGE PhCreateEventPairPage( + _In_ PPH_OPEN_OBJECT OpenObject, + _In_opt_ PVOID Context + ) +{ + return PhpCommonCreatePage( + OpenObject, + Context, + MAKEINTRESOURCE(IDD_OBJEVENTPAIR), + PhpEventPairPageProc + ); +} + +INT_PTR CALLBACK PhpEventPairPageProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + PCOMMON_PAGE_CONTEXT pageContext; + + pageContext = PhpCommonPageHeader(hwndDlg, uMsg, wParam, lParam); + + if (!pageContext) + return FALSE; + + switch (uMsg) + { + case WM_INITDIALOG: + { + // Nothing + } + break; + case WM_COMMAND: + { + switch (LOWORD(wParam)) + { + case IDC_SETLOW: + case IDC_SETHIGH: + { + NTSTATUS status; + HANDLE eventPairHandle; + + if (NT_SUCCESS(status = pageContext->OpenObject( + &eventPairHandle, + EVENT_PAIR_ALL_ACCESS, + pageContext->Context + ))) + { + switch (LOWORD(wParam)) + { + case IDC_SETLOW: + NtSetLowEventPair(eventPairHandle); + break; + case IDC_SETHIGH: + NtSetHighEventPair(eventPairHandle); + break; + } + + NtClose(eventPairHandle); + } + + if (!NT_SUCCESS(status)) + PhShowStatus(hwndDlg, L"Unable to open the event pair", status, 0); + } + break; + } + } + break; + } + + return FALSE; +} + +HPROPSHEETPAGE PhCreateMutantPage( + _In_ PPH_OPEN_OBJECT OpenObject, + _In_opt_ PVOID Context + ) +{ + return PhpCommonCreatePage( + OpenObject, + Context, + MAKEINTRESOURCE(IDD_OBJMUTANT), + PhpMutantPageProc + ); +} + +static VOID PhpRefreshMutantPageInfo( + _In_ HWND hwndDlg, + _In_ PCOMMON_PAGE_CONTEXT PageContext + ) +{ + HANDLE mutantHandle; + + if (NT_SUCCESS(PageContext->OpenObject( + &mutantHandle, + SEMAPHORE_QUERY_STATE, + PageContext->Context + ))) + { + MUTANT_BASIC_INFORMATION basicInfo; + MUTANT_OWNER_INFORMATION ownerInfo; + + if (NT_SUCCESS(PhGetMutantBasicInformation(mutantHandle, &basicInfo))) + { + SetDlgItemInt(hwndDlg, IDC_COUNT, basicInfo.CurrentCount, TRUE); + SetDlgItemText(hwndDlg, IDC_ABANDONED, basicInfo.AbandonedState ? L"True" : L"False"); + } + else + { + SetDlgItemText(hwndDlg, IDC_COUNT, L"Unknown"); + SetDlgItemText(hwndDlg, IDC_ABANDONED, L"Unknown"); + } + + if ( + WindowsVersion >= WINDOWS_VISTA && + NT_SUCCESS(PhGetMutantOwnerInformation(mutantHandle, &ownerInfo)) + ) + { + PPH_STRING name; + + if (ownerInfo.ClientId.UniqueProcess != NULL) + { + name = PhGetClientIdName(&ownerInfo.ClientId); + SetDlgItemText(hwndDlg, IDC_OWNER, name->Buffer); + PhDereferenceObject(name); + } + else + { + SetDlgItemText(hwndDlg, IDC_OWNER, L"N/A"); + } + } + else + { + SetDlgItemText(hwndDlg, IDC_OWNER, L"Unknown"); + } + + NtClose(mutantHandle); + } +} + +INT_PTR CALLBACK PhpMutantPageProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + PCOMMON_PAGE_CONTEXT pageContext; + + pageContext = PhpCommonPageHeader(hwndDlg, uMsg, wParam, lParam); + + if (!pageContext) + return FALSE; + + switch (uMsg) + { + case WM_INITDIALOG: + { + if (WindowsVersion < WINDOWS_VISTA) + { + EnableWindow(GetDlgItem(hwndDlg, IDC_OWNERLABEL), FALSE); + EnableWindow(GetDlgItem(hwndDlg, IDC_OWNER), FALSE); + } + + PhpRefreshMutantPageInfo(hwndDlg, pageContext); + } + break; + } + + return FALSE; +} + +HPROPSHEETPAGE PhCreateSectionPage( + _In_ PPH_OPEN_OBJECT OpenObject, + _In_opt_ PVOID Context + ) +{ + return PhpCommonCreatePage( + OpenObject, + Context, + MAKEINTRESOURCE(IDD_OBJSECTION), + PhpSectionPageProc + ); +} + +static VOID PhpRefreshSectionPageInfo( + _In_ HWND hwndDlg, + _In_ PCOMMON_PAGE_CONTEXT PageContext + ) +{ + HANDLE sectionHandle; + SECTION_BASIC_INFORMATION basicInfo; + PWSTR sectionType = L"Unknown"; + PPH_STRING sectionSize = NULL; + PPH_STRING fileName = NULL; + + if (!NT_SUCCESS(PageContext->OpenObject( + §ionHandle, + SECTION_QUERY | SECTION_MAP_READ, + PageContext->Context + ))) + { + if (!NT_SUCCESS(PageContext->OpenObject( + §ionHandle, + SECTION_QUERY | SECTION_MAP_READ, + PageContext->Context + ))) + { + return; + } + } + + if (NT_SUCCESS(PhGetSectionBasicInformation(sectionHandle, &basicInfo))) + { + if (basicInfo.AllocationAttributes & SEC_COMMIT) + sectionType = L"Commit"; + else if (basicInfo.AllocationAttributes & SEC_FILE) + sectionType = L"File"; + else if (basicInfo.AllocationAttributes & SEC_IMAGE) + sectionType = L"Image"; + else if (basicInfo.AllocationAttributes & SEC_RESERVE) + sectionType = L"Reserve"; + + sectionSize = PhaFormatSize(basicInfo.MaximumSize.QuadPart, -1); + } + + if (NT_SUCCESS(PhGetSectionFileName(sectionHandle, &fileName))) + { + PPH_STRING newFileName; + + PH_AUTO(fileName); + + if (newFileName = PhResolveDevicePrefix(fileName)) + fileName = PH_AUTO(newFileName); + } + + SetDlgItemText(hwndDlg, IDC_TYPE, sectionType); + SetDlgItemText(hwndDlg, IDC_SIZE_, PhGetStringOrDefault(sectionSize, L"Unknown")); + SetDlgItemText(hwndDlg, IDC_FILE, PhGetStringOrDefault(fileName, L"N/A")); + + NtClose(sectionHandle); +} + +INT_PTR CALLBACK PhpSectionPageProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + PCOMMON_PAGE_CONTEXT pageContext; + + pageContext = PhpCommonPageHeader(hwndDlg, uMsg, wParam, lParam); + + if (!pageContext) + return FALSE; + + switch (uMsg) + { + case WM_INITDIALOG: + { + PhpRefreshSectionPageInfo(hwndDlg, pageContext); + } + break; + } + + return FALSE; +} + +HPROPSHEETPAGE PhCreateSemaphorePage( + _In_ PPH_OPEN_OBJECT OpenObject, + _In_opt_ PVOID Context + ) +{ + return PhpCommonCreatePage( + OpenObject, + Context, + MAKEINTRESOURCE(IDD_OBJSEMAPHORE), + PhpSemaphorePageProc + ); +} + +static VOID PhpRefreshSemaphorePageInfo( + _In_ HWND hwndDlg, + _In_ PCOMMON_PAGE_CONTEXT PageContext + ) +{ + HANDLE semaphoreHandle; + + if (NT_SUCCESS(PageContext->OpenObject( + &semaphoreHandle, + SEMAPHORE_QUERY_STATE, + PageContext->Context + ))) + { + SEMAPHORE_BASIC_INFORMATION basicInfo; + + if (NT_SUCCESS(PhGetSemaphoreBasicInformation(semaphoreHandle, &basicInfo))) + { + SetDlgItemInt(hwndDlg, IDC_CURRENTCOUNT, basicInfo.CurrentCount, TRUE); + SetDlgItemInt(hwndDlg, IDC_MAXIMUMCOUNT, basicInfo.MaximumCount, TRUE); + } + else + { + SetDlgItemText(hwndDlg, IDC_CURRENTCOUNT, L"Unknown"); + SetDlgItemText(hwndDlg, IDC_MAXIMUMCOUNT, L"Unknown"); + } + + NtClose(semaphoreHandle); + } +} + +INT_PTR CALLBACK PhpSemaphorePageProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + PCOMMON_PAGE_CONTEXT pageContext; + + pageContext = PhpCommonPageHeader(hwndDlg, uMsg, wParam, lParam); + + if (!pageContext) + return FALSE; + + switch (uMsg) + { + case WM_INITDIALOG: + { + PhpRefreshSemaphorePageInfo(hwndDlg, pageContext); + } + break; + case WM_COMMAND: + { + switch (LOWORD(wParam)) + { + case IDC_ACQUIRE: + case IDC_RELEASE: + { + NTSTATUS status; + HANDLE semaphoreHandle; + + if (NT_SUCCESS(status = pageContext->OpenObject( + &semaphoreHandle, + LOWORD(wParam) == IDC_ACQUIRE ? SYNCHRONIZE : SEMAPHORE_MODIFY_STATE, + pageContext->Context + ))) + { + switch (LOWORD(wParam)) + { + case IDC_ACQUIRE: + { + LARGE_INTEGER timeout; + + timeout.QuadPart = 0; + NtWaitForSingleObject(semaphoreHandle, FALSE, &timeout); + } + break; + case IDC_RELEASE: + NtReleaseSemaphore(semaphoreHandle, 1, NULL); + break; + } + + NtClose(semaphoreHandle); + } + + PhpRefreshSemaphorePageInfo(hwndDlg, pageContext); + + if (!NT_SUCCESS(status)) + PhShowStatus(hwndDlg, L"Unable to open the semaphore", status, 0); + } + break; + } + } + break; + } + + return FALSE; +} + +HPROPSHEETPAGE PhCreateTimerPage( + _In_ PPH_OPEN_OBJECT OpenObject, + _In_opt_ PVOID Context + ) +{ + return PhpCommonCreatePage( + OpenObject, + Context, + MAKEINTRESOURCE(IDD_OBJTIMER), + PhpTimerPageProc + ); +} + +static VOID PhpRefreshTimerPageInfo( + _In_ HWND hwndDlg, + _In_ PCOMMON_PAGE_CONTEXT PageContext + ) +{ + HANDLE timerHandle; + + if (NT_SUCCESS(PageContext->OpenObject( + &timerHandle, + TIMER_QUERY_STATE, + PageContext->Context + ))) + { + TIMER_BASIC_INFORMATION basicInfo; + + if (NT_SUCCESS(PhGetTimerBasicInformation(timerHandle, &basicInfo))) + { + SetDlgItemText(hwndDlg, IDC_SIGNALED, basicInfo.TimerState ? L"True" : L"False"); + } + else + { + SetDlgItemText(hwndDlg, IDC_SIGNALED, L"Unknown"); + } + + NtClose(timerHandle); + } +} + +INT_PTR CALLBACK PhpTimerPageProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + PCOMMON_PAGE_CONTEXT pageContext; + + pageContext = PhpCommonPageHeader(hwndDlg, uMsg, wParam, lParam); + + if (!pageContext) + return FALSE; + + switch (uMsg) + { + case WM_INITDIALOG: + { + PhpRefreshTimerPageInfo(hwndDlg, pageContext); + } + break; + case WM_COMMAND: + { + switch (LOWORD(wParam)) + { + case IDC_CANCEL: + { + NTSTATUS status; + HANDLE timerHandle; + + if (NT_SUCCESS(status = pageContext->OpenObject( + &timerHandle, + TIMER_MODIFY_STATE, + pageContext->Context + ))) + { + switch (LOWORD(wParam)) + { + case IDC_CANCEL: + NtCancelTimer(timerHandle, NULL); + break; + } + + NtClose(timerHandle); + } + + PhpRefreshTimerPageInfo(hwndDlg, pageContext); + + if (!NT_SUCCESS(status)) + PhShowStatus(hwndDlg, L"Unable to open the timer", status, 0); + } + break; + } + } + break; + } + + return FALSE; +} diff --git a/ProcessHacker/options.c b/ProcessHacker/options.c index 8651a210c01e..32782a527ce9 100644 --- a/ProcessHacker/options.c +++ b/ProcessHacker/options.c @@ -1,1265 +1,1265 @@ -/* - * Process Hacker - - * options window - * - * Copyright (C) 2010-2016 wj32 - * Copyright (C) 2017 dmex - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include - -#include -#include - -#include - -#include -#include -#include -#include - -#define WM_PH_CHILD_EXIT (WM_APP + 301) - -INT CALLBACK PhpOptionsPropSheetProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ LPARAM lParam - ); - -LRESULT CALLBACK PhpOptionsWndProc( - _In_ HWND hwnd, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam, - _In_ UINT_PTR uIdSubclass, - _In_ ULONG_PTR dwRefData - ); - -INT_PTR CALLBACK PhpOptionsGeneralDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -INT_PTR CALLBACK PhpOptionsAdvancedDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -INT_PTR CALLBACK PhpOptionsSymbolsDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -INT_PTR CALLBACK PhpOptionsHighlightingDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -INT_PTR CALLBACK PhpOptionsGraphsDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -// All -static BOOLEAN PageInit; -static BOOLEAN PressedOk; -static BOOLEAN RestartRequired; -static POINT StartLocation; - -// General -static PH_STRINGREF CurrentUserRunKeyName = PH_STRINGREF_INIT(L"Software\\Microsoft\\Windows\\CurrentVersion\\Run"); -static BOOLEAN CurrentUserRunPresent; -static BOOLEAN CurrentUserRunStartHidden; -static HFONT CurrentFontInstance; -static PPH_STRING NewFontSelection; - -// Advanced -static PH_STRINGREF TaskMgrImageOptionsKeyName = PH_STRINGREF_INIT(L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\taskmgr.exe"); -static PPH_STRING OldTaskMgrDebugger; -static BOOLEAN OldReplaceTaskMgr; -static HWND WindowHandleForElevate; - -// Highlighting -static HWND HighlightingListViewHandle; - -VOID PhShowOptionsDialog( - _In_ HWND ParentWindowHandle - ) -{ - PROPSHEETHEADER propSheetHeader = { sizeof(propSheetHeader) }; - PROPSHEETPAGE propSheetPage; - HPROPSHEETPAGE pages[5]; - - propSheetHeader.dwFlags = - PSH_NOAPPLYNOW | - PSH_NOCONTEXTHELP | - PSH_USECALLBACK | - PSH_USEPSTARTPAGE; - propSheetHeader.hwndParent = ParentWindowHandle; - propSheetHeader.pszCaption = L"Options"; - propSheetHeader.nPages = 0; - propSheetHeader.pStartPage = !PhStartupParameters.ShowOptions ? L"General" : L"Advanced"; - propSheetHeader.phpage = pages; - propSheetHeader.pfnCallback = PhpOptionsPropSheetProc; - - if (!PhStartupParameters.ShowOptions) - { - // Disable all pages other than Advanced. - // General page - memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); - propSheetPage.dwSize = sizeof(PROPSHEETPAGE); - propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_OPTGENERAL); - propSheetPage.pfnDlgProc = PhpOptionsGeneralDlgProc; - pages[propSheetHeader.nPages++] = CreatePropertySheetPage(&propSheetPage); - } - - // Advanced page - memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); - propSheetPage.dwSize = sizeof(PROPSHEETPAGE); - propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_OPTADVANCED); - propSheetPage.pfnDlgProc = PhpOptionsAdvancedDlgProc; - pages[propSheetHeader.nPages++] = CreatePropertySheetPage(&propSheetPage); - - if (!PhStartupParameters.ShowOptions) - { - // Symbols page - memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); - propSheetPage.dwSize = sizeof(PROPSHEETPAGE); - propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_OPTSYMBOLS); - propSheetPage.pfnDlgProc = PhpOptionsSymbolsDlgProc; - pages[propSheetHeader.nPages++] = CreatePropertySheetPage(&propSheetPage); - } - - if (!PhStartupParameters.ShowOptions) - { - // Highlighting page - memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); - propSheetPage.dwSize = sizeof(PROPSHEETPAGE); - propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_OPTHIGHLIGHTING); - propSheetPage.pfnDlgProc = PhpOptionsHighlightingDlgProc; - pages[propSheetHeader.nPages++] = CreatePropertySheetPage(&propSheetPage); - } - - if (!PhStartupParameters.ShowOptions) - { - // Graphs page - memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); - propSheetPage.dwSize = sizeof(PROPSHEETPAGE); - propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_OPTGRAPHS); - propSheetPage.pfnDlgProc = PhpOptionsGraphsDlgProc; - pages[propSheetHeader.nPages++] = CreatePropertySheetPage(&propSheetPage); - } - - PageInit = FALSE; - PressedOk = FALSE; - RestartRequired = FALSE; - - if (PhStartupParameters.ShowOptions) - StartLocation = PhStartupParameters.Point; - else - StartLocation.x = MINLONG; - - OldTaskMgrDebugger = NULL; - - PhModalPropertySheet(&propSheetHeader); - - if (PressedOk) - { - if (!PhStartupParameters.ShowOptions) - { - PhUpdateCachedSettings(); - ProcessHacker_SaveAllSettings(PhMainWndHandle); - PhInvalidateAllProcessNodes(); - PhReloadSettingsProcessTreeList(); - PhSiNotifyChangeSettings(); - - if (RestartRequired) - { - if (PhShowMessage( - PhMainWndHandle, - MB_ICONQUESTION | MB_YESNO, - L"One or more options you have changed requires a restart of Process Hacker. " - L"Do you want to restart Process Hacker now?" - ) == IDYES) - { - ProcessHacker_PrepareForEarlyShutdown(PhMainWndHandle); - PhShellProcessHacker( - PhMainWndHandle, - L"-v", - SW_SHOW, - 0, - PH_SHELL_APP_PROPAGATE_PARAMETERS | PH_SHELL_APP_PROPAGATE_PARAMETERS_IGNORE_VISIBILITY, - 0, - NULL - ); - ProcessHacker_Destroy(PhMainWndHandle); - } - } - } - else - { - // Main window not available. - if (PhSettingsFileName) - PhSaveSettings(PhSettingsFileName->Buffer); - } - } -} - -INT CALLBACK PhpOptionsPropSheetProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ LPARAM lParam - ) -{ - switch (uMsg) - { - case PSCB_BUTTONPRESSED: - { - if (lParam == PSBTN_OK) - { - PressedOk = TRUE; - } - } - break; - } - - return 0; -} - -static VOID PhpPageInit( - _In_ HWND hwndDlg - ) -{ - if (!PageInit) - { - HWND optionsWindow; - HWND resetButton; - RECT clientRect; - RECT rect; - - optionsWindow = GetParent(hwndDlg); - SetWindowSubclass(optionsWindow, PhpOptionsWndProc, 0, 0); - - // Create the Reset button. - GetClientRect(optionsWindow, &clientRect); - GetWindowRect(GetDlgItem(optionsWindow, IDCANCEL), &rect); - MapWindowPoints(NULL, optionsWindow, (POINT *)&rect, 2); - resetButton = CreateWindowEx( - WS_EX_NOPARENTNOTIFY, - L"BUTTON", - L"Reset", - WS_CHILD | WS_VISIBLE | WS_TABSTOP, - clientRect.right - rect.right, - rect.top, - rect.right - rect.left, - rect.bottom - rect.top, - optionsWindow, - (HMENU)IDC_RESET, - PhInstanceHandle, - NULL - ); - SendMessage(resetButton, WM_SETFONT, SendMessage(GetDlgItem(optionsWindow, IDCANCEL), WM_GETFONT, 0, 0), TRUE); - - if (PhStartupParameters.ShowOptions) - ShowWindow(resetButton, SW_HIDE); - - // Set the location of the options window. - if (StartLocation.x == MINLONG) - { - PhCenterWindow(optionsWindow, GetParent(optionsWindow)); - } - else - { - SetWindowPos(optionsWindow, NULL, StartLocation.x, StartLocation.y, 0, 0, - SWP_NOACTIVATE | SWP_NOREDRAW | SWP_NOSIZE | SWP_NOZORDER); - } - - PageInit = TRUE; - } -} - -LRESULT CALLBACK PhpOptionsWndProc( - _In_ HWND hwnd, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam, - _In_ UINT_PTR uIdSubclass, - _In_ ULONG_PTR dwRefData - ) -{ - switch (uMsg) - { - case WM_DESTROY: - RemoveWindowSubclass(hwnd, PhpOptionsWndProc, uIdSubclass); - break; - case WM_COMMAND: - { - switch (LOWORD(wParam)) - { - case IDC_RESET: - { - if (PhShowMessage( - hwnd, - MB_ICONWARNING | MB_YESNO | MB_DEFBUTTON2, - L"Do you want to reset all settings and restart Process Hacker?" - ) == IDYES) - { - ProcessHacker_PrepareForEarlyShutdown(PhMainWndHandle); - - PhResetSettings(); - - if (PhSettingsFileName) - PhSaveSettings(PhSettingsFileName->Buffer); - - PhShellProcessHacker( - PhMainWndHandle, - L"-v", - SW_SHOW, - 0, - PH_SHELL_APP_PROPAGATE_PARAMETERS | PH_SHELL_APP_PROPAGATE_PARAMETERS_IGNORE_VISIBILITY, - 0, - NULL - ); - ProcessHacker_Destroy(PhMainWndHandle); - } - } - break; - } - } - break; - } - - return DefSubclassProc(hwnd, uMsg, wParam, lParam); -} - -#define SetDlgItemCheckForSetting(hwndDlg, Id, Name) \ - Button_SetCheck(GetDlgItem(hwndDlg, Id), PhGetIntegerSetting(Name) ? BST_CHECKED : BST_UNCHECKED) -#define SetSettingForDlgItemCheck(hwndDlg, Id, Name) \ - PhSetIntegerSetting(Name, Button_GetCheck(GetDlgItem(hwndDlg, Id)) == BST_CHECKED) -#define SetSettingForDlgItemCheckRestartRequired(hwndDlg, Id, Name) \ - do { \ - BOOLEAN __oldValue = !!PhGetIntegerSetting(Name); \ - BOOLEAN __newValue = Button_GetCheck(GetDlgItem(hwndDlg, Id)) == BST_CHECKED; \ - if (__newValue != __oldValue) \ - RestartRequired = TRUE; \ - PhSetIntegerSetting(Name, __newValue); \ - } while (0) -#define DialogChanged PropSheet_Changed(GetParent(hwndDlg), hwndDlg) - -static BOOLEAN GetCurrentFont( - _Out_ PLOGFONT Font - ) -{ - BOOLEAN result; - PPH_STRING fontHexString; - - if (NewFontSelection) - fontHexString = NewFontSelection; - else - fontHexString = PhaGetStringSetting(L"Font"); - - if (fontHexString->Length / 2 / 2 == sizeof(LOGFONT)) - result = PhHexStringToBuffer(&fontHexString->sr, (PUCHAR)Font); - else - result = FALSE; - - return result; -} - -static VOID ReadCurrentUserRun( - VOID - ) -{ - HANDLE keyHandle; - PPH_STRING value; - - CurrentUserRunPresent = FALSE; - CurrentUserRunStartHidden = FALSE; - - if (NT_SUCCESS(PhOpenKey( - &keyHandle, - KEY_READ, - PH_KEY_CURRENT_USER, - &CurrentUserRunKeyName, - 0 - ))) - { - if (value = PhQueryRegistryString(keyHandle, L"Process Hacker")) - { - PH_STRINGREF fileName; - PH_STRINGREF arguments; - PPH_STRING fullFileName; - - PH_AUTO(value); - - if (PhParseCommandLineFuzzy(&value->sr, &fileName, &arguments, &fullFileName)) - { - PH_AUTO(fullFileName); - - if (fullFileName && PhEqualString(fullFileName, PhApplicationFileName, TRUE)) - { - CurrentUserRunPresent = TRUE; - CurrentUserRunStartHidden = PhEqualStringRef2(&arguments, L"-hide", FALSE); - } - } - } - - NtClose(keyHandle); - } -} - -static VOID WriteCurrentUserRun( - _In_ BOOLEAN Present, - _In_ BOOLEAN StartHidden - ) -{ - HANDLE keyHandle; - - if (CurrentUserRunPresent == Present && (!Present || CurrentUserRunStartHidden == StartHidden)) - return; - - if (NT_SUCCESS(PhOpenKey( - &keyHandle, - KEY_WRITE, - PH_KEY_CURRENT_USER, - &CurrentUserRunKeyName, - 0 - ))) - { - UNICODE_STRING valueName; - - RtlInitUnicodeString(&valueName, L"Process Hacker"); - - if (Present) - { - PPH_STRING value; - - value = PH_AUTO(PhConcatStrings(3, L"\"", PhApplicationFileName->Buffer, L"\"")); - - if (StartHidden) - value = PhaConcatStrings2(value->Buffer, L" -hide"); - - NtSetValueKey(keyHandle, &valueName, 0, REG_SZ, value->Buffer, (ULONG)value->Length + 2); - } - else - { - NtDeleteValueKey(keyHandle, &valueName); - } - - NtClose(keyHandle); - } -} - - -INT_PTR CALLBACK PhpOptionsGeneralDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - switch (uMsg) - { - case WM_INITDIALOG: - { - HWND comboBoxHandle; - ULONG i; - LOGFONT font; - - PhpPageInit(hwndDlg); - - comboBoxHandle = GetDlgItem(hwndDlg, IDC_MAXSIZEUNIT); - - for (i = 0; i < sizeof(PhSizeUnitNames) / sizeof(PWSTR); i++) - ComboBox_AddString(comboBoxHandle, PhSizeUnitNames[i]); - - SetDlgItemText(hwndDlg, IDC_SEARCHENGINE, PhaGetStringSetting(L"SearchEngine")->Buffer); - SetDlgItemText(hwndDlg, IDC_PEVIEWER, PhaGetStringSetting(L"ProgramInspectExecutables")->Buffer); - - if (PhMaxSizeUnit != -1) - ComboBox_SetCurSel(comboBoxHandle, PhMaxSizeUnit); - else - ComboBox_SetCurSel(comboBoxHandle, sizeof(PhSizeUnitNames) / sizeof(PWSTR) - 1); - - SetDlgItemInt(hwndDlg, IDC_ICONPROCESSES, PhGetIntegerSetting(L"IconProcesses"), FALSE); - - SetDlgItemCheckForSetting(hwndDlg, IDC_ALLOWONLYONEINSTANCE, L"AllowOnlyOneInstance"); - SetDlgItemCheckForSetting(hwndDlg, IDC_HIDEONCLOSE, L"HideOnClose"); - SetDlgItemCheckForSetting(hwndDlg, IDC_HIDEONMINIMIZE, L"HideOnMinimize"); - SetDlgItemCheckForSetting(hwndDlg, IDC_COLLAPSESERVICES, L"CollapseServicesOnStart"); - SetDlgItemCheckForSetting(hwndDlg, IDC_ICONSINGLECLICK, L"IconSingleClick"); - SetDlgItemCheckForSetting(hwndDlg, IDC_ICONTOGGLESVISIBILITY, L"IconTogglesVisibility"); - SetDlgItemCheckForSetting(hwndDlg, IDC_ENABLEPLUGINS, L"EnablePlugins"); - - ReadCurrentUserRun(); - - if (CurrentUserRunPresent) - { - Button_SetCheck(GetDlgItem(hwndDlg, IDC_STARTATLOGON), BST_CHECKED); - - if (CurrentUserRunStartHidden) - Button_SetCheck(GetDlgItem(hwndDlg, IDC_STARTHIDDEN), BST_CHECKED); - } - else - { - EnableWindow(GetDlgItem(hwndDlg, IDC_STARTHIDDEN), FALSE); - } - - // Set the font of the button for a nice preview. - if (GetCurrentFont(&font)) - { - CurrentFontInstance = CreateFontIndirect(&font); - - if (CurrentFontInstance) - SendMessage(GetDlgItem(hwndDlg, IDC_FONT), WM_SETFONT, (WPARAM)CurrentFontInstance, TRUE); - } - } - break; - case WM_DESTROY: - { - if (CurrentFontInstance) - DeleteObject(CurrentFontInstance); - - PhClearReference(&NewFontSelection); - } - break; - case WM_COMMAND: - { - switch (LOWORD(wParam)) - { - case IDC_STARTATLOGON: - { - EnableWindow(GetDlgItem(hwndDlg, IDC_STARTHIDDEN), Button_GetCheck(GetDlgItem(hwndDlg, IDC_STARTATLOGON)) == BST_CHECKED); - } - break; - case IDC_FONT: - { - LOGFONT font; - CHOOSEFONT chooseFont; - - if (!GetCurrentFont(&font)) - { - // Can't get LOGFONT from the existing setting, probably - // because the user hasn't ever chosen a font before. - // Set the font to something familiar. - GetObject((HFONT)SendMessage(PhMainWndHandle, WM_PH_GET_FONT, 0, 0), sizeof(LOGFONT), &font); - } - - memset(&chooseFont, 0, sizeof(CHOOSEFONT)); - chooseFont.lStructSize = sizeof(CHOOSEFONT); - chooseFont.hwndOwner = hwndDlg; - chooseFont.lpLogFont = &font; - chooseFont.Flags = CF_FORCEFONTEXIST | CF_INITTOLOGFONTSTRUCT | CF_SCREENFONTS; - - if (ChooseFont(&chooseFont)) - { - PhMoveReference(&NewFontSelection, PhBufferToHexString((PUCHAR)&font, sizeof(LOGFONT))); - - // Update the button's font. - - if (CurrentFontInstance) - DeleteObject(CurrentFontInstance); - - CurrentFontInstance = CreateFontIndirect(&font); - SendMessage(GetDlgItem(hwndDlg, IDC_FONT), WM_SETFONT, (WPARAM)CurrentFontInstance, TRUE); - } - } - break; - } - } - break; - case WM_NOTIFY: - { - LPNMHDR header = (LPNMHDR)lParam; - - switch (header->code) - { - case PSN_APPLY: - { - BOOLEAN startAtLogon; - BOOLEAN startHidden; - - PhSetStringSetting2(L"SearchEngine", &(PhaGetDlgItemText(hwndDlg, IDC_SEARCHENGINE)->sr)); - PhSetStringSetting2(L"ProgramInspectExecutables", &(PhaGetDlgItemText(hwndDlg, IDC_PEVIEWER)->sr)); - PhSetIntegerSetting(L"MaxSizeUnit", PhMaxSizeUnit = ComboBox_GetCurSel(GetDlgItem(hwndDlg, IDC_MAXSIZEUNIT))); - PhSetIntegerSetting(L"IconProcesses", GetDlgItemInt(hwndDlg, IDC_ICONPROCESSES, NULL, FALSE)); - SetSettingForDlgItemCheck(hwndDlg, IDC_ALLOWONLYONEINSTANCE, L"AllowOnlyOneInstance"); - SetSettingForDlgItemCheck(hwndDlg, IDC_HIDEONCLOSE, L"HideOnClose"); - SetSettingForDlgItemCheck(hwndDlg, IDC_HIDEONMINIMIZE, L"HideOnMinimize"); - SetSettingForDlgItemCheck(hwndDlg, IDC_COLLAPSESERVICES, L"CollapseServicesOnStart"); - SetSettingForDlgItemCheck(hwndDlg, IDC_ICONSINGLECLICK, L"IconSingleClick"); - SetSettingForDlgItemCheck(hwndDlg, IDC_ICONTOGGLESVISIBILITY, L"IconTogglesVisibility"); - SetSettingForDlgItemCheckRestartRequired(hwndDlg, IDC_ENABLEPLUGINS, L"EnablePlugins"); - - startAtLogon = Button_GetCheck(GetDlgItem(hwndDlg, IDC_STARTATLOGON)) == BST_CHECKED; - startHidden = Button_GetCheck(GetDlgItem(hwndDlg, IDC_STARTHIDDEN)) == BST_CHECKED; - WriteCurrentUserRun(startAtLogon, startHidden); - - if (NewFontSelection) - { - PhSetStringSetting2(L"Font", &NewFontSelection->sr); - PostMessage(PhMainWndHandle, WM_PH_UPDATE_FONT, 0, 0); - } - - SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_NOERROR); - } - return TRUE; - } - } - break; - } - - return FALSE; -} - -static BOOLEAN PathMatchesPh( - _In_ PPH_STRING Path - ) -{ - BOOLEAN match = FALSE; - - if (PhEqualString(OldTaskMgrDebugger, PhApplicationFileName, TRUE)) - { - match = TRUE; - } - // Allow for a quoted value. - else if ( - OldTaskMgrDebugger->Length == PhApplicationFileName->Length + sizeof(WCHAR) * 2 && - OldTaskMgrDebugger->Buffer[0] == '"' && - OldTaskMgrDebugger->Buffer[OldTaskMgrDebugger->Length / sizeof(WCHAR) - 1] == '"' - ) - { - PH_STRINGREF partInside; - - partInside.Buffer = &OldTaskMgrDebugger->Buffer[1]; - partInside.Length = OldTaskMgrDebugger->Length - sizeof(WCHAR) * 2; - - if (PhEqualStringRef(&partInside, &PhApplicationFileName->sr, TRUE)) - match = TRUE; - } - - return match; -} - -VOID PhpAdvancedPageLoad( - _In_ HWND hwndDlg - ) -{ - HWND changeButton; - - SetDlgItemCheckForSetting(hwndDlg, IDC_ENABLEWARNINGS, L"EnableWarnings"); - SetDlgItemCheckForSetting(hwndDlg, IDC_ENABLEKERNELMODEDRIVER, L"EnableKph"); - SetDlgItemCheckForSetting(hwndDlg, IDC_HIDEUNNAMEDHANDLES, L"HideUnnamedHandles"); - SetDlgItemCheckForSetting(hwndDlg, IDC_ENABLESTAGE2, L"EnableStage2"); - SetDlgItemCheckForSetting(hwndDlg, IDC_ENABLENETWORKRESOLVE, L"EnableNetworkResolve"); - SetDlgItemCheckForSetting(hwndDlg, IDC_PROPAGATECPUUSAGE, L"PropagateCpuUsage"); - SetDlgItemCheckForSetting(hwndDlg, IDC_ENABLEINSTANTTOOLTIPS, L"EnableInstantTooltips"); - - if (WindowsVersion >= WINDOWS_7) - SetDlgItemCheckForSetting(hwndDlg, IDC_ENABLECYCLECPUUSAGE, L"EnableCycleCpuUsage"); - - SetDlgItemInt(hwndDlg, IDC_SAMPLECOUNT, PhGetIntegerSetting(L"SampleCount"), FALSE); - SetDlgItemCheckForSetting(hwndDlg, IDC_SAMPLECOUNTAUTOMATIC, L"SampleCountAutomatic"); - - if (PhGetIntegerSetting(L"SampleCountAutomatic")) - EnableWindow(GetDlgItem(hwndDlg, IDC_SAMPLECOUNT), FALSE); - - // Replace Task Manager - - changeButton = GetDlgItem(hwndDlg, IDC_CHANGE); - - if (PhGetOwnTokenAttributes().Elevated) - { - ShowWindow(changeButton, SW_HIDE); - } - else - { - SendMessage(changeButton, BCM_SETSHIELD, 0, TRUE); - } - - { - HANDLE taskmgrKeyHandle = NULL; - ULONG disposition; - BOOLEAN success = FALSE; - BOOLEAN alreadyReplaced = FALSE; - - // See if we can write to the key. - if (NT_SUCCESS(PhCreateKey( - &taskmgrKeyHandle, - KEY_READ | KEY_WRITE, - PH_KEY_LOCAL_MACHINE, - &TaskMgrImageOptionsKeyName, - 0, - 0, - &disposition - ))) - { - success = TRUE; - } - - if (taskmgrKeyHandle || NT_SUCCESS(PhOpenKey( - &taskmgrKeyHandle, - KEY_READ, - PH_KEY_LOCAL_MACHINE, - &TaskMgrImageOptionsKeyName, - 0 - ))) - { - PhClearReference(&OldTaskMgrDebugger); - - if (OldTaskMgrDebugger = PhQueryRegistryString(taskmgrKeyHandle, L"Debugger")) - { - alreadyReplaced = PathMatchesPh(OldTaskMgrDebugger); - } - - NtClose(taskmgrKeyHandle); - } - - if (!success) - EnableWindow(GetDlgItem(hwndDlg, IDC_REPLACETASKMANAGER), FALSE); - - OldReplaceTaskMgr = alreadyReplaced; - Button_SetCheck(GetDlgItem(hwndDlg, IDC_REPLACETASKMANAGER), alreadyReplaced ? BST_CHECKED : BST_UNCHECKED); - } -} - -VOID PhpAdvancedPageSave( - _In_ HWND hwndDlg - ) -{ - ULONG sampleCount; - - SetSettingForDlgItemCheck(hwndDlg, IDC_ENABLEWARNINGS, L"EnableWarnings"); - SetSettingForDlgItemCheckRestartRequired(hwndDlg, IDC_ENABLEKERNELMODEDRIVER, L"EnableKph"); - SetSettingForDlgItemCheck(hwndDlg, IDC_HIDEUNNAMEDHANDLES, L"HideUnnamedHandles"); - SetSettingForDlgItemCheckRestartRequired(hwndDlg, IDC_ENABLESTAGE2, L"EnableStage2"); - SetSettingForDlgItemCheckRestartRequired(hwndDlg, IDC_ENABLENETWORKRESOLVE, L"EnableNetworkResolve"); - SetSettingForDlgItemCheck(hwndDlg, IDC_PROPAGATECPUUSAGE, L"PropagateCpuUsage"); - SetSettingForDlgItemCheck(hwndDlg, IDC_ENABLEINSTANTTOOLTIPS, L"EnableInstantTooltips"); - - if (WindowsVersion >= WINDOWS_7) - SetSettingForDlgItemCheckRestartRequired(hwndDlg, IDC_ENABLECYCLECPUUSAGE, L"EnableCycleCpuUsage"); - - sampleCount = GetDlgItemInt(hwndDlg, IDC_SAMPLECOUNT, NULL, FALSE); - SetSettingForDlgItemCheckRestartRequired(hwndDlg, IDC_SAMPLECOUNTAUTOMATIC, L"SampleCountAutomatic"); - - if (sampleCount == 0) - sampleCount = 1; - - if (sampleCount != PhGetIntegerSetting(L"SampleCount")) - RestartRequired = TRUE; - - PhSetIntegerSetting(L"SampleCount", sampleCount); - - // Replace Task Manager - if (IsWindowEnabled(GetDlgItem(hwndDlg, IDC_REPLACETASKMANAGER))) - { - NTSTATUS status; - HANDLE taskmgrKeyHandle; - BOOLEAN replaceTaskMgr; - UNICODE_STRING valueName; - - replaceTaskMgr = Button_GetCheck(GetDlgItem(hwndDlg, IDC_REPLACETASKMANAGER)) == BST_CHECKED; - - if (OldReplaceTaskMgr != replaceTaskMgr) - { - // We should have created the key back in PhpAdvancedPageLoad, which is why - // we're opening the key here. - if (NT_SUCCESS(PhOpenKey( - &taskmgrKeyHandle, - KEY_WRITE, - PH_KEY_LOCAL_MACHINE, - &TaskMgrImageOptionsKeyName, - 0 - ))) - { - RtlInitUnicodeString(&valueName, L"Debugger"); - - if (replaceTaskMgr) - { - PPH_STRING quotedFileName; - - quotedFileName = PH_AUTO(PhConcatStrings(3, L"\"", PhApplicationFileName->Buffer, L"\"")); - status = NtSetValueKey(taskmgrKeyHandle, &valueName, 0, REG_SZ, quotedFileName->Buffer, (ULONG)quotedFileName->Length + 2); - } - else - { - status = NtDeleteValueKey(taskmgrKeyHandle, &valueName); - } - - if (!NT_SUCCESS(status)) - PhShowStatus(hwndDlg, L"Unable to replace Task Manager", status, 0); - - NtClose(taskmgrKeyHandle); - } - } - } -} - -NTSTATUS PhpElevateAdvancedThreadStart( - _In_ PVOID Parameter - ) -{ - PPH_STRING arguments; - - arguments = Parameter; - PhShellProcessHacker( - WindowHandleForElevate, - arguments->Buffer, - SW_SHOW, - PH_SHELL_EXECUTE_ADMIN, - PH_SHELL_APP_PROPAGATE_PARAMETERS, - INFINITE, - NULL - ); - PhDereferenceObject(arguments); - - PostMessage(WindowHandleForElevate, WM_PH_CHILD_EXIT, 0, 0); - - return STATUS_SUCCESS; -} - -INT_PTR CALLBACK PhpOptionsAdvancedDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - switch (uMsg) - { - case WM_INITDIALOG: - { - PhpPageInit(hwndDlg); - PhpAdvancedPageLoad(hwndDlg); - - if (PhStartupParameters.ShowOptions) - { - // Disable all controls except for Replace Task Manager. - EnableWindow(GetDlgItem(hwndDlg, IDC_ENABLEWARNINGS), FALSE); - EnableWindow(GetDlgItem(hwndDlg, IDC_ENABLEKERNELMODEDRIVER), FALSE); - EnableWindow(GetDlgItem(hwndDlg, IDC_HIDEUNNAMEDHANDLES), FALSE); - EnableWindow(GetDlgItem(hwndDlg, IDC_ENABLESTAGE2), FALSE); - EnableWindow(GetDlgItem(hwndDlg, IDC_ENABLENETWORKRESOLVE), FALSE); - EnableWindow(GetDlgItem(hwndDlg, IDC_PROPAGATECPUUSAGE), FALSE); - EnableWindow(GetDlgItem(hwndDlg, IDC_ENABLEINSTANTTOOLTIPS), FALSE); - EnableWindow(GetDlgItem(hwndDlg, IDC_ENABLECYCLECPUUSAGE), FALSE); - EnableWindow(GetDlgItem(hwndDlg, IDC_SAMPLECOUNTLABEL), FALSE); - EnableWindow(GetDlgItem(hwndDlg, IDC_SAMPLECOUNT), FALSE); - EnableWindow(GetDlgItem(hwndDlg, IDC_SAMPLECOUNTAUTOMATIC), FALSE); - } - else - { - if (WindowsVersion < WINDOWS_7) - EnableWindow(GetDlgItem(hwndDlg, IDC_ENABLECYCLECPUUSAGE), FALSE); // cycle-based CPU usage not available before Windows 7 - } - } - break; - case WM_DESTROY: - { - PhClearReference(&OldTaskMgrDebugger); - } - break; - case WM_COMMAND: - { - switch (LOWORD(wParam)) - { - case IDC_CHANGE: - { - HANDLE threadHandle; - RECT windowRect; - - // Save the options so they don't get "overwritten" when - // WM_PH_CHILD_EXIT gets sent. - PhpAdvancedPageSave(hwndDlg); - - GetWindowRect(GetParent(hwndDlg), &windowRect); - WindowHandleForElevate = hwndDlg; - threadHandle = PhCreateThread(0, PhpElevateAdvancedThreadStart, PhFormatString( - L"-showoptions -hwnd %Ix -point %u,%u", - (ULONG_PTR)GetParent(hwndDlg), - windowRect.left + 20, - windowRect.top + 20 - )); - - if (threadHandle) - NtClose(threadHandle); - } - break; - case IDC_SAMPLECOUNTAUTOMATIC: - { - EnableWindow(GetDlgItem(hwndDlg, IDC_SAMPLECOUNT), Button_GetCheck(GetDlgItem(hwndDlg, IDC_SAMPLECOUNTAUTOMATIC)) != BST_CHECKED); - } - break; - } - } - break; - case WM_NOTIFY: - { - LPNMHDR header = (LPNMHDR)lParam; - - switch (header->code) - { - case PSN_APPLY: - { - PhpAdvancedPageSave(hwndDlg); - SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_NOERROR); - } - return TRUE; - } - } - break; - case WM_PH_CHILD_EXIT: - { - PhpAdvancedPageLoad(hwndDlg); - } - break; - } - - return FALSE; -} - -INT_PTR CALLBACK PhpOptionsSymbolsDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - switch (uMsg) - { - case WM_INITDIALOG: - { - PhpPageInit(hwndDlg); - - SetDlgItemText(hwndDlg, IDC_DBGHELPPATH, PhaGetStringSetting(L"DbgHelpPath")->Buffer); - SetDlgItemText(hwndDlg, IDC_DBGHELPSEARCHPATH, PhaGetStringSetting(L"DbgHelpSearchPath")->Buffer); - - SetDlgItemCheckForSetting(hwndDlg, IDC_UNDECORATESYMBOLS, L"DbgHelpUndecorate"); - } - break; - case WM_COMMAND: - { - switch (LOWORD(wParam)) - { - case IDC_BROWSE: - { - static PH_FILETYPE_FILTER filters[] = - { - { L"dbghelp.dll", L"dbghelp.dll" }, - { L"All files (*.*)", L"*.*" } - }; - PVOID fileDialog; - PPH_STRING fileName; - - fileDialog = PhCreateOpenFileDialog(); - PhSetFileDialogFilter(fileDialog, filters, sizeof(filters) / sizeof(PH_FILETYPE_FILTER)); - - fileName = PH_AUTO(PhGetFileName(PhaGetDlgItemText(hwndDlg, IDC_DBGHELPPATH))); - PhSetFileDialogFileName(fileDialog, fileName->Buffer); - - if (PhShowFileDialog(hwndDlg, fileDialog)) - { - fileName = PH_AUTO(PhGetFileDialogFileName(fileDialog)); - SetDlgItemText(hwndDlg, IDC_DBGHELPPATH, fileName->Buffer); - } - - PhFreeFileDialog(fileDialog); - } - break; - } - } - break; - case WM_NOTIFY: - { - LPNMHDR header = (LPNMHDR)lParam; - - switch (header->code) - { - case PSN_APPLY: - { - PPH_STRING dbgHelpPath = PhaGetDlgItemText(hwndDlg, IDC_DBGHELPPATH); - - if (!PhEqualString(dbgHelpPath, PhaGetStringSetting(L"DbgHelpPath"), TRUE)) - RestartRequired = TRUE; - - PhSetStringSetting2(L"DbgHelpPath", &dbgHelpPath->sr); - PhSetStringSetting2(L"DbgHelpSearchPath", &(PhaGetDlgItemText(hwndDlg, IDC_DBGHELPSEARCHPATH)->sr)); - SetSettingForDlgItemCheck(hwndDlg, IDC_UNDECORATESYMBOLS, L"DbgHelpUndecorate"); - - SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_NOERROR); - } - return TRUE; - } - } - break; - } - - return FALSE; -} - -#define CROSS_INDEX 0 -#define TICK_INDEX 1 - -typedef struct _COLOR_ITEM -{ - PWSTR SettingName; - PWSTR UseSettingName; - PWSTR Name; - PWSTR Description; - - BOOLEAN CurrentUse; - COLORREF CurrentColor; -} COLOR_ITEM, *PCOLOR_ITEM; - -#define COLOR_ITEM(SettingName, Name, Description) { SettingName, L"Use" SettingName, Name, Description } - -static COLOR_ITEM ColorItems[] = -{ - COLOR_ITEM(L"ColorOwnProcesses", L"Own processes", L"Processes running under the same user account as Process Hacker."), - COLOR_ITEM(L"ColorSystemProcesses", L"System processes", L"Processes running under the NT AUTHORITY\\SYSTEM user account."), - COLOR_ITEM(L"ColorServiceProcesses", L"Service processes", L"Processes which host one or more services."), - COLOR_ITEM(L"ColorJobProcesses", L"Job processes", L"Processes associated with a job."), -#ifdef _WIN64 - COLOR_ITEM(L"ColorWow64Processes", L"32-bit processes", L"Processes running under WOW64, i.e. 32-bit."), -#endif - COLOR_ITEM(L"ColorDebuggedProcesses", L"Debugged processes", L"Processes that are currently being debugged."), - COLOR_ITEM(L"ColorElevatedProcesses", L"Elevated processes", L"Processes with full privileges on a system with UAC enabled."), - COLOR_ITEM(L"ColorPicoProcesses", L"Pico processes", L"Processes that belong to the Windows subsystem for Linux."), - COLOR_ITEM(L"ColorImmersiveProcesses", L"Immersive processes and DLLs", L"Processes and DLLs that belong to a Modern UI app."), - COLOR_ITEM(L"ColorSuspended", L"Suspended processes and threads", L"Processes and threads that are suspended from execution."), - COLOR_ITEM(L"ColorDotNet", L".NET processes and DLLs", L".NET (i.e. managed) processes and DLLs."), - COLOR_ITEM(L"ColorPacked", L"Packed processes", L"Executables are sometimes \"packed\" to reduce their size."), - COLOR_ITEM(L"ColorGuiThreads", L"GUI threads", L"Threads that have made at least one GUI-related system call."), - COLOR_ITEM(L"ColorRelocatedModules", L"Relocated DLLs", L"DLLs that were not loaded at their preferred image bases."), - COLOR_ITEM(L"ColorProtectedHandles", L"Protected handles", L"Handles that are protected from being closed."), - COLOR_ITEM(L"ColorInheritHandles", L"Inheritable handles", L"Handles that can be inherited by child processes.") -}; - -COLORREF NTAPI PhpColorItemColorFunction( - _In_ INT Index, - _In_ PVOID Param, - _In_opt_ PVOID Context - ) -{ - PCOLOR_ITEM item = Param; - - return item->CurrentColor; -} - -INT_PTR CALLBACK PhpOptionsHighlightingDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - switch (uMsg) - { - case WM_INITDIALOG: - { - ULONG i; - - PhpPageInit(hwndDlg); - - // Highlighting Duration - SetDlgItemInt(hwndDlg, IDC_HIGHLIGHTINGDURATION, PhCsHighlightingDuration, FALSE); - - // New Objects - ColorBox_SetColor(GetDlgItem(hwndDlg, IDC_NEWOBJECTS), PhCsColorNew); - - // Removed Objects - ColorBox_SetColor(GetDlgItem(hwndDlg, IDC_REMOVEDOBJECTS), PhCsColorRemoved); - - // Highlighting - HighlightingListViewHandle = GetDlgItem(hwndDlg, IDC_LIST); - PhSetListViewStyle(HighlightingListViewHandle, FALSE, TRUE); - ListView_SetExtendedListViewStyleEx(HighlightingListViewHandle, LVS_EX_CHECKBOXES, LVS_EX_CHECKBOXES); - PhAddListViewColumn(HighlightingListViewHandle, 0, 0, 0, LVCFMT_LEFT, 240, L"Name"); - PhSetExtendedListView(HighlightingListViewHandle); - ExtendedListView_SetItemColorFunction(HighlightingListViewHandle, PhpColorItemColorFunction); - - for (i = 0; i < sizeof(ColorItems) / sizeof(COLOR_ITEM); i++) - { - INT lvItemIndex; - - lvItemIndex = PhAddListViewItem(HighlightingListViewHandle, MAXINT, ColorItems[i].Name, &ColorItems[i]); - ColorItems[i].CurrentColor = PhGetIntegerSetting(ColorItems[i].SettingName); - ColorItems[i].CurrentUse = !!PhGetIntegerSetting(ColorItems[i].UseSettingName); - ListView_SetCheckState(HighlightingListViewHandle, lvItemIndex, ColorItems[i].CurrentUse); - } - } - break; - case WM_COMMAND: - { - switch (LOWORD(wParam)) - { - case IDC_ENABLEALL: - { - ULONG i; - - for (i = 0; i < sizeof(ColorItems) / sizeof(COLOR_ITEM); i++) - ListView_SetCheckState(HighlightingListViewHandle, i, TRUE); - } - break; - case IDC_DISABLEALL: - { - ULONG i; - - for (i = 0; i < sizeof(ColorItems) / sizeof(COLOR_ITEM); i++) - ListView_SetCheckState(HighlightingListViewHandle, i, FALSE); - } - break; - } - } - break; - case WM_NOTIFY: - { - LPNMHDR header = (LPNMHDR)lParam; - - switch (header->code) - { - case PSN_APPLY: - { - ULONG i; - - PH_SET_INTEGER_CACHED_SETTING(HighlightingDuration, GetDlgItemInt(hwndDlg, IDC_HIGHLIGHTINGDURATION, NULL, FALSE)); - PH_SET_INTEGER_CACHED_SETTING(ColorNew, ColorBox_GetColor(GetDlgItem(hwndDlg, IDC_NEWOBJECTS))); - PH_SET_INTEGER_CACHED_SETTING(ColorRemoved, ColorBox_GetColor(GetDlgItem(hwndDlg, IDC_REMOVEDOBJECTS))); - - for (i = 0; i < sizeof(ColorItems) / sizeof(COLOR_ITEM); i++) - { - ColorItems[i].CurrentUse = !!ListView_GetCheckState(HighlightingListViewHandle, i); - PhSetIntegerSetting(ColorItems[i].SettingName, ColorItems[i].CurrentColor); - PhSetIntegerSetting(ColorItems[i].UseSettingName, ColorItems[i].CurrentUse); - } - - SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_NOERROR); - } - return TRUE; - case NM_DBLCLK: - { - if (header->hwndFrom == HighlightingListViewHandle) - { - PCOLOR_ITEM item; - - if (item = PhGetSelectedListViewItemParam(HighlightingListViewHandle)) - { - CHOOSECOLOR chooseColor = { sizeof(chooseColor) }; - COLORREF customColors[16] = { 0 }; - - chooseColor.hwndOwner = hwndDlg; - chooseColor.rgbResult = item->CurrentColor; - chooseColor.lpCustColors = customColors; - chooseColor.Flags = CC_ANYCOLOR | CC_FULLOPEN | CC_RGBINIT; - - if (ChooseColor(&chooseColor)) - { - item->CurrentColor = chooseColor.rgbResult; - InvalidateRect(HighlightingListViewHandle, NULL, TRUE); - } - } - } - } - break; - case LVN_GETINFOTIP: - { - if (header->hwndFrom == HighlightingListViewHandle) - { - NMLVGETINFOTIP *getInfoTip = (NMLVGETINFOTIP *)lParam; - PH_STRINGREF tip; - - PhInitializeStringRefLongHint(&tip, ColorItems[getInfoTip->iItem].Description); - PhCopyListViewInfoTip(getInfoTip, &tip); - } - } - break; - } - } - break; - } - - REFLECT_MESSAGE_DLG(hwndDlg, HighlightingListViewHandle, uMsg, wParam, lParam); - - return FALSE; -} - -INT_PTR CALLBACK PhpOptionsGraphsDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - switch (uMsg) - { - case WM_INITDIALOG: - { - PhpPageInit(hwndDlg); - - // Show Text - SetDlgItemCheckForSetting(hwndDlg, IDC_SHOWTEXT, L"GraphShowText"); - SetDlgItemCheckForSetting(hwndDlg, IDC_USEOLDCOLORS, L"GraphColorMode"); - SetDlgItemCheckForSetting(hwndDlg, IDC_SHOWCOMMITINSUMMARY, L"ShowCommitInSummary"); - - ColorBox_SetColor(GetDlgItem(hwndDlg, IDC_CPUUSER), PhCsColorCpuUser); - ColorBox_SetColor(GetDlgItem(hwndDlg, IDC_CPUKERNEL), PhCsColorCpuKernel); - ColorBox_SetColor(GetDlgItem(hwndDlg, IDC_IORO), PhCsColorIoReadOther); - ColorBox_SetColor(GetDlgItem(hwndDlg, IDC_IOW), PhCsColorIoWrite); - ColorBox_SetColor(GetDlgItem(hwndDlg, IDC_PRIVATE), PhCsColorPrivate); - ColorBox_SetColor(GetDlgItem(hwndDlg, IDC_PHYSICAL), PhCsColorPhysical); - } - break; - case WM_NOTIFY: - { - LPNMHDR header = (LPNMHDR)lParam; - - switch (header->code) - { - case PSN_APPLY: - { - SetSettingForDlgItemCheck(hwndDlg, IDC_SHOWTEXT, L"GraphShowText"); - SetSettingForDlgItemCheck(hwndDlg, IDC_USEOLDCOLORS, L"GraphColorMode"); - SetSettingForDlgItemCheck(hwndDlg, IDC_SHOWCOMMITINSUMMARY, L"ShowCommitInSummary"); - PH_SET_INTEGER_CACHED_SETTING(ColorCpuUser, ColorBox_GetColor(GetDlgItem(hwndDlg, IDC_CPUUSER))); - PH_SET_INTEGER_CACHED_SETTING(ColorCpuKernel, ColorBox_GetColor(GetDlgItem(hwndDlg, IDC_CPUKERNEL))); - PH_SET_INTEGER_CACHED_SETTING(ColorIoReadOther, ColorBox_GetColor(GetDlgItem(hwndDlg, IDC_IORO))); - PH_SET_INTEGER_CACHED_SETTING(ColorIoWrite, ColorBox_GetColor(GetDlgItem(hwndDlg, IDC_IOW))); - PH_SET_INTEGER_CACHED_SETTING(ColorPrivate, ColorBox_GetColor(GetDlgItem(hwndDlg, IDC_PRIVATE))); - PH_SET_INTEGER_CACHED_SETTING(ColorPhysical, ColorBox_GetColor(GetDlgItem(hwndDlg, IDC_PHYSICAL))); - - SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_NOERROR); - } - return TRUE; - } - } - break; - } - - return FALSE; -} +/* + * Process Hacker - + * options window + * + * Copyright (C) 2010-2016 wj32 + * Copyright (C) 2017 dmex + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include + +#include +#include + +#include + +#include +#include +#include +#include + +#define WM_PH_CHILD_EXIT (WM_APP + 301) + +INT CALLBACK PhpOptionsPropSheetProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ LPARAM lParam + ); + +LRESULT CALLBACK PhpOptionsWndProc( + _In_ HWND hwnd, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam, + _In_ UINT_PTR uIdSubclass, + _In_ ULONG_PTR dwRefData + ); + +INT_PTR CALLBACK PhpOptionsGeneralDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +INT_PTR CALLBACK PhpOptionsAdvancedDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +INT_PTR CALLBACK PhpOptionsSymbolsDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +INT_PTR CALLBACK PhpOptionsHighlightingDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +INT_PTR CALLBACK PhpOptionsGraphsDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +// All +static BOOLEAN PageInit; +static BOOLEAN PressedOk; +static BOOLEAN RestartRequired; +static POINT StartLocation; + +// General +static PH_STRINGREF CurrentUserRunKeyName = PH_STRINGREF_INIT(L"Software\\Microsoft\\Windows\\CurrentVersion\\Run"); +static BOOLEAN CurrentUserRunPresent; +static BOOLEAN CurrentUserRunStartHidden; +static HFONT CurrentFontInstance; +static PPH_STRING NewFontSelection; + +// Advanced +static PH_STRINGREF TaskMgrImageOptionsKeyName = PH_STRINGREF_INIT(L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\taskmgr.exe"); +static PPH_STRING OldTaskMgrDebugger; +static BOOLEAN OldReplaceTaskMgr; +static HWND WindowHandleForElevate; + +// Highlighting +static HWND HighlightingListViewHandle; + +VOID PhShowOptionsDialog( + _In_ HWND ParentWindowHandle + ) +{ + PROPSHEETHEADER propSheetHeader = { sizeof(propSheetHeader) }; + PROPSHEETPAGE propSheetPage; + HPROPSHEETPAGE pages[5]; + + propSheetHeader.dwFlags = + PSH_NOAPPLYNOW | + PSH_NOCONTEXTHELP | + PSH_USECALLBACK | + PSH_USEPSTARTPAGE; + propSheetHeader.hwndParent = ParentWindowHandle; + propSheetHeader.pszCaption = L"Options"; + propSheetHeader.nPages = 0; + propSheetHeader.pStartPage = !PhStartupParameters.ShowOptions ? L"General" : L"Advanced"; + propSheetHeader.phpage = pages; + propSheetHeader.pfnCallback = PhpOptionsPropSheetProc; + + if (!PhStartupParameters.ShowOptions) + { + // Disable all pages other than Advanced. + // General page + memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); + propSheetPage.dwSize = sizeof(PROPSHEETPAGE); + propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_OPTGENERAL); + propSheetPage.pfnDlgProc = PhpOptionsGeneralDlgProc; + pages[propSheetHeader.nPages++] = CreatePropertySheetPage(&propSheetPage); + } + + // Advanced page + memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); + propSheetPage.dwSize = sizeof(PROPSHEETPAGE); + propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_OPTADVANCED); + propSheetPage.pfnDlgProc = PhpOptionsAdvancedDlgProc; + pages[propSheetHeader.nPages++] = CreatePropertySheetPage(&propSheetPage); + + if (!PhStartupParameters.ShowOptions) + { + // Symbols page + memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); + propSheetPage.dwSize = sizeof(PROPSHEETPAGE); + propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_OPTSYMBOLS); + propSheetPage.pfnDlgProc = PhpOptionsSymbolsDlgProc; + pages[propSheetHeader.nPages++] = CreatePropertySheetPage(&propSheetPage); + } + + if (!PhStartupParameters.ShowOptions) + { + // Highlighting page + memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); + propSheetPage.dwSize = sizeof(PROPSHEETPAGE); + propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_OPTHIGHLIGHTING); + propSheetPage.pfnDlgProc = PhpOptionsHighlightingDlgProc; + pages[propSheetHeader.nPages++] = CreatePropertySheetPage(&propSheetPage); + } + + if (!PhStartupParameters.ShowOptions) + { + // Graphs page + memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); + propSheetPage.dwSize = sizeof(PROPSHEETPAGE); + propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_OPTGRAPHS); + propSheetPage.pfnDlgProc = PhpOptionsGraphsDlgProc; + pages[propSheetHeader.nPages++] = CreatePropertySheetPage(&propSheetPage); + } + + PageInit = FALSE; + PressedOk = FALSE; + RestartRequired = FALSE; + + if (PhStartupParameters.ShowOptions) + StartLocation = PhStartupParameters.Point; + else + StartLocation.x = MINLONG; + + OldTaskMgrDebugger = NULL; + + PhModalPropertySheet(&propSheetHeader); + + if (PressedOk) + { + if (!PhStartupParameters.ShowOptions) + { + PhUpdateCachedSettings(); + ProcessHacker_SaveAllSettings(PhMainWndHandle); + PhInvalidateAllProcessNodes(); + PhReloadSettingsProcessTreeList(); + PhSiNotifyChangeSettings(); + + if (RestartRequired) + { + if (PhShowMessage( + PhMainWndHandle, + MB_ICONQUESTION | MB_YESNO, + L"One or more options you have changed requires a restart of Process Hacker. " + L"Do you want to restart Process Hacker now?" + ) == IDYES) + { + ProcessHacker_PrepareForEarlyShutdown(PhMainWndHandle); + PhShellProcessHacker( + PhMainWndHandle, + L"-v", + SW_SHOW, + 0, + PH_SHELL_APP_PROPAGATE_PARAMETERS | PH_SHELL_APP_PROPAGATE_PARAMETERS_IGNORE_VISIBILITY, + 0, + NULL + ); + ProcessHacker_Destroy(PhMainWndHandle); + } + } + } + else + { + // Main window not available. + if (PhSettingsFileName) + PhSaveSettings(PhSettingsFileName->Buffer); + } + } +} + +INT CALLBACK PhpOptionsPropSheetProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ LPARAM lParam + ) +{ + switch (uMsg) + { + case PSCB_BUTTONPRESSED: + { + if (lParam == PSBTN_OK) + { + PressedOk = TRUE; + } + } + break; + } + + return 0; +} + +static VOID PhpPageInit( + _In_ HWND hwndDlg + ) +{ + if (!PageInit) + { + HWND optionsWindow; + HWND resetButton; + RECT clientRect; + RECT rect; + + optionsWindow = GetParent(hwndDlg); + SetWindowSubclass(optionsWindow, PhpOptionsWndProc, 0, 0); + + // Create the Reset button. + GetClientRect(optionsWindow, &clientRect); + GetWindowRect(GetDlgItem(optionsWindow, IDCANCEL), &rect); + MapWindowPoints(NULL, optionsWindow, (POINT *)&rect, 2); + resetButton = CreateWindowEx( + WS_EX_NOPARENTNOTIFY, + L"BUTTON", + L"Reset", + WS_CHILD | WS_VISIBLE | WS_TABSTOP, + clientRect.right - rect.right, + rect.top, + rect.right - rect.left, + rect.bottom - rect.top, + optionsWindow, + (HMENU)IDC_RESET, + PhInstanceHandle, + NULL + ); + SendMessage(resetButton, WM_SETFONT, SendMessage(GetDlgItem(optionsWindow, IDCANCEL), WM_GETFONT, 0, 0), TRUE); + + if (PhStartupParameters.ShowOptions) + ShowWindow(resetButton, SW_HIDE); + + // Set the location of the options window. + if (StartLocation.x == MINLONG) + { + PhCenterWindow(optionsWindow, GetParent(optionsWindow)); + } + else + { + SetWindowPos(optionsWindow, NULL, StartLocation.x, StartLocation.y, 0, 0, + SWP_NOACTIVATE | SWP_NOREDRAW | SWP_NOSIZE | SWP_NOZORDER); + } + + PageInit = TRUE; + } +} + +LRESULT CALLBACK PhpOptionsWndProc( + _In_ HWND hwnd, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam, + _In_ UINT_PTR uIdSubclass, + _In_ ULONG_PTR dwRefData + ) +{ + switch (uMsg) + { + case WM_DESTROY: + RemoveWindowSubclass(hwnd, PhpOptionsWndProc, uIdSubclass); + break; + case WM_COMMAND: + { + switch (LOWORD(wParam)) + { + case IDC_RESET: + { + if (PhShowMessage( + hwnd, + MB_ICONWARNING | MB_YESNO | MB_DEFBUTTON2, + L"Do you want to reset all settings and restart Process Hacker?" + ) == IDYES) + { + ProcessHacker_PrepareForEarlyShutdown(PhMainWndHandle); + + PhResetSettings(); + + if (PhSettingsFileName) + PhSaveSettings(PhSettingsFileName->Buffer); + + PhShellProcessHacker( + PhMainWndHandle, + L"-v", + SW_SHOW, + 0, + PH_SHELL_APP_PROPAGATE_PARAMETERS | PH_SHELL_APP_PROPAGATE_PARAMETERS_IGNORE_VISIBILITY, + 0, + NULL + ); + ProcessHacker_Destroy(PhMainWndHandle); + } + } + break; + } + } + break; + } + + return DefSubclassProc(hwnd, uMsg, wParam, lParam); +} + +#define SetDlgItemCheckForSetting(hwndDlg, Id, Name) \ + Button_SetCheck(GetDlgItem(hwndDlg, Id), PhGetIntegerSetting(Name) ? BST_CHECKED : BST_UNCHECKED) +#define SetSettingForDlgItemCheck(hwndDlg, Id, Name) \ + PhSetIntegerSetting(Name, Button_GetCheck(GetDlgItem(hwndDlg, Id)) == BST_CHECKED) +#define SetSettingForDlgItemCheckRestartRequired(hwndDlg, Id, Name) \ + do { \ + BOOLEAN __oldValue = !!PhGetIntegerSetting(Name); \ + BOOLEAN __newValue = Button_GetCheck(GetDlgItem(hwndDlg, Id)) == BST_CHECKED; \ + if (__newValue != __oldValue) \ + RestartRequired = TRUE; \ + PhSetIntegerSetting(Name, __newValue); \ + } while (0) +#define DialogChanged PropSheet_Changed(GetParent(hwndDlg), hwndDlg) + +static BOOLEAN GetCurrentFont( + _Out_ PLOGFONT Font + ) +{ + BOOLEAN result; + PPH_STRING fontHexString; + + if (NewFontSelection) + fontHexString = NewFontSelection; + else + fontHexString = PhaGetStringSetting(L"Font"); + + if (fontHexString->Length / 2 / 2 == sizeof(LOGFONT)) + result = PhHexStringToBuffer(&fontHexString->sr, (PUCHAR)Font); + else + result = FALSE; + + return result; +} + +static VOID ReadCurrentUserRun( + VOID + ) +{ + HANDLE keyHandle; + PPH_STRING value; + + CurrentUserRunPresent = FALSE; + CurrentUserRunStartHidden = FALSE; + + if (NT_SUCCESS(PhOpenKey( + &keyHandle, + KEY_READ, + PH_KEY_CURRENT_USER, + &CurrentUserRunKeyName, + 0 + ))) + { + if (value = PhQueryRegistryString(keyHandle, L"Process Hacker")) + { + PH_STRINGREF fileName; + PH_STRINGREF arguments; + PPH_STRING fullFileName; + + PH_AUTO(value); + + if (PhParseCommandLineFuzzy(&value->sr, &fileName, &arguments, &fullFileName)) + { + PH_AUTO(fullFileName); + + if (fullFileName && PhEqualString(fullFileName, PhApplicationFileName, TRUE)) + { + CurrentUserRunPresent = TRUE; + CurrentUserRunStartHidden = PhEqualStringRef2(&arguments, L"-hide", FALSE); + } + } + } + + NtClose(keyHandle); + } +} + +static VOID WriteCurrentUserRun( + _In_ BOOLEAN Present, + _In_ BOOLEAN StartHidden + ) +{ + HANDLE keyHandle; + + if (CurrentUserRunPresent == Present && (!Present || CurrentUserRunStartHidden == StartHidden)) + return; + + if (NT_SUCCESS(PhOpenKey( + &keyHandle, + KEY_WRITE, + PH_KEY_CURRENT_USER, + &CurrentUserRunKeyName, + 0 + ))) + { + UNICODE_STRING valueName; + + RtlInitUnicodeString(&valueName, L"Process Hacker"); + + if (Present) + { + PPH_STRING value; + + value = PH_AUTO(PhConcatStrings(3, L"\"", PhApplicationFileName->Buffer, L"\"")); + + if (StartHidden) + value = PhaConcatStrings2(value->Buffer, L" -hide"); + + NtSetValueKey(keyHandle, &valueName, 0, REG_SZ, value->Buffer, (ULONG)value->Length + 2); + } + else + { + NtDeleteValueKey(keyHandle, &valueName); + } + + NtClose(keyHandle); + } +} + + +INT_PTR CALLBACK PhpOptionsGeneralDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + switch (uMsg) + { + case WM_INITDIALOG: + { + HWND comboBoxHandle; + ULONG i; + LOGFONT font; + + PhpPageInit(hwndDlg); + + comboBoxHandle = GetDlgItem(hwndDlg, IDC_MAXSIZEUNIT); + + for (i = 0; i < sizeof(PhSizeUnitNames) / sizeof(PWSTR); i++) + ComboBox_AddString(comboBoxHandle, PhSizeUnitNames[i]); + + SetDlgItemText(hwndDlg, IDC_SEARCHENGINE, PhaGetStringSetting(L"SearchEngine")->Buffer); + SetDlgItemText(hwndDlg, IDC_PEVIEWER, PhaGetStringSetting(L"ProgramInspectExecutables")->Buffer); + + if (PhMaxSizeUnit != -1) + ComboBox_SetCurSel(comboBoxHandle, PhMaxSizeUnit); + else + ComboBox_SetCurSel(comboBoxHandle, sizeof(PhSizeUnitNames) / sizeof(PWSTR) - 1); + + SetDlgItemInt(hwndDlg, IDC_ICONPROCESSES, PhGetIntegerSetting(L"IconProcesses"), FALSE); + + SetDlgItemCheckForSetting(hwndDlg, IDC_ALLOWONLYONEINSTANCE, L"AllowOnlyOneInstance"); + SetDlgItemCheckForSetting(hwndDlg, IDC_HIDEONCLOSE, L"HideOnClose"); + SetDlgItemCheckForSetting(hwndDlg, IDC_HIDEONMINIMIZE, L"HideOnMinimize"); + SetDlgItemCheckForSetting(hwndDlg, IDC_COLLAPSESERVICES, L"CollapseServicesOnStart"); + SetDlgItemCheckForSetting(hwndDlg, IDC_ICONSINGLECLICK, L"IconSingleClick"); + SetDlgItemCheckForSetting(hwndDlg, IDC_ICONTOGGLESVISIBILITY, L"IconTogglesVisibility"); + SetDlgItemCheckForSetting(hwndDlg, IDC_ENABLEPLUGINS, L"EnablePlugins"); + + ReadCurrentUserRun(); + + if (CurrentUserRunPresent) + { + Button_SetCheck(GetDlgItem(hwndDlg, IDC_STARTATLOGON), BST_CHECKED); + + if (CurrentUserRunStartHidden) + Button_SetCheck(GetDlgItem(hwndDlg, IDC_STARTHIDDEN), BST_CHECKED); + } + else + { + EnableWindow(GetDlgItem(hwndDlg, IDC_STARTHIDDEN), FALSE); + } + + // Set the font of the button for a nice preview. + if (GetCurrentFont(&font)) + { + CurrentFontInstance = CreateFontIndirect(&font); + + if (CurrentFontInstance) + SendMessage(GetDlgItem(hwndDlg, IDC_FONT), WM_SETFONT, (WPARAM)CurrentFontInstance, TRUE); + } + } + break; + case WM_DESTROY: + { + if (CurrentFontInstance) + DeleteObject(CurrentFontInstance); + + PhClearReference(&NewFontSelection); + } + break; + case WM_COMMAND: + { + switch (LOWORD(wParam)) + { + case IDC_STARTATLOGON: + { + EnableWindow(GetDlgItem(hwndDlg, IDC_STARTHIDDEN), Button_GetCheck(GetDlgItem(hwndDlg, IDC_STARTATLOGON)) == BST_CHECKED); + } + break; + case IDC_FONT: + { + LOGFONT font; + CHOOSEFONT chooseFont; + + if (!GetCurrentFont(&font)) + { + // Can't get LOGFONT from the existing setting, probably + // because the user hasn't ever chosen a font before. + // Set the font to something familiar. + GetObject((HFONT)SendMessage(PhMainWndHandle, WM_PH_GET_FONT, 0, 0), sizeof(LOGFONT), &font); + } + + memset(&chooseFont, 0, sizeof(CHOOSEFONT)); + chooseFont.lStructSize = sizeof(CHOOSEFONT); + chooseFont.hwndOwner = hwndDlg; + chooseFont.lpLogFont = &font; + chooseFont.Flags = CF_FORCEFONTEXIST | CF_INITTOLOGFONTSTRUCT | CF_SCREENFONTS; + + if (ChooseFont(&chooseFont)) + { + PhMoveReference(&NewFontSelection, PhBufferToHexString((PUCHAR)&font, sizeof(LOGFONT))); + + // Update the button's font. + + if (CurrentFontInstance) + DeleteObject(CurrentFontInstance); + + CurrentFontInstance = CreateFontIndirect(&font); + SendMessage(GetDlgItem(hwndDlg, IDC_FONT), WM_SETFONT, (WPARAM)CurrentFontInstance, TRUE); + } + } + break; + } + } + break; + case WM_NOTIFY: + { + LPNMHDR header = (LPNMHDR)lParam; + + switch (header->code) + { + case PSN_APPLY: + { + BOOLEAN startAtLogon; + BOOLEAN startHidden; + + PhSetStringSetting2(L"SearchEngine", &(PhaGetDlgItemText(hwndDlg, IDC_SEARCHENGINE)->sr)); + PhSetStringSetting2(L"ProgramInspectExecutables", &(PhaGetDlgItemText(hwndDlg, IDC_PEVIEWER)->sr)); + PhSetIntegerSetting(L"MaxSizeUnit", PhMaxSizeUnit = ComboBox_GetCurSel(GetDlgItem(hwndDlg, IDC_MAXSIZEUNIT))); + PhSetIntegerSetting(L"IconProcesses", GetDlgItemInt(hwndDlg, IDC_ICONPROCESSES, NULL, FALSE)); + SetSettingForDlgItemCheck(hwndDlg, IDC_ALLOWONLYONEINSTANCE, L"AllowOnlyOneInstance"); + SetSettingForDlgItemCheck(hwndDlg, IDC_HIDEONCLOSE, L"HideOnClose"); + SetSettingForDlgItemCheck(hwndDlg, IDC_HIDEONMINIMIZE, L"HideOnMinimize"); + SetSettingForDlgItemCheck(hwndDlg, IDC_COLLAPSESERVICES, L"CollapseServicesOnStart"); + SetSettingForDlgItemCheck(hwndDlg, IDC_ICONSINGLECLICK, L"IconSingleClick"); + SetSettingForDlgItemCheck(hwndDlg, IDC_ICONTOGGLESVISIBILITY, L"IconTogglesVisibility"); + SetSettingForDlgItemCheckRestartRequired(hwndDlg, IDC_ENABLEPLUGINS, L"EnablePlugins"); + + startAtLogon = Button_GetCheck(GetDlgItem(hwndDlg, IDC_STARTATLOGON)) == BST_CHECKED; + startHidden = Button_GetCheck(GetDlgItem(hwndDlg, IDC_STARTHIDDEN)) == BST_CHECKED; + WriteCurrentUserRun(startAtLogon, startHidden); + + if (NewFontSelection) + { + PhSetStringSetting2(L"Font", &NewFontSelection->sr); + PostMessage(PhMainWndHandle, WM_PH_UPDATE_FONT, 0, 0); + } + + SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_NOERROR); + } + return TRUE; + } + } + break; + } + + return FALSE; +} + +static BOOLEAN PathMatchesPh( + _In_ PPH_STRING Path + ) +{ + BOOLEAN match = FALSE; + + if (PhEqualString(OldTaskMgrDebugger, PhApplicationFileName, TRUE)) + { + match = TRUE; + } + // Allow for a quoted value. + else if ( + OldTaskMgrDebugger->Length == PhApplicationFileName->Length + sizeof(WCHAR) * 2 && + OldTaskMgrDebugger->Buffer[0] == '"' && + OldTaskMgrDebugger->Buffer[OldTaskMgrDebugger->Length / sizeof(WCHAR) - 1] == '"' + ) + { + PH_STRINGREF partInside; + + partInside.Buffer = &OldTaskMgrDebugger->Buffer[1]; + partInside.Length = OldTaskMgrDebugger->Length - sizeof(WCHAR) * 2; + + if (PhEqualStringRef(&partInside, &PhApplicationFileName->sr, TRUE)) + match = TRUE; + } + + return match; +} + +VOID PhpAdvancedPageLoad( + _In_ HWND hwndDlg + ) +{ + HWND changeButton; + + SetDlgItemCheckForSetting(hwndDlg, IDC_ENABLEWARNINGS, L"EnableWarnings"); + SetDlgItemCheckForSetting(hwndDlg, IDC_ENABLEKERNELMODEDRIVER, L"EnableKph"); + SetDlgItemCheckForSetting(hwndDlg, IDC_HIDEUNNAMEDHANDLES, L"HideUnnamedHandles"); + SetDlgItemCheckForSetting(hwndDlg, IDC_ENABLESTAGE2, L"EnableStage2"); + SetDlgItemCheckForSetting(hwndDlg, IDC_ENABLENETWORKRESOLVE, L"EnableNetworkResolve"); + SetDlgItemCheckForSetting(hwndDlg, IDC_PROPAGATECPUUSAGE, L"PropagateCpuUsage"); + SetDlgItemCheckForSetting(hwndDlg, IDC_ENABLEINSTANTTOOLTIPS, L"EnableInstantTooltips"); + + if (WindowsVersion >= WINDOWS_7) + SetDlgItemCheckForSetting(hwndDlg, IDC_ENABLECYCLECPUUSAGE, L"EnableCycleCpuUsage"); + + SetDlgItemInt(hwndDlg, IDC_SAMPLECOUNT, PhGetIntegerSetting(L"SampleCount"), FALSE); + SetDlgItemCheckForSetting(hwndDlg, IDC_SAMPLECOUNTAUTOMATIC, L"SampleCountAutomatic"); + + if (PhGetIntegerSetting(L"SampleCountAutomatic")) + EnableWindow(GetDlgItem(hwndDlg, IDC_SAMPLECOUNT), FALSE); + + // Replace Task Manager + + changeButton = GetDlgItem(hwndDlg, IDC_CHANGE); + + if (PhGetOwnTokenAttributes().Elevated) + { + ShowWindow(changeButton, SW_HIDE); + } + else + { + SendMessage(changeButton, BCM_SETSHIELD, 0, TRUE); + } + + { + HANDLE taskmgrKeyHandle = NULL; + ULONG disposition; + BOOLEAN success = FALSE; + BOOLEAN alreadyReplaced = FALSE; + + // See if we can write to the key. + if (NT_SUCCESS(PhCreateKey( + &taskmgrKeyHandle, + KEY_READ | KEY_WRITE, + PH_KEY_LOCAL_MACHINE, + &TaskMgrImageOptionsKeyName, + 0, + 0, + &disposition + ))) + { + success = TRUE; + } + + if (taskmgrKeyHandle || NT_SUCCESS(PhOpenKey( + &taskmgrKeyHandle, + KEY_READ, + PH_KEY_LOCAL_MACHINE, + &TaskMgrImageOptionsKeyName, + 0 + ))) + { + PhClearReference(&OldTaskMgrDebugger); + + if (OldTaskMgrDebugger = PhQueryRegistryString(taskmgrKeyHandle, L"Debugger")) + { + alreadyReplaced = PathMatchesPh(OldTaskMgrDebugger); + } + + NtClose(taskmgrKeyHandle); + } + + if (!success) + EnableWindow(GetDlgItem(hwndDlg, IDC_REPLACETASKMANAGER), FALSE); + + OldReplaceTaskMgr = alreadyReplaced; + Button_SetCheck(GetDlgItem(hwndDlg, IDC_REPLACETASKMANAGER), alreadyReplaced ? BST_CHECKED : BST_UNCHECKED); + } +} + +VOID PhpAdvancedPageSave( + _In_ HWND hwndDlg + ) +{ + ULONG sampleCount; + + SetSettingForDlgItemCheck(hwndDlg, IDC_ENABLEWARNINGS, L"EnableWarnings"); + SetSettingForDlgItemCheckRestartRequired(hwndDlg, IDC_ENABLEKERNELMODEDRIVER, L"EnableKph"); + SetSettingForDlgItemCheck(hwndDlg, IDC_HIDEUNNAMEDHANDLES, L"HideUnnamedHandles"); + SetSettingForDlgItemCheckRestartRequired(hwndDlg, IDC_ENABLESTAGE2, L"EnableStage2"); + SetSettingForDlgItemCheckRestartRequired(hwndDlg, IDC_ENABLENETWORKRESOLVE, L"EnableNetworkResolve"); + SetSettingForDlgItemCheck(hwndDlg, IDC_PROPAGATECPUUSAGE, L"PropagateCpuUsage"); + SetSettingForDlgItemCheck(hwndDlg, IDC_ENABLEINSTANTTOOLTIPS, L"EnableInstantTooltips"); + + if (WindowsVersion >= WINDOWS_7) + SetSettingForDlgItemCheckRestartRequired(hwndDlg, IDC_ENABLECYCLECPUUSAGE, L"EnableCycleCpuUsage"); + + sampleCount = GetDlgItemInt(hwndDlg, IDC_SAMPLECOUNT, NULL, FALSE); + SetSettingForDlgItemCheckRestartRequired(hwndDlg, IDC_SAMPLECOUNTAUTOMATIC, L"SampleCountAutomatic"); + + if (sampleCount == 0) + sampleCount = 1; + + if (sampleCount != PhGetIntegerSetting(L"SampleCount")) + RestartRequired = TRUE; + + PhSetIntegerSetting(L"SampleCount", sampleCount); + + // Replace Task Manager + if (IsWindowEnabled(GetDlgItem(hwndDlg, IDC_REPLACETASKMANAGER))) + { + NTSTATUS status; + HANDLE taskmgrKeyHandle; + BOOLEAN replaceTaskMgr; + UNICODE_STRING valueName; + + replaceTaskMgr = Button_GetCheck(GetDlgItem(hwndDlg, IDC_REPLACETASKMANAGER)) == BST_CHECKED; + + if (OldReplaceTaskMgr != replaceTaskMgr) + { + // We should have created the key back in PhpAdvancedPageLoad, which is why + // we're opening the key here. + if (NT_SUCCESS(PhOpenKey( + &taskmgrKeyHandle, + KEY_WRITE, + PH_KEY_LOCAL_MACHINE, + &TaskMgrImageOptionsKeyName, + 0 + ))) + { + RtlInitUnicodeString(&valueName, L"Debugger"); + + if (replaceTaskMgr) + { + PPH_STRING quotedFileName; + + quotedFileName = PH_AUTO(PhConcatStrings(3, L"\"", PhApplicationFileName->Buffer, L"\"")); + status = NtSetValueKey(taskmgrKeyHandle, &valueName, 0, REG_SZ, quotedFileName->Buffer, (ULONG)quotedFileName->Length + 2); + } + else + { + status = NtDeleteValueKey(taskmgrKeyHandle, &valueName); + } + + if (!NT_SUCCESS(status)) + PhShowStatus(hwndDlg, L"Unable to replace Task Manager", status, 0); + + NtClose(taskmgrKeyHandle); + } + } + } +} + +NTSTATUS PhpElevateAdvancedThreadStart( + _In_ PVOID Parameter + ) +{ + PPH_STRING arguments; + + arguments = Parameter; + PhShellProcessHacker( + WindowHandleForElevate, + arguments->Buffer, + SW_SHOW, + PH_SHELL_EXECUTE_ADMIN, + PH_SHELL_APP_PROPAGATE_PARAMETERS, + INFINITE, + NULL + ); + PhDereferenceObject(arguments); + + PostMessage(WindowHandleForElevate, WM_PH_CHILD_EXIT, 0, 0); + + return STATUS_SUCCESS; +} + +INT_PTR CALLBACK PhpOptionsAdvancedDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + switch (uMsg) + { + case WM_INITDIALOG: + { + PhpPageInit(hwndDlg); + PhpAdvancedPageLoad(hwndDlg); + + if (PhStartupParameters.ShowOptions) + { + // Disable all controls except for Replace Task Manager. + EnableWindow(GetDlgItem(hwndDlg, IDC_ENABLEWARNINGS), FALSE); + EnableWindow(GetDlgItem(hwndDlg, IDC_ENABLEKERNELMODEDRIVER), FALSE); + EnableWindow(GetDlgItem(hwndDlg, IDC_HIDEUNNAMEDHANDLES), FALSE); + EnableWindow(GetDlgItem(hwndDlg, IDC_ENABLESTAGE2), FALSE); + EnableWindow(GetDlgItem(hwndDlg, IDC_ENABLENETWORKRESOLVE), FALSE); + EnableWindow(GetDlgItem(hwndDlg, IDC_PROPAGATECPUUSAGE), FALSE); + EnableWindow(GetDlgItem(hwndDlg, IDC_ENABLEINSTANTTOOLTIPS), FALSE); + EnableWindow(GetDlgItem(hwndDlg, IDC_ENABLECYCLECPUUSAGE), FALSE); + EnableWindow(GetDlgItem(hwndDlg, IDC_SAMPLECOUNTLABEL), FALSE); + EnableWindow(GetDlgItem(hwndDlg, IDC_SAMPLECOUNT), FALSE); + EnableWindow(GetDlgItem(hwndDlg, IDC_SAMPLECOUNTAUTOMATIC), FALSE); + } + else + { + if (WindowsVersion < WINDOWS_7) + EnableWindow(GetDlgItem(hwndDlg, IDC_ENABLECYCLECPUUSAGE), FALSE); // cycle-based CPU usage not available before Windows 7 + } + } + break; + case WM_DESTROY: + { + PhClearReference(&OldTaskMgrDebugger); + } + break; + case WM_COMMAND: + { + switch (LOWORD(wParam)) + { + case IDC_CHANGE: + { + HANDLE threadHandle; + RECT windowRect; + + // Save the options so they don't get "overwritten" when + // WM_PH_CHILD_EXIT gets sent. + PhpAdvancedPageSave(hwndDlg); + + GetWindowRect(GetParent(hwndDlg), &windowRect); + WindowHandleForElevate = hwndDlg; + threadHandle = PhCreateThread(0, PhpElevateAdvancedThreadStart, PhFormatString( + L"-showoptions -hwnd %Ix -point %u,%u", + (ULONG_PTR)GetParent(hwndDlg), + windowRect.left + 20, + windowRect.top + 20 + )); + + if (threadHandle) + NtClose(threadHandle); + } + break; + case IDC_SAMPLECOUNTAUTOMATIC: + { + EnableWindow(GetDlgItem(hwndDlg, IDC_SAMPLECOUNT), Button_GetCheck(GetDlgItem(hwndDlg, IDC_SAMPLECOUNTAUTOMATIC)) != BST_CHECKED); + } + break; + } + } + break; + case WM_NOTIFY: + { + LPNMHDR header = (LPNMHDR)lParam; + + switch (header->code) + { + case PSN_APPLY: + { + PhpAdvancedPageSave(hwndDlg); + SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_NOERROR); + } + return TRUE; + } + } + break; + case WM_PH_CHILD_EXIT: + { + PhpAdvancedPageLoad(hwndDlg); + } + break; + } + + return FALSE; +} + +INT_PTR CALLBACK PhpOptionsSymbolsDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + switch (uMsg) + { + case WM_INITDIALOG: + { + PhpPageInit(hwndDlg); + + SetDlgItemText(hwndDlg, IDC_DBGHELPPATH, PhaGetStringSetting(L"DbgHelpPath")->Buffer); + SetDlgItemText(hwndDlg, IDC_DBGHELPSEARCHPATH, PhaGetStringSetting(L"DbgHelpSearchPath")->Buffer); + + SetDlgItemCheckForSetting(hwndDlg, IDC_UNDECORATESYMBOLS, L"DbgHelpUndecorate"); + } + break; + case WM_COMMAND: + { + switch (LOWORD(wParam)) + { + case IDC_BROWSE: + { + static PH_FILETYPE_FILTER filters[] = + { + { L"dbghelp.dll", L"dbghelp.dll" }, + { L"All files (*.*)", L"*.*" } + }; + PVOID fileDialog; + PPH_STRING fileName; + + fileDialog = PhCreateOpenFileDialog(); + PhSetFileDialogFilter(fileDialog, filters, sizeof(filters) / sizeof(PH_FILETYPE_FILTER)); + + fileName = PH_AUTO(PhGetFileName(PhaGetDlgItemText(hwndDlg, IDC_DBGHELPPATH))); + PhSetFileDialogFileName(fileDialog, fileName->Buffer); + + if (PhShowFileDialog(hwndDlg, fileDialog)) + { + fileName = PH_AUTO(PhGetFileDialogFileName(fileDialog)); + SetDlgItemText(hwndDlg, IDC_DBGHELPPATH, fileName->Buffer); + } + + PhFreeFileDialog(fileDialog); + } + break; + } + } + break; + case WM_NOTIFY: + { + LPNMHDR header = (LPNMHDR)lParam; + + switch (header->code) + { + case PSN_APPLY: + { + PPH_STRING dbgHelpPath = PhaGetDlgItemText(hwndDlg, IDC_DBGHELPPATH); + + if (!PhEqualString(dbgHelpPath, PhaGetStringSetting(L"DbgHelpPath"), TRUE)) + RestartRequired = TRUE; + + PhSetStringSetting2(L"DbgHelpPath", &dbgHelpPath->sr); + PhSetStringSetting2(L"DbgHelpSearchPath", &(PhaGetDlgItemText(hwndDlg, IDC_DBGHELPSEARCHPATH)->sr)); + SetSettingForDlgItemCheck(hwndDlg, IDC_UNDECORATESYMBOLS, L"DbgHelpUndecorate"); + + SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_NOERROR); + } + return TRUE; + } + } + break; + } + + return FALSE; +} + +#define CROSS_INDEX 0 +#define TICK_INDEX 1 + +typedef struct _COLOR_ITEM +{ + PWSTR SettingName; + PWSTR UseSettingName; + PWSTR Name; + PWSTR Description; + + BOOLEAN CurrentUse; + COLORREF CurrentColor; +} COLOR_ITEM, *PCOLOR_ITEM; + +#define COLOR_ITEM(SettingName, Name, Description) { SettingName, L"Use" SettingName, Name, Description } + +static COLOR_ITEM ColorItems[] = +{ + COLOR_ITEM(L"ColorOwnProcesses", L"Own processes", L"Processes running under the same user account as Process Hacker."), + COLOR_ITEM(L"ColorSystemProcesses", L"System processes", L"Processes running under the NT AUTHORITY\\SYSTEM user account."), + COLOR_ITEM(L"ColorServiceProcesses", L"Service processes", L"Processes which host one or more services."), + COLOR_ITEM(L"ColorJobProcesses", L"Job processes", L"Processes associated with a job."), +#ifdef _WIN64 + COLOR_ITEM(L"ColorWow64Processes", L"32-bit processes", L"Processes running under WOW64, i.e. 32-bit."), +#endif + COLOR_ITEM(L"ColorDebuggedProcesses", L"Debugged processes", L"Processes that are currently being debugged."), + COLOR_ITEM(L"ColorElevatedProcesses", L"Elevated processes", L"Processes with full privileges on a system with UAC enabled."), + COLOR_ITEM(L"ColorPicoProcesses", L"Pico processes", L"Processes that belong to the Windows subsystem for Linux."), + COLOR_ITEM(L"ColorImmersiveProcesses", L"Immersive processes and DLLs", L"Processes and DLLs that belong to a Modern UI app."), + COLOR_ITEM(L"ColorSuspended", L"Suspended processes and threads", L"Processes and threads that are suspended from execution."), + COLOR_ITEM(L"ColorDotNet", L".NET processes and DLLs", L".NET (i.e. managed) processes and DLLs."), + COLOR_ITEM(L"ColorPacked", L"Packed processes", L"Executables are sometimes \"packed\" to reduce their size."), + COLOR_ITEM(L"ColorGuiThreads", L"GUI threads", L"Threads that have made at least one GUI-related system call."), + COLOR_ITEM(L"ColorRelocatedModules", L"Relocated DLLs", L"DLLs that were not loaded at their preferred image bases."), + COLOR_ITEM(L"ColorProtectedHandles", L"Protected handles", L"Handles that are protected from being closed."), + COLOR_ITEM(L"ColorInheritHandles", L"Inheritable handles", L"Handles that can be inherited by child processes.") +}; + +COLORREF NTAPI PhpColorItemColorFunction( + _In_ INT Index, + _In_ PVOID Param, + _In_opt_ PVOID Context + ) +{ + PCOLOR_ITEM item = Param; + + return item->CurrentColor; +} + +INT_PTR CALLBACK PhpOptionsHighlightingDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + switch (uMsg) + { + case WM_INITDIALOG: + { + ULONG i; + + PhpPageInit(hwndDlg); + + // Highlighting Duration + SetDlgItemInt(hwndDlg, IDC_HIGHLIGHTINGDURATION, PhCsHighlightingDuration, FALSE); + + // New Objects + ColorBox_SetColor(GetDlgItem(hwndDlg, IDC_NEWOBJECTS), PhCsColorNew); + + // Removed Objects + ColorBox_SetColor(GetDlgItem(hwndDlg, IDC_REMOVEDOBJECTS), PhCsColorRemoved); + + // Highlighting + HighlightingListViewHandle = GetDlgItem(hwndDlg, IDC_LIST); + PhSetListViewStyle(HighlightingListViewHandle, FALSE, TRUE); + ListView_SetExtendedListViewStyleEx(HighlightingListViewHandle, LVS_EX_CHECKBOXES, LVS_EX_CHECKBOXES); + PhAddListViewColumn(HighlightingListViewHandle, 0, 0, 0, LVCFMT_LEFT, 240, L"Name"); + PhSetExtendedListView(HighlightingListViewHandle); + ExtendedListView_SetItemColorFunction(HighlightingListViewHandle, PhpColorItemColorFunction); + + for (i = 0; i < sizeof(ColorItems) / sizeof(COLOR_ITEM); i++) + { + INT lvItemIndex; + + lvItemIndex = PhAddListViewItem(HighlightingListViewHandle, MAXINT, ColorItems[i].Name, &ColorItems[i]); + ColorItems[i].CurrentColor = PhGetIntegerSetting(ColorItems[i].SettingName); + ColorItems[i].CurrentUse = !!PhGetIntegerSetting(ColorItems[i].UseSettingName); + ListView_SetCheckState(HighlightingListViewHandle, lvItemIndex, ColorItems[i].CurrentUse); + } + } + break; + case WM_COMMAND: + { + switch (LOWORD(wParam)) + { + case IDC_ENABLEALL: + { + ULONG i; + + for (i = 0; i < sizeof(ColorItems) / sizeof(COLOR_ITEM); i++) + ListView_SetCheckState(HighlightingListViewHandle, i, TRUE); + } + break; + case IDC_DISABLEALL: + { + ULONG i; + + for (i = 0; i < sizeof(ColorItems) / sizeof(COLOR_ITEM); i++) + ListView_SetCheckState(HighlightingListViewHandle, i, FALSE); + } + break; + } + } + break; + case WM_NOTIFY: + { + LPNMHDR header = (LPNMHDR)lParam; + + switch (header->code) + { + case PSN_APPLY: + { + ULONG i; + + PH_SET_INTEGER_CACHED_SETTING(HighlightingDuration, GetDlgItemInt(hwndDlg, IDC_HIGHLIGHTINGDURATION, NULL, FALSE)); + PH_SET_INTEGER_CACHED_SETTING(ColorNew, ColorBox_GetColor(GetDlgItem(hwndDlg, IDC_NEWOBJECTS))); + PH_SET_INTEGER_CACHED_SETTING(ColorRemoved, ColorBox_GetColor(GetDlgItem(hwndDlg, IDC_REMOVEDOBJECTS))); + + for (i = 0; i < sizeof(ColorItems) / sizeof(COLOR_ITEM); i++) + { + ColorItems[i].CurrentUse = !!ListView_GetCheckState(HighlightingListViewHandle, i); + PhSetIntegerSetting(ColorItems[i].SettingName, ColorItems[i].CurrentColor); + PhSetIntegerSetting(ColorItems[i].UseSettingName, ColorItems[i].CurrentUse); + } + + SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_NOERROR); + } + return TRUE; + case NM_DBLCLK: + { + if (header->hwndFrom == HighlightingListViewHandle) + { + PCOLOR_ITEM item; + + if (item = PhGetSelectedListViewItemParam(HighlightingListViewHandle)) + { + CHOOSECOLOR chooseColor = { sizeof(chooseColor) }; + COLORREF customColors[16] = { 0 }; + + chooseColor.hwndOwner = hwndDlg; + chooseColor.rgbResult = item->CurrentColor; + chooseColor.lpCustColors = customColors; + chooseColor.Flags = CC_ANYCOLOR | CC_FULLOPEN | CC_RGBINIT; + + if (ChooseColor(&chooseColor)) + { + item->CurrentColor = chooseColor.rgbResult; + InvalidateRect(HighlightingListViewHandle, NULL, TRUE); + } + } + } + } + break; + case LVN_GETINFOTIP: + { + if (header->hwndFrom == HighlightingListViewHandle) + { + NMLVGETINFOTIP *getInfoTip = (NMLVGETINFOTIP *)lParam; + PH_STRINGREF tip; + + PhInitializeStringRefLongHint(&tip, ColorItems[getInfoTip->iItem].Description); + PhCopyListViewInfoTip(getInfoTip, &tip); + } + } + break; + } + } + break; + } + + REFLECT_MESSAGE_DLG(hwndDlg, HighlightingListViewHandle, uMsg, wParam, lParam); + + return FALSE; +} + +INT_PTR CALLBACK PhpOptionsGraphsDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + switch (uMsg) + { + case WM_INITDIALOG: + { + PhpPageInit(hwndDlg); + + // Show Text + SetDlgItemCheckForSetting(hwndDlg, IDC_SHOWTEXT, L"GraphShowText"); + SetDlgItemCheckForSetting(hwndDlg, IDC_USEOLDCOLORS, L"GraphColorMode"); + SetDlgItemCheckForSetting(hwndDlg, IDC_SHOWCOMMITINSUMMARY, L"ShowCommitInSummary"); + + ColorBox_SetColor(GetDlgItem(hwndDlg, IDC_CPUUSER), PhCsColorCpuUser); + ColorBox_SetColor(GetDlgItem(hwndDlg, IDC_CPUKERNEL), PhCsColorCpuKernel); + ColorBox_SetColor(GetDlgItem(hwndDlg, IDC_IORO), PhCsColorIoReadOther); + ColorBox_SetColor(GetDlgItem(hwndDlg, IDC_IOW), PhCsColorIoWrite); + ColorBox_SetColor(GetDlgItem(hwndDlg, IDC_PRIVATE), PhCsColorPrivate); + ColorBox_SetColor(GetDlgItem(hwndDlg, IDC_PHYSICAL), PhCsColorPhysical); + } + break; + case WM_NOTIFY: + { + LPNMHDR header = (LPNMHDR)lParam; + + switch (header->code) + { + case PSN_APPLY: + { + SetSettingForDlgItemCheck(hwndDlg, IDC_SHOWTEXT, L"GraphShowText"); + SetSettingForDlgItemCheck(hwndDlg, IDC_USEOLDCOLORS, L"GraphColorMode"); + SetSettingForDlgItemCheck(hwndDlg, IDC_SHOWCOMMITINSUMMARY, L"ShowCommitInSummary"); + PH_SET_INTEGER_CACHED_SETTING(ColorCpuUser, ColorBox_GetColor(GetDlgItem(hwndDlg, IDC_CPUUSER))); + PH_SET_INTEGER_CACHED_SETTING(ColorCpuKernel, ColorBox_GetColor(GetDlgItem(hwndDlg, IDC_CPUKERNEL))); + PH_SET_INTEGER_CACHED_SETTING(ColorIoReadOther, ColorBox_GetColor(GetDlgItem(hwndDlg, IDC_IORO))); + PH_SET_INTEGER_CACHED_SETTING(ColorIoWrite, ColorBox_GetColor(GetDlgItem(hwndDlg, IDC_IOW))); + PH_SET_INTEGER_CACHED_SETTING(ColorPrivate, ColorBox_GetColor(GetDlgItem(hwndDlg, IDC_PRIVATE))); + PH_SET_INTEGER_CACHED_SETTING(ColorPhysical, ColorBox_GetColor(GetDlgItem(hwndDlg, IDC_PHYSICAL))); + + SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_NOERROR); + } + return TRUE; + } + } + break; + } + + return FALSE; +} diff --git a/ProcessHacker/pagfiles.c b/ProcessHacker/pagfiles.c index 067e31ad334c..43fa8df9d759 100644 --- a/ProcessHacker/pagfiles.c +++ b/ProcessHacker/pagfiles.c @@ -1,159 +1,159 @@ -/* - * Process Hacker - - * pagefiles viewer - * - * Copyright (C) 2010 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include - -INT_PTR CALLBACK PhpPagefilesDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -VOID PhShowPagefilesDialog( - _In_ HWND ParentWindowHandle - ) -{ - DialogBox( - PhInstanceHandle, - MAKEINTRESOURCE(IDD_PAGEFILES), - ParentWindowHandle, - PhpPagefilesDlgProc - ); -} - -static VOID PhpAddPagefileItems( - _In_ HWND ListViewHandle, - _In_ PVOID Pagefiles - ) -{ - PSYSTEM_PAGEFILE_INFORMATION pagefile; - - pagefile = PH_FIRST_PAGEFILE(Pagefiles); - - while (pagefile) - { - INT lvItemIndex; - PPH_STRING fileName; - PPH_STRING newFileName; - PPH_STRING usage; - - fileName = PhCreateStringFromUnicodeString(&pagefile->PageFileName); - newFileName = PhGetFileName(fileName); - PhDereferenceObject(fileName); - - lvItemIndex = PhAddListViewItem(ListViewHandle, MAXINT, - newFileName->Buffer, NULL); - - PhDereferenceObject(newFileName); - - // Usage - usage = PhFormatSize(UInt32x32To64(pagefile->TotalInUse, PAGE_SIZE), -1); - PhSetListViewSubItem(ListViewHandle, lvItemIndex, 1, usage->Buffer); - PhDereferenceObject(usage); - - // Peak usage - usage = PhFormatSize(UInt32x32To64(pagefile->PeakUsage, PAGE_SIZE), -1); - PhSetListViewSubItem(ListViewHandle, lvItemIndex, 2, usage->Buffer); - PhDereferenceObject(usage); - - // Total - usage = PhFormatSize(UInt32x32To64(pagefile->TotalSize, PAGE_SIZE), -1); - PhSetListViewSubItem(ListViewHandle, lvItemIndex, 3, usage->Buffer); - PhDereferenceObject(usage); - - pagefile = PH_NEXT_PAGEFILE(pagefile); - } -} - -INT_PTR CALLBACK PhpPagefilesDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - switch (uMsg) - { - case WM_INITDIALOG: - { - NTSTATUS status; - HWND lvHandle; - PVOID pagefiles; - - PhCenterWindow(hwndDlg, GetParent(hwndDlg)); - - lvHandle = GetDlgItem(hwndDlg, IDC_LIST); - - PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 120, L"File name"); - PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 100, L"Usage"); - PhAddListViewColumn(lvHandle, 2, 2, 2, LVCFMT_LEFT, 100, L"Peak usage"); - PhAddListViewColumn(lvHandle, 3, 3, 3, LVCFMT_LEFT, 100, L"Total"); - PhSetListViewStyle(lvHandle, FALSE, TRUE); - PhSetControlTheme(lvHandle, L"explorer"); - - if (NT_SUCCESS(status = PhEnumPagefiles(&pagefiles))) - { - PhpAddPagefileItems(lvHandle, pagefiles); - PhFree(pagefiles); - } - else - { - PhShowStatus(hwndDlg, L"Unable to get pagefile information", status, 0); - EndDialog(hwndDlg, IDCANCEL); - } - - SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hwndDlg, IDOK), TRUE); - } - break; - case WM_COMMAND: - { - switch (LOWORD(wParam)) - { - case IDCANCEL: - case IDOK: - EndDialog(hwndDlg, IDOK); - break; - case IDC_REFRESH: - { - NTSTATUS status; - PVOID pagefiles; - - if (NT_SUCCESS(status = PhEnumPagefiles(&pagefiles))) - { - ListView_DeleteAllItems(GetDlgItem(hwndDlg, IDC_LIST)); - PhpAddPagefileItems(GetDlgItem(hwndDlg, IDC_LIST), pagefiles); - PhFree(pagefiles); - } - else - { - PhShowStatus(hwndDlg, L"Unable to get pagefile information", status, 0); - } - } - break; - } - } - break; - } - - return FALSE; -} +/* + * Process Hacker - + * pagefiles viewer + * + * Copyright (C) 2010 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include + +INT_PTR CALLBACK PhpPagefilesDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +VOID PhShowPagefilesDialog( + _In_ HWND ParentWindowHandle + ) +{ + DialogBox( + PhInstanceHandle, + MAKEINTRESOURCE(IDD_PAGEFILES), + ParentWindowHandle, + PhpPagefilesDlgProc + ); +} + +static VOID PhpAddPagefileItems( + _In_ HWND ListViewHandle, + _In_ PVOID Pagefiles + ) +{ + PSYSTEM_PAGEFILE_INFORMATION pagefile; + + pagefile = PH_FIRST_PAGEFILE(Pagefiles); + + while (pagefile) + { + INT lvItemIndex; + PPH_STRING fileName; + PPH_STRING newFileName; + PPH_STRING usage; + + fileName = PhCreateStringFromUnicodeString(&pagefile->PageFileName); + newFileName = PhGetFileName(fileName); + PhDereferenceObject(fileName); + + lvItemIndex = PhAddListViewItem(ListViewHandle, MAXINT, + newFileName->Buffer, NULL); + + PhDereferenceObject(newFileName); + + // Usage + usage = PhFormatSize(UInt32x32To64(pagefile->TotalInUse, PAGE_SIZE), -1); + PhSetListViewSubItem(ListViewHandle, lvItemIndex, 1, usage->Buffer); + PhDereferenceObject(usage); + + // Peak usage + usage = PhFormatSize(UInt32x32To64(pagefile->PeakUsage, PAGE_SIZE), -1); + PhSetListViewSubItem(ListViewHandle, lvItemIndex, 2, usage->Buffer); + PhDereferenceObject(usage); + + // Total + usage = PhFormatSize(UInt32x32To64(pagefile->TotalSize, PAGE_SIZE), -1); + PhSetListViewSubItem(ListViewHandle, lvItemIndex, 3, usage->Buffer); + PhDereferenceObject(usage); + + pagefile = PH_NEXT_PAGEFILE(pagefile); + } +} + +INT_PTR CALLBACK PhpPagefilesDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + switch (uMsg) + { + case WM_INITDIALOG: + { + NTSTATUS status; + HWND lvHandle; + PVOID pagefiles; + + PhCenterWindow(hwndDlg, GetParent(hwndDlg)); + + lvHandle = GetDlgItem(hwndDlg, IDC_LIST); + + PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 120, L"File name"); + PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 100, L"Usage"); + PhAddListViewColumn(lvHandle, 2, 2, 2, LVCFMT_LEFT, 100, L"Peak usage"); + PhAddListViewColumn(lvHandle, 3, 3, 3, LVCFMT_LEFT, 100, L"Total"); + PhSetListViewStyle(lvHandle, FALSE, TRUE); + PhSetControlTheme(lvHandle, L"explorer"); + + if (NT_SUCCESS(status = PhEnumPagefiles(&pagefiles))) + { + PhpAddPagefileItems(lvHandle, pagefiles); + PhFree(pagefiles); + } + else + { + PhShowStatus(hwndDlg, L"Unable to get pagefile information", status, 0); + EndDialog(hwndDlg, IDCANCEL); + } + + SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hwndDlg, IDOK), TRUE); + } + break; + case WM_COMMAND: + { + switch (LOWORD(wParam)) + { + case IDCANCEL: + case IDOK: + EndDialog(hwndDlg, IDOK); + break; + case IDC_REFRESH: + { + NTSTATUS status; + PVOID pagefiles; + + if (NT_SUCCESS(status = PhEnumPagefiles(&pagefiles))) + { + ListView_DeleteAllItems(GetDlgItem(hwndDlg, IDC_LIST)); + PhpAddPagefileItems(GetDlgItem(hwndDlg, IDC_LIST), pagefiles); + PhFree(pagefiles); + } + else + { + PhShowStatus(hwndDlg, L"Unable to get pagefile information", status, 0); + } + } + break; + } + } + break; + } + + return FALSE; +} diff --git a/ProcessHacker/pcre/pcre2_compile.c b/ProcessHacker/pcre/pcre2_compile.c index 0b93e22c4b23..0677e1fc6f19 100644 --- a/ProcessHacker/pcre/pcre2_compile.c +++ b/ProcessHacker/pcre/pcre2_compile.c @@ -1,9087 +1,9087 @@ -/************************************************* -* Perl-Compatible Regular Expressions * -*************************************************/ - -/* PCRE is a library of functions to support regular expressions whose syntax -and semantics are as close as possible to those of the Perl 5 language. - - Written by Philip Hazel - Original API code Copyright (c) 1997-2012 University of Cambridge - New API code Copyright (c) 2016 University of Cambridge - ------------------------------------------------------------------------------ -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - * Neither the name of the University of Cambridge nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. ------------------------------------------------------------------------------ -*/ - -// dmex: Disable warnings -#pragma warning(push) -#pragma warning(disable : 4244 4267) - -#define HAVE_CONFIG_H -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#define NLBLOCK cb /* Block containing newline information */ -#define PSSTART start_pattern /* Field containing processed string start */ -#define PSEND end_pattern /* Field containing processed string end */ - -#include "pcre2_internal.h" - -/* In rare error cases debugging might require calling pcre2_printint(). */ - -#if 0 -#ifdef EBCDIC -#define PRINTABLE(c) ((c) >= 64 && (c) < 255) -#else -#define PRINTABLE(c) ((c) >= 32 && (c) < 127) -#endif -#include "pcre2_printint.c" -#define CALL_PRINTINT -#endif - -/* There are a few things that vary with different code unit sizes. Handle them -by defining macros in order to minimize #if usage. */ - -#if PCRE2_CODE_UNIT_WIDTH == 8 -#define STRING_UTFn_RIGHTPAR STRING_UTF8_RIGHTPAR, 5 -#define XDIGIT(c) xdigitab[c] - -#else /* Either 16-bit or 32-bit */ -#define XDIGIT(c) (MAX_255(c)? xdigitab[c] : 0xff) - -#if PCRE2_CODE_UNIT_WIDTH == 16 -#define STRING_UTFn_RIGHTPAR STRING_UTF16_RIGHTPAR, 6 - -#else /* 32-bit */ -#define STRING_UTFn_RIGHTPAR STRING_UTF32_RIGHTPAR, 6 -#endif -#endif - -/* Function definitions to allow mutual recursion */ - -static unsigned int - add_list_to_class(uint8_t *, PCRE2_UCHAR **, uint32_t, compile_block *, - const uint32_t *, unsigned int); - -static BOOL - compile_regex(uint32_t, PCRE2_UCHAR **, PCRE2_SPTR *, int *, BOOL, BOOL, - uint32_t, int, uint32_t *, int32_t *, uint32_t *, int32_t *, - branch_chain *, compile_block *, size_t *); - - - -/************************************************* -* Code parameters and static tables * -*************************************************/ - -/* This value specifies the size of stack workspace, which is used in different -ways in the different pattern scans. The group-identifying pre-scan uses it to -handle nesting, and needs it to be 16-bit aligned. - -During the first compiling phase, when determining how much memory is required, -the regex is partly compiled into this space, but the compiled parts are -discarded as soon as they can be, so that hopefully there will never be an -overrun. The code does, however, check for an overrun, which can occur for -pathological patterns. The size of the workspace depends on LINK_SIZE because -the length of compiled items varies with this. - -In the real compile phase, the workspace is used for remembering data about -numbered groups, provided there are not too many of them (if there are, extra -memory is acquired). For this phase the memory must be 32-bit aligned. Having -defined the size in code units, we set up C32_WORK_SIZE as the number of -elements in the 32-bit vector. */ - -#define COMPILE_WORK_SIZE (2048*LINK_SIZE) /* Size in code units */ - -#define C32_WORK_SIZE \ - ((COMPILE_WORK_SIZE * sizeof(PCRE2_UCHAR))/sizeof(uint32_t)) - -/* The overrun tests check for a slightly smaller size so that they detect the -overrun before it actually does run off the end of the data block. */ - -#define WORK_SIZE_SAFETY_MARGIN (100) - -/* This value determines the size of the initial vector that is used for -remembering named groups during the pre-compile. It is allocated on the stack, -but if it is too small, it is expanded, in a similar way to the workspace. The -value is the number of slots in the list. */ - -#define NAMED_GROUP_LIST_SIZE 20 - -/* The original PCRE required patterns to be zero-terminated, and it simplifies -the compiling code if it is guaranteed that there is a zero code unit at the -end of the pattern, because this means that tests for coding sequences such as -(*SKIP) or even just (?<= can check a sequence of code units without having to -keep checking for the end of the pattern. The new PCRE2 API allows zero code -units within patterns if a positive length is given, but in order to keep most -of the compiling code as it was, we copy such patterns and add a zero on the -end. This value determines the size of space on the stack that is used if the -pattern fits; if not, heap memory is used. */ - -#define COPIED_PATTERN_SIZE 1024 - -/* Maximum length value to check against when making sure that the variable -that holds the compiled pattern length does not overflow. We make it a bit less -than INT_MAX to allow for adding in group terminating bytes, so that we don't -have to check them every time. */ - -#define OFLOW_MAX (INT_MAX - 20) - -/* Macro for setting individual bits in class bitmaps. It took some -experimenting to figure out how to stop gcc 5.3.0 from warning with --Wconversion. This version gets a warning: - - #define SETBIT(a,b) a[(b)/8] |= (uint8_t)(1 << ((b)&7)) - -Let's hope the apparently less efficient version isn't actually so bad if the -compiler is clever with identical subexpressions. */ - -#define SETBIT(a,b) a[(b)/8] = (uint8_t)(a[(b)/8] | (1 << ((b)&7))) - -/* Private flags added to firstcu and reqcu. */ - -#define REQ_CASELESS (1 << 0) /* Indicates caselessness */ -#define REQ_VARY (1 << 1) /* reqcu followed non-literal item */ -/* Negative values for the firstcu and reqcu flags */ -#define REQ_UNSET (-2) /* Not yet found anything */ -#define REQ_NONE (-1) /* Found not fixed char */ - -/* These flags are used in the groupinfo vector. */ - -#define GI_SET_COULD_BE_EMPTY 0x80000000u -#define GI_COULD_BE_EMPTY 0x40000000u -#define GI_NOT_FIXED_LENGTH 0x20000000u -#define GI_SET_FIXED_LENGTH 0x10000000u -#define GI_FIXED_LENGTH_MASK 0x0000ffffu - -/* This bit (which is greater than any UTF value) is used to indicate that a -variable contains a number of code units instead of an actual code point. */ - -#define UTF_LENGTH 0x10000000l - -/* This simple test for a decimal digit works for both ASCII/Unicode and EBCDIC -and is fast (a good compiler can turn it into a subtraction and unsigned -comparison). */ - -#define IS_DIGIT(x) ((x) >= CHAR_0 && (x) <= CHAR_9) - -/* Table to identify hex digits. The tables in chartables are dependent on the -locale, and may mark arbitrary characters as digits. We want to recognize only -0-9, a-z, and A-Z as hex digits, which is why we have a private table here. It -costs 256 bytes, but it is a lot faster than doing character value tests (at -least in some simple cases I timed), and in some applications one wants PCRE to -compile efficiently as well as match efficiently. The value in the table is -the binary hex digit value, or 0xff for non-hex digits. */ - -/* This is the "normal" case, for ASCII systems, and EBCDIC systems running in -UTF-8 mode. */ - -#ifndef EBCDIC -static const uint8_t xdigitab[] = - { - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 0- 7 */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 8- 15 */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 16- 23 */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 24- 31 */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* - ' */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* ( - / */ - 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, /* 0 - 7 */ - 0x08,0x09,0xff,0xff,0xff,0xff,0xff,0xff, /* 8 - ? */ - 0xff,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0xff, /* @ - G */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* H - O */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* P - W */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* X - _ */ - 0xff,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0xff, /* ` - g */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* h - o */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* p - w */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* x -127 */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 128-135 */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 136-143 */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 144-151 */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 152-159 */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 160-167 */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 168-175 */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 176-183 */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 184-191 */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 192-199 */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 2ff-207 */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 208-215 */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 216-223 */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 224-231 */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 232-239 */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 240-247 */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};/* 248-255 */ - -#else - -/* This is the "abnormal" case, for EBCDIC systems not running in UTF-8 mode. */ - -static const uint8_t xdigitab[] = - { - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 0- 7 0 */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 8- 15 */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 16- 23 10 */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 24- 31 */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 32- 39 20 */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 40- 47 */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 48- 55 30 */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 56- 63 */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* - 71 40 */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 72- | */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* & - 87 50 */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 88- 95 */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* - -103 60 */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 104- ? */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 112-119 70 */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 120- " */ - 0xff,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0xff, /* 128- g 80 */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* h -143 */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 144- p 90 */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* q -159 */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 160- x A0 */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* y -175 */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* ^ -183 B0 */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 184-191 */ - 0xff,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0xff, /* { - G C0 */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* H -207 */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* } - P D0 */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* Q -223 */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* \ - X E0 */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* Y -239 */ - 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, /* 0 - 7 F0 */ - 0x08,0x09,0xff,0xff,0xff,0xff,0xff,0xff};/* 8 -255 */ -#endif /* EBCDIC */ - - -/* Table for handling alphanumeric escaped characters. Positive returns are -simple data values; negative values are for special things like \d and so on. -Zero means further processing is needed (for things like \x), or the escape is -invalid. */ - -/* This is the "normal" table for ASCII systems or for EBCDIC systems running -in UTF-8 mode. It runs from '0' to 'z'. */ - -#ifndef EBCDIC -#define ESCAPES_FIRST CHAR_0 -#define ESCAPES_LAST CHAR_z -#define UPPER_CASE(c) (c-32) - -static const short int escapes[] = { - 0, 0, - 0, 0, - 0, 0, - 0, 0, - 0, 0, - CHAR_COLON, CHAR_SEMICOLON, - CHAR_LESS_THAN_SIGN, CHAR_EQUALS_SIGN, - CHAR_GREATER_THAN_SIGN, CHAR_QUESTION_MARK, - CHAR_COMMERCIAL_AT, -ESC_A, - -ESC_B, -ESC_C, - -ESC_D, -ESC_E, - 0, -ESC_G, - -ESC_H, 0, - 0, -ESC_K, - 0, 0, - -ESC_N, 0, - -ESC_P, -ESC_Q, - -ESC_R, -ESC_S, - 0, 0, - -ESC_V, -ESC_W, - -ESC_X, 0, - -ESC_Z, CHAR_LEFT_SQUARE_BRACKET, - CHAR_BACKSLASH, CHAR_RIGHT_SQUARE_BRACKET, - CHAR_CIRCUMFLEX_ACCENT, CHAR_UNDERSCORE, - CHAR_GRAVE_ACCENT, ESC_a, - -ESC_b, 0, - -ESC_d, ESC_e, - ESC_f, 0, - -ESC_h, 0, - 0, -ESC_k, - 0, 0, - ESC_n, 0, - -ESC_p, 0, - ESC_r, -ESC_s, - ESC_tee, 0, - -ESC_v, -ESC_w, - 0, 0, - -ESC_z -}; - -#else - -/* This is the "abnormal" table for EBCDIC systems without UTF-8 support. -It runs from 'a' to '9'. For some minimal testing of EBCDIC features, the code -is sometimes compiled on an ASCII system. In this case, we must not use CHAR_a -because it is defined as 'a', which of course picks up the ASCII value. */ - -#if 'a' == 0x81 /* Check for a real EBCDIC environment */ -#define ESCAPES_FIRST CHAR_a -#define ESCAPES_LAST CHAR_9 -#define UPPER_CASE(c) (c+64) -#else /* Testing in an ASCII environment */ -#define ESCAPES_FIRST ((unsigned char)'\x81') /* EBCDIC 'a' */ -#define ESCAPES_LAST ((unsigned char)'\xf9') /* EBCDIC '9' */ -#define UPPER_CASE(c) (c-32) -#endif - -static const short int escapes[] = { -/* 80 */ ESC_a, -ESC_b, 0, -ESC_d, ESC_e, ESC_f, 0, -/* 88 */-ESC_h, 0, 0, '{', 0, 0, 0, 0, -/* 90 */ 0, 0, -ESC_k, 0, 0, ESC_n, 0, -ESC_p, -/* 98 */ 0, ESC_r, 0, '}', 0, 0, 0, 0, -/* A0 */ 0, '~', -ESC_s, ESC_tee, 0,-ESC_v, -ESC_w, 0, -/* A8 */ 0,-ESC_z, 0, 0, 0, '[', 0, 0, -/* B0 */ 0, 0, 0, 0, 0, 0, 0, 0, -/* B8 */ 0, 0, 0, 0, 0, ']', '=', '-', -/* C0 */ '{',-ESC_A, -ESC_B, -ESC_C, -ESC_D,-ESC_E, 0, -ESC_G, -/* C8 */-ESC_H, 0, 0, 0, 0, 0, 0, 0, -/* D0 */ '}', 0, -ESC_K, 0, 0,-ESC_N, 0, -ESC_P, -/* D8 */-ESC_Q,-ESC_R, 0, 0, 0, 0, 0, 0, -/* E0 */ '\\', 0, -ESC_S, 0, 0,-ESC_V, -ESC_W, -ESC_X, -/* E8 */ 0,-ESC_Z, 0, 0, 0, 0, 0, 0, -/* F0 */ 0, 0, 0, 0, 0, 0, 0, 0, -/* F8 */ 0, 0 -}; - -/* We also need a table of characters that may follow \c in an EBCDIC -environment for characters 0-31. */ - -static unsigned char ebcdic_escape_c[] = "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"; - -#endif /* EBCDIC */ - - -/* Table of special "verbs" like (*PRUNE). This is a short table, so it is -searched linearly. Put all the names into a single string, in order to reduce -the number of relocations when a shared library is dynamically linked. The -string is built from string macros so that it works in UTF-8 mode on EBCDIC -platforms. */ - -typedef struct verbitem { - int len; /* Length of verb name */ - int op; /* Op when no arg, or -1 if arg mandatory */ - int op_arg; /* Op when arg present, or -1 if not allowed */ -} verbitem; - -static const char verbnames[] = - "\0" /* Empty name is a shorthand for MARK */ - STRING_MARK0 - STRING_ACCEPT0 - STRING_COMMIT0 - STRING_F0 - STRING_FAIL0 - STRING_PRUNE0 - STRING_SKIP0 - STRING_THEN; - -static const verbitem verbs[] = { - { 0, -1, OP_MARK }, - { 4, -1, OP_MARK }, - { 6, OP_ACCEPT, -1 }, - { 6, OP_COMMIT, -1 }, - { 1, OP_FAIL, -1 }, - { 4, OP_FAIL, -1 }, - { 5, OP_PRUNE, OP_PRUNE_ARG }, - { 4, OP_SKIP, OP_SKIP_ARG }, - { 4, OP_THEN, OP_THEN_ARG } -}; - -static const int verbcount = sizeof(verbs)/sizeof(verbitem); - - -/* Substitutes for [[:<:]] and [[:>:]], which mean start and end of word in -another regex library. */ - -static const PCRE2_UCHAR sub_start_of_word[] = { - CHAR_BACKSLASH, CHAR_b, CHAR_LEFT_PARENTHESIS, CHAR_QUESTION_MARK, - CHAR_EQUALS_SIGN, CHAR_BACKSLASH, CHAR_w, CHAR_RIGHT_PARENTHESIS, '\0' }; - -static const PCRE2_UCHAR sub_end_of_word[] = { - CHAR_BACKSLASH, CHAR_b, CHAR_LEFT_PARENTHESIS, CHAR_QUESTION_MARK, - CHAR_LESS_THAN_SIGN, CHAR_EQUALS_SIGN, CHAR_BACKSLASH, CHAR_w, - CHAR_RIGHT_PARENTHESIS, '\0' }; - - -/* Tables of names of POSIX character classes and their lengths. The names are -now all in a single string, to reduce the number of relocations when a shared -library is dynamically loaded. The list of lengths is terminated by a zero -length entry. The first three must be alpha, lower, upper, as this is assumed -for handling case independence. The indices for graph, print, and punct are -needed, so identify them. */ - -static const char posix_names[] = - STRING_alpha0 STRING_lower0 STRING_upper0 STRING_alnum0 - STRING_ascii0 STRING_blank0 STRING_cntrl0 STRING_digit0 - STRING_graph0 STRING_print0 STRING_punct0 STRING_space0 - STRING_word0 STRING_xdigit; - -static const uint8_t posix_name_lengths[] = { - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 6, 0 }; - -#define PC_GRAPH 8 -#define PC_PRINT 9 -#define PC_PUNCT 10 - - -/* Table of class bit maps for each POSIX class. Each class is formed from a -base map, with an optional addition or removal of another map. Then, for some -classes, there is some additional tweaking: for [:blank:] the vertical space -characters are removed, and for [:alpha:] and [:alnum:] the underscore -character is removed. The triples in the table consist of the base map offset, -second map offset or -1 if no second map, and a non-negative value for map -addition or a negative value for map subtraction (if there are two maps). The -absolute value of the third field has these meanings: 0 => no tweaking, 1 => -remove vertical space characters, 2 => remove underscore. */ - -static const int posix_class_maps[] = { - cbit_word, cbit_digit, -2, /* alpha */ - cbit_lower, -1, 0, /* lower */ - cbit_upper, -1, 0, /* upper */ - cbit_word, -1, 2, /* alnum - word without underscore */ - cbit_print, cbit_cntrl, 0, /* ascii */ - cbit_space, -1, 1, /* blank - a GNU extension */ - cbit_cntrl, -1, 0, /* cntrl */ - cbit_digit, -1, 0, /* digit */ - cbit_graph, -1, 0, /* graph */ - cbit_print, -1, 0, /* print */ - cbit_punct, -1, 0, /* punct */ - cbit_space, -1, 0, /* space */ - cbit_word, -1, 0, /* word - a Perl extension */ - cbit_xdigit,-1, 0 /* xdigit */ -}; - -/* Table of substitutes for \d etc when PCRE2_UCP is set. They are replaced by -Unicode property escapes. */ - -#ifdef SUPPORT_UNICODE -static const PCRE2_UCHAR string_PNd[] = { - CHAR_BACKSLASH, CHAR_P, CHAR_LEFT_CURLY_BRACKET, - CHAR_N, CHAR_d, CHAR_RIGHT_CURLY_BRACKET, '\0' }; -static const PCRE2_UCHAR string_pNd[] = { - CHAR_BACKSLASH, CHAR_p, CHAR_LEFT_CURLY_BRACKET, - CHAR_N, CHAR_d, CHAR_RIGHT_CURLY_BRACKET, '\0' }; -static const PCRE2_UCHAR string_PXsp[] = { - CHAR_BACKSLASH, CHAR_P, CHAR_LEFT_CURLY_BRACKET, - CHAR_X, CHAR_s, CHAR_p, CHAR_RIGHT_CURLY_BRACKET, '\0' }; -static const PCRE2_UCHAR string_pXsp[] = { - CHAR_BACKSLASH, CHAR_p, CHAR_LEFT_CURLY_BRACKET, - CHAR_X, CHAR_s, CHAR_p, CHAR_RIGHT_CURLY_BRACKET, '\0' }; -static const PCRE2_UCHAR string_PXwd[] = { - CHAR_BACKSLASH, CHAR_P, CHAR_LEFT_CURLY_BRACKET, - CHAR_X, CHAR_w, CHAR_d, CHAR_RIGHT_CURLY_BRACKET, '\0' }; -static const PCRE2_UCHAR string_pXwd[] = { - CHAR_BACKSLASH, CHAR_p, CHAR_LEFT_CURLY_BRACKET, - CHAR_X, CHAR_w, CHAR_d, CHAR_RIGHT_CURLY_BRACKET, '\0' }; - -static PCRE2_SPTR substitutes[] = { - string_PNd, /* \D */ - string_pNd, /* \d */ - string_PXsp, /* \S */ /* Xsp is Perl space, but from 8.34, Perl */ - string_pXsp, /* \s */ /* space and POSIX space are the same. */ - string_PXwd, /* \W */ - string_pXwd /* \w */ -}; - -/* The POSIX class substitutes must be in the order of the POSIX class names, -defined above, and there are both positive and negative cases. NULL means no -general substitute of a Unicode property escape (\p or \P). However, for some -POSIX classes (e.g. graph, print, punct) a special property code is compiled -directly. */ - -static const PCRE2_UCHAR string_pCc[] = { - CHAR_BACKSLASH, CHAR_p, CHAR_LEFT_CURLY_BRACKET, - CHAR_C, CHAR_c, CHAR_RIGHT_CURLY_BRACKET, '\0' }; -static const PCRE2_UCHAR string_pL[] = { - CHAR_BACKSLASH, CHAR_p, CHAR_LEFT_CURLY_BRACKET, - CHAR_L, CHAR_RIGHT_CURLY_BRACKET, '\0' }; -static const PCRE2_UCHAR string_pLl[] = { - CHAR_BACKSLASH, CHAR_p, CHAR_LEFT_CURLY_BRACKET, - CHAR_L, CHAR_l, CHAR_RIGHT_CURLY_BRACKET, '\0' }; -static const PCRE2_UCHAR string_pLu[] = { - CHAR_BACKSLASH, CHAR_p, CHAR_LEFT_CURLY_BRACKET, - CHAR_L, CHAR_u, CHAR_RIGHT_CURLY_BRACKET, '\0' }; -static const PCRE2_UCHAR string_pXan[] = { - CHAR_BACKSLASH, CHAR_p, CHAR_LEFT_CURLY_BRACKET, - CHAR_X, CHAR_a, CHAR_n, CHAR_RIGHT_CURLY_BRACKET, '\0' }; -static const PCRE2_UCHAR string_h[] = { - CHAR_BACKSLASH, CHAR_h, '\0' }; -static const PCRE2_UCHAR string_pXps[] = { - CHAR_BACKSLASH, CHAR_p, CHAR_LEFT_CURLY_BRACKET, - CHAR_X, CHAR_p, CHAR_s, CHAR_RIGHT_CURLY_BRACKET, '\0' }; -static const PCRE2_UCHAR string_PCc[] = { - CHAR_BACKSLASH, CHAR_P, CHAR_LEFT_CURLY_BRACKET, - CHAR_C, CHAR_c, CHAR_RIGHT_CURLY_BRACKET, '\0' }; -static const PCRE2_UCHAR string_PL[] = { - CHAR_BACKSLASH, CHAR_P, CHAR_LEFT_CURLY_BRACKET, - CHAR_L, CHAR_RIGHT_CURLY_BRACKET, '\0' }; -static const PCRE2_UCHAR string_PLl[] = { - CHAR_BACKSLASH, CHAR_P, CHAR_LEFT_CURLY_BRACKET, - CHAR_L, CHAR_l, CHAR_RIGHT_CURLY_BRACKET, '\0' }; -static const PCRE2_UCHAR string_PLu[] = { - CHAR_BACKSLASH, CHAR_P, CHAR_LEFT_CURLY_BRACKET, - CHAR_L, CHAR_u, CHAR_RIGHT_CURLY_BRACKET, '\0' }; -static const PCRE2_UCHAR string_PXan[] = { - CHAR_BACKSLASH, CHAR_P, CHAR_LEFT_CURLY_BRACKET, - CHAR_X, CHAR_a, CHAR_n, CHAR_RIGHT_CURLY_BRACKET, '\0' }; -static const PCRE2_UCHAR string_H[] = { - CHAR_BACKSLASH, CHAR_H, '\0' }; -static const PCRE2_UCHAR string_PXps[] = { - CHAR_BACKSLASH, CHAR_P, CHAR_LEFT_CURLY_BRACKET, - CHAR_X, CHAR_p, CHAR_s, CHAR_RIGHT_CURLY_BRACKET, '\0' }; - -static PCRE2_SPTR posix_substitutes[] = { - string_pL, /* alpha */ - string_pLl, /* lower */ - string_pLu, /* upper */ - string_pXan, /* alnum */ - NULL, /* ascii */ - string_h, /* blank */ - string_pCc, /* cntrl */ - string_pNd, /* digit */ - NULL, /* graph */ - NULL, /* print */ - NULL, /* punct */ - string_pXps, /* space */ /* Xps is POSIX space, but from 8.34 */ - string_pXwd, /* word */ /* Perl and POSIX space are the same */ - NULL, /* xdigit */ - /* Negated cases */ - string_PL, /* ^alpha */ - string_PLl, /* ^lower */ - string_PLu, /* ^upper */ - string_PXan, /* ^alnum */ - NULL, /* ^ascii */ - string_H, /* ^blank */ - string_PCc, /* ^cntrl */ - string_PNd, /* ^digit */ - NULL, /* ^graph */ - NULL, /* ^print */ - NULL, /* ^punct */ - string_PXps, /* ^space */ /* Xps is POSIX space, but from 8.34 */ - string_PXwd, /* ^word */ /* Perl and POSIX space are the same */ - NULL /* ^xdigit */ -}; -#define POSIX_SUBSIZE (sizeof(posix_substitutes) / sizeof(PCRE2_UCHAR *)) -#endif /* SUPPORT_UNICODE */ - -/* Masks for checking option settings. */ - -#define PUBLIC_COMPILE_OPTIONS \ - (PCRE2_ANCHORED|PCRE2_ALLOW_EMPTY_CLASS|PCRE2_ALT_BSUX|PCRE2_ALT_CIRCUMFLEX| \ - PCRE2_ALT_VERBNAMES|PCRE2_AUTO_CALLOUT|PCRE2_CASELESS|PCRE2_DOLLAR_ENDONLY| \ - PCRE2_DOTALL|PCRE2_DUPNAMES|PCRE2_EXTENDED|PCRE2_FIRSTLINE| \ - PCRE2_MATCH_UNSET_BACKREF|PCRE2_MULTILINE|PCRE2_NEVER_BACKSLASH_C| \ - PCRE2_NEVER_UCP|PCRE2_NEVER_UTF|PCRE2_NO_AUTO_CAPTURE| \ - PCRE2_NO_AUTO_POSSESS|PCRE2_NO_DOTSTAR_ANCHOR|PCRE2_NO_START_OPTIMIZE| \ - PCRE2_NO_UTF_CHECK|PCRE2_UCP|PCRE2_UNGREEDY|PCRE2_USE_OFFSET_LIMIT| \ - PCRE2_UTF) - -/* Compile time error code numbers. They are given names so that they can more -easily be tracked. When a new number is added, the tables called eint1 and -eint2 in pcre2posix.c may need to be updated, and a new error text must be -added to compile_error_texts in pcre2_error.c. */ - -enum { ERR0 = COMPILE_ERROR_BASE, - ERR1, ERR2, ERR3, ERR4, ERR5, ERR6, ERR7, ERR8, ERR9, ERR10, - ERR11, ERR12, ERR13, ERR14, ERR15, ERR16, ERR17, ERR18, ERR19, ERR20, - ERR21, ERR22, ERR23, ERR24, ERR25, ERR26, ERR27, ERR28, ERR29, ERR30, - ERR31, ERR32, ERR33, ERR34, ERR35, ERR36, ERR37, ERR38, ERR39, ERR40, - ERR41, ERR42, ERR43, ERR44, ERR45, ERR46, ERR47, ERR48, ERR49, ERR50, - ERR51, ERR52, ERR53, ERR54, ERR55, ERR56, ERR57, ERR58, ERR59, ERR60, - ERR61, ERR62, ERR63, ERR64, ERR65, ERR66, ERR67, ERR68, ERR69, ERR70, - ERR71, ERR72, ERR73, ERR74, ERR75, ERR76, ERR77, ERR78, ERR79, ERR80, - ERR81, ERR82, ERR83, ERR84, ERR85, ERR86, ERR87, ERR88 }; - -/* Error codes that correspond to negative error codes returned by -find_fixedlength(). */ - -static int fixed_length_errors[] = - { - ERR0, /* Not an error */ - ERR0, /* Not an error; -1 is used for "process later" */ - ERR25, /* Lookbehind is not fixed length */ - ERR36, /* \C in lookbehind is not allowed */ - ERR87, /* Lookbehind is too long */ - ERR86, /* Pattern too complicated */ - ERR70 /* Internal error: unknown opcode encountered */ - }; - -/* This is a table of start-of-pattern options such as (*UTF) and settings such -as (*LIMIT_MATCH=nnnn) and (*CRLF). For completeness and backward -compatibility, (*UTFn) is supported in the relevant libraries, but (*UTF) is -generic and always supported. */ - -enum { PSO_OPT, /* Value is an option bit */ - PSO_FLG, /* Value is a flag bit */ - PSO_NL, /* Value is a newline type */ - PSO_BSR, /* Value is a \R type */ - PSO_LIMM, /* Read integer value for match limit */ - PSO_LIMR }; /* Read integer value for recursion limit */ - -typedef struct pso { - const uint8_t *name; - uint16_t length; - uint16_t type; - uint32_t value; -} pso; - -/* NB: STRING_UTFn_RIGHTPAR contains the length as well */ - -static pso pso_list[] = { - { (uint8_t *)STRING_UTFn_RIGHTPAR, PSO_OPT, PCRE2_UTF }, - { (uint8_t *)STRING_UTF_RIGHTPAR, 4, PSO_OPT, PCRE2_UTF }, - { (uint8_t *)STRING_UCP_RIGHTPAR, 4, PSO_OPT, PCRE2_UCP }, - { (uint8_t *)STRING_NOTEMPTY_RIGHTPAR, 9, PSO_FLG, PCRE2_NOTEMPTY_SET }, - { (uint8_t *)STRING_NOTEMPTY_ATSTART_RIGHTPAR, 17, PSO_FLG, PCRE2_NE_ATST_SET }, - { (uint8_t *)STRING_NO_AUTO_POSSESS_RIGHTPAR, 16, PSO_OPT, PCRE2_NO_AUTO_POSSESS }, - { (uint8_t *)STRING_NO_DOTSTAR_ANCHOR_RIGHTPAR, 18, PSO_OPT, PCRE2_NO_DOTSTAR_ANCHOR }, - { (uint8_t *)STRING_NO_JIT_RIGHTPAR, 7, PSO_FLG, PCRE2_NOJIT }, - { (uint8_t *)STRING_NO_START_OPT_RIGHTPAR, 13, PSO_OPT, PCRE2_NO_START_OPTIMIZE }, - { (uint8_t *)STRING_LIMIT_MATCH_EQ, 12, PSO_LIMM, 0 }, - { (uint8_t *)STRING_LIMIT_RECURSION_EQ, 16, PSO_LIMR, 0 }, - { (uint8_t *)STRING_CR_RIGHTPAR, 3, PSO_NL, PCRE2_NEWLINE_CR }, - { (uint8_t *)STRING_LF_RIGHTPAR, 3, PSO_NL, PCRE2_NEWLINE_LF }, - { (uint8_t *)STRING_CRLF_RIGHTPAR, 5, PSO_NL, PCRE2_NEWLINE_CRLF }, - { (uint8_t *)STRING_ANY_RIGHTPAR, 4, PSO_NL, PCRE2_NEWLINE_ANY }, - { (uint8_t *)STRING_ANYCRLF_RIGHTPAR, 8, PSO_NL, PCRE2_NEWLINE_ANYCRLF }, - { (uint8_t *)STRING_BSR_ANYCRLF_RIGHTPAR, 12, PSO_BSR, PCRE2_BSR_ANYCRLF }, - { (uint8_t *)STRING_BSR_UNICODE_RIGHTPAR, 12, PSO_BSR, PCRE2_BSR_UNICODE } -}; - -/* This table is used when converting repeating opcodes into possessified -versions as a result of an explicit possessive quantifier such as ++. A zero -value means there is no possessified version - in those cases the item in -question must be wrapped in ONCE brackets. The table is truncated at OP_CALLOUT -because all relevant opcodes are less than that. */ - -static const uint8_t opcode_possessify[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0 - 15 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 16 - 31 */ - - 0, /* NOTI */ - OP_POSSTAR, 0, /* STAR, MINSTAR */ - OP_POSPLUS, 0, /* PLUS, MINPLUS */ - OP_POSQUERY, 0, /* QUERY, MINQUERY */ - OP_POSUPTO, 0, /* UPTO, MINUPTO */ - 0, /* EXACT */ - 0, 0, 0, 0, /* POS{STAR,PLUS,QUERY,UPTO} */ - - OP_POSSTARI, 0, /* STARI, MINSTARI */ - OP_POSPLUSI, 0, /* PLUSI, MINPLUSI */ - OP_POSQUERYI, 0, /* QUERYI, MINQUERYI */ - OP_POSUPTOI, 0, /* UPTOI, MINUPTOI */ - 0, /* EXACTI */ - 0, 0, 0, 0, /* POS{STARI,PLUSI,QUERYI,UPTOI} */ - - OP_NOTPOSSTAR, 0, /* NOTSTAR, NOTMINSTAR */ - OP_NOTPOSPLUS, 0, /* NOTPLUS, NOTMINPLUS */ - OP_NOTPOSQUERY, 0, /* NOTQUERY, NOTMINQUERY */ - OP_NOTPOSUPTO, 0, /* NOTUPTO, NOTMINUPTO */ - 0, /* NOTEXACT */ - 0, 0, 0, 0, /* NOTPOS{STAR,PLUS,QUERY,UPTO} */ - - OP_NOTPOSSTARI, 0, /* NOTSTARI, NOTMINSTARI */ - OP_NOTPOSPLUSI, 0, /* NOTPLUSI, NOTMINPLUSI */ - OP_NOTPOSQUERYI, 0, /* NOTQUERYI, NOTMINQUERYI */ - OP_NOTPOSUPTOI, 0, /* NOTUPTOI, NOTMINUPTOI */ - 0, /* NOTEXACTI */ - 0, 0, 0, 0, /* NOTPOS{STARI,PLUSI,QUERYI,UPTOI} */ - - OP_TYPEPOSSTAR, 0, /* TYPESTAR, TYPEMINSTAR */ - OP_TYPEPOSPLUS, 0, /* TYPEPLUS, TYPEMINPLUS */ - OP_TYPEPOSQUERY, 0, /* TYPEQUERY, TYPEMINQUERY */ - OP_TYPEPOSUPTO, 0, /* TYPEUPTO, TYPEMINUPTO */ - 0, /* TYPEEXACT */ - 0, 0, 0, 0, /* TYPEPOS{STAR,PLUS,QUERY,UPTO} */ - - OP_CRPOSSTAR, 0, /* CRSTAR, CRMINSTAR */ - OP_CRPOSPLUS, 0, /* CRPLUS, CRMINPLUS */ - OP_CRPOSQUERY, 0, /* CRQUERY, CRMINQUERY */ - OP_CRPOSRANGE, 0, /* CRRANGE, CRMINRANGE */ - 0, 0, 0, 0, /* CRPOS{STAR,PLUS,QUERY,RANGE} */ - - 0, 0, 0, /* CLASS, NCLASS, XCLASS */ - 0, 0, /* REF, REFI */ - 0, 0, /* DNREF, DNREFI */ - 0, 0 /* RECURSE, CALLOUT */ -}; - - - -/************************************************* -* Copy compiled code * -*************************************************/ - -/* Compiled JIT code cannot be copied, so the new compiled block has no -associated JIT data. */ - -PCRE2_EXP_DEFN pcre2_code * PCRE2_CALL_CONVENTION -pcre2_code_copy(const pcre2_code *code) -{ -PCRE2_SIZE* ref_count; -pcre2_code *newcode; - -if (code == NULL) return NULL; -newcode = code->memctl.malloc(code->blocksize, code->memctl.memory_data); -if (newcode == NULL) return NULL; -memcpy(newcode, code, code->blocksize); -newcode->executable_jit = NULL; - -/* If the code is one that has been deserialized, increment the reference count -in the decoded tables. */ - -if ((code->flags & PCRE2_DEREF_TABLES) != 0) - { - ref_count = (PCRE2_SIZE *)(code->tables + tables_length); - (*ref_count)++; - } - -return newcode; -} - - - -/************************************************* -* Free compiled code * -*************************************************/ - -PCRE2_EXP_DEFN void PCRE2_CALL_CONVENTION -pcre2_code_free(pcre2_code *code) -{ -PCRE2_SIZE* ref_count; - -if (code != NULL) - { - if (code->executable_jit != NULL) - PRIV(jit_free)(code->executable_jit, &code->memctl); - - if ((code->flags & PCRE2_DEREF_TABLES) != 0) - { - /* Decoded tables belong to the codes after deserialization, and they must - be freed when there are no more reference to them. The *ref_count should - always be > 0. */ - - ref_count = (PCRE2_SIZE *)(code->tables + tables_length); - if (*ref_count > 0) - { - (*ref_count)--; - if (*ref_count == 0) - code->memctl.free((void *)code->tables, code->memctl.memory_data); - } - } - - code->memctl.free(code, code->memctl.memory_data); - } -} - - - -/************************************************* -* Insert an automatic callout point * -*************************************************/ - -/* This function is called when the PCRE2_AUTO_CALLOUT option is set, to insert -callout points before each pattern item. - -Arguments: - code current code pointer - ptr current pattern pointer - cb general compile-time data - -Returns: new code pointer -*/ - -static PCRE2_UCHAR * -auto_callout(PCRE2_UCHAR *code, PCRE2_SPTR ptr, compile_block *cb) -{ -code[0] = OP_CALLOUT; -PUT(code, 1, ptr - cb->start_pattern); /* Pattern offset */ -PUT(code, 1 + LINK_SIZE, 0); /* Default length */ -code[1 + 2*LINK_SIZE] = 255; -return code + PRIV(OP_lengths)[OP_CALLOUT]; -} - - - -/************************************************* -* Complete a callout item * -*************************************************/ - -/* A callout item contains the length of the next item in the pattern, which -we can't fill in till after we have reached the relevant point. This is used -for both automatic and manual callouts. - -Arguments: - previous_callout points to previous callout item - ptr current pattern pointer - cb general compile-time data - -Returns: nothing -*/ - -static void -complete_callout(PCRE2_UCHAR *previous_callout, PCRE2_SPTR ptr, - compile_block *cb) -{ -size_t length = (size_t)(ptr - cb->start_pattern - GET(previous_callout, 1)); -PUT(previous_callout, 1 + LINK_SIZE, length); -} - - - -/************************************************* -* Find the fixed length of a branch * -*************************************************/ - -/* Scan a branch and compute the fixed length of subject that will match it, if -the length is fixed. This is needed for dealing with lookbehind assertions. In -UTF mode, the result is in code units rather than bytes. The branch is -temporarily terminated with OP_END when this function is called. - -This function is called when a lookbehind assertion is encountered, so that if -it fails, the error message can point to the correct place in the pattern. -However, we cannot do this when the assertion contains subroutine calls, -because they can be forward references. We solve this by remembering this case -and doing the check at the end; a flag specifies which mode we are running in. - -Lookbehind lengths are held in 16-bit fields and the maximum value is defined -as LOOKBEHIND_MAX. - -Arguments: - code points to the start of the pattern (the bracket) - utf TRUE in UTF mode - atend TRUE if called when the pattern is complete - cb the "compile data" structure - recurses chain of recurse_check to catch mutual recursion - countptr pointer to counter, to catch over-complexity - -Returns: if non-negative, the fixed length, - or -1 if an OP_RECURSE item was encountered and atend is FALSE - or -2 if there is no fixed length, - or -3 if \C was encountered (in UTF mode only) - or -4 if length is too long - or -5 if regex is too complicated - or -6 if an unknown opcode was encountered (internal error) -*/ - -#define FFL_LATER (-1) -#define FFL_NOTFIXED (-2) -#define FFL_BACKSLASHC (-3) -#define FFL_TOOLONG (-4) -#define FFL_TOOCOMPLICATED (-5) -#define FFL_UNKNOWNOP (-6) - -static int -find_fixedlength(PCRE2_UCHAR *code, BOOL utf, BOOL atend, compile_block *cb, - recurse_check *recurses, int *countptr) -{ -uint32_t length = 0xffffffffu; /* Unset */ -uint32_t group = 0; -uint32_t groupinfo = 0; -recurse_check this_recurse; -register uint32_t branchlength = 0; -register PCRE2_UCHAR *cc = code + 1 + LINK_SIZE; - -/* If this is a capturing group, we may have the answer cached, but we can only -use this information if there are no (?| groups in the pattern, because -otherwise group numbers are not unique. */ - -if (*code == OP_CBRA || *code == OP_CBRAPOS || *code == OP_SCBRA || - *code == OP_SCBRAPOS) - { - group = GET2(cc, 0); - cc += IMM2_SIZE; - groupinfo = cb->groupinfo[group]; - if ((cb->external_flags & PCRE2_DUPCAPUSED) == 0) - { - if ((groupinfo & GI_NOT_FIXED_LENGTH) != 0) return FFL_NOTFIXED; - if ((groupinfo & GI_SET_FIXED_LENGTH) != 0) - return groupinfo & GI_FIXED_LENGTH_MASK; - } - } - -/* A large and/or complex regex can take too long to process. This can happen -more often when (?| groups are present in the pattern. */ - -if ((*countptr)++ > 2000) return FFL_TOOCOMPLICATED; - -/* Scan along the opcodes for this branch. If we get to the end of the -branch, check the length against that of the other branches. */ - -for (;;) - { - int d; - PCRE2_UCHAR *ce, *cs; - register PCRE2_UCHAR op = *cc; - - if (branchlength > LOOKBEHIND_MAX) return FFL_TOOLONG; - - switch (op) - { - /* We only need to continue for OP_CBRA (normal capturing bracket) and - OP_BRA (normal non-capturing bracket) because the other variants of these - opcodes are all concerned with unlimited repeated groups, which of course - are not of fixed length. */ - - case OP_CBRA: - case OP_BRA: - case OP_ONCE: - case OP_ONCE_NC: - case OP_COND: - d = find_fixedlength(cc, utf, atend, cb, recurses, countptr); - if (d < 0) return d; - branchlength += (uint32_t)d; - do cc += GET(cc, 1); while (*cc == OP_ALT); - cc += 1 + LINK_SIZE; - break; - - /* Reached end of a branch; if it's a ket it is the end of a nested call. - If it's ALT it is an alternation in a nested call. An ACCEPT is effectively - an ALT. If it is END it's the end of the outer call. All can be handled by - the same code. Note that we must not include the OP_KETRxxx opcodes here, - because they all imply an unlimited repeat. */ - - case OP_ALT: - case OP_KET: - case OP_END: - case OP_ACCEPT: - case OP_ASSERT_ACCEPT: - if (length == 0xffffffffu) length = branchlength; - else if (length != branchlength) goto ISNOTFIXED; - if (*cc != OP_ALT) - { - if (group > 0) - { - groupinfo |= (uint32_t)(GI_SET_FIXED_LENGTH | length); - cb->groupinfo[group] = groupinfo; - } - return (int)length; - } - cc += 1 + LINK_SIZE; - branchlength = 0; - break; - - /* A true recursion implies not fixed length, but a subroutine call may - be OK. If the subroutine is a forward reference, we can't deal with - it until the end of the pattern, so return FFL_LATER. */ - - case OP_RECURSE: - if (!atend) return FFL_LATER; - cs = ce = (PCRE2_UCHAR *)cb->start_code + GET(cc, 1); /* Start subpattern */ - do ce += GET(ce, 1); while (*ce == OP_ALT); /* End subpattern */ - if (cc > cs && cc < ce) goto ISNOTFIXED; /* Recursion */ - else /* Check for mutual recursion */ - { - recurse_check *r = recurses; - for (r = recurses; r != NULL; r = r->prev) if (r->group == cs) break; - if (r != NULL) goto ISNOTFIXED; /* Mutual recursion */ - } - this_recurse.prev = recurses; - this_recurse.group = cs; - d = find_fixedlength(cs, utf, atend, cb, &this_recurse, countptr); - if (d < 0) return d; - branchlength += (uint32_t)d; - cc += 1 + LINK_SIZE; - break; - - /* Skip over assertive subpatterns. Note that we must increment cc by - 1 + LINK_SIZE at the end, not by OP_length[*cc] because in a recursive - situation this assertion may be the one that is ultimately being checked - for having a fixed length, in which case its terminating OP_KET will have - been temporarily replaced by OP_END. */ - - case OP_ASSERT: - case OP_ASSERT_NOT: - case OP_ASSERTBACK: - case OP_ASSERTBACK_NOT: - do cc += GET(cc, 1); while (*cc == OP_ALT); - cc += 1 + LINK_SIZE; - break; - - /* Skip over things that don't match chars */ - - case OP_MARK: - case OP_PRUNE_ARG: - case OP_SKIP_ARG: - case OP_THEN_ARG: - cc += cc[1] + PRIV(OP_lengths)[*cc]; - break; - - case OP_CALLOUT: - case OP_CIRC: - case OP_CIRCM: - case OP_CLOSE: - case OP_COMMIT: - case OP_CREF: - case OP_FALSE: - case OP_TRUE: - case OP_DNCREF: - case OP_DNRREF: - case OP_DOLL: - case OP_DOLLM: - case OP_EOD: - case OP_EODN: - case OP_FAIL: - case OP_NOT_WORD_BOUNDARY: - case OP_PRUNE: - case OP_REVERSE: - case OP_RREF: - case OP_SET_SOM: - case OP_SKIP: - case OP_SOD: - case OP_SOM: - case OP_THEN: - case OP_WORD_BOUNDARY: - cc += PRIV(OP_lengths)[*cc]; - break; - - case OP_CALLOUT_STR: - cc += GET(cc, 1 + 2*LINK_SIZE); - break; - - /* Handle literal characters */ - - case OP_CHAR: - case OP_CHARI: - case OP_NOT: - case OP_NOTI: - branchlength++; - cc += 2; -#ifdef SUPPORT_UNICODE - if (utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]); -#endif - break; - - /* Handle exact repetitions. The count is already in characters, but we - need to skip over a multibyte character in UTF8 mode. */ - - case OP_EXACT: - case OP_EXACTI: - case OP_NOTEXACT: - case OP_NOTEXACTI: - branchlength += GET2(cc,1); - cc += 2 + IMM2_SIZE; -#ifdef SUPPORT_UNICODE - if (utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]); -#endif - break; - - case OP_TYPEEXACT: - branchlength += GET2(cc,1); - if (cc[1 + IMM2_SIZE] == OP_PROP || cc[1 + IMM2_SIZE] == OP_NOTPROP) - cc += 2; - cc += 1 + IMM2_SIZE + 1; - break; - - /* Handle single-char matchers */ - - case OP_PROP: - case OP_NOTPROP: - cc += 2; - /* Fall through */ - - case OP_HSPACE: - case OP_VSPACE: - case OP_NOT_HSPACE: - case OP_NOT_VSPACE: - case OP_NOT_DIGIT: - case OP_DIGIT: - case OP_NOT_WHITESPACE: - case OP_WHITESPACE: - case OP_NOT_WORDCHAR: - case OP_WORDCHAR: - case OP_ANY: - case OP_ALLANY: - branchlength++; - cc++; - break; - - /* The single-byte matcher isn't allowed. This only happens in UTF-8 or - UTF-16 mode; otherwise \C is coded as OP_ALLANY. */ - - case OP_ANYBYTE: - return FFL_BACKSLASHC; - - /* Check a class for variable quantification */ - - case OP_CLASS: - case OP_NCLASS: -#ifdef SUPPORT_WIDE_CHARS - case OP_XCLASS: - /* The original code caused an unsigned overflow in 64 bit systems, - so now we use a conditional statement. */ - if (op == OP_XCLASS) - cc += GET(cc, 1); - else - cc += PRIV(OP_lengths)[OP_CLASS]; -#else - cc += PRIV(OP_lengths)[OP_CLASS]; -#endif - - switch (*cc) - { - case OP_CRSTAR: - case OP_CRMINSTAR: - case OP_CRPLUS: - case OP_CRMINPLUS: - case OP_CRQUERY: - case OP_CRMINQUERY: - case OP_CRPOSSTAR: - case OP_CRPOSPLUS: - case OP_CRPOSQUERY: - goto ISNOTFIXED; - - case OP_CRRANGE: - case OP_CRMINRANGE: - case OP_CRPOSRANGE: - if (GET2(cc,1) != GET2(cc,1+IMM2_SIZE)) goto ISNOTFIXED; - branchlength += GET2(cc,1); - cc += 1 + 2 * IMM2_SIZE; - break; - - default: - branchlength++; - } - break; - - /* Anything else is variable length */ - - case OP_ANYNL: - case OP_BRAMINZERO: - case OP_BRAPOS: - case OP_BRAPOSZERO: - case OP_BRAZERO: - case OP_CBRAPOS: - case OP_EXTUNI: - case OP_KETRMAX: - case OP_KETRMIN: - case OP_KETRPOS: - case OP_MINPLUS: - case OP_MINPLUSI: - case OP_MINQUERY: - case OP_MINQUERYI: - case OP_MINSTAR: - case OP_MINSTARI: - case OP_MINUPTO: - case OP_MINUPTOI: - case OP_NOTMINPLUS: - case OP_NOTMINPLUSI: - case OP_NOTMINQUERY: - case OP_NOTMINQUERYI: - case OP_NOTMINSTAR: - case OP_NOTMINSTARI: - case OP_NOTMINUPTO: - case OP_NOTMINUPTOI: - case OP_NOTPLUS: - case OP_NOTPLUSI: - case OP_NOTPOSPLUS: - case OP_NOTPOSPLUSI: - case OP_NOTPOSQUERY: - case OP_NOTPOSQUERYI: - case OP_NOTPOSSTAR: - case OP_NOTPOSSTARI: - case OP_NOTPOSUPTO: - case OP_NOTPOSUPTOI: - case OP_NOTQUERY: - case OP_NOTQUERYI: - case OP_NOTSTAR: - case OP_NOTSTARI: - case OP_NOTUPTO: - case OP_NOTUPTOI: - case OP_PLUS: - case OP_PLUSI: - case OP_POSPLUS: - case OP_POSPLUSI: - case OP_POSQUERY: - case OP_POSQUERYI: - case OP_POSSTAR: - case OP_POSSTARI: - case OP_POSUPTO: - case OP_POSUPTOI: - case OP_QUERY: - case OP_QUERYI: - case OP_REF: - case OP_REFI: - case OP_DNREF: - case OP_DNREFI: - case OP_SBRA: - case OP_SBRAPOS: - case OP_SCBRA: - case OP_SCBRAPOS: - case OP_SCOND: - case OP_SKIPZERO: - case OP_STAR: - case OP_STARI: - case OP_TYPEMINPLUS: - case OP_TYPEMINQUERY: - case OP_TYPEMINSTAR: - case OP_TYPEMINUPTO: - case OP_TYPEPLUS: - case OP_TYPEPOSPLUS: - case OP_TYPEPOSQUERY: - case OP_TYPEPOSSTAR: - case OP_TYPEPOSUPTO: - case OP_TYPEQUERY: - case OP_TYPESTAR: - case OP_TYPEUPTO: - case OP_UPTO: - case OP_UPTOI: - goto ISNOTFIXED; - - /* Catch unrecognized opcodes so that when new ones are added they - are not forgotten, as has happened in the past. */ - - default: - return FFL_UNKNOWNOP; - } - } -/* Control never gets here except by goto. */ - -ISNOTFIXED: -if (group > 0) - { - groupinfo |= GI_NOT_FIXED_LENGTH; - cb->groupinfo[group] = groupinfo; - } -return FFL_NOTFIXED; -} - - - -/************************************************* -* Find first significant op code * -*************************************************/ - -/* This is called by several functions that scan a compiled expression looking -for a fixed first character, or an anchoring op code etc. It skips over things -that do not influence this. For some calls, it makes sense to skip negative -forward and all backward assertions, and also the \b assertion; for others it -does not. - -Arguments: - code pointer to the start of the group - skipassert TRUE if certain assertions are to be skipped - -Returns: pointer to the first significant opcode -*/ - -static const PCRE2_UCHAR* -first_significant_code(PCRE2_SPTR code, BOOL skipassert) -{ -for (;;) - { - switch ((int)*code) - { - case OP_ASSERT_NOT: - case OP_ASSERTBACK: - case OP_ASSERTBACK_NOT: - if (!skipassert) return code; - do code += GET(code, 1); while (*code == OP_ALT); - code += PRIV(OP_lengths)[*code]; - break; - - case OP_WORD_BOUNDARY: - case OP_NOT_WORD_BOUNDARY: - if (!skipassert) return code; - /* Fall through */ - - case OP_CALLOUT: - case OP_CREF: - case OP_DNCREF: - case OP_RREF: - case OP_DNRREF: - case OP_FALSE: - case OP_TRUE: - code += PRIV(OP_lengths)[*code]; - break; - - case OP_CALLOUT_STR: - code += GET(code, 1 + 2*LINK_SIZE); - break; - - default: - return code; - } - } -/* Control never reaches here */ -} - - - -/************************************************* -* Scan compiled branch for non-emptiness * -*************************************************/ - -/* This function scans through a branch of a compiled pattern to see whether it -can match the empty string. It is called at the end of compiling to check the -entire pattern, and from compile_branch() when checking for an unlimited repeat -of a group that can match nothing. In the latter case it is called only when -doing the real compile, not during the pre-compile that measures the size of -the compiled pattern. - -Note that first_significant_code() skips over backward and negative forward -assertions when its final argument is TRUE. If we hit an unclosed bracket, we -return "empty" - this means we've struck an inner bracket whose current branch -will already have been scanned. - -Arguments: - code points to start of search - endcode points to where to stop - utf TRUE if in UTF mode - cb compile data - atend TRUE if being called to check an entire pattern - recurses chain of recurse_check to catch mutual recursion - countptr pointer to count to catch over-complicated pattern - -Returns: 0 if what is matched cannot be empty - 1 if what is matched could be empty - -1 if the pattern is too complicated -*/ - -#define CBE_NOTEMPTY 0 -#define CBE_EMPTY 1 -#define CBE_TOOCOMPLICATED (-1) - - -static int -could_be_empty_branch(PCRE2_SPTR code, PCRE2_SPTR endcode, BOOL utf, - compile_block *cb, BOOL atend, recurse_check *recurses, int *countptr) -{ -uint32_t group = 0; -uint32_t groupinfo = 0; -register PCRE2_UCHAR c; -recurse_check this_recurse; - -/* If what we are checking has already been set as "could be empty", we know -the answer. */ - -if (*code >= OP_SBRA && *code <= OP_SCOND) return CBE_EMPTY; - -/* If this is a capturing group, we may have the answer cached, but we can only -use this information if there are no (?| groups in the pattern, because -otherwise group numbers are not unique. */ - -if ((cb->external_flags & PCRE2_DUPCAPUSED) == 0 && - (*code == OP_CBRA || *code == OP_CBRAPOS)) - { - group = GET2(code, 1 + LINK_SIZE); - groupinfo = cb->groupinfo[group]; - if ((groupinfo & GI_SET_COULD_BE_EMPTY) != 0) - return ((groupinfo & GI_COULD_BE_EMPTY) != 0)? CBE_EMPTY : CBE_NOTEMPTY; - } - -/* A large and/or complex regex can take too long to process. We have to assume -it can match an empty string. This can happen more often when (?| groups are -present in the pattern and the caching is disabled. Setting the cap at 1100 -allows the test for more than 1023 capturing patterns to work. */ - -if ((*countptr)++ > 1100) return CBE_TOOCOMPLICATED; - -/* Scan the opcodes for this branch. */ - -for (code = first_significant_code(code + PRIV(OP_lengths)[*code], TRUE); - code < endcode; - code = first_significant_code(code + PRIV(OP_lengths)[c], TRUE)) - { - PCRE2_SPTR ccode; - - c = *code; - - /* Skip over forward assertions; the other assertions are skipped by - first_significant_code() with a TRUE final argument. */ - - if (c == OP_ASSERT) - { - do code += GET(code, 1); while (*code == OP_ALT); - c = *code; - continue; - } - - /* For a recursion/subroutine call we can scan the recursion when this - function is called at the end, to check a complete pattern. Before then, - recursions just have the group number as their argument and in any case may - be forward references. In that situation, we return CBE_EMPTY, just in case. - It means that unlimited repeats of groups that contain recursions are always - treated as "could be empty" - which just adds a bit more processing time - because of the runtime check. */ - - if (c == OP_RECURSE) - { - PCRE2_SPTR scode, endgroup; - BOOL empty_branch; - - if (!atend) goto ISTRUE; - scode = cb->start_code + GET(code, 1); - endgroup = scode; - - /* We need to detect whether this is a recursive call, as otherwise there - will be an infinite loop. If it is a recursion, just skip over it. Simple - recursions are easily detected. For mutual recursions we keep a chain on - the stack. */ - - do endgroup += GET(endgroup, 1); while (*endgroup == OP_ALT); - if (code >= scode && code <= endgroup) continue; /* Simple recursion */ - else - { - recurse_check *r = recurses; - for (r = recurses; r != NULL; r = r->prev) - if (r->group == scode) break; - if (r != NULL) continue; /* Mutual recursion */ - } - - /* Scan the referenced group, remembering it on the stack chain to detect - mutual recursions. */ - - empty_branch = FALSE; - this_recurse.prev = recurses; - this_recurse.group = scode; - - do - { - int rc = could_be_empty_branch(scode, endcode, utf, cb, atend, - &this_recurse, countptr); - if (rc < 0) return rc; - if (rc > 0) - { - empty_branch = TRUE; - break; - } - scode += GET(scode, 1); - } - while (*scode == OP_ALT); - - if (!empty_branch) goto ISFALSE; /* All branches are non-empty */ - continue; - } - - /* Groups with zero repeats can of course be empty; skip them. */ - - if (c == OP_BRAZERO || c == OP_BRAMINZERO || c == OP_SKIPZERO || - c == OP_BRAPOSZERO) - { - code += PRIV(OP_lengths)[c]; - do code += GET(code, 1); while (*code == OP_ALT); - c = *code; - continue; - } - - /* A nested group that is already marked as "could be empty" can just be - skipped. */ - - if (c == OP_SBRA || c == OP_SBRAPOS || - c == OP_SCBRA || c == OP_SCBRAPOS) - { - do code += GET(code, 1); while (*code == OP_ALT); - c = *code; - continue; - } - - /* For other groups, scan the branches. */ - - if (c == OP_BRA || c == OP_BRAPOS || - c == OP_CBRA || c == OP_CBRAPOS || - c == OP_ONCE || c == OP_ONCE_NC || - c == OP_COND || c == OP_SCOND) - { - BOOL empty_branch; - if (GET(code, 1) == 0) goto ISTRUE; /* Hit unclosed bracket */ - - /* If a conditional group has only one branch, there is a second, implied, - empty branch, so just skip over the conditional, because it could be empty. - Otherwise, scan the individual branches of the group. */ - - if (c == OP_COND && code[GET(code, 1)] != OP_ALT) - code += GET(code, 1); - else - { - empty_branch = FALSE; - do - { - if (!empty_branch) - { - int rc = could_be_empty_branch(code, endcode, utf, cb, atend, - recurses, countptr); - if (rc < 0) return rc; - if (rc > 0) empty_branch = TRUE; - } - code += GET(code, 1); - } - while (*code == OP_ALT); - if (!empty_branch) goto ISFALSE; /* All branches are non-empty */ - } - - c = *code; - continue; - } - - /* Handle the other opcodes */ - - switch (c) - { - /* Check for quantifiers after a class. XCLASS is used for classes that - cannot be represented just by a bit map. This includes negated single - high-valued characters. The length in PRIV(OP_lengths)[] is zero; the - actual length is stored in the compiled code, so we must update "code" - here. */ - -#if defined SUPPORT_UNICODE || PCRE2_CODE_UNIT_WIDTH != 8 - case OP_XCLASS: - ccode = code += GET(code, 1); - goto CHECK_CLASS_REPEAT; -#endif - - case OP_CLASS: - case OP_NCLASS: - ccode = code + PRIV(OP_lengths)[OP_CLASS]; - -#if defined SUPPORT_UNICODE || PCRE2_CODE_UNIT_WIDTH != 8 - CHECK_CLASS_REPEAT: -#endif - - switch (*ccode) - { - case OP_CRSTAR: /* These could be empty; continue */ - case OP_CRMINSTAR: - case OP_CRQUERY: - case OP_CRMINQUERY: - case OP_CRPOSSTAR: - case OP_CRPOSQUERY: - break; - - default: /* Non-repeat => class must match */ - case OP_CRPLUS: /* These repeats aren't empty */ - case OP_CRMINPLUS: - case OP_CRPOSPLUS: - goto ISFALSE; - - case OP_CRRANGE: - case OP_CRMINRANGE: - case OP_CRPOSRANGE: - if (GET2(ccode, 1) > 0) goto ISFALSE; /* Minimum > 0 */ - break; - } - break; - - /* Opcodes that must match a character */ - - case OP_ANY: - case OP_ALLANY: - case OP_ANYBYTE: - - case OP_PROP: - case OP_NOTPROP: - case OP_ANYNL: - - case OP_NOT_HSPACE: - case OP_HSPACE: - case OP_NOT_VSPACE: - case OP_VSPACE: - case OP_EXTUNI: - - case OP_NOT_DIGIT: - case OP_DIGIT: - case OP_NOT_WHITESPACE: - case OP_WHITESPACE: - case OP_NOT_WORDCHAR: - case OP_WORDCHAR: - - case OP_CHAR: - case OP_CHARI: - case OP_NOT: - case OP_NOTI: - - case OP_PLUS: - case OP_PLUSI: - case OP_MINPLUS: - case OP_MINPLUSI: - - case OP_NOTPLUS: - case OP_NOTPLUSI: - case OP_NOTMINPLUS: - case OP_NOTMINPLUSI: - - case OP_POSPLUS: - case OP_POSPLUSI: - case OP_NOTPOSPLUS: - case OP_NOTPOSPLUSI: - - case OP_EXACT: - case OP_EXACTI: - case OP_NOTEXACT: - case OP_NOTEXACTI: - - case OP_TYPEPLUS: - case OP_TYPEMINPLUS: - case OP_TYPEPOSPLUS: - case OP_TYPEEXACT: - goto ISFALSE; - - /* These are going to continue, as they may be empty, but we have to - fudge the length for the \p and \P cases. */ - - case OP_TYPESTAR: - case OP_TYPEMINSTAR: - case OP_TYPEPOSSTAR: - case OP_TYPEQUERY: - case OP_TYPEMINQUERY: - case OP_TYPEPOSQUERY: - if (code[1] == OP_PROP || code[1] == OP_NOTPROP) code += 2; - break; - - /* Same for these */ - - case OP_TYPEUPTO: - case OP_TYPEMINUPTO: - case OP_TYPEPOSUPTO: - if (code[1 + IMM2_SIZE] == OP_PROP || code[1 + IMM2_SIZE] == OP_NOTPROP) - code += 2; - break; - - /* End of branch */ - - case OP_KET: - case OP_KETRMAX: - case OP_KETRMIN: - case OP_KETRPOS: - case OP_ALT: - goto ISTRUE; - - /* In UTF-8 or UTF-16 mode, STAR, MINSTAR, POSSTAR, QUERY, MINQUERY, - POSQUERY, UPTO, MINUPTO, and POSUPTO and their caseless and negative - versions may be followed by a multibyte character. */ - -#ifdef MAYBE_UTF_MULTI - case OP_STAR: - case OP_STARI: - case OP_NOTSTAR: - case OP_NOTSTARI: - - case OP_MINSTAR: - case OP_MINSTARI: - case OP_NOTMINSTAR: - case OP_NOTMINSTARI: - - case OP_POSSTAR: - case OP_POSSTARI: - case OP_NOTPOSSTAR: - case OP_NOTPOSSTARI: - - case OP_QUERY: - case OP_QUERYI: - case OP_NOTQUERY: - case OP_NOTQUERYI: - - case OP_MINQUERY: - case OP_MINQUERYI: - case OP_NOTMINQUERY: - case OP_NOTMINQUERYI: - - case OP_POSQUERY: - case OP_POSQUERYI: - case OP_NOTPOSQUERY: - case OP_NOTPOSQUERYI: - if (utf && HAS_EXTRALEN(code[1])) code += GET_EXTRALEN(code[1]); - break; - - case OP_UPTO: - case OP_UPTOI: - case OP_NOTUPTO: - case OP_NOTUPTOI: - - case OP_MINUPTO: - case OP_MINUPTOI: - case OP_NOTMINUPTO: - case OP_NOTMINUPTOI: - - case OP_POSUPTO: - case OP_POSUPTOI: - case OP_NOTPOSUPTO: - case OP_NOTPOSUPTOI: - if (utf && HAS_EXTRALEN(code[1 + IMM2_SIZE])) code += GET_EXTRALEN(code[1 + IMM2_SIZE]); - break; -#endif /* MAYBE_UTF_MULTI */ - - /* MARK, and PRUNE/SKIP/THEN with an argument must skip over the argument - string. */ - - case OP_MARK: - case OP_PRUNE_ARG: - case OP_SKIP_ARG: - case OP_THEN_ARG: - code += code[1]; - break; - - /* None of the remaining opcodes are required to match a character. */ - - default: - break; - } - } - -ISTRUE: -groupinfo |= GI_COULD_BE_EMPTY; - -ISFALSE: -if (group > 0) cb->groupinfo[group] = groupinfo | GI_SET_COULD_BE_EMPTY; - -return ((groupinfo & GI_COULD_BE_EMPTY) != 0)? CBE_EMPTY : CBE_NOTEMPTY; -} - - - -/************************************************* -* Check for counted repeat * -*************************************************/ - -/* This function is called when a '{' is encountered in a place where it might -start a quantifier. It looks ahead to see if it really is a quantifier, that -is, one of the forms {ddd} {ddd,} or {ddd,ddd} where the ddds are digits. - -Argument: pointer to the first char after '{' -Returns: TRUE or FALSE -*/ - -static BOOL -is_counted_repeat(PCRE2_SPTR p) -{ -if (!IS_DIGIT(*p)) return FALSE; -p++; -while (IS_DIGIT(*p)) p++; -if (*p == CHAR_RIGHT_CURLY_BRACKET) return TRUE; - -if (*p++ != CHAR_COMMA) return FALSE; -if (*p == CHAR_RIGHT_CURLY_BRACKET) return TRUE; - -if (!IS_DIGIT(*p)) return FALSE; -p++; -while (IS_DIGIT(*p)) p++; - -return (*p == CHAR_RIGHT_CURLY_BRACKET); -} - - - -/************************************************* -* Handle escapes * -*************************************************/ - -/* This function is called when a \ has been encountered. It either returns a -positive value for a simple escape such as \d, or 0 for a data character, which -is placed in chptr. A backreference to group n is returned as negative n. On -entry, ptr is pointing at the \. On exit, it points the final code unit of the -escape sequence. - -This function is also called from pcre2_substitute() to handle escape sequences -in replacement strings. In this case, the cb argument is NULL, and only -sequences that define a data character are recognised. The isclass argument is -not relevant, but the options argument is the final value of the compiled -pattern's options. - -There is one "trick" case: when a sequence such as [[:>:]] or \s in UCP mode is -processed, it is replaced by a nested alternative sequence. If this contains a -backslash (which is usually does), ptrend does not point to its end - it still -points to the end of the whole pattern. However, we can detect this case -because cb->nestptr[0] will be non-NULL. The nested sequences are all zero- -terminated and there are only ever two levels of nesting. - -Arguments: - ptrptr points to the input position pointer - ptrend points to the end of the input - chptr points to a returned data character - errorcodeptr points to the errorcode variable (containing zero) - options the current options bits - isclass TRUE if inside a character class - cb compile data block - -Returns: zero => a data character - positive => a special escape sequence - negative => a back reference - on error, errorcodeptr is set non-zero -*/ - -int -PRIV(check_escape)(PCRE2_SPTR *ptrptr, PCRE2_SPTR ptrend, uint32_t *chptr, - int *errorcodeptr, uint32_t options, BOOL isclass, compile_block *cb) -{ -BOOL utf = (options & PCRE2_UTF) != 0; -PCRE2_SPTR ptr = *ptrptr + 1; -register uint32_t c, cc; -int escape = 0; -int i; - -/* Find the end of a nested insert. */ - -if (cb != NULL && cb->nestptr[0] != NULL) - ptrend = ptr + PRIV(strlen)(ptr); - -/* If backslash is at the end of the string, it's an error. */ - -if (ptr >= ptrend) - { - *errorcodeptr = ERR1; - return 0; - } - -GETCHARINCTEST(c, ptr); /* Get character value, increment pointer */ -ptr--; /* Set pointer back to the last code unit */ - -/* Non-alphanumerics are literals, so we just leave the value in c. An initial -value test saves a memory lookup for code points outside the alphanumeric -range. Otherwise, do a table lookup. A non-zero result is something that can be -returned immediately. Otherwise further processing is required. */ - -if (c < ESCAPES_FIRST || c > ESCAPES_LAST) {} /* Definitely literal */ - -else if ((i = escapes[c - ESCAPES_FIRST]) != 0) - { - if (i > 0) c = (uint32_t)i; else /* Positive is a data character */ - { - escape = -i; /* Else return a special escape */ - if (escape == ESC_P || escape == ESC_p || escape == ESC_X) - cb->external_flags |= PCRE2_HASBKPORX; /* Note \P, \p, or \X */ - } - } - -/* Escapes that need further processing, including those that are unknown. -When called from pcre2_substitute(), only \c, \o, and \x are recognized (and \u -when BSUX is set). */ - -else - { - PCRE2_SPTR oldptr; - BOOL braced, negated, overflow; - unsigned int s; - - /* Filter calls from pcre2_substitute(). */ - - if (cb == NULL && c != CHAR_c && c != CHAR_o && c != CHAR_x && - (c != CHAR_u || (options & PCRE2_ALT_BSUX) != 0)) - { - *errorcodeptr = ERR3; - return 0; - } - - switch (c) - { - /* A number of Perl escapes are not handled by PCRE. We give an explicit - error. */ - - case CHAR_l: - case CHAR_L: - *errorcodeptr = ERR37; - break; - - /* \u is unrecognized when PCRE2_ALT_BSUX is not set. When it is treated - specially, \u must be followed by four hex digits. Otherwise it is a - lowercase u letter. */ - - case CHAR_u: - if ((options & PCRE2_ALT_BSUX) == 0) *errorcodeptr = ERR37; else - { - uint32_t xc; - if ((cc = XDIGIT(ptr[1])) == 0xff) break; /* Not a hex digit */ - if ((xc = XDIGIT(ptr[2])) == 0xff) break; /* Not a hex digit */ - cc = (cc << 4) | xc; - if ((xc = XDIGIT(ptr[3])) == 0xff) break; /* Not a hex digit */ - cc = (cc << 4) | xc; - if ((xc = XDIGIT(ptr[4])) == 0xff) break; /* Not a hex digit */ - c = (cc << 4) | xc; - ptr += 4; - if (utf) - { - if (c > 0x10ffffU) *errorcodeptr = ERR77; - else if (c >= 0xd800 && c <= 0xdfff) *errorcodeptr = ERR73; - } - else if (c > MAX_NON_UTF_CHAR) *errorcodeptr = ERR77; - } - break; - - case CHAR_U: - /* \U is unrecognized unless PCRE2_ALT_BSUX is set, in which case it is an - upper case letter. */ - if ((options & PCRE2_ALT_BSUX) == 0) *errorcodeptr = ERR37; - break; - - /* In a character class, \g is just a literal "g". Outside a character - class, \g must be followed by one of a number of specific things: - - (1) A number, either plain or braced. If positive, it is an absolute - backreference. If negative, it is a relative backreference. This is a Perl - 5.10 feature. - - (2) Perl 5.10 also supports \g{name} as a reference to a named group. This - is part of Perl's movement towards a unified syntax for back references. As - this is synonymous with \k{name}, we fudge it up by pretending it really - was \k. - - (3) For Oniguruma compatibility we also support \g followed by a name or a - number either in angle brackets or in single quotes. However, these are - (possibly recursive) subroutine calls, _not_ backreferences. Just return - the ESC_g code (cf \k). */ - - case CHAR_g: - if (isclass) break; - if (ptr[1] == CHAR_LESS_THAN_SIGN || ptr[1] == CHAR_APOSTROPHE) - { - escape = ESC_g; - break; - } - - /* Handle the Perl-compatible cases */ - - if (ptr[1] == CHAR_LEFT_CURLY_BRACKET) - { - PCRE2_SPTR p; - for (p = ptr+2; *p != CHAR_NULL && *p != CHAR_RIGHT_CURLY_BRACKET; p++) - if (*p != CHAR_MINUS && !IS_DIGIT(*p)) break; - if (*p != CHAR_NULL && *p != CHAR_RIGHT_CURLY_BRACKET) - { - escape = ESC_k; - break; - } - braced = TRUE; - ptr++; - } - else braced = FALSE; - - if (ptr[1] == CHAR_MINUS) - { - negated = TRUE; - ptr++; - } - else negated = FALSE; - - /* The integer range is limited by the machine's int representation. */ - s = 0; - overflow = FALSE; - while (IS_DIGIT(ptr[1])) - { - if (s > INT_MAX / 10 - 1) /* Integer overflow */ - { - overflow = TRUE; - break; - } - s = s * 10 + (unsigned int)(*(++ptr) - CHAR_0); - } - if (overflow) /* Integer overflow */ - { - while (IS_DIGIT(ptr[1])) ptr++; - *errorcodeptr = ERR61; - break; - } - - if (braced && *(++ptr) != CHAR_RIGHT_CURLY_BRACKET) - { - *errorcodeptr = ERR57; - break; - } - - if (s == 0) - { - *errorcodeptr = ERR58; - break; - } - - if (negated) - { - if (s > cb->bracount) - { - *errorcodeptr = ERR15; - break; - } - s = cb->bracount - (s - 1); - } - - escape = -(int)s; - break; - - /* The handling of escape sequences consisting of a string of digits - starting with one that is not zero is not straightforward. Perl has changed - over the years. Nowadays \g{} for backreferences and \o{} for octal are - recommended to avoid the ambiguities in the old syntax. - - Outside a character class, the digits are read as a decimal number. If the - number is less than 10, or if there are that many previous extracting left - brackets, it is a back reference. Otherwise, up to three octal digits are - read to form an escaped character code. Thus \123 is likely to be octal 123 - (cf \0123, which is octal 012 followed by the literal 3). - - Inside a character class, \ followed by a digit is always either a literal - 8 or 9 or an octal number. */ - - case CHAR_1: case CHAR_2: case CHAR_3: case CHAR_4: case CHAR_5: - case CHAR_6: case CHAR_7: case CHAR_8: case CHAR_9: - - if (!isclass) - { - oldptr = ptr; - /* The integer range is limited by the machine's int representation. */ - s = c - CHAR_0; - overflow = FALSE; - while (IS_DIGIT(ptr[1])) - { - if (s > INT_MAX / 10 - 1) /* Integer overflow */ - { - overflow = TRUE; - break; - } - s = s * 10 + (unsigned int)(*(++ptr) - CHAR_0); - } - if (overflow) /* Integer overflow */ - { - while (IS_DIGIT(ptr[1])) ptr++; - *errorcodeptr = ERR61; - break; - } - - /* \1 to \9 are always back references. \8x and \9x are too; \1x to \7x - are octal escapes if there are not that many previous captures. */ - - if (s < 10 || *oldptr >= CHAR_8 || s <= cb->bracount) - { - escape = -(int)s; /* Indicates a back reference */ - break; - } - ptr = oldptr; /* Put the pointer back and fall through */ - } - - /* Handle a digit following \ when the number is not a back reference, or - we are within a character class. If the first digit is 8 or 9, Perl used to - generate a binary zero byte and then treat the digit as a following - literal. At least by Perl 5.18 this changed so as not to insert the binary - zero. */ - - if ((c = *ptr) >= CHAR_8) break; - - /* Fall through with a digit less than 8 */ - - /* \0 always starts an octal number, but we may drop through to here with a - larger first octal digit. The original code used just to take the least - significant 8 bits of octal numbers (I think this is what early Perls used - to do). Nowadays we allow for larger numbers in UTF-8 mode and 16-bit mode, - but no more than 3 octal digits. */ - - case CHAR_0: - c -= CHAR_0; - while(i++ < 2 && ptr[1] >= CHAR_0 && ptr[1] <= CHAR_7) - c = c * 8 + *(++ptr) - CHAR_0; -#if PCRE2_CODE_UNIT_WIDTH == 8 - if (!utf && c > 0xff) *errorcodeptr = ERR51; -#endif - break; - - /* \o is a relatively new Perl feature, supporting a more general way of - specifying character codes in octal. The only supported form is \o{ddd}. */ - - case CHAR_o: - if (ptr[1] != CHAR_LEFT_CURLY_BRACKET) *errorcodeptr = ERR55; else - if (ptr[2] == CHAR_RIGHT_CURLY_BRACKET) *errorcodeptr = ERR78; else - { - ptr += 2; - c = 0; - overflow = FALSE; - while (*ptr >= CHAR_0 && *ptr <= CHAR_7) - { - cc = *ptr++; - if (c == 0 && cc == CHAR_0) continue; /* Leading zeroes */ -#if PCRE2_CODE_UNIT_WIDTH == 32 - if (c >= 0x20000000l) { overflow = TRUE; break; } -#endif - c = (c << 3) + (cc - CHAR_0); -#if PCRE2_CODE_UNIT_WIDTH == 8 - if (c > (utf ? 0x10ffffU : 0xffU)) { overflow = TRUE; break; } -#elif PCRE2_CODE_UNIT_WIDTH == 16 - if (c > (utf ? 0x10ffffU : 0xffffU)) { overflow = TRUE; break; } -#elif PCRE2_CODE_UNIT_WIDTH == 32 - if (utf && c > 0x10ffffU) { overflow = TRUE; break; } -#endif - } - if (overflow) - { - while (*ptr >= CHAR_0 && *ptr <= CHAR_7) ptr++; - *errorcodeptr = ERR34; - } - else if (*ptr == CHAR_RIGHT_CURLY_BRACKET) - { - if (utf && c >= 0xd800 && c <= 0xdfff) *errorcodeptr = ERR73; - } - else *errorcodeptr = ERR64; - } - break; - - /* \x is complicated. When PCRE2_ALT_BSUX is set, \x must be followed by - two hexadecimal digits. Otherwise it is a lowercase x letter. */ - - case CHAR_x: - if ((options & PCRE2_ALT_BSUX) != 0) - { - uint32_t xc; - if ((cc = XDIGIT(ptr[1])) == 0xff) break; /* Not a hex digit */ - if ((xc = XDIGIT(ptr[2])) == 0xff) break; /* Not a hex digit */ - c = (cc << 4) | xc; - ptr += 2; - } /* End PCRE2_ALT_BSUX handling */ - - /* Handle \x in Perl's style. \x{ddd} is a character number which can be - greater than 0xff in UTF-8 or non-8bit mode, but only if the ddd are hex - digits. If not, { used to be treated as a data character. However, Perl - seems to read hex digits up to the first non-such, and ignore the rest, so - that, for example \x{zz} matches a binary zero. This seems crazy, so PCRE - now gives an error. */ - - else - { - if (ptr[1] == CHAR_LEFT_CURLY_BRACKET) - { - ptr += 2; - if (*ptr == CHAR_RIGHT_CURLY_BRACKET) - { - *errorcodeptr = ERR78; - break; - } - c = 0; - overflow = FALSE; - - while ((cc = XDIGIT(*ptr)) != 0xff) - { - ptr++; - if (c == 0 && cc == 0) continue; /* Leading zeroes */ -#if PCRE2_CODE_UNIT_WIDTH == 32 - if (c >= 0x10000000l) { overflow = TRUE; break; } -#endif - c = (c << 4) | cc; - if ((utf && c > 0x10ffffU) || (!utf && c > MAX_NON_UTF_CHAR)) - { - overflow = TRUE; - break; - } - } - - if (overflow) - { - while (XDIGIT(*ptr) != 0xff) ptr++; - *errorcodeptr = ERR34; - } - else if (*ptr == CHAR_RIGHT_CURLY_BRACKET) - { - if (utf && c >= 0xd800 && c <= 0xdfff) *errorcodeptr = ERR73; - } - - /* If the sequence of hex digits does not end with '}', give an error. - We used just to recognize this construct and fall through to the normal - \x handling, but nowadays Perl gives an error, which seems much more - sensible, so we do too. */ - - else *errorcodeptr = ERR67; - } /* End of \x{} processing */ - - /* Read a single-byte hex-defined char (up to two hex digits after \x) */ - - else - { - c = 0; - if ((cc = XDIGIT(ptr[1])) == 0xff) break; /* Not a hex digit */ - ptr++; - c = cc; - if ((cc = XDIGIT(ptr[1])) == 0xff) break; /* Not a hex digit */ - ptr++; - c = (c << 4) | cc; - } /* End of \xdd handling */ - } /* End of Perl-style \x handling */ - break; - - /* The handling of \c is different in ASCII and EBCDIC environments. In an - ASCII (or Unicode) environment, an error is given if the character - following \c is not a printable ASCII character. Otherwise, the following - character is upper-cased if it is a letter, and after that the 0x40 bit is - flipped. The result is the value of the escape. - - In an EBCDIC environment the handling of \c is compatible with the - specification in the perlebcdic document. The following character must be - a letter or one of small number of special characters. These provide a - means of defining the character values 0-31. - - For testing the EBCDIC handling of \c in an ASCII environment, recognize - the EBCDIC value of 'c' explicitly. */ - -#if defined EBCDIC && 'a' != 0x81 - case 0x83: -#else - case CHAR_c: -#endif - - c = *(++ptr); - if (c >= CHAR_a && c <= CHAR_z) c = UPPER_CASE(c); - if (c == CHAR_NULL && ptr >= ptrend) - { - *errorcodeptr = ERR2; - break; - } - - /* Handle \c in an ASCII/Unicode environment. */ - -#ifndef EBCDIC /* ASCII/UTF-8 coding */ - if (c < 32 || c > 126) /* Excludes all non-printable ASCII */ - { - *errorcodeptr = ERR68; - break; - } - c ^= 0x40; - - /* Handle \c in an EBCDIC environment. The special case \c? is converted to - 255 (0xff) or 95 (0x5f) if other character suggest we are using th POSIX-BC - encoding. (This is the way Perl indicates that it handles \c?.) The other - valid sequences correspond to a list of specific characters. */ - -#else - if (c == CHAR_QUESTION_MARK) - c = ('\\' == 188 && '`' == 74)? 0x5f : 0xff; - else - { - for (i = 0; i < 32; i++) - { - if (c == ebcdic_escape_c[i]) break; - } - if (i < 32) c = i; else *errorcodeptr = ERR68; - } -#endif /* EBCDIC */ - - break; - - /* Any other alphanumeric following \ is an error. Perl gives an error only - if in warning mode, but PCRE doesn't have a warning mode. */ - - default: - *errorcodeptr = ERR3; - break; - } - } - -/* Perl supports \N{name} for character names, as well as plain \N for "not -newline". PCRE does not support \N{name}. However, it does support -quantification such as \N{2,3}. */ - -if (escape == ESC_N && ptr[1] == CHAR_LEFT_CURLY_BRACKET && - !is_counted_repeat(ptr+2)) - *errorcodeptr = ERR37; - -/* If PCRE2_UCP is set, we change the values for \d etc. */ - -if ((options & PCRE2_UCP) != 0 && escape >= ESC_D && escape <= ESC_w) - escape += (ESC_DU - ESC_D); - -/* Set the pointer to the final character before returning. */ - -*ptrptr = ptr; -*chptr = c; -return escape; -} - - - -#ifdef SUPPORT_UNICODE -/************************************************* -* Handle \P and \p * -*************************************************/ - -/* This function is called after \P or \p has been encountered, provided that -PCRE2 is compiled with support for UTF and Unicode properties. On entry, the -contents of ptrptr are pointing at the P or p. On exit, it is left pointing at -the final code unit of the escape sequence. - -Arguments: - ptrptr the pattern position pointer - negptr a boolean that is set TRUE for negation else FALSE - ptypeptr an unsigned int that is set to the type value - pdataptr an unsigned int that is set to the detailed property value - errorcodeptr the error code variable - cb the compile data - -Returns: TRUE if the type value was found, or FALSE for an invalid type -*/ - -static BOOL -get_ucp(PCRE2_SPTR *ptrptr, BOOL *negptr, unsigned int *ptypeptr, - unsigned int *pdataptr, int *errorcodeptr, compile_block *cb) -{ -register PCRE2_UCHAR c; -size_t i, bot, top; -PCRE2_SPTR ptr = *ptrptr; -PCRE2_UCHAR name[32]; - -*negptr = FALSE; -c = *(++ptr); - -/* \P or \p can be followed by a name in {}, optionally preceded by ^ for -negation. */ - -if (c == CHAR_LEFT_CURLY_BRACKET) - { - if (ptr[1] == CHAR_CIRCUMFLEX_ACCENT) - { - *negptr = TRUE; - ptr++; - } - for (i = 0; i < (int)(sizeof(name) / sizeof(PCRE2_UCHAR)) - 1; i++) - { - c = *(++ptr); - if (c == CHAR_NULL) goto ERROR_RETURN; - if (c == CHAR_RIGHT_CURLY_BRACKET) break; - name[i] = c; - } - if (c != CHAR_RIGHT_CURLY_BRACKET) goto ERROR_RETURN; - name[i] = 0; - } - -/* Otherwise there is just one following character, which must be an ASCII -letter. */ - -else if (MAX_255(c) && (cb->ctypes[c] & ctype_letter) != 0) - { - name[0] = c; - name[1] = 0; - } -else goto ERROR_RETURN; - -*ptrptr = ptr; - -/* Search for a recognized property name using binary chop. */ - -bot = 0; -top = PRIV(utt_size); - -while (bot < top) - { - int r; - i = (bot + top) >> 1; - r = PRIV(strcmp_c8)(name, PRIV(utt_names) + PRIV(utt)[i].name_offset); - if (r == 0) - { - *ptypeptr = PRIV(utt)[i].type; - *pdataptr = PRIV(utt)[i].value; - return TRUE; - } - if (r > 0) bot = i + 1; else top = i; - } -*errorcodeptr = ERR47; /* Unrecognized name */ -return FALSE; - -ERROR_RETURN: /* Malformed \P or \p */ -*errorcodeptr = ERR46; -*ptrptr = ptr; -return FALSE; -} -#endif - - - -/************************************************* -* Read repeat counts * -*************************************************/ - -/* Read an item of the form {n,m} and return the values. This is called only -after is_counted_repeat() has confirmed that a repeat-count quantifier exists, -so the syntax is guaranteed to be correct, but we need to check the values. - -Arguments: - p pointer to first char after '{' - minp pointer to int for min - maxp pointer to int for max - returned as -1 if no max - errorcodeptr points to error code variable - -Returns: pointer to '}' on success; - current ptr on error, with errorcodeptr set non-zero -*/ - -static PCRE2_SPTR -read_repeat_counts(PCRE2_SPTR p, int *minp, int *maxp, int *errorcodeptr) -{ -int min = 0; -int max = -1; - -while (IS_DIGIT(*p)) - { - min = min * 10 + (int)(*p++ - CHAR_0); - if (min > 65535) - { - *errorcodeptr = ERR5; - return p; - } - } - -if (*p == CHAR_RIGHT_CURLY_BRACKET) max = min; else - { - if (*(++p) != CHAR_RIGHT_CURLY_BRACKET) - { - max = 0; - while(IS_DIGIT(*p)) - { - max = max * 10 + (int)(*p++ - CHAR_0); - if (max > 65535) - { - *errorcodeptr = ERR5; - return p; - } - } - if (max < min) - { - *errorcodeptr = ERR4; - return p; - } - } - } - -*minp = min; -*maxp = max; -return p; -} - - - -/************************************************* -* Scan compiled regex for recursion reference * -*************************************************/ - -/* This function scans through a compiled pattern until it finds an instance of -OP_RECURSE. - -Arguments: - code points to start of expression - utf TRUE in UTF mode - -Returns: pointer to the opcode for OP_RECURSE, or NULL if not found -*/ - -static PCRE2_SPTR -find_recurse(PCRE2_SPTR code, BOOL utf) -{ -for (;;) - { - register PCRE2_UCHAR c = *code; - if (c == OP_END) return NULL; - if (c == OP_RECURSE) return code; - - /* XCLASS is used for classes that cannot be represented just by a bit map. - This includes negated single high-valued characters. CALLOUT_STR is used for - callouts with string arguments. In both cases the length in the table is - zero; the actual length is stored in the compiled code. */ - - if (c == OP_XCLASS) code += GET(code, 1); - else if (c == OP_CALLOUT_STR) code += GET(code, 1 + 2*LINK_SIZE); - - /* Otherwise, we can get the item's length from the table, except that for - repeated character types, we have to test for \p and \P, which have an extra - two bytes of parameters, and for MARK/PRUNE/SKIP/THEN with an argument, we - must add in its length. */ - - else - { - switch(c) - { - case OP_TYPESTAR: - case OP_TYPEMINSTAR: - case OP_TYPEPLUS: - case OP_TYPEMINPLUS: - case OP_TYPEQUERY: - case OP_TYPEMINQUERY: - case OP_TYPEPOSSTAR: - case OP_TYPEPOSPLUS: - case OP_TYPEPOSQUERY: - if (code[1] == OP_PROP || code[1] == OP_NOTPROP) code += 2; - break; - - case OP_TYPEPOSUPTO: - case OP_TYPEUPTO: - case OP_TYPEMINUPTO: - case OP_TYPEEXACT: - if (code[1 + IMM2_SIZE] == OP_PROP || code[1 + IMM2_SIZE] == OP_NOTPROP) - code += 2; - break; - - case OP_MARK: - case OP_PRUNE_ARG: - case OP_SKIP_ARG: - case OP_THEN_ARG: - code += code[1]; - break; - } - - /* Add in the fixed length from the table */ - - code += PRIV(OP_lengths)[c]; - - /* In UTF-8 and UTF-16 modes, opcodes that are followed by a character may - be followed by a multi-unit character. The length in the table is a - minimum, so we have to arrange to skip the extra units. */ - -#ifdef MAYBE_UTF_MULTI - if (utf) switch(c) - { - case OP_CHAR: - case OP_CHARI: - case OP_NOT: - case OP_NOTI: - case OP_EXACT: - case OP_EXACTI: - case OP_NOTEXACT: - case OP_NOTEXACTI: - case OP_UPTO: - case OP_UPTOI: - case OP_NOTUPTO: - case OP_NOTUPTOI: - case OP_MINUPTO: - case OP_MINUPTOI: - case OP_NOTMINUPTO: - case OP_NOTMINUPTOI: - case OP_POSUPTO: - case OP_POSUPTOI: - case OP_NOTPOSUPTO: - case OP_NOTPOSUPTOI: - case OP_STAR: - case OP_STARI: - case OP_NOTSTAR: - case OP_NOTSTARI: - case OP_MINSTAR: - case OP_MINSTARI: - case OP_NOTMINSTAR: - case OP_NOTMINSTARI: - case OP_POSSTAR: - case OP_POSSTARI: - case OP_NOTPOSSTAR: - case OP_NOTPOSSTARI: - case OP_PLUS: - case OP_PLUSI: - case OP_NOTPLUS: - case OP_NOTPLUSI: - case OP_MINPLUS: - case OP_MINPLUSI: - case OP_NOTMINPLUS: - case OP_NOTMINPLUSI: - case OP_POSPLUS: - case OP_POSPLUSI: - case OP_NOTPOSPLUS: - case OP_NOTPOSPLUSI: - case OP_QUERY: - case OP_QUERYI: - case OP_NOTQUERY: - case OP_NOTQUERYI: - case OP_MINQUERY: - case OP_MINQUERYI: - case OP_NOTMINQUERY: - case OP_NOTMINQUERYI: - case OP_POSQUERY: - case OP_POSQUERYI: - case OP_NOTPOSQUERY: - case OP_NOTPOSQUERYI: - if (HAS_EXTRALEN(code[-1])) code += GET_EXTRALEN(code[-1]); - break; - } -#else - (void)(utf); /* Keep compiler happy by referencing function argument */ -#endif /* MAYBE_UTF_MULTI */ - } - } -} - - - -/************************************************* -* Check for POSIX class syntax * -*************************************************/ - -/* This function is called when the sequence "[:" or "[." or "[=" is -encountered in a character class. It checks whether this is followed by a -sequence of characters terminated by a matching ":]" or ".]" or "=]". If we -reach an unescaped ']' without the special preceding character, return FALSE. - -Originally, this function only recognized a sequence of letters between the -terminators, but it seems that Perl recognizes any sequence of characters, -though of course unknown POSIX names are subsequently rejected. Perl gives an -"Unknown POSIX class" error for [:f\oo:] for example, where previously PCRE -didn't consider this to be a POSIX class. Likewise for [:1234:]. - -The problem in trying to be exactly like Perl is in the handling of escapes. We -have to be sure that [abc[:x\]pqr] is *not* treated as containing a POSIX -class, but [abc[:x\]pqr:]] is (so that an error can be generated). The code -below handles the special cases \\ and \], but does not try to do any other -escape processing. This makes it different from Perl for cases such as -[:l\ower:] where Perl recognizes it as the POSIX class "lower" but PCRE does -not recognize "l\ower". This is a lesser evil than not diagnosing bad classes -when Perl does, I think. - -A user pointed out that PCRE was rejecting [:a[:digit:]] whereas Perl was not. -It seems that the appearance of a nested POSIX class supersedes an apparent -external class. For example, [:a[:digit:]b:] matches "a", "b", ":", or -a digit. This is handled by returning FALSE if the start of a new group with -the same terminator is encountered, since the next closing sequence must close -the nested group, not the outer one. - -In Perl, unescaped square brackets may also appear as part of class names. For -example, [:a[:abc]b:] gives unknown POSIX class "[:abc]b:]". However, for -[:a[:abc]b][b:] it gives unknown POSIX class "[:abc]b][b:]", which does not -seem right at all. PCRE does not allow closing square brackets in POSIX class -names. - -Arguments: - ptr pointer to the initial [ - endptr where to return a pointer to the terminating ':', '.', or '=' - -Returns: TRUE or FALSE -*/ - -static BOOL -check_posix_syntax(PCRE2_SPTR ptr, PCRE2_SPTR *endptr) -{ -PCRE2_UCHAR terminator; /* Don't combine these lines; the Solaris cc */ -terminator = *(++ptr); /* compiler warns about "non-constant" initializer. */ - -for (++ptr; *ptr != CHAR_NULL; ptr++) - { - if (*ptr == CHAR_BACKSLASH && - (ptr[1] == CHAR_RIGHT_SQUARE_BRACKET || ptr[1] == CHAR_BACKSLASH)) - ptr++; - else if ((*ptr == CHAR_LEFT_SQUARE_BRACKET && ptr[1] == terminator) || - *ptr == CHAR_RIGHT_SQUARE_BRACKET) return FALSE; - else if (*ptr == terminator && ptr[1] == CHAR_RIGHT_SQUARE_BRACKET) - { - *endptr = ptr; - return TRUE; - } - } - -return FALSE; -} - - - -/************************************************* -* Check POSIX class name * -*************************************************/ - -/* This function is called to check the name given in a POSIX-style class entry -such as [:alnum:]. - -Arguments: - ptr points to the first letter - len the length of the name - -Returns: a value representing the name, or -1 if unknown -*/ - -static int -check_posix_name(PCRE2_SPTR ptr, int len) -{ -const char *pn = posix_names; -register int yield = 0; -while (posix_name_lengths[yield] != 0) - { - if (len == posix_name_lengths[yield] && - PRIV(strncmp_c8)(ptr, pn, (unsigned int)len) == 0) return yield; - pn += posix_name_lengths[yield] + 1; - yield++; - } -return -1; -} - - - -#ifdef SUPPORT_UNICODE -/************************************************* -* Get othercase range * -*************************************************/ - -/* This function is passed the start and end of a class range in UCT mode. It -searches up the characters, looking for ranges of characters in the "other" -case. Each call returns the next one, updating the start address. A character -with multiple other cases is returned on its own with a special return value. - -Arguments: - cptr points to starting character value; updated - d end value - ocptr where to put start of othercase range - odptr where to put end of othercase range - -Yield: -1 when no more - 0 when a range is returned - >0 the CASESET offset for char with multiple other cases - in this case, ocptr contains the original -*/ - -static int -get_othercase_range(uint32_t *cptr, uint32_t d, uint32_t *ocptr, - uint32_t *odptr) -{ -uint32_t c, othercase, next; -unsigned int co; - -/* Find the first character that has an other case. If it has multiple other -cases, return its case offset value. */ - -for (c = *cptr; c <= d; c++) - { - if ((co = UCD_CASESET(c)) != 0) - { - *ocptr = c++; /* Character that has the set */ - *cptr = c; /* Rest of input range */ - return (int)co; - } - if ((othercase = UCD_OTHERCASE(c)) != c) break; - } - -if (c > d) return -1; /* Reached end of range */ - -/* Found a character that has a single other case. Search for the end of the -range, which is either the end of the input range, or a character that has zero -or more than one other cases. */ - -*ocptr = othercase; -next = othercase + 1; - -for (++c; c <= d; c++) - { - if ((co = UCD_CASESET(c)) != 0 || UCD_OTHERCASE(c) != next) break; - next++; - } - -*odptr = next - 1; /* End of othercase range */ -*cptr = c; /* Rest of input range */ -return 0; -} -#endif /* SUPPORT_UNICODE */ - - - -/************************************************* -* Add a character or range to a class * -*************************************************/ - -/* This function packages up the logic of adding a character or range of -characters to a class. The character values in the arguments will be within the -valid values for the current mode (8-bit, 16-bit, UTF, etc). This function is -mutually recursive with the function immediately below. - -Arguments: - classbits the bit map for characters < 256 - uchardptr points to the pointer for extra data - options the options word - cb compile data - start start of range character - end end of range character - -Returns: the number of < 256 characters added - the pointer to extra data is updated -*/ - -static unsigned int -add_to_class(uint8_t *classbits, PCRE2_UCHAR **uchardptr, uint32_t options, - compile_block *cb, uint32_t start, uint32_t end) -{ -uint32_t c; -uint32_t classbits_end = (end <= 0xff ? end : 0xff); -unsigned int n8 = 0; - -/* If caseless matching is required, scan the range and process alternate -cases. In Unicode, there are 8-bit characters that have alternate cases that -are greater than 255 and vice-versa. Sometimes we can just extend the original -range. */ - -if ((options & PCRE2_CASELESS) != 0) - { -#ifdef SUPPORT_UNICODE - if ((options & PCRE2_UTF) != 0) - { - int rc; - uint32_t oc, od; - - options &= ~PCRE2_CASELESS; /* Remove for recursive calls */ - c = start; - - while ((rc = get_othercase_range(&c, end, &oc, &od)) >= 0) - { - /* Handle a single character that has more than one other case. */ - - if (rc > 0) n8 += add_list_to_class(classbits, uchardptr, options, cb, - PRIV(ucd_caseless_sets) + rc, oc); - - /* Do nothing if the other case range is within the original range. */ - - else if (oc >= start && od <= end) continue; - - /* Extend the original range if there is overlap, noting that if oc < c, we - can't have od > end because a subrange is always shorter than the basic - range. Otherwise, use a recursive call to add the additional range. */ - - else if (oc < start && od >= start - 1) start = oc; /* Extend downwards */ - else if (od > end && oc <= end + 1) - { - end = od; /* Extend upwards */ - if (end > classbits_end) classbits_end = (end <= 0xff ? end : 0xff); - } - else n8 += add_to_class(classbits, uchardptr, options, cb, oc, od); - } - } - else -#endif /* SUPPORT_UNICODE */ - - /* Not UTF mode */ - - for (c = start; c <= classbits_end; c++) - { - SETBIT(classbits, cb->fcc[c]); - n8++; - } - } - -/* Now handle the original range. Adjust the final value according to the bit -length - this means that the same lists of (e.g.) horizontal spaces can be used -in all cases. */ - -if ((options & PCRE2_UTF) == 0 && end > MAX_NON_UTF_CHAR) - end = MAX_NON_UTF_CHAR; - -/* Use the bitmap for characters < 256. Otherwise use extra data.*/ - -for (c = start; c <= classbits_end; c++) - { - /* Regardless of start, c will always be <= 255. */ - SETBIT(classbits, c); - n8++; - } - -#ifdef SUPPORT_WIDE_CHARS -if (start <= 0xff) start = 0xff + 1; - -if (end >= start) - { - PCRE2_UCHAR *uchardata = *uchardptr; - -#ifdef SUPPORT_UNICODE - if ((options & PCRE2_UTF) != 0) - { - if (start < end) - { - *uchardata++ = XCL_RANGE; - uchardata += PRIV(ord2utf)(start, uchardata); - uchardata += PRIV(ord2utf)(end, uchardata); - } - else if (start == end) - { - *uchardata++ = XCL_SINGLE; - uchardata += PRIV(ord2utf)(start, uchardata); - } - } - else -#endif /* SUPPORT_UNICODE */ - - /* Without UTF support, character values are constrained by the bit length, - and can only be > 256 for 16-bit and 32-bit libraries. */ - -#if PCRE2_CODE_UNIT_WIDTH == 8 - {} -#else - if (start < end) - { - *uchardata++ = XCL_RANGE; - *uchardata++ = start; - *uchardata++ = end; - } - else if (start == end) - { - *uchardata++ = XCL_SINGLE; - *uchardata++ = start; - } -#endif - *uchardptr = uchardata; /* Updata extra data pointer */ - } -#else - (void)uchardptr; /* Avoid compiler warning */ -#endif /* SUPPORT_WIDE_CHARS */ - -return n8; /* Number of 8-bit characters */ -} - - - -/************************************************* -* Add a list of characters to a class * -*************************************************/ - -/* This function is used for adding a list of case-equivalent characters to a -class, and also for adding a list of horizontal or vertical whitespace. If the -list is in order (which it should be), ranges of characters are detected and -handled appropriately. This function is mutually recursive with the function -above. - -Arguments: - classbits the bit map for characters < 256 - uchardptr points to the pointer for extra data - options the options word - cb contains pointers to tables etc. - p points to row of 32-bit values, terminated by NOTACHAR - except character to omit; this is used when adding lists of - case-equivalent characters to avoid including the one we - already know about - -Returns: the number of < 256 characters added - the pointer to extra data is updated -*/ - -static unsigned int -add_list_to_class(uint8_t *classbits, PCRE2_UCHAR **uchardptr, uint32_t options, - compile_block *cb, const uint32_t *p, unsigned int except) -{ -unsigned int n8 = 0; -while (p[0] < NOTACHAR) - { - unsigned int n = 0; - if (p[0] != except) - { - while(p[n+1] == p[0] + n + 1) n++; - n8 += add_to_class(classbits, uchardptr, options, cb, p[0], p[n]); - } - p += n + 1; - } -return n8; -} - - - -/************************************************* -* Add characters not in a list to a class * -*************************************************/ - -/* This function is used for adding the complement of a list of horizontal or -vertical whitespace to a class. The list must be in order. - -Arguments: - classbits the bit map for characters < 256 - uchardptr points to the pointer for extra data - options the options word - cb contains pointers to tables etc. - p points to row of 32-bit values, terminated by NOTACHAR - -Returns: the number of < 256 characters added - the pointer to extra data is updated -*/ - -static unsigned int -add_not_list_to_class(uint8_t *classbits, PCRE2_UCHAR **uchardptr, - uint32_t options, compile_block *cb, const uint32_t *p) -{ -BOOL utf = (options & PCRE2_UTF) != 0; -unsigned int n8 = 0; -if (p[0] > 0) - n8 += add_to_class(classbits, uchardptr, options, cb, 0, p[0] - 1); -while (p[0] < NOTACHAR) - { - while (p[1] == p[0] + 1) p++; - n8 += add_to_class(classbits, uchardptr, options, cb, p[0] + 1, - (p[1] == NOTACHAR) ? (utf ? 0x10ffffu : 0xffffffffu) : p[1] - 1); - p++; - } -return n8; -} - - - -/************************************************* -* Process (*VERB) name for escapes * -*************************************************/ - -/* This function is called when the PCRE2_ALT_VERBNAMES option is set, to -process the characters in a verb's name argument. It is called twice, once with -codeptr == NULL, to find out the length of the processed name, and again to put -the name into memory. - -Arguments: - ptrptr pointer to the input pointer - codeptr pointer to the compiled code pointer - errorcodeptr pointer to the error code - options the options bits - utf TRUE if processing UTF - cb compile data block - -Returns: length of the processed name, or < 0 on error -*/ - -static int -process_verb_name(PCRE2_SPTR *ptrptr, PCRE2_UCHAR **codeptr, int *errorcodeptr, - uint32_t options, BOOL utf, compile_block *cb) -{ -int32_t arglen = 0; -BOOL inescq = FALSE; -PCRE2_SPTR ptr = *ptrptr; -PCRE2_UCHAR *code = (codeptr == NULL)? NULL : *codeptr; - -for (; ptr < cb->end_pattern; ptr++) - { - uint32_t x = *ptr; - - /* Skip over literals */ - - if (inescq) - { - if (x == CHAR_BACKSLASH && ptr[1] == CHAR_E) - { - inescq = FALSE; - ptr++;; - continue; - } - } - - else /* Not a literal character */ - { - if (x == CHAR_RIGHT_PARENTHESIS) break; - - /* Skip over comments and whitespace in extended mode. */ - - if ((options & PCRE2_EXTENDED) != 0) - { - PCRE2_SPTR wscptr = ptr; - while (MAX_255(x) && (cb->ctypes[x] & ctype_space) != 0) x = *(++ptr); - if (x == CHAR_NUMBER_SIGN) - { - ptr++; - while (*ptr != CHAR_NULL || ptr < cb->end_pattern) - { - if (IS_NEWLINE(ptr)) /* For non-fixed-length newline cases, */ - { /* IS_NEWLINE sets cb->nllen. */ - ptr += cb->nllen; - break; - } - ptr++; -#ifdef SUPPORT_UNICODE - if (utf) FORWARDCHAR(ptr); -#endif - } - } - - /* If we have skipped any characters, restart the loop. */ - - if (ptr > wscptr) - { - ptr--; - continue; - } - } - - /* Process escapes */ - - if (x == '\\') - { - int rc; - *errorcodeptr = 0; - rc = PRIV(check_escape)(&ptr, cb->end_pattern, &x, errorcodeptr, options, - FALSE, cb); - *ptrptr = ptr; /* For possible error */ - if (*errorcodeptr != 0) return -1; - if (rc != 0) - { - if (rc == ESC_Q) - { - inescq = TRUE; - continue; - } - if (rc == ESC_E) continue; - *errorcodeptr = ERR40; - return -1; - } - } - } - - /* We have the next character in the name. */ - -#ifdef SUPPORT_UNICODE - if (utf) - { - if (code == NULL) /* Just want the length */ - { -#if PCRE2_CODE_UNIT_WIDTH == 8 - int i; - for (i = 0; i < PRIV(utf8_table1_size); i++) - if ((int)x <= PRIV(utf8_table1)[i]) break; - arglen += i; -#elif PCRE2_CODE_UNIT_WIDTH == 16 - if (x > 0xffff) arglen++; -#endif - } - else - { - PCRE2_UCHAR cbuff[8]; - x = PRIV(ord2utf)(x, cbuff); - memcpy(code, cbuff, CU2BYTES(x)); - code += x; - } - } - else -#endif /* SUPPORT_UNICODE */ - - /* Not UTF */ - { - if (code != NULL) *code++ = (PCRE2_UCHAR)x; - } - - arglen++; - - if ((unsigned int)arglen > MAX_MARK) - { - *errorcodeptr = ERR76; - *ptrptr = ptr; - return -1; - } - } - -/* Update the pointers before returning. */ - -*ptrptr = ptr; -if (codeptr != NULL) *codeptr = code; -return arglen; -} - - - -/************************************************* -* Macro for the next two functions * -*************************************************/ - -/* Both scan_for_captures() and compile_branch() use this macro to generate a -fragment of code that reads the characters of a name and sets its length -(checking for not being too long). Count the characters dynamically, to avoid -the possibility of integer overflow. The same macro is used for reading *VERB -names. */ - -#define READ_NAME(ctype, errno, errset) \ - namelen = 0; \ - while (MAX_255(*ptr) && (cb->ctypes[*ptr] & ctype) != 0) \ - { \ - ptr++; \ - namelen++; \ - if (namelen > MAX_NAME_SIZE) \ - { \ - errset = errno; \ - goto FAILED; \ - } \ - } - - - -/************************************************* -* Scan regex to identify named groups * -*************************************************/ - -/* This function is called first of all, to scan for named capturing groups so -that information about them is fully available to both the compiling scans. -It skips over everything except parenthesized items. - -Arguments: - ptrptr points to pointer to the start of the pattern - options compiling dynamic options - cb pointer to the compile data block - -Returns: zero on success or a non-zero error code, with pointer updated -*/ - -typedef struct nest_save { - uint16_t nest_depth; - uint16_t reset_group; - uint16_t max_group; - uint16_t flags; -} nest_save; - -#define NSF_RESET 0x0001u -#define NSF_EXTENDED 0x0002u -#define NSF_DUPNAMES 0x0004u - -static int scan_for_captures(PCRE2_SPTR *ptrptr, uint32_t options, - compile_block *cb) -{ -uint32_t c; -uint32_t delimiter; -uint32_t set, unset, *optset; -uint32_t skiptoket = 0; -uint16_t nest_depth = 0; -int errorcode = 0; -int escape; -int namelen; -int i; -BOOL inescq = FALSE; -BOOL isdupname; -BOOL utf = (options & PCRE2_UTF) != 0; -BOOL negate_class; -PCRE2_SPTR name; -PCRE2_SPTR start; -PCRE2_SPTR ptr = *ptrptr; -named_group *ng; -nest_save *top_nest = NULL; -nest_save *end_nests = (nest_save *)(cb->start_workspace + cb->workspace_size); - -/* The size of the nest_save structure might not be a factor of the size of the -workspace. Therefore we must round down end_nests so as to correctly avoid -creating a nest_save that spans the end of the workspace. */ - -end_nests = (nest_save *)((char *)end_nests - - ((cb->workspace_size * sizeof(PCRE2_UCHAR)) % sizeof(nest_save))); - -/* Now scan the pattern */ - -for (; ptr < cb->end_pattern; ptr++) - { - c = *ptr; - - /* Parenthesized groups set skiptoket when all following characters up to the - next closing parenthesis must be ignored. The parenthesis itself must be - processed (to end the nested parenthesized item). */ - - if (skiptoket != 0) - { - if (c != CHAR_RIGHT_PARENTHESIS) continue; - skiptoket = 0; - } - - /* Skip over literals */ - - if (inescq) - { - if (c == CHAR_BACKSLASH && ptr[1] == CHAR_E) - { - inescq = FALSE; - ptr++; - } - continue; - } - - /* Skip over # comments and whitespace in extended mode. */ - - if ((options & PCRE2_EXTENDED) != 0) - { - PCRE2_SPTR wscptr = ptr; - while (MAX_255(c) && (cb->ctypes[c] & ctype_space) != 0) c = *(++ptr); - if (c == CHAR_NUMBER_SIGN) - { - ptr++; - while (ptr < cb->end_pattern) - { - if (IS_NEWLINE(ptr)) /* For non-fixed-length newline cases, */ - { /* IS_NEWLINE sets cb->nllen. */ - ptr += cb->nllen; - break; - } - ptr++; -#ifdef SUPPORT_UNICODE - if (utf) FORWARDCHAR(ptr); -#endif - } - } - - /* If we skipped any characters, restart the loop. Otherwise, we didn't see - a comment. */ - - if (ptr > wscptr) - { - ptr--; - continue; - } - } - - /* Process the next pattern item. */ - - switch(c) - { - default: /* Most characters are just skipped */ - break; - - /* Skip escapes except for \Q */ - - case CHAR_BACKSLASH: - errorcode = 0; - escape = PRIV(check_escape)(&ptr, cb->end_pattern, &c, &errorcode, options, - FALSE, cb); - if (errorcode != 0) goto FAILED; - if (escape == ESC_Q) inescq = TRUE; - break; - - /* Skip a character class. The syntax is complicated so we have to - replicate some of what happens when a class is processed for real. */ - - case CHAR_LEFT_SQUARE_BRACKET: - if (PRIV(strncmp_c8)(ptr+1, STRING_WEIRD_STARTWORD, 6) == 0 || - PRIV(strncmp_c8)(ptr+1, STRING_WEIRD_ENDWORD, 6) == 0) - { - ptr += 6; - break; - } - - /* If the first character is '^', set the negation flag (not actually used - here, except to recognize only one ^) and skip it. If the first few - characters (either before or after ^) are \Q\E or \E we skip them too. This - makes for compatibility with Perl. */ - - negate_class = FALSE; - for (;;) - { - c = *(++ptr); /* First character in class */ - if (c == CHAR_BACKSLASH) - { - if (ptr[1] == CHAR_E) - ptr++; - else if (PRIV(strncmp_c8)(ptr + 1, STR_Q STR_BACKSLASH STR_E, 3) == 0) - ptr += 3; - else - break; - } - else if (!negate_class && c == CHAR_CIRCUMFLEX_ACCENT) - negate_class = TRUE; - else break; - } - - if (c == CHAR_RIGHT_SQUARE_BRACKET && - (cb->external_options & PCRE2_ALLOW_EMPTY_CLASS) != 0) - break; - - /* Loop for the contents of the class */ - - for (;;) - { - PCRE2_SPTR tempptr; - - if (c == CHAR_NULL && ptr >= cb->end_pattern) - { - errorcode = ERR6; /* Missing terminating ']' */ - goto FAILED; - } - -#ifdef SUPPORT_UNICODE - if (utf && HAS_EXTRALEN(c)) - { /* Braces are required because the */ - GETCHARLEN(c, ptr, ptr); /* macro generates multiple statements */ - } -#endif - - /* Inside \Q...\E everything is literal except \E */ - - if (inescq) - { - if (c == CHAR_BACKSLASH && ptr[1] == CHAR_E) /* If we are at \E */ - { - inescq = FALSE; /* Reset literal state */ - ptr++; /* Skip the 'E' */ - } - goto CONTINUE_CLASS; - } - - /* Skip POSIX class names. */ - if (c == CHAR_LEFT_SQUARE_BRACKET && - (ptr[1] == CHAR_COLON || ptr[1] == CHAR_DOT || - ptr[1] == CHAR_EQUALS_SIGN) && check_posix_syntax(ptr, &tempptr)) - { - ptr = tempptr + 1; - } - else if (c == CHAR_BACKSLASH) - { - errorcode = 0; - escape = PRIV(check_escape)(&ptr, cb->end_pattern, &c, &errorcode, - options, TRUE, cb); - if (errorcode != 0) goto FAILED; - if (escape == ESC_Q) inescq = TRUE; - } - - CONTINUE_CLASS: - c = *(++ptr); - if (c == CHAR_RIGHT_SQUARE_BRACKET && !inescq) break; - } /* End of class-processing loop */ - break; - - /* This is the real work of this function - handling parentheses. */ - - case CHAR_LEFT_PARENTHESIS: - nest_depth++; - - if (ptr[1] != CHAR_QUESTION_MARK) - { - if (ptr[1] != CHAR_ASTERISK) - { - if ((options & PCRE2_NO_AUTO_CAPTURE) == 0) cb->bracount++; - } - - /* (*something) - skip over a name, and then just skip to closing ket - unless PCRE2_ALT_VERBNAMES is set, in which case we have to process - escapes in the string after a verb name terminated by a colon. */ - - else - { - ptr += 2; - while (MAX_255(*ptr) && (cb->ctypes[*ptr] & ctype_word) != 0) ptr++; - if (*ptr == CHAR_COLON && (options & PCRE2_ALT_VERBNAMES) != 0) - { - ptr++; - if (process_verb_name(&ptr, NULL, &errorcode, options, utf, cb) < 0) - goto FAILED; - } - else - { - while (ptr < cb->end_pattern && *ptr != CHAR_RIGHT_PARENTHESIS) - ptr++; - } - nest_depth--; - } - } - - /* Handle (?...) groups */ - - else switch(ptr[2]) - { - default: - ptr += 2; - if (ptr[0] == CHAR_R || /* (?R) */ - ptr[0] == CHAR_NUMBER_SIGN || /* (?#) */ - IS_DIGIT(ptr[0]) || /* (?n) */ - (ptr[0] == CHAR_MINUS && IS_DIGIT(ptr[1]))) /* (?-n) */ - { - skiptoket = ptr[0]; - break; - } - - /* Handle (?| and (?imsxJU: which are the only other valid forms. Both - need a new block on the nest stack. */ - - if (top_nest == NULL) top_nest = (nest_save *)(cb->start_workspace); - else if (++top_nest >= end_nests) - { - errorcode = ERR84; - goto FAILED; - } - top_nest->nest_depth = nest_depth; - top_nest->flags = 0; - if ((options & PCRE2_EXTENDED) != 0) top_nest->flags |= NSF_EXTENDED; - if ((options & PCRE2_DUPNAMES) != 0) top_nest->flags |= NSF_DUPNAMES; - - if (*ptr == CHAR_VERTICAL_LINE) - { - top_nest->reset_group = (uint16_t)cb->bracount; - top_nest->max_group = (uint16_t)cb->bracount; - top_nest->flags |= NSF_RESET; - cb->external_flags |= PCRE2_DUPCAPUSED; - break; - } - - /* Scan options */ - - top_nest->reset_group = 0; - top_nest->max_group = 0; - - set = unset = 0; - optset = &set; - - /* Need only track (?x: and (?J: at this stage */ - - while (*ptr != CHAR_RIGHT_PARENTHESIS && *ptr != CHAR_COLON) - { - switch (*ptr++) - { - case CHAR_MINUS: optset = &unset; break; - - case CHAR_x: *optset |= PCRE2_EXTENDED; break; - - case CHAR_J: - *optset |= PCRE2_DUPNAMES; - cb->external_flags |= PCRE2_JCHANGED; - break; - - case CHAR_i: - case CHAR_m: - case CHAR_s: - case CHAR_U: - break; - - default: - errorcode = ERR11; - ptr--; /* Correct the offset */ - goto FAILED; - } - } - - options = (options | set) & (~unset); - - /* If the options ended with ')' this is not the start of a nested - group with option changes, so the options change at this level. If the - previous level set up a nest block, discard the one we have just created. - Otherwise adjust it for the previous level. */ - - if (*ptr == CHAR_RIGHT_PARENTHESIS) - { - nest_depth--; - if (top_nest > (nest_save *)(cb->start_workspace) && - (top_nest-1)->nest_depth == nest_depth) top_nest --; - else top_nest->nest_depth = nest_depth; - } - break; - - /* Skip over a numerical or string argument for a callout. */ - - case CHAR_C: - ptr += 2; - if (ptr[1] == CHAR_RIGHT_PARENTHESIS) break; - if (IS_DIGIT(ptr[1])) - { - while (IS_DIGIT(ptr[1])) ptr++; - } - - /* Handle a string argument */ - - else - { - ptr++; - delimiter = 0; - for (i = 0; PRIV(callout_start_delims)[i] != 0; i++) - { - if (*ptr == PRIV(callout_start_delims)[i]) - { - delimiter = PRIV(callout_end_delims)[i]; - break; - } - } - - if (delimiter == 0) - { - errorcode = ERR82; - goto FAILED; - } - - start = ptr; - do - { - if (++ptr >= cb->end_pattern) - { - errorcode = ERR81; - ptr = start; /* To give a more useful message */ - goto FAILED; - } - if (ptr[0] == delimiter && ptr[1] == delimiter) ptr += 2; - } - while (ptr[0] != delimiter); - } - - /* Check terminating ) */ - - if (ptr[1] != CHAR_RIGHT_PARENTHESIS) - { - errorcode = ERR39; - ptr++; - goto FAILED; - } - break; - - /* Conditional group */ - - case CHAR_LEFT_PARENTHESIS: - if (ptr[3] != CHAR_QUESTION_MARK) /* Not assertion or callout */ - { - nest_depth++; - ptr += 2; - break; - } - - /* Must be an assertion or a callout */ - - switch(ptr[4]) - { - case CHAR_LESS_THAN_SIGN: - if (ptr[5] != CHAR_EXCLAMATION_MARK && ptr[5] != CHAR_EQUALS_SIGN) - goto MISSING_ASSERTION; - /* Fall through */ - - case CHAR_C: - case CHAR_EXCLAMATION_MARK: - case CHAR_EQUALS_SIGN: - ptr++; - break; - - default: - MISSING_ASSERTION: - ptr += 3; /* To improve error message */ - errorcode = ERR28; - goto FAILED; - } - break; - - case CHAR_COLON: - case CHAR_GREATER_THAN_SIGN: - case CHAR_EQUALS_SIGN: - case CHAR_EXCLAMATION_MARK: - case CHAR_AMPERSAND: - case CHAR_PLUS: - ptr += 2; - break; - - case CHAR_P: - if (ptr[3] != CHAR_LESS_THAN_SIGN) - { - ptr += 3; - break; - } - ptr++; - c = CHAR_GREATER_THAN_SIGN; /* Terminator */ - goto DEFINE_NAME; - - case CHAR_LESS_THAN_SIGN: - if (ptr[3] == CHAR_EQUALS_SIGN || ptr[3] == CHAR_EXCLAMATION_MARK) - { - ptr += 3; - break; - } - c = CHAR_GREATER_THAN_SIGN; /* Terminator */ - goto DEFINE_NAME; - - case CHAR_APOSTROPHE: - c = CHAR_APOSTROPHE; /* Terminator */ - - DEFINE_NAME: - name = ptr = ptr + 3; - - if (*ptr == c) /* Empty name */ - { - errorcode = ERR62; - goto FAILED; - } - - if (IS_DIGIT(*ptr)) - { - errorcode = ERR44; /* Group name must start with non-digit */ - goto FAILED; - } - - if (MAX_255(*ptr) && (cb->ctypes[*ptr] & ctype_word) == 0) - { - errorcode = ERR24; - goto FAILED; - } - - /* Advance ptr, set namelen and check its length. */ - READ_NAME(ctype_word, ERR48, errorcode); - - if (*ptr != c) - { - errorcode = ERR42; - goto FAILED; - } - - if (cb->names_found >= MAX_NAME_COUNT) - { - errorcode = ERR49; - goto FAILED; - } - - if (namelen + IMM2_SIZE + 1 > cb->name_entry_size) - cb->name_entry_size = (uint16_t)(namelen + IMM2_SIZE + 1); - - /* We have a valid name for this capturing group. */ - - cb->bracount++; - - /* Scan the list to check for duplicates. For duplicate names, if the - number is the same, break the loop, which causes the name to be - discarded; otherwise, if DUPNAMES is not set, give an error. - If it is set, allow the name with a different number, but continue - scanning in case this is a duplicate with the same number. For - non-duplicate names, give an error if the number is duplicated. */ - - isdupname = FALSE; - ng = cb->named_groups; - for (i = 0; i < cb->names_found; i++, ng++) - { - if (namelen == ng->length && - PRIV(strncmp)(name, ng->name, (size_t)namelen) == 0) - { - if (ng->number == cb->bracount) break; - if ((options & PCRE2_DUPNAMES) == 0) - { - errorcode = ERR43; - goto FAILED; - } - isdupname = ng->isdup = TRUE; /* Mark as a duplicate */ - cb->dupnames = TRUE; /* Duplicate names exist */ - } - else if (ng->number == cb->bracount) - { - errorcode = ERR65; - goto FAILED; - } - } - - if (i < cb->names_found) break; /* Ignore duplicate with same number */ - - /* Increase the list size if necessary */ - - if (cb->names_found >= cb->named_group_list_size) - { - uint32_t newsize = cb->named_group_list_size * 2; - named_group *newspace = - cb->cx->memctl.malloc(newsize * sizeof(named_group), - cb->cx->memctl.memory_data); - if (newspace == NULL) - { - errorcode = ERR21; - goto FAILED; - } - - memcpy(newspace, cb->named_groups, - cb->named_group_list_size * sizeof(named_group)); - if (cb->named_group_list_size > NAMED_GROUP_LIST_SIZE) - cb->cx->memctl.free((void *)cb->named_groups, - cb->cx->memctl.memory_data); - cb->named_groups = newspace; - cb->named_group_list_size = newsize; - } - - /* Add this name to the list */ - - cb->named_groups[cb->names_found].name = name; - cb->named_groups[cb->names_found].length = (uint16_t)namelen; - cb->named_groups[cb->names_found].number = cb->bracount; - cb->named_groups[cb->names_found].isdup = (uint16_t)isdupname; - cb->names_found++; - break; - } /* End of (? switch */ - break; /* End of ( handling */ - - /* At an alternation, reset the capture count if we are in a (?| group. */ - - case CHAR_VERTICAL_LINE: - if (top_nest != NULL && top_nest->nest_depth == nest_depth && - (top_nest->flags & NSF_RESET) != 0) - { - if (cb->bracount > top_nest->max_group) - top_nest->max_group = (uint16_t)cb->bracount; - cb->bracount = top_nest->reset_group; - } - break; - - /* At a right parenthesis, reset the capture count to the maximum if we - are in a (?| group and/or reset the extended option. */ - - case CHAR_RIGHT_PARENTHESIS: - if (top_nest != NULL && top_nest->nest_depth == nest_depth) - { - if ((top_nest->flags & NSF_RESET) != 0 && - top_nest->max_group > cb->bracount) - cb->bracount = top_nest->max_group; - if ((top_nest->flags & NSF_EXTENDED) != 0) options |= PCRE2_EXTENDED; - else options &= ~PCRE2_EXTENDED; - if ((top_nest->flags & NSF_DUPNAMES) != 0) options |= PCRE2_DUPNAMES; - else options &= ~PCRE2_DUPNAMES; - if (top_nest == (nest_save *)(cb->start_workspace)) top_nest = NULL; - else top_nest--; - } - if (nest_depth == 0) /* Unmatched closing parenthesis */ - { - errorcode = ERR22; - goto FAILED; - } - nest_depth--; - break; - } - } - -if (nest_depth == 0) - { - cb->final_bracount = cb->bracount; - return 0; - } - -/* We give a special error for a missing closing parentheses after (?# because -it might otherwise be hard to see where the missing character is. */ - -errorcode = (skiptoket == CHAR_NUMBER_SIGN)? ERR18 : ERR14; - -FAILED: -*ptrptr = ptr; -return errorcode; -} - - - -/************************************************* -* Compile one branch * -*************************************************/ - -/* Scan the pattern, compiling it into the a vector. If the options are -changed during the branch, the pointer is used to change the external options -bits. This function is used during the pre-compile phase when we are trying -to find out the amount of memory needed, as well as during the real compile -phase. The value of lengthptr distinguishes the two phases. - -Arguments: - optionsptr pointer to the option bits - codeptr points to the pointer to the current code point - ptrptr points to the current pattern pointer - errorcodeptr points to error code variable - firstcuptr place to put the first required code unit - firstcuflagsptr place to put the first code unit flags, or a negative number - reqcuptr place to put the last required code unit - reqcuflagsptr place to put the last required code unit flags, or a negative number - bcptr points to current branch chain - cond_depth conditional nesting depth - cb contains pointers to tables etc. - lengthptr NULL during the real compile phase - points to length accumulator during pre-compile phase - -Returns: TRUE on success - FALSE, with *errorcodeptr set non-zero on error -*/ - -static BOOL -compile_branch(uint32_t *optionsptr, PCRE2_UCHAR **codeptr, - PCRE2_SPTR *ptrptr, int *errorcodeptr, - uint32_t *firstcuptr, int32_t *firstcuflagsptr, - uint32_t *reqcuptr, int32_t *reqcuflagsptr, - branch_chain *bcptr, int cond_depth, - compile_block *cb, size_t *lengthptr) -{ -int repeat_min = 0, repeat_max = 0; /* To please picky compilers */ -int bravalue = 0; -uint32_t greedy_default, greedy_non_default; -uint32_t repeat_type, op_type; -uint32_t options = *optionsptr; /* May change dynamically */ -uint32_t firstcu, reqcu; -int32_t firstcuflags, reqcuflags; -uint32_t zeroreqcu, zerofirstcu; -int32_t zeroreqcuflags, zerofirstcuflags; -int32_t req_caseopt, reqvary, tempreqvary; -int after_manual_callout = 0; -int escape; -size_t length_prevgroup = 0; -register uint32_t c; -register PCRE2_UCHAR *code = *codeptr; -PCRE2_UCHAR *last_code = code; -PCRE2_UCHAR *orig_code = code; -PCRE2_UCHAR *tempcode; -BOOL inescq = FALSE; -BOOL groupsetfirstcu = FALSE; -PCRE2_SPTR ptr = *ptrptr; -PCRE2_SPTR tempptr; -PCRE2_UCHAR *previous = NULL; -PCRE2_UCHAR *previous_callout = NULL; -uint8_t classbits[32]; - -/* We can fish out the UTF setting once and for all into a BOOL, but we must -not do this for other options (e.g. PCRE2_EXTENDED) because they may change -dynamically as we process the pattern. */ - -#ifdef SUPPORT_UNICODE -BOOL utf = (options & PCRE2_UTF) != 0; -#if PCRE2_CODE_UNIT_WIDTH != 32 -PCRE2_UCHAR utf_units[6]; /* For setting up multi-cu chars */ -#endif - -#else /* No UTF support */ -BOOL utf = FALSE; -#endif - -/* Helper variables for OP_XCLASS opcode (for characters > 255). We define -class_uchardata always so that it can be passed to add_to_class() always, -though it will not be used in non-UTF 8-bit cases. This avoids having to supply -alternative calls for the different cases. */ - -PCRE2_UCHAR *class_uchardata; -#ifdef SUPPORT_WIDE_CHARS -BOOL xclass; -PCRE2_UCHAR *class_uchardata_base; -#endif - -/* Set up the default and non-default settings for greediness */ - -greedy_default = ((options & PCRE2_UNGREEDY) != 0); -greedy_non_default = greedy_default ^ 1; - -/* Initialize no first unit, no required unit. REQ_UNSET means "no char -matching encountered yet". It gets changed to REQ_NONE if we hit something that -matches a non-fixed first unit; reqcu just remains unset if we never find one. - -When we hit a repeat whose minimum is zero, we may have to adjust these values -to take the zero repeat into account. This is implemented by setting them to -zerofirstcu and zeroreqcu when such a repeat is encountered. The individual -item types that can be repeated set these backoff variables appropriately. */ - -firstcu = reqcu = zerofirstcu = zeroreqcu = 0; -firstcuflags = reqcuflags = zerofirstcuflags = zeroreqcuflags = REQ_UNSET; - -/* The variable req_caseopt contains either the REQ_CASELESS value or zero, -according to the current setting of the caseless flag. The REQ_CASELESS value -leaves the lower 28 bit empty. It is added into the firstcu or reqcu variables -to record the case status of the value. This is used only for ASCII characters. -*/ - -req_caseopt = ((options & PCRE2_CASELESS) != 0)? REQ_CASELESS:0; - -/* Switch on next character until the end of the branch */ - -for (;; ptr++) - { - BOOL negate_class; - BOOL should_flip_negation; - BOOL match_all_or_no_wide_chars; - BOOL possessive_quantifier; - BOOL is_quantifier; - BOOL is_recurse; - BOOL is_dupname; - BOOL reset_bracount; - int class_has_8bitchar; - int class_one_char; -#ifdef SUPPORT_WIDE_CHARS - BOOL xclass_has_prop; -#endif - int recno; /* Must be signed */ - int refsign; /* Must be signed */ - int terminator; /* Must be signed */ - unsigned int mclength; - unsigned int tempbracount; - uint32_t ec; - uint32_t newoptions; - uint32_t skipunits; - uint32_t subreqcu, subfirstcu; - int32_t subreqcuflags, subfirstcuflags; /* Must be signed */ - PCRE2_UCHAR mcbuffer[8]; - - /* Come here to restart the loop. */ - - REDO_LOOP: - - /* Get next character in the pattern */ - - c = *ptr; - - /* If we are at the end of a nested substitution, revert to the outer level - string. Nesting only happens one or two levels deep, and the inserted string - is always zero terminated. */ - - if (c == CHAR_NULL && cb->nestptr[0] != NULL) - { - ptr = cb->nestptr[0]; - cb->nestptr[0] = cb->nestptr[1]; - cb->nestptr[1] = NULL; - c = *ptr; - } - - /* If we are in the pre-compile phase, accumulate the length used for the - previous cycle of this loop. */ - - if (lengthptr != NULL) - { - if (code > cb->start_workspace + cb->workspace_size - - WORK_SIZE_SAFETY_MARGIN) /* Check for overrun */ - { - *errorcodeptr = (code >= cb->start_workspace + cb->workspace_size)? - ERR52 : ERR86; - goto FAILED; - } - - /* There is at least one situation where code goes backwards: this is the - case of a zero quantifier after a class (e.g. [ab]{0}). At compile time, - the class is simply eliminated. However, it is created first, so we have to - allow memory for it. Therefore, don't ever reduce the length at this point. - */ - - if (code < last_code) code = last_code; - - /* Paranoid check for integer overflow */ - - if (OFLOW_MAX - *lengthptr < (size_t)(code - last_code)) - { - *errorcodeptr = ERR20; - goto FAILED; - } - *lengthptr += (size_t)(code - last_code); - - /* If "previous" is set and it is not at the start of the work space, move - it back to there, in order to avoid filling up the work space. Otherwise, - if "previous" is NULL, reset the current code pointer to the start. */ - - if (previous != NULL) - { - if (previous > orig_code) - { - memmove(orig_code, previous, (size_t)CU2BYTES(code - previous)); - code -= previous - orig_code; - previous = orig_code; - } - } - else code = orig_code; - - /* Remember where this code item starts so we can pick up the length - next time round. */ - - last_code = code; - } - - /* Before doing anything else we must handle all the special items that do - nothing, and which may come between an item and its quantifier. Otherwise, - when auto-callouts are enabled, a callout gets incorrectly inserted before - the quantifier is recognized. After recognizing a "do nothing" item, restart - the loop in case another one follows. */ - - /* If c is not NULL we are not at the end of the pattern. If it is NULL, we - may still be in the pattern with a NULL data item. In these cases, if we are - in \Q...\E, check for the \E that ends the literal string; if not, we have a - literal character. If not in \Q...\E, an isolated \E is ignored. */ - - if (c != CHAR_NULL || ptr < cb->end_pattern) - { - if (c == CHAR_BACKSLASH && ptr[1] == CHAR_E) - { - inescq = FALSE; - ptr++; - continue; - } - else if (inescq) /* Literal character */ - { - if (previous_callout != NULL) - { - if (lengthptr == NULL) /* Don't attempt in pre-compile phase */ - complete_callout(previous_callout, ptr, cb); - previous_callout = NULL; - } - if ((options & PCRE2_AUTO_CALLOUT) != 0) - { - previous_callout = code; - code = auto_callout(code, ptr, cb); - } - goto NORMAL_CHAR; - } - - /* Check for the start of a \Q...\E sequence. We must do this here rather - than later in case it is immediately followed by \E, which turns it into a - "do nothing" sequence. */ - - if (c == CHAR_BACKSLASH && ptr[1] == CHAR_Q) - { - inescq = TRUE; - ptr++; - continue; - } - } - - /* In extended mode, skip white space and #-comments that end at newline. */ - - if ((options & PCRE2_EXTENDED) != 0) - { - PCRE2_SPTR wscptr = ptr; - while (MAX_255(c) && (cb->ctypes[c] & ctype_space) != 0) c = *(++ptr); - if (c == CHAR_NUMBER_SIGN) - { - ptr++; - while (ptr < cb->end_pattern) - { - if (IS_NEWLINE(ptr)) /* For non-fixed-length newline cases, */ - { /* IS_NEWLINE sets cb->nllen. */ - ptr += cb->nllen; - break; - } - ptr++; -#ifdef SUPPORT_UNICODE - if (utf) FORWARDCHAR(ptr); -#endif - } - } - - /* If we skipped any characters, restart the loop. Otherwise, we didn't see - a comment. */ - - if (ptr > wscptr) goto REDO_LOOP; - } - - /* Skip over (?# comments. */ - - if (c == CHAR_LEFT_PARENTHESIS && ptr[1] == CHAR_QUESTION_MARK && - ptr[2] == CHAR_NUMBER_SIGN) - { - ptr += 3; - while (ptr < cb->end_pattern && *ptr != CHAR_RIGHT_PARENTHESIS) ptr++; - if (*ptr != CHAR_RIGHT_PARENTHESIS) - { - *errorcodeptr = ERR18; - goto FAILED; - } - continue; - } - - /* End of processing "do nothing" items. See if the next thing is a - quantifier. */ - - is_quantifier = - c == CHAR_ASTERISK || c == CHAR_PLUS || c == CHAR_QUESTION_MARK || - (c == CHAR_LEFT_CURLY_BRACKET && is_counted_repeat(ptr+1)); - - /* Fill in length of a previous callout and create an auto callout if - required, except when the next thing is a quantifier or when processing a - property substitution string for \w etc in UCP mode. */ - - if (!is_quantifier && cb->nestptr[0] == NULL) - { - if (previous_callout != NULL && after_manual_callout-- <= 0) - { - if (lengthptr == NULL) /* Don't attempt in pre-compile phase */ - complete_callout(previous_callout, ptr, cb); - previous_callout = NULL; - } - - if ((options & PCRE2_AUTO_CALLOUT) != 0) - { - previous_callout = code; - code = auto_callout(code, ptr, cb); - } - } - - /* Process the next pattern item. */ - - switch(c) - { - /* ===================================================================*/ - /* The branch terminates at string end or | or ) */ - - case CHAR_NULL: - if (ptr < cb->end_pattern) goto NORMAL_CHAR; /* Zero data character */ - /* Fall through */ - - case CHAR_VERTICAL_LINE: - case CHAR_RIGHT_PARENTHESIS: - *firstcuptr = firstcu; - *firstcuflagsptr = firstcuflags; - *reqcuptr = reqcu; - *reqcuflagsptr = reqcuflags; - *codeptr = code; - *ptrptr = ptr; - if (lengthptr != NULL) - { - if (OFLOW_MAX - *lengthptr < (size_t)(code - last_code)) - { - *errorcodeptr = ERR20; - goto FAILED; - } - *lengthptr += (size_t)(code - last_code); /* To include callout length */ - } - return TRUE; - - - /* ===================================================================*/ - /* Handle single-character metacharacters. In multiline mode, ^ disables - the setting of any following char as a first character. */ - - case CHAR_CIRCUMFLEX_ACCENT: - previous = NULL; - if ((options & PCRE2_MULTILINE) != 0) - { - if (firstcuflags == REQ_UNSET) - zerofirstcuflags = firstcuflags = REQ_NONE; - *code++ = OP_CIRCM; - } - else *code++ = OP_CIRC; - break; - - case CHAR_DOLLAR_SIGN: - previous = NULL; - *code++ = ((options & PCRE2_MULTILINE) != 0)? OP_DOLLM : OP_DOLL; - break; - - /* There can never be a first char if '.' is first, whatever happens about - repeats. The value of reqcu doesn't change either. */ - - case CHAR_DOT: - if (firstcuflags == REQ_UNSET) firstcuflags = REQ_NONE; - zerofirstcu = firstcu; - zerofirstcuflags = firstcuflags; - zeroreqcu = reqcu; - zeroreqcuflags = reqcuflags; - previous = code; - *code++ = ((options & PCRE2_DOTALL) != 0)? OP_ALLANY: OP_ANY; - break; - - - /* ===================================================================*/ - /* Character classes. If the included characters are all < 256, we build a - 32-byte bitmap of the permitted characters, except in the special case - where there is only one such character. For negated classes, we build the - map as usual, then invert it at the end. However, we use a different opcode - so that data characters > 255 can be handled correctly. - - If the class contains characters outside the 0-255 range, a different - opcode is compiled. It may optionally have a bit map for characters < 256, - but those above are are explicitly listed afterwards. A flag byte tells - whether the bitmap is present, and whether this is a negated class or not. - - An isolated ']' character is not treated specially, so is just another data - character. In earlier versions of PCRE that used the original API there was - a "JavaScript compatibility mode" in which it gave an error. However, - JavaScript itself has changed in this respect so there is no longer any - need for this special handling. - - In another (POSIX) regex library, the ugly syntax [[:<:]] and [[:>:]] is - used for "start of word" and "end of word". As these are otherwise illegal - sequences, we don't break anything by recognizing them. They are replaced - by \b(?=\w) and \b(?<=\w) respectively. This can only happen at the top - nesting level, as no other inserted sequences will contains these oddities. - Sequences like [a[:<:]] are erroneous and are handled by the normal code - below. */ - - case CHAR_LEFT_SQUARE_BRACKET: - if (PRIV(strncmp_c8)(ptr+1, STRING_WEIRD_STARTWORD, 6) == 0) - { - cb->nestptr[0] = ptr + 7; - ptr = sub_start_of_word; - goto REDO_LOOP; - } - - if (PRIV(strncmp_c8)(ptr+1, STRING_WEIRD_ENDWORD, 6) == 0) - { - cb->nestptr[0] = ptr + 7; - ptr = sub_end_of_word; - goto REDO_LOOP; - } - - /* Handle a real character class. */ - - previous = code; - - /* PCRE supports POSIX class stuff inside a class. Perl gives an error if - they are encountered at the top level, so we'll do that too. */ - - if ((ptr[1] == CHAR_COLON || ptr[1] == CHAR_DOT || - ptr[1] == CHAR_EQUALS_SIGN) && - check_posix_syntax(ptr, &tempptr)) - { - *errorcodeptr = (ptr[1] == CHAR_COLON)? ERR12 : ERR13; - goto FAILED; - } - - /* If the first character is '^', set the negation flag and skip it. Also, - if the first few characters (either before or after ^) are \Q\E or \E we - skip them too. This makes for compatibility with Perl. */ - - negate_class = FALSE; - for (;;) - { - c = *(++ptr); - if (c == CHAR_BACKSLASH) - { - if (ptr[1] == CHAR_E) - ptr++; - else if (PRIV(strncmp_c8)(ptr + 1, STR_Q STR_BACKSLASH STR_E, 3) == 0) - ptr += 3; - else - break; - } - else if (!negate_class && c == CHAR_CIRCUMFLEX_ACCENT) - negate_class = TRUE; - else break; - } - - /* Empty classes are allowed if PCRE2_ALLOW_EMPTY_CLASS is set. Otherwise, - an initial ']' is taken as a data character -- the code below handles - that. When empty classes are allowed, [] must always fail, so generate - OP_FAIL, whereas [^] must match any character, so generate OP_ALLANY. */ - - if (c == CHAR_RIGHT_SQUARE_BRACKET && - (cb->external_options & PCRE2_ALLOW_EMPTY_CLASS) != 0) - { - *code++ = negate_class? OP_ALLANY : OP_FAIL; - if (firstcuflags == REQ_UNSET) firstcuflags = REQ_NONE; - zerofirstcu = firstcu; - zerofirstcuflags = firstcuflags; - break; - } - - /* If a non-extended class contains a negative special such as \S, we need - to flip the negation flag at the end, so that support for characters > 255 - works correctly (they are all included in the class). An extended class may - need to insert specific matching or non-matching code for wide characters. - */ - - should_flip_negation = match_all_or_no_wide_chars = FALSE; - - /* Extended class (xclass) will be used when characters > 255 - might match. */ - -#ifdef SUPPORT_WIDE_CHARS - xclass = FALSE; - class_uchardata = code + LINK_SIZE + 2; /* For XCLASS items */ - class_uchardata_base = class_uchardata; /* Save the start */ -#endif - - /* For optimization purposes, we track some properties of the class: - class_has_8bitchar will be non-zero if the class contains at least one 256 - character with a code point less than 256; class_one_char will be 1 if the - class contains just one character; xclass_has_prop will be TRUE if Unicode - property checks are present in the class. */ - - class_has_8bitchar = 0; - class_one_char = 0; -#ifdef SUPPORT_WIDE_CHARS - xclass_has_prop = FALSE; -#endif - - /* Initialize the 256-bit (32-byte) bit map to all zeros. We build the map - in a temporary bit of memory, in case the class contains fewer than two - 8-bit characters because in that case the compiled code doesn't use the bit - map. */ - - memset(classbits, 0, 32 * sizeof(uint8_t)); - - /* Process characters until ] is reached. As the test is at the end of the - loop, an initial ] is taken as a data character. At the start of the loop, - c contains the first code unit of the character. If it is zero, check for - the end of the pattern, to allow binary zero as data. */ - - for(;;) - { - PCRE2_SPTR oldptr; -#ifdef EBCDIC - BOOL range_is_literal = TRUE; -#endif - - if (c == CHAR_NULL && ptr >= cb->end_pattern) - { - *errorcodeptr = ERR6; /* Missing terminating ']' */ - goto FAILED; - } - -#ifdef SUPPORT_UNICODE - if (utf && HAS_EXTRALEN(c)) - { /* Braces are required because the */ - GETCHARLEN(c, ptr, ptr); /* macro generates multiple statements */ - } -#endif - - /* Inside \Q...\E everything is literal except \E */ - - if (inescq) - { - if (c == CHAR_BACKSLASH && ptr[1] == CHAR_E) /* If we are at \E */ - { - inescq = FALSE; /* Reset literal state */ - ptr++; /* Skip the 'E' */ - goto CONTINUE_CLASS; /* Carry on with next char */ - } - goto CHECK_RANGE; /* Could be range if \E follows */ - } - - /* Handle POSIX class names. Perl allows a negation extension of the - form [:^name:]. A square bracket that doesn't match the syntax is - treated as a literal. We also recognize the POSIX constructions - [.ch.] and [=ch=] ("collating elements") and fault them, as Perl - 5.6 and 5.8 do. */ - - if (c == CHAR_LEFT_SQUARE_BRACKET && - (ptr[1] == CHAR_COLON || ptr[1] == CHAR_DOT || - ptr[1] == CHAR_EQUALS_SIGN) && check_posix_syntax(ptr, &tempptr)) - { - BOOL local_negate = FALSE; - int posix_class, taboffset, tabopt; - register const uint8_t *cbits = cb->cbits; - uint8_t pbits[32]; - - if (ptr[1] != CHAR_COLON) - { - *errorcodeptr = ERR13; - goto FAILED; - } - - ptr += 2; - if (*ptr == CHAR_CIRCUMFLEX_ACCENT) - { - local_negate = TRUE; - should_flip_negation = TRUE; /* Note negative special */ - ptr++; - } - - posix_class = check_posix_name(ptr, (int)(tempptr - ptr)); - if (posix_class < 0) - { - *errorcodeptr = ERR30; - goto FAILED; - } - - /* If matching is caseless, upper and lower are converted to - alpha. This relies on the fact that the class table starts with - alpha, lower, upper as the first 3 entries. */ - - if ((options & PCRE2_CASELESS) != 0 && posix_class <= 2) - posix_class = 0; - - /* When PCRE2_UCP is set, some of the POSIX classes are converted to - different escape sequences that use Unicode properties \p or \P. Others - that are not available via \p or \P generate XCL_PROP/XCL_NOTPROP - directly. UCP support is not available unless UTF support is.*/ - -#ifdef SUPPORT_UNICODE - if ((options & PCRE2_UCP) != 0) - { - unsigned int ptype = 0; - int pc = posix_class + ((local_negate)? POSIX_SUBSIZE/2 : 0); - - /* The posix_substitutes table specifies which POSIX classes can be - converted to \p or \P items. This can only happen at top nestling - level, as there will never be a POSIX class in a string that is - substituted for something else. */ - - if (posix_substitutes[pc] != NULL) - { - cb->nestptr[0] = tempptr + 1; - ptr = posix_substitutes[pc] - 1; - goto CONTINUE_CLASS; - } - - /* There are three other classes that generate special property calls - that are recognized only in an XCLASS. */ - - else switch(posix_class) - { - case PC_GRAPH: - ptype = PT_PXGRAPH; - /* Fall through */ - case PC_PRINT: - if (ptype == 0) ptype = PT_PXPRINT; - /* Fall through */ - case PC_PUNCT: - if (ptype == 0) ptype = PT_PXPUNCT; - *class_uchardata++ = local_negate? XCL_NOTPROP : XCL_PROP; - *class_uchardata++ = (PCRE2_UCHAR)ptype; - *class_uchardata++ = 0; - xclass_has_prop = TRUE; - ptr = tempptr + 1; - goto CONTINUE_CLASS; - - /* For the other POSIX classes (ascii, xdigit) we are going to fall - through to the non-UCP case and build a bit map for characters with - code points less than 256. However, if we are in a negated POSIX - class, characters with code points greater than 255 must either all - match or all not match, depending on whether the whole class is not - or is negated. For example, for [[:^ascii:]... they must all match, - whereas for [^[:^xdigit:]... they must not. - - In the special case where there are no xclass items, this is - automatically handled by the use of OP_CLASS or OP_NCLASS, but an - explicit range is needed for OP_XCLASS. Setting a flag here causes - the range to be generated later when it is known that OP_XCLASS is - required. */ - - default: - match_all_or_no_wide_chars |= local_negate; - break; - } - } -#endif /* SUPPORT_UNICODE */ - - /* In the non-UCP case, or when UCP makes no difference, we build the - bit map for the POSIX class in a chunk of local store because we may be - adding and subtracting from it, and we don't want to subtract bits that - may be in the main map already. At the end we or the result into the - bit map that is being built. */ - - posix_class *= 3; - - /* Copy in the first table (always present) */ - - memcpy(pbits, cbits + posix_class_maps[posix_class], - 32 * sizeof(uint8_t)); - - /* If there is a second table, add or remove it as required. */ - - taboffset = posix_class_maps[posix_class + 1]; - tabopt = posix_class_maps[posix_class + 2]; - - if (taboffset >= 0) - { - if (tabopt >= 0) - for (c = 0; c < 32; c++) pbits[c] |= cbits[(int)c + taboffset]; - else - for (c = 0; c < 32; c++) pbits[c] &= ~cbits[(int)c + taboffset]; - } - - /* Now see if we need to remove any special characters. An option - value of 1 removes vertical space and 2 removes underscore. */ - - if (tabopt < 0) tabopt = -tabopt; - if (tabopt == 1) pbits[1] &= ~0x3c; - else if (tabopt == 2) pbits[11] &= 0x7f; - - /* Add the POSIX table or its complement into the main table that is - being built and we are done. */ - - if (local_negate) - for (c = 0; c < 32; c++) classbits[c] |= ~pbits[c]; - else - for (c = 0; c < 32; c++) classbits[c] |= pbits[c]; - - ptr = tempptr + 1; - /* Every class contains at least one < 256 character. */ - class_has_8bitchar = 1; - /* Every class contains at least two characters. */ - class_one_char = 2; - goto CONTINUE_CLASS; /* End of POSIX syntax handling */ - } - - /* Backslash may introduce a single character, or it may introduce one - of the specials, which just set a flag. The sequence \b is a special - case. Inside a class (and only there) it is treated as backspace. We - assume that other escapes have more than one character in them, so - speculatively set both class_has_8bitchar and class_one_char bigger - than one. Unrecognized escapes fall through and are faulted. */ - - if (c == CHAR_BACKSLASH) - { - escape = PRIV(check_escape)(&ptr, cb->end_pattern, &ec, errorcodeptr, - options, TRUE, cb); - if (*errorcodeptr != 0) goto FAILED; - if (escape == 0) /* Escaped single char */ - { - c = ec; -#ifdef EBCDIC - range_is_literal = FALSE; -#endif - } - else if (escape == ESC_b) c = CHAR_BS; /* \b is backspace in a class */ - else if (escape == ESC_N) /* \N is not supported in a class */ - { - *errorcodeptr = ERR71; - goto FAILED; - } - else if (escape == ESC_Q) /* Handle start of quoted string */ - { - if (ptr[1] == CHAR_BACKSLASH && ptr[2] == CHAR_E) - { - ptr += 2; /* avoid empty string */ - } - else inescq = TRUE; - goto CONTINUE_CLASS; - } - else if (escape == ESC_E) goto CONTINUE_CLASS; /* Ignore orphan \E */ - - else /* Handle \d-type escapes */ - { - register const uint8_t *cbits = cb->cbits; - /* Every class contains at least two < 256 characters. */ - class_has_8bitchar++; - /* Every class contains at least two characters. */ - class_one_char += 2; - - switch (escape) - { -#ifdef SUPPORT_UNICODE - case ESC_du: /* These are the values given for \d etc */ - case ESC_DU: /* when PCRE2_UCP is set. We replace the */ - case ESC_wu: /* escape sequence with an appropriate \p */ - case ESC_WU: /* or \P to test Unicode properties instead */ - case ESC_su: /* of the default ASCII testing. This might be */ - case ESC_SU: /* a 2nd-level nesting for [[:<:]] or [[:>:]]. */ - cb->nestptr[1] = cb->nestptr[0]; - cb->nestptr[0] = ptr; - ptr = substitutes[escape - ESC_DU] - 1; /* Just before substitute */ - class_has_8bitchar--; /* Undo! */ - break; -#endif - case ESC_d: - for (c = 0; c < 32; c++) classbits[c] |= cbits[c+cbit_digit]; - break; - - case ESC_D: - should_flip_negation = TRUE; - for (c = 0; c < 32; c++) classbits[c] |= ~cbits[c+cbit_digit]; - break; - - case ESC_w: - for (c = 0; c < 32; c++) classbits[c] |= cbits[c+cbit_word]; - break; - - case ESC_W: - should_flip_negation = TRUE; - for (c = 0; c < 32; c++) classbits[c] |= ~cbits[c+cbit_word]; - break; - - /* Perl 5.004 onwards omitted VT from \s, but restored it at Perl - 5.18. Before PCRE 8.34, we had to preserve the VT bit if it was - previously set by something earlier in the character class. - Luckily, the value of CHAR_VT is 0x0b in both ASCII and EBCDIC, so - we could just adjust the appropriate bit. From PCRE 8.34 we no - longer treat \s and \S specially. */ - - case ESC_s: - for (c = 0; c < 32; c++) classbits[c] |= cbits[c+cbit_space]; - break; - - case ESC_S: - should_flip_negation = TRUE; - for (c = 0; c < 32; c++) classbits[c] |= ~cbits[c+cbit_space]; - break; - - /* The rest apply in both UCP and non-UCP cases. */ - - case ESC_h: - (void)add_list_to_class(classbits, &class_uchardata, options, cb, - PRIV(hspace_list), NOTACHAR); - break; - - case ESC_H: - (void)add_not_list_to_class(classbits, &class_uchardata, options, - cb, PRIV(hspace_list)); - break; - - case ESC_v: - (void)add_list_to_class(classbits, &class_uchardata, options, cb, - PRIV(vspace_list), NOTACHAR); - break; - - case ESC_V: - (void)add_not_list_to_class(classbits, &class_uchardata, options, - cb, PRIV(vspace_list)); - break; - - case ESC_p: - case ESC_P: -#ifdef SUPPORT_UNICODE - { - BOOL negated; - unsigned int ptype = 0, pdata = 0; - if (!get_ucp(&ptr, &negated, &ptype, &pdata, errorcodeptr, cb)) - goto FAILED; - *class_uchardata++ = ((escape == ESC_p) != negated)? - XCL_PROP : XCL_NOTPROP; - *class_uchardata++ = ptype; - *class_uchardata++ = pdata; - xclass_has_prop = TRUE; - class_has_8bitchar--; /* Undo! */ - } - break; -#else - *errorcodeptr = ERR45; - goto FAILED; -#endif - /* Unrecognized escapes are faulted. */ - - default: - *errorcodeptr = ERR7; - goto FAILED; - } - - /* Handled \d-type escape */ - - goto CONTINUE_CLASS; - } - - /* Control gets here if the escape just defined a single character. - This is in c and may be greater than 256. */ - - escape = 0; - } /* End of backslash handling */ - - /* A character may be followed by '-' to form a range. However, Perl does - not permit ']' to be the end of the range. A '-' character at the end is - treated as a literal. Perl ignores orphaned \E sequences entirely. The - code for handling \Q and \E is messy. */ - - CHECK_RANGE: - while (ptr[1] == CHAR_BACKSLASH && ptr[2] == CHAR_E) - { - inescq = FALSE; - ptr += 2; - } - oldptr = ptr; - - /* Remember if \r or \n were explicitly used */ - - if (c == CHAR_CR || c == CHAR_NL) cb->external_flags |= PCRE2_HASCRORLF; - - /* Check for range */ - - if (!inescq && ptr[1] == CHAR_MINUS) - { - uint32_t d; - ptr += 2; - while (*ptr == CHAR_BACKSLASH && ptr[1] == CHAR_E) ptr += 2; - - /* If we hit \Q (not followed by \E) at this point, go into escaped - mode. */ - - while (*ptr == CHAR_BACKSLASH && ptr[1] == CHAR_Q) - { - ptr += 2; - if (*ptr == CHAR_BACKSLASH && ptr[1] == CHAR_E) - { ptr += 2; continue; } - inescq = TRUE; - break; - } - - /* Minus (hyphen) at the end of a class is treated as a literal, so put - back the pointer and jump to handle the character that preceded it. */ - - if (*ptr == CHAR_NULL || (!inescq && *ptr == CHAR_RIGHT_SQUARE_BRACKET)) - { - ptr = oldptr; - goto CLASS_SINGLE_CHARACTER; - } - - /* Otherwise, we have a potential range; pick up the next character */ - -#ifdef SUPPORT_UNICODE - if (utf) - { /* Braces are required because the */ - GETCHARLEN(d, ptr, ptr); /* macro generates multiple statements */ - } - else -#endif - d = *ptr; /* Not UTF mode */ - - /* The second part of a range can be a single-character escape - sequence, but not any of the other escapes. Perl treats a hyphen as a - literal in such circumstances. However, in Perl's warning mode, a - warning is given, so PCRE now faults it as it is almost certainly a - mistake on the user's part. */ - - if (!inescq) - { - if (d == CHAR_BACKSLASH) - { - int descape; - descape = PRIV(check_escape)(&ptr, cb->end_pattern, &d, - errorcodeptr, options, TRUE, cb); - if (*errorcodeptr != 0) goto FAILED; -#ifdef EBCDIC - range_is_literal = FALSE; -#endif - /* 0 means a character was put into d; \b is backspace; any other - special causes an error. */ - - if (descape != 0) - { - if (descape == ESC_b) d = CHAR_BS; else - { - *errorcodeptr = ERR50; - goto FAILED; - } - } - } - - /* A hyphen followed by a POSIX class is treated in the same way. */ - - else if (d == CHAR_LEFT_SQUARE_BRACKET && - (ptr[1] == CHAR_COLON || ptr[1] == CHAR_DOT || - ptr[1] == CHAR_EQUALS_SIGN) && - check_posix_syntax(ptr, &tempptr)) - { - *errorcodeptr = ERR50; - goto FAILED; - } - } - - /* Check that the two values are in the correct order. Optimize - one-character ranges. */ - - if (d < c) - { - *errorcodeptr = ERR8; - goto FAILED; - } - if (d == c) goto CLASS_SINGLE_CHARACTER; /* A few lines below */ - - /* We have found a character range, so single character optimizations - cannot be done anymore. Any value greater than 1 indicates that there - is more than one character. */ - - class_one_char = 2; - - /* Remember an explicit \r or \n, and add the range to the class. */ - - if (d == CHAR_CR || d == CHAR_NL) cb->external_flags |= PCRE2_HASCRORLF; - - /* In an EBCDIC environment, Perl treats alphabetic ranges specially - because there are holes in the encoding, and simply using the range A-Z - (for example) would include the characters in the holes. This applies - only to literal ranges; [\xC1-\xE9] is different to [A-Z]. */ - -#ifdef EBCDIC - if (range_is_literal && - (cb->ctypes[c] & ctype_letter) != 0 && - (cb->ctypes[d] & ctype_letter) != 0 && - (c <= CHAR_z) == (d <= CHAR_z)) - { - uint32_t uc = (c <= CHAR_z)? 0 : 64; - uint32_t C = c - uc; - uint32_t D = d - uc; - - if (C <= CHAR_i) - { - class_has_8bitchar += - add_to_class(classbits, &class_uchardata, options, cb, C + uc, - ((D < CHAR_i)? D : CHAR_i) + uc); - C = CHAR_j; - } - - if (C <= D && C <= CHAR_r) - { - class_has_8bitchar += - add_to_class(classbits, &class_uchardata, options, cb, C + uc, - ((D < CHAR_r)? D : CHAR_r) + uc); - C = CHAR_s; - } - - if (C <= D) - { - class_has_8bitchar += - add_to_class(classbits, &class_uchardata, options, cb, C + uc, - D + uc); - } - } - else -#endif - class_has_8bitchar += - add_to_class(classbits, &class_uchardata, options, cb, c, d); - goto CONTINUE_CLASS; /* Go get the next char in the class */ - } - - /* Handle a single character - we can get here for a normal non-escape - char, or after \ that introduces a single character or for an apparent - range that isn't. Only the value 1 matters for class_one_char, so don't - increase it if it is already 2 or more ... just in case there's a class - with a zillion characters in it. */ - - CLASS_SINGLE_CHARACTER: - if (class_one_char < 2) class_one_char++; - - /* If class_one_char is 1 and xclass_has_prop is false, we have the first - single character in the class, and there have been no prior ranges, or - XCLASS items generated by escapes. If this is the final character in the - class, we can optimize by turning the item into a 1-character OP_CHAR[I] - if it's positive, or OP_NOT[I] if it's negative. In the positive case, it - can cause firstcu to be set. Otherwise, there can be no first char if - this item is first, whatever repeat count may follow. In the case of - reqcu, save the previous value for reinstating. */ - - if (!inescq && -#ifdef SUPPORT_UNICODE - !xclass_has_prop && -#endif - class_one_char == 1 && ptr[1] == CHAR_RIGHT_SQUARE_BRACKET) - { - ptr++; - zeroreqcu = reqcu; - zeroreqcuflags = reqcuflags; - - if (negate_class) - { -#ifdef SUPPORT_UNICODE - int d; -#endif - if (firstcuflags == REQ_UNSET) firstcuflags = REQ_NONE; - zerofirstcu = firstcu; - zerofirstcuflags = firstcuflags; - - /* For caseless UTF mode, check whether this character has more than - one other case. If so, generate a special OP_NOTPROP item instead of - OP_NOTI. */ - -#ifdef SUPPORT_UNICODE - if (utf && (options & PCRE2_CASELESS) != 0 && - (d = UCD_CASESET(c)) != 0) - { - *code++ = OP_NOTPROP; - *code++ = PT_CLIST; - *code++ = d; - } - else -#endif - /* Char has only one other case, or UCP not available */ - - { - *code++ = ((options & PCRE2_CASELESS) != 0)? OP_NOTI: OP_NOT; - code += PUTCHAR(c, code); - } - - /* We are finished with this character class */ - - goto END_CLASS; - } - - /* For a single, positive character, get the value into mcbuffer, and - then we can handle this with the normal one-character code. */ - - mclength = PUTCHAR(c, mcbuffer); - goto ONE_CHAR; - } /* End of 1-char optimization */ - - /* There is more than one character in the class, or an XCLASS item - has been generated. Add this character to the class. */ - - class_has_8bitchar += - add_to_class(classbits, &class_uchardata, options, cb, c, c); - - /* Continue to the next character in the class. Closing square bracket - not within \Q..\E ends the class. A NULL character terminates a - nested substitution string, but may be a data character in the main - pattern (tested at the start of this loop). */ - - CONTINUE_CLASS: - c = *(++ptr); - if (c == CHAR_NULL && cb->nestptr[0] != NULL) - { - ptr = cb->nestptr[0]; - cb->nestptr[0] = cb->nestptr[1]; - cb->nestptr[1] = NULL; - c = *(++ptr); - } - -#ifdef SUPPORT_WIDE_CHARS - /* If any wide characters have been encountered, set xclass = TRUE. Then, - in the pre-compile phase, accumulate the length of the wide characters - and reset the pointer. This is so that very large classes that contain a - zillion wide characters do not overwrite the work space (which is on the - stack). */ - - if (class_uchardata > class_uchardata_base) - { - xclass = TRUE; - if (lengthptr != NULL) - { - *lengthptr += class_uchardata - class_uchardata_base; - class_uchardata = class_uchardata_base; - } - } -#endif - /* An unescaped ] ends the class */ - - if (c == CHAR_RIGHT_SQUARE_BRACKET && !inescq) break; - } /* End of main class-processing loop */ - - /* If this is the first thing in the branch, there can be no first char - setting, whatever the repeat count. Any reqcu setting must remain - unchanged after any kind of repeat. */ - - if (firstcuflags == REQ_UNSET) firstcuflags = REQ_NONE; - zerofirstcu = firstcu; - zerofirstcuflags = firstcuflags; - zeroreqcu = reqcu; - zeroreqcuflags = reqcuflags; - - /* If there are characters with values > 255, or Unicode property settings - (\p or \P), we have to compile an extended class, with its own opcode, - unless there were no property settings and there was a negated special such - as \S in the class, and PCRE2_UCP is not set, because in that case all - characters > 255 are in or not in the class, so any that were explicitly - given as well can be ignored. - - In the UCP case, if certain negated POSIX classes ([:^ascii:] or - [^:xdigit:]) were present in a class, we either have to match or not match - all wide characters (depending on whether the whole class is or is not - negated). This requirement is indicated by match_all_or_no_wide_chars being - true. We do this by including an explicit range, which works in both cases. - - If, when generating an xclass, there are no characters < 256, we can omit - the bitmap in the actual compiled code. */ - -#ifdef SUPPORT_WIDE_CHARS -#ifdef SUPPORT_UNICODE - if (xclass && (xclass_has_prop || !should_flip_negation || - (options & PCRE2_UCP) != 0)) -#elif PCRE2_CODE_UNIT_WIDTH != 8 - if (xclass && (xclass_has_prop || !should_flip_negation)) -#endif - { - if (match_all_or_no_wide_chars) - { - *class_uchardata++ = XCL_RANGE; - class_uchardata += PRIV(ord2utf)(0x100, class_uchardata); - class_uchardata += PRIV(ord2utf)(MAX_UTF_CODE_POINT, class_uchardata); - } - *class_uchardata++ = XCL_END; /* Marks the end of extra data */ - *code++ = OP_XCLASS; - code += LINK_SIZE; - *code = negate_class? XCL_NOT:0; - if (xclass_has_prop) *code |= XCL_HASPROP; - - /* If the map is required, move up the extra data to make room for it; - otherwise just move the code pointer to the end of the extra data. */ - - if (class_has_8bitchar > 0) - { - *code++ |= XCL_MAP; - memmove(code + (32 / sizeof(PCRE2_UCHAR)), code, - CU2BYTES(class_uchardata - code)); - if (negate_class && !xclass_has_prop) - for (c = 0; c < 32; c++) classbits[c] = ~classbits[c]; - memcpy(code, classbits, 32); - code = class_uchardata + (32 / sizeof(PCRE2_UCHAR)); - } - else code = class_uchardata; - - /* Now fill in the complete length of the item */ - - PUT(previous, 1, (int)(code - previous)); - break; /* End of class handling */ - } -#endif - - /* If there are no characters > 255, or they are all to be included or - excluded, set the opcode to OP_CLASS or OP_NCLASS, depending on whether the - whole class was negated and whether there were negative specials such as \S - (non-UCP) in the class. Then copy the 32-byte map into the code vector, - negating it if necessary. */ - - *code++ = (negate_class == should_flip_negation) ? OP_CLASS : OP_NCLASS; - if (lengthptr == NULL) /* Save time in the pre-compile phase */ - { - if (negate_class) - for (c = 0; c < 32; c++) classbits[c] = ~classbits[c]; - memcpy(code, classbits, 32); - } - code += 32 / sizeof(PCRE2_UCHAR); - - END_CLASS: - break; - - - /* ===================================================================*/ - /* Various kinds of repeat; '{' is not necessarily a quantifier, but this - has been tested above. */ - - case CHAR_LEFT_CURLY_BRACKET: - if (!is_quantifier) goto NORMAL_CHAR; - ptr = read_repeat_counts(ptr+1, &repeat_min, &repeat_max, errorcodeptr); - if (*errorcodeptr != 0) goto FAILED; - goto REPEAT; - - case CHAR_ASTERISK: - repeat_min = 0; - repeat_max = -1; - goto REPEAT; - - case CHAR_PLUS: - repeat_min = 1; - repeat_max = -1; - goto REPEAT; - - case CHAR_QUESTION_MARK: - repeat_min = 0; - repeat_max = 1; - - REPEAT: - if (previous == NULL) - { - *errorcodeptr = ERR9; - goto FAILED; - } - - if (repeat_min == 0) - { - firstcu = zerofirstcu; /* Adjust for zero repeat */ - firstcuflags = zerofirstcuflags; - reqcu = zeroreqcu; /* Ditto */ - reqcuflags = zeroreqcuflags; - } - - /* Remember whether this is a variable length repeat */ - - reqvary = (repeat_min == repeat_max)? 0 : REQ_VARY; - - op_type = 0; /* Default single-char op codes */ - possessive_quantifier = FALSE; /* Default not possessive quantifier */ - - /* Save start of previous item, in case we have to move it up in order to - insert something before it. */ - - tempcode = previous; - - /* Before checking for a possessive quantifier, we must skip over - whitespace and comments in extended mode because Perl allows white space at - this point. */ - - if ((options & PCRE2_EXTENDED) != 0) - { - ptr++; - for (;;) - { - while (MAX_255(*ptr) && (cb->ctypes[*ptr] & ctype_space) != 0) ptr++; - if (*ptr != CHAR_NUMBER_SIGN) break; - ptr++; - while (ptr < cb->end_pattern) - { - if (IS_NEWLINE(ptr)) /* For non-fixed-length newline cases, */ - { /* IS_NEWLINE sets cb->nllen. */ - ptr += cb->nllen; - break; - } - ptr++; -#ifdef SUPPORT_UNICODE - if (utf) FORWARDCHAR(ptr); -#endif - } /* Loop for comment characters */ - } /* Loop for multiple comments */ - ptr--; /* Last code unit of previous character. */ - } - - /* If the next character is '+', we have a possessive quantifier. This - implies greediness, whatever the setting of the PCRE2_UNGREEDY option. - If the next character is '?' this is a minimizing repeat, by default, - but if PCRE2_UNGREEDY is set, it works the other way round. We change the - repeat type to the non-default. */ - - if (ptr[1] == CHAR_PLUS) - { - repeat_type = 0; /* Force greedy */ - possessive_quantifier = TRUE; - ptr++; - } - else if (ptr[1] == CHAR_QUESTION_MARK) - { - repeat_type = greedy_non_default; - ptr++; - } - else repeat_type = greedy_default; - - /* If the repeat is {1} we can ignore it. */ - - if (repeat_max == 1 && repeat_min == 1) goto END_REPEAT; - - /* If previous was a recursion call, wrap it in atomic brackets so that - previous becomes the atomic group. All recursions were so wrapped in the - past, but it no longer happens for non-repeated recursions. In fact, the - repeated ones could be re-implemented independently so as not to need this, - but for the moment we rely on the code for repeating groups. */ - - if (*previous == OP_RECURSE) - { - memmove(previous + 1 + LINK_SIZE, previous, CU2BYTES(1 + LINK_SIZE)); - *previous = OP_ONCE; - PUT(previous, 1, 2 + 2*LINK_SIZE); - previous[2 + 2*LINK_SIZE] = OP_KET; - PUT(previous, 3 + 2*LINK_SIZE, 2 + 2*LINK_SIZE); - code += 2 + 2 * LINK_SIZE; - length_prevgroup = 3 + 3*LINK_SIZE; - } - - /* Now handle repetition for the different types of item. */ - - /* If previous was a character or negated character match, abolish the item - and generate a repeat item instead. If a char item has a minimum of more - than one, ensure that it is set in reqcu - it might not be if a sequence - such as x{3} is the first thing in a branch because the x will have gone - into firstcu instead. */ - - if (*previous == OP_CHAR || *previous == OP_CHARI - || *previous == OP_NOT || *previous == OP_NOTI) - { - switch (*previous) - { - default: /* Make compiler happy. */ - case OP_CHAR: op_type = OP_STAR - OP_STAR; break; - case OP_CHARI: op_type = OP_STARI - OP_STAR; break; - case OP_NOT: op_type = OP_NOTSTAR - OP_STAR; break; - case OP_NOTI: op_type = OP_NOTSTARI - OP_STAR; break; - } - - /* Deal with UTF characters that take up more than one code unit. It's - easier to write this out separately than try to macrify it. Use c to - hold the length of the character in code units, plus UTF_LENGTH to flag - that it's a length rather than a small character. */ - -#ifdef MAYBE_UTF_MULTI - if (utf && NOT_FIRSTCU(code[-1])) - { - PCRE2_UCHAR *lastchar = code - 1; - BACKCHAR(lastchar); - c = (int)(code - lastchar); /* Length of UTF character */ - memcpy(utf_units, lastchar, CU2BYTES(c)); /* Save the char */ - c |= UTF_LENGTH; /* Flag c as a length */ - } - else -#endif /* MAYBE_UTF_MULTI */ - - /* Handle the case of a single charater - either with no UTF support, or - with UTF disabled, or for a single-code-unit UTF character. */ - { - c = code[-1]; - if (*previous <= OP_CHARI && repeat_min > 1) - { - reqcu = c; - reqcuflags = req_caseopt | cb->req_varyopt; - } - } - - goto OUTPUT_SINGLE_REPEAT; /* Code shared with single character types */ - } - - /* If previous was a character type match (\d or similar), abolish it and - create a suitable repeat item. The code is shared with single-character - repeats by setting op_type to add a suitable offset into repeat_type. Note - the the Unicode property types will be present only when SUPPORT_UNICODE is - defined, but we don't wrap the little bits of code here because it just - makes it horribly messy. */ - - else if (*previous < OP_EODN) - { - PCRE2_UCHAR *oldcode; - int prop_type, prop_value; - op_type = OP_TYPESTAR - OP_STAR; /* Use type opcodes */ - c = *previous; /* Save previous opcode */ - if (c == OP_PROP || c == OP_NOTPROP) - { - prop_type = previous[1]; - prop_value = previous[2]; - } - else - { - /* Come here from just above with a character in c */ - OUTPUT_SINGLE_REPEAT: - prop_type = prop_value = -1; - } - - /* At this point we either have prop_type == prop_value == -1 and either - a code point or a character type that is not OP_[NOT]PROP in c, or we - have OP_[NOT]PROP in c and prop_type/prop_value not negative. */ - - oldcode = code; /* Save where we were */ - code = previous; /* Usually overwrite previous item */ - - /* If the maximum is zero then the minimum must also be zero; Perl allows - this case, so we do too - by simply omitting the item altogether. */ - - if (repeat_max == 0) goto END_REPEAT; - - /* Combine the op_type with the repeat_type */ - - repeat_type += op_type; - - /* A minimum of zero is handled either as the special case * or ?, or as - an UPTO, with the maximum given. */ - - if (repeat_min == 0) - { - if (repeat_max == -1) *code++ = OP_STAR + repeat_type; - else if (repeat_max == 1) *code++ = OP_QUERY + repeat_type; - else - { - *code++ = OP_UPTO + repeat_type; - PUT2INC(code, 0, repeat_max); - } - } - - /* A repeat minimum of 1 is optimized into some special cases. If the - maximum is unlimited, we use OP_PLUS. Otherwise, the original item is - left in place and, if the maximum is greater than 1, we use OP_UPTO with - one less than the maximum. */ - - else if (repeat_min == 1) - { - if (repeat_max == -1) - *code++ = OP_PLUS + repeat_type; - else - { - code = oldcode; /* Leave previous item in place */ - if (repeat_max == 1) goto END_REPEAT; - *code++ = OP_UPTO + repeat_type; - PUT2INC(code, 0, repeat_max - 1); - } - } - - /* The case {n,n} is just an EXACT, while the general case {n,m} is - handled as an EXACT followed by an UPTO or STAR or QUERY. */ - - else - { - *code++ = OP_EXACT + op_type; /* NB EXACT doesn't have repeat_type */ - PUT2INC(code, 0, repeat_min); - - /* Unless repeat_max equals repeat_min, fill in the data for EXACT, and - then generate the second opcode. In UTF mode, multi-code-unit - characters have their length in c, with the UTF_LENGTH bit as a flag, - and the code units in utf_units. For a repeated Unicode property match, - there are two extra values that define the required property, and c - never has the UTF_LENGTH bit set. */ - - if (repeat_max != repeat_min) - { -#ifdef MAYBE_UTF_MULTI - if (utf && (c & UTF_LENGTH) != 0) - { - memcpy(code, utf_units, CU2BYTES(c & 7)); - code += c & 7; - } - else -#endif /* MAYBE_UTF_MULTI */ - { - *code++ = c; - if (prop_type >= 0) - { - *code++ = prop_type; - *code++ = prop_value; - } - } - - /* Now set up the following opcode */ - - if (repeat_max < 0) *code++ = OP_STAR + repeat_type; else - { - repeat_max -= repeat_min; - if (repeat_max == 1) - { - *code++ = OP_QUERY + repeat_type; - } - else - { - *code++ = OP_UPTO + repeat_type; - PUT2INC(code, 0, repeat_max); - } - } - } - } - - /* Fill in the character or character type for the final opcode. */ - -#ifdef MAYBE_UTF_MULTI - if (utf && (c & UTF_LENGTH) != 0) - { - memcpy(code, utf_units, CU2BYTES(c & 7)); - code += c & 7; - } - else -#endif /* MAYBEW_UTF_MULTI */ - { - *code++ = c; - if (prop_type >= 0) - { - *code++ = prop_type; - *code++ = prop_value; - } - } - } - - /* If previous was a character class or a back reference, we put the repeat - stuff after it, but just skip the item if the repeat was {0,0}. */ - - else if (*previous == OP_CLASS || *previous == OP_NCLASS || -#ifdef SUPPORT_WIDE_CHARS - *previous == OP_XCLASS || -#endif - *previous == OP_REF || *previous == OP_REFI || - *previous == OP_DNREF || *previous == OP_DNREFI) - { - if (repeat_max == 0) - { - code = previous; - goto END_REPEAT; - } - - if (repeat_min == 0 && repeat_max == -1) - *code++ = OP_CRSTAR + repeat_type; - else if (repeat_min == 1 && repeat_max == -1) - *code++ = OP_CRPLUS + repeat_type; - else if (repeat_min == 0 && repeat_max == 1) - *code++ = OP_CRQUERY + repeat_type; - else - { - *code++ = OP_CRRANGE + repeat_type; - PUT2INC(code, 0, repeat_min); - if (repeat_max == -1) repeat_max = 0; /* 2-byte encoding for max */ - PUT2INC(code, 0, repeat_max); - } - } - - /* If previous was a bracket group, we may have to replicate it in certain - cases. Note that at this point we can encounter only the "basic" bracket - opcodes such as BRA and CBRA, as this is the place where they get converted - into the more special varieties such as BRAPOS and SBRA. A test for >= - OP_ASSERT and <= OP_COND includes ASSERT, ASSERT_NOT, ASSERTBACK, - ASSERTBACK_NOT, ONCE, ONCE_NC, BRA, BRAPOS, CBRA, CBRAPOS, and COND. - Originally, PCRE did not allow repetition of assertions, but now it does, - for Perl compatibility. */ - - else if (*previous >= OP_ASSERT && *previous <= OP_COND) - { - register int i; - int len = (int)(code - previous); - PCRE2_UCHAR *bralink = NULL; - PCRE2_UCHAR *brazeroptr = NULL; - - /* Repeating a DEFINE group (or any group where the condition is always - FALSE and there is only one branch) is pointless, but Perl allows the - syntax, so we just ignore the repeat. */ - - if (*previous == OP_COND && previous[LINK_SIZE+1] == OP_FALSE && - previous[GET(previous, 1)] != OP_ALT) - goto END_REPEAT; - - /* There is no sense in actually repeating assertions. The only potential - use of repetition is in cases when the assertion is optional. Therefore, - if the minimum is greater than zero, just ignore the repeat. If the - maximum is not zero or one, set it to 1. */ - - if (*previous < OP_ONCE) /* Assertion */ - { - if (repeat_min > 0) goto END_REPEAT; - if (repeat_max < 0 || repeat_max > 1) repeat_max = 1; - } - - /* The case of a zero minimum is special because of the need to stick - OP_BRAZERO in front of it, and because the group appears once in the - data, whereas in other cases it appears the minimum number of times. For - this reason, it is simplest to treat this case separately, as otherwise - the code gets far too messy. There are several special subcases when the - minimum is zero. */ - - if (repeat_min == 0) - { - /* If the maximum is also zero, we used to just omit the group from the - output altogether, like this: - - ** if (repeat_max == 0) - ** { - ** code = previous; - ** goto END_REPEAT; - ** } - - However, that fails when a group or a subgroup within it is referenced - as a subroutine from elsewhere in the pattern, so now we stick in - OP_SKIPZERO in front of it so that it is skipped on execution. As we - don't have a list of which groups are referenced, we cannot do this - selectively. - - If the maximum is 1 or unlimited, we just have to stick in the BRAZERO - and do no more at this point. */ - - if (repeat_max <= 1) /* Covers 0, 1, and unlimited */ - { - memmove(previous + 1, previous, CU2BYTES(len)); - code++; - if (repeat_max == 0) - { - *previous++ = OP_SKIPZERO; - goto END_REPEAT; - } - brazeroptr = previous; /* Save for possessive optimizing */ - *previous++ = OP_BRAZERO + repeat_type; - } - - /* If the maximum is greater than 1 and limited, we have to replicate - in a nested fashion, sticking OP_BRAZERO before each set of brackets. - The first one has to be handled carefully because it's the original - copy, which has to be moved up. The remainder can be handled by code - that is common with the non-zero minimum case below. We have to - adjust the value or repeat_max, since one less copy is required. */ - - else - { - int offset; - memmove(previous + 2 + LINK_SIZE, previous, CU2BYTES(len)); - code += 2 + LINK_SIZE; - *previous++ = OP_BRAZERO + repeat_type; - *previous++ = OP_BRA; - - /* We chain together the bracket offset fields that have to be - filled in later when the ends of the brackets are reached. */ - - offset = (bralink == NULL)? 0 : (int)(previous - bralink); - bralink = previous; - PUTINC(previous, 0, offset); - } - - repeat_max--; - } - - /* If the minimum is greater than zero, replicate the group as many - times as necessary, and adjust the maximum to the number of subsequent - copies that we need. */ - - else - { - if (repeat_min > 1) - { - /* In the pre-compile phase, we don't actually do the replication. We - just adjust the length as if we had. Do some paranoid checks for - potential integer overflow. The INT64_OR_DOUBLE type is a 64-bit - integer type when available, otherwise double. */ - - if (lengthptr != NULL) - { - size_t delta = (repeat_min - 1)*length_prevgroup; - if ((INT64_OR_DOUBLE)(repeat_min - 1)* - (INT64_OR_DOUBLE)length_prevgroup > - (INT64_OR_DOUBLE)INT_MAX || - OFLOW_MAX - *lengthptr < delta) - { - *errorcodeptr = ERR20; - goto FAILED; - } - *lengthptr += delta; - } - - /* This is compiling for real. If there is a set first byte for - the group, and we have not yet set a "required byte", set it. */ - - else - { - if (groupsetfirstcu && reqcuflags < 0) - { - reqcu = firstcu; - reqcuflags = firstcuflags; - } - for (i = 1; i < repeat_min; i++) - { - memcpy(code, previous, CU2BYTES(len)); - code += len; - } - } - } - - if (repeat_max > 0) repeat_max -= repeat_min; - } - - /* This code is common to both the zero and non-zero minimum cases. If - the maximum is limited, it replicates the group in a nested fashion, - remembering the bracket starts on a stack. In the case of a zero minimum, - the first one was set up above. In all cases the repeat_max now specifies - the number of additional copies needed. Again, we must remember to - replicate entries on the forward reference list. */ - - if (repeat_max >= 0) - { - /* In the pre-compile phase, we don't actually do the replication. We - just adjust the length as if we had. For each repetition we must add 1 - to the length for BRAZERO and for all but the last repetition we must - add 2 + 2*LINKSIZE to allow for the nesting that occurs. Do some - paranoid checks to avoid integer overflow. The INT64_OR_DOUBLE type is - a 64-bit integer type when available, otherwise double. */ - - if (lengthptr != NULL && repeat_max > 0) - { - size_t delta = repeat_max*(length_prevgroup + 1 + 2 + 2*LINK_SIZE) - - 2 - 2*LINK_SIZE; /* Last one doesn't nest */ - if ((INT64_OR_DOUBLE)repeat_max * - (INT64_OR_DOUBLE)(length_prevgroup + 1 + 2 + 2*LINK_SIZE) - > (INT64_OR_DOUBLE)INT_MAX || - OFLOW_MAX - *lengthptr < delta) - { - *errorcodeptr = ERR20; - goto FAILED; - } - *lengthptr += delta; - } - - /* This is compiling for real */ - - else for (i = repeat_max - 1; i >= 0; i--) - { - *code++ = OP_BRAZERO + repeat_type; - - /* All but the final copy start a new nesting, maintaining the - chain of brackets outstanding. */ - - if (i != 0) - { - int offset; - *code++ = OP_BRA; - offset = (bralink == NULL)? 0 : (int)(code - bralink); - bralink = code; - PUTINC(code, 0, offset); - } - - memcpy(code, previous, CU2BYTES(len)); - code += len; - } - - /* Now chain through the pending brackets, and fill in their length - fields (which are holding the chain links pro tem). */ - - while (bralink != NULL) - { - int oldlinkoffset; - int offset = (int)(code - bralink + 1); - PCRE2_UCHAR *bra = code - offset; - oldlinkoffset = GET(bra, 1); - bralink = (oldlinkoffset == 0)? NULL : bralink - oldlinkoffset; - *code++ = OP_KET; - PUTINC(code, 0, offset); - PUT(bra, 1, offset); - } - } - - /* If the maximum is unlimited, set a repeater in the final copy. For - ONCE brackets, that's all we need to do. However, possessively repeated - ONCE brackets can be converted into non-capturing brackets, as the - behaviour of (?:xx)++ is the same as (?>xx)++ and this saves having to - deal with possessive ONCEs specially. - - Otherwise, when we are doing the actual compile phase, check to see - whether this group is one that could match an empty string. If so, - convert the initial operator to the S form (e.g. OP_BRA -> OP_SBRA) so - that runtime checking can be done. [This check is also applied to ONCE - groups at runtime, but in a different way.] - - Then, if the quantifier was possessive and the bracket is not a - conditional, we convert the BRA code to the POS form, and the KET code to - KETRPOS. (It turns out to be convenient at runtime to detect this kind of - subpattern at both the start and at the end.) The use of special opcodes - makes it possible to reduce greatly the stack usage in pcre2_match(). If - the group is preceded by OP_BRAZERO, convert this to OP_BRAPOSZERO. - - Then, if the minimum number of matches is 1 or 0, cancel the possessive - flag so that the default action below, of wrapping everything inside - atomic brackets, does not happen. When the minimum is greater than 1, - there will be earlier copies of the group, and so we still have to wrap - the whole thing. */ - - else - { - PCRE2_UCHAR *ketcode = code - 1 - LINK_SIZE; - PCRE2_UCHAR *bracode = ketcode - GET(ketcode, 1); - - /* Convert possessive ONCE brackets to non-capturing */ - - if ((*bracode == OP_ONCE || *bracode == OP_ONCE_NC) && - possessive_quantifier) *bracode = OP_BRA; - - /* For non-possessive ONCE brackets, all we need to do is to - set the KET. */ - - if (*bracode == OP_ONCE || *bracode == OP_ONCE_NC) - *ketcode = OP_KETRMAX + repeat_type; - - /* Handle non-ONCE brackets and possessive ONCEs (which have been - converted to non-capturing above). */ - - else - { - /* In the compile phase, check whether the group could match an empty - string. */ - - if (lengthptr == NULL) - { - PCRE2_UCHAR *scode = bracode; - do - { - int count = 0; - int rc = could_be_empty_branch(scode, ketcode, utf, cb, FALSE, - NULL, &count); - if (rc < 0) - { - *errorcodeptr = ERR86; - goto FAILED; - } - if (rc > 0) - { - *bracode += OP_SBRA - OP_BRA; - break; - } - scode += GET(scode, 1); - } - while (*scode == OP_ALT); - - /* A conditional group with only one branch has an implicit empty - alternative branch. */ - - if (*bracode == OP_COND && bracode[GET(bracode,1)] != OP_ALT) - *bracode = OP_SCOND; - } - - /* Handle possessive quantifiers. */ - - if (possessive_quantifier) - { - /* For COND brackets, we wrap the whole thing in a possessively - repeated non-capturing bracket, because we have not invented POS - versions of the COND opcodes. */ - - if (*bracode == OP_COND || *bracode == OP_SCOND) - { - int nlen = (int)(code - bracode); - memmove(bracode + 1 + LINK_SIZE, bracode, CU2BYTES(nlen)); - code += 1 + LINK_SIZE; - nlen += 1 + LINK_SIZE; - *bracode = (*bracode == OP_COND)? OP_BRAPOS : OP_SBRAPOS; - *code++ = OP_KETRPOS; - PUTINC(code, 0, nlen); - PUT(bracode, 1, nlen); - } - - /* For non-COND brackets, we modify the BRA code and use KETRPOS. */ - - else - { - *bracode += 1; /* Switch to xxxPOS opcodes */ - *ketcode = OP_KETRPOS; - } - - /* If the minimum is zero, mark it as possessive, then unset the - possessive flag when the minimum is 0 or 1. */ - - if (brazeroptr != NULL) *brazeroptr = OP_BRAPOSZERO; - if (repeat_min < 2) possessive_quantifier = FALSE; - } - - /* Non-possessive quantifier */ - - else *ketcode = OP_KETRMAX + repeat_type; - } - } - } - - /* If previous is OP_FAIL, it was generated by an empty class [] - (PCRE2_ALLOW_EMPTY_CLASS is set). The other ways in which OP_FAIL can be - generated, that is by (*FAIL) or (?!), set previous to NULL, which gives a - "nothing to repeat" error above. We can just ignore the repeat in empty - class case. */ - - else if (*previous == OP_FAIL) goto END_REPEAT; - - /* Else there's some kind of shambles */ - - else - { - *errorcodeptr = ERR10; - goto FAILED; - } - - /* If the character following a repeat is '+', possessive_quantifier is - TRUE. For some opcodes, there are special alternative opcodes for this - case. For anything else, we wrap the entire repeated item inside OP_ONCE - brackets. Logically, the '+' notation is just syntactic sugar, taken from - Sun's Java package, but the special opcodes can optimize it. - - Some (but not all) possessively repeated subpatterns have already been - completely handled in the code just above. For them, possessive_quantifier - is always FALSE at this stage. Note that the repeated item starts at - tempcode, not at previous, which might be the first part of a string whose - (former) last char we repeated. */ - - if (possessive_quantifier) - { - int len; - - /* Possessifying an EXACT quantifier has no effect, so we can ignore it. - However, QUERY, STAR, or UPTO may follow (for quantifiers such as {5,6}, - {5,}, or {5,10}). We skip over an EXACT item; if the length of what - remains is greater than zero, there's a further opcode that can be - handled. If not, do nothing, leaving the EXACT alone. */ - - switch(*tempcode) - { - case OP_TYPEEXACT: - tempcode += PRIV(OP_lengths)[*tempcode] + - ((tempcode[1 + IMM2_SIZE] == OP_PROP - || tempcode[1 + IMM2_SIZE] == OP_NOTPROP)? 2 : 0); - break; - - /* CHAR opcodes are used for exacts whose count is 1. */ - - case OP_CHAR: - case OP_CHARI: - case OP_NOT: - case OP_NOTI: - case OP_EXACT: - case OP_EXACTI: - case OP_NOTEXACT: - case OP_NOTEXACTI: - tempcode += PRIV(OP_lengths)[*tempcode]; -#ifdef SUPPORT_UNICODE - if (utf && HAS_EXTRALEN(tempcode[-1])) - tempcode += GET_EXTRALEN(tempcode[-1]); -#endif - break; - - /* For the class opcodes, the repeat operator appears at the end; - adjust tempcode to point to it. */ - - case OP_CLASS: - case OP_NCLASS: - tempcode += 1 + 32/sizeof(PCRE2_UCHAR); - break; - -#ifdef SUPPORT_WIDE_CHARS - case OP_XCLASS: - tempcode += GET(tempcode, 1); - break; -#endif - } - - /* If tempcode is equal to code (which points to the end of the repeated - item), it means we have skipped an EXACT item but there is no following - QUERY, STAR, or UPTO; the value of len will be 0, and we do nothing. In - all other cases, tempcode will be pointing to the repeat opcode, and will - be less than code, so the value of len will be greater than 0. */ - - len = (int)(code - tempcode); - if (len > 0) - { - unsigned int repcode = *tempcode; - - /* There is a table for possessifying opcodes, all of which are less - than OP_CALLOUT. A zero entry means there is no possessified version. - */ - - if (repcode < OP_CALLOUT && opcode_possessify[repcode] > 0) - *tempcode = opcode_possessify[repcode]; - - /* For opcode without a special possessified version, wrap the item in - ONCE brackets. */ - - else - { - memmove(tempcode + 1 + LINK_SIZE, tempcode, CU2BYTES(len)); - code += 1 + LINK_SIZE; - len += 1 + LINK_SIZE; - tempcode[0] = OP_ONCE; - *code++ = OP_KET; - PUTINC(code, 0, len); - PUT(tempcode, 1, len); - } - } - } - - /* In all case we no longer have a previous item. We also set the - "follows varying string" flag for subsequently encountered reqcus if - it isn't already set and we have just passed a varying length item. */ - - END_REPEAT: - previous = NULL; - cb->req_varyopt |= reqvary; - break; - - - /* ===================================================================*/ - /* Start of nested parenthesized sub-expression, or lookahead or lookbehind - or option setting or condition or all the other extended parenthesis forms. - We must save the current high-water-mark for the forward reference list so - that we know where they start for this group. However, because the list may - be extended when there are very many forward references (usually the result - of a replicated inner group), we must use an offset rather than an absolute - address. Note that (?# comments are dealt with at the top of the loop; - they do not get this far. */ - - case CHAR_LEFT_PARENTHESIS: - ptr++; - - /* Deal with various "verbs" that can be introduced by '*'. */ - - if (ptr[0] == CHAR_ASTERISK && (ptr[1] == ':' - || (MAX_255(ptr[1]) && ((cb->ctypes[ptr[1]] & ctype_letter) != 0)))) - { - int i, namelen; - int arglen = 0; - const char *vn = verbnames; - PCRE2_SPTR name = ptr + 1; - PCRE2_SPTR arg = NULL; - previous = NULL; - ptr++; - - /* Increment ptr, set namelen, check length */ - - READ_NAME(ctype_letter, ERR60, *errorcodeptr); - - /* It appears that Perl allows any characters whatsoever, other than - a closing parenthesis, to appear in arguments, so we no longer insist on - letters, digits, and underscores. Perl does not, however, do any - interpretation within arguments, and has no means of including a closing - parenthesis. PCRE supports escape processing but only when it is - requested by an option. Note that check_escape() will not return values - greater than the code unit maximum when not in UTF mode. */ - - if (*ptr == CHAR_COLON) - { - arg = ++ptr; - - if ((options & PCRE2_ALT_VERBNAMES) == 0) - { - arglen = 0; - while (ptr < cb->end_pattern && *ptr != CHAR_RIGHT_PARENTHESIS) - { - ptr++; /* Check length as we go */ - arglen++; /* along, to avoid the */ - if ((unsigned int)arglen > MAX_MARK) /* possibility of overflow. */ - { - *errorcodeptr = ERR76; - goto FAILED; - } - } - } - else - { - /* The length check is in process_verb_names() */ - arglen = process_verb_name(&ptr, NULL, errorcodeptr, options, - utf, cb); - if (arglen < 0) goto FAILED; - } - } - - if (*ptr != CHAR_RIGHT_PARENTHESIS) - { - *errorcodeptr = ERR60; - goto FAILED; - } - - /* Scan the table of verb names */ - - for (i = 0; i < verbcount; i++) - { - if (namelen == verbs[i].len && - PRIV(strncmp_c8)(name, vn, namelen) == 0) - { - int setverb; - - /* Check for open captures before ACCEPT and convert it to - ASSERT_ACCEPT if in an assertion. */ - - if (verbs[i].op == OP_ACCEPT) - { - open_capitem *oc; - if (arglen != 0) - { - *errorcodeptr = ERR59; - goto FAILED; - } - cb->had_accept = TRUE; - - /* In the first pass, just accumulate the length required; - otherwise hitting (*ACCEPT) inside many nested parentheses can - cause workspace overflow. */ - - for (oc = cb->open_caps; oc != NULL; oc = oc->next) - { - if (lengthptr != NULL) - { - *lengthptr += CU2BYTES(1) + IMM2_SIZE; - } - else - { - *code++ = OP_CLOSE; - PUT2INC(code, 0, oc->number); - } - } - setverb = *code++ = - (cb->assert_depth > 0)? OP_ASSERT_ACCEPT : OP_ACCEPT; - - /* Do not set firstcu after *ACCEPT */ - if (firstcuflags == REQ_UNSET) firstcuflags = REQ_NONE; - } - - /* Handle other cases with/without an argument */ - - else if (arglen == 0) /* There is no argument */ - { - if (verbs[i].op < 0) /* Argument is mandatory */ - { - *errorcodeptr = ERR66; - goto FAILED; - } - setverb = *code++ = verbs[i].op; - } - - else /* An argument is present */ - { - if (verbs[i].op_arg < 0) /* Argument is forbidden */ - { - *errorcodeptr = ERR59; - goto FAILED; - } - setverb = *code++ = verbs[i].op_arg; - - /* Arguments can be very long, especially in 16- and 32-bit modes, - and can overflow the workspace in the first pass. Instead of - putting the argument into memory, we just update the length counter - and set up an empty argument. */ - - if (lengthptr != NULL) - { - *lengthptr += arglen; - *code++ = 0; - } - else - { - *code++ = arglen; - if ((options & PCRE2_ALT_VERBNAMES) != 0) - { - PCRE2_UCHAR *memcode = code; /* code is "register" */ - (void)process_verb_name(&arg, &memcode, errorcodeptr, options, - utf, cb); - code = memcode; - } - else /* No argument processing */ - { - memcpy(code, arg, CU2BYTES(arglen)); - code += arglen; - } - } - - *code++ = 0; - } - - switch (setverb) - { - case OP_THEN: - case OP_THEN_ARG: - cb->external_flags |= PCRE2_HASTHEN; - break; - - case OP_PRUNE: - case OP_PRUNE_ARG: - case OP_SKIP: - case OP_SKIP_ARG: - cb->had_pruneorskip = TRUE; - break; - } - - break; /* Found verb, exit loop */ - } - - vn += verbs[i].len + 1; - } - - if (i < verbcount) continue; /* Successfully handled a verb */ - *errorcodeptr = ERR60; /* Verb not recognized */ - goto FAILED; - } - - /* Initialization for "real" parentheses */ - - newoptions = options; - skipunits = 0; - bravalue = OP_CBRA; - reset_bracount = FALSE; - - /* Deal with the extended parentheses; all are introduced by '?', and the - appearance of any of them means that this is not a capturing group. */ - - if (*ptr == CHAR_QUESTION_MARK) - { - int i, count; - int namelen; /* Must be signed */ - uint32_t index; - uint32_t set, unset, *optset; - named_group *ng; - PCRE2_SPTR name; - PCRE2_UCHAR *slot; - - switch (*(++ptr)) - { - /* ------------------------------------------------------------ */ - case CHAR_VERTICAL_LINE: /* Reset capture count for each branch */ - reset_bracount = TRUE; - /* Fall through */ - - /* ------------------------------------------------------------ */ - case CHAR_COLON: /* Non-capturing bracket */ - bravalue = OP_BRA; - ptr++; - break; - - /* ------------------------------------------------------------ */ - case CHAR_LEFT_PARENTHESIS: - bravalue = OP_COND; /* Conditional group */ - tempptr = ptr; - - /* A condition can be an assertion, a number (referring to a numbered - group's having been set), a name (referring to a named group), or 'R', - referring to recursion. R and R&name are also permitted for - recursion tests. - - There are ways of testing a named group: (?(name)) is used by Python; - Perl 5.10 onwards uses (?() or (?('name')). - - There is one unfortunate ambiguity, caused by history. 'R' can be the - recursive thing or the name 'R' (and similarly for 'R' followed by - digits). We look for a name first; if not found, we try the other case. - - For compatibility with auto-callouts, we allow a callout to be - specified before a condition that is an assertion. First, check for the - syntax of a callout; if found, adjust the temporary pointer that is - used to check for an assertion condition. That's all that is needed! */ - - if (ptr[1] == CHAR_QUESTION_MARK && ptr[2] == CHAR_C) - { - if (IS_DIGIT(ptr[3]) || ptr[3] == CHAR_RIGHT_PARENTHESIS) - { - for (i = 3;; i++) if (!IS_DIGIT(ptr[i])) break; - if (ptr[i] == CHAR_RIGHT_PARENTHESIS) - tempptr += i + 1; - } - else - { - uint32_t delimiter = 0; - for (i = 0; PRIV(callout_start_delims)[i] != 0; i++) - { - if (ptr[3] == PRIV(callout_start_delims)[i]) - { - delimiter = PRIV(callout_end_delims)[i]; - break; - } - } - if (delimiter != 0) - { - for (i = 4; ptr + i < cb->end_pattern; i++) - { - if (ptr[i] == delimiter) - { - if (ptr[i+1] == delimiter) i++; - else - { - if (ptr[i+1] == CHAR_RIGHT_PARENTHESIS) tempptr += i + 2; - break; - } - } - } - } - } - - /* tempptr should now be pointing to the opening parenthesis of the - assertion condition. */ - - if (*tempptr != CHAR_LEFT_PARENTHESIS) - { - *errorcodeptr = ERR28; - goto FAILED; - } - } - - /* For conditions that are assertions, check the syntax, and then exit - the switch. This will take control down to where bracketed groups - are processed. The assertion will be handled as part of the group, - but we need to identify this case because the conditional assertion may - not be quantifier. */ - - if (tempptr[1] == CHAR_QUESTION_MARK && - (tempptr[2] == CHAR_EQUALS_SIGN || - tempptr[2] == CHAR_EXCLAMATION_MARK || - (tempptr[2] == CHAR_LESS_THAN_SIGN && - (tempptr[3] == CHAR_EQUALS_SIGN || - tempptr[3] == CHAR_EXCLAMATION_MARK)))) - { - cb->iscondassert = TRUE; - break; - } - - /* Other conditions use OP_CREF/OP_DNCREF/OP_RREF/OP_DNRREF, and all - need to skip at least 1+IMM2_SIZE bytes at the start of the group. */ - - code[1+LINK_SIZE] = OP_CREF; - skipunits = 1+IMM2_SIZE; - refsign = -1; /* => not a number */ - namelen = -1; /* => not a name; must set to avoid warning */ - name = NULL; /* Always set to avoid warning */ - recno = 0; /* Always set to avoid warning */ - - /* Point at character after (?( */ - - ptr++; - - /* Check for (?(VERSION[>]=n.m), which is a facility whereby indirect - users of PCRE2 via an application can discover which release of PCRE2 - is being used. */ - - if (PRIV(strncmp_c8)(ptr, STRING_VERSION, 7) == 0 && - ptr[7] != CHAR_RIGHT_PARENTHESIS) - { - BOOL ge = FALSE; - int major = 0; - int minor = 0; - - ptr += 7; - if (*ptr == CHAR_GREATER_THAN_SIGN) - { - ge = TRUE; - ptr++; - } - - /* NOTE: cannot write IS_DIGIT(*(++ptr)) here because IS_DIGIT - references its argument twice. */ - - if (*ptr != CHAR_EQUALS_SIGN || (ptr++, !IS_DIGIT(*ptr))) - { - *errorcodeptr = ERR79; - goto FAILED; - } - - while (IS_DIGIT(*ptr)) major = major * 10 + *ptr++ - '0'; - if (*ptr == CHAR_DOT) - { - ptr++; - while (IS_DIGIT(*ptr)) minor = minor * 10 + *ptr++ - '0'; - if (minor < 10) minor *= 10; - } - - if (*ptr != CHAR_RIGHT_PARENTHESIS || minor > 99) - { - *errorcodeptr = ERR79; - goto FAILED; - } - - if (ge) - code[1+LINK_SIZE] = ((PCRE2_MAJOR > major) || - (PCRE2_MAJOR == major && PCRE2_MINOR >= minor))? - OP_TRUE : OP_FALSE; - else - code[1+LINK_SIZE] = (PCRE2_MAJOR == major && PCRE2_MINOR == minor)? - OP_TRUE : OP_FALSE; - - ptr++; - skipunits = 1; - break; /* End of condition processing */ - } - - /* Check for a test for recursion in a named group. */ - - if (*ptr == CHAR_R && ptr[1] == CHAR_AMPERSAND) - { - terminator = -1; - ptr += 2; - code[1+LINK_SIZE] = OP_RREF; /* Change the type of test */ - } - - /* Check for a test for a named group's having been set, using the Perl - syntax (?() or (?('name'), and also allow for the original PCRE - syntax of (?(name) or for (?(+n), (?(-n), and just (?(n). */ - - else if (*ptr == CHAR_LESS_THAN_SIGN) - { - terminator = CHAR_GREATER_THAN_SIGN; - ptr++; - } - else if (*ptr == CHAR_APOSTROPHE) - { - terminator = CHAR_APOSTROPHE; - ptr++; - } - else - { - terminator = CHAR_NULL; - if (*ptr == CHAR_MINUS || *ptr == CHAR_PLUS) refsign = *ptr++; - else if (IS_DIGIT(*ptr)) refsign = 0; - } - - /* Handle a number */ - - if (refsign >= 0) - { - while (IS_DIGIT(*ptr)) - { - if (recno > INT_MAX / 10 - 1) /* Integer overflow */ - { - while (IS_DIGIT(*ptr)) ptr++; - *errorcodeptr = ERR61; - goto FAILED; - } - recno = recno * 10 + (int)(*ptr - CHAR_0); - ptr++; - } - } - - /* Otherwise we expect to read a name; anything else is an error. When - the referenced name is one of a number of duplicates, a different - opcode is used and it needs more memory. Unfortunately we cannot tell - whether this is the case in the first pass, so we have to allow for - more memory always. In the second pass, the additional to skipunits - happens later. */ - - else - { - if (IS_DIGIT(*ptr)) - { - *errorcodeptr = ERR44; /* Group name must start with non-digit */ - goto FAILED; - } - if (!MAX_255(*ptr) || (cb->ctypes[*ptr] & ctype_word) == 0) - { - *errorcodeptr = ERR28; /* Assertion expected */ - goto FAILED; - } - name = ptr; - /* Increment ptr, set namelen, check length */ - READ_NAME(ctype_word, ERR48, *errorcodeptr); - if (lengthptr != NULL) skipunits += IMM2_SIZE; - } - - /* Check the terminator */ - - if ((terminator > 0 && *ptr++ != (PCRE2_UCHAR)terminator) || - *ptr++ != CHAR_RIGHT_PARENTHESIS) - { - ptr--; /* Error offset */ - *errorcodeptr = ERR26; /* Malformed number or name */ - goto FAILED; - } - - /* Do no further checking in the pre-compile phase. */ - - if (lengthptr != NULL) break; - - /* In the real compile we do the work of looking for the actual - reference. If refsign is not negative, it means we have a number in - recno. */ - - if (refsign >= 0) - { - if (recno <= 0) - { - *errorcodeptr = ERR35; - goto FAILED; - } - if (refsign != 0) recno = (refsign == CHAR_MINUS)? - (cb->bracount + 1) - recno : recno + cb->bracount; - if (recno <= 0 || (uint32_t)recno > cb->final_bracount) - { - *errorcodeptr = ERR15; - goto FAILED; - } - PUT2(code, 2+LINK_SIZE, recno); - if ((uint32_t)recno > cb->top_backref) cb->top_backref = recno; - break; - } - - /* Otherwise look for the name. */ - - slot = cb->name_table; - for (i = 0; i < cb->names_found; i++) - { - if (PRIV(strncmp)(name, slot+IMM2_SIZE, namelen) == 0) break; - slot += cb->name_entry_size; - } - - /* Found the named subpattern. If the name is duplicated, add one to - the opcode to change CREF/RREF into DNCREF/DNRREF and insert - appropriate data values. Otherwise, just insert the unique subpattern - number. */ - - if (i < cb->names_found) - { - int offset = i; /* Offset of first name found */ - - count = 0; - for (;;) - { - recno = GET2(slot, 0); /* Number for last found */ - if ((uint32_t)recno > cb->top_backref) cb->top_backref = recno; - count++; - if (++i >= cb->names_found) break; - slot += cb->name_entry_size; - if (PRIV(strncmp)(name, slot+IMM2_SIZE, namelen) != 0 || - (slot+IMM2_SIZE)[namelen] != 0) break; - } - - if (count > 1) - { - PUT2(code, 2+LINK_SIZE, offset); - PUT2(code, 2+LINK_SIZE+IMM2_SIZE, count); - skipunits += IMM2_SIZE; - code[1+LINK_SIZE]++; - } - else /* Not a duplicated name */ - { - PUT2(code, 2+LINK_SIZE, recno); - } - } - - /* If terminator == CHAR_NULL it means that the name followed directly - after the opening parenthesis [e.g. (?(abc)...] and in this case there - are some further alternatives to try. For the cases where terminator != - CHAR_NULL [things like (?(... or (?('name')... or (?(R&name)... ] - we have now checked all the possibilities, so give an error. */ - - else if (terminator != CHAR_NULL) - { - *errorcodeptr = ERR15; - goto FAILED; - } - - /* Check for (?(R) for recursion. Allow digits after R to specify a - specific group number. */ - - else if (*name == CHAR_R) - { - recno = 0; - for (i = 1; i < namelen; i++) - { - if (!IS_DIGIT(name[i])) - { - *errorcodeptr = ERR15; /* Non-existent subpattern */ - goto FAILED; - } - if (recno > INT_MAX / 10 - 1) /* Integer overflow */ - { - *errorcodeptr = ERR61; - goto FAILED; - } - recno = recno * 10 + name[i] - CHAR_0; - } - if (recno == 0) recno = RREF_ANY; - code[1+LINK_SIZE] = OP_RREF; /* Change test type */ - PUT2(code, 2+LINK_SIZE, recno); - } - - /* Similarly, check for the (?(DEFINE) "condition", which is always - false. During compilation we set OP_DEFINE to distinguish this from - other OP_FALSE conditions so that it can be checked for having only one - branch, but after that the opcode is changed to OP_FALSE. */ - - else if (namelen == 6 && PRIV(strncmp_c8)(name, STRING_DEFINE, 6) == 0) - { - code[1+LINK_SIZE] = OP_DEFINE; - skipunits = 1; - } - - /* Reference to an unidentified subpattern. */ - - else - { - *errorcodeptr = ERR15; - goto FAILED; - } - break; - - - /* ------------------------------------------------------------ */ - case CHAR_EQUALS_SIGN: /* Positive lookahead */ - bravalue = OP_ASSERT; - cb->assert_depth += 1; - ptr++; - break; - - /* Optimize (?!) to (*FAIL) unless it is quantified - which is a weird - thing to do, but Perl allows all assertions to be quantified, and when - they contain capturing parentheses there may be a potential use for - this feature. Not that that applies to a quantified (?!) but we allow - it for uniformity. */ - - /* ------------------------------------------------------------ */ - case CHAR_EXCLAMATION_MARK: /* Negative lookahead */ - ptr++; - if (*ptr == CHAR_RIGHT_PARENTHESIS && ptr[1] != CHAR_ASTERISK && - ptr[1] != CHAR_PLUS && ptr[1] != CHAR_QUESTION_MARK && - (ptr[1] != CHAR_LEFT_CURLY_BRACKET || !is_counted_repeat(ptr+2))) - { - *code++ = OP_FAIL; - previous = NULL; - continue; - } - bravalue = OP_ASSERT_NOT; - cb->assert_depth += 1; - break; - - - /* ------------------------------------------------------------ */ - case CHAR_LESS_THAN_SIGN: /* Lookbehind or named define */ - switch (ptr[1]) - { - case CHAR_EQUALS_SIGN: /* Positive lookbehind */ - bravalue = OP_ASSERTBACK; - cb->assert_depth += 1; - ptr += 2; - break; - - case CHAR_EXCLAMATION_MARK: /* Negative lookbehind */ - bravalue = OP_ASSERTBACK_NOT; - cb->assert_depth += 1; - ptr += 2; - break; - - /* Must be a name definition - as the syntax was checked in the - pre-pass, we can assume here that it is valid. Skip over the name - and go to handle the numbered group. */ - - default: - while (*(++ptr) != CHAR_GREATER_THAN_SIGN); - ptr++; - goto NUMBERED_GROUP; - } - break; - - - /* ------------------------------------------------------------ */ - case CHAR_GREATER_THAN_SIGN: /* One-time brackets */ - bravalue = OP_ONCE; - ptr++; - break; - - - /* ------------------------------------------------------------ */ - case CHAR_C: /* Callout */ - previous_callout = code; /* Save for later completion */ - after_manual_callout = 1; /* Skip one item before completing */ - ptr++; /* Character after (?C */ - - /* A callout may have a string argument, delimited by one of a fixed - number of characters, or an undelimited numerical argument, or no - argument, which is the same as (?C0). Different opcodes are used for - the two cases. */ - - if (*ptr != CHAR_RIGHT_PARENTHESIS && !IS_DIGIT(*ptr)) - { - uint32_t delimiter = 0; - - for (i = 0; PRIV(callout_start_delims)[i] != 0; i++) - { - if (*ptr == PRIV(callout_start_delims)[i]) - { - delimiter = PRIV(callout_end_delims)[i]; - break; - } - } - - if (delimiter == 0) - { - *errorcodeptr = ERR82; - goto FAILED; - } - - /* During the pre-compile phase, we parse the string and update the - length. There is no need to generate any code. (In fact, the string - has already been parsed in the pre-pass that looks for named - parentheses, but it does no harm to leave this code in.) */ - - if (lengthptr != NULL) /* Only check the string */ - { - PCRE2_SPTR start = ptr; - do - { - if (++ptr >= cb->end_pattern) - { - *errorcodeptr = ERR81; - ptr = start; /* To give a more useful message */ - goto FAILED; - } - if (ptr[0] == delimiter && ptr[1] == delimiter) ptr += 2; - } - while (ptr[0] != delimiter); - - /* Start points to the opening delimiter, ptr points to the - closing delimiter. We must allow for including the delimiter and - for the terminating zero. Any doubled delimiters within the string - make this an overestimate, but it is not worth bothering about. */ - - (*lengthptr) += (ptr - start) + 2 + (1 + 4*LINK_SIZE); - } - - /* In the real compile we can copy the string, knowing that it is - syntactically OK. The starting delimiter is included so that the - client can discover it if they want. We also pass the start offset to - help a script language give better error messages. */ - - else - { - PCRE2_UCHAR *callout_string = code + (1 + 4*LINK_SIZE); - *callout_string++ = *ptr++; - PUT(code, 1 + 3*LINK_SIZE, (int)(ptr - cb->start_pattern)); /* Start offset */ - for(;;) - { - if (*ptr == delimiter) - { - if (ptr[1] == delimiter) ptr++; else break; - } - *callout_string++ = *ptr++; - } - *callout_string++ = CHAR_NULL; - code[0] = OP_CALLOUT_STR; - PUT(code, 1, (int)(ptr + 2 - cb->start_pattern)); /* Next offset */ - PUT(code, 1 + LINK_SIZE, 0); /* Default length */ - PUT(code, 1 + 2*LINK_SIZE, /* Compute size */ - (int)(callout_string - code)); - code = callout_string; - } - - /* Advance to what should be the closing parenthesis, which is - checked below. */ - - ptr++; - } - - /* Handle a callout with an optional numerical argument, which must be - less than or equal to 255. A missing argument gives 0. */ - - else - { - int n = 0; - code[0] = OP_CALLOUT; /* Numerical callout */ - while (IS_DIGIT(*ptr)) - { - n = n * 10 + *ptr++ - CHAR_0; - if (n > 255) - { - *errorcodeptr = ERR38; - goto FAILED; - } - } - PUT(code, 1, (int)(ptr - cb->start_pattern + 1)); /* Next offset */ - PUT(code, 1 + LINK_SIZE, 0); /* Default length */ - code[1 + 2*LINK_SIZE] = n; /* Callout number */ - code += PRIV(OP_lengths)[OP_CALLOUT]; - } - - /* Both formats must have a closing parenthesis */ - - if (*ptr != CHAR_RIGHT_PARENTHESIS) - { - *errorcodeptr = ERR39; - goto FAILED; - } - - /* Callouts cannot be quantified. */ - - previous = NULL; - continue; - - - /* ------------------------------------------------------------ */ - case CHAR_P: /* Python-style named subpattern handling */ - if (*(++ptr) == CHAR_EQUALS_SIGN || - *ptr == CHAR_GREATER_THAN_SIGN) /* Reference or recursion */ - { - is_recurse = *ptr == CHAR_GREATER_THAN_SIGN; - terminator = CHAR_RIGHT_PARENTHESIS; - goto NAMED_REF_OR_RECURSE; - } - else if (*ptr != CHAR_LESS_THAN_SIGN) /* Test for Python-style defn */ - { - *errorcodeptr = ERR41; - goto FAILED; - } - /* Fall through to handle (?P< as (?< is handled */ - - - /* ------------------------------------------------------------ */ - case CHAR_APOSTROPHE: /* Define a name - note fall through above */ - - /* The syntax was checked and the list of names was set up in the - pre-pass, so there is nothing to be done now except to skip over the - name. */ - - terminator = (*ptr == CHAR_LESS_THAN_SIGN)? - CHAR_GREATER_THAN_SIGN : CHAR_APOSTROPHE; - while (*(++ptr) != (unsigned int)terminator); - ptr++; - goto NUMBERED_GROUP; /* Set up numbered group */ - - - /* ------------------------------------------------------------ */ - case CHAR_AMPERSAND: /* Perl recursion/subroutine syntax */ - terminator = CHAR_RIGHT_PARENTHESIS; - is_recurse = TRUE; - /* Fall through */ - - /* We come here from the Python syntax above that handles both - references (?P=name) and recursion (?P>name), as well as falling - through from the Perl recursion syntax (?&name). We also come here from - the Perl \k or \k'name' back reference syntax and the \k{name} - .NET syntax, and the Oniguruma \g<...> and \g'...' subroutine syntax. */ - - NAMED_REF_OR_RECURSE: - name = ++ptr; - if (IS_DIGIT(*ptr)) - { - *errorcodeptr = ERR44; /* Group name must start with non-digit */ - goto FAILED; - } - /* Increment ptr, set namelen, check length */ - READ_NAME(ctype_word, ERR48, *errorcodeptr); - - /* In the pre-compile phase, do a syntax check. */ - - if (lengthptr != NULL) - { - if (namelen == 0) - { - *errorcodeptr = ERR62; - goto FAILED; - } - if (*ptr != (PCRE2_UCHAR)terminator) - { - *errorcodeptr = ERR42; - goto FAILED; - } - } - - /* Scan the list of names generated in the pre-pass in order to get - a number and whether or not this name is duplicated. */ - - recno = 0; - is_dupname = FALSE; - ng = cb->named_groups; - - for (i = 0; i < cb->names_found; i++, ng++) - { - if (namelen == ng->length && - PRIV(strncmp)(name, ng->name, namelen) == 0) - { - open_capitem *oc; - is_dupname = ng->isdup; - recno = ng->number; - - /* For a recursion, that's all that is needed. We can now go to the - code that handles numerical recursion. */ - - if (is_recurse) goto HANDLE_RECURSION; - - /* For a back reference, update the back reference map and the - maximum back reference. Then for each group we must check to see if - it is recursive, that is, it is inside the group that it - references. A flag is set so that the group can be made atomic. */ - - cb->backref_map |= (recno < 32)? (1u << recno) : 1; - if ((uint32_t)recno > cb->top_backref) cb->top_backref = recno; - - for (oc = cb->open_caps; oc != NULL; oc = oc->next) - { - if (oc->number == recno) - { - oc->flag = TRUE; - break; - } - } - } - } - - /* If the name was not found we have a bad reference. */ - - if (recno == 0) - { - *errorcodeptr = ERR15; - goto FAILED; - } - - /* If a back reference name is not duplicated, we can handle it as a - numerical reference. */ - - if (!is_dupname) goto HANDLE_REFERENCE; - - /* If a back reference name is duplicated, we generate a different - opcode to a numerical back reference. In the second pass we must search - for the index and count in the final name table. */ - - count = 0; - index = 0; - - if (lengthptr == NULL) - { - slot = cb->name_table; - for (i = 0; i < cb->names_found; i++) - { - if (PRIV(strncmp)(name, slot+IMM2_SIZE, namelen) == 0 && - slot[IMM2_SIZE+namelen] == 0) - { - if (count == 0) index = i; - count++; - } - slot += cb->name_entry_size; - } - - if (count == 0) - { - *errorcodeptr = ERR15; - goto FAILED; - } - } - - if (firstcuflags == REQ_UNSET) firstcuflags = REQ_NONE; - previous = code; - *code++ = ((options & PCRE2_CASELESS) != 0)? OP_DNREFI : OP_DNREF; - PUT2INC(code, 0, index); - PUT2INC(code, 0, count); - continue; /* End of back ref handling */ - - - /* ------------------------------------------------------------ */ - case CHAR_R: /* Recursion, same as (?0) */ - recno = 0; - if (*(++ptr) != CHAR_RIGHT_PARENTHESIS) - { - *errorcodeptr = ERR29; - goto FAILED; - } - goto HANDLE_RECURSION; - - - /* ------------------------------------------------------------ */ - case CHAR_MINUS: case CHAR_PLUS: /* Recursion or subroutine */ - case CHAR_0: case CHAR_1: case CHAR_2: case CHAR_3: case CHAR_4: - case CHAR_5: case CHAR_6: case CHAR_7: case CHAR_8: case CHAR_9: - { - terminator = CHAR_RIGHT_PARENTHESIS; - - /* Come here from the \g<...> and \g'...' code (Oniguruma - compatibility). However, the syntax has been checked to ensure that - the ... are a (signed) number, so that neither ERR63 nor ERR29 will - be called on this path, nor with the jump to OTHER_CHAR_AFTER_QUERY - ever be taken. */ - - HANDLE_NUMERICAL_RECURSION: - - if ((refsign = *ptr) == CHAR_PLUS) - { - ptr++; - if (!IS_DIGIT(*ptr)) - { - *errorcodeptr = ERR63; - goto FAILED; - } - } - else if (refsign == CHAR_MINUS) - { - if (!IS_DIGIT(ptr[1])) - goto OTHER_CHAR_AFTER_QUERY; - ptr++; - } - - recno = 0; - while (IS_DIGIT(*ptr)) - { - if (recno > INT_MAX / 10 - 1) /* Integer overflow */ - { - while (IS_DIGIT(*ptr)) ptr++; - *errorcodeptr = ERR61; - goto FAILED; - } - recno = recno * 10 + *ptr++ - CHAR_0; - } - - if (*ptr != (PCRE2_UCHAR)terminator) - { - *errorcodeptr = ERR29; - goto FAILED; - } - - if (refsign == CHAR_MINUS) - { - if (recno == 0) - { - *errorcodeptr = ERR58; - goto FAILED; - } - recno = (int)(cb->bracount + 1) - recno; - if (recno <= 0) - { - *errorcodeptr = ERR15; - goto FAILED; - } - } - else if (refsign == CHAR_PLUS) - { - if (recno == 0) - { - *errorcodeptr = ERR58; - goto FAILED; - } - recno += cb->bracount; - } - - if ((uint32_t)recno > cb->final_bracount) - { - *errorcodeptr = ERR15; - goto FAILED; - } - - /* Come here from code above that handles a named recursion. - We insert the number of the called group after OP_RECURSE. At the - end of compiling the pattern is scanned and these numbers are - replaced by offsets within the pattern. It is done like this to avoid - problems with forward references and adjusting offsets when groups - are duplicated and moved (as discovered in previous implementations). - Note that a recursion does not have a set first character (relevant - if it is repeated, because it will then be wrapped with ONCE - brackets). */ - - HANDLE_RECURSION: - previous = code; - *code = OP_RECURSE; - PUT(code, 1, recno); - code += 1 + LINK_SIZE; - groupsetfirstcu = FALSE; - cb->had_recurse = TRUE; - } - - /* Can't determine a first byte now */ - - if (firstcuflags == REQ_UNSET) firstcuflags = REQ_NONE; - continue; - - - /* ------------------------------------------------------------ */ - default: /* Other characters: check option setting */ - OTHER_CHAR_AFTER_QUERY: - set = unset = 0; - optset = &set; - - while (*ptr != CHAR_RIGHT_PARENTHESIS && *ptr != CHAR_COLON) - { - switch (*ptr++) - { - case CHAR_MINUS: optset = &unset; break; - - case CHAR_J: /* Record that it changed in the external options */ - *optset |= PCRE2_DUPNAMES; - cb->external_flags |= PCRE2_JCHANGED; - break; - - case CHAR_i: *optset |= PCRE2_CASELESS; break; - case CHAR_m: *optset |= PCRE2_MULTILINE; break; - case CHAR_s: *optset |= PCRE2_DOTALL; break; - case CHAR_x: *optset |= PCRE2_EXTENDED; break; - case CHAR_U: *optset |= PCRE2_UNGREEDY; break; - - default: *errorcodeptr = ERR11; - ptr--; /* Correct the offset */ - goto FAILED; - } - } - - /* Set up the changed option bits, but don't change anything yet. */ - - newoptions = (options | set) & (~unset); - - /* If the options ended with ')' this is not the start of a nested - group with option changes, so the options change at this level. They - must also be passed back for use in subsequent branches. Reset the - greedy defaults and the case value for firstcu and reqcu. */ - - if (*ptr == CHAR_RIGHT_PARENTHESIS) - { - *optionsptr = options = newoptions; - greedy_default = ((newoptions & PCRE2_UNGREEDY) != 0); - greedy_non_default = greedy_default ^ 1; - req_caseopt = ((newoptions & PCRE2_CASELESS) != 0)? REQ_CASELESS:0; - previous = NULL; /* This item can't be repeated */ - continue; /* It is complete */ - } - - /* If the options ended with ':' we are heading into a nested group - with possible change of options. Such groups are non-capturing and are - not assertions of any kind. All we need to do is skip over the ':'; - the newoptions value is handled below. */ - - bravalue = OP_BRA; - ptr++; - } /* End of switch for character following (? */ - } /* End of (? handling */ - - /* Opening parenthesis not followed by '*' or '?'. If PCRE2_NO_AUTO_CAPTURE - is set, all unadorned brackets become non-capturing and behave like (?:...) - brackets. */ - - else if ((options & PCRE2_NO_AUTO_CAPTURE) != 0) - { - bravalue = OP_BRA; - } - - /* Else we have a capturing group. */ - - else - { - NUMBERED_GROUP: - cb->bracount += 1; - PUT2(code, 1+LINK_SIZE, cb->bracount); - skipunits = IMM2_SIZE; - } - - /* Process nested bracketed regex. First check for parentheses nested too - deeply. */ - - if ((cb->parens_depth += 1) > (int)(cb->cx->parens_nest_limit)) - { - *errorcodeptr = ERR19; - goto FAILED; - } - - /* All assertions used not to be repeatable, but this was changed for Perl - compatibility. All kinds can now be repeated except for assertions that are - conditions (Perl also forbids these to be repeated). We copy code into a - non-register variable (tempcode) in order to be able to pass its address - because some compilers complain otherwise. At the start of a conditional - group whose condition is an assertion, cb->iscondassert is set. We unset it - here so as to allow assertions later in the group to be quantified. */ - - if (bravalue >= OP_ASSERT && bravalue <= OP_ASSERTBACK_NOT && - cb->iscondassert) - { - previous = NULL; - cb->iscondassert = FALSE; - } - else - { - previous = code; - } - - *code = bravalue; - tempcode = code; - tempreqvary = cb->req_varyopt; /* Save value before bracket */ - tempbracount = cb->bracount; /* Save value before bracket */ - length_prevgroup = 0; /* Initialize for pre-compile phase */ - - if (!compile_regex( - newoptions, /* The complete new option state */ - &tempcode, /* Where to put code (updated) */ - &ptr, /* Input pointer (updated) */ - errorcodeptr, /* Where to put an error message */ - (bravalue == OP_ASSERTBACK || - bravalue == OP_ASSERTBACK_NOT), /* TRUE if back assert */ - reset_bracount, /* True if (?| group */ - skipunits, /* Skip over bracket number */ - cond_depth + - ((bravalue == OP_COND)?1:0), /* Depth of condition subpatterns */ - &subfirstcu, /* For possible first char */ - &subfirstcuflags, - &subreqcu, /* For possible last char */ - &subreqcuflags, - bcptr, /* Current branch chain */ - cb, /* Compile data block */ - (lengthptr == NULL)? NULL : /* Actual compile phase */ - &length_prevgroup /* Pre-compile phase */ - )) - goto FAILED; - - cb->parens_depth -= 1; - - /* If this was an atomic group and there are no capturing groups within it, - generate OP_ONCE_NC instead of OP_ONCE. */ - - if (bravalue == OP_ONCE && cb->bracount <= tempbracount) - *code = OP_ONCE_NC; - - if (bravalue >= OP_ASSERT && bravalue <= OP_ASSERTBACK_NOT) - cb->assert_depth -= 1; - - /* At the end of compiling, code is still pointing to the start of the - group, while tempcode has been updated to point past the end of the group. - The pattern pointer (ptr) is on the bracket. - - If this is a conditional bracket, check that there are no more than - two branches in the group, or just one if it's a DEFINE group. We do this - in the real compile phase, not in the pre-pass, where the whole group may - not be available. */ - - if (bravalue == OP_COND && lengthptr == NULL) - { - PCRE2_UCHAR *tc = code; - int condcount = 0; - - do { - condcount++; - tc += GET(tc,1); - } - while (*tc != OP_KET); - - /* A DEFINE group is never obeyed inline (the "condition" is always - false). It must have only one branch. Having checked this, change the - opcode to OP_FALSE. */ - - if (code[LINK_SIZE+1] == OP_DEFINE) - { - if (condcount > 1) - { - *errorcodeptr = ERR54; - goto FAILED; - } - code[LINK_SIZE+1] = OP_FALSE; - bravalue = OP_DEFINE; /* Just a flag to suppress char handling below */ - } - - /* A "normal" conditional group. If there is just one branch, we must not - make use of its firstcu or reqcu, because this is equivalent to an - empty second branch. */ - - else - { - if (condcount > 2) - { - *errorcodeptr = ERR27; - goto FAILED; - } - if (condcount == 1) subfirstcuflags = subreqcuflags = REQ_NONE; - } - } - - /* At the end of a group, it's an error if we hit end of pattern or - any non-closing parenthesis. This check also happens in the pre-scan, - so should not trigger here, but leave this code as an insurance. */ - - if (*ptr != CHAR_RIGHT_PARENTHESIS) - { - *errorcodeptr = ERR14; - goto FAILED; - } - - /* In the pre-compile phase, update the length by the length of the group, - less the brackets at either end. Then reduce the compiled code to just a - set of non-capturing brackets so that it doesn't use much memory if it is - duplicated by a quantifier.*/ - - if (lengthptr != NULL) - { - if (OFLOW_MAX - *lengthptr < length_prevgroup - 2 - 2*LINK_SIZE) - { - *errorcodeptr = ERR20; - goto FAILED; - } - *lengthptr += length_prevgroup - 2 - 2*LINK_SIZE; - code++; /* This already contains bravalue */ - PUTINC(code, 0, 1 + LINK_SIZE); - *code++ = OP_KET; - PUTINC(code, 0, 1 + LINK_SIZE); - break; /* No need to waste time with special character handling */ - } - - /* Otherwise update the main code pointer to the end of the group. */ - - code = tempcode; - - /* For a DEFINE group, required and first character settings are not - relevant. */ - - if (bravalue == OP_DEFINE) break; - - /* Handle updating of the required and first characters for other types of - group. Update for normal brackets of all kinds, and conditions with two - branches (see code above). If the bracket is followed by a quantifier with - zero repeat, we have to back off. Hence the definition of zeroreqcu and - zerofirstcu outside the main loop so that they can be accessed for the - back off. */ - - zeroreqcu = reqcu; - zeroreqcuflags = reqcuflags; - zerofirstcu = firstcu; - zerofirstcuflags = firstcuflags; - groupsetfirstcu = FALSE; - - if (bravalue >= OP_ONCE) - { - /* If we have not yet set a firstcu in this branch, take it from the - subpattern, remembering that it was set here so that a repeat of more - than one can replicate it as reqcu if necessary. If the subpattern has - no firstcu, set "none" for the whole branch. In both cases, a zero - repeat forces firstcu to "none". */ - - if (firstcuflags == REQ_UNSET && subfirstcuflags != REQ_UNSET) - { - if (subfirstcuflags >= 0) - { - firstcu = subfirstcu; - firstcuflags = subfirstcuflags; - groupsetfirstcu = TRUE; - } - else firstcuflags = REQ_NONE; - zerofirstcuflags = REQ_NONE; - } - - /* If firstcu was previously set, convert the subpattern's firstcu - into reqcu if there wasn't one, using the vary flag that was in - existence beforehand. */ - - else if (subfirstcuflags >= 0 && subreqcuflags < 0) - { - subreqcu = subfirstcu; - subreqcuflags = subfirstcuflags | tempreqvary; - } - - /* If the subpattern set a required byte (or set a first byte that isn't - really the first byte - see above), set it. */ - - if (subreqcuflags >= 0) - { - reqcu = subreqcu; - reqcuflags = subreqcuflags; - } - } - - /* For a forward assertion, we take the reqcu, if set. This can be - helpful if the pattern that follows the assertion doesn't set a different - char. For example, it's useful for /(?=abcde).+/. We can't set firstcu - for an assertion, however because it leads to incorrect effect for patterns - such as /(?=a)a.+/ when the "real" "a" would then become a reqcu instead - of a firstcu. This is overcome by a scan at the end if there's no - firstcu, looking for an asserted first char. */ - - else if (bravalue == OP_ASSERT && subreqcuflags >= 0) - { - reqcu = subreqcu; - reqcuflags = subreqcuflags; - } - break; /* End of processing '(' */ - - - /* ===================================================================*/ - /* Handle metasequences introduced by \. For ones like \d, the ESC_ values - are arranged to be the negation of the corresponding OP_values in the - default case when PCRE2_UCP is not set. For the back references, the values - are negative the reference number. Only back references and those types - that consume a character may be repeated. We can test for values between - ESC_b and ESC_Z for the latter; this may have to change if any new ones are - ever created. - - Note: \Q and \E are handled at the start of the character-processing loop, - not here. */ - - case CHAR_BACKSLASH: - tempptr = ptr; - escape = PRIV(check_escape)(&ptr, cb->end_pattern, &ec, errorcodeptr, - options, FALSE, cb); - if (*errorcodeptr != 0) goto FAILED; - - if (escape == 0) /* The escape coded a single character */ - c = ec; - else - { - /* For metasequences that actually match a character, we disable the - setting of a first character if it hasn't already been set. */ - - if (firstcuflags == REQ_UNSET && escape > ESC_b && escape < ESC_Z) - firstcuflags = REQ_NONE; - - /* Set values to reset to if this is followed by a zero repeat. */ - - zerofirstcu = firstcu; - zerofirstcuflags = firstcuflags; - zeroreqcu = reqcu; - zeroreqcuflags = reqcuflags; - - /* \g or \g'name' is a subroutine call by name and \g or \g'n' - is a subroutine call by number (Oniguruma syntax). In fact, the value - ESC_g is returned only for these cases. So we don't need to check for < - or ' if the value is ESC_g. For the Perl syntax \g{n} the value is - -n, and for the Perl syntax \g{name} the result is ESC_k (as - that is a synonym for a named back reference). */ - - if (escape == ESC_g) - { - PCRE2_SPTR p; - uint32_t cf; - - terminator = (*(++ptr) == CHAR_LESS_THAN_SIGN)? - CHAR_GREATER_THAN_SIGN : CHAR_APOSTROPHE; - - /* These two statements stop the compiler for warning about possibly - unset variables caused by the jump to HANDLE_NUMERICAL_RECURSION. In - fact, because we do the check for a number below, the paths that - would actually be in error are never taken. */ - - skipunits = 0; - reset_bracount = FALSE; - - /* If it's not a signed or unsigned number, treat it as a name. */ - - cf = ptr[1]; - if (cf != CHAR_PLUS && cf != CHAR_MINUS && !IS_DIGIT(cf)) - { - is_recurse = TRUE; - goto NAMED_REF_OR_RECURSE; - } - - /* Signed or unsigned number (cf = ptr[1]) is known to be plus or minus - or a digit. */ - - p = ptr + 2; - while (IS_DIGIT(*p)) p++; - if (*p != (PCRE2_UCHAR)terminator) - { - *errorcodeptr = ERR57; - goto FAILED; - } - ptr++; - goto HANDLE_NUMERICAL_RECURSION; - } - - /* \k or \k'name' is a back reference by name (Perl syntax). - We also support \k{name} (.NET syntax). */ - - if (escape == ESC_k) - { - if ((ptr[1] != CHAR_LESS_THAN_SIGN && - ptr[1] != CHAR_APOSTROPHE && ptr[1] != CHAR_LEFT_CURLY_BRACKET)) - { - *errorcodeptr = ERR69; - goto FAILED; - } - is_recurse = FALSE; - terminator = (*(++ptr) == CHAR_LESS_THAN_SIGN)? - CHAR_GREATER_THAN_SIGN : (*ptr == CHAR_APOSTROPHE)? - CHAR_APOSTROPHE : CHAR_RIGHT_CURLY_BRACKET; - goto NAMED_REF_OR_RECURSE; - } - - /* Back references are handled specially; must disable firstcu if - not set to cope with cases like (?=(\w+))\1: which would otherwise set - ':' later. */ - - if (escape < 0) - { - open_capitem *oc; - recno = -escape; - - /* Come here from named backref handling when the reference is to a - single group (i.e. not to a duplicated name). */ - - HANDLE_REFERENCE: - if (recno > (int)cb->final_bracount) - { - *errorcodeptr = ERR15; - goto FAILED; - } - if (firstcuflags == REQ_UNSET) firstcuflags = REQ_NONE; - previous = code; - *code++ = ((options & PCRE2_CASELESS) != 0)? OP_REFI : OP_REF; - PUT2INC(code, 0, recno); - cb->backref_map |= (recno < 32)? (1u << recno) : 1; - if ((uint32_t)recno > cb->top_backref) cb->top_backref = recno; - - /* Check to see if this back reference is recursive, that it, it - is inside the group that it references. A flag is set so that the - group can be made atomic. */ - - for (oc = cb->open_caps; oc != NULL; oc = oc->next) - { - if (oc->number == recno) - { - oc->flag = TRUE; - break; - } - } - } - - /* So are Unicode property matches, if supported. */ - -#ifdef SUPPORT_UNICODE - else if (escape == ESC_P || escape == ESC_p) - { - BOOL negated; - unsigned int ptype = 0, pdata = 0; - if (!get_ucp(&ptr, &negated, &ptype, &pdata, errorcodeptr, cb)) - goto FAILED; - previous = code; - *code++ = ((escape == ESC_p) != negated)? OP_PROP : OP_NOTPROP; - *code++ = ptype; - *code++ = pdata; - } -#else - - /* If Unicode properties are not supported, \X, \P, and \p are not - allowed. */ - - else if (escape == ESC_X || escape == ESC_P || escape == ESC_p) - { - *errorcodeptr = ERR45; - goto FAILED; - } -#endif - - /* The use of \C can be locked out. */ - -#ifdef NEVER_BACKSLASH_C - else if (escape == ESC_C) - { - *errorcodeptr = ERR85; - goto FAILED; - } -#else - else if (escape == ESC_C && (options & PCRE2_NEVER_BACKSLASH_C) != 0) - { - *errorcodeptr = ERR83; - goto FAILED; - } -#endif - - /* For the rest (including \X when Unicode properties are supported), we - can obtain the OP value by negating the escape value in the default - situation when PCRE2_UCP is not set. When it *is* set, we substitute - Unicode property tests. Note that \b and \B do a one-character - lookbehind, and \A also behaves as if it does. */ - - else - { - if (escape == ESC_C) cb->external_flags |= PCRE2_HASBKC; /* Record */ - if ((escape == ESC_b || escape == ESC_B || escape == ESC_A) && - cb->max_lookbehind == 0) - cb->max_lookbehind = 1; -#ifdef SUPPORT_UNICODE - if (escape >= ESC_DU && escape <= ESC_wu) - { - cb->nestptr[1] = cb->nestptr[0]; /* Back up if at 2nd level */ - cb->nestptr[0] = ptr + 1; /* Where to resume */ - ptr = substitutes[escape - ESC_DU] - 1; /* Just before substitute */ - } - else -#endif - /* In non-UTF mode, and for both 32-bit modes, we turn \C into - OP_ALLANY instead of OP_ANYBYTE so that it works in DFA mode and in - lookbehinds. */ - - { - previous = (escape > ESC_b && escape < ESC_Z)? code : NULL; -#if PCRE2_CODE_UNIT_WIDTH == 32 - *code++ = (escape == ESC_C)? OP_ALLANY : escape; -#else - *code++ = (!utf && escape == ESC_C)? OP_ALLANY : escape; -#endif - } - } - continue; - } - - /* We have a data character whose value is in c. In UTF-8 mode it may have - a value > 127. We set its representation in the length/buffer, and then - handle it as a data character. */ - - mclength = PUTCHAR(c, mcbuffer); - goto ONE_CHAR; - - - /* ===================================================================*/ - /* Handle a literal character. It is guaranteed not to be whitespace or # - when the extended flag is set. If we are in a UTF mode, it may be a - multi-unit literal character. */ - - default: - NORMAL_CHAR: - mclength = 1; - mcbuffer[0] = c; - -#ifdef SUPPORT_UNICODE - if (utf && HAS_EXTRALEN(c)) - ACROSSCHAR(TRUE, ptr[1], mcbuffer[mclength++] = *(++ptr)); -#endif - - /* At this point we have the character's bytes in mcbuffer, and the length - in mclength. When not in UTF mode, the length is always 1. */ - - ONE_CHAR: - previous = code; - - /* For caseless UTF mode, check whether this character has more than one - other case. If so, generate a special OP_PROP item instead of OP_CHARI. */ - -#ifdef SUPPORT_UNICODE - if (utf && (options & PCRE2_CASELESS) != 0) - { - GETCHAR(c, mcbuffer); - if ((c = UCD_CASESET(c)) != 0) - { - *code++ = OP_PROP; - *code++ = PT_CLIST; - *code++ = c; - if (firstcuflags == REQ_UNSET) - firstcuflags = zerofirstcuflags = REQ_NONE; - break; - } - } -#endif - - /* Caseful matches, or not one of the multicase characters. */ - - *code++ = ((options & PCRE2_CASELESS) != 0)? OP_CHARI : OP_CHAR; - for (c = 0; c < mclength; c++) *code++ = mcbuffer[c]; - - /* Remember if \r or \n were seen */ - - if (mcbuffer[0] == CHAR_CR || mcbuffer[0] == CHAR_NL) - cb->external_flags |= PCRE2_HASCRORLF; - - /* Set the first and required bytes appropriately. If no previous first - byte, set it from this character, but revert to none on a zero repeat. - Otherwise, leave the firstcu value alone, and don't change it on a zero - repeat. */ - - if (firstcuflags == REQ_UNSET) - { - zerofirstcuflags = REQ_NONE; - zeroreqcu = reqcu; - zeroreqcuflags = reqcuflags; - - /* If the character is more than one byte long, we can set firstcu - only if it is not to be matched caselessly. */ - - if (mclength == 1 || req_caseopt == 0) - { - firstcu = mcbuffer[0] | req_caseopt; - firstcu = mcbuffer[0]; - firstcuflags = req_caseopt; - - if (mclength != 1) - { - reqcu = code[-1]; - reqcuflags = cb->req_varyopt; - } - } - else firstcuflags = reqcuflags = REQ_NONE; - } - - /* firstcu was previously set; we can set reqcu only if the length is - 1 or the matching is caseful. */ - - else - { - zerofirstcu = firstcu; - zerofirstcuflags = firstcuflags; - zeroreqcu = reqcu; - zeroreqcuflags = reqcuflags; - if (mclength == 1 || req_caseopt == 0) - { - reqcu = code[-1]; - reqcuflags = req_caseopt | cb->req_varyopt; - } - } - - break; /* End of literal character handling */ - } - } /* end of big loop */ - -/* Control never reaches here by falling through, only by a goto for all the -error states. Pass back the position in the pattern so that it can be displayed -to the user for diagnosing the error. */ - -FAILED: -*ptrptr = ptr; -return FALSE; -} - - - -/************************************************* -* Compile regex: a sequence of alternatives * -*************************************************/ - -/* On entry, ptr is pointing past the bracket character, but on return it -points to the closing bracket, or vertical bar, or end of string. The code -variable is pointing at the byte into which the BRA operator has been stored. -This function is used during the pre-compile phase when we are trying to find -out the amount of memory needed, as well as during the real compile phase. The -value of lengthptr distinguishes the two phases. - -Arguments: - options option bits, including any changes for this subpattern - codeptr -> the address of the current code pointer - ptrptr -> the address of the current pattern pointer - errorcodeptr -> pointer to error code variable - lookbehind TRUE if this is a lookbehind assertion - reset_bracount TRUE to reset the count for each branch - skipunits skip this many code units at start (for brackets and OP_COND) - cond_depth depth of nesting for conditional subpatterns - firstcuptr place to put the first required code unit - firstcuflagsptr place to put the first code unit flags, or a negative number - reqcuptr place to put the last required code unit - reqcuflagsptr place to put the last required code unit flags, or a negative number - bcptr pointer to the chain of currently open branches - cb points to the data block with tables pointers etc. - lengthptr NULL during the real compile phase - points to length accumulator during pre-compile phase - -Returns: TRUE on success -*/ - -static BOOL -compile_regex(uint32_t options, PCRE2_UCHAR **codeptr, PCRE2_SPTR *ptrptr, - int *errorcodeptr, BOOL lookbehind, BOOL reset_bracount, uint32_t skipunits, - int cond_depth, uint32_t *firstcuptr, int32_t *firstcuflagsptr, - uint32_t *reqcuptr, int32_t *reqcuflagsptr, branch_chain *bcptr, - compile_block *cb, size_t *lengthptr) -{ -PCRE2_SPTR ptr = *ptrptr; -PCRE2_UCHAR *code = *codeptr; -PCRE2_UCHAR *last_branch = code; -PCRE2_UCHAR *start_bracket = code; -PCRE2_UCHAR *reverse_count = NULL; -open_capitem capitem; -int capnumber = 0; -uint32_t firstcu, reqcu; -int32_t firstcuflags, reqcuflags; -uint32_t branchfirstcu, branchreqcu; -int32_t branchfirstcuflags, branchreqcuflags; -size_t length; -unsigned int orig_bracount; -unsigned int max_bracount; -branch_chain bc; - -/* If set, call the external function that checks for stack availability. */ - -if (cb->cx->stack_guard != NULL && - cb->cx->stack_guard(cb->parens_depth, cb->cx->stack_guard_data)) - { - *errorcodeptr= ERR33; - return FALSE; - } - -/* Miscellaneous initialization */ - -bc.outer = bcptr; -bc.current_branch = code; - -firstcu = reqcu = 0; -firstcuflags = reqcuflags = REQ_UNSET; - -/* Accumulate the length for use in the pre-compile phase. Start with the -length of the BRA and KET and any extra code units that are required at the -beginning. We accumulate in a local variable to save frequent testing of -lengthptr for NULL. We cannot do this by looking at the value of 'code' at the -start and end of each alternative, because compiled items are discarded during -the pre-compile phase so that the work space is not exceeded. */ - -length = 2 + 2*LINK_SIZE + skipunits; - -/* WARNING: If the above line is changed for any reason, you must also change -the code that abstracts option settings at the start of the pattern and makes -them global. It tests the value of length for (2 + 2*LINK_SIZE) in the -pre-compile phase to find out whether or not anything has yet been compiled. - -If this is a capturing subpattern, add to the chain of open capturing items -so that we can detect them if (*ACCEPT) is encountered. This is also used to -detect groups that contain recursive back references to themselves. Note that -only OP_CBRA need be tested here; changing this opcode to one of its variants, -e.g. OP_SCBRAPOS, happens later, after the group has been compiled. */ - -if (*code == OP_CBRA) - { - capnumber = GET2(code, 1 + LINK_SIZE); - capitem.number = capnumber; - capitem.next = cb->open_caps; - capitem.flag = FALSE; - cb->open_caps = &capitem; - } - -/* Offset is set zero to mark that this bracket is still open */ - -PUT(code, 1, 0); -code += 1 + LINK_SIZE + skipunits; - -/* Loop for each alternative branch */ - -orig_bracount = max_bracount = cb->bracount; - -for (;;) - { - /* For a (?| group, reset the capturing bracket count so that each branch - uses the same numbers. */ - - if (reset_bracount) cb->bracount = orig_bracount; - - /* Set up dummy OP_REVERSE if lookbehind assertion */ - - if (lookbehind) - { - *code++ = OP_REVERSE; - reverse_count = code; - PUTINC(code, 0, 0); - length += 1 + LINK_SIZE; - } - - /* Now compile the branch; in the pre-compile phase its length gets added - into the length. */ - - if (!compile_branch(&options, &code, &ptr, errorcodeptr, &branchfirstcu, - &branchfirstcuflags, &branchreqcu, &branchreqcuflags, &bc, - cond_depth, cb, (lengthptr == NULL)? NULL : &length)) - { - *ptrptr = ptr; - return FALSE; - } - - /* Keep the highest bracket count in case (?| was used and some branch - has fewer than the rest. */ - - if (cb->bracount > max_bracount) max_bracount = cb->bracount; - - /* In the real compile phase, there is some post-processing to be done. */ - - if (lengthptr == NULL) - { - /* If this is the first branch, the firstcu and reqcu values for the - branch become the values for the regex. */ - - if (*last_branch != OP_ALT) - { - firstcu = branchfirstcu; - firstcuflags = branchfirstcuflags; - reqcu = branchreqcu; - reqcuflags = branchreqcuflags; - } - - /* If this is not the first branch, the first char and reqcu have to - match the values from all the previous branches, except that if the - previous value for reqcu didn't have REQ_VARY set, it can still match, - and we set REQ_VARY for the regex. */ - - else - { - /* If we previously had a firstcu, but it doesn't match the new branch, - we have to abandon the firstcu for the regex, but if there was - previously no reqcu, it takes on the value of the old firstcu. */ - - if (firstcuflags != branchfirstcuflags || firstcu != branchfirstcu) - { - if (firstcuflags >= 0) - { - if (reqcuflags < 0) - { - reqcu = firstcu; - reqcuflags = firstcuflags; - } - } - firstcuflags = REQ_NONE; - } - - /* If we (now or from before) have no firstcu, a firstcu from the - branch becomes a reqcu if there isn't a branch reqcu. */ - - if (firstcuflags < 0 && branchfirstcuflags >= 0 && - branchreqcuflags < 0) - { - branchreqcu = branchfirstcu; - branchreqcuflags = branchfirstcuflags; - } - - /* Now ensure that the reqcus match */ - - if (((reqcuflags & ~REQ_VARY) != (branchreqcuflags & ~REQ_VARY)) || - reqcu != branchreqcu) - reqcuflags = REQ_NONE; - else - { - reqcu = branchreqcu; - reqcuflags |= branchreqcuflags; /* To "or" REQ_VARY */ - } - } - - /* If lookbehind, check that this branch matches a fixed-length string, and - put the length into the OP_REVERSE item. Temporarily mark the end of the - branch with OP_END. If the branch contains OP_RECURSE, the result is - FFL_LATER (a negative value) because there may be forward references that - we can't check here. Set a flag to cause another lookbehind check at the - end. Why not do it all at the end? Because common errors can be picked up - here and the offset of the problem can be shown. */ - - if (lookbehind) - { - int fixed_length; - int count = 0; - *code = OP_END; - fixed_length = find_fixedlength(last_branch, (options & PCRE2_UTF) != 0, - FALSE, cb, NULL, &count); - if (fixed_length == FFL_LATER) - { - cb->check_lookbehind = TRUE; - } - else if (fixed_length < 0) - { - *errorcodeptr = fixed_length_errors[-fixed_length]; - *ptrptr = ptr; - return FALSE; - } - else - { - if (fixed_length > cb->max_lookbehind) - cb->max_lookbehind = fixed_length; - PUT(reverse_count, 0, fixed_length); - } - } - } - - /* Reached end of expression, either ')' or end of pattern. In the real - compile phase, go back through the alternative branches and reverse the chain - of offsets, with the field in the BRA item now becoming an offset to the - first alternative. If there are no alternatives, it points to the end of the - group. The length in the terminating ket is always the length of the whole - bracketed item. Return leaving the pointer at the terminating char. */ - - if (*ptr != CHAR_VERTICAL_LINE) - { - if (lengthptr == NULL) - { - size_t branch_length = code - last_branch; - do - { - size_t prev_length = GET(last_branch, 1); - PUT(last_branch, 1, branch_length); - branch_length = prev_length; - last_branch -= branch_length; - } - while (branch_length > 0); - } - - /* Fill in the ket */ - - *code = OP_KET; - PUT(code, 1, (int)(code - start_bracket)); - code += 1 + LINK_SIZE; - - /* If it was a capturing subpattern, check to see if it contained any - recursive back references. If so, we must wrap it in atomic brackets. In - any event, remove the block from the chain. */ - - if (capnumber > 0) - { - if (cb->open_caps->flag) - { - memmove(start_bracket + 1 + LINK_SIZE, start_bracket, - CU2BYTES(code - start_bracket)); - *start_bracket = OP_ONCE; - code += 1 + LINK_SIZE; - PUT(start_bracket, 1, (int)(code - start_bracket)); - *code = OP_KET; - PUT(code, 1, (int)(code - start_bracket)); - code += 1 + LINK_SIZE; - length += 2 + 2*LINK_SIZE; - } - cb->open_caps = cb->open_caps->next; - } - - /* Retain the highest bracket number, in case resetting was used. */ - - cb->bracount = max_bracount; - - /* Set values to pass back */ - - *codeptr = code; - *ptrptr = ptr; - *firstcuptr = firstcu; - *firstcuflagsptr = firstcuflags; - *reqcuptr = reqcu; - *reqcuflagsptr = reqcuflags; - if (lengthptr != NULL) - { - if (OFLOW_MAX - *lengthptr < length) - { - *errorcodeptr = ERR20; - return FALSE; - } - *lengthptr += length; - } - return TRUE; - } - - /* Another branch follows. In the pre-compile phase, we can move the code - pointer back to where it was for the start of the first branch. (That is, - pretend that each branch is the only one.) - - In the real compile phase, insert an ALT node. Its length field points back - to the previous branch while the bracket remains open. At the end the chain - is reversed. It's done like this so that the start of the bracket has a - zero offset until it is closed, making it possible to detect recursion. */ - - if (lengthptr != NULL) - { - code = *codeptr + 1 + LINK_SIZE + skipunits; - length += 1 + LINK_SIZE; - } - else - { - *code = OP_ALT; - PUT(code, 1, (int)(code - last_branch)); - bc.current_branch = last_branch = code; - code += 1 + LINK_SIZE; - } - - /* Advance past the vertical bar */ - - ptr++; - } -/* Control never reaches here */ -} - - - -/************************************************* -* Check for anchored pattern * -*************************************************/ - -/* Try to find out if this is an anchored regular expression. Consider each -alternative branch. If they all start with OP_SOD or OP_CIRC, or with a bracket -all of whose alternatives start with OP_SOD or OP_CIRC (recurse ad lib), then -it's anchored. However, if this is a multiline pattern, then only OP_SOD will -be found, because ^ generates OP_CIRCM in that mode. - -We can also consider a regex to be anchored if OP_SOM starts all its branches. -This is the code for \G, which means "match at start of match position, taking -into account the match offset". - -A branch is also implicitly anchored if it starts with .* and DOTALL is set, -because that will try the rest of the pattern at all possible matching points, -so there is no point trying again.... er .... - -.... except when the .* appears inside capturing parentheses, and there is a -subsequent back reference to those parentheses. We haven't enough information -to catch that case precisely. - -At first, the best we could do was to detect when .* was in capturing brackets -and the highest back reference was greater than or equal to that level. -However, by keeping a bitmap of the first 31 back references, we can catch some -of the more common cases more precisely. - -... A second exception is when the .* appears inside an atomic group, because -this prevents the number of characters it matches from being adjusted. - -Arguments: - code points to start of the compiled pattern - bracket_map a bitmap of which brackets we are inside while testing; this - handles up to substring 31; after that we just have to take - the less precise approach - cb points to the compile data block - atomcount atomic group level - -Returns: TRUE or FALSE -*/ - -static BOOL -is_anchored(register PCRE2_SPTR code, unsigned int bracket_map, - compile_block *cb, int atomcount) -{ -do { - PCRE2_SPTR scode = first_significant_code( - code + PRIV(OP_lengths)[*code], FALSE); - register int op = *scode; - - /* Non-capturing brackets */ - - if (op == OP_BRA || op == OP_BRAPOS || - op == OP_SBRA || op == OP_SBRAPOS) - { - if (!is_anchored(scode, bracket_map, cb, atomcount)) return FALSE; - } - - /* Capturing brackets */ - - else if (op == OP_CBRA || op == OP_CBRAPOS || - op == OP_SCBRA || op == OP_SCBRAPOS) - { - int n = GET2(scode, 1+LINK_SIZE); - int new_map = bracket_map | ((n < 32)? (1u << n) : 1); - if (!is_anchored(scode, new_map, cb, atomcount)) return FALSE; - } - - /* Positive forward assertions and conditions */ - - else if (op == OP_ASSERT || op == OP_COND) - { - if (!is_anchored(scode, bracket_map, cb, atomcount)) return FALSE; - } - - /* Atomic groups */ - - else if (op == OP_ONCE || op == OP_ONCE_NC) - { - if (!is_anchored(scode, bracket_map, cb, atomcount + 1)) - return FALSE; - } - - /* .* is not anchored unless DOTALL is set (which generates OP_ALLANY) and - it isn't in brackets that are or may be referenced or inside an atomic - group. There is also an option that disables auto-anchoring. */ - - else if ((op == OP_TYPESTAR || op == OP_TYPEMINSTAR || - op == OP_TYPEPOSSTAR)) - { - if (scode[1] != OP_ALLANY || (bracket_map & cb->backref_map) != 0 || - atomcount > 0 || cb->had_pruneorskip || - (cb->external_options & PCRE2_NO_DOTSTAR_ANCHOR) != 0) - return FALSE; - } - - /* Check for explicit anchoring */ - - else if (op != OP_SOD && op != OP_SOM && op != OP_CIRC) return FALSE; - - code += GET(code, 1); - } -while (*code == OP_ALT); /* Loop for each alternative */ -return TRUE; -} - - - -/************************************************* -* Check for starting with ^ or .* * -*************************************************/ - -/* This is called to find out if every branch starts with ^ or .* so that -"first char" processing can be done to speed things up in multiline -matching and for non-DOTALL patterns that start with .* (which must start at -the beginning or after \n). As in the case of is_anchored() (see above), we -have to take account of back references to capturing brackets that contain .* -because in that case we can't make the assumption. Also, the appearance of .* -inside atomic brackets or in a pattern that contains *PRUNE or *SKIP does not -count, because once again the assumption no longer holds. - -Arguments: - code points to start of the compiled pattern or a group - bracket_map a bitmap of which brackets we are inside while testing; this - handles up to substring 31; after that we just have to take - the less precise approach - cb points to the compile data - atomcount atomic group level - -Returns: TRUE or FALSE -*/ - -static BOOL -is_startline(PCRE2_SPTR code, unsigned int bracket_map, compile_block *cb, - int atomcount) -{ -do { - PCRE2_SPTR scode = first_significant_code( - code + PRIV(OP_lengths)[*code], FALSE); - register int op = *scode; - - /* If we are at the start of a conditional assertion group, *both* the - conditional assertion *and* what follows the condition must satisfy the test - for start of line. Other kinds of condition fail. Note that there may be an - auto-callout at the start of a condition. */ - - if (op == OP_COND) - { - scode += 1 + LINK_SIZE; - - if (*scode == OP_CALLOUT) scode += PRIV(OP_lengths)[OP_CALLOUT]; - else if (*scode == OP_CALLOUT_STR) scode += GET(scode, 1 + 2*LINK_SIZE); - - switch (*scode) - { - case OP_CREF: - case OP_DNCREF: - case OP_RREF: - case OP_DNRREF: - case OP_FAIL: - case OP_FALSE: - case OP_TRUE: - return FALSE; - - default: /* Assertion */ - if (!is_startline(scode, bracket_map, cb, atomcount)) return FALSE; - do scode += GET(scode, 1); while (*scode == OP_ALT); - scode += 1 + LINK_SIZE; - break; - } - scode = first_significant_code(scode, FALSE); - op = *scode; - } - - /* Non-capturing brackets */ - - if (op == OP_BRA || op == OP_BRAPOS || - op == OP_SBRA || op == OP_SBRAPOS) - { - if (!is_startline(scode, bracket_map, cb, atomcount)) return FALSE; - } - - /* Capturing brackets */ - - else if (op == OP_CBRA || op == OP_CBRAPOS || - op == OP_SCBRA || op == OP_SCBRAPOS) - { - int n = GET2(scode, 1+LINK_SIZE); - int new_map = bracket_map | ((n < 32)? (1u << n) : 1); - if (!is_startline(scode, new_map, cb, atomcount)) return FALSE; - } - - /* Positive forward assertions */ - - else if (op == OP_ASSERT) - { - if (!is_startline(scode, bracket_map, cb, atomcount)) return FALSE; - } - - /* Atomic brackets */ - - else if (op == OP_ONCE || op == OP_ONCE_NC) - { - if (!is_startline(scode, bracket_map, cb, atomcount + 1)) return FALSE; - } - - /* .* means "start at start or after \n" if it isn't in atomic brackets or - brackets that may be referenced, as long as the pattern does not contain - *PRUNE or *SKIP, because these break the feature. Consider, for example, - /.*?a(*PRUNE)b/ with the subject "aab", which matches "ab", i.e. not at the - start of a line. There is also an option that disables this optimization. */ - - else if (op == OP_TYPESTAR || op == OP_TYPEMINSTAR || op == OP_TYPEPOSSTAR) - { - if (scode[1] != OP_ANY || (bracket_map & cb->backref_map) != 0 || - atomcount > 0 || cb->had_pruneorskip || - (cb->external_options & PCRE2_NO_DOTSTAR_ANCHOR) != 0) - return FALSE; - } - - /* Check for explicit circumflex; anything else gives a FALSE result. Note - in particular that this includes atomic brackets OP_ONCE and OP_ONCE_NC - because the number of characters matched by .* cannot be adjusted inside - them. */ - - else if (op != OP_CIRC && op != OP_CIRCM) return FALSE; - - /* Move on to the next alternative */ - - code += GET(code, 1); - } -while (*code == OP_ALT); /* Loop for each alternative */ -return TRUE; -} - - - -/************************************************* -* Check for asserted fixed first code unit * -*************************************************/ - -/* During compilation, the "first code unit" settings from forward assertions -are discarded, because they can cause conflicts with actual literals that -follow. However, if we end up without a first code unit setting for an -unanchored pattern, it is worth scanning the regex to see if there is an -initial asserted first code unit. If all branches start with the same asserted -code unit, or with a non-conditional bracket all of whose alternatives start -with the same asserted code unit (recurse ad lib), then we return that code -unit, with the flags set to zero or REQ_CASELESS; otherwise return zero with -REQ_NONE in the flags. - -Arguments: - code points to start of compiled pattern - flags points to the first code unit flags - inassert TRUE if in an assertion - -Returns: the fixed first code unit, or 0 with REQ_NONE in flags -*/ - -static uint32_t -find_firstassertedcu(PCRE2_SPTR code, int32_t *flags, BOOL inassert) -{ -register uint32_t c = 0; -int cflags = REQ_NONE; - -*flags = REQ_NONE; -do { - uint32_t d; - int dflags; - int xl = (*code == OP_CBRA || *code == OP_SCBRA || - *code == OP_CBRAPOS || *code == OP_SCBRAPOS)? IMM2_SIZE:0; - PCRE2_SPTR scode = first_significant_code(code + 1+LINK_SIZE + xl, TRUE); - register PCRE2_UCHAR op = *scode; - - switch(op) - { - default: - return 0; - - case OP_BRA: - case OP_BRAPOS: - case OP_CBRA: - case OP_SCBRA: - case OP_CBRAPOS: - case OP_SCBRAPOS: - case OP_ASSERT: - case OP_ONCE: - case OP_ONCE_NC: - d = find_firstassertedcu(scode, &dflags, op == OP_ASSERT); - if (dflags < 0) - return 0; - if (cflags < 0) { c = d; cflags = dflags; } - else if (c != d || cflags != dflags) return 0; - break; - - case OP_EXACT: - scode += IMM2_SIZE; - /* Fall through */ - - case OP_CHAR: - case OP_PLUS: - case OP_MINPLUS: - case OP_POSPLUS: - if (!inassert) return 0; - if (cflags < 0) { c = scode[1]; cflags = 0; } - else if (c != scode[1]) return 0; - break; - - case OP_EXACTI: - scode += IMM2_SIZE; - /* Fall through */ - - case OP_CHARI: - case OP_PLUSI: - case OP_MINPLUSI: - case OP_POSPLUSI: - if (!inassert) return 0; - if (cflags < 0) { c = scode[1]; cflags = REQ_CASELESS; } - else if (c != scode[1]) return 0; - break; - } - - code += GET(code, 1); - } -while (*code == OP_ALT); - -*flags = cflags; -return c; -} - - - -/************************************************* -* Add an entry to the name/number table * -*************************************************/ - -/* This function is called between compiling passes to add an entry to the -name/number table, maintaining alphabetical order. Checking for permitted -and forbidden duplicates has already been done. - -Arguments: - cb the compile data block - name the name to add - length the length of the name - groupno the group number - -Returns: nothing -*/ - -static void -add_name_to_table(compile_block *cb, PCRE2_SPTR name, int length, - unsigned int groupno) -{ -int i; -PCRE2_UCHAR *slot = cb->name_table; - -for (i = 0; i < cb->names_found; i++) - { - int crc = memcmp(name, slot+IMM2_SIZE, CU2BYTES(length)); - if (crc == 0 && slot[IMM2_SIZE+length] != 0) - crc = -1; /* Current name is a substring */ - - /* Make space in the table and break the loop for an earlier name. For a - duplicate or later name, carry on. We do this for duplicates so that in the - simple case (when ?(| is not used) they are in order of their numbers. In all - cases they are in the order in which they appear in the pattern. */ - - if (crc < 0) - { - memmove(slot + cb->name_entry_size, slot, - CU2BYTES((cb->names_found - i) * cb->name_entry_size)); - break; - } - - /* Continue the loop for a later or duplicate name */ - - slot += cb->name_entry_size; - } - -PUT2(slot, 0, groupno); -memcpy(slot + IMM2_SIZE, name, CU2BYTES(length)); -cb->names_found++; - -/* Add a terminating zero and fill the rest of the slot with zeroes so that -the memory is all initialized. Otherwise valgrind moans about uninitialized -memory when saving serialized compiled patterns. */ - -memset(slot + IMM2_SIZE + length, 0, - CU2BYTES(cb->name_entry_size - length - IMM2_SIZE)); -} - - - -/************************************************* -* External function to compile a pattern * -*************************************************/ - -/* This function reads a regular expression in the form of a string and returns -a pointer to a block of store holding a compiled version of the expression. - -Arguments: - pattern the regular expression - patlen the length of the pattern, or PCRE2_ZERO_TERMINATED - options option bits - errorptr pointer to errorcode - erroroffset pointer to error offset - ccontext points to a compile context or is NULL - -Returns: pointer to compiled data block, or NULL on error, - with errorcode and erroroffset set -*/ - -PCRE2_EXP_DEFN pcre2_code * PCRE2_CALL_CONVENTION -pcre2_compile(PCRE2_SPTR pattern, PCRE2_SIZE patlen, uint32_t options, - int *errorptr, PCRE2_SIZE *erroroffset, pcre2_compile_context *ccontext) -{ -BOOL utf; /* Set TRUE for UTF mode */ -pcre2_real_code *re = NULL; /* What we will return */ -compile_block cb; /* "Static" compile-time data */ -const uint8_t *tables; /* Char tables base pointer */ - -PCRE2_UCHAR *code; /* Current pointer in compiled code */ -PCRE2_SPTR codestart; /* Start of compiled code */ -PCRE2_SPTR ptr; /* Current pointer in pattern */ - -size_t length = 1; /* Allow or final END opcode */ -size_t usedlength; /* Actual length used */ -size_t re_blocksize; /* Size of memory block */ - -int32_t firstcuflags, reqcuflags; /* Type of first/req code unit */ -uint32_t firstcu, reqcu; /* Value of first/req code unit */ -uint32_t setflags = 0; /* NL and BSR set flags */ - -uint32_t skipatstart; /* When checking (*UTF) etc */ -uint32_t limit_match = UINT32_MAX; /* Unset match limits */ -uint32_t limit_recursion = UINT32_MAX; - -int newline = 0; /* Unset; can be set by the pattern */ -int bsr = 0; /* Unset; can be set by the pattern */ -int errorcode = 0; /* Initialize to avoid compiler warn */ - -/* Comments at the head of this file explain about these variables. */ - -PCRE2_UCHAR *copied_pattern = NULL; -PCRE2_UCHAR stack_copied_pattern[COPIED_PATTERN_SIZE]; -named_group named_groups[NAMED_GROUP_LIST_SIZE]; - -/* The workspace is used in different ways in the different compiling phases. -It needs to be 16-bit aligned for the preliminary group scan, and 32-bit -aligned for the group information cache. */ - -uint32_t c32workspace[C32_WORK_SIZE]; -PCRE2_UCHAR *cworkspace = (PCRE2_UCHAR *)c32workspace; - - -/* -------------- Check arguments and set up the pattern ----------------- */ - -/* There must be error code and offset pointers. */ - -if (errorptr == NULL || erroroffset == NULL) return NULL; -*errorptr = ERR0; -*erroroffset = 0; - -/* There must be a pattern! */ - -if (pattern == NULL) - { - *errorptr = ERR16; - return NULL; - } - -/* Check that all undefined public option bits are zero. */ - -if ((options & ~PUBLIC_COMPILE_OPTIONS) != 0) - { - *errorptr = ERR17; - return NULL; - } - -/* A NULL compile context means "use a default context" */ - -if (ccontext == NULL) - ccontext = (pcre2_compile_context *)(&PRIV(default_compile_context)); - -/* A zero-terminated pattern is indicated by the special length value -PCRE2_ZERO_TERMINATED. Otherwise, we make a copy of the pattern and add a zero, -to ensure that it is always possible to look one code unit beyond the end of -the pattern's characters. In both cases, check that the pattern is overlong. */ - -if (patlen == PCRE2_ZERO_TERMINATED) - { - patlen = PRIV(strlen)(pattern); - if (patlen > ccontext->max_pattern_length) - { - *errorptr = ERR88; - return NULL; - } - } -else - { - if (patlen > ccontext->max_pattern_length) - { - *errorptr = ERR88; - return NULL; - } - if (patlen < COPIED_PATTERN_SIZE) - copied_pattern = stack_copied_pattern; - else - { - copied_pattern = ccontext->memctl.malloc(CU2BYTES(patlen + 1), - ccontext->memctl.memory_data); - if (copied_pattern == NULL) - { - *errorptr = ERR21; - return NULL; - } - } - memcpy(copied_pattern, pattern, CU2BYTES(patlen)); - copied_pattern[patlen] = 0; - pattern = copied_pattern; - } - -/* ------------ Initialize the "static" compile data -------------- */ - -tables = (ccontext->tables != NULL)? ccontext->tables : PRIV(default_tables); - -cb.lcc = tables + lcc_offset; /* Individual */ -cb.fcc = tables + fcc_offset; /* character */ -cb.cbits = tables + cbits_offset; /* tables */ -cb.ctypes = tables + ctypes_offset; - -cb.assert_depth = 0; -cb.bracount = cb.final_bracount = 0; -cb.cx = ccontext; -cb.dupnames = FALSE; -cb.end_pattern = pattern + patlen; -cb.nestptr[0] = cb.nestptr[1] = NULL; -cb.external_flags = 0; -cb.external_options = options; -cb.groupinfo = c32workspace; -cb.had_recurse = FALSE; -cb.iscondassert = FALSE; -cb.max_lookbehind = 0; -cb.name_entry_size = 0; -cb.name_table = NULL; -cb.named_groups = named_groups; -cb.named_group_list_size = NAMED_GROUP_LIST_SIZE; -cb.names_found = 0; -cb.open_caps = NULL; -cb.parens_depth = 0; -cb.req_varyopt = 0; -cb.start_code = cworkspace; -cb.start_pattern = pattern; -cb.start_workspace = cworkspace; -cb.workspace_size = COMPILE_WORK_SIZE; - -/* Maximum back reference and backref bitmap. The bitmap records up to 31 back -references to help in deciding whether (.*) can be treated as anchored or not. -*/ - -cb.top_backref = 0; -cb.backref_map = 0; - -/* --------------- Start looking at the pattern --------------- */ - -/* Check for global one-time option settings at the start of the pattern, and -remember the offset to the actual regex. */ - -ptr = pattern; -skipatstart = 0; - -while (ptr[skipatstart] == CHAR_LEFT_PARENTHESIS && - ptr[skipatstart+1] == CHAR_ASTERISK) - { - unsigned int i; - for (i = 0; i < sizeof(pso_list)/sizeof(pso); i++) - { - pso *p = pso_list + i; - - if (PRIV(strncmp_c8)(ptr+skipatstart+2, (char *)(p->name), p->length) == 0) - { - uint32_t c, pp; - - skipatstart += p->length + 2; - switch(p->type) - { - case PSO_OPT: - cb.external_options |= p->value; - break; - - case PSO_FLG: - setflags |= p->value; - break; - - case PSO_NL: - newline = p->value; - setflags |= PCRE2_NL_SET; - break; - - case PSO_BSR: - bsr = p->value; - setflags |= PCRE2_BSR_SET; - break; - - case PSO_LIMM: - case PSO_LIMR: - c = 0; - pp = skipatstart; - if (!IS_DIGIT(ptr[pp])) - { - errorcode = ERR60; - ptr += pp; - goto HAD_ERROR; - } - while (IS_DIGIT(ptr[pp])) - { - if (c > UINT32_MAX / 10 - 1) break; /* Integer overflow */ - c = c*10 + (ptr[pp++] - CHAR_0); - } - if (ptr[pp++] != CHAR_RIGHT_PARENTHESIS) - { - errorcode = ERR60; - ptr += pp; - goto HAD_ERROR; - } - if (p->type == PSO_LIMM) limit_match = c; - else limit_recursion = c; - skipatstart += pp - skipatstart; - break; - } - break; /* Out of the table scan loop */ - } - } - if (i >= sizeof(pso_list)/sizeof(pso)) break; /* Out of pso loop */ - } - -/* End of pattern-start options; advance to start of real regex. */ - -ptr += skipatstart; - -/* Can't support UTF or UCP unless PCRE2 has been compiled with UTF support. */ - -#ifndef SUPPORT_UNICODE -if ((cb.external_options & (PCRE2_UTF|PCRE2_UCP)) != 0) - { - errorcode = ERR32; - goto HAD_ERROR; - } -#endif - -/* Check UTF. We have the original options in 'options', with that value as -modified by (*UTF) etc in cb->external_options. */ - -utf = (cb.external_options & PCRE2_UTF) != 0; -if (utf) - { - if ((options & PCRE2_NEVER_UTF) != 0) - { - errorcode = ERR74; - goto HAD_ERROR; - } - if ((options & PCRE2_NO_UTF_CHECK) == 0 && - (errorcode = PRIV(valid_utf)(pattern, patlen, erroroffset)) != 0) - goto HAD_UTF_ERROR; - } - -/* Check UCP lockout. */ - -if ((cb.external_options & (PCRE2_UCP|PCRE2_NEVER_UCP)) == - (PCRE2_UCP|PCRE2_NEVER_UCP)) - { - errorcode = ERR75; - goto HAD_ERROR; - } - -/* Process the BSR setting. */ - -if (bsr == 0) bsr = ccontext->bsr_convention; - -/* Process the newline setting. */ - -if (newline == 0) newline = ccontext->newline_convention; -cb.nltype = NLTYPE_FIXED; -switch(newline) - { - case PCRE2_NEWLINE_CR: - cb.nllen = 1; - cb.nl[0] = CHAR_CR; - break; - - case PCRE2_NEWLINE_LF: - cb.nllen = 1; - cb.nl[0] = CHAR_NL; - break; - - case PCRE2_NEWLINE_CRLF: - cb.nllen = 2; - cb.nl[0] = CHAR_CR; - cb.nl[1] = CHAR_NL; - break; - - case PCRE2_NEWLINE_ANY: - cb.nltype = NLTYPE_ANY; - break; - - case PCRE2_NEWLINE_ANYCRLF: - cb.nltype = NLTYPE_ANYCRLF; - break; - - default: - errorcode = ERR56; - goto HAD_ERROR; - } - -/* Before we do anything else, do a pre-scan of the pattern in order to -discover the named groups and their numerical equivalents, so that this -information is always available for the remaining processing. */ - -errorcode = scan_for_captures(&ptr, cb.external_options, &cb); -if (errorcode != 0) goto HAD_ERROR; - -/* For obscure debugging this code can be enabled. */ - -#if 0 - { - int i; - named_group *ng = cb.named_groups; - fprintf(stderr, "+++Captures: %d\n", cb.final_bracount); - for (i = 0; i < cb.names_found; i++, ng++) - { - fprintf(stderr, "+++%3d %.*s\n", ng->number, ng->length, ng->name); - } - } -#endif - -/* Reset current bracket count to zero and current pointer to the start of the -pattern. */ - -cb.bracount = 0; -ptr = pattern + skipatstart; - -/* Pretend to compile the pattern while actually just accumulating the amount -of memory required in the 'length' variable. This behaviour is triggered by -passing a non-NULL final argument to compile_regex(). We pass a block of -workspace (cworkspace) for it to compile parts of the pattern into; the -compiled code is discarded when it is no longer needed, so hopefully this -workspace will never overflow, though there is a test for its doing so. - -On error, errorcode will be set non-zero, so we don't need to look at the -result of the function. The initial options have been put into the cb block so -that they can be changed if an option setting is found within the regex right -at the beginning. Bringing initial option settings outside can help speed up -starting point checks. We still have to pass a separate options variable (the -first argument) because that may change as the pattern is processed. */ - -code = cworkspace; -*code = OP_BRA; - -(void)compile_regex(cb.external_options, &code, &ptr, &errorcode, FALSE, - FALSE, 0, 0, &firstcu, &firstcuflags, &reqcu, &reqcuflags, NULL, - &cb, &length); - -if (errorcode != 0) goto HAD_ERROR; -if (length > MAX_PATTERN_SIZE) - { - errorcode = ERR20; - goto HAD_ERROR; - } - -/* Compute the size of, and then get and initialize, the data block for storing -the compiled pattern and names table. Integer overflow should no longer be -possible because nowadays we limit the maximum value of cb.names_found and -cb.name_entry_size. */ - -re_blocksize = sizeof(pcre2_real_code) + - CU2BYTES(length + cb.names_found * cb.name_entry_size); -re = (pcre2_real_code *) - ccontext->memctl.malloc(re_blocksize, ccontext->memctl.memory_data); -if (re == NULL) - { - errorcode = ERR21; - goto HAD_ERROR; - } - -re->memctl = ccontext->memctl; -re->tables = tables; -re->executable_jit = NULL; -memset(re->start_bitmap, 0, 32 * sizeof(uint8_t)); -re->blocksize = re_blocksize; -re->magic_number = MAGIC_NUMBER; -re->compile_options = options; -re->overall_options = cb.external_options; -re->flags = PCRE2_CODE_UNIT_WIDTH/8 | cb.external_flags | setflags; -re->limit_match = limit_match; -re->limit_recursion = limit_recursion; -re->first_codeunit = 0; -re->last_codeunit = 0; -re->bsr_convention = bsr; -re->newline_convention = newline; -re->max_lookbehind = 0; -re->minlength = 0; -re->top_bracket = 0; -re->top_backref = 0; -re->name_entry_size = cb.name_entry_size; -re->name_count = cb.names_found; - -/* The basic block is immediately followed by the name table, and the compiled -code follows after that. */ - -codestart = (PCRE2_SPTR)((uint8_t *)re + sizeof(pcre2_real_code)) + - re->name_entry_size * re->name_count; - -/* Workspace is needed to remember information about numbered groups: whether a -group can match an empty string and what its fixed length is. This is done to -avoid the possibility of recursive references causing very long compile times -when checking these features. Unnumbered groups do not have this exposure since -they cannot be referenced. We use an indexed vector for this purpose. If there -are sufficiently few groups, it can be the c32workspace vector, as set up -above. Otherwise we have to get/free a special vector. The vector must be -initialized to zero. */ - -if (cb.final_bracount >= C32_WORK_SIZE) - { - cb.groupinfo = ccontext->memctl.malloc( - (cb.final_bracount + 1)*sizeof(uint32_t), ccontext->memctl.memory_data); - if (cb.groupinfo == NULL) - { - errorcode = ERR21; - goto HAD_ERROR; - } - } -memset(cb.groupinfo, 0, (cb.final_bracount + 1) * sizeof(uint32_t)); - -/* Update the compile data block for the actual compile. The starting points of -the name/number translation table and of the code are passed around in the -compile data block. The start/end pattern and initial options are already set -from the pre-compile phase, as is the name_entry_size field. Reset the bracket -count and the names_found field. */ - -cb.parens_depth = 0; -cb.assert_depth = 0; -cb.bracount = 0; -cb.max_lookbehind = 0; -cb.name_table = (PCRE2_UCHAR *)((uint8_t *)re + sizeof(pcre2_real_code)); -cb.start_code = codestart; -cb.iscondassert = FALSE; -cb.req_varyopt = 0; -cb.had_accept = FALSE; -cb.had_pruneorskip = FALSE; -cb.check_lookbehind = FALSE; -cb.open_caps = NULL; - -/* If any named groups were found, create the name/number table from the list -created in the pre-pass. */ - -if (cb.names_found > 0) - { - int i = cb.names_found; - named_group *ng = cb.named_groups; - cb.names_found = 0; - for (; i > 0; i--, ng++) - add_name_to_table(&cb, ng->name, ng->length, ng->number); - } - -/* Set up a starting, non-extracting bracket, then compile the expression. On -error, errorcode will be set non-zero, so we don't need to look at the result -of the function here. */ - -ptr = pattern + skipatstart; -code = (PCRE2_UCHAR *)codestart; -*code = OP_BRA; -(void)compile_regex(re->overall_options, &code, &ptr, &errorcode, FALSE, FALSE, - 0, 0, &firstcu, &firstcuflags, &reqcu, &reqcuflags, NULL, &cb, NULL); - -re->top_bracket = cb.bracount; -re->top_backref = cb.top_backref; -re->max_lookbehind = cb.max_lookbehind; - -if (cb.had_accept) - { - reqcu = 0; /* Must disable after (*ACCEPT) */ - reqcuflags = REQ_NONE; - } - -/* Fill in the final opcode and check for disastrous overflow. If no overflow, -but the estimated length exceeds the really used length, adjust the value of -re->blocksize, and if valgrind support is configured, mark the extra allocated -memory as unaddressable, so that any out-of-bound reads can be detected. */ - -*code++ = OP_END; -usedlength = code - codestart; -if (usedlength > length) errorcode = ERR23; else - { - re->blocksize -= CU2BYTES(length - usedlength); -#ifdef SUPPORT_VALGRIND - VALGRIND_MAKE_MEM_NOACCESS(code, CU2BYTES(length - usedlength)); -#endif - } - -/* Scan the pattern for recursion/subroutine calls and convert the group -numbers into offsets. Maintain a small cache so that repeated groups containing -recursions are efficiently handled. */ - -#define RSCAN_CACHE_SIZE 8 - -if (errorcode == 0 && cb.had_recurse) - { - PCRE2_UCHAR *rcode; - PCRE2_SPTR rgroup; - int ccount = 0; - int start = RSCAN_CACHE_SIZE; - recurse_cache rc[RSCAN_CACHE_SIZE]; - - for (rcode = (PCRE2_UCHAR *)find_recurse(codestart, utf); - rcode != NULL; - rcode = (PCRE2_UCHAR *)find_recurse(rcode + 1 + LINK_SIZE, utf)) - { - int i, p, recno; - - recno = (int)GET(rcode, 1); - if (recno == 0) rgroup = codestart; else - { - PCRE2_SPTR search_from = codestart; - rgroup = NULL; - for (i = 0, p = start; i < ccount; i++, p = (p + 1) & 7) - { - if (recno == rc[p].recno) - { - rgroup = rc[p].group; - break; - } - - /* Group n+1 must always start to the right of group n, so we can save - search time below when the new group number is greater than any of the - previously found groups. */ - - if (recno > rc[p].recno) search_from = rc[p].group; - } - - if (rgroup == NULL) - { - rgroup = PRIV(find_bracket)(search_from, utf, recno); - if (rgroup == NULL) - { - errorcode = ERR53; - break; - } - if (--start < 0) start = RSCAN_CACHE_SIZE - 1; - rc[start].recno = recno; - rc[start].group = rgroup; - if (ccount < RSCAN_CACHE_SIZE) ccount++; - } - } - - PUT(rcode, 1, rgroup - codestart); - } - } - -/* In rare debugging situations we sometimes need to look at the compiled code -at this stage. */ - -#ifdef CALL_PRINTINT -pcre2_printint(re, stderr, TRUE); -fprintf(stderr, "Length=%lu Used=%lu\n", length, usedlength); -#endif - -/* After a successful compile, give an error if there's back reference to a -non-existent capturing subpattern. Then, unless disabled, check whether any -single character iterators can be auto-possessified. The function overwrites -the appropriate opcode values, so the type of the pointer must be cast. NOTE: -the intermediate variable "temp" is used in this code because at least one -compiler gives a warning about loss of "const" attribute if the cast -(PCRE2_UCHAR *)codestart is used directly in the function call. */ - -if (errorcode == 0) - { - if (re->top_backref > re->top_bracket) errorcode = ERR15; - else if ((re->overall_options & PCRE2_NO_AUTO_POSSESS) == 0) - { - PCRE2_UCHAR *temp = (PCRE2_UCHAR *)codestart; - if (PRIV(auto_possessify)(temp, utf, &cb) != 0) errorcode = ERR80; - } - } - -/* If there were any lookbehind assertions that contained OP_RECURSE -(recursions or subroutine calls), a flag is set for them to be checked here, -because they may contain forward references. Actual recursions cannot be fixed -length, but subroutine calls can. It is done like this so that those without -OP_RECURSE that are not fixed length get a diagnosic with a useful offset. The -exceptional ones forgo this. We scan the pattern to check that they are fixed -length, and set their lengths. */ - -if (errorcode == 0 && cb.check_lookbehind) - { - PCRE2_UCHAR *cc = (PCRE2_UCHAR *)codestart; - - /* Loop, searching for OP_REVERSE items, and process those that do not have - their length set. (Actually, it will also re-process any that have a length - of zero, but that is a pathological case, and it does no harm.) When we find - one, we temporarily terminate the branch it is in while we scan it. Note that - calling find_bracket() with a negative group number returns a pointer to the - OP_REVERSE item, not the actual lookbehind. */ - - for (cc = (PCRE2_UCHAR *)PRIV(find_bracket)(codestart, utf, -1); - cc != NULL; - cc = (PCRE2_UCHAR *)PRIV(find_bracket)(cc, utf, -1)) - { - if (GET(cc, 1) == 0) - { - int fixed_length; - int count = 0; - PCRE2_UCHAR *be = cc - 1 - LINK_SIZE + GET(cc, -LINK_SIZE); - int end_op = *be; - *be = OP_END; - fixed_length = find_fixedlength(cc, utf, TRUE, &cb, NULL, &count); - *be = end_op; - if (fixed_length < 0) - { - errorcode = fixed_length_errors[-fixed_length]; - break; - } - if (fixed_length > cb.max_lookbehind) cb.max_lookbehind = fixed_length; - PUT(cc, 1, fixed_length); - } - cc += 1 + LINK_SIZE; - } - - /* The previous value of the maximum lookbehind was transferred to the - compiled regex block above. We could have updated this value in the loop - above, but keep the two values in step, just in case some later code below - uses the cb value. */ - - re->max_lookbehind = cb.max_lookbehind; - } - -/* Failed to compile, or error while post-processing. Earlier errors get here -via the dreaded goto. */ - -if (errorcode != 0) - { - HAD_ERROR: - *erroroffset = (int)(ptr - pattern); - HAD_UTF_ERROR: - *errorptr = errorcode; - pcre2_code_free(re); - re = NULL; - goto EXIT; - } - -/* Successful compile. If the anchored option was not passed, set it if -we can determine that the pattern is anchored by virtue of ^ characters or \A -or anything else, such as starting with non-atomic .* when DOTALL is set and -there are no occurrences of *PRUNE or *SKIP (though there is an option to -disable this case). */ - -if ((re->overall_options & PCRE2_ANCHORED) == 0 && - is_anchored(codestart, 0, &cb, 0)) - re->overall_options |= PCRE2_ANCHORED; - -/* If the pattern is still not anchored and we do not have a first code unit, -see if there is one that is asserted (these are not saved during the compile -because they can cause conflicts with actual literals that follow). This code -need not be obeyed if PCRE2_NO_START_OPTIMIZE is set, as the data it would -create will not be used. */ - -if ((re->overall_options & (PCRE2_ANCHORED|PCRE2_NO_START_OPTIMIZE)) == 0) - { - if (firstcuflags < 0) - firstcu = find_firstassertedcu(codestart, &firstcuflags, FALSE); - - /* Save the data for a first code unit. */ - - if (firstcuflags >= 0) - { - re->first_codeunit = firstcu; - re->flags |= PCRE2_FIRSTSET; - - /* Handle caseless first code units. */ - - if ((firstcuflags & REQ_CASELESS) != 0) - { - if (firstcu < 128 || (!utf && firstcu < 255)) - { - if (cb.fcc[firstcu] != firstcu) re->flags |= PCRE2_FIRSTCASELESS; - } - - /* The first code unit is > 128 in UTF mode, or > 255 otherwise. In - 8-bit UTF mode, codepoints in the range 128-255 are introductory code - points and cannot have another case. In 16-bit and 32-bit modes, we can - check wide characters when UTF (and therefore UCP) is supported. */ - -#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 8 - else if (firstcu <= MAX_UTF_CODE_POINT && - UCD_OTHERCASE(firstcu) != firstcu) - re->flags |= PCRE2_FIRSTCASELESS; -#endif - } - } - - /* When there is no first code unit, see if we can set the PCRE2_STARTLINE - flag. This is helpful for multiline matches when all branches start with ^ - and also when all branches start with non-atomic .* for non-DOTALL matches - when *PRUNE and SKIP are not present. (There is an option that disables this - case.) */ - - else if (is_startline(codestart, 0, &cb, 0)) re->flags |= PCRE2_STARTLINE; - } - -/* Handle the "required code unit", if one is set. In the case of an anchored -pattern, do this only if it follows a variable length item in the pattern. -Again, skip this if PCRE2_NO_START_OPTIMIZE is set. */ - -if (reqcuflags >= 0 && - ((re->overall_options & (PCRE2_ANCHORED|PCRE2_NO_START_OPTIMIZE)) == 0 || - (reqcuflags & REQ_VARY) != 0)) - { - re->last_codeunit = reqcu; - re->flags |= PCRE2_LASTSET; - - /* Handle caseless required code units as for first code units (above). */ - - if ((reqcuflags & REQ_CASELESS) != 0) - { - if (reqcu < 128 || (!utf && reqcu < 255)) - { - if (cb.fcc[reqcu] != reqcu) re->flags |= PCRE2_LASTCASELESS; - } -#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 8 - else if (reqcu <= MAX_UTF_CODE_POINT && UCD_OTHERCASE(reqcu) != reqcu) - re->flags |= PCRE2_LASTCASELESS; -#endif - } - } - -/* Check for a pattern than can match an empty string, so that this information -can be provided to applications. */ - -do - { - int count = 0; - int rc = could_be_empty_branch(codestart, code, utf, &cb, TRUE, NULL, &count); - if (rc < 0) - { - errorcode = ERR86; - goto HAD_ERROR; - } - if (rc > 0) - { - re->flags |= PCRE2_MATCH_EMPTY; - break; - } - codestart += GET(codestart, 1); - } -while (*codestart == OP_ALT); - -/* Finally, unless PCRE2_NO_START_OPTIMIZE is set, study the compiled pattern -to set up information such as a bitmap of starting code units and a minimum -matching length. */ - -if ((re->overall_options & PCRE2_NO_START_OPTIMIZE) == 0 && - PRIV(study)(re) != 0) - { - errorcode = ERR31; - goto HAD_ERROR; - } - -/* Control ends up here in all cases. If memory was obtained for a -zero-terminated copy of the pattern, remember to free it before returning. Also -free the list of named groups if a larger one had to be obtained, and likewise -the group information vector. */ - -EXIT: -if (copied_pattern != stack_copied_pattern) - ccontext->memctl.free(copied_pattern, ccontext->memctl.memory_data); -if (cb.named_group_list_size > NAMED_GROUP_LIST_SIZE) - ccontext->memctl.free((void *)cb.named_groups, ccontext->memctl.memory_data); -if (cb.groupinfo != c32workspace) - ccontext->memctl.free((void *)cb.groupinfo, ccontext->memctl.memory_data); - -return re; /* Will be NULL after an error */ -} - -/* End of pcre2_compile.c */ - +/************************************************* +* Perl-Compatible Regular Expressions * +*************************************************/ + +/* PCRE is a library of functions to support regular expressions whose syntax +and semantics are as close as possible to those of the Perl 5 language. + + Written by Philip Hazel + Original API code Copyright (c) 1997-2012 University of Cambridge + New API code Copyright (c) 2016 University of Cambridge + +----------------------------------------------------------------------------- +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of the University of Cambridge nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +----------------------------------------------------------------------------- +*/ + +// dmex: Disable warnings +#pragma warning(push) +#pragma warning(disable : 4244 4267) + +#define HAVE_CONFIG_H +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#define NLBLOCK cb /* Block containing newline information */ +#define PSSTART start_pattern /* Field containing processed string start */ +#define PSEND end_pattern /* Field containing processed string end */ + +#include "pcre2_internal.h" + +/* In rare error cases debugging might require calling pcre2_printint(). */ + +#if 0 +#ifdef EBCDIC +#define PRINTABLE(c) ((c) >= 64 && (c) < 255) +#else +#define PRINTABLE(c) ((c) >= 32 && (c) < 127) +#endif +#include "pcre2_printint.c" +#define CALL_PRINTINT +#endif + +/* There are a few things that vary with different code unit sizes. Handle them +by defining macros in order to minimize #if usage. */ + +#if PCRE2_CODE_UNIT_WIDTH == 8 +#define STRING_UTFn_RIGHTPAR STRING_UTF8_RIGHTPAR, 5 +#define XDIGIT(c) xdigitab[c] + +#else /* Either 16-bit or 32-bit */ +#define XDIGIT(c) (MAX_255(c)? xdigitab[c] : 0xff) + +#if PCRE2_CODE_UNIT_WIDTH == 16 +#define STRING_UTFn_RIGHTPAR STRING_UTF16_RIGHTPAR, 6 + +#else /* 32-bit */ +#define STRING_UTFn_RIGHTPAR STRING_UTF32_RIGHTPAR, 6 +#endif +#endif + +/* Function definitions to allow mutual recursion */ + +static unsigned int + add_list_to_class(uint8_t *, PCRE2_UCHAR **, uint32_t, compile_block *, + const uint32_t *, unsigned int); + +static BOOL + compile_regex(uint32_t, PCRE2_UCHAR **, PCRE2_SPTR *, int *, BOOL, BOOL, + uint32_t, int, uint32_t *, int32_t *, uint32_t *, int32_t *, + branch_chain *, compile_block *, size_t *); + + + +/************************************************* +* Code parameters and static tables * +*************************************************/ + +/* This value specifies the size of stack workspace, which is used in different +ways in the different pattern scans. The group-identifying pre-scan uses it to +handle nesting, and needs it to be 16-bit aligned. + +During the first compiling phase, when determining how much memory is required, +the regex is partly compiled into this space, but the compiled parts are +discarded as soon as they can be, so that hopefully there will never be an +overrun. The code does, however, check for an overrun, which can occur for +pathological patterns. The size of the workspace depends on LINK_SIZE because +the length of compiled items varies with this. + +In the real compile phase, the workspace is used for remembering data about +numbered groups, provided there are not too many of them (if there are, extra +memory is acquired). For this phase the memory must be 32-bit aligned. Having +defined the size in code units, we set up C32_WORK_SIZE as the number of +elements in the 32-bit vector. */ + +#define COMPILE_WORK_SIZE (2048*LINK_SIZE) /* Size in code units */ + +#define C32_WORK_SIZE \ + ((COMPILE_WORK_SIZE * sizeof(PCRE2_UCHAR))/sizeof(uint32_t)) + +/* The overrun tests check for a slightly smaller size so that they detect the +overrun before it actually does run off the end of the data block. */ + +#define WORK_SIZE_SAFETY_MARGIN (100) + +/* This value determines the size of the initial vector that is used for +remembering named groups during the pre-compile. It is allocated on the stack, +but if it is too small, it is expanded, in a similar way to the workspace. The +value is the number of slots in the list. */ + +#define NAMED_GROUP_LIST_SIZE 20 + +/* The original PCRE required patterns to be zero-terminated, and it simplifies +the compiling code if it is guaranteed that there is a zero code unit at the +end of the pattern, because this means that tests for coding sequences such as +(*SKIP) or even just (?<= can check a sequence of code units without having to +keep checking for the end of the pattern. The new PCRE2 API allows zero code +units within patterns if a positive length is given, but in order to keep most +of the compiling code as it was, we copy such patterns and add a zero on the +end. This value determines the size of space on the stack that is used if the +pattern fits; if not, heap memory is used. */ + +#define COPIED_PATTERN_SIZE 1024 + +/* Maximum length value to check against when making sure that the variable +that holds the compiled pattern length does not overflow. We make it a bit less +than INT_MAX to allow for adding in group terminating bytes, so that we don't +have to check them every time. */ + +#define OFLOW_MAX (INT_MAX - 20) + +/* Macro for setting individual bits in class bitmaps. It took some +experimenting to figure out how to stop gcc 5.3.0 from warning with +-Wconversion. This version gets a warning: + + #define SETBIT(a,b) a[(b)/8] |= (uint8_t)(1 << ((b)&7)) + +Let's hope the apparently less efficient version isn't actually so bad if the +compiler is clever with identical subexpressions. */ + +#define SETBIT(a,b) a[(b)/8] = (uint8_t)(a[(b)/8] | (1 << ((b)&7))) + +/* Private flags added to firstcu and reqcu. */ + +#define REQ_CASELESS (1 << 0) /* Indicates caselessness */ +#define REQ_VARY (1 << 1) /* reqcu followed non-literal item */ +/* Negative values for the firstcu and reqcu flags */ +#define REQ_UNSET (-2) /* Not yet found anything */ +#define REQ_NONE (-1) /* Found not fixed char */ + +/* These flags are used in the groupinfo vector. */ + +#define GI_SET_COULD_BE_EMPTY 0x80000000u +#define GI_COULD_BE_EMPTY 0x40000000u +#define GI_NOT_FIXED_LENGTH 0x20000000u +#define GI_SET_FIXED_LENGTH 0x10000000u +#define GI_FIXED_LENGTH_MASK 0x0000ffffu + +/* This bit (which is greater than any UTF value) is used to indicate that a +variable contains a number of code units instead of an actual code point. */ + +#define UTF_LENGTH 0x10000000l + +/* This simple test for a decimal digit works for both ASCII/Unicode and EBCDIC +and is fast (a good compiler can turn it into a subtraction and unsigned +comparison). */ + +#define IS_DIGIT(x) ((x) >= CHAR_0 && (x) <= CHAR_9) + +/* Table to identify hex digits. The tables in chartables are dependent on the +locale, and may mark arbitrary characters as digits. We want to recognize only +0-9, a-z, and A-Z as hex digits, which is why we have a private table here. It +costs 256 bytes, but it is a lot faster than doing character value tests (at +least in some simple cases I timed), and in some applications one wants PCRE to +compile efficiently as well as match efficiently. The value in the table is +the binary hex digit value, or 0xff for non-hex digits. */ + +/* This is the "normal" case, for ASCII systems, and EBCDIC systems running in +UTF-8 mode. */ + +#ifndef EBCDIC +static const uint8_t xdigitab[] = + { + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 0- 7 */ + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 8- 15 */ + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 16- 23 */ + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 24- 31 */ + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* - ' */ + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* ( - / */ + 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, /* 0 - 7 */ + 0x08,0x09,0xff,0xff,0xff,0xff,0xff,0xff, /* 8 - ? */ + 0xff,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0xff, /* @ - G */ + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* H - O */ + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* P - W */ + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* X - _ */ + 0xff,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0xff, /* ` - g */ + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* h - o */ + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* p - w */ + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* x -127 */ + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 128-135 */ + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 136-143 */ + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 144-151 */ + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 152-159 */ + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 160-167 */ + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 168-175 */ + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 176-183 */ + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 184-191 */ + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 192-199 */ + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 2ff-207 */ + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 208-215 */ + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 216-223 */ + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 224-231 */ + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 232-239 */ + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 240-247 */ + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};/* 248-255 */ + +#else + +/* This is the "abnormal" case, for EBCDIC systems not running in UTF-8 mode. */ + +static const uint8_t xdigitab[] = + { + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 0- 7 0 */ + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 8- 15 */ + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 16- 23 10 */ + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 24- 31 */ + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 32- 39 20 */ + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 40- 47 */ + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 48- 55 30 */ + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 56- 63 */ + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* - 71 40 */ + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 72- | */ + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* & - 87 50 */ + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 88- 95 */ + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* - -103 60 */ + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 104- ? */ + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 112-119 70 */ + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 120- " */ + 0xff,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0xff, /* 128- g 80 */ + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* h -143 */ + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 144- p 90 */ + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* q -159 */ + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 160- x A0 */ + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* y -175 */ + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* ^ -183 B0 */ + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 184-191 */ + 0xff,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0xff, /* { - G C0 */ + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* H -207 */ + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* } - P D0 */ + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* Q -223 */ + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* \ - X E0 */ + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* Y -239 */ + 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, /* 0 - 7 F0 */ + 0x08,0x09,0xff,0xff,0xff,0xff,0xff,0xff};/* 8 -255 */ +#endif /* EBCDIC */ + + +/* Table for handling alphanumeric escaped characters. Positive returns are +simple data values; negative values are for special things like \d and so on. +Zero means further processing is needed (for things like \x), or the escape is +invalid. */ + +/* This is the "normal" table for ASCII systems or for EBCDIC systems running +in UTF-8 mode. It runs from '0' to 'z'. */ + +#ifndef EBCDIC +#define ESCAPES_FIRST CHAR_0 +#define ESCAPES_LAST CHAR_z +#define UPPER_CASE(c) (c-32) + +static const short int escapes[] = { + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + CHAR_COLON, CHAR_SEMICOLON, + CHAR_LESS_THAN_SIGN, CHAR_EQUALS_SIGN, + CHAR_GREATER_THAN_SIGN, CHAR_QUESTION_MARK, + CHAR_COMMERCIAL_AT, -ESC_A, + -ESC_B, -ESC_C, + -ESC_D, -ESC_E, + 0, -ESC_G, + -ESC_H, 0, + 0, -ESC_K, + 0, 0, + -ESC_N, 0, + -ESC_P, -ESC_Q, + -ESC_R, -ESC_S, + 0, 0, + -ESC_V, -ESC_W, + -ESC_X, 0, + -ESC_Z, CHAR_LEFT_SQUARE_BRACKET, + CHAR_BACKSLASH, CHAR_RIGHT_SQUARE_BRACKET, + CHAR_CIRCUMFLEX_ACCENT, CHAR_UNDERSCORE, + CHAR_GRAVE_ACCENT, ESC_a, + -ESC_b, 0, + -ESC_d, ESC_e, + ESC_f, 0, + -ESC_h, 0, + 0, -ESC_k, + 0, 0, + ESC_n, 0, + -ESC_p, 0, + ESC_r, -ESC_s, + ESC_tee, 0, + -ESC_v, -ESC_w, + 0, 0, + -ESC_z +}; + +#else + +/* This is the "abnormal" table for EBCDIC systems without UTF-8 support. +It runs from 'a' to '9'. For some minimal testing of EBCDIC features, the code +is sometimes compiled on an ASCII system. In this case, we must not use CHAR_a +because it is defined as 'a', which of course picks up the ASCII value. */ + +#if 'a' == 0x81 /* Check for a real EBCDIC environment */ +#define ESCAPES_FIRST CHAR_a +#define ESCAPES_LAST CHAR_9 +#define UPPER_CASE(c) (c+64) +#else /* Testing in an ASCII environment */ +#define ESCAPES_FIRST ((unsigned char)'\x81') /* EBCDIC 'a' */ +#define ESCAPES_LAST ((unsigned char)'\xf9') /* EBCDIC '9' */ +#define UPPER_CASE(c) (c-32) +#endif + +static const short int escapes[] = { +/* 80 */ ESC_a, -ESC_b, 0, -ESC_d, ESC_e, ESC_f, 0, +/* 88 */-ESC_h, 0, 0, '{', 0, 0, 0, 0, +/* 90 */ 0, 0, -ESC_k, 0, 0, ESC_n, 0, -ESC_p, +/* 98 */ 0, ESC_r, 0, '}', 0, 0, 0, 0, +/* A0 */ 0, '~', -ESC_s, ESC_tee, 0,-ESC_v, -ESC_w, 0, +/* A8 */ 0,-ESC_z, 0, 0, 0, '[', 0, 0, +/* B0 */ 0, 0, 0, 0, 0, 0, 0, 0, +/* B8 */ 0, 0, 0, 0, 0, ']', '=', '-', +/* C0 */ '{',-ESC_A, -ESC_B, -ESC_C, -ESC_D,-ESC_E, 0, -ESC_G, +/* C8 */-ESC_H, 0, 0, 0, 0, 0, 0, 0, +/* D0 */ '}', 0, -ESC_K, 0, 0,-ESC_N, 0, -ESC_P, +/* D8 */-ESC_Q,-ESC_R, 0, 0, 0, 0, 0, 0, +/* E0 */ '\\', 0, -ESC_S, 0, 0,-ESC_V, -ESC_W, -ESC_X, +/* E8 */ 0,-ESC_Z, 0, 0, 0, 0, 0, 0, +/* F0 */ 0, 0, 0, 0, 0, 0, 0, 0, +/* F8 */ 0, 0 +}; + +/* We also need a table of characters that may follow \c in an EBCDIC +environment for characters 0-31. */ + +static unsigned char ebcdic_escape_c[] = "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"; + +#endif /* EBCDIC */ + + +/* Table of special "verbs" like (*PRUNE). This is a short table, so it is +searched linearly. Put all the names into a single string, in order to reduce +the number of relocations when a shared library is dynamically linked. The +string is built from string macros so that it works in UTF-8 mode on EBCDIC +platforms. */ + +typedef struct verbitem { + int len; /* Length of verb name */ + int op; /* Op when no arg, or -1 if arg mandatory */ + int op_arg; /* Op when arg present, or -1 if not allowed */ +} verbitem; + +static const char verbnames[] = + "\0" /* Empty name is a shorthand for MARK */ + STRING_MARK0 + STRING_ACCEPT0 + STRING_COMMIT0 + STRING_F0 + STRING_FAIL0 + STRING_PRUNE0 + STRING_SKIP0 + STRING_THEN; + +static const verbitem verbs[] = { + { 0, -1, OP_MARK }, + { 4, -1, OP_MARK }, + { 6, OP_ACCEPT, -1 }, + { 6, OP_COMMIT, -1 }, + { 1, OP_FAIL, -1 }, + { 4, OP_FAIL, -1 }, + { 5, OP_PRUNE, OP_PRUNE_ARG }, + { 4, OP_SKIP, OP_SKIP_ARG }, + { 4, OP_THEN, OP_THEN_ARG } +}; + +static const int verbcount = sizeof(verbs)/sizeof(verbitem); + + +/* Substitutes for [[:<:]] and [[:>:]], which mean start and end of word in +another regex library. */ + +static const PCRE2_UCHAR sub_start_of_word[] = { + CHAR_BACKSLASH, CHAR_b, CHAR_LEFT_PARENTHESIS, CHAR_QUESTION_MARK, + CHAR_EQUALS_SIGN, CHAR_BACKSLASH, CHAR_w, CHAR_RIGHT_PARENTHESIS, '\0' }; + +static const PCRE2_UCHAR sub_end_of_word[] = { + CHAR_BACKSLASH, CHAR_b, CHAR_LEFT_PARENTHESIS, CHAR_QUESTION_MARK, + CHAR_LESS_THAN_SIGN, CHAR_EQUALS_SIGN, CHAR_BACKSLASH, CHAR_w, + CHAR_RIGHT_PARENTHESIS, '\0' }; + + +/* Tables of names of POSIX character classes and their lengths. The names are +now all in a single string, to reduce the number of relocations when a shared +library is dynamically loaded. The list of lengths is terminated by a zero +length entry. The first three must be alpha, lower, upper, as this is assumed +for handling case independence. The indices for graph, print, and punct are +needed, so identify them. */ + +static const char posix_names[] = + STRING_alpha0 STRING_lower0 STRING_upper0 STRING_alnum0 + STRING_ascii0 STRING_blank0 STRING_cntrl0 STRING_digit0 + STRING_graph0 STRING_print0 STRING_punct0 STRING_space0 + STRING_word0 STRING_xdigit; + +static const uint8_t posix_name_lengths[] = { + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 6, 0 }; + +#define PC_GRAPH 8 +#define PC_PRINT 9 +#define PC_PUNCT 10 + + +/* Table of class bit maps for each POSIX class. Each class is formed from a +base map, with an optional addition or removal of another map. Then, for some +classes, there is some additional tweaking: for [:blank:] the vertical space +characters are removed, and for [:alpha:] and [:alnum:] the underscore +character is removed. The triples in the table consist of the base map offset, +second map offset or -1 if no second map, and a non-negative value for map +addition or a negative value for map subtraction (if there are two maps). The +absolute value of the third field has these meanings: 0 => no tweaking, 1 => +remove vertical space characters, 2 => remove underscore. */ + +static const int posix_class_maps[] = { + cbit_word, cbit_digit, -2, /* alpha */ + cbit_lower, -1, 0, /* lower */ + cbit_upper, -1, 0, /* upper */ + cbit_word, -1, 2, /* alnum - word without underscore */ + cbit_print, cbit_cntrl, 0, /* ascii */ + cbit_space, -1, 1, /* blank - a GNU extension */ + cbit_cntrl, -1, 0, /* cntrl */ + cbit_digit, -1, 0, /* digit */ + cbit_graph, -1, 0, /* graph */ + cbit_print, -1, 0, /* print */ + cbit_punct, -1, 0, /* punct */ + cbit_space, -1, 0, /* space */ + cbit_word, -1, 0, /* word - a Perl extension */ + cbit_xdigit,-1, 0 /* xdigit */ +}; + +/* Table of substitutes for \d etc when PCRE2_UCP is set. They are replaced by +Unicode property escapes. */ + +#ifdef SUPPORT_UNICODE +static const PCRE2_UCHAR string_PNd[] = { + CHAR_BACKSLASH, CHAR_P, CHAR_LEFT_CURLY_BRACKET, + CHAR_N, CHAR_d, CHAR_RIGHT_CURLY_BRACKET, '\0' }; +static const PCRE2_UCHAR string_pNd[] = { + CHAR_BACKSLASH, CHAR_p, CHAR_LEFT_CURLY_BRACKET, + CHAR_N, CHAR_d, CHAR_RIGHT_CURLY_BRACKET, '\0' }; +static const PCRE2_UCHAR string_PXsp[] = { + CHAR_BACKSLASH, CHAR_P, CHAR_LEFT_CURLY_BRACKET, + CHAR_X, CHAR_s, CHAR_p, CHAR_RIGHT_CURLY_BRACKET, '\0' }; +static const PCRE2_UCHAR string_pXsp[] = { + CHAR_BACKSLASH, CHAR_p, CHAR_LEFT_CURLY_BRACKET, + CHAR_X, CHAR_s, CHAR_p, CHAR_RIGHT_CURLY_BRACKET, '\0' }; +static const PCRE2_UCHAR string_PXwd[] = { + CHAR_BACKSLASH, CHAR_P, CHAR_LEFT_CURLY_BRACKET, + CHAR_X, CHAR_w, CHAR_d, CHAR_RIGHT_CURLY_BRACKET, '\0' }; +static const PCRE2_UCHAR string_pXwd[] = { + CHAR_BACKSLASH, CHAR_p, CHAR_LEFT_CURLY_BRACKET, + CHAR_X, CHAR_w, CHAR_d, CHAR_RIGHT_CURLY_BRACKET, '\0' }; + +static PCRE2_SPTR substitutes[] = { + string_PNd, /* \D */ + string_pNd, /* \d */ + string_PXsp, /* \S */ /* Xsp is Perl space, but from 8.34, Perl */ + string_pXsp, /* \s */ /* space and POSIX space are the same. */ + string_PXwd, /* \W */ + string_pXwd /* \w */ +}; + +/* The POSIX class substitutes must be in the order of the POSIX class names, +defined above, and there are both positive and negative cases. NULL means no +general substitute of a Unicode property escape (\p or \P). However, for some +POSIX classes (e.g. graph, print, punct) a special property code is compiled +directly. */ + +static const PCRE2_UCHAR string_pCc[] = { + CHAR_BACKSLASH, CHAR_p, CHAR_LEFT_CURLY_BRACKET, + CHAR_C, CHAR_c, CHAR_RIGHT_CURLY_BRACKET, '\0' }; +static const PCRE2_UCHAR string_pL[] = { + CHAR_BACKSLASH, CHAR_p, CHAR_LEFT_CURLY_BRACKET, + CHAR_L, CHAR_RIGHT_CURLY_BRACKET, '\0' }; +static const PCRE2_UCHAR string_pLl[] = { + CHAR_BACKSLASH, CHAR_p, CHAR_LEFT_CURLY_BRACKET, + CHAR_L, CHAR_l, CHAR_RIGHT_CURLY_BRACKET, '\0' }; +static const PCRE2_UCHAR string_pLu[] = { + CHAR_BACKSLASH, CHAR_p, CHAR_LEFT_CURLY_BRACKET, + CHAR_L, CHAR_u, CHAR_RIGHT_CURLY_BRACKET, '\0' }; +static const PCRE2_UCHAR string_pXan[] = { + CHAR_BACKSLASH, CHAR_p, CHAR_LEFT_CURLY_BRACKET, + CHAR_X, CHAR_a, CHAR_n, CHAR_RIGHT_CURLY_BRACKET, '\0' }; +static const PCRE2_UCHAR string_h[] = { + CHAR_BACKSLASH, CHAR_h, '\0' }; +static const PCRE2_UCHAR string_pXps[] = { + CHAR_BACKSLASH, CHAR_p, CHAR_LEFT_CURLY_BRACKET, + CHAR_X, CHAR_p, CHAR_s, CHAR_RIGHT_CURLY_BRACKET, '\0' }; +static const PCRE2_UCHAR string_PCc[] = { + CHAR_BACKSLASH, CHAR_P, CHAR_LEFT_CURLY_BRACKET, + CHAR_C, CHAR_c, CHAR_RIGHT_CURLY_BRACKET, '\0' }; +static const PCRE2_UCHAR string_PL[] = { + CHAR_BACKSLASH, CHAR_P, CHAR_LEFT_CURLY_BRACKET, + CHAR_L, CHAR_RIGHT_CURLY_BRACKET, '\0' }; +static const PCRE2_UCHAR string_PLl[] = { + CHAR_BACKSLASH, CHAR_P, CHAR_LEFT_CURLY_BRACKET, + CHAR_L, CHAR_l, CHAR_RIGHT_CURLY_BRACKET, '\0' }; +static const PCRE2_UCHAR string_PLu[] = { + CHAR_BACKSLASH, CHAR_P, CHAR_LEFT_CURLY_BRACKET, + CHAR_L, CHAR_u, CHAR_RIGHT_CURLY_BRACKET, '\0' }; +static const PCRE2_UCHAR string_PXan[] = { + CHAR_BACKSLASH, CHAR_P, CHAR_LEFT_CURLY_BRACKET, + CHAR_X, CHAR_a, CHAR_n, CHAR_RIGHT_CURLY_BRACKET, '\0' }; +static const PCRE2_UCHAR string_H[] = { + CHAR_BACKSLASH, CHAR_H, '\0' }; +static const PCRE2_UCHAR string_PXps[] = { + CHAR_BACKSLASH, CHAR_P, CHAR_LEFT_CURLY_BRACKET, + CHAR_X, CHAR_p, CHAR_s, CHAR_RIGHT_CURLY_BRACKET, '\0' }; + +static PCRE2_SPTR posix_substitutes[] = { + string_pL, /* alpha */ + string_pLl, /* lower */ + string_pLu, /* upper */ + string_pXan, /* alnum */ + NULL, /* ascii */ + string_h, /* blank */ + string_pCc, /* cntrl */ + string_pNd, /* digit */ + NULL, /* graph */ + NULL, /* print */ + NULL, /* punct */ + string_pXps, /* space */ /* Xps is POSIX space, but from 8.34 */ + string_pXwd, /* word */ /* Perl and POSIX space are the same */ + NULL, /* xdigit */ + /* Negated cases */ + string_PL, /* ^alpha */ + string_PLl, /* ^lower */ + string_PLu, /* ^upper */ + string_PXan, /* ^alnum */ + NULL, /* ^ascii */ + string_H, /* ^blank */ + string_PCc, /* ^cntrl */ + string_PNd, /* ^digit */ + NULL, /* ^graph */ + NULL, /* ^print */ + NULL, /* ^punct */ + string_PXps, /* ^space */ /* Xps is POSIX space, but from 8.34 */ + string_PXwd, /* ^word */ /* Perl and POSIX space are the same */ + NULL /* ^xdigit */ +}; +#define POSIX_SUBSIZE (sizeof(posix_substitutes) / sizeof(PCRE2_UCHAR *)) +#endif /* SUPPORT_UNICODE */ + +/* Masks for checking option settings. */ + +#define PUBLIC_COMPILE_OPTIONS \ + (PCRE2_ANCHORED|PCRE2_ALLOW_EMPTY_CLASS|PCRE2_ALT_BSUX|PCRE2_ALT_CIRCUMFLEX| \ + PCRE2_ALT_VERBNAMES|PCRE2_AUTO_CALLOUT|PCRE2_CASELESS|PCRE2_DOLLAR_ENDONLY| \ + PCRE2_DOTALL|PCRE2_DUPNAMES|PCRE2_EXTENDED|PCRE2_FIRSTLINE| \ + PCRE2_MATCH_UNSET_BACKREF|PCRE2_MULTILINE|PCRE2_NEVER_BACKSLASH_C| \ + PCRE2_NEVER_UCP|PCRE2_NEVER_UTF|PCRE2_NO_AUTO_CAPTURE| \ + PCRE2_NO_AUTO_POSSESS|PCRE2_NO_DOTSTAR_ANCHOR|PCRE2_NO_START_OPTIMIZE| \ + PCRE2_NO_UTF_CHECK|PCRE2_UCP|PCRE2_UNGREEDY|PCRE2_USE_OFFSET_LIMIT| \ + PCRE2_UTF) + +/* Compile time error code numbers. They are given names so that they can more +easily be tracked. When a new number is added, the tables called eint1 and +eint2 in pcre2posix.c may need to be updated, and a new error text must be +added to compile_error_texts in pcre2_error.c. */ + +enum { ERR0 = COMPILE_ERROR_BASE, + ERR1, ERR2, ERR3, ERR4, ERR5, ERR6, ERR7, ERR8, ERR9, ERR10, + ERR11, ERR12, ERR13, ERR14, ERR15, ERR16, ERR17, ERR18, ERR19, ERR20, + ERR21, ERR22, ERR23, ERR24, ERR25, ERR26, ERR27, ERR28, ERR29, ERR30, + ERR31, ERR32, ERR33, ERR34, ERR35, ERR36, ERR37, ERR38, ERR39, ERR40, + ERR41, ERR42, ERR43, ERR44, ERR45, ERR46, ERR47, ERR48, ERR49, ERR50, + ERR51, ERR52, ERR53, ERR54, ERR55, ERR56, ERR57, ERR58, ERR59, ERR60, + ERR61, ERR62, ERR63, ERR64, ERR65, ERR66, ERR67, ERR68, ERR69, ERR70, + ERR71, ERR72, ERR73, ERR74, ERR75, ERR76, ERR77, ERR78, ERR79, ERR80, + ERR81, ERR82, ERR83, ERR84, ERR85, ERR86, ERR87, ERR88 }; + +/* Error codes that correspond to negative error codes returned by +find_fixedlength(). */ + +static int fixed_length_errors[] = + { + ERR0, /* Not an error */ + ERR0, /* Not an error; -1 is used for "process later" */ + ERR25, /* Lookbehind is not fixed length */ + ERR36, /* \C in lookbehind is not allowed */ + ERR87, /* Lookbehind is too long */ + ERR86, /* Pattern too complicated */ + ERR70 /* Internal error: unknown opcode encountered */ + }; + +/* This is a table of start-of-pattern options such as (*UTF) and settings such +as (*LIMIT_MATCH=nnnn) and (*CRLF). For completeness and backward +compatibility, (*UTFn) is supported in the relevant libraries, but (*UTF) is +generic and always supported. */ + +enum { PSO_OPT, /* Value is an option bit */ + PSO_FLG, /* Value is a flag bit */ + PSO_NL, /* Value is a newline type */ + PSO_BSR, /* Value is a \R type */ + PSO_LIMM, /* Read integer value for match limit */ + PSO_LIMR }; /* Read integer value for recursion limit */ + +typedef struct pso { + const uint8_t *name; + uint16_t length; + uint16_t type; + uint32_t value; +} pso; + +/* NB: STRING_UTFn_RIGHTPAR contains the length as well */ + +static pso pso_list[] = { + { (uint8_t *)STRING_UTFn_RIGHTPAR, PSO_OPT, PCRE2_UTF }, + { (uint8_t *)STRING_UTF_RIGHTPAR, 4, PSO_OPT, PCRE2_UTF }, + { (uint8_t *)STRING_UCP_RIGHTPAR, 4, PSO_OPT, PCRE2_UCP }, + { (uint8_t *)STRING_NOTEMPTY_RIGHTPAR, 9, PSO_FLG, PCRE2_NOTEMPTY_SET }, + { (uint8_t *)STRING_NOTEMPTY_ATSTART_RIGHTPAR, 17, PSO_FLG, PCRE2_NE_ATST_SET }, + { (uint8_t *)STRING_NO_AUTO_POSSESS_RIGHTPAR, 16, PSO_OPT, PCRE2_NO_AUTO_POSSESS }, + { (uint8_t *)STRING_NO_DOTSTAR_ANCHOR_RIGHTPAR, 18, PSO_OPT, PCRE2_NO_DOTSTAR_ANCHOR }, + { (uint8_t *)STRING_NO_JIT_RIGHTPAR, 7, PSO_FLG, PCRE2_NOJIT }, + { (uint8_t *)STRING_NO_START_OPT_RIGHTPAR, 13, PSO_OPT, PCRE2_NO_START_OPTIMIZE }, + { (uint8_t *)STRING_LIMIT_MATCH_EQ, 12, PSO_LIMM, 0 }, + { (uint8_t *)STRING_LIMIT_RECURSION_EQ, 16, PSO_LIMR, 0 }, + { (uint8_t *)STRING_CR_RIGHTPAR, 3, PSO_NL, PCRE2_NEWLINE_CR }, + { (uint8_t *)STRING_LF_RIGHTPAR, 3, PSO_NL, PCRE2_NEWLINE_LF }, + { (uint8_t *)STRING_CRLF_RIGHTPAR, 5, PSO_NL, PCRE2_NEWLINE_CRLF }, + { (uint8_t *)STRING_ANY_RIGHTPAR, 4, PSO_NL, PCRE2_NEWLINE_ANY }, + { (uint8_t *)STRING_ANYCRLF_RIGHTPAR, 8, PSO_NL, PCRE2_NEWLINE_ANYCRLF }, + { (uint8_t *)STRING_BSR_ANYCRLF_RIGHTPAR, 12, PSO_BSR, PCRE2_BSR_ANYCRLF }, + { (uint8_t *)STRING_BSR_UNICODE_RIGHTPAR, 12, PSO_BSR, PCRE2_BSR_UNICODE } +}; + +/* This table is used when converting repeating opcodes into possessified +versions as a result of an explicit possessive quantifier such as ++. A zero +value means there is no possessified version - in those cases the item in +question must be wrapped in ONCE brackets. The table is truncated at OP_CALLOUT +because all relevant opcodes are less than that. */ + +static const uint8_t opcode_possessify[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0 - 15 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 16 - 31 */ + + 0, /* NOTI */ + OP_POSSTAR, 0, /* STAR, MINSTAR */ + OP_POSPLUS, 0, /* PLUS, MINPLUS */ + OP_POSQUERY, 0, /* QUERY, MINQUERY */ + OP_POSUPTO, 0, /* UPTO, MINUPTO */ + 0, /* EXACT */ + 0, 0, 0, 0, /* POS{STAR,PLUS,QUERY,UPTO} */ + + OP_POSSTARI, 0, /* STARI, MINSTARI */ + OP_POSPLUSI, 0, /* PLUSI, MINPLUSI */ + OP_POSQUERYI, 0, /* QUERYI, MINQUERYI */ + OP_POSUPTOI, 0, /* UPTOI, MINUPTOI */ + 0, /* EXACTI */ + 0, 0, 0, 0, /* POS{STARI,PLUSI,QUERYI,UPTOI} */ + + OP_NOTPOSSTAR, 0, /* NOTSTAR, NOTMINSTAR */ + OP_NOTPOSPLUS, 0, /* NOTPLUS, NOTMINPLUS */ + OP_NOTPOSQUERY, 0, /* NOTQUERY, NOTMINQUERY */ + OP_NOTPOSUPTO, 0, /* NOTUPTO, NOTMINUPTO */ + 0, /* NOTEXACT */ + 0, 0, 0, 0, /* NOTPOS{STAR,PLUS,QUERY,UPTO} */ + + OP_NOTPOSSTARI, 0, /* NOTSTARI, NOTMINSTARI */ + OP_NOTPOSPLUSI, 0, /* NOTPLUSI, NOTMINPLUSI */ + OP_NOTPOSQUERYI, 0, /* NOTQUERYI, NOTMINQUERYI */ + OP_NOTPOSUPTOI, 0, /* NOTUPTOI, NOTMINUPTOI */ + 0, /* NOTEXACTI */ + 0, 0, 0, 0, /* NOTPOS{STARI,PLUSI,QUERYI,UPTOI} */ + + OP_TYPEPOSSTAR, 0, /* TYPESTAR, TYPEMINSTAR */ + OP_TYPEPOSPLUS, 0, /* TYPEPLUS, TYPEMINPLUS */ + OP_TYPEPOSQUERY, 0, /* TYPEQUERY, TYPEMINQUERY */ + OP_TYPEPOSUPTO, 0, /* TYPEUPTO, TYPEMINUPTO */ + 0, /* TYPEEXACT */ + 0, 0, 0, 0, /* TYPEPOS{STAR,PLUS,QUERY,UPTO} */ + + OP_CRPOSSTAR, 0, /* CRSTAR, CRMINSTAR */ + OP_CRPOSPLUS, 0, /* CRPLUS, CRMINPLUS */ + OP_CRPOSQUERY, 0, /* CRQUERY, CRMINQUERY */ + OP_CRPOSRANGE, 0, /* CRRANGE, CRMINRANGE */ + 0, 0, 0, 0, /* CRPOS{STAR,PLUS,QUERY,RANGE} */ + + 0, 0, 0, /* CLASS, NCLASS, XCLASS */ + 0, 0, /* REF, REFI */ + 0, 0, /* DNREF, DNREFI */ + 0, 0 /* RECURSE, CALLOUT */ +}; + + + +/************************************************* +* Copy compiled code * +*************************************************/ + +/* Compiled JIT code cannot be copied, so the new compiled block has no +associated JIT data. */ + +PCRE2_EXP_DEFN pcre2_code * PCRE2_CALL_CONVENTION +pcre2_code_copy(const pcre2_code *code) +{ +PCRE2_SIZE* ref_count; +pcre2_code *newcode; + +if (code == NULL) return NULL; +newcode = code->memctl.malloc(code->blocksize, code->memctl.memory_data); +if (newcode == NULL) return NULL; +memcpy(newcode, code, code->blocksize); +newcode->executable_jit = NULL; + +/* If the code is one that has been deserialized, increment the reference count +in the decoded tables. */ + +if ((code->flags & PCRE2_DEREF_TABLES) != 0) + { + ref_count = (PCRE2_SIZE *)(code->tables + tables_length); + (*ref_count)++; + } + +return newcode; +} + + + +/************************************************* +* Free compiled code * +*************************************************/ + +PCRE2_EXP_DEFN void PCRE2_CALL_CONVENTION +pcre2_code_free(pcre2_code *code) +{ +PCRE2_SIZE* ref_count; + +if (code != NULL) + { + if (code->executable_jit != NULL) + PRIV(jit_free)(code->executable_jit, &code->memctl); + + if ((code->flags & PCRE2_DEREF_TABLES) != 0) + { + /* Decoded tables belong to the codes after deserialization, and they must + be freed when there are no more reference to them. The *ref_count should + always be > 0. */ + + ref_count = (PCRE2_SIZE *)(code->tables + tables_length); + if (*ref_count > 0) + { + (*ref_count)--; + if (*ref_count == 0) + code->memctl.free((void *)code->tables, code->memctl.memory_data); + } + } + + code->memctl.free(code, code->memctl.memory_data); + } +} + + + +/************************************************* +* Insert an automatic callout point * +*************************************************/ + +/* This function is called when the PCRE2_AUTO_CALLOUT option is set, to insert +callout points before each pattern item. + +Arguments: + code current code pointer + ptr current pattern pointer + cb general compile-time data + +Returns: new code pointer +*/ + +static PCRE2_UCHAR * +auto_callout(PCRE2_UCHAR *code, PCRE2_SPTR ptr, compile_block *cb) +{ +code[0] = OP_CALLOUT; +PUT(code, 1, ptr - cb->start_pattern); /* Pattern offset */ +PUT(code, 1 + LINK_SIZE, 0); /* Default length */ +code[1 + 2*LINK_SIZE] = 255; +return code + PRIV(OP_lengths)[OP_CALLOUT]; +} + + + +/************************************************* +* Complete a callout item * +*************************************************/ + +/* A callout item contains the length of the next item in the pattern, which +we can't fill in till after we have reached the relevant point. This is used +for both automatic and manual callouts. + +Arguments: + previous_callout points to previous callout item + ptr current pattern pointer + cb general compile-time data + +Returns: nothing +*/ + +static void +complete_callout(PCRE2_UCHAR *previous_callout, PCRE2_SPTR ptr, + compile_block *cb) +{ +size_t length = (size_t)(ptr - cb->start_pattern - GET(previous_callout, 1)); +PUT(previous_callout, 1 + LINK_SIZE, length); +} + + + +/************************************************* +* Find the fixed length of a branch * +*************************************************/ + +/* Scan a branch and compute the fixed length of subject that will match it, if +the length is fixed. This is needed for dealing with lookbehind assertions. In +UTF mode, the result is in code units rather than bytes. The branch is +temporarily terminated with OP_END when this function is called. + +This function is called when a lookbehind assertion is encountered, so that if +it fails, the error message can point to the correct place in the pattern. +However, we cannot do this when the assertion contains subroutine calls, +because they can be forward references. We solve this by remembering this case +and doing the check at the end; a flag specifies which mode we are running in. + +Lookbehind lengths are held in 16-bit fields and the maximum value is defined +as LOOKBEHIND_MAX. + +Arguments: + code points to the start of the pattern (the bracket) + utf TRUE in UTF mode + atend TRUE if called when the pattern is complete + cb the "compile data" structure + recurses chain of recurse_check to catch mutual recursion + countptr pointer to counter, to catch over-complexity + +Returns: if non-negative, the fixed length, + or -1 if an OP_RECURSE item was encountered and atend is FALSE + or -2 if there is no fixed length, + or -3 if \C was encountered (in UTF mode only) + or -4 if length is too long + or -5 if regex is too complicated + or -6 if an unknown opcode was encountered (internal error) +*/ + +#define FFL_LATER (-1) +#define FFL_NOTFIXED (-2) +#define FFL_BACKSLASHC (-3) +#define FFL_TOOLONG (-4) +#define FFL_TOOCOMPLICATED (-5) +#define FFL_UNKNOWNOP (-6) + +static int +find_fixedlength(PCRE2_UCHAR *code, BOOL utf, BOOL atend, compile_block *cb, + recurse_check *recurses, int *countptr) +{ +uint32_t length = 0xffffffffu; /* Unset */ +uint32_t group = 0; +uint32_t groupinfo = 0; +recurse_check this_recurse; +register uint32_t branchlength = 0; +register PCRE2_UCHAR *cc = code + 1 + LINK_SIZE; + +/* If this is a capturing group, we may have the answer cached, but we can only +use this information if there are no (?| groups in the pattern, because +otherwise group numbers are not unique. */ + +if (*code == OP_CBRA || *code == OP_CBRAPOS || *code == OP_SCBRA || + *code == OP_SCBRAPOS) + { + group = GET2(cc, 0); + cc += IMM2_SIZE; + groupinfo = cb->groupinfo[group]; + if ((cb->external_flags & PCRE2_DUPCAPUSED) == 0) + { + if ((groupinfo & GI_NOT_FIXED_LENGTH) != 0) return FFL_NOTFIXED; + if ((groupinfo & GI_SET_FIXED_LENGTH) != 0) + return groupinfo & GI_FIXED_LENGTH_MASK; + } + } + +/* A large and/or complex regex can take too long to process. This can happen +more often when (?| groups are present in the pattern. */ + +if ((*countptr)++ > 2000) return FFL_TOOCOMPLICATED; + +/* Scan along the opcodes for this branch. If we get to the end of the +branch, check the length against that of the other branches. */ + +for (;;) + { + int d; + PCRE2_UCHAR *ce, *cs; + register PCRE2_UCHAR op = *cc; + + if (branchlength > LOOKBEHIND_MAX) return FFL_TOOLONG; + + switch (op) + { + /* We only need to continue for OP_CBRA (normal capturing bracket) and + OP_BRA (normal non-capturing bracket) because the other variants of these + opcodes are all concerned with unlimited repeated groups, which of course + are not of fixed length. */ + + case OP_CBRA: + case OP_BRA: + case OP_ONCE: + case OP_ONCE_NC: + case OP_COND: + d = find_fixedlength(cc, utf, atend, cb, recurses, countptr); + if (d < 0) return d; + branchlength += (uint32_t)d; + do cc += GET(cc, 1); while (*cc == OP_ALT); + cc += 1 + LINK_SIZE; + break; + + /* Reached end of a branch; if it's a ket it is the end of a nested call. + If it's ALT it is an alternation in a nested call. An ACCEPT is effectively + an ALT. If it is END it's the end of the outer call. All can be handled by + the same code. Note that we must not include the OP_KETRxxx opcodes here, + because they all imply an unlimited repeat. */ + + case OP_ALT: + case OP_KET: + case OP_END: + case OP_ACCEPT: + case OP_ASSERT_ACCEPT: + if (length == 0xffffffffu) length = branchlength; + else if (length != branchlength) goto ISNOTFIXED; + if (*cc != OP_ALT) + { + if (group > 0) + { + groupinfo |= (uint32_t)(GI_SET_FIXED_LENGTH | length); + cb->groupinfo[group] = groupinfo; + } + return (int)length; + } + cc += 1 + LINK_SIZE; + branchlength = 0; + break; + + /* A true recursion implies not fixed length, but a subroutine call may + be OK. If the subroutine is a forward reference, we can't deal with + it until the end of the pattern, so return FFL_LATER. */ + + case OP_RECURSE: + if (!atend) return FFL_LATER; + cs = ce = (PCRE2_UCHAR *)cb->start_code + GET(cc, 1); /* Start subpattern */ + do ce += GET(ce, 1); while (*ce == OP_ALT); /* End subpattern */ + if (cc > cs && cc < ce) goto ISNOTFIXED; /* Recursion */ + else /* Check for mutual recursion */ + { + recurse_check *r = recurses; + for (r = recurses; r != NULL; r = r->prev) if (r->group == cs) break; + if (r != NULL) goto ISNOTFIXED; /* Mutual recursion */ + } + this_recurse.prev = recurses; + this_recurse.group = cs; + d = find_fixedlength(cs, utf, atend, cb, &this_recurse, countptr); + if (d < 0) return d; + branchlength += (uint32_t)d; + cc += 1 + LINK_SIZE; + break; + + /* Skip over assertive subpatterns. Note that we must increment cc by + 1 + LINK_SIZE at the end, not by OP_length[*cc] because in a recursive + situation this assertion may be the one that is ultimately being checked + for having a fixed length, in which case its terminating OP_KET will have + been temporarily replaced by OP_END. */ + + case OP_ASSERT: + case OP_ASSERT_NOT: + case OP_ASSERTBACK: + case OP_ASSERTBACK_NOT: + do cc += GET(cc, 1); while (*cc == OP_ALT); + cc += 1 + LINK_SIZE; + break; + + /* Skip over things that don't match chars */ + + case OP_MARK: + case OP_PRUNE_ARG: + case OP_SKIP_ARG: + case OP_THEN_ARG: + cc += cc[1] + PRIV(OP_lengths)[*cc]; + break; + + case OP_CALLOUT: + case OP_CIRC: + case OP_CIRCM: + case OP_CLOSE: + case OP_COMMIT: + case OP_CREF: + case OP_FALSE: + case OP_TRUE: + case OP_DNCREF: + case OP_DNRREF: + case OP_DOLL: + case OP_DOLLM: + case OP_EOD: + case OP_EODN: + case OP_FAIL: + case OP_NOT_WORD_BOUNDARY: + case OP_PRUNE: + case OP_REVERSE: + case OP_RREF: + case OP_SET_SOM: + case OP_SKIP: + case OP_SOD: + case OP_SOM: + case OP_THEN: + case OP_WORD_BOUNDARY: + cc += PRIV(OP_lengths)[*cc]; + break; + + case OP_CALLOUT_STR: + cc += GET(cc, 1 + 2*LINK_SIZE); + break; + + /* Handle literal characters */ + + case OP_CHAR: + case OP_CHARI: + case OP_NOT: + case OP_NOTI: + branchlength++; + cc += 2; +#ifdef SUPPORT_UNICODE + if (utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]); +#endif + break; + + /* Handle exact repetitions. The count is already in characters, but we + need to skip over a multibyte character in UTF8 mode. */ + + case OP_EXACT: + case OP_EXACTI: + case OP_NOTEXACT: + case OP_NOTEXACTI: + branchlength += GET2(cc,1); + cc += 2 + IMM2_SIZE; +#ifdef SUPPORT_UNICODE + if (utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]); +#endif + break; + + case OP_TYPEEXACT: + branchlength += GET2(cc,1); + if (cc[1 + IMM2_SIZE] == OP_PROP || cc[1 + IMM2_SIZE] == OP_NOTPROP) + cc += 2; + cc += 1 + IMM2_SIZE + 1; + break; + + /* Handle single-char matchers */ + + case OP_PROP: + case OP_NOTPROP: + cc += 2; + /* Fall through */ + + case OP_HSPACE: + case OP_VSPACE: + case OP_NOT_HSPACE: + case OP_NOT_VSPACE: + case OP_NOT_DIGIT: + case OP_DIGIT: + case OP_NOT_WHITESPACE: + case OP_WHITESPACE: + case OP_NOT_WORDCHAR: + case OP_WORDCHAR: + case OP_ANY: + case OP_ALLANY: + branchlength++; + cc++; + break; + + /* The single-byte matcher isn't allowed. This only happens in UTF-8 or + UTF-16 mode; otherwise \C is coded as OP_ALLANY. */ + + case OP_ANYBYTE: + return FFL_BACKSLASHC; + + /* Check a class for variable quantification */ + + case OP_CLASS: + case OP_NCLASS: +#ifdef SUPPORT_WIDE_CHARS + case OP_XCLASS: + /* The original code caused an unsigned overflow in 64 bit systems, + so now we use a conditional statement. */ + if (op == OP_XCLASS) + cc += GET(cc, 1); + else + cc += PRIV(OP_lengths)[OP_CLASS]; +#else + cc += PRIV(OP_lengths)[OP_CLASS]; +#endif + + switch (*cc) + { + case OP_CRSTAR: + case OP_CRMINSTAR: + case OP_CRPLUS: + case OP_CRMINPLUS: + case OP_CRQUERY: + case OP_CRMINQUERY: + case OP_CRPOSSTAR: + case OP_CRPOSPLUS: + case OP_CRPOSQUERY: + goto ISNOTFIXED; + + case OP_CRRANGE: + case OP_CRMINRANGE: + case OP_CRPOSRANGE: + if (GET2(cc,1) != GET2(cc,1+IMM2_SIZE)) goto ISNOTFIXED; + branchlength += GET2(cc,1); + cc += 1 + 2 * IMM2_SIZE; + break; + + default: + branchlength++; + } + break; + + /* Anything else is variable length */ + + case OP_ANYNL: + case OP_BRAMINZERO: + case OP_BRAPOS: + case OP_BRAPOSZERO: + case OP_BRAZERO: + case OP_CBRAPOS: + case OP_EXTUNI: + case OP_KETRMAX: + case OP_KETRMIN: + case OP_KETRPOS: + case OP_MINPLUS: + case OP_MINPLUSI: + case OP_MINQUERY: + case OP_MINQUERYI: + case OP_MINSTAR: + case OP_MINSTARI: + case OP_MINUPTO: + case OP_MINUPTOI: + case OP_NOTMINPLUS: + case OP_NOTMINPLUSI: + case OP_NOTMINQUERY: + case OP_NOTMINQUERYI: + case OP_NOTMINSTAR: + case OP_NOTMINSTARI: + case OP_NOTMINUPTO: + case OP_NOTMINUPTOI: + case OP_NOTPLUS: + case OP_NOTPLUSI: + case OP_NOTPOSPLUS: + case OP_NOTPOSPLUSI: + case OP_NOTPOSQUERY: + case OP_NOTPOSQUERYI: + case OP_NOTPOSSTAR: + case OP_NOTPOSSTARI: + case OP_NOTPOSUPTO: + case OP_NOTPOSUPTOI: + case OP_NOTQUERY: + case OP_NOTQUERYI: + case OP_NOTSTAR: + case OP_NOTSTARI: + case OP_NOTUPTO: + case OP_NOTUPTOI: + case OP_PLUS: + case OP_PLUSI: + case OP_POSPLUS: + case OP_POSPLUSI: + case OP_POSQUERY: + case OP_POSQUERYI: + case OP_POSSTAR: + case OP_POSSTARI: + case OP_POSUPTO: + case OP_POSUPTOI: + case OP_QUERY: + case OP_QUERYI: + case OP_REF: + case OP_REFI: + case OP_DNREF: + case OP_DNREFI: + case OP_SBRA: + case OP_SBRAPOS: + case OP_SCBRA: + case OP_SCBRAPOS: + case OP_SCOND: + case OP_SKIPZERO: + case OP_STAR: + case OP_STARI: + case OP_TYPEMINPLUS: + case OP_TYPEMINQUERY: + case OP_TYPEMINSTAR: + case OP_TYPEMINUPTO: + case OP_TYPEPLUS: + case OP_TYPEPOSPLUS: + case OP_TYPEPOSQUERY: + case OP_TYPEPOSSTAR: + case OP_TYPEPOSUPTO: + case OP_TYPEQUERY: + case OP_TYPESTAR: + case OP_TYPEUPTO: + case OP_UPTO: + case OP_UPTOI: + goto ISNOTFIXED; + + /* Catch unrecognized opcodes so that when new ones are added they + are not forgotten, as has happened in the past. */ + + default: + return FFL_UNKNOWNOP; + } + } +/* Control never gets here except by goto. */ + +ISNOTFIXED: +if (group > 0) + { + groupinfo |= GI_NOT_FIXED_LENGTH; + cb->groupinfo[group] = groupinfo; + } +return FFL_NOTFIXED; +} + + + +/************************************************* +* Find first significant op code * +*************************************************/ + +/* This is called by several functions that scan a compiled expression looking +for a fixed first character, or an anchoring op code etc. It skips over things +that do not influence this. For some calls, it makes sense to skip negative +forward and all backward assertions, and also the \b assertion; for others it +does not. + +Arguments: + code pointer to the start of the group + skipassert TRUE if certain assertions are to be skipped + +Returns: pointer to the first significant opcode +*/ + +static const PCRE2_UCHAR* +first_significant_code(PCRE2_SPTR code, BOOL skipassert) +{ +for (;;) + { + switch ((int)*code) + { + case OP_ASSERT_NOT: + case OP_ASSERTBACK: + case OP_ASSERTBACK_NOT: + if (!skipassert) return code; + do code += GET(code, 1); while (*code == OP_ALT); + code += PRIV(OP_lengths)[*code]; + break; + + case OP_WORD_BOUNDARY: + case OP_NOT_WORD_BOUNDARY: + if (!skipassert) return code; + /* Fall through */ + + case OP_CALLOUT: + case OP_CREF: + case OP_DNCREF: + case OP_RREF: + case OP_DNRREF: + case OP_FALSE: + case OP_TRUE: + code += PRIV(OP_lengths)[*code]; + break; + + case OP_CALLOUT_STR: + code += GET(code, 1 + 2*LINK_SIZE); + break; + + default: + return code; + } + } +/* Control never reaches here */ +} + + + +/************************************************* +* Scan compiled branch for non-emptiness * +*************************************************/ + +/* This function scans through a branch of a compiled pattern to see whether it +can match the empty string. It is called at the end of compiling to check the +entire pattern, and from compile_branch() when checking for an unlimited repeat +of a group that can match nothing. In the latter case it is called only when +doing the real compile, not during the pre-compile that measures the size of +the compiled pattern. + +Note that first_significant_code() skips over backward and negative forward +assertions when its final argument is TRUE. If we hit an unclosed bracket, we +return "empty" - this means we've struck an inner bracket whose current branch +will already have been scanned. + +Arguments: + code points to start of search + endcode points to where to stop + utf TRUE if in UTF mode + cb compile data + atend TRUE if being called to check an entire pattern + recurses chain of recurse_check to catch mutual recursion + countptr pointer to count to catch over-complicated pattern + +Returns: 0 if what is matched cannot be empty + 1 if what is matched could be empty + -1 if the pattern is too complicated +*/ + +#define CBE_NOTEMPTY 0 +#define CBE_EMPTY 1 +#define CBE_TOOCOMPLICATED (-1) + + +static int +could_be_empty_branch(PCRE2_SPTR code, PCRE2_SPTR endcode, BOOL utf, + compile_block *cb, BOOL atend, recurse_check *recurses, int *countptr) +{ +uint32_t group = 0; +uint32_t groupinfo = 0; +register PCRE2_UCHAR c; +recurse_check this_recurse; + +/* If what we are checking has already been set as "could be empty", we know +the answer. */ + +if (*code >= OP_SBRA && *code <= OP_SCOND) return CBE_EMPTY; + +/* If this is a capturing group, we may have the answer cached, but we can only +use this information if there are no (?| groups in the pattern, because +otherwise group numbers are not unique. */ + +if ((cb->external_flags & PCRE2_DUPCAPUSED) == 0 && + (*code == OP_CBRA || *code == OP_CBRAPOS)) + { + group = GET2(code, 1 + LINK_SIZE); + groupinfo = cb->groupinfo[group]; + if ((groupinfo & GI_SET_COULD_BE_EMPTY) != 0) + return ((groupinfo & GI_COULD_BE_EMPTY) != 0)? CBE_EMPTY : CBE_NOTEMPTY; + } + +/* A large and/or complex regex can take too long to process. We have to assume +it can match an empty string. This can happen more often when (?| groups are +present in the pattern and the caching is disabled. Setting the cap at 1100 +allows the test for more than 1023 capturing patterns to work. */ + +if ((*countptr)++ > 1100) return CBE_TOOCOMPLICATED; + +/* Scan the opcodes for this branch. */ + +for (code = first_significant_code(code + PRIV(OP_lengths)[*code], TRUE); + code < endcode; + code = first_significant_code(code + PRIV(OP_lengths)[c], TRUE)) + { + PCRE2_SPTR ccode; + + c = *code; + + /* Skip over forward assertions; the other assertions are skipped by + first_significant_code() with a TRUE final argument. */ + + if (c == OP_ASSERT) + { + do code += GET(code, 1); while (*code == OP_ALT); + c = *code; + continue; + } + + /* For a recursion/subroutine call we can scan the recursion when this + function is called at the end, to check a complete pattern. Before then, + recursions just have the group number as their argument and in any case may + be forward references. In that situation, we return CBE_EMPTY, just in case. + It means that unlimited repeats of groups that contain recursions are always + treated as "could be empty" - which just adds a bit more processing time + because of the runtime check. */ + + if (c == OP_RECURSE) + { + PCRE2_SPTR scode, endgroup; + BOOL empty_branch; + + if (!atend) goto ISTRUE; + scode = cb->start_code + GET(code, 1); + endgroup = scode; + + /* We need to detect whether this is a recursive call, as otherwise there + will be an infinite loop. If it is a recursion, just skip over it. Simple + recursions are easily detected. For mutual recursions we keep a chain on + the stack. */ + + do endgroup += GET(endgroup, 1); while (*endgroup == OP_ALT); + if (code >= scode && code <= endgroup) continue; /* Simple recursion */ + else + { + recurse_check *r = recurses; + for (r = recurses; r != NULL; r = r->prev) + if (r->group == scode) break; + if (r != NULL) continue; /* Mutual recursion */ + } + + /* Scan the referenced group, remembering it on the stack chain to detect + mutual recursions. */ + + empty_branch = FALSE; + this_recurse.prev = recurses; + this_recurse.group = scode; + + do + { + int rc = could_be_empty_branch(scode, endcode, utf, cb, atend, + &this_recurse, countptr); + if (rc < 0) return rc; + if (rc > 0) + { + empty_branch = TRUE; + break; + } + scode += GET(scode, 1); + } + while (*scode == OP_ALT); + + if (!empty_branch) goto ISFALSE; /* All branches are non-empty */ + continue; + } + + /* Groups with zero repeats can of course be empty; skip them. */ + + if (c == OP_BRAZERO || c == OP_BRAMINZERO || c == OP_SKIPZERO || + c == OP_BRAPOSZERO) + { + code += PRIV(OP_lengths)[c]; + do code += GET(code, 1); while (*code == OP_ALT); + c = *code; + continue; + } + + /* A nested group that is already marked as "could be empty" can just be + skipped. */ + + if (c == OP_SBRA || c == OP_SBRAPOS || + c == OP_SCBRA || c == OP_SCBRAPOS) + { + do code += GET(code, 1); while (*code == OP_ALT); + c = *code; + continue; + } + + /* For other groups, scan the branches. */ + + if (c == OP_BRA || c == OP_BRAPOS || + c == OP_CBRA || c == OP_CBRAPOS || + c == OP_ONCE || c == OP_ONCE_NC || + c == OP_COND || c == OP_SCOND) + { + BOOL empty_branch; + if (GET(code, 1) == 0) goto ISTRUE; /* Hit unclosed bracket */ + + /* If a conditional group has only one branch, there is a second, implied, + empty branch, so just skip over the conditional, because it could be empty. + Otherwise, scan the individual branches of the group. */ + + if (c == OP_COND && code[GET(code, 1)] != OP_ALT) + code += GET(code, 1); + else + { + empty_branch = FALSE; + do + { + if (!empty_branch) + { + int rc = could_be_empty_branch(code, endcode, utf, cb, atend, + recurses, countptr); + if (rc < 0) return rc; + if (rc > 0) empty_branch = TRUE; + } + code += GET(code, 1); + } + while (*code == OP_ALT); + if (!empty_branch) goto ISFALSE; /* All branches are non-empty */ + } + + c = *code; + continue; + } + + /* Handle the other opcodes */ + + switch (c) + { + /* Check for quantifiers after a class. XCLASS is used for classes that + cannot be represented just by a bit map. This includes negated single + high-valued characters. The length in PRIV(OP_lengths)[] is zero; the + actual length is stored in the compiled code, so we must update "code" + here. */ + +#if defined SUPPORT_UNICODE || PCRE2_CODE_UNIT_WIDTH != 8 + case OP_XCLASS: + ccode = code += GET(code, 1); + goto CHECK_CLASS_REPEAT; +#endif + + case OP_CLASS: + case OP_NCLASS: + ccode = code + PRIV(OP_lengths)[OP_CLASS]; + +#if defined SUPPORT_UNICODE || PCRE2_CODE_UNIT_WIDTH != 8 + CHECK_CLASS_REPEAT: +#endif + + switch (*ccode) + { + case OP_CRSTAR: /* These could be empty; continue */ + case OP_CRMINSTAR: + case OP_CRQUERY: + case OP_CRMINQUERY: + case OP_CRPOSSTAR: + case OP_CRPOSQUERY: + break; + + default: /* Non-repeat => class must match */ + case OP_CRPLUS: /* These repeats aren't empty */ + case OP_CRMINPLUS: + case OP_CRPOSPLUS: + goto ISFALSE; + + case OP_CRRANGE: + case OP_CRMINRANGE: + case OP_CRPOSRANGE: + if (GET2(ccode, 1) > 0) goto ISFALSE; /* Minimum > 0 */ + break; + } + break; + + /* Opcodes that must match a character */ + + case OP_ANY: + case OP_ALLANY: + case OP_ANYBYTE: + + case OP_PROP: + case OP_NOTPROP: + case OP_ANYNL: + + case OP_NOT_HSPACE: + case OP_HSPACE: + case OP_NOT_VSPACE: + case OP_VSPACE: + case OP_EXTUNI: + + case OP_NOT_DIGIT: + case OP_DIGIT: + case OP_NOT_WHITESPACE: + case OP_WHITESPACE: + case OP_NOT_WORDCHAR: + case OP_WORDCHAR: + + case OP_CHAR: + case OP_CHARI: + case OP_NOT: + case OP_NOTI: + + case OP_PLUS: + case OP_PLUSI: + case OP_MINPLUS: + case OP_MINPLUSI: + + case OP_NOTPLUS: + case OP_NOTPLUSI: + case OP_NOTMINPLUS: + case OP_NOTMINPLUSI: + + case OP_POSPLUS: + case OP_POSPLUSI: + case OP_NOTPOSPLUS: + case OP_NOTPOSPLUSI: + + case OP_EXACT: + case OP_EXACTI: + case OP_NOTEXACT: + case OP_NOTEXACTI: + + case OP_TYPEPLUS: + case OP_TYPEMINPLUS: + case OP_TYPEPOSPLUS: + case OP_TYPEEXACT: + goto ISFALSE; + + /* These are going to continue, as they may be empty, but we have to + fudge the length for the \p and \P cases. */ + + case OP_TYPESTAR: + case OP_TYPEMINSTAR: + case OP_TYPEPOSSTAR: + case OP_TYPEQUERY: + case OP_TYPEMINQUERY: + case OP_TYPEPOSQUERY: + if (code[1] == OP_PROP || code[1] == OP_NOTPROP) code += 2; + break; + + /* Same for these */ + + case OP_TYPEUPTO: + case OP_TYPEMINUPTO: + case OP_TYPEPOSUPTO: + if (code[1 + IMM2_SIZE] == OP_PROP || code[1 + IMM2_SIZE] == OP_NOTPROP) + code += 2; + break; + + /* End of branch */ + + case OP_KET: + case OP_KETRMAX: + case OP_KETRMIN: + case OP_KETRPOS: + case OP_ALT: + goto ISTRUE; + + /* In UTF-8 or UTF-16 mode, STAR, MINSTAR, POSSTAR, QUERY, MINQUERY, + POSQUERY, UPTO, MINUPTO, and POSUPTO and their caseless and negative + versions may be followed by a multibyte character. */ + +#ifdef MAYBE_UTF_MULTI + case OP_STAR: + case OP_STARI: + case OP_NOTSTAR: + case OP_NOTSTARI: + + case OP_MINSTAR: + case OP_MINSTARI: + case OP_NOTMINSTAR: + case OP_NOTMINSTARI: + + case OP_POSSTAR: + case OP_POSSTARI: + case OP_NOTPOSSTAR: + case OP_NOTPOSSTARI: + + case OP_QUERY: + case OP_QUERYI: + case OP_NOTQUERY: + case OP_NOTQUERYI: + + case OP_MINQUERY: + case OP_MINQUERYI: + case OP_NOTMINQUERY: + case OP_NOTMINQUERYI: + + case OP_POSQUERY: + case OP_POSQUERYI: + case OP_NOTPOSQUERY: + case OP_NOTPOSQUERYI: + if (utf && HAS_EXTRALEN(code[1])) code += GET_EXTRALEN(code[1]); + break; + + case OP_UPTO: + case OP_UPTOI: + case OP_NOTUPTO: + case OP_NOTUPTOI: + + case OP_MINUPTO: + case OP_MINUPTOI: + case OP_NOTMINUPTO: + case OP_NOTMINUPTOI: + + case OP_POSUPTO: + case OP_POSUPTOI: + case OP_NOTPOSUPTO: + case OP_NOTPOSUPTOI: + if (utf && HAS_EXTRALEN(code[1 + IMM2_SIZE])) code += GET_EXTRALEN(code[1 + IMM2_SIZE]); + break; +#endif /* MAYBE_UTF_MULTI */ + + /* MARK, and PRUNE/SKIP/THEN with an argument must skip over the argument + string. */ + + case OP_MARK: + case OP_PRUNE_ARG: + case OP_SKIP_ARG: + case OP_THEN_ARG: + code += code[1]; + break; + + /* None of the remaining opcodes are required to match a character. */ + + default: + break; + } + } + +ISTRUE: +groupinfo |= GI_COULD_BE_EMPTY; + +ISFALSE: +if (group > 0) cb->groupinfo[group] = groupinfo | GI_SET_COULD_BE_EMPTY; + +return ((groupinfo & GI_COULD_BE_EMPTY) != 0)? CBE_EMPTY : CBE_NOTEMPTY; +} + + + +/************************************************* +* Check for counted repeat * +*************************************************/ + +/* This function is called when a '{' is encountered in a place where it might +start a quantifier. It looks ahead to see if it really is a quantifier, that +is, one of the forms {ddd} {ddd,} or {ddd,ddd} where the ddds are digits. + +Argument: pointer to the first char after '{' +Returns: TRUE or FALSE +*/ + +static BOOL +is_counted_repeat(PCRE2_SPTR p) +{ +if (!IS_DIGIT(*p)) return FALSE; +p++; +while (IS_DIGIT(*p)) p++; +if (*p == CHAR_RIGHT_CURLY_BRACKET) return TRUE; + +if (*p++ != CHAR_COMMA) return FALSE; +if (*p == CHAR_RIGHT_CURLY_BRACKET) return TRUE; + +if (!IS_DIGIT(*p)) return FALSE; +p++; +while (IS_DIGIT(*p)) p++; + +return (*p == CHAR_RIGHT_CURLY_BRACKET); +} + + + +/************************************************* +* Handle escapes * +*************************************************/ + +/* This function is called when a \ has been encountered. It either returns a +positive value for a simple escape such as \d, or 0 for a data character, which +is placed in chptr. A backreference to group n is returned as negative n. On +entry, ptr is pointing at the \. On exit, it points the final code unit of the +escape sequence. + +This function is also called from pcre2_substitute() to handle escape sequences +in replacement strings. In this case, the cb argument is NULL, and only +sequences that define a data character are recognised. The isclass argument is +not relevant, but the options argument is the final value of the compiled +pattern's options. + +There is one "trick" case: when a sequence such as [[:>:]] or \s in UCP mode is +processed, it is replaced by a nested alternative sequence. If this contains a +backslash (which is usually does), ptrend does not point to its end - it still +points to the end of the whole pattern. However, we can detect this case +because cb->nestptr[0] will be non-NULL. The nested sequences are all zero- +terminated and there are only ever two levels of nesting. + +Arguments: + ptrptr points to the input position pointer + ptrend points to the end of the input + chptr points to a returned data character + errorcodeptr points to the errorcode variable (containing zero) + options the current options bits + isclass TRUE if inside a character class + cb compile data block + +Returns: zero => a data character + positive => a special escape sequence + negative => a back reference + on error, errorcodeptr is set non-zero +*/ + +int +PRIV(check_escape)(PCRE2_SPTR *ptrptr, PCRE2_SPTR ptrend, uint32_t *chptr, + int *errorcodeptr, uint32_t options, BOOL isclass, compile_block *cb) +{ +BOOL utf = (options & PCRE2_UTF) != 0; +PCRE2_SPTR ptr = *ptrptr + 1; +register uint32_t c, cc; +int escape = 0; +int i; + +/* Find the end of a nested insert. */ + +if (cb != NULL && cb->nestptr[0] != NULL) + ptrend = ptr + PRIV(strlen)(ptr); + +/* If backslash is at the end of the string, it's an error. */ + +if (ptr >= ptrend) + { + *errorcodeptr = ERR1; + return 0; + } + +GETCHARINCTEST(c, ptr); /* Get character value, increment pointer */ +ptr--; /* Set pointer back to the last code unit */ + +/* Non-alphanumerics are literals, so we just leave the value in c. An initial +value test saves a memory lookup for code points outside the alphanumeric +range. Otherwise, do a table lookup. A non-zero result is something that can be +returned immediately. Otherwise further processing is required. */ + +if (c < ESCAPES_FIRST || c > ESCAPES_LAST) {} /* Definitely literal */ + +else if ((i = escapes[c - ESCAPES_FIRST]) != 0) + { + if (i > 0) c = (uint32_t)i; else /* Positive is a data character */ + { + escape = -i; /* Else return a special escape */ + if (escape == ESC_P || escape == ESC_p || escape == ESC_X) + cb->external_flags |= PCRE2_HASBKPORX; /* Note \P, \p, or \X */ + } + } + +/* Escapes that need further processing, including those that are unknown. +When called from pcre2_substitute(), only \c, \o, and \x are recognized (and \u +when BSUX is set). */ + +else + { + PCRE2_SPTR oldptr; + BOOL braced, negated, overflow; + unsigned int s; + + /* Filter calls from pcre2_substitute(). */ + + if (cb == NULL && c != CHAR_c && c != CHAR_o && c != CHAR_x && + (c != CHAR_u || (options & PCRE2_ALT_BSUX) != 0)) + { + *errorcodeptr = ERR3; + return 0; + } + + switch (c) + { + /* A number of Perl escapes are not handled by PCRE. We give an explicit + error. */ + + case CHAR_l: + case CHAR_L: + *errorcodeptr = ERR37; + break; + + /* \u is unrecognized when PCRE2_ALT_BSUX is not set. When it is treated + specially, \u must be followed by four hex digits. Otherwise it is a + lowercase u letter. */ + + case CHAR_u: + if ((options & PCRE2_ALT_BSUX) == 0) *errorcodeptr = ERR37; else + { + uint32_t xc; + if ((cc = XDIGIT(ptr[1])) == 0xff) break; /* Not a hex digit */ + if ((xc = XDIGIT(ptr[2])) == 0xff) break; /* Not a hex digit */ + cc = (cc << 4) | xc; + if ((xc = XDIGIT(ptr[3])) == 0xff) break; /* Not a hex digit */ + cc = (cc << 4) | xc; + if ((xc = XDIGIT(ptr[4])) == 0xff) break; /* Not a hex digit */ + c = (cc << 4) | xc; + ptr += 4; + if (utf) + { + if (c > 0x10ffffU) *errorcodeptr = ERR77; + else if (c >= 0xd800 && c <= 0xdfff) *errorcodeptr = ERR73; + } + else if (c > MAX_NON_UTF_CHAR) *errorcodeptr = ERR77; + } + break; + + case CHAR_U: + /* \U is unrecognized unless PCRE2_ALT_BSUX is set, in which case it is an + upper case letter. */ + if ((options & PCRE2_ALT_BSUX) == 0) *errorcodeptr = ERR37; + break; + + /* In a character class, \g is just a literal "g". Outside a character + class, \g must be followed by one of a number of specific things: + + (1) A number, either plain or braced. If positive, it is an absolute + backreference. If negative, it is a relative backreference. This is a Perl + 5.10 feature. + + (2) Perl 5.10 also supports \g{name} as a reference to a named group. This + is part of Perl's movement towards a unified syntax for back references. As + this is synonymous with \k{name}, we fudge it up by pretending it really + was \k. + + (3) For Oniguruma compatibility we also support \g followed by a name or a + number either in angle brackets or in single quotes. However, these are + (possibly recursive) subroutine calls, _not_ backreferences. Just return + the ESC_g code (cf \k). */ + + case CHAR_g: + if (isclass) break; + if (ptr[1] == CHAR_LESS_THAN_SIGN || ptr[1] == CHAR_APOSTROPHE) + { + escape = ESC_g; + break; + } + + /* Handle the Perl-compatible cases */ + + if (ptr[1] == CHAR_LEFT_CURLY_BRACKET) + { + PCRE2_SPTR p; + for (p = ptr+2; *p != CHAR_NULL && *p != CHAR_RIGHT_CURLY_BRACKET; p++) + if (*p != CHAR_MINUS && !IS_DIGIT(*p)) break; + if (*p != CHAR_NULL && *p != CHAR_RIGHT_CURLY_BRACKET) + { + escape = ESC_k; + break; + } + braced = TRUE; + ptr++; + } + else braced = FALSE; + + if (ptr[1] == CHAR_MINUS) + { + negated = TRUE; + ptr++; + } + else negated = FALSE; + + /* The integer range is limited by the machine's int representation. */ + s = 0; + overflow = FALSE; + while (IS_DIGIT(ptr[1])) + { + if (s > INT_MAX / 10 - 1) /* Integer overflow */ + { + overflow = TRUE; + break; + } + s = s * 10 + (unsigned int)(*(++ptr) - CHAR_0); + } + if (overflow) /* Integer overflow */ + { + while (IS_DIGIT(ptr[1])) ptr++; + *errorcodeptr = ERR61; + break; + } + + if (braced && *(++ptr) != CHAR_RIGHT_CURLY_BRACKET) + { + *errorcodeptr = ERR57; + break; + } + + if (s == 0) + { + *errorcodeptr = ERR58; + break; + } + + if (negated) + { + if (s > cb->bracount) + { + *errorcodeptr = ERR15; + break; + } + s = cb->bracount - (s - 1); + } + + escape = -(int)s; + break; + + /* The handling of escape sequences consisting of a string of digits + starting with one that is not zero is not straightforward. Perl has changed + over the years. Nowadays \g{} for backreferences and \o{} for octal are + recommended to avoid the ambiguities in the old syntax. + + Outside a character class, the digits are read as a decimal number. If the + number is less than 10, or if there are that many previous extracting left + brackets, it is a back reference. Otherwise, up to three octal digits are + read to form an escaped character code. Thus \123 is likely to be octal 123 + (cf \0123, which is octal 012 followed by the literal 3). + + Inside a character class, \ followed by a digit is always either a literal + 8 or 9 or an octal number. */ + + case CHAR_1: case CHAR_2: case CHAR_3: case CHAR_4: case CHAR_5: + case CHAR_6: case CHAR_7: case CHAR_8: case CHAR_9: + + if (!isclass) + { + oldptr = ptr; + /* The integer range is limited by the machine's int representation. */ + s = c - CHAR_0; + overflow = FALSE; + while (IS_DIGIT(ptr[1])) + { + if (s > INT_MAX / 10 - 1) /* Integer overflow */ + { + overflow = TRUE; + break; + } + s = s * 10 + (unsigned int)(*(++ptr) - CHAR_0); + } + if (overflow) /* Integer overflow */ + { + while (IS_DIGIT(ptr[1])) ptr++; + *errorcodeptr = ERR61; + break; + } + + /* \1 to \9 are always back references. \8x and \9x are too; \1x to \7x + are octal escapes if there are not that many previous captures. */ + + if (s < 10 || *oldptr >= CHAR_8 || s <= cb->bracount) + { + escape = -(int)s; /* Indicates a back reference */ + break; + } + ptr = oldptr; /* Put the pointer back and fall through */ + } + + /* Handle a digit following \ when the number is not a back reference, or + we are within a character class. If the first digit is 8 or 9, Perl used to + generate a binary zero byte and then treat the digit as a following + literal. At least by Perl 5.18 this changed so as not to insert the binary + zero. */ + + if ((c = *ptr) >= CHAR_8) break; + + /* Fall through with a digit less than 8 */ + + /* \0 always starts an octal number, but we may drop through to here with a + larger first octal digit. The original code used just to take the least + significant 8 bits of octal numbers (I think this is what early Perls used + to do). Nowadays we allow for larger numbers in UTF-8 mode and 16-bit mode, + but no more than 3 octal digits. */ + + case CHAR_0: + c -= CHAR_0; + while(i++ < 2 && ptr[1] >= CHAR_0 && ptr[1] <= CHAR_7) + c = c * 8 + *(++ptr) - CHAR_0; +#if PCRE2_CODE_UNIT_WIDTH == 8 + if (!utf && c > 0xff) *errorcodeptr = ERR51; +#endif + break; + + /* \o is a relatively new Perl feature, supporting a more general way of + specifying character codes in octal. The only supported form is \o{ddd}. */ + + case CHAR_o: + if (ptr[1] != CHAR_LEFT_CURLY_BRACKET) *errorcodeptr = ERR55; else + if (ptr[2] == CHAR_RIGHT_CURLY_BRACKET) *errorcodeptr = ERR78; else + { + ptr += 2; + c = 0; + overflow = FALSE; + while (*ptr >= CHAR_0 && *ptr <= CHAR_7) + { + cc = *ptr++; + if (c == 0 && cc == CHAR_0) continue; /* Leading zeroes */ +#if PCRE2_CODE_UNIT_WIDTH == 32 + if (c >= 0x20000000l) { overflow = TRUE; break; } +#endif + c = (c << 3) + (cc - CHAR_0); +#if PCRE2_CODE_UNIT_WIDTH == 8 + if (c > (utf ? 0x10ffffU : 0xffU)) { overflow = TRUE; break; } +#elif PCRE2_CODE_UNIT_WIDTH == 16 + if (c > (utf ? 0x10ffffU : 0xffffU)) { overflow = TRUE; break; } +#elif PCRE2_CODE_UNIT_WIDTH == 32 + if (utf && c > 0x10ffffU) { overflow = TRUE; break; } +#endif + } + if (overflow) + { + while (*ptr >= CHAR_0 && *ptr <= CHAR_7) ptr++; + *errorcodeptr = ERR34; + } + else if (*ptr == CHAR_RIGHT_CURLY_BRACKET) + { + if (utf && c >= 0xd800 && c <= 0xdfff) *errorcodeptr = ERR73; + } + else *errorcodeptr = ERR64; + } + break; + + /* \x is complicated. When PCRE2_ALT_BSUX is set, \x must be followed by + two hexadecimal digits. Otherwise it is a lowercase x letter. */ + + case CHAR_x: + if ((options & PCRE2_ALT_BSUX) != 0) + { + uint32_t xc; + if ((cc = XDIGIT(ptr[1])) == 0xff) break; /* Not a hex digit */ + if ((xc = XDIGIT(ptr[2])) == 0xff) break; /* Not a hex digit */ + c = (cc << 4) | xc; + ptr += 2; + } /* End PCRE2_ALT_BSUX handling */ + + /* Handle \x in Perl's style. \x{ddd} is a character number which can be + greater than 0xff in UTF-8 or non-8bit mode, but only if the ddd are hex + digits. If not, { used to be treated as a data character. However, Perl + seems to read hex digits up to the first non-such, and ignore the rest, so + that, for example \x{zz} matches a binary zero. This seems crazy, so PCRE + now gives an error. */ + + else + { + if (ptr[1] == CHAR_LEFT_CURLY_BRACKET) + { + ptr += 2; + if (*ptr == CHAR_RIGHT_CURLY_BRACKET) + { + *errorcodeptr = ERR78; + break; + } + c = 0; + overflow = FALSE; + + while ((cc = XDIGIT(*ptr)) != 0xff) + { + ptr++; + if (c == 0 && cc == 0) continue; /* Leading zeroes */ +#if PCRE2_CODE_UNIT_WIDTH == 32 + if (c >= 0x10000000l) { overflow = TRUE; break; } +#endif + c = (c << 4) | cc; + if ((utf && c > 0x10ffffU) || (!utf && c > MAX_NON_UTF_CHAR)) + { + overflow = TRUE; + break; + } + } + + if (overflow) + { + while (XDIGIT(*ptr) != 0xff) ptr++; + *errorcodeptr = ERR34; + } + else if (*ptr == CHAR_RIGHT_CURLY_BRACKET) + { + if (utf && c >= 0xd800 && c <= 0xdfff) *errorcodeptr = ERR73; + } + + /* If the sequence of hex digits does not end with '}', give an error. + We used just to recognize this construct and fall through to the normal + \x handling, but nowadays Perl gives an error, which seems much more + sensible, so we do too. */ + + else *errorcodeptr = ERR67; + } /* End of \x{} processing */ + + /* Read a single-byte hex-defined char (up to two hex digits after \x) */ + + else + { + c = 0; + if ((cc = XDIGIT(ptr[1])) == 0xff) break; /* Not a hex digit */ + ptr++; + c = cc; + if ((cc = XDIGIT(ptr[1])) == 0xff) break; /* Not a hex digit */ + ptr++; + c = (c << 4) | cc; + } /* End of \xdd handling */ + } /* End of Perl-style \x handling */ + break; + + /* The handling of \c is different in ASCII and EBCDIC environments. In an + ASCII (or Unicode) environment, an error is given if the character + following \c is not a printable ASCII character. Otherwise, the following + character is upper-cased if it is a letter, and after that the 0x40 bit is + flipped. The result is the value of the escape. + + In an EBCDIC environment the handling of \c is compatible with the + specification in the perlebcdic document. The following character must be + a letter or one of small number of special characters. These provide a + means of defining the character values 0-31. + + For testing the EBCDIC handling of \c in an ASCII environment, recognize + the EBCDIC value of 'c' explicitly. */ + +#if defined EBCDIC && 'a' != 0x81 + case 0x83: +#else + case CHAR_c: +#endif + + c = *(++ptr); + if (c >= CHAR_a && c <= CHAR_z) c = UPPER_CASE(c); + if (c == CHAR_NULL && ptr >= ptrend) + { + *errorcodeptr = ERR2; + break; + } + + /* Handle \c in an ASCII/Unicode environment. */ + +#ifndef EBCDIC /* ASCII/UTF-8 coding */ + if (c < 32 || c > 126) /* Excludes all non-printable ASCII */ + { + *errorcodeptr = ERR68; + break; + } + c ^= 0x40; + + /* Handle \c in an EBCDIC environment. The special case \c? is converted to + 255 (0xff) or 95 (0x5f) if other character suggest we are using th POSIX-BC + encoding. (This is the way Perl indicates that it handles \c?.) The other + valid sequences correspond to a list of specific characters. */ + +#else + if (c == CHAR_QUESTION_MARK) + c = ('\\' == 188 && '`' == 74)? 0x5f : 0xff; + else + { + for (i = 0; i < 32; i++) + { + if (c == ebcdic_escape_c[i]) break; + } + if (i < 32) c = i; else *errorcodeptr = ERR68; + } +#endif /* EBCDIC */ + + break; + + /* Any other alphanumeric following \ is an error. Perl gives an error only + if in warning mode, but PCRE doesn't have a warning mode. */ + + default: + *errorcodeptr = ERR3; + break; + } + } + +/* Perl supports \N{name} for character names, as well as plain \N for "not +newline". PCRE does not support \N{name}. However, it does support +quantification such as \N{2,3}. */ + +if (escape == ESC_N && ptr[1] == CHAR_LEFT_CURLY_BRACKET && + !is_counted_repeat(ptr+2)) + *errorcodeptr = ERR37; + +/* If PCRE2_UCP is set, we change the values for \d etc. */ + +if ((options & PCRE2_UCP) != 0 && escape >= ESC_D && escape <= ESC_w) + escape += (ESC_DU - ESC_D); + +/* Set the pointer to the final character before returning. */ + +*ptrptr = ptr; +*chptr = c; +return escape; +} + + + +#ifdef SUPPORT_UNICODE +/************************************************* +* Handle \P and \p * +*************************************************/ + +/* This function is called after \P or \p has been encountered, provided that +PCRE2 is compiled with support for UTF and Unicode properties. On entry, the +contents of ptrptr are pointing at the P or p. On exit, it is left pointing at +the final code unit of the escape sequence. + +Arguments: + ptrptr the pattern position pointer + negptr a boolean that is set TRUE for negation else FALSE + ptypeptr an unsigned int that is set to the type value + pdataptr an unsigned int that is set to the detailed property value + errorcodeptr the error code variable + cb the compile data + +Returns: TRUE if the type value was found, or FALSE for an invalid type +*/ + +static BOOL +get_ucp(PCRE2_SPTR *ptrptr, BOOL *negptr, unsigned int *ptypeptr, + unsigned int *pdataptr, int *errorcodeptr, compile_block *cb) +{ +register PCRE2_UCHAR c; +size_t i, bot, top; +PCRE2_SPTR ptr = *ptrptr; +PCRE2_UCHAR name[32]; + +*negptr = FALSE; +c = *(++ptr); + +/* \P or \p can be followed by a name in {}, optionally preceded by ^ for +negation. */ + +if (c == CHAR_LEFT_CURLY_BRACKET) + { + if (ptr[1] == CHAR_CIRCUMFLEX_ACCENT) + { + *negptr = TRUE; + ptr++; + } + for (i = 0; i < (int)(sizeof(name) / sizeof(PCRE2_UCHAR)) - 1; i++) + { + c = *(++ptr); + if (c == CHAR_NULL) goto ERROR_RETURN; + if (c == CHAR_RIGHT_CURLY_BRACKET) break; + name[i] = c; + } + if (c != CHAR_RIGHT_CURLY_BRACKET) goto ERROR_RETURN; + name[i] = 0; + } + +/* Otherwise there is just one following character, which must be an ASCII +letter. */ + +else if (MAX_255(c) && (cb->ctypes[c] & ctype_letter) != 0) + { + name[0] = c; + name[1] = 0; + } +else goto ERROR_RETURN; + +*ptrptr = ptr; + +/* Search for a recognized property name using binary chop. */ + +bot = 0; +top = PRIV(utt_size); + +while (bot < top) + { + int r; + i = (bot + top) >> 1; + r = PRIV(strcmp_c8)(name, PRIV(utt_names) + PRIV(utt)[i].name_offset); + if (r == 0) + { + *ptypeptr = PRIV(utt)[i].type; + *pdataptr = PRIV(utt)[i].value; + return TRUE; + } + if (r > 0) bot = i + 1; else top = i; + } +*errorcodeptr = ERR47; /* Unrecognized name */ +return FALSE; + +ERROR_RETURN: /* Malformed \P or \p */ +*errorcodeptr = ERR46; +*ptrptr = ptr; +return FALSE; +} +#endif + + + +/************************************************* +* Read repeat counts * +*************************************************/ + +/* Read an item of the form {n,m} and return the values. This is called only +after is_counted_repeat() has confirmed that a repeat-count quantifier exists, +so the syntax is guaranteed to be correct, but we need to check the values. + +Arguments: + p pointer to first char after '{' + minp pointer to int for min + maxp pointer to int for max + returned as -1 if no max + errorcodeptr points to error code variable + +Returns: pointer to '}' on success; + current ptr on error, with errorcodeptr set non-zero +*/ + +static PCRE2_SPTR +read_repeat_counts(PCRE2_SPTR p, int *minp, int *maxp, int *errorcodeptr) +{ +int min = 0; +int max = -1; + +while (IS_DIGIT(*p)) + { + min = min * 10 + (int)(*p++ - CHAR_0); + if (min > 65535) + { + *errorcodeptr = ERR5; + return p; + } + } + +if (*p == CHAR_RIGHT_CURLY_BRACKET) max = min; else + { + if (*(++p) != CHAR_RIGHT_CURLY_BRACKET) + { + max = 0; + while(IS_DIGIT(*p)) + { + max = max * 10 + (int)(*p++ - CHAR_0); + if (max > 65535) + { + *errorcodeptr = ERR5; + return p; + } + } + if (max < min) + { + *errorcodeptr = ERR4; + return p; + } + } + } + +*minp = min; +*maxp = max; +return p; +} + + + +/************************************************* +* Scan compiled regex for recursion reference * +*************************************************/ + +/* This function scans through a compiled pattern until it finds an instance of +OP_RECURSE. + +Arguments: + code points to start of expression + utf TRUE in UTF mode + +Returns: pointer to the opcode for OP_RECURSE, or NULL if not found +*/ + +static PCRE2_SPTR +find_recurse(PCRE2_SPTR code, BOOL utf) +{ +for (;;) + { + register PCRE2_UCHAR c = *code; + if (c == OP_END) return NULL; + if (c == OP_RECURSE) return code; + + /* XCLASS is used for classes that cannot be represented just by a bit map. + This includes negated single high-valued characters. CALLOUT_STR is used for + callouts with string arguments. In both cases the length in the table is + zero; the actual length is stored in the compiled code. */ + + if (c == OP_XCLASS) code += GET(code, 1); + else if (c == OP_CALLOUT_STR) code += GET(code, 1 + 2*LINK_SIZE); + + /* Otherwise, we can get the item's length from the table, except that for + repeated character types, we have to test for \p and \P, which have an extra + two bytes of parameters, and for MARK/PRUNE/SKIP/THEN with an argument, we + must add in its length. */ + + else + { + switch(c) + { + case OP_TYPESTAR: + case OP_TYPEMINSTAR: + case OP_TYPEPLUS: + case OP_TYPEMINPLUS: + case OP_TYPEQUERY: + case OP_TYPEMINQUERY: + case OP_TYPEPOSSTAR: + case OP_TYPEPOSPLUS: + case OP_TYPEPOSQUERY: + if (code[1] == OP_PROP || code[1] == OP_NOTPROP) code += 2; + break; + + case OP_TYPEPOSUPTO: + case OP_TYPEUPTO: + case OP_TYPEMINUPTO: + case OP_TYPEEXACT: + if (code[1 + IMM2_SIZE] == OP_PROP || code[1 + IMM2_SIZE] == OP_NOTPROP) + code += 2; + break; + + case OP_MARK: + case OP_PRUNE_ARG: + case OP_SKIP_ARG: + case OP_THEN_ARG: + code += code[1]; + break; + } + + /* Add in the fixed length from the table */ + + code += PRIV(OP_lengths)[c]; + + /* In UTF-8 and UTF-16 modes, opcodes that are followed by a character may + be followed by a multi-unit character. The length in the table is a + minimum, so we have to arrange to skip the extra units. */ + +#ifdef MAYBE_UTF_MULTI + if (utf) switch(c) + { + case OP_CHAR: + case OP_CHARI: + case OP_NOT: + case OP_NOTI: + case OP_EXACT: + case OP_EXACTI: + case OP_NOTEXACT: + case OP_NOTEXACTI: + case OP_UPTO: + case OP_UPTOI: + case OP_NOTUPTO: + case OP_NOTUPTOI: + case OP_MINUPTO: + case OP_MINUPTOI: + case OP_NOTMINUPTO: + case OP_NOTMINUPTOI: + case OP_POSUPTO: + case OP_POSUPTOI: + case OP_NOTPOSUPTO: + case OP_NOTPOSUPTOI: + case OP_STAR: + case OP_STARI: + case OP_NOTSTAR: + case OP_NOTSTARI: + case OP_MINSTAR: + case OP_MINSTARI: + case OP_NOTMINSTAR: + case OP_NOTMINSTARI: + case OP_POSSTAR: + case OP_POSSTARI: + case OP_NOTPOSSTAR: + case OP_NOTPOSSTARI: + case OP_PLUS: + case OP_PLUSI: + case OP_NOTPLUS: + case OP_NOTPLUSI: + case OP_MINPLUS: + case OP_MINPLUSI: + case OP_NOTMINPLUS: + case OP_NOTMINPLUSI: + case OP_POSPLUS: + case OP_POSPLUSI: + case OP_NOTPOSPLUS: + case OP_NOTPOSPLUSI: + case OP_QUERY: + case OP_QUERYI: + case OP_NOTQUERY: + case OP_NOTQUERYI: + case OP_MINQUERY: + case OP_MINQUERYI: + case OP_NOTMINQUERY: + case OP_NOTMINQUERYI: + case OP_POSQUERY: + case OP_POSQUERYI: + case OP_NOTPOSQUERY: + case OP_NOTPOSQUERYI: + if (HAS_EXTRALEN(code[-1])) code += GET_EXTRALEN(code[-1]); + break; + } +#else + (void)(utf); /* Keep compiler happy by referencing function argument */ +#endif /* MAYBE_UTF_MULTI */ + } + } +} + + + +/************************************************* +* Check for POSIX class syntax * +*************************************************/ + +/* This function is called when the sequence "[:" or "[." or "[=" is +encountered in a character class. It checks whether this is followed by a +sequence of characters terminated by a matching ":]" or ".]" or "=]". If we +reach an unescaped ']' without the special preceding character, return FALSE. + +Originally, this function only recognized a sequence of letters between the +terminators, but it seems that Perl recognizes any sequence of characters, +though of course unknown POSIX names are subsequently rejected. Perl gives an +"Unknown POSIX class" error for [:f\oo:] for example, where previously PCRE +didn't consider this to be a POSIX class. Likewise for [:1234:]. + +The problem in trying to be exactly like Perl is in the handling of escapes. We +have to be sure that [abc[:x\]pqr] is *not* treated as containing a POSIX +class, but [abc[:x\]pqr:]] is (so that an error can be generated). The code +below handles the special cases \\ and \], but does not try to do any other +escape processing. This makes it different from Perl for cases such as +[:l\ower:] where Perl recognizes it as the POSIX class "lower" but PCRE does +not recognize "l\ower". This is a lesser evil than not diagnosing bad classes +when Perl does, I think. + +A user pointed out that PCRE was rejecting [:a[:digit:]] whereas Perl was not. +It seems that the appearance of a nested POSIX class supersedes an apparent +external class. For example, [:a[:digit:]b:] matches "a", "b", ":", or +a digit. This is handled by returning FALSE if the start of a new group with +the same terminator is encountered, since the next closing sequence must close +the nested group, not the outer one. + +In Perl, unescaped square brackets may also appear as part of class names. For +example, [:a[:abc]b:] gives unknown POSIX class "[:abc]b:]". However, for +[:a[:abc]b][b:] it gives unknown POSIX class "[:abc]b][b:]", which does not +seem right at all. PCRE does not allow closing square brackets in POSIX class +names. + +Arguments: + ptr pointer to the initial [ + endptr where to return a pointer to the terminating ':', '.', or '=' + +Returns: TRUE or FALSE +*/ + +static BOOL +check_posix_syntax(PCRE2_SPTR ptr, PCRE2_SPTR *endptr) +{ +PCRE2_UCHAR terminator; /* Don't combine these lines; the Solaris cc */ +terminator = *(++ptr); /* compiler warns about "non-constant" initializer. */ + +for (++ptr; *ptr != CHAR_NULL; ptr++) + { + if (*ptr == CHAR_BACKSLASH && + (ptr[1] == CHAR_RIGHT_SQUARE_BRACKET || ptr[1] == CHAR_BACKSLASH)) + ptr++; + else if ((*ptr == CHAR_LEFT_SQUARE_BRACKET && ptr[1] == terminator) || + *ptr == CHAR_RIGHT_SQUARE_BRACKET) return FALSE; + else if (*ptr == terminator && ptr[1] == CHAR_RIGHT_SQUARE_BRACKET) + { + *endptr = ptr; + return TRUE; + } + } + +return FALSE; +} + + + +/************************************************* +* Check POSIX class name * +*************************************************/ + +/* This function is called to check the name given in a POSIX-style class entry +such as [:alnum:]. + +Arguments: + ptr points to the first letter + len the length of the name + +Returns: a value representing the name, or -1 if unknown +*/ + +static int +check_posix_name(PCRE2_SPTR ptr, int len) +{ +const char *pn = posix_names; +register int yield = 0; +while (posix_name_lengths[yield] != 0) + { + if (len == posix_name_lengths[yield] && + PRIV(strncmp_c8)(ptr, pn, (unsigned int)len) == 0) return yield; + pn += posix_name_lengths[yield] + 1; + yield++; + } +return -1; +} + + + +#ifdef SUPPORT_UNICODE +/************************************************* +* Get othercase range * +*************************************************/ + +/* This function is passed the start and end of a class range in UCT mode. It +searches up the characters, looking for ranges of characters in the "other" +case. Each call returns the next one, updating the start address. A character +with multiple other cases is returned on its own with a special return value. + +Arguments: + cptr points to starting character value; updated + d end value + ocptr where to put start of othercase range + odptr where to put end of othercase range + +Yield: -1 when no more + 0 when a range is returned + >0 the CASESET offset for char with multiple other cases + in this case, ocptr contains the original +*/ + +static int +get_othercase_range(uint32_t *cptr, uint32_t d, uint32_t *ocptr, + uint32_t *odptr) +{ +uint32_t c, othercase, next; +unsigned int co; + +/* Find the first character that has an other case. If it has multiple other +cases, return its case offset value. */ + +for (c = *cptr; c <= d; c++) + { + if ((co = UCD_CASESET(c)) != 0) + { + *ocptr = c++; /* Character that has the set */ + *cptr = c; /* Rest of input range */ + return (int)co; + } + if ((othercase = UCD_OTHERCASE(c)) != c) break; + } + +if (c > d) return -1; /* Reached end of range */ + +/* Found a character that has a single other case. Search for the end of the +range, which is either the end of the input range, or a character that has zero +or more than one other cases. */ + +*ocptr = othercase; +next = othercase + 1; + +for (++c; c <= d; c++) + { + if ((co = UCD_CASESET(c)) != 0 || UCD_OTHERCASE(c) != next) break; + next++; + } + +*odptr = next - 1; /* End of othercase range */ +*cptr = c; /* Rest of input range */ +return 0; +} +#endif /* SUPPORT_UNICODE */ + + + +/************************************************* +* Add a character or range to a class * +*************************************************/ + +/* This function packages up the logic of adding a character or range of +characters to a class. The character values in the arguments will be within the +valid values for the current mode (8-bit, 16-bit, UTF, etc). This function is +mutually recursive with the function immediately below. + +Arguments: + classbits the bit map for characters < 256 + uchardptr points to the pointer for extra data + options the options word + cb compile data + start start of range character + end end of range character + +Returns: the number of < 256 characters added + the pointer to extra data is updated +*/ + +static unsigned int +add_to_class(uint8_t *classbits, PCRE2_UCHAR **uchardptr, uint32_t options, + compile_block *cb, uint32_t start, uint32_t end) +{ +uint32_t c; +uint32_t classbits_end = (end <= 0xff ? end : 0xff); +unsigned int n8 = 0; + +/* If caseless matching is required, scan the range and process alternate +cases. In Unicode, there are 8-bit characters that have alternate cases that +are greater than 255 and vice-versa. Sometimes we can just extend the original +range. */ + +if ((options & PCRE2_CASELESS) != 0) + { +#ifdef SUPPORT_UNICODE + if ((options & PCRE2_UTF) != 0) + { + int rc; + uint32_t oc, od; + + options &= ~PCRE2_CASELESS; /* Remove for recursive calls */ + c = start; + + while ((rc = get_othercase_range(&c, end, &oc, &od)) >= 0) + { + /* Handle a single character that has more than one other case. */ + + if (rc > 0) n8 += add_list_to_class(classbits, uchardptr, options, cb, + PRIV(ucd_caseless_sets) + rc, oc); + + /* Do nothing if the other case range is within the original range. */ + + else if (oc >= start && od <= end) continue; + + /* Extend the original range if there is overlap, noting that if oc < c, we + can't have od > end because a subrange is always shorter than the basic + range. Otherwise, use a recursive call to add the additional range. */ + + else if (oc < start && od >= start - 1) start = oc; /* Extend downwards */ + else if (od > end && oc <= end + 1) + { + end = od; /* Extend upwards */ + if (end > classbits_end) classbits_end = (end <= 0xff ? end : 0xff); + } + else n8 += add_to_class(classbits, uchardptr, options, cb, oc, od); + } + } + else +#endif /* SUPPORT_UNICODE */ + + /* Not UTF mode */ + + for (c = start; c <= classbits_end; c++) + { + SETBIT(classbits, cb->fcc[c]); + n8++; + } + } + +/* Now handle the original range. Adjust the final value according to the bit +length - this means that the same lists of (e.g.) horizontal spaces can be used +in all cases. */ + +if ((options & PCRE2_UTF) == 0 && end > MAX_NON_UTF_CHAR) + end = MAX_NON_UTF_CHAR; + +/* Use the bitmap for characters < 256. Otherwise use extra data.*/ + +for (c = start; c <= classbits_end; c++) + { + /* Regardless of start, c will always be <= 255. */ + SETBIT(classbits, c); + n8++; + } + +#ifdef SUPPORT_WIDE_CHARS +if (start <= 0xff) start = 0xff + 1; + +if (end >= start) + { + PCRE2_UCHAR *uchardata = *uchardptr; + +#ifdef SUPPORT_UNICODE + if ((options & PCRE2_UTF) != 0) + { + if (start < end) + { + *uchardata++ = XCL_RANGE; + uchardata += PRIV(ord2utf)(start, uchardata); + uchardata += PRIV(ord2utf)(end, uchardata); + } + else if (start == end) + { + *uchardata++ = XCL_SINGLE; + uchardata += PRIV(ord2utf)(start, uchardata); + } + } + else +#endif /* SUPPORT_UNICODE */ + + /* Without UTF support, character values are constrained by the bit length, + and can only be > 256 for 16-bit and 32-bit libraries. */ + +#if PCRE2_CODE_UNIT_WIDTH == 8 + {} +#else + if (start < end) + { + *uchardata++ = XCL_RANGE; + *uchardata++ = start; + *uchardata++ = end; + } + else if (start == end) + { + *uchardata++ = XCL_SINGLE; + *uchardata++ = start; + } +#endif + *uchardptr = uchardata; /* Updata extra data pointer */ + } +#else + (void)uchardptr; /* Avoid compiler warning */ +#endif /* SUPPORT_WIDE_CHARS */ + +return n8; /* Number of 8-bit characters */ +} + + + +/************************************************* +* Add a list of characters to a class * +*************************************************/ + +/* This function is used for adding a list of case-equivalent characters to a +class, and also for adding a list of horizontal or vertical whitespace. If the +list is in order (which it should be), ranges of characters are detected and +handled appropriately. This function is mutually recursive with the function +above. + +Arguments: + classbits the bit map for characters < 256 + uchardptr points to the pointer for extra data + options the options word + cb contains pointers to tables etc. + p points to row of 32-bit values, terminated by NOTACHAR + except character to omit; this is used when adding lists of + case-equivalent characters to avoid including the one we + already know about + +Returns: the number of < 256 characters added + the pointer to extra data is updated +*/ + +static unsigned int +add_list_to_class(uint8_t *classbits, PCRE2_UCHAR **uchardptr, uint32_t options, + compile_block *cb, const uint32_t *p, unsigned int except) +{ +unsigned int n8 = 0; +while (p[0] < NOTACHAR) + { + unsigned int n = 0; + if (p[0] != except) + { + while(p[n+1] == p[0] + n + 1) n++; + n8 += add_to_class(classbits, uchardptr, options, cb, p[0], p[n]); + } + p += n + 1; + } +return n8; +} + + + +/************************************************* +* Add characters not in a list to a class * +*************************************************/ + +/* This function is used for adding the complement of a list of horizontal or +vertical whitespace to a class. The list must be in order. + +Arguments: + classbits the bit map for characters < 256 + uchardptr points to the pointer for extra data + options the options word + cb contains pointers to tables etc. + p points to row of 32-bit values, terminated by NOTACHAR + +Returns: the number of < 256 characters added + the pointer to extra data is updated +*/ + +static unsigned int +add_not_list_to_class(uint8_t *classbits, PCRE2_UCHAR **uchardptr, + uint32_t options, compile_block *cb, const uint32_t *p) +{ +BOOL utf = (options & PCRE2_UTF) != 0; +unsigned int n8 = 0; +if (p[0] > 0) + n8 += add_to_class(classbits, uchardptr, options, cb, 0, p[0] - 1); +while (p[0] < NOTACHAR) + { + while (p[1] == p[0] + 1) p++; + n8 += add_to_class(classbits, uchardptr, options, cb, p[0] + 1, + (p[1] == NOTACHAR) ? (utf ? 0x10ffffu : 0xffffffffu) : p[1] - 1); + p++; + } +return n8; +} + + + +/************************************************* +* Process (*VERB) name for escapes * +*************************************************/ + +/* This function is called when the PCRE2_ALT_VERBNAMES option is set, to +process the characters in a verb's name argument. It is called twice, once with +codeptr == NULL, to find out the length of the processed name, and again to put +the name into memory. + +Arguments: + ptrptr pointer to the input pointer + codeptr pointer to the compiled code pointer + errorcodeptr pointer to the error code + options the options bits + utf TRUE if processing UTF + cb compile data block + +Returns: length of the processed name, or < 0 on error +*/ + +static int +process_verb_name(PCRE2_SPTR *ptrptr, PCRE2_UCHAR **codeptr, int *errorcodeptr, + uint32_t options, BOOL utf, compile_block *cb) +{ +int32_t arglen = 0; +BOOL inescq = FALSE; +PCRE2_SPTR ptr = *ptrptr; +PCRE2_UCHAR *code = (codeptr == NULL)? NULL : *codeptr; + +for (; ptr < cb->end_pattern; ptr++) + { + uint32_t x = *ptr; + + /* Skip over literals */ + + if (inescq) + { + if (x == CHAR_BACKSLASH && ptr[1] == CHAR_E) + { + inescq = FALSE; + ptr++;; + continue; + } + } + + else /* Not a literal character */ + { + if (x == CHAR_RIGHT_PARENTHESIS) break; + + /* Skip over comments and whitespace in extended mode. */ + + if ((options & PCRE2_EXTENDED) != 0) + { + PCRE2_SPTR wscptr = ptr; + while (MAX_255(x) && (cb->ctypes[x] & ctype_space) != 0) x = *(++ptr); + if (x == CHAR_NUMBER_SIGN) + { + ptr++; + while (*ptr != CHAR_NULL || ptr < cb->end_pattern) + { + if (IS_NEWLINE(ptr)) /* For non-fixed-length newline cases, */ + { /* IS_NEWLINE sets cb->nllen. */ + ptr += cb->nllen; + break; + } + ptr++; +#ifdef SUPPORT_UNICODE + if (utf) FORWARDCHAR(ptr); +#endif + } + } + + /* If we have skipped any characters, restart the loop. */ + + if (ptr > wscptr) + { + ptr--; + continue; + } + } + + /* Process escapes */ + + if (x == '\\') + { + int rc; + *errorcodeptr = 0; + rc = PRIV(check_escape)(&ptr, cb->end_pattern, &x, errorcodeptr, options, + FALSE, cb); + *ptrptr = ptr; /* For possible error */ + if (*errorcodeptr != 0) return -1; + if (rc != 0) + { + if (rc == ESC_Q) + { + inescq = TRUE; + continue; + } + if (rc == ESC_E) continue; + *errorcodeptr = ERR40; + return -1; + } + } + } + + /* We have the next character in the name. */ + +#ifdef SUPPORT_UNICODE + if (utf) + { + if (code == NULL) /* Just want the length */ + { +#if PCRE2_CODE_UNIT_WIDTH == 8 + int i; + for (i = 0; i < PRIV(utf8_table1_size); i++) + if ((int)x <= PRIV(utf8_table1)[i]) break; + arglen += i; +#elif PCRE2_CODE_UNIT_WIDTH == 16 + if (x > 0xffff) arglen++; +#endif + } + else + { + PCRE2_UCHAR cbuff[8]; + x = PRIV(ord2utf)(x, cbuff); + memcpy(code, cbuff, CU2BYTES(x)); + code += x; + } + } + else +#endif /* SUPPORT_UNICODE */ + + /* Not UTF */ + { + if (code != NULL) *code++ = (PCRE2_UCHAR)x; + } + + arglen++; + + if ((unsigned int)arglen > MAX_MARK) + { + *errorcodeptr = ERR76; + *ptrptr = ptr; + return -1; + } + } + +/* Update the pointers before returning. */ + +*ptrptr = ptr; +if (codeptr != NULL) *codeptr = code; +return arglen; +} + + + +/************************************************* +* Macro for the next two functions * +*************************************************/ + +/* Both scan_for_captures() and compile_branch() use this macro to generate a +fragment of code that reads the characters of a name and sets its length +(checking for not being too long). Count the characters dynamically, to avoid +the possibility of integer overflow. The same macro is used for reading *VERB +names. */ + +#define READ_NAME(ctype, errno, errset) \ + namelen = 0; \ + while (MAX_255(*ptr) && (cb->ctypes[*ptr] & ctype) != 0) \ + { \ + ptr++; \ + namelen++; \ + if (namelen > MAX_NAME_SIZE) \ + { \ + errset = errno; \ + goto FAILED; \ + } \ + } + + + +/************************************************* +* Scan regex to identify named groups * +*************************************************/ + +/* This function is called first of all, to scan for named capturing groups so +that information about them is fully available to both the compiling scans. +It skips over everything except parenthesized items. + +Arguments: + ptrptr points to pointer to the start of the pattern + options compiling dynamic options + cb pointer to the compile data block + +Returns: zero on success or a non-zero error code, with pointer updated +*/ + +typedef struct nest_save { + uint16_t nest_depth; + uint16_t reset_group; + uint16_t max_group; + uint16_t flags; +} nest_save; + +#define NSF_RESET 0x0001u +#define NSF_EXTENDED 0x0002u +#define NSF_DUPNAMES 0x0004u + +static int scan_for_captures(PCRE2_SPTR *ptrptr, uint32_t options, + compile_block *cb) +{ +uint32_t c; +uint32_t delimiter; +uint32_t set, unset, *optset; +uint32_t skiptoket = 0; +uint16_t nest_depth = 0; +int errorcode = 0; +int escape; +int namelen; +int i; +BOOL inescq = FALSE; +BOOL isdupname; +BOOL utf = (options & PCRE2_UTF) != 0; +BOOL negate_class; +PCRE2_SPTR name; +PCRE2_SPTR start; +PCRE2_SPTR ptr = *ptrptr; +named_group *ng; +nest_save *top_nest = NULL; +nest_save *end_nests = (nest_save *)(cb->start_workspace + cb->workspace_size); + +/* The size of the nest_save structure might not be a factor of the size of the +workspace. Therefore we must round down end_nests so as to correctly avoid +creating a nest_save that spans the end of the workspace. */ + +end_nests = (nest_save *)((char *)end_nests - + ((cb->workspace_size * sizeof(PCRE2_UCHAR)) % sizeof(nest_save))); + +/* Now scan the pattern */ + +for (; ptr < cb->end_pattern; ptr++) + { + c = *ptr; + + /* Parenthesized groups set skiptoket when all following characters up to the + next closing parenthesis must be ignored. The parenthesis itself must be + processed (to end the nested parenthesized item). */ + + if (skiptoket != 0) + { + if (c != CHAR_RIGHT_PARENTHESIS) continue; + skiptoket = 0; + } + + /* Skip over literals */ + + if (inescq) + { + if (c == CHAR_BACKSLASH && ptr[1] == CHAR_E) + { + inescq = FALSE; + ptr++; + } + continue; + } + + /* Skip over # comments and whitespace in extended mode. */ + + if ((options & PCRE2_EXTENDED) != 0) + { + PCRE2_SPTR wscptr = ptr; + while (MAX_255(c) && (cb->ctypes[c] & ctype_space) != 0) c = *(++ptr); + if (c == CHAR_NUMBER_SIGN) + { + ptr++; + while (ptr < cb->end_pattern) + { + if (IS_NEWLINE(ptr)) /* For non-fixed-length newline cases, */ + { /* IS_NEWLINE sets cb->nllen. */ + ptr += cb->nllen; + break; + } + ptr++; +#ifdef SUPPORT_UNICODE + if (utf) FORWARDCHAR(ptr); +#endif + } + } + + /* If we skipped any characters, restart the loop. Otherwise, we didn't see + a comment. */ + + if (ptr > wscptr) + { + ptr--; + continue; + } + } + + /* Process the next pattern item. */ + + switch(c) + { + default: /* Most characters are just skipped */ + break; + + /* Skip escapes except for \Q */ + + case CHAR_BACKSLASH: + errorcode = 0; + escape = PRIV(check_escape)(&ptr, cb->end_pattern, &c, &errorcode, options, + FALSE, cb); + if (errorcode != 0) goto FAILED; + if (escape == ESC_Q) inescq = TRUE; + break; + + /* Skip a character class. The syntax is complicated so we have to + replicate some of what happens when a class is processed for real. */ + + case CHAR_LEFT_SQUARE_BRACKET: + if (PRIV(strncmp_c8)(ptr+1, STRING_WEIRD_STARTWORD, 6) == 0 || + PRIV(strncmp_c8)(ptr+1, STRING_WEIRD_ENDWORD, 6) == 0) + { + ptr += 6; + break; + } + + /* If the first character is '^', set the negation flag (not actually used + here, except to recognize only one ^) and skip it. If the first few + characters (either before or after ^) are \Q\E or \E we skip them too. This + makes for compatibility with Perl. */ + + negate_class = FALSE; + for (;;) + { + c = *(++ptr); /* First character in class */ + if (c == CHAR_BACKSLASH) + { + if (ptr[1] == CHAR_E) + ptr++; + else if (PRIV(strncmp_c8)(ptr + 1, STR_Q STR_BACKSLASH STR_E, 3) == 0) + ptr += 3; + else + break; + } + else if (!negate_class && c == CHAR_CIRCUMFLEX_ACCENT) + negate_class = TRUE; + else break; + } + + if (c == CHAR_RIGHT_SQUARE_BRACKET && + (cb->external_options & PCRE2_ALLOW_EMPTY_CLASS) != 0) + break; + + /* Loop for the contents of the class */ + + for (;;) + { + PCRE2_SPTR tempptr; + + if (c == CHAR_NULL && ptr >= cb->end_pattern) + { + errorcode = ERR6; /* Missing terminating ']' */ + goto FAILED; + } + +#ifdef SUPPORT_UNICODE + if (utf && HAS_EXTRALEN(c)) + { /* Braces are required because the */ + GETCHARLEN(c, ptr, ptr); /* macro generates multiple statements */ + } +#endif + + /* Inside \Q...\E everything is literal except \E */ + + if (inescq) + { + if (c == CHAR_BACKSLASH && ptr[1] == CHAR_E) /* If we are at \E */ + { + inescq = FALSE; /* Reset literal state */ + ptr++; /* Skip the 'E' */ + } + goto CONTINUE_CLASS; + } + + /* Skip POSIX class names. */ + if (c == CHAR_LEFT_SQUARE_BRACKET && + (ptr[1] == CHAR_COLON || ptr[1] == CHAR_DOT || + ptr[1] == CHAR_EQUALS_SIGN) && check_posix_syntax(ptr, &tempptr)) + { + ptr = tempptr + 1; + } + else if (c == CHAR_BACKSLASH) + { + errorcode = 0; + escape = PRIV(check_escape)(&ptr, cb->end_pattern, &c, &errorcode, + options, TRUE, cb); + if (errorcode != 0) goto FAILED; + if (escape == ESC_Q) inescq = TRUE; + } + + CONTINUE_CLASS: + c = *(++ptr); + if (c == CHAR_RIGHT_SQUARE_BRACKET && !inescq) break; + } /* End of class-processing loop */ + break; + + /* This is the real work of this function - handling parentheses. */ + + case CHAR_LEFT_PARENTHESIS: + nest_depth++; + + if (ptr[1] != CHAR_QUESTION_MARK) + { + if (ptr[1] != CHAR_ASTERISK) + { + if ((options & PCRE2_NO_AUTO_CAPTURE) == 0) cb->bracount++; + } + + /* (*something) - skip over a name, and then just skip to closing ket + unless PCRE2_ALT_VERBNAMES is set, in which case we have to process + escapes in the string after a verb name terminated by a colon. */ + + else + { + ptr += 2; + while (MAX_255(*ptr) && (cb->ctypes[*ptr] & ctype_word) != 0) ptr++; + if (*ptr == CHAR_COLON && (options & PCRE2_ALT_VERBNAMES) != 0) + { + ptr++; + if (process_verb_name(&ptr, NULL, &errorcode, options, utf, cb) < 0) + goto FAILED; + } + else + { + while (ptr < cb->end_pattern && *ptr != CHAR_RIGHT_PARENTHESIS) + ptr++; + } + nest_depth--; + } + } + + /* Handle (?...) groups */ + + else switch(ptr[2]) + { + default: + ptr += 2; + if (ptr[0] == CHAR_R || /* (?R) */ + ptr[0] == CHAR_NUMBER_SIGN || /* (?#) */ + IS_DIGIT(ptr[0]) || /* (?n) */ + (ptr[0] == CHAR_MINUS && IS_DIGIT(ptr[1]))) /* (?-n) */ + { + skiptoket = ptr[0]; + break; + } + + /* Handle (?| and (?imsxJU: which are the only other valid forms. Both + need a new block on the nest stack. */ + + if (top_nest == NULL) top_nest = (nest_save *)(cb->start_workspace); + else if (++top_nest >= end_nests) + { + errorcode = ERR84; + goto FAILED; + } + top_nest->nest_depth = nest_depth; + top_nest->flags = 0; + if ((options & PCRE2_EXTENDED) != 0) top_nest->flags |= NSF_EXTENDED; + if ((options & PCRE2_DUPNAMES) != 0) top_nest->flags |= NSF_DUPNAMES; + + if (*ptr == CHAR_VERTICAL_LINE) + { + top_nest->reset_group = (uint16_t)cb->bracount; + top_nest->max_group = (uint16_t)cb->bracount; + top_nest->flags |= NSF_RESET; + cb->external_flags |= PCRE2_DUPCAPUSED; + break; + } + + /* Scan options */ + + top_nest->reset_group = 0; + top_nest->max_group = 0; + + set = unset = 0; + optset = &set; + + /* Need only track (?x: and (?J: at this stage */ + + while (*ptr != CHAR_RIGHT_PARENTHESIS && *ptr != CHAR_COLON) + { + switch (*ptr++) + { + case CHAR_MINUS: optset = &unset; break; + + case CHAR_x: *optset |= PCRE2_EXTENDED; break; + + case CHAR_J: + *optset |= PCRE2_DUPNAMES; + cb->external_flags |= PCRE2_JCHANGED; + break; + + case CHAR_i: + case CHAR_m: + case CHAR_s: + case CHAR_U: + break; + + default: + errorcode = ERR11; + ptr--; /* Correct the offset */ + goto FAILED; + } + } + + options = (options | set) & (~unset); + + /* If the options ended with ')' this is not the start of a nested + group with option changes, so the options change at this level. If the + previous level set up a nest block, discard the one we have just created. + Otherwise adjust it for the previous level. */ + + if (*ptr == CHAR_RIGHT_PARENTHESIS) + { + nest_depth--; + if (top_nest > (nest_save *)(cb->start_workspace) && + (top_nest-1)->nest_depth == nest_depth) top_nest --; + else top_nest->nest_depth = nest_depth; + } + break; + + /* Skip over a numerical or string argument for a callout. */ + + case CHAR_C: + ptr += 2; + if (ptr[1] == CHAR_RIGHT_PARENTHESIS) break; + if (IS_DIGIT(ptr[1])) + { + while (IS_DIGIT(ptr[1])) ptr++; + } + + /* Handle a string argument */ + + else + { + ptr++; + delimiter = 0; + for (i = 0; PRIV(callout_start_delims)[i] != 0; i++) + { + if (*ptr == PRIV(callout_start_delims)[i]) + { + delimiter = PRIV(callout_end_delims)[i]; + break; + } + } + + if (delimiter == 0) + { + errorcode = ERR82; + goto FAILED; + } + + start = ptr; + do + { + if (++ptr >= cb->end_pattern) + { + errorcode = ERR81; + ptr = start; /* To give a more useful message */ + goto FAILED; + } + if (ptr[0] == delimiter && ptr[1] == delimiter) ptr += 2; + } + while (ptr[0] != delimiter); + } + + /* Check terminating ) */ + + if (ptr[1] != CHAR_RIGHT_PARENTHESIS) + { + errorcode = ERR39; + ptr++; + goto FAILED; + } + break; + + /* Conditional group */ + + case CHAR_LEFT_PARENTHESIS: + if (ptr[3] != CHAR_QUESTION_MARK) /* Not assertion or callout */ + { + nest_depth++; + ptr += 2; + break; + } + + /* Must be an assertion or a callout */ + + switch(ptr[4]) + { + case CHAR_LESS_THAN_SIGN: + if (ptr[5] != CHAR_EXCLAMATION_MARK && ptr[5] != CHAR_EQUALS_SIGN) + goto MISSING_ASSERTION; + /* Fall through */ + + case CHAR_C: + case CHAR_EXCLAMATION_MARK: + case CHAR_EQUALS_SIGN: + ptr++; + break; + + default: + MISSING_ASSERTION: + ptr += 3; /* To improve error message */ + errorcode = ERR28; + goto FAILED; + } + break; + + case CHAR_COLON: + case CHAR_GREATER_THAN_SIGN: + case CHAR_EQUALS_SIGN: + case CHAR_EXCLAMATION_MARK: + case CHAR_AMPERSAND: + case CHAR_PLUS: + ptr += 2; + break; + + case CHAR_P: + if (ptr[3] != CHAR_LESS_THAN_SIGN) + { + ptr += 3; + break; + } + ptr++; + c = CHAR_GREATER_THAN_SIGN; /* Terminator */ + goto DEFINE_NAME; + + case CHAR_LESS_THAN_SIGN: + if (ptr[3] == CHAR_EQUALS_SIGN || ptr[3] == CHAR_EXCLAMATION_MARK) + { + ptr += 3; + break; + } + c = CHAR_GREATER_THAN_SIGN; /* Terminator */ + goto DEFINE_NAME; + + case CHAR_APOSTROPHE: + c = CHAR_APOSTROPHE; /* Terminator */ + + DEFINE_NAME: + name = ptr = ptr + 3; + + if (*ptr == c) /* Empty name */ + { + errorcode = ERR62; + goto FAILED; + } + + if (IS_DIGIT(*ptr)) + { + errorcode = ERR44; /* Group name must start with non-digit */ + goto FAILED; + } + + if (MAX_255(*ptr) && (cb->ctypes[*ptr] & ctype_word) == 0) + { + errorcode = ERR24; + goto FAILED; + } + + /* Advance ptr, set namelen and check its length. */ + READ_NAME(ctype_word, ERR48, errorcode); + + if (*ptr != c) + { + errorcode = ERR42; + goto FAILED; + } + + if (cb->names_found >= MAX_NAME_COUNT) + { + errorcode = ERR49; + goto FAILED; + } + + if (namelen + IMM2_SIZE + 1 > cb->name_entry_size) + cb->name_entry_size = (uint16_t)(namelen + IMM2_SIZE + 1); + + /* We have a valid name for this capturing group. */ + + cb->bracount++; + + /* Scan the list to check for duplicates. For duplicate names, if the + number is the same, break the loop, which causes the name to be + discarded; otherwise, if DUPNAMES is not set, give an error. + If it is set, allow the name with a different number, but continue + scanning in case this is a duplicate with the same number. For + non-duplicate names, give an error if the number is duplicated. */ + + isdupname = FALSE; + ng = cb->named_groups; + for (i = 0; i < cb->names_found; i++, ng++) + { + if (namelen == ng->length && + PRIV(strncmp)(name, ng->name, (size_t)namelen) == 0) + { + if (ng->number == cb->bracount) break; + if ((options & PCRE2_DUPNAMES) == 0) + { + errorcode = ERR43; + goto FAILED; + } + isdupname = ng->isdup = TRUE; /* Mark as a duplicate */ + cb->dupnames = TRUE; /* Duplicate names exist */ + } + else if (ng->number == cb->bracount) + { + errorcode = ERR65; + goto FAILED; + } + } + + if (i < cb->names_found) break; /* Ignore duplicate with same number */ + + /* Increase the list size if necessary */ + + if (cb->names_found >= cb->named_group_list_size) + { + uint32_t newsize = cb->named_group_list_size * 2; + named_group *newspace = + cb->cx->memctl.malloc(newsize * sizeof(named_group), + cb->cx->memctl.memory_data); + if (newspace == NULL) + { + errorcode = ERR21; + goto FAILED; + } + + memcpy(newspace, cb->named_groups, + cb->named_group_list_size * sizeof(named_group)); + if (cb->named_group_list_size > NAMED_GROUP_LIST_SIZE) + cb->cx->memctl.free((void *)cb->named_groups, + cb->cx->memctl.memory_data); + cb->named_groups = newspace; + cb->named_group_list_size = newsize; + } + + /* Add this name to the list */ + + cb->named_groups[cb->names_found].name = name; + cb->named_groups[cb->names_found].length = (uint16_t)namelen; + cb->named_groups[cb->names_found].number = cb->bracount; + cb->named_groups[cb->names_found].isdup = (uint16_t)isdupname; + cb->names_found++; + break; + } /* End of (? switch */ + break; /* End of ( handling */ + + /* At an alternation, reset the capture count if we are in a (?| group. */ + + case CHAR_VERTICAL_LINE: + if (top_nest != NULL && top_nest->nest_depth == nest_depth && + (top_nest->flags & NSF_RESET) != 0) + { + if (cb->bracount > top_nest->max_group) + top_nest->max_group = (uint16_t)cb->bracount; + cb->bracount = top_nest->reset_group; + } + break; + + /* At a right parenthesis, reset the capture count to the maximum if we + are in a (?| group and/or reset the extended option. */ + + case CHAR_RIGHT_PARENTHESIS: + if (top_nest != NULL && top_nest->nest_depth == nest_depth) + { + if ((top_nest->flags & NSF_RESET) != 0 && + top_nest->max_group > cb->bracount) + cb->bracount = top_nest->max_group; + if ((top_nest->flags & NSF_EXTENDED) != 0) options |= PCRE2_EXTENDED; + else options &= ~PCRE2_EXTENDED; + if ((top_nest->flags & NSF_DUPNAMES) != 0) options |= PCRE2_DUPNAMES; + else options &= ~PCRE2_DUPNAMES; + if (top_nest == (nest_save *)(cb->start_workspace)) top_nest = NULL; + else top_nest--; + } + if (nest_depth == 0) /* Unmatched closing parenthesis */ + { + errorcode = ERR22; + goto FAILED; + } + nest_depth--; + break; + } + } + +if (nest_depth == 0) + { + cb->final_bracount = cb->bracount; + return 0; + } + +/* We give a special error for a missing closing parentheses after (?# because +it might otherwise be hard to see where the missing character is. */ + +errorcode = (skiptoket == CHAR_NUMBER_SIGN)? ERR18 : ERR14; + +FAILED: +*ptrptr = ptr; +return errorcode; +} + + + +/************************************************* +* Compile one branch * +*************************************************/ + +/* Scan the pattern, compiling it into the a vector. If the options are +changed during the branch, the pointer is used to change the external options +bits. This function is used during the pre-compile phase when we are trying +to find out the amount of memory needed, as well as during the real compile +phase. The value of lengthptr distinguishes the two phases. + +Arguments: + optionsptr pointer to the option bits + codeptr points to the pointer to the current code point + ptrptr points to the current pattern pointer + errorcodeptr points to error code variable + firstcuptr place to put the first required code unit + firstcuflagsptr place to put the first code unit flags, or a negative number + reqcuptr place to put the last required code unit + reqcuflagsptr place to put the last required code unit flags, or a negative number + bcptr points to current branch chain + cond_depth conditional nesting depth + cb contains pointers to tables etc. + lengthptr NULL during the real compile phase + points to length accumulator during pre-compile phase + +Returns: TRUE on success + FALSE, with *errorcodeptr set non-zero on error +*/ + +static BOOL +compile_branch(uint32_t *optionsptr, PCRE2_UCHAR **codeptr, + PCRE2_SPTR *ptrptr, int *errorcodeptr, + uint32_t *firstcuptr, int32_t *firstcuflagsptr, + uint32_t *reqcuptr, int32_t *reqcuflagsptr, + branch_chain *bcptr, int cond_depth, + compile_block *cb, size_t *lengthptr) +{ +int repeat_min = 0, repeat_max = 0; /* To please picky compilers */ +int bravalue = 0; +uint32_t greedy_default, greedy_non_default; +uint32_t repeat_type, op_type; +uint32_t options = *optionsptr; /* May change dynamically */ +uint32_t firstcu, reqcu; +int32_t firstcuflags, reqcuflags; +uint32_t zeroreqcu, zerofirstcu; +int32_t zeroreqcuflags, zerofirstcuflags; +int32_t req_caseopt, reqvary, tempreqvary; +int after_manual_callout = 0; +int escape; +size_t length_prevgroup = 0; +register uint32_t c; +register PCRE2_UCHAR *code = *codeptr; +PCRE2_UCHAR *last_code = code; +PCRE2_UCHAR *orig_code = code; +PCRE2_UCHAR *tempcode; +BOOL inescq = FALSE; +BOOL groupsetfirstcu = FALSE; +PCRE2_SPTR ptr = *ptrptr; +PCRE2_SPTR tempptr; +PCRE2_UCHAR *previous = NULL; +PCRE2_UCHAR *previous_callout = NULL; +uint8_t classbits[32]; + +/* We can fish out the UTF setting once and for all into a BOOL, but we must +not do this for other options (e.g. PCRE2_EXTENDED) because they may change +dynamically as we process the pattern. */ + +#ifdef SUPPORT_UNICODE +BOOL utf = (options & PCRE2_UTF) != 0; +#if PCRE2_CODE_UNIT_WIDTH != 32 +PCRE2_UCHAR utf_units[6]; /* For setting up multi-cu chars */ +#endif + +#else /* No UTF support */ +BOOL utf = FALSE; +#endif + +/* Helper variables for OP_XCLASS opcode (for characters > 255). We define +class_uchardata always so that it can be passed to add_to_class() always, +though it will not be used in non-UTF 8-bit cases. This avoids having to supply +alternative calls for the different cases. */ + +PCRE2_UCHAR *class_uchardata; +#ifdef SUPPORT_WIDE_CHARS +BOOL xclass; +PCRE2_UCHAR *class_uchardata_base; +#endif + +/* Set up the default and non-default settings for greediness */ + +greedy_default = ((options & PCRE2_UNGREEDY) != 0); +greedy_non_default = greedy_default ^ 1; + +/* Initialize no first unit, no required unit. REQ_UNSET means "no char +matching encountered yet". It gets changed to REQ_NONE if we hit something that +matches a non-fixed first unit; reqcu just remains unset if we never find one. + +When we hit a repeat whose minimum is zero, we may have to adjust these values +to take the zero repeat into account. This is implemented by setting them to +zerofirstcu and zeroreqcu when such a repeat is encountered. The individual +item types that can be repeated set these backoff variables appropriately. */ + +firstcu = reqcu = zerofirstcu = zeroreqcu = 0; +firstcuflags = reqcuflags = zerofirstcuflags = zeroreqcuflags = REQ_UNSET; + +/* The variable req_caseopt contains either the REQ_CASELESS value or zero, +according to the current setting of the caseless flag. The REQ_CASELESS value +leaves the lower 28 bit empty. It is added into the firstcu or reqcu variables +to record the case status of the value. This is used only for ASCII characters. +*/ + +req_caseopt = ((options & PCRE2_CASELESS) != 0)? REQ_CASELESS:0; + +/* Switch on next character until the end of the branch */ + +for (;; ptr++) + { + BOOL negate_class; + BOOL should_flip_negation; + BOOL match_all_or_no_wide_chars; + BOOL possessive_quantifier; + BOOL is_quantifier; + BOOL is_recurse; + BOOL is_dupname; + BOOL reset_bracount; + int class_has_8bitchar; + int class_one_char; +#ifdef SUPPORT_WIDE_CHARS + BOOL xclass_has_prop; +#endif + int recno; /* Must be signed */ + int refsign; /* Must be signed */ + int terminator; /* Must be signed */ + unsigned int mclength; + unsigned int tempbracount; + uint32_t ec; + uint32_t newoptions; + uint32_t skipunits; + uint32_t subreqcu, subfirstcu; + int32_t subreqcuflags, subfirstcuflags; /* Must be signed */ + PCRE2_UCHAR mcbuffer[8]; + + /* Come here to restart the loop. */ + + REDO_LOOP: + + /* Get next character in the pattern */ + + c = *ptr; + + /* If we are at the end of a nested substitution, revert to the outer level + string. Nesting only happens one or two levels deep, and the inserted string + is always zero terminated. */ + + if (c == CHAR_NULL && cb->nestptr[0] != NULL) + { + ptr = cb->nestptr[0]; + cb->nestptr[0] = cb->nestptr[1]; + cb->nestptr[1] = NULL; + c = *ptr; + } + + /* If we are in the pre-compile phase, accumulate the length used for the + previous cycle of this loop. */ + + if (lengthptr != NULL) + { + if (code > cb->start_workspace + cb->workspace_size - + WORK_SIZE_SAFETY_MARGIN) /* Check for overrun */ + { + *errorcodeptr = (code >= cb->start_workspace + cb->workspace_size)? + ERR52 : ERR86; + goto FAILED; + } + + /* There is at least one situation where code goes backwards: this is the + case of a zero quantifier after a class (e.g. [ab]{0}). At compile time, + the class is simply eliminated. However, it is created first, so we have to + allow memory for it. Therefore, don't ever reduce the length at this point. + */ + + if (code < last_code) code = last_code; + + /* Paranoid check for integer overflow */ + + if (OFLOW_MAX - *lengthptr < (size_t)(code - last_code)) + { + *errorcodeptr = ERR20; + goto FAILED; + } + *lengthptr += (size_t)(code - last_code); + + /* If "previous" is set and it is not at the start of the work space, move + it back to there, in order to avoid filling up the work space. Otherwise, + if "previous" is NULL, reset the current code pointer to the start. */ + + if (previous != NULL) + { + if (previous > orig_code) + { + memmove(orig_code, previous, (size_t)CU2BYTES(code - previous)); + code -= previous - orig_code; + previous = orig_code; + } + } + else code = orig_code; + + /* Remember where this code item starts so we can pick up the length + next time round. */ + + last_code = code; + } + + /* Before doing anything else we must handle all the special items that do + nothing, and which may come between an item and its quantifier. Otherwise, + when auto-callouts are enabled, a callout gets incorrectly inserted before + the quantifier is recognized. After recognizing a "do nothing" item, restart + the loop in case another one follows. */ + + /* If c is not NULL we are not at the end of the pattern. If it is NULL, we + may still be in the pattern with a NULL data item. In these cases, if we are + in \Q...\E, check for the \E that ends the literal string; if not, we have a + literal character. If not in \Q...\E, an isolated \E is ignored. */ + + if (c != CHAR_NULL || ptr < cb->end_pattern) + { + if (c == CHAR_BACKSLASH && ptr[1] == CHAR_E) + { + inescq = FALSE; + ptr++; + continue; + } + else if (inescq) /* Literal character */ + { + if (previous_callout != NULL) + { + if (lengthptr == NULL) /* Don't attempt in pre-compile phase */ + complete_callout(previous_callout, ptr, cb); + previous_callout = NULL; + } + if ((options & PCRE2_AUTO_CALLOUT) != 0) + { + previous_callout = code; + code = auto_callout(code, ptr, cb); + } + goto NORMAL_CHAR; + } + + /* Check for the start of a \Q...\E sequence. We must do this here rather + than later in case it is immediately followed by \E, which turns it into a + "do nothing" sequence. */ + + if (c == CHAR_BACKSLASH && ptr[1] == CHAR_Q) + { + inescq = TRUE; + ptr++; + continue; + } + } + + /* In extended mode, skip white space and #-comments that end at newline. */ + + if ((options & PCRE2_EXTENDED) != 0) + { + PCRE2_SPTR wscptr = ptr; + while (MAX_255(c) && (cb->ctypes[c] & ctype_space) != 0) c = *(++ptr); + if (c == CHAR_NUMBER_SIGN) + { + ptr++; + while (ptr < cb->end_pattern) + { + if (IS_NEWLINE(ptr)) /* For non-fixed-length newline cases, */ + { /* IS_NEWLINE sets cb->nllen. */ + ptr += cb->nllen; + break; + } + ptr++; +#ifdef SUPPORT_UNICODE + if (utf) FORWARDCHAR(ptr); +#endif + } + } + + /* If we skipped any characters, restart the loop. Otherwise, we didn't see + a comment. */ + + if (ptr > wscptr) goto REDO_LOOP; + } + + /* Skip over (?# comments. */ + + if (c == CHAR_LEFT_PARENTHESIS && ptr[1] == CHAR_QUESTION_MARK && + ptr[2] == CHAR_NUMBER_SIGN) + { + ptr += 3; + while (ptr < cb->end_pattern && *ptr != CHAR_RIGHT_PARENTHESIS) ptr++; + if (*ptr != CHAR_RIGHT_PARENTHESIS) + { + *errorcodeptr = ERR18; + goto FAILED; + } + continue; + } + + /* End of processing "do nothing" items. See if the next thing is a + quantifier. */ + + is_quantifier = + c == CHAR_ASTERISK || c == CHAR_PLUS || c == CHAR_QUESTION_MARK || + (c == CHAR_LEFT_CURLY_BRACKET && is_counted_repeat(ptr+1)); + + /* Fill in length of a previous callout and create an auto callout if + required, except when the next thing is a quantifier or when processing a + property substitution string for \w etc in UCP mode. */ + + if (!is_quantifier && cb->nestptr[0] == NULL) + { + if (previous_callout != NULL && after_manual_callout-- <= 0) + { + if (lengthptr == NULL) /* Don't attempt in pre-compile phase */ + complete_callout(previous_callout, ptr, cb); + previous_callout = NULL; + } + + if ((options & PCRE2_AUTO_CALLOUT) != 0) + { + previous_callout = code; + code = auto_callout(code, ptr, cb); + } + } + + /* Process the next pattern item. */ + + switch(c) + { + /* ===================================================================*/ + /* The branch terminates at string end or | or ) */ + + case CHAR_NULL: + if (ptr < cb->end_pattern) goto NORMAL_CHAR; /* Zero data character */ + /* Fall through */ + + case CHAR_VERTICAL_LINE: + case CHAR_RIGHT_PARENTHESIS: + *firstcuptr = firstcu; + *firstcuflagsptr = firstcuflags; + *reqcuptr = reqcu; + *reqcuflagsptr = reqcuflags; + *codeptr = code; + *ptrptr = ptr; + if (lengthptr != NULL) + { + if (OFLOW_MAX - *lengthptr < (size_t)(code - last_code)) + { + *errorcodeptr = ERR20; + goto FAILED; + } + *lengthptr += (size_t)(code - last_code); /* To include callout length */ + } + return TRUE; + + + /* ===================================================================*/ + /* Handle single-character metacharacters. In multiline mode, ^ disables + the setting of any following char as a first character. */ + + case CHAR_CIRCUMFLEX_ACCENT: + previous = NULL; + if ((options & PCRE2_MULTILINE) != 0) + { + if (firstcuflags == REQ_UNSET) + zerofirstcuflags = firstcuflags = REQ_NONE; + *code++ = OP_CIRCM; + } + else *code++ = OP_CIRC; + break; + + case CHAR_DOLLAR_SIGN: + previous = NULL; + *code++ = ((options & PCRE2_MULTILINE) != 0)? OP_DOLLM : OP_DOLL; + break; + + /* There can never be a first char if '.' is first, whatever happens about + repeats. The value of reqcu doesn't change either. */ + + case CHAR_DOT: + if (firstcuflags == REQ_UNSET) firstcuflags = REQ_NONE; + zerofirstcu = firstcu; + zerofirstcuflags = firstcuflags; + zeroreqcu = reqcu; + zeroreqcuflags = reqcuflags; + previous = code; + *code++ = ((options & PCRE2_DOTALL) != 0)? OP_ALLANY: OP_ANY; + break; + + + /* ===================================================================*/ + /* Character classes. If the included characters are all < 256, we build a + 32-byte bitmap of the permitted characters, except in the special case + where there is only one such character. For negated classes, we build the + map as usual, then invert it at the end. However, we use a different opcode + so that data characters > 255 can be handled correctly. + + If the class contains characters outside the 0-255 range, a different + opcode is compiled. It may optionally have a bit map for characters < 256, + but those above are are explicitly listed afterwards. A flag byte tells + whether the bitmap is present, and whether this is a negated class or not. + + An isolated ']' character is not treated specially, so is just another data + character. In earlier versions of PCRE that used the original API there was + a "JavaScript compatibility mode" in which it gave an error. However, + JavaScript itself has changed in this respect so there is no longer any + need for this special handling. + + In another (POSIX) regex library, the ugly syntax [[:<:]] and [[:>:]] is + used for "start of word" and "end of word". As these are otherwise illegal + sequences, we don't break anything by recognizing them. They are replaced + by \b(?=\w) and \b(?<=\w) respectively. This can only happen at the top + nesting level, as no other inserted sequences will contains these oddities. + Sequences like [a[:<:]] are erroneous and are handled by the normal code + below. */ + + case CHAR_LEFT_SQUARE_BRACKET: + if (PRIV(strncmp_c8)(ptr+1, STRING_WEIRD_STARTWORD, 6) == 0) + { + cb->nestptr[0] = ptr + 7; + ptr = sub_start_of_word; + goto REDO_LOOP; + } + + if (PRIV(strncmp_c8)(ptr+1, STRING_WEIRD_ENDWORD, 6) == 0) + { + cb->nestptr[0] = ptr + 7; + ptr = sub_end_of_word; + goto REDO_LOOP; + } + + /* Handle a real character class. */ + + previous = code; + + /* PCRE supports POSIX class stuff inside a class. Perl gives an error if + they are encountered at the top level, so we'll do that too. */ + + if ((ptr[1] == CHAR_COLON || ptr[1] == CHAR_DOT || + ptr[1] == CHAR_EQUALS_SIGN) && + check_posix_syntax(ptr, &tempptr)) + { + *errorcodeptr = (ptr[1] == CHAR_COLON)? ERR12 : ERR13; + goto FAILED; + } + + /* If the first character is '^', set the negation flag and skip it. Also, + if the first few characters (either before or after ^) are \Q\E or \E we + skip them too. This makes for compatibility with Perl. */ + + negate_class = FALSE; + for (;;) + { + c = *(++ptr); + if (c == CHAR_BACKSLASH) + { + if (ptr[1] == CHAR_E) + ptr++; + else if (PRIV(strncmp_c8)(ptr + 1, STR_Q STR_BACKSLASH STR_E, 3) == 0) + ptr += 3; + else + break; + } + else if (!negate_class && c == CHAR_CIRCUMFLEX_ACCENT) + negate_class = TRUE; + else break; + } + + /* Empty classes are allowed if PCRE2_ALLOW_EMPTY_CLASS is set. Otherwise, + an initial ']' is taken as a data character -- the code below handles + that. When empty classes are allowed, [] must always fail, so generate + OP_FAIL, whereas [^] must match any character, so generate OP_ALLANY. */ + + if (c == CHAR_RIGHT_SQUARE_BRACKET && + (cb->external_options & PCRE2_ALLOW_EMPTY_CLASS) != 0) + { + *code++ = negate_class? OP_ALLANY : OP_FAIL; + if (firstcuflags == REQ_UNSET) firstcuflags = REQ_NONE; + zerofirstcu = firstcu; + zerofirstcuflags = firstcuflags; + break; + } + + /* If a non-extended class contains a negative special such as \S, we need + to flip the negation flag at the end, so that support for characters > 255 + works correctly (they are all included in the class). An extended class may + need to insert specific matching or non-matching code for wide characters. + */ + + should_flip_negation = match_all_or_no_wide_chars = FALSE; + + /* Extended class (xclass) will be used when characters > 255 + might match. */ + +#ifdef SUPPORT_WIDE_CHARS + xclass = FALSE; + class_uchardata = code + LINK_SIZE + 2; /* For XCLASS items */ + class_uchardata_base = class_uchardata; /* Save the start */ +#endif + + /* For optimization purposes, we track some properties of the class: + class_has_8bitchar will be non-zero if the class contains at least one 256 + character with a code point less than 256; class_one_char will be 1 if the + class contains just one character; xclass_has_prop will be TRUE if Unicode + property checks are present in the class. */ + + class_has_8bitchar = 0; + class_one_char = 0; +#ifdef SUPPORT_WIDE_CHARS + xclass_has_prop = FALSE; +#endif + + /* Initialize the 256-bit (32-byte) bit map to all zeros. We build the map + in a temporary bit of memory, in case the class contains fewer than two + 8-bit characters because in that case the compiled code doesn't use the bit + map. */ + + memset(classbits, 0, 32 * sizeof(uint8_t)); + + /* Process characters until ] is reached. As the test is at the end of the + loop, an initial ] is taken as a data character. At the start of the loop, + c contains the first code unit of the character. If it is zero, check for + the end of the pattern, to allow binary zero as data. */ + + for(;;) + { + PCRE2_SPTR oldptr; +#ifdef EBCDIC + BOOL range_is_literal = TRUE; +#endif + + if (c == CHAR_NULL && ptr >= cb->end_pattern) + { + *errorcodeptr = ERR6; /* Missing terminating ']' */ + goto FAILED; + } + +#ifdef SUPPORT_UNICODE + if (utf && HAS_EXTRALEN(c)) + { /* Braces are required because the */ + GETCHARLEN(c, ptr, ptr); /* macro generates multiple statements */ + } +#endif + + /* Inside \Q...\E everything is literal except \E */ + + if (inescq) + { + if (c == CHAR_BACKSLASH && ptr[1] == CHAR_E) /* If we are at \E */ + { + inescq = FALSE; /* Reset literal state */ + ptr++; /* Skip the 'E' */ + goto CONTINUE_CLASS; /* Carry on with next char */ + } + goto CHECK_RANGE; /* Could be range if \E follows */ + } + + /* Handle POSIX class names. Perl allows a negation extension of the + form [:^name:]. A square bracket that doesn't match the syntax is + treated as a literal. We also recognize the POSIX constructions + [.ch.] and [=ch=] ("collating elements") and fault them, as Perl + 5.6 and 5.8 do. */ + + if (c == CHAR_LEFT_SQUARE_BRACKET && + (ptr[1] == CHAR_COLON || ptr[1] == CHAR_DOT || + ptr[1] == CHAR_EQUALS_SIGN) && check_posix_syntax(ptr, &tempptr)) + { + BOOL local_negate = FALSE; + int posix_class, taboffset, tabopt; + register const uint8_t *cbits = cb->cbits; + uint8_t pbits[32]; + + if (ptr[1] != CHAR_COLON) + { + *errorcodeptr = ERR13; + goto FAILED; + } + + ptr += 2; + if (*ptr == CHAR_CIRCUMFLEX_ACCENT) + { + local_negate = TRUE; + should_flip_negation = TRUE; /* Note negative special */ + ptr++; + } + + posix_class = check_posix_name(ptr, (int)(tempptr - ptr)); + if (posix_class < 0) + { + *errorcodeptr = ERR30; + goto FAILED; + } + + /* If matching is caseless, upper and lower are converted to + alpha. This relies on the fact that the class table starts with + alpha, lower, upper as the first 3 entries. */ + + if ((options & PCRE2_CASELESS) != 0 && posix_class <= 2) + posix_class = 0; + + /* When PCRE2_UCP is set, some of the POSIX classes are converted to + different escape sequences that use Unicode properties \p or \P. Others + that are not available via \p or \P generate XCL_PROP/XCL_NOTPROP + directly. UCP support is not available unless UTF support is.*/ + +#ifdef SUPPORT_UNICODE + if ((options & PCRE2_UCP) != 0) + { + unsigned int ptype = 0; + int pc = posix_class + ((local_negate)? POSIX_SUBSIZE/2 : 0); + + /* The posix_substitutes table specifies which POSIX classes can be + converted to \p or \P items. This can only happen at top nestling + level, as there will never be a POSIX class in a string that is + substituted for something else. */ + + if (posix_substitutes[pc] != NULL) + { + cb->nestptr[0] = tempptr + 1; + ptr = posix_substitutes[pc] - 1; + goto CONTINUE_CLASS; + } + + /* There are three other classes that generate special property calls + that are recognized only in an XCLASS. */ + + else switch(posix_class) + { + case PC_GRAPH: + ptype = PT_PXGRAPH; + /* Fall through */ + case PC_PRINT: + if (ptype == 0) ptype = PT_PXPRINT; + /* Fall through */ + case PC_PUNCT: + if (ptype == 0) ptype = PT_PXPUNCT; + *class_uchardata++ = local_negate? XCL_NOTPROP : XCL_PROP; + *class_uchardata++ = (PCRE2_UCHAR)ptype; + *class_uchardata++ = 0; + xclass_has_prop = TRUE; + ptr = tempptr + 1; + goto CONTINUE_CLASS; + + /* For the other POSIX classes (ascii, xdigit) we are going to fall + through to the non-UCP case and build a bit map for characters with + code points less than 256. However, if we are in a negated POSIX + class, characters with code points greater than 255 must either all + match or all not match, depending on whether the whole class is not + or is negated. For example, for [[:^ascii:]... they must all match, + whereas for [^[:^xdigit:]... they must not. + + In the special case where there are no xclass items, this is + automatically handled by the use of OP_CLASS or OP_NCLASS, but an + explicit range is needed for OP_XCLASS. Setting a flag here causes + the range to be generated later when it is known that OP_XCLASS is + required. */ + + default: + match_all_or_no_wide_chars |= local_negate; + break; + } + } +#endif /* SUPPORT_UNICODE */ + + /* In the non-UCP case, or when UCP makes no difference, we build the + bit map for the POSIX class in a chunk of local store because we may be + adding and subtracting from it, and we don't want to subtract bits that + may be in the main map already. At the end we or the result into the + bit map that is being built. */ + + posix_class *= 3; + + /* Copy in the first table (always present) */ + + memcpy(pbits, cbits + posix_class_maps[posix_class], + 32 * sizeof(uint8_t)); + + /* If there is a second table, add or remove it as required. */ + + taboffset = posix_class_maps[posix_class + 1]; + tabopt = posix_class_maps[posix_class + 2]; + + if (taboffset >= 0) + { + if (tabopt >= 0) + for (c = 0; c < 32; c++) pbits[c] |= cbits[(int)c + taboffset]; + else + for (c = 0; c < 32; c++) pbits[c] &= ~cbits[(int)c + taboffset]; + } + + /* Now see if we need to remove any special characters. An option + value of 1 removes vertical space and 2 removes underscore. */ + + if (tabopt < 0) tabopt = -tabopt; + if (tabopt == 1) pbits[1] &= ~0x3c; + else if (tabopt == 2) pbits[11] &= 0x7f; + + /* Add the POSIX table or its complement into the main table that is + being built and we are done. */ + + if (local_negate) + for (c = 0; c < 32; c++) classbits[c] |= ~pbits[c]; + else + for (c = 0; c < 32; c++) classbits[c] |= pbits[c]; + + ptr = tempptr + 1; + /* Every class contains at least one < 256 character. */ + class_has_8bitchar = 1; + /* Every class contains at least two characters. */ + class_one_char = 2; + goto CONTINUE_CLASS; /* End of POSIX syntax handling */ + } + + /* Backslash may introduce a single character, or it may introduce one + of the specials, which just set a flag. The sequence \b is a special + case. Inside a class (and only there) it is treated as backspace. We + assume that other escapes have more than one character in them, so + speculatively set both class_has_8bitchar and class_one_char bigger + than one. Unrecognized escapes fall through and are faulted. */ + + if (c == CHAR_BACKSLASH) + { + escape = PRIV(check_escape)(&ptr, cb->end_pattern, &ec, errorcodeptr, + options, TRUE, cb); + if (*errorcodeptr != 0) goto FAILED; + if (escape == 0) /* Escaped single char */ + { + c = ec; +#ifdef EBCDIC + range_is_literal = FALSE; +#endif + } + else if (escape == ESC_b) c = CHAR_BS; /* \b is backspace in a class */ + else if (escape == ESC_N) /* \N is not supported in a class */ + { + *errorcodeptr = ERR71; + goto FAILED; + } + else if (escape == ESC_Q) /* Handle start of quoted string */ + { + if (ptr[1] == CHAR_BACKSLASH && ptr[2] == CHAR_E) + { + ptr += 2; /* avoid empty string */ + } + else inescq = TRUE; + goto CONTINUE_CLASS; + } + else if (escape == ESC_E) goto CONTINUE_CLASS; /* Ignore orphan \E */ + + else /* Handle \d-type escapes */ + { + register const uint8_t *cbits = cb->cbits; + /* Every class contains at least two < 256 characters. */ + class_has_8bitchar++; + /* Every class contains at least two characters. */ + class_one_char += 2; + + switch (escape) + { +#ifdef SUPPORT_UNICODE + case ESC_du: /* These are the values given for \d etc */ + case ESC_DU: /* when PCRE2_UCP is set. We replace the */ + case ESC_wu: /* escape sequence with an appropriate \p */ + case ESC_WU: /* or \P to test Unicode properties instead */ + case ESC_su: /* of the default ASCII testing. This might be */ + case ESC_SU: /* a 2nd-level nesting for [[:<:]] or [[:>:]]. */ + cb->nestptr[1] = cb->nestptr[0]; + cb->nestptr[0] = ptr; + ptr = substitutes[escape - ESC_DU] - 1; /* Just before substitute */ + class_has_8bitchar--; /* Undo! */ + break; +#endif + case ESC_d: + for (c = 0; c < 32; c++) classbits[c] |= cbits[c+cbit_digit]; + break; + + case ESC_D: + should_flip_negation = TRUE; + for (c = 0; c < 32; c++) classbits[c] |= ~cbits[c+cbit_digit]; + break; + + case ESC_w: + for (c = 0; c < 32; c++) classbits[c] |= cbits[c+cbit_word]; + break; + + case ESC_W: + should_flip_negation = TRUE; + for (c = 0; c < 32; c++) classbits[c] |= ~cbits[c+cbit_word]; + break; + + /* Perl 5.004 onwards omitted VT from \s, but restored it at Perl + 5.18. Before PCRE 8.34, we had to preserve the VT bit if it was + previously set by something earlier in the character class. + Luckily, the value of CHAR_VT is 0x0b in both ASCII and EBCDIC, so + we could just adjust the appropriate bit. From PCRE 8.34 we no + longer treat \s and \S specially. */ + + case ESC_s: + for (c = 0; c < 32; c++) classbits[c] |= cbits[c+cbit_space]; + break; + + case ESC_S: + should_flip_negation = TRUE; + for (c = 0; c < 32; c++) classbits[c] |= ~cbits[c+cbit_space]; + break; + + /* The rest apply in both UCP and non-UCP cases. */ + + case ESC_h: + (void)add_list_to_class(classbits, &class_uchardata, options, cb, + PRIV(hspace_list), NOTACHAR); + break; + + case ESC_H: + (void)add_not_list_to_class(classbits, &class_uchardata, options, + cb, PRIV(hspace_list)); + break; + + case ESC_v: + (void)add_list_to_class(classbits, &class_uchardata, options, cb, + PRIV(vspace_list), NOTACHAR); + break; + + case ESC_V: + (void)add_not_list_to_class(classbits, &class_uchardata, options, + cb, PRIV(vspace_list)); + break; + + case ESC_p: + case ESC_P: +#ifdef SUPPORT_UNICODE + { + BOOL negated; + unsigned int ptype = 0, pdata = 0; + if (!get_ucp(&ptr, &negated, &ptype, &pdata, errorcodeptr, cb)) + goto FAILED; + *class_uchardata++ = ((escape == ESC_p) != negated)? + XCL_PROP : XCL_NOTPROP; + *class_uchardata++ = ptype; + *class_uchardata++ = pdata; + xclass_has_prop = TRUE; + class_has_8bitchar--; /* Undo! */ + } + break; +#else + *errorcodeptr = ERR45; + goto FAILED; +#endif + /* Unrecognized escapes are faulted. */ + + default: + *errorcodeptr = ERR7; + goto FAILED; + } + + /* Handled \d-type escape */ + + goto CONTINUE_CLASS; + } + + /* Control gets here if the escape just defined a single character. + This is in c and may be greater than 256. */ + + escape = 0; + } /* End of backslash handling */ + + /* A character may be followed by '-' to form a range. However, Perl does + not permit ']' to be the end of the range. A '-' character at the end is + treated as a literal. Perl ignores orphaned \E sequences entirely. The + code for handling \Q and \E is messy. */ + + CHECK_RANGE: + while (ptr[1] == CHAR_BACKSLASH && ptr[2] == CHAR_E) + { + inescq = FALSE; + ptr += 2; + } + oldptr = ptr; + + /* Remember if \r or \n were explicitly used */ + + if (c == CHAR_CR || c == CHAR_NL) cb->external_flags |= PCRE2_HASCRORLF; + + /* Check for range */ + + if (!inescq && ptr[1] == CHAR_MINUS) + { + uint32_t d; + ptr += 2; + while (*ptr == CHAR_BACKSLASH && ptr[1] == CHAR_E) ptr += 2; + + /* If we hit \Q (not followed by \E) at this point, go into escaped + mode. */ + + while (*ptr == CHAR_BACKSLASH && ptr[1] == CHAR_Q) + { + ptr += 2; + if (*ptr == CHAR_BACKSLASH && ptr[1] == CHAR_E) + { ptr += 2; continue; } + inescq = TRUE; + break; + } + + /* Minus (hyphen) at the end of a class is treated as a literal, so put + back the pointer and jump to handle the character that preceded it. */ + + if (*ptr == CHAR_NULL || (!inescq && *ptr == CHAR_RIGHT_SQUARE_BRACKET)) + { + ptr = oldptr; + goto CLASS_SINGLE_CHARACTER; + } + + /* Otherwise, we have a potential range; pick up the next character */ + +#ifdef SUPPORT_UNICODE + if (utf) + { /* Braces are required because the */ + GETCHARLEN(d, ptr, ptr); /* macro generates multiple statements */ + } + else +#endif + d = *ptr; /* Not UTF mode */ + + /* The second part of a range can be a single-character escape + sequence, but not any of the other escapes. Perl treats a hyphen as a + literal in such circumstances. However, in Perl's warning mode, a + warning is given, so PCRE now faults it as it is almost certainly a + mistake on the user's part. */ + + if (!inescq) + { + if (d == CHAR_BACKSLASH) + { + int descape; + descape = PRIV(check_escape)(&ptr, cb->end_pattern, &d, + errorcodeptr, options, TRUE, cb); + if (*errorcodeptr != 0) goto FAILED; +#ifdef EBCDIC + range_is_literal = FALSE; +#endif + /* 0 means a character was put into d; \b is backspace; any other + special causes an error. */ + + if (descape != 0) + { + if (descape == ESC_b) d = CHAR_BS; else + { + *errorcodeptr = ERR50; + goto FAILED; + } + } + } + + /* A hyphen followed by a POSIX class is treated in the same way. */ + + else if (d == CHAR_LEFT_SQUARE_BRACKET && + (ptr[1] == CHAR_COLON || ptr[1] == CHAR_DOT || + ptr[1] == CHAR_EQUALS_SIGN) && + check_posix_syntax(ptr, &tempptr)) + { + *errorcodeptr = ERR50; + goto FAILED; + } + } + + /* Check that the two values are in the correct order. Optimize + one-character ranges. */ + + if (d < c) + { + *errorcodeptr = ERR8; + goto FAILED; + } + if (d == c) goto CLASS_SINGLE_CHARACTER; /* A few lines below */ + + /* We have found a character range, so single character optimizations + cannot be done anymore. Any value greater than 1 indicates that there + is more than one character. */ + + class_one_char = 2; + + /* Remember an explicit \r or \n, and add the range to the class. */ + + if (d == CHAR_CR || d == CHAR_NL) cb->external_flags |= PCRE2_HASCRORLF; + + /* In an EBCDIC environment, Perl treats alphabetic ranges specially + because there are holes in the encoding, and simply using the range A-Z + (for example) would include the characters in the holes. This applies + only to literal ranges; [\xC1-\xE9] is different to [A-Z]. */ + +#ifdef EBCDIC + if (range_is_literal && + (cb->ctypes[c] & ctype_letter) != 0 && + (cb->ctypes[d] & ctype_letter) != 0 && + (c <= CHAR_z) == (d <= CHAR_z)) + { + uint32_t uc = (c <= CHAR_z)? 0 : 64; + uint32_t C = c - uc; + uint32_t D = d - uc; + + if (C <= CHAR_i) + { + class_has_8bitchar += + add_to_class(classbits, &class_uchardata, options, cb, C + uc, + ((D < CHAR_i)? D : CHAR_i) + uc); + C = CHAR_j; + } + + if (C <= D && C <= CHAR_r) + { + class_has_8bitchar += + add_to_class(classbits, &class_uchardata, options, cb, C + uc, + ((D < CHAR_r)? D : CHAR_r) + uc); + C = CHAR_s; + } + + if (C <= D) + { + class_has_8bitchar += + add_to_class(classbits, &class_uchardata, options, cb, C + uc, + D + uc); + } + } + else +#endif + class_has_8bitchar += + add_to_class(classbits, &class_uchardata, options, cb, c, d); + goto CONTINUE_CLASS; /* Go get the next char in the class */ + } + + /* Handle a single character - we can get here for a normal non-escape + char, or after \ that introduces a single character or for an apparent + range that isn't. Only the value 1 matters for class_one_char, so don't + increase it if it is already 2 or more ... just in case there's a class + with a zillion characters in it. */ + + CLASS_SINGLE_CHARACTER: + if (class_one_char < 2) class_one_char++; + + /* If class_one_char is 1 and xclass_has_prop is false, we have the first + single character in the class, and there have been no prior ranges, or + XCLASS items generated by escapes. If this is the final character in the + class, we can optimize by turning the item into a 1-character OP_CHAR[I] + if it's positive, or OP_NOT[I] if it's negative. In the positive case, it + can cause firstcu to be set. Otherwise, there can be no first char if + this item is first, whatever repeat count may follow. In the case of + reqcu, save the previous value for reinstating. */ + + if (!inescq && +#ifdef SUPPORT_UNICODE + !xclass_has_prop && +#endif + class_one_char == 1 && ptr[1] == CHAR_RIGHT_SQUARE_BRACKET) + { + ptr++; + zeroreqcu = reqcu; + zeroreqcuflags = reqcuflags; + + if (negate_class) + { +#ifdef SUPPORT_UNICODE + int d; +#endif + if (firstcuflags == REQ_UNSET) firstcuflags = REQ_NONE; + zerofirstcu = firstcu; + zerofirstcuflags = firstcuflags; + + /* For caseless UTF mode, check whether this character has more than + one other case. If so, generate a special OP_NOTPROP item instead of + OP_NOTI. */ + +#ifdef SUPPORT_UNICODE + if (utf && (options & PCRE2_CASELESS) != 0 && + (d = UCD_CASESET(c)) != 0) + { + *code++ = OP_NOTPROP; + *code++ = PT_CLIST; + *code++ = d; + } + else +#endif + /* Char has only one other case, or UCP not available */ + + { + *code++ = ((options & PCRE2_CASELESS) != 0)? OP_NOTI: OP_NOT; + code += PUTCHAR(c, code); + } + + /* We are finished with this character class */ + + goto END_CLASS; + } + + /* For a single, positive character, get the value into mcbuffer, and + then we can handle this with the normal one-character code. */ + + mclength = PUTCHAR(c, mcbuffer); + goto ONE_CHAR; + } /* End of 1-char optimization */ + + /* There is more than one character in the class, or an XCLASS item + has been generated. Add this character to the class. */ + + class_has_8bitchar += + add_to_class(classbits, &class_uchardata, options, cb, c, c); + + /* Continue to the next character in the class. Closing square bracket + not within \Q..\E ends the class. A NULL character terminates a + nested substitution string, but may be a data character in the main + pattern (tested at the start of this loop). */ + + CONTINUE_CLASS: + c = *(++ptr); + if (c == CHAR_NULL && cb->nestptr[0] != NULL) + { + ptr = cb->nestptr[0]; + cb->nestptr[0] = cb->nestptr[1]; + cb->nestptr[1] = NULL; + c = *(++ptr); + } + +#ifdef SUPPORT_WIDE_CHARS + /* If any wide characters have been encountered, set xclass = TRUE. Then, + in the pre-compile phase, accumulate the length of the wide characters + and reset the pointer. This is so that very large classes that contain a + zillion wide characters do not overwrite the work space (which is on the + stack). */ + + if (class_uchardata > class_uchardata_base) + { + xclass = TRUE; + if (lengthptr != NULL) + { + *lengthptr += class_uchardata - class_uchardata_base; + class_uchardata = class_uchardata_base; + } + } +#endif + /* An unescaped ] ends the class */ + + if (c == CHAR_RIGHT_SQUARE_BRACKET && !inescq) break; + } /* End of main class-processing loop */ + + /* If this is the first thing in the branch, there can be no first char + setting, whatever the repeat count. Any reqcu setting must remain + unchanged after any kind of repeat. */ + + if (firstcuflags == REQ_UNSET) firstcuflags = REQ_NONE; + zerofirstcu = firstcu; + zerofirstcuflags = firstcuflags; + zeroreqcu = reqcu; + zeroreqcuflags = reqcuflags; + + /* If there are characters with values > 255, or Unicode property settings + (\p or \P), we have to compile an extended class, with its own opcode, + unless there were no property settings and there was a negated special such + as \S in the class, and PCRE2_UCP is not set, because in that case all + characters > 255 are in or not in the class, so any that were explicitly + given as well can be ignored. + + In the UCP case, if certain negated POSIX classes ([:^ascii:] or + [^:xdigit:]) were present in a class, we either have to match or not match + all wide characters (depending on whether the whole class is or is not + negated). This requirement is indicated by match_all_or_no_wide_chars being + true. We do this by including an explicit range, which works in both cases. + + If, when generating an xclass, there are no characters < 256, we can omit + the bitmap in the actual compiled code. */ + +#ifdef SUPPORT_WIDE_CHARS +#ifdef SUPPORT_UNICODE + if (xclass && (xclass_has_prop || !should_flip_negation || + (options & PCRE2_UCP) != 0)) +#elif PCRE2_CODE_UNIT_WIDTH != 8 + if (xclass && (xclass_has_prop || !should_flip_negation)) +#endif + { + if (match_all_or_no_wide_chars) + { + *class_uchardata++ = XCL_RANGE; + class_uchardata += PRIV(ord2utf)(0x100, class_uchardata); + class_uchardata += PRIV(ord2utf)(MAX_UTF_CODE_POINT, class_uchardata); + } + *class_uchardata++ = XCL_END; /* Marks the end of extra data */ + *code++ = OP_XCLASS; + code += LINK_SIZE; + *code = negate_class? XCL_NOT:0; + if (xclass_has_prop) *code |= XCL_HASPROP; + + /* If the map is required, move up the extra data to make room for it; + otherwise just move the code pointer to the end of the extra data. */ + + if (class_has_8bitchar > 0) + { + *code++ |= XCL_MAP; + memmove(code + (32 / sizeof(PCRE2_UCHAR)), code, + CU2BYTES(class_uchardata - code)); + if (negate_class && !xclass_has_prop) + for (c = 0; c < 32; c++) classbits[c] = ~classbits[c]; + memcpy(code, classbits, 32); + code = class_uchardata + (32 / sizeof(PCRE2_UCHAR)); + } + else code = class_uchardata; + + /* Now fill in the complete length of the item */ + + PUT(previous, 1, (int)(code - previous)); + break; /* End of class handling */ + } +#endif + + /* If there are no characters > 255, or they are all to be included or + excluded, set the opcode to OP_CLASS or OP_NCLASS, depending on whether the + whole class was negated and whether there were negative specials such as \S + (non-UCP) in the class. Then copy the 32-byte map into the code vector, + negating it if necessary. */ + + *code++ = (negate_class == should_flip_negation) ? OP_CLASS : OP_NCLASS; + if (lengthptr == NULL) /* Save time in the pre-compile phase */ + { + if (negate_class) + for (c = 0; c < 32; c++) classbits[c] = ~classbits[c]; + memcpy(code, classbits, 32); + } + code += 32 / sizeof(PCRE2_UCHAR); + + END_CLASS: + break; + + + /* ===================================================================*/ + /* Various kinds of repeat; '{' is not necessarily a quantifier, but this + has been tested above. */ + + case CHAR_LEFT_CURLY_BRACKET: + if (!is_quantifier) goto NORMAL_CHAR; + ptr = read_repeat_counts(ptr+1, &repeat_min, &repeat_max, errorcodeptr); + if (*errorcodeptr != 0) goto FAILED; + goto REPEAT; + + case CHAR_ASTERISK: + repeat_min = 0; + repeat_max = -1; + goto REPEAT; + + case CHAR_PLUS: + repeat_min = 1; + repeat_max = -1; + goto REPEAT; + + case CHAR_QUESTION_MARK: + repeat_min = 0; + repeat_max = 1; + + REPEAT: + if (previous == NULL) + { + *errorcodeptr = ERR9; + goto FAILED; + } + + if (repeat_min == 0) + { + firstcu = zerofirstcu; /* Adjust for zero repeat */ + firstcuflags = zerofirstcuflags; + reqcu = zeroreqcu; /* Ditto */ + reqcuflags = zeroreqcuflags; + } + + /* Remember whether this is a variable length repeat */ + + reqvary = (repeat_min == repeat_max)? 0 : REQ_VARY; + + op_type = 0; /* Default single-char op codes */ + possessive_quantifier = FALSE; /* Default not possessive quantifier */ + + /* Save start of previous item, in case we have to move it up in order to + insert something before it. */ + + tempcode = previous; + + /* Before checking for a possessive quantifier, we must skip over + whitespace and comments in extended mode because Perl allows white space at + this point. */ + + if ((options & PCRE2_EXTENDED) != 0) + { + ptr++; + for (;;) + { + while (MAX_255(*ptr) && (cb->ctypes[*ptr] & ctype_space) != 0) ptr++; + if (*ptr != CHAR_NUMBER_SIGN) break; + ptr++; + while (ptr < cb->end_pattern) + { + if (IS_NEWLINE(ptr)) /* For non-fixed-length newline cases, */ + { /* IS_NEWLINE sets cb->nllen. */ + ptr += cb->nllen; + break; + } + ptr++; +#ifdef SUPPORT_UNICODE + if (utf) FORWARDCHAR(ptr); +#endif + } /* Loop for comment characters */ + } /* Loop for multiple comments */ + ptr--; /* Last code unit of previous character. */ + } + + /* If the next character is '+', we have a possessive quantifier. This + implies greediness, whatever the setting of the PCRE2_UNGREEDY option. + If the next character is '?' this is a minimizing repeat, by default, + but if PCRE2_UNGREEDY is set, it works the other way round. We change the + repeat type to the non-default. */ + + if (ptr[1] == CHAR_PLUS) + { + repeat_type = 0; /* Force greedy */ + possessive_quantifier = TRUE; + ptr++; + } + else if (ptr[1] == CHAR_QUESTION_MARK) + { + repeat_type = greedy_non_default; + ptr++; + } + else repeat_type = greedy_default; + + /* If the repeat is {1} we can ignore it. */ + + if (repeat_max == 1 && repeat_min == 1) goto END_REPEAT; + + /* If previous was a recursion call, wrap it in atomic brackets so that + previous becomes the atomic group. All recursions were so wrapped in the + past, but it no longer happens for non-repeated recursions. In fact, the + repeated ones could be re-implemented independently so as not to need this, + but for the moment we rely on the code for repeating groups. */ + + if (*previous == OP_RECURSE) + { + memmove(previous + 1 + LINK_SIZE, previous, CU2BYTES(1 + LINK_SIZE)); + *previous = OP_ONCE; + PUT(previous, 1, 2 + 2*LINK_SIZE); + previous[2 + 2*LINK_SIZE] = OP_KET; + PUT(previous, 3 + 2*LINK_SIZE, 2 + 2*LINK_SIZE); + code += 2 + 2 * LINK_SIZE; + length_prevgroup = 3 + 3*LINK_SIZE; + } + + /* Now handle repetition for the different types of item. */ + + /* If previous was a character or negated character match, abolish the item + and generate a repeat item instead. If a char item has a minimum of more + than one, ensure that it is set in reqcu - it might not be if a sequence + such as x{3} is the first thing in a branch because the x will have gone + into firstcu instead. */ + + if (*previous == OP_CHAR || *previous == OP_CHARI + || *previous == OP_NOT || *previous == OP_NOTI) + { + switch (*previous) + { + default: /* Make compiler happy. */ + case OP_CHAR: op_type = OP_STAR - OP_STAR; break; + case OP_CHARI: op_type = OP_STARI - OP_STAR; break; + case OP_NOT: op_type = OP_NOTSTAR - OP_STAR; break; + case OP_NOTI: op_type = OP_NOTSTARI - OP_STAR; break; + } + + /* Deal with UTF characters that take up more than one code unit. It's + easier to write this out separately than try to macrify it. Use c to + hold the length of the character in code units, plus UTF_LENGTH to flag + that it's a length rather than a small character. */ + +#ifdef MAYBE_UTF_MULTI + if (utf && NOT_FIRSTCU(code[-1])) + { + PCRE2_UCHAR *lastchar = code - 1; + BACKCHAR(lastchar); + c = (int)(code - lastchar); /* Length of UTF character */ + memcpy(utf_units, lastchar, CU2BYTES(c)); /* Save the char */ + c |= UTF_LENGTH; /* Flag c as a length */ + } + else +#endif /* MAYBE_UTF_MULTI */ + + /* Handle the case of a single charater - either with no UTF support, or + with UTF disabled, or for a single-code-unit UTF character. */ + { + c = code[-1]; + if (*previous <= OP_CHARI && repeat_min > 1) + { + reqcu = c; + reqcuflags = req_caseopt | cb->req_varyopt; + } + } + + goto OUTPUT_SINGLE_REPEAT; /* Code shared with single character types */ + } + + /* If previous was a character type match (\d or similar), abolish it and + create a suitable repeat item. The code is shared with single-character + repeats by setting op_type to add a suitable offset into repeat_type. Note + the the Unicode property types will be present only when SUPPORT_UNICODE is + defined, but we don't wrap the little bits of code here because it just + makes it horribly messy. */ + + else if (*previous < OP_EODN) + { + PCRE2_UCHAR *oldcode; + int prop_type, prop_value; + op_type = OP_TYPESTAR - OP_STAR; /* Use type opcodes */ + c = *previous; /* Save previous opcode */ + if (c == OP_PROP || c == OP_NOTPROP) + { + prop_type = previous[1]; + prop_value = previous[2]; + } + else + { + /* Come here from just above with a character in c */ + OUTPUT_SINGLE_REPEAT: + prop_type = prop_value = -1; + } + + /* At this point we either have prop_type == prop_value == -1 and either + a code point or a character type that is not OP_[NOT]PROP in c, or we + have OP_[NOT]PROP in c and prop_type/prop_value not negative. */ + + oldcode = code; /* Save where we were */ + code = previous; /* Usually overwrite previous item */ + + /* If the maximum is zero then the minimum must also be zero; Perl allows + this case, so we do too - by simply omitting the item altogether. */ + + if (repeat_max == 0) goto END_REPEAT; + + /* Combine the op_type with the repeat_type */ + + repeat_type += op_type; + + /* A minimum of zero is handled either as the special case * or ?, or as + an UPTO, with the maximum given. */ + + if (repeat_min == 0) + { + if (repeat_max == -1) *code++ = OP_STAR + repeat_type; + else if (repeat_max == 1) *code++ = OP_QUERY + repeat_type; + else + { + *code++ = OP_UPTO + repeat_type; + PUT2INC(code, 0, repeat_max); + } + } + + /* A repeat minimum of 1 is optimized into some special cases. If the + maximum is unlimited, we use OP_PLUS. Otherwise, the original item is + left in place and, if the maximum is greater than 1, we use OP_UPTO with + one less than the maximum. */ + + else if (repeat_min == 1) + { + if (repeat_max == -1) + *code++ = OP_PLUS + repeat_type; + else + { + code = oldcode; /* Leave previous item in place */ + if (repeat_max == 1) goto END_REPEAT; + *code++ = OP_UPTO + repeat_type; + PUT2INC(code, 0, repeat_max - 1); + } + } + + /* The case {n,n} is just an EXACT, while the general case {n,m} is + handled as an EXACT followed by an UPTO or STAR or QUERY. */ + + else + { + *code++ = OP_EXACT + op_type; /* NB EXACT doesn't have repeat_type */ + PUT2INC(code, 0, repeat_min); + + /* Unless repeat_max equals repeat_min, fill in the data for EXACT, and + then generate the second opcode. In UTF mode, multi-code-unit + characters have their length in c, with the UTF_LENGTH bit as a flag, + and the code units in utf_units. For a repeated Unicode property match, + there are two extra values that define the required property, and c + never has the UTF_LENGTH bit set. */ + + if (repeat_max != repeat_min) + { +#ifdef MAYBE_UTF_MULTI + if (utf && (c & UTF_LENGTH) != 0) + { + memcpy(code, utf_units, CU2BYTES(c & 7)); + code += c & 7; + } + else +#endif /* MAYBE_UTF_MULTI */ + { + *code++ = c; + if (prop_type >= 0) + { + *code++ = prop_type; + *code++ = prop_value; + } + } + + /* Now set up the following opcode */ + + if (repeat_max < 0) *code++ = OP_STAR + repeat_type; else + { + repeat_max -= repeat_min; + if (repeat_max == 1) + { + *code++ = OP_QUERY + repeat_type; + } + else + { + *code++ = OP_UPTO + repeat_type; + PUT2INC(code, 0, repeat_max); + } + } + } + } + + /* Fill in the character or character type for the final opcode. */ + +#ifdef MAYBE_UTF_MULTI + if (utf && (c & UTF_LENGTH) != 0) + { + memcpy(code, utf_units, CU2BYTES(c & 7)); + code += c & 7; + } + else +#endif /* MAYBEW_UTF_MULTI */ + { + *code++ = c; + if (prop_type >= 0) + { + *code++ = prop_type; + *code++ = prop_value; + } + } + } + + /* If previous was a character class or a back reference, we put the repeat + stuff after it, but just skip the item if the repeat was {0,0}. */ + + else if (*previous == OP_CLASS || *previous == OP_NCLASS || +#ifdef SUPPORT_WIDE_CHARS + *previous == OP_XCLASS || +#endif + *previous == OP_REF || *previous == OP_REFI || + *previous == OP_DNREF || *previous == OP_DNREFI) + { + if (repeat_max == 0) + { + code = previous; + goto END_REPEAT; + } + + if (repeat_min == 0 && repeat_max == -1) + *code++ = OP_CRSTAR + repeat_type; + else if (repeat_min == 1 && repeat_max == -1) + *code++ = OP_CRPLUS + repeat_type; + else if (repeat_min == 0 && repeat_max == 1) + *code++ = OP_CRQUERY + repeat_type; + else + { + *code++ = OP_CRRANGE + repeat_type; + PUT2INC(code, 0, repeat_min); + if (repeat_max == -1) repeat_max = 0; /* 2-byte encoding for max */ + PUT2INC(code, 0, repeat_max); + } + } + + /* If previous was a bracket group, we may have to replicate it in certain + cases. Note that at this point we can encounter only the "basic" bracket + opcodes such as BRA and CBRA, as this is the place where they get converted + into the more special varieties such as BRAPOS and SBRA. A test for >= + OP_ASSERT and <= OP_COND includes ASSERT, ASSERT_NOT, ASSERTBACK, + ASSERTBACK_NOT, ONCE, ONCE_NC, BRA, BRAPOS, CBRA, CBRAPOS, and COND. + Originally, PCRE did not allow repetition of assertions, but now it does, + for Perl compatibility. */ + + else if (*previous >= OP_ASSERT && *previous <= OP_COND) + { + register int i; + int len = (int)(code - previous); + PCRE2_UCHAR *bralink = NULL; + PCRE2_UCHAR *brazeroptr = NULL; + + /* Repeating a DEFINE group (or any group where the condition is always + FALSE and there is only one branch) is pointless, but Perl allows the + syntax, so we just ignore the repeat. */ + + if (*previous == OP_COND && previous[LINK_SIZE+1] == OP_FALSE && + previous[GET(previous, 1)] != OP_ALT) + goto END_REPEAT; + + /* There is no sense in actually repeating assertions. The only potential + use of repetition is in cases when the assertion is optional. Therefore, + if the minimum is greater than zero, just ignore the repeat. If the + maximum is not zero or one, set it to 1. */ + + if (*previous < OP_ONCE) /* Assertion */ + { + if (repeat_min > 0) goto END_REPEAT; + if (repeat_max < 0 || repeat_max > 1) repeat_max = 1; + } + + /* The case of a zero minimum is special because of the need to stick + OP_BRAZERO in front of it, and because the group appears once in the + data, whereas in other cases it appears the minimum number of times. For + this reason, it is simplest to treat this case separately, as otherwise + the code gets far too messy. There are several special subcases when the + minimum is zero. */ + + if (repeat_min == 0) + { + /* If the maximum is also zero, we used to just omit the group from the + output altogether, like this: + + ** if (repeat_max == 0) + ** { + ** code = previous; + ** goto END_REPEAT; + ** } + + However, that fails when a group or a subgroup within it is referenced + as a subroutine from elsewhere in the pattern, so now we stick in + OP_SKIPZERO in front of it so that it is skipped on execution. As we + don't have a list of which groups are referenced, we cannot do this + selectively. + + If the maximum is 1 or unlimited, we just have to stick in the BRAZERO + and do no more at this point. */ + + if (repeat_max <= 1) /* Covers 0, 1, and unlimited */ + { + memmove(previous + 1, previous, CU2BYTES(len)); + code++; + if (repeat_max == 0) + { + *previous++ = OP_SKIPZERO; + goto END_REPEAT; + } + brazeroptr = previous; /* Save for possessive optimizing */ + *previous++ = OP_BRAZERO + repeat_type; + } + + /* If the maximum is greater than 1 and limited, we have to replicate + in a nested fashion, sticking OP_BRAZERO before each set of brackets. + The first one has to be handled carefully because it's the original + copy, which has to be moved up. The remainder can be handled by code + that is common with the non-zero minimum case below. We have to + adjust the value or repeat_max, since one less copy is required. */ + + else + { + int offset; + memmove(previous + 2 + LINK_SIZE, previous, CU2BYTES(len)); + code += 2 + LINK_SIZE; + *previous++ = OP_BRAZERO + repeat_type; + *previous++ = OP_BRA; + + /* We chain together the bracket offset fields that have to be + filled in later when the ends of the brackets are reached. */ + + offset = (bralink == NULL)? 0 : (int)(previous - bralink); + bralink = previous; + PUTINC(previous, 0, offset); + } + + repeat_max--; + } + + /* If the minimum is greater than zero, replicate the group as many + times as necessary, and adjust the maximum to the number of subsequent + copies that we need. */ + + else + { + if (repeat_min > 1) + { + /* In the pre-compile phase, we don't actually do the replication. We + just adjust the length as if we had. Do some paranoid checks for + potential integer overflow. The INT64_OR_DOUBLE type is a 64-bit + integer type when available, otherwise double. */ + + if (lengthptr != NULL) + { + size_t delta = (repeat_min - 1)*length_prevgroup; + if ((INT64_OR_DOUBLE)(repeat_min - 1)* + (INT64_OR_DOUBLE)length_prevgroup > + (INT64_OR_DOUBLE)INT_MAX || + OFLOW_MAX - *lengthptr < delta) + { + *errorcodeptr = ERR20; + goto FAILED; + } + *lengthptr += delta; + } + + /* This is compiling for real. If there is a set first byte for + the group, and we have not yet set a "required byte", set it. */ + + else + { + if (groupsetfirstcu && reqcuflags < 0) + { + reqcu = firstcu; + reqcuflags = firstcuflags; + } + for (i = 1; i < repeat_min; i++) + { + memcpy(code, previous, CU2BYTES(len)); + code += len; + } + } + } + + if (repeat_max > 0) repeat_max -= repeat_min; + } + + /* This code is common to both the zero and non-zero minimum cases. If + the maximum is limited, it replicates the group in a nested fashion, + remembering the bracket starts on a stack. In the case of a zero minimum, + the first one was set up above. In all cases the repeat_max now specifies + the number of additional copies needed. Again, we must remember to + replicate entries on the forward reference list. */ + + if (repeat_max >= 0) + { + /* In the pre-compile phase, we don't actually do the replication. We + just adjust the length as if we had. For each repetition we must add 1 + to the length for BRAZERO and for all but the last repetition we must + add 2 + 2*LINKSIZE to allow for the nesting that occurs. Do some + paranoid checks to avoid integer overflow. The INT64_OR_DOUBLE type is + a 64-bit integer type when available, otherwise double. */ + + if (lengthptr != NULL && repeat_max > 0) + { + size_t delta = repeat_max*(length_prevgroup + 1 + 2 + 2*LINK_SIZE) - + 2 - 2*LINK_SIZE; /* Last one doesn't nest */ + if ((INT64_OR_DOUBLE)repeat_max * + (INT64_OR_DOUBLE)(length_prevgroup + 1 + 2 + 2*LINK_SIZE) + > (INT64_OR_DOUBLE)INT_MAX || + OFLOW_MAX - *lengthptr < delta) + { + *errorcodeptr = ERR20; + goto FAILED; + } + *lengthptr += delta; + } + + /* This is compiling for real */ + + else for (i = repeat_max - 1; i >= 0; i--) + { + *code++ = OP_BRAZERO + repeat_type; + + /* All but the final copy start a new nesting, maintaining the + chain of brackets outstanding. */ + + if (i != 0) + { + int offset; + *code++ = OP_BRA; + offset = (bralink == NULL)? 0 : (int)(code - bralink); + bralink = code; + PUTINC(code, 0, offset); + } + + memcpy(code, previous, CU2BYTES(len)); + code += len; + } + + /* Now chain through the pending brackets, and fill in their length + fields (which are holding the chain links pro tem). */ + + while (bralink != NULL) + { + int oldlinkoffset; + int offset = (int)(code - bralink + 1); + PCRE2_UCHAR *bra = code - offset; + oldlinkoffset = GET(bra, 1); + bralink = (oldlinkoffset == 0)? NULL : bralink - oldlinkoffset; + *code++ = OP_KET; + PUTINC(code, 0, offset); + PUT(bra, 1, offset); + } + } + + /* If the maximum is unlimited, set a repeater in the final copy. For + ONCE brackets, that's all we need to do. However, possessively repeated + ONCE brackets can be converted into non-capturing brackets, as the + behaviour of (?:xx)++ is the same as (?>xx)++ and this saves having to + deal with possessive ONCEs specially. + + Otherwise, when we are doing the actual compile phase, check to see + whether this group is one that could match an empty string. If so, + convert the initial operator to the S form (e.g. OP_BRA -> OP_SBRA) so + that runtime checking can be done. [This check is also applied to ONCE + groups at runtime, but in a different way.] + + Then, if the quantifier was possessive and the bracket is not a + conditional, we convert the BRA code to the POS form, and the KET code to + KETRPOS. (It turns out to be convenient at runtime to detect this kind of + subpattern at both the start and at the end.) The use of special opcodes + makes it possible to reduce greatly the stack usage in pcre2_match(). If + the group is preceded by OP_BRAZERO, convert this to OP_BRAPOSZERO. + + Then, if the minimum number of matches is 1 or 0, cancel the possessive + flag so that the default action below, of wrapping everything inside + atomic brackets, does not happen. When the minimum is greater than 1, + there will be earlier copies of the group, and so we still have to wrap + the whole thing. */ + + else + { + PCRE2_UCHAR *ketcode = code - 1 - LINK_SIZE; + PCRE2_UCHAR *bracode = ketcode - GET(ketcode, 1); + + /* Convert possessive ONCE brackets to non-capturing */ + + if ((*bracode == OP_ONCE || *bracode == OP_ONCE_NC) && + possessive_quantifier) *bracode = OP_BRA; + + /* For non-possessive ONCE brackets, all we need to do is to + set the KET. */ + + if (*bracode == OP_ONCE || *bracode == OP_ONCE_NC) + *ketcode = OP_KETRMAX + repeat_type; + + /* Handle non-ONCE brackets and possessive ONCEs (which have been + converted to non-capturing above). */ + + else + { + /* In the compile phase, check whether the group could match an empty + string. */ + + if (lengthptr == NULL) + { + PCRE2_UCHAR *scode = bracode; + do + { + int count = 0; + int rc = could_be_empty_branch(scode, ketcode, utf, cb, FALSE, + NULL, &count); + if (rc < 0) + { + *errorcodeptr = ERR86; + goto FAILED; + } + if (rc > 0) + { + *bracode += OP_SBRA - OP_BRA; + break; + } + scode += GET(scode, 1); + } + while (*scode == OP_ALT); + + /* A conditional group with only one branch has an implicit empty + alternative branch. */ + + if (*bracode == OP_COND && bracode[GET(bracode,1)] != OP_ALT) + *bracode = OP_SCOND; + } + + /* Handle possessive quantifiers. */ + + if (possessive_quantifier) + { + /* For COND brackets, we wrap the whole thing in a possessively + repeated non-capturing bracket, because we have not invented POS + versions of the COND opcodes. */ + + if (*bracode == OP_COND || *bracode == OP_SCOND) + { + int nlen = (int)(code - bracode); + memmove(bracode + 1 + LINK_SIZE, bracode, CU2BYTES(nlen)); + code += 1 + LINK_SIZE; + nlen += 1 + LINK_SIZE; + *bracode = (*bracode == OP_COND)? OP_BRAPOS : OP_SBRAPOS; + *code++ = OP_KETRPOS; + PUTINC(code, 0, nlen); + PUT(bracode, 1, nlen); + } + + /* For non-COND brackets, we modify the BRA code and use KETRPOS. */ + + else + { + *bracode += 1; /* Switch to xxxPOS opcodes */ + *ketcode = OP_KETRPOS; + } + + /* If the minimum is zero, mark it as possessive, then unset the + possessive flag when the minimum is 0 or 1. */ + + if (brazeroptr != NULL) *brazeroptr = OP_BRAPOSZERO; + if (repeat_min < 2) possessive_quantifier = FALSE; + } + + /* Non-possessive quantifier */ + + else *ketcode = OP_KETRMAX + repeat_type; + } + } + } + + /* If previous is OP_FAIL, it was generated by an empty class [] + (PCRE2_ALLOW_EMPTY_CLASS is set). The other ways in which OP_FAIL can be + generated, that is by (*FAIL) or (?!), set previous to NULL, which gives a + "nothing to repeat" error above. We can just ignore the repeat in empty + class case. */ + + else if (*previous == OP_FAIL) goto END_REPEAT; + + /* Else there's some kind of shambles */ + + else + { + *errorcodeptr = ERR10; + goto FAILED; + } + + /* If the character following a repeat is '+', possessive_quantifier is + TRUE. For some opcodes, there are special alternative opcodes for this + case. For anything else, we wrap the entire repeated item inside OP_ONCE + brackets. Logically, the '+' notation is just syntactic sugar, taken from + Sun's Java package, but the special opcodes can optimize it. + + Some (but not all) possessively repeated subpatterns have already been + completely handled in the code just above. For them, possessive_quantifier + is always FALSE at this stage. Note that the repeated item starts at + tempcode, not at previous, which might be the first part of a string whose + (former) last char we repeated. */ + + if (possessive_quantifier) + { + int len; + + /* Possessifying an EXACT quantifier has no effect, so we can ignore it. + However, QUERY, STAR, or UPTO may follow (for quantifiers such as {5,6}, + {5,}, or {5,10}). We skip over an EXACT item; if the length of what + remains is greater than zero, there's a further opcode that can be + handled. If not, do nothing, leaving the EXACT alone. */ + + switch(*tempcode) + { + case OP_TYPEEXACT: + tempcode += PRIV(OP_lengths)[*tempcode] + + ((tempcode[1 + IMM2_SIZE] == OP_PROP + || tempcode[1 + IMM2_SIZE] == OP_NOTPROP)? 2 : 0); + break; + + /* CHAR opcodes are used for exacts whose count is 1. */ + + case OP_CHAR: + case OP_CHARI: + case OP_NOT: + case OP_NOTI: + case OP_EXACT: + case OP_EXACTI: + case OP_NOTEXACT: + case OP_NOTEXACTI: + tempcode += PRIV(OP_lengths)[*tempcode]; +#ifdef SUPPORT_UNICODE + if (utf && HAS_EXTRALEN(tempcode[-1])) + tempcode += GET_EXTRALEN(tempcode[-1]); +#endif + break; + + /* For the class opcodes, the repeat operator appears at the end; + adjust tempcode to point to it. */ + + case OP_CLASS: + case OP_NCLASS: + tempcode += 1 + 32/sizeof(PCRE2_UCHAR); + break; + +#ifdef SUPPORT_WIDE_CHARS + case OP_XCLASS: + tempcode += GET(tempcode, 1); + break; +#endif + } + + /* If tempcode is equal to code (which points to the end of the repeated + item), it means we have skipped an EXACT item but there is no following + QUERY, STAR, or UPTO; the value of len will be 0, and we do nothing. In + all other cases, tempcode will be pointing to the repeat opcode, and will + be less than code, so the value of len will be greater than 0. */ + + len = (int)(code - tempcode); + if (len > 0) + { + unsigned int repcode = *tempcode; + + /* There is a table for possessifying opcodes, all of which are less + than OP_CALLOUT. A zero entry means there is no possessified version. + */ + + if (repcode < OP_CALLOUT && opcode_possessify[repcode] > 0) + *tempcode = opcode_possessify[repcode]; + + /* For opcode without a special possessified version, wrap the item in + ONCE brackets. */ + + else + { + memmove(tempcode + 1 + LINK_SIZE, tempcode, CU2BYTES(len)); + code += 1 + LINK_SIZE; + len += 1 + LINK_SIZE; + tempcode[0] = OP_ONCE; + *code++ = OP_KET; + PUTINC(code, 0, len); + PUT(tempcode, 1, len); + } + } + } + + /* In all case we no longer have a previous item. We also set the + "follows varying string" flag for subsequently encountered reqcus if + it isn't already set and we have just passed a varying length item. */ + + END_REPEAT: + previous = NULL; + cb->req_varyopt |= reqvary; + break; + + + /* ===================================================================*/ + /* Start of nested parenthesized sub-expression, or lookahead or lookbehind + or option setting or condition or all the other extended parenthesis forms. + We must save the current high-water-mark for the forward reference list so + that we know where they start for this group. However, because the list may + be extended when there are very many forward references (usually the result + of a replicated inner group), we must use an offset rather than an absolute + address. Note that (?# comments are dealt with at the top of the loop; + they do not get this far. */ + + case CHAR_LEFT_PARENTHESIS: + ptr++; + + /* Deal with various "verbs" that can be introduced by '*'. */ + + if (ptr[0] == CHAR_ASTERISK && (ptr[1] == ':' + || (MAX_255(ptr[1]) && ((cb->ctypes[ptr[1]] & ctype_letter) != 0)))) + { + int i, namelen; + int arglen = 0; + const char *vn = verbnames; + PCRE2_SPTR name = ptr + 1; + PCRE2_SPTR arg = NULL; + previous = NULL; + ptr++; + + /* Increment ptr, set namelen, check length */ + + READ_NAME(ctype_letter, ERR60, *errorcodeptr); + + /* It appears that Perl allows any characters whatsoever, other than + a closing parenthesis, to appear in arguments, so we no longer insist on + letters, digits, and underscores. Perl does not, however, do any + interpretation within arguments, and has no means of including a closing + parenthesis. PCRE supports escape processing but only when it is + requested by an option. Note that check_escape() will not return values + greater than the code unit maximum when not in UTF mode. */ + + if (*ptr == CHAR_COLON) + { + arg = ++ptr; + + if ((options & PCRE2_ALT_VERBNAMES) == 0) + { + arglen = 0; + while (ptr < cb->end_pattern && *ptr != CHAR_RIGHT_PARENTHESIS) + { + ptr++; /* Check length as we go */ + arglen++; /* along, to avoid the */ + if ((unsigned int)arglen > MAX_MARK) /* possibility of overflow. */ + { + *errorcodeptr = ERR76; + goto FAILED; + } + } + } + else + { + /* The length check is in process_verb_names() */ + arglen = process_verb_name(&ptr, NULL, errorcodeptr, options, + utf, cb); + if (arglen < 0) goto FAILED; + } + } + + if (*ptr != CHAR_RIGHT_PARENTHESIS) + { + *errorcodeptr = ERR60; + goto FAILED; + } + + /* Scan the table of verb names */ + + for (i = 0; i < verbcount; i++) + { + if (namelen == verbs[i].len && + PRIV(strncmp_c8)(name, vn, namelen) == 0) + { + int setverb; + + /* Check for open captures before ACCEPT and convert it to + ASSERT_ACCEPT if in an assertion. */ + + if (verbs[i].op == OP_ACCEPT) + { + open_capitem *oc; + if (arglen != 0) + { + *errorcodeptr = ERR59; + goto FAILED; + } + cb->had_accept = TRUE; + + /* In the first pass, just accumulate the length required; + otherwise hitting (*ACCEPT) inside many nested parentheses can + cause workspace overflow. */ + + for (oc = cb->open_caps; oc != NULL; oc = oc->next) + { + if (lengthptr != NULL) + { + *lengthptr += CU2BYTES(1) + IMM2_SIZE; + } + else + { + *code++ = OP_CLOSE; + PUT2INC(code, 0, oc->number); + } + } + setverb = *code++ = + (cb->assert_depth > 0)? OP_ASSERT_ACCEPT : OP_ACCEPT; + + /* Do not set firstcu after *ACCEPT */ + if (firstcuflags == REQ_UNSET) firstcuflags = REQ_NONE; + } + + /* Handle other cases with/without an argument */ + + else if (arglen == 0) /* There is no argument */ + { + if (verbs[i].op < 0) /* Argument is mandatory */ + { + *errorcodeptr = ERR66; + goto FAILED; + } + setverb = *code++ = verbs[i].op; + } + + else /* An argument is present */ + { + if (verbs[i].op_arg < 0) /* Argument is forbidden */ + { + *errorcodeptr = ERR59; + goto FAILED; + } + setverb = *code++ = verbs[i].op_arg; + + /* Arguments can be very long, especially in 16- and 32-bit modes, + and can overflow the workspace in the first pass. Instead of + putting the argument into memory, we just update the length counter + and set up an empty argument. */ + + if (lengthptr != NULL) + { + *lengthptr += arglen; + *code++ = 0; + } + else + { + *code++ = arglen; + if ((options & PCRE2_ALT_VERBNAMES) != 0) + { + PCRE2_UCHAR *memcode = code; /* code is "register" */ + (void)process_verb_name(&arg, &memcode, errorcodeptr, options, + utf, cb); + code = memcode; + } + else /* No argument processing */ + { + memcpy(code, arg, CU2BYTES(arglen)); + code += arglen; + } + } + + *code++ = 0; + } + + switch (setverb) + { + case OP_THEN: + case OP_THEN_ARG: + cb->external_flags |= PCRE2_HASTHEN; + break; + + case OP_PRUNE: + case OP_PRUNE_ARG: + case OP_SKIP: + case OP_SKIP_ARG: + cb->had_pruneorskip = TRUE; + break; + } + + break; /* Found verb, exit loop */ + } + + vn += verbs[i].len + 1; + } + + if (i < verbcount) continue; /* Successfully handled a verb */ + *errorcodeptr = ERR60; /* Verb not recognized */ + goto FAILED; + } + + /* Initialization for "real" parentheses */ + + newoptions = options; + skipunits = 0; + bravalue = OP_CBRA; + reset_bracount = FALSE; + + /* Deal with the extended parentheses; all are introduced by '?', and the + appearance of any of them means that this is not a capturing group. */ + + if (*ptr == CHAR_QUESTION_MARK) + { + int i, count; + int namelen; /* Must be signed */ + uint32_t index; + uint32_t set, unset, *optset; + named_group *ng; + PCRE2_SPTR name; + PCRE2_UCHAR *slot; + + switch (*(++ptr)) + { + /* ------------------------------------------------------------ */ + case CHAR_VERTICAL_LINE: /* Reset capture count for each branch */ + reset_bracount = TRUE; + /* Fall through */ + + /* ------------------------------------------------------------ */ + case CHAR_COLON: /* Non-capturing bracket */ + bravalue = OP_BRA; + ptr++; + break; + + /* ------------------------------------------------------------ */ + case CHAR_LEFT_PARENTHESIS: + bravalue = OP_COND; /* Conditional group */ + tempptr = ptr; + + /* A condition can be an assertion, a number (referring to a numbered + group's having been set), a name (referring to a named group), or 'R', + referring to recursion. R and R&name are also permitted for + recursion tests. + + There are ways of testing a named group: (?(name)) is used by Python; + Perl 5.10 onwards uses (?() or (?('name')). + + There is one unfortunate ambiguity, caused by history. 'R' can be the + recursive thing or the name 'R' (and similarly for 'R' followed by + digits). We look for a name first; if not found, we try the other case. + + For compatibility with auto-callouts, we allow a callout to be + specified before a condition that is an assertion. First, check for the + syntax of a callout; if found, adjust the temporary pointer that is + used to check for an assertion condition. That's all that is needed! */ + + if (ptr[1] == CHAR_QUESTION_MARK && ptr[2] == CHAR_C) + { + if (IS_DIGIT(ptr[3]) || ptr[3] == CHAR_RIGHT_PARENTHESIS) + { + for (i = 3;; i++) if (!IS_DIGIT(ptr[i])) break; + if (ptr[i] == CHAR_RIGHT_PARENTHESIS) + tempptr += i + 1; + } + else + { + uint32_t delimiter = 0; + for (i = 0; PRIV(callout_start_delims)[i] != 0; i++) + { + if (ptr[3] == PRIV(callout_start_delims)[i]) + { + delimiter = PRIV(callout_end_delims)[i]; + break; + } + } + if (delimiter != 0) + { + for (i = 4; ptr + i < cb->end_pattern; i++) + { + if (ptr[i] == delimiter) + { + if (ptr[i+1] == delimiter) i++; + else + { + if (ptr[i+1] == CHAR_RIGHT_PARENTHESIS) tempptr += i + 2; + break; + } + } + } + } + } + + /* tempptr should now be pointing to the opening parenthesis of the + assertion condition. */ + + if (*tempptr != CHAR_LEFT_PARENTHESIS) + { + *errorcodeptr = ERR28; + goto FAILED; + } + } + + /* For conditions that are assertions, check the syntax, and then exit + the switch. This will take control down to where bracketed groups + are processed. The assertion will be handled as part of the group, + but we need to identify this case because the conditional assertion may + not be quantifier. */ + + if (tempptr[1] == CHAR_QUESTION_MARK && + (tempptr[2] == CHAR_EQUALS_SIGN || + tempptr[2] == CHAR_EXCLAMATION_MARK || + (tempptr[2] == CHAR_LESS_THAN_SIGN && + (tempptr[3] == CHAR_EQUALS_SIGN || + tempptr[3] == CHAR_EXCLAMATION_MARK)))) + { + cb->iscondassert = TRUE; + break; + } + + /* Other conditions use OP_CREF/OP_DNCREF/OP_RREF/OP_DNRREF, and all + need to skip at least 1+IMM2_SIZE bytes at the start of the group. */ + + code[1+LINK_SIZE] = OP_CREF; + skipunits = 1+IMM2_SIZE; + refsign = -1; /* => not a number */ + namelen = -1; /* => not a name; must set to avoid warning */ + name = NULL; /* Always set to avoid warning */ + recno = 0; /* Always set to avoid warning */ + + /* Point at character after (?( */ + + ptr++; + + /* Check for (?(VERSION[>]=n.m), which is a facility whereby indirect + users of PCRE2 via an application can discover which release of PCRE2 + is being used. */ + + if (PRIV(strncmp_c8)(ptr, STRING_VERSION, 7) == 0 && + ptr[7] != CHAR_RIGHT_PARENTHESIS) + { + BOOL ge = FALSE; + int major = 0; + int minor = 0; + + ptr += 7; + if (*ptr == CHAR_GREATER_THAN_SIGN) + { + ge = TRUE; + ptr++; + } + + /* NOTE: cannot write IS_DIGIT(*(++ptr)) here because IS_DIGIT + references its argument twice. */ + + if (*ptr != CHAR_EQUALS_SIGN || (ptr++, !IS_DIGIT(*ptr))) + { + *errorcodeptr = ERR79; + goto FAILED; + } + + while (IS_DIGIT(*ptr)) major = major * 10 + *ptr++ - '0'; + if (*ptr == CHAR_DOT) + { + ptr++; + while (IS_DIGIT(*ptr)) minor = minor * 10 + *ptr++ - '0'; + if (minor < 10) minor *= 10; + } + + if (*ptr != CHAR_RIGHT_PARENTHESIS || minor > 99) + { + *errorcodeptr = ERR79; + goto FAILED; + } + + if (ge) + code[1+LINK_SIZE] = ((PCRE2_MAJOR > major) || + (PCRE2_MAJOR == major && PCRE2_MINOR >= minor))? + OP_TRUE : OP_FALSE; + else + code[1+LINK_SIZE] = (PCRE2_MAJOR == major && PCRE2_MINOR == minor)? + OP_TRUE : OP_FALSE; + + ptr++; + skipunits = 1; + break; /* End of condition processing */ + } + + /* Check for a test for recursion in a named group. */ + + if (*ptr == CHAR_R && ptr[1] == CHAR_AMPERSAND) + { + terminator = -1; + ptr += 2; + code[1+LINK_SIZE] = OP_RREF; /* Change the type of test */ + } + + /* Check for a test for a named group's having been set, using the Perl + syntax (?() or (?('name'), and also allow for the original PCRE + syntax of (?(name) or for (?(+n), (?(-n), and just (?(n). */ + + else if (*ptr == CHAR_LESS_THAN_SIGN) + { + terminator = CHAR_GREATER_THAN_SIGN; + ptr++; + } + else if (*ptr == CHAR_APOSTROPHE) + { + terminator = CHAR_APOSTROPHE; + ptr++; + } + else + { + terminator = CHAR_NULL; + if (*ptr == CHAR_MINUS || *ptr == CHAR_PLUS) refsign = *ptr++; + else if (IS_DIGIT(*ptr)) refsign = 0; + } + + /* Handle a number */ + + if (refsign >= 0) + { + while (IS_DIGIT(*ptr)) + { + if (recno > INT_MAX / 10 - 1) /* Integer overflow */ + { + while (IS_DIGIT(*ptr)) ptr++; + *errorcodeptr = ERR61; + goto FAILED; + } + recno = recno * 10 + (int)(*ptr - CHAR_0); + ptr++; + } + } + + /* Otherwise we expect to read a name; anything else is an error. When + the referenced name is one of a number of duplicates, a different + opcode is used and it needs more memory. Unfortunately we cannot tell + whether this is the case in the first pass, so we have to allow for + more memory always. In the second pass, the additional to skipunits + happens later. */ + + else + { + if (IS_DIGIT(*ptr)) + { + *errorcodeptr = ERR44; /* Group name must start with non-digit */ + goto FAILED; + } + if (!MAX_255(*ptr) || (cb->ctypes[*ptr] & ctype_word) == 0) + { + *errorcodeptr = ERR28; /* Assertion expected */ + goto FAILED; + } + name = ptr; + /* Increment ptr, set namelen, check length */ + READ_NAME(ctype_word, ERR48, *errorcodeptr); + if (lengthptr != NULL) skipunits += IMM2_SIZE; + } + + /* Check the terminator */ + + if ((terminator > 0 && *ptr++ != (PCRE2_UCHAR)terminator) || + *ptr++ != CHAR_RIGHT_PARENTHESIS) + { + ptr--; /* Error offset */ + *errorcodeptr = ERR26; /* Malformed number or name */ + goto FAILED; + } + + /* Do no further checking in the pre-compile phase. */ + + if (lengthptr != NULL) break; + + /* In the real compile we do the work of looking for the actual + reference. If refsign is not negative, it means we have a number in + recno. */ + + if (refsign >= 0) + { + if (recno <= 0) + { + *errorcodeptr = ERR35; + goto FAILED; + } + if (refsign != 0) recno = (refsign == CHAR_MINUS)? + (cb->bracount + 1) - recno : recno + cb->bracount; + if (recno <= 0 || (uint32_t)recno > cb->final_bracount) + { + *errorcodeptr = ERR15; + goto FAILED; + } + PUT2(code, 2+LINK_SIZE, recno); + if ((uint32_t)recno > cb->top_backref) cb->top_backref = recno; + break; + } + + /* Otherwise look for the name. */ + + slot = cb->name_table; + for (i = 0; i < cb->names_found; i++) + { + if (PRIV(strncmp)(name, slot+IMM2_SIZE, namelen) == 0) break; + slot += cb->name_entry_size; + } + + /* Found the named subpattern. If the name is duplicated, add one to + the opcode to change CREF/RREF into DNCREF/DNRREF and insert + appropriate data values. Otherwise, just insert the unique subpattern + number. */ + + if (i < cb->names_found) + { + int offset = i; /* Offset of first name found */ + + count = 0; + for (;;) + { + recno = GET2(slot, 0); /* Number for last found */ + if ((uint32_t)recno > cb->top_backref) cb->top_backref = recno; + count++; + if (++i >= cb->names_found) break; + slot += cb->name_entry_size; + if (PRIV(strncmp)(name, slot+IMM2_SIZE, namelen) != 0 || + (slot+IMM2_SIZE)[namelen] != 0) break; + } + + if (count > 1) + { + PUT2(code, 2+LINK_SIZE, offset); + PUT2(code, 2+LINK_SIZE+IMM2_SIZE, count); + skipunits += IMM2_SIZE; + code[1+LINK_SIZE]++; + } + else /* Not a duplicated name */ + { + PUT2(code, 2+LINK_SIZE, recno); + } + } + + /* If terminator == CHAR_NULL it means that the name followed directly + after the opening parenthesis [e.g. (?(abc)...] and in this case there + are some further alternatives to try. For the cases where terminator != + CHAR_NULL [things like (?(... or (?('name')... or (?(R&name)... ] + we have now checked all the possibilities, so give an error. */ + + else if (terminator != CHAR_NULL) + { + *errorcodeptr = ERR15; + goto FAILED; + } + + /* Check for (?(R) for recursion. Allow digits after R to specify a + specific group number. */ + + else if (*name == CHAR_R) + { + recno = 0; + for (i = 1; i < namelen; i++) + { + if (!IS_DIGIT(name[i])) + { + *errorcodeptr = ERR15; /* Non-existent subpattern */ + goto FAILED; + } + if (recno > INT_MAX / 10 - 1) /* Integer overflow */ + { + *errorcodeptr = ERR61; + goto FAILED; + } + recno = recno * 10 + name[i] - CHAR_0; + } + if (recno == 0) recno = RREF_ANY; + code[1+LINK_SIZE] = OP_RREF; /* Change test type */ + PUT2(code, 2+LINK_SIZE, recno); + } + + /* Similarly, check for the (?(DEFINE) "condition", which is always + false. During compilation we set OP_DEFINE to distinguish this from + other OP_FALSE conditions so that it can be checked for having only one + branch, but after that the opcode is changed to OP_FALSE. */ + + else if (namelen == 6 && PRIV(strncmp_c8)(name, STRING_DEFINE, 6) == 0) + { + code[1+LINK_SIZE] = OP_DEFINE; + skipunits = 1; + } + + /* Reference to an unidentified subpattern. */ + + else + { + *errorcodeptr = ERR15; + goto FAILED; + } + break; + + + /* ------------------------------------------------------------ */ + case CHAR_EQUALS_SIGN: /* Positive lookahead */ + bravalue = OP_ASSERT; + cb->assert_depth += 1; + ptr++; + break; + + /* Optimize (?!) to (*FAIL) unless it is quantified - which is a weird + thing to do, but Perl allows all assertions to be quantified, and when + they contain capturing parentheses there may be a potential use for + this feature. Not that that applies to a quantified (?!) but we allow + it for uniformity. */ + + /* ------------------------------------------------------------ */ + case CHAR_EXCLAMATION_MARK: /* Negative lookahead */ + ptr++; + if (*ptr == CHAR_RIGHT_PARENTHESIS && ptr[1] != CHAR_ASTERISK && + ptr[1] != CHAR_PLUS && ptr[1] != CHAR_QUESTION_MARK && + (ptr[1] != CHAR_LEFT_CURLY_BRACKET || !is_counted_repeat(ptr+2))) + { + *code++ = OP_FAIL; + previous = NULL; + continue; + } + bravalue = OP_ASSERT_NOT; + cb->assert_depth += 1; + break; + + + /* ------------------------------------------------------------ */ + case CHAR_LESS_THAN_SIGN: /* Lookbehind or named define */ + switch (ptr[1]) + { + case CHAR_EQUALS_SIGN: /* Positive lookbehind */ + bravalue = OP_ASSERTBACK; + cb->assert_depth += 1; + ptr += 2; + break; + + case CHAR_EXCLAMATION_MARK: /* Negative lookbehind */ + bravalue = OP_ASSERTBACK_NOT; + cb->assert_depth += 1; + ptr += 2; + break; + + /* Must be a name definition - as the syntax was checked in the + pre-pass, we can assume here that it is valid. Skip over the name + and go to handle the numbered group. */ + + default: + while (*(++ptr) != CHAR_GREATER_THAN_SIGN); + ptr++; + goto NUMBERED_GROUP; + } + break; + + + /* ------------------------------------------------------------ */ + case CHAR_GREATER_THAN_SIGN: /* One-time brackets */ + bravalue = OP_ONCE; + ptr++; + break; + + + /* ------------------------------------------------------------ */ + case CHAR_C: /* Callout */ + previous_callout = code; /* Save for later completion */ + after_manual_callout = 1; /* Skip one item before completing */ + ptr++; /* Character after (?C */ + + /* A callout may have a string argument, delimited by one of a fixed + number of characters, or an undelimited numerical argument, or no + argument, which is the same as (?C0). Different opcodes are used for + the two cases. */ + + if (*ptr != CHAR_RIGHT_PARENTHESIS && !IS_DIGIT(*ptr)) + { + uint32_t delimiter = 0; + + for (i = 0; PRIV(callout_start_delims)[i] != 0; i++) + { + if (*ptr == PRIV(callout_start_delims)[i]) + { + delimiter = PRIV(callout_end_delims)[i]; + break; + } + } + + if (delimiter == 0) + { + *errorcodeptr = ERR82; + goto FAILED; + } + + /* During the pre-compile phase, we parse the string and update the + length. There is no need to generate any code. (In fact, the string + has already been parsed in the pre-pass that looks for named + parentheses, but it does no harm to leave this code in.) */ + + if (lengthptr != NULL) /* Only check the string */ + { + PCRE2_SPTR start = ptr; + do + { + if (++ptr >= cb->end_pattern) + { + *errorcodeptr = ERR81; + ptr = start; /* To give a more useful message */ + goto FAILED; + } + if (ptr[0] == delimiter && ptr[1] == delimiter) ptr += 2; + } + while (ptr[0] != delimiter); + + /* Start points to the opening delimiter, ptr points to the + closing delimiter. We must allow for including the delimiter and + for the terminating zero. Any doubled delimiters within the string + make this an overestimate, but it is not worth bothering about. */ + + (*lengthptr) += (ptr - start) + 2 + (1 + 4*LINK_SIZE); + } + + /* In the real compile we can copy the string, knowing that it is + syntactically OK. The starting delimiter is included so that the + client can discover it if they want. We also pass the start offset to + help a script language give better error messages. */ + + else + { + PCRE2_UCHAR *callout_string = code + (1 + 4*LINK_SIZE); + *callout_string++ = *ptr++; + PUT(code, 1 + 3*LINK_SIZE, (int)(ptr - cb->start_pattern)); /* Start offset */ + for(;;) + { + if (*ptr == delimiter) + { + if (ptr[1] == delimiter) ptr++; else break; + } + *callout_string++ = *ptr++; + } + *callout_string++ = CHAR_NULL; + code[0] = OP_CALLOUT_STR; + PUT(code, 1, (int)(ptr + 2 - cb->start_pattern)); /* Next offset */ + PUT(code, 1 + LINK_SIZE, 0); /* Default length */ + PUT(code, 1 + 2*LINK_SIZE, /* Compute size */ + (int)(callout_string - code)); + code = callout_string; + } + + /* Advance to what should be the closing parenthesis, which is + checked below. */ + + ptr++; + } + + /* Handle a callout with an optional numerical argument, which must be + less than or equal to 255. A missing argument gives 0. */ + + else + { + int n = 0; + code[0] = OP_CALLOUT; /* Numerical callout */ + while (IS_DIGIT(*ptr)) + { + n = n * 10 + *ptr++ - CHAR_0; + if (n > 255) + { + *errorcodeptr = ERR38; + goto FAILED; + } + } + PUT(code, 1, (int)(ptr - cb->start_pattern + 1)); /* Next offset */ + PUT(code, 1 + LINK_SIZE, 0); /* Default length */ + code[1 + 2*LINK_SIZE] = n; /* Callout number */ + code += PRIV(OP_lengths)[OP_CALLOUT]; + } + + /* Both formats must have a closing parenthesis */ + + if (*ptr != CHAR_RIGHT_PARENTHESIS) + { + *errorcodeptr = ERR39; + goto FAILED; + } + + /* Callouts cannot be quantified. */ + + previous = NULL; + continue; + + + /* ------------------------------------------------------------ */ + case CHAR_P: /* Python-style named subpattern handling */ + if (*(++ptr) == CHAR_EQUALS_SIGN || + *ptr == CHAR_GREATER_THAN_SIGN) /* Reference or recursion */ + { + is_recurse = *ptr == CHAR_GREATER_THAN_SIGN; + terminator = CHAR_RIGHT_PARENTHESIS; + goto NAMED_REF_OR_RECURSE; + } + else if (*ptr != CHAR_LESS_THAN_SIGN) /* Test for Python-style defn */ + { + *errorcodeptr = ERR41; + goto FAILED; + } + /* Fall through to handle (?P< as (?< is handled */ + + + /* ------------------------------------------------------------ */ + case CHAR_APOSTROPHE: /* Define a name - note fall through above */ + + /* The syntax was checked and the list of names was set up in the + pre-pass, so there is nothing to be done now except to skip over the + name. */ + + terminator = (*ptr == CHAR_LESS_THAN_SIGN)? + CHAR_GREATER_THAN_SIGN : CHAR_APOSTROPHE; + while (*(++ptr) != (unsigned int)terminator); + ptr++; + goto NUMBERED_GROUP; /* Set up numbered group */ + + + /* ------------------------------------------------------------ */ + case CHAR_AMPERSAND: /* Perl recursion/subroutine syntax */ + terminator = CHAR_RIGHT_PARENTHESIS; + is_recurse = TRUE; + /* Fall through */ + + /* We come here from the Python syntax above that handles both + references (?P=name) and recursion (?P>name), as well as falling + through from the Perl recursion syntax (?&name). We also come here from + the Perl \k or \k'name' back reference syntax and the \k{name} + .NET syntax, and the Oniguruma \g<...> and \g'...' subroutine syntax. */ + + NAMED_REF_OR_RECURSE: + name = ++ptr; + if (IS_DIGIT(*ptr)) + { + *errorcodeptr = ERR44; /* Group name must start with non-digit */ + goto FAILED; + } + /* Increment ptr, set namelen, check length */ + READ_NAME(ctype_word, ERR48, *errorcodeptr); + + /* In the pre-compile phase, do a syntax check. */ + + if (lengthptr != NULL) + { + if (namelen == 0) + { + *errorcodeptr = ERR62; + goto FAILED; + } + if (*ptr != (PCRE2_UCHAR)terminator) + { + *errorcodeptr = ERR42; + goto FAILED; + } + } + + /* Scan the list of names generated in the pre-pass in order to get + a number and whether or not this name is duplicated. */ + + recno = 0; + is_dupname = FALSE; + ng = cb->named_groups; + + for (i = 0; i < cb->names_found; i++, ng++) + { + if (namelen == ng->length && + PRIV(strncmp)(name, ng->name, namelen) == 0) + { + open_capitem *oc; + is_dupname = ng->isdup; + recno = ng->number; + + /* For a recursion, that's all that is needed. We can now go to the + code that handles numerical recursion. */ + + if (is_recurse) goto HANDLE_RECURSION; + + /* For a back reference, update the back reference map and the + maximum back reference. Then for each group we must check to see if + it is recursive, that is, it is inside the group that it + references. A flag is set so that the group can be made atomic. */ + + cb->backref_map |= (recno < 32)? (1u << recno) : 1; + if ((uint32_t)recno > cb->top_backref) cb->top_backref = recno; + + for (oc = cb->open_caps; oc != NULL; oc = oc->next) + { + if (oc->number == recno) + { + oc->flag = TRUE; + break; + } + } + } + } + + /* If the name was not found we have a bad reference. */ + + if (recno == 0) + { + *errorcodeptr = ERR15; + goto FAILED; + } + + /* If a back reference name is not duplicated, we can handle it as a + numerical reference. */ + + if (!is_dupname) goto HANDLE_REFERENCE; + + /* If a back reference name is duplicated, we generate a different + opcode to a numerical back reference. In the second pass we must search + for the index and count in the final name table. */ + + count = 0; + index = 0; + + if (lengthptr == NULL) + { + slot = cb->name_table; + for (i = 0; i < cb->names_found; i++) + { + if (PRIV(strncmp)(name, slot+IMM2_SIZE, namelen) == 0 && + slot[IMM2_SIZE+namelen] == 0) + { + if (count == 0) index = i; + count++; + } + slot += cb->name_entry_size; + } + + if (count == 0) + { + *errorcodeptr = ERR15; + goto FAILED; + } + } + + if (firstcuflags == REQ_UNSET) firstcuflags = REQ_NONE; + previous = code; + *code++ = ((options & PCRE2_CASELESS) != 0)? OP_DNREFI : OP_DNREF; + PUT2INC(code, 0, index); + PUT2INC(code, 0, count); + continue; /* End of back ref handling */ + + + /* ------------------------------------------------------------ */ + case CHAR_R: /* Recursion, same as (?0) */ + recno = 0; + if (*(++ptr) != CHAR_RIGHT_PARENTHESIS) + { + *errorcodeptr = ERR29; + goto FAILED; + } + goto HANDLE_RECURSION; + + + /* ------------------------------------------------------------ */ + case CHAR_MINUS: case CHAR_PLUS: /* Recursion or subroutine */ + case CHAR_0: case CHAR_1: case CHAR_2: case CHAR_3: case CHAR_4: + case CHAR_5: case CHAR_6: case CHAR_7: case CHAR_8: case CHAR_9: + { + terminator = CHAR_RIGHT_PARENTHESIS; + + /* Come here from the \g<...> and \g'...' code (Oniguruma + compatibility). However, the syntax has been checked to ensure that + the ... are a (signed) number, so that neither ERR63 nor ERR29 will + be called on this path, nor with the jump to OTHER_CHAR_AFTER_QUERY + ever be taken. */ + + HANDLE_NUMERICAL_RECURSION: + + if ((refsign = *ptr) == CHAR_PLUS) + { + ptr++; + if (!IS_DIGIT(*ptr)) + { + *errorcodeptr = ERR63; + goto FAILED; + } + } + else if (refsign == CHAR_MINUS) + { + if (!IS_DIGIT(ptr[1])) + goto OTHER_CHAR_AFTER_QUERY; + ptr++; + } + + recno = 0; + while (IS_DIGIT(*ptr)) + { + if (recno > INT_MAX / 10 - 1) /* Integer overflow */ + { + while (IS_DIGIT(*ptr)) ptr++; + *errorcodeptr = ERR61; + goto FAILED; + } + recno = recno * 10 + *ptr++ - CHAR_0; + } + + if (*ptr != (PCRE2_UCHAR)terminator) + { + *errorcodeptr = ERR29; + goto FAILED; + } + + if (refsign == CHAR_MINUS) + { + if (recno == 0) + { + *errorcodeptr = ERR58; + goto FAILED; + } + recno = (int)(cb->bracount + 1) - recno; + if (recno <= 0) + { + *errorcodeptr = ERR15; + goto FAILED; + } + } + else if (refsign == CHAR_PLUS) + { + if (recno == 0) + { + *errorcodeptr = ERR58; + goto FAILED; + } + recno += cb->bracount; + } + + if ((uint32_t)recno > cb->final_bracount) + { + *errorcodeptr = ERR15; + goto FAILED; + } + + /* Come here from code above that handles a named recursion. + We insert the number of the called group after OP_RECURSE. At the + end of compiling the pattern is scanned and these numbers are + replaced by offsets within the pattern. It is done like this to avoid + problems with forward references and adjusting offsets when groups + are duplicated and moved (as discovered in previous implementations). + Note that a recursion does not have a set first character (relevant + if it is repeated, because it will then be wrapped with ONCE + brackets). */ + + HANDLE_RECURSION: + previous = code; + *code = OP_RECURSE; + PUT(code, 1, recno); + code += 1 + LINK_SIZE; + groupsetfirstcu = FALSE; + cb->had_recurse = TRUE; + } + + /* Can't determine a first byte now */ + + if (firstcuflags == REQ_UNSET) firstcuflags = REQ_NONE; + continue; + + + /* ------------------------------------------------------------ */ + default: /* Other characters: check option setting */ + OTHER_CHAR_AFTER_QUERY: + set = unset = 0; + optset = &set; + + while (*ptr != CHAR_RIGHT_PARENTHESIS && *ptr != CHAR_COLON) + { + switch (*ptr++) + { + case CHAR_MINUS: optset = &unset; break; + + case CHAR_J: /* Record that it changed in the external options */ + *optset |= PCRE2_DUPNAMES; + cb->external_flags |= PCRE2_JCHANGED; + break; + + case CHAR_i: *optset |= PCRE2_CASELESS; break; + case CHAR_m: *optset |= PCRE2_MULTILINE; break; + case CHAR_s: *optset |= PCRE2_DOTALL; break; + case CHAR_x: *optset |= PCRE2_EXTENDED; break; + case CHAR_U: *optset |= PCRE2_UNGREEDY; break; + + default: *errorcodeptr = ERR11; + ptr--; /* Correct the offset */ + goto FAILED; + } + } + + /* Set up the changed option bits, but don't change anything yet. */ + + newoptions = (options | set) & (~unset); + + /* If the options ended with ')' this is not the start of a nested + group with option changes, so the options change at this level. They + must also be passed back for use in subsequent branches. Reset the + greedy defaults and the case value for firstcu and reqcu. */ + + if (*ptr == CHAR_RIGHT_PARENTHESIS) + { + *optionsptr = options = newoptions; + greedy_default = ((newoptions & PCRE2_UNGREEDY) != 0); + greedy_non_default = greedy_default ^ 1; + req_caseopt = ((newoptions & PCRE2_CASELESS) != 0)? REQ_CASELESS:0; + previous = NULL; /* This item can't be repeated */ + continue; /* It is complete */ + } + + /* If the options ended with ':' we are heading into a nested group + with possible change of options. Such groups are non-capturing and are + not assertions of any kind. All we need to do is skip over the ':'; + the newoptions value is handled below. */ + + bravalue = OP_BRA; + ptr++; + } /* End of switch for character following (? */ + } /* End of (? handling */ + + /* Opening parenthesis not followed by '*' or '?'. If PCRE2_NO_AUTO_CAPTURE + is set, all unadorned brackets become non-capturing and behave like (?:...) + brackets. */ + + else if ((options & PCRE2_NO_AUTO_CAPTURE) != 0) + { + bravalue = OP_BRA; + } + + /* Else we have a capturing group. */ + + else + { + NUMBERED_GROUP: + cb->bracount += 1; + PUT2(code, 1+LINK_SIZE, cb->bracount); + skipunits = IMM2_SIZE; + } + + /* Process nested bracketed regex. First check for parentheses nested too + deeply. */ + + if ((cb->parens_depth += 1) > (int)(cb->cx->parens_nest_limit)) + { + *errorcodeptr = ERR19; + goto FAILED; + } + + /* All assertions used not to be repeatable, but this was changed for Perl + compatibility. All kinds can now be repeated except for assertions that are + conditions (Perl also forbids these to be repeated). We copy code into a + non-register variable (tempcode) in order to be able to pass its address + because some compilers complain otherwise. At the start of a conditional + group whose condition is an assertion, cb->iscondassert is set. We unset it + here so as to allow assertions later in the group to be quantified. */ + + if (bravalue >= OP_ASSERT && bravalue <= OP_ASSERTBACK_NOT && + cb->iscondassert) + { + previous = NULL; + cb->iscondassert = FALSE; + } + else + { + previous = code; + } + + *code = bravalue; + tempcode = code; + tempreqvary = cb->req_varyopt; /* Save value before bracket */ + tempbracount = cb->bracount; /* Save value before bracket */ + length_prevgroup = 0; /* Initialize for pre-compile phase */ + + if (!compile_regex( + newoptions, /* The complete new option state */ + &tempcode, /* Where to put code (updated) */ + &ptr, /* Input pointer (updated) */ + errorcodeptr, /* Where to put an error message */ + (bravalue == OP_ASSERTBACK || + bravalue == OP_ASSERTBACK_NOT), /* TRUE if back assert */ + reset_bracount, /* True if (?| group */ + skipunits, /* Skip over bracket number */ + cond_depth + + ((bravalue == OP_COND)?1:0), /* Depth of condition subpatterns */ + &subfirstcu, /* For possible first char */ + &subfirstcuflags, + &subreqcu, /* For possible last char */ + &subreqcuflags, + bcptr, /* Current branch chain */ + cb, /* Compile data block */ + (lengthptr == NULL)? NULL : /* Actual compile phase */ + &length_prevgroup /* Pre-compile phase */ + )) + goto FAILED; + + cb->parens_depth -= 1; + + /* If this was an atomic group and there are no capturing groups within it, + generate OP_ONCE_NC instead of OP_ONCE. */ + + if (bravalue == OP_ONCE && cb->bracount <= tempbracount) + *code = OP_ONCE_NC; + + if (bravalue >= OP_ASSERT && bravalue <= OP_ASSERTBACK_NOT) + cb->assert_depth -= 1; + + /* At the end of compiling, code is still pointing to the start of the + group, while tempcode has been updated to point past the end of the group. + The pattern pointer (ptr) is on the bracket. + + If this is a conditional bracket, check that there are no more than + two branches in the group, or just one if it's a DEFINE group. We do this + in the real compile phase, not in the pre-pass, where the whole group may + not be available. */ + + if (bravalue == OP_COND && lengthptr == NULL) + { + PCRE2_UCHAR *tc = code; + int condcount = 0; + + do { + condcount++; + tc += GET(tc,1); + } + while (*tc != OP_KET); + + /* A DEFINE group is never obeyed inline (the "condition" is always + false). It must have only one branch. Having checked this, change the + opcode to OP_FALSE. */ + + if (code[LINK_SIZE+1] == OP_DEFINE) + { + if (condcount > 1) + { + *errorcodeptr = ERR54; + goto FAILED; + } + code[LINK_SIZE+1] = OP_FALSE; + bravalue = OP_DEFINE; /* Just a flag to suppress char handling below */ + } + + /* A "normal" conditional group. If there is just one branch, we must not + make use of its firstcu or reqcu, because this is equivalent to an + empty second branch. */ + + else + { + if (condcount > 2) + { + *errorcodeptr = ERR27; + goto FAILED; + } + if (condcount == 1) subfirstcuflags = subreqcuflags = REQ_NONE; + } + } + + /* At the end of a group, it's an error if we hit end of pattern or + any non-closing parenthesis. This check also happens in the pre-scan, + so should not trigger here, but leave this code as an insurance. */ + + if (*ptr != CHAR_RIGHT_PARENTHESIS) + { + *errorcodeptr = ERR14; + goto FAILED; + } + + /* In the pre-compile phase, update the length by the length of the group, + less the brackets at either end. Then reduce the compiled code to just a + set of non-capturing brackets so that it doesn't use much memory if it is + duplicated by a quantifier.*/ + + if (lengthptr != NULL) + { + if (OFLOW_MAX - *lengthptr < length_prevgroup - 2 - 2*LINK_SIZE) + { + *errorcodeptr = ERR20; + goto FAILED; + } + *lengthptr += length_prevgroup - 2 - 2*LINK_SIZE; + code++; /* This already contains bravalue */ + PUTINC(code, 0, 1 + LINK_SIZE); + *code++ = OP_KET; + PUTINC(code, 0, 1 + LINK_SIZE); + break; /* No need to waste time with special character handling */ + } + + /* Otherwise update the main code pointer to the end of the group. */ + + code = tempcode; + + /* For a DEFINE group, required and first character settings are not + relevant. */ + + if (bravalue == OP_DEFINE) break; + + /* Handle updating of the required and first characters for other types of + group. Update for normal brackets of all kinds, and conditions with two + branches (see code above). If the bracket is followed by a quantifier with + zero repeat, we have to back off. Hence the definition of zeroreqcu and + zerofirstcu outside the main loop so that they can be accessed for the + back off. */ + + zeroreqcu = reqcu; + zeroreqcuflags = reqcuflags; + zerofirstcu = firstcu; + zerofirstcuflags = firstcuflags; + groupsetfirstcu = FALSE; + + if (bravalue >= OP_ONCE) + { + /* If we have not yet set a firstcu in this branch, take it from the + subpattern, remembering that it was set here so that a repeat of more + than one can replicate it as reqcu if necessary. If the subpattern has + no firstcu, set "none" for the whole branch. In both cases, a zero + repeat forces firstcu to "none". */ + + if (firstcuflags == REQ_UNSET && subfirstcuflags != REQ_UNSET) + { + if (subfirstcuflags >= 0) + { + firstcu = subfirstcu; + firstcuflags = subfirstcuflags; + groupsetfirstcu = TRUE; + } + else firstcuflags = REQ_NONE; + zerofirstcuflags = REQ_NONE; + } + + /* If firstcu was previously set, convert the subpattern's firstcu + into reqcu if there wasn't one, using the vary flag that was in + existence beforehand. */ + + else if (subfirstcuflags >= 0 && subreqcuflags < 0) + { + subreqcu = subfirstcu; + subreqcuflags = subfirstcuflags | tempreqvary; + } + + /* If the subpattern set a required byte (or set a first byte that isn't + really the first byte - see above), set it. */ + + if (subreqcuflags >= 0) + { + reqcu = subreqcu; + reqcuflags = subreqcuflags; + } + } + + /* For a forward assertion, we take the reqcu, if set. This can be + helpful if the pattern that follows the assertion doesn't set a different + char. For example, it's useful for /(?=abcde).+/. We can't set firstcu + for an assertion, however because it leads to incorrect effect for patterns + such as /(?=a)a.+/ when the "real" "a" would then become a reqcu instead + of a firstcu. This is overcome by a scan at the end if there's no + firstcu, looking for an asserted first char. */ + + else if (bravalue == OP_ASSERT && subreqcuflags >= 0) + { + reqcu = subreqcu; + reqcuflags = subreqcuflags; + } + break; /* End of processing '(' */ + + + /* ===================================================================*/ + /* Handle metasequences introduced by \. For ones like \d, the ESC_ values + are arranged to be the negation of the corresponding OP_values in the + default case when PCRE2_UCP is not set. For the back references, the values + are negative the reference number. Only back references and those types + that consume a character may be repeated. We can test for values between + ESC_b and ESC_Z for the latter; this may have to change if any new ones are + ever created. + + Note: \Q and \E are handled at the start of the character-processing loop, + not here. */ + + case CHAR_BACKSLASH: + tempptr = ptr; + escape = PRIV(check_escape)(&ptr, cb->end_pattern, &ec, errorcodeptr, + options, FALSE, cb); + if (*errorcodeptr != 0) goto FAILED; + + if (escape == 0) /* The escape coded a single character */ + c = ec; + else + { + /* For metasequences that actually match a character, we disable the + setting of a first character if it hasn't already been set. */ + + if (firstcuflags == REQ_UNSET && escape > ESC_b && escape < ESC_Z) + firstcuflags = REQ_NONE; + + /* Set values to reset to if this is followed by a zero repeat. */ + + zerofirstcu = firstcu; + zerofirstcuflags = firstcuflags; + zeroreqcu = reqcu; + zeroreqcuflags = reqcuflags; + + /* \g or \g'name' is a subroutine call by name and \g or \g'n' + is a subroutine call by number (Oniguruma syntax). In fact, the value + ESC_g is returned only for these cases. So we don't need to check for < + or ' if the value is ESC_g. For the Perl syntax \g{n} the value is + -n, and for the Perl syntax \g{name} the result is ESC_k (as + that is a synonym for a named back reference). */ + + if (escape == ESC_g) + { + PCRE2_SPTR p; + uint32_t cf; + + terminator = (*(++ptr) == CHAR_LESS_THAN_SIGN)? + CHAR_GREATER_THAN_SIGN : CHAR_APOSTROPHE; + + /* These two statements stop the compiler for warning about possibly + unset variables caused by the jump to HANDLE_NUMERICAL_RECURSION. In + fact, because we do the check for a number below, the paths that + would actually be in error are never taken. */ + + skipunits = 0; + reset_bracount = FALSE; + + /* If it's not a signed or unsigned number, treat it as a name. */ + + cf = ptr[1]; + if (cf != CHAR_PLUS && cf != CHAR_MINUS && !IS_DIGIT(cf)) + { + is_recurse = TRUE; + goto NAMED_REF_OR_RECURSE; + } + + /* Signed or unsigned number (cf = ptr[1]) is known to be plus or minus + or a digit. */ + + p = ptr + 2; + while (IS_DIGIT(*p)) p++; + if (*p != (PCRE2_UCHAR)terminator) + { + *errorcodeptr = ERR57; + goto FAILED; + } + ptr++; + goto HANDLE_NUMERICAL_RECURSION; + } + + /* \k or \k'name' is a back reference by name (Perl syntax). + We also support \k{name} (.NET syntax). */ + + if (escape == ESC_k) + { + if ((ptr[1] != CHAR_LESS_THAN_SIGN && + ptr[1] != CHAR_APOSTROPHE && ptr[1] != CHAR_LEFT_CURLY_BRACKET)) + { + *errorcodeptr = ERR69; + goto FAILED; + } + is_recurse = FALSE; + terminator = (*(++ptr) == CHAR_LESS_THAN_SIGN)? + CHAR_GREATER_THAN_SIGN : (*ptr == CHAR_APOSTROPHE)? + CHAR_APOSTROPHE : CHAR_RIGHT_CURLY_BRACKET; + goto NAMED_REF_OR_RECURSE; + } + + /* Back references are handled specially; must disable firstcu if + not set to cope with cases like (?=(\w+))\1: which would otherwise set + ':' later. */ + + if (escape < 0) + { + open_capitem *oc; + recno = -escape; + + /* Come here from named backref handling when the reference is to a + single group (i.e. not to a duplicated name). */ + + HANDLE_REFERENCE: + if (recno > (int)cb->final_bracount) + { + *errorcodeptr = ERR15; + goto FAILED; + } + if (firstcuflags == REQ_UNSET) firstcuflags = REQ_NONE; + previous = code; + *code++ = ((options & PCRE2_CASELESS) != 0)? OP_REFI : OP_REF; + PUT2INC(code, 0, recno); + cb->backref_map |= (recno < 32)? (1u << recno) : 1; + if ((uint32_t)recno > cb->top_backref) cb->top_backref = recno; + + /* Check to see if this back reference is recursive, that it, it + is inside the group that it references. A flag is set so that the + group can be made atomic. */ + + for (oc = cb->open_caps; oc != NULL; oc = oc->next) + { + if (oc->number == recno) + { + oc->flag = TRUE; + break; + } + } + } + + /* So are Unicode property matches, if supported. */ + +#ifdef SUPPORT_UNICODE + else if (escape == ESC_P || escape == ESC_p) + { + BOOL negated; + unsigned int ptype = 0, pdata = 0; + if (!get_ucp(&ptr, &negated, &ptype, &pdata, errorcodeptr, cb)) + goto FAILED; + previous = code; + *code++ = ((escape == ESC_p) != negated)? OP_PROP : OP_NOTPROP; + *code++ = ptype; + *code++ = pdata; + } +#else + + /* If Unicode properties are not supported, \X, \P, and \p are not + allowed. */ + + else if (escape == ESC_X || escape == ESC_P || escape == ESC_p) + { + *errorcodeptr = ERR45; + goto FAILED; + } +#endif + + /* The use of \C can be locked out. */ + +#ifdef NEVER_BACKSLASH_C + else if (escape == ESC_C) + { + *errorcodeptr = ERR85; + goto FAILED; + } +#else + else if (escape == ESC_C && (options & PCRE2_NEVER_BACKSLASH_C) != 0) + { + *errorcodeptr = ERR83; + goto FAILED; + } +#endif + + /* For the rest (including \X when Unicode properties are supported), we + can obtain the OP value by negating the escape value in the default + situation when PCRE2_UCP is not set. When it *is* set, we substitute + Unicode property tests. Note that \b and \B do a one-character + lookbehind, and \A also behaves as if it does. */ + + else + { + if (escape == ESC_C) cb->external_flags |= PCRE2_HASBKC; /* Record */ + if ((escape == ESC_b || escape == ESC_B || escape == ESC_A) && + cb->max_lookbehind == 0) + cb->max_lookbehind = 1; +#ifdef SUPPORT_UNICODE + if (escape >= ESC_DU && escape <= ESC_wu) + { + cb->nestptr[1] = cb->nestptr[0]; /* Back up if at 2nd level */ + cb->nestptr[0] = ptr + 1; /* Where to resume */ + ptr = substitutes[escape - ESC_DU] - 1; /* Just before substitute */ + } + else +#endif + /* In non-UTF mode, and for both 32-bit modes, we turn \C into + OP_ALLANY instead of OP_ANYBYTE so that it works in DFA mode and in + lookbehinds. */ + + { + previous = (escape > ESC_b && escape < ESC_Z)? code : NULL; +#if PCRE2_CODE_UNIT_WIDTH == 32 + *code++ = (escape == ESC_C)? OP_ALLANY : escape; +#else + *code++ = (!utf && escape == ESC_C)? OP_ALLANY : escape; +#endif + } + } + continue; + } + + /* We have a data character whose value is in c. In UTF-8 mode it may have + a value > 127. We set its representation in the length/buffer, and then + handle it as a data character. */ + + mclength = PUTCHAR(c, mcbuffer); + goto ONE_CHAR; + + + /* ===================================================================*/ + /* Handle a literal character. It is guaranteed not to be whitespace or # + when the extended flag is set. If we are in a UTF mode, it may be a + multi-unit literal character. */ + + default: + NORMAL_CHAR: + mclength = 1; + mcbuffer[0] = c; + +#ifdef SUPPORT_UNICODE + if (utf && HAS_EXTRALEN(c)) + ACROSSCHAR(TRUE, ptr[1], mcbuffer[mclength++] = *(++ptr)); +#endif + + /* At this point we have the character's bytes in mcbuffer, and the length + in mclength. When not in UTF mode, the length is always 1. */ + + ONE_CHAR: + previous = code; + + /* For caseless UTF mode, check whether this character has more than one + other case. If so, generate a special OP_PROP item instead of OP_CHARI. */ + +#ifdef SUPPORT_UNICODE + if (utf && (options & PCRE2_CASELESS) != 0) + { + GETCHAR(c, mcbuffer); + if ((c = UCD_CASESET(c)) != 0) + { + *code++ = OP_PROP; + *code++ = PT_CLIST; + *code++ = c; + if (firstcuflags == REQ_UNSET) + firstcuflags = zerofirstcuflags = REQ_NONE; + break; + } + } +#endif + + /* Caseful matches, or not one of the multicase characters. */ + + *code++ = ((options & PCRE2_CASELESS) != 0)? OP_CHARI : OP_CHAR; + for (c = 0; c < mclength; c++) *code++ = mcbuffer[c]; + + /* Remember if \r or \n were seen */ + + if (mcbuffer[0] == CHAR_CR || mcbuffer[0] == CHAR_NL) + cb->external_flags |= PCRE2_HASCRORLF; + + /* Set the first and required bytes appropriately. If no previous first + byte, set it from this character, but revert to none on a zero repeat. + Otherwise, leave the firstcu value alone, and don't change it on a zero + repeat. */ + + if (firstcuflags == REQ_UNSET) + { + zerofirstcuflags = REQ_NONE; + zeroreqcu = reqcu; + zeroreqcuflags = reqcuflags; + + /* If the character is more than one byte long, we can set firstcu + only if it is not to be matched caselessly. */ + + if (mclength == 1 || req_caseopt == 0) + { + firstcu = mcbuffer[0] | req_caseopt; + firstcu = mcbuffer[0]; + firstcuflags = req_caseopt; + + if (mclength != 1) + { + reqcu = code[-1]; + reqcuflags = cb->req_varyopt; + } + } + else firstcuflags = reqcuflags = REQ_NONE; + } + + /* firstcu was previously set; we can set reqcu only if the length is + 1 or the matching is caseful. */ + + else + { + zerofirstcu = firstcu; + zerofirstcuflags = firstcuflags; + zeroreqcu = reqcu; + zeroreqcuflags = reqcuflags; + if (mclength == 1 || req_caseopt == 0) + { + reqcu = code[-1]; + reqcuflags = req_caseopt | cb->req_varyopt; + } + } + + break; /* End of literal character handling */ + } + } /* end of big loop */ + +/* Control never reaches here by falling through, only by a goto for all the +error states. Pass back the position in the pattern so that it can be displayed +to the user for diagnosing the error. */ + +FAILED: +*ptrptr = ptr; +return FALSE; +} + + + +/************************************************* +* Compile regex: a sequence of alternatives * +*************************************************/ + +/* On entry, ptr is pointing past the bracket character, but on return it +points to the closing bracket, or vertical bar, or end of string. The code +variable is pointing at the byte into which the BRA operator has been stored. +This function is used during the pre-compile phase when we are trying to find +out the amount of memory needed, as well as during the real compile phase. The +value of lengthptr distinguishes the two phases. + +Arguments: + options option bits, including any changes for this subpattern + codeptr -> the address of the current code pointer + ptrptr -> the address of the current pattern pointer + errorcodeptr -> pointer to error code variable + lookbehind TRUE if this is a lookbehind assertion + reset_bracount TRUE to reset the count for each branch + skipunits skip this many code units at start (for brackets and OP_COND) + cond_depth depth of nesting for conditional subpatterns + firstcuptr place to put the first required code unit + firstcuflagsptr place to put the first code unit flags, or a negative number + reqcuptr place to put the last required code unit + reqcuflagsptr place to put the last required code unit flags, or a negative number + bcptr pointer to the chain of currently open branches + cb points to the data block with tables pointers etc. + lengthptr NULL during the real compile phase + points to length accumulator during pre-compile phase + +Returns: TRUE on success +*/ + +static BOOL +compile_regex(uint32_t options, PCRE2_UCHAR **codeptr, PCRE2_SPTR *ptrptr, + int *errorcodeptr, BOOL lookbehind, BOOL reset_bracount, uint32_t skipunits, + int cond_depth, uint32_t *firstcuptr, int32_t *firstcuflagsptr, + uint32_t *reqcuptr, int32_t *reqcuflagsptr, branch_chain *bcptr, + compile_block *cb, size_t *lengthptr) +{ +PCRE2_SPTR ptr = *ptrptr; +PCRE2_UCHAR *code = *codeptr; +PCRE2_UCHAR *last_branch = code; +PCRE2_UCHAR *start_bracket = code; +PCRE2_UCHAR *reverse_count = NULL; +open_capitem capitem; +int capnumber = 0; +uint32_t firstcu, reqcu; +int32_t firstcuflags, reqcuflags; +uint32_t branchfirstcu, branchreqcu; +int32_t branchfirstcuflags, branchreqcuflags; +size_t length; +unsigned int orig_bracount; +unsigned int max_bracount; +branch_chain bc; + +/* If set, call the external function that checks for stack availability. */ + +if (cb->cx->stack_guard != NULL && + cb->cx->stack_guard(cb->parens_depth, cb->cx->stack_guard_data)) + { + *errorcodeptr= ERR33; + return FALSE; + } + +/* Miscellaneous initialization */ + +bc.outer = bcptr; +bc.current_branch = code; + +firstcu = reqcu = 0; +firstcuflags = reqcuflags = REQ_UNSET; + +/* Accumulate the length for use in the pre-compile phase. Start with the +length of the BRA and KET and any extra code units that are required at the +beginning. We accumulate in a local variable to save frequent testing of +lengthptr for NULL. We cannot do this by looking at the value of 'code' at the +start and end of each alternative, because compiled items are discarded during +the pre-compile phase so that the work space is not exceeded. */ + +length = 2 + 2*LINK_SIZE + skipunits; + +/* WARNING: If the above line is changed for any reason, you must also change +the code that abstracts option settings at the start of the pattern and makes +them global. It tests the value of length for (2 + 2*LINK_SIZE) in the +pre-compile phase to find out whether or not anything has yet been compiled. + +If this is a capturing subpattern, add to the chain of open capturing items +so that we can detect them if (*ACCEPT) is encountered. This is also used to +detect groups that contain recursive back references to themselves. Note that +only OP_CBRA need be tested here; changing this opcode to one of its variants, +e.g. OP_SCBRAPOS, happens later, after the group has been compiled. */ + +if (*code == OP_CBRA) + { + capnumber = GET2(code, 1 + LINK_SIZE); + capitem.number = capnumber; + capitem.next = cb->open_caps; + capitem.flag = FALSE; + cb->open_caps = &capitem; + } + +/* Offset is set zero to mark that this bracket is still open */ + +PUT(code, 1, 0); +code += 1 + LINK_SIZE + skipunits; + +/* Loop for each alternative branch */ + +orig_bracount = max_bracount = cb->bracount; + +for (;;) + { + /* For a (?| group, reset the capturing bracket count so that each branch + uses the same numbers. */ + + if (reset_bracount) cb->bracount = orig_bracount; + + /* Set up dummy OP_REVERSE if lookbehind assertion */ + + if (lookbehind) + { + *code++ = OP_REVERSE; + reverse_count = code; + PUTINC(code, 0, 0); + length += 1 + LINK_SIZE; + } + + /* Now compile the branch; in the pre-compile phase its length gets added + into the length. */ + + if (!compile_branch(&options, &code, &ptr, errorcodeptr, &branchfirstcu, + &branchfirstcuflags, &branchreqcu, &branchreqcuflags, &bc, + cond_depth, cb, (lengthptr == NULL)? NULL : &length)) + { + *ptrptr = ptr; + return FALSE; + } + + /* Keep the highest bracket count in case (?| was used and some branch + has fewer than the rest. */ + + if (cb->bracount > max_bracount) max_bracount = cb->bracount; + + /* In the real compile phase, there is some post-processing to be done. */ + + if (lengthptr == NULL) + { + /* If this is the first branch, the firstcu and reqcu values for the + branch become the values for the regex. */ + + if (*last_branch != OP_ALT) + { + firstcu = branchfirstcu; + firstcuflags = branchfirstcuflags; + reqcu = branchreqcu; + reqcuflags = branchreqcuflags; + } + + /* If this is not the first branch, the first char and reqcu have to + match the values from all the previous branches, except that if the + previous value for reqcu didn't have REQ_VARY set, it can still match, + and we set REQ_VARY for the regex. */ + + else + { + /* If we previously had a firstcu, but it doesn't match the new branch, + we have to abandon the firstcu for the regex, but if there was + previously no reqcu, it takes on the value of the old firstcu. */ + + if (firstcuflags != branchfirstcuflags || firstcu != branchfirstcu) + { + if (firstcuflags >= 0) + { + if (reqcuflags < 0) + { + reqcu = firstcu; + reqcuflags = firstcuflags; + } + } + firstcuflags = REQ_NONE; + } + + /* If we (now or from before) have no firstcu, a firstcu from the + branch becomes a reqcu if there isn't a branch reqcu. */ + + if (firstcuflags < 0 && branchfirstcuflags >= 0 && + branchreqcuflags < 0) + { + branchreqcu = branchfirstcu; + branchreqcuflags = branchfirstcuflags; + } + + /* Now ensure that the reqcus match */ + + if (((reqcuflags & ~REQ_VARY) != (branchreqcuflags & ~REQ_VARY)) || + reqcu != branchreqcu) + reqcuflags = REQ_NONE; + else + { + reqcu = branchreqcu; + reqcuflags |= branchreqcuflags; /* To "or" REQ_VARY */ + } + } + + /* If lookbehind, check that this branch matches a fixed-length string, and + put the length into the OP_REVERSE item. Temporarily mark the end of the + branch with OP_END. If the branch contains OP_RECURSE, the result is + FFL_LATER (a negative value) because there may be forward references that + we can't check here. Set a flag to cause another lookbehind check at the + end. Why not do it all at the end? Because common errors can be picked up + here and the offset of the problem can be shown. */ + + if (lookbehind) + { + int fixed_length; + int count = 0; + *code = OP_END; + fixed_length = find_fixedlength(last_branch, (options & PCRE2_UTF) != 0, + FALSE, cb, NULL, &count); + if (fixed_length == FFL_LATER) + { + cb->check_lookbehind = TRUE; + } + else if (fixed_length < 0) + { + *errorcodeptr = fixed_length_errors[-fixed_length]; + *ptrptr = ptr; + return FALSE; + } + else + { + if (fixed_length > cb->max_lookbehind) + cb->max_lookbehind = fixed_length; + PUT(reverse_count, 0, fixed_length); + } + } + } + + /* Reached end of expression, either ')' or end of pattern. In the real + compile phase, go back through the alternative branches and reverse the chain + of offsets, with the field in the BRA item now becoming an offset to the + first alternative. If there are no alternatives, it points to the end of the + group. The length in the terminating ket is always the length of the whole + bracketed item. Return leaving the pointer at the terminating char. */ + + if (*ptr != CHAR_VERTICAL_LINE) + { + if (lengthptr == NULL) + { + size_t branch_length = code - last_branch; + do + { + size_t prev_length = GET(last_branch, 1); + PUT(last_branch, 1, branch_length); + branch_length = prev_length; + last_branch -= branch_length; + } + while (branch_length > 0); + } + + /* Fill in the ket */ + + *code = OP_KET; + PUT(code, 1, (int)(code - start_bracket)); + code += 1 + LINK_SIZE; + + /* If it was a capturing subpattern, check to see if it contained any + recursive back references. If so, we must wrap it in atomic brackets. In + any event, remove the block from the chain. */ + + if (capnumber > 0) + { + if (cb->open_caps->flag) + { + memmove(start_bracket + 1 + LINK_SIZE, start_bracket, + CU2BYTES(code - start_bracket)); + *start_bracket = OP_ONCE; + code += 1 + LINK_SIZE; + PUT(start_bracket, 1, (int)(code - start_bracket)); + *code = OP_KET; + PUT(code, 1, (int)(code - start_bracket)); + code += 1 + LINK_SIZE; + length += 2 + 2*LINK_SIZE; + } + cb->open_caps = cb->open_caps->next; + } + + /* Retain the highest bracket number, in case resetting was used. */ + + cb->bracount = max_bracount; + + /* Set values to pass back */ + + *codeptr = code; + *ptrptr = ptr; + *firstcuptr = firstcu; + *firstcuflagsptr = firstcuflags; + *reqcuptr = reqcu; + *reqcuflagsptr = reqcuflags; + if (lengthptr != NULL) + { + if (OFLOW_MAX - *lengthptr < length) + { + *errorcodeptr = ERR20; + return FALSE; + } + *lengthptr += length; + } + return TRUE; + } + + /* Another branch follows. In the pre-compile phase, we can move the code + pointer back to where it was for the start of the first branch. (That is, + pretend that each branch is the only one.) + + In the real compile phase, insert an ALT node. Its length field points back + to the previous branch while the bracket remains open. At the end the chain + is reversed. It's done like this so that the start of the bracket has a + zero offset until it is closed, making it possible to detect recursion. */ + + if (lengthptr != NULL) + { + code = *codeptr + 1 + LINK_SIZE + skipunits; + length += 1 + LINK_SIZE; + } + else + { + *code = OP_ALT; + PUT(code, 1, (int)(code - last_branch)); + bc.current_branch = last_branch = code; + code += 1 + LINK_SIZE; + } + + /* Advance past the vertical bar */ + + ptr++; + } +/* Control never reaches here */ +} + + + +/************************************************* +* Check for anchored pattern * +*************************************************/ + +/* Try to find out if this is an anchored regular expression. Consider each +alternative branch. If they all start with OP_SOD or OP_CIRC, or with a bracket +all of whose alternatives start with OP_SOD or OP_CIRC (recurse ad lib), then +it's anchored. However, if this is a multiline pattern, then only OP_SOD will +be found, because ^ generates OP_CIRCM in that mode. + +We can also consider a regex to be anchored if OP_SOM starts all its branches. +This is the code for \G, which means "match at start of match position, taking +into account the match offset". + +A branch is also implicitly anchored if it starts with .* and DOTALL is set, +because that will try the rest of the pattern at all possible matching points, +so there is no point trying again.... er .... + +.... except when the .* appears inside capturing parentheses, and there is a +subsequent back reference to those parentheses. We haven't enough information +to catch that case precisely. + +At first, the best we could do was to detect when .* was in capturing brackets +and the highest back reference was greater than or equal to that level. +However, by keeping a bitmap of the first 31 back references, we can catch some +of the more common cases more precisely. + +... A second exception is when the .* appears inside an atomic group, because +this prevents the number of characters it matches from being adjusted. + +Arguments: + code points to start of the compiled pattern + bracket_map a bitmap of which brackets we are inside while testing; this + handles up to substring 31; after that we just have to take + the less precise approach + cb points to the compile data block + atomcount atomic group level + +Returns: TRUE or FALSE +*/ + +static BOOL +is_anchored(register PCRE2_SPTR code, unsigned int bracket_map, + compile_block *cb, int atomcount) +{ +do { + PCRE2_SPTR scode = first_significant_code( + code + PRIV(OP_lengths)[*code], FALSE); + register int op = *scode; + + /* Non-capturing brackets */ + + if (op == OP_BRA || op == OP_BRAPOS || + op == OP_SBRA || op == OP_SBRAPOS) + { + if (!is_anchored(scode, bracket_map, cb, atomcount)) return FALSE; + } + + /* Capturing brackets */ + + else if (op == OP_CBRA || op == OP_CBRAPOS || + op == OP_SCBRA || op == OP_SCBRAPOS) + { + int n = GET2(scode, 1+LINK_SIZE); + int new_map = bracket_map | ((n < 32)? (1u << n) : 1); + if (!is_anchored(scode, new_map, cb, atomcount)) return FALSE; + } + + /* Positive forward assertions and conditions */ + + else if (op == OP_ASSERT || op == OP_COND) + { + if (!is_anchored(scode, bracket_map, cb, atomcount)) return FALSE; + } + + /* Atomic groups */ + + else if (op == OP_ONCE || op == OP_ONCE_NC) + { + if (!is_anchored(scode, bracket_map, cb, atomcount + 1)) + return FALSE; + } + + /* .* is not anchored unless DOTALL is set (which generates OP_ALLANY) and + it isn't in brackets that are or may be referenced or inside an atomic + group. There is also an option that disables auto-anchoring. */ + + else if ((op == OP_TYPESTAR || op == OP_TYPEMINSTAR || + op == OP_TYPEPOSSTAR)) + { + if (scode[1] != OP_ALLANY || (bracket_map & cb->backref_map) != 0 || + atomcount > 0 || cb->had_pruneorskip || + (cb->external_options & PCRE2_NO_DOTSTAR_ANCHOR) != 0) + return FALSE; + } + + /* Check for explicit anchoring */ + + else if (op != OP_SOD && op != OP_SOM && op != OP_CIRC) return FALSE; + + code += GET(code, 1); + } +while (*code == OP_ALT); /* Loop for each alternative */ +return TRUE; +} + + + +/************************************************* +* Check for starting with ^ or .* * +*************************************************/ + +/* This is called to find out if every branch starts with ^ or .* so that +"first char" processing can be done to speed things up in multiline +matching and for non-DOTALL patterns that start with .* (which must start at +the beginning or after \n). As in the case of is_anchored() (see above), we +have to take account of back references to capturing brackets that contain .* +because in that case we can't make the assumption. Also, the appearance of .* +inside atomic brackets or in a pattern that contains *PRUNE or *SKIP does not +count, because once again the assumption no longer holds. + +Arguments: + code points to start of the compiled pattern or a group + bracket_map a bitmap of which brackets we are inside while testing; this + handles up to substring 31; after that we just have to take + the less precise approach + cb points to the compile data + atomcount atomic group level + +Returns: TRUE or FALSE +*/ + +static BOOL +is_startline(PCRE2_SPTR code, unsigned int bracket_map, compile_block *cb, + int atomcount) +{ +do { + PCRE2_SPTR scode = first_significant_code( + code + PRIV(OP_lengths)[*code], FALSE); + register int op = *scode; + + /* If we are at the start of a conditional assertion group, *both* the + conditional assertion *and* what follows the condition must satisfy the test + for start of line. Other kinds of condition fail. Note that there may be an + auto-callout at the start of a condition. */ + + if (op == OP_COND) + { + scode += 1 + LINK_SIZE; + + if (*scode == OP_CALLOUT) scode += PRIV(OP_lengths)[OP_CALLOUT]; + else if (*scode == OP_CALLOUT_STR) scode += GET(scode, 1 + 2*LINK_SIZE); + + switch (*scode) + { + case OP_CREF: + case OP_DNCREF: + case OP_RREF: + case OP_DNRREF: + case OP_FAIL: + case OP_FALSE: + case OP_TRUE: + return FALSE; + + default: /* Assertion */ + if (!is_startline(scode, bracket_map, cb, atomcount)) return FALSE; + do scode += GET(scode, 1); while (*scode == OP_ALT); + scode += 1 + LINK_SIZE; + break; + } + scode = first_significant_code(scode, FALSE); + op = *scode; + } + + /* Non-capturing brackets */ + + if (op == OP_BRA || op == OP_BRAPOS || + op == OP_SBRA || op == OP_SBRAPOS) + { + if (!is_startline(scode, bracket_map, cb, atomcount)) return FALSE; + } + + /* Capturing brackets */ + + else if (op == OP_CBRA || op == OP_CBRAPOS || + op == OP_SCBRA || op == OP_SCBRAPOS) + { + int n = GET2(scode, 1+LINK_SIZE); + int new_map = bracket_map | ((n < 32)? (1u << n) : 1); + if (!is_startline(scode, new_map, cb, atomcount)) return FALSE; + } + + /* Positive forward assertions */ + + else if (op == OP_ASSERT) + { + if (!is_startline(scode, bracket_map, cb, atomcount)) return FALSE; + } + + /* Atomic brackets */ + + else if (op == OP_ONCE || op == OP_ONCE_NC) + { + if (!is_startline(scode, bracket_map, cb, atomcount + 1)) return FALSE; + } + + /* .* means "start at start or after \n" if it isn't in atomic brackets or + brackets that may be referenced, as long as the pattern does not contain + *PRUNE or *SKIP, because these break the feature. Consider, for example, + /.*?a(*PRUNE)b/ with the subject "aab", which matches "ab", i.e. not at the + start of a line. There is also an option that disables this optimization. */ + + else if (op == OP_TYPESTAR || op == OP_TYPEMINSTAR || op == OP_TYPEPOSSTAR) + { + if (scode[1] != OP_ANY || (bracket_map & cb->backref_map) != 0 || + atomcount > 0 || cb->had_pruneorskip || + (cb->external_options & PCRE2_NO_DOTSTAR_ANCHOR) != 0) + return FALSE; + } + + /* Check for explicit circumflex; anything else gives a FALSE result. Note + in particular that this includes atomic brackets OP_ONCE and OP_ONCE_NC + because the number of characters matched by .* cannot be adjusted inside + them. */ + + else if (op != OP_CIRC && op != OP_CIRCM) return FALSE; + + /* Move on to the next alternative */ + + code += GET(code, 1); + } +while (*code == OP_ALT); /* Loop for each alternative */ +return TRUE; +} + + + +/************************************************* +* Check for asserted fixed first code unit * +*************************************************/ + +/* During compilation, the "first code unit" settings from forward assertions +are discarded, because they can cause conflicts with actual literals that +follow. However, if we end up without a first code unit setting for an +unanchored pattern, it is worth scanning the regex to see if there is an +initial asserted first code unit. If all branches start with the same asserted +code unit, or with a non-conditional bracket all of whose alternatives start +with the same asserted code unit (recurse ad lib), then we return that code +unit, with the flags set to zero or REQ_CASELESS; otherwise return zero with +REQ_NONE in the flags. + +Arguments: + code points to start of compiled pattern + flags points to the first code unit flags + inassert TRUE if in an assertion + +Returns: the fixed first code unit, or 0 with REQ_NONE in flags +*/ + +static uint32_t +find_firstassertedcu(PCRE2_SPTR code, int32_t *flags, BOOL inassert) +{ +register uint32_t c = 0; +int cflags = REQ_NONE; + +*flags = REQ_NONE; +do { + uint32_t d; + int dflags; + int xl = (*code == OP_CBRA || *code == OP_SCBRA || + *code == OP_CBRAPOS || *code == OP_SCBRAPOS)? IMM2_SIZE:0; + PCRE2_SPTR scode = first_significant_code(code + 1+LINK_SIZE + xl, TRUE); + register PCRE2_UCHAR op = *scode; + + switch(op) + { + default: + return 0; + + case OP_BRA: + case OP_BRAPOS: + case OP_CBRA: + case OP_SCBRA: + case OP_CBRAPOS: + case OP_SCBRAPOS: + case OP_ASSERT: + case OP_ONCE: + case OP_ONCE_NC: + d = find_firstassertedcu(scode, &dflags, op == OP_ASSERT); + if (dflags < 0) + return 0; + if (cflags < 0) { c = d; cflags = dflags; } + else if (c != d || cflags != dflags) return 0; + break; + + case OP_EXACT: + scode += IMM2_SIZE; + /* Fall through */ + + case OP_CHAR: + case OP_PLUS: + case OP_MINPLUS: + case OP_POSPLUS: + if (!inassert) return 0; + if (cflags < 0) { c = scode[1]; cflags = 0; } + else if (c != scode[1]) return 0; + break; + + case OP_EXACTI: + scode += IMM2_SIZE; + /* Fall through */ + + case OP_CHARI: + case OP_PLUSI: + case OP_MINPLUSI: + case OP_POSPLUSI: + if (!inassert) return 0; + if (cflags < 0) { c = scode[1]; cflags = REQ_CASELESS; } + else if (c != scode[1]) return 0; + break; + } + + code += GET(code, 1); + } +while (*code == OP_ALT); + +*flags = cflags; +return c; +} + + + +/************************************************* +* Add an entry to the name/number table * +*************************************************/ + +/* This function is called between compiling passes to add an entry to the +name/number table, maintaining alphabetical order. Checking for permitted +and forbidden duplicates has already been done. + +Arguments: + cb the compile data block + name the name to add + length the length of the name + groupno the group number + +Returns: nothing +*/ + +static void +add_name_to_table(compile_block *cb, PCRE2_SPTR name, int length, + unsigned int groupno) +{ +int i; +PCRE2_UCHAR *slot = cb->name_table; + +for (i = 0; i < cb->names_found; i++) + { + int crc = memcmp(name, slot+IMM2_SIZE, CU2BYTES(length)); + if (crc == 0 && slot[IMM2_SIZE+length] != 0) + crc = -1; /* Current name is a substring */ + + /* Make space in the table and break the loop for an earlier name. For a + duplicate or later name, carry on. We do this for duplicates so that in the + simple case (when ?(| is not used) they are in order of their numbers. In all + cases they are in the order in which they appear in the pattern. */ + + if (crc < 0) + { + memmove(slot + cb->name_entry_size, slot, + CU2BYTES((cb->names_found - i) * cb->name_entry_size)); + break; + } + + /* Continue the loop for a later or duplicate name */ + + slot += cb->name_entry_size; + } + +PUT2(slot, 0, groupno); +memcpy(slot + IMM2_SIZE, name, CU2BYTES(length)); +cb->names_found++; + +/* Add a terminating zero and fill the rest of the slot with zeroes so that +the memory is all initialized. Otherwise valgrind moans about uninitialized +memory when saving serialized compiled patterns. */ + +memset(slot + IMM2_SIZE + length, 0, + CU2BYTES(cb->name_entry_size - length - IMM2_SIZE)); +} + + + +/************************************************* +* External function to compile a pattern * +*************************************************/ + +/* This function reads a regular expression in the form of a string and returns +a pointer to a block of store holding a compiled version of the expression. + +Arguments: + pattern the regular expression + patlen the length of the pattern, or PCRE2_ZERO_TERMINATED + options option bits + errorptr pointer to errorcode + erroroffset pointer to error offset + ccontext points to a compile context or is NULL + +Returns: pointer to compiled data block, or NULL on error, + with errorcode and erroroffset set +*/ + +PCRE2_EXP_DEFN pcre2_code * PCRE2_CALL_CONVENTION +pcre2_compile(PCRE2_SPTR pattern, PCRE2_SIZE patlen, uint32_t options, + int *errorptr, PCRE2_SIZE *erroroffset, pcre2_compile_context *ccontext) +{ +BOOL utf; /* Set TRUE for UTF mode */ +pcre2_real_code *re = NULL; /* What we will return */ +compile_block cb; /* "Static" compile-time data */ +const uint8_t *tables; /* Char tables base pointer */ + +PCRE2_UCHAR *code; /* Current pointer in compiled code */ +PCRE2_SPTR codestart; /* Start of compiled code */ +PCRE2_SPTR ptr; /* Current pointer in pattern */ + +size_t length = 1; /* Allow or final END opcode */ +size_t usedlength; /* Actual length used */ +size_t re_blocksize; /* Size of memory block */ + +int32_t firstcuflags, reqcuflags; /* Type of first/req code unit */ +uint32_t firstcu, reqcu; /* Value of first/req code unit */ +uint32_t setflags = 0; /* NL and BSR set flags */ + +uint32_t skipatstart; /* When checking (*UTF) etc */ +uint32_t limit_match = UINT32_MAX; /* Unset match limits */ +uint32_t limit_recursion = UINT32_MAX; + +int newline = 0; /* Unset; can be set by the pattern */ +int bsr = 0; /* Unset; can be set by the pattern */ +int errorcode = 0; /* Initialize to avoid compiler warn */ + +/* Comments at the head of this file explain about these variables. */ + +PCRE2_UCHAR *copied_pattern = NULL; +PCRE2_UCHAR stack_copied_pattern[COPIED_PATTERN_SIZE]; +named_group named_groups[NAMED_GROUP_LIST_SIZE]; + +/* The workspace is used in different ways in the different compiling phases. +It needs to be 16-bit aligned for the preliminary group scan, and 32-bit +aligned for the group information cache. */ + +uint32_t c32workspace[C32_WORK_SIZE]; +PCRE2_UCHAR *cworkspace = (PCRE2_UCHAR *)c32workspace; + + +/* -------------- Check arguments and set up the pattern ----------------- */ + +/* There must be error code and offset pointers. */ + +if (errorptr == NULL || erroroffset == NULL) return NULL; +*errorptr = ERR0; +*erroroffset = 0; + +/* There must be a pattern! */ + +if (pattern == NULL) + { + *errorptr = ERR16; + return NULL; + } + +/* Check that all undefined public option bits are zero. */ + +if ((options & ~PUBLIC_COMPILE_OPTIONS) != 0) + { + *errorptr = ERR17; + return NULL; + } + +/* A NULL compile context means "use a default context" */ + +if (ccontext == NULL) + ccontext = (pcre2_compile_context *)(&PRIV(default_compile_context)); + +/* A zero-terminated pattern is indicated by the special length value +PCRE2_ZERO_TERMINATED. Otherwise, we make a copy of the pattern and add a zero, +to ensure that it is always possible to look one code unit beyond the end of +the pattern's characters. In both cases, check that the pattern is overlong. */ + +if (patlen == PCRE2_ZERO_TERMINATED) + { + patlen = PRIV(strlen)(pattern); + if (patlen > ccontext->max_pattern_length) + { + *errorptr = ERR88; + return NULL; + } + } +else + { + if (patlen > ccontext->max_pattern_length) + { + *errorptr = ERR88; + return NULL; + } + if (patlen < COPIED_PATTERN_SIZE) + copied_pattern = stack_copied_pattern; + else + { + copied_pattern = ccontext->memctl.malloc(CU2BYTES(patlen + 1), + ccontext->memctl.memory_data); + if (copied_pattern == NULL) + { + *errorptr = ERR21; + return NULL; + } + } + memcpy(copied_pattern, pattern, CU2BYTES(patlen)); + copied_pattern[patlen] = 0; + pattern = copied_pattern; + } + +/* ------------ Initialize the "static" compile data -------------- */ + +tables = (ccontext->tables != NULL)? ccontext->tables : PRIV(default_tables); + +cb.lcc = tables + lcc_offset; /* Individual */ +cb.fcc = tables + fcc_offset; /* character */ +cb.cbits = tables + cbits_offset; /* tables */ +cb.ctypes = tables + ctypes_offset; + +cb.assert_depth = 0; +cb.bracount = cb.final_bracount = 0; +cb.cx = ccontext; +cb.dupnames = FALSE; +cb.end_pattern = pattern + patlen; +cb.nestptr[0] = cb.nestptr[1] = NULL; +cb.external_flags = 0; +cb.external_options = options; +cb.groupinfo = c32workspace; +cb.had_recurse = FALSE; +cb.iscondassert = FALSE; +cb.max_lookbehind = 0; +cb.name_entry_size = 0; +cb.name_table = NULL; +cb.named_groups = named_groups; +cb.named_group_list_size = NAMED_GROUP_LIST_SIZE; +cb.names_found = 0; +cb.open_caps = NULL; +cb.parens_depth = 0; +cb.req_varyopt = 0; +cb.start_code = cworkspace; +cb.start_pattern = pattern; +cb.start_workspace = cworkspace; +cb.workspace_size = COMPILE_WORK_SIZE; + +/* Maximum back reference and backref bitmap. The bitmap records up to 31 back +references to help in deciding whether (.*) can be treated as anchored or not. +*/ + +cb.top_backref = 0; +cb.backref_map = 0; + +/* --------------- Start looking at the pattern --------------- */ + +/* Check for global one-time option settings at the start of the pattern, and +remember the offset to the actual regex. */ + +ptr = pattern; +skipatstart = 0; + +while (ptr[skipatstart] == CHAR_LEFT_PARENTHESIS && + ptr[skipatstart+1] == CHAR_ASTERISK) + { + unsigned int i; + for (i = 0; i < sizeof(pso_list)/sizeof(pso); i++) + { + pso *p = pso_list + i; + + if (PRIV(strncmp_c8)(ptr+skipatstart+2, (char *)(p->name), p->length) == 0) + { + uint32_t c, pp; + + skipatstart += p->length + 2; + switch(p->type) + { + case PSO_OPT: + cb.external_options |= p->value; + break; + + case PSO_FLG: + setflags |= p->value; + break; + + case PSO_NL: + newline = p->value; + setflags |= PCRE2_NL_SET; + break; + + case PSO_BSR: + bsr = p->value; + setflags |= PCRE2_BSR_SET; + break; + + case PSO_LIMM: + case PSO_LIMR: + c = 0; + pp = skipatstart; + if (!IS_DIGIT(ptr[pp])) + { + errorcode = ERR60; + ptr += pp; + goto HAD_ERROR; + } + while (IS_DIGIT(ptr[pp])) + { + if (c > UINT32_MAX / 10 - 1) break; /* Integer overflow */ + c = c*10 + (ptr[pp++] - CHAR_0); + } + if (ptr[pp++] != CHAR_RIGHT_PARENTHESIS) + { + errorcode = ERR60; + ptr += pp; + goto HAD_ERROR; + } + if (p->type == PSO_LIMM) limit_match = c; + else limit_recursion = c; + skipatstart += pp - skipatstart; + break; + } + break; /* Out of the table scan loop */ + } + } + if (i >= sizeof(pso_list)/sizeof(pso)) break; /* Out of pso loop */ + } + +/* End of pattern-start options; advance to start of real regex. */ + +ptr += skipatstart; + +/* Can't support UTF or UCP unless PCRE2 has been compiled with UTF support. */ + +#ifndef SUPPORT_UNICODE +if ((cb.external_options & (PCRE2_UTF|PCRE2_UCP)) != 0) + { + errorcode = ERR32; + goto HAD_ERROR; + } +#endif + +/* Check UTF. We have the original options in 'options', with that value as +modified by (*UTF) etc in cb->external_options. */ + +utf = (cb.external_options & PCRE2_UTF) != 0; +if (utf) + { + if ((options & PCRE2_NEVER_UTF) != 0) + { + errorcode = ERR74; + goto HAD_ERROR; + } + if ((options & PCRE2_NO_UTF_CHECK) == 0 && + (errorcode = PRIV(valid_utf)(pattern, patlen, erroroffset)) != 0) + goto HAD_UTF_ERROR; + } + +/* Check UCP lockout. */ + +if ((cb.external_options & (PCRE2_UCP|PCRE2_NEVER_UCP)) == + (PCRE2_UCP|PCRE2_NEVER_UCP)) + { + errorcode = ERR75; + goto HAD_ERROR; + } + +/* Process the BSR setting. */ + +if (bsr == 0) bsr = ccontext->bsr_convention; + +/* Process the newline setting. */ + +if (newline == 0) newline = ccontext->newline_convention; +cb.nltype = NLTYPE_FIXED; +switch(newline) + { + case PCRE2_NEWLINE_CR: + cb.nllen = 1; + cb.nl[0] = CHAR_CR; + break; + + case PCRE2_NEWLINE_LF: + cb.nllen = 1; + cb.nl[0] = CHAR_NL; + break; + + case PCRE2_NEWLINE_CRLF: + cb.nllen = 2; + cb.nl[0] = CHAR_CR; + cb.nl[1] = CHAR_NL; + break; + + case PCRE2_NEWLINE_ANY: + cb.nltype = NLTYPE_ANY; + break; + + case PCRE2_NEWLINE_ANYCRLF: + cb.nltype = NLTYPE_ANYCRLF; + break; + + default: + errorcode = ERR56; + goto HAD_ERROR; + } + +/* Before we do anything else, do a pre-scan of the pattern in order to +discover the named groups and their numerical equivalents, so that this +information is always available for the remaining processing. */ + +errorcode = scan_for_captures(&ptr, cb.external_options, &cb); +if (errorcode != 0) goto HAD_ERROR; + +/* For obscure debugging this code can be enabled. */ + +#if 0 + { + int i; + named_group *ng = cb.named_groups; + fprintf(stderr, "+++Captures: %d\n", cb.final_bracount); + for (i = 0; i < cb.names_found; i++, ng++) + { + fprintf(stderr, "+++%3d %.*s\n", ng->number, ng->length, ng->name); + } + } +#endif + +/* Reset current bracket count to zero and current pointer to the start of the +pattern. */ + +cb.bracount = 0; +ptr = pattern + skipatstart; + +/* Pretend to compile the pattern while actually just accumulating the amount +of memory required in the 'length' variable. This behaviour is triggered by +passing a non-NULL final argument to compile_regex(). We pass a block of +workspace (cworkspace) for it to compile parts of the pattern into; the +compiled code is discarded when it is no longer needed, so hopefully this +workspace will never overflow, though there is a test for its doing so. + +On error, errorcode will be set non-zero, so we don't need to look at the +result of the function. The initial options have been put into the cb block so +that they can be changed if an option setting is found within the regex right +at the beginning. Bringing initial option settings outside can help speed up +starting point checks. We still have to pass a separate options variable (the +first argument) because that may change as the pattern is processed. */ + +code = cworkspace; +*code = OP_BRA; + +(void)compile_regex(cb.external_options, &code, &ptr, &errorcode, FALSE, + FALSE, 0, 0, &firstcu, &firstcuflags, &reqcu, &reqcuflags, NULL, + &cb, &length); + +if (errorcode != 0) goto HAD_ERROR; +if (length > MAX_PATTERN_SIZE) + { + errorcode = ERR20; + goto HAD_ERROR; + } + +/* Compute the size of, and then get and initialize, the data block for storing +the compiled pattern and names table. Integer overflow should no longer be +possible because nowadays we limit the maximum value of cb.names_found and +cb.name_entry_size. */ + +re_blocksize = sizeof(pcre2_real_code) + + CU2BYTES(length + cb.names_found * cb.name_entry_size); +re = (pcre2_real_code *) + ccontext->memctl.malloc(re_blocksize, ccontext->memctl.memory_data); +if (re == NULL) + { + errorcode = ERR21; + goto HAD_ERROR; + } + +re->memctl = ccontext->memctl; +re->tables = tables; +re->executable_jit = NULL; +memset(re->start_bitmap, 0, 32 * sizeof(uint8_t)); +re->blocksize = re_blocksize; +re->magic_number = MAGIC_NUMBER; +re->compile_options = options; +re->overall_options = cb.external_options; +re->flags = PCRE2_CODE_UNIT_WIDTH/8 | cb.external_flags | setflags; +re->limit_match = limit_match; +re->limit_recursion = limit_recursion; +re->first_codeunit = 0; +re->last_codeunit = 0; +re->bsr_convention = bsr; +re->newline_convention = newline; +re->max_lookbehind = 0; +re->minlength = 0; +re->top_bracket = 0; +re->top_backref = 0; +re->name_entry_size = cb.name_entry_size; +re->name_count = cb.names_found; + +/* The basic block is immediately followed by the name table, and the compiled +code follows after that. */ + +codestart = (PCRE2_SPTR)((uint8_t *)re + sizeof(pcre2_real_code)) + + re->name_entry_size * re->name_count; + +/* Workspace is needed to remember information about numbered groups: whether a +group can match an empty string and what its fixed length is. This is done to +avoid the possibility of recursive references causing very long compile times +when checking these features. Unnumbered groups do not have this exposure since +they cannot be referenced. We use an indexed vector for this purpose. If there +are sufficiently few groups, it can be the c32workspace vector, as set up +above. Otherwise we have to get/free a special vector. The vector must be +initialized to zero. */ + +if (cb.final_bracount >= C32_WORK_SIZE) + { + cb.groupinfo = ccontext->memctl.malloc( + (cb.final_bracount + 1)*sizeof(uint32_t), ccontext->memctl.memory_data); + if (cb.groupinfo == NULL) + { + errorcode = ERR21; + goto HAD_ERROR; + } + } +memset(cb.groupinfo, 0, (cb.final_bracount + 1) * sizeof(uint32_t)); + +/* Update the compile data block for the actual compile. The starting points of +the name/number translation table and of the code are passed around in the +compile data block. The start/end pattern and initial options are already set +from the pre-compile phase, as is the name_entry_size field. Reset the bracket +count and the names_found field. */ + +cb.parens_depth = 0; +cb.assert_depth = 0; +cb.bracount = 0; +cb.max_lookbehind = 0; +cb.name_table = (PCRE2_UCHAR *)((uint8_t *)re + sizeof(pcre2_real_code)); +cb.start_code = codestart; +cb.iscondassert = FALSE; +cb.req_varyopt = 0; +cb.had_accept = FALSE; +cb.had_pruneorskip = FALSE; +cb.check_lookbehind = FALSE; +cb.open_caps = NULL; + +/* If any named groups were found, create the name/number table from the list +created in the pre-pass. */ + +if (cb.names_found > 0) + { + int i = cb.names_found; + named_group *ng = cb.named_groups; + cb.names_found = 0; + for (; i > 0; i--, ng++) + add_name_to_table(&cb, ng->name, ng->length, ng->number); + } + +/* Set up a starting, non-extracting bracket, then compile the expression. On +error, errorcode will be set non-zero, so we don't need to look at the result +of the function here. */ + +ptr = pattern + skipatstart; +code = (PCRE2_UCHAR *)codestart; +*code = OP_BRA; +(void)compile_regex(re->overall_options, &code, &ptr, &errorcode, FALSE, FALSE, + 0, 0, &firstcu, &firstcuflags, &reqcu, &reqcuflags, NULL, &cb, NULL); + +re->top_bracket = cb.bracount; +re->top_backref = cb.top_backref; +re->max_lookbehind = cb.max_lookbehind; + +if (cb.had_accept) + { + reqcu = 0; /* Must disable after (*ACCEPT) */ + reqcuflags = REQ_NONE; + } + +/* Fill in the final opcode and check for disastrous overflow. If no overflow, +but the estimated length exceeds the really used length, adjust the value of +re->blocksize, and if valgrind support is configured, mark the extra allocated +memory as unaddressable, so that any out-of-bound reads can be detected. */ + +*code++ = OP_END; +usedlength = code - codestart; +if (usedlength > length) errorcode = ERR23; else + { + re->blocksize -= CU2BYTES(length - usedlength); +#ifdef SUPPORT_VALGRIND + VALGRIND_MAKE_MEM_NOACCESS(code, CU2BYTES(length - usedlength)); +#endif + } + +/* Scan the pattern for recursion/subroutine calls and convert the group +numbers into offsets. Maintain a small cache so that repeated groups containing +recursions are efficiently handled. */ + +#define RSCAN_CACHE_SIZE 8 + +if (errorcode == 0 && cb.had_recurse) + { + PCRE2_UCHAR *rcode; + PCRE2_SPTR rgroup; + int ccount = 0; + int start = RSCAN_CACHE_SIZE; + recurse_cache rc[RSCAN_CACHE_SIZE]; + + for (rcode = (PCRE2_UCHAR *)find_recurse(codestart, utf); + rcode != NULL; + rcode = (PCRE2_UCHAR *)find_recurse(rcode + 1 + LINK_SIZE, utf)) + { + int i, p, recno; + + recno = (int)GET(rcode, 1); + if (recno == 0) rgroup = codestart; else + { + PCRE2_SPTR search_from = codestart; + rgroup = NULL; + for (i = 0, p = start; i < ccount; i++, p = (p + 1) & 7) + { + if (recno == rc[p].recno) + { + rgroup = rc[p].group; + break; + } + + /* Group n+1 must always start to the right of group n, so we can save + search time below when the new group number is greater than any of the + previously found groups. */ + + if (recno > rc[p].recno) search_from = rc[p].group; + } + + if (rgroup == NULL) + { + rgroup = PRIV(find_bracket)(search_from, utf, recno); + if (rgroup == NULL) + { + errorcode = ERR53; + break; + } + if (--start < 0) start = RSCAN_CACHE_SIZE - 1; + rc[start].recno = recno; + rc[start].group = rgroup; + if (ccount < RSCAN_CACHE_SIZE) ccount++; + } + } + + PUT(rcode, 1, rgroup - codestart); + } + } + +/* In rare debugging situations we sometimes need to look at the compiled code +at this stage. */ + +#ifdef CALL_PRINTINT +pcre2_printint(re, stderr, TRUE); +fprintf(stderr, "Length=%lu Used=%lu\n", length, usedlength); +#endif + +/* After a successful compile, give an error if there's back reference to a +non-existent capturing subpattern. Then, unless disabled, check whether any +single character iterators can be auto-possessified. The function overwrites +the appropriate opcode values, so the type of the pointer must be cast. NOTE: +the intermediate variable "temp" is used in this code because at least one +compiler gives a warning about loss of "const" attribute if the cast +(PCRE2_UCHAR *)codestart is used directly in the function call. */ + +if (errorcode == 0) + { + if (re->top_backref > re->top_bracket) errorcode = ERR15; + else if ((re->overall_options & PCRE2_NO_AUTO_POSSESS) == 0) + { + PCRE2_UCHAR *temp = (PCRE2_UCHAR *)codestart; + if (PRIV(auto_possessify)(temp, utf, &cb) != 0) errorcode = ERR80; + } + } + +/* If there were any lookbehind assertions that contained OP_RECURSE +(recursions or subroutine calls), a flag is set for them to be checked here, +because they may contain forward references. Actual recursions cannot be fixed +length, but subroutine calls can. It is done like this so that those without +OP_RECURSE that are not fixed length get a diagnosic with a useful offset. The +exceptional ones forgo this. We scan the pattern to check that they are fixed +length, and set their lengths. */ + +if (errorcode == 0 && cb.check_lookbehind) + { + PCRE2_UCHAR *cc = (PCRE2_UCHAR *)codestart; + + /* Loop, searching for OP_REVERSE items, and process those that do not have + their length set. (Actually, it will also re-process any that have a length + of zero, but that is a pathological case, and it does no harm.) When we find + one, we temporarily terminate the branch it is in while we scan it. Note that + calling find_bracket() with a negative group number returns a pointer to the + OP_REVERSE item, not the actual lookbehind. */ + + for (cc = (PCRE2_UCHAR *)PRIV(find_bracket)(codestart, utf, -1); + cc != NULL; + cc = (PCRE2_UCHAR *)PRIV(find_bracket)(cc, utf, -1)) + { + if (GET(cc, 1) == 0) + { + int fixed_length; + int count = 0; + PCRE2_UCHAR *be = cc - 1 - LINK_SIZE + GET(cc, -LINK_SIZE); + int end_op = *be; + *be = OP_END; + fixed_length = find_fixedlength(cc, utf, TRUE, &cb, NULL, &count); + *be = end_op; + if (fixed_length < 0) + { + errorcode = fixed_length_errors[-fixed_length]; + break; + } + if (fixed_length > cb.max_lookbehind) cb.max_lookbehind = fixed_length; + PUT(cc, 1, fixed_length); + } + cc += 1 + LINK_SIZE; + } + + /* The previous value of the maximum lookbehind was transferred to the + compiled regex block above. We could have updated this value in the loop + above, but keep the two values in step, just in case some later code below + uses the cb value. */ + + re->max_lookbehind = cb.max_lookbehind; + } + +/* Failed to compile, or error while post-processing. Earlier errors get here +via the dreaded goto. */ + +if (errorcode != 0) + { + HAD_ERROR: + *erroroffset = (int)(ptr - pattern); + HAD_UTF_ERROR: + *errorptr = errorcode; + pcre2_code_free(re); + re = NULL; + goto EXIT; + } + +/* Successful compile. If the anchored option was not passed, set it if +we can determine that the pattern is anchored by virtue of ^ characters or \A +or anything else, such as starting with non-atomic .* when DOTALL is set and +there are no occurrences of *PRUNE or *SKIP (though there is an option to +disable this case). */ + +if ((re->overall_options & PCRE2_ANCHORED) == 0 && + is_anchored(codestart, 0, &cb, 0)) + re->overall_options |= PCRE2_ANCHORED; + +/* If the pattern is still not anchored and we do not have a first code unit, +see if there is one that is asserted (these are not saved during the compile +because they can cause conflicts with actual literals that follow). This code +need not be obeyed if PCRE2_NO_START_OPTIMIZE is set, as the data it would +create will not be used. */ + +if ((re->overall_options & (PCRE2_ANCHORED|PCRE2_NO_START_OPTIMIZE)) == 0) + { + if (firstcuflags < 0) + firstcu = find_firstassertedcu(codestart, &firstcuflags, FALSE); + + /* Save the data for a first code unit. */ + + if (firstcuflags >= 0) + { + re->first_codeunit = firstcu; + re->flags |= PCRE2_FIRSTSET; + + /* Handle caseless first code units. */ + + if ((firstcuflags & REQ_CASELESS) != 0) + { + if (firstcu < 128 || (!utf && firstcu < 255)) + { + if (cb.fcc[firstcu] != firstcu) re->flags |= PCRE2_FIRSTCASELESS; + } + + /* The first code unit is > 128 in UTF mode, or > 255 otherwise. In + 8-bit UTF mode, codepoints in the range 128-255 are introductory code + points and cannot have another case. In 16-bit and 32-bit modes, we can + check wide characters when UTF (and therefore UCP) is supported. */ + +#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 8 + else if (firstcu <= MAX_UTF_CODE_POINT && + UCD_OTHERCASE(firstcu) != firstcu) + re->flags |= PCRE2_FIRSTCASELESS; +#endif + } + } + + /* When there is no first code unit, see if we can set the PCRE2_STARTLINE + flag. This is helpful for multiline matches when all branches start with ^ + and also when all branches start with non-atomic .* for non-DOTALL matches + when *PRUNE and SKIP are not present. (There is an option that disables this + case.) */ + + else if (is_startline(codestart, 0, &cb, 0)) re->flags |= PCRE2_STARTLINE; + } + +/* Handle the "required code unit", if one is set. In the case of an anchored +pattern, do this only if it follows a variable length item in the pattern. +Again, skip this if PCRE2_NO_START_OPTIMIZE is set. */ + +if (reqcuflags >= 0 && + ((re->overall_options & (PCRE2_ANCHORED|PCRE2_NO_START_OPTIMIZE)) == 0 || + (reqcuflags & REQ_VARY) != 0)) + { + re->last_codeunit = reqcu; + re->flags |= PCRE2_LASTSET; + + /* Handle caseless required code units as for first code units (above). */ + + if ((reqcuflags & REQ_CASELESS) != 0) + { + if (reqcu < 128 || (!utf && reqcu < 255)) + { + if (cb.fcc[reqcu] != reqcu) re->flags |= PCRE2_LASTCASELESS; + } +#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 8 + else if (reqcu <= MAX_UTF_CODE_POINT && UCD_OTHERCASE(reqcu) != reqcu) + re->flags |= PCRE2_LASTCASELESS; +#endif + } + } + +/* Check for a pattern than can match an empty string, so that this information +can be provided to applications. */ + +do + { + int count = 0; + int rc = could_be_empty_branch(codestart, code, utf, &cb, TRUE, NULL, &count); + if (rc < 0) + { + errorcode = ERR86; + goto HAD_ERROR; + } + if (rc > 0) + { + re->flags |= PCRE2_MATCH_EMPTY; + break; + } + codestart += GET(codestart, 1); + } +while (*codestart == OP_ALT); + +/* Finally, unless PCRE2_NO_START_OPTIMIZE is set, study the compiled pattern +to set up information such as a bitmap of starting code units and a minimum +matching length. */ + +if ((re->overall_options & PCRE2_NO_START_OPTIMIZE) == 0 && + PRIV(study)(re) != 0) + { + errorcode = ERR31; + goto HAD_ERROR; + } + +/* Control ends up here in all cases. If memory was obtained for a +zero-terminated copy of the pattern, remember to free it before returning. Also +free the list of named groups if a larger one had to be obtained, and likewise +the group information vector. */ + +EXIT: +if (copied_pattern != stack_copied_pattern) + ccontext->memctl.free(copied_pattern, ccontext->memctl.memory_data); +if (cb.named_group_list_size > NAMED_GROUP_LIST_SIZE) + ccontext->memctl.free((void *)cb.named_groups, ccontext->memctl.memory_data); +if (cb.groupinfo != c32workspace) + ccontext->memctl.free((void *)cb.groupinfo, ccontext->memctl.memory_data); + +return re; /* Will be NULL after an error */ +} + +/* End of pcre2_compile.c */ + #pragma warning(pop) \ No newline at end of file diff --git a/ProcessHacker/pcre/pcre2_match.c b/ProcessHacker/pcre/pcre2_match.c index 9a8a472e7361..bf770ab90cb0 100644 --- a/ProcessHacker/pcre/pcre2_match.c +++ b/ProcessHacker/pcre/pcre2_match.c @@ -38,8 +38,8 @@ POSSIBILITY OF SUCH DAMAGE. ----------------------------------------------------------------------------- */ -// dmex: Disable warnings -#pragma warning(push) +// dmex: Disable warnings +#pragma warning(push) #pragma warning(disable : 4267) #define HAVE_CONFIG_H diff --git a/ProcessHacker/pcre/pcre2posix.c b/ProcessHacker/pcre/pcre2posix.c index 6a71969340d4..eb5926550119 100644 --- a/ProcessHacker/pcre/pcre2posix.c +++ b/ProcessHacker/pcre/pcre2posix.c @@ -38,8 +38,8 @@ POSSIBILITY OF SUCH DAMAGE. ----------------------------------------------------------------------------- */ -// dmex: Disable warnings -#pragma warning(push) +// dmex: Disable warnings +#pragma warning(push) #pragma warning(disable : 4267) /* This module is a wrapper that provides a POSIX API to the underlying PCRE2 diff --git a/ProcessHacker/phsvc/clapi.c b/ProcessHacker/phsvc/clapi.c index 3772cf25e837..5a5cfb5b867a 100644 --- a/ProcessHacker/phsvc/clapi.c +++ b/ProcessHacker/phsvc/clapi.c @@ -1,1217 +1,1217 @@ -/* - * Process Hacker - - * phsvc client - * - * Copyright (C) 2011-2015 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include -#include - -HANDLE PhSvcClPortHandle; -PVOID PhSvcClPortHeap; -HANDLE PhSvcClServerProcessId; - -NTSTATUS PhSvcConnectToServer( - _In_ PUNICODE_STRING PortName, - _In_opt_ SIZE_T PortSectionSize - ) -{ - NTSTATUS status; - HANDLE sectionHandle; - LARGE_INTEGER sectionSize; - PORT_VIEW clientView; - REMOTE_PORT_VIEW serverView; - SECURITY_QUALITY_OF_SERVICE securityQos; - ULONG maxMessageLength; - PHSVC_API_CONNECTINFO connectInfo; - ULONG connectInfoLength; - - if (PhSvcClPortHandle) - return STATUS_ADDRESS_ALREADY_EXISTS; - - if (PortSectionSize == 0) - PortSectionSize = 512 * 1024; - - // Create the port section and connect to the port. - - sectionSize.QuadPart = PortSectionSize; - status = NtCreateSection( - §ionHandle, - SECTION_ALL_ACCESS, - NULL, - §ionSize, - PAGE_READWRITE, - SEC_COMMIT, - NULL - ); - - if (!NT_SUCCESS(status)) - return status; - - clientView.Length = sizeof(PORT_VIEW); - clientView.SectionHandle = sectionHandle; - clientView.SectionOffset = 0; - clientView.ViewSize = PortSectionSize; - clientView.ViewBase = NULL; - clientView.ViewRemoteBase = NULL; - - serverView.Length = sizeof(REMOTE_PORT_VIEW); - serverView.ViewSize = 0; - serverView.ViewBase = NULL; - - securityQos.Length = sizeof(SECURITY_QUALITY_OF_SERVICE); - securityQos.ImpersonationLevel = SecurityImpersonation; - securityQos.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING; - securityQos.EffectiveOnly = TRUE; - - connectInfoLength = sizeof(PHSVC_API_CONNECTINFO); - - status = NtConnectPort( - &PhSvcClPortHandle, - PortName, - &securityQos, - &clientView, - &serverView, - &maxMessageLength, - &connectInfo, - &connectInfoLength - ); - NtClose(sectionHandle); - - if (!NT_SUCCESS(status)) - return status; - - PhSvcClServerProcessId = UlongToHandle(connectInfo.ServerProcessId); - - // Create the port heap. - - PhSvcClPortHeap = RtlCreateHeap( - HEAP_CLASS_1, - clientView.ViewBase, - clientView.ViewSize, - PAGE_SIZE, - NULL, - NULL - ); - - if (!PhSvcClPortHeap) - { - NtClose(PhSvcClPortHandle); - return STATUS_INSUFFICIENT_RESOURCES; - } - - return status; -} - -VOID PhSvcDisconnectFromServer( - VOID - ) -{ - if (PhSvcClPortHeap) - { - RtlDestroyHeap(PhSvcClPortHeap); - PhSvcClPortHeap = NULL; - } - - if (PhSvcClPortHandle) - { - NtClose(PhSvcClPortHandle); - PhSvcClPortHandle = NULL; - } - - PhSvcClServerProcessId = NULL; -} - -PVOID PhSvcpAllocateHeap( - _In_ SIZE_T Size, - _Out_ PULONG Offset - ) -{ - PVOID memory; - - if (!PhSvcClPortHeap) - return NULL; - - memory = RtlAllocateHeap(PhSvcClPortHeap, 0, Size); - - if (!memory) - return NULL; - - *Offset = (ULONG)((ULONG_PTR)memory - (ULONG_PTR)PhSvcClPortHeap); - - return memory; -} - -VOID PhSvcpFreeHeap( - _In_ PVOID Memory - ) -{ - if (!PhSvcClPortHeap) - return; - - RtlFreeHeap(PhSvcClPortHeap, 0, Memory); -} - -PVOID PhSvcpCreateString( - _In_opt_ PVOID String, - _In_ SIZE_T Length, - _Out_ PPH_RELATIVE_STRINGREF StringRef - ) -{ - PVOID memory; - SIZE_T length; - ULONG offset; - - if (Length != -1) - length = Length; - else - length = PhCountStringZ(String) * sizeof(WCHAR); - - if (length > MAXULONG32) - return NULL; - - memory = PhSvcpAllocateHeap(length, &offset); - - if (!memory) - return NULL; - - if (String) - memcpy(memory, String, length); - - StringRef->Length = (ULONG)length; - StringRef->Offset = offset; - - return memory; -} - -NTSTATUS PhSvcpCallServer( - _Inout_ PPHSVC_API_MSG Message - ) -{ - NTSTATUS status; - - Message->h.u1.s1.DataLength = sizeof(PHSVC_API_MSG) - FIELD_OFFSET(PHSVC_API_MSG, p); - Message->h.u1.s1.TotalLength = sizeof(PHSVC_API_MSG); - Message->h.u2.ZeroInit = 0; - - status = NtRequestWaitReplyPort(PhSvcClPortHandle, &Message->h, &Message->h); - - if (!NT_SUCCESS(status)) - return status; - - return Message->p.ReturnStatus; -} - -NTSTATUS PhSvcCallPlugin( - _In_ PPH_STRINGREF ApiId, - _In_reads_bytes_opt_(InLength) PVOID InBuffer, - _In_ ULONG InLength, - _Out_writes_bytes_opt_(OutLength) PVOID OutBuffer, - _In_ ULONG OutLength - ) -{ - NTSTATUS status; - PHSVC_API_MSG m; - PVOID apiId = NULL; - - memset(&m, 0, sizeof(PHSVC_API_MSG)); - - if (!PhSvcClPortHandle) - return STATUS_PORT_DISCONNECTED; - if (InLength > sizeof(m.p.u.Plugin.i.Data)) - return STATUS_BUFFER_OVERFLOW; - - m.p.ApiNumber = PhSvcPluginApiNumber; - - if (!(apiId = PhSvcpCreateString(ApiId->Buffer, ApiId->Length, &m.p.u.Plugin.i.ApiId))) - return STATUS_NO_MEMORY; - - if (InLength != 0) - memcpy(m.p.u.Plugin.i.Data, InBuffer, InLength); - - status = PhSvcpCallServer(&m); - - if (OutLength != 0) - memcpy(OutBuffer, m.p.u.Plugin.o.Data, min(OutLength, sizeof(m.p.u.Plugin.o.Data))); - - if (apiId) - PhSvcpFreeHeap(apiId); - - return status; -} - -NTSTATUS PhSvcpCallExecuteRunAsCommand( - _In_ PHSVC_API_NUMBER ApiNumber, - _In_ PPH_RUNAS_SERVICE_PARAMETERS Parameters - ) -{ - NTSTATUS status; - PHSVC_API_MSG m; - PVOID userName = NULL; - PVOID password = NULL; - ULONG passwordLength; - PVOID currentDirectory = NULL; - PVOID commandLine = NULL; - PVOID fileName = NULL; - PVOID desktopName = NULL; - PVOID serviceName = NULL; - - memset(&m, 0, sizeof(PHSVC_API_MSG)); - - if (!PhSvcClPortHandle) - return STATUS_PORT_DISCONNECTED; - - m.p.ApiNumber = ApiNumber; - - m.p.u.ExecuteRunAsCommand.i.ProcessId = Parameters->ProcessId; - m.p.u.ExecuteRunAsCommand.i.LogonType = Parameters->LogonType; - m.p.u.ExecuteRunAsCommand.i.SessionId = Parameters->SessionId; - m.p.u.ExecuteRunAsCommand.i.UseLinkedToken = Parameters->UseLinkedToken; - - status = STATUS_NO_MEMORY; - - if (Parameters->UserName && !(userName = PhSvcpCreateString(Parameters->UserName, -1, &m.p.u.ExecuteRunAsCommand.i.UserName))) - goto CleanupExit; - - if (Parameters->Password) - { - if (!(password = PhSvcpCreateString(Parameters->Password, -1, &m.p.u.ExecuteRunAsCommand.i.Password))) - goto CleanupExit; - - passwordLength = m.p.u.ExecuteRunAsCommand.i.Password.Length; - } - - if (Parameters->CurrentDirectory && !(currentDirectory = PhSvcpCreateString(Parameters->CurrentDirectory, -1, &m.p.u.ExecuteRunAsCommand.i.CurrentDirectory))) - goto CleanupExit; - if (Parameters->CommandLine && !(commandLine = PhSvcpCreateString(Parameters->CommandLine, -1, &m.p.u.ExecuteRunAsCommand.i.CommandLine))) - goto CleanupExit; - if (Parameters->FileName && !(fileName = PhSvcpCreateString(Parameters->FileName, -1, &m.p.u.ExecuteRunAsCommand.i.FileName))) - goto CleanupExit; - if (Parameters->DesktopName && !(desktopName = PhSvcpCreateString(Parameters->DesktopName, -1, &m.p.u.ExecuteRunAsCommand.i.DesktopName))) - goto CleanupExit; - if (Parameters->ServiceName && !(serviceName = PhSvcpCreateString(Parameters->ServiceName, -1, &m.p.u.ExecuteRunAsCommand.i.ServiceName))) - goto CleanupExit; - - status = PhSvcpCallServer(&m); - -CleanupExit: - if (serviceName) PhSvcpFreeHeap(serviceName); - if (desktopName) PhSvcpFreeHeap(desktopName); - if (fileName) PhSvcpFreeHeap(fileName); - if (commandLine) PhSvcpFreeHeap(commandLine); - if (currentDirectory) PhSvcpFreeHeap(currentDirectory); - - if (password) - { - RtlSecureZeroMemory(password, passwordLength); - PhSvcpFreeHeap(password); - } - - if (userName) PhSvcpFreeHeap(userName); - - return status; -} - -NTSTATUS PhSvcCallExecuteRunAsCommand( - _In_ PPH_RUNAS_SERVICE_PARAMETERS Parameters - ) -{ - return PhSvcpCallExecuteRunAsCommand(PhSvcExecuteRunAsCommandApiNumber, Parameters); -} - -NTSTATUS PhSvcCallUnloadDriver( - _In_opt_ PVOID BaseAddress, - _In_opt_ PWSTR Name - ) -{ - NTSTATUS status; - PHSVC_API_MSG m; - PVOID name = NULL; - - memset(&m, 0, sizeof(PHSVC_API_MSG)); - - if (!PhSvcClPortHandle) - return STATUS_PORT_DISCONNECTED; - - m.p.ApiNumber = PhSvcUnloadDriverApiNumber; - - m.p.u.UnloadDriver.i.BaseAddress = BaseAddress; - - if (Name) - { - name = PhSvcpCreateString(Name, -1, &m.p.u.UnloadDriver.i.Name); - - if (!name) - return STATUS_NO_MEMORY; - } - - status = PhSvcpCallServer(&m); - - if (name) - PhSvcpFreeHeap(name); - - return status; -} - -NTSTATUS PhSvcCallControlProcess( - _In_ HANDLE ProcessId, - _In_ PHSVC_API_CONTROLPROCESS_COMMAND Command, - _In_ ULONG Argument - ) -{ - PHSVC_API_MSG m; - - if (!PhSvcClPortHandle) - return STATUS_PORT_DISCONNECTED; - - m.p.ApiNumber = PhSvcControlProcessApiNumber; - m.p.u.ControlProcess.i.ProcessId = ProcessId; - m.p.u.ControlProcess.i.Command = Command; - m.p.u.ControlProcess.i.Argument = Argument; - - return PhSvcpCallServer(&m); -} - -NTSTATUS PhSvcCallControlService( - _In_ PWSTR ServiceName, - _In_ PHSVC_API_CONTROLSERVICE_COMMAND Command - ) -{ - NTSTATUS status; - PHSVC_API_MSG m; - PVOID serviceName; - - if (!PhSvcClPortHandle) - return STATUS_PORT_DISCONNECTED; - - m.p.ApiNumber = PhSvcControlServiceApiNumber; - - serviceName = PhSvcpCreateString(ServiceName, -1, &m.p.u.ControlService.i.ServiceName); - m.p.u.ControlService.i.Command = Command; - - if (serviceName) - { - status = PhSvcpCallServer(&m); - } - else - { - status = STATUS_NO_MEMORY; - } - - if (serviceName) - PhSvcpFreeHeap(serviceName); - - return status; -} - -NTSTATUS PhSvcCallCreateService( - _In_ PWSTR ServiceName, - _In_opt_ PWSTR DisplayName, - _In_ ULONG ServiceType, - _In_ ULONG StartType, - _In_ ULONG ErrorControl, - _In_opt_ PWSTR BinaryPathName, - _In_opt_ PWSTR LoadOrderGroup, - _Out_opt_ PULONG TagId, - _In_opt_ PWSTR Dependencies, - _In_opt_ PWSTR ServiceStartName, - _In_opt_ PWSTR Password - ) -{ - NTSTATUS status; - PHSVC_API_MSG m; - PVOID serviceName = NULL; - PVOID displayName = NULL; - PVOID binaryPathName = NULL; - PVOID loadOrderGroup = NULL; - PVOID dependencies = NULL; - PVOID serviceStartName = NULL; - PVOID password = NULL; - ULONG passwordLength; - - memset(&m, 0, sizeof(PHSVC_API_MSG)); - - if (!PhSvcClPortHandle) - return STATUS_PORT_DISCONNECTED; - - m.p.ApiNumber = PhSvcCreateServiceApiNumber; - - m.p.u.CreateService.i.ServiceType = ServiceType; - m.p.u.CreateService.i.StartType = StartType; - m.p.u.CreateService.i.ErrorControl = ErrorControl; - m.p.u.CreateService.i.TagIdSpecified = TagId != NULL; - - status = STATUS_NO_MEMORY; - - if (!(serviceName = PhSvcpCreateString(ServiceName, -1, &m.p.u.CreateService.i.ServiceName))) - goto CleanupExit; - if (DisplayName && !(displayName = PhSvcpCreateString(DisplayName, -1, &m.p.u.CreateService.i.DisplayName))) - goto CleanupExit; - if (BinaryPathName && !(binaryPathName = PhSvcpCreateString(BinaryPathName, -1, &m.p.u.CreateService.i.BinaryPathName))) - goto CleanupExit; - if (LoadOrderGroup && !(loadOrderGroup = PhSvcpCreateString(LoadOrderGroup, -1, &m.p.u.CreateService.i.LoadOrderGroup))) - goto CleanupExit; - - if (Dependencies) - { - SIZE_T dependenciesLength; - SIZE_T partCount; - PWSTR part; - - dependenciesLength = sizeof(WCHAR); - part = Dependencies; - - do - { - partCount = PhCountStringZ(part) + 1; - part += partCount; - dependenciesLength += partCount * sizeof(WCHAR); - } while (partCount != 1); // stop at empty dependency part - - if (!(dependencies = PhSvcpCreateString(Dependencies, dependenciesLength, &m.p.u.CreateService.i.Dependencies))) - goto CleanupExit; - } - - if (ServiceStartName && !(serviceStartName = PhSvcpCreateString(ServiceStartName, -1, &m.p.u.CreateService.i.ServiceStartName))) - goto CleanupExit; - - if (Password) - { - if (!(password = PhSvcpCreateString(Password, -1, &m.p.u.CreateService.i.Password))) - goto CleanupExit; - - passwordLength = m.p.u.CreateService.i.Password.Length; - } - - status = PhSvcpCallServer(&m); - - if (NT_SUCCESS(status)) - { - if (TagId) - *TagId = m.p.u.CreateService.o.TagId; - } - -CleanupExit: - if (password) - { - RtlSecureZeroMemory(password, passwordLength); - PhSvcpFreeHeap(password); - } - - if (serviceStartName) PhSvcpFreeHeap(serviceStartName); - if (dependencies) PhSvcpFreeHeap(dependencies); - if (loadOrderGroup) PhSvcpFreeHeap(loadOrderGroup); - if (binaryPathName) PhSvcpFreeHeap(binaryPathName); - if (displayName) PhSvcpFreeHeap(displayName); - if (serviceName) PhSvcpFreeHeap(serviceName); - - return status; -} - -NTSTATUS PhSvcCallChangeServiceConfig( - _In_ PWSTR ServiceName, - _In_ ULONG ServiceType, - _In_ ULONG StartType, - _In_ ULONG ErrorControl, - _In_opt_ PWSTR BinaryPathName, - _In_opt_ PWSTR LoadOrderGroup, - _Out_opt_ PULONG TagId, - _In_opt_ PWSTR Dependencies, - _In_opt_ PWSTR ServiceStartName, - _In_opt_ PWSTR Password, - _In_opt_ PWSTR DisplayName - ) -{ - NTSTATUS status; - PHSVC_API_MSG m; - PVOID serviceName = NULL; - PVOID binaryPathName = NULL; - PVOID loadOrderGroup = NULL; - PVOID dependencies = NULL; - PVOID serviceStartName = NULL; - PVOID password = NULL; - ULONG passwordLength; - PVOID displayName = NULL; - - memset(&m, 0, sizeof(PHSVC_API_MSG)); - - if (!PhSvcClPortHandle) - return STATUS_PORT_DISCONNECTED; - - m.p.ApiNumber = PhSvcChangeServiceConfigApiNumber; - - m.p.u.ChangeServiceConfig.i.ServiceType = ServiceType; - m.p.u.ChangeServiceConfig.i.StartType = StartType; - m.p.u.ChangeServiceConfig.i.ErrorControl = ErrorControl; - m.p.u.ChangeServiceConfig.i.TagIdSpecified = TagId != NULL; - - status = STATUS_NO_MEMORY; - - if (!(serviceName = PhSvcpCreateString(ServiceName, -1, &m.p.u.ChangeServiceConfig.i.ServiceName))) - goto CleanupExit; - if (BinaryPathName && !(binaryPathName = PhSvcpCreateString(BinaryPathName, -1, &m.p.u.ChangeServiceConfig.i.BinaryPathName))) - goto CleanupExit; - if (LoadOrderGroup && !(loadOrderGroup = PhSvcpCreateString(LoadOrderGroup, -1, &m.p.u.ChangeServiceConfig.i.LoadOrderGroup))) - goto CleanupExit; - - if (Dependencies) - { - SIZE_T dependenciesLength; - SIZE_T partCount; - PWSTR part; - - dependenciesLength = sizeof(WCHAR); - part = Dependencies; - - do - { - partCount = PhCountStringZ(part) + 1; - part += partCount; - dependenciesLength += partCount * sizeof(WCHAR); - } while (partCount != 1); // stop at empty dependency part - - if (!(dependencies = PhSvcpCreateString(Dependencies, dependenciesLength, &m.p.u.ChangeServiceConfig.i.Dependencies))) - goto CleanupExit; - } - - if (ServiceStartName && !(serviceStartName = PhSvcpCreateString(ServiceStartName, -1, &m.p.u.ChangeServiceConfig.i.ServiceStartName))) - goto CleanupExit; - - if (Password) - { - if (!(password = PhSvcpCreateString(Password, -1, &m.p.u.ChangeServiceConfig.i.Password))) - goto CleanupExit; - - passwordLength = m.p.u.ChangeServiceConfig.i.Password.Length; - } - - if (DisplayName && !(displayName = PhSvcpCreateString(DisplayName, -1, &m.p.u.ChangeServiceConfig.i.DisplayName))) - goto CleanupExit; - - status = PhSvcpCallServer(&m); - - if (NT_SUCCESS(status)) - { - if (TagId) - *TagId = m.p.u.ChangeServiceConfig.o.TagId; - } - -CleanupExit: - if (displayName) PhSvcpFreeHeap(displayName); - - if (password) - { - RtlSecureZeroMemory(password, passwordLength); - PhSvcpFreeHeap(password); - } - - if (serviceStartName) PhSvcpFreeHeap(serviceStartName); - if (dependencies) PhSvcpFreeHeap(dependencies); - if (loadOrderGroup) PhSvcpFreeHeap(loadOrderGroup); - if (binaryPathName) PhSvcpFreeHeap(binaryPathName); - if (serviceName) PhSvcpFreeHeap(serviceName); - - return status; -} - -PVOID PhSvcpPackRoot( - _Inout_ PPH_BYTES_BUILDER BytesBuilder, - _In_ PVOID Buffer, - _In_ SIZE_T Length - ) -{ - return PhAppendBytesBuilderEx(BytesBuilder, Buffer, Length, sizeof(ULONG_PTR), NULL); -} - -VOID PhSvcpPackBuffer_V( - _Inout_ PPH_BYTES_BUILDER BytesBuilder, - _Inout_ PVOID *PointerInBytesBuilder, - _In_ SIZE_T Length, - _In_ SIZE_T Alignment, - _In_ ULONG NumberOfPointersToRebase, - _In_ va_list ArgPtr - ) -{ - va_list argptr; - ULONG_PTR oldBase; - SIZE_T oldLength; - ULONG_PTR newBase; - SIZE_T offset; - ULONG i; - PVOID *pointer; - - oldBase = (ULONG_PTR)BytesBuilder->Bytes->Buffer; - oldLength = BytesBuilder->Bytes->Length; - assert((ULONG_PTR)PointerInBytesBuilder >= oldBase && (ULONG_PTR)PointerInBytesBuilder + sizeof(PVOID) <= oldBase + oldLength); - - if (!*PointerInBytesBuilder) - return; - - PhAppendBytesBuilderEx(BytesBuilder, *PointerInBytesBuilder, Length, Alignment, &offset); - newBase = (ULONG_PTR)BytesBuilder->Bytes->Buffer; - - PointerInBytesBuilder = (PVOID *)((ULONG_PTR)PointerInBytesBuilder - oldBase + newBase); - *PointerInBytesBuilder = (PVOID)offset; - - argptr = ArgPtr; - - for (i = 0; i < NumberOfPointersToRebase; i++) - { - pointer = va_arg(argptr, PVOID *); - assert(!*pointer || ((ULONG_PTR)*pointer >= oldBase && (ULONG_PTR)*pointer + sizeof(PVOID) <= oldBase + oldLength)); - - if (*pointer) - *pointer = (PVOID)((ULONG_PTR)*pointer - oldBase + newBase); - } -} - -VOID PhSvcpPackBuffer( - _Inout_ PPH_BYTES_BUILDER BytesBuilder, - _Inout_ PVOID *PointerInBytesBuilder, - _In_ SIZE_T Length, - _In_ SIZE_T Alignment, - _In_ ULONG NumberOfPointersToRebase, - ... - ) -{ - va_list argptr; - - va_start(argptr, NumberOfPointersToRebase); - PhSvcpPackBuffer_V(BytesBuilder, PointerInBytesBuilder, Length, Alignment, NumberOfPointersToRebase, argptr); -} - -SIZE_T PhSvcpBufferLengthStringZ( - _In_opt_ PWSTR String, - _In_ BOOLEAN Multi - ) -{ - SIZE_T length = 0; - - if (String) - { - if (Multi) - { - PWSTR part = String; - SIZE_T partCount; - - while (TRUE) - { - partCount = PhCountStringZ(part); - length += (partCount + 1) * sizeof(WCHAR); - - if (partCount == 0) - break; - - part += partCount + 1; - } - } - else - { - length = (PhCountStringZ(String) + 1) * sizeof(WCHAR); - } - } - - return length; -} - -NTSTATUS PhSvcCallChangeServiceConfig2( - _In_ PWSTR ServiceName, - _In_ ULONG InfoLevel, - _In_ PVOID Info - ) -{ - NTSTATUS status; - PHSVC_API_MSG m; - PVOID serviceName = NULL; - PVOID info = NULL; - PH_BYTES_BUILDER bb; - - if (!PhSvcClPortHandle) - return STATUS_PORT_DISCONNECTED; - - m.p.ApiNumber = PhSvcChangeServiceConfig2ApiNumber; - - m.p.u.ChangeServiceConfig2.i.InfoLevel = InfoLevel; - - if (serviceName = PhSvcpCreateString(ServiceName, -1, &m.p.u.ChangeServiceConfig2.i.ServiceName)) - { - switch (InfoLevel) - { - case SERVICE_CONFIG_FAILURE_ACTIONS: - { - LPSERVICE_FAILURE_ACTIONS failureActions = Info; - LPSERVICE_FAILURE_ACTIONS packedFailureActions; - - PhInitializeBytesBuilder(&bb, 200); - packedFailureActions = PhSvcpPackRoot(&bb, failureActions, sizeof(SERVICE_FAILURE_ACTIONS)); - PhSvcpPackBuffer(&bb, &packedFailureActions->lpRebootMsg, PhSvcpBufferLengthStringZ(failureActions->lpRebootMsg, FALSE), sizeof(WCHAR), - 1, &packedFailureActions); - PhSvcpPackBuffer(&bb, &packedFailureActions->lpCommand, PhSvcpBufferLengthStringZ(failureActions->lpCommand, FALSE), sizeof(WCHAR), - 1, &packedFailureActions); - - if (failureActions->cActions != 0 && failureActions->lpsaActions) - { - PhSvcpPackBuffer(&bb, &packedFailureActions->lpsaActions, failureActions->cActions * sizeof(SC_ACTION), __alignof(SC_ACTION), - 1, &packedFailureActions); - } - - info = PhSvcpCreateString(bb.Bytes->Buffer, bb.Bytes->Length, &m.p.u.ChangeServiceConfig2.i.Info); - PhDeleteBytesBuilder(&bb); - } - break; - case SERVICE_CONFIG_DELAYED_AUTO_START_INFO: - info = PhSvcpCreateString(Info, sizeof(SERVICE_DELAYED_AUTO_START_INFO), &m.p.u.ChangeServiceConfig2.i.Info); - break; - case SERVICE_CONFIG_FAILURE_ACTIONS_FLAG: - info = PhSvcpCreateString(Info, sizeof(SERVICE_FAILURE_ACTIONS_FLAG), &m.p.u.ChangeServiceConfig2.i.Info); - break; - case SERVICE_CONFIG_SERVICE_SID_INFO: - info = PhSvcpCreateString(Info, sizeof(SERVICE_SID_INFO), &m.p.u.ChangeServiceConfig2.i.Info); - break; - case SERVICE_CONFIG_REQUIRED_PRIVILEGES_INFO: - { - LPSERVICE_REQUIRED_PRIVILEGES_INFO requiredPrivilegesInfo = Info; - LPSERVICE_REQUIRED_PRIVILEGES_INFO packedRequiredPrivilegesInfo; - - PhInitializeBytesBuilder(&bb, 100); - packedRequiredPrivilegesInfo = PhSvcpPackRoot(&bb, requiredPrivilegesInfo, sizeof(SERVICE_REQUIRED_PRIVILEGES_INFO)); - PhSvcpPackBuffer(&bb, &packedRequiredPrivilegesInfo->pmszRequiredPrivileges, PhSvcpBufferLengthStringZ(requiredPrivilegesInfo->pmszRequiredPrivileges, TRUE), sizeof(WCHAR), - 1, &packedRequiredPrivilegesInfo); - - info = PhSvcpCreateString(bb.Bytes->Buffer, bb.Bytes->Length, &m.p.u.ChangeServiceConfig2.i.Info); - PhDeleteBytesBuilder(&bb); - } - break; - case SERVICE_CONFIG_PRESHUTDOWN_INFO: - info = PhSvcpCreateString(Info, sizeof(SERVICE_PRESHUTDOWN_INFO), &m.p.u.ChangeServiceConfig2.i.Info); - break; - case SERVICE_CONFIG_TRIGGER_INFO: - { - PSERVICE_TRIGGER_INFO triggerInfo = Info; - PSERVICE_TRIGGER_INFO packedTriggerInfo; - ULONG i; - PSERVICE_TRIGGER packedTrigger; - ULONG j; - PSERVICE_TRIGGER_SPECIFIC_DATA_ITEM packedDataItem; - ULONG alignment; - - PhInitializeBytesBuilder(&bb, 400); - packedTriggerInfo = PhSvcpPackRoot(&bb, triggerInfo, sizeof(SERVICE_TRIGGER_INFO)); - - if (triggerInfo->cTriggers != 0 && triggerInfo->pTriggers) - { - PhSvcpPackBuffer(&bb, &packedTriggerInfo->pTriggers, triggerInfo->cTriggers * sizeof(SERVICE_TRIGGER), __alignof(SERVICE_TRIGGER), - 1, &packedTriggerInfo); - - for (i = 0; i < triggerInfo->cTriggers; i++) - { - packedTrigger = PhOffsetBytesBuilder(&bb, (SIZE_T)packedTriggerInfo->pTriggers + i * sizeof(SERVICE_TRIGGER)); - - PhSvcpPackBuffer(&bb, &packedTrigger->pTriggerSubtype, sizeof(GUID), __alignof(GUID), - 2, &packedTriggerInfo, &packedTrigger); - - if (packedTrigger->cDataItems != 0 && packedTrigger->pDataItems) - { - PhSvcpPackBuffer(&bb, &packedTrigger->pDataItems, packedTrigger->cDataItems * sizeof(SERVICE_TRIGGER_SPECIFIC_DATA_ITEM), __alignof(SERVICE_TRIGGER_SPECIFIC_DATA_ITEM), - 2, &packedTriggerInfo, &packedTrigger); - - for (j = 0; j < packedTrigger->cDataItems; j++) - { - packedDataItem = PhOffsetBytesBuilder(&bb, (SIZE_T)packedTrigger->pDataItems + j * sizeof(SERVICE_TRIGGER_SPECIFIC_DATA_ITEM)); - alignment = 1; - - switch (packedDataItem->dwDataType) - { - case SERVICE_TRIGGER_DATA_TYPE_BINARY: - case SERVICE_TRIGGER_DATA_TYPE_LEVEL: - alignment = sizeof(CHAR); - break; - case SERVICE_TRIGGER_DATA_TYPE_STRING: - alignment = sizeof(WCHAR); - break; - case SERVICE_TRIGGER_DATA_TYPE_KEYWORD_ANY: - case SERVICE_TRIGGER_DATA_TYPE_KEYWORD_ALL: - alignment = sizeof(ULONG64); - break; - } - - PhSvcpPackBuffer(&bb, &packedDataItem->pData, packedDataItem->cbData, alignment, - 3, &packedTriggerInfo, &packedTrigger, &packedDataItem); - } - } - } - } - - info = PhSvcpCreateString(bb.Bytes->Buffer, bb.Bytes->Length, &m.p.u.ChangeServiceConfig2.i.Info); - PhDeleteBytesBuilder(&bb); - } - break; - case SERVICE_CONFIG_LAUNCH_PROTECTED: - info = PhSvcpCreateString(Info, sizeof(SERVICE_LAUNCH_PROTECTED_INFO), &m.p.u.ChangeServiceConfig2.i.Info); - break; - default: - status = STATUS_INVALID_PARAMETER; - break; - } - } - - if (serviceName && info) - { - status = PhSvcpCallServer(&m); - } - else - { - status = STATUS_NO_MEMORY; - } - - if (info) - PhSvcpFreeHeap(info); - if (serviceName) - PhSvcpFreeHeap(serviceName); - - return status; -} - -NTSTATUS PhSvcCallSetTcpEntry( - _In_ PVOID TcpRow - ) -{ - PHSVC_API_MSG m; - struct - { - DWORD dwState; - DWORD dwLocalAddr; - DWORD dwLocalPort; - DWORD dwRemoteAddr; - DWORD dwRemotePort; - } *tcpRow = TcpRow; - - if (!PhSvcClPortHandle) - return STATUS_PORT_DISCONNECTED; - - m.p.ApiNumber = PhSvcSetTcpEntryApiNumber; - - m.p.u.SetTcpEntry.i.State = tcpRow->dwState; - m.p.u.SetTcpEntry.i.LocalAddress = tcpRow->dwLocalAddr; - m.p.u.SetTcpEntry.i.LocalPort = tcpRow->dwLocalPort; - m.p.u.SetTcpEntry.i.RemoteAddress = tcpRow->dwRemoteAddr; - m.p.u.SetTcpEntry.i.RemotePort = tcpRow->dwRemotePort; - - return PhSvcpCallServer(&m); -} - -NTSTATUS PhSvcCallControlThread( - _In_ HANDLE ThreadId, - _In_ PHSVC_API_CONTROLTHREAD_COMMAND Command, - _In_ ULONG Argument - ) -{ - PHSVC_API_MSG m; - - if (!PhSvcClPortHandle) - return STATUS_PORT_DISCONNECTED; - - m.p.ApiNumber = PhSvcControlThreadApiNumber; - m.p.u.ControlThread.i.ThreadId = ThreadId; - m.p.u.ControlThread.i.Command = Command; - m.p.u.ControlThread.i.Argument = Argument; - - return PhSvcpCallServer(&m); -} - -NTSTATUS PhSvcCallAddAccountRight( - _In_ PSID AccountSid, - _In_ PUNICODE_STRING UserRight - ) -{ - NTSTATUS status; - PHSVC_API_MSG m; - PVOID accountSid = NULL; - PVOID userRight = NULL; - - if (!PhSvcClPortHandle) - return STATUS_PORT_DISCONNECTED; - - m.p.ApiNumber = PhSvcAddAccountRightApiNumber; - - status = STATUS_NO_MEMORY; - - if (!(accountSid = PhSvcpCreateString(AccountSid, RtlLengthSid(AccountSid), &m.p.u.AddAccountRight.i.AccountSid))) - goto CleanupExit; - if (!(userRight = PhSvcpCreateString(UserRight->Buffer, UserRight->Length, &m.p.u.AddAccountRight.i.UserRight))) - goto CleanupExit; - - status = PhSvcpCallServer(&m); - -CleanupExit: - if (userRight) PhSvcpFreeHeap(userRight); - if (accountSid) PhSvcpFreeHeap(accountSid); - - return status; -} - -NTSTATUS PhSvcCallInvokeRunAsService( - _In_ PPH_RUNAS_SERVICE_PARAMETERS Parameters - ) -{ - return PhSvcpCallExecuteRunAsCommand(PhSvcInvokeRunAsServiceApiNumber, Parameters); -} - -NTSTATUS PhSvcCallIssueMemoryListCommand( - _In_ SYSTEM_MEMORY_LIST_COMMAND Command - ) -{ - PHSVC_API_MSG m; - - if (!PhSvcClPortHandle) - return STATUS_PORT_DISCONNECTED; - - m.p.ApiNumber = PhSvcIssueMemoryListCommandApiNumber; - m.p.u.IssueMemoryListCommand.i.Command = Command; - - return PhSvcpCallServer(&m); -} - -NTSTATUS PhSvcCallPostMessage( - _In_opt_ HWND hWnd, - _In_ UINT Msg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - PHSVC_API_MSG m; - - if (!PhSvcClPortHandle) - return STATUS_PORT_DISCONNECTED; - - m.p.ApiNumber = PhSvcPostMessageApiNumber; - m.p.u.PostMessage.i.hWnd = hWnd; - m.p.u.PostMessage.i.Msg = Msg; - m.p.u.PostMessage.i.wParam = wParam; - m.p.u.PostMessage.i.lParam = lParam; - - return PhSvcpCallServer(&m); -} - -NTSTATUS PhSvcCallSendMessage( - _In_opt_ HWND hWnd, - _In_ UINT Msg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - PHSVC_API_MSG m; - - if (!PhSvcClPortHandle) - return STATUS_PORT_DISCONNECTED; - - m.p.ApiNumber = PhSvcSendMessageApiNumber; - m.p.u.PostMessage.i.hWnd = hWnd; - m.p.u.PostMessage.i.Msg = Msg; - m.p.u.PostMessage.i.wParam = wParam; - m.p.u.PostMessage.i.lParam = lParam; - - return PhSvcpCallServer(&m); -} - -NTSTATUS PhSvcCallCreateProcessIgnoreIfeoDebugger( - _In_ PWSTR FileName - ) -{ - NTSTATUS status; - PHSVC_API_MSG m; - PVOID fileName = NULL; - - memset(&m, 0, sizeof(PHSVC_API_MSG)); - - if (!PhSvcClPortHandle) - return STATUS_PORT_DISCONNECTED; - - m.p.ApiNumber = PhSvcCreateProcessIgnoreIfeoDebuggerApiNumber; - fileName = PhSvcpCreateString(FileName, -1, &m.p.u.CreateProcessIgnoreIfeoDebugger.i.FileName); - - if (!fileName) - return STATUS_NO_MEMORY; - - status = PhSvcpCallServer(&m); - - if (fileName) - PhSvcpFreeHeap(fileName); - - return status; -} - -PSECURITY_DESCRIPTOR PhpAbsoluteToSelfRelativeSD( - _In_ PSECURITY_DESCRIPTOR AbsoluteSecurityDescriptor, - _Out_ PULONG BufferSize - ) -{ - NTSTATUS status; - ULONG bufferSize = 0; - PSECURITY_DESCRIPTOR selfRelativeSecurityDescriptor; - - status = RtlAbsoluteToSelfRelativeSD(AbsoluteSecurityDescriptor, NULL, &bufferSize); - - if (status != STATUS_BUFFER_TOO_SMALL) - return NULL; - - selfRelativeSecurityDescriptor = PhAllocate(bufferSize); - status = RtlAbsoluteToSelfRelativeSD(AbsoluteSecurityDescriptor, selfRelativeSecurityDescriptor, &bufferSize); - - if (!NT_SUCCESS(status)) - { - PhFree(selfRelativeSecurityDescriptor); - return NULL; - } - - *BufferSize = bufferSize; - - return selfRelativeSecurityDescriptor; -} - -NTSTATUS PhSvcCallSetServiceSecurity( - _In_ PWSTR ServiceName, - _In_ SECURITY_INFORMATION SecurityInformation, - _In_ PSECURITY_DESCRIPTOR SecurityDescriptor - ) -{ - NTSTATUS status; - PHSVC_API_MSG m; - PSECURITY_DESCRIPTOR selfRelativeSecurityDescriptor = NULL; - ULONG bufferSize; - PVOID serviceName = NULL; - PVOID copiedSelfRelativeSecurityDescriptor = NULL; - - if (!PhSvcClPortHandle) - return STATUS_PORT_DISCONNECTED; - - selfRelativeSecurityDescriptor = PhpAbsoluteToSelfRelativeSD(SecurityDescriptor, &bufferSize); - - if (!selfRelativeSecurityDescriptor) - { - status = STATUS_BAD_DESCRIPTOR_FORMAT; - goto CleanupExit; - } - - m.p.ApiNumber = PhSvcSetServiceSecurityApiNumber; - m.p.u.SetServiceSecurity.i.SecurityInformation = SecurityInformation; - status = STATUS_NO_MEMORY; - - if (!(serviceName = PhSvcpCreateString(ServiceName, -1, &m.p.u.SetServiceSecurity.i.ServiceName))) - goto CleanupExit; - if (!(copiedSelfRelativeSecurityDescriptor = PhSvcpCreateString(selfRelativeSecurityDescriptor, bufferSize, &m.p.u.SetServiceSecurity.i.SecurityDescriptor))) - goto CleanupExit; - - status = PhSvcpCallServer(&m); - -CleanupExit: - if (selfRelativeSecurityDescriptor) PhFree(selfRelativeSecurityDescriptor); - if (serviceName) PhSvcpFreeHeap(serviceName); - if (copiedSelfRelativeSecurityDescriptor) PhSvcpFreeHeap(copiedSelfRelativeSecurityDescriptor); - - return status; -} - -NTSTATUS PhSvcCallLoadDbgHelp( - _In_ PWSTR DbgHelpPath - ) -{ - NTSTATUS status; - PHSVC_API_MSG m; - PVOID dbgHelpPath = NULL; - - memset(&m, 0, sizeof(PHSVC_API_MSG)); - - if (!PhSvcClPortHandle) - return STATUS_PORT_DISCONNECTED; - - m.p.ApiNumber = PhSvcLoadDbgHelpApiNumber; - dbgHelpPath = PhSvcpCreateString(DbgHelpPath, -1, &m.p.u.LoadDbgHelp.i.DbgHelpPath); - - if (!dbgHelpPath) - return STATUS_NO_MEMORY; - - status = PhSvcpCallServer(&m); - - if (dbgHelpPath) - PhSvcpFreeHeap(dbgHelpPath); - - return status; -} - -NTSTATUS PhSvcCallWriteMiniDumpProcess( - _In_ HANDLE ProcessHandle, - _In_ HANDLE ProcessId, - _In_ HANDLE FileHandle, - _In_ ULONG DumpType - ) -{ - NTSTATUS status; - PHSVC_API_MSG m; - HANDLE serverHandle = NULL; - HANDLE remoteProcessHandle = NULL; - HANDLE remoteFileHandle = NULL; - - memset(&m, 0, sizeof(PHSVC_API_MSG)); - - if (!PhSvcClPortHandle) - return STATUS_PORT_DISCONNECTED; - - // For typical uses of this function, the client has more privileges than the server. - // We therefore duplicate our handles into the server's process. - - m.p.ApiNumber = PhSvcWriteMiniDumpProcessApiNumber; - - if (!NT_SUCCESS(status = PhOpenProcess(&serverHandle, PROCESS_DUP_HANDLE, PhSvcClServerProcessId))) - { - goto CleanupExit; - } - - if (!NT_SUCCESS(status = NtDuplicateObject(NtCurrentProcess(), ProcessHandle, serverHandle, &remoteProcessHandle, - PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, 0, 0))) - { - goto CleanupExit; - } - - if (!NT_SUCCESS(status = NtDuplicateObject(NtCurrentProcess(), FileHandle, serverHandle, &remoteFileHandle, - FILE_GENERIC_WRITE, 0, 0))) - { - goto CleanupExit; - } - - m.p.u.WriteMiniDumpProcess.i.LocalProcessHandle = HandleToUlong(remoteProcessHandle); - m.p.u.WriteMiniDumpProcess.i.ProcessId = HandleToUlong(ProcessId); - m.p.u.WriteMiniDumpProcess.i.LocalFileHandle = HandleToUlong(remoteFileHandle); - m.p.u.WriteMiniDumpProcess.i.DumpType = DumpType; - - status = PhSvcpCallServer(&m); - -CleanupExit: - if (serverHandle) - { - if (remoteProcessHandle) - NtDuplicateObject(serverHandle, remoteProcessHandle, NULL, NULL, 0, 0, DUPLICATE_CLOSE_SOURCE); - if (remoteFileHandle) - NtDuplicateObject(serverHandle, remoteFileHandle, NULL, NULL, 0, 0, DUPLICATE_CLOSE_SOURCE); - - NtClose(serverHandle); - } - - return status; -} +/* + * Process Hacker - + * phsvc client + * + * Copyright (C) 2011-2015 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include +#include + +HANDLE PhSvcClPortHandle; +PVOID PhSvcClPortHeap; +HANDLE PhSvcClServerProcessId; + +NTSTATUS PhSvcConnectToServer( + _In_ PUNICODE_STRING PortName, + _In_opt_ SIZE_T PortSectionSize + ) +{ + NTSTATUS status; + HANDLE sectionHandle; + LARGE_INTEGER sectionSize; + PORT_VIEW clientView; + REMOTE_PORT_VIEW serverView; + SECURITY_QUALITY_OF_SERVICE securityQos; + ULONG maxMessageLength; + PHSVC_API_CONNECTINFO connectInfo; + ULONG connectInfoLength; + + if (PhSvcClPortHandle) + return STATUS_ADDRESS_ALREADY_EXISTS; + + if (PortSectionSize == 0) + PortSectionSize = 512 * 1024; + + // Create the port section and connect to the port. + + sectionSize.QuadPart = PortSectionSize; + status = NtCreateSection( + §ionHandle, + SECTION_ALL_ACCESS, + NULL, + §ionSize, + PAGE_READWRITE, + SEC_COMMIT, + NULL + ); + + if (!NT_SUCCESS(status)) + return status; + + clientView.Length = sizeof(PORT_VIEW); + clientView.SectionHandle = sectionHandle; + clientView.SectionOffset = 0; + clientView.ViewSize = PortSectionSize; + clientView.ViewBase = NULL; + clientView.ViewRemoteBase = NULL; + + serverView.Length = sizeof(REMOTE_PORT_VIEW); + serverView.ViewSize = 0; + serverView.ViewBase = NULL; + + securityQos.Length = sizeof(SECURITY_QUALITY_OF_SERVICE); + securityQos.ImpersonationLevel = SecurityImpersonation; + securityQos.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING; + securityQos.EffectiveOnly = TRUE; + + connectInfoLength = sizeof(PHSVC_API_CONNECTINFO); + + status = NtConnectPort( + &PhSvcClPortHandle, + PortName, + &securityQos, + &clientView, + &serverView, + &maxMessageLength, + &connectInfo, + &connectInfoLength + ); + NtClose(sectionHandle); + + if (!NT_SUCCESS(status)) + return status; + + PhSvcClServerProcessId = UlongToHandle(connectInfo.ServerProcessId); + + // Create the port heap. + + PhSvcClPortHeap = RtlCreateHeap( + HEAP_CLASS_1, + clientView.ViewBase, + clientView.ViewSize, + PAGE_SIZE, + NULL, + NULL + ); + + if (!PhSvcClPortHeap) + { + NtClose(PhSvcClPortHandle); + return STATUS_INSUFFICIENT_RESOURCES; + } + + return status; +} + +VOID PhSvcDisconnectFromServer( + VOID + ) +{ + if (PhSvcClPortHeap) + { + RtlDestroyHeap(PhSvcClPortHeap); + PhSvcClPortHeap = NULL; + } + + if (PhSvcClPortHandle) + { + NtClose(PhSvcClPortHandle); + PhSvcClPortHandle = NULL; + } + + PhSvcClServerProcessId = NULL; +} + +PVOID PhSvcpAllocateHeap( + _In_ SIZE_T Size, + _Out_ PULONG Offset + ) +{ + PVOID memory; + + if (!PhSvcClPortHeap) + return NULL; + + memory = RtlAllocateHeap(PhSvcClPortHeap, 0, Size); + + if (!memory) + return NULL; + + *Offset = (ULONG)((ULONG_PTR)memory - (ULONG_PTR)PhSvcClPortHeap); + + return memory; +} + +VOID PhSvcpFreeHeap( + _In_ PVOID Memory + ) +{ + if (!PhSvcClPortHeap) + return; + + RtlFreeHeap(PhSvcClPortHeap, 0, Memory); +} + +PVOID PhSvcpCreateString( + _In_opt_ PVOID String, + _In_ SIZE_T Length, + _Out_ PPH_RELATIVE_STRINGREF StringRef + ) +{ + PVOID memory; + SIZE_T length; + ULONG offset; + + if (Length != -1) + length = Length; + else + length = PhCountStringZ(String) * sizeof(WCHAR); + + if (length > MAXULONG32) + return NULL; + + memory = PhSvcpAllocateHeap(length, &offset); + + if (!memory) + return NULL; + + if (String) + memcpy(memory, String, length); + + StringRef->Length = (ULONG)length; + StringRef->Offset = offset; + + return memory; +} + +NTSTATUS PhSvcpCallServer( + _Inout_ PPHSVC_API_MSG Message + ) +{ + NTSTATUS status; + + Message->h.u1.s1.DataLength = sizeof(PHSVC_API_MSG) - FIELD_OFFSET(PHSVC_API_MSG, p); + Message->h.u1.s1.TotalLength = sizeof(PHSVC_API_MSG); + Message->h.u2.ZeroInit = 0; + + status = NtRequestWaitReplyPort(PhSvcClPortHandle, &Message->h, &Message->h); + + if (!NT_SUCCESS(status)) + return status; + + return Message->p.ReturnStatus; +} + +NTSTATUS PhSvcCallPlugin( + _In_ PPH_STRINGREF ApiId, + _In_reads_bytes_opt_(InLength) PVOID InBuffer, + _In_ ULONG InLength, + _Out_writes_bytes_opt_(OutLength) PVOID OutBuffer, + _In_ ULONG OutLength + ) +{ + NTSTATUS status; + PHSVC_API_MSG m; + PVOID apiId = NULL; + + memset(&m, 0, sizeof(PHSVC_API_MSG)); + + if (!PhSvcClPortHandle) + return STATUS_PORT_DISCONNECTED; + if (InLength > sizeof(m.p.u.Plugin.i.Data)) + return STATUS_BUFFER_OVERFLOW; + + m.p.ApiNumber = PhSvcPluginApiNumber; + + if (!(apiId = PhSvcpCreateString(ApiId->Buffer, ApiId->Length, &m.p.u.Plugin.i.ApiId))) + return STATUS_NO_MEMORY; + + if (InLength != 0) + memcpy(m.p.u.Plugin.i.Data, InBuffer, InLength); + + status = PhSvcpCallServer(&m); + + if (OutLength != 0) + memcpy(OutBuffer, m.p.u.Plugin.o.Data, min(OutLength, sizeof(m.p.u.Plugin.o.Data))); + + if (apiId) + PhSvcpFreeHeap(apiId); + + return status; +} + +NTSTATUS PhSvcpCallExecuteRunAsCommand( + _In_ PHSVC_API_NUMBER ApiNumber, + _In_ PPH_RUNAS_SERVICE_PARAMETERS Parameters + ) +{ + NTSTATUS status; + PHSVC_API_MSG m; + PVOID userName = NULL; + PVOID password = NULL; + ULONG passwordLength; + PVOID currentDirectory = NULL; + PVOID commandLine = NULL; + PVOID fileName = NULL; + PVOID desktopName = NULL; + PVOID serviceName = NULL; + + memset(&m, 0, sizeof(PHSVC_API_MSG)); + + if (!PhSvcClPortHandle) + return STATUS_PORT_DISCONNECTED; + + m.p.ApiNumber = ApiNumber; + + m.p.u.ExecuteRunAsCommand.i.ProcessId = Parameters->ProcessId; + m.p.u.ExecuteRunAsCommand.i.LogonType = Parameters->LogonType; + m.p.u.ExecuteRunAsCommand.i.SessionId = Parameters->SessionId; + m.p.u.ExecuteRunAsCommand.i.UseLinkedToken = Parameters->UseLinkedToken; + + status = STATUS_NO_MEMORY; + + if (Parameters->UserName && !(userName = PhSvcpCreateString(Parameters->UserName, -1, &m.p.u.ExecuteRunAsCommand.i.UserName))) + goto CleanupExit; + + if (Parameters->Password) + { + if (!(password = PhSvcpCreateString(Parameters->Password, -1, &m.p.u.ExecuteRunAsCommand.i.Password))) + goto CleanupExit; + + passwordLength = m.p.u.ExecuteRunAsCommand.i.Password.Length; + } + + if (Parameters->CurrentDirectory && !(currentDirectory = PhSvcpCreateString(Parameters->CurrentDirectory, -1, &m.p.u.ExecuteRunAsCommand.i.CurrentDirectory))) + goto CleanupExit; + if (Parameters->CommandLine && !(commandLine = PhSvcpCreateString(Parameters->CommandLine, -1, &m.p.u.ExecuteRunAsCommand.i.CommandLine))) + goto CleanupExit; + if (Parameters->FileName && !(fileName = PhSvcpCreateString(Parameters->FileName, -1, &m.p.u.ExecuteRunAsCommand.i.FileName))) + goto CleanupExit; + if (Parameters->DesktopName && !(desktopName = PhSvcpCreateString(Parameters->DesktopName, -1, &m.p.u.ExecuteRunAsCommand.i.DesktopName))) + goto CleanupExit; + if (Parameters->ServiceName && !(serviceName = PhSvcpCreateString(Parameters->ServiceName, -1, &m.p.u.ExecuteRunAsCommand.i.ServiceName))) + goto CleanupExit; + + status = PhSvcpCallServer(&m); + +CleanupExit: + if (serviceName) PhSvcpFreeHeap(serviceName); + if (desktopName) PhSvcpFreeHeap(desktopName); + if (fileName) PhSvcpFreeHeap(fileName); + if (commandLine) PhSvcpFreeHeap(commandLine); + if (currentDirectory) PhSvcpFreeHeap(currentDirectory); + + if (password) + { + RtlSecureZeroMemory(password, passwordLength); + PhSvcpFreeHeap(password); + } + + if (userName) PhSvcpFreeHeap(userName); + + return status; +} + +NTSTATUS PhSvcCallExecuteRunAsCommand( + _In_ PPH_RUNAS_SERVICE_PARAMETERS Parameters + ) +{ + return PhSvcpCallExecuteRunAsCommand(PhSvcExecuteRunAsCommandApiNumber, Parameters); +} + +NTSTATUS PhSvcCallUnloadDriver( + _In_opt_ PVOID BaseAddress, + _In_opt_ PWSTR Name + ) +{ + NTSTATUS status; + PHSVC_API_MSG m; + PVOID name = NULL; + + memset(&m, 0, sizeof(PHSVC_API_MSG)); + + if (!PhSvcClPortHandle) + return STATUS_PORT_DISCONNECTED; + + m.p.ApiNumber = PhSvcUnloadDriverApiNumber; + + m.p.u.UnloadDriver.i.BaseAddress = BaseAddress; + + if (Name) + { + name = PhSvcpCreateString(Name, -1, &m.p.u.UnloadDriver.i.Name); + + if (!name) + return STATUS_NO_MEMORY; + } + + status = PhSvcpCallServer(&m); + + if (name) + PhSvcpFreeHeap(name); + + return status; +} + +NTSTATUS PhSvcCallControlProcess( + _In_ HANDLE ProcessId, + _In_ PHSVC_API_CONTROLPROCESS_COMMAND Command, + _In_ ULONG Argument + ) +{ + PHSVC_API_MSG m; + + if (!PhSvcClPortHandle) + return STATUS_PORT_DISCONNECTED; + + m.p.ApiNumber = PhSvcControlProcessApiNumber; + m.p.u.ControlProcess.i.ProcessId = ProcessId; + m.p.u.ControlProcess.i.Command = Command; + m.p.u.ControlProcess.i.Argument = Argument; + + return PhSvcpCallServer(&m); +} + +NTSTATUS PhSvcCallControlService( + _In_ PWSTR ServiceName, + _In_ PHSVC_API_CONTROLSERVICE_COMMAND Command + ) +{ + NTSTATUS status; + PHSVC_API_MSG m; + PVOID serviceName; + + if (!PhSvcClPortHandle) + return STATUS_PORT_DISCONNECTED; + + m.p.ApiNumber = PhSvcControlServiceApiNumber; + + serviceName = PhSvcpCreateString(ServiceName, -1, &m.p.u.ControlService.i.ServiceName); + m.p.u.ControlService.i.Command = Command; + + if (serviceName) + { + status = PhSvcpCallServer(&m); + } + else + { + status = STATUS_NO_MEMORY; + } + + if (serviceName) + PhSvcpFreeHeap(serviceName); + + return status; +} + +NTSTATUS PhSvcCallCreateService( + _In_ PWSTR ServiceName, + _In_opt_ PWSTR DisplayName, + _In_ ULONG ServiceType, + _In_ ULONG StartType, + _In_ ULONG ErrorControl, + _In_opt_ PWSTR BinaryPathName, + _In_opt_ PWSTR LoadOrderGroup, + _Out_opt_ PULONG TagId, + _In_opt_ PWSTR Dependencies, + _In_opt_ PWSTR ServiceStartName, + _In_opt_ PWSTR Password + ) +{ + NTSTATUS status; + PHSVC_API_MSG m; + PVOID serviceName = NULL; + PVOID displayName = NULL; + PVOID binaryPathName = NULL; + PVOID loadOrderGroup = NULL; + PVOID dependencies = NULL; + PVOID serviceStartName = NULL; + PVOID password = NULL; + ULONG passwordLength; + + memset(&m, 0, sizeof(PHSVC_API_MSG)); + + if (!PhSvcClPortHandle) + return STATUS_PORT_DISCONNECTED; + + m.p.ApiNumber = PhSvcCreateServiceApiNumber; + + m.p.u.CreateService.i.ServiceType = ServiceType; + m.p.u.CreateService.i.StartType = StartType; + m.p.u.CreateService.i.ErrorControl = ErrorControl; + m.p.u.CreateService.i.TagIdSpecified = TagId != NULL; + + status = STATUS_NO_MEMORY; + + if (!(serviceName = PhSvcpCreateString(ServiceName, -1, &m.p.u.CreateService.i.ServiceName))) + goto CleanupExit; + if (DisplayName && !(displayName = PhSvcpCreateString(DisplayName, -1, &m.p.u.CreateService.i.DisplayName))) + goto CleanupExit; + if (BinaryPathName && !(binaryPathName = PhSvcpCreateString(BinaryPathName, -1, &m.p.u.CreateService.i.BinaryPathName))) + goto CleanupExit; + if (LoadOrderGroup && !(loadOrderGroup = PhSvcpCreateString(LoadOrderGroup, -1, &m.p.u.CreateService.i.LoadOrderGroup))) + goto CleanupExit; + + if (Dependencies) + { + SIZE_T dependenciesLength; + SIZE_T partCount; + PWSTR part; + + dependenciesLength = sizeof(WCHAR); + part = Dependencies; + + do + { + partCount = PhCountStringZ(part) + 1; + part += partCount; + dependenciesLength += partCount * sizeof(WCHAR); + } while (partCount != 1); // stop at empty dependency part + + if (!(dependencies = PhSvcpCreateString(Dependencies, dependenciesLength, &m.p.u.CreateService.i.Dependencies))) + goto CleanupExit; + } + + if (ServiceStartName && !(serviceStartName = PhSvcpCreateString(ServiceStartName, -1, &m.p.u.CreateService.i.ServiceStartName))) + goto CleanupExit; + + if (Password) + { + if (!(password = PhSvcpCreateString(Password, -1, &m.p.u.CreateService.i.Password))) + goto CleanupExit; + + passwordLength = m.p.u.CreateService.i.Password.Length; + } + + status = PhSvcpCallServer(&m); + + if (NT_SUCCESS(status)) + { + if (TagId) + *TagId = m.p.u.CreateService.o.TagId; + } + +CleanupExit: + if (password) + { + RtlSecureZeroMemory(password, passwordLength); + PhSvcpFreeHeap(password); + } + + if (serviceStartName) PhSvcpFreeHeap(serviceStartName); + if (dependencies) PhSvcpFreeHeap(dependencies); + if (loadOrderGroup) PhSvcpFreeHeap(loadOrderGroup); + if (binaryPathName) PhSvcpFreeHeap(binaryPathName); + if (displayName) PhSvcpFreeHeap(displayName); + if (serviceName) PhSvcpFreeHeap(serviceName); + + return status; +} + +NTSTATUS PhSvcCallChangeServiceConfig( + _In_ PWSTR ServiceName, + _In_ ULONG ServiceType, + _In_ ULONG StartType, + _In_ ULONG ErrorControl, + _In_opt_ PWSTR BinaryPathName, + _In_opt_ PWSTR LoadOrderGroup, + _Out_opt_ PULONG TagId, + _In_opt_ PWSTR Dependencies, + _In_opt_ PWSTR ServiceStartName, + _In_opt_ PWSTR Password, + _In_opt_ PWSTR DisplayName + ) +{ + NTSTATUS status; + PHSVC_API_MSG m; + PVOID serviceName = NULL; + PVOID binaryPathName = NULL; + PVOID loadOrderGroup = NULL; + PVOID dependencies = NULL; + PVOID serviceStartName = NULL; + PVOID password = NULL; + ULONG passwordLength; + PVOID displayName = NULL; + + memset(&m, 0, sizeof(PHSVC_API_MSG)); + + if (!PhSvcClPortHandle) + return STATUS_PORT_DISCONNECTED; + + m.p.ApiNumber = PhSvcChangeServiceConfigApiNumber; + + m.p.u.ChangeServiceConfig.i.ServiceType = ServiceType; + m.p.u.ChangeServiceConfig.i.StartType = StartType; + m.p.u.ChangeServiceConfig.i.ErrorControl = ErrorControl; + m.p.u.ChangeServiceConfig.i.TagIdSpecified = TagId != NULL; + + status = STATUS_NO_MEMORY; + + if (!(serviceName = PhSvcpCreateString(ServiceName, -1, &m.p.u.ChangeServiceConfig.i.ServiceName))) + goto CleanupExit; + if (BinaryPathName && !(binaryPathName = PhSvcpCreateString(BinaryPathName, -1, &m.p.u.ChangeServiceConfig.i.BinaryPathName))) + goto CleanupExit; + if (LoadOrderGroup && !(loadOrderGroup = PhSvcpCreateString(LoadOrderGroup, -1, &m.p.u.ChangeServiceConfig.i.LoadOrderGroup))) + goto CleanupExit; + + if (Dependencies) + { + SIZE_T dependenciesLength; + SIZE_T partCount; + PWSTR part; + + dependenciesLength = sizeof(WCHAR); + part = Dependencies; + + do + { + partCount = PhCountStringZ(part) + 1; + part += partCount; + dependenciesLength += partCount * sizeof(WCHAR); + } while (partCount != 1); // stop at empty dependency part + + if (!(dependencies = PhSvcpCreateString(Dependencies, dependenciesLength, &m.p.u.ChangeServiceConfig.i.Dependencies))) + goto CleanupExit; + } + + if (ServiceStartName && !(serviceStartName = PhSvcpCreateString(ServiceStartName, -1, &m.p.u.ChangeServiceConfig.i.ServiceStartName))) + goto CleanupExit; + + if (Password) + { + if (!(password = PhSvcpCreateString(Password, -1, &m.p.u.ChangeServiceConfig.i.Password))) + goto CleanupExit; + + passwordLength = m.p.u.ChangeServiceConfig.i.Password.Length; + } + + if (DisplayName && !(displayName = PhSvcpCreateString(DisplayName, -1, &m.p.u.ChangeServiceConfig.i.DisplayName))) + goto CleanupExit; + + status = PhSvcpCallServer(&m); + + if (NT_SUCCESS(status)) + { + if (TagId) + *TagId = m.p.u.ChangeServiceConfig.o.TagId; + } + +CleanupExit: + if (displayName) PhSvcpFreeHeap(displayName); + + if (password) + { + RtlSecureZeroMemory(password, passwordLength); + PhSvcpFreeHeap(password); + } + + if (serviceStartName) PhSvcpFreeHeap(serviceStartName); + if (dependencies) PhSvcpFreeHeap(dependencies); + if (loadOrderGroup) PhSvcpFreeHeap(loadOrderGroup); + if (binaryPathName) PhSvcpFreeHeap(binaryPathName); + if (serviceName) PhSvcpFreeHeap(serviceName); + + return status; +} + +PVOID PhSvcpPackRoot( + _Inout_ PPH_BYTES_BUILDER BytesBuilder, + _In_ PVOID Buffer, + _In_ SIZE_T Length + ) +{ + return PhAppendBytesBuilderEx(BytesBuilder, Buffer, Length, sizeof(ULONG_PTR), NULL); +} + +VOID PhSvcpPackBuffer_V( + _Inout_ PPH_BYTES_BUILDER BytesBuilder, + _Inout_ PVOID *PointerInBytesBuilder, + _In_ SIZE_T Length, + _In_ SIZE_T Alignment, + _In_ ULONG NumberOfPointersToRebase, + _In_ va_list ArgPtr + ) +{ + va_list argptr; + ULONG_PTR oldBase; + SIZE_T oldLength; + ULONG_PTR newBase; + SIZE_T offset; + ULONG i; + PVOID *pointer; + + oldBase = (ULONG_PTR)BytesBuilder->Bytes->Buffer; + oldLength = BytesBuilder->Bytes->Length; + assert((ULONG_PTR)PointerInBytesBuilder >= oldBase && (ULONG_PTR)PointerInBytesBuilder + sizeof(PVOID) <= oldBase + oldLength); + + if (!*PointerInBytesBuilder) + return; + + PhAppendBytesBuilderEx(BytesBuilder, *PointerInBytesBuilder, Length, Alignment, &offset); + newBase = (ULONG_PTR)BytesBuilder->Bytes->Buffer; + + PointerInBytesBuilder = (PVOID *)((ULONG_PTR)PointerInBytesBuilder - oldBase + newBase); + *PointerInBytesBuilder = (PVOID)offset; + + argptr = ArgPtr; + + for (i = 0; i < NumberOfPointersToRebase; i++) + { + pointer = va_arg(argptr, PVOID *); + assert(!*pointer || ((ULONG_PTR)*pointer >= oldBase && (ULONG_PTR)*pointer + sizeof(PVOID) <= oldBase + oldLength)); + + if (*pointer) + *pointer = (PVOID)((ULONG_PTR)*pointer - oldBase + newBase); + } +} + +VOID PhSvcpPackBuffer( + _Inout_ PPH_BYTES_BUILDER BytesBuilder, + _Inout_ PVOID *PointerInBytesBuilder, + _In_ SIZE_T Length, + _In_ SIZE_T Alignment, + _In_ ULONG NumberOfPointersToRebase, + ... + ) +{ + va_list argptr; + + va_start(argptr, NumberOfPointersToRebase); + PhSvcpPackBuffer_V(BytesBuilder, PointerInBytesBuilder, Length, Alignment, NumberOfPointersToRebase, argptr); +} + +SIZE_T PhSvcpBufferLengthStringZ( + _In_opt_ PWSTR String, + _In_ BOOLEAN Multi + ) +{ + SIZE_T length = 0; + + if (String) + { + if (Multi) + { + PWSTR part = String; + SIZE_T partCount; + + while (TRUE) + { + partCount = PhCountStringZ(part); + length += (partCount + 1) * sizeof(WCHAR); + + if (partCount == 0) + break; + + part += partCount + 1; + } + } + else + { + length = (PhCountStringZ(String) + 1) * sizeof(WCHAR); + } + } + + return length; +} + +NTSTATUS PhSvcCallChangeServiceConfig2( + _In_ PWSTR ServiceName, + _In_ ULONG InfoLevel, + _In_ PVOID Info + ) +{ + NTSTATUS status; + PHSVC_API_MSG m; + PVOID serviceName = NULL; + PVOID info = NULL; + PH_BYTES_BUILDER bb; + + if (!PhSvcClPortHandle) + return STATUS_PORT_DISCONNECTED; + + m.p.ApiNumber = PhSvcChangeServiceConfig2ApiNumber; + + m.p.u.ChangeServiceConfig2.i.InfoLevel = InfoLevel; + + if (serviceName = PhSvcpCreateString(ServiceName, -1, &m.p.u.ChangeServiceConfig2.i.ServiceName)) + { + switch (InfoLevel) + { + case SERVICE_CONFIG_FAILURE_ACTIONS: + { + LPSERVICE_FAILURE_ACTIONS failureActions = Info; + LPSERVICE_FAILURE_ACTIONS packedFailureActions; + + PhInitializeBytesBuilder(&bb, 200); + packedFailureActions = PhSvcpPackRoot(&bb, failureActions, sizeof(SERVICE_FAILURE_ACTIONS)); + PhSvcpPackBuffer(&bb, &packedFailureActions->lpRebootMsg, PhSvcpBufferLengthStringZ(failureActions->lpRebootMsg, FALSE), sizeof(WCHAR), + 1, &packedFailureActions); + PhSvcpPackBuffer(&bb, &packedFailureActions->lpCommand, PhSvcpBufferLengthStringZ(failureActions->lpCommand, FALSE), sizeof(WCHAR), + 1, &packedFailureActions); + + if (failureActions->cActions != 0 && failureActions->lpsaActions) + { + PhSvcpPackBuffer(&bb, &packedFailureActions->lpsaActions, failureActions->cActions * sizeof(SC_ACTION), __alignof(SC_ACTION), + 1, &packedFailureActions); + } + + info = PhSvcpCreateString(bb.Bytes->Buffer, bb.Bytes->Length, &m.p.u.ChangeServiceConfig2.i.Info); + PhDeleteBytesBuilder(&bb); + } + break; + case SERVICE_CONFIG_DELAYED_AUTO_START_INFO: + info = PhSvcpCreateString(Info, sizeof(SERVICE_DELAYED_AUTO_START_INFO), &m.p.u.ChangeServiceConfig2.i.Info); + break; + case SERVICE_CONFIG_FAILURE_ACTIONS_FLAG: + info = PhSvcpCreateString(Info, sizeof(SERVICE_FAILURE_ACTIONS_FLAG), &m.p.u.ChangeServiceConfig2.i.Info); + break; + case SERVICE_CONFIG_SERVICE_SID_INFO: + info = PhSvcpCreateString(Info, sizeof(SERVICE_SID_INFO), &m.p.u.ChangeServiceConfig2.i.Info); + break; + case SERVICE_CONFIG_REQUIRED_PRIVILEGES_INFO: + { + LPSERVICE_REQUIRED_PRIVILEGES_INFO requiredPrivilegesInfo = Info; + LPSERVICE_REQUIRED_PRIVILEGES_INFO packedRequiredPrivilegesInfo; + + PhInitializeBytesBuilder(&bb, 100); + packedRequiredPrivilegesInfo = PhSvcpPackRoot(&bb, requiredPrivilegesInfo, sizeof(SERVICE_REQUIRED_PRIVILEGES_INFO)); + PhSvcpPackBuffer(&bb, &packedRequiredPrivilegesInfo->pmszRequiredPrivileges, PhSvcpBufferLengthStringZ(requiredPrivilegesInfo->pmszRequiredPrivileges, TRUE), sizeof(WCHAR), + 1, &packedRequiredPrivilegesInfo); + + info = PhSvcpCreateString(bb.Bytes->Buffer, bb.Bytes->Length, &m.p.u.ChangeServiceConfig2.i.Info); + PhDeleteBytesBuilder(&bb); + } + break; + case SERVICE_CONFIG_PRESHUTDOWN_INFO: + info = PhSvcpCreateString(Info, sizeof(SERVICE_PRESHUTDOWN_INFO), &m.p.u.ChangeServiceConfig2.i.Info); + break; + case SERVICE_CONFIG_TRIGGER_INFO: + { + PSERVICE_TRIGGER_INFO triggerInfo = Info; + PSERVICE_TRIGGER_INFO packedTriggerInfo; + ULONG i; + PSERVICE_TRIGGER packedTrigger; + ULONG j; + PSERVICE_TRIGGER_SPECIFIC_DATA_ITEM packedDataItem; + ULONG alignment; + + PhInitializeBytesBuilder(&bb, 400); + packedTriggerInfo = PhSvcpPackRoot(&bb, triggerInfo, sizeof(SERVICE_TRIGGER_INFO)); + + if (triggerInfo->cTriggers != 0 && triggerInfo->pTriggers) + { + PhSvcpPackBuffer(&bb, &packedTriggerInfo->pTriggers, triggerInfo->cTriggers * sizeof(SERVICE_TRIGGER), __alignof(SERVICE_TRIGGER), + 1, &packedTriggerInfo); + + for (i = 0; i < triggerInfo->cTriggers; i++) + { + packedTrigger = PhOffsetBytesBuilder(&bb, (SIZE_T)packedTriggerInfo->pTriggers + i * sizeof(SERVICE_TRIGGER)); + + PhSvcpPackBuffer(&bb, &packedTrigger->pTriggerSubtype, sizeof(GUID), __alignof(GUID), + 2, &packedTriggerInfo, &packedTrigger); + + if (packedTrigger->cDataItems != 0 && packedTrigger->pDataItems) + { + PhSvcpPackBuffer(&bb, &packedTrigger->pDataItems, packedTrigger->cDataItems * sizeof(SERVICE_TRIGGER_SPECIFIC_DATA_ITEM), __alignof(SERVICE_TRIGGER_SPECIFIC_DATA_ITEM), + 2, &packedTriggerInfo, &packedTrigger); + + for (j = 0; j < packedTrigger->cDataItems; j++) + { + packedDataItem = PhOffsetBytesBuilder(&bb, (SIZE_T)packedTrigger->pDataItems + j * sizeof(SERVICE_TRIGGER_SPECIFIC_DATA_ITEM)); + alignment = 1; + + switch (packedDataItem->dwDataType) + { + case SERVICE_TRIGGER_DATA_TYPE_BINARY: + case SERVICE_TRIGGER_DATA_TYPE_LEVEL: + alignment = sizeof(CHAR); + break; + case SERVICE_TRIGGER_DATA_TYPE_STRING: + alignment = sizeof(WCHAR); + break; + case SERVICE_TRIGGER_DATA_TYPE_KEYWORD_ANY: + case SERVICE_TRIGGER_DATA_TYPE_KEYWORD_ALL: + alignment = sizeof(ULONG64); + break; + } + + PhSvcpPackBuffer(&bb, &packedDataItem->pData, packedDataItem->cbData, alignment, + 3, &packedTriggerInfo, &packedTrigger, &packedDataItem); + } + } + } + } + + info = PhSvcpCreateString(bb.Bytes->Buffer, bb.Bytes->Length, &m.p.u.ChangeServiceConfig2.i.Info); + PhDeleteBytesBuilder(&bb); + } + break; + case SERVICE_CONFIG_LAUNCH_PROTECTED: + info = PhSvcpCreateString(Info, sizeof(SERVICE_LAUNCH_PROTECTED_INFO), &m.p.u.ChangeServiceConfig2.i.Info); + break; + default: + status = STATUS_INVALID_PARAMETER; + break; + } + } + + if (serviceName && info) + { + status = PhSvcpCallServer(&m); + } + else + { + status = STATUS_NO_MEMORY; + } + + if (info) + PhSvcpFreeHeap(info); + if (serviceName) + PhSvcpFreeHeap(serviceName); + + return status; +} + +NTSTATUS PhSvcCallSetTcpEntry( + _In_ PVOID TcpRow + ) +{ + PHSVC_API_MSG m; + struct + { + DWORD dwState; + DWORD dwLocalAddr; + DWORD dwLocalPort; + DWORD dwRemoteAddr; + DWORD dwRemotePort; + } *tcpRow = TcpRow; + + if (!PhSvcClPortHandle) + return STATUS_PORT_DISCONNECTED; + + m.p.ApiNumber = PhSvcSetTcpEntryApiNumber; + + m.p.u.SetTcpEntry.i.State = tcpRow->dwState; + m.p.u.SetTcpEntry.i.LocalAddress = tcpRow->dwLocalAddr; + m.p.u.SetTcpEntry.i.LocalPort = tcpRow->dwLocalPort; + m.p.u.SetTcpEntry.i.RemoteAddress = tcpRow->dwRemoteAddr; + m.p.u.SetTcpEntry.i.RemotePort = tcpRow->dwRemotePort; + + return PhSvcpCallServer(&m); +} + +NTSTATUS PhSvcCallControlThread( + _In_ HANDLE ThreadId, + _In_ PHSVC_API_CONTROLTHREAD_COMMAND Command, + _In_ ULONG Argument + ) +{ + PHSVC_API_MSG m; + + if (!PhSvcClPortHandle) + return STATUS_PORT_DISCONNECTED; + + m.p.ApiNumber = PhSvcControlThreadApiNumber; + m.p.u.ControlThread.i.ThreadId = ThreadId; + m.p.u.ControlThread.i.Command = Command; + m.p.u.ControlThread.i.Argument = Argument; + + return PhSvcpCallServer(&m); +} + +NTSTATUS PhSvcCallAddAccountRight( + _In_ PSID AccountSid, + _In_ PUNICODE_STRING UserRight + ) +{ + NTSTATUS status; + PHSVC_API_MSG m; + PVOID accountSid = NULL; + PVOID userRight = NULL; + + if (!PhSvcClPortHandle) + return STATUS_PORT_DISCONNECTED; + + m.p.ApiNumber = PhSvcAddAccountRightApiNumber; + + status = STATUS_NO_MEMORY; + + if (!(accountSid = PhSvcpCreateString(AccountSid, RtlLengthSid(AccountSid), &m.p.u.AddAccountRight.i.AccountSid))) + goto CleanupExit; + if (!(userRight = PhSvcpCreateString(UserRight->Buffer, UserRight->Length, &m.p.u.AddAccountRight.i.UserRight))) + goto CleanupExit; + + status = PhSvcpCallServer(&m); + +CleanupExit: + if (userRight) PhSvcpFreeHeap(userRight); + if (accountSid) PhSvcpFreeHeap(accountSid); + + return status; +} + +NTSTATUS PhSvcCallInvokeRunAsService( + _In_ PPH_RUNAS_SERVICE_PARAMETERS Parameters + ) +{ + return PhSvcpCallExecuteRunAsCommand(PhSvcInvokeRunAsServiceApiNumber, Parameters); +} + +NTSTATUS PhSvcCallIssueMemoryListCommand( + _In_ SYSTEM_MEMORY_LIST_COMMAND Command + ) +{ + PHSVC_API_MSG m; + + if (!PhSvcClPortHandle) + return STATUS_PORT_DISCONNECTED; + + m.p.ApiNumber = PhSvcIssueMemoryListCommandApiNumber; + m.p.u.IssueMemoryListCommand.i.Command = Command; + + return PhSvcpCallServer(&m); +} + +NTSTATUS PhSvcCallPostMessage( + _In_opt_ HWND hWnd, + _In_ UINT Msg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + PHSVC_API_MSG m; + + if (!PhSvcClPortHandle) + return STATUS_PORT_DISCONNECTED; + + m.p.ApiNumber = PhSvcPostMessageApiNumber; + m.p.u.PostMessage.i.hWnd = hWnd; + m.p.u.PostMessage.i.Msg = Msg; + m.p.u.PostMessage.i.wParam = wParam; + m.p.u.PostMessage.i.lParam = lParam; + + return PhSvcpCallServer(&m); +} + +NTSTATUS PhSvcCallSendMessage( + _In_opt_ HWND hWnd, + _In_ UINT Msg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + PHSVC_API_MSG m; + + if (!PhSvcClPortHandle) + return STATUS_PORT_DISCONNECTED; + + m.p.ApiNumber = PhSvcSendMessageApiNumber; + m.p.u.PostMessage.i.hWnd = hWnd; + m.p.u.PostMessage.i.Msg = Msg; + m.p.u.PostMessage.i.wParam = wParam; + m.p.u.PostMessage.i.lParam = lParam; + + return PhSvcpCallServer(&m); +} + +NTSTATUS PhSvcCallCreateProcessIgnoreIfeoDebugger( + _In_ PWSTR FileName + ) +{ + NTSTATUS status; + PHSVC_API_MSG m; + PVOID fileName = NULL; + + memset(&m, 0, sizeof(PHSVC_API_MSG)); + + if (!PhSvcClPortHandle) + return STATUS_PORT_DISCONNECTED; + + m.p.ApiNumber = PhSvcCreateProcessIgnoreIfeoDebuggerApiNumber; + fileName = PhSvcpCreateString(FileName, -1, &m.p.u.CreateProcessIgnoreIfeoDebugger.i.FileName); + + if (!fileName) + return STATUS_NO_MEMORY; + + status = PhSvcpCallServer(&m); + + if (fileName) + PhSvcpFreeHeap(fileName); + + return status; +} + +PSECURITY_DESCRIPTOR PhpAbsoluteToSelfRelativeSD( + _In_ PSECURITY_DESCRIPTOR AbsoluteSecurityDescriptor, + _Out_ PULONG BufferSize + ) +{ + NTSTATUS status; + ULONG bufferSize = 0; + PSECURITY_DESCRIPTOR selfRelativeSecurityDescriptor; + + status = RtlAbsoluteToSelfRelativeSD(AbsoluteSecurityDescriptor, NULL, &bufferSize); + + if (status != STATUS_BUFFER_TOO_SMALL) + return NULL; + + selfRelativeSecurityDescriptor = PhAllocate(bufferSize); + status = RtlAbsoluteToSelfRelativeSD(AbsoluteSecurityDescriptor, selfRelativeSecurityDescriptor, &bufferSize); + + if (!NT_SUCCESS(status)) + { + PhFree(selfRelativeSecurityDescriptor); + return NULL; + } + + *BufferSize = bufferSize; + + return selfRelativeSecurityDescriptor; +} + +NTSTATUS PhSvcCallSetServiceSecurity( + _In_ PWSTR ServiceName, + _In_ SECURITY_INFORMATION SecurityInformation, + _In_ PSECURITY_DESCRIPTOR SecurityDescriptor + ) +{ + NTSTATUS status; + PHSVC_API_MSG m; + PSECURITY_DESCRIPTOR selfRelativeSecurityDescriptor = NULL; + ULONG bufferSize; + PVOID serviceName = NULL; + PVOID copiedSelfRelativeSecurityDescriptor = NULL; + + if (!PhSvcClPortHandle) + return STATUS_PORT_DISCONNECTED; + + selfRelativeSecurityDescriptor = PhpAbsoluteToSelfRelativeSD(SecurityDescriptor, &bufferSize); + + if (!selfRelativeSecurityDescriptor) + { + status = STATUS_BAD_DESCRIPTOR_FORMAT; + goto CleanupExit; + } + + m.p.ApiNumber = PhSvcSetServiceSecurityApiNumber; + m.p.u.SetServiceSecurity.i.SecurityInformation = SecurityInformation; + status = STATUS_NO_MEMORY; + + if (!(serviceName = PhSvcpCreateString(ServiceName, -1, &m.p.u.SetServiceSecurity.i.ServiceName))) + goto CleanupExit; + if (!(copiedSelfRelativeSecurityDescriptor = PhSvcpCreateString(selfRelativeSecurityDescriptor, bufferSize, &m.p.u.SetServiceSecurity.i.SecurityDescriptor))) + goto CleanupExit; + + status = PhSvcpCallServer(&m); + +CleanupExit: + if (selfRelativeSecurityDescriptor) PhFree(selfRelativeSecurityDescriptor); + if (serviceName) PhSvcpFreeHeap(serviceName); + if (copiedSelfRelativeSecurityDescriptor) PhSvcpFreeHeap(copiedSelfRelativeSecurityDescriptor); + + return status; +} + +NTSTATUS PhSvcCallLoadDbgHelp( + _In_ PWSTR DbgHelpPath + ) +{ + NTSTATUS status; + PHSVC_API_MSG m; + PVOID dbgHelpPath = NULL; + + memset(&m, 0, sizeof(PHSVC_API_MSG)); + + if (!PhSvcClPortHandle) + return STATUS_PORT_DISCONNECTED; + + m.p.ApiNumber = PhSvcLoadDbgHelpApiNumber; + dbgHelpPath = PhSvcpCreateString(DbgHelpPath, -1, &m.p.u.LoadDbgHelp.i.DbgHelpPath); + + if (!dbgHelpPath) + return STATUS_NO_MEMORY; + + status = PhSvcpCallServer(&m); + + if (dbgHelpPath) + PhSvcpFreeHeap(dbgHelpPath); + + return status; +} + +NTSTATUS PhSvcCallWriteMiniDumpProcess( + _In_ HANDLE ProcessHandle, + _In_ HANDLE ProcessId, + _In_ HANDLE FileHandle, + _In_ ULONG DumpType + ) +{ + NTSTATUS status; + PHSVC_API_MSG m; + HANDLE serverHandle = NULL; + HANDLE remoteProcessHandle = NULL; + HANDLE remoteFileHandle = NULL; + + memset(&m, 0, sizeof(PHSVC_API_MSG)); + + if (!PhSvcClPortHandle) + return STATUS_PORT_DISCONNECTED; + + // For typical uses of this function, the client has more privileges than the server. + // We therefore duplicate our handles into the server's process. + + m.p.ApiNumber = PhSvcWriteMiniDumpProcessApiNumber; + + if (!NT_SUCCESS(status = PhOpenProcess(&serverHandle, PROCESS_DUP_HANDLE, PhSvcClServerProcessId))) + { + goto CleanupExit; + } + + if (!NT_SUCCESS(status = NtDuplicateObject(NtCurrentProcess(), ProcessHandle, serverHandle, &remoteProcessHandle, + PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, 0, 0))) + { + goto CleanupExit; + } + + if (!NT_SUCCESS(status = NtDuplicateObject(NtCurrentProcess(), FileHandle, serverHandle, &remoteFileHandle, + FILE_GENERIC_WRITE, 0, 0))) + { + goto CleanupExit; + } + + m.p.u.WriteMiniDumpProcess.i.LocalProcessHandle = HandleToUlong(remoteProcessHandle); + m.p.u.WriteMiniDumpProcess.i.ProcessId = HandleToUlong(ProcessId); + m.p.u.WriteMiniDumpProcess.i.LocalFileHandle = HandleToUlong(remoteFileHandle); + m.p.u.WriteMiniDumpProcess.i.DumpType = DumpType; + + status = PhSvcpCallServer(&m); + +CleanupExit: + if (serverHandle) + { + if (remoteProcessHandle) + NtDuplicateObject(serverHandle, remoteProcessHandle, NULL, NULL, 0, 0, DUPLICATE_CLOSE_SOURCE); + if (remoteFileHandle) + NtDuplicateObject(serverHandle, remoteFileHandle, NULL, NULL, 0, 0, DUPLICATE_CLOSE_SOURCE); + + NtClose(serverHandle); + } + + return status; +} diff --git a/ProcessHacker/phsvc/svcapi.c b/ProcessHacker/phsvc/svcapi.c index c18ca5045e44..a375f4a6dee4 100644 --- a/ProcessHacker/phsvc/svcapi.c +++ b/ProcessHacker/phsvc/svcapi.c @@ -1,1446 +1,1446 @@ -/* - * Process Hacker - - * server API - * - * Copyright (C) 2011-2015 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include -#include - -#include - -#include -#include -#include -#include - -#include -#include -#include - -typedef struct _PHSVCP_CAPTURED_RUNAS_SERVICE_PARAMETERS -{ - PPH_STRING UserName; - PPH_STRING Password; - PPH_STRING CurrentDirectory; - PPH_STRING CommandLine; - PPH_STRING FileName; - PPH_STRING DesktopName; - PPH_STRING ServiceName; -} PHSVCP_CAPTURED_RUNAS_SERVICE_PARAMETERS, *PPHSVCP_CAPTURED_RUNAS_SERVICE_PARAMETERS; - -PPHSVC_API_PROCEDURE PhSvcApiCallTable[] = -{ - PhSvcApiPlugin, - PhSvcApiExecuteRunAsCommand, - PhSvcApiUnloadDriver, - PhSvcApiControlProcess, - PhSvcApiControlService, - PhSvcApiCreateService, - PhSvcApiChangeServiceConfig, - PhSvcApiChangeServiceConfig2, - PhSvcApiSetTcpEntry, - PhSvcApiControlThread, - PhSvcApiAddAccountRight, - PhSvcApiInvokeRunAsService, - PhSvcApiIssueMemoryListCommand, - PhSvcApiPostMessage, - PhSvcApiSendMessage, - PhSvcApiCreateProcessIgnoreIfeoDebugger, - PhSvcApiSetServiceSecurity, - PhSvcApiLoadDbgHelp, - PhSvcApiWriteMiniDumpProcess -}; -C_ASSERT(sizeof(PhSvcApiCallTable) / sizeof(PPHSVC_API_PROCEDURE) == PhSvcMaximumApiNumber - 1); - -NTSTATUS PhSvcApiInitialization( - VOID - ) -{ - return STATUS_SUCCESS; -} - -VOID PhSvcDispatchApiCall( - _In_ PPHSVC_CLIENT Client, - _Inout_ PPHSVC_API_PAYLOAD Payload, - _Out_ PHANDLE ReplyPortHandle - ) -{ - NTSTATUS status; - - if ( - Payload->ApiNumber == 0 || - (ULONG)Payload->ApiNumber >= (ULONG)PhSvcMaximumApiNumber || - !PhSvcApiCallTable[Payload->ApiNumber - 1] - ) - { - Payload->ReturnStatus = STATUS_INVALID_SYSTEM_SERVICE; - *ReplyPortHandle = Client->PortHandle; - return; - } - - status = PhSvcApiCallTable[Payload->ApiNumber - 1](Client, Payload); - Payload->ReturnStatus = status; - - *ReplyPortHandle = Client->PortHandle; -} - -PVOID PhSvcValidateString( - _In_ PPH_RELATIVE_STRINGREF String, - _In_ ULONG Alignment - ) -{ - PPHSVC_CLIENT client = PhSvcGetCurrentClient(); - PVOID address; - - address = (PCHAR)client->ClientViewBase + String->Offset; - - if ((ULONG_PTR)address + String->Length < (ULONG_PTR)address || - (ULONG_PTR)address < (ULONG_PTR)client->ClientViewBase || - (ULONG_PTR)address + String->Length > (ULONG_PTR)client->ClientViewLimit) - { - return NULL; - } - - if ((ULONG_PTR)address & (Alignment - 1)) - { - return NULL; - } - - return address; -} - -NTSTATUS PhSvcProbeBuffer( - _In_ PPH_RELATIVE_STRINGREF String, - _In_ ULONG Alignment, - _In_ BOOLEAN AllowNull, - _Out_ PVOID *Pointer - ) -{ - PVOID address; - - if (String->Offset != 0) - { - address = PhSvcValidateString(String, Alignment); - - if (!address) - return STATUS_ACCESS_VIOLATION; - - *Pointer = address; - } - else - { - if (!AllowNull) - return STATUS_ACCESS_VIOLATION; - - *Pointer = NULL; - } - - return STATUS_SUCCESS; -} - -NTSTATUS PhSvcCaptureBuffer( - _In_ PPH_RELATIVE_STRINGREF String, - _In_ BOOLEAN AllowNull, - _Out_ PVOID *CapturedBuffer - ) -{ - PVOID address; - PVOID buffer; - - if (String->Offset != 0) - { - address = PhSvcValidateString(String, 1); - - if (!address) - return STATUS_ACCESS_VIOLATION; - - buffer = PhAllocateSafe(String->Length); - - if (!buffer) - return STATUS_NO_MEMORY; - - memcpy(buffer, address, String->Length); - *CapturedBuffer = buffer; - } - else - { - if (!AllowNull) - return STATUS_ACCESS_VIOLATION; - - *CapturedBuffer = NULL; - } - - return STATUS_SUCCESS; -} - -NTSTATUS PhSvcCaptureString( - _In_ PPH_RELATIVE_STRINGREF String, - _In_ BOOLEAN AllowNull, - _Out_ PPH_STRING *CapturedString - ) -{ - PVOID address; - - if (String->Length & 1) - return STATUS_INVALID_BUFFER_SIZE; - if (String->Length > 0xfffe) - return STATUS_INVALID_BUFFER_SIZE; - - if (String->Offset != 0) - { - address = PhSvcValidateString(String, sizeof(WCHAR)); - - if (!address) - return STATUS_ACCESS_VIOLATION; - - if (String->Length != 0) - *CapturedString = PhCreateStringEx(address, String->Length); - else - *CapturedString = PhReferenceEmptyString(); - } - else - { - if (!AllowNull) - return STATUS_ACCESS_VIOLATION; - - *CapturedString = NULL; - } - - return STATUS_SUCCESS; -} - -NTSTATUS PhSvcCaptureSid( - _In_ PPH_RELATIVE_STRINGREF String, - _In_ BOOLEAN AllowNull, - _Out_ PSID *CapturedSid - ) -{ - NTSTATUS status; - PSID sid; - - if (!NT_SUCCESS(status = PhSvcCaptureBuffer(String, AllowNull, &sid))) - return status; - - if (sid) - { - if (String->Length < (ULONG)FIELD_OFFSET(struct _SID, IdentifierAuthority) || - String->Length < RtlLengthRequiredSid(((struct _SID *)sid)->SubAuthorityCount) || - !RtlValidSid(sid)) - { - PhFree(sid); - return STATUS_INVALID_SID; - } - - *CapturedSid = sid; - } - else - { - *CapturedSid = NULL; - } - - return STATUS_SUCCESS; -} - -NTSTATUS PhSvcCaptureSecurityDescriptor( - _In_ PPH_RELATIVE_STRINGREF String, - _In_ BOOLEAN AllowNull, - _In_ SECURITY_INFORMATION RequiredInformation, - _Out_ PSECURITY_DESCRIPTOR *CapturedSecurityDescriptor - ) -{ - NTSTATUS status; - PSECURITY_DESCRIPTOR securityDescriptor; - ULONG bufferSize; - - if (!NT_SUCCESS(status = PhSvcCaptureBuffer(String, AllowNull, &securityDescriptor))) - return status; - - if (securityDescriptor) - { - if (!RtlValidRelativeSecurityDescriptor(securityDescriptor, String->Length, RequiredInformation)) - { - PhFree(securityDescriptor); - return STATUS_INVALID_SECURITY_DESCR; - } - - bufferSize = String->Length; - status = RtlSelfRelativeToAbsoluteSD2(securityDescriptor, &bufferSize); - - if (status == STATUS_BUFFER_TOO_SMALL) - { - PVOID newBuffer; - - newBuffer = PhAllocate(bufferSize); - memcpy(newBuffer, securityDescriptor, String->Length); - PhFree(securityDescriptor); - securityDescriptor = newBuffer; - - status = RtlSelfRelativeToAbsoluteSD2(securityDescriptor, &bufferSize); - } - - if (!NT_SUCCESS(status)) - { - PhFree(securityDescriptor); - return status; - } - - *CapturedSecurityDescriptor = securityDescriptor; - } - else - { - *CapturedSecurityDescriptor = NULL; - } - - return STATUS_SUCCESS; -} - -NTSTATUS PhSvcApiDefault( - _In_ PPHSVC_CLIENT Client, - _Inout_ PPHSVC_API_PAYLOAD Payload - ) -{ - return STATUS_NOT_IMPLEMENTED; -} - -NTSTATUS PhSvcApiPlugin( - _In_ PPHSVC_CLIENT Client, - _Inout_ PPHSVC_API_PAYLOAD Payload - ) -{ - NTSTATUS status; - PPH_STRING apiId; - PPH_PLUGIN plugin; - PH_STRINGREF pluginName; - PH_PLUGIN_PHSVC_REQUEST request; - - if (NT_SUCCESS(status = PhSvcCaptureString(&Payload->u.Plugin.i.ApiId, FALSE, &apiId))) - { - PH_AUTO(apiId); - - if (PhPluginsEnabled && - PhEmParseCompoundId(&apiId->sr, &pluginName, &request.SubId) && - (plugin = PhFindPlugin2(&pluginName))) - { - request.ReturnStatus = STATUS_NOT_IMPLEMENTED; - request.InBuffer = Payload->u.Plugin.i.Data; - request.InLength = sizeof(Payload->u.Plugin.i.Data); - request.OutBuffer = Payload->u.Plugin.o.Data; - request.OutLength = sizeof(Payload->u.Plugin.o.Data); - - request.ProbeBuffer = PhSvcProbeBuffer; - request.CaptureBuffer = PhSvcCaptureBuffer; - request.CaptureString = PhSvcCaptureString; - - PhInvokeCallback(PhGetPluginCallback(plugin, PluginCallbackPhSvcRequest), &request); - status = request.ReturnStatus; - } - else - { - status = STATUS_NOT_FOUND; - } - } - - return status; -} - -NTSTATUS PhSvcpCaptureRunAsServiceParameters( - _In_ PPHSVC_CLIENT Client, - _Inout_ PPHSVC_API_PAYLOAD Payload, - _Out_ PPH_RUNAS_SERVICE_PARAMETERS Parameters, - _Out_ PPHSVCP_CAPTURED_RUNAS_SERVICE_PARAMETERS CapturedParameters - ) -{ - NTSTATUS status; - - memset(CapturedParameters, 0, sizeof(PHSVCP_CAPTURED_RUNAS_SERVICE_PARAMETERS)); - - if (!NT_SUCCESS(status = PhSvcCaptureString(&Payload->u.ExecuteRunAsCommand.i.UserName, TRUE, &CapturedParameters->UserName))) - return status; - if (!NT_SUCCESS(status = PhSvcCaptureString(&Payload->u.ExecuteRunAsCommand.i.Password, TRUE, &CapturedParameters->Password))) - return status; - if (!NT_SUCCESS(status = PhSvcCaptureString(&Payload->u.ExecuteRunAsCommand.i.CurrentDirectory, TRUE, &CapturedParameters->CurrentDirectory))) - return status; - if (!NT_SUCCESS(status = PhSvcCaptureString(&Payload->u.ExecuteRunAsCommand.i.CommandLine, TRUE, &CapturedParameters->CommandLine))) - return status; - if (!NT_SUCCESS(status = PhSvcCaptureString(&Payload->u.ExecuteRunAsCommand.i.FileName, TRUE, &CapturedParameters->FileName))) - return status; - if (!NT_SUCCESS(status = PhSvcCaptureString(&Payload->u.ExecuteRunAsCommand.i.DesktopName, TRUE, &CapturedParameters->DesktopName))) - return status; - if (!NT_SUCCESS(status = PhSvcCaptureString(&Payload->u.ExecuteRunAsCommand.i.ServiceName, TRUE, &CapturedParameters->ServiceName))) - return status; - - Parameters->ProcessId = Payload->u.ExecuteRunAsCommand.i.ProcessId; - Parameters->UserName = PhGetString(CapturedParameters->UserName); - Parameters->Password = PhGetString(CapturedParameters->Password); - Parameters->LogonType = Payload->u.ExecuteRunAsCommand.i.LogonType; - Parameters->SessionId = Payload->u.ExecuteRunAsCommand.i.SessionId; - Parameters->CurrentDirectory = PhGetString(CapturedParameters->CurrentDirectory); - Parameters->CommandLine = PhGetString(CapturedParameters->CommandLine); - Parameters->FileName = PhGetString(CapturedParameters->FileName); - Parameters->DesktopName = PhGetString(CapturedParameters->DesktopName); - Parameters->UseLinkedToken = Payload->u.ExecuteRunAsCommand.i.UseLinkedToken; - Parameters->ServiceName = PhGetString(CapturedParameters->ServiceName); - - return status; -} - -VOID PhSvcpReleaseRunAsServiceParameters( - _In_ PPHSVCP_CAPTURED_RUNAS_SERVICE_PARAMETERS CapturedParameters - ) -{ - if (CapturedParameters->UserName) - PhDereferenceObject(CapturedParameters->UserName); - - if (CapturedParameters->Password) - { - RtlSecureZeroMemory(CapturedParameters->Password->Buffer, CapturedParameters->Password->Length); - PhDereferenceObject(CapturedParameters->Password); - } - - if (CapturedParameters->CurrentDirectory) - PhDereferenceObject(CapturedParameters->CurrentDirectory); - if (CapturedParameters->CommandLine) - PhDereferenceObject(CapturedParameters->CommandLine); - if (CapturedParameters->FileName) - PhDereferenceObject(CapturedParameters->FileName); - if (CapturedParameters->DesktopName) - PhDereferenceObject(CapturedParameters->DesktopName); - if (CapturedParameters->ServiceName) - PhDereferenceObject(CapturedParameters->ServiceName); -} - -NTSTATUS PhSvcpValidateRunAsServiceParameters( - _In_ PPH_RUNAS_SERVICE_PARAMETERS Parameters - ) -{ - if ((!Parameters->UserName || !Parameters->Password) && !Parameters->ProcessId) - return STATUS_INVALID_PARAMETER_MIX; - if (!Parameters->FileName && !Parameters->CommandLine) - return STATUS_INVALID_PARAMETER_MIX; - if (!Parameters->ServiceName) - return STATUS_INVALID_PARAMETER; - - return STATUS_SUCCESS; -} - -NTSTATUS PhSvcApiExecuteRunAsCommand( - _In_ PPHSVC_CLIENT Client, - _Inout_ PPHSVC_API_PAYLOAD Payload - ) -{ - NTSTATUS status; - PH_RUNAS_SERVICE_PARAMETERS parameters; - PHSVCP_CAPTURED_RUNAS_SERVICE_PARAMETERS capturedParameters; - - if (NT_SUCCESS(status = PhSvcpCaptureRunAsServiceParameters(Client, Payload, ¶meters, &capturedParameters))) - { - if (NT_SUCCESS(status = PhSvcpValidateRunAsServiceParameters(¶meters))) - { - status = PhExecuteRunAsCommand(¶meters); - } - } - - PhSvcpReleaseRunAsServiceParameters(&capturedParameters); - - return status; -} - -NTSTATUS PhSvcApiUnloadDriver( - _In_ PPHSVC_CLIENT Client, - _Inout_ PPHSVC_API_PAYLOAD Payload - ) -{ - NTSTATUS status; - PPH_STRING name; - - if (NT_SUCCESS(status = PhSvcCaptureString(&Payload->u.UnloadDriver.i.Name, TRUE, &name))) - { - status = PhUnloadDriver(Payload->u.UnloadDriver.i.BaseAddress, PhGetString(name)); - PhClearReference(&name); - } - - return status; -} - -NTSTATUS PhSvcApiControlProcess( - _In_ PPHSVC_CLIENT Client, - _Inout_ PPHSVC_API_PAYLOAD Payload - ) -{ - NTSTATUS status; - HANDLE processId; - HANDLE processHandle; - - processId = Payload->u.ControlProcess.i.ProcessId; - - switch (Payload->u.ControlProcess.i.Command) - { - case PhSvcControlProcessTerminate: - if (NT_SUCCESS(status = PhOpenProcess(&processHandle, PROCESS_TERMINATE, processId))) - { - status = PhTerminateProcess(processHandle, 1); // see notes in PhUiTerminateProcesses - NtClose(processHandle); - } - break; - case PhSvcControlProcessSuspend: - if (NT_SUCCESS(status = PhOpenProcess(&processHandle, PROCESS_SUSPEND_RESUME, processId))) - { - status = NtSuspendProcess(processHandle); - NtClose(processHandle); - } - break; - case PhSvcControlProcessResume: - if (NT_SUCCESS(status = PhOpenProcess(&processHandle, PROCESS_SUSPEND_RESUME, processId))) - { - status = NtResumeProcess(processHandle); - NtClose(processHandle); - } - break; - case PhSvcControlProcessPriority: - if (processId != SYSTEM_PROCESS_ID) - { - if (NT_SUCCESS(status = PhOpenProcess(&processHandle, PROCESS_SET_INFORMATION, processId))) - { - PROCESS_PRIORITY_CLASS priorityClass; - - priorityClass.Foreground = FALSE; - priorityClass.PriorityClass = (UCHAR)Payload->u.ControlProcess.i.Argument; - status = NtSetInformationProcess(processHandle, ProcessPriorityClass, &priorityClass, sizeof(PROCESS_PRIORITY_CLASS)); - - NtClose(processHandle); - } - } - else - { - status = STATUS_UNSUCCESSFUL; - } - break; - case PhSvcControlProcessIoPriority: - if (processId != SYSTEM_PROCESS_ID) - { - if (NT_SUCCESS(status = PhOpenProcess(&processHandle, PROCESS_SET_INFORMATION, processId))) - { - status = PhSetProcessIoPriority(processHandle, Payload->u.ControlProcess.i.Argument); - NtClose(processHandle); - } - } - else - { - status = STATUS_UNSUCCESSFUL; - } - break; - default: - status = STATUS_INVALID_PARAMETER; - break; - } - - return status; -} - -NTSTATUS PhSvcApiControlService( - _In_ PPHSVC_CLIENT Client, - _Inout_ PPHSVC_API_PAYLOAD Payload - ) -{ - NTSTATUS status; - PPH_STRING serviceName; - SC_HANDLE serviceHandle; - SERVICE_STATUS serviceStatus; - - if (NT_SUCCESS(status = PhSvcCaptureString(&Payload->u.ControlService.i.ServiceName, FALSE, &serviceName))) - { - PH_AUTO(serviceName); - - switch (Payload->u.ControlService.i.Command) - { - case PhSvcControlServiceStart: - if (serviceHandle = PhOpenService( - serviceName->Buffer, - SERVICE_START - )) - { - if (!StartService(serviceHandle, 0, NULL)) - status = PhGetLastWin32ErrorAsNtStatus(); - - CloseServiceHandle(serviceHandle); - } - else - { - status = PhGetLastWin32ErrorAsNtStatus(); - } - break; - case PhSvcControlServiceContinue: - if (serviceHandle = PhOpenService( - serviceName->Buffer, - SERVICE_PAUSE_CONTINUE - )) - { - if (!ControlService(serviceHandle, SERVICE_CONTROL_CONTINUE, &serviceStatus)) - status = PhGetLastWin32ErrorAsNtStatus(); - - CloseServiceHandle(serviceHandle); - } - else - { - status = PhGetLastWin32ErrorAsNtStatus(); - } - break; - case PhSvcControlServicePause: - if (serviceHandle = PhOpenService( - serviceName->Buffer, - SERVICE_PAUSE_CONTINUE - )) - { - if (!ControlService(serviceHandle, SERVICE_CONTROL_PAUSE, &serviceStatus)) - status = PhGetLastWin32ErrorAsNtStatus(); - - CloseServiceHandle(serviceHandle); - } - else - { - status = PhGetLastWin32ErrorAsNtStatus(); - } - break; - case PhSvcControlServiceStop: - if (serviceHandle = PhOpenService( - serviceName->Buffer, - SERVICE_STOP - )) - { - if (!ControlService(serviceHandle, SERVICE_CONTROL_STOP, &serviceStatus)) - status = PhGetLastWin32ErrorAsNtStatus(); - - CloseServiceHandle(serviceHandle); - } - else - { - status = PhGetLastWin32ErrorAsNtStatus(); - } - break; - case PhSvcControlServiceDelete: - if (serviceHandle = PhOpenService( - serviceName->Buffer, - DELETE - )) - { - if (!DeleteService(serviceHandle)) - status = PhGetLastWin32ErrorAsNtStatus(); - - CloseServiceHandle(serviceHandle); - } - else - { - status = PhGetLastWin32ErrorAsNtStatus(); - } - break; - default: - status = STATUS_INVALID_PARAMETER; - break; - } - } - - return status; -} - -NTSTATUS PhSvcApiCreateService( - _In_ PPHSVC_CLIENT Client, - _Inout_ PPHSVC_API_PAYLOAD Payload - ) -{ - NTSTATUS status; - PPH_STRING serviceName = NULL; - PPH_STRING displayName = NULL; - PPH_STRING binaryPathName = NULL; - PPH_STRING loadOrderGroup = NULL; - PPH_STRING dependencies = NULL; - PPH_STRING serviceStartName = NULL; - PPH_STRING password = NULL; - ULONG tagId = 0; - SC_HANDLE scManagerHandle; - SC_HANDLE serviceHandle; - - if (!NT_SUCCESS(status = PhSvcCaptureString(&Payload->u.CreateService.i.ServiceName, FALSE, &serviceName))) - goto CleanupExit; - if (!NT_SUCCESS(status = PhSvcCaptureString(&Payload->u.CreateService.i.DisplayName, TRUE, &displayName))) - goto CleanupExit; - if (!NT_SUCCESS(status = PhSvcCaptureString(&Payload->u.CreateService.i.BinaryPathName, TRUE, &binaryPathName))) - goto CleanupExit; - if (!NT_SUCCESS(status = PhSvcCaptureString(&Payload->u.CreateService.i.LoadOrderGroup, TRUE, &loadOrderGroup))) - goto CleanupExit; - if (!NT_SUCCESS(status = PhSvcCaptureString(&Payload->u.CreateService.i.Dependencies, TRUE, &dependencies))) - goto CleanupExit; - if (!NT_SUCCESS(status = PhSvcCaptureString(&Payload->u.CreateService.i.ServiceStartName, TRUE, &serviceStartName))) - goto CleanupExit; - if (!NT_SUCCESS(status = PhSvcCaptureString(&Payload->u.CreateService.i.Password, TRUE, &password))) - goto CleanupExit; - - if (scManagerHandle = OpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE)) - { - if (serviceHandle = CreateService( - scManagerHandle, - serviceName->Buffer, - PhGetString(displayName), - SERVICE_CHANGE_CONFIG, - Payload->u.CreateService.i.ServiceType, - Payload->u.CreateService.i.StartType, - Payload->u.CreateService.i.ErrorControl, - PhGetString(binaryPathName), - PhGetString(loadOrderGroup), - Payload->u.CreateService.i.TagIdSpecified ? &tagId : NULL, - PhGetString(dependencies), - PhGetString(serviceStartName), - PhGetString(password) - )) - { - Payload->u.CreateService.o.TagId = tagId; - CloseServiceHandle(serviceHandle); - } - else - { - status = PhGetLastWin32ErrorAsNtStatus(); - } - - CloseServiceHandle(scManagerHandle); - } - else - { - status = PhGetLastWin32ErrorAsNtStatus(); - } - -CleanupExit: - if (password) - { - RtlSecureZeroMemory(password->Buffer, password->Length); - PhDereferenceObject(password); - } - - PhClearReference(&serviceStartName); - PhClearReference(&dependencies); - PhClearReference(&loadOrderGroup); - PhClearReference(&binaryPathName); - PhClearReference(&displayName); - PhClearReference(&serviceName); - - return status; -} - -NTSTATUS PhSvcApiChangeServiceConfig( - _In_ PPHSVC_CLIENT Client, - _Inout_ PPHSVC_API_PAYLOAD Payload - ) -{ - NTSTATUS status; - PPH_STRING serviceName = NULL; - PPH_STRING binaryPathName = NULL; - PPH_STRING loadOrderGroup = NULL; - PPH_STRING dependencies = NULL; - PPH_STRING serviceStartName = NULL; - PPH_STRING password = NULL; - PPH_STRING displayName = NULL; - ULONG tagId = 0; - SC_HANDLE serviceHandle; - - if (!NT_SUCCESS(status = PhSvcCaptureString(&Payload->u.ChangeServiceConfig.i.ServiceName, FALSE, &serviceName))) - goto CleanupExit; - if (!NT_SUCCESS(status = PhSvcCaptureString(&Payload->u.ChangeServiceConfig.i.BinaryPathName, TRUE, &binaryPathName))) - goto CleanupExit; - if (!NT_SUCCESS(status = PhSvcCaptureString(&Payload->u.ChangeServiceConfig.i.LoadOrderGroup, TRUE, &loadOrderGroup))) - goto CleanupExit; - if (!NT_SUCCESS(status = PhSvcCaptureString(&Payload->u.ChangeServiceConfig.i.Dependencies, TRUE, &dependencies))) - goto CleanupExit; - if (!NT_SUCCESS(status = PhSvcCaptureString(&Payload->u.ChangeServiceConfig.i.ServiceStartName, TRUE, &serviceStartName))) - goto CleanupExit; - if (!NT_SUCCESS(status = PhSvcCaptureString(&Payload->u.ChangeServiceConfig.i.Password, TRUE, &password))) - goto CleanupExit; - if (!NT_SUCCESS(status = PhSvcCaptureString(&Payload->u.ChangeServiceConfig.i.DisplayName, TRUE, &displayName))) - goto CleanupExit; - - if (serviceHandle = PhOpenService(serviceName->Buffer, SERVICE_CHANGE_CONFIG)) - { - if (ChangeServiceConfig( - serviceHandle, - Payload->u.ChangeServiceConfig.i.ServiceType, - Payload->u.ChangeServiceConfig.i.StartType, - Payload->u.ChangeServiceConfig.i.ErrorControl, - PhGetString(binaryPathName), - PhGetString(loadOrderGroup), - Payload->u.ChangeServiceConfig.i.TagIdSpecified ? &tagId : NULL, - PhGetString(dependencies), - PhGetString(serviceStartName), - PhGetString(password), - PhGetString(displayName) - )) - { - Payload->u.ChangeServiceConfig.o.TagId = tagId; - } - else - { - status = PhGetLastWin32ErrorAsNtStatus(); - } - - CloseServiceHandle(serviceHandle); - } - else - { - status = PhGetLastWin32ErrorAsNtStatus(); - } - -CleanupExit: - PhClearReference(&displayName); - - if (password) - { - RtlSecureZeroMemory(password->Buffer, password->Length); - PhDereferenceObject(password); - } - - PhClearReference(&serviceStartName); - PhClearReference(&dependencies); - PhClearReference(&loadOrderGroup); - PhClearReference(&binaryPathName); - PhClearReference(&serviceName); - - return status; -} - -NTSTATUS PhSvcpUnpackRoot( - _In_ PPH_RELATIVE_STRINGREF PackedData, - _In_ PVOID CapturedBuffer, - _In_ SIZE_T Length, - _Out_ PVOID *ValidatedBuffer - ) -{ - if (Length > PackedData->Length) - return STATUS_ACCESS_VIOLATION; - - *ValidatedBuffer = CapturedBuffer; - - return STATUS_SUCCESS; -} - -NTSTATUS PhSvcpUnpackBuffer( - _In_ PPH_RELATIVE_STRINGREF PackedData, - _In_ PVOID CapturedBuffer, - _In_ PVOID *OffsetInBuffer, - _In_ SIZE_T Length, - _In_ ULONG Alignment, - _In_ BOOLEAN AllowNull - ) -{ - SIZE_T offset; - - offset = (SIZE_T)*OffsetInBuffer; - - if (offset == 0) - { - if (AllowNull) - return STATUS_SUCCESS; - else - return STATUS_ACCESS_VIOLATION; - } - - if (offset + Length < offset) - return STATUS_ACCESS_VIOLATION; - if (offset + Length > PackedData->Length) - return STATUS_ACCESS_VIOLATION; - if (offset & (Alignment - 1)) - return STATUS_DATATYPE_MISALIGNMENT; - - *OffsetInBuffer = (PVOID)((ULONG_PTR)CapturedBuffer + offset); - - return STATUS_SUCCESS; -} - -NTSTATUS PhSvcpUnpackStringZ( - _In_ PPH_RELATIVE_STRINGREF PackedData, - _In_ PVOID CapturedBuffer, - _In_ PVOID *OffsetInBuffer, - _In_ BOOLEAN Multi, - _In_ BOOLEAN AllowNull - ) -{ - SIZE_T offset; - PWCHAR start; - PWCHAR end; - PH_STRINGREF remainingPart; - PH_STRINGREF firstPart; - - offset = (SIZE_T)*OffsetInBuffer; - - if (offset == 0) - { - if (AllowNull) - return STATUS_SUCCESS; - else - return STATUS_ACCESS_VIOLATION; - } - - if (offset >= PackedData->Length) - return STATUS_ACCESS_VIOLATION; - if (offset & 1) - return STATUS_DATATYPE_MISALIGNMENT; - - start = (PWCHAR)((ULONG_PTR)CapturedBuffer + offset); - end = (PWCHAR)((ULONG_PTR)CapturedBuffer + (PackedData->Length & -2)); - remainingPart.Buffer = start; - remainingPart.Length = (end - start) * sizeof(WCHAR); - - if (Multi) - { - SIZE_T validatedLength = 0; - - while (PhSplitStringRefAtChar(&remainingPart, 0, &firstPart, &remainingPart)) - { - validatedLength += firstPart.Length + sizeof(WCHAR); - - if (firstPart.Length == 0) - { - *OffsetInBuffer = start; - - return STATUS_SUCCESS; - } - } - } - else - { - if (PhSplitStringRefAtChar(&remainingPart, 0, &firstPart, &remainingPart)) - { - *OffsetInBuffer = start; - - return STATUS_SUCCESS; - } - } - - return STATUS_ACCESS_VIOLATION; -} - -NTSTATUS PhSvcApiChangeServiceConfig2( - _In_ PPHSVC_CLIENT Client, - _Inout_ PPHSVC_API_PAYLOAD Payload - ) -{ - NTSTATUS status; - PPH_STRING serviceName = NULL; - PVOID info = NULL; - SC_HANDLE serviceHandle = NULL; - PH_RELATIVE_STRINGREF packedData; - PVOID unpackedInfo = NULL; - ACCESS_MASK desiredAccess = SERVICE_CHANGE_CONFIG; - - if (!NT_SUCCESS(status = PhSvcCaptureString(&Payload->u.ChangeServiceConfig2.i.ServiceName, FALSE, &serviceName))) - goto CleanupExit; - if (!NT_SUCCESS(status = PhSvcCaptureBuffer(&Payload->u.ChangeServiceConfig2.i.Info, FALSE, &info))) - goto CleanupExit; - - packedData = Payload->u.ChangeServiceConfig2.i.Info; - - switch (Payload->u.ChangeServiceConfig2.i.InfoLevel) - { - case SERVICE_CONFIG_FAILURE_ACTIONS: - { - LPSERVICE_FAILURE_ACTIONS failureActions; - - if (!NT_SUCCESS(status = PhSvcpUnpackRoot(&packedData, info, sizeof(SERVICE_FAILURE_ACTIONS), &failureActions))) - goto CleanupExit; - if (!NT_SUCCESS(status = PhSvcpUnpackStringZ(&packedData, info, &failureActions->lpRebootMsg, FALSE, TRUE))) - goto CleanupExit; - if (!NT_SUCCESS(status = PhSvcpUnpackStringZ(&packedData, info, &failureActions->lpCommand, FALSE, TRUE))) - goto CleanupExit; - if (!NT_SUCCESS(status = PhSvcpUnpackBuffer(&packedData, info, &failureActions->lpsaActions, failureActions->cActions * sizeof(SC_ACTION), __alignof(SC_ACTION), TRUE))) - goto CleanupExit; - - if (failureActions->lpsaActions) - { - ULONG i; - - for (i = 0; i < failureActions->cActions; i++) - { - if (failureActions->lpsaActions[i].Type == SC_ACTION_RESTART) - { - desiredAccess |= SERVICE_START; - break; - } - } - } - - unpackedInfo = failureActions; - } - break; - case SERVICE_CONFIG_DELAYED_AUTO_START_INFO: - status = PhSvcpUnpackRoot(&packedData, info, sizeof(SERVICE_DELAYED_AUTO_START_INFO), &unpackedInfo); - break; - case SERVICE_CONFIG_FAILURE_ACTIONS_FLAG: - status = PhSvcpUnpackRoot(&packedData, info, sizeof(SERVICE_FAILURE_ACTIONS_FLAG), &unpackedInfo); - break; - case SERVICE_CONFIG_SERVICE_SID_INFO: - status = PhSvcpUnpackRoot(&packedData, info, sizeof(SERVICE_SID_INFO), &unpackedInfo); - break; - case SERVICE_CONFIG_REQUIRED_PRIVILEGES_INFO: - { - LPSERVICE_REQUIRED_PRIVILEGES_INFO requiredPrivilegesInfo; - - if (!NT_SUCCESS(status = PhSvcpUnpackRoot(&packedData, info, sizeof(SERVICE_REQUIRED_PRIVILEGES_INFO), &requiredPrivilegesInfo))) - goto CleanupExit; - if (!NT_SUCCESS(status = PhSvcpUnpackStringZ(&packedData, info, &requiredPrivilegesInfo->pmszRequiredPrivileges, TRUE, FALSE))) - goto CleanupExit; - - unpackedInfo = requiredPrivilegesInfo; - } - break; - case SERVICE_CONFIG_PRESHUTDOWN_INFO: - status = PhSvcpUnpackRoot(&packedData, info, sizeof(SERVICE_PRESHUTDOWN_INFO), &unpackedInfo); - break; - case SERVICE_CONFIG_TRIGGER_INFO: - { - PSERVICE_TRIGGER_INFO triggerInfo; - ULONG i; - PSERVICE_TRIGGER trigger; - ULONG j; - PSERVICE_TRIGGER_SPECIFIC_DATA_ITEM dataItem; - ULONG alignment; - - if (!NT_SUCCESS(status = PhSvcpUnpackRoot(&packedData, info, sizeof(SERVICE_TRIGGER_INFO), &triggerInfo))) - goto CleanupExit; - if (!NT_SUCCESS(status = PhSvcpUnpackBuffer(&packedData, info, &triggerInfo->pTriggers, triggerInfo->cTriggers * sizeof(SERVICE_TRIGGER), __alignof(SERVICE_TRIGGER), TRUE))) - goto CleanupExit; - - if (triggerInfo->pTriggers) - { - for (i = 0; i < triggerInfo->cTriggers; i++) - { - trigger = &triggerInfo->pTriggers[i]; - - if (!NT_SUCCESS(status = PhSvcpUnpackBuffer(&packedData, info, &trigger->pTriggerSubtype, sizeof(GUID), __alignof(GUID), TRUE))) - goto CleanupExit; - if (!NT_SUCCESS(status = PhSvcpUnpackBuffer(&packedData, info, &trigger->pDataItems, trigger->cDataItems * sizeof(SERVICE_TRIGGER_SPECIFIC_DATA_ITEM), __alignof(SERVICE_TRIGGER_SPECIFIC_DATA_ITEM), TRUE))) - goto CleanupExit; - - if (trigger->pDataItems) - { - for (j = 0; j < trigger->cDataItems; j++) - { - dataItem = &trigger->pDataItems[j]; - alignment = 1; - - switch (dataItem->dwDataType) - { - case SERVICE_TRIGGER_DATA_TYPE_BINARY: - case SERVICE_TRIGGER_DATA_TYPE_LEVEL: - alignment = sizeof(CHAR); - break; - case SERVICE_TRIGGER_DATA_TYPE_STRING: - alignment = sizeof(WCHAR); - break; - case SERVICE_TRIGGER_DATA_TYPE_KEYWORD_ANY: - case SERVICE_TRIGGER_DATA_TYPE_KEYWORD_ALL: - alignment = sizeof(ULONG64); - break; - } - - if (!NT_SUCCESS(status = PhSvcpUnpackBuffer(&packedData, info, &dataItem->pData, dataItem->cbData, alignment, FALSE))) - goto CleanupExit; - } - } - } - } - - unpackedInfo = triggerInfo; - } - break; - case SERVICE_CONFIG_LAUNCH_PROTECTED: - status = PhSvcpUnpackRoot(&packedData, info, sizeof(SERVICE_LAUNCH_PROTECTED_INFO), &unpackedInfo); - break; - default: - status = STATUS_INVALID_PARAMETER; - break; - } - - if (NT_SUCCESS(status)) - { - assert(unpackedInfo); - - if (!(serviceHandle = PhOpenService(serviceName->Buffer, desiredAccess))) - { - status = PhGetLastWin32ErrorAsNtStatus(); - goto CleanupExit; - } - - if (!ChangeServiceConfig2( - serviceHandle, - Payload->u.ChangeServiceConfig2.i.InfoLevel, - unpackedInfo - )) - { - status = PhGetLastWin32ErrorAsNtStatus(); - } - } - -CleanupExit: - if (serviceHandle) - CloseServiceHandle(serviceHandle); - if (info) - PhFree(info); - if (serviceName) - PhDereferenceObject(serviceName); - - return status; -} - -NTSTATUS PhSvcApiSetTcpEntry( - _In_ PPHSVC_CLIENT Client, - _Inout_ PPHSVC_API_PAYLOAD Payload - ) -{ - static PVOID setTcpEntry = NULL; - - ULONG (__stdcall *localSetTcpEntry)(PVOID TcpRow); - struct - { - DWORD dwState; - DWORD dwLocalAddr; - DWORD dwLocalPort; - DWORD dwRemoteAddr; - DWORD dwRemotePort; - } tcpRow; - ULONG result; - - localSetTcpEntry = setTcpEntry; - - if (!localSetTcpEntry) - { - HMODULE iphlpapiModule; - - iphlpapiModule = LoadLibrary(L"iphlpapi.dll"); - - if (iphlpapiModule) - { - localSetTcpEntry = PhGetProcedureAddress(iphlpapiModule, "SetTcpEntry", 0); - - if (localSetTcpEntry) - { - if (_InterlockedExchangePointer(&setTcpEntry, localSetTcpEntry) != NULL) - { - // Another thread got the address of SetTcpEntry already. - // Decrement the reference count of iphlpapi.dll. - FreeLibrary(iphlpapiModule); - } - } - } - } - - if (!localSetTcpEntry) - return STATUS_NOT_SUPPORTED; - - tcpRow.dwState = Payload->u.SetTcpEntry.i.State; - tcpRow.dwLocalAddr = Payload->u.SetTcpEntry.i.LocalAddress; - tcpRow.dwLocalPort = Payload->u.SetTcpEntry.i.LocalPort; - tcpRow.dwRemoteAddr = Payload->u.SetTcpEntry.i.RemoteAddress; - tcpRow.dwRemotePort = Payload->u.SetTcpEntry.i.RemotePort; - result = localSetTcpEntry(&tcpRow); - - return NTSTATUS_FROM_WIN32(result); -} - -NTSTATUS PhSvcApiControlThread( - _In_ PPHSVC_CLIENT Client, - _Inout_ PPHSVC_API_PAYLOAD Payload - ) -{ - NTSTATUS status; - HANDLE threadId; - HANDLE threadHandle; - - threadId = Payload->u.ControlThread.i.ThreadId; - - switch (Payload->u.ControlThread.i.Command) - { - case PhSvcControlThreadTerminate: - if (NT_SUCCESS(status = PhOpenThread(&threadHandle, THREAD_TERMINATE, threadId))) - { - status = NtTerminateThread(threadHandle, STATUS_SUCCESS); - NtClose(threadHandle); - } - break; - case PhSvcControlThreadSuspend: - if (NT_SUCCESS(status = PhOpenThread(&threadHandle, THREAD_SUSPEND_RESUME, threadId))) - { - status = NtSuspendThread(threadHandle, NULL); - NtClose(threadHandle); - } - break; - case PhSvcControlThreadResume: - if (NT_SUCCESS(status = PhOpenThread(&threadHandle, THREAD_SUSPEND_RESUME, threadId))) - { - status = NtResumeThread(threadHandle, NULL); - NtClose(threadHandle); - } - break; - case PhSvcControlThreadIoPriority: - if (NT_SUCCESS(status = PhOpenThread(&threadHandle, THREAD_SET_INFORMATION, threadId))) - { - status = PhSetThreadIoPriority(threadHandle, Payload->u.ControlThread.i.Argument); - NtClose(threadHandle); - } - break; - default: - status = STATUS_INVALID_PARAMETER; - break; - } - - return status; -} - -NTSTATUS PhSvcApiAddAccountRight( - _In_ PPHSVC_CLIENT Client, - _Inout_ PPHSVC_API_PAYLOAD Payload - ) -{ - NTSTATUS status; - PSID accountSid; - PPH_STRING userRight; - LSA_HANDLE policyHandle; - UNICODE_STRING userRightUs; - - if (NT_SUCCESS(status = PhSvcCaptureSid(&Payload->u.AddAccountRight.i.AccountSid, FALSE, &accountSid))) - { - if (NT_SUCCESS(status = PhSvcCaptureString(&Payload->u.AddAccountRight.i.UserRight, FALSE, &userRight))) - { - PH_AUTO(userRight); - - if (NT_SUCCESS(status = PhOpenLsaPolicy(&policyHandle, POLICY_LOOKUP_NAMES | POLICY_CREATE_ACCOUNT, NULL))) - { - PhStringRefToUnicodeString(&userRight->sr, &userRightUs); - status = LsaAddAccountRights(policyHandle, accountSid, &userRightUs, 1); - LsaClose(policyHandle); - } - } - - PhFree(accountSid); - } - - return status; -} - -NTSTATUS PhSvcApiInvokeRunAsService( - _In_ PPHSVC_CLIENT Client, - _Inout_ PPHSVC_API_PAYLOAD Payload - ) -{ - NTSTATUS status; - PH_RUNAS_SERVICE_PARAMETERS parameters; - PHSVCP_CAPTURED_RUNAS_SERVICE_PARAMETERS capturedParameters; - - if (NT_SUCCESS(status = PhSvcpCaptureRunAsServiceParameters(Client, Payload, ¶meters, &capturedParameters))) - { - if (NT_SUCCESS(status = PhSvcpValidateRunAsServiceParameters(¶meters))) - { - status = PhInvokeRunAsService(¶meters); - } - } - - PhSvcpReleaseRunAsServiceParameters(&capturedParameters); - - return status; -} - -NTSTATUS PhSvcApiIssueMemoryListCommand( - _In_ PPHSVC_CLIENT Client, - _Inout_ PPHSVC_API_PAYLOAD Payload - ) -{ - NTSTATUS status; - - status = NtSetSystemInformation( - SystemMemoryListInformation, - &Payload->u.IssueMemoryListCommand.i.Command, - sizeof(SYSTEM_MEMORY_LIST_COMMAND) - ); - - return status; -} - -NTSTATUS PhSvcApiPostMessage( - _In_ PPHSVC_CLIENT Client, - _Inout_ PPHSVC_API_PAYLOAD Payload - ) -{ - if (PostMessage( - Payload->u.PostMessage.i.hWnd, - Payload->u.PostMessage.i.Msg, - Payload->u.PostMessage.i.wParam, - Payload->u.PostMessage.i.lParam - )) - { - return STATUS_SUCCESS; - } - else - { - return PhGetLastWin32ErrorAsNtStatus(); - } -} - -NTSTATUS PhSvcApiSendMessage( - _In_ PPHSVC_CLIENT Client, - _Inout_ PPHSVC_API_PAYLOAD Payload - ) -{ - if (SendMessage( - Payload->u.PostMessage.i.hWnd, - Payload->u.PostMessage.i.Msg, - Payload->u.PostMessage.i.wParam, - Payload->u.PostMessage.i.lParam - )) - { - return STATUS_SUCCESS; - } - else - { - return PhGetLastWin32ErrorAsNtStatus(); - } -} - -NTSTATUS PhSvcApiCreateProcessIgnoreIfeoDebugger( - _In_ PPHSVC_CLIENT Client, - _Inout_ PPHSVC_API_PAYLOAD Payload - ) -{ - NTSTATUS status; - PPH_STRING fileName; - - if (NT_SUCCESS(status = PhSvcCaptureString(&Payload->u.CreateProcessIgnoreIfeoDebugger.i.FileName, FALSE, &fileName))) - { - PH_AUTO(fileName); - - if (!PhCreateProcessIgnoreIfeoDebugger(fileName->Buffer)) - status = STATUS_UNSUCCESSFUL; - } - - return status; -} - -NTSTATUS PhSvcApiSetServiceSecurity( - _In_ PPHSVC_CLIENT Client, - _Inout_ PPHSVC_API_PAYLOAD Payload - ) -{ - NTSTATUS status; - PPH_STRING serviceName; - PSECURITY_DESCRIPTOR securityDescriptor; - ACCESS_MASK desiredAccess; - SC_HANDLE serviceHandle; - - if (NT_SUCCESS(status = PhSvcCaptureString(&Payload->u.SetServiceSecurity.i.ServiceName, FALSE, &serviceName))) - { - PH_AUTO(serviceName); - - if (NT_SUCCESS(status = PhSvcCaptureSecurityDescriptor(&Payload->u.SetServiceSecurity.i.SecurityDescriptor, FALSE, 0, &securityDescriptor))) - { - desiredAccess = 0; - - if ((Payload->u.SetServiceSecurity.i.SecurityInformation & OWNER_SECURITY_INFORMATION) || - (Payload->u.SetServiceSecurity.i.SecurityInformation & GROUP_SECURITY_INFORMATION)) - { - desiredAccess |= WRITE_OWNER; - } - - if (Payload->u.SetServiceSecurity.i.SecurityInformation & DACL_SECURITY_INFORMATION) - { - desiredAccess |= WRITE_DAC; - } - - if (Payload->u.SetServiceSecurity.i.SecurityInformation & SACL_SECURITY_INFORMATION) - { - desiredAccess |= ACCESS_SYSTEM_SECURITY; - } - - if (serviceHandle = PhOpenService(serviceName->Buffer, desiredAccess)) - { - status = PhSetSeObjectSecurity( - serviceHandle, - SE_SERVICE, - Payload->u.SetServiceSecurity.i.SecurityInformation, - securityDescriptor - ); - CloseServiceHandle(serviceHandle); - } - else - { - status = PhGetLastWin32ErrorAsNtStatus(); - } - - PhFree(securityDescriptor); - } - } - - return status; -} - -NTSTATUS PhSvcApiLoadDbgHelp( - _In_ PPHSVC_CLIENT Client, - _Inout_ PPHSVC_API_PAYLOAD Payload - ) -{ - static BOOLEAN alreadyLoaded; - - NTSTATUS status; - PPH_STRING dbgHelpPath; - - if (alreadyLoaded) - return STATUS_SOME_NOT_MAPPED; - - if (NT_SUCCESS(status = PhSvcCaptureString(&Payload->u.LoadDbgHelp.i.DbgHelpPath, FALSE, &dbgHelpPath))) - { - PH_AUTO(dbgHelpPath); - PhLoadDbgHelpFromPath(dbgHelpPath->Buffer); - alreadyLoaded = TRUE; - } - - return status; -} - -NTSTATUS PhSvcApiWriteMiniDumpProcess( - _In_ PPHSVC_CLIENT Client, - _Inout_ PPHSVC_API_PAYLOAD Payload - ) -{ - if (PhWriteMiniDumpProcess( - UlongToHandle(Payload->u.WriteMiniDumpProcess.i.LocalProcessHandle), - UlongToHandle(Payload->u.WriteMiniDumpProcess.i.ProcessId), - UlongToHandle(Payload->u.WriteMiniDumpProcess.i.LocalFileHandle), - Payload->u.WriteMiniDumpProcess.i.DumpType, - NULL, - NULL, - NULL - )) - { - return STATUS_SUCCESS; - } - else - { - ULONG error; - - error = GetLastError(); - - if (error == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER)) - return STATUS_INVALID_PARAMETER; - else - return STATUS_UNSUCCESSFUL; - } -} +/* + * Process Hacker - + * server API + * + * Copyright (C) 2011-2015 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include +#include + +#include + +#include +#include +#include +#include + +#include +#include +#include + +typedef struct _PHSVCP_CAPTURED_RUNAS_SERVICE_PARAMETERS +{ + PPH_STRING UserName; + PPH_STRING Password; + PPH_STRING CurrentDirectory; + PPH_STRING CommandLine; + PPH_STRING FileName; + PPH_STRING DesktopName; + PPH_STRING ServiceName; +} PHSVCP_CAPTURED_RUNAS_SERVICE_PARAMETERS, *PPHSVCP_CAPTURED_RUNAS_SERVICE_PARAMETERS; + +PPHSVC_API_PROCEDURE PhSvcApiCallTable[] = +{ + PhSvcApiPlugin, + PhSvcApiExecuteRunAsCommand, + PhSvcApiUnloadDriver, + PhSvcApiControlProcess, + PhSvcApiControlService, + PhSvcApiCreateService, + PhSvcApiChangeServiceConfig, + PhSvcApiChangeServiceConfig2, + PhSvcApiSetTcpEntry, + PhSvcApiControlThread, + PhSvcApiAddAccountRight, + PhSvcApiInvokeRunAsService, + PhSvcApiIssueMemoryListCommand, + PhSvcApiPostMessage, + PhSvcApiSendMessage, + PhSvcApiCreateProcessIgnoreIfeoDebugger, + PhSvcApiSetServiceSecurity, + PhSvcApiLoadDbgHelp, + PhSvcApiWriteMiniDumpProcess +}; +C_ASSERT(sizeof(PhSvcApiCallTable) / sizeof(PPHSVC_API_PROCEDURE) == PhSvcMaximumApiNumber - 1); + +NTSTATUS PhSvcApiInitialization( + VOID + ) +{ + return STATUS_SUCCESS; +} + +VOID PhSvcDispatchApiCall( + _In_ PPHSVC_CLIENT Client, + _Inout_ PPHSVC_API_PAYLOAD Payload, + _Out_ PHANDLE ReplyPortHandle + ) +{ + NTSTATUS status; + + if ( + Payload->ApiNumber == 0 || + (ULONG)Payload->ApiNumber >= (ULONG)PhSvcMaximumApiNumber || + !PhSvcApiCallTable[Payload->ApiNumber - 1] + ) + { + Payload->ReturnStatus = STATUS_INVALID_SYSTEM_SERVICE; + *ReplyPortHandle = Client->PortHandle; + return; + } + + status = PhSvcApiCallTable[Payload->ApiNumber - 1](Client, Payload); + Payload->ReturnStatus = status; + + *ReplyPortHandle = Client->PortHandle; +} + +PVOID PhSvcValidateString( + _In_ PPH_RELATIVE_STRINGREF String, + _In_ ULONG Alignment + ) +{ + PPHSVC_CLIENT client = PhSvcGetCurrentClient(); + PVOID address; + + address = (PCHAR)client->ClientViewBase + String->Offset; + + if ((ULONG_PTR)address + String->Length < (ULONG_PTR)address || + (ULONG_PTR)address < (ULONG_PTR)client->ClientViewBase || + (ULONG_PTR)address + String->Length > (ULONG_PTR)client->ClientViewLimit) + { + return NULL; + } + + if ((ULONG_PTR)address & (Alignment - 1)) + { + return NULL; + } + + return address; +} + +NTSTATUS PhSvcProbeBuffer( + _In_ PPH_RELATIVE_STRINGREF String, + _In_ ULONG Alignment, + _In_ BOOLEAN AllowNull, + _Out_ PVOID *Pointer + ) +{ + PVOID address; + + if (String->Offset != 0) + { + address = PhSvcValidateString(String, Alignment); + + if (!address) + return STATUS_ACCESS_VIOLATION; + + *Pointer = address; + } + else + { + if (!AllowNull) + return STATUS_ACCESS_VIOLATION; + + *Pointer = NULL; + } + + return STATUS_SUCCESS; +} + +NTSTATUS PhSvcCaptureBuffer( + _In_ PPH_RELATIVE_STRINGREF String, + _In_ BOOLEAN AllowNull, + _Out_ PVOID *CapturedBuffer + ) +{ + PVOID address; + PVOID buffer; + + if (String->Offset != 0) + { + address = PhSvcValidateString(String, 1); + + if (!address) + return STATUS_ACCESS_VIOLATION; + + buffer = PhAllocateSafe(String->Length); + + if (!buffer) + return STATUS_NO_MEMORY; + + memcpy(buffer, address, String->Length); + *CapturedBuffer = buffer; + } + else + { + if (!AllowNull) + return STATUS_ACCESS_VIOLATION; + + *CapturedBuffer = NULL; + } + + return STATUS_SUCCESS; +} + +NTSTATUS PhSvcCaptureString( + _In_ PPH_RELATIVE_STRINGREF String, + _In_ BOOLEAN AllowNull, + _Out_ PPH_STRING *CapturedString + ) +{ + PVOID address; + + if (String->Length & 1) + return STATUS_INVALID_BUFFER_SIZE; + if (String->Length > 0xfffe) + return STATUS_INVALID_BUFFER_SIZE; + + if (String->Offset != 0) + { + address = PhSvcValidateString(String, sizeof(WCHAR)); + + if (!address) + return STATUS_ACCESS_VIOLATION; + + if (String->Length != 0) + *CapturedString = PhCreateStringEx(address, String->Length); + else + *CapturedString = PhReferenceEmptyString(); + } + else + { + if (!AllowNull) + return STATUS_ACCESS_VIOLATION; + + *CapturedString = NULL; + } + + return STATUS_SUCCESS; +} + +NTSTATUS PhSvcCaptureSid( + _In_ PPH_RELATIVE_STRINGREF String, + _In_ BOOLEAN AllowNull, + _Out_ PSID *CapturedSid + ) +{ + NTSTATUS status; + PSID sid; + + if (!NT_SUCCESS(status = PhSvcCaptureBuffer(String, AllowNull, &sid))) + return status; + + if (sid) + { + if (String->Length < (ULONG)FIELD_OFFSET(struct _SID, IdentifierAuthority) || + String->Length < RtlLengthRequiredSid(((struct _SID *)sid)->SubAuthorityCount) || + !RtlValidSid(sid)) + { + PhFree(sid); + return STATUS_INVALID_SID; + } + + *CapturedSid = sid; + } + else + { + *CapturedSid = NULL; + } + + return STATUS_SUCCESS; +} + +NTSTATUS PhSvcCaptureSecurityDescriptor( + _In_ PPH_RELATIVE_STRINGREF String, + _In_ BOOLEAN AllowNull, + _In_ SECURITY_INFORMATION RequiredInformation, + _Out_ PSECURITY_DESCRIPTOR *CapturedSecurityDescriptor + ) +{ + NTSTATUS status; + PSECURITY_DESCRIPTOR securityDescriptor; + ULONG bufferSize; + + if (!NT_SUCCESS(status = PhSvcCaptureBuffer(String, AllowNull, &securityDescriptor))) + return status; + + if (securityDescriptor) + { + if (!RtlValidRelativeSecurityDescriptor(securityDescriptor, String->Length, RequiredInformation)) + { + PhFree(securityDescriptor); + return STATUS_INVALID_SECURITY_DESCR; + } + + bufferSize = String->Length; + status = RtlSelfRelativeToAbsoluteSD2(securityDescriptor, &bufferSize); + + if (status == STATUS_BUFFER_TOO_SMALL) + { + PVOID newBuffer; + + newBuffer = PhAllocate(bufferSize); + memcpy(newBuffer, securityDescriptor, String->Length); + PhFree(securityDescriptor); + securityDescriptor = newBuffer; + + status = RtlSelfRelativeToAbsoluteSD2(securityDescriptor, &bufferSize); + } + + if (!NT_SUCCESS(status)) + { + PhFree(securityDescriptor); + return status; + } + + *CapturedSecurityDescriptor = securityDescriptor; + } + else + { + *CapturedSecurityDescriptor = NULL; + } + + return STATUS_SUCCESS; +} + +NTSTATUS PhSvcApiDefault( + _In_ PPHSVC_CLIENT Client, + _Inout_ PPHSVC_API_PAYLOAD Payload + ) +{ + return STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS PhSvcApiPlugin( + _In_ PPHSVC_CLIENT Client, + _Inout_ PPHSVC_API_PAYLOAD Payload + ) +{ + NTSTATUS status; + PPH_STRING apiId; + PPH_PLUGIN plugin; + PH_STRINGREF pluginName; + PH_PLUGIN_PHSVC_REQUEST request; + + if (NT_SUCCESS(status = PhSvcCaptureString(&Payload->u.Plugin.i.ApiId, FALSE, &apiId))) + { + PH_AUTO(apiId); + + if (PhPluginsEnabled && + PhEmParseCompoundId(&apiId->sr, &pluginName, &request.SubId) && + (plugin = PhFindPlugin2(&pluginName))) + { + request.ReturnStatus = STATUS_NOT_IMPLEMENTED; + request.InBuffer = Payload->u.Plugin.i.Data; + request.InLength = sizeof(Payload->u.Plugin.i.Data); + request.OutBuffer = Payload->u.Plugin.o.Data; + request.OutLength = sizeof(Payload->u.Plugin.o.Data); + + request.ProbeBuffer = PhSvcProbeBuffer; + request.CaptureBuffer = PhSvcCaptureBuffer; + request.CaptureString = PhSvcCaptureString; + + PhInvokeCallback(PhGetPluginCallback(plugin, PluginCallbackPhSvcRequest), &request); + status = request.ReturnStatus; + } + else + { + status = STATUS_NOT_FOUND; + } + } + + return status; +} + +NTSTATUS PhSvcpCaptureRunAsServiceParameters( + _In_ PPHSVC_CLIENT Client, + _Inout_ PPHSVC_API_PAYLOAD Payload, + _Out_ PPH_RUNAS_SERVICE_PARAMETERS Parameters, + _Out_ PPHSVCP_CAPTURED_RUNAS_SERVICE_PARAMETERS CapturedParameters + ) +{ + NTSTATUS status; + + memset(CapturedParameters, 0, sizeof(PHSVCP_CAPTURED_RUNAS_SERVICE_PARAMETERS)); + + if (!NT_SUCCESS(status = PhSvcCaptureString(&Payload->u.ExecuteRunAsCommand.i.UserName, TRUE, &CapturedParameters->UserName))) + return status; + if (!NT_SUCCESS(status = PhSvcCaptureString(&Payload->u.ExecuteRunAsCommand.i.Password, TRUE, &CapturedParameters->Password))) + return status; + if (!NT_SUCCESS(status = PhSvcCaptureString(&Payload->u.ExecuteRunAsCommand.i.CurrentDirectory, TRUE, &CapturedParameters->CurrentDirectory))) + return status; + if (!NT_SUCCESS(status = PhSvcCaptureString(&Payload->u.ExecuteRunAsCommand.i.CommandLine, TRUE, &CapturedParameters->CommandLine))) + return status; + if (!NT_SUCCESS(status = PhSvcCaptureString(&Payload->u.ExecuteRunAsCommand.i.FileName, TRUE, &CapturedParameters->FileName))) + return status; + if (!NT_SUCCESS(status = PhSvcCaptureString(&Payload->u.ExecuteRunAsCommand.i.DesktopName, TRUE, &CapturedParameters->DesktopName))) + return status; + if (!NT_SUCCESS(status = PhSvcCaptureString(&Payload->u.ExecuteRunAsCommand.i.ServiceName, TRUE, &CapturedParameters->ServiceName))) + return status; + + Parameters->ProcessId = Payload->u.ExecuteRunAsCommand.i.ProcessId; + Parameters->UserName = PhGetString(CapturedParameters->UserName); + Parameters->Password = PhGetString(CapturedParameters->Password); + Parameters->LogonType = Payload->u.ExecuteRunAsCommand.i.LogonType; + Parameters->SessionId = Payload->u.ExecuteRunAsCommand.i.SessionId; + Parameters->CurrentDirectory = PhGetString(CapturedParameters->CurrentDirectory); + Parameters->CommandLine = PhGetString(CapturedParameters->CommandLine); + Parameters->FileName = PhGetString(CapturedParameters->FileName); + Parameters->DesktopName = PhGetString(CapturedParameters->DesktopName); + Parameters->UseLinkedToken = Payload->u.ExecuteRunAsCommand.i.UseLinkedToken; + Parameters->ServiceName = PhGetString(CapturedParameters->ServiceName); + + return status; +} + +VOID PhSvcpReleaseRunAsServiceParameters( + _In_ PPHSVCP_CAPTURED_RUNAS_SERVICE_PARAMETERS CapturedParameters + ) +{ + if (CapturedParameters->UserName) + PhDereferenceObject(CapturedParameters->UserName); + + if (CapturedParameters->Password) + { + RtlSecureZeroMemory(CapturedParameters->Password->Buffer, CapturedParameters->Password->Length); + PhDereferenceObject(CapturedParameters->Password); + } + + if (CapturedParameters->CurrentDirectory) + PhDereferenceObject(CapturedParameters->CurrentDirectory); + if (CapturedParameters->CommandLine) + PhDereferenceObject(CapturedParameters->CommandLine); + if (CapturedParameters->FileName) + PhDereferenceObject(CapturedParameters->FileName); + if (CapturedParameters->DesktopName) + PhDereferenceObject(CapturedParameters->DesktopName); + if (CapturedParameters->ServiceName) + PhDereferenceObject(CapturedParameters->ServiceName); +} + +NTSTATUS PhSvcpValidateRunAsServiceParameters( + _In_ PPH_RUNAS_SERVICE_PARAMETERS Parameters + ) +{ + if ((!Parameters->UserName || !Parameters->Password) && !Parameters->ProcessId) + return STATUS_INVALID_PARAMETER_MIX; + if (!Parameters->FileName && !Parameters->CommandLine) + return STATUS_INVALID_PARAMETER_MIX; + if (!Parameters->ServiceName) + return STATUS_INVALID_PARAMETER; + + return STATUS_SUCCESS; +} + +NTSTATUS PhSvcApiExecuteRunAsCommand( + _In_ PPHSVC_CLIENT Client, + _Inout_ PPHSVC_API_PAYLOAD Payload + ) +{ + NTSTATUS status; + PH_RUNAS_SERVICE_PARAMETERS parameters; + PHSVCP_CAPTURED_RUNAS_SERVICE_PARAMETERS capturedParameters; + + if (NT_SUCCESS(status = PhSvcpCaptureRunAsServiceParameters(Client, Payload, ¶meters, &capturedParameters))) + { + if (NT_SUCCESS(status = PhSvcpValidateRunAsServiceParameters(¶meters))) + { + status = PhExecuteRunAsCommand(¶meters); + } + } + + PhSvcpReleaseRunAsServiceParameters(&capturedParameters); + + return status; +} + +NTSTATUS PhSvcApiUnloadDriver( + _In_ PPHSVC_CLIENT Client, + _Inout_ PPHSVC_API_PAYLOAD Payload + ) +{ + NTSTATUS status; + PPH_STRING name; + + if (NT_SUCCESS(status = PhSvcCaptureString(&Payload->u.UnloadDriver.i.Name, TRUE, &name))) + { + status = PhUnloadDriver(Payload->u.UnloadDriver.i.BaseAddress, PhGetString(name)); + PhClearReference(&name); + } + + return status; +} + +NTSTATUS PhSvcApiControlProcess( + _In_ PPHSVC_CLIENT Client, + _Inout_ PPHSVC_API_PAYLOAD Payload + ) +{ + NTSTATUS status; + HANDLE processId; + HANDLE processHandle; + + processId = Payload->u.ControlProcess.i.ProcessId; + + switch (Payload->u.ControlProcess.i.Command) + { + case PhSvcControlProcessTerminate: + if (NT_SUCCESS(status = PhOpenProcess(&processHandle, PROCESS_TERMINATE, processId))) + { + status = PhTerminateProcess(processHandle, 1); // see notes in PhUiTerminateProcesses + NtClose(processHandle); + } + break; + case PhSvcControlProcessSuspend: + if (NT_SUCCESS(status = PhOpenProcess(&processHandle, PROCESS_SUSPEND_RESUME, processId))) + { + status = NtSuspendProcess(processHandle); + NtClose(processHandle); + } + break; + case PhSvcControlProcessResume: + if (NT_SUCCESS(status = PhOpenProcess(&processHandle, PROCESS_SUSPEND_RESUME, processId))) + { + status = NtResumeProcess(processHandle); + NtClose(processHandle); + } + break; + case PhSvcControlProcessPriority: + if (processId != SYSTEM_PROCESS_ID) + { + if (NT_SUCCESS(status = PhOpenProcess(&processHandle, PROCESS_SET_INFORMATION, processId))) + { + PROCESS_PRIORITY_CLASS priorityClass; + + priorityClass.Foreground = FALSE; + priorityClass.PriorityClass = (UCHAR)Payload->u.ControlProcess.i.Argument; + status = NtSetInformationProcess(processHandle, ProcessPriorityClass, &priorityClass, sizeof(PROCESS_PRIORITY_CLASS)); + + NtClose(processHandle); + } + } + else + { + status = STATUS_UNSUCCESSFUL; + } + break; + case PhSvcControlProcessIoPriority: + if (processId != SYSTEM_PROCESS_ID) + { + if (NT_SUCCESS(status = PhOpenProcess(&processHandle, PROCESS_SET_INFORMATION, processId))) + { + status = PhSetProcessIoPriority(processHandle, Payload->u.ControlProcess.i.Argument); + NtClose(processHandle); + } + } + else + { + status = STATUS_UNSUCCESSFUL; + } + break; + default: + status = STATUS_INVALID_PARAMETER; + break; + } + + return status; +} + +NTSTATUS PhSvcApiControlService( + _In_ PPHSVC_CLIENT Client, + _Inout_ PPHSVC_API_PAYLOAD Payload + ) +{ + NTSTATUS status; + PPH_STRING serviceName; + SC_HANDLE serviceHandle; + SERVICE_STATUS serviceStatus; + + if (NT_SUCCESS(status = PhSvcCaptureString(&Payload->u.ControlService.i.ServiceName, FALSE, &serviceName))) + { + PH_AUTO(serviceName); + + switch (Payload->u.ControlService.i.Command) + { + case PhSvcControlServiceStart: + if (serviceHandle = PhOpenService( + serviceName->Buffer, + SERVICE_START + )) + { + if (!StartService(serviceHandle, 0, NULL)) + status = PhGetLastWin32ErrorAsNtStatus(); + + CloseServiceHandle(serviceHandle); + } + else + { + status = PhGetLastWin32ErrorAsNtStatus(); + } + break; + case PhSvcControlServiceContinue: + if (serviceHandle = PhOpenService( + serviceName->Buffer, + SERVICE_PAUSE_CONTINUE + )) + { + if (!ControlService(serviceHandle, SERVICE_CONTROL_CONTINUE, &serviceStatus)) + status = PhGetLastWin32ErrorAsNtStatus(); + + CloseServiceHandle(serviceHandle); + } + else + { + status = PhGetLastWin32ErrorAsNtStatus(); + } + break; + case PhSvcControlServicePause: + if (serviceHandle = PhOpenService( + serviceName->Buffer, + SERVICE_PAUSE_CONTINUE + )) + { + if (!ControlService(serviceHandle, SERVICE_CONTROL_PAUSE, &serviceStatus)) + status = PhGetLastWin32ErrorAsNtStatus(); + + CloseServiceHandle(serviceHandle); + } + else + { + status = PhGetLastWin32ErrorAsNtStatus(); + } + break; + case PhSvcControlServiceStop: + if (serviceHandle = PhOpenService( + serviceName->Buffer, + SERVICE_STOP + )) + { + if (!ControlService(serviceHandle, SERVICE_CONTROL_STOP, &serviceStatus)) + status = PhGetLastWin32ErrorAsNtStatus(); + + CloseServiceHandle(serviceHandle); + } + else + { + status = PhGetLastWin32ErrorAsNtStatus(); + } + break; + case PhSvcControlServiceDelete: + if (serviceHandle = PhOpenService( + serviceName->Buffer, + DELETE + )) + { + if (!DeleteService(serviceHandle)) + status = PhGetLastWin32ErrorAsNtStatus(); + + CloseServiceHandle(serviceHandle); + } + else + { + status = PhGetLastWin32ErrorAsNtStatus(); + } + break; + default: + status = STATUS_INVALID_PARAMETER; + break; + } + } + + return status; +} + +NTSTATUS PhSvcApiCreateService( + _In_ PPHSVC_CLIENT Client, + _Inout_ PPHSVC_API_PAYLOAD Payload + ) +{ + NTSTATUS status; + PPH_STRING serviceName = NULL; + PPH_STRING displayName = NULL; + PPH_STRING binaryPathName = NULL; + PPH_STRING loadOrderGroup = NULL; + PPH_STRING dependencies = NULL; + PPH_STRING serviceStartName = NULL; + PPH_STRING password = NULL; + ULONG tagId = 0; + SC_HANDLE scManagerHandle; + SC_HANDLE serviceHandle; + + if (!NT_SUCCESS(status = PhSvcCaptureString(&Payload->u.CreateService.i.ServiceName, FALSE, &serviceName))) + goto CleanupExit; + if (!NT_SUCCESS(status = PhSvcCaptureString(&Payload->u.CreateService.i.DisplayName, TRUE, &displayName))) + goto CleanupExit; + if (!NT_SUCCESS(status = PhSvcCaptureString(&Payload->u.CreateService.i.BinaryPathName, TRUE, &binaryPathName))) + goto CleanupExit; + if (!NT_SUCCESS(status = PhSvcCaptureString(&Payload->u.CreateService.i.LoadOrderGroup, TRUE, &loadOrderGroup))) + goto CleanupExit; + if (!NT_SUCCESS(status = PhSvcCaptureString(&Payload->u.CreateService.i.Dependencies, TRUE, &dependencies))) + goto CleanupExit; + if (!NT_SUCCESS(status = PhSvcCaptureString(&Payload->u.CreateService.i.ServiceStartName, TRUE, &serviceStartName))) + goto CleanupExit; + if (!NT_SUCCESS(status = PhSvcCaptureString(&Payload->u.CreateService.i.Password, TRUE, &password))) + goto CleanupExit; + + if (scManagerHandle = OpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE)) + { + if (serviceHandle = CreateService( + scManagerHandle, + serviceName->Buffer, + PhGetString(displayName), + SERVICE_CHANGE_CONFIG, + Payload->u.CreateService.i.ServiceType, + Payload->u.CreateService.i.StartType, + Payload->u.CreateService.i.ErrorControl, + PhGetString(binaryPathName), + PhGetString(loadOrderGroup), + Payload->u.CreateService.i.TagIdSpecified ? &tagId : NULL, + PhGetString(dependencies), + PhGetString(serviceStartName), + PhGetString(password) + )) + { + Payload->u.CreateService.o.TagId = tagId; + CloseServiceHandle(serviceHandle); + } + else + { + status = PhGetLastWin32ErrorAsNtStatus(); + } + + CloseServiceHandle(scManagerHandle); + } + else + { + status = PhGetLastWin32ErrorAsNtStatus(); + } + +CleanupExit: + if (password) + { + RtlSecureZeroMemory(password->Buffer, password->Length); + PhDereferenceObject(password); + } + + PhClearReference(&serviceStartName); + PhClearReference(&dependencies); + PhClearReference(&loadOrderGroup); + PhClearReference(&binaryPathName); + PhClearReference(&displayName); + PhClearReference(&serviceName); + + return status; +} + +NTSTATUS PhSvcApiChangeServiceConfig( + _In_ PPHSVC_CLIENT Client, + _Inout_ PPHSVC_API_PAYLOAD Payload + ) +{ + NTSTATUS status; + PPH_STRING serviceName = NULL; + PPH_STRING binaryPathName = NULL; + PPH_STRING loadOrderGroup = NULL; + PPH_STRING dependencies = NULL; + PPH_STRING serviceStartName = NULL; + PPH_STRING password = NULL; + PPH_STRING displayName = NULL; + ULONG tagId = 0; + SC_HANDLE serviceHandle; + + if (!NT_SUCCESS(status = PhSvcCaptureString(&Payload->u.ChangeServiceConfig.i.ServiceName, FALSE, &serviceName))) + goto CleanupExit; + if (!NT_SUCCESS(status = PhSvcCaptureString(&Payload->u.ChangeServiceConfig.i.BinaryPathName, TRUE, &binaryPathName))) + goto CleanupExit; + if (!NT_SUCCESS(status = PhSvcCaptureString(&Payload->u.ChangeServiceConfig.i.LoadOrderGroup, TRUE, &loadOrderGroup))) + goto CleanupExit; + if (!NT_SUCCESS(status = PhSvcCaptureString(&Payload->u.ChangeServiceConfig.i.Dependencies, TRUE, &dependencies))) + goto CleanupExit; + if (!NT_SUCCESS(status = PhSvcCaptureString(&Payload->u.ChangeServiceConfig.i.ServiceStartName, TRUE, &serviceStartName))) + goto CleanupExit; + if (!NT_SUCCESS(status = PhSvcCaptureString(&Payload->u.ChangeServiceConfig.i.Password, TRUE, &password))) + goto CleanupExit; + if (!NT_SUCCESS(status = PhSvcCaptureString(&Payload->u.ChangeServiceConfig.i.DisplayName, TRUE, &displayName))) + goto CleanupExit; + + if (serviceHandle = PhOpenService(serviceName->Buffer, SERVICE_CHANGE_CONFIG)) + { + if (ChangeServiceConfig( + serviceHandle, + Payload->u.ChangeServiceConfig.i.ServiceType, + Payload->u.ChangeServiceConfig.i.StartType, + Payload->u.ChangeServiceConfig.i.ErrorControl, + PhGetString(binaryPathName), + PhGetString(loadOrderGroup), + Payload->u.ChangeServiceConfig.i.TagIdSpecified ? &tagId : NULL, + PhGetString(dependencies), + PhGetString(serviceStartName), + PhGetString(password), + PhGetString(displayName) + )) + { + Payload->u.ChangeServiceConfig.o.TagId = tagId; + } + else + { + status = PhGetLastWin32ErrorAsNtStatus(); + } + + CloseServiceHandle(serviceHandle); + } + else + { + status = PhGetLastWin32ErrorAsNtStatus(); + } + +CleanupExit: + PhClearReference(&displayName); + + if (password) + { + RtlSecureZeroMemory(password->Buffer, password->Length); + PhDereferenceObject(password); + } + + PhClearReference(&serviceStartName); + PhClearReference(&dependencies); + PhClearReference(&loadOrderGroup); + PhClearReference(&binaryPathName); + PhClearReference(&serviceName); + + return status; +} + +NTSTATUS PhSvcpUnpackRoot( + _In_ PPH_RELATIVE_STRINGREF PackedData, + _In_ PVOID CapturedBuffer, + _In_ SIZE_T Length, + _Out_ PVOID *ValidatedBuffer + ) +{ + if (Length > PackedData->Length) + return STATUS_ACCESS_VIOLATION; + + *ValidatedBuffer = CapturedBuffer; + + return STATUS_SUCCESS; +} + +NTSTATUS PhSvcpUnpackBuffer( + _In_ PPH_RELATIVE_STRINGREF PackedData, + _In_ PVOID CapturedBuffer, + _In_ PVOID *OffsetInBuffer, + _In_ SIZE_T Length, + _In_ ULONG Alignment, + _In_ BOOLEAN AllowNull + ) +{ + SIZE_T offset; + + offset = (SIZE_T)*OffsetInBuffer; + + if (offset == 0) + { + if (AllowNull) + return STATUS_SUCCESS; + else + return STATUS_ACCESS_VIOLATION; + } + + if (offset + Length < offset) + return STATUS_ACCESS_VIOLATION; + if (offset + Length > PackedData->Length) + return STATUS_ACCESS_VIOLATION; + if (offset & (Alignment - 1)) + return STATUS_DATATYPE_MISALIGNMENT; + + *OffsetInBuffer = (PVOID)((ULONG_PTR)CapturedBuffer + offset); + + return STATUS_SUCCESS; +} + +NTSTATUS PhSvcpUnpackStringZ( + _In_ PPH_RELATIVE_STRINGREF PackedData, + _In_ PVOID CapturedBuffer, + _In_ PVOID *OffsetInBuffer, + _In_ BOOLEAN Multi, + _In_ BOOLEAN AllowNull + ) +{ + SIZE_T offset; + PWCHAR start; + PWCHAR end; + PH_STRINGREF remainingPart; + PH_STRINGREF firstPart; + + offset = (SIZE_T)*OffsetInBuffer; + + if (offset == 0) + { + if (AllowNull) + return STATUS_SUCCESS; + else + return STATUS_ACCESS_VIOLATION; + } + + if (offset >= PackedData->Length) + return STATUS_ACCESS_VIOLATION; + if (offset & 1) + return STATUS_DATATYPE_MISALIGNMENT; + + start = (PWCHAR)((ULONG_PTR)CapturedBuffer + offset); + end = (PWCHAR)((ULONG_PTR)CapturedBuffer + (PackedData->Length & -2)); + remainingPart.Buffer = start; + remainingPart.Length = (end - start) * sizeof(WCHAR); + + if (Multi) + { + SIZE_T validatedLength = 0; + + while (PhSplitStringRefAtChar(&remainingPart, 0, &firstPart, &remainingPart)) + { + validatedLength += firstPart.Length + sizeof(WCHAR); + + if (firstPart.Length == 0) + { + *OffsetInBuffer = start; + + return STATUS_SUCCESS; + } + } + } + else + { + if (PhSplitStringRefAtChar(&remainingPart, 0, &firstPart, &remainingPart)) + { + *OffsetInBuffer = start; + + return STATUS_SUCCESS; + } + } + + return STATUS_ACCESS_VIOLATION; +} + +NTSTATUS PhSvcApiChangeServiceConfig2( + _In_ PPHSVC_CLIENT Client, + _Inout_ PPHSVC_API_PAYLOAD Payload + ) +{ + NTSTATUS status; + PPH_STRING serviceName = NULL; + PVOID info = NULL; + SC_HANDLE serviceHandle = NULL; + PH_RELATIVE_STRINGREF packedData; + PVOID unpackedInfo = NULL; + ACCESS_MASK desiredAccess = SERVICE_CHANGE_CONFIG; + + if (!NT_SUCCESS(status = PhSvcCaptureString(&Payload->u.ChangeServiceConfig2.i.ServiceName, FALSE, &serviceName))) + goto CleanupExit; + if (!NT_SUCCESS(status = PhSvcCaptureBuffer(&Payload->u.ChangeServiceConfig2.i.Info, FALSE, &info))) + goto CleanupExit; + + packedData = Payload->u.ChangeServiceConfig2.i.Info; + + switch (Payload->u.ChangeServiceConfig2.i.InfoLevel) + { + case SERVICE_CONFIG_FAILURE_ACTIONS: + { + LPSERVICE_FAILURE_ACTIONS failureActions; + + if (!NT_SUCCESS(status = PhSvcpUnpackRoot(&packedData, info, sizeof(SERVICE_FAILURE_ACTIONS), &failureActions))) + goto CleanupExit; + if (!NT_SUCCESS(status = PhSvcpUnpackStringZ(&packedData, info, &failureActions->lpRebootMsg, FALSE, TRUE))) + goto CleanupExit; + if (!NT_SUCCESS(status = PhSvcpUnpackStringZ(&packedData, info, &failureActions->lpCommand, FALSE, TRUE))) + goto CleanupExit; + if (!NT_SUCCESS(status = PhSvcpUnpackBuffer(&packedData, info, &failureActions->lpsaActions, failureActions->cActions * sizeof(SC_ACTION), __alignof(SC_ACTION), TRUE))) + goto CleanupExit; + + if (failureActions->lpsaActions) + { + ULONG i; + + for (i = 0; i < failureActions->cActions; i++) + { + if (failureActions->lpsaActions[i].Type == SC_ACTION_RESTART) + { + desiredAccess |= SERVICE_START; + break; + } + } + } + + unpackedInfo = failureActions; + } + break; + case SERVICE_CONFIG_DELAYED_AUTO_START_INFO: + status = PhSvcpUnpackRoot(&packedData, info, sizeof(SERVICE_DELAYED_AUTO_START_INFO), &unpackedInfo); + break; + case SERVICE_CONFIG_FAILURE_ACTIONS_FLAG: + status = PhSvcpUnpackRoot(&packedData, info, sizeof(SERVICE_FAILURE_ACTIONS_FLAG), &unpackedInfo); + break; + case SERVICE_CONFIG_SERVICE_SID_INFO: + status = PhSvcpUnpackRoot(&packedData, info, sizeof(SERVICE_SID_INFO), &unpackedInfo); + break; + case SERVICE_CONFIG_REQUIRED_PRIVILEGES_INFO: + { + LPSERVICE_REQUIRED_PRIVILEGES_INFO requiredPrivilegesInfo; + + if (!NT_SUCCESS(status = PhSvcpUnpackRoot(&packedData, info, sizeof(SERVICE_REQUIRED_PRIVILEGES_INFO), &requiredPrivilegesInfo))) + goto CleanupExit; + if (!NT_SUCCESS(status = PhSvcpUnpackStringZ(&packedData, info, &requiredPrivilegesInfo->pmszRequiredPrivileges, TRUE, FALSE))) + goto CleanupExit; + + unpackedInfo = requiredPrivilegesInfo; + } + break; + case SERVICE_CONFIG_PRESHUTDOWN_INFO: + status = PhSvcpUnpackRoot(&packedData, info, sizeof(SERVICE_PRESHUTDOWN_INFO), &unpackedInfo); + break; + case SERVICE_CONFIG_TRIGGER_INFO: + { + PSERVICE_TRIGGER_INFO triggerInfo; + ULONG i; + PSERVICE_TRIGGER trigger; + ULONG j; + PSERVICE_TRIGGER_SPECIFIC_DATA_ITEM dataItem; + ULONG alignment; + + if (!NT_SUCCESS(status = PhSvcpUnpackRoot(&packedData, info, sizeof(SERVICE_TRIGGER_INFO), &triggerInfo))) + goto CleanupExit; + if (!NT_SUCCESS(status = PhSvcpUnpackBuffer(&packedData, info, &triggerInfo->pTriggers, triggerInfo->cTriggers * sizeof(SERVICE_TRIGGER), __alignof(SERVICE_TRIGGER), TRUE))) + goto CleanupExit; + + if (triggerInfo->pTriggers) + { + for (i = 0; i < triggerInfo->cTriggers; i++) + { + trigger = &triggerInfo->pTriggers[i]; + + if (!NT_SUCCESS(status = PhSvcpUnpackBuffer(&packedData, info, &trigger->pTriggerSubtype, sizeof(GUID), __alignof(GUID), TRUE))) + goto CleanupExit; + if (!NT_SUCCESS(status = PhSvcpUnpackBuffer(&packedData, info, &trigger->pDataItems, trigger->cDataItems * sizeof(SERVICE_TRIGGER_SPECIFIC_DATA_ITEM), __alignof(SERVICE_TRIGGER_SPECIFIC_DATA_ITEM), TRUE))) + goto CleanupExit; + + if (trigger->pDataItems) + { + for (j = 0; j < trigger->cDataItems; j++) + { + dataItem = &trigger->pDataItems[j]; + alignment = 1; + + switch (dataItem->dwDataType) + { + case SERVICE_TRIGGER_DATA_TYPE_BINARY: + case SERVICE_TRIGGER_DATA_TYPE_LEVEL: + alignment = sizeof(CHAR); + break; + case SERVICE_TRIGGER_DATA_TYPE_STRING: + alignment = sizeof(WCHAR); + break; + case SERVICE_TRIGGER_DATA_TYPE_KEYWORD_ANY: + case SERVICE_TRIGGER_DATA_TYPE_KEYWORD_ALL: + alignment = sizeof(ULONG64); + break; + } + + if (!NT_SUCCESS(status = PhSvcpUnpackBuffer(&packedData, info, &dataItem->pData, dataItem->cbData, alignment, FALSE))) + goto CleanupExit; + } + } + } + } + + unpackedInfo = triggerInfo; + } + break; + case SERVICE_CONFIG_LAUNCH_PROTECTED: + status = PhSvcpUnpackRoot(&packedData, info, sizeof(SERVICE_LAUNCH_PROTECTED_INFO), &unpackedInfo); + break; + default: + status = STATUS_INVALID_PARAMETER; + break; + } + + if (NT_SUCCESS(status)) + { + assert(unpackedInfo); + + if (!(serviceHandle = PhOpenService(serviceName->Buffer, desiredAccess))) + { + status = PhGetLastWin32ErrorAsNtStatus(); + goto CleanupExit; + } + + if (!ChangeServiceConfig2( + serviceHandle, + Payload->u.ChangeServiceConfig2.i.InfoLevel, + unpackedInfo + )) + { + status = PhGetLastWin32ErrorAsNtStatus(); + } + } + +CleanupExit: + if (serviceHandle) + CloseServiceHandle(serviceHandle); + if (info) + PhFree(info); + if (serviceName) + PhDereferenceObject(serviceName); + + return status; +} + +NTSTATUS PhSvcApiSetTcpEntry( + _In_ PPHSVC_CLIENT Client, + _Inout_ PPHSVC_API_PAYLOAD Payload + ) +{ + static PVOID setTcpEntry = NULL; + + ULONG (__stdcall *localSetTcpEntry)(PVOID TcpRow); + struct + { + DWORD dwState; + DWORD dwLocalAddr; + DWORD dwLocalPort; + DWORD dwRemoteAddr; + DWORD dwRemotePort; + } tcpRow; + ULONG result; + + localSetTcpEntry = setTcpEntry; + + if (!localSetTcpEntry) + { + HMODULE iphlpapiModule; + + iphlpapiModule = LoadLibrary(L"iphlpapi.dll"); + + if (iphlpapiModule) + { + localSetTcpEntry = PhGetProcedureAddress(iphlpapiModule, "SetTcpEntry", 0); + + if (localSetTcpEntry) + { + if (_InterlockedExchangePointer(&setTcpEntry, localSetTcpEntry) != NULL) + { + // Another thread got the address of SetTcpEntry already. + // Decrement the reference count of iphlpapi.dll. + FreeLibrary(iphlpapiModule); + } + } + } + } + + if (!localSetTcpEntry) + return STATUS_NOT_SUPPORTED; + + tcpRow.dwState = Payload->u.SetTcpEntry.i.State; + tcpRow.dwLocalAddr = Payload->u.SetTcpEntry.i.LocalAddress; + tcpRow.dwLocalPort = Payload->u.SetTcpEntry.i.LocalPort; + tcpRow.dwRemoteAddr = Payload->u.SetTcpEntry.i.RemoteAddress; + tcpRow.dwRemotePort = Payload->u.SetTcpEntry.i.RemotePort; + result = localSetTcpEntry(&tcpRow); + + return NTSTATUS_FROM_WIN32(result); +} + +NTSTATUS PhSvcApiControlThread( + _In_ PPHSVC_CLIENT Client, + _Inout_ PPHSVC_API_PAYLOAD Payload + ) +{ + NTSTATUS status; + HANDLE threadId; + HANDLE threadHandle; + + threadId = Payload->u.ControlThread.i.ThreadId; + + switch (Payload->u.ControlThread.i.Command) + { + case PhSvcControlThreadTerminate: + if (NT_SUCCESS(status = PhOpenThread(&threadHandle, THREAD_TERMINATE, threadId))) + { + status = NtTerminateThread(threadHandle, STATUS_SUCCESS); + NtClose(threadHandle); + } + break; + case PhSvcControlThreadSuspend: + if (NT_SUCCESS(status = PhOpenThread(&threadHandle, THREAD_SUSPEND_RESUME, threadId))) + { + status = NtSuspendThread(threadHandle, NULL); + NtClose(threadHandle); + } + break; + case PhSvcControlThreadResume: + if (NT_SUCCESS(status = PhOpenThread(&threadHandle, THREAD_SUSPEND_RESUME, threadId))) + { + status = NtResumeThread(threadHandle, NULL); + NtClose(threadHandle); + } + break; + case PhSvcControlThreadIoPriority: + if (NT_SUCCESS(status = PhOpenThread(&threadHandle, THREAD_SET_INFORMATION, threadId))) + { + status = PhSetThreadIoPriority(threadHandle, Payload->u.ControlThread.i.Argument); + NtClose(threadHandle); + } + break; + default: + status = STATUS_INVALID_PARAMETER; + break; + } + + return status; +} + +NTSTATUS PhSvcApiAddAccountRight( + _In_ PPHSVC_CLIENT Client, + _Inout_ PPHSVC_API_PAYLOAD Payload + ) +{ + NTSTATUS status; + PSID accountSid; + PPH_STRING userRight; + LSA_HANDLE policyHandle; + UNICODE_STRING userRightUs; + + if (NT_SUCCESS(status = PhSvcCaptureSid(&Payload->u.AddAccountRight.i.AccountSid, FALSE, &accountSid))) + { + if (NT_SUCCESS(status = PhSvcCaptureString(&Payload->u.AddAccountRight.i.UserRight, FALSE, &userRight))) + { + PH_AUTO(userRight); + + if (NT_SUCCESS(status = PhOpenLsaPolicy(&policyHandle, POLICY_LOOKUP_NAMES | POLICY_CREATE_ACCOUNT, NULL))) + { + PhStringRefToUnicodeString(&userRight->sr, &userRightUs); + status = LsaAddAccountRights(policyHandle, accountSid, &userRightUs, 1); + LsaClose(policyHandle); + } + } + + PhFree(accountSid); + } + + return status; +} + +NTSTATUS PhSvcApiInvokeRunAsService( + _In_ PPHSVC_CLIENT Client, + _Inout_ PPHSVC_API_PAYLOAD Payload + ) +{ + NTSTATUS status; + PH_RUNAS_SERVICE_PARAMETERS parameters; + PHSVCP_CAPTURED_RUNAS_SERVICE_PARAMETERS capturedParameters; + + if (NT_SUCCESS(status = PhSvcpCaptureRunAsServiceParameters(Client, Payload, ¶meters, &capturedParameters))) + { + if (NT_SUCCESS(status = PhSvcpValidateRunAsServiceParameters(¶meters))) + { + status = PhInvokeRunAsService(¶meters); + } + } + + PhSvcpReleaseRunAsServiceParameters(&capturedParameters); + + return status; +} + +NTSTATUS PhSvcApiIssueMemoryListCommand( + _In_ PPHSVC_CLIENT Client, + _Inout_ PPHSVC_API_PAYLOAD Payload + ) +{ + NTSTATUS status; + + status = NtSetSystemInformation( + SystemMemoryListInformation, + &Payload->u.IssueMemoryListCommand.i.Command, + sizeof(SYSTEM_MEMORY_LIST_COMMAND) + ); + + return status; +} + +NTSTATUS PhSvcApiPostMessage( + _In_ PPHSVC_CLIENT Client, + _Inout_ PPHSVC_API_PAYLOAD Payload + ) +{ + if (PostMessage( + Payload->u.PostMessage.i.hWnd, + Payload->u.PostMessage.i.Msg, + Payload->u.PostMessage.i.wParam, + Payload->u.PostMessage.i.lParam + )) + { + return STATUS_SUCCESS; + } + else + { + return PhGetLastWin32ErrorAsNtStatus(); + } +} + +NTSTATUS PhSvcApiSendMessage( + _In_ PPHSVC_CLIENT Client, + _Inout_ PPHSVC_API_PAYLOAD Payload + ) +{ + if (SendMessage( + Payload->u.PostMessage.i.hWnd, + Payload->u.PostMessage.i.Msg, + Payload->u.PostMessage.i.wParam, + Payload->u.PostMessage.i.lParam + )) + { + return STATUS_SUCCESS; + } + else + { + return PhGetLastWin32ErrorAsNtStatus(); + } +} + +NTSTATUS PhSvcApiCreateProcessIgnoreIfeoDebugger( + _In_ PPHSVC_CLIENT Client, + _Inout_ PPHSVC_API_PAYLOAD Payload + ) +{ + NTSTATUS status; + PPH_STRING fileName; + + if (NT_SUCCESS(status = PhSvcCaptureString(&Payload->u.CreateProcessIgnoreIfeoDebugger.i.FileName, FALSE, &fileName))) + { + PH_AUTO(fileName); + + if (!PhCreateProcessIgnoreIfeoDebugger(fileName->Buffer)) + status = STATUS_UNSUCCESSFUL; + } + + return status; +} + +NTSTATUS PhSvcApiSetServiceSecurity( + _In_ PPHSVC_CLIENT Client, + _Inout_ PPHSVC_API_PAYLOAD Payload + ) +{ + NTSTATUS status; + PPH_STRING serviceName; + PSECURITY_DESCRIPTOR securityDescriptor; + ACCESS_MASK desiredAccess; + SC_HANDLE serviceHandle; + + if (NT_SUCCESS(status = PhSvcCaptureString(&Payload->u.SetServiceSecurity.i.ServiceName, FALSE, &serviceName))) + { + PH_AUTO(serviceName); + + if (NT_SUCCESS(status = PhSvcCaptureSecurityDescriptor(&Payload->u.SetServiceSecurity.i.SecurityDescriptor, FALSE, 0, &securityDescriptor))) + { + desiredAccess = 0; + + if ((Payload->u.SetServiceSecurity.i.SecurityInformation & OWNER_SECURITY_INFORMATION) || + (Payload->u.SetServiceSecurity.i.SecurityInformation & GROUP_SECURITY_INFORMATION)) + { + desiredAccess |= WRITE_OWNER; + } + + if (Payload->u.SetServiceSecurity.i.SecurityInformation & DACL_SECURITY_INFORMATION) + { + desiredAccess |= WRITE_DAC; + } + + if (Payload->u.SetServiceSecurity.i.SecurityInformation & SACL_SECURITY_INFORMATION) + { + desiredAccess |= ACCESS_SYSTEM_SECURITY; + } + + if (serviceHandle = PhOpenService(serviceName->Buffer, desiredAccess)) + { + status = PhSetSeObjectSecurity( + serviceHandle, + SE_SERVICE, + Payload->u.SetServiceSecurity.i.SecurityInformation, + securityDescriptor + ); + CloseServiceHandle(serviceHandle); + } + else + { + status = PhGetLastWin32ErrorAsNtStatus(); + } + + PhFree(securityDescriptor); + } + } + + return status; +} + +NTSTATUS PhSvcApiLoadDbgHelp( + _In_ PPHSVC_CLIENT Client, + _Inout_ PPHSVC_API_PAYLOAD Payload + ) +{ + static BOOLEAN alreadyLoaded; + + NTSTATUS status; + PPH_STRING dbgHelpPath; + + if (alreadyLoaded) + return STATUS_SOME_NOT_MAPPED; + + if (NT_SUCCESS(status = PhSvcCaptureString(&Payload->u.LoadDbgHelp.i.DbgHelpPath, FALSE, &dbgHelpPath))) + { + PH_AUTO(dbgHelpPath); + PhLoadDbgHelpFromPath(dbgHelpPath->Buffer); + alreadyLoaded = TRUE; + } + + return status; +} + +NTSTATUS PhSvcApiWriteMiniDumpProcess( + _In_ PPHSVC_CLIENT Client, + _Inout_ PPHSVC_API_PAYLOAD Payload + ) +{ + if (PhWriteMiniDumpProcess( + UlongToHandle(Payload->u.WriteMiniDumpProcess.i.LocalProcessHandle), + UlongToHandle(Payload->u.WriteMiniDumpProcess.i.ProcessId), + UlongToHandle(Payload->u.WriteMiniDumpProcess.i.LocalFileHandle), + Payload->u.WriteMiniDumpProcess.i.DumpType, + NULL, + NULL, + NULL + )) + { + return STATUS_SUCCESS; + } + else + { + ULONG error; + + error = GetLastError(); + + if (error == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER)) + return STATUS_INVALID_PARAMETER; + else + return STATUS_UNSUCCESSFUL; + } +} diff --git a/ProcessHacker/phsvc/svcapiport.c b/ProcessHacker/phsvc/svcapiport.c index 7eae7d306460..fb31465e3e3c 100644 --- a/ProcessHacker/phsvc/svcapiport.c +++ b/ProcessHacker/phsvc/svcapiport.c @@ -1,318 +1,318 @@ -/* - * Process Hacker - - * server API port - * - * Copyright (C) 2011-2015 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include -#include - -NTSTATUS PhSvcApiRequestThreadStart( - _In_ PVOID Parameter - ); - -extern HANDLE PhSvcTimeoutStandbyEventHandle; -extern HANDLE PhSvcTimeoutCancelEventHandle; - -ULONG PhSvcApiThreadContextTlsIndex; -HANDLE PhSvcApiPortHandle; -ULONG PhSvcApiNumberOfClients = 0; - -NTSTATUS PhSvcApiPortInitialization( - _In_ PUNICODE_STRING PortName - ) -{ - static SID_IDENTIFIER_AUTHORITY ntAuthority = SECURITY_NT_AUTHORITY; - - NTSTATUS status; - OBJECT_ATTRIBUTES objectAttributes; - PSECURITY_DESCRIPTOR securityDescriptor; - ULONG sdAllocationLength; - UCHAR administratorsSidBuffer[FIELD_OFFSET(SID, SubAuthority) + sizeof(ULONG) * 2]; - PSID administratorsSid; - PACL dacl; - ULONG i; - HANDLE threadHandle; - - // Create the API port. - - administratorsSid = (PSID)administratorsSidBuffer; - RtlInitializeSid(administratorsSid, &ntAuthority, 2); - *RtlSubAuthoritySid(administratorsSid, 0) = SECURITY_BUILTIN_DOMAIN_RID; - *RtlSubAuthoritySid(administratorsSid, 1) = DOMAIN_ALIAS_RID_ADMINS; - - sdAllocationLength = SECURITY_DESCRIPTOR_MIN_LENGTH + - (ULONG)sizeof(ACL) + - (ULONG)sizeof(ACCESS_ALLOWED_ACE) + - RtlLengthSid(administratorsSid) + - (ULONG)sizeof(ACCESS_ALLOWED_ACE) + - RtlLengthSid(&PhSeEveryoneSid); - - securityDescriptor = PhAllocate(sdAllocationLength); - dacl = (PACL)((PCHAR)securityDescriptor + SECURITY_DESCRIPTOR_MIN_LENGTH); - - RtlCreateSecurityDescriptor(securityDescriptor, SECURITY_DESCRIPTOR_REVISION); - RtlCreateAcl(dacl, sdAllocationLength - SECURITY_DESCRIPTOR_MIN_LENGTH, ACL_REVISION); - RtlAddAccessAllowedAce(dacl, ACL_REVISION, PORT_ALL_ACCESS, administratorsSid); - RtlAddAccessAllowedAce(dacl, ACL_REVISION, PORT_CONNECT, &PhSeEveryoneSid); - RtlSetDaclSecurityDescriptor(securityDescriptor, TRUE, dacl, FALSE); - - InitializeObjectAttributes( - &objectAttributes, - PortName, - OBJ_CASE_INSENSITIVE, - NULL, - securityDescriptor - ); - - status = NtCreatePort( - &PhSvcApiPortHandle, - &objectAttributes, - sizeof(PHSVC_API_CONNECTINFO), - PhIsExecutingInWow64() ? sizeof(PHSVC_API_MSG64) : sizeof(PHSVC_API_MSG), - 0 - ); - PhFree(securityDescriptor); - - if (!NT_SUCCESS(status)) - return status; - - // Start the API threads. - - PhSvcApiThreadContextTlsIndex = TlsAlloc(); - - for (i = 0; i < 2; i++) - { - threadHandle = PhCreateThread(0, PhSvcApiRequestThreadStart, NULL); - - if (threadHandle) - NtClose(threadHandle); - } - - return status; -} - -PPHSVC_THREAD_CONTEXT PhSvcGetCurrentThreadContext( - VOID - ) -{ - return (PPHSVC_THREAD_CONTEXT)TlsGetValue(PhSvcApiThreadContextTlsIndex); -} - -NTSTATUS PhSvcApiRequestThreadStart( - _In_ PVOID Parameter - ) -{ - PH_AUTO_POOL autoPool; - NTSTATUS status; - PHSVC_THREAD_CONTEXT threadContext; - HANDLE portHandle; - PVOID portContext; - SIZE_T messageSize; - PPORT_MESSAGE receiveMessage; - PPORT_MESSAGE replyMessage; - CSHORT messageType; - PPHSVC_CLIENT client; - PPHSVC_API_PAYLOAD payload; - - PhInitializeAutoPool(&autoPool); - - threadContext.CurrentClient = NULL; - threadContext.OldClient = NULL; - - TlsSetValue(PhSvcApiThreadContextTlsIndex, &threadContext); - - portHandle = PhSvcApiPortHandle; - messageSize = PhIsExecutingInWow64() ? sizeof(PHSVC_API_MSG64) : sizeof(PHSVC_API_MSG); - receiveMessage = PhAllocate(messageSize); - replyMessage = NULL; - - while (TRUE) - { - status = NtReplyWaitReceivePort( - portHandle, - &portContext, - replyMessage, - receiveMessage - ); - - portHandle = PhSvcApiPortHandle; - replyMessage = NULL; - - if (!NT_SUCCESS(status)) - { - // Client probably died. - continue; - } - - messageType = receiveMessage->u2.s2.Type; - - if (messageType == LPC_CONNECTION_REQUEST) - { - PhSvcHandleConnectionRequest(receiveMessage); - continue; - } - - if (!portContext) - continue; - - client = portContext; - threadContext.CurrentClient = client; - PhWaitForEvent(&client->ReadyEvent, NULL); - - if (messageType == LPC_REQUEST) - { - if (PhIsExecutingInWow64()) - payload = &((PPHSVC_API_MSG64)receiveMessage)->p; - else - payload = &((PPHSVC_API_MSG)receiveMessage)->p; - - PhSvcDispatchApiCall(client, payload, &portHandle); - replyMessage = receiveMessage; - } - else if (messageType == LPC_PORT_CLOSED) - { - PhDereferenceObject(client); - - if (_InterlockedDecrement(&PhSvcApiNumberOfClients) == 0) - { - NtSetEvent(PhSvcTimeoutStandbyEventHandle, NULL); - } - } - - assert(!threadContext.OldClient); - PhDrainAutoPool(&autoPool); - } - - PhDeleteAutoPool(&autoPool); -} - -VOID PhSvcHandleConnectionRequest( - _In_ PPORT_MESSAGE PortMessage - ) -{ - NTSTATUS status; - PPHSVC_API_MSG message; - PPHSVC_API_MSG64 message64; - CLIENT_ID clientId; - PPHSVC_CLIENT client; - HANDLE portHandle; - REMOTE_PORT_VIEW clientView; - REMOTE_PORT_VIEW64 clientView64; - PREMOTE_PORT_VIEW actualClientView; - - message = (PPHSVC_API_MSG)PortMessage; - message64 = (PPHSVC_API_MSG64)PortMessage; - - if (PhIsExecutingInWow64()) - { - clientId.UniqueProcess = (HANDLE)message64->h.ClientId.UniqueProcess; - clientId.UniqueThread = (HANDLE)message64->h.ClientId.UniqueThread; - } - else - { - PPH_STRING referenceFileName; - PPH_STRING remoteFileName; - - clientId = message->h.ClientId; - - // Make sure that the remote process is Process Hacker itself and not some other program. - - referenceFileName = NULL; - PhGetProcessImageFileNameByProcessId(NtCurrentProcessId(), &referenceFileName); - PH_AUTO(referenceFileName); - - remoteFileName = NULL; - PhGetProcessImageFileNameByProcessId(clientId.UniqueProcess, &remoteFileName); - PH_AUTO(remoteFileName); - - if (!referenceFileName || !remoteFileName || !PhEqualString(referenceFileName, remoteFileName, TRUE)) - { - NtAcceptConnectPort(&portHandle, NULL, PortMessage, FALSE, NULL, NULL); - return; - } - } - - client = PhSvcCreateClient(&clientId); - - if (!client) - { - NtAcceptConnectPort(&portHandle, NULL, PortMessage, FALSE, NULL, NULL); - return; - } - - if (PhIsExecutingInWow64()) - { - message64->p.ConnectInfo.ServerProcessId = HandleToUlong(NtCurrentProcessId()); - - clientView64.Length = sizeof(REMOTE_PORT_VIEW64); - clientView64.ViewSize = 0; - clientView64.ViewBase = 0; - actualClientView = (PREMOTE_PORT_VIEW)&clientView64; - } - else - { - message->p.ConnectInfo.ServerProcessId = HandleToUlong(NtCurrentProcessId()); - - clientView.Length = sizeof(REMOTE_PORT_VIEW); - clientView.ViewSize = 0; - clientView.ViewBase = NULL; - actualClientView = &clientView; - } - - status = NtAcceptConnectPort( - &portHandle, - client, - PortMessage, - TRUE, - NULL, - actualClientView - ); - - if (!NT_SUCCESS(status)) - { - PhDereferenceObject(client); - return; - } - - // IMPORTANT: Since Vista, NtCompleteConnectPort does not do anything and simply returns STATUS_SUCCESS. - // We will call it anyway (for completeness), but we need to use an event to ensure that other threads don't try - // to process requests before we have finished setting up the client object. - - client->PortHandle = portHandle; - - if (PhIsExecutingInWow64()) - { - client->ClientViewBase = (PVOID)clientView64.ViewBase; - client->ClientViewLimit = (PCHAR)clientView64.ViewBase + (ULONG)clientView64.ViewSize; - } - else - { - client->ClientViewBase = clientView.ViewBase; - client->ClientViewLimit = (PCHAR)clientView.ViewBase + clientView.ViewSize; - } - - NtCompleteConnectPort(portHandle); - PhSetEvent(&client->ReadyEvent); - - if (_InterlockedIncrement(&PhSvcApiNumberOfClients) == 1) - { - NtSetEvent(PhSvcTimeoutCancelEventHandle, NULL); - } -} +/* + * Process Hacker - + * server API port + * + * Copyright (C) 2011-2015 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include +#include + +NTSTATUS PhSvcApiRequestThreadStart( + _In_ PVOID Parameter + ); + +extern HANDLE PhSvcTimeoutStandbyEventHandle; +extern HANDLE PhSvcTimeoutCancelEventHandle; + +ULONG PhSvcApiThreadContextTlsIndex; +HANDLE PhSvcApiPortHandle; +ULONG PhSvcApiNumberOfClients = 0; + +NTSTATUS PhSvcApiPortInitialization( + _In_ PUNICODE_STRING PortName + ) +{ + static SID_IDENTIFIER_AUTHORITY ntAuthority = SECURITY_NT_AUTHORITY; + + NTSTATUS status; + OBJECT_ATTRIBUTES objectAttributes; + PSECURITY_DESCRIPTOR securityDescriptor; + ULONG sdAllocationLength; + UCHAR administratorsSidBuffer[FIELD_OFFSET(SID, SubAuthority) + sizeof(ULONG) * 2]; + PSID administratorsSid; + PACL dacl; + ULONG i; + HANDLE threadHandle; + + // Create the API port. + + administratorsSid = (PSID)administratorsSidBuffer; + RtlInitializeSid(administratorsSid, &ntAuthority, 2); + *RtlSubAuthoritySid(administratorsSid, 0) = SECURITY_BUILTIN_DOMAIN_RID; + *RtlSubAuthoritySid(administratorsSid, 1) = DOMAIN_ALIAS_RID_ADMINS; + + sdAllocationLength = SECURITY_DESCRIPTOR_MIN_LENGTH + + (ULONG)sizeof(ACL) + + (ULONG)sizeof(ACCESS_ALLOWED_ACE) + + RtlLengthSid(administratorsSid) + + (ULONG)sizeof(ACCESS_ALLOWED_ACE) + + RtlLengthSid(&PhSeEveryoneSid); + + securityDescriptor = PhAllocate(sdAllocationLength); + dacl = (PACL)((PCHAR)securityDescriptor + SECURITY_DESCRIPTOR_MIN_LENGTH); + + RtlCreateSecurityDescriptor(securityDescriptor, SECURITY_DESCRIPTOR_REVISION); + RtlCreateAcl(dacl, sdAllocationLength - SECURITY_DESCRIPTOR_MIN_LENGTH, ACL_REVISION); + RtlAddAccessAllowedAce(dacl, ACL_REVISION, PORT_ALL_ACCESS, administratorsSid); + RtlAddAccessAllowedAce(dacl, ACL_REVISION, PORT_CONNECT, &PhSeEveryoneSid); + RtlSetDaclSecurityDescriptor(securityDescriptor, TRUE, dacl, FALSE); + + InitializeObjectAttributes( + &objectAttributes, + PortName, + OBJ_CASE_INSENSITIVE, + NULL, + securityDescriptor + ); + + status = NtCreatePort( + &PhSvcApiPortHandle, + &objectAttributes, + sizeof(PHSVC_API_CONNECTINFO), + PhIsExecutingInWow64() ? sizeof(PHSVC_API_MSG64) : sizeof(PHSVC_API_MSG), + 0 + ); + PhFree(securityDescriptor); + + if (!NT_SUCCESS(status)) + return status; + + // Start the API threads. + + PhSvcApiThreadContextTlsIndex = TlsAlloc(); + + for (i = 0; i < 2; i++) + { + threadHandle = PhCreateThread(0, PhSvcApiRequestThreadStart, NULL); + + if (threadHandle) + NtClose(threadHandle); + } + + return status; +} + +PPHSVC_THREAD_CONTEXT PhSvcGetCurrentThreadContext( + VOID + ) +{ + return (PPHSVC_THREAD_CONTEXT)TlsGetValue(PhSvcApiThreadContextTlsIndex); +} + +NTSTATUS PhSvcApiRequestThreadStart( + _In_ PVOID Parameter + ) +{ + PH_AUTO_POOL autoPool; + NTSTATUS status; + PHSVC_THREAD_CONTEXT threadContext; + HANDLE portHandle; + PVOID portContext; + SIZE_T messageSize; + PPORT_MESSAGE receiveMessage; + PPORT_MESSAGE replyMessage; + CSHORT messageType; + PPHSVC_CLIENT client; + PPHSVC_API_PAYLOAD payload; + + PhInitializeAutoPool(&autoPool); + + threadContext.CurrentClient = NULL; + threadContext.OldClient = NULL; + + TlsSetValue(PhSvcApiThreadContextTlsIndex, &threadContext); + + portHandle = PhSvcApiPortHandle; + messageSize = PhIsExecutingInWow64() ? sizeof(PHSVC_API_MSG64) : sizeof(PHSVC_API_MSG); + receiveMessage = PhAllocate(messageSize); + replyMessage = NULL; + + while (TRUE) + { + status = NtReplyWaitReceivePort( + portHandle, + &portContext, + replyMessage, + receiveMessage + ); + + portHandle = PhSvcApiPortHandle; + replyMessage = NULL; + + if (!NT_SUCCESS(status)) + { + // Client probably died. + continue; + } + + messageType = receiveMessage->u2.s2.Type; + + if (messageType == LPC_CONNECTION_REQUEST) + { + PhSvcHandleConnectionRequest(receiveMessage); + continue; + } + + if (!portContext) + continue; + + client = portContext; + threadContext.CurrentClient = client; + PhWaitForEvent(&client->ReadyEvent, NULL); + + if (messageType == LPC_REQUEST) + { + if (PhIsExecutingInWow64()) + payload = &((PPHSVC_API_MSG64)receiveMessage)->p; + else + payload = &((PPHSVC_API_MSG)receiveMessage)->p; + + PhSvcDispatchApiCall(client, payload, &portHandle); + replyMessage = receiveMessage; + } + else if (messageType == LPC_PORT_CLOSED) + { + PhDereferenceObject(client); + + if (_InterlockedDecrement(&PhSvcApiNumberOfClients) == 0) + { + NtSetEvent(PhSvcTimeoutStandbyEventHandle, NULL); + } + } + + assert(!threadContext.OldClient); + PhDrainAutoPool(&autoPool); + } + + PhDeleteAutoPool(&autoPool); +} + +VOID PhSvcHandleConnectionRequest( + _In_ PPORT_MESSAGE PortMessage + ) +{ + NTSTATUS status; + PPHSVC_API_MSG message; + PPHSVC_API_MSG64 message64; + CLIENT_ID clientId; + PPHSVC_CLIENT client; + HANDLE portHandle; + REMOTE_PORT_VIEW clientView; + REMOTE_PORT_VIEW64 clientView64; + PREMOTE_PORT_VIEW actualClientView; + + message = (PPHSVC_API_MSG)PortMessage; + message64 = (PPHSVC_API_MSG64)PortMessage; + + if (PhIsExecutingInWow64()) + { + clientId.UniqueProcess = (HANDLE)message64->h.ClientId.UniqueProcess; + clientId.UniqueThread = (HANDLE)message64->h.ClientId.UniqueThread; + } + else + { + PPH_STRING referenceFileName; + PPH_STRING remoteFileName; + + clientId = message->h.ClientId; + + // Make sure that the remote process is Process Hacker itself and not some other program. + + referenceFileName = NULL; + PhGetProcessImageFileNameByProcessId(NtCurrentProcessId(), &referenceFileName); + PH_AUTO(referenceFileName); + + remoteFileName = NULL; + PhGetProcessImageFileNameByProcessId(clientId.UniqueProcess, &remoteFileName); + PH_AUTO(remoteFileName); + + if (!referenceFileName || !remoteFileName || !PhEqualString(referenceFileName, remoteFileName, TRUE)) + { + NtAcceptConnectPort(&portHandle, NULL, PortMessage, FALSE, NULL, NULL); + return; + } + } + + client = PhSvcCreateClient(&clientId); + + if (!client) + { + NtAcceptConnectPort(&portHandle, NULL, PortMessage, FALSE, NULL, NULL); + return; + } + + if (PhIsExecutingInWow64()) + { + message64->p.ConnectInfo.ServerProcessId = HandleToUlong(NtCurrentProcessId()); + + clientView64.Length = sizeof(REMOTE_PORT_VIEW64); + clientView64.ViewSize = 0; + clientView64.ViewBase = 0; + actualClientView = (PREMOTE_PORT_VIEW)&clientView64; + } + else + { + message->p.ConnectInfo.ServerProcessId = HandleToUlong(NtCurrentProcessId()); + + clientView.Length = sizeof(REMOTE_PORT_VIEW); + clientView.ViewSize = 0; + clientView.ViewBase = NULL; + actualClientView = &clientView; + } + + status = NtAcceptConnectPort( + &portHandle, + client, + PortMessage, + TRUE, + NULL, + actualClientView + ); + + if (!NT_SUCCESS(status)) + { + PhDereferenceObject(client); + return; + } + + // IMPORTANT: Since Vista, NtCompleteConnectPort does not do anything and simply returns STATUS_SUCCESS. + // We will call it anyway (for completeness), but we need to use an event to ensure that other threads don't try + // to process requests before we have finished setting up the client object. + + client->PortHandle = portHandle; + + if (PhIsExecutingInWow64()) + { + client->ClientViewBase = (PVOID)clientView64.ViewBase; + client->ClientViewLimit = (PCHAR)clientView64.ViewBase + (ULONG)clientView64.ViewSize; + } + else + { + client->ClientViewBase = clientView.ViewBase; + client->ClientViewLimit = (PCHAR)clientView.ViewBase + clientView.ViewSize; + } + + NtCompleteConnectPort(portHandle); + PhSetEvent(&client->ReadyEvent); + + if (_InterlockedIncrement(&PhSvcApiNumberOfClients) == 1) + { + NtSetEvent(PhSvcTimeoutCancelEventHandle, NULL); + } +} diff --git a/ProcessHacker/phsvc/svcclient.c b/ProcessHacker/phsvc/svcclient.c index 537d30440a6d..8b6fe4cea657 100644 --- a/ProcessHacker/phsvc/svcclient.c +++ b/ProcessHacker/phsvc/svcclient.c @@ -1,159 +1,159 @@ -/* - * Process Hacker - - * server client - * - * Copyright (C) 2011-2015 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include -#include - -VOID NTAPI PhSvcpClientDeleteProcedure( - _In_ PVOID Object, - _In_ ULONG Flags - ); - -PPH_OBJECT_TYPE PhSvcClientType; -LIST_ENTRY PhSvcClientListHead; -PH_QUEUED_LOCK PhSvcClientListLock = PH_QUEUED_LOCK_INIT; - -NTSTATUS PhSvcClientInitialization( - VOID - ) -{ - PhSvcClientType = PhCreateObjectType(L"Client", 0, PhSvcpClientDeleteProcedure); - InitializeListHead(&PhSvcClientListHead); - - return STATUS_SUCCESS; -} - -PPHSVC_CLIENT PhSvcCreateClient( - _In_opt_ PCLIENT_ID ClientId - ) -{ - PPHSVC_CLIENT client; - - client = PhCreateObject(sizeof(PHSVC_CLIENT), PhSvcClientType); - memset(client, 0, sizeof(PHSVC_CLIENT)); - PhInitializeEvent(&client->ReadyEvent); - - if (ClientId) - client->ClientId = *ClientId; - - PhAcquireQueuedLockExclusive(&PhSvcClientListLock); - InsertTailList(&PhSvcClientListHead, &client->ListEntry); - PhReleaseQueuedLockExclusive(&PhSvcClientListLock); - - return client; -} - -VOID NTAPI PhSvcpClientDeleteProcedure( - _In_ PVOID Object, - _In_ ULONG Flags - ) -{ - PPHSVC_CLIENT client = Object; - - PhAcquireQueuedLockExclusive(&PhSvcClientListLock); - RemoveEntryList(&client->ListEntry); - PhReleaseQueuedLockExclusive(&PhSvcClientListLock); - - if (client->PortHandle) - NtClose(client->PortHandle); -} - -PPHSVC_CLIENT PhSvcReferenceClientByClientId( - _In_ PCLIENT_ID ClientId - ) -{ - PLIST_ENTRY listEntry; - PPHSVC_CLIENT client = NULL; - - PhAcquireQueuedLockShared(&PhSvcClientListLock); - - listEntry = PhSvcClientListHead.Flink; - - while (listEntry != &PhSvcClientListHead) - { - client = CONTAINING_RECORD(listEntry, PHSVC_CLIENT, ListEntry); - - if (ClientId->UniqueThread) - { - if ( - client->ClientId.UniqueProcess == ClientId->UniqueProcess && - client->ClientId.UniqueThread == ClientId->UniqueThread - ) - { - break; - } - } - else - { - if (client->ClientId.UniqueProcess == ClientId->UniqueProcess) - break; - } - - client = NULL; - - listEntry = listEntry->Flink; - } - - if (client) - { - if (!PhReferenceObjectSafe(client)) - client = NULL; - } - - PhReleaseQueuedLockShared(&PhSvcClientListLock); - - return client; -} - -PPHSVC_CLIENT PhSvcGetCurrentClient( - VOID - ) -{ - return PhSvcGetCurrentThreadContext()->CurrentClient; -} - -BOOLEAN PhSvcAttachClient( - _In_ PPHSVC_CLIENT Client - ) -{ - PPHSVC_THREAD_CONTEXT threadContext = PhSvcGetCurrentThreadContext(); - - if (threadContext->OldClient) - return FALSE; - - PhReferenceObject(Client); - threadContext->OldClient = threadContext->CurrentClient; - threadContext->CurrentClient = Client; - - return TRUE; -} - -VOID PhSvcDetachClient( - _In_ PPHSVC_CLIENT Client - ) -{ - PPHSVC_THREAD_CONTEXT threadContext = PhSvcGetCurrentThreadContext(); - - PhDereferenceObject(threadContext->CurrentClient); - threadContext->CurrentClient = threadContext->OldClient; - threadContext->OldClient = NULL; -} +/* + * Process Hacker - + * server client + * + * Copyright (C) 2011-2015 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include +#include + +VOID NTAPI PhSvcpClientDeleteProcedure( + _In_ PVOID Object, + _In_ ULONG Flags + ); + +PPH_OBJECT_TYPE PhSvcClientType; +LIST_ENTRY PhSvcClientListHead; +PH_QUEUED_LOCK PhSvcClientListLock = PH_QUEUED_LOCK_INIT; + +NTSTATUS PhSvcClientInitialization( + VOID + ) +{ + PhSvcClientType = PhCreateObjectType(L"Client", 0, PhSvcpClientDeleteProcedure); + InitializeListHead(&PhSvcClientListHead); + + return STATUS_SUCCESS; +} + +PPHSVC_CLIENT PhSvcCreateClient( + _In_opt_ PCLIENT_ID ClientId + ) +{ + PPHSVC_CLIENT client; + + client = PhCreateObject(sizeof(PHSVC_CLIENT), PhSvcClientType); + memset(client, 0, sizeof(PHSVC_CLIENT)); + PhInitializeEvent(&client->ReadyEvent); + + if (ClientId) + client->ClientId = *ClientId; + + PhAcquireQueuedLockExclusive(&PhSvcClientListLock); + InsertTailList(&PhSvcClientListHead, &client->ListEntry); + PhReleaseQueuedLockExclusive(&PhSvcClientListLock); + + return client; +} + +VOID NTAPI PhSvcpClientDeleteProcedure( + _In_ PVOID Object, + _In_ ULONG Flags + ) +{ + PPHSVC_CLIENT client = Object; + + PhAcquireQueuedLockExclusive(&PhSvcClientListLock); + RemoveEntryList(&client->ListEntry); + PhReleaseQueuedLockExclusive(&PhSvcClientListLock); + + if (client->PortHandle) + NtClose(client->PortHandle); +} + +PPHSVC_CLIENT PhSvcReferenceClientByClientId( + _In_ PCLIENT_ID ClientId + ) +{ + PLIST_ENTRY listEntry; + PPHSVC_CLIENT client = NULL; + + PhAcquireQueuedLockShared(&PhSvcClientListLock); + + listEntry = PhSvcClientListHead.Flink; + + while (listEntry != &PhSvcClientListHead) + { + client = CONTAINING_RECORD(listEntry, PHSVC_CLIENT, ListEntry); + + if (ClientId->UniqueThread) + { + if ( + client->ClientId.UniqueProcess == ClientId->UniqueProcess && + client->ClientId.UniqueThread == ClientId->UniqueThread + ) + { + break; + } + } + else + { + if (client->ClientId.UniqueProcess == ClientId->UniqueProcess) + break; + } + + client = NULL; + + listEntry = listEntry->Flink; + } + + if (client) + { + if (!PhReferenceObjectSafe(client)) + client = NULL; + } + + PhReleaseQueuedLockShared(&PhSvcClientListLock); + + return client; +} + +PPHSVC_CLIENT PhSvcGetCurrentClient( + VOID + ) +{ + return PhSvcGetCurrentThreadContext()->CurrentClient; +} + +BOOLEAN PhSvcAttachClient( + _In_ PPHSVC_CLIENT Client + ) +{ + PPHSVC_THREAD_CONTEXT threadContext = PhSvcGetCurrentThreadContext(); + + if (threadContext->OldClient) + return FALSE; + + PhReferenceObject(Client); + threadContext->OldClient = threadContext->CurrentClient; + threadContext->CurrentClient = Client; + + return TRUE; +} + +VOID PhSvcDetachClient( + _In_ PPHSVC_CLIENT Client + ) +{ + PPHSVC_THREAD_CONTEXT threadContext = PhSvcGetCurrentThreadContext(); + + PhDereferenceObject(threadContext->CurrentClient); + threadContext->CurrentClient = threadContext->OldClient; + threadContext->OldClient = NULL; +} diff --git a/ProcessHacker/phsvc/svcmain.c b/ProcessHacker/phsvc/svcmain.c index dfc9685e4198..660c55cb3618 100644 --- a/ProcessHacker/phsvc/svcmain.c +++ b/ProcessHacker/phsvc/svcmain.c @@ -1,111 +1,111 @@ -/* - * Process Hacker - - * server - * - * Copyright (C) 2011 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include -#include - -HANDLE PhSvcTimeoutStandbyEventHandle; -HANDLE PhSvcTimeoutCancelEventHandle; - -NTSTATUS PhSvcMain( - _In_opt_ PUNICODE_STRING PortName, - _In_opt_ PLARGE_INTEGER Timeout, - _Inout_opt_ PPHSVC_STOP Stop - ) -{ - NTSTATUS status; - UNICODE_STRING portName; - LARGE_INTEGER timeout; - - if (!PortName) - { - if (PhIsExecutingInWow64()) - RtlInitUnicodeString(&portName, PHSVC_WOW64_PORT_NAME); - else - RtlInitUnicodeString(&portName, PHSVC_PORT_NAME); - - PortName = &portName; - } - - if (!Timeout) - { - timeout.QuadPart = -15 * PH_TIMEOUT_SEC; - Timeout = &timeout; - } - - if (!NT_SUCCESS(status = PhSvcClientInitialization())) - return status; - if (!NT_SUCCESS(status = PhSvcApiInitialization())) - return status; - if (!NT_SUCCESS(status = PhSvcApiPortInitialization(PortName))) - return status; - - if (!NT_SUCCESS(status = NtCreateEvent(&PhSvcTimeoutStandbyEventHandle, EVENT_ALL_ACCESS, NULL, SynchronizationEvent, TRUE))) - return status; - - if (!NT_SUCCESS(status = NtCreateEvent(&PhSvcTimeoutCancelEventHandle, EVENT_ALL_ACCESS, NULL, SynchronizationEvent, FALSE))) - { - NtClose(PhSvcTimeoutStandbyEventHandle); - return status; - } - - if (Stop) - { - Stop->Event1 = PhSvcTimeoutStandbyEventHandle; - Stop->Event2 = PhSvcTimeoutCancelEventHandle; - MemoryBarrier(); - - if (Stop->Stop) - return STATUS_SUCCESS; - } - - while (TRUE) - { - NtWaitForSingleObject(PhSvcTimeoutStandbyEventHandle, FALSE, NULL); - - if (Stop && Stop->Stop) - break; - - status = NtWaitForSingleObject(PhSvcTimeoutCancelEventHandle, FALSE, Timeout); - - if (Stop && Stop->Stop) - break; - if (status == STATUS_TIMEOUT) - break; - - // A client connected, so we wait on the standby event again. - } - - return status; -} - -VOID PhSvcStop( - _Inout_ PPHSVC_STOP Stop - ) -{ - Stop->Stop = TRUE; - - if (Stop->Event1) - NtSetEvent(Stop->Event1, NULL); - if (Stop->Event2) - NtSetEvent(Stop->Event2, NULL); -} +/* + * Process Hacker - + * server + * + * Copyright (C) 2011 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include +#include + +HANDLE PhSvcTimeoutStandbyEventHandle; +HANDLE PhSvcTimeoutCancelEventHandle; + +NTSTATUS PhSvcMain( + _In_opt_ PUNICODE_STRING PortName, + _In_opt_ PLARGE_INTEGER Timeout, + _Inout_opt_ PPHSVC_STOP Stop + ) +{ + NTSTATUS status; + UNICODE_STRING portName; + LARGE_INTEGER timeout; + + if (!PortName) + { + if (PhIsExecutingInWow64()) + RtlInitUnicodeString(&portName, PHSVC_WOW64_PORT_NAME); + else + RtlInitUnicodeString(&portName, PHSVC_PORT_NAME); + + PortName = &portName; + } + + if (!Timeout) + { + timeout.QuadPart = -15 * PH_TIMEOUT_SEC; + Timeout = &timeout; + } + + if (!NT_SUCCESS(status = PhSvcClientInitialization())) + return status; + if (!NT_SUCCESS(status = PhSvcApiInitialization())) + return status; + if (!NT_SUCCESS(status = PhSvcApiPortInitialization(PortName))) + return status; + + if (!NT_SUCCESS(status = NtCreateEvent(&PhSvcTimeoutStandbyEventHandle, EVENT_ALL_ACCESS, NULL, SynchronizationEvent, TRUE))) + return status; + + if (!NT_SUCCESS(status = NtCreateEvent(&PhSvcTimeoutCancelEventHandle, EVENT_ALL_ACCESS, NULL, SynchronizationEvent, FALSE))) + { + NtClose(PhSvcTimeoutStandbyEventHandle); + return status; + } + + if (Stop) + { + Stop->Event1 = PhSvcTimeoutStandbyEventHandle; + Stop->Event2 = PhSvcTimeoutCancelEventHandle; + MemoryBarrier(); + + if (Stop->Stop) + return STATUS_SUCCESS; + } + + while (TRUE) + { + NtWaitForSingleObject(PhSvcTimeoutStandbyEventHandle, FALSE, NULL); + + if (Stop && Stop->Stop) + break; + + status = NtWaitForSingleObject(PhSvcTimeoutCancelEventHandle, FALSE, Timeout); + + if (Stop && Stop->Stop) + break; + if (status == STATUS_TIMEOUT) + break; + + // A client connected, so we wait on the standby event again. + } + + return status; +} + +VOID PhSvcStop( + _Inout_ PPHSVC_STOP Stop + ) +{ + Stop->Stop = TRUE; + + if (Stop->Event1) + NtSetEvent(Stop->Event1, NULL); + if (Stop->Event2) + NtSetEvent(Stop->Event2, NULL); +} diff --git a/ProcessHacker/plugin.c b/ProcessHacker/plugin.c index 0af42c05aacc..8f30f4e9da33 100644 --- a/ProcessHacker/plugin.c +++ b/ProcessHacker/plugin.c @@ -1,1043 +1,1043 @@ -/* - * Process Hacker - - * plugin support - * - * Copyright (C) 2010-2015 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include - -typedef struct _PHP_PLUGIN_LOAD_ERROR -{ - PPH_STRING FileName; - PPH_STRING ErrorMessage; -} PHP_PLUGIN_LOAD_ERROR, *PPHP_PLUGIN_LOAD_ERROR; - -typedef struct _PHP_PLUGIN_MENU_HOOK -{ - PPH_PLUGIN Plugin; - PVOID Context; -} PHP_PLUGIN_MENU_HOOK, *PPHP_PLUGIN_MENU_HOOK; - -INT NTAPI PhpPluginsCompareFunction( - _In_ PPH_AVL_LINKS Links1, - _In_ PPH_AVL_LINKS Links2 - ); - -BOOLEAN PhLoadPlugin( - _In_ PPH_STRING FileName - ); - -VOID PhpExecuteCallbackForAllPlugins( - _In_ PH_PLUGIN_CALLBACK Callback, - _In_ BOOLEAN StartupParameters - ); - -PH_AVL_TREE PhPluginsByName = PH_AVL_TREE_INIT(PhpPluginsCompareFunction); - -static PH_CALLBACK GeneralCallbacks[GeneralCallbackMaximum]; -static PPH_STRING PluginsDirectory; -static PPH_LIST LoadErrors; -static ULONG NextPluginId = IDPLUGINS + 1; - -VOID PhPluginsInitialization( - VOID - ) -{ - ULONG i; - - for (i = 0; i < GeneralCallbackMaximum; i++) - PhInitializeCallback(&GeneralCallbacks[i]); -} - -INT NTAPI PhpPluginsCompareFunction( - _In_ PPH_AVL_LINKS Links1, - _In_ PPH_AVL_LINKS Links2 - ) -{ - PPH_PLUGIN plugin1 = CONTAINING_RECORD(Links1, PH_PLUGIN, Links); - PPH_PLUGIN plugin2 = CONTAINING_RECORD(Links2, PH_PLUGIN, Links); - - return PhCompareStringRef(&plugin1->Name, &plugin2->Name, FALSE); -} - -BOOLEAN PhpLocateDisabledPlugin( - _In_ PPH_STRING List, - _In_ PPH_STRINGREF BaseName, - _Out_opt_ PULONG FoundIndex - ) -{ - PH_STRINGREF namePart; - PH_STRINGREF remainingPart; - - remainingPart = List->sr; - - while (remainingPart.Length != 0) - { - PhSplitStringRefAtChar(&remainingPart, '|', &namePart, &remainingPart); - - if (PhEqualStringRef(&namePart, BaseName, TRUE)) - { - if (FoundIndex) - *FoundIndex = (ULONG)(namePart.Buffer - List->Buffer); - - return TRUE; - } - } - - return FALSE; -} - -BOOLEAN PhIsPluginDisabled( - _In_ PPH_STRINGREF BaseName - ) -{ - BOOLEAN found; - PPH_STRING disabled; - - disabled = PhGetStringSetting(L"DisabledPlugins"); - found = PhpLocateDisabledPlugin(disabled, BaseName, NULL); - PhDereferenceObject(disabled); - - return found; -} - -VOID PhSetPluginDisabled( - _In_ PPH_STRINGREF BaseName, - _In_ BOOLEAN Disable - ) -{ - BOOLEAN found; - PPH_STRING disabled; - ULONG foundIndex; - PPH_STRING newDisabled; - - disabled = PhGetStringSetting(L"DisabledPlugins"); - - found = PhpLocateDisabledPlugin(disabled, BaseName, &foundIndex); - - if (Disable && !found) - { - // We need to add the plugin to the disabled list. - - if (disabled->Length != 0) - { - // We have other disabled plugins. Append a pipe character followed by the plugin name. - newDisabled = PhCreateStringEx(NULL, disabled->Length + sizeof(WCHAR) + BaseName->Length); - memcpy(newDisabled->Buffer, disabled->Buffer, disabled->Length); - newDisabled->Buffer[disabled->Length / 2] = '|'; - memcpy(&newDisabled->Buffer[disabled->Length / 2 + 1], BaseName->Buffer, BaseName->Length); - PhSetStringSetting2(L"DisabledPlugins", &newDisabled->sr); - PhDereferenceObject(newDisabled); - } - else - { - // This is the first disabled plugin. - PhSetStringSetting2(L"DisabledPlugins", BaseName); - } - } - else if (!Disable && found) - { - ULONG removeCount; - - // We need to remove the plugin from the disabled list. - - removeCount = (ULONG)BaseName->Length / 2; - - if (foundIndex + (ULONG)BaseName->Length / 2 < (ULONG)disabled->Length / 2) - { - // Remove the following pipe character as well. - removeCount++; - } - else if (foundIndex != 0) - { - // Remove the preceding pipe character as well. - foundIndex--; - removeCount++; - } - - newDisabled = PhCreateStringEx(NULL, disabled->Length - removeCount * sizeof(WCHAR)); - memcpy(newDisabled->Buffer, disabled->Buffer, foundIndex * sizeof(WCHAR)); - memcpy(&newDisabled->Buffer[foundIndex], &disabled->Buffer[foundIndex + removeCount], - disabled->Length - removeCount * sizeof(WCHAR) - foundIndex * sizeof(WCHAR)); - PhSetStringSetting2(L"DisabledPlugins", &newDisabled->sr); - PhDereferenceObject(newDisabled); - } - - PhDereferenceObject(disabled); -} - -static BOOLEAN EnumPluginsDirectoryCallback( - _In_ PFILE_DIRECTORY_INFORMATION Information, - _In_opt_ PVOID Context - ) -{ - PH_STRINGREF baseName; - PPH_STRING fileName; - - baseName.Buffer = Information->FileName; - baseName.Length = Information->FileNameLength; - - if (PhEndsWithStringRef2(&baseName, L".dll", TRUE)) - { - if (!PhIsPluginDisabled(&baseName)) - { - fileName = PhCreateStringEx(NULL, PluginsDirectory->Length + Information->FileNameLength); - memcpy(fileName->Buffer, PluginsDirectory->Buffer, PluginsDirectory->Length); - memcpy(&fileName->Buffer[PluginsDirectory->Length / 2], Information->FileName, Information->FileNameLength); - - PhLoadPlugin(fileName); - - PhDereferenceObject(fileName); - } - } - - return TRUE; -} - -/** - * Loads plugins from the default plugins directory. - */ -VOID PhLoadPlugins( - VOID - ) -{ - HANDLE pluginsDirectoryHandle; - PPH_STRING pluginsDirectory; - - pluginsDirectory = PhGetStringSetting(L"PluginsDirectory"); - - if (RtlDetermineDosPathNameType_U(pluginsDirectory->Buffer) == RtlPathTypeRelative) - { - // Not absolute. Make sure it is. - PluginsDirectory = PhConcatStrings(4, PhApplicationDirectory->Buffer, L"\\", pluginsDirectory->Buffer, L"\\"); - PhDereferenceObject(pluginsDirectory); - } - else - { - PluginsDirectory = pluginsDirectory; - } - - if (NT_SUCCESS(PhCreateFileWin32( - &pluginsDirectoryHandle, - PluginsDirectory->Buffer, - FILE_GENERIC_READ, - 0, - FILE_SHARE_READ, - FILE_OPEN, - FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT - ))) - { - UNICODE_STRING pattern = RTL_CONSTANT_STRING(L"*.dll"); - - PhEnumDirectoryFile(pluginsDirectoryHandle, &pattern, EnumPluginsDirectoryCallback, NULL); - NtClose(pluginsDirectoryHandle); - } - - // Handle load errors. - // In certain startup modes we want to ignore all plugin load errors. - if (LoadErrors && LoadErrors->Count != 0 && !PhStartupParameters.PhSvc) - { - PH_STRING_BUILDER sb; - ULONG i; - PPHP_PLUGIN_LOAD_ERROR loadError; - PPH_STRING baseName; - - PhInitializeStringBuilder(&sb, 100); - PhAppendStringBuilder2(&sb, L"Unable to load the following plugin(s):\n\n"); - - for (i = 0; i < LoadErrors->Count; i++) - { - loadError = LoadErrors->Items[i]; - baseName = PhGetBaseName(loadError->FileName); - PhAppendFormatStringBuilder(&sb, L"%s: %s\n", - baseName->Buffer, PhGetStringOrDefault(loadError->ErrorMessage, L"An unknown error occurred.")); - PhDereferenceObject(baseName); - } - - PhAppendStringBuilder2(&sb, L"\nDo you want to disable the above plugin(s)?"); - - if (PhShowMessage( - NULL, - MB_ICONERROR | MB_YESNO, - sb.String->Buffer - ) == IDYES) - { - ULONG i; - - for (i = 0; i < LoadErrors->Count; i++) - { - loadError = LoadErrors->Items[i]; - baseName = PhGetBaseName(loadError->FileName); - PhSetPluginDisabled(&baseName->sr, TRUE); - PhDereferenceObject(baseName); - } - } - - PhDeleteStringBuilder(&sb); - } - - // When we loaded settings before, we didn't know about plugin settings, so they - // went into the ignored settings list. Now that they've had a chance to add - // settings, we should scan the ignored settings list and move the settings to - // the right places. - if (PhSettingsFileName) - PhConvertIgnoredSettings(); - - PhpExecuteCallbackForAllPlugins(PluginCallbackLoad, TRUE); -} - -/** - * Notifies all plugins that the program is shutting down. - */ -VOID PhUnloadPlugins( - VOID - ) -{ - PhpExecuteCallbackForAllPlugins(PluginCallbackUnload, FALSE); -} - -/** - * Loads a plugin. - * - * \param FileName The full file name of the plugin. - */ -BOOLEAN PhLoadPlugin( - _In_ PPH_STRING FileName - ) -{ - BOOLEAN success; - PPH_STRING fileName; - PPH_STRING errorMessage; - - fileName = PhGetFullPath(FileName->Buffer, NULL); - - if (!fileName) - PhSetReference(&fileName, FileName); - - success = TRUE; - - if (!LoadLibrary(fileName->Buffer)) - { - success = FALSE; - errorMessage = PhGetWin32Message(GetLastError()); - } - - if (!success) - { - PPHP_PLUGIN_LOAD_ERROR loadError; - - loadError = PhAllocate(sizeof(PHP_PLUGIN_LOAD_ERROR)); - PhSetReference(&loadError->FileName, fileName); - PhSetReference(&loadError->ErrorMessage, errorMessage); - - if (!LoadErrors) - LoadErrors = PhCreateList(2); - - PhAddItemList(LoadErrors, loadError); - - if (errorMessage) - PhDereferenceObject(errorMessage); - } - - PhDereferenceObject(fileName); - - return success; -} - -VOID PhpExecuteCallbackForAllPlugins( - _In_ PH_PLUGIN_CALLBACK Callback, - _In_ BOOLEAN StartupParameters - ) -{ - PPH_AVL_LINKS links; - - for (links = PhMinimumElementAvlTree(&PhPluginsByName); links; links = PhSuccessorElementAvlTree(links)) - { - PPH_PLUGIN plugin = CONTAINING_RECORD(links, PH_PLUGIN, Links); - PPH_LIST parameters = NULL; - - // Find relevant startup parameters for this plugin. - if (StartupParameters && PhStartupParameters.PluginParameters) - { - ULONG i; - - for (i = 0; i < PhStartupParameters.PluginParameters->Count; i++) - { - PPH_STRING string = PhStartupParameters.PluginParameters->Items[i]; - PH_STRINGREF pluginName; - PH_STRINGREF parameter; - - if (PhSplitStringRefAtChar(&string->sr, ':', &pluginName, ¶meter) && - PhEqualStringRef(&pluginName, &plugin->Name, FALSE) && - parameter.Length != 0) - { - if (!parameters) - parameters = PhCreateList(3); - - PhAddItemList(parameters, PhCreateString2(¶meter)); - } - } - } - - PhInvokeCallback(PhGetPluginCallback(plugin, Callback), parameters); - - if (parameters) - { - PhDereferenceObjects(parameters->Items, parameters->Count); - PhDereferenceObject(parameters); - } - } -} - -BOOLEAN PhpValidatePluginName( - _In_ PPH_STRINGREF Name - ) -{ - SIZE_T i; - PWSTR buffer; - SIZE_T count; - - buffer = Name->Buffer; - count = Name->Length / sizeof(WCHAR); - - for (i = 0; i < count; i++) - { - if (!iswalnum(buffer[i]) && buffer[i] != ' ' && buffer[i] != '.' && buffer[i] != '_') - { - return FALSE; - } - } - - return TRUE; -} - -/** - * Registers a plugin with the host. - * - * \param Name A unique identifier for the plugin. The function fails - * if another plugin has already been registered with the same name. The - * name must only contain alphanumeric characters, spaces, dots and - * underscores. - * \param DllBase The base address of the plugin DLL. This is passed - * to the DllMain function. - * \param Information A variable which receives a pointer to the - * plugin's additional information block. This should be filled in after - * the function returns. - * - * \return A pointer to the plugin instance structure, or NULL if the - * function failed. - */ -PPH_PLUGIN PhRegisterPlugin( - _In_ PWSTR Name, - _In_ PVOID DllBase, - _Out_opt_ PPH_PLUGIN_INFORMATION *Information - ) -{ - PPH_PLUGIN plugin; - PH_STRINGREF pluginName; - PPH_AVL_LINKS existingLinks; - ULONG i; - PPH_STRING fileName; - - PhInitializeStringRefLongHint(&pluginName, Name); - - if (!PhpValidatePluginName(&pluginName)) - return NULL; - - fileName = PhGetDllFileName(DllBase, NULL); - - if (!fileName) - return NULL; - - plugin = PhAllocate(sizeof(PH_PLUGIN)); - memset(plugin, 0, sizeof(PH_PLUGIN)); - - plugin->Name = pluginName; - plugin->DllBase = DllBase; - - plugin->FileName = fileName; - - existingLinks = PhAddElementAvlTree(&PhPluginsByName, &plugin->Links); - - if (existingLinks) - { - // Another plugin has already been registered with the same name. - PhFree(plugin); - return NULL; - } - - for (i = 0; i < PluginCallbackMaximum; i++) - PhInitializeCallback(&plugin->Callbacks[i]); - - PhEmInitializeAppContext(&plugin->AppContext, &pluginName); - - if (Information) - *Information = &plugin->Information; - - return plugin; -} - -/** - * Locates a plugin instance structure. - * - * \param Name The name of the plugin. - * - * \return A plugin instance structure, or NULL if the plugin was not found. - */ -PPH_PLUGIN PhFindPlugin( - _In_ PWSTR Name - ) -{ - PH_STRINGREF name; - - PhInitializeStringRefLongHint(&name, Name); - - return PhFindPlugin2(&name); -} - -/** - * Locates a plugin instance structure. - * - * \param Name The name of the plugin. - * - * \return A plugin instance structure, or NULL if the plugin was not found. - */ -PPH_PLUGIN PhFindPlugin2( - _In_ PPH_STRINGREF Name - ) -{ - PPH_AVL_LINKS links; - PH_PLUGIN lookupPlugin; - - lookupPlugin.Name = *Name; - links = PhFindElementAvlTree(&PhPluginsByName, &lookupPlugin.Links); - - if (links) - return CONTAINING_RECORD(links, PH_PLUGIN, Links); - else - return NULL; -} - -/** - * Gets a pointer to a plugin's additional information block. - * - * \param Plugin The plugin instance structure. - * - * \return The plugin's additional information block. - */ -PPH_PLUGIN_INFORMATION PhGetPluginInformation( - _In_ PPH_PLUGIN Plugin - ) -{ - return &Plugin->Information; -} - -/** - * Retrieves a pointer to a plugin callback. - * - * \param Plugin A plugin instance structure. - * \param Callback The type of callback. - * - * \remarks The program invokes plugin callbacks for notifications - * specific to a plugin. - */ -PPH_CALLBACK PhGetPluginCallback( - _In_ PPH_PLUGIN Plugin, - _In_ PH_PLUGIN_CALLBACK Callback - ) -{ - if (Callback >= PluginCallbackMaximum) - PhRaiseStatus(STATUS_INVALID_PARAMETER_2); - - return &Plugin->Callbacks[Callback]; -} - -/** - * Retrieves a pointer to a general callback. - * - * \param Callback The type of callback. - * - * \remarks The program invokes general callbacks for system-wide - * notifications. - */ -PPH_CALLBACK PhGetGeneralCallback( - _In_ PH_GENERAL_CALLBACK Callback - ) -{ - if (Callback >= GeneralCallbackMaximum) - PhRaiseStatus(STATUS_INVALID_PARAMETER_2); - - return &GeneralCallbacks[Callback]; -} - -/** - * Reserves unique GUI identifiers. - * - * \param Count The number of identifiers to reserve. - * - * \return The start of the reserved range. - * - * \remarks The identifiers reserved by this function are - * guaranteed to be unique throughout the program. - */ -ULONG PhPluginReserveIds( - _In_ ULONG Count - ) -{ - ULONG nextPluginId; - - nextPluginId = NextPluginId; - NextPluginId += Count; - - return nextPluginId; -} - -/** - * Adds a menu item to the program's main menu. This function is - * deprecated. Use \c GeneralCallbackMainMenuInitializing instead. - * - * \param Plugin A plugin instance structure. - * \param Location A handle to the parent menu, or one of the following: - * \li \c PH_MENU_ITEM_LOCATION_VIEW The "View" menu. - * \li \c PH_MENU_ITEM_LOCATION_TOOLS The "Tools" menu. - * \param InsertAfter The text of the menu item to insert the - * new menu item after. The search is a case-insensitive prefix search - * that ignores prefix characters (ampersands). - * \param Id An identifier for the menu item. This should be unique - * within the plugin. - * \param Text The text of the menu item. - * \param Context A user-defined value for the menu item. - * - * \return TRUE if the function succeeded, otherwise FALSE. - * - * \remarks The \ref PluginCallbackMenuItem callback is invoked when - * the menu item is chosen, and the \ref PH_PLUGIN_MENU_ITEM structure - * will contain the \a Id and \a Context values passed to this function. - */ -ULONG_PTR PhPluginAddMenuItem( - _In_ PPH_PLUGIN Plugin, - _In_ ULONG_PTR Location, - _In_opt_ PWSTR InsertAfter, - _In_ ULONG Id, - _In_ PWSTR Text, - _In_opt_ PVOID Context - ) -{ - PH_ADD_MENU_ITEM addMenuItem; - - addMenuItem.Plugin = Plugin; - addMenuItem.InsertAfter = InsertAfter; - addMenuItem.Text = Text; - addMenuItem.Context = Context; - - if (Location < 0x1000) - { - addMenuItem.Location = (ULONG)Location; - } - else - { - return 0; - } - - addMenuItem.Flags = Id & PH_MENU_ITEM_VALID_FLAGS; - Id &= ~PH_MENU_ITEM_VALID_FLAGS; - addMenuItem.Id = Id; - - return ProcessHacker_AddMenuItem(PhMainWndHandle, &addMenuItem); -} - -/** - * Retrieves current system statistics. - */ -VOID PhPluginGetSystemStatistics( - _Out_ PPH_PLUGIN_SYSTEM_STATISTICS Statistics - ) -{ - Statistics->Performance = &PhPerfInformation; - - Statistics->NumberOfProcesses = PhTotalProcesses; - Statistics->NumberOfThreads = PhTotalThreads; - Statistics->NumberOfHandles = PhTotalHandles; - - Statistics->CpuKernelUsage = PhCpuKernelUsage; - Statistics->CpuUserUsage = PhCpuUserUsage; - - Statistics->IoReadDelta = PhIoReadDelta; - Statistics->IoWriteDelta = PhIoWriteDelta; - Statistics->IoOtherDelta = PhIoOtherDelta; - - Statistics->CommitPages = PhGetItemCircularBuffer_ULONG(&PhCommitHistory, 0); - Statistics->PhysicalPages = PhGetItemCircularBuffer_ULONG(&PhPhysicalHistory, 0); - - Statistics->MaxCpuProcessId = UlongToHandle(PhGetItemCircularBuffer_ULONG(&PhMaxCpuHistory, 0)); - Statistics->MaxIoProcessId = UlongToHandle(PhGetItemCircularBuffer_ULONG(&PhMaxIoHistory, 0)); - - Statistics->CpuKernelHistory = &PhCpuKernelHistory; - Statistics->CpuUserHistory = &PhCpuUserHistory; - Statistics->CpusKernelHistory = &PhCpusKernelHistory; - Statistics->CpusUserHistory = &PhCpusUserHistory; - Statistics->IoReadHistory = &PhIoReadHistory; - Statistics->IoWriteHistory = &PhIoWriteHistory; - Statistics->IoOtherHistory = &PhIoOtherHistory; - Statistics->CommitHistory = &PhCommitHistory; - Statistics->PhysicalHistory = &PhPhysicalHistory; - Statistics->MaxCpuHistory = &PhMaxCpuHistory; - Statistics->MaxIoHistory = &PhMaxIoHistory; -#ifdef PH_RECORD_MAX_USAGE - Statistics->MaxCpuUsageHistory = &PhMaxCpuUsageHistory; - Statistics->MaxIoReadOtherHistory = &PhMaxIoReadOtherHistory; - Statistics->MaxIoWriteHistory = &PhMaxIoWriteHistory; -#else - Statistics->MaxCpuUsageHistory = NULL; - Statistics->MaxIoReadOtherHistory = NULL; - Statistics->MaxIoWriteHistory = NULL; -#endif -} - -static VOID NTAPI PhpPluginEMenuItemDeleteFunction( - _In_ PPH_EMENU_ITEM Item - ) -{ - PPH_PLUGIN_MENU_ITEM pluginMenuItem; - - pluginMenuItem = Item->Context; - - if (pluginMenuItem->DeleteFunction) - pluginMenuItem->DeleteFunction(pluginMenuItem); - - PhFree(pluginMenuItem); -} - -/** - * Creates a menu item. - * - * \param Plugin A plugin instance structure. - * \param Flags A combination of flags. - * \param Id An identifier for the menu item. This should be unique - * within the plugin. - * \param Text The text of the menu item. - * \param Context A user-defined value for the menu item. - * - * \return A menu item object. This can then be inserted into another - * menu using PhInsertEMenuItem(). - * - * \remarks The \ref PluginCallbackMenuItem callback is invoked when - * the menu item is chosen, and the \ref PH_PLUGIN_MENU_ITEM structure - * will contain the \a Id and \a Context values passed to this function. - */ -PPH_EMENU_ITEM PhPluginCreateEMenuItem( - _In_ PPH_PLUGIN Plugin, - _In_ ULONG Flags, - _In_ ULONG Id, - _In_ PWSTR Text, - _In_opt_ PVOID Context - ) -{ - PPH_EMENU_ITEM item; - PPH_PLUGIN_MENU_ITEM pluginMenuItem; - - item = PhCreateEMenuItem(Flags, ID_PLUGIN_MENU_ITEM, Text, NULL, NULL); - - pluginMenuItem = PhAllocate(sizeof(PH_PLUGIN_MENU_ITEM)); - memset(pluginMenuItem, 0, sizeof(PH_PLUGIN_MENU_ITEM)); - pluginMenuItem->Plugin = Plugin; - pluginMenuItem->Id = Id; - pluginMenuItem->Context = Context; - - item->Context = pluginMenuItem; - item->DeleteFunction = PhpPluginEMenuItemDeleteFunction; - - return item; -} - -/** - * Adds a menu hook. - * - * \param MenuInfo The plugin menu information structure. - * \param Plugin A plugin instance structure. - * \param Context A user-defined value that is later accessible from the callback. - * - * \remarks The \ref PluginCallbackMenuHook callback is invoked when any menu item - * from the menu is chosen. - */ -BOOLEAN PhPluginAddMenuHook( - _Inout_ PPH_PLUGIN_MENU_INFORMATION MenuInfo, - _In_ PPH_PLUGIN Plugin, - _In_opt_ PVOID Context - ) -{ - PPHP_PLUGIN_MENU_HOOK hook; - - if (MenuInfo->Flags & PH_PLUGIN_MENU_DISALLOW_HOOKS) - return FALSE; - - if (!MenuInfo->PluginHookList) - MenuInfo->PluginHookList = PH_AUTO(PhCreateList(2)); - - hook = PH_AUTO(PhCreateAlloc(sizeof(PHP_PLUGIN_MENU_HOOK))); - hook->Plugin = Plugin; - hook->Context = Context; - PhAddItemList(MenuInfo->PluginHookList, hook); - - return TRUE; -} - -/** - * Initializes a plugin menu information structure. - * - * \param MenuInfo The structure to initialize. - * \param Menu The menu being shown. - * \param OwnerWindow The window that owns the menu. - * \param Flags Additional flags. - * - * \remarks This function is reserved for internal use. - */ -VOID PhPluginInitializeMenuInfo( - _Out_ PPH_PLUGIN_MENU_INFORMATION MenuInfo, - _In_opt_ PPH_EMENU Menu, - _In_ HWND OwnerWindow, - _In_ ULONG Flags - ) -{ - memset(MenuInfo, 0, sizeof(PH_PLUGIN_MENU_INFORMATION)); - MenuInfo->Menu = Menu; - MenuInfo->OwnerWindow = OwnerWindow; - MenuInfo->Flags = Flags; -} - -/** - * Triggers a plugin menu item. - * - * \param MenuInfo The plugin menu information structure. - * \param Item The menu item chosen by the user. - * - * \remarks This function is reserved for internal use. - */ -BOOLEAN PhPluginTriggerEMenuItem( - _In_ PPH_PLUGIN_MENU_INFORMATION MenuInfo, - _In_ PPH_EMENU_ITEM Item - ) -{ - PPH_PLUGIN_MENU_ITEM pluginMenuItem; - ULONG i; - PPHP_PLUGIN_MENU_HOOK hook; - PH_PLUGIN_MENU_HOOK_INFORMATION menuHookInfo; - - if (MenuInfo->PluginHookList) - { - for (i = 0; i < MenuInfo->PluginHookList->Count; i++) - { - hook = MenuInfo->PluginHookList->Items[i]; - menuHookInfo.MenuInfo = MenuInfo; - menuHookInfo.SelectedItem = Item; - menuHookInfo.Context = hook->Context; - menuHookInfo.Handled = FALSE; - PhInvokeCallback(PhGetPluginCallback(hook->Plugin, PluginCallbackMenuHook), &menuHookInfo); - - if (menuHookInfo.Handled) - return TRUE; - } - } - - if (Item->Id != ID_PLUGIN_MENU_ITEM) - return FALSE; - - pluginMenuItem = Item->Context; - - pluginMenuItem->OwnerWindow = MenuInfo->OwnerWindow; - - PhInvokeCallback(PhGetPluginCallback(pluginMenuItem->Plugin, PluginCallbackMenuItem), pluginMenuItem); - - return TRUE; -} - -/** - * Adds a column to a tree new control. - * - * \param Plugin A plugin instance structure. - * \param CmData The CmData value from the \ref PH_PLUGIN_TREENEW_INFORMATION - * structure. - * \param Column The column properties. - * \param SubId An identifier for the column. This should be unique within the - * plugin. - * \param Context A user-defined value. - * \param SortFunction The sort function for the column. - */ -BOOLEAN PhPluginAddTreeNewColumn( - _In_ PPH_PLUGIN Plugin, - _In_ PVOID CmData, - _In_ PPH_TREENEW_COLUMN Column, - _In_ ULONG SubId, - _In_opt_ PVOID Context, - _In_opt_ PPH_PLUGIN_TREENEW_SORT_FUNCTION SortFunction - ) -{ - return !!PhCmCreateColumn( - CmData, - Column, - Plugin, - SubId, - Context, - SortFunction - ); -} - -/** - * Sets the object extension size and callbacks for an object type. - * - * \param Plugin A plugin instance structure. - * \param ObjectType The type of object for which the extension is being registered. - * \param ExtensionSize The size of the extension, in bytes. - * \param CreateCallback The object creation callback. - * \param DeleteCallback The object deletion callback. - */ -VOID PhPluginSetObjectExtension( - _In_ PPH_PLUGIN Plugin, - _In_ PH_EM_OBJECT_TYPE ObjectType, - _In_ ULONG ExtensionSize, - _In_opt_ PPH_EM_OBJECT_CALLBACK CreateCallback, - _In_opt_ PPH_EM_OBJECT_CALLBACK DeleteCallback - ) -{ - PhEmSetObjectExtension( - &Plugin->AppContext, - ObjectType, - ExtensionSize, - CreateCallback, - DeleteCallback - ); -} - -/** - * Gets the object extension for an object. - * - * \param Plugin A plugin instance structure. - * \param Object The object. - * \param ObjectType The type of object for which an extension has been registered. - */ -PVOID PhPluginGetObjectExtension( - _In_ PPH_PLUGIN Plugin, - _In_ PVOID Object, - _In_ PH_EM_OBJECT_TYPE ObjectType - ) -{ - return PhEmGetObjectExtension( - &Plugin->AppContext, - ObjectType, - Object - ); -} - -/** - * Creates a notification icon. - * - * \param Plugin A plugin instance structure. - * \param SubId An identifier for the column. This should be unique within the - * plugin. - * \param Context A user-defined value. - * \param Text A string describing the notification icon. - * \param Flags A combination of flags. - * \li \c PH_NF_ICON_UNAVAILABLE The notification icon is currently unavailable. - * \param RegistrationData A \ref PH_NF_ICON_REGISTRATION_DATA structure that - * contains registration information. - */ -struct _PH_NF_ICON *PhPluginRegisterIcon( - _In_ PPH_PLUGIN Plugin, - _In_ ULONG SubId, - _In_opt_ PVOID Context, - _In_ PWSTR Text, - _In_ ULONG Flags, - _In_ struct _PH_NF_ICON_REGISTRATION_DATA *RegistrationData - ) -{ - return PhNfRegisterIcon( - Plugin, - SubId, - Context, - Text, - Flags, - RegistrationData->UpdateCallback, - RegistrationData->MessageCallback - ); -} - -/** - * Allows a plugin to receive all treenew messages, not just column-related ones. - * - * \param Plugin A plugin instance structure. - * \param CmData The CmData value from the \ref PH_PLUGIN_TREENEW_INFORMATION - * structure. - */ -VOID PhPluginEnableTreeNewNotify( - _In_ PPH_PLUGIN Plugin, - _In_ PVOID CmData - ) -{ - PhCmSetNotifyPlugin(CmData, Plugin); -} - -BOOLEAN PhPluginQueryPhSvc( - _Out_ PPH_PLUGIN_PHSVC_CLIENT Client - ) -{ - if (!PhSvcClServerProcessId) - return FALSE; - - Client->ServerProcessId = PhSvcClServerProcessId; - Client->FreeHeap = PhSvcpFreeHeap; - Client->CreateString = PhSvcpCreateString; - - return TRUE; -} - -NTSTATUS PhPluginCallPhSvc( - _In_ PPH_PLUGIN Plugin, - _In_ ULONG SubId, - _In_reads_bytes_opt_(InLength) PVOID InBuffer, - _In_ ULONG InLength, - _Out_writes_bytes_opt_(OutLength) PVOID OutBuffer, - _In_ ULONG OutLength - ) -{ - NTSTATUS status; - PPH_STRING apiId; - PH_FORMAT format[4]; - - PhInitFormatC(&format[0], '+'); - PhInitFormatSR(&format[1], Plugin->Name); - PhInitFormatC(&format[2], '+'); - PhInitFormatU(&format[3], SubId); - apiId = PhFormat(format, 4, 50); - - status = PhSvcCallPlugin(&apiId->sr, InBuffer, InLength, OutBuffer, OutLength); - PhDereferenceObject(apiId); - - return status; -} +/* + * Process Hacker - + * plugin support + * + * Copyright (C) 2010-2015 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +typedef struct _PHP_PLUGIN_LOAD_ERROR +{ + PPH_STRING FileName; + PPH_STRING ErrorMessage; +} PHP_PLUGIN_LOAD_ERROR, *PPHP_PLUGIN_LOAD_ERROR; + +typedef struct _PHP_PLUGIN_MENU_HOOK +{ + PPH_PLUGIN Plugin; + PVOID Context; +} PHP_PLUGIN_MENU_HOOK, *PPHP_PLUGIN_MENU_HOOK; + +INT NTAPI PhpPluginsCompareFunction( + _In_ PPH_AVL_LINKS Links1, + _In_ PPH_AVL_LINKS Links2 + ); + +BOOLEAN PhLoadPlugin( + _In_ PPH_STRING FileName + ); + +VOID PhpExecuteCallbackForAllPlugins( + _In_ PH_PLUGIN_CALLBACK Callback, + _In_ BOOLEAN StartupParameters + ); + +PH_AVL_TREE PhPluginsByName = PH_AVL_TREE_INIT(PhpPluginsCompareFunction); + +static PH_CALLBACK GeneralCallbacks[GeneralCallbackMaximum]; +static PPH_STRING PluginsDirectory; +static PPH_LIST LoadErrors; +static ULONG NextPluginId = IDPLUGINS + 1; + +VOID PhPluginsInitialization( + VOID + ) +{ + ULONG i; + + for (i = 0; i < GeneralCallbackMaximum; i++) + PhInitializeCallback(&GeneralCallbacks[i]); +} + +INT NTAPI PhpPluginsCompareFunction( + _In_ PPH_AVL_LINKS Links1, + _In_ PPH_AVL_LINKS Links2 + ) +{ + PPH_PLUGIN plugin1 = CONTAINING_RECORD(Links1, PH_PLUGIN, Links); + PPH_PLUGIN plugin2 = CONTAINING_RECORD(Links2, PH_PLUGIN, Links); + + return PhCompareStringRef(&plugin1->Name, &plugin2->Name, FALSE); +} + +BOOLEAN PhpLocateDisabledPlugin( + _In_ PPH_STRING List, + _In_ PPH_STRINGREF BaseName, + _Out_opt_ PULONG FoundIndex + ) +{ + PH_STRINGREF namePart; + PH_STRINGREF remainingPart; + + remainingPart = List->sr; + + while (remainingPart.Length != 0) + { + PhSplitStringRefAtChar(&remainingPart, '|', &namePart, &remainingPart); + + if (PhEqualStringRef(&namePart, BaseName, TRUE)) + { + if (FoundIndex) + *FoundIndex = (ULONG)(namePart.Buffer - List->Buffer); + + return TRUE; + } + } + + return FALSE; +} + +BOOLEAN PhIsPluginDisabled( + _In_ PPH_STRINGREF BaseName + ) +{ + BOOLEAN found; + PPH_STRING disabled; + + disabled = PhGetStringSetting(L"DisabledPlugins"); + found = PhpLocateDisabledPlugin(disabled, BaseName, NULL); + PhDereferenceObject(disabled); + + return found; +} + +VOID PhSetPluginDisabled( + _In_ PPH_STRINGREF BaseName, + _In_ BOOLEAN Disable + ) +{ + BOOLEAN found; + PPH_STRING disabled; + ULONG foundIndex; + PPH_STRING newDisabled; + + disabled = PhGetStringSetting(L"DisabledPlugins"); + + found = PhpLocateDisabledPlugin(disabled, BaseName, &foundIndex); + + if (Disable && !found) + { + // We need to add the plugin to the disabled list. + + if (disabled->Length != 0) + { + // We have other disabled plugins. Append a pipe character followed by the plugin name. + newDisabled = PhCreateStringEx(NULL, disabled->Length + sizeof(WCHAR) + BaseName->Length); + memcpy(newDisabled->Buffer, disabled->Buffer, disabled->Length); + newDisabled->Buffer[disabled->Length / 2] = '|'; + memcpy(&newDisabled->Buffer[disabled->Length / 2 + 1], BaseName->Buffer, BaseName->Length); + PhSetStringSetting2(L"DisabledPlugins", &newDisabled->sr); + PhDereferenceObject(newDisabled); + } + else + { + // This is the first disabled plugin. + PhSetStringSetting2(L"DisabledPlugins", BaseName); + } + } + else if (!Disable && found) + { + ULONG removeCount; + + // We need to remove the plugin from the disabled list. + + removeCount = (ULONG)BaseName->Length / 2; + + if (foundIndex + (ULONG)BaseName->Length / 2 < (ULONG)disabled->Length / 2) + { + // Remove the following pipe character as well. + removeCount++; + } + else if (foundIndex != 0) + { + // Remove the preceding pipe character as well. + foundIndex--; + removeCount++; + } + + newDisabled = PhCreateStringEx(NULL, disabled->Length - removeCount * sizeof(WCHAR)); + memcpy(newDisabled->Buffer, disabled->Buffer, foundIndex * sizeof(WCHAR)); + memcpy(&newDisabled->Buffer[foundIndex], &disabled->Buffer[foundIndex + removeCount], + disabled->Length - removeCount * sizeof(WCHAR) - foundIndex * sizeof(WCHAR)); + PhSetStringSetting2(L"DisabledPlugins", &newDisabled->sr); + PhDereferenceObject(newDisabled); + } + + PhDereferenceObject(disabled); +} + +static BOOLEAN EnumPluginsDirectoryCallback( + _In_ PFILE_DIRECTORY_INFORMATION Information, + _In_opt_ PVOID Context + ) +{ + PH_STRINGREF baseName; + PPH_STRING fileName; + + baseName.Buffer = Information->FileName; + baseName.Length = Information->FileNameLength; + + if (PhEndsWithStringRef2(&baseName, L".dll", TRUE)) + { + if (!PhIsPluginDisabled(&baseName)) + { + fileName = PhCreateStringEx(NULL, PluginsDirectory->Length + Information->FileNameLength); + memcpy(fileName->Buffer, PluginsDirectory->Buffer, PluginsDirectory->Length); + memcpy(&fileName->Buffer[PluginsDirectory->Length / 2], Information->FileName, Information->FileNameLength); + + PhLoadPlugin(fileName); + + PhDereferenceObject(fileName); + } + } + + return TRUE; +} + +/** + * Loads plugins from the default plugins directory. + */ +VOID PhLoadPlugins( + VOID + ) +{ + HANDLE pluginsDirectoryHandle; + PPH_STRING pluginsDirectory; + + pluginsDirectory = PhGetStringSetting(L"PluginsDirectory"); + + if (RtlDetermineDosPathNameType_U(pluginsDirectory->Buffer) == RtlPathTypeRelative) + { + // Not absolute. Make sure it is. + PluginsDirectory = PhConcatStrings(4, PhApplicationDirectory->Buffer, L"\\", pluginsDirectory->Buffer, L"\\"); + PhDereferenceObject(pluginsDirectory); + } + else + { + PluginsDirectory = pluginsDirectory; + } + + if (NT_SUCCESS(PhCreateFileWin32( + &pluginsDirectoryHandle, + PluginsDirectory->Buffer, + FILE_GENERIC_READ, + 0, + FILE_SHARE_READ, + FILE_OPEN, + FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT + ))) + { + UNICODE_STRING pattern = RTL_CONSTANT_STRING(L"*.dll"); + + PhEnumDirectoryFile(pluginsDirectoryHandle, &pattern, EnumPluginsDirectoryCallback, NULL); + NtClose(pluginsDirectoryHandle); + } + + // Handle load errors. + // In certain startup modes we want to ignore all plugin load errors. + if (LoadErrors && LoadErrors->Count != 0 && !PhStartupParameters.PhSvc) + { + PH_STRING_BUILDER sb; + ULONG i; + PPHP_PLUGIN_LOAD_ERROR loadError; + PPH_STRING baseName; + + PhInitializeStringBuilder(&sb, 100); + PhAppendStringBuilder2(&sb, L"Unable to load the following plugin(s):\n\n"); + + for (i = 0; i < LoadErrors->Count; i++) + { + loadError = LoadErrors->Items[i]; + baseName = PhGetBaseName(loadError->FileName); + PhAppendFormatStringBuilder(&sb, L"%s: %s\n", + baseName->Buffer, PhGetStringOrDefault(loadError->ErrorMessage, L"An unknown error occurred.")); + PhDereferenceObject(baseName); + } + + PhAppendStringBuilder2(&sb, L"\nDo you want to disable the above plugin(s)?"); + + if (PhShowMessage( + NULL, + MB_ICONERROR | MB_YESNO, + sb.String->Buffer + ) == IDYES) + { + ULONG i; + + for (i = 0; i < LoadErrors->Count; i++) + { + loadError = LoadErrors->Items[i]; + baseName = PhGetBaseName(loadError->FileName); + PhSetPluginDisabled(&baseName->sr, TRUE); + PhDereferenceObject(baseName); + } + } + + PhDeleteStringBuilder(&sb); + } + + // When we loaded settings before, we didn't know about plugin settings, so they + // went into the ignored settings list. Now that they've had a chance to add + // settings, we should scan the ignored settings list and move the settings to + // the right places. + if (PhSettingsFileName) + PhConvertIgnoredSettings(); + + PhpExecuteCallbackForAllPlugins(PluginCallbackLoad, TRUE); +} + +/** + * Notifies all plugins that the program is shutting down. + */ +VOID PhUnloadPlugins( + VOID + ) +{ + PhpExecuteCallbackForAllPlugins(PluginCallbackUnload, FALSE); +} + +/** + * Loads a plugin. + * + * \param FileName The full file name of the plugin. + */ +BOOLEAN PhLoadPlugin( + _In_ PPH_STRING FileName + ) +{ + BOOLEAN success; + PPH_STRING fileName; + PPH_STRING errorMessage; + + fileName = PhGetFullPath(FileName->Buffer, NULL); + + if (!fileName) + PhSetReference(&fileName, FileName); + + success = TRUE; + + if (!LoadLibrary(fileName->Buffer)) + { + success = FALSE; + errorMessage = PhGetWin32Message(GetLastError()); + } + + if (!success) + { + PPHP_PLUGIN_LOAD_ERROR loadError; + + loadError = PhAllocate(sizeof(PHP_PLUGIN_LOAD_ERROR)); + PhSetReference(&loadError->FileName, fileName); + PhSetReference(&loadError->ErrorMessage, errorMessage); + + if (!LoadErrors) + LoadErrors = PhCreateList(2); + + PhAddItemList(LoadErrors, loadError); + + if (errorMessage) + PhDereferenceObject(errorMessage); + } + + PhDereferenceObject(fileName); + + return success; +} + +VOID PhpExecuteCallbackForAllPlugins( + _In_ PH_PLUGIN_CALLBACK Callback, + _In_ BOOLEAN StartupParameters + ) +{ + PPH_AVL_LINKS links; + + for (links = PhMinimumElementAvlTree(&PhPluginsByName); links; links = PhSuccessorElementAvlTree(links)) + { + PPH_PLUGIN plugin = CONTAINING_RECORD(links, PH_PLUGIN, Links); + PPH_LIST parameters = NULL; + + // Find relevant startup parameters for this plugin. + if (StartupParameters && PhStartupParameters.PluginParameters) + { + ULONG i; + + for (i = 0; i < PhStartupParameters.PluginParameters->Count; i++) + { + PPH_STRING string = PhStartupParameters.PluginParameters->Items[i]; + PH_STRINGREF pluginName; + PH_STRINGREF parameter; + + if (PhSplitStringRefAtChar(&string->sr, ':', &pluginName, ¶meter) && + PhEqualStringRef(&pluginName, &plugin->Name, FALSE) && + parameter.Length != 0) + { + if (!parameters) + parameters = PhCreateList(3); + + PhAddItemList(parameters, PhCreateString2(¶meter)); + } + } + } + + PhInvokeCallback(PhGetPluginCallback(plugin, Callback), parameters); + + if (parameters) + { + PhDereferenceObjects(parameters->Items, parameters->Count); + PhDereferenceObject(parameters); + } + } +} + +BOOLEAN PhpValidatePluginName( + _In_ PPH_STRINGREF Name + ) +{ + SIZE_T i; + PWSTR buffer; + SIZE_T count; + + buffer = Name->Buffer; + count = Name->Length / sizeof(WCHAR); + + for (i = 0; i < count; i++) + { + if (!iswalnum(buffer[i]) && buffer[i] != ' ' && buffer[i] != '.' && buffer[i] != '_') + { + return FALSE; + } + } + + return TRUE; +} + +/** + * Registers a plugin with the host. + * + * \param Name A unique identifier for the plugin. The function fails + * if another plugin has already been registered with the same name. The + * name must only contain alphanumeric characters, spaces, dots and + * underscores. + * \param DllBase The base address of the plugin DLL. This is passed + * to the DllMain function. + * \param Information A variable which receives a pointer to the + * plugin's additional information block. This should be filled in after + * the function returns. + * + * \return A pointer to the plugin instance structure, or NULL if the + * function failed. + */ +PPH_PLUGIN PhRegisterPlugin( + _In_ PWSTR Name, + _In_ PVOID DllBase, + _Out_opt_ PPH_PLUGIN_INFORMATION *Information + ) +{ + PPH_PLUGIN plugin; + PH_STRINGREF pluginName; + PPH_AVL_LINKS existingLinks; + ULONG i; + PPH_STRING fileName; + + PhInitializeStringRefLongHint(&pluginName, Name); + + if (!PhpValidatePluginName(&pluginName)) + return NULL; + + fileName = PhGetDllFileName(DllBase, NULL); + + if (!fileName) + return NULL; + + plugin = PhAllocate(sizeof(PH_PLUGIN)); + memset(plugin, 0, sizeof(PH_PLUGIN)); + + plugin->Name = pluginName; + plugin->DllBase = DllBase; + + plugin->FileName = fileName; + + existingLinks = PhAddElementAvlTree(&PhPluginsByName, &plugin->Links); + + if (existingLinks) + { + // Another plugin has already been registered with the same name. + PhFree(plugin); + return NULL; + } + + for (i = 0; i < PluginCallbackMaximum; i++) + PhInitializeCallback(&plugin->Callbacks[i]); + + PhEmInitializeAppContext(&plugin->AppContext, &pluginName); + + if (Information) + *Information = &plugin->Information; + + return plugin; +} + +/** + * Locates a plugin instance structure. + * + * \param Name The name of the plugin. + * + * \return A plugin instance structure, or NULL if the plugin was not found. + */ +PPH_PLUGIN PhFindPlugin( + _In_ PWSTR Name + ) +{ + PH_STRINGREF name; + + PhInitializeStringRefLongHint(&name, Name); + + return PhFindPlugin2(&name); +} + +/** + * Locates a plugin instance structure. + * + * \param Name The name of the plugin. + * + * \return A plugin instance structure, or NULL if the plugin was not found. + */ +PPH_PLUGIN PhFindPlugin2( + _In_ PPH_STRINGREF Name + ) +{ + PPH_AVL_LINKS links; + PH_PLUGIN lookupPlugin; + + lookupPlugin.Name = *Name; + links = PhFindElementAvlTree(&PhPluginsByName, &lookupPlugin.Links); + + if (links) + return CONTAINING_RECORD(links, PH_PLUGIN, Links); + else + return NULL; +} + +/** + * Gets a pointer to a plugin's additional information block. + * + * \param Plugin The plugin instance structure. + * + * \return The plugin's additional information block. + */ +PPH_PLUGIN_INFORMATION PhGetPluginInformation( + _In_ PPH_PLUGIN Plugin + ) +{ + return &Plugin->Information; +} + +/** + * Retrieves a pointer to a plugin callback. + * + * \param Plugin A plugin instance structure. + * \param Callback The type of callback. + * + * \remarks The program invokes plugin callbacks for notifications + * specific to a plugin. + */ +PPH_CALLBACK PhGetPluginCallback( + _In_ PPH_PLUGIN Plugin, + _In_ PH_PLUGIN_CALLBACK Callback + ) +{ + if (Callback >= PluginCallbackMaximum) + PhRaiseStatus(STATUS_INVALID_PARAMETER_2); + + return &Plugin->Callbacks[Callback]; +} + +/** + * Retrieves a pointer to a general callback. + * + * \param Callback The type of callback. + * + * \remarks The program invokes general callbacks for system-wide + * notifications. + */ +PPH_CALLBACK PhGetGeneralCallback( + _In_ PH_GENERAL_CALLBACK Callback + ) +{ + if (Callback >= GeneralCallbackMaximum) + PhRaiseStatus(STATUS_INVALID_PARAMETER_2); + + return &GeneralCallbacks[Callback]; +} + +/** + * Reserves unique GUI identifiers. + * + * \param Count The number of identifiers to reserve. + * + * \return The start of the reserved range. + * + * \remarks The identifiers reserved by this function are + * guaranteed to be unique throughout the program. + */ +ULONG PhPluginReserveIds( + _In_ ULONG Count + ) +{ + ULONG nextPluginId; + + nextPluginId = NextPluginId; + NextPluginId += Count; + + return nextPluginId; +} + +/** + * Adds a menu item to the program's main menu. This function is + * deprecated. Use \c GeneralCallbackMainMenuInitializing instead. + * + * \param Plugin A plugin instance structure. + * \param Location A handle to the parent menu, or one of the following: + * \li \c PH_MENU_ITEM_LOCATION_VIEW The "View" menu. + * \li \c PH_MENU_ITEM_LOCATION_TOOLS The "Tools" menu. + * \param InsertAfter The text of the menu item to insert the + * new menu item after. The search is a case-insensitive prefix search + * that ignores prefix characters (ampersands). + * \param Id An identifier for the menu item. This should be unique + * within the plugin. + * \param Text The text of the menu item. + * \param Context A user-defined value for the menu item. + * + * \return TRUE if the function succeeded, otherwise FALSE. + * + * \remarks The \ref PluginCallbackMenuItem callback is invoked when + * the menu item is chosen, and the \ref PH_PLUGIN_MENU_ITEM structure + * will contain the \a Id and \a Context values passed to this function. + */ +ULONG_PTR PhPluginAddMenuItem( + _In_ PPH_PLUGIN Plugin, + _In_ ULONG_PTR Location, + _In_opt_ PWSTR InsertAfter, + _In_ ULONG Id, + _In_ PWSTR Text, + _In_opt_ PVOID Context + ) +{ + PH_ADD_MENU_ITEM addMenuItem; + + addMenuItem.Plugin = Plugin; + addMenuItem.InsertAfter = InsertAfter; + addMenuItem.Text = Text; + addMenuItem.Context = Context; + + if (Location < 0x1000) + { + addMenuItem.Location = (ULONG)Location; + } + else + { + return 0; + } + + addMenuItem.Flags = Id & PH_MENU_ITEM_VALID_FLAGS; + Id &= ~PH_MENU_ITEM_VALID_FLAGS; + addMenuItem.Id = Id; + + return ProcessHacker_AddMenuItem(PhMainWndHandle, &addMenuItem); +} + +/** + * Retrieves current system statistics. + */ +VOID PhPluginGetSystemStatistics( + _Out_ PPH_PLUGIN_SYSTEM_STATISTICS Statistics + ) +{ + Statistics->Performance = &PhPerfInformation; + + Statistics->NumberOfProcesses = PhTotalProcesses; + Statistics->NumberOfThreads = PhTotalThreads; + Statistics->NumberOfHandles = PhTotalHandles; + + Statistics->CpuKernelUsage = PhCpuKernelUsage; + Statistics->CpuUserUsage = PhCpuUserUsage; + + Statistics->IoReadDelta = PhIoReadDelta; + Statistics->IoWriteDelta = PhIoWriteDelta; + Statistics->IoOtherDelta = PhIoOtherDelta; + + Statistics->CommitPages = PhGetItemCircularBuffer_ULONG(&PhCommitHistory, 0); + Statistics->PhysicalPages = PhGetItemCircularBuffer_ULONG(&PhPhysicalHistory, 0); + + Statistics->MaxCpuProcessId = UlongToHandle(PhGetItemCircularBuffer_ULONG(&PhMaxCpuHistory, 0)); + Statistics->MaxIoProcessId = UlongToHandle(PhGetItemCircularBuffer_ULONG(&PhMaxIoHistory, 0)); + + Statistics->CpuKernelHistory = &PhCpuKernelHistory; + Statistics->CpuUserHistory = &PhCpuUserHistory; + Statistics->CpusKernelHistory = &PhCpusKernelHistory; + Statistics->CpusUserHistory = &PhCpusUserHistory; + Statistics->IoReadHistory = &PhIoReadHistory; + Statistics->IoWriteHistory = &PhIoWriteHistory; + Statistics->IoOtherHistory = &PhIoOtherHistory; + Statistics->CommitHistory = &PhCommitHistory; + Statistics->PhysicalHistory = &PhPhysicalHistory; + Statistics->MaxCpuHistory = &PhMaxCpuHistory; + Statistics->MaxIoHistory = &PhMaxIoHistory; +#ifdef PH_RECORD_MAX_USAGE + Statistics->MaxCpuUsageHistory = &PhMaxCpuUsageHistory; + Statistics->MaxIoReadOtherHistory = &PhMaxIoReadOtherHistory; + Statistics->MaxIoWriteHistory = &PhMaxIoWriteHistory; +#else + Statistics->MaxCpuUsageHistory = NULL; + Statistics->MaxIoReadOtherHistory = NULL; + Statistics->MaxIoWriteHistory = NULL; +#endif +} + +static VOID NTAPI PhpPluginEMenuItemDeleteFunction( + _In_ PPH_EMENU_ITEM Item + ) +{ + PPH_PLUGIN_MENU_ITEM pluginMenuItem; + + pluginMenuItem = Item->Context; + + if (pluginMenuItem->DeleteFunction) + pluginMenuItem->DeleteFunction(pluginMenuItem); + + PhFree(pluginMenuItem); +} + +/** + * Creates a menu item. + * + * \param Plugin A plugin instance structure. + * \param Flags A combination of flags. + * \param Id An identifier for the menu item. This should be unique + * within the plugin. + * \param Text The text of the menu item. + * \param Context A user-defined value for the menu item. + * + * \return A menu item object. This can then be inserted into another + * menu using PhInsertEMenuItem(). + * + * \remarks The \ref PluginCallbackMenuItem callback is invoked when + * the menu item is chosen, and the \ref PH_PLUGIN_MENU_ITEM structure + * will contain the \a Id and \a Context values passed to this function. + */ +PPH_EMENU_ITEM PhPluginCreateEMenuItem( + _In_ PPH_PLUGIN Plugin, + _In_ ULONG Flags, + _In_ ULONG Id, + _In_ PWSTR Text, + _In_opt_ PVOID Context + ) +{ + PPH_EMENU_ITEM item; + PPH_PLUGIN_MENU_ITEM pluginMenuItem; + + item = PhCreateEMenuItem(Flags, ID_PLUGIN_MENU_ITEM, Text, NULL, NULL); + + pluginMenuItem = PhAllocate(sizeof(PH_PLUGIN_MENU_ITEM)); + memset(pluginMenuItem, 0, sizeof(PH_PLUGIN_MENU_ITEM)); + pluginMenuItem->Plugin = Plugin; + pluginMenuItem->Id = Id; + pluginMenuItem->Context = Context; + + item->Context = pluginMenuItem; + item->DeleteFunction = PhpPluginEMenuItemDeleteFunction; + + return item; +} + +/** + * Adds a menu hook. + * + * \param MenuInfo The plugin menu information structure. + * \param Plugin A plugin instance structure. + * \param Context A user-defined value that is later accessible from the callback. + * + * \remarks The \ref PluginCallbackMenuHook callback is invoked when any menu item + * from the menu is chosen. + */ +BOOLEAN PhPluginAddMenuHook( + _Inout_ PPH_PLUGIN_MENU_INFORMATION MenuInfo, + _In_ PPH_PLUGIN Plugin, + _In_opt_ PVOID Context + ) +{ + PPHP_PLUGIN_MENU_HOOK hook; + + if (MenuInfo->Flags & PH_PLUGIN_MENU_DISALLOW_HOOKS) + return FALSE; + + if (!MenuInfo->PluginHookList) + MenuInfo->PluginHookList = PH_AUTO(PhCreateList(2)); + + hook = PH_AUTO(PhCreateAlloc(sizeof(PHP_PLUGIN_MENU_HOOK))); + hook->Plugin = Plugin; + hook->Context = Context; + PhAddItemList(MenuInfo->PluginHookList, hook); + + return TRUE; +} + +/** + * Initializes a plugin menu information structure. + * + * \param MenuInfo The structure to initialize. + * \param Menu The menu being shown. + * \param OwnerWindow The window that owns the menu. + * \param Flags Additional flags. + * + * \remarks This function is reserved for internal use. + */ +VOID PhPluginInitializeMenuInfo( + _Out_ PPH_PLUGIN_MENU_INFORMATION MenuInfo, + _In_opt_ PPH_EMENU Menu, + _In_ HWND OwnerWindow, + _In_ ULONG Flags + ) +{ + memset(MenuInfo, 0, sizeof(PH_PLUGIN_MENU_INFORMATION)); + MenuInfo->Menu = Menu; + MenuInfo->OwnerWindow = OwnerWindow; + MenuInfo->Flags = Flags; +} + +/** + * Triggers a plugin menu item. + * + * \param MenuInfo The plugin menu information structure. + * \param Item The menu item chosen by the user. + * + * \remarks This function is reserved for internal use. + */ +BOOLEAN PhPluginTriggerEMenuItem( + _In_ PPH_PLUGIN_MENU_INFORMATION MenuInfo, + _In_ PPH_EMENU_ITEM Item + ) +{ + PPH_PLUGIN_MENU_ITEM pluginMenuItem; + ULONG i; + PPHP_PLUGIN_MENU_HOOK hook; + PH_PLUGIN_MENU_HOOK_INFORMATION menuHookInfo; + + if (MenuInfo->PluginHookList) + { + for (i = 0; i < MenuInfo->PluginHookList->Count; i++) + { + hook = MenuInfo->PluginHookList->Items[i]; + menuHookInfo.MenuInfo = MenuInfo; + menuHookInfo.SelectedItem = Item; + menuHookInfo.Context = hook->Context; + menuHookInfo.Handled = FALSE; + PhInvokeCallback(PhGetPluginCallback(hook->Plugin, PluginCallbackMenuHook), &menuHookInfo); + + if (menuHookInfo.Handled) + return TRUE; + } + } + + if (Item->Id != ID_PLUGIN_MENU_ITEM) + return FALSE; + + pluginMenuItem = Item->Context; + + pluginMenuItem->OwnerWindow = MenuInfo->OwnerWindow; + + PhInvokeCallback(PhGetPluginCallback(pluginMenuItem->Plugin, PluginCallbackMenuItem), pluginMenuItem); + + return TRUE; +} + +/** + * Adds a column to a tree new control. + * + * \param Plugin A plugin instance structure. + * \param CmData The CmData value from the \ref PH_PLUGIN_TREENEW_INFORMATION + * structure. + * \param Column The column properties. + * \param SubId An identifier for the column. This should be unique within the + * plugin. + * \param Context A user-defined value. + * \param SortFunction The sort function for the column. + */ +BOOLEAN PhPluginAddTreeNewColumn( + _In_ PPH_PLUGIN Plugin, + _In_ PVOID CmData, + _In_ PPH_TREENEW_COLUMN Column, + _In_ ULONG SubId, + _In_opt_ PVOID Context, + _In_opt_ PPH_PLUGIN_TREENEW_SORT_FUNCTION SortFunction + ) +{ + return !!PhCmCreateColumn( + CmData, + Column, + Plugin, + SubId, + Context, + SortFunction + ); +} + +/** + * Sets the object extension size and callbacks for an object type. + * + * \param Plugin A plugin instance structure. + * \param ObjectType The type of object for which the extension is being registered. + * \param ExtensionSize The size of the extension, in bytes. + * \param CreateCallback The object creation callback. + * \param DeleteCallback The object deletion callback. + */ +VOID PhPluginSetObjectExtension( + _In_ PPH_PLUGIN Plugin, + _In_ PH_EM_OBJECT_TYPE ObjectType, + _In_ ULONG ExtensionSize, + _In_opt_ PPH_EM_OBJECT_CALLBACK CreateCallback, + _In_opt_ PPH_EM_OBJECT_CALLBACK DeleteCallback + ) +{ + PhEmSetObjectExtension( + &Plugin->AppContext, + ObjectType, + ExtensionSize, + CreateCallback, + DeleteCallback + ); +} + +/** + * Gets the object extension for an object. + * + * \param Plugin A plugin instance structure. + * \param Object The object. + * \param ObjectType The type of object for which an extension has been registered. + */ +PVOID PhPluginGetObjectExtension( + _In_ PPH_PLUGIN Plugin, + _In_ PVOID Object, + _In_ PH_EM_OBJECT_TYPE ObjectType + ) +{ + return PhEmGetObjectExtension( + &Plugin->AppContext, + ObjectType, + Object + ); +} + +/** + * Creates a notification icon. + * + * \param Plugin A plugin instance structure. + * \param SubId An identifier for the column. This should be unique within the + * plugin. + * \param Context A user-defined value. + * \param Text A string describing the notification icon. + * \param Flags A combination of flags. + * \li \c PH_NF_ICON_UNAVAILABLE The notification icon is currently unavailable. + * \param RegistrationData A \ref PH_NF_ICON_REGISTRATION_DATA structure that + * contains registration information. + */ +struct _PH_NF_ICON *PhPluginRegisterIcon( + _In_ PPH_PLUGIN Plugin, + _In_ ULONG SubId, + _In_opt_ PVOID Context, + _In_ PWSTR Text, + _In_ ULONG Flags, + _In_ struct _PH_NF_ICON_REGISTRATION_DATA *RegistrationData + ) +{ + return PhNfRegisterIcon( + Plugin, + SubId, + Context, + Text, + Flags, + RegistrationData->UpdateCallback, + RegistrationData->MessageCallback + ); +} + +/** + * Allows a plugin to receive all treenew messages, not just column-related ones. + * + * \param Plugin A plugin instance structure. + * \param CmData The CmData value from the \ref PH_PLUGIN_TREENEW_INFORMATION + * structure. + */ +VOID PhPluginEnableTreeNewNotify( + _In_ PPH_PLUGIN Plugin, + _In_ PVOID CmData + ) +{ + PhCmSetNotifyPlugin(CmData, Plugin); +} + +BOOLEAN PhPluginQueryPhSvc( + _Out_ PPH_PLUGIN_PHSVC_CLIENT Client + ) +{ + if (!PhSvcClServerProcessId) + return FALSE; + + Client->ServerProcessId = PhSvcClServerProcessId; + Client->FreeHeap = PhSvcpFreeHeap; + Client->CreateString = PhSvcpCreateString; + + return TRUE; +} + +NTSTATUS PhPluginCallPhSvc( + _In_ PPH_PLUGIN Plugin, + _In_ ULONG SubId, + _In_reads_bytes_opt_(InLength) PVOID InBuffer, + _In_ ULONG InLength, + _Out_writes_bytes_opt_(OutLength) PVOID OutBuffer, + _In_ ULONG OutLength + ) +{ + NTSTATUS status; + PPH_STRING apiId; + PH_FORMAT format[4]; + + PhInitFormatC(&format[0], '+'); + PhInitFormatSR(&format[1], Plugin->Name); + PhInitFormatC(&format[2], '+'); + PhInitFormatU(&format[3], SubId); + apiId = PhFormat(format, 4, 50); + + status = PhSvcCallPlugin(&apiId->sr, InBuffer, InLength, OutBuffer, OutLength); + PhDereferenceObject(apiId); + + return status; +} diff --git a/ProcessHacker/plugman.c b/ProcessHacker/plugman.c index 680a7dcfce9c..a7c4314126a5 100644 --- a/ProcessHacker/plugman.c +++ b/ProcessHacker/plugman.c @@ -1,445 +1,445 @@ -/* - * Process Hacker - - * plugins - * - * Copyright (C) 2010-2011 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include - -#include -#include -#include - -#define IS_PLUGIN_LOADED(Plugin) (!!(Plugin)->AppContext.AppName.Buffer) -#define STR_OR_DEFAULT(String, Default) ((String) ? (String) : (Default)) - -static HWND PluginsLv; -static PPH_PLUGIN SelectedPlugin; -static PPH_LIST DisabledPluginInstances; // fake PH_PLUGIN structures for disabled plugins -static PPH_HASHTABLE DisabledPluginLookup; // list of all disabled plugins (including fake structures) by PH_PLUGIN address - -INT_PTR CALLBACK PhpPluginsDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -VOID PhShowPluginsDialog( - _In_ HWND ParentWindowHandle - ) -{ - if (PhPluginsEnabled) - { - DialogBox( - PhInstanceHandle, - MAKEINTRESOURCE(IDD_PLUGINS), - ParentWindowHandle, - PhpPluginsDlgProc - ); - } - else - { - PhShowInformation(ParentWindowHandle, - L"Plugins are not enabled. To use plugins enable them in Options and restart Process Hacker."); - } -} - -PWSTR PhpGetPluginBaseName( - _In_ PPH_PLUGIN Plugin - ) -{ - if (Plugin->FileName) - { - PH_STRINGREF pathNamePart; - PH_STRINGREF baseNamePart; - - if (PhSplitStringRefAtLastChar(&Plugin->FileName->sr, '\\', &pathNamePart, &baseNamePart)) - return baseNamePart.Buffer; - else - return Plugin->FileName->Buffer; - } - else - { - // Fake disabled plugin. - return Plugin->Name.Buffer; - } -} - -PWSTR PhpGetPluginDisableButtonText( - _In_ PWSTR BaseName - ) -{ - PH_STRINGREF baseName; - - PhInitializeStringRefLongHint(&baseName, BaseName); - - if (PhIsPluginDisabled(&baseName)) - return L"Enable"; - else - return L"Disable"; -} - -VOID PhpRefreshPluginDetails( - _In_ HWND hwndDlg - ) -{ - PPH_STRING fileName; - PH_IMAGE_VERSION_INFO versionInfo; - - if (SelectedPlugin && SelectedPlugin->FileName) // if there's no FileName, then it's a fake disabled plugin instance - { - fileName = SelectedPlugin->FileName; - - SetDlgItemText(hwndDlg, IDC_NAME, SelectedPlugin->Information.DisplayName ? SelectedPlugin->Information.DisplayName : L"(unnamed)"); - SetDlgItemText(hwndDlg, IDC_INTERNALNAME, SelectedPlugin->Name.Buffer); - SetDlgItemText(hwndDlg, IDC_AUTHOR, SelectedPlugin->Information.Author); - SetDlgItemText(hwndDlg, IDC_FILENAME, fileName->Buffer); - SetDlgItemText(hwndDlg, IDC_DESCRIPTION, SelectedPlugin->Information.Description); - SetDlgItemText(hwndDlg, IDC_URL, SelectedPlugin->Information.Url); - - if (PhInitializeImageVersionInfo(&versionInfo, fileName->Buffer)) - { - SetDlgItemText(hwndDlg, IDC_VERSION, PhGetStringOrDefault(versionInfo.FileVersion, L"Unknown")); - PhDeleteImageVersionInfo(&versionInfo); - } - else - { - SetDlgItemText(hwndDlg, IDC_VERSION, L"Unknown"); - } - - ShowWindow(GetDlgItem(hwndDlg, IDC_OPENURL), SelectedPlugin->Information.Url ? SW_SHOW : SW_HIDE); - EnableWindow(GetDlgItem(hwndDlg, IDC_DISABLE), TRUE); - SetDlgItemText(hwndDlg, IDC_DISABLE, PhpGetPluginDisableButtonText(PhpGetPluginBaseName(SelectedPlugin))); - EnableWindow(GetDlgItem(hwndDlg, IDC_OPTIONS), SelectedPlugin->Information.HasOptions); - } - else - { - SetDlgItemText(hwndDlg, IDC_NAME, L"N/A"); - SetDlgItemText(hwndDlg, IDC_VERSION, L"N/A"); - SetDlgItemText(hwndDlg, IDC_INTERNALNAME, L"N/A"); - SetDlgItemText(hwndDlg, IDC_AUTHOR, L"N/A"); - SetDlgItemText(hwndDlg, IDC_URL, L"N/A"); - SetDlgItemText(hwndDlg, IDC_FILENAME, L"N/A"); - SetDlgItemText(hwndDlg, IDC_DESCRIPTION, L"N/A"); - - ShowWindow(GetDlgItem(hwndDlg, IDC_OPENURL), SW_HIDE); - - if (SelectedPlugin) - { - // This is a disabled plugin. - EnableWindow(GetDlgItem(hwndDlg, IDC_DISABLE), TRUE); - SetDlgItemText(hwndDlg, IDC_DISABLE, PhpGetPluginDisableButtonText(SelectedPlugin->Name.Buffer)); - } - else - { - EnableWindow(GetDlgItem(hwndDlg, IDC_DISABLE), FALSE); - SetDlgItemText(hwndDlg, IDC_DISABLE, L"Disable"); - } - - EnableWindow(GetDlgItem(hwndDlg, IDC_OPTIONS), FALSE); - } -} - -BOOLEAN PhpIsPluginLoadedByBaseName( - _In_ PPH_STRINGREF BaseName - ) -{ - PPH_AVL_LINKS links; - - // Extremely inefficient code follows. - // TODO: Make this better. - - for (links = PhMinimumElementAvlTree(&PhPluginsByName); links; links = PhSuccessorElementAvlTree(links)) - { - PPH_PLUGIN plugin = CONTAINING_RECORD(links, PH_PLUGIN, Links); - PH_STRINGREF pluginBaseName; - - PhInitializeStringRefLongHint(&pluginBaseName, PhpGetPluginBaseName(plugin)); - - if (PhEqualStringRef(&pluginBaseName, BaseName, TRUE)) - return TRUE; - } - - return FALSE; -} - -PPH_PLUGIN PhpCreateDisabledPlugin( - _In_ PPH_STRINGREF BaseName - ) -{ - PPH_PLUGIN plugin; - - plugin = PhAllocate(sizeof(PH_PLUGIN)); - memset(plugin, 0, sizeof(PH_PLUGIN)); - - plugin->Name.Length = BaseName->Length; - plugin->Name.Buffer = PhAllocate(BaseName->Length + sizeof(WCHAR)); - memcpy(plugin->Name.Buffer, BaseName->Buffer, BaseName->Length); - plugin->Name.Buffer[BaseName->Length / 2] = 0; - - return plugin; -} - -VOID PhpFreeDisabledPlugin( - _In_ PPH_PLUGIN Plugin - ) -{ - PhFree(Plugin->Name.Buffer); - PhFree(Plugin); -} - -VOID PhpAddDisabledPlugins( - VOID - ) -{ - PPH_STRING disabled; - PH_STRINGREF remainingPart; - PH_STRINGREF part; - PPH_PLUGIN disabledPlugin; - PPH_STRING displayText; - INT lvItemIndex; - - disabled = PhGetStringSetting(L"DisabledPlugins"); - remainingPart = disabled->sr; - - while (remainingPart.Length != 0) - { - PhSplitStringRefAtChar(&remainingPart, '|', &part, &remainingPart); - - if (part.Length != 0) - { - if (!PhpIsPluginLoadedByBaseName(&part)) - { - disabledPlugin = PhpCreateDisabledPlugin(&part); - PhAddItemList(DisabledPluginInstances, disabledPlugin); - PhAddItemSimpleHashtable(DisabledPluginLookup, disabledPlugin, NULL); - - displayText = PhCreateString2(&part); - lvItemIndex = PhAddListViewItem(PluginsLv, MAXINT, displayText->Buffer, disabledPlugin); - PhDereferenceObject(displayText); - } - } - } - - PhDereferenceObject(disabled); -} - -VOID PhpUpdateDisabledPlugin( - _In_ HWND hwndDlg, - _In_ INT ItemIndex, - _In_ PPH_PLUGIN Plugin, - _In_ BOOLEAN NewDisabledState - ) -{ - if (NewDisabledState) - { - PhAddItemSimpleHashtable(DisabledPluginLookup, Plugin, NULL); - } - else - { - PhRemoveItemSimpleHashtable(DisabledPluginLookup, Plugin); - } - - if (!IS_PLUGIN_LOADED(Plugin)) - { - assert(!NewDisabledState); - ListView_DeleteItem(PluginsLv, ItemIndex); - } - - InvalidateRect(PluginsLv, NULL, TRUE); - - ShowWindow(GetDlgItem(hwndDlg, IDC_INSTRUCTION), SW_SHOW); -} - -static COLORREF PhpPluginColorFunction( - _In_ INT Index, - _In_ PVOID Param, - _In_opt_ PVOID Context - ) -{ - PPH_PLUGIN plugin = Param; - - if (PhFindItemSimpleHashtable(DisabledPluginLookup, plugin)) - return RGB(0x77, 0x77, 0x77); // fake disabled plugin - - return GetSysColor(COLOR_WINDOW); -} - -INT_PTR CALLBACK PhpPluginsDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - switch (uMsg) - { - case WM_INITDIALOG: - { - PPH_AVL_LINKS links; - - PhCenterWindow(hwndDlg, PhMainWndHandle); - - PluginsLv = GetDlgItem(hwndDlg, IDC_LIST); - PhSetListViewStyle(PluginsLv, FALSE, TRUE); - PhSetControlTheme(PluginsLv, L"explorer"); - PhAddListViewColumn(PluginsLv, 0, 0, 0, LVCFMT_LEFT, 280, L"Name"); - PhAddListViewColumn(PluginsLv, 1, 1, 1, LVCFMT_LEFT, 100, L"Author"); - PhSetExtendedListView(PluginsLv); - ExtendedListView_SetItemColorFunction(PluginsLv, PhpPluginColorFunction); - - DisabledPluginLookup = PhCreateSimpleHashtable(10); - - for (links = PhMinimumElementAvlTree(&PhPluginsByName); links; links = PhSuccessorElementAvlTree(links)) - { - PPH_PLUGIN plugin = CONTAINING_RECORD(links, PH_PLUGIN, Links); - INT lvItemIndex; - PH_STRINGREF baseNameSr; - - lvItemIndex = PhAddListViewItem(PluginsLv, MAXINT, plugin->Information.DisplayName ? plugin->Information.DisplayName : plugin->Name.Buffer, plugin); - - if (plugin->Information.Author) - PhSetListViewSubItem(PluginsLv, lvItemIndex, 1, plugin->Information.Author); - - PhInitializeStringRefLongHint(&baseNameSr, PhpGetPluginBaseName(plugin)); - - if (PhIsPluginDisabled(&baseNameSr)) - PhAddItemSimpleHashtable(DisabledPluginLookup, plugin, NULL); - } - - DisabledPluginInstances = PhCreateList(10); - PhpAddDisabledPlugins(); - - ExtendedListView_SortItems(PluginsLv); - - SelectedPlugin = NULL; - PhpRefreshPluginDetails(hwndDlg); - } - break; - case WM_DESTROY: - { - ULONG i; - - for (i = 0; i < DisabledPluginInstances->Count; i++) - PhpFreeDisabledPlugin(DisabledPluginInstances->Items[i]); - - PhDereferenceObject(DisabledPluginInstances); - PhDereferenceObject(DisabledPluginLookup); - } - break; - case WM_COMMAND: - { - switch (LOWORD(wParam)) - { - case IDCANCEL: - case IDOK: - EndDialog(hwndDlg, IDOK); - break; - case IDC_DISABLE: - { - if (SelectedPlugin) - { - PWSTR baseName; - PH_STRINGREF baseNameRef; - BOOLEAN newDisabledState; - - baseName = PhpGetPluginBaseName(SelectedPlugin); - PhInitializeStringRef(&baseNameRef, baseName); - newDisabledState = !PhIsPluginDisabled(&baseNameRef); - PhSetPluginDisabled(&baseNameRef, newDisabledState); - PhpUpdateDisabledPlugin(hwndDlg, PhFindListViewItemByFlags(PluginsLv, -1, LVNI_SELECTED), SelectedPlugin, newDisabledState); - - SetDlgItemText(hwndDlg, IDC_DISABLE, PhpGetPluginDisableButtonText(baseName)); - } - } - break; - case IDC_OPTIONS: - { - if (SelectedPlugin && IS_PLUGIN_LOADED(SelectedPlugin)) - { - PhInvokeCallback(PhGetPluginCallback(SelectedPlugin, PluginCallbackShowOptions), hwndDlg); - } - } - break; - case IDC_CLEANUP: - { - if (PhShowMessage(hwndDlg, MB_ICONQUESTION | MB_YESNO, - L"Do you want to clean up unused plugin settings?") == IDYES) - { - PhClearIgnoredSettings(); - } - } - break; - case IDC_OPENURL: - { - NOTHING; - } - break; - } - } - break; - case WM_NOTIFY: - { - LPNMHDR header = (LPNMHDR)lParam; - - switch (header->code) - { - case LVN_ITEMCHANGED: - { - if (header->hwndFrom == PluginsLv) - { - if (ListView_GetSelectedCount(PluginsLv) == 1) - SelectedPlugin = PhGetSelectedListViewItemParam(PluginsLv); - else - SelectedPlugin = NULL; - - PhpRefreshPluginDetails(hwndDlg); - } - } - break; - case NM_CLICK: - { - if (header->hwndFrom == GetDlgItem(hwndDlg, IDC_OPENURL)) - { - if (SelectedPlugin && IS_PLUGIN_LOADED(SelectedPlugin)) - PhShellExecute(hwndDlg, SelectedPlugin->Information.Url, NULL); - } - } - break; - case NM_DBLCLK: - { - if (header->hwndFrom == PluginsLv) - { - if (SelectedPlugin && IS_PLUGIN_LOADED(SelectedPlugin)) - { - PhInvokeCallback(PhGetPluginCallback(SelectedPlugin, PluginCallbackShowOptions), hwndDlg); - } - } - } - break; - } - } - break; - } - - REFLECT_MESSAGE_DLG(hwndDlg, PluginsLv, uMsg, wParam, lParam); - - return FALSE; -} +/* + * Process Hacker - + * plugins + * + * Copyright (C) 2010-2011 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include + +#include +#include +#include + +#define IS_PLUGIN_LOADED(Plugin) (!!(Plugin)->AppContext.AppName.Buffer) +#define STR_OR_DEFAULT(String, Default) ((String) ? (String) : (Default)) + +static HWND PluginsLv; +static PPH_PLUGIN SelectedPlugin; +static PPH_LIST DisabledPluginInstances; // fake PH_PLUGIN structures for disabled plugins +static PPH_HASHTABLE DisabledPluginLookup; // list of all disabled plugins (including fake structures) by PH_PLUGIN address + +INT_PTR CALLBACK PhpPluginsDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +VOID PhShowPluginsDialog( + _In_ HWND ParentWindowHandle + ) +{ + if (PhPluginsEnabled) + { + DialogBox( + PhInstanceHandle, + MAKEINTRESOURCE(IDD_PLUGINS), + ParentWindowHandle, + PhpPluginsDlgProc + ); + } + else + { + PhShowInformation(ParentWindowHandle, + L"Plugins are not enabled. To use plugins enable them in Options and restart Process Hacker."); + } +} + +PWSTR PhpGetPluginBaseName( + _In_ PPH_PLUGIN Plugin + ) +{ + if (Plugin->FileName) + { + PH_STRINGREF pathNamePart; + PH_STRINGREF baseNamePart; + + if (PhSplitStringRefAtLastChar(&Plugin->FileName->sr, '\\', &pathNamePart, &baseNamePart)) + return baseNamePart.Buffer; + else + return Plugin->FileName->Buffer; + } + else + { + // Fake disabled plugin. + return Plugin->Name.Buffer; + } +} + +PWSTR PhpGetPluginDisableButtonText( + _In_ PWSTR BaseName + ) +{ + PH_STRINGREF baseName; + + PhInitializeStringRefLongHint(&baseName, BaseName); + + if (PhIsPluginDisabled(&baseName)) + return L"Enable"; + else + return L"Disable"; +} + +VOID PhpRefreshPluginDetails( + _In_ HWND hwndDlg + ) +{ + PPH_STRING fileName; + PH_IMAGE_VERSION_INFO versionInfo; + + if (SelectedPlugin && SelectedPlugin->FileName) // if there's no FileName, then it's a fake disabled plugin instance + { + fileName = SelectedPlugin->FileName; + + SetDlgItemText(hwndDlg, IDC_NAME, SelectedPlugin->Information.DisplayName ? SelectedPlugin->Information.DisplayName : L"(unnamed)"); + SetDlgItemText(hwndDlg, IDC_INTERNALNAME, SelectedPlugin->Name.Buffer); + SetDlgItemText(hwndDlg, IDC_AUTHOR, SelectedPlugin->Information.Author); + SetDlgItemText(hwndDlg, IDC_FILENAME, fileName->Buffer); + SetDlgItemText(hwndDlg, IDC_DESCRIPTION, SelectedPlugin->Information.Description); + SetDlgItemText(hwndDlg, IDC_URL, SelectedPlugin->Information.Url); + + if (PhInitializeImageVersionInfo(&versionInfo, fileName->Buffer)) + { + SetDlgItemText(hwndDlg, IDC_VERSION, PhGetStringOrDefault(versionInfo.FileVersion, L"Unknown")); + PhDeleteImageVersionInfo(&versionInfo); + } + else + { + SetDlgItemText(hwndDlg, IDC_VERSION, L"Unknown"); + } + + ShowWindow(GetDlgItem(hwndDlg, IDC_OPENURL), SelectedPlugin->Information.Url ? SW_SHOW : SW_HIDE); + EnableWindow(GetDlgItem(hwndDlg, IDC_DISABLE), TRUE); + SetDlgItemText(hwndDlg, IDC_DISABLE, PhpGetPluginDisableButtonText(PhpGetPluginBaseName(SelectedPlugin))); + EnableWindow(GetDlgItem(hwndDlg, IDC_OPTIONS), SelectedPlugin->Information.HasOptions); + } + else + { + SetDlgItemText(hwndDlg, IDC_NAME, L"N/A"); + SetDlgItemText(hwndDlg, IDC_VERSION, L"N/A"); + SetDlgItemText(hwndDlg, IDC_INTERNALNAME, L"N/A"); + SetDlgItemText(hwndDlg, IDC_AUTHOR, L"N/A"); + SetDlgItemText(hwndDlg, IDC_URL, L"N/A"); + SetDlgItemText(hwndDlg, IDC_FILENAME, L"N/A"); + SetDlgItemText(hwndDlg, IDC_DESCRIPTION, L"N/A"); + + ShowWindow(GetDlgItem(hwndDlg, IDC_OPENURL), SW_HIDE); + + if (SelectedPlugin) + { + // This is a disabled plugin. + EnableWindow(GetDlgItem(hwndDlg, IDC_DISABLE), TRUE); + SetDlgItemText(hwndDlg, IDC_DISABLE, PhpGetPluginDisableButtonText(SelectedPlugin->Name.Buffer)); + } + else + { + EnableWindow(GetDlgItem(hwndDlg, IDC_DISABLE), FALSE); + SetDlgItemText(hwndDlg, IDC_DISABLE, L"Disable"); + } + + EnableWindow(GetDlgItem(hwndDlg, IDC_OPTIONS), FALSE); + } +} + +BOOLEAN PhpIsPluginLoadedByBaseName( + _In_ PPH_STRINGREF BaseName + ) +{ + PPH_AVL_LINKS links; + + // Extremely inefficient code follows. + // TODO: Make this better. + + for (links = PhMinimumElementAvlTree(&PhPluginsByName); links; links = PhSuccessorElementAvlTree(links)) + { + PPH_PLUGIN plugin = CONTAINING_RECORD(links, PH_PLUGIN, Links); + PH_STRINGREF pluginBaseName; + + PhInitializeStringRefLongHint(&pluginBaseName, PhpGetPluginBaseName(plugin)); + + if (PhEqualStringRef(&pluginBaseName, BaseName, TRUE)) + return TRUE; + } + + return FALSE; +} + +PPH_PLUGIN PhpCreateDisabledPlugin( + _In_ PPH_STRINGREF BaseName + ) +{ + PPH_PLUGIN plugin; + + plugin = PhAllocate(sizeof(PH_PLUGIN)); + memset(plugin, 0, sizeof(PH_PLUGIN)); + + plugin->Name.Length = BaseName->Length; + plugin->Name.Buffer = PhAllocate(BaseName->Length + sizeof(WCHAR)); + memcpy(plugin->Name.Buffer, BaseName->Buffer, BaseName->Length); + plugin->Name.Buffer[BaseName->Length / 2] = 0; + + return plugin; +} + +VOID PhpFreeDisabledPlugin( + _In_ PPH_PLUGIN Plugin + ) +{ + PhFree(Plugin->Name.Buffer); + PhFree(Plugin); +} + +VOID PhpAddDisabledPlugins( + VOID + ) +{ + PPH_STRING disabled; + PH_STRINGREF remainingPart; + PH_STRINGREF part; + PPH_PLUGIN disabledPlugin; + PPH_STRING displayText; + INT lvItemIndex; + + disabled = PhGetStringSetting(L"DisabledPlugins"); + remainingPart = disabled->sr; + + while (remainingPart.Length != 0) + { + PhSplitStringRefAtChar(&remainingPart, '|', &part, &remainingPart); + + if (part.Length != 0) + { + if (!PhpIsPluginLoadedByBaseName(&part)) + { + disabledPlugin = PhpCreateDisabledPlugin(&part); + PhAddItemList(DisabledPluginInstances, disabledPlugin); + PhAddItemSimpleHashtable(DisabledPluginLookup, disabledPlugin, NULL); + + displayText = PhCreateString2(&part); + lvItemIndex = PhAddListViewItem(PluginsLv, MAXINT, displayText->Buffer, disabledPlugin); + PhDereferenceObject(displayText); + } + } + } + + PhDereferenceObject(disabled); +} + +VOID PhpUpdateDisabledPlugin( + _In_ HWND hwndDlg, + _In_ INT ItemIndex, + _In_ PPH_PLUGIN Plugin, + _In_ BOOLEAN NewDisabledState + ) +{ + if (NewDisabledState) + { + PhAddItemSimpleHashtable(DisabledPluginLookup, Plugin, NULL); + } + else + { + PhRemoveItemSimpleHashtable(DisabledPluginLookup, Plugin); + } + + if (!IS_PLUGIN_LOADED(Plugin)) + { + assert(!NewDisabledState); + ListView_DeleteItem(PluginsLv, ItemIndex); + } + + InvalidateRect(PluginsLv, NULL, TRUE); + + ShowWindow(GetDlgItem(hwndDlg, IDC_INSTRUCTION), SW_SHOW); +} + +static COLORREF PhpPluginColorFunction( + _In_ INT Index, + _In_ PVOID Param, + _In_opt_ PVOID Context + ) +{ + PPH_PLUGIN plugin = Param; + + if (PhFindItemSimpleHashtable(DisabledPluginLookup, plugin)) + return RGB(0x77, 0x77, 0x77); // fake disabled plugin + + return GetSysColor(COLOR_WINDOW); +} + +INT_PTR CALLBACK PhpPluginsDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + switch (uMsg) + { + case WM_INITDIALOG: + { + PPH_AVL_LINKS links; + + PhCenterWindow(hwndDlg, PhMainWndHandle); + + PluginsLv = GetDlgItem(hwndDlg, IDC_LIST); + PhSetListViewStyle(PluginsLv, FALSE, TRUE); + PhSetControlTheme(PluginsLv, L"explorer"); + PhAddListViewColumn(PluginsLv, 0, 0, 0, LVCFMT_LEFT, 280, L"Name"); + PhAddListViewColumn(PluginsLv, 1, 1, 1, LVCFMT_LEFT, 100, L"Author"); + PhSetExtendedListView(PluginsLv); + ExtendedListView_SetItemColorFunction(PluginsLv, PhpPluginColorFunction); + + DisabledPluginLookup = PhCreateSimpleHashtable(10); + + for (links = PhMinimumElementAvlTree(&PhPluginsByName); links; links = PhSuccessorElementAvlTree(links)) + { + PPH_PLUGIN plugin = CONTAINING_RECORD(links, PH_PLUGIN, Links); + INT lvItemIndex; + PH_STRINGREF baseNameSr; + + lvItemIndex = PhAddListViewItem(PluginsLv, MAXINT, plugin->Information.DisplayName ? plugin->Information.DisplayName : plugin->Name.Buffer, plugin); + + if (plugin->Information.Author) + PhSetListViewSubItem(PluginsLv, lvItemIndex, 1, plugin->Information.Author); + + PhInitializeStringRefLongHint(&baseNameSr, PhpGetPluginBaseName(plugin)); + + if (PhIsPluginDisabled(&baseNameSr)) + PhAddItemSimpleHashtable(DisabledPluginLookup, plugin, NULL); + } + + DisabledPluginInstances = PhCreateList(10); + PhpAddDisabledPlugins(); + + ExtendedListView_SortItems(PluginsLv); + + SelectedPlugin = NULL; + PhpRefreshPluginDetails(hwndDlg); + } + break; + case WM_DESTROY: + { + ULONG i; + + for (i = 0; i < DisabledPluginInstances->Count; i++) + PhpFreeDisabledPlugin(DisabledPluginInstances->Items[i]); + + PhDereferenceObject(DisabledPluginInstances); + PhDereferenceObject(DisabledPluginLookup); + } + break; + case WM_COMMAND: + { + switch (LOWORD(wParam)) + { + case IDCANCEL: + case IDOK: + EndDialog(hwndDlg, IDOK); + break; + case IDC_DISABLE: + { + if (SelectedPlugin) + { + PWSTR baseName; + PH_STRINGREF baseNameRef; + BOOLEAN newDisabledState; + + baseName = PhpGetPluginBaseName(SelectedPlugin); + PhInitializeStringRef(&baseNameRef, baseName); + newDisabledState = !PhIsPluginDisabled(&baseNameRef); + PhSetPluginDisabled(&baseNameRef, newDisabledState); + PhpUpdateDisabledPlugin(hwndDlg, PhFindListViewItemByFlags(PluginsLv, -1, LVNI_SELECTED), SelectedPlugin, newDisabledState); + + SetDlgItemText(hwndDlg, IDC_DISABLE, PhpGetPluginDisableButtonText(baseName)); + } + } + break; + case IDC_OPTIONS: + { + if (SelectedPlugin && IS_PLUGIN_LOADED(SelectedPlugin)) + { + PhInvokeCallback(PhGetPluginCallback(SelectedPlugin, PluginCallbackShowOptions), hwndDlg); + } + } + break; + case IDC_CLEANUP: + { + if (PhShowMessage(hwndDlg, MB_ICONQUESTION | MB_YESNO, + L"Do you want to clean up unused plugin settings?") == IDYES) + { + PhClearIgnoredSettings(); + } + } + break; + case IDC_OPENURL: + { + NOTHING; + } + break; + } + } + break; + case WM_NOTIFY: + { + LPNMHDR header = (LPNMHDR)lParam; + + switch (header->code) + { + case LVN_ITEMCHANGED: + { + if (header->hwndFrom == PluginsLv) + { + if (ListView_GetSelectedCount(PluginsLv) == 1) + SelectedPlugin = PhGetSelectedListViewItemParam(PluginsLv); + else + SelectedPlugin = NULL; + + PhpRefreshPluginDetails(hwndDlg); + } + } + break; + case NM_CLICK: + { + if (header->hwndFrom == GetDlgItem(hwndDlg, IDC_OPENURL)) + { + if (SelectedPlugin && IS_PLUGIN_LOADED(SelectedPlugin)) + PhShellExecute(hwndDlg, SelectedPlugin->Information.Url, NULL); + } + } + break; + case NM_DBLCLK: + { + if (header->hwndFrom == PluginsLv) + { + if (SelectedPlugin && IS_PLUGIN_LOADED(SelectedPlugin)) + { + PhInvokeCallback(PhGetPluginCallback(SelectedPlugin, PluginCallbackShowOptions), hwndDlg); + } + } + } + break; + } + } + break; + } + + REFLECT_MESSAGE_DLG(hwndDlg, PluginsLv, uMsg, wParam, lParam); + + return FALSE; +} diff --git a/ProcessHacker/procgrp.c b/ProcessHacker/procgrp.c index 87f76ababcaa..e0e38b8ca587 100644 --- a/ProcessHacker/procgrp.c +++ b/ProcessHacker/procgrp.c @@ -1,343 +1,343 @@ -/* - * Process Hacker - - * process grouping - * - * Copyright (C) 2015 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include -#include - -#include -#include - -typedef struct _PHP_PROCESS_DATA -{ - PPH_PROCESS_NODE Process; - LIST_ENTRY ListEntry; - HWND WindowHandle; -} PHP_PROCESS_DATA, *PPHP_PROCESS_DATA; - -PPH_LIST PhpCreateProcessDataList( - _In_ PPH_LIST Processes - ) -{ - PPH_LIST processDataList; - ULONG i; - - processDataList = PhCreateList(Processes->Count); - - for (i = 0; i < Processes->Count; i++) - { - PPH_PROCESS_NODE process = Processes->Items[i]; - PPHP_PROCESS_DATA processData; - - if (PH_IS_FAKE_PROCESS_ID(process->ProcessId) || process->ProcessId == SYSTEM_IDLE_PROCESS_ID) - continue; - - processData = PhAllocate(sizeof(PHP_PROCESS_DATA)); - memset(processData, 0, sizeof(PHP_PROCESS_DATA)); - processData->Process = process; - PhAddItemList(processDataList, processData); - } - - return processDataList; -} - -VOID PhpDestroyProcessDataList( - _In_ PPH_LIST List - ) -{ - ULONG i; - - for (i = 0; i < List->Count; i++) - { - PPHP_PROCESS_DATA processData = List->Items[i]; - PhFree(processData); - } - - PhDereferenceObject(List); -} - -VOID PhpProcessDataListToLinkedList( - _In_ PPH_LIST List, - _Out_ PLIST_ENTRY ListHead - ) -{ - ULONG i; - - InitializeListHead(ListHead); - - for (i = 0; i < List->Count; i++) - { - PPHP_PROCESS_DATA processData = List->Items[i]; - InsertTailList(ListHead, &processData->ListEntry); - } -} - -VOID PhpProcessDataListToHashtable( - _In_ PPH_LIST List, - _Out_ PPH_HASHTABLE *Hashtable - ) -{ - PPH_HASHTABLE hashtable; - ULONG i; - - hashtable = PhCreateSimpleHashtable(List->Count); - - for (i = 0; i < List->Count; i++) - { - PPHP_PROCESS_DATA processData = List->Items[i]; - PhAddItemSimpleHashtable(hashtable, processData->Process->ProcessId, processData); - } - - *Hashtable = hashtable; -} - -typedef struct _QUERY_WINDOWS_CONTEXT -{ - PPH_HASHTABLE ProcessDataHashtable; -} QUERY_WINDOWS_CONTEXT, *PQUERY_WINDOWS_CONTEXT; - -BOOL CALLBACK PhpQueryWindowsEnumWindowsProc( - _In_ HWND hwnd, - _In_ LPARAM lParam - ) -{ - PQUERY_WINDOWS_CONTEXT context = (PQUERY_WINDOWS_CONTEXT)lParam; - ULONG processId; - PPHP_PROCESS_DATA processData; - HWND parentWindow; - - if (!IsWindowVisible(hwnd)) - return TRUE; - - GetWindowThreadProcessId(hwnd, &processId); - processData = PhFindItemSimpleHashtable2(context->ProcessDataHashtable, UlongToHandle(processId)); - - if (!processData || processData->WindowHandle) - return TRUE; - - if (!((parentWindow = GetParent(hwnd)) && IsWindowVisible(parentWindow)) && // Skip windows with a visible parent - PhGetWindowTextEx(hwnd, PH_GET_WINDOW_TEXT_INTERNAL | PH_GET_WINDOW_TEXT_LENGTH_ONLY, NULL) != 0) // Skip windows with no title - { - processData->WindowHandle = hwnd; - } - - return TRUE; -} - -PPH_STRING PhpGetRelevantFileName( - _In_ PPH_PROCESS_ITEM ProcessItem, - _In_ ULONG Flags - ) -{ - if (Flags & PH_GROUP_PROCESSES_FILE_PATH) - return ProcessItem->FileName; - else - return ProcessItem->ProcessName; -} - -BOOLEAN PhpEqualFileNameAndUserName( - _In_ PPH_STRING FileName, - _In_ PPH_STRING UserName, - _In_ PPH_PROCESS_ITEM ProcessItem, - _In_ ULONG Flags - ) -{ - PPH_STRING otherFileName; - PPH_STRING otherUserName; - - otherFileName = PhpGetRelevantFileName(ProcessItem, Flags); - otherUserName = ProcessItem->UserName; - - return - otherFileName && PhEqualString(otherFileName, FileName, TRUE) && - otherUserName && PhEqualString(otherUserName, UserName, TRUE); -} - -PPHP_PROCESS_DATA PhpFindGroupRoot( - _In_ PPHP_PROCESS_DATA ProcessData, - _In_ PPH_HASHTABLE ProcessDataHashtable, - _In_ ULONG Flags - ) -{ - PPH_PROCESS_NODE root; - PPHP_PROCESS_DATA rootProcessData; - PPH_PROCESS_NODE parent; - PPHP_PROCESS_DATA processData; - PPH_STRING fileName; - PPH_STRING userName; - - root = ProcessData->Process; - rootProcessData = ProcessData; - fileName = PhpGetRelevantFileName(ProcessData->Process->ProcessItem, Flags); - userName = ProcessData->Process->ProcessItem->UserName; - - if (ProcessData->WindowHandle) - return rootProcessData; - - while (parent = root->Parent) - { - if ((processData = PhFindItemSimpleHashtable2(ProcessDataHashtable, parent->ProcessId)) && - PhpEqualFileNameAndUserName(fileName, userName, parent->ProcessItem, Flags)) - { - root = parent; - rootProcessData = processData; - - if (processData->WindowHandle) - break; - } - else - { - break; - } - } - - return rootProcessData; -} - -VOID PhpAddGroupMember( - _In_ PPHP_PROCESS_DATA ProcessData, - _Inout_ PPH_LIST List - ) -{ - PhReferenceObject(ProcessData->Process->ProcessItem); - PhAddItemList(List, ProcessData->Process->ProcessItem); - RemoveEntryList(&ProcessData->ListEntry); -} - -VOID PhpAddGroupMembersFromRoot( - _In_ PPHP_PROCESS_DATA ProcessData, - _Inout_ PPH_LIST List, - _In_ PPH_HASHTABLE ProcessDataHashtable, - _In_ ULONG Flags - ) -{ - PPH_STRING fileName; - PPH_STRING userName; - ULONG i; - - PhpAddGroupMember(ProcessData, List); - fileName = PhpGetRelevantFileName(ProcessData->Process->ProcessItem, Flags); - userName = ProcessData->Process->ProcessItem->UserName; - - for (i = 0; i < ProcessData->Process->Children->Count; i++) - { - PPH_PROCESS_NODE node = ProcessData->Process->Children->Items[i]; - PPHP_PROCESS_DATA processData; - - if ((processData = PhFindItemSimpleHashtable2(ProcessDataHashtable, node->ProcessId)) && - PhpEqualFileNameAndUserName(fileName, userName, node->ProcessItem, Flags) && - node->ProcessItem->UserName && PhEqualString(node->ProcessItem->UserName, userName, TRUE) && - !processData->WindowHandle) - { - PhpAddGroupMembersFromRoot(processData, List, ProcessDataHashtable, Flags); - } - } -} - -PPH_LIST PhCreateProcessGroupList( - _In_opt_ PPH_SORT_LIST_FUNCTION SortListFunction, - _In_opt_ PVOID Context, - _In_ ULONG MaximumGroups, - _In_ ULONG Flags - ) -{ - PPH_LIST processList; - PPH_LIST processDataList; - LIST_ENTRY processDataListHead; // We will be removing things from this list as we group processes together - PPH_HASHTABLE processDataHashtable; // Process ID to process data hashtable - QUERY_WINDOWS_CONTEXT queryWindowsContext; - PPH_LIST processGroupList; - - // We group together processes that share a common ancestor and have the same file name, where - // the ancestor must have a visible window and all other processes in the group do not have a - // visible window. All processes in the group must have the same user name. All ancestors up to - // the lowest common ancestor must have the same file name and user name. - // - // The current algorithm is greedy and may not detect groups that have many processes, each with - // a small usage amount. - - processList = PhDuplicateProcessNodeList(); - - if (SortListFunction) - SortListFunction(processList, Context); - - processDataList = PhpCreateProcessDataList(processList); - PhDereferenceObject(processList); - PhpProcessDataListToLinkedList(processDataList, &processDataListHead); - PhpProcessDataListToHashtable(processDataList, &processDataHashtable); - - queryWindowsContext.ProcessDataHashtable = processDataHashtable; - PhEnumChildWindows(NULL, 0x800, PhpQueryWindowsEnumWindowsProc, (LPARAM)&queryWindowsContext); - - processGroupList = PhCreateList(10); - - while (processDataListHead.Flink != &processDataListHead && processGroupList->Count < MaximumGroups) - { - PPHP_PROCESS_DATA processData = CONTAINING_RECORD(processDataListHead.Flink, PHP_PROCESS_DATA, ListEntry); - PPH_PROCESS_GROUP processGroup; - PPH_STRING fileName; - PPH_STRING userName; - - processGroup = PhAllocate(sizeof(PH_PROCESS_GROUP)); - processGroup->Processes = PhCreateList(4); - fileName = PhpGetRelevantFileName(processData->Process->ProcessItem, Flags); - userName = processData->Process->ProcessItem->UserName; - - if (!fileName || !userName || (Flags & PH_GROUP_PROCESSES_DONT_GROUP)) - { - processGroup->Representative = processData->Process->ProcessItem; - PhpAddGroupMember(processData, processGroup->Processes); - } - else - { - processData = PhpFindGroupRoot(processData, processDataHashtable, Flags); - processGroup->Representative = processData->Process->ProcessItem; - PhpAddGroupMembersFromRoot(processData, processGroup->Processes, processDataHashtable, Flags); - } - - processGroup->WindowHandle = processData->WindowHandle; - - PhAddItemList(processGroupList, processGroup); - } - - PhDereferenceObject(processDataHashtable); - PhpDestroyProcessDataList(processDataList); - - return processGroupList; -} - -VOID PhFreeProcessGroupList( - _In_ PPH_LIST List - ) -{ - ULONG i; - - for (i = 0; i < List->Count; i++) - { - PPH_PROCESS_GROUP processGroup = List->Items[i]; - - PhDereferenceObjects(processGroup->Processes->Items, processGroup->Processes->Count); - PhDereferenceObject(processGroup->Processes); - PhFree(processGroup); - } - - PhDereferenceObject(List); -} +/* + * Process Hacker - + * process grouping + * + * Copyright (C) 2015 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include +#include + +#include +#include + +typedef struct _PHP_PROCESS_DATA +{ + PPH_PROCESS_NODE Process; + LIST_ENTRY ListEntry; + HWND WindowHandle; +} PHP_PROCESS_DATA, *PPHP_PROCESS_DATA; + +PPH_LIST PhpCreateProcessDataList( + _In_ PPH_LIST Processes + ) +{ + PPH_LIST processDataList; + ULONG i; + + processDataList = PhCreateList(Processes->Count); + + for (i = 0; i < Processes->Count; i++) + { + PPH_PROCESS_NODE process = Processes->Items[i]; + PPHP_PROCESS_DATA processData; + + if (PH_IS_FAKE_PROCESS_ID(process->ProcessId) || process->ProcessId == SYSTEM_IDLE_PROCESS_ID) + continue; + + processData = PhAllocate(sizeof(PHP_PROCESS_DATA)); + memset(processData, 0, sizeof(PHP_PROCESS_DATA)); + processData->Process = process; + PhAddItemList(processDataList, processData); + } + + return processDataList; +} + +VOID PhpDestroyProcessDataList( + _In_ PPH_LIST List + ) +{ + ULONG i; + + for (i = 0; i < List->Count; i++) + { + PPHP_PROCESS_DATA processData = List->Items[i]; + PhFree(processData); + } + + PhDereferenceObject(List); +} + +VOID PhpProcessDataListToLinkedList( + _In_ PPH_LIST List, + _Out_ PLIST_ENTRY ListHead + ) +{ + ULONG i; + + InitializeListHead(ListHead); + + for (i = 0; i < List->Count; i++) + { + PPHP_PROCESS_DATA processData = List->Items[i]; + InsertTailList(ListHead, &processData->ListEntry); + } +} + +VOID PhpProcessDataListToHashtable( + _In_ PPH_LIST List, + _Out_ PPH_HASHTABLE *Hashtable + ) +{ + PPH_HASHTABLE hashtable; + ULONG i; + + hashtable = PhCreateSimpleHashtable(List->Count); + + for (i = 0; i < List->Count; i++) + { + PPHP_PROCESS_DATA processData = List->Items[i]; + PhAddItemSimpleHashtable(hashtable, processData->Process->ProcessId, processData); + } + + *Hashtable = hashtable; +} + +typedef struct _QUERY_WINDOWS_CONTEXT +{ + PPH_HASHTABLE ProcessDataHashtable; +} QUERY_WINDOWS_CONTEXT, *PQUERY_WINDOWS_CONTEXT; + +BOOL CALLBACK PhpQueryWindowsEnumWindowsProc( + _In_ HWND hwnd, + _In_ LPARAM lParam + ) +{ + PQUERY_WINDOWS_CONTEXT context = (PQUERY_WINDOWS_CONTEXT)lParam; + ULONG processId; + PPHP_PROCESS_DATA processData; + HWND parentWindow; + + if (!IsWindowVisible(hwnd)) + return TRUE; + + GetWindowThreadProcessId(hwnd, &processId); + processData = PhFindItemSimpleHashtable2(context->ProcessDataHashtable, UlongToHandle(processId)); + + if (!processData || processData->WindowHandle) + return TRUE; + + if (!((parentWindow = GetParent(hwnd)) && IsWindowVisible(parentWindow)) && // Skip windows with a visible parent + PhGetWindowTextEx(hwnd, PH_GET_WINDOW_TEXT_INTERNAL | PH_GET_WINDOW_TEXT_LENGTH_ONLY, NULL) != 0) // Skip windows with no title + { + processData->WindowHandle = hwnd; + } + + return TRUE; +} + +PPH_STRING PhpGetRelevantFileName( + _In_ PPH_PROCESS_ITEM ProcessItem, + _In_ ULONG Flags + ) +{ + if (Flags & PH_GROUP_PROCESSES_FILE_PATH) + return ProcessItem->FileName; + else + return ProcessItem->ProcessName; +} + +BOOLEAN PhpEqualFileNameAndUserName( + _In_ PPH_STRING FileName, + _In_ PPH_STRING UserName, + _In_ PPH_PROCESS_ITEM ProcessItem, + _In_ ULONG Flags + ) +{ + PPH_STRING otherFileName; + PPH_STRING otherUserName; + + otherFileName = PhpGetRelevantFileName(ProcessItem, Flags); + otherUserName = ProcessItem->UserName; + + return + otherFileName && PhEqualString(otherFileName, FileName, TRUE) && + otherUserName && PhEqualString(otherUserName, UserName, TRUE); +} + +PPHP_PROCESS_DATA PhpFindGroupRoot( + _In_ PPHP_PROCESS_DATA ProcessData, + _In_ PPH_HASHTABLE ProcessDataHashtable, + _In_ ULONG Flags + ) +{ + PPH_PROCESS_NODE root; + PPHP_PROCESS_DATA rootProcessData; + PPH_PROCESS_NODE parent; + PPHP_PROCESS_DATA processData; + PPH_STRING fileName; + PPH_STRING userName; + + root = ProcessData->Process; + rootProcessData = ProcessData; + fileName = PhpGetRelevantFileName(ProcessData->Process->ProcessItem, Flags); + userName = ProcessData->Process->ProcessItem->UserName; + + if (ProcessData->WindowHandle) + return rootProcessData; + + while (parent = root->Parent) + { + if ((processData = PhFindItemSimpleHashtable2(ProcessDataHashtable, parent->ProcessId)) && + PhpEqualFileNameAndUserName(fileName, userName, parent->ProcessItem, Flags)) + { + root = parent; + rootProcessData = processData; + + if (processData->WindowHandle) + break; + } + else + { + break; + } + } + + return rootProcessData; +} + +VOID PhpAddGroupMember( + _In_ PPHP_PROCESS_DATA ProcessData, + _Inout_ PPH_LIST List + ) +{ + PhReferenceObject(ProcessData->Process->ProcessItem); + PhAddItemList(List, ProcessData->Process->ProcessItem); + RemoveEntryList(&ProcessData->ListEntry); +} + +VOID PhpAddGroupMembersFromRoot( + _In_ PPHP_PROCESS_DATA ProcessData, + _Inout_ PPH_LIST List, + _In_ PPH_HASHTABLE ProcessDataHashtable, + _In_ ULONG Flags + ) +{ + PPH_STRING fileName; + PPH_STRING userName; + ULONG i; + + PhpAddGroupMember(ProcessData, List); + fileName = PhpGetRelevantFileName(ProcessData->Process->ProcessItem, Flags); + userName = ProcessData->Process->ProcessItem->UserName; + + for (i = 0; i < ProcessData->Process->Children->Count; i++) + { + PPH_PROCESS_NODE node = ProcessData->Process->Children->Items[i]; + PPHP_PROCESS_DATA processData; + + if ((processData = PhFindItemSimpleHashtable2(ProcessDataHashtable, node->ProcessId)) && + PhpEqualFileNameAndUserName(fileName, userName, node->ProcessItem, Flags) && + node->ProcessItem->UserName && PhEqualString(node->ProcessItem->UserName, userName, TRUE) && + !processData->WindowHandle) + { + PhpAddGroupMembersFromRoot(processData, List, ProcessDataHashtable, Flags); + } + } +} + +PPH_LIST PhCreateProcessGroupList( + _In_opt_ PPH_SORT_LIST_FUNCTION SortListFunction, + _In_opt_ PVOID Context, + _In_ ULONG MaximumGroups, + _In_ ULONG Flags + ) +{ + PPH_LIST processList; + PPH_LIST processDataList; + LIST_ENTRY processDataListHead; // We will be removing things from this list as we group processes together + PPH_HASHTABLE processDataHashtable; // Process ID to process data hashtable + QUERY_WINDOWS_CONTEXT queryWindowsContext; + PPH_LIST processGroupList; + + // We group together processes that share a common ancestor and have the same file name, where + // the ancestor must have a visible window and all other processes in the group do not have a + // visible window. All processes in the group must have the same user name. All ancestors up to + // the lowest common ancestor must have the same file name and user name. + // + // The current algorithm is greedy and may not detect groups that have many processes, each with + // a small usage amount. + + processList = PhDuplicateProcessNodeList(); + + if (SortListFunction) + SortListFunction(processList, Context); + + processDataList = PhpCreateProcessDataList(processList); + PhDereferenceObject(processList); + PhpProcessDataListToLinkedList(processDataList, &processDataListHead); + PhpProcessDataListToHashtable(processDataList, &processDataHashtable); + + queryWindowsContext.ProcessDataHashtable = processDataHashtable; + PhEnumChildWindows(NULL, 0x800, PhpQueryWindowsEnumWindowsProc, (LPARAM)&queryWindowsContext); + + processGroupList = PhCreateList(10); + + while (processDataListHead.Flink != &processDataListHead && processGroupList->Count < MaximumGroups) + { + PPHP_PROCESS_DATA processData = CONTAINING_RECORD(processDataListHead.Flink, PHP_PROCESS_DATA, ListEntry); + PPH_PROCESS_GROUP processGroup; + PPH_STRING fileName; + PPH_STRING userName; + + processGroup = PhAllocate(sizeof(PH_PROCESS_GROUP)); + processGroup->Processes = PhCreateList(4); + fileName = PhpGetRelevantFileName(processData->Process->ProcessItem, Flags); + userName = processData->Process->ProcessItem->UserName; + + if (!fileName || !userName || (Flags & PH_GROUP_PROCESSES_DONT_GROUP)) + { + processGroup->Representative = processData->Process->ProcessItem; + PhpAddGroupMember(processData, processGroup->Processes); + } + else + { + processData = PhpFindGroupRoot(processData, processDataHashtable, Flags); + processGroup->Representative = processData->Process->ProcessItem; + PhpAddGroupMembersFromRoot(processData, processGroup->Processes, processDataHashtable, Flags); + } + + processGroup->WindowHandle = processData->WindowHandle; + + PhAddItemList(processGroupList, processGroup); + } + + PhDereferenceObject(processDataHashtable); + PhpDestroyProcessDataList(processDataList); + + return processGroupList; +} + +VOID PhFreeProcessGroupList( + _In_ PPH_LIST List + ) +{ + ULONG i; + + for (i = 0; i < List->Count; i++) + { + PPH_PROCESS_GROUP processGroup = List->Items[i]; + + PhDereferenceObjects(processGroup->Processes->Items, processGroup->Processes->Count); + PhDereferenceObject(processGroup->Processes); + PhFree(processGroup); + } + + PhDereferenceObject(List); +} diff --git a/ProcessHacker/procprp.c b/ProcessHacker/procprp.c index b106b68a795b..17488331c501 100644 --- a/ProcessHacker/procprp.c +++ b/ProcessHacker/procprp.c @@ -1,724 +1,724 @@ -/* - * Process Hacker - - * Process properties - * - * Copyright (C) 2009-2016 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include -#include -#include - -#include - -#include - -#include -#include -#include - -PPH_OBJECT_TYPE PhpProcessPropContextType; -PPH_OBJECT_TYPE PhpProcessPropPageContextType; -PH_STRINGREF PhpLoadingText = PH_STRINGREF_INIT(L"Loading..."); - -static RECT MinimumSize = { -1, -1, -1, -1 }; - -BOOLEAN PhProcessPropInitialization( - VOID - ) -{ - PhpProcessPropContextType = PhCreateObjectType(L"ProcessPropContext", 0, PhpProcessPropContextDeleteProcedure); - PhpProcessPropPageContextType = PhCreateObjectType(L"ProcessPropPageContext", 0, PhpProcessPropPageContextDeleteProcedure); - - return TRUE; -} - -PPH_PROCESS_PROPCONTEXT PhCreateProcessPropContext( - _In_ HWND ParentWindowHandle, - _In_ PPH_PROCESS_ITEM ProcessItem - ) -{ - PPH_PROCESS_PROPCONTEXT propContext; - PROPSHEETHEADER propSheetHeader; - - propContext = PhCreateObject(sizeof(PH_PROCESS_PROPCONTEXT), PhpProcessPropContextType); - memset(propContext, 0, sizeof(PH_PROCESS_PROPCONTEXT)); - - propContext->PropSheetPages = PhAllocate(sizeof(HPROPSHEETPAGE) * PH_PROCESS_PROPCONTEXT_MAXPAGES); - - if (!PH_IS_FAKE_PROCESS_ID(ProcessItem->ProcessId)) - { - propContext->Title = PhFormatString( - L"%s (%u)", - ProcessItem->ProcessName->Buffer, - HandleToUlong(ProcessItem->ProcessId) - ); - } - else - { - PhSetReference(&propContext->Title, ProcessItem->ProcessName); - } - - memset(&propSheetHeader, 0, sizeof(PROPSHEETHEADER)); - propSheetHeader.dwSize = sizeof(PROPSHEETHEADER); - propSheetHeader.dwFlags = - PSH_MODELESS | - PSH_NOAPPLYNOW | - PSH_NOCONTEXTHELP | - PSH_PROPTITLE | - PSH_USECALLBACK | - PSH_USEHICON; - propSheetHeader.hwndParent = ParentWindowHandle; - propSheetHeader.hIcon = ProcessItem->SmallIcon; - propSheetHeader.pszCaption = propContext->Title->Buffer; - propSheetHeader.pfnCallback = PhpPropSheetProc; - - propSheetHeader.nPages = 0; - propSheetHeader.nStartPage = 0; - propSheetHeader.phpage = propContext->PropSheetPages; - - if (PhCsForceNoParent) - propSheetHeader.hwndParent = NULL; - - memcpy(&propContext->PropSheetHeader, &propSheetHeader, sizeof(PROPSHEETHEADER)); - - PhSetReference(&propContext->ProcessItem, ProcessItem); - PhInitializeEvent(&propContext->CreatedEvent); - - return propContext; -} - -VOID NTAPI PhpProcessPropContextDeleteProcedure( - _In_ PVOID Object, - _In_ ULONG Flags - ) -{ - PPH_PROCESS_PROPCONTEXT propContext = (PPH_PROCESS_PROPCONTEXT)Object; - - PhFree(propContext->PropSheetPages); - PhDereferenceObject(propContext->Title); - PhDereferenceObject(propContext->ProcessItem); -} - -VOID PhRefreshProcessPropContext( - _Inout_ PPH_PROCESS_PROPCONTEXT PropContext - ) -{ - PropContext->PropSheetHeader.hIcon = PropContext->ProcessItem->SmallIcon; -} - -VOID PhSetSelectThreadIdProcessPropContext( - _Inout_ PPH_PROCESS_PROPCONTEXT PropContext, - _In_ HANDLE ThreadId - ) -{ - PropContext->SelectThreadId = ThreadId; -} - -INT CALLBACK PhpPropSheetProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ LPARAM lParam - ) -{ -#define PROPSHEET_ADD_STYLE (WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_THICKFRAME); - - switch (uMsg) - { - case PSCB_PRECREATE: - { - if (lParam) - { - if (((DLGTEMPLATEEX *)lParam)->signature == 0xffff) - { - ((DLGTEMPLATEEX *)lParam)->style |= PROPSHEET_ADD_STYLE; - } - else - { - ((DLGTEMPLATE *)lParam)->style |= PROPSHEET_ADD_STYLE; - } - } - } - break; - case PSCB_INITIALIZED: - { - PPH_PROCESS_PROPSHEETCONTEXT propSheetContext; - - propSheetContext = PhAllocate(sizeof(PH_PROCESS_PROPSHEETCONTEXT)); - memset(propSheetContext, 0, sizeof(PH_PROCESS_PROPSHEETCONTEXT)); - - PhInitializeLayoutManager(&propSheetContext->LayoutManager, hwndDlg); - - SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)propSheetContext); - SetWindowSubclass(hwndDlg, PhpPropSheetWndProc, 0, (ULONG_PTR)propSheetContext); - - if (MinimumSize.left == -1) - { - RECT rect; - - rect.left = 0; - rect.top = 0; - rect.right = 290; - rect.bottom = 320; - MapDialogRect(hwndDlg, &rect); - MinimumSize = rect; - MinimumSize.left = 0; - } - } - break; - } - - return 0; -} - -PPH_PROCESS_PROPSHEETCONTEXT PhpGetPropSheetContext( - _In_ HWND hwnd - ) -{ - return (PPH_PROCESS_PROPSHEETCONTEXT)GetProp(hwnd, PhMakeContextAtom()); -} - -LRESULT CALLBACK PhpPropSheetWndProc( - _In_ HWND hwnd, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam, - _In_ UINT_PTR uIdSubclass, - _In_ ULONG_PTR dwRefData - ) -{ - PPH_PROCESS_PROPSHEETCONTEXT propSheetContext = (PPH_PROCESS_PROPSHEETCONTEXT)dwRefData; - - switch (uMsg) - { - case WM_DESTROY: - { - HWND tabControl; - TCITEM tabItem; - WCHAR text[128]; - - // Save the window position and size. - - PhSaveWindowPlacementToSetting(L"ProcPropPosition", L"ProcPropSize", hwnd); - - // Save the selected tab. - - tabControl = PropSheet_GetTabControl(hwnd); - - tabItem.mask = TCIF_TEXT; - tabItem.pszText = text; - tabItem.cchTextMax = sizeof(text) / 2 - 1; - - if (TabCtrl_GetItem(tabControl, TabCtrl_GetCurSel(tabControl), &tabItem)) - { - PhSetStringSetting(L"ProcPropPage", text); - } - } - break; - case WM_NCDESTROY: - { - RemoveWindowSubclass(hwnd, PhpPropSheetWndProc, uIdSubclass); - RemoveProp(hwnd, PhMakeContextAtom()); - - PhDeleteLayoutManager(&propSheetContext->LayoutManager); - PhFree(propSheetContext); - } - break; - case WM_COMMAND: - { - switch (LOWORD(wParam)) - { - case IDOK: - // Prevent the OK button from working (even though - // it's already hidden). This prevents the Enter - // key from closing the dialog box. - return 0; - } - } - break; - case WM_SIZE: - { - if (!IsIconic(hwnd)) - { - PhLayoutManagerLayout(&propSheetContext->LayoutManager); - } - } - break; - case WM_SIZING: - { - PhResizingMinimumSize((PRECT)lParam, wParam, MinimumSize.right, MinimumSize.bottom); - } - break; - } - - return DefSubclassProc(hwnd, uMsg, wParam, lParam); -} - -BOOLEAN PhpInitializePropSheetLayoutStage1( - _In_ PPH_PROCESS_PROPSHEETCONTEXT Context, - _In_ HWND hwnd - ) -{ - if (!Context->LayoutInitialized) - { - HWND tabControlHandle; - PPH_LAYOUT_ITEM tabControlItem; - PPH_LAYOUT_ITEM tabPageItem; - - tabControlHandle = PropSheet_GetTabControl(hwnd); - tabControlItem = PhAddLayoutItem(&Context->LayoutManager, tabControlHandle, - NULL, PH_ANCHOR_ALL | PH_LAYOUT_IMMEDIATE_RESIZE); - tabPageItem = PhAddLayoutItem(&Context->LayoutManager, tabControlHandle, - NULL, PH_LAYOUT_TAB_CONTROL); // dummy item to fix multiline tab control - - Context->TabPageItem = tabPageItem; - - PhAddLayoutItem(&Context->LayoutManager, GetDlgItem(hwnd, IDCANCEL), - NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); - - // Hide the OK button. - ShowWindow(GetDlgItem(hwnd, IDOK), SW_HIDE); - // Set the Cancel button's text to "Close". - SetDlgItemText(hwnd, IDCANCEL, L"Close"); - - Context->LayoutInitialized = TRUE; - - return TRUE; - } - - return FALSE; -} - -VOID PhpInitializePropSheetLayoutStage2( - _In_ HWND hwnd - ) -{ - PH_RECTANGLE windowRectangle; - - windowRectangle.Position = PhGetIntegerPairSetting(L"ProcPropPosition"); - windowRectangle.Size = PhGetScalableIntegerPairSetting(L"ProcPropSize", TRUE).Pair; - - if (windowRectangle.Size.X < MinimumSize.right) - windowRectangle.Size.X = MinimumSize.right; - if (windowRectangle.Size.Y < MinimumSize.bottom) - windowRectangle.Size.Y = MinimumSize.bottom; - - PhAdjustRectangleToWorkingArea(NULL, &windowRectangle); - - MoveWindow(hwnd, windowRectangle.Left, windowRectangle.Top, - windowRectangle.Width, windowRectangle.Height, FALSE); - - // Implement cascading by saving an offsetted rectangle. - windowRectangle.Left += 20; - windowRectangle.Top += 20; - - PhSetIntegerPairSetting(L"ProcPropPosition", windowRectangle.Position); -} - -BOOLEAN PhAddProcessPropPage( - _Inout_ PPH_PROCESS_PROPCONTEXT PropContext, - _In_ _Assume_refs_(1) PPH_PROCESS_PROPPAGECONTEXT PropPageContext - ) -{ - HPROPSHEETPAGE propSheetPageHandle; - - if (PropContext->PropSheetHeader.nPages == PH_PROCESS_PROPCONTEXT_MAXPAGES) - return FALSE; - - propSheetPageHandle = CreatePropertySheetPage( - &PropPageContext->PropSheetPage - ); - // CreatePropertySheetPage would have sent PSPCB_ADDREF, - // which would have added a reference. - PhDereferenceObject(PropPageContext); - - PropPageContext->PropContext = PropContext; - PhReferenceObject(PropContext); - - PropContext->PropSheetPages[PropContext->PropSheetHeader.nPages] = - propSheetPageHandle; - PropContext->PropSheetHeader.nPages++; - - return TRUE; -} - -BOOLEAN PhAddProcessPropPage2( - _Inout_ PPH_PROCESS_PROPCONTEXT PropContext, - _In_ HPROPSHEETPAGE PropSheetPageHandle - ) -{ - if (PropContext->PropSheetHeader.nPages == PH_PROCESS_PROPCONTEXT_MAXPAGES) - return FALSE; - - PropContext->PropSheetPages[PropContext->PropSheetHeader.nPages] = - PropSheetPageHandle; - PropContext->PropSheetHeader.nPages++; - - return TRUE; -} - -PPH_PROCESS_PROPPAGECONTEXT PhCreateProcessPropPageContext( - _In_ LPCWSTR Template, - _In_ DLGPROC DlgProc, - _In_opt_ PVOID Context - ) -{ - return PhCreateProcessPropPageContextEx(NULL, Template, DlgProc, Context); -} - -PPH_PROCESS_PROPPAGECONTEXT PhCreateProcessPropPageContextEx( - _In_opt_ PVOID InstanceHandle, - _In_ LPCWSTR Template, - _In_ DLGPROC DlgProc, - _In_opt_ PVOID Context - ) -{ - PPH_PROCESS_PROPPAGECONTEXT propPageContext; - - propPageContext = PhCreateObject(sizeof(PH_PROCESS_PROPPAGECONTEXT), PhpProcessPropPageContextType); - memset(propPageContext, 0, sizeof(PH_PROCESS_PROPPAGECONTEXT)); - - propPageContext->PropSheetPage.dwSize = sizeof(PROPSHEETPAGE); - propPageContext->PropSheetPage.dwFlags = - PSP_USECALLBACK; - propPageContext->PropSheetPage.hInstance = InstanceHandle; - propPageContext->PropSheetPage.pszTemplate = Template; - propPageContext->PropSheetPage.pfnDlgProc = DlgProc; - propPageContext->PropSheetPage.lParam = (LPARAM)propPageContext; - propPageContext->PropSheetPage.pfnCallback = PhpStandardPropPageProc; - - propPageContext->Context = Context; - - return propPageContext; -} - -VOID NTAPI PhpProcessPropPageContextDeleteProcedure( - _In_ PVOID Object, - _In_ ULONG Flags - ) -{ - PPH_PROCESS_PROPPAGECONTEXT propPageContext = (PPH_PROCESS_PROPPAGECONTEXT)Object; - - if (propPageContext->PropContext) - PhDereferenceObject(propPageContext->PropContext); -} - -INT CALLBACK PhpStandardPropPageProc( - _In_ HWND hwnd, - _In_ UINT uMsg, - _In_ LPPROPSHEETPAGE ppsp - ) -{ - PPH_PROCESS_PROPPAGECONTEXT propPageContext; - - propPageContext = (PPH_PROCESS_PROPPAGECONTEXT)ppsp->lParam; - - if (uMsg == PSPCB_ADDREF) - PhReferenceObject(propPageContext); - else if (uMsg == PSPCB_RELEASE) - PhDereferenceObject(propPageContext); - - return 1; -} - -BOOLEAN PhPropPageDlgProcHeader( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ LPARAM lParam, - _Out_ LPPROPSHEETPAGE *PropSheetPage, - _Out_ PPH_PROCESS_PROPPAGECONTEXT *PropPageContext, - _Out_ PPH_PROCESS_ITEM *ProcessItem - ) -{ - return PhpPropPageDlgProcHeader(hwndDlg, uMsg, lParam, PropSheetPage, PropPageContext, ProcessItem); -} - -VOID PhPropPageDlgProcDestroy( - _In_ HWND hwndDlg - ) -{ - PhpPropPageDlgProcDestroy(hwndDlg); -} - -PPH_LAYOUT_ITEM PhAddPropPageLayoutItem( - _In_ HWND hwnd, - _In_ HWND Handle, - _In_ PPH_LAYOUT_ITEM ParentItem, - _In_ ULONG Anchor - ) -{ - HWND parent; - PPH_PROCESS_PROPSHEETCONTEXT propSheetContext; - PPH_LAYOUT_MANAGER layoutManager; - PPH_LAYOUT_ITEM realParentItem; - BOOLEAN doLayoutStage2; - PPH_LAYOUT_ITEM item; - - parent = GetParent(hwnd); - propSheetContext = PhpGetPropSheetContext(parent); - layoutManager = &propSheetContext->LayoutManager; - - doLayoutStage2 = PhpInitializePropSheetLayoutStage1(propSheetContext, parent); - - if (ParentItem != PH_PROP_PAGE_TAB_CONTROL_PARENT) - realParentItem = ParentItem; - else - realParentItem = propSheetContext->TabPageItem; - - // Use the HACK if the control is a direct child of the dialog. - if (ParentItem && ParentItem != PH_PROP_PAGE_TAB_CONTROL_PARENT && - // We detect if ParentItem is the layout item for the dialog - // by looking at its parent. - (ParentItem->ParentItem == &layoutManager->RootItem || - (ParentItem->ParentItem->Anchor & PH_LAYOUT_TAB_CONTROL))) - { - RECT dialogRect; - RECT dialogSize; - RECT margin; - - // MAKE SURE THESE NUMBERS ARE CORRECT. - dialogSize.right = 260; - dialogSize.bottom = 260; - MapDialogRect(hwnd, &dialogSize); - - // Get the original dialog rectangle. - GetWindowRect(hwnd, &dialogRect); - dialogRect.right = dialogRect.left + dialogSize.right; - dialogRect.bottom = dialogRect.top + dialogSize.bottom; - - // Calculate the margin from the original rectangle. - GetWindowRect(Handle, &margin); - margin = PhMapRect(margin, dialogRect); - PhConvertRect(&margin, &dialogRect); - - item = PhAddLayoutItemEx(layoutManager, Handle, realParentItem, Anchor, margin); - } - else - { - item = PhAddLayoutItem(layoutManager, Handle, realParentItem, Anchor); - } - - if (doLayoutStage2) - PhpInitializePropSheetLayoutStage2(parent); - - return item; -} - -VOID PhDoPropPageLayout( - _In_ HWND hwnd - ) -{ - HWND parent; - PPH_PROCESS_PROPSHEETCONTEXT propSheetContext; - - parent = GetParent(hwnd); - propSheetContext = PhpGetPropSheetContext(parent); - PhLayoutManagerLayout(&propSheetContext->LayoutManager); -} - -NTSTATUS PhpProcessPropertiesThreadStart( - _In_ PVOID Parameter - ) -{ - PH_AUTO_POOL autoPool; - PPH_PROCESS_PROPCONTEXT PropContext = (PPH_PROCESS_PROPCONTEXT)Parameter; - PPH_PROCESS_PROPPAGECONTEXT newPage; - PPH_STRING startPage; - HWND hwnd; - BOOL result; - MSG message; - - PhInitializeAutoPool(&autoPool); - - // Wait for stage 1 to be processed. - PhWaitForEvent(&PropContext->ProcessItem->Stage1Event, NULL); - // Refresh the icon which may have been updated due to - // stage 1. - PhRefreshProcessPropContext(PropContext); - - // Add the pages... - - // General - newPage = PhCreateProcessPropPageContext( - MAKEINTRESOURCE(IDD_PROCGENERAL), - PhpProcessGeneralDlgProc, - NULL - ); - PhAddProcessPropPage(PropContext, newPage); - - // Statistics - newPage = PhCreateProcessPropPageContext( - MAKEINTRESOURCE(IDD_PROCSTATISTICS), - PhpProcessStatisticsDlgProc, - NULL - ); - PhAddProcessPropPage(PropContext, newPage); - - // Performance - newPage = PhCreateProcessPropPageContext( - MAKEINTRESOURCE(IDD_PROCPERFORMANCE), - PhpProcessPerformanceDlgProc, - NULL - ); - PhAddProcessPropPage(PropContext, newPage); - - // Threads - newPage = PhCreateProcessPropPageContext( - MAKEINTRESOURCE(IDD_PROCTHREADS), - PhpProcessThreadsDlgProc, - NULL - ); - PhAddProcessPropPage(PropContext, newPage); - - // Token - PhAddProcessPropPage2( - PropContext, - PhCreateTokenPage(PhpOpenProcessTokenForPage, (PVOID)PropContext->ProcessItem->ProcessId, PhpProcessTokenHookProc) - ); - - // Modules - newPage = PhCreateProcessPropPageContext( - MAKEINTRESOURCE(IDD_PROCMODULES), - PhpProcessModulesDlgProc, - NULL - ); - PhAddProcessPropPage(PropContext, newPage); - - // Memory - newPage = PhCreateProcessPropPageContext( - MAKEINTRESOURCE(IDD_PROCMEMORY), - PhpProcessMemoryDlgProc, - NULL - ); - PhAddProcessPropPage(PropContext, newPage); - - // Environment - newPage = PhCreateProcessPropPageContext( - MAKEINTRESOURCE(IDD_PROCENVIRONMENT), - PhpProcessEnvironmentDlgProc, - NULL - ); - PhAddProcessPropPage(PropContext, newPage); - - // Handles - newPage = PhCreateProcessPropPageContext( - MAKEINTRESOURCE(IDD_PROCHANDLES), - PhpProcessHandlesDlgProc, - NULL - ); - PhAddProcessPropPage(PropContext, newPage); - - // Job - if ( - PropContext->ProcessItem->IsInJob && - // There's no way the job page can function without KPH since it needs - // to open a handle to the job. - KphIsConnected() - ) - { - PhAddProcessPropPage2( - PropContext, - PhCreateJobPage(PhpOpenProcessJobForPage, (PVOID)PropContext->ProcessItem->ProcessId, PhpProcessJobHookProc) - ); - } - - // Services - if (PropContext->ProcessItem->ServiceList && PropContext->ProcessItem->ServiceList->Count != 0) - { - newPage = PhCreateProcessPropPageContext( - MAKEINTRESOURCE(IDD_PROCSERVICES), - PhpProcessServicesDlgProc, - NULL - ); - PhAddProcessPropPage(PropContext, newPage); - } - - // Plugin-supplied pages - if (PhPluginsEnabled) - { - PH_PLUGIN_PROCESS_PROPCONTEXT pluginProcessPropContext; - - pluginProcessPropContext.PropContext = PropContext; - pluginProcessPropContext.ProcessItem = PropContext->ProcessItem; - - PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackProcessPropertiesInitializing), &pluginProcessPropContext); - } - - // Create the property sheet - - if (PropContext->SelectThreadId) - PhSetStringSetting(L"ProcPropPage", L"Threads"); - - startPage = PhGetStringSetting(L"ProcPropPage"); - PropContext->PropSheetHeader.dwFlags |= PSH_USEPSTARTPAGE; - PropContext->PropSheetHeader.pStartPage = startPage->Buffer; - - hwnd = (HWND)PropertySheet(&PropContext->PropSheetHeader); - - PhDereferenceObject(startPage); - - PropContext->WindowHandle = hwnd; - PhSetEvent(&PropContext->CreatedEvent); - - // Main event loop - - while (result = GetMessage(&message, NULL, 0, 0)) - { - if (result == -1) - break; - - if (!PropSheet_IsDialogMessage(hwnd, &message)) - { - TranslateMessage(&message); - DispatchMessage(&message); - } - - PhDrainAutoPool(&autoPool); - - if (!PropSheet_GetCurrentPageHwnd(hwnd)) - break; - } - - DestroyWindow(hwnd); - PhDereferenceObject(PropContext); - - PhDeleteAutoPool(&autoPool); - - return STATUS_SUCCESS; -} - -BOOLEAN PhShowProcessProperties( - _In_ PPH_PROCESS_PROPCONTEXT Context - ) -{ - HANDLE threadHandle; - - PhReferenceObject(Context); - threadHandle = PhCreateThread(0, PhpProcessPropertiesThreadStart, Context); - - if (threadHandle) - { - NtClose(threadHandle); - return TRUE; - } - else - { - PhDereferenceObject(Context); - return FALSE; - } -} +/* + * Process Hacker - + * Process properties + * + * Copyright (C) 2009-2016 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include +#include +#include + +#include + +#include + +#include +#include +#include + +PPH_OBJECT_TYPE PhpProcessPropContextType; +PPH_OBJECT_TYPE PhpProcessPropPageContextType; +PH_STRINGREF PhpLoadingText = PH_STRINGREF_INIT(L"Loading..."); + +static RECT MinimumSize = { -1, -1, -1, -1 }; + +BOOLEAN PhProcessPropInitialization( + VOID + ) +{ + PhpProcessPropContextType = PhCreateObjectType(L"ProcessPropContext", 0, PhpProcessPropContextDeleteProcedure); + PhpProcessPropPageContextType = PhCreateObjectType(L"ProcessPropPageContext", 0, PhpProcessPropPageContextDeleteProcedure); + + return TRUE; +} + +PPH_PROCESS_PROPCONTEXT PhCreateProcessPropContext( + _In_ HWND ParentWindowHandle, + _In_ PPH_PROCESS_ITEM ProcessItem + ) +{ + PPH_PROCESS_PROPCONTEXT propContext; + PROPSHEETHEADER propSheetHeader; + + propContext = PhCreateObject(sizeof(PH_PROCESS_PROPCONTEXT), PhpProcessPropContextType); + memset(propContext, 0, sizeof(PH_PROCESS_PROPCONTEXT)); + + propContext->PropSheetPages = PhAllocate(sizeof(HPROPSHEETPAGE) * PH_PROCESS_PROPCONTEXT_MAXPAGES); + + if (!PH_IS_FAKE_PROCESS_ID(ProcessItem->ProcessId)) + { + propContext->Title = PhFormatString( + L"%s (%u)", + ProcessItem->ProcessName->Buffer, + HandleToUlong(ProcessItem->ProcessId) + ); + } + else + { + PhSetReference(&propContext->Title, ProcessItem->ProcessName); + } + + memset(&propSheetHeader, 0, sizeof(PROPSHEETHEADER)); + propSheetHeader.dwSize = sizeof(PROPSHEETHEADER); + propSheetHeader.dwFlags = + PSH_MODELESS | + PSH_NOAPPLYNOW | + PSH_NOCONTEXTHELP | + PSH_PROPTITLE | + PSH_USECALLBACK | + PSH_USEHICON; + propSheetHeader.hwndParent = ParentWindowHandle; + propSheetHeader.hIcon = ProcessItem->SmallIcon; + propSheetHeader.pszCaption = propContext->Title->Buffer; + propSheetHeader.pfnCallback = PhpPropSheetProc; + + propSheetHeader.nPages = 0; + propSheetHeader.nStartPage = 0; + propSheetHeader.phpage = propContext->PropSheetPages; + + if (PhCsForceNoParent) + propSheetHeader.hwndParent = NULL; + + memcpy(&propContext->PropSheetHeader, &propSheetHeader, sizeof(PROPSHEETHEADER)); + + PhSetReference(&propContext->ProcessItem, ProcessItem); + PhInitializeEvent(&propContext->CreatedEvent); + + return propContext; +} + +VOID NTAPI PhpProcessPropContextDeleteProcedure( + _In_ PVOID Object, + _In_ ULONG Flags + ) +{ + PPH_PROCESS_PROPCONTEXT propContext = (PPH_PROCESS_PROPCONTEXT)Object; + + PhFree(propContext->PropSheetPages); + PhDereferenceObject(propContext->Title); + PhDereferenceObject(propContext->ProcessItem); +} + +VOID PhRefreshProcessPropContext( + _Inout_ PPH_PROCESS_PROPCONTEXT PropContext + ) +{ + PropContext->PropSheetHeader.hIcon = PropContext->ProcessItem->SmallIcon; +} + +VOID PhSetSelectThreadIdProcessPropContext( + _Inout_ PPH_PROCESS_PROPCONTEXT PropContext, + _In_ HANDLE ThreadId + ) +{ + PropContext->SelectThreadId = ThreadId; +} + +INT CALLBACK PhpPropSheetProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ LPARAM lParam + ) +{ +#define PROPSHEET_ADD_STYLE (WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_THICKFRAME); + + switch (uMsg) + { + case PSCB_PRECREATE: + { + if (lParam) + { + if (((DLGTEMPLATEEX *)lParam)->signature == 0xffff) + { + ((DLGTEMPLATEEX *)lParam)->style |= PROPSHEET_ADD_STYLE; + } + else + { + ((DLGTEMPLATE *)lParam)->style |= PROPSHEET_ADD_STYLE; + } + } + } + break; + case PSCB_INITIALIZED: + { + PPH_PROCESS_PROPSHEETCONTEXT propSheetContext; + + propSheetContext = PhAllocate(sizeof(PH_PROCESS_PROPSHEETCONTEXT)); + memset(propSheetContext, 0, sizeof(PH_PROCESS_PROPSHEETCONTEXT)); + + PhInitializeLayoutManager(&propSheetContext->LayoutManager, hwndDlg); + + SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)propSheetContext); + SetWindowSubclass(hwndDlg, PhpPropSheetWndProc, 0, (ULONG_PTR)propSheetContext); + + if (MinimumSize.left == -1) + { + RECT rect; + + rect.left = 0; + rect.top = 0; + rect.right = 290; + rect.bottom = 320; + MapDialogRect(hwndDlg, &rect); + MinimumSize = rect; + MinimumSize.left = 0; + } + } + break; + } + + return 0; +} + +PPH_PROCESS_PROPSHEETCONTEXT PhpGetPropSheetContext( + _In_ HWND hwnd + ) +{ + return (PPH_PROCESS_PROPSHEETCONTEXT)GetProp(hwnd, PhMakeContextAtom()); +} + +LRESULT CALLBACK PhpPropSheetWndProc( + _In_ HWND hwnd, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam, + _In_ UINT_PTR uIdSubclass, + _In_ ULONG_PTR dwRefData + ) +{ + PPH_PROCESS_PROPSHEETCONTEXT propSheetContext = (PPH_PROCESS_PROPSHEETCONTEXT)dwRefData; + + switch (uMsg) + { + case WM_DESTROY: + { + HWND tabControl; + TCITEM tabItem; + WCHAR text[128]; + + // Save the window position and size. + + PhSaveWindowPlacementToSetting(L"ProcPropPosition", L"ProcPropSize", hwnd); + + // Save the selected tab. + + tabControl = PropSheet_GetTabControl(hwnd); + + tabItem.mask = TCIF_TEXT; + tabItem.pszText = text; + tabItem.cchTextMax = sizeof(text) / 2 - 1; + + if (TabCtrl_GetItem(tabControl, TabCtrl_GetCurSel(tabControl), &tabItem)) + { + PhSetStringSetting(L"ProcPropPage", text); + } + } + break; + case WM_NCDESTROY: + { + RemoveWindowSubclass(hwnd, PhpPropSheetWndProc, uIdSubclass); + RemoveProp(hwnd, PhMakeContextAtom()); + + PhDeleteLayoutManager(&propSheetContext->LayoutManager); + PhFree(propSheetContext); + } + break; + case WM_COMMAND: + { + switch (LOWORD(wParam)) + { + case IDOK: + // Prevent the OK button from working (even though + // it's already hidden). This prevents the Enter + // key from closing the dialog box. + return 0; + } + } + break; + case WM_SIZE: + { + if (!IsIconic(hwnd)) + { + PhLayoutManagerLayout(&propSheetContext->LayoutManager); + } + } + break; + case WM_SIZING: + { + PhResizingMinimumSize((PRECT)lParam, wParam, MinimumSize.right, MinimumSize.bottom); + } + break; + } + + return DefSubclassProc(hwnd, uMsg, wParam, lParam); +} + +BOOLEAN PhpInitializePropSheetLayoutStage1( + _In_ PPH_PROCESS_PROPSHEETCONTEXT Context, + _In_ HWND hwnd + ) +{ + if (!Context->LayoutInitialized) + { + HWND tabControlHandle; + PPH_LAYOUT_ITEM tabControlItem; + PPH_LAYOUT_ITEM tabPageItem; + + tabControlHandle = PropSheet_GetTabControl(hwnd); + tabControlItem = PhAddLayoutItem(&Context->LayoutManager, tabControlHandle, + NULL, PH_ANCHOR_ALL | PH_LAYOUT_IMMEDIATE_RESIZE); + tabPageItem = PhAddLayoutItem(&Context->LayoutManager, tabControlHandle, + NULL, PH_LAYOUT_TAB_CONTROL); // dummy item to fix multiline tab control + + Context->TabPageItem = tabPageItem; + + PhAddLayoutItem(&Context->LayoutManager, GetDlgItem(hwnd, IDCANCEL), + NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); + + // Hide the OK button. + ShowWindow(GetDlgItem(hwnd, IDOK), SW_HIDE); + // Set the Cancel button's text to "Close". + SetDlgItemText(hwnd, IDCANCEL, L"Close"); + + Context->LayoutInitialized = TRUE; + + return TRUE; + } + + return FALSE; +} + +VOID PhpInitializePropSheetLayoutStage2( + _In_ HWND hwnd + ) +{ + PH_RECTANGLE windowRectangle; + + windowRectangle.Position = PhGetIntegerPairSetting(L"ProcPropPosition"); + windowRectangle.Size = PhGetScalableIntegerPairSetting(L"ProcPropSize", TRUE).Pair; + + if (windowRectangle.Size.X < MinimumSize.right) + windowRectangle.Size.X = MinimumSize.right; + if (windowRectangle.Size.Y < MinimumSize.bottom) + windowRectangle.Size.Y = MinimumSize.bottom; + + PhAdjustRectangleToWorkingArea(NULL, &windowRectangle); + + MoveWindow(hwnd, windowRectangle.Left, windowRectangle.Top, + windowRectangle.Width, windowRectangle.Height, FALSE); + + // Implement cascading by saving an offsetted rectangle. + windowRectangle.Left += 20; + windowRectangle.Top += 20; + + PhSetIntegerPairSetting(L"ProcPropPosition", windowRectangle.Position); +} + +BOOLEAN PhAddProcessPropPage( + _Inout_ PPH_PROCESS_PROPCONTEXT PropContext, + _In_ _Assume_refs_(1) PPH_PROCESS_PROPPAGECONTEXT PropPageContext + ) +{ + HPROPSHEETPAGE propSheetPageHandle; + + if (PropContext->PropSheetHeader.nPages == PH_PROCESS_PROPCONTEXT_MAXPAGES) + return FALSE; + + propSheetPageHandle = CreatePropertySheetPage( + &PropPageContext->PropSheetPage + ); + // CreatePropertySheetPage would have sent PSPCB_ADDREF, + // which would have added a reference. + PhDereferenceObject(PropPageContext); + + PropPageContext->PropContext = PropContext; + PhReferenceObject(PropContext); + + PropContext->PropSheetPages[PropContext->PropSheetHeader.nPages] = + propSheetPageHandle; + PropContext->PropSheetHeader.nPages++; + + return TRUE; +} + +BOOLEAN PhAddProcessPropPage2( + _Inout_ PPH_PROCESS_PROPCONTEXT PropContext, + _In_ HPROPSHEETPAGE PropSheetPageHandle + ) +{ + if (PropContext->PropSheetHeader.nPages == PH_PROCESS_PROPCONTEXT_MAXPAGES) + return FALSE; + + PropContext->PropSheetPages[PropContext->PropSheetHeader.nPages] = + PropSheetPageHandle; + PropContext->PropSheetHeader.nPages++; + + return TRUE; +} + +PPH_PROCESS_PROPPAGECONTEXT PhCreateProcessPropPageContext( + _In_ LPCWSTR Template, + _In_ DLGPROC DlgProc, + _In_opt_ PVOID Context + ) +{ + return PhCreateProcessPropPageContextEx(NULL, Template, DlgProc, Context); +} + +PPH_PROCESS_PROPPAGECONTEXT PhCreateProcessPropPageContextEx( + _In_opt_ PVOID InstanceHandle, + _In_ LPCWSTR Template, + _In_ DLGPROC DlgProc, + _In_opt_ PVOID Context + ) +{ + PPH_PROCESS_PROPPAGECONTEXT propPageContext; + + propPageContext = PhCreateObject(sizeof(PH_PROCESS_PROPPAGECONTEXT), PhpProcessPropPageContextType); + memset(propPageContext, 0, sizeof(PH_PROCESS_PROPPAGECONTEXT)); + + propPageContext->PropSheetPage.dwSize = sizeof(PROPSHEETPAGE); + propPageContext->PropSheetPage.dwFlags = + PSP_USECALLBACK; + propPageContext->PropSheetPage.hInstance = InstanceHandle; + propPageContext->PropSheetPage.pszTemplate = Template; + propPageContext->PropSheetPage.pfnDlgProc = DlgProc; + propPageContext->PropSheetPage.lParam = (LPARAM)propPageContext; + propPageContext->PropSheetPage.pfnCallback = PhpStandardPropPageProc; + + propPageContext->Context = Context; + + return propPageContext; +} + +VOID NTAPI PhpProcessPropPageContextDeleteProcedure( + _In_ PVOID Object, + _In_ ULONG Flags + ) +{ + PPH_PROCESS_PROPPAGECONTEXT propPageContext = (PPH_PROCESS_PROPPAGECONTEXT)Object; + + if (propPageContext->PropContext) + PhDereferenceObject(propPageContext->PropContext); +} + +INT CALLBACK PhpStandardPropPageProc( + _In_ HWND hwnd, + _In_ UINT uMsg, + _In_ LPPROPSHEETPAGE ppsp + ) +{ + PPH_PROCESS_PROPPAGECONTEXT propPageContext; + + propPageContext = (PPH_PROCESS_PROPPAGECONTEXT)ppsp->lParam; + + if (uMsg == PSPCB_ADDREF) + PhReferenceObject(propPageContext); + else if (uMsg == PSPCB_RELEASE) + PhDereferenceObject(propPageContext); + + return 1; +} + +BOOLEAN PhPropPageDlgProcHeader( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ LPARAM lParam, + _Out_ LPPROPSHEETPAGE *PropSheetPage, + _Out_ PPH_PROCESS_PROPPAGECONTEXT *PropPageContext, + _Out_ PPH_PROCESS_ITEM *ProcessItem + ) +{ + return PhpPropPageDlgProcHeader(hwndDlg, uMsg, lParam, PropSheetPage, PropPageContext, ProcessItem); +} + +VOID PhPropPageDlgProcDestroy( + _In_ HWND hwndDlg + ) +{ + PhpPropPageDlgProcDestroy(hwndDlg); +} + +PPH_LAYOUT_ITEM PhAddPropPageLayoutItem( + _In_ HWND hwnd, + _In_ HWND Handle, + _In_ PPH_LAYOUT_ITEM ParentItem, + _In_ ULONG Anchor + ) +{ + HWND parent; + PPH_PROCESS_PROPSHEETCONTEXT propSheetContext; + PPH_LAYOUT_MANAGER layoutManager; + PPH_LAYOUT_ITEM realParentItem; + BOOLEAN doLayoutStage2; + PPH_LAYOUT_ITEM item; + + parent = GetParent(hwnd); + propSheetContext = PhpGetPropSheetContext(parent); + layoutManager = &propSheetContext->LayoutManager; + + doLayoutStage2 = PhpInitializePropSheetLayoutStage1(propSheetContext, parent); + + if (ParentItem != PH_PROP_PAGE_TAB_CONTROL_PARENT) + realParentItem = ParentItem; + else + realParentItem = propSheetContext->TabPageItem; + + // Use the HACK if the control is a direct child of the dialog. + if (ParentItem && ParentItem != PH_PROP_PAGE_TAB_CONTROL_PARENT && + // We detect if ParentItem is the layout item for the dialog + // by looking at its parent. + (ParentItem->ParentItem == &layoutManager->RootItem || + (ParentItem->ParentItem->Anchor & PH_LAYOUT_TAB_CONTROL))) + { + RECT dialogRect; + RECT dialogSize; + RECT margin; + + // MAKE SURE THESE NUMBERS ARE CORRECT. + dialogSize.right = 260; + dialogSize.bottom = 260; + MapDialogRect(hwnd, &dialogSize); + + // Get the original dialog rectangle. + GetWindowRect(hwnd, &dialogRect); + dialogRect.right = dialogRect.left + dialogSize.right; + dialogRect.bottom = dialogRect.top + dialogSize.bottom; + + // Calculate the margin from the original rectangle. + GetWindowRect(Handle, &margin); + margin = PhMapRect(margin, dialogRect); + PhConvertRect(&margin, &dialogRect); + + item = PhAddLayoutItemEx(layoutManager, Handle, realParentItem, Anchor, margin); + } + else + { + item = PhAddLayoutItem(layoutManager, Handle, realParentItem, Anchor); + } + + if (doLayoutStage2) + PhpInitializePropSheetLayoutStage2(parent); + + return item; +} + +VOID PhDoPropPageLayout( + _In_ HWND hwnd + ) +{ + HWND parent; + PPH_PROCESS_PROPSHEETCONTEXT propSheetContext; + + parent = GetParent(hwnd); + propSheetContext = PhpGetPropSheetContext(parent); + PhLayoutManagerLayout(&propSheetContext->LayoutManager); +} + +NTSTATUS PhpProcessPropertiesThreadStart( + _In_ PVOID Parameter + ) +{ + PH_AUTO_POOL autoPool; + PPH_PROCESS_PROPCONTEXT PropContext = (PPH_PROCESS_PROPCONTEXT)Parameter; + PPH_PROCESS_PROPPAGECONTEXT newPage; + PPH_STRING startPage; + HWND hwnd; + BOOL result; + MSG message; + + PhInitializeAutoPool(&autoPool); + + // Wait for stage 1 to be processed. + PhWaitForEvent(&PropContext->ProcessItem->Stage1Event, NULL); + // Refresh the icon which may have been updated due to + // stage 1. + PhRefreshProcessPropContext(PropContext); + + // Add the pages... + + // General + newPage = PhCreateProcessPropPageContext( + MAKEINTRESOURCE(IDD_PROCGENERAL), + PhpProcessGeneralDlgProc, + NULL + ); + PhAddProcessPropPage(PropContext, newPage); + + // Statistics + newPage = PhCreateProcessPropPageContext( + MAKEINTRESOURCE(IDD_PROCSTATISTICS), + PhpProcessStatisticsDlgProc, + NULL + ); + PhAddProcessPropPage(PropContext, newPage); + + // Performance + newPage = PhCreateProcessPropPageContext( + MAKEINTRESOURCE(IDD_PROCPERFORMANCE), + PhpProcessPerformanceDlgProc, + NULL + ); + PhAddProcessPropPage(PropContext, newPage); + + // Threads + newPage = PhCreateProcessPropPageContext( + MAKEINTRESOURCE(IDD_PROCTHREADS), + PhpProcessThreadsDlgProc, + NULL + ); + PhAddProcessPropPage(PropContext, newPage); + + // Token + PhAddProcessPropPage2( + PropContext, + PhCreateTokenPage(PhpOpenProcessTokenForPage, (PVOID)PropContext->ProcessItem->ProcessId, PhpProcessTokenHookProc) + ); + + // Modules + newPage = PhCreateProcessPropPageContext( + MAKEINTRESOURCE(IDD_PROCMODULES), + PhpProcessModulesDlgProc, + NULL + ); + PhAddProcessPropPage(PropContext, newPage); + + // Memory + newPage = PhCreateProcessPropPageContext( + MAKEINTRESOURCE(IDD_PROCMEMORY), + PhpProcessMemoryDlgProc, + NULL + ); + PhAddProcessPropPage(PropContext, newPage); + + // Environment + newPage = PhCreateProcessPropPageContext( + MAKEINTRESOURCE(IDD_PROCENVIRONMENT), + PhpProcessEnvironmentDlgProc, + NULL + ); + PhAddProcessPropPage(PropContext, newPage); + + // Handles + newPage = PhCreateProcessPropPageContext( + MAKEINTRESOURCE(IDD_PROCHANDLES), + PhpProcessHandlesDlgProc, + NULL + ); + PhAddProcessPropPage(PropContext, newPage); + + // Job + if ( + PropContext->ProcessItem->IsInJob && + // There's no way the job page can function without KPH since it needs + // to open a handle to the job. + KphIsConnected() + ) + { + PhAddProcessPropPage2( + PropContext, + PhCreateJobPage(PhpOpenProcessJobForPage, (PVOID)PropContext->ProcessItem->ProcessId, PhpProcessJobHookProc) + ); + } + + // Services + if (PropContext->ProcessItem->ServiceList && PropContext->ProcessItem->ServiceList->Count != 0) + { + newPage = PhCreateProcessPropPageContext( + MAKEINTRESOURCE(IDD_PROCSERVICES), + PhpProcessServicesDlgProc, + NULL + ); + PhAddProcessPropPage(PropContext, newPage); + } + + // Plugin-supplied pages + if (PhPluginsEnabled) + { + PH_PLUGIN_PROCESS_PROPCONTEXT pluginProcessPropContext; + + pluginProcessPropContext.PropContext = PropContext; + pluginProcessPropContext.ProcessItem = PropContext->ProcessItem; + + PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackProcessPropertiesInitializing), &pluginProcessPropContext); + } + + // Create the property sheet + + if (PropContext->SelectThreadId) + PhSetStringSetting(L"ProcPropPage", L"Threads"); + + startPage = PhGetStringSetting(L"ProcPropPage"); + PropContext->PropSheetHeader.dwFlags |= PSH_USEPSTARTPAGE; + PropContext->PropSheetHeader.pStartPage = startPage->Buffer; + + hwnd = (HWND)PropertySheet(&PropContext->PropSheetHeader); + + PhDereferenceObject(startPage); + + PropContext->WindowHandle = hwnd; + PhSetEvent(&PropContext->CreatedEvent); + + // Main event loop + + while (result = GetMessage(&message, NULL, 0, 0)) + { + if (result == -1) + break; + + if (!PropSheet_IsDialogMessage(hwnd, &message)) + { + TranslateMessage(&message); + DispatchMessage(&message); + } + + PhDrainAutoPool(&autoPool); + + if (!PropSheet_GetCurrentPageHwnd(hwnd)) + break; + } + + DestroyWindow(hwnd); + PhDereferenceObject(PropContext); + + PhDeleteAutoPool(&autoPool); + + return STATUS_SUCCESS; +} + +BOOLEAN PhShowProcessProperties( + _In_ PPH_PROCESS_PROPCONTEXT Context + ) +{ + HANDLE threadHandle; + + PhReferenceObject(Context); + threadHandle = PhCreateThread(0, PhpProcessPropertiesThreadStart, Context); + + if (threadHandle) + { + NtClose(threadHandle); + return TRUE; + } + else + { + PhDereferenceObject(Context); + return FALSE; + } +} diff --git a/ProcessHacker/procprv.c b/ProcessHacker/procprv.c index 5640344ef0d5..9445050002f7 100644 --- a/ProcessHacker/procprv.c +++ b/ProcessHacker/procprv.c @@ -1,2979 +1,2979 @@ -/* - * Process Hacker - - * process provider - * - * Copyright (C) 2009-2016 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -/* - * This provider module handles the collection of process information and system-wide statistics. A - * list of all running processes is kept and periodically scanned to detect new and terminated - * processes. - * - * The retrieval of certain information is delayed in order to improve performance. This includes - * things such as file icons, version information, digital signature verification, and packed - * executable detection. These requests are handed to worker threads which then post back - * information to a S-list. - * - * Also contained in this module is the storage of process records, which contain static information - * about processes. Unlike process items which are removed as soon as their corresponding process - * exits, process records remain as long as they are needed by the statistics system, and more - * specifically the max. CPU and I/O history buffers. In PH 1.x, a new formatted string was created - * at each update containing information about the maximum-usage process within that interval. Here - * we use a much more storage-efficient method, where the raw maximum-usage PIDs are stored for each - * interval, and the process record list is searched when the name of a process is needed. - * - * The process record list is stored as a list of records sorted by process creation time. If two or - * more processes have the same creation time, they are added to a doubly-linked list. This - * structure allows for fast searching in the typical scenario where we know the PID of a process - * and a specific time in which the process was running. In this case a binary search is used and - * then the list is traversed backwards until the process is found. Binary search is similarly used - * for insertion and removal. - * - * On Windows 7 and above, CPU usage can be calculated from cycle time. However, cycle time cannot - * be split into kernel/user components, and cycle time is not available for DPCs and Interrupts - * separately (only a "system" cycle time). - */ - -#include -#include - -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include - -#define PROCESS_ID_BUCKETS 64 -#define PROCESS_ID_TO_BUCKET_INDEX(ProcessId) ((HandleToUlong(ProcessId) / 4) & (PROCESS_ID_BUCKETS - 1)) - -typedef struct _PH_PROCESS_QUERY_DATA -{ - SLIST_ENTRY ListEntry; - ULONG Stage; - PPH_PROCESS_ITEM ProcessItem; -} PH_PROCESS_QUERY_DATA, *PPH_PROCESS_QUERY_DATA; - -typedef struct _PH_PROCESS_QUERY_S1_DATA -{ - PH_PROCESS_QUERY_DATA Header; - - PPH_STRING CommandLine; - - HICON SmallIcon; - HICON LargeIcon; - PH_IMAGE_VERSION_INFO VersionInfo; - - TOKEN_ELEVATION_TYPE ElevationType; - MANDATORY_LEVEL IntegrityLevel; - PWSTR IntegrityString; - - PPH_STRING JobName; - HANDLE ConsoleHostProcessId; - PPH_STRING PackageFullName; - - union - { - ULONG Flags; - struct - { - ULONG IsDotNet : 1; - ULONG IsElevated : 1; - ULONG IsInJob : 1; - ULONG IsInSignificantJob : 1; - ULONG IsWow64 : 1; - ULONG IsWow64Valid : 1; - ULONG IsProtectedProcess : 1; - ULONG IsSecureProcess : 1; - ULONG IsSubsystemProcess : 1; - - ULONG Spare : 23; - }; - }; -} PH_PROCESS_QUERY_S1_DATA, *PPH_PROCESS_QUERY_S1_DATA; - -typedef struct _PH_PROCESS_QUERY_S2_DATA -{ - PH_PROCESS_QUERY_DATA Header; - - VERIFY_RESULT VerifyResult; - PPH_STRING VerifySignerName; - - BOOLEAN IsPacked; - ULONG ImportFunctions; - ULONG ImportModules; -} PH_PROCESS_QUERY_S2_DATA, *PPH_PROCESS_QUERY_S2_DATA; - -typedef struct _PH_VERIFY_CACHE_ENTRY -{ - PH_AVL_LINKS Links; - - PPH_STRING FileName; - VERIFY_RESULT VerifyResult; - PPH_STRING VerifySignerName; -} PH_VERIFY_CACHE_ENTRY, *PPH_VERIFY_CACHE_ENTRY; - -typedef struct _PH_SID_FULL_NAME_CACHE_ENTRY -{ - PSID Sid; - PPH_STRING FullName; -} PH_SID_FULL_NAME_CACHE_ENTRY, *PPH_SID_FULL_NAME_CACHE_ENTRY; - -VOID NTAPI PhpProcessItemDeleteProcedure( - _In_ PVOID Object, - _In_ ULONG Flags - ); - -INT NTAPI PhpVerifyCacheCompareFunction( - _In_ PPH_AVL_LINKS Links1, - _In_ PPH_AVL_LINKS Links2 - ); - -VOID PhpQueueProcessQueryStage1( - _In_ PPH_PROCESS_ITEM ProcessItem - ); - -VOID PhpQueueProcessQueryStage2( - _In_ PPH_PROCESS_ITEM ProcessItem - ); - -PPH_PROCESS_RECORD PhpCreateProcessRecord( - _In_ PPH_PROCESS_ITEM ProcessItem - ); - -VOID PhpAddProcessRecord( - _Inout_ PPH_PROCESS_RECORD ProcessRecord - ); - -VOID PhpRemoveProcessRecord( - _Inout_ PPH_PROCESS_RECORD ProcessRecord - ); - -PPH_OBJECT_TYPE PhProcessItemType; - -PPH_HASH_ENTRY PhProcessHashSet[256] = PH_HASH_SET_INIT; -ULONG PhProcessHashSetCount = 0; -PH_QUEUED_LOCK PhProcessHashSetLock = PH_QUEUED_LOCK_INIT; - -SLIST_HEADER PhProcessQueryDataListHead; - -PHAPPAPI PH_CALLBACK_DECLARE(PhProcessAddedEvent); -PHAPPAPI PH_CALLBACK_DECLARE(PhProcessModifiedEvent); -PHAPPAPI PH_CALLBACK_DECLARE(PhProcessRemovedEvent); -PHAPPAPI PH_CALLBACK_DECLARE(PhProcessesUpdatedEvent); - -PPH_LIST PhProcessRecordList; -PH_QUEUED_LOCK PhProcessRecordListLock = PH_QUEUED_LOCK_INIT; - -ULONG PhStatisticsSampleCount = 512; -BOOLEAN PhEnableProcessQueryStage2 = FALSE; -BOOLEAN PhEnablePurgeProcessRecords = TRUE; -BOOLEAN PhEnableCycleCpuUsage = TRUE; - -PVOID PhProcessInformation; // only can be used if running on same thread as process provider -SYSTEM_PERFORMANCE_INFORMATION PhPerfInformation; -PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION PhCpuInformation; -SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION PhCpuTotals; -ULONG PhTotalProcesses; -ULONG PhTotalThreads; -ULONG PhTotalHandles; - -SYSTEM_PROCESS_INFORMATION PhDpcsProcessInformation; -SYSTEM_PROCESS_INFORMATION PhInterruptsProcessInformation; - -ULONG64 PhCpuTotalCycleDelta; // real cycle time delta for this period -PLARGE_INTEGER PhCpuIdleCycleTime; // cycle time for Idle -PLARGE_INTEGER PhCpuSystemCycleTime; // cycle time for DPCs and Interrupts -PH_UINT64_DELTA PhCpuIdleCycleDelta; -PH_UINT64_DELTA PhCpuSystemCycleDelta; -//PPH_UINT64_DELTA PhCpusIdleCycleDelta; - -FLOAT PhCpuKernelUsage; -FLOAT PhCpuUserUsage; -PFLOAT PhCpusKernelUsage; -PFLOAT PhCpusUserUsage; - -PH_UINT64_DELTA PhCpuKernelDelta; -PH_UINT64_DELTA PhCpuUserDelta; -PH_UINT64_DELTA PhCpuIdleDelta; - -PPH_UINT64_DELTA PhCpusKernelDelta; -PPH_UINT64_DELTA PhCpusUserDelta; -PPH_UINT64_DELTA PhCpusIdleDelta; - -PH_UINT64_DELTA PhIoReadDelta; -PH_UINT64_DELTA PhIoWriteDelta; -PH_UINT64_DELTA PhIoOtherDelta; - -static BOOLEAN PhProcessStatisticsInitialized = FALSE; -static ULONG PhTimeSequenceNumber = 0; -static PH_CIRCULAR_BUFFER_ULONG PhTimeHistory; - -PH_CIRCULAR_BUFFER_FLOAT PhCpuKernelHistory; -PH_CIRCULAR_BUFFER_FLOAT PhCpuUserHistory; -//PH_CIRCULAR_BUFFER_FLOAT PhCpuOtherHistory; - -PPH_CIRCULAR_BUFFER_FLOAT PhCpusKernelHistory; -PPH_CIRCULAR_BUFFER_FLOAT PhCpusUserHistory; -//PPH_CIRCULAR_BUFFER_FLOAT PhCpusOtherHistory; - -PH_CIRCULAR_BUFFER_ULONG64 PhIoReadHistory; -PH_CIRCULAR_BUFFER_ULONG64 PhIoWriteHistory; -PH_CIRCULAR_BUFFER_ULONG64 PhIoOtherHistory; - -PH_CIRCULAR_BUFFER_ULONG PhCommitHistory; -PH_CIRCULAR_BUFFER_ULONG PhPhysicalHistory; - -PH_CIRCULAR_BUFFER_ULONG PhMaxCpuHistory; // ID of max. CPU process -PH_CIRCULAR_BUFFER_ULONG PhMaxIoHistory; // ID of max. I/O process -#ifdef PH_RECORD_MAX_USAGE -PH_CIRCULAR_BUFFER_FLOAT PhMaxCpuUsageHistory; -PH_CIRCULAR_BUFFER_ULONG64 PhMaxIoReadOtherHistory; -PH_CIRCULAR_BUFFER_ULONG64 PhMaxIoWriteHistory; -#endif - -static PTS_ALL_PROCESSES_INFO PhpTsProcesses = NULL; -static ULONG PhpTsNumberOfProcesses; - -#ifdef PH_ENABLE_VERIFY_CACHE -static PH_AVL_TREE PhpVerifyCacheSet = PH_AVL_TREE_INIT(PhpVerifyCacheCompareFunction); -static PH_QUEUED_LOCK PhpVerifyCacheLock = PH_QUEUED_LOCK_INIT; -#endif - -static PPH_HASHTABLE PhpSidFullNameCacheHashtable; - -BOOLEAN PhProcessProviderInitialization( - VOID - ) -{ - PFLOAT usageBuffer; - PPH_UINT64_DELTA deltaBuffer; - PPH_CIRCULAR_BUFFER_FLOAT historyBuffer; - - PhProcessItemType = PhCreateObjectType(L"ProcessItem", 0, PhpProcessItemDeleteProcedure); - - RtlInitializeSListHead(&PhProcessQueryDataListHead); - - PhProcessRecordList = PhCreateList(40); - - RtlInitUnicodeString( - &PhDpcsProcessInformation.ImageName, - L"DPCs" - ); - PhDpcsProcessInformation.UniqueProcessId = DPCS_PROCESS_ID; - PhDpcsProcessInformation.InheritedFromUniqueProcessId = SYSTEM_IDLE_PROCESS_ID; - - RtlInitUnicodeString( - &PhInterruptsProcessInformation.ImageName, - L"Interrupts" - ); - PhInterruptsProcessInformation.UniqueProcessId = INTERRUPTS_PROCESS_ID; - PhInterruptsProcessInformation.InheritedFromUniqueProcessId = SYSTEM_IDLE_PROCESS_ID; - - PhCpuInformation = PhAllocate( - sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION) * - (ULONG)PhSystemBasicInformation.NumberOfProcessors - ); - - PhCpuIdleCycleTime = PhAllocate( - sizeof(LARGE_INTEGER) * - (ULONG)PhSystemBasicInformation.NumberOfProcessors - ); - PhCpuSystemCycleTime = PhAllocate( - sizeof(LARGE_INTEGER) * - (ULONG)PhSystemBasicInformation.NumberOfProcessors - ); - - usageBuffer = PhAllocate( - sizeof(FLOAT) * - (ULONG)PhSystemBasicInformation.NumberOfProcessors * - 2 - ); - deltaBuffer = PhAllocate( - sizeof(PH_UINT64_DELTA) * - (ULONG)PhSystemBasicInformation.NumberOfProcessors * - 3 // 4 for PhCpusIdleCycleDelta - ); - historyBuffer = PhAllocate( - sizeof(PH_CIRCULAR_BUFFER_FLOAT) * - (ULONG)PhSystemBasicInformation.NumberOfProcessors * - 2 - ); - - PhCpusKernelUsage = usageBuffer; - PhCpusUserUsage = PhCpusKernelUsage + (ULONG)PhSystemBasicInformation.NumberOfProcessors; - - PhCpusKernelDelta = deltaBuffer; - PhCpusUserDelta = PhCpusKernelDelta + (ULONG)PhSystemBasicInformation.NumberOfProcessors; - PhCpusIdleDelta = PhCpusUserDelta + (ULONG)PhSystemBasicInformation.NumberOfProcessors; - //PhCpusIdleCycleDelta = PhCpusIdleDelta + (ULONG)PhSystemBasicInformation.NumberOfProcessors; - - PhCpusKernelHistory = historyBuffer; - PhCpusUserHistory = PhCpusKernelHistory + (ULONG)PhSystemBasicInformation.NumberOfProcessors; - - memset(deltaBuffer, 0, sizeof(PH_UINT64_DELTA) * (ULONG)PhSystemBasicInformation.NumberOfProcessors); - - return TRUE; -} - -PPH_STRING PhGetClientIdName( - _In_ PCLIENT_ID ClientId - ) -{ - PPH_STRING name; - PPH_PROCESS_ITEM processItem; - - processItem = PhReferenceProcessItem(ClientId->UniqueProcess); - - if (processItem) - { - name = PhGetClientIdNameEx(ClientId, processItem->ProcessName); - PhDereferenceObject(processItem); - } - else - { - name = PhGetClientIdNameEx(ClientId, NULL); - } - - return name; -} - -PPH_STRING PhGetClientIdNameEx( - _In_ PCLIENT_ID ClientId, - _In_opt_ PPH_STRING ProcessName - ) -{ - PPH_STRING name; - PH_FORMAT format[5]; - - if (ClientId->UniqueThread) - { - if (ProcessName) - { - PhInitFormatSR(&format[0], ProcessName->sr); - PhInitFormatS(&format[1], L" ("); - PhInitFormatIU(&format[2], (ULONG_PTR)ClientId->UniqueProcess); - PhInitFormatS(&format[3], L"): "); - PhInitFormatIU(&format[4], (ULONG_PTR)ClientId->UniqueThread); - - name = PhFormat(format, 5, ProcessName->Length + 16 * sizeof(WCHAR)); - } - else - { - PhInitFormatS(&format[0], L"Non-existent process ("); - PhInitFormatIU(&format[1], (ULONG_PTR)ClientId->UniqueProcess); - PhInitFormatS(&format[2], L"): "); - PhInitFormatIU(&format[3], (ULONG_PTR)ClientId->UniqueThread); - - name = PhFormat(format, 4, 0); - } - } - else - { - if (ProcessName) - { - PhInitFormatSR(&format[0], ProcessName->sr); - PhInitFormatS(&format[1], L" ("); - PhInitFormatIU(&format[2], (ULONG_PTR)ClientId->UniqueProcess); - PhInitFormatC(&format[3], ')'); - - name = PhFormat(format, 4, 0); - } - else - { - PhInitFormatS(&format[0], L"Non-existent process ("); - PhInitFormatIU(&format[1], (ULONG_PTR)ClientId->UniqueProcess); - PhInitFormatC(&format[2], ')'); - - name = PhFormat(format, 3, 0); - } - } - - return name; -} - -PWSTR PhGetProcessPriorityClassString( - _In_ ULONG PriorityClass - ) -{ - switch (PriorityClass) - { - case PROCESS_PRIORITY_CLASS_REALTIME: - return L"Real time"; - case PROCESS_PRIORITY_CLASS_HIGH: - return L"High"; - case PROCESS_PRIORITY_CLASS_ABOVE_NORMAL: - return L"Above normal"; - case PROCESS_PRIORITY_CLASS_NORMAL: - return L"Normal"; - case PROCESS_PRIORITY_CLASS_BELOW_NORMAL: - return L"Below normal"; - case PROCESS_PRIORITY_CLASS_IDLE: - return L"Idle"; - default: - return L"Unknown"; - } -} - -/** - * Creates a process item. - */ -PPH_PROCESS_ITEM PhCreateProcessItem( - _In_ HANDLE ProcessId - ) -{ - PPH_PROCESS_ITEM processItem; - - processItem = PhCreateObject( - PhEmGetObjectSize(EmProcessItemType, sizeof(PH_PROCESS_ITEM)), - PhProcessItemType - ); - memset(processItem, 0, sizeof(PH_PROCESS_ITEM)); - PhInitializeEvent(&processItem->Stage1Event); - PhInitializeQueuedLock(&processItem->ServiceListLock); - - processItem->ProcessId = ProcessId; - - if (!PH_IS_FAKE_PROCESS_ID(ProcessId)) - PhPrintUInt32(processItem->ProcessIdString, HandleToUlong(ProcessId)); - - // Create the statistics buffers. - PhInitializeCircularBuffer_FLOAT(&processItem->CpuKernelHistory, PhStatisticsSampleCount); - PhInitializeCircularBuffer_FLOAT(&processItem->CpuUserHistory, PhStatisticsSampleCount); - PhInitializeCircularBuffer_ULONG64(&processItem->IoReadHistory, PhStatisticsSampleCount); - PhInitializeCircularBuffer_ULONG64(&processItem->IoWriteHistory, PhStatisticsSampleCount); - PhInitializeCircularBuffer_ULONG64(&processItem->IoOtherHistory, PhStatisticsSampleCount); - PhInitializeCircularBuffer_SIZE_T(&processItem->PrivateBytesHistory, PhStatisticsSampleCount); - //PhInitializeCircularBuffer_SIZE_T(&processItem->WorkingSetHistory, PhStatisticsSampleCount); - - PhEmCallObjectOperation(EmProcessItemType, processItem, EmObjectCreate); - - return processItem; -} - -VOID PhpProcessItemDeleteProcedure( - _In_ PVOID Object, - _In_ ULONG Flags - ) -{ - PPH_PROCESS_ITEM processItem = (PPH_PROCESS_ITEM)Object; - ULONG i; - - PhEmCallObjectOperation(EmProcessItemType, processItem, EmObjectDelete); - - PhDeleteCircularBuffer_FLOAT(&processItem->CpuKernelHistory); - PhDeleteCircularBuffer_FLOAT(&processItem->CpuUserHistory); - PhDeleteCircularBuffer_ULONG64(&processItem->IoReadHistory); - PhDeleteCircularBuffer_ULONG64(&processItem->IoWriteHistory); - PhDeleteCircularBuffer_ULONG64(&processItem->IoOtherHistory); - PhDeleteCircularBuffer_SIZE_T(&processItem->PrivateBytesHistory); - //PhDeleteCircularBuffer_SIZE_T(&processItem->WorkingSetHistory); - - if (processItem->ServiceList) - { - PPH_SERVICE_ITEM serviceItem; - - i = 0; - - while (PhEnumPointerList(processItem->ServiceList, &i, &serviceItem)) - PhDereferenceObject(serviceItem); - - PhDereferenceObject(processItem->ServiceList); - } - - if (processItem->ProcessName) PhDereferenceObject(processItem->ProcessName); - if (processItem->FileName) PhDereferenceObject(processItem->FileName); - if (processItem->CommandLine) PhDereferenceObject(processItem->CommandLine); - if (processItem->SmallIcon) DestroyIcon(processItem->SmallIcon); - if (processItem->LargeIcon) DestroyIcon(processItem->LargeIcon); - PhDeleteImageVersionInfo(&processItem->VersionInfo); - if (processItem->UserName) PhDereferenceObject(processItem->UserName); - if (processItem->JobName) PhDereferenceObject(processItem->JobName); - if (processItem->VerifySignerName) PhDereferenceObject(processItem->VerifySignerName); - if (processItem->PackageFullName) PhDereferenceObject(processItem->PackageFullName); - - if (processItem->QueryHandle) NtClose(processItem->QueryHandle); - - if (processItem->Record) PhDereferenceProcessRecord(processItem->Record); -} - -FORCEINLINE BOOLEAN PhCompareProcessItem( - _In_ PPH_PROCESS_ITEM Value1, - _In_ PPH_PROCESS_ITEM Value2 - ) -{ - return Value1->ProcessId == Value2->ProcessId; -} - -FORCEINLINE ULONG PhHashProcessItem( - _In_ PPH_PROCESS_ITEM Value - ) -{ - return HandleToUlong(Value->ProcessId) / 4; -} - -/** - * Finds a process item in the hash set. - * - * \param ProcessId The process ID of the process item. - * - * \remarks The hash set must be locked before calling this function. The reference count of the - * found process item is not incremented. - */ -PPH_PROCESS_ITEM PhpLookupProcessItem( - _In_ HANDLE ProcessId - ) -{ - PH_PROCESS_ITEM lookupProcessItem; - PPH_HASH_ENTRY entry; - PPH_PROCESS_ITEM processItem; - - lookupProcessItem.ProcessId = ProcessId; - entry = PhFindEntryHashSet( - PhProcessHashSet, - PH_HASH_SET_SIZE(PhProcessHashSet), - PhHashProcessItem(&lookupProcessItem) - ); - - for (; entry; entry = entry->Next) - { - processItem = CONTAINING_RECORD(entry, PH_PROCESS_ITEM, HashEntry); - - if (PhCompareProcessItem(&lookupProcessItem, processItem)) - return processItem; - } - - return NULL; -} - -/** - * Finds and references a process item. - * - * \param ProcessId The process ID of the process item. - * - * \return The found process item. - */ -PPH_PROCESS_ITEM PhReferenceProcessItem( - _In_ HANDLE ProcessId - ) -{ - PPH_PROCESS_ITEM processItem; - - PhAcquireQueuedLockShared(&PhProcessHashSetLock); - - processItem = PhpLookupProcessItem(ProcessId); - - if (processItem) - PhReferenceObject(processItem); - - PhReleaseQueuedLockShared(&PhProcessHashSetLock); - - return processItem; -} - -/** - * Enumerates the process items. - * - * \param ProcessItems A variable which receives an array of pointers to process items. You must - * free the buffer with PhFree() when you no longer need it. - * \param NumberOfProcessItems A variable which receives the number of process items returned in - * \a ProcessItems. - */ -VOID PhEnumProcessItems( - _Out_opt_ PPH_PROCESS_ITEM **ProcessItems, - _Out_ PULONG NumberOfProcessItems - ) -{ - PPH_PROCESS_ITEM *processItems; - ULONG numberOfProcessItems; - ULONG count = 0; - ULONG i; - PPH_HASH_ENTRY entry; - PPH_PROCESS_ITEM processItem; - - if (!ProcessItems) - { - *NumberOfProcessItems = PhProcessHashSetCount; - return; - } - - PhAcquireQueuedLockShared(&PhProcessHashSetLock); - - numberOfProcessItems = PhProcessHashSetCount; - processItems = PhAllocate(sizeof(PPH_PROCESS_ITEM) * numberOfProcessItems); - - for (i = 0; i < PH_HASH_SET_SIZE(PhProcessHashSet); i++) - { - for (entry = PhProcessHashSet[i]; entry; entry = entry->Next) - { - processItem = CONTAINING_RECORD(entry, PH_PROCESS_ITEM, HashEntry); - PhReferenceObject(processItem); - processItems[count++] = processItem; - } - } - - PhReleaseQueuedLockShared(&PhProcessHashSetLock); - - *ProcessItems = processItems; - *NumberOfProcessItems = numberOfProcessItems; -} - -VOID PhpAddProcessItem( - _In_ _Assume_refs_(1) PPH_PROCESS_ITEM ProcessItem - ) -{ - PhAddEntryHashSet( - PhProcessHashSet, - PH_HASH_SET_SIZE(PhProcessHashSet), - &ProcessItem->HashEntry, - PhHashProcessItem(ProcessItem) - ); - PhProcessHashSetCount++; -} - -VOID PhpRemoveProcessItem( - _In_ PPH_PROCESS_ITEM ProcessItem - ) -{ - PhRemoveEntryHashSet(PhProcessHashSet, PH_HASH_SET_SIZE(PhProcessHashSet), &ProcessItem->HashEntry); - PhProcessHashSetCount--; - PhDereferenceObject(ProcessItem); -} - -INT NTAPI PhpVerifyCacheCompareFunction( - _In_ PPH_AVL_LINKS Links1, - _In_ PPH_AVL_LINKS Links2 - ) -{ - PPH_VERIFY_CACHE_ENTRY entry1 = CONTAINING_RECORD(Links1, PH_VERIFY_CACHE_ENTRY, Links); - PPH_VERIFY_CACHE_ENTRY entry2 = CONTAINING_RECORD(Links2, PH_VERIFY_CACHE_ENTRY, Links); - - return PhCompareString(entry1->FileName, entry2->FileName, TRUE); -} - -VERIFY_RESULT PhVerifyFileWithAdditionalCatalog( - _In_ PPH_VERIFY_FILE_INFO Information, - _In_opt_ PWSTR PackageFullName, - _Out_opt_ PPH_STRING *SignerName - ) -{ - static PH_STRINGREF codeIntegrityFileName = PH_STRINGREF_INIT(L"\\AppxMetadata\\CodeIntegrity.cat"); - - VERIFY_RESULT result; - PPH_STRING additionalCatalogFileName = NULL; - PCERT_CONTEXT *signatures; - ULONG numberOfSignatures; - - if (PackageFullName) - { - PACKAGE_ID *packageId; - PPH_STRING packagePath; - - if (packageId = PhPackageIdFromFullName(PackageFullName)) - { - if (packagePath = PhGetPackagePath(packageId)) - { - additionalCatalogFileName = PhConcatStringRef2(&packagePath->sr, &codeIntegrityFileName); - PhDereferenceObject(packagePath); - } - - PhFree(packageId); - } - } - - if (additionalCatalogFileName) - { - Information->NumberOfCatalogFileNames = 1; - Information->CatalogFileNames = &additionalCatalogFileName->Buffer; - } - - if (!NT_SUCCESS(PhVerifyFileEx(Information, &result, &signatures, &numberOfSignatures))) - { - result = VrNoSignature; - signatures = NULL; - numberOfSignatures = 0; - } - - if (additionalCatalogFileName) - PhDereferenceObject(additionalCatalogFileName); - - if (SignerName) - { - if (numberOfSignatures != 0) - *SignerName = PhGetSignerNameFromCertificate(signatures[0]); - else - *SignerName = NULL; - } - - PhFreeVerifySignatures(signatures, numberOfSignatures); - - return result; -} - -/** - * Verifies a file's digital signature, using a cached result if possible. - * - * \param FileName A file name. - * \param ProcessItem An associated process item. - * \param SignerName A variable which receives a pointer to a string containing the signer name. You - * must free the string using PhDereferenceObject() when you no longer need it. Note that the signer - * name may be NULL if it is not valid. - * \param CachedOnly Specify TRUE to fail the function when no cached result exists. - * - * \return A VERIFY_RESULT value. - */ -VERIFY_RESULT PhVerifyFileCached( - _In_ PPH_STRING FileName, - _In_opt_ PWSTR PackageFullName, - _Out_opt_ PPH_STRING *SignerName, - _In_ BOOLEAN CachedOnly - ) -{ -#ifdef PH_ENABLE_VERIFY_CACHE - PPH_AVL_LINKS links; - PPH_VERIFY_CACHE_ENTRY entry; - PH_VERIFY_CACHE_ENTRY lookupEntry; - - lookupEntry.FileName = FileName; - - PhAcquireQueuedLockShared(&PhpVerifyCacheLock); - links = PhFindElementAvlTree(&PhpVerifyCacheSet, &lookupEntry.Links); - PhReleaseQueuedLockShared(&PhpVerifyCacheLock); - - if (links) - { - entry = CONTAINING_RECORD(links, PH_VERIFY_CACHE_ENTRY, Links); - - if (SignerName) - PhSetReference(SignerName, entry->VerifySignerName); - - return entry->VerifyResult; - } - else - { - VERIFY_RESULT result; - PPH_STRING signerName; - - if (!CachedOnly) - { - PH_VERIFY_FILE_INFO info; - - memset(&info, 0, sizeof(PH_VERIFY_FILE_INFO)); - info.FileName = FileName->Buffer; - info.Flags = PH_VERIFY_PREVENT_NETWORK_ACCESS; - result = PhVerifyFileWithAdditionalCatalog(&info, PackageFullName, &signerName); - - if (result != VrTrusted) - PhClearReference(&signerName); - } - else - { - result = VrUnknown; - signerName = NULL; - } - - if (result != VrUnknown) - { - entry = PhAllocate(sizeof(PH_VERIFY_CACHE_ENTRY)); - entry->FileName = FileName; - entry->VerifyResult = result; - entry->VerifySignerName = signerName; - - PhAcquireQueuedLockExclusive(&PhpVerifyCacheLock); - links = PhAddElementAvlTree(&PhpVerifyCacheSet, &entry->Links); - PhReleaseQueuedLockExclusive(&PhpVerifyCacheLock); - - if (!links) - { - // We successfully added the cache entry. Add references. - - PhReferenceObject(entry->FileName); - - if (entry->VerifySignerName) - PhReferenceObject(entry->VerifySignerName); - } - else - { - // Entry already exists. - PhFree(entry); - } - } - - if (SignerName) - { - *SignerName = signerName; - } - else - { - if (signerName) - PhDereferenceObject(signerName); - } - - return result; - } -#else - VERIFY_RESULT result; - PPH_STRING signerName; - PH_VERIFY_FILE_INFO info; - - memset(&info, 0, sizeof(PH_VERIFY_FILE_INFO)); - info.FileName = FileName->Buffer; - info.Flags = PH_VERIFY_PREVENT_NETWORK_ACCESS; - result = PhVerifyFileWithAdditionalCatalog(&info, PackageFullName, &signerName); - - if (result != VrTrusted) - PhClearReference(&signerName); - - if (SignerName) - { - *SignerName = signerName; - } - else - { - if (signerName) - PhDereferenceObject(signerName); - } - - return result; -#endif -} - -BOOLEAN PhpSidFullNameCacheHashtableEqualFunction( - _In_ PVOID Entry1, - _In_ PVOID Entry2 - ) -{ - PPH_SID_FULL_NAME_CACHE_ENTRY entry1 = Entry1; - PPH_SID_FULL_NAME_CACHE_ENTRY entry2 = Entry2; - - return RtlEqualSid(entry1->Sid, entry2->Sid); -} - -ULONG PhpSidFullNameCacheHashtableHashFunction( - _In_ PVOID Entry - ) -{ - PPH_SID_FULL_NAME_CACHE_ENTRY entry = Entry; - - return PhHashBytes(entry->Sid, RtlLengthSid(entry->Sid)); -} - -PPH_STRING PhpGetSidFullNameCached( - _In_ PSID Sid - ) -{ - PPH_STRING fullName; - PH_SID_FULL_NAME_CACHE_ENTRY newEntry; - - if (PhpSidFullNameCacheHashtable) - { - PPH_SID_FULL_NAME_CACHE_ENTRY entry; - PH_SID_FULL_NAME_CACHE_ENTRY lookupEntry; - - lookupEntry.Sid = Sid; - entry = PhFindEntryHashtable(PhpSidFullNameCacheHashtable, &lookupEntry); - - if (entry) - return PhReferenceObject(entry->FullName); - } - - fullName = PhGetSidFullName(Sid, TRUE, NULL); - - if (!fullName) - return NULL; - - if (!PhpSidFullNameCacheHashtable) - { - PhpSidFullNameCacheHashtable = PhCreateHashtable( - sizeof(PH_SID_FULL_NAME_CACHE_ENTRY), - PhpSidFullNameCacheHashtableEqualFunction, - PhpSidFullNameCacheHashtableHashFunction, - 16 - ); - } - - newEntry.Sid = PhAllocateCopy(Sid, RtlLengthSid(Sid)); - newEntry.FullName = PhReferenceObject(fullName); - PhAddEntryHashtable(PhpSidFullNameCacheHashtable, &newEntry); - - return fullName; -} - -VOID PhpFlushSidFullNameCache( - VOID - ) -{ - PH_HASHTABLE_ENUM_CONTEXT enumContext; - PPH_SID_FULL_NAME_CACHE_ENTRY entry; - - if (!PhpSidFullNameCacheHashtable) - return; - - PhBeginEnumHashtable(PhpSidFullNameCacheHashtable, &enumContext); - - while (entry = PhNextEnumHashtable(&enumContext)) - { - PhFree(entry->Sid); - PhDereferenceObject(entry->FullName); - } - - PhClearReference(&PhpSidFullNameCacheHashtable); -} - -VOID PhpProcessQueryStage1( - _Inout_ PPH_PROCESS_QUERY_S1_DATA Data - ) -{ - NTSTATUS status; - PPH_PROCESS_ITEM processItem = Data->Header.ProcessItem; - HANDLE processId = processItem->ProcessId; - HANDLE processHandleLimited = NULL; - - PhOpenProcess(&processHandleLimited, ProcessQueryAccess, processId); - - if (processItem->FileName) - { - // Small icon, large icon. - if (ExtractIconEx( - processItem->FileName->Buffer, - 0, - &Data->LargeIcon, - &Data->SmallIcon, - 1 - ) == 0) - { - Data->LargeIcon = NULL; - Data->SmallIcon = NULL; - } - - // Version info. - PhInitializeImageVersionInfo(&Data->VersionInfo, processItem->FileName->Buffer); - } - - // Use the default EXE icon if we didn't get the file's icon. - { - if (!Data->SmallIcon || !Data->LargeIcon) - { - if (Data->SmallIcon) - { - DestroyIcon(Data->SmallIcon); - Data->SmallIcon = NULL; - } - else if (Data->LargeIcon) - { - DestroyIcon(Data->LargeIcon); - Data->LargeIcon = NULL; - } - - PhGetStockApplicationIcon(&Data->SmallIcon, &Data->LargeIcon); - Data->SmallIcon = CopyIcon(Data->SmallIcon); - Data->LargeIcon = CopyIcon(Data->LargeIcon); - } - } - - // Process flags - if (processHandleLimited) - { - PROCESS_EXTENDED_BASIC_INFORMATION basicInfo; - - if (NT_SUCCESS(PhGetProcessExtendedBasicInformation(processHandleLimited, &basicInfo))) - { - Data->IsProtectedProcess = basicInfo.IsProtectedProcess; - Data->IsSecureProcess = basicInfo.IsSecureProcess; - Data->IsSubsystemProcess = basicInfo.IsSubsystemProcess; - Data->IsWow64 = basicInfo.IsWow64Process; - Data->IsWow64Valid = TRUE; - } - } - - // Command line, .NET - { - HANDLE processHandle; - BOOLEAN queryAccess = FALSE; - - status = PhOpenProcess( - &processHandle, - ProcessQueryAccess | PROCESS_VM_READ, - processId - ); - - if (!NT_SUCCESS(status) && WindowsVersion >= WINDOWS_8_1) - { - queryAccess = TRUE; - status = PhOpenProcess( - &processHandle, - ProcessQueryAccess, - processId - ); - } - - if (NT_SUCCESS(status)) - { - BOOLEAN isDotNet = FALSE; - PPH_STRING commandLine; - ULONG i; - - if (NT_SUCCESS(status = PhGetProcessCommandLine(processHandle, &commandLine))) - { - // Some command lines (e.g. from taskeng.exe) have nulls in them. Since Windows - // can't display them, we'll replace them with spaces. - for (i = 0; i < (ULONG)commandLine->Length / 2; i++) - { - if (commandLine->Buffer[i] == 0) - commandLine->Buffer[i] = ' '; - } - } - - if (NT_SUCCESS(status)) - { - Data->CommandLine = commandLine; - } - - if (!queryAccess) - { - PhGetProcessIsDotNetEx( - processId, - processHandle, -#ifdef _WIN64 - PH_CLR_NO_WOW64_CHECK | (Data->IsWow64 ? PH_CLR_KNOWN_IS_WOW64 : 0), -#else - 0, -#endif - &isDotNet, - NULL - ); - Data->IsDotNet = isDotNet; - } - - NtClose(processHandle); - } - } - - // Token information - if (processHandleLimited) - { - if (WINDOWS_HAS_UAC) - { - HANDLE tokenHandle; - - status = PhOpenProcessToken(processHandleLimited, TOKEN_QUERY, &tokenHandle); - - if (NT_SUCCESS(status)) - { - // Elevation - if (NT_SUCCESS(PhGetTokenElevationType( - tokenHandle, - &Data->ElevationType - ))) - { - Data->IsElevated = Data->ElevationType == TokenElevationTypeFull; - } - - // Integrity - PhGetTokenIntegrityLevel( - tokenHandle, - &Data->IntegrityLevel, - &Data->IntegrityString - ); - - NtClose(tokenHandle); - } - } - } - - // Job - if (processHandleLimited) - { - if (KphIsConnected()) - { - HANDLE jobHandle = NULL; - - status = KphOpenProcessJob( - processHandleLimited, - JOB_OBJECT_QUERY, - &jobHandle - ); - - if (NT_SUCCESS(status) && status != STATUS_PROCESS_NOT_IN_JOB && jobHandle) - { - JOBOBJECT_BASIC_LIMIT_INFORMATION basicLimits; - - Data->IsInJob = TRUE; - - PhGetHandleInformation( - NtCurrentProcess(), - jobHandle, - -1, - NULL, - NULL, - NULL, - &Data->JobName - ); - - // Process Explorer only recognizes processes as being in jobs if they don't have - // the silent-breakaway-OK limit as their only limit. Emulate this behaviour. - if (NT_SUCCESS(PhGetJobBasicLimits(jobHandle, &basicLimits))) - { - Data->IsInSignificantJob = - basicLimits.LimitFlags != JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK; - } - - NtClose(jobHandle); - } - } - else - { - // KProcessHacker is not available. We can determine if the process is in a job, but we - // can't get a handle to the job. - - status = NtIsProcessInJob(processHandleLimited, NULL); - - if (NT_SUCCESS(status)) - Data->IsInJob = status == STATUS_PROCESS_IN_JOB; - } - } - - // Console host process - if (processHandleLimited && WINDOWS_HAS_CONSOLE_HOST) - { - PhGetProcessConsoleHostProcessId(processHandleLimited, &Data->ConsoleHostProcessId); - } - - // Package full name - if (processHandleLimited && WINDOWS_HAS_IMMERSIVE) - { - Data->PackageFullName = PhGetProcessPackageFullName(processHandleLimited); - } - - if (processHandleLimited) - NtClose(processHandleLimited); - - PhpQueueProcessQueryStage2(processItem); -} - -VOID PhpProcessQueryStage2( - _Inout_ PPH_PROCESS_QUERY_S2_DATA Data - ) -{ - NTSTATUS status; - PPH_PROCESS_ITEM processItem = Data->Header.ProcessItem; - - if (PhEnableProcessQueryStage2 && processItem->FileName) - { - PPH_STRING packageFullName = NULL; - - if (processItem->QueryHandle) - packageFullName = PhGetProcessPackageFullName(processItem->QueryHandle); - - Data->VerifyResult = PhVerifyFileCached( - processItem->FileName, - PhGetString(packageFullName), - &Data->VerifySignerName, - FALSE - ); - - if (packageFullName) - PhDereferenceObject(packageFullName); - - status = PhIsExecutablePacked( - processItem->FileName->Buffer, - &Data->IsPacked, - &Data->ImportModules, - &Data->ImportFunctions - ); - - // If we got an image-related error, the image is packed. - if ( - status == STATUS_INVALID_IMAGE_NOT_MZ || - status == STATUS_INVALID_IMAGE_FORMAT || - status == STATUS_ACCESS_VIOLATION - ) - { - Data->IsPacked = TRUE; - Data->ImportModules = -1; - Data->ImportFunctions = -1; - } - } -} - -NTSTATUS PhpProcessQueryStage1Worker( - _In_ PVOID Parameter - ) -{ - PPH_PROCESS_QUERY_S1_DATA data; - PPH_PROCESS_ITEM processItem = (PPH_PROCESS_ITEM)Parameter; - - data = PhAllocate(sizeof(PH_PROCESS_QUERY_S1_DATA)); - memset(data, 0, sizeof(PH_PROCESS_QUERY_S1_DATA)); - data->Header.Stage = 1; - data->Header.ProcessItem = processItem; - - PhpProcessQueryStage1(data); - - RtlInterlockedPushEntrySList(&PhProcessQueryDataListHead, &data->Header.ListEntry); - - return STATUS_SUCCESS; -} - -NTSTATUS PhpProcessQueryStage2Worker( - _In_ PVOID Parameter - ) -{ - PPH_PROCESS_QUERY_S2_DATA data; - PPH_PROCESS_ITEM processItem = (PPH_PROCESS_ITEM)Parameter; - - data = PhAllocate(sizeof(PH_PROCESS_QUERY_S2_DATA)); - memset(data, 0, sizeof(PH_PROCESS_QUERY_S2_DATA)); - data->Header.Stage = 2; - data->Header.ProcessItem = processItem; - - PhpProcessQueryStage2(data); - - RtlInterlockedPushEntrySList(&PhProcessQueryDataListHead, &data->Header.ListEntry); - - return STATUS_SUCCESS; -} - -VOID PhpQueueProcessQueryStage1( - _In_ PPH_PROCESS_ITEM ProcessItem - ) -{ - PH_WORK_QUEUE_ENVIRONMENT environment; - - // Ref: dereferenced when the provider update function removes the item from the queue. - PhReferenceObject(ProcessItem); - - PhInitializeWorkQueueEnvironment(&environment); - environment.BasePriority = THREAD_PRIORITY_BELOW_NORMAL; - - PhQueueItemWorkQueueEx(PhGetGlobalWorkQueue(), PhpProcessQueryStage1Worker, ProcessItem, - NULL, &environment); -} - -VOID PhpQueueProcessQueryStage2( - _In_ PPH_PROCESS_ITEM ProcessItem - ) -{ - PH_WORK_QUEUE_ENVIRONMENT environment; - - if (!PhEnableProcessQueryStage2) - return; - - PhReferenceObject(ProcessItem); - - PhInitializeWorkQueueEnvironment(&environment); - environment.BasePriority = THREAD_PRIORITY_BELOW_NORMAL; - environment.IoPriority = IoPriorityVeryLow; - environment.PagePriority = MEMORY_PRIORITY_VERY_LOW; - - PhQueueItemWorkQueueEx(PhGetGlobalWorkQueue(), PhpProcessQueryStage2Worker, ProcessItem, - NULL, &environment); -} - -VOID PhpFillProcessItemStage1( - _In_ PPH_PROCESS_QUERY_S1_DATA Data - ) -{ - PPH_PROCESS_ITEM processItem = Data->Header.ProcessItem; - - processItem->CommandLine = Data->CommandLine; - processItem->SmallIcon = Data->SmallIcon; - processItem->LargeIcon = Data->LargeIcon; - memcpy(&processItem->VersionInfo, &Data->VersionInfo, sizeof(PH_IMAGE_VERSION_INFO)); - processItem->ElevationType = Data->ElevationType; - processItem->IntegrityLevel = Data->IntegrityLevel; - processItem->IntegrityString = Data->IntegrityString; - processItem->JobName = Data->JobName; - processItem->ConsoleHostProcessId = Data->ConsoleHostProcessId; - processItem->PackageFullName = Data->PackageFullName; - processItem->IsDotNet = Data->IsDotNet; - processItem->IsElevated = Data->IsElevated; - processItem->IsInJob = Data->IsInJob; - processItem->IsInSignificantJob = Data->IsInSignificantJob; - processItem->IsWow64 = Data->IsWow64; - processItem->IsWow64Valid = Data->IsWow64Valid; - processItem->IsProtectedProcess = Data->IsProtectedProcess; - processItem->IsSecureProcess = Data->IsSecureProcess; - processItem->IsSubsystemProcess = Data->IsSubsystemProcess; - - PhSwapReference(&processItem->Record->CommandLine, processItem->CommandLine); -} - -VOID PhpFillProcessItemStage2( - _In_ PPH_PROCESS_QUERY_S2_DATA Data - ) -{ - PPH_PROCESS_ITEM processItem = Data->Header.ProcessItem; - - processItem->VerifyResult = Data->VerifyResult; - processItem->VerifySignerName = Data->VerifySignerName; - processItem->IsPacked = Data->IsPacked; - processItem->ImportFunctions = Data->ImportFunctions; - processItem->ImportModules = Data->ImportModules; -} - -VOID PhpFillProcessItem( - _Inout_ PPH_PROCESS_ITEM ProcessItem, - _In_ PSYSTEM_PROCESS_INFORMATION Process - ) -{ - NTSTATUS status; - HANDLE processHandle = NULL; - - ProcessItem->ParentProcessId = Process->InheritedFromUniqueProcessId; - ProcessItem->SessionId = Process->SessionId; - ProcessItem->CreateTime = Process->CreateTime; - - if (ProcessItem->ProcessId != SYSTEM_IDLE_PROCESS_ID) - ProcessItem->ProcessName = PhCreateStringFromUnicodeString(&Process->ImageName); - else - ProcessItem->ProcessName = PhCreateString(SYSTEM_IDLE_PROCESS_NAME); - - PhPrintUInt32(ProcessItem->ParentProcessIdString, HandleToUlong(ProcessItem->ParentProcessId)); - PhPrintUInt32(ProcessItem->SessionIdString, ProcessItem->SessionId); - - PhOpenProcess(&processHandle, ProcessQueryAccess, ProcessItem->ProcessId); - - // Process information - { - // If we're dealing with System (PID 4), we need to get the - // kernel file name. Otherwise, get the image file name. - - if (ProcessItem->ProcessId != SYSTEM_PROCESS_ID) - { - PPH_STRING fileName; - - if (WindowsVersion >= WINDOWS_VISTA) - { - if (processHandle) - { - PhGetProcessImageFileNameWin32(processHandle, &ProcessItem->FileName); - } - else - { - if (NT_SUCCESS(PhGetProcessImageFileNameByProcessId(ProcessItem->ProcessId, &fileName))) - { - ProcessItem->FileName = PhGetFileName(fileName); - PhDereferenceObject(fileName); - } - } - } - else - { - if (processHandle && NT_SUCCESS(PhGetProcessImageFileName(processHandle, &fileName))) - { - ProcessItem->FileName = PhGetFileName(fileName); - PhDereferenceObject(fileName); - } - } - } - else - { - PPH_STRING fileName; - - fileName = PhGetKernelFileName(); - - if (fileName) - { - ProcessItem->FileName = PhGetFileName(fileName); - PhDereferenceObject(fileName); - } - } - } - - // Token-related information - if ( - processHandle && - ProcessItem->ProcessId != SYSTEM_PROCESS_ID // Token of System process can't be opened sometimes - ) - { - HANDLE tokenHandle; - - status = PhOpenProcessToken(processHandle, TOKEN_QUERY, &tokenHandle); - - if (NT_SUCCESS(status)) - { - // User name - { - PTOKEN_USER user; - - status = PhGetTokenUser(tokenHandle, &user); - - if (NT_SUCCESS(status)) - { - ProcessItem->UserName = PhpGetSidFullNameCached(user->User.Sid); - PhFree(user); - } - } - - NtClose(tokenHandle); - } - } - else - { - if ( - ProcessItem->ProcessId == SYSTEM_IDLE_PROCESS_ID || - ProcessItem->ProcessId == SYSTEM_PROCESS_ID // System token can't be opened on XP - ) - { - PhSetReference(&ProcessItem->UserName, PhLocalSystemName); - } - } - - if (!ProcessItem->UserName && WindowsVersion <= WINDOWS_XP) - { - // In some cases we can get the user SID using WTS (only works on XP and below). - - if (!PhpTsProcesses) - { - WinStationGetAllProcesses( - NULL, - 0, - &PhpTsNumberOfProcesses, - &PhpTsProcesses - ); - } - - if (PhpTsProcesses) - { - ULONG i; - - for (i = 0; i < PhpTsNumberOfProcesses; i++) - { - if (UlongToHandle(PhpTsProcesses[i].pTsProcessInfo->UniqueProcessId) == ProcessItem->ProcessId) - { - ProcessItem->UserName = PhpGetSidFullNameCached(PhpTsProcesses[i].pSid); - break; - } - } - } - } - - NtClose(processHandle); -} - -FORCEINLINE VOID PhpUpdateDynamicInfoProcessItem( - _Inout_ PPH_PROCESS_ITEM ProcessItem, - _In_ PSYSTEM_PROCESS_INFORMATION Process - ) -{ - ProcessItem->BasePriority = Process->BasePriority; - - if (ProcessItem->QueryHandle) - { - PROCESS_PRIORITY_CLASS priorityClass; - - if (NT_SUCCESS(NtQueryInformationProcess( - ProcessItem->QueryHandle, - ProcessPriorityClass, - &priorityClass, - sizeof(PROCESS_PRIORITY_CLASS), - NULL - ))) - { - ProcessItem->PriorityClass = priorityClass.PriorityClass; - } - } - else - { - ProcessItem->PriorityClass = 0; - } - - ProcessItem->KernelTime = Process->KernelTime; - ProcessItem->UserTime = Process->UserTime; - ProcessItem->NumberOfHandles = Process->HandleCount; - ProcessItem->NumberOfThreads = Process->NumberOfThreads; - ProcessItem->WorkingSetPrivateSize = (SIZE_T)Process->WorkingSetPrivateSize.QuadPart; - ProcessItem->PeakNumberOfThreads = Process->NumberOfThreadsHighWatermark; - ProcessItem->HardFaultCount = Process->HardFaultCount; - - // Update VM and I/O counters. - ProcessItem->VmCounters = *(PVM_COUNTERS_EX)&Process->PeakVirtualSize; - ProcessItem->IoCounters = *(PIO_COUNTERS)&Process->ReadOperationCount; -} - -VOID PhpUpdatePerfInformation( - VOID - ) -{ - NtQuerySystemInformation( - SystemPerformanceInformation, - &PhPerfInformation, - sizeof(SYSTEM_PERFORMANCE_INFORMATION), - NULL - ); - - PhUpdateDelta(&PhIoReadDelta, PhPerfInformation.IoReadTransferCount.QuadPart); - PhUpdateDelta(&PhIoWriteDelta, PhPerfInformation.IoWriteTransferCount.QuadPart); - PhUpdateDelta(&PhIoOtherDelta, PhPerfInformation.IoOtherTransferCount.QuadPart); -} - -VOID PhpUpdateCpuInformation( - _In_ BOOLEAN SetCpuUsage, - _Out_ PULONG64 TotalTime - ) -{ - ULONG i; - ULONG64 totalTime; - - NtQuerySystemInformation( - SystemProcessorPerformanceInformation, - PhCpuInformation, - sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION) * (ULONG)PhSystemBasicInformation.NumberOfProcessors, - NULL - ); - - // Zero the CPU totals. - memset(&PhCpuTotals, 0, sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION)); - - for (i = 0; i < (ULONG)PhSystemBasicInformation.NumberOfProcessors; i++) - { - PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION cpuInfo = - &PhCpuInformation[i]; - - // KernelTime includes IdleTime. - cpuInfo->KernelTime.QuadPart -= cpuInfo->IdleTime.QuadPart; - - PhCpuTotals.DpcTime.QuadPart += cpuInfo->DpcTime.QuadPart; - PhCpuTotals.IdleTime.QuadPart += cpuInfo->IdleTime.QuadPart; - PhCpuTotals.InterruptCount += cpuInfo->InterruptCount; - PhCpuTotals.InterruptTime.QuadPart += cpuInfo->InterruptTime.QuadPart; - PhCpuTotals.KernelTime.QuadPart += cpuInfo->KernelTime.QuadPart; - PhCpuTotals.UserTime.QuadPart += cpuInfo->UserTime.QuadPart; - - PhUpdateDelta(&PhCpusKernelDelta[i], cpuInfo->KernelTime.QuadPart); - PhUpdateDelta(&PhCpusUserDelta[i], cpuInfo->UserTime.QuadPart); - PhUpdateDelta(&PhCpusIdleDelta[i], cpuInfo->IdleTime.QuadPart); - - if (SetCpuUsage) - { - totalTime = PhCpusKernelDelta[i].Delta + PhCpusUserDelta[i].Delta + PhCpusIdleDelta[i].Delta; - - if (totalTime != 0) - { - PhCpusKernelUsage[i] = (FLOAT)PhCpusKernelDelta[i].Delta / totalTime; - PhCpusUserUsage[i] = (FLOAT)PhCpusUserDelta[i].Delta / totalTime; - } - else - { - PhCpusKernelUsage[i] = 0; - PhCpusUserUsage[i] = 0; - } - } - } - - PhUpdateDelta(&PhCpuKernelDelta, PhCpuTotals.KernelTime.QuadPart); - PhUpdateDelta(&PhCpuUserDelta, PhCpuTotals.UserTime.QuadPart); - PhUpdateDelta(&PhCpuIdleDelta, PhCpuTotals.IdleTime.QuadPart); - - totalTime = PhCpuKernelDelta.Delta + PhCpuUserDelta.Delta + PhCpuIdleDelta.Delta; - - if (SetCpuUsage) - { - if (totalTime != 0) - { - PhCpuKernelUsage = (FLOAT)PhCpuKernelDelta.Delta / totalTime; - PhCpuUserUsage = (FLOAT)PhCpuUserDelta.Delta / totalTime; - } - else - { - PhCpuKernelUsage = 0; - PhCpuUserUsage = 0; - } - } - - *TotalTime = totalTime; -} - -VOID PhpUpdateCpuCycleInformation( - _Out_ PULONG64 IdleCycleTime - ) -{ - ULONG i; - ULONG64 total; - - // Idle - - // We need to query this separately because the idle cycle time in SYSTEM_PROCESS_INFORMATION - // doesn't give us data for individual processors. - - NtQuerySystemInformation( - SystemProcessorIdleCycleTimeInformation, - PhCpuIdleCycleTime, - sizeof(LARGE_INTEGER) * (ULONG)PhSystemBasicInformation.NumberOfProcessors, - NULL - ); - - total = 0; - - for (i = 0; i < (ULONG)PhSystemBasicInformation.NumberOfProcessors; i++) - { - //PhUpdateDelta(&PhCpusIdleCycleDelta[i], PhCpuIdleCycleTime[i].QuadPart); - total += PhCpuIdleCycleTime[i].QuadPart; - } - - PhUpdateDelta(&PhCpuIdleCycleDelta, total); - *IdleCycleTime = PhCpuIdleCycleDelta.Delta; - - // System - - NtQuerySystemInformation( - SystemProcessorCycleTimeInformation, - PhCpuSystemCycleTime, - sizeof(LARGE_INTEGER) * (ULONG)PhSystemBasicInformation.NumberOfProcessors, - NULL - ); - - total = 0; - - for (i = 0; i < (ULONG)PhSystemBasicInformation.NumberOfProcessors; i++) - { - total += PhCpuSystemCycleTime[i].QuadPart; - } - - PhUpdateDelta(&PhCpuSystemCycleDelta, total); -} - -VOID PhpUpdateCpuCycleUsageInformation( - _In_ ULONG64 TotalCycleTime, - _In_ ULONG64 IdleCycleTime - ) -{ - ULONG i; - FLOAT baseCpuUsage; - FLOAT totalTimeDelta; - ULONG64 totalTime; - - // Cycle time is not only lacking for kernel/user components, but also for individual - // processors. We can get the total idle cycle time for individual processors but - // without knowing the total cycle time for individual processors, this information - // is useless. - // - // We'll start by calculating the total CPU usage, then we'll calculate the kernel/user - // components. In the event that the corresponding CPU time deltas are zero, we'll split - // the CPU usage evenly across the kernel/user components. CPU usage for individual - // processors is left untouched, because it's too difficult to provide an estimate. - // - // Let I_1, I_2, ..., I_n be the idle cycle times and T_1, T_2, ..., T_n be the - // total cycle times. Let I'_1, I'_2, ..., I'_n be the idle CPU times and T'_1, T'_2, ..., - // T'_n be the total CPU times. - // We know all I'_n, T'_n and I_n, but we only know sigma(T). The "real" total CPU usage is - // sigma(I)/sigma(T), and the "real" individual CPU usage is I_n/T_n. The problem is that - // we don't know T_n; we only know sigma(T). Hence we need to find values i_1, i_2, ..., i_n - // and t_1, t_2, ..., t_n such that: - // sigma(i)/sigma(t) ~= sigma(I)/sigma(T), and - // i_n/t_n ~= I_n/T_n - // - // Solution 1: Set i_n = I_n and t_n = sigma(T)*T'_n/sigma(T'). Then: - // sigma(i)/sigma(t) = sigma(I)/(sigma(T)*sigma(T')/sigma(T')) = sigma(I)/sigma(T), and - // i_n/t_n = I_n/T'_n*sigma(T')/sigma(T) ~= I_n/T_n since I_n/T'_n ~= I_n/T_n and sigma(T')/sigma(T) ~= 1. - // However, it is not guaranteed that i_n/t_n <= 1, which may lead to CPU usages over 100% being displayed. - // - // Solution 2: Set i_n = I'_n and t_n = T'_n. Then: - // sigma(i)/sigma(t) = sigma(I')/sigma(T') ~= sigma(I)/sigma(T) since I'_n ~= I_n and T'_n ~= T_n. - // i_n/t_n = I'_n/T'_n ~= I_n/T_n as above. - // Not scaling at all is currently the best solution, since it's fast, simple and guarantees that i_n/t_n <= 1. - - baseCpuUsage = 1 - (FLOAT)IdleCycleTime / TotalCycleTime; - totalTimeDelta = (FLOAT)(PhCpuKernelDelta.Delta + PhCpuUserDelta.Delta); - - if (totalTimeDelta != 0) - { - PhCpuKernelUsage = baseCpuUsage * ((FLOAT)PhCpuKernelDelta.Delta / totalTimeDelta); - PhCpuUserUsage = baseCpuUsage * ((FLOAT)PhCpuUserDelta.Delta / totalTimeDelta); - } - else - { - PhCpuKernelUsage = baseCpuUsage / 2; - PhCpuUserUsage = baseCpuUsage / 2; - } - - for (i = 0; i < (ULONG)PhSystemBasicInformation.NumberOfProcessors; i++) - { - totalTime = PhCpusKernelDelta[i].Delta + PhCpusUserDelta[i].Delta + PhCpusIdleDelta[i].Delta; - - if (totalTime != 0) - { - PhCpusKernelUsage[i] = (FLOAT)PhCpusKernelDelta[i].Delta / totalTime; - PhCpusUserUsage[i] = (FLOAT)PhCpusUserDelta[i].Delta / totalTime; - } - else - { - PhCpusKernelUsage[i] = 0; - PhCpusUserUsage[i] = 0; - } - } -} - -VOID PhpInitializeProcessStatistics( - VOID - ) -{ - ULONG i; - - PhInitializeCircularBuffer_ULONG(&PhTimeHistory, PhStatisticsSampleCount); - PhInitializeCircularBuffer_FLOAT(&PhCpuKernelHistory, PhStatisticsSampleCount); - PhInitializeCircularBuffer_FLOAT(&PhCpuUserHistory, PhStatisticsSampleCount); - PhInitializeCircularBuffer_ULONG64(&PhIoReadHistory, PhStatisticsSampleCount); - PhInitializeCircularBuffer_ULONG64(&PhIoWriteHistory, PhStatisticsSampleCount); - PhInitializeCircularBuffer_ULONG64(&PhIoOtherHistory, PhStatisticsSampleCount); - PhInitializeCircularBuffer_ULONG(&PhCommitHistory, PhStatisticsSampleCount); - PhInitializeCircularBuffer_ULONG(&PhPhysicalHistory, PhStatisticsSampleCount); - PhInitializeCircularBuffer_ULONG(&PhMaxCpuHistory, PhStatisticsSampleCount); - PhInitializeCircularBuffer_ULONG(&PhMaxIoHistory, PhStatisticsSampleCount); -#ifdef PH_RECORD_MAX_USAGE - PhInitializeCircularBuffer_FLOAT(&PhMaxCpuUsageHistory, PhStatisticsSampleCount); - PhInitializeCircularBuffer_ULONG64(&PhMaxIoReadOtherHistory, PhStatisticsSampleCount); - PhInitializeCircularBuffer_ULONG64(&PhMaxIoWriteHistory, PhStatisticsSampleCount); -#endif - - for (i = 0; i < (ULONG)PhSystemBasicInformation.NumberOfProcessors; i++) - { - PhInitializeCircularBuffer_FLOAT(&PhCpusKernelHistory[i], PhStatisticsSampleCount); - PhInitializeCircularBuffer_FLOAT(&PhCpusUserHistory[i], PhStatisticsSampleCount); - } -} - -VOID PhpUpdateSystemHistory( - VOID - ) -{ - ULONG i; - LARGE_INTEGER systemTime; - ULONG secondsSince1980; - - // CPU - PhAddItemCircularBuffer_FLOAT(&PhCpuKernelHistory, PhCpuKernelUsage); - PhAddItemCircularBuffer_FLOAT(&PhCpuUserHistory, PhCpuUserUsage); - - // CPUs - for (i = 0; i < (ULONG)PhSystemBasicInformation.NumberOfProcessors; i++) - { - PhAddItemCircularBuffer_FLOAT(&PhCpusKernelHistory[i], PhCpusKernelUsage[i]); - PhAddItemCircularBuffer_FLOAT(&PhCpusUserHistory[i], PhCpusUserUsage[i]); - } - - // I/O - PhAddItemCircularBuffer_ULONG64(&PhIoReadHistory, PhIoReadDelta.Delta); - PhAddItemCircularBuffer_ULONG64(&PhIoWriteHistory, PhIoWriteDelta.Delta); - PhAddItemCircularBuffer_ULONG64(&PhIoOtherHistory, PhIoOtherDelta.Delta); - - // Memory - PhAddItemCircularBuffer_ULONG(&PhCommitHistory, PhPerfInformation.CommittedPages); - PhAddItemCircularBuffer_ULONG(&PhPhysicalHistory, - PhSystemBasicInformation.NumberOfPhysicalPages - PhPerfInformation.AvailablePages - ); - - // Time - PhQuerySystemTime(&systemTime); - RtlTimeToSecondsSince1980(&systemTime, &secondsSince1980); - PhAddItemCircularBuffer_ULONG(&PhTimeHistory, secondsSince1980); -} - -/** - * Retrieves a time value recorded by the statistics system. - * - * \param ProcessItem A process item to synchronize with, or NULL if no synchronization is - * necessary. - * \param Index The history index. - * \param Time A variable which receives the time at \a Index. - * - * \return TRUE if the function succeeded, otherwise FALSE if \a ProcessItem was specified and - * \a Index is too far into the past for that process item. - */ -BOOLEAN PhGetStatisticsTime( - _In_opt_ PPH_PROCESS_ITEM ProcessItem, - _In_ ULONG Index, - _Out_ PLARGE_INTEGER Time - ) -{ - ULONG secondsSince1980; - ULONG index; - LARGE_INTEGER time; - - if (ProcessItem) - { - // The sequence number is used to synchronize statistics when a process exits, since that - // process' history is not updated anymore. - index = PhTimeSequenceNumber - ProcessItem->SequenceNumber + Index; - - if (index >= PhTimeHistory.Count) - { - // The data point is too far into the past. - return FALSE; - } - } - else - { - // Assume the index is valid. - index = Index; - } - - secondsSince1980 = PhGetItemCircularBuffer_ULONG(&PhTimeHistory, index); - RtlSecondsSince1980ToTime(secondsSince1980, &time); - - *Time = time; - - return TRUE; -} - -PPH_STRING PhGetStatisticsTimeString( - _In_opt_ PPH_PROCESS_ITEM ProcessItem, - _In_ ULONG Index - ) -{ - LARGE_INTEGER time; - SYSTEMTIME systemTime; - - if (PhGetStatisticsTime(ProcessItem, Index, &time)) - { - PhLargeIntegerToLocalSystemTime(&systemTime, &time); - - return PhFormatDateTime(&systemTime); - } - else - { - return PhCreateString(L"Unknown time"); - } -} - -VOID PhFlushProcessQueryData( - _In_ BOOLEAN SendModifiedEvent - ) -{ - PSLIST_ENTRY entry; - PPH_PROCESS_QUERY_DATA data; - BOOLEAN processed; - - if (!RtlFirstEntrySList(&PhProcessQueryDataListHead)) - return; - - entry = RtlInterlockedFlushSList(&PhProcessQueryDataListHead); - - while (entry) - { - data = CONTAINING_RECORD(entry, PH_PROCESS_QUERY_DATA, ListEntry); - entry = entry->Next; - processed = FALSE; - - if (data->Stage == 1) - { - PhpFillProcessItemStage1((PPH_PROCESS_QUERY_S1_DATA)data); - PhSetEvent(&data->ProcessItem->Stage1Event); - processed = TRUE; - } - else if (data->Stage == 2) - { - PhpFillProcessItemStage2((PPH_PROCESS_QUERY_S2_DATA)data); - processed = TRUE; - } - - if (processed) - { - // Invoke the modified event only if the main provider has sent the added event already. - if (SendModifiedEvent && data->ProcessItem->AddedEventSent) - { - // Since this may be executing on a thread other than the main provider thread, we - // need to check whether the process has been removed already. If we don't do this - // then users may get a modified event after a removed event for the same process, - // which will lead to very bad things happening. - PhAcquireQueuedLockExclusive(&data->ProcessItem->RemoveLock); - if (!(data->ProcessItem->State & PH_PROCESS_ITEM_REMOVED)) - PhInvokeCallback(&PhProcessModifiedEvent, data->ProcessItem); - PhReleaseQueuedLockExclusive(&data->ProcessItem->RemoveLock); - } - else - { - data->ProcessItem->JustProcessed = 1; - } - } - - PhDereferenceObject(data->ProcessItem); - PhFree(data); - } -} - -VOID PhpGetProcessThreadInformation( - _In_ PSYSTEM_PROCESS_INFORMATION Process, - _Out_opt_ PBOOLEAN IsSuspended, - _Out_opt_ PBOOLEAN IsPartiallySuspended, - _Out_opt_ PULONG ContextSwitches - ) -{ - ULONG i; - BOOLEAN isSuspended; - BOOLEAN isPartiallySuspended; - ULONG contextSwitches; - - isSuspended = PH_IS_REAL_PROCESS_ID(Process->UniqueProcessId); - isPartiallySuspended = FALSE; - contextSwitches = 0; - - for (i = 0; i < Process->NumberOfThreads; i++) - { - if (Process->Threads[i].ThreadState != Waiting || - Process->Threads[i].WaitReason != Suspended) - { - isSuspended = FALSE; - } - else - { - isPartiallySuspended = TRUE; - } - - contextSwitches += Process->Threads[i].ContextSwitches; - } - - if (IsSuspended) - *IsSuspended = isSuspended; - if (IsPartiallySuspended) - *IsPartiallySuspended = isPartiallySuspended; - if (ContextSwitches) - *ContextSwitches = contextSwitches; -} - -VOID PhProcessProviderUpdate( - _In_ PVOID Object - ) -{ - static ULONG runCount = 0; - static PSYSTEM_PROCESS_INFORMATION pidBuckets[PROCESS_ID_BUCKETS]; - - // Note about locking: - // - // Since this is the only function that is allowed to modify the process hashtable, locking is - // not needed for shared accesses. However, exclusive accesses need locking. - - PVOID processes; - PSYSTEM_PROCESS_INFORMATION process; - ULONG bucketIndex; - - BOOLEAN isCycleCpuUsageEnabled = FALSE; - - ULONG64 sysTotalTime; // total time for this update period - ULONG64 sysTotalCycleTime = 0; // total cycle time for this update period - ULONG64 sysIdleCycleTime = 0; // total idle cycle time for this update period - FLOAT maxCpuValue = 0; - PPH_PROCESS_ITEM maxCpuProcessItem = NULL; - ULONG64 maxIoValue = 0; - PPH_PROCESS_ITEM maxIoProcessItem = NULL; - - // Pre-update tasks - - if (runCount % 5 == 0) - { - PhUpdateDosDevicePrefixes(); - } - - if (runCount % 512 == 0) // yes, a very long time - { - if (PhEnablePurgeProcessRecords) - PhPurgeProcessRecords(); - } - - isCycleCpuUsageEnabled = WindowsVersion >= WINDOWS_7 && PhEnableCycleCpuUsage; - - if (!PhProcessStatisticsInitialized) - { - PhpInitializeProcessStatistics(); - PhProcessStatisticsInitialized = TRUE; - } - - PhpUpdatePerfInformation(); - - if (isCycleCpuUsageEnabled) - { - PhpUpdateCpuInformation(FALSE, &sysTotalTime); - PhpUpdateCpuCycleInformation(&sysIdleCycleTime); - } - else - { - PhpUpdateCpuInformation(TRUE, &sysTotalTime); - } - - if (runCount != 0) - { - PhTimeSequenceNumber++; - } - - // Get the process list. - - PhTotalProcesses = 0; - PhTotalThreads = 0; - PhTotalHandles = 0; - - if (!NT_SUCCESS(PhEnumProcesses(&processes))) - return; - - // Notes on cycle-based CPU usage: - // - // Cycle-based CPU usage is a bit tricky to calculate because we cannot get the total number of - // cycles consumed by all processes since system startup - we can only get total number of - // cycles per process. This means there are two ways to calculate the system-wide cycle time - // delta: - // - // 1. Each update, sum the cycle times of all processes, and calculate the system-wide delta - // from this. Process Explorer seems to do this. - // 2. Each update, calculate the cycle time delta for each individual process, and sum these - // deltas to create the system-wide delta. We use this here. - // - // The first method is simpler but has a problem when a process exits and its cycle time is no - // longer counted in the system-wide total. This may cause the delta to be negative and all - // other calculations to become invalid. Process Explorer simply ignored this fact and treated - // the system-wide delta as unsigned (and therefore huge when negative), leading to all CPU - // usages being displayed as "< 0.01". - // - // The second method is used here, but the adjustments must be done before the main new/modified - // pass. We need take into account new, existing and terminated processes. - - // Create the PID hash set. This contains the process information structures returned by - // PhEnumProcesses, distinct from the process item hash set. Note that we use the - // UniqueProcessKey field as the next node pointer to avoid having to allocate extra memory. - - memset(pidBuckets, 0, sizeof(pidBuckets)); - - process = PH_FIRST_PROCESS(processes); - - do - { - PhTotalProcesses++; - PhTotalThreads += process->NumberOfThreads; - PhTotalHandles += process->HandleCount; - - if (process->UniqueProcessId == SYSTEM_IDLE_PROCESS_ID) - { - process->CycleTime = PhCpuIdleCycleDelta.Value; - process->KernelTime = PhCpuTotals.IdleTime; - } - - bucketIndex = PROCESS_ID_TO_BUCKET_INDEX(process->UniqueProcessId); - process->UniqueProcessKey = (ULONG_PTR)pidBuckets[bucketIndex]; - pidBuckets[bucketIndex] = process; - - if (isCycleCpuUsageEnabled) - { - PPH_PROCESS_ITEM processItem; - - if ((processItem = PhpLookupProcessItem(process->UniqueProcessId)) && processItem->CreateTime.QuadPart == process->CreateTime.QuadPart) - sysTotalCycleTime += process->CycleTime - processItem->CycleTimeDelta.Value; // existing process - else - sysTotalCycleTime += process->CycleTime; // new process - } - } while (process = PH_NEXT_PROCESS(process)); - - // Add the fake processes to the PID list. - // - // On Windows 7 the two fake processes are merged into "Interrupts" since we can only get cycle - // time information both DPCs and Interrupts combined. - - if (isCycleCpuUsageEnabled) - { - PhInterruptsProcessInformation.KernelTime.QuadPart = PhCpuTotals.DpcTime.QuadPart + PhCpuTotals.InterruptTime.QuadPart; - PhInterruptsProcessInformation.CycleTime = PhCpuSystemCycleDelta.Value; - sysTotalCycleTime += PhCpuSystemCycleDelta.Delta; - } - else - { - PhDpcsProcessInformation.KernelTime = PhCpuTotals.DpcTime; - PhInterruptsProcessInformation.KernelTime = PhCpuTotals.InterruptTime; - } - - // Look for dead processes. - { - PPH_LIST processesToRemove = NULL; - ULONG i; - PPH_HASH_ENTRY entry; - PPH_PROCESS_ITEM processItem; - PSYSTEM_PROCESS_INFORMATION processEntry; - - for (i = 0; i < PH_HASH_SET_SIZE(PhProcessHashSet); i++) - { - for (entry = PhProcessHashSet[i]; entry; entry = entry->Next) - { - processItem = CONTAINING_RECORD(entry, PH_PROCESS_ITEM, HashEntry); - - // Check if the process still exists. Note that we take into account PID re-use by - // checking CreateTime as well. - - if (processItem->ProcessId == DPCS_PROCESS_ID) - { - processEntry = &PhDpcsProcessInformation; - } - else if (processItem->ProcessId == INTERRUPTS_PROCESS_ID) - { - processEntry = &PhInterruptsProcessInformation; - } - else - { - processEntry = pidBuckets[PROCESS_ID_TO_BUCKET_INDEX(processItem->ProcessId)]; - - while (processEntry && processEntry->UniqueProcessId != processItem->ProcessId) - processEntry = (PSYSTEM_PROCESS_INFORMATION)processEntry->UniqueProcessKey; - } - - if (!processEntry || processEntry->CreateTime.QuadPart != processItem->CreateTime.QuadPart) - { - LARGE_INTEGER exitTime; - - processItem->State |= PH_PROCESS_ITEM_REMOVED; - exitTime.QuadPart = 0; - - if (processItem->QueryHandle) - { - KERNEL_USER_TIMES times; - ULONG64 finalCycleTime; - - if (NT_SUCCESS(PhGetProcessTimes(processItem->QueryHandle, ×))) - { - exitTime = times.ExitTime; - } - - if (isCycleCpuUsageEnabled) - { - if (NT_SUCCESS(PhGetProcessCycleTime(processItem->QueryHandle, &finalCycleTime))) - { - // Adjust deltas for the terminated process because this doesn't get - // picked up anywhere else. - // - // Note that if we don't have sufficient access to the process, the - // worst that will happen is that the CPU usages of other processes - // will get inflated. (See above; if we were using the first - // technique, we could get negative deltas, which is much worse.) - sysTotalCycleTime += finalCycleTime - processItem->CycleTimeDelta.Value; - } - } - } - - // If we don't have a valid exit time, use the current time. - if (exitTime.QuadPart == 0) - PhQuerySystemTime(&exitTime); - - processItem->Record->Flags |= PH_PROCESS_RECORD_DEAD; - processItem->Record->ExitTime = exitTime; - - // Raise the process removed event. - // See PhFlushProcessQueryData for why we need to lock here. - PhAcquireQueuedLockExclusive(&processItem->RemoveLock); - PhInvokeCallback(&PhProcessRemovedEvent, processItem); - PhReleaseQueuedLockExclusive(&processItem->RemoveLock); - - if (!processesToRemove) - processesToRemove = PhCreateList(2); - - PhAddItemList(processesToRemove, processItem); - } - } - } - - // Lock only if we have something to do. - if (processesToRemove) - { - PhAcquireQueuedLockExclusive(&PhProcessHashSetLock); - - for (i = 0; i < processesToRemove->Count; i++) - { - PhpRemoveProcessItem((PPH_PROCESS_ITEM)processesToRemove->Items[i]); - } - - PhReleaseQueuedLockExclusive(&PhProcessHashSetLock); - PhDereferenceObject(processesToRemove); - } - } - - // Go through the queued process query data. - PhFlushProcessQueryData(FALSE); - - if (sysTotalTime == 0) - sysTotalTime = -1; // max. value - if (sysTotalCycleTime == 0) - sysTotalCycleTime = -1; - - PhCpuTotalCycleDelta = sysTotalCycleTime; - - // Look for new processes and update existing ones. - process = PH_FIRST_PROCESS(processes); - - while (process) - { - PPH_PROCESS_ITEM processItem; - - processItem = PhpLookupProcessItem(process->UniqueProcessId); - - if (!processItem) - { - PPH_PROCESS_RECORD processRecord; - BOOLEAN isSuspended; - BOOLEAN isPartiallySuspended; - ULONG contextSwitches; - - // Create the process item and fill in basic information. - processItem = PhCreateProcessItem(process->UniqueProcessId); - PhpFillProcessItem(processItem, process); - processItem->SequenceNumber = PhTimeSequenceNumber; - - processRecord = PhpCreateProcessRecord(processItem); - PhpAddProcessRecord(processRecord); - processItem->Record = processRecord; - - // Open a handle to the process for later usage. - // - // Don't try to do this if the process has no threads. On Windows 8.1, processes without - // threads are probably reflected processes which will not terminate if we have a handle - // open. - if (process->NumberOfThreads != 0) - { - PhOpenProcess(&processItem->QueryHandle, PROCESS_QUERY_INFORMATION, processItem->ProcessId); - - if (WINDOWS_HAS_LIMITED_ACCESS && !processItem->QueryHandle) - PhOpenProcess(&processItem->QueryHandle, PROCESS_QUERY_LIMITED_INFORMATION, processItem->ProcessId); - } - - PhpGetProcessThreadInformation(process, &isSuspended, &isPartiallySuspended, &contextSwitches); - PhpUpdateDynamicInfoProcessItem(processItem, process); - - // Initialize the deltas. - PhUpdateDelta(&processItem->CpuKernelDelta, process->KernelTime.QuadPart); - PhUpdateDelta(&processItem->CpuUserDelta, process->UserTime.QuadPart); - PhUpdateDelta(&processItem->IoReadDelta, process->ReadTransferCount.QuadPart); - PhUpdateDelta(&processItem->IoWriteDelta, process->WriteTransferCount.QuadPart); - PhUpdateDelta(&processItem->IoOtherDelta, process->OtherTransferCount.QuadPart); - PhUpdateDelta(&processItem->IoReadCountDelta, process->ReadOperationCount.QuadPart); - PhUpdateDelta(&processItem->IoWriteCountDelta, process->WriteOperationCount.QuadPart); - PhUpdateDelta(&processItem->IoOtherCountDelta, process->OtherOperationCount.QuadPart); - PhUpdateDelta(&processItem->ContextSwitchesDelta, contextSwitches); - PhUpdateDelta(&processItem->PageFaultsDelta, process->PageFaultCount); - PhUpdateDelta(&processItem->CycleTimeDelta, process->CycleTime); - PhUpdateDelta(&processItem->PrivateBytesDelta, process->PagefileUsage); - - processItem->IsSuspended = isSuspended; - processItem->IsPartiallySuspended = isPartiallySuspended; - - // If this is the first run of the provider, queue the - // process query tasks. Otherwise, perform stage 1 - // processing now and queue stage 2 processing. - if (runCount > 0) - { - PH_PROCESS_QUERY_S1_DATA data; - - memset(&data, 0, sizeof(PH_PROCESS_QUERY_S1_DATA)); - data.Header.Stage = 1; - data.Header.ProcessItem = processItem; - PhpProcessQueryStage1(&data); - PhpFillProcessItemStage1(&data); - PhSetEvent(&processItem->Stage1Event); - } - else - { - PhpQueueProcessQueryStage1(processItem); - } - - // Add pending service items to the process item. - PhUpdateProcessItemServices(processItem); - - // Add the process item to the hashtable. - PhAcquireQueuedLockExclusive(&PhProcessHashSetLock); - PhpAddProcessItem(processItem); - PhReleaseQueuedLockExclusive(&PhProcessHashSetLock); - - // Raise the process added event. - PhInvokeCallback(&PhProcessAddedEvent, processItem); - processItem->AddedEventSent = TRUE; - - // (Ref: for the process item being in the hashtable.) - // Instead of referencing then dereferencing we simply don't do anything. - // Dereferenced in PhpRemoveProcessItem. - } - else - { - BOOLEAN modified = FALSE; - BOOLEAN isSuspended; - BOOLEAN isPartiallySuspended; - ULONG contextSwitches; - FLOAT newCpuUsage; - FLOAT kernelCpuUsage; - FLOAT userCpuUsage; - - PhpGetProcessThreadInformation(process, &isSuspended, &isPartiallySuspended, &contextSwitches); - PhpUpdateDynamicInfoProcessItem(processItem, process); - - // Update the deltas. - PhUpdateDelta(&processItem->CpuKernelDelta, process->KernelTime.QuadPart); - PhUpdateDelta(&processItem->CpuUserDelta, process->UserTime.QuadPart); - PhUpdateDelta(&processItem->IoReadDelta, process->ReadTransferCount.QuadPart); - PhUpdateDelta(&processItem->IoWriteDelta, process->WriteTransferCount.QuadPart); - PhUpdateDelta(&processItem->IoOtherDelta, process->OtherTransferCount.QuadPart); - PhUpdateDelta(&processItem->IoReadCountDelta, process->ReadOperationCount.QuadPart); - PhUpdateDelta(&processItem->IoWriteCountDelta, process->WriteOperationCount.QuadPart); - PhUpdateDelta(&processItem->IoOtherCountDelta, process->OtherOperationCount.QuadPart); - PhUpdateDelta(&processItem->ContextSwitchesDelta, contextSwitches); - PhUpdateDelta(&processItem->PageFaultsDelta, process->PageFaultCount); - PhUpdateDelta(&processItem->CycleTimeDelta, process->CycleTime); - PhUpdateDelta(&processItem->PrivateBytesDelta, process->PagefileUsage); - - processItem->SequenceNumber++; - PhAddItemCircularBuffer_ULONG64(&processItem->IoReadHistory, processItem->IoReadDelta.Delta); - PhAddItemCircularBuffer_ULONG64(&processItem->IoWriteHistory, processItem->IoWriteDelta.Delta); - PhAddItemCircularBuffer_ULONG64(&processItem->IoOtherHistory, processItem->IoOtherDelta.Delta); - - PhAddItemCircularBuffer_SIZE_T(&processItem->PrivateBytesHistory, processItem->VmCounters.PagefileUsage); - //PhAddItemCircularBuffer_SIZE_T(&processItem->WorkingSetHistory, processItem->VmCounters.WorkingSetSize); - - if (InterlockedExchange(&processItem->JustProcessed, 0) != 0) - modified = TRUE; - - if (isCycleCpuUsageEnabled) - { - FLOAT totalDelta; - - newCpuUsage = (FLOAT)processItem->CycleTimeDelta.Delta / sysTotalCycleTime; - - // Calculate the kernel/user CPU usage based on the kernel/user time. If the kernel - // and user deltas are both zero, we'll just have to use an estimate. Currently, we - // split the CPU usage evenly across the kernel and user components, except when the - // total user time is zero, in which case we assign it all to the kernel component. - - totalDelta = (FLOAT)(processItem->CpuKernelDelta.Delta + processItem->CpuUserDelta.Delta); - - if (totalDelta != 0) - { - kernelCpuUsage = newCpuUsage * ((FLOAT)processItem->CpuKernelDelta.Delta / totalDelta); - userCpuUsage = newCpuUsage * ((FLOAT)processItem->CpuUserDelta.Delta / totalDelta); - } - else - { - if (processItem->UserTime.QuadPart != 0) - { - kernelCpuUsage = newCpuUsage / 2; - userCpuUsage = newCpuUsage / 2; - } - else - { - kernelCpuUsage = newCpuUsage; - userCpuUsage = 0; - } - } - } - else - { - kernelCpuUsage = (FLOAT)processItem->CpuKernelDelta.Delta / sysTotalTime; - userCpuUsage = (FLOAT)processItem->CpuUserDelta.Delta / sysTotalTime; - newCpuUsage = kernelCpuUsage + userCpuUsage; - } - - processItem->CpuUsage = newCpuUsage; - processItem->CpuKernelUsage = kernelCpuUsage; - processItem->CpuUserUsage = userCpuUsage; - - PhAddItemCircularBuffer_FLOAT(&processItem->CpuKernelHistory, kernelCpuUsage); - PhAddItemCircularBuffer_FLOAT(&processItem->CpuUserHistory, userCpuUsage); - - // Max. values - - if (processItem->ProcessId != NULL) - { - if (maxCpuValue < newCpuUsage) - { - maxCpuValue = newCpuUsage; - maxCpuProcessItem = processItem; - } - - // I/O for Other is not included because it is too generic. - if (maxIoValue < processItem->IoReadDelta.Delta + processItem->IoWriteDelta.Delta) - { - maxIoValue = processItem->IoReadDelta.Delta + processItem->IoWriteDelta.Delta; - maxIoProcessItem = processItem; - } - } - - // Debugged - if (processItem->QueryHandle) - { - BOOLEAN isBeingDebugged; - - if (NT_SUCCESS(PhGetProcessIsBeingDebugged( - processItem->QueryHandle, - &isBeingDebugged - )) && processItem->IsBeingDebugged != isBeingDebugged) - { - processItem->IsBeingDebugged = isBeingDebugged; - modified = TRUE; - } - } - - // Suspended - if (processItem->IsSuspended != isSuspended) - { - processItem->IsSuspended = isSuspended; - modified = TRUE; - } - - processItem->IsPartiallySuspended = isPartiallySuspended; - - // .NET - if (processItem->UpdateIsDotNet) - { - BOOLEAN isDotNet; - - if (NT_SUCCESS(PhGetProcessIsDotNet(processItem->ProcessId, &isDotNet))) - { - processItem->IsDotNet = isDotNet; - modified = TRUE; - } - - processItem->UpdateIsDotNet = FALSE; - } - - // Immersive - if (processItem->QueryHandle && IsImmersiveProcess_I) - { - BOOLEAN isImmersive; - - isImmersive = !!IsImmersiveProcess_I(processItem->QueryHandle); - - if (processItem->IsImmersive != isImmersive) - { - processItem->IsImmersive = isImmersive; - modified = TRUE; - } - } - - if (modified) - { - PhInvokeCallback(&PhProcessModifiedEvent, processItem); - } - - // No reference added by PhpLookupProcessItem. - } - - // Trick ourselves into thinking that the fake processes - // are on the list. - if (process == &PhInterruptsProcessInformation) - { - process = NULL; - } - else if (process == &PhDpcsProcessInformation) - { - process = &PhInterruptsProcessInformation; - } - else - { - process = PH_NEXT_PROCESS(process); - - if (process == NULL) - { - if (isCycleCpuUsageEnabled) - process = &PhInterruptsProcessInformation; - else - process = &PhDpcsProcessInformation; - } - } - } - - if (PhProcessInformation) - PhFree(PhProcessInformation); - - PhProcessInformation = processes; - - if (PhpTsProcesses) - { - WinStationFreeGAPMemory(0, PhpTsProcesses, PhpTsNumberOfProcesses); - PhpTsProcesses = NULL; - } - - PhpFlushSidFullNameCache(); - - // History cannot be updated on the first run because the deltas are invalid. For example, the - // I/O "deltas" will be huge because they are currently the raw accumulated values. - if (runCount != 0) - { - if (isCycleCpuUsageEnabled) - PhpUpdateCpuCycleUsageInformation(sysTotalCycleTime, sysIdleCycleTime); - - PhpUpdateSystemHistory(); - - // Note that we need to add a reference to the records of these processes, to make it - // possible for others to get the name of a max. CPU or I/O process. - - if (maxCpuProcessItem) - { - PhAddItemCircularBuffer_ULONG(&PhMaxCpuHistory, HandleToUlong(maxCpuProcessItem->ProcessId)); -#ifdef PH_RECORD_MAX_USAGE - PhAddItemCircularBuffer_FLOAT(&PhMaxCpuUsageHistory, maxCpuProcessItem->CpuUsage); -#endif - - if (!(maxCpuProcessItem->Record->Flags & PH_PROCESS_RECORD_STAT_REF)) - { - PhReferenceProcessRecord(maxCpuProcessItem->Record); - maxCpuProcessItem->Record->Flags |= PH_PROCESS_RECORD_STAT_REF; - } - } - else - { - PhAddItemCircularBuffer_ULONG(&PhMaxCpuHistory, PtrToUlong(NULL)); -#ifdef PH_RECORD_MAX_USAGE - PhAddItemCircularBuffer_FLOAT(&PhMaxCpuUsageHistory, 0); -#endif - } - - if (maxIoProcessItem) - { - PhAddItemCircularBuffer_ULONG(&PhMaxIoHistory, HandleToUlong(maxIoProcessItem->ProcessId)); -#ifdef PH_RECORD_MAX_USAGE - PhAddItemCircularBuffer_ULONG64(&PhMaxIoReadOtherHistory, - maxIoProcessItem->IoReadDelta.Delta + maxIoProcessItem->IoOtherDelta.Delta); - PhAddItemCircularBuffer_ULONG64(&PhMaxIoWriteHistory, maxIoProcessItem->IoWriteDelta.Delta); -#endif - - if (!(maxIoProcessItem->Record->Flags & PH_PROCESS_RECORD_STAT_REF)) - { - PhReferenceProcessRecord(maxIoProcessItem->Record); - maxIoProcessItem->Record->Flags |= PH_PROCESS_RECORD_STAT_REF; - } - } - else - { - PhAddItemCircularBuffer_ULONG(&PhMaxIoHistory, PtrToUlong(NULL)); -#ifdef PH_RECORD_MAX_USAGE - PhAddItemCircularBuffer_ULONG64(&PhMaxIoReadOtherHistory, 0); - PhAddItemCircularBuffer_ULONG64(&PhMaxIoWriteHistory, 0); -#endif - } - } - - PhInvokeCallback(&PhProcessesUpdatedEvent, NULL); - runCount++; -} - -PPH_PROCESS_RECORD PhpCreateProcessRecord( - _In_ PPH_PROCESS_ITEM ProcessItem - ) -{ - PPH_PROCESS_RECORD processRecord; - - processRecord = PhAllocate(sizeof(PH_PROCESS_RECORD)); - memset(processRecord, 0, sizeof(PH_PROCESS_RECORD)); - - InitializeListHead(&processRecord->ListEntry); - processRecord->RefCount = 1; - - processRecord->ProcessId = ProcessItem->ProcessId; - processRecord->ParentProcessId = ProcessItem->ParentProcessId; - processRecord->SessionId = ProcessItem->SessionId; - processRecord->CreateTime = ProcessItem->CreateTime; - - PhSetReference(&processRecord->ProcessName, ProcessItem->ProcessName); - PhSetReference(&processRecord->FileName, ProcessItem->FileName); - PhSetReference(&processRecord->CommandLine, ProcessItem->CommandLine); - //PhSetReference(&processRecord->UserName, ProcessItem->UserName); - - return processRecord; -} - -PPH_PROCESS_RECORD PhpSearchProcessRecordList( - _In_ PLARGE_INTEGER Time, - _Out_opt_ PULONG Index, - _Out_opt_ PULONG InsertIndex - ) -{ - PPH_PROCESS_RECORD processRecord; - LONG low; - LONG high; - LONG i; - BOOLEAN found = FALSE; - INT comparison; - - if (PhProcessRecordList->Count == 0) - { - if (Index) - *Index = 0; - if (InsertIndex) - *InsertIndex = 0; - - return NULL; - } - - low = 0; - high = PhProcessRecordList->Count - 1; - - // Do a binary search. - do - { - i = (low + high) / 2; - processRecord = (PPH_PROCESS_RECORD)PhProcessRecordList->Items[i]; - - comparison = uint64cmp(Time->QuadPart, processRecord->CreateTime.QuadPart); - - if (comparison == 0) - { - found = TRUE; - break; - } - else if (comparison < 0) - { - high = i - 1; - } - else - { - low = i + 1; - } - } while (low <= high); - - if (Index) - *Index = i; - - if (found) - { - return processRecord; - } - else - { - if (InsertIndex) - *InsertIndex = i + (comparison > 0); - - return NULL; - } -} - -VOID PhpAddProcessRecord( - _Inout_ PPH_PROCESS_RECORD ProcessRecord - ) -{ - PPH_PROCESS_RECORD processRecord; - ULONG insertIndex; - - PhAcquireQueuedLockExclusive(&PhProcessRecordListLock); - - processRecord = PhpSearchProcessRecordList(&ProcessRecord->CreateTime, NULL, &insertIndex); - - if (!processRecord) - { - // Insert the process record, keeping the list sorted. - PhInsertItemList(PhProcessRecordList, insertIndex, ProcessRecord); - } - else - { - // Link the process record with the existing one that we found. - InsertTailList(&processRecord->ListEntry, &ProcessRecord->ListEntry); - } - - PhReleaseQueuedLockExclusive(&PhProcessRecordListLock); -} - -VOID PhpRemoveProcessRecord( - _Inout_ PPH_PROCESS_RECORD ProcessRecord - ) -{ - ULONG i; - PPH_PROCESS_RECORD headProcessRecord; - - PhAcquireQueuedLockExclusive(&PhProcessRecordListLock); - - headProcessRecord = PhpSearchProcessRecordList(&ProcessRecord->CreateTime, &i, NULL); - assert(headProcessRecord); - - // Unlink the record from the list. - RemoveEntryList(&ProcessRecord->ListEntry); - - if (ProcessRecord == headProcessRecord) - { - // Remove the slot completely, or choose a new head record. - if (IsListEmpty(&headProcessRecord->ListEntry)) - PhRemoveItemList(PhProcessRecordList, i); - else - PhProcessRecordList->Items[i] = CONTAINING_RECORD(headProcessRecord->ListEntry.Flink, PH_PROCESS_RECORD, ListEntry); - } - - PhReleaseQueuedLockExclusive(&PhProcessRecordListLock); -} - -VOID PhReferenceProcessRecord( - _In_ PPH_PROCESS_RECORD ProcessRecord - ) -{ - _InterlockedIncrement(&ProcessRecord->RefCount); -} - -BOOLEAN PhReferenceProcessRecordSafe( - _In_ PPH_PROCESS_RECORD ProcessRecord - ) -{ - return _InterlockedIncrementNoZero(&ProcessRecord->RefCount); -} - -VOID PhReferenceProcessRecordForStatistics( - _In_ PPH_PROCESS_RECORD ProcessRecord - ) -{ - if (!(ProcessRecord->Flags & PH_PROCESS_RECORD_STAT_REF)) - { - PhReferenceProcessRecord(ProcessRecord); - ProcessRecord->Flags |= PH_PROCESS_RECORD_STAT_REF; - } -} - -VOID PhDereferenceProcessRecord( - _In_ PPH_PROCESS_RECORD ProcessRecord - ) -{ - if (_InterlockedDecrement(&ProcessRecord->RefCount) == 0) - { - PhpRemoveProcessRecord(ProcessRecord); - - PhDereferenceObject(ProcessRecord->ProcessName); - if (ProcessRecord->FileName) PhDereferenceObject(ProcessRecord->FileName); - if (ProcessRecord->CommandLine) PhDereferenceObject(ProcessRecord->CommandLine); - /*if (ProcessRecord->UserName) PhDereferenceObject(ProcessRecord->UserName);*/ - PhFree(ProcessRecord); - } -} - -PPH_PROCESS_RECORD PhpFindProcessRecord( - _In_ PPH_PROCESS_RECORD ProcessRecord, - _In_ HANDLE ProcessId - ) -{ - PPH_PROCESS_RECORD startProcessRecord; - - startProcessRecord = ProcessRecord; - - do - { - if (ProcessRecord->ProcessId == ProcessId) - return ProcessRecord; - - ProcessRecord = CONTAINING_RECORD(ProcessRecord->ListEntry.Flink, PH_PROCESS_RECORD, ListEntry); - } while (ProcessRecord != startProcessRecord); - - return NULL; -} - -/** - * Finds a process record. - * - * \param ProcessId The ID of the process. - * \param Time A time in which the process was active. - * - * \return The newest record older than \a Time, or NULL - * if the record could not be found. You must call - * PhDereferenceProcessRecord() when you no longer need - * the record. - */ -PPH_PROCESS_RECORD PhFindProcessRecord( - _In_opt_ HANDLE ProcessId, - _In_ PLARGE_INTEGER Time - ) -{ - PPH_PROCESS_RECORD processRecord; - ULONG i; - BOOLEAN found; - - if (PhProcessRecordList->Count == 0) - return NULL; - - PhAcquireQueuedLockShared(&PhProcessRecordListLock); - - processRecord = PhpSearchProcessRecordList(Time, &i, NULL); - - if (!processRecord) - { - // This is expected. Now we search backwards to find the newest matching element older than - // the given time. - - found = FALSE; - - while (TRUE) - { - processRecord = (PPH_PROCESS_RECORD)PhProcessRecordList->Items[i]; - - if (processRecord->CreateTime.QuadPart < Time->QuadPart) - { - if (ProcessId) - { - processRecord = PhpFindProcessRecord(processRecord, ProcessId); - - if (processRecord) - found = TRUE; - } - else - { - found = TRUE; - } - - if (found) - break; - } - - if (i == 0) - break; - - i--; - } - } - else - { - if (ProcessId) - { - processRecord = PhpFindProcessRecord(processRecord, ProcessId); - - if (processRecord) - found = TRUE; - else - found = FALSE; - } - else - { - found = TRUE; - } - } - - if (found) - { - // The record might have had its last reference just cleared but it hasn't been removed from - // the list yet. - if (!PhReferenceProcessRecordSafe(processRecord)) - found = FALSE; - } - - PhReleaseQueuedLockShared(&PhProcessRecordListLock); - - if (found) - return processRecord; - else - return NULL; -} - -/** - * Deletes unused process records. - */ -VOID PhPurgeProcessRecords( - VOID - ) -{ - PPH_PROCESS_RECORD processRecord; - PPH_PROCESS_RECORD startProcessRecord; - ULONG i; - LARGE_INTEGER threshold; - PPH_LIST derefList = NULL; - - if (PhProcessRecordList->Count == 0) - return; - - // Get the oldest statistics time. - PhGetStatisticsTime(NULL, PhTimeHistory.Count - 1, &threshold); - - PhAcquireQueuedLockShared(&PhProcessRecordListLock); - - for (i = 0; i < PhProcessRecordList->Count; i++) - { - processRecord = PhProcessRecordList->Items[i]; - startProcessRecord = processRecord; - - do - { - ULONG requiredFlags; - - requiredFlags = PH_PROCESS_RECORD_DEAD | PH_PROCESS_RECORD_STAT_REF; - - if ((processRecord->Flags & requiredFlags) == requiredFlags) - { - // Check if the process exit time is before the oldest statistics time. If so we can - // dereference the process record. - if (processRecord->ExitTime.QuadPart < threshold.QuadPart) - { - // Clear the stat ref bit; this is to make sure we don't try to dereference the - // record twice (e.g. if someone else currently holds a reference to the record - // and it doesn't get removed immediately). - processRecord->Flags &= ~PH_PROCESS_RECORD_STAT_REF; - - if (!derefList) - derefList = PhCreateList(2); - - PhAddItemList(derefList, processRecord); - } - } - - processRecord = CONTAINING_RECORD(processRecord->ListEntry.Flink, PH_PROCESS_RECORD, ListEntry); - } while (processRecord != startProcessRecord); - } - - PhReleaseQueuedLockShared(&PhProcessRecordListLock); - - if (derefList) - { - for (i = 0; i < derefList->Count; i++) - { - PhDereferenceProcessRecord(derefList->Items[i]); - } - - PhDereferenceObject(derefList); - } -} - -PPH_PROCESS_ITEM PhReferenceProcessItemForParent( - _In_ HANDLE ParentProcessId, - _In_ HANDLE ProcessId, - _In_ PLARGE_INTEGER CreateTime - ) -{ - PPH_PROCESS_ITEM processItem; - - if (ParentProcessId == ProcessId) // for cases where the parent PID = PID (e.g. System Idle Process) - return NULL; - - PhAcquireQueuedLockShared(&PhProcessHashSetLock); - - processItem = PhpLookupProcessItem(ParentProcessId); - - // We make sure that the process item we found is actually the parent process - its start time - // must not be larger than the supplied time. - if (processItem && processItem->CreateTime.QuadPart <= CreateTime->QuadPart) - PhReferenceObject(processItem); - else - processItem = NULL; - - PhReleaseQueuedLockShared(&PhProcessHashSetLock); - - return processItem; -} - -PPH_PROCESS_ITEM PhReferenceProcessItemForRecord( - _In_ PPH_PROCESS_RECORD Record - ) -{ - PPH_PROCESS_ITEM processItem; - - PhAcquireQueuedLockShared(&PhProcessHashSetLock); - - processItem = PhpLookupProcessItem(Record->ProcessId); - - if (processItem && processItem->CreateTime.QuadPart == Record->CreateTime.QuadPart) - PhReferenceObject(processItem); - else - processItem = NULL; - - PhReleaseQueuedLockShared(&PhProcessHashSetLock); - - return processItem; -} +/* + * Process Hacker - + * process provider + * + * Copyright (C) 2009-2016 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +/* + * This provider module handles the collection of process information and system-wide statistics. A + * list of all running processes is kept and periodically scanned to detect new and terminated + * processes. + * + * The retrieval of certain information is delayed in order to improve performance. This includes + * things such as file icons, version information, digital signature verification, and packed + * executable detection. These requests are handed to worker threads which then post back + * information to a S-list. + * + * Also contained in this module is the storage of process records, which contain static information + * about processes. Unlike process items which are removed as soon as their corresponding process + * exits, process records remain as long as they are needed by the statistics system, and more + * specifically the max. CPU and I/O history buffers. In PH 1.x, a new formatted string was created + * at each update containing information about the maximum-usage process within that interval. Here + * we use a much more storage-efficient method, where the raw maximum-usage PIDs are stored for each + * interval, and the process record list is searched when the name of a process is needed. + * + * The process record list is stored as a list of records sorted by process creation time. If two or + * more processes have the same creation time, they are added to a doubly-linked list. This + * structure allows for fast searching in the typical scenario where we know the PID of a process + * and a specific time in which the process was running. In this case a binary search is used and + * then the list is traversed backwards until the process is found. Binary search is similarly used + * for insertion and removal. + * + * On Windows 7 and above, CPU usage can be calculated from cycle time. However, cycle time cannot + * be split into kernel/user components, and cycle time is not available for DPCs and Interrupts + * separately (only a "system" cycle time). + */ + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#define PROCESS_ID_BUCKETS 64 +#define PROCESS_ID_TO_BUCKET_INDEX(ProcessId) ((HandleToUlong(ProcessId) / 4) & (PROCESS_ID_BUCKETS - 1)) + +typedef struct _PH_PROCESS_QUERY_DATA +{ + SLIST_ENTRY ListEntry; + ULONG Stage; + PPH_PROCESS_ITEM ProcessItem; +} PH_PROCESS_QUERY_DATA, *PPH_PROCESS_QUERY_DATA; + +typedef struct _PH_PROCESS_QUERY_S1_DATA +{ + PH_PROCESS_QUERY_DATA Header; + + PPH_STRING CommandLine; + + HICON SmallIcon; + HICON LargeIcon; + PH_IMAGE_VERSION_INFO VersionInfo; + + TOKEN_ELEVATION_TYPE ElevationType; + MANDATORY_LEVEL IntegrityLevel; + PWSTR IntegrityString; + + PPH_STRING JobName; + HANDLE ConsoleHostProcessId; + PPH_STRING PackageFullName; + + union + { + ULONG Flags; + struct + { + ULONG IsDotNet : 1; + ULONG IsElevated : 1; + ULONG IsInJob : 1; + ULONG IsInSignificantJob : 1; + ULONG IsWow64 : 1; + ULONG IsWow64Valid : 1; + ULONG IsProtectedProcess : 1; + ULONG IsSecureProcess : 1; + ULONG IsSubsystemProcess : 1; + + ULONG Spare : 23; + }; + }; +} PH_PROCESS_QUERY_S1_DATA, *PPH_PROCESS_QUERY_S1_DATA; + +typedef struct _PH_PROCESS_QUERY_S2_DATA +{ + PH_PROCESS_QUERY_DATA Header; + + VERIFY_RESULT VerifyResult; + PPH_STRING VerifySignerName; + + BOOLEAN IsPacked; + ULONG ImportFunctions; + ULONG ImportModules; +} PH_PROCESS_QUERY_S2_DATA, *PPH_PROCESS_QUERY_S2_DATA; + +typedef struct _PH_VERIFY_CACHE_ENTRY +{ + PH_AVL_LINKS Links; + + PPH_STRING FileName; + VERIFY_RESULT VerifyResult; + PPH_STRING VerifySignerName; +} PH_VERIFY_CACHE_ENTRY, *PPH_VERIFY_CACHE_ENTRY; + +typedef struct _PH_SID_FULL_NAME_CACHE_ENTRY +{ + PSID Sid; + PPH_STRING FullName; +} PH_SID_FULL_NAME_CACHE_ENTRY, *PPH_SID_FULL_NAME_CACHE_ENTRY; + +VOID NTAPI PhpProcessItemDeleteProcedure( + _In_ PVOID Object, + _In_ ULONG Flags + ); + +INT NTAPI PhpVerifyCacheCompareFunction( + _In_ PPH_AVL_LINKS Links1, + _In_ PPH_AVL_LINKS Links2 + ); + +VOID PhpQueueProcessQueryStage1( + _In_ PPH_PROCESS_ITEM ProcessItem + ); + +VOID PhpQueueProcessQueryStage2( + _In_ PPH_PROCESS_ITEM ProcessItem + ); + +PPH_PROCESS_RECORD PhpCreateProcessRecord( + _In_ PPH_PROCESS_ITEM ProcessItem + ); + +VOID PhpAddProcessRecord( + _Inout_ PPH_PROCESS_RECORD ProcessRecord + ); + +VOID PhpRemoveProcessRecord( + _Inout_ PPH_PROCESS_RECORD ProcessRecord + ); + +PPH_OBJECT_TYPE PhProcessItemType; + +PPH_HASH_ENTRY PhProcessHashSet[256] = PH_HASH_SET_INIT; +ULONG PhProcessHashSetCount = 0; +PH_QUEUED_LOCK PhProcessHashSetLock = PH_QUEUED_LOCK_INIT; + +SLIST_HEADER PhProcessQueryDataListHead; + +PHAPPAPI PH_CALLBACK_DECLARE(PhProcessAddedEvent); +PHAPPAPI PH_CALLBACK_DECLARE(PhProcessModifiedEvent); +PHAPPAPI PH_CALLBACK_DECLARE(PhProcessRemovedEvent); +PHAPPAPI PH_CALLBACK_DECLARE(PhProcessesUpdatedEvent); + +PPH_LIST PhProcessRecordList; +PH_QUEUED_LOCK PhProcessRecordListLock = PH_QUEUED_LOCK_INIT; + +ULONG PhStatisticsSampleCount = 512; +BOOLEAN PhEnableProcessQueryStage2 = FALSE; +BOOLEAN PhEnablePurgeProcessRecords = TRUE; +BOOLEAN PhEnableCycleCpuUsage = TRUE; + +PVOID PhProcessInformation; // only can be used if running on same thread as process provider +SYSTEM_PERFORMANCE_INFORMATION PhPerfInformation; +PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION PhCpuInformation; +SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION PhCpuTotals; +ULONG PhTotalProcesses; +ULONG PhTotalThreads; +ULONG PhTotalHandles; + +SYSTEM_PROCESS_INFORMATION PhDpcsProcessInformation; +SYSTEM_PROCESS_INFORMATION PhInterruptsProcessInformation; + +ULONG64 PhCpuTotalCycleDelta; // real cycle time delta for this period +PLARGE_INTEGER PhCpuIdleCycleTime; // cycle time for Idle +PLARGE_INTEGER PhCpuSystemCycleTime; // cycle time for DPCs and Interrupts +PH_UINT64_DELTA PhCpuIdleCycleDelta; +PH_UINT64_DELTA PhCpuSystemCycleDelta; +//PPH_UINT64_DELTA PhCpusIdleCycleDelta; + +FLOAT PhCpuKernelUsage; +FLOAT PhCpuUserUsage; +PFLOAT PhCpusKernelUsage; +PFLOAT PhCpusUserUsage; + +PH_UINT64_DELTA PhCpuKernelDelta; +PH_UINT64_DELTA PhCpuUserDelta; +PH_UINT64_DELTA PhCpuIdleDelta; + +PPH_UINT64_DELTA PhCpusKernelDelta; +PPH_UINT64_DELTA PhCpusUserDelta; +PPH_UINT64_DELTA PhCpusIdleDelta; + +PH_UINT64_DELTA PhIoReadDelta; +PH_UINT64_DELTA PhIoWriteDelta; +PH_UINT64_DELTA PhIoOtherDelta; + +static BOOLEAN PhProcessStatisticsInitialized = FALSE; +static ULONG PhTimeSequenceNumber = 0; +static PH_CIRCULAR_BUFFER_ULONG PhTimeHistory; + +PH_CIRCULAR_BUFFER_FLOAT PhCpuKernelHistory; +PH_CIRCULAR_BUFFER_FLOAT PhCpuUserHistory; +//PH_CIRCULAR_BUFFER_FLOAT PhCpuOtherHistory; + +PPH_CIRCULAR_BUFFER_FLOAT PhCpusKernelHistory; +PPH_CIRCULAR_BUFFER_FLOAT PhCpusUserHistory; +//PPH_CIRCULAR_BUFFER_FLOAT PhCpusOtherHistory; + +PH_CIRCULAR_BUFFER_ULONG64 PhIoReadHistory; +PH_CIRCULAR_BUFFER_ULONG64 PhIoWriteHistory; +PH_CIRCULAR_BUFFER_ULONG64 PhIoOtherHistory; + +PH_CIRCULAR_BUFFER_ULONG PhCommitHistory; +PH_CIRCULAR_BUFFER_ULONG PhPhysicalHistory; + +PH_CIRCULAR_BUFFER_ULONG PhMaxCpuHistory; // ID of max. CPU process +PH_CIRCULAR_BUFFER_ULONG PhMaxIoHistory; // ID of max. I/O process +#ifdef PH_RECORD_MAX_USAGE +PH_CIRCULAR_BUFFER_FLOAT PhMaxCpuUsageHistory; +PH_CIRCULAR_BUFFER_ULONG64 PhMaxIoReadOtherHistory; +PH_CIRCULAR_BUFFER_ULONG64 PhMaxIoWriteHistory; +#endif + +static PTS_ALL_PROCESSES_INFO PhpTsProcesses = NULL; +static ULONG PhpTsNumberOfProcesses; + +#ifdef PH_ENABLE_VERIFY_CACHE +static PH_AVL_TREE PhpVerifyCacheSet = PH_AVL_TREE_INIT(PhpVerifyCacheCompareFunction); +static PH_QUEUED_LOCK PhpVerifyCacheLock = PH_QUEUED_LOCK_INIT; +#endif + +static PPH_HASHTABLE PhpSidFullNameCacheHashtable; + +BOOLEAN PhProcessProviderInitialization( + VOID + ) +{ + PFLOAT usageBuffer; + PPH_UINT64_DELTA deltaBuffer; + PPH_CIRCULAR_BUFFER_FLOAT historyBuffer; + + PhProcessItemType = PhCreateObjectType(L"ProcessItem", 0, PhpProcessItemDeleteProcedure); + + RtlInitializeSListHead(&PhProcessQueryDataListHead); + + PhProcessRecordList = PhCreateList(40); + + RtlInitUnicodeString( + &PhDpcsProcessInformation.ImageName, + L"DPCs" + ); + PhDpcsProcessInformation.UniqueProcessId = DPCS_PROCESS_ID; + PhDpcsProcessInformation.InheritedFromUniqueProcessId = SYSTEM_IDLE_PROCESS_ID; + + RtlInitUnicodeString( + &PhInterruptsProcessInformation.ImageName, + L"Interrupts" + ); + PhInterruptsProcessInformation.UniqueProcessId = INTERRUPTS_PROCESS_ID; + PhInterruptsProcessInformation.InheritedFromUniqueProcessId = SYSTEM_IDLE_PROCESS_ID; + + PhCpuInformation = PhAllocate( + sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION) * + (ULONG)PhSystemBasicInformation.NumberOfProcessors + ); + + PhCpuIdleCycleTime = PhAllocate( + sizeof(LARGE_INTEGER) * + (ULONG)PhSystemBasicInformation.NumberOfProcessors + ); + PhCpuSystemCycleTime = PhAllocate( + sizeof(LARGE_INTEGER) * + (ULONG)PhSystemBasicInformation.NumberOfProcessors + ); + + usageBuffer = PhAllocate( + sizeof(FLOAT) * + (ULONG)PhSystemBasicInformation.NumberOfProcessors * + 2 + ); + deltaBuffer = PhAllocate( + sizeof(PH_UINT64_DELTA) * + (ULONG)PhSystemBasicInformation.NumberOfProcessors * + 3 // 4 for PhCpusIdleCycleDelta + ); + historyBuffer = PhAllocate( + sizeof(PH_CIRCULAR_BUFFER_FLOAT) * + (ULONG)PhSystemBasicInformation.NumberOfProcessors * + 2 + ); + + PhCpusKernelUsage = usageBuffer; + PhCpusUserUsage = PhCpusKernelUsage + (ULONG)PhSystemBasicInformation.NumberOfProcessors; + + PhCpusKernelDelta = deltaBuffer; + PhCpusUserDelta = PhCpusKernelDelta + (ULONG)PhSystemBasicInformation.NumberOfProcessors; + PhCpusIdleDelta = PhCpusUserDelta + (ULONG)PhSystemBasicInformation.NumberOfProcessors; + //PhCpusIdleCycleDelta = PhCpusIdleDelta + (ULONG)PhSystemBasicInformation.NumberOfProcessors; + + PhCpusKernelHistory = historyBuffer; + PhCpusUserHistory = PhCpusKernelHistory + (ULONG)PhSystemBasicInformation.NumberOfProcessors; + + memset(deltaBuffer, 0, sizeof(PH_UINT64_DELTA) * (ULONG)PhSystemBasicInformation.NumberOfProcessors); + + return TRUE; +} + +PPH_STRING PhGetClientIdName( + _In_ PCLIENT_ID ClientId + ) +{ + PPH_STRING name; + PPH_PROCESS_ITEM processItem; + + processItem = PhReferenceProcessItem(ClientId->UniqueProcess); + + if (processItem) + { + name = PhGetClientIdNameEx(ClientId, processItem->ProcessName); + PhDereferenceObject(processItem); + } + else + { + name = PhGetClientIdNameEx(ClientId, NULL); + } + + return name; +} + +PPH_STRING PhGetClientIdNameEx( + _In_ PCLIENT_ID ClientId, + _In_opt_ PPH_STRING ProcessName + ) +{ + PPH_STRING name; + PH_FORMAT format[5]; + + if (ClientId->UniqueThread) + { + if (ProcessName) + { + PhInitFormatSR(&format[0], ProcessName->sr); + PhInitFormatS(&format[1], L" ("); + PhInitFormatIU(&format[2], (ULONG_PTR)ClientId->UniqueProcess); + PhInitFormatS(&format[3], L"): "); + PhInitFormatIU(&format[4], (ULONG_PTR)ClientId->UniqueThread); + + name = PhFormat(format, 5, ProcessName->Length + 16 * sizeof(WCHAR)); + } + else + { + PhInitFormatS(&format[0], L"Non-existent process ("); + PhInitFormatIU(&format[1], (ULONG_PTR)ClientId->UniqueProcess); + PhInitFormatS(&format[2], L"): "); + PhInitFormatIU(&format[3], (ULONG_PTR)ClientId->UniqueThread); + + name = PhFormat(format, 4, 0); + } + } + else + { + if (ProcessName) + { + PhInitFormatSR(&format[0], ProcessName->sr); + PhInitFormatS(&format[1], L" ("); + PhInitFormatIU(&format[2], (ULONG_PTR)ClientId->UniqueProcess); + PhInitFormatC(&format[3], ')'); + + name = PhFormat(format, 4, 0); + } + else + { + PhInitFormatS(&format[0], L"Non-existent process ("); + PhInitFormatIU(&format[1], (ULONG_PTR)ClientId->UniqueProcess); + PhInitFormatC(&format[2], ')'); + + name = PhFormat(format, 3, 0); + } + } + + return name; +} + +PWSTR PhGetProcessPriorityClassString( + _In_ ULONG PriorityClass + ) +{ + switch (PriorityClass) + { + case PROCESS_PRIORITY_CLASS_REALTIME: + return L"Real time"; + case PROCESS_PRIORITY_CLASS_HIGH: + return L"High"; + case PROCESS_PRIORITY_CLASS_ABOVE_NORMAL: + return L"Above normal"; + case PROCESS_PRIORITY_CLASS_NORMAL: + return L"Normal"; + case PROCESS_PRIORITY_CLASS_BELOW_NORMAL: + return L"Below normal"; + case PROCESS_PRIORITY_CLASS_IDLE: + return L"Idle"; + default: + return L"Unknown"; + } +} + +/** + * Creates a process item. + */ +PPH_PROCESS_ITEM PhCreateProcessItem( + _In_ HANDLE ProcessId + ) +{ + PPH_PROCESS_ITEM processItem; + + processItem = PhCreateObject( + PhEmGetObjectSize(EmProcessItemType, sizeof(PH_PROCESS_ITEM)), + PhProcessItemType + ); + memset(processItem, 0, sizeof(PH_PROCESS_ITEM)); + PhInitializeEvent(&processItem->Stage1Event); + PhInitializeQueuedLock(&processItem->ServiceListLock); + + processItem->ProcessId = ProcessId; + + if (!PH_IS_FAKE_PROCESS_ID(ProcessId)) + PhPrintUInt32(processItem->ProcessIdString, HandleToUlong(ProcessId)); + + // Create the statistics buffers. + PhInitializeCircularBuffer_FLOAT(&processItem->CpuKernelHistory, PhStatisticsSampleCount); + PhInitializeCircularBuffer_FLOAT(&processItem->CpuUserHistory, PhStatisticsSampleCount); + PhInitializeCircularBuffer_ULONG64(&processItem->IoReadHistory, PhStatisticsSampleCount); + PhInitializeCircularBuffer_ULONG64(&processItem->IoWriteHistory, PhStatisticsSampleCount); + PhInitializeCircularBuffer_ULONG64(&processItem->IoOtherHistory, PhStatisticsSampleCount); + PhInitializeCircularBuffer_SIZE_T(&processItem->PrivateBytesHistory, PhStatisticsSampleCount); + //PhInitializeCircularBuffer_SIZE_T(&processItem->WorkingSetHistory, PhStatisticsSampleCount); + + PhEmCallObjectOperation(EmProcessItemType, processItem, EmObjectCreate); + + return processItem; +} + +VOID PhpProcessItemDeleteProcedure( + _In_ PVOID Object, + _In_ ULONG Flags + ) +{ + PPH_PROCESS_ITEM processItem = (PPH_PROCESS_ITEM)Object; + ULONG i; + + PhEmCallObjectOperation(EmProcessItemType, processItem, EmObjectDelete); + + PhDeleteCircularBuffer_FLOAT(&processItem->CpuKernelHistory); + PhDeleteCircularBuffer_FLOAT(&processItem->CpuUserHistory); + PhDeleteCircularBuffer_ULONG64(&processItem->IoReadHistory); + PhDeleteCircularBuffer_ULONG64(&processItem->IoWriteHistory); + PhDeleteCircularBuffer_ULONG64(&processItem->IoOtherHistory); + PhDeleteCircularBuffer_SIZE_T(&processItem->PrivateBytesHistory); + //PhDeleteCircularBuffer_SIZE_T(&processItem->WorkingSetHistory); + + if (processItem->ServiceList) + { + PPH_SERVICE_ITEM serviceItem; + + i = 0; + + while (PhEnumPointerList(processItem->ServiceList, &i, &serviceItem)) + PhDereferenceObject(serviceItem); + + PhDereferenceObject(processItem->ServiceList); + } + + if (processItem->ProcessName) PhDereferenceObject(processItem->ProcessName); + if (processItem->FileName) PhDereferenceObject(processItem->FileName); + if (processItem->CommandLine) PhDereferenceObject(processItem->CommandLine); + if (processItem->SmallIcon) DestroyIcon(processItem->SmallIcon); + if (processItem->LargeIcon) DestroyIcon(processItem->LargeIcon); + PhDeleteImageVersionInfo(&processItem->VersionInfo); + if (processItem->UserName) PhDereferenceObject(processItem->UserName); + if (processItem->JobName) PhDereferenceObject(processItem->JobName); + if (processItem->VerifySignerName) PhDereferenceObject(processItem->VerifySignerName); + if (processItem->PackageFullName) PhDereferenceObject(processItem->PackageFullName); + + if (processItem->QueryHandle) NtClose(processItem->QueryHandle); + + if (processItem->Record) PhDereferenceProcessRecord(processItem->Record); +} + +FORCEINLINE BOOLEAN PhCompareProcessItem( + _In_ PPH_PROCESS_ITEM Value1, + _In_ PPH_PROCESS_ITEM Value2 + ) +{ + return Value1->ProcessId == Value2->ProcessId; +} + +FORCEINLINE ULONG PhHashProcessItem( + _In_ PPH_PROCESS_ITEM Value + ) +{ + return HandleToUlong(Value->ProcessId) / 4; +} + +/** + * Finds a process item in the hash set. + * + * \param ProcessId The process ID of the process item. + * + * \remarks The hash set must be locked before calling this function. The reference count of the + * found process item is not incremented. + */ +PPH_PROCESS_ITEM PhpLookupProcessItem( + _In_ HANDLE ProcessId + ) +{ + PH_PROCESS_ITEM lookupProcessItem; + PPH_HASH_ENTRY entry; + PPH_PROCESS_ITEM processItem; + + lookupProcessItem.ProcessId = ProcessId; + entry = PhFindEntryHashSet( + PhProcessHashSet, + PH_HASH_SET_SIZE(PhProcessHashSet), + PhHashProcessItem(&lookupProcessItem) + ); + + for (; entry; entry = entry->Next) + { + processItem = CONTAINING_RECORD(entry, PH_PROCESS_ITEM, HashEntry); + + if (PhCompareProcessItem(&lookupProcessItem, processItem)) + return processItem; + } + + return NULL; +} + +/** + * Finds and references a process item. + * + * \param ProcessId The process ID of the process item. + * + * \return The found process item. + */ +PPH_PROCESS_ITEM PhReferenceProcessItem( + _In_ HANDLE ProcessId + ) +{ + PPH_PROCESS_ITEM processItem; + + PhAcquireQueuedLockShared(&PhProcessHashSetLock); + + processItem = PhpLookupProcessItem(ProcessId); + + if (processItem) + PhReferenceObject(processItem); + + PhReleaseQueuedLockShared(&PhProcessHashSetLock); + + return processItem; +} + +/** + * Enumerates the process items. + * + * \param ProcessItems A variable which receives an array of pointers to process items. You must + * free the buffer with PhFree() when you no longer need it. + * \param NumberOfProcessItems A variable which receives the number of process items returned in + * \a ProcessItems. + */ +VOID PhEnumProcessItems( + _Out_opt_ PPH_PROCESS_ITEM **ProcessItems, + _Out_ PULONG NumberOfProcessItems + ) +{ + PPH_PROCESS_ITEM *processItems; + ULONG numberOfProcessItems; + ULONG count = 0; + ULONG i; + PPH_HASH_ENTRY entry; + PPH_PROCESS_ITEM processItem; + + if (!ProcessItems) + { + *NumberOfProcessItems = PhProcessHashSetCount; + return; + } + + PhAcquireQueuedLockShared(&PhProcessHashSetLock); + + numberOfProcessItems = PhProcessHashSetCount; + processItems = PhAllocate(sizeof(PPH_PROCESS_ITEM) * numberOfProcessItems); + + for (i = 0; i < PH_HASH_SET_SIZE(PhProcessHashSet); i++) + { + for (entry = PhProcessHashSet[i]; entry; entry = entry->Next) + { + processItem = CONTAINING_RECORD(entry, PH_PROCESS_ITEM, HashEntry); + PhReferenceObject(processItem); + processItems[count++] = processItem; + } + } + + PhReleaseQueuedLockShared(&PhProcessHashSetLock); + + *ProcessItems = processItems; + *NumberOfProcessItems = numberOfProcessItems; +} + +VOID PhpAddProcessItem( + _In_ _Assume_refs_(1) PPH_PROCESS_ITEM ProcessItem + ) +{ + PhAddEntryHashSet( + PhProcessHashSet, + PH_HASH_SET_SIZE(PhProcessHashSet), + &ProcessItem->HashEntry, + PhHashProcessItem(ProcessItem) + ); + PhProcessHashSetCount++; +} + +VOID PhpRemoveProcessItem( + _In_ PPH_PROCESS_ITEM ProcessItem + ) +{ + PhRemoveEntryHashSet(PhProcessHashSet, PH_HASH_SET_SIZE(PhProcessHashSet), &ProcessItem->HashEntry); + PhProcessHashSetCount--; + PhDereferenceObject(ProcessItem); +} + +INT NTAPI PhpVerifyCacheCompareFunction( + _In_ PPH_AVL_LINKS Links1, + _In_ PPH_AVL_LINKS Links2 + ) +{ + PPH_VERIFY_CACHE_ENTRY entry1 = CONTAINING_RECORD(Links1, PH_VERIFY_CACHE_ENTRY, Links); + PPH_VERIFY_CACHE_ENTRY entry2 = CONTAINING_RECORD(Links2, PH_VERIFY_CACHE_ENTRY, Links); + + return PhCompareString(entry1->FileName, entry2->FileName, TRUE); +} + +VERIFY_RESULT PhVerifyFileWithAdditionalCatalog( + _In_ PPH_VERIFY_FILE_INFO Information, + _In_opt_ PWSTR PackageFullName, + _Out_opt_ PPH_STRING *SignerName + ) +{ + static PH_STRINGREF codeIntegrityFileName = PH_STRINGREF_INIT(L"\\AppxMetadata\\CodeIntegrity.cat"); + + VERIFY_RESULT result; + PPH_STRING additionalCatalogFileName = NULL; + PCERT_CONTEXT *signatures; + ULONG numberOfSignatures; + + if (PackageFullName) + { + PACKAGE_ID *packageId; + PPH_STRING packagePath; + + if (packageId = PhPackageIdFromFullName(PackageFullName)) + { + if (packagePath = PhGetPackagePath(packageId)) + { + additionalCatalogFileName = PhConcatStringRef2(&packagePath->sr, &codeIntegrityFileName); + PhDereferenceObject(packagePath); + } + + PhFree(packageId); + } + } + + if (additionalCatalogFileName) + { + Information->NumberOfCatalogFileNames = 1; + Information->CatalogFileNames = &additionalCatalogFileName->Buffer; + } + + if (!NT_SUCCESS(PhVerifyFileEx(Information, &result, &signatures, &numberOfSignatures))) + { + result = VrNoSignature; + signatures = NULL; + numberOfSignatures = 0; + } + + if (additionalCatalogFileName) + PhDereferenceObject(additionalCatalogFileName); + + if (SignerName) + { + if (numberOfSignatures != 0) + *SignerName = PhGetSignerNameFromCertificate(signatures[0]); + else + *SignerName = NULL; + } + + PhFreeVerifySignatures(signatures, numberOfSignatures); + + return result; +} + +/** + * Verifies a file's digital signature, using a cached result if possible. + * + * \param FileName A file name. + * \param ProcessItem An associated process item. + * \param SignerName A variable which receives a pointer to a string containing the signer name. You + * must free the string using PhDereferenceObject() when you no longer need it. Note that the signer + * name may be NULL if it is not valid. + * \param CachedOnly Specify TRUE to fail the function when no cached result exists. + * + * \return A VERIFY_RESULT value. + */ +VERIFY_RESULT PhVerifyFileCached( + _In_ PPH_STRING FileName, + _In_opt_ PWSTR PackageFullName, + _Out_opt_ PPH_STRING *SignerName, + _In_ BOOLEAN CachedOnly + ) +{ +#ifdef PH_ENABLE_VERIFY_CACHE + PPH_AVL_LINKS links; + PPH_VERIFY_CACHE_ENTRY entry; + PH_VERIFY_CACHE_ENTRY lookupEntry; + + lookupEntry.FileName = FileName; + + PhAcquireQueuedLockShared(&PhpVerifyCacheLock); + links = PhFindElementAvlTree(&PhpVerifyCacheSet, &lookupEntry.Links); + PhReleaseQueuedLockShared(&PhpVerifyCacheLock); + + if (links) + { + entry = CONTAINING_RECORD(links, PH_VERIFY_CACHE_ENTRY, Links); + + if (SignerName) + PhSetReference(SignerName, entry->VerifySignerName); + + return entry->VerifyResult; + } + else + { + VERIFY_RESULT result; + PPH_STRING signerName; + + if (!CachedOnly) + { + PH_VERIFY_FILE_INFO info; + + memset(&info, 0, sizeof(PH_VERIFY_FILE_INFO)); + info.FileName = FileName->Buffer; + info.Flags = PH_VERIFY_PREVENT_NETWORK_ACCESS; + result = PhVerifyFileWithAdditionalCatalog(&info, PackageFullName, &signerName); + + if (result != VrTrusted) + PhClearReference(&signerName); + } + else + { + result = VrUnknown; + signerName = NULL; + } + + if (result != VrUnknown) + { + entry = PhAllocate(sizeof(PH_VERIFY_CACHE_ENTRY)); + entry->FileName = FileName; + entry->VerifyResult = result; + entry->VerifySignerName = signerName; + + PhAcquireQueuedLockExclusive(&PhpVerifyCacheLock); + links = PhAddElementAvlTree(&PhpVerifyCacheSet, &entry->Links); + PhReleaseQueuedLockExclusive(&PhpVerifyCacheLock); + + if (!links) + { + // We successfully added the cache entry. Add references. + + PhReferenceObject(entry->FileName); + + if (entry->VerifySignerName) + PhReferenceObject(entry->VerifySignerName); + } + else + { + // Entry already exists. + PhFree(entry); + } + } + + if (SignerName) + { + *SignerName = signerName; + } + else + { + if (signerName) + PhDereferenceObject(signerName); + } + + return result; + } +#else + VERIFY_RESULT result; + PPH_STRING signerName; + PH_VERIFY_FILE_INFO info; + + memset(&info, 0, sizeof(PH_VERIFY_FILE_INFO)); + info.FileName = FileName->Buffer; + info.Flags = PH_VERIFY_PREVENT_NETWORK_ACCESS; + result = PhVerifyFileWithAdditionalCatalog(&info, PackageFullName, &signerName); + + if (result != VrTrusted) + PhClearReference(&signerName); + + if (SignerName) + { + *SignerName = signerName; + } + else + { + if (signerName) + PhDereferenceObject(signerName); + } + + return result; +#endif +} + +BOOLEAN PhpSidFullNameCacheHashtableEqualFunction( + _In_ PVOID Entry1, + _In_ PVOID Entry2 + ) +{ + PPH_SID_FULL_NAME_CACHE_ENTRY entry1 = Entry1; + PPH_SID_FULL_NAME_CACHE_ENTRY entry2 = Entry2; + + return RtlEqualSid(entry1->Sid, entry2->Sid); +} + +ULONG PhpSidFullNameCacheHashtableHashFunction( + _In_ PVOID Entry + ) +{ + PPH_SID_FULL_NAME_CACHE_ENTRY entry = Entry; + + return PhHashBytes(entry->Sid, RtlLengthSid(entry->Sid)); +} + +PPH_STRING PhpGetSidFullNameCached( + _In_ PSID Sid + ) +{ + PPH_STRING fullName; + PH_SID_FULL_NAME_CACHE_ENTRY newEntry; + + if (PhpSidFullNameCacheHashtable) + { + PPH_SID_FULL_NAME_CACHE_ENTRY entry; + PH_SID_FULL_NAME_CACHE_ENTRY lookupEntry; + + lookupEntry.Sid = Sid; + entry = PhFindEntryHashtable(PhpSidFullNameCacheHashtable, &lookupEntry); + + if (entry) + return PhReferenceObject(entry->FullName); + } + + fullName = PhGetSidFullName(Sid, TRUE, NULL); + + if (!fullName) + return NULL; + + if (!PhpSidFullNameCacheHashtable) + { + PhpSidFullNameCacheHashtable = PhCreateHashtable( + sizeof(PH_SID_FULL_NAME_CACHE_ENTRY), + PhpSidFullNameCacheHashtableEqualFunction, + PhpSidFullNameCacheHashtableHashFunction, + 16 + ); + } + + newEntry.Sid = PhAllocateCopy(Sid, RtlLengthSid(Sid)); + newEntry.FullName = PhReferenceObject(fullName); + PhAddEntryHashtable(PhpSidFullNameCacheHashtable, &newEntry); + + return fullName; +} + +VOID PhpFlushSidFullNameCache( + VOID + ) +{ + PH_HASHTABLE_ENUM_CONTEXT enumContext; + PPH_SID_FULL_NAME_CACHE_ENTRY entry; + + if (!PhpSidFullNameCacheHashtable) + return; + + PhBeginEnumHashtable(PhpSidFullNameCacheHashtable, &enumContext); + + while (entry = PhNextEnumHashtable(&enumContext)) + { + PhFree(entry->Sid); + PhDereferenceObject(entry->FullName); + } + + PhClearReference(&PhpSidFullNameCacheHashtable); +} + +VOID PhpProcessQueryStage1( + _Inout_ PPH_PROCESS_QUERY_S1_DATA Data + ) +{ + NTSTATUS status; + PPH_PROCESS_ITEM processItem = Data->Header.ProcessItem; + HANDLE processId = processItem->ProcessId; + HANDLE processHandleLimited = NULL; + + PhOpenProcess(&processHandleLimited, ProcessQueryAccess, processId); + + if (processItem->FileName) + { + // Small icon, large icon. + if (ExtractIconEx( + processItem->FileName->Buffer, + 0, + &Data->LargeIcon, + &Data->SmallIcon, + 1 + ) == 0) + { + Data->LargeIcon = NULL; + Data->SmallIcon = NULL; + } + + // Version info. + PhInitializeImageVersionInfo(&Data->VersionInfo, processItem->FileName->Buffer); + } + + // Use the default EXE icon if we didn't get the file's icon. + { + if (!Data->SmallIcon || !Data->LargeIcon) + { + if (Data->SmallIcon) + { + DestroyIcon(Data->SmallIcon); + Data->SmallIcon = NULL; + } + else if (Data->LargeIcon) + { + DestroyIcon(Data->LargeIcon); + Data->LargeIcon = NULL; + } + + PhGetStockApplicationIcon(&Data->SmallIcon, &Data->LargeIcon); + Data->SmallIcon = CopyIcon(Data->SmallIcon); + Data->LargeIcon = CopyIcon(Data->LargeIcon); + } + } + + // Process flags + if (processHandleLimited) + { + PROCESS_EXTENDED_BASIC_INFORMATION basicInfo; + + if (NT_SUCCESS(PhGetProcessExtendedBasicInformation(processHandleLimited, &basicInfo))) + { + Data->IsProtectedProcess = basicInfo.IsProtectedProcess; + Data->IsSecureProcess = basicInfo.IsSecureProcess; + Data->IsSubsystemProcess = basicInfo.IsSubsystemProcess; + Data->IsWow64 = basicInfo.IsWow64Process; + Data->IsWow64Valid = TRUE; + } + } + + // Command line, .NET + { + HANDLE processHandle; + BOOLEAN queryAccess = FALSE; + + status = PhOpenProcess( + &processHandle, + ProcessQueryAccess | PROCESS_VM_READ, + processId + ); + + if (!NT_SUCCESS(status) && WindowsVersion >= WINDOWS_8_1) + { + queryAccess = TRUE; + status = PhOpenProcess( + &processHandle, + ProcessQueryAccess, + processId + ); + } + + if (NT_SUCCESS(status)) + { + BOOLEAN isDotNet = FALSE; + PPH_STRING commandLine; + ULONG i; + + if (NT_SUCCESS(status = PhGetProcessCommandLine(processHandle, &commandLine))) + { + // Some command lines (e.g. from taskeng.exe) have nulls in them. Since Windows + // can't display them, we'll replace them with spaces. + for (i = 0; i < (ULONG)commandLine->Length / 2; i++) + { + if (commandLine->Buffer[i] == 0) + commandLine->Buffer[i] = ' '; + } + } + + if (NT_SUCCESS(status)) + { + Data->CommandLine = commandLine; + } + + if (!queryAccess) + { + PhGetProcessIsDotNetEx( + processId, + processHandle, +#ifdef _WIN64 + PH_CLR_NO_WOW64_CHECK | (Data->IsWow64 ? PH_CLR_KNOWN_IS_WOW64 : 0), +#else + 0, +#endif + &isDotNet, + NULL + ); + Data->IsDotNet = isDotNet; + } + + NtClose(processHandle); + } + } + + // Token information + if (processHandleLimited) + { + if (WINDOWS_HAS_UAC) + { + HANDLE tokenHandle; + + status = PhOpenProcessToken(processHandleLimited, TOKEN_QUERY, &tokenHandle); + + if (NT_SUCCESS(status)) + { + // Elevation + if (NT_SUCCESS(PhGetTokenElevationType( + tokenHandle, + &Data->ElevationType + ))) + { + Data->IsElevated = Data->ElevationType == TokenElevationTypeFull; + } + + // Integrity + PhGetTokenIntegrityLevel( + tokenHandle, + &Data->IntegrityLevel, + &Data->IntegrityString + ); + + NtClose(tokenHandle); + } + } + } + + // Job + if (processHandleLimited) + { + if (KphIsConnected()) + { + HANDLE jobHandle = NULL; + + status = KphOpenProcessJob( + processHandleLimited, + JOB_OBJECT_QUERY, + &jobHandle + ); + + if (NT_SUCCESS(status) && status != STATUS_PROCESS_NOT_IN_JOB && jobHandle) + { + JOBOBJECT_BASIC_LIMIT_INFORMATION basicLimits; + + Data->IsInJob = TRUE; + + PhGetHandleInformation( + NtCurrentProcess(), + jobHandle, + -1, + NULL, + NULL, + NULL, + &Data->JobName + ); + + // Process Explorer only recognizes processes as being in jobs if they don't have + // the silent-breakaway-OK limit as their only limit. Emulate this behaviour. + if (NT_SUCCESS(PhGetJobBasicLimits(jobHandle, &basicLimits))) + { + Data->IsInSignificantJob = + basicLimits.LimitFlags != JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK; + } + + NtClose(jobHandle); + } + } + else + { + // KProcessHacker is not available. We can determine if the process is in a job, but we + // can't get a handle to the job. + + status = NtIsProcessInJob(processHandleLimited, NULL); + + if (NT_SUCCESS(status)) + Data->IsInJob = status == STATUS_PROCESS_IN_JOB; + } + } + + // Console host process + if (processHandleLimited && WINDOWS_HAS_CONSOLE_HOST) + { + PhGetProcessConsoleHostProcessId(processHandleLimited, &Data->ConsoleHostProcessId); + } + + // Package full name + if (processHandleLimited && WINDOWS_HAS_IMMERSIVE) + { + Data->PackageFullName = PhGetProcessPackageFullName(processHandleLimited); + } + + if (processHandleLimited) + NtClose(processHandleLimited); + + PhpQueueProcessQueryStage2(processItem); +} + +VOID PhpProcessQueryStage2( + _Inout_ PPH_PROCESS_QUERY_S2_DATA Data + ) +{ + NTSTATUS status; + PPH_PROCESS_ITEM processItem = Data->Header.ProcessItem; + + if (PhEnableProcessQueryStage2 && processItem->FileName) + { + PPH_STRING packageFullName = NULL; + + if (processItem->QueryHandle) + packageFullName = PhGetProcessPackageFullName(processItem->QueryHandle); + + Data->VerifyResult = PhVerifyFileCached( + processItem->FileName, + PhGetString(packageFullName), + &Data->VerifySignerName, + FALSE + ); + + if (packageFullName) + PhDereferenceObject(packageFullName); + + status = PhIsExecutablePacked( + processItem->FileName->Buffer, + &Data->IsPacked, + &Data->ImportModules, + &Data->ImportFunctions + ); + + // If we got an image-related error, the image is packed. + if ( + status == STATUS_INVALID_IMAGE_NOT_MZ || + status == STATUS_INVALID_IMAGE_FORMAT || + status == STATUS_ACCESS_VIOLATION + ) + { + Data->IsPacked = TRUE; + Data->ImportModules = -1; + Data->ImportFunctions = -1; + } + } +} + +NTSTATUS PhpProcessQueryStage1Worker( + _In_ PVOID Parameter + ) +{ + PPH_PROCESS_QUERY_S1_DATA data; + PPH_PROCESS_ITEM processItem = (PPH_PROCESS_ITEM)Parameter; + + data = PhAllocate(sizeof(PH_PROCESS_QUERY_S1_DATA)); + memset(data, 0, sizeof(PH_PROCESS_QUERY_S1_DATA)); + data->Header.Stage = 1; + data->Header.ProcessItem = processItem; + + PhpProcessQueryStage1(data); + + RtlInterlockedPushEntrySList(&PhProcessQueryDataListHead, &data->Header.ListEntry); + + return STATUS_SUCCESS; +} + +NTSTATUS PhpProcessQueryStage2Worker( + _In_ PVOID Parameter + ) +{ + PPH_PROCESS_QUERY_S2_DATA data; + PPH_PROCESS_ITEM processItem = (PPH_PROCESS_ITEM)Parameter; + + data = PhAllocate(sizeof(PH_PROCESS_QUERY_S2_DATA)); + memset(data, 0, sizeof(PH_PROCESS_QUERY_S2_DATA)); + data->Header.Stage = 2; + data->Header.ProcessItem = processItem; + + PhpProcessQueryStage2(data); + + RtlInterlockedPushEntrySList(&PhProcessQueryDataListHead, &data->Header.ListEntry); + + return STATUS_SUCCESS; +} + +VOID PhpQueueProcessQueryStage1( + _In_ PPH_PROCESS_ITEM ProcessItem + ) +{ + PH_WORK_QUEUE_ENVIRONMENT environment; + + // Ref: dereferenced when the provider update function removes the item from the queue. + PhReferenceObject(ProcessItem); + + PhInitializeWorkQueueEnvironment(&environment); + environment.BasePriority = THREAD_PRIORITY_BELOW_NORMAL; + + PhQueueItemWorkQueueEx(PhGetGlobalWorkQueue(), PhpProcessQueryStage1Worker, ProcessItem, + NULL, &environment); +} + +VOID PhpQueueProcessQueryStage2( + _In_ PPH_PROCESS_ITEM ProcessItem + ) +{ + PH_WORK_QUEUE_ENVIRONMENT environment; + + if (!PhEnableProcessQueryStage2) + return; + + PhReferenceObject(ProcessItem); + + PhInitializeWorkQueueEnvironment(&environment); + environment.BasePriority = THREAD_PRIORITY_BELOW_NORMAL; + environment.IoPriority = IoPriorityVeryLow; + environment.PagePriority = MEMORY_PRIORITY_VERY_LOW; + + PhQueueItemWorkQueueEx(PhGetGlobalWorkQueue(), PhpProcessQueryStage2Worker, ProcessItem, + NULL, &environment); +} + +VOID PhpFillProcessItemStage1( + _In_ PPH_PROCESS_QUERY_S1_DATA Data + ) +{ + PPH_PROCESS_ITEM processItem = Data->Header.ProcessItem; + + processItem->CommandLine = Data->CommandLine; + processItem->SmallIcon = Data->SmallIcon; + processItem->LargeIcon = Data->LargeIcon; + memcpy(&processItem->VersionInfo, &Data->VersionInfo, sizeof(PH_IMAGE_VERSION_INFO)); + processItem->ElevationType = Data->ElevationType; + processItem->IntegrityLevel = Data->IntegrityLevel; + processItem->IntegrityString = Data->IntegrityString; + processItem->JobName = Data->JobName; + processItem->ConsoleHostProcessId = Data->ConsoleHostProcessId; + processItem->PackageFullName = Data->PackageFullName; + processItem->IsDotNet = Data->IsDotNet; + processItem->IsElevated = Data->IsElevated; + processItem->IsInJob = Data->IsInJob; + processItem->IsInSignificantJob = Data->IsInSignificantJob; + processItem->IsWow64 = Data->IsWow64; + processItem->IsWow64Valid = Data->IsWow64Valid; + processItem->IsProtectedProcess = Data->IsProtectedProcess; + processItem->IsSecureProcess = Data->IsSecureProcess; + processItem->IsSubsystemProcess = Data->IsSubsystemProcess; + + PhSwapReference(&processItem->Record->CommandLine, processItem->CommandLine); +} + +VOID PhpFillProcessItemStage2( + _In_ PPH_PROCESS_QUERY_S2_DATA Data + ) +{ + PPH_PROCESS_ITEM processItem = Data->Header.ProcessItem; + + processItem->VerifyResult = Data->VerifyResult; + processItem->VerifySignerName = Data->VerifySignerName; + processItem->IsPacked = Data->IsPacked; + processItem->ImportFunctions = Data->ImportFunctions; + processItem->ImportModules = Data->ImportModules; +} + +VOID PhpFillProcessItem( + _Inout_ PPH_PROCESS_ITEM ProcessItem, + _In_ PSYSTEM_PROCESS_INFORMATION Process + ) +{ + NTSTATUS status; + HANDLE processHandle = NULL; + + ProcessItem->ParentProcessId = Process->InheritedFromUniqueProcessId; + ProcessItem->SessionId = Process->SessionId; + ProcessItem->CreateTime = Process->CreateTime; + + if (ProcessItem->ProcessId != SYSTEM_IDLE_PROCESS_ID) + ProcessItem->ProcessName = PhCreateStringFromUnicodeString(&Process->ImageName); + else + ProcessItem->ProcessName = PhCreateString(SYSTEM_IDLE_PROCESS_NAME); + + PhPrintUInt32(ProcessItem->ParentProcessIdString, HandleToUlong(ProcessItem->ParentProcessId)); + PhPrintUInt32(ProcessItem->SessionIdString, ProcessItem->SessionId); + + PhOpenProcess(&processHandle, ProcessQueryAccess, ProcessItem->ProcessId); + + // Process information + { + // If we're dealing with System (PID 4), we need to get the + // kernel file name. Otherwise, get the image file name. + + if (ProcessItem->ProcessId != SYSTEM_PROCESS_ID) + { + PPH_STRING fileName; + + if (WindowsVersion >= WINDOWS_VISTA) + { + if (processHandle) + { + PhGetProcessImageFileNameWin32(processHandle, &ProcessItem->FileName); + } + else + { + if (NT_SUCCESS(PhGetProcessImageFileNameByProcessId(ProcessItem->ProcessId, &fileName))) + { + ProcessItem->FileName = PhGetFileName(fileName); + PhDereferenceObject(fileName); + } + } + } + else + { + if (processHandle && NT_SUCCESS(PhGetProcessImageFileName(processHandle, &fileName))) + { + ProcessItem->FileName = PhGetFileName(fileName); + PhDereferenceObject(fileName); + } + } + } + else + { + PPH_STRING fileName; + + fileName = PhGetKernelFileName(); + + if (fileName) + { + ProcessItem->FileName = PhGetFileName(fileName); + PhDereferenceObject(fileName); + } + } + } + + // Token-related information + if ( + processHandle && + ProcessItem->ProcessId != SYSTEM_PROCESS_ID // Token of System process can't be opened sometimes + ) + { + HANDLE tokenHandle; + + status = PhOpenProcessToken(processHandle, TOKEN_QUERY, &tokenHandle); + + if (NT_SUCCESS(status)) + { + // User name + { + PTOKEN_USER user; + + status = PhGetTokenUser(tokenHandle, &user); + + if (NT_SUCCESS(status)) + { + ProcessItem->UserName = PhpGetSidFullNameCached(user->User.Sid); + PhFree(user); + } + } + + NtClose(tokenHandle); + } + } + else + { + if ( + ProcessItem->ProcessId == SYSTEM_IDLE_PROCESS_ID || + ProcessItem->ProcessId == SYSTEM_PROCESS_ID // System token can't be opened on XP + ) + { + PhSetReference(&ProcessItem->UserName, PhLocalSystemName); + } + } + + if (!ProcessItem->UserName && WindowsVersion <= WINDOWS_XP) + { + // In some cases we can get the user SID using WTS (only works on XP and below). + + if (!PhpTsProcesses) + { + WinStationGetAllProcesses( + NULL, + 0, + &PhpTsNumberOfProcesses, + &PhpTsProcesses + ); + } + + if (PhpTsProcesses) + { + ULONG i; + + for (i = 0; i < PhpTsNumberOfProcesses; i++) + { + if (UlongToHandle(PhpTsProcesses[i].pTsProcessInfo->UniqueProcessId) == ProcessItem->ProcessId) + { + ProcessItem->UserName = PhpGetSidFullNameCached(PhpTsProcesses[i].pSid); + break; + } + } + } + } + + NtClose(processHandle); +} + +FORCEINLINE VOID PhpUpdateDynamicInfoProcessItem( + _Inout_ PPH_PROCESS_ITEM ProcessItem, + _In_ PSYSTEM_PROCESS_INFORMATION Process + ) +{ + ProcessItem->BasePriority = Process->BasePriority; + + if (ProcessItem->QueryHandle) + { + PROCESS_PRIORITY_CLASS priorityClass; + + if (NT_SUCCESS(NtQueryInformationProcess( + ProcessItem->QueryHandle, + ProcessPriorityClass, + &priorityClass, + sizeof(PROCESS_PRIORITY_CLASS), + NULL + ))) + { + ProcessItem->PriorityClass = priorityClass.PriorityClass; + } + } + else + { + ProcessItem->PriorityClass = 0; + } + + ProcessItem->KernelTime = Process->KernelTime; + ProcessItem->UserTime = Process->UserTime; + ProcessItem->NumberOfHandles = Process->HandleCount; + ProcessItem->NumberOfThreads = Process->NumberOfThreads; + ProcessItem->WorkingSetPrivateSize = (SIZE_T)Process->WorkingSetPrivateSize.QuadPart; + ProcessItem->PeakNumberOfThreads = Process->NumberOfThreadsHighWatermark; + ProcessItem->HardFaultCount = Process->HardFaultCount; + + // Update VM and I/O counters. + ProcessItem->VmCounters = *(PVM_COUNTERS_EX)&Process->PeakVirtualSize; + ProcessItem->IoCounters = *(PIO_COUNTERS)&Process->ReadOperationCount; +} + +VOID PhpUpdatePerfInformation( + VOID + ) +{ + NtQuerySystemInformation( + SystemPerformanceInformation, + &PhPerfInformation, + sizeof(SYSTEM_PERFORMANCE_INFORMATION), + NULL + ); + + PhUpdateDelta(&PhIoReadDelta, PhPerfInformation.IoReadTransferCount.QuadPart); + PhUpdateDelta(&PhIoWriteDelta, PhPerfInformation.IoWriteTransferCount.QuadPart); + PhUpdateDelta(&PhIoOtherDelta, PhPerfInformation.IoOtherTransferCount.QuadPart); +} + +VOID PhpUpdateCpuInformation( + _In_ BOOLEAN SetCpuUsage, + _Out_ PULONG64 TotalTime + ) +{ + ULONG i; + ULONG64 totalTime; + + NtQuerySystemInformation( + SystemProcessorPerformanceInformation, + PhCpuInformation, + sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION) * (ULONG)PhSystemBasicInformation.NumberOfProcessors, + NULL + ); + + // Zero the CPU totals. + memset(&PhCpuTotals, 0, sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION)); + + for (i = 0; i < (ULONG)PhSystemBasicInformation.NumberOfProcessors; i++) + { + PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION cpuInfo = + &PhCpuInformation[i]; + + // KernelTime includes IdleTime. + cpuInfo->KernelTime.QuadPart -= cpuInfo->IdleTime.QuadPart; + + PhCpuTotals.DpcTime.QuadPart += cpuInfo->DpcTime.QuadPart; + PhCpuTotals.IdleTime.QuadPart += cpuInfo->IdleTime.QuadPart; + PhCpuTotals.InterruptCount += cpuInfo->InterruptCount; + PhCpuTotals.InterruptTime.QuadPart += cpuInfo->InterruptTime.QuadPart; + PhCpuTotals.KernelTime.QuadPart += cpuInfo->KernelTime.QuadPart; + PhCpuTotals.UserTime.QuadPart += cpuInfo->UserTime.QuadPart; + + PhUpdateDelta(&PhCpusKernelDelta[i], cpuInfo->KernelTime.QuadPart); + PhUpdateDelta(&PhCpusUserDelta[i], cpuInfo->UserTime.QuadPart); + PhUpdateDelta(&PhCpusIdleDelta[i], cpuInfo->IdleTime.QuadPart); + + if (SetCpuUsage) + { + totalTime = PhCpusKernelDelta[i].Delta + PhCpusUserDelta[i].Delta + PhCpusIdleDelta[i].Delta; + + if (totalTime != 0) + { + PhCpusKernelUsage[i] = (FLOAT)PhCpusKernelDelta[i].Delta / totalTime; + PhCpusUserUsage[i] = (FLOAT)PhCpusUserDelta[i].Delta / totalTime; + } + else + { + PhCpusKernelUsage[i] = 0; + PhCpusUserUsage[i] = 0; + } + } + } + + PhUpdateDelta(&PhCpuKernelDelta, PhCpuTotals.KernelTime.QuadPart); + PhUpdateDelta(&PhCpuUserDelta, PhCpuTotals.UserTime.QuadPart); + PhUpdateDelta(&PhCpuIdleDelta, PhCpuTotals.IdleTime.QuadPart); + + totalTime = PhCpuKernelDelta.Delta + PhCpuUserDelta.Delta + PhCpuIdleDelta.Delta; + + if (SetCpuUsage) + { + if (totalTime != 0) + { + PhCpuKernelUsage = (FLOAT)PhCpuKernelDelta.Delta / totalTime; + PhCpuUserUsage = (FLOAT)PhCpuUserDelta.Delta / totalTime; + } + else + { + PhCpuKernelUsage = 0; + PhCpuUserUsage = 0; + } + } + + *TotalTime = totalTime; +} + +VOID PhpUpdateCpuCycleInformation( + _Out_ PULONG64 IdleCycleTime + ) +{ + ULONG i; + ULONG64 total; + + // Idle + + // We need to query this separately because the idle cycle time in SYSTEM_PROCESS_INFORMATION + // doesn't give us data for individual processors. + + NtQuerySystemInformation( + SystemProcessorIdleCycleTimeInformation, + PhCpuIdleCycleTime, + sizeof(LARGE_INTEGER) * (ULONG)PhSystemBasicInformation.NumberOfProcessors, + NULL + ); + + total = 0; + + for (i = 0; i < (ULONG)PhSystemBasicInformation.NumberOfProcessors; i++) + { + //PhUpdateDelta(&PhCpusIdleCycleDelta[i], PhCpuIdleCycleTime[i].QuadPart); + total += PhCpuIdleCycleTime[i].QuadPart; + } + + PhUpdateDelta(&PhCpuIdleCycleDelta, total); + *IdleCycleTime = PhCpuIdleCycleDelta.Delta; + + // System + + NtQuerySystemInformation( + SystemProcessorCycleTimeInformation, + PhCpuSystemCycleTime, + sizeof(LARGE_INTEGER) * (ULONG)PhSystemBasicInformation.NumberOfProcessors, + NULL + ); + + total = 0; + + for (i = 0; i < (ULONG)PhSystemBasicInformation.NumberOfProcessors; i++) + { + total += PhCpuSystemCycleTime[i].QuadPart; + } + + PhUpdateDelta(&PhCpuSystemCycleDelta, total); +} + +VOID PhpUpdateCpuCycleUsageInformation( + _In_ ULONG64 TotalCycleTime, + _In_ ULONG64 IdleCycleTime + ) +{ + ULONG i; + FLOAT baseCpuUsage; + FLOAT totalTimeDelta; + ULONG64 totalTime; + + // Cycle time is not only lacking for kernel/user components, but also for individual + // processors. We can get the total idle cycle time for individual processors but + // without knowing the total cycle time for individual processors, this information + // is useless. + // + // We'll start by calculating the total CPU usage, then we'll calculate the kernel/user + // components. In the event that the corresponding CPU time deltas are zero, we'll split + // the CPU usage evenly across the kernel/user components. CPU usage for individual + // processors is left untouched, because it's too difficult to provide an estimate. + // + // Let I_1, I_2, ..., I_n be the idle cycle times and T_1, T_2, ..., T_n be the + // total cycle times. Let I'_1, I'_2, ..., I'_n be the idle CPU times and T'_1, T'_2, ..., + // T'_n be the total CPU times. + // We know all I'_n, T'_n and I_n, but we only know sigma(T). The "real" total CPU usage is + // sigma(I)/sigma(T), and the "real" individual CPU usage is I_n/T_n. The problem is that + // we don't know T_n; we only know sigma(T). Hence we need to find values i_1, i_2, ..., i_n + // and t_1, t_2, ..., t_n such that: + // sigma(i)/sigma(t) ~= sigma(I)/sigma(T), and + // i_n/t_n ~= I_n/T_n + // + // Solution 1: Set i_n = I_n and t_n = sigma(T)*T'_n/sigma(T'). Then: + // sigma(i)/sigma(t) = sigma(I)/(sigma(T)*sigma(T')/sigma(T')) = sigma(I)/sigma(T), and + // i_n/t_n = I_n/T'_n*sigma(T')/sigma(T) ~= I_n/T_n since I_n/T'_n ~= I_n/T_n and sigma(T')/sigma(T) ~= 1. + // However, it is not guaranteed that i_n/t_n <= 1, which may lead to CPU usages over 100% being displayed. + // + // Solution 2: Set i_n = I'_n and t_n = T'_n. Then: + // sigma(i)/sigma(t) = sigma(I')/sigma(T') ~= sigma(I)/sigma(T) since I'_n ~= I_n and T'_n ~= T_n. + // i_n/t_n = I'_n/T'_n ~= I_n/T_n as above. + // Not scaling at all is currently the best solution, since it's fast, simple and guarantees that i_n/t_n <= 1. + + baseCpuUsage = 1 - (FLOAT)IdleCycleTime / TotalCycleTime; + totalTimeDelta = (FLOAT)(PhCpuKernelDelta.Delta + PhCpuUserDelta.Delta); + + if (totalTimeDelta != 0) + { + PhCpuKernelUsage = baseCpuUsage * ((FLOAT)PhCpuKernelDelta.Delta / totalTimeDelta); + PhCpuUserUsage = baseCpuUsage * ((FLOAT)PhCpuUserDelta.Delta / totalTimeDelta); + } + else + { + PhCpuKernelUsage = baseCpuUsage / 2; + PhCpuUserUsage = baseCpuUsage / 2; + } + + for (i = 0; i < (ULONG)PhSystemBasicInformation.NumberOfProcessors; i++) + { + totalTime = PhCpusKernelDelta[i].Delta + PhCpusUserDelta[i].Delta + PhCpusIdleDelta[i].Delta; + + if (totalTime != 0) + { + PhCpusKernelUsage[i] = (FLOAT)PhCpusKernelDelta[i].Delta / totalTime; + PhCpusUserUsage[i] = (FLOAT)PhCpusUserDelta[i].Delta / totalTime; + } + else + { + PhCpusKernelUsage[i] = 0; + PhCpusUserUsage[i] = 0; + } + } +} + +VOID PhpInitializeProcessStatistics( + VOID + ) +{ + ULONG i; + + PhInitializeCircularBuffer_ULONG(&PhTimeHistory, PhStatisticsSampleCount); + PhInitializeCircularBuffer_FLOAT(&PhCpuKernelHistory, PhStatisticsSampleCount); + PhInitializeCircularBuffer_FLOAT(&PhCpuUserHistory, PhStatisticsSampleCount); + PhInitializeCircularBuffer_ULONG64(&PhIoReadHistory, PhStatisticsSampleCount); + PhInitializeCircularBuffer_ULONG64(&PhIoWriteHistory, PhStatisticsSampleCount); + PhInitializeCircularBuffer_ULONG64(&PhIoOtherHistory, PhStatisticsSampleCount); + PhInitializeCircularBuffer_ULONG(&PhCommitHistory, PhStatisticsSampleCount); + PhInitializeCircularBuffer_ULONG(&PhPhysicalHistory, PhStatisticsSampleCount); + PhInitializeCircularBuffer_ULONG(&PhMaxCpuHistory, PhStatisticsSampleCount); + PhInitializeCircularBuffer_ULONG(&PhMaxIoHistory, PhStatisticsSampleCount); +#ifdef PH_RECORD_MAX_USAGE + PhInitializeCircularBuffer_FLOAT(&PhMaxCpuUsageHistory, PhStatisticsSampleCount); + PhInitializeCircularBuffer_ULONG64(&PhMaxIoReadOtherHistory, PhStatisticsSampleCount); + PhInitializeCircularBuffer_ULONG64(&PhMaxIoWriteHistory, PhStatisticsSampleCount); +#endif + + for (i = 0; i < (ULONG)PhSystemBasicInformation.NumberOfProcessors; i++) + { + PhInitializeCircularBuffer_FLOAT(&PhCpusKernelHistory[i], PhStatisticsSampleCount); + PhInitializeCircularBuffer_FLOAT(&PhCpusUserHistory[i], PhStatisticsSampleCount); + } +} + +VOID PhpUpdateSystemHistory( + VOID + ) +{ + ULONG i; + LARGE_INTEGER systemTime; + ULONG secondsSince1980; + + // CPU + PhAddItemCircularBuffer_FLOAT(&PhCpuKernelHistory, PhCpuKernelUsage); + PhAddItemCircularBuffer_FLOAT(&PhCpuUserHistory, PhCpuUserUsage); + + // CPUs + for (i = 0; i < (ULONG)PhSystemBasicInformation.NumberOfProcessors; i++) + { + PhAddItemCircularBuffer_FLOAT(&PhCpusKernelHistory[i], PhCpusKernelUsage[i]); + PhAddItemCircularBuffer_FLOAT(&PhCpusUserHistory[i], PhCpusUserUsage[i]); + } + + // I/O + PhAddItemCircularBuffer_ULONG64(&PhIoReadHistory, PhIoReadDelta.Delta); + PhAddItemCircularBuffer_ULONG64(&PhIoWriteHistory, PhIoWriteDelta.Delta); + PhAddItemCircularBuffer_ULONG64(&PhIoOtherHistory, PhIoOtherDelta.Delta); + + // Memory + PhAddItemCircularBuffer_ULONG(&PhCommitHistory, PhPerfInformation.CommittedPages); + PhAddItemCircularBuffer_ULONG(&PhPhysicalHistory, + PhSystemBasicInformation.NumberOfPhysicalPages - PhPerfInformation.AvailablePages + ); + + // Time + PhQuerySystemTime(&systemTime); + RtlTimeToSecondsSince1980(&systemTime, &secondsSince1980); + PhAddItemCircularBuffer_ULONG(&PhTimeHistory, secondsSince1980); +} + +/** + * Retrieves a time value recorded by the statistics system. + * + * \param ProcessItem A process item to synchronize with, or NULL if no synchronization is + * necessary. + * \param Index The history index. + * \param Time A variable which receives the time at \a Index. + * + * \return TRUE if the function succeeded, otherwise FALSE if \a ProcessItem was specified and + * \a Index is too far into the past for that process item. + */ +BOOLEAN PhGetStatisticsTime( + _In_opt_ PPH_PROCESS_ITEM ProcessItem, + _In_ ULONG Index, + _Out_ PLARGE_INTEGER Time + ) +{ + ULONG secondsSince1980; + ULONG index; + LARGE_INTEGER time; + + if (ProcessItem) + { + // The sequence number is used to synchronize statistics when a process exits, since that + // process' history is not updated anymore. + index = PhTimeSequenceNumber - ProcessItem->SequenceNumber + Index; + + if (index >= PhTimeHistory.Count) + { + // The data point is too far into the past. + return FALSE; + } + } + else + { + // Assume the index is valid. + index = Index; + } + + secondsSince1980 = PhGetItemCircularBuffer_ULONG(&PhTimeHistory, index); + RtlSecondsSince1980ToTime(secondsSince1980, &time); + + *Time = time; + + return TRUE; +} + +PPH_STRING PhGetStatisticsTimeString( + _In_opt_ PPH_PROCESS_ITEM ProcessItem, + _In_ ULONG Index + ) +{ + LARGE_INTEGER time; + SYSTEMTIME systemTime; + + if (PhGetStatisticsTime(ProcessItem, Index, &time)) + { + PhLargeIntegerToLocalSystemTime(&systemTime, &time); + + return PhFormatDateTime(&systemTime); + } + else + { + return PhCreateString(L"Unknown time"); + } +} + +VOID PhFlushProcessQueryData( + _In_ BOOLEAN SendModifiedEvent + ) +{ + PSLIST_ENTRY entry; + PPH_PROCESS_QUERY_DATA data; + BOOLEAN processed; + + if (!RtlFirstEntrySList(&PhProcessQueryDataListHead)) + return; + + entry = RtlInterlockedFlushSList(&PhProcessQueryDataListHead); + + while (entry) + { + data = CONTAINING_RECORD(entry, PH_PROCESS_QUERY_DATA, ListEntry); + entry = entry->Next; + processed = FALSE; + + if (data->Stage == 1) + { + PhpFillProcessItemStage1((PPH_PROCESS_QUERY_S1_DATA)data); + PhSetEvent(&data->ProcessItem->Stage1Event); + processed = TRUE; + } + else if (data->Stage == 2) + { + PhpFillProcessItemStage2((PPH_PROCESS_QUERY_S2_DATA)data); + processed = TRUE; + } + + if (processed) + { + // Invoke the modified event only if the main provider has sent the added event already. + if (SendModifiedEvent && data->ProcessItem->AddedEventSent) + { + // Since this may be executing on a thread other than the main provider thread, we + // need to check whether the process has been removed already. If we don't do this + // then users may get a modified event after a removed event for the same process, + // which will lead to very bad things happening. + PhAcquireQueuedLockExclusive(&data->ProcessItem->RemoveLock); + if (!(data->ProcessItem->State & PH_PROCESS_ITEM_REMOVED)) + PhInvokeCallback(&PhProcessModifiedEvent, data->ProcessItem); + PhReleaseQueuedLockExclusive(&data->ProcessItem->RemoveLock); + } + else + { + data->ProcessItem->JustProcessed = 1; + } + } + + PhDereferenceObject(data->ProcessItem); + PhFree(data); + } +} + +VOID PhpGetProcessThreadInformation( + _In_ PSYSTEM_PROCESS_INFORMATION Process, + _Out_opt_ PBOOLEAN IsSuspended, + _Out_opt_ PBOOLEAN IsPartiallySuspended, + _Out_opt_ PULONG ContextSwitches + ) +{ + ULONG i; + BOOLEAN isSuspended; + BOOLEAN isPartiallySuspended; + ULONG contextSwitches; + + isSuspended = PH_IS_REAL_PROCESS_ID(Process->UniqueProcessId); + isPartiallySuspended = FALSE; + contextSwitches = 0; + + for (i = 0; i < Process->NumberOfThreads; i++) + { + if (Process->Threads[i].ThreadState != Waiting || + Process->Threads[i].WaitReason != Suspended) + { + isSuspended = FALSE; + } + else + { + isPartiallySuspended = TRUE; + } + + contextSwitches += Process->Threads[i].ContextSwitches; + } + + if (IsSuspended) + *IsSuspended = isSuspended; + if (IsPartiallySuspended) + *IsPartiallySuspended = isPartiallySuspended; + if (ContextSwitches) + *ContextSwitches = contextSwitches; +} + +VOID PhProcessProviderUpdate( + _In_ PVOID Object + ) +{ + static ULONG runCount = 0; + static PSYSTEM_PROCESS_INFORMATION pidBuckets[PROCESS_ID_BUCKETS]; + + // Note about locking: + // + // Since this is the only function that is allowed to modify the process hashtable, locking is + // not needed for shared accesses. However, exclusive accesses need locking. + + PVOID processes; + PSYSTEM_PROCESS_INFORMATION process; + ULONG bucketIndex; + + BOOLEAN isCycleCpuUsageEnabled = FALSE; + + ULONG64 sysTotalTime; // total time for this update period + ULONG64 sysTotalCycleTime = 0; // total cycle time for this update period + ULONG64 sysIdleCycleTime = 0; // total idle cycle time for this update period + FLOAT maxCpuValue = 0; + PPH_PROCESS_ITEM maxCpuProcessItem = NULL; + ULONG64 maxIoValue = 0; + PPH_PROCESS_ITEM maxIoProcessItem = NULL; + + // Pre-update tasks + + if (runCount % 5 == 0) + { + PhUpdateDosDevicePrefixes(); + } + + if (runCount % 512 == 0) // yes, a very long time + { + if (PhEnablePurgeProcessRecords) + PhPurgeProcessRecords(); + } + + isCycleCpuUsageEnabled = WindowsVersion >= WINDOWS_7 && PhEnableCycleCpuUsage; + + if (!PhProcessStatisticsInitialized) + { + PhpInitializeProcessStatistics(); + PhProcessStatisticsInitialized = TRUE; + } + + PhpUpdatePerfInformation(); + + if (isCycleCpuUsageEnabled) + { + PhpUpdateCpuInformation(FALSE, &sysTotalTime); + PhpUpdateCpuCycleInformation(&sysIdleCycleTime); + } + else + { + PhpUpdateCpuInformation(TRUE, &sysTotalTime); + } + + if (runCount != 0) + { + PhTimeSequenceNumber++; + } + + // Get the process list. + + PhTotalProcesses = 0; + PhTotalThreads = 0; + PhTotalHandles = 0; + + if (!NT_SUCCESS(PhEnumProcesses(&processes))) + return; + + // Notes on cycle-based CPU usage: + // + // Cycle-based CPU usage is a bit tricky to calculate because we cannot get the total number of + // cycles consumed by all processes since system startup - we can only get total number of + // cycles per process. This means there are two ways to calculate the system-wide cycle time + // delta: + // + // 1. Each update, sum the cycle times of all processes, and calculate the system-wide delta + // from this. Process Explorer seems to do this. + // 2. Each update, calculate the cycle time delta for each individual process, and sum these + // deltas to create the system-wide delta. We use this here. + // + // The first method is simpler but has a problem when a process exits and its cycle time is no + // longer counted in the system-wide total. This may cause the delta to be negative and all + // other calculations to become invalid. Process Explorer simply ignored this fact and treated + // the system-wide delta as unsigned (and therefore huge when negative), leading to all CPU + // usages being displayed as "< 0.01". + // + // The second method is used here, but the adjustments must be done before the main new/modified + // pass. We need take into account new, existing and terminated processes. + + // Create the PID hash set. This contains the process information structures returned by + // PhEnumProcesses, distinct from the process item hash set. Note that we use the + // UniqueProcessKey field as the next node pointer to avoid having to allocate extra memory. + + memset(pidBuckets, 0, sizeof(pidBuckets)); + + process = PH_FIRST_PROCESS(processes); + + do + { + PhTotalProcesses++; + PhTotalThreads += process->NumberOfThreads; + PhTotalHandles += process->HandleCount; + + if (process->UniqueProcessId == SYSTEM_IDLE_PROCESS_ID) + { + process->CycleTime = PhCpuIdleCycleDelta.Value; + process->KernelTime = PhCpuTotals.IdleTime; + } + + bucketIndex = PROCESS_ID_TO_BUCKET_INDEX(process->UniqueProcessId); + process->UniqueProcessKey = (ULONG_PTR)pidBuckets[bucketIndex]; + pidBuckets[bucketIndex] = process; + + if (isCycleCpuUsageEnabled) + { + PPH_PROCESS_ITEM processItem; + + if ((processItem = PhpLookupProcessItem(process->UniqueProcessId)) && processItem->CreateTime.QuadPart == process->CreateTime.QuadPart) + sysTotalCycleTime += process->CycleTime - processItem->CycleTimeDelta.Value; // existing process + else + sysTotalCycleTime += process->CycleTime; // new process + } + } while (process = PH_NEXT_PROCESS(process)); + + // Add the fake processes to the PID list. + // + // On Windows 7 the two fake processes are merged into "Interrupts" since we can only get cycle + // time information both DPCs and Interrupts combined. + + if (isCycleCpuUsageEnabled) + { + PhInterruptsProcessInformation.KernelTime.QuadPart = PhCpuTotals.DpcTime.QuadPart + PhCpuTotals.InterruptTime.QuadPart; + PhInterruptsProcessInformation.CycleTime = PhCpuSystemCycleDelta.Value; + sysTotalCycleTime += PhCpuSystemCycleDelta.Delta; + } + else + { + PhDpcsProcessInformation.KernelTime = PhCpuTotals.DpcTime; + PhInterruptsProcessInformation.KernelTime = PhCpuTotals.InterruptTime; + } + + // Look for dead processes. + { + PPH_LIST processesToRemove = NULL; + ULONG i; + PPH_HASH_ENTRY entry; + PPH_PROCESS_ITEM processItem; + PSYSTEM_PROCESS_INFORMATION processEntry; + + for (i = 0; i < PH_HASH_SET_SIZE(PhProcessHashSet); i++) + { + for (entry = PhProcessHashSet[i]; entry; entry = entry->Next) + { + processItem = CONTAINING_RECORD(entry, PH_PROCESS_ITEM, HashEntry); + + // Check if the process still exists. Note that we take into account PID re-use by + // checking CreateTime as well. + + if (processItem->ProcessId == DPCS_PROCESS_ID) + { + processEntry = &PhDpcsProcessInformation; + } + else if (processItem->ProcessId == INTERRUPTS_PROCESS_ID) + { + processEntry = &PhInterruptsProcessInformation; + } + else + { + processEntry = pidBuckets[PROCESS_ID_TO_BUCKET_INDEX(processItem->ProcessId)]; + + while (processEntry && processEntry->UniqueProcessId != processItem->ProcessId) + processEntry = (PSYSTEM_PROCESS_INFORMATION)processEntry->UniqueProcessKey; + } + + if (!processEntry || processEntry->CreateTime.QuadPart != processItem->CreateTime.QuadPart) + { + LARGE_INTEGER exitTime; + + processItem->State |= PH_PROCESS_ITEM_REMOVED; + exitTime.QuadPart = 0; + + if (processItem->QueryHandle) + { + KERNEL_USER_TIMES times; + ULONG64 finalCycleTime; + + if (NT_SUCCESS(PhGetProcessTimes(processItem->QueryHandle, ×))) + { + exitTime = times.ExitTime; + } + + if (isCycleCpuUsageEnabled) + { + if (NT_SUCCESS(PhGetProcessCycleTime(processItem->QueryHandle, &finalCycleTime))) + { + // Adjust deltas for the terminated process because this doesn't get + // picked up anywhere else. + // + // Note that if we don't have sufficient access to the process, the + // worst that will happen is that the CPU usages of other processes + // will get inflated. (See above; if we were using the first + // technique, we could get negative deltas, which is much worse.) + sysTotalCycleTime += finalCycleTime - processItem->CycleTimeDelta.Value; + } + } + } + + // If we don't have a valid exit time, use the current time. + if (exitTime.QuadPart == 0) + PhQuerySystemTime(&exitTime); + + processItem->Record->Flags |= PH_PROCESS_RECORD_DEAD; + processItem->Record->ExitTime = exitTime; + + // Raise the process removed event. + // See PhFlushProcessQueryData for why we need to lock here. + PhAcquireQueuedLockExclusive(&processItem->RemoveLock); + PhInvokeCallback(&PhProcessRemovedEvent, processItem); + PhReleaseQueuedLockExclusive(&processItem->RemoveLock); + + if (!processesToRemove) + processesToRemove = PhCreateList(2); + + PhAddItemList(processesToRemove, processItem); + } + } + } + + // Lock only if we have something to do. + if (processesToRemove) + { + PhAcquireQueuedLockExclusive(&PhProcessHashSetLock); + + for (i = 0; i < processesToRemove->Count; i++) + { + PhpRemoveProcessItem((PPH_PROCESS_ITEM)processesToRemove->Items[i]); + } + + PhReleaseQueuedLockExclusive(&PhProcessHashSetLock); + PhDereferenceObject(processesToRemove); + } + } + + // Go through the queued process query data. + PhFlushProcessQueryData(FALSE); + + if (sysTotalTime == 0) + sysTotalTime = -1; // max. value + if (sysTotalCycleTime == 0) + sysTotalCycleTime = -1; + + PhCpuTotalCycleDelta = sysTotalCycleTime; + + // Look for new processes and update existing ones. + process = PH_FIRST_PROCESS(processes); + + while (process) + { + PPH_PROCESS_ITEM processItem; + + processItem = PhpLookupProcessItem(process->UniqueProcessId); + + if (!processItem) + { + PPH_PROCESS_RECORD processRecord; + BOOLEAN isSuspended; + BOOLEAN isPartiallySuspended; + ULONG contextSwitches; + + // Create the process item and fill in basic information. + processItem = PhCreateProcessItem(process->UniqueProcessId); + PhpFillProcessItem(processItem, process); + processItem->SequenceNumber = PhTimeSequenceNumber; + + processRecord = PhpCreateProcessRecord(processItem); + PhpAddProcessRecord(processRecord); + processItem->Record = processRecord; + + // Open a handle to the process for later usage. + // + // Don't try to do this if the process has no threads. On Windows 8.1, processes without + // threads are probably reflected processes which will not terminate if we have a handle + // open. + if (process->NumberOfThreads != 0) + { + PhOpenProcess(&processItem->QueryHandle, PROCESS_QUERY_INFORMATION, processItem->ProcessId); + + if (WINDOWS_HAS_LIMITED_ACCESS && !processItem->QueryHandle) + PhOpenProcess(&processItem->QueryHandle, PROCESS_QUERY_LIMITED_INFORMATION, processItem->ProcessId); + } + + PhpGetProcessThreadInformation(process, &isSuspended, &isPartiallySuspended, &contextSwitches); + PhpUpdateDynamicInfoProcessItem(processItem, process); + + // Initialize the deltas. + PhUpdateDelta(&processItem->CpuKernelDelta, process->KernelTime.QuadPart); + PhUpdateDelta(&processItem->CpuUserDelta, process->UserTime.QuadPart); + PhUpdateDelta(&processItem->IoReadDelta, process->ReadTransferCount.QuadPart); + PhUpdateDelta(&processItem->IoWriteDelta, process->WriteTransferCount.QuadPart); + PhUpdateDelta(&processItem->IoOtherDelta, process->OtherTransferCount.QuadPart); + PhUpdateDelta(&processItem->IoReadCountDelta, process->ReadOperationCount.QuadPart); + PhUpdateDelta(&processItem->IoWriteCountDelta, process->WriteOperationCount.QuadPart); + PhUpdateDelta(&processItem->IoOtherCountDelta, process->OtherOperationCount.QuadPart); + PhUpdateDelta(&processItem->ContextSwitchesDelta, contextSwitches); + PhUpdateDelta(&processItem->PageFaultsDelta, process->PageFaultCount); + PhUpdateDelta(&processItem->CycleTimeDelta, process->CycleTime); + PhUpdateDelta(&processItem->PrivateBytesDelta, process->PagefileUsage); + + processItem->IsSuspended = isSuspended; + processItem->IsPartiallySuspended = isPartiallySuspended; + + // If this is the first run of the provider, queue the + // process query tasks. Otherwise, perform stage 1 + // processing now and queue stage 2 processing. + if (runCount > 0) + { + PH_PROCESS_QUERY_S1_DATA data; + + memset(&data, 0, sizeof(PH_PROCESS_QUERY_S1_DATA)); + data.Header.Stage = 1; + data.Header.ProcessItem = processItem; + PhpProcessQueryStage1(&data); + PhpFillProcessItemStage1(&data); + PhSetEvent(&processItem->Stage1Event); + } + else + { + PhpQueueProcessQueryStage1(processItem); + } + + // Add pending service items to the process item. + PhUpdateProcessItemServices(processItem); + + // Add the process item to the hashtable. + PhAcquireQueuedLockExclusive(&PhProcessHashSetLock); + PhpAddProcessItem(processItem); + PhReleaseQueuedLockExclusive(&PhProcessHashSetLock); + + // Raise the process added event. + PhInvokeCallback(&PhProcessAddedEvent, processItem); + processItem->AddedEventSent = TRUE; + + // (Ref: for the process item being in the hashtable.) + // Instead of referencing then dereferencing we simply don't do anything. + // Dereferenced in PhpRemoveProcessItem. + } + else + { + BOOLEAN modified = FALSE; + BOOLEAN isSuspended; + BOOLEAN isPartiallySuspended; + ULONG contextSwitches; + FLOAT newCpuUsage; + FLOAT kernelCpuUsage; + FLOAT userCpuUsage; + + PhpGetProcessThreadInformation(process, &isSuspended, &isPartiallySuspended, &contextSwitches); + PhpUpdateDynamicInfoProcessItem(processItem, process); + + // Update the deltas. + PhUpdateDelta(&processItem->CpuKernelDelta, process->KernelTime.QuadPart); + PhUpdateDelta(&processItem->CpuUserDelta, process->UserTime.QuadPart); + PhUpdateDelta(&processItem->IoReadDelta, process->ReadTransferCount.QuadPart); + PhUpdateDelta(&processItem->IoWriteDelta, process->WriteTransferCount.QuadPart); + PhUpdateDelta(&processItem->IoOtherDelta, process->OtherTransferCount.QuadPart); + PhUpdateDelta(&processItem->IoReadCountDelta, process->ReadOperationCount.QuadPart); + PhUpdateDelta(&processItem->IoWriteCountDelta, process->WriteOperationCount.QuadPart); + PhUpdateDelta(&processItem->IoOtherCountDelta, process->OtherOperationCount.QuadPart); + PhUpdateDelta(&processItem->ContextSwitchesDelta, contextSwitches); + PhUpdateDelta(&processItem->PageFaultsDelta, process->PageFaultCount); + PhUpdateDelta(&processItem->CycleTimeDelta, process->CycleTime); + PhUpdateDelta(&processItem->PrivateBytesDelta, process->PagefileUsage); + + processItem->SequenceNumber++; + PhAddItemCircularBuffer_ULONG64(&processItem->IoReadHistory, processItem->IoReadDelta.Delta); + PhAddItemCircularBuffer_ULONG64(&processItem->IoWriteHistory, processItem->IoWriteDelta.Delta); + PhAddItemCircularBuffer_ULONG64(&processItem->IoOtherHistory, processItem->IoOtherDelta.Delta); + + PhAddItemCircularBuffer_SIZE_T(&processItem->PrivateBytesHistory, processItem->VmCounters.PagefileUsage); + //PhAddItemCircularBuffer_SIZE_T(&processItem->WorkingSetHistory, processItem->VmCounters.WorkingSetSize); + + if (InterlockedExchange(&processItem->JustProcessed, 0) != 0) + modified = TRUE; + + if (isCycleCpuUsageEnabled) + { + FLOAT totalDelta; + + newCpuUsage = (FLOAT)processItem->CycleTimeDelta.Delta / sysTotalCycleTime; + + // Calculate the kernel/user CPU usage based on the kernel/user time. If the kernel + // and user deltas are both zero, we'll just have to use an estimate. Currently, we + // split the CPU usage evenly across the kernel and user components, except when the + // total user time is zero, in which case we assign it all to the kernel component. + + totalDelta = (FLOAT)(processItem->CpuKernelDelta.Delta + processItem->CpuUserDelta.Delta); + + if (totalDelta != 0) + { + kernelCpuUsage = newCpuUsage * ((FLOAT)processItem->CpuKernelDelta.Delta / totalDelta); + userCpuUsage = newCpuUsage * ((FLOAT)processItem->CpuUserDelta.Delta / totalDelta); + } + else + { + if (processItem->UserTime.QuadPart != 0) + { + kernelCpuUsage = newCpuUsage / 2; + userCpuUsage = newCpuUsage / 2; + } + else + { + kernelCpuUsage = newCpuUsage; + userCpuUsage = 0; + } + } + } + else + { + kernelCpuUsage = (FLOAT)processItem->CpuKernelDelta.Delta / sysTotalTime; + userCpuUsage = (FLOAT)processItem->CpuUserDelta.Delta / sysTotalTime; + newCpuUsage = kernelCpuUsage + userCpuUsage; + } + + processItem->CpuUsage = newCpuUsage; + processItem->CpuKernelUsage = kernelCpuUsage; + processItem->CpuUserUsage = userCpuUsage; + + PhAddItemCircularBuffer_FLOAT(&processItem->CpuKernelHistory, kernelCpuUsage); + PhAddItemCircularBuffer_FLOAT(&processItem->CpuUserHistory, userCpuUsage); + + // Max. values + + if (processItem->ProcessId != NULL) + { + if (maxCpuValue < newCpuUsage) + { + maxCpuValue = newCpuUsage; + maxCpuProcessItem = processItem; + } + + // I/O for Other is not included because it is too generic. + if (maxIoValue < processItem->IoReadDelta.Delta + processItem->IoWriteDelta.Delta) + { + maxIoValue = processItem->IoReadDelta.Delta + processItem->IoWriteDelta.Delta; + maxIoProcessItem = processItem; + } + } + + // Debugged + if (processItem->QueryHandle) + { + BOOLEAN isBeingDebugged; + + if (NT_SUCCESS(PhGetProcessIsBeingDebugged( + processItem->QueryHandle, + &isBeingDebugged + )) && processItem->IsBeingDebugged != isBeingDebugged) + { + processItem->IsBeingDebugged = isBeingDebugged; + modified = TRUE; + } + } + + // Suspended + if (processItem->IsSuspended != isSuspended) + { + processItem->IsSuspended = isSuspended; + modified = TRUE; + } + + processItem->IsPartiallySuspended = isPartiallySuspended; + + // .NET + if (processItem->UpdateIsDotNet) + { + BOOLEAN isDotNet; + + if (NT_SUCCESS(PhGetProcessIsDotNet(processItem->ProcessId, &isDotNet))) + { + processItem->IsDotNet = isDotNet; + modified = TRUE; + } + + processItem->UpdateIsDotNet = FALSE; + } + + // Immersive + if (processItem->QueryHandle && IsImmersiveProcess_I) + { + BOOLEAN isImmersive; + + isImmersive = !!IsImmersiveProcess_I(processItem->QueryHandle); + + if (processItem->IsImmersive != isImmersive) + { + processItem->IsImmersive = isImmersive; + modified = TRUE; + } + } + + if (modified) + { + PhInvokeCallback(&PhProcessModifiedEvent, processItem); + } + + // No reference added by PhpLookupProcessItem. + } + + // Trick ourselves into thinking that the fake processes + // are on the list. + if (process == &PhInterruptsProcessInformation) + { + process = NULL; + } + else if (process == &PhDpcsProcessInformation) + { + process = &PhInterruptsProcessInformation; + } + else + { + process = PH_NEXT_PROCESS(process); + + if (process == NULL) + { + if (isCycleCpuUsageEnabled) + process = &PhInterruptsProcessInformation; + else + process = &PhDpcsProcessInformation; + } + } + } + + if (PhProcessInformation) + PhFree(PhProcessInformation); + + PhProcessInformation = processes; + + if (PhpTsProcesses) + { + WinStationFreeGAPMemory(0, PhpTsProcesses, PhpTsNumberOfProcesses); + PhpTsProcesses = NULL; + } + + PhpFlushSidFullNameCache(); + + // History cannot be updated on the first run because the deltas are invalid. For example, the + // I/O "deltas" will be huge because they are currently the raw accumulated values. + if (runCount != 0) + { + if (isCycleCpuUsageEnabled) + PhpUpdateCpuCycleUsageInformation(sysTotalCycleTime, sysIdleCycleTime); + + PhpUpdateSystemHistory(); + + // Note that we need to add a reference to the records of these processes, to make it + // possible for others to get the name of a max. CPU or I/O process. + + if (maxCpuProcessItem) + { + PhAddItemCircularBuffer_ULONG(&PhMaxCpuHistory, HandleToUlong(maxCpuProcessItem->ProcessId)); +#ifdef PH_RECORD_MAX_USAGE + PhAddItemCircularBuffer_FLOAT(&PhMaxCpuUsageHistory, maxCpuProcessItem->CpuUsage); +#endif + + if (!(maxCpuProcessItem->Record->Flags & PH_PROCESS_RECORD_STAT_REF)) + { + PhReferenceProcessRecord(maxCpuProcessItem->Record); + maxCpuProcessItem->Record->Flags |= PH_PROCESS_RECORD_STAT_REF; + } + } + else + { + PhAddItemCircularBuffer_ULONG(&PhMaxCpuHistory, PtrToUlong(NULL)); +#ifdef PH_RECORD_MAX_USAGE + PhAddItemCircularBuffer_FLOAT(&PhMaxCpuUsageHistory, 0); +#endif + } + + if (maxIoProcessItem) + { + PhAddItemCircularBuffer_ULONG(&PhMaxIoHistory, HandleToUlong(maxIoProcessItem->ProcessId)); +#ifdef PH_RECORD_MAX_USAGE + PhAddItemCircularBuffer_ULONG64(&PhMaxIoReadOtherHistory, + maxIoProcessItem->IoReadDelta.Delta + maxIoProcessItem->IoOtherDelta.Delta); + PhAddItemCircularBuffer_ULONG64(&PhMaxIoWriteHistory, maxIoProcessItem->IoWriteDelta.Delta); +#endif + + if (!(maxIoProcessItem->Record->Flags & PH_PROCESS_RECORD_STAT_REF)) + { + PhReferenceProcessRecord(maxIoProcessItem->Record); + maxIoProcessItem->Record->Flags |= PH_PROCESS_RECORD_STAT_REF; + } + } + else + { + PhAddItemCircularBuffer_ULONG(&PhMaxIoHistory, PtrToUlong(NULL)); +#ifdef PH_RECORD_MAX_USAGE + PhAddItemCircularBuffer_ULONG64(&PhMaxIoReadOtherHistory, 0); + PhAddItemCircularBuffer_ULONG64(&PhMaxIoWriteHistory, 0); +#endif + } + } + + PhInvokeCallback(&PhProcessesUpdatedEvent, NULL); + runCount++; +} + +PPH_PROCESS_RECORD PhpCreateProcessRecord( + _In_ PPH_PROCESS_ITEM ProcessItem + ) +{ + PPH_PROCESS_RECORD processRecord; + + processRecord = PhAllocate(sizeof(PH_PROCESS_RECORD)); + memset(processRecord, 0, sizeof(PH_PROCESS_RECORD)); + + InitializeListHead(&processRecord->ListEntry); + processRecord->RefCount = 1; + + processRecord->ProcessId = ProcessItem->ProcessId; + processRecord->ParentProcessId = ProcessItem->ParentProcessId; + processRecord->SessionId = ProcessItem->SessionId; + processRecord->CreateTime = ProcessItem->CreateTime; + + PhSetReference(&processRecord->ProcessName, ProcessItem->ProcessName); + PhSetReference(&processRecord->FileName, ProcessItem->FileName); + PhSetReference(&processRecord->CommandLine, ProcessItem->CommandLine); + //PhSetReference(&processRecord->UserName, ProcessItem->UserName); + + return processRecord; +} + +PPH_PROCESS_RECORD PhpSearchProcessRecordList( + _In_ PLARGE_INTEGER Time, + _Out_opt_ PULONG Index, + _Out_opt_ PULONG InsertIndex + ) +{ + PPH_PROCESS_RECORD processRecord; + LONG low; + LONG high; + LONG i; + BOOLEAN found = FALSE; + INT comparison; + + if (PhProcessRecordList->Count == 0) + { + if (Index) + *Index = 0; + if (InsertIndex) + *InsertIndex = 0; + + return NULL; + } + + low = 0; + high = PhProcessRecordList->Count - 1; + + // Do a binary search. + do + { + i = (low + high) / 2; + processRecord = (PPH_PROCESS_RECORD)PhProcessRecordList->Items[i]; + + comparison = uint64cmp(Time->QuadPart, processRecord->CreateTime.QuadPart); + + if (comparison == 0) + { + found = TRUE; + break; + } + else if (comparison < 0) + { + high = i - 1; + } + else + { + low = i + 1; + } + } while (low <= high); + + if (Index) + *Index = i; + + if (found) + { + return processRecord; + } + else + { + if (InsertIndex) + *InsertIndex = i + (comparison > 0); + + return NULL; + } +} + +VOID PhpAddProcessRecord( + _Inout_ PPH_PROCESS_RECORD ProcessRecord + ) +{ + PPH_PROCESS_RECORD processRecord; + ULONG insertIndex; + + PhAcquireQueuedLockExclusive(&PhProcessRecordListLock); + + processRecord = PhpSearchProcessRecordList(&ProcessRecord->CreateTime, NULL, &insertIndex); + + if (!processRecord) + { + // Insert the process record, keeping the list sorted. + PhInsertItemList(PhProcessRecordList, insertIndex, ProcessRecord); + } + else + { + // Link the process record with the existing one that we found. + InsertTailList(&processRecord->ListEntry, &ProcessRecord->ListEntry); + } + + PhReleaseQueuedLockExclusive(&PhProcessRecordListLock); +} + +VOID PhpRemoveProcessRecord( + _Inout_ PPH_PROCESS_RECORD ProcessRecord + ) +{ + ULONG i; + PPH_PROCESS_RECORD headProcessRecord; + + PhAcquireQueuedLockExclusive(&PhProcessRecordListLock); + + headProcessRecord = PhpSearchProcessRecordList(&ProcessRecord->CreateTime, &i, NULL); + assert(headProcessRecord); + + // Unlink the record from the list. + RemoveEntryList(&ProcessRecord->ListEntry); + + if (ProcessRecord == headProcessRecord) + { + // Remove the slot completely, or choose a new head record. + if (IsListEmpty(&headProcessRecord->ListEntry)) + PhRemoveItemList(PhProcessRecordList, i); + else + PhProcessRecordList->Items[i] = CONTAINING_RECORD(headProcessRecord->ListEntry.Flink, PH_PROCESS_RECORD, ListEntry); + } + + PhReleaseQueuedLockExclusive(&PhProcessRecordListLock); +} + +VOID PhReferenceProcessRecord( + _In_ PPH_PROCESS_RECORD ProcessRecord + ) +{ + _InterlockedIncrement(&ProcessRecord->RefCount); +} + +BOOLEAN PhReferenceProcessRecordSafe( + _In_ PPH_PROCESS_RECORD ProcessRecord + ) +{ + return _InterlockedIncrementNoZero(&ProcessRecord->RefCount); +} + +VOID PhReferenceProcessRecordForStatistics( + _In_ PPH_PROCESS_RECORD ProcessRecord + ) +{ + if (!(ProcessRecord->Flags & PH_PROCESS_RECORD_STAT_REF)) + { + PhReferenceProcessRecord(ProcessRecord); + ProcessRecord->Flags |= PH_PROCESS_RECORD_STAT_REF; + } +} + +VOID PhDereferenceProcessRecord( + _In_ PPH_PROCESS_RECORD ProcessRecord + ) +{ + if (_InterlockedDecrement(&ProcessRecord->RefCount) == 0) + { + PhpRemoveProcessRecord(ProcessRecord); + + PhDereferenceObject(ProcessRecord->ProcessName); + if (ProcessRecord->FileName) PhDereferenceObject(ProcessRecord->FileName); + if (ProcessRecord->CommandLine) PhDereferenceObject(ProcessRecord->CommandLine); + /*if (ProcessRecord->UserName) PhDereferenceObject(ProcessRecord->UserName);*/ + PhFree(ProcessRecord); + } +} + +PPH_PROCESS_RECORD PhpFindProcessRecord( + _In_ PPH_PROCESS_RECORD ProcessRecord, + _In_ HANDLE ProcessId + ) +{ + PPH_PROCESS_RECORD startProcessRecord; + + startProcessRecord = ProcessRecord; + + do + { + if (ProcessRecord->ProcessId == ProcessId) + return ProcessRecord; + + ProcessRecord = CONTAINING_RECORD(ProcessRecord->ListEntry.Flink, PH_PROCESS_RECORD, ListEntry); + } while (ProcessRecord != startProcessRecord); + + return NULL; +} + +/** + * Finds a process record. + * + * \param ProcessId The ID of the process. + * \param Time A time in which the process was active. + * + * \return The newest record older than \a Time, or NULL + * if the record could not be found. You must call + * PhDereferenceProcessRecord() when you no longer need + * the record. + */ +PPH_PROCESS_RECORD PhFindProcessRecord( + _In_opt_ HANDLE ProcessId, + _In_ PLARGE_INTEGER Time + ) +{ + PPH_PROCESS_RECORD processRecord; + ULONG i; + BOOLEAN found; + + if (PhProcessRecordList->Count == 0) + return NULL; + + PhAcquireQueuedLockShared(&PhProcessRecordListLock); + + processRecord = PhpSearchProcessRecordList(Time, &i, NULL); + + if (!processRecord) + { + // This is expected. Now we search backwards to find the newest matching element older than + // the given time. + + found = FALSE; + + while (TRUE) + { + processRecord = (PPH_PROCESS_RECORD)PhProcessRecordList->Items[i]; + + if (processRecord->CreateTime.QuadPart < Time->QuadPart) + { + if (ProcessId) + { + processRecord = PhpFindProcessRecord(processRecord, ProcessId); + + if (processRecord) + found = TRUE; + } + else + { + found = TRUE; + } + + if (found) + break; + } + + if (i == 0) + break; + + i--; + } + } + else + { + if (ProcessId) + { + processRecord = PhpFindProcessRecord(processRecord, ProcessId); + + if (processRecord) + found = TRUE; + else + found = FALSE; + } + else + { + found = TRUE; + } + } + + if (found) + { + // The record might have had its last reference just cleared but it hasn't been removed from + // the list yet. + if (!PhReferenceProcessRecordSafe(processRecord)) + found = FALSE; + } + + PhReleaseQueuedLockShared(&PhProcessRecordListLock); + + if (found) + return processRecord; + else + return NULL; +} + +/** + * Deletes unused process records. + */ +VOID PhPurgeProcessRecords( + VOID + ) +{ + PPH_PROCESS_RECORD processRecord; + PPH_PROCESS_RECORD startProcessRecord; + ULONG i; + LARGE_INTEGER threshold; + PPH_LIST derefList = NULL; + + if (PhProcessRecordList->Count == 0) + return; + + // Get the oldest statistics time. + PhGetStatisticsTime(NULL, PhTimeHistory.Count - 1, &threshold); + + PhAcquireQueuedLockShared(&PhProcessRecordListLock); + + for (i = 0; i < PhProcessRecordList->Count; i++) + { + processRecord = PhProcessRecordList->Items[i]; + startProcessRecord = processRecord; + + do + { + ULONG requiredFlags; + + requiredFlags = PH_PROCESS_RECORD_DEAD | PH_PROCESS_RECORD_STAT_REF; + + if ((processRecord->Flags & requiredFlags) == requiredFlags) + { + // Check if the process exit time is before the oldest statistics time. If so we can + // dereference the process record. + if (processRecord->ExitTime.QuadPart < threshold.QuadPart) + { + // Clear the stat ref bit; this is to make sure we don't try to dereference the + // record twice (e.g. if someone else currently holds a reference to the record + // and it doesn't get removed immediately). + processRecord->Flags &= ~PH_PROCESS_RECORD_STAT_REF; + + if (!derefList) + derefList = PhCreateList(2); + + PhAddItemList(derefList, processRecord); + } + } + + processRecord = CONTAINING_RECORD(processRecord->ListEntry.Flink, PH_PROCESS_RECORD, ListEntry); + } while (processRecord != startProcessRecord); + } + + PhReleaseQueuedLockShared(&PhProcessRecordListLock); + + if (derefList) + { + for (i = 0; i < derefList->Count; i++) + { + PhDereferenceProcessRecord(derefList->Items[i]); + } + + PhDereferenceObject(derefList); + } +} + +PPH_PROCESS_ITEM PhReferenceProcessItemForParent( + _In_ HANDLE ParentProcessId, + _In_ HANDLE ProcessId, + _In_ PLARGE_INTEGER CreateTime + ) +{ + PPH_PROCESS_ITEM processItem; + + if (ParentProcessId == ProcessId) // for cases where the parent PID = PID (e.g. System Idle Process) + return NULL; + + PhAcquireQueuedLockShared(&PhProcessHashSetLock); + + processItem = PhpLookupProcessItem(ParentProcessId); + + // We make sure that the process item we found is actually the parent process - its start time + // must not be larger than the supplied time. + if (processItem && processItem->CreateTime.QuadPart <= CreateTime->QuadPart) + PhReferenceObject(processItem); + else + processItem = NULL; + + PhReleaseQueuedLockShared(&PhProcessHashSetLock); + + return processItem; +} + +PPH_PROCESS_ITEM PhReferenceProcessItemForRecord( + _In_ PPH_PROCESS_RECORD Record + ) +{ + PPH_PROCESS_ITEM processItem; + + PhAcquireQueuedLockShared(&PhProcessHashSetLock); + + processItem = PhpLookupProcessItem(Record->ProcessId); + + if (processItem && processItem->CreateTime.QuadPart == Record->CreateTime.QuadPart) + PhReferenceObject(processItem); + else + processItem = NULL; + + PhReleaseQueuedLockShared(&PhProcessHashSetLock); + + return processItem; +} diff --git a/ProcessHacker/procrec.c b/ProcessHacker/procrec.c index 77d407ef28c9..486a3db8841c 100644 --- a/ProcessHacker/procrec.c +++ b/ProcessHacker/procrec.c @@ -1,262 +1,262 @@ -/* - * Process Hacker - - * process record properties - * - * Copyright (C) 2010 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include - -#include -#include - -typedef struct _PROCESS_RECORD_CONTEXT -{ - PPH_PROCESS_RECORD Record; - HICON FileIcon; -} PROCESS_RECORD_CONTEXT, *PPROCESS_RECORD_CONTEXT; - -INT_PTR CALLBACK PhpProcessRecordDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -VOID PhShowProcessRecordDialog( - _In_ HWND ParentWindowHandle, - _In_ PPH_PROCESS_RECORD Record - ) -{ - PROCESS_RECORD_CONTEXT context; - - context.Record = Record; - - DialogBoxParam( - PhInstanceHandle, - MAKEINTRESOURCE(IDD_PROCRECORD), - ParentWindowHandle, - PhpProcessRecordDlgProc, - (LPARAM)&context - ); -} - -PPH_STRING PhpaGetRelativeTimeString( - _In_ PLARGE_INTEGER Time - ) -{ - LARGE_INTEGER time; - LARGE_INTEGER currentTime; - SYSTEMTIME timeFields; - PPH_STRING timeRelativeString; - PPH_STRING timeString; - - time = *Time; - PhQuerySystemTime(¤tTime); - timeRelativeString = PH_AUTO(PhFormatTimeSpanRelative(currentTime.QuadPart - time.QuadPart)); - - PhLargeIntegerToLocalSystemTime(&timeFields, &time); - timeString = PhaFormatDateTime(&timeFields); - - return PhaFormatString(L"%s ago (%s)", timeRelativeString->Buffer, timeString->Buffer); -} - -FORCEINLINE PWSTR PhpGetStringOrNa( - _In_ PPH_STRING String - ) -{ - if (String) - return String->Buffer; - else - return L"N/A"; -} - -INT_PTR CALLBACK PhpProcessRecordDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - PPROCESS_RECORD_CONTEXT context = NULL; - - if (uMsg == WM_INITDIALOG) - { - context = (PPROCESS_RECORD_CONTEXT)lParam; - SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)context); - } - else - { - context = (PPROCESS_RECORD_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom()); - - if (uMsg == WM_DESTROY) - { - RemoveProp(hwndDlg, PhMakeContextAtom()); - } - } - - if (!context) - return FALSE; - - switch (uMsg) - { - case WM_INITDIALOG: - { - PH_IMAGE_VERSION_INFO versionInfo; - BOOLEAN versionInfoInitialized; - PPH_STRING processNameString; - PPH_PROCESS_ITEM processItem; - - if (!PH_IS_FAKE_PROCESS_ID(context->Record->ProcessId)) - { - processNameString = PhaFormatString(L"%s (%u)", - context->Record->ProcessName->Buffer, HandleToUlong(context->Record->ProcessId)); - } - else - { - processNameString = context->Record->ProcessName; - } - - PhCenterWindow(hwndDlg, GetParent(hwndDlg)); - SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hwndDlg, IDOK), TRUE); - SetWindowText(hwndDlg, processNameString->Buffer); - - SetDlgItemText(hwndDlg, IDC_PROCESSNAME, processNameString->Buffer); - - if (processItem = PhReferenceProcessItemForRecord(context->Record)) - { - PPH_PROCESS_ITEM parentProcess; - - if (parentProcess = PhReferenceProcessItemForParent( - processItem->ParentProcessId, - processItem->ProcessId, - &processItem->CreateTime - )) - { - CLIENT_ID clientId; - - clientId.UniqueProcess = parentProcess->ProcessId; - clientId.UniqueThread = NULL; - - SetDlgItemText(hwndDlg, IDC_PARENT, - PH_AUTO_T(PH_STRING, PhGetClientIdNameEx(&clientId, parentProcess->ProcessName))->Buffer); - - PhDereferenceObject(parentProcess); - } - else - { - SetDlgItemText(hwndDlg, IDC_PARENT, PhaFormatString(L"Non-existent process (%u)", - HandleToUlong(context->Record->ParentProcessId))->Buffer); - } - - PhDereferenceObject(processItem); - } - else - { - SetDlgItemText(hwndDlg, IDC_PARENT, PhaFormatString(L"Unknown process (%u)", - HandleToUlong(context->Record->ParentProcessId))->Buffer); - - EnableWindow(GetDlgItem(hwndDlg, IDC_PROPERTIES), FALSE); - } - - memset(&versionInfo, 0, sizeof(PH_IMAGE_VERSION_INFO)); - versionInfoInitialized = FALSE; - - if (context->Record->FileName) - { - if (PhInitializeImageVersionInfo(&versionInfo, context->Record->FileName->Buffer)) - versionInfoInitialized = TRUE; - } - - context->FileIcon = PhGetFileShellIcon(PhGetString(context->Record->FileName), L".exe", TRUE); - - SendMessage(GetDlgItem(hwndDlg, IDC_OPENFILENAME), BM_SETIMAGE, IMAGE_ICON, - (LPARAM)PH_LOAD_SHARED_ICON_SMALL(MAKEINTRESOURCE(IDI_FOLDER))); - SendMessage(GetDlgItem(hwndDlg, IDC_FILEICON), STM_SETICON, - (WPARAM)context->FileIcon, 0); - - SetDlgItemText(hwndDlg, IDC_NAME, PhpGetStringOrNa(versionInfo.FileDescription)); - SetDlgItemText(hwndDlg, IDC_COMPANYNAME, PhpGetStringOrNa(versionInfo.CompanyName)); - SetDlgItemText(hwndDlg, IDC_VERSION, PhpGetStringOrNa(versionInfo.FileVersion)); - SetDlgItemText(hwndDlg, IDC_FILENAME, PhpGetStringOrNa(context->Record->FileName)); - - if (versionInfoInitialized) - PhDeleteImageVersionInfo(&versionInfo); - - if (!context->Record->FileName) - EnableWindow(GetDlgItem(hwndDlg, IDC_OPENFILENAME), FALSE); - - SetDlgItemText(hwndDlg, IDC_CMDLINE, PhpGetStringOrNa(context->Record->CommandLine)); - - if (context->Record->CreateTime.QuadPart != 0) - SetDlgItemText(hwndDlg, IDC_STARTED, PhpaGetRelativeTimeString(&context->Record->CreateTime)->Buffer); - else - SetDlgItemText(hwndDlg, IDC_STARTED, L"N/A"); - - if (context->Record->ExitTime.QuadPart != 0) - SetDlgItemText(hwndDlg, IDC_TERMINATED, PhpaGetRelativeTimeString(&context->Record->ExitTime)->Buffer); - else - SetDlgItemText(hwndDlg, IDC_TERMINATED, L"N/A"); - - SetDlgItemInt(hwndDlg, IDC_SESSIONID, context->Record->SessionId, FALSE); - } - break; - case WM_DESTROY: - { - if (context->FileIcon) - DestroyIcon(context->FileIcon); - } - break; - case WM_COMMAND: - { - switch (LOWORD(wParam)) - { - case IDCANCEL: - case IDOK: - { - EndDialog(hwndDlg, IDOK); - } - break; - case IDC_OPENFILENAME: - { - if (context->Record->FileName) - PhShellExploreFile(hwndDlg, context->Record->FileName->Buffer); - } - break; - case IDC_PROPERTIES: - { - PPH_PROCESS_ITEM processItem; - - if (processItem = PhReferenceProcessItemForRecord(context->Record)) - { - ProcessHacker_ShowProcessProperties(PhMainWndHandle, processItem); - PhDereferenceObject(processItem); - } - else - { - PhShowError(hwndDlg, L"The process has already terminated; only the process record is available."); - } - } - break; - } - } - break; - } - - return FALSE; -} +/* + * Process Hacker - + * process record properties + * + * Copyright (C) 2010 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include + +#include +#include + +typedef struct _PROCESS_RECORD_CONTEXT +{ + PPH_PROCESS_RECORD Record; + HICON FileIcon; +} PROCESS_RECORD_CONTEXT, *PPROCESS_RECORD_CONTEXT; + +INT_PTR CALLBACK PhpProcessRecordDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +VOID PhShowProcessRecordDialog( + _In_ HWND ParentWindowHandle, + _In_ PPH_PROCESS_RECORD Record + ) +{ + PROCESS_RECORD_CONTEXT context; + + context.Record = Record; + + DialogBoxParam( + PhInstanceHandle, + MAKEINTRESOURCE(IDD_PROCRECORD), + ParentWindowHandle, + PhpProcessRecordDlgProc, + (LPARAM)&context + ); +} + +PPH_STRING PhpaGetRelativeTimeString( + _In_ PLARGE_INTEGER Time + ) +{ + LARGE_INTEGER time; + LARGE_INTEGER currentTime; + SYSTEMTIME timeFields; + PPH_STRING timeRelativeString; + PPH_STRING timeString; + + time = *Time; + PhQuerySystemTime(¤tTime); + timeRelativeString = PH_AUTO(PhFormatTimeSpanRelative(currentTime.QuadPart - time.QuadPart)); + + PhLargeIntegerToLocalSystemTime(&timeFields, &time); + timeString = PhaFormatDateTime(&timeFields); + + return PhaFormatString(L"%s ago (%s)", timeRelativeString->Buffer, timeString->Buffer); +} + +FORCEINLINE PWSTR PhpGetStringOrNa( + _In_ PPH_STRING String + ) +{ + if (String) + return String->Buffer; + else + return L"N/A"; +} + +INT_PTR CALLBACK PhpProcessRecordDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + PPROCESS_RECORD_CONTEXT context = NULL; + + if (uMsg == WM_INITDIALOG) + { + context = (PPROCESS_RECORD_CONTEXT)lParam; + SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)context); + } + else + { + context = (PPROCESS_RECORD_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom()); + + if (uMsg == WM_DESTROY) + { + RemoveProp(hwndDlg, PhMakeContextAtom()); + } + } + + if (!context) + return FALSE; + + switch (uMsg) + { + case WM_INITDIALOG: + { + PH_IMAGE_VERSION_INFO versionInfo; + BOOLEAN versionInfoInitialized; + PPH_STRING processNameString; + PPH_PROCESS_ITEM processItem; + + if (!PH_IS_FAKE_PROCESS_ID(context->Record->ProcessId)) + { + processNameString = PhaFormatString(L"%s (%u)", + context->Record->ProcessName->Buffer, HandleToUlong(context->Record->ProcessId)); + } + else + { + processNameString = context->Record->ProcessName; + } + + PhCenterWindow(hwndDlg, GetParent(hwndDlg)); + SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hwndDlg, IDOK), TRUE); + SetWindowText(hwndDlg, processNameString->Buffer); + + SetDlgItemText(hwndDlg, IDC_PROCESSNAME, processNameString->Buffer); + + if (processItem = PhReferenceProcessItemForRecord(context->Record)) + { + PPH_PROCESS_ITEM parentProcess; + + if (parentProcess = PhReferenceProcessItemForParent( + processItem->ParentProcessId, + processItem->ProcessId, + &processItem->CreateTime + )) + { + CLIENT_ID clientId; + + clientId.UniqueProcess = parentProcess->ProcessId; + clientId.UniqueThread = NULL; + + SetDlgItemText(hwndDlg, IDC_PARENT, + PH_AUTO_T(PH_STRING, PhGetClientIdNameEx(&clientId, parentProcess->ProcessName))->Buffer); + + PhDereferenceObject(parentProcess); + } + else + { + SetDlgItemText(hwndDlg, IDC_PARENT, PhaFormatString(L"Non-existent process (%u)", + HandleToUlong(context->Record->ParentProcessId))->Buffer); + } + + PhDereferenceObject(processItem); + } + else + { + SetDlgItemText(hwndDlg, IDC_PARENT, PhaFormatString(L"Unknown process (%u)", + HandleToUlong(context->Record->ParentProcessId))->Buffer); + + EnableWindow(GetDlgItem(hwndDlg, IDC_PROPERTIES), FALSE); + } + + memset(&versionInfo, 0, sizeof(PH_IMAGE_VERSION_INFO)); + versionInfoInitialized = FALSE; + + if (context->Record->FileName) + { + if (PhInitializeImageVersionInfo(&versionInfo, context->Record->FileName->Buffer)) + versionInfoInitialized = TRUE; + } + + context->FileIcon = PhGetFileShellIcon(PhGetString(context->Record->FileName), L".exe", TRUE); + + SendMessage(GetDlgItem(hwndDlg, IDC_OPENFILENAME), BM_SETIMAGE, IMAGE_ICON, + (LPARAM)PH_LOAD_SHARED_ICON_SMALL(MAKEINTRESOURCE(IDI_FOLDER))); + SendMessage(GetDlgItem(hwndDlg, IDC_FILEICON), STM_SETICON, + (WPARAM)context->FileIcon, 0); + + SetDlgItemText(hwndDlg, IDC_NAME, PhpGetStringOrNa(versionInfo.FileDescription)); + SetDlgItemText(hwndDlg, IDC_COMPANYNAME, PhpGetStringOrNa(versionInfo.CompanyName)); + SetDlgItemText(hwndDlg, IDC_VERSION, PhpGetStringOrNa(versionInfo.FileVersion)); + SetDlgItemText(hwndDlg, IDC_FILENAME, PhpGetStringOrNa(context->Record->FileName)); + + if (versionInfoInitialized) + PhDeleteImageVersionInfo(&versionInfo); + + if (!context->Record->FileName) + EnableWindow(GetDlgItem(hwndDlg, IDC_OPENFILENAME), FALSE); + + SetDlgItemText(hwndDlg, IDC_CMDLINE, PhpGetStringOrNa(context->Record->CommandLine)); + + if (context->Record->CreateTime.QuadPart != 0) + SetDlgItemText(hwndDlg, IDC_STARTED, PhpaGetRelativeTimeString(&context->Record->CreateTime)->Buffer); + else + SetDlgItemText(hwndDlg, IDC_STARTED, L"N/A"); + + if (context->Record->ExitTime.QuadPart != 0) + SetDlgItemText(hwndDlg, IDC_TERMINATED, PhpaGetRelativeTimeString(&context->Record->ExitTime)->Buffer); + else + SetDlgItemText(hwndDlg, IDC_TERMINATED, L"N/A"); + + SetDlgItemInt(hwndDlg, IDC_SESSIONID, context->Record->SessionId, FALSE); + } + break; + case WM_DESTROY: + { + if (context->FileIcon) + DestroyIcon(context->FileIcon); + } + break; + case WM_COMMAND: + { + switch (LOWORD(wParam)) + { + case IDCANCEL: + case IDOK: + { + EndDialog(hwndDlg, IDOK); + } + break; + case IDC_OPENFILENAME: + { + if (context->Record->FileName) + PhShellExploreFile(hwndDlg, context->Record->FileName->Buffer); + } + break; + case IDC_PROPERTIES: + { + PPH_PROCESS_ITEM processItem; + + if (processItem = PhReferenceProcessItemForRecord(context->Record)) + { + ProcessHacker_ShowProcessProperties(PhMainWndHandle, processItem); + PhDereferenceObject(processItem); + } + else + { + PhShowError(hwndDlg, L"The process has already terminated; only the process record is available."); + } + } + break; + } + } + break; + } + + return FALSE; +} diff --git a/ProcessHacker/proctree.c b/ProcessHacker/proctree.c index 0bd39228551e..9cdd693494ed 100644 --- a/ProcessHacker/proctree.c +++ b/ProcessHacker/proctree.c @@ -1,3508 +1,3508 @@ -/* - * Process Hacker - - * process tree list - * - * Copyright (C) 2010-2016 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -/* - * The process tree list manages a list of tree nodes and handles callback events generated by the - * underlying treenew control. Retrieval of certain types of process information is also performed - * here, on the GUI thread (see PH_PROCESS_NODE.ValidMask). This is done for columns that require - * data not supplied by the process provider. - */ - -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -typedef enum _PHP_AGGREGATE_TYPE -{ - AggregateTypeFloat, - AggregateTypeInt32, - AggregateTypeInt64, - AggregateTypeIntPtr -} PHP_AGGREGATE_TYPE; - -typedef enum _PHP_AGGREGATE_LOCATION -{ - AggregateLocationProcessNode, - AggregateLocationProcessItem -} PHP_AGGREGATE_LOCATION; - -VOID PhpRemoveProcessNode( - _In_ PPH_PROCESS_NODE ProcessNode - ); - -VOID PhpUpdateNeedCyclesInformation( - VOID - ); - -VOID PhpUpdateProcessNodeCycles( - _Inout_ PPH_PROCESS_NODE ProcessNode - ); - -LONG PhpProcessTreeNewPostSortFunction( - _In_ LONG Result, - _In_ PVOID Node1, - _In_ PVOID Node2, - _In_ PH_SORT_ORDER SortOrder - ); - -BOOLEAN NTAPI PhpProcessTreeNewCallback( - _In_ HWND hwnd, - _In_ PH_TREENEW_MESSAGE Message, - _In_opt_ PVOID Parameter1, - _In_opt_ PVOID Parameter2, - _In_opt_ PVOID Context - ); - -static HWND ProcessTreeListHandle; -static ULONG ProcessTreeListSortColumn; -static PH_SORT_ORDER ProcessTreeListSortOrder; -static PH_CM_MANAGER ProcessTreeListCm; - -static PPH_HASH_ENTRY ProcessNodeHashSet[256] = PH_HASH_SET_INIT; // hashtable of all nodes -static PPH_LIST ProcessNodeList; // list of all nodes, used when sorting is enabled -static PPH_LIST ProcessNodeRootList; // list of root nodes - -BOOLEAN PhProcessTreeListStateHighlighting = TRUE; -static PPH_POINTER_LIST ProcessNodeStateList = NULL; // list of nodes which need to be processed - -static PH_TN_FILTER_SUPPORT FilterSupport; -static BOOLEAN NeedCyclesInformation = FALSE; - -static HDC GraphContext = NULL; -static ULONG GraphContextWidth = 0; -static ULONG GraphContextHeight = 0; -static HBITMAP GraphOldBitmap; -static HBITMAP GraphBitmap = NULL; -static PVOID GraphBits = NULL; - -VOID PhProcessTreeListInitialization( - VOID - ) -{ - ProcessNodeList = PhCreateList(40); - ProcessNodeRootList = PhCreateList(10); -} - -VOID PhInitializeProcessTreeList( - _In_ HWND hwnd - ) -{ - ProcessTreeListHandle = hwnd; - PhSetControlTheme(ProcessTreeListHandle, L"explorer"); - TreeNew_SetExtendedFlags(hwnd, TN_FLAG_ITEM_DRAG_SELECT, TN_FLAG_ITEM_DRAG_SELECT); - SendMessage(TreeNew_GetTooltips(ProcessTreeListHandle), TTM_SETDELAYTIME, TTDT_AUTOPOP, MAXSHORT); - - TreeNew_SetCallback(hwnd, PhpProcessTreeNewCallback, NULL); - - TreeNew_SetMaxId(hwnd, PHPRTLC_MAXIMUM - 1); - - TreeNew_SetRedraw(hwnd, FALSE); - - // Default columns - PhAddTreeNewColumn(hwnd, PHPRTLC_NAME, TRUE, L"Name", 200, PH_ALIGN_LEFT, -2, 0); - PhAddTreeNewColumn(hwnd, PHPRTLC_PID, TRUE, L"PID", 50, PH_ALIGN_RIGHT, 0, DT_RIGHT); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_CPU, TRUE, L"CPU", 45, PH_ALIGN_RIGHT, 1, DT_RIGHT, TRUE); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_IOTOTALRATE, TRUE, L"I/O total rate", 70, PH_ALIGN_RIGHT, 2, DT_RIGHT, TRUE); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_PRIVATEBYTES, TRUE, L"Private bytes", 70, PH_ALIGN_RIGHT, 3, DT_RIGHT, TRUE); - PhAddTreeNewColumn(hwnd, PHPRTLC_USERNAME, TRUE, L"User name", 140, PH_ALIGN_LEFT, 4, DT_PATH_ELLIPSIS); - PhAddTreeNewColumn(hwnd, PHPRTLC_DESCRIPTION, TRUE, L"Description", 180, PH_ALIGN_LEFT, 5, 0); - - // Customizable columns (1) - PhAddTreeNewColumn(hwnd, PHPRTLC_COMPANYNAME, FALSE, L"Company name", 180, PH_ALIGN_LEFT, -1, 0); - PhAddTreeNewColumn(hwnd, PHPRTLC_VERSION, FALSE, L"Version", 100, PH_ALIGN_LEFT, -1, 0); - PhAddTreeNewColumn(hwnd, PHPRTLC_FILENAME, FALSE, L"File name", 180, PH_ALIGN_LEFT, -1, DT_PATH_ELLIPSIS); - PhAddTreeNewColumn(hwnd, PHPRTLC_COMMANDLINE, FALSE, L"Command line", 180, PH_ALIGN_LEFT, -1, 0); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_PEAKPRIVATEBYTES, FALSE, L"Peak private bytes", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_WORKINGSET, FALSE, L"Working set", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_PEAKWORKINGSET, FALSE, L"Peak working set", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_PRIVATEWS, FALSE, L"Private WS", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_SHAREDWS, FALSE, L"Shared WS", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_SHAREABLEWS, FALSE, L"Shareable WS", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_VIRTUALSIZE, FALSE, L"Virtual size", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_PEAKVIRTUALSIZE, FALSE, L"Peak virtual size", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_PAGEFAULTS, FALSE, L"Page faults", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); - PhAddTreeNewColumn(hwnd, PHPRTLC_SESSIONID, FALSE, L"Session ID", 45, PH_ALIGN_RIGHT, -1, DT_RIGHT); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_PRIORITYCLASS, FALSE, L"Priority class", 100, PH_ALIGN_LEFT, -1, 0, TRUE); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_BASEPRIORITY, FALSE, L"Base priority", 45, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); - - // Customizable columns (2) - PhAddTreeNewColumnEx(hwnd, PHPRTLC_THREADS, FALSE, L"Threads", 45, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_HANDLES, FALSE, L"Handles", 45, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_GDIHANDLES, FALSE, L"GDI handles", 45, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_USERHANDLES, FALSE, L"USER handles", 45, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_IORORATE, FALSE, L"I/O read+other rate", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_IOWRATE, FALSE, L"I/O write rate", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); - PhAddTreeNewColumn(hwnd, PHPRTLC_INTEGRITY, FALSE, L"Integrity", 100, PH_ALIGN_LEFT, -1, 0); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_IOPRIORITY, FALSE, L"I/O priority", 70, PH_ALIGN_LEFT, -1, 0, TRUE); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_PAGEPRIORITY, FALSE, L"Page priority", 45, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_STARTTIME, FALSE, L"Start time", 100, PH_ALIGN_LEFT, -1, 0, TRUE); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_TOTALCPUTIME, FALSE, L"Total CPU time", 90, PH_ALIGN_LEFT, -1, 0, TRUE); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_KERNELCPUTIME, FALSE, L"Kernel CPU time", 90, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_USERCPUTIME, FALSE, L"User CPU time", 90, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); - PhAddTreeNewColumn(hwnd, PHPRTLC_VERIFICATIONSTATUS, FALSE, L"Verification status", 70, PH_ALIGN_LEFT, -1, 0); - PhAddTreeNewColumn(hwnd, PHPRTLC_VERIFIEDSIGNER, FALSE, L"Verified signer", 100, PH_ALIGN_LEFT, -1, 0); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_ASLR, FALSE, L"ASLR", 50, PH_ALIGN_LEFT, -1, 0, TRUE); - PhAddTreeNewColumn(hwnd, PHPRTLC_RELATIVESTARTTIME, FALSE, L"Relative start time", 180, PH_ALIGN_LEFT, -1, 0); - PhAddTreeNewColumn(hwnd, PHPRTLC_BITS, FALSE, L"Bits", 50, PH_ALIGN_LEFT, -1, 0); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_ELEVATION, FALSE, L"Elevation", 60, PH_ALIGN_LEFT, -1, 0, TRUE); - PhAddTreeNewColumn(hwnd, PHPRTLC_WINDOWTITLE, FALSE, L"Window title", 120, PH_ALIGN_LEFT, -1, 0); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_WINDOWSTATUS, FALSE, L"Window status", 60, PH_ALIGN_LEFT, -1, 0, TRUE); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_CYCLES, FALSE, L"Cycles", 110, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_CYCLESDELTA, FALSE, L"Cycles delta", 90, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); - PhAddTreeNewColumnEx2(hwnd, PHPRTLC_CPUHISTORY, FALSE, L"CPU history", 100, PH_ALIGN_LEFT, -1, 0, TN_COLUMN_FLAG_CUSTOMDRAW | TN_COLUMN_FLAG_SORTDESCENDING); - PhAddTreeNewColumnEx2(hwnd, PHPRTLC_PRIVATEBYTESHISTORY, FALSE, L"Private bytes history", 100, PH_ALIGN_LEFT, -1, 0, TN_COLUMN_FLAG_CUSTOMDRAW | TN_COLUMN_FLAG_SORTDESCENDING); - PhAddTreeNewColumnEx2(hwnd, PHPRTLC_IOHISTORY, FALSE, L"I/O history", 100, PH_ALIGN_LEFT, -1, 0, TN_COLUMN_FLAG_CUSTOMDRAW | TN_COLUMN_FLAG_SORTDESCENDING); - PhAddTreeNewColumn(hwnd, PHPRTLC_DEP, FALSE, L"DEP", 100, PH_ALIGN_LEFT, -1, 0); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_VIRTUALIZED, FALSE, L"Virtualized", 80, PH_ALIGN_LEFT, -1, 0, TRUE); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_CONTEXTSWITCHES, FALSE, L"Context switches", 100, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_CONTEXTSWITCHESDELTA, FALSE, L"Context switches delta", 80, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_PAGEFAULTSDELTA, FALSE, L"Page faults delta", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); - - // I/O group columns - PhAddTreeNewColumnEx(hwnd, PHPRTLC_IOREADS, FALSE, L"I/O reads", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_IOWRITES, FALSE, L"I/O writes", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_IOOTHER, FALSE, L"I/O other", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_IOREADBYTES, FALSE, L"I/O read bytes", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_IOWRITEBYTES, FALSE, L"I/O write bytes", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_IOOTHERBYTES, FALSE, L"I/O other bytes", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_IOREADSDELTA, FALSE, L"I/O reads delta", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_IOWRITESDELTA, FALSE, L"I/O writes delta", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_IOOTHERDELTA, FALSE, L"I/O other delta", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); - - // Customizable columns (3) - PhAddTreeNewColumn(hwnd, PHPRTLC_OSCONTEXT, FALSE, L"OS context", 100, PH_ALIGN_LEFT, -1, 0); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_PAGEDPOOL, FALSE, L"Paged pool", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_PEAKPAGEDPOOL, FALSE, L"Peak paged pool", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_NONPAGEDPOOL, FALSE, L"Non-paged pool", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_PEAKNONPAGEDPOOL, FALSE, L"Peak non-paged pool", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_MINIMUMWORKINGSET, FALSE, L"Minimum working set", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_MAXIMUMWORKINGSET, FALSE, L"Maximum working set", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_PRIVATEBYTESDELTA, FALSE, L"Private bytes delta", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); - PhAddTreeNewColumn(hwnd, PHPRTLC_SUBSYSTEM, FALSE, L"Subsystem", 110, PH_ALIGN_LEFT, -1, 0); - PhAddTreeNewColumn(hwnd, PHPRTLC_PACKAGENAME, FALSE, L"Package name", 160, PH_ALIGN_LEFT, -1, 0); - PhAddTreeNewColumn(hwnd, PHPRTLC_APPID, FALSE, L"App ID", 160, PH_ALIGN_LEFT, -1, 0); - PhAddTreeNewColumn(hwnd, PHPRTLC_DPIAWARENESS, FALSE, L"DPI awareness", 110, PH_ALIGN_LEFT, -1, 0); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_CFGUARD, FALSE, L"CF Guard", 70, PH_ALIGN_LEFT, -1, 0, TRUE); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_TIMESTAMP, FALSE, L"Time stamp", 140, PH_ALIGN_LEFT, -1, 0, TRUE); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_FILEMODIFIEDTIME, FALSE, L"File modified time", 140, PH_ALIGN_LEFT, -1, 0, TRUE); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_FILESIZE, FALSE, L"File size", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); - - TreeNew_SetRedraw(hwnd, TRUE); - - TreeNew_SetTriState(hwnd, TRUE); - TreeNew_SetSort(hwnd, 0, NoSortOrder); - - PhCmInitializeManager(&ProcessTreeListCm, hwnd, PHPRTLC_MAXIMUM, PhpProcessTreeNewPostSortFunction); - - if (PhPluginsEnabled) - { - PH_PLUGIN_TREENEW_INFORMATION treeNewInfo; - - treeNewInfo.TreeNewHandle = hwnd; - treeNewInfo.CmData = &ProcessTreeListCm; - PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackProcessTreeNewInitializing), &treeNewInfo); - } - - PhInitializeTreeNewFilterSupport(&FilterSupport, hwnd, ProcessNodeList); -} - -VOID PhLoadSettingsProcessTreeList( - VOID - ) -{ - PPH_STRING settings; - PPH_STRING sortSettings; - - settings = PhGetStringSetting(L"ProcessTreeListColumns"); - sortSettings = PhGetStringSetting(L"ProcessTreeListSort"); - PhCmLoadSettingsEx(ProcessTreeListHandle, &ProcessTreeListCm, 0, &settings->sr, &sortSettings->sr); - PhDereferenceObject(settings); - PhDereferenceObject(sortSettings); - - if (PhGetIntegerSetting(L"EnableInstantTooltips")) - { - SendMessage(TreeNew_GetTooltips(ProcessTreeListHandle), TTM_SETDELAYTIME, TTDT_INITIAL, 0); - } - - PhpUpdateNeedCyclesInformation(); -} - -VOID PhSaveSettingsProcessTreeList( - VOID - ) -{ - PPH_STRING settings; - PPH_STRING sortSettings; - - settings = PhCmSaveSettingsEx(ProcessTreeListHandle, &ProcessTreeListCm, 0, &sortSettings); - PhSetStringSetting2(L"ProcessTreeListColumns", &settings->sr); - PhSetStringSetting2(L"ProcessTreeListSort", &sortSettings->sr); - PhDereferenceObject(settings); - PhDereferenceObject(sortSettings); -} - -VOID PhReloadSettingsProcessTreeList( - VOID - ) -{ - SendMessage(TreeNew_GetTooltips(ProcessTreeListHandle), TTM_SETDELAYTIME, TTDT_INITIAL, - PhGetIntegerSetting(L"EnableInstantTooltips") ? 0 : -1); -} - -struct _PH_TN_FILTER_SUPPORT *PhGetFilterSupportProcessTreeList( - VOID - ) -{ - return &FilterSupport; -} - -FORCEINLINE BOOLEAN PhCompareProcessNode( - _In_ PPH_PROCESS_NODE Value1, - _In_ PPH_PROCESS_NODE Value2 - ) -{ - return Value1->ProcessId == Value2->ProcessId; -} - -FORCEINLINE ULONG PhHashProcessNode( - _In_ PPH_PROCESS_NODE Value - ) -{ - return HandleToUlong(Value->ProcessId) / 4; -} - -FORCEINLINE BOOLEAN PhpValidateParentCreateTime( - _In_ PPH_PROCESS_NODE Child, - _In_ PPH_PROCESS_NODE Parent - ) -{ - return - PH_IS_FAKE_PROCESS_ID(Child->ProcessId) || - Parent->ProcessItem->CreateTime.QuadPart <= Child->ProcessItem->CreateTime.QuadPart; -} - -PPH_PROCESS_NODE PhAddProcessNode( - _In_ PPH_PROCESS_ITEM ProcessItem, - _In_ ULONG RunId - ) -{ - PPH_PROCESS_NODE processNode; - PPH_PROCESS_NODE parentNode; - ULONG i; - - processNode = PhAllocate(PhEmGetObjectSize(EmProcessNodeType, sizeof(PH_PROCESS_NODE))); - memset(processNode, 0, sizeof(PH_PROCESS_NODE)); - PhInitializeTreeNewNode(&processNode->Node); - - if (PhProcessTreeListStateHighlighting && RunId != 1) - { - PhChangeShStateTn( - &processNode->Node, - &processNode->ShState, - &ProcessNodeStateList, - NewItemState, - PhCsColorNew, - NULL - ); - } - - processNode->ProcessId = ProcessItem->ProcessId; - processNode->ProcessItem = ProcessItem; - PhReferenceObject(ProcessItem); - - memset(processNode->TextCache, 0, sizeof(PH_STRINGREF) * PHPRTLC_MAXIMUM); - processNode->Node.TextCache = processNode->TextCache; - processNode->Node.TextCacheSize = PHPRTLC_MAXIMUM; - - processNode->Children = PhCreateList(1); - - // Find this process' parent and add the process to it if we found it. - if ( - (parentNode = PhFindProcessNode(ProcessItem->ParentProcessId)) && - PhpValidateParentCreateTime(processNode, parentNode) - ) - { - PhAddItemList(parentNode->Children, processNode); - processNode->Parent = parentNode; - } - else - { - // No parent, add to root list. - processNode->Parent = NULL; - PhAddItemList(ProcessNodeRootList, processNode); - } - - // Find this process' children and move them to this node. - - for (i = 0; i < ProcessNodeRootList->Count; i++) - { - PPH_PROCESS_NODE node = ProcessNodeRootList->Items[i]; - - if ( - node != processNode && // for cases where the parent PID = PID (e.g. System Idle Process) - node->ProcessItem->ParentProcessId == ProcessItem->ProcessId && - PhpValidateParentCreateTime(node, processNode) - ) - { - node->Parent = processNode; - PhAddItemList(processNode->Children, node); - } - } - - for (i = 0; i < processNode->Children->Count; i++) - { - PhRemoveItemList( - ProcessNodeRootList, - PhFindItemList(ProcessNodeRootList, processNode->Children->Items[i]) - ); - } - - PhAddEntryHashSet( - ProcessNodeHashSet, - PH_HASH_SET_SIZE(ProcessNodeHashSet), - &processNode->HashEntry, - PhHashProcessNode(processNode) - ); - PhAddItemList(ProcessNodeList, processNode); - - if (PhCsCollapseServicesOnStart) - { - static PH_STRINGREF servicesBaseName = PH_STRINGREF_INIT(L"\\services.exe"); - static BOOLEAN servicesFound = FALSE; - static PPH_STRING servicesFileName = NULL; - - if (!servicesFound) - { - if (!servicesFileName) - { - PPH_STRING systemDirectory; - - systemDirectory = PhGetSystemDirectory(); - servicesFileName = PhConcatStringRef2(&systemDirectory->sr, &servicesBaseName); - PhDereferenceObject(systemDirectory); - } - - // If this process is services.exe, collapse the node and free the string. - if ( - ProcessItem->FileName && - PhEqualString(ProcessItem->FileName, servicesFileName, TRUE) - ) - { - processNode->Node.Expanded = FALSE; - PhDereferenceObject(servicesFileName); - servicesFileName = NULL; - servicesFound = TRUE; - } - } - } - - if (WindowsVersion >= WINDOWS_7 && PhEnableCycleCpuUsage && ProcessItem->ProcessId == INTERRUPTS_PROCESS_ID) - PhInitializeStringRef(&processNode->DescriptionText, L"Interrupts and DPCs"); - - if (FilterSupport.FilterList) - processNode->Node.Visible = PhApplyTreeNewFiltersToNode(&FilterSupport, &processNode->Node); - - PhEmCallObjectOperation(EmProcessNodeType, processNode, EmObjectCreate); - - TreeNew_NodesStructured(ProcessTreeListHandle); - - return processNode; -} - -PPH_PROCESS_NODE PhFindProcessNode( - _In_ HANDLE ProcessId - ) -{ - PH_PROCESS_NODE lookupNode; - PPH_HASH_ENTRY entry; - PPH_PROCESS_NODE node; - - lookupNode.ProcessId = ProcessId; - entry = PhFindEntryHashSet( - ProcessNodeHashSet, - PH_HASH_SET_SIZE(ProcessNodeHashSet), - PhHashProcessNode(&lookupNode) - ); - - for (; entry; entry = entry->Next) - { - node = CONTAINING_RECORD(entry, PH_PROCESS_NODE, HashEntry); - - if (PhCompareProcessNode(&lookupNode, node)) - return node; - } - - return NULL; -} - -VOID PhRemoveProcessNode( - _In_ PPH_PROCESS_NODE ProcessNode - ) -{ - // Remove from the hashtable here to avoid problems in case the key is re-used. - PhRemoveEntryHashSet(ProcessNodeHashSet, PH_HASH_SET_SIZE(ProcessNodeHashSet), &ProcessNode->HashEntry); - - if (PhProcessTreeListStateHighlighting) - { - PhChangeShStateTn( - &ProcessNode->Node, - &ProcessNode->ShState, - &ProcessNodeStateList, - RemovingItemState, - PhCsColorRemoved, - ProcessTreeListHandle - ); - } - else - { - PhpRemoveProcessNode(ProcessNode); - } -} - -VOID PhpRemoveProcessNode( - _In_ PPH_PROCESS_NODE ProcessNode - ) -{ - ULONG index; - ULONG i; - - PhEmCallObjectOperation(EmProcessNodeType, ProcessNode, EmObjectDelete); - - if (ProcessNode->Parent) - { - // Remove the node from its parent. - - if ((index = PhFindItemList(ProcessNode->Parent->Children, ProcessNode)) != -1) - PhRemoveItemList(ProcessNode->Parent->Children, index); - } - else - { - // Remove the node from the root list. - - if ((index = PhFindItemList(ProcessNodeRootList, ProcessNode)) != -1) - PhRemoveItemList(ProcessNodeRootList, index); - } - - // Move the node's children to the root list. - for (i = 0; i < ProcessNode->Children->Count; i++) - { - PPH_PROCESS_NODE node = ProcessNode->Children->Items[i]; - - node->Parent = NULL; - PhAddItemList(ProcessNodeRootList, node); - } - - // Remove from list and cleanup. - - if ((index = PhFindItemList(ProcessNodeList, ProcessNode)) != -1) - PhRemoveItemList(ProcessNodeList, index); - - PhDereferenceObject(ProcessNode->Children); - - PhClearReference(&ProcessNode->WindowText); - PhClearReference(&ProcessNode->AppIdText); - - PhClearReference(&ProcessNode->TooltipText); - - PhClearReference(&ProcessNode->IoTotalRateText); - PhClearReference(&ProcessNode->PrivateBytesText); - PhClearReference(&ProcessNode->PeakPrivateBytesText); - PhClearReference(&ProcessNode->WorkingSetText); - PhClearReference(&ProcessNode->PeakWorkingSetText); - PhClearReference(&ProcessNode->PrivateWsText); - PhClearReference(&ProcessNode->SharedWsText); - PhClearReference(&ProcessNode->ShareableWsText); - PhClearReference(&ProcessNode->VirtualSizeText); - PhClearReference(&ProcessNode->PeakVirtualSizeText); - PhClearReference(&ProcessNode->PageFaultsText); - PhClearReference(&ProcessNode->IoRoRateText); - PhClearReference(&ProcessNode->IoWRateText); - PhClearReference(&ProcessNode->StartTimeText); - PhClearReference(&ProcessNode->TotalCpuTimeText); - PhClearReference(&ProcessNode->KernelCpuTimeText); - PhClearReference(&ProcessNode->UserCpuTimeText); - PhClearReference(&ProcessNode->RelativeStartTimeText); - PhClearReference(&ProcessNode->WindowTitleText); - PhClearReference(&ProcessNode->CyclesText); - PhClearReference(&ProcessNode->CyclesDeltaText); - PhClearReference(&ProcessNode->ContextSwitchesText); - PhClearReference(&ProcessNode->ContextSwitchesDeltaText); - PhClearReference(&ProcessNode->PageFaultsDeltaText); - - for (i = 0; i < PHPRTLC_IOGROUP_COUNT; i++) - PhClearReference(&ProcessNode->IoGroupText[i]); - - PhClearReference(&ProcessNode->PagedPoolText); - PhClearReference(&ProcessNode->PeakPagedPoolText); - PhClearReference(&ProcessNode->NonPagedPoolText); - PhClearReference(&ProcessNode->PeakNonPagedPoolText); - PhClearReference(&ProcessNode->MinimumWorkingSetText); - PhClearReference(&ProcessNode->MaximumWorkingSetText); - PhClearReference(&ProcessNode->PrivateBytesDeltaText); - PhClearReference(&ProcessNode->TimeStampText); - PhClearReference(&ProcessNode->FileModifiedTimeText); - PhClearReference(&ProcessNode->FileSizeText); - - PhDeleteGraphBuffers(&ProcessNode->CpuGraphBuffers); - PhDeleteGraphBuffers(&ProcessNode->PrivateGraphBuffers); - PhDeleteGraphBuffers(&ProcessNode->IoGraphBuffers); - - PhDereferenceObject(ProcessNode->ProcessItem); - - PhFree(ProcessNode); - - TreeNew_NodesStructured(ProcessTreeListHandle); -} - -VOID PhUpdateProcessNode( - _In_ PPH_PROCESS_NODE ProcessNode - ) -{ - memset(ProcessNode->TextCache, 0, sizeof(PH_STRINGREF) * PHPRTLC_MAXIMUM); - - if (ProcessNode->TooltipText) - { - PhDereferenceObject(ProcessNode->TooltipText); - ProcessNode->TooltipText = NULL; - } - - PhInvalidateTreeNewNode(&ProcessNode->Node, TN_CACHE_COLOR | TN_CACHE_ICON); - TreeNew_InvalidateNode(ProcessTreeListHandle, &ProcessNode->Node); -} - -VOID PhTickProcessNodes( - VOID - ) -{ - ULONG i; - PH_TREENEW_VIEW_PARTS viewParts; - BOOLEAN fullyInvalidated; - RECT rect; - - // Text invalidation, node updates - - for (i = 0; i < ProcessNodeList->Count; i++) - { - PPH_PROCESS_NODE node = ProcessNodeList->Items[i]; - - // The name and PID never change, so we don't invalidate that. - memset(&node->TextCache[2], 0, sizeof(PH_STRINGREF) * (PHPRTLC_MAXIMUM - 2)); - node->ValidMask &= PHPN_OSCONTEXT | PHPN_IMAGE | PHPN_DPIAWARENESS; // Items that always remain valid - - // Invalidate graph buffers. - node->CpuGraphBuffers.Valid = FALSE; - node->PrivateGraphBuffers.Valid = FALSE; - node->IoGraphBuffers.Valid = FALSE; - - // Updates cycles if necessary. - if (NeedCyclesInformation) - PhpUpdateProcessNodeCycles(node); - } - - fullyInvalidated = FALSE; - - if (ProcessTreeListSortOrder != NoSortOrder) - { - // Force a rebuild to sort the items. - TreeNew_NodesStructured(ProcessTreeListHandle); - fullyInvalidated = TRUE; - } - - // State highlighting - PH_TICK_SH_STATE_TN(PH_PROCESS_NODE, ShState, ProcessNodeStateList, PhpRemoveProcessNode, PhCsHighlightingDuration, ProcessTreeListHandle, TRUE, &fullyInvalidated); - - if (!fullyInvalidated) - { - // The first column doesn't need to be invalidated because the process name never changes, and - // icon changes are handled by the modified event. This small optimization can save more than - // 10 million cycles per update (on my machine). - TreeNew_GetViewParts(ProcessTreeListHandle, &viewParts); - rect.left = viewParts.NormalLeft; - rect.top = viewParts.HeaderHeight; - rect.right = viewParts.ClientRect.right - viewParts.VScrollWidth; - rect.bottom = viewParts.ClientRect.bottom; - InvalidateRect(ProcessTreeListHandle, &rect, FALSE); - } -} - -static VOID PhpNeedGraphContext( - _In_ HDC hdc, - _In_ ULONG Width, - _In_ ULONG Height - ) -{ - BITMAPINFOHEADER header; - - // If we already have a graph context and it's the right size, then return immediately. - if (GraphContextWidth == Width && GraphContextHeight == Height) - return; - - if (GraphContext) - { - // The original bitmap must be selected back into the context, otherwise - // the bitmap can't be deleted. - SelectObject(GraphContext, GraphBitmap); - DeleteObject(GraphBitmap); - DeleteDC(GraphContext); - - GraphContext = NULL; - GraphBitmap = NULL; - GraphBits = NULL; - } - - GraphContext = CreateCompatibleDC(hdc); - - memset(&header, 0, sizeof(BITMAPINFOHEADER)); - header.biSize = sizeof(BITMAPINFOHEADER); - header.biWidth = Width; - header.biHeight = Height; - header.biPlanes = 1; - header.biBitCount = 32; - GraphBitmap = CreateDIBSection(hdc, (BITMAPINFO *)&header, DIB_RGB_COLORS, &GraphBits, NULL, 0); - GraphOldBitmap = SelectObject(GraphContext, GraphBitmap); -} - -static BOOLEAN PhpFormatInt32GroupDigits( - _In_ ULONG Value, - _Out_writes_bytes_(BufferLength) PWCHAR Buffer, - _In_ ULONG BufferLength, - _Out_opt_ PPH_STRINGREF String - ) -{ - PH_FORMAT format; - SIZE_T returnLength; - - PhInitFormatU(&format, Value); - format.Type |= FormatGroupDigits; - - if (PhFormatToBuffer(&format, 1, Buffer, BufferLength, &returnLength)) - { - if (String) - { - String->Buffer = Buffer; - String->Length = returnLength - sizeof(WCHAR); - } - - return TRUE; - } - else - { - return FALSE; - } -} - -FORCEINLINE PVOID PhpFieldForAggregate( - _In_ PPH_PROCESS_NODE ProcessNode, - _In_ PHP_AGGREGATE_LOCATION Location, - _In_ SIZE_T FieldOffset - ) -{ - PVOID object; - - switch (Location) - { - case AggregateLocationProcessNode: - object = ProcessNode; - break; - case AggregateLocationProcessItem: - object = ProcessNode->ProcessItem; - break; - default: - PhRaiseStatus(STATUS_INVALID_PARAMETER); - } - - return PTR_ADD_OFFSET(object, FieldOffset); -} - -FORCEINLINE VOID PhpAccumulateField( - _Inout_ PVOID Accumulator, - _In_ PVOID Value, - _In_ PHP_AGGREGATE_TYPE Type - ) -{ - switch (Type) - { - case AggregateTypeFloat: - *(PFLOAT)Accumulator += *(PFLOAT)Value; - break; - case AggregateTypeInt32: - *(PULONG)Accumulator += *(PULONG)Value; - break; - case AggregateTypeInt64: - *(PULONG64)Accumulator += *(PULONG64)Value; - break; - case AggregateTypeIntPtr: - *(PULONG_PTR)Accumulator += *(PULONG_PTR)Value; - break; - } -} - -static VOID PhpAggregateField( - _In_ PPH_PROCESS_NODE ProcessNode, - _In_ PHP_AGGREGATE_TYPE Type, - _In_ PHP_AGGREGATE_LOCATION Location, - _In_ SIZE_T FieldOffset, - _Inout_ PVOID AggregatedValue - ) -{ - ULONG i; - - PhpAccumulateField(AggregatedValue, PhpFieldForAggregate(ProcessNode, Location, FieldOffset), Type); - - for (i = 0; i < ProcessNode->Children->Count; i++) - { - PhpAggregateField(ProcessNode->Children->Items[i], Type, Location, FieldOffset, AggregatedValue); - } -} - -static VOID PhpAggregateFieldIfNeeded( - _In_ PPH_PROCESS_NODE ProcessNode, - _In_ PHP_AGGREGATE_TYPE Type, - _In_ PHP_AGGREGATE_LOCATION Location, - _In_ SIZE_T FieldOffset, - _Inout_ PVOID AggregatedValue - ) -{ - if (!PhCsPropagateCpuUsage || ProcessNode->Node.Expanded || ProcessTreeListSortOrder != NoSortOrder) - { - PhpAccumulateField(AggregatedValue, PhpFieldForAggregate(ProcessNode, Location, FieldOffset), Type); - } - else - { - PhpAggregateField(ProcessNode, Type, Location, FieldOffset, AggregatedValue); - } -} - -static VOID PhpUpdateProcessNodeWsCounters( - _Inout_ PPH_PROCESS_NODE ProcessNode - ) -{ - if (!(ProcessNode->ValidMask & PHPN_WSCOUNTERS)) - { - BOOLEAN success = FALSE; - HANDLE processHandle; - - if (NT_SUCCESS(PhOpenProcess( - &processHandle, - PROCESS_QUERY_INFORMATION, - ProcessNode->ProcessItem->ProcessId - ))) - { - if (NT_SUCCESS(PhGetProcessWsCounters( - processHandle, - &ProcessNode->WsCounters - ))) - success = TRUE; - - NtClose(processHandle); - } - - if (!success) - memset(&ProcessNode->WsCounters, 0, sizeof(PH_PROCESS_WS_COUNTERS)); - - ProcessNode->ValidMask |= PHPN_WSCOUNTERS; - } -} - -static VOID PhpUpdateProcessNodeGdiUserHandles( - _Inout_ PPH_PROCESS_NODE ProcessNode - ) -{ - if (!(ProcessNode->ValidMask & PHPN_GDIUSERHANDLES)) - { - if (ProcessNode->ProcessItem->QueryHandle) - { - ProcessNode->GdiHandles = GetGuiResources(ProcessNode->ProcessItem->QueryHandle, GR_GDIOBJECTS); - ProcessNode->UserHandles = GetGuiResources(ProcessNode->ProcessItem->QueryHandle, GR_USEROBJECTS); - } - else - { - ProcessNode->GdiHandles = 0; - ProcessNode->UserHandles = 0; - } - - ProcessNode->ValidMask |= PHPN_GDIUSERHANDLES; - } -} - -static VOID PhpUpdateProcessNodeIoPagePriority( - _Inout_ PPH_PROCESS_NODE ProcessNode - ) -{ - if (!(ProcessNode->ValidMask & PHPN_IOPAGEPRIORITY)) - { - if (ProcessNode->ProcessItem->QueryHandle) - { - if (!NT_SUCCESS(PhGetProcessIoPriority(ProcessNode->ProcessItem->QueryHandle, &ProcessNode->IoPriority))) - ProcessNode->IoPriority = -1; - if (!NT_SUCCESS(PhGetProcessPagePriority(ProcessNode->ProcessItem->QueryHandle, &ProcessNode->PagePriority))) - ProcessNode->PagePriority = -1; - } - else - { - ProcessNode->IoPriority = -1; - ProcessNode->PagePriority = -1; - } - - ProcessNode->ValidMask |= PHPN_IOPAGEPRIORITY; - } -} - -static VOID PhpUpdateProcessNodeWindow( - _Inout_ PPH_PROCESS_NODE ProcessNode - ) -{ - if (!(ProcessNode->ValidMask & PHPN_WINDOW)) - { - ProcessNode->WindowHandle = PhGetProcessMainWindow(ProcessNode->ProcessId, ProcessNode->ProcessItem->QueryHandle); - - PhClearReference(&ProcessNode->WindowText); - - if (ProcessNode->WindowHandle) - { - PhGetWindowTextEx(ProcessNode->WindowHandle, PH_GET_WINDOW_TEXT_INTERNAL, &ProcessNode->WindowText); - ProcessNode->WindowHung = !!IsHungAppWindow(ProcessNode->WindowHandle); - } - - ProcessNode->ValidMask |= PHPN_WINDOW; - } -} - -static VOID PhpUpdateProcessNodeDepStatus( - _Inout_ PPH_PROCESS_NODE ProcessNode - ) -{ - if (!(ProcessNode->ValidMask & PHPN_DEPSTATUS)) - { - HANDLE processHandle; - ULONG depStatus; - - depStatus = 0; - -#ifdef _WIN64 - if (ProcessNode->ProcessItem->IsWow64) -#else - if (TRUE) -#endif - { - if (NT_SUCCESS(PhOpenProcess( - &processHandle, - PROCESS_QUERY_INFORMATION, - ProcessNode->ProcessItem->ProcessId - ))) - { - PhGetProcessDepStatus(processHandle, &depStatus); - NtClose(processHandle); - } - } - else - { - if (ProcessNode->ProcessItem->QueryHandle) - depStatus = PH_PROCESS_DEP_ENABLED | PH_PROCESS_DEP_PERMANENT; - } - - ProcessNode->DepStatus = depStatus; - - ProcessNode->ValidMask |= PHPN_DEPSTATUS; - } -} - -static VOID PhpUpdateProcessNodeToken( - _Inout_ PPH_PROCESS_NODE ProcessNode - ) -{ - if (!(ProcessNode->ValidMask & PHPN_TOKEN)) - { - HANDLE tokenHandle; - - ProcessNode->VirtualizationAllowed = FALSE; - ProcessNode->VirtualizationEnabled = FALSE; - - if (WINDOWS_HAS_UAC && ProcessNode->ProcessItem->QueryHandle) - { - if (NT_SUCCESS(PhOpenProcessToken( - ProcessNode->ProcessItem->QueryHandle, - TOKEN_QUERY, - &tokenHandle - ))) - { - if (NT_SUCCESS(PhGetTokenIsVirtualizationAllowed(tokenHandle, &ProcessNode->VirtualizationAllowed)) && - ProcessNode->VirtualizationAllowed) - { - if (!NT_SUCCESS(PhGetTokenIsVirtualizationEnabled(tokenHandle, &ProcessNode->VirtualizationEnabled))) - { - ProcessNode->VirtualizationAllowed = FALSE; // display N/A on error - } - } - - NtClose(tokenHandle); - } - } - - ProcessNode->ValidMask |= PHPN_TOKEN; - } -} - -static VOID PhpUpdateProcessOsContext( - _Inout_ PPH_PROCESS_NODE ProcessNode - ) -{ - if (!(ProcessNode->ValidMask & PHPN_OSCONTEXT)) - { - HANDLE processHandle; - - if (WindowsVersion >= WINDOWS_7) - { - if (NT_SUCCESS(PhOpenProcess(&processHandle, ProcessQueryAccess | PROCESS_VM_READ, ProcessNode->ProcessId))) - { - if (NT_SUCCESS(PhGetProcessSwitchContext(processHandle, &ProcessNode->OsContextGuid))) - { - if (memcmp(&ProcessNode->OsContextGuid, &WINTHRESHOLD_CONTEXT_GUID, sizeof(GUID)) == 0) - ProcessNode->OsContextVersion = WINDOWS_10; - else if (memcmp(&ProcessNode->OsContextGuid, &WINBLUE_CONTEXT_GUID, sizeof(GUID)) == 0) - ProcessNode->OsContextVersion = WINDOWS_8_1; - else if (memcmp(&ProcessNode->OsContextGuid, &WIN8_CONTEXT_GUID, sizeof(GUID)) == 0) - ProcessNode->OsContextVersion = WINDOWS_8; - else if (memcmp(&ProcessNode->OsContextGuid, &WIN7_CONTEXT_GUID, sizeof(GUID)) == 0) - ProcessNode->OsContextVersion = WINDOWS_7; - else if (memcmp(&ProcessNode->OsContextGuid, &VISTA_CONTEXT_GUID, sizeof(GUID)) == 0) - ProcessNode->OsContextVersion = WINDOWS_VISTA; - else if (memcmp(&ProcessNode->OsContextGuid, &XP_CONTEXT_GUID, sizeof(GUID)) == 0) - ProcessNode->OsContextVersion = WINDOWS_XP; - } - - NtClose(processHandle); - } - } - - ProcessNode->ValidMask |= PHPN_OSCONTEXT; - } -} - -static VOID PhpUpdateProcessNodeQuotaLimits( - _Inout_ PPH_PROCESS_NODE ProcessNode - ) -{ - if (!(ProcessNode->ValidMask & PHPN_QUOTALIMITS)) - { - QUOTA_LIMITS quotaLimits; - - if (ProcessNode->ProcessItem->QueryHandle && NT_SUCCESS(NtQueryInformationProcess( - ProcessNode->ProcessItem->QueryHandle, - ProcessQuotaLimits, - "aLimits, - sizeof(QUOTA_LIMITS), - NULL - ))) - { - ProcessNode->MinimumWorkingSetSize = quotaLimits.MinimumWorkingSetSize; - ProcessNode->MaximumWorkingSetSize = quotaLimits.MaximumWorkingSetSize; - } - else - { - ProcessNode->MinimumWorkingSetSize = 0; - ProcessNode->MaximumWorkingSetSize = 0; - } - - ProcessNode->ValidMask |= PHPN_QUOTALIMITS; - } -} - -static VOID PhpUpdateProcessNodeImage( - _Inout_ PPH_PROCESS_NODE ProcessNode - ) -{ - if (!(ProcessNode->ValidMask & PHPN_IMAGE)) - { - HANDLE processHandle; - PROCESS_BASIC_INFORMATION basicInfo; - PVOID imageBaseAddress; - PH_REMOTE_MAPPED_IMAGE mappedImage; - - if (NT_SUCCESS(PhOpenProcess(&processHandle, ProcessQueryAccess | PROCESS_VM_READ, ProcessNode->ProcessId))) - { - if (NT_SUCCESS(PhGetProcessBasicInformation(processHandle, &basicInfo))) - { - if (NT_SUCCESS(NtReadVirtualMemory( - processHandle, - PTR_ADD_OFFSET(basicInfo.PebBaseAddress, FIELD_OFFSET(PEB, ImageBaseAddress)), - &imageBaseAddress, - sizeof(PVOID), - NULL - ))) - { - if (NT_SUCCESS(PhLoadRemoteMappedImage(processHandle, imageBaseAddress, &mappedImage))) - { - ProcessNode->ImageTimeDateStamp = mappedImage.NtHeaders->FileHeader.TimeDateStamp; - ProcessNode->ImageCharacteristics = mappedImage.NtHeaders->FileHeader.Characteristics; - - if (mappedImage.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) - { - ProcessNode->ImageSubsystem = ((PIMAGE_OPTIONAL_HEADER32)&mappedImage.NtHeaders->OptionalHeader)->Subsystem; - ProcessNode->ImageDllCharacteristics = ((PIMAGE_OPTIONAL_HEADER32)&mappedImage.NtHeaders->OptionalHeader)->DllCharacteristics; - } - else if (mappedImage.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) - { - ProcessNode->ImageSubsystem = ((PIMAGE_OPTIONAL_HEADER64)&mappedImage.NtHeaders->OptionalHeader)->Subsystem; - ProcessNode->ImageDllCharacteristics = ((PIMAGE_OPTIONAL_HEADER64)&mappedImage.NtHeaders->OptionalHeader)->DllCharacteristics; - } - - PhUnloadRemoteMappedImage(&mappedImage); - } - } - } - - NtClose(processHandle); - } - - ProcessNode->ValidMask |= PHPN_IMAGE; - } -} - -static VOID PhpUpdateProcessNodeAppId( - _Inout_ PPH_PROCESS_NODE ProcessNode - ) -{ - if (!(ProcessNode->ValidMask & PHPN_APPID)) - { - HANDLE processHandle; - ULONG windowFlags; - PPH_STRING windowTitle; - - PhClearReference(&ProcessNode->AppIdText); - - if (!NT_SUCCESS(PhOpenProcess(&processHandle, ProcessQueryAccess | PROCESS_VM_READ, ProcessNode->ProcessId))) - { - if (WindowsVersion >= WINDOWS_7) - { - if (!NT_SUCCESS(PhOpenProcess(&processHandle, ProcessQueryAccess, ProcessNode->ProcessId))) - goto Done; - } - else - { - goto Done; - } - } - - if (NT_SUCCESS(PhGetProcessWindowTitle( - processHandle, - &windowFlags, - &windowTitle - ))) - { - if (windowFlags & STARTF_TITLEISAPPID) - ProcessNode->AppIdText = windowTitle; - else - PhDereferenceObject(windowTitle); - } - - NtClose(processHandle); - -Done: - ProcessNode->ValidMask |= PHPN_APPID; - } -} - -static VOID PhpUpdateProcessNodeDpiAwareness( - _Inout_ PPH_PROCESS_NODE ProcessNode - ) -{ - static PH_INITONCE initOnce = PH_INITONCE_INIT; - static BOOL (WINAPI *getProcessDpiAwarenessInternal)( - _In_ HANDLE hprocess, - _Out_ ULONG *value - ); - - if (PhBeginInitOnce(&initOnce)) - { - getProcessDpiAwarenessInternal = PhGetModuleProcAddress(L"user32.dll", "GetProcessDpiAwarenessInternal"); - PhEndInitOnce(&initOnce); - } - - if (!getProcessDpiAwarenessInternal) - return; - - if (!(ProcessNode->ValidMask & PHPN_DPIAWARENESS)) - { - if (ProcessNode->ProcessItem->QueryHandle) - { - ULONG dpiAwareness; - - if (getProcessDpiAwarenessInternal(ProcessNode->ProcessItem->QueryHandle, &dpiAwareness)) - ProcessNode->DpiAwareness = dpiAwareness + 1; - } - - ProcessNode->ValidMask |= PHPN_DPIAWARENESS; - } -} - -static VOID PhpUpdateProcessNodeFileAttributes( - _Inout_ PPH_PROCESS_NODE ProcessNode - ) -{ - if (!(ProcessNode->ValidMask & PHPN_FILEATTRIBUTES)) - { - FILE_NETWORK_OPEN_INFORMATION networkOpenInfo; - - if (ProcessNode->ProcessItem->FileName && NT_SUCCESS(PhQueryFullAttributesFileWin32( - ProcessNode->ProcessItem->FileName->Buffer, - &networkOpenInfo - ))) - { - ProcessNode->FileLastWriteTime = networkOpenInfo.LastWriteTime; - ProcessNode->FileEndOfFile = networkOpenInfo.EndOfFile; - } - else - { - ProcessNode->FileEndOfFile.QuadPart = -1; - } - - ProcessNode->ValidMask |= PHPN_FILEATTRIBUTES; - } -} - -static VOID PhpUpdateNeedCyclesInformation( - VOID - ) -{ - PH_TREENEW_COLUMN column; - - NeedCyclesInformation = FALSE; - - // Before Windows Vista, there is no cycle time measurement. - // On Windows 7 and above, cycle time information is available directly from the process item. - // We only need to query cycle time separately for Windows Vista. - if (WindowsVersion != WINDOWS_VISTA) - return; - - TreeNew_GetColumn(ProcessTreeListHandle, PHPRTLC_CYCLES, &column); - - if (column.Visible) - { - NeedCyclesInformation = TRUE; - return; - } - - TreeNew_GetColumn(ProcessTreeListHandle, PHPRTLC_CYCLESDELTA, &column); - - if (column.Visible) - { - NeedCyclesInformation = TRUE; - return; - } -} - -static VOID PhpUpdateProcessNodeCycles( - _Inout_ PPH_PROCESS_NODE ProcessNode - ) -{ - if (ProcessNode->ProcessId == SYSTEM_IDLE_PROCESS_ID) - { - PULARGE_INTEGER idleThreadCycleTimes; - ULONG64 cycleTime; - ULONG i; - - // System Idle Process requires special treatment. - - idleThreadCycleTimes = PhAllocate( - sizeof(ULARGE_INTEGER) * (ULONG)PhSystemBasicInformation.NumberOfProcessors - ); - - if (NT_SUCCESS(NtQuerySystemInformation( - SystemProcessorIdleCycleTimeInformation, - idleThreadCycleTimes, - sizeof(ULARGE_INTEGER) * (ULONG)PhSystemBasicInformation.NumberOfProcessors, - NULL - ))) - { - cycleTime = 0; - - for (i = 0; i < (ULONG)PhSystemBasicInformation.NumberOfProcessors; i++) - cycleTime += idleThreadCycleTimes[i].QuadPart; - - PhUpdateDelta(&ProcessNode->CyclesDelta, cycleTime); - } - - PhFree(idleThreadCycleTimes); - } - else if (ProcessNode->ProcessItem->QueryHandle) - { - ULONG64 cycleTime; - - if (NT_SUCCESS(PhGetProcessCycleTime(ProcessNode->ProcessItem->QueryHandle, &cycleTime))) - { - PhUpdateDelta(&ProcessNode->CyclesDelta, cycleTime); - } - } - - if (ProcessNode->CyclesDelta.Value != 0) - PhMoveReference(&ProcessNode->CyclesText, PhFormatUInt64(ProcessNode->CyclesDelta.Value, TRUE)); - else - PhClearReference(&ProcessNode->CyclesText); - - if (ProcessNode->CyclesDelta.Delta != 0) - PhMoveReference(&ProcessNode->CyclesDeltaText, PhFormatUInt64(ProcessNode->CyclesDelta.Delta, TRUE)); - else - PhClearReference(&ProcessNode->CyclesDeltaText); -} - -#define SORT_FUNCTION(Column) PhpProcessTreeNewCompare##Column - -#define BEGIN_SORT_FUNCTION(Column) static int __cdecl PhpProcessTreeNewCompare##Column( \ - _In_ const void *_elem1, \ - _In_ const void *_elem2 \ - ) \ -{ \ - PPH_PROCESS_NODE node1 = *(PPH_PROCESS_NODE *)_elem1; \ - PPH_PROCESS_NODE node2 = *(PPH_PROCESS_NODE *)_elem2; \ - PPH_PROCESS_ITEM processItem1 = node1->ProcessItem; \ - PPH_PROCESS_ITEM processItem2 = node2->ProcessItem; \ - int sortResult = 0; - -#define END_SORT_FUNCTION \ - if (sortResult == 0) \ - sortResult = intptrcmp((LONG_PTR)processItem1->ProcessId, (LONG_PTR)processItem2->ProcessId); \ - \ - return PhModifySort(sortResult, ProcessTreeListSortOrder); \ -} - -LONG PhpProcessTreeNewPostSortFunction( - _In_ LONG Result, - _In_ PVOID Node1, - _In_ PVOID Node2, - _In_ PH_SORT_ORDER SortOrder - ) -{ - if (Result == 0) - Result = intptrcmp((LONG_PTR)((PPH_PROCESS_NODE)Node1)->ProcessItem->ProcessId, (LONG_PTR)((PPH_PROCESS_NODE)Node2)->ProcessItem->ProcessId); - - return PhModifySort(Result, SortOrder); -} - -BEGIN_SORT_FUNCTION(Name) -{ - sortResult = PhCompareString(processItem1->ProcessName, processItem2->ProcessName, TRUE); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(Pid) -{ - // Use signed int so DPCs and Interrupts are placed above System Idle Process. - sortResult = intptrcmp((LONG_PTR)processItem1->ProcessId, (LONG_PTR)processItem2->ProcessId); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(Cpu) -{ - sortResult = singlecmp(processItem1->CpuUsage, processItem2->CpuUsage); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(IoTotalRate) -{ - sortResult = uint64cmp( - processItem1->IoReadDelta.Delta + processItem1->IoWriteDelta.Delta + processItem1->IoOtherDelta.Delta, - processItem2->IoReadDelta.Delta + processItem2->IoWriteDelta.Delta + processItem2->IoOtherDelta.Delta - ); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(PrivateBytes) -{ - sortResult = uintptrcmp(processItem1->VmCounters.PagefileUsage, processItem2->VmCounters.PagefileUsage); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(UserName) -{ - sortResult = PhCompareStringWithNull(processItem1->UserName, processItem2->UserName, TRUE); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(Description) -{ - PH_STRINGREF sr1; - PH_STRINGREF sr2; - - sr1 = processItem1->VersionInfo.FileDescription ? processItem1->VersionInfo.FileDescription->sr : node1->DescriptionText; - sr2 = processItem2->VersionInfo.FileDescription ? processItem2->VersionInfo.FileDescription->sr : node2->DescriptionText; - - sortResult = PhCompareStringRef(&sr1, &sr2, TRUE); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(CompanyName) -{ - sortResult = PhCompareStringWithNull( - processItem1->VersionInfo.CompanyName, - processItem2->VersionInfo.CompanyName, - TRUE - ); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(Version) -{ - sortResult = PhCompareStringWithNull( - processItem1->VersionInfo.FileVersion, - processItem2->VersionInfo.FileVersion, - TRUE - ); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(FileName) -{ - sortResult = PhCompareStringWithNull( - processItem1->FileName, - processItem2->FileName, - TRUE - ); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(CommandLine) -{ - sortResult = PhCompareStringWithNull( - processItem1->CommandLine, - processItem2->CommandLine, - TRUE - ); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(PeakPrivateBytes) -{ - sortResult = uintptrcmp(processItem1->VmCounters.PeakPagefileUsage, processItem2->VmCounters.PeakPagefileUsage); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(WorkingSet) -{ - sortResult = uintptrcmp(processItem1->VmCounters.WorkingSetSize, processItem2->VmCounters.WorkingSetSize); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(PeakWorkingSet) -{ - sortResult = uintptrcmp(processItem1->VmCounters.PeakWorkingSetSize, processItem2->VmCounters.PeakWorkingSetSize); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(PrivateWs) -{ - PhpUpdateProcessNodeWsCounters(node1); - PhpUpdateProcessNodeWsCounters(node2); - sortResult = uintptrcmp(node1->WsCounters.NumberOfPrivatePages, node2->WsCounters.NumberOfPrivatePages); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(PrivateWsWin7) -{ - sortResult = uintptrcmp(processItem1->WorkingSetPrivateSize, processItem2->WorkingSetPrivateSize); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(SharedWs) -{ - PhpUpdateProcessNodeWsCounters(node1); - PhpUpdateProcessNodeWsCounters(node2); - sortResult = uintptrcmp(node1->WsCounters.NumberOfSharedPages, node2->WsCounters.NumberOfSharedPages); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(ShareableWs) -{ - PhpUpdateProcessNodeWsCounters(node1); - PhpUpdateProcessNodeWsCounters(node2); - sortResult = uintptrcmp(node1->WsCounters.NumberOfShareablePages, node2->WsCounters.NumberOfShareablePages); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(VirtualSize) -{ - sortResult = uintptrcmp(processItem1->VmCounters.VirtualSize, processItem2->VmCounters.VirtualSize); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(PeakVirtualSize) -{ - sortResult = uintptrcmp(processItem1->VmCounters.PeakVirtualSize, processItem2->VmCounters.PeakVirtualSize); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(PageFaults) -{ - sortResult = uintcmp(processItem1->VmCounters.PageFaultCount, processItem2->VmCounters.PageFaultCount); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(SessionId) -{ - sortResult = uintcmp(processItem1->SessionId, processItem2->SessionId); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(BasePriority) -{ - sortResult = intcmp(processItem1->BasePriority, processItem2->BasePriority); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(Threads) -{ - sortResult = uintcmp(processItem1->NumberOfThreads, processItem2->NumberOfThreads); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(Handles) -{ - sortResult = uintcmp(processItem1->NumberOfHandles, processItem2->NumberOfHandles); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(GdiHandles) -{ - sortResult = uintcmp(node1->GdiHandles, node2->GdiHandles); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(UserHandles) -{ - sortResult = uintcmp(node1->UserHandles, node2->UserHandles); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(IoRoRate) -{ - sortResult = uint64cmp( - processItem1->IoReadDelta.Delta + processItem1->IoOtherDelta.Delta, - processItem2->IoReadDelta.Delta + processItem2->IoOtherDelta.Delta - ); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(IoWRate) -{ - sortResult = uint64cmp( - processItem1->IoWriteDelta.Delta, - processItem2->IoWriteDelta.Delta - ); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(Integrity) -{ - sortResult = uintcmp(processItem1->IntegrityLevel, processItem2->IntegrityLevel); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(IoPriority) -{ - sortResult = uintcmp(node1->IoPriority, node2->IoPriority); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(PagePriority) -{ - sortResult = uintcmp(node1->PagePriority, node2->PagePriority); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(StartTime) -{ - sortResult = int64cmp(processItem1->CreateTime.QuadPart, processItem2->CreateTime.QuadPart); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(TotalCpuTime) -{ - sortResult = uint64cmp( - processItem1->KernelTime.QuadPart + processItem1->UserTime.QuadPart, - processItem2->KernelTime.QuadPart + processItem2->UserTime.QuadPart - ); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(KernelCpuTime) -{ - sortResult = uint64cmp( - processItem1->KernelTime.QuadPart, - processItem2->KernelTime.QuadPart - ); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(UserCpuTime) -{ - sortResult = uint64cmp( - processItem1->UserTime.QuadPart, - processItem2->UserTime.QuadPart - ); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(VerificationStatus) -{ - sortResult = intcmp(processItem1->VerifyResult, processItem2->VerifyResult); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(VerifiedSigner) -{ - sortResult = PhCompareStringWithNull( - processItem1->VerifySignerName, - processItem2->VerifySignerName, - TRUE - ); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(Aslr) -{ - PhpUpdateProcessNodeImage(node1); - PhpUpdateProcessNodeImage(node2); - sortResult = intcmp( - node1->ImageDllCharacteristics & IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE, - node2->ImageDllCharacteristics & IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE - ); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(RelativeStartTime) -{ - sortResult = -int64cmp(processItem1->CreateTime.QuadPart, processItem2->CreateTime.QuadPart); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(Bits) -{ - sortResult = intcmp(processItem1->IsWow64Valid, processItem2->IsWow64Valid); - - if (sortResult == 0) - sortResult = intcmp(processItem1->IsWow64, processItem2->IsWow64); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(Elevation) -{ - ULONG key1; - ULONG key2; - - switch (processItem1->ElevationType) - { - case TokenElevationTypeFull: - key1 = 2; - break; - case TokenElevationTypeLimited: - key1 = 1; - break; - default: - key1 = 0; - break; - } - - switch (processItem2->ElevationType) - { - case TokenElevationTypeFull: - key2 = 2; - break; - case TokenElevationTypeLimited: - key2 = 1; - break; - default: - key2 = 0; - break; - } - - sortResult = intcmp(key1, key2); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(WindowTitle) -{ - PhpUpdateProcessNodeWindow(node1); - PhpUpdateProcessNodeWindow(node2); - sortResult = PhCompareStringWithNull(node1->WindowText, node2->WindowText, TRUE); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(WindowStatus) -{ - PhpUpdateProcessNodeWindow(node1); - PhpUpdateProcessNodeWindow(node2); - sortResult = intcmp(node1->WindowHung, node2->WindowHung); - - // Make sure all processes with windows get grouped together. - if (sortResult == 0) - sortResult = intcmp(!!node1->WindowHandle, !!node2->WindowHandle); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(Cycles) -{ - sortResult = uint64cmp(node1->CyclesDelta.Value, node2->CyclesDelta.Value); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(CyclesWin7) -{ - sortResult = uint64cmp(processItem1->CycleTimeDelta.Value, processItem2->CycleTimeDelta.Value); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(CyclesDelta) -{ - sortResult = uint64cmp(node1->CyclesDelta.Delta, node2->CyclesDelta.Delta); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(CyclesDeltaWin7) -{ - sortResult = uint64cmp(processItem1->CycleTimeDelta.Delta, processItem2->CycleTimeDelta.Delta); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(Dep) -{ - PhpUpdateProcessNodeDepStatus(node1); - PhpUpdateProcessNodeDepStatus(node2); - sortResult = uintcmp(node1->DepStatus, node2->DepStatus); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(Virtualized) -{ - PhpUpdateProcessNodeToken(node1); - PhpUpdateProcessNodeToken(node2); - sortResult = intcmp(node1->VirtualizationEnabled, node2->VirtualizationEnabled); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(ContextSwitches) -{ - sortResult = uintcmp(processItem1->ContextSwitchesDelta.Value, processItem2->ContextSwitchesDelta.Value); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(ContextSwitchesDelta) -{ - sortResult = intcmp((LONG)processItem1->ContextSwitchesDelta.Delta, (LONG)processItem2->ContextSwitchesDelta.Delta); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(PageFaultsDelta) -{ - sortResult = uintcmp(processItem1->PageFaultsDelta.Delta, processItem2->PageFaultsDelta.Delta); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(IoReads) -{ - sortResult = uint64cmp(processItem1->IoReadCountDelta.Value, processItem2->IoReadCountDelta.Value); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(IoWrites) -{ - sortResult = uint64cmp(processItem1->IoWriteCountDelta.Value, processItem2->IoWriteCountDelta.Value); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(IoOther) -{ - sortResult = uint64cmp(processItem1->IoOtherCountDelta.Value, processItem2->IoOtherCountDelta.Value); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(IoReadBytes) -{ - sortResult = uint64cmp(processItem1->IoReadDelta.Value, processItem2->IoReadDelta.Value); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(IoWriteBytes) -{ - sortResult = uint64cmp(processItem1->IoWriteDelta.Value, processItem2->IoWriteDelta.Value); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(IoOtherBytes) -{ - sortResult = uint64cmp(processItem1->IoOtherDelta.Value, processItem2->IoOtherDelta.Value); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(IoReadsDelta) -{ - sortResult = uint64cmp(processItem1->IoReadCountDelta.Delta, processItem2->IoReadCountDelta.Delta); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(IoWritesDelta) -{ - sortResult = uint64cmp(processItem1->IoWriteCountDelta.Delta, processItem2->IoWriteCountDelta.Delta); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(IoOtherDelta) -{ - sortResult = uint64cmp(processItem1->IoOtherCountDelta.Delta, processItem2->IoOtherCountDelta.Delta); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(OsContext) -{ - PhpUpdateProcessOsContext(node1); - PhpUpdateProcessOsContext(node2); - sortResult = uintcmp(node1->OsContextVersion, node2->OsContextVersion); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(PagedPool) -{ - sortResult = uintptrcmp(processItem1->VmCounters.QuotaPagedPoolUsage, processItem2->VmCounters.QuotaPagedPoolUsage); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(PeakPagedPool) -{ - sortResult = uintptrcmp(processItem1->VmCounters.QuotaPeakPagedPoolUsage, processItem2->VmCounters.QuotaPeakPagedPoolUsage); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(NonPagedPool) -{ - sortResult = uintptrcmp(processItem1->VmCounters.QuotaNonPagedPoolUsage, processItem2->VmCounters.QuotaNonPagedPoolUsage); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(PeakNonPagedPool) -{ - sortResult = uintptrcmp(processItem1->VmCounters.QuotaPeakNonPagedPoolUsage, processItem2->VmCounters.QuotaPeakNonPagedPoolUsage); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(MinimumWorkingSet) -{ - PhpUpdateProcessNodeQuotaLimits(node1); - PhpUpdateProcessNodeQuotaLimits(node2); - sortResult = uintptrcmp(node1->MinimumWorkingSetSize, node2->MinimumWorkingSetSize); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(MaximumWorkingSet) -{ - PhpUpdateProcessNodeQuotaLimits(node1); - PhpUpdateProcessNodeQuotaLimits(node2); - sortResult = uintptrcmp(node1->MaximumWorkingSetSize, node2->MaximumWorkingSetSize); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(PrivateBytesDelta) -{ - sortResult = intptrcmp(processItem1->PrivateBytesDelta.Delta, processItem2->PrivateBytesDelta.Delta); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(Subsystem) -{ - PhpUpdateProcessNodeImage(node1); - PhpUpdateProcessNodeImage(node2); - sortResult = intcmp(node1->ImageSubsystem, node2->ImageSubsystem); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(PackageName) -{ - sortResult = PhCompareStringWithNull(processItem1->PackageFullName, processItem2->PackageFullName, TRUE); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(AppId) -{ - PhpUpdateProcessNodeAppId(node1); - PhpUpdateProcessNodeAppId(node2); - sortResult = PhCompareStringWithNull(node1->AppIdText, node2->AppIdText, TRUE); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(DpiAwareness) -{ - PhpUpdateProcessNodeDpiAwareness(node1); - PhpUpdateProcessNodeDpiAwareness(node2); - sortResult = uintcmp(node1->DpiAwareness, node2->DpiAwareness); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(CfGuard) -{ - PhpUpdateProcessNodeImage(node1); - PhpUpdateProcessNodeImage(node2); - sortResult = intcmp( - node1->ImageDllCharacteristics & IMAGE_DLLCHARACTERISTICS_GUARD_CF, - node2->ImageDllCharacteristics & IMAGE_DLLCHARACTERISTICS_GUARD_CF - ); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(TimeStamp) -{ - PhpUpdateProcessNodeImage(node1); - PhpUpdateProcessNodeImage(node2); - sortResult = uintcmp(node1->ImageTimeDateStamp, node2->ImageTimeDateStamp); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(FileModifiedTime) -{ - PhpUpdateProcessNodeFileAttributes(node1); - PhpUpdateProcessNodeFileAttributes(node2); - sortResult = int64cmp(node1->FileLastWriteTime.QuadPart, node2->FileLastWriteTime.QuadPart); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(FileSize) -{ - PhpUpdateProcessNodeFileAttributes(node1); - PhpUpdateProcessNodeFileAttributes(node2); - sortResult = int64cmp(node1->FileEndOfFile.QuadPart, node2->FileEndOfFile.QuadPart); -} -END_SORT_FUNCTION - -BOOLEAN NTAPI PhpProcessTreeNewCallback( - _In_ HWND hwnd, - _In_ PH_TREENEW_MESSAGE Message, - _In_opt_ PVOID Parameter1, - _In_opt_ PVOID Parameter2, - _In_opt_ PVOID Context - ) -{ - PPH_PROCESS_NODE node; - - if (PhCmForwardMessage(hwnd, Message, Parameter1, Parameter2, &ProcessTreeListCm)) - return TRUE; - - switch (Message) - { - case TreeNewGetChildren: - { - PPH_TREENEW_GET_CHILDREN getChildren = Parameter1; - - node = (PPH_PROCESS_NODE)getChildren->Node; - - if (ProcessTreeListSortOrder == NoSortOrder) - { - if (!node) - { - getChildren->Children = (PPH_TREENEW_NODE *)ProcessNodeRootList->Items; - getChildren->NumberOfChildren = ProcessNodeRootList->Count; - } - else - { - getChildren->Children = (PPH_TREENEW_NODE *)node->Children->Items; - getChildren->NumberOfChildren = node->Children->Count; - } - } - else - { - if (!node) - { - static PVOID sortFunctions[] = - { - SORT_FUNCTION(Name), - SORT_FUNCTION(Pid), - SORT_FUNCTION(Cpu), - SORT_FUNCTION(IoTotalRate), - SORT_FUNCTION(PrivateBytes), - SORT_FUNCTION(UserName), - SORT_FUNCTION(Description), - SORT_FUNCTION(CompanyName), - SORT_FUNCTION(Version), - SORT_FUNCTION(FileName), - SORT_FUNCTION(CommandLine), - SORT_FUNCTION(PeakPrivateBytes), - SORT_FUNCTION(WorkingSet), - SORT_FUNCTION(PeakWorkingSet), - SORT_FUNCTION(PrivateWs), - SORT_FUNCTION(SharedWs), - SORT_FUNCTION(ShareableWs), - SORT_FUNCTION(VirtualSize), - SORT_FUNCTION(PeakVirtualSize), - SORT_FUNCTION(PageFaults), - SORT_FUNCTION(SessionId), - SORT_FUNCTION(BasePriority), // Priority Class - SORT_FUNCTION(BasePriority), - SORT_FUNCTION(Threads), - SORT_FUNCTION(Handles), - SORT_FUNCTION(GdiHandles), - SORT_FUNCTION(UserHandles), - SORT_FUNCTION(IoRoRate), - SORT_FUNCTION(IoWRate), - SORT_FUNCTION(Integrity), - SORT_FUNCTION(IoPriority), - SORT_FUNCTION(PagePriority), - SORT_FUNCTION(StartTime), - SORT_FUNCTION(TotalCpuTime), - SORT_FUNCTION(KernelCpuTime), - SORT_FUNCTION(UserCpuTime), - SORT_FUNCTION(VerificationStatus), - SORT_FUNCTION(VerifiedSigner), - SORT_FUNCTION(Aslr), - SORT_FUNCTION(RelativeStartTime), - SORT_FUNCTION(Bits), - SORT_FUNCTION(Elevation), - SORT_FUNCTION(WindowTitle), - SORT_FUNCTION(WindowStatus), - SORT_FUNCTION(Cycles), - SORT_FUNCTION(CyclesDelta), - SORT_FUNCTION(Cpu), // CPU History - SORT_FUNCTION(PrivateBytes), // Private Bytes History - SORT_FUNCTION(IoTotalRate), // I/O History - SORT_FUNCTION(Dep), - SORT_FUNCTION(Virtualized), - SORT_FUNCTION(ContextSwitches), - SORT_FUNCTION(ContextSwitchesDelta), - SORT_FUNCTION(PageFaultsDelta), - SORT_FUNCTION(IoReads), - SORT_FUNCTION(IoWrites), - SORT_FUNCTION(IoOther), - SORT_FUNCTION(IoReadBytes), - SORT_FUNCTION(IoWriteBytes), - SORT_FUNCTION(IoOtherBytes), - SORT_FUNCTION(IoReadsDelta), - SORT_FUNCTION(IoWritesDelta), - SORT_FUNCTION(IoOtherDelta), - SORT_FUNCTION(OsContext), - SORT_FUNCTION(PagedPool), - SORT_FUNCTION(PeakPagedPool), - SORT_FUNCTION(NonPagedPool), - SORT_FUNCTION(PeakNonPagedPool), - SORT_FUNCTION(MinimumWorkingSet), - SORT_FUNCTION(MaximumWorkingSet), - SORT_FUNCTION(PrivateBytesDelta), - SORT_FUNCTION(Subsystem), - SORT_FUNCTION(PackageName), - SORT_FUNCTION(AppId), - SORT_FUNCTION(DpiAwareness), - SORT_FUNCTION(CfGuard), - SORT_FUNCTION(TimeStamp), - SORT_FUNCTION(FileModifiedTime), - SORT_FUNCTION(FileSize) - }; - static PH_INITONCE initOnce = PH_INITONCE_INIT; - int (__cdecl *sortFunction)(const void *, const void *); - - if (PhBeginInitOnce(&initOnce)) - { - if (WindowsVersion >= WINDOWS_7) - { - sortFunctions[PHPRTLC_PRIVATEWS] = SORT_FUNCTION(PrivateWsWin7); - sortFunctions[PHPRTLC_CYCLES] = SORT_FUNCTION(CyclesWin7); - sortFunctions[PHPRTLC_CYCLESDELTA] = SORT_FUNCTION(CyclesDeltaWin7); - } - - PhEndInitOnce(&initOnce); - } - - if (!PhCmForwardSort( - (PPH_TREENEW_NODE *)ProcessNodeList->Items, - ProcessNodeList->Count, - ProcessTreeListSortColumn, - ProcessTreeListSortOrder, - &ProcessTreeListCm - )) - { - if (ProcessTreeListSortColumn < PHPRTLC_MAXIMUM) - sortFunction = sortFunctions[ProcessTreeListSortColumn]; - else - sortFunction = NULL; - - if (sortFunction) - { - qsort(ProcessNodeList->Items, ProcessNodeList->Count, sizeof(PVOID), sortFunction); - } - } - - getChildren->Children = (PPH_TREENEW_NODE *)ProcessNodeList->Items; - getChildren->NumberOfChildren = ProcessNodeList->Count; - } - } - } - return TRUE; - case TreeNewIsLeaf: - { - PPH_TREENEW_IS_LEAF isLeaf = Parameter1; - - node = (PPH_PROCESS_NODE)isLeaf->Node; - - if (ProcessTreeListSortOrder == NoSortOrder) - isLeaf->IsLeaf = node->Children->Count == 0; - else - isLeaf->IsLeaf = TRUE; - } - return TRUE; - case TreeNewGetCellText: - { - PPH_TREENEW_GET_CELL_TEXT getCellText = Parameter1; - PPH_PROCESS_ITEM processItem; - - node = (PPH_PROCESS_NODE)getCellText->Node; - processItem = node->ProcessItem; - - switch (getCellText->Id) - { - case PHPRTLC_NAME: - getCellText->Text = processItem->ProcessName->sr; - break; - case PHPRTLC_PID: - PhInitializeStringRefLongHint(&getCellText->Text, processItem->ProcessIdString); - break; - case PHPRTLC_CPU: - { - FLOAT cpuUsage = 0; - - PhpAggregateFieldIfNeeded(node, AggregateTypeFloat, AggregateLocationProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, CpuUsage), &cpuUsage); - cpuUsage *= 100; - - if (cpuUsage >= 0.01) - { - PH_FORMAT format; - SIZE_T returnLength; - - PhInitFormatF(&format, cpuUsage, 2); - - if (PhFormatToBuffer(&format, 1, node->CpuUsageText, sizeof(node->CpuUsageText), &returnLength)) - { - getCellText->Text.Buffer = node->CpuUsageText; - getCellText->Text.Length = returnLength - sizeof(WCHAR); // minus null terminator - } - } - else if (cpuUsage != 0 && PhCsShowCpuBelow001) - { - PH_FORMAT format[2]; - SIZE_T returnLength; - - PhInitFormatS(&format[0], L"< "); - PhInitFormatF(&format[1], 0.01, 2); - - if (PhFormatToBuffer(format, 2, node->CpuUsageText, sizeof(node->CpuUsageText), &returnLength)) - { - getCellText->Text.Buffer = node->CpuUsageText; - getCellText->Text.Length = returnLength - sizeof(WCHAR); - } - } - } - break; - case PHPRTLC_IOTOTALRATE: - { - ULONG64 number = 0; - - if (processItem->IoReadDelta.Delta != processItem->IoReadDelta.Value) // delta is wrong on first run of process provider - { - PhpAggregateFieldIfNeeded(node, AggregateTypeInt64, AggregateLocationProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, IoReadDelta.Delta), &number); - PhpAggregateFieldIfNeeded(node, AggregateTypeInt64, AggregateLocationProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, IoWriteDelta.Delta), &number); - PhpAggregateFieldIfNeeded(node, AggregateTypeInt64, AggregateLocationProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, IoOtherDelta.Delta), &number); - number *= 1000; - number /= PhCsUpdateInterval; - } - - if (number != 0) - { - PH_FORMAT format[2]; - - PhInitFormatSize(&format[0], number); - PhInitFormatS(&format[1], L"/s"); - PhMoveReference(&node->IoTotalRateText, PhFormat(format, 2, 0)); - getCellText->Text = node->IoTotalRateText->sr; - } - } - break; - case PHPRTLC_PRIVATEBYTES: - { - SIZE_T value = 0; - PhpAggregateFieldIfNeeded(node, AggregateTypeIntPtr, AggregateLocationProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, VmCounters.PagefileUsage), &value); - PhMoveReference(&node->PrivateBytesText, PhFormatSize(value, -1)); - getCellText->Text = node->PrivateBytesText->sr; - } - break; - case PHPRTLC_USERNAME: - getCellText->Text = PhGetStringRef(processItem->UserName); - break; - case PHPRTLC_DESCRIPTION: - if (processItem->VersionInfo.FileDescription) - getCellText->Text = processItem->VersionInfo.FileDescription->sr; - else - getCellText->Text = node->DescriptionText; - break; - case PHPRTLC_COMPANYNAME: - getCellText->Text = PhGetStringRef(processItem->VersionInfo.CompanyName); - break; - case PHPRTLC_VERSION: - getCellText->Text = PhGetStringRef(processItem->VersionInfo.FileVersion); - break; - case PHPRTLC_FILENAME: - getCellText->Text = PhGetStringRef(processItem->FileName); - break; - case PHPRTLC_COMMANDLINE: - getCellText->Text = PhGetStringRef(processItem->CommandLine); - break; - case PHPRTLC_PEAKPRIVATEBYTES: - PhMoveReference(&node->PeakPrivateBytesText, PhFormatSize(processItem->VmCounters.PeakPagefileUsage, -1)); - getCellText->Text = node->PeakPrivateBytesText->sr; - break; - case PHPRTLC_WORKINGSET: - { - SIZE_T value = 0; - PhpAggregateFieldIfNeeded(node, AggregateTypeIntPtr, AggregateLocationProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, VmCounters.WorkingSetSize), &value); - PhMoveReference(&node->WorkingSetText, PhFormatSize(value, -1)); - getCellText->Text = node->WorkingSetText->sr; - } - break; - case PHPRTLC_PEAKWORKINGSET: - PhMoveReference(&node->PeakWorkingSetText, PhFormatSize(processItem->VmCounters.PeakWorkingSetSize, -1)); - getCellText->Text = node->PeakWorkingSetText->sr; - break; - case PHPRTLC_PRIVATEWS: - if (WindowsVersion >= WINDOWS_7) - { - PhMoveReference(&node->PrivateWsText, PhFormatSize(processItem->WorkingSetPrivateSize, -1)); - } - else - { - PhpUpdateProcessNodeWsCounters(node); - PhMoveReference(&node->PrivateWsText, PhFormatSize((ULONG64)node->WsCounters.NumberOfPrivatePages * PAGE_SIZE, -1)); - } - getCellText->Text = node->PrivateWsText->sr; - break; - case PHPRTLC_SHAREDWS: - PhpUpdateProcessNodeWsCounters(node); - PhMoveReference(&node->SharedWsText, PhFormatSize((ULONG64)node->WsCounters.NumberOfSharedPages * PAGE_SIZE, -1)); - getCellText->Text = node->SharedWsText->sr; - break; - case PHPRTLC_SHAREABLEWS: - PhpUpdateProcessNodeWsCounters(node); - PhMoveReference(&node->ShareableWsText, PhFormatSize((ULONG64)node->WsCounters.NumberOfShareablePages * PAGE_SIZE, -1)); - getCellText->Text = node->ShareableWsText->sr; - break; - case PHPRTLC_VIRTUALSIZE: - PhMoveReference(&node->VirtualSizeText, PhFormatSize(processItem->VmCounters.VirtualSize, -1)); - getCellText->Text = node->VirtualSizeText->sr; - break; - case PHPRTLC_PEAKVIRTUALSIZE: - PhMoveReference(&node->PeakVirtualSizeText, PhFormatSize(processItem->VmCounters.PeakVirtualSize, -1)); - getCellText->Text = node->PeakVirtualSizeText->sr; - break; - case PHPRTLC_PAGEFAULTS: - PhMoveReference(&node->PageFaultsText, PhFormatUInt64(processItem->VmCounters.PageFaultCount, TRUE)); - getCellText->Text = node->PageFaultsText->sr; - break; - case PHPRTLC_SESSIONID: - PhInitializeStringRefLongHint(&getCellText->Text, processItem->SessionIdString); - break; - case PHPRTLC_PRIORITYCLASS: - PhInitializeStringRefLongHint(&getCellText->Text, PhGetProcessPriorityClassString(processItem->PriorityClass)); - break; - case PHPRTLC_BASEPRIORITY: - PhPrintInt32(node->BasePriorityText, processItem->BasePriority); - PhInitializeStringRefLongHint(&getCellText->Text, node->BasePriorityText); - break; - case PHPRTLC_THREADS: - { - ULONG value = 0; - PhpAggregateFieldIfNeeded(node, AggregateTypeInt32, AggregateLocationProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, NumberOfThreads), &value); - PhpFormatInt32GroupDigits(value, node->ThreadsText, sizeof(node->ThreadsText), &getCellText->Text); - } - break; - case PHPRTLC_HANDLES: - { - ULONG value = 0; - PhpAggregateFieldIfNeeded(node, AggregateTypeInt32, AggregateLocationProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, NumberOfHandles), &value); - PhpFormatInt32GroupDigits(value, node->HandlesText, sizeof(node->HandlesText), &getCellText->Text); - } - break; - case PHPRTLC_GDIHANDLES: - PhpUpdateProcessNodeGdiUserHandles(node); - PhpFormatInt32GroupDigits(node->GdiHandles, node->GdiHandlesText, sizeof(node->GdiHandlesText), &getCellText->Text); - break; - case PHPRTLC_USERHANDLES: - PhpUpdateProcessNodeGdiUserHandles(node); - PhpFormatInt32GroupDigits(node->UserHandles, node->UserHandlesText, sizeof(node->UserHandlesText), &getCellText->Text); - break; - case PHPRTLC_IORORATE: - { - ULONG64 number = 0; - - if (processItem->IoReadDelta.Delta != processItem->IoReadDelta.Value) - { - PhpAggregateFieldIfNeeded(node, AggregateTypeInt64, AggregateLocationProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, IoReadDelta.Delta), &number); - PhpAggregateFieldIfNeeded(node, AggregateTypeInt64, AggregateLocationProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, IoOtherDelta.Delta), &number); - number *= 1000; - number /= PhCsUpdateInterval; - } - - if (number != 0) - { - PH_FORMAT format[2]; - - PhInitFormatSize(&format[0], number); - PhInitFormatS(&format[1], L"/s"); - PhMoveReference(&node->IoRoRateText, PhFormat(format, 2, 0)); - getCellText->Text = node->IoRoRateText->sr; - } - } - break; - case PHPRTLC_IOWRATE: - { - ULONG64 number = 0; - - if (processItem->IoReadDelta.Delta != processItem->IoReadDelta.Value) - { - PhpAggregateFieldIfNeeded(node, AggregateTypeInt64, AggregateLocationProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, IoWriteDelta.Delta), &number); - number *= 1000; - number /= PhCsUpdateInterval; - } - - if (number != 0) - { - PH_FORMAT format[2]; - - PhInitFormatSize(&format[0], number); - PhInitFormatS(&format[1], L"/s"); - PhMoveReference(&node->IoWRateText, PhFormat(format, 2, 0)); - getCellText->Text = node->IoWRateText->sr; - } - } - break; - case PHPRTLC_INTEGRITY: - if (processItem->IntegrityString) - PhInitializeStringRefLongHint(&getCellText->Text, processItem->IntegrityString); - break; - case PHPRTLC_IOPRIORITY: - PhpUpdateProcessNodeIoPagePriority(node); - if (node->IoPriority != -1 && node->IoPriority < MaxIoPriorityTypes) - PhInitializeStringRefLongHint(&getCellText->Text, PhIoPriorityHintNames[node->IoPriority]); - break; - case PHPRTLC_PAGEPRIORITY: - PhpUpdateProcessNodeIoPagePriority(node); - if (node->PagePriority != -1 && node->PagePriority <= MEMORY_PRIORITY_NORMAL) - PhInitializeStringRefLongHint(&getCellText->Text, PhPagePriorityNames[node->PagePriority]); - break; - case PHPRTLC_STARTTIME: - if (processItem->CreateTime.QuadPart != 0) - { - SYSTEMTIME systemTime; - - PhLargeIntegerToLocalSystemTime(&systemTime, &processItem->CreateTime); - PhMoveReference(&node->StartTimeText, PhFormatDateTime(&systemTime)); - getCellText->Text = node->StartTimeText->sr; - } - break; - case PHPRTLC_TOTALCPUTIME: - PhMoveReference(&node->TotalCpuTimeText, PhFormatTimeSpan( - processItem->KernelTime.QuadPart + processItem->UserTime.QuadPart, - PH_TIMESPAN_HMSM - )); - getCellText->Text = node->TotalCpuTimeText->sr; - break; - case PHPRTLC_KERNELCPUTIME: - PhMoveReference(&node->KernelCpuTimeText, PhFormatTimeSpan( - processItem->KernelTime.QuadPart, - PH_TIMESPAN_HMSM - )); - getCellText->Text = node->KernelCpuTimeText->sr; - break; - case PHPRTLC_USERCPUTIME: - PhMoveReference(&node->UserCpuTimeText, PhFormatTimeSpan( - processItem->UserTime.QuadPart, - PH_TIMESPAN_HMSM - )); - getCellText->Text = node->UserCpuTimeText->sr; - break; - case PHPRTLC_VERIFICATIONSTATUS: - if (processItem->VerifyResult == VrTrusted) - PhInitializeStringRef(&getCellText->Text, L"Trusted"); - break; - case PHPRTLC_VERIFIEDSIGNER: - getCellText->Text = PhGetStringRef(processItem->VerifySignerName); - break; - case PHPRTLC_ASLR: - PhpUpdateProcessNodeImage(node); - - if (WindowsVersion >= WINDOWS_VISTA) - { - if (node->ImageDllCharacteristics & IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE) - PhInitializeStringRef(&getCellText->Text, L"ASLR"); - } - else - { - PhInitializeStringRef(&getCellText->Text, L"N/A"); - } - break; - case PHPRTLC_RELATIVESTARTTIME: - { - if (processItem->CreateTime.QuadPart != 0) - { - LARGE_INTEGER currentTime; - PPH_STRING startTimeString; - - PhQuerySystemTime(¤tTime); - startTimeString = PhFormatTimeSpanRelative(currentTime.QuadPart - processItem->CreateTime.QuadPart); - PhMoveReference(&node->RelativeStartTimeText, PhConcatStrings2(startTimeString->Buffer, L" ago")); - PhDereferenceObject(startTimeString); - getCellText->Text = node->RelativeStartTimeText->sr; - } - } - break; - case PHPRTLC_BITS: -#ifdef _WIN64 - if (processItem->IsWow64Valid) - PhInitializeStringRef(&getCellText->Text, processItem->IsWow64 ? L"32" : L"64"); -#else - PhInitializeStringRef(&getCellText->Text, L"32"); -#endif - break; - case PHPRTLC_ELEVATION: - { - PWSTR type; - - if (WINDOWS_HAS_UAC) - { - switch (processItem->ElevationType) - { - case TokenElevationTypeDefault: - type = L"N/A"; - break; - case TokenElevationTypeLimited: - type = L"Limited"; - break; - case TokenElevationTypeFull: - type = L"Full"; - break; - default: - type = L"N/A"; - break; - } - } - else - { - type = L""; - } - - PhInitializeStringRefLongHint(&getCellText->Text, type); - } - break; - case PHPRTLC_WINDOWTITLE: - PhpUpdateProcessNodeWindow(node); - PhSwapReference(&node->WindowTitleText, node->WindowText); - getCellText->Text = PhGetStringRef(node->WindowTitleText); - break; - case PHPRTLC_WINDOWSTATUS: - PhpUpdateProcessNodeWindow(node); - - if (node->WindowHandle) - PhInitializeStringRef(&getCellText->Text, node->WindowHung ? L"Not responding" : L"Running"); - - break; - case PHPRTLC_CYCLES: - if (WindowsVersion >= WINDOWS_7) - { - ULONG64 value = 0; - PhpAggregateFieldIfNeeded(node, AggregateTypeInt64, AggregateLocationProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, CycleTimeDelta.Value), &value); - - if (value != 0) - { - PhMoveReference(&node->CyclesText, PhFormatUInt64(value, TRUE)); - getCellText->Text = node->CyclesText->sr; - } - } - else - { - getCellText->Text = PhGetStringRef(node->CyclesText); - } - break; - case PHPRTLC_CYCLESDELTA: - if (WindowsVersion >= WINDOWS_7) - { - ULONG64 value = 0; - PhpAggregateFieldIfNeeded(node, AggregateTypeInt64, AggregateLocationProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, CycleTimeDelta.Delta), &value); - - if (value != 0) - { - PhMoveReference(&node->CyclesDeltaText, PhFormatUInt64(value, TRUE)); - getCellText->Text = node->CyclesDeltaText->sr; - } - } - else - { - getCellText->Text = PhGetStringRef(node->CyclesDeltaText); - } - break; - case PHPRTLC_DEP: - PhpUpdateProcessNodeDepStatus(node); - - if (node->DepStatus & PH_PROCESS_DEP_ENABLED) - { - if (node->DepStatus & PH_PROCESS_DEP_PERMANENT) - PhInitializeStringRef(&getCellText->Text, L"DEP (permanent)"); - else - PhInitializeStringRef(&getCellText->Text, L"DEP"); - } - - break; - case PHPRTLC_VIRTUALIZED: - PhpUpdateProcessNodeToken(node); - - if (node->VirtualizationEnabled) - PhInitializeStringRef(&getCellText->Text, L"Virtualized"); - - break; - case PHPRTLC_CONTEXTSWITCHES: - if (processItem->ContextSwitchesDelta.Value != 0) - { - PhMoveReference(&node->ContextSwitchesText, PhFormatUInt64(processItem->ContextSwitchesDelta.Value, TRUE)); - getCellText->Text = node->ContextSwitchesText->sr; - } - break; - case PHPRTLC_CONTEXTSWITCHESDELTA: - if ((LONG)processItem->ContextSwitchesDelta.Delta > 0) // the delta may be negative if a thread exits - just don't show anything - { - PhMoveReference(&node->ContextSwitchesDeltaText, PhFormatUInt64(processItem->ContextSwitchesDelta.Delta, TRUE)); - getCellText->Text = node->ContextSwitchesDeltaText->sr; - } - break; - case PHPRTLC_PAGEFAULTSDELTA: - if (processItem->PageFaultsDelta.Delta != 0) - { - PhMoveReference(&node->PageFaultsDeltaText, PhFormatUInt64(processItem->PageFaultsDelta.Delta, TRUE)); - getCellText->Text = node->PageFaultsDeltaText->sr; - } - break; - case PHPRTLC_IOREADS: - if (processItem->IoReadCountDelta.Value != 0) - { - PhMoveReference(&node->IoGroupText[0], PhFormatUInt64(processItem->IoReadCountDelta.Value, TRUE)); - getCellText->Text = node->IoGroupText[0]->sr; - } - break; - case PHPRTLC_IOWRITES: - if (processItem->IoWriteCountDelta.Value != 0) - { - PhMoveReference(&node->IoGroupText[1], PhFormatUInt64(processItem->IoWriteCountDelta.Value, TRUE)); - getCellText->Text = node->IoGroupText[1]->sr; - } - break; - case PHPRTLC_IOOTHER: - if (processItem->IoOtherCountDelta.Value != 0) - { - PhMoveReference(&node->IoGroupText[2], PhFormatUInt64(processItem->IoOtherCountDelta.Value, TRUE)); - getCellText->Text = node->IoGroupText[2]->sr; - } - break; - case PHPRTLC_IOREADBYTES: - if (processItem->IoReadDelta.Value != 0) - { - PhMoveReference(&node->IoGroupText[3], PhFormatSize(processItem->IoReadDelta.Value, -1)); - getCellText->Text = node->IoGroupText[3]->sr; - } - break; - case PHPRTLC_IOWRITEBYTES: - if (processItem->IoWriteDelta.Value != 0) - { - PhMoveReference(&node->IoGroupText[4], PhFormatSize(processItem->IoWriteDelta.Value, -1)); - getCellText->Text = node->IoGroupText[4]->sr; - } - break; - case PHPRTLC_IOOTHERBYTES: - if (processItem->IoOtherDelta.Value != 0) - { - PhMoveReference(&node->IoGroupText[5], PhFormatSize(processItem->IoOtherDelta.Value, -1)); - getCellText->Text = node->IoGroupText[5]->sr; - } - break; - case PHPRTLC_IOREADSDELTA: - if (processItem->IoReadCountDelta.Delta != 0) - { - PhMoveReference(&node->IoGroupText[6], PhFormatUInt64(processItem->IoReadCountDelta.Delta, TRUE)); - getCellText->Text = node->IoGroupText[6]->sr; - } - break; - case PHPRTLC_IOWRITESDELTA: - if (processItem->IoWriteCountDelta.Delta != 0) - { - PhMoveReference(&node->IoGroupText[7], PhFormatUInt64(processItem->IoWriteCountDelta.Delta, TRUE)); - getCellText->Text = node->IoGroupText[7]->sr; - } - break; - case PHPRTLC_IOOTHERDELTA: - if (processItem->IoOtherCountDelta.Delta != 0) - { - PhMoveReference(&node->IoGroupText[8], PhFormatUInt64(processItem->IoOtherCountDelta.Delta, TRUE)); - getCellText->Text = node->IoGroupText[8]->sr; - } - break; - case PHPRTLC_OSCONTEXT: - PhpUpdateProcessOsContext(node); - - if (WindowsVersion >= WINDOWS_7) - { - switch (node->OsContextVersion) - { - case WINDOWS_10: - PhInitializeStringRef(&getCellText->Text, L"Windows 10"); - break; - case WINDOWS_8_1: - PhInitializeStringRef(&getCellText->Text, L"Windows 8.1"); - break; - case WINDOWS_8: - PhInitializeStringRef(&getCellText->Text, L"Windows 8"); - break; - case WINDOWS_7: - PhInitializeStringRef(&getCellText->Text, L"Windows 7"); - break; - case WINDOWS_VISTA: - PhInitializeStringRef(&getCellText->Text, L"Windows Vista"); - break; - case WINDOWS_XP: - PhInitializeStringRef(&getCellText->Text, L"Windows XP"); - break; - } - } - else - { - PhInitializeStringRef(&getCellText->Text, L"N/A"); - } - break; - case PHPRTLC_PAGEDPOOL: - PhMoveReference(&node->PagedPoolText, PhFormatSize(processItem->VmCounters.QuotaPagedPoolUsage, -1)); - getCellText->Text = node->PagedPoolText->sr; - break; - case PHPRTLC_PEAKPAGEDPOOL: - PhMoveReference(&node->PeakPagedPoolText, PhFormatSize(processItem->VmCounters.QuotaPeakPagedPoolUsage, -1)); - getCellText->Text = node->PeakPagedPoolText->sr; - break; - case PHPRTLC_NONPAGEDPOOL: - PhMoveReference(&node->NonPagedPoolText, PhFormatSize(processItem->VmCounters.QuotaNonPagedPoolUsage, -1)); - getCellText->Text = node->NonPagedPoolText->sr; - break; - case PHPRTLC_PEAKNONPAGEDPOOL: - PhMoveReference(&node->PeakNonPagedPoolText, PhFormatSize(processItem->VmCounters.QuotaPeakNonPagedPoolUsage, -1)); - getCellText->Text = node->PeakNonPagedPoolText->sr; - break; - case PHPRTLC_MINIMUMWORKINGSET: - PhpUpdateProcessNodeQuotaLimits(node); - PhMoveReference(&node->MinimumWorkingSetText, PhFormatSize(node->MinimumWorkingSetSize, -1)); - getCellText->Text = node->MinimumWorkingSetText->sr; - break; - case PHPRTLC_MAXIMUMWORKINGSET: - PhpUpdateProcessNodeQuotaLimits(node); - PhMoveReference(&node->MaximumWorkingSetText, PhFormatSize(node->MaximumWorkingSetSize, -1)); - getCellText->Text = node->MaximumWorkingSetText->sr; - break; - case PHPRTLC_PRIVATEBYTESDELTA: - { - LONG_PTR delta; - - delta = processItem->PrivateBytesDelta.Delta; - - if (delta != 0) - { - PH_FORMAT format[2]; - - if (delta > 0) - { - PhInitFormatC(&format[0], '+'); - } - else - { - PhInitFormatC(&format[0], '-'); - delta = -delta; - } - - format[1].Type = SizeFormatType | FormatUseRadix; - format[1].Radix = (UCHAR)PhMaxSizeUnit; - format[1].u.Size = delta; - - PhMoveReference(&node->PrivateBytesDeltaText, PhFormat(format, 2, 0)); - getCellText->Text = node->PrivateBytesDeltaText->sr; - } - } - break; - case PHPRTLC_SUBSYSTEM: - PhpUpdateProcessNodeImage(node); - - switch (node->ImageSubsystem) - { - case 0: - break; - case IMAGE_SUBSYSTEM_NATIVE: - PhInitializeStringRef(&getCellText->Text, L"Native"); - break; - case IMAGE_SUBSYSTEM_WINDOWS_GUI: - PhInitializeStringRef(&getCellText->Text, L"Windows"); - break; - case IMAGE_SUBSYSTEM_WINDOWS_CUI: - PhInitializeStringRef(&getCellText->Text, L"Windows console"); - break; - case IMAGE_SUBSYSTEM_OS2_CUI: - PhInitializeStringRef(&getCellText->Text, L"OS/2"); - break; - case IMAGE_SUBSYSTEM_POSIX_CUI: - PhInitializeStringRef(&getCellText->Text, L"POSIX"); - break; - default: - PhInitializeStringRef(&getCellText->Text, L"Unknown"); - break; - } - break; - case PHPRTLC_PACKAGENAME: - getCellText->Text = PhGetStringRef(processItem->PackageFullName); - break; - case PHPRTLC_APPID: - PhpUpdateProcessNodeAppId(node); - getCellText->Text = PhGetStringRef(node->AppIdText); - break; - case PHPRTLC_DPIAWARENESS: - PhpUpdateProcessNodeDpiAwareness(node); - - switch (node->DpiAwareness) - { - case 0: - break; - case 1: - PhInitializeStringRef(&getCellText->Text, L"Unaware"); - break; - case 2: - PhInitializeStringRef(&getCellText->Text, L"System aware"); - break; - case 3: - PhInitializeStringRef(&getCellText->Text, L"Per-monitor aware"); - break; - } - break; - case PHPRTLC_CFGUARD: - PhpUpdateProcessNodeImage(node); - - if (WindowsVersion >= WINDOWS_8_1) - { - if (node->ImageDllCharacteristics & IMAGE_DLLCHARACTERISTICS_GUARD_CF) - PhInitializeStringRef(&getCellText->Text, L"CF Guard"); - } - else - { - PhInitializeStringRef(&getCellText->Text, L"N/A"); - } - break; - case PHPRTLC_TIMESTAMP: - PhpUpdateProcessNodeImage(node); - - if (node->ImageTimeDateStamp != 0) - { - LARGE_INTEGER time; - SYSTEMTIME systemTime; - - RtlSecondsSince1970ToTime(node->ImageTimeDateStamp, &time); - PhLargeIntegerToLocalSystemTime(&systemTime, &time); - - PhMoveReference(&node->TimeStampText, PhFormatDateTime(&systemTime)); - getCellText->Text = node->TimeStampText->sr; - } - break; - case PHPRTLC_FILEMODIFIEDTIME: - PhpUpdateProcessNodeFileAttributes(node); - - if (node->FileLastWriteTime.QuadPart != 0) - { - SYSTEMTIME systemTime; - - PhLargeIntegerToLocalSystemTime(&systemTime, &node->FileLastWriteTime); - PhMoveReference(&node->FileModifiedTimeText, PhFormatDateTime(&systemTime)); - getCellText->Text = node->FileModifiedTimeText->sr; - } - break; - case PHPRTLC_FILESIZE: - PhpUpdateProcessNodeFileAttributes(node); - - if (node->FileEndOfFile.QuadPart != -1) - { - PhMoveReference(&node->FileSizeText, PhFormatSize(node->FileEndOfFile.QuadPart, -1)); - getCellText->Text = node->FileSizeText->sr; - } - break; - default: - return FALSE; - } - - getCellText->Flags = TN_CACHE; - } - return TRUE; - case TreeNewGetNodeColor: - { - PPH_TREENEW_GET_NODE_COLOR getNodeColor = Parameter1; - PPH_PROCESS_ITEM processItem; - - node = (PPH_PROCESS_NODE)getNodeColor->Node; - processItem = node->ProcessItem; - - if (PhPluginsEnabled) - { - PH_PLUGIN_GET_HIGHLIGHTING_COLOR getHighlightingColor; - - getHighlightingColor.Parameter = processItem; - getHighlightingColor.BackColor = RGB(0xff, 0xff, 0xff); - getHighlightingColor.Handled = FALSE; - getHighlightingColor.Cache = FALSE; - - PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackGetProcessHighlightingColor), &getHighlightingColor); - - if (getHighlightingColor.Handled) - { - getNodeColor->BackColor = getHighlightingColor.BackColor; - getNodeColor->Flags = TN_AUTO_FORECOLOR; - - if (getHighlightingColor.Cache) - getNodeColor->Flags |= TN_CACHE; - - return TRUE; - } - } - - if (!processItem) - ; // Dummy - else if (PhCsUseColorDebuggedProcesses && processItem->IsBeingDebugged) - getNodeColor->BackColor = PhCsColorDebuggedProcesses; - else if (PhCsUseColorSuspended && processItem->IsSuspended) - getNodeColor->BackColor = PhCsColorSuspended; - else if (PhCsUseColorElevatedProcesses && processItem->IsElevated) - getNodeColor->BackColor = PhCsColorElevatedProcesses; - else if (PhCsUseColorPicoProcesses && processItem->IsSubsystemProcess) - getNodeColor->BackColor = PhCsColorPicoProcesses; - else if (PhCsUseColorImmersiveProcesses && processItem->IsImmersive) - getNodeColor->BackColor = PhCsColorImmersiveProcesses; - else if (PhCsUseColorDotNet && processItem->IsDotNet) - getNodeColor->BackColor = PhCsColorDotNet; - else if (PhCsUseColorPacked && processItem->IsPacked) - getNodeColor->BackColor = PhCsColorPacked; - else if (PhCsUseColorWow64Processes && processItem->IsWow64) - getNodeColor->BackColor = PhCsColorWow64Processes; - else if (PhCsUseColorJobProcesses && processItem->IsInSignificantJob) - getNodeColor->BackColor = PhCsColorJobProcesses; - else if (PhCsUseColorServiceProcesses && processItem->ServiceList && processItem->ServiceList->Count != 0) - getNodeColor->BackColor = PhCsColorServiceProcesses; - else if ( - PhCsUseColorSystemProcesses && - processItem->UserName && - PhEqualString(processItem->UserName, PhLocalSystemName, TRUE) - ) - getNodeColor->BackColor = PhCsColorSystemProcesses; - else if ( - PhCsUseColorOwnProcesses && - processItem->UserName && - PhCurrentUserName && - PhEqualString(processItem->UserName, PhCurrentUserName, TRUE) - ) - getNodeColor->BackColor = PhCsColorOwnProcesses; - - getNodeColor->Flags = TN_CACHE | TN_AUTO_FORECOLOR; - } - return TRUE; - case TreeNewGetNodeIcon: - { - PPH_TREENEW_GET_NODE_ICON getNodeIcon = Parameter1; - - node = (PPH_PROCESS_NODE)getNodeIcon->Node; - - if (node->ProcessItem->SmallIcon) - { - getNodeIcon->Icon = node->ProcessItem->SmallIcon; - } - else - { - PhGetStockApplicationIcon(&getNodeIcon->Icon, NULL); - } - - getNodeIcon->Flags = TN_CACHE; - } - return TRUE; - case TreeNewGetCellTooltip: - { - PPH_TREENEW_GET_CELL_TOOLTIP getCellTooltip = Parameter1; - ULONG tickCount; - - node = (PPH_PROCESS_NODE)getCellTooltip->Node; - - if (getCellTooltip->Column->Id != 0) - return FALSE; - - tickCount = GetTickCount(); - - if ((LONG)(node->TooltipTextValidToTickCount - tickCount) < 0) - PhClearReference(&node->TooltipText); - if (!node->TooltipText) - node->TooltipText = PhGetProcessTooltipText(node->ProcessItem, &node->TooltipTextValidToTickCount); - - if (!PhIsNullOrEmptyString(node->TooltipText)) - { - getCellTooltip->Text = node->TooltipText->sr; - getCellTooltip->Unfolding = FALSE; - getCellTooltip->MaximumWidth = -1; - } - else - { - return FALSE; - } - } - return TRUE; - case TreeNewCustomDraw: - { - PPH_TREENEW_CUSTOM_DRAW customDraw = Parameter1; - PPH_PROCESS_ITEM processItem; - RECT rect; - PH_GRAPH_DRAW_INFO drawInfo; - - node = (PPH_PROCESS_NODE)customDraw->Node; - processItem = node->ProcessItem; - rect = customDraw->CellRect; - - if (rect.right - rect.left <= 1) - break; // nothing to draw - - // Generic graph pre-processing - switch (customDraw->Column->Id) - { - case PHPRTLC_CPUHISTORY: - case PHPRTLC_PRIVATEBYTESHISTORY: - case PHPRTLC_IOHISTORY: - memset(&drawInfo, 0, sizeof(PH_GRAPH_DRAW_INFO)); - drawInfo.Width = rect.right - rect.left - 1; // leave a small gap - drawInfo.Height = rect.bottom - rect.top - 1; // leave a small gap - drawInfo.Step = 2; - drawInfo.BackColor = RGB(0x00, 0x00, 0x00); - break; - } - - // Specific graph processing - switch (customDraw->Column->Id) - { - case PHPRTLC_CPUHISTORY: - { - drawInfo.Flags = PH_GRAPH_USE_LINE_2; - drawInfo.LineColor1 = PhCsColorCpuKernel; - drawInfo.LineColor2 = PhCsColorCpuUser; - drawInfo.LineBackColor1 = PhHalveColorBrightness(PhCsColorCpuKernel); - drawInfo.LineBackColor2 = PhHalveColorBrightness(PhCsColorCpuUser); - - PhGetDrawInfoGraphBuffers( - &node->CpuGraphBuffers, - &drawInfo, - processItem->CpuKernelHistory.Count - ); - - if (!node->CpuGraphBuffers.Valid) - { - PhCopyCircularBuffer_FLOAT(&processItem->CpuKernelHistory, - node->CpuGraphBuffers.Data1, drawInfo.LineDataCount); - PhCopyCircularBuffer_FLOAT(&processItem->CpuUserHistory, - node->CpuGraphBuffers.Data2, drawInfo.LineDataCount); - node->CpuGraphBuffers.Valid = TRUE; - } - } - break; - case PHPRTLC_PRIVATEBYTESHISTORY: - { - drawInfo.Flags = 0; - drawInfo.LineColor1 = PhCsColorPrivate; - drawInfo.LineBackColor1 = PhHalveColorBrightness(PhCsColorPrivate); - - PhGetDrawInfoGraphBuffers( - &node->PrivateGraphBuffers, - &drawInfo, - processItem->PrivateBytesHistory.Count - ); - - if (!node->PrivateGraphBuffers.Valid) - { - ULONG i; - FLOAT total; - FLOAT max; - - for (i = 0; i < drawInfo.LineDataCount; i++) - { - node->PrivateGraphBuffers.Data1[i] = - (FLOAT)PhGetItemCircularBuffer_SIZE_T(&processItem->PrivateBytesHistory, i); - } - - // This makes it easier for the user to see what processes are hogging memory. - // Scaling is still *not* consistent across all graphs. - total = (FLOAT)PhPerfInformation.CommittedPages * PAGE_SIZE / 4; // divide by 4 to make the scaling a bit better - max = (FLOAT)processItem->VmCounters.PeakPagefileUsage; - - if (max < total) - max = total; - - if (max != 0) - { - // Scale the data. - PhDivideSinglesBySingle( - node->PrivateGraphBuffers.Data1, - max, - drawInfo.LineDataCount - ); - } - - node->PrivateGraphBuffers.Valid = TRUE; - } - } - break; - case PHPRTLC_IOHISTORY: - { - drawInfo.Flags = PH_GRAPH_USE_LINE_2; - drawInfo.LineColor1 = PhCsColorIoReadOther; - drawInfo.LineColor2 = PhCsColorIoWrite; - drawInfo.LineBackColor1 = PhHalveColorBrightness(PhCsColorIoReadOther); - drawInfo.LineBackColor2 = PhHalveColorBrightness(PhCsColorIoWrite); - - PhGetDrawInfoGraphBuffers( - &node->IoGraphBuffers, - &drawInfo, - processItem->IoReadHistory.Count - ); - - if (!node->IoGraphBuffers.Valid) - { - ULONG i; - FLOAT total; - FLOAT max = 0; - - for (i = 0; i < drawInfo.LineDataCount; i++) - { - FLOAT data1; - FLOAT data2; - - node->IoGraphBuffers.Data1[i] = data1 = - (FLOAT)PhGetItemCircularBuffer_ULONG64(&processItem->IoReadHistory, i) + - (FLOAT)PhGetItemCircularBuffer_ULONG64(&processItem->IoOtherHistory, i); - node->IoGraphBuffers.Data2[i] = data2 = - (FLOAT)PhGetItemCircularBuffer_ULONG64(&processItem->IoWriteHistory, i); - - if (max < data1 + data2) - max = data1 + data2; - } - - // Make the scaling a bit more consistent across the processes. - // It does *not* scale all graphs using the same maximum. - total = (FLOAT)(PhIoReadDelta.Delta + PhIoWriteDelta.Delta + PhIoOtherDelta.Delta); - - if (max < total) - max = total; - - if (max != 0) - { - // Scale the data. - - PhDivideSinglesBySingle( - node->IoGraphBuffers.Data1, - max, - drawInfo.LineDataCount - ); - PhDivideSinglesBySingle( - node->IoGraphBuffers.Data2, - max, - drawInfo.LineDataCount - ); - } - - node->IoGraphBuffers.Valid = TRUE; - } - } - break; - } - - // Draw the graph. - switch (customDraw->Column->Id) - { - case PHPRTLC_CPUHISTORY: - case PHPRTLC_PRIVATEBYTESHISTORY: - case PHPRTLC_IOHISTORY: - PhpNeedGraphContext(customDraw->Dc, drawInfo.Width, drawInfo.Height); - - if (GraphBits) - { - PhDrawGraphDirect(GraphContext, GraphBits, &drawInfo); - BitBlt( - customDraw->Dc, - rect.left, - rect.top + 1, // + 1 for small gap - drawInfo.Width, - drawInfo.Height, - GraphContext, - 0, - 0, - SRCCOPY - ); - } - - break; - } - } - return TRUE; - case TreeNewColumnResized: - { - PPH_TREENEW_COLUMN column = Parameter1; - ULONG i; - - if (column->Id == PHPRTLC_CPUHISTORY || column->Id == PHPRTLC_IOHISTORY || column->Id == PHPRTLC_PRIVATEBYTESHISTORY) - { - for (i = 0; i < ProcessNodeList->Count; i++) - { - node = ProcessNodeList->Items[i]; - - if (column->Id == PHPRTLC_CPUHISTORY) - node->CpuGraphBuffers.Valid = FALSE; - if (column->Id == PHPRTLC_IOHISTORY) - node->IoGraphBuffers.Valid = FALSE; - if (column->Id == PHPRTLC_PRIVATEBYTESHISTORY) - node->PrivateGraphBuffers.Valid = FALSE; - } - } - } - return TRUE; - case TreeNewSortChanged: - { - TreeNew_GetSort(hwnd, &ProcessTreeListSortColumn, &ProcessTreeListSortOrder); - // Force a rebuild to sort the items. - TreeNew_NodesStructured(hwnd); - } - return TRUE; - case TreeNewKeyDown: - { - PPH_TREENEW_KEY_EVENT keyEvent = Parameter1; - - switch (keyEvent->VirtualKey) - { - case 'C': - if (GetKeyState(VK_CONTROL) < 0) - SendMessage(PhMainWndHandle, WM_COMMAND, ID_PROCESS_COPY, 0); - break; - case 'A': - if (GetKeyState(VK_CONTROL) < 0) - TreeNew_SelectRange(ProcessTreeListHandle, 0, -1); - break; - case VK_DELETE: - if (GetKeyState(VK_SHIFT) >= 0) - SendMessage(PhMainWndHandle, WM_COMMAND, ID_PROCESS_TERMINATE, 0); - else - SendMessage(PhMainWndHandle, WM_COMMAND, ID_PROCESS_TERMINATETREE, 0); - break; - case VK_RETURN: - if (GetKeyState(VK_CONTROL) >= 0) - SendMessage(PhMainWndHandle, WM_COMMAND, ID_PROCESS_PROPERTIES, 0); - else - SendMessage(PhMainWndHandle, WM_COMMAND, ID_PROCESS_OPENFILELOCATION, 0); - break; - } - } - return TRUE; - case TreeNewHeaderRightClick: - { - PH_TN_COLUMN_MENU_DATA data; - - data.TreeNewHandle = hwnd; - data.MouseEvent = Parameter1; - data.DefaultSortColumn = 0; - data.DefaultSortOrder = NoSortOrder; - PhInitializeTreeNewColumnMenuEx(&data, PH_TN_COLUMN_MENU_SHOW_RESET_SORT); - - data.Selection = PhShowEMenu(data.Menu, hwnd, PH_EMENU_SHOW_LEFTRIGHT, - PH_ALIGN_LEFT | PH_ALIGN_TOP, data.MouseEvent->ScreenLocation.x, data.MouseEvent->ScreenLocation.y); - PhHandleTreeNewColumnMenu(&data); - - if (data.ProcessedId == PH_TN_COLUMN_MENU_HIDE_COLUMN_ID || data.ProcessedId == PH_TN_COLUMN_MENU_CHOOSE_COLUMNS_ID) - PhpUpdateNeedCyclesInformation(); - - PhDeleteTreeNewColumnMenu(&data); - } - return TRUE; - case TreeNewLeftDoubleClick: - { - SendMessage(PhMainWndHandle, WM_COMMAND, ID_PROCESS_PROPERTIES, 0); - } - return TRUE; - case TreeNewContextMenu: - { - PPH_TREENEW_CONTEXT_MENU contextMenu = Parameter1; - - PhShowProcessContextMenu(contextMenu); - } - return TRUE; - case TreeNewNodeExpanding: - { - node = Parameter1; - - if (PhCsPropagateCpuUsage) - PhUpdateProcessNode(node); - } - return TRUE; - } - - return FALSE; -} - -PPH_PROCESS_ITEM PhGetSelectedProcessItem( - VOID - ) -{ - PPH_PROCESS_ITEM processItem = NULL; - ULONG i; - - for (i = 0; i < ProcessNodeList->Count; i++) - { - PPH_PROCESS_NODE node = ProcessNodeList->Items[i]; - - if (node->Node.Selected) - { - processItem = node->ProcessItem; - break; - } - } - - return processItem; -} - -VOID PhGetSelectedProcessItems( - _Out_ PPH_PROCESS_ITEM **Processes, - _Out_ PULONG NumberOfProcesses - ) -{ - PH_ARRAY array; - ULONG i; - - PhInitializeArray(&array, sizeof(PVOID), 2); - - for (i = 0; i < ProcessNodeList->Count; i++) - { - PPH_PROCESS_NODE node = ProcessNodeList->Items[i]; - - if (node->Node.Selected) - PhAddItemArray(&array, &node->ProcessItem); - } - - *NumberOfProcesses = (ULONG)array.Count; - *Processes = PhFinalArrayItems(&array); -} - -VOID PhDeselectAllProcessNodes( - VOID - ) -{ - TreeNew_DeselectRange(ProcessTreeListHandle, 0, -1); -} - -VOID PhExpandAllProcessNodes( - _In_ BOOLEAN Expand - ) -{ - ULONG i; - BOOLEAN needsRestructure = FALSE; - - for (i = 0; i < ProcessNodeList->Count; i++) - { - PPH_PROCESS_NODE node = ProcessNodeList->Items[i]; - - if (node->Children->Count != 0 && node->Node.Expanded != Expand) - { - node->Node.Expanded = Expand; - needsRestructure = TRUE; - } - } - - if (needsRestructure) - TreeNew_NodesStructured(ProcessTreeListHandle); -} - -VOID PhInvalidateAllProcessNodes( - VOID - ) -{ - ULONG i; - - for (i = 0; i < ProcessNodeList->Count; i++) - { - PPH_PROCESS_NODE node = ProcessNodeList->Items[i]; - - memset(node->TextCache, 0, sizeof(PH_STRINGREF) * PHPRTLC_MAXIMUM); - PhInvalidateTreeNewNode(&node->Node, TN_CACHE_COLOR); - node->ValidMask = 0; - - // Invalidate graph buffers. - node->CpuGraphBuffers.Valid = FALSE; - node->PrivateGraphBuffers.Valid = FALSE; - node->IoGraphBuffers.Valid = FALSE; - } - - InvalidateRect(ProcessTreeListHandle, NULL, FALSE); -} - -VOID PhSelectAndEnsureVisibleProcessNode( - _In_ PPH_PROCESS_NODE ProcessNode - ) -{ - PhSelectAndEnsureVisibleProcessNodes(&ProcessNode, 1); -} - -VOID PhSelectAndEnsureVisibleProcessNodes( - _In_ PPH_PROCESS_NODE *ProcessNodes, - _In_ ULONG NumberOfProcessNodes - ) -{ - ULONG i; - PPH_PROCESS_NODE leader = NULL; - PPH_PROCESS_NODE node; - BOOLEAN needsRestructure = FALSE; - - PhDeselectAllProcessNodes(); - - for (i = 0; i < NumberOfProcessNodes; i++) - { - if (ProcessNodes[i]->Node.Visible) - { - leader = ProcessNodes[i]; - break; - } - } - - if (!leader) - return; - - // Expand recursively upwards, and select the nodes. - - for (i = 0; i < NumberOfProcessNodes; i++) - { - if (!ProcessNodes[i]->Node.Visible) - continue; - - node = ProcessNodes[i]->Parent; - - while (node) - { - if (!node->Node.Expanded) - needsRestructure = TRUE; - - node->Node.Expanded = TRUE; - node = node->Parent; - } - - ProcessNodes[i]->Node.Selected = TRUE; - } - - if (needsRestructure) - TreeNew_NodesStructured(ProcessTreeListHandle); - - TreeNew_SetFocusNode(ProcessTreeListHandle, &leader->Node); - TreeNew_SetMarkNode(ProcessTreeListHandle, &leader->Node); - TreeNew_EnsureVisible(ProcessTreeListHandle, &leader->Node); - TreeNew_InvalidateNode(ProcessTreeListHandle, &leader->Node); -} - -VOID PhpPopulateTableWithProcessNodes( - _In_ HWND TreeListHandle, - _In_ PPH_PROCESS_NODE Node, - _In_ ULONG Level, - _In_ PPH_STRING **Table, - _Inout_ PULONG Index, - _In_ PULONG DisplayToId, - _In_ ULONG Columns - ) -{ - ULONG i; - - for (i = 0; i < Columns; i++) - { - PH_TREENEW_GET_CELL_TEXT getCellText; - PPH_STRING text; - - getCellText.Node = &Node->Node; - getCellText.Id = DisplayToId[i]; - PhInitializeEmptyStringRef(&getCellText.Text); - TreeNew_GetCellText(TreeListHandle, &getCellText); - - if (i != 0) - { - text = PhaCreateStringEx(getCellText.Text.Buffer, getCellText.Text.Length); - } - else - { - // If this is the first column in the row, add some indentation. - text = PhaCreateStringEx( - NULL, - getCellText.Text.Length + Level * 2 * sizeof(WCHAR) - ); - wmemset(text->Buffer, ' ', Level * 2); - memcpy(&text->Buffer[Level * 2], getCellText.Text.Buffer, getCellText.Text.Length); - } - - Table[*Index][i] = text; - } - - (*Index)++; - - // Process the children. - for (i = 0; i < Node->Children->Count; i++) - { - PhpPopulateTableWithProcessNodes( - TreeListHandle, - Node->Children->Items[i], - Level + 1, - Table, - Index, - DisplayToId, - Columns - ); - } -} - -PPH_LIST PhGetProcessTreeListLines( - _In_ HWND TreeListHandle, - _In_ ULONG NumberOfNodes, - _In_ PPH_LIST RootNodes, - _In_ ULONG Mode - ) -{ - PH_AUTO_POOL autoPool; - PPH_LIST lines; - // The number of rows in the table (including +1 for the column headers). - ULONG rows; - // The number of columns. - ULONG columns; - // A column display index to ID map. - PULONG displayToId; - // A column display index to text map. - PWSTR *displayToText; - // The actual string table. - PPH_STRING **table; - ULONG i; - ULONG j; - - // Use a local auto-pool to make memory mangement a bit less painful. - PhInitializeAutoPool(&autoPool); - - rows = NumberOfNodes + 1; - - // Create the display index to ID map. - PhMapDisplayIndexTreeNew(TreeListHandle, &displayToId, &displayToText, &columns); - - PhaCreateTextTable(&table, rows, columns); - - // Populate the first row with the column headers. - for (i = 0; i < columns; i++) - { - table[0][i] = PhaCreateString(displayToText[i]); - } - - // Go through the nodes in the process tree and populate each cell of the table. - - j = 1; // index starts at one because the first row contains the column headers. - - for (i = 0; i < RootNodes->Count; i++) - { - PhpPopulateTableWithProcessNodes( - TreeListHandle, - RootNodes->Items[i], - 0, - table, - &j, - displayToId, - columns - ); - } - - PhFree(displayToId); - PhFree(displayToText); - - lines = PhaFormatTextTable(table, rows, columns, Mode); - - PhDeleteAutoPool(&autoPool); - - return lines; -} - -VOID PhCopyProcessTree( - VOID - ) -{ - PPH_STRING text; - - text = PhGetTreeNewText(ProcessTreeListHandle, 0); - PhSetClipboardString(ProcessTreeListHandle, &text->sr); - PhDereferenceObject(text); -} - -VOID PhWriteProcessTree( - _Inout_ PPH_FILE_STREAM FileStream, - _In_ ULONG Mode - ) -{ - PPH_LIST lines; - ULONG i; - - lines = PhGetProcessTreeListLines( - ProcessTreeListHandle, - ProcessNodeList->Count, - ProcessNodeRootList, - Mode - ); - - for (i = 0; i < lines->Count; i++) - { - PPH_STRING line; - - line = lines->Items[i]; - PhWriteStringAsUtf8FileStream(FileStream, &line->sr); - PhDereferenceObject(line); - PhWriteStringAsUtf8FileStream2(FileStream, L"\r\n"); - } - - PhDereferenceObject(lines); -} - -PPH_LIST PhDuplicateProcessNodeList( - VOID - ) -{ - PPH_LIST newList; - - newList = PhCreateList(ProcessNodeList->Count); - PhInsertItemsList(newList, 0, ProcessNodeList->Items, ProcessNodeList->Count); - - return newList; -} +/* + * Process Hacker - + * process tree list + * + * Copyright (C) 2010-2016 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +/* + * The process tree list manages a list of tree nodes and handles callback events generated by the + * underlying treenew control. Retrieval of certain types of process information is also performed + * here, on the GUI thread (see PH_PROCESS_NODE.ValidMask). This is done for columns that require + * data not supplied by the process provider. + */ + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +typedef enum _PHP_AGGREGATE_TYPE +{ + AggregateTypeFloat, + AggregateTypeInt32, + AggregateTypeInt64, + AggregateTypeIntPtr +} PHP_AGGREGATE_TYPE; + +typedef enum _PHP_AGGREGATE_LOCATION +{ + AggregateLocationProcessNode, + AggregateLocationProcessItem +} PHP_AGGREGATE_LOCATION; + +VOID PhpRemoveProcessNode( + _In_ PPH_PROCESS_NODE ProcessNode + ); + +VOID PhpUpdateNeedCyclesInformation( + VOID + ); + +VOID PhpUpdateProcessNodeCycles( + _Inout_ PPH_PROCESS_NODE ProcessNode + ); + +LONG PhpProcessTreeNewPostSortFunction( + _In_ LONG Result, + _In_ PVOID Node1, + _In_ PVOID Node2, + _In_ PH_SORT_ORDER SortOrder + ); + +BOOLEAN NTAPI PhpProcessTreeNewCallback( + _In_ HWND hwnd, + _In_ PH_TREENEW_MESSAGE Message, + _In_opt_ PVOID Parameter1, + _In_opt_ PVOID Parameter2, + _In_opt_ PVOID Context + ); + +static HWND ProcessTreeListHandle; +static ULONG ProcessTreeListSortColumn; +static PH_SORT_ORDER ProcessTreeListSortOrder; +static PH_CM_MANAGER ProcessTreeListCm; + +static PPH_HASH_ENTRY ProcessNodeHashSet[256] = PH_HASH_SET_INIT; // hashtable of all nodes +static PPH_LIST ProcessNodeList; // list of all nodes, used when sorting is enabled +static PPH_LIST ProcessNodeRootList; // list of root nodes + +BOOLEAN PhProcessTreeListStateHighlighting = TRUE; +static PPH_POINTER_LIST ProcessNodeStateList = NULL; // list of nodes which need to be processed + +static PH_TN_FILTER_SUPPORT FilterSupport; +static BOOLEAN NeedCyclesInformation = FALSE; + +static HDC GraphContext = NULL; +static ULONG GraphContextWidth = 0; +static ULONG GraphContextHeight = 0; +static HBITMAP GraphOldBitmap; +static HBITMAP GraphBitmap = NULL; +static PVOID GraphBits = NULL; + +VOID PhProcessTreeListInitialization( + VOID + ) +{ + ProcessNodeList = PhCreateList(40); + ProcessNodeRootList = PhCreateList(10); +} + +VOID PhInitializeProcessTreeList( + _In_ HWND hwnd + ) +{ + ProcessTreeListHandle = hwnd; + PhSetControlTheme(ProcessTreeListHandle, L"explorer"); + TreeNew_SetExtendedFlags(hwnd, TN_FLAG_ITEM_DRAG_SELECT, TN_FLAG_ITEM_DRAG_SELECT); + SendMessage(TreeNew_GetTooltips(ProcessTreeListHandle), TTM_SETDELAYTIME, TTDT_AUTOPOP, MAXSHORT); + + TreeNew_SetCallback(hwnd, PhpProcessTreeNewCallback, NULL); + + TreeNew_SetMaxId(hwnd, PHPRTLC_MAXIMUM - 1); + + TreeNew_SetRedraw(hwnd, FALSE); + + // Default columns + PhAddTreeNewColumn(hwnd, PHPRTLC_NAME, TRUE, L"Name", 200, PH_ALIGN_LEFT, -2, 0); + PhAddTreeNewColumn(hwnd, PHPRTLC_PID, TRUE, L"PID", 50, PH_ALIGN_RIGHT, 0, DT_RIGHT); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_CPU, TRUE, L"CPU", 45, PH_ALIGN_RIGHT, 1, DT_RIGHT, TRUE); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_IOTOTALRATE, TRUE, L"I/O total rate", 70, PH_ALIGN_RIGHT, 2, DT_RIGHT, TRUE); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_PRIVATEBYTES, TRUE, L"Private bytes", 70, PH_ALIGN_RIGHT, 3, DT_RIGHT, TRUE); + PhAddTreeNewColumn(hwnd, PHPRTLC_USERNAME, TRUE, L"User name", 140, PH_ALIGN_LEFT, 4, DT_PATH_ELLIPSIS); + PhAddTreeNewColumn(hwnd, PHPRTLC_DESCRIPTION, TRUE, L"Description", 180, PH_ALIGN_LEFT, 5, 0); + + // Customizable columns (1) + PhAddTreeNewColumn(hwnd, PHPRTLC_COMPANYNAME, FALSE, L"Company name", 180, PH_ALIGN_LEFT, -1, 0); + PhAddTreeNewColumn(hwnd, PHPRTLC_VERSION, FALSE, L"Version", 100, PH_ALIGN_LEFT, -1, 0); + PhAddTreeNewColumn(hwnd, PHPRTLC_FILENAME, FALSE, L"File name", 180, PH_ALIGN_LEFT, -1, DT_PATH_ELLIPSIS); + PhAddTreeNewColumn(hwnd, PHPRTLC_COMMANDLINE, FALSE, L"Command line", 180, PH_ALIGN_LEFT, -1, 0); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_PEAKPRIVATEBYTES, FALSE, L"Peak private bytes", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_WORKINGSET, FALSE, L"Working set", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_PEAKWORKINGSET, FALSE, L"Peak working set", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_PRIVATEWS, FALSE, L"Private WS", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_SHAREDWS, FALSE, L"Shared WS", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_SHAREABLEWS, FALSE, L"Shareable WS", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_VIRTUALSIZE, FALSE, L"Virtual size", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_PEAKVIRTUALSIZE, FALSE, L"Peak virtual size", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_PAGEFAULTS, FALSE, L"Page faults", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); + PhAddTreeNewColumn(hwnd, PHPRTLC_SESSIONID, FALSE, L"Session ID", 45, PH_ALIGN_RIGHT, -1, DT_RIGHT); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_PRIORITYCLASS, FALSE, L"Priority class", 100, PH_ALIGN_LEFT, -1, 0, TRUE); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_BASEPRIORITY, FALSE, L"Base priority", 45, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); + + // Customizable columns (2) + PhAddTreeNewColumnEx(hwnd, PHPRTLC_THREADS, FALSE, L"Threads", 45, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_HANDLES, FALSE, L"Handles", 45, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_GDIHANDLES, FALSE, L"GDI handles", 45, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_USERHANDLES, FALSE, L"USER handles", 45, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_IORORATE, FALSE, L"I/O read+other rate", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_IOWRATE, FALSE, L"I/O write rate", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); + PhAddTreeNewColumn(hwnd, PHPRTLC_INTEGRITY, FALSE, L"Integrity", 100, PH_ALIGN_LEFT, -1, 0); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_IOPRIORITY, FALSE, L"I/O priority", 70, PH_ALIGN_LEFT, -1, 0, TRUE); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_PAGEPRIORITY, FALSE, L"Page priority", 45, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_STARTTIME, FALSE, L"Start time", 100, PH_ALIGN_LEFT, -1, 0, TRUE); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_TOTALCPUTIME, FALSE, L"Total CPU time", 90, PH_ALIGN_LEFT, -1, 0, TRUE); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_KERNELCPUTIME, FALSE, L"Kernel CPU time", 90, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_USERCPUTIME, FALSE, L"User CPU time", 90, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); + PhAddTreeNewColumn(hwnd, PHPRTLC_VERIFICATIONSTATUS, FALSE, L"Verification status", 70, PH_ALIGN_LEFT, -1, 0); + PhAddTreeNewColumn(hwnd, PHPRTLC_VERIFIEDSIGNER, FALSE, L"Verified signer", 100, PH_ALIGN_LEFT, -1, 0); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_ASLR, FALSE, L"ASLR", 50, PH_ALIGN_LEFT, -1, 0, TRUE); + PhAddTreeNewColumn(hwnd, PHPRTLC_RELATIVESTARTTIME, FALSE, L"Relative start time", 180, PH_ALIGN_LEFT, -1, 0); + PhAddTreeNewColumn(hwnd, PHPRTLC_BITS, FALSE, L"Bits", 50, PH_ALIGN_LEFT, -1, 0); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_ELEVATION, FALSE, L"Elevation", 60, PH_ALIGN_LEFT, -1, 0, TRUE); + PhAddTreeNewColumn(hwnd, PHPRTLC_WINDOWTITLE, FALSE, L"Window title", 120, PH_ALIGN_LEFT, -1, 0); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_WINDOWSTATUS, FALSE, L"Window status", 60, PH_ALIGN_LEFT, -1, 0, TRUE); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_CYCLES, FALSE, L"Cycles", 110, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_CYCLESDELTA, FALSE, L"Cycles delta", 90, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); + PhAddTreeNewColumnEx2(hwnd, PHPRTLC_CPUHISTORY, FALSE, L"CPU history", 100, PH_ALIGN_LEFT, -1, 0, TN_COLUMN_FLAG_CUSTOMDRAW | TN_COLUMN_FLAG_SORTDESCENDING); + PhAddTreeNewColumnEx2(hwnd, PHPRTLC_PRIVATEBYTESHISTORY, FALSE, L"Private bytes history", 100, PH_ALIGN_LEFT, -1, 0, TN_COLUMN_FLAG_CUSTOMDRAW | TN_COLUMN_FLAG_SORTDESCENDING); + PhAddTreeNewColumnEx2(hwnd, PHPRTLC_IOHISTORY, FALSE, L"I/O history", 100, PH_ALIGN_LEFT, -1, 0, TN_COLUMN_FLAG_CUSTOMDRAW | TN_COLUMN_FLAG_SORTDESCENDING); + PhAddTreeNewColumn(hwnd, PHPRTLC_DEP, FALSE, L"DEP", 100, PH_ALIGN_LEFT, -1, 0); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_VIRTUALIZED, FALSE, L"Virtualized", 80, PH_ALIGN_LEFT, -1, 0, TRUE); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_CONTEXTSWITCHES, FALSE, L"Context switches", 100, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_CONTEXTSWITCHESDELTA, FALSE, L"Context switches delta", 80, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_PAGEFAULTSDELTA, FALSE, L"Page faults delta", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); + + // I/O group columns + PhAddTreeNewColumnEx(hwnd, PHPRTLC_IOREADS, FALSE, L"I/O reads", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_IOWRITES, FALSE, L"I/O writes", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_IOOTHER, FALSE, L"I/O other", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_IOREADBYTES, FALSE, L"I/O read bytes", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_IOWRITEBYTES, FALSE, L"I/O write bytes", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_IOOTHERBYTES, FALSE, L"I/O other bytes", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_IOREADSDELTA, FALSE, L"I/O reads delta", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_IOWRITESDELTA, FALSE, L"I/O writes delta", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_IOOTHERDELTA, FALSE, L"I/O other delta", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); + + // Customizable columns (3) + PhAddTreeNewColumn(hwnd, PHPRTLC_OSCONTEXT, FALSE, L"OS context", 100, PH_ALIGN_LEFT, -1, 0); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_PAGEDPOOL, FALSE, L"Paged pool", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_PEAKPAGEDPOOL, FALSE, L"Peak paged pool", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_NONPAGEDPOOL, FALSE, L"Non-paged pool", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_PEAKNONPAGEDPOOL, FALSE, L"Peak non-paged pool", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_MINIMUMWORKINGSET, FALSE, L"Minimum working set", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_MAXIMUMWORKINGSET, FALSE, L"Maximum working set", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_PRIVATEBYTESDELTA, FALSE, L"Private bytes delta", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); + PhAddTreeNewColumn(hwnd, PHPRTLC_SUBSYSTEM, FALSE, L"Subsystem", 110, PH_ALIGN_LEFT, -1, 0); + PhAddTreeNewColumn(hwnd, PHPRTLC_PACKAGENAME, FALSE, L"Package name", 160, PH_ALIGN_LEFT, -1, 0); + PhAddTreeNewColumn(hwnd, PHPRTLC_APPID, FALSE, L"App ID", 160, PH_ALIGN_LEFT, -1, 0); + PhAddTreeNewColumn(hwnd, PHPRTLC_DPIAWARENESS, FALSE, L"DPI awareness", 110, PH_ALIGN_LEFT, -1, 0); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_CFGUARD, FALSE, L"CF Guard", 70, PH_ALIGN_LEFT, -1, 0, TRUE); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_TIMESTAMP, FALSE, L"Time stamp", 140, PH_ALIGN_LEFT, -1, 0, TRUE); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_FILEMODIFIEDTIME, FALSE, L"File modified time", 140, PH_ALIGN_LEFT, -1, 0, TRUE); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_FILESIZE, FALSE, L"File size", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); + + TreeNew_SetRedraw(hwnd, TRUE); + + TreeNew_SetTriState(hwnd, TRUE); + TreeNew_SetSort(hwnd, 0, NoSortOrder); + + PhCmInitializeManager(&ProcessTreeListCm, hwnd, PHPRTLC_MAXIMUM, PhpProcessTreeNewPostSortFunction); + + if (PhPluginsEnabled) + { + PH_PLUGIN_TREENEW_INFORMATION treeNewInfo; + + treeNewInfo.TreeNewHandle = hwnd; + treeNewInfo.CmData = &ProcessTreeListCm; + PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackProcessTreeNewInitializing), &treeNewInfo); + } + + PhInitializeTreeNewFilterSupport(&FilterSupport, hwnd, ProcessNodeList); +} + +VOID PhLoadSettingsProcessTreeList( + VOID + ) +{ + PPH_STRING settings; + PPH_STRING sortSettings; + + settings = PhGetStringSetting(L"ProcessTreeListColumns"); + sortSettings = PhGetStringSetting(L"ProcessTreeListSort"); + PhCmLoadSettingsEx(ProcessTreeListHandle, &ProcessTreeListCm, 0, &settings->sr, &sortSettings->sr); + PhDereferenceObject(settings); + PhDereferenceObject(sortSettings); + + if (PhGetIntegerSetting(L"EnableInstantTooltips")) + { + SendMessage(TreeNew_GetTooltips(ProcessTreeListHandle), TTM_SETDELAYTIME, TTDT_INITIAL, 0); + } + + PhpUpdateNeedCyclesInformation(); +} + +VOID PhSaveSettingsProcessTreeList( + VOID + ) +{ + PPH_STRING settings; + PPH_STRING sortSettings; + + settings = PhCmSaveSettingsEx(ProcessTreeListHandle, &ProcessTreeListCm, 0, &sortSettings); + PhSetStringSetting2(L"ProcessTreeListColumns", &settings->sr); + PhSetStringSetting2(L"ProcessTreeListSort", &sortSettings->sr); + PhDereferenceObject(settings); + PhDereferenceObject(sortSettings); +} + +VOID PhReloadSettingsProcessTreeList( + VOID + ) +{ + SendMessage(TreeNew_GetTooltips(ProcessTreeListHandle), TTM_SETDELAYTIME, TTDT_INITIAL, + PhGetIntegerSetting(L"EnableInstantTooltips") ? 0 : -1); +} + +struct _PH_TN_FILTER_SUPPORT *PhGetFilterSupportProcessTreeList( + VOID + ) +{ + return &FilterSupport; +} + +FORCEINLINE BOOLEAN PhCompareProcessNode( + _In_ PPH_PROCESS_NODE Value1, + _In_ PPH_PROCESS_NODE Value2 + ) +{ + return Value1->ProcessId == Value2->ProcessId; +} + +FORCEINLINE ULONG PhHashProcessNode( + _In_ PPH_PROCESS_NODE Value + ) +{ + return HandleToUlong(Value->ProcessId) / 4; +} + +FORCEINLINE BOOLEAN PhpValidateParentCreateTime( + _In_ PPH_PROCESS_NODE Child, + _In_ PPH_PROCESS_NODE Parent + ) +{ + return + PH_IS_FAKE_PROCESS_ID(Child->ProcessId) || + Parent->ProcessItem->CreateTime.QuadPart <= Child->ProcessItem->CreateTime.QuadPart; +} + +PPH_PROCESS_NODE PhAddProcessNode( + _In_ PPH_PROCESS_ITEM ProcessItem, + _In_ ULONG RunId + ) +{ + PPH_PROCESS_NODE processNode; + PPH_PROCESS_NODE parentNode; + ULONG i; + + processNode = PhAllocate(PhEmGetObjectSize(EmProcessNodeType, sizeof(PH_PROCESS_NODE))); + memset(processNode, 0, sizeof(PH_PROCESS_NODE)); + PhInitializeTreeNewNode(&processNode->Node); + + if (PhProcessTreeListStateHighlighting && RunId != 1) + { + PhChangeShStateTn( + &processNode->Node, + &processNode->ShState, + &ProcessNodeStateList, + NewItemState, + PhCsColorNew, + NULL + ); + } + + processNode->ProcessId = ProcessItem->ProcessId; + processNode->ProcessItem = ProcessItem; + PhReferenceObject(ProcessItem); + + memset(processNode->TextCache, 0, sizeof(PH_STRINGREF) * PHPRTLC_MAXIMUM); + processNode->Node.TextCache = processNode->TextCache; + processNode->Node.TextCacheSize = PHPRTLC_MAXIMUM; + + processNode->Children = PhCreateList(1); + + // Find this process' parent and add the process to it if we found it. + if ( + (parentNode = PhFindProcessNode(ProcessItem->ParentProcessId)) && + PhpValidateParentCreateTime(processNode, parentNode) + ) + { + PhAddItemList(parentNode->Children, processNode); + processNode->Parent = parentNode; + } + else + { + // No parent, add to root list. + processNode->Parent = NULL; + PhAddItemList(ProcessNodeRootList, processNode); + } + + // Find this process' children and move them to this node. + + for (i = 0; i < ProcessNodeRootList->Count; i++) + { + PPH_PROCESS_NODE node = ProcessNodeRootList->Items[i]; + + if ( + node != processNode && // for cases where the parent PID = PID (e.g. System Idle Process) + node->ProcessItem->ParentProcessId == ProcessItem->ProcessId && + PhpValidateParentCreateTime(node, processNode) + ) + { + node->Parent = processNode; + PhAddItemList(processNode->Children, node); + } + } + + for (i = 0; i < processNode->Children->Count; i++) + { + PhRemoveItemList( + ProcessNodeRootList, + PhFindItemList(ProcessNodeRootList, processNode->Children->Items[i]) + ); + } + + PhAddEntryHashSet( + ProcessNodeHashSet, + PH_HASH_SET_SIZE(ProcessNodeHashSet), + &processNode->HashEntry, + PhHashProcessNode(processNode) + ); + PhAddItemList(ProcessNodeList, processNode); + + if (PhCsCollapseServicesOnStart) + { + static PH_STRINGREF servicesBaseName = PH_STRINGREF_INIT(L"\\services.exe"); + static BOOLEAN servicesFound = FALSE; + static PPH_STRING servicesFileName = NULL; + + if (!servicesFound) + { + if (!servicesFileName) + { + PPH_STRING systemDirectory; + + systemDirectory = PhGetSystemDirectory(); + servicesFileName = PhConcatStringRef2(&systemDirectory->sr, &servicesBaseName); + PhDereferenceObject(systemDirectory); + } + + // If this process is services.exe, collapse the node and free the string. + if ( + ProcessItem->FileName && + PhEqualString(ProcessItem->FileName, servicesFileName, TRUE) + ) + { + processNode->Node.Expanded = FALSE; + PhDereferenceObject(servicesFileName); + servicesFileName = NULL; + servicesFound = TRUE; + } + } + } + + if (WindowsVersion >= WINDOWS_7 && PhEnableCycleCpuUsage && ProcessItem->ProcessId == INTERRUPTS_PROCESS_ID) + PhInitializeStringRef(&processNode->DescriptionText, L"Interrupts and DPCs"); + + if (FilterSupport.FilterList) + processNode->Node.Visible = PhApplyTreeNewFiltersToNode(&FilterSupport, &processNode->Node); + + PhEmCallObjectOperation(EmProcessNodeType, processNode, EmObjectCreate); + + TreeNew_NodesStructured(ProcessTreeListHandle); + + return processNode; +} + +PPH_PROCESS_NODE PhFindProcessNode( + _In_ HANDLE ProcessId + ) +{ + PH_PROCESS_NODE lookupNode; + PPH_HASH_ENTRY entry; + PPH_PROCESS_NODE node; + + lookupNode.ProcessId = ProcessId; + entry = PhFindEntryHashSet( + ProcessNodeHashSet, + PH_HASH_SET_SIZE(ProcessNodeHashSet), + PhHashProcessNode(&lookupNode) + ); + + for (; entry; entry = entry->Next) + { + node = CONTAINING_RECORD(entry, PH_PROCESS_NODE, HashEntry); + + if (PhCompareProcessNode(&lookupNode, node)) + return node; + } + + return NULL; +} + +VOID PhRemoveProcessNode( + _In_ PPH_PROCESS_NODE ProcessNode + ) +{ + // Remove from the hashtable here to avoid problems in case the key is re-used. + PhRemoveEntryHashSet(ProcessNodeHashSet, PH_HASH_SET_SIZE(ProcessNodeHashSet), &ProcessNode->HashEntry); + + if (PhProcessTreeListStateHighlighting) + { + PhChangeShStateTn( + &ProcessNode->Node, + &ProcessNode->ShState, + &ProcessNodeStateList, + RemovingItemState, + PhCsColorRemoved, + ProcessTreeListHandle + ); + } + else + { + PhpRemoveProcessNode(ProcessNode); + } +} + +VOID PhpRemoveProcessNode( + _In_ PPH_PROCESS_NODE ProcessNode + ) +{ + ULONG index; + ULONG i; + + PhEmCallObjectOperation(EmProcessNodeType, ProcessNode, EmObjectDelete); + + if (ProcessNode->Parent) + { + // Remove the node from its parent. + + if ((index = PhFindItemList(ProcessNode->Parent->Children, ProcessNode)) != -1) + PhRemoveItemList(ProcessNode->Parent->Children, index); + } + else + { + // Remove the node from the root list. + + if ((index = PhFindItemList(ProcessNodeRootList, ProcessNode)) != -1) + PhRemoveItemList(ProcessNodeRootList, index); + } + + // Move the node's children to the root list. + for (i = 0; i < ProcessNode->Children->Count; i++) + { + PPH_PROCESS_NODE node = ProcessNode->Children->Items[i]; + + node->Parent = NULL; + PhAddItemList(ProcessNodeRootList, node); + } + + // Remove from list and cleanup. + + if ((index = PhFindItemList(ProcessNodeList, ProcessNode)) != -1) + PhRemoveItemList(ProcessNodeList, index); + + PhDereferenceObject(ProcessNode->Children); + + PhClearReference(&ProcessNode->WindowText); + PhClearReference(&ProcessNode->AppIdText); + + PhClearReference(&ProcessNode->TooltipText); + + PhClearReference(&ProcessNode->IoTotalRateText); + PhClearReference(&ProcessNode->PrivateBytesText); + PhClearReference(&ProcessNode->PeakPrivateBytesText); + PhClearReference(&ProcessNode->WorkingSetText); + PhClearReference(&ProcessNode->PeakWorkingSetText); + PhClearReference(&ProcessNode->PrivateWsText); + PhClearReference(&ProcessNode->SharedWsText); + PhClearReference(&ProcessNode->ShareableWsText); + PhClearReference(&ProcessNode->VirtualSizeText); + PhClearReference(&ProcessNode->PeakVirtualSizeText); + PhClearReference(&ProcessNode->PageFaultsText); + PhClearReference(&ProcessNode->IoRoRateText); + PhClearReference(&ProcessNode->IoWRateText); + PhClearReference(&ProcessNode->StartTimeText); + PhClearReference(&ProcessNode->TotalCpuTimeText); + PhClearReference(&ProcessNode->KernelCpuTimeText); + PhClearReference(&ProcessNode->UserCpuTimeText); + PhClearReference(&ProcessNode->RelativeStartTimeText); + PhClearReference(&ProcessNode->WindowTitleText); + PhClearReference(&ProcessNode->CyclesText); + PhClearReference(&ProcessNode->CyclesDeltaText); + PhClearReference(&ProcessNode->ContextSwitchesText); + PhClearReference(&ProcessNode->ContextSwitchesDeltaText); + PhClearReference(&ProcessNode->PageFaultsDeltaText); + + for (i = 0; i < PHPRTLC_IOGROUP_COUNT; i++) + PhClearReference(&ProcessNode->IoGroupText[i]); + + PhClearReference(&ProcessNode->PagedPoolText); + PhClearReference(&ProcessNode->PeakPagedPoolText); + PhClearReference(&ProcessNode->NonPagedPoolText); + PhClearReference(&ProcessNode->PeakNonPagedPoolText); + PhClearReference(&ProcessNode->MinimumWorkingSetText); + PhClearReference(&ProcessNode->MaximumWorkingSetText); + PhClearReference(&ProcessNode->PrivateBytesDeltaText); + PhClearReference(&ProcessNode->TimeStampText); + PhClearReference(&ProcessNode->FileModifiedTimeText); + PhClearReference(&ProcessNode->FileSizeText); + + PhDeleteGraphBuffers(&ProcessNode->CpuGraphBuffers); + PhDeleteGraphBuffers(&ProcessNode->PrivateGraphBuffers); + PhDeleteGraphBuffers(&ProcessNode->IoGraphBuffers); + + PhDereferenceObject(ProcessNode->ProcessItem); + + PhFree(ProcessNode); + + TreeNew_NodesStructured(ProcessTreeListHandle); +} + +VOID PhUpdateProcessNode( + _In_ PPH_PROCESS_NODE ProcessNode + ) +{ + memset(ProcessNode->TextCache, 0, sizeof(PH_STRINGREF) * PHPRTLC_MAXIMUM); + + if (ProcessNode->TooltipText) + { + PhDereferenceObject(ProcessNode->TooltipText); + ProcessNode->TooltipText = NULL; + } + + PhInvalidateTreeNewNode(&ProcessNode->Node, TN_CACHE_COLOR | TN_CACHE_ICON); + TreeNew_InvalidateNode(ProcessTreeListHandle, &ProcessNode->Node); +} + +VOID PhTickProcessNodes( + VOID + ) +{ + ULONG i; + PH_TREENEW_VIEW_PARTS viewParts; + BOOLEAN fullyInvalidated; + RECT rect; + + // Text invalidation, node updates + + for (i = 0; i < ProcessNodeList->Count; i++) + { + PPH_PROCESS_NODE node = ProcessNodeList->Items[i]; + + // The name and PID never change, so we don't invalidate that. + memset(&node->TextCache[2], 0, sizeof(PH_STRINGREF) * (PHPRTLC_MAXIMUM - 2)); + node->ValidMask &= PHPN_OSCONTEXT | PHPN_IMAGE | PHPN_DPIAWARENESS; // Items that always remain valid + + // Invalidate graph buffers. + node->CpuGraphBuffers.Valid = FALSE; + node->PrivateGraphBuffers.Valid = FALSE; + node->IoGraphBuffers.Valid = FALSE; + + // Updates cycles if necessary. + if (NeedCyclesInformation) + PhpUpdateProcessNodeCycles(node); + } + + fullyInvalidated = FALSE; + + if (ProcessTreeListSortOrder != NoSortOrder) + { + // Force a rebuild to sort the items. + TreeNew_NodesStructured(ProcessTreeListHandle); + fullyInvalidated = TRUE; + } + + // State highlighting + PH_TICK_SH_STATE_TN(PH_PROCESS_NODE, ShState, ProcessNodeStateList, PhpRemoveProcessNode, PhCsHighlightingDuration, ProcessTreeListHandle, TRUE, &fullyInvalidated); + + if (!fullyInvalidated) + { + // The first column doesn't need to be invalidated because the process name never changes, and + // icon changes are handled by the modified event. This small optimization can save more than + // 10 million cycles per update (on my machine). + TreeNew_GetViewParts(ProcessTreeListHandle, &viewParts); + rect.left = viewParts.NormalLeft; + rect.top = viewParts.HeaderHeight; + rect.right = viewParts.ClientRect.right - viewParts.VScrollWidth; + rect.bottom = viewParts.ClientRect.bottom; + InvalidateRect(ProcessTreeListHandle, &rect, FALSE); + } +} + +static VOID PhpNeedGraphContext( + _In_ HDC hdc, + _In_ ULONG Width, + _In_ ULONG Height + ) +{ + BITMAPINFOHEADER header; + + // If we already have a graph context and it's the right size, then return immediately. + if (GraphContextWidth == Width && GraphContextHeight == Height) + return; + + if (GraphContext) + { + // The original bitmap must be selected back into the context, otherwise + // the bitmap can't be deleted. + SelectObject(GraphContext, GraphBitmap); + DeleteObject(GraphBitmap); + DeleteDC(GraphContext); + + GraphContext = NULL; + GraphBitmap = NULL; + GraphBits = NULL; + } + + GraphContext = CreateCompatibleDC(hdc); + + memset(&header, 0, sizeof(BITMAPINFOHEADER)); + header.biSize = sizeof(BITMAPINFOHEADER); + header.biWidth = Width; + header.biHeight = Height; + header.biPlanes = 1; + header.biBitCount = 32; + GraphBitmap = CreateDIBSection(hdc, (BITMAPINFO *)&header, DIB_RGB_COLORS, &GraphBits, NULL, 0); + GraphOldBitmap = SelectObject(GraphContext, GraphBitmap); +} + +static BOOLEAN PhpFormatInt32GroupDigits( + _In_ ULONG Value, + _Out_writes_bytes_(BufferLength) PWCHAR Buffer, + _In_ ULONG BufferLength, + _Out_opt_ PPH_STRINGREF String + ) +{ + PH_FORMAT format; + SIZE_T returnLength; + + PhInitFormatU(&format, Value); + format.Type |= FormatGroupDigits; + + if (PhFormatToBuffer(&format, 1, Buffer, BufferLength, &returnLength)) + { + if (String) + { + String->Buffer = Buffer; + String->Length = returnLength - sizeof(WCHAR); + } + + return TRUE; + } + else + { + return FALSE; + } +} + +FORCEINLINE PVOID PhpFieldForAggregate( + _In_ PPH_PROCESS_NODE ProcessNode, + _In_ PHP_AGGREGATE_LOCATION Location, + _In_ SIZE_T FieldOffset + ) +{ + PVOID object; + + switch (Location) + { + case AggregateLocationProcessNode: + object = ProcessNode; + break; + case AggregateLocationProcessItem: + object = ProcessNode->ProcessItem; + break; + default: + PhRaiseStatus(STATUS_INVALID_PARAMETER); + } + + return PTR_ADD_OFFSET(object, FieldOffset); +} + +FORCEINLINE VOID PhpAccumulateField( + _Inout_ PVOID Accumulator, + _In_ PVOID Value, + _In_ PHP_AGGREGATE_TYPE Type + ) +{ + switch (Type) + { + case AggregateTypeFloat: + *(PFLOAT)Accumulator += *(PFLOAT)Value; + break; + case AggregateTypeInt32: + *(PULONG)Accumulator += *(PULONG)Value; + break; + case AggregateTypeInt64: + *(PULONG64)Accumulator += *(PULONG64)Value; + break; + case AggregateTypeIntPtr: + *(PULONG_PTR)Accumulator += *(PULONG_PTR)Value; + break; + } +} + +static VOID PhpAggregateField( + _In_ PPH_PROCESS_NODE ProcessNode, + _In_ PHP_AGGREGATE_TYPE Type, + _In_ PHP_AGGREGATE_LOCATION Location, + _In_ SIZE_T FieldOffset, + _Inout_ PVOID AggregatedValue + ) +{ + ULONG i; + + PhpAccumulateField(AggregatedValue, PhpFieldForAggregate(ProcessNode, Location, FieldOffset), Type); + + for (i = 0; i < ProcessNode->Children->Count; i++) + { + PhpAggregateField(ProcessNode->Children->Items[i], Type, Location, FieldOffset, AggregatedValue); + } +} + +static VOID PhpAggregateFieldIfNeeded( + _In_ PPH_PROCESS_NODE ProcessNode, + _In_ PHP_AGGREGATE_TYPE Type, + _In_ PHP_AGGREGATE_LOCATION Location, + _In_ SIZE_T FieldOffset, + _Inout_ PVOID AggregatedValue + ) +{ + if (!PhCsPropagateCpuUsage || ProcessNode->Node.Expanded || ProcessTreeListSortOrder != NoSortOrder) + { + PhpAccumulateField(AggregatedValue, PhpFieldForAggregate(ProcessNode, Location, FieldOffset), Type); + } + else + { + PhpAggregateField(ProcessNode, Type, Location, FieldOffset, AggregatedValue); + } +} + +static VOID PhpUpdateProcessNodeWsCounters( + _Inout_ PPH_PROCESS_NODE ProcessNode + ) +{ + if (!(ProcessNode->ValidMask & PHPN_WSCOUNTERS)) + { + BOOLEAN success = FALSE; + HANDLE processHandle; + + if (NT_SUCCESS(PhOpenProcess( + &processHandle, + PROCESS_QUERY_INFORMATION, + ProcessNode->ProcessItem->ProcessId + ))) + { + if (NT_SUCCESS(PhGetProcessWsCounters( + processHandle, + &ProcessNode->WsCounters + ))) + success = TRUE; + + NtClose(processHandle); + } + + if (!success) + memset(&ProcessNode->WsCounters, 0, sizeof(PH_PROCESS_WS_COUNTERS)); + + ProcessNode->ValidMask |= PHPN_WSCOUNTERS; + } +} + +static VOID PhpUpdateProcessNodeGdiUserHandles( + _Inout_ PPH_PROCESS_NODE ProcessNode + ) +{ + if (!(ProcessNode->ValidMask & PHPN_GDIUSERHANDLES)) + { + if (ProcessNode->ProcessItem->QueryHandle) + { + ProcessNode->GdiHandles = GetGuiResources(ProcessNode->ProcessItem->QueryHandle, GR_GDIOBJECTS); + ProcessNode->UserHandles = GetGuiResources(ProcessNode->ProcessItem->QueryHandle, GR_USEROBJECTS); + } + else + { + ProcessNode->GdiHandles = 0; + ProcessNode->UserHandles = 0; + } + + ProcessNode->ValidMask |= PHPN_GDIUSERHANDLES; + } +} + +static VOID PhpUpdateProcessNodeIoPagePriority( + _Inout_ PPH_PROCESS_NODE ProcessNode + ) +{ + if (!(ProcessNode->ValidMask & PHPN_IOPAGEPRIORITY)) + { + if (ProcessNode->ProcessItem->QueryHandle) + { + if (!NT_SUCCESS(PhGetProcessIoPriority(ProcessNode->ProcessItem->QueryHandle, &ProcessNode->IoPriority))) + ProcessNode->IoPriority = -1; + if (!NT_SUCCESS(PhGetProcessPagePriority(ProcessNode->ProcessItem->QueryHandle, &ProcessNode->PagePriority))) + ProcessNode->PagePriority = -1; + } + else + { + ProcessNode->IoPriority = -1; + ProcessNode->PagePriority = -1; + } + + ProcessNode->ValidMask |= PHPN_IOPAGEPRIORITY; + } +} + +static VOID PhpUpdateProcessNodeWindow( + _Inout_ PPH_PROCESS_NODE ProcessNode + ) +{ + if (!(ProcessNode->ValidMask & PHPN_WINDOW)) + { + ProcessNode->WindowHandle = PhGetProcessMainWindow(ProcessNode->ProcessId, ProcessNode->ProcessItem->QueryHandle); + + PhClearReference(&ProcessNode->WindowText); + + if (ProcessNode->WindowHandle) + { + PhGetWindowTextEx(ProcessNode->WindowHandle, PH_GET_WINDOW_TEXT_INTERNAL, &ProcessNode->WindowText); + ProcessNode->WindowHung = !!IsHungAppWindow(ProcessNode->WindowHandle); + } + + ProcessNode->ValidMask |= PHPN_WINDOW; + } +} + +static VOID PhpUpdateProcessNodeDepStatus( + _Inout_ PPH_PROCESS_NODE ProcessNode + ) +{ + if (!(ProcessNode->ValidMask & PHPN_DEPSTATUS)) + { + HANDLE processHandle; + ULONG depStatus; + + depStatus = 0; + +#ifdef _WIN64 + if (ProcessNode->ProcessItem->IsWow64) +#else + if (TRUE) +#endif + { + if (NT_SUCCESS(PhOpenProcess( + &processHandle, + PROCESS_QUERY_INFORMATION, + ProcessNode->ProcessItem->ProcessId + ))) + { + PhGetProcessDepStatus(processHandle, &depStatus); + NtClose(processHandle); + } + } + else + { + if (ProcessNode->ProcessItem->QueryHandle) + depStatus = PH_PROCESS_DEP_ENABLED | PH_PROCESS_DEP_PERMANENT; + } + + ProcessNode->DepStatus = depStatus; + + ProcessNode->ValidMask |= PHPN_DEPSTATUS; + } +} + +static VOID PhpUpdateProcessNodeToken( + _Inout_ PPH_PROCESS_NODE ProcessNode + ) +{ + if (!(ProcessNode->ValidMask & PHPN_TOKEN)) + { + HANDLE tokenHandle; + + ProcessNode->VirtualizationAllowed = FALSE; + ProcessNode->VirtualizationEnabled = FALSE; + + if (WINDOWS_HAS_UAC && ProcessNode->ProcessItem->QueryHandle) + { + if (NT_SUCCESS(PhOpenProcessToken( + ProcessNode->ProcessItem->QueryHandle, + TOKEN_QUERY, + &tokenHandle + ))) + { + if (NT_SUCCESS(PhGetTokenIsVirtualizationAllowed(tokenHandle, &ProcessNode->VirtualizationAllowed)) && + ProcessNode->VirtualizationAllowed) + { + if (!NT_SUCCESS(PhGetTokenIsVirtualizationEnabled(tokenHandle, &ProcessNode->VirtualizationEnabled))) + { + ProcessNode->VirtualizationAllowed = FALSE; // display N/A on error + } + } + + NtClose(tokenHandle); + } + } + + ProcessNode->ValidMask |= PHPN_TOKEN; + } +} + +static VOID PhpUpdateProcessOsContext( + _Inout_ PPH_PROCESS_NODE ProcessNode + ) +{ + if (!(ProcessNode->ValidMask & PHPN_OSCONTEXT)) + { + HANDLE processHandle; + + if (WindowsVersion >= WINDOWS_7) + { + if (NT_SUCCESS(PhOpenProcess(&processHandle, ProcessQueryAccess | PROCESS_VM_READ, ProcessNode->ProcessId))) + { + if (NT_SUCCESS(PhGetProcessSwitchContext(processHandle, &ProcessNode->OsContextGuid))) + { + if (memcmp(&ProcessNode->OsContextGuid, &WINTHRESHOLD_CONTEXT_GUID, sizeof(GUID)) == 0) + ProcessNode->OsContextVersion = WINDOWS_10; + else if (memcmp(&ProcessNode->OsContextGuid, &WINBLUE_CONTEXT_GUID, sizeof(GUID)) == 0) + ProcessNode->OsContextVersion = WINDOWS_8_1; + else if (memcmp(&ProcessNode->OsContextGuid, &WIN8_CONTEXT_GUID, sizeof(GUID)) == 0) + ProcessNode->OsContextVersion = WINDOWS_8; + else if (memcmp(&ProcessNode->OsContextGuid, &WIN7_CONTEXT_GUID, sizeof(GUID)) == 0) + ProcessNode->OsContextVersion = WINDOWS_7; + else if (memcmp(&ProcessNode->OsContextGuid, &VISTA_CONTEXT_GUID, sizeof(GUID)) == 0) + ProcessNode->OsContextVersion = WINDOWS_VISTA; + else if (memcmp(&ProcessNode->OsContextGuid, &XP_CONTEXT_GUID, sizeof(GUID)) == 0) + ProcessNode->OsContextVersion = WINDOWS_XP; + } + + NtClose(processHandle); + } + } + + ProcessNode->ValidMask |= PHPN_OSCONTEXT; + } +} + +static VOID PhpUpdateProcessNodeQuotaLimits( + _Inout_ PPH_PROCESS_NODE ProcessNode + ) +{ + if (!(ProcessNode->ValidMask & PHPN_QUOTALIMITS)) + { + QUOTA_LIMITS quotaLimits; + + if (ProcessNode->ProcessItem->QueryHandle && NT_SUCCESS(NtQueryInformationProcess( + ProcessNode->ProcessItem->QueryHandle, + ProcessQuotaLimits, + "aLimits, + sizeof(QUOTA_LIMITS), + NULL + ))) + { + ProcessNode->MinimumWorkingSetSize = quotaLimits.MinimumWorkingSetSize; + ProcessNode->MaximumWorkingSetSize = quotaLimits.MaximumWorkingSetSize; + } + else + { + ProcessNode->MinimumWorkingSetSize = 0; + ProcessNode->MaximumWorkingSetSize = 0; + } + + ProcessNode->ValidMask |= PHPN_QUOTALIMITS; + } +} + +static VOID PhpUpdateProcessNodeImage( + _Inout_ PPH_PROCESS_NODE ProcessNode + ) +{ + if (!(ProcessNode->ValidMask & PHPN_IMAGE)) + { + HANDLE processHandle; + PROCESS_BASIC_INFORMATION basicInfo; + PVOID imageBaseAddress; + PH_REMOTE_MAPPED_IMAGE mappedImage; + + if (NT_SUCCESS(PhOpenProcess(&processHandle, ProcessQueryAccess | PROCESS_VM_READ, ProcessNode->ProcessId))) + { + if (NT_SUCCESS(PhGetProcessBasicInformation(processHandle, &basicInfo))) + { + if (NT_SUCCESS(NtReadVirtualMemory( + processHandle, + PTR_ADD_OFFSET(basicInfo.PebBaseAddress, FIELD_OFFSET(PEB, ImageBaseAddress)), + &imageBaseAddress, + sizeof(PVOID), + NULL + ))) + { + if (NT_SUCCESS(PhLoadRemoteMappedImage(processHandle, imageBaseAddress, &mappedImage))) + { + ProcessNode->ImageTimeDateStamp = mappedImage.NtHeaders->FileHeader.TimeDateStamp; + ProcessNode->ImageCharacteristics = mappedImage.NtHeaders->FileHeader.Characteristics; + + if (mappedImage.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) + { + ProcessNode->ImageSubsystem = ((PIMAGE_OPTIONAL_HEADER32)&mappedImage.NtHeaders->OptionalHeader)->Subsystem; + ProcessNode->ImageDllCharacteristics = ((PIMAGE_OPTIONAL_HEADER32)&mappedImage.NtHeaders->OptionalHeader)->DllCharacteristics; + } + else if (mappedImage.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) + { + ProcessNode->ImageSubsystem = ((PIMAGE_OPTIONAL_HEADER64)&mappedImage.NtHeaders->OptionalHeader)->Subsystem; + ProcessNode->ImageDllCharacteristics = ((PIMAGE_OPTIONAL_HEADER64)&mappedImage.NtHeaders->OptionalHeader)->DllCharacteristics; + } + + PhUnloadRemoteMappedImage(&mappedImage); + } + } + } + + NtClose(processHandle); + } + + ProcessNode->ValidMask |= PHPN_IMAGE; + } +} + +static VOID PhpUpdateProcessNodeAppId( + _Inout_ PPH_PROCESS_NODE ProcessNode + ) +{ + if (!(ProcessNode->ValidMask & PHPN_APPID)) + { + HANDLE processHandle; + ULONG windowFlags; + PPH_STRING windowTitle; + + PhClearReference(&ProcessNode->AppIdText); + + if (!NT_SUCCESS(PhOpenProcess(&processHandle, ProcessQueryAccess | PROCESS_VM_READ, ProcessNode->ProcessId))) + { + if (WindowsVersion >= WINDOWS_7) + { + if (!NT_SUCCESS(PhOpenProcess(&processHandle, ProcessQueryAccess, ProcessNode->ProcessId))) + goto Done; + } + else + { + goto Done; + } + } + + if (NT_SUCCESS(PhGetProcessWindowTitle( + processHandle, + &windowFlags, + &windowTitle + ))) + { + if (windowFlags & STARTF_TITLEISAPPID) + ProcessNode->AppIdText = windowTitle; + else + PhDereferenceObject(windowTitle); + } + + NtClose(processHandle); + +Done: + ProcessNode->ValidMask |= PHPN_APPID; + } +} + +static VOID PhpUpdateProcessNodeDpiAwareness( + _Inout_ PPH_PROCESS_NODE ProcessNode + ) +{ + static PH_INITONCE initOnce = PH_INITONCE_INIT; + static BOOL (WINAPI *getProcessDpiAwarenessInternal)( + _In_ HANDLE hprocess, + _Out_ ULONG *value + ); + + if (PhBeginInitOnce(&initOnce)) + { + getProcessDpiAwarenessInternal = PhGetModuleProcAddress(L"user32.dll", "GetProcessDpiAwarenessInternal"); + PhEndInitOnce(&initOnce); + } + + if (!getProcessDpiAwarenessInternal) + return; + + if (!(ProcessNode->ValidMask & PHPN_DPIAWARENESS)) + { + if (ProcessNode->ProcessItem->QueryHandle) + { + ULONG dpiAwareness; + + if (getProcessDpiAwarenessInternal(ProcessNode->ProcessItem->QueryHandle, &dpiAwareness)) + ProcessNode->DpiAwareness = dpiAwareness + 1; + } + + ProcessNode->ValidMask |= PHPN_DPIAWARENESS; + } +} + +static VOID PhpUpdateProcessNodeFileAttributes( + _Inout_ PPH_PROCESS_NODE ProcessNode + ) +{ + if (!(ProcessNode->ValidMask & PHPN_FILEATTRIBUTES)) + { + FILE_NETWORK_OPEN_INFORMATION networkOpenInfo; + + if (ProcessNode->ProcessItem->FileName && NT_SUCCESS(PhQueryFullAttributesFileWin32( + ProcessNode->ProcessItem->FileName->Buffer, + &networkOpenInfo + ))) + { + ProcessNode->FileLastWriteTime = networkOpenInfo.LastWriteTime; + ProcessNode->FileEndOfFile = networkOpenInfo.EndOfFile; + } + else + { + ProcessNode->FileEndOfFile.QuadPart = -1; + } + + ProcessNode->ValidMask |= PHPN_FILEATTRIBUTES; + } +} + +static VOID PhpUpdateNeedCyclesInformation( + VOID + ) +{ + PH_TREENEW_COLUMN column; + + NeedCyclesInformation = FALSE; + + // Before Windows Vista, there is no cycle time measurement. + // On Windows 7 and above, cycle time information is available directly from the process item. + // We only need to query cycle time separately for Windows Vista. + if (WindowsVersion != WINDOWS_VISTA) + return; + + TreeNew_GetColumn(ProcessTreeListHandle, PHPRTLC_CYCLES, &column); + + if (column.Visible) + { + NeedCyclesInformation = TRUE; + return; + } + + TreeNew_GetColumn(ProcessTreeListHandle, PHPRTLC_CYCLESDELTA, &column); + + if (column.Visible) + { + NeedCyclesInformation = TRUE; + return; + } +} + +static VOID PhpUpdateProcessNodeCycles( + _Inout_ PPH_PROCESS_NODE ProcessNode + ) +{ + if (ProcessNode->ProcessId == SYSTEM_IDLE_PROCESS_ID) + { + PULARGE_INTEGER idleThreadCycleTimes; + ULONG64 cycleTime; + ULONG i; + + // System Idle Process requires special treatment. + + idleThreadCycleTimes = PhAllocate( + sizeof(ULARGE_INTEGER) * (ULONG)PhSystemBasicInformation.NumberOfProcessors + ); + + if (NT_SUCCESS(NtQuerySystemInformation( + SystemProcessorIdleCycleTimeInformation, + idleThreadCycleTimes, + sizeof(ULARGE_INTEGER) * (ULONG)PhSystemBasicInformation.NumberOfProcessors, + NULL + ))) + { + cycleTime = 0; + + for (i = 0; i < (ULONG)PhSystemBasicInformation.NumberOfProcessors; i++) + cycleTime += idleThreadCycleTimes[i].QuadPart; + + PhUpdateDelta(&ProcessNode->CyclesDelta, cycleTime); + } + + PhFree(idleThreadCycleTimes); + } + else if (ProcessNode->ProcessItem->QueryHandle) + { + ULONG64 cycleTime; + + if (NT_SUCCESS(PhGetProcessCycleTime(ProcessNode->ProcessItem->QueryHandle, &cycleTime))) + { + PhUpdateDelta(&ProcessNode->CyclesDelta, cycleTime); + } + } + + if (ProcessNode->CyclesDelta.Value != 0) + PhMoveReference(&ProcessNode->CyclesText, PhFormatUInt64(ProcessNode->CyclesDelta.Value, TRUE)); + else + PhClearReference(&ProcessNode->CyclesText); + + if (ProcessNode->CyclesDelta.Delta != 0) + PhMoveReference(&ProcessNode->CyclesDeltaText, PhFormatUInt64(ProcessNode->CyclesDelta.Delta, TRUE)); + else + PhClearReference(&ProcessNode->CyclesDeltaText); +} + +#define SORT_FUNCTION(Column) PhpProcessTreeNewCompare##Column + +#define BEGIN_SORT_FUNCTION(Column) static int __cdecl PhpProcessTreeNewCompare##Column( \ + _In_ const void *_elem1, \ + _In_ const void *_elem2 \ + ) \ +{ \ + PPH_PROCESS_NODE node1 = *(PPH_PROCESS_NODE *)_elem1; \ + PPH_PROCESS_NODE node2 = *(PPH_PROCESS_NODE *)_elem2; \ + PPH_PROCESS_ITEM processItem1 = node1->ProcessItem; \ + PPH_PROCESS_ITEM processItem2 = node2->ProcessItem; \ + int sortResult = 0; + +#define END_SORT_FUNCTION \ + if (sortResult == 0) \ + sortResult = intptrcmp((LONG_PTR)processItem1->ProcessId, (LONG_PTR)processItem2->ProcessId); \ + \ + return PhModifySort(sortResult, ProcessTreeListSortOrder); \ +} + +LONG PhpProcessTreeNewPostSortFunction( + _In_ LONG Result, + _In_ PVOID Node1, + _In_ PVOID Node2, + _In_ PH_SORT_ORDER SortOrder + ) +{ + if (Result == 0) + Result = intptrcmp((LONG_PTR)((PPH_PROCESS_NODE)Node1)->ProcessItem->ProcessId, (LONG_PTR)((PPH_PROCESS_NODE)Node2)->ProcessItem->ProcessId); + + return PhModifySort(Result, SortOrder); +} + +BEGIN_SORT_FUNCTION(Name) +{ + sortResult = PhCompareString(processItem1->ProcessName, processItem2->ProcessName, TRUE); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(Pid) +{ + // Use signed int so DPCs and Interrupts are placed above System Idle Process. + sortResult = intptrcmp((LONG_PTR)processItem1->ProcessId, (LONG_PTR)processItem2->ProcessId); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(Cpu) +{ + sortResult = singlecmp(processItem1->CpuUsage, processItem2->CpuUsage); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(IoTotalRate) +{ + sortResult = uint64cmp( + processItem1->IoReadDelta.Delta + processItem1->IoWriteDelta.Delta + processItem1->IoOtherDelta.Delta, + processItem2->IoReadDelta.Delta + processItem2->IoWriteDelta.Delta + processItem2->IoOtherDelta.Delta + ); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(PrivateBytes) +{ + sortResult = uintptrcmp(processItem1->VmCounters.PagefileUsage, processItem2->VmCounters.PagefileUsage); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(UserName) +{ + sortResult = PhCompareStringWithNull(processItem1->UserName, processItem2->UserName, TRUE); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(Description) +{ + PH_STRINGREF sr1; + PH_STRINGREF sr2; + + sr1 = processItem1->VersionInfo.FileDescription ? processItem1->VersionInfo.FileDescription->sr : node1->DescriptionText; + sr2 = processItem2->VersionInfo.FileDescription ? processItem2->VersionInfo.FileDescription->sr : node2->DescriptionText; + + sortResult = PhCompareStringRef(&sr1, &sr2, TRUE); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(CompanyName) +{ + sortResult = PhCompareStringWithNull( + processItem1->VersionInfo.CompanyName, + processItem2->VersionInfo.CompanyName, + TRUE + ); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(Version) +{ + sortResult = PhCompareStringWithNull( + processItem1->VersionInfo.FileVersion, + processItem2->VersionInfo.FileVersion, + TRUE + ); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(FileName) +{ + sortResult = PhCompareStringWithNull( + processItem1->FileName, + processItem2->FileName, + TRUE + ); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(CommandLine) +{ + sortResult = PhCompareStringWithNull( + processItem1->CommandLine, + processItem2->CommandLine, + TRUE + ); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(PeakPrivateBytes) +{ + sortResult = uintptrcmp(processItem1->VmCounters.PeakPagefileUsage, processItem2->VmCounters.PeakPagefileUsage); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(WorkingSet) +{ + sortResult = uintptrcmp(processItem1->VmCounters.WorkingSetSize, processItem2->VmCounters.WorkingSetSize); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(PeakWorkingSet) +{ + sortResult = uintptrcmp(processItem1->VmCounters.PeakWorkingSetSize, processItem2->VmCounters.PeakWorkingSetSize); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(PrivateWs) +{ + PhpUpdateProcessNodeWsCounters(node1); + PhpUpdateProcessNodeWsCounters(node2); + sortResult = uintptrcmp(node1->WsCounters.NumberOfPrivatePages, node2->WsCounters.NumberOfPrivatePages); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(PrivateWsWin7) +{ + sortResult = uintptrcmp(processItem1->WorkingSetPrivateSize, processItem2->WorkingSetPrivateSize); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(SharedWs) +{ + PhpUpdateProcessNodeWsCounters(node1); + PhpUpdateProcessNodeWsCounters(node2); + sortResult = uintptrcmp(node1->WsCounters.NumberOfSharedPages, node2->WsCounters.NumberOfSharedPages); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(ShareableWs) +{ + PhpUpdateProcessNodeWsCounters(node1); + PhpUpdateProcessNodeWsCounters(node2); + sortResult = uintptrcmp(node1->WsCounters.NumberOfShareablePages, node2->WsCounters.NumberOfShareablePages); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(VirtualSize) +{ + sortResult = uintptrcmp(processItem1->VmCounters.VirtualSize, processItem2->VmCounters.VirtualSize); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(PeakVirtualSize) +{ + sortResult = uintptrcmp(processItem1->VmCounters.PeakVirtualSize, processItem2->VmCounters.PeakVirtualSize); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(PageFaults) +{ + sortResult = uintcmp(processItem1->VmCounters.PageFaultCount, processItem2->VmCounters.PageFaultCount); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(SessionId) +{ + sortResult = uintcmp(processItem1->SessionId, processItem2->SessionId); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(BasePriority) +{ + sortResult = intcmp(processItem1->BasePriority, processItem2->BasePriority); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(Threads) +{ + sortResult = uintcmp(processItem1->NumberOfThreads, processItem2->NumberOfThreads); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(Handles) +{ + sortResult = uintcmp(processItem1->NumberOfHandles, processItem2->NumberOfHandles); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(GdiHandles) +{ + sortResult = uintcmp(node1->GdiHandles, node2->GdiHandles); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(UserHandles) +{ + sortResult = uintcmp(node1->UserHandles, node2->UserHandles); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(IoRoRate) +{ + sortResult = uint64cmp( + processItem1->IoReadDelta.Delta + processItem1->IoOtherDelta.Delta, + processItem2->IoReadDelta.Delta + processItem2->IoOtherDelta.Delta + ); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(IoWRate) +{ + sortResult = uint64cmp( + processItem1->IoWriteDelta.Delta, + processItem2->IoWriteDelta.Delta + ); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(Integrity) +{ + sortResult = uintcmp(processItem1->IntegrityLevel, processItem2->IntegrityLevel); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(IoPriority) +{ + sortResult = uintcmp(node1->IoPriority, node2->IoPriority); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(PagePriority) +{ + sortResult = uintcmp(node1->PagePriority, node2->PagePriority); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(StartTime) +{ + sortResult = int64cmp(processItem1->CreateTime.QuadPart, processItem2->CreateTime.QuadPart); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(TotalCpuTime) +{ + sortResult = uint64cmp( + processItem1->KernelTime.QuadPart + processItem1->UserTime.QuadPart, + processItem2->KernelTime.QuadPart + processItem2->UserTime.QuadPart + ); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(KernelCpuTime) +{ + sortResult = uint64cmp( + processItem1->KernelTime.QuadPart, + processItem2->KernelTime.QuadPart + ); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(UserCpuTime) +{ + sortResult = uint64cmp( + processItem1->UserTime.QuadPart, + processItem2->UserTime.QuadPart + ); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(VerificationStatus) +{ + sortResult = intcmp(processItem1->VerifyResult, processItem2->VerifyResult); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(VerifiedSigner) +{ + sortResult = PhCompareStringWithNull( + processItem1->VerifySignerName, + processItem2->VerifySignerName, + TRUE + ); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(Aslr) +{ + PhpUpdateProcessNodeImage(node1); + PhpUpdateProcessNodeImage(node2); + sortResult = intcmp( + node1->ImageDllCharacteristics & IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE, + node2->ImageDllCharacteristics & IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE + ); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(RelativeStartTime) +{ + sortResult = -int64cmp(processItem1->CreateTime.QuadPart, processItem2->CreateTime.QuadPart); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(Bits) +{ + sortResult = intcmp(processItem1->IsWow64Valid, processItem2->IsWow64Valid); + + if (sortResult == 0) + sortResult = intcmp(processItem1->IsWow64, processItem2->IsWow64); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(Elevation) +{ + ULONG key1; + ULONG key2; + + switch (processItem1->ElevationType) + { + case TokenElevationTypeFull: + key1 = 2; + break; + case TokenElevationTypeLimited: + key1 = 1; + break; + default: + key1 = 0; + break; + } + + switch (processItem2->ElevationType) + { + case TokenElevationTypeFull: + key2 = 2; + break; + case TokenElevationTypeLimited: + key2 = 1; + break; + default: + key2 = 0; + break; + } + + sortResult = intcmp(key1, key2); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(WindowTitle) +{ + PhpUpdateProcessNodeWindow(node1); + PhpUpdateProcessNodeWindow(node2); + sortResult = PhCompareStringWithNull(node1->WindowText, node2->WindowText, TRUE); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(WindowStatus) +{ + PhpUpdateProcessNodeWindow(node1); + PhpUpdateProcessNodeWindow(node2); + sortResult = intcmp(node1->WindowHung, node2->WindowHung); + + // Make sure all processes with windows get grouped together. + if (sortResult == 0) + sortResult = intcmp(!!node1->WindowHandle, !!node2->WindowHandle); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(Cycles) +{ + sortResult = uint64cmp(node1->CyclesDelta.Value, node2->CyclesDelta.Value); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(CyclesWin7) +{ + sortResult = uint64cmp(processItem1->CycleTimeDelta.Value, processItem2->CycleTimeDelta.Value); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(CyclesDelta) +{ + sortResult = uint64cmp(node1->CyclesDelta.Delta, node2->CyclesDelta.Delta); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(CyclesDeltaWin7) +{ + sortResult = uint64cmp(processItem1->CycleTimeDelta.Delta, processItem2->CycleTimeDelta.Delta); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(Dep) +{ + PhpUpdateProcessNodeDepStatus(node1); + PhpUpdateProcessNodeDepStatus(node2); + sortResult = uintcmp(node1->DepStatus, node2->DepStatus); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(Virtualized) +{ + PhpUpdateProcessNodeToken(node1); + PhpUpdateProcessNodeToken(node2); + sortResult = intcmp(node1->VirtualizationEnabled, node2->VirtualizationEnabled); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(ContextSwitches) +{ + sortResult = uintcmp(processItem1->ContextSwitchesDelta.Value, processItem2->ContextSwitchesDelta.Value); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(ContextSwitchesDelta) +{ + sortResult = intcmp((LONG)processItem1->ContextSwitchesDelta.Delta, (LONG)processItem2->ContextSwitchesDelta.Delta); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(PageFaultsDelta) +{ + sortResult = uintcmp(processItem1->PageFaultsDelta.Delta, processItem2->PageFaultsDelta.Delta); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(IoReads) +{ + sortResult = uint64cmp(processItem1->IoReadCountDelta.Value, processItem2->IoReadCountDelta.Value); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(IoWrites) +{ + sortResult = uint64cmp(processItem1->IoWriteCountDelta.Value, processItem2->IoWriteCountDelta.Value); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(IoOther) +{ + sortResult = uint64cmp(processItem1->IoOtherCountDelta.Value, processItem2->IoOtherCountDelta.Value); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(IoReadBytes) +{ + sortResult = uint64cmp(processItem1->IoReadDelta.Value, processItem2->IoReadDelta.Value); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(IoWriteBytes) +{ + sortResult = uint64cmp(processItem1->IoWriteDelta.Value, processItem2->IoWriteDelta.Value); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(IoOtherBytes) +{ + sortResult = uint64cmp(processItem1->IoOtherDelta.Value, processItem2->IoOtherDelta.Value); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(IoReadsDelta) +{ + sortResult = uint64cmp(processItem1->IoReadCountDelta.Delta, processItem2->IoReadCountDelta.Delta); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(IoWritesDelta) +{ + sortResult = uint64cmp(processItem1->IoWriteCountDelta.Delta, processItem2->IoWriteCountDelta.Delta); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(IoOtherDelta) +{ + sortResult = uint64cmp(processItem1->IoOtherCountDelta.Delta, processItem2->IoOtherCountDelta.Delta); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(OsContext) +{ + PhpUpdateProcessOsContext(node1); + PhpUpdateProcessOsContext(node2); + sortResult = uintcmp(node1->OsContextVersion, node2->OsContextVersion); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(PagedPool) +{ + sortResult = uintptrcmp(processItem1->VmCounters.QuotaPagedPoolUsage, processItem2->VmCounters.QuotaPagedPoolUsage); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(PeakPagedPool) +{ + sortResult = uintptrcmp(processItem1->VmCounters.QuotaPeakPagedPoolUsage, processItem2->VmCounters.QuotaPeakPagedPoolUsage); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(NonPagedPool) +{ + sortResult = uintptrcmp(processItem1->VmCounters.QuotaNonPagedPoolUsage, processItem2->VmCounters.QuotaNonPagedPoolUsage); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(PeakNonPagedPool) +{ + sortResult = uintptrcmp(processItem1->VmCounters.QuotaPeakNonPagedPoolUsage, processItem2->VmCounters.QuotaPeakNonPagedPoolUsage); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(MinimumWorkingSet) +{ + PhpUpdateProcessNodeQuotaLimits(node1); + PhpUpdateProcessNodeQuotaLimits(node2); + sortResult = uintptrcmp(node1->MinimumWorkingSetSize, node2->MinimumWorkingSetSize); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(MaximumWorkingSet) +{ + PhpUpdateProcessNodeQuotaLimits(node1); + PhpUpdateProcessNodeQuotaLimits(node2); + sortResult = uintptrcmp(node1->MaximumWorkingSetSize, node2->MaximumWorkingSetSize); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(PrivateBytesDelta) +{ + sortResult = intptrcmp(processItem1->PrivateBytesDelta.Delta, processItem2->PrivateBytesDelta.Delta); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(Subsystem) +{ + PhpUpdateProcessNodeImage(node1); + PhpUpdateProcessNodeImage(node2); + sortResult = intcmp(node1->ImageSubsystem, node2->ImageSubsystem); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(PackageName) +{ + sortResult = PhCompareStringWithNull(processItem1->PackageFullName, processItem2->PackageFullName, TRUE); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(AppId) +{ + PhpUpdateProcessNodeAppId(node1); + PhpUpdateProcessNodeAppId(node2); + sortResult = PhCompareStringWithNull(node1->AppIdText, node2->AppIdText, TRUE); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(DpiAwareness) +{ + PhpUpdateProcessNodeDpiAwareness(node1); + PhpUpdateProcessNodeDpiAwareness(node2); + sortResult = uintcmp(node1->DpiAwareness, node2->DpiAwareness); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(CfGuard) +{ + PhpUpdateProcessNodeImage(node1); + PhpUpdateProcessNodeImage(node2); + sortResult = intcmp( + node1->ImageDllCharacteristics & IMAGE_DLLCHARACTERISTICS_GUARD_CF, + node2->ImageDllCharacteristics & IMAGE_DLLCHARACTERISTICS_GUARD_CF + ); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(TimeStamp) +{ + PhpUpdateProcessNodeImage(node1); + PhpUpdateProcessNodeImage(node2); + sortResult = uintcmp(node1->ImageTimeDateStamp, node2->ImageTimeDateStamp); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(FileModifiedTime) +{ + PhpUpdateProcessNodeFileAttributes(node1); + PhpUpdateProcessNodeFileAttributes(node2); + sortResult = int64cmp(node1->FileLastWriteTime.QuadPart, node2->FileLastWriteTime.QuadPart); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(FileSize) +{ + PhpUpdateProcessNodeFileAttributes(node1); + PhpUpdateProcessNodeFileAttributes(node2); + sortResult = int64cmp(node1->FileEndOfFile.QuadPart, node2->FileEndOfFile.QuadPart); +} +END_SORT_FUNCTION + +BOOLEAN NTAPI PhpProcessTreeNewCallback( + _In_ HWND hwnd, + _In_ PH_TREENEW_MESSAGE Message, + _In_opt_ PVOID Parameter1, + _In_opt_ PVOID Parameter2, + _In_opt_ PVOID Context + ) +{ + PPH_PROCESS_NODE node; + + if (PhCmForwardMessage(hwnd, Message, Parameter1, Parameter2, &ProcessTreeListCm)) + return TRUE; + + switch (Message) + { + case TreeNewGetChildren: + { + PPH_TREENEW_GET_CHILDREN getChildren = Parameter1; + + node = (PPH_PROCESS_NODE)getChildren->Node; + + if (ProcessTreeListSortOrder == NoSortOrder) + { + if (!node) + { + getChildren->Children = (PPH_TREENEW_NODE *)ProcessNodeRootList->Items; + getChildren->NumberOfChildren = ProcessNodeRootList->Count; + } + else + { + getChildren->Children = (PPH_TREENEW_NODE *)node->Children->Items; + getChildren->NumberOfChildren = node->Children->Count; + } + } + else + { + if (!node) + { + static PVOID sortFunctions[] = + { + SORT_FUNCTION(Name), + SORT_FUNCTION(Pid), + SORT_FUNCTION(Cpu), + SORT_FUNCTION(IoTotalRate), + SORT_FUNCTION(PrivateBytes), + SORT_FUNCTION(UserName), + SORT_FUNCTION(Description), + SORT_FUNCTION(CompanyName), + SORT_FUNCTION(Version), + SORT_FUNCTION(FileName), + SORT_FUNCTION(CommandLine), + SORT_FUNCTION(PeakPrivateBytes), + SORT_FUNCTION(WorkingSet), + SORT_FUNCTION(PeakWorkingSet), + SORT_FUNCTION(PrivateWs), + SORT_FUNCTION(SharedWs), + SORT_FUNCTION(ShareableWs), + SORT_FUNCTION(VirtualSize), + SORT_FUNCTION(PeakVirtualSize), + SORT_FUNCTION(PageFaults), + SORT_FUNCTION(SessionId), + SORT_FUNCTION(BasePriority), // Priority Class + SORT_FUNCTION(BasePriority), + SORT_FUNCTION(Threads), + SORT_FUNCTION(Handles), + SORT_FUNCTION(GdiHandles), + SORT_FUNCTION(UserHandles), + SORT_FUNCTION(IoRoRate), + SORT_FUNCTION(IoWRate), + SORT_FUNCTION(Integrity), + SORT_FUNCTION(IoPriority), + SORT_FUNCTION(PagePriority), + SORT_FUNCTION(StartTime), + SORT_FUNCTION(TotalCpuTime), + SORT_FUNCTION(KernelCpuTime), + SORT_FUNCTION(UserCpuTime), + SORT_FUNCTION(VerificationStatus), + SORT_FUNCTION(VerifiedSigner), + SORT_FUNCTION(Aslr), + SORT_FUNCTION(RelativeStartTime), + SORT_FUNCTION(Bits), + SORT_FUNCTION(Elevation), + SORT_FUNCTION(WindowTitle), + SORT_FUNCTION(WindowStatus), + SORT_FUNCTION(Cycles), + SORT_FUNCTION(CyclesDelta), + SORT_FUNCTION(Cpu), // CPU History + SORT_FUNCTION(PrivateBytes), // Private Bytes History + SORT_FUNCTION(IoTotalRate), // I/O History + SORT_FUNCTION(Dep), + SORT_FUNCTION(Virtualized), + SORT_FUNCTION(ContextSwitches), + SORT_FUNCTION(ContextSwitchesDelta), + SORT_FUNCTION(PageFaultsDelta), + SORT_FUNCTION(IoReads), + SORT_FUNCTION(IoWrites), + SORT_FUNCTION(IoOther), + SORT_FUNCTION(IoReadBytes), + SORT_FUNCTION(IoWriteBytes), + SORT_FUNCTION(IoOtherBytes), + SORT_FUNCTION(IoReadsDelta), + SORT_FUNCTION(IoWritesDelta), + SORT_FUNCTION(IoOtherDelta), + SORT_FUNCTION(OsContext), + SORT_FUNCTION(PagedPool), + SORT_FUNCTION(PeakPagedPool), + SORT_FUNCTION(NonPagedPool), + SORT_FUNCTION(PeakNonPagedPool), + SORT_FUNCTION(MinimumWorkingSet), + SORT_FUNCTION(MaximumWorkingSet), + SORT_FUNCTION(PrivateBytesDelta), + SORT_FUNCTION(Subsystem), + SORT_FUNCTION(PackageName), + SORT_FUNCTION(AppId), + SORT_FUNCTION(DpiAwareness), + SORT_FUNCTION(CfGuard), + SORT_FUNCTION(TimeStamp), + SORT_FUNCTION(FileModifiedTime), + SORT_FUNCTION(FileSize) + }; + static PH_INITONCE initOnce = PH_INITONCE_INIT; + int (__cdecl *sortFunction)(const void *, const void *); + + if (PhBeginInitOnce(&initOnce)) + { + if (WindowsVersion >= WINDOWS_7) + { + sortFunctions[PHPRTLC_PRIVATEWS] = SORT_FUNCTION(PrivateWsWin7); + sortFunctions[PHPRTLC_CYCLES] = SORT_FUNCTION(CyclesWin7); + sortFunctions[PHPRTLC_CYCLESDELTA] = SORT_FUNCTION(CyclesDeltaWin7); + } + + PhEndInitOnce(&initOnce); + } + + if (!PhCmForwardSort( + (PPH_TREENEW_NODE *)ProcessNodeList->Items, + ProcessNodeList->Count, + ProcessTreeListSortColumn, + ProcessTreeListSortOrder, + &ProcessTreeListCm + )) + { + if (ProcessTreeListSortColumn < PHPRTLC_MAXIMUM) + sortFunction = sortFunctions[ProcessTreeListSortColumn]; + else + sortFunction = NULL; + + if (sortFunction) + { + qsort(ProcessNodeList->Items, ProcessNodeList->Count, sizeof(PVOID), sortFunction); + } + } + + getChildren->Children = (PPH_TREENEW_NODE *)ProcessNodeList->Items; + getChildren->NumberOfChildren = ProcessNodeList->Count; + } + } + } + return TRUE; + case TreeNewIsLeaf: + { + PPH_TREENEW_IS_LEAF isLeaf = Parameter1; + + node = (PPH_PROCESS_NODE)isLeaf->Node; + + if (ProcessTreeListSortOrder == NoSortOrder) + isLeaf->IsLeaf = node->Children->Count == 0; + else + isLeaf->IsLeaf = TRUE; + } + return TRUE; + case TreeNewGetCellText: + { + PPH_TREENEW_GET_CELL_TEXT getCellText = Parameter1; + PPH_PROCESS_ITEM processItem; + + node = (PPH_PROCESS_NODE)getCellText->Node; + processItem = node->ProcessItem; + + switch (getCellText->Id) + { + case PHPRTLC_NAME: + getCellText->Text = processItem->ProcessName->sr; + break; + case PHPRTLC_PID: + PhInitializeStringRefLongHint(&getCellText->Text, processItem->ProcessIdString); + break; + case PHPRTLC_CPU: + { + FLOAT cpuUsage = 0; + + PhpAggregateFieldIfNeeded(node, AggregateTypeFloat, AggregateLocationProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, CpuUsage), &cpuUsage); + cpuUsage *= 100; + + if (cpuUsage >= 0.01) + { + PH_FORMAT format; + SIZE_T returnLength; + + PhInitFormatF(&format, cpuUsage, 2); + + if (PhFormatToBuffer(&format, 1, node->CpuUsageText, sizeof(node->CpuUsageText), &returnLength)) + { + getCellText->Text.Buffer = node->CpuUsageText; + getCellText->Text.Length = returnLength - sizeof(WCHAR); // minus null terminator + } + } + else if (cpuUsage != 0 && PhCsShowCpuBelow001) + { + PH_FORMAT format[2]; + SIZE_T returnLength; + + PhInitFormatS(&format[0], L"< "); + PhInitFormatF(&format[1], 0.01, 2); + + if (PhFormatToBuffer(format, 2, node->CpuUsageText, sizeof(node->CpuUsageText), &returnLength)) + { + getCellText->Text.Buffer = node->CpuUsageText; + getCellText->Text.Length = returnLength - sizeof(WCHAR); + } + } + } + break; + case PHPRTLC_IOTOTALRATE: + { + ULONG64 number = 0; + + if (processItem->IoReadDelta.Delta != processItem->IoReadDelta.Value) // delta is wrong on first run of process provider + { + PhpAggregateFieldIfNeeded(node, AggregateTypeInt64, AggregateLocationProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, IoReadDelta.Delta), &number); + PhpAggregateFieldIfNeeded(node, AggregateTypeInt64, AggregateLocationProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, IoWriteDelta.Delta), &number); + PhpAggregateFieldIfNeeded(node, AggregateTypeInt64, AggregateLocationProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, IoOtherDelta.Delta), &number); + number *= 1000; + number /= PhCsUpdateInterval; + } + + if (number != 0) + { + PH_FORMAT format[2]; + + PhInitFormatSize(&format[0], number); + PhInitFormatS(&format[1], L"/s"); + PhMoveReference(&node->IoTotalRateText, PhFormat(format, 2, 0)); + getCellText->Text = node->IoTotalRateText->sr; + } + } + break; + case PHPRTLC_PRIVATEBYTES: + { + SIZE_T value = 0; + PhpAggregateFieldIfNeeded(node, AggregateTypeIntPtr, AggregateLocationProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, VmCounters.PagefileUsage), &value); + PhMoveReference(&node->PrivateBytesText, PhFormatSize(value, -1)); + getCellText->Text = node->PrivateBytesText->sr; + } + break; + case PHPRTLC_USERNAME: + getCellText->Text = PhGetStringRef(processItem->UserName); + break; + case PHPRTLC_DESCRIPTION: + if (processItem->VersionInfo.FileDescription) + getCellText->Text = processItem->VersionInfo.FileDescription->sr; + else + getCellText->Text = node->DescriptionText; + break; + case PHPRTLC_COMPANYNAME: + getCellText->Text = PhGetStringRef(processItem->VersionInfo.CompanyName); + break; + case PHPRTLC_VERSION: + getCellText->Text = PhGetStringRef(processItem->VersionInfo.FileVersion); + break; + case PHPRTLC_FILENAME: + getCellText->Text = PhGetStringRef(processItem->FileName); + break; + case PHPRTLC_COMMANDLINE: + getCellText->Text = PhGetStringRef(processItem->CommandLine); + break; + case PHPRTLC_PEAKPRIVATEBYTES: + PhMoveReference(&node->PeakPrivateBytesText, PhFormatSize(processItem->VmCounters.PeakPagefileUsage, -1)); + getCellText->Text = node->PeakPrivateBytesText->sr; + break; + case PHPRTLC_WORKINGSET: + { + SIZE_T value = 0; + PhpAggregateFieldIfNeeded(node, AggregateTypeIntPtr, AggregateLocationProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, VmCounters.WorkingSetSize), &value); + PhMoveReference(&node->WorkingSetText, PhFormatSize(value, -1)); + getCellText->Text = node->WorkingSetText->sr; + } + break; + case PHPRTLC_PEAKWORKINGSET: + PhMoveReference(&node->PeakWorkingSetText, PhFormatSize(processItem->VmCounters.PeakWorkingSetSize, -1)); + getCellText->Text = node->PeakWorkingSetText->sr; + break; + case PHPRTLC_PRIVATEWS: + if (WindowsVersion >= WINDOWS_7) + { + PhMoveReference(&node->PrivateWsText, PhFormatSize(processItem->WorkingSetPrivateSize, -1)); + } + else + { + PhpUpdateProcessNodeWsCounters(node); + PhMoveReference(&node->PrivateWsText, PhFormatSize((ULONG64)node->WsCounters.NumberOfPrivatePages * PAGE_SIZE, -1)); + } + getCellText->Text = node->PrivateWsText->sr; + break; + case PHPRTLC_SHAREDWS: + PhpUpdateProcessNodeWsCounters(node); + PhMoveReference(&node->SharedWsText, PhFormatSize((ULONG64)node->WsCounters.NumberOfSharedPages * PAGE_SIZE, -1)); + getCellText->Text = node->SharedWsText->sr; + break; + case PHPRTLC_SHAREABLEWS: + PhpUpdateProcessNodeWsCounters(node); + PhMoveReference(&node->ShareableWsText, PhFormatSize((ULONG64)node->WsCounters.NumberOfShareablePages * PAGE_SIZE, -1)); + getCellText->Text = node->ShareableWsText->sr; + break; + case PHPRTLC_VIRTUALSIZE: + PhMoveReference(&node->VirtualSizeText, PhFormatSize(processItem->VmCounters.VirtualSize, -1)); + getCellText->Text = node->VirtualSizeText->sr; + break; + case PHPRTLC_PEAKVIRTUALSIZE: + PhMoveReference(&node->PeakVirtualSizeText, PhFormatSize(processItem->VmCounters.PeakVirtualSize, -1)); + getCellText->Text = node->PeakVirtualSizeText->sr; + break; + case PHPRTLC_PAGEFAULTS: + PhMoveReference(&node->PageFaultsText, PhFormatUInt64(processItem->VmCounters.PageFaultCount, TRUE)); + getCellText->Text = node->PageFaultsText->sr; + break; + case PHPRTLC_SESSIONID: + PhInitializeStringRefLongHint(&getCellText->Text, processItem->SessionIdString); + break; + case PHPRTLC_PRIORITYCLASS: + PhInitializeStringRefLongHint(&getCellText->Text, PhGetProcessPriorityClassString(processItem->PriorityClass)); + break; + case PHPRTLC_BASEPRIORITY: + PhPrintInt32(node->BasePriorityText, processItem->BasePriority); + PhInitializeStringRefLongHint(&getCellText->Text, node->BasePriorityText); + break; + case PHPRTLC_THREADS: + { + ULONG value = 0; + PhpAggregateFieldIfNeeded(node, AggregateTypeInt32, AggregateLocationProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, NumberOfThreads), &value); + PhpFormatInt32GroupDigits(value, node->ThreadsText, sizeof(node->ThreadsText), &getCellText->Text); + } + break; + case PHPRTLC_HANDLES: + { + ULONG value = 0; + PhpAggregateFieldIfNeeded(node, AggregateTypeInt32, AggregateLocationProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, NumberOfHandles), &value); + PhpFormatInt32GroupDigits(value, node->HandlesText, sizeof(node->HandlesText), &getCellText->Text); + } + break; + case PHPRTLC_GDIHANDLES: + PhpUpdateProcessNodeGdiUserHandles(node); + PhpFormatInt32GroupDigits(node->GdiHandles, node->GdiHandlesText, sizeof(node->GdiHandlesText), &getCellText->Text); + break; + case PHPRTLC_USERHANDLES: + PhpUpdateProcessNodeGdiUserHandles(node); + PhpFormatInt32GroupDigits(node->UserHandles, node->UserHandlesText, sizeof(node->UserHandlesText), &getCellText->Text); + break; + case PHPRTLC_IORORATE: + { + ULONG64 number = 0; + + if (processItem->IoReadDelta.Delta != processItem->IoReadDelta.Value) + { + PhpAggregateFieldIfNeeded(node, AggregateTypeInt64, AggregateLocationProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, IoReadDelta.Delta), &number); + PhpAggregateFieldIfNeeded(node, AggregateTypeInt64, AggregateLocationProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, IoOtherDelta.Delta), &number); + number *= 1000; + number /= PhCsUpdateInterval; + } + + if (number != 0) + { + PH_FORMAT format[2]; + + PhInitFormatSize(&format[0], number); + PhInitFormatS(&format[1], L"/s"); + PhMoveReference(&node->IoRoRateText, PhFormat(format, 2, 0)); + getCellText->Text = node->IoRoRateText->sr; + } + } + break; + case PHPRTLC_IOWRATE: + { + ULONG64 number = 0; + + if (processItem->IoReadDelta.Delta != processItem->IoReadDelta.Value) + { + PhpAggregateFieldIfNeeded(node, AggregateTypeInt64, AggregateLocationProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, IoWriteDelta.Delta), &number); + number *= 1000; + number /= PhCsUpdateInterval; + } + + if (number != 0) + { + PH_FORMAT format[2]; + + PhInitFormatSize(&format[0], number); + PhInitFormatS(&format[1], L"/s"); + PhMoveReference(&node->IoWRateText, PhFormat(format, 2, 0)); + getCellText->Text = node->IoWRateText->sr; + } + } + break; + case PHPRTLC_INTEGRITY: + if (processItem->IntegrityString) + PhInitializeStringRefLongHint(&getCellText->Text, processItem->IntegrityString); + break; + case PHPRTLC_IOPRIORITY: + PhpUpdateProcessNodeIoPagePriority(node); + if (node->IoPriority != -1 && node->IoPriority < MaxIoPriorityTypes) + PhInitializeStringRefLongHint(&getCellText->Text, PhIoPriorityHintNames[node->IoPriority]); + break; + case PHPRTLC_PAGEPRIORITY: + PhpUpdateProcessNodeIoPagePriority(node); + if (node->PagePriority != -1 && node->PagePriority <= MEMORY_PRIORITY_NORMAL) + PhInitializeStringRefLongHint(&getCellText->Text, PhPagePriorityNames[node->PagePriority]); + break; + case PHPRTLC_STARTTIME: + if (processItem->CreateTime.QuadPart != 0) + { + SYSTEMTIME systemTime; + + PhLargeIntegerToLocalSystemTime(&systemTime, &processItem->CreateTime); + PhMoveReference(&node->StartTimeText, PhFormatDateTime(&systemTime)); + getCellText->Text = node->StartTimeText->sr; + } + break; + case PHPRTLC_TOTALCPUTIME: + PhMoveReference(&node->TotalCpuTimeText, PhFormatTimeSpan( + processItem->KernelTime.QuadPart + processItem->UserTime.QuadPart, + PH_TIMESPAN_HMSM + )); + getCellText->Text = node->TotalCpuTimeText->sr; + break; + case PHPRTLC_KERNELCPUTIME: + PhMoveReference(&node->KernelCpuTimeText, PhFormatTimeSpan( + processItem->KernelTime.QuadPart, + PH_TIMESPAN_HMSM + )); + getCellText->Text = node->KernelCpuTimeText->sr; + break; + case PHPRTLC_USERCPUTIME: + PhMoveReference(&node->UserCpuTimeText, PhFormatTimeSpan( + processItem->UserTime.QuadPart, + PH_TIMESPAN_HMSM + )); + getCellText->Text = node->UserCpuTimeText->sr; + break; + case PHPRTLC_VERIFICATIONSTATUS: + if (processItem->VerifyResult == VrTrusted) + PhInitializeStringRef(&getCellText->Text, L"Trusted"); + break; + case PHPRTLC_VERIFIEDSIGNER: + getCellText->Text = PhGetStringRef(processItem->VerifySignerName); + break; + case PHPRTLC_ASLR: + PhpUpdateProcessNodeImage(node); + + if (WindowsVersion >= WINDOWS_VISTA) + { + if (node->ImageDllCharacteristics & IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE) + PhInitializeStringRef(&getCellText->Text, L"ASLR"); + } + else + { + PhInitializeStringRef(&getCellText->Text, L"N/A"); + } + break; + case PHPRTLC_RELATIVESTARTTIME: + { + if (processItem->CreateTime.QuadPart != 0) + { + LARGE_INTEGER currentTime; + PPH_STRING startTimeString; + + PhQuerySystemTime(¤tTime); + startTimeString = PhFormatTimeSpanRelative(currentTime.QuadPart - processItem->CreateTime.QuadPart); + PhMoveReference(&node->RelativeStartTimeText, PhConcatStrings2(startTimeString->Buffer, L" ago")); + PhDereferenceObject(startTimeString); + getCellText->Text = node->RelativeStartTimeText->sr; + } + } + break; + case PHPRTLC_BITS: +#ifdef _WIN64 + if (processItem->IsWow64Valid) + PhInitializeStringRef(&getCellText->Text, processItem->IsWow64 ? L"32" : L"64"); +#else + PhInitializeStringRef(&getCellText->Text, L"32"); +#endif + break; + case PHPRTLC_ELEVATION: + { + PWSTR type; + + if (WINDOWS_HAS_UAC) + { + switch (processItem->ElevationType) + { + case TokenElevationTypeDefault: + type = L"N/A"; + break; + case TokenElevationTypeLimited: + type = L"Limited"; + break; + case TokenElevationTypeFull: + type = L"Full"; + break; + default: + type = L"N/A"; + break; + } + } + else + { + type = L""; + } + + PhInitializeStringRefLongHint(&getCellText->Text, type); + } + break; + case PHPRTLC_WINDOWTITLE: + PhpUpdateProcessNodeWindow(node); + PhSwapReference(&node->WindowTitleText, node->WindowText); + getCellText->Text = PhGetStringRef(node->WindowTitleText); + break; + case PHPRTLC_WINDOWSTATUS: + PhpUpdateProcessNodeWindow(node); + + if (node->WindowHandle) + PhInitializeStringRef(&getCellText->Text, node->WindowHung ? L"Not responding" : L"Running"); + + break; + case PHPRTLC_CYCLES: + if (WindowsVersion >= WINDOWS_7) + { + ULONG64 value = 0; + PhpAggregateFieldIfNeeded(node, AggregateTypeInt64, AggregateLocationProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, CycleTimeDelta.Value), &value); + + if (value != 0) + { + PhMoveReference(&node->CyclesText, PhFormatUInt64(value, TRUE)); + getCellText->Text = node->CyclesText->sr; + } + } + else + { + getCellText->Text = PhGetStringRef(node->CyclesText); + } + break; + case PHPRTLC_CYCLESDELTA: + if (WindowsVersion >= WINDOWS_7) + { + ULONG64 value = 0; + PhpAggregateFieldIfNeeded(node, AggregateTypeInt64, AggregateLocationProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, CycleTimeDelta.Delta), &value); + + if (value != 0) + { + PhMoveReference(&node->CyclesDeltaText, PhFormatUInt64(value, TRUE)); + getCellText->Text = node->CyclesDeltaText->sr; + } + } + else + { + getCellText->Text = PhGetStringRef(node->CyclesDeltaText); + } + break; + case PHPRTLC_DEP: + PhpUpdateProcessNodeDepStatus(node); + + if (node->DepStatus & PH_PROCESS_DEP_ENABLED) + { + if (node->DepStatus & PH_PROCESS_DEP_PERMANENT) + PhInitializeStringRef(&getCellText->Text, L"DEP (permanent)"); + else + PhInitializeStringRef(&getCellText->Text, L"DEP"); + } + + break; + case PHPRTLC_VIRTUALIZED: + PhpUpdateProcessNodeToken(node); + + if (node->VirtualizationEnabled) + PhInitializeStringRef(&getCellText->Text, L"Virtualized"); + + break; + case PHPRTLC_CONTEXTSWITCHES: + if (processItem->ContextSwitchesDelta.Value != 0) + { + PhMoveReference(&node->ContextSwitchesText, PhFormatUInt64(processItem->ContextSwitchesDelta.Value, TRUE)); + getCellText->Text = node->ContextSwitchesText->sr; + } + break; + case PHPRTLC_CONTEXTSWITCHESDELTA: + if ((LONG)processItem->ContextSwitchesDelta.Delta > 0) // the delta may be negative if a thread exits - just don't show anything + { + PhMoveReference(&node->ContextSwitchesDeltaText, PhFormatUInt64(processItem->ContextSwitchesDelta.Delta, TRUE)); + getCellText->Text = node->ContextSwitchesDeltaText->sr; + } + break; + case PHPRTLC_PAGEFAULTSDELTA: + if (processItem->PageFaultsDelta.Delta != 0) + { + PhMoveReference(&node->PageFaultsDeltaText, PhFormatUInt64(processItem->PageFaultsDelta.Delta, TRUE)); + getCellText->Text = node->PageFaultsDeltaText->sr; + } + break; + case PHPRTLC_IOREADS: + if (processItem->IoReadCountDelta.Value != 0) + { + PhMoveReference(&node->IoGroupText[0], PhFormatUInt64(processItem->IoReadCountDelta.Value, TRUE)); + getCellText->Text = node->IoGroupText[0]->sr; + } + break; + case PHPRTLC_IOWRITES: + if (processItem->IoWriteCountDelta.Value != 0) + { + PhMoveReference(&node->IoGroupText[1], PhFormatUInt64(processItem->IoWriteCountDelta.Value, TRUE)); + getCellText->Text = node->IoGroupText[1]->sr; + } + break; + case PHPRTLC_IOOTHER: + if (processItem->IoOtherCountDelta.Value != 0) + { + PhMoveReference(&node->IoGroupText[2], PhFormatUInt64(processItem->IoOtherCountDelta.Value, TRUE)); + getCellText->Text = node->IoGroupText[2]->sr; + } + break; + case PHPRTLC_IOREADBYTES: + if (processItem->IoReadDelta.Value != 0) + { + PhMoveReference(&node->IoGroupText[3], PhFormatSize(processItem->IoReadDelta.Value, -1)); + getCellText->Text = node->IoGroupText[3]->sr; + } + break; + case PHPRTLC_IOWRITEBYTES: + if (processItem->IoWriteDelta.Value != 0) + { + PhMoveReference(&node->IoGroupText[4], PhFormatSize(processItem->IoWriteDelta.Value, -1)); + getCellText->Text = node->IoGroupText[4]->sr; + } + break; + case PHPRTLC_IOOTHERBYTES: + if (processItem->IoOtherDelta.Value != 0) + { + PhMoveReference(&node->IoGroupText[5], PhFormatSize(processItem->IoOtherDelta.Value, -1)); + getCellText->Text = node->IoGroupText[5]->sr; + } + break; + case PHPRTLC_IOREADSDELTA: + if (processItem->IoReadCountDelta.Delta != 0) + { + PhMoveReference(&node->IoGroupText[6], PhFormatUInt64(processItem->IoReadCountDelta.Delta, TRUE)); + getCellText->Text = node->IoGroupText[6]->sr; + } + break; + case PHPRTLC_IOWRITESDELTA: + if (processItem->IoWriteCountDelta.Delta != 0) + { + PhMoveReference(&node->IoGroupText[7], PhFormatUInt64(processItem->IoWriteCountDelta.Delta, TRUE)); + getCellText->Text = node->IoGroupText[7]->sr; + } + break; + case PHPRTLC_IOOTHERDELTA: + if (processItem->IoOtherCountDelta.Delta != 0) + { + PhMoveReference(&node->IoGroupText[8], PhFormatUInt64(processItem->IoOtherCountDelta.Delta, TRUE)); + getCellText->Text = node->IoGroupText[8]->sr; + } + break; + case PHPRTLC_OSCONTEXT: + PhpUpdateProcessOsContext(node); + + if (WindowsVersion >= WINDOWS_7) + { + switch (node->OsContextVersion) + { + case WINDOWS_10: + PhInitializeStringRef(&getCellText->Text, L"Windows 10"); + break; + case WINDOWS_8_1: + PhInitializeStringRef(&getCellText->Text, L"Windows 8.1"); + break; + case WINDOWS_8: + PhInitializeStringRef(&getCellText->Text, L"Windows 8"); + break; + case WINDOWS_7: + PhInitializeStringRef(&getCellText->Text, L"Windows 7"); + break; + case WINDOWS_VISTA: + PhInitializeStringRef(&getCellText->Text, L"Windows Vista"); + break; + case WINDOWS_XP: + PhInitializeStringRef(&getCellText->Text, L"Windows XP"); + break; + } + } + else + { + PhInitializeStringRef(&getCellText->Text, L"N/A"); + } + break; + case PHPRTLC_PAGEDPOOL: + PhMoveReference(&node->PagedPoolText, PhFormatSize(processItem->VmCounters.QuotaPagedPoolUsage, -1)); + getCellText->Text = node->PagedPoolText->sr; + break; + case PHPRTLC_PEAKPAGEDPOOL: + PhMoveReference(&node->PeakPagedPoolText, PhFormatSize(processItem->VmCounters.QuotaPeakPagedPoolUsage, -1)); + getCellText->Text = node->PeakPagedPoolText->sr; + break; + case PHPRTLC_NONPAGEDPOOL: + PhMoveReference(&node->NonPagedPoolText, PhFormatSize(processItem->VmCounters.QuotaNonPagedPoolUsage, -1)); + getCellText->Text = node->NonPagedPoolText->sr; + break; + case PHPRTLC_PEAKNONPAGEDPOOL: + PhMoveReference(&node->PeakNonPagedPoolText, PhFormatSize(processItem->VmCounters.QuotaPeakNonPagedPoolUsage, -1)); + getCellText->Text = node->PeakNonPagedPoolText->sr; + break; + case PHPRTLC_MINIMUMWORKINGSET: + PhpUpdateProcessNodeQuotaLimits(node); + PhMoveReference(&node->MinimumWorkingSetText, PhFormatSize(node->MinimumWorkingSetSize, -1)); + getCellText->Text = node->MinimumWorkingSetText->sr; + break; + case PHPRTLC_MAXIMUMWORKINGSET: + PhpUpdateProcessNodeQuotaLimits(node); + PhMoveReference(&node->MaximumWorkingSetText, PhFormatSize(node->MaximumWorkingSetSize, -1)); + getCellText->Text = node->MaximumWorkingSetText->sr; + break; + case PHPRTLC_PRIVATEBYTESDELTA: + { + LONG_PTR delta; + + delta = processItem->PrivateBytesDelta.Delta; + + if (delta != 0) + { + PH_FORMAT format[2]; + + if (delta > 0) + { + PhInitFormatC(&format[0], '+'); + } + else + { + PhInitFormatC(&format[0], '-'); + delta = -delta; + } + + format[1].Type = SizeFormatType | FormatUseRadix; + format[1].Radix = (UCHAR)PhMaxSizeUnit; + format[1].u.Size = delta; + + PhMoveReference(&node->PrivateBytesDeltaText, PhFormat(format, 2, 0)); + getCellText->Text = node->PrivateBytesDeltaText->sr; + } + } + break; + case PHPRTLC_SUBSYSTEM: + PhpUpdateProcessNodeImage(node); + + switch (node->ImageSubsystem) + { + case 0: + break; + case IMAGE_SUBSYSTEM_NATIVE: + PhInitializeStringRef(&getCellText->Text, L"Native"); + break; + case IMAGE_SUBSYSTEM_WINDOWS_GUI: + PhInitializeStringRef(&getCellText->Text, L"Windows"); + break; + case IMAGE_SUBSYSTEM_WINDOWS_CUI: + PhInitializeStringRef(&getCellText->Text, L"Windows console"); + break; + case IMAGE_SUBSYSTEM_OS2_CUI: + PhInitializeStringRef(&getCellText->Text, L"OS/2"); + break; + case IMAGE_SUBSYSTEM_POSIX_CUI: + PhInitializeStringRef(&getCellText->Text, L"POSIX"); + break; + default: + PhInitializeStringRef(&getCellText->Text, L"Unknown"); + break; + } + break; + case PHPRTLC_PACKAGENAME: + getCellText->Text = PhGetStringRef(processItem->PackageFullName); + break; + case PHPRTLC_APPID: + PhpUpdateProcessNodeAppId(node); + getCellText->Text = PhGetStringRef(node->AppIdText); + break; + case PHPRTLC_DPIAWARENESS: + PhpUpdateProcessNodeDpiAwareness(node); + + switch (node->DpiAwareness) + { + case 0: + break; + case 1: + PhInitializeStringRef(&getCellText->Text, L"Unaware"); + break; + case 2: + PhInitializeStringRef(&getCellText->Text, L"System aware"); + break; + case 3: + PhInitializeStringRef(&getCellText->Text, L"Per-monitor aware"); + break; + } + break; + case PHPRTLC_CFGUARD: + PhpUpdateProcessNodeImage(node); + + if (WindowsVersion >= WINDOWS_8_1) + { + if (node->ImageDllCharacteristics & IMAGE_DLLCHARACTERISTICS_GUARD_CF) + PhInitializeStringRef(&getCellText->Text, L"CF Guard"); + } + else + { + PhInitializeStringRef(&getCellText->Text, L"N/A"); + } + break; + case PHPRTLC_TIMESTAMP: + PhpUpdateProcessNodeImage(node); + + if (node->ImageTimeDateStamp != 0) + { + LARGE_INTEGER time; + SYSTEMTIME systemTime; + + RtlSecondsSince1970ToTime(node->ImageTimeDateStamp, &time); + PhLargeIntegerToLocalSystemTime(&systemTime, &time); + + PhMoveReference(&node->TimeStampText, PhFormatDateTime(&systemTime)); + getCellText->Text = node->TimeStampText->sr; + } + break; + case PHPRTLC_FILEMODIFIEDTIME: + PhpUpdateProcessNodeFileAttributes(node); + + if (node->FileLastWriteTime.QuadPart != 0) + { + SYSTEMTIME systemTime; + + PhLargeIntegerToLocalSystemTime(&systemTime, &node->FileLastWriteTime); + PhMoveReference(&node->FileModifiedTimeText, PhFormatDateTime(&systemTime)); + getCellText->Text = node->FileModifiedTimeText->sr; + } + break; + case PHPRTLC_FILESIZE: + PhpUpdateProcessNodeFileAttributes(node); + + if (node->FileEndOfFile.QuadPart != -1) + { + PhMoveReference(&node->FileSizeText, PhFormatSize(node->FileEndOfFile.QuadPart, -1)); + getCellText->Text = node->FileSizeText->sr; + } + break; + default: + return FALSE; + } + + getCellText->Flags = TN_CACHE; + } + return TRUE; + case TreeNewGetNodeColor: + { + PPH_TREENEW_GET_NODE_COLOR getNodeColor = Parameter1; + PPH_PROCESS_ITEM processItem; + + node = (PPH_PROCESS_NODE)getNodeColor->Node; + processItem = node->ProcessItem; + + if (PhPluginsEnabled) + { + PH_PLUGIN_GET_HIGHLIGHTING_COLOR getHighlightingColor; + + getHighlightingColor.Parameter = processItem; + getHighlightingColor.BackColor = RGB(0xff, 0xff, 0xff); + getHighlightingColor.Handled = FALSE; + getHighlightingColor.Cache = FALSE; + + PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackGetProcessHighlightingColor), &getHighlightingColor); + + if (getHighlightingColor.Handled) + { + getNodeColor->BackColor = getHighlightingColor.BackColor; + getNodeColor->Flags = TN_AUTO_FORECOLOR; + + if (getHighlightingColor.Cache) + getNodeColor->Flags |= TN_CACHE; + + return TRUE; + } + } + + if (!processItem) + ; // Dummy + else if (PhCsUseColorDebuggedProcesses && processItem->IsBeingDebugged) + getNodeColor->BackColor = PhCsColorDebuggedProcesses; + else if (PhCsUseColorSuspended && processItem->IsSuspended) + getNodeColor->BackColor = PhCsColorSuspended; + else if (PhCsUseColorElevatedProcesses && processItem->IsElevated) + getNodeColor->BackColor = PhCsColorElevatedProcesses; + else if (PhCsUseColorPicoProcesses && processItem->IsSubsystemProcess) + getNodeColor->BackColor = PhCsColorPicoProcesses; + else if (PhCsUseColorImmersiveProcesses && processItem->IsImmersive) + getNodeColor->BackColor = PhCsColorImmersiveProcesses; + else if (PhCsUseColorDotNet && processItem->IsDotNet) + getNodeColor->BackColor = PhCsColorDotNet; + else if (PhCsUseColorPacked && processItem->IsPacked) + getNodeColor->BackColor = PhCsColorPacked; + else if (PhCsUseColorWow64Processes && processItem->IsWow64) + getNodeColor->BackColor = PhCsColorWow64Processes; + else if (PhCsUseColorJobProcesses && processItem->IsInSignificantJob) + getNodeColor->BackColor = PhCsColorJobProcesses; + else if (PhCsUseColorServiceProcesses && processItem->ServiceList && processItem->ServiceList->Count != 0) + getNodeColor->BackColor = PhCsColorServiceProcesses; + else if ( + PhCsUseColorSystemProcesses && + processItem->UserName && + PhEqualString(processItem->UserName, PhLocalSystemName, TRUE) + ) + getNodeColor->BackColor = PhCsColorSystemProcesses; + else if ( + PhCsUseColorOwnProcesses && + processItem->UserName && + PhCurrentUserName && + PhEqualString(processItem->UserName, PhCurrentUserName, TRUE) + ) + getNodeColor->BackColor = PhCsColorOwnProcesses; + + getNodeColor->Flags = TN_CACHE | TN_AUTO_FORECOLOR; + } + return TRUE; + case TreeNewGetNodeIcon: + { + PPH_TREENEW_GET_NODE_ICON getNodeIcon = Parameter1; + + node = (PPH_PROCESS_NODE)getNodeIcon->Node; + + if (node->ProcessItem->SmallIcon) + { + getNodeIcon->Icon = node->ProcessItem->SmallIcon; + } + else + { + PhGetStockApplicationIcon(&getNodeIcon->Icon, NULL); + } + + getNodeIcon->Flags = TN_CACHE; + } + return TRUE; + case TreeNewGetCellTooltip: + { + PPH_TREENEW_GET_CELL_TOOLTIP getCellTooltip = Parameter1; + ULONG tickCount; + + node = (PPH_PROCESS_NODE)getCellTooltip->Node; + + if (getCellTooltip->Column->Id != 0) + return FALSE; + + tickCount = GetTickCount(); + + if ((LONG)(node->TooltipTextValidToTickCount - tickCount) < 0) + PhClearReference(&node->TooltipText); + if (!node->TooltipText) + node->TooltipText = PhGetProcessTooltipText(node->ProcessItem, &node->TooltipTextValidToTickCount); + + if (!PhIsNullOrEmptyString(node->TooltipText)) + { + getCellTooltip->Text = node->TooltipText->sr; + getCellTooltip->Unfolding = FALSE; + getCellTooltip->MaximumWidth = -1; + } + else + { + return FALSE; + } + } + return TRUE; + case TreeNewCustomDraw: + { + PPH_TREENEW_CUSTOM_DRAW customDraw = Parameter1; + PPH_PROCESS_ITEM processItem; + RECT rect; + PH_GRAPH_DRAW_INFO drawInfo; + + node = (PPH_PROCESS_NODE)customDraw->Node; + processItem = node->ProcessItem; + rect = customDraw->CellRect; + + if (rect.right - rect.left <= 1) + break; // nothing to draw + + // Generic graph pre-processing + switch (customDraw->Column->Id) + { + case PHPRTLC_CPUHISTORY: + case PHPRTLC_PRIVATEBYTESHISTORY: + case PHPRTLC_IOHISTORY: + memset(&drawInfo, 0, sizeof(PH_GRAPH_DRAW_INFO)); + drawInfo.Width = rect.right - rect.left - 1; // leave a small gap + drawInfo.Height = rect.bottom - rect.top - 1; // leave a small gap + drawInfo.Step = 2; + drawInfo.BackColor = RGB(0x00, 0x00, 0x00); + break; + } + + // Specific graph processing + switch (customDraw->Column->Id) + { + case PHPRTLC_CPUHISTORY: + { + drawInfo.Flags = PH_GRAPH_USE_LINE_2; + drawInfo.LineColor1 = PhCsColorCpuKernel; + drawInfo.LineColor2 = PhCsColorCpuUser; + drawInfo.LineBackColor1 = PhHalveColorBrightness(PhCsColorCpuKernel); + drawInfo.LineBackColor2 = PhHalveColorBrightness(PhCsColorCpuUser); + + PhGetDrawInfoGraphBuffers( + &node->CpuGraphBuffers, + &drawInfo, + processItem->CpuKernelHistory.Count + ); + + if (!node->CpuGraphBuffers.Valid) + { + PhCopyCircularBuffer_FLOAT(&processItem->CpuKernelHistory, + node->CpuGraphBuffers.Data1, drawInfo.LineDataCount); + PhCopyCircularBuffer_FLOAT(&processItem->CpuUserHistory, + node->CpuGraphBuffers.Data2, drawInfo.LineDataCount); + node->CpuGraphBuffers.Valid = TRUE; + } + } + break; + case PHPRTLC_PRIVATEBYTESHISTORY: + { + drawInfo.Flags = 0; + drawInfo.LineColor1 = PhCsColorPrivate; + drawInfo.LineBackColor1 = PhHalveColorBrightness(PhCsColorPrivate); + + PhGetDrawInfoGraphBuffers( + &node->PrivateGraphBuffers, + &drawInfo, + processItem->PrivateBytesHistory.Count + ); + + if (!node->PrivateGraphBuffers.Valid) + { + ULONG i; + FLOAT total; + FLOAT max; + + for (i = 0; i < drawInfo.LineDataCount; i++) + { + node->PrivateGraphBuffers.Data1[i] = + (FLOAT)PhGetItemCircularBuffer_SIZE_T(&processItem->PrivateBytesHistory, i); + } + + // This makes it easier for the user to see what processes are hogging memory. + // Scaling is still *not* consistent across all graphs. + total = (FLOAT)PhPerfInformation.CommittedPages * PAGE_SIZE / 4; // divide by 4 to make the scaling a bit better + max = (FLOAT)processItem->VmCounters.PeakPagefileUsage; + + if (max < total) + max = total; + + if (max != 0) + { + // Scale the data. + PhDivideSinglesBySingle( + node->PrivateGraphBuffers.Data1, + max, + drawInfo.LineDataCount + ); + } + + node->PrivateGraphBuffers.Valid = TRUE; + } + } + break; + case PHPRTLC_IOHISTORY: + { + drawInfo.Flags = PH_GRAPH_USE_LINE_2; + drawInfo.LineColor1 = PhCsColorIoReadOther; + drawInfo.LineColor2 = PhCsColorIoWrite; + drawInfo.LineBackColor1 = PhHalveColorBrightness(PhCsColorIoReadOther); + drawInfo.LineBackColor2 = PhHalveColorBrightness(PhCsColorIoWrite); + + PhGetDrawInfoGraphBuffers( + &node->IoGraphBuffers, + &drawInfo, + processItem->IoReadHistory.Count + ); + + if (!node->IoGraphBuffers.Valid) + { + ULONG i; + FLOAT total; + FLOAT max = 0; + + for (i = 0; i < drawInfo.LineDataCount; i++) + { + FLOAT data1; + FLOAT data2; + + node->IoGraphBuffers.Data1[i] = data1 = + (FLOAT)PhGetItemCircularBuffer_ULONG64(&processItem->IoReadHistory, i) + + (FLOAT)PhGetItemCircularBuffer_ULONG64(&processItem->IoOtherHistory, i); + node->IoGraphBuffers.Data2[i] = data2 = + (FLOAT)PhGetItemCircularBuffer_ULONG64(&processItem->IoWriteHistory, i); + + if (max < data1 + data2) + max = data1 + data2; + } + + // Make the scaling a bit more consistent across the processes. + // It does *not* scale all graphs using the same maximum. + total = (FLOAT)(PhIoReadDelta.Delta + PhIoWriteDelta.Delta + PhIoOtherDelta.Delta); + + if (max < total) + max = total; + + if (max != 0) + { + // Scale the data. + + PhDivideSinglesBySingle( + node->IoGraphBuffers.Data1, + max, + drawInfo.LineDataCount + ); + PhDivideSinglesBySingle( + node->IoGraphBuffers.Data2, + max, + drawInfo.LineDataCount + ); + } + + node->IoGraphBuffers.Valid = TRUE; + } + } + break; + } + + // Draw the graph. + switch (customDraw->Column->Id) + { + case PHPRTLC_CPUHISTORY: + case PHPRTLC_PRIVATEBYTESHISTORY: + case PHPRTLC_IOHISTORY: + PhpNeedGraphContext(customDraw->Dc, drawInfo.Width, drawInfo.Height); + + if (GraphBits) + { + PhDrawGraphDirect(GraphContext, GraphBits, &drawInfo); + BitBlt( + customDraw->Dc, + rect.left, + rect.top + 1, // + 1 for small gap + drawInfo.Width, + drawInfo.Height, + GraphContext, + 0, + 0, + SRCCOPY + ); + } + + break; + } + } + return TRUE; + case TreeNewColumnResized: + { + PPH_TREENEW_COLUMN column = Parameter1; + ULONG i; + + if (column->Id == PHPRTLC_CPUHISTORY || column->Id == PHPRTLC_IOHISTORY || column->Id == PHPRTLC_PRIVATEBYTESHISTORY) + { + for (i = 0; i < ProcessNodeList->Count; i++) + { + node = ProcessNodeList->Items[i]; + + if (column->Id == PHPRTLC_CPUHISTORY) + node->CpuGraphBuffers.Valid = FALSE; + if (column->Id == PHPRTLC_IOHISTORY) + node->IoGraphBuffers.Valid = FALSE; + if (column->Id == PHPRTLC_PRIVATEBYTESHISTORY) + node->PrivateGraphBuffers.Valid = FALSE; + } + } + } + return TRUE; + case TreeNewSortChanged: + { + TreeNew_GetSort(hwnd, &ProcessTreeListSortColumn, &ProcessTreeListSortOrder); + // Force a rebuild to sort the items. + TreeNew_NodesStructured(hwnd); + } + return TRUE; + case TreeNewKeyDown: + { + PPH_TREENEW_KEY_EVENT keyEvent = Parameter1; + + switch (keyEvent->VirtualKey) + { + case 'C': + if (GetKeyState(VK_CONTROL) < 0) + SendMessage(PhMainWndHandle, WM_COMMAND, ID_PROCESS_COPY, 0); + break; + case 'A': + if (GetKeyState(VK_CONTROL) < 0) + TreeNew_SelectRange(ProcessTreeListHandle, 0, -1); + break; + case VK_DELETE: + if (GetKeyState(VK_SHIFT) >= 0) + SendMessage(PhMainWndHandle, WM_COMMAND, ID_PROCESS_TERMINATE, 0); + else + SendMessage(PhMainWndHandle, WM_COMMAND, ID_PROCESS_TERMINATETREE, 0); + break; + case VK_RETURN: + if (GetKeyState(VK_CONTROL) >= 0) + SendMessage(PhMainWndHandle, WM_COMMAND, ID_PROCESS_PROPERTIES, 0); + else + SendMessage(PhMainWndHandle, WM_COMMAND, ID_PROCESS_OPENFILELOCATION, 0); + break; + } + } + return TRUE; + case TreeNewHeaderRightClick: + { + PH_TN_COLUMN_MENU_DATA data; + + data.TreeNewHandle = hwnd; + data.MouseEvent = Parameter1; + data.DefaultSortColumn = 0; + data.DefaultSortOrder = NoSortOrder; + PhInitializeTreeNewColumnMenuEx(&data, PH_TN_COLUMN_MENU_SHOW_RESET_SORT); + + data.Selection = PhShowEMenu(data.Menu, hwnd, PH_EMENU_SHOW_LEFTRIGHT, + PH_ALIGN_LEFT | PH_ALIGN_TOP, data.MouseEvent->ScreenLocation.x, data.MouseEvent->ScreenLocation.y); + PhHandleTreeNewColumnMenu(&data); + + if (data.ProcessedId == PH_TN_COLUMN_MENU_HIDE_COLUMN_ID || data.ProcessedId == PH_TN_COLUMN_MENU_CHOOSE_COLUMNS_ID) + PhpUpdateNeedCyclesInformation(); + + PhDeleteTreeNewColumnMenu(&data); + } + return TRUE; + case TreeNewLeftDoubleClick: + { + SendMessage(PhMainWndHandle, WM_COMMAND, ID_PROCESS_PROPERTIES, 0); + } + return TRUE; + case TreeNewContextMenu: + { + PPH_TREENEW_CONTEXT_MENU contextMenu = Parameter1; + + PhShowProcessContextMenu(contextMenu); + } + return TRUE; + case TreeNewNodeExpanding: + { + node = Parameter1; + + if (PhCsPropagateCpuUsage) + PhUpdateProcessNode(node); + } + return TRUE; + } + + return FALSE; +} + +PPH_PROCESS_ITEM PhGetSelectedProcessItem( + VOID + ) +{ + PPH_PROCESS_ITEM processItem = NULL; + ULONG i; + + for (i = 0; i < ProcessNodeList->Count; i++) + { + PPH_PROCESS_NODE node = ProcessNodeList->Items[i]; + + if (node->Node.Selected) + { + processItem = node->ProcessItem; + break; + } + } + + return processItem; +} + +VOID PhGetSelectedProcessItems( + _Out_ PPH_PROCESS_ITEM **Processes, + _Out_ PULONG NumberOfProcesses + ) +{ + PH_ARRAY array; + ULONG i; + + PhInitializeArray(&array, sizeof(PVOID), 2); + + for (i = 0; i < ProcessNodeList->Count; i++) + { + PPH_PROCESS_NODE node = ProcessNodeList->Items[i]; + + if (node->Node.Selected) + PhAddItemArray(&array, &node->ProcessItem); + } + + *NumberOfProcesses = (ULONG)array.Count; + *Processes = PhFinalArrayItems(&array); +} + +VOID PhDeselectAllProcessNodes( + VOID + ) +{ + TreeNew_DeselectRange(ProcessTreeListHandle, 0, -1); +} + +VOID PhExpandAllProcessNodes( + _In_ BOOLEAN Expand + ) +{ + ULONG i; + BOOLEAN needsRestructure = FALSE; + + for (i = 0; i < ProcessNodeList->Count; i++) + { + PPH_PROCESS_NODE node = ProcessNodeList->Items[i]; + + if (node->Children->Count != 0 && node->Node.Expanded != Expand) + { + node->Node.Expanded = Expand; + needsRestructure = TRUE; + } + } + + if (needsRestructure) + TreeNew_NodesStructured(ProcessTreeListHandle); +} + +VOID PhInvalidateAllProcessNodes( + VOID + ) +{ + ULONG i; + + for (i = 0; i < ProcessNodeList->Count; i++) + { + PPH_PROCESS_NODE node = ProcessNodeList->Items[i]; + + memset(node->TextCache, 0, sizeof(PH_STRINGREF) * PHPRTLC_MAXIMUM); + PhInvalidateTreeNewNode(&node->Node, TN_CACHE_COLOR); + node->ValidMask = 0; + + // Invalidate graph buffers. + node->CpuGraphBuffers.Valid = FALSE; + node->PrivateGraphBuffers.Valid = FALSE; + node->IoGraphBuffers.Valid = FALSE; + } + + InvalidateRect(ProcessTreeListHandle, NULL, FALSE); +} + +VOID PhSelectAndEnsureVisibleProcessNode( + _In_ PPH_PROCESS_NODE ProcessNode + ) +{ + PhSelectAndEnsureVisibleProcessNodes(&ProcessNode, 1); +} + +VOID PhSelectAndEnsureVisibleProcessNodes( + _In_ PPH_PROCESS_NODE *ProcessNodes, + _In_ ULONG NumberOfProcessNodes + ) +{ + ULONG i; + PPH_PROCESS_NODE leader = NULL; + PPH_PROCESS_NODE node; + BOOLEAN needsRestructure = FALSE; + + PhDeselectAllProcessNodes(); + + for (i = 0; i < NumberOfProcessNodes; i++) + { + if (ProcessNodes[i]->Node.Visible) + { + leader = ProcessNodes[i]; + break; + } + } + + if (!leader) + return; + + // Expand recursively upwards, and select the nodes. + + for (i = 0; i < NumberOfProcessNodes; i++) + { + if (!ProcessNodes[i]->Node.Visible) + continue; + + node = ProcessNodes[i]->Parent; + + while (node) + { + if (!node->Node.Expanded) + needsRestructure = TRUE; + + node->Node.Expanded = TRUE; + node = node->Parent; + } + + ProcessNodes[i]->Node.Selected = TRUE; + } + + if (needsRestructure) + TreeNew_NodesStructured(ProcessTreeListHandle); + + TreeNew_SetFocusNode(ProcessTreeListHandle, &leader->Node); + TreeNew_SetMarkNode(ProcessTreeListHandle, &leader->Node); + TreeNew_EnsureVisible(ProcessTreeListHandle, &leader->Node); + TreeNew_InvalidateNode(ProcessTreeListHandle, &leader->Node); +} + +VOID PhpPopulateTableWithProcessNodes( + _In_ HWND TreeListHandle, + _In_ PPH_PROCESS_NODE Node, + _In_ ULONG Level, + _In_ PPH_STRING **Table, + _Inout_ PULONG Index, + _In_ PULONG DisplayToId, + _In_ ULONG Columns + ) +{ + ULONG i; + + for (i = 0; i < Columns; i++) + { + PH_TREENEW_GET_CELL_TEXT getCellText; + PPH_STRING text; + + getCellText.Node = &Node->Node; + getCellText.Id = DisplayToId[i]; + PhInitializeEmptyStringRef(&getCellText.Text); + TreeNew_GetCellText(TreeListHandle, &getCellText); + + if (i != 0) + { + text = PhaCreateStringEx(getCellText.Text.Buffer, getCellText.Text.Length); + } + else + { + // If this is the first column in the row, add some indentation. + text = PhaCreateStringEx( + NULL, + getCellText.Text.Length + Level * 2 * sizeof(WCHAR) + ); + wmemset(text->Buffer, ' ', Level * 2); + memcpy(&text->Buffer[Level * 2], getCellText.Text.Buffer, getCellText.Text.Length); + } + + Table[*Index][i] = text; + } + + (*Index)++; + + // Process the children. + for (i = 0; i < Node->Children->Count; i++) + { + PhpPopulateTableWithProcessNodes( + TreeListHandle, + Node->Children->Items[i], + Level + 1, + Table, + Index, + DisplayToId, + Columns + ); + } +} + +PPH_LIST PhGetProcessTreeListLines( + _In_ HWND TreeListHandle, + _In_ ULONG NumberOfNodes, + _In_ PPH_LIST RootNodes, + _In_ ULONG Mode + ) +{ + PH_AUTO_POOL autoPool; + PPH_LIST lines; + // The number of rows in the table (including +1 for the column headers). + ULONG rows; + // The number of columns. + ULONG columns; + // A column display index to ID map. + PULONG displayToId; + // A column display index to text map. + PWSTR *displayToText; + // The actual string table. + PPH_STRING **table; + ULONG i; + ULONG j; + + // Use a local auto-pool to make memory mangement a bit less painful. + PhInitializeAutoPool(&autoPool); + + rows = NumberOfNodes + 1; + + // Create the display index to ID map. + PhMapDisplayIndexTreeNew(TreeListHandle, &displayToId, &displayToText, &columns); + + PhaCreateTextTable(&table, rows, columns); + + // Populate the first row with the column headers. + for (i = 0; i < columns; i++) + { + table[0][i] = PhaCreateString(displayToText[i]); + } + + // Go through the nodes in the process tree and populate each cell of the table. + + j = 1; // index starts at one because the first row contains the column headers. + + for (i = 0; i < RootNodes->Count; i++) + { + PhpPopulateTableWithProcessNodes( + TreeListHandle, + RootNodes->Items[i], + 0, + table, + &j, + displayToId, + columns + ); + } + + PhFree(displayToId); + PhFree(displayToText); + + lines = PhaFormatTextTable(table, rows, columns, Mode); + + PhDeleteAutoPool(&autoPool); + + return lines; +} + +VOID PhCopyProcessTree( + VOID + ) +{ + PPH_STRING text; + + text = PhGetTreeNewText(ProcessTreeListHandle, 0); + PhSetClipboardString(ProcessTreeListHandle, &text->sr); + PhDereferenceObject(text); +} + +VOID PhWriteProcessTree( + _Inout_ PPH_FILE_STREAM FileStream, + _In_ ULONG Mode + ) +{ + PPH_LIST lines; + ULONG i; + + lines = PhGetProcessTreeListLines( + ProcessTreeListHandle, + ProcessNodeList->Count, + ProcessNodeRootList, + Mode + ); + + for (i = 0; i < lines->Count; i++) + { + PPH_STRING line; + + line = lines->Items[i]; + PhWriteStringAsUtf8FileStream(FileStream, &line->sr); + PhDereferenceObject(line); + PhWriteStringAsUtf8FileStream2(FileStream, L"\r\n"); + } + + PhDereferenceObject(lines); +} + +PPH_LIST PhDuplicateProcessNodeList( + VOID + ) +{ + PPH_LIST newList; + + newList = PhCreateList(ProcessNodeList->Count); + PhInsertItemsList(newList, 0, ProcessNodeList->Items, ProcessNodeList->Count); + + return newList; +} diff --git a/ProcessHacker/resource.h b/ProcessHacker/resource.h index ce6d174476b4..d5f721adb148 100644 --- a/ProcessHacker/resource.h +++ b/ProcessHacker/resource.h @@ -1,751 +1,751 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by ProcessHacker.rc -// -#define IDR_RT_MANIFEST 1 -#define IDI_PROCESSHACKER 101 -#define IDR_MAINWND 102 -#define IDR_MAINWND_ACCEL 102 -#define IDD_PROCGENERAL 103 -#define IDD_PROCMODULES 104 -#define IDD_PROCTHREADS 105 -#define IDD_PROCHANDLES 106 -#define IDD_PROCENVIRONMENT 107 -#define IDD_THRDSTACK 108 -#define IDR_THREAD 110 -#define IDR_HANDLE 111 -#define IDR_MODULE 112 -#define IDC_CPU 112 -#define IDC_PRIVATEBYTES 113 -#define IDC_IO 114 -#define IDB_CROSS 117 -#define IDB_TICK 118 -#define IDC_PHYSICAL 119 -#define IDR_COMPUTER 120 -#define IDC_MEMORY 120 -#define IDD_ABOUT 121 -#define IDC_NEWOBJECTS 121 -#define IDC_REMOVEDOBJECTS 122 -#define IDR_PROCESS 123 -#define IDC_CPUUSER 123 -#define IDR_SERVICE 124 -#define IDC_CPUKERNEL 124 -#define IDC_IORO 125 -#define IDD_SRVLIST 125 -#define IDD_SRVGENERAL 126 -#define IDC_IOW 126 -#define IDD_HNDLGENERAL 128 -#define IDD_INFORMATION 129 -#define IDD_FINDOBJECTS 130 -#define IDD_OBJTOKEN 131 -#define ID_PLUGIN_MENU_ITEM 131 -#define ID_SHOWCONTEXTMENU 132 -#define IDR_PRIVILEGE 133 -#define IDC_SEPARATOR 133 -#define IDR_FINDOBJ 134 -#define IDC_COMMIT 134 -#define IDD_HIDDENPROCESSES 135 -#define ID_TRAYICONS_REGISTERED 135 -#define IDD_RUNAS 136 -#define ID_COPY_CELL 136 -#define IDD_PROGRESS 137 -#define IDD_PAGEFILES 138 -#define IDD_TOKGENERAL 139 -#define IDD_TOKADVANCED 140 -#define IDD_OBJJOB 141 -#define IDD_OBJEVENT 142 -#define IDD_OBJMUTANT 143 -#define IDD_OBJSEMAPHORE 144 -#define IDD_OBJTIMER 145 -#define IDD_JOBSTATISTICS 146 -#define IDD_OBJEVENTPAIR 147 -#define IDD_OBJSECTION 148 -#define IDD_AFFINITY 149 -#define IDD_SYSINFO 150 -#define IDR_USER 151 -#define IDD_EDITMESSAGE 152 -#define IDD_SESSION 153 -#define IDD_PROCMEMORY 154 -#define IDD_CHOOSE 155 -#define IDD_OPTGENERAL 162 -#define IDD_OPTHIGHLIGHTING 163 -#define IDR_NETWORK 164 -#define IDD_CHOOSECOLUMNS 166 -#define IDD_NETSTACK 167 -#define IDD_CREATESERVICE 168 -#define IDD_PROCPERFORMANCE 169 -#define IDD_PROCSTATISTICS 170 -#define IDD_OPTADVANCED 171 -#define IDR_ICON 173 -#define IDD_GDIHANDLES 175 -#define IDD_LOG 178 -#define IDD_OPTSYMBOLS 179 -#define IDD_MEMEDIT 180 -#define IDR_MEMORY 181 -#define IDD_MEMPROTECT 182 -#define IDD_MEMRESULTS 183 -#define IDR_MEMFILTER 184 -#define IDD_MEMSTRING 185 -#define IDD_OPTGRAPHS 186 -#define IDD_PLUGINS 187 -#define IDD_HANDLESTATS 188 -#define IDD_PROCRECORD 189 -#define IDD_CHOOSEPROCESS 190 -#define IDD_PROCSERVICES 191 -#define IDI_PHAPPLICATION 191 -#define IDI_COG 192 -#define IDD_SHADOWSESSION 193 -#define IDI_PHAPPLICATIONGO 194 -#define IDD_TOKCAPABILITIES 194 -#define IDI_COGGO 195 -#define IDD_TOKATTRIBUTES 195 -#define IDD_SYSINFO_CPU 196 -#define IDD_SYSINFO_CPUPANEL 197 -#define IDD_SYSINFO_MEMPANEL 198 -#define IDR_SYSINFO_ACCEL 198 -#define IDD_SYSINFO_MEM 199 -#define IDD_SYSINFO_IO 200 -#define IDD_SYSINFO_IOPANEL 201 -#define IDD_MEMLISTS 202 -#define IDR_EMPTYMEMLISTS 204 -#define IDD_CONTAINER 205 -#define IDD_SYSINFO_MEMPANELXP 206 -#define IDD_MINIINFO 207 -#define IDD_MINIINFO_LIST 210 -#define IDR_MINIINFO 211 -#define IDR_MINIINFO_PROCESS 212 -#define IDR_ENVIRONMENT 214 -#define IDD_MITIGATION 215 -#define IDI_PIN 216 -#define IDI_FOLDER 217 -#define IDI_PENCIL 218 -#define IDI_MAGNIFIER 219 -#define IDD_EDITENV 221 -#define IDB_SEARCH_ACTIVE 223 -#define IDB_SEARCH_INACTIVE 224 -#define IDB_SEARCH_ACTIVE_BMP 225 -#define IDB_SEARCH_INACTIVE_BMP 226 -#define IDC_TERMINATE 1003 -#define IDC_FILEICON 1005 -#define IDC_FILE 1006 -#define IDC_PROCESS 1007 -#define IDC_COMPANYNAME 1009 -#define IDC_VERSION 1010 -#define IDC_REFRESH 1015 -#define IDC_PERMISSIONS 1018 -#define IDC_FILENAME 1020 -#define IDC_CMDLINE 1021 -#define IDC_URL 1021 -#define IDC_RUNSELECTED 1021 -#define IDC_CURDIR 1022 -#define IDC_STARTED 1023 -#define IDC_ABOUT_NAME 1024 -#define IDC_PEBADDRESS 1024 -#define IDC_TERMINATED 1024 -#define IDC_PARENTPROCESS 1025 -#define IDC_MITIGATION 1026 -#define IDC_PAUSE 1027 -#define IDC_PROTECTION 1027 -#define IDC_START 1028 -#define IDC_DESCRIPTION 1029 -#define IDC_TYPE 1032 -#define IDC_STARTTYPE 1033 -#define IDC_ADDRESS 1033 -#define IDC_IMPERSONATIONLEVEL 1033 -#define IDC_ERRORCONTROL 1034 -#define IDC_GRANTED_ACCESS 1034 -#define IDC_TOKENLUID 1034 -#define IDC_GROUP 1035 -#define IDC_AUTHENTICATIONLUID 1035 -#define IDC_BINARYPATH 1036 -#define IDC_MEMORYUSED 1036 -#define IDC_USERACCOUNT 1037 -#define IDC_MEMORYAVAILABLE 1037 -#define IDC_PASSWORD 1040 -#define IDC_PASSWORDCHECK 1041 -#define IDC_SERVICEDLL 1042 -#define IDC_NAME 1044 -#define IDC_REFERENCES 1045 -#define IDC_INTERNALNAME 1045 -#define IDC_HANDLES 1046 -#define IDC_PROCESSTYPELABEL 1046 -#define IDC_AUTHOR 1046 -#define IDC_PAGED 1047 -#define IDC_PROCESSTYPETEXT 1047 -#define IDC_NONPAGED 1048 -#define IDC_TEXT 1048 -#define IDC_DIAGNOSTICS 1049 -#define IDC_FILTER 1050 -#define IDC_RESULTS 1051 -#define IDC_USER 1052 -#define IDC_USERSID 1053 -#define IDC_ADVANCED 1054 -#define IDC_OWNER 1054 -#define IDC_GROUPS 1055 -#define IDC_PRIMARYGROUP 1055 -#define IDC_PRIVILEGES 1056 -#define IDC_VIRTUALIZATION 1056 -#define IDC_SESSIONID 1057 -#define IDC_ELEVATED 1058 -#define IDC_VIRTUALIZED 1059 -#define IDC_SOURCENAME 1059 -#define IDC_PROPERTIES 1060 -#define IDC_SOURCELUID 1060 -#define IDC_APPCONTAINERSID 1060 -#define IDC_LIST 1061 -#define IDC_PROCESSES 1063 -#define IDC_SCAN 1064 -#define IDC_SAVE 1065 -#define IDC_METHOD 1067 -#define IDC_INTRO 1068 -#define IDC_PROGRAM 1069 -#define IDC_BROWSE 1070 -#define IDC_USERNAME 1071 -#define IDC_SESSIONS 1074 -#define IDC_DESKTOPS 1075 -#define IDC_PROGRESS 1076 -#define IDC_PROGRESSTEXT 1077 -#define IDC_LINKEDTOKEN 1079 -#define IDC_DISABLEALL 1079 -#define IDC_MOVEUP 1079 -#define IDC_CHANGE 1079 -#define IDC_CLEAR 1079 -#define IDC_GOTO 1079 -#define IDC_OPTIONS 1079 -#define IDC_DETAILS 1079 -#define IDC_ADD 1079 -#define IDC_FONT 1079 -#define IDC_INTEGRITY 1079 -#define IDC_MORE 1079 -#define IDC_VIEWMITIGATION 1080 -#define IDC_VIEWPARENTPROCESS 1081 -#define IDC_OPENFILENAME 1082 -#define IDC_LIMITS 1083 -#define IDC_SIGNALED 1084 -#define IDC_SET 1085 -#define IDC_RESET 1086 -#define IDC_PULSE 1087 -#define IDC_COUNT 1088 -#define IDC_ABANDONED 1089 -#define IDC_CURRENTCOUNT 1090 -#define IDC_MAXIMUMCOUNT 1091 -#define IDC_ACQUIRE 1092 -#define IDC_RELEASE 1093 -#define IDC_CANCEL 1094 -#define IDC_OWNERLABEL 1095 -#define IDC_SETLOW 1096 -#define IDC_SETHIGH 1097 -#define IDC_SIZE_ 1098 -#define IDC_CPU0 1099 -#define IDC_CPU1 1100 -#define IDC_CPU2 1101 -#define IDC_CPU3 1102 -#define IDC_CPU4 1103 -#define IDC_CPU5 1104 -#define IDC_CPU6 1105 -#define IDC_CPU7 1106 -#define IDC_CPU8 1107 -#define IDC_TITLE 1107 -#define IDC_CPU9 1108 -#define IDC_CPU10 1109 -#define IDC_TIMEOUT 1109 -#define IDC_CPU11 1110 -#define IDC_CPU12 1111 -#define IDC_STATE 1111 -#define IDC_CPU13 1112 -#define IDC_CLIENTNAME 1112 -#define IDC_CPU14 1113 -#define IDC_CLIENTADDRESS 1113 -#define IDC_CPU15 1114 -#define IDC_CLIENTDISPLAY 1114 -#define IDC_CPU16 1115 -#define IDC_CHOICE 1115 -#define IDC_CPU17 1116 -#define IDC_OPTION 1116 -#define IDC_CPU18 1117 -#define IDC_CHOICEUSER 1117 -#define IDC_CPU19 1118 -#define IDC_HIDEUNNAMEDHANDLES 1118 -#define IDC_CPU20 1119 -#define IDC_CPU21 1120 -#define IDC_STARTMODULE 1120 -#define IDC_CPU22 1121 -#define IDC_OPENSTARTMODULE 1121 -#define IDC_CPU23 1122 -#define IDC_KERNELTIME 1122 -#define IDC_CPU24 1123 -#define IDC_USERTIME 1123 -#define IDC_CPU25 1124 -#define IDC_CONTEXTSWITCHES 1124 -#define IDC_CPU26 1125 -#define IDC_CYCLES 1125 -#define IDC_CPU27 1126 -#define IDC_PRIORITY 1126 -#define IDC_CPU28 1127 -#define IDC_BASEPRIORITY 1127 -#define IDC_CPU29 1128 -#define IDC_IOPRIORITY 1128 -#define IDC_CPU30 1129 -#define IDC_PAGEPRIORITY 1129 -#define IDC_CPU31 1130 -#define IDC_STATICBL1 1130 -#define IDC_STATICBL2 1131 -#define IDC_CPU32 1131 -#define IDC_STATICBL3 1132 -#define IDC_CPU33 1132 -#define IDC_STATICBL4 1133 -#define IDC_CPU34 1133 -#define IDC_STATICBL5 1134 -#define IDC_CPU35 1134 -#define IDC_STATICBL6 1135 -#define IDC_CPU36 1135 -#define IDC_STATICBL7 1136 -#define IDC_CPU37 1136 -#define IDC_STATICBL8 1137 -#define IDC_CPU38 1137 -#define IDC_STATICBL9 1138 -#define IDC_CPU39 1138 -#define IDC_STATICBL10 1139 -#define IDC_CPU40 1139 -#define IDC_STATICBL11 1140 -#define IDC_CPU41 1140 -#define IDC_CHOICESIMPLE 1141 -#define IDC_CPU42 1141 -#define IDC_MESSAGE 1142 -#define IDC_CPU43 1142 -#define IDC_SEARCHENGINE 1143 -#define IDC_CPU44 1143 -#define IDC_MAXSIZEUNIT 1144 -#define IDC_CPU45 1144 -#define IDC_ALLOWONLYONEINSTANCE 1145 -#define IDC_CPU46 1145 -#define IDC_HIDEONCLOSE 1146 -#define IDC_CPU47 1146 -#define IDC_ENABLEWARNINGS 1147 -#define IDC_HIDEONMINIMIZE 1147 -#define IDC_CPU48 1147 -#define IDC_STARTHIDDEN 1148 -#define IDC_CPU49 1148 -#define IDC_ENABLEKERNELMODEDRIVER 1149 -#define IDC_CPU50 1149 -#define IDC_CPU51 1150 -#define IDC_PEVIEWER 1151 -#define IDC_CPU52 1151 -#define IDC_CPU53 1152 -#define IDC_CPU54 1153 -#define IDC_CPU55 1154 -#define IDC_HIGHLIGHTINGDURATION 1155 -#define IDC_CPU56 1155 -#define IDC_CPU57 1156 -#define IDC_ENABLEALL 1157 -#define IDC_CPU58 1157 -#define IDC_ZACTIVEPROCESSES_V 1158 -#define IDC_CPU59 1158 -#define IDC_ZTOTALPROCESSES_V 1159 -#define IDC_CPU60 1159 -#define IDC_ZTERMINATEDPROCESSES_V 1160 -#define IDC_CPU61 1160 -#define IDC_ZUSERTIME_V 1161 -#define IDC_CPU62 1161 -#define IDC_ZKERNELTIME_V 1162 -#define IDC_CPU63 1162 -#define IDC_ZUSERTIMEPERIOD_V 1163 -#define IDC_ZKERNELTIMEPERIOD_V 1164 -#define IDC_ZPAGEFAULTS_V 1165 -#define IDC_ZPEAKPROCESSUSAGE_V 1166 -#define IDC_ZPEAKJOBUSAGE_V 1167 -#define IDC_ZIOREADS_V 1168 -#define IDC_ZIOREADBYTES_V 1169 -#define IDC_ZIOWRITES_V 1170 -#define IDC_ZIOWRITEBYTES_V 1171 -#define IDC_ZIOOTHER_V 1172 -#define IDC_ZIOOTHERBYTES_V 1173 -#define IDC_MOVEDOWN 1176 -#define IDC_DISPLAYNAME 1179 -#define IDC_ZPRIORITY_V 1181 -#define IDC_ZCYCLES_V 1182 -#define IDC_ZTOTALTIME_V 1185 -#define IDC_ZPRIVATEBYTES_V 1186 -#define IDC_ZWORKINGSET_V 1187 -#define IDC_ZPEAKWORKINGSET_V 1188 -#define IDC_ZVIRTUALSIZE_V 1189 -#define IDC_ZPEAKVIRTUALSIZE_V 1190 -#define IDC_ZPEAKPRIVATEBYTES_V 1191 -#define IDC_ZPAGEPRIORITY_V 1192 -#define IDC_ZIOPRIORITY_V 1194 -#define IDC_ZHANDLES_V 1195 -#define IDC_ZGDIHANDLES_V 1196 -#define IDC_ZOTHERDELTA_V 1196 -#define IDC_ZUSERHANDLES_V 1197 -#define IDC_ZOTHER_V 1197 -#define IDC_GROUPCPU 1198 -#define IDC_GROUPPRIVATEBYTES 1199 -#define IDC_GROUPIO 1200 -#define IDC_ONEGRAPHPERCPU 1202 -#define IDC_ALWAYSONTOP 1203 -#define IDC_COPY 1206 -#define IDC_INACTIVE 1207 -#define IDC_ACTIVE 1208 -#define IDC_SHOW 1209 -#define IDC_HIDE 1210 -#define IDC_REPLACETASKMANAGER 1211 -#define IDC_AUTOSCROLL 1215 -#define IDC_UNDECORATESYMBOLS 1216 -#define IDC_DBGHELPPATH 1217 -#define IDC_DBGHELPSEARCHPATH 1218 -#define IDC_COLLAPSESERVICES 1219 -#define IDC_ICONSINGLECLICK 1220 -#define IDC_DESKTOP 1221 -#define IDC_REREAD 1224 -#define IDC_WRITE 1225 -#define IDC_VALUE 1230 -#define IDC_DELAYEDSTART 1234 -#define IDC_MINIMUMLENGTH 1236 -#define IDC_DETECTUNICODE 1237 -#define IDC_PRIVATE 1238 -#define IDC_IMAGE 1239 -#define IDC_MAPPED 1240 -#define IDC_STRINGS 1242 -#define IDC_SHOWTEXT 1245 -#define IDC_ICONPROCESSES 1248 -#define IDC_CLEANUP 1251 -#define IDC_ENABLESTAGE2 1253 -#define IDC_TOGGLEELEVATION 1254 -#define IDC_ENABLEPLUGINS 1258 -#define IDC_PARENT 1263 -#define IDC_PROCESSNAME 1264 -#define IDC_SERVICES_LAYOUT 1266 -#define IDC_LINK_SF 1267 -#define IDC_CREDITS 1270 -#define IDC_ENABLENETWORKRESOLVE 1271 -#define IDC_LOGONTIME 1272 -#define IDC_ZPEAKHANDLES_V 1273 -#define IDC_PROPAGATECPUUSAGE 1274 -#define IDC_SHIFT 1274 -#define IDC_USEOLDCOLORS 1274 -#define IDC_ICONTOGGLESVISIBILITY 1274 -#define IDC_OPENURL 1279 -#define IDC_COMPANYNAME_LINK 1279 -#define IDC_SAMPLECOUNT 1280 -#define IDC_SAMPLECOUNTLABEL 1281 -#define IDC_DISABLE 1282 -#define IDC_VIRTUALKEY 1283 -#define IDC_CTRL 1284 -#define IDC_ALT 1285 -#define IDC_CONNECTTIME 1286 -#define IDC_DISCONNECTTIME 1287 -#define IDC_LASTINPUTTIME 1288 -#define IDC_ZPRIVATEWS_V 1289 -#define IDC_ZSHAREABLEWS_V 1290 -#define IDC_ZSHAREDWS_V 1291 -#define IDC_ENABLEINSTANTTOOLTIPS 1292 -#define IDC_ENABLECYCLECPUUSAGE 1293 -#define IDC_IDEALPROCESSOR 1294 -#define IDC_STATICBL12 1295 -#define IDC_BASICINFORMATION 1296 -#define IDC_INSTRUCTION 1298 -#define IDC_CPUNAME 1299 -#define IDC_LAYOUT 1300 -#define IDC_UTILIZATION 1301 -#define IDC_SPEED 1302 -#define IDC_ZPROCESSES_V 1303 -#define IDC_ZTHREADS_V 1304 -#define IDC_ZCONTEXTSWITCHESDELTA_V 1307 -#define IDC_ZINTERRUPTSDELTA_V 1308 -#define IDC_ZDPCSDELTA_V 1309 -#define IDC_ZSYSTEMCALLSDELTA_V 1310 -#define IDC_GRAPH_LAYOUT 1311 -#define IDC_TOTALPHYSICAL 1312 -#define IDC_ZCOMMITCURRENT_V 1314 -#define IDC_ZCOMMITPEAK_V 1315 -#define IDC_ZCOMMITLIMIT_V 1316 -#define IDC_ZPHYSICALCURRENT_V 1317 -#define IDC_ZPHYSICALTOTAL_V 1318 -#define IDC_ZPHYSICALCACHEWS_V 1319 -#define IDC_ZPHYSICALKERNELWS_V 1320 -#define IDC_ZPHYSICALDRIVERWS_V 1321 -#define IDC_ZPAGEDWORKINGSET_V 1322 -#define IDC_ZPAGEDVIRTUALSIZE_V 1323 -#define IDC_ZPAGEDLIMIT_V 1324 -#define IDC_ZPAGEDALLOCSDELTA_V 1325 -#define IDC_ZPAGEDFREESDELTA_V 1326 -#define IDC_ZNONPAGEDUSAGE_V 1327 -#define IDC_ZNONPAGEDLIMIT_V 1328 -#define IDC_ZNONPAGEDALLOCSDELTA_V 1329 -#define IDC_ZNONPAGEDFREESDELTA_V 1330 -#define IDC_ZPHYSICALRESERVED_V 1331 -#define IDC_ZLISTZEROED_V 1332 -#define IDC_ZLISTFREE_V 1333 -#define IDC_ZLISTMODIFIED_V 1334 -#define IDC_ZLISTMODIFIEDNOWRITE_V 1335 -#define IDC_ZLISTSTANDBY_V 1337 -#define IDC_COMMIT_L 1339 -#define IDC_PHYSICAL_L 1340 -#define IDC_ZUPTIME_V 1341 -#define IDC_ZOTHERBYTESDELTA_V 1342 -#define IDC_ZREADSDELTA_V 1343 -#define IDC_ZREADBYTESDELTA_V 1344 -#define IDC_ZWRITESDELTA_V 1345 -#define IDC_ZLISTSTANDBY0_V 1346 -#define IDC_ZWRITEBYTESDELTA_V 1346 -#define IDC_ZLISTSTANDBY1_V 1347 -#define IDC_ZREADS_V 1347 -#define IDC_ZLISTSTANDBY2_V 1348 -#define IDC_ZREADBYTES_V 1348 -#define IDC_ZLISTSTANDBY3_V 1349 -#define IDC_ZWRITES_V 1349 -#define IDC_ZLISTBAD_V 1350 -#define IDC_ZWRITEBYTES_V 1350 -#define IDC_ZLISTREPURPOSED_V 1351 -#define IDC_ZOTHERBYTES_V 1351 -#define IDC_ZLISTREPURPOSED0_V 1352 -#define IDC_ZLISTREPURPOSED1_V 1353 -#define IDC_ZLISTREPURPOSED2_V 1354 -#define IDC_ZLISTREPURPOSED3_V 1355 -#define IDC_ZLISTREPURPOSED4_V 1356 -#define IDC_ZLISTREPURPOSED5_V 1357 -#define IDC_ZLISTREPURPOSED6_V 1358 -#define IDC_ZLISTREPURPOSED7_V 1359 -#define IDC_EMPTY 1360 -#define IDC_SAMPLECOUNTAUTOMATIC 1361 -#define IDC_SHOWCOMMITINSUMMARY 1361 -#define IDC_ZLISTSTANDBY4_V 1364 -#define IDC_ZLISTSTANDBY5_V 1365 -#define IDC_SELECTALL 1365 -#define IDC_ZLISTSTANDBY6_V 1366 -#define IDC_DESELECTALL 1366 -#define IDC_ZLISTSTANDBY7_V 1367 -#define IDC_INSPECT 1367 -#define IDC_ZPAGINGPAGEFAULTSDELTA_V 1368 -#define IDC_HIDEFREEREGIONS 1368 -#define IDC_ZPAGINGPAGEREADSDELTA_V 1369 -#define IDC_BYTESPERROW 1369 -#define IDC_ZPAGINGPAGEFILEWRITESDELTA_V 1370 -#define IDC_PIN 1370 -#define IDC_ZPAGINGMAPPEDWRITESDELTA_V 1371 -#define IDC_ZLISTMODIFIEDPAGEFILE_V 1373 -#define IDC_SECTION 1375 -#define IDC_REGEX 1377 -#define IDC_DESCRIPTIONLABEL 1378 -#define IDC_STARTATLOGON 1380 -#define IDC_VIEWCOMMANDLINE 1381 -#define IDC_DELETE 1382 -#define IDC_EDIT 1383 -#define IDC_NEW 1384 -#define IDC_HANDLESEARCH 1385 -#define ID_MAINWND_PROCESSTL 2001 -#define ID_MAINWND_SERVICETL 2002 -#define ID_MAINWND_NETWORKTL 2003 -#define ID_MAINWND_PROCESSLV 2004 -#define ID_HACKER_EXIT 40001 -#define ID_PROCESS_PROPERTIES 40006 -#define ID_PROCESS_TERMINATE 40007 -#define ID_PROCESS_SUSPEND 40008 -#define ID_PROCESS_RESUME 40009 -#define ID_HACKER_SAVE 40010 -#define ID_THREAD_TERMINATE 40011 -#define ID_THREAD_SUSPEND 40012 -#define ID_THREAD_RESUME 40013 -#define ID_THREAD_PERMISSIONS 40015 -#define ID_THREAD_TOKEN 40016 -#define ID_ANALYZE_WAIT 40018 -#define ID_PRIORITY_TIMECRITICAL 40020 -#define ID_PRIORITY_HIGHEST 40021 -#define ID_PRIORITY_ABOVENORMAL 40022 -#define ID_PRIORITY_NORMAL 40023 -#define ID_PRIORITY_BELOWNORMAL 40024 -#define ID_PRIORITY_LOWEST 40025 -#define ID_PRIORITY_IDLE 40026 -#define ID_IOPRIORITY_VERYLOW 40028 -#define ID_IOPRIORITY_LOW 40029 -#define ID_IOPRIORITY_NORMAL 40030 -#define ID_IOPRIORITY_HIGH 40031 -#define ID_PROCESS_RESTART 40032 -#define ID_PROCESS_VIRTUALIZATION 40034 -#define ID_PROCESS_AFFINITY 40035 -#define ID_PROCESS_CREATEDUMPFILE 40036 -#define ID_MISCELLANEOUS_DETACHFROMDEBUGGER 40039 -#define ID_MISCELLANEOUS_HEAPS 40040 -#define ID_MISCELLANEOUS_INJECTDLL 40041 -#define ID_PRIORITY_REALTIME 40048 -#define ID_PRIORITY_HIGH 40049 -#define ID_WINDOW_BRINGTOFRONT 40055 -#define ID_WINDOW_RESTORE 40056 -#define ID_WINDOW_MINIMIZE 40057 -#define ID_WINDOW_MAXIMIZE 40058 -#define ID_WINDOW_CLOSE 40059 -#define ID_PROCESS_SEARCHONLINE 40060 -#define ID_HANDLE_CLOSE 40061 -#define ID_HANDLE_PROTECTED 40062 -#define ID_HANDLE_INHERIT 40063 -#define ID_HANDLE_PROPERTIES 40064 -#define ID_MODULE_UNLOAD 40066 -#define ID_MODULE_PROPERTIES 40068 -#define ID_PROCESS_TERMINATETREE 40069 -#define ID_THREAD_INSPECT 40075 -#define ID_HACKER_RUN 40076 -#define ID_HACKER_RUNASADMINISTRATOR 40077 -#define ID_HACKER_RUNAS 40078 -#define ID_HACKER_SHOWDETAILSFORALLPROCESSES 40079 -#define ID_HACKER_FINDHANDLESORDLLS 40082 -#define ID_HACKER_OPTIONS 40083 -#define ID_VIEW_SYSTEMINFORMATION 40091 -#define ID_TRAYICONS_CPUHISTORY 40093 -#define ID_TRAYICONS_CPUUSAGE 40094 -#define ID_TRAYICONS_COMMITHISTORY 40096 -#define ID_TRAYICONS_PHYSICALMEMORYHISTORY 40097 -#define ID_VIEW_REFRESH 40098 -#define ID_TOOLS_CREATESERVICE 40101 -#define ID_TOOLS_HIDDENPROCESSES 40102 -#define ID_TOOLS_INSPECTEXECUTABLEFILE 40103 -#define ID_HELP_LOG 40104 -#define ID_HELP_DONATE 40105 -#define ID_HELP_ABOUT 40106 -#define ID_SERVICE_GOTOPROCESS 40107 -#define ID_SERVICE_START 40108 -#define ID_SERVICE_CONTINUE 40109 -#define ID_SERVICE_PAUSE 40110 -#define ID_SERVICE_STOP 40111 -#define ID_SERVICE_DELETE 40112 -#define ID_SERVICE_PROPERTIES 40113 -#define ID_SERVICE_OPENKEY 40114 -#define ID_PRIVILEGE_ENABLE 40116 -#define ID_PRIVILEGE_DISABLE 40117 -#define ID_PRIVILEGE_REMOVE 40118 -#define ID_OBJECT_CLOSE 40119 -#define ID_OBJECT_PROPERTIES 40120 -#define ID_HELP_DEBUGCONSOLE 40122 -#define ID_MODULE_SEARCHONLINE 40125 -#define ID_TOOLS_PAGEFILES 40126 -#define ID_USER_DISCONNECT 40127 -#define ID_USER_LOGOFF 40128 -#define ID_USER_SENDMESSAGE 40129 -#define ID_USER_PROPERTIES 40130 -#define ID_USERS_DUMMY 40131 -#define ID_MODULE_INSPECT 40132 -#define ID_PROCESS_DEBUG 40133 -#define ID_USER_CONNECT 40138 -#define ID_NETWORK_GOTOPROCESS 40139 -#define ID_NETWORK_CLOSE 40140 -#define ID_OPACITY_10 40142 -#define ID_OPACITY_20 40143 -#define ID_OPACITY_30 40144 -#define ID_OPACITY_40 40145 -#define ID_OPACITY_50 40146 -#define ID_OPACITY_60 40147 -#define ID_OPACITY_70 40148 -#define ID_OPACITY_80 40149 -#define ID_OPACITY_90 40150 -#define ID_OPACITY_OPAQUE 40151 -#define ID_VIEW_ALWAYSONTOP 40153 -#define ID_UPDATEINTERVAL_FAST 40155 -#define ID_UPDATEINTERVAL_NORMAL 40156 -#define ID_UPDATEINTERVAL_BELOWNORMAL 40157 -#define ID_UPDATEINTERVAL_SLOW 40158 -#define ID_UPDATEINTERVAL_VERYSLOW 40159 -#define ID_COMPUTER_LOCK 40160 -#define ID_COMPUTER_LOGOFF 40161 -#define ID_COMPUTER_SLEEP 40162 -#define ID_COMPUTER_HIBERNATE 40163 -#define ID_COMPUTER_RESTART 40164 -#define ID_COMPUTER_SHUTDOWN 40165 -#define ID_NETWORK_VIEWSTACK 40167 -#define ID_TRAYICONS_IOHISTORY 40168 -#define ID_ICON_EXIT 40169 -#define ID_ICON_SHOWHIDEPROCESSHACKER 40171 -#define ID_ICON_SYSTEMINFORMATION 40172 -#define ID_PROCESSES_DUMMY 40177 -#define ID_NOTIFICATIONS_ENABLEALL 40178 -#define ID_NOTIFICATIONS_DISABLEALL 40179 -#define ID_NOTIFICATIONS_NEWPROCESSES 40180 -#define ID_NOTIFICATIONS_TERMINATEDPROCESSES 40181 -#define ID_NOTIFICATIONS_NEWSERVICES 40182 -#define ID_NOTIFICATIONS_STARTEDSERVICES 40183 -#define ID_NOTIFICATIONS_STOPPEDSERVICES 40184 -#define ID_NOTIFICATIONS_DELETEDSERVICES 40185 -#define ID_MISCELLANEOUS_GDIHANDLES 40188 -#define ID_ESC_EXIT 40190 -#define ID_PROCESS_COPY 40194 -#define ID_THREAD_COPY 40195 -#define ID_PRIVILEGE_COPY 40196 -#define ID_NETWORK_COPY 40197 -#define ID_SERVICE_COPY 40198 -#define ID_MODULE_COPY 40199 -#define ID_HANDLE_COPY 40200 -#define ID_OBJECT_COPY 40201 -#define ID_MEMORY_SAVE 40208 -#define ID_MEMORY_CHANGEPROTECTION 40209 -#define ID_MEMORY_FREE 40210 -#define ID_MEMORY_DECOMMIT 40211 -#define ID_MEMORY_COPY 40213 -#define ID_MEMORY_READWRITEMEMORY 40214 -#define ID_MEMORY_READWRITEADDRESS 40215 -#define ID_FILTER_CONTAINS 40216 -#define ID_FILTER_CONTAINS_CASEINSENSITIVE 40218 -#define ID_FILTER_REGEX 40219 -#define ID_FILTER_REGEX_CASEINSENSITIVE 40221 -#define ID_TAB_NEXT 40223 -#define ID_TAB_PREV 40224 -#define ID_MISCELLANEOUS_RUNAS 40229 -#define ID_MISCELLANEOUS_RUNASTHISUSER 40230 -#define ID_HACKER_PLUGINS 40231 -#define ID_VIEW_HIDEPROCESSESFROMOTHERUSERS 40232 -#define ID_THREAD_AFFINITY 40233 -#define ID_VIEW_HIDESIGNEDPROCESSES 40234 -#define ID_VIEW_UPDATEAUTOMATICALLY 40235 -#define ID_HACKER_RUNASLIMITEDUSER 40236 -#define ID_USER_REMOTECONTROL 40237 -#define ID_PAGEPRIORITY_NORMAL 40239 -#define ID_PAGEPRIORITY_BELOWNORMAL 40240 -#define ID_PAGEPRIORITY_MEDIUM 40241 -#define ID_PAGEPRIORITY_LOW 40242 -#define ID_PAGEPRIORITY_VERYLOW 40243 -#define ID_VIEW_SHOWCPUBELOW001 40246 -#define ID_MODULE_OPENFILELOCATION 40247 -#define ID_PROCESS_OPENFILELOCATION 40248 -#define ID_MISCELLANEOUS_REDUCEWORKINGSET 40249 -#define ID_EMPTY_EMPTYWORKINGSETS 40250 -#define ID_EMPTY_EMPTYMODIFIEDPAGELIST 40251 -#define ID_EMPTY_EMPTYSTANDBYLIST 40252 -#define ID_EMPTY_EMPTYPRIORITY0STANDBYLIST 40253 -#define IDC_BACK 40255 -#define ID_DIGIT1 40263 -#define ID_DIGIT2 40264 -#define ID_DIGIT3 40265 -#define ID_DIGIT4 40266 -#define ID_DIGIT5 40267 -#define ID_DIGIT6 40268 -#define ID_DIGIT7 40269 -#define ID_DIGIT8 40270 -#define ID_DIGIT9 40271 -#define ID_VIEW_HIDEDRIVERSERVICES 40273 -#define ID_VIEW_SECTIONPLACEHOLDER 40274 -#define ID_VIEW_SCROLLTONEWPROCESSES 40275 -#define ID_TOOLS_STARTTASKMANAGER 40277 -#define ID_COMPUTER_SHUTDOWNHYBRID 40278 -#define ID_COMPUTER_RESTARTBOOTOPTIONS 40280 -#define ID_HANDLE_OBJECTPROPERTIES1 40282 -#define ID_HANDLE_OBJECTPROPERTIES2 40283 -#define ID_OBJECT_GOTOOWNINGPROCESS 40284 -#define ID_NETWORK_GOTOSERVICE 40285 -#define ID_SERVICE_OPENFILELOCATION 40286 -#define ID_PROCESS_GOTOPROCESS 40287 -#define ID_MINIINFO_REFRESH 40288 -#define ID_MINIINFO_REFRESHAUTOMATICALLY 40289 -#define ID_ENVIRONMENT_EDIT 40290 -#define ID_ENVIRONMENT_COPY 40291 -#define ID_ENVIRONMENT_DELETE 40292 -#define IDC_MAXSCREEN 40293 -#define IDDYNAMIC 50000 -#define IDPLUGINS 55000 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 228 -#define _APS_NEXT_COMMAND_VALUE 40295 -#define _APS_NEXT_CONTROL_VALUE 1387 -#define _APS_NEXT_SYMED_VALUE 169 -#endif -#endif +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by ProcessHacker.rc +// +#define IDR_RT_MANIFEST 1 +#define IDI_PROCESSHACKER 101 +#define IDR_MAINWND 102 +#define IDR_MAINWND_ACCEL 102 +#define IDD_PROCGENERAL 103 +#define IDD_PROCMODULES 104 +#define IDD_PROCTHREADS 105 +#define IDD_PROCHANDLES 106 +#define IDD_PROCENVIRONMENT 107 +#define IDD_THRDSTACK 108 +#define IDR_THREAD 110 +#define IDR_HANDLE 111 +#define IDR_MODULE 112 +#define IDC_CPU 112 +#define IDC_PRIVATEBYTES 113 +#define IDC_IO 114 +#define IDB_CROSS 117 +#define IDB_TICK 118 +#define IDC_PHYSICAL 119 +#define IDR_COMPUTER 120 +#define IDC_MEMORY 120 +#define IDD_ABOUT 121 +#define IDC_NEWOBJECTS 121 +#define IDC_REMOVEDOBJECTS 122 +#define IDR_PROCESS 123 +#define IDC_CPUUSER 123 +#define IDR_SERVICE 124 +#define IDC_CPUKERNEL 124 +#define IDC_IORO 125 +#define IDD_SRVLIST 125 +#define IDD_SRVGENERAL 126 +#define IDC_IOW 126 +#define IDD_HNDLGENERAL 128 +#define IDD_INFORMATION 129 +#define IDD_FINDOBJECTS 130 +#define IDD_OBJTOKEN 131 +#define ID_PLUGIN_MENU_ITEM 131 +#define ID_SHOWCONTEXTMENU 132 +#define IDR_PRIVILEGE 133 +#define IDC_SEPARATOR 133 +#define IDR_FINDOBJ 134 +#define IDC_COMMIT 134 +#define IDD_HIDDENPROCESSES 135 +#define ID_TRAYICONS_REGISTERED 135 +#define IDD_RUNAS 136 +#define ID_COPY_CELL 136 +#define IDD_PROGRESS 137 +#define IDD_PAGEFILES 138 +#define IDD_TOKGENERAL 139 +#define IDD_TOKADVANCED 140 +#define IDD_OBJJOB 141 +#define IDD_OBJEVENT 142 +#define IDD_OBJMUTANT 143 +#define IDD_OBJSEMAPHORE 144 +#define IDD_OBJTIMER 145 +#define IDD_JOBSTATISTICS 146 +#define IDD_OBJEVENTPAIR 147 +#define IDD_OBJSECTION 148 +#define IDD_AFFINITY 149 +#define IDD_SYSINFO 150 +#define IDR_USER 151 +#define IDD_EDITMESSAGE 152 +#define IDD_SESSION 153 +#define IDD_PROCMEMORY 154 +#define IDD_CHOOSE 155 +#define IDD_OPTGENERAL 162 +#define IDD_OPTHIGHLIGHTING 163 +#define IDR_NETWORK 164 +#define IDD_CHOOSECOLUMNS 166 +#define IDD_NETSTACK 167 +#define IDD_CREATESERVICE 168 +#define IDD_PROCPERFORMANCE 169 +#define IDD_PROCSTATISTICS 170 +#define IDD_OPTADVANCED 171 +#define IDR_ICON 173 +#define IDD_GDIHANDLES 175 +#define IDD_LOG 178 +#define IDD_OPTSYMBOLS 179 +#define IDD_MEMEDIT 180 +#define IDR_MEMORY 181 +#define IDD_MEMPROTECT 182 +#define IDD_MEMRESULTS 183 +#define IDR_MEMFILTER 184 +#define IDD_MEMSTRING 185 +#define IDD_OPTGRAPHS 186 +#define IDD_PLUGINS 187 +#define IDD_HANDLESTATS 188 +#define IDD_PROCRECORD 189 +#define IDD_CHOOSEPROCESS 190 +#define IDD_PROCSERVICES 191 +#define IDI_PHAPPLICATION 191 +#define IDI_COG 192 +#define IDD_SHADOWSESSION 193 +#define IDI_PHAPPLICATIONGO 194 +#define IDD_TOKCAPABILITIES 194 +#define IDI_COGGO 195 +#define IDD_TOKATTRIBUTES 195 +#define IDD_SYSINFO_CPU 196 +#define IDD_SYSINFO_CPUPANEL 197 +#define IDD_SYSINFO_MEMPANEL 198 +#define IDR_SYSINFO_ACCEL 198 +#define IDD_SYSINFO_MEM 199 +#define IDD_SYSINFO_IO 200 +#define IDD_SYSINFO_IOPANEL 201 +#define IDD_MEMLISTS 202 +#define IDR_EMPTYMEMLISTS 204 +#define IDD_CONTAINER 205 +#define IDD_SYSINFO_MEMPANELXP 206 +#define IDD_MINIINFO 207 +#define IDD_MINIINFO_LIST 210 +#define IDR_MINIINFO 211 +#define IDR_MINIINFO_PROCESS 212 +#define IDR_ENVIRONMENT 214 +#define IDD_MITIGATION 215 +#define IDI_PIN 216 +#define IDI_FOLDER 217 +#define IDI_PENCIL 218 +#define IDI_MAGNIFIER 219 +#define IDD_EDITENV 221 +#define IDB_SEARCH_ACTIVE 223 +#define IDB_SEARCH_INACTIVE 224 +#define IDB_SEARCH_ACTIVE_BMP 225 +#define IDB_SEARCH_INACTIVE_BMP 226 +#define IDC_TERMINATE 1003 +#define IDC_FILEICON 1005 +#define IDC_FILE 1006 +#define IDC_PROCESS 1007 +#define IDC_COMPANYNAME 1009 +#define IDC_VERSION 1010 +#define IDC_REFRESH 1015 +#define IDC_PERMISSIONS 1018 +#define IDC_FILENAME 1020 +#define IDC_CMDLINE 1021 +#define IDC_URL 1021 +#define IDC_RUNSELECTED 1021 +#define IDC_CURDIR 1022 +#define IDC_STARTED 1023 +#define IDC_ABOUT_NAME 1024 +#define IDC_PEBADDRESS 1024 +#define IDC_TERMINATED 1024 +#define IDC_PARENTPROCESS 1025 +#define IDC_MITIGATION 1026 +#define IDC_PAUSE 1027 +#define IDC_PROTECTION 1027 +#define IDC_START 1028 +#define IDC_DESCRIPTION 1029 +#define IDC_TYPE 1032 +#define IDC_STARTTYPE 1033 +#define IDC_ADDRESS 1033 +#define IDC_IMPERSONATIONLEVEL 1033 +#define IDC_ERRORCONTROL 1034 +#define IDC_GRANTED_ACCESS 1034 +#define IDC_TOKENLUID 1034 +#define IDC_GROUP 1035 +#define IDC_AUTHENTICATIONLUID 1035 +#define IDC_BINARYPATH 1036 +#define IDC_MEMORYUSED 1036 +#define IDC_USERACCOUNT 1037 +#define IDC_MEMORYAVAILABLE 1037 +#define IDC_PASSWORD 1040 +#define IDC_PASSWORDCHECK 1041 +#define IDC_SERVICEDLL 1042 +#define IDC_NAME 1044 +#define IDC_REFERENCES 1045 +#define IDC_INTERNALNAME 1045 +#define IDC_HANDLES 1046 +#define IDC_PROCESSTYPELABEL 1046 +#define IDC_AUTHOR 1046 +#define IDC_PAGED 1047 +#define IDC_PROCESSTYPETEXT 1047 +#define IDC_NONPAGED 1048 +#define IDC_TEXT 1048 +#define IDC_DIAGNOSTICS 1049 +#define IDC_FILTER 1050 +#define IDC_RESULTS 1051 +#define IDC_USER 1052 +#define IDC_USERSID 1053 +#define IDC_ADVANCED 1054 +#define IDC_OWNER 1054 +#define IDC_GROUPS 1055 +#define IDC_PRIMARYGROUP 1055 +#define IDC_PRIVILEGES 1056 +#define IDC_VIRTUALIZATION 1056 +#define IDC_SESSIONID 1057 +#define IDC_ELEVATED 1058 +#define IDC_VIRTUALIZED 1059 +#define IDC_SOURCENAME 1059 +#define IDC_PROPERTIES 1060 +#define IDC_SOURCELUID 1060 +#define IDC_APPCONTAINERSID 1060 +#define IDC_LIST 1061 +#define IDC_PROCESSES 1063 +#define IDC_SCAN 1064 +#define IDC_SAVE 1065 +#define IDC_METHOD 1067 +#define IDC_INTRO 1068 +#define IDC_PROGRAM 1069 +#define IDC_BROWSE 1070 +#define IDC_USERNAME 1071 +#define IDC_SESSIONS 1074 +#define IDC_DESKTOPS 1075 +#define IDC_PROGRESS 1076 +#define IDC_PROGRESSTEXT 1077 +#define IDC_LINKEDTOKEN 1079 +#define IDC_DISABLEALL 1079 +#define IDC_MOVEUP 1079 +#define IDC_CHANGE 1079 +#define IDC_CLEAR 1079 +#define IDC_GOTO 1079 +#define IDC_OPTIONS 1079 +#define IDC_DETAILS 1079 +#define IDC_ADD 1079 +#define IDC_FONT 1079 +#define IDC_INTEGRITY 1079 +#define IDC_MORE 1079 +#define IDC_VIEWMITIGATION 1080 +#define IDC_VIEWPARENTPROCESS 1081 +#define IDC_OPENFILENAME 1082 +#define IDC_LIMITS 1083 +#define IDC_SIGNALED 1084 +#define IDC_SET 1085 +#define IDC_RESET 1086 +#define IDC_PULSE 1087 +#define IDC_COUNT 1088 +#define IDC_ABANDONED 1089 +#define IDC_CURRENTCOUNT 1090 +#define IDC_MAXIMUMCOUNT 1091 +#define IDC_ACQUIRE 1092 +#define IDC_RELEASE 1093 +#define IDC_CANCEL 1094 +#define IDC_OWNERLABEL 1095 +#define IDC_SETLOW 1096 +#define IDC_SETHIGH 1097 +#define IDC_SIZE_ 1098 +#define IDC_CPU0 1099 +#define IDC_CPU1 1100 +#define IDC_CPU2 1101 +#define IDC_CPU3 1102 +#define IDC_CPU4 1103 +#define IDC_CPU5 1104 +#define IDC_CPU6 1105 +#define IDC_CPU7 1106 +#define IDC_CPU8 1107 +#define IDC_TITLE 1107 +#define IDC_CPU9 1108 +#define IDC_CPU10 1109 +#define IDC_TIMEOUT 1109 +#define IDC_CPU11 1110 +#define IDC_CPU12 1111 +#define IDC_STATE 1111 +#define IDC_CPU13 1112 +#define IDC_CLIENTNAME 1112 +#define IDC_CPU14 1113 +#define IDC_CLIENTADDRESS 1113 +#define IDC_CPU15 1114 +#define IDC_CLIENTDISPLAY 1114 +#define IDC_CPU16 1115 +#define IDC_CHOICE 1115 +#define IDC_CPU17 1116 +#define IDC_OPTION 1116 +#define IDC_CPU18 1117 +#define IDC_CHOICEUSER 1117 +#define IDC_CPU19 1118 +#define IDC_HIDEUNNAMEDHANDLES 1118 +#define IDC_CPU20 1119 +#define IDC_CPU21 1120 +#define IDC_STARTMODULE 1120 +#define IDC_CPU22 1121 +#define IDC_OPENSTARTMODULE 1121 +#define IDC_CPU23 1122 +#define IDC_KERNELTIME 1122 +#define IDC_CPU24 1123 +#define IDC_USERTIME 1123 +#define IDC_CPU25 1124 +#define IDC_CONTEXTSWITCHES 1124 +#define IDC_CPU26 1125 +#define IDC_CYCLES 1125 +#define IDC_CPU27 1126 +#define IDC_PRIORITY 1126 +#define IDC_CPU28 1127 +#define IDC_BASEPRIORITY 1127 +#define IDC_CPU29 1128 +#define IDC_IOPRIORITY 1128 +#define IDC_CPU30 1129 +#define IDC_PAGEPRIORITY 1129 +#define IDC_CPU31 1130 +#define IDC_STATICBL1 1130 +#define IDC_STATICBL2 1131 +#define IDC_CPU32 1131 +#define IDC_STATICBL3 1132 +#define IDC_CPU33 1132 +#define IDC_STATICBL4 1133 +#define IDC_CPU34 1133 +#define IDC_STATICBL5 1134 +#define IDC_CPU35 1134 +#define IDC_STATICBL6 1135 +#define IDC_CPU36 1135 +#define IDC_STATICBL7 1136 +#define IDC_CPU37 1136 +#define IDC_STATICBL8 1137 +#define IDC_CPU38 1137 +#define IDC_STATICBL9 1138 +#define IDC_CPU39 1138 +#define IDC_STATICBL10 1139 +#define IDC_CPU40 1139 +#define IDC_STATICBL11 1140 +#define IDC_CPU41 1140 +#define IDC_CHOICESIMPLE 1141 +#define IDC_CPU42 1141 +#define IDC_MESSAGE 1142 +#define IDC_CPU43 1142 +#define IDC_SEARCHENGINE 1143 +#define IDC_CPU44 1143 +#define IDC_MAXSIZEUNIT 1144 +#define IDC_CPU45 1144 +#define IDC_ALLOWONLYONEINSTANCE 1145 +#define IDC_CPU46 1145 +#define IDC_HIDEONCLOSE 1146 +#define IDC_CPU47 1146 +#define IDC_ENABLEWARNINGS 1147 +#define IDC_HIDEONMINIMIZE 1147 +#define IDC_CPU48 1147 +#define IDC_STARTHIDDEN 1148 +#define IDC_CPU49 1148 +#define IDC_ENABLEKERNELMODEDRIVER 1149 +#define IDC_CPU50 1149 +#define IDC_CPU51 1150 +#define IDC_PEVIEWER 1151 +#define IDC_CPU52 1151 +#define IDC_CPU53 1152 +#define IDC_CPU54 1153 +#define IDC_CPU55 1154 +#define IDC_HIGHLIGHTINGDURATION 1155 +#define IDC_CPU56 1155 +#define IDC_CPU57 1156 +#define IDC_ENABLEALL 1157 +#define IDC_CPU58 1157 +#define IDC_ZACTIVEPROCESSES_V 1158 +#define IDC_CPU59 1158 +#define IDC_ZTOTALPROCESSES_V 1159 +#define IDC_CPU60 1159 +#define IDC_ZTERMINATEDPROCESSES_V 1160 +#define IDC_CPU61 1160 +#define IDC_ZUSERTIME_V 1161 +#define IDC_CPU62 1161 +#define IDC_ZKERNELTIME_V 1162 +#define IDC_CPU63 1162 +#define IDC_ZUSERTIMEPERIOD_V 1163 +#define IDC_ZKERNELTIMEPERIOD_V 1164 +#define IDC_ZPAGEFAULTS_V 1165 +#define IDC_ZPEAKPROCESSUSAGE_V 1166 +#define IDC_ZPEAKJOBUSAGE_V 1167 +#define IDC_ZIOREADS_V 1168 +#define IDC_ZIOREADBYTES_V 1169 +#define IDC_ZIOWRITES_V 1170 +#define IDC_ZIOWRITEBYTES_V 1171 +#define IDC_ZIOOTHER_V 1172 +#define IDC_ZIOOTHERBYTES_V 1173 +#define IDC_MOVEDOWN 1176 +#define IDC_DISPLAYNAME 1179 +#define IDC_ZPRIORITY_V 1181 +#define IDC_ZCYCLES_V 1182 +#define IDC_ZTOTALTIME_V 1185 +#define IDC_ZPRIVATEBYTES_V 1186 +#define IDC_ZWORKINGSET_V 1187 +#define IDC_ZPEAKWORKINGSET_V 1188 +#define IDC_ZVIRTUALSIZE_V 1189 +#define IDC_ZPEAKVIRTUALSIZE_V 1190 +#define IDC_ZPEAKPRIVATEBYTES_V 1191 +#define IDC_ZPAGEPRIORITY_V 1192 +#define IDC_ZIOPRIORITY_V 1194 +#define IDC_ZHANDLES_V 1195 +#define IDC_ZGDIHANDLES_V 1196 +#define IDC_ZOTHERDELTA_V 1196 +#define IDC_ZUSERHANDLES_V 1197 +#define IDC_ZOTHER_V 1197 +#define IDC_GROUPCPU 1198 +#define IDC_GROUPPRIVATEBYTES 1199 +#define IDC_GROUPIO 1200 +#define IDC_ONEGRAPHPERCPU 1202 +#define IDC_ALWAYSONTOP 1203 +#define IDC_COPY 1206 +#define IDC_INACTIVE 1207 +#define IDC_ACTIVE 1208 +#define IDC_SHOW 1209 +#define IDC_HIDE 1210 +#define IDC_REPLACETASKMANAGER 1211 +#define IDC_AUTOSCROLL 1215 +#define IDC_UNDECORATESYMBOLS 1216 +#define IDC_DBGHELPPATH 1217 +#define IDC_DBGHELPSEARCHPATH 1218 +#define IDC_COLLAPSESERVICES 1219 +#define IDC_ICONSINGLECLICK 1220 +#define IDC_DESKTOP 1221 +#define IDC_REREAD 1224 +#define IDC_WRITE 1225 +#define IDC_VALUE 1230 +#define IDC_DELAYEDSTART 1234 +#define IDC_MINIMUMLENGTH 1236 +#define IDC_DETECTUNICODE 1237 +#define IDC_PRIVATE 1238 +#define IDC_IMAGE 1239 +#define IDC_MAPPED 1240 +#define IDC_STRINGS 1242 +#define IDC_SHOWTEXT 1245 +#define IDC_ICONPROCESSES 1248 +#define IDC_CLEANUP 1251 +#define IDC_ENABLESTAGE2 1253 +#define IDC_TOGGLEELEVATION 1254 +#define IDC_ENABLEPLUGINS 1258 +#define IDC_PARENT 1263 +#define IDC_PROCESSNAME 1264 +#define IDC_SERVICES_LAYOUT 1266 +#define IDC_LINK_SF 1267 +#define IDC_CREDITS 1270 +#define IDC_ENABLENETWORKRESOLVE 1271 +#define IDC_LOGONTIME 1272 +#define IDC_ZPEAKHANDLES_V 1273 +#define IDC_PROPAGATECPUUSAGE 1274 +#define IDC_SHIFT 1274 +#define IDC_USEOLDCOLORS 1274 +#define IDC_ICONTOGGLESVISIBILITY 1274 +#define IDC_OPENURL 1279 +#define IDC_COMPANYNAME_LINK 1279 +#define IDC_SAMPLECOUNT 1280 +#define IDC_SAMPLECOUNTLABEL 1281 +#define IDC_DISABLE 1282 +#define IDC_VIRTUALKEY 1283 +#define IDC_CTRL 1284 +#define IDC_ALT 1285 +#define IDC_CONNECTTIME 1286 +#define IDC_DISCONNECTTIME 1287 +#define IDC_LASTINPUTTIME 1288 +#define IDC_ZPRIVATEWS_V 1289 +#define IDC_ZSHAREABLEWS_V 1290 +#define IDC_ZSHAREDWS_V 1291 +#define IDC_ENABLEINSTANTTOOLTIPS 1292 +#define IDC_ENABLECYCLECPUUSAGE 1293 +#define IDC_IDEALPROCESSOR 1294 +#define IDC_STATICBL12 1295 +#define IDC_BASICINFORMATION 1296 +#define IDC_INSTRUCTION 1298 +#define IDC_CPUNAME 1299 +#define IDC_LAYOUT 1300 +#define IDC_UTILIZATION 1301 +#define IDC_SPEED 1302 +#define IDC_ZPROCESSES_V 1303 +#define IDC_ZTHREADS_V 1304 +#define IDC_ZCONTEXTSWITCHESDELTA_V 1307 +#define IDC_ZINTERRUPTSDELTA_V 1308 +#define IDC_ZDPCSDELTA_V 1309 +#define IDC_ZSYSTEMCALLSDELTA_V 1310 +#define IDC_GRAPH_LAYOUT 1311 +#define IDC_TOTALPHYSICAL 1312 +#define IDC_ZCOMMITCURRENT_V 1314 +#define IDC_ZCOMMITPEAK_V 1315 +#define IDC_ZCOMMITLIMIT_V 1316 +#define IDC_ZPHYSICALCURRENT_V 1317 +#define IDC_ZPHYSICALTOTAL_V 1318 +#define IDC_ZPHYSICALCACHEWS_V 1319 +#define IDC_ZPHYSICALKERNELWS_V 1320 +#define IDC_ZPHYSICALDRIVERWS_V 1321 +#define IDC_ZPAGEDWORKINGSET_V 1322 +#define IDC_ZPAGEDVIRTUALSIZE_V 1323 +#define IDC_ZPAGEDLIMIT_V 1324 +#define IDC_ZPAGEDALLOCSDELTA_V 1325 +#define IDC_ZPAGEDFREESDELTA_V 1326 +#define IDC_ZNONPAGEDUSAGE_V 1327 +#define IDC_ZNONPAGEDLIMIT_V 1328 +#define IDC_ZNONPAGEDALLOCSDELTA_V 1329 +#define IDC_ZNONPAGEDFREESDELTA_V 1330 +#define IDC_ZPHYSICALRESERVED_V 1331 +#define IDC_ZLISTZEROED_V 1332 +#define IDC_ZLISTFREE_V 1333 +#define IDC_ZLISTMODIFIED_V 1334 +#define IDC_ZLISTMODIFIEDNOWRITE_V 1335 +#define IDC_ZLISTSTANDBY_V 1337 +#define IDC_COMMIT_L 1339 +#define IDC_PHYSICAL_L 1340 +#define IDC_ZUPTIME_V 1341 +#define IDC_ZOTHERBYTESDELTA_V 1342 +#define IDC_ZREADSDELTA_V 1343 +#define IDC_ZREADBYTESDELTA_V 1344 +#define IDC_ZWRITESDELTA_V 1345 +#define IDC_ZLISTSTANDBY0_V 1346 +#define IDC_ZWRITEBYTESDELTA_V 1346 +#define IDC_ZLISTSTANDBY1_V 1347 +#define IDC_ZREADS_V 1347 +#define IDC_ZLISTSTANDBY2_V 1348 +#define IDC_ZREADBYTES_V 1348 +#define IDC_ZLISTSTANDBY3_V 1349 +#define IDC_ZWRITES_V 1349 +#define IDC_ZLISTBAD_V 1350 +#define IDC_ZWRITEBYTES_V 1350 +#define IDC_ZLISTREPURPOSED_V 1351 +#define IDC_ZOTHERBYTES_V 1351 +#define IDC_ZLISTREPURPOSED0_V 1352 +#define IDC_ZLISTREPURPOSED1_V 1353 +#define IDC_ZLISTREPURPOSED2_V 1354 +#define IDC_ZLISTREPURPOSED3_V 1355 +#define IDC_ZLISTREPURPOSED4_V 1356 +#define IDC_ZLISTREPURPOSED5_V 1357 +#define IDC_ZLISTREPURPOSED6_V 1358 +#define IDC_ZLISTREPURPOSED7_V 1359 +#define IDC_EMPTY 1360 +#define IDC_SAMPLECOUNTAUTOMATIC 1361 +#define IDC_SHOWCOMMITINSUMMARY 1361 +#define IDC_ZLISTSTANDBY4_V 1364 +#define IDC_ZLISTSTANDBY5_V 1365 +#define IDC_SELECTALL 1365 +#define IDC_ZLISTSTANDBY6_V 1366 +#define IDC_DESELECTALL 1366 +#define IDC_ZLISTSTANDBY7_V 1367 +#define IDC_INSPECT 1367 +#define IDC_ZPAGINGPAGEFAULTSDELTA_V 1368 +#define IDC_HIDEFREEREGIONS 1368 +#define IDC_ZPAGINGPAGEREADSDELTA_V 1369 +#define IDC_BYTESPERROW 1369 +#define IDC_ZPAGINGPAGEFILEWRITESDELTA_V 1370 +#define IDC_PIN 1370 +#define IDC_ZPAGINGMAPPEDWRITESDELTA_V 1371 +#define IDC_ZLISTMODIFIEDPAGEFILE_V 1373 +#define IDC_SECTION 1375 +#define IDC_REGEX 1377 +#define IDC_DESCRIPTIONLABEL 1378 +#define IDC_STARTATLOGON 1380 +#define IDC_VIEWCOMMANDLINE 1381 +#define IDC_DELETE 1382 +#define IDC_EDIT 1383 +#define IDC_NEW 1384 +#define IDC_HANDLESEARCH 1385 +#define ID_MAINWND_PROCESSTL 2001 +#define ID_MAINWND_SERVICETL 2002 +#define ID_MAINWND_NETWORKTL 2003 +#define ID_MAINWND_PROCESSLV 2004 +#define ID_HACKER_EXIT 40001 +#define ID_PROCESS_PROPERTIES 40006 +#define ID_PROCESS_TERMINATE 40007 +#define ID_PROCESS_SUSPEND 40008 +#define ID_PROCESS_RESUME 40009 +#define ID_HACKER_SAVE 40010 +#define ID_THREAD_TERMINATE 40011 +#define ID_THREAD_SUSPEND 40012 +#define ID_THREAD_RESUME 40013 +#define ID_THREAD_PERMISSIONS 40015 +#define ID_THREAD_TOKEN 40016 +#define ID_ANALYZE_WAIT 40018 +#define ID_PRIORITY_TIMECRITICAL 40020 +#define ID_PRIORITY_HIGHEST 40021 +#define ID_PRIORITY_ABOVENORMAL 40022 +#define ID_PRIORITY_NORMAL 40023 +#define ID_PRIORITY_BELOWNORMAL 40024 +#define ID_PRIORITY_LOWEST 40025 +#define ID_PRIORITY_IDLE 40026 +#define ID_IOPRIORITY_VERYLOW 40028 +#define ID_IOPRIORITY_LOW 40029 +#define ID_IOPRIORITY_NORMAL 40030 +#define ID_IOPRIORITY_HIGH 40031 +#define ID_PROCESS_RESTART 40032 +#define ID_PROCESS_VIRTUALIZATION 40034 +#define ID_PROCESS_AFFINITY 40035 +#define ID_PROCESS_CREATEDUMPFILE 40036 +#define ID_MISCELLANEOUS_DETACHFROMDEBUGGER 40039 +#define ID_MISCELLANEOUS_HEAPS 40040 +#define ID_MISCELLANEOUS_INJECTDLL 40041 +#define ID_PRIORITY_REALTIME 40048 +#define ID_PRIORITY_HIGH 40049 +#define ID_WINDOW_BRINGTOFRONT 40055 +#define ID_WINDOW_RESTORE 40056 +#define ID_WINDOW_MINIMIZE 40057 +#define ID_WINDOW_MAXIMIZE 40058 +#define ID_WINDOW_CLOSE 40059 +#define ID_PROCESS_SEARCHONLINE 40060 +#define ID_HANDLE_CLOSE 40061 +#define ID_HANDLE_PROTECTED 40062 +#define ID_HANDLE_INHERIT 40063 +#define ID_HANDLE_PROPERTIES 40064 +#define ID_MODULE_UNLOAD 40066 +#define ID_MODULE_PROPERTIES 40068 +#define ID_PROCESS_TERMINATETREE 40069 +#define ID_THREAD_INSPECT 40075 +#define ID_HACKER_RUN 40076 +#define ID_HACKER_RUNASADMINISTRATOR 40077 +#define ID_HACKER_RUNAS 40078 +#define ID_HACKER_SHOWDETAILSFORALLPROCESSES 40079 +#define ID_HACKER_FINDHANDLESORDLLS 40082 +#define ID_HACKER_OPTIONS 40083 +#define ID_VIEW_SYSTEMINFORMATION 40091 +#define ID_TRAYICONS_CPUHISTORY 40093 +#define ID_TRAYICONS_CPUUSAGE 40094 +#define ID_TRAYICONS_COMMITHISTORY 40096 +#define ID_TRAYICONS_PHYSICALMEMORYHISTORY 40097 +#define ID_VIEW_REFRESH 40098 +#define ID_TOOLS_CREATESERVICE 40101 +#define ID_TOOLS_HIDDENPROCESSES 40102 +#define ID_TOOLS_INSPECTEXECUTABLEFILE 40103 +#define ID_HELP_LOG 40104 +#define ID_HELP_DONATE 40105 +#define ID_HELP_ABOUT 40106 +#define ID_SERVICE_GOTOPROCESS 40107 +#define ID_SERVICE_START 40108 +#define ID_SERVICE_CONTINUE 40109 +#define ID_SERVICE_PAUSE 40110 +#define ID_SERVICE_STOP 40111 +#define ID_SERVICE_DELETE 40112 +#define ID_SERVICE_PROPERTIES 40113 +#define ID_SERVICE_OPENKEY 40114 +#define ID_PRIVILEGE_ENABLE 40116 +#define ID_PRIVILEGE_DISABLE 40117 +#define ID_PRIVILEGE_REMOVE 40118 +#define ID_OBJECT_CLOSE 40119 +#define ID_OBJECT_PROPERTIES 40120 +#define ID_HELP_DEBUGCONSOLE 40122 +#define ID_MODULE_SEARCHONLINE 40125 +#define ID_TOOLS_PAGEFILES 40126 +#define ID_USER_DISCONNECT 40127 +#define ID_USER_LOGOFF 40128 +#define ID_USER_SENDMESSAGE 40129 +#define ID_USER_PROPERTIES 40130 +#define ID_USERS_DUMMY 40131 +#define ID_MODULE_INSPECT 40132 +#define ID_PROCESS_DEBUG 40133 +#define ID_USER_CONNECT 40138 +#define ID_NETWORK_GOTOPROCESS 40139 +#define ID_NETWORK_CLOSE 40140 +#define ID_OPACITY_10 40142 +#define ID_OPACITY_20 40143 +#define ID_OPACITY_30 40144 +#define ID_OPACITY_40 40145 +#define ID_OPACITY_50 40146 +#define ID_OPACITY_60 40147 +#define ID_OPACITY_70 40148 +#define ID_OPACITY_80 40149 +#define ID_OPACITY_90 40150 +#define ID_OPACITY_OPAQUE 40151 +#define ID_VIEW_ALWAYSONTOP 40153 +#define ID_UPDATEINTERVAL_FAST 40155 +#define ID_UPDATEINTERVAL_NORMAL 40156 +#define ID_UPDATEINTERVAL_BELOWNORMAL 40157 +#define ID_UPDATEINTERVAL_SLOW 40158 +#define ID_UPDATEINTERVAL_VERYSLOW 40159 +#define ID_COMPUTER_LOCK 40160 +#define ID_COMPUTER_LOGOFF 40161 +#define ID_COMPUTER_SLEEP 40162 +#define ID_COMPUTER_HIBERNATE 40163 +#define ID_COMPUTER_RESTART 40164 +#define ID_COMPUTER_SHUTDOWN 40165 +#define ID_NETWORK_VIEWSTACK 40167 +#define ID_TRAYICONS_IOHISTORY 40168 +#define ID_ICON_EXIT 40169 +#define ID_ICON_SHOWHIDEPROCESSHACKER 40171 +#define ID_ICON_SYSTEMINFORMATION 40172 +#define ID_PROCESSES_DUMMY 40177 +#define ID_NOTIFICATIONS_ENABLEALL 40178 +#define ID_NOTIFICATIONS_DISABLEALL 40179 +#define ID_NOTIFICATIONS_NEWPROCESSES 40180 +#define ID_NOTIFICATIONS_TERMINATEDPROCESSES 40181 +#define ID_NOTIFICATIONS_NEWSERVICES 40182 +#define ID_NOTIFICATIONS_STARTEDSERVICES 40183 +#define ID_NOTIFICATIONS_STOPPEDSERVICES 40184 +#define ID_NOTIFICATIONS_DELETEDSERVICES 40185 +#define ID_MISCELLANEOUS_GDIHANDLES 40188 +#define ID_ESC_EXIT 40190 +#define ID_PROCESS_COPY 40194 +#define ID_THREAD_COPY 40195 +#define ID_PRIVILEGE_COPY 40196 +#define ID_NETWORK_COPY 40197 +#define ID_SERVICE_COPY 40198 +#define ID_MODULE_COPY 40199 +#define ID_HANDLE_COPY 40200 +#define ID_OBJECT_COPY 40201 +#define ID_MEMORY_SAVE 40208 +#define ID_MEMORY_CHANGEPROTECTION 40209 +#define ID_MEMORY_FREE 40210 +#define ID_MEMORY_DECOMMIT 40211 +#define ID_MEMORY_COPY 40213 +#define ID_MEMORY_READWRITEMEMORY 40214 +#define ID_MEMORY_READWRITEADDRESS 40215 +#define ID_FILTER_CONTAINS 40216 +#define ID_FILTER_CONTAINS_CASEINSENSITIVE 40218 +#define ID_FILTER_REGEX 40219 +#define ID_FILTER_REGEX_CASEINSENSITIVE 40221 +#define ID_TAB_NEXT 40223 +#define ID_TAB_PREV 40224 +#define ID_MISCELLANEOUS_RUNAS 40229 +#define ID_MISCELLANEOUS_RUNASTHISUSER 40230 +#define ID_HACKER_PLUGINS 40231 +#define ID_VIEW_HIDEPROCESSESFROMOTHERUSERS 40232 +#define ID_THREAD_AFFINITY 40233 +#define ID_VIEW_HIDESIGNEDPROCESSES 40234 +#define ID_VIEW_UPDATEAUTOMATICALLY 40235 +#define ID_HACKER_RUNASLIMITEDUSER 40236 +#define ID_USER_REMOTECONTROL 40237 +#define ID_PAGEPRIORITY_NORMAL 40239 +#define ID_PAGEPRIORITY_BELOWNORMAL 40240 +#define ID_PAGEPRIORITY_MEDIUM 40241 +#define ID_PAGEPRIORITY_LOW 40242 +#define ID_PAGEPRIORITY_VERYLOW 40243 +#define ID_VIEW_SHOWCPUBELOW001 40246 +#define ID_MODULE_OPENFILELOCATION 40247 +#define ID_PROCESS_OPENFILELOCATION 40248 +#define ID_MISCELLANEOUS_REDUCEWORKINGSET 40249 +#define ID_EMPTY_EMPTYWORKINGSETS 40250 +#define ID_EMPTY_EMPTYMODIFIEDPAGELIST 40251 +#define ID_EMPTY_EMPTYSTANDBYLIST 40252 +#define ID_EMPTY_EMPTYPRIORITY0STANDBYLIST 40253 +#define IDC_BACK 40255 +#define ID_DIGIT1 40263 +#define ID_DIGIT2 40264 +#define ID_DIGIT3 40265 +#define ID_DIGIT4 40266 +#define ID_DIGIT5 40267 +#define ID_DIGIT6 40268 +#define ID_DIGIT7 40269 +#define ID_DIGIT8 40270 +#define ID_DIGIT9 40271 +#define ID_VIEW_HIDEDRIVERSERVICES 40273 +#define ID_VIEW_SECTIONPLACEHOLDER 40274 +#define ID_VIEW_SCROLLTONEWPROCESSES 40275 +#define ID_TOOLS_STARTTASKMANAGER 40277 +#define ID_COMPUTER_SHUTDOWNHYBRID 40278 +#define ID_COMPUTER_RESTARTBOOTOPTIONS 40280 +#define ID_HANDLE_OBJECTPROPERTIES1 40282 +#define ID_HANDLE_OBJECTPROPERTIES2 40283 +#define ID_OBJECT_GOTOOWNINGPROCESS 40284 +#define ID_NETWORK_GOTOSERVICE 40285 +#define ID_SERVICE_OPENFILELOCATION 40286 +#define ID_PROCESS_GOTOPROCESS 40287 +#define ID_MINIINFO_REFRESH 40288 +#define ID_MINIINFO_REFRESHAUTOMATICALLY 40289 +#define ID_ENVIRONMENT_EDIT 40290 +#define ID_ENVIRONMENT_COPY 40291 +#define ID_ENVIRONMENT_DELETE 40292 +#define IDC_MAXSCREEN 40293 +#define IDDYNAMIC 50000 +#define IDPLUGINS 55000 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 228 +#define _APS_NEXT_COMMAND_VALUE 40295 +#define _APS_NEXT_CONTROL_VALUE 1387 +#define _APS_NEXT_SYMED_VALUE 169 +#endif +#endif diff --git a/ProcessHacker/runas.c b/ProcessHacker/runas.c index fb71c6fe94f7..6abbef469ff3 100644 --- a/ProcessHacker/runas.c +++ b/ProcessHacker/runas.c @@ -1,1167 +1,1167 @@ -/* - * Process Hacker - - * run as dialog - * - * Copyright (C) 2010-2013 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -/* - * The run-as mechanism has three stages: - * 1. The user enters the information into the dialog box. Here it is decided whether the run-as - * service is needed. If it is not, PhCreateProcessAsUser is called directly. Otherwise, - * PhExecuteRunAsCommand2 is called for stage 2. - * 2. PhExecuteRunAsCommand2 creates a random service name and tries to create the service and - * execute it (using PhExecuteRunAsCommand). If the process has insufficient permissions, an - * elevated instance of phsvc is started and PhSvcCallExecuteRunAsCommand is called. - * 3. The service is started, and sets up an instance of phsvc with the same random service name as - * its port name. Either the original or elevated Process Hacker instance then calls - * PhSvcCallInvokeRunAsService to complete the operation. - */ - -/* - * - * ProcessHacker.exe (user, limited privileges) - * * | ^ - * | | | phsvc API (LPC) - * | | | - * | v | - * ProcessHacker.exe (user, full privileges) - * | ^ | ^ - * | | SCM API (RPC) | | - * | | | | - * v | | | phsvc API (LPC) - * services.exe | | - * * | | - * | | | - * | | | - * | v | - * ProcessHacker.exe (NT AUTHORITY\SYSTEM) - * * - * | - * | - * | - * program.exe - */ - -#include - -#include -#include -#include - -#include -#include - -#include -#include -#include -#include - -typedef struct _RUNAS_DIALOG_CONTEXT -{ - HANDLE ProcessId; - PPH_LIST DesktopList; - PPH_STRING CurrentWinStaName; -} RUNAS_DIALOG_CONTEXT, *PRUNAS_DIALOG_CONTEXT; - -INT_PTR CALLBACK PhpRunAsDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -VOID PhSetDesktopWinStaAccess( - VOID - ); - -VOID PhpSplitUserName( - _In_ PWSTR UserName, - _Out_ PPH_STRING *DomainPart, - _Out_ PPH_STRING *UserPart - ); - -#define SIP(String, Integer) { (String), (PVOID)(Integer) } - -static PH_KEY_VALUE_PAIR PhpLogonTypePairs[] = -{ - SIP(L"Batch", LOGON32_LOGON_BATCH), - SIP(L"Interactive", LOGON32_LOGON_INTERACTIVE), - SIP(L"Network", LOGON32_LOGON_NETWORK), - SIP(L"New credentials", LOGON32_LOGON_NEW_CREDENTIALS), - SIP(L"Service", LOGON32_LOGON_SERVICE) -}; - -static WCHAR RunAsOldServiceName[32] = L""; -static PH_QUEUED_LOCK RunAsOldServiceLock = PH_QUEUED_LOCK_INIT; - -static PPH_STRING RunAsServiceName; -static SERVICE_STATUS_HANDLE RunAsServiceStatusHandle; -static PHSVC_STOP RunAsServiceStop; - -VOID PhShowRunAsDialog( - _In_ HWND ParentWindowHandle, - _In_opt_ HANDLE ProcessId - ) -{ - RUNAS_DIALOG_CONTEXT context; - - context.ProcessId = ProcessId; - context.DesktopList = NULL; - - DialogBoxParam( - PhInstanceHandle, - MAKEINTRESOURCE(IDD_RUNAS), - ParentWindowHandle, - PhpRunAsDlgProc, - (LPARAM)&context - ); -} - -static VOID PhpAddAccountsToComboBox( - _In_ HWND ComboBoxHandle - ) -{ - LSA_HANDLE policyHandle; - LSA_ENUMERATION_HANDLE enumerationContext = 0; - PLSA_ENUMERATION_INFORMATION buffer; - ULONG count; - ULONG i; - PPH_STRING name; - SID_NAME_USE nameUse; - - if (NT_SUCCESS(PhOpenLsaPolicy(&policyHandle, POLICY_VIEW_LOCAL_INFORMATION, NULL))) - { - while (NT_SUCCESS(LsaEnumerateAccounts( - policyHandle, - &enumerationContext, - &buffer, - 0x100, - &count - ))) - { - for (i = 0; i < count; i++) - { - name = PhGetSidFullName(buffer[i].Sid, TRUE, &nameUse); - - if (name) - { - if (nameUse == SidTypeUser) - ComboBox_AddString(ComboBoxHandle, name->Buffer); - - PhDereferenceObject(name); - } - } - - LsaFreeMemory(buffer); - } - - LsaClose(policyHandle); - } -} - -static BOOLEAN IsServiceAccount( - _In_ PPH_STRING UserName - ) -{ - if ( - PhEqualString2(UserName, L"NT AUTHORITY\\LOCAL SERVICE", TRUE) || - PhEqualString2(UserName, L"NT AUTHORITY\\NETWORK SERVICE", TRUE) || - PhEqualString2(UserName, L"NT AUTHORITY\\SYSTEM", TRUE) - ) - { - return TRUE; - } - else - { - return FALSE; - } -} - -static PPH_STRING GetCurrentWinStaName( - VOID - ) -{ - PPH_STRING string; - - string = PhCreateStringEx(NULL, 0x200); - - if (GetUserObjectInformation( - GetProcessWindowStation(), - UOI_NAME, - string->Buffer, - (ULONG)string->Length + 2, - NULL - )) - { - PhTrimToNullTerminatorString(string); - return string; - } - else - { - PhDereferenceObject(string); - return PhCreateString(L"WinSta0"); // assume the current window station is WinSta0 - } -} - -static BOOL CALLBACK EnumDesktopsCallback( - _In_ PWSTR DesktopName, - _In_ LPARAM Context - ) -{ - PRUNAS_DIALOG_CONTEXT context = (PRUNAS_DIALOG_CONTEXT)Context; - - PhAddItemList(context->DesktopList, PhConcatStrings( - 3, - context->CurrentWinStaName->Buffer, - L"\\", - DesktopName - )); - - return TRUE; -} - -INT_PTR CALLBACK PhpRunAsDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - PRUNAS_DIALOG_CONTEXT context; - - if (uMsg != WM_INITDIALOG) - { - context = (PRUNAS_DIALOG_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom()); - } - else - { - context = (PRUNAS_DIALOG_CONTEXT)lParam; - SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)context); - } - - if (!context) - return FALSE; - - switch (uMsg) - { - case WM_INITDIALOG: - { - HWND typeComboBoxHandle = GetDlgItem(hwndDlg, IDC_TYPE); - HWND userNameComboBoxHandle = GetDlgItem(hwndDlg, IDC_USERNAME); - ULONG sessionId; - - PhCenterWindow(hwndDlg, GetParent(hwndDlg)); - - if (SHAutoComplete_I) - { - SHAutoComplete_I( - GetDlgItem(hwndDlg, IDC_PROGRAM), - SHACF_AUTOAPPEND_FORCE_ON | SHACF_AUTOSUGGEST_FORCE_ON | SHACF_FILESYS_ONLY - ); - } - - ComboBox_AddString(typeComboBoxHandle, L"Batch"); - ComboBox_AddString(typeComboBoxHandle, L"Interactive"); - ComboBox_AddString(typeComboBoxHandle, L"Network"); - ComboBox_AddString(typeComboBoxHandle, L"New credentials"); - ComboBox_AddString(typeComboBoxHandle, L"Service"); - PhSelectComboBoxString(typeComboBoxHandle, L"Interactive", FALSE); - - ComboBox_AddString(userNameComboBoxHandle, L"NT AUTHORITY\\SYSTEM"); - ComboBox_AddString(userNameComboBoxHandle, L"NT AUTHORITY\\LOCAL SERVICE"); - ComboBox_AddString(userNameComboBoxHandle, L"NT AUTHORITY\\NETWORK SERVICE"); - - PhpAddAccountsToComboBox(userNameComboBoxHandle); - - if (NT_SUCCESS(PhGetProcessSessionId(NtCurrentProcess(), &sessionId))) - SetDlgItemInt(hwndDlg, IDC_SESSIONID, sessionId, FALSE); - - SetDlgItemText(hwndDlg, IDC_DESKTOP, L"WinSta0\\Default"); - SetDlgItemText(hwndDlg, IDC_PROGRAM, PhaGetStringSetting(L"RunAsProgram")->Buffer); - - if (!context->ProcessId) - { - SetDlgItemText(hwndDlg, IDC_USERNAME, - PH_AUTO_T(PH_STRING, PhGetStringSetting(L"RunAsUserName"))->Buffer); - - // Fire the user name changed event so we can fix the logon type. - SendMessage(hwndDlg, WM_COMMAND, MAKEWPARAM(IDC_USERNAME, CBN_EDITCHANGE), 0); - } - else - { - HANDLE processHandle; - HANDLE tokenHandle; - PTOKEN_USER user; - PPH_STRING userName; - - if (NT_SUCCESS(PhOpenProcess( - &processHandle, - ProcessQueryAccess, - context->ProcessId - ))) - { - if (NT_SUCCESS(PhOpenProcessToken( - processHandle, - TOKEN_QUERY, - &tokenHandle - ))) - { - if (NT_SUCCESS(PhGetTokenUser(tokenHandle, &user))) - { - if (userName = PhGetSidFullName(user->User.Sid, TRUE, NULL)) - { - SetDlgItemText(hwndDlg, IDC_USERNAME, userName->Buffer); - PhDereferenceObject(userName); - } - - PhFree(user); - } - - NtClose(tokenHandle); - } - - NtClose(processHandle); - } - - EnableWindow(GetDlgItem(hwndDlg, IDC_USERNAME), FALSE); - EnableWindow(GetDlgItem(hwndDlg, IDC_PASSWORD), FALSE); - EnableWindow(GetDlgItem(hwndDlg, IDC_TYPE), FALSE); - } - - SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hwndDlg, IDC_PROGRAM), TRUE); - Edit_SetSel(GetDlgItem(hwndDlg, IDC_PROGRAM), 0, -1); - - //if (!PhGetOwnTokenAttributes().Elevated) - // SendMessage(GetDlgItem(hwndDlg, IDOK), BCM_SETSHIELD, 0, TRUE); - - if (!WINDOWS_HAS_UAC) - ShowWindow(GetDlgItem(hwndDlg, IDC_TOGGLEELEVATION), SW_HIDE); - } - break; - case WM_DESTROY: - { - if (context->DesktopList) - PhDereferenceObject(context->DesktopList); - - RemoveProp(hwndDlg, PhMakeContextAtom()); - } - break; - case WM_COMMAND: - { - switch (LOWORD(wParam)) - { - case IDCANCEL: - EndDialog(hwndDlg, IDCANCEL); - break; - case IDOK: - { - NTSTATUS status; - PPH_STRING program; - PPH_STRING userName; - PPH_STRING password; - PPH_STRING logonTypeString; - ULONG logonType; - ULONG sessionId; - PPH_STRING desktopName; - BOOLEAN useLinkedToken; - - program = PhaGetDlgItemText(hwndDlg, IDC_PROGRAM); - userName = PhaGetDlgItemText(hwndDlg, IDC_USERNAME); - logonTypeString = PhaGetDlgItemText(hwndDlg, IDC_TYPE); - - // Fix up the user name if it doesn't have a domain. - if (PhFindCharInString(userName, 0, '\\') == -1) - { - PSID sid; - PPH_STRING newUserName; - - if (NT_SUCCESS(PhLookupName(&userName->sr, &sid, NULL, NULL))) - { - if (newUserName = PH_AUTO(PhGetSidFullName(sid, TRUE, NULL))) - userName = newUserName; - - PhFree(sid); - } - } - - if (!IsServiceAccount(userName)) - password = PhGetWindowText(GetDlgItem(hwndDlg, IDC_PASSWORD)); - else - password = NULL; - - sessionId = GetDlgItemInt(hwndDlg, IDC_SESSIONID, NULL, FALSE); - desktopName = PhaGetDlgItemText(hwndDlg, IDC_DESKTOP); - - if (WINDOWS_HAS_UAC) - useLinkedToken = Button_GetCheck(GetDlgItem(hwndDlg, IDC_TOGGLEELEVATION)) == BST_CHECKED; - else - useLinkedToken = FALSE; - - if (PhFindIntegerSiKeyValuePairs( - PhpLogonTypePairs, - sizeof(PhpLogonTypePairs), - logonTypeString->Buffer, - &logonType - )) - { - if ( - logonType == LOGON32_LOGON_INTERACTIVE && - !context->ProcessId && - sessionId == NtCurrentPeb()->SessionId && - !useLinkedToken - ) - { - // We are eligible to load the user profile. - // This must be done here, not in the service, because - // we need to be in the target session. - - PH_CREATE_PROCESS_AS_USER_INFO createInfo; - PPH_STRING domainPart; - PPH_STRING userPart; - - PhpSplitUserName(userName->Buffer, &domainPart, &userPart); - - memset(&createInfo, 0, sizeof(PH_CREATE_PROCESS_AS_USER_INFO)); - createInfo.CommandLine = program->Buffer; - createInfo.UserName = userPart->Buffer; - createInfo.DomainName = domainPart->Buffer; - createInfo.Password = PhGetStringOrEmpty(password); - - // Whenever we can, try not to set the desktop name; it breaks a lot of things. - // Note that on XP we must set it, otherwise the program doesn't display correctly. - if (WindowsVersion < WINDOWS_VISTA || (desktopName->Length != 0 && !PhEqualString2(desktopName, L"WinSta0\\Default", TRUE))) - createInfo.DesktopName = desktopName->Buffer; - - PhSetDesktopWinStaAccess(); - - status = PhCreateProcessAsUser( - &createInfo, - PH_CREATE_PROCESS_WITH_PROFILE, - NULL, - NULL, - NULL - ); - - if (domainPart) PhDereferenceObject(domainPart); - if (userPart) PhDereferenceObject(userPart); - } - else - { - status = PhExecuteRunAsCommand2( - hwndDlg, - program->Buffer, - userName->Buffer, - PhGetStringOrEmpty(password), - logonType, - context->ProcessId, - sessionId, - desktopName->Buffer, - useLinkedToken - ); - } - } - else - { - status = STATUS_INVALID_PARAMETER; - } - - if (password) - { - RtlSecureZeroMemory(password->Buffer, password->Length); - PhDereferenceObject(password); - } - - if (!NT_SUCCESS(status)) - { - if (status != STATUS_CANCELLED) - PhShowStatus(hwndDlg, L"Unable to start the program", status, 0); - } - else if (status != STATUS_TIMEOUT) - { - PhSetStringSetting2(L"RunAsProgram", &program->sr); - PhSetStringSetting2(L"RunAsUserName", &userName->sr); - EndDialog(hwndDlg, IDOK); - } - } - break; - case IDC_BROWSE: - { - static PH_FILETYPE_FILTER filters[] = - { - { L"Programs (*.exe;*.pif;*.com;*.bat)", L"*.exe;*.pif;*.com;*.bat" }, - { L"All files (*.*)", L"*.*" } - }; - PVOID fileDialog; - - fileDialog = PhCreateOpenFileDialog(); - PhSetFileDialogFilter(fileDialog, filters, sizeof(filters) / sizeof(PH_FILETYPE_FILTER)); - PhSetFileDialogFileName(fileDialog, PhaGetDlgItemText(hwndDlg, IDC_PROGRAM)->Buffer); - - if (PhShowFileDialog(hwndDlg, fileDialog)) - { - PPH_STRING fileName; - - fileName = PhGetFileDialogFileName(fileDialog); - SetDlgItemText(hwndDlg, IDC_PROGRAM, fileName->Buffer); - PhDereferenceObject(fileName); - } - - PhFreeFileDialog(fileDialog); - } - break; - case IDC_USERNAME: - { - PPH_STRING userName = NULL; - - if (!context->ProcessId && HIWORD(wParam) == CBN_SELCHANGE) - { - userName = PH_AUTO(PhGetComboBoxString(GetDlgItem(hwndDlg, IDC_USERNAME), -1)); - } - else if (!context->ProcessId && ( - HIWORD(wParam) == CBN_EDITCHANGE || - HIWORD(wParam) == CBN_CLOSEUP - )) - { - userName = PhaGetDlgItemText(hwndDlg, IDC_USERNAME); - } - - if (userName) - { - if (IsServiceAccount(userName)) - { - EnableWindow(GetDlgItem(hwndDlg, IDC_PASSWORD), FALSE); - - // Hack for Windows XP - if ( - PhEqualString2(userName, L"NT AUTHORITY\\SYSTEM", TRUE) && - WindowsVersion <= WINDOWS_XP - ) - { - PhSelectComboBoxString(GetDlgItem(hwndDlg, IDC_TYPE), L"New credentials", FALSE); - } - else - { - PhSelectComboBoxString(GetDlgItem(hwndDlg, IDC_TYPE), L"Service", FALSE); - } - } - else - { - EnableWindow(GetDlgItem(hwndDlg, IDC_PASSWORD), TRUE); - PhSelectComboBoxString(GetDlgItem(hwndDlg, IDC_TYPE), L"Interactive", FALSE); - } - } - } - break; - case IDC_SESSIONS: - { - PPH_EMENU sessionsMenu; - PSESSIONIDW sessions; - ULONG numberOfSessions; - ULONG i; - RECT buttonRect; - PPH_EMENU_ITEM selectedItem; - - sessionsMenu = PhCreateEMenu(); - - if (WinStationEnumerateW(NULL, &sessions, &numberOfSessions)) - { - for (i = 0; i < numberOfSessions; i++) - { - PPH_STRING menuString; - WINSTATIONINFORMATION winStationInfo; - ULONG returnLength; - - if (!WinStationQueryInformationW( - NULL, - sessions[i].SessionId, - WinStationInformation, - &winStationInfo, - sizeof(WINSTATIONINFORMATION), - &returnLength - )) - { - winStationInfo.Domain[0] = 0; - winStationInfo.UserName[0] = 0; - } - - if ( - winStationInfo.UserName[0] != 0 && - sessions[i].WinStationName[0] != 0 - ) - { - menuString = PhaFormatString( - L"%u: %s (%s\\%s)", - sessions[i].SessionId, - sessions[i].WinStationName, - winStationInfo.Domain, - winStationInfo.UserName - ); - } - else if (winStationInfo.UserName[0] != 0) - { - menuString = PhaFormatString( - L"%u: %s\\%s", - sessions[i].SessionId, - winStationInfo.Domain, - winStationInfo.UserName - ); - } - else if (sessions[i].WinStationName[0] != 0) - { - menuString = PhaFormatString( - L"%u: %s", - sessions[i].SessionId, - sessions[i].WinStationName - ); - } - else - { - menuString = PhaFormatString(L"%u", sessions[i].SessionId); - } - - PhInsertEMenuItem(sessionsMenu, - PhCreateEMenuItem(0, 0, menuString->Buffer, NULL, UlongToPtr(sessions[i].SessionId)), -1); - } - - WinStationFreeMemory(sessions); - - GetWindowRect(GetDlgItem(hwndDlg, IDC_SESSIONS), &buttonRect); - - selectedItem = PhShowEMenu( - sessionsMenu, - hwndDlg, - PH_EMENU_SHOW_LEFTRIGHT, - PH_ALIGN_LEFT | PH_ALIGN_TOP, - buttonRect.right, - buttonRect.top - ); - - if (selectedItem) - { - SetDlgItemInt( - hwndDlg, - IDC_SESSIONID, - PtrToUlong(selectedItem->Context), - FALSE - ); - } - - PhDestroyEMenu(sessionsMenu); - } - } - break; - case IDC_DESKTOPS: - { - PPH_EMENU desktopsMenu; - ULONG i; - RECT buttonRect; - PPH_EMENU_ITEM selectedItem; - - desktopsMenu = PhCreateEMenu(); - - if (!context->DesktopList) - context->DesktopList = PhCreateList(10); - - context->CurrentWinStaName = GetCurrentWinStaName(); - - EnumDesktops(GetProcessWindowStation(), EnumDesktopsCallback, (LPARAM)context); - - for (i = 0; i < context->DesktopList->Count; i++) - { - PhInsertEMenuItem( - desktopsMenu, - PhCreateEMenuItem(0, 0, ((PPH_STRING)context->DesktopList->Items[i])->Buffer, NULL, NULL), - -1 - ); - } - - GetWindowRect(GetDlgItem(hwndDlg, IDC_DESKTOPS), &buttonRect); - - selectedItem = PhShowEMenu( - desktopsMenu, - hwndDlg, - PH_EMENU_SHOW_LEFTRIGHT, - PH_ALIGN_LEFT | PH_ALIGN_TOP, - buttonRect.right, - buttonRect.top - ); - - if (selectedItem) - { - SetDlgItemText( - hwndDlg, - IDC_DESKTOP, - selectedItem->Text - ); - } - - for (i = 0; i < context->DesktopList->Count; i++) - PhDereferenceObject(context->DesktopList->Items[i]); - - PhClearList(context->DesktopList); - PhDereferenceObject(context->CurrentWinStaName); - PhDestroyEMenu(desktopsMenu); - } - break; - } - } - break; - } - - return FALSE; -} - -/** - * Sets the access control lists of the current window station - * and desktop to allow all access. - */ -VOID PhSetDesktopWinStaAccess( - VOID - ) -{ - static SID_IDENTIFIER_AUTHORITY appPackageAuthority = SECURITY_APP_PACKAGE_AUTHORITY; - - HWINSTA wsHandle; - HDESK desktopHandle; - ULONG allocationLength; - PSECURITY_DESCRIPTOR securityDescriptor; - PACL dacl; - CHAR allAppPackagesSidBuffer[FIELD_OFFSET(SID, SubAuthority) + sizeof(ULONG) * 2]; - PSID allAppPackagesSid; - - // TODO: Set security on the correct window station and desktop. - - allAppPackagesSid = (PISID)allAppPackagesSidBuffer; - RtlInitializeSid(allAppPackagesSid, &appPackageAuthority, SECURITY_BUILTIN_APP_PACKAGE_RID_COUNT); - *RtlSubAuthoritySid(allAppPackagesSid, 0) = SECURITY_APP_PACKAGE_BASE_RID; - *RtlSubAuthoritySid(allAppPackagesSid, 1) = SECURITY_BUILTIN_PACKAGE_ANY_PACKAGE; - - // We create a DACL that allows everyone to access everything. - - allocationLength = SECURITY_DESCRIPTOR_MIN_LENGTH + - (ULONG)sizeof(ACL) + - (ULONG)sizeof(ACCESS_ALLOWED_ACE) + - RtlLengthSid(&PhSeEveryoneSid) + - (ULONG)sizeof(ACCESS_ALLOWED_ACE) + - RtlLengthSid(allAppPackagesSid); - securityDescriptor = PhAllocate(allocationLength); - dacl = (PACL)((PCHAR)securityDescriptor + SECURITY_DESCRIPTOR_MIN_LENGTH); - - RtlCreateSecurityDescriptor(securityDescriptor, SECURITY_DESCRIPTOR_REVISION); - - RtlCreateAcl(dacl, allocationLength - SECURITY_DESCRIPTOR_MIN_LENGTH, ACL_REVISION); - RtlAddAccessAllowedAce(dacl, ACL_REVISION, GENERIC_ALL, &PhSeEveryoneSid); - - if (WindowsVersion >= WINDOWS_8) - { - RtlAddAccessAllowedAce(dacl, ACL_REVISION, GENERIC_ALL, allAppPackagesSid); - } - - RtlSetDaclSecurityDescriptor(securityDescriptor, TRUE, dacl, FALSE); - - if (wsHandle = OpenWindowStation( - L"WinSta0", - FALSE, - WRITE_DAC - )) - { - PhSetObjectSecurity(wsHandle, DACL_SECURITY_INFORMATION, securityDescriptor); - CloseWindowStation(wsHandle); - } - - if (desktopHandle = OpenDesktop( - L"Default", - 0, - FALSE, - WRITE_DAC | DESKTOP_READOBJECTS | DESKTOP_WRITEOBJECTS - )) - { - PhSetObjectSecurity(desktopHandle, DACL_SECURITY_INFORMATION, securityDescriptor); - CloseDesktop(desktopHandle); - } - - PhFree(securityDescriptor); -} - -/** - * Executes the run-as service. - * - * \param Parameters The run-as parameters. - * - * \remarks This function requires administrator-level access. - */ -NTSTATUS PhExecuteRunAsCommand( - _In_ PPH_RUNAS_SERVICE_PARAMETERS Parameters - ) -{ - NTSTATUS status; - ULONG win32Result; - PPH_STRING commandLine; - SC_HANDLE scManagerHandle; - SC_HANDLE serviceHandle; - PPH_STRING portName; - UNICODE_STRING portNameUs; - ULONG attempts; - LARGE_INTEGER interval; - - if (!(scManagerHandle = OpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE))) - return PhGetLastWin32ErrorAsNtStatus(); - - commandLine = PhFormatString(L"\"%s\" -ras \"%s\"", PhApplicationFileName->Buffer, Parameters->ServiceName); - - serviceHandle = CreateService( - scManagerHandle, - Parameters->ServiceName, - Parameters->ServiceName, - SERVICE_ALL_ACCESS, - SERVICE_WIN32_OWN_PROCESS, - SERVICE_DEMAND_START, - SERVICE_ERROR_IGNORE, - commandLine->Buffer, - NULL, - NULL, - NULL, - L"LocalSystem", - L"" - ); - win32Result = GetLastError(); - - PhDereferenceObject(commandLine); - - CloseServiceHandle(scManagerHandle); - - if (!serviceHandle) - { - return NTSTATUS_FROM_WIN32(win32Result); - } - - PhSetDesktopWinStaAccess(); - - StartService(serviceHandle, 0, NULL); - DeleteService(serviceHandle); - - portName = PhConcatStrings2(L"\\BaseNamedObjects\\", Parameters->ServiceName); - PhStringRefToUnicodeString(&portName->sr, &portNameUs); - attempts = 10; - - // Try to connect several times because the server may take - // a while to initialize. - do - { - status = PhSvcConnectToServer(&portNameUs, 0); - - if (NT_SUCCESS(status)) - break; - - interval.QuadPart = -50 * PH_TIMEOUT_MS; - NtDelayExecution(FALSE, &interval); - } while (--attempts != 0); - - PhDereferenceObject(portName); - - if (NT_SUCCESS(status)) - { - status = PhSvcCallInvokeRunAsService(Parameters); - PhSvcDisconnectFromServer(); - } - - if (serviceHandle) - CloseServiceHandle(serviceHandle); - - return status; -} - -/** - * Starts a program as another user. - * - * \param hWnd A handle to the parent window. - * \param Program The command line of the program to start. - * \param UserName The user to start the program as. The user - * name should be specified as: domain\\name. This parameter - * can be NULL if \a ProcessIdWithToken is specified. - * \param Password The password for the specified user. If there - * is no password, specify an empty string. This parameter - * can be NULL if \a ProcessIdWithToken is specified. - * \param LogonType The logon type for the specified user. This - * parameter can be 0 if \a ProcessIdWithToken is specified. - * \param ProcessIdWithToken The ID of a process from which - * to duplicate the token. - * \param SessionId The ID of the session to run the program - * under. - * \param DesktopName The window station and desktop to run the - * program under. - * \param UseLinkedToken Uses the linked token if possible. - * - * \retval STATUS_CANCELLED The user cancelled the operation. - * - * \remarks This function will cause another instance of - * Process Hacker to be executed if the current security context - * does not have sufficient system access. This is done - * through a UAC elevation prompt. - */ -NTSTATUS PhExecuteRunAsCommand2( - _In_ HWND hWnd, - _In_ PWSTR Program, - _In_opt_ PWSTR UserName, - _In_opt_ PWSTR Password, - _In_opt_ ULONG LogonType, - _In_opt_ HANDLE ProcessIdWithToken, - _In_ ULONG SessionId, - _In_ PWSTR DesktopName, - _In_ BOOLEAN UseLinkedToken - ) -{ - NTSTATUS status = STATUS_SUCCESS; - PH_RUNAS_SERVICE_PARAMETERS parameters; - WCHAR serviceName[32]; - PPH_STRING portName; - UNICODE_STRING portNameUs; - - memset(¶meters, 0, sizeof(PH_RUNAS_SERVICE_PARAMETERS)); - parameters.ProcessId = HandleToUlong(ProcessIdWithToken); - parameters.UserName = UserName; - parameters.Password = Password; - parameters.LogonType = LogonType; - parameters.SessionId = SessionId; - parameters.CommandLine = Program; - parameters.DesktopName = DesktopName; - parameters.UseLinkedToken = UseLinkedToken; - - // Try to use an existing instance of the service if possible. - if (RunAsOldServiceName[0] != 0) - { - PhAcquireQueuedLockExclusive(&RunAsOldServiceLock); - - portName = PhConcatStrings2(L"\\BaseNamedObjects\\", RunAsOldServiceName); - PhStringRefToUnicodeString(&portName->sr, &portNameUs); - - if (NT_SUCCESS(PhSvcConnectToServer(&portNameUs, 0))) - { - parameters.ServiceName = RunAsOldServiceName; - status = PhSvcCallInvokeRunAsService(¶meters); - PhSvcDisconnectFromServer(); - - PhDereferenceObject(portName); - PhReleaseQueuedLockExclusive(&RunAsOldServiceLock); - - return status; - } - - PhDereferenceObject(portName); - PhReleaseQueuedLockExclusive(&RunAsOldServiceLock); - } - - // An existing instance was not available. Proceed normally. - - memcpy(serviceName, L"ProcessHacker", 13 * sizeof(WCHAR)); - PhGenerateRandomAlphaString(&serviceName[13], 16); - PhAcquireQueuedLockExclusive(&RunAsOldServiceLock); - memcpy(RunAsOldServiceName, serviceName, sizeof(serviceName)); - PhReleaseQueuedLockExclusive(&RunAsOldServiceLock); - - parameters.ServiceName = serviceName; - - if (PhGetOwnTokenAttributes().Elevated) - { - status = PhExecuteRunAsCommand(¶meters); - } - else - { - if (PhUiConnectToPhSvc(hWnd, FALSE)) - { - status = PhSvcCallExecuteRunAsCommand(¶meters); - PhUiDisconnectFromPhSvc(); - } - else - { - status = STATUS_CANCELLED; - } - } - - return status; -} - -static VOID PhpSplitUserName( - _In_ PWSTR UserName, - _Out_ PPH_STRING *DomainPart, - _Out_ PPH_STRING *UserPart - ) -{ - PH_STRINGREF userName; - PH_STRINGREF domainPart; - PH_STRINGREF userPart; - - PhInitializeStringRefLongHint(&userName, UserName); - - if (PhSplitStringRefAtChar(&userName, '\\', &domainPart, &userPart)) - { - *DomainPart = PhCreateString2(&domainPart); - *UserPart = PhCreateString2(&userPart); - } - else - { - *DomainPart = NULL; - *UserPart = PhCreateString2(&userName); - } -} - -static VOID SetRunAsServiceStatus( - _In_ ULONG State - ) -{ - SERVICE_STATUS status; - - memset(&status, 0, sizeof(SERVICE_STATUS)); - status.dwServiceType = SERVICE_WIN32_OWN_PROCESS; - status.dwCurrentState = State; - status.dwControlsAccepted = SERVICE_ACCEPT_STOP; - - SetServiceStatus(RunAsServiceStatusHandle, &status); -} - -static DWORD WINAPI RunAsServiceHandlerEx( - _In_ DWORD dwControl, - _In_ DWORD dwEventType, - _In_ LPVOID lpEventData, - _In_ LPVOID lpContext - ) -{ - switch (dwControl) - { - case SERVICE_CONTROL_STOP: - PhSvcStop(&RunAsServiceStop); - return NO_ERROR; - case SERVICE_CONTROL_INTERROGATE: - return NO_ERROR; - } - - return ERROR_CALL_NOT_IMPLEMENTED; -} - -static VOID WINAPI RunAsServiceMain( - _In_ DWORD dwArgc, - _In_ LPTSTR *lpszArgv - ) -{ - PPH_STRING portName; - UNICODE_STRING portNameUs; - LARGE_INTEGER timeout; - - memset(&RunAsServiceStop, 0, sizeof(PHSVC_STOP)); - RunAsServiceStatusHandle = RegisterServiceCtrlHandlerEx(RunAsServiceName->Buffer, RunAsServiceHandlerEx, NULL); - SetRunAsServiceStatus(SERVICE_RUNNING); - - portName = PhConcatStrings2(L"\\BaseNamedObjects\\", RunAsServiceName->Buffer); - PhStringRefToUnicodeString(&portName->sr, &portNameUs); - // Use a shorter timeout value to reduce the time spent running as SYSTEM. - timeout.QuadPart = -5 * PH_TIMEOUT_SEC; - - PhSvcMain(&portNameUs, &timeout, &RunAsServiceStop); - - SetRunAsServiceStatus(SERVICE_STOPPED); -} - -NTSTATUS PhRunAsServiceStart( - _In_ PPH_STRING ServiceName - ) -{ - HANDLE tokenHandle; - SERVICE_TABLE_ENTRY entry; - - // Enable some required privileges. - - if (NT_SUCCESS(NtOpenProcessToken( - NtCurrentProcess(), - TOKEN_ADJUST_PRIVILEGES, - &tokenHandle - ))) - { - PhSetTokenPrivilege(tokenHandle, L"SeAssignPrimaryTokenPrivilege", NULL, SE_PRIVILEGE_ENABLED); - PhSetTokenPrivilege(tokenHandle, L"SeBackupPrivilege", NULL, SE_PRIVILEGE_ENABLED); - PhSetTokenPrivilege(tokenHandle, L"SeImpersonatePrivilege", NULL, SE_PRIVILEGE_ENABLED); - PhSetTokenPrivilege(tokenHandle, L"SeIncreaseQuotaPrivilege", NULL, SE_PRIVILEGE_ENABLED); - PhSetTokenPrivilege(tokenHandle, L"SeRestorePrivilege", NULL, SE_PRIVILEGE_ENABLED); - NtClose(tokenHandle); - } - - RunAsServiceName = ServiceName; - - entry.lpServiceName = ServiceName->Buffer; - entry.lpServiceProc = RunAsServiceMain; - - StartServiceCtrlDispatcher(&entry); - - return STATUS_SUCCESS; -} - -NTSTATUS PhInvokeRunAsService( - _In_ PPH_RUNAS_SERVICE_PARAMETERS Parameters - ) -{ - NTSTATUS status; - PPH_STRING domainName; - PPH_STRING userName; - PH_CREATE_PROCESS_AS_USER_INFO createInfo; - ULONG flags; - - if (Parameters->UserName) - { - PhpSplitUserName(Parameters->UserName, &domainName, &userName); - } - else - { - domainName = NULL; - userName = NULL; - } - - memset(&createInfo, 0, sizeof(PH_CREATE_PROCESS_AS_USER_INFO)); - createInfo.ApplicationName = Parameters->FileName; - createInfo.CommandLine = Parameters->CommandLine; - createInfo.CurrentDirectory = Parameters->CurrentDirectory; - createInfo.DomainName = PhGetString(domainName); - createInfo.UserName = PhGetString(userName); - createInfo.Password = Parameters->Password; - createInfo.LogonType = Parameters->LogonType; - createInfo.SessionId = Parameters->SessionId; - createInfo.DesktopName = Parameters->DesktopName; - - flags = PH_CREATE_PROCESS_SET_SESSION_ID; - - if (Parameters->ProcessId) - { - createInfo.ProcessIdWithToken = UlongToHandle(Parameters->ProcessId); - flags |= PH_CREATE_PROCESS_USE_PROCESS_TOKEN; - } - - if (Parameters->UseLinkedToken) - flags |= PH_CREATE_PROCESS_USE_LINKED_TOKEN; - - status = PhCreateProcessAsUser( - &createInfo, - flags, - NULL, - NULL, - NULL - ); - - if (domainName) PhDereferenceObject(domainName); - if (userName) PhDereferenceObject(userName); - - return status; -} +/* + * Process Hacker - + * run as dialog + * + * Copyright (C) 2010-2013 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +/* + * The run-as mechanism has three stages: + * 1. The user enters the information into the dialog box. Here it is decided whether the run-as + * service is needed. If it is not, PhCreateProcessAsUser is called directly. Otherwise, + * PhExecuteRunAsCommand2 is called for stage 2. + * 2. PhExecuteRunAsCommand2 creates a random service name and tries to create the service and + * execute it (using PhExecuteRunAsCommand). If the process has insufficient permissions, an + * elevated instance of phsvc is started and PhSvcCallExecuteRunAsCommand is called. + * 3. The service is started, and sets up an instance of phsvc with the same random service name as + * its port name. Either the original or elevated Process Hacker instance then calls + * PhSvcCallInvokeRunAsService to complete the operation. + */ + +/* + * + * ProcessHacker.exe (user, limited privileges) + * * | ^ + * | | | phsvc API (LPC) + * | | | + * | v | + * ProcessHacker.exe (user, full privileges) + * | ^ | ^ + * | | SCM API (RPC) | | + * | | | | + * v | | | phsvc API (LPC) + * services.exe | | + * * | | + * | | | + * | | | + * | v | + * ProcessHacker.exe (NT AUTHORITY\SYSTEM) + * * + * | + * | + * | + * program.exe + */ + +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +typedef struct _RUNAS_DIALOG_CONTEXT +{ + HANDLE ProcessId; + PPH_LIST DesktopList; + PPH_STRING CurrentWinStaName; +} RUNAS_DIALOG_CONTEXT, *PRUNAS_DIALOG_CONTEXT; + +INT_PTR CALLBACK PhpRunAsDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +VOID PhSetDesktopWinStaAccess( + VOID + ); + +VOID PhpSplitUserName( + _In_ PWSTR UserName, + _Out_ PPH_STRING *DomainPart, + _Out_ PPH_STRING *UserPart + ); + +#define SIP(String, Integer) { (String), (PVOID)(Integer) } + +static PH_KEY_VALUE_PAIR PhpLogonTypePairs[] = +{ + SIP(L"Batch", LOGON32_LOGON_BATCH), + SIP(L"Interactive", LOGON32_LOGON_INTERACTIVE), + SIP(L"Network", LOGON32_LOGON_NETWORK), + SIP(L"New credentials", LOGON32_LOGON_NEW_CREDENTIALS), + SIP(L"Service", LOGON32_LOGON_SERVICE) +}; + +static WCHAR RunAsOldServiceName[32] = L""; +static PH_QUEUED_LOCK RunAsOldServiceLock = PH_QUEUED_LOCK_INIT; + +static PPH_STRING RunAsServiceName; +static SERVICE_STATUS_HANDLE RunAsServiceStatusHandle; +static PHSVC_STOP RunAsServiceStop; + +VOID PhShowRunAsDialog( + _In_ HWND ParentWindowHandle, + _In_opt_ HANDLE ProcessId + ) +{ + RUNAS_DIALOG_CONTEXT context; + + context.ProcessId = ProcessId; + context.DesktopList = NULL; + + DialogBoxParam( + PhInstanceHandle, + MAKEINTRESOURCE(IDD_RUNAS), + ParentWindowHandle, + PhpRunAsDlgProc, + (LPARAM)&context + ); +} + +static VOID PhpAddAccountsToComboBox( + _In_ HWND ComboBoxHandle + ) +{ + LSA_HANDLE policyHandle; + LSA_ENUMERATION_HANDLE enumerationContext = 0; + PLSA_ENUMERATION_INFORMATION buffer; + ULONG count; + ULONG i; + PPH_STRING name; + SID_NAME_USE nameUse; + + if (NT_SUCCESS(PhOpenLsaPolicy(&policyHandle, POLICY_VIEW_LOCAL_INFORMATION, NULL))) + { + while (NT_SUCCESS(LsaEnumerateAccounts( + policyHandle, + &enumerationContext, + &buffer, + 0x100, + &count + ))) + { + for (i = 0; i < count; i++) + { + name = PhGetSidFullName(buffer[i].Sid, TRUE, &nameUse); + + if (name) + { + if (nameUse == SidTypeUser) + ComboBox_AddString(ComboBoxHandle, name->Buffer); + + PhDereferenceObject(name); + } + } + + LsaFreeMemory(buffer); + } + + LsaClose(policyHandle); + } +} + +static BOOLEAN IsServiceAccount( + _In_ PPH_STRING UserName + ) +{ + if ( + PhEqualString2(UserName, L"NT AUTHORITY\\LOCAL SERVICE", TRUE) || + PhEqualString2(UserName, L"NT AUTHORITY\\NETWORK SERVICE", TRUE) || + PhEqualString2(UserName, L"NT AUTHORITY\\SYSTEM", TRUE) + ) + { + return TRUE; + } + else + { + return FALSE; + } +} + +static PPH_STRING GetCurrentWinStaName( + VOID + ) +{ + PPH_STRING string; + + string = PhCreateStringEx(NULL, 0x200); + + if (GetUserObjectInformation( + GetProcessWindowStation(), + UOI_NAME, + string->Buffer, + (ULONG)string->Length + 2, + NULL + )) + { + PhTrimToNullTerminatorString(string); + return string; + } + else + { + PhDereferenceObject(string); + return PhCreateString(L"WinSta0"); // assume the current window station is WinSta0 + } +} + +static BOOL CALLBACK EnumDesktopsCallback( + _In_ PWSTR DesktopName, + _In_ LPARAM Context + ) +{ + PRUNAS_DIALOG_CONTEXT context = (PRUNAS_DIALOG_CONTEXT)Context; + + PhAddItemList(context->DesktopList, PhConcatStrings( + 3, + context->CurrentWinStaName->Buffer, + L"\\", + DesktopName + )); + + return TRUE; +} + +INT_PTR CALLBACK PhpRunAsDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + PRUNAS_DIALOG_CONTEXT context; + + if (uMsg != WM_INITDIALOG) + { + context = (PRUNAS_DIALOG_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom()); + } + else + { + context = (PRUNAS_DIALOG_CONTEXT)lParam; + SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)context); + } + + if (!context) + return FALSE; + + switch (uMsg) + { + case WM_INITDIALOG: + { + HWND typeComboBoxHandle = GetDlgItem(hwndDlg, IDC_TYPE); + HWND userNameComboBoxHandle = GetDlgItem(hwndDlg, IDC_USERNAME); + ULONG sessionId; + + PhCenterWindow(hwndDlg, GetParent(hwndDlg)); + + if (SHAutoComplete_I) + { + SHAutoComplete_I( + GetDlgItem(hwndDlg, IDC_PROGRAM), + SHACF_AUTOAPPEND_FORCE_ON | SHACF_AUTOSUGGEST_FORCE_ON | SHACF_FILESYS_ONLY + ); + } + + ComboBox_AddString(typeComboBoxHandle, L"Batch"); + ComboBox_AddString(typeComboBoxHandle, L"Interactive"); + ComboBox_AddString(typeComboBoxHandle, L"Network"); + ComboBox_AddString(typeComboBoxHandle, L"New credentials"); + ComboBox_AddString(typeComboBoxHandle, L"Service"); + PhSelectComboBoxString(typeComboBoxHandle, L"Interactive", FALSE); + + ComboBox_AddString(userNameComboBoxHandle, L"NT AUTHORITY\\SYSTEM"); + ComboBox_AddString(userNameComboBoxHandle, L"NT AUTHORITY\\LOCAL SERVICE"); + ComboBox_AddString(userNameComboBoxHandle, L"NT AUTHORITY\\NETWORK SERVICE"); + + PhpAddAccountsToComboBox(userNameComboBoxHandle); + + if (NT_SUCCESS(PhGetProcessSessionId(NtCurrentProcess(), &sessionId))) + SetDlgItemInt(hwndDlg, IDC_SESSIONID, sessionId, FALSE); + + SetDlgItemText(hwndDlg, IDC_DESKTOP, L"WinSta0\\Default"); + SetDlgItemText(hwndDlg, IDC_PROGRAM, PhaGetStringSetting(L"RunAsProgram")->Buffer); + + if (!context->ProcessId) + { + SetDlgItemText(hwndDlg, IDC_USERNAME, + PH_AUTO_T(PH_STRING, PhGetStringSetting(L"RunAsUserName"))->Buffer); + + // Fire the user name changed event so we can fix the logon type. + SendMessage(hwndDlg, WM_COMMAND, MAKEWPARAM(IDC_USERNAME, CBN_EDITCHANGE), 0); + } + else + { + HANDLE processHandle; + HANDLE tokenHandle; + PTOKEN_USER user; + PPH_STRING userName; + + if (NT_SUCCESS(PhOpenProcess( + &processHandle, + ProcessQueryAccess, + context->ProcessId + ))) + { + if (NT_SUCCESS(PhOpenProcessToken( + processHandle, + TOKEN_QUERY, + &tokenHandle + ))) + { + if (NT_SUCCESS(PhGetTokenUser(tokenHandle, &user))) + { + if (userName = PhGetSidFullName(user->User.Sid, TRUE, NULL)) + { + SetDlgItemText(hwndDlg, IDC_USERNAME, userName->Buffer); + PhDereferenceObject(userName); + } + + PhFree(user); + } + + NtClose(tokenHandle); + } + + NtClose(processHandle); + } + + EnableWindow(GetDlgItem(hwndDlg, IDC_USERNAME), FALSE); + EnableWindow(GetDlgItem(hwndDlg, IDC_PASSWORD), FALSE); + EnableWindow(GetDlgItem(hwndDlg, IDC_TYPE), FALSE); + } + + SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hwndDlg, IDC_PROGRAM), TRUE); + Edit_SetSel(GetDlgItem(hwndDlg, IDC_PROGRAM), 0, -1); + + //if (!PhGetOwnTokenAttributes().Elevated) + // SendMessage(GetDlgItem(hwndDlg, IDOK), BCM_SETSHIELD, 0, TRUE); + + if (!WINDOWS_HAS_UAC) + ShowWindow(GetDlgItem(hwndDlg, IDC_TOGGLEELEVATION), SW_HIDE); + } + break; + case WM_DESTROY: + { + if (context->DesktopList) + PhDereferenceObject(context->DesktopList); + + RemoveProp(hwndDlg, PhMakeContextAtom()); + } + break; + case WM_COMMAND: + { + switch (LOWORD(wParam)) + { + case IDCANCEL: + EndDialog(hwndDlg, IDCANCEL); + break; + case IDOK: + { + NTSTATUS status; + PPH_STRING program; + PPH_STRING userName; + PPH_STRING password; + PPH_STRING logonTypeString; + ULONG logonType; + ULONG sessionId; + PPH_STRING desktopName; + BOOLEAN useLinkedToken; + + program = PhaGetDlgItemText(hwndDlg, IDC_PROGRAM); + userName = PhaGetDlgItemText(hwndDlg, IDC_USERNAME); + logonTypeString = PhaGetDlgItemText(hwndDlg, IDC_TYPE); + + // Fix up the user name if it doesn't have a domain. + if (PhFindCharInString(userName, 0, '\\') == -1) + { + PSID sid; + PPH_STRING newUserName; + + if (NT_SUCCESS(PhLookupName(&userName->sr, &sid, NULL, NULL))) + { + if (newUserName = PH_AUTO(PhGetSidFullName(sid, TRUE, NULL))) + userName = newUserName; + + PhFree(sid); + } + } + + if (!IsServiceAccount(userName)) + password = PhGetWindowText(GetDlgItem(hwndDlg, IDC_PASSWORD)); + else + password = NULL; + + sessionId = GetDlgItemInt(hwndDlg, IDC_SESSIONID, NULL, FALSE); + desktopName = PhaGetDlgItemText(hwndDlg, IDC_DESKTOP); + + if (WINDOWS_HAS_UAC) + useLinkedToken = Button_GetCheck(GetDlgItem(hwndDlg, IDC_TOGGLEELEVATION)) == BST_CHECKED; + else + useLinkedToken = FALSE; + + if (PhFindIntegerSiKeyValuePairs( + PhpLogonTypePairs, + sizeof(PhpLogonTypePairs), + logonTypeString->Buffer, + &logonType + )) + { + if ( + logonType == LOGON32_LOGON_INTERACTIVE && + !context->ProcessId && + sessionId == NtCurrentPeb()->SessionId && + !useLinkedToken + ) + { + // We are eligible to load the user profile. + // This must be done here, not in the service, because + // we need to be in the target session. + + PH_CREATE_PROCESS_AS_USER_INFO createInfo; + PPH_STRING domainPart; + PPH_STRING userPart; + + PhpSplitUserName(userName->Buffer, &domainPart, &userPart); + + memset(&createInfo, 0, sizeof(PH_CREATE_PROCESS_AS_USER_INFO)); + createInfo.CommandLine = program->Buffer; + createInfo.UserName = userPart->Buffer; + createInfo.DomainName = domainPart->Buffer; + createInfo.Password = PhGetStringOrEmpty(password); + + // Whenever we can, try not to set the desktop name; it breaks a lot of things. + // Note that on XP we must set it, otherwise the program doesn't display correctly. + if (WindowsVersion < WINDOWS_VISTA || (desktopName->Length != 0 && !PhEqualString2(desktopName, L"WinSta0\\Default", TRUE))) + createInfo.DesktopName = desktopName->Buffer; + + PhSetDesktopWinStaAccess(); + + status = PhCreateProcessAsUser( + &createInfo, + PH_CREATE_PROCESS_WITH_PROFILE, + NULL, + NULL, + NULL + ); + + if (domainPart) PhDereferenceObject(domainPart); + if (userPart) PhDereferenceObject(userPart); + } + else + { + status = PhExecuteRunAsCommand2( + hwndDlg, + program->Buffer, + userName->Buffer, + PhGetStringOrEmpty(password), + logonType, + context->ProcessId, + sessionId, + desktopName->Buffer, + useLinkedToken + ); + } + } + else + { + status = STATUS_INVALID_PARAMETER; + } + + if (password) + { + RtlSecureZeroMemory(password->Buffer, password->Length); + PhDereferenceObject(password); + } + + if (!NT_SUCCESS(status)) + { + if (status != STATUS_CANCELLED) + PhShowStatus(hwndDlg, L"Unable to start the program", status, 0); + } + else if (status != STATUS_TIMEOUT) + { + PhSetStringSetting2(L"RunAsProgram", &program->sr); + PhSetStringSetting2(L"RunAsUserName", &userName->sr); + EndDialog(hwndDlg, IDOK); + } + } + break; + case IDC_BROWSE: + { + static PH_FILETYPE_FILTER filters[] = + { + { L"Programs (*.exe;*.pif;*.com;*.bat)", L"*.exe;*.pif;*.com;*.bat" }, + { L"All files (*.*)", L"*.*" } + }; + PVOID fileDialog; + + fileDialog = PhCreateOpenFileDialog(); + PhSetFileDialogFilter(fileDialog, filters, sizeof(filters) / sizeof(PH_FILETYPE_FILTER)); + PhSetFileDialogFileName(fileDialog, PhaGetDlgItemText(hwndDlg, IDC_PROGRAM)->Buffer); + + if (PhShowFileDialog(hwndDlg, fileDialog)) + { + PPH_STRING fileName; + + fileName = PhGetFileDialogFileName(fileDialog); + SetDlgItemText(hwndDlg, IDC_PROGRAM, fileName->Buffer); + PhDereferenceObject(fileName); + } + + PhFreeFileDialog(fileDialog); + } + break; + case IDC_USERNAME: + { + PPH_STRING userName = NULL; + + if (!context->ProcessId && HIWORD(wParam) == CBN_SELCHANGE) + { + userName = PH_AUTO(PhGetComboBoxString(GetDlgItem(hwndDlg, IDC_USERNAME), -1)); + } + else if (!context->ProcessId && ( + HIWORD(wParam) == CBN_EDITCHANGE || + HIWORD(wParam) == CBN_CLOSEUP + )) + { + userName = PhaGetDlgItemText(hwndDlg, IDC_USERNAME); + } + + if (userName) + { + if (IsServiceAccount(userName)) + { + EnableWindow(GetDlgItem(hwndDlg, IDC_PASSWORD), FALSE); + + // Hack for Windows XP + if ( + PhEqualString2(userName, L"NT AUTHORITY\\SYSTEM", TRUE) && + WindowsVersion <= WINDOWS_XP + ) + { + PhSelectComboBoxString(GetDlgItem(hwndDlg, IDC_TYPE), L"New credentials", FALSE); + } + else + { + PhSelectComboBoxString(GetDlgItem(hwndDlg, IDC_TYPE), L"Service", FALSE); + } + } + else + { + EnableWindow(GetDlgItem(hwndDlg, IDC_PASSWORD), TRUE); + PhSelectComboBoxString(GetDlgItem(hwndDlg, IDC_TYPE), L"Interactive", FALSE); + } + } + } + break; + case IDC_SESSIONS: + { + PPH_EMENU sessionsMenu; + PSESSIONIDW sessions; + ULONG numberOfSessions; + ULONG i; + RECT buttonRect; + PPH_EMENU_ITEM selectedItem; + + sessionsMenu = PhCreateEMenu(); + + if (WinStationEnumerateW(NULL, &sessions, &numberOfSessions)) + { + for (i = 0; i < numberOfSessions; i++) + { + PPH_STRING menuString; + WINSTATIONINFORMATION winStationInfo; + ULONG returnLength; + + if (!WinStationQueryInformationW( + NULL, + sessions[i].SessionId, + WinStationInformation, + &winStationInfo, + sizeof(WINSTATIONINFORMATION), + &returnLength + )) + { + winStationInfo.Domain[0] = 0; + winStationInfo.UserName[0] = 0; + } + + if ( + winStationInfo.UserName[0] != 0 && + sessions[i].WinStationName[0] != 0 + ) + { + menuString = PhaFormatString( + L"%u: %s (%s\\%s)", + sessions[i].SessionId, + sessions[i].WinStationName, + winStationInfo.Domain, + winStationInfo.UserName + ); + } + else if (winStationInfo.UserName[0] != 0) + { + menuString = PhaFormatString( + L"%u: %s\\%s", + sessions[i].SessionId, + winStationInfo.Domain, + winStationInfo.UserName + ); + } + else if (sessions[i].WinStationName[0] != 0) + { + menuString = PhaFormatString( + L"%u: %s", + sessions[i].SessionId, + sessions[i].WinStationName + ); + } + else + { + menuString = PhaFormatString(L"%u", sessions[i].SessionId); + } + + PhInsertEMenuItem(sessionsMenu, + PhCreateEMenuItem(0, 0, menuString->Buffer, NULL, UlongToPtr(sessions[i].SessionId)), -1); + } + + WinStationFreeMemory(sessions); + + GetWindowRect(GetDlgItem(hwndDlg, IDC_SESSIONS), &buttonRect); + + selectedItem = PhShowEMenu( + sessionsMenu, + hwndDlg, + PH_EMENU_SHOW_LEFTRIGHT, + PH_ALIGN_LEFT | PH_ALIGN_TOP, + buttonRect.right, + buttonRect.top + ); + + if (selectedItem) + { + SetDlgItemInt( + hwndDlg, + IDC_SESSIONID, + PtrToUlong(selectedItem->Context), + FALSE + ); + } + + PhDestroyEMenu(sessionsMenu); + } + } + break; + case IDC_DESKTOPS: + { + PPH_EMENU desktopsMenu; + ULONG i; + RECT buttonRect; + PPH_EMENU_ITEM selectedItem; + + desktopsMenu = PhCreateEMenu(); + + if (!context->DesktopList) + context->DesktopList = PhCreateList(10); + + context->CurrentWinStaName = GetCurrentWinStaName(); + + EnumDesktops(GetProcessWindowStation(), EnumDesktopsCallback, (LPARAM)context); + + for (i = 0; i < context->DesktopList->Count; i++) + { + PhInsertEMenuItem( + desktopsMenu, + PhCreateEMenuItem(0, 0, ((PPH_STRING)context->DesktopList->Items[i])->Buffer, NULL, NULL), + -1 + ); + } + + GetWindowRect(GetDlgItem(hwndDlg, IDC_DESKTOPS), &buttonRect); + + selectedItem = PhShowEMenu( + desktopsMenu, + hwndDlg, + PH_EMENU_SHOW_LEFTRIGHT, + PH_ALIGN_LEFT | PH_ALIGN_TOP, + buttonRect.right, + buttonRect.top + ); + + if (selectedItem) + { + SetDlgItemText( + hwndDlg, + IDC_DESKTOP, + selectedItem->Text + ); + } + + for (i = 0; i < context->DesktopList->Count; i++) + PhDereferenceObject(context->DesktopList->Items[i]); + + PhClearList(context->DesktopList); + PhDereferenceObject(context->CurrentWinStaName); + PhDestroyEMenu(desktopsMenu); + } + break; + } + } + break; + } + + return FALSE; +} + +/** + * Sets the access control lists of the current window station + * and desktop to allow all access. + */ +VOID PhSetDesktopWinStaAccess( + VOID + ) +{ + static SID_IDENTIFIER_AUTHORITY appPackageAuthority = SECURITY_APP_PACKAGE_AUTHORITY; + + HWINSTA wsHandle; + HDESK desktopHandle; + ULONG allocationLength; + PSECURITY_DESCRIPTOR securityDescriptor; + PACL dacl; + CHAR allAppPackagesSidBuffer[FIELD_OFFSET(SID, SubAuthority) + sizeof(ULONG) * 2]; + PSID allAppPackagesSid; + + // TODO: Set security on the correct window station and desktop. + + allAppPackagesSid = (PISID)allAppPackagesSidBuffer; + RtlInitializeSid(allAppPackagesSid, &appPackageAuthority, SECURITY_BUILTIN_APP_PACKAGE_RID_COUNT); + *RtlSubAuthoritySid(allAppPackagesSid, 0) = SECURITY_APP_PACKAGE_BASE_RID; + *RtlSubAuthoritySid(allAppPackagesSid, 1) = SECURITY_BUILTIN_PACKAGE_ANY_PACKAGE; + + // We create a DACL that allows everyone to access everything. + + allocationLength = SECURITY_DESCRIPTOR_MIN_LENGTH + + (ULONG)sizeof(ACL) + + (ULONG)sizeof(ACCESS_ALLOWED_ACE) + + RtlLengthSid(&PhSeEveryoneSid) + + (ULONG)sizeof(ACCESS_ALLOWED_ACE) + + RtlLengthSid(allAppPackagesSid); + securityDescriptor = PhAllocate(allocationLength); + dacl = (PACL)((PCHAR)securityDescriptor + SECURITY_DESCRIPTOR_MIN_LENGTH); + + RtlCreateSecurityDescriptor(securityDescriptor, SECURITY_DESCRIPTOR_REVISION); + + RtlCreateAcl(dacl, allocationLength - SECURITY_DESCRIPTOR_MIN_LENGTH, ACL_REVISION); + RtlAddAccessAllowedAce(dacl, ACL_REVISION, GENERIC_ALL, &PhSeEveryoneSid); + + if (WindowsVersion >= WINDOWS_8) + { + RtlAddAccessAllowedAce(dacl, ACL_REVISION, GENERIC_ALL, allAppPackagesSid); + } + + RtlSetDaclSecurityDescriptor(securityDescriptor, TRUE, dacl, FALSE); + + if (wsHandle = OpenWindowStation( + L"WinSta0", + FALSE, + WRITE_DAC + )) + { + PhSetObjectSecurity(wsHandle, DACL_SECURITY_INFORMATION, securityDescriptor); + CloseWindowStation(wsHandle); + } + + if (desktopHandle = OpenDesktop( + L"Default", + 0, + FALSE, + WRITE_DAC | DESKTOP_READOBJECTS | DESKTOP_WRITEOBJECTS + )) + { + PhSetObjectSecurity(desktopHandle, DACL_SECURITY_INFORMATION, securityDescriptor); + CloseDesktop(desktopHandle); + } + + PhFree(securityDescriptor); +} + +/** + * Executes the run-as service. + * + * \param Parameters The run-as parameters. + * + * \remarks This function requires administrator-level access. + */ +NTSTATUS PhExecuteRunAsCommand( + _In_ PPH_RUNAS_SERVICE_PARAMETERS Parameters + ) +{ + NTSTATUS status; + ULONG win32Result; + PPH_STRING commandLine; + SC_HANDLE scManagerHandle; + SC_HANDLE serviceHandle; + PPH_STRING portName; + UNICODE_STRING portNameUs; + ULONG attempts; + LARGE_INTEGER interval; + + if (!(scManagerHandle = OpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE))) + return PhGetLastWin32ErrorAsNtStatus(); + + commandLine = PhFormatString(L"\"%s\" -ras \"%s\"", PhApplicationFileName->Buffer, Parameters->ServiceName); + + serviceHandle = CreateService( + scManagerHandle, + Parameters->ServiceName, + Parameters->ServiceName, + SERVICE_ALL_ACCESS, + SERVICE_WIN32_OWN_PROCESS, + SERVICE_DEMAND_START, + SERVICE_ERROR_IGNORE, + commandLine->Buffer, + NULL, + NULL, + NULL, + L"LocalSystem", + L"" + ); + win32Result = GetLastError(); + + PhDereferenceObject(commandLine); + + CloseServiceHandle(scManagerHandle); + + if (!serviceHandle) + { + return NTSTATUS_FROM_WIN32(win32Result); + } + + PhSetDesktopWinStaAccess(); + + StartService(serviceHandle, 0, NULL); + DeleteService(serviceHandle); + + portName = PhConcatStrings2(L"\\BaseNamedObjects\\", Parameters->ServiceName); + PhStringRefToUnicodeString(&portName->sr, &portNameUs); + attempts = 10; + + // Try to connect several times because the server may take + // a while to initialize. + do + { + status = PhSvcConnectToServer(&portNameUs, 0); + + if (NT_SUCCESS(status)) + break; + + interval.QuadPart = -50 * PH_TIMEOUT_MS; + NtDelayExecution(FALSE, &interval); + } while (--attempts != 0); + + PhDereferenceObject(portName); + + if (NT_SUCCESS(status)) + { + status = PhSvcCallInvokeRunAsService(Parameters); + PhSvcDisconnectFromServer(); + } + + if (serviceHandle) + CloseServiceHandle(serviceHandle); + + return status; +} + +/** + * Starts a program as another user. + * + * \param hWnd A handle to the parent window. + * \param Program The command line of the program to start. + * \param UserName The user to start the program as. The user + * name should be specified as: domain\\name. This parameter + * can be NULL if \a ProcessIdWithToken is specified. + * \param Password The password for the specified user. If there + * is no password, specify an empty string. This parameter + * can be NULL if \a ProcessIdWithToken is specified. + * \param LogonType The logon type for the specified user. This + * parameter can be 0 if \a ProcessIdWithToken is specified. + * \param ProcessIdWithToken The ID of a process from which + * to duplicate the token. + * \param SessionId The ID of the session to run the program + * under. + * \param DesktopName The window station and desktop to run the + * program under. + * \param UseLinkedToken Uses the linked token if possible. + * + * \retval STATUS_CANCELLED The user cancelled the operation. + * + * \remarks This function will cause another instance of + * Process Hacker to be executed if the current security context + * does not have sufficient system access. This is done + * through a UAC elevation prompt. + */ +NTSTATUS PhExecuteRunAsCommand2( + _In_ HWND hWnd, + _In_ PWSTR Program, + _In_opt_ PWSTR UserName, + _In_opt_ PWSTR Password, + _In_opt_ ULONG LogonType, + _In_opt_ HANDLE ProcessIdWithToken, + _In_ ULONG SessionId, + _In_ PWSTR DesktopName, + _In_ BOOLEAN UseLinkedToken + ) +{ + NTSTATUS status = STATUS_SUCCESS; + PH_RUNAS_SERVICE_PARAMETERS parameters; + WCHAR serviceName[32]; + PPH_STRING portName; + UNICODE_STRING portNameUs; + + memset(¶meters, 0, sizeof(PH_RUNAS_SERVICE_PARAMETERS)); + parameters.ProcessId = HandleToUlong(ProcessIdWithToken); + parameters.UserName = UserName; + parameters.Password = Password; + parameters.LogonType = LogonType; + parameters.SessionId = SessionId; + parameters.CommandLine = Program; + parameters.DesktopName = DesktopName; + parameters.UseLinkedToken = UseLinkedToken; + + // Try to use an existing instance of the service if possible. + if (RunAsOldServiceName[0] != 0) + { + PhAcquireQueuedLockExclusive(&RunAsOldServiceLock); + + portName = PhConcatStrings2(L"\\BaseNamedObjects\\", RunAsOldServiceName); + PhStringRefToUnicodeString(&portName->sr, &portNameUs); + + if (NT_SUCCESS(PhSvcConnectToServer(&portNameUs, 0))) + { + parameters.ServiceName = RunAsOldServiceName; + status = PhSvcCallInvokeRunAsService(¶meters); + PhSvcDisconnectFromServer(); + + PhDereferenceObject(portName); + PhReleaseQueuedLockExclusive(&RunAsOldServiceLock); + + return status; + } + + PhDereferenceObject(portName); + PhReleaseQueuedLockExclusive(&RunAsOldServiceLock); + } + + // An existing instance was not available. Proceed normally. + + memcpy(serviceName, L"ProcessHacker", 13 * sizeof(WCHAR)); + PhGenerateRandomAlphaString(&serviceName[13], 16); + PhAcquireQueuedLockExclusive(&RunAsOldServiceLock); + memcpy(RunAsOldServiceName, serviceName, sizeof(serviceName)); + PhReleaseQueuedLockExclusive(&RunAsOldServiceLock); + + parameters.ServiceName = serviceName; + + if (PhGetOwnTokenAttributes().Elevated) + { + status = PhExecuteRunAsCommand(¶meters); + } + else + { + if (PhUiConnectToPhSvc(hWnd, FALSE)) + { + status = PhSvcCallExecuteRunAsCommand(¶meters); + PhUiDisconnectFromPhSvc(); + } + else + { + status = STATUS_CANCELLED; + } + } + + return status; +} + +static VOID PhpSplitUserName( + _In_ PWSTR UserName, + _Out_ PPH_STRING *DomainPart, + _Out_ PPH_STRING *UserPart + ) +{ + PH_STRINGREF userName; + PH_STRINGREF domainPart; + PH_STRINGREF userPart; + + PhInitializeStringRefLongHint(&userName, UserName); + + if (PhSplitStringRefAtChar(&userName, '\\', &domainPart, &userPart)) + { + *DomainPart = PhCreateString2(&domainPart); + *UserPart = PhCreateString2(&userPart); + } + else + { + *DomainPart = NULL; + *UserPart = PhCreateString2(&userName); + } +} + +static VOID SetRunAsServiceStatus( + _In_ ULONG State + ) +{ + SERVICE_STATUS status; + + memset(&status, 0, sizeof(SERVICE_STATUS)); + status.dwServiceType = SERVICE_WIN32_OWN_PROCESS; + status.dwCurrentState = State; + status.dwControlsAccepted = SERVICE_ACCEPT_STOP; + + SetServiceStatus(RunAsServiceStatusHandle, &status); +} + +static DWORD WINAPI RunAsServiceHandlerEx( + _In_ DWORD dwControl, + _In_ DWORD dwEventType, + _In_ LPVOID lpEventData, + _In_ LPVOID lpContext + ) +{ + switch (dwControl) + { + case SERVICE_CONTROL_STOP: + PhSvcStop(&RunAsServiceStop); + return NO_ERROR; + case SERVICE_CONTROL_INTERROGATE: + return NO_ERROR; + } + + return ERROR_CALL_NOT_IMPLEMENTED; +} + +static VOID WINAPI RunAsServiceMain( + _In_ DWORD dwArgc, + _In_ LPTSTR *lpszArgv + ) +{ + PPH_STRING portName; + UNICODE_STRING portNameUs; + LARGE_INTEGER timeout; + + memset(&RunAsServiceStop, 0, sizeof(PHSVC_STOP)); + RunAsServiceStatusHandle = RegisterServiceCtrlHandlerEx(RunAsServiceName->Buffer, RunAsServiceHandlerEx, NULL); + SetRunAsServiceStatus(SERVICE_RUNNING); + + portName = PhConcatStrings2(L"\\BaseNamedObjects\\", RunAsServiceName->Buffer); + PhStringRefToUnicodeString(&portName->sr, &portNameUs); + // Use a shorter timeout value to reduce the time spent running as SYSTEM. + timeout.QuadPart = -5 * PH_TIMEOUT_SEC; + + PhSvcMain(&portNameUs, &timeout, &RunAsServiceStop); + + SetRunAsServiceStatus(SERVICE_STOPPED); +} + +NTSTATUS PhRunAsServiceStart( + _In_ PPH_STRING ServiceName + ) +{ + HANDLE tokenHandle; + SERVICE_TABLE_ENTRY entry; + + // Enable some required privileges. + + if (NT_SUCCESS(NtOpenProcessToken( + NtCurrentProcess(), + TOKEN_ADJUST_PRIVILEGES, + &tokenHandle + ))) + { + PhSetTokenPrivilege(tokenHandle, L"SeAssignPrimaryTokenPrivilege", NULL, SE_PRIVILEGE_ENABLED); + PhSetTokenPrivilege(tokenHandle, L"SeBackupPrivilege", NULL, SE_PRIVILEGE_ENABLED); + PhSetTokenPrivilege(tokenHandle, L"SeImpersonatePrivilege", NULL, SE_PRIVILEGE_ENABLED); + PhSetTokenPrivilege(tokenHandle, L"SeIncreaseQuotaPrivilege", NULL, SE_PRIVILEGE_ENABLED); + PhSetTokenPrivilege(tokenHandle, L"SeRestorePrivilege", NULL, SE_PRIVILEGE_ENABLED); + NtClose(tokenHandle); + } + + RunAsServiceName = ServiceName; + + entry.lpServiceName = ServiceName->Buffer; + entry.lpServiceProc = RunAsServiceMain; + + StartServiceCtrlDispatcher(&entry); + + return STATUS_SUCCESS; +} + +NTSTATUS PhInvokeRunAsService( + _In_ PPH_RUNAS_SERVICE_PARAMETERS Parameters + ) +{ + NTSTATUS status; + PPH_STRING domainName; + PPH_STRING userName; + PH_CREATE_PROCESS_AS_USER_INFO createInfo; + ULONG flags; + + if (Parameters->UserName) + { + PhpSplitUserName(Parameters->UserName, &domainName, &userName); + } + else + { + domainName = NULL; + userName = NULL; + } + + memset(&createInfo, 0, sizeof(PH_CREATE_PROCESS_AS_USER_INFO)); + createInfo.ApplicationName = Parameters->FileName; + createInfo.CommandLine = Parameters->CommandLine; + createInfo.CurrentDirectory = Parameters->CurrentDirectory; + createInfo.DomainName = PhGetString(domainName); + createInfo.UserName = PhGetString(userName); + createInfo.Password = Parameters->Password; + createInfo.LogonType = Parameters->LogonType; + createInfo.SessionId = Parameters->SessionId; + createInfo.DesktopName = Parameters->DesktopName; + + flags = PH_CREATE_PROCESS_SET_SESSION_ID; + + if (Parameters->ProcessId) + { + createInfo.ProcessIdWithToken = UlongToHandle(Parameters->ProcessId); + flags |= PH_CREATE_PROCESS_USE_PROCESS_TOKEN; + } + + if (Parameters->UseLinkedToken) + flags |= PH_CREATE_PROCESS_USE_LINKED_TOKEN; + + status = PhCreateProcessAsUser( + &createInfo, + flags, + NULL, + NULL, + NULL + ); + + if (domainName) PhDereferenceObject(domainName); + if (userName) PhDereferenceObject(userName); + + return status; +} diff --git a/ProcessHacker/sdk/phdk.h b/ProcessHacker/sdk/phdk.h index ddecc15ff419..59303ee4416a 100644 --- a/ProcessHacker/sdk/phdk.h +++ b/ProcessHacker/sdk/phdk.h @@ -1,26 +1,26 @@ -#ifndef _PH_PHDK_H -#define _PH_PHDK_H - -#pragma once - -#define PHNT_VERSION PHNT_WIN7 -#define PHAPPAPI __declspec(dllimport) - -#include "ph.h" -#include "phnet.h" -#include "provider.h" -#include "filestream.h" -#include "fastlock.h" -#include "lsasup.h" -#include "svcsup.h" -#include "circbuf.h" -#include "dltmgr.h" -#include "guisup.h" -#include "treenew.h" -#include "graph.h" -#include "emenu.h" -#include "cpysave.h" - -#include "phapppub.h" - -#endif +#ifndef _PH_PHDK_H +#define _PH_PHDK_H + +#pragma once + +#define PHNT_VERSION PHNT_WIN7 +#define PHAPPAPI __declspec(dllimport) + +#include "ph.h" +#include "phnet.h" +#include "provider.h" +#include "filestream.h" +#include "fastlock.h" +#include "lsasup.h" +#include "svcsup.h" +#include "circbuf.h" +#include "dltmgr.h" +#include "guisup.h" +#include "treenew.h" +#include "graph.h" +#include "emenu.h" +#include "cpysave.h" + +#include "phapppub.h" + +#endif diff --git a/ProcessHacker/sdk/readme.txt b/ProcessHacker/sdk/readme.txt index deae177e4c41..abff41352718 100644 --- a/ProcessHacker/sdk/readme.txt +++ b/ProcessHacker/sdk/readme.txt @@ -1,37 +1,37 @@ -This SDK allows you to create plugins for Process Hacker. - -Doxygen output is supplied in the doc\doxygen directory. -Header files are supplied in the include directory. -Import libraries are supplied in the lib directory. -Samples are supplied in the samples directory. - -The latest version of the Windows SDK is required to build -plugins. - -Add the include directory to your compiler's include paths, -and add the lib\ directory to your compiler's library -paths. Your plugin must be a DLL, and should at minimum use the -libraries ProcessHacker.lib and ntdll.lib. Your plugin should -include the header file in order to gain access to: - -* phlib functions -* Process Hacker application functions -* The Native API - -Some functions are not exported by Process Hacker. If you -receive linker errors, check if the relevant function is -marked with PHLIBAPI or PHAPPAPI; if not, the function -cannot be used by your plugin. - -If you wish to use Native API functions available only on -platforms newer than Windows 7, set PHNT_VERSION to the -appropriate value before including : - - #define PHNT_VERSION PHNT_WIN8 // or PHNT_WIN10 - #include - -To load a plugin, create a directory named "plugins" in the -same directory as ProcessHacker.exe and copy the plugin DLL -file into that directory. Then enable plugins in Options and -restart Process Hacker. Note that plugins will only work if -Process Hacker's executable file is named ProcessHacker.exe. +This SDK allows you to create plugins for Process Hacker. + +Doxygen output is supplied in the doc\doxygen directory. +Header files are supplied in the include directory. +Import libraries are supplied in the lib directory. +Samples are supplied in the samples directory. + +The latest version of the Windows SDK is required to build +plugins. + +Add the include directory to your compiler's include paths, +and add the lib\ directory to your compiler's library +paths. Your plugin must be a DLL, and should at minimum use the +libraries ProcessHacker.lib and ntdll.lib. Your plugin should +include the header file in order to gain access to: + +* phlib functions +* Process Hacker application functions +* The Native API + +Some functions are not exported by Process Hacker. If you +receive linker errors, check if the relevant function is +marked with PHLIBAPI or PHAPPAPI; if not, the function +cannot be used by your plugin. + +If you wish to use Native API functions available only on +platforms newer than Windows 7, set PHNT_VERSION to the +appropriate value before including : + + #define PHNT_VERSION PHNT_WIN8 // or PHNT_WIN10 + #include + +To load a plugin, create a directory named "plugins" in the +same directory as ProcessHacker.exe and copy the plugin DLL +file into that directory. Then enable plugins in Options and +restart Process Hacker. Note that plugins will only work if +Process Hacker's executable file is named ProcessHacker.exe. diff --git a/ProcessHacker/sessmsg.c b/ProcessHacker/sessmsg.c index 776f8d1995d5..2e48174e87e2 100644 --- a/ProcessHacker/sessmsg.c +++ b/ProcessHacker/sessmsg.c @@ -1,160 +1,160 @@ -/* - * Process Hacker - - * send message window - * - * Copyright (C) 2010-2013 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include - -#include -#include - -#define SIP(String, Integer) { (String), (PVOID)(Integer) } - -static PH_KEY_VALUE_PAIR PhpMessageBoxIconPairs[] = -{ - SIP(L"None", 0), - SIP(L"Information", MB_ICONINFORMATION), - SIP(L"Warning", MB_ICONWARNING), - SIP(L"Error", MB_ICONERROR), - SIP(L"Question", MB_ICONQUESTION) -}; - -INT_PTR CALLBACK PhpSessionSendMessageDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -VOID PhShowSessionSendMessageDialog( - _In_ HWND ParentWindowHandle, - _In_ ULONG SessionId - ) -{ - DialogBoxParam( - PhInstanceHandle, - MAKEINTRESOURCE(IDD_EDITMESSAGE), - ParentWindowHandle, - PhpSessionSendMessageDlgProc, - (LPARAM)SessionId - ); -} - -INT_PTR CALLBACK PhpSessionSendMessageDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - switch (uMsg) - { - case WM_INITDIALOG: - { - HWND iconComboBox; - - SetProp(hwndDlg, L"SessionId", UlongToHandle((ULONG)lParam)); - PhCenterWindow(hwndDlg, GetParent(hwndDlg)); - - iconComboBox = GetDlgItem(hwndDlg, IDC_TYPE); - - ComboBox_AddString(iconComboBox, L"None"); - ComboBox_AddString(iconComboBox, L"Information"); - ComboBox_AddString(iconComboBox, L"Warning"); - ComboBox_AddString(iconComboBox, L"Error"); - ComboBox_AddString(iconComboBox, L"Question"); - PhSelectComboBoxString(iconComboBox, L"None", FALSE); - - if (PhCurrentUserName) - { - SetDlgItemText( - hwndDlg, - IDC_TITLE, - PhaFormatString(L"Message from %s", PhCurrentUserName->Buffer)->Buffer - ); - } - - SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hwndDlg, IDC_TEXT), TRUE); - } - break; - case WM_DESTROY: - { - RemoveProp(hwndDlg, L"SessionId"); - } - break; - case WM_COMMAND: - { - switch (LOWORD(wParam)) - { - case IDCANCEL: - EndDialog(hwndDlg, IDCANCEL); - break; - case IDOK: - { - ULONG sessionId = HandleToUlong(GetProp(hwndDlg, L"SessionId")); - PPH_STRING title; - PPH_STRING text; - ULONG icon = 0; - ULONG64 timeout = 0; - ULONG response; - - title = PhaGetDlgItemText(hwndDlg, IDC_TITLE); - text = PhaGetDlgItemText(hwndDlg, IDC_TEXT); - - PhFindIntegerSiKeyValuePairs( - PhpMessageBoxIconPairs, - sizeof(PhpMessageBoxIconPairs), - PhaGetDlgItemText(hwndDlg, IDC_TYPE)->Buffer, - &icon - ); - PhStringToInteger64( - &PhaGetDlgItemText(hwndDlg, IDC_TIMEOUT)->sr, - 10, - &timeout - ); - - if (WinStationSendMessageW( - NULL, - sessionId, - title->Buffer, - (ULONG)title->Length, - text->Buffer, - (ULONG)text->Length, - icon, - (ULONG)timeout, - &response, - TRUE - )) - { - EndDialog(hwndDlg, IDOK); - } - else - { - PhShowStatus(hwndDlg, L"Unable to send the message", 0, GetLastError()); - } - } - break; - } - } - break; - } - - return FALSE; -} +/* + * Process Hacker - + * send message window + * + * Copyright (C) 2010-2013 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include + +#include +#include + +#define SIP(String, Integer) { (String), (PVOID)(Integer) } + +static PH_KEY_VALUE_PAIR PhpMessageBoxIconPairs[] = +{ + SIP(L"None", 0), + SIP(L"Information", MB_ICONINFORMATION), + SIP(L"Warning", MB_ICONWARNING), + SIP(L"Error", MB_ICONERROR), + SIP(L"Question", MB_ICONQUESTION) +}; + +INT_PTR CALLBACK PhpSessionSendMessageDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +VOID PhShowSessionSendMessageDialog( + _In_ HWND ParentWindowHandle, + _In_ ULONG SessionId + ) +{ + DialogBoxParam( + PhInstanceHandle, + MAKEINTRESOURCE(IDD_EDITMESSAGE), + ParentWindowHandle, + PhpSessionSendMessageDlgProc, + (LPARAM)SessionId + ); +} + +INT_PTR CALLBACK PhpSessionSendMessageDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + switch (uMsg) + { + case WM_INITDIALOG: + { + HWND iconComboBox; + + SetProp(hwndDlg, L"SessionId", UlongToHandle((ULONG)lParam)); + PhCenterWindow(hwndDlg, GetParent(hwndDlg)); + + iconComboBox = GetDlgItem(hwndDlg, IDC_TYPE); + + ComboBox_AddString(iconComboBox, L"None"); + ComboBox_AddString(iconComboBox, L"Information"); + ComboBox_AddString(iconComboBox, L"Warning"); + ComboBox_AddString(iconComboBox, L"Error"); + ComboBox_AddString(iconComboBox, L"Question"); + PhSelectComboBoxString(iconComboBox, L"None", FALSE); + + if (PhCurrentUserName) + { + SetDlgItemText( + hwndDlg, + IDC_TITLE, + PhaFormatString(L"Message from %s", PhCurrentUserName->Buffer)->Buffer + ); + } + + SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hwndDlg, IDC_TEXT), TRUE); + } + break; + case WM_DESTROY: + { + RemoveProp(hwndDlg, L"SessionId"); + } + break; + case WM_COMMAND: + { + switch (LOWORD(wParam)) + { + case IDCANCEL: + EndDialog(hwndDlg, IDCANCEL); + break; + case IDOK: + { + ULONG sessionId = HandleToUlong(GetProp(hwndDlg, L"SessionId")); + PPH_STRING title; + PPH_STRING text; + ULONG icon = 0; + ULONG64 timeout = 0; + ULONG response; + + title = PhaGetDlgItemText(hwndDlg, IDC_TITLE); + text = PhaGetDlgItemText(hwndDlg, IDC_TEXT); + + PhFindIntegerSiKeyValuePairs( + PhpMessageBoxIconPairs, + sizeof(PhpMessageBoxIconPairs), + PhaGetDlgItemText(hwndDlg, IDC_TYPE)->Buffer, + &icon + ); + PhStringToInteger64( + &PhaGetDlgItemText(hwndDlg, IDC_TIMEOUT)->sr, + 10, + &timeout + ); + + if (WinStationSendMessageW( + NULL, + sessionId, + title->Buffer, + (ULONG)title->Length, + text->Buffer, + (ULONG)text->Length, + icon, + (ULONG)timeout, + &response, + TRUE + )) + { + EndDialog(hwndDlg, IDOK); + } + else + { + PhShowStatus(hwndDlg, L"Unable to send the message", 0, GetLastError()); + } + } + break; + } + } + break; + } + + return FALSE; +} diff --git a/ProcessHacker/sessprp.c b/ProcessHacker/sessprp.c index 60a1aee807f2..076696e7b71a 100644 --- a/ProcessHacker/sessprp.c +++ b/ProcessHacker/sessprp.c @@ -1,237 +1,237 @@ -/* - * Process Hacker - - * session properties - * - * Copyright (C) 2010 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include - -#include -#include - -INT_PTR CALLBACK PhpSessionPropertiesDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -#define SIP(String, Integer) { (String), (PVOID)(Integer) } - -static PH_KEY_VALUE_PAIR PhpConnectStatePairs[] = -{ - SIP(L"Active", State_Active), - SIP(L"Connected", State_Connected), - SIP(L"ConnectQuery", State_ConnectQuery), - SIP(L"Shadow", State_Shadow), - SIP(L"Disconnected", State_Disconnected), - SIP(L"Idle", State_Idle), - SIP(L"Listen", State_Listen), - SIP(L"Reset", State_Reset), - SIP(L"Down", State_Down), - SIP(L"Init", State_Init) -}; - -VOID PhShowSessionProperties( - _In_ HWND ParentWindowHandle, - _In_ ULONG SessionId - ) -{ - DialogBoxParam( - PhInstanceHandle, - MAKEINTRESOURCE(IDD_SESSION), - ParentWindowHandle, - PhpSessionPropertiesDlgProc, - (LPARAM)SessionId - ); -} - -INT_PTR CALLBACK PhpSessionPropertiesDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - switch (uMsg) - { - case WM_INITDIALOG: - { - ULONG sessionId = (ULONG)lParam; - WINSTATIONINFORMATION winStationInfo; - BOOLEAN haveWinStationInfo; - WINSTATIONCLIENT clientInfo; - BOOLEAN haveClientInfo; - ULONG returnLength; - PWSTR stateString; - - SetProp(hwndDlg, L"SessionId", UlongToHandle(sessionId)); - PhCenterWindow(hwndDlg, GetParent(hwndDlg)); - - // Query basic session information - - haveWinStationInfo = WinStationQueryInformationW( - NULL, - sessionId, - WinStationInformation, - &winStationInfo, - sizeof(WINSTATIONINFORMATION), - &returnLength - ); - - // Query client information - - haveClientInfo = WinStationQueryInformationW( - NULL, - sessionId, - WinStationClient, - &clientInfo, - sizeof(WINSTATIONCLIENT), - &returnLength - ); - - if (haveWinStationInfo) - { - SetDlgItemText(hwndDlg, IDC_USERNAME, - PhaFormatString(L"%s\\%s", winStationInfo.Domain, winStationInfo.UserName)->Buffer); - } - - SetDlgItemInt(hwndDlg, IDC_SESSIONID, sessionId, FALSE); - - if (haveWinStationInfo) - { - if (PhFindStringSiKeyValuePairs( - PhpConnectStatePairs, - sizeof(PhpConnectStatePairs), - winStationInfo.ConnectState, - &stateString - )) - { - SetDlgItemText(hwndDlg, IDC_STATE, stateString); - } - } - - if (haveWinStationInfo && winStationInfo.LogonTime.QuadPart != 0) - { - SYSTEMTIME systemTime; - PPH_STRING time; - - PhLargeIntegerToLocalSystemTime(&systemTime, &winStationInfo.LogonTime); - time = PhFormatDateTime(&systemTime); - SetDlgItemText(hwndDlg, IDC_LOGONTIME, time->Buffer); - PhDereferenceObject(time); - } - - if (haveWinStationInfo && winStationInfo.ConnectTime.QuadPart != 0) - { - SYSTEMTIME systemTime; - PPH_STRING time; - - PhLargeIntegerToLocalSystemTime(&systemTime, &winStationInfo.ConnectTime); - time = PhFormatDateTime(&systemTime); - SetDlgItemText(hwndDlg, IDC_CONNECTTIME, time->Buffer); - PhDereferenceObject(time); - } - - if (haveWinStationInfo && winStationInfo.DisconnectTime.QuadPart != 0) - { - SYSTEMTIME systemTime; - PPH_STRING time; - - PhLargeIntegerToLocalSystemTime(&systemTime, &winStationInfo.DisconnectTime); - time = PhFormatDateTime(&systemTime); - SetDlgItemText(hwndDlg, IDC_DISCONNECTTIME, time->Buffer); - PhDereferenceObject(time); - } - - if (haveWinStationInfo && winStationInfo.LastInputTime.QuadPart != 0) - { - SYSTEMTIME systemTime; - PPH_STRING time; - - PhLargeIntegerToLocalSystemTime(&systemTime, &winStationInfo.LastInputTime); - time = PhFormatDateTime(&systemTime); - SetDlgItemText(hwndDlg, IDC_LASTINPUTTIME, time->Buffer); - PhDereferenceObject(time); - } - - if (haveClientInfo && clientInfo.ClientName[0] != 0) - { - WCHAR addressString[65]; - - SetDlgItemText(hwndDlg, IDC_CLIENTNAME, clientInfo.ClientName); - - if (clientInfo.ClientAddressFamily == AF_INET6) - { - struct in6_addr address; - ULONG i; - PUSHORT in; - PUSHORT out; - - // IPv6 is special - the client address data is a reversed version of - // the real address. - - in = (PUSHORT)clientInfo.ClientAddress; - out = (PUSHORT)address.u.Word; - - for (i = 8; i != 0; i--) - { - *out = _byteswap_ushort(*in); - in++; - out++; - } - - RtlIpv6AddressToString(&address, addressString); - } - else - { - wcscpy_s(addressString, 65, clientInfo.ClientAddress); - } - - SetDlgItemText(hwndDlg, IDC_CLIENTADDRESS, addressString); - - SetDlgItemText(hwndDlg, IDC_CLIENTDISPLAY, - PhaFormatString(L"%ux%u@%u", clientInfo.HRes, - clientInfo.VRes, clientInfo.ColorDepth)->Buffer - ); - } - - SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hwndDlg, IDOK), TRUE); - } - break; - case WM_DESTROY: - { - RemoveProp(hwndDlg, L"SessionId"); - } - break; - case WM_COMMAND: - { - switch (LOWORD(wParam)) - { - case IDCANCEL: - case IDOK: - EndDialog(hwndDlg, IDOK); - break; - } - } - break; - } - - return FALSE; -} +/* + * Process Hacker - + * session properties + * + * Copyright (C) 2010 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include + +#include +#include + +INT_PTR CALLBACK PhpSessionPropertiesDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +#define SIP(String, Integer) { (String), (PVOID)(Integer) } + +static PH_KEY_VALUE_PAIR PhpConnectStatePairs[] = +{ + SIP(L"Active", State_Active), + SIP(L"Connected", State_Connected), + SIP(L"ConnectQuery", State_ConnectQuery), + SIP(L"Shadow", State_Shadow), + SIP(L"Disconnected", State_Disconnected), + SIP(L"Idle", State_Idle), + SIP(L"Listen", State_Listen), + SIP(L"Reset", State_Reset), + SIP(L"Down", State_Down), + SIP(L"Init", State_Init) +}; + +VOID PhShowSessionProperties( + _In_ HWND ParentWindowHandle, + _In_ ULONG SessionId + ) +{ + DialogBoxParam( + PhInstanceHandle, + MAKEINTRESOURCE(IDD_SESSION), + ParentWindowHandle, + PhpSessionPropertiesDlgProc, + (LPARAM)SessionId + ); +} + +INT_PTR CALLBACK PhpSessionPropertiesDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + switch (uMsg) + { + case WM_INITDIALOG: + { + ULONG sessionId = (ULONG)lParam; + WINSTATIONINFORMATION winStationInfo; + BOOLEAN haveWinStationInfo; + WINSTATIONCLIENT clientInfo; + BOOLEAN haveClientInfo; + ULONG returnLength; + PWSTR stateString; + + SetProp(hwndDlg, L"SessionId", UlongToHandle(sessionId)); + PhCenterWindow(hwndDlg, GetParent(hwndDlg)); + + // Query basic session information + + haveWinStationInfo = WinStationQueryInformationW( + NULL, + sessionId, + WinStationInformation, + &winStationInfo, + sizeof(WINSTATIONINFORMATION), + &returnLength + ); + + // Query client information + + haveClientInfo = WinStationQueryInformationW( + NULL, + sessionId, + WinStationClient, + &clientInfo, + sizeof(WINSTATIONCLIENT), + &returnLength + ); + + if (haveWinStationInfo) + { + SetDlgItemText(hwndDlg, IDC_USERNAME, + PhaFormatString(L"%s\\%s", winStationInfo.Domain, winStationInfo.UserName)->Buffer); + } + + SetDlgItemInt(hwndDlg, IDC_SESSIONID, sessionId, FALSE); + + if (haveWinStationInfo) + { + if (PhFindStringSiKeyValuePairs( + PhpConnectStatePairs, + sizeof(PhpConnectStatePairs), + winStationInfo.ConnectState, + &stateString + )) + { + SetDlgItemText(hwndDlg, IDC_STATE, stateString); + } + } + + if (haveWinStationInfo && winStationInfo.LogonTime.QuadPart != 0) + { + SYSTEMTIME systemTime; + PPH_STRING time; + + PhLargeIntegerToLocalSystemTime(&systemTime, &winStationInfo.LogonTime); + time = PhFormatDateTime(&systemTime); + SetDlgItemText(hwndDlg, IDC_LOGONTIME, time->Buffer); + PhDereferenceObject(time); + } + + if (haveWinStationInfo && winStationInfo.ConnectTime.QuadPart != 0) + { + SYSTEMTIME systemTime; + PPH_STRING time; + + PhLargeIntegerToLocalSystemTime(&systemTime, &winStationInfo.ConnectTime); + time = PhFormatDateTime(&systemTime); + SetDlgItemText(hwndDlg, IDC_CONNECTTIME, time->Buffer); + PhDereferenceObject(time); + } + + if (haveWinStationInfo && winStationInfo.DisconnectTime.QuadPart != 0) + { + SYSTEMTIME systemTime; + PPH_STRING time; + + PhLargeIntegerToLocalSystemTime(&systemTime, &winStationInfo.DisconnectTime); + time = PhFormatDateTime(&systemTime); + SetDlgItemText(hwndDlg, IDC_DISCONNECTTIME, time->Buffer); + PhDereferenceObject(time); + } + + if (haveWinStationInfo && winStationInfo.LastInputTime.QuadPart != 0) + { + SYSTEMTIME systemTime; + PPH_STRING time; + + PhLargeIntegerToLocalSystemTime(&systemTime, &winStationInfo.LastInputTime); + time = PhFormatDateTime(&systemTime); + SetDlgItemText(hwndDlg, IDC_LASTINPUTTIME, time->Buffer); + PhDereferenceObject(time); + } + + if (haveClientInfo && clientInfo.ClientName[0] != 0) + { + WCHAR addressString[65]; + + SetDlgItemText(hwndDlg, IDC_CLIENTNAME, clientInfo.ClientName); + + if (clientInfo.ClientAddressFamily == AF_INET6) + { + struct in6_addr address; + ULONG i; + PUSHORT in; + PUSHORT out; + + // IPv6 is special - the client address data is a reversed version of + // the real address. + + in = (PUSHORT)clientInfo.ClientAddress; + out = (PUSHORT)address.u.Word; + + for (i = 8; i != 0; i--) + { + *out = _byteswap_ushort(*in); + in++; + out++; + } + + RtlIpv6AddressToString(&address, addressString); + } + else + { + wcscpy_s(addressString, 65, clientInfo.ClientAddress); + } + + SetDlgItemText(hwndDlg, IDC_CLIENTADDRESS, addressString); + + SetDlgItemText(hwndDlg, IDC_CLIENTDISPLAY, + PhaFormatString(L"%ux%u@%u", clientInfo.HRes, + clientInfo.VRes, clientInfo.ColorDepth)->Buffer + ); + } + + SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hwndDlg, IDOK), TRUE); + } + break; + case WM_DESTROY: + { + RemoveProp(hwndDlg, L"SessionId"); + } + break; + case WM_COMMAND: + { + switch (LOWORD(wParam)) + { + case IDCANCEL: + case IDOK: + EndDialog(hwndDlg, IDOK); + break; + } + } + break; + } + + return FALSE; +} diff --git a/ProcessHacker/sessshad.c b/ProcessHacker/sessshad.c index 78e4377fbf10..58c03ced17f6 100644 --- a/ProcessHacker/sessshad.c +++ b/ProcessHacker/sessshad.c @@ -1,239 +1,239 @@ -/* - * Process Hacker - - * session shadow configuration - * - * Copyright (C) 2011-2013 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include - -#include -#include - -#include - -#define SIP(String, Integer) { (String), (PVOID)(Integer) } - -static PH_KEY_VALUE_PAIR VirtualKeyPairs[] = -{ - SIP(L"0", '0'), - SIP(L"1", '1'), - SIP(L"2", '2'), - SIP(L"3", '3'), - SIP(L"4", '4'), - SIP(L"5", '5'), - SIP(L"6", '6'), - SIP(L"7", '7'), - SIP(L"8", '8'), - SIP(L"9", '9'), - SIP(L"A", 'A'), - SIP(L"B", 'B'), - SIP(L"C", 'C'), - SIP(L"D", 'D'), - SIP(L"E", 'E'), - SIP(L"F", 'F'), - SIP(L"G", 'G'), - SIP(L"H", 'H'), - SIP(L"I", 'I'), - SIP(L"J", 'J'), - SIP(L"K", 'K'), - SIP(L"L", 'L'), - SIP(L"M", 'M'), - SIP(L"N", 'N'), - SIP(L"O", 'O'), - SIP(L"P", 'P'), - SIP(L"Q", 'Q'), - SIP(L"R", 'R'), - SIP(L"S", 'S'), - SIP(L"T", 'T'), - SIP(L"U", 'U'), - SIP(L"V", 'V'), - SIP(L"W", 'W'), - SIP(L"X", 'X'), - SIP(L"Y", 'Y'), - SIP(L"Z", 'Z'), - SIP(L"{backspace}", VK_BACK), - SIP(L"{delete}", VK_DELETE), - SIP(L"{down}", VK_DOWN), - SIP(L"{end}", VK_END), - SIP(L"{enter}", VK_RETURN), - SIP(L"{F2}", VK_F2), - SIP(L"{F3}", VK_F3), - SIP(L"{F4}", VK_F4), - SIP(L"{F5}", VK_F5), - SIP(L"{F6}", VK_F6), - SIP(L"{F7}", VK_F7), - SIP(L"{F8}", VK_F8), - SIP(L"{F9}", VK_F9), - SIP(L"{F10}", VK_F10), - SIP(L"{F11}", VK_F11), - SIP(L"{F12}", VK_F12), - SIP(L"{home}", VK_HOME), - SIP(L"{insert}", VK_INSERT), - SIP(L"{left}", VK_LEFT), - SIP(L"{-}", VK_SUBTRACT), - SIP(L"{pagedown}", VK_NEXT), - SIP(L"{pageup}", VK_PRIOR), - SIP(L"{+}", VK_ADD), - SIP(L"{prtscrn}", VK_SNAPSHOT), - SIP(L"{right}", VK_RIGHT), - SIP(L"{spacebar}", VK_SPACE), - SIP(L"{*}", VK_MULTIPLY), - SIP(L"{tab}", VK_TAB), - SIP(L"{up}", VK_UP) -}; - -INT_PTR CALLBACK PhpSessionShadowDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -VOID PhShowSessionShadowDialog( - _In_ HWND ParentWindowHandle, - _In_ ULONG SessionId - ) -{ - if (SessionId == NtCurrentPeb()->SessionId) - { - PhShowError(ParentWindowHandle, L"You cannot remote control the current session."); - return; - } - - DialogBoxParam( - PhInstanceHandle, - MAKEINTRESOURCE(IDD_SHADOWSESSION), - ParentWindowHandle, - PhpSessionShadowDlgProc, - (LPARAM)SessionId - ); -} - -INT_PTR CALLBACK PhpSessionShadowDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - switch (uMsg) - { - case WM_INITDIALOG: - { - HWND virtualKeyComboBox; - PH_INTEGER_PAIR hotkey; - ULONG i; - PWSTR stringToSelect; - - SetProp(hwndDlg, L"SessionId", UlongToHandle((ULONG)lParam)); - PhCenterWindow(hwndDlg, GetParent(hwndDlg)); - - hotkey = PhGetIntegerPairSetting(L"SessionShadowHotkey"); - - // Set up the hotkeys. - - virtualKeyComboBox = GetDlgItem(hwndDlg, IDC_VIRTUALKEY); - stringToSelect = L"{*}"; - - for (i = 0; i < sizeof(VirtualKeyPairs) / sizeof(PH_KEY_VALUE_PAIR); i++) - { - ComboBox_AddString(virtualKeyComboBox, VirtualKeyPairs[i].Key); - - if (PtrToUlong(VirtualKeyPairs[i].Value) == (ULONG)hotkey.X) - { - stringToSelect = VirtualKeyPairs[i].Key; - } - } - - PhSelectComboBoxString(virtualKeyComboBox, stringToSelect, FALSE); - - // Set up the modifiers. - - Button_SetCheck(GetDlgItem(hwndDlg, IDC_SHIFT), hotkey.Y & KBDSHIFT); - Button_SetCheck(GetDlgItem(hwndDlg, IDC_CTRL), hotkey.Y & KBDCTRL); - Button_SetCheck(GetDlgItem(hwndDlg, IDC_ALT), hotkey.Y & KBDALT); - } - break; - case WM_DESTROY: - { - RemoveProp(hwndDlg, L"SessionId"); - } - break; - case WM_COMMAND: - { - switch (LOWORD(wParam)) - { - case IDCANCEL: - EndDialog(hwndDlg, IDCANCEL); - break; - case IDOK: - { - ULONG sessionId = HandleToUlong(GetProp(hwndDlg, L"SessionId")); - ULONG virtualKey; - ULONG modifiers; - WCHAR computerName[64]; - ULONG computerNameLength = 64; - - virtualKey = VK_MULTIPLY; - PhFindIntegerSiKeyValuePairs( - VirtualKeyPairs, - sizeof(VirtualKeyPairs), - PhaGetDlgItemText(hwndDlg, IDC_VIRTUALKEY)->Buffer, - &virtualKey - ); - - modifiers = 0; - - if (Button_GetCheck(GetDlgItem(hwndDlg, IDC_SHIFT)) == BST_CHECKED) - modifiers |= KBDSHIFT; - if (Button_GetCheck(GetDlgItem(hwndDlg, IDC_CTRL)) == BST_CHECKED) - modifiers |= KBDCTRL; - if (Button_GetCheck(GetDlgItem(hwndDlg, IDC_ALT)) == BST_CHECKED) - modifiers |= KBDALT; - - if (GetComputerName(computerName, &computerNameLength)) - { - if (WinStationShadow(NULL, computerName, sessionId, (UCHAR)virtualKey, (USHORT)modifiers)) - { - PH_INTEGER_PAIR hotkey; - - hotkey.X = virtualKey; - hotkey.Y = modifiers; - PhSetIntegerPairSetting(L"SessionShadowHotkey", hotkey); - - EndDialog(hwndDlg, IDOK); - } - else - { - PhShowStatus(hwndDlg, L"Unable to remote control the session", 0, GetLastError()); - } - } - else - { - PhShowError(hwndDlg, L"The computer name is too long."); - } - } - break; - } - } - break; - } - - return FALSE; -} +/* + * Process Hacker - + * session shadow configuration + * + * Copyright (C) 2011-2013 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include + +#include +#include + +#include + +#define SIP(String, Integer) { (String), (PVOID)(Integer) } + +static PH_KEY_VALUE_PAIR VirtualKeyPairs[] = +{ + SIP(L"0", '0'), + SIP(L"1", '1'), + SIP(L"2", '2'), + SIP(L"3", '3'), + SIP(L"4", '4'), + SIP(L"5", '5'), + SIP(L"6", '6'), + SIP(L"7", '7'), + SIP(L"8", '8'), + SIP(L"9", '9'), + SIP(L"A", 'A'), + SIP(L"B", 'B'), + SIP(L"C", 'C'), + SIP(L"D", 'D'), + SIP(L"E", 'E'), + SIP(L"F", 'F'), + SIP(L"G", 'G'), + SIP(L"H", 'H'), + SIP(L"I", 'I'), + SIP(L"J", 'J'), + SIP(L"K", 'K'), + SIP(L"L", 'L'), + SIP(L"M", 'M'), + SIP(L"N", 'N'), + SIP(L"O", 'O'), + SIP(L"P", 'P'), + SIP(L"Q", 'Q'), + SIP(L"R", 'R'), + SIP(L"S", 'S'), + SIP(L"T", 'T'), + SIP(L"U", 'U'), + SIP(L"V", 'V'), + SIP(L"W", 'W'), + SIP(L"X", 'X'), + SIP(L"Y", 'Y'), + SIP(L"Z", 'Z'), + SIP(L"{backspace}", VK_BACK), + SIP(L"{delete}", VK_DELETE), + SIP(L"{down}", VK_DOWN), + SIP(L"{end}", VK_END), + SIP(L"{enter}", VK_RETURN), + SIP(L"{F2}", VK_F2), + SIP(L"{F3}", VK_F3), + SIP(L"{F4}", VK_F4), + SIP(L"{F5}", VK_F5), + SIP(L"{F6}", VK_F6), + SIP(L"{F7}", VK_F7), + SIP(L"{F8}", VK_F8), + SIP(L"{F9}", VK_F9), + SIP(L"{F10}", VK_F10), + SIP(L"{F11}", VK_F11), + SIP(L"{F12}", VK_F12), + SIP(L"{home}", VK_HOME), + SIP(L"{insert}", VK_INSERT), + SIP(L"{left}", VK_LEFT), + SIP(L"{-}", VK_SUBTRACT), + SIP(L"{pagedown}", VK_NEXT), + SIP(L"{pageup}", VK_PRIOR), + SIP(L"{+}", VK_ADD), + SIP(L"{prtscrn}", VK_SNAPSHOT), + SIP(L"{right}", VK_RIGHT), + SIP(L"{spacebar}", VK_SPACE), + SIP(L"{*}", VK_MULTIPLY), + SIP(L"{tab}", VK_TAB), + SIP(L"{up}", VK_UP) +}; + +INT_PTR CALLBACK PhpSessionShadowDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +VOID PhShowSessionShadowDialog( + _In_ HWND ParentWindowHandle, + _In_ ULONG SessionId + ) +{ + if (SessionId == NtCurrentPeb()->SessionId) + { + PhShowError(ParentWindowHandle, L"You cannot remote control the current session."); + return; + } + + DialogBoxParam( + PhInstanceHandle, + MAKEINTRESOURCE(IDD_SHADOWSESSION), + ParentWindowHandle, + PhpSessionShadowDlgProc, + (LPARAM)SessionId + ); +} + +INT_PTR CALLBACK PhpSessionShadowDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + switch (uMsg) + { + case WM_INITDIALOG: + { + HWND virtualKeyComboBox; + PH_INTEGER_PAIR hotkey; + ULONG i; + PWSTR stringToSelect; + + SetProp(hwndDlg, L"SessionId", UlongToHandle((ULONG)lParam)); + PhCenterWindow(hwndDlg, GetParent(hwndDlg)); + + hotkey = PhGetIntegerPairSetting(L"SessionShadowHotkey"); + + // Set up the hotkeys. + + virtualKeyComboBox = GetDlgItem(hwndDlg, IDC_VIRTUALKEY); + stringToSelect = L"{*}"; + + for (i = 0; i < sizeof(VirtualKeyPairs) / sizeof(PH_KEY_VALUE_PAIR); i++) + { + ComboBox_AddString(virtualKeyComboBox, VirtualKeyPairs[i].Key); + + if (PtrToUlong(VirtualKeyPairs[i].Value) == (ULONG)hotkey.X) + { + stringToSelect = VirtualKeyPairs[i].Key; + } + } + + PhSelectComboBoxString(virtualKeyComboBox, stringToSelect, FALSE); + + // Set up the modifiers. + + Button_SetCheck(GetDlgItem(hwndDlg, IDC_SHIFT), hotkey.Y & KBDSHIFT); + Button_SetCheck(GetDlgItem(hwndDlg, IDC_CTRL), hotkey.Y & KBDCTRL); + Button_SetCheck(GetDlgItem(hwndDlg, IDC_ALT), hotkey.Y & KBDALT); + } + break; + case WM_DESTROY: + { + RemoveProp(hwndDlg, L"SessionId"); + } + break; + case WM_COMMAND: + { + switch (LOWORD(wParam)) + { + case IDCANCEL: + EndDialog(hwndDlg, IDCANCEL); + break; + case IDOK: + { + ULONG sessionId = HandleToUlong(GetProp(hwndDlg, L"SessionId")); + ULONG virtualKey; + ULONG modifiers; + WCHAR computerName[64]; + ULONG computerNameLength = 64; + + virtualKey = VK_MULTIPLY; + PhFindIntegerSiKeyValuePairs( + VirtualKeyPairs, + sizeof(VirtualKeyPairs), + PhaGetDlgItemText(hwndDlg, IDC_VIRTUALKEY)->Buffer, + &virtualKey + ); + + modifiers = 0; + + if (Button_GetCheck(GetDlgItem(hwndDlg, IDC_SHIFT)) == BST_CHECKED) + modifiers |= KBDSHIFT; + if (Button_GetCheck(GetDlgItem(hwndDlg, IDC_CTRL)) == BST_CHECKED) + modifiers |= KBDCTRL; + if (Button_GetCheck(GetDlgItem(hwndDlg, IDC_ALT)) == BST_CHECKED) + modifiers |= KBDALT; + + if (GetComputerName(computerName, &computerNameLength)) + { + if (WinStationShadow(NULL, computerName, sessionId, (UCHAR)virtualKey, (USHORT)modifiers)) + { + PH_INTEGER_PAIR hotkey; + + hotkey.X = virtualKey; + hotkey.Y = modifiers; + PhSetIntegerPairSetting(L"SessionShadowHotkey", hotkey); + + EndDialog(hwndDlg, IDOK); + } + else + { + PhShowStatus(hwndDlg, L"Unable to remote control the session", 0, GetLastError()); + } + } + else + { + PhShowError(hwndDlg, L"The computer name is too long."); + } + } + break; + } + } + break; + } + + return FALSE; +} diff --git a/ProcessHacker/settings.c b/ProcessHacker/settings.c index ddc8f441af47..addc547df23f 100644 --- a/ProcessHacker/settings.c +++ b/ProcessHacker/settings.c @@ -1,1198 +1,1198 @@ -/* - * Process Hacker - - * program settings - * - * Copyright (C) 2010-2016 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -/* - * This file contains a program-specific settings system. All possible - * settings are defined at program startup and added to a hashtable. - * The values of these settings can then be read in from a XML file or - * saved to a XML file at any time. Settings which are not recognized - * are added to a list of "ignored settings"; this is necessary to - * support plugin settings, as we don't want their settings to get - * deleted whenever the plugins are disabled. - * - * The get/set functions are very strict. If the wrong function is used - * (the get-integer-setting function is used on a string setting) or - * the setting does not exist, an exception will be raised. - */ - -#include -#define PH_SETTINGS_PRIVATE -#include -#include - -#include "mxml/mxml.h" - -PPH_HASHTABLE PhSettingsHashtable; -PH_QUEUED_LOCK PhSettingsLock = PH_QUEUED_LOCK_INIT; - -PPH_LIST PhIgnoredSettings; - -// These macros make sure the C strings can be seamlessly converted into -// PH_STRINGREFs at compile time, for a small speed boost. - -#define ADD_SETTING_WRAPPER(Type, Name, DefaultValue) \ - { \ - static PH_STRINGREF name = PH_STRINGREF_INIT(Name); \ - static PH_STRINGREF defaultValue = PH_STRINGREF_INIT(DefaultValue); \ - PhpAddSetting(Type, &name, &defaultValue); \ - } - -#define PhpAddStringSetting(A, B) ADD_SETTING_WRAPPER(StringSettingType, A, B) -#define PhpAddIntegerSetting(A, B) ADD_SETTING_WRAPPER(IntegerSettingType, A, B) -#define PhpAddIntegerPairSetting(A, B) ADD_SETTING_WRAPPER(IntegerPairSettingType, A, B) -#define PhpAddScalableIntegerPairSetting(A, B) ADD_SETTING_WRAPPER(ScalableIntegerPairSettingType, A, B) - -VOID PhSettingsInitialization( - VOID - ) -{ - PhSettingsHashtable = PhCreateHashtable( - sizeof(PH_SETTING), - PhpSettingsHashtableEqualFunction, - PhpSettingsHashtableHashFunction, - 256 - ); - PhIgnoredSettings = PhCreateList(4); - - PhpAddIntegerSetting(L"AllowOnlyOneInstance", L"1"); - PhpAddIntegerSetting(L"CloseOnEscape", L"0"); - PhpAddIntegerSetting(L"CollapseServicesOnStart", L"0"); - PhpAddStringSetting(L"DbgHelpPath", L"dbghelp.dll"); - PhpAddStringSetting(L"DbgHelpSearchPath", L""); - PhpAddIntegerSetting(L"DbgHelpUndecorate", L"1"); - PhpAddStringSetting(L"DisabledPlugins", L""); - PhpAddIntegerSetting(L"ElevationLevel", L"1"); // PromptElevateAction - PhpAddIntegerSetting(L"EnableCycleCpuUsage", L"1"); - PhpAddIntegerSetting(L"EnableInstantTooltips", L"0"); - PhpAddIntegerSetting(L"EnableKph", L"1"); - PhpAddIntegerSetting(L"EnableNetworkResolve", L"1"); - PhpAddIntegerSetting(L"EnablePlugins", L"1"); - PhpAddIntegerSetting(L"EnableServiceNonPoll", L"1"); - PhpAddIntegerSetting(L"EnableStage2", L"1"); - PhpAddIntegerSetting(L"EnableWarnings", L"1"); - PhpAddStringSetting(L"EnvironmentListViewColumns", L""); - PhpAddIntegerSetting(L"FindObjRegex", L"0"); - PhpAddStringSetting(L"FindObjListViewColumns", L""); - PhpAddIntegerPairSetting(L"FindObjWindowPosition", L"350,350"); - PhpAddScalableIntegerPairSetting(L"FindObjWindowSize", L"@96|550,420"); - PhpAddIntegerSetting(L"FirstRun", L"1"); - PhpAddStringSetting(L"Font", L""); // null - PhpAddIntegerSetting(L"ForceNoParent", L"0"); - PhpAddStringSetting(L"HandleTreeListColumns", L""); - PhpAddStringSetting(L"HandleTreeListSort", L"0,1"); // 0, AscendingSortOrder - PhpAddStringSetting(L"HiddenProcessesListViewColumns", L""); - PhpAddIntegerPairSetting(L"HiddenProcessesWindowPosition", L"400,400"); - PhpAddScalableIntegerPairSetting(L"HiddenProcessesWindowSize", L"@96|520,400"); - PhpAddIntegerSetting(L"HideDriverServices", L"0"); - PhpAddIntegerSetting(L"HideFreeRegions", L"1"); - PhpAddIntegerSetting(L"HideOnClose", L"0"); - PhpAddIntegerSetting(L"HideOnMinimize", L"0"); - PhpAddIntegerSetting(L"HideOtherUserProcesses", L"0"); - PhpAddIntegerSetting(L"HideSignedProcesses", L"0"); - PhpAddIntegerSetting(L"HideUnnamedHandles", L"1"); - PhpAddIntegerSetting(L"HighlightingDuration", L"3e8"); // 1000ms - PhpAddIntegerSetting(L"IconMask", L"1"); // PH_ICON_CPU_HISTORY - PhpAddStringSetting(L"IconMaskList", L""); - PhpAddIntegerSetting(L"IconNotifyMask", L"c"); // PH_NOTIFY_SERVICE_CREATE | PH_NOTIFY_SERVICE_DELETE - PhpAddIntegerSetting(L"IconProcesses", L"f"); // 15 - PhpAddIntegerSetting(L"IconSingleClick", L"0"); - PhpAddIntegerSetting(L"IconTogglesVisibility", L"1"); - PhpAddStringSetting(L"JobListViewColumns", L""); - PhpAddIntegerSetting(L"KphUnloadOnShutdown", L"0"); - PhpAddIntegerSetting(L"LogEntries", L"200"); // 512 - PhpAddStringSetting(L"LogListViewColumns", L""); - PhpAddIntegerPairSetting(L"LogWindowPosition", L"300,300"); - PhpAddScalableIntegerPairSetting(L"LogWindowSize", L"@96|450,500"); - PhpAddIntegerSetting(L"MainWindowAlwaysOnTop", L"0"); - PhpAddIntegerSetting(L"MainWindowOpacity", L"0"); // means 100% - PhpAddIntegerPairSetting(L"MainWindowPosition", L"100,100"); - PhpAddScalableIntegerPairSetting(L"MainWindowSize", L"@96|800,600"); - PhpAddIntegerSetting(L"MainWindowState", L"1"); - PhpAddIntegerSetting(L"MaxSizeUnit", L"6"); - PhpAddIntegerSetting(L"MemEditBytesPerRow", L"10"); // 16 - PhpAddStringSetting(L"MemEditGotoChoices", L""); - PhpAddIntegerPairSetting(L"MemEditPosition", L"450,450"); - PhpAddScalableIntegerPairSetting(L"MemEditSize", L"@96|600,500"); - PhpAddStringSetting(L"MemFilterChoices", L""); - PhpAddStringSetting(L"MemResultsListViewColumns", L""); - PhpAddIntegerPairSetting(L"MemResultsPosition", L"300,300"); - PhpAddScalableIntegerPairSetting(L"MemResultsSize", L"@96|500,520"); - PhpAddStringSetting(L"MemoryTreeListColumns", L""); - PhpAddStringSetting(L"MemoryTreeListSort", L"0,0"); // 0, NoSortOrder - PhpAddIntegerPairSetting(L"MemoryListsWindowPosition", L"400,400"); - PhpAddStringSetting(L"MemoryReadWriteAddressChoices", L""); - PhpAddIntegerSetting(L"MiniInfoWindowEnabled", L"1"); - PhpAddIntegerSetting(L"MiniInfoWindowOpacity", L"0"); // means 100% - PhpAddIntegerSetting(L"MiniInfoWindowPinned", L"0"); - PhpAddIntegerPairSetting(L"MiniInfoWindowPosition", L"200,200"); - PhpAddIntegerSetting(L"MiniInfoWindowRefreshAutomatically", L"1"); - PhpAddScalableIntegerPairSetting(L"MiniInfoWindowSize", L"@96|10,200"); - PhpAddStringSetting(L"ModuleTreeListColumns", L""); - PhpAddStringSetting(L"ModuleTreeListSort", L"0,0"); // 0, NoSortOrder - PhpAddStringSetting(L"NetworkTreeListColumns", L""); - PhpAddStringSetting(L"NetworkTreeListSort", L"0,1"); // 0, AscendingSortOrder - PhpAddIntegerSetting(L"NoPurgeProcessRecords", L"0"); - PhpAddStringSetting(L"PluginsDirectory", L"plugins"); - PhpAddStringSetting(L"ProcessServiceListViewColumns", L""); - PhpAddStringSetting(L"ProcessTreeListColumns", L""); - PhpAddStringSetting(L"ProcessTreeListSort", L"0,0"); // 0, NoSortOrder - PhpAddStringSetting(L"ProcPropPage", L"General"); - PhpAddIntegerPairSetting(L"ProcPropPosition", L"200,200"); - PhpAddScalableIntegerPairSetting(L"ProcPropSize", L"@96|460,580"); - PhpAddStringSetting(L"ProgramInspectExecutables", L"peview.exe \"%s\""); - PhpAddIntegerSetting(L"PropagateCpuUsage", L"0"); - PhpAddStringSetting(L"RunAsProgram", L""); - PhpAddStringSetting(L"RunAsUserName", L""); - PhpAddIntegerSetting(L"SampleCount", L"200"); // 512 - PhpAddIntegerSetting(L"SampleCountAutomatic", L"1"); - PhpAddIntegerSetting(L"ScrollToNewProcesses", L"0"); - PhpAddStringSetting(L"SearchEngine", L"http://www.google.com/search?q=\"%s\""); - PhpAddStringSetting(L"ServiceListViewColumns", L""); - PhpAddStringSetting(L"ServiceTreeListColumns", L""); - PhpAddStringSetting(L"ServiceTreeListSort", L"0,1"); // 0, AscendingSortOrder - PhpAddIntegerPairSetting(L"SessionShadowHotkey", L"106,2"); // VK_MULTIPLY,KBDCTRL - PhpAddIntegerSetting(L"ShowCommitInSummary", L"1"); - PhpAddIntegerSetting(L"ShowCpuBelow001", L"0"); - PhpAddIntegerSetting(L"StartHidden", L"0"); - PhpAddIntegerSetting(L"SysInfoWindowAlwaysOnTop", L"0"); - PhpAddIntegerSetting(L"SysInfoWindowOneGraphPerCpu", L"0"); - PhpAddIntegerPairSetting(L"SysInfoWindowPosition", L"200,200"); - PhpAddStringSetting(L"SysInfoWindowSection", L""); - PhpAddScalableIntegerPairSetting(L"SysInfoWindowSize", L"@96|620,590"); - PhpAddIntegerSetting(L"SysInfoWindowState", L"1"); - PhpAddIntegerSetting(L"ThinRows", L"0"); - PhpAddStringSetting(L"ThreadTreeListColumns", L""); - PhpAddStringSetting(L"ThreadTreeListSort", L"1,2"); // 1, DescendingSortOrder - PhpAddStringSetting(L"ThreadStackListViewColumns", L""); - PhpAddScalableIntegerPairSetting(L"ThreadStackWindowSize", L"@96|420,380"); - PhpAddIntegerSetting(L"UpdateInterval", L"3e8"); // 1000ms - - // Colors are specified with R in the lowest byte, then G, then B. - // So: bbggrr. - PhpAddIntegerSetting(L"ColorNew", L"00ff7f"); // Chartreuse - PhpAddIntegerSetting(L"ColorRemoved", L"283cff"); - PhpAddIntegerSetting(L"UseColorOwnProcesses", L"1"); - PhpAddIntegerSetting(L"ColorOwnProcesses", L"aaffff"); - PhpAddIntegerSetting(L"UseColorSystemProcesses", L"1"); - PhpAddIntegerSetting(L"ColorSystemProcesses", L"ffccaa"); - PhpAddIntegerSetting(L"UseColorServiceProcesses", L"1"); - PhpAddIntegerSetting(L"ColorServiceProcesses", L"ffffcc"); - PhpAddIntegerSetting(L"UseColorJobProcesses", L"0"); - PhpAddIntegerSetting(L"ColorJobProcesses", L"3f85cd"); // Peru - PhpAddIntegerSetting(L"UseColorWow64Processes", L"0"); - PhpAddIntegerSetting(L"ColorWow64Processes", L"8f8fbc"); // Rosy Brown - PhpAddIntegerSetting(L"UseColorDebuggedProcesses", L"1"); - PhpAddIntegerSetting(L"ColorDebuggedProcesses", L"ffbbcc"); - PhpAddIntegerSetting(L"UseColorElevatedProcesses", L"1"); - PhpAddIntegerSetting(L"ColorElevatedProcesses", L"00aaff"); - PhpAddIntegerSetting(L"UseColorPicoProcesses", L"1"); - PhpAddIntegerSetting(L"ColorPicoProcesses", L"ff8000"); // Blue - PhpAddIntegerSetting(L"UseColorImmersiveProcesses", L"1"); - PhpAddIntegerSetting(L"ColorImmersiveProcesses", L"cbc0ff"); // Pink - PhpAddIntegerSetting(L"UseColorSuspended", L"1"); - PhpAddIntegerSetting(L"ColorSuspended", L"777777"); - PhpAddIntegerSetting(L"UseColorDotNet", L"1"); - PhpAddIntegerSetting(L"ColorDotNet", L"00ffde"); - PhpAddIntegerSetting(L"UseColorPacked", L"1"); - PhpAddIntegerSetting(L"ColorPacked", L"9314ff"); // Deep Pink - PhpAddIntegerSetting(L"UseColorGuiThreads", L"1"); - PhpAddIntegerSetting(L"ColorGuiThreads", L"77ffff"); - PhpAddIntegerSetting(L"UseColorRelocatedModules", L"1"); - PhpAddIntegerSetting(L"ColorRelocatedModules", L"80c0ff"); - PhpAddIntegerSetting(L"UseColorProtectedHandles", L"1"); - PhpAddIntegerSetting(L"ColorProtectedHandles", L"777777"); - PhpAddIntegerSetting(L"UseColorInheritHandles", L"1"); - PhpAddIntegerSetting(L"ColorInheritHandles", L"ffff77"); - - PhpAddIntegerSetting(L"GraphShowText", L"1"); - PhpAddIntegerSetting(L"GraphColorMode", L"0"); - PhpAddIntegerSetting(L"ColorCpuKernel", L"00ff00"); - PhpAddIntegerSetting(L"ColorCpuUser", L"0000ff"); - PhpAddIntegerSetting(L"ColorIoReadOther", L"00ffff"); - PhpAddIntegerSetting(L"ColorIoWrite", L"ff0077"); - PhpAddIntegerSetting(L"ColorPrivate", L"0077ff"); - PhpAddIntegerSetting(L"ColorPhysical", L"ffff00"); - - PhUpdateCachedSettings(); -} - -VOID PhUpdateCachedSettings( - VOID - ) -{ -#define UPDATE_INTEGER_CS(Name) (PhCs##Name = PhGetIntegerSetting(L#Name)) - - UPDATE_INTEGER_CS(CollapseServicesOnStart); - UPDATE_INTEGER_CS(ForceNoParent); - UPDATE_INTEGER_CS(HighlightingDuration); - UPDATE_INTEGER_CS(PropagateCpuUsage); - UPDATE_INTEGER_CS(ScrollToNewProcesses); - UPDATE_INTEGER_CS(ShowCpuBelow001); - UPDATE_INTEGER_CS(UpdateInterval); - - UPDATE_INTEGER_CS(ColorNew); - UPDATE_INTEGER_CS(ColorRemoved); - UPDATE_INTEGER_CS(UseColorOwnProcesses); - UPDATE_INTEGER_CS(ColorOwnProcesses); - UPDATE_INTEGER_CS(UseColorSystemProcesses); - UPDATE_INTEGER_CS(ColorSystemProcesses); - UPDATE_INTEGER_CS(UseColorServiceProcesses); - UPDATE_INTEGER_CS(ColorServiceProcesses); - UPDATE_INTEGER_CS(UseColorJobProcesses); - UPDATE_INTEGER_CS(ColorJobProcesses); - UPDATE_INTEGER_CS(UseColorWow64Processes); - UPDATE_INTEGER_CS(ColorWow64Processes); - UPDATE_INTEGER_CS(UseColorDebuggedProcesses); - UPDATE_INTEGER_CS(ColorDebuggedProcesses); - UPDATE_INTEGER_CS(UseColorElevatedProcesses); - UPDATE_INTEGER_CS(ColorElevatedProcesses); - UPDATE_INTEGER_CS(UseColorPicoProcesses); - UPDATE_INTEGER_CS(ColorPicoProcesses); - UPDATE_INTEGER_CS(UseColorImmersiveProcesses); - UPDATE_INTEGER_CS(ColorImmersiveProcesses); - UPDATE_INTEGER_CS(UseColorSuspended); - UPDATE_INTEGER_CS(ColorSuspended); - UPDATE_INTEGER_CS(UseColorDotNet); - UPDATE_INTEGER_CS(ColorDotNet); - UPDATE_INTEGER_CS(UseColorPacked); - UPDATE_INTEGER_CS(ColorPacked); - UPDATE_INTEGER_CS(UseColorGuiThreads); - UPDATE_INTEGER_CS(ColorGuiThreads); - UPDATE_INTEGER_CS(UseColorRelocatedModules); - UPDATE_INTEGER_CS(ColorRelocatedModules); - UPDATE_INTEGER_CS(UseColorProtectedHandles); - UPDATE_INTEGER_CS(ColorProtectedHandles); - UPDATE_INTEGER_CS(UseColorInheritHandles); - UPDATE_INTEGER_CS(ColorInheritHandles); - UPDATE_INTEGER_CS(GraphShowText); - UPDATE_INTEGER_CS(GraphColorMode); - UPDATE_INTEGER_CS(ColorCpuKernel); - UPDATE_INTEGER_CS(ColorCpuUser); - UPDATE_INTEGER_CS(ColorIoReadOther); - UPDATE_INTEGER_CS(ColorIoWrite); - UPDATE_INTEGER_CS(ColorPrivate); - UPDATE_INTEGER_CS(ColorPhysical); -} - -BOOLEAN NTAPI PhpSettingsHashtableEqualFunction( - _In_ PVOID Entry1, - _In_ PVOID Entry2 - ) -{ - PPH_SETTING setting1 = (PPH_SETTING)Entry1; - PPH_SETTING setting2 = (PPH_SETTING)Entry2; - - return PhEqualStringRef(&setting1->Name, &setting2->Name, FALSE); -} - -ULONG NTAPI PhpSettingsHashtableHashFunction( - _In_ PVOID Entry - ) -{ - PPH_SETTING setting = (PPH_SETTING)Entry; - - return PhHashBytes((PUCHAR)setting->Name.Buffer, setting->Name.Length); -} - -static VOID PhpAddSetting( - _In_ PH_SETTING_TYPE Type, - _In_ PPH_STRINGREF Name, - _In_ PPH_STRINGREF DefaultValue - ) -{ - PH_SETTING setting; - - setting.Type = Type; - setting.Name = *Name; - setting.DefaultValue = *DefaultValue; - memset(&setting.u, 0, sizeof(setting.u)); - - PhpSettingFromString(Type, &setting.DefaultValue, NULL, &setting); - - PhAddEntryHashtable(PhSettingsHashtable, &setting); -} - -static ULONG PhpGetCurrentScale( - VOID - ) -{ - static PH_INITONCE initOnce; - static ULONG dpi = 96; - - if (PhBeginInitOnce(&initOnce)) - { - HDC hdc; - - if (hdc = GetDC(NULL)) - { - dpi = GetDeviceCaps(hdc, LOGPIXELSY); - ReleaseDC(NULL, hdc); - } - - PhEndInitOnce(&initOnce); - } - - return dpi; -} - -static PPH_STRING PhpSettingToString( - _In_ PH_SETTING_TYPE Type, - _In_ PPH_SETTING Setting - ) -{ - switch (Type) - { - case StringSettingType: - { - if (!Setting->u.Pointer) - return PhReferenceEmptyString(); - - PhReferenceObject(Setting->u.Pointer); - - return (PPH_STRING)Setting->u.Pointer; - } - case IntegerSettingType: - { - return PhFormatString(L"%x", Setting->u.Integer); - } - case IntegerPairSettingType: - { - PPH_INTEGER_PAIR integerPair = &Setting->u.IntegerPair; - - return PhFormatString(L"%d,%d", integerPair->X, integerPair->Y); - } - case ScalableIntegerPairSettingType: - { - PPH_SCALABLE_INTEGER_PAIR scalableIntegerPair = Setting->u.Pointer; - - if (!scalableIntegerPair) - return PhReferenceEmptyString(); - - return PhFormatString(L"@%u|%d,%d", scalableIntegerPair->Scale, scalableIntegerPair->X, scalableIntegerPair->Y); - } - } - - return PhReferenceEmptyString(); -} - -static BOOLEAN PhpSettingFromString( - _In_ PH_SETTING_TYPE Type, - _In_ PPH_STRINGREF StringRef, - _In_opt_ PPH_STRING String, - _Inout_ PPH_SETTING Setting - ) -{ - switch (Type) - { - case StringSettingType: - { - if (String) - { - PhSetReference(&Setting->u.Pointer, String); - } - else - { - Setting->u.Pointer = PhCreateString2(StringRef); - } - - return TRUE; - } - case IntegerSettingType: - { - ULONG64 integer; - - if (PhStringToInteger64(StringRef, 16, &integer)) - { - Setting->u.Integer = (ULONG)integer; - return TRUE; - } - else - { - return FALSE; - } - } - case IntegerPairSettingType: - { - LONG64 x; - LONG64 y; - PH_STRINGREF xString; - PH_STRINGREF yString; - - if (!PhSplitStringRefAtChar(StringRef, ',', &xString, &yString)) - return FALSE; - - if (PhStringToInteger64(&xString, 10, &x) && PhStringToInteger64(&yString, 10, &y)) - { - Setting->u.IntegerPair.X = (LONG)x; - Setting->u.IntegerPair.Y = (LONG)y; - return TRUE; - } - else - { - return FALSE; - } - } - case ScalableIntegerPairSettingType: - { - ULONG64 scale; - LONG64 x; - LONG64 y; - PH_STRINGREF stringRef; - PH_STRINGREF firstPart; - PH_STRINGREF secondPart; - PPH_SCALABLE_INTEGER_PAIR scalableIntegerPair; - - stringRef = *StringRef; - - if (stringRef.Length != 0 && stringRef.Buffer[0] == '@') - { - PhSkipStringRef(&stringRef, sizeof(WCHAR)); - - if (!PhSplitStringRefAtChar(&stringRef, '|', &firstPart, &stringRef)) - return FALSE; - if (!PhStringToInteger64(&firstPart, 10, &scale)) - return FALSE; - } - else - { - scale = PhpGetCurrentScale(); - } - - if (!PhSplitStringRefAtChar(&stringRef, ',', &firstPart, &secondPart)) - return FALSE; - - if (PhStringToInteger64(&firstPart, 10, &x) && PhStringToInteger64(&secondPart, 10, &y)) - { - scalableIntegerPair = PhAllocate(sizeof(PH_SCALABLE_INTEGER_PAIR)); - scalableIntegerPair->X = (LONG)x; - scalableIntegerPair->Y = (LONG)y; - scalableIntegerPair->Scale = (ULONG)scale; - Setting->u.Pointer = scalableIntegerPair; - return TRUE; - } - else - { - return FALSE; - } - } - } - - return FALSE; -} - -static VOID PhpFreeSettingValue( - _In_ PH_SETTING_TYPE Type, - _In_ PPH_SETTING Setting - ) -{ - switch (Type) - { - case StringSettingType: - PhClearReference(&Setting->u.Pointer); - break; - case ScalableIntegerPairSettingType: - PhFree(Setting->u.Pointer); - Setting->u.Pointer = NULL; - break; - } -} - -static PVOID PhpLookupSetting( - _In_ PPH_STRINGREF Name - ) -{ - PH_SETTING lookupSetting; - PPH_SETTING setting; - - lookupSetting.Name = *Name; - setting = (PPH_SETTING)PhFindEntryHashtable( - PhSettingsHashtable, - &lookupSetting - ); - - return setting; -} - -_May_raise_ ULONG PhGetIntegerSetting( - _In_ PWSTR Name - ) -{ - PPH_SETTING setting; - PH_STRINGREF name; - ULONG value; - - PhInitializeStringRef(&name, Name); - - PhAcquireQueuedLockShared(&PhSettingsLock); - - setting = PhpLookupSetting(&name); - - if (setting && setting->Type == IntegerSettingType) - { - value = setting->u.Integer; - } - else - { - setting = NULL; - } - - PhReleaseQueuedLockShared(&PhSettingsLock); - - if (!setting) - PhRaiseStatus(STATUS_NOT_FOUND); - - return value; -} - -_May_raise_ PH_INTEGER_PAIR PhGetIntegerPairSetting( - _In_ PWSTR Name - ) -{ - PPH_SETTING setting; - PH_STRINGREF name; - PH_INTEGER_PAIR value; - - PhInitializeStringRef(&name, Name); - - PhAcquireQueuedLockShared(&PhSettingsLock); - - setting = PhpLookupSetting(&name); - - if (setting && setting->Type == IntegerPairSettingType) - { - value = setting->u.IntegerPair; - } - else - { - setting = NULL; - } - - PhReleaseQueuedLockShared(&PhSettingsLock); - - if (!setting) - PhRaiseStatus(STATUS_NOT_FOUND); - - return value; -} - -_May_raise_ PH_SCALABLE_INTEGER_PAIR PhGetScalableIntegerPairSetting( - _In_ PWSTR Name, - _In_ BOOLEAN ScaleToCurrent - ) -{ - PPH_SETTING setting; - PH_STRINGREF name; - PH_SCALABLE_INTEGER_PAIR value; - - PhInitializeStringRef(&name, Name); - - PhAcquireQueuedLockShared(&PhSettingsLock); - - setting = PhpLookupSetting(&name); - - if (setting && setting->Type == ScalableIntegerPairSettingType) - { - value = *(PPH_SCALABLE_INTEGER_PAIR)setting->u.Pointer; - } - else - { - setting = NULL; - } - - PhReleaseQueuedLockShared(&PhSettingsLock); - - if (!setting) - PhRaiseStatus(STATUS_NOT_FOUND); - - if (ScaleToCurrent) - { - ULONG currentScale; - - currentScale = PhpGetCurrentScale(); - - if (value.Scale != currentScale && value.Scale != 0) - { - value.X = PhMultiplyDivideSigned(value.X, currentScale, value.Scale); - value.Y = PhMultiplyDivideSigned(value.Y, currentScale, value.Scale); - value.Scale = currentScale; - } - } - - return value; -} - -_May_raise_ PPH_STRING PhGetStringSetting( - _In_ PWSTR Name - ) -{ - PPH_SETTING setting; - PH_STRINGREF name; - PPH_STRING value; - - PhInitializeStringRef(&name, Name); - - PhAcquireQueuedLockShared(&PhSettingsLock); - - setting = PhpLookupSetting(&name); - - if (setting && setting->Type == StringSettingType) - { - if (setting->u.Pointer) - { - PhSetReference(&value, setting->u.Pointer); - } - else - { - // Set to NULL, create an empty string - // outside of the lock. - value = NULL; - } - } - else - { - setting = NULL; - } - - PhReleaseQueuedLockShared(&PhSettingsLock); - - if (!setting) - PhRaiseStatus(STATUS_NOT_FOUND); - - if (!value) - value = PhReferenceEmptyString(); - - return value; -} - -_May_raise_ VOID PhSetIntegerSetting( - _In_ PWSTR Name, - _In_ ULONG Value - ) -{ - PPH_SETTING setting; - PH_STRINGREF name; - - PhInitializeStringRef(&name, Name); - - PhAcquireQueuedLockExclusive(&PhSettingsLock); - - setting = PhpLookupSetting(&name); - - if (setting && setting->Type == IntegerSettingType) - { - setting->u.Integer = Value; - } - - PhReleaseQueuedLockExclusive(&PhSettingsLock); - - if (!setting) - PhRaiseStatus(STATUS_NOT_FOUND); -} - -_May_raise_ VOID PhSetIntegerPairSetting( - _In_ PWSTR Name, - _In_ PH_INTEGER_PAIR Value - ) -{ - PPH_SETTING setting; - PH_STRINGREF name; - - PhInitializeStringRef(&name, Name); - - PhAcquireQueuedLockExclusive(&PhSettingsLock); - - setting = PhpLookupSetting(&name); - - if (setting && setting->Type == IntegerPairSettingType) - { - setting->u.IntegerPair = Value; - } - - PhReleaseQueuedLockExclusive(&PhSettingsLock); - - if (!setting) - PhRaiseStatus(STATUS_NOT_FOUND); -} - -_May_raise_ VOID PhSetScalableIntegerPairSetting( - _In_ PWSTR Name, - _In_ PH_SCALABLE_INTEGER_PAIR Value - ) -{ - PPH_SETTING setting; - PH_STRINGREF name; - - PhInitializeStringRef(&name, Name); - - PhAcquireQueuedLockExclusive(&PhSettingsLock); - - setting = PhpLookupSetting(&name); - - if (setting && setting->Type == ScalableIntegerPairSettingType) - { - PhpFreeSettingValue(ScalableIntegerPairSettingType, setting); - setting->u.Pointer = PhAllocateCopy(&Value, sizeof(PH_SCALABLE_INTEGER_PAIR)); - } - - PhReleaseQueuedLockExclusive(&PhSettingsLock); - - if (!setting) - PhRaiseStatus(STATUS_NOT_FOUND); -} - -_May_raise_ VOID PhSetScalableIntegerPairSetting2( - _In_ PWSTR Name, - _In_ PH_INTEGER_PAIR Value - ) -{ - PH_SCALABLE_INTEGER_PAIR scalableIntegerPair; - - scalableIntegerPair.Pair = Value; - scalableIntegerPair.Scale = PhpGetCurrentScale(); - PhSetScalableIntegerPairSetting(Name, scalableIntegerPair); -} - -_May_raise_ VOID PhSetStringSetting( - _In_ PWSTR Name, - _In_ PWSTR Value - ) -{ - PPH_SETTING setting; - PH_STRINGREF name; - - PhInitializeStringRef(&name, Name); - - PhAcquireQueuedLockExclusive(&PhSettingsLock); - - setting = PhpLookupSetting(&name); - - if (setting && setting->Type == StringSettingType) - { - PhpFreeSettingValue(StringSettingType, setting); - setting->u.Pointer = PhCreateString(Value); - } - - PhReleaseQueuedLockExclusive(&PhSettingsLock); - - if (!setting) - PhRaiseStatus(STATUS_NOT_FOUND); -} - -_May_raise_ VOID PhSetStringSetting2( - _In_ PWSTR Name, - _In_ PPH_STRINGREF Value - ) -{ - PPH_SETTING setting; - PH_STRINGREF name; - - PhInitializeStringRef(&name, Name); - - PhAcquireQueuedLockExclusive(&PhSettingsLock); - - setting = PhpLookupSetting(&name); - - if (setting && setting->Type == StringSettingType) - { - PhpFreeSettingValue(StringSettingType, setting); - setting->u.Pointer = PhCreateString2(Value); - } - - PhReleaseQueuedLockExclusive(&PhSettingsLock); - - if (!setting) - PhRaiseStatus(STATUS_NOT_FOUND); -} - -VOID PhpFreeIgnoredSetting( - _In_ PPH_SETTING Setting - ) -{ - PhFree(Setting->Name.Buffer); - PhDereferenceObject(Setting->u.Pointer); - - PhFree(Setting); -} - -VOID PhpClearIgnoredSettings( - VOID - ) -{ - ULONG i; - - PhAcquireQueuedLockExclusive(&PhSettingsLock); - - for (i = 0; i < PhIgnoredSettings->Count; i++) - { - PhpFreeIgnoredSetting(PhIgnoredSettings->Items[i]); - } - - PhClearList(PhIgnoredSettings); - - PhReleaseQueuedLockExclusive(&PhSettingsLock); -} - -VOID PhClearIgnoredSettings( - VOID - ) -{ - PhpClearIgnoredSettings(); -} - -VOID PhConvertIgnoredSettings( - VOID - ) -{ - ULONG i; - - PhAcquireQueuedLockExclusive(&PhSettingsLock); - - for (i = 0; i < PhIgnoredSettings->Count; i++) - { - PPH_SETTING ignoredSetting = PhIgnoredSettings->Items[i]; - PPH_SETTING setting; - - setting = PhpLookupSetting(&ignoredSetting->Name); - - if (setting) - { - PhpFreeSettingValue(setting->Type, setting); - - if (!PhpSettingFromString( - setting->Type, - &((PPH_STRING)ignoredSetting->u.Pointer)->sr, - ignoredSetting->u.Pointer, - setting - )) - { - PhpSettingFromString( - setting->Type, - &setting->DefaultValue, - NULL, - setting - ); - } - - PhpFreeIgnoredSetting(ignoredSetting); - - PhRemoveItemList(PhIgnoredSettings, i); - i--; - } - } - - PhReleaseQueuedLockExclusive(&PhSettingsLock); -} - -NTSTATUS PhLoadSettings( - _In_ PWSTR FileName - ) -{ - NTSTATUS status; - HANDLE fileHandle; - LARGE_INTEGER fileSize; - mxml_node_t *topNode; - mxml_node_t *currentNode; - - PhpClearIgnoredSettings(); - - status = PhCreateFileWin32( - &fileHandle, - FileName, - FILE_GENERIC_READ, - 0, - FILE_SHARE_READ | FILE_SHARE_DELETE, - FILE_OPEN, - FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT - ); - - if (!NT_SUCCESS(status)) - return status; - - if (NT_SUCCESS(PhGetFileSize(fileHandle, &fileSize)) && fileSize.QuadPart == 0) - { - // A blank file is OK. There are no settings to load. - NtClose(fileHandle); - return status; - } - - topNode = mxmlLoadFd(NULL, fileHandle, MXML_OPAQUE_CALLBACK); - NtClose(fileHandle); - - if (!topNode) - return STATUS_FILE_CORRUPT_ERROR; - - if (topNode->type != MXML_ELEMENT) - { - mxmlDelete(topNode); - return STATUS_FILE_CORRUPT_ERROR; - } - - currentNode = topNode->child; - - while (currentNode) - { - PPH_STRING settingName = NULL; - - if ( - currentNode->type == MXML_ELEMENT && - currentNode->value.element.num_attrs >= 1 && - _stricmp(currentNode->value.element.attrs[0].name, "name") == 0 - ) - { - settingName = PhConvertUtf8ToUtf16(currentNode->value.element.attrs[0].value); - } - - if (settingName) - { - PPH_STRING settingValue; - - settingValue = PhGetOpaqueXmlNodeText(currentNode); - - PhAcquireQueuedLockExclusive(&PhSettingsLock); - - { - PPH_SETTING setting; - - setting = PhpLookupSetting(&settingName->sr); - - if (setting) - { - PhpFreeSettingValue(setting->Type, setting); - - if (!PhpSettingFromString( - setting->Type, - &settingValue->sr, - settingValue, - setting - )) - { - PhpSettingFromString( - setting->Type, - &setting->DefaultValue, - NULL, - setting - ); - } - } - else - { - setting = PhAllocate(sizeof(PH_SETTING)); - setting->Name.Buffer = PhAllocateCopy(settingName->Buffer, settingName->Length + sizeof(WCHAR)); - setting->Name.Length = settingName->Length; - PhReferenceObject(settingValue); - setting->u.Pointer = settingValue; - - PhAddItemList(PhIgnoredSettings, setting); - } - } - - PhReleaseQueuedLockExclusive(&PhSettingsLock); - - PhDereferenceObject(settingValue); - PhDereferenceObject(settingName); - } - - currentNode = currentNode->next; - } - - mxmlDelete(topNode); - - PhUpdateCachedSettings(); - - return STATUS_SUCCESS; -} - -char *PhpSettingsSaveCallback( - _In_ mxml_node_t *node, - _In_ int position - ) -{ - if (PhEqualBytesZ(node->value.element.name, "setting", TRUE)) - { - if (position == MXML_WS_BEFORE_OPEN) - return " "; - else if (position == MXML_WS_AFTER_CLOSE) - return "\r\n"; - } - else if (PhEqualBytesZ(node->value.element.name, "settings", TRUE)) - { - if (position == MXML_WS_AFTER_OPEN) - return "\r\n"; - } - - return NULL; -} - -mxml_node_t *PhpCreateSettingElement( - _Inout_ mxml_node_t *ParentNode, - _In_ PPH_STRINGREF SettingName, - _In_ PPH_STRINGREF SettingValue - ) -{ - mxml_node_t *settingNode; - mxml_node_t *textNode; - PPH_BYTES settingNameUtf8; - PPH_BYTES settingValueUtf8; - - // Create the setting element. - - settingNode = mxmlNewElement(ParentNode, "setting"); - - settingNameUtf8 = PhConvertUtf16ToUtf8Ex(SettingName->Buffer, SettingName->Length); - mxmlElementSetAttr(settingNode, "name", settingNameUtf8->Buffer); - PhDereferenceObject(settingNameUtf8); - - // Set the value. - - settingValueUtf8 = PhConvertUtf16ToUtf8Ex(SettingValue->Buffer, SettingValue->Length); - textNode = mxmlNewOpaque(settingNode, settingValueUtf8->Buffer); - PhDereferenceObject(settingValueUtf8); - - return settingNode; -} - -NTSTATUS PhSaveSettings( - _In_ PWSTR FileName - ) -{ - NTSTATUS status; - HANDLE fileHandle; - mxml_node_t *topNode; - PH_HASHTABLE_ENUM_CONTEXT enumContext; - PPH_SETTING setting; - - topNode = mxmlNewElement(MXML_NO_PARENT, "settings"); - - PhAcquireQueuedLockShared(&PhSettingsLock); - - PhBeginEnumHashtable(PhSettingsHashtable, &enumContext); - - while (setting = PhNextEnumHashtable(&enumContext)) - { - PPH_STRING settingValue; - - settingValue = PhpSettingToString(setting->Type, setting); - PhpCreateSettingElement(topNode, &setting->Name, &settingValue->sr); - PhDereferenceObject(settingValue); - } - - // Write the ignored settings. - { - ULONG i; - - for (i = 0; i < PhIgnoredSettings->Count; i++) - { - PPH_STRING settingValue; - - setting = PhIgnoredSettings->Items[i]; - settingValue = setting->u.Pointer; - PhpCreateSettingElement(topNode, &setting->Name, &settingValue->sr); - } - } - - PhReleaseQueuedLockShared(&PhSettingsLock); - - // Create the directory if it does not exist. - { - PPH_STRING fullPath; - ULONG indexOfFileName; - PPH_STRING directoryName; - - fullPath = PhGetFullPath(FileName, &indexOfFileName); - - if (fullPath) - { - if (indexOfFileName != -1) - { - directoryName = PhSubstring(fullPath, 0, indexOfFileName); - SHCreateDirectoryEx(NULL, directoryName->Buffer, NULL); - PhDereferenceObject(directoryName); - } - - PhDereferenceObject(fullPath); - } - } - - status = PhCreateFileWin32( - &fileHandle, - FileName, - FILE_GENERIC_WRITE, - 0, - FILE_SHARE_READ, - FILE_OVERWRITE_IF, - FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT - ); - - if (!NT_SUCCESS(status)) - { - mxmlDelete(topNode); - return status; - } - - mxmlSaveFd(topNode, fileHandle, PhpSettingsSaveCallback); - mxmlDelete(topNode); - NtClose(fileHandle); - - return STATUS_SUCCESS; -} - -VOID PhResetSettings( - VOID - ) -{ - PH_HASHTABLE_ENUM_CONTEXT enumContext; - PPH_SETTING setting; - - PhAcquireQueuedLockExclusive(&PhSettingsLock); - - PhBeginEnumHashtable(PhSettingsHashtable, &enumContext); - - while (setting = PhNextEnumHashtable(&enumContext)) - { - PhpFreeSettingValue(setting->Type, setting); - PhpSettingFromString(setting->Type, &setting->DefaultValue, NULL, setting); - } - - PhReleaseQueuedLockExclusive(&PhSettingsLock); -} - -VOID PhAddSettings( - _In_ PPH_SETTING_CREATE Settings, - _In_ ULONG NumberOfSettings - ) -{ - ULONG i; - - PhAcquireQueuedLockExclusive(&PhSettingsLock); - - for (i = 0; i < NumberOfSettings; i++) - { - PH_STRINGREF name; - PH_STRINGREF defaultValue; - - PhInitializeStringRefLongHint(&name, Settings[i].Name); - PhInitializeStringRefLongHint(&defaultValue, Settings[i].DefaultValue); - PhpAddSetting(Settings[i].Type, &name, &defaultValue); - } - - PhReleaseQueuedLockExclusive(&PhSettingsLock); -} +/* + * Process Hacker - + * program settings + * + * Copyright (C) 2010-2016 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +/* + * This file contains a program-specific settings system. All possible + * settings are defined at program startup and added to a hashtable. + * The values of these settings can then be read in from a XML file or + * saved to a XML file at any time. Settings which are not recognized + * are added to a list of "ignored settings"; this is necessary to + * support plugin settings, as we don't want their settings to get + * deleted whenever the plugins are disabled. + * + * The get/set functions are very strict. If the wrong function is used + * (the get-integer-setting function is used on a string setting) or + * the setting does not exist, an exception will be raised. + */ + +#include +#define PH_SETTINGS_PRIVATE +#include +#include + +#include "mxml/mxml.h" + +PPH_HASHTABLE PhSettingsHashtable; +PH_QUEUED_LOCK PhSettingsLock = PH_QUEUED_LOCK_INIT; + +PPH_LIST PhIgnoredSettings; + +// These macros make sure the C strings can be seamlessly converted into +// PH_STRINGREFs at compile time, for a small speed boost. + +#define ADD_SETTING_WRAPPER(Type, Name, DefaultValue) \ + { \ + static PH_STRINGREF name = PH_STRINGREF_INIT(Name); \ + static PH_STRINGREF defaultValue = PH_STRINGREF_INIT(DefaultValue); \ + PhpAddSetting(Type, &name, &defaultValue); \ + } + +#define PhpAddStringSetting(A, B) ADD_SETTING_WRAPPER(StringSettingType, A, B) +#define PhpAddIntegerSetting(A, B) ADD_SETTING_WRAPPER(IntegerSettingType, A, B) +#define PhpAddIntegerPairSetting(A, B) ADD_SETTING_WRAPPER(IntegerPairSettingType, A, B) +#define PhpAddScalableIntegerPairSetting(A, B) ADD_SETTING_WRAPPER(ScalableIntegerPairSettingType, A, B) + +VOID PhSettingsInitialization( + VOID + ) +{ + PhSettingsHashtable = PhCreateHashtable( + sizeof(PH_SETTING), + PhpSettingsHashtableEqualFunction, + PhpSettingsHashtableHashFunction, + 256 + ); + PhIgnoredSettings = PhCreateList(4); + + PhpAddIntegerSetting(L"AllowOnlyOneInstance", L"1"); + PhpAddIntegerSetting(L"CloseOnEscape", L"0"); + PhpAddIntegerSetting(L"CollapseServicesOnStart", L"0"); + PhpAddStringSetting(L"DbgHelpPath", L"dbghelp.dll"); + PhpAddStringSetting(L"DbgHelpSearchPath", L""); + PhpAddIntegerSetting(L"DbgHelpUndecorate", L"1"); + PhpAddStringSetting(L"DisabledPlugins", L""); + PhpAddIntegerSetting(L"ElevationLevel", L"1"); // PromptElevateAction + PhpAddIntegerSetting(L"EnableCycleCpuUsage", L"1"); + PhpAddIntegerSetting(L"EnableInstantTooltips", L"0"); + PhpAddIntegerSetting(L"EnableKph", L"1"); + PhpAddIntegerSetting(L"EnableNetworkResolve", L"1"); + PhpAddIntegerSetting(L"EnablePlugins", L"1"); + PhpAddIntegerSetting(L"EnableServiceNonPoll", L"1"); + PhpAddIntegerSetting(L"EnableStage2", L"1"); + PhpAddIntegerSetting(L"EnableWarnings", L"1"); + PhpAddStringSetting(L"EnvironmentListViewColumns", L""); + PhpAddIntegerSetting(L"FindObjRegex", L"0"); + PhpAddStringSetting(L"FindObjListViewColumns", L""); + PhpAddIntegerPairSetting(L"FindObjWindowPosition", L"350,350"); + PhpAddScalableIntegerPairSetting(L"FindObjWindowSize", L"@96|550,420"); + PhpAddIntegerSetting(L"FirstRun", L"1"); + PhpAddStringSetting(L"Font", L""); // null + PhpAddIntegerSetting(L"ForceNoParent", L"0"); + PhpAddStringSetting(L"HandleTreeListColumns", L""); + PhpAddStringSetting(L"HandleTreeListSort", L"0,1"); // 0, AscendingSortOrder + PhpAddStringSetting(L"HiddenProcessesListViewColumns", L""); + PhpAddIntegerPairSetting(L"HiddenProcessesWindowPosition", L"400,400"); + PhpAddScalableIntegerPairSetting(L"HiddenProcessesWindowSize", L"@96|520,400"); + PhpAddIntegerSetting(L"HideDriverServices", L"0"); + PhpAddIntegerSetting(L"HideFreeRegions", L"1"); + PhpAddIntegerSetting(L"HideOnClose", L"0"); + PhpAddIntegerSetting(L"HideOnMinimize", L"0"); + PhpAddIntegerSetting(L"HideOtherUserProcesses", L"0"); + PhpAddIntegerSetting(L"HideSignedProcesses", L"0"); + PhpAddIntegerSetting(L"HideUnnamedHandles", L"1"); + PhpAddIntegerSetting(L"HighlightingDuration", L"3e8"); // 1000ms + PhpAddIntegerSetting(L"IconMask", L"1"); // PH_ICON_CPU_HISTORY + PhpAddStringSetting(L"IconMaskList", L""); + PhpAddIntegerSetting(L"IconNotifyMask", L"c"); // PH_NOTIFY_SERVICE_CREATE | PH_NOTIFY_SERVICE_DELETE + PhpAddIntegerSetting(L"IconProcesses", L"f"); // 15 + PhpAddIntegerSetting(L"IconSingleClick", L"0"); + PhpAddIntegerSetting(L"IconTogglesVisibility", L"1"); + PhpAddStringSetting(L"JobListViewColumns", L""); + PhpAddIntegerSetting(L"KphUnloadOnShutdown", L"0"); + PhpAddIntegerSetting(L"LogEntries", L"200"); // 512 + PhpAddStringSetting(L"LogListViewColumns", L""); + PhpAddIntegerPairSetting(L"LogWindowPosition", L"300,300"); + PhpAddScalableIntegerPairSetting(L"LogWindowSize", L"@96|450,500"); + PhpAddIntegerSetting(L"MainWindowAlwaysOnTop", L"0"); + PhpAddIntegerSetting(L"MainWindowOpacity", L"0"); // means 100% + PhpAddIntegerPairSetting(L"MainWindowPosition", L"100,100"); + PhpAddScalableIntegerPairSetting(L"MainWindowSize", L"@96|800,600"); + PhpAddIntegerSetting(L"MainWindowState", L"1"); + PhpAddIntegerSetting(L"MaxSizeUnit", L"6"); + PhpAddIntegerSetting(L"MemEditBytesPerRow", L"10"); // 16 + PhpAddStringSetting(L"MemEditGotoChoices", L""); + PhpAddIntegerPairSetting(L"MemEditPosition", L"450,450"); + PhpAddScalableIntegerPairSetting(L"MemEditSize", L"@96|600,500"); + PhpAddStringSetting(L"MemFilterChoices", L""); + PhpAddStringSetting(L"MemResultsListViewColumns", L""); + PhpAddIntegerPairSetting(L"MemResultsPosition", L"300,300"); + PhpAddScalableIntegerPairSetting(L"MemResultsSize", L"@96|500,520"); + PhpAddStringSetting(L"MemoryTreeListColumns", L""); + PhpAddStringSetting(L"MemoryTreeListSort", L"0,0"); // 0, NoSortOrder + PhpAddIntegerPairSetting(L"MemoryListsWindowPosition", L"400,400"); + PhpAddStringSetting(L"MemoryReadWriteAddressChoices", L""); + PhpAddIntegerSetting(L"MiniInfoWindowEnabled", L"1"); + PhpAddIntegerSetting(L"MiniInfoWindowOpacity", L"0"); // means 100% + PhpAddIntegerSetting(L"MiniInfoWindowPinned", L"0"); + PhpAddIntegerPairSetting(L"MiniInfoWindowPosition", L"200,200"); + PhpAddIntegerSetting(L"MiniInfoWindowRefreshAutomatically", L"1"); + PhpAddScalableIntegerPairSetting(L"MiniInfoWindowSize", L"@96|10,200"); + PhpAddStringSetting(L"ModuleTreeListColumns", L""); + PhpAddStringSetting(L"ModuleTreeListSort", L"0,0"); // 0, NoSortOrder + PhpAddStringSetting(L"NetworkTreeListColumns", L""); + PhpAddStringSetting(L"NetworkTreeListSort", L"0,1"); // 0, AscendingSortOrder + PhpAddIntegerSetting(L"NoPurgeProcessRecords", L"0"); + PhpAddStringSetting(L"PluginsDirectory", L"plugins"); + PhpAddStringSetting(L"ProcessServiceListViewColumns", L""); + PhpAddStringSetting(L"ProcessTreeListColumns", L""); + PhpAddStringSetting(L"ProcessTreeListSort", L"0,0"); // 0, NoSortOrder + PhpAddStringSetting(L"ProcPropPage", L"General"); + PhpAddIntegerPairSetting(L"ProcPropPosition", L"200,200"); + PhpAddScalableIntegerPairSetting(L"ProcPropSize", L"@96|460,580"); + PhpAddStringSetting(L"ProgramInspectExecutables", L"peview.exe \"%s\""); + PhpAddIntegerSetting(L"PropagateCpuUsage", L"0"); + PhpAddStringSetting(L"RunAsProgram", L""); + PhpAddStringSetting(L"RunAsUserName", L""); + PhpAddIntegerSetting(L"SampleCount", L"200"); // 512 + PhpAddIntegerSetting(L"SampleCountAutomatic", L"1"); + PhpAddIntegerSetting(L"ScrollToNewProcesses", L"0"); + PhpAddStringSetting(L"SearchEngine", L"http://www.google.com/search?q=\"%s\""); + PhpAddStringSetting(L"ServiceListViewColumns", L""); + PhpAddStringSetting(L"ServiceTreeListColumns", L""); + PhpAddStringSetting(L"ServiceTreeListSort", L"0,1"); // 0, AscendingSortOrder + PhpAddIntegerPairSetting(L"SessionShadowHotkey", L"106,2"); // VK_MULTIPLY,KBDCTRL + PhpAddIntegerSetting(L"ShowCommitInSummary", L"1"); + PhpAddIntegerSetting(L"ShowCpuBelow001", L"0"); + PhpAddIntegerSetting(L"StartHidden", L"0"); + PhpAddIntegerSetting(L"SysInfoWindowAlwaysOnTop", L"0"); + PhpAddIntegerSetting(L"SysInfoWindowOneGraphPerCpu", L"0"); + PhpAddIntegerPairSetting(L"SysInfoWindowPosition", L"200,200"); + PhpAddStringSetting(L"SysInfoWindowSection", L""); + PhpAddScalableIntegerPairSetting(L"SysInfoWindowSize", L"@96|620,590"); + PhpAddIntegerSetting(L"SysInfoWindowState", L"1"); + PhpAddIntegerSetting(L"ThinRows", L"0"); + PhpAddStringSetting(L"ThreadTreeListColumns", L""); + PhpAddStringSetting(L"ThreadTreeListSort", L"1,2"); // 1, DescendingSortOrder + PhpAddStringSetting(L"ThreadStackListViewColumns", L""); + PhpAddScalableIntegerPairSetting(L"ThreadStackWindowSize", L"@96|420,380"); + PhpAddIntegerSetting(L"UpdateInterval", L"3e8"); // 1000ms + + // Colors are specified with R in the lowest byte, then G, then B. + // So: bbggrr. + PhpAddIntegerSetting(L"ColorNew", L"00ff7f"); // Chartreuse + PhpAddIntegerSetting(L"ColorRemoved", L"283cff"); + PhpAddIntegerSetting(L"UseColorOwnProcesses", L"1"); + PhpAddIntegerSetting(L"ColorOwnProcesses", L"aaffff"); + PhpAddIntegerSetting(L"UseColorSystemProcesses", L"1"); + PhpAddIntegerSetting(L"ColorSystemProcesses", L"ffccaa"); + PhpAddIntegerSetting(L"UseColorServiceProcesses", L"1"); + PhpAddIntegerSetting(L"ColorServiceProcesses", L"ffffcc"); + PhpAddIntegerSetting(L"UseColorJobProcesses", L"0"); + PhpAddIntegerSetting(L"ColorJobProcesses", L"3f85cd"); // Peru + PhpAddIntegerSetting(L"UseColorWow64Processes", L"0"); + PhpAddIntegerSetting(L"ColorWow64Processes", L"8f8fbc"); // Rosy Brown + PhpAddIntegerSetting(L"UseColorDebuggedProcesses", L"1"); + PhpAddIntegerSetting(L"ColorDebuggedProcesses", L"ffbbcc"); + PhpAddIntegerSetting(L"UseColorElevatedProcesses", L"1"); + PhpAddIntegerSetting(L"ColorElevatedProcesses", L"00aaff"); + PhpAddIntegerSetting(L"UseColorPicoProcesses", L"1"); + PhpAddIntegerSetting(L"ColorPicoProcesses", L"ff8000"); // Blue + PhpAddIntegerSetting(L"UseColorImmersiveProcesses", L"1"); + PhpAddIntegerSetting(L"ColorImmersiveProcesses", L"cbc0ff"); // Pink + PhpAddIntegerSetting(L"UseColorSuspended", L"1"); + PhpAddIntegerSetting(L"ColorSuspended", L"777777"); + PhpAddIntegerSetting(L"UseColorDotNet", L"1"); + PhpAddIntegerSetting(L"ColorDotNet", L"00ffde"); + PhpAddIntegerSetting(L"UseColorPacked", L"1"); + PhpAddIntegerSetting(L"ColorPacked", L"9314ff"); // Deep Pink + PhpAddIntegerSetting(L"UseColorGuiThreads", L"1"); + PhpAddIntegerSetting(L"ColorGuiThreads", L"77ffff"); + PhpAddIntegerSetting(L"UseColorRelocatedModules", L"1"); + PhpAddIntegerSetting(L"ColorRelocatedModules", L"80c0ff"); + PhpAddIntegerSetting(L"UseColorProtectedHandles", L"1"); + PhpAddIntegerSetting(L"ColorProtectedHandles", L"777777"); + PhpAddIntegerSetting(L"UseColorInheritHandles", L"1"); + PhpAddIntegerSetting(L"ColorInheritHandles", L"ffff77"); + + PhpAddIntegerSetting(L"GraphShowText", L"1"); + PhpAddIntegerSetting(L"GraphColorMode", L"0"); + PhpAddIntegerSetting(L"ColorCpuKernel", L"00ff00"); + PhpAddIntegerSetting(L"ColorCpuUser", L"0000ff"); + PhpAddIntegerSetting(L"ColorIoReadOther", L"00ffff"); + PhpAddIntegerSetting(L"ColorIoWrite", L"ff0077"); + PhpAddIntegerSetting(L"ColorPrivate", L"0077ff"); + PhpAddIntegerSetting(L"ColorPhysical", L"ffff00"); + + PhUpdateCachedSettings(); +} + +VOID PhUpdateCachedSettings( + VOID + ) +{ +#define UPDATE_INTEGER_CS(Name) (PhCs##Name = PhGetIntegerSetting(L#Name)) + + UPDATE_INTEGER_CS(CollapseServicesOnStart); + UPDATE_INTEGER_CS(ForceNoParent); + UPDATE_INTEGER_CS(HighlightingDuration); + UPDATE_INTEGER_CS(PropagateCpuUsage); + UPDATE_INTEGER_CS(ScrollToNewProcesses); + UPDATE_INTEGER_CS(ShowCpuBelow001); + UPDATE_INTEGER_CS(UpdateInterval); + + UPDATE_INTEGER_CS(ColorNew); + UPDATE_INTEGER_CS(ColorRemoved); + UPDATE_INTEGER_CS(UseColorOwnProcesses); + UPDATE_INTEGER_CS(ColorOwnProcesses); + UPDATE_INTEGER_CS(UseColorSystemProcesses); + UPDATE_INTEGER_CS(ColorSystemProcesses); + UPDATE_INTEGER_CS(UseColorServiceProcesses); + UPDATE_INTEGER_CS(ColorServiceProcesses); + UPDATE_INTEGER_CS(UseColorJobProcesses); + UPDATE_INTEGER_CS(ColorJobProcesses); + UPDATE_INTEGER_CS(UseColorWow64Processes); + UPDATE_INTEGER_CS(ColorWow64Processes); + UPDATE_INTEGER_CS(UseColorDebuggedProcesses); + UPDATE_INTEGER_CS(ColorDebuggedProcesses); + UPDATE_INTEGER_CS(UseColorElevatedProcesses); + UPDATE_INTEGER_CS(ColorElevatedProcesses); + UPDATE_INTEGER_CS(UseColorPicoProcesses); + UPDATE_INTEGER_CS(ColorPicoProcesses); + UPDATE_INTEGER_CS(UseColorImmersiveProcesses); + UPDATE_INTEGER_CS(ColorImmersiveProcesses); + UPDATE_INTEGER_CS(UseColorSuspended); + UPDATE_INTEGER_CS(ColorSuspended); + UPDATE_INTEGER_CS(UseColorDotNet); + UPDATE_INTEGER_CS(ColorDotNet); + UPDATE_INTEGER_CS(UseColorPacked); + UPDATE_INTEGER_CS(ColorPacked); + UPDATE_INTEGER_CS(UseColorGuiThreads); + UPDATE_INTEGER_CS(ColorGuiThreads); + UPDATE_INTEGER_CS(UseColorRelocatedModules); + UPDATE_INTEGER_CS(ColorRelocatedModules); + UPDATE_INTEGER_CS(UseColorProtectedHandles); + UPDATE_INTEGER_CS(ColorProtectedHandles); + UPDATE_INTEGER_CS(UseColorInheritHandles); + UPDATE_INTEGER_CS(ColorInheritHandles); + UPDATE_INTEGER_CS(GraphShowText); + UPDATE_INTEGER_CS(GraphColorMode); + UPDATE_INTEGER_CS(ColorCpuKernel); + UPDATE_INTEGER_CS(ColorCpuUser); + UPDATE_INTEGER_CS(ColorIoReadOther); + UPDATE_INTEGER_CS(ColorIoWrite); + UPDATE_INTEGER_CS(ColorPrivate); + UPDATE_INTEGER_CS(ColorPhysical); +} + +BOOLEAN NTAPI PhpSettingsHashtableEqualFunction( + _In_ PVOID Entry1, + _In_ PVOID Entry2 + ) +{ + PPH_SETTING setting1 = (PPH_SETTING)Entry1; + PPH_SETTING setting2 = (PPH_SETTING)Entry2; + + return PhEqualStringRef(&setting1->Name, &setting2->Name, FALSE); +} + +ULONG NTAPI PhpSettingsHashtableHashFunction( + _In_ PVOID Entry + ) +{ + PPH_SETTING setting = (PPH_SETTING)Entry; + + return PhHashBytes((PUCHAR)setting->Name.Buffer, setting->Name.Length); +} + +static VOID PhpAddSetting( + _In_ PH_SETTING_TYPE Type, + _In_ PPH_STRINGREF Name, + _In_ PPH_STRINGREF DefaultValue + ) +{ + PH_SETTING setting; + + setting.Type = Type; + setting.Name = *Name; + setting.DefaultValue = *DefaultValue; + memset(&setting.u, 0, sizeof(setting.u)); + + PhpSettingFromString(Type, &setting.DefaultValue, NULL, &setting); + + PhAddEntryHashtable(PhSettingsHashtable, &setting); +} + +static ULONG PhpGetCurrentScale( + VOID + ) +{ + static PH_INITONCE initOnce; + static ULONG dpi = 96; + + if (PhBeginInitOnce(&initOnce)) + { + HDC hdc; + + if (hdc = GetDC(NULL)) + { + dpi = GetDeviceCaps(hdc, LOGPIXELSY); + ReleaseDC(NULL, hdc); + } + + PhEndInitOnce(&initOnce); + } + + return dpi; +} + +static PPH_STRING PhpSettingToString( + _In_ PH_SETTING_TYPE Type, + _In_ PPH_SETTING Setting + ) +{ + switch (Type) + { + case StringSettingType: + { + if (!Setting->u.Pointer) + return PhReferenceEmptyString(); + + PhReferenceObject(Setting->u.Pointer); + + return (PPH_STRING)Setting->u.Pointer; + } + case IntegerSettingType: + { + return PhFormatString(L"%x", Setting->u.Integer); + } + case IntegerPairSettingType: + { + PPH_INTEGER_PAIR integerPair = &Setting->u.IntegerPair; + + return PhFormatString(L"%d,%d", integerPair->X, integerPair->Y); + } + case ScalableIntegerPairSettingType: + { + PPH_SCALABLE_INTEGER_PAIR scalableIntegerPair = Setting->u.Pointer; + + if (!scalableIntegerPair) + return PhReferenceEmptyString(); + + return PhFormatString(L"@%u|%d,%d", scalableIntegerPair->Scale, scalableIntegerPair->X, scalableIntegerPair->Y); + } + } + + return PhReferenceEmptyString(); +} + +static BOOLEAN PhpSettingFromString( + _In_ PH_SETTING_TYPE Type, + _In_ PPH_STRINGREF StringRef, + _In_opt_ PPH_STRING String, + _Inout_ PPH_SETTING Setting + ) +{ + switch (Type) + { + case StringSettingType: + { + if (String) + { + PhSetReference(&Setting->u.Pointer, String); + } + else + { + Setting->u.Pointer = PhCreateString2(StringRef); + } + + return TRUE; + } + case IntegerSettingType: + { + ULONG64 integer; + + if (PhStringToInteger64(StringRef, 16, &integer)) + { + Setting->u.Integer = (ULONG)integer; + return TRUE; + } + else + { + return FALSE; + } + } + case IntegerPairSettingType: + { + LONG64 x; + LONG64 y; + PH_STRINGREF xString; + PH_STRINGREF yString; + + if (!PhSplitStringRefAtChar(StringRef, ',', &xString, &yString)) + return FALSE; + + if (PhStringToInteger64(&xString, 10, &x) && PhStringToInteger64(&yString, 10, &y)) + { + Setting->u.IntegerPair.X = (LONG)x; + Setting->u.IntegerPair.Y = (LONG)y; + return TRUE; + } + else + { + return FALSE; + } + } + case ScalableIntegerPairSettingType: + { + ULONG64 scale; + LONG64 x; + LONG64 y; + PH_STRINGREF stringRef; + PH_STRINGREF firstPart; + PH_STRINGREF secondPart; + PPH_SCALABLE_INTEGER_PAIR scalableIntegerPair; + + stringRef = *StringRef; + + if (stringRef.Length != 0 && stringRef.Buffer[0] == '@') + { + PhSkipStringRef(&stringRef, sizeof(WCHAR)); + + if (!PhSplitStringRefAtChar(&stringRef, '|', &firstPart, &stringRef)) + return FALSE; + if (!PhStringToInteger64(&firstPart, 10, &scale)) + return FALSE; + } + else + { + scale = PhpGetCurrentScale(); + } + + if (!PhSplitStringRefAtChar(&stringRef, ',', &firstPart, &secondPart)) + return FALSE; + + if (PhStringToInteger64(&firstPart, 10, &x) && PhStringToInteger64(&secondPart, 10, &y)) + { + scalableIntegerPair = PhAllocate(sizeof(PH_SCALABLE_INTEGER_PAIR)); + scalableIntegerPair->X = (LONG)x; + scalableIntegerPair->Y = (LONG)y; + scalableIntegerPair->Scale = (ULONG)scale; + Setting->u.Pointer = scalableIntegerPair; + return TRUE; + } + else + { + return FALSE; + } + } + } + + return FALSE; +} + +static VOID PhpFreeSettingValue( + _In_ PH_SETTING_TYPE Type, + _In_ PPH_SETTING Setting + ) +{ + switch (Type) + { + case StringSettingType: + PhClearReference(&Setting->u.Pointer); + break; + case ScalableIntegerPairSettingType: + PhFree(Setting->u.Pointer); + Setting->u.Pointer = NULL; + break; + } +} + +static PVOID PhpLookupSetting( + _In_ PPH_STRINGREF Name + ) +{ + PH_SETTING lookupSetting; + PPH_SETTING setting; + + lookupSetting.Name = *Name; + setting = (PPH_SETTING)PhFindEntryHashtable( + PhSettingsHashtable, + &lookupSetting + ); + + return setting; +} + +_May_raise_ ULONG PhGetIntegerSetting( + _In_ PWSTR Name + ) +{ + PPH_SETTING setting; + PH_STRINGREF name; + ULONG value; + + PhInitializeStringRef(&name, Name); + + PhAcquireQueuedLockShared(&PhSettingsLock); + + setting = PhpLookupSetting(&name); + + if (setting && setting->Type == IntegerSettingType) + { + value = setting->u.Integer; + } + else + { + setting = NULL; + } + + PhReleaseQueuedLockShared(&PhSettingsLock); + + if (!setting) + PhRaiseStatus(STATUS_NOT_FOUND); + + return value; +} + +_May_raise_ PH_INTEGER_PAIR PhGetIntegerPairSetting( + _In_ PWSTR Name + ) +{ + PPH_SETTING setting; + PH_STRINGREF name; + PH_INTEGER_PAIR value; + + PhInitializeStringRef(&name, Name); + + PhAcquireQueuedLockShared(&PhSettingsLock); + + setting = PhpLookupSetting(&name); + + if (setting && setting->Type == IntegerPairSettingType) + { + value = setting->u.IntegerPair; + } + else + { + setting = NULL; + } + + PhReleaseQueuedLockShared(&PhSettingsLock); + + if (!setting) + PhRaiseStatus(STATUS_NOT_FOUND); + + return value; +} + +_May_raise_ PH_SCALABLE_INTEGER_PAIR PhGetScalableIntegerPairSetting( + _In_ PWSTR Name, + _In_ BOOLEAN ScaleToCurrent + ) +{ + PPH_SETTING setting; + PH_STRINGREF name; + PH_SCALABLE_INTEGER_PAIR value; + + PhInitializeStringRef(&name, Name); + + PhAcquireQueuedLockShared(&PhSettingsLock); + + setting = PhpLookupSetting(&name); + + if (setting && setting->Type == ScalableIntegerPairSettingType) + { + value = *(PPH_SCALABLE_INTEGER_PAIR)setting->u.Pointer; + } + else + { + setting = NULL; + } + + PhReleaseQueuedLockShared(&PhSettingsLock); + + if (!setting) + PhRaiseStatus(STATUS_NOT_FOUND); + + if (ScaleToCurrent) + { + ULONG currentScale; + + currentScale = PhpGetCurrentScale(); + + if (value.Scale != currentScale && value.Scale != 0) + { + value.X = PhMultiplyDivideSigned(value.X, currentScale, value.Scale); + value.Y = PhMultiplyDivideSigned(value.Y, currentScale, value.Scale); + value.Scale = currentScale; + } + } + + return value; +} + +_May_raise_ PPH_STRING PhGetStringSetting( + _In_ PWSTR Name + ) +{ + PPH_SETTING setting; + PH_STRINGREF name; + PPH_STRING value; + + PhInitializeStringRef(&name, Name); + + PhAcquireQueuedLockShared(&PhSettingsLock); + + setting = PhpLookupSetting(&name); + + if (setting && setting->Type == StringSettingType) + { + if (setting->u.Pointer) + { + PhSetReference(&value, setting->u.Pointer); + } + else + { + // Set to NULL, create an empty string + // outside of the lock. + value = NULL; + } + } + else + { + setting = NULL; + } + + PhReleaseQueuedLockShared(&PhSettingsLock); + + if (!setting) + PhRaiseStatus(STATUS_NOT_FOUND); + + if (!value) + value = PhReferenceEmptyString(); + + return value; +} + +_May_raise_ VOID PhSetIntegerSetting( + _In_ PWSTR Name, + _In_ ULONG Value + ) +{ + PPH_SETTING setting; + PH_STRINGREF name; + + PhInitializeStringRef(&name, Name); + + PhAcquireQueuedLockExclusive(&PhSettingsLock); + + setting = PhpLookupSetting(&name); + + if (setting && setting->Type == IntegerSettingType) + { + setting->u.Integer = Value; + } + + PhReleaseQueuedLockExclusive(&PhSettingsLock); + + if (!setting) + PhRaiseStatus(STATUS_NOT_FOUND); +} + +_May_raise_ VOID PhSetIntegerPairSetting( + _In_ PWSTR Name, + _In_ PH_INTEGER_PAIR Value + ) +{ + PPH_SETTING setting; + PH_STRINGREF name; + + PhInitializeStringRef(&name, Name); + + PhAcquireQueuedLockExclusive(&PhSettingsLock); + + setting = PhpLookupSetting(&name); + + if (setting && setting->Type == IntegerPairSettingType) + { + setting->u.IntegerPair = Value; + } + + PhReleaseQueuedLockExclusive(&PhSettingsLock); + + if (!setting) + PhRaiseStatus(STATUS_NOT_FOUND); +} + +_May_raise_ VOID PhSetScalableIntegerPairSetting( + _In_ PWSTR Name, + _In_ PH_SCALABLE_INTEGER_PAIR Value + ) +{ + PPH_SETTING setting; + PH_STRINGREF name; + + PhInitializeStringRef(&name, Name); + + PhAcquireQueuedLockExclusive(&PhSettingsLock); + + setting = PhpLookupSetting(&name); + + if (setting && setting->Type == ScalableIntegerPairSettingType) + { + PhpFreeSettingValue(ScalableIntegerPairSettingType, setting); + setting->u.Pointer = PhAllocateCopy(&Value, sizeof(PH_SCALABLE_INTEGER_PAIR)); + } + + PhReleaseQueuedLockExclusive(&PhSettingsLock); + + if (!setting) + PhRaiseStatus(STATUS_NOT_FOUND); +} + +_May_raise_ VOID PhSetScalableIntegerPairSetting2( + _In_ PWSTR Name, + _In_ PH_INTEGER_PAIR Value + ) +{ + PH_SCALABLE_INTEGER_PAIR scalableIntegerPair; + + scalableIntegerPair.Pair = Value; + scalableIntegerPair.Scale = PhpGetCurrentScale(); + PhSetScalableIntegerPairSetting(Name, scalableIntegerPair); +} + +_May_raise_ VOID PhSetStringSetting( + _In_ PWSTR Name, + _In_ PWSTR Value + ) +{ + PPH_SETTING setting; + PH_STRINGREF name; + + PhInitializeStringRef(&name, Name); + + PhAcquireQueuedLockExclusive(&PhSettingsLock); + + setting = PhpLookupSetting(&name); + + if (setting && setting->Type == StringSettingType) + { + PhpFreeSettingValue(StringSettingType, setting); + setting->u.Pointer = PhCreateString(Value); + } + + PhReleaseQueuedLockExclusive(&PhSettingsLock); + + if (!setting) + PhRaiseStatus(STATUS_NOT_FOUND); +} + +_May_raise_ VOID PhSetStringSetting2( + _In_ PWSTR Name, + _In_ PPH_STRINGREF Value + ) +{ + PPH_SETTING setting; + PH_STRINGREF name; + + PhInitializeStringRef(&name, Name); + + PhAcquireQueuedLockExclusive(&PhSettingsLock); + + setting = PhpLookupSetting(&name); + + if (setting && setting->Type == StringSettingType) + { + PhpFreeSettingValue(StringSettingType, setting); + setting->u.Pointer = PhCreateString2(Value); + } + + PhReleaseQueuedLockExclusive(&PhSettingsLock); + + if (!setting) + PhRaiseStatus(STATUS_NOT_FOUND); +} + +VOID PhpFreeIgnoredSetting( + _In_ PPH_SETTING Setting + ) +{ + PhFree(Setting->Name.Buffer); + PhDereferenceObject(Setting->u.Pointer); + + PhFree(Setting); +} + +VOID PhpClearIgnoredSettings( + VOID + ) +{ + ULONG i; + + PhAcquireQueuedLockExclusive(&PhSettingsLock); + + for (i = 0; i < PhIgnoredSettings->Count; i++) + { + PhpFreeIgnoredSetting(PhIgnoredSettings->Items[i]); + } + + PhClearList(PhIgnoredSettings); + + PhReleaseQueuedLockExclusive(&PhSettingsLock); +} + +VOID PhClearIgnoredSettings( + VOID + ) +{ + PhpClearIgnoredSettings(); +} + +VOID PhConvertIgnoredSettings( + VOID + ) +{ + ULONG i; + + PhAcquireQueuedLockExclusive(&PhSettingsLock); + + for (i = 0; i < PhIgnoredSettings->Count; i++) + { + PPH_SETTING ignoredSetting = PhIgnoredSettings->Items[i]; + PPH_SETTING setting; + + setting = PhpLookupSetting(&ignoredSetting->Name); + + if (setting) + { + PhpFreeSettingValue(setting->Type, setting); + + if (!PhpSettingFromString( + setting->Type, + &((PPH_STRING)ignoredSetting->u.Pointer)->sr, + ignoredSetting->u.Pointer, + setting + )) + { + PhpSettingFromString( + setting->Type, + &setting->DefaultValue, + NULL, + setting + ); + } + + PhpFreeIgnoredSetting(ignoredSetting); + + PhRemoveItemList(PhIgnoredSettings, i); + i--; + } + } + + PhReleaseQueuedLockExclusive(&PhSettingsLock); +} + +NTSTATUS PhLoadSettings( + _In_ PWSTR FileName + ) +{ + NTSTATUS status; + HANDLE fileHandle; + LARGE_INTEGER fileSize; + mxml_node_t *topNode; + mxml_node_t *currentNode; + + PhpClearIgnoredSettings(); + + status = PhCreateFileWin32( + &fileHandle, + FileName, + FILE_GENERIC_READ, + 0, + FILE_SHARE_READ | FILE_SHARE_DELETE, + FILE_OPEN, + FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT + ); + + if (!NT_SUCCESS(status)) + return status; + + if (NT_SUCCESS(PhGetFileSize(fileHandle, &fileSize)) && fileSize.QuadPart == 0) + { + // A blank file is OK. There are no settings to load. + NtClose(fileHandle); + return status; + } + + topNode = mxmlLoadFd(NULL, fileHandle, MXML_OPAQUE_CALLBACK); + NtClose(fileHandle); + + if (!topNode) + return STATUS_FILE_CORRUPT_ERROR; + + if (topNode->type != MXML_ELEMENT) + { + mxmlDelete(topNode); + return STATUS_FILE_CORRUPT_ERROR; + } + + currentNode = topNode->child; + + while (currentNode) + { + PPH_STRING settingName = NULL; + + if ( + currentNode->type == MXML_ELEMENT && + currentNode->value.element.num_attrs >= 1 && + _stricmp(currentNode->value.element.attrs[0].name, "name") == 0 + ) + { + settingName = PhConvertUtf8ToUtf16(currentNode->value.element.attrs[0].value); + } + + if (settingName) + { + PPH_STRING settingValue; + + settingValue = PhGetOpaqueXmlNodeText(currentNode); + + PhAcquireQueuedLockExclusive(&PhSettingsLock); + + { + PPH_SETTING setting; + + setting = PhpLookupSetting(&settingName->sr); + + if (setting) + { + PhpFreeSettingValue(setting->Type, setting); + + if (!PhpSettingFromString( + setting->Type, + &settingValue->sr, + settingValue, + setting + )) + { + PhpSettingFromString( + setting->Type, + &setting->DefaultValue, + NULL, + setting + ); + } + } + else + { + setting = PhAllocate(sizeof(PH_SETTING)); + setting->Name.Buffer = PhAllocateCopy(settingName->Buffer, settingName->Length + sizeof(WCHAR)); + setting->Name.Length = settingName->Length; + PhReferenceObject(settingValue); + setting->u.Pointer = settingValue; + + PhAddItemList(PhIgnoredSettings, setting); + } + } + + PhReleaseQueuedLockExclusive(&PhSettingsLock); + + PhDereferenceObject(settingValue); + PhDereferenceObject(settingName); + } + + currentNode = currentNode->next; + } + + mxmlDelete(topNode); + + PhUpdateCachedSettings(); + + return STATUS_SUCCESS; +} + +char *PhpSettingsSaveCallback( + _In_ mxml_node_t *node, + _In_ int position + ) +{ + if (PhEqualBytesZ(node->value.element.name, "setting", TRUE)) + { + if (position == MXML_WS_BEFORE_OPEN) + return " "; + else if (position == MXML_WS_AFTER_CLOSE) + return "\r\n"; + } + else if (PhEqualBytesZ(node->value.element.name, "settings", TRUE)) + { + if (position == MXML_WS_AFTER_OPEN) + return "\r\n"; + } + + return NULL; +} + +mxml_node_t *PhpCreateSettingElement( + _Inout_ mxml_node_t *ParentNode, + _In_ PPH_STRINGREF SettingName, + _In_ PPH_STRINGREF SettingValue + ) +{ + mxml_node_t *settingNode; + mxml_node_t *textNode; + PPH_BYTES settingNameUtf8; + PPH_BYTES settingValueUtf8; + + // Create the setting element. + + settingNode = mxmlNewElement(ParentNode, "setting"); + + settingNameUtf8 = PhConvertUtf16ToUtf8Ex(SettingName->Buffer, SettingName->Length); + mxmlElementSetAttr(settingNode, "name", settingNameUtf8->Buffer); + PhDereferenceObject(settingNameUtf8); + + // Set the value. + + settingValueUtf8 = PhConvertUtf16ToUtf8Ex(SettingValue->Buffer, SettingValue->Length); + textNode = mxmlNewOpaque(settingNode, settingValueUtf8->Buffer); + PhDereferenceObject(settingValueUtf8); + + return settingNode; +} + +NTSTATUS PhSaveSettings( + _In_ PWSTR FileName + ) +{ + NTSTATUS status; + HANDLE fileHandle; + mxml_node_t *topNode; + PH_HASHTABLE_ENUM_CONTEXT enumContext; + PPH_SETTING setting; + + topNode = mxmlNewElement(MXML_NO_PARENT, "settings"); + + PhAcquireQueuedLockShared(&PhSettingsLock); + + PhBeginEnumHashtable(PhSettingsHashtable, &enumContext); + + while (setting = PhNextEnumHashtable(&enumContext)) + { + PPH_STRING settingValue; + + settingValue = PhpSettingToString(setting->Type, setting); + PhpCreateSettingElement(topNode, &setting->Name, &settingValue->sr); + PhDereferenceObject(settingValue); + } + + // Write the ignored settings. + { + ULONG i; + + for (i = 0; i < PhIgnoredSettings->Count; i++) + { + PPH_STRING settingValue; + + setting = PhIgnoredSettings->Items[i]; + settingValue = setting->u.Pointer; + PhpCreateSettingElement(topNode, &setting->Name, &settingValue->sr); + } + } + + PhReleaseQueuedLockShared(&PhSettingsLock); + + // Create the directory if it does not exist. + { + PPH_STRING fullPath; + ULONG indexOfFileName; + PPH_STRING directoryName; + + fullPath = PhGetFullPath(FileName, &indexOfFileName); + + if (fullPath) + { + if (indexOfFileName != -1) + { + directoryName = PhSubstring(fullPath, 0, indexOfFileName); + SHCreateDirectoryEx(NULL, directoryName->Buffer, NULL); + PhDereferenceObject(directoryName); + } + + PhDereferenceObject(fullPath); + } + } + + status = PhCreateFileWin32( + &fileHandle, + FileName, + FILE_GENERIC_WRITE, + 0, + FILE_SHARE_READ, + FILE_OVERWRITE_IF, + FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT + ); + + if (!NT_SUCCESS(status)) + { + mxmlDelete(topNode); + return status; + } + + mxmlSaveFd(topNode, fileHandle, PhpSettingsSaveCallback); + mxmlDelete(topNode); + NtClose(fileHandle); + + return STATUS_SUCCESS; +} + +VOID PhResetSettings( + VOID + ) +{ + PH_HASHTABLE_ENUM_CONTEXT enumContext; + PPH_SETTING setting; + + PhAcquireQueuedLockExclusive(&PhSettingsLock); + + PhBeginEnumHashtable(PhSettingsHashtable, &enumContext); + + while (setting = PhNextEnumHashtable(&enumContext)) + { + PhpFreeSettingValue(setting->Type, setting); + PhpSettingFromString(setting->Type, &setting->DefaultValue, NULL, setting); + } + + PhReleaseQueuedLockExclusive(&PhSettingsLock); +} + +VOID PhAddSettings( + _In_ PPH_SETTING_CREATE Settings, + _In_ ULONG NumberOfSettings + ) +{ + ULONG i; + + PhAcquireQueuedLockExclusive(&PhSettingsLock); + + for (i = 0; i < NumberOfSettings; i++) + { + PH_STRINGREF name; + PH_STRINGREF defaultValue; + + PhInitializeStringRefLongHint(&name, Settings[i].Name); + PhInitializeStringRefLongHint(&defaultValue, Settings[i].DefaultValue); + PhpAddSetting(Settings[i].Type, &name, &defaultValue); + } + + PhReleaseQueuedLockExclusive(&PhSettingsLock); +} diff --git a/ProcessHacker/srvcr.c b/ProcessHacker/srvcr.c index 5ad4500bd80c..2e19f821bc82 100644 --- a/ProcessHacker/srvcr.c +++ b/ProcessHacker/srvcr.c @@ -1,226 +1,226 @@ -/* - * Process Hacker - - * service creation dialog - * - * Copyright (C) 2010-2013 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include - -#include - -#include - -#include -#include - -INT_PTR CALLBACK PhpCreateServiceDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -VOID PhShowCreateServiceDialog( - _In_ HWND ParentWindowHandle - ) -{ - DialogBox( - PhInstanceHandle, - MAKEINTRESOURCE(IDD_CREATESERVICE), - ParentWindowHandle, - PhpCreateServiceDlgProc - ); -} - -INT_PTR CALLBACK PhpCreateServiceDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - switch (uMsg) - { - case WM_INITDIALOG: - { - PhCenterWindow(hwndDlg, GetParent(hwndDlg)); - - PhAddComboBoxStrings(GetDlgItem(hwndDlg, IDC_TYPE), PhServiceTypeStrings, - sizeof(PhServiceTypeStrings) / sizeof(WCHAR *)); - PhAddComboBoxStrings(GetDlgItem(hwndDlg, IDC_STARTTYPE), PhServiceStartTypeStrings, - sizeof(PhServiceStartTypeStrings) / sizeof(WCHAR *)); - PhAddComboBoxStrings(GetDlgItem(hwndDlg, IDC_ERRORCONTROL), PhServiceErrorControlStrings, - sizeof(PhServiceErrorControlStrings) / sizeof(WCHAR *)); - - PhSelectComboBoxString(GetDlgItem(hwndDlg, IDC_TYPE), L"Own Process", FALSE); - PhSelectComboBoxString(GetDlgItem(hwndDlg, IDC_STARTTYPE), L"Demand Start", FALSE); - PhSelectComboBoxString(GetDlgItem(hwndDlg, IDC_ERRORCONTROL), L"Ignore", FALSE); - - if (!PhGetOwnTokenAttributes().Elevated) - { - SendMessage(GetDlgItem(hwndDlg, IDOK), BCM_SETSHIELD, 0, TRUE); - } - - SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hwndDlg, IDC_NAME), TRUE); - } - break; - case WM_COMMAND: - { - switch (LOWORD(wParam)) - { - case IDCANCEL: - { - EndDialog(hwndDlg, IDCANCEL); - } - break; - case IDOK: - { - NTSTATUS status = 0; - BOOLEAN success = FALSE; - SC_HANDLE scManagerHandle; - SC_HANDLE serviceHandle; - ULONG win32Result = 0; - PPH_STRING serviceName; - PPH_STRING serviceDisplayName; - PPH_STRING serviceTypeString; - PPH_STRING serviceStartTypeString; - PPH_STRING serviceErrorControlString; - ULONG serviceType; - ULONG serviceStartType; - ULONG serviceErrorControl; - PPH_STRING serviceBinaryPath; - - serviceName = PH_AUTO(PhGetWindowText(GetDlgItem(hwndDlg, IDC_NAME))); - serviceDisplayName = PH_AUTO(PhGetWindowText(GetDlgItem(hwndDlg, IDC_DISPLAYNAME))); - - serviceTypeString = PH_AUTO(PhGetWindowText(GetDlgItem(hwndDlg, IDC_TYPE))); - serviceStartTypeString = PH_AUTO(PhGetWindowText(GetDlgItem(hwndDlg, IDC_STARTTYPE))); - serviceErrorControlString = PH_AUTO(PhGetWindowText(GetDlgItem(hwndDlg, IDC_ERRORCONTROL))); - serviceType = PhGetServiceTypeInteger(serviceTypeString->Buffer); - serviceStartType = PhGetServiceStartTypeInteger(serviceStartTypeString->Buffer); - serviceErrorControl = PhGetServiceErrorControlInteger(serviceErrorControlString->Buffer); - - serviceBinaryPath = PH_AUTO(PhGetWindowText(GetDlgItem(hwndDlg, IDC_BINARYPATH))); - - if (PhGetOwnTokenAttributes().Elevated) - { - if (scManagerHandle = OpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE)) - { - if (serviceHandle = CreateService( - scManagerHandle, - serviceName->Buffer, - serviceDisplayName->Buffer, - SERVICE_CHANGE_CONFIG, - serviceType, - serviceStartType, - serviceErrorControl, - serviceBinaryPath->Buffer, - NULL, - NULL, - NULL, - NULL, - L"" - )) - { - EndDialog(hwndDlg, IDOK); - CloseServiceHandle(serviceHandle); - success = TRUE; - } - else - { - win32Result = GetLastError(); - } - - CloseServiceHandle(scManagerHandle); - } - else - { - win32Result = GetLastError(); - } - } - else - { - if (PhUiConnectToPhSvc(hwndDlg, FALSE)) - { - status = PhSvcCallCreateService( - serviceName->Buffer, - serviceDisplayName->Buffer, - serviceType, - serviceStartType, - serviceErrorControl, - serviceBinaryPath->Buffer, - NULL, - NULL, - NULL, - NULL, - L"" - ); - PhUiDisconnectFromPhSvc(); - - if (NT_SUCCESS(status)) - { - EndDialog(hwndDlg, IDOK); - success = TRUE; - } - } - else - { - // User cancelled elevation. - success = TRUE; - } - } - - if (!success) - PhShowStatus(hwndDlg, L"Unable to create the service", status, win32Result); - } - break; - case IDC_BROWSE: - { - static PH_FILETYPE_FILTER filters[] = - { - { L"Executable files (*.exe;*.sys)", L"*.exe;*.sys" }, - { L"All files (*.*)", L"*.*" } - }; - PVOID fileDialog; - PPH_STRING fileName; - - fileDialog = PhCreateOpenFileDialog(); - PhSetFileDialogFilter(fileDialog, filters, sizeof(filters) / sizeof(PH_FILETYPE_FILTER)); - - fileName = PhGetFileName(PhaGetDlgItemText(hwndDlg, IDC_BINARYPATH)); - PhSetFileDialogFileName(fileDialog, fileName->Buffer); - PhDereferenceObject(fileName); - - if (PhShowFileDialog(hwndDlg, fileDialog)) - { - fileName = PhGetFileDialogFileName(fileDialog); - SetDlgItemText(hwndDlg, IDC_BINARYPATH, fileName->Buffer); - PhDereferenceObject(fileName); - } - - PhFreeFileDialog(fileDialog); - } - break; - } - } - break; - } - - return FALSE; -} +/* + * Process Hacker - + * service creation dialog + * + * Copyright (C) 2010-2013 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include + +#include + +#include + +#include +#include + +INT_PTR CALLBACK PhpCreateServiceDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +VOID PhShowCreateServiceDialog( + _In_ HWND ParentWindowHandle + ) +{ + DialogBox( + PhInstanceHandle, + MAKEINTRESOURCE(IDD_CREATESERVICE), + ParentWindowHandle, + PhpCreateServiceDlgProc + ); +} + +INT_PTR CALLBACK PhpCreateServiceDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + switch (uMsg) + { + case WM_INITDIALOG: + { + PhCenterWindow(hwndDlg, GetParent(hwndDlg)); + + PhAddComboBoxStrings(GetDlgItem(hwndDlg, IDC_TYPE), PhServiceTypeStrings, + sizeof(PhServiceTypeStrings) / sizeof(WCHAR *)); + PhAddComboBoxStrings(GetDlgItem(hwndDlg, IDC_STARTTYPE), PhServiceStartTypeStrings, + sizeof(PhServiceStartTypeStrings) / sizeof(WCHAR *)); + PhAddComboBoxStrings(GetDlgItem(hwndDlg, IDC_ERRORCONTROL), PhServiceErrorControlStrings, + sizeof(PhServiceErrorControlStrings) / sizeof(WCHAR *)); + + PhSelectComboBoxString(GetDlgItem(hwndDlg, IDC_TYPE), L"Own Process", FALSE); + PhSelectComboBoxString(GetDlgItem(hwndDlg, IDC_STARTTYPE), L"Demand Start", FALSE); + PhSelectComboBoxString(GetDlgItem(hwndDlg, IDC_ERRORCONTROL), L"Ignore", FALSE); + + if (!PhGetOwnTokenAttributes().Elevated) + { + SendMessage(GetDlgItem(hwndDlg, IDOK), BCM_SETSHIELD, 0, TRUE); + } + + SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hwndDlg, IDC_NAME), TRUE); + } + break; + case WM_COMMAND: + { + switch (LOWORD(wParam)) + { + case IDCANCEL: + { + EndDialog(hwndDlg, IDCANCEL); + } + break; + case IDOK: + { + NTSTATUS status = 0; + BOOLEAN success = FALSE; + SC_HANDLE scManagerHandle; + SC_HANDLE serviceHandle; + ULONG win32Result = 0; + PPH_STRING serviceName; + PPH_STRING serviceDisplayName; + PPH_STRING serviceTypeString; + PPH_STRING serviceStartTypeString; + PPH_STRING serviceErrorControlString; + ULONG serviceType; + ULONG serviceStartType; + ULONG serviceErrorControl; + PPH_STRING serviceBinaryPath; + + serviceName = PH_AUTO(PhGetWindowText(GetDlgItem(hwndDlg, IDC_NAME))); + serviceDisplayName = PH_AUTO(PhGetWindowText(GetDlgItem(hwndDlg, IDC_DISPLAYNAME))); + + serviceTypeString = PH_AUTO(PhGetWindowText(GetDlgItem(hwndDlg, IDC_TYPE))); + serviceStartTypeString = PH_AUTO(PhGetWindowText(GetDlgItem(hwndDlg, IDC_STARTTYPE))); + serviceErrorControlString = PH_AUTO(PhGetWindowText(GetDlgItem(hwndDlg, IDC_ERRORCONTROL))); + serviceType = PhGetServiceTypeInteger(serviceTypeString->Buffer); + serviceStartType = PhGetServiceStartTypeInteger(serviceStartTypeString->Buffer); + serviceErrorControl = PhGetServiceErrorControlInteger(serviceErrorControlString->Buffer); + + serviceBinaryPath = PH_AUTO(PhGetWindowText(GetDlgItem(hwndDlg, IDC_BINARYPATH))); + + if (PhGetOwnTokenAttributes().Elevated) + { + if (scManagerHandle = OpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE)) + { + if (serviceHandle = CreateService( + scManagerHandle, + serviceName->Buffer, + serviceDisplayName->Buffer, + SERVICE_CHANGE_CONFIG, + serviceType, + serviceStartType, + serviceErrorControl, + serviceBinaryPath->Buffer, + NULL, + NULL, + NULL, + NULL, + L"" + )) + { + EndDialog(hwndDlg, IDOK); + CloseServiceHandle(serviceHandle); + success = TRUE; + } + else + { + win32Result = GetLastError(); + } + + CloseServiceHandle(scManagerHandle); + } + else + { + win32Result = GetLastError(); + } + } + else + { + if (PhUiConnectToPhSvc(hwndDlg, FALSE)) + { + status = PhSvcCallCreateService( + serviceName->Buffer, + serviceDisplayName->Buffer, + serviceType, + serviceStartType, + serviceErrorControl, + serviceBinaryPath->Buffer, + NULL, + NULL, + NULL, + NULL, + L"" + ); + PhUiDisconnectFromPhSvc(); + + if (NT_SUCCESS(status)) + { + EndDialog(hwndDlg, IDOK); + success = TRUE; + } + } + else + { + // User cancelled elevation. + success = TRUE; + } + } + + if (!success) + PhShowStatus(hwndDlg, L"Unable to create the service", status, win32Result); + } + break; + case IDC_BROWSE: + { + static PH_FILETYPE_FILTER filters[] = + { + { L"Executable files (*.exe;*.sys)", L"*.exe;*.sys" }, + { L"All files (*.*)", L"*.*" } + }; + PVOID fileDialog; + PPH_STRING fileName; + + fileDialog = PhCreateOpenFileDialog(); + PhSetFileDialogFilter(fileDialog, filters, sizeof(filters) / sizeof(PH_FILETYPE_FILTER)); + + fileName = PhGetFileName(PhaGetDlgItemText(hwndDlg, IDC_BINARYPATH)); + PhSetFileDialogFileName(fileDialog, fileName->Buffer); + PhDereferenceObject(fileName); + + if (PhShowFileDialog(hwndDlg, fileDialog)) + { + fileName = PhGetFileDialogFileName(fileDialog); + SetDlgItemText(hwndDlg, IDC_BINARYPATH, fileName->Buffer); + PhDereferenceObject(fileName); + } + + PhFreeFileDialog(fileDialog); + } + break; + } + } + break; + } + + return FALSE; +} diff --git a/ProcessHacker/srvctl.c b/ProcessHacker/srvctl.c index 29b39231266a..72b9066b80ab 100644 --- a/ProcessHacker/srvctl.c +++ b/ProcessHacker/srvctl.c @@ -1,412 +1,412 @@ -/* - * Process Hacker - - * service list control - * - * Copyright (C) 2010-2011 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include - -#include - -#include -#include -#include - -typedef struct _PH_SERVICES_CONTEXT -{ - PPH_SERVICE_ITEM *Services; - ULONG NumberOfServices; - PH_CALLBACK_REGISTRATION ModifiedEventRegistration; - - PWSTR ListViewSettingName; - - PH_LAYOUT_MANAGER LayoutManager; - HWND WindowHandle; -} PH_SERVICES_CONTEXT, *PPH_SERVICES_CONTEXT; - -VOID NTAPI ServiceModifiedHandler( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ); - -INT_PTR CALLBACK PhpServicesPageProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -/** - * Creates a service list property page. - * - * \param ParentWindowHandle The parent of the service list. - * \param Services An array of service items. Each - * service item must have a reference that is transferred - * to this function. The array must be allocated using - * PhAllocate() and must not be freed by the caller; it - * will be freed automatically when no longer needed. - * \param NumberOfServices The number of service items - * in \a Services. - */ -HWND PhCreateServiceListControl( - _In_ HWND ParentWindowHandle, - _In_ PPH_SERVICE_ITEM *Services, - _In_ ULONG NumberOfServices - ) -{ - HWND windowHandle; - PPH_SERVICES_CONTEXT servicesContext; - - servicesContext = PhAllocate(sizeof(PH_SERVICES_CONTEXT)); - - memset(servicesContext, 0, sizeof(PH_SERVICES_CONTEXT)); - servicesContext->Services = Services; - servicesContext->NumberOfServices = NumberOfServices; - - windowHandle = CreateDialogParam( - PhInstanceHandle, - MAKEINTRESOURCE(IDD_SRVLIST), - ParentWindowHandle, - PhpServicesPageProc, - (LPARAM)servicesContext - ); - - if (!windowHandle) - { - PhFree(servicesContext); - return windowHandle; - } - - return windowHandle; -} - -static VOID NTAPI ServiceModifiedHandler( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - PPH_SERVICE_MODIFIED_DATA serviceModifiedData = (PPH_SERVICE_MODIFIED_DATA)Parameter; - PPH_SERVICES_CONTEXT servicesContext = (PPH_SERVICES_CONTEXT)Context; - PPH_SERVICE_MODIFIED_DATA copy; - - copy = PhAllocateCopy(serviceModifiedData, sizeof(PH_SERVICE_MODIFIED_DATA)); - - PostMessage(servicesContext->WindowHandle, WM_PH_SERVICE_MODIFIED, 0, (LPARAM)copy); -} - -VOID PhpFixProcessServicesControls( - _In_ HWND hWnd, - _In_opt_ PPH_SERVICE_ITEM ServiceItem - ) -{ - HWND startButton; - HWND pauseButton; - HWND descriptionLabel; - - startButton = GetDlgItem(hWnd, IDC_START); - pauseButton = GetDlgItem(hWnd, IDC_PAUSE); - descriptionLabel = GetDlgItem(hWnd, IDC_DESCRIPTION); - - if (ServiceItem) - { - SC_HANDLE serviceHandle; - PPH_STRING description; - - switch (ServiceItem->State) - { - case SERVICE_RUNNING: - { - SetWindowText(startButton, L"S&top"); - SetWindowText(pauseButton, L"&Pause"); - EnableWindow(startButton, ServiceItem->ControlsAccepted & SERVICE_ACCEPT_STOP); - EnableWindow(pauseButton, ServiceItem->ControlsAccepted & SERVICE_ACCEPT_PAUSE_CONTINUE); - } - break; - case SERVICE_PAUSED: - { - SetWindowText(startButton, L"S&top"); - SetWindowText(pauseButton, L"C&ontinue"); - EnableWindow(startButton, ServiceItem->ControlsAccepted & SERVICE_ACCEPT_STOP); - EnableWindow(pauseButton, ServiceItem->ControlsAccepted & SERVICE_ACCEPT_PAUSE_CONTINUE); - } - break; - case SERVICE_STOPPED: - { - SetWindowText(startButton, L"&Start"); - SetWindowText(pauseButton, L"&Pause"); - EnableWindow(startButton, TRUE); - EnableWindow(pauseButton, FALSE); - } - break; - case SERVICE_START_PENDING: - case SERVICE_CONTINUE_PENDING: - case SERVICE_PAUSE_PENDING: - case SERVICE_STOP_PENDING: - { - SetWindowText(startButton, L"&Start"); - SetWindowText(pauseButton, L"&Pause"); - EnableWindow(startButton, FALSE); - EnableWindow(pauseButton, FALSE); - } - break; - } - - if (serviceHandle = PhOpenService( - ServiceItem->Name->Buffer, - SERVICE_QUERY_CONFIG - )) - { - if (description = PhGetServiceDescription(serviceHandle)) - { - SetWindowText(descriptionLabel, description->Buffer); - PhDereferenceObject(description); - } - - CloseServiceHandle(serviceHandle); - } - } - else - { - SetWindowText(startButton, L"&Start"); - SetWindowText(pauseButton, L"&Pause"); - EnableWindow(startButton, FALSE); - EnableWindow(pauseButton, FALSE); - SetWindowText(descriptionLabel, L""); - } -} - -INT_PTR CALLBACK PhpServicesPageProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - PPH_SERVICES_CONTEXT servicesContext; - HWND lvHandle; - - if (uMsg == WM_INITDIALOG) - { - servicesContext = (PPH_SERVICES_CONTEXT)lParam; - SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)servicesContext); - } - else - { - servicesContext = (PPH_SERVICES_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom()); - - if (uMsg == WM_DESTROY) - { - RemoveProp(hwndDlg, PhMakeContextAtom()); - } - } - - if (!servicesContext) - return FALSE; - - lvHandle = GetDlgItem(hwndDlg, IDC_LIST); - - switch (uMsg) - { - case WM_INITDIALOG: - { - ULONG i; - - PhRegisterCallback( - &PhServiceModifiedEvent, - ServiceModifiedHandler, - servicesContext, - &servicesContext->ModifiedEventRegistration - ); - - servicesContext->WindowHandle = hwndDlg; - - // Initialize the list. - PhSetListViewStyle(lvHandle, TRUE, TRUE); - PhSetControlTheme(lvHandle, L"explorer"); - PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 120, L"Name"); - PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 220, L"Display name"); - - PhSetExtendedListView(lvHandle); - - for (i = 0; i < servicesContext->NumberOfServices; i++) - { - PPH_SERVICE_ITEM serviceItem; - INT lvItemIndex; - - serviceItem = servicesContext->Services[i]; - lvItemIndex = PhAddListViewItem(lvHandle, MAXINT, serviceItem->Name->Buffer, serviceItem); - PhSetListViewSubItem(lvHandle, lvItemIndex, 1, serviceItem->DisplayName->Buffer); - } - - ExtendedListView_SortItems(lvHandle); - - PhpFixProcessServicesControls(hwndDlg, NULL); - - PhInitializeLayoutManager(&servicesContext->LayoutManager, hwndDlg); - PhAddLayoutItem(&servicesContext->LayoutManager, GetDlgItem(hwndDlg, IDC_LIST), - NULL, PH_ANCHOR_ALL); - PhAddLayoutItem(&servicesContext->LayoutManager, GetDlgItem(hwndDlg, IDC_DESCRIPTION), - NULL, PH_ANCHOR_LEFT | PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); - PhAddLayoutItem(&servicesContext->LayoutManager, GetDlgItem(hwndDlg, IDC_START), - NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); - PhAddLayoutItem(&servicesContext->LayoutManager, GetDlgItem(hwndDlg, IDC_PAUSE), - NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); - } - break; - case WM_DESTROY: - { - ULONG i; - - for (i = 0; i < servicesContext->NumberOfServices; i++) - PhDereferenceObject(servicesContext->Services[i]); - - PhFree(servicesContext->Services); - - PhUnregisterCallback( - &PhServiceModifiedEvent, - &servicesContext->ModifiedEventRegistration - ); - - if (servicesContext->ListViewSettingName) - PhSaveListViewColumnsToSetting(servicesContext->ListViewSettingName, lvHandle); - - PhDeleteLayoutManager(&servicesContext->LayoutManager); - - PhFree(servicesContext); - } - break; - case WM_COMMAND: - { - INT id = LOWORD(wParam); - - switch (id) - { - case IDC_START: - { - PPH_SERVICE_ITEM serviceItem = PhGetSelectedListViewItemParam(lvHandle); - - if (serviceItem) - { - switch (serviceItem->State) - { - case SERVICE_RUNNING: - PhUiStopService(hwndDlg, serviceItem); - break; - case SERVICE_PAUSED: - PhUiStopService(hwndDlg, serviceItem); - break; - case SERVICE_STOPPED: - PhUiStartService(hwndDlg, serviceItem); - break; - } - } - } - break; - case IDC_PAUSE: - { - PPH_SERVICE_ITEM serviceItem = PhGetSelectedListViewItemParam(lvHandle); - - if (serviceItem) - { - switch (serviceItem->State) - { - case SERVICE_RUNNING: - PhUiPauseService(hwndDlg, serviceItem); - break; - case SERVICE_PAUSED: - PhUiContinueService(hwndDlg, serviceItem); - break; - } - } - } - break; - } - } - break; - case WM_NOTIFY: - { - LPNMHDR header = (LPNMHDR)lParam; - - PhHandleListViewNotifyBehaviors(lParam, lvHandle, PH_LIST_VIEW_DEFAULT_1_BEHAVIORS); - - switch (header->code) - { - case NM_DBLCLK: - { - if (header->hwndFrom == lvHandle) - { - PPH_SERVICE_ITEM serviceItem = PhGetSelectedListViewItemParam(lvHandle); - - if (serviceItem) - { - PhShowServiceProperties(hwndDlg, serviceItem); - } - } - } - break; - case LVN_ITEMCHANGED: - { - if (header->hwndFrom == lvHandle) - { - //LPNMITEMACTIVATE itemActivate = (LPNMITEMACTIVATE)header; - PPH_SERVICE_ITEM serviceItem = NULL; - - if (ListView_GetSelectedCount(lvHandle) == 1) - serviceItem = PhGetSelectedListViewItemParam(lvHandle); - - PhpFixProcessServicesControls(hwndDlg, serviceItem); - } - } - break; - } - } - break; - case WM_SIZE: - { - PhLayoutManagerLayout(&servicesContext->LayoutManager); - } - break; - case WM_PH_SERVICE_MODIFIED: - { - PPH_SERVICE_MODIFIED_DATA serviceModifiedData = (PPH_SERVICE_MODIFIED_DATA)lParam; - PPH_SERVICE_ITEM serviceItem = NULL; - - if (ListView_GetSelectedCount(lvHandle) == 1) - serviceItem = PhGetSelectedListViewItemParam(lvHandle); - - if (serviceModifiedData->Service == serviceItem) - { - PhpFixProcessServicesControls(hwndDlg, serviceItem); - } - - PhFree(serviceModifiedData); - } - break; - case WM_PH_SET_LIST_VIEW_SETTINGS: - { - PWSTR settingName = (PWSTR)lParam; - - servicesContext->ListViewSettingName = settingName; - PhLoadListViewColumnsFromSetting(settingName, lvHandle); - } - break; - } - - return FALSE; -} +/* + * Process Hacker - + * service list control + * + * Copyright (C) 2010-2011 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include + +#include + +#include +#include +#include + +typedef struct _PH_SERVICES_CONTEXT +{ + PPH_SERVICE_ITEM *Services; + ULONG NumberOfServices; + PH_CALLBACK_REGISTRATION ModifiedEventRegistration; + + PWSTR ListViewSettingName; + + PH_LAYOUT_MANAGER LayoutManager; + HWND WindowHandle; +} PH_SERVICES_CONTEXT, *PPH_SERVICES_CONTEXT; + +VOID NTAPI ServiceModifiedHandler( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ); + +INT_PTR CALLBACK PhpServicesPageProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +/** + * Creates a service list property page. + * + * \param ParentWindowHandle The parent of the service list. + * \param Services An array of service items. Each + * service item must have a reference that is transferred + * to this function. The array must be allocated using + * PhAllocate() and must not be freed by the caller; it + * will be freed automatically when no longer needed. + * \param NumberOfServices The number of service items + * in \a Services. + */ +HWND PhCreateServiceListControl( + _In_ HWND ParentWindowHandle, + _In_ PPH_SERVICE_ITEM *Services, + _In_ ULONG NumberOfServices + ) +{ + HWND windowHandle; + PPH_SERVICES_CONTEXT servicesContext; + + servicesContext = PhAllocate(sizeof(PH_SERVICES_CONTEXT)); + + memset(servicesContext, 0, sizeof(PH_SERVICES_CONTEXT)); + servicesContext->Services = Services; + servicesContext->NumberOfServices = NumberOfServices; + + windowHandle = CreateDialogParam( + PhInstanceHandle, + MAKEINTRESOURCE(IDD_SRVLIST), + ParentWindowHandle, + PhpServicesPageProc, + (LPARAM)servicesContext + ); + + if (!windowHandle) + { + PhFree(servicesContext); + return windowHandle; + } + + return windowHandle; +} + +static VOID NTAPI ServiceModifiedHandler( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + PPH_SERVICE_MODIFIED_DATA serviceModifiedData = (PPH_SERVICE_MODIFIED_DATA)Parameter; + PPH_SERVICES_CONTEXT servicesContext = (PPH_SERVICES_CONTEXT)Context; + PPH_SERVICE_MODIFIED_DATA copy; + + copy = PhAllocateCopy(serviceModifiedData, sizeof(PH_SERVICE_MODIFIED_DATA)); + + PostMessage(servicesContext->WindowHandle, WM_PH_SERVICE_MODIFIED, 0, (LPARAM)copy); +} + +VOID PhpFixProcessServicesControls( + _In_ HWND hWnd, + _In_opt_ PPH_SERVICE_ITEM ServiceItem + ) +{ + HWND startButton; + HWND pauseButton; + HWND descriptionLabel; + + startButton = GetDlgItem(hWnd, IDC_START); + pauseButton = GetDlgItem(hWnd, IDC_PAUSE); + descriptionLabel = GetDlgItem(hWnd, IDC_DESCRIPTION); + + if (ServiceItem) + { + SC_HANDLE serviceHandle; + PPH_STRING description; + + switch (ServiceItem->State) + { + case SERVICE_RUNNING: + { + SetWindowText(startButton, L"S&top"); + SetWindowText(pauseButton, L"&Pause"); + EnableWindow(startButton, ServiceItem->ControlsAccepted & SERVICE_ACCEPT_STOP); + EnableWindow(pauseButton, ServiceItem->ControlsAccepted & SERVICE_ACCEPT_PAUSE_CONTINUE); + } + break; + case SERVICE_PAUSED: + { + SetWindowText(startButton, L"S&top"); + SetWindowText(pauseButton, L"C&ontinue"); + EnableWindow(startButton, ServiceItem->ControlsAccepted & SERVICE_ACCEPT_STOP); + EnableWindow(pauseButton, ServiceItem->ControlsAccepted & SERVICE_ACCEPT_PAUSE_CONTINUE); + } + break; + case SERVICE_STOPPED: + { + SetWindowText(startButton, L"&Start"); + SetWindowText(pauseButton, L"&Pause"); + EnableWindow(startButton, TRUE); + EnableWindow(pauseButton, FALSE); + } + break; + case SERVICE_START_PENDING: + case SERVICE_CONTINUE_PENDING: + case SERVICE_PAUSE_PENDING: + case SERVICE_STOP_PENDING: + { + SetWindowText(startButton, L"&Start"); + SetWindowText(pauseButton, L"&Pause"); + EnableWindow(startButton, FALSE); + EnableWindow(pauseButton, FALSE); + } + break; + } + + if (serviceHandle = PhOpenService( + ServiceItem->Name->Buffer, + SERVICE_QUERY_CONFIG + )) + { + if (description = PhGetServiceDescription(serviceHandle)) + { + SetWindowText(descriptionLabel, description->Buffer); + PhDereferenceObject(description); + } + + CloseServiceHandle(serviceHandle); + } + } + else + { + SetWindowText(startButton, L"&Start"); + SetWindowText(pauseButton, L"&Pause"); + EnableWindow(startButton, FALSE); + EnableWindow(pauseButton, FALSE); + SetWindowText(descriptionLabel, L""); + } +} + +INT_PTR CALLBACK PhpServicesPageProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + PPH_SERVICES_CONTEXT servicesContext; + HWND lvHandle; + + if (uMsg == WM_INITDIALOG) + { + servicesContext = (PPH_SERVICES_CONTEXT)lParam; + SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)servicesContext); + } + else + { + servicesContext = (PPH_SERVICES_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom()); + + if (uMsg == WM_DESTROY) + { + RemoveProp(hwndDlg, PhMakeContextAtom()); + } + } + + if (!servicesContext) + return FALSE; + + lvHandle = GetDlgItem(hwndDlg, IDC_LIST); + + switch (uMsg) + { + case WM_INITDIALOG: + { + ULONG i; + + PhRegisterCallback( + &PhServiceModifiedEvent, + ServiceModifiedHandler, + servicesContext, + &servicesContext->ModifiedEventRegistration + ); + + servicesContext->WindowHandle = hwndDlg; + + // Initialize the list. + PhSetListViewStyle(lvHandle, TRUE, TRUE); + PhSetControlTheme(lvHandle, L"explorer"); + PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 120, L"Name"); + PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 220, L"Display name"); + + PhSetExtendedListView(lvHandle); + + for (i = 0; i < servicesContext->NumberOfServices; i++) + { + PPH_SERVICE_ITEM serviceItem; + INT lvItemIndex; + + serviceItem = servicesContext->Services[i]; + lvItemIndex = PhAddListViewItem(lvHandle, MAXINT, serviceItem->Name->Buffer, serviceItem); + PhSetListViewSubItem(lvHandle, lvItemIndex, 1, serviceItem->DisplayName->Buffer); + } + + ExtendedListView_SortItems(lvHandle); + + PhpFixProcessServicesControls(hwndDlg, NULL); + + PhInitializeLayoutManager(&servicesContext->LayoutManager, hwndDlg); + PhAddLayoutItem(&servicesContext->LayoutManager, GetDlgItem(hwndDlg, IDC_LIST), + NULL, PH_ANCHOR_ALL); + PhAddLayoutItem(&servicesContext->LayoutManager, GetDlgItem(hwndDlg, IDC_DESCRIPTION), + NULL, PH_ANCHOR_LEFT | PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); + PhAddLayoutItem(&servicesContext->LayoutManager, GetDlgItem(hwndDlg, IDC_START), + NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); + PhAddLayoutItem(&servicesContext->LayoutManager, GetDlgItem(hwndDlg, IDC_PAUSE), + NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); + } + break; + case WM_DESTROY: + { + ULONG i; + + for (i = 0; i < servicesContext->NumberOfServices; i++) + PhDereferenceObject(servicesContext->Services[i]); + + PhFree(servicesContext->Services); + + PhUnregisterCallback( + &PhServiceModifiedEvent, + &servicesContext->ModifiedEventRegistration + ); + + if (servicesContext->ListViewSettingName) + PhSaveListViewColumnsToSetting(servicesContext->ListViewSettingName, lvHandle); + + PhDeleteLayoutManager(&servicesContext->LayoutManager); + + PhFree(servicesContext); + } + break; + case WM_COMMAND: + { + INT id = LOWORD(wParam); + + switch (id) + { + case IDC_START: + { + PPH_SERVICE_ITEM serviceItem = PhGetSelectedListViewItemParam(lvHandle); + + if (serviceItem) + { + switch (serviceItem->State) + { + case SERVICE_RUNNING: + PhUiStopService(hwndDlg, serviceItem); + break; + case SERVICE_PAUSED: + PhUiStopService(hwndDlg, serviceItem); + break; + case SERVICE_STOPPED: + PhUiStartService(hwndDlg, serviceItem); + break; + } + } + } + break; + case IDC_PAUSE: + { + PPH_SERVICE_ITEM serviceItem = PhGetSelectedListViewItemParam(lvHandle); + + if (serviceItem) + { + switch (serviceItem->State) + { + case SERVICE_RUNNING: + PhUiPauseService(hwndDlg, serviceItem); + break; + case SERVICE_PAUSED: + PhUiContinueService(hwndDlg, serviceItem); + break; + } + } + } + break; + } + } + break; + case WM_NOTIFY: + { + LPNMHDR header = (LPNMHDR)lParam; + + PhHandleListViewNotifyBehaviors(lParam, lvHandle, PH_LIST_VIEW_DEFAULT_1_BEHAVIORS); + + switch (header->code) + { + case NM_DBLCLK: + { + if (header->hwndFrom == lvHandle) + { + PPH_SERVICE_ITEM serviceItem = PhGetSelectedListViewItemParam(lvHandle); + + if (serviceItem) + { + PhShowServiceProperties(hwndDlg, serviceItem); + } + } + } + break; + case LVN_ITEMCHANGED: + { + if (header->hwndFrom == lvHandle) + { + //LPNMITEMACTIVATE itemActivate = (LPNMITEMACTIVATE)header; + PPH_SERVICE_ITEM serviceItem = NULL; + + if (ListView_GetSelectedCount(lvHandle) == 1) + serviceItem = PhGetSelectedListViewItemParam(lvHandle); + + PhpFixProcessServicesControls(hwndDlg, serviceItem); + } + } + break; + } + } + break; + case WM_SIZE: + { + PhLayoutManagerLayout(&servicesContext->LayoutManager); + } + break; + case WM_PH_SERVICE_MODIFIED: + { + PPH_SERVICE_MODIFIED_DATA serviceModifiedData = (PPH_SERVICE_MODIFIED_DATA)lParam; + PPH_SERVICE_ITEM serviceItem = NULL; + + if (ListView_GetSelectedCount(lvHandle) == 1) + serviceItem = PhGetSelectedListViewItemParam(lvHandle); + + if (serviceModifiedData->Service == serviceItem) + { + PhpFixProcessServicesControls(hwndDlg, serviceItem); + } + + PhFree(serviceModifiedData); + } + break; + case WM_PH_SET_LIST_VIEW_SETTINGS: + { + PWSTR settingName = (PWSTR)lParam; + + servicesContext->ListViewSettingName = settingName; + PhLoadListViewColumnsFromSetting(settingName, lvHandle); + } + break; + } + + return FALSE; +} diff --git a/ProcessHacker/srvlist.c b/ProcessHacker/srvlist.c index f39fb8ad392b..897399a6bb29 100644 --- a/ProcessHacker/srvlist.c +++ b/ProcessHacker/srvlist.c @@ -1,904 +1,904 @@ -/* - * Process Hacker - - * service list - * - * Copyright (C) 2010-2015 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -BOOLEAN PhpServiceNodeHashtableEqualFunction( - _In_ PVOID Entry1, - _In_ PVOID Entry2 - ); - -ULONG PhpServiceNodeHashtableHashFunction( - _In_ PVOID Entry - ); - -VOID PhpRemoveServiceNode( - _In_ PPH_SERVICE_NODE ServiceNode - ); - -LONG PhpServiceTreeNewPostSortFunction( - _In_ LONG Result, - _In_ PVOID Node1, - _In_ PVOID Node2, - _In_ PH_SORT_ORDER SortOrder - ); - -BOOLEAN NTAPI PhpServiceTreeNewCallback( - _In_ HWND hwnd, - _In_ PH_TREENEW_MESSAGE Message, - _In_opt_ PVOID Parameter1, - _In_opt_ PVOID Parameter2, - _In_opt_ PVOID Context - ); - -static HWND ServiceTreeListHandle; -static ULONG ServiceTreeListSortColumn; -static PH_SORT_ORDER ServiceTreeListSortOrder; -static PH_CM_MANAGER ServiceTreeListCm; - -static PPH_HASHTABLE ServiceNodeHashtable; // hashtable of all nodes -static PPH_LIST ServiceNodeList; // list of all nodes - -static PH_TN_FILTER_SUPPORT FilterSupport; - -static BOOLEAN ServiceIconsLoaded = FALSE; -static HICON ServiceApplicationIcon; -static HICON ServiceApplicationGoIcon; -static HICON ServiceCogIcon; -static HICON ServiceCogGoIcon; - -BOOLEAN PhServiceTreeListStateHighlighting = TRUE; -static PPH_POINTER_LIST ServiceNodeStateList = NULL; // list of nodes which need to be processed - -VOID PhServiceTreeListInitialization( - VOID - ) -{ - ServiceNodeHashtable = PhCreateHashtable( - sizeof(PPH_SERVICE_NODE), - PhpServiceNodeHashtableEqualFunction, - PhpServiceNodeHashtableHashFunction, - 100 - ); - ServiceNodeList = PhCreateList(100); -} - -BOOLEAN PhpServiceNodeHashtableEqualFunction( - _In_ PVOID Entry1, - _In_ PVOID Entry2 - ) -{ - PPH_SERVICE_NODE serviceNode1 = *(PPH_SERVICE_NODE *)Entry1; - PPH_SERVICE_NODE serviceNode2 = *(PPH_SERVICE_NODE *)Entry2; - - return serviceNode1->ServiceItem == serviceNode2->ServiceItem; -} - -ULONG PhpServiceNodeHashtableHashFunction( - _In_ PVOID Entry - ) -{ - return PhHashIntPtr((ULONG_PTR)(*(PPH_SERVICE_NODE *)Entry)->ServiceItem); -} - -VOID PhInitializeServiceTreeList( - _In_ HWND hwnd - ) -{ - ServiceTreeListHandle = hwnd; - PhSetControlTheme(ServiceTreeListHandle, L"explorer"); - SendMessage(TreeNew_GetTooltips(ServiceTreeListHandle), TTM_SETDELAYTIME, TTDT_AUTOPOP, MAXSHORT); - - TreeNew_SetCallback(hwnd, PhpServiceTreeNewCallback, NULL); - - TreeNew_SetRedraw(hwnd, FALSE); - - // Default columns - PhAddTreeNewColumn(hwnd, PHSVTLC_NAME, TRUE, L"Name", 140, PH_ALIGN_LEFT, 0, 0); - PhAddTreeNewColumn(hwnd, PHSVTLC_DISPLAYNAME, TRUE, L"Display name", 220, PH_ALIGN_LEFT, 1, 0); - PhAddTreeNewColumn(hwnd, PHSVTLC_TYPE, TRUE, L"Type", 100, PH_ALIGN_LEFT, 2, 0); - PhAddTreeNewColumn(hwnd, PHSVTLC_STATUS, TRUE, L"Status", 70, PH_ALIGN_LEFT, 3, 0); - PhAddTreeNewColumn(hwnd, PHSVTLC_STARTTYPE, TRUE, L"Start type", 130, PH_ALIGN_LEFT, 4, 0); - PhAddTreeNewColumn(hwnd, PHSVTLC_PID, TRUE, L"PID", 50, PH_ALIGN_RIGHT, 5, DT_RIGHT); - - PhAddTreeNewColumn(hwnd, PHSVTLC_BINARYPATH, FALSE, L"Binary path", 180, PH_ALIGN_LEFT, -1, DT_PATH_ELLIPSIS); - PhAddTreeNewColumn(hwnd, PHSVTLC_ERRORCONTROL, FALSE, L"Error control", 70, PH_ALIGN_LEFT, -1, 0); - PhAddTreeNewColumn(hwnd, PHSVTLC_GROUP, FALSE, L"Group", 100, PH_ALIGN_LEFT, -1, 0); - PhAddTreeNewColumn(hwnd, PHSVTLC_DESCRIPTION, FALSE, L"Description", 200, PH_ALIGN_LEFT, -1, 0); - PhAddTreeNewColumnEx(hwnd, PHSVTLC_KEYMODIFIEDTIME, FALSE, L"Key modified time", 140, PH_ALIGN_LEFT, -1, 0, TRUE); - - TreeNew_SetRedraw(hwnd, TRUE); - - TreeNew_SetSort(hwnd, 0, AscendingSortOrder); - - PhCmInitializeManager(&ServiceTreeListCm, hwnd, PHSVTLC_MAXIMUM, PhpServiceTreeNewPostSortFunction); - - if (PhPluginsEnabled) - { - PH_PLUGIN_TREENEW_INFORMATION treeNewInfo; - - treeNewInfo.TreeNewHandle = hwnd; - treeNewInfo.CmData = &ServiceTreeListCm; - PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackServiceTreeNewInitializing), &treeNewInfo); - } - - PhInitializeTreeNewFilterSupport(&FilterSupport, hwnd, ServiceNodeList); -} - -VOID PhLoadSettingsServiceTreeList( - VOID - ) -{ - PPH_STRING settings; - PPH_STRING sortSettings; - - settings = PhGetStringSetting(L"ServiceTreeListColumns"); - sortSettings = PhGetStringSetting(L"ServiceTreeListSort"); - PhCmLoadSettingsEx(ServiceTreeListHandle, &ServiceTreeListCm, 0, &settings->sr, &sortSettings->sr); - PhDereferenceObject(settings); - PhDereferenceObject(sortSettings); -} - -VOID PhSaveSettingsServiceTreeList( - VOID - ) -{ - PPH_STRING settings; - PPH_STRING sortSettings; - - settings = PhCmSaveSettingsEx(ServiceTreeListHandle, &ServiceTreeListCm, 0, &sortSettings); - PhSetStringSetting2(L"ServiceTreeListColumns", &settings->sr); - PhSetStringSetting2(L"ServiceTreeListSort", &sortSettings->sr); - PhDereferenceObject(settings); - PhDereferenceObject(sortSettings); -} - -struct _PH_TN_FILTER_SUPPORT *PhGetFilterSupportServiceTreeList( - VOID - ) -{ - return &FilterSupport; -} - -PPH_SERVICE_NODE PhAddServiceNode( - _In_ PPH_SERVICE_ITEM ServiceItem, - _In_ ULONG RunId - ) -{ - PPH_SERVICE_NODE serviceNode; - - serviceNode = PhAllocate(PhEmGetObjectSize(EmServiceNodeType, sizeof(PH_SERVICE_NODE))); - memset(serviceNode, 0, sizeof(PH_SERVICE_NODE)); - PhInitializeTreeNewNode(&serviceNode->Node); - - if (PhServiceTreeListStateHighlighting && RunId != 1) - { - PhChangeShStateTn( - &serviceNode->Node, - &serviceNode->ShState, - &ServiceNodeStateList, - NewItemState, - PhCsColorNew, - NULL - ); - } - - serviceNode->ServiceItem = ServiceItem; - PhReferenceObject(ServiceItem); - - memset(serviceNode->TextCache, 0, sizeof(PH_STRINGREF) * PHSVTLC_MAXIMUM); - serviceNode->Node.TextCache = serviceNode->TextCache; - serviceNode->Node.TextCacheSize = PHSVTLC_MAXIMUM; - - PhAddEntryHashtable(ServiceNodeHashtable, &serviceNode); - PhAddItemList(ServiceNodeList, serviceNode); - - if (FilterSupport.FilterList) - serviceNode->Node.Visible = PhApplyTreeNewFiltersToNode(&FilterSupport, &serviceNode->Node); - - PhEmCallObjectOperation(EmServiceNodeType, serviceNode, EmObjectCreate); - - TreeNew_NodesStructured(ServiceTreeListHandle); - - return serviceNode; -} - -PPH_SERVICE_NODE PhFindServiceNode( - _In_ PPH_SERVICE_ITEM ServiceItem - ) -{ - PH_SERVICE_NODE lookupServiceNode; - PPH_SERVICE_NODE lookupServiceNodePtr = &lookupServiceNode; - PPH_SERVICE_NODE *serviceNode; - - lookupServiceNode.ServiceItem = ServiceItem; - - serviceNode = (PPH_SERVICE_NODE *)PhFindEntryHashtable( - ServiceNodeHashtable, - &lookupServiceNodePtr - ); - - if (serviceNode) - return *serviceNode; - else - return NULL; -} - -VOID PhRemoveServiceNode( - _In_ PPH_SERVICE_NODE ServiceNode - ) -{ - // Remove from the hashtable here to avoid problems in case the key is re-used. - PhRemoveEntryHashtable(ServiceNodeHashtable, &ServiceNode); - - if (PhServiceTreeListStateHighlighting) - { - PhChangeShStateTn( - &ServiceNode->Node, - &ServiceNode->ShState, - &ServiceNodeStateList, - RemovingItemState, - PhCsColorRemoved, - ServiceTreeListHandle - ); - } - else - { - PhpRemoveServiceNode(ServiceNode); - } -} - -VOID PhpRemoveServiceNode( - _In_ PPH_SERVICE_NODE ServiceNode - ) -{ - ULONG index; - - PhEmCallObjectOperation(EmServiceNodeType, ServiceNode, EmObjectDelete); - - // Remove from list and cleanup. - - if ((index = PhFindItemList(ServiceNodeList, ServiceNode)) != -1) - PhRemoveItemList(ServiceNodeList, index); - - PhClearReference(&ServiceNode->BinaryPath); - PhClearReference(&ServiceNode->LoadOrderGroup); - PhClearReference(&ServiceNode->Description); - - PhClearReference(&ServiceNode->TooltipText); - - PhClearReference(&ServiceNode->KeyModifiedTimeText); - - PhDereferenceObject(ServiceNode->ServiceItem); - - PhFree(ServiceNode); - - TreeNew_NodesStructured(ServiceTreeListHandle); -} - -VOID PhUpdateServiceNode( - _In_ PPH_SERVICE_NODE ServiceNode - ) -{ - memset(ServiceNode->TextCache, 0, sizeof(PH_STRINGREF) * PHSVTLC_MAXIMUM); - PhClearReference(&ServiceNode->TooltipText); - - ServiceNode->ValidMask = 0; - PhInvalidateTreeNewNode(&ServiceNode->Node, TN_CACHE_ICON); - TreeNew_NodesStructured(ServiceTreeListHandle); -} - -VOID PhTickServiceNodes( - VOID - ) -{ - if (ServiceTreeListSortOrder != NoSortOrder && ServiceTreeListSortColumn >= PHSVTLC_MAXIMUM) - { - // Sorting is on, but it's not one of our columns. Force a rebuild. (If it was one of our - // columns, the restructure would have been handled in PhUpdateServiceNode.) - TreeNew_NodesStructured(ServiceTreeListHandle); - } - - PH_TICK_SH_STATE_TN(PH_SERVICE_NODE, ShState, ServiceNodeStateList, PhpRemoveServiceNode, PhCsHighlightingDuration, ServiceTreeListHandle, TRUE, NULL); -} - -static VOID PhpUpdateServiceNodeConfig( - _Inout_ PPH_SERVICE_NODE ServiceNode - ) -{ - if (!(ServiceNode->ValidMask & PHSN_CONFIG)) - { - SC_HANDLE serviceHandle; - LPQUERY_SERVICE_CONFIG serviceConfig; - - if (serviceHandle = PhOpenService(ServiceNode->ServiceItem->Name->Buffer, SERVICE_QUERY_CONFIG)) - { - if (serviceConfig = PhGetServiceConfig(serviceHandle)) - { - if (serviceConfig->lpBinaryPathName) - PhMoveReference(&ServiceNode->BinaryPath, PhCreateString(serviceConfig->lpBinaryPathName)); - if (serviceConfig->lpLoadOrderGroup) - PhMoveReference(&ServiceNode->LoadOrderGroup, PhCreateString(serviceConfig->lpLoadOrderGroup)); - - PhFree(serviceConfig); - } - - CloseServiceHandle(serviceHandle); - } - - ServiceNode->ValidMask |= PHSN_CONFIG; - } -} - -static VOID PhpUpdateServiceNodeDescription( - _Inout_ PPH_SERVICE_NODE ServiceNode - ) -{ - if (!(ServiceNode->ValidMask & PHSN_DESCRIPTION)) - { - SC_HANDLE serviceHandle; - - if (serviceHandle = PhOpenService(ServiceNode->ServiceItem->Name->Buffer, SERVICE_QUERY_CONFIG)) - { - PhMoveReference(&ServiceNode->Description, PhGetServiceDescription(serviceHandle)); - - CloseServiceHandle(serviceHandle); - } - - ServiceNode->ValidMask |= PHSN_DESCRIPTION; - } -} - -static VOID PhpUpdateServiceNodeKey( - _Inout_ PPH_SERVICE_NODE ServiceNode - ) -{ - if (!(ServiceNode->ValidMask & PHSN_KEY)) - { - static PH_STRINGREF servicesKeyName = PH_STRINGREF_INIT(L"System\\CurrentControlSet\\Services\\"); - - HANDLE keyHandle; - PPH_STRING keyName; - - keyName = PhConcatStringRef2(&servicesKeyName, &ServiceNode->ServiceItem->Name->sr); - - if (NT_SUCCESS(PhOpenKey( - &keyHandle, - KEY_READ, - PH_KEY_LOCAL_MACHINE, - &keyName->sr, - 0 - ))) - { - PKEY_BASIC_INFORMATION basicInfo; - - if (NT_SUCCESS(PhQueryKey(keyHandle, KeyBasicInformation, &basicInfo))) - { - ServiceNode->KeyLastWriteTime = basicInfo->LastWriteTime; - PhFree(basicInfo); - } - - NtClose(keyHandle); - } - - PhDereferenceObject(keyName); - - ServiceNode->ValidMask |= PHSN_KEY; - } -} - -#define SORT_FUNCTION(Column) PhpServiceTreeNewCompare##Column - -#define BEGIN_SORT_FUNCTION(Column) static int __cdecl PhpServiceTreeNewCompare##Column( \ - _In_ const void *_elem1, \ - _In_ const void *_elem2 \ - ) \ -{ \ - PPH_SERVICE_NODE node1 = *(PPH_SERVICE_NODE *)_elem1; \ - PPH_SERVICE_NODE node2 = *(PPH_SERVICE_NODE *)_elem2; \ - PPH_SERVICE_ITEM serviceItem1 = node1->ServiceItem; \ - PPH_SERVICE_ITEM serviceItem2 = node2->ServiceItem; \ - int sortResult = 0; - -#define END_SORT_FUNCTION \ - /* if (sortResult == 0) */ \ - /* sortResult = PhCompareString(serviceItem1->Name, serviceItem2->Name, TRUE); */ \ - \ - return PhModifySort(sortResult, ServiceTreeListSortOrder); \ -} - -LONG PhpServiceTreeNewPostSortFunction( - _In_ LONG Result, - _In_ PVOID Node1, - _In_ PVOID Node2, - _In_ PH_SORT_ORDER SortOrder - ) -{ - return PhModifySort(Result, SortOrder); -} - -BEGIN_SORT_FUNCTION(Name) -{ - sortResult = PhCompareString(serviceItem1->Name, serviceItem2->Name, TRUE); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(DisplayName) -{ - sortResult = PhCompareStringWithNull(serviceItem1->DisplayName, serviceItem2->DisplayName, TRUE); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(Type) -{ - sortResult = intcmp(serviceItem1->Type, serviceItem2->Type); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(Status) -{ - sortResult = intcmp(serviceItem1->State, serviceItem2->State); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(StartType) -{ - sortResult = intcmp(serviceItem1->StartType, serviceItem2->StartType); - - if (sortResult == 0) - sortResult = intcmp(serviceItem1->DelayedStart, serviceItem2->DelayedStart); - if (sortResult == 0) - sortResult = intcmp(serviceItem1->HasTriggers, serviceItem2->HasTriggers); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(Pid) -{ - sortResult = uintptrcmp((ULONG_PTR)serviceItem1->ProcessId, (ULONG_PTR)serviceItem2->ProcessId); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(BinaryPath) -{ - PhpUpdateServiceNodeConfig(node1); - PhpUpdateServiceNodeConfig(node2); - sortResult = PhCompareStringWithNull(node1->BinaryPath, node2->BinaryPath, TRUE); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(ErrorControl) -{ - sortResult = intcmp(serviceItem1->ErrorControl, serviceItem2->ErrorControl); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(Group) -{ - PhpUpdateServiceNodeConfig(node1); - PhpUpdateServiceNodeConfig(node2); - sortResult = PhCompareStringWithNull(node1->LoadOrderGroup, node2->LoadOrderGroup, TRUE); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(Description) -{ - PhpUpdateServiceNodeDescription(node1); - PhpUpdateServiceNodeDescription(node2); - sortResult = PhCompareStringWithNull(node1->Description, node2->Description, TRUE); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(KeyModifiedTime) -{ - PhpUpdateServiceNodeKey(node1); - PhpUpdateServiceNodeKey(node2); - sortResult = int64cmp(node1->KeyLastWriteTime.QuadPart, node2->KeyLastWriteTime.QuadPart); -} -END_SORT_FUNCTION - -BOOLEAN NTAPI PhpServiceTreeNewCallback( - _In_ HWND hwnd, - _In_ PH_TREENEW_MESSAGE Message, - _In_opt_ PVOID Parameter1, - _In_opt_ PVOID Parameter2, - _In_opt_ PVOID Context - ) -{ - PPH_SERVICE_NODE node; - - if (PhCmForwardMessage(hwnd, Message, Parameter1, Parameter2, &ServiceTreeListCm)) - return TRUE; - - switch (Message) - { - case TreeNewGetChildren: - { - PPH_TREENEW_GET_CHILDREN getChildren = Parameter1; - - if (!getChildren->Node) - { - static PVOID sortFunctions[] = - { - SORT_FUNCTION(Name), - SORT_FUNCTION(DisplayName), - SORT_FUNCTION(Type), - SORT_FUNCTION(Status), - SORT_FUNCTION(StartType), - SORT_FUNCTION(Pid), - SORT_FUNCTION(BinaryPath), - SORT_FUNCTION(ErrorControl), - SORT_FUNCTION(Group), - SORT_FUNCTION(Description), - SORT_FUNCTION(KeyModifiedTime) - }; - int (__cdecl *sortFunction)(const void *, const void *); - - if (!PhCmForwardSort( - (PPH_TREENEW_NODE *)ServiceNodeList->Items, - ServiceNodeList->Count, - ServiceTreeListSortColumn, - ServiceTreeListSortOrder, - &ServiceTreeListCm - )) - { - if (ServiceTreeListSortColumn < PHSVTLC_MAXIMUM) - sortFunction = sortFunctions[ServiceTreeListSortColumn]; - else - sortFunction = NULL; - - if (sortFunction) - { - qsort(ServiceNodeList->Items, ServiceNodeList->Count, sizeof(PVOID), sortFunction); - } - } - - getChildren->Children = (PPH_TREENEW_NODE *)ServiceNodeList->Items; - getChildren->NumberOfChildren = ServiceNodeList->Count; - } - } - return TRUE; - case TreeNewIsLeaf: - { - PPH_TREENEW_IS_LEAF isLeaf = Parameter1; - - isLeaf->IsLeaf = TRUE; - } - return TRUE; - case TreeNewGetCellText: - { - PPH_TREENEW_GET_CELL_TEXT getCellText = Parameter1; - PPH_SERVICE_ITEM serviceItem; - - node = (PPH_SERVICE_NODE)getCellText->Node; - serviceItem = node->ServiceItem; - - switch (getCellText->Id) - { - case PHSVTLC_NAME: - getCellText->Text = serviceItem->Name->sr; - break; - case PHSVTLC_DISPLAYNAME: - getCellText->Text = serviceItem->DisplayName->sr; - break; - case PHSVTLC_TYPE: - PhInitializeStringRefLongHint(&getCellText->Text, PhGetServiceTypeString(serviceItem->Type)); - break; - case PHSVTLC_STATUS: - PhInitializeStringRefLongHint(&getCellText->Text, PhGetServiceStateString(serviceItem->State)); - break; - case PHSVTLC_STARTTYPE: - { - PH_FORMAT format[2]; - PWSTR additional = NULL; - SIZE_T returnLength; - - PhInitFormatS(&format[0], PhGetServiceStartTypeString(serviceItem->StartType)); - - if (serviceItem->DelayedStart && serviceItem->HasTriggers) - additional = L" (delayed, trigger)"; - else if (serviceItem->DelayedStart) - additional = L" (delayed)"; - else if (serviceItem->HasTriggers) - additional = L" (trigger)"; - - if (additional) - PhInitFormatS(&format[1], additional); - - if (PhFormatToBuffer(format, 1 + (additional ? 1 : 0), node->StartTypeText, - sizeof(node->StartTypeText), &returnLength)) - { - getCellText->Text.Buffer = node->StartTypeText; - getCellText->Text.Length = returnLength - sizeof(WCHAR); // minus null terminator - } - } - break; - case PHSVTLC_PID: - PhInitializeStringRefLongHint(&getCellText->Text, serviceItem->ProcessIdString); - break; - case PHSVTLC_BINARYPATH: - PhpUpdateServiceNodeConfig(node); - getCellText->Text = PhGetStringRef(node->BinaryPath); - break; - case PHSVTLC_ERRORCONTROL: - PhInitializeStringRefLongHint(&getCellText->Text, PhGetServiceErrorControlString(serviceItem->ErrorControl)); - break; - case PHSVTLC_GROUP: - PhpUpdateServiceNodeConfig(node); - getCellText->Text = PhGetStringRef(node->LoadOrderGroup); - break; - case PHSVTLC_DESCRIPTION: - PhpUpdateServiceNodeDescription(node); - getCellText->Text = PhGetStringRef(node->Description); - break; - case PHSVTLC_KEYMODIFIEDTIME: - PhpUpdateServiceNodeKey(node); - - if (node->KeyLastWriteTime.QuadPart != 0) - { - SYSTEMTIME systemTime; - - PhLargeIntegerToLocalSystemTime(&systemTime, &node->KeyLastWriteTime); - PhMoveReference(&node->KeyModifiedTimeText, PhFormatDateTime(&systemTime)); - getCellText->Text = node->KeyModifiedTimeText->sr; - } - break; - default: - return FALSE; - } - - getCellText->Flags = TN_CACHE; - } - return TRUE; - case TreeNewGetNodeIcon: - { - PPH_TREENEW_GET_NODE_ICON getNodeIcon = Parameter1; - - node = (PPH_SERVICE_NODE)getNodeIcon->Node; - - if (!ServiceIconsLoaded) - { - ServiceApplicationIcon = PH_LOAD_SHARED_ICON_SMALL(MAKEINTRESOURCE(IDI_PHAPPLICATION)); - ServiceApplicationGoIcon = PH_LOAD_SHARED_ICON_SMALL(MAKEINTRESOURCE(IDI_PHAPPLICATIONGO)); - ServiceCogIcon = PH_LOAD_SHARED_ICON_SMALL(MAKEINTRESOURCE(IDI_COG)); - ServiceCogGoIcon = PH_LOAD_SHARED_ICON_SMALL(MAKEINTRESOURCE(IDI_COGGO)); - - ServiceIconsLoaded = TRUE; - } - - if (node->ServiceItem->Type == SERVICE_KERNEL_DRIVER || node->ServiceItem->Type == SERVICE_FILE_SYSTEM_DRIVER) - { - if (node->ServiceItem->State == SERVICE_RUNNING) - getNodeIcon->Icon = ServiceCogGoIcon; - else - getNodeIcon->Icon = ServiceCogIcon; - } - else - { - if (node->ServiceItem->State == SERVICE_RUNNING) - getNodeIcon->Icon = ServiceApplicationGoIcon; - else - getNodeIcon->Icon = ServiceApplicationIcon; - } - - getNodeIcon->Flags = TN_CACHE; - } - return TRUE; - case TreeNewGetCellTooltip: - { - PPH_TREENEW_GET_CELL_TOOLTIP getCellTooltip = Parameter1; - - node = (PPH_SERVICE_NODE)getCellTooltip->Node; - - if (getCellTooltip->Column->Id != 0) - return FALSE; - - if (!node->TooltipText) - node->TooltipText = PhGetServiceTooltipText(node->ServiceItem); - - if (!PhIsNullOrEmptyString(node->TooltipText)) - { - getCellTooltip->Text = node->TooltipText->sr; - getCellTooltip->Unfolding = FALSE; - getCellTooltip->MaximumWidth = 550; - } - else - { - return FALSE; - } - } - return TRUE; - case TreeNewSortChanged: - { - TreeNew_GetSort(hwnd, &ServiceTreeListSortColumn, &ServiceTreeListSortOrder); - // Force a rebuild to sort the items. - TreeNew_NodesStructured(hwnd); - } - return TRUE; - case TreeNewKeyDown: - { - PPH_TREENEW_KEY_EVENT keyEvent = Parameter1; - - switch (keyEvent->VirtualKey) - { - case 'C': - if (GetKeyState(VK_CONTROL) < 0) - SendMessage(PhMainWndHandle, WM_COMMAND, ID_SERVICE_COPY, 0); - break; - case 'A': - if (GetKeyState(VK_CONTROL) < 0) - TreeNew_SelectRange(ServiceTreeListHandle, 0, -1); - break; - case VK_DELETE: - SendMessage(PhMainWndHandle, WM_COMMAND, ID_SERVICE_DELETE, 0); - break; - case VK_RETURN: - if (GetKeyState(VK_CONTROL) >= 0) - SendMessage(PhMainWndHandle, WM_COMMAND, ID_SERVICE_PROPERTIES, 0); - else - SendMessage(PhMainWndHandle, WM_COMMAND, ID_SERVICE_OPENFILELOCATION, 0); - break; - } - } - return TRUE; - case TreeNewHeaderRightClick: - { - PH_TN_COLUMN_MENU_DATA data; - - data.TreeNewHandle = hwnd; - data.MouseEvent = Parameter1; - data.DefaultSortColumn = 0; - data.DefaultSortOrder = AscendingSortOrder; - PhInitializeTreeNewColumnMenu(&data); - - data.Selection = PhShowEMenu(data.Menu, hwnd, PH_EMENU_SHOW_LEFTRIGHT, - PH_ALIGN_LEFT | PH_ALIGN_TOP, data.MouseEvent->ScreenLocation.x, data.MouseEvent->ScreenLocation.y); - PhHandleTreeNewColumnMenu(&data); - PhDeleteTreeNewColumnMenu(&data); - } - return TRUE; - case TreeNewLeftDoubleClick: - { - SendMessage(PhMainWndHandle, WM_COMMAND, ID_SERVICE_PROPERTIES, 0); - } - return TRUE; - case TreeNewContextMenu: - { - PPH_TREENEW_CONTEXT_MENU contextMenu = Parameter1; - - PhShowServiceContextMenu(contextMenu); - } - return TRUE; - } - - return FALSE; -} - -PPH_SERVICE_ITEM PhGetSelectedServiceItem( - VOID - ) -{ - PPH_SERVICE_ITEM serviceItem = NULL; - ULONG i; - - for (i = 0; i < ServiceNodeList->Count; i++) - { - PPH_SERVICE_NODE node = ServiceNodeList->Items[i]; - - if (node->Node.Selected) - { - serviceItem = node->ServiceItem; - break; - } - } - - return serviceItem; -} - -VOID PhGetSelectedServiceItems( - _Out_ PPH_SERVICE_ITEM **Services, - _Out_ PULONG NumberOfServices - ) -{ - PH_ARRAY array; - ULONG i; - - PhInitializeArray(&array, sizeof(PVOID), 2); - - for (i = 0; i < ServiceNodeList->Count; i++) - { - PPH_SERVICE_NODE node = ServiceNodeList->Items[i]; - - if (node->Node.Selected) - PhAddItemArray(&array, &node->ServiceItem); - } - - *NumberOfServices = (ULONG)array.Count; - *Services = PhFinalArrayItems(&array); -} - -VOID PhDeselectAllServiceNodes( - VOID - ) -{ - TreeNew_DeselectRange(ServiceTreeListHandle, 0, -1); -} - -VOID PhSelectAndEnsureVisibleServiceNode( - _In_ PPH_SERVICE_NODE ServiceNode - ) -{ - PhDeselectAllServiceNodes(); - - if (!ServiceNode->Node.Visible) - return; - - TreeNew_SetFocusNode(ServiceTreeListHandle, &ServiceNode->Node); - TreeNew_SetMarkNode(ServiceTreeListHandle, &ServiceNode->Node); - TreeNew_SelectRange(ServiceTreeListHandle, ServiceNode->Node.Index, ServiceNode->Node.Index); - TreeNew_EnsureVisible(ServiceTreeListHandle, &ServiceNode->Node); -} - -VOID PhCopyServiceList( - VOID - ) -{ - PPH_STRING text; - - text = PhGetTreeNewText(ServiceTreeListHandle, 0); - PhSetClipboardString(ServiceTreeListHandle, &text->sr); - PhDereferenceObject(text); -} - -VOID PhWriteServiceList( - _Inout_ PPH_FILE_STREAM FileStream, - _In_ ULONG Mode - ) -{ - PPH_LIST lines; - ULONG i; - - lines = PhGetGenericTreeNewLines(ServiceTreeListHandle, Mode); - - for (i = 0; i < lines->Count; i++) - { - PPH_STRING line; - - line = lines->Items[i]; - PhWriteStringAsUtf8FileStream(FileStream, &line->sr); - PhDereferenceObject(line); - PhWriteStringAsUtf8FileStream2(FileStream, L"\r\n"); - } - - PhDereferenceObject(lines); -} +/* + * Process Hacker - + * service list + * + * Copyright (C) 2010-2015 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +BOOLEAN PhpServiceNodeHashtableEqualFunction( + _In_ PVOID Entry1, + _In_ PVOID Entry2 + ); + +ULONG PhpServiceNodeHashtableHashFunction( + _In_ PVOID Entry + ); + +VOID PhpRemoveServiceNode( + _In_ PPH_SERVICE_NODE ServiceNode + ); + +LONG PhpServiceTreeNewPostSortFunction( + _In_ LONG Result, + _In_ PVOID Node1, + _In_ PVOID Node2, + _In_ PH_SORT_ORDER SortOrder + ); + +BOOLEAN NTAPI PhpServiceTreeNewCallback( + _In_ HWND hwnd, + _In_ PH_TREENEW_MESSAGE Message, + _In_opt_ PVOID Parameter1, + _In_opt_ PVOID Parameter2, + _In_opt_ PVOID Context + ); + +static HWND ServiceTreeListHandle; +static ULONG ServiceTreeListSortColumn; +static PH_SORT_ORDER ServiceTreeListSortOrder; +static PH_CM_MANAGER ServiceTreeListCm; + +static PPH_HASHTABLE ServiceNodeHashtable; // hashtable of all nodes +static PPH_LIST ServiceNodeList; // list of all nodes + +static PH_TN_FILTER_SUPPORT FilterSupport; + +static BOOLEAN ServiceIconsLoaded = FALSE; +static HICON ServiceApplicationIcon; +static HICON ServiceApplicationGoIcon; +static HICON ServiceCogIcon; +static HICON ServiceCogGoIcon; + +BOOLEAN PhServiceTreeListStateHighlighting = TRUE; +static PPH_POINTER_LIST ServiceNodeStateList = NULL; // list of nodes which need to be processed + +VOID PhServiceTreeListInitialization( + VOID + ) +{ + ServiceNodeHashtable = PhCreateHashtable( + sizeof(PPH_SERVICE_NODE), + PhpServiceNodeHashtableEqualFunction, + PhpServiceNodeHashtableHashFunction, + 100 + ); + ServiceNodeList = PhCreateList(100); +} + +BOOLEAN PhpServiceNodeHashtableEqualFunction( + _In_ PVOID Entry1, + _In_ PVOID Entry2 + ) +{ + PPH_SERVICE_NODE serviceNode1 = *(PPH_SERVICE_NODE *)Entry1; + PPH_SERVICE_NODE serviceNode2 = *(PPH_SERVICE_NODE *)Entry2; + + return serviceNode1->ServiceItem == serviceNode2->ServiceItem; +} + +ULONG PhpServiceNodeHashtableHashFunction( + _In_ PVOID Entry + ) +{ + return PhHashIntPtr((ULONG_PTR)(*(PPH_SERVICE_NODE *)Entry)->ServiceItem); +} + +VOID PhInitializeServiceTreeList( + _In_ HWND hwnd + ) +{ + ServiceTreeListHandle = hwnd; + PhSetControlTheme(ServiceTreeListHandle, L"explorer"); + SendMessage(TreeNew_GetTooltips(ServiceTreeListHandle), TTM_SETDELAYTIME, TTDT_AUTOPOP, MAXSHORT); + + TreeNew_SetCallback(hwnd, PhpServiceTreeNewCallback, NULL); + + TreeNew_SetRedraw(hwnd, FALSE); + + // Default columns + PhAddTreeNewColumn(hwnd, PHSVTLC_NAME, TRUE, L"Name", 140, PH_ALIGN_LEFT, 0, 0); + PhAddTreeNewColumn(hwnd, PHSVTLC_DISPLAYNAME, TRUE, L"Display name", 220, PH_ALIGN_LEFT, 1, 0); + PhAddTreeNewColumn(hwnd, PHSVTLC_TYPE, TRUE, L"Type", 100, PH_ALIGN_LEFT, 2, 0); + PhAddTreeNewColumn(hwnd, PHSVTLC_STATUS, TRUE, L"Status", 70, PH_ALIGN_LEFT, 3, 0); + PhAddTreeNewColumn(hwnd, PHSVTLC_STARTTYPE, TRUE, L"Start type", 130, PH_ALIGN_LEFT, 4, 0); + PhAddTreeNewColumn(hwnd, PHSVTLC_PID, TRUE, L"PID", 50, PH_ALIGN_RIGHT, 5, DT_RIGHT); + + PhAddTreeNewColumn(hwnd, PHSVTLC_BINARYPATH, FALSE, L"Binary path", 180, PH_ALIGN_LEFT, -1, DT_PATH_ELLIPSIS); + PhAddTreeNewColumn(hwnd, PHSVTLC_ERRORCONTROL, FALSE, L"Error control", 70, PH_ALIGN_LEFT, -1, 0); + PhAddTreeNewColumn(hwnd, PHSVTLC_GROUP, FALSE, L"Group", 100, PH_ALIGN_LEFT, -1, 0); + PhAddTreeNewColumn(hwnd, PHSVTLC_DESCRIPTION, FALSE, L"Description", 200, PH_ALIGN_LEFT, -1, 0); + PhAddTreeNewColumnEx(hwnd, PHSVTLC_KEYMODIFIEDTIME, FALSE, L"Key modified time", 140, PH_ALIGN_LEFT, -1, 0, TRUE); + + TreeNew_SetRedraw(hwnd, TRUE); + + TreeNew_SetSort(hwnd, 0, AscendingSortOrder); + + PhCmInitializeManager(&ServiceTreeListCm, hwnd, PHSVTLC_MAXIMUM, PhpServiceTreeNewPostSortFunction); + + if (PhPluginsEnabled) + { + PH_PLUGIN_TREENEW_INFORMATION treeNewInfo; + + treeNewInfo.TreeNewHandle = hwnd; + treeNewInfo.CmData = &ServiceTreeListCm; + PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackServiceTreeNewInitializing), &treeNewInfo); + } + + PhInitializeTreeNewFilterSupport(&FilterSupport, hwnd, ServiceNodeList); +} + +VOID PhLoadSettingsServiceTreeList( + VOID + ) +{ + PPH_STRING settings; + PPH_STRING sortSettings; + + settings = PhGetStringSetting(L"ServiceTreeListColumns"); + sortSettings = PhGetStringSetting(L"ServiceTreeListSort"); + PhCmLoadSettingsEx(ServiceTreeListHandle, &ServiceTreeListCm, 0, &settings->sr, &sortSettings->sr); + PhDereferenceObject(settings); + PhDereferenceObject(sortSettings); +} + +VOID PhSaveSettingsServiceTreeList( + VOID + ) +{ + PPH_STRING settings; + PPH_STRING sortSettings; + + settings = PhCmSaveSettingsEx(ServiceTreeListHandle, &ServiceTreeListCm, 0, &sortSettings); + PhSetStringSetting2(L"ServiceTreeListColumns", &settings->sr); + PhSetStringSetting2(L"ServiceTreeListSort", &sortSettings->sr); + PhDereferenceObject(settings); + PhDereferenceObject(sortSettings); +} + +struct _PH_TN_FILTER_SUPPORT *PhGetFilterSupportServiceTreeList( + VOID + ) +{ + return &FilterSupport; +} + +PPH_SERVICE_NODE PhAddServiceNode( + _In_ PPH_SERVICE_ITEM ServiceItem, + _In_ ULONG RunId + ) +{ + PPH_SERVICE_NODE serviceNode; + + serviceNode = PhAllocate(PhEmGetObjectSize(EmServiceNodeType, sizeof(PH_SERVICE_NODE))); + memset(serviceNode, 0, sizeof(PH_SERVICE_NODE)); + PhInitializeTreeNewNode(&serviceNode->Node); + + if (PhServiceTreeListStateHighlighting && RunId != 1) + { + PhChangeShStateTn( + &serviceNode->Node, + &serviceNode->ShState, + &ServiceNodeStateList, + NewItemState, + PhCsColorNew, + NULL + ); + } + + serviceNode->ServiceItem = ServiceItem; + PhReferenceObject(ServiceItem); + + memset(serviceNode->TextCache, 0, sizeof(PH_STRINGREF) * PHSVTLC_MAXIMUM); + serviceNode->Node.TextCache = serviceNode->TextCache; + serviceNode->Node.TextCacheSize = PHSVTLC_MAXIMUM; + + PhAddEntryHashtable(ServiceNodeHashtable, &serviceNode); + PhAddItemList(ServiceNodeList, serviceNode); + + if (FilterSupport.FilterList) + serviceNode->Node.Visible = PhApplyTreeNewFiltersToNode(&FilterSupport, &serviceNode->Node); + + PhEmCallObjectOperation(EmServiceNodeType, serviceNode, EmObjectCreate); + + TreeNew_NodesStructured(ServiceTreeListHandle); + + return serviceNode; +} + +PPH_SERVICE_NODE PhFindServiceNode( + _In_ PPH_SERVICE_ITEM ServiceItem + ) +{ + PH_SERVICE_NODE lookupServiceNode; + PPH_SERVICE_NODE lookupServiceNodePtr = &lookupServiceNode; + PPH_SERVICE_NODE *serviceNode; + + lookupServiceNode.ServiceItem = ServiceItem; + + serviceNode = (PPH_SERVICE_NODE *)PhFindEntryHashtable( + ServiceNodeHashtable, + &lookupServiceNodePtr + ); + + if (serviceNode) + return *serviceNode; + else + return NULL; +} + +VOID PhRemoveServiceNode( + _In_ PPH_SERVICE_NODE ServiceNode + ) +{ + // Remove from the hashtable here to avoid problems in case the key is re-used. + PhRemoveEntryHashtable(ServiceNodeHashtable, &ServiceNode); + + if (PhServiceTreeListStateHighlighting) + { + PhChangeShStateTn( + &ServiceNode->Node, + &ServiceNode->ShState, + &ServiceNodeStateList, + RemovingItemState, + PhCsColorRemoved, + ServiceTreeListHandle + ); + } + else + { + PhpRemoveServiceNode(ServiceNode); + } +} + +VOID PhpRemoveServiceNode( + _In_ PPH_SERVICE_NODE ServiceNode + ) +{ + ULONG index; + + PhEmCallObjectOperation(EmServiceNodeType, ServiceNode, EmObjectDelete); + + // Remove from list and cleanup. + + if ((index = PhFindItemList(ServiceNodeList, ServiceNode)) != -1) + PhRemoveItemList(ServiceNodeList, index); + + PhClearReference(&ServiceNode->BinaryPath); + PhClearReference(&ServiceNode->LoadOrderGroup); + PhClearReference(&ServiceNode->Description); + + PhClearReference(&ServiceNode->TooltipText); + + PhClearReference(&ServiceNode->KeyModifiedTimeText); + + PhDereferenceObject(ServiceNode->ServiceItem); + + PhFree(ServiceNode); + + TreeNew_NodesStructured(ServiceTreeListHandle); +} + +VOID PhUpdateServiceNode( + _In_ PPH_SERVICE_NODE ServiceNode + ) +{ + memset(ServiceNode->TextCache, 0, sizeof(PH_STRINGREF) * PHSVTLC_MAXIMUM); + PhClearReference(&ServiceNode->TooltipText); + + ServiceNode->ValidMask = 0; + PhInvalidateTreeNewNode(&ServiceNode->Node, TN_CACHE_ICON); + TreeNew_NodesStructured(ServiceTreeListHandle); +} + +VOID PhTickServiceNodes( + VOID + ) +{ + if (ServiceTreeListSortOrder != NoSortOrder && ServiceTreeListSortColumn >= PHSVTLC_MAXIMUM) + { + // Sorting is on, but it's not one of our columns. Force a rebuild. (If it was one of our + // columns, the restructure would have been handled in PhUpdateServiceNode.) + TreeNew_NodesStructured(ServiceTreeListHandle); + } + + PH_TICK_SH_STATE_TN(PH_SERVICE_NODE, ShState, ServiceNodeStateList, PhpRemoveServiceNode, PhCsHighlightingDuration, ServiceTreeListHandle, TRUE, NULL); +} + +static VOID PhpUpdateServiceNodeConfig( + _Inout_ PPH_SERVICE_NODE ServiceNode + ) +{ + if (!(ServiceNode->ValidMask & PHSN_CONFIG)) + { + SC_HANDLE serviceHandle; + LPQUERY_SERVICE_CONFIG serviceConfig; + + if (serviceHandle = PhOpenService(ServiceNode->ServiceItem->Name->Buffer, SERVICE_QUERY_CONFIG)) + { + if (serviceConfig = PhGetServiceConfig(serviceHandle)) + { + if (serviceConfig->lpBinaryPathName) + PhMoveReference(&ServiceNode->BinaryPath, PhCreateString(serviceConfig->lpBinaryPathName)); + if (serviceConfig->lpLoadOrderGroup) + PhMoveReference(&ServiceNode->LoadOrderGroup, PhCreateString(serviceConfig->lpLoadOrderGroup)); + + PhFree(serviceConfig); + } + + CloseServiceHandle(serviceHandle); + } + + ServiceNode->ValidMask |= PHSN_CONFIG; + } +} + +static VOID PhpUpdateServiceNodeDescription( + _Inout_ PPH_SERVICE_NODE ServiceNode + ) +{ + if (!(ServiceNode->ValidMask & PHSN_DESCRIPTION)) + { + SC_HANDLE serviceHandle; + + if (serviceHandle = PhOpenService(ServiceNode->ServiceItem->Name->Buffer, SERVICE_QUERY_CONFIG)) + { + PhMoveReference(&ServiceNode->Description, PhGetServiceDescription(serviceHandle)); + + CloseServiceHandle(serviceHandle); + } + + ServiceNode->ValidMask |= PHSN_DESCRIPTION; + } +} + +static VOID PhpUpdateServiceNodeKey( + _Inout_ PPH_SERVICE_NODE ServiceNode + ) +{ + if (!(ServiceNode->ValidMask & PHSN_KEY)) + { + static PH_STRINGREF servicesKeyName = PH_STRINGREF_INIT(L"System\\CurrentControlSet\\Services\\"); + + HANDLE keyHandle; + PPH_STRING keyName; + + keyName = PhConcatStringRef2(&servicesKeyName, &ServiceNode->ServiceItem->Name->sr); + + if (NT_SUCCESS(PhOpenKey( + &keyHandle, + KEY_READ, + PH_KEY_LOCAL_MACHINE, + &keyName->sr, + 0 + ))) + { + PKEY_BASIC_INFORMATION basicInfo; + + if (NT_SUCCESS(PhQueryKey(keyHandle, KeyBasicInformation, &basicInfo))) + { + ServiceNode->KeyLastWriteTime = basicInfo->LastWriteTime; + PhFree(basicInfo); + } + + NtClose(keyHandle); + } + + PhDereferenceObject(keyName); + + ServiceNode->ValidMask |= PHSN_KEY; + } +} + +#define SORT_FUNCTION(Column) PhpServiceTreeNewCompare##Column + +#define BEGIN_SORT_FUNCTION(Column) static int __cdecl PhpServiceTreeNewCompare##Column( \ + _In_ const void *_elem1, \ + _In_ const void *_elem2 \ + ) \ +{ \ + PPH_SERVICE_NODE node1 = *(PPH_SERVICE_NODE *)_elem1; \ + PPH_SERVICE_NODE node2 = *(PPH_SERVICE_NODE *)_elem2; \ + PPH_SERVICE_ITEM serviceItem1 = node1->ServiceItem; \ + PPH_SERVICE_ITEM serviceItem2 = node2->ServiceItem; \ + int sortResult = 0; + +#define END_SORT_FUNCTION \ + /* if (sortResult == 0) */ \ + /* sortResult = PhCompareString(serviceItem1->Name, serviceItem2->Name, TRUE); */ \ + \ + return PhModifySort(sortResult, ServiceTreeListSortOrder); \ +} + +LONG PhpServiceTreeNewPostSortFunction( + _In_ LONG Result, + _In_ PVOID Node1, + _In_ PVOID Node2, + _In_ PH_SORT_ORDER SortOrder + ) +{ + return PhModifySort(Result, SortOrder); +} + +BEGIN_SORT_FUNCTION(Name) +{ + sortResult = PhCompareString(serviceItem1->Name, serviceItem2->Name, TRUE); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(DisplayName) +{ + sortResult = PhCompareStringWithNull(serviceItem1->DisplayName, serviceItem2->DisplayName, TRUE); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(Type) +{ + sortResult = intcmp(serviceItem1->Type, serviceItem2->Type); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(Status) +{ + sortResult = intcmp(serviceItem1->State, serviceItem2->State); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(StartType) +{ + sortResult = intcmp(serviceItem1->StartType, serviceItem2->StartType); + + if (sortResult == 0) + sortResult = intcmp(serviceItem1->DelayedStart, serviceItem2->DelayedStart); + if (sortResult == 0) + sortResult = intcmp(serviceItem1->HasTriggers, serviceItem2->HasTriggers); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(Pid) +{ + sortResult = uintptrcmp((ULONG_PTR)serviceItem1->ProcessId, (ULONG_PTR)serviceItem2->ProcessId); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(BinaryPath) +{ + PhpUpdateServiceNodeConfig(node1); + PhpUpdateServiceNodeConfig(node2); + sortResult = PhCompareStringWithNull(node1->BinaryPath, node2->BinaryPath, TRUE); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(ErrorControl) +{ + sortResult = intcmp(serviceItem1->ErrorControl, serviceItem2->ErrorControl); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(Group) +{ + PhpUpdateServiceNodeConfig(node1); + PhpUpdateServiceNodeConfig(node2); + sortResult = PhCompareStringWithNull(node1->LoadOrderGroup, node2->LoadOrderGroup, TRUE); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(Description) +{ + PhpUpdateServiceNodeDescription(node1); + PhpUpdateServiceNodeDescription(node2); + sortResult = PhCompareStringWithNull(node1->Description, node2->Description, TRUE); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(KeyModifiedTime) +{ + PhpUpdateServiceNodeKey(node1); + PhpUpdateServiceNodeKey(node2); + sortResult = int64cmp(node1->KeyLastWriteTime.QuadPart, node2->KeyLastWriteTime.QuadPart); +} +END_SORT_FUNCTION + +BOOLEAN NTAPI PhpServiceTreeNewCallback( + _In_ HWND hwnd, + _In_ PH_TREENEW_MESSAGE Message, + _In_opt_ PVOID Parameter1, + _In_opt_ PVOID Parameter2, + _In_opt_ PVOID Context + ) +{ + PPH_SERVICE_NODE node; + + if (PhCmForwardMessage(hwnd, Message, Parameter1, Parameter2, &ServiceTreeListCm)) + return TRUE; + + switch (Message) + { + case TreeNewGetChildren: + { + PPH_TREENEW_GET_CHILDREN getChildren = Parameter1; + + if (!getChildren->Node) + { + static PVOID sortFunctions[] = + { + SORT_FUNCTION(Name), + SORT_FUNCTION(DisplayName), + SORT_FUNCTION(Type), + SORT_FUNCTION(Status), + SORT_FUNCTION(StartType), + SORT_FUNCTION(Pid), + SORT_FUNCTION(BinaryPath), + SORT_FUNCTION(ErrorControl), + SORT_FUNCTION(Group), + SORT_FUNCTION(Description), + SORT_FUNCTION(KeyModifiedTime) + }; + int (__cdecl *sortFunction)(const void *, const void *); + + if (!PhCmForwardSort( + (PPH_TREENEW_NODE *)ServiceNodeList->Items, + ServiceNodeList->Count, + ServiceTreeListSortColumn, + ServiceTreeListSortOrder, + &ServiceTreeListCm + )) + { + if (ServiceTreeListSortColumn < PHSVTLC_MAXIMUM) + sortFunction = sortFunctions[ServiceTreeListSortColumn]; + else + sortFunction = NULL; + + if (sortFunction) + { + qsort(ServiceNodeList->Items, ServiceNodeList->Count, sizeof(PVOID), sortFunction); + } + } + + getChildren->Children = (PPH_TREENEW_NODE *)ServiceNodeList->Items; + getChildren->NumberOfChildren = ServiceNodeList->Count; + } + } + return TRUE; + case TreeNewIsLeaf: + { + PPH_TREENEW_IS_LEAF isLeaf = Parameter1; + + isLeaf->IsLeaf = TRUE; + } + return TRUE; + case TreeNewGetCellText: + { + PPH_TREENEW_GET_CELL_TEXT getCellText = Parameter1; + PPH_SERVICE_ITEM serviceItem; + + node = (PPH_SERVICE_NODE)getCellText->Node; + serviceItem = node->ServiceItem; + + switch (getCellText->Id) + { + case PHSVTLC_NAME: + getCellText->Text = serviceItem->Name->sr; + break; + case PHSVTLC_DISPLAYNAME: + getCellText->Text = serviceItem->DisplayName->sr; + break; + case PHSVTLC_TYPE: + PhInitializeStringRefLongHint(&getCellText->Text, PhGetServiceTypeString(serviceItem->Type)); + break; + case PHSVTLC_STATUS: + PhInitializeStringRefLongHint(&getCellText->Text, PhGetServiceStateString(serviceItem->State)); + break; + case PHSVTLC_STARTTYPE: + { + PH_FORMAT format[2]; + PWSTR additional = NULL; + SIZE_T returnLength; + + PhInitFormatS(&format[0], PhGetServiceStartTypeString(serviceItem->StartType)); + + if (serviceItem->DelayedStart && serviceItem->HasTriggers) + additional = L" (delayed, trigger)"; + else if (serviceItem->DelayedStart) + additional = L" (delayed)"; + else if (serviceItem->HasTriggers) + additional = L" (trigger)"; + + if (additional) + PhInitFormatS(&format[1], additional); + + if (PhFormatToBuffer(format, 1 + (additional ? 1 : 0), node->StartTypeText, + sizeof(node->StartTypeText), &returnLength)) + { + getCellText->Text.Buffer = node->StartTypeText; + getCellText->Text.Length = returnLength - sizeof(WCHAR); // minus null terminator + } + } + break; + case PHSVTLC_PID: + PhInitializeStringRefLongHint(&getCellText->Text, serviceItem->ProcessIdString); + break; + case PHSVTLC_BINARYPATH: + PhpUpdateServiceNodeConfig(node); + getCellText->Text = PhGetStringRef(node->BinaryPath); + break; + case PHSVTLC_ERRORCONTROL: + PhInitializeStringRefLongHint(&getCellText->Text, PhGetServiceErrorControlString(serviceItem->ErrorControl)); + break; + case PHSVTLC_GROUP: + PhpUpdateServiceNodeConfig(node); + getCellText->Text = PhGetStringRef(node->LoadOrderGroup); + break; + case PHSVTLC_DESCRIPTION: + PhpUpdateServiceNodeDescription(node); + getCellText->Text = PhGetStringRef(node->Description); + break; + case PHSVTLC_KEYMODIFIEDTIME: + PhpUpdateServiceNodeKey(node); + + if (node->KeyLastWriteTime.QuadPart != 0) + { + SYSTEMTIME systemTime; + + PhLargeIntegerToLocalSystemTime(&systemTime, &node->KeyLastWriteTime); + PhMoveReference(&node->KeyModifiedTimeText, PhFormatDateTime(&systemTime)); + getCellText->Text = node->KeyModifiedTimeText->sr; + } + break; + default: + return FALSE; + } + + getCellText->Flags = TN_CACHE; + } + return TRUE; + case TreeNewGetNodeIcon: + { + PPH_TREENEW_GET_NODE_ICON getNodeIcon = Parameter1; + + node = (PPH_SERVICE_NODE)getNodeIcon->Node; + + if (!ServiceIconsLoaded) + { + ServiceApplicationIcon = PH_LOAD_SHARED_ICON_SMALL(MAKEINTRESOURCE(IDI_PHAPPLICATION)); + ServiceApplicationGoIcon = PH_LOAD_SHARED_ICON_SMALL(MAKEINTRESOURCE(IDI_PHAPPLICATIONGO)); + ServiceCogIcon = PH_LOAD_SHARED_ICON_SMALL(MAKEINTRESOURCE(IDI_COG)); + ServiceCogGoIcon = PH_LOAD_SHARED_ICON_SMALL(MAKEINTRESOURCE(IDI_COGGO)); + + ServiceIconsLoaded = TRUE; + } + + if (node->ServiceItem->Type == SERVICE_KERNEL_DRIVER || node->ServiceItem->Type == SERVICE_FILE_SYSTEM_DRIVER) + { + if (node->ServiceItem->State == SERVICE_RUNNING) + getNodeIcon->Icon = ServiceCogGoIcon; + else + getNodeIcon->Icon = ServiceCogIcon; + } + else + { + if (node->ServiceItem->State == SERVICE_RUNNING) + getNodeIcon->Icon = ServiceApplicationGoIcon; + else + getNodeIcon->Icon = ServiceApplicationIcon; + } + + getNodeIcon->Flags = TN_CACHE; + } + return TRUE; + case TreeNewGetCellTooltip: + { + PPH_TREENEW_GET_CELL_TOOLTIP getCellTooltip = Parameter1; + + node = (PPH_SERVICE_NODE)getCellTooltip->Node; + + if (getCellTooltip->Column->Id != 0) + return FALSE; + + if (!node->TooltipText) + node->TooltipText = PhGetServiceTooltipText(node->ServiceItem); + + if (!PhIsNullOrEmptyString(node->TooltipText)) + { + getCellTooltip->Text = node->TooltipText->sr; + getCellTooltip->Unfolding = FALSE; + getCellTooltip->MaximumWidth = 550; + } + else + { + return FALSE; + } + } + return TRUE; + case TreeNewSortChanged: + { + TreeNew_GetSort(hwnd, &ServiceTreeListSortColumn, &ServiceTreeListSortOrder); + // Force a rebuild to sort the items. + TreeNew_NodesStructured(hwnd); + } + return TRUE; + case TreeNewKeyDown: + { + PPH_TREENEW_KEY_EVENT keyEvent = Parameter1; + + switch (keyEvent->VirtualKey) + { + case 'C': + if (GetKeyState(VK_CONTROL) < 0) + SendMessage(PhMainWndHandle, WM_COMMAND, ID_SERVICE_COPY, 0); + break; + case 'A': + if (GetKeyState(VK_CONTROL) < 0) + TreeNew_SelectRange(ServiceTreeListHandle, 0, -1); + break; + case VK_DELETE: + SendMessage(PhMainWndHandle, WM_COMMAND, ID_SERVICE_DELETE, 0); + break; + case VK_RETURN: + if (GetKeyState(VK_CONTROL) >= 0) + SendMessage(PhMainWndHandle, WM_COMMAND, ID_SERVICE_PROPERTIES, 0); + else + SendMessage(PhMainWndHandle, WM_COMMAND, ID_SERVICE_OPENFILELOCATION, 0); + break; + } + } + return TRUE; + case TreeNewHeaderRightClick: + { + PH_TN_COLUMN_MENU_DATA data; + + data.TreeNewHandle = hwnd; + data.MouseEvent = Parameter1; + data.DefaultSortColumn = 0; + data.DefaultSortOrder = AscendingSortOrder; + PhInitializeTreeNewColumnMenu(&data); + + data.Selection = PhShowEMenu(data.Menu, hwnd, PH_EMENU_SHOW_LEFTRIGHT, + PH_ALIGN_LEFT | PH_ALIGN_TOP, data.MouseEvent->ScreenLocation.x, data.MouseEvent->ScreenLocation.y); + PhHandleTreeNewColumnMenu(&data); + PhDeleteTreeNewColumnMenu(&data); + } + return TRUE; + case TreeNewLeftDoubleClick: + { + SendMessage(PhMainWndHandle, WM_COMMAND, ID_SERVICE_PROPERTIES, 0); + } + return TRUE; + case TreeNewContextMenu: + { + PPH_TREENEW_CONTEXT_MENU contextMenu = Parameter1; + + PhShowServiceContextMenu(contextMenu); + } + return TRUE; + } + + return FALSE; +} + +PPH_SERVICE_ITEM PhGetSelectedServiceItem( + VOID + ) +{ + PPH_SERVICE_ITEM serviceItem = NULL; + ULONG i; + + for (i = 0; i < ServiceNodeList->Count; i++) + { + PPH_SERVICE_NODE node = ServiceNodeList->Items[i]; + + if (node->Node.Selected) + { + serviceItem = node->ServiceItem; + break; + } + } + + return serviceItem; +} + +VOID PhGetSelectedServiceItems( + _Out_ PPH_SERVICE_ITEM **Services, + _Out_ PULONG NumberOfServices + ) +{ + PH_ARRAY array; + ULONG i; + + PhInitializeArray(&array, sizeof(PVOID), 2); + + for (i = 0; i < ServiceNodeList->Count; i++) + { + PPH_SERVICE_NODE node = ServiceNodeList->Items[i]; + + if (node->Node.Selected) + PhAddItemArray(&array, &node->ServiceItem); + } + + *NumberOfServices = (ULONG)array.Count; + *Services = PhFinalArrayItems(&array); +} + +VOID PhDeselectAllServiceNodes( + VOID + ) +{ + TreeNew_DeselectRange(ServiceTreeListHandle, 0, -1); +} + +VOID PhSelectAndEnsureVisibleServiceNode( + _In_ PPH_SERVICE_NODE ServiceNode + ) +{ + PhDeselectAllServiceNodes(); + + if (!ServiceNode->Node.Visible) + return; + + TreeNew_SetFocusNode(ServiceTreeListHandle, &ServiceNode->Node); + TreeNew_SetMarkNode(ServiceTreeListHandle, &ServiceNode->Node); + TreeNew_SelectRange(ServiceTreeListHandle, ServiceNode->Node.Index, ServiceNode->Node.Index); + TreeNew_EnsureVisible(ServiceTreeListHandle, &ServiceNode->Node); +} + +VOID PhCopyServiceList( + VOID + ) +{ + PPH_STRING text; + + text = PhGetTreeNewText(ServiceTreeListHandle, 0); + PhSetClipboardString(ServiceTreeListHandle, &text->sr); + PhDereferenceObject(text); +} + +VOID PhWriteServiceList( + _Inout_ PPH_FILE_STREAM FileStream, + _In_ ULONG Mode + ) +{ + PPH_LIST lines; + ULONG i; + + lines = PhGetGenericTreeNewLines(ServiceTreeListHandle, Mode); + + for (i = 0; i < lines->Count; i++) + { + PPH_STRING line; + + line = lines->Items[i]; + PhWriteStringAsUtf8FileStream(FileStream, &line->sr); + PhDereferenceObject(line); + PhWriteStringAsUtf8FileStream2(FileStream, L"\r\n"); + } + + PhDereferenceObject(lines); +} diff --git a/ProcessHacker/srvprp.c b/ProcessHacker/srvprp.c index fe193f2dd90a..658efd1f439c 100644 --- a/ProcessHacker/srvprp.c +++ b/ProcessHacker/srvprp.c @@ -1,574 +1,574 @@ -/* - * Process Hacker - - * service properties - * - * Copyright (C) 2010-2015 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include - -#include - -#include -#include - -#include -#include -#include -#include - -typedef struct _SERVICE_PROPERTIES_CONTEXT -{ - PPH_SERVICE_ITEM ServiceItem; - BOOLEAN Ready; - BOOLEAN Dirty; - - BOOLEAN OldDelayedStart; -} SERVICE_PROPERTIES_CONTEXT, *PSERVICE_PROPERTIES_CONTEXT; - -INT_PTR CALLBACK PhpServiceGeneralDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -static NTSTATUS PhpOpenService( - _Out_ PHANDLE Handle, - _In_ ACCESS_MASK DesiredAccess, - _In_opt_ PVOID Context - ) -{ - SC_HANDLE serviceHandle; - - if (!(serviceHandle = PhOpenService( - ((PPH_SERVICE_ITEM)Context)->Name->Buffer, - DesiredAccess - ))) - return PhGetLastWin32ErrorAsNtStatus(); - - *Handle = serviceHandle; - - return STATUS_SUCCESS; -} - -static _Callback_ NTSTATUS PhpSetServiceSecurity( - _In_ PSECURITY_DESCRIPTOR SecurityDescriptor, - _In_ SECURITY_INFORMATION SecurityInformation, - _In_opt_ PVOID Context - ) -{ - NTSTATUS status; - PPH_STD_OBJECT_SECURITY stdObjectSecurity; - - stdObjectSecurity = (PPH_STD_OBJECT_SECURITY)Context; - - status = PhStdSetObjectSecurity(SecurityDescriptor, SecurityInformation, Context); - - if ((status == STATUS_ACCESS_DENIED || status == NTSTATUS_FROM_WIN32(ERROR_ACCESS_DENIED)) && !PhGetOwnTokenAttributes().Elevated) - { - // Elevate using phsvc. - if (PhUiConnectToPhSvc(NULL, FALSE)) - { - status = PhSvcCallSetServiceSecurity( - ((PPH_SERVICE_ITEM)stdObjectSecurity->Context)->Name->Buffer, - SecurityInformation, - SecurityDescriptor - ); - PhUiDisconnectFromPhSvc(); - } - } - - return status; -} - -VOID PhShowServiceProperties( - _In_ HWND ParentWindowHandle, - _In_ PPH_SERVICE_ITEM ServiceItem - ) -{ - PROPSHEETHEADER propSheetHeader = { sizeof(propSheetHeader) }; - PROPSHEETPAGE propSheetPage; - HPROPSHEETPAGE pages[32]; - SERVICE_PROPERTIES_CONTEXT context; - PH_STD_OBJECT_SECURITY stdObjectSecurity; - PPH_ACCESS_ENTRY accessEntries; - ULONG numberOfAccessEntries; - - propSheetHeader.dwFlags = - PSH_NOAPPLYNOW | - PSH_NOCONTEXTHELP | - PSH_PROPTITLE; - propSheetHeader.hwndParent = ParentWindowHandle; - propSheetHeader.pszCaption = ServiceItem->Name->Buffer; - propSheetHeader.nPages = 0; - propSheetHeader.nStartPage = 0; - propSheetHeader.phpage = pages; - - // General - - memset(&context, 0, sizeof(SERVICE_PROPERTIES_CONTEXT)); - context.ServiceItem = ServiceItem; - context.Ready = FALSE; - context.Dirty = FALSE; - - memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); - propSheetPage.dwSize = sizeof(PROPSHEETPAGE); - propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_SRVGENERAL); - propSheetPage.pfnDlgProc = PhpServiceGeneralDlgProc; - propSheetPage.lParam = (LPARAM)&context; - pages[propSheetHeader.nPages++] = CreatePropertySheetPage(&propSheetPage); - - // Security - - stdObjectSecurity.OpenObject = PhpOpenService; - stdObjectSecurity.ObjectType = L"Service"; - stdObjectSecurity.Context = ServiceItem; - - if (PhGetAccessEntries(L"Service", &accessEntries, &numberOfAccessEntries)) - { - pages[propSheetHeader.nPages++] = PhCreateSecurityPage( - ServiceItem->Name->Buffer, - PhStdGetObjectSecurity, - PhpSetServiceSecurity, - &stdObjectSecurity, - accessEntries, - numberOfAccessEntries - ); - PhFree(accessEntries); - } - - if (PhPluginsEnabled) - { - PH_PLUGIN_OBJECT_PROPERTIES objectProperties; - - objectProperties.Parameter = ServiceItem; - objectProperties.NumberOfPages = propSheetHeader.nPages; - objectProperties.MaximumNumberOfPages = sizeof(pages) / sizeof(HPROPSHEETPAGE); - objectProperties.Pages = pages; - - PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackServicePropertiesInitializing), &objectProperties); - - propSheetHeader.nPages = objectProperties.NumberOfPages; - } - - PhModalPropertySheet(&propSheetHeader); -} - -static VOID PhpRefreshControls( - _In_ HWND hwndDlg - ) -{ - if ( - WindowsVersion >= WINDOWS_VISTA && - PhEqualString2(PhaGetDlgItemText(hwndDlg, IDC_STARTTYPE), L"Auto start", FALSE) - ) - { - EnableWindow(GetDlgItem(hwndDlg, IDC_DELAYEDSTART), TRUE); - } - else - { - EnableWindow(GetDlgItem(hwndDlg, IDC_DELAYEDSTART), FALSE); - } -} - -INT_PTR CALLBACK PhpServiceGeneralDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - switch (uMsg) - { - case WM_INITDIALOG: - { - LPPROPSHEETPAGE propSheetPage = (LPPROPSHEETPAGE)lParam; - PSERVICE_PROPERTIES_CONTEXT context = (PSERVICE_PROPERTIES_CONTEXT)propSheetPage->lParam; - PPH_SERVICE_ITEM serviceItem = context->ServiceItem; - SC_HANDLE serviceHandle; - ULONG startType; - ULONG errorControl; - PPH_STRING serviceDll; - - // HACK - PhCenterWindow(GetParent(hwndDlg), GetParent(GetParent(hwndDlg))); - - SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)context); - - PhAddComboBoxStrings(GetDlgItem(hwndDlg, IDC_TYPE), PhServiceTypeStrings, - sizeof(PhServiceTypeStrings) / sizeof(WCHAR *)); - PhAddComboBoxStrings(GetDlgItem(hwndDlg, IDC_STARTTYPE), PhServiceStartTypeStrings, - sizeof(PhServiceStartTypeStrings) / sizeof(WCHAR *)); - PhAddComboBoxStrings(GetDlgItem(hwndDlg, IDC_ERRORCONTROL), PhServiceErrorControlStrings, - sizeof(PhServiceErrorControlStrings) / sizeof(WCHAR *)); - - SetDlgItemText(hwndDlg, IDC_DESCRIPTION, serviceItem->DisplayName->Buffer); - PhSelectComboBoxString(GetDlgItem(hwndDlg, IDC_TYPE), - PhGetServiceTypeString(serviceItem->Type), FALSE); - - startType = serviceItem->StartType; - errorControl = serviceItem->ErrorControl; - serviceHandle = PhOpenService(serviceItem->Name->Buffer, SERVICE_QUERY_CONFIG); - - if (serviceHandle) - { - LPQUERY_SERVICE_CONFIG config; - PPH_STRING description; - BOOLEAN delayedStart; - - if (config = PhGetServiceConfig(serviceHandle)) - { - SetDlgItemText(hwndDlg, IDC_GROUP, config->lpLoadOrderGroup); - SetDlgItemText(hwndDlg, IDC_BINARYPATH, config->lpBinaryPathName); - SetDlgItemText(hwndDlg, IDC_USERACCOUNT, config->lpServiceStartName); - - if (startType != config->dwStartType || errorControl != config->dwErrorControl) - { - startType = config->dwStartType; - errorControl = config->dwErrorControl; - PhMarkNeedsConfigUpdateServiceItem(serviceItem); - } - - PhFree(config); - } - - if (description = PhGetServiceDescription(serviceHandle)) - { - SetDlgItemText(hwndDlg, IDC_DESCRIPTION, description->Buffer); - PhDereferenceObject(description); - } - - if ( - WindowsVersion >= WINDOWS_VISTA && - PhGetServiceDelayedAutoStart(serviceHandle, &delayedStart) - ) - { - context->OldDelayedStart = delayedStart; - - if (delayedStart) - Button_SetCheck(GetDlgItem(hwndDlg, IDC_DELAYEDSTART), BST_CHECKED); - } - - CloseServiceHandle(serviceHandle); - } - - PhSelectComboBoxString(GetDlgItem(hwndDlg, IDC_STARTTYPE), - PhGetServiceStartTypeString(startType), FALSE); - PhSelectComboBoxString(GetDlgItem(hwndDlg, IDC_ERRORCONTROL), - PhGetServiceErrorControlString(errorControl), FALSE); - - SetDlgItemText(hwndDlg, IDC_PASSWORD, L"password"); - Button_SetCheck(GetDlgItem(hwndDlg, IDC_PASSWORDCHECK), BST_UNCHECKED); - - if (NT_SUCCESS(PhGetServiceDllParameter(&serviceItem->Name->sr, &serviceDll))) - { - SetDlgItemText(hwndDlg, IDC_SERVICEDLL, serviceDll->Buffer); - PhDereferenceObject(serviceDll); - } - else - { - SetDlgItemText(hwndDlg, IDC_SERVICEDLL, L"N/A"); - } - - PhpRefreshControls(hwndDlg); - - context->Ready = TRUE; - } - break; - case WM_DESTROY: - { - RemoveProp(hwndDlg, PhMakeContextAtom()); - } - break; - case WM_COMMAND: - { - PSERVICE_PROPERTIES_CONTEXT context = - (PSERVICE_PROPERTIES_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom()); - - switch (LOWORD(wParam)) - { - case IDCANCEL: - { - // Workaround for property sheet + multiline edit: http://support.microsoft.com/kb/130765 - - SendMessage(GetParent(hwndDlg), uMsg, wParam, lParam); - } - break; - case IDC_PASSWORD: - { - if (HIWORD(wParam) == EN_CHANGE) - { - Button_SetCheck(GetDlgItem(hwndDlg, IDC_PASSWORDCHECK), BST_CHECKED); - } - } - break; - case IDC_DELAYEDSTART: - { - context->Dirty = TRUE; - } - break; - case IDC_BROWSE: - { - static PH_FILETYPE_FILTER filters[] = - { - { L"Executable files (*.exe;*.sys)", L"*.exe;*.sys" }, - { L"All files (*.*)", L"*.*" } - }; - PVOID fileDialog; - PPH_STRING commandLine; - PPH_STRING fileName; - - fileDialog = PhCreateOpenFileDialog(); - PhSetFileDialogFilter(fileDialog, filters, sizeof(filters) / sizeof(PH_FILETYPE_FILTER)); - - commandLine = PhaGetDlgItemText(hwndDlg, IDC_BINARYPATH); - - if (context->ServiceItem->Type & SERVICE_WIN32) - { - PH_STRINGREF dummyFileName; - PH_STRINGREF dummyArguments; - - if (!PhParseCommandLineFuzzy(&commandLine->sr, &dummyFileName, &dummyArguments, &fileName)) - fileName = NULL; - - if (!fileName) - PhSwapReference(&fileName, commandLine); - } - else - { - fileName = PhGetFileName(commandLine); - } - - PhSetFileDialogFileName(fileDialog, fileName->Buffer); - PhDereferenceObject(fileName); - - if (PhShowFileDialog(hwndDlg, fileDialog)) - { - fileName = PhGetFileDialogFileName(fileDialog); - SetDlgItemText(hwndDlg, IDC_BINARYPATH, fileName->Buffer); - PhDereferenceObject(fileName); - } - - PhFreeFileDialog(fileDialog); - } - break; - } - - switch (HIWORD(wParam)) - { - case EN_CHANGE: - case CBN_SELCHANGE: - { - PhpRefreshControls(hwndDlg); - - if (context->Ready) - context->Dirty = TRUE; - } - break; - } - } - break; - case WM_NOTIFY: - { - LPNMHDR header = (LPNMHDR)lParam; - - switch (header->code) - { - case PSN_QUERYINITIALFOCUS: - { - SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, (LONG_PTR)GetDlgItem(hwndDlg, IDC_STARTTYPE)); - } - return TRUE; - case PSN_KILLACTIVE: - { - SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, FALSE); - } - return TRUE; - case PSN_APPLY: - { - NTSTATUS status; - PSERVICE_PROPERTIES_CONTEXT context = - (PSERVICE_PROPERTIES_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom()); - PPH_SERVICE_ITEM serviceItem = context->ServiceItem; - SC_HANDLE serviceHandle; - PPH_STRING newServiceTypeString; - PPH_STRING newServiceStartTypeString; - PPH_STRING newServiceErrorControlString; - ULONG newServiceType; - ULONG newServiceStartType; - ULONG newServiceErrorControl; - PPH_STRING newServiceGroup = NULL; - PPH_STRING newServiceBinaryPath = NULL; - PPH_STRING newServiceUserAccount = NULL; - PPH_STRING newServicePassword = NULL; - - SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_NOERROR); - - if (!context->Dirty) - { - return TRUE; - } - - newServiceTypeString = PH_AUTO(PhGetWindowText(GetDlgItem(hwndDlg, IDC_TYPE))); - newServiceStartTypeString = PH_AUTO(PhGetWindowText(GetDlgItem(hwndDlg, IDC_STARTTYPE))); - newServiceErrorControlString = PH_AUTO(PhGetWindowText(GetDlgItem(hwndDlg, IDC_ERRORCONTROL))); - newServiceType = PhGetServiceTypeInteger(newServiceTypeString->Buffer); - newServiceStartType = PhGetServiceStartTypeInteger(newServiceStartTypeString->Buffer); - newServiceErrorControl = PhGetServiceErrorControlInteger(newServiceErrorControlString->Buffer); - - if (GetWindowTextLength(GetDlgItem(hwndDlg, IDC_GROUP))) - newServiceGroup = PH_AUTO(PhGetWindowText(GetDlgItem(hwndDlg, IDC_GROUP))); - if (GetWindowTextLength(GetDlgItem(hwndDlg, IDC_BINARYPATH))) - newServiceBinaryPath = PH_AUTO(PhGetWindowText(GetDlgItem(hwndDlg, IDC_BINARYPATH))); - if (GetWindowTextLength(GetDlgItem(hwndDlg, IDC_USERACCOUNT))) - newServiceUserAccount = PH_AUTO(PhGetWindowText(GetDlgItem(hwndDlg, IDC_USERACCOUNT))); - - if (Button_GetCheck(GetDlgItem(hwndDlg, IDC_PASSWORDCHECK)) == BST_CHECKED) - newServicePassword = PhGetWindowText(GetDlgItem(hwndDlg, IDC_PASSWORD)); - - serviceHandle = PhOpenService(serviceItem->Name->Buffer, SERVICE_CHANGE_CONFIG); - - if (serviceHandle) - { - if (ChangeServiceConfig( - serviceHandle, - newServiceType, - newServiceStartType, - newServiceErrorControl, - PhGetString(newServiceBinaryPath), - PhGetString(newServiceGroup), - NULL, - NULL, - PhGetString(newServiceUserAccount), - PhGetString(newServicePassword), - NULL - )) - { - if (WindowsVersion >= WINDOWS_VISTA) - { - BOOLEAN newDelayedStart; - - newDelayedStart = Button_GetCheck(GetDlgItem(hwndDlg, IDC_DELAYEDSTART)) == BST_CHECKED; - - if (newDelayedStart != context->OldDelayedStart) - { - PhSetServiceDelayedAutoStart(serviceHandle, newDelayedStart); - } - } - - PhMarkNeedsConfigUpdateServiceItem(serviceItem); - - CloseServiceHandle(serviceHandle); - } - else - { - CloseServiceHandle(serviceHandle); - goto ErrorCase; - } - } - else - { - if (GetLastError() == ERROR_ACCESS_DENIED && !PhGetOwnTokenAttributes().Elevated) - { - // Elevate using phsvc. - if (PhUiConnectToPhSvc(hwndDlg, FALSE)) - { - if (NT_SUCCESS(status = PhSvcCallChangeServiceConfig( - serviceItem->Name->Buffer, - newServiceType, - newServiceStartType, - newServiceErrorControl, - PhGetString(newServiceBinaryPath), - PhGetString(newServiceGroup), - NULL, - NULL, - PhGetString(newServiceUserAccount), - PhGetString(newServicePassword), - NULL - ))) - { - if (WindowsVersion >= WINDOWS_VISTA) - { - BOOLEAN newDelayedStart; - - newDelayedStart = Button_GetCheck(GetDlgItem(hwndDlg, IDC_DELAYEDSTART)) == BST_CHECKED; - - if (newDelayedStart != context->OldDelayedStart) - { - SERVICE_DELAYED_AUTO_START_INFO info; - - info.fDelayedAutostart = newDelayedStart; - PhSvcCallChangeServiceConfig2( - serviceItem->Name->Buffer, - SERVICE_CONFIG_DELAYED_AUTO_START_INFO, - &info - ); - } - } - - PhMarkNeedsConfigUpdateServiceItem(serviceItem); - } - - PhUiDisconnectFromPhSvc(); - - if (!NT_SUCCESS(status)) - { - SetLastError(PhNtStatusToDosError(status)); - goto ErrorCase; - } - } - else - { - // User cancelled elevation. - SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_INVALID); - } - } - else - { - goto ErrorCase; - } - } - - goto Cleanup; -ErrorCase: - if (PhShowMessage( - hwndDlg, - MB_ICONERROR | MB_RETRYCANCEL, - L"Unable to change service configuration: %s", - PH_AUTO_T(PH_STRING, PhGetWin32Message(GetLastError()))->Buffer - ) == IDRETRY) - { - SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_INVALID); - } - -Cleanup: - if (newServicePassword) - { - RtlSecureZeroMemory(newServicePassword->Buffer, newServicePassword->Length); - PhDereferenceObject(newServicePassword); - } - } - return TRUE; - } - } - break; - } - - return FALSE; -} +/* + * Process Hacker - + * service properties + * + * Copyright (C) 2010-2015 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include + +#include + +#include +#include + +#include +#include +#include +#include + +typedef struct _SERVICE_PROPERTIES_CONTEXT +{ + PPH_SERVICE_ITEM ServiceItem; + BOOLEAN Ready; + BOOLEAN Dirty; + + BOOLEAN OldDelayedStart; +} SERVICE_PROPERTIES_CONTEXT, *PSERVICE_PROPERTIES_CONTEXT; + +INT_PTR CALLBACK PhpServiceGeneralDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +static NTSTATUS PhpOpenService( + _Out_ PHANDLE Handle, + _In_ ACCESS_MASK DesiredAccess, + _In_opt_ PVOID Context + ) +{ + SC_HANDLE serviceHandle; + + if (!(serviceHandle = PhOpenService( + ((PPH_SERVICE_ITEM)Context)->Name->Buffer, + DesiredAccess + ))) + return PhGetLastWin32ErrorAsNtStatus(); + + *Handle = serviceHandle; + + return STATUS_SUCCESS; +} + +static _Callback_ NTSTATUS PhpSetServiceSecurity( + _In_ PSECURITY_DESCRIPTOR SecurityDescriptor, + _In_ SECURITY_INFORMATION SecurityInformation, + _In_opt_ PVOID Context + ) +{ + NTSTATUS status; + PPH_STD_OBJECT_SECURITY stdObjectSecurity; + + stdObjectSecurity = (PPH_STD_OBJECT_SECURITY)Context; + + status = PhStdSetObjectSecurity(SecurityDescriptor, SecurityInformation, Context); + + if ((status == STATUS_ACCESS_DENIED || status == NTSTATUS_FROM_WIN32(ERROR_ACCESS_DENIED)) && !PhGetOwnTokenAttributes().Elevated) + { + // Elevate using phsvc. + if (PhUiConnectToPhSvc(NULL, FALSE)) + { + status = PhSvcCallSetServiceSecurity( + ((PPH_SERVICE_ITEM)stdObjectSecurity->Context)->Name->Buffer, + SecurityInformation, + SecurityDescriptor + ); + PhUiDisconnectFromPhSvc(); + } + } + + return status; +} + +VOID PhShowServiceProperties( + _In_ HWND ParentWindowHandle, + _In_ PPH_SERVICE_ITEM ServiceItem + ) +{ + PROPSHEETHEADER propSheetHeader = { sizeof(propSheetHeader) }; + PROPSHEETPAGE propSheetPage; + HPROPSHEETPAGE pages[32]; + SERVICE_PROPERTIES_CONTEXT context; + PH_STD_OBJECT_SECURITY stdObjectSecurity; + PPH_ACCESS_ENTRY accessEntries; + ULONG numberOfAccessEntries; + + propSheetHeader.dwFlags = + PSH_NOAPPLYNOW | + PSH_NOCONTEXTHELP | + PSH_PROPTITLE; + propSheetHeader.hwndParent = ParentWindowHandle; + propSheetHeader.pszCaption = ServiceItem->Name->Buffer; + propSheetHeader.nPages = 0; + propSheetHeader.nStartPage = 0; + propSheetHeader.phpage = pages; + + // General + + memset(&context, 0, sizeof(SERVICE_PROPERTIES_CONTEXT)); + context.ServiceItem = ServiceItem; + context.Ready = FALSE; + context.Dirty = FALSE; + + memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); + propSheetPage.dwSize = sizeof(PROPSHEETPAGE); + propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_SRVGENERAL); + propSheetPage.pfnDlgProc = PhpServiceGeneralDlgProc; + propSheetPage.lParam = (LPARAM)&context; + pages[propSheetHeader.nPages++] = CreatePropertySheetPage(&propSheetPage); + + // Security + + stdObjectSecurity.OpenObject = PhpOpenService; + stdObjectSecurity.ObjectType = L"Service"; + stdObjectSecurity.Context = ServiceItem; + + if (PhGetAccessEntries(L"Service", &accessEntries, &numberOfAccessEntries)) + { + pages[propSheetHeader.nPages++] = PhCreateSecurityPage( + ServiceItem->Name->Buffer, + PhStdGetObjectSecurity, + PhpSetServiceSecurity, + &stdObjectSecurity, + accessEntries, + numberOfAccessEntries + ); + PhFree(accessEntries); + } + + if (PhPluginsEnabled) + { + PH_PLUGIN_OBJECT_PROPERTIES objectProperties; + + objectProperties.Parameter = ServiceItem; + objectProperties.NumberOfPages = propSheetHeader.nPages; + objectProperties.MaximumNumberOfPages = sizeof(pages) / sizeof(HPROPSHEETPAGE); + objectProperties.Pages = pages; + + PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackServicePropertiesInitializing), &objectProperties); + + propSheetHeader.nPages = objectProperties.NumberOfPages; + } + + PhModalPropertySheet(&propSheetHeader); +} + +static VOID PhpRefreshControls( + _In_ HWND hwndDlg + ) +{ + if ( + WindowsVersion >= WINDOWS_VISTA && + PhEqualString2(PhaGetDlgItemText(hwndDlg, IDC_STARTTYPE), L"Auto start", FALSE) + ) + { + EnableWindow(GetDlgItem(hwndDlg, IDC_DELAYEDSTART), TRUE); + } + else + { + EnableWindow(GetDlgItem(hwndDlg, IDC_DELAYEDSTART), FALSE); + } +} + +INT_PTR CALLBACK PhpServiceGeneralDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + switch (uMsg) + { + case WM_INITDIALOG: + { + LPPROPSHEETPAGE propSheetPage = (LPPROPSHEETPAGE)lParam; + PSERVICE_PROPERTIES_CONTEXT context = (PSERVICE_PROPERTIES_CONTEXT)propSheetPage->lParam; + PPH_SERVICE_ITEM serviceItem = context->ServiceItem; + SC_HANDLE serviceHandle; + ULONG startType; + ULONG errorControl; + PPH_STRING serviceDll; + + // HACK + PhCenterWindow(GetParent(hwndDlg), GetParent(GetParent(hwndDlg))); + + SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)context); + + PhAddComboBoxStrings(GetDlgItem(hwndDlg, IDC_TYPE), PhServiceTypeStrings, + sizeof(PhServiceTypeStrings) / sizeof(WCHAR *)); + PhAddComboBoxStrings(GetDlgItem(hwndDlg, IDC_STARTTYPE), PhServiceStartTypeStrings, + sizeof(PhServiceStartTypeStrings) / sizeof(WCHAR *)); + PhAddComboBoxStrings(GetDlgItem(hwndDlg, IDC_ERRORCONTROL), PhServiceErrorControlStrings, + sizeof(PhServiceErrorControlStrings) / sizeof(WCHAR *)); + + SetDlgItemText(hwndDlg, IDC_DESCRIPTION, serviceItem->DisplayName->Buffer); + PhSelectComboBoxString(GetDlgItem(hwndDlg, IDC_TYPE), + PhGetServiceTypeString(serviceItem->Type), FALSE); + + startType = serviceItem->StartType; + errorControl = serviceItem->ErrorControl; + serviceHandle = PhOpenService(serviceItem->Name->Buffer, SERVICE_QUERY_CONFIG); + + if (serviceHandle) + { + LPQUERY_SERVICE_CONFIG config; + PPH_STRING description; + BOOLEAN delayedStart; + + if (config = PhGetServiceConfig(serviceHandle)) + { + SetDlgItemText(hwndDlg, IDC_GROUP, config->lpLoadOrderGroup); + SetDlgItemText(hwndDlg, IDC_BINARYPATH, config->lpBinaryPathName); + SetDlgItemText(hwndDlg, IDC_USERACCOUNT, config->lpServiceStartName); + + if (startType != config->dwStartType || errorControl != config->dwErrorControl) + { + startType = config->dwStartType; + errorControl = config->dwErrorControl; + PhMarkNeedsConfigUpdateServiceItem(serviceItem); + } + + PhFree(config); + } + + if (description = PhGetServiceDescription(serviceHandle)) + { + SetDlgItemText(hwndDlg, IDC_DESCRIPTION, description->Buffer); + PhDereferenceObject(description); + } + + if ( + WindowsVersion >= WINDOWS_VISTA && + PhGetServiceDelayedAutoStart(serviceHandle, &delayedStart) + ) + { + context->OldDelayedStart = delayedStart; + + if (delayedStart) + Button_SetCheck(GetDlgItem(hwndDlg, IDC_DELAYEDSTART), BST_CHECKED); + } + + CloseServiceHandle(serviceHandle); + } + + PhSelectComboBoxString(GetDlgItem(hwndDlg, IDC_STARTTYPE), + PhGetServiceStartTypeString(startType), FALSE); + PhSelectComboBoxString(GetDlgItem(hwndDlg, IDC_ERRORCONTROL), + PhGetServiceErrorControlString(errorControl), FALSE); + + SetDlgItemText(hwndDlg, IDC_PASSWORD, L"password"); + Button_SetCheck(GetDlgItem(hwndDlg, IDC_PASSWORDCHECK), BST_UNCHECKED); + + if (NT_SUCCESS(PhGetServiceDllParameter(&serviceItem->Name->sr, &serviceDll))) + { + SetDlgItemText(hwndDlg, IDC_SERVICEDLL, serviceDll->Buffer); + PhDereferenceObject(serviceDll); + } + else + { + SetDlgItemText(hwndDlg, IDC_SERVICEDLL, L"N/A"); + } + + PhpRefreshControls(hwndDlg); + + context->Ready = TRUE; + } + break; + case WM_DESTROY: + { + RemoveProp(hwndDlg, PhMakeContextAtom()); + } + break; + case WM_COMMAND: + { + PSERVICE_PROPERTIES_CONTEXT context = + (PSERVICE_PROPERTIES_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom()); + + switch (LOWORD(wParam)) + { + case IDCANCEL: + { + // Workaround for property sheet + multiline edit: http://support.microsoft.com/kb/130765 + + SendMessage(GetParent(hwndDlg), uMsg, wParam, lParam); + } + break; + case IDC_PASSWORD: + { + if (HIWORD(wParam) == EN_CHANGE) + { + Button_SetCheck(GetDlgItem(hwndDlg, IDC_PASSWORDCHECK), BST_CHECKED); + } + } + break; + case IDC_DELAYEDSTART: + { + context->Dirty = TRUE; + } + break; + case IDC_BROWSE: + { + static PH_FILETYPE_FILTER filters[] = + { + { L"Executable files (*.exe;*.sys)", L"*.exe;*.sys" }, + { L"All files (*.*)", L"*.*" } + }; + PVOID fileDialog; + PPH_STRING commandLine; + PPH_STRING fileName; + + fileDialog = PhCreateOpenFileDialog(); + PhSetFileDialogFilter(fileDialog, filters, sizeof(filters) / sizeof(PH_FILETYPE_FILTER)); + + commandLine = PhaGetDlgItemText(hwndDlg, IDC_BINARYPATH); + + if (context->ServiceItem->Type & SERVICE_WIN32) + { + PH_STRINGREF dummyFileName; + PH_STRINGREF dummyArguments; + + if (!PhParseCommandLineFuzzy(&commandLine->sr, &dummyFileName, &dummyArguments, &fileName)) + fileName = NULL; + + if (!fileName) + PhSwapReference(&fileName, commandLine); + } + else + { + fileName = PhGetFileName(commandLine); + } + + PhSetFileDialogFileName(fileDialog, fileName->Buffer); + PhDereferenceObject(fileName); + + if (PhShowFileDialog(hwndDlg, fileDialog)) + { + fileName = PhGetFileDialogFileName(fileDialog); + SetDlgItemText(hwndDlg, IDC_BINARYPATH, fileName->Buffer); + PhDereferenceObject(fileName); + } + + PhFreeFileDialog(fileDialog); + } + break; + } + + switch (HIWORD(wParam)) + { + case EN_CHANGE: + case CBN_SELCHANGE: + { + PhpRefreshControls(hwndDlg); + + if (context->Ready) + context->Dirty = TRUE; + } + break; + } + } + break; + case WM_NOTIFY: + { + LPNMHDR header = (LPNMHDR)lParam; + + switch (header->code) + { + case PSN_QUERYINITIALFOCUS: + { + SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, (LONG_PTR)GetDlgItem(hwndDlg, IDC_STARTTYPE)); + } + return TRUE; + case PSN_KILLACTIVE: + { + SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, FALSE); + } + return TRUE; + case PSN_APPLY: + { + NTSTATUS status; + PSERVICE_PROPERTIES_CONTEXT context = + (PSERVICE_PROPERTIES_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom()); + PPH_SERVICE_ITEM serviceItem = context->ServiceItem; + SC_HANDLE serviceHandle; + PPH_STRING newServiceTypeString; + PPH_STRING newServiceStartTypeString; + PPH_STRING newServiceErrorControlString; + ULONG newServiceType; + ULONG newServiceStartType; + ULONG newServiceErrorControl; + PPH_STRING newServiceGroup = NULL; + PPH_STRING newServiceBinaryPath = NULL; + PPH_STRING newServiceUserAccount = NULL; + PPH_STRING newServicePassword = NULL; + + SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_NOERROR); + + if (!context->Dirty) + { + return TRUE; + } + + newServiceTypeString = PH_AUTO(PhGetWindowText(GetDlgItem(hwndDlg, IDC_TYPE))); + newServiceStartTypeString = PH_AUTO(PhGetWindowText(GetDlgItem(hwndDlg, IDC_STARTTYPE))); + newServiceErrorControlString = PH_AUTO(PhGetWindowText(GetDlgItem(hwndDlg, IDC_ERRORCONTROL))); + newServiceType = PhGetServiceTypeInteger(newServiceTypeString->Buffer); + newServiceStartType = PhGetServiceStartTypeInteger(newServiceStartTypeString->Buffer); + newServiceErrorControl = PhGetServiceErrorControlInteger(newServiceErrorControlString->Buffer); + + if (GetWindowTextLength(GetDlgItem(hwndDlg, IDC_GROUP))) + newServiceGroup = PH_AUTO(PhGetWindowText(GetDlgItem(hwndDlg, IDC_GROUP))); + if (GetWindowTextLength(GetDlgItem(hwndDlg, IDC_BINARYPATH))) + newServiceBinaryPath = PH_AUTO(PhGetWindowText(GetDlgItem(hwndDlg, IDC_BINARYPATH))); + if (GetWindowTextLength(GetDlgItem(hwndDlg, IDC_USERACCOUNT))) + newServiceUserAccount = PH_AUTO(PhGetWindowText(GetDlgItem(hwndDlg, IDC_USERACCOUNT))); + + if (Button_GetCheck(GetDlgItem(hwndDlg, IDC_PASSWORDCHECK)) == BST_CHECKED) + newServicePassword = PhGetWindowText(GetDlgItem(hwndDlg, IDC_PASSWORD)); + + serviceHandle = PhOpenService(serviceItem->Name->Buffer, SERVICE_CHANGE_CONFIG); + + if (serviceHandle) + { + if (ChangeServiceConfig( + serviceHandle, + newServiceType, + newServiceStartType, + newServiceErrorControl, + PhGetString(newServiceBinaryPath), + PhGetString(newServiceGroup), + NULL, + NULL, + PhGetString(newServiceUserAccount), + PhGetString(newServicePassword), + NULL + )) + { + if (WindowsVersion >= WINDOWS_VISTA) + { + BOOLEAN newDelayedStart; + + newDelayedStart = Button_GetCheck(GetDlgItem(hwndDlg, IDC_DELAYEDSTART)) == BST_CHECKED; + + if (newDelayedStart != context->OldDelayedStart) + { + PhSetServiceDelayedAutoStart(serviceHandle, newDelayedStart); + } + } + + PhMarkNeedsConfigUpdateServiceItem(serviceItem); + + CloseServiceHandle(serviceHandle); + } + else + { + CloseServiceHandle(serviceHandle); + goto ErrorCase; + } + } + else + { + if (GetLastError() == ERROR_ACCESS_DENIED && !PhGetOwnTokenAttributes().Elevated) + { + // Elevate using phsvc. + if (PhUiConnectToPhSvc(hwndDlg, FALSE)) + { + if (NT_SUCCESS(status = PhSvcCallChangeServiceConfig( + serviceItem->Name->Buffer, + newServiceType, + newServiceStartType, + newServiceErrorControl, + PhGetString(newServiceBinaryPath), + PhGetString(newServiceGroup), + NULL, + NULL, + PhGetString(newServiceUserAccount), + PhGetString(newServicePassword), + NULL + ))) + { + if (WindowsVersion >= WINDOWS_VISTA) + { + BOOLEAN newDelayedStart; + + newDelayedStart = Button_GetCheck(GetDlgItem(hwndDlg, IDC_DELAYEDSTART)) == BST_CHECKED; + + if (newDelayedStart != context->OldDelayedStart) + { + SERVICE_DELAYED_AUTO_START_INFO info; + + info.fDelayedAutostart = newDelayedStart; + PhSvcCallChangeServiceConfig2( + serviceItem->Name->Buffer, + SERVICE_CONFIG_DELAYED_AUTO_START_INFO, + &info + ); + } + } + + PhMarkNeedsConfigUpdateServiceItem(serviceItem); + } + + PhUiDisconnectFromPhSvc(); + + if (!NT_SUCCESS(status)) + { + SetLastError(PhNtStatusToDosError(status)); + goto ErrorCase; + } + } + else + { + // User cancelled elevation. + SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_INVALID); + } + } + else + { + goto ErrorCase; + } + } + + goto Cleanup; +ErrorCase: + if (PhShowMessage( + hwndDlg, + MB_ICONERROR | MB_RETRYCANCEL, + L"Unable to change service configuration: %s", + PH_AUTO_T(PH_STRING, PhGetWin32Message(GetLastError()))->Buffer + ) == IDRETRY) + { + SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_INVALID); + } + +Cleanup: + if (newServicePassword) + { + RtlSecureZeroMemory(newServicePassword->Buffer, newServicePassword->Length); + PhDereferenceObject(newServicePassword); + } + } + return TRUE; + } + } + break; + } + + return FALSE; +} diff --git a/ProcessHacker/srvprv.c b/ProcessHacker/srvprv.c index c7f9d45bbc7f..18f258c7aa3d 100644 --- a/ProcessHacker/srvprv.c +++ b/ProcessHacker/srvprv.c @@ -1,1041 +1,1041 @@ -/* - * Process Hacker - - * service provider - * - * Copyright (C) 2009-2015 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include -#include - -#include -#include - -#include -#include - -typedef DWORD (WINAPI *_NotifyServiceStatusChangeW)( - _In_ SC_HANDLE hService, - _In_ DWORD dwNotifyMask, - _In_ PSERVICE_NOTIFYW pNotifyBuffer - ); - -typedef struct _PHP_SERVICE_NAME_ENTRY -{ - PH_HASH_ENTRY HashEntry; - PH_STRINGREF Name; - ENUM_SERVICE_STATUS_PROCESS *ServiceEntry; -} PHP_SERVICE_NAME_ENTRY, *PPHP_SERVICE_NAME_ENTRY; - -typedef enum _PHP_SERVICE_NOTIFY_STATE -{ - SnNone, - SnAdding, - SnRemoving, - SnNotify -} PHP_SERVICE_NOTIFY_STATE; - -typedef struct _PHP_SERVICE_NOTIFY_CONTEXT -{ - LIST_ENTRY ListEntry; - SC_HANDLE ServiceHandle; - PPH_STRING ServiceName; // Valid only when adding - BOOLEAN IsServiceManager; - PHP_SERVICE_NOTIFY_STATE State; - SERVICE_NOTIFY Buffer; -} PHP_SERVICE_NOTIFY_CONTEXT, *PPHP_SERVICE_NOTIFY_CONTEXT; - -VOID NTAPI PhpServiceItemDeleteProcedure( - _In_ PVOID Object, - _In_ ULONG Flags - ); - -BOOLEAN NTAPI PhpServiceHashtableEqualFunction( - _In_ PVOID Entry1, - _In_ PVOID Entry2 - ); - -ULONG NTAPI PhpServiceHashtableHashFunction( - _In_ PVOID Entry - ); - -VOID PhpAddProcessItemService( - _In_ PPH_PROCESS_ITEM ProcessItem, - _In_ PPH_SERVICE_ITEM ServiceItem - ); - -VOID PhpRemoveProcessItemService( - _In_ PPH_PROCESS_ITEM ProcessItem, - _In_ PPH_SERVICE_ITEM ServiceItem - ); - -VOID PhpInitializeServiceNonPoll( - VOID - ); - -PPH_OBJECT_TYPE PhServiceItemType; - -PPH_HASHTABLE PhServiceHashtable; -PH_QUEUED_LOCK PhServiceHashtableLock = PH_QUEUED_LOCK_INIT; - -PHAPPAPI PH_CALLBACK_DECLARE(PhServiceAddedEvent); -PHAPPAPI PH_CALLBACK_DECLARE(PhServiceModifiedEvent); -PHAPPAPI PH_CALLBACK_DECLARE(PhServiceRemovedEvent); -PHAPPAPI PH_CALLBACK_DECLARE(PhServicesUpdatedEvent); - -BOOLEAN PhEnableServiceNonPoll = FALSE; -static BOOLEAN PhpNonPollInitialized = FALSE; -static BOOLEAN PhpNonPollActive = FALSE; -static HANDLE PhpNonPollThreadHandle; -static ULONG PhpNonPollGate; -static _NotifyServiceStatusChangeW NotifyServiceStatusChangeW_I; -static HANDLE PhpNonPollEventHandle; -static PH_QUEUED_LOCK PhpNonPollServiceListLock = PH_QUEUED_LOCK_INIT; -static LIST_ENTRY PhpNonPollServiceListHead; -static LIST_ENTRY PhpNonPollServicePendingListHead; - -BOOLEAN PhServiceProviderInitialization( - VOID - ) -{ - PhServiceItemType = PhCreateObjectType(L"ServiceItem", 0, PhpServiceItemDeleteProcedure); - PhServiceHashtable = PhCreateHashtable( - sizeof(PPH_SERVICE_ITEM), - PhpServiceHashtableEqualFunction, - PhpServiceHashtableHashFunction, - 40 - ); - - return TRUE; -} - -PPH_SERVICE_ITEM PhCreateServiceItem( - _In_opt_ LPENUM_SERVICE_STATUS_PROCESS Information - ) -{ - PPH_SERVICE_ITEM serviceItem; - - serviceItem = PhCreateObject( - PhEmGetObjectSize(EmServiceItemType, sizeof(PH_SERVICE_ITEM)), - PhServiceItemType - ); - memset(serviceItem, 0, sizeof(PH_SERVICE_ITEM)); - - if (Information) - { - serviceItem->Name = PhCreateString(Information->lpServiceName); - serviceItem->Key = serviceItem->Name->sr; - serviceItem->DisplayName = PhCreateString(Information->lpDisplayName); - serviceItem->Type = Information->ServiceStatusProcess.dwServiceType; - serviceItem->State = Information->ServiceStatusProcess.dwCurrentState; - serviceItem->ControlsAccepted = Information->ServiceStatusProcess.dwControlsAccepted; - serviceItem->Flags = Information->ServiceStatusProcess.dwServiceFlags; - serviceItem->ProcessId = UlongToHandle(Information->ServiceStatusProcess.dwProcessId); - - if (serviceItem->ProcessId) - PhPrintUInt32(serviceItem->ProcessIdString, HandleToUlong(serviceItem->ProcessId)); - } - - PhEmCallObjectOperation(EmServiceItemType, serviceItem, EmObjectCreate); - - return serviceItem; -} - -VOID PhpServiceItemDeleteProcedure( - _In_ PVOID Object, - _In_ ULONG Flags - ) -{ - PPH_SERVICE_ITEM serviceItem = (PPH_SERVICE_ITEM)Object; - - PhEmCallObjectOperation(EmServiceItemType, serviceItem, EmObjectDelete); - - if (serviceItem->Name) PhDereferenceObject(serviceItem->Name); - if (serviceItem->DisplayName) PhDereferenceObject(serviceItem->DisplayName); -} - -BOOLEAN PhpServiceHashtableEqualFunction( - _In_ PVOID Entry1, - _In_ PVOID Entry2 - ) -{ - PPH_SERVICE_ITEM serviceItem1 = *(PPH_SERVICE_ITEM *)Entry1; - PPH_SERVICE_ITEM serviceItem2 = *(PPH_SERVICE_ITEM *)Entry2; - - return PhEqualStringRef(&serviceItem1->Key, &serviceItem2->Key, TRUE); -} - -ULONG PhpServiceHashtableHashFunction( - _In_ PVOID Entry - ) -{ - PPH_SERVICE_ITEM serviceItem = *(PPH_SERVICE_ITEM *)Entry; - - return PhHashStringRef(&serviceItem->Key, TRUE); -} - -PPH_SERVICE_ITEM PhpLookupServiceItem( - _In_ PPH_STRINGREF Name - ) -{ - PH_SERVICE_ITEM lookupServiceItem; - PPH_SERVICE_ITEM lookupServiceItemPtr = &lookupServiceItem; - PPH_SERVICE_ITEM *serviceItem; - - // Construct a temporary service item for the lookup. - lookupServiceItem.Key = *Name; - - serviceItem = (PPH_SERVICE_ITEM *)PhFindEntryHashtable( - PhServiceHashtable, - &lookupServiceItemPtr - ); - - if (serviceItem) - return *serviceItem; - else - return NULL; -} - -PPH_SERVICE_ITEM PhReferenceServiceItem( - _In_ PWSTR Name - ) -{ - PPH_SERVICE_ITEM serviceItem; - PH_STRINGREF key; - - PhInitializeStringRef(&key, Name); - - PhAcquireQueuedLockShared(&PhServiceHashtableLock); - - serviceItem = PhpLookupServiceItem(&key); - - if (serviceItem) - PhReferenceObject(serviceItem); - - PhReleaseQueuedLockShared(&PhServiceHashtableLock); - - return serviceItem; -} - -VOID PhMarkNeedsConfigUpdateServiceItem( - _In_ PPH_SERVICE_ITEM ServiceItem - ) -{ - ServiceItem->NeedsConfigUpdate = TRUE; - - if (PhEnableServiceNonPoll) - PhpNonPollGate = 1; -} - -VOID PhpRemoveServiceItem( - _In_ PPH_SERVICE_ITEM ServiceItem - ) -{ - PhRemoveEntryHashtable(PhServiceHashtable, &ServiceItem); - PhDereferenceObject(ServiceItem); -} - -PH_SERVICE_CHANGE PhGetServiceChange( - _In_ PPH_SERVICE_MODIFIED_DATA Data - ) -{ - if ( - ( - Data->OldService.State == SERVICE_STOPPED || - Data->OldService.State == SERVICE_START_PENDING - ) && - Data->Service->State == SERVICE_RUNNING - ) - { - return ServiceStarted; - } - - if ( - ( - Data->OldService.State == SERVICE_PAUSED || - Data->OldService.State == SERVICE_CONTINUE_PENDING - ) && - Data->Service->State == SERVICE_RUNNING - ) - { - return ServiceContinued; - } - - if ( - ( - Data->OldService.State == SERVICE_RUNNING || - Data->OldService.State == SERVICE_PAUSE_PENDING - ) && - Data->Service->State == SERVICE_PAUSED - ) - { - return ServicePaused; - } - - if ( - ( - Data->OldService.State == SERVICE_RUNNING || - Data->OldService.State == SERVICE_STOP_PENDING - ) && - Data->Service->State == SERVICE_STOPPED - ) - { - return ServiceStopped; - } - - return -1; -} - -VOID PhUpdateProcessItemServices( - _In_ PPH_PROCESS_ITEM ProcessItem - ) -{ - PH_HASHTABLE_ENUM_CONTEXT enumContext; - PPH_SERVICE_ITEM *serviceItem; - - // We don't need to lock as long as the service provider - // never runs concurrently with the process provider. This - // is currently true. - - PhBeginEnumHashtable(PhServiceHashtable, &enumContext); - - while (serviceItem = PhNextEnumHashtable(&enumContext)) - { - if ( - (*serviceItem)->PendingProcess && - (*serviceItem)->ProcessId == ProcessItem->ProcessId - ) - { - PhpAddProcessItemService(ProcessItem, *serviceItem); - } - } -} - -VOID PhpAddProcessItemService( - _In_ PPH_PROCESS_ITEM ProcessItem, - _In_ PPH_SERVICE_ITEM ServiceItem - ) -{ - PhAcquireQueuedLockExclusive(&ProcessItem->ServiceListLock); - - if (!ProcessItem->ServiceList) - ProcessItem->ServiceList = PhCreatePointerList(2); - - if (!PhFindItemPointerList(ProcessItem->ServiceList, ServiceItem)) - { - PhReferenceObject(ServiceItem); - PhAddItemPointerList(ProcessItem->ServiceList, ServiceItem); - } - - PhReleaseQueuedLockExclusive(&ProcessItem->ServiceListLock); - - ServiceItem->PendingProcess = FALSE; - ProcessItem->JustProcessed = 1; -} - -VOID PhpRemoveProcessItemService( - _In_ PPH_PROCESS_ITEM ProcessItem, - _In_ PPH_SERVICE_ITEM ServiceItem - ) -{ - HANDLE pointerHandle; - - if (!ProcessItem->ServiceList) - return; - - PhAcquireQueuedLockExclusive(&ProcessItem->ServiceListLock); - - if (pointerHandle = PhFindItemPointerList(ProcessItem->ServiceList, ServiceItem)) - { - PhRemoveItemPointerList(ProcessItem->ServiceList, pointerHandle); - PhDereferenceObject(ServiceItem); - } - - PhReleaseQueuedLockExclusive(&ProcessItem->ServiceListLock); - - ProcessItem->JustProcessed = 1; -} - -VOID PhpUpdateServiceItemConfig( - _In_ SC_HANDLE ScManagerHandle, - _In_ PPH_SERVICE_ITEM ServiceItem - ) -{ - SC_HANDLE serviceHandle; - - serviceHandle = OpenService(ScManagerHandle, ServiceItem->Name->Buffer, SERVICE_QUERY_CONFIG); - - if (serviceHandle) - { - LPQUERY_SERVICE_CONFIG config; - SERVICE_DELAYED_AUTO_START_INFO delayedAutoStartInfo; - ULONG returnLength; - PSERVICE_TRIGGER_INFO triggerInfo; - - config = PhGetServiceConfig(serviceHandle); - - if (config) - { - ServiceItem->StartType = config->dwStartType; - ServiceItem->ErrorControl = config->dwErrorControl; - - PhFree(config); - } - - if (QueryServiceConfig2( - serviceHandle, - SERVICE_CONFIG_DELAYED_AUTO_START_INFO, - (BYTE *)&delayedAutoStartInfo, - sizeof(SERVICE_DELAYED_AUTO_START_INFO), - &returnLength - )) - { - ServiceItem->DelayedStart = delayedAutoStartInfo.fDelayedAutostart; - } - else - { - ServiceItem->DelayedStart = FALSE; - } - - if (triggerInfo = PhQueryServiceVariableSize(serviceHandle, SERVICE_CONFIG_TRIGGER_INFO)) - { - ServiceItem->HasTriggers = triggerInfo->cTriggers != 0; - PhFree(triggerInfo); - } - else - { - ServiceItem->HasTriggers = FALSE; - } - - CloseServiceHandle(serviceHandle); - } -} - -static BOOLEAN PhpCompareServiceNameEntry( - _In_ PPHP_SERVICE_NAME_ENTRY Value1, - _In_ PPHP_SERVICE_NAME_ENTRY Value2 - ) -{ - return PhEqualStringRef(&Value1->Name, &Value2->Name, TRUE); -} - -static ULONG PhpHashServiceNameEntry( - _In_ PPHP_SERVICE_NAME_ENTRY Value - ) -{ - return PhHashStringRef(&Value->Name, TRUE); -} - -VOID PhServiceProviderUpdate( - _In_ PVOID Object - ) -{ - static SC_HANDLE scManagerHandle = NULL; - static ULONG runCount = 0; - - static PPH_HASH_ENTRY nameHashSet[256]; - static PPHP_SERVICE_NAME_ENTRY nameEntries = NULL; - static ULONG nameEntriesCount; - static ULONG nameEntriesAllocated = 0; - - LPENUM_SERVICE_STATUS_PROCESS services; - ULONG numberOfServices; - ULONG i; - PPH_HASH_ENTRY hashEntry; - - // We always execute the first run, and we only initialize non-polling after the first run. - if (PhEnableServiceNonPoll && runCount != 0) - { - if (!PhpNonPollInitialized) - { - if (WindowsVersion >= WINDOWS_VISTA) - { - PhpInitializeServiceNonPoll(); - } - - PhpNonPollInitialized = TRUE; - } - - if (PhpNonPollActive) - { - if (InterlockedExchange(&PhpNonPollGate, 0) == 0) - { - // Non-poll gate is closed; skip all processing. - goto UpdateEnd; - } - } - } - - if (!scManagerHandle) - { - scManagerHandle = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT | SC_MANAGER_ENUMERATE_SERVICE); - - if (!scManagerHandle) - return; - } - - services = PhEnumServices(scManagerHandle, 0, 0, &numberOfServices); - - if (!services) - return; - - // Build a hash set containing the service names. - - // This has caused a massive decrease in background CPU usage, and - // is certainly much better than the quadratic-time string comparisons - // we were doing before (in the "Look for dead services" section). - - nameEntriesCount = 0; - - if (nameEntriesAllocated < numberOfServices) - { - nameEntriesAllocated = numberOfServices + 32; - - if (nameEntries) PhFree(nameEntries); - nameEntries = PhAllocate(sizeof(PHP_SERVICE_NAME_ENTRY) * nameEntriesAllocated); - } - - PhInitializeHashSet(nameHashSet, PH_HASH_SET_SIZE(nameHashSet)); - - for (i = 0; i < numberOfServices; i++) - { - PPHP_SERVICE_NAME_ENTRY entry; - - entry = &nameEntries[nameEntriesCount++]; - PhInitializeStringRefLongHint(&entry->Name, services[i].lpServiceName); - entry->ServiceEntry = &services[i]; - PhAddEntryHashSet( - nameHashSet, - PH_HASH_SET_SIZE(nameHashSet), - &entry->HashEntry, - PhpHashServiceNameEntry(entry) - ); - } - - // Look for dead services. - { - PPH_LIST servicesToRemove = NULL; - PH_HASHTABLE_ENUM_CONTEXT enumContext; - PPH_SERVICE_ITEM *serviceItem; - - PhBeginEnumHashtable(PhServiceHashtable, &enumContext); - - while (serviceItem = PhNextEnumHashtable(&enumContext)) - { - BOOLEAN found = FALSE; - PHP_SERVICE_NAME_ENTRY lookupNameEntry; - - // Check if the service still exists. - - lookupNameEntry.Name = (*serviceItem)->Name->sr; - hashEntry = PhFindEntryHashSet( - nameHashSet, - PH_HASH_SET_SIZE(nameHashSet), - PhpHashServiceNameEntry(&lookupNameEntry) - ); - - for (; hashEntry; hashEntry = hashEntry->Next) - { - PPHP_SERVICE_NAME_ENTRY nameEntry; - - nameEntry = CONTAINING_RECORD(hashEntry, PHP_SERVICE_NAME_ENTRY, HashEntry); - - if (PhpCompareServiceNameEntry(&lookupNameEntry, nameEntry)) - { - found = TRUE; - break; - } - } - - if (!found) - { - // Remove the service from its process. - if ((*serviceItem)->ProcessId) - { - PPH_PROCESS_ITEM processItem; - - processItem = PhReferenceProcessItem((HANDLE)(*serviceItem)->ProcessId); - - if (processItem) - { - PhpRemoveProcessItemService(processItem, *serviceItem); - PhDereferenceObject(processItem); - } - } - - // Raise the service removed event. - PhInvokeCallback(&PhServiceRemovedEvent, *serviceItem); - - if (!servicesToRemove) - servicesToRemove = PhCreateList(2); - - PhAddItemList(servicesToRemove, *serviceItem); - } - } - - if (servicesToRemove) - { - PhAcquireQueuedLockExclusive(&PhServiceHashtableLock); - - for (i = 0; i < servicesToRemove->Count; i++) - { - PhpRemoveServiceItem((PPH_SERVICE_ITEM)servicesToRemove->Items[i]); - } - - PhReleaseQueuedLockExclusive(&PhServiceHashtableLock); - PhDereferenceObject(servicesToRemove); - } - } - - // Look for new services and update existing ones. - for (i = 0; i < PH_HASH_SET_SIZE(nameHashSet); i++) - { - for (hashEntry = nameHashSet[i]; hashEntry; hashEntry = hashEntry->Next) - { - PPH_SERVICE_ITEM serviceItem; - PPHP_SERVICE_NAME_ENTRY nameEntry; - ENUM_SERVICE_STATUS_PROCESS *serviceEntry; - - nameEntry = CONTAINING_RECORD(hashEntry, PHP_SERVICE_NAME_ENTRY, HashEntry); - serviceEntry = nameEntry->ServiceEntry; - serviceItem = PhpLookupServiceItem(&nameEntry->Name); - - if (!serviceItem) - { - // Create the service item and fill in basic information. - - serviceItem = PhCreateServiceItem(serviceEntry); - - PhpUpdateServiceItemConfig(scManagerHandle, serviceItem); - - // Add the service to its process, if appropriate. - if ( - ( - serviceItem->State == SERVICE_RUNNING || - serviceItem->State == SERVICE_PAUSED - ) && - serviceItem->ProcessId - ) - { - PPH_PROCESS_ITEM processItem; - - if (processItem = PhReferenceProcessItem(serviceItem->ProcessId)) - { - PhpAddProcessItemService(processItem, serviceItem); - PhDereferenceObject(processItem); - } - else - { - // The process doesn't exist yet (to us). Set the pending - // flag and when the process is added this will be - // fixed. - serviceItem->PendingProcess = TRUE; - } - } - - // Add the service item to the hashtable. - PhAcquireQueuedLockExclusive(&PhServiceHashtableLock); - PhAddEntryHashtable(PhServiceHashtable, &serviceItem); - PhReleaseQueuedLockExclusive(&PhServiceHashtableLock); - - // Raise the service added event. - PhInvokeCallback(&PhServiceAddedEvent, serviceItem); - } - else - { - if ( - serviceItem->Type != serviceEntry->ServiceStatusProcess.dwServiceType || - serviceItem->State != serviceEntry->ServiceStatusProcess.dwCurrentState || - serviceItem->ControlsAccepted != serviceEntry->ServiceStatusProcess.dwControlsAccepted || - serviceItem->ProcessId != UlongToHandle(serviceEntry->ServiceStatusProcess.dwProcessId) || - serviceItem->NeedsConfigUpdate - ) - { - PH_SERVICE_MODIFIED_DATA serviceModifiedData; - PH_SERVICE_CHANGE serviceChange; - - // The service has been "modified". - - serviceModifiedData.Service = serviceItem; - memset(&serviceModifiedData.OldService, 0, sizeof(PH_SERVICE_ITEM)); - serviceModifiedData.OldService.Type = serviceItem->Type; - serviceModifiedData.OldService.State = serviceItem->State; - serviceModifiedData.OldService.ControlsAccepted = serviceItem->ControlsAccepted; - serviceModifiedData.OldService.ProcessId = serviceItem->ProcessId; - - // Update the service item. - serviceItem->Type = serviceEntry->ServiceStatusProcess.dwServiceType; - serviceItem->State = serviceEntry->ServiceStatusProcess.dwCurrentState; - serviceItem->ControlsAccepted = serviceEntry->ServiceStatusProcess.dwControlsAccepted; - serviceItem->ProcessId = UlongToHandle(serviceEntry->ServiceStatusProcess.dwProcessId); - - if (serviceItem->ProcessId) - PhPrintUInt32(serviceItem->ProcessIdString, HandleToUlong(serviceItem->ProcessId)); - else - serviceItem->ProcessIdString[0] = 0; - - // Add/remove the service from its process. - - serviceChange = PhGetServiceChange(&serviceModifiedData); - - if ( - (serviceChange == ServiceStarted && serviceItem->ProcessId) || - (serviceChange == ServiceStopped && serviceModifiedData.OldService.ProcessId) - ) - { - PPH_PROCESS_ITEM processItem; - - if (serviceChange == ServiceStarted) - processItem = PhReferenceProcessItem(serviceItem->ProcessId); - else - processItem = PhReferenceProcessItem(serviceModifiedData.OldService.ProcessId); - - if (processItem) - { - if (serviceChange == ServiceStarted) - PhpAddProcessItemService(processItem, serviceItem); - else - PhpRemoveProcessItemService(processItem, serviceItem); - - PhDereferenceObject(processItem); - } - else - { - if (serviceChange == ServiceStarted) - serviceItem->PendingProcess = TRUE; - else - serviceItem->PendingProcess = FALSE; - } - } - else if ( - serviceItem->State == SERVICE_RUNNING && - serviceItem->ProcessId != serviceModifiedData.OldService.ProcessId && - serviceItem->ProcessId - ) - { - PPH_PROCESS_ITEM processItem; - - // The service stopped and started, and the only change we have detected - // is in the process ID. - - if (processItem = PhReferenceProcessItem(serviceModifiedData.OldService.ProcessId)) - { - PhpRemoveProcessItemService(processItem, serviceItem); - PhDereferenceObject(processItem); - } - - if (processItem = PhReferenceProcessItem(serviceItem->ProcessId)) - { - PhpAddProcessItemService(processItem, serviceItem); - PhDereferenceObject(processItem); - } - else - { - serviceItem->PendingProcess = TRUE; - } - } - - // Do a config update if necessary. - if (serviceItem->NeedsConfigUpdate) - { - PhpUpdateServiceItemConfig(scManagerHandle, serviceItem); - serviceItem->NeedsConfigUpdate = FALSE; - } - - // Raise the service modified event. - PhInvokeCallback(&PhServiceModifiedEvent, &serviceModifiedData); - } - } - } - } - - PhFree(services); - -UpdateEnd: - PhInvokeCallback(&PhServicesUpdatedEvent, NULL); - runCount++; -} - -VOID CALLBACK PhpServiceNonPollScNotifyCallback( - _In_ PVOID pParameter - ) -{ - PSERVICE_NOTIFYW notifyBuffer = pParameter; - PPHP_SERVICE_NOTIFY_CONTEXT notifyContext = notifyBuffer->pContext; - - if (notifyBuffer->dwNotificationStatus == ERROR_SUCCESS) - { - if ((notifyBuffer->dwNotificationTriggered & (SERVICE_NOTIFY_CREATED | SERVICE_NOTIFY_DELETED)) && - notifyBuffer->pszServiceNames) - { - PWSTR name; - SIZE_T nameLength; - - name = notifyBuffer->pszServiceNames; - - while (TRUE) - { - nameLength = PhCountStringZ(name); - - if (nameLength == 0) - break; - - if (name[0] == '/') - { - PPHP_SERVICE_NOTIFY_CONTEXT newNotifyContext; - - // Service creation - newNotifyContext = PhAllocate(sizeof(PHP_SERVICE_NOTIFY_CONTEXT)); - memset(newNotifyContext, 0, sizeof(PHP_SERVICE_NOTIFY_CONTEXT)); - newNotifyContext->State = SnAdding; - newNotifyContext->ServiceName = PhCreateString(name + 1); - InsertTailList(&PhpNonPollServicePendingListHead, &newNotifyContext->ListEntry); - } - - name += nameLength + 1; - } - - LocalFree(notifyBuffer->pszServiceNames); - } - - notifyContext->State = SnNotify; - RemoveEntryList(¬ifyContext->ListEntry); - InsertTailList(&PhpNonPollServicePendingListHead, ¬ifyContext->ListEntry); - } - else if (notifyBuffer->dwNotificationStatus == ERROR_SERVICE_MARKED_FOR_DELETE) - { - if (!notifyContext->IsServiceManager) - { - notifyContext->State = SnRemoving; - RemoveEntryList(¬ifyContext->ListEntry); - InsertTailList(&PhpNonPollServicePendingListHead, ¬ifyContext->ListEntry); - } - } - else - { - notifyContext->State = SnNotify; - RemoveEntryList(¬ifyContext->ListEntry); - InsertTailList(&PhpNonPollServicePendingListHead, ¬ifyContext->ListEntry); - } - - PhpNonPollGate = 1; - NtSetEvent(PhpNonPollEventHandle, NULL); -} - -VOID PhpDestroyServiceNotifyContext( - _In_ PPHP_SERVICE_NOTIFY_CONTEXT NotifyContext - ) -{ - if (NotifyContext->Buffer.pszServiceNames) - LocalFree(NotifyContext->Buffer.pszServiceNames); - - CloseServiceHandle(NotifyContext->ServiceHandle); - PhClearReference(&NotifyContext->ServiceName); - PhFree(NotifyContext); -} - -NTSTATUS PhpServiceNonPollThreadStart( - _In_ PVOID Parameter - ) -{ - ULONG result; - SC_HANDLE scManagerHandle; - LPENUM_SERVICE_STATUS_PROCESS services; - ULONG numberOfServices; - ULONG i; - PLIST_ENTRY listEntry; - PPHP_SERVICE_NOTIFY_CONTEXT notifyContext; - - if (!NT_SUCCESS(NtCreateEvent(&PhpNonPollEventHandle, EVENT_ALL_ACCESS, NULL, SynchronizationEvent, FALSE))) - { - PhpNonPollActive = FALSE; - PhpNonPollGate = 1; - return STATUS_UNSUCCESSFUL; - } - - while (TRUE) - { - scManagerHandle = OpenSCManager(NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE); - - if (!scManagerHandle) - goto ErrorExit; - - InitializeListHead(&PhpNonPollServiceListHead); - InitializeListHead(&PhpNonPollServicePendingListHead); - - if (!(services = PhEnumServices(scManagerHandle, 0, 0, &numberOfServices))) - goto ErrorExit; - - for (i = 0; i < numberOfServices; i++) - { - SC_HANDLE serviceHandle; - - if (serviceHandle = OpenService(scManagerHandle, services[i].lpServiceName, SERVICE_QUERY_STATUS)) - { - notifyContext = PhAllocate(sizeof(PHP_SERVICE_NOTIFY_CONTEXT)); - memset(notifyContext, 0, sizeof(PHP_SERVICE_NOTIFY_CONTEXT)); - notifyContext->ServiceHandle = serviceHandle; - notifyContext->State = SnNotify; - InsertTailList(&PhpNonPollServicePendingListHead, ¬ifyContext->ListEntry); - } - } - - PhFree(services); - - notifyContext = PhAllocate(sizeof(PHP_SERVICE_NOTIFY_CONTEXT)); - memset(notifyContext, 0, sizeof(PHP_SERVICE_NOTIFY_CONTEXT)); - notifyContext->ServiceHandle = scManagerHandle; - notifyContext->IsServiceManager = TRUE; - notifyContext->State = SnNotify; - InsertTailList(&PhpNonPollServicePendingListHead, ¬ifyContext->ListEntry); - - while (TRUE) - { - BOOLEAN lagging = FALSE; - - listEntry = PhpNonPollServicePendingListHead.Flink; - - while (listEntry != &PhpNonPollServicePendingListHead) - { - notifyContext = CONTAINING_RECORD(listEntry, PHP_SERVICE_NOTIFY_CONTEXT, ListEntry); - listEntry = listEntry->Flink; - - switch (notifyContext->State) - { - case SnNone: - break; - case SnAdding: - notifyContext->ServiceHandle = - OpenService(scManagerHandle, notifyContext->ServiceName->Buffer, SERVICE_QUERY_STATUS); - - if (!notifyContext->ServiceHandle) - { - RemoveEntryList(¬ifyContext->ListEntry); - PhpDestroyServiceNotifyContext(notifyContext); - continue; - } - - PhClearReference(¬ifyContext->ServiceName); - notifyContext->State = SnNotify; - goto NotifyCase; - case SnRemoving: - RemoveEntryList(¬ifyContext->ListEntry); - PhpDestroyServiceNotifyContext(notifyContext); - break; - case SnNotify: -NotifyCase: - memset(¬ifyContext->Buffer, 0, sizeof(SERVICE_NOTIFY)); - notifyContext->Buffer.dwVersion = SERVICE_NOTIFY_STATUS_CHANGE; - notifyContext->Buffer.pfnNotifyCallback = PhpServiceNonPollScNotifyCallback; - notifyContext->Buffer.pContext = notifyContext; - result = NotifyServiceStatusChangeW_I( - notifyContext->ServiceHandle, - notifyContext->IsServiceManager - ? (SERVICE_NOTIFY_CREATED | SERVICE_NOTIFY_DELETED) - : (SERVICE_NOTIFY_STOPPED | SERVICE_NOTIFY_START_PENDING | SERVICE_NOTIFY_STOP_PENDING | - SERVICE_NOTIFY_RUNNING | SERVICE_NOTIFY_CONTINUE_PENDING | SERVICE_NOTIFY_PAUSE_PENDING | - SERVICE_NOTIFY_PAUSED | SERVICE_NOTIFY_DELETE_PENDING), - ¬ifyContext->Buffer - ); - - switch (result) - { - case ERROR_SUCCESS: - notifyContext->State = SnNone; - RemoveEntryList(¬ifyContext->ListEntry); - InsertTailList(&PhpNonPollServiceListHead, ¬ifyContext->ListEntry); - break; - case ERROR_SERVICE_NOTIFY_CLIENT_LAGGING: - // We are lagging behind. Re-open the handle to the SCM as soon as possible. - lagging = TRUE; - break; - case ERROR_SERVICE_MARKED_FOR_DELETE: - default: - RemoveEntryList(¬ifyContext->ListEntry); - PhpDestroyServiceNotifyContext(notifyContext); - break; - } - - break; - } - } - - while (NtWaitForSingleObject(PhpNonPollEventHandle, TRUE, NULL) != STATUS_WAIT_0) - NOTHING; - - if (lagging) - break; - } - - // Execute all pending callbacks. - NtTestAlert(); - - listEntry = PhpNonPollServiceListHead.Flink; - - while (listEntry != &PhpNonPollServiceListHead) - { - notifyContext = CONTAINING_RECORD(listEntry, PHP_SERVICE_NOTIFY_CONTEXT, ListEntry); - listEntry = listEntry->Flink; - PhpDestroyServiceNotifyContext(notifyContext); - } - - listEntry = PhpNonPollServicePendingListHead.Flink; - - while (listEntry != &PhpNonPollServicePendingListHead) - { - notifyContext = CONTAINING_RECORD(listEntry, PHP_SERVICE_NOTIFY_CONTEXT, ListEntry); - listEntry = listEntry->Flink; - PhpDestroyServiceNotifyContext(notifyContext); - } - - CloseServiceHandle(scManagerHandle); - } - - NtClose(PhpNonPollEventHandle); - - return STATUS_SUCCESS; - -ErrorExit: - PhpNonPollActive = FALSE; - PhpNonPollGate = 1; - NtClose(PhpNonPollEventHandle); - return STATUS_UNSUCCESSFUL; -} - -VOID PhpInitializeServiceNonPoll( - VOID - ) -{ - // Dynamically import the required functions. - - NotifyServiceStatusChangeW_I = PhGetModuleProcAddress(L"advapi32.dll", "NotifyServiceStatusChangeW"); - - if (!NotifyServiceStatusChangeW_I) - return; - - PhpNonPollActive = TRUE; - PhpNonPollGate = 1; // initially the gate should be open since we only just initialized everything - - PhpNonPollThreadHandle = PhCreateThread(0, PhpServiceNonPollThreadStart, NULL); - - if (!PhpNonPollThreadHandle) - { - PhpNonPollActive = FALSE; - return; - } -} +/* + * Process Hacker - + * service provider + * + * Copyright (C) 2009-2015 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include +#include + +#include +#include + +#include +#include + +typedef DWORD (WINAPI *_NotifyServiceStatusChangeW)( + _In_ SC_HANDLE hService, + _In_ DWORD dwNotifyMask, + _In_ PSERVICE_NOTIFYW pNotifyBuffer + ); + +typedef struct _PHP_SERVICE_NAME_ENTRY +{ + PH_HASH_ENTRY HashEntry; + PH_STRINGREF Name; + ENUM_SERVICE_STATUS_PROCESS *ServiceEntry; +} PHP_SERVICE_NAME_ENTRY, *PPHP_SERVICE_NAME_ENTRY; + +typedef enum _PHP_SERVICE_NOTIFY_STATE +{ + SnNone, + SnAdding, + SnRemoving, + SnNotify +} PHP_SERVICE_NOTIFY_STATE; + +typedef struct _PHP_SERVICE_NOTIFY_CONTEXT +{ + LIST_ENTRY ListEntry; + SC_HANDLE ServiceHandle; + PPH_STRING ServiceName; // Valid only when adding + BOOLEAN IsServiceManager; + PHP_SERVICE_NOTIFY_STATE State; + SERVICE_NOTIFY Buffer; +} PHP_SERVICE_NOTIFY_CONTEXT, *PPHP_SERVICE_NOTIFY_CONTEXT; + +VOID NTAPI PhpServiceItemDeleteProcedure( + _In_ PVOID Object, + _In_ ULONG Flags + ); + +BOOLEAN NTAPI PhpServiceHashtableEqualFunction( + _In_ PVOID Entry1, + _In_ PVOID Entry2 + ); + +ULONG NTAPI PhpServiceHashtableHashFunction( + _In_ PVOID Entry + ); + +VOID PhpAddProcessItemService( + _In_ PPH_PROCESS_ITEM ProcessItem, + _In_ PPH_SERVICE_ITEM ServiceItem + ); + +VOID PhpRemoveProcessItemService( + _In_ PPH_PROCESS_ITEM ProcessItem, + _In_ PPH_SERVICE_ITEM ServiceItem + ); + +VOID PhpInitializeServiceNonPoll( + VOID + ); + +PPH_OBJECT_TYPE PhServiceItemType; + +PPH_HASHTABLE PhServiceHashtable; +PH_QUEUED_LOCK PhServiceHashtableLock = PH_QUEUED_LOCK_INIT; + +PHAPPAPI PH_CALLBACK_DECLARE(PhServiceAddedEvent); +PHAPPAPI PH_CALLBACK_DECLARE(PhServiceModifiedEvent); +PHAPPAPI PH_CALLBACK_DECLARE(PhServiceRemovedEvent); +PHAPPAPI PH_CALLBACK_DECLARE(PhServicesUpdatedEvent); + +BOOLEAN PhEnableServiceNonPoll = FALSE; +static BOOLEAN PhpNonPollInitialized = FALSE; +static BOOLEAN PhpNonPollActive = FALSE; +static HANDLE PhpNonPollThreadHandle; +static ULONG PhpNonPollGate; +static _NotifyServiceStatusChangeW NotifyServiceStatusChangeW_I; +static HANDLE PhpNonPollEventHandle; +static PH_QUEUED_LOCK PhpNonPollServiceListLock = PH_QUEUED_LOCK_INIT; +static LIST_ENTRY PhpNonPollServiceListHead; +static LIST_ENTRY PhpNonPollServicePendingListHead; + +BOOLEAN PhServiceProviderInitialization( + VOID + ) +{ + PhServiceItemType = PhCreateObjectType(L"ServiceItem", 0, PhpServiceItemDeleteProcedure); + PhServiceHashtable = PhCreateHashtable( + sizeof(PPH_SERVICE_ITEM), + PhpServiceHashtableEqualFunction, + PhpServiceHashtableHashFunction, + 40 + ); + + return TRUE; +} + +PPH_SERVICE_ITEM PhCreateServiceItem( + _In_opt_ LPENUM_SERVICE_STATUS_PROCESS Information + ) +{ + PPH_SERVICE_ITEM serviceItem; + + serviceItem = PhCreateObject( + PhEmGetObjectSize(EmServiceItemType, sizeof(PH_SERVICE_ITEM)), + PhServiceItemType + ); + memset(serviceItem, 0, sizeof(PH_SERVICE_ITEM)); + + if (Information) + { + serviceItem->Name = PhCreateString(Information->lpServiceName); + serviceItem->Key = serviceItem->Name->sr; + serviceItem->DisplayName = PhCreateString(Information->lpDisplayName); + serviceItem->Type = Information->ServiceStatusProcess.dwServiceType; + serviceItem->State = Information->ServiceStatusProcess.dwCurrentState; + serviceItem->ControlsAccepted = Information->ServiceStatusProcess.dwControlsAccepted; + serviceItem->Flags = Information->ServiceStatusProcess.dwServiceFlags; + serviceItem->ProcessId = UlongToHandle(Information->ServiceStatusProcess.dwProcessId); + + if (serviceItem->ProcessId) + PhPrintUInt32(serviceItem->ProcessIdString, HandleToUlong(serviceItem->ProcessId)); + } + + PhEmCallObjectOperation(EmServiceItemType, serviceItem, EmObjectCreate); + + return serviceItem; +} + +VOID PhpServiceItemDeleteProcedure( + _In_ PVOID Object, + _In_ ULONG Flags + ) +{ + PPH_SERVICE_ITEM serviceItem = (PPH_SERVICE_ITEM)Object; + + PhEmCallObjectOperation(EmServiceItemType, serviceItem, EmObjectDelete); + + if (serviceItem->Name) PhDereferenceObject(serviceItem->Name); + if (serviceItem->DisplayName) PhDereferenceObject(serviceItem->DisplayName); +} + +BOOLEAN PhpServiceHashtableEqualFunction( + _In_ PVOID Entry1, + _In_ PVOID Entry2 + ) +{ + PPH_SERVICE_ITEM serviceItem1 = *(PPH_SERVICE_ITEM *)Entry1; + PPH_SERVICE_ITEM serviceItem2 = *(PPH_SERVICE_ITEM *)Entry2; + + return PhEqualStringRef(&serviceItem1->Key, &serviceItem2->Key, TRUE); +} + +ULONG PhpServiceHashtableHashFunction( + _In_ PVOID Entry + ) +{ + PPH_SERVICE_ITEM serviceItem = *(PPH_SERVICE_ITEM *)Entry; + + return PhHashStringRef(&serviceItem->Key, TRUE); +} + +PPH_SERVICE_ITEM PhpLookupServiceItem( + _In_ PPH_STRINGREF Name + ) +{ + PH_SERVICE_ITEM lookupServiceItem; + PPH_SERVICE_ITEM lookupServiceItemPtr = &lookupServiceItem; + PPH_SERVICE_ITEM *serviceItem; + + // Construct a temporary service item for the lookup. + lookupServiceItem.Key = *Name; + + serviceItem = (PPH_SERVICE_ITEM *)PhFindEntryHashtable( + PhServiceHashtable, + &lookupServiceItemPtr + ); + + if (serviceItem) + return *serviceItem; + else + return NULL; +} + +PPH_SERVICE_ITEM PhReferenceServiceItem( + _In_ PWSTR Name + ) +{ + PPH_SERVICE_ITEM serviceItem; + PH_STRINGREF key; + + PhInitializeStringRef(&key, Name); + + PhAcquireQueuedLockShared(&PhServiceHashtableLock); + + serviceItem = PhpLookupServiceItem(&key); + + if (serviceItem) + PhReferenceObject(serviceItem); + + PhReleaseQueuedLockShared(&PhServiceHashtableLock); + + return serviceItem; +} + +VOID PhMarkNeedsConfigUpdateServiceItem( + _In_ PPH_SERVICE_ITEM ServiceItem + ) +{ + ServiceItem->NeedsConfigUpdate = TRUE; + + if (PhEnableServiceNonPoll) + PhpNonPollGate = 1; +} + +VOID PhpRemoveServiceItem( + _In_ PPH_SERVICE_ITEM ServiceItem + ) +{ + PhRemoveEntryHashtable(PhServiceHashtable, &ServiceItem); + PhDereferenceObject(ServiceItem); +} + +PH_SERVICE_CHANGE PhGetServiceChange( + _In_ PPH_SERVICE_MODIFIED_DATA Data + ) +{ + if ( + ( + Data->OldService.State == SERVICE_STOPPED || + Data->OldService.State == SERVICE_START_PENDING + ) && + Data->Service->State == SERVICE_RUNNING + ) + { + return ServiceStarted; + } + + if ( + ( + Data->OldService.State == SERVICE_PAUSED || + Data->OldService.State == SERVICE_CONTINUE_PENDING + ) && + Data->Service->State == SERVICE_RUNNING + ) + { + return ServiceContinued; + } + + if ( + ( + Data->OldService.State == SERVICE_RUNNING || + Data->OldService.State == SERVICE_PAUSE_PENDING + ) && + Data->Service->State == SERVICE_PAUSED + ) + { + return ServicePaused; + } + + if ( + ( + Data->OldService.State == SERVICE_RUNNING || + Data->OldService.State == SERVICE_STOP_PENDING + ) && + Data->Service->State == SERVICE_STOPPED + ) + { + return ServiceStopped; + } + + return -1; +} + +VOID PhUpdateProcessItemServices( + _In_ PPH_PROCESS_ITEM ProcessItem + ) +{ + PH_HASHTABLE_ENUM_CONTEXT enumContext; + PPH_SERVICE_ITEM *serviceItem; + + // We don't need to lock as long as the service provider + // never runs concurrently with the process provider. This + // is currently true. + + PhBeginEnumHashtable(PhServiceHashtable, &enumContext); + + while (serviceItem = PhNextEnumHashtable(&enumContext)) + { + if ( + (*serviceItem)->PendingProcess && + (*serviceItem)->ProcessId == ProcessItem->ProcessId + ) + { + PhpAddProcessItemService(ProcessItem, *serviceItem); + } + } +} + +VOID PhpAddProcessItemService( + _In_ PPH_PROCESS_ITEM ProcessItem, + _In_ PPH_SERVICE_ITEM ServiceItem + ) +{ + PhAcquireQueuedLockExclusive(&ProcessItem->ServiceListLock); + + if (!ProcessItem->ServiceList) + ProcessItem->ServiceList = PhCreatePointerList(2); + + if (!PhFindItemPointerList(ProcessItem->ServiceList, ServiceItem)) + { + PhReferenceObject(ServiceItem); + PhAddItemPointerList(ProcessItem->ServiceList, ServiceItem); + } + + PhReleaseQueuedLockExclusive(&ProcessItem->ServiceListLock); + + ServiceItem->PendingProcess = FALSE; + ProcessItem->JustProcessed = 1; +} + +VOID PhpRemoveProcessItemService( + _In_ PPH_PROCESS_ITEM ProcessItem, + _In_ PPH_SERVICE_ITEM ServiceItem + ) +{ + HANDLE pointerHandle; + + if (!ProcessItem->ServiceList) + return; + + PhAcquireQueuedLockExclusive(&ProcessItem->ServiceListLock); + + if (pointerHandle = PhFindItemPointerList(ProcessItem->ServiceList, ServiceItem)) + { + PhRemoveItemPointerList(ProcessItem->ServiceList, pointerHandle); + PhDereferenceObject(ServiceItem); + } + + PhReleaseQueuedLockExclusive(&ProcessItem->ServiceListLock); + + ProcessItem->JustProcessed = 1; +} + +VOID PhpUpdateServiceItemConfig( + _In_ SC_HANDLE ScManagerHandle, + _In_ PPH_SERVICE_ITEM ServiceItem + ) +{ + SC_HANDLE serviceHandle; + + serviceHandle = OpenService(ScManagerHandle, ServiceItem->Name->Buffer, SERVICE_QUERY_CONFIG); + + if (serviceHandle) + { + LPQUERY_SERVICE_CONFIG config; + SERVICE_DELAYED_AUTO_START_INFO delayedAutoStartInfo; + ULONG returnLength; + PSERVICE_TRIGGER_INFO triggerInfo; + + config = PhGetServiceConfig(serviceHandle); + + if (config) + { + ServiceItem->StartType = config->dwStartType; + ServiceItem->ErrorControl = config->dwErrorControl; + + PhFree(config); + } + + if (QueryServiceConfig2( + serviceHandle, + SERVICE_CONFIG_DELAYED_AUTO_START_INFO, + (BYTE *)&delayedAutoStartInfo, + sizeof(SERVICE_DELAYED_AUTO_START_INFO), + &returnLength + )) + { + ServiceItem->DelayedStart = delayedAutoStartInfo.fDelayedAutostart; + } + else + { + ServiceItem->DelayedStart = FALSE; + } + + if (triggerInfo = PhQueryServiceVariableSize(serviceHandle, SERVICE_CONFIG_TRIGGER_INFO)) + { + ServiceItem->HasTriggers = triggerInfo->cTriggers != 0; + PhFree(triggerInfo); + } + else + { + ServiceItem->HasTriggers = FALSE; + } + + CloseServiceHandle(serviceHandle); + } +} + +static BOOLEAN PhpCompareServiceNameEntry( + _In_ PPHP_SERVICE_NAME_ENTRY Value1, + _In_ PPHP_SERVICE_NAME_ENTRY Value2 + ) +{ + return PhEqualStringRef(&Value1->Name, &Value2->Name, TRUE); +} + +static ULONG PhpHashServiceNameEntry( + _In_ PPHP_SERVICE_NAME_ENTRY Value + ) +{ + return PhHashStringRef(&Value->Name, TRUE); +} + +VOID PhServiceProviderUpdate( + _In_ PVOID Object + ) +{ + static SC_HANDLE scManagerHandle = NULL; + static ULONG runCount = 0; + + static PPH_HASH_ENTRY nameHashSet[256]; + static PPHP_SERVICE_NAME_ENTRY nameEntries = NULL; + static ULONG nameEntriesCount; + static ULONG nameEntriesAllocated = 0; + + LPENUM_SERVICE_STATUS_PROCESS services; + ULONG numberOfServices; + ULONG i; + PPH_HASH_ENTRY hashEntry; + + // We always execute the first run, and we only initialize non-polling after the first run. + if (PhEnableServiceNonPoll && runCount != 0) + { + if (!PhpNonPollInitialized) + { + if (WindowsVersion >= WINDOWS_VISTA) + { + PhpInitializeServiceNonPoll(); + } + + PhpNonPollInitialized = TRUE; + } + + if (PhpNonPollActive) + { + if (InterlockedExchange(&PhpNonPollGate, 0) == 0) + { + // Non-poll gate is closed; skip all processing. + goto UpdateEnd; + } + } + } + + if (!scManagerHandle) + { + scManagerHandle = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT | SC_MANAGER_ENUMERATE_SERVICE); + + if (!scManagerHandle) + return; + } + + services = PhEnumServices(scManagerHandle, 0, 0, &numberOfServices); + + if (!services) + return; + + // Build a hash set containing the service names. + + // This has caused a massive decrease in background CPU usage, and + // is certainly much better than the quadratic-time string comparisons + // we were doing before (in the "Look for dead services" section). + + nameEntriesCount = 0; + + if (nameEntriesAllocated < numberOfServices) + { + nameEntriesAllocated = numberOfServices + 32; + + if (nameEntries) PhFree(nameEntries); + nameEntries = PhAllocate(sizeof(PHP_SERVICE_NAME_ENTRY) * nameEntriesAllocated); + } + + PhInitializeHashSet(nameHashSet, PH_HASH_SET_SIZE(nameHashSet)); + + for (i = 0; i < numberOfServices; i++) + { + PPHP_SERVICE_NAME_ENTRY entry; + + entry = &nameEntries[nameEntriesCount++]; + PhInitializeStringRefLongHint(&entry->Name, services[i].lpServiceName); + entry->ServiceEntry = &services[i]; + PhAddEntryHashSet( + nameHashSet, + PH_HASH_SET_SIZE(nameHashSet), + &entry->HashEntry, + PhpHashServiceNameEntry(entry) + ); + } + + // Look for dead services. + { + PPH_LIST servicesToRemove = NULL; + PH_HASHTABLE_ENUM_CONTEXT enumContext; + PPH_SERVICE_ITEM *serviceItem; + + PhBeginEnumHashtable(PhServiceHashtable, &enumContext); + + while (serviceItem = PhNextEnumHashtable(&enumContext)) + { + BOOLEAN found = FALSE; + PHP_SERVICE_NAME_ENTRY lookupNameEntry; + + // Check if the service still exists. + + lookupNameEntry.Name = (*serviceItem)->Name->sr; + hashEntry = PhFindEntryHashSet( + nameHashSet, + PH_HASH_SET_SIZE(nameHashSet), + PhpHashServiceNameEntry(&lookupNameEntry) + ); + + for (; hashEntry; hashEntry = hashEntry->Next) + { + PPHP_SERVICE_NAME_ENTRY nameEntry; + + nameEntry = CONTAINING_RECORD(hashEntry, PHP_SERVICE_NAME_ENTRY, HashEntry); + + if (PhpCompareServiceNameEntry(&lookupNameEntry, nameEntry)) + { + found = TRUE; + break; + } + } + + if (!found) + { + // Remove the service from its process. + if ((*serviceItem)->ProcessId) + { + PPH_PROCESS_ITEM processItem; + + processItem = PhReferenceProcessItem((HANDLE)(*serviceItem)->ProcessId); + + if (processItem) + { + PhpRemoveProcessItemService(processItem, *serviceItem); + PhDereferenceObject(processItem); + } + } + + // Raise the service removed event. + PhInvokeCallback(&PhServiceRemovedEvent, *serviceItem); + + if (!servicesToRemove) + servicesToRemove = PhCreateList(2); + + PhAddItemList(servicesToRemove, *serviceItem); + } + } + + if (servicesToRemove) + { + PhAcquireQueuedLockExclusive(&PhServiceHashtableLock); + + for (i = 0; i < servicesToRemove->Count; i++) + { + PhpRemoveServiceItem((PPH_SERVICE_ITEM)servicesToRemove->Items[i]); + } + + PhReleaseQueuedLockExclusive(&PhServiceHashtableLock); + PhDereferenceObject(servicesToRemove); + } + } + + // Look for new services and update existing ones. + for (i = 0; i < PH_HASH_SET_SIZE(nameHashSet); i++) + { + for (hashEntry = nameHashSet[i]; hashEntry; hashEntry = hashEntry->Next) + { + PPH_SERVICE_ITEM serviceItem; + PPHP_SERVICE_NAME_ENTRY nameEntry; + ENUM_SERVICE_STATUS_PROCESS *serviceEntry; + + nameEntry = CONTAINING_RECORD(hashEntry, PHP_SERVICE_NAME_ENTRY, HashEntry); + serviceEntry = nameEntry->ServiceEntry; + serviceItem = PhpLookupServiceItem(&nameEntry->Name); + + if (!serviceItem) + { + // Create the service item and fill in basic information. + + serviceItem = PhCreateServiceItem(serviceEntry); + + PhpUpdateServiceItemConfig(scManagerHandle, serviceItem); + + // Add the service to its process, if appropriate. + if ( + ( + serviceItem->State == SERVICE_RUNNING || + serviceItem->State == SERVICE_PAUSED + ) && + serviceItem->ProcessId + ) + { + PPH_PROCESS_ITEM processItem; + + if (processItem = PhReferenceProcessItem(serviceItem->ProcessId)) + { + PhpAddProcessItemService(processItem, serviceItem); + PhDereferenceObject(processItem); + } + else + { + // The process doesn't exist yet (to us). Set the pending + // flag and when the process is added this will be + // fixed. + serviceItem->PendingProcess = TRUE; + } + } + + // Add the service item to the hashtable. + PhAcquireQueuedLockExclusive(&PhServiceHashtableLock); + PhAddEntryHashtable(PhServiceHashtable, &serviceItem); + PhReleaseQueuedLockExclusive(&PhServiceHashtableLock); + + // Raise the service added event. + PhInvokeCallback(&PhServiceAddedEvent, serviceItem); + } + else + { + if ( + serviceItem->Type != serviceEntry->ServiceStatusProcess.dwServiceType || + serviceItem->State != serviceEntry->ServiceStatusProcess.dwCurrentState || + serviceItem->ControlsAccepted != serviceEntry->ServiceStatusProcess.dwControlsAccepted || + serviceItem->ProcessId != UlongToHandle(serviceEntry->ServiceStatusProcess.dwProcessId) || + serviceItem->NeedsConfigUpdate + ) + { + PH_SERVICE_MODIFIED_DATA serviceModifiedData; + PH_SERVICE_CHANGE serviceChange; + + // The service has been "modified". + + serviceModifiedData.Service = serviceItem; + memset(&serviceModifiedData.OldService, 0, sizeof(PH_SERVICE_ITEM)); + serviceModifiedData.OldService.Type = serviceItem->Type; + serviceModifiedData.OldService.State = serviceItem->State; + serviceModifiedData.OldService.ControlsAccepted = serviceItem->ControlsAccepted; + serviceModifiedData.OldService.ProcessId = serviceItem->ProcessId; + + // Update the service item. + serviceItem->Type = serviceEntry->ServiceStatusProcess.dwServiceType; + serviceItem->State = serviceEntry->ServiceStatusProcess.dwCurrentState; + serviceItem->ControlsAccepted = serviceEntry->ServiceStatusProcess.dwControlsAccepted; + serviceItem->ProcessId = UlongToHandle(serviceEntry->ServiceStatusProcess.dwProcessId); + + if (serviceItem->ProcessId) + PhPrintUInt32(serviceItem->ProcessIdString, HandleToUlong(serviceItem->ProcessId)); + else + serviceItem->ProcessIdString[0] = 0; + + // Add/remove the service from its process. + + serviceChange = PhGetServiceChange(&serviceModifiedData); + + if ( + (serviceChange == ServiceStarted && serviceItem->ProcessId) || + (serviceChange == ServiceStopped && serviceModifiedData.OldService.ProcessId) + ) + { + PPH_PROCESS_ITEM processItem; + + if (serviceChange == ServiceStarted) + processItem = PhReferenceProcessItem(serviceItem->ProcessId); + else + processItem = PhReferenceProcessItem(serviceModifiedData.OldService.ProcessId); + + if (processItem) + { + if (serviceChange == ServiceStarted) + PhpAddProcessItemService(processItem, serviceItem); + else + PhpRemoveProcessItemService(processItem, serviceItem); + + PhDereferenceObject(processItem); + } + else + { + if (serviceChange == ServiceStarted) + serviceItem->PendingProcess = TRUE; + else + serviceItem->PendingProcess = FALSE; + } + } + else if ( + serviceItem->State == SERVICE_RUNNING && + serviceItem->ProcessId != serviceModifiedData.OldService.ProcessId && + serviceItem->ProcessId + ) + { + PPH_PROCESS_ITEM processItem; + + // The service stopped and started, and the only change we have detected + // is in the process ID. + + if (processItem = PhReferenceProcessItem(serviceModifiedData.OldService.ProcessId)) + { + PhpRemoveProcessItemService(processItem, serviceItem); + PhDereferenceObject(processItem); + } + + if (processItem = PhReferenceProcessItem(serviceItem->ProcessId)) + { + PhpAddProcessItemService(processItem, serviceItem); + PhDereferenceObject(processItem); + } + else + { + serviceItem->PendingProcess = TRUE; + } + } + + // Do a config update if necessary. + if (serviceItem->NeedsConfigUpdate) + { + PhpUpdateServiceItemConfig(scManagerHandle, serviceItem); + serviceItem->NeedsConfigUpdate = FALSE; + } + + // Raise the service modified event. + PhInvokeCallback(&PhServiceModifiedEvent, &serviceModifiedData); + } + } + } + } + + PhFree(services); + +UpdateEnd: + PhInvokeCallback(&PhServicesUpdatedEvent, NULL); + runCount++; +} + +VOID CALLBACK PhpServiceNonPollScNotifyCallback( + _In_ PVOID pParameter + ) +{ + PSERVICE_NOTIFYW notifyBuffer = pParameter; + PPHP_SERVICE_NOTIFY_CONTEXT notifyContext = notifyBuffer->pContext; + + if (notifyBuffer->dwNotificationStatus == ERROR_SUCCESS) + { + if ((notifyBuffer->dwNotificationTriggered & (SERVICE_NOTIFY_CREATED | SERVICE_NOTIFY_DELETED)) && + notifyBuffer->pszServiceNames) + { + PWSTR name; + SIZE_T nameLength; + + name = notifyBuffer->pszServiceNames; + + while (TRUE) + { + nameLength = PhCountStringZ(name); + + if (nameLength == 0) + break; + + if (name[0] == '/') + { + PPHP_SERVICE_NOTIFY_CONTEXT newNotifyContext; + + // Service creation + newNotifyContext = PhAllocate(sizeof(PHP_SERVICE_NOTIFY_CONTEXT)); + memset(newNotifyContext, 0, sizeof(PHP_SERVICE_NOTIFY_CONTEXT)); + newNotifyContext->State = SnAdding; + newNotifyContext->ServiceName = PhCreateString(name + 1); + InsertTailList(&PhpNonPollServicePendingListHead, &newNotifyContext->ListEntry); + } + + name += nameLength + 1; + } + + LocalFree(notifyBuffer->pszServiceNames); + } + + notifyContext->State = SnNotify; + RemoveEntryList(¬ifyContext->ListEntry); + InsertTailList(&PhpNonPollServicePendingListHead, ¬ifyContext->ListEntry); + } + else if (notifyBuffer->dwNotificationStatus == ERROR_SERVICE_MARKED_FOR_DELETE) + { + if (!notifyContext->IsServiceManager) + { + notifyContext->State = SnRemoving; + RemoveEntryList(¬ifyContext->ListEntry); + InsertTailList(&PhpNonPollServicePendingListHead, ¬ifyContext->ListEntry); + } + } + else + { + notifyContext->State = SnNotify; + RemoveEntryList(¬ifyContext->ListEntry); + InsertTailList(&PhpNonPollServicePendingListHead, ¬ifyContext->ListEntry); + } + + PhpNonPollGate = 1; + NtSetEvent(PhpNonPollEventHandle, NULL); +} + +VOID PhpDestroyServiceNotifyContext( + _In_ PPHP_SERVICE_NOTIFY_CONTEXT NotifyContext + ) +{ + if (NotifyContext->Buffer.pszServiceNames) + LocalFree(NotifyContext->Buffer.pszServiceNames); + + CloseServiceHandle(NotifyContext->ServiceHandle); + PhClearReference(&NotifyContext->ServiceName); + PhFree(NotifyContext); +} + +NTSTATUS PhpServiceNonPollThreadStart( + _In_ PVOID Parameter + ) +{ + ULONG result; + SC_HANDLE scManagerHandle; + LPENUM_SERVICE_STATUS_PROCESS services; + ULONG numberOfServices; + ULONG i; + PLIST_ENTRY listEntry; + PPHP_SERVICE_NOTIFY_CONTEXT notifyContext; + + if (!NT_SUCCESS(NtCreateEvent(&PhpNonPollEventHandle, EVENT_ALL_ACCESS, NULL, SynchronizationEvent, FALSE))) + { + PhpNonPollActive = FALSE; + PhpNonPollGate = 1; + return STATUS_UNSUCCESSFUL; + } + + while (TRUE) + { + scManagerHandle = OpenSCManager(NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE); + + if (!scManagerHandle) + goto ErrorExit; + + InitializeListHead(&PhpNonPollServiceListHead); + InitializeListHead(&PhpNonPollServicePendingListHead); + + if (!(services = PhEnumServices(scManagerHandle, 0, 0, &numberOfServices))) + goto ErrorExit; + + for (i = 0; i < numberOfServices; i++) + { + SC_HANDLE serviceHandle; + + if (serviceHandle = OpenService(scManagerHandle, services[i].lpServiceName, SERVICE_QUERY_STATUS)) + { + notifyContext = PhAllocate(sizeof(PHP_SERVICE_NOTIFY_CONTEXT)); + memset(notifyContext, 0, sizeof(PHP_SERVICE_NOTIFY_CONTEXT)); + notifyContext->ServiceHandle = serviceHandle; + notifyContext->State = SnNotify; + InsertTailList(&PhpNonPollServicePendingListHead, ¬ifyContext->ListEntry); + } + } + + PhFree(services); + + notifyContext = PhAllocate(sizeof(PHP_SERVICE_NOTIFY_CONTEXT)); + memset(notifyContext, 0, sizeof(PHP_SERVICE_NOTIFY_CONTEXT)); + notifyContext->ServiceHandle = scManagerHandle; + notifyContext->IsServiceManager = TRUE; + notifyContext->State = SnNotify; + InsertTailList(&PhpNonPollServicePendingListHead, ¬ifyContext->ListEntry); + + while (TRUE) + { + BOOLEAN lagging = FALSE; + + listEntry = PhpNonPollServicePendingListHead.Flink; + + while (listEntry != &PhpNonPollServicePendingListHead) + { + notifyContext = CONTAINING_RECORD(listEntry, PHP_SERVICE_NOTIFY_CONTEXT, ListEntry); + listEntry = listEntry->Flink; + + switch (notifyContext->State) + { + case SnNone: + break; + case SnAdding: + notifyContext->ServiceHandle = + OpenService(scManagerHandle, notifyContext->ServiceName->Buffer, SERVICE_QUERY_STATUS); + + if (!notifyContext->ServiceHandle) + { + RemoveEntryList(¬ifyContext->ListEntry); + PhpDestroyServiceNotifyContext(notifyContext); + continue; + } + + PhClearReference(¬ifyContext->ServiceName); + notifyContext->State = SnNotify; + goto NotifyCase; + case SnRemoving: + RemoveEntryList(¬ifyContext->ListEntry); + PhpDestroyServiceNotifyContext(notifyContext); + break; + case SnNotify: +NotifyCase: + memset(¬ifyContext->Buffer, 0, sizeof(SERVICE_NOTIFY)); + notifyContext->Buffer.dwVersion = SERVICE_NOTIFY_STATUS_CHANGE; + notifyContext->Buffer.pfnNotifyCallback = PhpServiceNonPollScNotifyCallback; + notifyContext->Buffer.pContext = notifyContext; + result = NotifyServiceStatusChangeW_I( + notifyContext->ServiceHandle, + notifyContext->IsServiceManager + ? (SERVICE_NOTIFY_CREATED | SERVICE_NOTIFY_DELETED) + : (SERVICE_NOTIFY_STOPPED | SERVICE_NOTIFY_START_PENDING | SERVICE_NOTIFY_STOP_PENDING | + SERVICE_NOTIFY_RUNNING | SERVICE_NOTIFY_CONTINUE_PENDING | SERVICE_NOTIFY_PAUSE_PENDING | + SERVICE_NOTIFY_PAUSED | SERVICE_NOTIFY_DELETE_PENDING), + ¬ifyContext->Buffer + ); + + switch (result) + { + case ERROR_SUCCESS: + notifyContext->State = SnNone; + RemoveEntryList(¬ifyContext->ListEntry); + InsertTailList(&PhpNonPollServiceListHead, ¬ifyContext->ListEntry); + break; + case ERROR_SERVICE_NOTIFY_CLIENT_LAGGING: + // We are lagging behind. Re-open the handle to the SCM as soon as possible. + lagging = TRUE; + break; + case ERROR_SERVICE_MARKED_FOR_DELETE: + default: + RemoveEntryList(¬ifyContext->ListEntry); + PhpDestroyServiceNotifyContext(notifyContext); + break; + } + + break; + } + } + + while (NtWaitForSingleObject(PhpNonPollEventHandle, TRUE, NULL) != STATUS_WAIT_0) + NOTHING; + + if (lagging) + break; + } + + // Execute all pending callbacks. + NtTestAlert(); + + listEntry = PhpNonPollServiceListHead.Flink; + + while (listEntry != &PhpNonPollServiceListHead) + { + notifyContext = CONTAINING_RECORD(listEntry, PHP_SERVICE_NOTIFY_CONTEXT, ListEntry); + listEntry = listEntry->Flink; + PhpDestroyServiceNotifyContext(notifyContext); + } + + listEntry = PhpNonPollServicePendingListHead.Flink; + + while (listEntry != &PhpNonPollServicePendingListHead) + { + notifyContext = CONTAINING_RECORD(listEntry, PHP_SERVICE_NOTIFY_CONTEXT, ListEntry); + listEntry = listEntry->Flink; + PhpDestroyServiceNotifyContext(notifyContext); + } + + CloseServiceHandle(scManagerHandle); + } + + NtClose(PhpNonPollEventHandle); + + return STATUS_SUCCESS; + +ErrorExit: + PhpNonPollActive = FALSE; + PhpNonPollGate = 1; + NtClose(PhpNonPollEventHandle); + return STATUS_UNSUCCESSFUL; +} + +VOID PhpInitializeServiceNonPoll( + VOID + ) +{ + // Dynamically import the required functions. + + NotifyServiceStatusChangeW_I = PhGetModuleProcAddress(L"advapi32.dll", "NotifyServiceStatusChangeW"); + + if (!NotifyServiceStatusChangeW_I) + return; + + PhpNonPollActive = TRUE; + PhpNonPollGate = 1; // initially the gate should be open since we only just initialized everything + + PhpNonPollThreadHandle = PhCreateThread(0, PhpServiceNonPollThreadStart, NULL); + + if (!PhpNonPollThreadHandle) + { + PhpNonPollActive = FALSE; + return; + } +} diff --git a/ProcessHacker/sysinfo.c b/ProcessHacker/sysinfo.c index 709a126b2f5c..e8e389dbce97 100644 --- a/ProcessHacker/sysinfo.c +++ b/ProcessHacker/sysinfo.c @@ -1,2054 +1,2054 @@ -/* - * Process Hacker - - * System Information window - * - * Copyright (C) 2011-2016 wj32 - * Copyright (C) 2017 dmex - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -/* - * This file contains the System Information framework. The "framework" handles creation, layout and - * events for the top-level window itself. It manages the list of sections. - * - * A section is an object that provides information to the user about a type of system resource. The - * CPU, Memory and I/O sections are added automatically to every System Information window. Plugins - * can also add sections to the window. There are two views: summary and section. In summary view, - * rows of graphs are displayed in the window, one graph for each section. The section is - * responsible for providing the graph data and any text to draw on the left-hand side of the graph. - * In section view, the graphs become mini-graphs on the left-hand side of the window. The section - * displays its own embedded dialog in the remaining space. Any controls contained in this dialog, - * including graphs, are the responsibility of the section. - * - * Users can enter section view by: - * * Clicking on a graph or mini-graph. - * * Pressing a number from 1 to 9. - * * Using the tab or arrow keys to select a graph and pressing space or enter. - * - * Users can return to summary view by: - * * Clicking "Back" on the left-hand side of the window. - * * Pressing Backspace. - * * Using the tab or arrow keys to select "Back" and pressing space or enter. - */ - -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include - -static HANDLE PhSipThread = NULL; -HWND PhSipWindow = NULL; -static PPH_LIST PhSipDialogList = NULL; -static PH_EVENT InitializedEvent = PH_EVENT_INIT; -static PWSTR InitialSectionName; -static PH_LAYOUT_MANAGER WindowLayoutManager; -static RECT MinimumSize; -static PH_CALLBACK_REGISTRATION ProcessesUpdatedRegistration; - -static PPH_LIST SectionList; -static PH_SYSINFO_PARAMETERS CurrentParameters; -static PH_SYSINFO_VIEW_TYPE CurrentView; -static PPH_SYSINFO_SECTION CurrentSection; -static HWND ContainerControl; -static HWND SeparatorControl; -static HWND RestoreSummaryControl; -static BOOLEAN RestoreSummaryControlHot; -static BOOLEAN RestoreSummaryControlHasFocus; - -static HTHEME ThemeData; -static BOOLEAN ThemeHasItemBackground; - -static BOOLEAN AlwaysOnTop; - -VOID PhShowSystemInformationDialog( - _In_opt_ PWSTR SectionName - ) -{ - InitialSectionName = SectionName; - - if (!PhSipWindow) - { - if (!(PhSipThread = PhCreateThread(0, PhSipSysInfoThreadStart, NULL))) - { - PhShowStatus(PhMainWndHandle, L"Unable to create the system information window", 0, GetLastError()); - return; - } - - PhWaitForEvent(&InitializedEvent, NULL); - } - - SendMessage(PhSipWindow, SI_MSG_SYSINFO_ACTIVATE, (WPARAM)SectionName, 0); -} - -NTSTATUS PhSipSysInfoThreadStart( - _In_ PVOID Parameter - ) -{ - PH_AUTO_POOL autoPool; - BOOL result; - MSG message; - HACCEL acceleratorTable; - BOOLEAN processed; - - PhInitializeAutoPool(&autoPool); - - PhSipWindow = CreateDialog( - PhInstanceHandle, - MAKEINTRESOURCE(IDD_SYSINFO), - NULL, - PhSipSysInfoDialogProc - ); - - PhSetEvent(&InitializedEvent); - - acceleratorTable = LoadAccelerators(PhInstanceHandle, MAKEINTRESOURCE(IDR_SYSINFO_ACCEL)); - - while (result = GetMessage(&message, NULL, 0, 0)) - { - if (result == -1) - break; - - processed = FALSE; - - if ( - message.hwnd == PhSipWindow || - IsChild(PhSipWindow, message.hwnd) - ) - { - if (TranslateAccelerator(PhSipWindow, acceleratorTable, &message)) - processed = TRUE; - } - - if (!processed && PhSipDialogList) - { - ULONG i; - - for (i = 0; i < PhSipDialogList->Count; i++) - { - if (IsDialogMessage((HWND)PhSipDialogList->Items[i], &message)) - { - processed = TRUE; - break; - } - } - } - - if (!processed) - { - if (!IsDialogMessage(PhSipWindow, &message)) - { - TranslateMessage(&message); - DispatchMessage(&message); - } - } - - PhDrainAutoPool(&autoPool); - } - - PhDeleteAutoPool(&autoPool); - PhResetEvent(&InitializedEvent); - NtClose(PhSipThread); - - PhSipWindow = NULL; - PhSipThread = NULL; - - if (PhSipDialogList) - { - PhDereferenceObject(PhSipDialogList); - PhSipDialogList = NULL; - } - - return STATUS_SUCCESS; -} - -INT_PTR CALLBACK PhSipSysInfoDialogProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - switch (uMsg) - { - case WM_INITDIALOG: - { - PhSipWindow = hwndDlg; - PhSipOnInitDialog(); - } - break; - case WM_DESTROY: - { - PhSipOnDestroy(); - } - break; - case WM_NCDESTROY: - { - PhSipOnNcDestroy(); - } - break; - case WM_SHOWWINDOW: - { - PhSipOnShowWindow(!!wParam, (ULONG)lParam); - } - break; - case WM_SYSCOMMAND: - { - if (PhSipOnSysCommand((ULONG)wParam, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))) - return 0; - } - break; - case WM_SIZE: - { - PhSipOnSize(); - } - break; - case WM_SIZING: - { - PhSipOnSizing((ULONG)wParam, (PRECT)lParam); - } - break; - case WM_THEMECHANGED: - { - PhSipOnThemeChanged(); - } - break; - case WM_COMMAND: - { - PhSipOnCommand(LOWORD(wParam), HIWORD(wParam)); - } - break; - case WM_NOTIFY: - { - LRESULT result; - - if (PhSipOnNotify((NMHDR *)lParam, &result)) - { - SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, result); - return TRUE; - } - } - break; - case WM_DRAWITEM: - { - if (PhSipOnDrawItem(wParam, (DRAWITEMSTRUCT *)lParam)) - return TRUE; - } - break; - } - - if (uMsg >= SI_MSG_SYSINFO_FIRST && uMsg <= SI_MSG_SYSINFO_LAST) - { - PhSipOnUserMessage(uMsg, wParam, lParam); - } - - return FALSE; -} - -INT_PTR CALLBACK PhSipContainerDialogProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - return FALSE; -} - -VOID PhSipOnInitDialog( - VOID - ) -{ - PhInitializeLayoutManager(&WindowLayoutManager, PhSipWindow); - - PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(PhSipWindow, IDC_INSTRUCTION), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_BOTTOM); - PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(PhSipWindow, IDC_ALWAYSONTOP), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); - PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(PhSipWindow, IDOK), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); - - PhRegisterCallback( - &PhProcessesUpdatedEvent, - PhSipSysInfoUpdateHandler, - NULL, - &ProcessesUpdatedRegistration - ); - - ContainerControl = CreateDialog( - PhInstanceHandle, - MAKEINTRESOURCE(IDD_CONTAINER), - PhSipWindow, - PhSipContainerDialogProc - ); - - PhSetControlTheme(PhSipWindow, L"explorer"); - PhSipUpdateThemeData(); -} - -VOID PhSipOnDestroy( - VOID - ) -{ - PhUnregisterCallback( - &PhProcessesUpdatedEvent, - &ProcessesUpdatedRegistration - ); - - if (CurrentSection) - PhSetStringSetting2(L"SysInfoWindowSection", &CurrentSection->Name); - else - PhSetStringSetting(L"SysInfoWindowSection", L""); - - PhSetIntegerSetting(L"SysInfoWindowAlwaysOnTop", AlwaysOnTop); - - PhSaveWindowPlacementToSetting(L"SysInfoWindowPosition", L"SysInfoWindowSize", PhSipWindow); - PhSipSaveWindowState(); -} - -VOID PhSipOnNcDestroy( - VOID - ) -{ - ULONG i; - PPH_SYSINFO_SECTION section; - - for (i = 0; i < SectionList->Count; i++) - { - section = SectionList->Items[i]; - PhSipDestroySection(section); - } - - PhDereferenceObject(SectionList); - SectionList = NULL; - PhSipDeleteParameters(); - - if (ThemeData) - { - CloseThemeData(ThemeData); - ThemeData = NULL; - } - - PhDeleteLayoutManager(&WindowLayoutManager); - PostQuitMessage(0); -} - -VOID PhSipOnShowWindow( - _In_ BOOLEAN Showing, - _In_ ULONG State - ) -{ - RECT buttonRect; - RECT clientRect; - PH_STRINGREF sectionName; - PPH_SYSINFO_SECTION section; - - if (SectionList) - return; - - SectionList = PhCreateList(8); - PhSipInitializeParameters(); - CurrentView = SysInfoSummaryView; - CurrentSection = NULL; - - PhSipCreateInternalSection(L"CPU", 0, PhSipCpuSectionCallback); - PhSipCreateInternalSection(L"Memory", 0, PhSipMemorySectionCallback); - PhSipCreateInternalSection(L"I/O", 0, PhSipIoSectionCallback); - - if (PhPluginsEnabled) - { - PH_PLUGIN_SYSINFO_POINTERS pointers; - - pointers.WindowHandle = PhSipWindow; - pointers.CreateSection = PhSipCreateSection; - pointers.FindSection = PhSipFindSection; - pointers.EnterSectionView = PhSipEnterSectionView; - pointers.RestoreSummaryView = PhSipRestoreSummaryView; - PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackSystemInformationInitializing), &pointers); - } - - SeparatorControl = CreateWindow( - L"STATIC", - NULL, - WS_CHILD | SS_OWNERDRAW, - 0, - 0, - 3, - 3, - PhSipWindow, - (HMENU)IDC_SEPARATOR, - PhInstanceHandle, - NULL - ); - - RestoreSummaryControl = CreateWindow( - L"STATIC", - NULL, - WS_CHILD | WS_TABSTOP | SS_OWNERDRAW | SS_NOTIFY, - 0, - 0, - 3, - 3, - PhSipWindow, - (HMENU)IDC_RESET, - PhInstanceHandle, - NULL - ); - - SetWindowSubclass(RestoreSummaryControl, PhSipPanelHookWndProc, 0, 0); - RestoreSummaryControlHot = FALSE; - - EnableThemeDialogTexture(ContainerControl, ETDT_ENABLETAB); - - GetWindowRect(GetDlgItem(PhSipWindow, IDOK), &buttonRect); - MapWindowPoints(NULL, PhSipWindow, (POINT *)&buttonRect, 2); - GetClientRect(PhSipWindow, &clientRect); - - MinimumSize.left = 0; - MinimumSize.top = 0; - MinimumSize.right = WindowsVersion >= WINDOWS_VISTA ? 430 : 370; // XP doesn't have the Memory Lists group - MinimumSize.bottom = 290; - MapDialogRect(PhSipWindow, &MinimumSize); - - MinimumSize.right += CurrentParameters.PanelWidth; - MinimumSize.right += GetSystemMetrics(SM_CXFRAME) * 2; - MinimumSize.bottom += GetSystemMetrics(SM_CYFRAME) * 2; - - if (SectionList->Count != 0) - { - ULONG newMinimumHeight; - - newMinimumHeight = - GetSystemMetrics(SM_CYCAPTION) + - CurrentParameters.WindowPadding + - CurrentParameters.MinimumGraphHeight * SectionList->Count + - CurrentParameters.MinimumGraphHeight + // Back button - CurrentParameters.GraphPadding * SectionList->Count + - CurrentParameters.WindowPadding + - clientRect.bottom - buttonRect.top + - GetSystemMetrics(SM_CYFRAME) * 2; - - if (newMinimumHeight > (ULONG)MinimumSize.bottom) - MinimumSize.bottom = newMinimumHeight; - } - - PhLoadWindowPlacementFromSetting(L"SysInfoWindowPosition", L"SysInfoWindowSize", PhSipWindow); - - if (PhGetIntegerSetting(L"SysInfoWindowState") == SW_MAXIMIZE) - ShowWindow(PhSipWindow, SW_MAXIMIZE); - - if (InitialSectionName) - PhInitializeStringRefLongHint(§ionName, InitialSectionName); - else - sectionName = PhaGetStringSetting(L"SysInfoWindowSection")->sr; - - if (sectionName.Length != 0 && (section = PhSipFindSection(§ionName))) - { - PhSipEnterSectionView(section); - } - - AlwaysOnTop = (BOOLEAN)PhGetIntegerSetting(L"SysInfoWindowAlwaysOnTop"); - Button_SetCheck(GetDlgItem(PhSipWindow, IDC_ALWAYSONTOP), AlwaysOnTop ? BST_CHECKED : BST_UNCHECKED); - PhSipSetAlwaysOnTop(); - - PhSipOnSize(); - PhSipOnUserMessage(SI_MSG_SYSINFO_UPDATE, 0, 0); -} - -BOOLEAN PhSipOnSysCommand( - _In_ ULONG Type, - _In_ LONG CursorScreenX, - _In_ LONG CursorScreenY - ) -{ - switch (Type) - { - case SC_MINIMIZE: - { - // Save the current window state because we may not have a chance to later. - PhSipSaveWindowState(); - } - break; - } - - return FALSE; -} - -VOID PhSipOnSize( - VOID - ) -{ - PhLayoutManagerLayout(&WindowLayoutManager); - - if (SectionList && SectionList->Count != 0) - { - if (CurrentView == SysInfoSummaryView) - PhSipLayoutSummaryView(); - else if (CurrentView == SysInfoSectionView) - PhSipLayoutSectionView(); - } -} - -VOID PhSipOnSizing( - _In_ ULONG Edge, - _In_ PRECT DragRectangle - ) -{ - PhResizingMinimumSize(DragRectangle, Edge, MinimumSize.right, MinimumSize.bottom); -} - -VOID PhSipOnThemeChanged( - VOID - ) -{ - PhSipUpdateThemeData(); -} - -VOID PhSipOnCommand( - _In_ ULONG Id, - _In_ ULONG Code - ) -{ - switch (Id) - { - case IDCANCEL: - case IDOK: - DestroyWindow(PhSipWindow); - break; - case IDC_ALWAYSONTOP: - { - AlwaysOnTop = Button_GetCheck(GetDlgItem(PhSipWindow, IDC_ALWAYSONTOP)) == BST_CHECKED; - PhSipSetAlwaysOnTop(); - } - break; - case IDC_RESET: - { - if (Code == STN_CLICKED) - { - PhSipRestoreSummaryView(); - } - } - break; - case IDC_BACK: - { - PhSipRestoreSummaryView(); - } - break; - case IDC_REFRESH: - { - ProcessHacker_Refresh(PhMainWndHandle); - } - break; - case IDC_PAUSE: - { - ProcessHacker_SetUpdateAutomatically(PhMainWndHandle, !ProcessHacker_GetUpdateAutomatically(PhMainWndHandle)); - } - break; - case IDC_MAXSCREEN: - { - static WINDOWPLACEMENT windowLayout = { sizeof(WINDOWPLACEMENT) }; - ULONG windowStyle = (ULONG)GetWindowLongPtr(PhSipWindow, GWL_STYLE); - - if (windowStyle & WS_OVERLAPPEDWINDOW) - { - MONITORINFO info = { sizeof(MONITORINFO) }; - - if ( - GetWindowPlacement(PhSipWindow, &windowLayout) && - GetMonitorInfo(MonitorFromWindow(PhSipWindow, MONITOR_DEFAULTTOPRIMARY), &info) - ) - { - ULONG padding = CurrentParameters.WindowPadding / 2; - PhSetWindowStyle(PhSipWindow, WS_OVERLAPPEDWINDOW, 0); - SetWindowPos( - PhSipWindow, - HWND_TOPMOST, - info.rcMonitor.left - padding, - info.rcMonitor.top - padding, - (info.rcMonitor.right - info.rcMonitor.left) + padding * 2, - (info.rcMonitor.bottom - info.rcMonitor.top) + padding * 2, - SWP_NOOWNERZORDER | SWP_FRAMECHANGED - ); - } - } - else - { - PhSetWindowStyle(PhSipWindow, WS_OVERLAPPEDWINDOW, WS_OVERLAPPEDWINDOW); - SetWindowPlacement(PhSipWindow, &windowLayout); - SetWindowPos(PhSipWindow, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_FRAMECHANGED); - } - } - break; - } - - if (SectionList && Id >= ID_DIGIT1 && Id <= ID_DIGIT9) - { - ULONG index; - - index = Id - ID_DIGIT1; - - if (index < SectionList->Count) - PhSipEnterSectionView(SectionList->Items[index]); - } - - if (SectionList && Code == STN_CLICKED) - { - ULONG i; - PPH_SYSINFO_SECTION section; - - for (i = 0; i < SectionList->Count; i++) - { - section = SectionList->Items[i]; - - if (Id == section->PanelId) - { - PhSipEnterSectionView(section); - break; - } - } - } -} - -BOOLEAN PhSipOnNotify( - _In_ NMHDR *Header, - _Out_ LRESULT *Result - ) -{ - switch (Header->code) - { - case GCN_GETDRAWINFO: - { - PPH_GRAPH_GETDRAWINFO getDrawInfo = (PPH_GRAPH_GETDRAWINFO)Header; - PPH_GRAPH_DRAW_INFO drawInfo = getDrawInfo->DrawInfo; - ULONG i; - PPH_SYSINFO_SECTION section; - - for (i = 0; i < SectionList->Count; i++) - { - section = SectionList->Items[i]; - - if (getDrawInfo->Header.hwndFrom == section->GraphHandle) - { - section->Callback(section, SysInfoGraphGetDrawInfo, drawInfo, 0); - - if (CurrentView == SysInfoSectionView) - { - drawInfo->Flags &= ~(PH_GRAPH_USE_GRID_X | PH_GRAPH_USE_GRID_Y | PH_GRAPH_LABEL_MAX_Y); - } - else - { - ULONG badWidth = CurrentParameters.PanelWidth; - - // Try not to draw max data point labels that will get covered by the - // fade-out part of the graph. - if (badWidth < drawInfo->Width) - drawInfo->LabelMaxYIndexLimit = (drawInfo->Width - badWidth) / 2; - else - drawInfo->LabelMaxYIndexLimit = -1; - } - - break; - } - } - } - break; - case GCN_GETTOOLTIPTEXT: - { - PPH_GRAPH_GETTOOLTIPTEXT getTooltipText = (PPH_GRAPH_GETTOOLTIPTEXT)Header; - ULONG i; - PPH_SYSINFO_SECTION section; - - if (getTooltipText->Index < getTooltipText->TotalCount) - { - for (i = 0; i < SectionList->Count; i++) - { - section = SectionList->Items[i]; - - if (getTooltipText->Header.hwndFrom == section->GraphHandle) - { - PH_SYSINFO_GRAPH_GET_TOOLTIP_TEXT graphGetTooltipText; - - graphGetTooltipText.Index = getTooltipText->Index; - PhInitializeEmptyStringRef(&graphGetTooltipText.Text); - - section->Callback(section, SysInfoGraphGetTooltipText, &graphGetTooltipText, 0); - - getTooltipText->Text = graphGetTooltipText.Text; - - break; - } - } - } - } - break; - case GCN_DRAWPANEL: - { - PPH_GRAPH_DRAWPANEL drawPanel = (PPH_GRAPH_DRAWPANEL)Header; - ULONG i; - PPH_SYSINFO_SECTION section; - - if (CurrentView == SysInfoSummaryView) - { - for (i = 0; i < SectionList->Count; i++) - { - section = SectionList->Items[i]; - - if (drawPanel->Header.hwndFrom == section->GraphHandle) - { - PhSipDrawPanel(section, drawPanel->hdc, &drawPanel->Rect); - break; - } - } - } - } - break; - case GCN_MOUSEEVENT: - { - PPH_GRAPH_MOUSEEVENT mouseEvent = (PPH_GRAPH_MOUSEEVENT)Header; - ULONG i; - PPH_SYSINFO_SECTION section; - - for (i = 0; i < SectionList->Count; i++) - { - section = SectionList->Items[i]; - - if (mouseEvent->Header.hwndFrom == section->GraphHandle) - { - if (mouseEvent->Message == WM_LBUTTONDOWN) - { - PhSipEnterSectionView(section); - } - - break; - } - } - } - break; - } - - return FALSE; -} - -BOOLEAN PhSipOnDrawItem( - _In_ ULONG_PTR Id, - _In_ DRAWITEMSTRUCT *DrawItemStruct - ) -{ - ULONG i; - PPH_SYSINFO_SECTION section; - - if (Id == IDC_RESET) - { - PhSipDrawRestoreSummaryPanel(DrawItemStruct->hDC, &DrawItemStruct->rcItem); - return TRUE; - } - else if (Id == IDC_SEPARATOR) - { - PhSipDrawSeparator(DrawItemStruct->hDC, &DrawItemStruct->rcItem); - return TRUE; - } - - for (i = 0; i < SectionList->Count; i++) - { - section = SectionList->Items[i]; - - if (Id == section->PanelId) - { - PhSipDrawPanel(section, DrawItemStruct->hDC, &DrawItemStruct->rcItem); - return TRUE; - } - } - - return FALSE; -} - -VOID PhSipOnUserMessage( - _In_ ULONG Message, - _In_ ULONG_PTR WParam, - _In_ ULONG_PTR LParam - ) -{ - switch (Message) - { - case SI_MSG_SYSINFO_ACTIVATE: - { - PWSTR sectionName = (PWSTR)WParam; - - if (SectionList && sectionName) - { - PH_STRINGREF sectionNameSr; - PPH_SYSINFO_SECTION section; - - PhInitializeStringRefLongHint(§ionNameSr, sectionName); - section = PhSipFindSection(§ionNameSr); - - if (section) - PhSipEnterSectionView(section); - else - PhSipRestoreSummaryView(); - } - - if (IsIconic(PhSipWindow)) - ShowWindow(PhSipWindow, SW_RESTORE); - else - ShowWindow(PhSipWindow, SW_SHOW); - - SetForegroundWindow(PhSipWindow); - } - break; - case SI_MSG_SYSINFO_UPDATE: - { - ULONG i; - PPH_SYSINFO_SECTION section; - - if (SectionList) - { - for (i = 0; i < SectionList->Count; i++) - { - section = SectionList->Items[i]; - - section->Callback(section, SysInfoTick, NULL, NULL); - - section->GraphState.Valid = FALSE; - section->GraphState.TooltipIndex = -1; - Graph_MoveGrid(section->GraphHandle, 1); - Graph_Draw(section->GraphHandle); - Graph_UpdateTooltip(section->GraphHandle); - InvalidateRect(section->GraphHandle, NULL, FALSE); - - InvalidateRect(section->PanelHandle, NULL, FALSE); - } - } - } - break; - case SI_MSG_SYSINFO_CHANGE_SETTINGS: - { - ULONG i; - PPH_SYSINFO_SECTION section; - PH_GRAPH_OPTIONS options; - - if (SectionList) - { - for (i = 0; i < SectionList->Count; i++) - { - section = SectionList->Items[i]; - Graph_GetOptions(section->GraphHandle, &options); - options.FadeOutBackColor = CurrentParameters.GraphBackColor; - Graph_SetOptions(section->GraphHandle, &options); - } - } - - InvalidateRect(PhSipWindow, NULL, TRUE); - } - break; - } -} - -VOID PhSiNotifyChangeSettings( - VOID - ) -{ - HWND window; - - PhSipUpdateColorParameters(); - - window = PhSipWindow; - - if (window) - PostMessage(window, SI_MSG_SYSINFO_CHANGE_SETTINGS, 0, 0); -} - -VOID PhSiSetColorsGraphDrawInfo( - _Out_ PPH_GRAPH_DRAW_INFO DrawInfo, - _In_ COLORREF Color1, - _In_ COLORREF Color2 - ) -{ - static PH_QUEUED_LOCK lock = PH_QUEUED_LOCK_INIT; - static ULONG lastDpi = -1; - static HFONT iconTitleFont; - - // Get the appropriate fonts. - - if (DrawInfo->Flags & PH_GRAPH_LABEL_MAX_Y) - { - PhAcquireQueuedLockExclusive(&lock); - - if (lastDpi != PhGlobalDpi) - { - LOGFONT logFont; - - if (SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(LOGFONT), &logFont, 0)) - { - logFont.lfHeight += PhMultiplyDivide(1, PhGlobalDpi, 72); - iconTitleFont = CreateFontIndirect(&logFont); - } - - if (!iconTitleFont) - iconTitleFont = PhApplicationFont; - - lastDpi = PhGlobalDpi; - } - - DrawInfo->LabelYFont = iconTitleFont; - - PhReleaseQueuedLockExclusive(&lock); - } - - DrawInfo->TextFont = PhApplicationFont; - - // Set up the colors. - - switch (PhCsGraphColorMode) - { - case 0: // New colors - DrawInfo->BackColor = RGB(0xef, 0xef, 0xef); - DrawInfo->LineColor1 = PhHalveColorBrightness(Color1); - DrawInfo->LineBackColor1 = PhMakeColorBrighter(Color1, 125); - DrawInfo->LineColor2 = PhHalveColorBrightness(Color2); - DrawInfo->LineBackColor2 = PhMakeColorBrighter(Color2, 125); - DrawInfo->GridColor = RGB(0xc7, 0xc7, 0xc7); - DrawInfo->LabelYColor = RGB(0xa0, 0x60, 0x20); - DrawInfo->TextColor = RGB(0x00, 0x00, 0x00); - DrawInfo->TextBoxColor = RGB(0xe7, 0xe7, 0xe7); - break; - case 1: // Old colors - DrawInfo->BackColor = RGB(0x00, 0x00, 0x00); - DrawInfo->LineColor1 = Color1; - DrawInfo->LineBackColor1 = PhHalveColorBrightness(Color1); - DrawInfo->LineColor2 = Color2; - DrawInfo->LineBackColor2 = PhHalveColorBrightness(Color2); - DrawInfo->GridColor = RGB(0x00, 0x57, 0x00); - DrawInfo->LabelYColor = RGB(0xd0, 0xa0, 0x70); - DrawInfo->TextColor = RGB(0x00, 0xff, 0x00); - DrawInfo->TextBoxColor = RGB(0x00, 0x22, 0x00); - break; - } -} - -PPH_STRING PhSiSizeLabelYFunction( - _In_ PPH_GRAPH_DRAW_INFO DrawInfo, - _In_ ULONG DataIndex, - _In_ FLOAT Value, - _In_ FLOAT Parameter - ) -{ - ULONG64 size; - - size = (ULONG64)(Value * Parameter); - - if (size != 0) - { - PH_FORMAT format; - - format.Type = SizeFormatType | FormatUsePrecision | FormatUseRadix; - format.Precision = 0; - format.Radix = -1; - format.u.Size = size; - - return PhFormat(&format, 1, 0); - } - else - { - return PhReferenceEmptyString(); - } -} - -VOID PhSipRegisterDialog( - _In_ HWND DialogWindowHandle - ) -{ - if (!PhSipDialogList) - PhSipDialogList = PhCreateList(4); - - PhAddItemList(PhSipDialogList, DialogWindowHandle); -} - -VOID PhSipUnregisterDialog( - _In_ HWND DialogWindowHandle - ) -{ - ULONG index; - - if ((index = PhFindItemList(PhSipDialogList, DialogWindowHandle)) != -1) - PhRemoveItemList(PhSipDialogList, index); -} - -VOID PhSipInitializeParameters( - VOID - ) -{ - LOGFONT logFont; - HDC hdc; - TEXTMETRIC textMetrics; - HFONT originalFont; - - memset(&CurrentParameters, 0, sizeof(PH_SYSINFO_PARAMETERS)); - - CurrentParameters.SysInfoWindowHandle = PhSipWindow; - CurrentParameters.ContainerWindowHandle = ContainerControl; - - if (SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(LOGFONT), &logFont, 0)) - { - CurrentParameters.Font = CreateFontIndirect(&logFont); - } - else - { - CurrentParameters.Font = PhApplicationFont; - GetObject(PhApplicationFont, sizeof(LOGFONT), &logFont); - } - - hdc = GetDC(PhSipWindow); - - logFont.lfHeight -= PhMultiplyDivide(3, GetDeviceCaps(hdc, LOGPIXELSY), 72); - CurrentParameters.MediumFont = CreateFontIndirect(&logFont); - - logFont.lfHeight -= PhMultiplyDivide(3, GetDeviceCaps(hdc, LOGPIXELSY), 72); - CurrentParameters.LargeFont = CreateFontIndirect(&logFont); - - PhSipUpdateColorParameters(); - - CurrentParameters.ColorSetupFunction = PhSiSetColorsGraphDrawInfo; - - originalFont = SelectObject(hdc, CurrentParameters.Font); - GetTextMetrics(hdc, &textMetrics); - CurrentParameters.FontHeight = textMetrics.tmHeight; - CurrentParameters.FontAverageWidth = textMetrics.tmAveCharWidth; - - SelectObject(hdc, CurrentParameters.MediumFont); - GetTextMetrics(hdc, &textMetrics); - CurrentParameters.MediumFontHeight = textMetrics.tmHeight; - CurrentParameters.MediumFontAverageWidth = textMetrics.tmAveCharWidth; - - SelectObject(hdc, originalFont); - - // Internal padding and other values - CurrentParameters.PanelPadding = PH_SCALE_DPI(PH_SYSINFO_PANEL_PADDING); - CurrentParameters.WindowPadding = PH_SCALE_DPI(PH_SYSINFO_WINDOW_PADDING); - CurrentParameters.GraphPadding = PH_SCALE_DPI(PH_SYSINFO_GRAPH_PADDING); - CurrentParameters.SmallGraphWidth = PH_SCALE_DPI(PH_SYSINFO_SMALL_GRAPH_WIDTH); - CurrentParameters.SmallGraphPadding = PH_SCALE_DPI(PH_SYSINFO_SMALL_GRAPH_PADDING); - CurrentParameters.SeparatorWidth = PH_SCALE_DPI(PH_SYSINFO_SEPARATOR_WIDTH); - CurrentParameters.CpuPadding = PH_SCALE_DPI(PH_SYSINFO_CPU_PADDING); - CurrentParameters.MemoryPadding = PH_SCALE_DPI(PH_SYSINFO_MEMORY_PADDING); - - CurrentParameters.MinimumGraphHeight = - CurrentParameters.PanelPadding + - CurrentParameters.MediumFontHeight + - CurrentParameters.PanelPadding; - - CurrentParameters.SectionViewGraphHeight = - CurrentParameters.PanelPadding + - CurrentParameters.MediumFontHeight + - CurrentParameters.PanelPadding + - CurrentParameters.FontHeight + - 2 + - CurrentParameters.FontHeight + - CurrentParameters.PanelPadding + - 2; - - CurrentParameters.PanelWidth = CurrentParameters.MediumFontAverageWidth * 10; - - ReleaseDC(PhSipWindow, hdc); -} - -VOID PhSipDeleteParameters( - VOID - ) -{ - if (CurrentParameters.Font) - DeleteObject(CurrentParameters.Font); - if (CurrentParameters.MediumFont) - DeleteObject(CurrentParameters.MediumFont); - if (CurrentParameters.LargeFont) - DeleteObject(CurrentParameters.LargeFont); -} - -VOID PhSipUpdateColorParameters( - VOID - ) -{ - switch (PhCsGraphColorMode) - { - case 0: // New colors - CurrentParameters.GraphBackColor = RGB(0xef, 0xef, 0xef); - CurrentParameters.PanelForeColor = RGB(0x00, 0x00, 0x00); - break; - case 1: // Old colors - CurrentParameters.GraphBackColor = RGB(0x00, 0x00, 0x00); - CurrentParameters.PanelForeColor = RGB(0xff, 0xff, 0xff); - break; - } -} - -PPH_SYSINFO_SECTION PhSipCreateSection( - _In_ PPH_SYSINFO_SECTION Template - ) -{ - PPH_SYSINFO_SECTION section; - PH_GRAPH_OPTIONS options; - - section = PhAllocate(sizeof(PH_SYSINFO_SECTION)); - memset(section, 0, sizeof(PH_SYSINFO_SECTION)); - - section->Name = Template->Name; - section->Flags = Template->Flags; - section->Callback = Template->Callback; - section->Context = Template->Context; - - section->GraphHandle = CreateWindow( - PH_GRAPH_CLASSNAME, - NULL, - WS_VISIBLE | WS_CHILD | WS_BORDER | WS_TABSTOP | GC_STYLE_FADEOUT | GC_STYLE_DRAW_PANEL, - 0, - 0, - 3, - 3, - PhSipWindow, - NULL, - PhInstanceHandle, - NULL - ); - PhInitializeGraphState(§ion->GraphState); - section->Parameters = &CurrentParameters; - - Graph_GetOptions(section->GraphHandle, &options); - options.FadeOutBackColor = CurrentParameters.GraphBackColor; - options.FadeOutWidth = CurrentParameters.PanelWidth + PH_SYSINFO_FADE_ADD; - options.DefaultCursor = LoadCursor(NULL, IDC_HAND); - Graph_SetOptions(section->GraphHandle, &options); - Graph_SetTooltip(section->GraphHandle, TRUE); - - section->PanelId = IDDYNAMIC + SectionList->Count * 2 + 2; - section->PanelHandle = CreateWindow( - L"STATIC", - NULL, - WS_CHILD | SS_OWNERDRAW | SS_NOTIFY, - 0, - 0, - 3, - 3, - PhSipWindow, - (HMENU)(ULONG_PTR)section->PanelId, - PhInstanceHandle, - NULL - ); - - SetWindowSubclass(section->GraphHandle, PhSipGraphHookWndProc, 0, (ULONG_PTR)section); - SetWindowSubclass(section->PanelHandle, PhSipPanelHookWndProc, 0, (ULONG_PTR)section); - - PhAddItemList(SectionList, section); - - section->Callback(section, SysInfoCreate, NULL, NULL); - - return section; -} - -VOID PhSipDestroySection( - _In_ PPH_SYSINFO_SECTION Section - ) -{ - Section->Callback(Section, SysInfoDestroy, NULL, NULL); - - PhDeleteGraphState(&Section->GraphState); - PhFree(Section); -} - -PPH_SYSINFO_SECTION PhSipFindSection( - _In_ PPH_STRINGREF Name - ) -{ - ULONG i; - PPH_SYSINFO_SECTION section; - - for (i = 0; i < SectionList->Count; i++) - { - section = SectionList->Items[i]; - - if (PhEqualStringRef(§ion->Name, Name, TRUE)) - return section; - } - - return NULL; -} - -PPH_SYSINFO_SECTION PhSipCreateInternalSection( - _In_ PWSTR Name, - _In_ ULONG Flags, - _In_ PPH_SYSINFO_SECTION_CALLBACK Callback - ) -{ - PH_SYSINFO_SECTION section; - - memset(§ion, 0, sizeof(PH_SYSINFO_SECTION)); - PhInitializeStringRef(§ion.Name, Name); - section.Flags = Flags; - section.Callback = Callback; - - return PhSipCreateSection(§ion); -} - -VOID PhSipDrawRestoreSummaryPanel( - _In_ HDC hdc, - _In_ PRECT Rect - ) -{ - FillRect(hdc, Rect, GetSysColorBrush(COLOR_3DFACE)); - - if (RestoreSummaryControlHot || RestoreSummaryControlHasFocus) - { - if (ThemeHasItemBackground) - { - DrawThemeBackground( - ThemeData, - hdc, - TVP_TREEITEM, - TREIS_HOT, - Rect, - Rect - ); - } - else - { - FillRect(hdc, Rect, GetSysColorBrush(COLOR_WINDOW)); - } - } - - SetTextColor(hdc, GetSysColor(COLOR_WINDOWTEXT)); - SetBkMode(hdc, TRANSPARENT); - - SelectObject(hdc, CurrentParameters.MediumFont); - DrawText(hdc, L"Back", 4, Rect, DT_CENTER | DT_VCENTER | DT_SINGLELINE); -} - -VOID PhSipDrawSeparator( - _In_ HDC hdc, - _In_ PRECT Rect - ) -{ - RECT rect; - - rect = *Rect; - FillRect(hdc, &rect, GetSysColorBrush(COLOR_3DHIGHLIGHT)); - rect.left += 1; - FillRect(hdc, &rect, GetSysColorBrush(COLOR_3DSHADOW)); -} - -VOID PhSipDrawPanel( - _In_ PPH_SYSINFO_SECTION Section, - _In_ HDC hdc, - _In_ PRECT Rect - ) -{ - PH_SYSINFO_DRAW_PANEL sysInfoDrawPanel; - - if (CurrentView == SysInfoSectionView) - FillRect(hdc, Rect, GetSysColorBrush(COLOR_3DFACE)); - - sysInfoDrawPanel.hdc = hdc; - sysInfoDrawPanel.Rect = *Rect; - sysInfoDrawPanel.Rect.right = CurrentParameters.PanelWidth; - sysInfoDrawPanel.CustomDraw = FALSE; - - sysInfoDrawPanel.Title = NULL; - sysInfoDrawPanel.SubTitle = NULL; - sysInfoDrawPanel.SubTitleOverflow = NULL; - - Section->Callback(Section, SysInfoGraphDrawPanel, &sysInfoDrawPanel, NULL); - - if (!sysInfoDrawPanel.CustomDraw) - { - sysInfoDrawPanel.Rect.right = Rect->right; - PhSipDefaultDrawPanel(Section, &sysInfoDrawPanel); - } - - PhClearReference(&sysInfoDrawPanel.Title); - PhClearReference(&sysInfoDrawPanel.SubTitle); - PhClearReference(&sysInfoDrawPanel.SubTitleOverflow); -} - -VOID PhSipDefaultDrawPanel( - _In_ PPH_SYSINFO_SECTION Section, - _In_ PPH_SYSINFO_DRAW_PANEL DrawPanel - ) -{ - HDC hdc; - RECT rect; - ULONG flags; - - hdc = DrawPanel->hdc; - - if (ThemeHasItemBackground) - { - if (CurrentView == SysInfoSectionView) - { - INT stateId; - - stateId = -1; - - if (Section->GraphHot || Section->PanelHot || Section->HasFocus) - { - if (Section == CurrentSection) - stateId = TREIS_HOTSELECTED; - else - stateId = TREIS_HOT; - } - else if (Section == CurrentSection) - { - stateId = TREIS_SELECTED; - } - - if (stateId != -1) - { - RECT themeRect; - - themeRect = DrawPanel->Rect; - themeRect.left -= 2; // remove left edge - - DrawThemeBackground( - ThemeData, - hdc, - TVP_TREEITEM, - stateId, - &themeRect, - &DrawPanel->Rect - ); - } - } - else if (Section->HasFocus) - { - DrawThemeBackground( - ThemeData, - hdc, - TVP_TREEITEM, - TREIS_HOT, - &DrawPanel->Rect, - &DrawPanel->Rect - ); - } - } - else - { - if (CurrentView == SysInfoSectionView) - { - HBRUSH brush; - - brush = NULL; - - if (Section->GraphHot || Section->PanelHot || Section->HasFocus) - { - brush = GetSysColorBrush(COLOR_WINDOW); // TODO: Use a different color - } - else if (Section == CurrentSection) - { - brush = GetSysColorBrush(COLOR_WINDOW); - } - - if (brush) - { - FillRect(hdc, &DrawPanel->Rect, brush); - } - } - } - - if (CurrentView == SysInfoSummaryView) - SetTextColor(hdc, CurrentParameters.PanelForeColor); - else - SetTextColor(hdc, GetSysColor(COLOR_WINDOWTEXT)); - - SetBkMode(hdc, TRANSPARENT); - - rect.left = CurrentParameters.SmallGraphPadding + CurrentParameters.PanelPadding; - rect.top = CurrentParameters.PanelPadding; - rect.right = CurrentParameters.PanelWidth; - rect.bottom = DrawPanel->Rect.bottom; - - flags = DT_NOPREFIX; - - if (CurrentView == SysInfoSummaryView) - rect.right = DrawPanel->Rect.right; // allow the text to overflow - else - flags |= DT_END_ELLIPSIS; - - if (DrawPanel->Title) - { - SelectObject(hdc, CurrentParameters.MediumFont); - DrawText(hdc, DrawPanel->Title->Buffer, (ULONG)DrawPanel->Title->Length / 2, &rect, flags | DT_SINGLELINE); - } - - if (DrawPanel->SubTitle) - { - RECT measureRect; - - rect.top += CurrentParameters.MediumFontHeight + CurrentParameters.PanelPadding; - SelectObject(hdc, CurrentParameters.Font); - - measureRect = rect; - DrawText(hdc, DrawPanel->SubTitle->Buffer, (ULONG)DrawPanel->SubTitle->Length / 2, &measureRect, (flags & ~DT_END_ELLIPSIS) | DT_CALCRECT); - - if (measureRect.right <= rect.right || !DrawPanel->SubTitleOverflow) - { - // Text fits; draw normally. - DrawText(hdc, DrawPanel->SubTitle->Buffer, (ULONG)DrawPanel->SubTitle->Length / 2, &rect, flags); - } - else - { - // Text doesn't fit; draw the alternative text. - DrawText(hdc, DrawPanel->SubTitleOverflow->Buffer, (ULONG)DrawPanel->SubTitleOverflow->Length / 2, &rect, flags); - } - } -} - -VOID PhSipLayoutSummaryView( - VOID - ) -{ - RECT buttonRect; - RECT clientRect; - ULONG availableHeight; - ULONG availableWidth; - ULONG graphHeight; - ULONG i; - PPH_SYSINFO_SECTION section; - HDWP deferHandle; - ULONG y; - - GetWindowRect(GetDlgItem(PhSipWindow, IDOK), &buttonRect); - MapWindowPoints(NULL, PhSipWindow, (POINT *)&buttonRect, 2); - GetClientRect(PhSipWindow, &clientRect); - - availableHeight = buttonRect.top - CurrentParameters.WindowPadding * 2; - availableWidth = clientRect.right - CurrentParameters.WindowPadding * 2; - graphHeight = (availableHeight - CurrentParameters.GraphPadding * (SectionList->Count - 1)) / SectionList->Count; - - deferHandle = BeginDeferWindowPos(SectionList->Count); - y = CurrentParameters.WindowPadding; - - for (i = 0; i < SectionList->Count; i++) - { - section = SectionList->Items[i]; - - deferHandle = DeferWindowPos( - deferHandle, - section->GraphHandle, - NULL, - CurrentParameters.WindowPadding, - y, - availableWidth, - graphHeight, - SWP_NOACTIVATE | SWP_NOZORDER - ); - y += graphHeight + CurrentParameters.GraphPadding; - - section->GraphState.Valid = FALSE; - } - - EndDeferWindowPos(deferHandle); -} - -VOID PhSipLayoutSectionView( - VOID - ) -{ - RECT buttonRect; - RECT clientRect; - ULONG availableHeight; - ULONG availableWidth; - ULONG graphHeight; - ULONG i; - PPH_SYSINFO_SECTION section; - HDWP deferHandle; - ULONG y; - ULONG containerLeft; - - GetWindowRect(GetDlgItem(PhSipWindow, IDOK), &buttonRect); - MapWindowPoints(NULL, PhSipWindow, (POINT *)&buttonRect, 2); - GetClientRect(PhSipWindow, &clientRect); - - availableHeight = buttonRect.top - CurrentParameters.WindowPadding * 2; - availableWidth = clientRect.right - CurrentParameters.WindowPadding * 2; - graphHeight = (availableHeight - CurrentParameters.SmallGraphPadding * SectionList->Count) / (SectionList->Count + 1); - - if (graphHeight > CurrentParameters.SectionViewGraphHeight) - graphHeight = CurrentParameters.SectionViewGraphHeight; - - deferHandle = BeginDeferWindowPos(SectionList->Count * 2 + 3); - y = CurrentParameters.WindowPadding; - - for (i = 0; i < SectionList->Count; i++) - { - section = SectionList->Items[i]; - - deferHandle = DeferWindowPos( - deferHandle, - section->GraphHandle, - NULL, - CurrentParameters.WindowPadding, - y, - CurrentParameters.SmallGraphWidth, - graphHeight, - SWP_NOACTIVATE | SWP_NOZORDER - ); - - deferHandle = DeferWindowPos( - deferHandle, - section->PanelHandle, - NULL, - CurrentParameters.WindowPadding + CurrentParameters.SmallGraphWidth, - y, - CurrentParameters.SmallGraphPadding + CurrentParameters.PanelWidth, - graphHeight, - SWP_NOACTIVATE | SWP_NOZORDER - ); - InvalidateRect(section->PanelHandle, NULL, TRUE); - - y += graphHeight + CurrentParameters.SmallGraphPadding; - - section->GraphState.Valid = FALSE; - } - - deferHandle = DeferWindowPos( - deferHandle, - RestoreSummaryControl, - NULL, - CurrentParameters.WindowPadding, - y, - CurrentParameters.SmallGraphWidth + CurrentParameters.SmallGraphPadding + CurrentParameters.PanelWidth, - graphHeight, - SWP_NOACTIVATE | SWP_NOZORDER - ); - InvalidateRect(RestoreSummaryControl, NULL, TRUE); - - deferHandle = DeferWindowPos( - deferHandle, - SeparatorControl, - NULL, - CurrentParameters.WindowPadding + CurrentParameters.SmallGraphWidth + CurrentParameters.SmallGraphPadding + CurrentParameters.PanelWidth + CurrentParameters.WindowPadding - 7, - 0, - CurrentParameters.SeparatorWidth, - CurrentParameters.WindowPadding + availableHeight, - SWP_NOACTIVATE | SWP_NOZORDER - ); - - containerLeft = CurrentParameters.WindowPadding + CurrentParameters.SmallGraphWidth + CurrentParameters.SmallGraphPadding + CurrentParameters.PanelWidth + CurrentParameters.WindowPadding - 7 + CurrentParameters.SeparatorWidth; - deferHandle = DeferWindowPos( - deferHandle, - ContainerControl, - NULL, - containerLeft, - 0, - clientRect.right - containerLeft, - CurrentParameters.WindowPadding + availableHeight, - SWP_NOACTIVATE | SWP_NOZORDER - ); - - EndDeferWindowPos(deferHandle); - - if (CurrentSection && CurrentSection->DialogHandle) - { - SetWindowPos( - CurrentSection->DialogHandle, - NULL, - CurrentParameters.WindowPadding, - CurrentParameters.WindowPadding, - clientRect.right - containerLeft - CurrentParameters.WindowPadding - CurrentParameters.WindowPadding, - availableHeight, - SWP_NOACTIVATE | SWP_NOZORDER - ); - } -} - -VOID PhSipEnterSectionView( - _In_ PPH_SYSINFO_SECTION NewSection - ) -{ - ULONG i; - PPH_SYSINFO_SECTION section; - BOOLEAN fromSummaryView; - PPH_SYSINFO_SECTION oldSection; - HDWP deferHandle; - HDWP containerDeferHandle; - - if (CurrentSection == NewSection) - return; - - fromSummaryView = CurrentView == SysInfoSummaryView; - CurrentView = SysInfoSectionView; - oldSection = CurrentSection; - CurrentSection = NewSection; - - deferHandle = BeginDeferWindowPos(SectionList->Count + 4); - containerDeferHandle = BeginDeferWindowPos(SectionList->Count); - - PhSipEnterSectionViewInner(NewSection, fromSummaryView, &deferHandle, &containerDeferHandle); - PhSipLayoutSectionView(); - - for (i = 0; i < SectionList->Count; i++) - { - section = SectionList->Items[i]; - - if (section != NewSection) - PhSipEnterSectionViewInner(section, fromSummaryView, &deferHandle, &containerDeferHandle); - } - - deferHandle = DeferWindowPos(deferHandle, ContainerControl, NULL, 0, 0, 0, 0, SWP_SHOWWINDOW_ONLY); - deferHandle = DeferWindowPos(deferHandle, RestoreSummaryControl, NULL, 0, 0, 0, 0, SWP_SHOWWINDOW_ONLY); - deferHandle = DeferWindowPos(deferHandle, SeparatorControl, NULL, 0, 0, 0, 0, SWP_SHOWWINDOW_ONLY); - deferHandle = DeferWindowPos(deferHandle, GetDlgItem(PhSipWindow, IDC_INSTRUCTION), NULL, 0, 0, 0, 0, SWP_HIDEWINDOW_ONLY); - - EndDeferWindowPos(deferHandle); - EndDeferWindowPos(containerDeferHandle); - - if (oldSection) - InvalidateRect(oldSection->PanelHandle, NULL, TRUE); - - InvalidateRect(NewSection->PanelHandle, NULL, TRUE); - - if (NewSection->DialogHandle) - RedrawWindow(NewSection->DialogHandle, NULL, NULL, RDW_ERASE | RDW_INVALIDATE | RDW_ALLCHILDREN | RDW_UPDATENOW); -} - -VOID PhSipEnterSectionViewInner( - _In_ PPH_SYSINFO_SECTION Section, - _In_ BOOLEAN FromSummaryView, - _Inout_ HDWP *DeferHandle, - _Inout_ HDWP *ContainerDeferHandle - ) -{ - Section->HasFocus = FALSE; - Section->Callback(Section, SysInfoViewChanging, (PVOID)CurrentView, CurrentSection); - - if (FromSummaryView) - { - PhSetWindowStyle(Section->GraphHandle, GC_STYLE_FADEOUT | GC_STYLE_DRAW_PANEL, 0); - *DeferHandle = DeferWindowPos(*DeferHandle, Section->PanelHandle, NULL, 0, 0, 0, 0, SWP_SHOWWINDOW_ONLY); - } - - if (Section == CurrentSection && !Section->DialogHandle) - PhSipCreateSectionDialog(Section); - - if (Section->DialogHandle) - { - if (Section == CurrentSection) - *ContainerDeferHandle = DeferWindowPos(*ContainerDeferHandle, Section->DialogHandle, NULL, 0, 0, 0, 0, SWP_SHOWWINDOW_ONLY | SWP_NOREDRAW); - else - *ContainerDeferHandle = DeferWindowPos(*ContainerDeferHandle, Section->DialogHandle, NULL, 0, 0, 0, 0, SWP_HIDEWINDOW_ONLY | SWP_NOREDRAW); - } -} - -VOID PhSipRestoreSummaryView( - VOID - ) -{ - ULONG i; - PPH_SYSINFO_SECTION section; - - if (CurrentView == SysInfoSummaryView) - return; - - CurrentView = SysInfoSummaryView; - CurrentSection = NULL; - - for (i = 0; i < SectionList->Count; i++) - { - section = SectionList->Items[i]; - - section->Callback(section, SysInfoViewChanging, (PVOID)CurrentView, NULL); - - PhSetWindowStyle(section->GraphHandle, GC_STYLE_FADEOUT | GC_STYLE_DRAW_PANEL, GC_STYLE_FADEOUT | GC_STYLE_DRAW_PANEL); - ShowWindow(section->PanelHandle, SW_HIDE); - - if (section->DialogHandle) - ShowWindow(section->DialogHandle, SW_HIDE); - } - - ShowWindow(ContainerControl, SW_HIDE); - ShowWindow(RestoreSummaryControl, SW_HIDE); - ShowWindow(SeparatorControl, SW_HIDE); - ShowWindow(GetDlgItem(PhSipWindow, IDC_INSTRUCTION), SW_SHOW); - - PhSipLayoutSummaryView(); -} - -VOID PhSipCreateSectionDialog( - _In_ PPH_SYSINFO_SECTION Section - ) -{ - PH_SYSINFO_CREATE_DIALOG createDialog; - - memset(&createDialog, 0, sizeof(PH_SYSINFO_CREATE_DIALOG)); - - if (Section->Callback(Section, SysInfoCreateDialog, &createDialog, NULL)) - { - if (!createDialog.CustomCreate) - { - Section->DialogHandle = PhCreateDialogFromTemplate( - ContainerControl, - DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD, - createDialog.Instance, - createDialog.Template, - createDialog.DialogProc, - createDialog.Parameter - ); - } - } -} - -LRESULT CALLBACK PhSipGraphHookWndProc( - _In_ HWND hwnd, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam, - _In_ UINT_PTR uIdSubclass, - _In_ ULONG_PTR dwRefData - ) -{ - PPH_SYSINFO_SECTION section = (PPH_SYSINFO_SECTION)dwRefData; - - switch (uMsg) - { - case WM_DESTROY: - RemoveWindowSubclass(hwnd, PhSipGraphHookWndProc, uIdSubclass); - break; - case WM_SETFOCUS: - section->HasFocus = TRUE; - - if (CurrentView == SysInfoSummaryView) - { - Graph_Draw(section->GraphHandle); - InvalidateRect(section->GraphHandle, NULL, FALSE); - } - else - { - InvalidateRect(section->PanelHandle, NULL, TRUE); - } - - break; - case WM_KILLFOCUS: - section->HasFocus = FALSE; - - if (CurrentView == SysInfoSummaryView) - { - Graph_Draw(section->GraphHandle); - InvalidateRect(section->GraphHandle, NULL, FALSE); - } - else - { - InvalidateRect(section->PanelHandle, NULL, TRUE); - } - - break; - case WM_GETDLGCODE: - if (wParam == VK_SPACE || wParam == VK_RETURN || - wParam == VK_UP || wParam == VK_DOWN || - wParam == VK_LEFT || wParam == VK_RIGHT) - return DLGC_WANTALLKEYS; - break; - case WM_KEYDOWN: - { - if (wParam == VK_SPACE || wParam == VK_RETURN) - { - PhSipEnterSectionView(section); - } - else if (wParam == VK_UP || wParam == VK_LEFT || - wParam == VK_DOWN || wParam == VK_RIGHT) - { - ULONG i; - - for (i = 0; i < SectionList->Count; i++) - { - if (SectionList->Items[i] == section) - { - if ((wParam == VK_UP || wParam == VK_LEFT) && i > 0) - { - SetFocus(((PPH_SYSINFO_SECTION)SectionList->Items[i - 1])->GraphHandle); - } - else if (wParam == VK_DOWN || wParam == VK_RIGHT) - { - if (i < SectionList->Count - 1) - SetFocus(((PPH_SYSINFO_SECTION)SectionList->Items[i + 1])->GraphHandle); - else - SetFocus(RestoreSummaryControl); - } - - break; - } - } - } - } - break; - case WM_MOUSEMOVE: - { - TRACKMOUSEEVENT trackMouseEvent; - - trackMouseEvent.cbSize = sizeof(TRACKMOUSEEVENT); - trackMouseEvent.dwFlags = TME_LEAVE; - trackMouseEvent.hwndTrack = hwnd; - trackMouseEvent.dwHoverTime = 0; - TrackMouseEvent(&trackMouseEvent); - - if (!(section->GraphHot || section->PanelHot)) - { - section->GraphHot = TRUE; - InvalidateRect(section->PanelHandle, NULL, TRUE); - } - else - { - section->GraphHot = TRUE; - } - } - break; - case WM_MOUSELEAVE: - { - if (!section->PanelHot) - { - section->GraphHot = FALSE; - InvalidateRect(section->PanelHandle, NULL, TRUE); - } - else - { - section->GraphHot = FALSE; - } - - section->HasFocus = FALSE; - - if (CurrentView == SysInfoSummaryView) - { - Graph_Draw(section->GraphHandle); - InvalidateRect(section->GraphHandle, NULL, FALSE); - } - } - break; - case WM_NCLBUTTONDOWN: - { - PhSipEnterSectionView(section); - } - break; - case WM_UPDATEUISTATE: - { - switch (LOWORD(wParam)) - { - case UIS_SET: - if (HIWORD(wParam) & UISF_HIDEFOCUS) - section->HideFocus = TRUE; - break; - case UIS_CLEAR: - if (HIWORD(wParam) & UISF_HIDEFOCUS) - section->HideFocus = FALSE; - break; - case UIS_INITIALIZE: - section->HideFocus = !!(HIWORD(wParam) & UISF_HIDEFOCUS); - break; - } - } - break; - } - - return DefSubclassProc(hwnd, uMsg, wParam, lParam); -} - -LRESULT CALLBACK PhSipPanelHookWndProc( - _In_ HWND hwnd, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam, - _In_ UINT_PTR uIdSubclass, - _In_ ULONG_PTR dwRefData - ) -{ - PPH_SYSINFO_SECTION section = (PPH_SYSINFO_SECTION)dwRefData; - - switch (uMsg) - { - case WM_DESTROY: - RemoveWindowSubclass(hwnd, PhSipPanelHookWndProc, uIdSubclass); - break; - case WM_SETFOCUS: - { - if (!section) - { - RestoreSummaryControlHasFocus = TRUE; - InvalidateRect(hwnd, NULL, TRUE); - } - } - break; - case WM_KILLFOCUS: - { - if (!section) - { - RestoreSummaryControlHasFocus = FALSE; - InvalidateRect(hwnd, NULL, TRUE); - } - } - break; - case WM_SETCURSOR: - { - SetCursor(LoadCursor(NULL, IDC_HAND)); - } - return TRUE; - case WM_GETDLGCODE: - if (wParam == VK_SPACE || wParam == VK_RETURN || - wParam == VK_UP || wParam == VK_DOWN || - wParam == VK_LEFT || wParam == VK_RIGHT) - return DLGC_WANTALLKEYS; - break; - case WM_KEYDOWN: - { - if (wParam == VK_SPACE || wParam == VK_RETURN) - { - if (section) - PhSipEnterSectionView(section); - else - PhSipRestoreSummaryView(); - } - else if (wParam == VK_UP || wParam == VK_LEFT) - { - if (!section && SectionList->Count != 0) - { - SetFocus(((PPH_SYSINFO_SECTION)SectionList->Items[SectionList->Count - 1])->GraphHandle); - } - } - } - break; - case WM_MOUSEMOVE: - { - TRACKMOUSEEVENT trackMouseEvent; - - trackMouseEvent.cbSize = sizeof(TRACKMOUSEEVENT); - trackMouseEvent.dwFlags = TME_LEAVE; - trackMouseEvent.hwndTrack = hwnd; - trackMouseEvent.dwHoverTime = 0; - TrackMouseEvent(&trackMouseEvent); - - if (section) - { - if (!(section->GraphHot || section->PanelHot)) - { - section->PanelHot = TRUE; - InvalidateRect(section->PanelHandle, NULL, TRUE); - } - else - { - section->PanelHot = TRUE; - } - } - else - { - RestoreSummaryControlHot = TRUE; - InvalidateRect(RestoreSummaryControl, NULL, TRUE); - } - } - break; - case WM_MOUSELEAVE: - { - if (section) - { - section->HasFocus = FALSE; - - if (!section->GraphHot) - { - section->PanelHot = FALSE; - InvalidateRect(section->PanelHandle, NULL, TRUE); - } - else - { - section->PanelHot = FALSE; - } - } - else - { - RestoreSummaryControlHasFocus = FALSE; - RestoreSummaryControlHot = FALSE; - InvalidateRect(RestoreSummaryControl, NULL, TRUE); - } - } - break; - } - - return DefSubclassProc(hwnd, uMsg, wParam, lParam); -} - -VOID PhSipUpdateThemeData( - VOID - ) -{ - if (ThemeData) - { - CloseThemeData(ThemeData); - ThemeData = NULL; - } - - ThemeData = OpenThemeData(PhSipWindow, L"TREEVIEW"); - - if (ThemeData) - { - ThemeHasItemBackground = !!IsThemePartDefined(ThemeData, TVP_TREEITEM, 0); - } - else - { - ThemeHasItemBackground = FALSE; - } -} - -VOID PhSipSetAlwaysOnTop( - VOID - ) -{ - SetFocus(PhSipWindow); // HACK - SetWindowPos doesn't work properly without this - SetWindowPos(PhSipWindow, AlwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST, 0, 0, 0, 0, - SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE); -} - -VOID PhSipSaveWindowState( - VOID - ) -{ - WINDOWPLACEMENT placement = { sizeof(placement) }; - - GetWindowPlacement(PhSipWindow, &placement); - - if (placement.showCmd == SW_NORMAL) - PhSetIntegerSetting(L"SysInfoWindowState", SW_NORMAL); - else if (placement.showCmd == SW_MAXIMIZE) - PhSetIntegerSetting(L"SysInfoWindowState", SW_MAXIMIZE); -} - -VOID NTAPI PhSipSysInfoUpdateHandler( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - PostMessage(PhSipWindow, SI_MSG_SYSINFO_UPDATE, 0, 0); -} - -PPH_STRING PhSipFormatSizeWithPrecision( - _In_ ULONG64 Size, - _In_ USHORT Precision - ) -{ - PH_FORMAT format; - - format.Type = SizeFormatType | FormatUsePrecision; - format.Precision = Precision; - format.u.Size = Size; - - return PH_AUTO(PhFormat(&format, 1, 0)); -} +/* + * Process Hacker - + * System Information window + * + * Copyright (C) 2011-2016 wj32 + * Copyright (C) 2017 dmex + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +/* + * This file contains the System Information framework. The "framework" handles creation, layout and + * events for the top-level window itself. It manages the list of sections. + * + * A section is an object that provides information to the user about a type of system resource. The + * CPU, Memory and I/O sections are added automatically to every System Information window. Plugins + * can also add sections to the window. There are two views: summary and section. In summary view, + * rows of graphs are displayed in the window, one graph for each section. The section is + * responsible for providing the graph data and any text to draw on the left-hand side of the graph. + * In section view, the graphs become mini-graphs on the left-hand side of the window. The section + * displays its own embedded dialog in the remaining space. Any controls contained in this dialog, + * including graphs, are the responsibility of the section. + * + * Users can enter section view by: + * * Clicking on a graph or mini-graph. + * * Pressing a number from 1 to 9. + * * Using the tab or arrow keys to select a graph and pressing space or enter. + * + * Users can return to summary view by: + * * Clicking "Back" on the left-hand side of the window. + * * Pressing Backspace. + * * Using the tab or arrow keys to select "Back" and pressing space or enter. + */ + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +static HANDLE PhSipThread = NULL; +HWND PhSipWindow = NULL; +static PPH_LIST PhSipDialogList = NULL; +static PH_EVENT InitializedEvent = PH_EVENT_INIT; +static PWSTR InitialSectionName; +static PH_LAYOUT_MANAGER WindowLayoutManager; +static RECT MinimumSize; +static PH_CALLBACK_REGISTRATION ProcessesUpdatedRegistration; + +static PPH_LIST SectionList; +static PH_SYSINFO_PARAMETERS CurrentParameters; +static PH_SYSINFO_VIEW_TYPE CurrentView; +static PPH_SYSINFO_SECTION CurrentSection; +static HWND ContainerControl; +static HWND SeparatorControl; +static HWND RestoreSummaryControl; +static BOOLEAN RestoreSummaryControlHot; +static BOOLEAN RestoreSummaryControlHasFocus; + +static HTHEME ThemeData; +static BOOLEAN ThemeHasItemBackground; + +static BOOLEAN AlwaysOnTop; + +VOID PhShowSystemInformationDialog( + _In_opt_ PWSTR SectionName + ) +{ + InitialSectionName = SectionName; + + if (!PhSipWindow) + { + if (!(PhSipThread = PhCreateThread(0, PhSipSysInfoThreadStart, NULL))) + { + PhShowStatus(PhMainWndHandle, L"Unable to create the system information window", 0, GetLastError()); + return; + } + + PhWaitForEvent(&InitializedEvent, NULL); + } + + SendMessage(PhSipWindow, SI_MSG_SYSINFO_ACTIVATE, (WPARAM)SectionName, 0); +} + +NTSTATUS PhSipSysInfoThreadStart( + _In_ PVOID Parameter + ) +{ + PH_AUTO_POOL autoPool; + BOOL result; + MSG message; + HACCEL acceleratorTable; + BOOLEAN processed; + + PhInitializeAutoPool(&autoPool); + + PhSipWindow = CreateDialog( + PhInstanceHandle, + MAKEINTRESOURCE(IDD_SYSINFO), + NULL, + PhSipSysInfoDialogProc + ); + + PhSetEvent(&InitializedEvent); + + acceleratorTable = LoadAccelerators(PhInstanceHandle, MAKEINTRESOURCE(IDR_SYSINFO_ACCEL)); + + while (result = GetMessage(&message, NULL, 0, 0)) + { + if (result == -1) + break; + + processed = FALSE; + + if ( + message.hwnd == PhSipWindow || + IsChild(PhSipWindow, message.hwnd) + ) + { + if (TranslateAccelerator(PhSipWindow, acceleratorTable, &message)) + processed = TRUE; + } + + if (!processed && PhSipDialogList) + { + ULONG i; + + for (i = 0; i < PhSipDialogList->Count; i++) + { + if (IsDialogMessage((HWND)PhSipDialogList->Items[i], &message)) + { + processed = TRUE; + break; + } + } + } + + if (!processed) + { + if (!IsDialogMessage(PhSipWindow, &message)) + { + TranslateMessage(&message); + DispatchMessage(&message); + } + } + + PhDrainAutoPool(&autoPool); + } + + PhDeleteAutoPool(&autoPool); + PhResetEvent(&InitializedEvent); + NtClose(PhSipThread); + + PhSipWindow = NULL; + PhSipThread = NULL; + + if (PhSipDialogList) + { + PhDereferenceObject(PhSipDialogList); + PhSipDialogList = NULL; + } + + return STATUS_SUCCESS; +} + +INT_PTR CALLBACK PhSipSysInfoDialogProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + switch (uMsg) + { + case WM_INITDIALOG: + { + PhSipWindow = hwndDlg; + PhSipOnInitDialog(); + } + break; + case WM_DESTROY: + { + PhSipOnDestroy(); + } + break; + case WM_NCDESTROY: + { + PhSipOnNcDestroy(); + } + break; + case WM_SHOWWINDOW: + { + PhSipOnShowWindow(!!wParam, (ULONG)lParam); + } + break; + case WM_SYSCOMMAND: + { + if (PhSipOnSysCommand((ULONG)wParam, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))) + return 0; + } + break; + case WM_SIZE: + { + PhSipOnSize(); + } + break; + case WM_SIZING: + { + PhSipOnSizing((ULONG)wParam, (PRECT)lParam); + } + break; + case WM_THEMECHANGED: + { + PhSipOnThemeChanged(); + } + break; + case WM_COMMAND: + { + PhSipOnCommand(LOWORD(wParam), HIWORD(wParam)); + } + break; + case WM_NOTIFY: + { + LRESULT result; + + if (PhSipOnNotify((NMHDR *)lParam, &result)) + { + SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, result); + return TRUE; + } + } + break; + case WM_DRAWITEM: + { + if (PhSipOnDrawItem(wParam, (DRAWITEMSTRUCT *)lParam)) + return TRUE; + } + break; + } + + if (uMsg >= SI_MSG_SYSINFO_FIRST && uMsg <= SI_MSG_SYSINFO_LAST) + { + PhSipOnUserMessage(uMsg, wParam, lParam); + } + + return FALSE; +} + +INT_PTR CALLBACK PhSipContainerDialogProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + return FALSE; +} + +VOID PhSipOnInitDialog( + VOID + ) +{ + PhInitializeLayoutManager(&WindowLayoutManager, PhSipWindow); + + PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(PhSipWindow, IDC_INSTRUCTION), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_BOTTOM); + PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(PhSipWindow, IDC_ALWAYSONTOP), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); + PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(PhSipWindow, IDOK), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); + + PhRegisterCallback( + &PhProcessesUpdatedEvent, + PhSipSysInfoUpdateHandler, + NULL, + &ProcessesUpdatedRegistration + ); + + ContainerControl = CreateDialog( + PhInstanceHandle, + MAKEINTRESOURCE(IDD_CONTAINER), + PhSipWindow, + PhSipContainerDialogProc + ); + + PhSetControlTheme(PhSipWindow, L"explorer"); + PhSipUpdateThemeData(); +} + +VOID PhSipOnDestroy( + VOID + ) +{ + PhUnregisterCallback( + &PhProcessesUpdatedEvent, + &ProcessesUpdatedRegistration + ); + + if (CurrentSection) + PhSetStringSetting2(L"SysInfoWindowSection", &CurrentSection->Name); + else + PhSetStringSetting(L"SysInfoWindowSection", L""); + + PhSetIntegerSetting(L"SysInfoWindowAlwaysOnTop", AlwaysOnTop); + + PhSaveWindowPlacementToSetting(L"SysInfoWindowPosition", L"SysInfoWindowSize", PhSipWindow); + PhSipSaveWindowState(); +} + +VOID PhSipOnNcDestroy( + VOID + ) +{ + ULONG i; + PPH_SYSINFO_SECTION section; + + for (i = 0; i < SectionList->Count; i++) + { + section = SectionList->Items[i]; + PhSipDestroySection(section); + } + + PhDereferenceObject(SectionList); + SectionList = NULL; + PhSipDeleteParameters(); + + if (ThemeData) + { + CloseThemeData(ThemeData); + ThemeData = NULL; + } + + PhDeleteLayoutManager(&WindowLayoutManager); + PostQuitMessage(0); +} + +VOID PhSipOnShowWindow( + _In_ BOOLEAN Showing, + _In_ ULONG State + ) +{ + RECT buttonRect; + RECT clientRect; + PH_STRINGREF sectionName; + PPH_SYSINFO_SECTION section; + + if (SectionList) + return; + + SectionList = PhCreateList(8); + PhSipInitializeParameters(); + CurrentView = SysInfoSummaryView; + CurrentSection = NULL; + + PhSipCreateInternalSection(L"CPU", 0, PhSipCpuSectionCallback); + PhSipCreateInternalSection(L"Memory", 0, PhSipMemorySectionCallback); + PhSipCreateInternalSection(L"I/O", 0, PhSipIoSectionCallback); + + if (PhPluginsEnabled) + { + PH_PLUGIN_SYSINFO_POINTERS pointers; + + pointers.WindowHandle = PhSipWindow; + pointers.CreateSection = PhSipCreateSection; + pointers.FindSection = PhSipFindSection; + pointers.EnterSectionView = PhSipEnterSectionView; + pointers.RestoreSummaryView = PhSipRestoreSummaryView; + PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackSystemInformationInitializing), &pointers); + } + + SeparatorControl = CreateWindow( + L"STATIC", + NULL, + WS_CHILD | SS_OWNERDRAW, + 0, + 0, + 3, + 3, + PhSipWindow, + (HMENU)IDC_SEPARATOR, + PhInstanceHandle, + NULL + ); + + RestoreSummaryControl = CreateWindow( + L"STATIC", + NULL, + WS_CHILD | WS_TABSTOP | SS_OWNERDRAW | SS_NOTIFY, + 0, + 0, + 3, + 3, + PhSipWindow, + (HMENU)IDC_RESET, + PhInstanceHandle, + NULL + ); + + SetWindowSubclass(RestoreSummaryControl, PhSipPanelHookWndProc, 0, 0); + RestoreSummaryControlHot = FALSE; + + EnableThemeDialogTexture(ContainerControl, ETDT_ENABLETAB); + + GetWindowRect(GetDlgItem(PhSipWindow, IDOK), &buttonRect); + MapWindowPoints(NULL, PhSipWindow, (POINT *)&buttonRect, 2); + GetClientRect(PhSipWindow, &clientRect); + + MinimumSize.left = 0; + MinimumSize.top = 0; + MinimumSize.right = WindowsVersion >= WINDOWS_VISTA ? 430 : 370; // XP doesn't have the Memory Lists group + MinimumSize.bottom = 290; + MapDialogRect(PhSipWindow, &MinimumSize); + + MinimumSize.right += CurrentParameters.PanelWidth; + MinimumSize.right += GetSystemMetrics(SM_CXFRAME) * 2; + MinimumSize.bottom += GetSystemMetrics(SM_CYFRAME) * 2; + + if (SectionList->Count != 0) + { + ULONG newMinimumHeight; + + newMinimumHeight = + GetSystemMetrics(SM_CYCAPTION) + + CurrentParameters.WindowPadding + + CurrentParameters.MinimumGraphHeight * SectionList->Count + + CurrentParameters.MinimumGraphHeight + // Back button + CurrentParameters.GraphPadding * SectionList->Count + + CurrentParameters.WindowPadding + + clientRect.bottom - buttonRect.top + + GetSystemMetrics(SM_CYFRAME) * 2; + + if (newMinimumHeight > (ULONG)MinimumSize.bottom) + MinimumSize.bottom = newMinimumHeight; + } + + PhLoadWindowPlacementFromSetting(L"SysInfoWindowPosition", L"SysInfoWindowSize", PhSipWindow); + + if (PhGetIntegerSetting(L"SysInfoWindowState") == SW_MAXIMIZE) + ShowWindow(PhSipWindow, SW_MAXIMIZE); + + if (InitialSectionName) + PhInitializeStringRefLongHint(§ionName, InitialSectionName); + else + sectionName = PhaGetStringSetting(L"SysInfoWindowSection")->sr; + + if (sectionName.Length != 0 && (section = PhSipFindSection(§ionName))) + { + PhSipEnterSectionView(section); + } + + AlwaysOnTop = (BOOLEAN)PhGetIntegerSetting(L"SysInfoWindowAlwaysOnTop"); + Button_SetCheck(GetDlgItem(PhSipWindow, IDC_ALWAYSONTOP), AlwaysOnTop ? BST_CHECKED : BST_UNCHECKED); + PhSipSetAlwaysOnTop(); + + PhSipOnSize(); + PhSipOnUserMessage(SI_MSG_SYSINFO_UPDATE, 0, 0); +} + +BOOLEAN PhSipOnSysCommand( + _In_ ULONG Type, + _In_ LONG CursorScreenX, + _In_ LONG CursorScreenY + ) +{ + switch (Type) + { + case SC_MINIMIZE: + { + // Save the current window state because we may not have a chance to later. + PhSipSaveWindowState(); + } + break; + } + + return FALSE; +} + +VOID PhSipOnSize( + VOID + ) +{ + PhLayoutManagerLayout(&WindowLayoutManager); + + if (SectionList && SectionList->Count != 0) + { + if (CurrentView == SysInfoSummaryView) + PhSipLayoutSummaryView(); + else if (CurrentView == SysInfoSectionView) + PhSipLayoutSectionView(); + } +} + +VOID PhSipOnSizing( + _In_ ULONG Edge, + _In_ PRECT DragRectangle + ) +{ + PhResizingMinimumSize(DragRectangle, Edge, MinimumSize.right, MinimumSize.bottom); +} + +VOID PhSipOnThemeChanged( + VOID + ) +{ + PhSipUpdateThemeData(); +} + +VOID PhSipOnCommand( + _In_ ULONG Id, + _In_ ULONG Code + ) +{ + switch (Id) + { + case IDCANCEL: + case IDOK: + DestroyWindow(PhSipWindow); + break; + case IDC_ALWAYSONTOP: + { + AlwaysOnTop = Button_GetCheck(GetDlgItem(PhSipWindow, IDC_ALWAYSONTOP)) == BST_CHECKED; + PhSipSetAlwaysOnTop(); + } + break; + case IDC_RESET: + { + if (Code == STN_CLICKED) + { + PhSipRestoreSummaryView(); + } + } + break; + case IDC_BACK: + { + PhSipRestoreSummaryView(); + } + break; + case IDC_REFRESH: + { + ProcessHacker_Refresh(PhMainWndHandle); + } + break; + case IDC_PAUSE: + { + ProcessHacker_SetUpdateAutomatically(PhMainWndHandle, !ProcessHacker_GetUpdateAutomatically(PhMainWndHandle)); + } + break; + case IDC_MAXSCREEN: + { + static WINDOWPLACEMENT windowLayout = { sizeof(WINDOWPLACEMENT) }; + ULONG windowStyle = (ULONG)GetWindowLongPtr(PhSipWindow, GWL_STYLE); + + if (windowStyle & WS_OVERLAPPEDWINDOW) + { + MONITORINFO info = { sizeof(MONITORINFO) }; + + if ( + GetWindowPlacement(PhSipWindow, &windowLayout) && + GetMonitorInfo(MonitorFromWindow(PhSipWindow, MONITOR_DEFAULTTOPRIMARY), &info) + ) + { + ULONG padding = CurrentParameters.WindowPadding / 2; + PhSetWindowStyle(PhSipWindow, WS_OVERLAPPEDWINDOW, 0); + SetWindowPos( + PhSipWindow, + HWND_TOPMOST, + info.rcMonitor.left - padding, + info.rcMonitor.top - padding, + (info.rcMonitor.right - info.rcMonitor.left) + padding * 2, + (info.rcMonitor.bottom - info.rcMonitor.top) + padding * 2, + SWP_NOOWNERZORDER | SWP_FRAMECHANGED + ); + } + } + else + { + PhSetWindowStyle(PhSipWindow, WS_OVERLAPPEDWINDOW, WS_OVERLAPPEDWINDOW); + SetWindowPlacement(PhSipWindow, &windowLayout); + SetWindowPos(PhSipWindow, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_FRAMECHANGED); + } + } + break; + } + + if (SectionList && Id >= ID_DIGIT1 && Id <= ID_DIGIT9) + { + ULONG index; + + index = Id - ID_DIGIT1; + + if (index < SectionList->Count) + PhSipEnterSectionView(SectionList->Items[index]); + } + + if (SectionList && Code == STN_CLICKED) + { + ULONG i; + PPH_SYSINFO_SECTION section; + + for (i = 0; i < SectionList->Count; i++) + { + section = SectionList->Items[i]; + + if (Id == section->PanelId) + { + PhSipEnterSectionView(section); + break; + } + } + } +} + +BOOLEAN PhSipOnNotify( + _In_ NMHDR *Header, + _Out_ LRESULT *Result + ) +{ + switch (Header->code) + { + case GCN_GETDRAWINFO: + { + PPH_GRAPH_GETDRAWINFO getDrawInfo = (PPH_GRAPH_GETDRAWINFO)Header; + PPH_GRAPH_DRAW_INFO drawInfo = getDrawInfo->DrawInfo; + ULONG i; + PPH_SYSINFO_SECTION section; + + for (i = 0; i < SectionList->Count; i++) + { + section = SectionList->Items[i]; + + if (getDrawInfo->Header.hwndFrom == section->GraphHandle) + { + section->Callback(section, SysInfoGraphGetDrawInfo, drawInfo, 0); + + if (CurrentView == SysInfoSectionView) + { + drawInfo->Flags &= ~(PH_GRAPH_USE_GRID_X | PH_GRAPH_USE_GRID_Y | PH_GRAPH_LABEL_MAX_Y); + } + else + { + ULONG badWidth = CurrentParameters.PanelWidth; + + // Try not to draw max data point labels that will get covered by the + // fade-out part of the graph. + if (badWidth < drawInfo->Width) + drawInfo->LabelMaxYIndexLimit = (drawInfo->Width - badWidth) / 2; + else + drawInfo->LabelMaxYIndexLimit = -1; + } + + break; + } + } + } + break; + case GCN_GETTOOLTIPTEXT: + { + PPH_GRAPH_GETTOOLTIPTEXT getTooltipText = (PPH_GRAPH_GETTOOLTIPTEXT)Header; + ULONG i; + PPH_SYSINFO_SECTION section; + + if (getTooltipText->Index < getTooltipText->TotalCount) + { + for (i = 0; i < SectionList->Count; i++) + { + section = SectionList->Items[i]; + + if (getTooltipText->Header.hwndFrom == section->GraphHandle) + { + PH_SYSINFO_GRAPH_GET_TOOLTIP_TEXT graphGetTooltipText; + + graphGetTooltipText.Index = getTooltipText->Index; + PhInitializeEmptyStringRef(&graphGetTooltipText.Text); + + section->Callback(section, SysInfoGraphGetTooltipText, &graphGetTooltipText, 0); + + getTooltipText->Text = graphGetTooltipText.Text; + + break; + } + } + } + } + break; + case GCN_DRAWPANEL: + { + PPH_GRAPH_DRAWPANEL drawPanel = (PPH_GRAPH_DRAWPANEL)Header; + ULONG i; + PPH_SYSINFO_SECTION section; + + if (CurrentView == SysInfoSummaryView) + { + for (i = 0; i < SectionList->Count; i++) + { + section = SectionList->Items[i]; + + if (drawPanel->Header.hwndFrom == section->GraphHandle) + { + PhSipDrawPanel(section, drawPanel->hdc, &drawPanel->Rect); + break; + } + } + } + } + break; + case GCN_MOUSEEVENT: + { + PPH_GRAPH_MOUSEEVENT mouseEvent = (PPH_GRAPH_MOUSEEVENT)Header; + ULONG i; + PPH_SYSINFO_SECTION section; + + for (i = 0; i < SectionList->Count; i++) + { + section = SectionList->Items[i]; + + if (mouseEvent->Header.hwndFrom == section->GraphHandle) + { + if (mouseEvent->Message == WM_LBUTTONDOWN) + { + PhSipEnterSectionView(section); + } + + break; + } + } + } + break; + } + + return FALSE; +} + +BOOLEAN PhSipOnDrawItem( + _In_ ULONG_PTR Id, + _In_ DRAWITEMSTRUCT *DrawItemStruct + ) +{ + ULONG i; + PPH_SYSINFO_SECTION section; + + if (Id == IDC_RESET) + { + PhSipDrawRestoreSummaryPanel(DrawItemStruct->hDC, &DrawItemStruct->rcItem); + return TRUE; + } + else if (Id == IDC_SEPARATOR) + { + PhSipDrawSeparator(DrawItemStruct->hDC, &DrawItemStruct->rcItem); + return TRUE; + } + + for (i = 0; i < SectionList->Count; i++) + { + section = SectionList->Items[i]; + + if (Id == section->PanelId) + { + PhSipDrawPanel(section, DrawItemStruct->hDC, &DrawItemStruct->rcItem); + return TRUE; + } + } + + return FALSE; +} + +VOID PhSipOnUserMessage( + _In_ ULONG Message, + _In_ ULONG_PTR WParam, + _In_ ULONG_PTR LParam + ) +{ + switch (Message) + { + case SI_MSG_SYSINFO_ACTIVATE: + { + PWSTR sectionName = (PWSTR)WParam; + + if (SectionList && sectionName) + { + PH_STRINGREF sectionNameSr; + PPH_SYSINFO_SECTION section; + + PhInitializeStringRefLongHint(§ionNameSr, sectionName); + section = PhSipFindSection(§ionNameSr); + + if (section) + PhSipEnterSectionView(section); + else + PhSipRestoreSummaryView(); + } + + if (IsIconic(PhSipWindow)) + ShowWindow(PhSipWindow, SW_RESTORE); + else + ShowWindow(PhSipWindow, SW_SHOW); + + SetForegroundWindow(PhSipWindow); + } + break; + case SI_MSG_SYSINFO_UPDATE: + { + ULONG i; + PPH_SYSINFO_SECTION section; + + if (SectionList) + { + for (i = 0; i < SectionList->Count; i++) + { + section = SectionList->Items[i]; + + section->Callback(section, SysInfoTick, NULL, NULL); + + section->GraphState.Valid = FALSE; + section->GraphState.TooltipIndex = -1; + Graph_MoveGrid(section->GraphHandle, 1); + Graph_Draw(section->GraphHandle); + Graph_UpdateTooltip(section->GraphHandle); + InvalidateRect(section->GraphHandle, NULL, FALSE); + + InvalidateRect(section->PanelHandle, NULL, FALSE); + } + } + } + break; + case SI_MSG_SYSINFO_CHANGE_SETTINGS: + { + ULONG i; + PPH_SYSINFO_SECTION section; + PH_GRAPH_OPTIONS options; + + if (SectionList) + { + for (i = 0; i < SectionList->Count; i++) + { + section = SectionList->Items[i]; + Graph_GetOptions(section->GraphHandle, &options); + options.FadeOutBackColor = CurrentParameters.GraphBackColor; + Graph_SetOptions(section->GraphHandle, &options); + } + } + + InvalidateRect(PhSipWindow, NULL, TRUE); + } + break; + } +} + +VOID PhSiNotifyChangeSettings( + VOID + ) +{ + HWND window; + + PhSipUpdateColorParameters(); + + window = PhSipWindow; + + if (window) + PostMessage(window, SI_MSG_SYSINFO_CHANGE_SETTINGS, 0, 0); +} + +VOID PhSiSetColorsGraphDrawInfo( + _Out_ PPH_GRAPH_DRAW_INFO DrawInfo, + _In_ COLORREF Color1, + _In_ COLORREF Color2 + ) +{ + static PH_QUEUED_LOCK lock = PH_QUEUED_LOCK_INIT; + static ULONG lastDpi = -1; + static HFONT iconTitleFont; + + // Get the appropriate fonts. + + if (DrawInfo->Flags & PH_GRAPH_LABEL_MAX_Y) + { + PhAcquireQueuedLockExclusive(&lock); + + if (lastDpi != PhGlobalDpi) + { + LOGFONT logFont; + + if (SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(LOGFONT), &logFont, 0)) + { + logFont.lfHeight += PhMultiplyDivide(1, PhGlobalDpi, 72); + iconTitleFont = CreateFontIndirect(&logFont); + } + + if (!iconTitleFont) + iconTitleFont = PhApplicationFont; + + lastDpi = PhGlobalDpi; + } + + DrawInfo->LabelYFont = iconTitleFont; + + PhReleaseQueuedLockExclusive(&lock); + } + + DrawInfo->TextFont = PhApplicationFont; + + // Set up the colors. + + switch (PhCsGraphColorMode) + { + case 0: // New colors + DrawInfo->BackColor = RGB(0xef, 0xef, 0xef); + DrawInfo->LineColor1 = PhHalveColorBrightness(Color1); + DrawInfo->LineBackColor1 = PhMakeColorBrighter(Color1, 125); + DrawInfo->LineColor2 = PhHalveColorBrightness(Color2); + DrawInfo->LineBackColor2 = PhMakeColorBrighter(Color2, 125); + DrawInfo->GridColor = RGB(0xc7, 0xc7, 0xc7); + DrawInfo->LabelYColor = RGB(0xa0, 0x60, 0x20); + DrawInfo->TextColor = RGB(0x00, 0x00, 0x00); + DrawInfo->TextBoxColor = RGB(0xe7, 0xe7, 0xe7); + break; + case 1: // Old colors + DrawInfo->BackColor = RGB(0x00, 0x00, 0x00); + DrawInfo->LineColor1 = Color1; + DrawInfo->LineBackColor1 = PhHalveColorBrightness(Color1); + DrawInfo->LineColor2 = Color2; + DrawInfo->LineBackColor2 = PhHalveColorBrightness(Color2); + DrawInfo->GridColor = RGB(0x00, 0x57, 0x00); + DrawInfo->LabelYColor = RGB(0xd0, 0xa0, 0x70); + DrawInfo->TextColor = RGB(0x00, 0xff, 0x00); + DrawInfo->TextBoxColor = RGB(0x00, 0x22, 0x00); + break; + } +} + +PPH_STRING PhSiSizeLabelYFunction( + _In_ PPH_GRAPH_DRAW_INFO DrawInfo, + _In_ ULONG DataIndex, + _In_ FLOAT Value, + _In_ FLOAT Parameter + ) +{ + ULONG64 size; + + size = (ULONG64)(Value * Parameter); + + if (size != 0) + { + PH_FORMAT format; + + format.Type = SizeFormatType | FormatUsePrecision | FormatUseRadix; + format.Precision = 0; + format.Radix = -1; + format.u.Size = size; + + return PhFormat(&format, 1, 0); + } + else + { + return PhReferenceEmptyString(); + } +} + +VOID PhSipRegisterDialog( + _In_ HWND DialogWindowHandle + ) +{ + if (!PhSipDialogList) + PhSipDialogList = PhCreateList(4); + + PhAddItemList(PhSipDialogList, DialogWindowHandle); +} + +VOID PhSipUnregisterDialog( + _In_ HWND DialogWindowHandle + ) +{ + ULONG index; + + if ((index = PhFindItemList(PhSipDialogList, DialogWindowHandle)) != -1) + PhRemoveItemList(PhSipDialogList, index); +} + +VOID PhSipInitializeParameters( + VOID + ) +{ + LOGFONT logFont; + HDC hdc; + TEXTMETRIC textMetrics; + HFONT originalFont; + + memset(&CurrentParameters, 0, sizeof(PH_SYSINFO_PARAMETERS)); + + CurrentParameters.SysInfoWindowHandle = PhSipWindow; + CurrentParameters.ContainerWindowHandle = ContainerControl; + + if (SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(LOGFONT), &logFont, 0)) + { + CurrentParameters.Font = CreateFontIndirect(&logFont); + } + else + { + CurrentParameters.Font = PhApplicationFont; + GetObject(PhApplicationFont, sizeof(LOGFONT), &logFont); + } + + hdc = GetDC(PhSipWindow); + + logFont.lfHeight -= PhMultiplyDivide(3, GetDeviceCaps(hdc, LOGPIXELSY), 72); + CurrentParameters.MediumFont = CreateFontIndirect(&logFont); + + logFont.lfHeight -= PhMultiplyDivide(3, GetDeviceCaps(hdc, LOGPIXELSY), 72); + CurrentParameters.LargeFont = CreateFontIndirect(&logFont); + + PhSipUpdateColorParameters(); + + CurrentParameters.ColorSetupFunction = PhSiSetColorsGraphDrawInfo; + + originalFont = SelectObject(hdc, CurrentParameters.Font); + GetTextMetrics(hdc, &textMetrics); + CurrentParameters.FontHeight = textMetrics.tmHeight; + CurrentParameters.FontAverageWidth = textMetrics.tmAveCharWidth; + + SelectObject(hdc, CurrentParameters.MediumFont); + GetTextMetrics(hdc, &textMetrics); + CurrentParameters.MediumFontHeight = textMetrics.tmHeight; + CurrentParameters.MediumFontAverageWidth = textMetrics.tmAveCharWidth; + + SelectObject(hdc, originalFont); + + // Internal padding and other values + CurrentParameters.PanelPadding = PH_SCALE_DPI(PH_SYSINFO_PANEL_PADDING); + CurrentParameters.WindowPadding = PH_SCALE_DPI(PH_SYSINFO_WINDOW_PADDING); + CurrentParameters.GraphPadding = PH_SCALE_DPI(PH_SYSINFO_GRAPH_PADDING); + CurrentParameters.SmallGraphWidth = PH_SCALE_DPI(PH_SYSINFO_SMALL_GRAPH_WIDTH); + CurrentParameters.SmallGraphPadding = PH_SCALE_DPI(PH_SYSINFO_SMALL_GRAPH_PADDING); + CurrentParameters.SeparatorWidth = PH_SCALE_DPI(PH_SYSINFO_SEPARATOR_WIDTH); + CurrentParameters.CpuPadding = PH_SCALE_DPI(PH_SYSINFO_CPU_PADDING); + CurrentParameters.MemoryPadding = PH_SCALE_DPI(PH_SYSINFO_MEMORY_PADDING); + + CurrentParameters.MinimumGraphHeight = + CurrentParameters.PanelPadding + + CurrentParameters.MediumFontHeight + + CurrentParameters.PanelPadding; + + CurrentParameters.SectionViewGraphHeight = + CurrentParameters.PanelPadding + + CurrentParameters.MediumFontHeight + + CurrentParameters.PanelPadding + + CurrentParameters.FontHeight + + 2 + + CurrentParameters.FontHeight + + CurrentParameters.PanelPadding + + 2; + + CurrentParameters.PanelWidth = CurrentParameters.MediumFontAverageWidth * 10; + + ReleaseDC(PhSipWindow, hdc); +} + +VOID PhSipDeleteParameters( + VOID + ) +{ + if (CurrentParameters.Font) + DeleteObject(CurrentParameters.Font); + if (CurrentParameters.MediumFont) + DeleteObject(CurrentParameters.MediumFont); + if (CurrentParameters.LargeFont) + DeleteObject(CurrentParameters.LargeFont); +} + +VOID PhSipUpdateColorParameters( + VOID + ) +{ + switch (PhCsGraphColorMode) + { + case 0: // New colors + CurrentParameters.GraphBackColor = RGB(0xef, 0xef, 0xef); + CurrentParameters.PanelForeColor = RGB(0x00, 0x00, 0x00); + break; + case 1: // Old colors + CurrentParameters.GraphBackColor = RGB(0x00, 0x00, 0x00); + CurrentParameters.PanelForeColor = RGB(0xff, 0xff, 0xff); + break; + } +} + +PPH_SYSINFO_SECTION PhSipCreateSection( + _In_ PPH_SYSINFO_SECTION Template + ) +{ + PPH_SYSINFO_SECTION section; + PH_GRAPH_OPTIONS options; + + section = PhAllocate(sizeof(PH_SYSINFO_SECTION)); + memset(section, 0, sizeof(PH_SYSINFO_SECTION)); + + section->Name = Template->Name; + section->Flags = Template->Flags; + section->Callback = Template->Callback; + section->Context = Template->Context; + + section->GraphHandle = CreateWindow( + PH_GRAPH_CLASSNAME, + NULL, + WS_VISIBLE | WS_CHILD | WS_BORDER | WS_TABSTOP | GC_STYLE_FADEOUT | GC_STYLE_DRAW_PANEL, + 0, + 0, + 3, + 3, + PhSipWindow, + NULL, + PhInstanceHandle, + NULL + ); + PhInitializeGraphState(§ion->GraphState); + section->Parameters = &CurrentParameters; + + Graph_GetOptions(section->GraphHandle, &options); + options.FadeOutBackColor = CurrentParameters.GraphBackColor; + options.FadeOutWidth = CurrentParameters.PanelWidth + PH_SYSINFO_FADE_ADD; + options.DefaultCursor = LoadCursor(NULL, IDC_HAND); + Graph_SetOptions(section->GraphHandle, &options); + Graph_SetTooltip(section->GraphHandle, TRUE); + + section->PanelId = IDDYNAMIC + SectionList->Count * 2 + 2; + section->PanelHandle = CreateWindow( + L"STATIC", + NULL, + WS_CHILD | SS_OWNERDRAW | SS_NOTIFY, + 0, + 0, + 3, + 3, + PhSipWindow, + (HMENU)(ULONG_PTR)section->PanelId, + PhInstanceHandle, + NULL + ); + + SetWindowSubclass(section->GraphHandle, PhSipGraphHookWndProc, 0, (ULONG_PTR)section); + SetWindowSubclass(section->PanelHandle, PhSipPanelHookWndProc, 0, (ULONG_PTR)section); + + PhAddItemList(SectionList, section); + + section->Callback(section, SysInfoCreate, NULL, NULL); + + return section; +} + +VOID PhSipDestroySection( + _In_ PPH_SYSINFO_SECTION Section + ) +{ + Section->Callback(Section, SysInfoDestroy, NULL, NULL); + + PhDeleteGraphState(&Section->GraphState); + PhFree(Section); +} + +PPH_SYSINFO_SECTION PhSipFindSection( + _In_ PPH_STRINGREF Name + ) +{ + ULONG i; + PPH_SYSINFO_SECTION section; + + for (i = 0; i < SectionList->Count; i++) + { + section = SectionList->Items[i]; + + if (PhEqualStringRef(§ion->Name, Name, TRUE)) + return section; + } + + return NULL; +} + +PPH_SYSINFO_SECTION PhSipCreateInternalSection( + _In_ PWSTR Name, + _In_ ULONG Flags, + _In_ PPH_SYSINFO_SECTION_CALLBACK Callback + ) +{ + PH_SYSINFO_SECTION section; + + memset(§ion, 0, sizeof(PH_SYSINFO_SECTION)); + PhInitializeStringRef(§ion.Name, Name); + section.Flags = Flags; + section.Callback = Callback; + + return PhSipCreateSection(§ion); +} + +VOID PhSipDrawRestoreSummaryPanel( + _In_ HDC hdc, + _In_ PRECT Rect + ) +{ + FillRect(hdc, Rect, GetSysColorBrush(COLOR_3DFACE)); + + if (RestoreSummaryControlHot || RestoreSummaryControlHasFocus) + { + if (ThemeHasItemBackground) + { + DrawThemeBackground( + ThemeData, + hdc, + TVP_TREEITEM, + TREIS_HOT, + Rect, + Rect + ); + } + else + { + FillRect(hdc, Rect, GetSysColorBrush(COLOR_WINDOW)); + } + } + + SetTextColor(hdc, GetSysColor(COLOR_WINDOWTEXT)); + SetBkMode(hdc, TRANSPARENT); + + SelectObject(hdc, CurrentParameters.MediumFont); + DrawText(hdc, L"Back", 4, Rect, DT_CENTER | DT_VCENTER | DT_SINGLELINE); +} + +VOID PhSipDrawSeparator( + _In_ HDC hdc, + _In_ PRECT Rect + ) +{ + RECT rect; + + rect = *Rect; + FillRect(hdc, &rect, GetSysColorBrush(COLOR_3DHIGHLIGHT)); + rect.left += 1; + FillRect(hdc, &rect, GetSysColorBrush(COLOR_3DSHADOW)); +} + +VOID PhSipDrawPanel( + _In_ PPH_SYSINFO_SECTION Section, + _In_ HDC hdc, + _In_ PRECT Rect + ) +{ + PH_SYSINFO_DRAW_PANEL sysInfoDrawPanel; + + if (CurrentView == SysInfoSectionView) + FillRect(hdc, Rect, GetSysColorBrush(COLOR_3DFACE)); + + sysInfoDrawPanel.hdc = hdc; + sysInfoDrawPanel.Rect = *Rect; + sysInfoDrawPanel.Rect.right = CurrentParameters.PanelWidth; + sysInfoDrawPanel.CustomDraw = FALSE; + + sysInfoDrawPanel.Title = NULL; + sysInfoDrawPanel.SubTitle = NULL; + sysInfoDrawPanel.SubTitleOverflow = NULL; + + Section->Callback(Section, SysInfoGraphDrawPanel, &sysInfoDrawPanel, NULL); + + if (!sysInfoDrawPanel.CustomDraw) + { + sysInfoDrawPanel.Rect.right = Rect->right; + PhSipDefaultDrawPanel(Section, &sysInfoDrawPanel); + } + + PhClearReference(&sysInfoDrawPanel.Title); + PhClearReference(&sysInfoDrawPanel.SubTitle); + PhClearReference(&sysInfoDrawPanel.SubTitleOverflow); +} + +VOID PhSipDefaultDrawPanel( + _In_ PPH_SYSINFO_SECTION Section, + _In_ PPH_SYSINFO_DRAW_PANEL DrawPanel + ) +{ + HDC hdc; + RECT rect; + ULONG flags; + + hdc = DrawPanel->hdc; + + if (ThemeHasItemBackground) + { + if (CurrentView == SysInfoSectionView) + { + INT stateId; + + stateId = -1; + + if (Section->GraphHot || Section->PanelHot || Section->HasFocus) + { + if (Section == CurrentSection) + stateId = TREIS_HOTSELECTED; + else + stateId = TREIS_HOT; + } + else if (Section == CurrentSection) + { + stateId = TREIS_SELECTED; + } + + if (stateId != -1) + { + RECT themeRect; + + themeRect = DrawPanel->Rect; + themeRect.left -= 2; // remove left edge + + DrawThemeBackground( + ThemeData, + hdc, + TVP_TREEITEM, + stateId, + &themeRect, + &DrawPanel->Rect + ); + } + } + else if (Section->HasFocus) + { + DrawThemeBackground( + ThemeData, + hdc, + TVP_TREEITEM, + TREIS_HOT, + &DrawPanel->Rect, + &DrawPanel->Rect + ); + } + } + else + { + if (CurrentView == SysInfoSectionView) + { + HBRUSH brush; + + brush = NULL; + + if (Section->GraphHot || Section->PanelHot || Section->HasFocus) + { + brush = GetSysColorBrush(COLOR_WINDOW); // TODO: Use a different color + } + else if (Section == CurrentSection) + { + brush = GetSysColorBrush(COLOR_WINDOW); + } + + if (brush) + { + FillRect(hdc, &DrawPanel->Rect, brush); + } + } + } + + if (CurrentView == SysInfoSummaryView) + SetTextColor(hdc, CurrentParameters.PanelForeColor); + else + SetTextColor(hdc, GetSysColor(COLOR_WINDOWTEXT)); + + SetBkMode(hdc, TRANSPARENT); + + rect.left = CurrentParameters.SmallGraphPadding + CurrentParameters.PanelPadding; + rect.top = CurrentParameters.PanelPadding; + rect.right = CurrentParameters.PanelWidth; + rect.bottom = DrawPanel->Rect.bottom; + + flags = DT_NOPREFIX; + + if (CurrentView == SysInfoSummaryView) + rect.right = DrawPanel->Rect.right; // allow the text to overflow + else + flags |= DT_END_ELLIPSIS; + + if (DrawPanel->Title) + { + SelectObject(hdc, CurrentParameters.MediumFont); + DrawText(hdc, DrawPanel->Title->Buffer, (ULONG)DrawPanel->Title->Length / 2, &rect, flags | DT_SINGLELINE); + } + + if (DrawPanel->SubTitle) + { + RECT measureRect; + + rect.top += CurrentParameters.MediumFontHeight + CurrentParameters.PanelPadding; + SelectObject(hdc, CurrentParameters.Font); + + measureRect = rect; + DrawText(hdc, DrawPanel->SubTitle->Buffer, (ULONG)DrawPanel->SubTitle->Length / 2, &measureRect, (flags & ~DT_END_ELLIPSIS) | DT_CALCRECT); + + if (measureRect.right <= rect.right || !DrawPanel->SubTitleOverflow) + { + // Text fits; draw normally. + DrawText(hdc, DrawPanel->SubTitle->Buffer, (ULONG)DrawPanel->SubTitle->Length / 2, &rect, flags); + } + else + { + // Text doesn't fit; draw the alternative text. + DrawText(hdc, DrawPanel->SubTitleOverflow->Buffer, (ULONG)DrawPanel->SubTitleOverflow->Length / 2, &rect, flags); + } + } +} + +VOID PhSipLayoutSummaryView( + VOID + ) +{ + RECT buttonRect; + RECT clientRect; + ULONG availableHeight; + ULONG availableWidth; + ULONG graphHeight; + ULONG i; + PPH_SYSINFO_SECTION section; + HDWP deferHandle; + ULONG y; + + GetWindowRect(GetDlgItem(PhSipWindow, IDOK), &buttonRect); + MapWindowPoints(NULL, PhSipWindow, (POINT *)&buttonRect, 2); + GetClientRect(PhSipWindow, &clientRect); + + availableHeight = buttonRect.top - CurrentParameters.WindowPadding * 2; + availableWidth = clientRect.right - CurrentParameters.WindowPadding * 2; + graphHeight = (availableHeight - CurrentParameters.GraphPadding * (SectionList->Count - 1)) / SectionList->Count; + + deferHandle = BeginDeferWindowPos(SectionList->Count); + y = CurrentParameters.WindowPadding; + + for (i = 0; i < SectionList->Count; i++) + { + section = SectionList->Items[i]; + + deferHandle = DeferWindowPos( + deferHandle, + section->GraphHandle, + NULL, + CurrentParameters.WindowPadding, + y, + availableWidth, + graphHeight, + SWP_NOACTIVATE | SWP_NOZORDER + ); + y += graphHeight + CurrentParameters.GraphPadding; + + section->GraphState.Valid = FALSE; + } + + EndDeferWindowPos(deferHandle); +} + +VOID PhSipLayoutSectionView( + VOID + ) +{ + RECT buttonRect; + RECT clientRect; + ULONG availableHeight; + ULONG availableWidth; + ULONG graphHeight; + ULONG i; + PPH_SYSINFO_SECTION section; + HDWP deferHandle; + ULONG y; + ULONG containerLeft; + + GetWindowRect(GetDlgItem(PhSipWindow, IDOK), &buttonRect); + MapWindowPoints(NULL, PhSipWindow, (POINT *)&buttonRect, 2); + GetClientRect(PhSipWindow, &clientRect); + + availableHeight = buttonRect.top - CurrentParameters.WindowPadding * 2; + availableWidth = clientRect.right - CurrentParameters.WindowPadding * 2; + graphHeight = (availableHeight - CurrentParameters.SmallGraphPadding * SectionList->Count) / (SectionList->Count + 1); + + if (graphHeight > CurrentParameters.SectionViewGraphHeight) + graphHeight = CurrentParameters.SectionViewGraphHeight; + + deferHandle = BeginDeferWindowPos(SectionList->Count * 2 + 3); + y = CurrentParameters.WindowPadding; + + for (i = 0; i < SectionList->Count; i++) + { + section = SectionList->Items[i]; + + deferHandle = DeferWindowPos( + deferHandle, + section->GraphHandle, + NULL, + CurrentParameters.WindowPadding, + y, + CurrentParameters.SmallGraphWidth, + graphHeight, + SWP_NOACTIVATE | SWP_NOZORDER + ); + + deferHandle = DeferWindowPos( + deferHandle, + section->PanelHandle, + NULL, + CurrentParameters.WindowPadding + CurrentParameters.SmallGraphWidth, + y, + CurrentParameters.SmallGraphPadding + CurrentParameters.PanelWidth, + graphHeight, + SWP_NOACTIVATE | SWP_NOZORDER + ); + InvalidateRect(section->PanelHandle, NULL, TRUE); + + y += graphHeight + CurrentParameters.SmallGraphPadding; + + section->GraphState.Valid = FALSE; + } + + deferHandle = DeferWindowPos( + deferHandle, + RestoreSummaryControl, + NULL, + CurrentParameters.WindowPadding, + y, + CurrentParameters.SmallGraphWidth + CurrentParameters.SmallGraphPadding + CurrentParameters.PanelWidth, + graphHeight, + SWP_NOACTIVATE | SWP_NOZORDER + ); + InvalidateRect(RestoreSummaryControl, NULL, TRUE); + + deferHandle = DeferWindowPos( + deferHandle, + SeparatorControl, + NULL, + CurrentParameters.WindowPadding + CurrentParameters.SmallGraphWidth + CurrentParameters.SmallGraphPadding + CurrentParameters.PanelWidth + CurrentParameters.WindowPadding - 7, + 0, + CurrentParameters.SeparatorWidth, + CurrentParameters.WindowPadding + availableHeight, + SWP_NOACTIVATE | SWP_NOZORDER + ); + + containerLeft = CurrentParameters.WindowPadding + CurrentParameters.SmallGraphWidth + CurrentParameters.SmallGraphPadding + CurrentParameters.PanelWidth + CurrentParameters.WindowPadding - 7 + CurrentParameters.SeparatorWidth; + deferHandle = DeferWindowPos( + deferHandle, + ContainerControl, + NULL, + containerLeft, + 0, + clientRect.right - containerLeft, + CurrentParameters.WindowPadding + availableHeight, + SWP_NOACTIVATE | SWP_NOZORDER + ); + + EndDeferWindowPos(deferHandle); + + if (CurrentSection && CurrentSection->DialogHandle) + { + SetWindowPos( + CurrentSection->DialogHandle, + NULL, + CurrentParameters.WindowPadding, + CurrentParameters.WindowPadding, + clientRect.right - containerLeft - CurrentParameters.WindowPadding - CurrentParameters.WindowPadding, + availableHeight, + SWP_NOACTIVATE | SWP_NOZORDER + ); + } +} + +VOID PhSipEnterSectionView( + _In_ PPH_SYSINFO_SECTION NewSection + ) +{ + ULONG i; + PPH_SYSINFO_SECTION section; + BOOLEAN fromSummaryView; + PPH_SYSINFO_SECTION oldSection; + HDWP deferHandle; + HDWP containerDeferHandle; + + if (CurrentSection == NewSection) + return; + + fromSummaryView = CurrentView == SysInfoSummaryView; + CurrentView = SysInfoSectionView; + oldSection = CurrentSection; + CurrentSection = NewSection; + + deferHandle = BeginDeferWindowPos(SectionList->Count + 4); + containerDeferHandle = BeginDeferWindowPos(SectionList->Count); + + PhSipEnterSectionViewInner(NewSection, fromSummaryView, &deferHandle, &containerDeferHandle); + PhSipLayoutSectionView(); + + for (i = 0; i < SectionList->Count; i++) + { + section = SectionList->Items[i]; + + if (section != NewSection) + PhSipEnterSectionViewInner(section, fromSummaryView, &deferHandle, &containerDeferHandle); + } + + deferHandle = DeferWindowPos(deferHandle, ContainerControl, NULL, 0, 0, 0, 0, SWP_SHOWWINDOW_ONLY); + deferHandle = DeferWindowPos(deferHandle, RestoreSummaryControl, NULL, 0, 0, 0, 0, SWP_SHOWWINDOW_ONLY); + deferHandle = DeferWindowPos(deferHandle, SeparatorControl, NULL, 0, 0, 0, 0, SWP_SHOWWINDOW_ONLY); + deferHandle = DeferWindowPos(deferHandle, GetDlgItem(PhSipWindow, IDC_INSTRUCTION), NULL, 0, 0, 0, 0, SWP_HIDEWINDOW_ONLY); + + EndDeferWindowPos(deferHandle); + EndDeferWindowPos(containerDeferHandle); + + if (oldSection) + InvalidateRect(oldSection->PanelHandle, NULL, TRUE); + + InvalidateRect(NewSection->PanelHandle, NULL, TRUE); + + if (NewSection->DialogHandle) + RedrawWindow(NewSection->DialogHandle, NULL, NULL, RDW_ERASE | RDW_INVALIDATE | RDW_ALLCHILDREN | RDW_UPDATENOW); +} + +VOID PhSipEnterSectionViewInner( + _In_ PPH_SYSINFO_SECTION Section, + _In_ BOOLEAN FromSummaryView, + _Inout_ HDWP *DeferHandle, + _Inout_ HDWP *ContainerDeferHandle + ) +{ + Section->HasFocus = FALSE; + Section->Callback(Section, SysInfoViewChanging, (PVOID)CurrentView, CurrentSection); + + if (FromSummaryView) + { + PhSetWindowStyle(Section->GraphHandle, GC_STYLE_FADEOUT | GC_STYLE_DRAW_PANEL, 0); + *DeferHandle = DeferWindowPos(*DeferHandle, Section->PanelHandle, NULL, 0, 0, 0, 0, SWP_SHOWWINDOW_ONLY); + } + + if (Section == CurrentSection && !Section->DialogHandle) + PhSipCreateSectionDialog(Section); + + if (Section->DialogHandle) + { + if (Section == CurrentSection) + *ContainerDeferHandle = DeferWindowPos(*ContainerDeferHandle, Section->DialogHandle, NULL, 0, 0, 0, 0, SWP_SHOWWINDOW_ONLY | SWP_NOREDRAW); + else + *ContainerDeferHandle = DeferWindowPos(*ContainerDeferHandle, Section->DialogHandle, NULL, 0, 0, 0, 0, SWP_HIDEWINDOW_ONLY | SWP_NOREDRAW); + } +} + +VOID PhSipRestoreSummaryView( + VOID + ) +{ + ULONG i; + PPH_SYSINFO_SECTION section; + + if (CurrentView == SysInfoSummaryView) + return; + + CurrentView = SysInfoSummaryView; + CurrentSection = NULL; + + for (i = 0; i < SectionList->Count; i++) + { + section = SectionList->Items[i]; + + section->Callback(section, SysInfoViewChanging, (PVOID)CurrentView, NULL); + + PhSetWindowStyle(section->GraphHandle, GC_STYLE_FADEOUT | GC_STYLE_DRAW_PANEL, GC_STYLE_FADEOUT | GC_STYLE_DRAW_PANEL); + ShowWindow(section->PanelHandle, SW_HIDE); + + if (section->DialogHandle) + ShowWindow(section->DialogHandle, SW_HIDE); + } + + ShowWindow(ContainerControl, SW_HIDE); + ShowWindow(RestoreSummaryControl, SW_HIDE); + ShowWindow(SeparatorControl, SW_HIDE); + ShowWindow(GetDlgItem(PhSipWindow, IDC_INSTRUCTION), SW_SHOW); + + PhSipLayoutSummaryView(); +} + +VOID PhSipCreateSectionDialog( + _In_ PPH_SYSINFO_SECTION Section + ) +{ + PH_SYSINFO_CREATE_DIALOG createDialog; + + memset(&createDialog, 0, sizeof(PH_SYSINFO_CREATE_DIALOG)); + + if (Section->Callback(Section, SysInfoCreateDialog, &createDialog, NULL)) + { + if (!createDialog.CustomCreate) + { + Section->DialogHandle = PhCreateDialogFromTemplate( + ContainerControl, + DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD, + createDialog.Instance, + createDialog.Template, + createDialog.DialogProc, + createDialog.Parameter + ); + } + } +} + +LRESULT CALLBACK PhSipGraphHookWndProc( + _In_ HWND hwnd, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam, + _In_ UINT_PTR uIdSubclass, + _In_ ULONG_PTR dwRefData + ) +{ + PPH_SYSINFO_SECTION section = (PPH_SYSINFO_SECTION)dwRefData; + + switch (uMsg) + { + case WM_DESTROY: + RemoveWindowSubclass(hwnd, PhSipGraphHookWndProc, uIdSubclass); + break; + case WM_SETFOCUS: + section->HasFocus = TRUE; + + if (CurrentView == SysInfoSummaryView) + { + Graph_Draw(section->GraphHandle); + InvalidateRect(section->GraphHandle, NULL, FALSE); + } + else + { + InvalidateRect(section->PanelHandle, NULL, TRUE); + } + + break; + case WM_KILLFOCUS: + section->HasFocus = FALSE; + + if (CurrentView == SysInfoSummaryView) + { + Graph_Draw(section->GraphHandle); + InvalidateRect(section->GraphHandle, NULL, FALSE); + } + else + { + InvalidateRect(section->PanelHandle, NULL, TRUE); + } + + break; + case WM_GETDLGCODE: + if (wParam == VK_SPACE || wParam == VK_RETURN || + wParam == VK_UP || wParam == VK_DOWN || + wParam == VK_LEFT || wParam == VK_RIGHT) + return DLGC_WANTALLKEYS; + break; + case WM_KEYDOWN: + { + if (wParam == VK_SPACE || wParam == VK_RETURN) + { + PhSipEnterSectionView(section); + } + else if (wParam == VK_UP || wParam == VK_LEFT || + wParam == VK_DOWN || wParam == VK_RIGHT) + { + ULONG i; + + for (i = 0; i < SectionList->Count; i++) + { + if (SectionList->Items[i] == section) + { + if ((wParam == VK_UP || wParam == VK_LEFT) && i > 0) + { + SetFocus(((PPH_SYSINFO_SECTION)SectionList->Items[i - 1])->GraphHandle); + } + else if (wParam == VK_DOWN || wParam == VK_RIGHT) + { + if (i < SectionList->Count - 1) + SetFocus(((PPH_SYSINFO_SECTION)SectionList->Items[i + 1])->GraphHandle); + else + SetFocus(RestoreSummaryControl); + } + + break; + } + } + } + } + break; + case WM_MOUSEMOVE: + { + TRACKMOUSEEVENT trackMouseEvent; + + trackMouseEvent.cbSize = sizeof(TRACKMOUSEEVENT); + trackMouseEvent.dwFlags = TME_LEAVE; + trackMouseEvent.hwndTrack = hwnd; + trackMouseEvent.dwHoverTime = 0; + TrackMouseEvent(&trackMouseEvent); + + if (!(section->GraphHot || section->PanelHot)) + { + section->GraphHot = TRUE; + InvalidateRect(section->PanelHandle, NULL, TRUE); + } + else + { + section->GraphHot = TRUE; + } + } + break; + case WM_MOUSELEAVE: + { + if (!section->PanelHot) + { + section->GraphHot = FALSE; + InvalidateRect(section->PanelHandle, NULL, TRUE); + } + else + { + section->GraphHot = FALSE; + } + + section->HasFocus = FALSE; + + if (CurrentView == SysInfoSummaryView) + { + Graph_Draw(section->GraphHandle); + InvalidateRect(section->GraphHandle, NULL, FALSE); + } + } + break; + case WM_NCLBUTTONDOWN: + { + PhSipEnterSectionView(section); + } + break; + case WM_UPDATEUISTATE: + { + switch (LOWORD(wParam)) + { + case UIS_SET: + if (HIWORD(wParam) & UISF_HIDEFOCUS) + section->HideFocus = TRUE; + break; + case UIS_CLEAR: + if (HIWORD(wParam) & UISF_HIDEFOCUS) + section->HideFocus = FALSE; + break; + case UIS_INITIALIZE: + section->HideFocus = !!(HIWORD(wParam) & UISF_HIDEFOCUS); + break; + } + } + break; + } + + return DefSubclassProc(hwnd, uMsg, wParam, lParam); +} + +LRESULT CALLBACK PhSipPanelHookWndProc( + _In_ HWND hwnd, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam, + _In_ UINT_PTR uIdSubclass, + _In_ ULONG_PTR dwRefData + ) +{ + PPH_SYSINFO_SECTION section = (PPH_SYSINFO_SECTION)dwRefData; + + switch (uMsg) + { + case WM_DESTROY: + RemoveWindowSubclass(hwnd, PhSipPanelHookWndProc, uIdSubclass); + break; + case WM_SETFOCUS: + { + if (!section) + { + RestoreSummaryControlHasFocus = TRUE; + InvalidateRect(hwnd, NULL, TRUE); + } + } + break; + case WM_KILLFOCUS: + { + if (!section) + { + RestoreSummaryControlHasFocus = FALSE; + InvalidateRect(hwnd, NULL, TRUE); + } + } + break; + case WM_SETCURSOR: + { + SetCursor(LoadCursor(NULL, IDC_HAND)); + } + return TRUE; + case WM_GETDLGCODE: + if (wParam == VK_SPACE || wParam == VK_RETURN || + wParam == VK_UP || wParam == VK_DOWN || + wParam == VK_LEFT || wParam == VK_RIGHT) + return DLGC_WANTALLKEYS; + break; + case WM_KEYDOWN: + { + if (wParam == VK_SPACE || wParam == VK_RETURN) + { + if (section) + PhSipEnterSectionView(section); + else + PhSipRestoreSummaryView(); + } + else if (wParam == VK_UP || wParam == VK_LEFT) + { + if (!section && SectionList->Count != 0) + { + SetFocus(((PPH_SYSINFO_SECTION)SectionList->Items[SectionList->Count - 1])->GraphHandle); + } + } + } + break; + case WM_MOUSEMOVE: + { + TRACKMOUSEEVENT trackMouseEvent; + + trackMouseEvent.cbSize = sizeof(TRACKMOUSEEVENT); + trackMouseEvent.dwFlags = TME_LEAVE; + trackMouseEvent.hwndTrack = hwnd; + trackMouseEvent.dwHoverTime = 0; + TrackMouseEvent(&trackMouseEvent); + + if (section) + { + if (!(section->GraphHot || section->PanelHot)) + { + section->PanelHot = TRUE; + InvalidateRect(section->PanelHandle, NULL, TRUE); + } + else + { + section->PanelHot = TRUE; + } + } + else + { + RestoreSummaryControlHot = TRUE; + InvalidateRect(RestoreSummaryControl, NULL, TRUE); + } + } + break; + case WM_MOUSELEAVE: + { + if (section) + { + section->HasFocus = FALSE; + + if (!section->GraphHot) + { + section->PanelHot = FALSE; + InvalidateRect(section->PanelHandle, NULL, TRUE); + } + else + { + section->PanelHot = FALSE; + } + } + else + { + RestoreSummaryControlHasFocus = FALSE; + RestoreSummaryControlHot = FALSE; + InvalidateRect(RestoreSummaryControl, NULL, TRUE); + } + } + break; + } + + return DefSubclassProc(hwnd, uMsg, wParam, lParam); +} + +VOID PhSipUpdateThemeData( + VOID + ) +{ + if (ThemeData) + { + CloseThemeData(ThemeData); + ThemeData = NULL; + } + + ThemeData = OpenThemeData(PhSipWindow, L"TREEVIEW"); + + if (ThemeData) + { + ThemeHasItemBackground = !!IsThemePartDefined(ThemeData, TVP_TREEITEM, 0); + } + else + { + ThemeHasItemBackground = FALSE; + } +} + +VOID PhSipSetAlwaysOnTop( + VOID + ) +{ + SetFocus(PhSipWindow); // HACK - SetWindowPos doesn't work properly without this + SetWindowPos(PhSipWindow, AlwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST, 0, 0, 0, 0, + SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE); +} + +VOID PhSipSaveWindowState( + VOID + ) +{ + WINDOWPLACEMENT placement = { sizeof(placement) }; + + GetWindowPlacement(PhSipWindow, &placement); + + if (placement.showCmd == SW_NORMAL) + PhSetIntegerSetting(L"SysInfoWindowState", SW_NORMAL); + else if (placement.showCmd == SW_MAXIMIZE) + PhSetIntegerSetting(L"SysInfoWindowState", SW_MAXIMIZE); +} + +VOID NTAPI PhSipSysInfoUpdateHandler( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + PostMessage(PhSipWindow, SI_MSG_SYSINFO_UPDATE, 0, 0); +} + +PPH_STRING PhSipFormatSizeWithPrecision( + _In_ ULONG64 Size, + _In_ USHORT Precision + ) +{ + PH_FORMAT format; + + format.Type = SizeFormatType | FormatUsePrecision; + format.Precision = Precision; + format.u.Size = Size; + + return PH_AUTO(PhFormat(&format, 1, 0)); +} diff --git a/ProcessHacker/thrdlist.c b/ProcessHacker/thrdlist.c index 1800cbdadfdc..cae5d04594aa 100644 --- a/ProcessHacker/thrdlist.c +++ b/ProcessHacker/thrdlist.c @@ -1,723 +1,723 @@ -/* - * Process Hacker - - * thread list - * - * Copyright (C) 2011-2012 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include -#include - -#include - -#include -#include -#include -#include -#include -#include - -BOOLEAN PhpThreadNodeHashtableEqualFunction( - _In_ PVOID Entry1, - _In_ PVOID Entry2 - ); - -ULONG PhpThreadNodeHashtableHashFunction( - _In_ PVOID Entry - ); - -VOID PhpDestroyThreadNode( - _In_ PPH_THREAD_NODE ThreadNode - ); - -VOID PhpRemoveThreadNode( - _In_ PPH_THREAD_NODE ThreadNode, - _In_ PPH_THREAD_LIST_CONTEXT Context - ); - -LONG PhpThreadTreeNewPostSortFunction( - _In_ LONG Result, - _In_ PVOID Node1, - _In_ PVOID Node2, - _In_ PH_SORT_ORDER SortOrder - ); - -BOOLEAN NTAPI PhpThreadTreeNewCallback( - _In_ HWND hwnd, - _In_ PH_TREENEW_MESSAGE Message, - _In_opt_ PVOID Parameter1, - _In_opt_ PVOID Parameter2, - _In_opt_ PVOID Context - ); - -VOID PhInitializeThreadList( - _In_ HWND ParentWindowHandle, - _In_ HWND TreeNewHandle, - _Out_ PPH_THREAD_LIST_CONTEXT Context - ) -{ - HWND hwnd; - - memset(Context, 0, sizeof(PH_THREAD_LIST_CONTEXT)); - Context->EnableStateHighlighting = TRUE; - - Context->NodeHashtable = PhCreateHashtable( - sizeof(PPH_THREAD_NODE), - PhpThreadNodeHashtableEqualFunction, - PhpThreadNodeHashtableHashFunction, - 100 - ); - Context->NodeList = PhCreateList(100); - - Context->ParentWindowHandle = ParentWindowHandle; - Context->TreeNewHandle = TreeNewHandle; - hwnd = TreeNewHandle; - PhSetControlTheme(hwnd, L"explorer"); - - TreeNew_SetCallback(hwnd, PhpThreadTreeNewCallback, Context); - - TreeNew_SetRedraw(hwnd, FALSE); - - // Default columns - PhAddTreeNewColumn(hwnd, PHTHTLC_TID, TRUE, L"TID", 50, PH_ALIGN_RIGHT, 0, DT_RIGHT); - PhAddTreeNewColumnEx(hwnd, PHTHTLC_CPU, TRUE, L"CPU", 45, PH_ALIGN_RIGHT, 1, DT_RIGHT, TRUE); - PhAddTreeNewColumnEx(hwnd, PHTHTLC_CYCLESDELTA, TRUE, L"Cycles delta", 80, PH_ALIGN_RIGHT, 2, DT_RIGHT, TRUE); - PhAddTreeNewColumn(hwnd, PHTHTLC_STARTADDRESS, TRUE, L"Start address", 180, PH_ALIGN_LEFT, 3, 0); - PhAddTreeNewColumnEx(hwnd, PHTHTLC_PRIORITY, TRUE, L"Priority", 80, PH_ALIGN_LEFT, 4, 0, TRUE); - PhAddTreeNewColumn(hwnd, PHTHTLC_SERVICE, FALSE, L"Service", 100, PH_ALIGN_LEFT, -1, 0); - - TreeNew_SetRedraw(hwnd, TRUE); - - TreeNew_SetSort(hwnd, PHTHTLC_CYCLESDELTA, DescendingSortOrder); - - PhCmInitializeManager(&Context->Cm, hwnd, PHTHTLC_MAXIMUM, PhpThreadTreeNewPostSortFunction); -} - -VOID PhDeleteThreadList( - _In_ PPH_THREAD_LIST_CONTEXT Context - ) -{ - ULONG i; - - PhCmDeleteManager(&Context->Cm); - - for (i = 0; i < Context->NodeList->Count; i++) - PhpDestroyThreadNode(Context->NodeList->Items[i]); - - PhDereferenceObject(Context->NodeHashtable); - PhDereferenceObject(Context->NodeList); -} - -BOOLEAN PhpThreadNodeHashtableEqualFunction( - _In_ PVOID Entry1, - _In_ PVOID Entry2 - ) -{ - PPH_THREAD_NODE threadNode1 = *(PPH_THREAD_NODE *)Entry1; - PPH_THREAD_NODE threadNode2 = *(PPH_THREAD_NODE *)Entry2; - - return threadNode1->ThreadId == threadNode2->ThreadId; -} - -ULONG PhpThreadNodeHashtableHashFunction( - _In_ PVOID Entry - ) -{ - return HandleToUlong((*(PPH_THREAD_NODE *)Entry)->ThreadId) / 4; -} - -VOID PhLoadSettingsThreadList( - _Inout_ PPH_THREAD_LIST_CONTEXT Context - ) -{ - PPH_STRING settings; - PPH_STRING sortSettings; - PH_TREENEW_COLUMN column; - ULONG sortColumn; - PH_SORT_ORDER sortOrder; - - if (!Context->UseCycleTime) - { - column.Id = PHTHTLC_CYCLESDELTA; - column.Text = L"Context switches delta"; - TreeNew_SetColumn(Context->TreeNewHandle, TN_COLUMN_TEXT, &column); - } - - if (Context->HasServices) - { - column.Id = PHTHTLC_SERVICE; - column.Visible = TRUE; - TreeNew_SetColumn(Context->TreeNewHandle, TN_COLUMN_FLAG_VISIBLE, &column); - } - - settings = PhGetStringSetting(L"ThreadTreeListColumns"); - sortSettings = PhGetStringSetting(L"ThreadTreeListSort"); - PhCmLoadSettingsEx(Context->TreeNewHandle, &Context->Cm, PH_CM_COLUMN_WIDTHS_ONLY, &settings->sr, &sortSettings->sr); - PhDereferenceObject(settings); - PhDereferenceObject(sortSettings); - - TreeNew_GetSort(Context->TreeNewHandle, &sortColumn, &sortOrder); - - // Make sure we're not sorting by an invisible column. - if (sortOrder != NoSortOrder && !(TreeNew_GetColumn(Context->TreeNewHandle, sortColumn, &column) && column.Visible)) - { - TreeNew_SetSort(Context->TreeNewHandle, PHTHTLC_CYCLESDELTA, DescendingSortOrder); - } -} - -VOID PhSaveSettingsThreadList( - _Inout_ PPH_THREAD_LIST_CONTEXT Context - ) -{ - PPH_STRING settings; - PPH_STRING sortSettings; - - settings = PhCmSaveSettingsEx(Context->TreeNewHandle, &Context->Cm, PH_CM_COLUMN_WIDTHS_ONLY, &sortSettings); - PhSetStringSetting2(L"ThreadTreeListColumns", &settings->sr); - PhSetStringSetting2(L"ThreadTreeListSort", &sortSettings->sr); - PhDereferenceObject(settings); - PhDereferenceObject(sortSettings); -} - -PPH_THREAD_NODE PhAddThreadNode( - _Inout_ PPH_THREAD_LIST_CONTEXT Context, - _In_ PPH_THREAD_ITEM ThreadItem, - _In_ BOOLEAN FirstRun - ) -{ - PPH_THREAD_NODE threadNode; - - threadNode = PhAllocate(PhEmGetObjectSize(EmThreadNodeType, sizeof(PH_THREAD_NODE))); - memset(threadNode, 0, sizeof(PH_THREAD_NODE)); - PhInitializeTreeNewNode(&threadNode->Node); - - if (Context->EnableStateHighlighting && !FirstRun) - { - PhChangeShStateTn( - &threadNode->Node, - &threadNode->ShState, - &Context->NodeStateList, - NewItemState, - PhCsColorNew, - NULL - ); - } - - threadNode->ThreadId = ThreadItem->ThreadId; - threadNode->ThreadItem = ThreadItem; - PhReferenceObject(ThreadItem); - - memset(threadNode->TextCache, 0, sizeof(PH_STRINGREF) * PHTHTLC_MAXIMUM); - threadNode->Node.TextCache = threadNode->TextCache; - threadNode->Node.TextCacheSize = PHTHTLC_MAXIMUM; - - PhAddEntryHashtable(Context->NodeHashtable, &threadNode); - PhAddItemList(Context->NodeList, threadNode); - - PhEmCallObjectOperation(EmThreadNodeType, threadNode, EmObjectCreate); - - TreeNew_NodesStructured(Context->TreeNewHandle); - - return threadNode; -} - -PPH_THREAD_NODE PhFindThreadNode( - _In_ PPH_THREAD_LIST_CONTEXT Context, - _In_ HANDLE ThreadId - ) -{ - PH_THREAD_NODE lookupThreadNode; - PPH_THREAD_NODE lookupThreadNodePtr = &lookupThreadNode; - PPH_THREAD_NODE *threadNode; - - lookupThreadNode.ThreadId = ThreadId; - - threadNode = (PPH_THREAD_NODE *)PhFindEntryHashtable( - Context->NodeHashtable, - &lookupThreadNodePtr - ); - - if (threadNode) - return *threadNode; - else - return NULL; -} - -VOID PhRemoveThreadNode( - _In_ PPH_THREAD_LIST_CONTEXT Context, - _In_ PPH_THREAD_NODE ThreadNode - ) -{ - // Remove from the hashtable here to avoid problems in case the key is re-used. - PhRemoveEntryHashtable(Context->NodeHashtable, &ThreadNode); - - if (Context->EnableStateHighlighting) - { - PhChangeShStateTn( - &ThreadNode->Node, - &ThreadNode->ShState, - &Context->NodeStateList, - RemovingItemState, - PhCsColorRemoved, - Context->TreeNewHandle - ); - } - else - { - PhpRemoveThreadNode(ThreadNode, Context); - } -} - -VOID PhpDestroyThreadNode( - _In_ PPH_THREAD_NODE ThreadNode - ) -{ - PhEmCallObjectOperation(EmThreadNodeType, ThreadNode, EmObjectDelete); - - if (ThreadNode->CyclesDeltaText) PhDereferenceObject(ThreadNode->CyclesDeltaText); - if (ThreadNode->StartAddressText) PhDereferenceObject(ThreadNode->StartAddressText); - if (ThreadNode->PriorityText) PhDereferenceObject(ThreadNode->PriorityText); - - PhDereferenceObject(ThreadNode->ThreadItem); - - PhFree(ThreadNode); -} - -VOID PhpRemoveThreadNode( - _In_ PPH_THREAD_NODE ThreadNode, - _In_ PPH_THREAD_LIST_CONTEXT Context // PH_TICK_SH_STATE requires this parameter to be after ThreadNode - ) -{ - ULONG index; - - // Remove from list and cleanup. - - if ((index = PhFindItemList(Context->NodeList, ThreadNode)) != -1) - PhRemoveItemList(Context->NodeList, index); - - PhpDestroyThreadNode(ThreadNode); - - TreeNew_NodesStructured(Context->TreeNewHandle); -} - -VOID PhUpdateThreadNode( - _In_ PPH_THREAD_LIST_CONTEXT Context, - _In_ PPH_THREAD_NODE ThreadNode - ) -{ - memset(ThreadNode->TextCache, 0, sizeof(PH_STRINGREF) * PHTHTLC_MAXIMUM); - - ThreadNode->ValidMask = 0; - PhInvalidateTreeNewNode(&ThreadNode->Node, TN_CACHE_COLOR); - TreeNew_NodesStructured(Context->TreeNewHandle); -} - -VOID PhTickThreadNodes( - _In_ PPH_THREAD_LIST_CONTEXT Context - ) -{ - PH_TICK_SH_STATE_TN(PH_THREAD_NODE, ShState, Context->NodeStateList, PhpRemoveThreadNode, PhCsHighlightingDuration, Context->TreeNewHandle, TRUE, NULL, Context); -} - -#define SORT_FUNCTION(Column) PhpThreadTreeNewCompare##Column - -#define BEGIN_SORT_FUNCTION(Column) static int __cdecl PhpThreadTreeNewCompare##Column( \ - _In_ void *_context, \ - _In_ const void *_elem1, \ - _In_ const void *_elem2 \ - ) \ -{ \ - PPH_THREAD_NODE node1 = *(PPH_THREAD_NODE *)_elem1; \ - PPH_THREAD_NODE node2 = *(PPH_THREAD_NODE *)_elem2; \ - PPH_THREAD_ITEM threadItem1 = node1->ThreadItem; \ - PPH_THREAD_ITEM threadItem2 = node2->ThreadItem; \ - PPH_THREAD_LIST_CONTEXT context = (PPH_THREAD_LIST_CONTEXT)_context; \ - int sortResult = 0; - -#define END_SORT_FUNCTION \ - if (sortResult == 0) \ - sortResult = uintptrcmp((ULONG_PTR)node1->ThreadId, (ULONG_PTR)node2->ThreadId); \ - \ - return PhModifySort(sortResult, context->TreeNewSortOrder); \ -} - -LONG PhpThreadTreeNewPostSortFunction( - _In_ LONG Result, - _In_ PVOID Node1, - _In_ PVOID Node2, - _In_ PH_SORT_ORDER SortOrder - ) -{ - if (Result == 0) - Result = uintptrcmp((ULONG_PTR)((PPH_THREAD_NODE)Node1)->ThreadId, (ULONG_PTR)((PPH_THREAD_NODE)Node2)->ThreadId); - - return PhModifySort(Result, SortOrder); -} - -BEGIN_SORT_FUNCTION(Tid) -{ - sortResult = uintptrcmp((ULONG_PTR)node1->ThreadId, (ULONG_PTR)node2->ThreadId); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(Cpu) -{ - sortResult = singlecmp(threadItem1->CpuUsage, threadItem2->CpuUsage); - - if (sortResult == 0) - { - if (context->UseCycleTime) - sortResult = uint64cmp(threadItem1->CyclesDelta.Delta, threadItem2->CyclesDelta.Delta); - else - sortResult = uintcmp(threadItem1->ContextSwitchesDelta.Delta, threadItem2->ContextSwitchesDelta.Delta); - } -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(CyclesDelta) -{ - if (context->UseCycleTime) - sortResult = uint64cmp(threadItem1->CyclesDelta.Delta, threadItem2->CyclesDelta.Delta); - else - sortResult = uintcmp(threadItem1->ContextSwitchesDelta.Delta, threadItem2->ContextSwitchesDelta.Delta); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(StartAddress) -{ - sortResult = PhCompareStringWithNull(threadItem1->StartAddressString, threadItem2->StartAddressString, TRUE); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(Priority) -{ - sortResult = intcmp(threadItem1->BasePriorityIncrement, threadItem2->BasePriorityIncrement); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(Service) -{ - sortResult = PhCompareStringWithNull(threadItem1->ServiceName, threadItem2->ServiceName, TRUE); -} -END_SORT_FUNCTION - -BOOLEAN NTAPI PhpThreadTreeNewCallback( - _In_ HWND hwnd, - _In_ PH_TREENEW_MESSAGE Message, - _In_opt_ PVOID Parameter1, - _In_opt_ PVOID Parameter2, - _In_opt_ PVOID Context - ) -{ - PPH_THREAD_LIST_CONTEXT context; - PPH_THREAD_NODE node; - - context = Context; - - if (PhCmForwardMessage(hwnd, Message, Parameter1, Parameter2, &context->Cm)) - return TRUE; - - switch (Message) - { - case TreeNewGetChildren: - { - PPH_TREENEW_GET_CHILDREN getChildren = Parameter1; - - if (!getChildren->Node) - { - static PVOID sortFunctions[] = - { - SORT_FUNCTION(Tid), - SORT_FUNCTION(Cpu), - SORT_FUNCTION(CyclesDelta), - SORT_FUNCTION(StartAddress), - SORT_FUNCTION(Priority), - SORT_FUNCTION(Service) - }; - int (__cdecl *sortFunction)(void *, const void *, const void *); - - if (!PhCmForwardSort( - (PPH_TREENEW_NODE *)context->NodeList->Items, - context->NodeList->Count, - context->TreeNewSortColumn, - context->TreeNewSortOrder, - &context->Cm - )) - { - if (context->TreeNewSortColumn < PHTHTLC_MAXIMUM) - sortFunction = sortFunctions[context->TreeNewSortColumn]; - else - sortFunction = NULL; - } - else - { - sortFunction = NULL; - } - - if (sortFunction) - { - qsort_s(context->NodeList->Items, context->NodeList->Count, sizeof(PVOID), sortFunction, context); - } - - getChildren->Children = (PPH_TREENEW_NODE *)context->NodeList->Items; - getChildren->NumberOfChildren = context->NodeList->Count; - } - } - return TRUE; - case TreeNewIsLeaf: - { - PPH_TREENEW_IS_LEAF isLeaf = Parameter1; - - isLeaf->IsLeaf = TRUE; - } - return TRUE; - case TreeNewGetCellText: - { - PPH_TREENEW_GET_CELL_TEXT getCellText = Parameter1; - PPH_THREAD_ITEM threadItem; - - node = (PPH_THREAD_NODE)getCellText->Node; - threadItem = node->ThreadItem; - - switch (getCellText->Id) - { - case PHTHTLC_TID: - PhInitializeStringRefLongHint(&getCellText->Text, threadItem->ThreadIdString); - break; - case PHTHTLC_CPU: - { - FLOAT cpuUsage; - - cpuUsage = threadItem->CpuUsage * 100; - - if (cpuUsage >= 0.01) - { - PH_FORMAT format; - SIZE_T returnLength; - - PhInitFormatF(&format, cpuUsage, 2); - - if (PhFormatToBuffer(&format, 1, node->CpuUsageText, sizeof(node->CpuUsageText), &returnLength)) - { - getCellText->Text.Buffer = node->CpuUsageText; - getCellText->Text.Length = returnLength - sizeof(WCHAR); // minus null terminator - } - } - else if (cpuUsage != 0 && PhCsShowCpuBelow001) - { - PH_FORMAT format[2]; - SIZE_T returnLength; - - PhInitFormatS(&format[0], L"< "); - PhInitFormatF(&format[1], 0.01, 2); - - if (PhFormatToBuffer(format, 2, node->CpuUsageText, sizeof(node->CpuUsageText), &returnLength)) - { - getCellText->Text.Buffer = node->CpuUsageText; - getCellText->Text.Length = returnLength - sizeof(WCHAR); - } - } - } - break; - case PHTHTLC_CYCLESDELTA: - if (context->UseCycleTime) - { - if (threadItem->CyclesDelta.Delta != threadItem->CyclesDelta.Value && threadItem->CyclesDelta.Delta != 0) - { - PhMoveReference(&node->CyclesDeltaText, PhFormatUInt64(threadItem->CyclesDelta.Delta, TRUE)); - getCellText->Text = node->CyclesDeltaText->sr; - } - } - else - { - if (threadItem->ContextSwitchesDelta.Delta != threadItem->ContextSwitchesDelta.Value && threadItem->ContextSwitchesDelta.Delta != 0) - { - PhMoveReference(&node->CyclesDeltaText, PhFormatUInt64(threadItem->ContextSwitchesDelta.Delta, TRUE)); - getCellText->Text = node->CyclesDeltaText->sr; - } - } - break; - case PHTHTLC_STARTADDRESS: - PhSwapReference(&node->StartAddressText, threadItem->StartAddressString); - getCellText->Text = PhGetStringRef(node->StartAddressText); - break; - case PHTHTLC_PRIORITY: - PhMoveReference(&node->PriorityText, PhGetBasePriorityIncrementString(threadItem->BasePriorityIncrement)); - getCellText->Text = PhGetStringRef(node->PriorityText); - break; - case PHTHTLC_SERVICE: - getCellText->Text = PhGetStringRef(threadItem->ServiceName); - break; - default: - return FALSE; - } - - getCellText->Flags = TN_CACHE; - } - return TRUE; - case TreeNewGetNodeColor: - { - PPH_TREENEW_GET_NODE_COLOR getNodeColor = Parameter1; - PPH_THREAD_ITEM threadItem; - - node = (PPH_THREAD_NODE)getNodeColor->Node; - threadItem = node->ThreadItem; - - if (!threadItem) - ; // Dummy - else if (PhCsUseColorSuspended && threadItem->WaitReason == Suspended) - getNodeColor->BackColor = PhCsColorSuspended; - else if (PhCsUseColorGuiThreads && threadItem->IsGuiThread) - getNodeColor->BackColor = PhCsColorGuiThreads; - - getNodeColor->Flags = TN_CACHE | TN_AUTO_FORECOLOR; - } - return TRUE; - case TreeNewSortChanged: - { - TreeNew_GetSort(hwnd, &context->TreeNewSortColumn, &context->TreeNewSortOrder); - // Force a rebuild to sort the items. - TreeNew_NodesStructured(hwnd); - } - return TRUE; - case TreeNewSelectionChanged: - { - SendMessage(context->ParentWindowHandle, WM_PH_THREAD_SELECTION_CHANGED, 0, 0); - } - return TRUE; - case TreeNewKeyDown: - { - PPH_TREENEW_KEY_EVENT keyEvent = Parameter1; - - switch (keyEvent->VirtualKey) - { - case 'C': - if (GetKeyState(VK_CONTROL) < 0) - SendMessage(context->ParentWindowHandle, WM_COMMAND, ID_THREAD_COPY, 0); - break; - case 'A': - if (GetKeyState(VK_CONTROL) < 0) - TreeNew_SelectRange(context->TreeNewHandle, 0, -1); - break; - case VK_DELETE: - SendMessage(context->ParentWindowHandle, WM_COMMAND, ID_THREAD_TERMINATE, 0); - break; - case VK_RETURN: - SendMessage(context->ParentWindowHandle, WM_COMMAND, ID_THREAD_INSPECT, 0); - break; - } - } - return TRUE; - case TreeNewHeaderRightClick: - { - PH_TN_COLUMN_MENU_DATA data; - - // Customizable columns are disabled until we can figure out how to make it - // co-operate with the column adjustments (e.g. Cycles Delta vs Context Switches Delta, - // Service column). - - data.TreeNewHandle = hwnd; - data.MouseEvent = Parameter1; - data.DefaultSortColumn = PHTHTLC_CYCLESDELTA; - data.DefaultSortOrder = DescendingSortOrder; - PhInitializeTreeNewColumnMenuEx(&data, PH_TN_COLUMN_MENU_NO_VISIBILITY); - - data.Selection = PhShowEMenu(data.Menu, hwnd, PH_EMENU_SHOW_LEFTRIGHT, - PH_ALIGN_LEFT | PH_ALIGN_TOP, data.MouseEvent->ScreenLocation.x, data.MouseEvent->ScreenLocation.y); - PhHandleTreeNewColumnMenu(&data); - PhDeleteTreeNewColumnMenu(&data); - } - return TRUE; - case TreeNewLeftDoubleClick: - { - SendMessage(context->ParentWindowHandle, WM_COMMAND, ID_THREAD_INSPECT, 0); - } - return TRUE; - case TreeNewContextMenu: - { - PPH_TREENEW_CONTEXT_MENU contextMenu = Parameter1; - - SendMessage(context->ParentWindowHandle, WM_COMMAND, ID_SHOWCONTEXTMENU, (LPARAM)contextMenu); - } - return TRUE; - case TreeNewGetDialogCode: - { - PULONG code = Parameter2; - - if (PtrToUlong(Parameter1) == VK_RETURN) - { - *code = DLGC_WANTMESSAGE; - return TRUE; - } - } - return FALSE; - } - - return FALSE; -} - -PPH_THREAD_ITEM PhGetSelectedThreadItem( - _In_ PPH_THREAD_LIST_CONTEXT Context - ) -{ - PPH_THREAD_ITEM threadItem = NULL; - ULONG i; - - for (i = 0; i < Context->NodeList->Count; i++) - { - PPH_THREAD_NODE node = Context->NodeList->Items[i]; - - if (node->Node.Selected) - { - threadItem = node->ThreadItem; - break; - } - } - - return threadItem; -} - -VOID PhGetSelectedThreadItems( - _In_ PPH_THREAD_LIST_CONTEXT Context, - _Out_ PPH_THREAD_ITEM **Threads, - _Out_ PULONG NumberOfThreads - ) -{ - PH_ARRAY array; - ULONG i; - - PhInitializeArray(&array, sizeof(PVOID), 2); - - for (i = 0; i < Context->NodeList->Count; i++) - { - PPH_THREAD_NODE node = Context->NodeList->Items[i]; - - if (node->Node.Selected) - PhAddItemArray(&array, &node->ThreadItem); - } - - *NumberOfThreads = (ULONG)array.Count; - *Threads = PhFinalArrayItems(&array); -} - -VOID PhDeselectAllThreadNodes( - _In_ PPH_THREAD_LIST_CONTEXT Context - ) -{ - TreeNew_DeselectRange(Context->TreeNewHandle, 0, -1); -} +/* + * Process Hacker - + * thread list + * + * Copyright (C) 2011-2012 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +BOOLEAN PhpThreadNodeHashtableEqualFunction( + _In_ PVOID Entry1, + _In_ PVOID Entry2 + ); + +ULONG PhpThreadNodeHashtableHashFunction( + _In_ PVOID Entry + ); + +VOID PhpDestroyThreadNode( + _In_ PPH_THREAD_NODE ThreadNode + ); + +VOID PhpRemoveThreadNode( + _In_ PPH_THREAD_NODE ThreadNode, + _In_ PPH_THREAD_LIST_CONTEXT Context + ); + +LONG PhpThreadTreeNewPostSortFunction( + _In_ LONG Result, + _In_ PVOID Node1, + _In_ PVOID Node2, + _In_ PH_SORT_ORDER SortOrder + ); + +BOOLEAN NTAPI PhpThreadTreeNewCallback( + _In_ HWND hwnd, + _In_ PH_TREENEW_MESSAGE Message, + _In_opt_ PVOID Parameter1, + _In_opt_ PVOID Parameter2, + _In_opt_ PVOID Context + ); + +VOID PhInitializeThreadList( + _In_ HWND ParentWindowHandle, + _In_ HWND TreeNewHandle, + _Out_ PPH_THREAD_LIST_CONTEXT Context + ) +{ + HWND hwnd; + + memset(Context, 0, sizeof(PH_THREAD_LIST_CONTEXT)); + Context->EnableStateHighlighting = TRUE; + + Context->NodeHashtable = PhCreateHashtable( + sizeof(PPH_THREAD_NODE), + PhpThreadNodeHashtableEqualFunction, + PhpThreadNodeHashtableHashFunction, + 100 + ); + Context->NodeList = PhCreateList(100); + + Context->ParentWindowHandle = ParentWindowHandle; + Context->TreeNewHandle = TreeNewHandle; + hwnd = TreeNewHandle; + PhSetControlTheme(hwnd, L"explorer"); + + TreeNew_SetCallback(hwnd, PhpThreadTreeNewCallback, Context); + + TreeNew_SetRedraw(hwnd, FALSE); + + // Default columns + PhAddTreeNewColumn(hwnd, PHTHTLC_TID, TRUE, L"TID", 50, PH_ALIGN_RIGHT, 0, DT_RIGHT); + PhAddTreeNewColumnEx(hwnd, PHTHTLC_CPU, TRUE, L"CPU", 45, PH_ALIGN_RIGHT, 1, DT_RIGHT, TRUE); + PhAddTreeNewColumnEx(hwnd, PHTHTLC_CYCLESDELTA, TRUE, L"Cycles delta", 80, PH_ALIGN_RIGHT, 2, DT_RIGHT, TRUE); + PhAddTreeNewColumn(hwnd, PHTHTLC_STARTADDRESS, TRUE, L"Start address", 180, PH_ALIGN_LEFT, 3, 0); + PhAddTreeNewColumnEx(hwnd, PHTHTLC_PRIORITY, TRUE, L"Priority", 80, PH_ALIGN_LEFT, 4, 0, TRUE); + PhAddTreeNewColumn(hwnd, PHTHTLC_SERVICE, FALSE, L"Service", 100, PH_ALIGN_LEFT, -1, 0); + + TreeNew_SetRedraw(hwnd, TRUE); + + TreeNew_SetSort(hwnd, PHTHTLC_CYCLESDELTA, DescendingSortOrder); + + PhCmInitializeManager(&Context->Cm, hwnd, PHTHTLC_MAXIMUM, PhpThreadTreeNewPostSortFunction); +} + +VOID PhDeleteThreadList( + _In_ PPH_THREAD_LIST_CONTEXT Context + ) +{ + ULONG i; + + PhCmDeleteManager(&Context->Cm); + + for (i = 0; i < Context->NodeList->Count; i++) + PhpDestroyThreadNode(Context->NodeList->Items[i]); + + PhDereferenceObject(Context->NodeHashtable); + PhDereferenceObject(Context->NodeList); +} + +BOOLEAN PhpThreadNodeHashtableEqualFunction( + _In_ PVOID Entry1, + _In_ PVOID Entry2 + ) +{ + PPH_THREAD_NODE threadNode1 = *(PPH_THREAD_NODE *)Entry1; + PPH_THREAD_NODE threadNode2 = *(PPH_THREAD_NODE *)Entry2; + + return threadNode1->ThreadId == threadNode2->ThreadId; +} + +ULONG PhpThreadNodeHashtableHashFunction( + _In_ PVOID Entry + ) +{ + return HandleToUlong((*(PPH_THREAD_NODE *)Entry)->ThreadId) / 4; +} + +VOID PhLoadSettingsThreadList( + _Inout_ PPH_THREAD_LIST_CONTEXT Context + ) +{ + PPH_STRING settings; + PPH_STRING sortSettings; + PH_TREENEW_COLUMN column; + ULONG sortColumn; + PH_SORT_ORDER sortOrder; + + if (!Context->UseCycleTime) + { + column.Id = PHTHTLC_CYCLESDELTA; + column.Text = L"Context switches delta"; + TreeNew_SetColumn(Context->TreeNewHandle, TN_COLUMN_TEXT, &column); + } + + if (Context->HasServices) + { + column.Id = PHTHTLC_SERVICE; + column.Visible = TRUE; + TreeNew_SetColumn(Context->TreeNewHandle, TN_COLUMN_FLAG_VISIBLE, &column); + } + + settings = PhGetStringSetting(L"ThreadTreeListColumns"); + sortSettings = PhGetStringSetting(L"ThreadTreeListSort"); + PhCmLoadSettingsEx(Context->TreeNewHandle, &Context->Cm, PH_CM_COLUMN_WIDTHS_ONLY, &settings->sr, &sortSettings->sr); + PhDereferenceObject(settings); + PhDereferenceObject(sortSettings); + + TreeNew_GetSort(Context->TreeNewHandle, &sortColumn, &sortOrder); + + // Make sure we're not sorting by an invisible column. + if (sortOrder != NoSortOrder && !(TreeNew_GetColumn(Context->TreeNewHandle, sortColumn, &column) && column.Visible)) + { + TreeNew_SetSort(Context->TreeNewHandle, PHTHTLC_CYCLESDELTA, DescendingSortOrder); + } +} + +VOID PhSaveSettingsThreadList( + _Inout_ PPH_THREAD_LIST_CONTEXT Context + ) +{ + PPH_STRING settings; + PPH_STRING sortSettings; + + settings = PhCmSaveSettingsEx(Context->TreeNewHandle, &Context->Cm, PH_CM_COLUMN_WIDTHS_ONLY, &sortSettings); + PhSetStringSetting2(L"ThreadTreeListColumns", &settings->sr); + PhSetStringSetting2(L"ThreadTreeListSort", &sortSettings->sr); + PhDereferenceObject(settings); + PhDereferenceObject(sortSettings); +} + +PPH_THREAD_NODE PhAddThreadNode( + _Inout_ PPH_THREAD_LIST_CONTEXT Context, + _In_ PPH_THREAD_ITEM ThreadItem, + _In_ BOOLEAN FirstRun + ) +{ + PPH_THREAD_NODE threadNode; + + threadNode = PhAllocate(PhEmGetObjectSize(EmThreadNodeType, sizeof(PH_THREAD_NODE))); + memset(threadNode, 0, sizeof(PH_THREAD_NODE)); + PhInitializeTreeNewNode(&threadNode->Node); + + if (Context->EnableStateHighlighting && !FirstRun) + { + PhChangeShStateTn( + &threadNode->Node, + &threadNode->ShState, + &Context->NodeStateList, + NewItemState, + PhCsColorNew, + NULL + ); + } + + threadNode->ThreadId = ThreadItem->ThreadId; + threadNode->ThreadItem = ThreadItem; + PhReferenceObject(ThreadItem); + + memset(threadNode->TextCache, 0, sizeof(PH_STRINGREF) * PHTHTLC_MAXIMUM); + threadNode->Node.TextCache = threadNode->TextCache; + threadNode->Node.TextCacheSize = PHTHTLC_MAXIMUM; + + PhAddEntryHashtable(Context->NodeHashtable, &threadNode); + PhAddItemList(Context->NodeList, threadNode); + + PhEmCallObjectOperation(EmThreadNodeType, threadNode, EmObjectCreate); + + TreeNew_NodesStructured(Context->TreeNewHandle); + + return threadNode; +} + +PPH_THREAD_NODE PhFindThreadNode( + _In_ PPH_THREAD_LIST_CONTEXT Context, + _In_ HANDLE ThreadId + ) +{ + PH_THREAD_NODE lookupThreadNode; + PPH_THREAD_NODE lookupThreadNodePtr = &lookupThreadNode; + PPH_THREAD_NODE *threadNode; + + lookupThreadNode.ThreadId = ThreadId; + + threadNode = (PPH_THREAD_NODE *)PhFindEntryHashtable( + Context->NodeHashtable, + &lookupThreadNodePtr + ); + + if (threadNode) + return *threadNode; + else + return NULL; +} + +VOID PhRemoveThreadNode( + _In_ PPH_THREAD_LIST_CONTEXT Context, + _In_ PPH_THREAD_NODE ThreadNode + ) +{ + // Remove from the hashtable here to avoid problems in case the key is re-used. + PhRemoveEntryHashtable(Context->NodeHashtable, &ThreadNode); + + if (Context->EnableStateHighlighting) + { + PhChangeShStateTn( + &ThreadNode->Node, + &ThreadNode->ShState, + &Context->NodeStateList, + RemovingItemState, + PhCsColorRemoved, + Context->TreeNewHandle + ); + } + else + { + PhpRemoveThreadNode(ThreadNode, Context); + } +} + +VOID PhpDestroyThreadNode( + _In_ PPH_THREAD_NODE ThreadNode + ) +{ + PhEmCallObjectOperation(EmThreadNodeType, ThreadNode, EmObjectDelete); + + if (ThreadNode->CyclesDeltaText) PhDereferenceObject(ThreadNode->CyclesDeltaText); + if (ThreadNode->StartAddressText) PhDereferenceObject(ThreadNode->StartAddressText); + if (ThreadNode->PriorityText) PhDereferenceObject(ThreadNode->PriorityText); + + PhDereferenceObject(ThreadNode->ThreadItem); + + PhFree(ThreadNode); +} + +VOID PhpRemoveThreadNode( + _In_ PPH_THREAD_NODE ThreadNode, + _In_ PPH_THREAD_LIST_CONTEXT Context // PH_TICK_SH_STATE requires this parameter to be after ThreadNode + ) +{ + ULONG index; + + // Remove from list and cleanup. + + if ((index = PhFindItemList(Context->NodeList, ThreadNode)) != -1) + PhRemoveItemList(Context->NodeList, index); + + PhpDestroyThreadNode(ThreadNode); + + TreeNew_NodesStructured(Context->TreeNewHandle); +} + +VOID PhUpdateThreadNode( + _In_ PPH_THREAD_LIST_CONTEXT Context, + _In_ PPH_THREAD_NODE ThreadNode + ) +{ + memset(ThreadNode->TextCache, 0, sizeof(PH_STRINGREF) * PHTHTLC_MAXIMUM); + + ThreadNode->ValidMask = 0; + PhInvalidateTreeNewNode(&ThreadNode->Node, TN_CACHE_COLOR); + TreeNew_NodesStructured(Context->TreeNewHandle); +} + +VOID PhTickThreadNodes( + _In_ PPH_THREAD_LIST_CONTEXT Context + ) +{ + PH_TICK_SH_STATE_TN(PH_THREAD_NODE, ShState, Context->NodeStateList, PhpRemoveThreadNode, PhCsHighlightingDuration, Context->TreeNewHandle, TRUE, NULL, Context); +} + +#define SORT_FUNCTION(Column) PhpThreadTreeNewCompare##Column + +#define BEGIN_SORT_FUNCTION(Column) static int __cdecl PhpThreadTreeNewCompare##Column( \ + _In_ void *_context, \ + _In_ const void *_elem1, \ + _In_ const void *_elem2 \ + ) \ +{ \ + PPH_THREAD_NODE node1 = *(PPH_THREAD_NODE *)_elem1; \ + PPH_THREAD_NODE node2 = *(PPH_THREAD_NODE *)_elem2; \ + PPH_THREAD_ITEM threadItem1 = node1->ThreadItem; \ + PPH_THREAD_ITEM threadItem2 = node2->ThreadItem; \ + PPH_THREAD_LIST_CONTEXT context = (PPH_THREAD_LIST_CONTEXT)_context; \ + int sortResult = 0; + +#define END_SORT_FUNCTION \ + if (sortResult == 0) \ + sortResult = uintptrcmp((ULONG_PTR)node1->ThreadId, (ULONG_PTR)node2->ThreadId); \ + \ + return PhModifySort(sortResult, context->TreeNewSortOrder); \ +} + +LONG PhpThreadTreeNewPostSortFunction( + _In_ LONG Result, + _In_ PVOID Node1, + _In_ PVOID Node2, + _In_ PH_SORT_ORDER SortOrder + ) +{ + if (Result == 0) + Result = uintptrcmp((ULONG_PTR)((PPH_THREAD_NODE)Node1)->ThreadId, (ULONG_PTR)((PPH_THREAD_NODE)Node2)->ThreadId); + + return PhModifySort(Result, SortOrder); +} + +BEGIN_SORT_FUNCTION(Tid) +{ + sortResult = uintptrcmp((ULONG_PTR)node1->ThreadId, (ULONG_PTR)node2->ThreadId); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(Cpu) +{ + sortResult = singlecmp(threadItem1->CpuUsage, threadItem2->CpuUsage); + + if (sortResult == 0) + { + if (context->UseCycleTime) + sortResult = uint64cmp(threadItem1->CyclesDelta.Delta, threadItem2->CyclesDelta.Delta); + else + sortResult = uintcmp(threadItem1->ContextSwitchesDelta.Delta, threadItem2->ContextSwitchesDelta.Delta); + } +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(CyclesDelta) +{ + if (context->UseCycleTime) + sortResult = uint64cmp(threadItem1->CyclesDelta.Delta, threadItem2->CyclesDelta.Delta); + else + sortResult = uintcmp(threadItem1->ContextSwitchesDelta.Delta, threadItem2->ContextSwitchesDelta.Delta); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(StartAddress) +{ + sortResult = PhCompareStringWithNull(threadItem1->StartAddressString, threadItem2->StartAddressString, TRUE); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(Priority) +{ + sortResult = intcmp(threadItem1->BasePriorityIncrement, threadItem2->BasePriorityIncrement); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(Service) +{ + sortResult = PhCompareStringWithNull(threadItem1->ServiceName, threadItem2->ServiceName, TRUE); +} +END_SORT_FUNCTION + +BOOLEAN NTAPI PhpThreadTreeNewCallback( + _In_ HWND hwnd, + _In_ PH_TREENEW_MESSAGE Message, + _In_opt_ PVOID Parameter1, + _In_opt_ PVOID Parameter2, + _In_opt_ PVOID Context + ) +{ + PPH_THREAD_LIST_CONTEXT context; + PPH_THREAD_NODE node; + + context = Context; + + if (PhCmForwardMessage(hwnd, Message, Parameter1, Parameter2, &context->Cm)) + return TRUE; + + switch (Message) + { + case TreeNewGetChildren: + { + PPH_TREENEW_GET_CHILDREN getChildren = Parameter1; + + if (!getChildren->Node) + { + static PVOID sortFunctions[] = + { + SORT_FUNCTION(Tid), + SORT_FUNCTION(Cpu), + SORT_FUNCTION(CyclesDelta), + SORT_FUNCTION(StartAddress), + SORT_FUNCTION(Priority), + SORT_FUNCTION(Service) + }; + int (__cdecl *sortFunction)(void *, const void *, const void *); + + if (!PhCmForwardSort( + (PPH_TREENEW_NODE *)context->NodeList->Items, + context->NodeList->Count, + context->TreeNewSortColumn, + context->TreeNewSortOrder, + &context->Cm + )) + { + if (context->TreeNewSortColumn < PHTHTLC_MAXIMUM) + sortFunction = sortFunctions[context->TreeNewSortColumn]; + else + sortFunction = NULL; + } + else + { + sortFunction = NULL; + } + + if (sortFunction) + { + qsort_s(context->NodeList->Items, context->NodeList->Count, sizeof(PVOID), sortFunction, context); + } + + getChildren->Children = (PPH_TREENEW_NODE *)context->NodeList->Items; + getChildren->NumberOfChildren = context->NodeList->Count; + } + } + return TRUE; + case TreeNewIsLeaf: + { + PPH_TREENEW_IS_LEAF isLeaf = Parameter1; + + isLeaf->IsLeaf = TRUE; + } + return TRUE; + case TreeNewGetCellText: + { + PPH_TREENEW_GET_CELL_TEXT getCellText = Parameter1; + PPH_THREAD_ITEM threadItem; + + node = (PPH_THREAD_NODE)getCellText->Node; + threadItem = node->ThreadItem; + + switch (getCellText->Id) + { + case PHTHTLC_TID: + PhInitializeStringRefLongHint(&getCellText->Text, threadItem->ThreadIdString); + break; + case PHTHTLC_CPU: + { + FLOAT cpuUsage; + + cpuUsage = threadItem->CpuUsage * 100; + + if (cpuUsage >= 0.01) + { + PH_FORMAT format; + SIZE_T returnLength; + + PhInitFormatF(&format, cpuUsage, 2); + + if (PhFormatToBuffer(&format, 1, node->CpuUsageText, sizeof(node->CpuUsageText), &returnLength)) + { + getCellText->Text.Buffer = node->CpuUsageText; + getCellText->Text.Length = returnLength - sizeof(WCHAR); // minus null terminator + } + } + else if (cpuUsage != 0 && PhCsShowCpuBelow001) + { + PH_FORMAT format[2]; + SIZE_T returnLength; + + PhInitFormatS(&format[0], L"< "); + PhInitFormatF(&format[1], 0.01, 2); + + if (PhFormatToBuffer(format, 2, node->CpuUsageText, sizeof(node->CpuUsageText), &returnLength)) + { + getCellText->Text.Buffer = node->CpuUsageText; + getCellText->Text.Length = returnLength - sizeof(WCHAR); + } + } + } + break; + case PHTHTLC_CYCLESDELTA: + if (context->UseCycleTime) + { + if (threadItem->CyclesDelta.Delta != threadItem->CyclesDelta.Value && threadItem->CyclesDelta.Delta != 0) + { + PhMoveReference(&node->CyclesDeltaText, PhFormatUInt64(threadItem->CyclesDelta.Delta, TRUE)); + getCellText->Text = node->CyclesDeltaText->sr; + } + } + else + { + if (threadItem->ContextSwitchesDelta.Delta != threadItem->ContextSwitchesDelta.Value && threadItem->ContextSwitchesDelta.Delta != 0) + { + PhMoveReference(&node->CyclesDeltaText, PhFormatUInt64(threadItem->ContextSwitchesDelta.Delta, TRUE)); + getCellText->Text = node->CyclesDeltaText->sr; + } + } + break; + case PHTHTLC_STARTADDRESS: + PhSwapReference(&node->StartAddressText, threadItem->StartAddressString); + getCellText->Text = PhGetStringRef(node->StartAddressText); + break; + case PHTHTLC_PRIORITY: + PhMoveReference(&node->PriorityText, PhGetBasePriorityIncrementString(threadItem->BasePriorityIncrement)); + getCellText->Text = PhGetStringRef(node->PriorityText); + break; + case PHTHTLC_SERVICE: + getCellText->Text = PhGetStringRef(threadItem->ServiceName); + break; + default: + return FALSE; + } + + getCellText->Flags = TN_CACHE; + } + return TRUE; + case TreeNewGetNodeColor: + { + PPH_TREENEW_GET_NODE_COLOR getNodeColor = Parameter1; + PPH_THREAD_ITEM threadItem; + + node = (PPH_THREAD_NODE)getNodeColor->Node; + threadItem = node->ThreadItem; + + if (!threadItem) + ; // Dummy + else if (PhCsUseColorSuspended && threadItem->WaitReason == Suspended) + getNodeColor->BackColor = PhCsColorSuspended; + else if (PhCsUseColorGuiThreads && threadItem->IsGuiThread) + getNodeColor->BackColor = PhCsColorGuiThreads; + + getNodeColor->Flags = TN_CACHE | TN_AUTO_FORECOLOR; + } + return TRUE; + case TreeNewSortChanged: + { + TreeNew_GetSort(hwnd, &context->TreeNewSortColumn, &context->TreeNewSortOrder); + // Force a rebuild to sort the items. + TreeNew_NodesStructured(hwnd); + } + return TRUE; + case TreeNewSelectionChanged: + { + SendMessage(context->ParentWindowHandle, WM_PH_THREAD_SELECTION_CHANGED, 0, 0); + } + return TRUE; + case TreeNewKeyDown: + { + PPH_TREENEW_KEY_EVENT keyEvent = Parameter1; + + switch (keyEvent->VirtualKey) + { + case 'C': + if (GetKeyState(VK_CONTROL) < 0) + SendMessage(context->ParentWindowHandle, WM_COMMAND, ID_THREAD_COPY, 0); + break; + case 'A': + if (GetKeyState(VK_CONTROL) < 0) + TreeNew_SelectRange(context->TreeNewHandle, 0, -1); + break; + case VK_DELETE: + SendMessage(context->ParentWindowHandle, WM_COMMAND, ID_THREAD_TERMINATE, 0); + break; + case VK_RETURN: + SendMessage(context->ParentWindowHandle, WM_COMMAND, ID_THREAD_INSPECT, 0); + break; + } + } + return TRUE; + case TreeNewHeaderRightClick: + { + PH_TN_COLUMN_MENU_DATA data; + + // Customizable columns are disabled until we can figure out how to make it + // co-operate with the column adjustments (e.g. Cycles Delta vs Context Switches Delta, + // Service column). + + data.TreeNewHandle = hwnd; + data.MouseEvent = Parameter1; + data.DefaultSortColumn = PHTHTLC_CYCLESDELTA; + data.DefaultSortOrder = DescendingSortOrder; + PhInitializeTreeNewColumnMenuEx(&data, PH_TN_COLUMN_MENU_NO_VISIBILITY); + + data.Selection = PhShowEMenu(data.Menu, hwnd, PH_EMENU_SHOW_LEFTRIGHT, + PH_ALIGN_LEFT | PH_ALIGN_TOP, data.MouseEvent->ScreenLocation.x, data.MouseEvent->ScreenLocation.y); + PhHandleTreeNewColumnMenu(&data); + PhDeleteTreeNewColumnMenu(&data); + } + return TRUE; + case TreeNewLeftDoubleClick: + { + SendMessage(context->ParentWindowHandle, WM_COMMAND, ID_THREAD_INSPECT, 0); + } + return TRUE; + case TreeNewContextMenu: + { + PPH_TREENEW_CONTEXT_MENU contextMenu = Parameter1; + + SendMessage(context->ParentWindowHandle, WM_COMMAND, ID_SHOWCONTEXTMENU, (LPARAM)contextMenu); + } + return TRUE; + case TreeNewGetDialogCode: + { + PULONG code = Parameter2; + + if (PtrToUlong(Parameter1) == VK_RETURN) + { + *code = DLGC_WANTMESSAGE; + return TRUE; + } + } + return FALSE; + } + + return FALSE; +} + +PPH_THREAD_ITEM PhGetSelectedThreadItem( + _In_ PPH_THREAD_LIST_CONTEXT Context + ) +{ + PPH_THREAD_ITEM threadItem = NULL; + ULONG i; + + for (i = 0; i < Context->NodeList->Count; i++) + { + PPH_THREAD_NODE node = Context->NodeList->Items[i]; + + if (node->Node.Selected) + { + threadItem = node->ThreadItem; + break; + } + } + + return threadItem; +} + +VOID PhGetSelectedThreadItems( + _In_ PPH_THREAD_LIST_CONTEXT Context, + _Out_ PPH_THREAD_ITEM **Threads, + _Out_ PULONG NumberOfThreads + ) +{ + PH_ARRAY array; + ULONG i; + + PhInitializeArray(&array, sizeof(PVOID), 2); + + for (i = 0; i < Context->NodeList->Count; i++) + { + PPH_THREAD_NODE node = Context->NodeList->Items[i]; + + if (node->Node.Selected) + PhAddItemArray(&array, &node->ThreadItem); + } + + *NumberOfThreads = (ULONG)array.Count; + *Threads = PhFinalArrayItems(&array); +} + +VOID PhDeselectAllThreadNodes( + _In_ PPH_THREAD_LIST_CONTEXT Context + ) +{ + TreeNew_DeselectRange(Context->TreeNewHandle, 0, -1); +} diff --git a/ProcessHacker/thrdprv.c b/ProcessHacker/thrdprv.c index 85f3f6a6c79d..8f7a60b85b6a 100644 --- a/ProcessHacker/thrdprv.c +++ b/ProcessHacker/thrdprv.c @@ -1,1115 +1,1115 @@ -/* - * Process Hacker - - * thread provider - * - * Copyright (C) 2010-2016 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -/* - * The thread provider is tied to the process provider, and runs by registering a callback for the - * processes-updated event. This is because calculating CPU usage depends on deltas calculated by - * the process provider. However, this does increase the complexity of the thread provider system. - */ - -#include -#include - -#include -#include -#include -#include - -#include -#include - -typedef struct _PH_THREAD_QUERY_DATA -{ - SLIST_ENTRY ListEntry; - PPH_THREAD_PROVIDER ThreadProvider; - PPH_THREAD_ITEM ThreadItem; - ULONG64 RunId; - - PPH_STRING StartAddressString; - PH_SYMBOL_RESOLVE_LEVEL StartAddressResolveLevel; - - PPH_STRING ServiceName; -} PH_THREAD_QUERY_DATA, *PPH_THREAD_QUERY_DATA; - -typedef struct _PH_THREAD_SYMBOL_LOAD_CONTEXT -{ - HANDLE ProcessId; - PPH_THREAD_PROVIDER ThreadProvider; - PPH_SYMBOL_PROVIDER SymbolProvider; -} PH_THREAD_SYMBOL_LOAD_CONTEXT, *PPH_THREAD_SYMBOL_LOAD_CONTEXT; - -VOID NTAPI PhpThreadProviderDeleteProcedure( - _In_ PVOID Object, - _In_ ULONG Flags - ); - -VOID NTAPI PhpThreadItemDeleteProcedure( - _In_ PVOID Object, - _In_ ULONG Flags - ); - -BOOLEAN NTAPI PhpThreadHashtableEqualFunction( - _In_ PVOID Entry1, - _In_ PVOID Entry2 - ); - -ULONG NTAPI PhpThreadHashtableHashFunction( - _In_ PVOID Entry - ); - -VOID PhpThreadProviderCallbackHandler( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ); - -VOID PhpThreadProviderUpdate( - _In_ PPH_THREAD_PROVIDER ThreadProvider, - _In_ PVOID ProcessInformation - ); - -PPH_OBJECT_TYPE PhThreadProviderType; -PPH_OBJECT_TYPE PhThreadItemType; - -PH_WORK_QUEUE PhThreadProviderWorkQueue; -PH_INITONCE PhThreadProviderWorkQueueInitOnce = PH_INITONCE_INIT; - -BOOLEAN PhThreadProviderInitialization( - VOID - ) -{ - PhThreadProviderType = PhCreateObjectType(L"ThreadProvider", 0, PhpThreadProviderDeleteProcedure); - PhThreadItemType = PhCreateObjectType(L"ThreadItem", 0, PhpThreadItemDeleteProcedure); - - return TRUE; -} - -VOID PhpQueueThreadWorkQueueItem( - _In_ PTHREAD_START_ROUTINE Function, - _In_opt_ PVOID Context - ) -{ - if (PhBeginInitOnce(&PhThreadProviderWorkQueueInitOnce)) - { - PhInitializeWorkQueue(&PhThreadProviderWorkQueue, 0, 1, 1000); - PhEndInitOnce(&PhThreadProviderWorkQueueInitOnce); - } - - PhQueueItemWorkQueue(&PhThreadProviderWorkQueue, Function, Context); -} - -PPH_THREAD_PROVIDER PhCreateThreadProvider( - _In_ HANDLE ProcessId - ) -{ - PPH_THREAD_PROVIDER threadProvider; - - threadProvider = PhCreateObject( - PhEmGetObjectSize(EmThreadProviderType, sizeof(PH_THREAD_PROVIDER)), - PhThreadProviderType - ); - memset(threadProvider, 0, sizeof(PH_THREAD_PROVIDER)); - - threadProvider->ThreadHashtable = PhCreateHashtable( - sizeof(PPH_THREAD_ITEM), - PhpThreadHashtableEqualFunction, - PhpThreadHashtableHashFunction, - 20 - ); - PhInitializeFastLock(&threadProvider->ThreadHashtableLock); - - PhInitializeCallback(&threadProvider->ThreadAddedEvent); - PhInitializeCallback(&threadProvider->ThreadModifiedEvent); - PhInitializeCallback(&threadProvider->ThreadRemovedEvent); - PhInitializeCallback(&threadProvider->UpdatedEvent); - PhInitializeCallback(&threadProvider->LoadingStateChangedEvent); - - threadProvider->ProcessId = ProcessId; - threadProvider->SymbolProvider = PhCreateSymbolProvider(ProcessId); - - if (threadProvider->SymbolProvider) - { - if (threadProvider->SymbolProvider->IsRealHandle) - threadProvider->ProcessHandle = threadProvider->SymbolProvider->ProcessHandle; - } - - RtlInitializeSListHead(&threadProvider->QueryListHead); - PhInitializeQueuedLock(&threadProvider->LoadSymbolsLock); - - threadProvider->RunId = 1; - threadProvider->SymbolsLoadedRunId = 0; // Force symbols to be loaded the first time we try to resolve an address - - PhEmCallObjectOperation(EmThreadProviderType, threadProvider, EmObjectCreate); - - return threadProvider; -} - -VOID PhpThreadProviderDeleteProcedure( - _In_ PVOID Object, - _In_ ULONG Flags - ) -{ - PPH_THREAD_PROVIDER threadProvider = (PPH_THREAD_PROVIDER)Object; - - PhEmCallObjectOperation(EmThreadProviderType, threadProvider, EmObjectDelete); - - // Dereference all thread items (we referenced them - // when we added them to the hashtable). - PhDereferenceAllThreadItems(threadProvider); - - PhDereferenceObject(threadProvider->ThreadHashtable); - PhDeleteFastLock(&threadProvider->ThreadHashtableLock); - PhDeleteCallback(&threadProvider->ThreadAddedEvent); - PhDeleteCallback(&threadProvider->ThreadModifiedEvent); - PhDeleteCallback(&threadProvider->ThreadRemovedEvent); - PhDeleteCallback(&threadProvider->UpdatedEvent); - PhDeleteCallback(&threadProvider->LoadingStateChangedEvent); - - // Destroy all queue items. - { - PSLIST_ENTRY entry; - PPH_THREAD_QUERY_DATA data; - - entry = RtlInterlockedFlushSList(&threadProvider->QueryListHead); - - while (entry) - { - data = CONTAINING_RECORD(entry, PH_THREAD_QUERY_DATA, ListEntry); - entry = entry->Next; - - PhClearReference(&data->StartAddressString); - PhClearReference(&data->ServiceName); - PhDereferenceObject(data->ThreadItem); - PhFree(data); - } - } - - // We don't close the process handle because it is owned by the symbol provider. - if (threadProvider->SymbolProvider) PhDereferenceObject(threadProvider->SymbolProvider); -} - -VOID PhRegisterThreadProvider( - _In_ PPH_THREAD_PROVIDER ThreadProvider, - _Out_ PPH_CALLBACK_REGISTRATION CallbackRegistration - ) -{ - PhReferenceObject(ThreadProvider); - PhRegisterCallback(&PhProcessesUpdatedEvent, PhpThreadProviderCallbackHandler, ThreadProvider, CallbackRegistration); -} - -VOID PhUnregisterThreadProvider( - _In_ PPH_THREAD_PROVIDER ThreadProvider, - _In_ PPH_CALLBACK_REGISTRATION CallbackRegistration - ) -{ - PhUnregisterCallback(&PhProcessesUpdatedEvent, CallbackRegistration); - PhDereferenceObject(ThreadProvider); -} - -VOID PhSetTerminatingThreadProvider( - _Inout_ PPH_THREAD_PROVIDER ThreadProvider - ) -{ - ThreadProvider->Terminating = TRUE; -} - -static BOOLEAN LoadSymbolsEnumGenericModulesCallback( - _In_ PPH_MODULE_INFO Module, - _In_opt_ PVOID Context - ) -{ - PPH_THREAD_SYMBOL_LOAD_CONTEXT context = Context; - PPH_SYMBOL_PROVIDER symbolProvider = context->SymbolProvider; - - if (context->ThreadProvider->Terminating) - return FALSE; - - // If we're loading kernel module symbols for a process other than System, ignore modules which - // are in user space. This may happen in Windows 7. - if (context->ProcessId == SYSTEM_PROCESS_ID && - context->ThreadProvider->ProcessId != SYSTEM_PROCESS_ID && - (ULONG_PTR)Module->BaseAddress <= PhSystemBasicInformation.MaximumUserModeAddress) - { - return TRUE; - } - - PhLoadModuleSymbolProvider( - symbolProvider, - Module->FileName->Buffer, - (ULONG64)Module->BaseAddress, - Module->Size - ); - - return TRUE; -} - -static BOOLEAN LoadBasicSymbolsEnumGenericModulesCallback( - _In_ PPH_MODULE_INFO Module, - _In_opt_ PVOID Context - ) -{ - PPH_THREAD_SYMBOL_LOAD_CONTEXT context = Context; - PPH_SYMBOL_PROVIDER symbolProvider = context->SymbolProvider; - - if (context->ThreadProvider->Terminating) - return FALSE; - - if (PhEqualString2(Module->Name, L"ntdll.dll", TRUE) || - PhEqualString2(Module->Name, L"kernel32.dll", TRUE)) - { - PhLoadModuleSymbolProvider( - symbolProvider, - Module->FileName->Buffer, - (ULONG64)Module->BaseAddress, - Module->Size - ); - } - - return TRUE; -} - -VOID PhLoadSymbolsThreadProvider( - _In_ PPH_THREAD_PROVIDER ThreadProvider - ) -{ - PH_THREAD_SYMBOL_LOAD_CONTEXT loadContext; - ULONG64 runId; - - loadContext.ThreadProvider = ThreadProvider; - loadContext.SymbolProvider = ThreadProvider->SymbolProvider; - - PhAcquireQueuedLockExclusive(&ThreadProvider->LoadSymbolsLock); - runId = ThreadProvider->RunId; - PhLoadSymbolProviderOptions(ThreadProvider->SymbolProvider); - - if (ThreadProvider->ProcessId != SYSTEM_IDLE_PROCESS_ID) - { - if (ThreadProvider->SymbolProvider->IsRealHandle || - ThreadProvider->ProcessId == SYSTEM_PROCESS_ID) - { - loadContext.ProcessId = ThreadProvider->ProcessId; - PhEnumGenericModules( - ThreadProvider->ProcessId, - ThreadProvider->SymbolProvider->ProcessHandle, - 0, - LoadSymbolsEnumGenericModulesCallback, - &loadContext - ); - } - else - { - // We can't enumerate the process modules. Load symbols for ntdll.dll and kernel32.dll. - loadContext.ProcessId = NtCurrentProcessId(); - PhEnumGenericModules( - NtCurrentProcessId(), - NtCurrentProcess(), - 0, - LoadBasicSymbolsEnumGenericModulesCallback, - &loadContext - ); - } - - // Load kernel module symbols as well. - if (ThreadProvider->ProcessId != SYSTEM_PROCESS_ID) - { - loadContext.ProcessId = SYSTEM_PROCESS_ID; - PhEnumGenericModules( - SYSTEM_PROCESS_ID, - NULL, - 0, - LoadSymbolsEnumGenericModulesCallback, - &loadContext - ); - } - } - else - { - // System Idle Process has one thread for each CPU, each having a start address at - // KiIdleLoop. We need to load symbols for the kernel. - - PRTL_PROCESS_MODULES kernelModules; - - if (NT_SUCCESS(PhEnumKernelModules(&kernelModules))) - { - if (kernelModules->NumberOfModules > 0) - { - PPH_STRING fileName; - PPH_STRING newFileName; - - fileName = PhConvertMultiByteToUtf16(kernelModules->Modules[0].FullPathName); - newFileName = PhGetFileName(fileName); - PhDereferenceObject(fileName); - - PhLoadModuleSymbolProvider( - ThreadProvider->SymbolProvider, - newFileName->Buffer, - (ULONG64)kernelModules->Modules[0].ImageBase, - kernelModules->Modules[0].ImageSize - ); - PhDereferenceObject(newFileName); - } - - PhFree(kernelModules); - } - } - - ThreadProvider->SymbolsLoadedRunId = runId; - PhReleaseQueuedLockExclusive(&ThreadProvider->LoadSymbolsLock); -} - -PPH_THREAD_ITEM PhCreateThreadItem( - _In_ HANDLE ThreadId - ) -{ - PPH_THREAD_ITEM threadItem; - - threadItem = PhCreateObject( - PhEmGetObjectSize(EmThreadItemType, sizeof(PH_THREAD_ITEM)), - PhThreadItemType - ); - memset(threadItem, 0, sizeof(PH_THREAD_ITEM)); - threadItem->ThreadId = ThreadId; - PhPrintUInt32(threadItem->ThreadIdString, HandleToUlong(ThreadId)); - - PhEmCallObjectOperation(EmThreadItemType, threadItem, EmObjectCreate); - - return threadItem; -} - -VOID PhpThreadItemDeleteProcedure( - _In_ PVOID Object, - _In_ ULONG Flags - ) -{ - PPH_THREAD_ITEM threadItem = (PPH_THREAD_ITEM)Object; - - PhEmCallObjectOperation(EmThreadItemType, threadItem, EmObjectDelete); - - if (threadItem->ThreadHandle) NtClose(threadItem->ThreadHandle); - if (threadItem->StartAddressString) PhDereferenceObject(threadItem->StartAddressString); - if (threadItem->StartAddressFileName) PhDereferenceObject(threadItem->StartAddressFileName); - if (threadItem->ServiceName) PhDereferenceObject(threadItem->ServiceName); -} - -BOOLEAN PhpThreadHashtableEqualFunction( - _In_ PVOID Entry1, - _In_ PVOID Entry2 - ) -{ - return - (*(PPH_THREAD_ITEM *)Entry1)->ThreadId == - (*(PPH_THREAD_ITEM *)Entry2)->ThreadId; -} - -ULONG PhpThreadHashtableHashFunction( - _In_ PVOID Entry - ) -{ - return HandleToUlong((*(PPH_THREAD_ITEM *)Entry)->ThreadId) / 4; -} - -PPH_THREAD_ITEM PhReferenceThreadItem( - _In_ PPH_THREAD_PROVIDER ThreadProvider, - _In_ HANDLE ThreadId - ) -{ - PH_THREAD_ITEM lookupThreadItem; - PPH_THREAD_ITEM lookupThreadItemPtr = &lookupThreadItem; - PPH_THREAD_ITEM *threadItemPtr; - PPH_THREAD_ITEM threadItem; - - lookupThreadItem.ThreadId = ThreadId; - - PhAcquireFastLockShared(&ThreadProvider->ThreadHashtableLock); - - threadItemPtr = (PPH_THREAD_ITEM *)PhFindEntryHashtable( - ThreadProvider->ThreadHashtable, - &lookupThreadItemPtr - ); - - if (threadItemPtr) - { - threadItem = *threadItemPtr; - PhReferenceObject(threadItem); - } - else - { - threadItem = NULL; - } - - PhReleaseFastLockShared(&ThreadProvider->ThreadHashtableLock); - - return threadItem; -} - -VOID PhDereferenceAllThreadItems( - _In_ PPH_THREAD_PROVIDER ThreadProvider - ) -{ - ULONG enumerationKey = 0; - PPH_THREAD_ITEM *threadItem; - - PhAcquireFastLockExclusive(&ThreadProvider->ThreadHashtableLock); - - while (PhEnumHashtable(ThreadProvider->ThreadHashtable, (PVOID *)&threadItem, &enumerationKey)) - { - PhDereferenceObject(*threadItem); - } - - PhReleaseFastLockExclusive(&ThreadProvider->ThreadHashtableLock); -} - -VOID PhpRemoveThreadItem( - _In_ PPH_THREAD_PROVIDER ThreadProvider, - _In_ PPH_THREAD_ITEM ThreadItem - ) -{ - PhRemoveEntryHashtable(ThreadProvider->ThreadHashtable, &ThreadItem); - PhDereferenceObject(ThreadItem); -} - -NTSTATUS PhpThreadQueryWorker( - _In_ PVOID Parameter - ) -{ - PPH_THREAD_QUERY_DATA data = (PPH_THREAD_QUERY_DATA)Parameter; - LONG newSymbolsLoading; - - if (data->ThreadProvider->Terminating) - goto Done; - - newSymbolsLoading = _InterlockedIncrement(&data->ThreadProvider->SymbolsLoading); - - if (newSymbolsLoading == 1) - PhInvokeCallback(&data->ThreadProvider->LoadingStateChangedEvent, (PVOID)TRUE); - - if (data->ThreadProvider->SymbolsLoadedRunId == 0) - PhLoadSymbolsThreadProvider(data->ThreadProvider); - - data->StartAddressString = PhGetSymbolFromAddress( - data->ThreadProvider->SymbolProvider, - data->ThreadItem->StartAddress, - &data->StartAddressResolveLevel, - &data->ThreadItem->StartAddressFileName, - NULL, - NULL - ); - - if (data->StartAddressResolveLevel == PhsrlAddress && data->ThreadProvider->SymbolsLoadedRunId < data->RunId) - { - // The process may have loaded new modules, so load symbols for those and try again. - - PhLoadSymbolsThreadProvider(data->ThreadProvider); - - PhClearReference(&data->StartAddressString); - PhClearReference(&data->ThreadItem->StartAddressFileName); - data->StartAddressString = PhGetSymbolFromAddress( - data->ThreadProvider->SymbolProvider, - data->ThreadItem->StartAddress, - &data->StartAddressResolveLevel, - &data->ThreadItem->StartAddressFileName, - NULL, - NULL - ); - } - - newSymbolsLoading = _InterlockedDecrement(&data->ThreadProvider->SymbolsLoading); - - if (newSymbolsLoading == 0) - PhInvokeCallback(&data->ThreadProvider->LoadingStateChangedEvent, (PVOID)FALSE); - - // Check if the process has services - we'll need to know before getting service tag/name - // information. - if (WINDOWS_HAS_SERVICE_TAGS && !data->ThreadProvider->HasServicesKnown) - { - PPH_PROCESS_ITEM processItem; - - if (processItem = PhReferenceProcessItem(data->ThreadProvider->ProcessId)) - { - data->ThreadProvider->HasServices = processItem->ServiceList && processItem->ServiceList->Count != 0; - PhDereferenceObject(processItem); - } - - data->ThreadProvider->HasServicesKnown = TRUE; - } - - // Get the service tag, and the service name. - if (WINDOWS_HAS_SERVICE_TAGS && - data->ThreadProvider->SymbolProvider->IsRealHandle && - data->ThreadItem->ThreadHandle) - { - PVOID serviceTag; - - if (NT_SUCCESS(PhGetThreadServiceTag( - data->ThreadItem->ThreadHandle, - data->ThreadProvider->ProcessHandle, - &serviceTag - ))) - { - data->ServiceName = PhGetServiceNameFromTag( - data->ThreadProvider->ProcessId, - serviceTag - ); - } - } - -Done: - RtlInterlockedPushEntrySList(&data->ThreadProvider->QueryListHead, &data->ListEntry); - PhDereferenceObject(data->ThreadProvider); - - return STATUS_SUCCESS; -} - -VOID PhpQueueThreadQuery( - _In_ PPH_THREAD_PROVIDER ThreadProvider, - _In_ PPH_THREAD_ITEM ThreadItem - ) -{ - PPH_THREAD_QUERY_DATA data; - - data = PhAllocate(sizeof(PH_THREAD_QUERY_DATA)); - memset(data, 0, sizeof(PH_THREAD_QUERY_DATA)); - PhSetReference(&data->ThreadProvider, ThreadProvider); - PhSetReference(&data->ThreadItem, ThreadItem); - data->RunId = ThreadProvider->RunId; - - PhpQueueThreadWorkQueueItem(PhpThreadQueryWorker, data); -} - -PPH_STRING PhpGetThreadBasicStartAddress( - _In_ PPH_THREAD_PROVIDER ThreadProvider, - _In_ ULONG64 Address, - _Out_ PPH_SYMBOL_RESOLVE_LEVEL ResolveLevel - ) -{ - ULONG64 modBase; - PPH_STRING fileName = NULL; - PPH_STRING baseName = NULL; - PPH_STRING symbol; - - modBase = PhGetModuleFromAddress( - ThreadProvider->SymbolProvider, - Address, - &fileName - ); - - if (fileName == NULL) - { - *ResolveLevel = PhsrlAddress; - - symbol = PhCreateStringEx(NULL, PH_PTR_STR_LEN * 2); - PhPrintPointer(symbol->Buffer, (PVOID)Address); - PhTrimToNullTerminatorString(symbol); - } - else - { - PH_FORMAT format[3]; - - baseName = PhGetBaseName(fileName); - *ResolveLevel = PhsrlModule; - - PhInitFormatSR(&format[0], baseName->sr); - PhInitFormatS(&format[1], L"+0x"); - PhInitFormatIX(&format[2], (ULONG_PTR)(Address - modBase)); - - symbol = PhFormat(format, 3, baseName->Length + 6 + 32); - } - - if (fileName) - PhDereferenceObject(fileName); - if (baseName) - PhDereferenceObject(baseName); - - return symbol; -} - -static NTSTATUS PhpGetThreadCycleTime( - _In_ PPH_THREAD_PROVIDER ThreadProvider, - _In_ PPH_THREAD_ITEM ThreadItem, - _Out_ PULONG64 CycleTime - ) -{ - if (ThreadProvider->ProcessId != SYSTEM_IDLE_PROCESS_ID) - { - return PhGetThreadCycleTime(ThreadItem->ThreadHandle, CycleTime); - } - else - { - if (HandleToUlong(ThreadItem->ThreadId) < (ULONG)PhSystemBasicInformation.NumberOfProcessors) - { - *CycleTime = PhCpuIdleCycleTime[HandleToUlong(ThreadItem->ThreadId)].QuadPart; - return STATUS_SUCCESS; - } - } - - return STATUS_INVALID_PARAMETER; -} - -PPH_STRING PhGetBasePriorityIncrementString( - _In_ LONG Increment - ) -{ - switch (Increment) - { - case THREAD_BASE_PRIORITY_LOWRT + 1: - case THREAD_BASE_PRIORITY_LOWRT: - return PhCreateString(L"Time critical"); - case THREAD_PRIORITY_HIGHEST: - return PhCreateString(L"Highest"); - case THREAD_PRIORITY_ABOVE_NORMAL: - return PhCreateString(L"Above normal"); - case THREAD_PRIORITY_NORMAL: - return PhCreateString(L"Normal"); - case THREAD_PRIORITY_BELOW_NORMAL: - return PhCreateString(L"Below normal"); - case THREAD_PRIORITY_LOWEST: - return PhCreateString(L"Lowest"); - case THREAD_BASE_PRIORITY_IDLE: - case THREAD_BASE_PRIORITY_IDLE - 1: - return PhCreateString(L"Idle"); - case THREAD_PRIORITY_ERROR_RETURN: - return NULL; - default: - return PhFormatString(L"%d", Increment); - } -} - -VOID PhThreadProviderInitialUpdate( - _In_ PPH_THREAD_PROVIDER ThreadProvider - ) -{ - PVOID processes; - - if (NT_SUCCESS(PhEnumProcesses(&processes))) - { - PhpThreadProviderUpdate(ThreadProvider, processes); - PhFree(processes); - } -} - -VOID PhpThreadProviderCallbackHandler( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - if (PhProcessInformation) - { - PhpThreadProviderUpdate((PPH_THREAD_PROVIDER)Context, PhProcessInformation); - } -} - -VOID PhpThreadProviderUpdate( - _In_ PPH_THREAD_PROVIDER ThreadProvider, - _In_ PVOID ProcessInformation - ) -{ - PPH_THREAD_PROVIDER threadProvider = ThreadProvider; - PSYSTEM_PROCESS_INFORMATION process; - SYSTEM_PROCESS_INFORMATION localProcess; - PSYSTEM_THREAD_INFORMATION threads; - ULONG numberOfThreads; - ULONG i; - - process = PhFindProcessInformation(ProcessInformation, threadProvider->ProcessId); - - if (!process) - { - // The process doesn't exist anymore. Pretend it does but has no threads. - process = &localProcess; - process->NumberOfThreads = 0; - } - - threads = process->Threads; - numberOfThreads = process->NumberOfThreads; - - // System Idle Process has one thread per CPU. They all have a TID of 0. We can't have duplicate - // TIDs, so we'll assign unique TIDs. - if (threadProvider->ProcessId == SYSTEM_IDLE_PROCESS_ID) - { - for (i = 0; i < numberOfThreads; i++) - { - threads[i].ClientId.UniqueThread = UlongToHandle(i); - } - } - - // Look for dead threads. - { - PPH_LIST threadsToRemove = NULL; - ULONG enumerationKey = 0; - PPH_THREAD_ITEM *threadItem; - - while (PhEnumHashtable(threadProvider->ThreadHashtable, (PVOID *)&threadItem, &enumerationKey)) - { - BOOLEAN found = FALSE; - - // Check if the thread still exists. - for (i = 0; i < numberOfThreads; i++) - { - PSYSTEM_THREAD_INFORMATION thread = &threads[i]; - - if ((*threadItem)->ThreadId == thread->ClientId.UniqueThread) - { - found = TRUE; - break; - } - } - - if (!found) - { - // Raise the thread removed event. - PhInvokeCallback(&threadProvider->ThreadRemovedEvent, *threadItem); - - if (!threadsToRemove) - threadsToRemove = PhCreateList(2); - - PhAddItemList(threadsToRemove, *threadItem); - } - } - - if (threadsToRemove) - { - PhAcquireFastLockExclusive(&threadProvider->ThreadHashtableLock); - - for (i = 0; i < threadsToRemove->Count; i++) - { - PhpRemoveThreadItem( - threadProvider, - (PPH_THREAD_ITEM)threadsToRemove->Items[i] - ); - } - - PhReleaseFastLockExclusive(&threadProvider->ThreadHashtableLock); - PhDereferenceObject(threadsToRemove); - } - } - - // Go through the queued thread query data. - { - PSLIST_ENTRY entry; - PPH_THREAD_QUERY_DATA data; - - entry = RtlInterlockedFlushSList(&threadProvider->QueryListHead); - - while (entry) - { - data = CONTAINING_RECORD(entry, PH_THREAD_QUERY_DATA, ListEntry); - entry = entry->Next; - - if (data->StartAddressResolveLevel == PhsrlFunction && data->StartAddressString) - { - PhSwapReference(&data->ThreadItem->StartAddressString, data->StartAddressString); - data->ThreadItem->StartAddressResolveLevel = data->StartAddressResolveLevel; - } - - PhMoveReference(&data->ThreadItem->ServiceName, data->ServiceName); - - data->ThreadItem->JustResolved = TRUE; - - if (data->StartAddressString) PhDereferenceObject(data->StartAddressString); - PhDereferenceObject(data->ThreadItem); - PhFree(data); - } - } - - // Look for new threads and update existing ones. - for (i = 0; i < numberOfThreads; i++) - { - PSYSTEM_THREAD_INFORMATION thread = &threads[i]; - PPH_THREAD_ITEM threadItem; - THREAD_BASIC_INFORMATION basicInfo; - - threadItem = PhReferenceThreadItem(threadProvider, thread->ClientId.UniqueThread); - - if (!threadItem) - { - PVOID startAddress = NULL; - - threadItem = PhCreateThreadItem(thread->ClientId.UniqueThread); - - threadItem->CreateTime = thread->CreateTime; - threadItem->KernelTime = thread->KernelTime; - threadItem->UserTime = thread->UserTime; - - PhUpdateDelta(&threadItem->ContextSwitchesDelta, thread->ContextSwitches); - threadItem->Priority = thread->Priority; - threadItem->BasePriority = thread->BasePriority; - threadItem->State = (KTHREAD_STATE)thread->ThreadState; - threadItem->WaitReason = thread->WaitReason; - - // Try to open a handle to the thread. - if (!NT_SUCCESS(PhOpenThread( - &threadItem->ThreadHandle, - THREAD_QUERY_INFORMATION, - threadItem->ThreadId - ))) - { - PhOpenThread( - &threadItem->ThreadHandle, - ThreadQueryAccess, - threadItem->ThreadId - ); - } - - // Get the cycle count. - if (WINDOWS_HAS_CYCLE_TIME) - { - ULONG64 cycles; - - if (NT_SUCCESS(PhpGetThreadCycleTime( - threadProvider, - threadItem, - &cycles - ))) - { - PhUpdateDelta(&threadItem->CyclesDelta, cycles); - } - } - - // Initialize the CPU time deltas. - PhUpdateDelta(&threadItem->CpuKernelDelta, threadItem->KernelTime.QuadPart); - PhUpdateDelta(&threadItem->CpuUserDelta, threadItem->UserTime.QuadPart); - - // Try to get the start address. - - if (threadItem->ThreadHandle) - { - NtQueryInformationThread( - threadItem->ThreadHandle, - ThreadQuerySetWin32StartAddress, - &startAddress, - sizeof(PVOID), - NULL - ); - } - - if (!startAddress) - startAddress = thread->StartAddress; - - threadItem->StartAddress = (ULONG64)startAddress; - - // Get the base priority increment (relative to the process priority). - if (threadItem->ThreadHandle && NT_SUCCESS(PhGetThreadBasicInformation( - threadItem->ThreadHandle, - &basicInfo - ))) - { - threadItem->BasePriorityIncrement = basicInfo.BasePriority; - } - else - { - threadItem->BasePriorityIncrement = THREAD_PRIORITY_ERROR_RETURN; - } - - if (threadProvider->SymbolsLoadedRunId != 0) - { - threadItem->StartAddressString = PhpGetThreadBasicStartAddress( - threadProvider, - threadItem->StartAddress, - &threadItem->StartAddressResolveLevel - ); - } - - if (!threadItem->StartAddressString) - { - threadItem->StartAddressResolveLevel = PhsrlAddress; - threadItem->StartAddressString = PhCreateStringEx(NULL, PH_PTR_STR_LEN * 2); - PhPrintPointer( - threadItem->StartAddressString->Buffer, - (PVOID)threadItem->StartAddress - ); - PhTrimToNullTerminatorString(threadItem->StartAddressString); - } - - PhpQueueThreadQuery(threadProvider, threadItem); - - // Is it a GUI thread? - { - GUITHREADINFO info = { sizeof(GUITHREADINFO) }; - - threadItem->IsGuiThread = !!GetGUIThreadInfo(HandleToUlong(threadItem->ThreadId), &info); - } - - // Add the thread item to the hashtable. - PhAcquireFastLockExclusive(&threadProvider->ThreadHashtableLock); - PhAddEntryHashtable(threadProvider->ThreadHashtable, &threadItem); - PhReleaseFastLockExclusive(&threadProvider->ThreadHashtableLock); - - // Raise the thread added event. - PhInvokeCallback(&threadProvider->ThreadAddedEvent, threadItem); - } - else - { - BOOLEAN modified = FALSE; - - if (threadItem->JustResolved) - modified = TRUE; - - threadItem->KernelTime = thread->KernelTime; - threadItem->UserTime = thread->UserTime; - - threadItem->Priority = thread->Priority; - threadItem->BasePriority = thread->BasePriority; - - threadItem->State = (KTHREAD_STATE)thread->ThreadState; - - if (threadItem->WaitReason != thread->WaitReason) - { - threadItem->WaitReason = thread->WaitReason; - modified = TRUE; - } - - // If the resolve level is only at address, it probably - // means symbols weren't loaded the last time we - // tried to get the start address. Try again. - if (threadItem->StartAddressResolveLevel == PhsrlAddress) - { - if (threadProvider->SymbolsLoadedRunId != 0) - { - PPH_STRING newStartAddressString; - - newStartAddressString = PhpGetThreadBasicStartAddress( - threadProvider, - threadItem->StartAddress, - &threadItem->StartAddressResolveLevel - ); - - PhMoveReference( - &threadItem->StartAddressString, - newStartAddressString - ); - - modified = TRUE; - } - } - - // If we couldn't resolve the start address to a module+offset, use the StartAddress - // instead of the Win32StartAddress and try again. Note that we check the resolve level - // again because we may have changed it in the previous block. - if (threadItem->JustResolved && - threadItem->StartAddressResolveLevel == PhsrlAddress) - { - if (threadItem->StartAddress != (ULONG64)thread->StartAddress) - { - threadItem->StartAddress = (ULONG64)thread->StartAddress; - PhpQueueThreadQuery(threadProvider, threadItem); - } - } - - // Update the context switch count. - { - ULONG oldDelta; - - oldDelta = threadItem->ContextSwitchesDelta.Delta; - PhUpdateDelta(&threadItem->ContextSwitchesDelta, thread->ContextSwitches); - - if (threadItem->ContextSwitchesDelta.Delta != oldDelta) - { - modified = TRUE; - } - } - - // Update the cycle count. - if (WINDOWS_HAS_CYCLE_TIME) - { - ULONG64 cycles; - ULONG64 oldDelta; - - oldDelta = threadItem->CyclesDelta.Delta; - - if (NT_SUCCESS(PhpGetThreadCycleTime( - threadProvider, - threadItem, - &cycles - ))) - { - PhUpdateDelta(&threadItem->CyclesDelta, cycles); - - if (threadItem->CyclesDelta.Delta != oldDelta) - { - modified = TRUE; - } - } - } - - // Update the CPU time deltas. - PhUpdateDelta(&threadItem->CpuKernelDelta, threadItem->KernelTime.QuadPart); - PhUpdateDelta(&threadItem->CpuUserDelta, threadItem->UserTime.QuadPart); - - // Update the CPU usage. - // If the cycle time isn't available, we'll fall back to using the CPU time. - if (WINDOWS_HAS_CYCLE_TIME && PhEnableCycleCpuUsage && (threadProvider->ProcessId == SYSTEM_IDLE_PROCESS_ID || threadItem->ThreadHandle)) - { - threadItem->CpuUsage = (FLOAT)threadItem->CyclesDelta.Delta / PhCpuTotalCycleDelta; - } - else - { - threadItem->CpuUsage = (FLOAT)(threadItem->CpuKernelDelta.Delta + threadItem->CpuUserDelta.Delta) / - (PhCpuKernelDelta.Delta + PhCpuUserDelta.Delta + PhCpuIdleDelta.Delta); - } - - // Update the base priority increment. - { - LONG oldBasePriorityIncrement = threadItem->BasePriorityIncrement; - - if (threadItem->ThreadHandle && NT_SUCCESS(PhGetThreadBasicInformation( - threadItem->ThreadHandle, - &basicInfo - ))) - { - threadItem->BasePriorityIncrement = basicInfo.BasePriority; - } - else - { - threadItem->BasePriorityIncrement = THREAD_PRIORITY_ERROR_RETURN; - } - - if (threadItem->BasePriorityIncrement != oldBasePriorityIncrement) - { - modified = TRUE; - } - } - - // Update the GUI thread status. - { - GUITHREADINFO info = { sizeof(GUITHREADINFO) }; - BOOLEAN oldIsGuiThread = threadItem->IsGuiThread; - - threadItem->IsGuiThread = !!GetGUIThreadInfo(HandleToUlong(threadItem->ThreadId), &info); - - if (threadItem->IsGuiThread != oldIsGuiThread) - modified = TRUE; - } - - threadItem->JustResolved = FALSE; - - if (modified) - { - // Raise the thread modified event. - PhInvokeCallback(&threadProvider->ThreadModifiedEvent, threadItem); - } - - PhDereferenceObject(threadItem); - } - } - - PhInvokeCallback(&threadProvider->UpdatedEvent, NULL); - threadProvider->RunId++; -} +/* + * Process Hacker - + * thread provider + * + * Copyright (C) 2010-2016 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +/* + * The thread provider is tied to the process provider, and runs by registering a callback for the + * processes-updated event. This is because calculating CPU usage depends on deltas calculated by + * the process provider. However, this does increase the complexity of the thread provider system. + */ + +#include +#include + +#include +#include +#include +#include + +#include +#include + +typedef struct _PH_THREAD_QUERY_DATA +{ + SLIST_ENTRY ListEntry; + PPH_THREAD_PROVIDER ThreadProvider; + PPH_THREAD_ITEM ThreadItem; + ULONG64 RunId; + + PPH_STRING StartAddressString; + PH_SYMBOL_RESOLVE_LEVEL StartAddressResolveLevel; + + PPH_STRING ServiceName; +} PH_THREAD_QUERY_DATA, *PPH_THREAD_QUERY_DATA; + +typedef struct _PH_THREAD_SYMBOL_LOAD_CONTEXT +{ + HANDLE ProcessId; + PPH_THREAD_PROVIDER ThreadProvider; + PPH_SYMBOL_PROVIDER SymbolProvider; +} PH_THREAD_SYMBOL_LOAD_CONTEXT, *PPH_THREAD_SYMBOL_LOAD_CONTEXT; + +VOID NTAPI PhpThreadProviderDeleteProcedure( + _In_ PVOID Object, + _In_ ULONG Flags + ); + +VOID NTAPI PhpThreadItemDeleteProcedure( + _In_ PVOID Object, + _In_ ULONG Flags + ); + +BOOLEAN NTAPI PhpThreadHashtableEqualFunction( + _In_ PVOID Entry1, + _In_ PVOID Entry2 + ); + +ULONG NTAPI PhpThreadHashtableHashFunction( + _In_ PVOID Entry + ); + +VOID PhpThreadProviderCallbackHandler( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ); + +VOID PhpThreadProviderUpdate( + _In_ PPH_THREAD_PROVIDER ThreadProvider, + _In_ PVOID ProcessInformation + ); + +PPH_OBJECT_TYPE PhThreadProviderType; +PPH_OBJECT_TYPE PhThreadItemType; + +PH_WORK_QUEUE PhThreadProviderWorkQueue; +PH_INITONCE PhThreadProviderWorkQueueInitOnce = PH_INITONCE_INIT; + +BOOLEAN PhThreadProviderInitialization( + VOID + ) +{ + PhThreadProviderType = PhCreateObjectType(L"ThreadProvider", 0, PhpThreadProviderDeleteProcedure); + PhThreadItemType = PhCreateObjectType(L"ThreadItem", 0, PhpThreadItemDeleteProcedure); + + return TRUE; +} + +VOID PhpQueueThreadWorkQueueItem( + _In_ PTHREAD_START_ROUTINE Function, + _In_opt_ PVOID Context + ) +{ + if (PhBeginInitOnce(&PhThreadProviderWorkQueueInitOnce)) + { + PhInitializeWorkQueue(&PhThreadProviderWorkQueue, 0, 1, 1000); + PhEndInitOnce(&PhThreadProviderWorkQueueInitOnce); + } + + PhQueueItemWorkQueue(&PhThreadProviderWorkQueue, Function, Context); +} + +PPH_THREAD_PROVIDER PhCreateThreadProvider( + _In_ HANDLE ProcessId + ) +{ + PPH_THREAD_PROVIDER threadProvider; + + threadProvider = PhCreateObject( + PhEmGetObjectSize(EmThreadProviderType, sizeof(PH_THREAD_PROVIDER)), + PhThreadProviderType + ); + memset(threadProvider, 0, sizeof(PH_THREAD_PROVIDER)); + + threadProvider->ThreadHashtable = PhCreateHashtable( + sizeof(PPH_THREAD_ITEM), + PhpThreadHashtableEqualFunction, + PhpThreadHashtableHashFunction, + 20 + ); + PhInitializeFastLock(&threadProvider->ThreadHashtableLock); + + PhInitializeCallback(&threadProvider->ThreadAddedEvent); + PhInitializeCallback(&threadProvider->ThreadModifiedEvent); + PhInitializeCallback(&threadProvider->ThreadRemovedEvent); + PhInitializeCallback(&threadProvider->UpdatedEvent); + PhInitializeCallback(&threadProvider->LoadingStateChangedEvent); + + threadProvider->ProcessId = ProcessId; + threadProvider->SymbolProvider = PhCreateSymbolProvider(ProcessId); + + if (threadProvider->SymbolProvider) + { + if (threadProvider->SymbolProvider->IsRealHandle) + threadProvider->ProcessHandle = threadProvider->SymbolProvider->ProcessHandle; + } + + RtlInitializeSListHead(&threadProvider->QueryListHead); + PhInitializeQueuedLock(&threadProvider->LoadSymbolsLock); + + threadProvider->RunId = 1; + threadProvider->SymbolsLoadedRunId = 0; // Force symbols to be loaded the first time we try to resolve an address + + PhEmCallObjectOperation(EmThreadProviderType, threadProvider, EmObjectCreate); + + return threadProvider; +} + +VOID PhpThreadProviderDeleteProcedure( + _In_ PVOID Object, + _In_ ULONG Flags + ) +{ + PPH_THREAD_PROVIDER threadProvider = (PPH_THREAD_PROVIDER)Object; + + PhEmCallObjectOperation(EmThreadProviderType, threadProvider, EmObjectDelete); + + // Dereference all thread items (we referenced them + // when we added them to the hashtable). + PhDereferenceAllThreadItems(threadProvider); + + PhDereferenceObject(threadProvider->ThreadHashtable); + PhDeleteFastLock(&threadProvider->ThreadHashtableLock); + PhDeleteCallback(&threadProvider->ThreadAddedEvent); + PhDeleteCallback(&threadProvider->ThreadModifiedEvent); + PhDeleteCallback(&threadProvider->ThreadRemovedEvent); + PhDeleteCallback(&threadProvider->UpdatedEvent); + PhDeleteCallback(&threadProvider->LoadingStateChangedEvent); + + // Destroy all queue items. + { + PSLIST_ENTRY entry; + PPH_THREAD_QUERY_DATA data; + + entry = RtlInterlockedFlushSList(&threadProvider->QueryListHead); + + while (entry) + { + data = CONTAINING_RECORD(entry, PH_THREAD_QUERY_DATA, ListEntry); + entry = entry->Next; + + PhClearReference(&data->StartAddressString); + PhClearReference(&data->ServiceName); + PhDereferenceObject(data->ThreadItem); + PhFree(data); + } + } + + // We don't close the process handle because it is owned by the symbol provider. + if (threadProvider->SymbolProvider) PhDereferenceObject(threadProvider->SymbolProvider); +} + +VOID PhRegisterThreadProvider( + _In_ PPH_THREAD_PROVIDER ThreadProvider, + _Out_ PPH_CALLBACK_REGISTRATION CallbackRegistration + ) +{ + PhReferenceObject(ThreadProvider); + PhRegisterCallback(&PhProcessesUpdatedEvent, PhpThreadProviderCallbackHandler, ThreadProvider, CallbackRegistration); +} + +VOID PhUnregisterThreadProvider( + _In_ PPH_THREAD_PROVIDER ThreadProvider, + _In_ PPH_CALLBACK_REGISTRATION CallbackRegistration + ) +{ + PhUnregisterCallback(&PhProcessesUpdatedEvent, CallbackRegistration); + PhDereferenceObject(ThreadProvider); +} + +VOID PhSetTerminatingThreadProvider( + _Inout_ PPH_THREAD_PROVIDER ThreadProvider + ) +{ + ThreadProvider->Terminating = TRUE; +} + +static BOOLEAN LoadSymbolsEnumGenericModulesCallback( + _In_ PPH_MODULE_INFO Module, + _In_opt_ PVOID Context + ) +{ + PPH_THREAD_SYMBOL_LOAD_CONTEXT context = Context; + PPH_SYMBOL_PROVIDER symbolProvider = context->SymbolProvider; + + if (context->ThreadProvider->Terminating) + return FALSE; + + // If we're loading kernel module symbols for a process other than System, ignore modules which + // are in user space. This may happen in Windows 7. + if (context->ProcessId == SYSTEM_PROCESS_ID && + context->ThreadProvider->ProcessId != SYSTEM_PROCESS_ID && + (ULONG_PTR)Module->BaseAddress <= PhSystemBasicInformation.MaximumUserModeAddress) + { + return TRUE; + } + + PhLoadModuleSymbolProvider( + symbolProvider, + Module->FileName->Buffer, + (ULONG64)Module->BaseAddress, + Module->Size + ); + + return TRUE; +} + +static BOOLEAN LoadBasicSymbolsEnumGenericModulesCallback( + _In_ PPH_MODULE_INFO Module, + _In_opt_ PVOID Context + ) +{ + PPH_THREAD_SYMBOL_LOAD_CONTEXT context = Context; + PPH_SYMBOL_PROVIDER symbolProvider = context->SymbolProvider; + + if (context->ThreadProvider->Terminating) + return FALSE; + + if (PhEqualString2(Module->Name, L"ntdll.dll", TRUE) || + PhEqualString2(Module->Name, L"kernel32.dll", TRUE)) + { + PhLoadModuleSymbolProvider( + symbolProvider, + Module->FileName->Buffer, + (ULONG64)Module->BaseAddress, + Module->Size + ); + } + + return TRUE; +} + +VOID PhLoadSymbolsThreadProvider( + _In_ PPH_THREAD_PROVIDER ThreadProvider + ) +{ + PH_THREAD_SYMBOL_LOAD_CONTEXT loadContext; + ULONG64 runId; + + loadContext.ThreadProvider = ThreadProvider; + loadContext.SymbolProvider = ThreadProvider->SymbolProvider; + + PhAcquireQueuedLockExclusive(&ThreadProvider->LoadSymbolsLock); + runId = ThreadProvider->RunId; + PhLoadSymbolProviderOptions(ThreadProvider->SymbolProvider); + + if (ThreadProvider->ProcessId != SYSTEM_IDLE_PROCESS_ID) + { + if (ThreadProvider->SymbolProvider->IsRealHandle || + ThreadProvider->ProcessId == SYSTEM_PROCESS_ID) + { + loadContext.ProcessId = ThreadProvider->ProcessId; + PhEnumGenericModules( + ThreadProvider->ProcessId, + ThreadProvider->SymbolProvider->ProcessHandle, + 0, + LoadSymbolsEnumGenericModulesCallback, + &loadContext + ); + } + else + { + // We can't enumerate the process modules. Load symbols for ntdll.dll and kernel32.dll. + loadContext.ProcessId = NtCurrentProcessId(); + PhEnumGenericModules( + NtCurrentProcessId(), + NtCurrentProcess(), + 0, + LoadBasicSymbolsEnumGenericModulesCallback, + &loadContext + ); + } + + // Load kernel module symbols as well. + if (ThreadProvider->ProcessId != SYSTEM_PROCESS_ID) + { + loadContext.ProcessId = SYSTEM_PROCESS_ID; + PhEnumGenericModules( + SYSTEM_PROCESS_ID, + NULL, + 0, + LoadSymbolsEnumGenericModulesCallback, + &loadContext + ); + } + } + else + { + // System Idle Process has one thread for each CPU, each having a start address at + // KiIdleLoop. We need to load symbols for the kernel. + + PRTL_PROCESS_MODULES kernelModules; + + if (NT_SUCCESS(PhEnumKernelModules(&kernelModules))) + { + if (kernelModules->NumberOfModules > 0) + { + PPH_STRING fileName; + PPH_STRING newFileName; + + fileName = PhConvertMultiByteToUtf16(kernelModules->Modules[0].FullPathName); + newFileName = PhGetFileName(fileName); + PhDereferenceObject(fileName); + + PhLoadModuleSymbolProvider( + ThreadProvider->SymbolProvider, + newFileName->Buffer, + (ULONG64)kernelModules->Modules[0].ImageBase, + kernelModules->Modules[0].ImageSize + ); + PhDereferenceObject(newFileName); + } + + PhFree(kernelModules); + } + } + + ThreadProvider->SymbolsLoadedRunId = runId; + PhReleaseQueuedLockExclusive(&ThreadProvider->LoadSymbolsLock); +} + +PPH_THREAD_ITEM PhCreateThreadItem( + _In_ HANDLE ThreadId + ) +{ + PPH_THREAD_ITEM threadItem; + + threadItem = PhCreateObject( + PhEmGetObjectSize(EmThreadItemType, sizeof(PH_THREAD_ITEM)), + PhThreadItemType + ); + memset(threadItem, 0, sizeof(PH_THREAD_ITEM)); + threadItem->ThreadId = ThreadId; + PhPrintUInt32(threadItem->ThreadIdString, HandleToUlong(ThreadId)); + + PhEmCallObjectOperation(EmThreadItemType, threadItem, EmObjectCreate); + + return threadItem; +} + +VOID PhpThreadItemDeleteProcedure( + _In_ PVOID Object, + _In_ ULONG Flags + ) +{ + PPH_THREAD_ITEM threadItem = (PPH_THREAD_ITEM)Object; + + PhEmCallObjectOperation(EmThreadItemType, threadItem, EmObjectDelete); + + if (threadItem->ThreadHandle) NtClose(threadItem->ThreadHandle); + if (threadItem->StartAddressString) PhDereferenceObject(threadItem->StartAddressString); + if (threadItem->StartAddressFileName) PhDereferenceObject(threadItem->StartAddressFileName); + if (threadItem->ServiceName) PhDereferenceObject(threadItem->ServiceName); +} + +BOOLEAN PhpThreadHashtableEqualFunction( + _In_ PVOID Entry1, + _In_ PVOID Entry2 + ) +{ + return + (*(PPH_THREAD_ITEM *)Entry1)->ThreadId == + (*(PPH_THREAD_ITEM *)Entry2)->ThreadId; +} + +ULONG PhpThreadHashtableHashFunction( + _In_ PVOID Entry + ) +{ + return HandleToUlong((*(PPH_THREAD_ITEM *)Entry)->ThreadId) / 4; +} + +PPH_THREAD_ITEM PhReferenceThreadItem( + _In_ PPH_THREAD_PROVIDER ThreadProvider, + _In_ HANDLE ThreadId + ) +{ + PH_THREAD_ITEM lookupThreadItem; + PPH_THREAD_ITEM lookupThreadItemPtr = &lookupThreadItem; + PPH_THREAD_ITEM *threadItemPtr; + PPH_THREAD_ITEM threadItem; + + lookupThreadItem.ThreadId = ThreadId; + + PhAcquireFastLockShared(&ThreadProvider->ThreadHashtableLock); + + threadItemPtr = (PPH_THREAD_ITEM *)PhFindEntryHashtable( + ThreadProvider->ThreadHashtable, + &lookupThreadItemPtr + ); + + if (threadItemPtr) + { + threadItem = *threadItemPtr; + PhReferenceObject(threadItem); + } + else + { + threadItem = NULL; + } + + PhReleaseFastLockShared(&ThreadProvider->ThreadHashtableLock); + + return threadItem; +} + +VOID PhDereferenceAllThreadItems( + _In_ PPH_THREAD_PROVIDER ThreadProvider + ) +{ + ULONG enumerationKey = 0; + PPH_THREAD_ITEM *threadItem; + + PhAcquireFastLockExclusive(&ThreadProvider->ThreadHashtableLock); + + while (PhEnumHashtable(ThreadProvider->ThreadHashtable, (PVOID *)&threadItem, &enumerationKey)) + { + PhDereferenceObject(*threadItem); + } + + PhReleaseFastLockExclusive(&ThreadProvider->ThreadHashtableLock); +} + +VOID PhpRemoveThreadItem( + _In_ PPH_THREAD_PROVIDER ThreadProvider, + _In_ PPH_THREAD_ITEM ThreadItem + ) +{ + PhRemoveEntryHashtable(ThreadProvider->ThreadHashtable, &ThreadItem); + PhDereferenceObject(ThreadItem); +} + +NTSTATUS PhpThreadQueryWorker( + _In_ PVOID Parameter + ) +{ + PPH_THREAD_QUERY_DATA data = (PPH_THREAD_QUERY_DATA)Parameter; + LONG newSymbolsLoading; + + if (data->ThreadProvider->Terminating) + goto Done; + + newSymbolsLoading = _InterlockedIncrement(&data->ThreadProvider->SymbolsLoading); + + if (newSymbolsLoading == 1) + PhInvokeCallback(&data->ThreadProvider->LoadingStateChangedEvent, (PVOID)TRUE); + + if (data->ThreadProvider->SymbolsLoadedRunId == 0) + PhLoadSymbolsThreadProvider(data->ThreadProvider); + + data->StartAddressString = PhGetSymbolFromAddress( + data->ThreadProvider->SymbolProvider, + data->ThreadItem->StartAddress, + &data->StartAddressResolveLevel, + &data->ThreadItem->StartAddressFileName, + NULL, + NULL + ); + + if (data->StartAddressResolveLevel == PhsrlAddress && data->ThreadProvider->SymbolsLoadedRunId < data->RunId) + { + // The process may have loaded new modules, so load symbols for those and try again. + + PhLoadSymbolsThreadProvider(data->ThreadProvider); + + PhClearReference(&data->StartAddressString); + PhClearReference(&data->ThreadItem->StartAddressFileName); + data->StartAddressString = PhGetSymbolFromAddress( + data->ThreadProvider->SymbolProvider, + data->ThreadItem->StartAddress, + &data->StartAddressResolveLevel, + &data->ThreadItem->StartAddressFileName, + NULL, + NULL + ); + } + + newSymbolsLoading = _InterlockedDecrement(&data->ThreadProvider->SymbolsLoading); + + if (newSymbolsLoading == 0) + PhInvokeCallback(&data->ThreadProvider->LoadingStateChangedEvent, (PVOID)FALSE); + + // Check if the process has services - we'll need to know before getting service tag/name + // information. + if (WINDOWS_HAS_SERVICE_TAGS && !data->ThreadProvider->HasServicesKnown) + { + PPH_PROCESS_ITEM processItem; + + if (processItem = PhReferenceProcessItem(data->ThreadProvider->ProcessId)) + { + data->ThreadProvider->HasServices = processItem->ServiceList && processItem->ServiceList->Count != 0; + PhDereferenceObject(processItem); + } + + data->ThreadProvider->HasServicesKnown = TRUE; + } + + // Get the service tag, and the service name. + if (WINDOWS_HAS_SERVICE_TAGS && + data->ThreadProvider->SymbolProvider->IsRealHandle && + data->ThreadItem->ThreadHandle) + { + PVOID serviceTag; + + if (NT_SUCCESS(PhGetThreadServiceTag( + data->ThreadItem->ThreadHandle, + data->ThreadProvider->ProcessHandle, + &serviceTag + ))) + { + data->ServiceName = PhGetServiceNameFromTag( + data->ThreadProvider->ProcessId, + serviceTag + ); + } + } + +Done: + RtlInterlockedPushEntrySList(&data->ThreadProvider->QueryListHead, &data->ListEntry); + PhDereferenceObject(data->ThreadProvider); + + return STATUS_SUCCESS; +} + +VOID PhpQueueThreadQuery( + _In_ PPH_THREAD_PROVIDER ThreadProvider, + _In_ PPH_THREAD_ITEM ThreadItem + ) +{ + PPH_THREAD_QUERY_DATA data; + + data = PhAllocate(sizeof(PH_THREAD_QUERY_DATA)); + memset(data, 0, sizeof(PH_THREAD_QUERY_DATA)); + PhSetReference(&data->ThreadProvider, ThreadProvider); + PhSetReference(&data->ThreadItem, ThreadItem); + data->RunId = ThreadProvider->RunId; + + PhpQueueThreadWorkQueueItem(PhpThreadQueryWorker, data); +} + +PPH_STRING PhpGetThreadBasicStartAddress( + _In_ PPH_THREAD_PROVIDER ThreadProvider, + _In_ ULONG64 Address, + _Out_ PPH_SYMBOL_RESOLVE_LEVEL ResolveLevel + ) +{ + ULONG64 modBase; + PPH_STRING fileName = NULL; + PPH_STRING baseName = NULL; + PPH_STRING symbol; + + modBase = PhGetModuleFromAddress( + ThreadProvider->SymbolProvider, + Address, + &fileName + ); + + if (fileName == NULL) + { + *ResolveLevel = PhsrlAddress; + + symbol = PhCreateStringEx(NULL, PH_PTR_STR_LEN * 2); + PhPrintPointer(symbol->Buffer, (PVOID)Address); + PhTrimToNullTerminatorString(symbol); + } + else + { + PH_FORMAT format[3]; + + baseName = PhGetBaseName(fileName); + *ResolveLevel = PhsrlModule; + + PhInitFormatSR(&format[0], baseName->sr); + PhInitFormatS(&format[1], L"+0x"); + PhInitFormatIX(&format[2], (ULONG_PTR)(Address - modBase)); + + symbol = PhFormat(format, 3, baseName->Length + 6 + 32); + } + + if (fileName) + PhDereferenceObject(fileName); + if (baseName) + PhDereferenceObject(baseName); + + return symbol; +} + +static NTSTATUS PhpGetThreadCycleTime( + _In_ PPH_THREAD_PROVIDER ThreadProvider, + _In_ PPH_THREAD_ITEM ThreadItem, + _Out_ PULONG64 CycleTime + ) +{ + if (ThreadProvider->ProcessId != SYSTEM_IDLE_PROCESS_ID) + { + return PhGetThreadCycleTime(ThreadItem->ThreadHandle, CycleTime); + } + else + { + if (HandleToUlong(ThreadItem->ThreadId) < (ULONG)PhSystemBasicInformation.NumberOfProcessors) + { + *CycleTime = PhCpuIdleCycleTime[HandleToUlong(ThreadItem->ThreadId)].QuadPart; + return STATUS_SUCCESS; + } + } + + return STATUS_INVALID_PARAMETER; +} + +PPH_STRING PhGetBasePriorityIncrementString( + _In_ LONG Increment + ) +{ + switch (Increment) + { + case THREAD_BASE_PRIORITY_LOWRT + 1: + case THREAD_BASE_PRIORITY_LOWRT: + return PhCreateString(L"Time critical"); + case THREAD_PRIORITY_HIGHEST: + return PhCreateString(L"Highest"); + case THREAD_PRIORITY_ABOVE_NORMAL: + return PhCreateString(L"Above normal"); + case THREAD_PRIORITY_NORMAL: + return PhCreateString(L"Normal"); + case THREAD_PRIORITY_BELOW_NORMAL: + return PhCreateString(L"Below normal"); + case THREAD_PRIORITY_LOWEST: + return PhCreateString(L"Lowest"); + case THREAD_BASE_PRIORITY_IDLE: + case THREAD_BASE_PRIORITY_IDLE - 1: + return PhCreateString(L"Idle"); + case THREAD_PRIORITY_ERROR_RETURN: + return NULL; + default: + return PhFormatString(L"%d", Increment); + } +} + +VOID PhThreadProviderInitialUpdate( + _In_ PPH_THREAD_PROVIDER ThreadProvider + ) +{ + PVOID processes; + + if (NT_SUCCESS(PhEnumProcesses(&processes))) + { + PhpThreadProviderUpdate(ThreadProvider, processes); + PhFree(processes); + } +} + +VOID PhpThreadProviderCallbackHandler( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + if (PhProcessInformation) + { + PhpThreadProviderUpdate((PPH_THREAD_PROVIDER)Context, PhProcessInformation); + } +} + +VOID PhpThreadProviderUpdate( + _In_ PPH_THREAD_PROVIDER ThreadProvider, + _In_ PVOID ProcessInformation + ) +{ + PPH_THREAD_PROVIDER threadProvider = ThreadProvider; + PSYSTEM_PROCESS_INFORMATION process; + SYSTEM_PROCESS_INFORMATION localProcess; + PSYSTEM_THREAD_INFORMATION threads; + ULONG numberOfThreads; + ULONG i; + + process = PhFindProcessInformation(ProcessInformation, threadProvider->ProcessId); + + if (!process) + { + // The process doesn't exist anymore. Pretend it does but has no threads. + process = &localProcess; + process->NumberOfThreads = 0; + } + + threads = process->Threads; + numberOfThreads = process->NumberOfThreads; + + // System Idle Process has one thread per CPU. They all have a TID of 0. We can't have duplicate + // TIDs, so we'll assign unique TIDs. + if (threadProvider->ProcessId == SYSTEM_IDLE_PROCESS_ID) + { + for (i = 0; i < numberOfThreads; i++) + { + threads[i].ClientId.UniqueThread = UlongToHandle(i); + } + } + + // Look for dead threads. + { + PPH_LIST threadsToRemove = NULL; + ULONG enumerationKey = 0; + PPH_THREAD_ITEM *threadItem; + + while (PhEnumHashtable(threadProvider->ThreadHashtable, (PVOID *)&threadItem, &enumerationKey)) + { + BOOLEAN found = FALSE; + + // Check if the thread still exists. + for (i = 0; i < numberOfThreads; i++) + { + PSYSTEM_THREAD_INFORMATION thread = &threads[i]; + + if ((*threadItem)->ThreadId == thread->ClientId.UniqueThread) + { + found = TRUE; + break; + } + } + + if (!found) + { + // Raise the thread removed event. + PhInvokeCallback(&threadProvider->ThreadRemovedEvent, *threadItem); + + if (!threadsToRemove) + threadsToRemove = PhCreateList(2); + + PhAddItemList(threadsToRemove, *threadItem); + } + } + + if (threadsToRemove) + { + PhAcquireFastLockExclusive(&threadProvider->ThreadHashtableLock); + + for (i = 0; i < threadsToRemove->Count; i++) + { + PhpRemoveThreadItem( + threadProvider, + (PPH_THREAD_ITEM)threadsToRemove->Items[i] + ); + } + + PhReleaseFastLockExclusive(&threadProvider->ThreadHashtableLock); + PhDereferenceObject(threadsToRemove); + } + } + + // Go through the queued thread query data. + { + PSLIST_ENTRY entry; + PPH_THREAD_QUERY_DATA data; + + entry = RtlInterlockedFlushSList(&threadProvider->QueryListHead); + + while (entry) + { + data = CONTAINING_RECORD(entry, PH_THREAD_QUERY_DATA, ListEntry); + entry = entry->Next; + + if (data->StartAddressResolveLevel == PhsrlFunction && data->StartAddressString) + { + PhSwapReference(&data->ThreadItem->StartAddressString, data->StartAddressString); + data->ThreadItem->StartAddressResolveLevel = data->StartAddressResolveLevel; + } + + PhMoveReference(&data->ThreadItem->ServiceName, data->ServiceName); + + data->ThreadItem->JustResolved = TRUE; + + if (data->StartAddressString) PhDereferenceObject(data->StartAddressString); + PhDereferenceObject(data->ThreadItem); + PhFree(data); + } + } + + // Look for new threads and update existing ones. + for (i = 0; i < numberOfThreads; i++) + { + PSYSTEM_THREAD_INFORMATION thread = &threads[i]; + PPH_THREAD_ITEM threadItem; + THREAD_BASIC_INFORMATION basicInfo; + + threadItem = PhReferenceThreadItem(threadProvider, thread->ClientId.UniqueThread); + + if (!threadItem) + { + PVOID startAddress = NULL; + + threadItem = PhCreateThreadItem(thread->ClientId.UniqueThread); + + threadItem->CreateTime = thread->CreateTime; + threadItem->KernelTime = thread->KernelTime; + threadItem->UserTime = thread->UserTime; + + PhUpdateDelta(&threadItem->ContextSwitchesDelta, thread->ContextSwitches); + threadItem->Priority = thread->Priority; + threadItem->BasePriority = thread->BasePriority; + threadItem->State = (KTHREAD_STATE)thread->ThreadState; + threadItem->WaitReason = thread->WaitReason; + + // Try to open a handle to the thread. + if (!NT_SUCCESS(PhOpenThread( + &threadItem->ThreadHandle, + THREAD_QUERY_INFORMATION, + threadItem->ThreadId + ))) + { + PhOpenThread( + &threadItem->ThreadHandle, + ThreadQueryAccess, + threadItem->ThreadId + ); + } + + // Get the cycle count. + if (WINDOWS_HAS_CYCLE_TIME) + { + ULONG64 cycles; + + if (NT_SUCCESS(PhpGetThreadCycleTime( + threadProvider, + threadItem, + &cycles + ))) + { + PhUpdateDelta(&threadItem->CyclesDelta, cycles); + } + } + + // Initialize the CPU time deltas. + PhUpdateDelta(&threadItem->CpuKernelDelta, threadItem->KernelTime.QuadPart); + PhUpdateDelta(&threadItem->CpuUserDelta, threadItem->UserTime.QuadPart); + + // Try to get the start address. + + if (threadItem->ThreadHandle) + { + NtQueryInformationThread( + threadItem->ThreadHandle, + ThreadQuerySetWin32StartAddress, + &startAddress, + sizeof(PVOID), + NULL + ); + } + + if (!startAddress) + startAddress = thread->StartAddress; + + threadItem->StartAddress = (ULONG64)startAddress; + + // Get the base priority increment (relative to the process priority). + if (threadItem->ThreadHandle && NT_SUCCESS(PhGetThreadBasicInformation( + threadItem->ThreadHandle, + &basicInfo + ))) + { + threadItem->BasePriorityIncrement = basicInfo.BasePriority; + } + else + { + threadItem->BasePriorityIncrement = THREAD_PRIORITY_ERROR_RETURN; + } + + if (threadProvider->SymbolsLoadedRunId != 0) + { + threadItem->StartAddressString = PhpGetThreadBasicStartAddress( + threadProvider, + threadItem->StartAddress, + &threadItem->StartAddressResolveLevel + ); + } + + if (!threadItem->StartAddressString) + { + threadItem->StartAddressResolveLevel = PhsrlAddress; + threadItem->StartAddressString = PhCreateStringEx(NULL, PH_PTR_STR_LEN * 2); + PhPrintPointer( + threadItem->StartAddressString->Buffer, + (PVOID)threadItem->StartAddress + ); + PhTrimToNullTerminatorString(threadItem->StartAddressString); + } + + PhpQueueThreadQuery(threadProvider, threadItem); + + // Is it a GUI thread? + { + GUITHREADINFO info = { sizeof(GUITHREADINFO) }; + + threadItem->IsGuiThread = !!GetGUIThreadInfo(HandleToUlong(threadItem->ThreadId), &info); + } + + // Add the thread item to the hashtable. + PhAcquireFastLockExclusive(&threadProvider->ThreadHashtableLock); + PhAddEntryHashtable(threadProvider->ThreadHashtable, &threadItem); + PhReleaseFastLockExclusive(&threadProvider->ThreadHashtableLock); + + // Raise the thread added event. + PhInvokeCallback(&threadProvider->ThreadAddedEvent, threadItem); + } + else + { + BOOLEAN modified = FALSE; + + if (threadItem->JustResolved) + modified = TRUE; + + threadItem->KernelTime = thread->KernelTime; + threadItem->UserTime = thread->UserTime; + + threadItem->Priority = thread->Priority; + threadItem->BasePriority = thread->BasePriority; + + threadItem->State = (KTHREAD_STATE)thread->ThreadState; + + if (threadItem->WaitReason != thread->WaitReason) + { + threadItem->WaitReason = thread->WaitReason; + modified = TRUE; + } + + // If the resolve level is only at address, it probably + // means symbols weren't loaded the last time we + // tried to get the start address. Try again. + if (threadItem->StartAddressResolveLevel == PhsrlAddress) + { + if (threadProvider->SymbolsLoadedRunId != 0) + { + PPH_STRING newStartAddressString; + + newStartAddressString = PhpGetThreadBasicStartAddress( + threadProvider, + threadItem->StartAddress, + &threadItem->StartAddressResolveLevel + ); + + PhMoveReference( + &threadItem->StartAddressString, + newStartAddressString + ); + + modified = TRUE; + } + } + + // If we couldn't resolve the start address to a module+offset, use the StartAddress + // instead of the Win32StartAddress and try again. Note that we check the resolve level + // again because we may have changed it in the previous block. + if (threadItem->JustResolved && + threadItem->StartAddressResolveLevel == PhsrlAddress) + { + if (threadItem->StartAddress != (ULONG64)thread->StartAddress) + { + threadItem->StartAddress = (ULONG64)thread->StartAddress; + PhpQueueThreadQuery(threadProvider, threadItem); + } + } + + // Update the context switch count. + { + ULONG oldDelta; + + oldDelta = threadItem->ContextSwitchesDelta.Delta; + PhUpdateDelta(&threadItem->ContextSwitchesDelta, thread->ContextSwitches); + + if (threadItem->ContextSwitchesDelta.Delta != oldDelta) + { + modified = TRUE; + } + } + + // Update the cycle count. + if (WINDOWS_HAS_CYCLE_TIME) + { + ULONG64 cycles; + ULONG64 oldDelta; + + oldDelta = threadItem->CyclesDelta.Delta; + + if (NT_SUCCESS(PhpGetThreadCycleTime( + threadProvider, + threadItem, + &cycles + ))) + { + PhUpdateDelta(&threadItem->CyclesDelta, cycles); + + if (threadItem->CyclesDelta.Delta != oldDelta) + { + modified = TRUE; + } + } + } + + // Update the CPU time deltas. + PhUpdateDelta(&threadItem->CpuKernelDelta, threadItem->KernelTime.QuadPart); + PhUpdateDelta(&threadItem->CpuUserDelta, threadItem->UserTime.QuadPart); + + // Update the CPU usage. + // If the cycle time isn't available, we'll fall back to using the CPU time. + if (WINDOWS_HAS_CYCLE_TIME && PhEnableCycleCpuUsage && (threadProvider->ProcessId == SYSTEM_IDLE_PROCESS_ID || threadItem->ThreadHandle)) + { + threadItem->CpuUsage = (FLOAT)threadItem->CyclesDelta.Delta / PhCpuTotalCycleDelta; + } + else + { + threadItem->CpuUsage = (FLOAT)(threadItem->CpuKernelDelta.Delta + threadItem->CpuUserDelta.Delta) / + (PhCpuKernelDelta.Delta + PhCpuUserDelta.Delta + PhCpuIdleDelta.Delta); + } + + // Update the base priority increment. + { + LONG oldBasePriorityIncrement = threadItem->BasePriorityIncrement; + + if (threadItem->ThreadHandle && NT_SUCCESS(PhGetThreadBasicInformation( + threadItem->ThreadHandle, + &basicInfo + ))) + { + threadItem->BasePriorityIncrement = basicInfo.BasePriority; + } + else + { + threadItem->BasePriorityIncrement = THREAD_PRIORITY_ERROR_RETURN; + } + + if (threadItem->BasePriorityIncrement != oldBasePriorityIncrement) + { + modified = TRUE; + } + } + + // Update the GUI thread status. + { + GUITHREADINFO info = { sizeof(GUITHREADINFO) }; + BOOLEAN oldIsGuiThread = threadItem->IsGuiThread; + + threadItem->IsGuiThread = !!GetGUIThreadInfo(HandleToUlong(threadItem->ThreadId), &info); + + if (threadItem->IsGuiThread != oldIsGuiThread) + modified = TRUE; + } + + threadItem->JustResolved = FALSE; + + if (modified) + { + // Raise the thread modified event. + PhInvokeCallback(&threadProvider->ThreadModifiedEvent, threadItem); + } + + PhDereferenceObject(threadItem); + } + } + + PhInvokeCallback(&threadProvider->UpdatedEvent, NULL); + threadProvider->RunId++; +} diff --git a/ProcessHacker/thrdstk.c b/ProcessHacker/thrdstk.c index 3e64ca2dc9f1..5e7d9e053328 100644 --- a/ProcessHacker/thrdstk.c +++ b/ProcessHacker/thrdstk.c @@ -1,697 +1,697 @@ -/* - * Process Hacker - - * thread stack viewer - * - * Copyright (C) 2010-2016 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include - -#include -#include - -#include -#include -#include -#include - -#define WM_PH_COMPLETED (WM_APP + 301) -#define WM_PH_STATUS_UPDATE (WM_APP + 302) - -typedef struct _THREAD_STACK_CONTEXT -{ - HANDLE ProcessId; - HANDLE ThreadId; - HANDLE ThreadHandle; - HWND ListViewHandle; - PPH_THREAD_PROVIDER ThreadProvider; - PPH_SYMBOL_PROVIDER SymbolProvider; - BOOLEAN CustomWalk; - - BOOLEAN StopWalk; - PPH_LIST List; - PPH_LIST NewList; - HWND ProgressWindowHandle; - NTSTATUS WalkStatus; - PPH_STRING StatusMessage; - PH_QUEUED_LOCK StatusLock; -} THREAD_STACK_CONTEXT, *PTHREAD_STACK_CONTEXT; - -typedef struct _THREAD_STACK_ITEM -{ - PH_THREAD_STACK_FRAME StackFrame; - ULONG Index; - PPH_STRING Symbol; -} THREAD_STACK_ITEM, *PTHREAD_STACK_ITEM; - -INT_PTR CALLBACK PhpThreadStackDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -VOID PhpFreeThreadStackItem( - _In_ PTHREAD_STACK_ITEM StackItem - ); - -NTSTATUS PhpRefreshThreadStack( - _In_ HWND hwnd, - _In_ PTHREAD_STACK_CONTEXT ThreadStackContext - ); - -INT_PTR CALLBACK PhpThreadStackProgressDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -static RECT MinimumSize = { -1, -1, -1, -1 }; - -VOID PhShowThreadStackDialog( - _In_ HWND ParentWindowHandle, - _In_ HANDLE ProcessId, - _In_ HANDLE ThreadId, - _In_ PPH_THREAD_PROVIDER ThreadProvider - ) -{ - NTSTATUS status; - THREAD_STACK_CONTEXT threadStackContext; - HANDLE threadHandle = NULL; - - // If the user is trying to view a system thread stack - // but KProcessHacker is not loaded, show an error message. - if (ProcessId == SYSTEM_PROCESS_ID && !KphIsConnected()) - { - PhShowError(ParentWindowHandle, PH_KPH_ERROR_MESSAGE); - return; - } - - memset(&threadStackContext, 0, sizeof(THREAD_STACK_CONTEXT)); - threadStackContext.ProcessId = ProcessId; - threadStackContext.ThreadId = ThreadId; - threadStackContext.ThreadProvider = ThreadProvider; - threadStackContext.SymbolProvider = ThreadProvider->SymbolProvider; - - if (!NT_SUCCESS(status = PhOpenThread( - &threadHandle, - THREAD_QUERY_INFORMATION | THREAD_GET_CONTEXT | THREAD_SUSPEND_RESUME, - ThreadId - ))) - { - if (KphIsConnected()) - { - status = PhOpenThread( - &threadHandle, - ThreadQueryAccess, - ThreadId - ); - } - } - - if (!NT_SUCCESS(status)) - { - PhShowStatus(ParentWindowHandle, L"Unable to open the thread", status, 0); - return; - } - - threadStackContext.ThreadHandle = threadHandle; - threadStackContext.List = PhCreateList(10); - threadStackContext.NewList = PhCreateList(10); - PhInitializeQueuedLock(&threadStackContext.StatusLock); - - DialogBoxParam( - PhInstanceHandle, - MAKEINTRESOURCE(IDD_THRDSTACK), - ParentWindowHandle, - PhpThreadStackDlgProc, - (LPARAM)&threadStackContext - ); - - PhClearReference(&threadStackContext.StatusMessage); - PhDereferenceObject(threadStackContext.NewList); - PhDereferenceObject(threadStackContext.List); - - if (threadStackContext.ThreadHandle) - NtClose(threadStackContext.ThreadHandle); -} - -static INT_PTR CALLBACK PhpThreadStackDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - switch (uMsg) - { - case WM_INITDIALOG: - { - NTSTATUS status; - PTHREAD_STACK_CONTEXT threadStackContext; - PPH_STRING title; - HWND lvHandle; - PPH_LAYOUT_MANAGER layoutManager; - - threadStackContext = (PTHREAD_STACK_CONTEXT)lParam; - SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)threadStackContext); - - title = PhFormatString(L"Stack - thread %u", HandleToUlong(threadStackContext->ThreadId)); - SetWindowText(hwndDlg, title->Buffer); - PhDereferenceObject(title); - - lvHandle = GetDlgItem(hwndDlg, IDC_LIST); - PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 30, L" "); - PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 300, L"Name"); - PhSetListViewStyle(lvHandle, FALSE, TRUE); - PhSetControlTheme(lvHandle, L"explorer"); - PhLoadListViewColumnsFromSetting(L"ThreadStackListViewColumns", lvHandle); - - threadStackContext->ListViewHandle = lvHandle; - - layoutManager = PhAllocate(sizeof(PH_LAYOUT_MANAGER)); - PhInitializeLayoutManager(layoutManager, hwndDlg); - SetProp(hwndDlg, L"LayoutManager", (HANDLE)layoutManager); - - PhAddLayoutItem(layoutManager, lvHandle, NULL, - PH_ANCHOR_ALL); - PhAddLayoutItem(layoutManager, GetDlgItem(hwndDlg, IDC_COPY), - NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); - PhAddLayoutItem(layoutManager, GetDlgItem(hwndDlg, IDC_REFRESH), - NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); - PhAddLayoutItem(layoutManager, GetDlgItem(hwndDlg, IDOK), - NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); - - if (MinimumSize.left == -1) - { - RECT rect; - - rect.left = 0; - rect.top = 0; - rect.right = 190; - rect.bottom = 120; - MapDialogRect(hwndDlg, &rect); - MinimumSize = rect; - MinimumSize.left = 0; - } - - PhLoadWindowPlacementFromSetting(NULL, L"ThreadStackWindowSize", hwndDlg); - PhCenterWindow(hwndDlg, GetParent(hwndDlg)); - - if (PhPluginsEnabled) - { - PH_PLUGIN_THREAD_STACK_CONTROL control; - - control.Type = PluginThreadStackInitializing; - control.UniqueKey = threadStackContext; - control.u.Initializing.ProcessId = threadStackContext->ProcessId; - control.u.Initializing.ThreadId = threadStackContext->ThreadId; - control.u.Initializing.ThreadHandle = threadStackContext->ThreadHandle; - control.u.Initializing.SymbolProvider = threadStackContext->SymbolProvider; - control.u.Initializing.CustomWalk = FALSE; - PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackThreadStackControl), &control); - - threadStackContext->CustomWalk = control.u.Initializing.CustomWalk; - } - - status = PhpRefreshThreadStack(hwndDlg, threadStackContext); - - if (status == STATUS_ABANDONED) - EndDialog(hwndDlg, IDCANCEL); - else if (!NT_SUCCESS(status)) - PhShowStatus(hwndDlg, L"Unable to load the stack", status, 0); - } - break; - case WM_DESTROY: - { - PPH_LAYOUT_MANAGER layoutManager; - PTHREAD_STACK_CONTEXT threadStackContext; - ULONG i; - - layoutManager = (PPH_LAYOUT_MANAGER)GetProp(hwndDlg, L"LayoutManager"); - PhDeleteLayoutManager(layoutManager); - PhFree(layoutManager); - - threadStackContext = (PTHREAD_STACK_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom()); - - if (PhPluginsEnabled) - { - PH_PLUGIN_THREAD_STACK_CONTROL control; - - control.Type = PluginThreadStackUninitializing; - control.UniqueKey = threadStackContext; - PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackThreadStackControl), &control); - } - - for (i = 0; i < threadStackContext->List->Count; i++) - PhpFreeThreadStackItem(threadStackContext->List->Items[i]); - - PhSaveListViewColumnsToSetting(L"ThreadStackListViewColumns", GetDlgItem(hwndDlg, IDC_LIST)); - PhSaveWindowPlacementToSetting(NULL, L"ThreadStackWindowSize", hwndDlg); - - RemoveProp(hwndDlg, PhMakeContextAtom()); - RemoveProp(hwndDlg, L"LayoutManager"); - } - break; - case WM_COMMAND: - { - INT id = LOWORD(wParam); - - switch (id) - { - case IDCANCEL: // Esc and X button to close - case IDOK: - EndDialog(hwndDlg, IDOK); - break; - case IDC_REFRESH: - { - NTSTATUS status; - - if (!NT_SUCCESS(status = PhpRefreshThreadStack( - hwndDlg, - (PTHREAD_STACK_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom()) - ))) - { - PhShowStatus(hwndDlg, L"Unable to load the stack", status, 0); - } - } - break; - case IDC_COPY: - { - HWND lvHandle; - - lvHandle = GetDlgItem(hwndDlg, IDC_LIST); - - if (ListView_GetSelectedCount(lvHandle) == 0) - PhSetStateAllListViewItems(lvHandle, LVIS_SELECTED, LVIS_SELECTED); - - PhCopyListView(lvHandle); - SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)lvHandle, TRUE); - } - break; - } - } - break; - case WM_NOTIFY: - { - LPNMHDR header = (LPNMHDR)lParam; - - switch (header->code) - { - case LVN_GETINFOTIP: - { - LPNMLVGETINFOTIP getInfoTip = (LPNMLVGETINFOTIP)header; - HWND lvHandle; - PTHREAD_STACK_CONTEXT threadStackContext; - - lvHandle = GetDlgItem(hwndDlg, IDC_LIST); - threadStackContext = (PTHREAD_STACK_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom()); - - if (header->hwndFrom == lvHandle) - { - PTHREAD_STACK_ITEM stackItem; - PPH_THREAD_STACK_FRAME stackFrame; - - if (PhGetListViewItemParam(lvHandle, getInfoTip->iItem, &stackItem)) - { - PH_STRING_BUILDER stringBuilder; - PPH_STRING fileName; - PH_SYMBOL_LINE_INFORMATION lineInfo; - - stackFrame = &stackItem->StackFrame; - PhInitializeStringBuilder(&stringBuilder, 40); - - PhAppendFormatStringBuilder( - &stringBuilder, - L"Stack: 0x%Ix, Frame: 0x%Ix\n", - stackFrame->StackAddress, - stackFrame->FrameAddress - ); - - // There are no params for kernel-mode stack traces. - if ((ULONG_PTR)stackFrame->PcAddress <= PhSystemBasicInformation.MaximumUserModeAddress) - { - PhAppendFormatStringBuilder( - &stringBuilder, - L"Parameters: 0x%Ix, 0x%Ix, 0x%Ix, 0x%Ix\n", - stackFrame->Params[0], - stackFrame->Params[1], - stackFrame->Params[2], - stackFrame->Params[3] - ); - } - - if (PhGetLineFromAddress( - threadStackContext->SymbolProvider, - (ULONG64)stackFrame->PcAddress, - &fileName, - NULL, - &lineInfo - )) - { - PhAppendFormatStringBuilder( - &stringBuilder, - L"File: %s: line %u\n", - fileName->Buffer, - lineInfo.LineNumber - ); - PhDereferenceObject(fileName); - } - - if (stringBuilder.String->Length != 0) - PhRemoveEndStringBuilder(&stringBuilder, 1); - - if (PhPluginsEnabled) - { - PH_PLUGIN_THREAD_STACK_CONTROL control; - - control.Type = PluginThreadStackGetTooltip; - control.UniqueKey = threadStackContext; - control.u.GetTooltip.StackFrame = stackFrame; - control.u.GetTooltip.StringBuilder = &stringBuilder; - PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackThreadStackControl), &control); - } - - PhCopyListViewInfoTip(getInfoTip, &stringBuilder.String->sr); - PhDeleteStringBuilder(&stringBuilder); - } - } - } - break; - } - } - break; - case WM_SIZE: - { - PPH_LAYOUT_MANAGER layoutManager; - - layoutManager = (PPH_LAYOUT_MANAGER)GetProp(hwndDlg, L"LayoutManager"); - PhLayoutManagerLayout(layoutManager); - } - break; - case WM_SIZING: - { - PhResizingMinimumSize((PRECT)lParam, wParam, MinimumSize.right, MinimumSize.bottom); - } - break; - } - - return FALSE; -} - -static VOID PhpFreeThreadStackItem( - _In_ PTHREAD_STACK_ITEM StackItem - ) -{ - PhClearReference(&StackItem->Symbol); - PhFree(StackItem); -} - -static NTSTATUS PhpRefreshThreadStack( - _In_ HWND hwnd, - _In_ PTHREAD_STACK_CONTEXT ThreadStackContext - ) -{ - ULONG i; - - ThreadStackContext->StopWalk = FALSE; - PhMoveReference(&ThreadStackContext->StatusMessage, PhCreateString(L"Loading stack...")); - - DialogBoxParam( - PhInstanceHandle, - MAKEINTRESOURCE(IDD_PROGRESS), - hwnd, - PhpThreadStackProgressDlgProc, - (LPARAM)ThreadStackContext - ); - - if (!ThreadStackContext->StopWalk && NT_SUCCESS(ThreadStackContext->WalkStatus)) - { - for (i = 0; i < ThreadStackContext->List->Count; i++) - PhpFreeThreadStackItem(ThreadStackContext->List->Items[i]); - - PhDereferenceObject(ThreadStackContext->List); - ThreadStackContext->List = ThreadStackContext->NewList; - ThreadStackContext->NewList = PhCreateList(10); - - SendMessage(ThreadStackContext->ListViewHandle, WM_SETREDRAW, FALSE, 0); - ListView_DeleteAllItems(ThreadStackContext->ListViewHandle); - - for (i = 0; i < ThreadStackContext->List->Count; i++) - { - PTHREAD_STACK_ITEM item = ThreadStackContext->List->Items[i]; - INT lvItemIndex; - WCHAR integerString[PH_INT32_STR_LEN_1]; - - PhPrintUInt32(integerString, item->Index); - lvItemIndex = PhAddListViewItem(ThreadStackContext->ListViewHandle, MAXINT, integerString, item); - PhSetListViewSubItem(ThreadStackContext->ListViewHandle, lvItemIndex, 1, PhGetStringOrDefault(item->Symbol, L"???")); - } - - SendMessage(ThreadStackContext->ListViewHandle, WM_SETREDRAW, TRUE, 0); - InvalidateRect(ThreadStackContext->ListViewHandle, NULL, FALSE); - } - else - { - for (i = 0; i < ThreadStackContext->NewList->Count; i++) - PhpFreeThreadStackItem(ThreadStackContext->NewList->Items[i]); - - PhClearList(ThreadStackContext->NewList); - } - - if (ThreadStackContext->StopWalk) - return STATUS_ABANDONED; - - return ThreadStackContext->WalkStatus; -} - -static BOOLEAN NTAPI PhpWalkThreadStackCallback( - _In_ PPH_THREAD_STACK_FRAME StackFrame, - _In_opt_ PVOID Context - ) -{ - PTHREAD_STACK_CONTEXT threadStackContext = (PTHREAD_STACK_CONTEXT)Context; - PPH_STRING symbol; - PTHREAD_STACK_ITEM item; - - if (threadStackContext->StopWalk) - return FALSE; - - PhAcquireQueuedLockExclusive(&threadStackContext->StatusLock); - PhMoveReference(&threadStackContext->StatusMessage, - PhFormatString(L"Processing frame %u...", threadStackContext->NewList->Count)); - PhReleaseQueuedLockExclusive(&threadStackContext->StatusLock); - PostMessage(threadStackContext->ProgressWindowHandle, WM_PH_STATUS_UPDATE, 0, 0); - - symbol = PhGetSymbolFromAddress( - threadStackContext->SymbolProvider, - (ULONG64)StackFrame->PcAddress, - NULL, - NULL, - NULL, - NULL - ); - - if (symbol && - (StackFrame->Flags & PH_THREAD_STACK_FRAME_I386) && - !(StackFrame->Flags & PH_THREAD_STACK_FRAME_FPO_DATA_PRESENT)) - { - PhMoveReference(&symbol, PhConcatStrings2(symbol->Buffer, L" (No unwind info)")); - } - - item = PhAllocate(sizeof(THREAD_STACK_ITEM)); - item->StackFrame = *StackFrame; - item->Index = threadStackContext->NewList->Count; - - if (PhPluginsEnabled) - { - PH_PLUGIN_THREAD_STACK_CONTROL control; - - control.Type = PluginThreadStackResolveSymbol; - control.UniqueKey = threadStackContext; - control.u.ResolveSymbol.StackFrame = StackFrame; - control.u.ResolveSymbol.Symbol = symbol; - PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackThreadStackControl), &control); - - symbol = control.u.ResolveSymbol.Symbol; - } - - item->Symbol = symbol; - PhAddItemList(threadStackContext->NewList, item); - - return TRUE; -} - -static NTSTATUS PhpRefreshThreadStackThreadStart( - _In_ PVOID Parameter - ) -{ - PH_AUTO_POOL autoPool; - NTSTATUS status; - PTHREAD_STACK_CONTEXT threadStackContext = Parameter; - CLIENT_ID clientId; - BOOLEAN defaultWalk; - - PhInitializeAutoPool(&autoPool); - - PhLoadSymbolsThreadProvider(threadStackContext->ThreadProvider); - - clientId.UniqueProcess = threadStackContext->ProcessId; - clientId.UniqueThread = threadStackContext->ThreadId; - defaultWalk = TRUE; - - if (threadStackContext->CustomWalk) - { - PH_PLUGIN_THREAD_STACK_CONTROL control; - - control.Type = PluginThreadStackWalkStack; - control.UniqueKey = threadStackContext; - control.u.WalkStack.Status = STATUS_UNSUCCESSFUL; - control.u.WalkStack.ThreadHandle = threadStackContext->ThreadHandle; - control.u.WalkStack.ProcessHandle = threadStackContext->SymbolProvider->ProcessHandle; - control.u.WalkStack.ClientId = &clientId; - control.u.WalkStack.Flags = PH_WALK_I386_STACK | PH_WALK_AMD64_STACK | PH_WALK_KERNEL_STACK; - control.u.WalkStack.Callback = PhpWalkThreadStackCallback; - control.u.WalkStack.CallbackContext = threadStackContext; - PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackThreadStackControl), &control); - status = control.u.WalkStack.Status; - - if (NT_SUCCESS(status)) - defaultWalk = FALSE; - } - - if (defaultWalk) - { - PH_PLUGIN_THREAD_STACK_CONTROL control; - - control.UniqueKey = threadStackContext; - - if (PhPluginsEnabled) - { - control.Type = PluginThreadStackBeginDefaultWalkStack; - PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackThreadStackControl), &control); - } - - status = PhWalkThreadStack( - threadStackContext->ThreadHandle, - threadStackContext->SymbolProvider->ProcessHandle, - &clientId, - threadStackContext->SymbolProvider, - PH_WALK_I386_STACK | PH_WALK_AMD64_STACK | PH_WALK_KERNEL_STACK, - PhpWalkThreadStackCallback, - threadStackContext - ); - - if (PhPluginsEnabled) - { - control.Type = PluginThreadStackEndDefaultWalkStack; - PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackThreadStackControl), &control); - } - } - - if (threadStackContext->NewList->Count != 0) - status = STATUS_SUCCESS; - - threadStackContext->WalkStatus = status; - PostMessage(threadStackContext->ProgressWindowHandle, WM_PH_COMPLETED, 0, 0); - - PhDeleteAutoPool(&autoPool); - - return STATUS_SUCCESS; -} - -static INT_PTR CALLBACK PhpThreadStackProgressDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - switch (uMsg) - { - case WM_INITDIALOG: - { - PTHREAD_STACK_CONTEXT threadStackContext; - HANDLE threadHandle; - - threadStackContext = (PTHREAD_STACK_CONTEXT)lParam; - SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)threadStackContext); - threadStackContext->ProgressWindowHandle = hwndDlg; - - if (threadHandle = PhCreateThread(0, PhpRefreshThreadStackThreadStart, threadStackContext)) - { - NtClose(threadHandle); - } - else - { - threadStackContext->WalkStatus = STATUS_UNSUCCESSFUL; - EndDialog(hwndDlg, IDOK); - break; - } - - PhCenterWindow(hwndDlg, GetParent(hwndDlg)); - - PhSetWindowStyle(GetDlgItem(hwndDlg, IDC_PROGRESS), PBS_MARQUEE, PBS_MARQUEE); - SendMessage(GetDlgItem(hwndDlg, IDC_PROGRESS), PBM_SETMARQUEE, TRUE, 75); - SetWindowText(hwndDlg, L"Loading stack..."); - } - break; - case WM_DESTROY: - { - RemoveProp(hwndDlg, PhMakeContextAtom()); - } - break; - case WM_COMMAND: - { - switch (LOWORD(wParam)) - { - case IDCANCEL: - { - PTHREAD_STACK_CONTEXT threadStackContext = (PTHREAD_STACK_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom()); - - EnableWindow(GetDlgItem(hwndDlg, IDCANCEL), FALSE); - threadStackContext->StopWalk = TRUE; - } - break; - } - } - break; - case WM_PH_COMPLETED: - { - EndDialog(hwndDlg, IDOK); - } - break; - case WM_PH_STATUS_UPDATE: - { - PTHREAD_STACK_CONTEXT threadStackContext = (PTHREAD_STACK_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom()); - PPH_STRING message; - - PhAcquireQueuedLockExclusive(&threadStackContext->StatusLock); - message = threadStackContext->StatusMessage; - PhReferenceObject(message); - PhReleaseQueuedLockExclusive(&threadStackContext->StatusLock); - - SetDlgItemText(hwndDlg, IDC_PROGRESSTEXT, message->Buffer); - PhDereferenceObject(message); - } - break; - } - - return 0; -} +/* + * Process Hacker - + * thread stack viewer + * + * Copyright (C) 2010-2016 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include + +#include +#include + +#include +#include +#include +#include + +#define WM_PH_COMPLETED (WM_APP + 301) +#define WM_PH_STATUS_UPDATE (WM_APP + 302) + +typedef struct _THREAD_STACK_CONTEXT +{ + HANDLE ProcessId; + HANDLE ThreadId; + HANDLE ThreadHandle; + HWND ListViewHandle; + PPH_THREAD_PROVIDER ThreadProvider; + PPH_SYMBOL_PROVIDER SymbolProvider; + BOOLEAN CustomWalk; + + BOOLEAN StopWalk; + PPH_LIST List; + PPH_LIST NewList; + HWND ProgressWindowHandle; + NTSTATUS WalkStatus; + PPH_STRING StatusMessage; + PH_QUEUED_LOCK StatusLock; +} THREAD_STACK_CONTEXT, *PTHREAD_STACK_CONTEXT; + +typedef struct _THREAD_STACK_ITEM +{ + PH_THREAD_STACK_FRAME StackFrame; + ULONG Index; + PPH_STRING Symbol; +} THREAD_STACK_ITEM, *PTHREAD_STACK_ITEM; + +INT_PTR CALLBACK PhpThreadStackDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +VOID PhpFreeThreadStackItem( + _In_ PTHREAD_STACK_ITEM StackItem + ); + +NTSTATUS PhpRefreshThreadStack( + _In_ HWND hwnd, + _In_ PTHREAD_STACK_CONTEXT ThreadStackContext + ); + +INT_PTR CALLBACK PhpThreadStackProgressDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +static RECT MinimumSize = { -1, -1, -1, -1 }; + +VOID PhShowThreadStackDialog( + _In_ HWND ParentWindowHandle, + _In_ HANDLE ProcessId, + _In_ HANDLE ThreadId, + _In_ PPH_THREAD_PROVIDER ThreadProvider + ) +{ + NTSTATUS status; + THREAD_STACK_CONTEXT threadStackContext; + HANDLE threadHandle = NULL; + + // If the user is trying to view a system thread stack + // but KProcessHacker is not loaded, show an error message. + if (ProcessId == SYSTEM_PROCESS_ID && !KphIsConnected()) + { + PhShowError(ParentWindowHandle, PH_KPH_ERROR_MESSAGE); + return; + } + + memset(&threadStackContext, 0, sizeof(THREAD_STACK_CONTEXT)); + threadStackContext.ProcessId = ProcessId; + threadStackContext.ThreadId = ThreadId; + threadStackContext.ThreadProvider = ThreadProvider; + threadStackContext.SymbolProvider = ThreadProvider->SymbolProvider; + + if (!NT_SUCCESS(status = PhOpenThread( + &threadHandle, + THREAD_QUERY_INFORMATION | THREAD_GET_CONTEXT | THREAD_SUSPEND_RESUME, + ThreadId + ))) + { + if (KphIsConnected()) + { + status = PhOpenThread( + &threadHandle, + ThreadQueryAccess, + ThreadId + ); + } + } + + if (!NT_SUCCESS(status)) + { + PhShowStatus(ParentWindowHandle, L"Unable to open the thread", status, 0); + return; + } + + threadStackContext.ThreadHandle = threadHandle; + threadStackContext.List = PhCreateList(10); + threadStackContext.NewList = PhCreateList(10); + PhInitializeQueuedLock(&threadStackContext.StatusLock); + + DialogBoxParam( + PhInstanceHandle, + MAKEINTRESOURCE(IDD_THRDSTACK), + ParentWindowHandle, + PhpThreadStackDlgProc, + (LPARAM)&threadStackContext + ); + + PhClearReference(&threadStackContext.StatusMessage); + PhDereferenceObject(threadStackContext.NewList); + PhDereferenceObject(threadStackContext.List); + + if (threadStackContext.ThreadHandle) + NtClose(threadStackContext.ThreadHandle); +} + +static INT_PTR CALLBACK PhpThreadStackDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + switch (uMsg) + { + case WM_INITDIALOG: + { + NTSTATUS status; + PTHREAD_STACK_CONTEXT threadStackContext; + PPH_STRING title; + HWND lvHandle; + PPH_LAYOUT_MANAGER layoutManager; + + threadStackContext = (PTHREAD_STACK_CONTEXT)lParam; + SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)threadStackContext); + + title = PhFormatString(L"Stack - thread %u", HandleToUlong(threadStackContext->ThreadId)); + SetWindowText(hwndDlg, title->Buffer); + PhDereferenceObject(title); + + lvHandle = GetDlgItem(hwndDlg, IDC_LIST); + PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 30, L" "); + PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 300, L"Name"); + PhSetListViewStyle(lvHandle, FALSE, TRUE); + PhSetControlTheme(lvHandle, L"explorer"); + PhLoadListViewColumnsFromSetting(L"ThreadStackListViewColumns", lvHandle); + + threadStackContext->ListViewHandle = lvHandle; + + layoutManager = PhAllocate(sizeof(PH_LAYOUT_MANAGER)); + PhInitializeLayoutManager(layoutManager, hwndDlg); + SetProp(hwndDlg, L"LayoutManager", (HANDLE)layoutManager); + + PhAddLayoutItem(layoutManager, lvHandle, NULL, + PH_ANCHOR_ALL); + PhAddLayoutItem(layoutManager, GetDlgItem(hwndDlg, IDC_COPY), + NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); + PhAddLayoutItem(layoutManager, GetDlgItem(hwndDlg, IDC_REFRESH), + NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); + PhAddLayoutItem(layoutManager, GetDlgItem(hwndDlg, IDOK), + NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); + + if (MinimumSize.left == -1) + { + RECT rect; + + rect.left = 0; + rect.top = 0; + rect.right = 190; + rect.bottom = 120; + MapDialogRect(hwndDlg, &rect); + MinimumSize = rect; + MinimumSize.left = 0; + } + + PhLoadWindowPlacementFromSetting(NULL, L"ThreadStackWindowSize", hwndDlg); + PhCenterWindow(hwndDlg, GetParent(hwndDlg)); + + if (PhPluginsEnabled) + { + PH_PLUGIN_THREAD_STACK_CONTROL control; + + control.Type = PluginThreadStackInitializing; + control.UniqueKey = threadStackContext; + control.u.Initializing.ProcessId = threadStackContext->ProcessId; + control.u.Initializing.ThreadId = threadStackContext->ThreadId; + control.u.Initializing.ThreadHandle = threadStackContext->ThreadHandle; + control.u.Initializing.SymbolProvider = threadStackContext->SymbolProvider; + control.u.Initializing.CustomWalk = FALSE; + PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackThreadStackControl), &control); + + threadStackContext->CustomWalk = control.u.Initializing.CustomWalk; + } + + status = PhpRefreshThreadStack(hwndDlg, threadStackContext); + + if (status == STATUS_ABANDONED) + EndDialog(hwndDlg, IDCANCEL); + else if (!NT_SUCCESS(status)) + PhShowStatus(hwndDlg, L"Unable to load the stack", status, 0); + } + break; + case WM_DESTROY: + { + PPH_LAYOUT_MANAGER layoutManager; + PTHREAD_STACK_CONTEXT threadStackContext; + ULONG i; + + layoutManager = (PPH_LAYOUT_MANAGER)GetProp(hwndDlg, L"LayoutManager"); + PhDeleteLayoutManager(layoutManager); + PhFree(layoutManager); + + threadStackContext = (PTHREAD_STACK_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom()); + + if (PhPluginsEnabled) + { + PH_PLUGIN_THREAD_STACK_CONTROL control; + + control.Type = PluginThreadStackUninitializing; + control.UniqueKey = threadStackContext; + PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackThreadStackControl), &control); + } + + for (i = 0; i < threadStackContext->List->Count; i++) + PhpFreeThreadStackItem(threadStackContext->List->Items[i]); + + PhSaveListViewColumnsToSetting(L"ThreadStackListViewColumns", GetDlgItem(hwndDlg, IDC_LIST)); + PhSaveWindowPlacementToSetting(NULL, L"ThreadStackWindowSize", hwndDlg); + + RemoveProp(hwndDlg, PhMakeContextAtom()); + RemoveProp(hwndDlg, L"LayoutManager"); + } + break; + case WM_COMMAND: + { + INT id = LOWORD(wParam); + + switch (id) + { + case IDCANCEL: // Esc and X button to close + case IDOK: + EndDialog(hwndDlg, IDOK); + break; + case IDC_REFRESH: + { + NTSTATUS status; + + if (!NT_SUCCESS(status = PhpRefreshThreadStack( + hwndDlg, + (PTHREAD_STACK_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom()) + ))) + { + PhShowStatus(hwndDlg, L"Unable to load the stack", status, 0); + } + } + break; + case IDC_COPY: + { + HWND lvHandle; + + lvHandle = GetDlgItem(hwndDlg, IDC_LIST); + + if (ListView_GetSelectedCount(lvHandle) == 0) + PhSetStateAllListViewItems(lvHandle, LVIS_SELECTED, LVIS_SELECTED); + + PhCopyListView(lvHandle); + SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)lvHandle, TRUE); + } + break; + } + } + break; + case WM_NOTIFY: + { + LPNMHDR header = (LPNMHDR)lParam; + + switch (header->code) + { + case LVN_GETINFOTIP: + { + LPNMLVGETINFOTIP getInfoTip = (LPNMLVGETINFOTIP)header; + HWND lvHandle; + PTHREAD_STACK_CONTEXT threadStackContext; + + lvHandle = GetDlgItem(hwndDlg, IDC_LIST); + threadStackContext = (PTHREAD_STACK_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom()); + + if (header->hwndFrom == lvHandle) + { + PTHREAD_STACK_ITEM stackItem; + PPH_THREAD_STACK_FRAME stackFrame; + + if (PhGetListViewItemParam(lvHandle, getInfoTip->iItem, &stackItem)) + { + PH_STRING_BUILDER stringBuilder; + PPH_STRING fileName; + PH_SYMBOL_LINE_INFORMATION lineInfo; + + stackFrame = &stackItem->StackFrame; + PhInitializeStringBuilder(&stringBuilder, 40); + + PhAppendFormatStringBuilder( + &stringBuilder, + L"Stack: 0x%Ix, Frame: 0x%Ix\n", + stackFrame->StackAddress, + stackFrame->FrameAddress + ); + + // There are no params for kernel-mode stack traces. + if ((ULONG_PTR)stackFrame->PcAddress <= PhSystemBasicInformation.MaximumUserModeAddress) + { + PhAppendFormatStringBuilder( + &stringBuilder, + L"Parameters: 0x%Ix, 0x%Ix, 0x%Ix, 0x%Ix\n", + stackFrame->Params[0], + stackFrame->Params[1], + stackFrame->Params[2], + stackFrame->Params[3] + ); + } + + if (PhGetLineFromAddress( + threadStackContext->SymbolProvider, + (ULONG64)stackFrame->PcAddress, + &fileName, + NULL, + &lineInfo + )) + { + PhAppendFormatStringBuilder( + &stringBuilder, + L"File: %s: line %u\n", + fileName->Buffer, + lineInfo.LineNumber + ); + PhDereferenceObject(fileName); + } + + if (stringBuilder.String->Length != 0) + PhRemoveEndStringBuilder(&stringBuilder, 1); + + if (PhPluginsEnabled) + { + PH_PLUGIN_THREAD_STACK_CONTROL control; + + control.Type = PluginThreadStackGetTooltip; + control.UniqueKey = threadStackContext; + control.u.GetTooltip.StackFrame = stackFrame; + control.u.GetTooltip.StringBuilder = &stringBuilder; + PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackThreadStackControl), &control); + } + + PhCopyListViewInfoTip(getInfoTip, &stringBuilder.String->sr); + PhDeleteStringBuilder(&stringBuilder); + } + } + } + break; + } + } + break; + case WM_SIZE: + { + PPH_LAYOUT_MANAGER layoutManager; + + layoutManager = (PPH_LAYOUT_MANAGER)GetProp(hwndDlg, L"LayoutManager"); + PhLayoutManagerLayout(layoutManager); + } + break; + case WM_SIZING: + { + PhResizingMinimumSize((PRECT)lParam, wParam, MinimumSize.right, MinimumSize.bottom); + } + break; + } + + return FALSE; +} + +static VOID PhpFreeThreadStackItem( + _In_ PTHREAD_STACK_ITEM StackItem + ) +{ + PhClearReference(&StackItem->Symbol); + PhFree(StackItem); +} + +static NTSTATUS PhpRefreshThreadStack( + _In_ HWND hwnd, + _In_ PTHREAD_STACK_CONTEXT ThreadStackContext + ) +{ + ULONG i; + + ThreadStackContext->StopWalk = FALSE; + PhMoveReference(&ThreadStackContext->StatusMessage, PhCreateString(L"Loading stack...")); + + DialogBoxParam( + PhInstanceHandle, + MAKEINTRESOURCE(IDD_PROGRESS), + hwnd, + PhpThreadStackProgressDlgProc, + (LPARAM)ThreadStackContext + ); + + if (!ThreadStackContext->StopWalk && NT_SUCCESS(ThreadStackContext->WalkStatus)) + { + for (i = 0; i < ThreadStackContext->List->Count; i++) + PhpFreeThreadStackItem(ThreadStackContext->List->Items[i]); + + PhDereferenceObject(ThreadStackContext->List); + ThreadStackContext->List = ThreadStackContext->NewList; + ThreadStackContext->NewList = PhCreateList(10); + + SendMessage(ThreadStackContext->ListViewHandle, WM_SETREDRAW, FALSE, 0); + ListView_DeleteAllItems(ThreadStackContext->ListViewHandle); + + for (i = 0; i < ThreadStackContext->List->Count; i++) + { + PTHREAD_STACK_ITEM item = ThreadStackContext->List->Items[i]; + INT lvItemIndex; + WCHAR integerString[PH_INT32_STR_LEN_1]; + + PhPrintUInt32(integerString, item->Index); + lvItemIndex = PhAddListViewItem(ThreadStackContext->ListViewHandle, MAXINT, integerString, item); + PhSetListViewSubItem(ThreadStackContext->ListViewHandle, lvItemIndex, 1, PhGetStringOrDefault(item->Symbol, L"???")); + } + + SendMessage(ThreadStackContext->ListViewHandle, WM_SETREDRAW, TRUE, 0); + InvalidateRect(ThreadStackContext->ListViewHandle, NULL, FALSE); + } + else + { + for (i = 0; i < ThreadStackContext->NewList->Count; i++) + PhpFreeThreadStackItem(ThreadStackContext->NewList->Items[i]); + + PhClearList(ThreadStackContext->NewList); + } + + if (ThreadStackContext->StopWalk) + return STATUS_ABANDONED; + + return ThreadStackContext->WalkStatus; +} + +static BOOLEAN NTAPI PhpWalkThreadStackCallback( + _In_ PPH_THREAD_STACK_FRAME StackFrame, + _In_opt_ PVOID Context + ) +{ + PTHREAD_STACK_CONTEXT threadStackContext = (PTHREAD_STACK_CONTEXT)Context; + PPH_STRING symbol; + PTHREAD_STACK_ITEM item; + + if (threadStackContext->StopWalk) + return FALSE; + + PhAcquireQueuedLockExclusive(&threadStackContext->StatusLock); + PhMoveReference(&threadStackContext->StatusMessage, + PhFormatString(L"Processing frame %u...", threadStackContext->NewList->Count)); + PhReleaseQueuedLockExclusive(&threadStackContext->StatusLock); + PostMessage(threadStackContext->ProgressWindowHandle, WM_PH_STATUS_UPDATE, 0, 0); + + symbol = PhGetSymbolFromAddress( + threadStackContext->SymbolProvider, + (ULONG64)StackFrame->PcAddress, + NULL, + NULL, + NULL, + NULL + ); + + if (symbol && + (StackFrame->Flags & PH_THREAD_STACK_FRAME_I386) && + !(StackFrame->Flags & PH_THREAD_STACK_FRAME_FPO_DATA_PRESENT)) + { + PhMoveReference(&symbol, PhConcatStrings2(symbol->Buffer, L" (No unwind info)")); + } + + item = PhAllocate(sizeof(THREAD_STACK_ITEM)); + item->StackFrame = *StackFrame; + item->Index = threadStackContext->NewList->Count; + + if (PhPluginsEnabled) + { + PH_PLUGIN_THREAD_STACK_CONTROL control; + + control.Type = PluginThreadStackResolveSymbol; + control.UniqueKey = threadStackContext; + control.u.ResolveSymbol.StackFrame = StackFrame; + control.u.ResolveSymbol.Symbol = symbol; + PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackThreadStackControl), &control); + + symbol = control.u.ResolveSymbol.Symbol; + } + + item->Symbol = symbol; + PhAddItemList(threadStackContext->NewList, item); + + return TRUE; +} + +static NTSTATUS PhpRefreshThreadStackThreadStart( + _In_ PVOID Parameter + ) +{ + PH_AUTO_POOL autoPool; + NTSTATUS status; + PTHREAD_STACK_CONTEXT threadStackContext = Parameter; + CLIENT_ID clientId; + BOOLEAN defaultWalk; + + PhInitializeAutoPool(&autoPool); + + PhLoadSymbolsThreadProvider(threadStackContext->ThreadProvider); + + clientId.UniqueProcess = threadStackContext->ProcessId; + clientId.UniqueThread = threadStackContext->ThreadId; + defaultWalk = TRUE; + + if (threadStackContext->CustomWalk) + { + PH_PLUGIN_THREAD_STACK_CONTROL control; + + control.Type = PluginThreadStackWalkStack; + control.UniqueKey = threadStackContext; + control.u.WalkStack.Status = STATUS_UNSUCCESSFUL; + control.u.WalkStack.ThreadHandle = threadStackContext->ThreadHandle; + control.u.WalkStack.ProcessHandle = threadStackContext->SymbolProvider->ProcessHandle; + control.u.WalkStack.ClientId = &clientId; + control.u.WalkStack.Flags = PH_WALK_I386_STACK | PH_WALK_AMD64_STACK | PH_WALK_KERNEL_STACK; + control.u.WalkStack.Callback = PhpWalkThreadStackCallback; + control.u.WalkStack.CallbackContext = threadStackContext; + PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackThreadStackControl), &control); + status = control.u.WalkStack.Status; + + if (NT_SUCCESS(status)) + defaultWalk = FALSE; + } + + if (defaultWalk) + { + PH_PLUGIN_THREAD_STACK_CONTROL control; + + control.UniqueKey = threadStackContext; + + if (PhPluginsEnabled) + { + control.Type = PluginThreadStackBeginDefaultWalkStack; + PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackThreadStackControl), &control); + } + + status = PhWalkThreadStack( + threadStackContext->ThreadHandle, + threadStackContext->SymbolProvider->ProcessHandle, + &clientId, + threadStackContext->SymbolProvider, + PH_WALK_I386_STACK | PH_WALK_AMD64_STACK | PH_WALK_KERNEL_STACK, + PhpWalkThreadStackCallback, + threadStackContext + ); + + if (PhPluginsEnabled) + { + control.Type = PluginThreadStackEndDefaultWalkStack; + PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackThreadStackControl), &control); + } + } + + if (threadStackContext->NewList->Count != 0) + status = STATUS_SUCCESS; + + threadStackContext->WalkStatus = status; + PostMessage(threadStackContext->ProgressWindowHandle, WM_PH_COMPLETED, 0, 0); + + PhDeleteAutoPool(&autoPool); + + return STATUS_SUCCESS; +} + +static INT_PTR CALLBACK PhpThreadStackProgressDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + switch (uMsg) + { + case WM_INITDIALOG: + { + PTHREAD_STACK_CONTEXT threadStackContext; + HANDLE threadHandle; + + threadStackContext = (PTHREAD_STACK_CONTEXT)lParam; + SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)threadStackContext); + threadStackContext->ProgressWindowHandle = hwndDlg; + + if (threadHandle = PhCreateThread(0, PhpRefreshThreadStackThreadStart, threadStackContext)) + { + NtClose(threadHandle); + } + else + { + threadStackContext->WalkStatus = STATUS_UNSUCCESSFUL; + EndDialog(hwndDlg, IDOK); + break; + } + + PhCenterWindow(hwndDlg, GetParent(hwndDlg)); + + PhSetWindowStyle(GetDlgItem(hwndDlg, IDC_PROGRESS), PBS_MARQUEE, PBS_MARQUEE); + SendMessage(GetDlgItem(hwndDlg, IDC_PROGRESS), PBM_SETMARQUEE, TRUE, 75); + SetWindowText(hwndDlg, L"Loading stack..."); + } + break; + case WM_DESTROY: + { + RemoveProp(hwndDlg, PhMakeContextAtom()); + } + break; + case WM_COMMAND: + { + switch (LOWORD(wParam)) + { + case IDCANCEL: + { + PTHREAD_STACK_CONTEXT threadStackContext = (PTHREAD_STACK_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom()); + + EnableWindow(GetDlgItem(hwndDlg, IDCANCEL), FALSE); + threadStackContext->StopWalk = TRUE; + } + break; + } + } + break; + case WM_PH_COMPLETED: + { + EndDialog(hwndDlg, IDOK); + } + break; + case WM_PH_STATUS_UPDATE: + { + PTHREAD_STACK_CONTEXT threadStackContext = (PTHREAD_STACK_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom()); + PPH_STRING message; + + PhAcquireQueuedLockExclusive(&threadStackContext->StatusLock); + message = threadStackContext->StatusMessage; + PhReferenceObject(message); + PhReleaseQueuedLockExclusive(&threadStackContext->StatusLock); + + SetDlgItemText(hwndDlg, IDC_PROGRESSTEXT, message->Buffer); + PhDereferenceObject(message); + } + break; + } + + return 0; +} diff --git a/ProcessHacker/tokprp.c b/ProcessHacker/tokprp.c index 27263e020fac..a80fc3f4aac8 100644 --- a/ProcessHacker/tokprp.c +++ b/ProcessHacker/tokprp.c @@ -1,1968 +1,1968 @@ -/* - * Process Hacker - - * token properties - * - * Copyright (C) 2010-2012 wj32 - * Copyright (C) 2017 dmex - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include -#include -#include -#include -#include -#include - -#include - -typedef struct _ATTRIBUTE_NODE -{ - PH_TREENEW_NODE Node; - PPH_LIST Children; - PPH_STRING Text; -} ATTRIBUTE_NODE, *PATTRIBUTE_NODE; - -typedef struct _ATTRIBUTE_TREE_CONTEXT -{ - PPH_LIST RootList; - PPH_LIST NodeList; -} ATTRIBUTE_TREE_CONTEXT, *PATTRIBUTE_TREE_CONTEXT; - -typedef struct _TOKEN_PAGE_CONTEXT -{ - PPH_OPEN_OBJECT OpenObject; - PVOID Context; - DLGPROC HookProc; - - HWND GroupsListViewHandle; - HWND PrivilegesListViewHandle; - PPH_HSPLITTER_CONTEXT HSplitterContext; - - PTOKEN_GROUPS Groups; - PTOKEN_PRIVILEGES Privileges; - PTOKEN_GROUPS Capabilities; - - ATTRIBUTE_TREE_CONTEXT ClaimsTreeContext; - ATTRIBUTE_TREE_CONTEXT AuthzTreeContext; -} TOKEN_PAGE_CONTEXT, *PTOKEN_PAGE_CONTEXT; - -INT CALLBACK PhpTokenPropPageProc( - _In_ HWND hwnd, - _In_ UINT uMsg, - _In_ LPPROPSHEETPAGE ppsp - ); - -INT_PTR CALLBACK PhpTokenPageProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -VOID PhpShowTokenAdvancedProperties( - _In_ HWND ParentWindowHandle, - _In_ PTOKEN_PAGE_CONTEXT Context - ); - -INT_PTR CALLBACK PhpTokenGeneralPageProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -INT_PTR CALLBACK PhpTokenAdvancedPageProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -INT_PTR CALLBACK PhpTokenCapabilitiesPageProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -BOOLEAN NTAPI PhpAttributeTreeNewCallback( - _In_ HWND hwnd, - _In_ PH_TREENEW_MESSAGE Message, - _In_opt_ PVOID Parameter1, - _In_opt_ PVOID Parameter2, - _In_opt_ PVOID Context - ); - -INT_PTR CALLBACK PhpTokenClaimsPageProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -INT_PTR CALLBACK PhpTokenAttributesPageProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -VOID PhShowTokenProperties( - _In_ HWND ParentWindowHandle, - _In_ PPH_OPEN_OBJECT OpenObject, - _In_opt_ PVOID Context, - _In_opt_ PWSTR Title - ) -{ - PROPSHEETHEADER propSheetHeader = { sizeof(propSheetHeader) }; - HPROPSHEETPAGE pages[1]; - - propSheetHeader.dwFlags = - PSH_NOAPPLYNOW | - PSH_NOCONTEXTHELP | - PSH_PROPTITLE; - propSheetHeader.hwndParent = ParentWindowHandle; - propSheetHeader.pszCaption = Title ? Title : L"Token"; - propSheetHeader.nPages = 1; - propSheetHeader.nStartPage = 0; - propSheetHeader.phpage = pages; - - pages[0] = PhCreateTokenPage(OpenObject, Context, NULL); - - PhModalPropertySheet(&propSheetHeader); -} - -HPROPSHEETPAGE PhCreateTokenPage( - _In_ PPH_OPEN_OBJECT OpenObject, - _In_opt_ PVOID Context, - _In_opt_ DLGPROC HookProc - ) -{ - HPROPSHEETPAGE propSheetPageHandle; - PROPSHEETPAGE propSheetPage; - PTOKEN_PAGE_CONTEXT tokenPageContext; - - tokenPageContext = PhCreateAlloc(sizeof(TOKEN_PAGE_CONTEXT)); - memset(tokenPageContext, 0, sizeof(TOKEN_PAGE_CONTEXT)); - tokenPageContext->OpenObject = OpenObject; - tokenPageContext->Context = Context; - tokenPageContext->HookProc = HookProc; - - memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); - propSheetPage.dwSize = sizeof(PROPSHEETPAGE); - propSheetPage.dwFlags = PSP_USECALLBACK; - propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_OBJTOKEN); - propSheetPage.pfnDlgProc = PhpTokenPageProc; - propSheetPage.lParam = (LPARAM)tokenPageContext; - propSheetPage.pfnCallback = PhpTokenPropPageProc; - - propSheetPageHandle = CreatePropertySheetPage(&propSheetPage); - // CreatePropertySheetPage would have sent PSPCB_ADDREF (below), - // which would have added a reference. - PhDereferenceObject(tokenPageContext); - - return propSheetPageHandle; -} - -INT CALLBACK PhpTokenPropPageProc( - _In_ HWND hwnd, - _In_ UINT uMsg, - _In_ LPPROPSHEETPAGE ppsp - ) -{ - PTOKEN_PAGE_CONTEXT tokenPageContext; - - tokenPageContext = (PTOKEN_PAGE_CONTEXT)ppsp->lParam; - - if (uMsg == PSPCB_ADDREF) - { - PhReferenceObject(tokenPageContext); - } - else if (uMsg == PSPCB_RELEASE) - { - PhDereferenceObject(tokenPageContext); - } - - return 1; -} - -PPH_STRING PhGetGroupAttributesString( - _In_ ULONG Attributes - ) -{ - PWSTR baseString; - PPH_STRING string; - - if (Attributes & SE_GROUP_INTEGRITY) - { - if (Attributes & SE_GROUP_INTEGRITY_ENABLED) - return PhCreateString(L"Integrity"); - else - return PhCreateString(L"Integrity (disabled)"); - } - - if (Attributes & SE_GROUP_LOGON_ID) - baseString = L"Logon ID"; - else if (Attributes & SE_GROUP_MANDATORY) - baseString = L"Mandatory"; - else if (Attributes & SE_GROUP_OWNER) - baseString = L"Owner"; - else if (Attributes & SE_GROUP_RESOURCE) - baseString = L"Resource"; - else if (Attributes & SE_GROUP_USE_FOR_DENY_ONLY) - baseString = L"Use for deny only"; - else - baseString = NULL; - - if (!baseString) - { - if (Attributes & SE_GROUP_ENABLED_BY_DEFAULT) - return PhCreateString(L"Default enabled"); - else if (Attributes & SE_GROUP_ENABLED) - return PhReferenceEmptyString(); - else - return PhCreateString(L"Disabled"); - } - - if (Attributes & SE_GROUP_ENABLED_BY_DEFAULT) - string = PhConcatStrings2(baseString, L" (default enabled)"); - else if (Attributes & SE_GROUP_ENABLED) - string = PhCreateString(baseString); - else - string = PhConcatStrings2(baseString, L" (disabled)"); - - return string; -} - -COLORREF PhGetGroupAttributesColor( - _In_ ULONG Attributes - ) -{ - if (Attributes & SE_GROUP_INTEGRITY) - { - if (Attributes & SE_GROUP_INTEGRITY_ENABLED) - return RGB(0xe0, 0xf0, 0xe0); - else - return GetSysColor(COLOR_WINDOW); - } - - if (Attributes & SE_GROUP_ENABLED_BY_DEFAULT) - return RGB(0xe0, 0xf0, 0xe0); - else if (Attributes & SE_GROUP_ENABLED) - return GetSysColor(COLOR_WINDOW); - else - return RGB(0xf0, 0xe0, 0xe0); -} - -static COLORREF NTAPI PhpTokenGroupColorFunction( - _In_ INT Index, - _In_ PVOID Param, - _In_opt_ PVOID Context - ) -{ - PSID_AND_ATTRIBUTES sidAndAttributes = Param; - - return PhGetGroupAttributesColor(sidAndAttributes->Attributes); -} - -PWSTR PhGetPrivilegeAttributesString( - _In_ ULONG Attributes - ) -{ - if (Attributes & SE_PRIVILEGE_ENABLED_BY_DEFAULT) - return L"Default Enabled"; - else if (Attributes & SE_PRIVILEGE_ENABLED) - return L"Enabled"; - else - return L"Disabled"; -} - -COLORREF PhGetPrivilegeAttributesColor( - _In_ ULONG Attributes - ) -{ - if (Attributes & SE_PRIVILEGE_ENABLED_BY_DEFAULT) - return RGB(0xc0, 0xf0, 0xc0); - else if (Attributes & SE_PRIVILEGE_ENABLED) - return RGB(0xe0, 0xf0, 0xe0); - else - return RGB(0xf0, 0xe0, 0xe0); -} - -static COLORREF NTAPI PhpTokenPrivilegeColorFunction( - _In_ INT Index, - _In_ PVOID Param, - _In_opt_ PVOID Context - ) -{ - PLUID_AND_ATTRIBUTES luidAndAttributes = Param; - - return PhGetPrivilegeAttributesColor(luidAndAttributes->Attributes); -} - -PWSTR PhGetElevationTypeString( - _In_ TOKEN_ELEVATION_TYPE ElevationType - ) -{ - switch (ElevationType) - { - case TokenElevationTypeFull: - return L"Yes"; - case TokenElevationTypeLimited: - return L"No"; - default: - return L"N/A"; - } -} - -BOOLEAN PhpUpdateTokenGroups( - _In_ HWND hwndDlg, - _In_ PTOKEN_PAGE_CONTEXT TokenPageContext, - _In_ HWND GroupsLv, - _In_ HANDLE TokenHandle - ) -{ - PTOKEN_GROUPS groups; - ULONG i; - - if (!NT_SUCCESS(PhGetTokenGroups(TokenHandle, &groups))) - return FALSE; - - ExtendedListView_SetRedraw(GroupsLv, FALSE); - - ListView_DeleteAllItems(GroupsLv); - - for (i = 0; i < groups->GroupCount; i++) - { - INT lvItemIndex; - PPH_STRING fullName; - PPH_STRING attributesString; - - if (!(fullName = PhGetSidFullName(groups->Groups[i].Sid, TRUE, NULL))) - fullName = PhSidToStringSid(groups->Groups[i].Sid); - - if (fullName) - { - lvItemIndex = PhAddListViewItem(GroupsLv, MAXINT, fullName->Buffer, &groups->Groups[i]); - attributesString = PhGetGroupAttributesString(groups->Groups[i].Attributes); - PhSetListViewSubItem(GroupsLv, lvItemIndex, 1, attributesString->Buffer); - - PhDereferenceObject(attributesString); - PhDereferenceObject(fullName); - } - } - - ExtendedListView_SortItems(GroupsLv); - - ExtendedListView_SetRedraw(GroupsLv, TRUE); - - if (TokenPageContext->Groups) - PhFree(TokenPageContext->Groups); - - TokenPageContext->Groups = groups; - - return TRUE; -} - -FORCEINLINE PTOKEN_PAGE_CONTEXT PhpTokenPageHeader( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - return (PTOKEN_PAGE_CONTEXT)PhpGenericPropertyPageHeader( - hwndDlg, uMsg, wParam, lParam, L"TokenPageContext"); -} - -INT_PTR CALLBACK PhpTokenPageProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - PTOKEN_PAGE_CONTEXT tokenPageContext; - - tokenPageContext = PhpTokenPageHeader(hwndDlg, uMsg, wParam, lParam); - - if (!tokenPageContext) - return FALSE; - - if (tokenPageContext->HookProc) - { - if (tokenPageContext->HookProc(hwndDlg, uMsg, wParam, lParam)) - return TRUE; - } - - switch (uMsg) - { - case WM_INITDIALOG: - { - HWND groupsLv; - HWND privilegesLv; - HANDLE tokenHandle; - - tokenPageContext->GroupsListViewHandle = groupsLv = GetDlgItem(hwndDlg, IDC_GROUPS); - tokenPageContext->PrivilegesListViewHandle = privilegesLv = GetDlgItem(hwndDlg, IDC_PRIVILEGES); - PhSetListViewStyle(groupsLv, FALSE, TRUE); - PhSetListViewStyle(privilegesLv, FALSE, TRUE); - PhSetControlTheme(groupsLv, L"explorer"); - PhSetControlTheme(privilegesLv, L"explorer"); - - tokenPageContext->HSplitterContext = PhInitializeHSplitter( - hwndDlg, - tokenPageContext->GroupsListViewHandle, - tokenPageContext->PrivilegesListViewHandle - ); - - PhAddListViewColumn(groupsLv, 0, 0, 0, LVCFMT_LEFT, 160, L"Name"); - PhAddListViewColumn(groupsLv, 1, 1, 1, LVCFMT_LEFT, 200, L"Flags"); - - PhAddListViewColumn(privilegesLv, 0, 0, 0, LVCFMT_LEFT, 100, L"Name"); - PhAddListViewColumn(privilegesLv, 1, 1, 1, LVCFMT_LEFT, 100, L"Status"); - PhAddListViewColumn(privilegesLv, 2, 2, 2, LVCFMT_LEFT, 170, L"Description"); - - PhSetExtendedListView(groupsLv); - ExtendedListView_SetItemColorFunction(groupsLv, PhpTokenGroupColorFunction); - PhSetExtendedListView(privilegesLv); - ExtendedListView_SetItemColorFunction(privilegesLv, PhpTokenPrivilegeColorFunction); - - SetDlgItemText(hwndDlg, IDC_USER, L"Unknown"); - SetDlgItemText(hwndDlg, IDC_USERSID, L"Unknown"); - SetDlgItemText(hwndDlg, IDC_APPCONTAINERSID, L"Unknown"); - - if (!WINDOWS_HAS_UAC) - ShowWindow(GetDlgItem(hwndDlg, IDC_INTEGRITY), SW_HIDE); - - if (NT_SUCCESS(tokenPageContext->OpenObject( - &tokenHandle, - TOKEN_QUERY, - tokenPageContext->Context - ))) - { - PTOKEN_USER tokenUser; - PPH_STRING fullUserName; - PPH_STRING stringUserSid; - ULONG sessionId; - TOKEN_ELEVATION_TYPE elevationType; - BOOLEAN isVirtualizationAllowed; - BOOLEAN isVirtualizationEnabled; - PTOKEN_APPCONTAINER_INFORMATION appContainerInfo; - PPH_STRING appContainerSid; - ULONG i; - - if (NT_SUCCESS(PhGetTokenUser(tokenHandle, &tokenUser))) - { - if (fullUserName = PhGetSidFullName(tokenUser->User.Sid, TRUE, NULL)) - { - SetDlgItemText(hwndDlg, IDC_USER, fullUserName->Buffer); - PhDereferenceObject(fullUserName); - } - - if (stringUserSid = PhSidToStringSid(tokenUser->User.Sid)) - { - SetDlgItemText(hwndDlg, IDC_USERSID, stringUserSid->Buffer); - PhDereferenceObject(stringUserSid); - } - - PhFree(tokenUser); - } - - if (NT_SUCCESS(PhGetTokenSessionId(tokenHandle, &sessionId))) - SetDlgItemInt(hwndDlg, IDC_SESSIONID, sessionId, FALSE); - - if (WINDOWS_HAS_UAC) - { - if (NT_SUCCESS(PhGetTokenElevationType(tokenHandle, &elevationType))) - SetDlgItemText(hwndDlg, IDC_ELEVATED, PhGetElevationTypeString(elevationType)); - - if (NT_SUCCESS(PhGetTokenIsVirtualizationAllowed(tokenHandle, &isVirtualizationAllowed))) - { - if (isVirtualizationAllowed) - { - if (NT_SUCCESS(PhGetTokenIsVirtualizationEnabled(tokenHandle, &isVirtualizationEnabled))) - { - SetDlgItemText( - hwndDlg, - IDC_VIRTUALIZED, - isVirtualizationEnabled ? L"Yes" : L"No" - ); - } - } - else - { - SetDlgItemText(hwndDlg, IDC_VIRTUALIZED, L"Not allowed"); - } - } - } - else - { - SetDlgItemText(hwndDlg, IDC_ELEVATED, L"N/A"); - SetDlgItemText(hwndDlg, IDC_VIRTUALIZED, L"N/A"); - } - - if (WINDOWS_HAS_IMMERSIVE) - { - appContainerSid = NULL; - - if (NT_SUCCESS(PhQueryTokenVariableSize(tokenHandle, TokenAppContainerSid, &appContainerInfo))) - { - if (appContainerInfo->TokenAppContainer) - appContainerSid = PhSidToStringSid(appContainerInfo->TokenAppContainer); - - PhFree(appContainerInfo); - } - - if (appContainerSid) - { - SetDlgItemText(hwndDlg, IDC_APPCONTAINERSID, appContainerSid->Buffer); - PhDereferenceObject(appContainerSid); - } - else - { - SetDlgItemText(hwndDlg, IDC_APPCONTAINERSID, L"N/A"); - } - } - else - { - SetDlgItemText(hwndDlg, IDC_APPCONTAINERSID, L"N/A"); - } - - // Groups - PhpUpdateTokenGroups(hwndDlg, tokenPageContext, groupsLv, tokenHandle); - - // Privileges - if (NT_SUCCESS(PhGetTokenPrivileges(tokenHandle, &tokenPageContext->Privileges))) - { - for (i = 0; i < tokenPageContext->Privileges->PrivilegeCount; i++) - { - INT lvItemIndex; - PPH_STRING privilegeName; - PPH_STRING privilegeDisplayName; - - if (PhLookupPrivilegeName( - &tokenPageContext->Privileges->Privileges[i].Luid, - &privilegeName - )) - { - privilegeDisplayName = NULL; - PhLookupPrivilegeDisplayName(&privilegeName->sr, &privilegeDisplayName); - - // Name - lvItemIndex = PhAddListViewItem(privilegesLv, MAXINT, privilegeName->Buffer, - &tokenPageContext->Privileges->Privileges[i]); - // Status - PhSetListViewSubItem(privilegesLv, lvItemIndex, 1, - PhGetPrivilegeAttributesString( - tokenPageContext->Privileges->Privileges[i].Attributes)); - // Description - PhSetListViewSubItem(privilegesLv, lvItemIndex, 2, - PhGetString(privilegeDisplayName)); - - if (privilegeDisplayName) PhDereferenceObject(privilegeDisplayName); - PhDereferenceObject(privilegeName); - } - } - - ExtendedListView_SortItems(privilegesLv); - } - - NtClose(tokenHandle); - } - } - break; - case WM_DESTROY: - { - if (tokenPageContext->Groups) PhFree(tokenPageContext->Groups); - if (tokenPageContext->Privileges) PhFree(tokenPageContext->Privileges); - if (tokenPageContext->HSplitterContext) PhDeleteHSplitter(tokenPageContext->HSplitterContext); - } - break; - case WM_COMMAND: - { - switch (LOWORD(wParam)) - { - case ID_PRIVILEGE_ENABLE: - case ID_PRIVILEGE_DISABLE: - case ID_PRIVILEGE_REMOVE: - { - NTSTATUS status; - PLUID_AND_ATTRIBUTES *privileges; - ULONG numberOfPrivileges; - HANDLE tokenHandle; - ULONG i; - - if (LOWORD(wParam) == ID_PRIVILEGE_REMOVE) - { - if (!PhShowConfirmMessage( - hwndDlg, - L"remove", - L"the selected privilege(s)", - L"Removing privileges may reduce the functionality of the process, " - L"and is permanent for the lifetime of the process.", - FALSE - )) - break; - } - - PhGetSelectedListViewItemParams( - tokenPageContext->PrivilegesListViewHandle, - &privileges, - &numberOfPrivileges - ); - - status = tokenPageContext->OpenObject( - &tokenHandle, - TOKEN_ADJUST_PRIVILEGES, - tokenPageContext->Context - ); - - if (NT_SUCCESS(status)) - { - ExtendedListView_SetRedraw(tokenPageContext->PrivilegesListViewHandle, FALSE); - - for (i = 0; i < numberOfPrivileges; i++) - { - PPH_STRING privilegeName = NULL; - ULONG newAttributes; - - PhLookupPrivilegeName(&privileges[i]->Luid, &privilegeName); - PH_AUTO(privilegeName); - - switch (LOWORD(wParam)) - { - case ID_PRIVILEGE_ENABLE: - newAttributes = SE_PRIVILEGE_ENABLED; - break; - case ID_PRIVILEGE_DISABLE: - newAttributes = 0; - break; - case ID_PRIVILEGE_REMOVE: - newAttributes = SE_PRIVILEGE_REMOVED; - break; - } - - // Privileges which are enabled by default cannot be - // modified except to remove them. - - if ( - privileges[i]->Attributes & SE_PRIVILEGE_ENABLED_BY_DEFAULT && - LOWORD(wParam) != ID_PRIVILEGE_REMOVE - ) - { - if (LOWORD(wParam) == ID_PRIVILEGE_DISABLE) - { - if (!PhShowContinueStatus( - hwndDlg, - PhaConcatStrings2(L"Unable to disable ", privilegeName->Buffer)->Buffer, - STATUS_UNSUCCESSFUL, - 0 - )) - break; - } - - continue; - } - - if (PhSetTokenPrivilege( - tokenHandle, - NULL, - &privileges[i]->Luid, - newAttributes - )) - { - INT lvItemIndex = PhFindListViewItemByParam( - tokenPageContext->PrivilegesListViewHandle, - -1, - privileges[i] - ); - - if (LOWORD(wParam) != ID_PRIVILEGE_REMOVE) - { - // Refresh the status text (and background - // color). - privileges[i]->Attributes = newAttributes; - PhSetListViewSubItem( - tokenPageContext->PrivilegesListViewHandle, - lvItemIndex, - 1, - PhGetPrivilegeAttributesString(newAttributes) - ); - } - else - { - ListView_DeleteItem( - tokenPageContext->PrivilegesListViewHandle, - lvItemIndex - ); - } - } - else - { - PWSTR action = L"set"; - - switch (LOWORD(wParam)) - { - case ID_PRIVILEGE_ENABLE: - action = L"enable"; - break; - case ID_PRIVILEGE_DISABLE: - action = L"disable"; - break; - case ID_PRIVILEGE_REMOVE: - action = L"remove"; - break; - } - - if (!PhShowContinueStatus( - hwndDlg, - PhaFormatString(L"Unable to %s %s", action, privilegeName->Buffer)->Buffer, - STATUS_UNSUCCESSFUL, - 0 - )) - break; - } - } - - ExtendedListView_SetRedraw(tokenPageContext->PrivilegesListViewHandle, TRUE); - - NtClose(tokenHandle); - } - else - { - PhShowStatus(hwndDlg, L"Unable to open the token", status, 0); - } - - PhFree(privileges); - - ExtendedListView_SortItems(tokenPageContext->PrivilegesListViewHandle); - } - break; - case ID_PRIVILEGE_COPY: - { - PhCopyListView(tokenPageContext->PrivilegesListViewHandle); - } - break; - case IDC_INTEGRITY: - { - NTSTATUS status; - RECT rect; - PPH_EMENU menu; - HANDLE tokenHandle; - MANDATORY_LEVEL integrityLevel; - PPH_EMENU_ITEM selectedItem; - - GetWindowRect(GetDlgItem(hwndDlg, IDC_INTEGRITY), &rect); - - menu = PhCreateEMenu(); - - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, MandatoryLevelSecureProcess, L"Protected", NULL, NULL), -1); - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, MandatoryLevelSystem, L"System", NULL, NULL), -1); - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, MandatoryLevelHigh, L"High", NULL, NULL), -1); - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, MandatoryLevelMedium, L"Medium", NULL, NULL), -1); - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, MandatoryLevelLow, L"Low", NULL, NULL), -1); - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, MandatoryLevelUntrusted, L"Untrusted", NULL, NULL), -1); - - integrityLevel = -1; - - // Put a radio check on the menu item that corresponds with the current integrity level. - // Also disable menu items which correspond to higher integrity levels since - // NtSetInformationToken doesn't allow integrity levels to be raised. - if (NT_SUCCESS(tokenPageContext->OpenObject( - &tokenHandle, - TOKEN_QUERY, - tokenPageContext->Context - ))) - { - if (NT_SUCCESS(PhGetTokenIntegrityLevel( - tokenHandle, - &integrityLevel, - NULL - ))) - { - ULONG i; - - for (i = 0; i < menu->Items->Count; i++) - { - PPH_EMENU_ITEM menuItem = menu->Items->Items[i]; - - if (menuItem->Id == integrityLevel) - { - menuItem->Flags |= PH_EMENU_CHECKED | PH_EMENU_RADIOCHECK; - } - else if (menuItem->Id > (ULONG)integrityLevel) - { - menuItem->Flags |= PH_EMENU_DISABLED; - } - } - } - - NtClose(tokenHandle); - } - - selectedItem = PhShowEMenu( - menu, - hwndDlg, - PH_EMENU_SHOW_LEFTRIGHT, - PH_ALIGN_LEFT | PH_ALIGN_TOP, - rect.left, - rect.bottom - ); - - if (selectedItem && selectedItem->Id != integrityLevel) - { - if (PhShowConfirmMessage( - hwndDlg, - L"set", - L"the integrity level", - L"Once lowered, the integrity level of the token cannot be raised again.", - FALSE - )) - { - if (NT_SUCCESS(status = tokenPageContext->OpenObject( - &tokenHandle, - TOKEN_QUERY | TOKEN_ADJUST_DEFAULT, - tokenPageContext->Context - ))) - { - static SID_IDENTIFIER_AUTHORITY mandatoryLabelAuthority = SECURITY_MANDATORY_LABEL_AUTHORITY; - - UCHAR newSidBuffer[FIELD_OFFSET(SID, SubAuthority) + sizeof(ULONG)]; - PSID newSid; - TOKEN_MANDATORY_LABEL mandatoryLabel; - - newSid = (PSID)newSidBuffer; - RtlInitializeSid(newSid, &mandatoryLabelAuthority, 1); - *RtlSubAuthoritySid(newSid, 0) = MANDATORY_LEVEL_TO_MANDATORY_RID(selectedItem->Id); - mandatoryLabel.Label.Sid = newSid; - mandatoryLabel.Label.Attributes = SE_GROUP_INTEGRITY; - - status = NtSetInformationToken( - tokenHandle, - TokenIntegrityLevel, - &mandatoryLabel, - sizeof(TOKEN_MANDATORY_LABEL) - ); - - if (NT_SUCCESS(status)) - PhpUpdateTokenGroups(hwndDlg, tokenPageContext, GetDlgItem(hwndDlg, IDC_GROUPS), tokenHandle); - - NtClose(tokenHandle); - } - - if (!NT_SUCCESS(status)) - PhShowStatus(hwndDlg, L"Unable to set the integrity level", status, 0); - } - } - - PhDestroyEMenu(menu); - } - break; - case IDC_ADVANCED: - { - PhpShowTokenAdvancedProperties(hwndDlg, tokenPageContext); - } - break; - } - } - break; - case WM_NOTIFY: - { - LPNMHDR header = (LPNMHDR)lParam; - - switch (header->code) - { - case PSN_QUERYINITIALFOCUS: - { - if (ListView_GetItemCount(tokenPageContext->GroupsListViewHandle) != 0) - { - ListView_SetColumnWidth(tokenPageContext->GroupsListViewHandle, 0, LVSCW_AUTOSIZE); - ExtendedListView_SetColumnWidth(tokenPageContext->GroupsListViewHandle, 1, ELVSCW_AUTOSIZE_REMAININGSPACE); - } - - if (ListView_GetItemCount(tokenPageContext->PrivilegesListViewHandle) != 0) - { - ListView_SetColumnWidth(tokenPageContext->PrivilegesListViewHandle, 0, LVSCW_AUTOSIZE); - ListView_SetColumnWidth(tokenPageContext->PrivilegesListViewHandle, 1, LVSCW_AUTOSIZE); - ExtendedListView_SetColumnWidth(tokenPageContext->PrivilegesListViewHandle, 2, ELVSCW_AUTOSIZE_REMAININGSPACE); - } - - SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, (LONG_PTR)GetDlgItem(hwndDlg, IDC_SESSIONID)); - return TRUE; - } - break; - } - - PhHandleListViewNotifyBehaviors(lParam, tokenPageContext->GroupsListViewHandle, PH_LIST_VIEW_DEFAULT_1_BEHAVIORS); - PhHandleListViewNotifyBehaviors(lParam, tokenPageContext->PrivilegesListViewHandle, PH_LIST_VIEW_DEFAULT_1_BEHAVIORS); - } - break; - case WM_CONTEXTMENU: - { - if ((HWND)wParam == tokenPageContext->PrivilegesListViewHandle) - { - POINT point; - - point.x = (SHORT)LOWORD(lParam); - point.y = (SHORT)HIWORD(lParam); - - if (point.x == -1 && point.y == -1) - PhGetListViewContextMenuPoint((HWND)wParam, &point); - - if (ListView_GetSelectedCount(tokenPageContext->PrivilegesListViewHandle) != 0) - { - PPH_EMENU menu; - - menu = PhCreateEMenu(); - PhLoadResourceEMenuItem(menu, PhInstanceHandle, MAKEINTRESOURCE(IDR_PRIVILEGE), 0); - PhShowEMenu(menu, hwndDlg, PH_EMENU_SHOW_SEND_COMMAND | PH_EMENU_SHOW_LEFTRIGHT, - PH_ALIGN_LEFT | PH_ALIGN_TOP, point.x, point.y); - PhDestroyEMenu(menu); - } - } - } - break; - case WM_SIZE: - PhHSplitterHandleWmSize(tokenPageContext->HSplitterContext, LOWORD(lParam), HIWORD(lParam)); - break; - case WM_LBUTTONDOWN: - PhHSplitterHandleLButtonDown(tokenPageContext->HSplitterContext, hwndDlg, wParam, lParam); - break; - case WM_LBUTTONUP: - PhHSplitterHandleLButtonUp(tokenPageContext->HSplitterContext, hwndDlg, wParam, lParam); - break; - case WM_MOUSEMOVE: - PhHSplitterHandleMouseMove(tokenPageContext->HSplitterContext, hwndDlg, wParam, lParam); - break; - } - - REFLECT_MESSAGE_DLG(hwndDlg, tokenPageContext->GroupsListViewHandle, uMsg, wParam, lParam); - REFLECT_MESSAGE_DLG(hwndDlg, tokenPageContext->PrivilegesListViewHandle, uMsg, wParam, lParam); - - return FALSE; -} - -VOID PhpShowTokenAdvancedProperties( - _In_ HWND ParentWindowHandle, - _In_ PTOKEN_PAGE_CONTEXT Context - ) -{ - PROPSHEETHEADER propSheetHeader = { sizeof(propSheetHeader) }; - HPROPSHEETPAGE pages[6]; - PROPSHEETPAGE page; - ULONG numberOfPages; - PH_STD_OBJECT_SECURITY stdObjectSecurity; - PPH_ACCESS_ENTRY accessEntries; - ULONG numberOfAccessEntries; - - propSheetHeader.dwFlags = - PSH_NOAPPLYNOW | - PSH_NOCONTEXTHELP | - PSH_PROPTITLE; - propSheetHeader.hwndParent = ParentWindowHandle; - propSheetHeader.pszCaption = L"Token"; - propSheetHeader.nStartPage = 0; - propSheetHeader.phpage = pages; - - numberOfPages = 0; - - // General - - memset(&page, 0, sizeof(PROPSHEETPAGE)); - page.dwSize = sizeof(PROPSHEETPAGE); - page.pszTemplate = MAKEINTRESOURCE(IDD_TOKGENERAL); - page.pfnDlgProc = PhpTokenGeneralPageProc; - page.lParam = (LPARAM)Context; - pages[numberOfPages++] = CreatePropertySheetPage(&page); - - // Advanced - - memset(&page, 0, sizeof(PROPSHEETPAGE)); - page.dwSize = sizeof(PROPSHEETPAGE); - page.pszTemplate = MAKEINTRESOURCE(IDD_TOKADVANCED); - page.pfnDlgProc = PhpTokenAdvancedPageProc; - page.lParam = (LPARAM)Context; - pages[numberOfPages++] = CreatePropertySheetPage(&page); - - if (WindowsVersion >= WINDOWS_8) - { - // Capabilities - - memset(&page, 0, sizeof(PROPSHEETPAGE)); - page.dwSize = sizeof(PROPSHEETPAGE); - page.pszTemplate = MAKEINTRESOURCE(IDD_TOKCAPABILITIES); - page.pfnDlgProc = PhpTokenCapabilitiesPageProc; - page.lParam = (LPARAM)Context; - pages[numberOfPages++] = CreatePropertySheetPage(&page); - - // Claims - - memset(&page, 0, sizeof(PROPSHEETPAGE)); - page.dwSize = sizeof(PROPSHEETPAGE); - page.dwFlags = PSP_USETITLE; - page.pszTemplate = MAKEINTRESOURCE(IDD_TOKATTRIBUTES); - page.pszTitle = L"Claims"; - page.pfnDlgProc = PhpTokenClaimsPageProc; - page.lParam = (LPARAM)Context; - pages[numberOfPages++] = CreatePropertySheetPage(&page); - - // (Token) Attributes - - memset(&page, 0, sizeof(PROPSHEETPAGE)); - page.dwSize = sizeof(PROPSHEETPAGE); - page.dwFlags = PSP_USETITLE; - page.pszTemplate = MAKEINTRESOURCE(IDD_TOKATTRIBUTES); - page.pszTitle = L"Attributes"; - page.pfnDlgProc = PhpTokenAttributesPageProc; - page.lParam = (LPARAM)Context; - pages[numberOfPages++] = CreatePropertySheetPage(&page); - } - - // Security - - stdObjectSecurity.OpenObject = Context->OpenObject; - stdObjectSecurity.ObjectType = L"Token"; - stdObjectSecurity.Context = Context->Context; - - if (PhGetAccessEntries(L"Token", &accessEntries, &numberOfAccessEntries)) - { - pages[numberOfPages++] = PhCreateSecurityPage( - L"Token", - PhStdGetObjectSecurity, - PhStdSetObjectSecurity, - &stdObjectSecurity, - accessEntries, - numberOfAccessEntries - ); - PhFree(accessEntries); - } - - propSheetHeader.nPages = numberOfPages; - PhModalPropertySheet(&propSheetHeader); -} - -static NTSTATUS PhpOpenLinkedToken( - _Out_ PHANDLE Handle, - _In_ ACCESS_MASK DesiredAccess, - _In_opt_ PVOID Context - ) -{ - return PhGetTokenLinkedToken((HANDLE)Context, Handle); -} - -INT_PTR CALLBACK PhpTokenGeneralPageProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - PTOKEN_PAGE_CONTEXT tokenPageContext; - - tokenPageContext = PhpTokenPageHeader(hwndDlg, uMsg, wParam, lParam); - - if (!tokenPageContext) - return FALSE; - - switch (uMsg) - { - case WM_INITDIALOG: - { - HANDLE tokenHandle; - PPH_STRING tokenUserName = NULL; - PPH_STRING tokenUserSid = NULL; - PPH_STRING tokenOwnerName = NULL; - PPH_STRING tokenPrimaryGroupName = NULL; - ULONG tokenSessionId = -1; - PWSTR tokenElevated = L"N/A"; - BOOLEAN hasLinkedToken = FALSE; - PWSTR tokenVirtualization = L"N/A"; - WCHAR tokenSourceName[TOKEN_SOURCE_LENGTH + 1] = L"Unknown"; - WCHAR tokenSourceLuid[PH_PTR_STR_LEN_1] = L"Unknown"; - - // HACK - PhCenterWindow(GetParent(hwndDlg), GetParent(GetParent(hwndDlg))); - - if (NT_SUCCESS(tokenPageContext->OpenObject( - &tokenHandle, - TOKEN_QUERY, - tokenPageContext->Context - ))) - { - PTOKEN_USER tokenUser; - PTOKEN_OWNER tokenOwner; - PTOKEN_PRIMARY_GROUP tokenPrimaryGroup; - TOKEN_ELEVATION_TYPE elevationType; - BOOLEAN isVirtualizationAllowed; - BOOLEAN isVirtualizationEnabled; - - if (NT_SUCCESS(PhGetTokenUser(tokenHandle, &tokenUser))) - { - tokenUserName = PH_AUTO(PhGetSidFullName(tokenUser->User.Sid, TRUE, NULL)); - tokenUserSid = PH_AUTO(PhSidToStringSid(tokenUser->User.Sid)); - - PhFree(tokenUser); - } - - if (NT_SUCCESS(PhGetTokenOwner(tokenHandle, &tokenOwner))) - { - tokenOwnerName = PH_AUTO(PhGetSidFullName(tokenOwner->Owner, TRUE, NULL)); - PhFree(tokenOwner); - } - - if (NT_SUCCESS(PhGetTokenPrimaryGroup(tokenHandle, &tokenPrimaryGroup))) - { - tokenPrimaryGroupName = PH_AUTO(PhGetSidFullName( - tokenPrimaryGroup->PrimaryGroup, TRUE, NULL)); - PhFree(tokenPrimaryGroup); - } - - PhGetTokenSessionId(tokenHandle, &tokenSessionId); - - if (WINDOWS_HAS_UAC) - { - if (NT_SUCCESS(PhGetTokenElevationType(tokenHandle, &elevationType))) - { - tokenElevated = PhGetElevationTypeString(elevationType); - hasLinkedToken = elevationType != TokenElevationTypeDefault; - } - - if (NT_SUCCESS(PhGetTokenIsVirtualizationAllowed(tokenHandle, &isVirtualizationAllowed))) - { - if (isVirtualizationAllowed) - { - if (NT_SUCCESS(PhGetTokenIsVirtualizationEnabled(tokenHandle, &isVirtualizationEnabled))) - { - tokenVirtualization = isVirtualizationEnabled ? L"Enabled" : L"Disabled"; - } - } - else - { - tokenVirtualization = L"Not Allowed"; - } - } - } - - NtClose(tokenHandle); - } - - if (NT_SUCCESS(tokenPageContext->OpenObject( - &tokenHandle, - TOKEN_QUERY_SOURCE, - tokenPageContext->Context - ))) - { - TOKEN_SOURCE tokenSource; - - if (NT_SUCCESS(PhGetTokenSource(tokenHandle, &tokenSource))) - { - PhCopyStringZFromBytes( - tokenSource.SourceName, - TOKEN_SOURCE_LENGTH, - tokenSourceName, - sizeof(tokenSourceName) / 2, - NULL - ); - - PhPrintPointer(tokenSourceLuid, UlongToPtr(tokenSource.SourceIdentifier.LowPart)); - } - - NtClose(tokenHandle); - } - - SetDlgItemText(hwndDlg, IDC_USER, PhGetStringOrDefault(tokenUserName, L"Unknown")); - SetDlgItemText(hwndDlg, IDC_USERSID, PhGetStringOrDefault(tokenUserSid, L"Unknown")); - SetDlgItemText(hwndDlg, IDC_OWNER, PhGetStringOrDefault(tokenOwnerName, L"Unknown")); - SetDlgItemText(hwndDlg, IDC_PRIMARYGROUP, PhGetStringOrDefault(tokenPrimaryGroupName, L"Unknown")); - - if (tokenSessionId != -1) - SetDlgItemInt(hwndDlg, IDC_SESSIONID, tokenSessionId, FALSE); - else - SetDlgItemText(hwndDlg, IDC_SESSIONID, L"Unknown"); - - SetDlgItemText(hwndDlg, IDC_ELEVATED, tokenElevated); - SetDlgItemText(hwndDlg, IDC_VIRTUALIZATION, tokenVirtualization); - SetDlgItemText(hwndDlg, IDC_SOURCENAME, tokenSourceName); - SetDlgItemText(hwndDlg, IDC_SOURCELUID, tokenSourceLuid); - - if (!hasLinkedToken) - ShowWindow(GetDlgItem(hwndDlg, IDC_LINKEDTOKEN), SW_HIDE); - } - break; - case WM_COMMAND: - { - switch (LOWORD(wParam)) - { - case IDC_LINKEDTOKEN: - { - NTSTATUS status; - HANDLE tokenHandle; - - if (NT_SUCCESS(status = tokenPageContext->OpenObject( - &tokenHandle, - TOKEN_QUERY, - tokenPageContext->Context - ))) - { - PhShowTokenProperties(hwndDlg, PhpOpenLinkedToken, (PVOID)tokenHandle, L"Linked Token"); - NtClose(tokenHandle); - } - else - { - PhShowStatus(hwndDlg, L"Unable to open the token", status, 0); - } - } - break; - } - } - break; - case WM_NOTIFY: - { - LPNMHDR header = (LPNMHDR)lParam; - - switch (header->code) - { - case PSN_QUERYINITIALFOCUS: - { - SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, (LONG_PTR)GetDlgItem(hwndDlg, IDC_LINKEDTOKEN)); - return TRUE; - } - break; - } - } - break; - } - - return FALSE; -} - -INT_PTR CALLBACK PhpTokenAdvancedPageProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - PTOKEN_PAGE_CONTEXT tokenPageContext; - - tokenPageContext = PhpTokenPageHeader(hwndDlg, uMsg, wParam, lParam); - - if (!tokenPageContext) - return FALSE; - - switch (uMsg) - { - case WM_INITDIALOG: - { - HANDLE tokenHandle; - PWSTR tokenType = L"Unknown"; - PWSTR tokenImpersonationLevel = L"Unknown"; - WCHAR tokenLuid[PH_PTR_STR_LEN_1] = L"Unknown"; - WCHAR authenticationLuid[PH_PTR_STR_LEN_1] = L"Unknown"; - PPH_STRING memoryUsed = NULL; - PPH_STRING memoryAvailable = NULL; - - if (NT_SUCCESS(tokenPageContext->OpenObject( - &tokenHandle, - TOKEN_QUERY, - tokenPageContext->Context - ))) - { - TOKEN_STATISTICS statistics; - - if (NT_SUCCESS(PhGetTokenStatistics(tokenHandle, &statistics))) - { - switch (statistics.TokenType) - { - case TokenPrimary: - tokenType = L"Primary"; - break; - case TokenImpersonation: - tokenType = L"Impersonation"; - break; - } - - if (statistics.TokenType == TokenImpersonation) - { - switch (statistics.ImpersonationLevel) - { - case SecurityAnonymous: - tokenImpersonationLevel = L"Anonymous"; - break; - case SecurityIdentification: - tokenImpersonationLevel = L"Identification"; - break; - case SecurityImpersonation: - tokenImpersonationLevel = L"Impersonation"; - break; - case SecurityDelegation: - tokenImpersonationLevel = L"Delegation"; - break; - } - } - else - { - tokenImpersonationLevel = L"N/A"; - } - - PhPrintPointer(tokenLuid, UlongToPtr(statistics.TokenId.LowPart)); - PhPrintPointer(authenticationLuid, UlongToPtr(statistics.AuthenticationId.LowPart)); - - // DynamicCharged contains the number of bytes allocated. - // DynamicAvailable contains the number of bytes free. - memoryUsed = PhaFormatSize(statistics.DynamicCharged - statistics.DynamicAvailable, -1); - memoryAvailable = PhaFormatSize(statistics.DynamicCharged, -1); - } - - NtClose(tokenHandle); - } - - SetDlgItemText(hwndDlg, IDC_TYPE, tokenType); - SetDlgItemText(hwndDlg, IDC_IMPERSONATIONLEVEL, tokenImpersonationLevel); - SetDlgItemText(hwndDlg, IDC_TOKENLUID, tokenLuid); - SetDlgItemText(hwndDlg, IDC_AUTHENTICATIONLUID, authenticationLuid); - SetDlgItemText(hwndDlg, IDC_MEMORYUSED, PhGetStringOrDefault(memoryUsed, L"Unknown")); - SetDlgItemText(hwndDlg, IDC_MEMORYAVAILABLE, PhGetStringOrDefault(memoryAvailable, L"Unknown")); - } - break; - } - - return FALSE; -} - -static COLORREF NTAPI PhpTokenCapabilitiesColorFunction( - _In_ INT Index, - _In_ PVOID Param, - _In_opt_ PVOID Context - ) -{ - PSID_AND_ATTRIBUTES sidAndAttributes = Param; - - return PhGetGroupAttributesColor(sidAndAttributes->Attributes); -} - -INT_PTR CALLBACK PhpTokenCapabilitiesPageProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - PTOKEN_PAGE_CONTEXT tokenPageContext; - HWND lvHandle; - - tokenPageContext = PhpTokenPageHeader(hwndDlg, uMsg, wParam, lParam); - - if (!tokenPageContext) - return FALSE; - - lvHandle = GetDlgItem(hwndDlg, IDC_LIST); - - switch (uMsg) - { - case WM_INITDIALOG: - { - HANDLE tokenHandle; - ULONG i; - - PhSetListViewStyle(lvHandle, FALSE, TRUE); - PhSetControlTheme(lvHandle, L"explorer"); - PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 160, L"Name"); - PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 200, L"Flags"); - PhSetExtendedListView(lvHandle); - ExtendedListView_SetItemColorFunction(lvHandle, PhpTokenCapabilitiesColorFunction); - - if (NT_SUCCESS(tokenPageContext->OpenObject( - &tokenHandle, - TOKEN_QUERY, - tokenPageContext->Context - ))) - { - if (NT_SUCCESS(PhQueryTokenVariableSize(tokenHandle, TokenCapabilities, &tokenPageContext->Capabilities))) - { - for (i = 0; i < tokenPageContext->Capabilities->GroupCount; i++) - { - INT lvItemIndex; - PPH_STRING name; - PPH_STRING attributesString; - - name = PhGetSidFullName(tokenPageContext->Capabilities->Groups[i].Sid, TRUE, NULL); - - if (!name) - name = PhSidToStringSid(tokenPageContext->Capabilities->Groups[i].Sid); - - if (name) - { - lvItemIndex = PhAddListViewItem(lvHandle, MAXINT, name->Buffer, - &tokenPageContext->Capabilities->Groups[i]); - attributesString = PhGetGroupAttributesString( - tokenPageContext->Capabilities->Groups[i].Attributes); - PhSetListViewSubItem(lvHandle, lvItemIndex, 1, attributesString->Buffer); - - PhDereferenceObject(attributesString); - PhDereferenceObject(name); - } - } - - if (ListView_GetItemCount(lvHandle) != 0) - { - ListView_SetColumnWidth(lvHandle, 0, LVSCW_AUTOSIZE); - ExtendedListView_SetColumnWidth(lvHandle, 1, ELVSCW_AUTOSIZE_REMAININGSPACE); - } - - ExtendedListView_SortItems(lvHandle); - } - - NtClose(tokenHandle); - } - - EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); - } - break; - case WM_DESTROY: - { - PhFree(tokenPageContext->Capabilities); - tokenPageContext->Capabilities = NULL; - } - break; - case WM_NOTIFY: - { - PhHandleListViewNotifyBehaviors(lParam, lvHandle, PH_LIST_VIEW_DEFAULT_1_BEHAVIORS); - } - break; - } - - REFLECT_MESSAGE_DLG(hwndDlg, lvHandle, uMsg, wParam, lParam); - - return FALSE; -} - -BOOLEAN NTAPI PhpAttributeTreeNewCallback( - _In_ HWND hwnd, - _In_ PH_TREENEW_MESSAGE Message, - _In_opt_ PVOID Parameter1, - _In_opt_ PVOID Parameter2, - _In_opt_ PVOID Context - ) -{ - PATTRIBUTE_TREE_CONTEXT context; - PATTRIBUTE_NODE node; - - context = Context; - - switch (Message) - { - case TreeNewGetChildren: - { - PPH_TREENEW_GET_CHILDREN getChildren = Parameter1; - - node = (PATTRIBUTE_NODE)getChildren->Node; - - if (!node) - { - getChildren->Children = (PPH_TREENEW_NODE *)context->RootList->Items; - getChildren->NumberOfChildren = context->RootList->Count; - } - else - { - getChildren->Children = (PPH_TREENEW_NODE *)node->Children->Items; - getChildren->NumberOfChildren = node->Children->Count; - } - } - return TRUE; - case TreeNewIsLeaf: - { - PPH_TREENEW_IS_LEAF isLeaf = Parameter1; - - node = (PATTRIBUTE_NODE)isLeaf->Node; - - isLeaf->IsLeaf = node->Children->Count == 0; - } - return TRUE; - case TreeNewGetCellText: - { - PPH_TREENEW_GET_CELL_TEXT getCellText = Parameter1; - - node = (PATTRIBUTE_NODE)getCellText->Node; - - if (getCellText->Id == 0) - getCellText->Text = PhGetStringRef(node->Text); - else - return FALSE; - } - return TRUE; - case TreeNewKeyDown: - { - PPH_TREENEW_KEY_EVENT keyEvent = Parameter1; - - switch (keyEvent->VirtualKey) - { - case 'C': - if (GetKeyState(VK_CONTROL) < 0) - { - PPH_STRING text; - - text = PhGetTreeNewText(hwnd, 0); - PhSetClipboardString(hwnd, &text->sr); - PhDereferenceObject(text); - } - break; - } - } - return TRUE; - } - - return FALSE; -} - -PATTRIBUTE_NODE PhpAddAttributeNode( - _In_ PATTRIBUTE_TREE_CONTEXT Context, - _In_opt_ PATTRIBUTE_NODE Parent, - _In_opt_ _Assume_refs_(1) PPH_STRING Text - ) -{ - PATTRIBUTE_NODE node; - - node = PhAllocate(sizeof(ATTRIBUTE_NODE)); - memset(node, 0, sizeof(ATTRIBUTE_NODE)); - PhInitializeTreeNewNode(&node->Node); - - node->Children = PhCreateList(2); - - PhAddItemList(Context->NodeList, node); - - if (Parent) - PhAddItemList(Parent->Children, node); - else - PhAddItemList(Context->RootList, node); - - PhMoveReference(&node->Text, Text); - - return node; -} - -VOID PhpDestroyAttributeNode( - _In_ PATTRIBUTE_NODE Node - ) -{ - PhDereferenceObject(Node->Children); - PhClearReference(&Node->Text); - PhFree(Node); -} - -VOID PhpInitializeAttributeTreeContext( - _Out_ PATTRIBUTE_TREE_CONTEXT Context, - _In_ HWND TreeNewHandle - ) -{ - PH_TREENEW_VIEW_PARTS parts; - - Context->NodeList = PhCreateList(10); - Context->RootList = PhCreateList(10); - - PhSetControlTheme(TreeNewHandle, L"explorer"); - TreeNew_SetCallback(TreeNewHandle, PhpAttributeTreeNewCallback, Context); - TreeNew_GetViewParts(TreeNewHandle, &parts); - PhAddTreeNewColumnEx2(TreeNewHandle, 0, TRUE, L"Attributes", parts.ClientRect.right - parts.VScrollWidth, PH_ALIGN_LEFT, 0, 0, TN_COLUMN_FLAG_NODPISCALEONADD); -} - -VOID PhpDeleteAttributeTreeContext( - _Inout_ PATTRIBUTE_TREE_CONTEXT Context - ) -{ - ULONG i; - - for (i = 0; i < Context->NodeList->Count; i++) - PhpDestroyAttributeNode(Context->NodeList->Items[i]); - - PhDereferenceObject(Context->NodeList); - PhDereferenceObject(Context->RootList); -} - -PWSTR PhGetSecurityAttributeTypeString( - _In_ USHORT Type - ) -{ - // These types are shared between CLAIM_* and TOKEN_* security attributes. - - switch (Type) - { - case TOKEN_SECURITY_ATTRIBUTE_TYPE_INVALID: - return L"Invalid"; - case TOKEN_SECURITY_ATTRIBUTE_TYPE_INT64: - return L"Int64"; - case TOKEN_SECURITY_ATTRIBUTE_TYPE_UINT64: - return L"UInt64"; - case TOKEN_SECURITY_ATTRIBUTE_TYPE_STRING: - return L"String"; - case TOKEN_SECURITY_ATTRIBUTE_TYPE_FQBN: - return L"FQBN"; - case TOKEN_SECURITY_ATTRIBUTE_TYPE_SID: - return L"SID"; - case TOKEN_SECURITY_ATTRIBUTE_TYPE_BOOLEAN: - return L"Boolean"; - case TOKEN_SECURITY_ATTRIBUTE_TYPE_OCTET_STRING: - return L"Octet string"; - default: - return L"(Unknown)"; - } -} - -PPH_STRING PhGetSecurityAttributeFlagsString( - _In_ ULONG Flags - ) -{ - PH_STRING_BUILDER sb; - - // These flags are shared between CLAIM_* and TOKEN_* security attributes. - - PhInitializeStringBuilder(&sb, 100); - - if (Flags & TOKEN_SECURITY_ATTRIBUTE_MANDATORY) - PhAppendStringBuilder2(&sb, L"Mandatory, "); - if (Flags & TOKEN_SECURITY_ATTRIBUTE_DISABLED) - PhAppendStringBuilder2(&sb, L"Disabled, "); - if (Flags & TOKEN_SECURITY_ATTRIBUTE_DISABLED_BY_DEFAULT) - PhAppendStringBuilder2(&sb, L"Default disabled, "); - if (Flags & TOKEN_SECURITY_ATTRIBUTE_USE_FOR_DENY_ONLY) - PhAppendStringBuilder2(&sb, L"Use for deny only, "); - if (Flags & TOKEN_SECURITY_ATTRIBUTE_VALUE_CASE_SENSITIVE) - PhAppendStringBuilder2(&sb, L"Case-sensitive, "); - if (Flags & TOKEN_SECURITY_ATTRIBUTE_NON_INHERITABLE) - PhAppendStringBuilder2(&sb, L"Non-inheritable, "); - - if (sb.String->Length != 0) - PhRemoveEndStringBuilder(&sb, 2); - else - PhAppendStringBuilder2(&sb, L"(None)"); - - return PhFinalStringBuilderString(&sb); -} - -PPH_STRING PhFormatClaimSecurityAttributeValue( - _In_ PCLAIM_SECURITY_ATTRIBUTE_V1 Attribute, - _In_ ULONG ValueIndex - ) -{ - PH_FORMAT format; - - switch (Attribute->ValueType) - { - case CLAIM_SECURITY_ATTRIBUTE_TYPE_INT64: - PhInitFormatI64D(&format, Attribute->Values.pInt64[ValueIndex]); - return PhFormat(&format, 1, 0); - case CLAIM_SECURITY_ATTRIBUTE_TYPE_UINT64: - PhInitFormatI64U(&format, Attribute->Values.pUint64[ValueIndex]); - return PhFormat(&format, 1, 0); - case CLAIM_SECURITY_ATTRIBUTE_TYPE_STRING: - return PhCreateString(Attribute->Values.ppString[ValueIndex]); - case CLAIM_SECURITY_ATTRIBUTE_TYPE_FQBN: - return PhFormatString(L"Version %I64u: %s", - Attribute->Values.pFqbn[ValueIndex].Version, - Attribute->Values.pFqbn[ValueIndex].Name); - case CLAIM_SECURITY_ATTRIBUTE_TYPE_SID: - { - if (RtlValidSid(Attribute->Values.pOctetString[ValueIndex].pValue)) - { - PPH_STRING name; - - name = PhGetSidFullName(Attribute->Values.pOctetString[ValueIndex].pValue, TRUE, NULL); - - if (name) - return name; - - name = PhSidToStringSid(Attribute->Values.pOctetString[ValueIndex].pValue); - - if (name) - return name; - } - } - return PhCreateString(L"(Invalid SID)"); - case CLAIM_SECURITY_ATTRIBUTE_TYPE_BOOLEAN: - return PhCreateString(Attribute->Values.pInt64[ValueIndex] != 0 ? L"True" : L"False"); - case CLAIM_SECURITY_ATTRIBUTE_TYPE_OCTET_STRING: - return PhCreateString(L"(Octet string)"); - default: - return PhCreateString(L"(Unknown)"); - } -} - -PPH_STRING PhFormatTokenSecurityAttributeValue( - _In_ PTOKEN_SECURITY_ATTRIBUTE_V1 Attribute, - _In_ ULONG ValueIndex - ) -{ - PH_FORMAT format; - - switch (Attribute->ValueType) - { - case TOKEN_SECURITY_ATTRIBUTE_TYPE_INT64: - PhInitFormatI64D(&format, Attribute->Values.pInt64[ValueIndex]); - return PhFormat(&format, 1, 0); - case TOKEN_SECURITY_ATTRIBUTE_TYPE_UINT64: - PhInitFormatI64U(&format, Attribute->Values.pUint64[ValueIndex]); - return PhFormat(&format, 1, 0); - case TOKEN_SECURITY_ATTRIBUTE_TYPE_STRING: - return PhCreateStringFromUnicodeString(&Attribute->Values.pString[ValueIndex]); - case TOKEN_SECURITY_ATTRIBUTE_TYPE_FQBN: - return PhFormatString(L"Version %I64u: %.*s", - Attribute->Values.pFqbn[ValueIndex].Version, - Attribute->Values.pFqbn[ValueIndex].Name.Length / sizeof(WCHAR), - Attribute->Values.pFqbn[ValueIndex].Name.Buffer); - case TOKEN_SECURITY_ATTRIBUTE_TYPE_SID: - { - if (RtlValidSid(Attribute->Values.pOctetString[ValueIndex].pValue)) - { - PPH_STRING name; - - name = PhGetSidFullName(Attribute->Values.pOctetString[ValueIndex].pValue, TRUE, NULL); - - if (name) - return name; - - name = PhSidToStringSid(Attribute->Values.pOctetString[ValueIndex].pValue); - - if (name) - return name; - } - } - return PhCreateString(L"(Invalid SID)"); - case TOKEN_SECURITY_ATTRIBUTE_TYPE_BOOLEAN: - return PhCreateString(Attribute->Values.pInt64[ValueIndex] != 0 ? L"True" : L"False"); - case TOKEN_SECURITY_ATTRIBUTE_TYPE_OCTET_STRING: - return PhCreateString(L"(Octet string)"); - default: - return PhCreateString(L"(Unknown)"); - } -} - -BOOLEAN PhpAddTokenClaimAttributes( - _In_ PTOKEN_PAGE_CONTEXT TokenPageContext, - _In_ HWND tnHandle, - _In_ BOOLEAN DeviceClaims, - _In_ PATTRIBUTE_NODE Parent - ) -{ - HANDLE tokenHandle; - PCLAIM_SECURITY_ATTRIBUTES_INFORMATION info; - ULONG i; - ULONG j; - - if (!NT_SUCCESS(TokenPageContext->OpenObject( - &tokenHandle, - TOKEN_QUERY, - TokenPageContext->Context - ))) - return FALSE; - - if (NT_SUCCESS(PhQueryTokenVariableSize(tokenHandle, DeviceClaims ? TokenDeviceClaimAttributes : TokenUserClaimAttributes, &info))) - { - for (i = 0; i < info->AttributeCount; i++) - { - PCLAIM_SECURITY_ATTRIBUTE_V1 attribute = &info->Attribute.pAttributeV1[i]; - PATTRIBUTE_NODE node; - PPH_STRING temp; - - // Attribute - node = PhpAddAttributeNode(&TokenPageContext->ClaimsTreeContext, Parent, PhCreateString(attribute->Name)); - // Type - PhpAddAttributeNode(&TokenPageContext->ClaimsTreeContext, node, - PhFormatString(L"Type: %s", PhGetSecurityAttributeTypeString(attribute->ValueType))); - // Flags - temp = PhGetSecurityAttributeFlagsString(attribute->Flags); - PhpAddAttributeNode(&TokenPageContext->ClaimsTreeContext, node, - PhFormatString(L"Flags: %s", temp->Buffer)); - PhDereferenceObject(temp); - - // Values - for (j = 0; j < attribute->ValueCount; j++) - { - temp = PhFormatClaimSecurityAttributeValue(attribute, j); - PhpAddAttributeNode(&TokenPageContext->ClaimsTreeContext, node, - PhFormatString(L"Value %u: %s", j, temp->Buffer)); - PhDereferenceObject(temp); - } - } - - PhFree(info); - } - - NtClose(tokenHandle); - - TreeNew_NodesStructured(tnHandle); - - return TRUE; -} - -INT_PTR CALLBACK PhpTokenClaimsPageProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - PTOKEN_PAGE_CONTEXT tokenPageContext; - HWND tnHandle; - - tokenPageContext = PhpTokenPageHeader(hwndDlg, uMsg, wParam, lParam); - - if (!tokenPageContext) - return FALSE; - - tnHandle = GetDlgItem(hwndDlg, IDC_LIST); - - switch (uMsg) - { - case WM_INITDIALOG: - { - PATTRIBUTE_NODE userNode; - PATTRIBUTE_NODE deviceNode; - - PhpInitializeAttributeTreeContext(&tokenPageContext->ClaimsTreeContext, tnHandle); - - TreeNew_SetRedraw(tnHandle, FALSE); - - userNode = PhpAddAttributeNode(&tokenPageContext->ClaimsTreeContext, NULL, PhCreateString(L"User claims")); - PhpAddTokenClaimAttributes(tokenPageContext, tnHandle, FALSE, userNode); - deviceNode = PhpAddAttributeNode(&tokenPageContext->ClaimsTreeContext, NULL, PhCreateString(L"Device claims")); - PhpAddTokenClaimAttributes(tokenPageContext, tnHandle, TRUE, deviceNode); - - if (userNode->Children->Count == 0) - PhpAddAttributeNode(&tokenPageContext->ClaimsTreeContext, userNode, PhCreateString(L"(None)")); - if (deviceNode->Children->Count == 0) - PhpAddAttributeNode(&tokenPageContext->ClaimsTreeContext, deviceNode, PhCreateString(L"(None)")); - - TreeNew_NodesStructured(tnHandle); - TreeNew_SetRedraw(tnHandle, TRUE); - - EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); - } - break; - case WM_DESTROY: - { - PhpDeleteAttributeTreeContext(&tokenPageContext->ClaimsTreeContext); - } - break; - } - - return FALSE; -} - -BOOLEAN PhpAddTokenAttributes( - _In_ PTOKEN_PAGE_CONTEXT TokenPageContext, - _In_ HWND tnHandle - ) -{ - HANDLE tokenHandle; - PTOKEN_SECURITY_ATTRIBUTES_INFORMATION info; - ULONG i; - ULONG j; - - if (!NT_SUCCESS(TokenPageContext->OpenObject( - &tokenHandle, - TOKEN_QUERY, - TokenPageContext->Context - ))) - return FALSE; - - if (NT_SUCCESS(PhQueryTokenVariableSize(tokenHandle, TokenSecurityAttributes, &info))) - { - for (i = 0; i < info->AttributeCount; i++) - { - PTOKEN_SECURITY_ATTRIBUTE_V1 attribute = &info->Attribute.pAttributeV1[i]; - PATTRIBUTE_NODE node; - PPH_STRING temp; - - // Attribute - node = PhpAddAttributeNode(&TokenPageContext->AuthzTreeContext, NULL, - PhCreateStringFromUnicodeString(&attribute->Name)); - // Type - PhpAddAttributeNode(&TokenPageContext->AuthzTreeContext, node, - PhFormatString(L"Type: %s", PhGetSecurityAttributeTypeString(attribute->ValueType))); - // Flags - temp = PhGetSecurityAttributeFlagsString(attribute->Flags); - PhpAddAttributeNode(&TokenPageContext->AuthzTreeContext, node, - PhFormatString(L"Flags: %s", temp->Buffer)); - PhDereferenceObject(temp); - - // Values - for (j = 0; j < attribute->ValueCount; j++) - { - temp = PhFormatTokenSecurityAttributeValue(attribute, j); - PhpAddAttributeNode(&TokenPageContext->AuthzTreeContext, node, - PhFormatString(L"Value %u: %s", j, temp->Buffer)); - PhDereferenceObject(temp); - } - } - - PhFree(info); - } - - NtClose(tokenHandle); - - TreeNew_NodesStructured(tnHandle); - - return TRUE; -} - -INT_PTR CALLBACK PhpTokenAttributesPageProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - PTOKEN_PAGE_CONTEXT tokenPageContext; - HWND tnHandle; - - tokenPageContext = PhpTokenPageHeader(hwndDlg, uMsg, wParam, lParam); - - if (!tokenPageContext) - return FALSE; - - tnHandle = GetDlgItem(hwndDlg, IDC_LIST); - - switch (uMsg) - { - case WM_INITDIALOG: - { - PhpInitializeAttributeTreeContext(&tokenPageContext->AuthzTreeContext, tnHandle); - - TreeNew_SetRedraw(tnHandle, FALSE); - - PhpAddTokenAttributes(tokenPageContext, tnHandle); - - if (tokenPageContext->AuthzTreeContext.RootList->Count == 0) - PhpAddAttributeNode(&tokenPageContext->AuthzTreeContext, NULL, PhCreateString(L"(None)")); - - TreeNew_NodesStructured(tnHandle); - TreeNew_SetRedraw(tnHandle, TRUE); - - EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); - } - break; - case WM_DESTROY: - { - PhpDeleteAttributeTreeContext(&tokenPageContext->AuthzTreeContext); - } - break; - } - - return FALSE; -} +/* + * Process Hacker - + * token properties + * + * Copyright (C) 2010-2012 wj32 + * Copyright (C) 2017 dmex + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include +#include +#include +#include +#include +#include + +#include + +typedef struct _ATTRIBUTE_NODE +{ + PH_TREENEW_NODE Node; + PPH_LIST Children; + PPH_STRING Text; +} ATTRIBUTE_NODE, *PATTRIBUTE_NODE; + +typedef struct _ATTRIBUTE_TREE_CONTEXT +{ + PPH_LIST RootList; + PPH_LIST NodeList; +} ATTRIBUTE_TREE_CONTEXT, *PATTRIBUTE_TREE_CONTEXT; + +typedef struct _TOKEN_PAGE_CONTEXT +{ + PPH_OPEN_OBJECT OpenObject; + PVOID Context; + DLGPROC HookProc; + + HWND GroupsListViewHandle; + HWND PrivilegesListViewHandle; + PPH_HSPLITTER_CONTEXT HSplitterContext; + + PTOKEN_GROUPS Groups; + PTOKEN_PRIVILEGES Privileges; + PTOKEN_GROUPS Capabilities; + + ATTRIBUTE_TREE_CONTEXT ClaimsTreeContext; + ATTRIBUTE_TREE_CONTEXT AuthzTreeContext; +} TOKEN_PAGE_CONTEXT, *PTOKEN_PAGE_CONTEXT; + +INT CALLBACK PhpTokenPropPageProc( + _In_ HWND hwnd, + _In_ UINT uMsg, + _In_ LPPROPSHEETPAGE ppsp + ); + +INT_PTR CALLBACK PhpTokenPageProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +VOID PhpShowTokenAdvancedProperties( + _In_ HWND ParentWindowHandle, + _In_ PTOKEN_PAGE_CONTEXT Context + ); + +INT_PTR CALLBACK PhpTokenGeneralPageProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +INT_PTR CALLBACK PhpTokenAdvancedPageProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +INT_PTR CALLBACK PhpTokenCapabilitiesPageProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +BOOLEAN NTAPI PhpAttributeTreeNewCallback( + _In_ HWND hwnd, + _In_ PH_TREENEW_MESSAGE Message, + _In_opt_ PVOID Parameter1, + _In_opt_ PVOID Parameter2, + _In_opt_ PVOID Context + ); + +INT_PTR CALLBACK PhpTokenClaimsPageProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +INT_PTR CALLBACK PhpTokenAttributesPageProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +VOID PhShowTokenProperties( + _In_ HWND ParentWindowHandle, + _In_ PPH_OPEN_OBJECT OpenObject, + _In_opt_ PVOID Context, + _In_opt_ PWSTR Title + ) +{ + PROPSHEETHEADER propSheetHeader = { sizeof(propSheetHeader) }; + HPROPSHEETPAGE pages[1]; + + propSheetHeader.dwFlags = + PSH_NOAPPLYNOW | + PSH_NOCONTEXTHELP | + PSH_PROPTITLE; + propSheetHeader.hwndParent = ParentWindowHandle; + propSheetHeader.pszCaption = Title ? Title : L"Token"; + propSheetHeader.nPages = 1; + propSheetHeader.nStartPage = 0; + propSheetHeader.phpage = pages; + + pages[0] = PhCreateTokenPage(OpenObject, Context, NULL); + + PhModalPropertySheet(&propSheetHeader); +} + +HPROPSHEETPAGE PhCreateTokenPage( + _In_ PPH_OPEN_OBJECT OpenObject, + _In_opt_ PVOID Context, + _In_opt_ DLGPROC HookProc + ) +{ + HPROPSHEETPAGE propSheetPageHandle; + PROPSHEETPAGE propSheetPage; + PTOKEN_PAGE_CONTEXT tokenPageContext; + + tokenPageContext = PhCreateAlloc(sizeof(TOKEN_PAGE_CONTEXT)); + memset(tokenPageContext, 0, sizeof(TOKEN_PAGE_CONTEXT)); + tokenPageContext->OpenObject = OpenObject; + tokenPageContext->Context = Context; + tokenPageContext->HookProc = HookProc; + + memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); + propSheetPage.dwSize = sizeof(PROPSHEETPAGE); + propSheetPage.dwFlags = PSP_USECALLBACK; + propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_OBJTOKEN); + propSheetPage.pfnDlgProc = PhpTokenPageProc; + propSheetPage.lParam = (LPARAM)tokenPageContext; + propSheetPage.pfnCallback = PhpTokenPropPageProc; + + propSheetPageHandle = CreatePropertySheetPage(&propSheetPage); + // CreatePropertySheetPage would have sent PSPCB_ADDREF (below), + // which would have added a reference. + PhDereferenceObject(tokenPageContext); + + return propSheetPageHandle; +} + +INT CALLBACK PhpTokenPropPageProc( + _In_ HWND hwnd, + _In_ UINT uMsg, + _In_ LPPROPSHEETPAGE ppsp + ) +{ + PTOKEN_PAGE_CONTEXT tokenPageContext; + + tokenPageContext = (PTOKEN_PAGE_CONTEXT)ppsp->lParam; + + if (uMsg == PSPCB_ADDREF) + { + PhReferenceObject(tokenPageContext); + } + else if (uMsg == PSPCB_RELEASE) + { + PhDereferenceObject(tokenPageContext); + } + + return 1; +} + +PPH_STRING PhGetGroupAttributesString( + _In_ ULONG Attributes + ) +{ + PWSTR baseString; + PPH_STRING string; + + if (Attributes & SE_GROUP_INTEGRITY) + { + if (Attributes & SE_GROUP_INTEGRITY_ENABLED) + return PhCreateString(L"Integrity"); + else + return PhCreateString(L"Integrity (disabled)"); + } + + if (Attributes & SE_GROUP_LOGON_ID) + baseString = L"Logon ID"; + else if (Attributes & SE_GROUP_MANDATORY) + baseString = L"Mandatory"; + else if (Attributes & SE_GROUP_OWNER) + baseString = L"Owner"; + else if (Attributes & SE_GROUP_RESOURCE) + baseString = L"Resource"; + else if (Attributes & SE_GROUP_USE_FOR_DENY_ONLY) + baseString = L"Use for deny only"; + else + baseString = NULL; + + if (!baseString) + { + if (Attributes & SE_GROUP_ENABLED_BY_DEFAULT) + return PhCreateString(L"Default enabled"); + else if (Attributes & SE_GROUP_ENABLED) + return PhReferenceEmptyString(); + else + return PhCreateString(L"Disabled"); + } + + if (Attributes & SE_GROUP_ENABLED_BY_DEFAULT) + string = PhConcatStrings2(baseString, L" (default enabled)"); + else if (Attributes & SE_GROUP_ENABLED) + string = PhCreateString(baseString); + else + string = PhConcatStrings2(baseString, L" (disabled)"); + + return string; +} + +COLORREF PhGetGroupAttributesColor( + _In_ ULONG Attributes + ) +{ + if (Attributes & SE_GROUP_INTEGRITY) + { + if (Attributes & SE_GROUP_INTEGRITY_ENABLED) + return RGB(0xe0, 0xf0, 0xe0); + else + return GetSysColor(COLOR_WINDOW); + } + + if (Attributes & SE_GROUP_ENABLED_BY_DEFAULT) + return RGB(0xe0, 0xf0, 0xe0); + else if (Attributes & SE_GROUP_ENABLED) + return GetSysColor(COLOR_WINDOW); + else + return RGB(0xf0, 0xe0, 0xe0); +} + +static COLORREF NTAPI PhpTokenGroupColorFunction( + _In_ INT Index, + _In_ PVOID Param, + _In_opt_ PVOID Context + ) +{ + PSID_AND_ATTRIBUTES sidAndAttributes = Param; + + return PhGetGroupAttributesColor(sidAndAttributes->Attributes); +} + +PWSTR PhGetPrivilegeAttributesString( + _In_ ULONG Attributes + ) +{ + if (Attributes & SE_PRIVILEGE_ENABLED_BY_DEFAULT) + return L"Default Enabled"; + else if (Attributes & SE_PRIVILEGE_ENABLED) + return L"Enabled"; + else + return L"Disabled"; +} + +COLORREF PhGetPrivilegeAttributesColor( + _In_ ULONG Attributes + ) +{ + if (Attributes & SE_PRIVILEGE_ENABLED_BY_DEFAULT) + return RGB(0xc0, 0xf0, 0xc0); + else if (Attributes & SE_PRIVILEGE_ENABLED) + return RGB(0xe0, 0xf0, 0xe0); + else + return RGB(0xf0, 0xe0, 0xe0); +} + +static COLORREF NTAPI PhpTokenPrivilegeColorFunction( + _In_ INT Index, + _In_ PVOID Param, + _In_opt_ PVOID Context + ) +{ + PLUID_AND_ATTRIBUTES luidAndAttributes = Param; + + return PhGetPrivilegeAttributesColor(luidAndAttributes->Attributes); +} + +PWSTR PhGetElevationTypeString( + _In_ TOKEN_ELEVATION_TYPE ElevationType + ) +{ + switch (ElevationType) + { + case TokenElevationTypeFull: + return L"Yes"; + case TokenElevationTypeLimited: + return L"No"; + default: + return L"N/A"; + } +} + +BOOLEAN PhpUpdateTokenGroups( + _In_ HWND hwndDlg, + _In_ PTOKEN_PAGE_CONTEXT TokenPageContext, + _In_ HWND GroupsLv, + _In_ HANDLE TokenHandle + ) +{ + PTOKEN_GROUPS groups; + ULONG i; + + if (!NT_SUCCESS(PhGetTokenGroups(TokenHandle, &groups))) + return FALSE; + + ExtendedListView_SetRedraw(GroupsLv, FALSE); + + ListView_DeleteAllItems(GroupsLv); + + for (i = 0; i < groups->GroupCount; i++) + { + INT lvItemIndex; + PPH_STRING fullName; + PPH_STRING attributesString; + + if (!(fullName = PhGetSidFullName(groups->Groups[i].Sid, TRUE, NULL))) + fullName = PhSidToStringSid(groups->Groups[i].Sid); + + if (fullName) + { + lvItemIndex = PhAddListViewItem(GroupsLv, MAXINT, fullName->Buffer, &groups->Groups[i]); + attributesString = PhGetGroupAttributesString(groups->Groups[i].Attributes); + PhSetListViewSubItem(GroupsLv, lvItemIndex, 1, attributesString->Buffer); + + PhDereferenceObject(attributesString); + PhDereferenceObject(fullName); + } + } + + ExtendedListView_SortItems(GroupsLv); + + ExtendedListView_SetRedraw(GroupsLv, TRUE); + + if (TokenPageContext->Groups) + PhFree(TokenPageContext->Groups); + + TokenPageContext->Groups = groups; + + return TRUE; +} + +FORCEINLINE PTOKEN_PAGE_CONTEXT PhpTokenPageHeader( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + return (PTOKEN_PAGE_CONTEXT)PhpGenericPropertyPageHeader( + hwndDlg, uMsg, wParam, lParam, L"TokenPageContext"); +} + +INT_PTR CALLBACK PhpTokenPageProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + PTOKEN_PAGE_CONTEXT tokenPageContext; + + tokenPageContext = PhpTokenPageHeader(hwndDlg, uMsg, wParam, lParam); + + if (!tokenPageContext) + return FALSE; + + if (tokenPageContext->HookProc) + { + if (tokenPageContext->HookProc(hwndDlg, uMsg, wParam, lParam)) + return TRUE; + } + + switch (uMsg) + { + case WM_INITDIALOG: + { + HWND groupsLv; + HWND privilegesLv; + HANDLE tokenHandle; + + tokenPageContext->GroupsListViewHandle = groupsLv = GetDlgItem(hwndDlg, IDC_GROUPS); + tokenPageContext->PrivilegesListViewHandle = privilegesLv = GetDlgItem(hwndDlg, IDC_PRIVILEGES); + PhSetListViewStyle(groupsLv, FALSE, TRUE); + PhSetListViewStyle(privilegesLv, FALSE, TRUE); + PhSetControlTheme(groupsLv, L"explorer"); + PhSetControlTheme(privilegesLv, L"explorer"); + + tokenPageContext->HSplitterContext = PhInitializeHSplitter( + hwndDlg, + tokenPageContext->GroupsListViewHandle, + tokenPageContext->PrivilegesListViewHandle + ); + + PhAddListViewColumn(groupsLv, 0, 0, 0, LVCFMT_LEFT, 160, L"Name"); + PhAddListViewColumn(groupsLv, 1, 1, 1, LVCFMT_LEFT, 200, L"Flags"); + + PhAddListViewColumn(privilegesLv, 0, 0, 0, LVCFMT_LEFT, 100, L"Name"); + PhAddListViewColumn(privilegesLv, 1, 1, 1, LVCFMT_LEFT, 100, L"Status"); + PhAddListViewColumn(privilegesLv, 2, 2, 2, LVCFMT_LEFT, 170, L"Description"); + + PhSetExtendedListView(groupsLv); + ExtendedListView_SetItemColorFunction(groupsLv, PhpTokenGroupColorFunction); + PhSetExtendedListView(privilegesLv); + ExtendedListView_SetItemColorFunction(privilegesLv, PhpTokenPrivilegeColorFunction); + + SetDlgItemText(hwndDlg, IDC_USER, L"Unknown"); + SetDlgItemText(hwndDlg, IDC_USERSID, L"Unknown"); + SetDlgItemText(hwndDlg, IDC_APPCONTAINERSID, L"Unknown"); + + if (!WINDOWS_HAS_UAC) + ShowWindow(GetDlgItem(hwndDlg, IDC_INTEGRITY), SW_HIDE); + + if (NT_SUCCESS(tokenPageContext->OpenObject( + &tokenHandle, + TOKEN_QUERY, + tokenPageContext->Context + ))) + { + PTOKEN_USER tokenUser; + PPH_STRING fullUserName; + PPH_STRING stringUserSid; + ULONG sessionId; + TOKEN_ELEVATION_TYPE elevationType; + BOOLEAN isVirtualizationAllowed; + BOOLEAN isVirtualizationEnabled; + PTOKEN_APPCONTAINER_INFORMATION appContainerInfo; + PPH_STRING appContainerSid; + ULONG i; + + if (NT_SUCCESS(PhGetTokenUser(tokenHandle, &tokenUser))) + { + if (fullUserName = PhGetSidFullName(tokenUser->User.Sid, TRUE, NULL)) + { + SetDlgItemText(hwndDlg, IDC_USER, fullUserName->Buffer); + PhDereferenceObject(fullUserName); + } + + if (stringUserSid = PhSidToStringSid(tokenUser->User.Sid)) + { + SetDlgItemText(hwndDlg, IDC_USERSID, stringUserSid->Buffer); + PhDereferenceObject(stringUserSid); + } + + PhFree(tokenUser); + } + + if (NT_SUCCESS(PhGetTokenSessionId(tokenHandle, &sessionId))) + SetDlgItemInt(hwndDlg, IDC_SESSIONID, sessionId, FALSE); + + if (WINDOWS_HAS_UAC) + { + if (NT_SUCCESS(PhGetTokenElevationType(tokenHandle, &elevationType))) + SetDlgItemText(hwndDlg, IDC_ELEVATED, PhGetElevationTypeString(elevationType)); + + if (NT_SUCCESS(PhGetTokenIsVirtualizationAllowed(tokenHandle, &isVirtualizationAllowed))) + { + if (isVirtualizationAllowed) + { + if (NT_SUCCESS(PhGetTokenIsVirtualizationEnabled(tokenHandle, &isVirtualizationEnabled))) + { + SetDlgItemText( + hwndDlg, + IDC_VIRTUALIZED, + isVirtualizationEnabled ? L"Yes" : L"No" + ); + } + } + else + { + SetDlgItemText(hwndDlg, IDC_VIRTUALIZED, L"Not allowed"); + } + } + } + else + { + SetDlgItemText(hwndDlg, IDC_ELEVATED, L"N/A"); + SetDlgItemText(hwndDlg, IDC_VIRTUALIZED, L"N/A"); + } + + if (WINDOWS_HAS_IMMERSIVE) + { + appContainerSid = NULL; + + if (NT_SUCCESS(PhQueryTokenVariableSize(tokenHandle, TokenAppContainerSid, &appContainerInfo))) + { + if (appContainerInfo->TokenAppContainer) + appContainerSid = PhSidToStringSid(appContainerInfo->TokenAppContainer); + + PhFree(appContainerInfo); + } + + if (appContainerSid) + { + SetDlgItemText(hwndDlg, IDC_APPCONTAINERSID, appContainerSid->Buffer); + PhDereferenceObject(appContainerSid); + } + else + { + SetDlgItemText(hwndDlg, IDC_APPCONTAINERSID, L"N/A"); + } + } + else + { + SetDlgItemText(hwndDlg, IDC_APPCONTAINERSID, L"N/A"); + } + + // Groups + PhpUpdateTokenGroups(hwndDlg, tokenPageContext, groupsLv, tokenHandle); + + // Privileges + if (NT_SUCCESS(PhGetTokenPrivileges(tokenHandle, &tokenPageContext->Privileges))) + { + for (i = 0; i < tokenPageContext->Privileges->PrivilegeCount; i++) + { + INT lvItemIndex; + PPH_STRING privilegeName; + PPH_STRING privilegeDisplayName; + + if (PhLookupPrivilegeName( + &tokenPageContext->Privileges->Privileges[i].Luid, + &privilegeName + )) + { + privilegeDisplayName = NULL; + PhLookupPrivilegeDisplayName(&privilegeName->sr, &privilegeDisplayName); + + // Name + lvItemIndex = PhAddListViewItem(privilegesLv, MAXINT, privilegeName->Buffer, + &tokenPageContext->Privileges->Privileges[i]); + // Status + PhSetListViewSubItem(privilegesLv, lvItemIndex, 1, + PhGetPrivilegeAttributesString( + tokenPageContext->Privileges->Privileges[i].Attributes)); + // Description + PhSetListViewSubItem(privilegesLv, lvItemIndex, 2, + PhGetString(privilegeDisplayName)); + + if (privilegeDisplayName) PhDereferenceObject(privilegeDisplayName); + PhDereferenceObject(privilegeName); + } + } + + ExtendedListView_SortItems(privilegesLv); + } + + NtClose(tokenHandle); + } + } + break; + case WM_DESTROY: + { + if (tokenPageContext->Groups) PhFree(tokenPageContext->Groups); + if (tokenPageContext->Privileges) PhFree(tokenPageContext->Privileges); + if (tokenPageContext->HSplitterContext) PhDeleteHSplitter(tokenPageContext->HSplitterContext); + } + break; + case WM_COMMAND: + { + switch (LOWORD(wParam)) + { + case ID_PRIVILEGE_ENABLE: + case ID_PRIVILEGE_DISABLE: + case ID_PRIVILEGE_REMOVE: + { + NTSTATUS status; + PLUID_AND_ATTRIBUTES *privileges; + ULONG numberOfPrivileges; + HANDLE tokenHandle; + ULONG i; + + if (LOWORD(wParam) == ID_PRIVILEGE_REMOVE) + { + if (!PhShowConfirmMessage( + hwndDlg, + L"remove", + L"the selected privilege(s)", + L"Removing privileges may reduce the functionality of the process, " + L"and is permanent for the lifetime of the process.", + FALSE + )) + break; + } + + PhGetSelectedListViewItemParams( + tokenPageContext->PrivilegesListViewHandle, + &privileges, + &numberOfPrivileges + ); + + status = tokenPageContext->OpenObject( + &tokenHandle, + TOKEN_ADJUST_PRIVILEGES, + tokenPageContext->Context + ); + + if (NT_SUCCESS(status)) + { + ExtendedListView_SetRedraw(tokenPageContext->PrivilegesListViewHandle, FALSE); + + for (i = 0; i < numberOfPrivileges; i++) + { + PPH_STRING privilegeName = NULL; + ULONG newAttributes; + + PhLookupPrivilegeName(&privileges[i]->Luid, &privilegeName); + PH_AUTO(privilegeName); + + switch (LOWORD(wParam)) + { + case ID_PRIVILEGE_ENABLE: + newAttributes = SE_PRIVILEGE_ENABLED; + break; + case ID_PRIVILEGE_DISABLE: + newAttributes = 0; + break; + case ID_PRIVILEGE_REMOVE: + newAttributes = SE_PRIVILEGE_REMOVED; + break; + } + + // Privileges which are enabled by default cannot be + // modified except to remove them. + + if ( + privileges[i]->Attributes & SE_PRIVILEGE_ENABLED_BY_DEFAULT && + LOWORD(wParam) != ID_PRIVILEGE_REMOVE + ) + { + if (LOWORD(wParam) == ID_PRIVILEGE_DISABLE) + { + if (!PhShowContinueStatus( + hwndDlg, + PhaConcatStrings2(L"Unable to disable ", privilegeName->Buffer)->Buffer, + STATUS_UNSUCCESSFUL, + 0 + )) + break; + } + + continue; + } + + if (PhSetTokenPrivilege( + tokenHandle, + NULL, + &privileges[i]->Luid, + newAttributes + )) + { + INT lvItemIndex = PhFindListViewItemByParam( + tokenPageContext->PrivilegesListViewHandle, + -1, + privileges[i] + ); + + if (LOWORD(wParam) != ID_PRIVILEGE_REMOVE) + { + // Refresh the status text (and background + // color). + privileges[i]->Attributes = newAttributes; + PhSetListViewSubItem( + tokenPageContext->PrivilegesListViewHandle, + lvItemIndex, + 1, + PhGetPrivilegeAttributesString(newAttributes) + ); + } + else + { + ListView_DeleteItem( + tokenPageContext->PrivilegesListViewHandle, + lvItemIndex + ); + } + } + else + { + PWSTR action = L"set"; + + switch (LOWORD(wParam)) + { + case ID_PRIVILEGE_ENABLE: + action = L"enable"; + break; + case ID_PRIVILEGE_DISABLE: + action = L"disable"; + break; + case ID_PRIVILEGE_REMOVE: + action = L"remove"; + break; + } + + if (!PhShowContinueStatus( + hwndDlg, + PhaFormatString(L"Unable to %s %s", action, privilegeName->Buffer)->Buffer, + STATUS_UNSUCCESSFUL, + 0 + )) + break; + } + } + + ExtendedListView_SetRedraw(tokenPageContext->PrivilegesListViewHandle, TRUE); + + NtClose(tokenHandle); + } + else + { + PhShowStatus(hwndDlg, L"Unable to open the token", status, 0); + } + + PhFree(privileges); + + ExtendedListView_SortItems(tokenPageContext->PrivilegesListViewHandle); + } + break; + case ID_PRIVILEGE_COPY: + { + PhCopyListView(tokenPageContext->PrivilegesListViewHandle); + } + break; + case IDC_INTEGRITY: + { + NTSTATUS status; + RECT rect; + PPH_EMENU menu; + HANDLE tokenHandle; + MANDATORY_LEVEL integrityLevel; + PPH_EMENU_ITEM selectedItem; + + GetWindowRect(GetDlgItem(hwndDlg, IDC_INTEGRITY), &rect); + + menu = PhCreateEMenu(); + + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, MandatoryLevelSecureProcess, L"Protected", NULL, NULL), -1); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, MandatoryLevelSystem, L"System", NULL, NULL), -1); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, MandatoryLevelHigh, L"High", NULL, NULL), -1); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, MandatoryLevelMedium, L"Medium", NULL, NULL), -1); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, MandatoryLevelLow, L"Low", NULL, NULL), -1); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, MandatoryLevelUntrusted, L"Untrusted", NULL, NULL), -1); + + integrityLevel = -1; + + // Put a radio check on the menu item that corresponds with the current integrity level. + // Also disable menu items which correspond to higher integrity levels since + // NtSetInformationToken doesn't allow integrity levels to be raised. + if (NT_SUCCESS(tokenPageContext->OpenObject( + &tokenHandle, + TOKEN_QUERY, + tokenPageContext->Context + ))) + { + if (NT_SUCCESS(PhGetTokenIntegrityLevel( + tokenHandle, + &integrityLevel, + NULL + ))) + { + ULONG i; + + for (i = 0; i < menu->Items->Count; i++) + { + PPH_EMENU_ITEM menuItem = menu->Items->Items[i]; + + if (menuItem->Id == integrityLevel) + { + menuItem->Flags |= PH_EMENU_CHECKED | PH_EMENU_RADIOCHECK; + } + else if (menuItem->Id > (ULONG)integrityLevel) + { + menuItem->Flags |= PH_EMENU_DISABLED; + } + } + } + + NtClose(tokenHandle); + } + + selectedItem = PhShowEMenu( + menu, + hwndDlg, + PH_EMENU_SHOW_LEFTRIGHT, + PH_ALIGN_LEFT | PH_ALIGN_TOP, + rect.left, + rect.bottom + ); + + if (selectedItem && selectedItem->Id != integrityLevel) + { + if (PhShowConfirmMessage( + hwndDlg, + L"set", + L"the integrity level", + L"Once lowered, the integrity level of the token cannot be raised again.", + FALSE + )) + { + if (NT_SUCCESS(status = tokenPageContext->OpenObject( + &tokenHandle, + TOKEN_QUERY | TOKEN_ADJUST_DEFAULT, + tokenPageContext->Context + ))) + { + static SID_IDENTIFIER_AUTHORITY mandatoryLabelAuthority = SECURITY_MANDATORY_LABEL_AUTHORITY; + + UCHAR newSidBuffer[FIELD_OFFSET(SID, SubAuthority) + sizeof(ULONG)]; + PSID newSid; + TOKEN_MANDATORY_LABEL mandatoryLabel; + + newSid = (PSID)newSidBuffer; + RtlInitializeSid(newSid, &mandatoryLabelAuthority, 1); + *RtlSubAuthoritySid(newSid, 0) = MANDATORY_LEVEL_TO_MANDATORY_RID(selectedItem->Id); + mandatoryLabel.Label.Sid = newSid; + mandatoryLabel.Label.Attributes = SE_GROUP_INTEGRITY; + + status = NtSetInformationToken( + tokenHandle, + TokenIntegrityLevel, + &mandatoryLabel, + sizeof(TOKEN_MANDATORY_LABEL) + ); + + if (NT_SUCCESS(status)) + PhpUpdateTokenGroups(hwndDlg, tokenPageContext, GetDlgItem(hwndDlg, IDC_GROUPS), tokenHandle); + + NtClose(tokenHandle); + } + + if (!NT_SUCCESS(status)) + PhShowStatus(hwndDlg, L"Unable to set the integrity level", status, 0); + } + } + + PhDestroyEMenu(menu); + } + break; + case IDC_ADVANCED: + { + PhpShowTokenAdvancedProperties(hwndDlg, tokenPageContext); + } + break; + } + } + break; + case WM_NOTIFY: + { + LPNMHDR header = (LPNMHDR)lParam; + + switch (header->code) + { + case PSN_QUERYINITIALFOCUS: + { + if (ListView_GetItemCount(tokenPageContext->GroupsListViewHandle) != 0) + { + ListView_SetColumnWidth(tokenPageContext->GroupsListViewHandle, 0, LVSCW_AUTOSIZE); + ExtendedListView_SetColumnWidth(tokenPageContext->GroupsListViewHandle, 1, ELVSCW_AUTOSIZE_REMAININGSPACE); + } + + if (ListView_GetItemCount(tokenPageContext->PrivilegesListViewHandle) != 0) + { + ListView_SetColumnWidth(tokenPageContext->PrivilegesListViewHandle, 0, LVSCW_AUTOSIZE); + ListView_SetColumnWidth(tokenPageContext->PrivilegesListViewHandle, 1, LVSCW_AUTOSIZE); + ExtendedListView_SetColumnWidth(tokenPageContext->PrivilegesListViewHandle, 2, ELVSCW_AUTOSIZE_REMAININGSPACE); + } + + SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, (LONG_PTR)GetDlgItem(hwndDlg, IDC_SESSIONID)); + return TRUE; + } + break; + } + + PhHandleListViewNotifyBehaviors(lParam, tokenPageContext->GroupsListViewHandle, PH_LIST_VIEW_DEFAULT_1_BEHAVIORS); + PhHandleListViewNotifyBehaviors(lParam, tokenPageContext->PrivilegesListViewHandle, PH_LIST_VIEW_DEFAULT_1_BEHAVIORS); + } + break; + case WM_CONTEXTMENU: + { + if ((HWND)wParam == tokenPageContext->PrivilegesListViewHandle) + { + POINT point; + + point.x = (SHORT)LOWORD(lParam); + point.y = (SHORT)HIWORD(lParam); + + if (point.x == -1 && point.y == -1) + PhGetListViewContextMenuPoint((HWND)wParam, &point); + + if (ListView_GetSelectedCount(tokenPageContext->PrivilegesListViewHandle) != 0) + { + PPH_EMENU menu; + + menu = PhCreateEMenu(); + PhLoadResourceEMenuItem(menu, PhInstanceHandle, MAKEINTRESOURCE(IDR_PRIVILEGE), 0); + PhShowEMenu(menu, hwndDlg, PH_EMENU_SHOW_SEND_COMMAND | PH_EMENU_SHOW_LEFTRIGHT, + PH_ALIGN_LEFT | PH_ALIGN_TOP, point.x, point.y); + PhDestroyEMenu(menu); + } + } + } + break; + case WM_SIZE: + PhHSplitterHandleWmSize(tokenPageContext->HSplitterContext, LOWORD(lParam), HIWORD(lParam)); + break; + case WM_LBUTTONDOWN: + PhHSplitterHandleLButtonDown(tokenPageContext->HSplitterContext, hwndDlg, wParam, lParam); + break; + case WM_LBUTTONUP: + PhHSplitterHandleLButtonUp(tokenPageContext->HSplitterContext, hwndDlg, wParam, lParam); + break; + case WM_MOUSEMOVE: + PhHSplitterHandleMouseMove(tokenPageContext->HSplitterContext, hwndDlg, wParam, lParam); + break; + } + + REFLECT_MESSAGE_DLG(hwndDlg, tokenPageContext->GroupsListViewHandle, uMsg, wParam, lParam); + REFLECT_MESSAGE_DLG(hwndDlg, tokenPageContext->PrivilegesListViewHandle, uMsg, wParam, lParam); + + return FALSE; +} + +VOID PhpShowTokenAdvancedProperties( + _In_ HWND ParentWindowHandle, + _In_ PTOKEN_PAGE_CONTEXT Context + ) +{ + PROPSHEETHEADER propSheetHeader = { sizeof(propSheetHeader) }; + HPROPSHEETPAGE pages[6]; + PROPSHEETPAGE page; + ULONG numberOfPages; + PH_STD_OBJECT_SECURITY stdObjectSecurity; + PPH_ACCESS_ENTRY accessEntries; + ULONG numberOfAccessEntries; + + propSheetHeader.dwFlags = + PSH_NOAPPLYNOW | + PSH_NOCONTEXTHELP | + PSH_PROPTITLE; + propSheetHeader.hwndParent = ParentWindowHandle; + propSheetHeader.pszCaption = L"Token"; + propSheetHeader.nStartPage = 0; + propSheetHeader.phpage = pages; + + numberOfPages = 0; + + // General + + memset(&page, 0, sizeof(PROPSHEETPAGE)); + page.dwSize = sizeof(PROPSHEETPAGE); + page.pszTemplate = MAKEINTRESOURCE(IDD_TOKGENERAL); + page.pfnDlgProc = PhpTokenGeneralPageProc; + page.lParam = (LPARAM)Context; + pages[numberOfPages++] = CreatePropertySheetPage(&page); + + // Advanced + + memset(&page, 0, sizeof(PROPSHEETPAGE)); + page.dwSize = sizeof(PROPSHEETPAGE); + page.pszTemplate = MAKEINTRESOURCE(IDD_TOKADVANCED); + page.pfnDlgProc = PhpTokenAdvancedPageProc; + page.lParam = (LPARAM)Context; + pages[numberOfPages++] = CreatePropertySheetPage(&page); + + if (WindowsVersion >= WINDOWS_8) + { + // Capabilities + + memset(&page, 0, sizeof(PROPSHEETPAGE)); + page.dwSize = sizeof(PROPSHEETPAGE); + page.pszTemplate = MAKEINTRESOURCE(IDD_TOKCAPABILITIES); + page.pfnDlgProc = PhpTokenCapabilitiesPageProc; + page.lParam = (LPARAM)Context; + pages[numberOfPages++] = CreatePropertySheetPage(&page); + + // Claims + + memset(&page, 0, sizeof(PROPSHEETPAGE)); + page.dwSize = sizeof(PROPSHEETPAGE); + page.dwFlags = PSP_USETITLE; + page.pszTemplate = MAKEINTRESOURCE(IDD_TOKATTRIBUTES); + page.pszTitle = L"Claims"; + page.pfnDlgProc = PhpTokenClaimsPageProc; + page.lParam = (LPARAM)Context; + pages[numberOfPages++] = CreatePropertySheetPage(&page); + + // (Token) Attributes + + memset(&page, 0, sizeof(PROPSHEETPAGE)); + page.dwSize = sizeof(PROPSHEETPAGE); + page.dwFlags = PSP_USETITLE; + page.pszTemplate = MAKEINTRESOURCE(IDD_TOKATTRIBUTES); + page.pszTitle = L"Attributes"; + page.pfnDlgProc = PhpTokenAttributesPageProc; + page.lParam = (LPARAM)Context; + pages[numberOfPages++] = CreatePropertySheetPage(&page); + } + + // Security + + stdObjectSecurity.OpenObject = Context->OpenObject; + stdObjectSecurity.ObjectType = L"Token"; + stdObjectSecurity.Context = Context->Context; + + if (PhGetAccessEntries(L"Token", &accessEntries, &numberOfAccessEntries)) + { + pages[numberOfPages++] = PhCreateSecurityPage( + L"Token", + PhStdGetObjectSecurity, + PhStdSetObjectSecurity, + &stdObjectSecurity, + accessEntries, + numberOfAccessEntries + ); + PhFree(accessEntries); + } + + propSheetHeader.nPages = numberOfPages; + PhModalPropertySheet(&propSheetHeader); +} + +static NTSTATUS PhpOpenLinkedToken( + _Out_ PHANDLE Handle, + _In_ ACCESS_MASK DesiredAccess, + _In_opt_ PVOID Context + ) +{ + return PhGetTokenLinkedToken((HANDLE)Context, Handle); +} + +INT_PTR CALLBACK PhpTokenGeneralPageProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + PTOKEN_PAGE_CONTEXT tokenPageContext; + + tokenPageContext = PhpTokenPageHeader(hwndDlg, uMsg, wParam, lParam); + + if (!tokenPageContext) + return FALSE; + + switch (uMsg) + { + case WM_INITDIALOG: + { + HANDLE tokenHandle; + PPH_STRING tokenUserName = NULL; + PPH_STRING tokenUserSid = NULL; + PPH_STRING tokenOwnerName = NULL; + PPH_STRING tokenPrimaryGroupName = NULL; + ULONG tokenSessionId = -1; + PWSTR tokenElevated = L"N/A"; + BOOLEAN hasLinkedToken = FALSE; + PWSTR tokenVirtualization = L"N/A"; + WCHAR tokenSourceName[TOKEN_SOURCE_LENGTH + 1] = L"Unknown"; + WCHAR tokenSourceLuid[PH_PTR_STR_LEN_1] = L"Unknown"; + + // HACK + PhCenterWindow(GetParent(hwndDlg), GetParent(GetParent(hwndDlg))); + + if (NT_SUCCESS(tokenPageContext->OpenObject( + &tokenHandle, + TOKEN_QUERY, + tokenPageContext->Context + ))) + { + PTOKEN_USER tokenUser; + PTOKEN_OWNER tokenOwner; + PTOKEN_PRIMARY_GROUP tokenPrimaryGroup; + TOKEN_ELEVATION_TYPE elevationType; + BOOLEAN isVirtualizationAllowed; + BOOLEAN isVirtualizationEnabled; + + if (NT_SUCCESS(PhGetTokenUser(tokenHandle, &tokenUser))) + { + tokenUserName = PH_AUTO(PhGetSidFullName(tokenUser->User.Sid, TRUE, NULL)); + tokenUserSid = PH_AUTO(PhSidToStringSid(tokenUser->User.Sid)); + + PhFree(tokenUser); + } + + if (NT_SUCCESS(PhGetTokenOwner(tokenHandle, &tokenOwner))) + { + tokenOwnerName = PH_AUTO(PhGetSidFullName(tokenOwner->Owner, TRUE, NULL)); + PhFree(tokenOwner); + } + + if (NT_SUCCESS(PhGetTokenPrimaryGroup(tokenHandle, &tokenPrimaryGroup))) + { + tokenPrimaryGroupName = PH_AUTO(PhGetSidFullName( + tokenPrimaryGroup->PrimaryGroup, TRUE, NULL)); + PhFree(tokenPrimaryGroup); + } + + PhGetTokenSessionId(tokenHandle, &tokenSessionId); + + if (WINDOWS_HAS_UAC) + { + if (NT_SUCCESS(PhGetTokenElevationType(tokenHandle, &elevationType))) + { + tokenElevated = PhGetElevationTypeString(elevationType); + hasLinkedToken = elevationType != TokenElevationTypeDefault; + } + + if (NT_SUCCESS(PhGetTokenIsVirtualizationAllowed(tokenHandle, &isVirtualizationAllowed))) + { + if (isVirtualizationAllowed) + { + if (NT_SUCCESS(PhGetTokenIsVirtualizationEnabled(tokenHandle, &isVirtualizationEnabled))) + { + tokenVirtualization = isVirtualizationEnabled ? L"Enabled" : L"Disabled"; + } + } + else + { + tokenVirtualization = L"Not Allowed"; + } + } + } + + NtClose(tokenHandle); + } + + if (NT_SUCCESS(tokenPageContext->OpenObject( + &tokenHandle, + TOKEN_QUERY_SOURCE, + tokenPageContext->Context + ))) + { + TOKEN_SOURCE tokenSource; + + if (NT_SUCCESS(PhGetTokenSource(tokenHandle, &tokenSource))) + { + PhCopyStringZFromBytes( + tokenSource.SourceName, + TOKEN_SOURCE_LENGTH, + tokenSourceName, + sizeof(tokenSourceName) / 2, + NULL + ); + + PhPrintPointer(tokenSourceLuid, UlongToPtr(tokenSource.SourceIdentifier.LowPart)); + } + + NtClose(tokenHandle); + } + + SetDlgItemText(hwndDlg, IDC_USER, PhGetStringOrDefault(tokenUserName, L"Unknown")); + SetDlgItemText(hwndDlg, IDC_USERSID, PhGetStringOrDefault(tokenUserSid, L"Unknown")); + SetDlgItemText(hwndDlg, IDC_OWNER, PhGetStringOrDefault(tokenOwnerName, L"Unknown")); + SetDlgItemText(hwndDlg, IDC_PRIMARYGROUP, PhGetStringOrDefault(tokenPrimaryGroupName, L"Unknown")); + + if (tokenSessionId != -1) + SetDlgItemInt(hwndDlg, IDC_SESSIONID, tokenSessionId, FALSE); + else + SetDlgItemText(hwndDlg, IDC_SESSIONID, L"Unknown"); + + SetDlgItemText(hwndDlg, IDC_ELEVATED, tokenElevated); + SetDlgItemText(hwndDlg, IDC_VIRTUALIZATION, tokenVirtualization); + SetDlgItemText(hwndDlg, IDC_SOURCENAME, tokenSourceName); + SetDlgItemText(hwndDlg, IDC_SOURCELUID, tokenSourceLuid); + + if (!hasLinkedToken) + ShowWindow(GetDlgItem(hwndDlg, IDC_LINKEDTOKEN), SW_HIDE); + } + break; + case WM_COMMAND: + { + switch (LOWORD(wParam)) + { + case IDC_LINKEDTOKEN: + { + NTSTATUS status; + HANDLE tokenHandle; + + if (NT_SUCCESS(status = tokenPageContext->OpenObject( + &tokenHandle, + TOKEN_QUERY, + tokenPageContext->Context + ))) + { + PhShowTokenProperties(hwndDlg, PhpOpenLinkedToken, (PVOID)tokenHandle, L"Linked Token"); + NtClose(tokenHandle); + } + else + { + PhShowStatus(hwndDlg, L"Unable to open the token", status, 0); + } + } + break; + } + } + break; + case WM_NOTIFY: + { + LPNMHDR header = (LPNMHDR)lParam; + + switch (header->code) + { + case PSN_QUERYINITIALFOCUS: + { + SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, (LONG_PTR)GetDlgItem(hwndDlg, IDC_LINKEDTOKEN)); + return TRUE; + } + break; + } + } + break; + } + + return FALSE; +} + +INT_PTR CALLBACK PhpTokenAdvancedPageProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + PTOKEN_PAGE_CONTEXT tokenPageContext; + + tokenPageContext = PhpTokenPageHeader(hwndDlg, uMsg, wParam, lParam); + + if (!tokenPageContext) + return FALSE; + + switch (uMsg) + { + case WM_INITDIALOG: + { + HANDLE tokenHandle; + PWSTR tokenType = L"Unknown"; + PWSTR tokenImpersonationLevel = L"Unknown"; + WCHAR tokenLuid[PH_PTR_STR_LEN_1] = L"Unknown"; + WCHAR authenticationLuid[PH_PTR_STR_LEN_1] = L"Unknown"; + PPH_STRING memoryUsed = NULL; + PPH_STRING memoryAvailable = NULL; + + if (NT_SUCCESS(tokenPageContext->OpenObject( + &tokenHandle, + TOKEN_QUERY, + tokenPageContext->Context + ))) + { + TOKEN_STATISTICS statistics; + + if (NT_SUCCESS(PhGetTokenStatistics(tokenHandle, &statistics))) + { + switch (statistics.TokenType) + { + case TokenPrimary: + tokenType = L"Primary"; + break; + case TokenImpersonation: + tokenType = L"Impersonation"; + break; + } + + if (statistics.TokenType == TokenImpersonation) + { + switch (statistics.ImpersonationLevel) + { + case SecurityAnonymous: + tokenImpersonationLevel = L"Anonymous"; + break; + case SecurityIdentification: + tokenImpersonationLevel = L"Identification"; + break; + case SecurityImpersonation: + tokenImpersonationLevel = L"Impersonation"; + break; + case SecurityDelegation: + tokenImpersonationLevel = L"Delegation"; + break; + } + } + else + { + tokenImpersonationLevel = L"N/A"; + } + + PhPrintPointer(tokenLuid, UlongToPtr(statistics.TokenId.LowPart)); + PhPrintPointer(authenticationLuid, UlongToPtr(statistics.AuthenticationId.LowPart)); + + // DynamicCharged contains the number of bytes allocated. + // DynamicAvailable contains the number of bytes free. + memoryUsed = PhaFormatSize(statistics.DynamicCharged - statistics.DynamicAvailable, -1); + memoryAvailable = PhaFormatSize(statistics.DynamicCharged, -1); + } + + NtClose(tokenHandle); + } + + SetDlgItemText(hwndDlg, IDC_TYPE, tokenType); + SetDlgItemText(hwndDlg, IDC_IMPERSONATIONLEVEL, tokenImpersonationLevel); + SetDlgItemText(hwndDlg, IDC_TOKENLUID, tokenLuid); + SetDlgItemText(hwndDlg, IDC_AUTHENTICATIONLUID, authenticationLuid); + SetDlgItemText(hwndDlg, IDC_MEMORYUSED, PhGetStringOrDefault(memoryUsed, L"Unknown")); + SetDlgItemText(hwndDlg, IDC_MEMORYAVAILABLE, PhGetStringOrDefault(memoryAvailable, L"Unknown")); + } + break; + } + + return FALSE; +} + +static COLORREF NTAPI PhpTokenCapabilitiesColorFunction( + _In_ INT Index, + _In_ PVOID Param, + _In_opt_ PVOID Context + ) +{ + PSID_AND_ATTRIBUTES sidAndAttributes = Param; + + return PhGetGroupAttributesColor(sidAndAttributes->Attributes); +} + +INT_PTR CALLBACK PhpTokenCapabilitiesPageProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + PTOKEN_PAGE_CONTEXT tokenPageContext; + HWND lvHandle; + + tokenPageContext = PhpTokenPageHeader(hwndDlg, uMsg, wParam, lParam); + + if (!tokenPageContext) + return FALSE; + + lvHandle = GetDlgItem(hwndDlg, IDC_LIST); + + switch (uMsg) + { + case WM_INITDIALOG: + { + HANDLE tokenHandle; + ULONG i; + + PhSetListViewStyle(lvHandle, FALSE, TRUE); + PhSetControlTheme(lvHandle, L"explorer"); + PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 160, L"Name"); + PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 200, L"Flags"); + PhSetExtendedListView(lvHandle); + ExtendedListView_SetItemColorFunction(lvHandle, PhpTokenCapabilitiesColorFunction); + + if (NT_SUCCESS(tokenPageContext->OpenObject( + &tokenHandle, + TOKEN_QUERY, + tokenPageContext->Context + ))) + { + if (NT_SUCCESS(PhQueryTokenVariableSize(tokenHandle, TokenCapabilities, &tokenPageContext->Capabilities))) + { + for (i = 0; i < tokenPageContext->Capabilities->GroupCount; i++) + { + INT lvItemIndex; + PPH_STRING name; + PPH_STRING attributesString; + + name = PhGetSidFullName(tokenPageContext->Capabilities->Groups[i].Sid, TRUE, NULL); + + if (!name) + name = PhSidToStringSid(tokenPageContext->Capabilities->Groups[i].Sid); + + if (name) + { + lvItemIndex = PhAddListViewItem(lvHandle, MAXINT, name->Buffer, + &tokenPageContext->Capabilities->Groups[i]); + attributesString = PhGetGroupAttributesString( + tokenPageContext->Capabilities->Groups[i].Attributes); + PhSetListViewSubItem(lvHandle, lvItemIndex, 1, attributesString->Buffer); + + PhDereferenceObject(attributesString); + PhDereferenceObject(name); + } + } + + if (ListView_GetItemCount(lvHandle) != 0) + { + ListView_SetColumnWidth(lvHandle, 0, LVSCW_AUTOSIZE); + ExtendedListView_SetColumnWidth(lvHandle, 1, ELVSCW_AUTOSIZE_REMAININGSPACE); + } + + ExtendedListView_SortItems(lvHandle); + } + + NtClose(tokenHandle); + } + + EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); + } + break; + case WM_DESTROY: + { + PhFree(tokenPageContext->Capabilities); + tokenPageContext->Capabilities = NULL; + } + break; + case WM_NOTIFY: + { + PhHandleListViewNotifyBehaviors(lParam, lvHandle, PH_LIST_VIEW_DEFAULT_1_BEHAVIORS); + } + break; + } + + REFLECT_MESSAGE_DLG(hwndDlg, lvHandle, uMsg, wParam, lParam); + + return FALSE; +} + +BOOLEAN NTAPI PhpAttributeTreeNewCallback( + _In_ HWND hwnd, + _In_ PH_TREENEW_MESSAGE Message, + _In_opt_ PVOID Parameter1, + _In_opt_ PVOID Parameter2, + _In_opt_ PVOID Context + ) +{ + PATTRIBUTE_TREE_CONTEXT context; + PATTRIBUTE_NODE node; + + context = Context; + + switch (Message) + { + case TreeNewGetChildren: + { + PPH_TREENEW_GET_CHILDREN getChildren = Parameter1; + + node = (PATTRIBUTE_NODE)getChildren->Node; + + if (!node) + { + getChildren->Children = (PPH_TREENEW_NODE *)context->RootList->Items; + getChildren->NumberOfChildren = context->RootList->Count; + } + else + { + getChildren->Children = (PPH_TREENEW_NODE *)node->Children->Items; + getChildren->NumberOfChildren = node->Children->Count; + } + } + return TRUE; + case TreeNewIsLeaf: + { + PPH_TREENEW_IS_LEAF isLeaf = Parameter1; + + node = (PATTRIBUTE_NODE)isLeaf->Node; + + isLeaf->IsLeaf = node->Children->Count == 0; + } + return TRUE; + case TreeNewGetCellText: + { + PPH_TREENEW_GET_CELL_TEXT getCellText = Parameter1; + + node = (PATTRIBUTE_NODE)getCellText->Node; + + if (getCellText->Id == 0) + getCellText->Text = PhGetStringRef(node->Text); + else + return FALSE; + } + return TRUE; + case TreeNewKeyDown: + { + PPH_TREENEW_KEY_EVENT keyEvent = Parameter1; + + switch (keyEvent->VirtualKey) + { + case 'C': + if (GetKeyState(VK_CONTROL) < 0) + { + PPH_STRING text; + + text = PhGetTreeNewText(hwnd, 0); + PhSetClipboardString(hwnd, &text->sr); + PhDereferenceObject(text); + } + break; + } + } + return TRUE; + } + + return FALSE; +} + +PATTRIBUTE_NODE PhpAddAttributeNode( + _In_ PATTRIBUTE_TREE_CONTEXT Context, + _In_opt_ PATTRIBUTE_NODE Parent, + _In_opt_ _Assume_refs_(1) PPH_STRING Text + ) +{ + PATTRIBUTE_NODE node; + + node = PhAllocate(sizeof(ATTRIBUTE_NODE)); + memset(node, 0, sizeof(ATTRIBUTE_NODE)); + PhInitializeTreeNewNode(&node->Node); + + node->Children = PhCreateList(2); + + PhAddItemList(Context->NodeList, node); + + if (Parent) + PhAddItemList(Parent->Children, node); + else + PhAddItemList(Context->RootList, node); + + PhMoveReference(&node->Text, Text); + + return node; +} + +VOID PhpDestroyAttributeNode( + _In_ PATTRIBUTE_NODE Node + ) +{ + PhDereferenceObject(Node->Children); + PhClearReference(&Node->Text); + PhFree(Node); +} + +VOID PhpInitializeAttributeTreeContext( + _Out_ PATTRIBUTE_TREE_CONTEXT Context, + _In_ HWND TreeNewHandle + ) +{ + PH_TREENEW_VIEW_PARTS parts; + + Context->NodeList = PhCreateList(10); + Context->RootList = PhCreateList(10); + + PhSetControlTheme(TreeNewHandle, L"explorer"); + TreeNew_SetCallback(TreeNewHandle, PhpAttributeTreeNewCallback, Context); + TreeNew_GetViewParts(TreeNewHandle, &parts); + PhAddTreeNewColumnEx2(TreeNewHandle, 0, TRUE, L"Attributes", parts.ClientRect.right - parts.VScrollWidth, PH_ALIGN_LEFT, 0, 0, TN_COLUMN_FLAG_NODPISCALEONADD); +} + +VOID PhpDeleteAttributeTreeContext( + _Inout_ PATTRIBUTE_TREE_CONTEXT Context + ) +{ + ULONG i; + + for (i = 0; i < Context->NodeList->Count; i++) + PhpDestroyAttributeNode(Context->NodeList->Items[i]); + + PhDereferenceObject(Context->NodeList); + PhDereferenceObject(Context->RootList); +} + +PWSTR PhGetSecurityAttributeTypeString( + _In_ USHORT Type + ) +{ + // These types are shared between CLAIM_* and TOKEN_* security attributes. + + switch (Type) + { + case TOKEN_SECURITY_ATTRIBUTE_TYPE_INVALID: + return L"Invalid"; + case TOKEN_SECURITY_ATTRIBUTE_TYPE_INT64: + return L"Int64"; + case TOKEN_SECURITY_ATTRIBUTE_TYPE_UINT64: + return L"UInt64"; + case TOKEN_SECURITY_ATTRIBUTE_TYPE_STRING: + return L"String"; + case TOKEN_SECURITY_ATTRIBUTE_TYPE_FQBN: + return L"FQBN"; + case TOKEN_SECURITY_ATTRIBUTE_TYPE_SID: + return L"SID"; + case TOKEN_SECURITY_ATTRIBUTE_TYPE_BOOLEAN: + return L"Boolean"; + case TOKEN_SECURITY_ATTRIBUTE_TYPE_OCTET_STRING: + return L"Octet string"; + default: + return L"(Unknown)"; + } +} + +PPH_STRING PhGetSecurityAttributeFlagsString( + _In_ ULONG Flags + ) +{ + PH_STRING_BUILDER sb; + + // These flags are shared between CLAIM_* and TOKEN_* security attributes. + + PhInitializeStringBuilder(&sb, 100); + + if (Flags & TOKEN_SECURITY_ATTRIBUTE_MANDATORY) + PhAppendStringBuilder2(&sb, L"Mandatory, "); + if (Flags & TOKEN_SECURITY_ATTRIBUTE_DISABLED) + PhAppendStringBuilder2(&sb, L"Disabled, "); + if (Flags & TOKEN_SECURITY_ATTRIBUTE_DISABLED_BY_DEFAULT) + PhAppendStringBuilder2(&sb, L"Default disabled, "); + if (Flags & TOKEN_SECURITY_ATTRIBUTE_USE_FOR_DENY_ONLY) + PhAppendStringBuilder2(&sb, L"Use for deny only, "); + if (Flags & TOKEN_SECURITY_ATTRIBUTE_VALUE_CASE_SENSITIVE) + PhAppendStringBuilder2(&sb, L"Case-sensitive, "); + if (Flags & TOKEN_SECURITY_ATTRIBUTE_NON_INHERITABLE) + PhAppendStringBuilder2(&sb, L"Non-inheritable, "); + + if (sb.String->Length != 0) + PhRemoveEndStringBuilder(&sb, 2); + else + PhAppendStringBuilder2(&sb, L"(None)"); + + return PhFinalStringBuilderString(&sb); +} + +PPH_STRING PhFormatClaimSecurityAttributeValue( + _In_ PCLAIM_SECURITY_ATTRIBUTE_V1 Attribute, + _In_ ULONG ValueIndex + ) +{ + PH_FORMAT format; + + switch (Attribute->ValueType) + { + case CLAIM_SECURITY_ATTRIBUTE_TYPE_INT64: + PhInitFormatI64D(&format, Attribute->Values.pInt64[ValueIndex]); + return PhFormat(&format, 1, 0); + case CLAIM_SECURITY_ATTRIBUTE_TYPE_UINT64: + PhInitFormatI64U(&format, Attribute->Values.pUint64[ValueIndex]); + return PhFormat(&format, 1, 0); + case CLAIM_SECURITY_ATTRIBUTE_TYPE_STRING: + return PhCreateString(Attribute->Values.ppString[ValueIndex]); + case CLAIM_SECURITY_ATTRIBUTE_TYPE_FQBN: + return PhFormatString(L"Version %I64u: %s", + Attribute->Values.pFqbn[ValueIndex].Version, + Attribute->Values.pFqbn[ValueIndex].Name); + case CLAIM_SECURITY_ATTRIBUTE_TYPE_SID: + { + if (RtlValidSid(Attribute->Values.pOctetString[ValueIndex].pValue)) + { + PPH_STRING name; + + name = PhGetSidFullName(Attribute->Values.pOctetString[ValueIndex].pValue, TRUE, NULL); + + if (name) + return name; + + name = PhSidToStringSid(Attribute->Values.pOctetString[ValueIndex].pValue); + + if (name) + return name; + } + } + return PhCreateString(L"(Invalid SID)"); + case CLAIM_SECURITY_ATTRIBUTE_TYPE_BOOLEAN: + return PhCreateString(Attribute->Values.pInt64[ValueIndex] != 0 ? L"True" : L"False"); + case CLAIM_SECURITY_ATTRIBUTE_TYPE_OCTET_STRING: + return PhCreateString(L"(Octet string)"); + default: + return PhCreateString(L"(Unknown)"); + } +} + +PPH_STRING PhFormatTokenSecurityAttributeValue( + _In_ PTOKEN_SECURITY_ATTRIBUTE_V1 Attribute, + _In_ ULONG ValueIndex + ) +{ + PH_FORMAT format; + + switch (Attribute->ValueType) + { + case TOKEN_SECURITY_ATTRIBUTE_TYPE_INT64: + PhInitFormatI64D(&format, Attribute->Values.pInt64[ValueIndex]); + return PhFormat(&format, 1, 0); + case TOKEN_SECURITY_ATTRIBUTE_TYPE_UINT64: + PhInitFormatI64U(&format, Attribute->Values.pUint64[ValueIndex]); + return PhFormat(&format, 1, 0); + case TOKEN_SECURITY_ATTRIBUTE_TYPE_STRING: + return PhCreateStringFromUnicodeString(&Attribute->Values.pString[ValueIndex]); + case TOKEN_SECURITY_ATTRIBUTE_TYPE_FQBN: + return PhFormatString(L"Version %I64u: %.*s", + Attribute->Values.pFqbn[ValueIndex].Version, + Attribute->Values.pFqbn[ValueIndex].Name.Length / sizeof(WCHAR), + Attribute->Values.pFqbn[ValueIndex].Name.Buffer); + case TOKEN_SECURITY_ATTRIBUTE_TYPE_SID: + { + if (RtlValidSid(Attribute->Values.pOctetString[ValueIndex].pValue)) + { + PPH_STRING name; + + name = PhGetSidFullName(Attribute->Values.pOctetString[ValueIndex].pValue, TRUE, NULL); + + if (name) + return name; + + name = PhSidToStringSid(Attribute->Values.pOctetString[ValueIndex].pValue); + + if (name) + return name; + } + } + return PhCreateString(L"(Invalid SID)"); + case TOKEN_SECURITY_ATTRIBUTE_TYPE_BOOLEAN: + return PhCreateString(Attribute->Values.pInt64[ValueIndex] != 0 ? L"True" : L"False"); + case TOKEN_SECURITY_ATTRIBUTE_TYPE_OCTET_STRING: + return PhCreateString(L"(Octet string)"); + default: + return PhCreateString(L"(Unknown)"); + } +} + +BOOLEAN PhpAddTokenClaimAttributes( + _In_ PTOKEN_PAGE_CONTEXT TokenPageContext, + _In_ HWND tnHandle, + _In_ BOOLEAN DeviceClaims, + _In_ PATTRIBUTE_NODE Parent + ) +{ + HANDLE tokenHandle; + PCLAIM_SECURITY_ATTRIBUTES_INFORMATION info; + ULONG i; + ULONG j; + + if (!NT_SUCCESS(TokenPageContext->OpenObject( + &tokenHandle, + TOKEN_QUERY, + TokenPageContext->Context + ))) + return FALSE; + + if (NT_SUCCESS(PhQueryTokenVariableSize(tokenHandle, DeviceClaims ? TokenDeviceClaimAttributes : TokenUserClaimAttributes, &info))) + { + for (i = 0; i < info->AttributeCount; i++) + { + PCLAIM_SECURITY_ATTRIBUTE_V1 attribute = &info->Attribute.pAttributeV1[i]; + PATTRIBUTE_NODE node; + PPH_STRING temp; + + // Attribute + node = PhpAddAttributeNode(&TokenPageContext->ClaimsTreeContext, Parent, PhCreateString(attribute->Name)); + // Type + PhpAddAttributeNode(&TokenPageContext->ClaimsTreeContext, node, + PhFormatString(L"Type: %s", PhGetSecurityAttributeTypeString(attribute->ValueType))); + // Flags + temp = PhGetSecurityAttributeFlagsString(attribute->Flags); + PhpAddAttributeNode(&TokenPageContext->ClaimsTreeContext, node, + PhFormatString(L"Flags: %s", temp->Buffer)); + PhDereferenceObject(temp); + + // Values + for (j = 0; j < attribute->ValueCount; j++) + { + temp = PhFormatClaimSecurityAttributeValue(attribute, j); + PhpAddAttributeNode(&TokenPageContext->ClaimsTreeContext, node, + PhFormatString(L"Value %u: %s", j, temp->Buffer)); + PhDereferenceObject(temp); + } + } + + PhFree(info); + } + + NtClose(tokenHandle); + + TreeNew_NodesStructured(tnHandle); + + return TRUE; +} + +INT_PTR CALLBACK PhpTokenClaimsPageProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + PTOKEN_PAGE_CONTEXT tokenPageContext; + HWND tnHandle; + + tokenPageContext = PhpTokenPageHeader(hwndDlg, uMsg, wParam, lParam); + + if (!tokenPageContext) + return FALSE; + + tnHandle = GetDlgItem(hwndDlg, IDC_LIST); + + switch (uMsg) + { + case WM_INITDIALOG: + { + PATTRIBUTE_NODE userNode; + PATTRIBUTE_NODE deviceNode; + + PhpInitializeAttributeTreeContext(&tokenPageContext->ClaimsTreeContext, tnHandle); + + TreeNew_SetRedraw(tnHandle, FALSE); + + userNode = PhpAddAttributeNode(&tokenPageContext->ClaimsTreeContext, NULL, PhCreateString(L"User claims")); + PhpAddTokenClaimAttributes(tokenPageContext, tnHandle, FALSE, userNode); + deviceNode = PhpAddAttributeNode(&tokenPageContext->ClaimsTreeContext, NULL, PhCreateString(L"Device claims")); + PhpAddTokenClaimAttributes(tokenPageContext, tnHandle, TRUE, deviceNode); + + if (userNode->Children->Count == 0) + PhpAddAttributeNode(&tokenPageContext->ClaimsTreeContext, userNode, PhCreateString(L"(None)")); + if (deviceNode->Children->Count == 0) + PhpAddAttributeNode(&tokenPageContext->ClaimsTreeContext, deviceNode, PhCreateString(L"(None)")); + + TreeNew_NodesStructured(tnHandle); + TreeNew_SetRedraw(tnHandle, TRUE); + + EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); + } + break; + case WM_DESTROY: + { + PhpDeleteAttributeTreeContext(&tokenPageContext->ClaimsTreeContext); + } + break; + } + + return FALSE; +} + +BOOLEAN PhpAddTokenAttributes( + _In_ PTOKEN_PAGE_CONTEXT TokenPageContext, + _In_ HWND tnHandle + ) +{ + HANDLE tokenHandle; + PTOKEN_SECURITY_ATTRIBUTES_INFORMATION info; + ULONG i; + ULONG j; + + if (!NT_SUCCESS(TokenPageContext->OpenObject( + &tokenHandle, + TOKEN_QUERY, + TokenPageContext->Context + ))) + return FALSE; + + if (NT_SUCCESS(PhQueryTokenVariableSize(tokenHandle, TokenSecurityAttributes, &info))) + { + for (i = 0; i < info->AttributeCount; i++) + { + PTOKEN_SECURITY_ATTRIBUTE_V1 attribute = &info->Attribute.pAttributeV1[i]; + PATTRIBUTE_NODE node; + PPH_STRING temp; + + // Attribute + node = PhpAddAttributeNode(&TokenPageContext->AuthzTreeContext, NULL, + PhCreateStringFromUnicodeString(&attribute->Name)); + // Type + PhpAddAttributeNode(&TokenPageContext->AuthzTreeContext, node, + PhFormatString(L"Type: %s", PhGetSecurityAttributeTypeString(attribute->ValueType))); + // Flags + temp = PhGetSecurityAttributeFlagsString(attribute->Flags); + PhpAddAttributeNode(&TokenPageContext->AuthzTreeContext, node, + PhFormatString(L"Flags: %s", temp->Buffer)); + PhDereferenceObject(temp); + + // Values + for (j = 0; j < attribute->ValueCount; j++) + { + temp = PhFormatTokenSecurityAttributeValue(attribute, j); + PhpAddAttributeNode(&TokenPageContext->AuthzTreeContext, node, + PhFormatString(L"Value %u: %s", j, temp->Buffer)); + PhDereferenceObject(temp); + } + } + + PhFree(info); + } + + NtClose(tokenHandle); + + TreeNew_NodesStructured(tnHandle); + + return TRUE; +} + +INT_PTR CALLBACK PhpTokenAttributesPageProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + PTOKEN_PAGE_CONTEXT tokenPageContext; + HWND tnHandle; + + tokenPageContext = PhpTokenPageHeader(hwndDlg, uMsg, wParam, lParam); + + if (!tokenPageContext) + return FALSE; + + tnHandle = GetDlgItem(hwndDlg, IDC_LIST); + + switch (uMsg) + { + case WM_INITDIALOG: + { + PhpInitializeAttributeTreeContext(&tokenPageContext->AuthzTreeContext, tnHandle); + + TreeNew_SetRedraw(tnHandle, FALSE); + + PhpAddTokenAttributes(tokenPageContext, tnHandle); + + if (tokenPageContext->AuthzTreeContext.RootList->Count == 0) + PhpAddAttributeNode(&tokenPageContext->AuthzTreeContext, NULL, PhCreateString(L"(None)")); + + TreeNew_NodesStructured(tnHandle); + TreeNew_SetRedraw(tnHandle, TRUE); + + EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); + } + break; + case WM_DESTROY: + { + PhpDeleteAttributeTreeContext(&tokenPageContext->AuthzTreeContext); + } + break; + } + + return FALSE; +} diff --git a/ProcessHacker/version.rc b/ProcessHacker/version.rc index 719f3d2ab572..6caa53e40114 100644 --- a/ProcessHacker/version.rc +++ b/ProcessHacker/version.rc @@ -1,35 +1,35 @@ -#include "winres.h" -#include "include/phappres.h" - -VS_VERSION_INFO VERSIONINFO - FILEVERSION PHAPP_VERSION_NUMBER - PRODUCTVERSION PHAPP_VERSION_NUMBER - FILEFLAGSMASK 0x17L -#ifdef _DEBUG - FILEFLAGS 0x1L -#else - FILEFLAGS 0x0L -#endif - FILEOS 0x4L - FILETYPE 0x1L - FILESUBTYPE 0x0L -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "0c0904b0" - BEGIN - VALUE "CompanyName", "wj32" - VALUE "FileDescription", "Process Hacker" - VALUE "FileVersion", PHAPP_VERSION_STRING - VALUE "InternalName", "Process Hacker" - VALUE "LegalCopyright", "Licensed under the GNU GPL, v3." - VALUE "OriginalFilename", "ProcessHacker.exe" - VALUE "ProductName", "Process Hacker" - VALUE "ProductVersion", PHAPP_VERSION_STRING - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0xc09, 1200 - END -END +#include "winres.h" +#include "include/phappres.h" + +VS_VERSION_INFO VERSIONINFO + FILEVERSION PHAPP_VERSION_NUMBER + PRODUCTVERSION PHAPP_VERSION_NUMBER + FILEFLAGSMASK 0x17L +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "0c0904b0" + BEGIN + VALUE "CompanyName", "wj32" + VALUE "FileDescription", "Process Hacker" + VALUE "FileVersion", PHAPP_VERSION_STRING + VALUE "InternalName", "Process Hacker" + VALUE "LegalCopyright", "Licensed under the GNU GPL, v3." + VALUE "OriginalFilename", "ProcessHacker.exe" + VALUE "ProductName", "Process Hacker" + VALUE "ProductVersion", PHAPP_VERSION_STRING + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0xc09, 1200 + END +END diff --git a/phlib/apiimport.c b/phlib/apiimport.c index a538d8359f6b..bcf06a49574a 100644 --- a/phlib/apiimport.c +++ b/phlib/apiimport.c @@ -1,68 +1,68 @@ -/* - * Process Hacker - - * procedure import module - * - * Copyright (C) 2015 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include -#include - -PVOID PhpImportProcedure( - _Inout_ PVOID *Cache, - _Inout_ PBOOLEAN CacheValid, - _In_ PWSTR ModuleName, - _In_ PSTR ProcedureName - ) -{ - HMODULE module; - PVOID procedure; - - if (*CacheValid) - return *Cache; - - module = GetModuleHandle(ModuleName); - - if (!module) - return NULL; - - procedure = GetProcAddress(module, ProcedureName); - *Cache = procedure; - MemoryBarrier(); - *CacheValid = TRUE; - - return procedure; -} - -#define PH_DEFINE_IMPORT(Module, Name) \ -_##Name Name##_Import(VOID) \ -{ \ - static PVOID cache = NULL; \ - static BOOLEAN cacheValid = FALSE; \ -\ - return (_##Name)PhpImportProcedure(&cache, &cacheValid, Module, #Name); \ -} - -PH_DEFINE_IMPORT(L"comctl32.dll", TaskDialogIndirect); -PH_DEFINE_IMPORT(L"ntdll.dll", NtQueryInformationEnlistment); -PH_DEFINE_IMPORT(L"ntdll.dll", NtQueryInformationResourceManager); -PH_DEFINE_IMPORT(L"ntdll.dll", NtQueryInformationTransaction); -PH_DEFINE_IMPORT(L"ntdll.dll", NtQueryInformationTransactionManager); -PH_DEFINE_IMPORT(L"shell32.dll", SHCreateShellItem); -PH_DEFINE_IMPORT(L"shell32.dll", SHOpenFolderAndSelectItems); -PH_DEFINE_IMPORT(L"shell32.dll", SHParseDisplayName); +/* + * Process Hacker - + * procedure import module + * + * Copyright (C) 2015 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include +#include + +PVOID PhpImportProcedure( + _Inout_ PVOID *Cache, + _Inout_ PBOOLEAN CacheValid, + _In_ PWSTR ModuleName, + _In_ PSTR ProcedureName + ) +{ + HMODULE module; + PVOID procedure; + + if (*CacheValid) + return *Cache; + + module = GetModuleHandle(ModuleName); + + if (!module) + return NULL; + + procedure = GetProcAddress(module, ProcedureName); + *Cache = procedure; + MemoryBarrier(); + *CacheValid = TRUE; + + return procedure; +} + +#define PH_DEFINE_IMPORT(Module, Name) \ +_##Name Name##_Import(VOID) \ +{ \ + static PVOID cache = NULL; \ + static BOOLEAN cacheValid = FALSE; \ +\ + return (_##Name)PhpImportProcedure(&cache, &cacheValid, Module, #Name); \ +} + +PH_DEFINE_IMPORT(L"comctl32.dll", TaskDialogIndirect); +PH_DEFINE_IMPORT(L"ntdll.dll", NtQueryInformationEnlistment); +PH_DEFINE_IMPORT(L"ntdll.dll", NtQueryInformationResourceManager); +PH_DEFINE_IMPORT(L"ntdll.dll", NtQueryInformationTransaction); +PH_DEFINE_IMPORT(L"ntdll.dll", NtQueryInformationTransactionManager); +PH_DEFINE_IMPORT(L"shell32.dll", SHCreateShellItem); +PH_DEFINE_IMPORT(L"shell32.dll", SHOpenFolderAndSelectItems); +PH_DEFINE_IMPORT(L"shell32.dll", SHParseDisplayName); diff --git a/phlib/basesup.c b/phlib/basesup.c index e93241089a70..61ee300a3574 100644 --- a/phlib/basesup.c +++ b/phlib/basesup.c @@ -1,5985 +1,5985 @@ -/* - * Process Hacker - - * base support functions - * - * Copyright (C) 2009-2016 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -/* - * This file contains basic low-level code as well as general algorithms and data structures. - * - * Memory allocation. PhAllocate is a wrapper around RtlAllocateHeap, and always allocates from the - * phlib heap. PhAllocatePage is a wrapper around NtAllocateVirtualMemory and allocates pages. - * - * Null-terminated strings. The Ph*StringZ functions manipulate null-terminated strings. The copying - * functions provide a simple way to copy strings which may not be null-terminated, but have a - * specified limit. - * - * String. The design of the string object was chosen for maximum compatibility. As such each string - * buffer must be null-terminated, and each object contains an embedded PH_STRINGREF structure. Note - * that efficient sub-string creation (no copying, only references the parent string object) could - * not be implemented due to the mandatory null-termination. String objects must be regarded as - * immutable (for thread-safety reasons) unless the object has just been created and no references - * have been shared. - * - * String builder. This is a set of functions which allow for efficient modification of strings. For - * performance reasons, these functions modify string objects directly, even though they are - * normally immutable. - * - * List. A simple PVOID list that resizes itself when needed. - * - * Pointer list. Similar to the normal list object, but uses a free list in order to support - * constant time insertion and deletion. In order for the free list to work, normal entries have - * their lowest bit clear while free entries have their lowest bit set, with the index of the next - * free entry in the upper bits. - * - * Hashtable. A hashtable with power-of-two bucket sizes and with all entries stored in a single - * array. This improves locality but may be inefficient when resizing the hashtable. It is a good - * idea to store pointers to objects as entries, as opposed to the objects themselves. - * - * Simple hashtable. A wrapper around the normal hashtable, with PVOID keys and PVOID values. - * - * Free list. A thread-safe memory allocation method where freed blocks are stored in a S-list, and - * allocations are made from this list whenever possible. - * - * Callback. A thread-safe notification mechanism where clients can register callback functions - * which are then invoked by other code. - */ - -#include - -#include -#include - -#include - -#define PH_VECTOR_LEVEL_NONE 0 -#define PH_VECTOR_LEVEL_SSE2 1 -#define PH_VECTOR_LEVEL_AVX 2 - -typedef struct _PHP_BASE_THREAD_CONTEXT -{ - PUSER_THREAD_START_ROUTINE StartAddress; - PVOID Parameter; -} PHP_BASE_THREAD_CONTEXT, *PPHP_BASE_THREAD_CONTEXT; - -VOID NTAPI PhpListDeleteProcedure( - _In_ PVOID Object, - _In_ ULONG Flags - ); - -VOID NTAPI PhpPointerListDeleteProcedure( - _In_ PVOID Object, - _In_ ULONG Flags - ); - -VOID NTAPI PhpQueueDeleteProcedure( - _In_ PVOID Object, - _In_ ULONG Flags - ); - -VOID NTAPI PhpHashtableDeleteProcedure( - _In_ PVOID Object, - _In_ ULONG Flags - ); - -// Types - -PPH_OBJECT_TYPE PhStringType; -PPH_OBJECT_TYPE PhBytesType; -PPH_OBJECT_TYPE PhListType; -PPH_OBJECT_TYPE PhPointerListType; -PPH_OBJECT_TYPE PhHashtableType; - -// Misc. - -static BOOLEAN PhpVectorLevel = PH_VECTOR_LEVEL_NONE; -static PPH_STRING PhSharedEmptyString = NULL; - -// Threads - -static PH_FREE_LIST PhpBaseThreadContextFreeList; -#ifdef DEBUG -ULONG PhDbgThreadDbgTlsIndex; -LIST_ENTRY PhDbgThreadListHead; -PH_QUEUED_LOCK PhDbgThreadListLock = PH_QUEUED_LOCK_INIT; -#endif - -// Data - -static ULONG PhpPrimeNumbers[] = -{ - 0x3, 0x7, 0xb, 0x11, 0x17, 0x1d, 0x25, 0x2f, 0x3b, 0x47, 0x59, 0x6b, 0x83, - 0xa3, 0xc5, 0xef, 0x125, 0x161, 0x1af, 0x209, 0x277, 0x2f9, 0x397, 0x44f, - 0x52f, 0x63d, 0x78b, 0x91d, 0xaf1, 0xd2b, 0xfd1, 0x12fd, 0x16cf, 0x1b65, - 0x20e3, 0x2777, 0x2f6f, 0x38ff, 0x446f, 0x521f, 0x628d, 0x7655, 0x8e01, - 0xaa6b, 0xcc89, 0xf583, 0x126a7, 0x1619b, 0x1a857, 0x1fd3b, 0x26315, 0x2dd67, - 0x3701b, 0x42023, 0x4f361, 0x5f0ed, 0x72125, 0x88e31, 0xa443b, 0xc51eb, - 0xec8c1, 0x11bdbf, 0x154a3f, 0x198c4f, 0x1ea867, 0x24ca19, 0x2c25c1, 0x34fa1b, - 0x3f928f, 0x4c4987, 0x5b8b6f, 0x6dda89 -}; - -/** - * Initializes the base support module. - */ -BOOLEAN PhBaseInitialization( - VOID - ) -{ - PH_OBJECT_TYPE_PARAMETERS parameters; - - // The following relies on the (technically undefined) value of XState being zero before Windows 7 SP1. - // NOTE: This is unused for now. - /*if (USER_SHARED_DATA->XState.EnabledFeatures & XSTATE_MASK_AVX) - PhpVectorLevel = PH_VECTOR_LEVEL_AVX; - else*/ if (USER_SHARED_DATA->ProcessorFeatures[PF_XMMI64_INSTRUCTIONS_AVAILABLE]) - PhpVectorLevel = PH_VECTOR_LEVEL_SSE2; - - PhStringType = PhCreateObjectType(L"String", 0, NULL); - PhBytesType = PhCreateObjectType(L"Bytes", 0, NULL); - - parameters.FreeListSize = sizeof(PH_LIST); - parameters.FreeListCount = 128; - - PhListType = PhCreateObjectTypeEx(L"List", PH_OBJECT_TYPE_USE_FREE_LIST, PhpListDeleteProcedure, ¶meters); - PhPointerListType = PhCreateObjectType(L"PointerList", 0, PhpPointerListDeleteProcedure); - - parameters.FreeListSize = sizeof(PH_HASHTABLE); - parameters.FreeListCount = 64; - - PhHashtableType = PhCreateObjectTypeEx(L"Hashtable", PH_OBJECT_TYPE_USE_FREE_LIST, PhpHashtableDeleteProcedure, ¶meters); - - PhInitializeFreeList(&PhpBaseThreadContextFreeList, sizeof(PHP_BASE_THREAD_CONTEXT), 16); - -#ifdef DEBUG - PhDbgThreadDbgTlsIndex = TlsAlloc(); - InitializeListHead(&PhDbgThreadListHead); -#endif - - return TRUE; -} - -NTSTATUS PhpBaseThreadStart( - _In_ PVOID Parameter - ) -{ - NTSTATUS status; - HRESULT result; - PHP_BASE_THREAD_CONTEXT context; -#ifdef DEBUG - PHP_BASE_THREAD_DBG dbg; -#endif - - context = *(PPHP_BASE_THREAD_CONTEXT)Parameter; - PhFreeToFreeList(&PhpBaseThreadContextFreeList, Parameter); - -#ifdef DEBUG - dbg.ClientId = NtCurrentTeb()->ClientId; - - dbg.StartAddress = context.StartAddress; - dbg.Parameter = context.Parameter; - dbg.CurrentAutoPool = NULL; - - PhAcquireQueuedLockExclusive(&PhDbgThreadListLock); - InsertTailList(&PhDbgThreadListHead, &dbg.ListEntry); - PhReleaseQueuedLockExclusive(&PhDbgThreadListLock); - - TlsSetValue(PhDbgThreadDbgTlsIndex, &dbg); -#endif - - // Initialization code - - result = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE); - - // Call the user-supplied function. - status = context.StartAddress(context.Parameter); - - // De-initialization code - - if (result == S_OK || result == S_FALSE) - CoUninitialize(); - -#ifdef DEBUG - PhAcquireQueuedLockExclusive(&PhDbgThreadListLock); - RemoveEntryList(&dbg.ListEntry); - PhReleaseQueuedLockExclusive(&PhDbgThreadListLock); -#endif - - return status; -} - -/** - * Creates a thread. - * - * \param StackSize The initial stack size of the thread. - * \param StartAddress The function to execute in the thread. - * \param Parameter A user-defined value to pass to the function. - */ -HANDLE PhCreateThread( - _In_opt_ SIZE_T StackSize, - _In_ PUSER_THREAD_START_ROUTINE StartAddress, - _In_opt_ PVOID Parameter - ) -{ - HANDLE threadHandle; - PPHP_BASE_THREAD_CONTEXT context; - - context = PhAllocateFromFreeList(&PhpBaseThreadContextFreeList); - context->StartAddress = StartAddress; - context->Parameter = Parameter; - - threadHandle = CreateThread( - NULL, - StackSize, - PhpBaseThreadStart, - context, - 0, - NULL - ); - - if (threadHandle) - { - PHLIB_INC_STATISTIC(BaseThreadsCreated); - return threadHandle; - } - else - { - PHLIB_INC_STATISTIC(BaseThreadsCreateFailed); - PhFreeToFreeList(&PhpBaseThreadContextFreeList, context); - return NULL; - } -} - -/** - * Gets the current system time (UTC). - * - * \remarks Use this function instead of NtQuerySystemTime() because no system calls are involved. - */ -VOID PhQuerySystemTime( - _Out_ PLARGE_INTEGER SystemTime - ) -{ - do - { - SystemTime->HighPart = USER_SHARED_DATA->SystemTime.High1Time; - SystemTime->LowPart = USER_SHARED_DATA->SystemTime.LowPart; - } while (SystemTime->HighPart != USER_SHARED_DATA->SystemTime.High2Time); -} - -/** - * Gets the offset of the current time zone from UTC. - */ -VOID PhQueryTimeZoneBias( - _Out_ PLARGE_INTEGER TimeZoneBias - ) -{ - do - { - TimeZoneBias->HighPart = USER_SHARED_DATA->TimeZoneBias.High1Time; - TimeZoneBias->LowPart = USER_SHARED_DATA->TimeZoneBias.LowPart; - } while (TimeZoneBias->HighPart != USER_SHARED_DATA->TimeZoneBias.High2Time); -} - -/** - * Converts system time to local time. - * - * \param SystemTime A UTC time value. - * \param LocalTime A variable which receives the local time value. This may be the same variable as - * \a SystemTime. - * - * \remarks Use this function instead of RtlSystemTimeToLocalTime() because no system calls are - * involved. - */ -VOID PhSystemTimeToLocalTime( - _In_ PLARGE_INTEGER SystemTime, - _Out_ PLARGE_INTEGER LocalTime - ) -{ - LARGE_INTEGER timeZoneBias; - - PhQueryTimeZoneBias(&timeZoneBias); - LocalTime->QuadPart = SystemTime->QuadPart - timeZoneBias.QuadPart; -} - -/** - * Converts local time to system time. - * - * \param LocalTime A local time value. - * \param SystemTime A variable which receives the UTC time value. This may be the same variable as - * \a LocalTime. - * - * \remarks Use this function instead of RtlLocalTimeToSystemTime() because no system calls are - * involved. - */ -VOID PhLocalTimeToSystemTime( - _In_ PLARGE_INTEGER LocalTime, - _Out_ PLARGE_INTEGER SystemTime - ) -{ - LARGE_INTEGER timeZoneBias; - - PhQueryTimeZoneBias(&timeZoneBias); - SystemTime->QuadPart = LocalTime->QuadPart + timeZoneBias.QuadPart; -} - -/** - * Allocates a block of memory. - * - * \param Size The number of bytes to allocate. - * - * \return A pointer to the allocated block of memory. - * - * \remarks If the function fails to allocate the block of memory, it raises an exception. The block - * is guaranteed to be aligned at MEMORY_ALLOCATION_ALIGNMENT bytes. - */ -_May_raise_ -_Check_return_ -_Ret_notnull_ -_Post_writable_byte_size_(Size) -PVOID PhAllocate( - _In_ SIZE_T Size - ) -{ - return RtlAllocateHeap(PhHeapHandle, HEAP_GENERATE_EXCEPTIONS, Size); -} - -/** - * Allocates a block of memory. - * - * \param Size The number of bytes to allocate. - * - * \return A pointer to the allocated block of memory, or NULL if the block could not be allocated. - */ -PVOID PhAllocateSafe( - _In_ SIZE_T Size - ) -{ - return RtlAllocateHeap(PhHeapHandle, 0, Size); -} - -/** - * Allocates a block of memory. - * - * \param Size The number of bytes to allocate. - * \param Flags Flags controlling the allocation. - * - * \return A pointer to the allocated block of memory, or NULL if the block could not be allocated. - */ -PVOID PhAllocateExSafe( - _In_ SIZE_T Size, - _In_ ULONG Flags - ) -{ - return RtlAllocateHeap(PhHeapHandle, Flags, Size); -} - -/** - * Frees a block of memory allocated with PhAllocate(). - * - * \param Memory A pointer to a block of memory. - */ -VOID PhFree( - _Frees_ptr_opt_ PVOID Memory - ) -{ - RtlFreeHeap(PhHeapHandle, 0, Memory); -} - -/** - * Re-allocates a block of memory originally allocated with PhAllocate(). - * - * \param Memory A pointer to a block of memory. - * \param Size The new size of the memory block, in bytes. - * - * \return A pointer to the new block of memory. The existing contents of the memory block are - * copied to the new block. - * - * \remarks If the function fails to allocate the block of memory, it raises an exception. - */ -_May_raise_ -_Post_writable_byte_size_(Size) -PVOID PhReAllocate( - _Frees_ptr_opt_ PVOID Memory, - _In_ SIZE_T Size - ) -{ - return RtlReAllocateHeap(PhHeapHandle, HEAP_GENERATE_EXCEPTIONS, Memory, Size); -} - -/** - * Re-allocates a block of memory originally allocated with PhAllocate(). - * - * \param Memory A pointer to a block of memory. - * \param Size The new size of the memory block, in bytes. - * - * \return A pointer to the new block of memory, or NULL if the block could not be allocated. The - * existing contents of the memory block are copied to the new block. - */ -PVOID PhReAllocateSafe( - _In_ PVOID Memory, - _In_ SIZE_T Size - ) -{ - return RtlReAllocateHeap(PhHeapHandle, 0, Memory, Size); -} - -/** - * Allocates pages of memory. - * - * \param Size The number of bytes to allocate. The number of pages allocated will be large enough - * to contain \a Size bytes. - * \param NewSize The number of bytes actually allocated. This is \a Size rounded up to the next - * multiple of PAGE_SIZE. - * - * \return A pointer to the allocated block of memory, or NULL if the block could not be allocated. - */ -_Check_return_ -_Ret_maybenull_ -PVOID PhAllocatePage( - _In_ SIZE_T Size, - _Out_opt_ PSIZE_T NewSize - ) -{ - PVOID baseAddress; - - baseAddress = NULL; - - if (NT_SUCCESS(NtAllocateVirtualMemory( - NtCurrentProcess(), - &baseAddress, - 0, - &Size, - MEM_COMMIT, - PAGE_READWRITE - ))) - { - if (NewSize) - *NewSize = Size; - - return baseAddress; - } - else - { - return NULL; - } -} - -/** - * Frees pages of memory allocated with PhAllocatePage(). - * - * \param Memory A pointer to a block of memory. - */ -VOID PhFreePage( - _Frees_ptr_opt_ PVOID Memory - ) -{ - SIZE_T size; - - size = 0; - - NtFreeVirtualMemory( - NtCurrentProcess(), - &Memory, - &size, - MEM_RELEASE - ); -} - -/** - * Determines the length of the specified string, in characters. - * - * \param String The string. - */ -SIZE_T PhCountStringZ( - _In_ PWSTR String - ) -{ - if (PhpVectorLevel >= PH_VECTOR_LEVEL_SSE2) - { - PWSTR p; - ULONG unaligned; - __m128i b; - __m128i z; - ULONG mask; - ULONG index; - - p = (PWSTR)((ULONG_PTR)String & ~0xe); // String should be 2 byte aligned - unaligned = PtrToUlong(String) & 0xf; - z = _mm_setzero_si128(); - - if (unaligned != 0) - { - b = _mm_load_si128((__m128i *)p); - b = _mm_cmpeq_epi16(b, z); - mask = _mm_movemask_epi8(b) >> unaligned; - - if (_BitScanForward(&index, mask)) - return index / sizeof(WCHAR); - - p += 16 / sizeof(WCHAR); - } - - while (TRUE) - { - b = _mm_load_si128((__m128i *)p); - b = _mm_cmpeq_epi16(b, z); - mask = _mm_movemask_epi8(b); - - if (_BitScanForward(&index, mask)) - return (SIZE_T)(p - String) + index / sizeof(WCHAR); - - p += 16 / sizeof(WCHAR); - } - } - else - { - return wcslen(String); - } -} - -/** - * Allocates space for and copies a byte string. - * - * \param String The string to duplicate. - * - * \return The new string, which can be freed using PhFree(). - */ -PSTR PhDuplicateBytesZ( - _In_ PSTR String - ) -{ - PSTR newString; - SIZE_T length; - - length = strlen(String) + 1; // include the null terminator - - newString = PhAllocate(length); - memcpy(newString, String, length); - - return newString; -} - -/** - * Allocates space for and copies a byte string. - * - * \param String The string to duplicate. - * - * \return The new string, which can be freed using PhFree(), or NULL if storage could not be - * allocated. - */ -PSTR PhDuplicateBytesZSafe( - _In_ PSTR String - ) -{ - PSTR newString; - SIZE_T length; - - length = strlen(String) + 1; // include the null terminator - - newString = PhAllocateSafe(length); - - if (!newString) - return NULL; - - memcpy(newString, String, length); - - return newString; -} - -/** - * Allocates space for and copies a 16-bit string. - * - * \param String The string to duplicate. - * - * \return The new string, which can be freed using PhFree(). - */ -PWSTR PhDuplicateStringZ( - _In_ PWSTR String - ) -{ - PWSTR newString; - SIZE_T length; - - length = (PhCountStringZ(String) + 1) * sizeof(WCHAR); // include the null terminator - - newString = PhAllocate(length); - memcpy(newString, String, length); - - return newString; -} - -/** - * Copies a string with optional null termination and a maximum number of characters. - * - * \param InputBuffer A pointer to the input string. - * \param InputCount The maximum number of characters to copy, not including the null terminator. - * Specify -1 for no limit. - * \param OutputBuffer A pointer to the output buffer. - * \param OutputCount The number of characters in the output buffer, including the null terminator. - * \param ReturnCount A variable which receives the number of characters required to contain the - * input string, including the null terminator. If the function returns TRUE, this variable contains - * the number of characters written to the output buffer. - * - * \return TRUE if the input string was copied to the output string, otherwise FALSE. - * - * \remarks The function stops copying when it encounters the first null character in the input - * string. It will also stop copying when it reaches the character count specified in \a InputCount, - * if \a InputCount is not -1. - */ -BOOLEAN PhCopyBytesZ( - _In_ PSTR InputBuffer, - _In_ SIZE_T InputCount, - _Out_writes_opt_z_(OutputCount) PSTR OutputBuffer, - _In_ SIZE_T OutputCount, - _Out_opt_ PSIZE_T ReturnCount - ) -{ - SIZE_T i; - BOOLEAN copied; - - // Determine the length of the input string. - - if (InputCount != -1) - { - i = 0; - - while (i < InputCount && InputBuffer[i]) - i++; - } - else - { - i = strlen(InputBuffer); - } - - // Copy the string if there is enough room. - - if (OutputBuffer && OutputCount >= i + 1) // need one character for null terminator - { - memcpy(OutputBuffer, InputBuffer, i); - OutputBuffer[i] = 0; - copied = TRUE; - } - else - { - copied = FALSE; - } - - if (ReturnCount) - *ReturnCount = i + 1; - - return copied; -} - -/** - * Copies a string with optional null termination and a maximum number of characters. - * - * \param InputBuffer A pointer to the input string. - * \param InputCount The maximum number of characters to copy, not including the null terminator. - * Specify -1 for no limit. - * \param OutputBuffer A pointer to the output buffer. - * \param OutputCount The number of characters in the output buffer, including the null terminator. - * \param ReturnCount A variable which receives the number of characters required to contain the - * input string, including the null terminator. If the function returns TRUE, this variable contains - * the number of characters written to the output buffer. - * - * \return TRUE if the input string was copied to the output string, otherwise FALSE. - * - * \remarks The function stops copying when it encounters the first null character in the input - * string. It will also stop copying when it reaches the character count specified in \a InputCount, - * if \a InputCount is not -1. - */ -BOOLEAN PhCopyStringZ( - _In_ PWSTR InputBuffer, - _In_ SIZE_T InputCount, - _Out_writes_opt_z_(OutputCount) PWSTR OutputBuffer, - _In_ SIZE_T OutputCount, - _Out_opt_ PSIZE_T ReturnCount - ) -{ - SIZE_T i; - BOOLEAN copied; - - // Determine the length of the input string. - - if (InputCount != -1) - { - i = 0; - - while (i < InputCount && InputBuffer[i]) - i++; - } - else - { - i = PhCountStringZ(InputBuffer); - } - - // Copy the string if there is enough room. - - if (OutputBuffer && OutputCount >= i + 1) // need one character for null terminator - { - memcpy(OutputBuffer, InputBuffer, i * sizeof(WCHAR)); - OutputBuffer[i] = 0; - copied = TRUE; - } - else - { - copied = FALSE; - } - - if (ReturnCount) - *ReturnCount = i + 1; - - return copied; -} - -/** - * Copies a string with optional null termination and a maximum number of characters. - * - * \param InputBuffer A pointer to the input string. - * \param InputCount The maximum number of characters to copy, not including the null terminator. - * Specify -1 for no limit. - * \param OutputBuffer A pointer to the output buffer. - * \param OutputCount The number of characters in the output buffer, including the null terminator. - * \param ReturnCount A variable which receives the number of characters required to contain the - * input string, including the null terminator. If the function returns TRUE, this variable contains - * the number of characters written to the output buffer. - * - * \return TRUE if the input string was copied to the output string, otherwise FALSE. - * - * \remarks The function stops copying when it encounters the first null character in the input - * string. It will also stop copying when it reaches the character count specified in \a InputCount, - * if \a InputCount is not -1. - */ -BOOLEAN PhCopyStringZFromBytes( - _In_ PSTR InputBuffer, - _In_ SIZE_T InputCount, - _Out_writes_opt_z_(OutputCount) PWSTR OutputBuffer, - _In_ SIZE_T OutputCount, - _Out_opt_ PSIZE_T ReturnCount - ) -{ - SIZE_T i; - BOOLEAN copied; - - // Determine the length of the input string. - - if (InputCount != -1) - { - i = 0; - - while (i < InputCount && InputBuffer[i]) - i++; - } - else - { - i = strlen(InputBuffer); - } - - // Copy the string if there is enough room. - - if (OutputBuffer && OutputCount >= i + 1) // need one character for null terminator - { - PhZeroExtendToUtf16Buffer(InputBuffer, i, OutputBuffer); - OutputBuffer[i] = 0; - copied = TRUE; - } - else - { - copied = FALSE; - } - - if (ReturnCount) - *ReturnCount = i + 1; - - return copied; -} - -/** - * Copies a string with optional null termination and a maximum number of characters. - * - * \param InputBuffer A pointer to the input string. - * \param InputCount The maximum number of characters to copy, not including the null terminator. - * Specify -1 for no limit. - * \param OutputBuffer A pointer to the output buffer. - * \param OutputCount The number of characters in the output buffer, including the null terminator. - * \param ReturnCount A variable which receives the number of characters required to contain the - * input string, including the null terminator. If the function returns TRUE, this variable contains - * the number of characters written to the output buffer. - * - * \return TRUE if the input string was copied to the output string, otherwise FALSE. - * - * \remarks The function stops copying when it encounters the first null character in the input - * string. It will also stop copying when it reaches the character count specified in \a InputCount, - * if \a InputCount is not -1. - */ -BOOLEAN PhCopyStringZFromMultiByte( - _In_ PSTR InputBuffer, - _In_ SIZE_T InputCount, - _Out_writes_opt_z_(OutputCount) PWSTR OutputBuffer, - _In_ SIZE_T OutputCount, - _Out_opt_ PSIZE_T ReturnCount - ) -{ - NTSTATUS status; - SIZE_T i; - ULONG unicodeBytes; - BOOLEAN copied; - - // Determine the length of the input string. - - if (InputCount != -1) - { - i = 0; - - while (i < InputCount && InputBuffer[i]) - i++; - } - else - { - i = strlen(InputBuffer); - } - - // Determine the length of the output string. - - status = RtlMultiByteToUnicodeSize( - &unicodeBytes, - InputBuffer, - (ULONG)i - ); - - if (!NT_SUCCESS(status)) - { - if (ReturnCount) - *ReturnCount = -1; - - return FALSE; - } - - // Convert the string to Unicode if there is enough room. - - if (OutputBuffer && OutputCount >= unicodeBytes / sizeof(WCHAR) + 1) - { - status = RtlMultiByteToUnicodeN( - OutputBuffer, - unicodeBytes, - NULL, - InputBuffer, - (ULONG)i - ); - - if (NT_SUCCESS(status)) - { - // RtlMultiByteToUnicodeN doesn't null terminate the string. - *(PWCHAR)((PCHAR)OutputBuffer + unicodeBytes) = 0; - copied = TRUE; - } - else - { - copied = FALSE; - } - } - else - { - copied = FALSE; - } - - if (ReturnCount) - *ReturnCount = unicodeBytes / sizeof(WCHAR) + 1; - - return copied; -} - -FORCEINLINE LONG PhpCompareRightNatural( - _In_ PWSTR A, - _In_ PWSTR B - ) -{ - LONG bias = 0; - - for (; ; A++, B++) - { - if (!PhIsDigitCharacter(*A) && !PhIsDigitCharacter(*B)) - { - return bias; - } - else if (!PhIsDigitCharacter(*A)) - { - return -1; - } - else if (!PhIsDigitCharacter(*B)) - { - return 1; - } - else if (*A < *B) - { - if (bias == 0) - bias = -1; - } - else if (*A > *B) - { - if (bias == 0) - bias = 1; - } - else if (!*A && !*B) - { - return bias; - } - } - - return 0; -} - -FORCEINLINE LONG PhpCompareLeftNatural( - _In_ PWSTR A, - _In_ PWSTR B - ) -{ - for (; ; A++, B++) - { - if (!PhIsDigitCharacter(*A) && !PhIsDigitCharacter(*B)) - { - return 0; - } - else if (!PhIsDigitCharacter(*A)) - { - return -1; - } - else if (!PhIsDigitCharacter(*B)) - { - return 1; - } - else if (*A < *B) - { - return -1; - } - else if (*A > *B) - { - return 1; - } - } - - return 0; -} - -FORCEINLINE LONG PhpCompareStringZNatural( - _In_ PWSTR A, - _In_ PWSTR B, - _In_ BOOLEAN IgnoreCase - ) -{ - /* strnatcmp.c -- Perform 'natural order' comparisons of strings in C. - Copyright (C) 2000, 2004 by Martin Pool - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - This code has been modified for Process Hacker. - */ - - ULONG ai, bi; - WCHAR ca, cb; - LONG result; - BOOLEAN fractional; - - ai = 0; - bi = 0; - - while (TRUE) - { - ca = A[ai]; - cb = B[bi]; - - /* Skip over leading spaces or zeros. */ - - while (ca == ' ') - ca = A[++ai]; - - while (cb == ' ') - cb = B[++bi]; - - /* Process run of digits. */ - if (PhIsDigitCharacter(ca) && PhIsDigitCharacter(cb)) - { - fractional = (ca == '0' || cb == '0'); - - if (fractional) - { - if ((result = PhpCompareLeftNatural(A + ai, B + bi)) != 0) - return result; - } - else - { - if ((result = PhpCompareRightNatural(A + ai, B + bi)) != 0) - return result; - } - } - - if (!ca && !cb) - { - /* Strings are considered the same. */ - return 0; - } - - if (IgnoreCase) - { - ca = towupper(ca); - cb = towupper(cb); - } - - if (ca < cb) - return -1; - else if (ca > cb) - return 1; - - ai++; - bi++; - } -} - -/** - * Compares two strings in natural sort order. - * - * \param A The first string. - * \param B The second string. - * \param IgnoreCase Whether to ignore character cases. - */ -LONG PhCompareStringZNatural( - _In_ PWSTR A, - _In_ PWSTR B, - _In_ BOOLEAN IgnoreCase - ) -{ - if (!IgnoreCase) - return PhpCompareStringZNatural(A, B, FALSE); - else - return PhpCompareStringZNatural(A, B, TRUE); -} - -/** - * Compares two strings. - * - * \param String1 The first string. - * \param String2 The second string. - * \param IgnoreCase TRUE to perform a case-insensitive comparison, otherwise FALSE. - */ -LONG PhCompareStringRef( - _In_ PPH_STRINGREF String1, - _In_ PPH_STRINGREF String2, - _In_ BOOLEAN IgnoreCase - ) -{ - SIZE_T l1; - SIZE_T l2; - PWCHAR s1; - PWCHAR s2; - WCHAR c1; - WCHAR c2; - PWCHAR end; - - // Note: this function assumes that the difference between the lengths of the two strings can - // fit inside a LONG. - - l1 = String1->Length; - l2 = String2->Length; - assert(!(l1 & 1)); - assert(!(l2 & 1)); - s1 = String1->Buffer; - s2 = String2->Buffer; - - end = (PWCHAR)((PCHAR)s1 + (l1 <= l2 ? l1 : l2)); - - if (!IgnoreCase) - { - while (s1 != end) - { - c1 = *s1; - c2 = *s2; - - if (c1 != c2) - return (LONG)c1 - (LONG)c2; - - s1++; - s2++; - } - } - else - { - while (s1 != end) - { - c1 = *s1; - c2 = *s2; - - if (c1 != c2) - { - c1 = RtlUpcaseUnicodeChar(c1); - c2 = RtlUpcaseUnicodeChar(c2); - - if (c1 != c2) - return (LONG)c1 - (LONG)c2; - } - - s1++; - s2++; - } - } - - return (LONG)(l1 - l2); -} - -/** - * Determines if two strings are equal. - * - * \param String1 The first string. - * \param String2 The second string. - * \param IgnoreCase TRUE to perform a case-insensitive comparison, otherwise FALSE. - */ -BOOLEAN PhEqualStringRef( - _In_ PPH_STRINGREF String1, - _In_ PPH_STRINGREF String2, - _In_ BOOLEAN IgnoreCase - ) -{ - SIZE_T l1; - SIZE_T l2; - PWSTR s1; - PWSTR s2; - WCHAR c1; - WCHAR c2; - SIZE_T length; - - l1 = String1->Length; - l2 = String2->Length; - assert(!(l1 & 1)); - assert(!(l2 & 1)); - - if (l1 != l2) - return FALSE; - - s1 = String1->Buffer; - s2 = String2->Buffer; - - if (PhpVectorLevel >= PH_VECTOR_LEVEL_SSE2) - { - length = l1 / 16; - - if (length != 0) - { - __m128i b1; - __m128i b2; - - do - { - b1 = _mm_loadu_si128((__m128i *)s1); - b2 = _mm_loadu_si128((__m128i *)s2); - b1 = _mm_cmpeq_epi32(b1, b2); - - if (_mm_movemask_epi8(b1) != 0xffff) - { - if (!IgnoreCase) - { - return FALSE; - } - else - { - // Compare character-by-character to ignore case. - l1 = length * 16 + (l1 & 15); - l1 /= sizeof(WCHAR); - goto CompareCharacters; - } - } - - s1 += 16 / sizeof(WCHAR); - s2 += 16 / sizeof(WCHAR); - } while (--length != 0); - } - - // Compare character-by-character because we have no more 16-byte blocks to compare. - l1 = (l1 & 15) / sizeof(WCHAR); - } - else - { - length = l1 / sizeof(ULONG_PTR); - - if (length != 0) - { - do - { - if (*(PULONG_PTR)s1 != *(PULONG_PTR)s2) - { - if (!IgnoreCase) - { - return FALSE; - } - else - { - // Compare character-by-character to ignore case. - l1 = length * sizeof(ULONG_PTR) + (l1 & (sizeof(ULONG_PTR) - 1)); - l1 /= sizeof(WCHAR); - goto CompareCharacters; - } - } - - s1 += sizeof(ULONG_PTR) / sizeof(WCHAR); - s2 += sizeof(ULONG_PTR) / sizeof(WCHAR); - } while (--length != 0); - } - - // Compare character-by-character because we have no more ULONG_PTR blocks to compare. - l1 = (l1 & (sizeof(ULONG_PTR) - 1)) / sizeof(WCHAR); - } - -CompareCharacters: - if (l1 != 0) - { - if (!IgnoreCase) - { - do - { - c1 = *s1; - c2 = *s2; - - if (c1 != c2) - return FALSE; - - s1++; - s2++; - } while (--l1 != 0); - } - else - { - do - { - c1 = *s1; - c2 = *s2; - - if (c1 != c2) - { - c1 = RtlUpcaseUnicodeChar(c1); - c2 = RtlUpcaseUnicodeChar(c2); - - if (c1 != c2) - return FALSE; - } - - s1++; - s2++; - } while (--l1 != 0); - } - } - - return TRUE; -} - -/** - * Locates a character in a string. - * - * \param String The string to search. - * \param Character The character to search for. - * \param IgnoreCase TRUE to perform a case-insensitive search, otherwise FALSE. - * - * \return The index, in characters, of the first occurrence of \a Character in \a String1. If - * \a Character was not found, -1 is returned. - */ -ULONG_PTR PhFindCharInStringRef( - _In_ PPH_STRINGREF String, - _In_ WCHAR Character, - _In_ BOOLEAN IgnoreCase - ) -{ - PWSTR buffer; - SIZE_T length; - - buffer = String->Buffer; - length = String->Length / sizeof(WCHAR); - - if (!IgnoreCase) - { - if (PhpVectorLevel >= PH_VECTOR_LEVEL_SSE2) - { - SIZE_T length16; - - length16 = String->Length / 16; - length &= 7; - - if (length16 != 0) - { - __m128i pattern; - __m128i block; - ULONG mask; - ULONG index; - - pattern = _mm_set1_epi16(Character); - - do - { - block = _mm_loadu_si128((__m128i *)buffer); - block = _mm_cmpeq_epi16(block, pattern); - mask = _mm_movemask_epi8(block); - - if (_BitScanForward(&index, mask)) - return (String->Length - length16 * 16) / sizeof(WCHAR) - length + index / 2; - - buffer += 16 / sizeof(WCHAR); - } while (--length16 != 0); - } - } - - if (length != 0) - { - do - { - if (*buffer == Character) - return String->Length / sizeof(WCHAR) - length; - - buffer++; - } while (--length != 0); - } - } - else - { - if (length != 0) - { - WCHAR c; - - c = RtlUpcaseUnicodeChar(Character); - - do - { - if (RtlUpcaseUnicodeChar(*buffer) == c) - return String->Length / sizeof(WCHAR) - length; - - buffer++; - } while (--length != 0); - } - } - - return -1; -} - -/** - * Locates a character in a string, searching backwards. - * - * \param String The string to search. - * \param Character The character to search for. - * \param IgnoreCase TRUE to perform a case-insensitive search, otherwise FALSE. - * - * \return The index, in characters, of the last occurrence of \a Character in \a String1. If - * \a Character was not found, -1 is returned. - */ -ULONG_PTR PhFindLastCharInStringRef( - _In_ PPH_STRINGREF String, - _In_ WCHAR Character, - _In_ BOOLEAN IgnoreCase - ) -{ - PWCHAR buffer; - SIZE_T length; - - buffer = (PWCHAR)((PCHAR)String->Buffer + String->Length); - length = String->Length / sizeof(WCHAR); - - if (!IgnoreCase) - { - if (PhpVectorLevel >= PH_VECTOR_LEVEL_SSE2) - { - SIZE_T length16; - - length16 = String->Length / 16; - length &= 7; - - if (length16 != 0) - { - __m128i pattern; - __m128i block; - ULONG mask; - ULONG index; - - pattern = _mm_set1_epi16(Character); - buffer -= 16 / sizeof(WCHAR); - - do - { - block = _mm_loadu_si128((__m128i *)buffer); - block = _mm_cmpeq_epi16(block, pattern); - mask = _mm_movemask_epi8(block); - - if (_BitScanReverse(&index, mask)) - return (length16 - 1) * 16 / sizeof(WCHAR) + length + index / 2; - - buffer -= 16 / sizeof(WCHAR); - } while (--length16 != 0); - - buffer += 16 / sizeof(WCHAR); - } - } - - if (length != 0) - { - buffer--; - - do - { - if (*buffer == Character) - return length - 1; - - buffer--; - } while (--length != 0); - } - } - else - { - if (length != 0) - { - WCHAR c; - - c = RtlUpcaseUnicodeChar(Character); - buffer--; - - do - { - if (RtlUpcaseUnicodeChar(*buffer) == c) - return length - 1; - - buffer--; - } while (--length != 0); - } - } - - return -1; -} - -/** - * Locates a string in a string. - * - * \param String The string to search. - * \param SubString The string to search for. - * \param IgnoreCase TRUE to perform a case-insensitive search, otherwise FALSE. - * - * \return The index, in characters, of the first occurrence of \a SubString in \a String. If - * \a SubString was not found, -1 is returned. - */ -ULONG_PTR PhFindStringInStringRef( - _In_ PPH_STRINGREF String, - _In_ PPH_STRINGREF SubString, - _In_ BOOLEAN IgnoreCase - ) -{ - SIZE_T length1; - SIZE_T length2; - PH_STRINGREF sr1; - PH_STRINGREF sr2; - WCHAR c; - SIZE_T i; - - length1 = String->Length / sizeof(WCHAR); - length2 = SubString->Length / sizeof(WCHAR); - - // Can't be a substring if it's bigger than the first string. - if (length2 > length1) - return -1; - // We always get a match if the substring is zero-length. - if (length2 == 0) - return 0; - - sr1.Buffer = String->Buffer; - sr1.Length = SubString->Length - sizeof(WCHAR); - sr2.Buffer = SubString->Buffer; - sr2.Length = SubString->Length - sizeof(WCHAR); - - if (!IgnoreCase) - { - c = *sr2.Buffer++; - - for (i = length1 - length2 + 1; i != 0; i--) - { - if (*sr1.Buffer++ == c && PhEqualStringRef(&sr1, &sr2, FALSE)) - { - goto FoundUString; - } - } - } - else - { - c = RtlUpcaseUnicodeChar(*sr2.Buffer++); - - for (i = length1 - length2 + 1; i != 0; i--) - { - if (RtlUpcaseUnicodeChar(*sr1.Buffer++) == c && PhEqualStringRef(&sr1, &sr2, TRUE)) - { - goto FoundUString; - } - } - } - - return -1; -FoundUString: - return (ULONG_PTR)(sr1.Buffer - String->Buffer - 1); -} - -/** - * Splits a string. - * - * \param Input The input string. - * \param Separator The character to split at. - * \param FirstPart A variable which receives the part of \a Input before the separator. This may be - * the same variable as \a Input. If the separator is not found in \a Input, this variable is set to - * \a Input. - * \param SecondPart A variable which recieves the part of \a Input after the separator. This may be - * the same variable as \a Input. If the separator is not found in \a Input, this variable is set to - * an empty string. - * - * \return TRUE if \a Separator was found in \a Input, otherwise FALSE. - */ -BOOLEAN PhSplitStringRefAtChar( - _In_ PPH_STRINGREF Input, - _In_ WCHAR Separator, - _Out_ PPH_STRINGREF FirstPart, - _Out_ PPH_STRINGREF SecondPart - ) -{ - PH_STRINGREF input; - ULONG_PTR index; - - input = *Input; // get a copy of the input because FirstPart/SecondPart may alias Input - index = PhFindCharInStringRef(Input, Separator, FALSE); - - if (index == -1) - { - // The separator was not found. - - FirstPart->Buffer = Input->Buffer; - FirstPart->Length = Input->Length; - SecondPart->Buffer = NULL; - SecondPart->Length = 0; - - return FALSE; - } - - FirstPart->Buffer = input.Buffer; - FirstPart->Length = index * sizeof(WCHAR); - SecondPart->Buffer = (PWCHAR)((PCHAR)input.Buffer + index * sizeof(WCHAR) + sizeof(WCHAR)); - SecondPart->Length = input.Length - index * sizeof(WCHAR) - sizeof(WCHAR); - - return TRUE; -} - -/** - * Splits a string at the last occurrence of a character. - * - * \param Input The input string. - * \param Separator The character to split at. - * \param FirstPart A variable which receives the part of \a Input before the separator. This may be - * the same variable as \a Input. If the separator is not found in \a Input, this variable is set to - * \a Input. - * \param SecondPart A variable which recieves the part of \a Input after the separator. This may be - * the same variable as \a Input. If the separator is not found in \a Input, this variable is set to - * an empty string. - * - * \return TRUE if \a Separator was found in \a Input, otherwise FALSE. - */ -BOOLEAN PhSplitStringRefAtLastChar( - _In_ PPH_STRINGREF Input, - _In_ WCHAR Separator, - _Out_ PPH_STRINGREF FirstPart, - _Out_ PPH_STRINGREF SecondPart - ) -{ - PH_STRINGREF input; - ULONG_PTR index; - - input = *Input; // get a copy of the input because FirstPart/SecondPart may alias Input - index = PhFindLastCharInStringRef(Input, Separator, FALSE); - - if (index == -1) - { - // The separator was not found. - - FirstPart->Buffer = Input->Buffer; - FirstPart->Length = Input->Length; - SecondPart->Buffer = NULL; - SecondPart->Length = 0; - - return FALSE; - } - - FirstPart->Buffer = input.Buffer; - FirstPart->Length = index * sizeof(WCHAR); - SecondPart->Buffer = (PWCHAR)((PCHAR)input.Buffer + index * sizeof(WCHAR) + sizeof(WCHAR)); - SecondPart->Length = input.Length - index * sizeof(WCHAR) - sizeof(WCHAR); - - return TRUE; -} - -/** - * Splits a string. - * - * \param Input The input string. - * \param Separator The string to split at. - * \param IgnoreCase TRUE to perform a case-insensitive search, otherwise FALSE. - * \param FirstPart A variable which receives the part of \a Input before the separator. This may be - * the same variable as \a Input. If the separator is not found in \a Input, this variable is set to - * \a Input. - * \param SecondPart A variable which recieves the part of \a Input after the separator. This may be - * the same variable as \a Input. If the separator is not found in \a Input, this variable is set to - * an empty string. - * - * \return TRUE if \a Separator was found in \a Input, otherwise FALSE. - */ -BOOLEAN PhSplitStringRefAtString( - _In_ PPH_STRINGREF Input, - _In_ PPH_STRINGREF Separator, - _In_ BOOLEAN IgnoreCase, - _Out_ PPH_STRINGREF FirstPart, - _Out_ PPH_STRINGREF SecondPart - ) -{ - PH_STRINGREF input; - ULONG_PTR index; - - input = *Input; // get a copy of the input because FirstPart/SecondPart may alias Input - index = PhFindStringInStringRef(Input, Separator, IgnoreCase); - - if (index == -1) - { - // The separator was not found. - - FirstPart->Buffer = Input->Buffer; - FirstPart->Length = Input->Length; - SecondPart->Buffer = NULL; - SecondPart->Length = 0; - - return FALSE; - } - - FirstPart->Buffer = input.Buffer; - FirstPart->Length = index * sizeof(WCHAR); - SecondPart->Buffer = (PWCHAR)((PCHAR)input.Buffer + index * sizeof(WCHAR) + Separator->Length); - SecondPart->Length = input.Length - index * sizeof(WCHAR) - Separator->Length; - - return TRUE; -} - -/** - * Splits a string. - * - * \param Input The input string. - * \param Separator The character set, string or range to split at. - * \param Flags A combination of flags. - * \li \c PH_SPLIT_AT_CHAR_SET \a Separator specifies a character set. \a Input will be split at a - * character which is contained in \a Separator. - * \li \c PH_SPLIT_AT_STRING \a Separator specifies a string. \a Input will be split an occurrence - * of \a Separator. - * \li \c PH_SPLIT_AT_RANGE \a Separator specifies a range. The \a Buffer field contains a character - * index cast to \c PWSTR and the \a Length field contains the length of the range, in bytes. - * \li \c PH_SPLIT_CASE_INSENSITIVE Specifies a case-insensitive search. - * \li \c PH_SPLIT_COMPLEMENT_CHAR_SET If used with \c PH_SPLIT_AT_CHAR_SET, the separator is a - * character which is not contained in \a Separator. - * \li \c PH_SPLIT_START_AT_END If used with \c PH_SPLIT_AT_CHAR_SET, the search is performed - * starting from the end of the string. - * \li \c PH_SPLIT_CHAR_SET_IS_UPPERCASE If used with \c PH_SPLIT_CASE_INSENSITIVE, specifies that - * the character set in \a Separator contains only uppercase characters. - * \param FirstPart A variable which receives the part of \a Input before the separator. This may be - * the same variable as \a Input. If the separator is not found in \a Input, this variable is set to - * \a Input. - * \param SecondPart A variable which recieves the part of \a Input after the separator. This may be - * the same variable as \a Input. If the separator is not found in \a Input, this variable is set to - * an empty string. - * \param SeparatorPart A variable which receives the part of \a Input that is the separator. If the - * separator is not found in \a Input, this variable is set to an empty string. - * - * \return TRUE if a separator was found in \a Input, otherwise FALSE. - */ -BOOLEAN PhSplitStringRefEx( - _In_ PPH_STRINGREF Input, - _In_ PPH_STRINGREF Separator, - _In_ ULONG Flags, - _Out_ PPH_STRINGREF FirstPart, - _Out_ PPH_STRINGREF SecondPart, - _Out_opt_ PPH_STRINGREF SeparatorPart - ) -{ - PH_STRINGREF input; - SIZE_T separatorIndex; - SIZE_T separatorLength; - PWCHAR charSet; - SIZE_T charSetCount; - BOOLEAN charSetTable[256]; - BOOLEAN charSetTableComplete; - SIZE_T i; - SIZE_T j; - USHORT c; - PWCHAR s; - LONG_PTR direction; - - input = *Input; // Get a copy of the input because FirstPart/SecondPart/SeparatorPart may alias Input - - if (Flags & PH_SPLIT_AT_RANGE) - { - separatorIndex = (SIZE_T)Separator->Buffer; - separatorLength = Separator->Length; - - if (separatorIndex == -1) - goto SeparatorNotFound; - - goto SeparatorFound; - } - else if (Flags & PH_SPLIT_AT_STRING) - { - if (Flags & PH_SPLIT_START_AT_END) - { - // not implemented - goto SeparatorNotFound; - } - - separatorIndex = PhFindStringInStringRef(Input, Separator, !!(Flags & PH_SPLIT_CASE_INSENSITIVE)); - - if (separatorIndex == -1) - goto SeparatorNotFound; - - separatorLength = Separator->Length; - goto SeparatorFound; - } - - // Special case for character sets with only one character. - if (!(Flags & PH_SPLIT_COMPLEMENT_CHAR_SET) && Separator->Length == sizeof(WCHAR)) - { - if (!(Flags & PH_SPLIT_START_AT_END)) - separatorIndex = PhFindCharInStringRef(Input, Separator->Buffer[0], !!(Flags & PH_SPLIT_CASE_INSENSITIVE)); - else - separatorIndex = PhFindLastCharInStringRef(Input, Separator->Buffer[0], !!(Flags & PH_SPLIT_CASE_INSENSITIVE)); - - if (separatorIndex == -1) - goto SeparatorNotFound; - - separatorLength = sizeof(WCHAR); - goto SeparatorFound; - } - - if (input.Length == 0) - goto SeparatorNotFound; - - // Build the character set lookup table. - - charSet = Separator->Buffer; - charSetCount = Separator->Length / sizeof(WCHAR); - memset(charSetTable, 0, sizeof(charSetTable)); - charSetTableComplete = TRUE; - - for (i = 0; i < charSetCount; i++) - { - c = charSet[i]; - - if (Flags & PH_SPLIT_CASE_INSENSITIVE) - c = RtlUpcaseUnicodeChar(c); - - charSetTable[c & 0xff] = TRUE; - - if (c >= 256) - charSetTableComplete = FALSE; - } - - // Perform the search. - - i = input.Length / sizeof(WCHAR); - separatorLength = sizeof(WCHAR); - - if (!(Flags & PH_SPLIT_START_AT_END)) - { - s = input.Buffer; - direction = 1; - } - else - { - s = (PWCHAR)((PCHAR)input.Buffer + input.Length - sizeof(WCHAR)); - direction = -1; - } - - do - { - c = *s; - - if (Flags & PH_SPLIT_CASE_INSENSITIVE) - c = RtlUpcaseUnicodeChar(c); - - if (c < 256 && charSetTableComplete) - { - if (!(Flags & PH_SPLIT_COMPLEMENT_CHAR_SET)) - { - if (charSetTable[c]) - goto CharFound; - } - else - { - if (!charSetTable[c]) - goto CharFound; - } - } - else - { - if (!(Flags & PH_SPLIT_COMPLEMENT_CHAR_SET)) - { - if (charSetTable[c & 0xff]) - { - if (!(Flags & PH_SPLIT_CASE_INSENSITIVE) || (Flags & PH_SPLIT_CHAR_SET_IS_UPPERCASE)) - { - for (j = 0; j < charSetCount; j++) - { - if (charSet[j] == c) - goto CharFound; - } - } - else - { - for (j = 0; j < charSetCount; j++) - { - if (RtlUpcaseUnicodeChar(charSet[j]) == c) - goto CharFound; - } - } - } - } - else - { - if (charSetTable[c & 0xff]) - { - if (!(Flags & PH_SPLIT_CASE_INSENSITIVE) || (Flags & PH_SPLIT_CHAR_SET_IS_UPPERCASE)) - { - for (j = 0; j < charSetCount; j++) - { - if (charSet[j] == c) - break; - } - } - else - { - for (j = 0; j < charSetCount; j++) - { - if (RtlUpcaseUnicodeChar(charSet[j]) == c) - break; - } - } - - if (j == charSetCount) - goto CharFound; - } - else - { - goto CharFound; - } - } - } - - s += direction; - } while (--i != 0); - - goto SeparatorNotFound; - -CharFound: - separatorIndex = s - input.Buffer; - -SeparatorFound: - FirstPart->Buffer = input.Buffer; - FirstPart->Length = separatorIndex * sizeof(WCHAR); - SecondPart->Buffer = (PWCHAR)((PCHAR)input.Buffer + separatorIndex * sizeof(WCHAR) + separatorLength); - SecondPart->Length = input.Length - separatorIndex * sizeof(WCHAR) - separatorLength; - - if (SeparatorPart) - { - SeparatorPart->Buffer = input.Buffer + separatorIndex; - SeparatorPart->Length = separatorLength; - } - - return TRUE; - -SeparatorNotFound: - FirstPart->Buffer = input.Buffer; - FirstPart->Length = input.Length; - SecondPart->Buffer = NULL; - SecondPart->Length = 0; - - if (SeparatorPart) - { - SeparatorPart->Buffer = NULL; - SeparatorPart->Length = 0; - } - - return FALSE; -} - -VOID PhTrimStringRef( - _Inout_ PPH_STRINGREF String, - _In_ PPH_STRINGREF CharSet, - _In_ ULONG Flags - ) -{ - PWCHAR charSet; - SIZE_T charSetCount; - BOOLEAN charSetTable[256]; - BOOLEAN charSetTableComplete; - SIZE_T i; - SIZE_T j; - USHORT c; - SIZE_T trimCount; - SIZE_T count; - PWCHAR s; - - if (String->Length == 0 || CharSet->Length == 0) - return; - - if (CharSet->Length == sizeof(WCHAR)) - { - c = CharSet->Buffer[0]; - - if (!(Flags & PH_TRIM_END_ONLY)) - { - trimCount = 0; - count = String->Length / sizeof(WCHAR); - s = String->Buffer; - - while (count-- != 0) - { - if (*s++ != c) - break; - - trimCount++; - } - - PhSkipStringRef(String, trimCount * sizeof(WCHAR)); - } - - if (!(Flags & PH_TRIM_START_ONLY)) - { - trimCount = 0; - count = String->Length / sizeof(WCHAR); - s = (PWCHAR)((PCHAR)String->Buffer + String->Length - sizeof(WCHAR)); - - while (count-- != 0) - { - if (*s-- != c) - break; - - trimCount++; - } - - String->Length -= trimCount * sizeof(WCHAR); - } - - return; - } - - // Build the character set lookup table. - - charSet = CharSet->Buffer; - charSetCount = CharSet->Length / sizeof(WCHAR); - memset(charSetTable, 0, sizeof(charSetTable)); - charSetTableComplete = TRUE; - - for (i = 0; i < charSetCount; i++) - { - c = charSet[i]; - charSetTable[c & 0xff] = TRUE; - - if (c >= 256) - charSetTableComplete = FALSE; - } - - // Trim the string. - - if (!(Flags & PH_TRIM_END_ONLY)) - { - trimCount = 0; - count = String->Length / sizeof(WCHAR); - s = String->Buffer; - - while (count-- != 0) - { - c = *s++; - - if (!charSetTable[c & 0xff]) - break; - - if (!charSetTableComplete) - { - for (j = 0; j < charSetCount; j++) - { - if (charSet[j] == c) - goto CharFound; - } - - break; - } - -CharFound: - trimCount++; - } - - PhSkipStringRef(String, trimCount * sizeof(WCHAR)); - } - - if (!(Flags & PH_TRIM_START_ONLY)) - { - trimCount = 0; - count = String->Length / sizeof(WCHAR); - s = (PWCHAR)((PCHAR)String->Buffer + String->Length - sizeof(WCHAR)); - - while (count-- != 0) - { - c = *s--; - - if (!charSetTable[c & 0xff]) - break; - - if (!charSetTableComplete) - { - for (j = 0; j < charSetCount; j++) - { - if (charSet[j] == c) - goto CharFound2; - } - - break; - } - -CharFound2: - trimCount++; - } - - String->Length -= trimCount * sizeof(WCHAR); - } -} - -/** - * Creates a string object from an existing null-terminated string. - * - * \param Buffer A null-terminated Unicode string. - */ -PPH_STRING PhCreateString( - _In_ PWSTR Buffer - ) -{ - return PhCreateStringEx(Buffer, wcslen(Buffer) * sizeof(WCHAR)); -} - -/** - * Creates a string object using a specified length. - * - * \param Buffer A null-terminated Unicode string. - * \param Length The length, in bytes, of the string. - */ -PPH_STRING PhCreateStringEx( - _In_opt_ PWCHAR Buffer, - _In_ SIZE_T Length - ) -{ - PPH_STRING string; - - string = PhCreateObject( - FIELD_OFFSET(PH_STRING, Data) + Length + sizeof(WCHAR), // Null terminator - PhStringType - ); - - assert(!(Length & 1)); - string->Length = Length; - string->Buffer = string->Data; - *(PWCHAR)((PCHAR)string->Buffer + Length) = 0; - - if (Buffer) - { - memcpy(string->Buffer, Buffer, Length); - } - - return string; -} - -/** - * Obtains a reference to a zero-length string. - */ -PPH_STRING PhReferenceEmptyString( - VOID - ) -{ - PPH_STRING string; - PPH_STRING newString; - - string = PhSharedEmptyString; - - if (!string) - { - newString = PhCreateStringEx(NULL, 0); - - string = _InterlockedCompareExchangePointer( - &PhSharedEmptyString, - newString, - NULL - ); - - if (!string) - { - string = newString; // success - } - else - { - PhDereferenceObject(newString); - } - } - - return PhReferenceObject(string); -} - -/** - * Concatenates multiple strings. - * - * \param Count The number of strings to concatenate. - */ -PPH_STRING PhConcatStrings( - _In_ ULONG Count, - ... - ) -{ - va_list argptr; - - va_start(argptr, Count); - - return PhConcatStrings_V(Count, argptr); -} - -/** - * Concatenates multiple strings. - * - * \param Count The number of strings to concatenate. - * \param ArgPtr A pointer to an array of strings. - */ -PPH_STRING PhConcatStrings_V( - _In_ ULONG Count, - _In_ va_list ArgPtr - ) -{ - va_list argptr; - ULONG i; - SIZE_T totalLength = 0; - SIZE_T stringLength; - SIZE_T cachedLengths[PH_CONCAT_STRINGS_LENGTH_CACHE_SIZE]; - PWSTR arg; - PPH_STRING string; - - // Compute the total length, in bytes, of the strings. - - argptr = ArgPtr; - - for (i = 0; i < Count; i++) - { - arg = va_arg(argptr, PWSTR); - stringLength = PhCountStringZ(arg) * sizeof(WCHAR); - totalLength += stringLength; - - if (i < PH_CONCAT_STRINGS_LENGTH_CACHE_SIZE) - cachedLengths[i] = stringLength; - } - - // Create the string. - - string = PhCreateStringEx(NULL, totalLength); - totalLength = 0; - - // Append the strings one by one. - - argptr = ArgPtr; - - for (i = 0; i < Count; i++) - { - arg = va_arg(argptr, PWSTR); - - if (i < PH_CONCAT_STRINGS_LENGTH_CACHE_SIZE) - stringLength = cachedLengths[i]; - else - stringLength = PhCountStringZ(arg) * sizeof(WCHAR); - - memcpy( - (PCHAR)string->Buffer + totalLength, - arg, - stringLength - ); - totalLength += stringLength; - } - - return string; -} - -/** - * Concatenates two strings. - * - * \param String1 The first string. - * \param String2 The second string. - */ -PPH_STRING PhConcatStrings2( - _In_ PWSTR String1, - _In_ PWSTR String2 - ) -{ - PPH_STRING string; - SIZE_T length1; - SIZE_T length2; - - length1 = PhCountStringZ(String1) * sizeof(WCHAR); - length2 = PhCountStringZ(String2) * sizeof(WCHAR); - string = PhCreateStringEx(NULL, length1 + length2); - memcpy( - string->Buffer, - String1, - length1 - ); - memcpy( - (PCHAR)string->Buffer + length1, - String2, - length2 - ); - - return string; -} - -/** - * Concatenates two strings. - * - * \param String1 The first string. - * \param String2 The second string. - */ -PPH_STRING PhConcatStringRef2( - _In_ PPH_STRINGREF String1, - _In_ PPH_STRINGREF String2 - ) -{ - PPH_STRING string; - - assert(!(String1->Length & 1)); - assert(!(String2->Length & 1)); - - string = PhCreateStringEx(NULL, String1->Length + String2->Length); - memcpy(string->Buffer, String1->Buffer, String1->Length); - memcpy((PCHAR)string->Buffer + String1->Length, String2->Buffer, String2->Length); - - return string; -} - -/** - * Concatenates three strings. - * - * \param String1 The first string. - * \param String2 The second string. - * \param String3 The third string. - */ -PPH_STRING PhConcatStringRef3( - _In_ PPH_STRINGREF String1, - _In_ PPH_STRINGREF String2, - _In_ PPH_STRINGREF String3 - ) -{ - PPH_STRING string; - PCHAR buffer; - - assert(!(String1->Length & 1)); - assert(!(String2->Length & 1)); - assert(!(String3->Length & 1)); - - string = PhCreateStringEx(NULL, String1->Length + String2->Length + String3->Length); - - buffer = (PCHAR)string->Buffer; - memcpy(buffer, String1->Buffer, String1->Length); - - buffer += String1->Length; - memcpy(buffer, String2->Buffer, String2->Length); - - buffer += String2->Length; - memcpy(buffer, String3->Buffer, String3->Length); - - return string; -} - -/** - * Creates a string using format specifiers. - * - * \param Format The format-control string. - */ -PPH_STRING PhFormatString( - _In_ _Printf_format_string_ PWSTR Format, - ... - ) -{ - va_list argptr; - - va_start(argptr, Format); - - return PhFormatString_V(Format, argptr); -} - -/** - * Creates a string using format specifiers. - * - * \param Format The format-control string. - * \param ArgPtr A pointer to the list of arguments. - */ -PPH_STRING PhFormatString_V( - _In_ _Printf_format_string_ PWSTR Format, - _In_ va_list ArgPtr - ) -{ - PPH_STRING string; - int length; - - length = _vscwprintf(Format, ArgPtr); - - if (length == -1) - return NULL; - - string = PhCreateStringEx(NULL, length * sizeof(WCHAR)); - _vsnwprintf(string->Buffer, length, Format, ArgPtr); - - return string; -} - -/** - * Creates a bytes object from an existing null-terminated string of bytes. - * - * \param Buffer A null-terminated byte string. - */ -PPH_BYTES PhCreateBytes( - _In_ PSTR Buffer - ) -{ - return PhCreateBytesEx(Buffer, strlen(Buffer) * sizeof(CHAR)); -} - -/** - * Creates a bytes object. - * - * \param Buffer An array of bytes. - * \param Length The length of \a Buffer, in bytes. - */ -PPH_BYTES PhCreateBytesEx( - _In_opt_ PCHAR Buffer, - _In_ SIZE_T Length - ) -{ - PPH_BYTES bytes; - - bytes = PhCreateObject( - FIELD_OFFSET(PH_BYTES, Data) + Length + sizeof(CHAR), // Null terminator for compatibility - PhBytesType - ); - - bytes->Length = Length; - bytes->Buffer = bytes->Data; - bytes->Buffer[Length] = 0; - - if (Buffer) - { - memcpy(bytes->Buffer, Buffer, Length); - } - - return bytes; -} - -BOOLEAN PhWriteUnicodeDecoder( - _Inout_ PPH_UNICODE_DECODER Decoder, - _In_ ULONG CodeUnit - ) -{ - switch (Decoder->Encoding) - { - case PH_UNICODE_UTF8: - if (Decoder->InputCount >= 4) - return FALSE; - Decoder->u.Utf8.Input[Decoder->InputCount] = (UCHAR)CodeUnit; - Decoder->InputCount++; - return TRUE; - case PH_UNICODE_UTF16: - if (Decoder->InputCount >= 2) - return FALSE; - Decoder->u.Utf16.Input[Decoder->InputCount] = (USHORT)CodeUnit; - Decoder->InputCount++; - return TRUE; - case PH_UNICODE_UTF32: - if (Decoder->InputCount >= 1) - return FALSE; - Decoder->u.Utf32.Input = CodeUnit; - Decoder->InputCount = 1; - return TRUE; - default: - PhRaiseStatus(STATUS_UNSUCCESSFUL); - } -} - -BOOLEAN PhpReadUnicodeDecoder( - _Inout_ PPH_UNICODE_DECODER Decoder, - _Out_ PULONG CodeUnit - ) -{ - switch (Decoder->Encoding) - { - case PH_UNICODE_UTF8: - if (Decoder->InputCount == 0) - return FALSE; - *CodeUnit = Decoder->u.Utf8.Input[0]; - Decoder->u.Utf8.Input[0] = Decoder->u.Utf8.Input[1]; - Decoder->u.Utf8.Input[1] = Decoder->u.Utf8.Input[2]; - Decoder->u.Utf8.Input[2] = Decoder->u.Utf8.Input[3]; - Decoder->InputCount--; - return TRUE; - case PH_UNICODE_UTF16: - if (Decoder->InputCount == 0) - return FALSE; - *CodeUnit = Decoder->u.Utf16.Input[0]; - Decoder->u.Utf16.Input[0] = Decoder->u.Utf16.Input[1]; - Decoder->InputCount--; - return TRUE; - case PH_UNICODE_UTF32: - if (Decoder->InputCount == 0) - return FALSE; - *CodeUnit = Decoder->u.Utf32.Input; - Decoder->InputCount--; - return TRUE; - default: - PhRaiseStatus(STATUS_UNSUCCESSFUL); - } -} - -VOID PhpUnreadUnicodeDecoder( - _Inout_ PPH_UNICODE_DECODER Decoder, - _In_ ULONG CodeUnit - ) -{ - switch (Decoder->Encoding) - { - case PH_UNICODE_UTF8: - if (Decoder->InputCount >= 4) - PhRaiseStatus(STATUS_UNSUCCESSFUL); - Decoder->u.Utf8.Input[3] = Decoder->u.Utf8.Input[2]; - Decoder->u.Utf8.Input[2] = Decoder->u.Utf8.Input[1]; - Decoder->u.Utf8.Input[1] = Decoder->u.Utf8.Input[0]; - Decoder->u.Utf8.Input[0] = (UCHAR)CodeUnit; - Decoder->InputCount++; - break; - case PH_UNICODE_UTF16: - if (Decoder->InputCount >= 2) - PhRaiseStatus(STATUS_UNSUCCESSFUL); - Decoder->u.Utf16.Input[1] = Decoder->u.Utf16.Input[0]; - Decoder->u.Utf16.Input[0] = (USHORT)CodeUnit; - Decoder->InputCount++; - break; - case PH_UNICODE_UTF32: - if (Decoder->InputCount >= 1) - PhRaiseStatus(STATUS_UNSUCCESSFUL); - Decoder->u.Utf32.Input = CodeUnit; - Decoder->InputCount = 1; - break; - default: - PhRaiseStatus(STATUS_UNSUCCESSFUL); - } -} - -BOOLEAN PhpDecodeUtf8Error( - _Inout_ PPH_UNICODE_DECODER Decoder, - _Out_ PULONG CodePoint, - _In_ ULONG Which - ) -{ - if (Which >= 4) - PhpUnreadUnicodeDecoder(Decoder, Decoder->u.Utf8.CodeUnit4); - if (Which >= 3) - PhpUnreadUnicodeDecoder(Decoder, Decoder->u.Utf8.CodeUnit3); - if (Which >= 2) - PhpUnreadUnicodeDecoder(Decoder, Decoder->u.Utf8.CodeUnit2); - - *CodePoint = (ULONG)Decoder->u.Utf8.CodeUnit1 + 0xdc00; - Decoder->State = 0; - - return TRUE; -} - -BOOLEAN PhDecodeUnicodeDecoder( - _Inout_ PPH_UNICODE_DECODER Decoder, - _Out_ PULONG CodePoint - ) -{ - ULONG codeUnit; - - while (TRUE) - { - switch (Decoder->Encoding) - { - case PH_UNICODE_UTF8: - if (!PhpReadUnicodeDecoder(Decoder, &codeUnit)) - return FALSE; - - switch (Decoder->State) - { - case 0: - Decoder->u.Utf8.CodeUnit1 = (UCHAR)codeUnit; - - if (codeUnit < 0x80) - { - *CodePoint = codeUnit; - return TRUE; - } - else if (codeUnit < 0xc2) - { - return PhpDecodeUtf8Error(Decoder, CodePoint, 1); - } - else if (codeUnit < 0xe0) - { - Decoder->State = 1; // 2 byte sequence - continue; - } - else if (codeUnit < 0xf0) - { - Decoder->State = 2; // 3 byte sequence - continue; - } - else if (codeUnit < 0xf5) - { - Decoder->State = 3; // 4 byte sequence - continue; - } - else - { - return PhpDecodeUtf8Error(Decoder, CodePoint, 1); - } - - break; - case 1: // 2 byte sequence - Decoder->u.Utf8.CodeUnit2 = (UCHAR)codeUnit; - - if ((codeUnit & 0xc0) == 0x80) - { - *CodePoint = ((ULONG)Decoder->u.Utf8.CodeUnit1 << 6) + codeUnit - 0x3080; - Decoder->State = 0; - return TRUE; - } - else - { - return PhpDecodeUtf8Error(Decoder, CodePoint, 2); - } - - break; - case 2: // 3 byte sequence (1) - Decoder->u.Utf8.CodeUnit2 = (UCHAR)codeUnit; - - if (((codeUnit & 0xc0) == 0x80) && - (Decoder->u.Utf8.CodeUnit1 != 0xe0 || codeUnit >= 0xa0)) - { - Decoder->State = 4; // 3 byte sequence (2) - continue; - } - else - { - return PhpDecodeUtf8Error(Decoder, CodePoint, 2); - } - - break; - case 3: // 4 byte sequence (1) - Decoder->u.Utf8.CodeUnit2 = (UCHAR)codeUnit; - - if (((codeUnit & 0xc0) == 0x80) && - (Decoder->u.Utf8.CodeUnit1 != 0xf0 || codeUnit >= 0x90) && - (Decoder->u.Utf8.CodeUnit1 != 0xf4 || codeUnit < 0x90)) - { - Decoder->State = 5; // 4 byte sequence (2) - continue; - } - else - { - return PhpDecodeUtf8Error(Decoder, CodePoint, 2); - } - - break; - case 4: // 3 byte sequence (2) - Decoder->u.Utf8.CodeUnit3 = (UCHAR)codeUnit; - - if ((codeUnit & 0xc0) == 0x80) - { - *CodePoint = - ((ULONG)Decoder->u.Utf8.CodeUnit1 << 12) + - ((ULONG)Decoder->u.Utf8.CodeUnit2 << 6) + - codeUnit - 0xe2080; - Decoder->State = 0; - return TRUE; - } - else - { - return PhpDecodeUtf8Error(Decoder, CodePoint, 3); - } - - break; - case 5: // 4 byte sequence (2) - Decoder->u.Utf8.CodeUnit3 = (UCHAR)codeUnit; - - if ((codeUnit & 0xc0) == 0x80) - { - Decoder->State = 6; // 4 byte sequence (3) - continue; - } - else - { - return PhpDecodeUtf8Error(Decoder, CodePoint, 3); - } - - break; - case 6: // 4 byte sequence (3) - Decoder->u.Utf8.CodeUnit4 = (UCHAR)codeUnit; - - if ((codeUnit & 0xc0) == 0x80) - { - *CodePoint = - ((ULONG)Decoder->u.Utf8.CodeUnit1 << 18) + - ((ULONG)Decoder->u.Utf8.CodeUnit2 << 12) + - ((ULONG)Decoder->u.Utf8.CodeUnit3 << 6) + - codeUnit - 0x3c82080; - Decoder->State = 0; - return TRUE; - } - else - { - return PhpDecodeUtf8Error(Decoder, CodePoint, 4); - } - - break; - } - - return FALSE; - case PH_UNICODE_UTF16: - if (!PhpReadUnicodeDecoder(Decoder, &codeUnit)) - return FALSE; - - switch (Decoder->State) - { - case 0: - if (PH_UNICODE_UTF16_IS_HIGH_SURROGATE(codeUnit)) - { - Decoder->u.Utf16.CodeUnit = (USHORT)codeUnit; - Decoder->State = 1; - continue; - } - else - { - *CodePoint = codeUnit; - return TRUE; - } - break; - case 1: - if (PH_UNICODE_UTF16_IS_LOW_SURROGATE(codeUnit)) - { - *CodePoint = PH_UNICODE_UTF16_TO_CODE_POINT(Decoder->u.Utf16.CodeUnit, codeUnit); - Decoder->State = 0; - return TRUE; - } - else - { - *CodePoint = Decoder->u.Utf16.CodeUnit; - PhpUnreadUnicodeDecoder(Decoder, codeUnit); - Decoder->State = 0; - return TRUE; - } - break; - } - - return FALSE; - case PH_UNICODE_UTF32: - if (PhpReadUnicodeDecoder(Decoder, CodePoint)) - return TRUE; - return FALSE; - default: - return FALSE; - } - } -} - -BOOLEAN PhEncodeUnicode( - _In_ UCHAR Encoding, - _In_ ULONG CodePoint, - _Out_opt_ PVOID CodeUnits, - _Out_ PULONG NumberOfCodeUnits - ) -{ - switch (Encoding) - { - case PH_UNICODE_UTF8: - { - PUCHAR codeUnits = CodeUnits; - - if (CodePoint < 0x80) - { - *NumberOfCodeUnits = 1; - - if (codeUnits) - codeUnits[0] = (UCHAR)CodePoint; - } - else if (CodePoint <= 0x7ff) - { - *NumberOfCodeUnits = 2; - - if (codeUnits) - { - codeUnits[0] = (UCHAR)(CodePoint >> 6) + 0xc0; - codeUnits[1] = (UCHAR)(CodePoint & 0x3f) + 0x80; - } - } - else if (CodePoint <= 0xffff) - { - *NumberOfCodeUnits = 3; - - if (codeUnits) - { - codeUnits[0] = (UCHAR)(CodePoint >> 12) + 0xe0; - codeUnits[1] = (UCHAR)((CodePoint >> 6) & 0x3f) + 0x80; - codeUnits[2] = (UCHAR)(CodePoint & 0x3f) + 0x80; - } - } - else if (CodePoint <= PH_UNICODE_MAX_CODE_POINT) - { - *NumberOfCodeUnits = 4; - - if (codeUnits) - { - codeUnits[0] = (UCHAR)(CodePoint >> 18) + 0xf0; - codeUnits[1] = (UCHAR)((CodePoint >> 12) & 0x3f) + 0x80; - codeUnits[2] = (UCHAR)((CodePoint >> 6) & 0x3f) + 0x80; - codeUnits[3] = (UCHAR)(CodePoint & 0x3f) + 0x80; - } - } - else - { - return FALSE; - } - } - return TRUE; - case PH_UNICODE_UTF16: - { - PUSHORT codeUnits = CodeUnits; - - if (CodePoint < 0x10000) - { - *NumberOfCodeUnits = 1; - - if (codeUnits) - codeUnits[0] = (USHORT)CodePoint; - } - else if (CodePoint <= PH_UNICODE_MAX_CODE_POINT) - { - *NumberOfCodeUnits = 2; - - if (codeUnits) - { - codeUnits[0] = PH_UNICODE_UTF16_TO_HIGH_SURROGATE(CodePoint); - codeUnits[1] = PH_UNICODE_UTF16_TO_LOW_SURROGATE(CodePoint); - } - } - else - { - return FALSE; - } - } - return TRUE; - case PH_UNICODE_UTF32: - *NumberOfCodeUnits = 1; - if (CodeUnits) - *(PULONG)CodeUnits = CodePoint; - return TRUE; - default: - return FALSE; - } -} - -/** - * Converts an ASCII string to a UTF-16 string by zero-extending each byte. - * - * \param Input The original ASCII string. - * \param InputLength The length of \a Input. - * \param Output A buffer which will contain the converted string. - */ -VOID PhZeroExtendToUtf16Buffer( - _In_reads_bytes_(InputLength) PCH Input, - _In_ SIZE_T InputLength, - _Out_writes_bytes_(InputLength * sizeof(WCHAR)) PWCH Output - ) -{ - SIZE_T inputLength; - - inputLength = InputLength & -4; - - if (inputLength) - { - do - { - Output[0] = C_1uTo2(Input[0]); - Output[1] = C_1uTo2(Input[1]); - Output[2] = C_1uTo2(Input[2]); - Output[3] = C_1uTo2(Input[3]); - Input += 4; - Output += 4; - inputLength -= 4; - } while (inputLength != 0); - } - - switch (InputLength & 3) - { - case 3: - *Output++ = C_1uTo2(*Input++); - case 2: - *Output++ = C_1uTo2(*Input++); - case 1: - *Output++ = C_1uTo2(*Input++); - } -} - -PPH_STRING PhZeroExtendToUtf16Ex( - _In_reads_bytes_(InputLength) PCH Input, - _In_ SIZE_T InputLength - ) -{ - PPH_STRING string; - - string = PhCreateStringEx(NULL, InputLength * sizeof(WCHAR)); - PhZeroExtendToUtf16Buffer(Input, InputLength, string->Buffer); - - return string; -} - -PPH_BYTES PhConvertUtf16ToAsciiEx( - _In_ PWCH Buffer, - _In_ SIZE_T Length, - _In_opt_ CHAR Replacement - ) -{ - PPH_BYTES bytes; - PH_UNICODE_DECODER decoder; - PWCH in; - SIZE_T inRemaining; - PCH out; - SIZE_T outLength; - ULONG codePoint; - - bytes = PhCreateBytesEx(NULL, Length / sizeof(WCHAR)); - PhInitializeUnicodeDecoder(&decoder, PH_UNICODE_UTF16); - in = Buffer; - inRemaining = Length / sizeof(WCHAR); - out = bytes->Buffer; - outLength = 0; - - while (inRemaining != 0) - { - PhWriteUnicodeDecoder(&decoder, (USHORT)*in); - in++; - inRemaining--; - - while (PhDecodeUnicodeDecoder(&decoder, &codePoint)) - { - if (codePoint < 0x80) - { - *out++ = (CHAR)codePoint; - outLength++; - } - else if (Replacement) - { - *out++ = Replacement; - outLength++; - } - } - } - - bytes->Length = outLength; - bytes->Buffer[outLength] = 0; - - return bytes; -} - -/** - * Creates a string object from an existing null-terminated multi-byte string. - * - * \param Buffer A null-terminated multi-byte string. - */ -PPH_STRING PhConvertMultiByteToUtf16( - _In_ PSTR Buffer - ) -{ - return PhConvertMultiByteToUtf16Ex( - Buffer, - strlen(Buffer) - ); -} - -/** - * Creates a string object from an existing null-terminated multi-byte string. - * - * \param Buffer A null-terminated multi-byte string. - * \param Length The number of bytes to use. - */ -PPH_STRING PhConvertMultiByteToUtf16Ex( - _In_ PCHAR Buffer, - _In_ SIZE_T Length - ) -{ - NTSTATUS status; - PPH_STRING string; - ULONG unicodeBytes; - - status = RtlMultiByteToUnicodeSize( - &unicodeBytes, - Buffer, - (ULONG)Length - ); - - if (!NT_SUCCESS(status)) - return NULL; - - string = PhCreateStringEx(NULL, unicodeBytes); - status = RtlMultiByteToUnicodeN( - string->Buffer, - (ULONG)string->Length, - NULL, - Buffer, - (ULONG)Length - ); - - if (!NT_SUCCESS(status)) - { - PhDereferenceObject(string); - return NULL; - } - - return string; -} - -/** - * Creates a multi-byte string from an existing null-terminated UTF-16 string. - * - * \param Buffer A null-terminated UTF-16 string. - */ -PPH_BYTES PhConvertUtf16ToMultiByte( - _In_ PWSTR Buffer - ) -{ - return PhConvertUtf16ToMultiByteEx( - Buffer, - PhCountStringZ(Buffer) * sizeof(WCHAR) - ); -} - -/** - * Creates a multi-byte string from an existing null-terminated UTF-16 string. - * - * \param Buffer A null-terminated UTF-16 string. - * \param Length The number of bytes to use. - */ -PPH_BYTES PhConvertUtf16ToMultiByteEx( - _In_ PWCHAR Buffer, - _In_ SIZE_T Length - ) -{ - NTSTATUS status; - PPH_BYTES bytes; - ULONG multiByteLength; - - status = RtlUnicodeToMultiByteSize( - &multiByteLength, - Buffer, - (ULONG)Length - ); - - if (!NT_SUCCESS(status)) - return NULL; - - bytes = PhCreateBytesEx(NULL, multiByteLength); - status = RtlUnicodeToMultiByteN( - bytes->Buffer, - (ULONG)bytes->Length, - NULL, - Buffer, - (ULONG)Length - ); - - if (!NT_SUCCESS(status)) - { - PhDereferenceObject(bytes); - return NULL; - } - - return bytes; -} - -BOOLEAN PhConvertUtf8ToUtf16Size( - _Out_ PSIZE_T BytesInUtf16String, - _In_reads_bytes_(BytesInUtf8String) PCH Utf8String, - _In_ SIZE_T BytesInUtf8String - ) -{ - BOOLEAN result; - PH_UNICODE_DECODER decoder; - PCH in; - SIZE_T inRemaining; - SIZE_T bytesInUtf16String; - ULONG codePoint; - ULONG numberOfCodeUnits; - - result = TRUE; - PhInitializeUnicodeDecoder(&decoder, PH_UNICODE_UTF8); - in = Utf8String; - inRemaining = BytesInUtf8String; - bytesInUtf16String = 0; - - while (inRemaining != 0) - { - PhWriteUnicodeDecoder(&decoder, (UCHAR)*in); - in++; - inRemaining--; - - while (PhDecodeUnicodeDecoder(&decoder, &codePoint)) - { - if (PhEncodeUnicode(PH_UNICODE_UTF16, codePoint, NULL, &numberOfCodeUnits)) - bytesInUtf16String += numberOfCodeUnits * sizeof(WCHAR); - else - result = FALSE; - } - } - - *BytesInUtf16String = bytesInUtf16String; - - return result; -} - -BOOLEAN PhConvertUtf8ToUtf16Buffer( - _Out_writes_bytes_to_(MaxBytesInUtf16String, *BytesInUtf16String) PWCH Utf16String, - _In_ SIZE_T MaxBytesInUtf16String, - _Out_opt_ PSIZE_T BytesInUtf16String, - _In_reads_bytes_(BytesInUtf8String) PCH Utf8String, - _In_ SIZE_T BytesInUtf8String - ) -{ - BOOLEAN result; - PH_UNICODE_DECODER decoder; - PCH in; - SIZE_T inRemaining; - PWCH out; - SIZE_T outRemaining; - SIZE_T bytesInUtf16String; - ULONG codePoint; - USHORT codeUnits[2]; - ULONG numberOfCodeUnits; - - result = TRUE; - PhInitializeUnicodeDecoder(&decoder, PH_UNICODE_UTF8); - in = Utf8String; - inRemaining = BytesInUtf8String; - out = Utf16String; - outRemaining = MaxBytesInUtf16String / sizeof(WCHAR); - bytesInUtf16String = 0; - - while (inRemaining != 0) - { - PhWriteUnicodeDecoder(&decoder, (UCHAR)*in); - in++; - inRemaining--; - - while (PhDecodeUnicodeDecoder(&decoder, &codePoint)) - { - if (PhEncodeUnicode(PH_UNICODE_UTF16, codePoint, codeUnits, &numberOfCodeUnits)) - { - bytesInUtf16String += numberOfCodeUnits * sizeof(WCHAR); - - if (outRemaining >= numberOfCodeUnits) - { - *out++ = codeUnits[0]; - - if (numberOfCodeUnits >= 2) - *out++ = codeUnits[1]; - - outRemaining -= numberOfCodeUnits; - } - else - { - result = FALSE; - } - } - else - { - result = FALSE; - } - } - } - - if (BytesInUtf16String) - *BytesInUtf16String = bytesInUtf16String; - - return result; -} - -PPH_STRING PhConvertUtf8ToUtf16( - _In_ PSTR Buffer - ) -{ - return PhConvertUtf8ToUtf16Ex( - Buffer, - strlen(Buffer) - ); -} - -PPH_STRING PhConvertUtf8ToUtf16Ex( - _In_ PCHAR Buffer, - _In_ SIZE_T Length - ) -{ - PPH_STRING string; - SIZE_T utf16Bytes; - - if (!PhConvertUtf8ToUtf16Size( - &utf16Bytes, - Buffer, - Length - )) - { - return NULL; - } - - string = PhCreateStringEx(NULL, utf16Bytes); - - if (!PhConvertUtf8ToUtf16Buffer( - string->Buffer, - string->Length, - NULL, - Buffer, - Length - )) - { - PhDereferenceObject(string); - return NULL; - } - - return string; -} - -BOOLEAN PhConvertUtf16ToUtf8Size( - _Out_ PSIZE_T BytesInUtf8String, - _In_reads_bytes_(BytesInUtf16String) PWCH Utf16String, - _In_ SIZE_T BytesInUtf16String - ) -{ - BOOLEAN result; - PH_UNICODE_DECODER decoder; - PWCH in; - SIZE_T inRemaining; - SIZE_T bytesInUtf8String; - ULONG codePoint; - ULONG numberOfCodeUnits; - - result = TRUE; - PhInitializeUnicodeDecoder(&decoder, PH_UNICODE_UTF16); - in = Utf16String; - inRemaining = BytesInUtf16String / sizeof(WCHAR); - bytesInUtf8String = 0; - - while (inRemaining != 0) - { - PhWriteUnicodeDecoder(&decoder, (USHORT)*in); - in++; - inRemaining--; - - while (PhDecodeUnicodeDecoder(&decoder, &codePoint)) - { - if (PhEncodeUnicode(PH_UNICODE_UTF8, codePoint, NULL, &numberOfCodeUnits)) - bytesInUtf8String += numberOfCodeUnits; - else - result = FALSE; - } - } - - *BytesInUtf8String = bytesInUtf8String; - - return result; -} - -BOOLEAN PhConvertUtf16ToUtf8Buffer( - _Out_writes_bytes_to_(MaxBytesInUtf8String, *BytesInUtf8String) PCH Utf8String, - _In_ SIZE_T MaxBytesInUtf8String, - _Out_opt_ PSIZE_T BytesInUtf8String, - _In_reads_bytes_(BytesInUtf16String) PWCH Utf16String, - _In_ SIZE_T BytesInUtf16String - ) -{ - BOOLEAN result; - PH_UNICODE_DECODER decoder; - PWCH in; - SIZE_T inRemaining; - PCH out; - SIZE_T outRemaining; - SIZE_T bytesInUtf8String; - ULONG codePoint; - UCHAR codeUnits[4]; - ULONG numberOfCodeUnits; - - result = TRUE; - PhInitializeUnicodeDecoder(&decoder, PH_UNICODE_UTF16); - in = Utf16String; - inRemaining = BytesInUtf16String / sizeof(WCHAR); - out = Utf8String; - outRemaining = MaxBytesInUtf8String; - bytesInUtf8String = 0; - - while (inRemaining != 0) - { - PhWriteUnicodeDecoder(&decoder, (USHORT)*in); - in++; - inRemaining--; - - while (PhDecodeUnicodeDecoder(&decoder, &codePoint)) - { - if (PhEncodeUnicode(PH_UNICODE_UTF8, codePoint, codeUnits, &numberOfCodeUnits)) - { - bytesInUtf8String += numberOfCodeUnits; - - if (outRemaining >= numberOfCodeUnits) - { - *out++ = codeUnits[0]; - - if (numberOfCodeUnits >= 2) - *out++ = codeUnits[1]; - if (numberOfCodeUnits >= 3) - *out++ = codeUnits[2]; - if (numberOfCodeUnits >= 4) - *out++ = codeUnits[3]; - - outRemaining -= numberOfCodeUnits; - } - else - { - result = FALSE; - } - } - else - { - result = FALSE; - } - } - } - - if (BytesInUtf8String) - *BytesInUtf8String = bytesInUtf8String; - - return result; -} - -PPH_BYTES PhConvertUtf16ToUtf8( - _In_ PWSTR Buffer - ) -{ - return PhConvertUtf16ToUtf8Ex( - Buffer, - PhCountStringZ(Buffer) * sizeof(WCHAR) - ); -} - -PPH_BYTES PhConvertUtf16ToUtf8Ex( - _In_ PWCHAR Buffer, - _In_ SIZE_T Length - ) -{ - PPH_BYTES bytes; - SIZE_T utf8Bytes; - - if (!PhConvertUtf16ToUtf8Size( - &utf8Bytes, - Buffer, - Length - )) - { - return NULL; - } - - bytes = PhCreateBytesEx(NULL, utf8Bytes); - - if (!PhConvertUtf16ToUtf8Buffer( - bytes->Buffer, - bytes->Length, - NULL, - Buffer, - Length - )) - { - PhDereferenceObject(bytes); - return NULL; - } - - return bytes; -} - -/** - * Initializes a string builder object. - * - * \param StringBuilder A string builder object. - * \param InitialCapacity The number of bytes to allocate initially. - */ -VOID PhInitializeStringBuilder( - _Out_ PPH_STRING_BUILDER StringBuilder, - _In_ SIZE_T InitialCapacity - ) -{ - // Make sure the initial capacity is even, as required for all string objects. - if (InitialCapacity & 1) - InitialCapacity++; - - StringBuilder->AllocatedLength = InitialCapacity; - - // Allocate a PH_STRING for the string builder. - // We will dereference it and allocate a new one when we need to resize the string. - - StringBuilder->String = PhCreateStringEx(NULL, StringBuilder->AllocatedLength); - - // We will keep modifying the Length field of the string so that: - // 1. We know how much of the string is used, and - // 2. The user can simply get a reference to the string and use it as-is. - - StringBuilder->String->Length = 0; - - // Write the null terminator. - StringBuilder->String->Buffer[0] = 0; - - PHLIB_INC_STATISTIC(BaseStringBuildersCreated); -} - -/** - * Frees resources used by a string builder object. - * - * \param StringBuilder A string builder object. - */ -VOID PhDeleteStringBuilder( - _Inout_ PPH_STRING_BUILDER StringBuilder - ) -{ - PhDereferenceObject(StringBuilder->String); -} - -/** - * Obtains a reference to the string constructed by a string builder object and frees resources used - * by the object. - * - * \param StringBuilder A string builder object. - * - * \return A pointer to a string. You must free the string using PhDereferenceObject() when you no - * longer need it. - */ -PPH_STRING PhFinalStringBuilderString( - _Inout_ PPH_STRING_BUILDER StringBuilder - ) -{ - return StringBuilder->String; -} - -VOID PhpResizeStringBuilder( - _In_ PPH_STRING_BUILDER StringBuilder, - _In_ SIZE_T NewCapacity - ) -{ - PPH_STRING newString; - - // Double the string size. If that still isn't enough room, just use the new length. - - StringBuilder->AllocatedLength *= 2; - - if (StringBuilder->AllocatedLength < NewCapacity) - StringBuilder->AllocatedLength = NewCapacity; - - // Allocate a new string. - newString = PhCreateStringEx(NULL, StringBuilder->AllocatedLength); - - // Copy the old string to the new string. - memcpy( - newString->Buffer, - StringBuilder->String->Buffer, - StringBuilder->String->Length + sizeof(WCHAR) // Include null terminator - ); - - // Copy the old string length. - newString->Length = StringBuilder->String->Length; - - // Dereference the old string and replace it with the new string. - PhMoveReference(&StringBuilder->String, newString); - - PHLIB_INC_STATISTIC(BaseStringBuildersResized); -} - -FORCEINLINE VOID PhpWriteNullTerminatorStringBuilder( - _In_ PPH_STRING_BUILDER StringBuilder - ) -{ - assert(!(StringBuilder->String->Length & 1)); - *(PWCHAR)((PCHAR)StringBuilder->String->Buffer + StringBuilder->String->Length) = 0; -} - -/** - * Appends a string to the end of a string builder string. - * - * \param StringBuilder A string builder object. - * \param String The string to append. - */ -VOID PhAppendStringBuilder( - _Inout_ PPH_STRING_BUILDER StringBuilder, - _In_ PPH_STRINGREF String - ) -{ - PhAppendStringBuilderEx( - StringBuilder, - String->Buffer, - String->Length - ); -} - -/** - * Appends a string to the end of a string builder string. - * - * \param StringBuilder A string builder object. - * \param String The string to append. - */ -VOID PhAppendStringBuilder2( - _Inout_ PPH_STRING_BUILDER StringBuilder, - _In_ PWSTR String - ) -{ - PhAppendStringBuilderEx( - StringBuilder, - String, - PhCountStringZ(String) * sizeof(WCHAR) - ); -} - -/** - * Appends a string to the end of a string builder string. - * - * \param StringBuilder A string builder object. - * \param String The string to append. Specify NULL to simply reserve \a Length bytes. - * \param Length The number of bytes to append. - */ -VOID PhAppendStringBuilderEx( - _Inout_ PPH_STRING_BUILDER StringBuilder, - _In_opt_ PWCHAR String, - _In_ SIZE_T Length - ) -{ - if (Length == 0) - return; - - // See if we need to re-allocate the string. - if (StringBuilder->AllocatedLength < StringBuilder->String->Length + Length) - { - PhpResizeStringBuilder(StringBuilder, StringBuilder->String->Length + Length); - } - - // Copy the string, add the length, then write the null terminator. - - if (String) - { - memcpy( - (PCHAR)StringBuilder->String->Buffer + StringBuilder->String->Length, - String, - Length - ); - } - - StringBuilder->String->Length += Length; - PhpWriteNullTerminatorStringBuilder(StringBuilder); -} - -/** - * Appends a character to the end of a string builder string. - * - * \param StringBuilder A string builder object. - * \param Character The character to append. - */ -VOID PhAppendCharStringBuilder( - _Inout_ PPH_STRING_BUILDER StringBuilder, - _In_ WCHAR Character - ) -{ - if (StringBuilder->AllocatedLength < StringBuilder->String->Length + sizeof(WCHAR)) - { - PhpResizeStringBuilder(StringBuilder, StringBuilder->String->Length + sizeof(WCHAR)); - } - - *(PWCHAR)((PCHAR)StringBuilder->String->Buffer + StringBuilder->String->Length) = Character; - StringBuilder->String->Length += sizeof(WCHAR); - PhpWriteNullTerminatorStringBuilder(StringBuilder); -} - -/** - * Appends a number of characters to the end of a string builder string. - * - * \param StringBuilder A string builder object. - * \param Character The character to append. - * \param Count The number of times to append the character. - */ -VOID PhAppendCharStringBuilder2( - _Inout_ PPH_STRING_BUILDER StringBuilder, - _In_ WCHAR Character, - _In_ SIZE_T Count - ) -{ - if (Count == 0) - return; - - // See if we need to re-allocate the string. - if (StringBuilder->AllocatedLength < StringBuilder->String->Length + Count * sizeof(WCHAR)) - { - PhpResizeStringBuilder(StringBuilder, StringBuilder->String->Length + Count * sizeof(WCHAR)); - } - - wmemset( - (PWCHAR)((PCHAR)StringBuilder->String->Buffer + StringBuilder->String->Length), - Character, - Count - ); - - StringBuilder->String->Length += Count * sizeof(WCHAR); - PhpWriteNullTerminatorStringBuilder(StringBuilder); -} - -/** - * Appends a formatted string to the end of a string builder string. - * - * \param StringBuilder A string builder object. - * \param Format The format-control string. - */ -VOID PhAppendFormatStringBuilder( - _Inout_ PPH_STRING_BUILDER StringBuilder, - _In_ _Printf_format_string_ PWSTR Format, - ... - ) -{ - va_list argptr; - - va_start(argptr, Format); - PhAppendFormatStringBuilder_V(StringBuilder, Format, argptr); -} - -VOID PhAppendFormatStringBuilder_V( - _Inout_ PPH_STRING_BUILDER StringBuilder, - _In_ _Printf_format_string_ PWSTR Format, - _In_ va_list ArgPtr - ) -{ - int length; - SIZE_T lengthInBytes; - - length = _vscwprintf(Format, ArgPtr); - - if (length == -1 || length == 0) - return; - - lengthInBytes = length * sizeof(WCHAR); - - if (StringBuilder->AllocatedLength < StringBuilder->String->Length + lengthInBytes) - PhpResizeStringBuilder(StringBuilder, StringBuilder->String->Length + lengthInBytes); - - _vsnwprintf( - (PWCHAR)((PCHAR)StringBuilder->String->Buffer + StringBuilder->String->Length), - length, - Format, - ArgPtr - ); - - StringBuilder->String->Length += lengthInBytes; - PhpWriteNullTerminatorStringBuilder(StringBuilder); -} - -/** - * Inserts a string into a string builder string. - * - * \param StringBuilder A string builder object. - * \param Index The index, in characters, at which to insert the string. - * \param String The string to insert. - */ -VOID PhInsertStringBuilder( - _Inout_ PPH_STRING_BUILDER StringBuilder, - _In_ SIZE_T Index, - _In_ PPH_STRINGREF String - ) -{ - PhInsertStringBuilderEx( - StringBuilder, - Index, - String->Buffer, - String->Length - ); -} - -/** - * Inserts a string into a string builder string. - * - * \param StringBuilder A string builder object. - * \param Index The index, in characters, at which to insert the string. - * \param String The string to insert. - */ -VOID PhInsertStringBuilder2( - _Inout_ PPH_STRING_BUILDER StringBuilder, - _In_ SIZE_T Index, - _In_ PWSTR String - ) -{ - PhInsertStringBuilderEx( - StringBuilder, - Index, - String, - PhCountStringZ(String) * sizeof(WCHAR) - ); -} - -/** - * Inserts a string into a string builder string. - * - * \param StringBuilder A string builder object. - * \param Index The index, in characters, at which to insert the string. - * \param String The string to insert. Specify NULL to simply reserve \a Length bytes at \a Index. - * \param Length The number of bytes to insert. - */ -VOID PhInsertStringBuilderEx( - _Inout_ PPH_STRING_BUILDER StringBuilder, - _In_ SIZE_T Index, - _In_opt_ PWCHAR String, - _In_ SIZE_T Length - ) -{ - if (Length == 0) - return; - - // See if we need to re-allocate the string. - if (StringBuilder->AllocatedLength < StringBuilder->String->Length + Length) - { - PhpResizeStringBuilder(StringBuilder, StringBuilder->String->Length + Length); - } - - if (Index * sizeof(WCHAR) < StringBuilder->String->Length) - { - // Create some space for the string. - memmove( - &StringBuilder->String->Buffer[Index + Length / sizeof(WCHAR)], - &StringBuilder->String->Buffer[Index], - StringBuilder->String->Length - Index * sizeof(WCHAR) - ); - } - - if (String) - { - // Copy the new string. - memcpy( - &StringBuilder->String->Buffer[Index], - String, - Length - ); - } - - StringBuilder->String->Length += Length; - PhpWriteNullTerminatorStringBuilder(StringBuilder); -} - -/** - * Removes characters from a string builder string. - * - * \param StringBuilder A string builder object. - * \param StartIndex The index, in characters, at which to begin removing characters. - * \param Count The number of characters to remove. - */ -VOID PhRemoveStringBuilder( - _Inout_ PPH_STRING_BUILDER StringBuilder, - _In_ SIZE_T StartIndex, - _In_ SIZE_T Count - ) -{ - // Overwrite the removed part with the part - // behind it. - - memmove( - &StringBuilder->String->Buffer[StartIndex], - &StringBuilder->String->Buffer[StartIndex + Count], - StringBuilder->String->Length - (Count + StartIndex) * sizeof(WCHAR) - ); - StringBuilder->String->Length -= Count * sizeof(WCHAR); - PhpWriteNullTerminatorStringBuilder(StringBuilder); -} - -/** - * Initializes a byte string builder object. - * - * \param BytesBuilder A byte string builder object. - * \param InitialCapacity The number of bytes to allocate initially. - */ -VOID PhInitializeBytesBuilder( - _Out_ PPH_BYTES_BUILDER BytesBuilder, - _In_ SIZE_T InitialCapacity - ) -{ - BytesBuilder->AllocatedLength = InitialCapacity; - BytesBuilder->Bytes = PhCreateBytesEx(NULL, BytesBuilder->AllocatedLength); - BytesBuilder->Bytes->Length = 0; - BytesBuilder->Bytes->Buffer[0] = 0; -} - -/** - * Frees resources used by a byte string builder object. - * - * \param BytesBuilder A byte string builder object. - */ -VOID PhDeleteBytesBuilder( - _Inout_ PPH_BYTES_BUILDER BytesBuilder - ) -{ - PhDereferenceObject(BytesBuilder->Bytes); -} - -/** - * Obtains a reference to the byte string constructed by a byte string builder object and frees - * resources used by the object. - * - * \param BytesBuilder A byte string builder object. - * - * \return A pointer to a byte string. You must free the byte string using PhDereferenceObject() - * when you no longer need it. - */ -PPH_BYTES PhFinalBytesBuilderBytes( - _Inout_ PPH_BYTES_BUILDER BytesBuilder - ) -{ - return BytesBuilder->Bytes; -} - -VOID PhpResizeBytesBuilder( - _In_ PPH_BYTES_BUILDER BytesBuilder, - _In_ SIZE_T NewCapacity - ) -{ - PPH_BYTES newBytes; - - // Double the byte string size. If that still isn't enough room, just use the new length. - - BytesBuilder->AllocatedLength *= 2; - - if (BytesBuilder->AllocatedLength < NewCapacity) - BytesBuilder->AllocatedLength = NewCapacity; - - // Allocate a new byte string. - newBytes = PhCreateBytesEx(NULL, BytesBuilder->AllocatedLength); - - // Copy the old byte string to the new byte string. - memcpy( - newBytes->Buffer, - BytesBuilder->Bytes->Buffer, - BytesBuilder->Bytes->Length + sizeof(CHAR) // Include null terminator - ); - - // Copy the old byte string length. - newBytes->Length = BytesBuilder->Bytes->Length; - - // Dereference the old byte string and replace it with the new byte string. - PhMoveReference(&BytesBuilder->Bytes, newBytes); -} - -FORCEINLINE VOID PhpWriteNullTerminatorBytesBuilder( - _In_ PPH_BYTES_BUILDER BytesBuilder - ) -{ - BytesBuilder->Bytes->Buffer[BytesBuilder->Bytes->Length] = 0; -} - -/** - * Appends a byte string to the end of a byte string builder string. - * - * \param BytesBuilder A byte string builder object. - * \param Bytes The byte string to append. - */ -VOID PhAppendBytesBuilder( - _Inout_ PPH_BYTES_BUILDER BytesBuilder, - _In_ PPH_BYTESREF Bytes - ) -{ - PhAppendBytesBuilderEx( - BytesBuilder, - Bytes->Buffer, - Bytes->Length, - 0, - NULL - ); -} - -/** - * Appends a byte string to the end of a byte string builder string. - * - * \param BytesBuilder A byte string builder object. - * \param Bytes The byte string to append. - */ -VOID PhAppendBytesBuilder2( - _Inout_ PPH_BYTES_BUILDER BytesBuilder, - _In_ PCHAR Bytes - ) -{ - PhAppendBytesBuilderEx( - BytesBuilder, - Bytes, - strlen(Bytes), - 0, - NULL - ); -} - -/** - * Appends a byte string to the end of a byte string builder string. - * - * \param BytesBuilder A byte string builder object. - * \param Buffer The byte string to append. Specify NULL to simply reserve \a Length bytes. - * \param Length The number of bytes to append. - * \param Alignment The required alignment. This should not be greater than 8. - * \param Offset A variable which receives the byte offset of the appended or reserved bytes in the - * byte string builder string. - * - * \return A pointer to the appended or reserved bytes. - */ -PVOID PhAppendBytesBuilderEx( - _Inout_ PPH_BYTES_BUILDER BytesBuilder, - _In_opt_ PVOID Buffer, - _In_ SIZE_T Length, - _In_opt_ SIZE_T Alignment, - _Out_opt_ PSIZE_T Offset - ) -{ - SIZE_T currentLength; - - currentLength = BytesBuilder->Bytes->Length; - - if (Length == 0) - goto Done; - - if (Alignment) - currentLength = ALIGN_UP_BY(currentLength, Alignment); - - // See if we need to re-allocate the byte string. - if (BytesBuilder->AllocatedLength < currentLength + Length) - PhpResizeBytesBuilder(BytesBuilder, currentLength + Length); - - // Copy the byte string, add the length, then write the null terminator. - - if (Buffer) - memcpy(BytesBuilder->Bytes->Buffer + currentLength, Buffer, Length); - - BytesBuilder->Bytes->Length = currentLength + Length; - PhpWriteNullTerminatorBytesBuilder(BytesBuilder); - -Done: - if (Offset) - *Offset = currentLength; - - return BytesBuilder->Bytes->Buffer + currentLength; -} - -/** - * Creates an array object. - * - * \param Array An array object. - * \param ItemSize The size of each item, in bytes. - * \param InitialCapacity The number of elements to allocate storage for, initially. - */ -VOID PhInitializeArray( - _Out_ PPH_ARRAY Array, - _In_ SIZE_T ItemSize, - _In_ SIZE_T InitialCapacity - ) -{ - // Initial capacity of 0 is not allowed. - if (InitialCapacity == 0) - InitialCapacity = 1; - - Array->Count = 0; - Array->AllocatedCount = InitialCapacity; - Array->ItemSize = ItemSize; - Array->Items = PhAllocate(Array->AllocatedCount * ItemSize); -} - -/** - * Frees resources used by an array object. - * - * \param Array An array object. - */ -VOID PhDeleteArray( - _Inout_ PPH_ARRAY Array - ) -{ - PhFree(Array->Items); -} - -/** - * Obtains a copy of the array constructed by an array object and frees resources used by the - * object. - * - * \param Array An array object. - * - * \return The array buffer. - */ -PVOID PhFinalArrayItems( - _Inout_ PPH_ARRAY Array - ) -{ - return Array->Items; -} - -/** - * Resizes an array. - * - * \param Array An array object. - * \param NewCapacity The new required number of elements for which storage has been reserved. This - * must not be smaller than the current number of items in the array. - */ -VOID PhResizeArray( - _Inout_ PPH_ARRAY Array, - _In_ SIZE_T NewCapacity - ) -{ - if (Array->Count > NewCapacity) - PhRaiseStatus(STATUS_INVALID_PARAMETER_2); - - Array->AllocatedCount = NewCapacity; - Array->Items = PhReAllocate(Array->Items, Array->AllocatedCount * Array->ItemSize); -} - -/** - * Adds an item to an array. - * - * \param Array An array object. - * \param Item The item to add. - */ -VOID PhAddItemArray( - _Inout_ PPH_ARRAY Array, - _In_ PVOID Item - ) -{ - // See if we need to resize the list. - if (Array->Count == Array->AllocatedCount) - { - Array->AllocatedCount *= 2; - Array->Items = PhReAllocate(Array->Items, Array->AllocatedCount * Array->ItemSize); - } - - memcpy(PhItemArray(Array, Array->Count), Item, Array->ItemSize); - Array->Count++; -} - -/** - * Adds items to an array. - * - * \param Array An array object. - * \param Items An array containing the items to add. - * \param Count The number of items to add. - */ -VOID PhAddItemsArray( - _Inout_ PPH_ARRAY Array, - _In_ PVOID Items, - _In_ SIZE_T Count - ) -{ - // See if we need to resize the list. - if (Array->AllocatedCount < Array->Count + Count) - { - Array->AllocatedCount *= 2; - - if (Array->AllocatedCount < Array->Count + Count) - Array->AllocatedCount = Array->Count + Count; - - Array->Items = PhReAllocate(Array->Items, Array->AllocatedCount * Array->ItemSize); - } - - memcpy( - PhItemArray(Array, Array->Count), - Items, - Count * Array->ItemSize - ); - Array->Count += Count; -} - -/** - * Clears an array. - * - * \param Array An array object. - */ -VOID PhClearArray( - _Inout_ PPH_ARRAY Array - ) -{ - Array->Count = 0; -} - -/** - * Removes an item from an array. - * - * \param Array An array object. - * \param Index The index of the item. - */ -VOID PhRemoveItemArray( - _Inout_ PPH_ARRAY Array, - _In_ SIZE_T Index - ) -{ - PhRemoveItemsArray(Array, Index, 1); -} - -/** - * Removes items from an array. - * - * \param Array An array object. - * \param StartIndex The index at which to begin removing items. - * \param Count The number of items to remove. - */ -VOID PhRemoveItemsArray( - _Inout_ PPH_ARRAY Array, - _In_ SIZE_T StartIndex, - _In_ SIZE_T Count - ) -{ - // Shift the items after the items forward. - memmove( - PhItemArray(Array, StartIndex), - PhItemArray(Array, StartIndex + Count), - (Array->Count - StartIndex - Count) * Array->ItemSize - ); - Array->Count -= Count; -} - -/** - * Creates a list object. - * - * \param InitialCapacity The number of elements to allocate storage for, initially. - */ -PPH_LIST PhCreateList( - _In_ ULONG InitialCapacity - ) -{ - PPH_LIST list; - - list = PhCreateObject(sizeof(PH_LIST), PhListType); - - // Initial capacity of 0 is not allowed. - if (InitialCapacity == 0) - InitialCapacity = 1; - - list->Count = 0; - list->AllocatedCount = InitialCapacity; - list->Items = PhAllocate(list->AllocatedCount * sizeof(PVOID)); - - return list; -} - -VOID PhpListDeleteProcedure( - _In_ PVOID Object, - _In_ ULONG Flags - ) -{ - PPH_LIST list = (PPH_LIST)Object; - - PhFree(list->Items); -} - -/** - * Resizes a list. - * - * \param List A list object. - * \param NewCapacity The new required number of elements for which storage has been reserved. This - * must not be smaller than the current number of items in the list. - */ -VOID PhResizeList( - _Inout_ PPH_LIST List, - _In_ ULONG NewCapacity - ) -{ - if (List->Count > NewCapacity) - PhRaiseStatus(STATUS_INVALID_PARAMETER_2); - - List->AllocatedCount = NewCapacity; - List->Items = PhReAllocate(List->Items, List->AllocatedCount * sizeof(PVOID)); -} - -/** - * Adds an item to a list. - * - * \param List A list object. - * \param Item The item to add. - */ -VOID PhAddItemList( - _Inout_ PPH_LIST List, - _In_ PVOID Item - ) -{ - // See if we need to resize the list. - if (List->Count == List->AllocatedCount) - { - List->AllocatedCount *= 2; - List->Items = PhReAllocate(List->Items, List->AllocatedCount * sizeof(PVOID)); - } - - List->Items[List->Count++] = Item; -} - -/** - * Adds items to a list. - * - * \param List A list object. - * \param Items An array containing the items to add. - * \param Count The number of items to add. - */ -VOID PhAddItemsList( - _Inout_ PPH_LIST List, - _In_ PVOID *Items, - _In_ ULONG Count - ) -{ - // See if we need to resize the list. - if (List->AllocatedCount < List->Count + Count) - { - List->AllocatedCount *= 2; - - if (List->AllocatedCount < List->Count + Count) - List->AllocatedCount = List->Count + Count; - - List->Items = PhReAllocate(List->Items, List->AllocatedCount * sizeof(PVOID)); - } - - memcpy( - &List->Items[List->Count], - Items, - Count * sizeof(PVOID) - ); - List->Count += Count; -} - -/** - * Clears a list. - * - * \param List A list object. - */ -VOID PhClearList( - _Inout_ PPH_LIST List - ) -{ - List->Count = 0; -} - -_Success_(return != -1) -/** - * Locates an item in a list. - * - * \param List A list object. - * \param Item The item to search for. - * - * \return The index of the item. If the - * item was not found, -1 is returned. - */ -ULONG PhFindItemList( - _In_ PPH_LIST List, - _In_ PVOID Item - ) -{ - ULONG i; - - for (i = 0; i < List->Count; i++) - { - if (List->Items[i] == Item) - return i; - } - - return -1; -} - -/** - * Inserts an item into a list. - * - * \param List A list object. - * \param Index The index at which to insert the item. - * \param Item The item to add. - */ -VOID PhInsertItemList( - _Inout_ PPH_LIST List, - _In_ ULONG Index, - _In_ PVOID Item - ) -{ - PhInsertItemsList(List, Index, &Item, 1); -} - -/** - * Inserts items into a list. - * - * \param List A list object. - * \param Index The index at which to insert the items. - * \param Items An array containing the items to add. - * \param Count The number of items to add. - */ -VOID PhInsertItemsList( - _Inout_ PPH_LIST List, - _In_ ULONG Index, - _In_ PVOID *Items, - _In_ ULONG Count - ) -{ - // See if we need to resize the list. - if (List->AllocatedCount < List->Count + Count) - { - List->AllocatedCount *= 2; - - if (List->AllocatedCount < List->Count + Count) - List->AllocatedCount = List->Count + Count; - - List->Items = PhReAllocate(List->Items, List->AllocatedCount * sizeof(PVOID)); - } - - if (Index < List->Count) - { - // Shift the existing items backward. - memmove( - &List->Items[Index + Count], - &List->Items[Index], - (List->Count - Index) * sizeof(PVOID) - ); - } - - // Copy the new items into the list. - memcpy( - &List->Items[Index], - Items, - Count * sizeof(PVOID) - ); - - List->Count += Count; -} - -/** - * Removes an item from a list. - * - * \param List A list object. - * \param Index The index of the item. - */ -VOID PhRemoveItemList( - _Inout_ PPH_LIST List, - _In_ ULONG Index - ) -{ - PhRemoveItemsList(List, Index, 1); -} - -/** - * Removes items from a list. - * - * \param List A list object. - * \param StartIndex The index at which to begin removing items. - * \param Count The number of items to remove. - */ -VOID PhRemoveItemsList( - _Inout_ PPH_LIST List, - _In_ ULONG StartIndex, - _In_ ULONG Count - ) -{ - // Shift the items after the items forward. - memmove( - &List->Items[StartIndex], - &List->Items[StartIndex + Count], - (List->Count - StartIndex - Count) * sizeof(PVOID) - ); - List->Count -= Count; -} - -/** - * Creates a pointer list object. - * - * \param InitialCapacity The number of elements to allocate storage for initially. - */ -PPH_POINTER_LIST PhCreatePointerList( - _In_ ULONG InitialCapacity - ) -{ - PPH_POINTER_LIST pointerList; - - pointerList = PhCreateObject(sizeof(PH_POINTER_LIST), PhPointerListType); - - // Initial capacity of 0 is not allowed. - if (InitialCapacity == 0) - InitialCapacity = 1; - - pointerList->Count = 0; - pointerList->AllocatedCount = InitialCapacity; - pointerList->FreeEntry = -1; - pointerList->NextEntry = 0; - pointerList->Items = PhAllocate(pointerList->AllocatedCount * sizeof(PVOID)); - - return pointerList; -} - -VOID NTAPI PhpPointerListDeleteProcedure( - _In_ PVOID Object, - _In_ ULONG Flags - ) -{ - PPH_POINTER_LIST pointerList = (PPH_POINTER_LIST)Object; - - PhFree(pointerList->Items); -} - -/** - * Decodes an index stored in a free entry. - */ -FORCEINLINE ULONG PhpDecodePointerListIndex( - _In_ PVOID Index - ) -{ - // At least with Microsoft's compiler, shift right on a signed value preserves the sign. This is - // important because we want decode(encode(-1)) = ((-1 << 1) | 1) >> 1 = -1. - return (ULONG)((LONG_PTR)Index >> 1); -} - -/** - * Encodes an index for storage in a free entry. - */ -FORCEINLINE PVOID PhpEncodePointerListIndex( - _In_ ULONG Index - ) -{ - return (PVOID)(((ULONG_PTR)Index << 1) | 0x1); -} - -FORCEINLINE HANDLE PhpPointerListIndexToHandle( - _In_ ULONG Index - ) -{ - // Add one to allow NULL handles to indicate failure/an invalid index. - return UlongToHandle(Index + 1); -} - -FORCEINLINE ULONG PhpPointerListHandleToIndex( - _In_ HANDLE Handle - ) -{ - return HandleToUlong(Handle) - 1; -} - -/** - * Adds a pointer to a pointer list. - * - * \param PointerList A pointer list object. - * \param Pointer The pointer to add. The pointer must be at least 2 byte aligned. - * - * \return A handle to the pointer, valid until the pointer is removed from the pointer list. - */ -HANDLE PhAddItemPointerList( - _Inout_ PPH_POINTER_LIST PointerList, - _In_ PVOID Pointer - ) -{ - ULONG index; - - assert(PH_IS_LIST_POINTER_VALID(Pointer)); - - // Use a free entry if possible. - if (PointerList->FreeEntry != -1) - { - PVOID oldPointer; - - index = PointerList->FreeEntry; - oldPointer = PointerList->Items[index]; - PointerList->Items[index] = Pointer; - PointerList->FreeEntry = PhpDecodePointerListIndex(oldPointer); - } - else - { - // Use the next entry. - if (PointerList->NextEntry == PointerList->AllocatedCount) - { - PointerList->AllocatedCount *= 2; - PointerList->Items = PhReAllocate(PointerList->Items, PointerList->AllocatedCount * sizeof(PVOID)); - } - - index = PointerList->NextEntry++; - PointerList->Items[index] = Pointer; - } - - PointerList->Count++; - - return PhpPointerListIndexToHandle(index); -} - -BOOLEAN PhEnumPointerListEx( - _In_ PPH_POINTER_LIST PointerList, - _Inout_ PULONG EnumerationKey, - _Out_ PVOID *Pointer, - _Out_ PHANDLE PointerHandle - ) -{ - ULONG index; - - while ((index = *EnumerationKey) < PointerList->NextEntry) - { - PVOID pointer = PointerList->Items[index]; - - (*EnumerationKey)++; - - if (PH_IS_LIST_POINTER_VALID(pointer)) - { - *Pointer = pointer; - *PointerHandle = PhpPointerListIndexToHandle(index); - - return TRUE; - } - } - - return FALSE; -} - -/** - * Locates a pointer in a pointer list. - * - * \param PointerList A pointer list object. - * \param Pointer The pointer to find. The pointer must be at least 2 byte aligned. - * - * \return A handle to the pointer, valid until the pointer is removed from the pointer list. If the - * pointer is not contained in the pointer list, NULL is returned. - */ -HANDLE PhFindItemPointerList( - _In_ PPH_POINTER_LIST PointerList, - _In_ PVOID Pointer - ) -{ - ULONG i; - - assert(PH_IS_LIST_POINTER_VALID(Pointer)); - - for (i = 0; i < PointerList->NextEntry; i++) - { - if (PointerList->Items[i] == Pointer) - return PhpPointerListIndexToHandle(i); - } - - return NULL; -} - -/** - * Removes a pointer from a pointer list. - * - * \param PointerList A pointer list object. - * \param PointerHandle A handle to the pointer to remove. - * - * \remarks No checking is performed on the pointer handle. Make sure the handle is valid before - * calling the function. - */ -VOID PhRemoveItemPointerList( - _Inout_ PPH_POINTER_LIST PointerList, - _In_ HANDLE PointerHandle - ) -{ - ULONG index; - - assert(PointerHandle); - - index = PhpPointerListHandleToIndex(PointerHandle); - - PointerList->Items[index] = PhpEncodePointerListIndex(PointerList->FreeEntry); - PointerList->FreeEntry = index; - - PointerList->Count--; -} - -FORCEINLINE ULONG PhpValidateHash( - _In_ ULONG Hash - ) -{ - // No point in using a full hash when we're going to AND with size minus one anyway. -#if defined(PH_HASHTABLE_FULL_HASH) && !defined(PH_HASHTABLE_POWER_OF_TWO_SIZE) - if (Hash != -1) - return Hash; - else - return 0; -#else - return Hash & MAXLONG; -#endif -} - -FORCEINLINE ULONG PhpIndexFromHash( - _In_ PPH_HASHTABLE Hashtable, - _In_ ULONG Hash - ) -{ -#ifdef PH_HASHTABLE_POWER_OF_TWO_SIZE - return Hash & (Hashtable->AllocatedBuckets - 1); -#else - return Hash % Hashtable->AllocatedBuckets; -#endif -} - -FORCEINLINE ULONG PhpGetNumberOfBuckets( - _In_ ULONG Capacity - ) -{ -#ifdef PH_HASHTABLE_POWER_OF_TWO_SIZE - return PhRoundUpToPowerOfTwo(Capacity); -#else - return PhGetPrimeNumber(Capacity); -#endif -} - -/** - * Creates a hashtable object. - * - * \param EntrySize The size of each hashtable entry, in bytes. - * \param EqualFunction A comparison function that is executed to compare two hashtable entries. - * \param HashFunction A hash function that is executed to generate a hash code for a hashtable - * entry. - * \param InitialCapacity The number of entries to allocate storage for initially. - */ -PPH_HASHTABLE PhCreateHashtable( - _In_ ULONG EntrySize, - _In_ PPH_HASHTABLE_EQUAL_FUNCTION EqualFunction, - _In_ PPH_HASHTABLE_HASH_FUNCTION HashFunction, - _In_ ULONG InitialCapacity - ) -{ - PPH_HASHTABLE hashtable; - - hashtable = PhCreateObject(sizeof(PH_HASHTABLE), PhHashtableType); - - // Initial capacity of 0 is not allowed. - if (InitialCapacity == 0) - InitialCapacity = 1; - - hashtable->EntrySize = EntrySize; - hashtable->EqualFunction = EqualFunction; - hashtable->HashFunction = HashFunction; - - // Allocate the buckets. - hashtable->AllocatedBuckets = PhpGetNumberOfBuckets(InitialCapacity); - hashtable->Buckets = PhAllocate(sizeof(ULONG) * hashtable->AllocatedBuckets); - // Set all bucket values to -1. - memset(hashtable->Buckets, 0xff, sizeof(ULONG) * hashtable->AllocatedBuckets); - - // Allocate the entries. - hashtable->AllocatedEntries = hashtable->AllocatedBuckets; - hashtable->Entries = PhAllocate(PH_HASHTABLE_ENTRY_SIZE(EntrySize) * hashtable->AllocatedEntries); - - hashtable->Count = 0; - hashtable->FreeEntry = -1; - hashtable->NextEntry = 0; - - return hashtable; -} - -VOID PhpHashtableDeleteProcedure( - _In_ PVOID Object, - _In_ ULONG Flags - ) -{ - PPH_HASHTABLE hashtable = (PPH_HASHTABLE)Object; - - PhFree(hashtable->Buckets); - PhFree(hashtable->Entries); -} - -VOID PhpResizeHashtable( - _Inout_ PPH_HASHTABLE Hashtable, - _In_ ULONG NewCapacity - ) -{ - PPH_HASHTABLE_ENTRY entry; - ULONG i; - - // Re-allocate the buckets. Note that we don't need to keep the contents. - Hashtable->AllocatedBuckets = PhpGetNumberOfBuckets(NewCapacity); - PhFree(Hashtable->Buckets); - Hashtable->Buckets = PhAllocate(sizeof(ULONG) * Hashtable->AllocatedBuckets); - // Set all bucket values to -1. - memset(Hashtable->Buckets, 0xff, sizeof(ULONG) * Hashtable->AllocatedBuckets); - - // Re-allocate the entries. - Hashtable->AllocatedEntries = Hashtable->AllocatedBuckets; - Hashtable->Entries = PhReAllocate( - Hashtable->Entries, - PH_HASHTABLE_ENTRY_SIZE(Hashtable->EntrySize) * Hashtable->AllocatedEntries - ); - - // Re-distribute the entries among the buckets. - - // PH_HASHTABLE_GET_ENTRY is quite slow (it involves a multiply), so we use a pointer here. - entry = Hashtable->Entries; - - for (i = 0; i < Hashtable->NextEntry; i++) - { - if (entry->HashCode != -1) - { - ULONG index = PhpIndexFromHash(Hashtable, entry->HashCode); - - entry->Next = Hashtable->Buckets[index]; - Hashtable->Buckets[index] = i; - } - - entry = (PPH_HASHTABLE_ENTRY)((ULONG_PTR)entry + PH_HASHTABLE_ENTRY_SIZE(Hashtable->EntrySize)); - } -} - -FORCEINLINE PVOID PhpAddEntryHashtable( - _Inout_ PPH_HASHTABLE Hashtable, - _In_ PVOID Entry, - _In_ BOOLEAN CheckForDuplicate, - _Out_opt_ PBOOLEAN Added - ) -{ - ULONG hashCode; // hash code of the new entry - ULONG index; // bucket index of the new entry - ULONG freeEntry; // index of new entry in entry array - PPH_HASHTABLE_ENTRY entry; // pointer to new entry in entry array - - hashCode = PhpValidateHash(Hashtable->HashFunction(Entry)); - index = PhpIndexFromHash(Hashtable, hashCode); - - if (CheckForDuplicate) - { - ULONG i; - - for (i = Hashtable->Buckets[index]; i != -1; i = entry->Next) - { - entry = PH_HASHTABLE_GET_ENTRY(Hashtable, i); - - if (entry->HashCode == hashCode && Hashtable->EqualFunction(&entry->Body, Entry)) - { - if (Added) - *Added = FALSE; - - return &entry->Body; - } - } - } - - // Use a free entry if possible. - if (Hashtable->FreeEntry != -1) - { - freeEntry = Hashtable->FreeEntry; - entry = PH_HASHTABLE_GET_ENTRY(Hashtable, freeEntry); - Hashtable->FreeEntry = entry->Next; - } - else - { - // Use the next entry in the entry array. - - if (Hashtable->NextEntry == Hashtable->AllocatedEntries) - { - // Resize the hashtable. - PhpResizeHashtable(Hashtable, Hashtable->AllocatedBuckets * 2); - index = PhpIndexFromHash(Hashtable, hashCode); - } - - freeEntry = Hashtable->NextEntry++; - entry = PH_HASHTABLE_GET_ENTRY(Hashtable, freeEntry); - } - - // Initialize the entry. - entry->HashCode = hashCode; - entry->Next = Hashtable->Buckets[index]; - Hashtable->Buckets[index] = freeEntry; - // Copy the user-supplied data to the entry. - memcpy(&entry->Body, Entry, Hashtable->EntrySize); - - Hashtable->Count++; - - if (Added) - *Added = TRUE; - - return &entry->Body; -} - -/** - * Adds an entry to a hashtable. - * - * \param Hashtable A hashtable object. - * \param Entry The entry to add. - * - * \return A pointer to the entry as stored in the hashtable. This pointer is valid until the - * hashtable is modified. If the hashtable already contained an equal entry, NULL is returned. - * - * \remarks Entries are only guaranteed to be 8 byte aligned, even on 64-bit systems. - */ -PVOID PhAddEntryHashtable( - _Inout_ PPH_HASHTABLE Hashtable, - _In_ PVOID Entry - ) -{ - PVOID entry; - BOOLEAN added; - - entry = PhpAddEntryHashtable(Hashtable, Entry, TRUE, &added); - - if (added) - return entry; - else - return NULL; -} - -/** - * Adds an entry to a hashtable or returns an existing one. - * - * \param Hashtable A hashtable object. - * \param Entry The entry to add. - * \param Added A variable which receives TRUE if a new entry was created, and FALSE if an existing - * entry was returned. - * - * \return A pointer to the entry as stored in the hashtable. This pointer is valid until the - * hashtable is modified. If the hashtable already contained an equal entry, the existing entry is - * returned. Check the value of \a Added to determine whether the returned entry is new or existing. - * - * \remarks Entries are only guaranteed to be 8 byte aligned, even on 64-bit systems. - */ -PVOID PhAddEntryHashtableEx( - _Inout_ PPH_HASHTABLE Hashtable, - _In_ PVOID Entry, - _Out_opt_ PBOOLEAN Added - ) -{ - return PhpAddEntryHashtable(Hashtable, Entry, TRUE, Added); -} - -/** - * Clears a hashtable. - * - * \param Hashtable A hashtable object. - */ -VOID PhClearHashtable( - _Inout_ PPH_HASHTABLE Hashtable - ) -{ - if (Hashtable->Count > 0) - { - memset(Hashtable->Buckets, 0xff, sizeof(ULONG) * Hashtable->AllocatedBuckets); - Hashtable->Count = 0; - Hashtable->FreeEntry = -1; - Hashtable->NextEntry = 0; - } -} - -/** - * Enumerates the entries in a hashtable. - * - * \param Hashtable A hashtable object. - * \param Entry A variable which receives a pointer to the hashtable entry. The pointer is valid - * until the hashtable is modified. - * \param EnumerationKey A variable which is initialized to 0 before first calling this function. - * - * \return TRUE if an entry pointer was stored in \a Entry, FALSE if there are no more entries. - * - * \remarks Do not modify the hashtable while the hashtable is being enumerated (between calls to - * this function). Otherwise, the function may behave unexpectedly. You may reset the - * \a EnumerationKey variable to 0 if you wish to restart the enumeration. - */ -BOOLEAN PhEnumHashtable( - _In_ PPH_HASHTABLE Hashtable, - _Out_ PVOID *Entry, - _Inout_ PULONG EnumerationKey - ) -{ - while (*EnumerationKey < Hashtable->NextEntry) - { - PPH_HASHTABLE_ENTRY entry = PH_HASHTABLE_GET_ENTRY(Hashtable, *EnumerationKey); - - (*EnumerationKey)++; - - if (entry->HashCode != -1) - { - *Entry = &entry->Body; - return TRUE; - } - } - - return FALSE; -} - -/** - * Locates an entry in a hashtable. - * - * \param Hashtable A hashtable object. - * \param Entry An entry representing the entry to find. - * - * \return A pointer to the entry as stored in the hashtable. This pointer is valid until the - * hashtable is modified. If the entry could not be found, NULL is returned. - * - * \remarks The entry specified in \a Entry can be a partial entry that is filled in enough so that - * the comparison and hash functions can work with them. - */ -PVOID PhFindEntryHashtable( - _In_ PPH_HASHTABLE Hashtable, - _In_ PVOID Entry - ) -{ - ULONG hashCode; - ULONG index; - ULONG i; - PPH_HASHTABLE_ENTRY entry; - - hashCode = PhpValidateHash(Hashtable->HashFunction(Entry)); - index = PhpIndexFromHash(Hashtable, hashCode); - - for (i = Hashtable->Buckets[index]; i != -1; i = entry->Next) - { - entry = PH_HASHTABLE_GET_ENTRY(Hashtable, i); - - if (entry->HashCode == hashCode && Hashtable->EqualFunction(&entry->Body, Entry)) - { - return &entry->Body; - } - } - - return NULL; -} - -/** - * Removes an entry from a hashtable. - * - * \param Hashtable A hashtable object. - * \param Entry The entry to remove. - * - * \return TRUE if the entry was removed, FALSE if the entry could not be found. - * - * \remarks The entry specified in \a Entry can be an actual entry pointer returned by - * PhFindEntryHashtable, or a partial entry. - */ -BOOLEAN PhRemoveEntryHashtable( - _Inout_ PPH_HASHTABLE Hashtable, - _In_ PVOID Entry - ) -{ - ULONG hashCode; - ULONG index; - ULONG i; - ULONG previousIndex; - PPH_HASHTABLE_ENTRY entry; - - hashCode = PhpValidateHash(Hashtable->HashFunction(Entry)); - index = PhpIndexFromHash(Hashtable, hashCode); - previousIndex = -1; - - for (i = Hashtable->Buckets[index]; i != -1; i = entry->Next) - { - entry = PH_HASHTABLE_GET_ENTRY(Hashtable, i); - - if (entry->HashCode == hashCode && Hashtable->EqualFunction(&entry->Body, Entry)) - { - // Unlink the entry from the bucket. - if (previousIndex == -1) - { - Hashtable->Buckets[index] = entry->Next; - } - else - { - PH_HASHTABLE_GET_ENTRY(Hashtable, previousIndex)->Next = entry->Next; - } - - entry->HashCode = -1; // indicates the entry is not being used - entry->Next = Hashtable->FreeEntry; - Hashtable->FreeEntry = i; - - Hashtable->Count--; - - return TRUE; - } - - previousIndex = i; - } - - return FALSE; -} - -/** - * Generates a hash code for a sequence of bytes. - * - * \param Bytes A pointer to a byte array. - * \param Length The number of bytes to hash. - */ -ULONG PhHashBytes( - _In_reads_(Length) PUCHAR Bytes, - _In_ SIZE_T Length - ) -{ - ULONG hash = 0; - - if (Length == 0) - return hash; - - // FNV-1a algorithm: http://www.isthe.com/chongo/src/fnv/hash_32a.c - - do - { - hash ^= *Bytes++; - hash *= 0x01000193; - } while (--Length != 0); - - return hash; -} - -/** - * Generates a hash code for a string. - * - * \param String The string to hash. - * \param IgnoreCase TRUE for a case-insensitive hash function, otherwise FALSE. - */ -ULONG PhHashStringRef( - _In_ PPH_STRINGREF String, - _In_ BOOLEAN IgnoreCase - ) -{ - ULONG hash = 0; - SIZE_T count; - PWCHAR p; - - if (String->Length == 0) - return 0; - - count = String->Length / sizeof(WCHAR); - p = String->Buffer; - - if (!IgnoreCase) - { - return PhHashBytes((PUCHAR)String->Buffer, String->Length); - } - else - { - do - { - hash ^= (USHORT)RtlUpcaseUnicodeChar(*p++); - hash *= 0x01000193; - } while (--count != 0); - } - - return hash; -} - -BOOLEAN NTAPI PhpSimpleHashtableEqualFunction( - _In_ PVOID Entry1, - _In_ PVOID Entry2 - ) -{ - PPH_KEY_VALUE_PAIR entry1 = Entry1; - PPH_KEY_VALUE_PAIR entry2 = Entry2; - - return entry1->Key == entry2->Key; -} - -ULONG NTAPI PhpSimpleHashtableHashFunction( - _In_ PVOID Entry - ) -{ - PPH_KEY_VALUE_PAIR entry = Entry; - - return PhHashIntPtr((ULONG_PTR)entry->Key); -} - -PPH_HASHTABLE PhCreateSimpleHashtable( - _In_ ULONG InitialCapacity - ) -{ - return PhCreateHashtable( - sizeof(PH_KEY_VALUE_PAIR), - PhpSimpleHashtableEqualFunction, - PhpSimpleHashtableHashFunction, - InitialCapacity - ); -} - -PVOID PhAddItemSimpleHashtable( - _Inout_ PPH_HASHTABLE SimpleHashtable, - _In_opt_ PVOID Key, - _In_opt_ PVOID Value - ) -{ - PH_KEY_VALUE_PAIR entry; - - entry.Key = Key; - entry.Value = Value; - - if (PhAddEntryHashtable(SimpleHashtable, &entry)) - return Value; - else - return NULL; -} - -PVOID *PhFindItemSimpleHashtable( - _In_ PPH_HASHTABLE SimpleHashtable, - _In_opt_ PVOID Key - ) -{ - PH_KEY_VALUE_PAIR lookupEntry; - PPH_KEY_VALUE_PAIR entry; - - lookupEntry.Key = Key; - entry = PhFindEntryHashtable(SimpleHashtable, &lookupEntry); - - if (entry) - return &entry->Value; - else - return NULL; -} - -BOOLEAN PhRemoveItemSimpleHashtable( - _Inout_ PPH_HASHTABLE SimpleHashtable, - _In_opt_ PVOID Key - ) -{ - PH_KEY_VALUE_PAIR lookupEntry; - - lookupEntry.Key = Key; - - return PhRemoveEntryHashtable(SimpleHashtable, &lookupEntry); -} - -/** - * Initializes a free list object. - * - * \param FreeList A pointer to the free list object. - * \param Size The number of bytes in each allocation. - * \param MaximumCount The number of unused allocations to store. - */ -VOID PhInitializeFreeList( - _Out_ PPH_FREE_LIST FreeList, - _In_ SIZE_T Size, - _In_ ULONG MaximumCount - ) -{ - RtlInitializeSListHead(&FreeList->ListHead); - FreeList->Count = 0; - FreeList->MaximumCount = MaximumCount; - FreeList->Size = Size; -} - -/** - * Frees resources used by a free list object. - * - * \param FreeList A pointer to the free list object. - */ -VOID PhDeleteFreeList( - _Inout_ PPH_FREE_LIST FreeList - ) -{ - PPH_FREE_LIST_ENTRY entry; - PSLIST_ENTRY listEntry; - - listEntry = RtlInterlockedFlushSList(&FreeList->ListHead); - - while (listEntry) - { - entry = CONTAINING_RECORD(listEntry, PH_FREE_LIST_ENTRY, ListEntry); - listEntry = listEntry->Next; - PhFree(entry); - } -} - -/** - * Allocates a block of memory from a free list. - * - * \param FreeList A pointer to a free list object. - * - * \return A pointer to the allocated block of memory. The memory must be freed using - * PhFreeToFreeList(). The block is guaranteed to be aligned at MEMORY_ALLOCATION_ALIGNMENT bytes. - */ -PVOID PhAllocateFromFreeList( - _Inout_ PPH_FREE_LIST FreeList - ) -{ - PPH_FREE_LIST_ENTRY entry; - PSLIST_ENTRY listEntry; - - listEntry = RtlInterlockedPopEntrySList(&FreeList->ListHead); - - if (listEntry) - { - _InterlockedDecrement((PLONG)&FreeList->Count); - entry = CONTAINING_RECORD(listEntry, PH_FREE_LIST_ENTRY, ListEntry); - } - else - { - entry = PhAllocate(FIELD_OFFSET(PH_FREE_LIST_ENTRY, Body) + FreeList->Size); - } - - return &entry->Body; -} - -/** - * Frees a block of memory to a free list. - * - * \param FreeList A pointer to a free list object. - * \param Memory A pointer to a block of memory. - */ -VOID PhFreeToFreeList( - _Inout_ PPH_FREE_LIST FreeList, - _In_ PVOID Memory - ) -{ - PPH_FREE_LIST_ENTRY entry; - - entry = CONTAINING_RECORD(Memory, PH_FREE_LIST_ENTRY, Body); - - // We don't enforce Count <= MaximumCount (that would require locking), - // but we do check it. - if (FreeList->Count < FreeList->MaximumCount) - { - RtlInterlockedPushEntrySList(&FreeList->ListHead, &entry->ListEntry); - _InterlockedIncrement((PLONG)&FreeList->Count); - } - else - { - PhFree(entry); - } -} - -/** - * Initializes a callback object. - * - * \param Callback A pointer to a callback object. - */ -VOID PhInitializeCallback( - _Out_ PPH_CALLBACK Callback - ) -{ - InitializeListHead(&Callback->ListHead); - PhInitializeQueuedLock(&Callback->ListLock); - PhInitializeCondition(&Callback->BusyCondition); -} - -/** - * Frees resources used by a callback object. - * - * \param Callback A pointer to a callback object. - */ -VOID PhDeleteCallback( - _Inout_ PPH_CALLBACK Callback - ) -{ - // Nothing for now -} - -/** - * Registers a callback function to be notified. - * - * \param Callback A pointer to a callback object. - * \param Function The callback function. - * \param Context A user-defined value to pass to the callback function. - * \param Registration A variable which receives registration information for the callback. Do not - * modify the contents of this structure and do not free the storage for this structure until you - * have unregistered the callback. - */ -VOID PhRegisterCallback( - _Inout_ PPH_CALLBACK Callback, - _In_ PPH_CALLBACK_FUNCTION Function, - _In_opt_ PVOID Context, - _Out_ PPH_CALLBACK_REGISTRATION Registration - ) -{ - PhRegisterCallbackEx( - Callback, - Function, - Context, - 0, - Registration - ); -} - -/** - * Registers a callback function to be notified. - * - * \param Callback A pointer to a callback object. - * \param Function The callback function. - * \param Context A user-defined value to pass to the callback function. - * \param Flags A combination of flags controlling the callback. Set this parameter to 0. - * \param Registration A variable which receives registration information for the callback. Do not - * modify the contents of this structure and do not free the storage for this structure until you - * have unregistered the callback. - */ -VOID PhRegisterCallbackEx( - _Inout_ PPH_CALLBACK Callback, - _In_ PPH_CALLBACK_FUNCTION Function, - _In_opt_ PVOID Context, - _In_ USHORT Flags, - _Out_ PPH_CALLBACK_REGISTRATION Registration - ) -{ - Registration->Function = Function; - Registration->Context = Context; - Registration->Busy = 0; - Registration->Unregistering = FALSE; - Registration->Flags = Flags; - - PhAcquireQueuedLockExclusive(&Callback->ListLock); - InsertTailList(&Callback->ListHead, &Registration->ListEntry); - PhReleaseQueuedLockExclusive(&Callback->ListLock); -} - -/** - * Unregisters a callback function. - * - * \param Callback A pointer to a callback object. - * \param Registration The structure returned by PhRegisterCallback(). - * - * \remarks It is guaranteed that the callback function will not be in execution once this function - * returns. Attempting to unregister a callback function from within the same function will result - * in a deadlock. - */ -VOID PhUnregisterCallback( - _Inout_ PPH_CALLBACK Callback, - _Inout_ PPH_CALLBACK_REGISTRATION Registration - ) -{ - Registration->Unregistering = TRUE; - - PhAcquireQueuedLockExclusive(&Callback->ListLock); - - // Wait for the callback to be unbusy. - while (Registration->Busy) - PhWaitForCondition(&Callback->BusyCondition, &Callback->ListLock, NULL); - - RemoveEntryList(&Registration->ListEntry); - - PhReleaseQueuedLockExclusive(&Callback->ListLock); -} - -/** - * Notifies all registered callback functions. - * - * \param Callback A pointer to a callback object. - * \param Parameter A value to pass to all callback functions. - */ -VOID PhInvokeCallback( - _In_ PPH_CALLBACK Callback, - _In_opt_ PVOID Parameter - ) -{ - PLIST_ENTRY listEntry; - - PhAcquireQueuedLockShared(&Callback->ListLock); - - listEntry = Callback->ListHead.Flink; - - while (listEntry != &Callback->ListHead) - { - PPH_CALLBACK_REGISTRATION registration; - LONG busy; - - registration = CONTAINING_RECORD(listEntry, PH_CALLBACK_REGISTRATION, ListEntry); - - // Don't bother executing the callback function if it is being unregistered. - if (registration->Unregistering) - continue; - - _InterlockedIncrement(®istration->Busy); - - // Execute the callback function. - - PhReleaseQueuedLockShared(&Callback->ListLock); - registration->Function( - Parameter, - registration->Context - ); - PhAcquireQueuedLockShared(&Callback->ListLock); - - busy = _InterlockedDecrement(®istration->Busy); - - if (registration->Unregistering && busy == 0) - { - // Someone started unregistering while the callback function was executing, and we must - // wake them. - PhPulseAllCondition(&Callback->BusyCondition); - } - - listEntry = listEntry->Flink; - } - - PhReleaseQueuedLockShared(&Callback->ListLock); -} - -/** - * Retrieves a prime number bigger than or equal to the specified number. - */ -ULONG PhGetPrimeNumber( - _In_ ULONG Minimum - ) -{ - ULONG i, j; - - for (i = 0; i < sizeof(PhpPrimeNumbers) / sizeof(ULONG); i++) - { - if (PhpPrimeNumbers[i] >= Minimum) - return PhpPrimeNumbers[i]; - } - - for (i = Minimum | 1; i < MAXLONG; i += 2) - { - ULONG sqrtI = (ULONG)sqrt(i); - - for (j = 3; j <= sqrtI; j += 2) - { - if (i % j == 0) - { - // Not a prime. - goto NextPrime; - } - } - - // Success. - return i; -NextPrime: - NOTHING; - } - - return Minimum; -} - -/** - * Rounds up a number to the next power of two. - */ -ULONG PhRoundUpToPowerOfTwo( - _In_ ULONG Number - ) -{ - Number--; - Number |= Number >> 1; - Number |= Number >> 2; - Number |= Number >> 4; - Number |= Number >> 8; - Number |= Number >> 16; - Number++; - - return Number; -} - -/** - * Performs exponentiation. - */ -ULONG PhExponentiate( - _In_ ULONG Base, - _In_ ULONG Exponent - ) -{ - ULONG result = 1; - - while (Exponent) - { - if (Exponent & 1) - result *= Base; - - Exponent >>= 1; - Base *= Base; - } - - return result; -} - -/** - * Performs 64-bit exponentiation. - */ -ULONG64 PhExponentiate64( - _In_ ULONG64 Base, - _In_ ULONG Exponent - ) -{ - ULONG64 result = 1; - - while (Exponent) - { - if (Exponent & 1) - result *= Base; - - Exponent >>= 1; - Base *= Base; - } - - return result; -} - -/** - * Converts a sequence of hexadecimal digits into a byte array. - * - * \param String A string containing hexadecimal digits to convert. The string must have an even - * number of digits, because each pair of hexadecimal digits represents one byte. Example: - * "129a2eff5c0b". - * \param Buffer The output buffer. - * - * \return TRUE if the string was successfully converted, otherwise FALSE. - */ -BOOLEAN PhHexStringToBuffer( - _In_ PPH_STRINGREF String, - _Out_writes_bytes_(String->Length / sizeof(WCHAR) / 2) PUCHAR Buffer - ) -{ - SIZE_T i; - SIZE_T length; - - // The string must have an even length. - if ((String->Length / sizeof(WCHAR)) & 1) - return FALSE; - - length = String->Length / sizeof(WCHAR) / 2; - - for (i = 0; i < length; i++) - { - Buffer[i] = - (UCHAR)(PhCharToInteger[(UCHAR)String->Buffer[i * 2]] << 4) + - (UCHAR)PhCharToInteger[(UCHAR)String->Buffer[i * 2 + 1]]; - } - - return TRUE; -} - -/** - * Converts a byte array into a sequence of hexadecimal digits. - * - * \param Buffer The input buffer. - * \param Length The number of bytes to convert. - * - * \return A string containing a sequence of hexadecimal digits. - */ -PPH_STRING PhBufferToHexString( - _In_reads_bytes_(Length) PUCHAR Buffer, - _In_ ULONG Length - ) -{ - return PhBufferToHexStringEx(Buffer, Length, FALSE); -} - -/** - * Converts a byte array into a sequence of hexadecimal digits. - * - * \param Buffer The input buffer. - * \param Length The number of bytes to convert. - * \param UpperCase TRUE to use uppercase characters, otherwise FALSE. - * - * \return A string containing a sequence of hexadecimal digits. - */ -PPH_STRING PhBufferToHexStringEx( - _In_reads_bytes_(Length) PUCHAR Buffer, - _In_ ULONG Length, - _In_ BOOLEAN UpperCase - ) -{ - PCHAR table; - PPH_STRING string; - ULONG i; - - if (UpperCase) - table = PhIntegerToCharUpper; - else - table = PhIntegerToChar; - - string = PhCreateStringEx(NULL, Length * 2 * sizeof(WCHAR)); - - for (i = 0; i < Length; i++) - { - string->Buffer[i * 2] = table[Buffer[i] >> 4]; - string->Buffer[i * 2 + 1] = table[Buffer[i] & 0xf]; - } - - return string; -} - -/** - * Converts a string to an integer. - * - * \param String The string to process. - * \param Base The base which the string uses to represent the integer. The maximum value is 69. - * \param Integer The resulting integer. - */ -BOOLEAN PhpStringToInteger64( - _In_ PPH_STRINGREF String, - _In_ ULONG Base, - _Out_ PULONG64 Integer - ) -{ - BOOLEAN valid = TRUE; - ULONG64 result; - SIZE_T length; - SIZE_T i; - - length = String->Length / sizeof(WCHAR); - result = 0; - - for (i = 0; i < length; i++) - { - ULONG value; - - value = PhCharToInteger[(UCHAR)String->Buffer[i]]; - - if (value < Base) - result = result * Base + value; - else - valid = FALSE; - } - - *Integer = result; - - return valid; -} - -/** - * Converts a string to an integer. - * - * \param String The string to process. - * \param Base The base which the string uses to represent the integer. The maximum value is 69. If - * the parameter is 0, the base is inferred from the string. - * \param Integer The resulting integer. - * - * \remarks If \a Base is 0, the following prefixes may be used to indicate bases: - * - * \li \c 0x Base 16. - * \li \c 0o Base 8. - * \li \c 0b Base 2. - * \li \c 0t Base 3. - * \li \c 0q Base 4. - * \li \c 0w Base 12. - * \li \c 0r Base 32. - * - * If there is no recognized prefix, base 10 is used. - */ -BOOLEAN PhStringToInteger64( - _In_ PPH_STRINGREF String, - _In_opt_ ULONG Base, - _Out_opt_ PLONG64 Integer - ) -{ - BOOLEAN valid; - ULONG64 result; - PH_STRINGREF string; - BOOLEAN negative; - ULONG base; - - if (Base > 69) - return FALSE; - - string = *String; - negative = FALSE; - - if (string.Length != 0 && (string.Buffer[0] == '-' || string.Buffer[0] == '+')) - { - if (string.Buffer[0] == '-') - negative = TRUE; - - PhSkipStringRef(&string, sizeof(WCHAR)); - } - - // If the caller specified a base, don't perform any additional processing. - - if (Base) - { - base = Base; - } - else - { - base = 10; - - if (string.Length >= 2 * sizeof(WCHAR) && string.Buffer[0] == '0') - { - switch (string.Buffer[1]) - { - case 'x': - case 'X': - base = 16; - break; - case 'o': - case 'O': - base = 8; - break; - case 'b': - case 'B': - base = 2; - break; - case 't': // ternary - case 'T': - base = 3; - break; - case 'q': // quaternary - case 'Q': - base = 4; - break; - case 'w': // base 12 - case 'W': - base = 12; - break; - case 'r': // base 32 - case 'R': - base = 32; - break; - } - - if (base != 10) - PhSkipStringRef(&string, 2 * sizeof(WCHAR)); - } - } - - valid = PhpStringToInteger64(&string, base, &result); - - if (Integer) - *Integer = negative ? -(LONG64)result : result; - - return valid; -} - -BOOLEAN PhpStringToDouble( - _In_ PPH_STRINGREF String, - _In_ ULONG Base, - _Out_ DOUBLE *Double - ) -{ - BOOLEAN valid = TRUE; - BOOLEAN dotSeen = FALSE; - DOUBLE result; - DOUBLE fraction; - SIZE_T length; - SIZE_T i; - - length = String->Length / sizeof(WCHAR); - result = 0; - fraction = 1; - - for (i = 0; i < length; i++) - { - if (String->Buffer[i] == '.') - { - if (!dotSeen) - dotSeen = TRUE; - else - valid = FALSE; - } - else - { - ULONG value; - - value = PhCharToInteger[(UCHAR)String->Buffer[i]]; - - if (value < Base) - { - if (!dotSeen) - { - result = result * Base + value; - } - else - { - fraction /= Base; - result = result + value * fraction; - } - } - else - { - valid = FALSE; - } - } - } - - *Double = result; - - return valid; -} - -/** - * Converts a string to a double-precision floating point value. - * - * \param String The string to process. - * \param Base Reserved. - * \param Double The resulting double value. - */ -BOOLEAN PhStringToDouble( - _In_ PPH_STRINGREF String, - _Reserved_ ULONG Base, - _Out_opt_ DOUBLE *Double - ) -{ - BOOLEAN valid; - DOUBLE result; - PH_STRINGREF string; - BOOLEAN negative; - - string = *String; - negative = FALSE; - - if (string.Length != 0 && (string.Buffer[0] == '-' || string.Buffer[0] == '+')) - { - if (string.Buffer[0] == '-') - negative = TRUE; - - PhSkipStringRef(&string, sizeof(WCHAR)); - } - - valid = PhpStringToDouble(&string, 10, &result); - - if (Double) - *Double = negative ? -result : result; - - return valid; -} - -/** - * Converts an integer to a string. - * - * \param Integer The integer to process. - * \param Base The base which the integer is represented with. The maximum value is 69. The base - * cannot be 1. If the parameter is 0, the base used is 10. - * \param Signed TRUE if \a Integer is a signed value, otherwise FALSE. - * - * \return The resulting string, or NULL if an error occurred. - */ -PPH_STRING PhIntegerToString64( - _In_ LONG64 Integer, - _In_opt_ ULONG Base, - _In_ BOOLEAN Signed - ) -{ - PH_FORMAT format; - - if (Base == 1 || Base > 69) - return NULL; - - if (Signed) - PhInitFormatI64D(&format, Integer); - else - PhInitFormatI64U(&format, Integer); - - if (Base != 0) - { - format.Type |= FormatUseRadix; - format.Radix = (UCHAR)Base; - } - - return PhFormat(&format, 1, 0); -} - -VOID PhPrintTimeSpan( - _Out_writes_(PH_TIMESPAN_STR_LEN_1) PWSTR Destination, - _In_ ULONG64 Ticks, - _In_opt_ ULONG Mode - ) -{ - switch (Mode) - { - case PH_TIMESPAN_HMSM: - _snwprintf( - Destination, - PH_TIMESPAN_STR_LEN, - L"%02I64u:%02I64u:%02I64u.%03I64u", - PH_TICKS_PARTIAL_HOURS(Ticks), - PH_TICKS_PARTIAL_MIN(Ticks), - PH_TICKS_PARTIAL_SEC(Ticks), - PH_TICKS_PARTIAL_MS(Ticks) - ); - break; - case PH_TIMESPAN_DHMS: - _snwprintf( - Destination, - PH_TIMESPAN_STR_LEN, - L"%I64u:%02I64u:%02I64u:%02I64u", - PH_TICKS_PARTIAL_DAYS(Ticks), - PH_TICKS_PARTIAL_HOURS(Ticks), - PH_TICKS_PARTIAL_MIN(Ticks), - PH_TICKS_PARTIAL_SEC(Ticks) - ); - break; - default: - _snwprintf( - Destination, - PH_TIMESPAN_STR_LEN, - L"%02I64u:%02I64u:%02I64u", - PH_TICKS_PARTIAL_HOURS(Ticks), - PH_TICKS_PARTIAL_MIN(Ticks), - PH_TICKS_PARTIAL_SEC(Ticks) - ); - break; - } -} - -/** - * Fills a memory block with a ULONG pattern. - * - * \param Memory The memory block. The block must be 4 byte aligned. - * \param Value The ULONG pattern. - * \param Count The number of elements. - */ -VOID PhFillMemoryUlong( - _Inout_updates_(Count) _Needs_align_(4) PULONG Memory, - _In_ ULONG Value, - _In_ SIZE_T Count - ) -{ - __m128i pattern; - SIZE_T count; - - if (PhpVectorLevel < PH_VECTOR_LEVEL_SSE2) - { - if (Count != 0) - { - do - { - *Memory++ = Value; - } while (--Count != 0); - } - - return; - } - - if ((ULONG_PTR)Memory & 0xf) - { - switch ((ULONG_PTR)Memory & 0xf) - { - case 0x4: - if (Count >= 1) - { - *Memory++ = Value; - Count--; - } - __fallthrough; - case 0x8: - if (Count >= 1) - { - *Memory++ = Value; - Count--; - } - __fallthrough; - case 0xc: - if (Count >= 1) - { - *Memory++ = Value; - Count--; - } - break; - } - } - - pattern = _mm_set1_epi32(Value); - count = Count / 4; - - if (count != 0) - { - do - { - _mm_store_si128((__m128i *)Memory, pattern); - Memory += 4; - } while (--count != 0); - } - - switch (Count & 0x3) - { - case 0x3: - *Memory++ = Value; - __fallthrough; - case 0x2: - *Memory++ = Value; - __fallthrough; - case 0x1: - *Memory++ = Value; - break; - } -} - -/** - * Divides an array of numbers by a number. - * - * \param A The destination array, divided by \a B. - * \param B The number. - * \param Count The number of elements. - */ -VOID PhDivideSinglesBySingle( - _Inout_updates_(Count) PFLOAT A, - _In_ FLOAT B, - _In_ SIZE_T Count - ) -{ - PFLOAT endA; - __m128 b; - - if (PhpVectorLevel < PH_VECTOR_LEVEL_SSE2) - { - while (Count--) - *A++ /= B; - - return; - } - - if ((ULONG_PTR)A & 0xf) - { - switch ((ULONG_PTR)A & 0xf) - { - case 0x4: - if (Count >= 1) - { - *A++ /= B; - Count--; - } - __fallthrough; - case 0x8: - if (Count >= 1) - { - *A++ /= B; - Count--; - } - __fallthrough; - case 0xc: - if (Count >= 1) - { - *A++ /= B; - Count--; - } - else - { - return; // essential; A may not be aligned properly - } - break; - } - } - - endA = (PFLOAT)((ULONG_PTR)(A + Count) & ~0xf); - b = _mm_load1_ps(&B); - - while (A != endA) - { - __m128 a; - - a = _mm_load_ps(A); - a = _mm_div_ps(a, b); - _mm_store_ps(A, a); - - A += 4; - } - - switch (Count & 0x3) - { - case 0x3: - *A++ /= B; - __fallthrough; - case 0x2: - *A++ /= B; - __fallthrough; - case 0x1: - *A++ /= B; - break; - } -} +/* + * Process Hacker - + * base support functions + * + * Copyright (C) 2009-2016 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +/* + * This file contains basic low-level code as well as general algorithms and data structures. + * + * Memory allocation. PhAllocate is a wrapper around RtlAllocateHeap, and always allocates from the + * phlib heap. PhAllocatePage is a wrapper around NtAllocateVirtualMemory and allocates pages. + * + * Null-terminated strings. The Ph*StringZ functions manipulate null-terminated strings. The copying + * functions provide a simple way to copy strings which may not be null-terminated, but have a + * specified limit. + * + * String. The design of the string object was chosen for maximum compatibility. As such each string + * buffer must be null-terminated, and each object contains an embedded PH_STRINGREF structure. Note + * that efficient sub-string creation (no copying, only references the parent string object) could + * not be implemented due to the mandatory null-termination. String objects must be regarded as + * immutable (for thread-safety reasons) unless the object has just been created and no references + * have been shared. + * + * String builder. This is a set of functions which allow for efficient modification of strings. For + * performance reasons, these functions modify string objects directly, even though they are + * normally immutable. + * + * List. A simple PVOID list that resizes itself when needed. + * + * Pointer list. Similar to the normal list object, but uses a free list in order to support + * constant time insertion and deletion. In order for the free list to work, normal entries have + * their lowest bit clear while free entries have their lowest bit set, with the index of the next + * free entry in the upper bits. + * + * Hashtable. A hashtable with power-of-two bucket sizes and with all entries stored in a single + * array. This improves locality but may be inefficient when resizing the hashtable. It is a good + * idea to store pointers to objects as entries, as opposed to the objects themselves. + * + * Simple hashtable. A wrapper around the normal hashtable, with PVOID keys and PVOID values. + * + * Free list. A thread-safe memory allocation method where freed blocks are stored in a S-list, and + * allocations are made from this list whenever possible. + * + * Callback. A thread-safe notification mechanism where clients can register callback functions + * which are then invoked by other code. + */ + +#include + +#include +#include + +#include + +#define PH_VECTOR_LEVEL_NONE 0 +#define PH_VECTOR_LEVEL_SSE2 1 +#define PH_VECTOR_LEVEL_AVX 2 + +typedef struct _PHP_BASE_THREAD_CONTEXT +{ + PUSER_THREAD_START_ROUTINE StartAddress; + PVOID Parameter; +} PHP_BASE_THREAD_CONTEXT, *PPHP_BASE_THREAD_CONTEXT; + +VOID NTAPI PhpListDeleteProcedure( + _In_ PVOID Object, + _In_ ULONG Flags + ); + +VOID NTAPI PhpPointerListDeleteProcedure( + _In_ PVOID Object, + _In_ ULONG Flags + ); + +VOID NTAPI PhpQueueDeleteProcedure( + _In_ PVOID Object, + _In_ ULONG Flags + ); + +VOID NTAPI PhpHashtableDeleteProcedure( + _In_ PVOID Object, + _In_ ULONG Flags + ); + +// Types + +PPH_OBJECT_TYPE PhStringType; +PPH_OBJECT_TYPE PhBytesType; +PPH_OBJECT_TYPE PhListType; +PPH_OBJECT_TYPE PhPointerListType; +PPH_OBJECT_TYPE PhHashtableType; + +// Misc. + +static BOOLEAN PhpVectorLevel = PH_VECTOR_LEVEL_NONE; +static PPH_STRING PhSharedEmptyString = NULL; + +// Threads + +static PH_FREE_LIST PhpBaseThreadContextFreeList; +#ifdef DEBUG +ULONG PhDbgThreadDbgTlsIndex; +LIST_ENTRY PhDbgThreadListHead; +PH_QUEUED_LOCK PhDbgThreadListLock = PH_QUEUED_LOCK_INIT; +#endif + +// Data + +static ULONG PhpPrimeNumbers[] = +{ + 0x3, 0x7, 0xb, 0x11, 0x17, 0x1d, 0x25, 0x2f, 0x3b, 0x47, 0x59, 0x6b, 0x83, + 0xa3, 0xc5, 0xef, 0x125, 0x161, 0x1af, 0x209, 0x277, 0x2f9, 0x397, 0x44f, + 0x52f, 0x63d, 0x78b, 0x91d, 0xaf1, 0xd2b, 0xfd1, 0x12fd, 0x16cf, 0x1b65, + 0x20e3, 0x2777, 0x2f6f, 0x38ff, 0x446f, 0x521f, 0x628d, 0x7655, 0x8e01, + 0xaa6b, 0xcc89, 0xf583, 0x126a7, 0x1619b, 0x1a857, 0x1fd3b, 0x26315, 0x2dd67, + 0x3701b, 0x42023, 0x4f361, 0x5f0ed, 0x72125, 0x88e31, 0xa443b, 0xc51eb, + 0xec8c1, 0x11bdbf, 0x154a3f, 0x198c4f, 0x1ea867, 0x24ca19, 0x2c25c1, 0x34fa1b, + 0x3f928f, 0x4c4987, 0x5b8b6f, 0x6dda89 +}; + +/** + * Initializes the base support module. + */ +BOOLEAN PhBaseInitialization( + VOID + ) +{ + PH_OBJECT_TYPE_PARAMETERS parameters; + + // The following relies on the (technically undefined) value of XState being zero before Windows 7 SP1. + // NOTE: This is unused for now. + /*if (USER_SHARED_DATA->XState.EnabledFeatures & XSTATE_MASK_AVX) + PhpVectorLevel = PH_VECTOR_LEVEL_AVX; + else*/ if (USER_SHARED_DATA->ProcessorFeatures[PF_XMMI64_INSTRUCTIONS_AVAILABLE]) + PhpVectorLevel = PH_VECTOR_LEVEL_SSE2; + + PhStringType = PhCreateObjectType(L"String", 0, NULL); + PhBytesType = PhCreateObjectType(L"Bytes", 0, NULL); + + parameters.FreeListSize = sizeof(PH_LIST); + parameters.FreeListCount = 128; + + PhListType = PhCreateObjectTypeEx(L"List", PH_OBJECT_TYPE_USE_FREE_LIST, PhpListDeleteProcedure, ¶meters); + PhPointerListType = PhCreateObjectType(L"PointerList", 0, PhpPointerListDeleteProcedure); + + parameters.FreeListSize = sizeof(PH_HASHTABLE); + parameters.FreeListCount = 64; + + PhHashtableType = PhCreateObjectTypeEx(L"Hashtable", PH_OBJECT_TYPE_USE_FREE_LIST, PhpHashtableDeleteProcedure, ¶meters); + + PhInitializeFreeList(&PhpBaseThreadContextFreeList, sizeof(PHP_BASE_THREAD_CONTEXT), 16); + +#ifdef DEBUG + PhDbgThreadDbgTlsIndex = TlsAlloc(); + InitializeListHead(&PhDbgThreadListHead); +#endif + + return TRUE; +} + +NTSTATUS PhpBaseThreadStart( + _In_ PVOID Parameter + ) +{ + NTSTATUS status; + HRESULT result; + PHP_BASE_THREAD_CONTEXT context; +#ifdef DEBUG + PHP_BASE_THREAD_DBG dbg; +#endif + + context = *(PPHP_BASE_THREAD_CONTEXT)Parameter; + PhFreeToFreeList(&PhpBaseThreadContextFreeList, Parameter); + +#ifdef DEBUG + dbg.ClientId = NtCurrentTeb()->ClientId; + + dbg.StartAddress = context.StartAddress; + dbg.Parameter = context.Parameter; + dbg.CurrentAutoPool = NULL; + + PhAcquireQueuedLockExclusive(&PhDbgThreadListLock); + InsertTailList(&PhDbgThreadListHead, &dbg.ListEntry); + PhReleaseQueuedLockExclusive(&PhDbgThreadListLock); + + TlsSetValue(PhDbgThreadDbgTlsIndex, &dbg); +#endif + + // Initialization code + + result = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE); + + // Call the user-supplied function. + status = context.StartAddress(context.Parameter); + + // De-initialization code + + if (result == S_OK || result == S_FALSE) + CoUninitialize(); + +#ifdef DEBUG + PhAcquireQueuedLockExclusive(&PhDbgThreadListLock); + RemoveEntryList(&dbg.ListEntry); + PhReleaseQueuedLockExclusive(&PhDbgThreadListLock); +#endif + + return status; +} + +/** + * Creates a thread. + * + * \param StackSize The initial stack size of the thread. + * \param StartAddress The function to execute in the thread. + * \param Parameter A user-defined value to pass to the function. + */ +HANDLE PhCreateThread( + _In_opt_ SIZE_T StackSize, + _In_ PUSER_THREAD_START_ROUTINE StartAddress, + _In_opt_ PVOID Parameter + ) +{ + HANDLE threadHandle; + PPHP_BASE_THREAD_CONTEXT context; + + context = PhAllocateFromFreeList(&PhpBaseThreadContextFreeList); + context->StartAddress = StartAddress; + context->Parameter = Parameter; + + threadHandle = CreateThread( + NULL, + StackSize, + PhpBaseThreadStart, + context, + 0, + NULL + ); + + if (threadHandle) + { + PHLIB_INC_STATISTIC(BaseThreadsCreated); + return threadHandle; + } + else + { + PHLIB_INC_STATISTIC(BaseThreadsCreateFailed); + PhFreeToFreeList(&PhpBaseThreadContextFreeList, context); + return NULL; + } +} + +/** + * Gets the current system time (UTC). + * + * \remarks Use this function instead of NtQuerySystemTime() because no system calls are involved. + */ +VOID PhQuerySystemTime( + _Out_ PLARGE_INTEGER SystemTime + ) +{ + do + { + SystemTime->HighPart = USER_SHARED_DATA->SystemTime.High1Time; + SystemTime->LowPart = USER_SHARED_DATA->SystemTime.LowPart; + } while (SystemTime->HighPart != USER_SHARED_DATA->SystemTime.High2Time); +} + +/** + * Gets the offset of the current time zone from UTC. + */ +VOID PhQueryTimeZoneBias( + _Out_ PLARGE_INTEGER TimeZoneBias + ) +{ + do + { + TimeZoneBias->HighPart = USER_SHARED_DATA->TimeZoneBias.High1Time; + TimeZoneBias->LowPart = USER_SHARED_DATA->TimeZoneBias.LowPart; + } while (TimeZoneBias->HighPart != USER_SHARED_DATA->TimeZoneBias.High2Time); +} + +/** + * Converts system time to local time. + * + * \param SystemTime A UTC time value. + * \param LocalTime A variable which receives the local time value. This may be the same variable as + * \a SystemTime. + * + * \remarks Use this function instead of RtlSystemTimeToLocalTime() because no system calls are + * involved. + */ +VOID PhSystemTimeToLocalTime( + _In_ PLARGE_INTEGER SystemTime, + _Out_ PLARGE_INTEGER LocalTime + ) +{ + LARGE_INTEGER timeZoneBias; + + PhQueryTimeZoneBias(&timeZoneBias); + LocalTime->QuadPart = SystemTime->QuadPart - timeZoneBias.QuadPart; +} + +/** + * Converts local time to system time. + * + * \param LocalTime A local time value. + * \param SystemTime A variable which receives the UTC time value. This may be the same variable as + * \a LocalTime. + * + * \remarks Use this function instead of RtlLocalTimeToSystemTime() because no system calls are + * involved. + */ +VOID PhLocalTimeToSystemTime( + _In_ PLARGE_INTEGER LocalTime, + _Out_ PLARGE_INTEGER SystemTime + ) +{ + LARGE_INTEGER timeZoneBias; + + PhQueryTimeZoneBias(&timeZoneBias); + SystemTime->QuadPart = LocalTime->QuadPart + timeZoneBias.QuadPart; +} + +/** + * Allocates a block of memory. + * + * \param Size The number of bytes to allocate. + * + * \return A pointer to the allocated block of memory. + * + * \remarks If the function fails to allocate the block of memory, it raises an exception. The block + * is guaranteed to be aligned at MEMORY_ALLOCATION_ALIGNMENT bytes. + */ +_May_raise_ +_Check_return_ +_Ret_notnull_ +_Post_writable_byte_size_(Size) +PVOID PhAllocate( + _In_ SIZE_T Size + ) +{ + return RtlAllocateHeap(PhHeapHandle, HEAP_GENERATE_EXCEPTIONS, Size); +} + +/** + * Allocates a block of memory. + * + * \param Size The number of bytes to allocate. + * + * \return A pointer to the allocated block of memory, or NULL if the block could not be allocated. + */ +PVOID PhAllocateSafe( + _In_ SIZE_T Size + ) +{ + return RtlAllocateHeap(PhHeapHandle, 0, Size); +} + +/** + * Allocates a block of memory. + * + * \param Size The number of bytes to allocate. + * \param Flags Flags controlling the allocation. + * + * \return A pointer to the allocated block of memory, or NULL if the block could not be allocated. + */ +PVOID PhAllocateExSafe( + _In_ SIZE_T Size, + _In_ ULONG Flags + ) +{ + return RtlAllocateHeap(PhHeapHandle, Flags, Size); +} + +/** + * Frees a block of memory allocated with PhAllocate(). + * + * \param Memory A pointer to a block of memory. + */ +VOID PhFree( + _Frees_ptr_opt_ PVOID Memory + ) +{ + RtlFreeHeap(PhHeapHandle, 0, Memory); +} + +/** + * Re-allocates a block of memory originally allocated with PhAllocate(). + * + * \param Memory A pointer to a block of memory. + * \param Size The new size of the memory block, in bytes. + * + * \return A pointer to the new block of memory. The existing contents of the memory block are + * copied to the new block. + * + * \remarks If the function fails to allocate the block of memory, it raises an exception. + */ +_May_raise_ +_Post_writable_byte_size_(Size) +PVOID PhReAllocate( + _Frees_ptr_opt_ PVOID Memory, + _In_ SIZE_T Size + ) +{ + return RtlReAllocateHeap(PhHeapHandle, HEAP_GENERATE_EXCEPTIONS, Memory, Size); +} + +/** + * Re-allocates a block of memory originally allocated with PhAllocate(). + * + * \param Memory A pointer to a block of memory. + * \param Size The new size of the memory block, in bytes. + * + * \return A pointer to the new block of memory, or NULL if the block could not be allocated. The + * existing contents of the memory block are copied to the new block. + */ +PVOID PhReAllocateSafe( + _In_ PVOID Memory, + _In_ SIZE_T Size + ) +{ + return RtlReAllocateHeap(PhHeapHandle, 0, Memory, Size); +} + +/** + * Allocates pages of memory. + * + * \param Size The number of bytes to allocate. The number of pages allocated will be large enough + * to contain \a Size bytes. + * \param NewSize The number of bytes actually allocated. This is \a Size rounded up to the next + * multiple of PAGE_SIZE. + * + * \return A pointer to the allocated block of memory, or NULL if the block could not be allocated. + */ +_Check_return_ +_Ret_maybenull_ +PVOID PhAllocatePage( + _In_ SIZE_T Size, + _Out_opt_ PSIZE_T NewSize + ) +{ + PVOID baseAddress; + + baseAddress = NULL; + + if (NT_SUCCESS(NtAllocateVirtualMemory( + NtCurrentProcess(), + &baseAddress, + 0, + &Size, + MEM_COMMIT, + PAGE_READWRITE + ))) + { + if (NewSize) + *NewSize = Size; + + return baseAddress; + } + else + { + return NULL; + } +} + +/** + * Frees pages of memory allocated with PhAllocatePage(). + * + * \param Memory A pointer to a block of memory. + */ +VOID PhFreePage( + _Frees_ptr_opt_ PVOID Memory + ) +{ + SIZE_T size; + + size = 0; + + NtFreeVirtualMemory( + NtCurrentProcess(), + &Memory, + &size, + MEM_RELEASE + ); +} + +/** + * Determines the length of the specified string, in characters. + * + * \param String The string. + */ +SIZE_T PhCountStringZ( + _In_ PWSTR String + ) +{ + if (PhpVectorLevel >= PH_VECTOR_LEVEL_SSE2) + { + PWSTR p; + ULONG unaligned; + __m128i b; + __m128i z; + ULONG mask; + ULONG index; + + p = (PWSTR)((ULONG_PTR)String & ~0xe); // String should be 2 byte aligned + unaligned = PtrToUlong(String) & 0xf; + z = _mm_setzero_si128(); + + if (unaligned != 0) + { + b = _mm_load_si128((__m128i *)p); + b = _mm_cmpeq_epi16(b, z); + mask = _mm_movemask_epi8(b) >> unaligned; + + if (_BitScanForward(&index, mask)) + return index / sizeof(WCHAR); + + p += 16 / sizeof(WCHAR); + } + + while (TRUE) + { + b = _mm_load_si128((__m128i *)p); + b = _mm_cmpeq_epi16(b, z); + mask = _mm_movemask_epi8(b); + + if (_BitScanForward(&index, mask)) + return (SIZE_T)(p - String) + index / sizeof(WCHAR); + + p += 16 / sizeof(WCHAR); + } + } + else + { + return wcslen(String); + } +} + +/** + * Allocates space for and copies a byte string. + * + * \param String The string to duplicate. + * + * \return The new string, which can be freed using PhFree(). + */ +PSTR PhDuplicateBytesZ( + _In_ PSTR String + ) +{ + PSTR newString; + SIZE_T length; + + length = strlen(String) + 1; // include the null terminator + + newString = PhAllocate(length); + memcpy(newString, String, length); + + return newString; +} + +/** + * Allocates space for and copies a byte string. + * + * \param String The string to duplicate. + * + * \return The new string, which can be freed using PhFree(), or NULL if storage could not be + * allocated. + */ +PSTR PhDuplicateBytesZSafe( + _In_ PSTR String + ) +{ + PSTR newString; + SIZE_T length; + + length = strlen(String) + 1; // include the null terminator + + newString = PhAllocateSafe(length); + + if (!newString) + return NULL; + + memcpy(newString, String, length); + + return newString; +} + +/** + * Allocates space for and copies a 16-bit string. + * + * \param String The string to duplicate. + * + * \return The new string, which can be freed using PhFree(). + */ +PWSTR PhDuplicateStringZ( + _In_ PWSTR String + ) +{ + PWSTR newString; + SIZE_T length; + + length = (PhCountStringZ(String) + 1) * sizeof(WCHAR); // include the null terminator + + newString = PhAllocate(length); + memcpy(newString, String, length); + + return newString; +} + +/** + * Copies a string with optional null termination and a maximum number of characters. + * + * \param InputBuffer A pointer to the input string. + * \param InputCount The maximum number of characters to copy, not including the null terminator. + * Specify -1 for no limit. + * \param OutputBuffer A pointer to the output buffer. + * \param OutputCount The number of characters in the output buffer, including the null terminator. + * \param ReturnCount A variable which receives the number of characters required to contain the + * input string, including the null terminator. If the function returns TRUE, this variable contains + * the number of characters written to the output buffer. + * + * \return TRUE if the input string was copied to the output string, otherwise FALSE. + * + * \remarks The function stops copying when it encounters the first null character in the input + * string. It will also stop copying when it reaches the character count specified in \a InputCount, + * if \a InputCount is not -1. + */ +BOOLEAN PhCopyBytesZ( + _In_ PSTR InputBuffer, + _In_ SIZE_T InputCount, + _Out_writes_opt_z_(OutputCount) PSTR OutputBuffer, + _In_ SIZE_T OutputCount, + _Out_opt_ PSIZE_T ReturnCount + ) +{ + SIZE_T i; + BOOLEAN copied; + + // Determine the length of the input string. + + if (InputCount != -1) + { + i = 0; + + while (i < InputCount && InputBuffer[i]) + i++; + } + else + { + i = strlen(InputBuffer); + } + + // Copy the string if there is enough room. + + if (OutputBuffer && OutputCount >= i + 1) // need one character for null terminator + { + memcpy(OutputBuffer, InputBuffer, i); + OutputBuffer[i] = 0; + copied = TRUE; + } + else + { + copied = FALSE; + } + + if (ReturnCount) + *ReturnCount = i + 1; + + return copied; +} + +/** + * Copies a string with optional null termination and a maximum number of characters. + * + * \param InputBuffer A pointer to the input string. + * \param InputCount The maximum number of characters to copy, not including the null terminator. + * Specify -1 for no limit. + * \param OutputBuffer A pointer to the output buffer. + * \param OutputCount The number of characters in the output buffer, including the null terminator. + * \param ReturnCount A variable which receives the number of characters required to contain the + * input string, including the null terminator. If the function returns TRUE, this variable contains + * the number of characters written to the output buffer. + * + * \return TRUE if the input string was copied to the output string, otherwise FALSE. + * + * \remarks The function stops copying when it encounters the first null character in the input + * string. It will also stop copying when it reaches the character count specified in \a InputCount, + * if \a InputCount is not -1. + */ +BOOLEAN PhCopyStringZ( + _In_ PWSTR InputBuffer, + _In_ SIZE_T InputCount, + _Out_writes_opt_z_(OutputCount) PWSTR OutputBuffer, + _In_ SIZE_T OutputCount, + _Out_opt_ PSIZE_T ReturnCount + ) +{ + SIZE_T i; + BOOLEAN copied; + + // Determine the length of the input string. + + if (InputCount != -1) + { + i = 0; + + while (i < InputCount && InputBuffer[i]) + i++; + } + else + { + i = PhCountStringZ(InputBuffer); + } + + // Copy the string if there is enough room. + + if (OutputBuffer && OutputCount >= i + 1) // need one character for null terminator + { + memcpy(OutputBuffer, InputBuffer, i * sizeof(WCHAR)); + OutputBuffer[i] = 0; + copied = TRUE; + } + else + { + copied = FALSE; + } + + if (ReturnCount) + *ReturnCount = i + 1; + + return copied; +} + +/** + * Copies a string with optional null termination and a maximum number of characters. + * + * \param InputBuffer A pointer to the input string. + * \param InputCount The maximum number of characters to copy, not including the null terminator. + * Specify -1 for no limit. + * \param OutputBuffer A pointer to the output buffer. + * \param OutputCount The number of characters in the output buffer, including the null terminator. + * \param ReturnCount A variable which receives the number of characters required to contain the + * input string, including the null terminator. If the function returns TRUE, this variable contains + * the number of characters written to the output buffer. + * + * \return TRUE if the input string was copied to the output string, otherwise FALSE. + * + * \remarks The function stops copying when it encounters the first null character in the input + * string. It will also stop copying when it reaches the character count specified in \a InputCount, + * if \a InputCount is not -1. + */ +BOOLEAN PhCopyStringZFromBytes( + _In_ PSTR InputBuffer, + _In_ SIZE_T InputCount, + _Out_writes_opt_z_(OutputCount) PWSTR OutputBuffer, + _In_ SIZE_T OutputCount, + _Out_opt_ PSIZE_T ReturnCount + ) +{ + SIZE_T i; + BOOLEAN copied; + + // Determine the length of the input string. + + if (InputCount != -1) + { + i = 0; + + while (i < InputCount && InputBuffer[i]) + i++; + } + else + { + i = strlen(InputBuffer); + } + + // Copy the string if there is enough room. + + if (OutputBuffer && OutputCount >= i + 1) // need one character for null terminator + { + PhZeroExtendToUtf16Buffer(InputBuffer, i, OutputBuffer); + OutputBuffer[i] = 0; + copied = TRUE; + } + else + { + copied = FALSE; + } + + if (ReturnCount) + *ReturnCount = i + 1; + + return copied; +} + +/** + * Copies a string with optional null termination and a maximum number of characters. + * + * \param InputBuffer A pointer to the input string. + * \param InputCount The maximum number of characters to copy, not including the null terminator. + * Specify -1 for no limit. + * \param OutputBuffer A pointer to the output buffer. + * \param OutputCount The number of characters in the output buffer, including the null terminator. + * \param ReturnCount A variable which receives the number of characters required to contain the + * input string, including the null terminator. If the function returns TRUE, this variable contains + * the number of characters written to the output buffer. + * + * \return TRUE if the input string was copied to the output string, otherwise FALSE. + * + * \remarks The function stops copying when it encounters the first null character in the input + * string. It will also stop copying when it reaches the character count specified in \a InputCount, + * if \a InputCount is not -1. + */ +BOOLEAN PhCopyStringZFromMultiByte( + _In_ PSTR InputBuffer, + _In_ SIZE_T InputCount, + _Out_writes_opt_z_(OutputCount) PWSTR OutputBuffer, + _In_ SIZE_T OutputCount, + _Out_opt_ PSIZE_T ReturnCount + ) +{ + NTSTATUS status; + SIZE_T i; + ULONG unicodeBytes; + BOOLEAN copied; + + // Determine the length of the input string. + + if (InputCount != -1) + { + i = 0; + + while (i < InputCount && InputBuffer[i]) + i++; + } + else + { + i = strlen(InputBuffer); + } + + // Determine the length of the output string. + + status = RtlMultiByteToUnicodeSize( + &unicodeBytes, + InputBuffer, + (ULONG)i + ); + + if (!NT_SUCCESS(status)) + { + if (ReturnCount) + *ReturnCount = -1; + + return FALSE; + } + + // Convert the string to Unicode if there is enough room. + + if (OutputBuffer && OutputCount >= unicodeBytes / sizeof(WCHAR) + 1) + { + status = RtlMultiByteToUnicodeN( + OutputBuffer, + unicodeBytes, + NULL, + InputBuffer, + (ULONG)i + ); + + if (NT_SUCCESS(status)) + { + // RtlMultiByteToUnicodeN doesn't null terminate the string. + *(PWCHAR)((PCHAR)OutputBuffer + unicodeBytes) = 0; + copied = TRUE; + } + else + { + copied = FALSE; + } + } + else + { + copied = FALSE; + } + + if (ReturnCount) + *ReturnCount = unicodeBytes / sizeof(WCHAR) + 1; + + return copied; +} + +FORCEINLINE LONG PhpCompareRightNatural( + _In_ PWSTR A, + _In_ PWSTR B + ) +{ + LONG bias = 0; + + for (; ; A++, B++) + { + if (!PhIsDigitCharacter(*A) && !PhIsDigitCharacter(*B)) + { + return bias; + } + else if (!PhIsDigitCharacter(*A)) + { + return -1; + } + else if (!PhIsDigitCharacter(*B)) + { + return 1; + } + else if (*A < *B) + { + if (bias == 0) + bias = -1; + } + else if (*A > *B) + { + if (bias == 0) + bias = 1; + } + else if (!*A && !*B) + { + return bias; + } + } + + return 0; +} + +FORCEINLINE LONG PhpCompareLeftNatural( + _In_ PWSTR A, + _In_ PWSTR B + ) +{ + for (; ; A++, B++) + { + if (!PhIsDigitCharacter(*A) && !PhIsDigitCharacter(*B)) + { + return 0; + } + else if (!PhIsDigitCharacter(*A)) + { + return -1; + } + else if (!PhIsDigitCharacter(*B)) + { + return 1; + } + else if (*A < *B) + { + return -1; + } + else if (*A > *B) + { + return 1; + } + } + + return 0; +} + +FORCEINLINE LONG PhpCompareStringZNatural( + _In_ PWSTR A, + _In_ PWSTR B, + _In_ BOOLEAN IgnoreCase + ) +{ + /* strnatcmp.c -- Perform 'natural order' comparisons of strings in C. + Copyright (C) 2000, 2004 by Martin Pool + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + This code has been modified for Process Hacker. + */ + + ULONG ai, bi; + WCHAR ca, cb; + LONG result; + BOOLEAN fractional; + + ai = 0; + bi = 0; + + while (TRUE) + { + ca = A[ai]; + cb = B[bi]; + + /* Skip over leading spaces or zeros. */ + + while (ca == ' ') + ca = A[++ai]; + + while (cb == ' ') + cb = B[++bi]; + + /* Process run of digits. */ + if (PhIsDigitCharacter(ca) && PhIsDigitCharacter(cb)) + { + fractional = (ca == '0' || cb == '0'); + + if (fractional) + { + if ((result = PhpCompareLeftNatural(A + ai, B + bi)) != 0) + return result; + } + else + { + if ((result = PhpCompareRightNatural(A + ai, B + bi)) != 0) + return result; + } + } + + if (!ca && !cb) + { + /* Strings are considered the same. */ + return 0; + } + + if (IgnoreCase) + { + ca = towupper(ca); + cb = towupper(cb); + } + + if (ca < cb) + return -1; + else if (ca > cb) + return 1; + + ai++; + bi++; + } +} + +/** + * Compares two strings in natural sort order. + * + * \param A The first string. + * \param B The second string. + * \param IgnoreCase Whether to ignore character cases. + */ +LONG PhCompareStringZNatural( + _In_ PWSTR A, + _In_ PWSTR B, + _In_ BOOLEAN IgnoreCase + ) +{ + if (!IgnoreCase) + return PhpCompareStringZNatural(A, B, FALSE); + else + return PhpCompareStringZNatural(A, B, TRUE); +} + +/** + * Compares two strings. + * + * \param String1 The first string. + * \param String2 The second string. + * \param IgnoreCase TRUE to perform a case-insensitive comparison, otherwise FALSE. + */ +LONG PhCompareStringRef( + _In_ PPH_STRINGREF String1, + _In_ PPH_STRINGREF String2, + _In_ BOOLEAN IgnoreCase + ) +{ + SIZE_T l1; + SIZE_T l2; + PWCHAR s1; + PWCHAR s2; + WCHAR c1; + WCHAR c2; + PWCHAR end; + + // Note: this function assumes that the difference between the lengths of the two strings can + // fit inside a LONG. + + l1 = String1->Length; + l2 = String2->Length; + assert(!(l1 & 1)); + assert(!(l2 & 1)); + s1 = String1->Buffer; + s2 = String2->Buffer; + + end = (PWCHAR)((PCHAR)s1 + (l1 <= l2 ? l1 : l2)); + + if (!IgnoreCase) + { + while (s1 != end) + { + c1 = *s1; + c2 = *s2; + + if (c1 != c2) + return (LONG)c1 - (LONG)c2; + + s1++; + s2++; + } + } + else + { + while (s1 != end) + { + c1 = *s1; + c2 = *s2; + + if (c1 != c2) + { + c1 = RtlUpcaseUnicodeChar(c1); + c2 = RtlUpcaseUnicodeChar(c2); + + if (c1 != c2) + return (LONG)c1 - (LONG)c2; + } + + s1++; + s2++; + } + } + + return (LONG)(l1 - l2); +} + +/** + * Determines if two strings are equal. + * + * \param String1 The first string. + * \param String2 The second string. + * \param IgnoreCase TRUE to perform a case-insensitive comparison, otherwise FALSE. + */ +BOOLEAN PhEqualStringRef( + _In_ PPH_STRINGREF String1, + _In_ PPH_STRINGREF String2, + _In_ BOOLEAN IgnoreCase + ) +{ + SIZE_T l1; + SIZE_T l2; + PWSTR s1; + PWSTR s2; + WCHAR c1; + WCHAR c2; + SIZE_T length; + + l1 = String1->Length; + l2 = String2->Length; + assert(!(l1 & 1)); + assert(!(l2 & 1)); + + if (l1 != l2) + return FALSE; + + s1 = String1->Buffer; + s2 = String2->Buffer; + + if (PhpVectorLevel >= PH_VECTOR_LEVEL_SSE2) + { + length = l1 / 16; + + if (length != 0) + { + __m128i b1; + __m128i b2; + + do + { + b1 = _mm_loadu_si128((__m128i *)s1); + b2 = _mm_loadu_si128((__m128i *)s2); + b1 = _mm_cmpeq_epi32(b1, b2); + + if (_mm_movemask_epi8(b1) != 0xffff) + { + if (!IgnoreCase) + { + return FALSE; + } + else + { + // Compare character-by-character to ignore case. + l1 = length * 16 + (l1 & 15); + l1 /= sizeof(WCHAR); + goto CompareCharacters; + } + } + + s1 += 16 / sizeof(WCHAR); + s2 += 16 / sizeof(WCHAR); + } while (--length != 0); + } + + // Compare character-by-character because we have no more 16-byte blocks to compare. + l1 = (l1 & 15) / sizeof(WCHAR); + } + else + { + length = l1 / sizeof(ULONG_PTR); + + if (length != 0) + { + do + { + if (*(PULONG_PTR)s1 != *(PULONG_PTR)s2) + { + if (!IgnoreCase) + { + return FALSE; + } + else + { + // Compare character-by-character to ignore case. + l1 = length * sizeof(ULONG_PTR) + (l1 & (sizeof(ULONG_PTR) - 1)); + l1 /= sizeof(WCHAR); + goto CompareCharacters; + } + } + + s1 += sizeof(ULONG_PTR) / sizeof(WCHAR); + s2 += sizeof(ULONG_PTR) / sizeof(WCHAR); + } while (--length != 0); + } + + // Compare character-by-character because we have no more ULONG_PTR blocks to compare. + l1 = (l1 & (sizeof(ULONG_PTR) - 1)) / sizeof(WCHAR); + } + +CompareCharacters: + if (l1 != 0) + { + if (!IgnoreCase) + { + do + { + c1 = *s1; + c2 = *s2; + + if (c1 != c2) + return FALSE; + + s1++; + s2++; + } while (--l1 != 0); + } + else + { + do + { + c1 = *s1; + c2 = *s2; + + if (c1 != c2) + { + c1 = RtlUpcaseUnicodeChar(c1); + c2 = RtlUpcaseUnicodeChar(c2); + + if (c1 != c2) + return FALSE; + } + + s1++; + s2++; + } while (--l1 != 0); + } + } + + return TRUE; +} + +/** + * Locates a character in a string. + * + * \param String The string to search. + * \param Character The character to search for. + * \param IgnoreCase TRUE to perform a case-insensitive search, otherwise FALSE. + * + * \return The index, in characters, of the first occurrence of \a Character in \a String1. If + * \a Character was not found, -1 is returned. + */ +ULONG_PTR PhFindCharInStringRef( + _In_ PPH_STRINGREF String, + _In_ WCHAR Character, + _In_ BOOLEAN IgnoreCase + ) +{ + PWSTR buffer; + SIZE_T length; + + buffer = String->Buffer; + length = String->Length / sizeof(WCHAR); + + if (!IgnoreCase) + { + if (PhpVectorLevel >= PH_VECTOR_LEVEL_SSE2) + { + SIZE_T length16; + + length16 = String->Length / 16; + length &= 7; + + if (length16 != 0) + { + __m128i pattern; + __m128i block; + ULONG mask; + ULONG index; + + pattern = _mm_set1_epi16(Character); + + do + { + block = _mm_loadu_si128((__m128i *)buffer); + block = _mm_cmpeq_epi16(block, pattern); + mask = _mm_movemask_epi8(block); + + if (_BitScanForward(&index, mask)) + return (String->Length - length16 * 16) / sizeof(WCHAR) - length + index / 2; + + buffer += 16 / sizeof(WCHAR); + } while (--length16 != 0); + } + } + + if (length != 0) + { + do + { + if (*buffer == Character) + return String->Length / sizeof(WCHAR) - length; + + buffer++; + } while (--length != 0); + } + } + else + { + if (length != 0) + { + WCHAR c; + + c = RtlUpcaseUnicodeChar(Character); + + do + { + if (RtlUpcaseUnicodeChar(*buffer) == c) + return String->Length / sizeof(WCHAR) - length; + + buffer++; + } while (--length != 0); + } + } + + return -1; +} + +/** + * Locates a character in a string, searching backwards. + * + * \param String The string to search. + * \param Character The character to search for. + * \param IgnoreCase TRUE to perform a case-insensitive search, otherwise FALSE. + * + * \return The index, in characters, of the last occurrence of \a Character in \a String1. If + * \a Character was not found, -1 is returned. + */ +ULONG_PTR PhFindLastCharInStringRef( + _In_ PPH_STRINGREF String, + _In_ WCHAR Character, + _In_ BOOLEAN IgnoreCase + ) +{ + PWCHAR buffer; + SIZE_T length; + + buffer = (PWCHAR)((PCHAR)String->Buffer + String->Length); + length = String->Length / sizeof(WCHAR); + + if (!IgnoreCase) + { + if (PhpVectorLevel >= PH_VECTOR_LEVEL_SSE2) + { + SIZE_T length16; + + length16 = String->Length / 16; + length &= 7; + + if (length16 != 0) + { + __m128i pattern; + __m128i block; + ULONG mask; + ULONG index; + + pattern = _mm_set1_epi16(Character); + buffer -= 16 / sizeof(WCHAR); + + do + { + block = _mm_loadu_si128((__m128i *)buffer); + block = _mm_cmpeq_epi16(block, pattern); + mask = _mm_movemask_epi8(block); + + if (_BitScanReverse(&index, mask)) + return (length16 - 1) * 16 / sizeof(WCHAR) + length + index / 2; + + buffer -= 16 / sizeof(WCHAR); + } while (--length16 != 0); + + buffer += 16 / sizeof(WCHAR); + } + } + + if (length != 0) + { + buffer--; + + do + { + if (*buffer == Character) + return length - 1; + + buffer--; + } while (--length != 0); + } + } + else + { + if (length != 0) + { + WCHAR c; + + c = RtlUpcaseUnicodeChar(Character); + buffer--; + + do + { + if (RtlUpcaseUnicodeChar(*buffer) == c) + return length - 1; + + buffer--; + } while (--length != 0); + } + } + + return -1; +} + +/** + * Locates a string in a string. + * + * \param String The string to search. + * \param SubString The string to search for. + * \param IgnoreCase TRUE to perform a case-insensitive search, otherwise FALSE. + * + * \return The index, in characters, of the first occurrence of \a SubString in \a String. If + * \a SubString was not found, -1 is returned. + */ +ULONG_PTR PhFindStringInStringRef( + _In_ PPH_STRINGREF String, + _In_ PPH_STRINGREF SubString, + _In_ BOOLEAN IgnoreCase + ) +{ + SIZE_T length1; + SIZE_T length2; + PH_STRINGREF sr1; + PH_STRINGREF sr2; + WCHAR c; + SIZE_T i; + + length1 = String->Length / sizeof(WCHAR); + length2 = SubString->Length / sizeof(WCHAR); + + // Can't be a substring if it's bigger than the first string. + if (length2 > length1) + return -1; + // We always get a match if the substring is zero-length. + if (length2 == 0) + return 0; + + sr1.Buffer = String->Buffer; + sr1.Length = SubString->Length - sizeof(WCHAR); + sr2.Buffer = SubString->Buffer; + sr2.Length = SubString->Length - sizeof(WCHAR); + + if (!IgnoreCase) + { + c = *sr2.Buffer++; + + for (i = length1 - length2 + 1; i != 0; i--) + { + if (*sr1.Buffer++ == c && PhEqualStringRef(&sr1, &sr2, FALSE)) + { + goto FoundUString; + } + } + } + else + { + c = RtlUpcaseUnicodeChar(*sr2.Buffer++); + + for (i = length1 - length2 + 1; i != 0; i--) + { + if (RtlUpcaseUnicodeChar(*sr1.Buffer++) == c && PhEqualStringRef(&sr1, &sr2, TRUE)) + { + goto FoundUString; + } + } + } + + return -1; +FoundUString: + return (ULONG_PTR)(sr1.Buffer - String->Buffer - 1); +} + +/** + * Splits a string. + * + * \param Input The input string. + * \param Separator The character to split at. + * \param FirstPart A variable which receives the part of \a Input before the separator. This may be + * the same variable as \a Input. If the separator is not found in \a Input, this variable is set to + * \a Input. + * \param SecondPart A variable which recieves the part of \a Input after the separator. This may be + * the same variable as \a Input. If the separator is not found in \a Input, this variable is set to + * an empty string. + * + * \return TRUE if \a Separator was found in \a Input, otherwise FALSE. + */ +BOOLEAN PhSplitStringRefAtChar( + _In_ PPH_STRINGREF Input, + _In_ WCHAR Separator, + _Out_ PPH_STRINGREF FirstPart, + _Out_ PPH_STRINGREF SecondPart + ) +{ + PH_STRINGREF input; + ULONG_PTR index; + + input = *Input; // get a copy of the input because FirstPart/SecondPart may alias Input + index = PhFindCharInStringRef(Input, Separator, FALSE); + + if (index == -1) + { + // The separator was not found. + + FirstPart->Buffer = Input->Buffer; + FirstPart->Length = Input->Length; + SecondPart->Buffer = NULL; + SecondPart->Length = 0; + + return FALSE; + } + + FirstPart->Buffer = input.Buffer; + FirstPart->Length = index * sizeof(WCHAR); + SecondPart->Buffer = (PWCHAR)((PCHAR)input.Buffer + index * sizeof(WCHAR) + sizeof(WCHAR)); + SecondPart->Length = input.Length - index * sizeof(WCHAR) - sizeof(WCHAR); + + return TRUE; +} + +/** + * Splits a string at the last occurrence of a character. + * + * \param Input The input string. + * \param Separator The character to split at. + * \param FirstPart A variable which receives the part of \a Input before the separator. This may be + * the same variable as \a Input. If the separator is not found in \a Input, this variable is set to + * \a Input. + * \param SecondPart A variable which recieves the part of \a Input after the separator. This may be + * the same variable as \a Input. If the separator is not found in \a Input, this variable is set to + * an empty string. + * + * \return TRUE if \a Separator was found in \a Input, otherwise FALSE. + */ +BOOLEAN PhSplitStringRefAtLastChar( + _In_ PPH_STRINGREF Input, + _In_ WCHAR Separator, + _Out_ PPH_STRINGREF FirstPart, + _Out_ PPH_STRINGREF SecondPart + ) +{ + PH_STRINGREF input; + ULONG_PTR index; + + input = *Input; // get a copy of the input because FirstPart/SecondPart may alias Input + index = PhFindLastCharInStringRef(Input, Separator, FALSE); + + if (index == -1) + { + // The separator was not found. + + FirstPart->Buffer = Input->Buffer; + FirstPart->Length = Input->Length; + SecondPart->Buffer = NULL; + SecondPart->Length = 0; + + return FALSE; + } + + FirstPart->Buffer = input.Buffer; + FirstPart->Length = index * sizeof(WCHAR); + SecondPart->Buffer = (PWCHAR)((PCHAR)input.Buffer + index * sizeof(WCHAR) + sizeof(WCHAR)); + SecondPart->Length = input.Length - index * sizeof(WCHAR) - sizeof(WCHAR); + + return TRUE; +} + +/** + * Splits a string. + * + * \param Input The input string. + * \param Separator The string to split at. + * \param IgnoreCase TRUE to perform a case-insensitive search, otherwise FALSE. + * \param FirstPart A variable which receives the part of \a Input before the separator. This may be + * the same variable as \a Input. If the separator is not found in \a Input, this variable is set to + * \a Input. + * \param SecondPart A variable which recieves the part of \a Input after the separator. This may be + * the same variable as \a Input. If the separator is not found in \a Input, this variable is set to + * an empty string. + * + * \return TRUE if \a Separator was found in \a Input, otherwise FALSE. + */ +BOOLEAN PhSplitStringRefAtString( + _In_ PPH_STRINGREF Input, + _In_ PPH_STRINGREF Separator, + _In_ BOOLEAN IgnoreCase, + _Out_ PPH_STRINGREF FirstPart, + _Out_ PPH_STRINGREF SecondPart + ) +{ + PH_STRINGREF input; + ULONG_PTR index; + + input = *Input; // get a copy of the input because FirstPart/SecondPart may alias Input + index = PhFindStringInStringRef(Input, Separator, IgnoreCase); + + if (index == -1) + { + // The separator was not found. + + FirstPart->Buffer = Input->Buffer; + FirstPart->Length = Input->Length; + SecondPart->Buffer = NULL; + SecondPart->Length = 0; + + return FALSE; + } + + FirstPart->Buffer = input.Buffer; + FirstPart->Length = index * sizeof(WCHAR); + SecondPart->Buffer = (PWCHAR)((PCHAR)input.Buffer + index * sizeof(WCHAR) + Separator->Length); + SecondPart->Length = input.Length - index * sizeof(WCHAR) - Separator->Length; + + return TRUE; +} + +/** + * Splits a string. + * + * \param Input The input string. + * \param Separator The character set, string or range to split at. + * \param Flags A combination of flags. + * \li \c PH_SPLIT_AT_CHAR_SET \a Separator specifies a character set. \a Input will be split at a + * character which is contained in \a Separator. + * \li \c PH_SPLIT_AT_STRING \a Separator specifies a string. \a Input will be split an occurrence + * of \a Separator. + * \li \c PH_SPLIT_AT_RANGE \a Separator specifies a range. The \a Buffer field contains a character + * index cast to \c PWSTR and the \a Length field contains the length of the range, in bytes. + * \li \c PH_SPLIT_CASE_INSENSITIVE Specifies a case-insensitive search. + * \li \c PH_SPLIT_COMPLEMENT_CHAR_SET If used with \c PH_SPLIT_AT_CHAR_SET, the separator is a + * character which is not contained in \a Separator. + * \li \c PH_SPLIT_START_AT_END If used with \c PH_SPLIT_AT_CHAR_SET, the search is performed + * starting from the end of the string. + * \li \c PH_SPLIT_CHAR_SET_IS_UPPERCASE If used with \c PH_SPLIT_CASE_INSENSITIVE, specifies that + * the character set in \a Separator contains only uppercase characters. + * \param FirstPart A variable which receives the part of \a Input before the separator. This may be + * the same variable as \a Input. If the separator is not found in \a Input, this variable is set to + * \a Input. + * \param SecondPart A variable which recieves the part of \a Input after the separator. This may be + * the same variable as \a Input. If the separator is not found in \a Input, this variable is set to + * an empty string. + * \param SeparatorPart A variable which receives the part of \a Input that is the separator. If the + * separator is not found in \a Input, this variable is set to an empty string. + * + * \return TRUE if a separator was found in \a Input, otherwise FALSE. + */ +BOOLEAN PhSplitStringRefEx( + _In_ PPH_STRINGREF Input, + _In_ PPH_STRINGREF Separator, + _In_ ULONG Flags, + _Out_ PPH_STRINGREF FirstPart, + _Out_ PPH_STRINGREF SecondPart, + _Out_opt_ PPH_STRINGREF SeparatorPart + ) +{ + PH_STRINGREF input; + SIZE_T separatorIndex; + SIZE_T separatorLength; + PWCHAR charSet; + SIZE_T charSetCount; + BOOLEAN charSetTable[256]; + BOOLEAN charSetTableComplete; + SIZE_T i; + SIZE_T j; + USHORT c; + PWCHAR s; + LONG_PTR direction; + + input = *Input; // Get a copy of the input because FirstPart/SecondPart/SeparatorPart may alias Input + + if (Flags & PH_SPLIT_AT_RANGE) + { + separatorIndex = (SIZE_T)Separator->Buffer; + separatorLength = Separator->Length; + + if (separatorIndex == -1) + goto SeparatorNotFound; + + goto SeparatorFound; + } + else if (Flags & PH_SPLIT_AT_STRING) + { + if (Flags & PH_SPLIT_START_AT_END) + { + // not implemented + goto SeparatorNotFound; + } + + separatorIndex = PhFindStringInStringRef(Input, Separator, !!(Flags & PH_SPLIT_CASE_INSENSITIVE)); + + if (separatorIndex == -1) + goto SeparatorNotFound; + + separatorLength = Separator->Length; + goto SeparatorFound; + } + + // Special case for character sets with only one character. + if (!(Flags & PH_SPLIT_COMPLEMENT_CHAR_SET) && Separator->Length == sizeof(WCHAR)) + { + if (!(Flags & PH_SPLIT_START_AT_END)) + separatorIndex = PhFindCharInStringRef(Input, Separator->Buffer[0], !!(Flags & PH_SPLIT_CASE_INSENSITIVE)); + else + separatorIndex = PhFindLastCharInStringRef(Input, Separator->Buffer[0], !!(Flags & PH_SPLIT_CASE_INSENSITIVE)); + + if (separatorIndex == -1) + goto SeparatorNotFound; + + separatorLength = sizeof(WCHAR); + goto SeparatorFound; + } + + if (input.Length == 0) + goto SeparatorNotFound; + + // Build the character set lookup table. + + charSet = Separator->Buffer; + charSetCount = Separator->Length / sizeof(WCHAR); + memset(charSetTable, 0, sizeof(charSetTable)); + charSetTableComplete = TRUE; + + for (i = 0; i < charSetCount; i++) + { + c = charSet[i]; + + if (Flags & PH_SPLIT_CASE_INSENSITIVE) + c = RtlUpcaseUnicodeChar(c); + + charSetTable[c & 0xff] = TRUE; + + if (c >= 256) + charSetTableComplete = FALSE; + } + + // Perform the search. + + i = input.Length / sizeof(WCHAR); + separatorLength = sizeof(WCHAR); + + if (!(Flags & PH_SPLIT_START_AT_END)) + { + s = input.Buffer; + direction = 1; + } + else + { + s = (PWCHAR)((PCHAR)input.Buffer + input.Length - sizeof(WCHAR)); + direction = -1; + } + + do + { + c = *s; + + if (Flags & PH_SPLIT_CASE_INSENSITIVE) + c = RtlUpcaseUnicodeChar(c); + + if (c < 256 && charSetTableComplete) + { + if (!(Flags & PH_SPLIT_COMPLEMENT_CHAR_SET)) + { + if (charSetTable[c]) + goto CharFound; + } + else + { + if (!charSetTable[c]) + goto CharFound; + } + } + else + { + if (!(Flags & PH_SPLIT_COMPLEMENT_CHAR_SET)) + { + if (charSetTable[c & 0xff]) + { + if (!(Flags & PH_SPLIT_CASE_INSENSITIVE) || (Flags & PH_SPLIT_CHAR_SET_IS_UPPERCASE)) + { + for (j = 0; j < charSetCount; j++) + { + if (charSet[j] == c) + goto CharFound; + } + } + else + { + for (j = 0; j < charSetCount; j++) + { + if (RtlUpcaseUnicodeChar(charSet[j]) == c) + goto CharFound; + } + } + } + } + else + { + if (charSetTable[c & 0xff]) + { + if (!(Flags & PH_SPLIT_CASE_INSENSITIVE) || (Flags & PH_SPLIT_CHAR_SET_IS_UPPERCASE)) + { + for (j = 0; j < charSetCount; j++) + { + if (charSet[j] == c) + break; + } + } + else + { + for (j = 0; j < charSetCount; j++) + { + if (RtlUpcaseUnicodeChar(charSet[j]) == c) + break; + } + } + + if (j == charSetCount) + goto CharFound; + } + else + { + goto CharFound; + } + } + } + + s += direction; + } while (--i != 0); + + goto SeparatorNotFound; + +CharFound: + separatorIndex = s - input.Buffer; + +SeparatorFound: + FirstPart->Buffer = input.Buffer; + FirstPart->Length = separatorIndex * sizeof(WCHAR); + SecondPart->Buffer = (PWCHAR)((PCHAR)input.Buffer + separatorIndex * sizeof(WCHAR) + separatorLength); + SecondPart->Length = input.Length - separatorIndex * sizeof(WCHAR) - separatorLength; + + if (SeparatorPart) + { + SeparatorPart->Buffer = input.Buffer + separatorIndex; + SeparatorPart->Length = separatorLength; + } + + return TRUE; + +SeparatorNotFound: + FirstPart->Buffer = input.Buffer; + FirstPart->Length = input.Length; + SecondPart->Buffer = NULL; + SecondPart->Length = 0; + + if (SeparatorPart) + { + SeparatorPart->Buffer = NULL; + SeparatorPart->Length = 0; + } + + return FALSE; +} + +VOID PhTrimStringRef( + _Inout_ PPH_STRINGREF String, + _In_ PPH_STRINGREF CharSet, + _In_ ULONG Flags + ) +{ + PWCHAR charSet; + SIZE_T charSetCount; + BOOLEAN charSetTable[256]; + BOOLEAN charSetTableComplete; + SIZE_T i; + SIZE_T j; + USHORT c; + SIZE_T trimCount; + SIZE_T count; + PWCHAR s; + + if (String->Length == 0 || CharSet->Length == 0) + return; + + if (CharSet->Length == sizeof(WCHAR)) + { + c = CharSet->Buffer[0]; + + if (!(Flags & PH_TRIM_END_ONLY)) + { + trimCount = 0; + count = String->Length / sizeof(WCHAR); + s = String->Buffer; + + while (count-- != 0) + { + if (*s++ != c) + break; + + trimCount++; + } + + PhSkipStringRef(String, trimCount * sizeof(WCHAR)); + } + + if (!(Flags & PH_TRIM_START_ONLY)) + { + trimCount = 0; + count = String->Length / sizeof(WCHAR); + s = (PWCHAR)((PCHAR)String->Buffer + String->Length - sizeof(WCHAR)); + + while (count-- != 0) + { + if (*s-- != c) + break; + + trimCount++; + } + + String->Length -= trimCount * sizeof(WCHAR); + } + + return; + } + + // Build the character set lookup table. + + charSet = CharSet->Buffer; + charSetCount = CharSet->Length / sizeof(WCHAR); + memset(charSetTable, 0, sizeof(charSetTable)); + charSetTableComplete = TRUE; + + for (i = 0; i < charSetCount; i++) + { + c = charSet[i]; + charSetTable[c & 0xff] = TRUE; + + if (c >= 256) + charSetTableComplete = FALSE; + } + + // Trim the string. + + if (!(Flags & PH_TRIM_END_ONLY)) + { + trimCount = 0; + count = String->Length / sizeof(WCHAR); + s = String->Buffer; + + while (count-- != 0) + { + c = *s++; + + if (!charSetTable[c & 0xff]) + break; + + if (!charSetTableComplete) + { + for (j = 0; j < charSetCount; j++) + { + if (charSet[j] == c) + goto CharFound; + } + + break; + } + +CharFound: + trimCount++; + } + + PhSkipStringRef(String, trimCount * sizeof(WCHAR)); + } + + if (!(Flags & PH_TRIM_START_ONLY)) + { + trimCount = 0; + count = String->Length / sizeof(WCHAR); + s = (PWCHAR)((PCHAR)String->Buffer + String->Length - sizeof(WCHAR)); + + while (count-- != 0) + { + c = *s--; + + if (!charSetTable[c & 0xff]) + break; + + if (!charSetTableComplete) + { + for (j = 0; j < charSetCount; j++) + { + if (charSet[j] == c) + goto CharFound2; + } + + break; + } + +CharFound2: + trimCount++; + } + + String->Length -= trimCount * sizeof(WCHAR); + } +} + +/** + * Creates a string object from an existing null-terminated string. + * + * \param Buffer A null-terminated Unicode string. + */ +PPH_STRING PhCreateString( + _In_ PWSTR Buffer + ) +{ + return PhCreateStringEx(Buffer, wcslen(Buffer) * sizeof(WCHAR)); +} + +/** + * Creates a string object using a specified length. + * + * \param Buffer A null-terminated Unicode string. + * \param Length The length, in bytes, of the string. + */ +PPH_STRING PhCreateStringEx( + _In_opt_ PWCHAR Buffer, + _In_ SIZE_T Length + ) +{ + PPH_STRING string; + + string = PhCreateObject( + FIELD_OFFSET(PH_STRING, Data) + Length + sizeof(WCHAR), // Null terminator + PhStringType + ); + + assert(!(Length & 1)); + string->Length = Length; + string->Buffer = string->Data; + *(PWCHAR)((PCHAR)string->Buffer + Length) = 0; + + if (Buffer) + { + memcpy(string->Buffer, Buffer, Length); + } + + return string; +} + +/** + * Obtains a reference to a zero-length string. + */ +PPH_STRING PhReferenceEmptyString( + VOID + ) +{ + PPH_STRING string; + PPH_STRING newString; + + string = PhSharedEmptyString; + + if (!string) + { + newString = PhCreateStringEx(NULL, 0); + + string = _InterlockedCompareExchangePointer( + &PhSharedEmptyString, + newString, + NULL + ); + + if (!string) + { + string = newString; // success + } + else + { + PhDereferenceObject(newString); + } + } + + return PhReferenceObject(string); +} + +/** + * Concatenates multiple strings. + * + * \param Count The number of strings to concatenate. + */ +PPH_STRING PhConcatStrings( + _In_ ULONG Count, + ... + ) +{ + va_list argptr; + + va_start(argptr, Count); + + return PhConcatStrings_V(Count, argptr); +} + +/** + * Concatenates multiple strings. + * + * \param Count The number of strings to concatenate. + * \param ArgPtr A pointer to an array of strings. + */ +PPH_STRING PhConcatStrings_V( + _In_ ULONG Count, + _In_ va_list ArgPtr + ) +{ + va_list argptr; + ULONG i; + SIZE_T totalLength = 0; + SIZE_T stringLength; + SIZE_T cachedLengths[PH_CONCAT_STRINGS_LENGTH_CACHE_SIZE]; + PWSTR arg; + PPH_STRING string; + + // Compute the total length, in bytes, of the strings. + + argptr = ArgPtr; + + for (i = 0; i < Count; i++) + { + arg = va_arg(argptr, PWSTR); + stringLength = PhCountStringZ(arg) * sizeof(WCHAR); + totalLength += stringLength; + + if (i < PH_CONCAT_STRINGS_LENGTH_CACHE_SIZE) + cachedLengths[i] = stringLength; + } + + // Create the string. + + string = PhCreateStringEx(NULL, totalLength); + totalLength = 0; + + // Append the strings one by one. + + argptr = ArgPtr; + + for (i = 0; i < Count; i++) + { + arg = va_arg(argptr, PWSTR); + + if (i < PH_CONCAT_STRINGS_LENGTH_CACHE_SIZE) + stringLength = cachedLengths[i]; + else + stringLength = PhCountStringZ(arg) * sizeof(WCHAR); + + memcpy( + (PCHAR)string->Buffer + totalLength, + arg, + stringLength + ); + totalLength += stringLength; + } + + return string; +} + +/** + * Concatenates two strings. + * + * \param String1 The first string. + * \param String2 The second string. + */ +PPH_STRING PhConcatStrings2( + _In_ PWSTR String1, + _In_ PWSTR String2 + ) +{ + PPH_STRING string; + SIZE_T length1; + SIZE_T length2; + + length1 = PhCountStringZ(String1) * sizeof(WCHAR); + length2 = PhCountStringZ(String2) * sizeof(WCHAR); + string = PhCreateStringEx(NULL, length1 + length2); + memcpy( + string->Buffer, + String1, + length1 + ); + memcpy( + (PCHAR)string->Buffer + length1, + String2, + length2 + ); + + return string; +} + +/** + * Concatenates two strings. + * + * \param String1 The first string. + * \param String2 The second string. + */ +PPH_STRING PhConcatStringRef2( + _In_ PPH_STRINGREF String1, + _In_ PPH_STRINGREF String2 + ) +{ + PPH_STRING string; + + assert(!(String1->Length & 1)); + assert(!(String2->Length & 1)); + + string = PhCreateStringEx(NULL, String1->Length + String2->Length); + memcpy(string->Buffer, String1->Buffer, String1->Length); + memcpy((PCHAR)string->Buffer + String1->Length, String2->Buffer, String2->Length); + + return string; +} + +/** + * Concatenates three strings. + * + * \param String1 The first string. + * \param String2 The second string. + * \param String3 The third string. + */ +PPH_STRING PhConcatStringRef3( + _In_ PPH_STRINGREF String1, + _In_ PPH_STRINGREF String2, + _In_ PPH_STRINGREF String3 + ) +{ + PPH_STRING string; + PCHAR buffer; + + assert(!(String1->Length & 1)); + assert(!(String2->Length & 1)); + assert(!(String3->Length & 1)); + + string = PhCreateStringEx(NULL, String1->Length + String2->Length + String3->Length); + + buffer = (PCHAR)string->Buffer; + memcpy(buffer, String1->Buffer, String1->Length); + + buffer += String1->Length; + memcpy(buffer, String2->Buffer, String2->Length); + + buffer += String2->Length; + memcpy(buffer, String3->Buffer, String3->Length); + + return string; +} + +/** + * Creates a string using format specifiers. + * + * \param Format The format-control string. + */ +PPH_STRING PhFormatString( + _In_ _Printf_format_string_ PWSTR Format, + ... + ) +{ + va_list argptr; + + va_start(argptr, Format); + + return PhFormatString_V(Format, argptr); +} + +/** + * Creates a string using format specifiers. + * + * \param Format The format-control string. + * \param ArgPtr A pointer to the list of arguments. + */ +PPH_STRING PhFormatString_V( + _In_ _Printf_format_string_ PWSTR Format, + _In_ va_list ArgPtr + ) +{ + PPH_STRING string; + int length; + + length = _vscwprintf(Format, ArgPtr); + + if (length == -1) + return NULL; + + string = PhCreateStringEx(NULL, length * sizeof(WCHAR)); + _vsnwprintf(string->Buffer, length, Format, ArgPtr); + + return string; +} + +/** + * Creates a bytes object from an existing null-terminated string of bytes. + * + * \param Buffer A null-terminated byte string. + */ +PPH_BYTES PhCreateBytes( + _In_ PSTR Buffer + ) +{ + return PhCreateBytesEx(Buffer, strlen(Buffer) * sizeof(CHAR)); +} + +/** + * Creates a bytes object. + * + * \param Buffer An array of bytes. + * \param Length The length of \a Buffer, in bytes. + */ +PPH_BYTES PhCreateBytesEx( + _In_opt_ PCHAR Buffer, + _In_ SIZE_T Length + ) +{ + PPH_BYTES bytes; + + bytes = PhCreateObject( + FIELD_OFFSET(PH_BYTES, Data) + Length + sizeof(CHAR), // Null terminator for compatibility + PhBytesType + ); + + bytes->Length = Length; + bytes->Buffer = bytes->Data; + bytes->Buffer[Length] = 0; + + if (Buffer) + { + memcpy(bytes->Buffer, Buffer, Length); + } + + return bytes; +} + +BOOLEAN PhWriteUnicodeDecoder( + _Inout_ PPH_UNICODE_DECODER Decoder, + _In_ ULONG CodeUnit + ) +{ + switch (Decoder->Encoding) + { + case PH_UNICODE_UTF8: + if (Decoder->InputCount >= 4) + return FALSE; + Decoder->u.Utf8.Input[Decoder->InputCount] = (UCHAR)CodeUnit; + Decoder->InputCount++; + return TRUE; + case PH_UNICODE_UTF16: + if (Decoder->InputCount >= 2) + return FALSE; + Decoder->u.Utf16.Input[Decoder->InputCount] = (USHORT)CodeUnit; + Decoder->InputCount++; + return TRUE; + case PH_UNICODE_UTF32: + if (Decoder->InputCount >= 1) + return FALSE; + Decoder->u.Utf32.Input = CodeUnit; + Decoder->InputCount = 1; + return TRUE; + default: + PhRaiseStatus(STATUS_UNSUCCESSFUL); + } +} + +BOOLEAN PhpReadUnicodeDecoder( + _Inout_ PPH_UNICODE_DECODER Decoder, + _Out_ PULONG CodeUnit + ) +{ + switch (Decoder->Encoding) + { + case PH_UNICODE_UTF8: + if (Decoder->InputCount == 0) + return FALSE; + *CodeUnit = Decoder->u.Utf8.Input[0]; + Decoder->u.Utf8.Input[0] = Decoder->u.Utf8.Input[1]; + Decoder->u.Utf8.Input[1] = Decoder->u.Utf8.Input[2]; + Decoder->u.Utf8.Input[2] = Decoder->u.Utf8.Input[3]; + Decoder->InputCount--; + return TRUE; + case PH_UNICODE_UTF16: + if (Decoder->InputCount == 0) + return FALSE; + *CodeUnit = Decoder->u.Utf16.Input[0]; + Decoder->u.Utf16.Input[0] = Decoder->u.Utf16.Input[1]; + Decoder->InputCount--; + return TRUE; + case PH_UNICODE_UTF32: + if (Decoder->InputCount == 0) + return FALSE; + *CodeUnit = Decoder->u.Utf32.Input; + Decoder->InputCount--; + return TRUE; + default: + PhRaiseStatus(STATUS_UNSUCCESSFUL); + } +} + +VOID PhpUnreadUnicodeDecoder( + _Inout_ PPH_UNICODE_DECODER Decoder, + _In_ ULONG CodeUnit + ) +{ + switch (Decoder->Encoding) + { + case PH_UNICODE_UTF8: + if (Decoder->InputCount >= 4) + PhRaiseStatus(STATUS_UNSUCCESSFUL); + Decoder->u.Utf8.Input[3] = Decoder->u.Utf8.Input[2]; + Decoder->u.Utf8.Input[2] = Decoder->u.Utf8.Input[1]; + Decoder->u.Utf8.Input[1] = Decoder->u.Utf8.Input[0]; + Decoder->u.Utf8.Input[0] = (UCHAR)CodeUnit; + Decoder->InputCount++; + break; + case PH_UNICODE_UTF16: + if (Decoder->InputCount >= 2) + PhRaiseStatus(STATUS_UNSUCCESSFUL); + Decoder->u.Utf16.Input[1] = Decoder->u.Utf16.Input[0]; + Decoder->u.Utf16.Input[0] = (USHORT)CodeUnit; + Decoder->InputCount++; + break; + case PH_UNICODE_UTF32: + if (Decoder->InputCount >= 1) + PhRaiseStatus(STATUS_UNSUCCESSFUL); + Decoder->u.Utf32.Input = CodeUnit; + Decoder->InputCount = 1; + break; + default: + PhRaiseStatus(STATUS_UNSUCCESSFUL); + } +} + +BOOLEAN PhpDecodeUtf8Error( + _Inout_ PPH_UNICODE_DECODER Decoder, + _Out_ PULONG CodePoint, + _In_ ULONG Which + ) +{ + if (Which >= 4) + PhpUnreadUnicodeDecoder(Decoder, Decoder->u.Utf8.CodeUnit4); + if (Which >= 3) + PhpUnreadUnicodeDecoder(Decoder, Decoder->u.Utf8.CodeUnit3); + if (Which >= 2) + PhpUnreadUnicodeDecoder(Decoder, Decoder->u.Utf8.CodeUnit2); + + *CodePoint = (ULONG)Decoder->u.Utf8.CodeUnit1 + 0xdc00; + Decoder->State = 0; + + return TRUE; +} + +BOOLEAN PhDecodeUnicodeDecoder( + _Inout_ PPH_UNICODE_DECODER Decoder, + _Out_ PULONG CodePoint + ) +{ + ULONG codeUnit; + + while (TRUE) + { + switch (Decoder->Encoding) + { + case PH_UNICODE_UTF8: + if (!PhpReadUnicodeDecoder(Decoder, &codeUnit)) + return FALSE; + + switch (Decoder->State) + { + case 0: + Decoder->u.Utf8.CodeUnit1 = (UCHAR)codeUnit; + + if (codeUnit < 0x80) + { + *CodePoint = codeUnit; + return TRUE; + } + else if (codeUnit < 0xc2) + { + return PhpDecodeUtf8Error(Decoder, CodePoint, 1); + } + else if (codeUnit < 0xe0) + { + Decoder->State = 1; // 2 byte sequence + continue; + } + else if (codeUnit < 0xf0) + { + Decoder->State = 2; // 3 byte sequence + continue; + } + else if (codeUnit < 0xf5) + { + Decoder->State = 3; // 4 byte sequence + continue; + } + else + { + return PhpDecodeUtf8Error(Decoder, CodePoint, 1); + } + + break; + case 1: // 2 byte sequence + Decoder->u.Utf8.CodeUnit2 = (UCHAR)codeUnit; + + if ((codeUnit & 0xc0) == 0x80) + { + *CodePoint = ((ULONG)Decoder->u.Utf8.CodeUnit1 << 6) + codeUnit - 0x3080; + Decoder->State = 0; + return TRUE; + } + else + { + return PhpDecodeUtf8Error(Decoder, CodePoint, 2); + } + + break; + case 2: // 3 byte sequence (1) + Decoder->u.Utf8.CodeUnit2 = (UCHAR)codeUnit; + + if (((codeUnit & 0xc0) == 0x80) && + (Decoder->u.Utf8.CodeUnit1 != 0xe0 || codeUnit >= 0xa0)) + { + Decoder->State = 4; // 3 byte sequence (2) + continue; + } + else + { + return PhpDecodeUtf8Error(Decoder, CodePoint, 2); + } + + break; + case 3: // 4 byte sequence (1) + Decoder->u.Utf8.CodeUnit2 = (UCHAR)codeUnit; + + if (((codeUnit & 0xc0) == 0x80) && + (Decoder->u.Utf8.CodeUnit1 != 0xf0 || codeUnit >= 0x90) && + (Decoder->u.Utf8.CodeUnit1 != 0xf4 || codeUnit < 0x90)) + { + Decoder->State = 5; // 4 byte sequence (2) + continue; + } + else + { + return PhpDecodeUtf8Error(Decoder, CodePoint, 2); + } + + break; + case 4: // 3 byte sequence (2) + Decoder->u.Utf8.CodeUnit3 = (UCHAR)codeUnit; + + if ((codeUnit & 0xc0) == 0x80) + { + *CodePoint = + ((ULONG)Decoder->u.Utf8.CodeUnit1 << 12) + + ((ULONG)Decoder->u.Utf8.CodeUnit2 << 6) + + codeUnit - 0xe2080; + Decoder->State = 0; + return TRUE; + } + else + { + return PhpDecodeUtf8Error(Decoder, CodePoint, 3); + } + + break; + case 5: // 4 byte sequence (2) + Decoder->u.Utf8.CodeUnit3 = (UCHAR)codeUnit; + + if ((codeUnit & 0xc0) == 0x80) + { + Decoder->State = 6; // 4 byte sequence (3) + continue; + } + else + { + return PhpDecodeUtf8Error(Decoder, CodePoint, 3); + } + + break; + case 6: // 4 byte sequence (3) + Decoder->u.Utf8.CodeUnit4 = (UCHAR)codeUnit; + + if ((codeUnit & 0xc0) == 0x80) + { + *CodePoint = + ((ULONG)Decoder->u.Utf8.CodeUnit1 << 18) + + ((ULONG)Decoder->u.Utf8.CodeUnit2 << 12) + + ((ULONG)Decoder->u.Utf8.CodeUnit3 << 6) + + codeUnit - 0x3c82080; + Decoder->State = 0; + return TRUE; + } + else + { + return PhpDecodeUtf8Error(Decoder, CodePoint, 4); + } + + break; + } + + return FALSE; + case PH_UNICODE_UTF16: + if (!PhpReadUnicodeDecoder(Decoder, &codeUnit)) + return FALSE; + + switch (Decoder->State) + { + case 0: + if (PH_UNICODE_UTF16_IS_HIGH_SURROGATE(codeUnit)) + { + Decoder->u.Utf16.CodeUnit = (USHORT)codeUnit; + Decoder->State = 1; + continue; + } + else + { + *CodePoint = codeUnit; + return TRUE; + } + break; + case 1: + if (PH_UNICODE_UTF16_IS_LOW_SURROGATE(codeUnit)) + { + *CodePoint = PH_UNICODE_UTF16_TO_CODE_POINT(Decoder->u.Utf16.CodeUnit, codeUnit); + Decoder->State = 0; + return TRUE; + } + else + { + *CodePoint = Decoder->u.Utf16.CodeUnit; + PhpUnreadUnicodeDecoder(Decoder, codeUnit); + Decoder->State = 0; + return TRUE; + } + break; + } + + return FALSE; + case PH_UNICODE_UTF32: + if (PhpReadUnicodeDecoder(Decoder, CodePoint)) + return TRUE; + return FALSE; + default: + return FALSE; + } + } +} + +BOOLEAN PhEncodeUnicode( + _In_ UCHAR Encoding, + _In_ ULONG CodePoint, + _Out_opt_ PVOID CodeUnits, + _Out_ PULONG NumberOfCodeUnits + ) +{ + switch (Encoding) + { + case PH_UNICODE_UTF8: + { + PUCHAR codeUnits = CodeUnits; + + if (CodePoint < 0x80) + { + *NumberOfCodeUnits = 1; + + if (codeUnits) + codeUnits[0] = (UCHAR)CodePoint; + } + else if (CodePoint <= 0x7ff) + { + *NumberOfCodeUnits = 2; + + if (codeUnits) + { + codeUnits[0] = (UCHAR)(CodePoint >> 6) + 0xc0; + codeUnits[1] = (UCHAR)(CodePoint & 0x3f) + 0x80; + } + } + else if (CodePoint <= 0xffff) + { + *NumberOfCodeUnits = 3; + + if (codeUnits) + { + codeUnits[0] = (UCHAR)(CodePoint >> 12) + 0xe0; + codeUnits[1] = (UCHAR)((CodePoint >> 6) & 0x3f) + 0x80; + codeUnits[2] = (UCHAR)(CodePoint & 0x3f) + 0x80; + } + } + else if (CodePoint <= PH_UNICODE_MAX_CODE_POINT) + { + *NumberOfCodeUnits = 4; + + if (codeUnits) + { + codeUnits[0] = (UCHAR)(CodePoint >> 18) + 0xf0; + codeUnits[1] = (UCHAR)((CodePoint >> 12) & 0x3f) + 0x80; + codeUnits[2] = (UCHAR)((CodePoint >> 6) & 0x3f) + 0x80; + codeUnits[3] = (UCHAR)(CodePoint & 0x3f) + 0x80; + } + } + else + { + return FALSE; + } + } + return TRUE; + case PH_UNICODE_UTF16: + { + PUSHORT codeUnits = CodeUnits; + + if (CodePoint < 0x10000) + { + *NumberOfCodeUnits = 1; + + if (codeUnits) + codeUnits[0] = (USHORT)CodePoint; + } + else if (CodePoint <= PH_UNICODE_MAX_CODE_POINT) + { + *NumberOfCodeUnits = 2; + + if (codeUnits) + { + codeUnits[0] = PH_UNICODE_UTF16_TO_HIGH_SURROGATE(CodePoint); + codeUnits[1] = PH_UNICODE_UTF16_TO_LOW_SURROGATE(CodePoint); + } + } + else + { + return FALSE; + } + } + return TRUE; + case PH_UNICODE_UTF32: + *NumberOfCodeUnits = 1; + if (CodeUnits) + *(PULONG)CodeUnits = CodePoint; + return TRUE; + default: + return FALSE; + } +} + +/** + * Converts an ASCII string to a UTF-16 string by zero-extending each byte. + * + * \param Input The original ASCII string. + * \param InputLength The length of \a Input. + * \param Output A buffer which will contain the converted string. + */ +VOID PhZeroExtendToUtf16Buffer( + _In_reads_bytes_(InputLength) PCH Input, + _In_ SIZE_T InputLength, + _Out_writes_bytes_(InputLength * sizeof(WCHAR)) PWCH Output + ) +{ + SIZE_T inputLength; + + inputLength = InputLength & -4; + + if (inputLength) + { + do + { + Output[0] = C_1uTo2(Input[0]); + Output[1] = C_1uTo2(Input[1]); + Output[2] = C_1uTo2(Input[2]); + Output[3] = C_1uTo2(Input[3]); + Input += 4; + Output += 4; + inputLength -= 4; + } while (inputLength != 0); + } + + switch (InputLength & 3) + { + case 3: + *Output++ = C_1uTo2(*Input++); + case 2: + *Output++ = C_1uTo2(*Input++); + case 1: + *Output++ = C_1uTo2(*Input++); + } +} + +PPH_STRING PhZeroExtendToUtf16Ex( + _In_reads_bytes_(InputLength) PCH Input, + _In_ SIZE_T InputLength + ) +{ + PPH_STRING string; + + string = PhCreateStringEx(NULL, InputLength * sizeof(WCHAR)); + PhZeroExtendToUtf16Buffer(Input, InputLength, string->Buffer); + + return string; +} + +PPH_BYTES PhConvertUtf16ToAsciiEx( + _In_ PWCH Buffer, + _In_ SIZE_T Length, + _In_opt_ CHAR Replacement + ) +{ + PPH_BYTES bytes; + PH_UNICODE_DECODER decoder; + PWCH in; + SIZE_T inRemaining; + PCH out; + SIZE_T outLength; + ULONG codePoint; + + bytes = PhCreateBytesEx(NULL, Length / sizeof(WCHAR)); + PhInitializeUnicodeDecoder(&decoder, PH_UNICODE_UTF16); + in = Buffer; + inRemaining = Length / sizeof(WCHAR); + out = bytes->Buffer; + outLength = 0; + + while (inRemaining != 0) + { + PhWriteUnicodeDecoder(&decoder, (USHORT)*in); + in++; + inRemaining--; + + while (PhDecodeUnicodeDecoder(&decoder, &codePoint)) + { + if (codePoint < 0x80) + { + *out++ = (CHAR)codePoint; + outLength++; + } + else if (Replacement) + { + *out++ = Replacement; + outLength++; + } + } + } + + bytes->Length = outLength; + bytes->Buffer[outLength] = 0; + + return bytes; +} + +/** + * Creates a string object from an existing null-terminated multi-byte string. + * + * \param Buffer A null-terminated multi-byte string. + */ +PPH_STRING PhConvertMultiByteToUtf16( + _In_ PSTR Buffer + ) +{ + return PhConvertMultiByteToUtf16Ex( + Buffer, + strlen(Buffer) + ); +} + +/** + * Creates a string object from an existing null-terminated multi-byte string. + * + * \param Buffer A null-terminated multi-byte string. + * \param Length The number of bytes to use. + */ +PPH_STRING PhConvertMultiByteToUtf16Ex( + _In_ PCHAR Buffer, + _In_ SIZE_T Length + ) +{ + NTSTATUS status; + PPH_STRING string; + ULONG unicodeBytes; + + status = RtlMultiByteToUnicodeSize( + &unicodeBytes, + Buffer, + (ULONG)Length + ); + + if (!NT_SUCCESS(status)) + return NULL; + + string = PhCreateStringEx(NULL, unicodeBytes); + status = RtlMultiByteToUnicodeN( + string->Buffer, + (ULONG)string->Length, + NULL, + Buffer, + (ULONG)Length + ); + + if (!NT_SUCCESS(status)) + { + PhDereferenceObject(string); + return NULL; + } + + return string; +} + +/** + * Creates a multi-byte string from an existing null-terminated UTF-16 string. + * + * \param Buffer A null-terminated UTF-16 string. + */ +PPH_BYTES PhConvertUtf16ToMultiByte( + _In_ PWSTR Buffer + ) +{ + return PhConvertUtf16ToMultiByteEx( + Buffer, + PhCountStringZ(Buffer) * sizeof(WCHAR) + ); +} + +/** + * Creates a multi-byte string from an existing null-terminated UTF-16 string. + * + * \param Buffer A null-terminated UTF-16 string. + * \param Length The number of bytes to use. + */ +PPH_BYTES PhConvertUtf16ToMultiByteEx( + _In_ PWCHAR Buffer, + _In_ SIZE_T Length + ) +{ + NTSTATUS status; + PPH_BYTES bytes; + ULONG multiByteLength; + + status = RtlUnicodeToMultiByteSize( + &multiByteLength, + Buffer, + (ULONG)Length + ); + + if (!NT_SUCCESS(status)) + return NULL; + + bytes = PhCreateBytesEx(NULL, multiByteLength); + status = RtlUnicodeToMultiByteN( + bytes->Buffer, + (ULONG)bytes->Length, + NULL, + Buffer, + (ULONG)Length + ); + + if (!NT_SUCCESS(status)) + { + PhDereferenceObject(bytes); + return NULL; + } + + return bytes; +} + +BOOLEAN PhConvertUtf8ToUtf16Size( + _Out_ PSIZE_T BytesInUtf16String, + _In_reads_bytes_(BytesInUtf8String) PCH Utf8String, + _In_ SIZE_T BytesInUtf8String + ) +{ + BOOLEAN result; + PH_UNICODE_DECODER decoder; + PCH in; + SIZE_T inRemaining; + SIZE_T bytesInUtf16String; + ULONG codePoint; + ULONG numberOfCodeUnits; + + result = TRUE; + PhInitializeUnicodeDecoder(&decoder, PH_UNICODE_UTF8); + in = Utf8String; + inRemaining = BytesInUtf8String; + bytesInUtf16String = 0; + + while (inRemaining != 0) + { + PhWriteUnicodeDecoder(&decoder, (UCHAR)*in); + in++; + inRemaining--; + + while (PhDecodeUnicodeDecoder(&decoder, &codePoint)) + { + if (PhEncodeUnicode(PH_UNICODE_UTF16, codePoint, NULL, &numberOfCodeUnits)) + bytesInUtf16String += numberOfCodeUnits * sizeof(WCHAR); + else + result = FALSE; + } + } + + *BytesInUtf16String = bytesInUtf16String; + + return result; +} + +BOOLEAN PhConvertUtf8ToUtf16Buffer( + _Out_writes_bytes_to_(MaxBytesInUtf16String, *BytesInUtf16String) PWCH Utf16String, + _In_ SIZE_T MaxBytesInUtf16String, + _Out_opt_ PSIZE_T BytesInUtf16String, + _In_reads_bytes_(BytesInUtf8String) PCH Utf8String, + _In_ SIZE_T BytesInUtf8String + ) +{ + BOOLEAN result; + PH_UNICODE_DECODER decoder; + PCH in; + SIZE_T inRemaining; + PWCH out; + SIZE_T outRemaining; + SIZE_T bytesInUtf16String; + ULONG codePoint; + USHORT codeUnits[2]; + ULONG numberOfCodeUnits; + + result = TRUE; + PhInitializeUnicodeDecoder(&decoder, PH_UNICODE_UTF8); + in = Utf8String; + inRemaining = BytesInUtf8String; + out = Utf16String; + outRemaining = MaxBytesInUtf16String / sizeof(WCHAR); + bytesInUtf16String = 0; + + while (inRemaining != 0) + { + PhWriteUnicodeDecoder(&decoder, (UCHAR)*in); + in++; + inRemaining--; + + while (PhDecodeUnicodeDecoder(&decoder, &codePoint)) + { + if (PhEncodeUnicode(PH_UNICODE_UTF16, codePoint, codeUnits, &numberOfCodeUnits)) + { + bytesInUtf16String += numberOfCodeUnits * sizeof(WCHAR); + + if (outRemaining >= numberOfCodeUnits) + { + *out++ = codeUnits[0]; + + if (numberOfCodeUnits >= 2) + *out++ = codeUnits[1]; + + outRemaining -= numberOfCodeUnits; + } + else + { + result = FALSE; + } + } + else + { + result = FALSE; + } + } + } + + if (BytesInUtf16String) + *BytesInUtf16String = bytesInUtf16String; + + return result; +} + +PPH_STRING PhConvertUtf8ToUtf16( + _In_ PSTR Buffer + ) +{ + return PhConvertUtf8ToUtf16Ex( + Buffer, + strlen(Buffer) + ); +} + +PPH_STRING PhConvertUtf8ToUtf16Ex( + _In_ PCHAR Buffer, + _In_ SIZE_T Length + ) +{ + PPH_STRING string; + SIZE_T utf16Bytes; + + if (!PhConvertUtf8ToUtf16Size( + &utf16Bytes, + Buffer, + Length + )) + { + return NULL; + } + + string = PhCreateStringEx(NULL, utf16Bytes); + + if (!PhConvertUtf8ToUtf16Buffer( + string->Buffer, + string->Length, + NULL, + Buffer, + Length + )) + { + PhDereferenceObject(string); + return NULL; + } + + return string; +} + +BOOLEAN PhConvertUtf16ToUtf8Size( + _Out_ PSIZE_T BytesInUtf8String, + _In_reads_bytes_(BytesInUtf16String) PWCH Utf16String, + _In_ SIZE_T BytesInUtf16String + ) +{ + BOOLEAN result; + PH_UNICODE_DECODER decoder; + PWCH in; + SIZE_T inRemaining; + SIZE_T bytesInUtf8String; + ULONG codePoint; + ULONG numberOfCodeUnits; + + result = TRUE; + PhInitializeUnicodeDecoder(&decoder, PH_UNICODE_UTF16); + in = Utf16String; + inRemaining = BytesInUtf16String / sizeof(WCHAR); + bytesInUtf8String = 0; + + while (inRemaining != 0) + { + PhWriteUnicodeDecoder(&decoder, (USHORT)*in); + in++; + inRemaining--; + + while (PhDecodeUnicodeDecoder(&decoder, &codePoint)) + { + if (PhEncodeUnicode(PH_UNICODE_UTF8, codePoint, NULL, &numberOfCodeUnits)) + bytesInUtf8String += numberOfCodeUnits; + else + result = FALSE; + } + } + + *BytesInUtf8String = bytesInUtf8String; + + return result; +} + +BOOLEAN PhConvertUtf16ToUtf8Buffer( + _Out_writes_bytes_to_(MaxBytesInUtf8String, *BytesInUtf8String) PCH Utf8String, + _In_ SIZE_T MaxBytesInUtf8String, + _Out_opt_ PSIZE_T BytesInUtf8String, + _In_reads_bytes_(BytesInUtf16String) PWCH Utf16String, + _In_ SIZE_T BytesInUtf16String + ) +{ + BOOLEAN result; + PH_UNICODE_DECODER decoder; + PWCH in; + SIZE_T inRemaining; + PCH out; + SIZE_T outRemaining; + SIZE_T bytesInUtf8String; + ULONG codePoint; + UCHAR codeUnits[4]; + ULONG numberOfCodeUnits; + + result = TRUE; + PhInitializeUnicodeDecoder(&decoder, PH_UNICODE_UTF16); + in = Utf16String; + inRemaining = BytesInUtf16String / sizeof(WCHAR); + out = Utf8String; + outRemaining = MaxBytesInUtf8String; + bytesInUtf8String = 0; + + while (inRemaining != 0) + { + PhWriteUnicodeDecoder(&decoder, (USHORT)*in); + in++; + inRemaining--; + + while (PhDecodeUnicodeDecoder(&decoder, &codePoint)) + { + if (PhEncodeUnicode(PH_UNICODE_UTF8, codePoint, codeUnits, &numberOfCodeUnits)) + { + bytesInUtf8String += numberOfCodeUnits; + + if (outRemaining >= numberOfCodeUnits) + { + *out++ = codeUnits[0]; + + if (numberOfCodeUnits >= 2) + *out++ = codeUnits[1]; + if (numberOfCodeUnits >= 3) + *out++ = codeUnits[2]; + if (numberOfCodeUnits >= 4) + *out++ = codeUnits[3]; + + outRemaining -= numberOfCodeUnits; + } + else + { + result = FALSE; + } + } + else + { + result = FALSE; + } + } + } + + if (BytesInUtf8String) + *BytesInUtf8String = bytesInUtf8String; + + return result; +} + +PPH_BYTES PhConvertUtf16ToUtf8( + _In_ PWSTR Buffer + ) +{ + return PhConvertUtf16ToUtf8Ex( + Buffer, + PhCountStringZ(Buffer) * sizeof(WCHAR) + ); +} + +PPH_BYTES PhConvertUtf16ToUtf8Ex( + _In_ PWCHAR Buffer, + _In_ SIZE_T Length + ) +{ + PPH_BYTES bytes; + SIZE_T utf8Bytes; + + if (!PhConvertUtf16ToUtf8Size( + &utf8Bytes, + Buffer, + Length + )) + { + return NULL; + } + + bytes = PhCreateBytesEx(NULL, utf8Bytes); + + if (!PhConvertUtf16ToUtf8Buffer( + bytes->Buffer, + bytes->Length, + NULL, + Buffer, + Length + )) + { + PhDereferenceObject(bytes); + return NULL; + } + + return bytes; +} + +/** + * Initializes a string builder object. + * + * \param StringBuilder A string builder object. + * \param InitialCapacity The number of bytes to allocate initially. + */ +VOID PhInitializeStringBuilder( + _Out_ PPH_STRING_BUILDER StringBuilder, + _In_ SIZE_T InitialCapacity + ) +{ + // Make sure the initial capacity is even, as required for all string objects. + if (InitialCapacity & 1) + InitialCapacity++; + + StringBuilder->AllocatedLength = InitialCapacity; + + // Allocate a PH_STRING for the string builder. + // We will dereference it and allocate a new one when we need to resize the string. + + StringBuilder->String = PhCreateStringEx(NULL, StringBuilder->AllocatedLength); + + // We will keep modifying the Length field of the string so that: + // 1. We know how much of the string is used, and + // 2. The user can simply get a reference to the string and use it as-is. + + StringBuilder->String->Length = 0; + + // Write the null terminator. + StringBuilder->String->Buffer[0] = 0; + + PHLIB_INC_STATISTIC(BaseStringBuildersCreated); +} + +/** + * Frees resources used by a string builder object. + * + * \param StringBuilder A string builder object. + */ +VOID PhDeleteStringBuilder( + _Inout_ PPH_STRING_BUILDER StringBuilder + ) +{ + PhDereferenceObject(StringBuilder->String); +} + +/** + * Obtains a reference to the string constructed by a string builder object and frees resources used + * by the object. + * + * \param StringBuilder A string builder object. + * + * \return A pointer to a string. You must free the string using PhDereferenceObject() when you no + * longer need it. + */ +PPH_STRING PhFinalStringBuilderString( + _Inout_ PPH_STRING_BUILDER StringBuilder + ) +{ + return StringBuilder->String; +} + +VOID PhpResizeStringBuilder( + _In_ PPH_STRING_BUILDER StringBuilder, + _In_ SIZE_T NewCapacity + ) +{ + PPH_STRING newString; + + // Double the string size. If that still isn't enough room, just use the new length. + + StringBuilder->AllocatedLength *= 2; + + if (StringBuilder->AllocatedLength < NewCapacity) + StringBuilder->AllocatedLength = NewCapacity; + + // Allocate a new string. + newString = PhCreateStringEx(NULL, StringBuilder->AllocatedLength); + + // Copy the old string to the new string. + memcpy( + newString->Buffer, + StringBuilder->String->Buffer, + StringBuilder->String->Length + sizeof(WCHAR) // Include null terminator + ); + + // Copy the old string length. + newString->Length = StringBuilder->String->Length; + + // Dereference the old string and replace it with the new string. + PhMoveReference(&StringBuilder->String, newString); + + PHLIB_INC_STATISTIC(BaseStringBuildersResized); +} + +FORCEINLINE VOID PhpWriteNullTerminatorStringBuilder( + _In_ PPH_STRING_BUILDER StringBuilder + ) +{ + assert(!(StringBuilder->String->Length & 1)); + *(PWCHAR)((PCHAR)StringBuilder->String->Buffer + StringBuilder->String->Length) = 0; +} + +/** + * Appends a string to the end of a string builder string. + * + * \param StringBuilder A string builder object. + * \param String The string to append. + */ +VOID PhAppendStringBuilder( + _Inout_ PPH_STRING_BUILDER StringBuilder, + _In_ PPH_STRINGREF String + ) +{ + PhAppendStringBuilderEx( + StringBuilder, + String->Buffer, + String->Length + ); +} + +/** + * Appends a string to the end of a string builder string. + * + * \param StringBuilder A string builder object. + * \param String The string to append. + */ +VOID PhAppendStringBuilder2( + _Inout_ PPH_STRING_BUILDER StringBuilder, + _In_ PWSTR String + ) +{ + PhAppendStringBuilderEx( + StringBuilder, + String, + PhCountStringZ(String) * sizeof(WCHAR) + ); +} + +/** + * Appends a string to the end of a string builder string. + * + * \param StringBuilder A string builder object. + * \param String The string to append. Specify NULL to simply reserve \a Length bytes. + * \param Length The number of bytes to append. + */ +VOID PhAppendStringBuilderEx( + _Inout_ PPH_STRING_BUILDER StringBuilder, + _In_opt_ PWCHAR String, + _In_ SIZE_T Length + ) +{ + if (Length == 0) + return; + + // See if we need to re-allocate the string. + if (StringBuilder->AllocatedLength < StringBuilder->String->Length + Length) + { + PhpResizeStringBuilder(StringBuilder, StringBuilder->String->Length + Length); + } + + // Copy the string, add the length, then write the null terminator. + + if (String) + { + memcpy( + (PCHAR)StringBuilder->String->Buffer + StringBuilder->String->Length, + String, + Length + ); + } + + StringBuilder->String->Length += Length; + PhpWriteNullTerminatorStringBuilder(StringBuilder); +} + +/** + * Appends a character to the end of a string builder string. + * + * \param StringBuilder A string builder object. + * \param Character The character to append. + */ +VOID PhAppendCharStringBuilder( + _Inout_ PPH_STRING_BUILDER StringBuilder, + _In_ WCHAR Character + ) +{ + if (StringBuilder->AllocatedLength < StringBuilder->String->Length + sizeof(WCHAR)) + { + PhpResizeStringBuilder(StringBuilder, StringBuilder->String->Length + sizeof(WCHAR)); + } + + *(PWCHAR)((PCHAR)StringBuilder->String->Buffer + StringBuilder->String->Length) = Character; + StringBuilder->String->Length += sizeof(WCHAR); + PhpWriteNullTerminatorStringBuilder(StringBuilder); +} + +/** + * Appends a number of characters to the end of a string builder string. + * + * \param StringBuilder A string builder object. + * \param Character The character to append. + * \param Count The number of times to append the character. + */ +VOID PhAppendCharStringBuilder2( + _Inout_ PPH_STRING_BUILDER StringBuilder, + _In_ WCHAR Character, + _In_ SIZE_T Count + ) +{ + if (Count == 0) + return; + + // See if we need to re-allocate the string. + if (StringBuilder->AllocatedLength < StringBuilder->String->Length + Count * sizeof(WCHAR)) + { + PhpResizeStringBuilder(StringBuilder, StringBuilder->String->Length + Count * sizeof(WCHAR)); + } + + wmemset( + (PWCHAR)((PCHAR)StringBuilder->String->Buffer + StringBuilder->String->Length), + Character, + Count + ); + + StringBuilder->String->Length += Count * sizeof(WCHAR); + PhpWriteNullTerminatorStringBuilder(StringBuilder); +} + +/** + * Appends a formatted string to the end of a string builder string. + * + * \param StringBuilder A string builder object. + * \param Format The format-control string. + */ +VOID PhAppendFormatStringBuilder( + _Inout_ PPH_STRING_BUILDER StringBuilder, + _In_ _Printf_format_string_ PWSTR Format, + ... + ) +{ + va_list argptr; + + va_start(argptr, Format); + PhAppendFormatStringBuilder_V(StringBuilder, Format, argptr); +} + +VOID PhAppendFormatStringBuilder_V( + _Inout_ PPH_STRING_BUILDER StringBuilder, + _In_ _Printf_format_string_ PWSTR Format, + _In_ va_list ArgPtr + ) +{ + int length; + SIZE_T lengthInBytes; + + length = _vscwprintf(Format, ArgPtr); + + if (length == -1 || length == 0) + return; + + lengthInBytes = length * sizeof(WCHAR); + + if (StringBuilder->AllocatedLength < StringBuilder->String->Length + lengthInBytes) + PhpResizeStringBuilder(StringBuilder, StringBuilder->String->Length + lengthInBytes); + + _vsnwprintf( + (PWCHAR)((PCHAR)StringBuilder->String->Buffer + StringBuilder->String->Length), + length, + Format, + ArgPtr + ); + + StringBuilder->String->Length += lengthInBytes; + PhpWriteNullTerminatorStringBuilder(StringBuilder); +} + +/** + * Inserts a string into a string builder string. + * + * \param StringBuilder A string builder object. + * \param Index The index, in characters, at which to insert the string. + * \param String The string to insert. + */ +VOID PhInsertStringBuilder( + _Inout_ PPH_STRING_BUILDER StringBuilder, + _In_ SIZE_T Index, + _In_ PPH_STRINGREF String + ) +{ + PhInsertStringBuilderEx( + StringBuilder, + Index, + String->Buffer, + String->Length + ); +} + +/** + * Inserts a string into a string builder string. + * + * \param StringBuilder A string builder object. + * \param Index The index, in characters, at which to insert the string. + * \param String The string to insert. + */ +VOID PhInsertStringBuilder2( + _Inout_ PPH_STRING_BUILDER StringBuilder, + _In_ SIZE_T Index, + _In_ PWSTR String + ) +{ + PhInsertStringBuilderEx( + StringBuilder, + Index, + String, + PhCountStringZ(String) * sizeof(WCHAR) + ); +} + +/** + * Inserts a string into a string builder string. + * + * \param StringBuilder A string builder object. + * \param Index The index, in characters, at which to insert the string. + * \param String The string to insert. Specify NULL to simply reserve \a Length bytes at \a Index. + * \param Length The number of bytes to insert. + */ +VOID PhInsertStringBuilderEx( + _Inout_ PPH_STRING_BUILDER StringBuilder, + _In_ SIZE_T Index, + _In_opt_ PWCHAR String, + _In_ SIZE_T Length + ) +{ + if (Length == 0) + return; + + // See if we need to re-allocate the string. + if (StringBuilder->AllocatedLength < StringBuilder->String->Length + Length) + { + PhpResizeStringBuilder(StringBuilder, StringBuilder->String->Length + Length); + } + + if (Index * sizeof(WCHAR) < StringBuilder->String->Length) + { + // Create some space for the string. + memmove( + &StringBuilder->String->Buffer[Index + Length / sizeof(WCHAR)], + &StringBuilder->String->Buffer[Index], + StringBuilder->String->Length - Index * sizeof(WCHAR) + ); + } + + if (String) + { + // Copy the new string. + memcpy( + &StringBuilder->String->Buffer[Index], + String, + Length + ); + } + + StringBuilder->String->Length += Length; + PhpWriteNullTerminatorStringBuilder(StringBuilder); +} + +/** + * Removes characters from a string builder string. + * + * \param StringBuilder A string builder object. + * \param StartIndex The index, in characters, at which to begin removing characters. + * \param Count The number of characters to remove. + */ +VOID PhRemoveStringBuilder( + _Inout_ PPH_STRING_BUILDER StringBuilder, + _In_ SIZE_T StartIndex, + _In_ SIZE_T Count + ) +{ + // Overwrite the removed part with the part + // behind it. + + memmove( + &StringBuilder->String->Buffer[StartIndex], + &StringBuilder->String->Buffer[StartIndex + Count], + StringBuilder->String->Length - (Count + StartIndex) * sizeof(WCHAR) + ); + StringBuilder->String->Length -= Count * sizeof(WCHAR); + PhpWriteNullTerminatorStringBuilder(StringBuilder); +} + +/** + * Initializes a byte string builder object. + * + * \param BytesBuilder A byte string builder object. + * \param InitialCapacity The number of bytes to allocate initially. + */ +VOID PhInitializeBytesBuilder( + _Out_ PPH_BYTES_BUILDER BytesBuilder, + _In_ SIZE_T InitialCapacity + ) +{ + BytesBuilder->AllocatedLength = InitialCapacity; + BytesBuilder->Bytes = PhCreateBytesEx(NULL, BytesBuilder->AllocatedLength); + BytesBuilder->Bytes->Length = 0; + BytesBuilder->Bytes->Buffer[0] = 0; +} + +/** + * Frees resources used by a byte string builder object. + * + * \param BytesBuilder A byte string builder object. + */ +VOID PhDeleteBytesBuilder( + _Inout_ PPH_BYTES_BUILDER BytesBuilder + ) +{ + PhDereferenceObject(BytesBuilder->Bytes); +} + +/** + * Obtains a reference to the byte string constructed by a byte string builder object and frees + * resources used by the object. + * + * \param BytesBuilder A byte string builder object. + * + * \return A pointer to a byte string. You must free the byte string using PhDereferenceObject() + * when you no longer need it. + */ +PPH_BYTES PhFinalBytesBuilderBytes( + _Inout_ PPH_BYTES_BUILDER BytesBuilder + ) +{ + return BytesBuilder->Bytes; +} + +VOID PhpResizeBytesBuilder( + _In_ PPH_BYTES_BUILDER BytesBuilder, + _In_ SIZE_T NewCapacity + ) +{ + PPH_BYTES newBytes; + + // Double the byte string size. If that still isn't enough room, just use the new length. + + BytesBuilder->AllocatedLength *= 2; + + if (BytesBuilder->AllocatedLength < NewCapacity) + BytesBuilder->AllocatedLength = NewCapacity; + + // Allocate a new byte string. + newBytes = PhCreateBytesEx(NULL, BytesBuilder->AllocatedLength); + + // Copy the old byte string to the new byte string. + memcpy( + newBytes->Buffer, + BytesBuilder->Bytes->Buffer, + BytesBuilder->Bytes->Length + sizeof(CHAR) // Include null terminator + ); + + // Copy the old byte string length. + newBytes->Length = BytesBuilder->Bytes->Length; + + // Dereference the old byte string and replace it with the new byte string. + PhMoveReference(&BytesBuilder->Bytes, newBytes); +} + +FORCEINLINE VOID PhpWriteNullTerminatorBytesBuilder( + _In_ PPH_BYTES_BUILDER BytesBuilder + ) +{ + BytesBuilder->Bytes->Buffer[BytesBuilder->Bytes->Length] = 0; +} + +/** + * Appends a byte string to the end of a byte string builder string. + * + * \param BytesBuilder A byte string builder object. + * \param Bytes The byte string to append. + */ +VOID PhAppendBytesBuilder( + _Inout_ PPH_BYTES_BUILDER BytesBuilder, + _In_ PPH_BYTESREF Bytes + ) +{ + PhAppendBytesBuilderEx( + BytesBuilder, + Bytes->Buffer, + Bytes->Length, + 0, + NULL + ); +} + +/** + * Appends a byte string to the end of a byte string builder string. + * + * \param BytesBuilder A byte string builder object. + * \param Bytes The byte string to append. + */ +VOID PhAppendBytesBuilder2( + _Inout_ PPH_BYTES_BUILDER BytesBuilder, + _In_ PCHAR Bytes + ) +{ + PhAppendBytesBuilderEx( + BytesBuilder, + Bytes, + strlen(Bytes), + 0, + NULL + ); +} + +/** + * Appends a byte string to the end of a byte string builder string. + * + * \param BytesBuilder A byte string builder object. + * \param Buffer The byte string to append. Specify NULL to simply reserve \a Length bytes. + * \param Length The number of bytes to append. + * \param Alignment The required alignment. This should not be greater than 8. + * \param Offset A variable which receives the byte offset of the appended or reserved bytes in the + * byte string builder string. + * + * \return A pointer to the appended or reserved bytes. + */ +PVOID PhAppendBytesBuilderEx( + _Inout_ PPH_BYTES_BUILDER BytesBuilder, + _In_opt_ PVOID Buffer, + _In_ SIZE_T Length, + _In_opt_ SIZE_T Alignment, + _Out_opt_ PSIZE_T Offset + ) +{ + SIZE_T currentLength; + + currentLength = BytesBuilder->Bytes->Length; + + if (Length == 0) + goto Done; + + if (Alignment) + currentLength = ALIGN_UP_BY(currentLength, Alignment); + + // See if we need to re-allocate the byte string. + if (BytesBuilder->AllocatedLength < currentLength + Length) + PhpResizeBytesBuilder(BytesBuilder, currentLength + Length); + + // Copy the byte string, add the length, then write the null terminator. + + if (Buffer) + memcpy(BytesBuilder->Bytes->Buffer + currentLength, Buffer, Length); + + BytesBuilder->Bytes->Length = currentLength + Length; + PhpWriteNullTerminatorBytesBuilder(BytesBuilder); + +Done: + if (Offset) + *Offset = currentLength; + + return BytesBuilder->Bytes->Buffer + currentLength; +} + +/** + * Creates an array object. + * + * \param Array An array object. + * \param ItemSize The size of each item, in bytes. + * \param InitialCapacity The number of elements to allocate storage for, initially. + */ +VOID PhInitializeArray( + _Out_ PPH_ARRAY Array, + _In_ SIZE_T ItemSize, + _In_ SIZE_T InitialCapacity + ) +{ + // Initial capacity of 0 is not allowed. + if (InitialCapacity == 0) + InitialCapacity = 1; + + Array->Count = 0; + Array->AllocatedCount = InitialCapacity; + Array->ItemSize = ItemSize; + Array->Items = PhAllocate(Array->AllocatedCount * ItemSize); +} + +/** + * Frees resources used by an array object. + * + * \param Array An array object. + */ +VOID PhDeleteArray( + _Inout_ PPH_ARRAY Array + ) +{ + PhFree(Array->Items); +} + +/** + * Obtains a copy of the array constructed by an array object and frees resources used by the + * object. + * + * \param Array An array object. + * + * \return The array buffer. + */ +PVOID PhFinalArrayItems( + _Inout_ PPH_ARRAY Array + ) +{ + return Array->Items; +} + +/** + * Resizes an array. + * + * \param Array An array object. + * \param NewCapacity The new required number of elements for which storage has been reserved. This + * must not be smaller than the current number of items in the array. + */ +VOID PhResizeArray( + _Inout_ PPH_ARRAY Array, + _In_ SIZE_T NewCapacity + ) +{ + if (Array->Count > NewCapacity) + PhRaiseStatus(STATUS_INVALID_PARAMETER_2); + + Array->AllocatedCount = NewCapacity; + Array->Items = PhReAllocate(Array->Items, Array->AllocatedCount * Array->ItemSize); +} + +/** + * Adds an item to an array. + * + * \param Array An array object. + * \param Item The item to add. + */ +VOID PhAddItemArray( + _Inout_ PPH_ARRAY Array, + _In_ PVOID Item + ) +{ + // See if we need to resize the list. + if (Array->Count == Array->AllocatedCount) + { + Array->AllocatedCount *= 2; + Array->Items = PhReAllocate(Array->Items, Array->AllocatedCount * Array->ItemSize); + } + + memcpy(PhItemArray(Array, Array->Count), Item, Array->ItemSize); + Array->Count++; +} + +/** + * Adds items to an array. + * + * \param Array An array object. + * \param Items An array containing the items to add. + * \param Count The number of items to add. + */ +VOID PhAddItemsArray( + _Inout_ PPH_ARRAY Array, + _In_ PVOID Items, + _In_ SIZE_T Count + ) +{ + // See if we need to resize the list. + if (Array->AllocatedCount < Array->Count + Count) + { + Array->AllocatedCount *= 2; + + if (Array->AllocatedCount < Array->Count + Count) + Array->AllocatedCount = Array->Count + Count; + + Array->Items = PhReAllocate(Array->Items, Array->AllocatedCount * Array->ItemSize); + } + + memcpy( + PhItemArray(Array, Array->Count), + Items, + Count * Array->ItemSize + ); + Array->Count += Count; +} + +/** + * Clears an array. + * + * \param Array An array object. + */ +VOID PhClearArray( + _Inout_ PPH_ARRAY Array + ) +{ + Array->Count = 0; +} + +/** + * Removes an item from an array. + * + * \param Array An array object. + * \param Index The index of the item. + */ +VOID PhRemoveItemArray( + _Inout_ PPH_ARRAY Array, + _In_ SIZE_T Index + ) +{ + PhRemoveItemsArray(Array, Index, 1); +} + +/** + * Removes items from an array. + * + * \param Array An array object. + * \param StartIndex The index at which to begin removing items. + * \param Count The number of items to remove. + */ +VOID PhRemoveItemsArray( + _Inout_ PPH_ARRAY Array, + _In_ SIZE_T StartIndex, + _In_ SIZE_T Count + ) +{ + // Shift the items after the items forward. + memmove( + PhItemArray(Array, StartIndex), + PhItemArray(Array, StartIndex + Count), + (Array->Count - StartIndex - Count) * Array->ItemSize + ); + Array->Count -= Count; +} + +/** + * Creates a list object. + * + * \param InitialCapacity The number of elements to allocate storage for, initially. + */ +PPH_LIST PhCreateList( + _In_ ULONG InitialCapacity + ) +{ + PPH_LIST list; + + list = PhCreateObject(sizeof(PH_LIST), PhListType); + + // Initial capacity of 0 is not allowed. + if (InitialCapacity == 0) + InitialCapacity = 1; + + list->Count = 0; + list->AllocatedCount = InitialCapacity; + list->Items = PhAllocate(list->AllocatedCount * sizeof(PVOID)); + + return list; +} + +VOID PhpListDeleteProcedure( + _In_ PVOID Object, + _In_ ULONG Flags + ) +{ + PPH_LIST list = (PPH_LIST)Object; + + PhFree(list->Items); +} + +/** + * Resizes a list. + * + * \param List A list object. + * \param NewCapacity The new required number of elements for which storage has been reserved. This + * must not be smaller than the current number of items in the list. + */ +VOID PhResizeList( + _Inout_ PPH_LIST List, + _In_ ULONG NewCapacity + ) +{ + if (List->Count > NewCapacity) + PhRaiseStatus(STATUS_INVALID_PARAMETER_2); + + List->AllocatedCount = NewCapacity; + List->Items = PhReAllocate(List->Items, List->AllocatedCount * sizeof(PVOID)); +} + +/** + * Adds an item to a list. + * + * \param List A list object. + * \param Item The item to add. + */ +VOID PhAddItemList( + _Inout_ PPH_LIST List, + _In_ PVOID Item + ) +{ + // See if we need to resize the list. + if (List->Count == List->AllocatedCount) + { + List->AllocatedCount *= 2; + List->Items = PhReAllocate(List->Items, List->AllocatedCount * sizeof(PVOID)); + } + + List->Items[List->Count++] = Item; +} + +/** + * Adds items to a list. + * + * \param List A list object. + * \param Items An array containing the items to add. + * \param Count The number of items to add. + */ +VOID PhAddItemsList( + _Inout_ PPH_LIST List, + _In_ PVOID *Items, + _In_ ULONG Count + ) +{ + // See if we need to resize the list. + if (List->AllocatedCount < List->Count + Count) + { + List->AllocatedCount *= 2; + + if (List->AllocatedCount < List->Count + Count) + List->AllocatedCount = List->Count + Count; + + List->Items = PhReAllocate(List->Items, List->AllocatedCount * sizeof(PVOID)); + } + + memcpy( + &List->Items[List->Count], + Items, + Count * sizeof(PVOID) + ); + List->Count += Count; +} + +/** + * Clears a list. + * + * \param List A list object. + */ +VOID PhClearList( + _Inout_ PPH_LIST List + ) +{ + List->Count = 0; +} + +_Success_(return != -1) +/** + * Locates an item in a list. + * + * \param List A list object. + * \param Item The item to search for. + * + * \return The index of the item. If the + * item was not found, -1 is returned. + */ +ULONG PhFindItemList( + _In_ PPH_LIST List, + _In_ PVOID Item + ) +{ + ULONG i; + + for (i = 0; i < List->Count; i++) + { + if (List->Items[i] == Item) + return i; + } + + return -1; +} + +/** + * Inserts an item into a list. + * + * \param List A list object. + * \param Index The index at which to insert the item. + * \param Item The item to add. + */ +VOID PhInsertItemList( + _Inout_ PPH_LIST List, + _In_ ULONG Index, + _In_ PVOID Item + ) +{ + PhInsertItemsList(List, Index, &Item, 1); +} + +/** + * Inserts items into a list. + * + * \param List A list object. + * \param Index The index at which to insert the items. + * \param Items An array containing the items to add. + * \param Count The number of items to add. + */ +VOID PhInsertItemsList( + _Inout_ PPH_LIST List, + _In_ ULONG Index, + _In_ PVOID *Items, + _In_ ULONG Count + ) +{ + // See if we need to resize the list. + if (List->AllocatedCount < List->Count + Count) + { + List->AllocatedCount *= 2; + + if (List->AllocatedCount < List->Count + Count) + List->AllocatedCount = List->Count + Count; + + List->Items = PhReAllocate(List->Items, List->AllocatedCount * sizeof(PVOID)); + } + + if (Index < List->Count) + { + // Shift the existing items backward. + memmove( + &List->Items[Index + Count], + &List->Items[Index], + (List->Count - Index) * sizeof(PVOID) + ); + } + + // Copy the new items into the list. + memcpy( + &List->Items[Index], + Items, + Count * sizeof(PVOID) + ); + + List->Count += Count; +} + +/** + * Removes an item from a list. + * + * \param List A list object. + * \param Index The index of the item. + */ +VOID PhRemoveItemList( + _Inout_ PPH_LIST List, + _In_ ULONG Index + ) +{ + PhRemoveItemsList(List, Index, 1); +} + +/** + * Removes items from a list. + * + * \param List A list object. + * \param StartIndex The index at which to begin removing items. + * \param Count The number of items to remove. + */ +VOID PhRemoveItemsList( + _Inout_ PPH_LIST List, + _In_ ULONG StartIndex, + _In_ ULONG Count + ) +{ + // Shift the items after the items forward. + memmove( + &List->Items[StartIndex], + &List->Items[StartIndex + Count], + (List->Count - StartIndex - Count) * sizeof(PVOID) + ); + List->Count -= Count; +} + +/** + * Creates a pointer list object. + * + * \param InitialCapacity The number of elements to allocate storage for initially. + */ +PPH_POINTER_LIST PhCreatePointerList( + _In_ ULONG InitialCapacity + ) +{ + PPH_POINTER_LIST pointerList; + + pointerList = PhCreateObject(sizeof(PH_POINTER_LIST), PhPointerListType); + + // Initial capacity of 0 is not allowed. + if (InitialCapacity == 0) + InitialCapacity = 1; + + pointerList->Count = 0; + pointerList->AllocatedCount = InitialCapacity; + pointerList->FreeEntry = -1; + pointerList->NextEntry = 0; + pointerList->Items = PhAllocate(pointerList->AllocatedCount * sizeof(PVOID)); + + return pointerList; +} + +VOID NTAPI PhpPointerListDeleteProcedure( + _In_ PVOID Object, + _In_ ULONG Flags + ) +{ + PPH_POINTER_LIST pointerList = (PPH_POINTER_LIST)Object; + + PhFree(pointerList->Items); +} + +/** + * Decodes an index stored in a free entry. + */ +FORCEINLINE ULONG PhpDecodePointerListIndex( + _In_ PVOID Index + ) +{ + // At least with Microsoft's compiler, shift right on a signed value preserves the sign. This is + // important because we want decode(encode(-1)) = ((-1 << 1) | 1) >> 1 = -1. + return (ULONG)((LONG_PTR)Index >> 1); +} + +/** + * Encodes an index for storage in a free entry. + */ +FORCEINLINE PVOID PhpEncodePointerListIndex( + _In_ ULONG Index + ) +{ + return (PVOID)(((ULONG_PTR)Index << 1) | 0x1); +} + +FORCEINLINE HANDLE PhpPointerListIndexToHandle( + _In_ ULONG Index + ) +{ + // Add one to allow NULL handles to indicate failure/an invalid index. + return UlongToHandle(Index + 1); +} + +FORCEINLINE ULONG PhpPointerListHandleToIndex( + _In_ HANDLE Handle + ) +{ + return HandleToUlong(Handle) - 1; +} + +/** + * Adds a pointer to a pointer list. + * + * \param PointerList A pointer list object. + * \param Pointer The pointer to add. The pointer must be at least 2 byte aligned. + * + * \return A handle to the pointer, valid until the pointer is removed from the pointer list. + */ +HANDLE PhAddItemPointerList( + _Inout_ PPH_POINTER_LIST PointerList, + _In_ PVOID Pointer + ) +{ + ULONG index; + + assert(PH_IS_LIST_POINTER_VALID(Pointer)); + + // Use a free entry if possible. + if (PointerList->FreeEntry != -1) + { + PVOID oldPointer; + + index = PointerList->FreeEntry; + oldPointer = PointerList->Items[index]; + PointerList->Items[index] = Pointer; + PointerList->FreeEntry = PhpDecodePointerListIndex(oldPointer); + } + else + { + // Use the next entry. + if (PointerList->NextEntry == PointerList->AllocatedCount) + { + PointerList->AllocatedCount *= 2; + PointerList->Items = PhReAllocate(PointerList->Items, PointerList->AllocatedCount * sizeof(PVOID)); + } + + index = PointerList->NextEntry++; + PointerList->Items[index] = Pointer; + } + + PointerList->Count++; + + return PhpPointerListIndexToHandle(index); +} + +BOOLEAN PhEnumPointerListEx( + _In_ PPH_POINTER_LIST PointerList, + _Inout_ PULONG EnumerationKey, + _Out_ PVOID *Pointer, + _Out_ PHANDLE PointerHandle + ) +{ + ULONG index; + + while ((index = *EnumerationKey) < PointerList->NextEntry) + { + PVOID pointer = PointerList->Items[index]; + + (*EnumerationKey)++; + + if (PH_IS_LIST_POINTER_VALID(pointer)) + { + *Pointer = pointer; + *PointerHandle = PhpPointerListIndexToHandle(index); + + return TRUE; + } + } + + return FALSE; +} + +/** + * Locates a pointer in a pointer list. + * + * \param PointerList A pointer list object. + * \param Pointer The pointer to find. The pointer must be at least 2 byte aligned. + * + * \return A handle to the pointer, valid until the pointer is removed from the pointer list. If the + * pointer is not contained in the pointer list, NULL is returned. + */ +HANDLE PhFindItemPointerList( + _In_ PPH_POINTER_LIST PointerList, + _In_ PVOID Pointer + ) +{ + ULONG i; + + assert(PH_IS_LIST_POINTER_VALID(Pointer)); + + for (i = 0; i < PointerList->NextEntry; i++) + { + if (PointerList->Items[i] == Pointer) + return PhpPointerListIndexToHandle(i); + } + + return NULL; +} + +/** + * Removes a pointer from a pointer list. + * + * \param PointerList A pointer list object. + * \param PointerHandle A handle to the pointer to remove. + * + * \remarks No checking is performed on the pointer handle. Make sure the handle is valid before + * calling the function. + */ +VOID PhRemoveItemPointerList( + _Inout_ PPH_POINTER_LIST PointerList, + _In_ HANDLE PointerHandle + ) +{ + ULONG index; + + assert(PointerHandle); + + index = PhpPointerListHandleToIndex(PointerHandle); + + PointerList->Items[index] = PhpEncodePointerListIndex(PointerList->FreeEntry); + PointerList->FreeEntry = index; + + PointerList->Count--; +} + +FORCEINLINE ULONG PhpValidateHash( + _In_ ULONG Hash + ) +{ + // No point in using a full hash when we're going to AND with size minus one anyway. +#if defined(PH_HASHTABLE_FULL_HASH) && !defined(PH_HASHTABLE_POWER_OF_TWO_SIZE) + if (Hash != -1) + return Hash; + else + return 0; +#else + return Hash & MAXLONG; +#endif +} + +FORCEINLINE ULONG PhpIndexFromHash( + _In_ PPH_HASHTABLE Hashtable, + _In_ ULONG Hash + ) +{ +#ifdef PH_HASHTABLE_POWER_OF_TWO_SIZE + return Hash & (Hashtable->AllocatedBuckets - 1); +#else + return Hash % Hashtable->AllocatedBuckets; +#endif +} + +FORCEINLINE ULONG PhpGetNumberOfBuckets( + _In_ ULONG Capacity + ) +{ +#ifdef PH_HASHTABLE_POWER_OF_TWO_SIZE + return PhRoundUpToPowerOfTwo(Capacity); +#else + return PhGetPrimeNumber(Capacity); +#endif +} + +/** + * Creates a hashtable object. + * + * \param EntrySize The size of each hashtable entry, in bytes. + * \param EqualFunction A comparison function that is executed to compare two hashtable entries. + * \param HashFunction A hash function that is executed to generate a hash code for a hashtable + * entry. + * \param InitialCapacity The number of entries to allocate storage for initially. + */ +PPH_HASHTABLE PhCreateHashtable( + _In_ ULONG EntrySize, + _In_ PPH_HASHTABLE_EQUAL_FUNCTION EqualFunction, + _In_ PPH_HASHTABLE_HASH_FUNCTION HashFunction, + _In_ ULONG InitialCapacity + ) +{ + PPH_HASHTABLE hashtable; + + hashtable = PhCreateObject(sizeof(PH_HASHTABLE), PhHashtableType); + + // Initial capacity of 0 is not allowed. + if (InitialCapacity == 0) + InitialCapacity = 1; + + hashtable->EntrySize = EntrySize; + hashtable->EqualFunction = EqualFunction; + hashtable->HashFunction = HashFunction; + + // Allocate the buckets. + hashtable->AllocatedBuckets = PhpGetNumberOfBuckets(InitialCapacity); + hashtable->Buckets = PhAllocate(sizeof(ULONG) * hashtable->AllocatedBuckets); + // Set all bucket values to -1. + memset(hashtable->Buckets, 0xff, sizeof(ULONG) * hashtable->AllocatedBuckets); + + // Allocate the entries. + hashtable->AllocatedEntries = hashtable->AllocatedBuckets; + hashtable->Entries = PhAllocate(PH_HASHTABLE_ENTRY_SIZE(EntrySize) * hashtable->AllocatedEntries); + + hashtable->Count = 0; + hashtable->FreeEntry = -1; + hashtable->NextEntry = 0; + + return hashtable; +} + +VOID PhpHashtableDeleteProcedure( + _In_ PVOID Object, + _In_ ULONG Flags + ) +{ + PPH_HASHTABLE hashtable = (PPH_HASHTABLE)Object; + + PhFree(hashtable->Buckets); + PhFree(hashtable->Entries); +} + +VOID PhpResizeHashtable( + _Inout_ PPH_HASHTABLE Hashtable, + _In_ ULONG NewCapacity + ) +{ + PPH_HASHTABLE_ENTRY entry; + ULONG i; + + // Re-allocate the buckets. Note that we don't need to keep the contents. + Hashtable->AllocatedBuckets = PhpGetNumberOfBuckets(NewCapacity); + PhFree(Hashtable->Buckets); + Hashtable->Buckets = PhAllocate(sizeof(ULONG) * Hashtable->AllocatedBuckets); + // Set all bucket values to -1. + memset(Hashtable->Buckets, 0xff, sizeof(ULONG) * Hashtable->AllocatedBuckets); + + // Re-allocate the entries. + Hashtable->AllocatedEntries = Hashtable->AllocatedBuckets; + Hashtable->Entries = PhReAllocate( + Hashtable->Entries, + PH_HASHTABLE_ENTRY_SIZE(Hashtable->EntrySize) * Hashtable->AllocatedEntries + ); + + // Re-distribute the entries among the buckets. + + // PH_HASHTABLE_GET_ENTRY is quite slow (it involves a multiply), so we use a pointer here. + entry = Hashtable->Entries; + + for (i = 0; i < Hashtable->NextEntry; i++) + { + if (entry->HashCode != -1) + { + ULONG index = PhpIndexFromHash(Hashtable, entry->HashCode); + + entry->Next = Hashtable->Buckets[index]; + Hashtable->Buckets[index] = i; + } + + entry = (PPH_HASHTABLE_ENTRY)((ULONG_PTR)entry + PH_HASHTABLE_ENTRY_SIZE(Hashtable->EntrySize)); + } +} + +FORCEINLINE PVOID PhpAddEntryHashtable( + _Inout_ PPH_HASHTABLE Hashtable, + _In_ PVOID Entry, + _In_ BOOLEAN CheckForDuplicate, + _Out_opt_ PBOOLEAN Added + ) +{ + ULONG hashCode; // hash code of the new entry + ULONG index; // bucket index of the new entry + ULONG freeEntry; // index of new entry in entry array + PPH_HASHTABLE_ENTRY entry; // pointer to new entry in entry array + + hashCode = PhpValidateHash(Hashtable->HashFunction(Entry)); + index = PhpIndexFromHash(Hashtable, hashCode); + + if (CheckForDuplicate) + { + ULONG i; + + for (i = Hashtable->Buckets[index]; i != -1; i = entry->Next) + { + entry = PH_HASHTABLE_GET_ENTRY(Hashtable, i); + + if (entry->HashCode == hashCode && Hashtable->EqualFunction(&entry->Body, Entry)) + { + if (Added) + *Added = FALSE; + + return &entry->Body; + } + } + } + + // Use a free entry if possible. + if (Hashtable->FreeEntry != -1) + { + freeEntry = Hashtable->FreeEntry; + entry = PH_HASHTABLE_GET_ENTRY(Hashtable, freeEntry); + Hashtable->FreeEntry = entry->Next; + } + else + { + // Use the next entry in the entry array. + + if (Hashtable->NextEntry == Hashtable->AllocatedEntries) + { + // Resize the hashtable. + PhpResizeHashtable(Hashtable, Hashtable->AllocatedBuckets * 2); + index = PhpIndexFromHash(Hashtable, hashCode); + } + + freeEntry = Hashtable->NextEntry++; + entry = PH_HASHTABLE_GET_ENTRY(Hashtable, freeEntry); + } + + // Initialize the entry. + entry->HashCode = hashCode; + entry->Next = Hashtable->Buckets[index]; + Hashtable->Buckets[index] = freeEntry; + // Copy the user-supplied data to the entry. + memcpy(&entry->Body, Entry, Hashtable->EntrySize); + + Hashtable->Count++; + + if (Added) + *Added = TRUE; + + return &entry->Body; +} + +/** + * Adds an entry to a hashtable. + * + * \param Hashtable A hashtable object. + * \param Entry The entry to add. + * + * \return A pointer to the entry as stored in the hashtable. This pointer is valid until the + * hashtable is modified. If the hashtable already contained an equal entry, NULL is returned. + * + * \remarks Entries are only guaranteed to be 8 byte aligned, even on 64-bit systems. + */ +PVOID PhAddEntryHashtable( + _Inout_ PPH_HASHTABLE Hashtable, + _In_ PVOID Entry + ) +{ + PVOID entry; + BOOLEAN added; + + entry = PhpAddEntryHashtable(Hashtable, Entry, TRUE, &added); + + if (added) + return entry; + else + return NULL; +} + +/** + * Adds an entry to a hashtable or returns an existing one. + * + * \param Hashtable A hashtable object. + * \param Entry The entry to add. + * \param Added A variable which receives TRUE if a new entry was created, and FALSE if an existing + * entry was returned. + * + * \return A pointer to the entry as stored in the hashtable. This pointer is valid until the + * hashtable is modified. If the hashtable already contained an equal entry, the existing entry is + * returned. Check the value of \a Added to determine whether the returned entry is new or existing. + * + * \remarks Entries are only guaranteed to be 8 byte aligned, even on 64-bit systems. + */ +PVOID PhAddEntryHashtableEx( + _Inout_ PPH_HASHTABLE Hashtable, + _In_ PVOID Entry, + _Out_opt_ PBOOLEAN Added + ) +{ + return PhpAddEntryHashtable(Hashtable, Entry, TRUE, Added); +} + +/** + * Clears a hashtable. + * + * \param Hashtable A hashtable object. + */ +VOID PhClearHashtable( + _Inout_ PPH_HASHTABLE Hashtable + ) +{ + if (Hashtable->Count > 0) + { + memset(Hashtable->Buckets, 0xff, sizeof(ULONG) * Hashtable->AllocatedBuckets); + Hashtable->Count = 0; + Hashtable->FreeEntry = -1; + Hashtable->NextEntry = 0; + } +} + +/** + * Enumerates the entries in a hashtable. + * + * \param Hashtable A hashtable object. + * \param Entry A variable which receives a pointer to the hashtable entry. The pointer is valid + * until the hashtable is modified. + * \param EnumerationKey A variable which is initialized to 0 before first calling this function. + * + * \return TRUE if an entry pointer was stored in \a Entry, FALSE if there are no more entries. + * + * \remarks Do not modify the hashtable while the hashtable is being enumerated (between calls to + * this function). Otherwise, the function may behave unexpectedly. You may reset the + * \a EnumerationKey variable to 0 if you wish to restart the enumeration. + */ +BOOLEAN PhEnumHashtable( + _In_ PPH_HASHTABLE Hashtable, + _Out_ PVOID *Entry, + _Inout_ PULONG EnumerationKey + ) +{ + while (*EnumerationKey < Hashtable->NextEntry) + { + PPH_HASHTABLE_ENTRY entry = PH_HASHTABLE_GET_ENTRY(Hashtable, *EnumerationKey); + + (*EnumerationKey)++; + + if (entry->HashCode != -1) + { + *Entry = &entry->Body; + return TRUE; + } + } + + return FALSE; +} + +/** + * Locates an entry in a hashtable. + * + * \param Hashtable A hashtable object. + * \param Entry An entry representing the entry to find. + * + * \return A pointer to the entry as stored in the hashtable. This pointer is valid until the + * hashtable is modified. If the entry could not be found, NULL is returned. + * + * \remarks The entry specified in \a Entry can be a partial entry that is filled in enough so that + * the comparison and hash functions can work with them. + */ +PVOID PhFindEntryHashtable( + _In_ PPH_HASHTABLE Hashtable, + _In_ PVOID Entry + ) +{ + ULONG hashCode; + ULONG index; + ULONG i; + PPH_HASHTABLE_ENTRY entry; + + hashCode = PhpValidateHash(Hashtable->HashFunction(Entry)); + index = PhpIndexFromHash(Hashtable, hashCode); + + for (i = Hashtable->Buckets[index]; i != -1; i = entry->Next) + { + entry = PH_HASHTABLE_GET_ENTRY(Hashtable, i); + + if (entry->HashCode == hashCode && Hashtable->EqualFunction(&entry->Body, Entry)) + { + return &entry->Body; + } + } + + return NULL; +} + +/** + * Removes an entry from a hashtable. + * + * \param Hashtable A hashtable object. + * \param Entry The entry to remove. + * + * \return TRUE if the entry was removed, FALSE if the entry could not be found. + * + * \remarks The entry specified in \a Entry can be an actual entry pointer returned by + * PhFindEntryHashtable, or a partial entry. + */ +BOOLEAN PhRemoveEntryHashtable( + _Inout_ PPH_HASHTABLE Hashtable, + _In_ PVOID Entry + ) +{ + ULONG hashCode; + ULONG index; + ULONG i; + ULONG previousIndex; + PPH_HASHTABLE_ENTRY entry; + + hashCode = PhpValidateHash(Hashtable->HashFunction(Entry)); + index = PhpIndexFromHash(Hashtable, hashCode); + previousIndex = -1; + + for (i = Hashtable->Buckets[index]; i != -1; i = entry->Next) + { + entry = PH_HASHTABLE_GET_ENTRY(Hashtable, i); + + if (entry->HashCode == hashCode && Hashtable->EqualFunction(&entry->Body, Entry)) + { + // Unlink the entry from the bucket. + if (previousIndex == -1) + { + Hashtable->Buckets[index] = entry->Next; + } + else + { + PH_HASHTABLE_GET_ENTRY(Hashtable, previousIndex)->Next = entry->Next; + } + + entry->HashCode = -1; // indicates the entry is not being used + entry->Next = Hashtable->FreeEntry; + Hashtable->FreeEntry = i; + + Hashtable->Count--; + + return TRUE; + } + + previousIndex = i; + } + + return FALSE; +} + +/** + * Generates a hash code for a sequence of bytes. + * + * \param Bytes A pointer to a byte array. + * \param Length The number of bytes to hash. + */ +ULONG PhHashBytes( + _In_reads_(Length) PUCHAR Bytes, + _In_ SIZE_T Length + ) +{ + ULONG hash = 0; + + if (Length == 0) + return hash; + + // FNV-1a algorithm: http://www.isthe.com/chongo/src/fnv/hash_32a.c + + do + { + hash ^= *Bytes++; + hash *= 0x01000193; + } while (--Length != 0); + + return hash; +} + +/** + * Generates a hash code for a string. + * + * \param String The string to hash. + * \param IgnoreCase TRUE for a case-insensitive hash function, otherwise FALSE. + */ +ULONG PhHashStringRef( + _In_ PPH_STRINGREF String, + _In_ BOOLEAN IgnoreCase + ) +{ + ULONG hash = 0; + SIZE_T count; + PWCHAR p; + + if (String->Length == 0) + return 0; + + count = String->Length / sizeof(WCHAR); + p = String->Buffer; + + if (!IgnoreCase) + { + return PhHashBytes((PUCHAR)String->Buffer, String->Length); + } + else + { + do + { + hash ^= (USHORT)RtlUpcaseUnicodeChar(*p++); + hash *= 0x01000193; + } while (--count != 0); + } + + return hash; +} + +BOOLEAN NTAPI PhpSimpleHashtableEqualFunction( + _In_ PVOID Entry1, + _In_ PVOID Entry2 + ) +{ + PPH_KEY_VALUE_PAIR entry1 = Entry1; + PPH_KEY_VALUE_PAIR entry2 = Entry2; + + return entry1->Key == entry2->Key; +} + +ULONG NTAPI PhpSimpleHashtableHashFunction( + _In_ PVOID Entry + ) +{ + PPH_KEY_VALUE_PAIR entry = Entry; + + return PhHashIntPtr((ULONG_PTR)entry->Key); +} + +PPH_HASHTABLE PhCreateSimpleHashtable( + _In_ ULONG InitialCapacity + ) +{ + return PhCreateHashtable( + sizeof(PH_KEY_VALUE_PAIR), + PhpSimpleHashtableEqualFunction, + PhpSimpleHashtableHashFunction, + InitialCapacity + ); +} + +PVOID PhAddItemSimpleHashtable( + _Inout_ PPH_HASHTABLE SimpleHashtable, + _In_opt_ PVOID Key, + _In_opt_ PVOID Value + ) +{ + PH_KEY_VALUE_PAIR entry; + + entry.Key = Key; + entry.Value = Value; + + if (PhAddEntryHashtable(SimpleHashtable, &entry)) + return Value; + else + return NULL; +} + +PVOID *PhFindItemSimpleHashtable( + _In_ PPH_HASHTABLE SimpleHashtable, + _In_opt_ PVOID Key + ) +{ + PH_KEY_VALUE_PAIR lookupEntry; + PPH_KEY_VALUE_PAIR entry; + + lookupEntry.Key = Key; + entry = PhFindEntryHashtable(SimpleHashtable, &lookupEntry); + + if (entry) + return &entry->Value; + else + return NULL; +} + +BOOLEAN PhRemoveItemSimpleHashtable( + _Inout_ PPH_HASHTABLE SimpleHashtable, + _In_opt_ PVOID Key + ) +{ + PH_KEY_VALUE_PAIR lookupEntry; + + lookupEntry.Key = Key; + + return PhRemoveEntryHashtable(SimpleHashtable, &lookupEntry); +} + +/** + * Initializes a free list object. + * + * \param FreeList A pointer to the free list object. + * \param Size The number of bytes in each allocation. + * \param MaximumCount The number of unused allocations to store. + */ +VOID PhInitializeFreeList( + _Out_ PPH_FREE_LIST FreeList, + _In_ SIZE_T Size, + _In_ ULONG MaximumCount + ) +{ + RtlInitializeSListHead(&FreeList->ListHead); + FreeList->Count = 0; + FreeList->MaximumCount = MaximumCount; + FreeList->Size = Size; +} + +/** + * Frees resources used by a free list object. + * + * \param FreeList A pointer to the free list object. + */ +VOID PhDeleteFreeList( + _Inout_ PPH_FREE_LIST FreeList + ) +{ + PPH_FREE_LIST_ENTRY entry; + PSLIST_ENTRY listEntry; + + listEntry = RtlInterlockedFlushSList(&FreeList->ListHead); + + while (listEntry) + { + entry = CONTAINING_RECORD(listEntry, PH_FREE_LIST_ENTRY, ListEntry); + listEntry = listEntry->Next; + PhFree(entry); + } +} + +/** + * Allocates a block of memory from a free list. + * + * \param FreeList A pointer to a free list object. + * + * \return A pointer to the allocated block of memory. The memory must be freed using + * PhFreeToFreeList(). The block is guaranteed to be aligned at MEMORY_ALLOCATION_ALIGNMENT bytes. + */ +PVOID PhAllocateFromFreeList( + _Inout_ PPH_FREE_LIST FreeList + ) +{ + PPH_FREE_LIST_ENTRY entry; + PSLIST_ENTRY listEntry; + + listEntry = RtlInterlockedPopEntrySList(&FreeList->ListHead); + + if (listEntry) + { + _InterlockedDecrement((PLONG)&FreeList->Count); + entry = CONTAINING_RECORD(listEntry, PH_FREE_LIST_ENTRY, ListEntry); + } + else + { + entry = PhAllocate(FIELD_OFFSET(PH_FREE_LIST_ENTRY, Body) + FreeList->Size); + } + + return &entry->Body; +} + +/** + * Frees a block of memory to a free list. + * + * \param FreeList A pointer to a free list object. + * \param Memory A pointer to a block of memory. + */ +VOID PhFreeToFreeList( + _Inout_ PPH_FREE_LIST FreeList, + _In_ PVOID Memory + ) +{ + PPH_FREE_LIST_ENTRY entry; + + entry = CONTAINING_RECORD(Memory, PH_FREE_LIST_ENTRY, Body); + + // We don't enforce Count <= MaximumCount (that would require locking), + // but we do check it. + if (FreeList->Count < FreeList->MaximumCount) + { + RtlInterlockedPushEntrySList(&FreeList->ListHead, &entry->ListEntry); + _InterlockedIncrement((PLONG)&FreeList->Count); + } + else + { + PhFree(entry); + } +} + +/** + * Initializes a callback object. + * + * \param Callback A pointer to a callback object. + */ +VOID PhInitializeCallback( + _Out_ PPH_CALLBACK Callback + ) +{ + InitializeListHead(&Callback->ListHead); + PhInitializeQueuedLock(&Callback->ListLock); + PhInitializeCondition(&Callback->BusyCondition); +} + +/** + * Frees resources used by a callback object. + * + * \param Callback A pointer to a callback object. + */ +VOID PhDeleteCallback( + _Inout_ PPH_CALLBACK Callback + ) +{ + // Nothing for now +} + +/** + * Registers a callback function to be notified. + * + * \param Callback A pointer to a callback object. + * \param Function The callback function. + * \param Context A user-defined value to pass to the callback function. + * \param Registration A variable which receives registration information for the callback. Do not + * modify the contents of this structure and do not free the storage for this structure until you + * have unregistered the callback. + */ +VOID PhRegisterCallback( + _Inout_ PPH_CALLBACK Callback, + _In_ PPH_CALLBACK_FUNCTION Function, + _In_opt_ PVOID Context, + _Out_ PPH_CALLBACK_REGISTRATION Registration + ) +{ + PhRegisterCallbackEx( + Callback, + Function, + Context, + 0, + Registration + ); +} + +/** + * Registers a callback function to be notified. + * + * \param Callback A pointer to a callback object. + * \param Function The callback function. + * \param Context A user-defined value to pass to the callback function. + * \param Flags A combination of flags controlling the callback. Set this parameter to 0. + * \param Registration A variable which receives registration information for the callback. Do not + * modify the contents of this structure and do not free the storage for this structure until you + * have unregistered the callback. + */ +VOID PhRegisterCallbackEx( + _Inout_ PPH_CALLBACK Callback, + _In_ PPH_CALLBACK_FUNCTION Function, + _In_opt_ PVOID Context, + _In_ USHORT Flags, + _Out_ PPH_CALLBACK_REGISTRATION Registration + ) +{ + Registration->Function = Function; + Registration->Context = Context; + Registration->Busy = 0; + Registration->Unregistering = FALSE; + Registration->Flags = Flags; + + PhAcquireQueuedLockExclusive(&Callback->ListLock); + InsertTailList(&Callback->ListHead, &Registration->ListEntry); + PhReleaseQueuedLockExclusive(&Callback->ListLock); +} + +/** + * Unregisters a callback function. + * + * \param Callback A pointer to a callback object. + * \param Registration The structure returned by PhRegisterCallback(). + * + * \remarks It is guaranteed that the callback function will not be in execution once this function + * returns. Attempting to unregister a callback function from within the same function will result + * in a deadlock. + */ +VOID PhUnregisterCallback( + _Inout_ PPH_CALLBACK Callback, + _Inout_ PPH_CALLBACK_REGISTRATION Registration + ) +{ + Registration->Unregistering = TRUE; + + PhAcquireQueuedLockExclusive(&Callback->ListLock); + + // Wait for the callback to be unbusy. + while (Registration->Busy) + PhWaitForCondition(&Callback->BusyCondition, &Callback->ListLock, NULL); + + RemoveEntryList(&Registration->ListEntry); + + PhReleaseQueuedLockExclusive(&Callback->ListLock); +} + +/** + * Notifies all registered callback functions. + * + * \param Callback A pointer to a callback object. + * \param Parameter A value to pass to all callback functions. + */ +VOID PhInvokeCallback( + _In_ PPH_CALLBACK Callback, + _In_opt_ PVOID Parameter + ) +{ + PLIST_ENTRY listEntry; + + PhAcquireQueuedLockShared(&Callback->ListLock); + + listEntry = Callback->ListHead.Flink; + + while (listEntry != &Callback->ListHead) + { + PPH_CALLBACK_REGISTRATION registration; + LONG busy; + + registration = CONTAINING_RECORD(listEntry, PH_CALLBACK_REGISTRATION, ListEntry); + + // Don't bother executing the callback function if it is being unregistered. + if (registration->Unregistering) + continue; + + _InterlockedIncrement(®istration->Busy); + + // Execute the callback function. + + PhReleaseQueuedLockShared(&Callback->ListLock); + registration->Function( + Parameter, + registration->Context + ); + PhAcquireQueuedLockShared(&Callback->ListLock); + + busy = _InterlockedDecrement(®istration->Busy); + + if (registration->Unregistering && busy == 0) + { + // Someone started unregistering while the callback function was executing, and we must + // wake them. + PhPulseAllCondition(&Callback->BusyCondition); + } + + listEntry = listEntry->Flink; + } + + PhReleaseQueuedLockShared(&Callback->ListLock); +} + +/** + * Retrieves a prime number bigger than or equal to the specified number. + */ +ULONG PhGetPrimeNumber( + _In_ ULONG Minimum + ) +{ + ULONG i, j; + + for (i = 0; i < sizeof(PhpPrimeNumbers) / sizeof(ULONG); i++) + { + if (PhpPrimeNumbers[i] >= Minimum) + return PhpPrimeNumbers[i]; + } + + for (i = Minimum | 1; i < MAXLONG; i += 2) + { + ULONG sqrtI = (ULONG)sqrt(i); + + for (j = 3; j <= sqrtI; j += 2) + { + if (i % j == 0) + { + // Not a prime. + goto NextPrime; + } + } + + // Success. + return i; +NextPrime: + NOTHING; + } + + return Minimum; +} + +/** + * Rounds up a number to the next power of two. + */ +ULONG PhRoundUpToPowerOfTwo( + _In_ ULONG Number + ) +{ + Number--; + Number |= Number >> 1; + Number |= Number >> 2; + Number |= Number >> 4; + Number |= Number >> 8; + Number |= Number >> 16; + Number++; + + return Number; +} + +/** + * Performs exponentiation. + */ +ULONG PhExponentiate( + _In_ ULONG Base, + _In_ ULONG Exponent + ) +{ + ULONG result = 1; + + while (Exponent) + { + if (Exponent & 1) + result *= Base; + + Exponent >>= 1; + Base *= Base; + } + + return result; +} + +/** + * Performs 64-bit exponentiation. + */ +ULONG64 PhExponentiate64( + _In_ ULONG64 Base, + _In_ ULONG Exponent + ) +{ + ULONG64 result = 1; + + while (Exponent) + { + if (Exponent & 1) + result *= Base; + + Exponent >>= 1; + Base *= Base; + } + + return result; +} + +/** + * Converts a sequence of hexadecimal digits into a byte array. + * + * \param String A string containing hexadecimal digits to convert. The string must have an even + * number of digits, because each pair of hexadecimal digits represents one byte. Example: + * "129a2eff5c0b". + * \param Buffer The output buffer. + * + * \return TRUE if the string was successfully converted, otherwise FALSE. + */ +BOOLEAN PhHexStringToBuffer( + _In_ PPH_STRINGREF String, + _Out_writes_bytes_(String->Length / sizeof(WCHAR) / 2) PUCHAR Buffer + ) +{ + SIZE_T i; + SIZE_T length; + + // The string must have an even length. + if ((String->Length / sizeof(WCHAR)) & 1) + return FALSE; + + length = String->Length / sizeof(WCHAR) / 2; + + for (i = 0; i < length; i++) + { + Buffer[i] = + (UCHAR)(PhCharToInteger[(UCHAR)String->Buffer[i * 2]] << 4) + + (UCHAR)PhCharToInteger[(UCHAR)String->Buffer[i * 2 + 1]]; + } + + return TRUE; +} + +/** + * Converts a byte array into a sequence of hexadecimal digits. + * + * \param Buffer The input buffer. + * \param Length The number of bytes to convert. + * + * \return A string containing a sequence of hexadecimal digits. + */ +PPH_STRING PhBufferToHexString( + _In_reads_bytes_(Length) PUCHAR Buffer, + _In_ ULONG Length + ) +{ + return PhBufferToHexStringEx(Buffer, Length, FALSE); +} + +/** + * Converts a byte array into a sequence of hexadecimal digits. + * + * \param Buffer The input buffer. + * \param Length The number of bytes to convert. + * \param UpperCase TRUE to use uppercase characters, otherwise FALSE. + * + * \return A string containing a sequence of hexadecimal digits. + */ +PPH_STRING PhBufferToHexStringEx( + _In_reads_bytes_(Length) PUCHAR Buffer, + _In_ ULONG Length, + _In_ BOOLEAN UpperCase + ) +{ + PCHAR table; + PPH_STRING string; + ULONG i; + + if (UpperCase) + table = PhIntegerToCharUpper; + else + table = PhIntegerToChar; + + string = PhCreateStringEx(NULL, Length * 2 * sizeof(WCHAR)); + + for (i = 0; i < Length; i++) + { + string->Buffer[i * 2] = table[Buffer[i] >> 4]; + string->Buffer[i * 2 + 1] = table[Buffer[i] & 0xf]; + } + + return string; +} + +/** + * Converts a string to an integer. + * + * \param String The string to process. + * \param Base The base which the string uses to represent the integer. The maximum value is 69. + * \param Integer The resulting integer. + */ +BOOLEAN PhpStringToInteger64( + _In_ PPH_STRINGREF String, + _In_ ULONG Base, + _Out_ PULONG64 Integer + ) +{ + BOOLEAN valid = TRUE; + ULONG64 result; + SIZE_T length; + SIZE_T i; + + length = String->Length / sizeof(WCHAR); + result = 0; + + for (i = 0; i < length; i++) + { + ULONG value; + + value = PhCharToInteger[(UCHAR)String->Buffer[i]]; + + if (value < Base) + result = result * Base + value; + else + valid = FALSE; + } + + *Integer = result; + + return valid; +} + +/** + * Converts a string to an integer. + * + * \param String The string to process. + * \param Base The base which the string uses to represent the integer. The maximum value is 69. If + * the parameter is 0, the base is inferred from the string. + * \param Integer The resulting integer. + * + * \remarks If \a Base is 0, the following prefixes may be used to indicate bases: + * + * \li \c 0x Base 16. + * \li \c 0o Base 8. + * \li \c 0b Base 2. + * \li \c 0t Base 3. + * \li \c 0q Base 4. + * \li \c 0w Base 12. + * \li \c 0r Base 32. + * + * If there is no recognized prefix, base 10 is used. + */ +BOOLEAN PhStringToInteger64( + _In_ PPH_STRINGREF String, + _In_opt_ ULONG Base, + _Out_opt_ PLONG64 Integer + ) +{ + BOOLEAN valid; + ULONG64 result; + PH_STRINGREF string; + BOOLEAN negative; + ULONG base; + + if (Base > 69) + return FALSE; + + string = *String; + negative = FALSE; + + if (string.Length != 0 && (string.Buffer[0] == '-' || string.Buffer[0] == '+')) + { + if (string.Buffer[0] == '-') + negative = TRUE; + + PhSkipStringRef(&string, sizeof(WCHAR)); + } + + // If the caller specified a base, don't perform any additional processing. + + if (Base) + { + base = Base; + } + else + { + base = 10; + + if (string.Length >= 2 * sizeof(WCHAR) && string.Buffer[0] == '0') + { + switch (string.Buffer[1]) + { + case 'x': + case 'X': + base = 16; + break; + case 'o': + case 'O': + base = 8; + break; + case 'b': + case 'B': + base = 2; + break; + case 't': // ternary + case 'T': + base = 3; + break; + case 'q': // quaternary + case 'Q': + base = 4; + break; + case 'w': // base 12 + case 'W': + base = 12; + break; + case 'r': // base 32 + case 'R': + base = 32; + break; + } + + if (base != 10) + PhSkipStringRef(&string, 2 * sizeof(WCHAR)); + } + } + + valid = PhpStringToInteger64(&string, base, &result); + + if (Integer) + *Integer = negative ? -(LONG64)result : result; + + return valid; +} + +BOOLEAN PhpStringToDouble( + _In_ PPH_STRINGREF String, + _In_ ULONG Base, + _Out_ DOUBLE *Double + ) +{ + BOOLEAN valid = TRUE; + BOOLEAN dotSeen = FALSE; + DOUBLE result; + DOUBLE fraction; + SIZE_T length; + SIZE_T i; + + length = String->Length / sizeof(WCHAR); + result = 0; + fraction = 1; + + for (i = 0; i < length; i++) + { + if (String->Buffer[i] == '.') + { + if (!dotSeen) + dotSeen = TRUE; + else + valid = FALSE; + } + else + { + ULONG value; + + value = PhCharToInteger[(UCHAR)String->Buffer[i]]; + + if (value < Base) + { + if (!dotSeen) + { + result = result * Base + value; + } + else + { + fraction /= Base; + result = result + value * fraction; + } + } + else + { + valid = FALSE; + } + } + } + + *Double = result; + + return valid; +} + +/** + * Converts a string to a double-precision floating point value. + * + * \param String The string to process. + * \param Base Reserved. + * \param Double The resulting double value. + */ +BOOLEAN PhStringToDouble( + _In_ PPH_STRINGREF String, + _Reserved_ ULONG Base, + _Out_opt_ DOUBLE *Double + ) +{ + BOOLEAN valid; + DOUBLE result; + PH_STRINGREF string; + BOOLEAN negative; + + string = *String; + negative = FALSE; + + if (string.Length != 0 && (string.Buffer[0] == '-' || string.Buffer[0] == '+')) + { + if (string.Buffer[0] == '-') + negative = TRUE; + + PhSkipStringRef(&string, sizeof(WCHAR)); + } + + valid = PhpStringToDouble(&string, 10, &result); + + if (Double) + *Double = negative ? -result : result; + + return valid; +} + +/** + * Converts an integer to a string. + * + * \param Integer The integer to process. + * \param Base The base which the integer is represented with. The maximum value is 69. The base + * cannot be 1. If the parameter is 0, the base used is 10. + * \param Signed TRUE if \a Integer is a signed value, otherwise FALSE. + * + * \return The resulting string, or NULL if an error occurred. + */ +PPH_STRING PhIntegerToString64( + _In_ LONG64 Integer, + _In_opt_ ULONG Base, + _In_ BOOLEAN Signed + ) +{ + PH_FORMAT format; + + if (Base == 1 || Base > 69) + return NULL; + + if (Signed) + PhInitFormatI64D(&format, Integer); + else + PhInitFormatI64U(&format, Integer); + + if (Base != 0) + { + format.Type |= FormatUseRadix; + format.Radix = (UCHAR)Base; + } + + return PhFormat(&format, 1, 0); +} + +VOID PhPrintTimeSpan( + _Out_writes_(PH_TIMESPAN_STR_LEN_1) PWSTR Destination, + _In_ ULONG64 Ticks, + _In_opt_ ULONG Mode + ) +{ + switch (Mode) + { + case PH_TIMESPAN_HMSM: + _snwprintf( + Destination, + PH_TIMESPAN_STR_LEN, + L"%02I64u:%02I64u:%02I64u.%03I64u", + PH_TICKS_PARTIAL_HOURS(Ticks), + PH_TICKS_PARTIAL_MIN(Ticks), + PH_TICKS_PARTIAL_SEC(Ticks), + PH_TICKS_PARTIAL_MS(Ticks) + ); + break; + case PH_TIMESPAN_DHMS: + _snwprintf( + Destination, + PH_TIMESPAN_STR_LEN, + L"%I64u:%02I64u:%02I64u:%02I64u", + PH_TICKS_PARTIAL_DAYS(Ticks), + PH_TICKS_PARTIAL_HOURS(Ticks), + PH_TICKS_PARTIAL_MIN(Ticks), + PH_TICKS_PARTIAL_SEC(Ticks) + ); + break; + default: + _snwprintf( + Destination, + PH_TIMESPAN_STR_LEN, + L"%02I64u:%02I64u:%02I64u", + PH_TICKS_PARTIAL_HOURS(Ticks), + PH_TICKS_PARTIAL_MIN(Ticks), + PH_TICKS_PARTIAL_SEC(Ticks) + ); + break; + } +} + +/** + * Fills a memory block with a ULONG pattern. + * + * \param Memory The memory block. The block must be 4 byte aligned. + * \param Value The ULONG pattern. + * \param Count The number of elements. + */ +VOID PhFillMemoryUlong( + _Inout_updates_(Count) _Needs_align_(4) PULONG Memory, + _In_ ULONG Value, + _In_ SIZE_T Count + ) +{ + __m128i pattern; + SIZE_T count; + + if (PhpVectorLevel < PH_VECTOR_LEVEL_SSE2) + { + if (Count != 0) + { + do + { + *Memory++ = Value; + } while (--Count != 0); + } + + return; + } + + if ((ULONG_PTR)Memory & 0xf) + { + switch ((ULONG_PTR)Memory & 0xf) + { + case 0x4: + if (Count >= 1) + { + *Memory++ = Value; + Count--; + } + __fallthrough; + case 0x8: + if (Count >= 1) + { + *Memory++ = Value; + Count--; + } + __fallthrough; + case 0xc: + if (Count >= 1) + { + *Memory++ = Value; + Count--; + } + break; + } + } + + pattern = _mm_set1_epi32(Value); + count = Count / 4; + + if (count != 0) + { + do + { + _mm_store_si128((__m128i *)Memory, pattern); + Memory += 4; + } while (--count != 0); + } + + switch (Count & 0x3) + { + case 0x3: + *Memory++ = Value; + __fallthrough; + case 0x2: + *Memory++ = Value; + __fallthrough; + case 0x1: + *Memory++ = Value; + break; + } +} + +/** + * Divides an array of numbers by a number. + * + * \param A The destination array, divided by \a B. + * \param B The number. + * \param Count The number of elements. + */ +VOID PhDivideSinglesBySingle( + _Inout_updates_(Count) PFLOAT A, + _In_ FLOAT B, + _In_ SIZE_T Count + ) +{ + PFLOAT endA; + __m128 b; + + if (PhpVectorLevel < PH_VECTOR_LEVEL_SSE2) + { + while (Count--) + *A++ /= B; + + return; + } + + if ((ULONG_PTR)A & 0xf) + { + switch ((ULONG_PTR)A & 0xf) + { + case 0x4: + if (Count >= 1) + { + *A++ /= B; + Count--; + } + __fallthrough; + case 0x8: + if (Count >= 1) + { + *A++ /= B; + Count--; + } + __fallthrough; + case 0xc: + if (Count >= 1) + { + *A++ /= B; + Count--; + } + else + { + return; // essential; A may not be aligned properly + } + break; + } + } + + endA = (PFLOAT)((ULONG_PTR)(A + Count) & ~0xf); + b = _mm_load1_ps(&B); + + while (A != endA) + { + __m128 a; + + a = _mm_load_ps(A); + a = _mm_div_ps(a, b); + _mm_store_ps(A, a); + + A += 4; + } + + switch (Count & 0x3) + { + case 0x3: + *A++ /= B; + __fallthrough; + case 0x2: + *A++ /= B; + __fallthrough; + case 0x1: + *A++ /= B; + break; + } +} diff --git a/phlib/circbuf.c b/phlib/circbuf.c index 3696c11efc4e..1f9efb8bfd37 100644 --- a/phlib/circbuf.c +++ b/phlib/circbuf.c @@ -1,22 +1,22 @@ -#include -#include - -#undef T -#define T ULONG -#include "circbuf_i.h" - -#undef T -#define T ULONG64 -#include "circbuf_i.h" - -#undef T -#define T PVOID -#include "circbuf_i.h" - -#undef T -#define T SIZE_T -#include "circbuf_i.h" - -#undef T -#define T FLOAT -#include "circbuf_i.h" +#include +#include + +#undef T +#define T ULONG +#include "circbuf_i.h" + +#undef T +#define T ULONG64 +#include "circbuf_i.h" + +#undef T +#define T PVOID +#include "circbuf_i.h" + +#undef T +#define T SIZE_T +#include "circbuf_i.h" + +#undef T +#define T FLOAT +#include "circbuf_i.h" diff --git a/phlib/circbuf_i.h b/phlib/circbuf_i.h index c5e49b09398c..fd84c142880c 100644 --- a/phlib/circbuf_i.h +++ b/phlib/circbuf_i.h @@ -1,121 +1,121 @@ -#ifdef T - -#include - -VOID T___(PhInitializeCircularBuffer, T)( - _Out_ T___(PPH_CIRCULAR_BUFFER, T) Buffer, - _In_ ULONG Size - ) -{ -#ifdef PH_CIRCULAR_BUFFER_POWER_OF_TWO_SIZE - Buffer->Size = PhRoundUpToPowerOfTwo(Size); - Buffer->SizeMinusOne = Buffer->Size - 1; -#else - Buffer->Size = Size; -#endif - - Buffer->Count = 0; - Buffer->Index = 0; - Buffer->Data = PhAllocate(sizeof(T) * Buffer->Size); -} - -VOID T___(PhDeleteCircularBuffer, T)( - _Inout_ T___(PPH_CIRCULAR_BUFFER, T) Buffer - ) -{ - PhFree(Buffer->Data); -} - -VOID T___(PhResizeCircularBuffer, T)( - _Inout_ T___(PPH_CIRCULAR_BUFFER, T) Buffer, - _In_ ULONG NewSize - ) -{ - T *newData; - ULONG tailSize; - ULONG headSize; - -#ifdef PH_CIRCULAR_BUFFER_POWER_OF_TWO_SIZE - NewSize = PhRoundUpToPowerOfTwo(NewSize); -#endif - - // If we're not actually resizing it, return. - if (NewSize == Buffer->Size) - return; - - newData = PhAllocate(sizeof(T) * NewSize); - tailSize = (ULONG)(Buffer->Size - Buffer->Index); - headSize = Buffer->Count - tailSize; - - if (NewSize > Buffer->Size) - { - // Copy the tail, then the head. - memcpy(newData, &Buffer->Data[Buffer->Index], sizeof(T) * tailSize); - memcpy(&newData[tailSize], Buffer->Data, sizeof(T) * headSize); - Buffer->Index = 0; - } - else - { - if (tailSize >= NewSize) - { - // Copy only a part of the tail. - memcpy(newData, &Buffer->Data[Buffer->Index], sizeof(T) * NewSize); - Buffer->Index = 0; - } - else - { - // Copy the tail, then only part of the head. - memcpy(newData, &Buffer->Data[Buffer->Index], sizeof(T) * tailSize); - memcpy(&newData[tailSize], Buffer->Data, sizeof(T) * (NewSize - tailSize)); - Buffer->Index = 0; - } - - // Since we're making the circular buffer smaller, limit the count. - if (Buffer->Count > NewSize) - Buffer->Count = NewSize; - } - - Buffer->Data = newData; - Buffer->Size = NewSize; -#ifdef PH_CIRCULAR_BUFFER_POWER_OF_TWO_SIZE - Buffer->SizeMinusOne = NewSize - 1; -#endif -} - -VOID T___(PhClearCircularBuffer, T)( - _Inout_ T___(PPH_CIRCULAR_BUFFER, T) Buffer - ) -{ - Buffer->Count = 0; - Buffer->Index = 0; -} - -VOID T___(PhCopyCircularBuffer, T)( - _Inout_ T___(PPH_CIRCULAR_BUFFER, T) Buffer, - _Out_writes_(Count) T *Destination, - _In_ ULONG Count - ) -{ - ULONG tailSize; - ULONG headSize; - - tailSize = (ULONG)(Buffer->Size - Buffer->Index); - headSize = Buffer->Count - tailSize; - - if (Count > Buffer->Count) - Count = Buffer->Count; - - if (tailSize >= Count) - { - // Copy only a part of the tail. - memcpy(Destination, &Buffer->Data[Buffer->Index], sizeof(T) * Count); - } - else - { - // Copy the tail, then only part of the head. - memcpy(Destination, &Buffer->Data[Buffer->Index], sizeof(T) * tailSize); - memcpy(&Destination[tailSize], Buffer->Data, sizeof(T) * (Count - tailSize)); - } -} - -#endif +#ifdef T + +#include + +VOID T___(PhInitializeCircularBuffer, T)( + _Out_ T___(PPH_CIRCULAR_BUFFER, T) Buffer, + _In_ ULONG Size + ) +{ +#ifdef PH_CIRCULAR_BUFFER_POWER_OF_TWO_SIZE + Buffer->Size = PhRoundUpToPowerOfTwo(Size); + Buffer->SizeMinusOne = Buffer->Size - 1; +#else + Buffer->Size = Size; +#endif + + Buffer->Count = 0; + Buffer->Index = 0; + Buffer->Data = PhAllocate(sizeof(T) * Buffer->Size); +} + +VOID T___(PhDeleteCircularBuffer, T)( + _Inout_ T___(PPH_CIRCULAR_BUFFER, T) Buffer + ) +{ + PhFree(Buffer->Data); +} + +VOID T___(PhResizeCircularBuffer, T)( + _Inout_ T___(PPH_CIRCULAR_BUFFER, T) Buffer, + _In_ ULONG NewSize + ) +{ + T *newData; + ULONG tailSize; + ULONG headSize; + +#ifdef PH_CIRCULAR_BUFFER_POWER_OF_TWO_SIZE + NewSize = PhRoundUpToPowerOfTwo(NewSize); +#endif + + // If we're not actually resizing it, return. + if (NewSize == Buffer->Size) + return; + + newData = PhAllocate(sizeof(T) * NewSize); + tailSize = (ULONG)(Buffer->Size - Buffer->Index); + headSize = Buffer->Count - tailSize; + + if (NewSize > Buffer->Size) + { + // Copy the tail, then the head. + memcpy(newData, &Buffer->Data[Buffer->Index], sizeof(T) * tailSize); + memcpy(&newData[tailSize], Buffer->Data, sizeof(T) * headSize); + Buffer->Index = 0; + } + else + { + if (tailSize >= NewSize) + { + // Copy only a part of the tail. + memcpy(newData, &Buffer->Data[Buffer->Index], sizeof(T) * NewSize); + Buffer->Index = 0; + } + else + { + // Copy the tail, then only part of the head. + memcpy(newData, &Buffer->Data[Buffer->Index], sizeof(T) * tailSize); + memcpy(&newData[tailSize], Buffer->Data, sizeof(T) * (NewSize - tailSize)); + Buffer->Index = 0; + } + + // Since we're making the circular buffer smaller, limit the count. + if (Buffer->Count > NewSize) + Buffer->Count = NewSize; + } + + Buffer->Data = newData; + Buffer->Size = NewSize; +#ifdef PH_CIRCULAR_BUFFER_POWER_OF_TWO_SIZE + Buffer->SizeMinusOne = NewSize - 1; +#endif +} + +VOID T___(PhClearCircularBuffer, T)( + _Inout_ T___(PPH_CIRCULAR_BUFFER, T) Buffer + ) +{ + Buffer->Count = 0; + Buffer->Index = 0; +} + +VOID T___(PhCopyCircularBuffer, T)( + _Inout_ T___(PPH_CIRCULAR_BUFFER, T) Buffer, + _Out_writes_(Count) T *Destination, + _In_ ULONG Count + ) +{ + ULONG tailSize; + ULONG headSize; + + tailSize = (ULONG)(Buffer->Size - Buffer->Index); + headSize = Buffer->Count - tailSize; + + if (Count > Buffer->Count) + Count = Buffer->Count; + + if (tailSize >= Count) + { + // Copy only a part of the tail. + memcpy(Destination, &Buffer->Data[Buffer->Index], sizeof(T) * Count); + } + else + { + // Copy the tail, then only part of the head. + memcpy(Destination, &Buffer->Data[Buffer->Index], sizeof(T) * tailSize); + memcpy(&Destination[tailSize], Buffer->Data, sizeof(T) * (Count - tailSize)); + } +} + +#endif diff --git a/phlib/colorbox.c b/phlib/colorbox.c index 4011dd41b1fe..530690e9b458 100644 --- a/phlib/colorbox.c +++ b/phlib/colorbox.c @@ -1,230 +1,230 @@ -/* - * Process Hacker - - * color picker - * - * Copyright (C) 2010 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include -#include - -#include - -#include - -typedef struct _PHP_COLORBOX_CONTEXT -{ - COLORREF SelectedColor; - BOOLEAN Hot; - BOOLEAN HasFocus; -} PHP_COLORBOX_CONTEXT, *PPHP_COLORBOX_CONTEXT; - -LRESULT CALLBACK PhpColorBoxWndProc( - _In_ HWND hwnd, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -BOOLEAN PhColorBoxInitialization( - VOID - ) -{ - WNDCLASSEX c = { sizeof(c) }; - - c.style = CS_GLOBALCLASS; - c.lpfnWndProc = PhpColorBoxWndProc; - c.cbClsExtra = 0; - c.cbWndExtra = sizeof(PVOID); - c.hInstance = PhLibImageBase; - c.hIcon = NULL; - c.hCursor = LoadCursor(NULL, IDC_ARROW); - c.hbrBackground = NULL; - c.lpszMenuName = NULL; - c.lpszClassName = PH_COLORBOX_CLASSNAME; - c.hIconSm = NULL; - - if (!RegisterClassEx(&c)) - return FALSE; - - return TRUE; -} - -VOID PhpCreateColorBoxContext( - _Out_ PPHP_COLORBOX_CONTEXT *Context - ) -{ - PPHP_COLORBOX_CONTEXT context; - - context = PhAllocate(sizeof(PHP_COLORBOX_CONTEXT)); - memset(context, 0, sizeof(PHP_COLORBOX_CONTEXT)); - *Context = context; -} - -VOID PhpFreeColorBoxContext( - _In_ _Post_invalid_ PPHP_COLORBOX_CONTEXT Context - ) -{ - PhFree(Context); -} - -VOID PhpChooseColor( - _In_ HWND hwnd, - _In_ PPHP_COLORBOX_CONTEXT Context - ) -{ - CHOOSECOLOR chooseColor = { sizeof(chooseColor) }; - COLORREF customColors[16] = { 0 }; - - chooseColor.hwndOwner = hwnd; - chooseColor.rgbResult = Context->SelectedColor; - chooseColor.lpCustColors = customColors; - chooseColor.Flags = CC_ANYCOLOR | CC_FULLOPEN | CC_RGBINIT; - - if (ChooseColor(&chooseColor)) - { - Context->SelectedColor = chooseColor.rgbResult; - InvalidateRect(hwnd, NULL, TRUE); - } -} - -LRESULT CALLBACK PhpColorBoxWndProc( - _In_ HWND hwnd, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - PPHP_COLORBOX_CONTEXT context; - - context = (PPHP_COLORBOX_CONTEXT)GetWindowLongPtr(hwnd, 0); - - if (uMsg == WM_CREATE) - { - PhpCreateColorBoxContext(&context); - SetWindowLongPtr(hwnd, 0, (LONG_PTR)context); - } - - if (!context) - return DefWindowProc(hwnd, uMsg, wParam, lParam); - - switch (uMsg) - { - case WM_CREATE: - { - // Nothing - } - break; - case WM_DESTROY: - { - SetWindowLongPtr(hwnd, 0, (LONG_PTR)NULL); - PhpFreeColorBoxContext(context); - } - break; - case WM_PAINT: - { - PAINTSTRUCT paintStruct; - RECT clientRect; - HDC hdc; - - if (hdc = BeginPaint(hwnd, &paintStruct)) - { - GetClientRect(hwnd, &clientRect); - - // Border color - SetDCPenColor(hdc, RGB(0x44, 0x44, 0x44)); - - // Fill color - if (!context->Hot && !context->HasFocus) - SetDCBrushColor(hdc, context->SelectedColor); - else - SetDCBrushColor(hdc, PhMakeColorBrighter(context->SelectedColor, 64)); - - // Draw the rectangle. - SelectObject(hdc, GetStockObject(DC_PEN)); - SelectObject(hdc, GetStockObject(DC_BRUSH)); - Rectangle(hdc, clientRect.left, clientRect.top, clientRect.right, clientRect.bottom); - - EndPaint(hwnd, &paintStruct); - } - } - return 0; - case WM_ERASEBKGND: - return 1; - case WM_MOUSEMOVE: - { - if (!context->Hot) - { - TRACKMOUSEEVENT trackMouseEvent = { sizeof(trackMouseEvent) }; - - context->Hot = TRUE; - InvalidateRect(hwnd, NULL, TRUE); - - trackMouseEvent.dwFlags = TME_LEAVE; - trackMouseEvent.hwndTrack = hwnd; - TrackMouseEvent(&trackMouseEvent); - } - } - break; - case WM_MOUSELEAVE: - { - context->Hot = FALSE; - InvalidateRect(hwnd, NULL, TRUE); - } - break; - case WM_LBUTTONDOWN: - { - PhpChooseColor(hwnd, context); - } - break; - case WM_SETFOCUS: - { - context->HasFocus = TRUE; - InvalidateRect(hwnd, NULL, TRUE); - } - return 0; - case WM_KILLFOCUS: - { - context->HasFocus = FALSE; - InvalidateRect(hwnd, NULL, TRUE); - } - return 0; - case WM_GETDLGCODE: - if (wParam == VK_RETURN) - return DLGC_WANTMESSAGE; - return 0; - case WM_KEYDOWN: - { - switch (wParam) - { - case VK_SPACE: - case VK_RETURN: - PhpChooseColor(hwnd, context); - break; - } - } - break; - case CBCM_SETCOLOR: - context->SelectedColor = (COLORREF)wParam; - return TRUE; - case CBCM_GETCOLOR: - return (LRESULT)context->SelectedColor; - } - - return DefWindowProc(hwnd, uMsg, wParam, lParam); -} +/* + * Process Hacker - + * color picker + * + * Copyright (C) 2010 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include +#include + +#include + +#include + +typedef struct _PHP_COLORBOX_CONTEXT +{ + COLORREF SelectedColor; + BOOLEAN Hot; + BOOLEAN HasFocus; +} PHP_COLORBOX_CONTEXT, *PPHP_COLORBOX_CONTEXT; + +LRESULT CALLBACK PhpColorBoxWndProc( + _In_ HWND hwnd, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +BOOLEAN PhColorBoxInitialization( + VOID + ) +{ + WNDCLASSEX c = { sizeof(c) }; + + c.style = CS_GLOBALCLASS; + c.lpfnWndProc = PhpColorBoxWndProc; + c.cbClsExtra = 0; + c.cbWndExtra = sizeof(PVOID); + c.hInstance = PhLibImageBase; + c.hIcon = NULL; + c.hCursor = LoadCursor(NULL, IDC_ARROW); + c.hbrBackground = NULL; + c.lpszMenuName = NULL; + c.lpszClassName = PH_COLORBOX_CLASSNAME; + c.hIconSm = NULL; + + if (!RegisterClassEx(&c)) + return FALSE; + + return TRUE; +} + +VOID PhpCreateColorBoxContext( + _Out_ PPHP_COLORBOX_CONTEXT *Context + ) +{ + PPHP_COLORBOX_CONTEXT context; + + context = PhAllocate(sizeof(PHP_COLORBOX_CONTEXT)); + memset(context, 0, sizeof(PHP_COLORBOX_CONTEXT)); + *Context = context; +} + +VOID PhpFreeColorBoxContext( + _In_ _Post_invalid_ PPHP_COLORBOX_CONTEXT Context + ) +{ + PhFree(Context); +} + +VOID PhpChooseColor( + _In_ HWND hwnd, + _In_ PPHP_COLORBOX_CONTEXT Context + ) +{ + CHOOSECOLOR chooseColor = { sizeof(chooseColor) }; + COLORREF customColors[16] = { 0 }; + + chooseColor.hwndOwner = hwnd; + chooseColor.rgbResult = Context->SelectedColor; + chooseColor.lpCustColors = customColors; + chooseColor.Flags = CC_ANYCOLOR | CC_FULLOPEN | CC_RGBINIT; + + if (ChooseColor(&chooseColor)) + { + Context->SelectedColor = chooseColor.rgbResult; + InvalidateRect(hwnd, NULL, TRUE); + } +} + +LRESULT CALLBACK PhpColorBoxWndProc( + _In_ HWND hwnd, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + PPHP_COLORBOX_CONTEXT context; + + context = (PPHP_COLORBOX_CONTEXT)GetWindowLongPtr(hwnd, 0); + + if (uMsg == WM_CREATE) + { + PhpCreateColorBoxContext(&context); + SetWindowLongPtr(hwnd, 0, (LONG_PTR)context); + } + + if (!context) + return DefWindowProc(hwnd, uMsg, wParam, lParam); + + switch (uMsg) + { + case WM_CREATE: + { + // Nothing + } + break; + case WM_DESTROY: + { + SetWindowLongPtr(hwnd, 0, (LONG_PTR)NULL); + PhpFreeColorBoxContext(context); + } + break; + case WM_PAINT: + { + PAINTSTRUCT paintStruct; + RECT clientRect; + HDC hdc; + + if (hdc = BeginPaint(hwnd, &paintStruct)) + { + GetClientRect(hwnd, &clientRect); + + // Border color + SetDCPenColor(hdc, RGB(0x44, 0x44, 0x44)); + + // Fill color + if (!context->Hot && !context->HasFocus) + SetDCBrushColor(hdc, context->SelectedColor); + else + SetDCBrushColor(hdc, PhMakeColorBrighter(context->SelectedColor, 64)); + + // Draw the rectangle. + SelectObject(hdc, GetStockObject(DC_PEN)); + SelectObject(hdc, GetStockObject(DC_BRUSH)); + Rectangle(hdc, clientRect.left, clientRect.top, clientRect.right, clientRect.bottom); + + EndPaint(hwnd, &paintStruct); + } + } + return 0; + case WM_ERASEBKGND: + return 1; + case WM_MOUSEMOVE: + { + if (!context->Hot) + { + TRACKMOUSEEVENT trackMouseEvent = { sizeof(trackMouseEvent) }; + + context->Hot = TRUE; + InvalidateRect(hwnd, NULL, TRUE); + + trackMouseEvent.dwFlags = TME_LEAVE; + trackMouseEvent.hwndTrack = hwnd; + TrackMouseEvent(&trackMouseEvent); + } + } + break; + case WM_MOUSELEAVE: + { + context->Hot = FALSE; + InvalidateRect(hwnd, NULL, TRUE); + } + break; + case WM_LBUTTONDOWN: + { + PhpChooseColor(hwnd, context); + } + break; + case WM_SETFOCUS: + { + context->HasFocus = TRUE; + InvalidateRect(hwnd, NULL, TRUE); + } + return 0; + case WM_KILLFOCUS: + { + context->HasFocus = FALSE; + InvalidateRect(hwnd, NULL, TRUE); + } + return 0; + case WM_GETDLGCODE: + if (wParam == VK_RETURN) + return DLGC_WANTMESSAGE; + return 0; + case WM_KEYDOWN: + { + switch (wParam) + { + case VK_SPACE: + case VK_RETURN: + PhpChooseColor(hwnd, context); + break; + } + } + break; + case CBCM_SETCOLOR: + context->SelectedColor = (COLORREF)wParam; + return TRUE; + case CBCM_GETCOLOR: + return (LRESULT)context->SelectedColor; + } + + return DefWindowProc(hwnd, uMsg, wParam, lParam); +} diff --git a/phlib/cpysave.c b/phlib/cpysave.c index 3076f9f491cc..9c250999ef65 100644 --- a/phlib/cpysave.c +++ b/phlib/cpysave.c @@ -1,574 +1,574 @@ -/* - * Process Hacker - - * copy/save code for listviews and treelists - * - * Copyright (C) 2010-2012 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include -#include - -#include -#include - -#define TAB_SIZE 8 - -VOID PhpEscapeStringForCsv( - _Inout_ PPH_STRING_BUILDER StringBuilder, - _In_ PPH_STRING String - ) -{ - SIZE_T i; - SIZE_T length; - PWCHAR runStart; - SIZE_T runLength; - - length = String->Length / sizeof(WCHAR); - runStart = NULL; - - for (i = 0; i < length; i++) - { - switch (String->Buffer[i]) - { - case '\"': - if (runStart) - { - PhAppendStringBuilderEx(StringBuilder, runStart, runLength * sizeof(WCHAR)); - runStart = NULL; - } - - PhAppendStringBuilder2(StringBuilder, L"\"\""); - - break; - default: - if (runStart) - { - runLength++; - } - else - { - runStart = &String->Buffer[i]; - runLength = 1; - } - - break; - } - } - - if (runStart) - PhAppendStringBuilderEx(StringBuilder, runStart, runLength * sizeof(WCHAR)); -} - -/** - * Allocates a text table. - * - * \param Table A variable which receives a pointer to the text table. - * \param Rows The number of rows in the table. - * \param Columns The number of columns in the table. - */ -VOID PhaCreateTextTable( - _Out_ PPH_STRING ***Table, - _In_ ULONG Rows, - _In_ ULONG Columns - ) -{ - PPH_STRING **table; - ULONG i; - - table = PH_AUTO(PhCreateAlloc(sizeof(PPH_STRING *) * Rows)); - - for (i = 0; i < Rows; i++) - { - table[i] = PH_AUTO(PhCreateAlloc(sizeof(PPH_STRING) * Columns)); - memset(table[i], 0, sizeof(PPH_STRING) * Columns); - } - - *Table = table; -} - -/** - * Formats a text table to a list of lines. - * - * \param Table A pointer to the text table. - * \param Rows The number of rows in the table. - * \param Columns The number of columns in the table. - * \param Mode The export formatting mode. - * - * \return A list of strings for each line in the output. The list object and - * string objects are not auto-dereferenced. - */ -PPH_LIST PhaFormatTextTable( - _In_ PPH_STRING **Table, - _In_ ULONG Rows, - _In_ ULONG Columns, - _In_ ULONG Mode - ) -{ - PPH_LIST lines; - // The tab count array contains the number of tabs need to fill the biggest - // row cell in each column. - PULONG tabCount; - ULONG i; - ULONG j; - - if (Mode == PH_EXPORT_MODE_TABS || Mode == PH_EXPORT_MODE_SPACES) - { - // Create the tab count array. - - tabCount = PH_AUTO(PhCreateAlloc(sizeof(ULONG) * Columns)); - memset(tabCount, 0, sizeof(ULONG) * Columns); // zero all values - - for (i = 0; i < Rows; i++) - { - for (j = 0; j < Columns; j++) - { - ULONG newCount; - - if (Table[i][j]) - newCount = (ULONG)(Table[i][j]->Length / sizeof(WCHAR) / TAB_SIZE); - else - newCount = 0; - - // Replace the existing count if this tab count is bigger. - if (tabCount[j] < newCount) - tabCount[j] = newCount; - } - } - } - - // Create the final list of lines by going through each cell and appending - // the proper tab count (if we are using tabs). This will make sure each column - // is properly aligned. - - lines = PhCreateList(Rows); - - for (i = 0; i < Rows; i++) - { - PH_STRING_BUILDER stringBuilder; - - PhInitializeStringBuilder(&stringBuilder, 100); - - switch (Mode) - { - case PH_EXPORT_MODE_TABS: - { - for (j = 0; j < Columns; j++) - { - ULONG k; - - if (Table[i][j]) - { - // Calculate the number of tabs needed. - k = (ULONG)(tabCount[j] + 1 - Table[i][j]->Length / sizeof(WCHAR) / TAB_SIZE); - - PhAppendStringBuilder(&stringBuilder, &Table[i][j]->sr); - } - else - { - k = tabCount[j] + 1; - } - - PhAppendCharStringBuilder2(&stringBuilder, '\t', k); - } - } - break; - case PH_EXPORT_MODE_SPACES: - { - for (j = 0; j < Columns; j++) - { - ULONG k; - - if (Table[i][j]) - { - // Calculate the number of spaces needed. - k = (ULONG)((tabCount[j] + 1) * TAB_SIZE - Table[i][j]->Length / sizeof(WCHAR)); - - PhAppendStringBuilder(&stringBuilder, &Table[i][j]->sr); - } - else - { - k = (tabCount[j] + 1) * TAB_SIZE; - } - - PhAppendCharStringBuilder2(&stringBuilder, ' ', k); - } - } - break; - case PH_EXPORT_MODE_CSV: - { - for (j = 0; j < Columns; j++) - { - PhAppendCharStringBuilder(&stringBuilder, '\"'); - - if (Table[i][j]) - { - PhpEscapeStringForCsv(&stringBuilder, Table[i][j]); - } - - PhAppendCharStringBuilder(&stringBuilder, '\"'); - - if (j != Columns - 1) - PhAppendCharStringBuilder(&stringBuilder, ','); - } - } - break; - } - - PhAddItemList(lines, PhFinalStringBuilderString(&stringBuilder)); - } - - return lines; -} - -VOID PhMapDisplayIndexTreeNew( - _In_ HWND TreeNewHandle, - _Out_opt_ PULONG *DisplayToId, - _Out_opt_ PWSTR **DisplayToText, - _Out_ PULONG NumberOfColumns - ) -{ - PPH_TREENEW_COLUMN fixedColumn; - ULONG numberOfColumns; - PULONG displayToId; - PWSTR *displayToText; - ULONG i; - PH_TREENEW_COLUMN column; - - fixedColumn = TreeNew_GetFixedColumn(TreeNewHandle); - numberOfColumns = TreeNew_GetVisibleColumnCount(TreeNewHandle); - - displayToId = PhAllocate(numberOfColumns * sizeof(ULONG)); - - if (fixedColumn) - { - TreeNew_GetColumnOrderArray(TreeNewHandle, numberOfColumns - 1, displayToId + 1); - displayToId[0] = fixedColumn->Id; - } - else - { - TreeNew_GetColumnOrderArray(TreeNewHandle, numberOfColumns, displayToId); - } - - if (DisplayToText) - { - displayToText = PhAllocate(numberOfColumns * sizeof(PWSTR)); - - for (i = 0; i < numberOfColumns; i++) - { - if (TreeNew_GetColumn(TreeNewHandle, displayToId[i], &column)) - { - displayToText[i] = column.Text; - } - } - - *DisplayToText = displayToText; - } - - if (DisplayToId) - *DisplayToId = displayToId; - else - PhFree(displayToId); - - *NumberOfColumns = numberOfColumns; -} - -PPH_STRING PhGetTreeNewText( - _In_ HWND TreeNewHandle, - _Reserved_ ULONG Reserved - ) -{ - PH_STRING_BUILDER stringBuilder; - PULONG displayToId; - ULONG rows; - ULONG columns; - ULONG i; - ULONG j; - - PhMapDisplayIndexTreeNew(TreeNewHandle, &displayToId, NULL, &columns); - rows = TreeNew_GetFlatNodeCount(TreeNewHandle); - - PhInitializeStringBuilder(&stringBuilder, 0x100); - - for (i = 0; i < rows; i++) - { - PH_TREENEW_GET_CELL_TEXT getCellText; - - getCellText.Node = TreeNew_GetFlatNode(TreeNewHandle, i); - assert(getCellText.Node); - - if (!getCellText.Node->Selected) - continue; - - for (j = 0; j < columns; j++) - { - getCellText.Id = displayToId[j]; - PhInitializeEmptyStringRef(&getCellText.Text); - TreeNew_GetCellText(TreeNewHandle, &getCellText); - - PhAppendStringBuilder(&stringBuilder, &getCellText.Text); - PhAppendStringBuilder2(&stringBuilder, L", "); - } - - // Remove the trailing comma and space. - if (stringBuilder.String->Length != 0) - PhRemoveEndStringBuilder(&stringBuilder, 2); - - PhAppendStringBuilder2(&stringBuilder, L"\r\n"); - } - - PhFree(displayToId); - - return PhFinalStringBuilderString(&stringBuilder); -} - -PPH_LIST PhGetGenericTreeNewLines( - _In_ HWND TreeNewHandle, - _In_ ULONG Mode - ) -{ - PH_AUTO_POOL autoPool; - PPH_LIST lines; - ULONG rows; - ULONG columns; - ULONG numberOfNodes; - PULONG displayToId; - PWSTR *displayToText; - PPH_STRING **table; - ULONG i; - ULONG j; - - PhInitializeAutoPool(&autoPool); - - numberOfNodes = TreeNew_GetFlatNodeCount(TreeNewHandle); - - rows = numberOfNodes + 1; - PhMapDisplayIndexTreeNew(TreeNewHandle, &displayToId, &displayToText, &columns); - - PhaCreateTextTable(&table, rows, columns); - - for (i = 0; i < columns; i++) - table[0][i] = PhaCreateString(displayToText[i]); - - for (i = 0; i < numberOfNodes; i++) - { - PPH_TREENEW_NODE node; - - node = TreeNew_GetFlatNode(TreeNewHandle, i); - - if (node) - { - for (j = 0; j < columns; j++) - { - PH_TREENEW_GET_CELL_TEXT getCellText; - - getCellText.Node = node; - getCellText.Id = displayToId[j]; - PhInitializeEmptyStringRef(&getCellText.Text); - TreeNew_GetCellText(TreeNewHandle, &getCellText); - - table[i + 1][j] = PhaCreateStringEx(getCellText.Text.Buffer, getCellText.Text.Length); - } - } - else - { - for (j = 0; j < columns; j++) - { - table[i + 1][j] = PH_AUTO(PhReferenceEmptyString()); - } - } - } - - PhFree(displayToText); - PhFree(displayToId); - - lines = PhaFormatTextTable(table, rows, columns, Mode); - - PhDeleteAutoPool(&autoPool); - - return lines; -} - -VOID PhaMapDisplayIndexListView( - _In_ HWND ListViewHandle, - _Out_writes_(Count) PULONG DisplayToId, - _Out_writes_opt_(Count) PPH_STRING *DisplayToText, - _In_ ULONG Count, - _Out_ PULONG NumberOfColumns - ) -{ - LVCOLUMN lvColumn; - ULONG i; - ULONG count; - WCHAR buffer[128]; - - count = 0; - lvColumn.mask = LVCF_ORDER | LVCF_TEXT; - lvColumn.pszText = buffer; - lvColumn.cchTextMax = sizeof(buffer) / sizeof(WCHAR); - - for (i = 0; i < Count; i++) - { - if (ListView_GetColumn(ListViewHandle, i, &lvColumn)) - { - ULONG displayIndex; - - displayIndex = (ULONG)lvColumn.iOrder; - assert(displayIndex < Count); - DisplayToId[displayIndex] = i; - - if (DisplayToText) - DisplayToText[displayIndex] = PhaCreateString(buffer); - - count++; - } - else - { - break; - } - } - - *NumberOfColumns = count; -} - -PPH_STRING PhaGetListViewItemText( - _In_ HWND ListViewHandle, - _In_ INT Index, - _In_ INT SubItemIndex - ) -{ - PPH_STRING buffer; - SIZE_T allocatedCount; - SIZE_T count; - LVITEM lvItem; - - // Unfortunately LVM_GETITEMTEXT doesn't want to return the actual length of the text. - // Keep doubling the buffer size until we get a return count that is strictly less than - // the amount we allocated. - - buffer = NULL; - allocatedCount = 256; - count = allocatedCount; - - while (count >= allocatedCount) - { - if (buffer) - PhDereferenceObject(buffer); - - allocatedCount *= 2; - buffer = PhCreateStringEx(NULL, allocatedCount * sizeof(WCHAR)); - buffer->Buffer[0] = 0; - - lvItem.iSubItem = SubItemIndex; - lvItem.cchTextMax = (INT)allocatedCount + 1; - lvItem.pszText = buffer->Buffer; - count = SendMessage(ListViewHandle, LVM_GETITEMTEXT, Index, (LPARAM)&lvItem); - } - - PhTrimToNullTerminatorString(buffer); - PH_AUTO(buffer); - - return buffer; -} - -PPH_STRING PhGetListViewText( - _In_ HWND ListViewHandle - ) -{ - PH_AUTO_POOL autoPool; - PH_STRING_BUILDER stringBuilder; - ULONG displayToId[100]; - ULONG rows; - ULONG columns; - ULONG i; - ULONG j; - - PhInitializeAutoPool(&autoPool); - - PhaMapDisplayIndexListView(ListViewHandle, displayToId, NULL, 100, &columns); - rows = ListView_GetItemCount(ListViewHandle); - - PhInitializeStringBuilder(&stringBuilder, 0x100); - - for (i = 0; i < rows; i++) - { - if (!(ListView_GetItemState(ListViewHandle, i, LVIS_SELECTED) & LVIS_SELECTED)) - continue; - - for (j = 0; j < columns; j++) - { - PhAppendStringBuilder(&stringBuilder, &PhaGetListViewItemText(ListViewHandle, i, j)->sr); - PhAppendStringBuilder2(&stringBuilder, L", "); - } - - // Remove the trailing comma and space. - if (stringBuilder.String->Length != 0) - PhRemoveEndStringBuilder(&stringBuilder, 2); - - PhAppendStringBuilder2(&stringBuilder, L"\r\n"); - } - - PhDeleteAutoPool(&autoPool); - - return PhFinalStringBuilderString(&stringBuilder); -} - -PPH_LIST PhGetListViewLines( - _In_ HWND ListViewHandle, - _In_ ULONG Mode - ) -{ - PH_AUTO_POOL autoPool; - PPH_LIST lines; - ULONG rows; - ULONG columns; - ULONG displayToId[100]; - PPH_STRING displayToText[100]; - PPH_STRING **table; - ULONG i; - ULONG j; - - PhInitializeAutoPool(&autoPool); - - rows = ListView_GetItemCount(ListViewHandle) + 1; // +1 for column headers - - // Create the display index/text to ID map. - PhaMapDisplayIndexListView(ListViewHandle, displayToId, displayToText, 100, &columns); - - PhaCreateTextTable(&table, rows, columns); - - // Populate the first row with the column headers. - for (i = 0; i < columns; i++) - table[0][i] = displayToText[i]; - - // Populate the other rows with text. - for (i = 1; i < rows; i++) - { - for (j = 0; j < columns; j++) - { - // Important: use this to bypass extlv's hooking. - // extlv only hooks LVM_GETITEM, not LVM_GETITEMTEXT. - table[i][j] = PhaGetListViewItemText(ListViewHandle, i - 1, j); - } - } - - lines = PhaFormatTextTable(table, rows, columns, Mode); - - PhDeleteAutoPool(&autoPool); - - return lines; -} +/* + * Process Hacker - + * copy/save code for listviews and treelists + * + * Copyright (C) 2010-2012 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include +#include + +#include +#include + +#define TAB_SIZE 8 + +VOID PhpEscapeStringForCsv( + _Inout_ PPH_STRING_BUILDER StringBuilder, + _In_ PPH_STRING String + ) +{ + SIZE_T i; + SIZE_T length; + PWCHAR runStart; + SIZE_T runLength; + + length = String->Length / sizeof(WCHAR); + runStart = NULL; + + for (i = 0; i < length; i++) + { + switch (String->Buffer[i]) + { + case '\"': + if (runStart) + { + PhAppendStringBuilderEx(StringBuilder, runStart, runLength * sizeof(WCHAR)); + runStart = NULL; + } + + PhAppendStringBuilder2(StringBuilder, L"\"\""); + + break; + default: + if (runStart) + { + runLength++; + } + else + { + runStart = &String->Buffer[i]; + runLength = 1; + } + + break; + } + } + + if (runStart) + PhAppendStringBuilderEx(StringBuilder, runStart, runLength * sizeof(WCHAR)); +} + +/** + * Allocates a text table. + * + * \param Table A variable which receives a pointer to the text table. + * \param Rows The number of rows in the table. + * \param Columns The number of columns in the table. + */ +VOID PhaCreateTextTable( + _Out_ PPH_STRING ***Table, + _In_ ULONG Rows, + _In_ ULONG Columns + ) +{ + PPH_STRING **table; + ULONG i; + + table = PH_AUTO(PhCreateAlloc(sizeof(PPH_STRING *) * Rows)); + + for (i = 0; i < Rows; i++) + { + table[i] = PH_AUTO(PhCreateAlloc(sizeof(PPH_STRING) * Columns)); + memset(table[i], 0, sizeof(PPH_STRING) * Columns); + } + + *Table = table; +} + +/** + * Formats a text table to a list of lines. + * + * \param Table A pointer to the text table. + * \param Rows The number of rows in the table. + * \param Columns The number of columns in the table. + * \param Mode The export formatting mode. + * + * \return A list of strings for each line in the output. The list object and + * string objects are not auto-dereferenced. + */ +PPH_LIST PhaFormatTextTable( + _In_ PPH_STRING **Table, + _In_ ULONG Rows, + _In_ ULONG Columns, + _In_ ULONG Mode + ) +{ + PPH_LIST lines; + // The tab count array contains the number of tabs need to fill the biggest + // row cell in each column. + PULONG tabCount; + ULONG i; + ULONG j; + + if (Mode == PH_EXPORT_MODE_TABS || Mode == PH_EXPORT_MODE_SPACES) + { + // Create the tab count array. + + tabCount = PH_AUTO(PhCreateAlloc(sizeof(ULONG) * Columns)); + memset(tabCount, 0, sizeof(ULONG) * Columns); // zero all values + + for (i = 0; i < Rows; i++) + { + for (j = 0; j < Columns; j++) + { + ULONG newCount; + + if (Table[i][j]) + newCount = (ULONG)(Table[i][j]->Length / sizeof(WCHAR) / TAB_SIZE); + else + newCount = 0; + + // Replace the existing count if this tab count is bigger. + if (tabCount[j] < newCount) + tabCount[j] = newCount; + } + } + } + + // Create the final list of lines by going through each cell and appending + // the proper tab count (if we are using tabs). This will make sure each column + // is properly aligned. + + lines = PhCreateList(Rows); + + for (i = 0; i < Rows; i++) + { + PH_STRING_BUILDER stringBuilder; + + PhInitializeStringBuilder(&stringBuilder, 100); + + switch (Mode) + { + case PH_EXPORT_MODE_TABS: + { + for (j = 0; j < Columns; j++) + { + ULONG k; + + if (Table[i][j]) + { + // Calculate the number of tabs needed. + k = (ULONG)(tabCount[j] + 1 - Table[i][j]->Length / sizeof(WCHAR) / TAB_SIZE); + + PhAppendStringBuilder(&stringBuilder, &Table[i][j]->sr); + } + else + { + k = tabCount[j] + 1; + } + + PhAppendCharStringBuilder2(&stringBuilder, '\t', k); + } + } + break; + case PH_EXPORT_MODE_SPACES: + { + for (j = 0; j < Columns; j++) + { + ULONG k; + + if (Table[i][j]) + { + // Calculate the number of spaces needed. + k = (ULONG)((tabCount[j] + 1) * TAB_SIZE - Table[i][j]->Length / sizeof(WCHAR)); + + PhAppendStringBuilder(&stringBuilder, &Table[i][j]->sr); + } + else + { + k = (tabCount[j] + 1) * TAB_SIZE; + } + + PhAppendCharStringBuilder2(&stringBuilder, ' ', k); + } + } + break; + case PH_EXPORT_MODE_CSV: + { + for (j = 0; j < Columns; j++) + { + PhAppendCharStringBuilder(&stringBuilder, '\"'); + + if (Table[i][j]) + { + PhpEscapeStringForCsv(&stringBuilder, Table[i][j]); + } + + PhAppendCharStringBuilder(&stringBuilder, '\"'); + + if (j != Columns - 1) + PhAppendCharStringBuilder(&stringBuilder, ','); + } + } + break; + } + + PhAddItemList(lines, PhFinalStringBuilderString(&stringBuilder)); + } + + return lines; +} + +VOID PhMapDisplayIndexTreeNew( + _In_ HWND TreeNewHandle, + _Out_opt_ PULONG *DisplayToId, + _Out_opt_ PWSTR **DisplayToText, + _Out_ PULONG NumberOfColumns + ) +{ + PPH_TREENEW_COLUMN fixedColumn; + ULONG numberOfColumns; + PULONG displayToId; + PWSTR *displayToText; + ULONG i; + PH_TREENEW_COLUMN column; + + fixedColumn = TreeNew_GetFixedColumn(TreeNewHandle); + numberOfColumns = TreeNew_GetVisibleColumnCount(TreeNewHandle); + + displayToId = PhAllocate(numberOfColumns * sizeof(ULONG)); + + if (fixedColumn) + { + TreeNew_GetColumnOrderArray(TreeNewHandle, numberOfColumns - 1, displayToId + 1); + displayToId[0] = fixedColumn->Id; + } + else + { + TreeNew_GetColumnOrderArray(TreeNewHandle, numberOfColumns, displayToId); + } + + if (DisplayToText) + { + displayToText = PhAllocate(numberOfColumns * sizeof(PWSTR)); + + for (i = 0; i < numberOfColumns; i++) + { + if (TreeNew_GetColumn(TreeNewHandle, displayToId[i], &column)) + { + displayToText[i] = column.Text; + } + } + + *DisplayToText = displayToText; + } + + if (DisplayToId) + *DisplayToId = displayToId; + else + PhFree(displayToId); + + *NumberOfColumns = numberOfColumns; +} + +PPH_STRING PhGetTreeNewText( + _In_ HWND TreeNewHandle, + _Reserved_ ULONG Reserved + ) +{ + PH_STRING_BUILDER stringBuilder; + PULONG displayToId; + ULONG rows; + ULONG columns; + ULONG i; + ULONG j; + + PhMapDisplayIndexTreeNew(TreeNewHandle, &displayToId, NULL, &columns); + rows = TreeNew_GetFlatNodeCount(TreeNewHandle); + + PhInitializeStringBuilder(&stringBuilder, 0x100); + + for (i = 0; i < rows; i++) + { + PH_TREENEW_GET_CELL_TEXT getCellText; + + getCellText.Node = TreeNew_GetFlatNode(TreeNewHandle, i); + assert(getCellText.Node); + + if (!getCellText.Node->Selected) + continue; + + for (j = 0; j < columns; j++) + { + getCellText.Id = displayToId[j]; + PhInitializeEmptyStringRef(&getCellText.Text); + TreeNew_GetCellText(TreeNewHandle, &getCellText); + + PhAppendStringBuilder(&stringBuilder, &getCellText.Text); + PhAppendStringBuilder2(&stringBuilder, L", "); + } + + // Remove the trailing comma and space. + if (stringBuilder.String->Length != 0) + PhRemoveEndStringBuilder(&stringBuilder, 2); + + PhAppendStringBuilder2(&stringBuilder, L"\r\n"); + } + + PhFree(displayToId); + + return PhFinalStringBuilderString(&stringBuilder); +} + +PPH_LIST PhGetGenericTreeNewLines( + _In_ HWND TreeNewHandle, + _In_ ULONG Mode + ) +{ + PH_AUTO_POOL autoPool; + PPH_LIST lines; + ULONG rows; + ULONG columns; + ULONG numberOfNodes; + PULONG displayToId; + PWSTR *displayToText; + PPH_STRING **table; + ULONG i; + ULONG j; + + PhInitializeAutoPool(&autoPool); + + numberOfNodes = TreeNew_GetFlatNodeCount(TreeNewHandle); + + rows = numberOfNodes + 1; + PhMapDisplayIndexTreeNew(TreeNewHandle, &displayToId, &displayToText, &columns); + + PhaCreateTextTable(&table, rows, columns); + + for (i = 0; i < columns; i++) + table[0][i] = PhaCreateString(displayToText[i]); + + for (i = 0; i < numberOfNodes; i++) + { + PPH_TREENEW_NODE node; + + node = TreeNew_GetFlatNode(TreeNewHandle, i); + + if (node) + { + for (j = 0; j < columns; j++) + { + PH_TREENEW_GET_CELL_TEXT getCellText; + + getCellText.Node = node; + getCellText.Id = displayToId[j]; + PhInitializeEmptyStringRef(&getCellText.Text); + TreeNew_GetCellText(TreeNewHandle, &getCellText); + + table[i + 1][j] = PhaCreateStringEx(getCellText.Text.Buffer, getCellText.Text.Length); + } + } + else + { + for (j = 0; j < columns; j++) + { + table[i + 1][j] = PH_AUTO(PhReferenceEmptyString()); + } + } + } + + PhFree(displayToText); + PhFree(displayToId); + + lines = PhaFormatTextTable(table, rows, columns, Mode); + + PhDeleteAutoPool(&autoPool); + + return lines; +} + +VOID PhaMapDisplayIndexListView( + _In_ HWND ListViewHandle, + _Out_writes_(Count) PULONG DisplayToId, + _Out_writes_opt_(Count) PPH_STRING *DisplayToText, + _In_ ULONG Count, + _Out_ PULONG NumberOfColumns + ) +{ + LVCOLUMN lvColumn; + ULONG i; + ULONG count; + WCHAR buffer[128]; + + count = 0; + lvColumn.mask = LVCF_ORDER | LVCF_TEXT; + lvColumn.pszText = buffer; + lvColumn.cchTextMax = sizeof(buffer) / sizeof(WCHAR); + + for (i = 0; i < Count; i++) + { + if (ListView_GetColumn(ListViewHandle, i, &lvColumn)) + { + ULONG displayIndex; + + displayIndex = (ULONG)lvColumn.iOrder; + assert(displayIndex < Count); + DisplayToId[displayIndex] = i; + + if (DisplayToText) + DisplayToText[displayIndex] = PhaCreateString(buffer); + + count++; + } + else + { + break; + } + } + + *NumberOfColumns = count; +} + +PPH_STRING PhaGetListViewItemText( + _In_ HWND ListViewHandle, + _In_ INT Index, + _In_ INT SubItemIndex + ) +{ + PPH_STRING buffer; + SIZE_T allocatedCount; + SIZE_T count; + LVITEM lvItem; + + // Unfortunately LVM_GETITEMTEXT doesn't want to return the actual length of the text. + // Keep doubling the buffer size until we get a return count that is strictly less than + // the amount we allocated. + + buffer = NULL; + allocatedCount = 256; + count = allocatedCount; + + while (count >= allocatedCount) + { + if (buffer) + PhDereferenceObject(buffer); + + allocatedCount *= 2; + buffer = PhCreateStringEx(NULL, allocatedCount * sizeof(WCHAR)); + buffer->Buffer[0] = 0; + + lvItem.iSubItem = SubItemIndex; + lvItem.cchTextMax = (INT)allocatedCount + 1; + lvItem.pszText = buffer->Buffer; + count = SendMessage(ListViewHandle, LVM_GETITEMTEXT, Index, (LPARAM)&lvItem); + } + + PhTrimToNullTerminatorString(buffer); + PH_AUTO(buffer); + + return buffer; +} + +PPH_STRING PhGetListViewText( + _In_ HWND ListViewHandle + ) +{ + PH_AUTO_POOL autoPool; + PH_STRING_BUILDER stringBuilder; + ULONG displayToId[100]; + ULONG rows; + ULONG columns; + ULONG i; + ULONG j; + + PhInitializeAutoPool(&autoPool); + + PhaMapDisplayIndexListView(ListViewHandle, displayToId, NULL, 100, &columns); + rows = ListView_GetItemCount(ListViewHandle); + + PhInitializeStringBuilder(&stringBuilder, 0x100); + + for (i = 0; i < rows; i++) + { + if (!(ListView_GetItemState(ListViewHandle, i, LVIS_SELECTED) & LVIS_SELECTED)) + continue; + + for (j = 0; j < columns; j++) + { + PhAppendStringBuilder(&stringBuilder, &PhaGetListViewItemText(ListViewHandle, i, j)->sr); + PhAppendStringBuilder2(&stringBuilder, L", "); + } + + // Remove the trailing comma and space. + if (stringBuilder.String->Length != 0) + PhRemoveEndStringBuilder(&stringBuilder, 2); + + PhAppendStringBuilder2(&stringBuilder, L"\r\n"); + } + + PhDeleteAutoPool(&autoPool); + + return PhFinalStringBuilderString(&stringBuilder); +} + +PPH_LIST PhGetListViewLines( + _In_ HWND ListViewHandle, + _In_ ULONG Mode + ) +{ + PH_AUTO_POOL autoPool; + PPH_LIST lines; + ULONG rows; + ULONG columns; + ULONG displayToId[100]; + PPH_STRING displayToText[100]; + PPH_STRING **table; + ULONG i; + ULONG j; + + PhInitializeAutoPool(&autoPool); + + rows = ListView_GetItemCount(ListViewHandle) + 1; // +1 for column headers + + // Create the display index/text to ID map. + PhaMapDisplayIndexListView(ListViewHandle, displayToId, displayToText, 100, &columns); + + PhaCreateTextTable(&table, rows, columns); + + // Populate the first row with the column headers. + for (i = 0; i < columns; i++) + table[0][i] = displayToText[i]; + + // Populate the other rows with text. + for (i = 1; i < rows; i++) + { + for (j = 0; j < columns; j++) + { + // Important: use this to bypass extlv's hooking. + // extlv only hooks LVM_GETITEM, not LVM_GETITEMTEXT. + table[i][j] = PhaGetListViewItemText(ListViewHandle, i - 1, j); + } + } + + lines = PhaFormatTextTable(table, rows, columns, Mode); + + PhDeleteAutoPool(&autoPool); + + return lines; +} diff --git a/phlib/data.c b/phlib/data.c index 87939f96aa5f..0389dd563ce3 100644 --- a/phlib/data.c +++ b/phlib/data.c @@ -1,219 +1,219 @@ -#include -#include - -// SIDs - -SID PhSeNobodySid = { SID_REVISION, 1, SECURITY_NULL_SID_AUTHORITY, { SECURITY_NULL_RID } }; - -SID PhSeEveryoneSid = { SID_REVISION, 1, SECURITY_WORLD_SID_AUTHORITY, { SECURITY_WORLD_RID } }; - -SID PhSeLocalSid = { SID_REVISION, 1, SECURITY_LOCAL_SID_AUTHORITY, { SECURITY_LOCAL_RID } }; - -SID PhSeCreatorOwnerSid = { SID_REVISION, 1, SECURITY_CREATOR_SID_AUTHORITY, { SECURITY_CREATOR_OWNER_RID } }; -SID PhSeCreatorGroupSid = { SID_REVISION, 1, SECURITY_CREATOR_SID_AUTHORITY, { SECURITY_CREATOR_GROUP_RID } }; - -SID PhSeDialupSid = { SID_REVISION, 1, SECURITY_NT_AUTHORITY, { SECURITY_DIALUP_RID } }; -SID PhSeNetworkSid = { SID_REVISION, 1, SECURITY_NT_AUTHORITY, { SECURITY_NETWORK_RID } }; -SID PhSeBatchSid = { SID_REVISION, 1, SECURITY_NT_AUTHORITY, { SECURITY_BATCH_RID } }; -SID PhSeInteractiveSid = { SID_REVISION, 1, SECURITY_NT_AUTHORITY, { SECURITY_INTERACTIVE_RID } }; -SID PhSeServiceSid = { SID_REVISION, 1, SECURITY_NT_AUTHORITY, { SECURITY_SERVICE_RID } }; -SID PhSeAnonymousLogonSid = { SID_REVISION, 1, SECURITY_NT_AUTHORITY, { SECURITY_ANONYMOUS_LOGON_RID } }; -SID PhSeProxySid = { SID_REVISION, 1, SECURITY_NT_AUTHORITY, { SECURITY_PROXY_RID } }; -SID PhSeAuthenticatedUserSid = { SID_REVISION, 1, SECURITY_NT_AUTHORITY, { SECURITY_AUTHENTICATED_USER_RID } }; -SID PhSeRestrictedCodeSid = { SID_REVISION, 1, SECURITY_NT_AUTHORITY, { SECURITY_RESTRICTED_CODE_RID } }; -SID PhSeTerminalServerUserSid = { SID_REVISION, 1, SECURITY_NT_AUTHORITY, { SECURITY_TERMINAL_SERVER_RID } }; -SID PhSeRemoteInteractiveLogonSid = { SID_REVISION, 1, SECURITY_NT_AUTHORITY, { SECURITY_REMOTE_LOGON_RID } }; -SID PhSeLocalSystemSid = { SID_REVISION, 1, SECURITY_NT_AUTHORITY, { SECURITY_LOCAL_SYSTEM_RID } }; -SID PhSeLocalServiceSid = { SID_REVISION, 1, SECURITY_NT_AUTHORITY, { SECURITY_LOCAL_SERVICE_RID } }; -SID PhSeNetworkServiceSid = { SID_REVISION, 1, SECURITY_NT_AUTHORITY, { SECURITY_NETWORK_SERVICE_RID } }; - -// Unicode - -PH_STRINGREF PhUnicodeByteOrderMark = PH_STRINGREF_INIT(L"\ufeff"); - -// Characters - -DECLSPEC_SELECTANY -BOOLEAN PhCharIsPrintable[256] = -{ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, /* 0 - 15 */ // TAB, LF and CR are printable - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 16 - 31 */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ' ' - '/' */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* '0' - '9' */ - 1, 1, 1, 1, 1, 1, 1, /* ':' - '@' */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 'A' - 'Z' */ - 1, 1, 1, 1, 1, 1, /* '[' - '`' */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 'a' - 'z' */ - 1, 1, 1, 1, 0, /* '{' - 127 */ // DEL is not printable - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 128 - 143 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 144 - 159 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 160 - 175 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 176 - 191 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 192 - 207 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 208 - 223 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 224 - 239 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* 240 - 255 */ -}; - -DECLSPEC_SELECTANY -ULONG PhCharToInteger[256] = -{ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0 - 15 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 16 - 31 */ - 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, /* ' ' - '/' */ - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, /* '0' - '9' */ - 52, 53, 54, 55, 56, 57, 58, /* ':' - '@' */ - 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, /* 'A' - 'Z' */ - 59, 60, 61, 62, 63, 64, /* '[' - '`' */ - 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, /* 'a' - 'z' */ - 65, 66, 67, 68, -1, /* '{' - 127 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 128 - 143 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 144 - 159 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 160 - 175 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 176 - 191 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 192 - 207 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 208 - 223 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 224 - 239 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 /* 240 - 255 */ -}; - -DECLSPEC_SELECTANY -CHAR PhIntegerToChar[69] = - "0123456789" /* 0 - 9 */ - "abcdefghijklmnopqrstuvwxyz" /* 10 - 35 */ - " !\"#$%&'()*+,-./" /* 36 - 51 */ - ":;<=>?@" /* 52 - 58 */ - "[\\]^_`" /* 59 - 64 */ - "{|}~" /* 65 - 68 */ - ; - -DECLSPEC_SELECTANY -CHAR PhIntegerToCharUpper[69] = - "0123456789" /* 0 - 9 */ - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" /* 10 - 35 */ - " !\"#$%&'()*+,-./" /* 36 - 51 */ - ":;<=>?@" /* 52 - 58 */ - "[\\]^_`" /* 59 - 64 */ - "{|}~" /* 65 - 68 */ - ; - -// CRC32 (IEEE 802.3) - -DECLSPEC_SELECTANY -ULONG PhCrc32Table[256] = -{ - 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, - 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, - 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, - 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, - 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, - 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, - 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, - 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, - 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, - 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, - 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, - 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, - 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, - 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, - 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, - 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, - 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, - 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, - 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, - 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, - 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, - 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, - 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, - 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, - 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, - 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, - 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, - 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, - 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, - 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, - 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, - 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d -}; - -// Enums - -DECLSPEC_SELECTANY -WCHAR *PhIoPriorityHintNames[MaxIoPriorityTypes] = -{ - L"Very low", - L"Low", - L"Normal", - L"High", - L"Critical" -}; - -DECLSPEC_SELECTANY -WCHAR *PhPagePriorityNames[MEMORY_PRIORITY_NORMAL + 1] = -{ - L"Lowest", - L"Very low", - L"Low", - L"Medium", - L"Below normal", - L"Normal" -}; - -DECLSPEC_SELECTANY -WCHAR *PhKThreadStateNames[MaximumThreadState] = -{ - L"Initialized", - L"Ready", - L"Running", - L"Standby", - L"Terminated", - L"Waiting", - L"Transition", - L"DeferredReady", - L"GateWait", - L"WaitingForProcessInSwap" -}; - -DECLSPEC_SELECTANY -WCHAR *PhKWaitReasonNames[MaximumWaitReason] = -{ - L"Executive", - L"FreePage", - L"PageIn", - L"PoolAllocation", - L"DelayExecution", - L"Suspended", - L"UserRequest", - L"WrExecutive", - L"WrFreePage", - L"WrPageIn", - L"WrPoolAllocation", - L"WrDelayExecution", - L"WrSuspended", - L"WrUserRequest", - L"WrEventPair", - L"WrQueue", - L"WrLpcReceive", - L"WrLpcReply", - L"WrVirtualMemory", - L"WrPageOut", - L"WrRendezvous", - L"WrKeyedEvent", - L"WrTerminated", - L"WrProcessInSwap", - L"WrCpuRateControl", - L"WrCalloutStack", - L"WrKernel", - L"WrResource", - L"WrPushLock", - L"WrMutex", - L"WrQuantumEnd", - L"WrDispatchInt", - L"WrPreempted", - L"WrYieldExecution", - L"WrFastMutex", - L"WrGuardedMutex", - L"WrRundown", - L"WrAlertByThreadId", - L"WrDeferredPreempt" -}; +#include +#include + +// SIDs + +SID PhSeNobodySid = { SID_REVISION, 1, SECURITY_NULL_SID_AUTHORITY, { SECURITY_NULL_RID } }; + +SID PhSeEveryoneSid = { SID_REVISION, 1, SECURITY_WORLD_SID_AUTHORITY, { SECURITY_WORLD_RID } }; + +SID PhSeLocalSid = { SID_REVISION, 1, SECURITY_LOCAL_SID_AUTHORITY, { SECURITY_LOCAL_RID } }; + +SID PhSeCreatorOwnerSid = { SID_REVISION, 1, SECURITY_CREATOR_SID_AUTHORITY, { SECURITY_CREATOR_OWNER_RID } }; +SID PhSeCreatorGroupSid = { SID_REVISION, 1, SECURITY_CREATOR_SID_AUTHORITY, { SECURITY_CREATOR_GROUP_RID } }; + +SID PhSeDialupSid = { SID_REVISION, 1, SECURITY_NT_AUTHORITY, { SECURITY_DIALUP_RID } }; +SID PhSeNetworkSid = { SID_REVISION, 1, SECURITY_NT_AUTHORITY, { SECURITY_NETWORK_RID } }; +SID PhSeBatchSid = { SID_REVISION, 1, SECURITY_NT_AUTHORITY, { SECURITY_BATCH_RID } }; +SID PhSeInteractiveSid = { SID_REVISION, 1, SECURITY_NT_AUTHORITY, { SECURITY_INTERACTIVE_RID } }; +SID PhSeServiceSid = { SID_REVISION, 1, SECURITY_NT_AUTHORITY, { SECURITY_SERVICE_RID } }; +SID PhSeAnonymousLogonSid = { SID_REVISION, 1, SECURITY_NT_AUTHORITY, { SECURITY_ANONYMOUS_LOGON_RID } }; +SID PhSeProxySid = { SID_REVISION, 1, SECURITY_NT_AUTHORITY, { SECURITY_PROXY_RID } }; +SID PhSeAuthenticatedUserSid = { SID_REVISION, 1, SECURITY_NT_AUTHORITY, { SECURITY_AUTHENTICATED_USER_RID } }; +SID PhSeRestrictedCodeSid = { SID_REVISION, 1, SECURITY_NT_AUTHORITY, { SECURITY_RESTRICTED_CODE_RID } }; +SID PhSeTerminalServerUserSid = { SID_REVISION, 1, SECURITY_NT_AUTHORITY, { SECURITY_TERMINAL_SERVER_RID } }; +SID PhSeRemoteInteractiveLogonSid = { SID_REVISION, 1, SECURITY_NT_AUTHORITY, { SECURITY_REMOTE_LOGON_RID } }; +SID PhSeLocalSystemSid = { SID_REVISION, 1, SECURITY_NT_AUTHORITY, { SECURITY_LOCAL_SYSTEM_RID } }; +SID PhSeLocalServiceSid = { SID_REVISION, 1, SECURITY_NT_AUTHORITY, { SECURITY_LOCAL_SERVICE_RID } }; +SID PhSeNetworkServiceSid = { SID_REVISION, 1, SECURITY_NT_AUTHORITY, { SECURITY_NETWORK_SERVICE_RID } }; + +// Unicode + +PH_STRINGREF PhUnicodeByteOrderMark = PH_STRINGREF_INIT(L"\ufeff"); + +// Characters + +DECLSPEC_SELECTANY +BOOLEAN PhCharIsPrintable[256] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, /* 0 - 15 */ // TAB, LF and CR are printable + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 16 - 31 */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ' ' - '/' */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* '0' - '9' */ + 1, 1, 1, 1, 1, 1, 1, /* ':' - '@' */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 'A' - 'Z' */ + 1, 1, 1, 1, 1, 1, /* '[' - '`' */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 'a' - 'z' */ + 1, 1, 1, 1, 0, /* '{' - 127 */ // DEL is not printable + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 128 - 143 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 144 - 159 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 160 - 175 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 176 - 191 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 192 - 207 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 208 - 223 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 224 - 239 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* 240 - 255 */ +}; + +DECLSPEC_SELECTANY +ULONG PhCharToInteger[256] = +{ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0 - 15 */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 16 - 31 */ + 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, /* ' ' - '/' */ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, /* '0' - '9' */ + 52, 53, 54, 55, 56, 57, 58, /* ':' - '@' */ + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, /* 'A' - 'Z' */ + 59, 60, 61, 62, 63, 64, /* '[' - '`' */ + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, /* 'a' - 'z' */ + 65, 66, 67, 68, -1, /* '{' - 127 */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 128 - 143 */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 144 - 159 */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 160 - 175 */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 176 - 191 */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 192 - 207 */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 208 - 223 */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 224 - 239 */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 /* 240 - 255 */ +}; + +DECLSPEC_SELECTANY +CHAR PhIntegerToChar[69] = + "0123456789" /* 0 - 9 */ + "abcdefghijklmnopqrstuvwxyz" /* 10 - 35 */ + " !\"#$%&'()*+,-./" /* 36 - 51 */ + ":;<=>?@" /* 52 - 58 */ + "[\\]^_`" /* 59 - 64 */ + "{|}~" /* 65 - 68 */ + ; + +DECLSPEC_SELECTANY +CHAR PhIntegerToCharUpper[69] = + "0123456789" /* 0 - 9 */ + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" /* 10 - 35 */ + " !\"#$%&'()*+,-./" /* 36 - 51 */ + ":;<=>?@" /* 52 - 58 */ + "[\\]^_`" /* 59 - 64 */ + "{|}~" /* 65 - 68 */ + ; + +// CRC32 (IEEE 802.3) + +DECLSPEC_SELECTANY +ULONG PhCrc32Table[256] = +{ + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, + 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, + 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, + 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, + 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, + 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, + 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, + 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, + 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, + 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, + 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, + 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, + 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, + 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, + 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, + 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, + 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, + 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, + 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, + 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, + 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, + 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, + 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, + 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, + 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, + 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, + 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, + 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, + 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, + 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d +}; + +// Enums + +DECLSPEC_SELECTANY +WCHAR *PhIoPriorityHintNames[MaxIoPriorityTypes] = +{ + L"Very low", + L"Low", + L"Normal", + L"High", + L"Critical" +}; + +DECLSPEC_SELECTANY +WCHAR *PhPagePriorityNames[MEMORY_PRIORITY_NORMAL + 1] = +{ + L"Lowest", + L"Very low", + L"Low", + L"Medium", + L"Below normal", + L"Normal" +}; + +DECLSPEC_SELECTANY +WCHAR *PhKThreadStateNames[MaximumThreadState] = +{ + L"Initialized", + L"Ready", + L"Running", + L"Standby", + L"Terminated", + L"Waiting", + L"Transition", + L"DeferredReady", + L"GateWait", + L"WaitingForProcessInSwap" +}; + +DECLSPEC_SELECTANY +WCHAR *PhKWaitReasonNames[MaximumWaitReason] = +{ + L"Executive", + L"FreePage", + L"PageIn", + L"PoolAllocation", + L"DelayExecution", + L"Suspended", + L"UserRequest", + L"WrExecutive", + L"WrFreePage", + L"WrPageIn", + L"WrPoolAllocation", + L"WrDelayExecution", + L"WrSuspended", + L"WrUserRequest", + L"WrEventPair", + L"WrQueue", + L"WrLpcReceive", + L"WrLpcReply", + L"WrVirtualMemory", + L"WrPageOut", + L"WrRendezvous", + L"WrKeyedEvent", + L"WrTerminated", + L"WrProcessInSwap", + L"WrCpuRateControl", + L"WrCalloutStack", + L"WrKernel", + L"WrResource", + L"WrPushLock", + L"WrMutex", + L"WrQuantumEnd", + L"WrDispatchInt", + L"WrPreempted", + L"WrYieldExecution", + L"WrFastMutex", + L"WrGuardedMutex", + L"WrRundown", + L"WrAlertByThreadId", + L"WrDeferredPreempt" +}; diff --git a/phlib/dspick.c b/phlib/dspick.c index f62cb3bcd44d..5bbc7f1cad6e 100644 --- a/phlib/dspick.c +++ b/phlib/dspick.c @@ -1,251 +1,251 @@ -/* - * Process Hacker - - * DS object picker wrapper - * - * Copyright (C) 2010 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include -#include - -#include -#define CINTERFACE -#define COBJMACROS -#include - -#include -#include - -#define IDataObject_AddRef(This) ((This)->lpVtbl->AddRef(This)) -#define IDataObject_Release(This) ((This)->lpVtbl->Release(This)) -#define IDataObject_GetData(This, pformatetcIn, pmedium) ((This)->lpVtbl->GetData(This, pformatetcIn, pmedium)) - -#define IDsObjectPicker_QueryInterface(This, riid, ppvObject) ((This)->lpVtbl->QueryInterface(This, riid, ppvObject)) -#define IDsObjectPicker_AddRef(This) ((This)->lpVtbl->AddRef(This)) -#define IDsObjectPicker_Release(This) ((This)->lpVtbl->Release(This)) -#define IDsObjectPicker_Initialize(This, pInitInfo) ((This)->lpVtbl->Initialize(This, pInitInfo)) -#define IDsObjectPicker_InvokeDialog(This, hwndParent, ppdoSelections) ((This)->lpVtbl->InvokeDialog(This, hwndParent, ppdoSelections)) - -IDsObjectPicker *PhpCreateDsObjectPicker( - VOID - ) -{ - static CLSID CLSID_DsObjectPicker_I = { 0x17d6ccd8, 0x3b7b, 0x11d2, { 0xb9, 0xe0, 0x00, 0xc0, 0x4f, 0xd8, 0xdb, 0xf7 } }; - static IID IID_IDsObjectPicker_I = { 0x0c87e64e, 0x3b7a, 0x11d2, { 0xb9, 0xe0, 0x00, 0xc0, 0x4f, 0xd8, 0xdb, 0xf7 } }; - - IDsObjectPicker *picker; - - if (SUCCEEDED(CoCreateInstance( - &CLSID_DsObjectPicker_I, - NULL, - CLSCTX_INPROC_SERVER, - &IID_IDsObjectPicker_I, - &picker - ))) - { - return picker; - } - else - { - return NULL; - } -} - -VOID PhFreeDsObjectPickerDialog( - _In_ PVOID PickerDialog - ) -{ - IDsObjectPicker_Release((IDsObjectPicker *)PickerDialog); -} - -PVOID PhCreateDsObjectPickerDialog( - _In_ ULONG Flags - ) -{ - IDsObjectPicker *picker; - DSOP_INIT_INFO initInfo; - DSOP_SCOPE_INIT_INFO scopeInit[1]; - - picker = PhpCreateDsObjectPicker(); - - if (!picker) - return NULL; - - memset(scopeInit, 0, sizeof(scopeInit)); - - scopeInit[0].cbSize = sizeof(DSOP_SCOPE_INIT_INFO); - scopeInit[0].flType = DSOP_SCOPE_TYPE_TARGET_COMPUTER; - scopeInit[0].flScope = - DSOP_SCOPE_FLAG_WANT_PROVIDER_WINNT | - DSOP_SCOPE_FLAG_WANT_SID_PATH | - DSOP_SCOPE_FLAG_DEFAULT_FILTER_USERS | - DSOP_SCOPE_FLAG_DEFAULT_FILTER_GROUPS; - scopeInit[0].FilterFlags.Uplevel.flBothModes = - DSOP_FILTER_INCLUDE_ADVANCED_VIEW | - DSOP_FILTER_USERS | - DSOP_FILTER_BUILTIN_GROUPS | - DSOP_FILTER_WELL_KNOWN_PRINCIPALS; - scopeInit[0].FilterFlags.flDownlevel = - DSOP_DOWNLEVEL_FILTER_USERS | - DSOP_DOWNLEVEL_FILTER_LOCAL_GROUPS | - DSOP_DOWNLEVEL_FILTER_GLOBAL_GROUPS | - DSOP_DOWNLEVEL_FILTER_ALL_WELLKNOWN_SIDS; - - memset(&initInfo, 0, sizeof(DSOP_INIT_INFO)); - initInfo.cbSize = sizeof(DSOP_INIT_INFO); - initInfo.pwzTargetComputer = NULL; - initInfo.cDsScopeInfos = 1; - initInfo.aDsScopeInfos = scopeInit; - initInfo.flOptions = DSOP_FLAG_SKIP_TARGET_COMPUTER_DC_CHECK; - - if (Flags & PH_DSPICK_MULTISELECT) - initInfo.flOptions |= DSOP_FLAG_MULTISELECT; - - if (!SUCCEEDED(IDsObjectPicker_Initialize(picker, &initInfo))) - { - IDsObjectPicker_Release(picker); - return NULL; - } - - return picker; -} - -PDS_SELECTION_LIST PhpGetDsSelectionList( - _In_ IDataObject *Selections - ) -{ - FORMATETC format; - STGMEDIUM medium; - - format.cfFormat = (CLIPFORMAT)RegisterClipboardFormat(L"CFSTR_DSOP_DS_SELECTION_LIST"); - format.ptd = NULL; - format.dwAspect = -1; - format.lindex = -1; - format.tymed = TYMED_HGLOBAL; - - if (SUCCEEDED(IDataObject_GetData(Selections, &format, &medium))) - { - if (medium.tymed != TYMED_HGLOBAL) - return NULL; - - return (PDS_SELECTION_LIST)GlobalLock(medium.hGlobal); - } - else - { - return NULL; - } -} - -BOOLEAN PhShowDsObjectPickerDialog( - _In_ HWND hWnd, - _In_ PVOID PickerDialog, - _Out_ PPH_DSPICK_OBJECTS *Objects - ) -{ - IDsObjectPicker *picker; - IDataObject *dataObject; - PDS_SELECTION_LIST selections; - PPH_DSPICK_OBJECTS objects; - ULONG i; - - picker = (IDsObjectPicker *)PickerDialog; - - if (!SUCCEEDED(IDsObjectPicker_InvokeDialog(picker, hWnd, &dataObject))) - return FALSE; - - if (!dataObject) - return FALSE; - - selections = PhpGetDsSelectionList(dataObject); - IDataObject_Release(dataObject); - - if (!selections) - return FALSE; - - objects = PhAllocate( - FIELD_OFFSET(PH_DSPICK_OBJECTS, Objects) + - selections->cItems * sizeof(PH_DSPICK_OBJECT) - ); - - objects->NumberOfObjects = selections->cItems; - - for (i = 0; i < selections->cItems; i++) - { - PDS_SELECTION selection; - PSID sid; - PH_STRINGREF path; - PH_STRINGREF prefix; - - selection = &selections->aDsSelection[i]; - - objects->Objects[i].Name = PhCreateString(selection->pwzName); - objects->Objects[i].Sid = NULL; - - if (selection->pwzADsPath && selection->pwzADsPath[0] != 0) - { - PhInitializeStringRef(&path, selection->pwzADsPath); - PhInitializeStringRef(&prefix, L"LDAP://" at end - - sid = PhAllocate(path.Length / sizeof(WCHAR) / 2); - - if (PhHexStringToBuffer(&path, (PUCHAR)sid)) - { - if (RtlValidSid(sid)) - objects->Objects[i].Sid = sid; - else - PhFree(sid); - } - else - { - PhFree(sid); - } - } - } - else - { - // Try to get the SID. - PhLookupName(&objects->Objects[i].Name->sr, &objects->Objects[i].Sid, NULL, NULL); - } - } - - *Objects = objects; - - return TRUE; -} - -VOID PhFreeDsObjectPickerObjects( - _In_ PPH_DSPICK_OBJECTS Objects - ) -{ - ULONG i; - - for (i = 0; i < Objects->NumberOfObjects; i++) - { - PhDereferenceObject(Objects->Objects[i].Name); - - if (Objects->Objects[i].Sid) - PhFree(Objects->Objects[i].Sid); - } - - PhFree(Objects); -} +/* + * Process Hacker - + * DS object picker wrapper + * + * Copyright (C) 2010 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include +#include + +#include +#define CINTERFACE +#define COBJMACROS +#include + +#include +#include + +#define IDataObject_AddRef(This) ((This)->lpVtbl->AddRef(This)) +#define IDataObject_Release(This) ((This)->lpVtbl->Release(This)) +#define IDataObject_GetData(This, pformatetcIn, pmedium) ((This)->lpVtbl->GetData(This, pformatetcIn, pmedium)) + +#define IDsObjectPicker_QueryInterface(This, riid, ppvObject) ((This)->lpVtbl->QueryInterface(This, riid, ppvObject)) +#define IDsObjectPicker_AddRef(This) ((This)->lpVtbl->AddRef(This)) +#define IDsObjectPicker_Release(This) ((This)->lpVtbl->Release(This)) +#define IDsObjectPicker_Initialize(This, pInitInfo) ((This)->lpVtbl->Initialize(This, pInitInfo)) +#define IDsObjectPicker_InvokeDialog(This, hwndParent, ppdoSelections) ((This)->lpVtbl->InvokeDialog(This, hwndParent, ppdoSelections)) + +IDsObjectPicker *PhpCreateDsObjectPicker( + VOID + ) +{ + static CLSID CLSID_DsObjectPicker_I = { 0x17d6ccd8, 0x3b7b, 0x11d2, { 0xb9, 0xe0, 0x00, 0xc0, 0x4f, 0xd8, 0xdb, 0xf7 } }; + static IID IID_IDsObjectPicker_I = { 0x0c87e64e, 0x3b7a, 0x11d2, { 0xb9, 0xe0, 0x00, 0xc0, 0x4f, 0xd8, 0xdb, 0xf7 } }; + + IDsObjectPicker *picker; + + if (SUCCEEDED(CoCreateInstance( + &CLSID_DsObjectPicker_I, + NULL, + CLSCTX_INPROC_SERVER, + &IID_IDsObjectPicker_I, + &picker + ))) + { + return picker; + } + else + { + return NULL; + } +} + +VOID PhFreeDsObjectPickerDialog( + _In_ PVOID PickerDialog + ) +{ + IDsObjectPicker_Release((IDsObjectPicker *)PickerDialog); +} + +PVOID PhCreateDsObjectPickerDialog( + _In_ ULONG Flags + ) +{ + IDsObjectPicker *picker; + DSOP_INIT_INFO initInfo; + DSOP_SCOPE_INIT_INFO scopeInit[1]; + + picker = PhpCreateDsObjectPicker(); + + if (!picker) + return NULL; + + memset(scopeInit, 0, sizeof(scopeInit)); + + scopeInit[0].cbSize = sizeof(DSOP_SCOPE_INIT_INFO); + scopeInit[0].flType = DSOP_SCOPE_TYPE_TARGET_COMPUTER; + scopeInit[0].flScope = + DSOP_SCOPE_FLAG_WANT_PROVIDER_WINNT | + DSOP_SCOPE_FLAG_WANT_SID_PATH | + DSOP_SCOPE_FLAG_DEFAULT_FILTER_USERS | + DSOP_SCOPE_FLAG_DEFAULT_FILTER_GROUPS; + scopeInit[0].FilterFlags.Uplevel.flBothModes = + DSOP_FILTER_INCLUDE_ADVANCED_VIEW | + DSOP_FILTER_USERS | + DSOP_FILTER_BUILTIN_GROUPS | + DSOP_FILTER_WELL_KNOWN_PRINCIPALS; + scopeInit[0].FilterFlags.flDownlevel = + DSOP_DOWNLEVEL_FILTER_USERS | + DSOP_DOWNLEVEL_FILTER_LOCAL_GROUPS | + DSOP_DOWNLEVEL_FILTER_GLOBAL_GROUPS | + DSOP_DOWNLEVEL_FILTER_ALL_WELLKNOWN_SIDS; + + memset(&initInfo, 0, sizeof(DSOP_INIT_INFO)); + initInfo.cbSize = sizeof(DSOP_INIT_INFO); + initInfo.pwzTargetComputer = NULL; + initInfo.cDsScopeInfos = 1; + initInfo.aDsScopeInfos = scopeInit; + initInfo.flOptions = DSOP_FLAG_SKIP_TARGET_COMPUTER_DC_CHECK; + + if (Flags & PH_DSPICK_MULTISELECT) + initInfo.flOptions |= DSOP_FLAG_MULTISELECT; + + if (!SUCCEEDED(IDsObjectPicker_Initialize(picker, &initInfo))) + { + IDsObjectPicker_Release(picker); + return NULL; + } + + return picker; +} + +PDS_SELECTION_LIST PhpGetDsSelectionList( + _In_ IDataObject *Selections + ) +{ + FORMATETC format; + STGMEDIUM medium; + + format.cfFormat = (CLIPFORMAT)RegisterClipboardFormat(L"CFSTR_DSOP_DS_SELECTION_LIST"); + format.ptd = NULL; + format.dwAspect = -1; + format.lindex = -1; + format.tymed = TYMED_HGLOBAL; + + if (SUCCEEDED(IDataObject_GetData(Selections, &format, &medium))) + { + if (medium.tymed != TYMED_HGLOBAL) + return NULL; + + return (PDS_SELECTION_LIST)GlobalLock(medium.hGlobal); + } + else + { + return NULL; + } +} + +BOOLEAN PhShowDsObjectPickerDialog( + _In_ HWND hWnd, + _In_ PVOID PickerDialog, + _Out_ PPH_DSPICK_OBJECTS *Objects + ) +{ + IDsObjectPicker *picker; + IDataObject *dataObject; + PDS_SELECTION_LIST selections; + PPH_DSPICK_OBJECTS objects; + ULONG i; + + picker = (IDsObjectPicker *)PickerDialog; + + if (!SUCCEEDED(IDsObjectPicker_InvokeDialog(picker, hWnd, &dataObject))) + return FALSE; + + if (!dataObject) + return FALSE; + + selections = PhpGetDsSelectionList(dataObject); + IDataObject_Release(dataObject); + + if (!selections) + return FALSE; + + objects = PhAllocate( + FIELD_OFFSET(PH_DSPICK_OBJECTS, Objects) + + selections->cItems * sizeof(PH_DSPICK_OBJECT) + ); + + objects->NumberOfObjects = selections->cItems; + + for (i = 0; i < selections->cItems; i++) + { + PDS_SELECTION selection; + PSID sid; + PH_STRINGREF path; + PH_STRINGREF prefix; + + selection = &selections->aDsSelection[i]; + + objects->Objects[i].Name = PhCreateString(selection->pwzName); + objects->Objects[i].Sid = NULL; + + if (selection->pwzADsPath && selection->pwzADsPath[0] != 0) + { + PhInitializeStringRef(&path, selection->pwzADsPath); + PhInitializeStringRef(&prefix, L"LDAP://" at end + + sid = PhAllocate(path.Length / sizeof(WCHAR) / 2); + + if (PhHexStringToBuffer(&path, (PUCHAR)sid)) + { + if (RtlValidSid(sid)) + objects->Objects[i].Sid = sid; + else + PhFree(sid); + } + else + { + PhFree(sid); + } + } + } + else + { + // Try to get the SID. + PhLookupName(&objects->Objects[i].Name->sr, &objects->Objects[i].Sid, NULL, NULL); + } + } + + *Objects = objects; + + return TRUE; +} + +VOID PhFreeDsObjectPickerObjects( + _In_ PPH_DSPICK_OBJECTS Objects + ) +{ + ULONG i; + + for (i = 0; i < Objects->NumberOfObjects; i++) + { + PhDereferenceObject(Objects->Objects[i].Name); + + if (Objects->Objects[i].Sid) + PhFree(Objects->Objects[i].Sid); + } + + PhFree(Objects); +} diff --git a/phlib/emenu.c b/phlib/emenu.c index 128b1757692d..920a2d0f0e2a 100644 --- a/phlib/emenu.c +++ b/phlib/emenu.c @@ -1,857 +1,857 @@ -/* - * Process Hacker - - * extended menus - * - * Copyright (C) 2010-2011 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include -#include - -#include - -static const PH_FLAG_MAPPING EMenuTypeMappings[] = -{ - { PH_EMENU_MENUBARBREAK, MFT_MENUBARBREAK }, - { PH_EMENU_MENUBREAK, MFT_MENUBREAK }, - { PH_EMENU_RADIOCHECK, MFT_RADIOCHECK } -}; - -static const PH_FLAG_MAPPING EMenuStateMappings[] = -{ - { PH_EMENU_CHECKED, MFS_CHECKED }, - { PH_EMENU_DEFAULT, MFS_DEFAULT }, - { PH_EMENU_DISABLED, MFS_DISABLED }, - { PH_EMENU_HIGHLIGHT, MFS_HILITE } -}; - -PPH_EMENU_ITEM PhAllocateEMenuItem( - VOID - ) -{ - PPH_EMENU_ITEM item; - - item = PhAllocate(sizeof(PH_EMENU_ITEM)); - memset(item, 0, sizeof(PH_EMENU_ITEM)); - - return item; -} - -/** - * Creates a menu item. - * - * \param Flags A combination of the following: - * \li \c PH_EMENU_DISABLED The menu item is greyed and cannot be selected. - * \li \c PH_EMENU_CHECKED A check mark is displayed. - * \li \c PH_EMENU_HIGHLIGHT The menu item is highlighted. - * \li \c PH_EMENU_MENUBARBREAK Places the menu item in a new column, separated by a vertical line. - * \li \c PH_EMENU_MENUBREAK Places the menu item in a new column, with no vertical line. - * \li \c PH_EMENU_DEFAULT The menu item is displayed as the default item. This causes the text to - * be bolded. - * \li \c PH_EMENU_RADIOCHECK Uses a radio-button mark instead of a check mark. - * \param Id A unique identifier for the menu item. - * \param Text The text displayed for the menu item. - * \param Bitmap A bitmap image for the menu item. - * \param Context A user-defined value. - */ -PPH_EMENU_ITEM PhCreateEMenuItem( - _In_ ULONG Flags, - _In_ ULONG Id, - _In_ PWSTR Text, - _In_opt_ HBITMAP Bitmap, - _In_opt_ PVOID Context - ) -{ - PPH_EMENU_ITEM item; - - item = PhAllocateEMenuItem(); - - item->Flags = Flags; - item->Id = Id; - item->Text = Text; - item->Bitmap = Bitmap; - - item->Context = Context; - - return item; -} - -/** - * Frees resources used by a menu item and its children. - * - * \param Item The menu item. - * - * \remarks The menu item is NOT automatically removed from its parent. It is safe to call this - * function while enumerating menu items. - */ -VOID PhpDestroyEMenuItem( - _In_ PPH_EMENU_ITEM Item - ) -{ - if (Item->DeleteFunction) - Item->DeleteFunction(Item); - - if ((Item->Flags & PH_EMENU_TEXT_OWNED) && Item->Text) - PhFree(Item->Text); - if ((Item->Flags & PH_EMENU_BITMAP_OWNED) && Item->Bitmap) - DeleteObject(Item->Bitmap); - - if (Item->Items) - { - ULONG i; - - for (i = 0; i < Item->Items->Count; i++) - { - PhpDestroyEMenuItem(Item->Items->Items[i]); - } - - PhDereferenceObject(Item->Items); - } - - PhFree(Item); -} - -/** - * Frees resources used by a menu item and its children. - * - * \param Item The menu item. - * - * \remarks The menu item is automatically removed from its parent. - */ -VOID PhDestroyEMenuItem( - _In_ PPH_EMENU_ITEM Item - ) -{ - // Remove the item from its parent, if it has one. - if (Item->Parent) - PhRemoveEMenuItem(NULL, Item, -1); - - PhpDestroyEMenuItem(Item); -} - -/** - * Finds a child menu item. - * - * \param Item The parent menu item. - * \param Flags A combination of the following: - * \li \c PH_EMENU_FIND_DESCEND Searches recursively within child menu items. - * \li \c PH_EMENU_FIND_STARTSWITH Performs a partial text search instead of an exact search. - * \li \c PH_EMENU_FIND_LITERAL Performs a literal search instead of ignoring prefix characters - * (ampersands). - * \param Text The text of the menu item to find. If NULL, the text is ignored. - * \param Id The identifier of the menu item to find. If 0, the identifier is ignored. - * - * \return The found menu item, or NULL if the menu item could not be found. - */ -PPH_EMENU_ITEM PhFindEMenuItem( - _In_ PPH_EMENU_ITEM Item, - _In_ ULONG Flags, - _In_opt_ PWSTR Text, - _In_opt_ ULONG Id - ) -{ - return PhFindEMenuItemEx(Item, Flags, Text, Id, NULL, NULL); -} - -/** - * Finds a child menu item. - * - * \param Item The parent menu item. - * \param Flags A combination of the following: - * \li \c PH_EMENU_FIND_DESCEND Searches recursively within child menu items. - * \li \c PH_EMENU_FIND_STARTSWITH Performs a partial text search instead of an exact search. - * \li \c PH_EMENU_FIND_LITERAL Performs a literal search instead of ignoring prefix characters - * (ampersands). - * \param Text The text of the menu item to find. If NULL, the text is ignored. - * \param Id The identifier of the menu item to find. If 0, the identifier is ignored. - * \param FoundParent A variable which receives the parent of the found menu item. - * \param FoundIndex A variable which receives the index of the found menu item. - * - * \return The found menu item, or NULL if the menu item could not be found. - */ -PPH_EMENU_ITEM PhFindEMenuItemEx( - _In_ PPH_EMENU_ITEM Item, - _In_ ULONG Flags, - _In_opt_ PWSTR Text, - _In_opt_ ULONG Id, - _Out_opt_ PPH_EMENU_ITEM *FoundParent, - _Out_opt_ PULONG FoundIndex - ) -{ - PH_STRINGREF searchText; - ULONG i; - PPH_EMENU_ITEM item; - - if (!Item->Items) - return NULL; - - if (Text && (Flags & PH_EMENU_FIND_LITERAL)) - PhInitializeStringRef(&searchText, Text); - - for (i = 0; i < Item->Items->Count; i++) - { - item = Item->Items->Items[i]; - - if (Text) - { - if (Flags & PH_EMENU_FIND_LITERAL) - { - PH_STRINGREF text; - - PhInitializeStringRef(&text, item->Text); - - if (Flags & PH_EMENU_FIND_STARTSWITH) - { - if (PhStartsWithStringRef(&text, &searchText, TRUE)) - goto FoundItemHere; - } - else - { - if (PhEqualStringRef(&text, &searchText, TRUE)) - goto FoundItemHere; - } - } - else - { - if (PhCompareUnicodeStringZIgnoreMenuPrefix(Text, item->Text, - TRUE, !!(Flags & PH_EMENU_FIND_STARTSWITH)) == 0) - goto FoundItemHere; - } - } - - if (Id && item->Id == Id) - goto FoundItemHere; - - if (Flags & PH_EMENU_FIND_DESCEND) - { - PPH_EMENU_ITEM foundItem; - PPH_EMENU_ITEM foundParent; - ULONG foundIndex; - - foundItem = PhFindEMenuItemEx(item, Flags, Text, Id, &foundParent, &foundIndex); - - if (foundItem) - { - if (FoundParent) - *FoundParent = foundParent; - if (FoundIndex) - *FoundIndex = foundIndex; - - return foundItem; - } - } - } - - return NULL; - -FoundItemHere: - if (FoundParent) - *FoundParent = Item; - if (FoundIndex) - *FoundIndex = i; - - return item; -} - -/** - * Determines the index of a menu item. - * - * \param Parent The parent menu item. - * \param Item The child menu item. - * - * \return The index of the menu item, or -1 if the menu item was not found in the parent menu item. - */ -ULONG PhIndexOfEMenuItem( - _In_ PPH_EMENU_ITEM Parent, - _In_ PPH_EMENU_ITEM Item - ) -{ - if (!Parent->Items) - return -1; - - return PhFindItemList(Parent->Items, Item); -} - -/** - * Inserts a menu item into a parent menu item. - * - * \param Parent The parent menu item. - * \param Item The menu item to insert. - * \param Index The index at which to insert the menu item. If the index is too large, the menu item - * is inserted at the last position. - */ -VOID PhInsertEMenuItem( - _Inout_ PPH_EMENU_ITEM Parent, - _Inout_ PPH_EMENU_ITEM Item, - _In_ ULONG Index - ) -{ - // Remove the item from its old parent if it has one. - if (Item->Parent) - PhRemoveEMenuItem(Item->Parent, Item, 0); - - if (!Parent->Items) - Parent->Items = PhCreateList(16); - - if (Index > Parent->Items->Count) - Index = Parent->Items->Count; - - if (Index == -1) - PhAddItemList(Parent->Items, Item); - else - PhInsertItemList(Parent->Items, Index, Item); - - Item->Parent = Parent; -} - -/** - * Removes a menu item from its parent. - * - * \param Parent The parent menu item. If \a Item is NULL, this parameter must be specified. - * \param Item The child menu item. This may be NULL if \a Index is specified. - * \param Index The index of the menu item to remove. If \a Item is specified, this parameter is - * ignored. - */ -BOOLEAN PhRemoveEMenuItem( - _Inout_opt_ PPH_EMENU_ITEM Parent, - _In_opt_ PPH_EMENU_ITEM Item, - _In_opt_ ULONG Index - ) -{ - if (Item) - { - if (!Parent) - Parent = Item->Parent; - if (!Parent->Items) - return FALSE; - - Index = PhFindItemList(Parent->Items, Item); - - if (Index == -1) - return FALSE; - } - else - { - if (!Parent) - return FALSE; - if (!Parent->Items) - return FALSE; - } - - Item = Parent->Items->Items[Index]; - PhRemoveItemList(Parent->Items, Index); - Item->Parent = NULL; - - return TRUE; -} - -/** - * Removes all children from a menu item. - * - * \param Parent The parent menu item. - */ -VOID PhRemoveAllEMenuItems( - _Inout_ PPH_EMENU_ITEM Parent - ) -{ - ULONG i; - - if (!Parent->Items) - return; - - for (i = 0; i < Parent->Items->Count; i++) - { - PhpDestroyEMenuItem(Parent->Items->Items[i]); - } - - PhClearList(Parent->Items); -} - -/** - * Creates a root menu. - */ -PPH_EMENU PhCreateEMenu( - VOID - ) -{ - PPH_EMENU menu; - - menu = PhAllocate(sizeof(PH_EMENU)); - memset(menu, 0, sizeof(PH_EMENU)); - menu->Items = PhCreateList(16); - - return menu; -} - -/** - * Frees resources used by a root menu and its children. - * - * \param Menu A root menu. - */ -VOID PhDestroyEMenu( - _In_ PPH_EMENU Menu - ) -{ - ULONG i; - - for (i = 0; i < Menu->Items->Count; i++) - { - PhpDestroyEMenuItem(Menu->Items->Items[i]); - } - - PhDereferenceObject(Menu->Items); - PhFree(Menu); -} - -/** - * Initializes a data structure containing additional information resulting from a call to - * PhEMenuToHMenu(). - */ -VOID PhInitializeEMenuData( - _Out_ PPH_EMENU_DATA Data - ) -{ - Data->IdToItem = PhCreateList(16); -} - -/** - * Frees resources used by a data structure initialized by PhInitializeEMenuData(). - */ -VOID PhDeleteEMenuData( - _Inout_ PPH_EMENU_DATA Data - ) -{ - PhDereferenceObject(Data->IdToItem); -} - -/** - * Converts an EMENU to a Windows menu object. - * - * \param Menu The menu item to convert. - * \param Flags A combination of the following: - * \li \c PH_EMENU_CONVERT_ID Automatically assigns a unique identifier to each converted menu item. - * The resulting mappings are placed in \a Data. - * \param Data Additional data resulting from the conversion. The data structure must be initialized - * by PhInitializeEMenuData() prior to calling this function. - * - * \return A menu handle. The menu object must be destroyed using DestroyMenu() when it is no longer - * needed. - */ -HMENU PhEMenuToHMenu( - _In_ PPH_EMENU_ITEM Menu, - _In_ ULONG Flags, - _Inout_opt_ PPH_EMENU_DATA Data - ) -{ - HMENU menuHandle; - - menuHandle = CreatePopupMenu(); - - if (!menuHandle) - return NULL; - - PhEMenuToHMenu2(menuHandle, Menu, Flags, Data); - - if (!(Menu->Flags & PH_EMENU_SEPARATECHECKSPACE)) - { - MENUINFO menuInfo; - - memset(&menuInfo, 0, sizeof(MENUINFO)); - menuInfo.cbSize = sizeof(MENUINFO); - menuInfo.fMask = MIM_STYLE; - menuInfo.dwStyle = MNS_CHECKORBMP; - SetMenuInfo(menuHandle, &menuInfo); - } - - return menuHandle; -} - -/** - * Converts an EMENU to a Windows menu object. - * - * \param MenuHandle A handle to a Windows menu object. - * \param Menu The menu item to convert. The items are appended to \a MenuHandle. - * \param Flags A combination of the following: - * \li \c PH_EMENU_CONVERT_ID Automatically assigns a unique identifier to each converted menu item. - * The resulting mappings are placed in \a Data. - * \param Data Additional data resulting from the conversion. The data structure must be initialized - * by PhInitializeEMenuData() prior to calling this function. - */ -VOID PhEMenuToHMenu2( - _In_ HMENU MenuHandle, - _In_ PPH_EMENU_ITEM Menu, - _In_ ULONG Flags, - _Inout_opt_ PPH_EMENU_DATA Data - ) -{ - ULONG i; - PPH_EMENU_ITEM item; - MENUITEMINFO menuItemInfo; - - for (i = 0; i < Menu->Items->Count; i++) - { - item = Menu->Items->Items[i]; - - memset(&menuItemInfo, 0, sizeof(MENUITEMINFO)); - menuItemInfo.cbSize = sizeof(MENUITEMINFO); - - // Type - - menuItemInfo.fMask = MIIM_FTYPE | MIIM_STATE; - - if (item->Flags & PH_EMENU_SEPARATOR) - { - menuItemInfo.fType = MFT_SEPARATOR; - } - else - { - menuItemInfo.fType = MFT_STRING; - menuItemInfo.fMask |= MIIM_STRING; - menuItemInfo.dwTypeData = item->Text; - } - - PhMapFlags1( - &menuItemInfo.fType, - item->Flags, - EMenuTypeMappings, - sizeof(EMenuTypeMappings) / sizeof(PH_FLAG_MAPPING) - ); - - // Bitmap - - if (item->Bitmap) - { - menuItemInfo.fMask |= MIIM_BITMAP; - menuItemInfo.hbmpItem = item->Bitmap; - } - - // Id - - if (Flags & PH_EMENU_CONVERT_ID) - { - ULONG id; - - if (Data) - { - PhAddItemList(Data->IdToItem, item); - id = Data->IdToItem->Count; - - menuItemInfo.fMask |= MIIM_ID; - menuItemInfo.wID = id; - } - } - else - { - if (item->Id) - { - menuItemInfo.fMask |= MIIM_ID; - menuItemInfo.wID = item->Id; - } - } - - // State - - PhMapFlags1( - &menuItemInfo.fState, - item->Flags, - EMenuStateMappings, - sizeof(EMenuStateMappings) / sizeof(PH_FLAG_MAPPING) - ); - - // Context - - menuItemInfo.fMask |= MIIM_DATA; - menuItemInfo.dwItemData = (ULONG_PTR)item; - - // Submenu - - if (item->Items && item->Items->Count != 0) - { - menuItemInfo.fMask |= MIIM_SUBMENU; - menuItemInfo.hSubMenu = PhEMenuToHMenu(item, Flags, Data); - } - - InsertMenuItem(MenuHandle, MAXINT, TRUE, &menuItemInfo); - } -} - -/** - * Converts a Windows menu object to an EMENU. - * - * \param MenuItem The menu item in which the converted menu items will be placed. - * \param MenuHandle A menu handle. - */ -VOID PhHMenuToEMenuItem( - _Inout_ PPH_EMENU_ITEM MenuItem, - _In_ HMENU MenuHandle - ) -{ - ULONG i; - ULONG count; - - count = GetMenuItemCount(MenuHandle); - - if (count != -1) - { - for (i = 0; i < count; i++) - { - MENUITEMINFO menuItemInfo; - WCHAR buffer[256]; - PPH_EMENU_ITEM menuItem; - - menuItemInfo.cbSize = sizeof(menuItemInfo); - menuItemInfo.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STATE | MIIM_STRING | MIIM_SUBMENU; - menuItemInfo.cch = sizeof(buffer) / sizeof(WCHAR); - menuItemInfo.dwTypeData = buffer; - - if (!GetMenuItemInfo(MenuHandle, i, TRUE, &menuItemInfo)) - continue; - - menuItem = PhCreateEMenuItem( - PH_EMENU_TEXT_OWNED, - menuItemInfo.wID, - PhDuplicateStringZ(buffer), - NULL, - NULL - ); - - if (menuItemInfo.fType & MFT_SEPARATOR) - menuItem->Flags |= PH_EMENU_SEPARATOR; - - PhMapFlags2( - &menuItem->Flags, - menuItemInfo.fType, - EMenuTypeMappings, - sizeof(EMenuTypeMappings) / sizeof(PH_FLAG_MAPPING) - ); - PhMapFlags2( - &menuItem->Flags, - menuItemInfo.fState, - EMenuStateMappings, - sizeof(EMenuStateMappings) / sizeof(PH_FLAG_MAPPING) - ); - - if (menuItemInfo.hSubMenu) - PhHMenuToEMenuItem(menuItem, menuItemInfo.hSubMenu); - - PhInsertEMenuItem(MenuItem, menuItem, -1); - } - } -} - -/** - * Loads a menu resource and converts it to an EMENU. - * - * \param MenuItem The menu item in which the converted menu items will be placed. - * \param InstanceHandle The module containing the menu resource. - * \param Resource The resource identifier. - * \param SubMenuIndex The index of the sub menu to use, or -1 to use the root menu. - */ -VOID PhLoadResourceEMenuItem( - _Inout_ PPH_EMENU_ITEM MenuItem, - _In_ HINSTANCE InstanceHandle, - _In_ PWSTR Resource, - _In_ ULONG SubMenuIndex - ) -{ - HMENU menu; - HMENU realMenu; - - menu = LoadMenu(InstanceHandle, Resource); - - if (SubMenuIndex != -1) - realMenu = GetSubMenu(menu, SubMenuIndex); - else - realMenu = menu; - - PhHMenuToEMenuItem(MenuItem, realMenu); - - DestroyMenu(menu); -} - -/** - * Displays a menu. - * - * \param Menu A menu. - * \param WindowHandle The window that owns the popup menu. - * \param Flags A combination of the following: - * \li \c PH_EMENU_SHOW_SEND_COMMAND A WM_COMMAND message is sent to the window when the user clicks - * on a menu item. - * \li \c PH_EMENU_SHOW_LEFTRIGHT The user can select menu items with both the left and right mouse - * buttons. - * \param Align The alignment of the menu. - * \param X The horizontal location of the menu. - * \param Y The vertical location of the menu. - * - * \return The selected menu item, or NULL if the menu was cancelled. - */ -PPH_EMENU_ITEM PhShowEMenu( - _In_ PPH_EMENU Menu, - _In_ HWND WindowHandle, - _In_ ULONG Flags, - _In_ ULONG Align, - _In_ ULONG X, - _In_ ULONG Y - ) -{ - PPH_EMENU_ITEM selectedItem; - ULONG result; - ULONG flags; - PH_EMENU_DATA data; - HMENU popupMenu; - - selectedItem = NULL; - flags = TPM_RETURNCMD | TPM_NONOTIFY; - - // Flags - - if (Flags & PH_EMENU_SHOW_LEFTRIGHT) - flags |= TPM_RIGHTBUTTON; - else - flags |= TPM_LEFTBUTTON; - - // Align - - if (Align & PH_ALIGN_LEFT) - flags |= TPM_LEFTALIGN; - else if (Align & PH_ALIGN_RIGHT) - flags |= TPM_RIGHTALIGN; - else - flags |= TPM_CENTERALIGN; - - if (Align & PH_ALIGN_TOP) - flags |= TPM_TOPALIGN; - else if (Align & PH_ALIGN_BOTTOM) - flags |= TPM_BOTTOMALIGN; - else - flags |= TPM_VCENTERALIGN; - - PhInitializeEMenuData(&data); - - if (popupMenu = PhEMenuToHMenu(Menu, PH_EMENU_CONVERT_ID, &data)) - { - result = TrackPopupMenu( - popupMenu, - flags, - X, - Y, - 0, - WindowHandle, - NULL - ); - - if (result != 0) - { - selectedItem = data.IdToItem->Items[result - 1]; - } - - DestroyMenu(popupMenu); - } - - PhDeleteEMenuData(&data); - - if ((Flags & PH_EMENU_SHOW_SEND_COMMAND) && selectedItem && selectedItem->Id != 0) - SendMessage(WindowHandle, WM_COMMAND, MAKEWPARAM(selectedItem->Id, 0), 0); - - return selectedItem; -} - -/** - * Sets the flags of a menu item. - * - * \param Item The parent menu item. - * \param Id The identifier of the child menu item. - * \param Mask The flags to modify. - * \param Value The new value of the flags. - */ -BOOLEAN PhSetFlagsEMenuItem( - _Inout_ PPH_EMENU_ITEM Item, - _In_ ULONG Id, - _In_ ULONG Mask, - _In_ ULONG Value - ) -{ - PPH_EMENU_ITEM item; - - item = PhFindEMenuItem(Item, PH_EMENU_FIND_DESCEND, NULL, Id); - - if (item) - { - item->Flags &= ~Mask; - item->Flags |= Value; - - return TRUE; - } - else - { - return FALSE; - } -} - -/** - * Sets flags for all children of a menu item. - * - * \param Item The parent menu item. - * \param Mask The flags to modify. - * \param Value The new value of the flags. - */ -VOID PhSetFlagsAllEMenuItems( - _In_ PPH_EMENU_ITEM Item, - _In_ ULONG Mask, - _In_ ULONG Value - ) -{ - ULONG i; - - for (i = 0; i < Item->Items->Count; i++) - { - PPH_EMENU_ITEM item = Item->Items->Items[i]; - - item->Flags &= ~Mask; - item->Flags |= Value; - } -} - -VOID PhModifyEMenuItem( - _Inout_ PPH_EMENU_ITEM Item, - _In_ ULONG ModifyFlags, - _In_ ULONG OwnedFlags, - _In_opt_ PWSTR Text, - _In_opt_ HBITMAP Bitmap - ) -{ - if (ModifyFlags & PH_EMENU_MODIFY_TEXT) - { - if ((Item->Flags & PH_EMENU_TEXT_OWNED) && Item->Text) - PhFree(Item->Text); - - Item->Text = Text; - Item->Flags &= ~PH_EMENU_TEXT_OWNED; - Item->Flags |= OwnedFlags & PH_EMENU_TEXT_OWNED; - } - - if (ModifyFlags & PH_EMENU_MODIFY_BITMAP) - { - if ((Item->Flags & PH_EMENU_BITMAP_OWNED) && Item->Bitmap) - DeleteObject(Item->Bitmap); - - Item->Bitmap = Bitmap; - Item->Flags &= ~PH_EMENU_BITMAP_OWNED; - Item->Flags |= OwnedFlags & PH_EMENU_BITMAP_OWNED; - } -} +/* + * Process Hacker - + * extended menus + * + * Copyright (C) 2010-2011 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include +#include + +#include + +static const PH_FLAG_MAPPING EMenuTypeMappings[] = +{ + { PH_EMENU_MENUBARBREAK, MFT_MENUBARBREAK }, + { PH_EMENU_MENUBREAK, MFT_MENUBREAK }, + { PH_EMENU_RADIOCHECK, MFT_RADIOCHECK } +}; + +static const PH_FLAG_MAPPING EMenuStateMappings[] = +{ + { PH_EMENU_CHECKED, MFS_CHECKED }, + { PH_EMENU_DEFAULT, MFS_DEFAULT }, + { PH_EMENU_DISABLED, MFS_DISABLED }, + { PH_EMENU_HIGHLIGHT, MFS_HILITE } +}; + +PPH_EMENU_ITEM PhAllocateEMenuItem( + VOID + ) +{ + PPH_EMENU_ITEM item; + + item = PhAllocate(sizeof(PH_EMENU_ITEM)); + memset(item, 0, sizeof(PH_EMENU_ITEM)); + + return item; +} + +/** + * Creates a menu item. + * + * \param Flags A combination of the following: + * \li \c PH_EMENU_DISABLED The menu item is greyed and cannot be selected. + * \li \c PH_EMENU_CHECKED A check mark is displayed. + * \li \c PH_EMENU_HIGHLIGHT The menu item is highlighted. + * \li \c PH_EMENU_MENUBARBREAK Places the menu item in a new column, separated by a vertical line. + * \li \c PH_EMENU_MENUBREAK Places the menu item in a new column, with no vertical line. + * \li \c PH_EMENU_DEFAULT The menu item is displayed as the default item. This causes the text to + * be bolded. + * \li \c PH_EMENU_RADIOCHECK Uses a radio-button mark instead of a check mark. + * \param Id A unique identifier for the menu item. + * \param Text The text displayed for the menu item. + * \param Bitmap A bitmap image for the menu item. + * \param Context A user-defined value. + */ +PPH_EMENU_ITEM PhCreateEMenuItem( + _In_ ULONG Flags, + _In_ ULONG Id, + _In_ PWSTR Text, + _In_opt_ HBITMAP Bitmap, + _In_opt_ PVOID Context + ) +{ + PPH_EMENU_ITEM item; + + item = PhAllocateEMenuItem(); + + item->Flags = Flags; + item->Id = Id; + item->Text = Text; + item->Bitmap = Bitmap; + + item->Context = Context; + + return item; +} + +/** + * Frees resources used by a menu item and its children. + * + * \param Item The menu item. + * + * \remarks The menu item is NOT automatically removed from its parent. It is safe to call this + * function while enumerating menu items. + */ +VOID PhpDestroyEMenuItem( + _In_ PPH_EMENU_ITEM Item + ) +{ + if (Item->DeleteFunction) + Item->DeleteFunction(Item); + + if ((Item->Flags & PH_EMENU_TEXT_OWNED) && Item->Text) + PhFree(Item->Text); + if ((Item->Flags & PH_EMENU_BITMAP_OWNED) && Item->Bitmap) + DeleteObject(Item->Bitmap); + + if (Item->Items) + { + ULONG i; + + for (i = 0; i < Item->Items->Count; i++) + { + PhpDestroyEMenuItem(Item->Items->Items[i]); + } + + PhDereferenceObject(Item->Items); + } + + PhFree(Item); +} + +/** + * Frees resources used by a menu item and its children. + * + * \param Item The menu item. + * + * \remarks The menu item is automatically removed from its parent. + */ +VOID PhDestroyEMenuItem( + _In_ PPH_EMENU_ITEM Item + ) +{ + // Remove the item from its parent, if it has one. + if (Item->Parent) + PhRemoveEMenuItem(NULL, Item, -1); + + PhpDestroyEMenuItem(Item); +} + +/** + * Finds a child menu item. + * + * \param Item The parent menu item. + * \param Flags A combination of the following: + * \li \c PH_EMENU_FIND_DESCEND Searches recursively within child menu items. + * \li \c PH_EMENU_FIND_STARTSWITH Performs a partial text search instead of an exact search. + * \li \c PH_EMENU_FIND_LITERAL Performs a literal search instead of ignoring prefix characters + * (ampersands). + * \param Text The text of the menu item to find. If NULL, the text is ignored. + * \param Id The identifier of the menu item to find. If 0, the identifier is ignored. + * + * \return The found menu item, or NULL if the menu item could not be found. + */ +PPH_EMENU_ITEM PhFindEMenuItem( + _In_ PPH_EMENU_ITEM Item, + _In_ ULONG Flags, + _In_opt_ PWSTR Text, + _In_opt_ ULONG Id + ) +{ + return PhFindEMenuItemEx(Item, Flags, Text, Id, NULL, NULL); +} + +/** + * Finds a child menu item. + * + * \param Item The parent menu item. + * \param Flags A combination of the following: + * \li \c PH_EMENU_FIND_DESCEND Searches recursively within child menu items. + * \li \c PH_EMENU_FIND_STARTSWITH Performs a partial text search instead of an exact search. + * \li \c PH_EMENU_FIND_LITERAL Performs a literal search instead of ignoring prefix characters + * (ampersands). + * \param Text The text of the menu item to find. If NULL, the text is ignored. + * \param Id The identifier of the menu item to find. If 0, the identifier is ignored. + * \param FoundParent A variable which receives the parent of the found menu item. + * \param FoundIndex A variable which receives the index of the found menu item. + * + * \return The found menu item, or NULL if the menu item could not be found. + */ +PPH_EMENU_ITEM PhFindEMenuItemEx( + _In_ PPH_EMENU_ITEM Item, + _In_ ULONG Flags, + _In_opt_ PWSTR Text, + _In_opt_ ULONG Id, + _Out_opt_ PPH_EMENU_ITEM *FoundParent, + _Out_opt_ PULONG FoundIndex + ) +{ + PH_STRINGREF searchText; + ULONG i; + PPH_EMENU_ITEM item; + + if (!Item->Items) + return NULL; + + if (Text && (Flags & PH_EMENU_FIND_LITERAL)) + PhInitializeStringRef(&searchText, Text); + + for (i = 0; i < Item->Items->Count; i++) + { + item = Item->Items->Items[i]; + + if (Text) + { + if (Flags & PH_EMENU_FIND_LITERAL) + { + PH_STRINGREF text; + + PhInitializeStringRef(&text, item->Text); + + if (Flags & PH_EMENU_FIND_STARTSWITH) + { + if (PhStartsWithStringRef(&text, &searchText, TRUE)) + goto FoundItemHere; + } + else + { + if (PhEqualStringRef(&text, &searchText, TRUE)) + goto FoundItemHere; + } + } + else + { + if (PhCompareUnicodeStringZIgnoreMenuPrefix(Text, item->Text, + TRUE, !!(Flags & PH_EMENU_FIND_STARTSWITH)) == 0) + goto FoundItemHere; + } + } + + if (Id && item->Id == Id) + goto FoundItemHere; + + if (Flags & PH_EMENU_FIND_DESCEND) + { + PPH_EMENU_ITEM foundItem; + PPH_EMENU_ITEM foundParent; + ULONG foundIndex; + + foundItem = PhFindEMenuItemEx(item, Flags, Text, Id, &foundParent, &foundIndex); + + if (foundItem) + { + if (FoundParent) + *FoundParent = foundParent; + if (FoundIndex) + *FoundIndex = foundIndex; + + return foundItem; + } + } + } + + return NULL; + +FoundItemHere: + if (FoundParent) + *FoundParent = Item; + if (FoundIndex) + *FoundIndex = i; + + return item; +} + +/** + * Determines the index of a menu item. + * + * \param Parent The parent menu item. + * \param Item The child menu item. + * + * \return The index of the menu item, or -1 if the menu item was not found in the parent menu item. + */ +ULONG PhIndexOfEMenuItem( + _In_ PPH_EMENU_ITEM Parent, + _In_ PPH_EMENU_ITEM Item + ) +{ + if (!Parent->Items) + return -1; + + return PhFindItemList(Parent->Items, Item); +} + +/** + * Inserts a menu item into a parent menu item. + * + * \param Parent The parent menu item. + * \param Item The menu item to insert. + * \param Index The index at which to insert the menu item. If the index is too large, the menu item + * is inserted at the last position. + */ +VOID PhInsertEMenuItem( + _Inout_ PPH_EMENU_ITEM Parent, + _Inout_ PPH_EMENU_ITEM Item, + _In_ ULONG Index + ) +{ + // Remove the item from its old parent if it has one. + if (Item->Parent) + PhRemoveEMenuItem(Item->Parent, Item, 0); + + if (!Parent->Items) + Parent->Items = PhCreateList(16); + + if (Index > Parent->Items->Count) + Index = Parent->Items->Count; + + if (Index == -1) + PhAddItemList(Parent->Items, Item); + else + PhInsertItemList(Parent->Items, Index, Item); + + Item->Parent = Parent; +} + +/** + * Removes a menu item from its parent. + * + * \param Parent The parent menu item. If \a Item is NULL, this parameter must be specified. + * \param Item The child menu item. This may be NULL if \a Index is specified. + * \param Index The index of the menu item to remove. If \a Item is specified, this parameter is + * ignored. + */ +BOOLEAN PhRemoveEMenuItem( + _Inout_opt_ PPH_EMENU_ITEM Parent, + _In_opt_ PPH_EMENU_ITEM Item, + _In_opt_ ULONG Index + ) +{ + if (Item) + { + if (!Parent) + Parent = Item->Parent; + if (!Parent->Items) + return FALSE; + + Index = PhFindItemList(Parent->Items, Item); + + if (Index == -1) + return FALSE; + } + else + { + if (!Parent) + return FALSE; + if (!Parent->Items) + return FALSE; + } + + Item = Parent->Items->Items[Index]; + PhRemoveItemList(Parent->Items, Index); + Item->Parent = NULL; + + return TRUE; +} + +/** + * Removes all children from a menu item. + * + * \param Parent The parent menu item. + */ +VOID PhRemoveAllEMenuItems( + _Inout_ PPH_EMENU_ITEM Parent + ) +{ + ULONG i; + + if (!Parent->Items) + return; + + for (i = 0; i < Parent->Items->Count; i++) + { + PhpDestroyEMenuItem(Parent->Items->Items[i]); + } + + PhClearList(Parent->Items); +} + +/** + * Creates a root menu. + */ +PPH_EMENU PhCreateEMenu( + VOID + ) +{ + PPH_EMENU menu; + + menu = PhAllocate(sizeof(PH_EMENU)); + memset(menu, 0, sizeof(PH_EMENU)); + menu->Items = PhCreateList(16); + + return menu; +} + +/** + * Frees resources used by a root menu and its children. + * + * \param Menu A root menu. + */ +VOID PhDestroyEMenu( + _In_ PPH_EMENU Menu + ) +{ + ULONG i; + + for (i = 0; i < Menu->Items->Count; i++) + { + PhpDestroyEMenuItem(Menu->Items->Items[i]); + } + + PhDereferenceObject(Menu->Items); + PhFree(Menu); +} + +/** + * Initializes a data structure containing additional information resulting from a call to + * PhEMenuToHMenu(). + */ +VOID PhInitializeEMenuData( + _Out_ PPH_EMENU_DATA Data + ) +{ + Data->IdToItem = PhCreateList(16); +} + +/** + * Frees resources used by a data structure initialized by PhInitializeEMenuData(). + */ +VOID PhDeleteEMenuData( + _Inout_ PPH_EMENU_DATA Data + ) +{ + PhDereferenceObject(Data->IdToItem); +} + +/** + * Converts an EMENU to a Windows menu object. + * + * \param Menu The menu item to convert. + * \param Flags A combination of the following: + * \li \c PH_EMENU_CONVERT_ID Automatically assigns a unique identifier to each converted menu item. + * The resulting mappings are placed in \a Data. + * \param Data Additional data resulting from the conversion. The data structure must be initialized + * by PhInitializeEMenuData() prior to calling this function. + * + * \return A menu handle. The menu object must be destroyed using DestroyMenu() when it is no longer + * needed. + */ +HMENU PhEMenuToHMenu( + _In_ PPH_EMENU_ITEM Menu, + _In_ ULONG Flags, + _Inout_opt_ PPH_EMENU_DATA Data + ) +{ + HMENU menuHandle; + + menuHandle = CreatePopupMenu(); + + if (!menuHandle) + return NULL; + + PhEMenuToHMenu2(menuHandle, Menu, Flags, Data); + + if (!(Menu->Flags & PH_EMENU_SEPARATECHECKSPACE)) + { + MENUINFO menuInfo; + + memset(&menuInfo, 0, sizeof(MENUINFO)); + menuInfo.cbSize = sizeof(MENUINFO); + menuInfo.fMask = MIM_STYLE; + menuInfo.dwStyle = MNS_CHECKORBMP; + SetMenuInfo(menuHandle, &menuInfo); + } + + return menuHandle; +} + +/** + * Converts an EMENU to a Windows menu object. + * + * \param MenuHandle A handle to a Windows menu object. + * \param Menu The menu item to convert. The items are appended to \a MenuHandle. + * \param Flags A combination of the following: + * \li \c PH_EMENU_CONVERT_ID Automatically assigns a unique identifier to each converted menu item. + * The resulting mappings are placed in \a Data. + * \param Data Additional data resulting from the conversion. The data structure must be initialized + * by PhInitializeEMenuData() prior to calling this function. + */ +VOID PhEMenuToHMenu2( + _In_ HMENU MenuHandle, + _In_ PPH_EMENU_ITEM Menu, + _In_ ULONG Flags, + _Inout_opt_ PPH_EMENU_DATA Data + ) +{ + ULONG i; + PPH_EMENU_ITEM item; + MENUITEMINFO menuItemInfo; + + for (i = 0; i < Menu->Items->Count; i++) + { + item = Menu->Items->Items[i]; + + memset(&menuItemInfo, 0, sizeof(MENUITEMINFO)); + menuItemInfo.cbSize = sizeof(MENUITEMINFO); + + // Type + + menuItemInfo.fMask = MIIM_FTYPE | MIIM_STATE; + + if (item->Flags & PH_EMENU_SEPARATOR) + { + menuItemInfo.fType = MFT_SEPARATOR; + } + else + { + menuItemInfo.fType = MFT_STRING; + menuItemInfo.fMask |= MIIM_STRING; + menuItemInfo.dwTypeData = item->Text; + } + + PhMapFlags1( + &menuItemInfo.fType, + item->Flags, + EMenuTypeMappings, + sizeof(EMenuTypeMappings) / sizeof(PH_FLAG_MAPPING) + ); + + // Bitmap + + if (item->Bitmap) + { + menuItemInfo.fMask |= MIIM_BITMAP; + menuItemInfo.hbmpItem = item->Bitmap; + } + + // Id + + if (Flags & PH_EMENU_CONVERT_ID) + { + ULONG id; + + if (Data) + { + PhAddItemList(Data->IdToItem, item); + id = Data->IdToItem->Count; + + menuItemInfo.fMask |= MIIM_ID; + menuItemInfo.wID = id; + } + } + else + { + if (item->Id) + { + menuItemInfo.fMask |= MIIM_ID; + menuItemInfo.wID = item->Id; + } + } + + // State + + PhMapFlags1( + &menuItemInfo.fState, + item->Flags, + EMenuStateMappings, + sizeof(EMenuStateMappings) / sizeof(PH_FLAG_MAPPING) + ); + + // Context + + menuItemInfo.fMask |= MIIM_DATA; + menuItemInfo.dwItemData = (ULONG_PTR)item; + + // Submenu + + if (item->Items && item->Items->Count != 0) + { + menuItemInfo.fMask |= MIIM_SUBMENU; + menuItemInfo.hSubMenu = PhEMenuToHMenu(item, Flags, Data); + } + + InsertMenuItem(MenuHandle, MAXINT, TRUE, &menuItemInfo); + } +} + +/** + * Converts a Windows menu object to an EMENU. + * + * \param MenuItem The menu item in which the converted menu items will be placed. + * \param MenuHandle A menu handle. + */ +VOID PhHMenuToEMenuItem( + _Inout_ PPH_EMENU_ITEM MenuItem, + _In_ HMENU MenuHandle + ) +{ + ULONG i; + ULONG count; + + count = GetMenuItemCount(MenuHandle); + + if (count != -1) + { + for (i = 0; i < count; i++) + { + MENUITEMINFO menuItemInfo; + WCHAR buffer[256]; + PPH_EMENU_ITEM menuItem; + + menuItemInfo.cbSize = sizeof(menuItemInfo); + menuItemInfo.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STATE | MIIM_STRING | MIIM_SUBMENU; + menuItemInfo.cch = sizeof(buffer) / sizeof(WCHAR); + menuItemInfo.dwTypeData = buffer; + + if (!GetMenuItemInfo(MenuHandle, i, TRUE, &menuItemInfo)) + continue; + + menuItem = PhCreateEMenuItem( + PH_EMENU_TEXT_OWNED, + menuItemInfo.wID, + PhDuplicateStringZ(buffer), + NULL, + NULL + ); + + if (menuItemInfo.fType & MFT_SEPARATOR) + menuItem->Flags |= PH_EMENU_SEPARATOR; + + PhMapFlags2( + &menuItem->Flags, + menuItemInfo.fType, + EMenuTypeMappings, + sizeof(EMenuTypeMappings) / sizeof(PH_FLAG_MAPPING) + ); + PhMapFlags2( + &menuItem->Flags, + menuItemInfo.fState, + EMenuStateMappings, + sizeof(EMenuStateMappings) / sizeof(PH_FLAG_MAPPING) + ); + + if (menuItemInfo.hSubMenu) + PhHMenuToEMenuItem(menuItem, menuItemInfo.hSubMenu); + + PhInsertEMenuItem(MenuItem, menuItem, -1); + } + } +} + +/** + * Loads a menu resource and converts it to an EMENU. + * + * \param MenuItem The menu item in which the converted menu items will be placed. + * \param InstanceHandle The module containing the menu resource. + * \param Resource The resource identifier. + * \param SubMenuIndex The index of the sub menu to use, or -1 to use the root menu. + */ +VOID PhLoadResourceEMenuItem( + _Inout_ PPH_EMENU_ITEM MenuItem, + _In_ HINSTANCE InstanceHandle, + _In_ PWSTR Resource, + _In_ ULONG SubMenuIndex + ) +{ + HMENU menu; + HMENU realMenu; + + menu = LoadMenu(InstanceHandle, Resource); + + if (SubMenuIndex != -1) + realMenu = GetSubMenu(menu, SubMenuIndex); + else + realMenu = menu; + + PhHMenuToEMenuItem(MenuItem, realMenu); + + DestroyMenu(menu); +} + +/** + * Displays a menu. + * + * \param Menu A menu. + * \param WindowHandle The window that owns the popup menu. + * \param Flags A combination of the following: + * \li \c PH_EMENU_SHOW_SEND_COMMAND A WM_COMMAND message is sent to the window when the user clicks + * on a menu item. + * \li \c PH_EMENU_SHOW_LEFTRIGHT The user can select menu items with both the left and right mouse + * buttons. + * \param Align The alignment of the menu. + * \param X The horizontal location of the menu. + * \param Y The vertical location of the menu. + * + * \return The selected menu item, or NULL if the menu was cancelled. + */ +PPH_EMENU_ITEM PhShowEMenu( + _In_ PPH_EMENU Menu, + _In_ HWND WindowHandle, + _In_ ULONG Flags, + _In_ ULONG Align, + _In_ ULONG X, + _In_ ULONG Y + ) +{ + PPH_EMENU_ITEM selectedItem; + ULONG result; + ULONG flags; + PH_EMENU_DATA data; + HMENU popupMenu; + + selectedItem = NULL; + flags = TPM_RETURNCMD | TPM_NONOTIFY; + + // Flags + + if (Flags & PH_EMENU_SHOW_LEFTRIGHT) + flags |= TPM_RIGHTBUTTON; + else + flags |= TPM_LEFTBUTTON; + + // Align + + if (Align & PH_ALIGN_LEFT) + flags |= TPM_LEFTALIGN; + else if (Align & PH_ALIGN_RIGHT) + flags |= TPM_RIGHTALIGN; + else + flags |= TPM_CENTERALIGN; + + if (Align & PH_ALIGN_TOP) + flags |= TPM_TOPALIGN; + else if (Align & PH_ALIGN_BOTTOM) + flags |= TPM_BOTTOMALIGN; + else + flags |= TPM_VCENTERALIGN; + + PhInitializeEMenuData(&data); + + if (popupMenu = PhEMenuToHMenu(Menu, PH_EMENU_CONVERT_ID, &data)) + { + result = TrackPopupMenu( + popupMenu, + flags, + X, + Y, + 0, + WindowHandle, + NULL + ); + + if (result != 0) + { + selectedItem = data.IdToItem->Items[result - 1]; + } + + DestroyMenu(popupMenu); + } + + PhDeleteEMenuData(&data); + + if ((Flags & PH_EMENU_SHOW_SEND_COMMAND) && selectedItem && selectedItem->Id != 0) + SendMessage(WindowHandle, WM_COMMAND, MAKEWPARAM(selectedItem->Id, 0), 0); + + return selectedItem; +} + +/** + * Sets the flags of a menu item. + * + * \param Item The parent menu item. + * \param Id The identifier of the child menu item. + * \param Mask The flags to modify. + * \param Value The new value of the flags. + */ +BOOLEAN PhSetFlagsEMenuItem( + _Inout_ PPH_EMENU_ITEM Item, + _In_ ULONG Id, + _In_ ULONG Mask, + _In_ ULONG Value + ) +{ + PPH_EMENU_ITEM item; + + item = PhFindEMenuItem(Item, PH_EMENU_FIND_DESCEND, NULL, Id); + + if (item) + { + item->Flags &= ~Mask; + item->Flags |= Value; + + return TRUE; + } + else + { + return FALSE; + } +} + +/** + * Sets flags for all children of a menu item. + * + * \param Item The parent menu item. + * \param Mask The flags to modify. + * \param Value The new value of the flags. + */ +VOID PhSetFlagsAllEMenuItems( + _In_ PPH_EMENU_ITEM Item, + _In_ ULONG Mask, + _In_ ULONG Value + ) +{ + ULONG i; + + for (i = 0; i < Item->Items->Count; i++) + { + PPH_EMENU_ITEM item = Item->Items->Items[i]; + + item->Flags &= ~Mask; + item->Flags |= Value; + } +} + +VOID PhModifyEMenuItem( + _Inout_ PPH_EMENU_ITEM Item, + _In_ ULONG ModifyFlags, + _In_ ULONG OwnedFlags, + _In_opt_ PWSTR Text, + _In_opt_ HBITMAP Bitmap + ) +{ + if (ModifyFlags & PH_EMENU_MODIFY_TEXT) + { + if ((Item->Flags & PH_EMENU_TEXT_OWNED) && Item->Text) + PhFree(Item->Text); + + Item->Text = Text; + Item->Flags &= ~PH_EMENU_TEXT_OWNED; + Item->Flags |= OwnedFlags & PH_EMENU_TEXT_OWNED; + } + + if (ModifyFlags & PH_EMENU_MODIFY_BITMAP) + { + if ((Item->Flags & PH_EMENU_BITMAP_OWNED) && Item->Bitmap) + DeleteObject(Item->Bitmap); + + Item->Bitmap = Bitmap; + Item->Flags &= ~PH_EMENU_BITMAP_OWNED; + Item->Flags |= OwnedFlags & PH_EMENU_BITMAP_OWNED; + } +} diff --git a/phlib/error.c b/phlib/error.c index 8c3f2373a917..b0c27c4e909e 100644 --- a/phlib/error.c +++ b/phlib/error.c @@ -1,92 +1,92 @@ -/* - * Process Hacker - - * error codes - * - * Copyright (C) 2010-2011 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include - -/** - * Converts a NTSTATUS value to a Win32 error code. - * - * \remarks This function handles FACILITY_NTWIN32 status values properly, unlike - * RtlNtStatusToDosError. - */ -ULONG PhNtStatusToDosError( - _In_ NTSTATUS Status - ) -{ - if (NT_NTWIN32(Status)) // RtlNtStatusToDosError doesn't seem to handle these cases correctly - return WIN32_FROM_NTSTATUS(Status); - else - return RtlNtStatusToDosError(Status); -} - -/** - * Converts a Win32 error code to a NTSTATUS value. - * - * \remarks Only a small number of cases are currently supported. Other status values are wrapped - * using FACILITY_NTWIN32. - */ -NTSTATUS PhDosErrorToNtStatus( - _In_ ULONG DosError - ) -{ - switch (DosError) - { - case ERROR_INVALID_FUNCTION: return STATUS_ILLEGAL_FUNCTION; - case ERROR_FILE_NOT_FOUND: return STATUS_NO_SUCH_FILE; - case ERROR_ACCESS_DENIED: return STATUS_ACCESS_DENIED; - case ERROR_INVALID_HANDLE: return STATUS_INVALID_HANDLE; - case ERROR_HANDLE_EOF: return STATUS_END_OF_FILE; - case ERROR_NOT_SUPPORTED: return STATUS_NOT_SUPPORTED; - case ERROR_INVALID_PARAMETER: return STATUS_INVALID_PARAMETER; - case ERROR_NOT_LOCKED: return STATUS_NOT_LOCKED; - case ERROR_MORE_DATA: return STATUS_MORE_ENTRIES; - case ERROR_NOACCESS: return STATUS_ACCESS_VIOLATION; - case ERROR_STACK_OVERFLOW: return STATUS_STACK_OVERFLOW; - case ERROR_INTERNAL_ERROR: return STATUS_INTERNAL_ERROR; - default: return NTSTATUS_FROM_WIN32(DosError); - } -} - -/** - * Determines whether a NTSTATUS value indicates that a file cannot be not found. - */ -BOOLEAN PhNtStatusFileNotFound( - _In_ NTSTATUS Status - ) -{ - switch (Status) - { - case STATUS_NO_SUCH_FILE: - return TRUE; - case STATUS_OBJECT_NAME_INVALID: - return TRUE; - case STATUS_OBJECT_NAME_NOT_FOUND: - return TRUE; - case STATUS_OBJECT_NO_LONGER_EXISTS: - return TRUE; - case STATUS_OBJECT_PATH_INVALID: - return TRUE; - case STATUS_OBJECT_PATH_NOT_FOUND: - return TRUE; - default: return FALSE; - } -} +/* + * Process Hacker - + * error codes + * + * Copyright (C) 2010-2011 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include + +/** + * Converts a NTSTATUS value to a Win32 error code. + * + * \remarks This function handles FACILITY_NTWIN32 status values properly, unlike + * RtlNtStatusToDosError. + */ +ULONG PhNtStatusToDosError( + _In_ NTSTATUS Status + ) +{ + if (NT_NTWIN32(Status)) // RtlNtStatusToDosError doesn't seem to handle these cases correctly + return WIN32_FROM_NTSTATUS(Status); + else + return RtlNtStatusToDosError(Status); +} + +/** + * Converts a Win32 error code to a NTSTATUS value. + * + * \remarks Only a small number of cases are currently supported. Other status values are wrapped + * using FACILITY_NTWIN32. + */ +NTSTATUS PhDosErrorToNtStatus( + _In_ ULONG DosError + ) +{ + switch (DosError) + { + case ERROR_INVALID_FUNCTION: return STATUS_ILLEGAL_FUNCTION; + case ERROR_FILE_NOT_FOUND: return STATUS_NO_SUCH_FILE; + case ERROR_ACCESS_DENIED: return STATUS_ACCESS_DENIED; + case ERROR_INVALID_HANDLE: return STATUS_INVALID_HANDLE; + case ERROR_HANDLE_EOF: return STATUS_END_OF_FILE; + case ERROR_NOT_SUPPORTED: return STATUS_NOT_SUPPORTED; + case ERROR_INVALID_PARAMETER: return STATUS_INVALID_PARAMETER; + case ERROR_NOT_LOCKED: return STATUS_NOT_LOCKED; + case ERROR_MORE_DATA: return STATUS_MORE_ENTRIES; + case ERROR_NOACCESS: return STATUS_ACCESS_VIOLATION; + case ERROR_STACK_OVERFLOW: return STATUS_STACK_OVERFLOW; + case ERROR_INTERNAL_ERROR: return STATUS_INTERNAL_ERROR; + default: return NTSTATUS_FROM_WIN32(DosError); + } +} + +/** + * Determines whether a NTSTATUS value indicates that a file cannot be not found. + */ +BOOLEAN PhNtStatusFileNotFound( + _In_ NTSTATUS Status + ) +{ + switch (Status) + { + case STATUS_NO_SUCH_FILE: + return TRUE; + case STATUS_OBJECT_NAME_INVALID: + return TRUE; + case STATUS_OBJECT_NAME_NOT_FOUND: + return TRUE; + case STATUS_OBJECT_NO_LONGER_EXISTS: + return TRUE; + case STATUS_OBJECT_PATH_INVALID: + return TRUE; + case STATUS_OBJECT_PATH_NOT_FOUND: + return TRUE; + default: return FALSE; + } +} diff --git a/phlib/extlv.c b/phlib/extlv.c index cb4c1654d951..4ab2b593390c 100644 --- a/phlib/extlv.c +++ b/phlib/extlv.c @@ -1,734 +1,734 @@ -/* - * Process Hacker - - * extended list view - * - * Copyright (C) 2010-2012 wj32 - * Copyright (C) 2017 dmex - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -/* - * The extended list view adds some functionality to the default list view control, such as sorting, - * item colors and fonts, better redraw disabling, and the ability to change the cursor. This is - * currently implemented by hooking the window procedure. - */ - -#include - -#include - -#include - -#define PH_MAX_COMPARE_FUNCTIONS 16 - -typedef struct _PH_EXTLV_CONTEXT -{ - HWND Handle; - PVOID Context; - - // Sorting - - BOOLEAN TriState; - ULONG SortColumn; - PH_SORT_ORDER SortOrder; - BOOLEAN SortFast; - - PPH_COMPARE_FUNCTION TriStateCompareFunction; - PPH_COMPARE_FUNCTION CompareFunctions[PH_MAX_COMPARE_FUNCTIONS]; - ULONG FallbackColumns[PH_MAX_COMPARE_FUNCTIONS]; - ULONG NumberOfFallbackColumns; - - // Color and Font - PPH_EXTLV_GET_ITEM_COLOR ItemColorFunction; - PPH_EXTLV_GET_ITEM_FONT ItemFontFunction; - - // Misc. - - LONG EnableRedraw; - HCURSOR Cursor; -} PH_EXTLV_CONTEXT, *PPH_EXTLV_CONTEXT; - -LRESULT CALLBACK PhpExtendedListViewWndProc( - _In_ HWND hwnd, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam, - _In_ UINT_PTR uIdSubclass, - _In_ ULONG_PTR dwRefData - ); - -INT PhpExtendedListViewCompareFunc( - _In_ LPARAM lParam1, - _In_ LPARAM lParam2, - _In_ LPARAM lParamSort - ); - -INT PhpExtendedListViewCompareFastFunc( - _In_ LPARAM lParam1, - _In_ LPARAM lParam2, - _In_ LPARAM lParamSort - ); - -INT PhpCompareListViewItems( - _In_ PPH_EXTLV_CONTEXT Context, - _In_ INT X, - _In_ INT Y, - _In_ PVOID XParam, - _In_ PVOID YParam, - _In_ ULONG Column, - _In_ BOOLEAN EnableDefault - ); - -INT PhpDefaultCompareListViewItems( - _In_ PPH_EXTLV_CONTEXT Context, - _In_ INT X, - _In_ INT Y, - _In_ ULONG Column - ); - -/** - * Enables extended list view support for a list view control. - * - * \param hWnd A handle to the list view control. - */ -VOID PhSetExtendedListView( - _In_ HWND hWnd - ) -{ - PPH_EXTLV_CONTEXT context; - - context = PhAllocate(sizeof(PH_EXTLV_CONTEXT)); - - context->Handle = hWnd; - context->Context = NULL; - context->TriState = FALSE; - context->SortColumn = 0; - context->SortOrder = AscendingSortOrder; - context->SortFast = FALSE; - context->TriStateCompareFunction = NULL; - memset(context->CompareFunctions, 0, sizeof(context->CompareFunctions)); - context->NumberOfFallbackColumns = 0; - - context->ItemColorFunction = NULL; - context->ItemFontFunction = NULL; - - context->EnableRedraw = 1; - context->Cursor = NULL; - - SetWindowSubclass(hWnd, PhpExtendedListViewWndProc, 0, (ULONG_PTR)context); - - ExtendedListView_Init(hWnd); -} - -LRESULT CALLBACK PhpExtendedListViewWndProc( - _In_ HWND hwnd, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam, - _In_ UINT_PTR uIdSubclass, - _In_ ULONG_PTR dwRefData - ) -{ - PPH_EXTLV_CONTEXT context = (PPH_EXTLV_CONTEXT)dwRefData; - - switch (uMsg) - { - case WM_DESTROY: - { - RemoveWindowSubclass(hwnd, PhpExtendedListViewWndProc, uIdSubclass); - - PhFree(context); - } - break; - case WM_NOTIFY: - { - LPNMHDR header = (LPNMHDR)lParam; - - switch (header->code) - { - case HDN_ITEMCLICK: - { - HWND headerHandle; - - headerHandle = (HWND)SendMessage(hwnd, LVM_GETHEADER, 0, 0); - - if (header->hwndFrom == headerHandle) - { - LPNMHEADER header2 = (LPNMHEADER)header; - - if (header2->iItem == context->SortColumn) - { - if (context->TriState) - { - if (context->SortOrder == AscendingSortOrder) - context->SortOrder = DescendingSortOrder; - else if (context->SortOrder == DescendingSortOrder) - context->SortOrder = NoSortOrder; - else - context->SortOrder = AscendingSortOrder; - } - else - { - if (context->SortOrder == AscendingSortOrder) - context->SortOrder = DescendingSortOrder; - else - context->SortOrder = AscendingSortOrder; - } - } - else - { - context->SortColumn = header2->iItem; - context->SortOrder = AscendingSortOrder; - } - - PhSetHeaderSortIcon(headerHandle, context->SortColumn, context->SortOrder); - ExtendedListView_SortItems(hwnd); - } - } - break; - } - } - break; - case WM_REFLECT + WM_NOTIFY: - { - LPNMHDR header = (LPNMHDR)lParam; - - switch (header->code) - { - case NM_CUSTOMDRAW: - { - if (header->hwndFrom == hwnd) - { - LPNMLVCUSTOMDRAW customDraw = (LPNMLVCUSTOMDRAW)header; - - switch (customDraw->nmcd.dwDrawStage) - { - case CDDS_PREPAINT: - return CDRF_NOTIFYITEMDRAW; - case CDDS_ITEMPREPAINT: - { - BOOLEAN colorChanged = FALSE; - HFONT newFont = NULL; - - if (context->ItemColorFunction) - { - customDraw->clrTextBk = context->ItemColorFunction( - (INT)customDraw->nmcd.dwItemSpec, - (PVOID)customDraw->nmcd.lItemlParam, - context->Context - ); - colorChanged = TRUE; - } - - if (context->ItemFontFunction) - { - newFont = context->ItemFontFunction( - (INT)customDraw->nmcd.dwItemSpec, - (PVOID)customDraw->nmcd.lItemlParam, - context->Context - ); - } - - if (newFont) - SelectObject(customDraw->nmcd.hdc, newFont); - - if (colorChanged) - { - if (PhGetColorBrightness(customDraw->clrTextBk) > 100) // slightly less than half - customDraw->clrText = RGB(0x00, 0x00, 0x00); - else - customDraw->clrText = RGB(0xff, 0xff, 0xff); - } - - if (!newFont) - return CDRF_DODEFAULT; - else - return CDRF_NEWFONT; - } - break; - } - } - } - break; - } - } - break; - case WM_SETCURSOR: - { - if (context->Cursor) - { - SetCursor(context->Cursor); - return TRUE; - } - } - break; - case WM_UPDATEUISTATE: - { - // Disable focus rectangles by setting or masking out the flag where appropriate. - switch (LOWORD(wParam)) - { - case UIS_SET: - wParam |= UISF_HIDEFOCUS << 16; - break; - case UIS_CLEAR: - case UIS_INITIALIZE: - wParam &= ~(UISF_HIDEFOCUS << 16); - break; - } - } - break; - case ELVM_ADDFALLBACKCOLUMN: - { - if (context->NumberOfFallbackColumns < PH_MAX_COMPARE_FUNCTIONS) - context->FallbackColumns[context->NumberOfFallbackColumns++] = (ULONG)wParam; - else - return FALSE; - } - return TRUE; - case ELVM_ADDFALLBACKCOLUMNS: - { - ULONG numberOfColumns = (ULONG)wParam; - PULONG columns = (PULONG)lParam; - - if (context->NumberOfFallbackColumns + numberOfColumns <= PH_MAX_COMPARE_FUNCTIONS) - { - memcpy( - &context->FallbackColumns[context->NumberOfFallbackColumns], - columns, - numberOfColumns * sizeof(ULONG) - ); - context->NumberOfFallbackColumns += numberOfColumns; - } - else - { - return FALSE; - } - } - return TRUE; - case ELVM_INIT: - { - PhSetHeaderSortIcon(ListView_GetHeader(hwnd), context->SortColumn, context->SortOrder); - - // HACK to fix tooltips showing behind Always On Top windows. - SetWindowPos(ListView_GetToolTips(hwnd), HWND_TOPMOST, 0, 0, 0, 0, - SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE); - - // Make sure focus rectangles are disabled. - SendMessage(hwnd, WM_CHANGEUISTATE, MAKELONG(UIS_SET, UISF_HIDEFOCUS), 0); - } - return TRUE; - case ELVM_SETCOLUMNWIDTH: - { - ULONG column = (ULONG)wParam; - LONG width = (LONG)lParam; - - if (width == ELVSCW_AUTOSIZE_REMAININGSPACE) - { - RECT clientRect; - LONG availableWidth; - ULONG i; - LVCOLUMN lvColumn; - - GetClientRect(hwnd, &clientRect); - availableWidth = clientRect.right; - i = 0; - lvColumn.mask = LVCF_WIDTH; - - while (TRUE) - { - if (i != column) - { - if (SendMessage(hwnd, LVM_GETCOLUMN, i, (LPARAM)&lvColumn)) - { - availableWidth -= lvColumn.cx; - } - else - { - break; - } - } - - i++; - } - - if (availableWidth >= 40) - return SendMessage(hwnd, LVM_SETCOLUMNWIDTH, column, availableWidth); - } - - return SendMessage(hwnd, LVM_SETCOLUMNWIDTH, column, width); - } - break; - case ELVM_SETCOMPAREFUNCTION: - { - ULONG column = (ULONG)wParam; - PPH_COMPARE_FUNCTION compareFunction = (PPH_COMPARE_FUNCTION)lParam; - - if (column >= PH_MAX_COMPARE_FUNCTIONS) - return FALSE; - - context->CompareFunctions[column] = compareFunction; - } - return TRUE; - case ELVM_SETCONTEXT: - { - context->Context = (PVOID)lParam; - } - return TRUE; - case ELVM_SETCURSOR: - { - context->Cursor = (HCURSOR)lParam; - } - return TRUE; - case ELVM_SETITEMCOLORFUNCTION: - { - context->ItemColorFunction = (PPH_EXTLV_GET_ITEM_COLOR)lParam; - } - return TRUE; - case ELVM_SETITEMFONTFUNCTION: - { - context->ItemFontFunction = (PPH_EXTLV_GET_ITEM_FONT)lParam; - } - return TRUE; - case ELVM_SETREDRAW: - { - if (wParam) - context->EnableRedraw++; - else - context->EnableRedraw--; - - if (context->EnableRedraw == 1) - { - SendMessage(hwnd, WM_SETREDRAW, TRUE, 0); - InvalidateRect(hwnd, NULL, FALSE); - } - else if (context->EnableRedraw == 0) - { - SendMessage(hwnd, WM_SETREDRAW, FALSE, 0); - } - } - return TRUE; - case ELVM_SETSORT: - { - context->SortColumn = (ULONG)wParam; - context->SortOrder = (PH_SORT_ORDER)lParam; - - PhSetHeaderSortIcon(ListView_GetHeader(hwnd), context->SortColumn, context->SortOrder); - } - return TRUE; - case ELVM_SETSORTFAST: - { - context->SortFast = !!wParam; - } - return TRUE; - case ELVM_SETTRISTATE: - { - context->TriState = !!wParam; - } - return TRUE; - case ELVM_SETTRISTATECOMPAREFUNCTION: - { - context->TriStateCompareFunction = (PPH_COMPARE_FUNCTION)lParam; - } - return TRUE; - case ELVM_SORTITEMS: - { - if (context->SortFast) - { - // This sort method is faster than the normal sort because our comparison function - // doesn't have to call the list view window procedure to get the item lParam - // values. The disadvantage of this method is that default sorting is not available - // - if a column doesn't have a comparison function, it doesn't get sorted at all. - - ListView_SortItems( - hwnd, - PhpExtendedListViewCompareFastFunc, - (LPARAM)context - ); - } - else - { - ListView_SortItemsEx( - hwnd, - PhpExtendedListViewCompareFunc, - (LPARAM)context - ); - } - } - return TRUE; - } - - return DefSubclassProc(hwnd, uMsg, wParam, lParam); -} - -/** - * Visually indicates the sort order of a header control item. - * - * \param hwnd A handle to the header control. - * \param Index The index of the item. - * \param Order The sort order of the item. - */ -VOID PhSetHeaderSortIcon( - _In_ HWND hwnd, - _In_ INT Index, - _In_ PH_SORT_ORDER Order - ) -{ - ULONG count; - ULONG i; - - count = Header_GetItemCount(hwnd); - - if (count == -1) - return; - - for (i = 0; i < count; i++) - { - HDITEM item; - - item.mask = HDI_FORMAT; - Header_GetItem(hwnd, i, &item); - - if (Order != NoSortOrder && i == Index) - { - if (Order == AscendingSortOrder) - { - item.fmt &= ~HDF_SORTDOWN; - item.fmt |= HDF_SORTUP; - } - else if (Order == DescendingSortOrder) - { - item.fmt &= ~HDF_SORTUP; - item.fmt |= HDF_SORTDOWN; - } - } - else - { - item.fmt &= ~(HDF_SORTDOWN | HDF_SORTUP); - } - - Header_SetItem(hwnd, i, &item); - } -} - -static INT PhpExtendedListViewCompareFunc( - _In_ LPARAM lParam1, - _In_ LPARAM lParam2, - _In_ LPARAM lParamSort - ) -{ - PPH_EXTLV_CONTEXT context = (PPH_EXTLV_CONTEXT)lParamSort; - INT result; - INT x = (INT)lParam1; - INT y = (INT)lParam2; - ULONG i; - PULONG fallbackColumns; - LVITEM xItem; - LVITEM yItem; - - // Get the param values. - - xItem.mask = LVIF_PARAM | LVIF_STATE; - xItem.iItem = x; - xItem.iSubItem = 0; - - yItem.mask = LVIF_PARAM | LVIF_STATE; - yItem.iItem = y; - yItem.iSubItem = 0; - - if (!SendMessage(context->Handle, LVM_GETITEM, 0, (LPARAM)&xItem)) - return 0; - if (!SendMessage(context->Handle, LVM_GETITEM, 0, (LPARAM)&yItem)) - return 0; - - // First, do tri-state sorting. - - if ( - context->TriState && - context->SortOrder == NoSortOrder && - context->TriStateCompareFunction - ) - { - result = context->TriStateCompareFunction( - (PVOID)xItem.lParam, - (PVOID)yItem.lParam, - context->Context - ); - - if (result != 0) - return result; - } - - // Compare using the user-selected column and move on to the fallback columns if necessary. - - result = PhpCompareListViewItems(context, x, y, (PVOID)xItem.lParam, (PVOID)yItem.lParam, context->SortColumn, TRUE); - - if (result != 0) - return result; - - fallbackColumns = context->FallbackColumns; - - for (i = context->NumberOfFallbackColumns; i != 0; i--) - { - ULONG fallbackColumn = *fallbackColumns++; - - if (fallbackColumn == context->SortColumn) - continue; - - result = PhpCompareListViewItems(context, x, y, (PVOID)xItem.lParam, (PVOID)yItem.lParam, fallbackColumn, TRUE); - - if (result != 0) - return result; - } - - return 0; -} - -static INT PhpExtendedListViewCompareFastFunc( - _In_ LPARAM lParam1, - _In_ LPARAM lParam2, - _In_ LPARAM lParamSort - ) -{ - PPH_EXTLV_CONTEXT context = (PPH_EXTLV_CONTEXT)lParamSort; - INT result; - ULONG i; - PULONG fallbackColumns; - - if (!lParam1 || !lParam2) - return 0; - - // First, do tri-state sorting. - - if ( - context->TriState && - context->SortOrder == NoSortOrder && - context->TriStateCompareFunction - ) - { - result = context->TriStateCompareFunction( - (PVOID)lParam1, - (PVOID)lParam2, - context->Context - ); - - if (result != 0) - return result; - } - - // Compare using the user-selected column and move on to the fallback columns if necessary. - - result = PhpCompareListViewItems(context, 0, 0, (PVOID)lParam1, (PVOID)lParam2, context->SortColumn, FALSE); - - if (result != 0) - return result; - - fallbackColumns = context->FallbackColumns; - - for (i = context->NumberOfFallbackColumns; i != 0; i--) - { - ULONG fallbackColumn = *fallbackColumns++; - - if (fallbackColumn == context->SortColumn) - continue; - - result = PhpCompareListViewItems(context, 0, 0, (PVOID)lParam1, (PVOID)lParam2, fallbackColumn, FALSE); - - if (result != 0) - return result; - } - - return 0; -} - -static FORCEINLINE INT PhpCompareListViewItems( - _In_ PPH_EXTLV_CONTEXT Context, - _In_ INT X, - _In_ INT Y, - _In_ PVOID XParam, - _In_ PVOID YParam, - _In_ ULONG Column, - _In_ BOOLEAN EnableDefault - ) -{ - INT result = 0; - - if ( - Column < PH_MAX_COMPARE_FUNCTIONS && - Context->CompareFunctions[Column] - ) - { - result = PhModifySort( - Context->CompareFunctions[Column](XParam, YParam, Context->Context), - Context->SortOrder - ); - - if (result != 0) - return result; - } - - if (EnableDefault) - { - return PhModifySort( - PhpDefaultCompareListViewItems(Context, X, Y, Column), - Context->SortOrder - ); - } - else - { - return 0; - } -} - -static INT PhpDefaultCompareListViewItems( - _In_ PPH_EXTLV_CONTEXT Context, - _In_ INT X, - _In_ INT Y, - _In_ ULONG Column - ) -{ - WCHAR xText[261]; - WCHAR yText[261]; - LVITEM item; - - // Get the X item text. - - item.mask = LVIF_TEXT; - item.iItem = X; - item.iSubItem = Column; - item.pszText = xText; - item.cchTextMax = 260; - - xText[0] = 0; - SendMessage(Context->Handle, LVM_GETITEM, 0, (LPARAM)&item); - - // Get the Y item text. - - item.iItem = Y; - item.pszText = yText; - item.cchTextMax = 260; - - yText[0] = 0; - SendMessage(Context->Handle, LVM_GETITEM, 0, (LPARAM)&item); - - // Compare them. - -#if 1 - return PhCompareStringZNatural(xText, yText, TRUE); -#else - return _wcsicmp(xText, yText); -#endif -} +/* + * Process Hacker - + * extended list view + * + * Copyright (C) 2010-2012 wj32 + * Copyright (C) 2017 dmex + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +/* + * The extended list view adds some functionality to the default list view control, such as sorting, + * item colors and fonts, better redraw disabling, and the ability to change the cursor. This is + * currently implemented by hooking the window procedure. + */ + +#include + +#include + +#include + +#define PH_MAX_COMPARE_FUNCTIONS 16 + +typedef struct _PH_EXTLV_CONTEXT +{ + HWND Handle; + PVOID Context; + + // Sorting + + BOOLEAN TriState; + ULONG SortColumn; + PH_SORT_ORDER SortOrder; + BOOLEAN SortFast; + + PPH_COMPARE_FUNCTION TriStateCompareFunction; + PPH_COMPARE_FUNCTION CompareFunctions[PH_MAX_COMPARE_FUNCTIONS]; + ULONG FallbackColumns[PH_MAX_COMPARE_FUNCTIONS]; + ULONG NumberOfFallbackColumns; + + // Color and Font + PPH_EXTLV_GET_ITEM_COLOR ItemColorFunction; + PPH_EXTLV_GET_ITEM_FONT ItemFontFunction; + + // Misc. + + LONG EnableRedraw; + HCURSOR Cursor; +} PH_EXTLV_CONTEXT, *PPH_EXTLV_CONTEXT; + +LRESULT CALLBACK PhpExtendedListViewWndProc( + _In_ HWND hwnd, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam, + _In_ UINT_PTR uIdSubclass, + _In_ ULONG_PTR dwRefData + ); + +INT PhpExtendedListViewCompareFunc( + _In_ LPARAM lParam1, + _In_ LPARAM lParam2, + _In_ LPARAM lParamSort + ); + +INT PhpExtendedListViewCompareFastFunc( + _In_ LPARAM lParam1, + _In_ LPARAM lParam2, + _In_ LPARAM lParamSort + ); + +INT PhpCompareListViewItems( + _In_ PPH_EXTLV_CONTEXT Context, + _In_ INT X, + _In_ INT Y, + _In_ PVOID XParam, + _In_ PVOID YParam, + _In_ ULONG Column, + _In_ BOOLEAN EnableDefault + ); + +INT PhpDefaultCompareListViewItems( + _In_ PPH_EXTLV_CONTEXT Context, + _In_ INT X, + _In_ INT Y, + _In_ ULONG Column + ); + +/** + * Enables extended list view support for a list view control. + * + * \param hWnd A handle to the list view control. + */ +VOID PhSetExtendedListView( + _In_ HWND hWnd + ) +{ + PPH_EXTLV_CONTEXT context; + + context = PhAllocate(sizeof(PH_EXTLV_CONTEXT)); + + context->Handle = hWnd; + context->Context = NULL; + context->TriState = FALSE; + context->SortColumn = 0; + context->SortOrder = AscendingSortOrder; + context->SortFast = FALSE; + context->TriStateCompareFunction = NULL; + memset(context->CompareFunctions, 0, sizeof(context->CompareFunctions)); + context->NumberOfFallbackColumns = 0; + + context->ItemColorFunction = NULL; + context->ItemFontFunction = NULL; + + context->EnableRedraw = 1; + context->Cursor = NULL; + + SetWindowSubclass(hWnd, PhpExtendedListViewWndProc, 0, (ULONG_PTR)context); + + ExtendedListView_Init(hWnd); +} + +LRESULT CALLBACK PhpExtendedListViewWndProc( + _In_ HWND hwnd, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam, + _In_ UINT_PTR uIdSubclass, + _In_ ULONG_PTR dwRefData + ) +{ + PPH_EXTLV_CONTEXT context = (PPH_EXTLV_CONTEXT)dwRefData; + + switch (uMsg) + { + case WM_DESTROY: + { + RemoveWindowSubclass(hwnd, PhpExtendedListViewWndProc, uIdSubclass); + + PhFree(context); + } + break; + case WM_NOTIFY: + { + LPNMHDR header = (LPNMHDR)lParam; + + switch (header->code) + { + case HDN_ITEMCLICK: + { + HWND headerHandle; + + headerHandle = (HWND)SendMessage(hwnd, LVM_GETHEADER, 0, 0); + + if (header->hwndFrom == headerHandle) + { + LPNMHEADER header2 = (LPNMHEADER)header; + + if (header2->iItem == context->SortColumn) + { + if (context->TriState) + { + if (context->SortOrder == AscendingSortOrder) + context->SortOrder = DescendingSortOrder; + else if (context->SortOrder == DescendingSortOrder) + context->SortOrder = NoSortOrder; + else + context->SortOrder = AscendingSortOrder; + } + else + { + if (context->SortOrder == AscendingSortOrder) + context->SortOrder = DescendingSortOrder; + else + context->SortOrder = AscendingSortOrder; + } + } + else + { + context->SortColumn = header2->iItem; + context->SortOrder = AscendingSortOrder; + } + + PhSetHeaderSortIcon(headerHandle, context->SortColumn, context->SortOrder); + ExtendedListView_SortItems(hwnd); + } + } + break; + } + } + break; + case WM_REFLECT + WM_NOTIFY: + { + LPNMHDR header = (LPNMHDR)lParam; + + switch (header->code) + { + case NM_CUSTOMDRAW: + { + if (header->hwndFrom == hwnd) + { + LPNMLVCUSTOMDRAW customDraw = (LPNMLVCUSTOMDRAW)header; + + switch (customDraw->nmcd.dwDrawStage) + { + case CDDS_PREPAINT: + return CDRF_NOTIFYITEMDRAW; + case CDDS_ITEMPREPAINT: + { + BOOLEAN colorChanged = FALSE; + HFONT newFont = NULL; + + if (context->ItemColorFunction) + { + customDraw->clrTextBk = context->ItemColorFunction( + (INT)customDraw->nmcd.dwItemSpec, + (PVOID)customDraw->nmcd.lItemlParam, + context->Context + ); + colorChanged = TRUE; + } + + if (context->ItemFontFunction) + { + newFont = context->ItemFontFunction( + (INT)customDraw->nmcd.dwItemSpec, + (PVOID)customDraw->nmcd.lItemlParam, + context->Context + ); + } + + if (newFont) + SelectObject(customDraw->nmcd.hdc, newFont); + + if (colorChanged) + { + if (PhGetColorBrightness(customDraw->clrTextBk) > 100) // slightly less than half + customDraw->clrText = RGB(0x00, 0x00, 0x00); + else + customDraw->clrText = RGB(0xff, 0xff, 0xff); + } + + if (!newFont) + return CDRF_DODEFAULT; + else + return CDRF_NEWFONT; + } + break; + } + } + } + break; + } + } + break; + case WM_SETCURSOR: + { + if (context->Cursor) + { + SetCursor(context->Cursor); + return TRUE; + } + } + break; + case WM_UPDATEUISTATE: + { + // Disable focus rectangles by setting or masking out the flag where appropriate. + switch (LOWORD(wParam)) + { + case UIS_SET: + wParam |= UISF_HIDEFOCUS << 16; + break; + case UIS_CLEAR: + case UIS_INITIALIZE: + wParam &= ~(UISF_HIDEFOCUS << 16); + break; + } + } + break; + case ELVM_ADDFALLBACKCOLUMN: + { + if (context->NumberOfFallbackColumns < PH_MAX_COMPARE_FUNCTIONS) + context->FallbackColumns[context->NumberOfFallbackColumns++] = (ULONG)wParam; + else + return FALSE; + } + return TRUE; + case ELVM_ADDFALLBACKCOLUMNS: + { + ULONG numberOfColumns = (ULONG)wParam; + PULONG columns = (PULONG)lParam; + + if (context->NumberOfFallbackColumns + numberOfColumns <= PH_MAX_COMPARE_FUNCTIONS) + { + memcpy( + &context->FallbackColumns[context->NumberOfFallbackColumns], + columns, + numberOfColumns * sizeof(ULONG) + ); + context->NumberOfFallbackColumns += numberOfColumns; + } + else + { + return FALSE; + } + } + return TRUE; + case ELVM_INIT: + { + PhSetHeaderSortIcon(ListView_GetHeader(hwnd), context->SortColumn, context->SortOrder); + + // HACK to fix tooltips showing behind Always On Top windows. + SetWindowPos(ListView_GetToolTips(hwnd), HWND_TOPMOST, 0, 0, 0, 0, + SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE); + + // Make sure focus rectangles are disabled. + SendMessage(hwnd, WM_CHANGEUISTATE, MAKELONG(UIS_SET, UISF_HIDEFOCUS), 0); + } + return TRUE; + case ELVM_SETCOLUMNWIDTH: + { + ULONG column = (ULONG)wParam; + LONG width = (LONG)lParam; + + if (width == ELVSCW_AUTOSIZE_REMAININGSPACE) + { + RECT clientRect; + LONG availableWidth; + ULONG i; + LVCOLUMN lvColumn; + + GetClientRect(hwnd, &clientRect); + availableWidth = clientRect.right; + i = 0; + lvColumn.mask = LVCF_WIDTH; + + while (TRUE) + { + if (i != column) + { + if (SendMessage(hwnd, LVM_GETCOLUMN, i, (LPARAM)&lvColumn)) + { + availableWidth -= lvColumn.cx; + } + else + { + break; + } + } + + i++; + } + + if (availableWidth >= 40) + return SendMessage(hwnd, LVM_SETCOLUMNWIDTH, column, availableWidth); + } + + return SendMessage(hwnd, LVM_SETCOLUMNWIDTH, column, width); + } + break; + case ELVM_SETCOMPAREFUNCTION: + { + ULONG column = (ULONG)wParam; + PPH_COMPARE_FUNCTION compareFunction = (PPH_COMPARE_FUNCTION)lParam; + + if (column >= PH_MAX_COMPARE_FUNCTIONS) + return FALSE; + + context->CompareFunctions[column] = compareFunction; + } + return TRUE; + case ELVM_SETCONTEXT: + { + context->Context = (PVOID)lParam; + } + return TRUE; + case ELVM_SETCURSOR: + { + context->Cursor = (HCURSOR)lParam; + } + return TRUE; + case ELVM_SETITEMCOLORFUNCTION: + { + context->ItemColorFunction = (PPH_EXTLV_GET_ITEM_COLOR)lParam; + } + return TRUE; + case ELVM_SETITEMFONTFUNCTION: + { + context->ItemFontFunction = (PPH_EXTLV_GET_ITEM_FONT)lParam; + } + return TRUE; + case ELVM_SETREDRAW: + { + if (wParam) + context->EnableRedraw++; + else + context->EnableRedraw--; + + if (context->EnableRedraw == 1) + { + SendMessage(hwnd, WM_SETREDRAW, TRUE, 0); + InvalidateRect(hwnd, NULL, FALSE); + } + else if (context->EnableRedraw == 0) + { + SendMessage(hwnd, WM_SETREDRAW, FALSE, 0); + } + } + return TRUE; + case ELVM_SETSORT: + { + context->SortColumn = (ULONG)wParam; + context->SortOrder = (PH_SORT_ORDER)lParam; + + PhSetHeaderSortIcon(ListView_GetHeader(hwnd), context->SortColumn, context->SortOrder); + } + return TRUE; + case ELVM_SETSORTFAST: + { + context->SortFast = !!wParam; + } + return TRUE; + case ELVM_SETTRISTATE: + { + context->TriState = !!wParam; + } + return TRUE; + case ELVM_SETTRISTATECOMPAREFUNCTION: + { + context->TriStateCompareFunction = (PPH_COMPARE_FUNCTION)lParam; + } + return TRUE; + case ELVM_SORTITEMS: + { + if (context->SortFast) + { + // This sort method is faster than the normal sort because our comparison function + // doesn't have to call the list view window procedure to get the item lParam + // values. The disadvantage of this method is that default sorting is not available + // - if a column doesn't have a comparison function, it doesn't get sorted at all. + + ListView_SortItems( + hwnd, + PhpExtendedListViewCompareFastFunc, + (LPARAM)context + ); + } + else + { + ListView_SortItemsEx( + hwnd, + PhpExtendedListViewCompareFunc, + (LPARAM)context + ); + } + } + return TRUE; + } + + return DefSubclassProc(hwnd, uMsg, wParam, lParam); +} + +/** + * Visually indicates the sort order of a header control item. + * + * \param hwnd A handle to the header control. + * \param Index The index of the item. + * \param Order The sort order of the item. + */ +VOID PhSetHeaderSortIcon( + _In_ HWND hwnd, + _In_ INT Index, + _In_ PH_SORT_ORDER Order + ) +{ + ULONG count; + ULONG i; + + count = Header_GetItemCount(hwnd); + + if (count == -1) + return; + + for (i = 0; i < count; i++) + { + HDITEM item; + + item.mask = HDI_FORMAT; + Header_GetItem(hwnd, i, &item); + + if (Order != NoSortOrder && i == Index) + { + if (Order == AscendingSortOrder) + { + item.fmt &= ~HDF_SORTDOWN; + item.fmt |= HDF_SORTUP; + } + else if (Order == DescendingSortOrder) + { + item.fmt &= ~HDF_SORTUP; + item.fmt |= HDF_SORTDOWN; + } + } + else + { + item.fmt &= ~(HDF_SORTDOWN | HDF_SORTUP); + } + + Header_SetItem(hwnd, i, &item); + } +} + +static INT PhpExtendedListViewCompareFunc( + _In_ LPARAM lParam1, + _In_ LPARAM lParam2, + _In_ LPARAM lParamSort + ) +{ + PPH_EXTLV_CONTEXT context = (PPH_EXTLV_CONTEXT)lParamSort; + INT result; + INT x = (INT)lParam1; + INT y = (INT)lParam2; + ULONG i; + PULONG fallbackColumns; + LVITEM xItem; + LVITEM yItem; + + // Get the param values. + + xItem.mask = LVIF_PARAM | LVIF_STATE; + xItem.iItem = x; + xItem.iSubItem = 0; + + yItem.mask = LVIF_PARAM | LVIF_STATE; + yItem.iItem = y; + yItem.iSubItem = 0; + + if (!SendMessage(context->Handle, LVM_GETITEM, 0, (LPARAM)&xItem)) + return 0; + if (!SendMessage(context->Handle, LVM_GETITEM, 0, (LPARAM)&yItem)) + return 0; + + // First, do tri-state sorting. + + if ( + context->TriState && + context->SortOrder == NoSortOrder && + context->TriStateCompareFunction + ) + { + result = context->TriStateCompareFunction( + (PVOID)xItem.lParam, + (PVOID)yItem.lParam, + context->Context + ); + + if (result != 0) + return result; + } + + // Compare using the user-selected column and move on to the fallback columns if necessary. + + result = PhpCompareListViewItems(context, x, y, (PVOID)xItem.lParam, (PVOID)yItem.lParam, context->SortColumn, TRUE); + + if (result != 0) + return result; + + fallbackColumns = context->FallbackColumns; + + for (i = context->NumberOfFallbackColumns; i != 0; i--) + { + ULONG fallbackColumn = *fallbackColumns++; + + if (fallbackColumn == context->SortColumn) + continue; + + result = PhpCompareListViewItems(context, x, y, (PVOID)xItem.lParam, (PVOID)yItem.lParam, fallbackColumn, TRUE); + + if (result != 0) + return result; + } + + return 0; +} + +static INT PhpExtendedListViewCompareFastFunc( + _In_ LPARAM lParam1, + _In_ LPARAM lParam2, + _In_ LPARAM lParamSort + ) +{ + PPH_EXTLV_CONTEXT context = (PPH_EXTLV_CONTEXT)lParamSort; + INT result; + ULONG i; + PULONG fallbackColumns; + + if (!lParam1 || !lParam2) + return 0; + + // First, do tri-state sorting. + + if ( + context->TriState && + context->SortOrder == NoSortOrder && + context->TriStateCompareFunction + ) + { + result = context->TriStateCompareFunction( + (PVOID)lParam1, + (PVOID)lParam2, + context->Context + ); + + if (result != 0) + return result; + } + + // Compare using the user-selected column and move on to the fallback columns if necessary. + + result = PhpCompareListViewItems(context, 0, 0, (PVOID)lParam1, (PVOID)lParam2, context->SortColumn, FALSE); + + if (result != 0) + return result; + + fallbackColumns = context->FallbackColumns; + + for (i = context->NumberOfFallbackColumns; i != 0; i--) + { + ULONG fallbackColumn = *fallbackColumns++; + + if (fallbackColumn == context->SortColumn) + continue; + + result = PhpCompareListViewItems(context, 0, 0, (PVOID)lParam1, (PVOID)lParam2, fallbackColumn, FALSE); + + if (result != 0) + return result; + } + + return 0; +} + +static FORCEINLINE INT PhpCompareListViewItems( + _In_ PPH_EXTLV_CONTEXT Context, + _In_ INT X, + _In_ INT Y, + _In_ PVOID XParam, + _In_ PVOID YParam, + _In_ ULONG Column, + _In_ BOOLEAN EnableDefault + ) +{ + INT result = 0; + + if ( + Column < PH_MAX_COMPARE_FUNCTIONS && + Context->CompareFunctions[Column] + ) + { + result = PhModifySort( + Context->CompareFunctions[Column](XParam, YParam, Context->Context), + Context->SortOrder + ); + + if (result != 0) + return result; + } + + if (EnableDefault) + { + return PhModifySort( + PhpDefaultCompareListViewItems(Context, X, Y, Column), + Context->SortOrder + ); + } + else + { + return 0; + } +} + +static INT PhpDefaultCompareListViewItems( + _In_ PPH_EXTLV_CONTEXT Context, + _In_ INT X, + _In_ INT Y, + _In_ ULONG Column + ) +{ + WCHAR xText[261]; + WCHAR yText[261]; + LVITEM item; + + // Get the X item text. + + item.mask = LVIF_TEXT; + item.iItem = X; + item.iSubItem = Column; + item.pszText = xText; + item.cchTextMax = 260; + + xText[0] = 0; + SendMessage(Context->Handle, LVM_GETITEM, 0, (LPARAM)&item); + + // Get the Y item text. + + item.iItem = Y; + item.pszText = yText; + item.cchTextMax = 260; + + yText[0] = 0; + SendMessage(Context->Handle, LVM_GETITEM, 0, (LPARAM)&item); + + // Compare them. + +#if 1 + return PhCompareStringZNatural(xText, yText, TRUE); +#else + return _wcsicmp(xText, yText); +#endif +} diff --git a/phlib/fastlock.c b/phlib/fastlock.c index f673ac2288d7..87b5db33a4ba 100644 --- a/phlib/fastlock.c +++ b/phlib/fastlock.c @@ -1,384 +1,384 @@ -/* - * Process Hacker - - * fast resource lock - * - * Copyright (C) 2009-2010 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include -#include - -// FastLock is a port of FastResourceLock from PH 1.x. -// -// The code contains no comments because it is a direct port. Please see FastResourceLock.cs in PH -// 1.x for details. - -// The fast lock is around 7% faster than the critical section when there is no contention, when -// used solely for mutual exclusion. It is also much smaller than the critical section. - -#define PH_LOCK_OWNED 0x1 -#define PH_LOCK_EXCLUSIVE_WAKING 0x2 - -#define PH_LOCK_SHARED_OWNERS_SHIFT 2 -#define PH_LOCK_SHARED_OWNERS_MASK 0x3ff -#define PH_LOCK_SHARED_OWNERS_INC 0x4 - -#define PH_LOCK_SHARED_WAITERS_SHIFT 12 -#define PH_LOCK_SHARED_WAITERS_MASK 0x3ff -#define PH_LOCK_SHARED_WAITERS_INC 0x1000 - -#define PH_LOCK_EXCLUSIVE_WAITERS_SHIFT 22 -#define PH_LOCK_EXCLUSIVE_WAITERS_MASK 0x3ff -#define PH_LOCK_EXCLUSIVE_WAITERS_INC 0x400000 - -#define PH_LOCK_EXCLUSIVE_MASK \ - (PH_LOCK_EXCLUSIVE_WAKING | \ - (PH_LOCK_EXCLUSIVE_WAITERS_MASK << PH_LOCK_EXCLUSIVE_WAITERS_SHIFT)) - -VOID PhInitializeFastLock( - _Out_ PPH_FAST_LOCK FastLock - ) -{ - FastLock->Value = 0; - FastLock->ExclusiveWakeEvent = NULL; - FastLock->SharedWakeEvent = NULL; -} - -VOID PhDeleteFastLock( - _Inout_ PPH_FAST_LOCK FastLock - ) -{ - if (FastLock->ExclusiveWakeEvent) - { - NtClose(FastLock->ExclusiveWakeEvent); - FastLock->ExclusiveWakeEvent = NULL; - } - - if (FastLock->SharedWakeEvent) - { - NtClose(FastLock->SharedWakeEvent); - FastLock->SharedWakeEvent = NULL; - } -} - -FORCEINLINE VOID PhpEnsureEventCreated( - _Inout_ PHANDLE Handle - ) -{ - HANDLE handle; - - if (*Handle != NULL) - return; - - NtCreateSemaphore(&handle, SEMAPHORE_ALL_ACCESS, NULL, 0, MAXLONG); - - if (_InterlockedCompareExchangePointer( - Handle, - handle, - NULL - ) != NULL) - { - NtClose(handle); - } -} - -FORCEINLINE ULONG PhpGetSpinCount( - VOID - ) -{ - if ((ULONG)PhSystemBasicInformation.NumberOfProcessors > 1) - return 4000; - else - return 0; -} - -_May_raise_ -_Acquires_exclusive_lock_(*FastLock) -VOID FASTCALL PhfAcquireFastLockExclusive( - _Inout_ PPH_FAST_LOCK FastLock - ) -{ - ULONG value; - ULONG i = 0; - ULONG spinCount; - - spinCount = PhpGetSpinCount(); - - while (TRUE) - { - value = FastLock->Value; - - if (!(value & (PH_LOCK_OWNED | PH_LOCK_EXCLUSIVE_WAKING))) - { - if (_InterlockedCompareExchange( - &FastLock->Value, - value + PH_LOCK_OWNED, - value - ) == value) - break; - } - else if (i >= spinCount) - { - PhpEnsureEventCreated(&FastLock->ExclusiveWakeEvent); - - if (_InterlockedCompareExchange( - &FastLock->Value, - value + PH_LOCK_EXCLUSIVE_WAITERS_INC, - value - ) == value) - { - if (NtWaitForSingleObject( - FastLock->ExclusiveWakeEvent, - FALSE, - NULL - ) != STATUS_WAIT_0) - PhRaiseStatus(STATUS_UNSUCCESSFUL); - - do - { - value = FastLock->Value; - } while (_InterlockedCompareExchange( - &FastLock->Value, - value + PH_LOCK_OWNED - PH_LOCK_EXCLUSIVE_WAKING, - value - ) != value); - - break; - } - } - - i++; - YieldProcessor(); - } -} - -_May_raise_ -_Acquires_shared_lock_(*FastLock) -VOID FASTCALL PhfAcquireFastLockShared( - _Inout_ PPH_FAST_LOCK FastLock - ) -{ - ULONG value; - ULONG i = 0; - ULONG spinCount; - - spinCount = PhpGetSpinCount(); - - while (TRUE) - { - value = FastLock->Value; - - if (!(value & ( - PH_LOCK_OWNED | - (PH_LOCK_SHARED_OWNERS_MASK << PH_LOCK_SHARED_OWNERS_SHIFT) | - PH_LOCK_EXCLUSIVE_MASK - ))) - { - if (_InterlockedCompareExchange( - &FastLock->Value, - value + PH_LOCK_OWNED + PH_LOCK_SHARED_OWNERS_INC, - value - ) == value) - break; - } - else if ( - (value & PH_LOCK_OWNED) && - ((value >> PH_LOCK_SHARED_OWNERS_SHIFT) & PH_LOCK_SHARED_OWNERS_MASK) > 0 && - !(value & PH_LOCK_EXCLUSIVE_MASK) - ) - { - if (_InterlockedCompareExchange( - &FastLock->Value, - value + PH_LOCK_SHARED_OWNERS_INC, - value - ) == value) - break; - } - else if (i >= spinCount) - { - PhpEnsureEventCreated(&FastLock->SharedWakeEvent); - - if (_InterlockedCompareExchange( - &FastLock->Value, - value + PH_LOCK_SHARED_WAITERS_INC, - value - ) == value) - { - if (NtWaitForSingleObject( - FastLock->SharedWakeEvent, - FALSE, - NULL - ) != STATUS_WAIT_0) - PhRaiseStatus(STATUS_UNSUCCESSFUL); - - continue; - } - } - - i++; - YieldProcessor(); - } -} - -_Releases_exclusive_lock_(*FastLock) -VOID FASTCALL PhfReleaseFastLockExclusive( - _Inout_ PPH_FAST_LOCK FastLock - ) -{ - ULONG value; - - while (TRUE) - { - value = FastLock->Value; - - if ((value >> PH_LOCK_EXCLUSIVE_WAITERS_SHIFT) & PH_LOCK_EXCLUSIVE_WAITERS_MASK) - { - if (_InterlockedCompareExchange( - &FastLock->Value, - value - PH_LOCK_OWNED + PH_LOCK_EXCLUSIVE_WAKING - PH_LOCK_EXCLUSIVE_WAITERS_INC, - value - ) == value) - { - NtReleaseSemaphore(FastLock->ExclusiveWakeEvent, 1, NULL); - - break; - } - } - else - { - ULONG sharedWaiters; - - sharedWaiters = (value >> PH_LOCK_SHARED_WAITERS_SHIFT) & PH_LOCK_SHARED_WAITERS_MASK; - - if (_InterlockedCompareExchange( - &FastLock->Value, - value & ~(PH_LOCK_OWNED | (PH_LOCK_SHARED_WAITERS_MASK << PH_LOCK_SHARED_WAITERS_SHIFT)), - value - ) == value) - { - if (sharedWaiters) - NtReleaseSemaphore(FastLock->SharedWakeEvent, sharedWaiters, 0); - - break; - } - } - - YieldProcessor(); - } -} - -_Releases_shared_lock_(*FastLock) -VOID FASTCALL PhfReleaseFastLockShared( - _Inout_ PPH_FAST_LOCK FastLock - ) -{ - ULONG value; - - while (TRUE) - { - value = FastLock->Value; - - if (((value >> PH_LOCK_SHARED_OWNERS_SHIFT) & PH_LOCK_SHARED_OWNERS_MASK) > 1) - { - if (_InterlockedCompareExchange( - &FastLock->Value, - value - PH_LOCK_SHARED_OWNERS_INC, - value - ) == value) - break; - } - else if ((value >> PH_LOCK_EXCLUSIVE_WAITERS_SHIFT) & PH_LOCK_EXCLUSIVE_WAITERS_MASK) - { - if (_InterlockedCompareExchange( - &FastLock->Value, - value - PH_LOCK_OWNED + PH_LOCK_EXCLUSIVE_WAKING - - PH_LOCK_SHARED_OWNERS_INC - PH_LOCK_EXCLUSIVE_WAITERS_INC, - value - ) == value) - { - NtReleaseSemaphore(FastLock->ExclusiveWakeEvent, 1, NULL); - - break; - } - } - else - { - if (_InterlockedCompareExchange( - &FastLock->Value, - value - PH_LOCK_OWNED - PH_LOCK_SHARED_OWNERS_INC, - value - ) == value) - break; - } - - YieldProcessor(); - } -} - -_When_(return != 0, _Acquires_exclusive_lock_(*FastLock)) -BOOLEAN FASTCALL PhfTryAcquireFastLockExclusive( - _Inout_ PPH_FAST_LOCK FastLock - ) -{ - ULONG value; - - value = FastLock->Value; - - if (value & (PH_LOCK_OWNED | PH_LOCK_EXCLUSIVE_WAKING)) - return FALSE; - - return _InterlockedCompareExchange( - &FastLock->Value, - value + PH_LOCK_OWNED, - value - ) == value; -} - -_When_(return != 0, _Acquires_shared_lock_(*FastLock)) -BOOLEAN FASTCALL PhfTryAcquireFastLockShared( - _Inout_ PPH_FAST_LOCK FastLock - ) -{ - ULONG value; - - value = FastLock->Value; - - if (value & PH_LOCK_EXCLUSIVE_MASK) - return FALSE; - - if (!(value & PH_LOCK_OWNED)) - { - return _InterlockedCompareExchange( - &FastLock->Value, - value + PH_LOCK_OWNED + PH_LOCK_SHARED_OWNERS_INC, - value - ) == value; - } - else if ((value >> PH_LOCK_SHARED_OWNERS_SHIFT) & PH_LOCK_SHARED_OWNERS_MASK) - { - return _InterlockedCompareExchange( - &FastLock->Value, - value + PH_LOCK_SHARED_OWNERS_INC, - value - ) == value; - } - else - { - return FALSE; - } -} +/* + * Process Hacker - + * fast resource lock + * + * Copyright (C) 2009-2010 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include +#include + +// FastLock is a port of FastResourceLock from PH 1.x. +// +// The code contains no comments because it is a direct port. Please see FastResourceLock.cs in PH +// 1.x for details. + +// The fast lock is around 7% faster than the critical section when there is no contention, when +// used solely for mutual exclusion. It is also much smaller than the critical section. + +#define PH_LOCK_OWNED 0x1 +#define PH_LOCK_EXCLUSIVE_WAKING 0x2 + +#define PH_LOCK_SHARED_OWNERS_SHIFT 2 +#define PH_LOCK_SHARED_OWNERS_MASK 0x3ff +#define PH_LOCK_SHARED_OWNERS_INC 0x4 + +#define PH_LOCK_SHARED_WAITERS_SHIFT 12 +#define PH_LOCK_SHARED_WAITERS_MASK 0x3ff +#define PH_LOCK_SHARED_WAITERS_INC 0x1000 + +#define PH_LOCK_EXCLUSIVE_WAITERS_SHIFT 22 +#define PH_LOCK_EXCLUSIVE_WAITERS_MASK 0x3ff +#define PH_LOCK_EXCLUSIVE_WAITERS_INC 0x400000 + +#define PH_LOCK_EXCLUSIVE_MASK \ + (PH_LOCK_EXCLUSIVE_WAKING | \ + (PH_LOCK_EXCLUSIVE_WAITERS_MASK << PH_LOCK_EXCLUSIVE_WAITERS_SHIFT)) + +VOID PhInitializeFastLock( + _Out_ PPH_FAST_LOCK FastLock + ) +{ + FastLock->Value = 0; + FastLock->ExclusiveWakeEvent = NULL; + FastLock->SharedWakeEvent = NULL; +} + +VOID PhDeleteFastLock( + _Inout_ PPH_FAST_LOCK FastLock + ) +{ + if (FastLock->ExclusiveWakeEvent) + { + NtClose(FastLock->ExclusiveWakeEvent); + FastLock->ExclusiveWakeEvent = NULL; + } + + if (FastLock->SharedWakeEvent) + { + NtClose(FastLock->SharedWakeEvent); + FastLock->SharedWakeEvent = NULL; + } +} + +FORCEINLINE VOID PhpEnsureEventCreated( + _Inout_ PHANDLE Handle + ) +{ + HANDLE handle; + + if (*Handle != NULL) + return; + + NtCreateSemaphore(&handle, SEMAPHORE_ALL_ACCESS, NULL, 0, MAXLONG); + + if (_InterlockedCompareExchangePointer( + Handle, + handle, + NULL + ) != NULL) + { + NtClose(handle); + } +} + +FORCEINLINE ULONG PhpGetSpinCount( + VOID + ) +{ + if ((ULONG)PhSystemBasicInformation.NumberOfProcessors > 1) + return 4000; + else + return 0; +} + +_May_raise_ +_Acquires_exclusive_lock_(*FastLock) +VOID FASTCALL PhfAcquireFastLockExclusive( + _Inout_ PPH_FAST_LOCK FastLock + ) +{ + ULONG value; + ULONG i = 0; + ULONG spinCount; + + spinCount = PhpGetSpinCount(); + + while (TRUE) + { + value = FastLock->Value; + + if (!(value & (PH_LOCK_OWNED | PH_LOCK_EXCLUSIVE_WAKING))) + { + if (_InterlockedCompareExchange( + &FastLock->Value, + value + PH_LOCK_OWNED, + value + ) == value) + break; + } + else if (i >= spinCount) + { + PhpEnsureEventCreated(&FastLock->ExclusiveWakeEvent); + + if (_InterlockedCompareExchange( + &FastLock->Value, + value + PH_LOCK_EXCLUSIVE_WAITERS_INC, + value + ) == value) + { + if (NtWaitForSingleObject( + FastLock->ExclusiveWakeEvent, + FALSE, + NULL + ) != STATUS_WAIT_0) + PhRaiseStatus(STATUS_UNSUCCESSFUL); + + do + { + value = FastLock->Value; + } while (_InterlockedCompareExchange( + &FastLock->Value, + value + PH_LOCK_OWNED - PH_LOCK_EXCLUSIVE_WAKING, + value + ) != value); + + break; + } + } + + i++; + YieldProcessor(); + } +} + +_May_raise_ +_Acquires_shared_lock_(*FastLock) +VOID FASTCALL PhfAcquireFastLockShared( + _Inout_ PPH_FAST_LOCK FastLock + ) +{ + ULONG value; + ULONG i = 0; + ULONG spinCount; + + spinCount = PhpGetSpinCount(); + + while (TRUE) + { + value = FastLock->Value; + + if (!(value & ( + PH_LOCK_OWNED | + (PH_LOCK_SHARED_OWNERS_MASK << PH_LOCK_SHARED_OWNERS_SHIFT) | + PH_LOCK_EXCLUSIVE_MASK + ))) + { + if (_InterlockedCompareExchange( + &FastLock->Value, + value + PH_LOCK_OWNED + PH_LOCK_SHARED_OWNERS_INC, + value + ) == value) + break; + } + else if ( + (value & PH_LOCK_OWNED) && + ((value >> PH_LOCK_SHARED_OWNERS_SHIFT) & PH_LOCK_SHARED_OWNERS_MASK) > 0 && + !(value & PH_LOCK_EXCLUSIVE_MASK) + ) + { + if (_InterlockedCompareExchange( + &FastLock->Value, + value + PH_LOCK_SHARED_OWNERS_INC, + value + ) == value) + break; + } + else if (i >= spinCount) + { + PhpEnsureEventCreated(&FastLock->SharedWakeEvent); + + if (_InterlockedCompareExchange( + &FastLock->Value, + value + PH_LOCK_SHARED_WAITERS_INC, + value + ) == value) + { + if (NtWaitForSingleObject( + FastLock->SharedWakeEvent, + FALSE, + NULL + ) != STATUS_WAIT_0) + PhRaiseStatus(STATUS_UNSUCCESSFUL); + + continue; + } + } + + i++; + YieldProcessor(); + } +} + +_Releases_exclusive_lock_(*FastLock) +VOID FASTCALL PhfReleaseFastLockExclusive( + _Inout_ PPH_FAST_LOCK FastLock + ) +{ + ULONG value; + + while (TRUE) + { + value = FastLock->Value; + + if ((value >> PH_LOCK_EXCLUSIVE_WAITERS_SHIFT) & PH_LOCK_EXCLUSIVE_WAITERS_MASK) + { + if (_InterlockedCompareExchange( + &FastLock->Value, + value - PH_LOCK_OWNED + PH_LOCK_EXCLUSIVE_WAKING - PH_LOCK_EXCLUSIVE_WAITERS_INC, + value + ) == value) + { + NtReleaseSemaphore(FastLock->ExclusiveWakeEvent, 1, NULL); + + break; + } + } + else + { + ULONG sharedWaiters; + + sharedWaiters = (value >> PH_LOCK_SHARED_WAITERS_SHIFT) & PH_LOCK_SHARED_WAITERS_MASK; + + if (_InterlockedCompareExchange( + &FastLock->Value, + value & ~(PH_LOCK_OWNED | (PH_LOCK_SHARED_WAITERS_MASK << PH_LOCK_SHARED_WAITERS_SHIFT)), + value + ) == value) + { + if (sharedWaiters) + NtReleaseSemaphore(FastLock->SharedWakeEvent, sharedWaiters, 0); + + break; + } + } + + YieldProcessor(); + } +} + +_Releases_shared_lock_(*FastLock) +VOID FASTCALL PhfReleaseFastLockShared( + _Inout_ PPH_FAST_LOCK FastLock + ) +{ + ULONG value; + + while (TRUE) + { + value = FastLock->Value; + + if (((value >> PH_LOCK_SHARED_OWNERS_SHIFT) & PH_LOCK_SHARED_OWNERS_MASK) > 1) + { + if (_InterlockedCompareExchange( + &FastLock->Value, + value - PH_LOCK_SHARED_OWNERS_INC, + value + ) == value) + break; + } + else if ((value >> PH_LOCK_EXCLUSIVE_WAITERS_SHIFT) & PH_LOCK_EXCLUSIVE_WAITERS_MASK) + { + if (_InterlockedCompareExchange( + &FastLock->Value, + value - PH_LOCK_OWNED + PH_LOCK_EXCLUSIVE_WAKING - + PH_LOCK_SHARED_OWNERS_INC - PH_LOCK_EXCLUSIVE_WAITERS_INC, + value + ) == value) + { + NtReleaseSemaphore(FastLock->ExclusiveWakeEvent, 1, NULL); + + break; + } + } + else + { + if (_InterlockedCompareExchange( + &FastLock->Value, + value - PH_LOCK_OWNED - PH_LOCK_SHARED_OWNERS_INC, + value + ) == value) + break; + } + + YieldProcessor(); + } +} + +_When_(return != 0, _Acquires_exclusive_lock_(*FastLock)) +BOOLEAN FASTCALL PhfTryAcquireFastLockExclusive( + _Inout_ PPH_FAST_LOCK FastLock + ) +{ + ULONG value; + + value = FastLock->Value; + + if (value & (PH_LOCK_OWNED | PH_LOCK_EXCLUSIVE_WAKING)) + return FALSE; + + return _InterlockedCompareExchange( + &FastLock->Value, + value + PH_LOCK_OWNED, + value + ) == value; +} + +_When_(return != 0, _Acquires_shared_lock_(*FastLock)) +BOOLEAN FASTCALL PhfTryAcquireFastLockShared( + _Inout_ PPH_FAST_LOCK FastLock + ) +{ + ULONG value; + + value = FastLock->Value; + + if (value & PH_LOCK_EXCLUSIVE_MASK) + return FALSE; + + if (!(value & PH_LOCK_OWNED)) + { + return _InterlockedCompareExchange( + &FastLock->Value, + value + PH_LOCK_OWNED + PH_LOCK_SHARED_OWNERS_INC, + value + ) == value; + } + else if ((value >> PH_LOCK_SHARED_OWNERS_SHIFT) & PH_LOCK_SHARED_OWNERS_MASK) + { + return _InterlockedCompareExchange( + &FastLock->Value, + value + PH_LOCK_SHARED_OWNERS_INC, + value + ) == value; + } + else + { + return FALSE; + } +} diff --git a/phlib/filepool.c b/phlib/filepool.c index 3d9e95ca6fe1..9b76e6fa44a2 100644 --- a/phlib/filepool.c +++ b/phlib/filepool.c @@ -1,1511 +1,1511 @@ -/* - * Process Hacker - - * file-based allocator - * - * Copyright (C) 2011 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -/* - * File pool allows blocks of storage to be allocated from a file. Each file looks like this: - * - * Segment 0 __________________________________________________________ - * | | | | | - * | Block Header | File Header | Block Header | Segment Header | - * |______________|________________|______________|________________| - * | | | | | - * | Block Header | User Data | Block Header | User Data | - * |______________|________________|______________|________________| - * | | | | | - * | ... | ... | ... | ... | - * |______________|________________|______________|________________| - * Segment 1 __________________________________________________________ - * | | | | | - * | Block Header | Segment Header | Block Header | User Data | - * |______________|________________|______________|________________| - * | | | | | - * | ... | ... | ... | ... | - * |______________|________________|______________|________________| - * Segment 2 __________________________________________________________ - * | | | | | - * | ... | ... | ... | ... | - * |______________|________________|______________|________________| - * - */ - -/* - * A file consists of a variable number of segments, with the segment size specified as a power of - * two. Each segment contains a fixed number of blocks, leading to a variable block size. Every - * allocation made by the user is an allocation of a certain number of blocks, with enough space for - * the block header. This is placed at the beginning of each allocation and contains the number of - * blocks in the allocation (a better name for it would be the allocation header). - * - * Block management in each segment is handled by a bitmap which is stored in the segment header at - * the beginning of each segment. The first segment (segment 0) is special with the file header - * being placed immediately after an initial block header. This is because the segment size is - * stored in the file header, and without it we cannot calculate the block size, which is used to - * locate everything else in the file. - * - * To speed up allocations a number of free lists are maintained which categorize each segment based - * on how many free blocks they have. This means we can avoid trying to allocate from every existing - * segment before finding out we have to allocate a new segment, or trying to allocate from segments - * without the required number of free blocks. The downside of this technique is that it doesn't - * account for fragmentation within the allocation bitmap. - * - * Each segment is mapped in separately, and each view is cached. Even after a view becomes inactive - * (has a reference count of 0) it remains mapped in until the maximum number of inactive views is - * reached. - */ - -#include -#include - -#include - -/** - * Creates or opens a file pool. - * - * \param Pool A variable which receives the file pool instance. - * \param FileHandle A handle to the file. - * \param ReadOnly TRUE to disallow writes to the file. - * \param Parameters Parameters for on-disk and runtime structures. - */ -NTSTATUS PhCreateFilePool( - _Out_ PPH_FILE_POOL *Pool, - _In_ HANDLE FileHandle, - _In_ BOOLEAN ReadOnly, - _In_opt_ PPH_FILE_POOL_PARAMETERS Parameters - ) -{ - NTSTATUS status; - PPH_FILE_POOL pool; - LARGE_INTEGER fileSize; - PH_FILE_POOL_PARAMETERS localParameters; - BOOLEAN creating; - HANDLE sectionHandle; - PPH_FP_BLOCK_HEADER initialBlock; - PPH_FP_FILE_HEADER header; - ULONG i; - - if (Parameters) - { - PhpValidateFilePoolParameters(Parameters); - } - else - { - PhpSetDefaultFilePoolParameters(&localParameters); - Parameters = &localParameters; - } - - pool = PhAllocate(sizeof(PH_FILE_POOL)); - memset(pool, 0, sizeof(PH_FILE_POOL)); - - pool->FileHandle = FileHandle; - pool->ReadOnly = ReadOnly; - - if (!NT_SUCCESS(status = PhGetFileSize(FileHandle, &fileSize))) - goto CleanupExit; - - creating = FALSE; - - // If the file is smaller than the page size, assume we're creating a new file. - if (fileSize.QuadPart < PAGE_SIZE) - { - if (ReadOnly) - { - status = STATUS_BAD_FILE_TYPE; - goto CleanupExit; - } - - fileSize.QuadPart = PAGE_SIZE; - - if (!NT_SUCCESS(status = PhSetFileSize(FileHandle, &fileSize))) - goto CleanupExit; - - creating = TRUE; - } - - // Create a section. - status = NtCreateSection( - §ionHandle, - SECTION_ALL_ACCESS, - NULL, - &fileSize, - !ReadOnly ? PAGE_READWRITE : PAGE_READONLY, - SEC_COMMIT, - FileHandle - ); - - if (!NT_SUCCESS(status)) - goto CleanupExit; - - pool->SectionHandle = sectionHandle; - - // Map in the first segment, set up initial parameters, then remap the first segment. - - if (!NT_SUCCESS(status = PhFppMapRange(pool, 0, PAGE_SIZE, &initialBlock))) - goto CleanupExit; - - header = (PPH_FP_FILE_HEADER)&initialBlock->Body; - - if (creating) - { - header->Magic = PH_FP_MAGIC; - header->SegmentShift = Parameters->SegmentShift; - header->SegmentCount = 1; - - for (i = 0; i < PH_FP_FREE_LIST_COUNT; i++) - header->FreeLists[i] = -1; - } - else - { - if (header->Magic != PH_FP_MAGIC) - { - PhFppUnmapRange(pool, initialBlock); - status = STATUS_BAD_FILE_TYPE; - goto CleanupExit; - } - } - - pool->SegmentShift = header->SegmentShift; - pool->SegmentSize = 1 << pool->SegmentShift; - - pool->BlockShift = pool->SegmentShift - PH_FP_BLOCK_COUNT_SHIFT; - pool->BlockSize = 1 << pool->BlockShift; - pool->FileHeaderBlockSpan = (sizeof(PH_FP_FILE_HEADER) + pool->BlockSize - 1) >> pool->BlockShift; - pool->SegmentHeaderBlockSpan = (sizeof(PH_FP_SEGMENT_HEADER) + pool->BlockSize - 1) >> pool->BlockShift; - - // Unmap the first segment and remap with the new segment size. - - PhFppUnmapRange(pool, initialBlock); - - if (creating) - { - // Extend the section so it fits the entire first segment. - if (!NT_SUCCESS(status = PhFppExtendRange(pool, pool->SegmentSize))) - goto CleanupExit; - } - - // Runtime structure initialization - - PhInitializeFreeList(&pool->ViewFreeList, sizeof(PH_FILE_POOL_VIEW), 32); - pool->ByIndexSize = 32; - pool->ByIndexBuckets = PhAllocate(sizeof(PPH_FILE_POOL_VIEW) * pool->ByIndexSize); - memset(pool->ByIndexBuckets, 0, sizeof(PPH_FILE_POOL_VIEW) * pool->ByIndexSize); - PhInitializeAvlTree(&pool->ByBaseSet, PhpFilePoolViewByBaseCompareFunction); - - pool->MaximumInactiveViews = Parameters->MaximumInactiveViews; - InitializeListHead(&pool->InactiveViewsListHead); - - // File structure initialization - - pool->FirstBlockOfFirstSegment = PhFppReferenceSegment(pool, 0); - pool->Header = (PPH_FP_FILE_HEADER)&pool->FirstBlockOfFirstSegment->Body; - - if (creating) - { - PPH_FP_BLOCK_HEADER segmentHeaderBlock; - - // Set up the first segment properly. - - pool->FirstBlockOfFirstSegment->Span = pool->FileHeaderBlockSpan; - segmentHeaderBlock = (PPH_FP_BLOCK_HEADER)((PCHAR)pool->FirstBlockOfFirstSegment + (pool->FileHeaderBlockSpan << pool->BlockShift)); - PhFppInitializeSegment(pool, segmentHeaderBlock, pool->FileHeaderBlockSpan); - - pool->Header->FreeLists[1] = 0; - } - -CleanupExit: - if (NT_SUCCESS(status)) - { - *Pool = pool; - } - else - { - // Don't close the file handle the user passed in. - pool->FileHandle = NULL; - PhDestroyFilePool(pool); - } - - return status; -} - -/** - * Creates or opens a file pool. - * - * \param Pool A variable which receives the file pool instance. - * \param FileName The file name of the file pool. - * \param ReadOnly TRUE to disallow writes to the file. - * \param ShareAccess The file access granted to other threads. - * \param CreateDisposition The action to perform if the file does or does not exist. See - * PhCreateFileWin32() for more information. - * \param Parameters Parameters for on-disk and runtime structures. - */ -NTSTATUS PhCreateFilePool2( - _Out_ PPH_FILE_POOL *Pool, - _In_ PWSTR FileName, - _In_ BOOLEAN ReadOnly, - _In_ ULONG ShareAccess, - _In_ ULONG CreateDisposition, - _In_opt_ PPH_FILE_POOL_PARAMETERS Parameters - ) -{ - NTSTATUS status; - PPH_FILE_POOL pool; - HANDLE fileHandle; - ULONG createStatus; - - if (!NT_SUCCESS(status = PhCreateFileWin32Ex( - &fileHandle, - FileName, - !ReadOnly ? (FILE_GENERIC_READ | FILE_GENERIC_WRITE | DELETE) : FILE_GENERIC_READ, - FILE_ATTRIBUTE_NORMAL, - ShareAccess, - CreateDisposition, - FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, - &createStatus - ))) - { - return status; - } - - status = PhCreateFilePool(&pool, fileHandle, ReadOnly, Parameters); - - if (NT_SUCCESS(status)) - { - *Pool = pool; - } - else - { - if (!ReadOnly && createStatus == FILE_CREATED) - { - FILE_DISPOSITION_INFORMATION dispositionInfo; - IO_STATUS_BLOCK isb; - - dispositionInfo.DeleteFile = TRUE; - NtSetInformationFile(fileHandle, &isb, &dispositionInfo, sizeof(FILE_DISPOSITION_INFORMATION), FileDispositionInformation); - } - - NtClose(fileHandle); - } - - return status; -} - -/** - * Frees resources used by a file pool instance. - * - * \param Pool The file pool. - */ -VOID PhDestroyFilePool( - _In_ _Post_invalid_ PPH_FILE_POOL Pool - ) -{ - ULONG i; - PLIST_ENTRY head; - PLIST_ENTRY entry; - PPH_FILE_POOL_VIEW view; - - // Unmap all views. - for (i = 0; i < Pool->ByIndexSize; i++) - { - if (head = Pool->ByIndexBuckets[i]) - { - entry = head; - - do - { - view = CONTAINING_RECORD(entry, PH_FILE_POOL_VIEW, ByIndexListEntry); - entry = entry->Flink; - PhFppUnmapRange(Pool, view->Base); - PhFreeToFreeList(&Pool->ViewFreeList, view); - } while (entry != head); - } - } - - if (Pool->ByIndexBuckets) - PhFree(Pool->ByIndexBuckets); - - PhDeleteFreeList(&Pool->ViewFreeList); - - if (Pool->SectionHandle) - NtClose(Pool->SectionHandle); - if (Pool->FileHandle) - NtClose(Pool->FileHandle); - - PhFree(Pool); -} - -/** - * Validates and corrects file pool parameters. - * - * \param Parameters The parameters structure which is validated and modified if necessary. - */ -NTSTATUS PhpValidateFilePoolParameters( - _Inout_ PPH_FILE_POOL_PARAMETERS Parameters - ) -{ - NTSTATUS status = STATUS_SUCCESS; - - // 16 <= SegmentShift <= 28 - - if (Parameters->SegmentShift < 16) - { - Parameters->SegmentShift = 16; - status = STATUS_SOME_NOT_MAPPED; - } - - if (Parameters->SegmentShift > 28) - { - Parameters->SegmentShift = 28; - status = STATUS_SOME_NOT_MAPPED; - } - - return status; -} - -/** - * Creates default file pool parameters. - * - * \param Parameters The parameters structure which receives the default parameter values. - */ -VOID PhpSetDefaultFilePoolParameters( - _Out_ PPH_FILE_POOL_PARAMETERS Parameters - ) -{ - Parameters->SegmentShift = 18; // 256kB - Parameters->MaximumInactiveViews = 128; -} - -/** - * Allocates a block from a file pool. - * - * \param Pool The file pool. - * \param Size The number of bytes to allocate. - * \param Rva A variable which receives the relative virtual address of the allocated block. - * - * \return A pointer to the allocated block. You must call PhDereferenceFilePool() or - * PhDereferenceFilePoolByRva() when you no longer need a reference to the block. - * - * \remarks The returned pointer is not valid beyond the lifetime of the file pool instance. Use the - * relative virtual address if you need a permanent reference to the allocated block. - */ -PVOID PhAllocateFilePool( - _Inout_ PPH_FILE_POOL Pool, - _In_ ULONG Size, - _Out_opt_ PULONG Rva - ) -{ - PPH_FP_BLOCK_HEADER blockHeader; - ULONG numberOfBlocks; - PPH_FP_BLOCK_HEADER firstBlock; - PPH_FP_SEGMENT_HEADER segmentHeader; - ULONG freeListIndex; - ULONG freeListLimit; - ULONG segmentIndex; - ULONG nextSegmentIndex; - ULONG newFreeListIndex; - - // Calculate the number of blocks needed for the allocation. - numberOfBlocks = (FIELD_OFFSET(PH_FP_BLOCK_HEADER, Body) + Size + Pool->BlockSize - 1) >> Pool->BlockShift; - - if (numberOfBlocks > PH_FP_BLOCK_COUNT - Pool->SegmentHeaderBlockSpan) - { - // TODO: Perform a large allocation. - return NULL; - } - - // Scan each applicable free list and try to allocate from those segments. - - freeListLimit = PhFppComputeFreeListIndex(Pool, numberOfBlocks); - - for (freeListIndex = 0; freeListIndex <= freeListLimit; freeListIndex++) - { - segmentIndex = Pool->Header->FreeLists[freeListIndex]; - - while (segmentIndex != -1) - { - firstBlock = PhFppReferenceSegment(Pool, segmentIndex); - - if (!firstBlock) - return NULL; - - segmentHeader = PhFppGetHeaderSegment(Pool, firstBlock); - nextSegmentIndex = segmentHeader->FreeFlink; - - blockHeader = PhFppAllocateBlocks(Pool, firstBlock, segmentHeader, numberOfBlocks); - - if (blockHeader) - goto BlockAllocated; - - PhFppDereferenceSegment(Pool, segmentIndex); - segmentIndex = nextSegmentIndex; - } - } - - // No segments have the required number of contiguous free blocks. Allocate a new one. - - firstBlock = PhFppAllocateSegment(Pool, &segmentIndex); - - if (!firstBlock) - return NULL; - - freeListIndex = 0; - segmentHeader = PhFppGetHeaderSegment(Pool, firstBlock); - blockHeader = PhFppAllocateBlocks(Pool, firstBlock, segmentHeader, numberOfBlocks); - - if (!blockHeader) - { - PhFppDereferenceSegment(Pool, segmentIndex); - return NULL; - } - -BlockAllocated: - - // Compute the new free list index of the segment and move it to another free list if necessary. - - newFreeListIndex = PhFppComputeFreeListIndex(Pool, segmentHeader->FreeBlocks); - - if (newFreeListIndex != freeListIndex) - { - PhFppRemoveFreeList(Pool, freeListIndex, segmentIndex, segmentHeader); - PhFppInsertFreeList(Pool, newFreeListIndex, segmentIndex, segmentHeader); - } - - if (Rva) - { - *Rva = PhFppEncodeRva(Pool, segmentIndex, firstBlock, &blockHeader->Body); - } - - return &blockHeader->Body; -} - -/** - * Frees a block. - * - * \param Pool The file pool. - * \param SegmentIndex The index of the segment containing the block. - * \param FirstBlock The first block of the segment containing the block. - * \param Block A pointer to the block. - */ -VOID PhpFreeFilePool( - _Inout_ PPH_FILE_POOL Pool, - _In_ ULONG SegmentIndex, - _In_ PPH_FP_BLOCK_HEADER FirstBlock, - _In_ PVOID Block - ) -{ - PPH_FP_SEGMENT_HEADER segmentHeader; - ULONG oldFreeListIndex; - ULONG newFreeListIndex; - - segmentHeader = PhFppGetHeaderSegment(Pool, FirstBlock); - oldFreeListIndex = PhFppComputeFreeListIndex(Pool, segmentHeader->FreeBlocks); - PhFppFreeBlocks(Pool, FirstBlock, segmentHeader, PhFppGetHeaderBlock(Pool, Block)); - newFreeListIndex = PhFppComputeFreeListIndex(Pool, segmentHeader->FreeBlocks); - - // Move the segment into another free list if needed. - if (newFreeListIndex != oldFreeListIndex) - { - PhFppRemoveFreeList(Pool, oldFreeListIndex, SegmentIndex, segmentHeader); - PhFppInsertFreeList(Pool, newFreeListIndex, SegmentIndex, segmentHeader); - } -} - -/** - * Frees a block allocated by PhAllocateFilePool(). - * - * \param Pool The file pool. - * \param Block A pointer to the block. The pointer is no longer valid after you call this function. - * Do not use PhDereferenceFilePool() or PhDereferenceFilePoolByRva(). - */ -VOID PhFreeFilePool( - _Inout_ PPH_FILE_POOL Pool, - _In_ PVOID Block - ) -{ - PPH_FILE_POOL_VIEW view; - PPH_FP_BLOCK_HEADER firstBlock; - - view = PhFppFindViewByBase(Pool, Block); - - if (!view) - PhRaiseStatus(STATUS_INVALID_PARAMETER_2); - - firstBlock = view->Base; - PhpFreeFilePool(Pool, view->SegmentIndex, firstBlock, Block); - PhFppDereferenceView(Pool, view); -} - -/** - * Frees a block allocated by PhAllocateFilePool(). - * - * \param Pool The file pool. - * \param Rva The relative virtual address of the block. - */ -BOOLEAN PhFreeFilePoolByRva( - _Inout_ PPH_FILE_POOL Pool, - _In_ ULONG Rva - ) -{ - ULONG segmentIndex; - ULONG offset; - PPH_FP_BLOCK_HEADER firstBlock; - - offset = PhFppDecodeRva(Pool, Rva, &segmentIndex); - - if (offset == -1) - return FALSE; - - firstBlock = PhFppReferenceSegment(Pool, segmentIndex); - - if (!firstBlock) - return FALSE; - - PhpFreeFilePool(Pool, segmentIndex, firstBlock, (PCHAR)firstBlock + offset); - PhFppDereferenceSegment(Pool, segmentIndex); - - return TRUE; -} - -/** - * Increments the reference count for the specified address. - * - * \param Pool The file pool. - * \param Address An address. - */ -VOID PhReferenceFilePool( - _Inout_ PPH_FILE_POOL Pool, - _In_ PVOID Address - ) -{ - PhFppReferenceSegmentByBase(Pool, Address); -} - -/** - * Decrements the reference count for the specified address. - * - * \param Pool The file pool. - * \param Address An address. - */ -VOID PhDereferenceFilePool( - _Inout_ PPH_FILE_POOL Pool, - _In_ PVOID Address - ) -{ - PhFppDereferenceSegmentByBase(Pool, Address); -} - -/** - * Obtains a pointer for a relative virtual address, incrementing the reference count of the - * address. - * - * \param Pool The file pool. - * \param Rva A relative virtual address. - */ -PVOID PhReferenceFilePoolByRva( - _Inout_ PPH_FILE_POOL Pool, - _In_ ULONG Rva - ) -{ - ULONG segmentIndex; - ULONG offset; - PPH_FP_BLOCK_HEADER firstBlock; - - if (Rva == 0) - return NULL; - - offset = PhFppDecodeRva(Pool, Rva, &segmentIndex); - - if (offset == -1) - return NULL; - - firstBlock = PhFppReferenceSegment(Pool, segmentIndex); - - if (!firstBlock) - return NULL; - - return (PCHAR)firstBlock + offset; -} - -/** - * Decrements the reference count for the specified relative virtual address. - * - * \param Pool The file pool. - * \param Rva A relative virtual address. - */ -BOOLEAN PhDereferenceFilePoolByRva( - _Inout_ PPH_FILE_POOL Pool, - _In_ ULONG Rva - ) -{ - ULONG segmentIndex; - ULONG offset; - - offset = PhFppDecodeRva(Pool, Rva, &segmentIndex); - - if (offset == -1) - return FALSE; - - PhFppDereferenceSegment(Pool, segmentIndex); - - return TRUE; -} - -/** - * Obtains a relative virtual address for a pointer. - * - * \param Pool The file pool. - * \param Address A pointer. - * - * \return The relative virtual address. - * - * \remarks No reference counts are changed. - */ -ULONG PhEncodeRvaFilePool( - _In_ PPH_FILE_POOL Pool, - _In_ PVOID Address - ) -{ - PPH_FILE_POOL_VIEW view; - - if (!Address) - return 0; - - view = PhFppFindViewByBase(Pool, Address); - - if (!view) - PhRaiseStatus(STATUS_INVALID_PARAMETER_2); - - return PhFppEncodeRva(Pool, view->SegmentIndex, view->Base, Address); -} - -/** - * Retrieves user data. - * - * \param Pool The file pool. - * \param Context A variable which receives the user data. - */ -VOID PhGetUserContextFilePool( - _In_ PPH_FILE_POOL Pool, - _Out_ PULONGLONG Context - ) -{ - *Context = Pool->Header->UserContext; -} - -/** - * Stores user data. - * - * \param Pool The file pool. - * \param Context A variable which contains the user data. - */ -VOID PhSetUserContextFilePool( - _Inout_ PPH_FILE_POOL Pool, - _In_ PULONGLONG Context - ) -{ - Pool->Header->UserContext = *Context; -} - -/** - * Extends a file pool. - * - * \param Pool The file pool. - * \param NewSize The new size of the file, in bytes. - */ -NTSTATUS PhFppExtendRange( - _Inout_ PPH_FILE_POOL Pool, - _In_ ULONG NewSize - ) -{ - LARGE_INTEGER newSectionSize; - - newSectionSize.QuadPart = NewSize; - - return NtExtendSection(Pool->SectionHandle, &newSectionSize); -} - -/** - * Maps in a view of a file pool. - * - * \param Pool The file pool. - * \param Offset The offset of the view, in bytes. - * \param Size The size of the view, in bytes. - * \param Base A variable which receives the base address of the view. - */ -NTSTATUS PhFppMapRange( - _Inout_ PPH_FILE_POOL Pool, - _In_ ULONG Offset, - _In_ ULONG Size, - _Out_ PVOID *Base - ) -{ - NTSTATUS status; - PVOID baseAddress; - LARGE_INTEGER sectionOffset; - SIZE_T viewSize; - - baseAddress = NULL; - sectionOffset.QuadPart = Offset; - viewSize = Size; - - status = NtMapViewOfSection( - Pool->SectionHandle, - NtCurrentProcess(), - &baseAddress, - 0, - viewSize, - §ionOffset, - &viewSize, - ViewShare, - 0, - !Pool->ReadOnly ? PAGE_READWRITE : PAGE_READONLY - ); - - if (NT_SUCCESS(status)) - *Base = baseAddress; - - return status; -} - -/** - * Unmaps a view of a file pool. - * - * \param Pool The file pool. - * \param Base The base address of the view. - */ -NTSTATUS PhFppUnmapRange( - _Inout_ PPH_FILE_POOL Pool, - _In_ PVOID Base - ) -{ - return NtUnmapViewOfSection(NtCurrentProcess(), Base); -} - -/** - * Initializes a segment. - * - * \param Pool The file pool. - * \param BlockOfSegmentHeader The block header of the span containing the segment header. - * \param AdditionalBlocksUsed The number of blocks already allocated from the segment, excluding - * the blocks comprising the segment header. - */ -VOID PhFppInitializeSegment( - _Inout_ PPH_FILE_POOL Pool, - _Out_ PPH_FP_BLOCK_HEADER BlockOfSegmentHeader, - _In_ ULONG AdditionalBlocksUsed - ) -{ - PPH_FP_SEGMENT_HEADER segmentHeader; - RTL_BITMAP bitmap; - - BlockOfSegmentHeader->Span = Pool->SegmentHeaderBlockSpan; - segmentHeader = (PPH_FP_SEGMENT_HEADER)&BlockOfSegmentHeader->Body; - - RtlInitializeBitMap(&bitmap, segmentHeader->Bitmap, PH_FP_BLOCK_COUNT); - RtlSetBits(&bitmap, 0, Pool->SegmentHeaderBlockSpan + AdditionalBlocksUsed); - segmentHeader->FreeBlocks = PH_FP_BLOCK_COUNT - (Pool->SegmentHeaderBlockSpan + AdditionalBlocksUsed); - segmentHeader->FreeFlink = -1; - segmentHeader->FreeBlink = -1; -} - -/** - * Allocates a segment. - * - * \param Pool The file pool. - * \param NewSegmentIndex A variable which receives the index of the new segment. - * - * \return A pointer to the first block of the segment. - */ -PPH_FP_BLOCK_HEADER PhFppAllocateSegment( - _Inout_ PPH_FILE_POOL Pool, - _Out_ PULONG NewSegmentIndex - ) -{ - ULONG newSize; - ULONG segmentIndex; - PPH_FP_BLOCK_HEADER firstBlock; - PPH_FP_SEGMENT_HEADER segmentHeader; - - newSize = (Pool->Header->SegmentCount + 1) << Pool->SegmentShift; - - if (!NT_SUCCESS(PhFppExtendRange(Pool, newSize))) - return NULL; - - segmentIndex = Pool->Header->SegmentCount++; - firstBlock = PhFppReferenceSegment(Pool, segmentIndex); - PhFppInitializeSegment(Pool, firstBlock, 0); - segmentHeader = (PPH_FP_SEGMENT_HEADER)&firstBlock->Body; - - PhFppInsertFreeList(Pool, 0, segmentIndex, segmentHeader); - - *NewSegmentIndex = segmentIndex; - - return firstBlock; -} - -/** - * Retrieves the header of a segment. - * - * \param Pool The file pool. - * \param FirstBlock The first block of the segment. - */ -PPH_FP_SEGMENT_HEADER PhFppGetHeaderSegment( - _Inout_ PPH_FILE_POOL Pool, - _In_ PPH_FP_BLOCK_HEADER FirstBlock - ) -{ - if (FirstBlock != Pool->FirstBlockOfFirstSegment) - { - return (PPH_FP_SEGMENT_HEADER)&FirstBlock->Body; - } - else - { - // In the first segment, the segment header is after the file header. - return (PPH_FP_SEGMENT_HEADER)&((PPH_FP_BLOCK_HEADER)((PCHAR)FirstBlock + (Pool->FileHeaderBlockSpan << Pool->BlockShift)))->Body; - } -} - -VOID PhFppAddViewByIndex( - _Inout_ PPH_FILE_POOL Pool, - _Inout_ PPH_FILE_POOL_VIEW View - ) -{ - ULONG index; - PLIST_ENTRY head; - - index = View->SegmentIndex & (Pool->ByIndexSize - 1); - head = Pool->ByIndexBuckets[index]; - - if (head) - { - InsertHeadList(head, &View->ByIndexListEntry); - } - else - { - InitializeListHead(&View->ByIndexListEntry); - Pool->ByIndexBuckets[index] = &View->ByIndexListEntry; - } -} - -VOID PhFppRemoveViewByIndex( - _Inout_ PPH_FILE_POOL Pool, - _Inout_ PPH_FILE_POOL_VIEW View - ) -{ - ULONG index; - PLIST_ENTRY head; - - index = View->SegmentIndex & (Pool->ByIndexSize - 1); - head = Pool->ByIndexBuckets[index]; - assert(head); - - // Unlink the entry from the chain. - RemoveEntryList(&View->ByIndexListEntry); - - if (&View->ByIndexListEntry == head) - { - // This entry is currently the chain head. - - // If this was the last entry in the chain, then indicate that the chain is empty. - // Otherwise, choose a new head. - - if (IsListEmpty(head)) - Pool->ByIndexBuckets[index] = NULL; - else - Pool->ByIndexBuckets[index] = head->Flink; - } -} - -/** - * Finds a view for the specified segment. - * - * \param Pool The file pool. - * \param SegmentIndex The index of the segment. - * - * \return The view for the segment, or NULL if no view is present for the segment. - */ -PPH_FILE_POOL_VIEW PhFppFindViewByIndex( - _Inout_ PPH_FILE_POOL Pool, - _In_ ULONG SegmentIndex - ) -{ - ULONG index; - PLIST_ENTRY head; - PLIST_ENTRY entry; - PPH_FILE_POOL_VIEW view; - - index = SegmentIndex & (Pool->ByIndexSize - 1); - head = Pool->ByIndexBuckets[index]; - - if (!head) - return NULL; - - entry = head; - - do - { - view = CONTAINING_RECORD(entry, PH_FILE_POOL_VIEW, ByIndexListEntry); - - if (view->SegmentIndex == SegmentIndex) - return view; - - entry = entry->Flink; - } while (entry != head); - - return NULL; -} - -LONG NTAPI PhpFilePoolViewByBaseCompareFunction( - _In_ PPH_AVL_LINKS Links1, - _In_ PPH_AVL_LINKS Links2 - ) -{ - PPH_FILE_POOL_VIEW view1 = CONTAINING_RECORD(Links1, PH_FILE_POOL_VIEW, ByBaseLinks); - PPH_FILE_POOL_VIEW view2 = CONTAINING_RECORD(Links2, PH_FILE_POOL_VIEW, ByBaseLinks); - - return uintptrcmp((ULONG_PTR)view1->Base, (ULONG_PTR)view2->Base); -} - -VOID PhFppAddViewByBase( - _Inout_ PPH_FILE_POOL Pool, - _Inout_ PPH_FILE_POOL_VIEW View - ) -{ - PhAddElementAvlTree(&Pool->ByBaseSet, &View->ByBaseLinks); -} - -VOID PhFppRemoveViewByBase( - _Inout_ PPH_FILE_POOL Pool, - _Inout_ PPH_FILE_POOL_VIEW View - ) -{ - PhRemoveElementAvlTree(&Pool->ByBaseSet, &View->ByBaseLinks); -} - -/** - * Finds a view containing the specified address. - * - * \param Pool The file pool. - * \param Base The address. - * - * \return The view containing the address, or NULL if no view is present for the address. - */ -PPH_FILE_POOL_VIEW PhFppFindViewByBase( - _Inout_ PPH_FILE_POOL Pool, - _In_ PVOID Base - ) -{ - PPH_FILE_POOL_VIEW view; - PPH_AVL_LINKS links; - PH_FILE_POOL_VIEW lookupView; - - // This is an approximate search to find the target view in which the specified address lies. - - lookupView.Base = Base; - links = PhUpperDualBoundElementAvlTree(&Pool->ByBaseSet, &lookupView.ByBaseLinks); - - if (!links) - return NULL; - - view = CONTAINING_RECORD(links, PH_FILE_POOL_VIEW, ByBaseLinks); - - if ((ULONG_PTR)Base < (ULONG_PTR)view->Base + Pool->SegmentSize) - return view; - - return NULL; -} - -PPH_FILE_POOL_VIEW PhFppCreateView( - _Inout_ PPH_FILE_POOL Pool, - _In_ ULONG SegmentIndex - ) -{ - PPH_FILE_POOL_VIEW view; - PVOID base; - - // Map in the segment. - if (!NT_SUCCESS(PhFppMapRange(Pool, SegmentIndex << Pool->SegmentShift, Pool->SegmentSize, &base))) - return NULL; - - // Create and add the view entry. - - view = PhAllocateFromFreeList(&Pool->ViewFreeList); - memset(view, 0, sizeof(PH_FILE_POOL_VIEW)); - - view->RefCount = 1; - view->SegmentIndex = SegmentIndex; - view->Base = base; - - PhFppAddViewByIndex(Pool, view); - PhFppAddViewByBase(Pool, view); - - return view; -} - -VOID PhFppDestroyView( - _Inout_ PPH_FILE_POOL Pool, - _Inout_ PPH_FILE_POOL_VIEW View - ) -{ - PhFppUnmapRange(Pool, View->Base); - PhFppRemoveViewByIndex(Pool, View); - PhFppRemoveViewByBase(Pool, View); - - PhFreeToFreeList(&Pool->ViewFreeList, View); -} - -VOID PhFppActivateView( - _Inout_ PPH_FILE_POOL Pool, - _Inout_ PPH_FILE_POOL_VIEW View - ) -{ - RemoveEntryList(&View->InactiveViewsListEntry); - Pool->NumberOfInactiveViews--; -} - -VOID PhFppDeactivateView( - _Inout_ PPH_FILE_POOL Pool, - _Inout_ PPH_FILE_POOL_VIEW View - ) -{ - InsertHeadList(&Pool->InactiveViewsListHead, &View->InactiveViewsListEntry); - Pool->NumberOfInactiveViews++; - - // If we have too many inactive views, destroy the least recent ones. - while (Pool->NumberOfInactiveViews > Pool->MaximumInactiveViews) - { - PLIST_ENTRY lruEntry; - PPH_FILE_POOL_VIEW lruView; - - lruEntry = RemoveTailList(&Pool->InactiveViewsListHead); - Pool->NumberOfInactiveViews--; - - assert(lruEntry != &Pool->InactiveViewsListHead); - lruView = CONTAINING_RECORD(lruEntry, PH_FILE_POOL_VIEW, InactiveViewsListEntry); - PhFppDestroyView(Pool, lruView); - } -} - -VOID PhFppReferenceView( - _Inout_ PPH_FILE_POOL Pool, - _Inout_ PPH_FILE_POOL_VIEW View - ) -{ - if (View->RefCount == 0) - { - // The view is inactive, so make it active. - PhFppActivateView(Pool, View); - } - - View->RefCount++; -} - -VOID PhFppDereferenceView( - _Inout_ PPH_FILE_POOL Pool, - _Inout_ PPH_FILE_POOL_VIEW View - ) -{ - if (--View->RefCount == 0) - { - if (View->SegmentIndex == 0) - PhRaiseStatus(STATUS_INTERNAL_ERROR); - - PhFppDeactivateView(Pool, View); - } -} - -PPH_FP_BLOCK_HEADER PhFppReferenceSegment( - _Inout_ PPH_FILE_POOL Pool, - _In_ ULONG SegmentIndex - ) -{ - PPH_FILE_POOL_VIEW view; - - // Validate parameters. - if (SegmentIndex != 0 && SegmentIndex >= Pool->Header->SegmentCount) - return NULL; - - // Try to get a cached view. - - view = PhFppFindViewByIndex(Pool, SegmentIndex); - - if (view) - { - PhFppReferenceView(Pool, view); - - return (PPH_FP_BLOCK_HEADER)view->Base; - } - - // No cached view, so create one. - - view = PhFppCreateView(Pool, SegmentIndex); - - if (!view) - return NULL; - - return (PPH_FP_BLOCK_HEADER)view->Base; -} - -VOID PhFppDereferenceSegment( - _Inout_ PPH_FILE_POOL Pool, - _In_ ULONG SegmentIndex - ) -{ - PPH_FILE_POOL_VIEW view; - - view = PhFppFindViewByIndex(Pool, SegmentIndex); - - if (!view) - PhRaiseStatus(STATUS_INTERNAL_ERROR); - - PhFppDereferenceView(Pool, view); -} - -VOID PhFppReferenceSegmentByBase( - _Inout_ PPH_FILE_POOL Pool, - _In_ PVOID Base - ) -{ - PPH_FILE_POOL_VIEW view; - - view = PhFppFindViewByBase(Pool, Base); - - if (!view) - PhRaiseStatus(STATUS_INTERNAL_ERROR); - - PhFppReferenceView(Pool, view); -} - -VOID PhFppDereferenceSegmentByBase( - _Inout_ PPH_FILE_POOL Pool, - _In_ PVOID Base - ) -{ - PPH_FILE_POOL_VIEW view; - - view = PhFppFindViewByBase(Pool, Base); - - if (!view) - PhRaiseStatus(STATUS_INTERNAL_ERROR); - - PhFppDereferenceView(Pool, view); -} - -/** - * Allocates blocks from a segment. - * - * \param Pool The file pool. - * \param FirstBlock The first block of the segment. - * \param SegmentHeader The header of the segment. - * \param NumberOfBlocks The number of blocks to allocate. - * - * \return The header of the allocated span, or NULL if there is an insufficient number of - * contiguous free blocks for the allocation. - */ -PPH_FP_BLOCK_HEADER PhFppAllocateBlocks( - _Inout_ PPH_FILE_POOL Pool, - _In_ PPH_FP_BLOCK_HEADER FirstBlock, - _Inout_ PPH_FP_SEGMENT_HEADER SegmentHeader, - _In_ ULONG NumberOfBlocks - ) -{ - RTL_BITMAP bitmap; - ULONG hintIndex; - ULONG foundIndex; - PPH_FP_BLOCK_HEADER blockHeader; - - if (FirstBlock != Pool->FirstBlockOfFirstSegment) - hintIndex = Pool->SegmentHeaderBlockSpan; - else - hintIndex = Pool->SegmentHeaderBlockSpan + Pool->FileHeaderBlockSpan; - - RtlInitializeBitMap(&bitmap, SegmentHeader->Bitmap, PH_FP_BLOCK_COUNT); - - // Find a range of free blocks and mark them as in-use. - foundIndex = RtlFindClearBitsAndSet(&bitmap, NumberOfBlocks, hintIndex); - - if (foundIndex == -1) - { - // No more space. - return NULL; - } - - SegmentHeader->FreeBlocks -= NumberOfBlocks; - - blockHeader = (PPH_FP_BLOCK_HEADER)((PCHAR)FirstBlock + (foundIndex << Pool->BlockShift)); - blockHeader->Flags = 0; - blockHeader->Span = NumberOfBlocks; - - return blockHeader; -} - -/** - * Frees blocks in a segment. - * - * \param Pool The file pool. - * \param FirstBlock The first block of the segment. - * \param SegmentHeader The header of the segment. - * \param BlockHeader The header of the allocated span. - */ -VOID PhFppFreeBlocks( - _Inout_ PPH_FILE_POOL Pool, - _In_ PPH_FP_BLOCK_HEADER FirstBlock, - _Inout_ PPH_FP_SEGMENT_HEADER SegmentHeader, - _In_ PPH_FP_BLOCK_HEADER BlockHeader - ) -{ - RTL_BITMAP bitmap; - ULONG startIndex; - ULONG blockSpan; - - RtlInitializeBitMap(&bitmap, SegmentHeader->Bitmap, PH_FP_BLOCK_COUNT); - - // Mark the blocks as free. - startIndex = (ULONG)((PCHAR)BlockHeader - (PCHAR)FirstBlock) >> Pool->BlockShift; - blockSpan = BlockHeader->Span; - RtlClearBits(&bitmap, startIndex, blockSpan); - SegmentHeader->FreeBlocks += blockSpan; -} - -/** - * Computes the free list index (category) for a specified number of blocks. - * - * \param Pool The file pool. - * \param NumberOfBlocks The number of free or required blocks. - */ -ULONG PhFppComputeFreeListIndex( - _In_ PPH_FILE_POOL Pool, - _In_ ULONG NumberOfBlocks - ) -{ - // Use a binary tree to speed up comparison. - - if (NumberOfBlocks >= PH_FP_BLOCK_COUNT / 64) - { - if (NumberOfBlocks >= PH_FP_BLOCK_COUNT / 2) - { - if (NumberOfBlocks >= PH_FP_BLOCK_COUNT - Pool->SegmentHeaderBlockSpan) - return 0; - else - return 1; - } - else - { - if (NumberOfBlocks >= PH_FP_BLOCK_COUNT / 16) - return 2; - else - return 3; - } - } - else - { - if (NumberOfBlocks >= 4) - { - if (NumberOfBlocks >= PH_FP_BLOCK_COUNT / 256) - return 4; - else - return 5; - } - else - { - if (NumberOfBlocks >= 1) - return 6; - else - return 7; - } - } -} - -/** - * Inserts a segment into a free list. - * - * \param Pool The file pool. - * \param FreeListIndex The index of a free list. - * \param SegmentIndex The index of the segment. - * \param SegmentHeader The header of the segment. - */ -BOOLEAN PhFppInsertFreeList( - _Inout_ PPH_FILE_POOL Pool, - _In_ ULONG FreeListIndex, - _In_ ULONG SegmentIndex, - _In_ PPH_FP_SEGMENT_HEADER SegmentHeader - ) -{ - ULONG oldSegmentIndex; - PPH_FP_BLOCK_HEADER oldSegmentFirstBlock; - PPH_FP_SEGMENT_HEADER oldSegmentHeader; - - oldSegmentIndex = Pool->Header->FreeLists[FreeListIndex]; - - // Try to reference the segment before we commit any changes. - - if (oldSegmentIndex != -1) - { - oldSegmentFirstBlock = PhFppReferenceSegment(Pool, oldSegmentIndex); - - if (!oldSegmentFirstBlock) - return FALSE; - } - - // Insert the segment into the list. - - SegmentHeader->FreeBlink = -1; - SegmentHeader->FreeFlink = oldSegmentIndex; - Pool->Header->FreeLists[FreeListIndex] = SegmentIndex; - - if (oldSegmentIndex != -1) - { - oldSegmentHeader = PhFppGetHeaderSegment(Pool, oldSegmentFirstBlock); - oldSegmentHeader->FreeBlink = SegmentIndex; - PhFppDereferenceSegment(Pool, oldSegmentIndex); - } - - return TRUE; -} - -/** - * Removes a segment from a free list. - * - * \param Pool The file pool. - * \param FreeListIndex The index of a free list. - * \param SegmentIndex The index of the segment. - * \param SegmentHeader The header of the segment. - */ -BOOLEAN PhFppRemoveFreeList( - _Inout_ PPH_FILE_POOL Pool, - _In_ ULONG FreeListIndex, - _In_ ULONG SegmentIndex, - _In_ PPH_FP_SEGMENT_HEADER SegmentHeader - ) -{ - ULONG flinkSegmentIndex; - PPH_FP_BLOCK_HEADER flinkSegmentFirstBlock; - PPH_FP_SEGMENT_HEADER flinkSegmentHeader; - ULONG blinkSegmentIndex; - PPH_FP_BLOCK_HEADER blinkSegmentFirstBlock; - PPH_FP_SEGMENT_HEADER blinkSegmentHeader; - - flinkSegmentIndex = SegmentHeader->FreeFlink; - blinkSegmentIndex = SegmentHeader->FreeBlink; - - // Try to reference the segments before we commit any changes. - - if (flinkSegmentIndex != -1) - { - flinkSegmentFirstBlock = PhFppReferenceSegment(Pool, flinkSegmentIndex); - - if (!flinkSegmentFirstBlock) - return FALSE; - } - - if (blinkSegmentIndex != -1) - { - blinkSegmentFirstBlock = PhFppReferenceSegment(Pool, blinkSegmentIndex); - - if (!blinkSegmentFirstBlock) - { - if (flinkSegmentIndex != -1) - PhFppDereferenceSegment(Pool, flinkSegmentIndex); - - return FALSE; - } - } - - // Unlink the segment from the list. - - if (flinkSegmentIndex != -1) - { - flinkSegmentHeader = PhFppGetHeaderSegment(Pool, flinkSegmentFirstBlock); - flinkSegmentHeader->FreeBlink = blinkSegmentIndex; - PhFppDereferenceSegment(Pool, flinkSegmentIndex); - } - - if (blinkSegmentIndex != -1) - { - blinkSegmentHeader = PhFppGetHeaderSegment(Pool, blinkSegmentFirstBlock); - blinkSegmentHeader->FreeFlink = flinkSegmentIndex; - PhFppDereferenceSegment(Pool, blinkSegmentIndex); - } - else - { - // The segment was the list head; select a new one. - Pool->Header->FreeLists[FreeListIndex] = flinkSegmentIndex; - } - - return TRUE; -} - -/** - * Retrieves the header of a block. - * - * \param Pool The file pool. - * \param Block A pointer to the body of the block. - */ -PPH_FP_BLOCK_HEADER PhFppGetHeaderBlock( - _In_ PPH_FILE_POOL Pool, - _In_ PVOID Block - ) -{ - return CONTAINING_RECORD(Block, PH_FP_BLOCK_HEADER, Body); -} - -/** - * Creates a relative virtual address. - * - * \param Pool The file pool. - * \param SegmentIndex The index of the segment containing \a Address. - * \param FirstBlock The first block of the segment containing \a Address. - * \param Address An address. - */ -ULONG PhFppEncodeRva( - _In_ PPH_FILE_POOL Pool, - _In_ ULONG SegmentIndex, - _In_ PPH_FP_BLOCK_HEADER FirstBlock, - _In_ PVOID Address - ) -{ - return (SegmentIndex << Pool->SegmentShift) + (ULONG)((PCHAR)Address - (PCHAR)FirstBlock); -} - -/** - * Decodes a relative virtual address. - * - * \param Pool The file pool. - * \param Rva The relative virtual address. - * \param SegmentIndex A variable which receives the segment index. - * - * \return An offset into the segment specified by \a SegmentIndex, or -1 if \a Rva is invalid. - */ -ULONG PhFppDecodeRva( - _In_ PPH_FILE_POOL Pool, - _In_ ULONG Rva, - _Out_ PULONG SegmentIndex - ) -{ - ULONG segmentIndex; - - segmentIndex = Rva >> Pool->SegmentShift; - - if (segmentIndex >= Pool->Header->SegmentCount) - return -1; - - *SegmentIndex = segmentIndex; - - return Rva & (Pool->SegmentSize - 1); -} +/* + * Process Hacker - + * file-based allocator + * + * Copyright (C) 2011 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +/* + * File pool allows blocks of storage to be allocated from a file. Each file looks like this: + * + * Segment 0 __________________________________________________________ + * | | | | | + * | Block Header | File Header | Block Header | Segment Header | + * |______________|________________|______________|________________| + * | | | | | + * | Block Header | User Data | Block Header | User Data | + * |______________|________________|______________|________________| + * | | | | | + * | ... | ... | ... | ... | + * |______________|________________|______________|________________| + * Segment 1 __________________________________________________________ + * | | | | | + * | Block Header | Segment Header | Block Header | User Data | + * |______________|________________|______________|________________| + * | | | | | + * | ... | ... | ... | ... | + * |______________|________________|______________|________________| + * Segment 2 __________________________________________________________ + * | | | | | + * | ... | ... | ... | ... | + * |______________|________________|______________|________________| + * + */ + +/* + * A file consists of a variable number of segments, with the segment size specified as a power of + * two. Each segment contains a fixed number of blocks, leading to a variable block size. Every + * allocation made by the user is an allocation of a certain number of blocks, with enough space for + * the block header. This is placed at the beginning of each allocation and contains the number of + * blocks in the allocation (a better name for it would be the allocation header). + * + * Block management in each segment is handled by a bitmap which is stored in the segment header at + * the beginning of each segment. The first segment (segment 0) is special with the file header + * being placed immediately after an initial block header. This is because the segment size is + * stored in the file header, and without it we cannot calculate the block size, which is used to + * locate everything else in the file. + * + * To speed up allocations a number of free lists are maintained which categorize each segment based + * on how many free blocks they have. This means we can avoid trying to allocate from every existing + * segment before finding out we have to allocate a new segment, or trying to allocate from segments + * without the required number of free blocks. The downside of this technique is that it doesn't + * account for fragmentation within the allocation bitmap. + * + * Each segment is mapped in separately, and each view is cached. Even after a view becomes inactive + * (has a reference count of 0) it remains mapped in until the maximum number of inactive views is + * reached. + */ + +#include +#include + +#include + +/** + * Creates or opens a file pool. + * + * \param Pool A variable which receives the file pool instance. + * \param FileHandle A handle to the file. + * \param ReadOnly TRUE to disallow writes to the file. + * \param Parameters Parameters for on-disk and runtime structures. + */ +NTSTATUS PhCreateFilePool( + _Out_ PPH_FILE_POOL *Pool, + _In_ HANDLE FileHandle, + _In_ BOOLEAN ReadOnly, + _In_opt_ PPH_FILE_POOL_PARAMETERS Parameters + ) +{ + NTSTATUS status; + PPH_FILE_POOL pool; + LARGE_INTEGER fileSize; + PH_FILE_POOL_PARAMETERS localParameters; + BOOLEAN creating; + HANDLE sectionHandle; + PPH_FP_BLOCK_HEADER initialBlock; + PPH_FP_FILE_HEADER header; + ULONG i; + + if (Parameters) + { + PhpValidateFilePoolParameters(Parameters); + } + else + { + PhpSetDefaultFilePoolParameters(&localParameters); + Parameters = &localParameters; + } + + pool = PhAllocate(sizeof(PH_FILE_POOL)); + memset(pool, 0, sizeof(PH_FILE_POOL)); + + pool->FileHandle = FileHandle; + pool->ReadOnly = ReadOnly; + + if (!NT_SUCCESS(status = PhGetFileSize(FileHandle, &fileSize))) + goto CleanupExit; + + creating = FALSE; + + // If the file is smaller than the page size, assume we're creating a new file. + if (fileSize.QuadPart < PAGE_SIZE) + { + if (ReadOnly) + { + status = STATUS_BAD_FILE_TYPE; + goto CleanupExit; + } + + fileSize.QuadPart = PAGE_SIZE; + + if (!NT_SUCCESS(status = PhSetFileSize(FileHandle, &fileSize))) + goto CleanupExit; + + creating = TRUE; + } + + // Create a section. + status = NtCreateSection( + §ionHandle, + SECTION_ALL_ACCESS, + NULL, + &fileSize, + !ReadOnly ? PAGE_READWRITE : PAGE_READONLY, + SEC_COMMIT, + FileHandle + ); + + if (!NT_SUCCESS(status)) + goto CleanupExit; + + pool->SectionHandle = sectionHandle; + + // Map in the first segment, set up initial parameters, then remap the first segment. + + if (!NT_SUCCESS(status = PhFppMapRange(pool, 0, PAGE_SIZE, &initialBlock))) + goto CleanupExit; + + header = (PPH_FP_FILE_HEADER)&initialBlock->Body; + + if (creating) + { + header->Magic = PH_FP_MAGIC; + header->SegmentShift = Parameters->SegmentShift; + header->SegmentCount = 1; + + for (i = 0; i < PH_FP_FREE_LIST_COUNT; i++) + header->FreeLists[i] = -1; + } + else + { + if (header->Magic != PH_FP_MAGIC) + { + PhFppUnmapRange(pool, initialBlock); + status = STATUS_BAD_FILE_TYPE; + goto CleanupExit; + } + } + + pool->SegmentShift = header->SegmentShift; + pool->SegmentSize = 1 << pool->SegmentShift; + + pool->BlockShift = pool->SegmentShift - PH_FP_BLOCK_COUNT_SHIFT; + pool->BlockSize = 1 << pool->BlockShift; + pool->FileHeaderBlockSpan = (sizeof(PH_FP_FILE_HEADER) + pool->BlockSize - 1) >> pool->BlockShift; + pool->SegmentHeaderBlockSpan = (sizeof(PH_FP_SEGMENT_HEADER) + pool->BlockSize - 1) >> pool->BlockShift; + + // Unmap the first segment and remap with the new segment size. + + PhFppUnmapRange(pool, initialBlock); + + if (creating) + { + // Extend the section so it fits the entire first segment. + if (!NT_SUCCESS(status = PhFppExtendRange(pool, pool->SegmentSize))) + goto CleanupExit; + } + + // Runtime structure initialization + + PhInitializeFreeList(&pool->ViewFreeList, sizeof(PH_FILE_POOL_VIEW), 32); + pool->ByIndexSize = 32; + pool->ByIndexBuckets = PhAllocate(sizeof(PPH_FILE_POOL_VIEW) * pool->ByIndexSize); + memset(pool->ByIndexBuckets, 0, sizeof(PPH_FILE_POOL_VIEW) * pool->ByIndexSize); + PhInitializeAvlTree(&pool->ByBaseSet, PhpFilePoolViewByBaseCompareFunction); + + pool->MaximumInactiveViews = Parameters->MaximumInactiveViews; + InitializeListHead(&pool->InactiveViewsListHead); + + // File structure initialization + + pool->FirstBlockOfFirstSegment = PhFppReferenceSegment(pool, 0); + pool->Header = (PPH_FP_FILE_HEADER)&pool->FirstBlockOfFirstSegment->Body; + + if (creating) + { + PPH_FP_BLOCK_HEADER segmentHeaderBlock; + + // Set up the first segment properly. + + pool->FirstBlockOfFirstSegment->Span = pool->FileHeaderBlockSpan; + segmentHeaderBlock = (PPH_FP_BLOCK_HEADER)((PCHAR)pool->FirstBlockOfFirstSegment + (pool->FileHeaderBlockSpan << pool->BlockShift)); + PhFppInitializeSegment(pool, segmentHeaderBlock, pool->FileHeaderBlockSpan); + + pool->Header->FreeLists[1] = 0; + } + +CleanupExit: + if (NT_SUCCESS(status)) + { + *Pool = pool; + } + else + { + // Don't close the file handle the user passed in. + pool->FileHandle = NULL; + PhDestroyFilePool(pool); + } + + return status; +} + +/** + * Creates or opens a file pool. + * + * \param Pool A variable which receives the file pool instance. + * \param FileName The file name of the file pool. + * \param ReadOnly TRUE to disallow writes to the file. + * \param ShareAccess The file access granted to other threads. + * \param CreateDisposition The action to perform if the file does or does not exist. See + * PhCreateFileWin32() for more information. + * \param Parameters Parameters for on-disk and runtime structures. + */ +NTSTATUS PhCreateFilePool2( + _Out_ PPH_FILE_POOL *Pool, + _In_ PWSTR FileName, + _In_ BOOLEAN ReadOnly, + _In_ ULONG ShareAccess, + _In_ ULONG CreateDisposition, + _In_opt_ PPH_FILE_POOL_PARAMETERS Parameters + ) +{ + NTSTATUS status; + PPH_FILE_POOL pool; + HANDLE fileHandle; + ULONG createStatus; + + if (!NT_SUCCESS(status = PhCreateFileWin32Ex( + &fileHandle, + FileName, + !ReadOnly ? (FILE_GENERIC_READ | FILE_GENERIC_WRITE | DELETE) : FILE_GENERIC_READ, + FILE_ATTRIBUTE_NORMAL, + ShareAccess, + CreateDisposition, + FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, + &createStatus + ))) + { + return status; + } + + status = PhCreateFilePool(&pool, fileHandle, ReadOnly, Parameters); + + if (NT_SUCCESS(status)) + { + *Pool = pool; + } + else + { + if (!ReadOnly && createStatus == FILE_CREATED) + { + FILE_DISPOSITION_INFORMATION dispositionInfo; + IO_STATUS_BLOCK isb; + + dispositionInfo.DeleteFile = TRUE; + NtSetInformationFile(fileHandle, &isb, &dispositionInfo, sizeof(FILE_DISPOSITION_INFORMATION), FileDispositionInformation); + } + + NtClose(fileHandle); + } + + return status; +} + +/** + * Frees resources used by a file pool instance. + * + * \param Pool The file pool. + */ +VOID PhDestroyFilePool( + _In_ _Post_invalid_ PPH_FILE_POOL Pool + ) +{ + ULONG i; + PLIST_ENTRY head; + PLIST_ENTRY entry; + PPH_FILE_POOL_VIEW view; + + // Unmap all views. + for (i = 0; i < Pool->ByIndexSize; i++) + { + if (head = Pool->ByIndexBuckets[i]) + { + entry = head; + + do + { + view = CONTAINING_RECORD(entry, PH_FILE_POOL_VIEW, ByIndexListEntry); + entry = entry->Flink; + PhFppUnmapRange(Pool, view->Base); + PhFreeToFreeList(&Pool->ViewFreeList, view); + } while (entry != head); + } + } + + if (Pool->ByIndexBuckets) + PhFree(Pool->ByIndexBuckets); + + PhDeleteFreeList(&Pool->ViewFreeList); + + if (Pool->SectionHandle) + NtClose(Pool->SectionHandle); + if (Pool->FileHandle) + NtClose(Pool->FileHandle); + + PhFree(Pool); +} + +/** + * Validates and corrects file pool parameters. + * + * \param Parameters The parameters structure which is validated and modified if necessary. + */ +NTSTATUS PhpValidateFilePoolParameters( + _Inout_ PPH_FILE_POOL_PARAMETERS Parameters + ) +{ + NTSTATUS status = STATUS_SUCCESS; + + // 16 <= SegmentShift <= 28 + + if (Parameters->SegmentShift < 16) + { + Parameters->SegmentShift = 16; + status = STATUS_SOME_NOT_MAPPED; + } + + if (Parameters->SegmentShift > 28) + { + Parameters->SegmentShift = 28; + status = STATUS_SOME_NOT_MAPPED; + } + + return status; +} + +/** + * Creates default file pool parameters. + * + * \param Parameters The parameters structure which receives the default parameter values. + */ +VOID PhpSetDefaultFilePoolParameters( + _Out_ PPH_FILE_POOL_PARAMETERS Parameters + ) +{ + Parameters->SegmentShift = 18; // 256kB + Parameters->MaximumInactiveViews = 128; +} + +/** + * Allocates a block from a file pool. + * + * \param Pool The file pool. + * \param Size The number of bytes to allocate. + * \param Rva A variable which receives the relative virtual address of the allocated block. + * + * \return A pointer to the allocated block. You must call PhDereferenceFilePool() or + * PhDereferenceFilePoolByRva() when you no longer need a reference to the block. + * + * \remarks The returned pointer is not valid beyond the lifetime of the file pool instance. Use the + * relative virtual address if you need a permanent reference to the allocated block. + */ +PVOID PhAllocateFilePool( + _Inout_ PPH_FILE_POOL Pool, + _In_ ULONG Size, + _Out_opt_ PULONG Rva + ) +{ + PPH_FP_BLOCK_HEADER blockHeader; + ULONG numberOfBlocks; + PPH_FP_BLOCK_HEADER firstBlock; + PPH_FP_SEGMENT_HEADER segmentHeader; + ULONG freeListIndex; + ULONG freeListLimit; + ULONG segmentIndex; + ULONG nextSegmentIndex; + ULONG newFreeListIndex; + + // Calculate the number of blocks needed for the allocation. + numberOfBlocks = (FIELD_OFFSET(PH_FP_BLOCK_HEADER, Body) + Size + Pool->BlockSize - 1) >> Pool->BlockShift; + + if (numberOfBlocks > PH_FP_BLOCK_COUNT - Pool->SegmentHeaderBlockSpan) + { + // TODO: Perform a large allocation. + return NULL; + } + + // Scan each applicable free list and try to allocate from those segments. + + freeListLimit = PhFppComputeFreeListIndex(Pool, numberOfBlocks); + + for (freeListIndex = 0; freeListIndex <= freeListLimit; freeListIndex++) + { + segmentIndex = Pool->Header->FreeLists[freeListIndex]; + + while (segmentIndex != -1) + { + firstBlock = PhFppReferenceSegment(Pool, segmentIndex); + + if (!firstBlock) + return NULL; + + segmentHeader = PhFppGetHeaderSegment(Pool, firstBlock); + nextSegmentIndex = segmentHeader->FreeFlink; + + blockHeader = PhFppAllocateBlocks(Pool, firstBlock, segmentHeader, numberOfBlocks); + + if (blockHeader) + goto BlockAllocated; + + PhFppDereferenceSegment(Pool, segmentIndex); + segmentIndex = nextSegmentIndex; + } + } + + // No segments have the required number of contiguous free blocks. Allocate a new one. + + firstBlock = PhFppAllocateSegment(Pool, &segmentIndex); + + if (!firstBlock) + return NULL; + + freeListIndex = 0; + segmentHeader = PhFppGetHeaderSegment(Pool, firstBlock); + blockHeader = PhFppAllocateBlocks(Pool, firstBlock, segmentHeader, numberOfBlocks); + + if (!blockHeader) + { + PhFppDereferenceSegment(Pool, segmentIndex); + return NULL; + } + +BlockAllocated: + + // Compute the new free list index of the segment and move it to another free list if necessary. + + newFreeListIndex = PhFppComputeFreeListIndex(Pool, segmentHeader->FreeBlocks); + + if (newFreeListIndex != freeListIndex) + { + PhFppRemoveFreeList(Pool, freeListIndex, segmentIndex, segmentHeader); + PhFppInsertFreeList(Pool, newFreeListIndex, segmentIndex, segmentHeader); + } + + if (Rva) + { + *Rva = PhFppEncodeRva(Pool, segmentIndex, firstBlock, &blockHeader->Body); + } + + return &blockHeader->Body; +} + +/** + * Frees a block. + * + * \param Pool The file pool. + * \param SegmentIndex The index of the segment containing the block. + * \param FirstBlock The first block of the segment containing the block. + * \param Block A pointer to the block. + */ +VOID PhpFreeFilePool( + _Inout_ PPH_FILE_POOL Pool, + _In_ ULONG SegmentIndex, + _In_ PPH_FP_BLOCK_HEADER FirstBlock, + _In_ PVOID Block + ) +{ + PPH_FP_SEGMENT_HEADER segmentHeader; + ULONG oldFreeListIndex; + ULONG newFreeListIndex; + + segmentHeader = PhFppGetHeaderSegment(Pool, FirstBlock); + oldFreeListIndex = PhFppComputeFreeListIndex(Pool, segmentHeader->FreeBlocks); + PhFppFreeBlocks(Pool, FirstBlock, segmentHeader, PhFppGetHeaderBlock(Pool, Block)); + newFreeListIndex = PhFppComputeFreeListIndex(Pool, segmentHeader->FreeBlocks); + + // Move the segment into another free list if needed. + if (newFreeListIndex != oldFreeListIndex) + { + PhFppRemoveFreeList(Pool, oldFreeListIndex, SegmentIndex, segmentHeader); + PhFppInsertFreeList(Pool, newFreeListIndex, SegmentIndex, segmentHeader); + } +} + +/** + * Frees a block allocated by PhAllocateFilePool(). + * + * \param Pool The file pool. + * \param Block A pointer to the block. The pointer is no longer valid after you call this function. + * Do not use PhDereferenceFilePool() or PhDereferenceFilePoolByRva(). + */ +VOID PhFreeFilePool( + _Inout_ PPH_FILE_POOL Pool, + _In_ PVOID Block + ) +{ + PPH_FILE_POOL_VIEW view; + PPH_FP_BLOCK_HEADER firstBlock; + + view = PhFppFindViewByBase(Pool, Block); + + if (!view) + PhRaiseStatus(STATUS_INVALID_PARAMETER_2); + + firstBlock = view->Base; + PhpFreeFilePool(Pool, view->SegmentIndex, firstBlock, Block); + PhFppDereferenceView(Pool, view); +} + +/** + * Frees a block allocated by PhAllocateFilePool(). + * + * \param Pool The file pool. + * \param Rva The relative virtual address of the block. + */ +BOOLEAN PhFreeFilePoolByRva( + _Inout_ PPH_FILE_POOL Pool, + _In_ ULONG Rva + ) +{ + ULONG segmentIndex; + ULONG offset; + PPH_FP_BLOCK_HEADER firstBlock; + + offset = PhFppDecodeRva(Pool, Rva, &segmentIndex); + + if (offset == -1) + return FALSE; + + firstBlock = PhFppReferenceSegment(Pool, segmentIndex); + + if (!firstBlock) + return FALSE; + + PhpFreeFilePool(Pool, segmentIndex, firstBlock, (PCHAR)firstBlock + offset); + PhFppDereferenceSegment(Pool, segmentIndex); + + return TRUE; +} + +/** + * Increments the reference count for the specified address. + * + * \param Pool The file pool. + * \param Address An address. + */ +VOID PhReferenceFilePool( + _Inout_ PPH_FILE_POOL Pool, + _In_ PVOID Address + ) +{ + PhFppReferenceSegmentByBase(Pool, Address); +} + +/** + * Decrements the reference count for the specified address. + * + * \param Pool The file pool. + * \param Address An address. + */ +VOID PhDereferenceFilePool( + _Inout_ PPH_FILE_POOL Pool, + _In_ PVOID Address + ) +{ + PhFppDereferenceSegmentByBase(Pool, Address); +} + +/** + * Obtains a pointer for a relative virtual address, incrementing the reference count of the + * address. + * + * \param Pool The file pool. + * \param Rva A relative virtual address. + */ +PVOID PhReferenceFilePoolByRva( + _Inout_ PPH_FILE_POOL Pool, + _In_ ULONG Rva + ) +{ + ULONG segmentIndex; + ULONG offset; + PPH_FP_BLOCK_HEADER firstBlock; + + if (Rva == 0) + return NULL; + + offset = PhFppDecodeRva(Pool, Rva, &segmentIndex); + + if (offset == -1) + return NULL; + + firstBlock = PhFppReferenceSegment(Pool, segmentIndex); + + if (!firstBlock) + return NULL; + + return (PCHAR)firstBlock + offset; +} + +/** + * Decrements the reference count for the specified relative virtual address. + * + * \param Pool The file pool. + * \param Rva A relative virtual address. + */ +BOOLEAN PhDereferenceFilePoolByRva( + _Inout_ PPH_FILE_POOL Pool, + _In_ ULONG Rva + ) +{ + ULONG segmentIndex; + ULONG offset; + + offset = PhFppDecodeRva(Pool, Rva, &segmentIndex); + + if (offset == -1) + return FALSE; + + PhFppDereferenceSegment(Pool, segmentIndex); + + return TRUE; +} + +/** + * Obtains a relative virtual address for a pointer. + * + * \param Pool The file pool. + * \param Address A pointer. + * + * \return The relative virtual address. + * + * \remarks No reference counts are changed. + */ +ULONG PhEncodeRvaFilePool( + _In_ PPH_FILE_POOL Pool, + _In_ PVOID Address + ) +{ + PPH_FILE_POOL_VIEW view; + + if (!Address) + return 0; + + view = PhFppFindViewByBase(Pool, Address); + + if (!view) + PhRaiseStatus(STATUS_INVALID_PARAMETER_2); + + return PhFppEncodeRva(Pool, view->SegmentIndex, view->Base, Address); +} + +/** + * Retrieves user data. + * + * \param Pool The file pool. + * \param Context A variable which receives the user data. + */ +VOID PhGetUserContextFilePool( + _In_ PPH_FILE_POOL Pool, + _Out_ PULONGLONG Context + ) +{ + *Context = Pool->Header->UserContext; +} + +/** + * Stores user data. + * + * \param Pool The file pool. + * \param Context A variable which contains the user data. + */ +VOID PhSetUserContextFilePool( + _Inout_ PPH_FILE_POOL Pool, + _In_ PULONGLONG Context + ) +{ + Pool->Header->UserContext = *Context; +} + +/** + * Extends a file pool. + * + * \param Pool The file pool. + * \param NewSize The new size of the file, in bytes. + */ +NTSTATUS PhFppExtendRange( + _Inout_ PPH_FILE_POOL Pool, + _In_ ULONG NewSize + ) +{ + LARGE_INTEGER newSectionSize; + + newSectionSize.QuadPart = NewSize; + + return NtExtendSection(Pool->SectionHandle, &newSectionSize); +} + +/** + * Maps in a view of a file pool. + * + * \param Pool The file pool. + * \param Offset The offset of the view, in bytes. + * \param Size The size of the view, in bytes. + * \param Base A variable which receives the base address of the view. + */ +NTSTATUS PhFppMapRange( + _Inout_ PPH_FILE_POOL Pool, + _In_ ULONG Offset, + _In_ ULONG Size, + _Out_ PVOID *Base + ) +{ + NTSTATUS status; + PVOID baseAddress; + LARGE_INTEGER sectionOffset; + SIZE_T viewSize; + + baseAddress = NULL; + sectionOffset.QuadPart = Offset; + viewSize = Size; + + status = NtMapViewOfSection( + Pool->SectionHandle, + NtCurrentProcess(), + &baseAddress, + 0, + viewSize, + §ionOffset, + &viewSize, + ViewShare, + 0, + !Pool->ReadOnly ? PAGE_READWRITE : PAGE_READONLY + ); + + if (NT_SUCCESS(status)) + *Base = baseAddress; + + return status; +} + +/** + * Unmaps a view of a file pool. + * + * \param Pool The file pool. + * \param Base The base address of the view. + */ +NTSTATUS PhFppUnmapRange( + _Inout_ PPH_FILE_POOL Pool, + _In_ PVOID Base + ) +{ + return NtUnmapViewOfSection(NtCurrentProcess(), Base); +} + +/** + * Initializes a segment. + * + * \param Pool The file pool. + * \param BlockOfSegmentHeader The block header of the span containing the segment header. + * \param AdditionalBlocksUsed The number of blocks already allocated from the segment, excluding + * the blocks comprising the segment header. + */ +VOID PhFppInitializeSegment( + _Inout_ PPH_FILE_POOL Pool, + _Out_ PPH_FP_BLOCK_HEADER BlockOfSegmentHeader, + _In_ ULONG AdditionalBlocksUsed + ) +{ + PPH_FP_SEGMENT_HEADER segmentHeader; + RTL_BITMAP bitmap; + + BlockOfSegmentHeader->Span = Pool->SegmentHeaderBlockSpan; + segmentHeader = (PPH_FP_SEGMENT_HEADER)&BlockOfSegmentHeader->Body; + + RtlInitializeBitMap(&bitmap, segmentHeader->Bitmap, PH_FP_BLOCK_COUNT); + RtlSetBits(&bitmap, 0, Pool->SegmentHeaderBlockSpan + AdditionalBlocksUsed); + segmentHeader->FreeBlocks = PH_FP_BLOCK_COUNT - (Pool->SegmentHeaderBlockSpan + AdditionalBlocksUsed); + segmentHeader->FreeFlink = -1; + segmentHeader->FreeBlink = -1; +} + +/** + * Allocates a segment. + * + * \param Pool The file pool. + * \param NewSegmentIndex A variable which receives the index of the new segment. + * + * \return A pointer to the first block of the segment. + */ +PPH_FP_BLOCK_HEADER PhFppAllocateSegment( + _Inout_ PPH_FILE_POOL Pool, + _Out_ PULONG NewSegmentIndex + ) +{ + ULONG newSize; + ULONG segmentIndex; + PPH_FP_BLOCK_HEADER firstBlock; + PPH_FP_SEGMENT_HEADER segmentHeader; + + newSize = (Pool->Header->SegmentCount + 1) << Pool->SegmentShift; + + if (!NT_SUCCESS(PhFppExtendRange(Pool, newSize))) + return NULL; + + segmentIndex = Pool->Header->SegmentCount++; + firstBlock = PhFppReferenceSegment(Pool, segmentIndex); + PhFppInitializeSegment(Pool, firstBlock, 0); + segmentHeader = (PPH_FP_SEGMENT_HEADER)&firstBlock->Body; + + PhFppInsertFreeList(Pool, 0, segmentIndex, segmentHeader); + + *NewSegmentIndex = segmentIndex; + + return firstBlock; +} + +/** + * Retrieves the header of a segment. + * + * \param Pool The file pool. + * \param FirstBlock The first block of the segment. + */ +PPH_FP_SEGMENT_HEADER PhFppGetHeaderSegment( + _Inout_ PPH_FILE_POOL Pool, + _In_ PPH_FP_BLOCK_HEADER FirstBlock + ) +{ + if (FirstBlock != Pool->FirstBlockOfFirstSegment) + { + return (PPH_FP_SEGMENT_HEADER)&FirstBlock->Body; + } + else + { + // In the first segment, the segment header is after the file header. + return (PPH_FP_SEGMENT_HEADER)&((PPH_FP_BLOCK_HEADER)((PCHAR)FirstBlock + (Pool->FileHeaderBlockSpan << Pool->BlockShift)))->Body; + } +} + +VOID PhFppAddViewByIndex( + _Inout_ PPH_FILE_POOL Pool, + _Inout_ PPH_FILE_POOL_VIEW View + ) +{ + ULONG index; + PLIST_ENTRY head; + + index = View->SegmentIndex & (Pool->ByIndexSize - 1); + head = Pool->ByIndexBuckets[index]; + + if (head) + { + InsertHeadList(head, &View->ByIndexListEntry); + } + else + { + InitializeListHead(&View->ByIndexListEntry); + Pool->ByIndexBuckets[index] = &View->ByIndexListEntry; + } +} + +VOID PhFppRemoveViewByIndex( + _Inout_ PPH_FILE_POOL Pool, + _Inout_ PPH_FILE_POOL_VIEW View + ) +{ + ULONG index; + PLIST_ENTRY head; + + index = View->SegmentIndex & (Pool->ByIndexSize - 1); + head = Pool->ByIndexBuckets[index]; + assert(head); + + // Unlink the entry from the chain. + RemoveEntryList(&View->ByIndexListEntry); + + if (&View->ByIndexListEntry == head) + { + // This entry is currently the chain head. + + // If this was the last entry in the chain, then indicate that the chain is empty. + // Otherwise, choose a new head. + + if (IsListEmpty(head)) + Pool->ByIndexBuckets[index] = NULL; + else + Pool->ByIndexBuckets[index] = head->Flink; + } +} + +/** + * Finds a view for the specified segment. + * + * \param Pool The file pool. + * \param SegmentIndex The index of the segment. + * + * \return The view for the segment, or NULL if no view is present for the segment. + */ +PPH_FILE_POOL_VIEW PhFppFindViewByIndex( + _Inout_ PPH_FILE_POOL Pool, + _In_ ULONG SegmentIndex + ) +{ + ULONG index; + PLIST_ENTRY head; + PLIST_ENTRY entry; + PPH_FILE_POOL_VIEW view; + + index = SegmentIndex & (Pool->ByIndexSize - 1); + head = Pool->ByIndexBuckets[index]; + + if (!head) + return NULL; + + entry = head; + + do + { + view = CONTAINING_RECORD(entry, PH_FILE_POOL_VIEW, ByIndexListEntry); + + if (view->SegmentIndex == SegmentIndex) + return view; + + entry = entry->Flink; + } while (entry != head); + + return NULL; +} + +LONG NTAPI PhpFilePoolViewByBaseCompareFunction( + _In_ PPH_AVL_LINKS Links1, + _In_ PPH_AVL_LINKS Links2 + ) +{ + PPH_FILE_POOL_VIEW view1 = CONTAINING_RECORD(Links1, PH_FILE_POOL_VIEW, ByBaseLinks); + PPH_FILE_POOL_VIEW view2 = CONTAINING_RECORD(Links2, PH_FILE_POOL_VIEW, ByBaseLinks); + + return uintptrcmp((ULONG_PTR)view1->Base, (ULONG_PTR)view2->Base); +} + +VOID PhFppAddViewByBase( + _Inout_ PPH_FILE_POOL Pool, + _Inout_ PPH_FILE_POOL_VIEW View + ) +{ + PhAddElementAvlTree(&Pool->ByBaseSet, &View->ByBaseLinks); +} + +VOID PhFppRemoveViewByBase( + _Inout_ PPH_FILE_POOL Pool, + _Inout_ PPH_FILE_POOL_VIEW View + ) +{ + PhRemoveElementAvlTree(&Pool->ByBaseSet, &View->ByBaseLinks); +} + +/** + * Finds a view containing the specified address. + * + * \param Pool The file pool. + * \param Base The address. + * + * \return The view containing the address, or NULL if no view is present for the address. + */ +PPH_FILE_POOL_VIEW PhFppFindViewByBase( + _Inout_ PPH_FILE_POOL Pool, + _In_ PVOID Base + ) +{ + PPH_FILE_POOL_VIEW view; + PPH_AVL_LINKS links; + PH_FILE_POOL_VIEW lookupView; + + // This is an approximate search to find the target view in which the specified address lies. + + lookupView.Base = Base; + links = PhUpperDualBoundElementAvlTree(&Pool->ByBaseSet, &lookupView.ByBaseLinks); + + if (!links) + return NULL; + + view = CONTAINING_RECORD(links, PH_FILE_POOL_VIEW, ByBaseLinks); + + if ((ULONG_PTR)Base < (ULONG_PTR)view->Base + Pool->SegmentSize) + return view; + + return NULL; +} + +PPH_FILE_POOL_VIEW PhFppCreateView( + _Inout_ PPH_FILE_POOL Pool, + _In_ ULONG SegmentIndex + ) +{ + PPH_FILE_POOL_VIEW view; + PVOID base; + + // Map in the segment. + if (!NT_SUCCESS(PhFppMapRange(Pool, SegmentIndex << Pool->SegmentShift, Pool->SegmentSize, &base))) + return NULL; + + // Create and add the view entry. + + view = PhAllocateFromFreeList(&Pool->ViewFreeList); + memset(view, 0, sizeof(PH_FILE_POOL_VIEW)); + + view->RefCount = 1; + view->SegmentIndex = SegmentIndex; + view->Base = base; + + PhFppAddViewByIndex(Pool, view); + PhFppAddViewByBase(Pool, view); + + return view; +} + +VOID PhFppDestroyView( + _Inout_ PPH_FILE_POOL Pool, + _Inout_ PPH_FILE_POOL_VIEW View + ) +{ + PhFppUnmapRange(Pool, View->Base); + PhFppRemoveViewByIndex(Pool, View); + PhFppRemoveViewByBase(Pool, View); + + PhFreeToFreeList(&Pool->ViewFreeList, View); +} + +VOID PhFppActivateView( + _Inout_ PPH_FILE_POOL Pool, + _Inout_ PPH_FILE_POOL_VIEW View + ) +{ + RemoveEntryList(&View->InactiveViewsListEntry); + Pool->NumberOfInactiveViews--; +} + +VOID PhFppDeactivateView( + _Inout_ PPH_FILE_POOL Pool, + _Inout_ PPH_FILE_POOL_VIEW View + ) +{ + InsertHeadList(&Pool->InactiveViewsListHead, &View->InactiveViewsListEntry); + Pool->NumberOfInactiveViews++; + + // If we have too many inactive views, destroy the least recent ones. + while (Pool->NumberOfInactiveViews > Pool->MaximumInactiveViews) + { + PLIST_ENTRY lruEntry; + PPH_FILE_POOL_VIEW lruView; + + lruEntry = RemoveTailList(&Pool->InactiveViewsListHead); + Pool->NumberOfInactiveViews--; + + assert(lruEntry != &Pool->InactiveViewsListHead); + lruView = CONTAINING_RECORD(lruEntry, PH_FILE_POOL_VIEW, InactiveViewsListEntry); + PhFppDestroyView(Pool, lruView); + } +} + +VOID PhFppReferenceView( + _Inout_ PPH_FILE_POOL Pool, + _Inout_ PPH_FILE_POOL_VIEW View + ) +{ + if (View->RefCount == 0) + { + // The view is inactive, so make it active. + PhFppActivateView(Pool, View); + } + + View->RefCount++; +} + +VOID PhFppDereferenceView( + _Inout_ PPH_FILE_POOL Pool, + _Inout_ PPH_FILE_POOL_VIEW View + ) +{ + if (--View->RefCount == 0) + { + if (View->SegmentIndex == 0) + PhRaiseStatus(STATUS_INTERNAL_ERROR); + + PhFppDeactivateView(Pool, View); + } +} + +PPH_FP_BLOCK_HEADER PhFppReferenceSegment( + _Inout_ PPH_FILE_POOL Pool, + _In_ ULONG SegmentIndex + ) +{ + PPH_FILE_POOL_VIEW view; + + // Validate parameters. + if (SegmentIndex != 0 && SegmentIndex >= Pool->Header->SegmentCount) + return NULL; + + // Try to get a cached view. + + view = PhFppFindViewByIndex(Pool, SegmentIndex); + + if (view) + { + PhFppReferenceView(Pool, view); + + return (PPH_FP_BLOCK_HEADER)view->Base; + } + + // No cached view, so create one. + + view = PhFppCreateView(Pool, SegmentIndex); + + if (!view) + return NULL; + + return (PPH_FP_BLOCK_HEADER)view->Base; +} + +VOID PhFppDereferenceSegment( + _Inout_ PPH_FILE_POOL Pool, + _In_ ULONG SegmentIndex + ) +{ + PPH_FILE_POOL_VIEW view; + + view = PhFppFindViewByIndex(Pool, SegmentIndex); + + if (!view) + PhRaiseStatus(STATUS_INTERNAL_ERROR); + + PhFppDereferenceView(Pool, view); +} + +VOID PhFppReferenceSegmentByBase( + _Inout_ PPH_FILE_POOL Pool, + _In_ PVOID Base + ) +{ + PPH_FILE_POOL_VIEW view; + + view = PhFppFindViewByBase(Pool, Base); + + if (!view) + PhRaiseStatus(STATUS_INTERNAL_ERROR); + + PhFppReferenceView(Pool, view); +} + +VOID PhFppDereferenceSegmentByBase( + _Inout_ PPH_FILE_POOL Pool, + _In_ PVOID Base + ) +{ + PPH_FILE_POOL_VIEW view; + + view = PhFppFindViewByBase(Pool, Base); + + if (!view) + PhRaiseStatus(STATUS_INTERNAL_ERROR); + + PhFppDereferenceView(Pool, view); +} + +/** + * Allocates blocks from a segment. + * + * \param Pool The file pool. + * \param FirstBlock The first block of the segment. + * \param SegmentHeader The header of the segment. + * \param NumberOfBlocks The number of blocks to allocate. + * + * \return The header of the allocated span, or NULL if there is an insufficient number of + * contiguous free blocks for the allocation. + */ +PPH_FP_BLOCK_HEADER PhFppAllocateBlocks( + _Inout_ PPH_FILE_POOL Pool, + _In_ PPH_FP_BLOCK_HEADER FirstBlock, + _Inout_ PPH_FP_SEGMENT_HEADER SegmentHeader, + _In_ ULONG NumberOfBlocks + ) +{ + RTL_BITMAP bitmap; + ULONG hintIndex; + ULONG foundIndex; + PPH_FP_BLOCK_HEADER blockHeader; + + if (FirstBlock != Pool->FirstBlockOfFirstSegment) + hintIndex = Pool->SegmentHeaderBlockSpan; + else + hintIndex = Pool->SegmentHeaderBlockSpan + Pool->FileHeaderBlockSpan; + + RtlInitializeBitMap(&bitmap, SegmentHeader->Bitmap, PH_FP_BLOCK_COUNT); + + // Find a range of free blocks and mark them as in-use. + foundIndex = RtlFindClearBitsAndSet(&bitmap, NumberOfBlocks, hintIndex); + + if (foundIndex == -1) + { + // No more space. + return NULL; + } + + SegmentHeader->FreeBlocks -= NumberOfBlocks; + + blockHeader = (PPH_FP_BLOCK_HEADER)((PCHAR)FirstBlock + (foundIndex << Pool->BlockShift)); + blockHeader->Flags = 0; + blockHeader->Span = NumberOfBlocks; + + return blockHeader; +} + +/** + * Frees blocks in a segment. + * + * \param Pool The file pool. + * \param FirstBlock The first block of the segment. + * \param SegmentHeader The header of the segment. + * \param BlockHeader The header of the allocated span. + */ +VOID PhFppFreeBlocks( + _Inout_ PPH_FILE_POOL Pool, + _In_ PPH_FP_BLOCK_HEADER FirstBlock, + _Inout_ PPH_FP_SEGMENT_HEADER SegmentHeader, + _In_ PPH_FP_BLOCK_HEADER BlockHeader + ) +{ + RTL_BITMAP bitmap; + ULONG startIndex; + ULONG blockSpan; + + RtlInitializeBitMap(&bitmap, SegmentHeader->Bitmap, PH_FP_BLOCK_COUNT); + + // Mark the blocks as free. + startIndex = (ULONG)((PCHAR)BlockHeader - (PCHAR)FirstBlock) >> Pool->BlockShift; + blockSpan = BlockHeader->Span; + RtlClearBits(&bitmap, startIndex, blockSpan); + SegmentHeader->FreeBlocks += blockSpan; +} + +/** + * Computes the free list index (category) for a specified number of blocks. + * + * \param Pool The file pool. + * \param NumberOfBlocks The number of free or required blocks. + */ +ULONG PhFppComputeFreeListIndex( + _In_ PPH_FILE_POOL Pool, + _In_ ULONG NumberOfBlocks + ) +{ + // Use a binary tree to speed up comparison. + + if (NumberOfBlocks >= PH_FP_BLOCK_COUNT / 64) + { + if (NumberOfBlocks >= PH_FP_BLOCK_COUNT / 2) + { + if (NumberOfBlocks >= PH_FP_BLOCK_COUNT - Pool->SegmentHeaderBlockSpan) + return 0; + else + return 1; + } + else + { + if (NumberOfBlocks >= PH_FP_BLOCK_COUNT / 16) + return 2; + else + return 3; + } + } + else + { + if (NumberOfBlocks >= 4) + { + if (NumberOfBlocks >= PH_FP_BLOCK_COUNT / 256) + return 4; + else + return 5; + } + else + { + if (NumberOfBlocks >= 1) + return 6; + else + return 7; + } + } +} + +/** + * Inserts a segment into a free list. + * + * \param Pool The file pool. + * \param FreeListIndex The index of a free list. + * \param SegmentIndex The index of the segment. + * \param SegmentHeader The header of the segment. + */ +BOOLEAN PhFppInsertFreeList( + _Inout_ PPH_FILE_POOL Pool, + _In_ ULONG FreeListIndex, + _In_ ULONG SegmentIndex, + _In_ PPH_FP_SEGMENT_HEADER SegmentHeader + ) +{ + ULONG oldSegmentIndex; + PPH_FP_BLOCK_HEADER oldSegmentFirstBlock; + PPH_FP_SEGMENT_HEADER oldSegmentHeader; + + oldSegmentIndex = Pool->Header->FreeLists[FreeListIndex]; + + // Try to reference the segment before we commit any changes. + + if (oldSegmentIndex != -1) + { + oldSegmentFirstBlock = PhFppReferenceSegment(Pool, oldSegmentIndex); + + if (!oldSegmentFirstBlock) + return FALSE; + } + + // Insert the segment into the list. + + SegmentHeader->FreeBlink = -1; + SegmentHeader->FreeFlink = oldSegmentIndex; + Pool->Header->FreeLists[FreeListIndex] = SegmentIndex; + + if (oldSegmentIndex != -1) + { + oldSegmentHeader = PhFppGetHeaderSegment(Pool, oldSegmentFirstBlock); + oldSegmentHeader->FreeBlink = SegmentIndex; + PhFppDereferenceSegment(Pool, oldSegmentIndex); + } + + return TRUE; +} + +/** + * Removes a segment from a free list. + * + * \param Pool The file pool. + * \param FreeListIndex The index of a free list. + * \param SegmentIndex The index of the segment. + * \param SegmentHeader The header of the segment. + */ +BOOLEAN PhFppRemoveFreeList( + _Inout_ PPH_FILE_POOL Pool, + _In_ ULONG FreeListIndex, + _In_ ULONG SegmentIndex, + _In_ PPH_FP_SEGMENT_HEADER SegmentHeader + ) +{ + ULONG flinkSegmentIndex; + PPH_FP_BLOCK_HEADER flinkSegmentFirstBlock; + PPH_FP_SEGMENT_HEADER flinkSegmentHeader; + ULONG blinkSegmentIndex; + PPH_FP_BLOCK_HEADER blinkSegmentFirstBlock; + PPH_FP_SEGMENT_HEADER blinkSegmentHeader; + + flinkSegmentIndex = SegmentHeader->FreeFlink; + blinkSegmentIndex = SegmentHeader->FreeBlink; + + // Try to reference the segments before we commit any changes. + + if (flinkSegmentIndex != -1) + { + flinkSegmentFirstBlock = PhFppReferenceSegment(Pool, flinkSegmentIndex); + + if (!flinkSegmentFirstBlock) + return FALSE; + } + + if (blinkSegmentIndex != -1) + { + blinkSegmentFirstBlock = PhFppReferenceSegment(Pool, blinkSegmentIndex); + + if (!blinkSegmentFirstBlock) + { + if (flinkSegmentIndex != -1) + PhFppDereferenceSegment(Pool, flinkSegmentIndex); + + return FALSE; + } + } + + // Unlink the segment from the list. + + if (flinkSegmentIndex != -1) + { + flinkSegmentHeader = PhFppGetHeaderSegment(Pool, flinkSegmentFirstBlock); + flinkSegmentHeader->FreeBlink = blinkSegmentIndex; + PhFppDereferenceSegment(Pool, flinkSegmentIndex); + } + + if (blinkSegmentIndex != -1) + { + blinkSegmentHeader = PhFppGetHeaderSegment(Pool, blinkSegmentFirstBlock); + blinkSegmentHeader->FreeFlink = flinkSegmentIndex; + PhFppDereferenceSegment(Pool, blinkSegmentIndex); + } + else + { + // The segment was the list head; select a new one. + Pool->Header->FreeLists[FreeListIndex] = flinkSegmentIndex; + } + + return TRUE; +} + +/** + * Retrieves the header of a block. + * + * \param Pool The file pool. + * \param Block A pointer to the body of the block. + */ +PPH_FP_BLOCK_HEADER PhFppGetHeaderBlock( + _In_ PPH_FILE_POOL Pool, + _In_ PVOID Block + ) +{ + return CONTAINING_RECORD(Block, PH_FP_BLOCK_HEADER, Body); +} + +/** + * Creates a relative virtual address. + * + * \param Pool The file pool. + * \param SegmentIndex The index of the segment containing \a Address. + * \param FirstBlock The first block of the segment containing \a Address. + * \param Address An address. + */ +ULONG PhFppEncodeRva( + _In_ PPH_FILE_POOL Pool, + _In_ ULONG SegmentIndex, + _In_ PPH_FP_BLOCK_HEADER FirstBlock, + _In_ PVOID Address + ) +{ + return (SegmentIndex << Pool->SegmentShift) + (ULONG)((PCHAR)Address - (PCHAR)FirstBlock); +} + +/** + * Decodes a relative virtual address. + * + * \param Pool The file pool. + * \param Rva The relative virtual address. + * \param SegmentIndex A variable which receives the segment index. + * + * \return An offset into the segment specified by \a SegmentIndex, or -1 if \a Rva is invalid. + */ +ULONG PhFppDecodeRva( + _In_ PPH_FILE_POOL Pool, + _In_ ULONG Rva, + _Out_ PULONG SegmentIndex + ) +{ + ULONG segmentIndex; + + segmentIndex = Rva >> Pool->SegmentShift; + + if (segmentIndex >= Pool->Header->SegmentCount) + return -1; + + *SegmentIndex = segmentIndex; + + return Rva & (Pool->SegmentSize - 1); +} diff --git a/phlib/format.c b/phlib/format.c index ec036cd0dd6f..b45fd38439c4 100644 --- a/phlib/format.c +++ b/phlib/format.c @@ -1,277 +1,277 @@ -/* - * Process Hacker - - * string formatting - * - * Copyright (C) 2010-2015 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -/* - * This module provides a high-performance string formatting mechanism. Instead of using format - * strings, the user supplies an array of structures. This system is 2-5 times faster than - * printf-based functions. - * - * This file contains the public interfaces, while including the real formatting code from - * elsewhere. There are currently two functions: PhFormat, which returns a string object containing - * the formatted string, and PhFormatToBuffer, which writes the formatted string to a buffer. The - * latter is a bit faster due to the lack of resizing logic. - */ - -#include - -#include - -extern ULONG PhMaxSizeUnit; - -#define SMALL_BUFFER_LENGTH (PH_OBJECT_SMALL_OBJECT_SIZE - FIELD_OFFSET(PH_STRING, Data) - sizeof(WCHAR)) -#define BUFFER_SIZE 512 - -#define PHP_FORMAT_NEGATIVE 0x1 -#define PHP_FORMAT_POSITIVE 0x2 -#define PHP_FORMAT_PAD 0x4 - -// Internal CRT routine needed for floating-point conversion - -errno_t __cdecl _cfltcvt_l(double *arg, char *buffer, size_t sizeInBytes, - int format, int precision, int caps, _locale_t plocinfo); - -// Keep in sync with PhSizeUnitNames -static PH_STRINGREF PhpSizeUnitNamesCounted[7] = -{ - PH_STRINGREF_INIT(L"B"), - PH_STRINGREF_INIT(L"kB"), - PH_STRINGREF_INIT(L"MB"), - PH_STRINGREF_INIT(L"GB"), - PH_STRINGREF_INIT(L"TB"), - PH_STRINGREF_INIT(L"PB"), - PH_STRINGREF_INIT(L"EB") -}; - -static PH_INITONCE PhpFormatInitOnce = PH_INITONCE_INIT; -static WCHAR PhpFormatDecimalSeparator = '.'; -static WCHAR PhpFormatThousandSeparator = ','; -static _locale_t PhpFormatUserLocale = NULL; - -#if (_MSC_VER >= 1900) - -// See Source\10.0.10150.0\ucrt\convert\cvt.cpp in SDK v10. -errno_t __cdecl __acrt_fp_format( - double const* const value, - char* const result_buffer, - size_t const result_buffer_count, - char* const scratch_buffer, - size_t const scratch_buffer_count, - int const format, - int const precision, - UINT64 const options, - _locale_t const locale - ); - -static errno_t __cdecl _cfltcvt_l(double *arg, char *buffer, size_t sizeInBytes, - int format, int precision, int caps, _locale_t plocinfo) -{ - char scratch_buffer[_CVTBUFSIZE + 1]; - - if (caps & 1) - format -= 32; // Make uppercase - - return __acrt_fp_format(arg, buffer, sizeInBytes, scratch_buffer, sizeof(scratch_buffer), - format, precision, 0, plocinfo); -} - -#endif - -// From Source\10.0.10150.0\ucrt\inc\corecrt_internal_stdio_output.h in SDK v10. -VOID PhpCropZeros( - _Inout_ PCHAR Buffer, - _In_ _locale_t Locale - ) -{ - CHAR decimalSeparator = (CHAR)PhpFormatDecimalSeparator; - - while (*Buffer && *Buffer != decimalSeparator) - ++Buffer; - - if (*Buffer++) - { - while (*Buffer && *Buffer != 'e' && *Buffer != 'E') - ++Buffer; - - PCHAR stop = Buffer--; - - while (*Buffer == '0') - --Buffer; - - if (*Buffer == decimalSeparator) - --Buffer; - - while ((*++Buffer = *stop++) != '\0') - NOTHING; - } -} - -PPH_STRING PhpResizeFormatBuffer( - _In_ PPH_STRING String, - _Inout_ PSIZE_T AllocatedLength, - _In_ SIZE_T UsedLength, - _In_ SIZE_T NeededLength - ) -{ - PPH_STRING newString; - SIZE_T allocatedLength; - - allocatedLength = *AllocatedLength; - allocatedLength *= 2; - - if (allocatedLength < UsedLength + NeededLength) - allocatedLength = UsedLength + NeededLength; - - newString = PhCreateStringEx(NULL, allocatedLength); - memcpy(newString->Buffer, String->Buffer, UsedLength); - PhDereferenceObject(String); - - *AllocatedLength = allocatedLength; - - return newString; -} - -/** - * Creates a formatted string. - * - * \param Format An array of format structures. - * \param Count The number of structures supplied in \a Format. - * \param InitialCapacity The number of bytes to reserve initially for the string. If 0 is - * specified, a default value is used. - */ -PPH_STRING PhFormat( - _In_reads_(Count) PPH_FORMAT Format, - _In_ ULONG Count, - _In_opt_ SIZE_T InitialCapacity - ) -{ - PPH_STRING string; - SIZE_T allocatedLength; - PWSTR buffer; - SIZE_T usedLength; - - // Set up the buffer. - - // If the specified initial capacity is too small (or zero), use the largest buffer size which - // will still be eligible for allocation from the small object free list. - if (InitialCapacity < SMALL_BUFFER_LENGTH) - InitialCapacity = SMALL_BUFFER_LENGTH; - - string = PhCreateStringEx(NULL, InitialCapacity); - allocatedLength = InitialCapacity; - buffer = string->Buffer; - usedLength = 0; - -#undef ENSURE_BUFFER -#undef OK_BUFFER -#undef ADVANCE_BUFFER - -#define ENSURE_BUFFER(NeededLength) \ - do { \ - if (allocatedLength < usedLength + (NeededLength)) \ - { \ - string = PhpResizeFormatBuffer(string, &allocatedLength, usedLength, (NeededLength)); \ - buffer = string->Buffer + usedLength / sizeof(WCHAR); \ - } \ - } while (0) - -#define OK_BUFFER (TRUE) - -#define ADVANCE_BUFFER(Length) \ - do { buffer += (Length) / sizeof(WCHAR); usedLength += (Length); } while (0) - -#include "format_i.h" - - string->Length = usedLength; - // Null-terminate the string. - string->Buffer[usedLength / sizeof(WCHAR)] = 0; - - return string; -} - -/** - * Writes a formatted string to a buffer. - * - * \param Format An array of format structures. - * \param Count The number of structures supplied in \a Format. - * \param Buffer A buffer. If NULL, no data is written. - * \param BufferLength The number of bytes available in \a Buffer, including space for the null - * terminator. - * \param ReturnLength The number of bytes required to hold the string, including the null - * terminator. - * - * \return TRUE if the buffer was large enough and the string was written (i.e. \a BufferLength >= - * \a ReturnLength), otherwise FALSE. In either case, the required number of bytes is stored in - * \a ReturnLength. - * - * \remarks If the function fails but \a BufferLength != 0, a single null byte is written to the - * start of \a Buffer. - */ -BOOLEAN PhFormatToBuffer( - _In_reads_(Count) PPH_FORMAT Format, - _In_ ULONG Count, - _Out_writes_bytes_opt_(BufferLength) PWSTR Buffer, - _In_opt_ SIZE_T BufferLength, - _Out_opt_ PSIZE_T ReturnLength - ) -{ - PWSTR buffer; - SIZE_T usedLength; - BOOLEAN overrun; - - buffer = Buffer; - usedLength = 0; - overrun = FALSE; - - // Make sure we don't try to write anything if we don't have a buffer. - if (!Buffer) - overrun = TRUE; - -#undef ENSURE_BUFFER -#undef OK_BUFFER -#undef ADVANCE_BUFFER - -#define ENSURE_BUFFER(NeededLength) \ - do { \ - if (!overrun && (BufferLength < usedLength + (NeededLength))) \ - overrun = TRUE; \ - } while (0) - -#define OK_BUFFER (!overrun) - -#define ADVANCE_BUFFER(Length) \ - do { buffer += (Length) / sizeof(WCHAR); usedLength += (Length); } while (0) - -#include "format_i.h" - - // Write the null-terminator. - ENSURE_BUFFER(sizeof(WCHAR)); - if (OK_BUFFER) - *buffer = 0; - else if (Buffer && BufferLength != 0) // try to null-terminate even if this function fails - *Buffer = 0; - ADVANCE_BUFFER(sizeof(WCHAR)); - - if (ReturnLength) - *ReturnLength = usedLength; - - return OK_BUFFER; -} +/* + * Process Hacker - + * string formatting + * + * Copyright (C) 2010-2015 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +/* + * This module provides a high-performance string formatting mechanism. Instead of using format + * strings, the user supplies an array of structures. This system is 2-5 times faster than + * printf-based functions. + * + * This file contains the public interfaces, while including the real formatting code from + * elsewhere. There are currently two functions: PhFormat, which returns a string object containing + * the formatted string, and PhFormatToBuffer, which writes the formatted string to a buffer. The + * latter is a bit faster due to the lack of resizing logic. + */ + +#include + +#include + +extern ULONG PhMaxSizeUnit; + +#define SMALL_BUFFER_LENGTH (PH_OBJECT_SMALL_OBJECT_SIZE - FIELD_OFFSET(PH_STRING, Data) - sizeof(WCHAR)) +#define BUFFER_SIZE 512 + +#define PHP_FORMAT_NEGATIVE 0x1 +#define PHP_FORMAT_POSITIVE 0x2 +#define PHP_FORMAT_PAD 0x4 + +// Internal CRT routine needed for floating-point conversion + +errno_t __cdecl _cfltcvt_l(double *arg, char *buffer, size_t sizeInBytes, + int format, int precision, int caps, _locale_t plocinfo); + +// Keep in sync with PhSizeUnitNames +static PH_STRINGREF PhpSizeUnitNamesCounted[7] = +{ + PH_STRINGREF_INIT(L"B"), + PH_STRINGREF_INIT(L"kB"), + PH_STRINGREF_INIT(L"MB"), + PH_STRINGREF_INIT(L"GB"), + PH_STRINGREF_INIT(L"TB"), + PH_STRINGREF_INIT(L"PB"), + PH_STRINGREF_INIT(L"EB") +}; + +static PH_INITONCE PhpFormatInitOnce = PH_INITONCE_INIT; +static WCHAR PhpFormatDecimalSeparator = '.'; +static WCHAR PhpFormatThousandSeparator = ','; +static _locale_t PhpFormatUserLocale = NULL; + +#if (_MSC_VER >= 1900) + +// See Source\10.0.10150.0\ucrt\convert\cvt.cpp in SDK v10. +errno_t __cdecl __acrt_fp_format( + double const* const value, + char* const result_buffer, + size_t const result_buffer_count, + char* const scratch_buffer, + size_t const scratch_buffer_count, + int const format, + int const precision, + UINT64 const options, + _locale_t const locale + ); + +static errno_t __cdecl _cfltcvt_l(double *arg, char *buffer, size_t sizeInBytes, + int format, int precision, int caps, _locale_t plocinfo) +{ + char scratch_buffer[_CVTBUFSIZE + 1]; + + if (caps & 1) + format -= 32; // Make uppercase + + return __acrt_fp_format(arg, buffer, sizeInBytes, scratch_buffer, sizeof(scratch_buffer), + format, precision, 0, plocinfo); +} + +#endif + +// From Source\10.0.10150.0\ucrt\inc\corecrt_internal_stdio_output.h in SDK v10. +VOID PhpCropZeros( + _Inout_ PCHAR Buffer, + _In_ _locale_t Locale + ) +{ + CHAR decimalSeparator = (CHAR)PhpFormatDecimalSeparator; + + while (*Buffer && *Buffer != decimalSeparator) + ++Buffer; + + if (*Buffer++) + { + while (*Buffer && *Buffer != 'e' && *Buffer != 'E') + ++Buffer; + + PCHAR stop = Buffer--; + + while (*Buffer == '0') + --Buffer; + + if (*Buffer == decimalSeparator) + --Buffer; + + while ((*++Buffer = *stop++) != '\0') + NOTHING; + } +} + +PPH_STRING PhpResizeFormatBuffer( + _In_ PPH_STRING String, + _Inout_ PSIZE_T AllocatedLength, + _In_ SIZE_T UsedLength, + _In_ SIZE_T NeededLength + ) +{ + PPH_STRING newString; + SIZE_T allocatedLength; + + allocatedLength = *AllocatedLength; + allocatedLength *= 2; + + if (allocatedLength < UsedLength + NeededLength) + allocatedLength = UsedLength + NeededLength; + + newString = PhCreateStringEx(NULL, allocatedLength); + memcpy(newString->Buffer, String->Buffer, UsedLength); + PhDereferenceObject(String); + + *AllocatedLength = allocatedLength; + + return newString; +} + +/** + * Creates a formatted string. + * + * \param Format An array of format structures. + * \param Count The number of structures supplied in \a Format. + * \param InitialCapacity The number of bytes to reserve initially for the string. If 0 is + * specified, a default value is used. + */ +PPH_STRING PhFormat( + _In_reads_(Count) PPH_FORMAT Format, + _In_ ULONG Count, + _In_opt_ SIZE_T InitialCapacity + ) +{ + PPH_STRING string; + SIZE_T allocatedLength; + PWSTR buffer; + SIZE_T usedLength; + + // Set up the buffer. + + // If the specified initial capacity is too small (or zero), use the largest buffer size which + // will still be eligible for allocation from the small object free list. + if (InitialCapacity < SMALL_BUFFER_LENGTH) + InitialCapacity = SMALL_BUFFER_LENGTH; + + string = PhCreateStringEx(NULL, InitialCapacity); + allocatedLength = InitialCapacity; + buffer = string->Buffer; + usedLength = 0; + +#undef ENSURE_BUFFER +#undef OK_BUFFER +#undef ADVANCE_BUFFER + +#define ENSURE_BUFFER(NeededLength) \ + do { \ + if (allocatedLength < usedLength + (NeededLength)) \ + { \ + string = PhpResizeFormatBuffer(string, &allocatedLength, usedLength, (NeededLength)); \ + buffer = string->Buffer + usedLength / sizeof(WCHAR); \ + } \ + } while (0) + +#define OK_BUFFER (TRUE) + +#define ADVANCE_BUFFER(Length) \ + do { buffer += (Length) / sizeof(WCHAR); usedLength += (Length); } while (0) + +#include "format_i.h" + + string->Length = usedLength; + // Null-terminate the string. + string->Buffer[usedLength / sizeof(WCHAR)] = 0; + + return string; +} + +/** + * Writes a formatted string to a buffer. + * + * \param Format An array of format structures. + * \param Count The number of structures supplied in \a Format. + * \param Buffer A buffer. If NULL, no data is written. + * \param BufferLength The number of bytes available in \a Buffer, including space for the null + * terminator. + * \param ReturnLength The number of bytes required to hold the string, including the null + * terminator. + * + * \return TRUE if the buffer was large enough and the string was written (i.e. \a BufferLength >= + * \a ReturnLength), otherwise FALSE. In either case, the required number of bytes is stored in + * \a ReturnLength. + * + * \remarks If the function fails but \a BufferLength != 0, a single null byte is written to the + * start of \a Buffer. + */ +BOOLEAN PhFormatToBuffer( + _In_reads_(Count) PPH_FORMAT Format, + _In_ ULONG Count, + _Out_writes_bytes_opt_(BufferLength) PWSTR Buffer, + _In_opt_ SIZE_T BufferLength, + _Out_opt_ PSIZE_T ReturnLength + ) +{ + PWSTR buffer; + SIZE_T usedLength; + BOOLEAN overrun; + + buffer = Buffer; + usedLength = 0; + overrun = FALSE; + + // Make sure we don't try to write anything if we don't have a buffer. + if (!Buffer) + overrun = TRUE; + +#undef ENSURE_BUFFER +#undef OK_BUFFER +#undef ADVANCE_BUFFER + +#define ENSURE_BUFFER(NeededLength) \ + do { \ + if (!overrun && (BufferLength < usedLength + (NeededLength))) \ + overrun = TRUE; \ + } while (0) + +#define OK_BUFFER (!overrun) + +#define ADVANCE_BUFFER(Length) \ + do { buffer += (Length) / sizeof(WCHAR); usedLength += (Length); } while (0) + +#include "format_i.h" + + // Write the null-terminator. + ENSURE_BUFFER(sizeof(WCHAR)); + if (OK_BUFFER) + *buffer = 0; + else if (Buffer && BufferLength != 0) // try to null-terminate even if this function fails + *Buffer = 0; + ADVANCE_BUFFER(sizeof(WCHAR)); + + if (ReturnLength) + *ReturnLength = usedLength; + + return OK_BUFFER; +} diff --git a/phlib/format_i.h b/phlib/format_i.h index e3b219abe5f9..31a5771303ed 100644 --- a/phlib/format_i.h +++ b/phlib/format_i.h @@ -1,568 +1,568 @@ -/* - * This file contains the actual formatting code used by various public interface functions. - * - * There are three macros defined by the parent function which control how this code writes the - * formatted string: - * * ENSURE_BUFFER - This macro is passed the number of bytes required whenever characters need to - * be written to the buffer. The macro can resize the buffer if needed. - * * OK_BUFFER - This macro returns TRUE if it is OK to write to the buffer, otherwise FALSE when - * the buffer is too large, is not specified, or some other error has occurred. - * * ADVANCE_BUFFER - This macro is passed the number of bytes written to the buffer and should - * increment the "buffer" pointer and "usedLength" counter. - * In addition to these macros, the "buffer" and "usedLength" variables are assumed to be present. - * - * The below code defines many macros; this is so that composite formatting types can be constructed - * (e.g. the "size" type). - */ - -{ - if (PhBeginInitOnce(&PhpFormatInitOnce)) - { - WCHAR localeBuffer[4]; - - if (GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, localeBuffer, 4) && - (localeBuffer[0] != 0 && localeBuffer[1] == 0)) - { - PhpFormatDecimalSeparator = localeBuffer[0]; - } - - if (GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, localeBuffer, 4) && - (localeBuffer[0] != 0 && localeBuffer[1] == 0)) - { - PhpFormatThousandSeparator = localeBuffer[0]; - } - - if (PhpFormatDecimalSeparator != '.') - PhpFormatUserLocale = _create_locale(LC_ALL, ""); - - PhEndInitOnce(&PhpFormatInitOnce); - } - - while (Count--) - { - PPH_FORMAT format; - SIZE_T partLength; - WCHAR tempBuffer[BUFFER_SIZE]; - ULONG flags; - ULONG int32; - ULONG64 int64; - - format = Format++; - - // Save the currently used length so we can compute the part length later. - partLength = usedLength; - - flags = 0; - - switch (format->Type & FormatTypeMask) - { - - // Characters and Strings - - case CharFormatType: - ENSURE_BUFFER(sizeof(WCHAR)); - if (OK_BUFFER) - *buffer = format->u.Char; - ADVANCE_BUFFER(sizeof(WCHAR)); - break; - case StringFormatType: - ENSURE_BUFFER(format->u.String.Length); - if (OK_BUFFER) - memcpy(buffer, format->u.String.Buffer, format->u.String.Length); - ADVANCE_BUFFER(format->u.String.Length); - break; - case StringZFormatType: - { - SIZE_T count; - - count = PhCountStringZ(format->u.StringZ); - ENSURE_BUFFER(count * sizeof(WCHAR)); - if (OK_BUFFER) - memcpy(buffer, format->u.StringZ, count * sizeof(WCHAR)); - ADVANCE_BUFFER(count * sizeof(WCHAR)); - } - break; - case MultiByteStringFormatType: - case MultiByteStringZFormatType: - { - ULONG bytesInUnicodeString; - PSTR multiByteBuffer; - SIZE_T multiByteLength; - - if (format->Type == MultiByteStringFormatType) - { - multiByteBuffer = format->u.MultiByteString.Buffer; - multiByteLength = format->u.MultiByteString.Length; - } - else - { - multiByteBuffer = format->u.MultiByteStringZ; - multiByteLength = strlen(multiByteBuffer); - } - - if (NT_SUCCESS(RtlMultiByteToUnicodeSize( - &bytesInUnicodeString, - multiByteBuffer, - (ULONG)multiByteLength - ))) - { - ENSURE_BUFFER(bytesInUnicodeString); - - if (!OK_BUFFER || NT_SUCCESS(RtlMultiByteToUnicodeN( - buffer, - bytesInUnicodeString, - NULL, - multiByteBuffer, - (ULONG)multiByteLength - ))) - { - ADVANCE_BUFFER(bytesInUnicodeString); - } - } - } - break; - - // Integers - -#define PROCESS_DIGIT(Input) \ - do { \ - r = (ULONG)(Input % radix); \ - Input /= radix; \ - *temp-- = integerToChar[r]; \ - tempCount++; \ - } while (0) - -#define COMMON_INTEGER_FORMAT(Input, Format) \ - do { \ - ULONG radix; \ - PCHAR integerToChar; \ - PWSTR temp; \ - ULONG tempCount; \ - ULONG r; \ - ULONG preCount; \ - ULONG padCount; \ - \ - radix = 10; \ - if (((Format)->Type & FormatUseRadix) && (Format)->Radix >= 2 && (Format)->Radix <= 69) \ - radix = (Format)->Radix; \ - integerToChar = PhIntegerToChar; \ - if ((Format)->Type & FormatUpperCase) \ - integerToChar = PhIntegerToCharUpper; \ - temp = tempBuffer + BUFFER_SIZE - 1; \ - tempCount = 0; \ - \ - if (Input != 0) \ - { \ - if ((Format)->Type & FormatGroupDigits) \ - { \ - ULONG needsSep = 0; \ - \ - do \ - { \ - PROCESS_DIGIT(Input); \ - \ - if (++needsSep == 3 && Input != 0) /* get rid of trailing separator */ \ - { \ - *temp-- = PhpFormatThousandSeparator; \ - tempCount++; \ - needsSep = 0; \ - } \ - } while (Input != 0); \ - } \ - else \ - { \ - do \ - { \ - PROCESS_DIGIT(Input); \ - } while (Input != 0); \ - } \ - } \ - else \ - { \ - *temp-- = '0'; \ - tempCount++; \ - } \ - \ - preCount = 0; \ - \ - if (flags & PHP_FORMAT_NEGATIVE) \ - preCount++; \ - else if ((Format)->Type & FormatPrefixSign) \ - preCount++; \ - \ - if (((Format)->Type & FormatPadZeros) && !((Format)->Type & FormatGroupDigits)) \ - { \ - if (preCount + tempCount < (Format)->Width) \ - { \ - flags |= PHP_FORMAT_PAD; \ - padCount = (Format)->Width - (preCount + tempCount); \ - preCount += padCount; \ - } \ - } \ - \ - temp++; \ - ENSURE_BUFFER((preCount + tempCount) * sizeof(WCHAR)); \ - if (OK_BUFFER) \ - { \ - if (flags & PHP_FORMAT_NEGATIVE) \ - *buffer++ = '-'; \ - else if ((Format)->Type & FormatPrefixSign) \ - *buffer++ = '+'; \ - \ - if (flags & PHP_FORMAT_PAD) \ - { \ - wmemset(buffer, '0', padCount); \ - buffer += padCount; \ - } \ - \ - memcpy(buffer, temp, tempCount * sizeof(WCHAR)); \ - buffer += tempCount; \ - } \ - usedLength += (preCount + tempCount) * sizeof(WCHAR); \ - } while (0) - -#ifndef _WIN64 - case IntPtrFormatType: - int32 = format->u.IntPtr; - goto CommonMaybeNegativeInt32Format; -#endif - case Int32FormatType: - int32 = format->u.Int32; - -#ifndef _WIN64 -CommonMaybeNegativeInt32Format: -#endif - if ((LONG)int32 < 0) - { - int32 = -(LONG)int32; - flags |= PHP_FORMAT_NEGATIVE; - } - - goto CommonInt32Format; -#ifndef _WIN64 - case UIntPtrFormatType: - int32 = format->u.UIntPtr; - goto CommonInt32Format; -#endif - case UInt32FormatType: - int32 = format->u.UInt32; -CommonInt32Format: - COMMON_INTEGER_FORMAT(int32, format); - break; -#ifdef _WIN64 - case IntPtrFormatType: - int64 = format->u.IntPtr; - goto CommonMaybeNegativeInt64Format; -#endif - case Int64FormatType: - int64 = format->u.Int64; - -#ifdef _WIN64 -CommonMaybeNegativeInt64Format: -#endif - if ((LONG64)int64 < 0) - { - int64 = -(LONG64)int64; - flags |= PHP_FORMAT_NEGATIVE; - } - - goto CommonInt64Format; -#ifdef _WIN64 - case UIntPtrFormatType: - int64 = format->u.UIntPtr; - goto CommonInt64Format; -#endif - case UInt64FormatType: - int64 = format->u.UInt64; -CommonInt64Format: - COMMON_INTEGER_FORMAT(int64, format); - break; - - // Floating point numbers - -#define COMMON_DOUBLE_FORMAT(Format) \ - do { \ - ULONG precision; \ - DOUBLE value; \ - CHAR c; \ - PSTR temp; \ - ULONG length; \ - \ - if ((Format)->Type & FormatUsePrecision) \ - { \ - precision = (Format)->Precision; \ - \ - if (precision > BUFFER_SIZE - 1 - _CVTBUFSIZE) \ - precision = BUFFER_SIZE - 1 - _CVTBUFSIZE; \ - } \ - else \ - { \ - precision = 6; \ - } \ - \ - c = 'f'; \ - \ - if ((Format)->Type & FormatStandardForm) \ - c = 'e'; \ - else if ((Format)->Type & FormatHexadecimalForm) \ - c = 'a'; \ - \ - /* Use MS CRT routines to do the work. */ \ - \ - value = (Format)->u.Double; \ - temp = (PSTR)tempBuffer + 1; /* leave one character so we can insert a prefix if needed */ \ - _cfltcvt_l( \ - &value, \ - temp, \ - sizeof(tempBuffer) - 1, \ - c, \ - precision, \ - !!((Format)->Type & FormatUpperCase), \ - PhpFormatUserLocale \ - ); \ - \ - /* if (((Format)->Type & FormatForceDecimalPoint) && precision == 0) */ \ - /* _forcdecpt_l(tempBufferAnsi, PhpFormatUserLocale); */ \ - if ((Format)->Type & FormatCropZeros) \ - PhpCropZeros(temp, PhpFormatUserLocale); \ - \ - length = (ULONG)strlen(temp); \ - \ - if (temp[0] == '-') \ - { \ - flags |= PHP_FORMAT_NEGATIVE; \ - temp++; \ - length--; \ - } \ - else if ((Format)->Type & FormatPrefixSign) \ - { \ - flags |= PHP_FORMAT_POSITIVE; \ - } \ - \ - if (((Format)->Type & FormatGroupDigits) && !((Format)->Type & (FormatStandardForm | FormatHexadecimalForm))) \ - { \ - PSTR whole; \ - PSTR decimalPoint; \ - ULONG wholeCount; \ - ULONG sepsCount; \ - ULONG ensureLength; \ - ULONG copyCount; \ - ULONG needsSep; \ - \ - /* Find the first non-digit character and assume that is the */ \ - /* decimal point (or the end of the string). */ \ - \ - whole = temp; \ - decimalPoint = temp; \ - \ - while ((UCHAR)(*decimalPoint - '0') < 10) \ - decimalPoint++; \ - \ - /* Copy the characters to the output buffer, and at the same time */ \ - /* insert the separators. */ \ - \ - wholeCount = (ULONG)(decimalPoint - temp); \ - \ - if (wholeCount != 0) \ - sepsCount = (wholeCount + 2) / 3 - 1; \ - else \ - sepsCount = 0; \ - \ - ensureLength = (length + sepsCount) * sizeof(WCHAR); \ - if (flags & (PHP_FORMAT_NEGATIVE | PHP_FORMAT_POSITIVE)) \ - ensureLength += sizeof(WCHAR); \ - ENSURE_BUFFER(ensureLength); \ - \ - copyCount = wholeCount; \ - needsSep = (wholeCount + 2) % 3; \ - \ - if (OK_BUFFER) \ - { \ - if (flags & PHP_FORMAT_NEGATIVE) \ - *buffer++ = '-'; \ - else if (flags & PHP_FORMAT_POSITIVE) \ - *buffer++ = '+'; \ - \ - while (copyCount--) \ - { \ - *buffer++ = *whole++; \ - \ - if (needsSep-- == 0 && copyCount != 0) /* get rid of trailing separator */ \ - { \ - *buffer++ = PhpFormatThousandSeparator; \ - needsSep = 2; \ - } \ - } \ - } \ - \ - if (flags & (PHP_FORMAT_NEGATIVE | PHP_FORMAT_POSITIVE)) \ - usedLength += sizeof(WCHAR); \ - usedLength += (wholeCount + sepsCount) * sizeof(WCHAR); \ - \ - /* Copy the rest. */ \ - \ - copyCount = length - wholeCount; \ - \ - if (OK_BUFFER) \ - { \ - PhZeroExtendToUtf16Buffer(decimalPoint, copyCount, buffer); \ - ADVANCE_BUFFER(copyCount * sizeof(WCHAR)); \ - } \ - } \ - else \ - { \ - SIZE_T preLength; \ - SIZE_T padLength; \ - \ - /* Take care of the sign and zero padding. */ \ - preLength = 0; \ - \ - if (flags & (PHP_FORMAT_NEGATIVE | PHP_FORMAT_POSITIVE)) \ - preLength++; \ - \ - if ((Format)->Type & FormatPadZeros) \ - { \ - if (preLength + length < (Format)->Width) \ - { \ - flags |= PHP_FORMAT_PAD; \ - padLength = (Format)->Width - (preLength + length); \ - preLength += padLength; \ - } \ - } \ - /* We don't need to group digits, so directly copy the characters */ \ - /* to the output buffer. */ \ - \ - ENSURE_BUFFER((preLength + length) * sizeof(WCHAR)); \ - \ - if (OK_BUFFER) \ - { \ - if (flags & PHP_FORMAT_NEGATIVE) \ - *buffer++ = '-'; \ - else if (flags & PHP_FORMAT_POSITIVE) \ - *buffer++ = '+'; \ - \ - if (flags & PHP_FORMAT_PAD) \ - { \ - wmemset(buffer, '0', padLength); \ - buffer += padLength; \ - } \ - } \ - \ - usedLength += preLength * sizeof(WCHAR); \ - \ - if (OK_BUFFER) \ - { \ - PhZeroExtendToUtf16Buffer((PSTR)temp, length, buffer); \ - ADVANCE_BUFFER(length * sizeof(WCHAR)); \ - } \ - } \ - } while (0) - - case DoubleFormatType: - flags = 0; - COMMON_DOUBLE_FORMAT(format); - break; - - // Additional types - - case SizeFormatType: - { - ULONG i = 0; - ULONG maxSizeUnit; - DOUBLE s; - PH_FORMAT doubleFormat; - - s = (DOUBLE)format->u.Size; - - if (format->u.Size == 0) - { - ENSURE_BUFFER(sizeof(WCHAR)); - if (OK_BUFFER) - *buffer = '0'; - ADVANCE_BUFFER(sizeof(WCHAR)); - goto ContinueLoop; - } - - if (format->Type & FormatUseRadix) - maxSizeUnit = format->Radix; - else - maxSizeUnit = PhMaxSizeUnit; - - while ( - s >= 1000 && - i < sizeof(PhpSizeUnitNamesCounted) / sizeof(PH_STRINGREF) && - i < maxSizeUnit - ) - { - s /= 1024; - i++; - } - - // Format the number, then append the unit name. - - doubleFormat.Type = DoubleFormatType | FormatUsePrecision | FormatCropZeros | FormatGroupDigits; - doubleFormat.Precision = (format->Type & FormatUsePrecision) ? format->Precision : 2; - doubleFormat.Width = 0; // stupid compiler - doubleFormat.u.Double = s; - flags = 0; - COMMON_DOUBLE_FORMAT(&doubleFormat); - - ENSURE_BUFFER(sizeof(WCHAR) + PhpSizeUnitNamesCounted[i].Length); - if (OK_BUFFER) - { - *buffer = ' '; - memcpy(buffer + 1, PhpSizeUnitNamesCounted[i].Buffer, PhpSizeUnitNamesCounted[i].Length); - } - ADVANCE_BUFFER(sizeof(WCHAR) + PhpSizeUnitNamesCounted[i].Length); - } - break; - } - -ContinueLoop: - partLength = usedLength - partLength; - - if (format->Type & (FormatLeftAlign | FormatRightAlign)) - { - SIZE_T newLength; - SIZE_T addLength; - - newLength = format->Width * sizeof(WCHAR); - - // We only pad and never truncate. - if (partLength < newLength) - { - addLength = newLength - partLength; - ENSURE_BUFFER(addLength); - - if (OK_BUFFER) - { - WCHAR pad; - - if (format->Type & FormatUsePad) - pad = format->Pad; - else - pad = ' '; - - if (format->Type & FormatLeftAlign) - { - // Left alignment is easy; we just fill the remaining space with the pad - // character. - wmemset(buffer, pad, addLength / sizeof(WCHAR)); - } - else - { - PWSTR start; - - // Right alignment is much slower and involves moving the text forward, then - // filling in the space before it. - start = buffer - partLength / sizeof(WCHAR); - memmove(start + addLength / sizeof(WCHAR), start, partLength); - wmemset(start, pad, addLength / sizeof(WCHAR)); - } - } - - ADVANCE_BUFFER(addLength); - } - } - } -} +/* + * This file contains the actual formatting code used by various public interface functions. + * + * There are three macros defined by the parent function which control how this code writes the + * formatted string: + * * ENSURE_BUFFER - This macro is passed the number of bytes required whenever characters need to + * be written to the buffer. The macro can resize the buffer if needed. + * * OK_BUFFER - This macro returns TRUE if it is OK to write to the buffer, otherwise FALSE when + * the buffer is too large, is not specified, or some other error has occurred. + * * ADVANCE_BUFFER - This macro is passed the number of bytes written to the buffer and should + * increment the "buffer" pointer and "usedLength" counter. + * In addition to these macros, the "buffer" and "usedLength" variables are assumed to be present. + * + * The below code defines many macros; this is so that composite formatting types can be constructed + * (e.g. the "size" type). + */ + +{ + if (PhBeginInitOnce(&PhpFormatInitOnce)) + { + WCHAR localeBuffer[4]; + + if (GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, localeBuffer, 4) && + (localeBuffer[0] != 0 && localeBuffer[1] == 0)) + { + PhpFormatDecimalSeparator = localeBuffer[0]; + } + + if (GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, localeBuffer, 4) && + (localeBuffer[0] != 0 && localeBuffer[1] == 0)) + { + PhpFormatThousandSeparator = localeBuffer[0]; + } + + if (PhpFormatDecimalSeparator != '.') + PhpFormatUserLocale = _create_locale(LC_ALL, ""); + + PhEndInitOnce(&PhpFormatInitOnce); + } + + while (Count--) + { + PPH_FORMAT format; + SIZE_T partLength; + WCHAR tempBuffer[BUFFER_SIZE]; + ULONG flags; + ULONG int32; + ULONG64 int64; + + format = Format++; + + // Save the currently used length so we can compute the part length later. + partLength = usedLength; + + flags = 0; + + switch (format->Type & FormatTypeMask) + { + + // Characters and Strings + + case CharFormatType: + ENSURE_BUFFER(sizeof(WCHAR)); + if (OK_BUFFER) + *buffer = format->u.Char; + ADVANCE_BUFFER(sizeof(WCHAR)); + break; + case StringFormatType: + ENSURE_BUFFER(format->u.String.Length); + if (OK_BUFFER) + memcpy(buffer, format->u.String.Buffer, format->u.String.Length); + ADVANCE_BUFFER(format->u.String.Length); + break; + case StringZFormatType: + { + SIZE_T count; + + count = PhCountStringZ(format->u.StringZ); + ENSURE_BUFFER(count * sizeof(WCHAR)); + if (OK_BUFFER) + memcpy(buffer, format->u.StringZ, count * sizeof(WCHAR)); + ADVANCE_BUFFER(count * sizeof(WCHAR)); + } + break; + case MultiByteStringFormatType: + case MultiByteStringZFormatType: + { + ULONG bytesInUnicodeString; + PSTR multiByteBuffer; + SIZE_T multiByteLength; + + if (format->Type == MultiByteStringFormatType) + { + multiByteBuffer = format->u.MultiByteString.Buffer; + multiByteLength = format->u.MultiByteString.Length; + } + else + { + multiByteBuffer = format->u.MultiByteStringZ; + multiByteLength = strlen(multiByteBuffer); + } + + if (NT_SUCCESS(RtlMultiByteToUnicodeSize( + &bytesInUnicodeString, + multiByteBuffer, + (ULONG)multiByteLength + ))) + { + ENSURE_BUFFER(bytesInUnicodeString); + + if (!OK_BUFFER || NT_SUCCESS(RtlMultiByteToUnicodeN( + buffer, + bytesInUnicodeString, + NULL, + multiByteBuffer, + (ULONG)multiByteLength + ))) + { + ADVANCE_BUFFER(bytesInUnicodeString); + } + } + } + break; + + // Integers + +#define PROCESS_DIGIT(Input) \ + do { \ + r = (ULONG)(Input % radix); \ + Input /= radix; \ + *temp-- = integerToChar[r]; \ + tempCount++; \ + } while (0) + +#define COMMON_INTEGER_FORMAT(Input, Format) \ + do { \ + ULONG radix; \ + PCHAR integerToChar; \ + PWSTR temp; \ + ULONG tempCount; \ + ULONG r; \ + ULONG preCount; \ + ULONG padCount; \ + \ + radix = 10; \ + if (((Format)->Type & FormatUseRadix) && (Format)->Radix >= 2 && (Format)->Radix <= 69) \ + radix = (Format)->Radix; \ + integerToChar = PhIntegerToChar; \ + if ((Format)->Type & FormatUpperCase) \ + integerToChar = PhIntegerToCharUpper; \ + temp = tempBuffer + BUFFER_SIZE - 1; \ + tempCount = 0; \ + \ + if (Input != 0) \ + { \ + if ((Format)->Type & FormatGroupDigits) \ + { \ + ULONG needsSep = 0; \ + \ + do \ + { \ + PROCESS_DIGIT(Input); \ + \ + if (++needsSep == 3 && Input != 0) /* get rid of trailing separator */ \ + { \ + *temp-- = PhpFormatThousandSeparator; \ + tempCount++; \ + needsSep = 0; \ + } \ + } while (Input != 0); \ + } \ + else \ + { \ + do \ + { \ + PROCESS_DIGIT(Input); \ + } while (Input != 0); \ + } \ + } \ + else \ + { \ + *temp-- = '0'; \ + tempCount++; \ + } \ + \ + preCount = 0; \ + \ + if (flags & PHP_FORMAT_NEGATIVE) \ + preCount++; \ + else if ((Format)->Type & FormatPrefixSign) \ + preCount++; \ + \ + if (((Format)->Type & FormatPadZeros) && !((Format)->Type & FormatGroupDigits)) \ + { \ + if (preCount + tempCount < (Format)->Width) \ + { \ + flags |= PHP_FORMAT_PAD; \ + padCount = (Format)->Width - (preCount + tempCount); \ + preCount += padCount; \ + } \ + } \ + \ + temp++; \ + ENSURE_BUFFER((preCount + tempCount) * sizeof(WCHAR)); \ + if (OK_BUFFER) \ + { \ + if (flags & PHP_FORMAT_NEGATIVE) \ + *buffer++ = '-'; \ + else if ((Format)->Type & FormatPrefixSign) \ + *buffer++ = '+'; \ + \ + if (flags & PHP_FORMAT_PAD) \ + { \ + wmemset(buffer, '0', padCount); \ + buffer += padCount; \ + } \ + \ + memcpy(buffer, temp, tempCount * sizeof(WCHAR)); \ + buffer += tempCount; \ + } \ + usedLength += (preCount + tempCount) * sizeof(WCHAR); \ + } while (0) + +#ifndef _WIN64 + case IntPtrFormatType: + int32 = format->u.IntPtr; + goto CommonMaybeNegativeInt32Format; +#endif + case Int32FormatType: + int32 = format->u.Int32; + +#ifndef _WIN64 +CommonMaybeNegativeInt32Format: +#endif + if ((LONG)int32 < 0) + { + int32 = -(LONG)int32; + flags |= PHP_FORMAT_NEGATIVE; + } + + goto CommonInt32Format; +#ifndef _WIN64 + case UIntPtrFormatType: + int32 = format->u.UIntPtr; + goto CommonInt32Format; +#endif + case UInt32FormatType: + int32 = format->u.UInt32; +CommonInt32Format: + COMMON_INTEGER_FORMAT(int32, format); + break; +#ifdef _WIN64 + case IntPtrFormatType: + int64 = format->u.IntPtr; + goto CommonMaybeNegativeInt64Format; +#endif + case Int64FormatType: + int64 = format->u.Int64; + +#ifdef _WIN64 +CommonMaybeNegativeInt64Format: +#endif + if ((LONG64)int64 < 0) + { + int64 = -(LONG64)int64; + flags |= PHP_FORMAT_NEGATIVE; + } + + goto CommonInt64Format; +#ifdef _WIN64 + case UIntPtrFormatType: + int64 = format->u.UIntPtr; + goto CommonInt64Format; +#endif + case UInt64FormatType: + int64 = format->u.UInt64; +CommonInt64Format: + COMMON_INTEGER_FORMAT(int64, format); + break; + + // Floating point numbers + +#define COMMON_DOUBLE_FORMAT(Format) \ + do { \ + ULONG precision; \ + DOUBLE value; \ + CHAR c; \ + PSTR temp; \ + ULONG length; \ + \ + if ((Format)->Type & FormatUsePrecision) \ + { \ + precision = (Format)->Precision; \ + \ + if (precision > BUFFER_SIZE - 1 - _CVTBUFSIZE) \ + precision = BUFFER_SIZE - 1 - _CVTBUFSIZE; \ + } \ + else \ + { \ + precision = 6; \ + } \ + \ + c = 'f'; \ + \ + if ((Format)->Type & FormatStandardForm) \ + c = 'e'; \ + else if ((Format)->Type & FormatHexadecimalForm) \ + c = 'a'; \ + \ + /* Use MS CRT routines to do the work. */ \ + \ + value = (Format)->u.Double; \ + temp = (PSTR)tempBuffer + 1; /* leave one character so we can insert a prefix if needed */ \ + _cfltcvt_l( \ + &value, \ + temp, \ + sizeof(tempBuffer) - 1, \ + c, \ + precision, \ + !!((Format)->Type & FormatUpperCase), \ + PhpFormatUserLocale \ + ); \ + \ + /* if (((Format)->Type & FormatForceDecimalPoint) && precision == 0) */ \ + /* _forcdecpt_l(tempBufferAnsi, PhpFormatUserLocale); */ \ + if ((Format)->Type & FormatCropZeros) \ + PhpCropZeros(temp, PhpFormatUserLocale); \ + \ + length = (ULONG)strlen(temp); \ + \ + if (temp[0] == '-') \ + { \ + flags |= PHP_FORMAT_NEGATIVE; \ + temp++; \ + length--; \ + } \ + else if ((Format)->Type & FormatPrefixSign) \ + { \ + flags |= PHP_FORMAT_POSITIVE; \ + } \ + \ + if (((Format)->Type & FormatGroupDigits) && !((Format)->Type & (FormatStandardForm | FormatHexadecimalForm))) \ + { \ + PSTR whole; \ + PSTR decimalPoint; \ + ULONG wholeCount; \ + ULONG sepsCount; \ + ULONG ensureLength; \ + ULONG copyCount; \ + ULONG needsSep; \ + \ + /* Find the first non-digit character and assume that is the */ \ + /* decimal point (or the end of the string). */ \ + \ + whole = temp; \ + decimalPoint = temp; \ + \ + while ((UCHAR)(*decimalPoint - '0') < 10) \ + decimalPoint++; \ + \ + /* Copy the characters to the output buffer, and at the same time */ \ + /* insert the separators. */ \ + \ + wholeCount = (ULONG)(decimalPoint - temp); \ + \ + if (wholeCount != 0) \ + sepsCount = (wholeCount + 2) / 3 - 1; \ + else \ + sepsCount = 0; \ + \ + ensureLength = (length + sepsCount) * sizeof(WCHAR); \ + if (flags & (PHP_FORMAT_NEGATIVE | PHP_FORMAT_POSITIVE)) \ + ensureLength += sizeof(WCHAR); \ + ENSURE_BUFFER(ensureLength); \ + \ + copyCount = wholeCount; \ + needsSep = (wholeCount + 2) % 3; \ + \ + if (OK_BUFFER) \ + { \ + if (flags & PHP_FORMAT_NEGATIVE) \ + *buffer++ = '-'; \ + else if (flags & PHP_FORMAT_POSITIVE) \ + *buffer++ = '+'; \ + \ + while (copyCount--) \ + { \ + *buffer++ = *whole++; \ + \ + if (needsSep-- == 0 && copyCount != 0) /* get rid of trailing separator */ \ + { \ + *buffer++ = PhpFormatThousandSeparator; \ + needsSep = 2; \ + } \ + } \ + } \ + \ + if (flags & (PHP_FORMAT_NEGATIVE | PHP_FORMAT_POSITIVE)) \ + usedLength += sizeof(WCHAR); \ + usedLength += (wholeCount + sepsCount) * sizeof(WCHAR); \ + \ + /* Copy the rest. */ \ + \ + copyCount = length - wholeCount; \ + \ + if (OK_BUFFER) \ + { \ + PhZeroExtendToUtf16Buffer(decimalPoint, copyCount, buffer); \ + ADVANCE_BUFFER(copyCount * sizeof(WCHAR)); \ + } \ + } \ + else \ + { \ + SIZE_T preLength; \ + SIZE_T padLength; \ + \ + /* Take care of the sign and zero padding. */ \ + preLength = 0; \ + \ + if (flags & (PHP_FORMAT_NEGATIVE | PHP_FORMAT_POSITIVE)) \ + preLength++; \ + \ + if ((Format)->Type & FormatPadZeros) \ + { \ + if (preLength + length < (Format)->Width) \ + { \ + flags |= PHP_FORMAT_PAD; \ + padLength = (Format)->Width - (preLength + length); \ + preLength += padLength; \ + } \ + } \ + /* We don't need to group digits, so directly copy the characters */ \ + /* to the output buffer. */ \ + \ + ENSURE_BUFFER((preLength + length) * sizeof(WCHAR)); \ + \ + if (OK_BUFFER) \ + { \ + if (flags & PHP_FORMAT_NEGATIVE) \ + *buffer++ = '-'; \ + else if (flags & PHP_FORMAT_POSITIVE) \ + *buffer++ = '+'; \ + \ + if (flags & PHP_FORMAT_PAD) \ + { \ + wmemset(buffer, '0', padLength); \ + buffer += padLength; \ + } \ + } \ + \ + usedLength += preLength * sizeof(WCHAR); \ + \ + if (OK_BUFFER) \ + { \ + PhZeroExtendToUtf16Buffer((PSTR)temp, length, buffer); \ + ADVANCE_BUFFER(length * sizeof(WCHAR)); \ + } \ + } \ + } while (0) + + case DoubleFormatType: + flags = 0; + COMMON_DOUBLE_FORMAT(format); + break; + + // Additional types + + case SizeFormatType: + { + ULONG i = 0; + ULONG maxSizeUnit; + DOUBLE s; + PH_FORMAT doubleFormat; + + s = (DOUBLE)format->u.Size; + + if (format->u.Size == 0) + { + ENSURE_BUFFER(sizeof(WCHAR)); + if (OK_BUFFER) + *buffer = '0'; + ADVANCE_BUFFER(sizeof(WCHAR)); + goto ContinueLoop; + } + + if (format->Type & FormatUseRadix) + maxSizeUnit = format->Radix; + else + maxSizeUnit = PhMaxSizeUnit; + + while ( + s >= 1000 && + i < sizeof(PhpSizeUnitNamesCounted) / sizeof(PH_STRINGREF) && + i < maxSizeUnit + ) + { + s /= 1024; + i++; + } + + // Format the number, then append the unit name. + + doubleFormat.Type = DoubleFormatType | FormatUsePrecision | FormatCropZeros | FormatGroupDigits; + doubleFormat.Precision = (format->Type & FormatUsePrecision) ? format->Precision : 2; + doubleFormat.Width = 0; // stupid compiler + doubleFormat.u.Double = s; + flags = 0; + COMMON_DOUBLE_FORMAT(&doubleFormat); + + ENSURE_BUFFER(sizeof(WCHAR) + PhpSizeUnitNamesCounted[i].Length); + if (OK_BUFFER) + { + *buffer = ' '; + memcpy(buffer + 1, PhpSizeUnitNamesCounted[i].Buffer, PhpSizeUnitNamesCounted[i].Length); + } + ADVANCE_BUFFER(sizeof(WCHAR) + PhpSizeUnitNamesCounted[i].Length); + } + break; + } + +ContinueLoop: + partLength = usedLength - partLength; + + if (format->Type & (FormatLeftAlign | FormatRightAlign)) + { + SIZE_T newLength; + SIZE_T addLength; + + newLength = format->Width * sizeof(WCHAR); + + // We only pad and never truncate. + if (partLength < newLength) + { + addLength = newLength - partLength; + ENSURE_BUFFER(addLength); + + if (OK_BUFFER) + { + WCHAR pad; + + if (format->Type & FormatUsePad) + pad = format->Pad; + else + pad = ' '; + + if (format->Type & FormatLeftAlign) + { + // Left alignment is easy; we just fill the remaining space with the pad + // character. + wmemset(buffer, pad, addLength / sizeof(WCHAR)); + } + else + { + PWSTR start; + + // Right alignment is much slower and involves moving the text forward, then + // filling in the space before it. + start = buffer - partLength / sizeof(WCHAR); + memmove(start + addLength / sizeof(WCHAR), start, partLength); + wmemset(start, pad, addLength / sizeof(WCHAR)); + } + } + + ADVANCE_BUFFER(addLength); + } + } + } +} diff --git a/phlib/global.c b/phlib/global.c index 3575b0f358c3..fb8a44453ab0 100644 --- a/phlib/global.c +++ b/phlib/global.c @@ -1,239 +1,239 @@ -/* - * Process Hacker - - * global variables and initialization functions - * - * Copyright (C) 2010-2013 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include - -#include -#include -#include - -BOOLEAN PhInitializeSystem( - _In_ ULONG Flags - ); - -VOID PhInitializeSystemInformation( - VOID - ); - -VOID PhInitializeWindowsVersion( - VOID - ); - -PHLIBAPI PVOID PhLibImageBase; - -PHLIBAPI PWSTR PhApplicationName = L"Application"; -PHLIBAPI ULONG PhGlobalDpi = 96; -PHLIBAPI PVOID PhHeapHandle; -PHLIBAPI RTL_OSVERSIONINFOEXW PhOsVersion; -PHLIBAPI SYSTEM_BASIC_INFORMATION PhSystemBasicInformation; -PHLIBAPI ULONG WindowsVersion; - -PHLIBAPI ACCESS_MASK ProcessQueryAccess; -PHLIBAPI ACCESS_MASK ProcessAllAccess; -PHLIBAPI ACCESS_MASK ThreadQueryAccess; -PHLIBAPI ACCESS_MASK ThreadSetAccess; -PHLIBAPI ACCESS_MASK ThreadAllAccess; - -// Internal data -#ifdef DEBUG -PHLIB_STATISTICS_BLOCK PhLibStatisticsBlock; -#endif - -NTSTATUS PhInitializePhLib( - VOID - ) -{ - return PhInitializePhLibEx( - 0xffffffff, // all possible features - 0, - 0 - ); -} - -NTSTATUS PhInitializePhLibEx( - _In_ ULONG Flags, - _In_opt_ SIZE_T HeapReserveSize, - _In_opt_ SIZE_T HeapCommitSize - ) -{ - PhHeapHandle = RtlCreateHeap( - HEAP_GROWABLE | HEAP_CLASS_1, - NULL, - HeapReserveSize ? HeapReserveSize : 2 * 1024 * 1024, // 2 MB - HeapCommitSize ? HeapCommitSize : 1024 * 1024, // 1 MB - NULL, - NULL - ); - - if (!PhHeapHandle) - return STATUS_INSUFFICIENT_RESOURCES; - - PhLibImageBase = NtCurrentPeb()->ImageBaseAddress; - - PhInitializeWindowsVersion(); - PhInitializeSystemInformation(); - - if (!PhQueuedLockInitialization()) - return STATUS_UNSUCCESSFUL; - - if (!NT_SUCCESS(PhRefInitialization())) - return STATUS_UNSUCCESSFUL; - if (!PhBaseInitialization()) - return STATUS_UNSUCCESSFUL; - - if (!PhInitializeSystem(Flags)) - return STATUS_UNSUCCESSFUL; - - return STATUS_SUCCESS; -} - -#ifndef _WIN64 -BOOLEAN PhIsExecutingInWow64( - VOID - ) -{ - static BOOLEAN valid = FALSE; - static BOOLEAN isWow64; - - if (!valid) - { - PhGetProcessIsWow64(NtCurrentProcess(), &isWow64); - MemoryBarrier(); - valid = TRUE; - } - - return isWow64; -} -#endif - -static BOOLEAN PhInitializeSystem( - _In_ ULONG Flags - ) -{ - if (Flags & PHLIB_INIT_MODULE_FILE_STREAM) - { - if (!PhFileStreamInitialization()) - return FALSE; - } - - if (Flags & PHLIB_INIT_MODULE_SYMBOL_PROVIDER) - { - if (!PhSymbolProviderInitialization()) - return FALSE; - } - - return TRUE; -} - -static VOID PhInitializeSystemInformation( - VOID - ) -{ - NtQuerySystemInformation( - SystemBasicInformation, - &PhSystemBasicInformation, - sizeof(SYSTEM_BASIC_INFORMATION), - NULL - ); -} - -static VOID PhInitializeWindowsVersion( - VOID - ) -{ - RTL_OSVERSIONINFOEXW versionInfo; - ULONG majorVersion; - ULONG minorVersion; - - versionInfo.dwOSVersionInfoSize = sizeof(RTL_OSVERSIONINFOEXW); - - if (!NT_SUCCESS(RtlGetVersion((PRTL_OSVERSIONINFOW)&versionInfo))) - { - WindowsVersion = WINDOWS_NEW; - return; - } - - memcpy(&PhOsVersion, &versionInfo, sizeof(RTL_OSVERSIONINFOEXW)); - majorVersion = versionInfo.dwMajorVersion; - minorVersion = versionInfo.dwMinorVersion; - - if (majorVersion == 5 && minorVersion < 1 || majorVersion < 5) - { - WindowsVersion = WINDOWS_ANCIENT; - } - /* Windows XP */ - else if (majorVersion == 5 && minorVersion == 1) - { - WindowsVersion = WINDOWS_XP; - } - /* Windows Server 2003 */ - else if (majorVersion == 5 && minorVersion == 2) - { - WindowsVersion = WINDOWS_SERVER_2003; - } - /* Windows Vista, Windows Server 2008 */ - else if (majorVersion == 6 && minorVersion == 0) - { - WindowsVersion = WINDOWS_VISTA; - } - /* Windows 7, Windows Server 2008 R2 */ - else if (majorVersion == 6 && minorVersion == 1) - { - WindowsVersion = WINDOWS_7; - } - /* Windows 8 */ - else if (majorVersion == 6 && minorVersion == 2) - { - WindowsVersion = WINDOWS_8; - } - /* Windows 8.1 */ - else if (majorVersion == 6 && minorVersion == 3) - { - WindowsVersion = WINDOWS_8_1; - } - /* Windows 10 */ - else if (majorVersion == 10 && minorVersion == 0) - { - WindowsVersion = WINDOWS_10; - } - else if (majorVersion == 10 && minorVersion > 0 || majorVersion > 10) - { - WindowsVersion = WINDOWS_NEW; - } - - if (WINDOWS_HAS_LIMITED_ACCESS) - { - ProcessQueryAccess = PROCESS_QUERY_LIMITED_INFORMATION; - ProcessAllAccess = STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x1fff; - ThreadQueryAccess = THREAD_QUERY_LIMITED_INFORMATION; - ThreadSetAccess = THREAD_SET_LIMITED_INFORMATION; - ThreadAllAccess = STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xfff; - } - else - { - ProcessQueryAccess = PROCESS_QUERY_INFORMATION; - ProcessAllAccess = STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xfff; - ThreadQueryAccess = THREAD_QUERY_INFORMATION; - ThreadSetAccess = THREAD_SET_INFORMATION; - ThreadAllAccess = STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x3ff; - } -} +/* + * Process Hacker - + * global variables and initialization functions + * + * Copyright (C) 2010-2013 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include + +#include +#include +#include + +BOOLEAN PhInitializeSystem( + _In_ ULONG Flags + ); + +VOID PhInitializeSystemInformation( + VOID + ); + +VOID PhInitializeWindowsVersion( + VOID + ); + +PHLIBAPI PVOID PhLibImageBase; + +PHLIBAPI PWSTR PhApplicationName = L"Application"; +PHLIBAPI ULONG PhGlobalDpi = 96; +PHLIBAPI PVOID PhHeapHandle; +PHLIBAPI RTL_OSVERSIONINFOEXW PhOsVersion; +PHLIBAPI SYSTEM_BASIC_INFORMATION PhSystemBasicInformation; +PHLIBAPI ULONG WindowsVersion; + +PHLIBAPI ACCESS_MASK ProcessQueryAccess; +PHLIBAPI ACCESS_MASK ProcessAllAccess; +PHLIBAPI ACCESS_MASK ThreadQueryAccess; +PHLIBAPI ACCESS_MASK ThreadSetAccess; +PHLIBAPI ACCESS_MASK ThreadAllAccess; + +// Internal data +#ifdef DEBUG +PHLIB_STATISTICS_BLOCK PhLibStatisticsBlock; +#endif + +NTSTATUS PhInitializePhLib( + VOID + ) +{ + return PhInitializePhLibEx( + 0xffffffff, // all possible features + 0, + 0 + ); +} + +NTSTATUS PhInitializePhLibEx( + _In_ ULONG Flags, + _In_opt_ SIZE_T HeapReserveSize, + _In_opt_ SIZE_T HeapCommitSize + ) +{ + PhHeapHandle = RtlCreateHeap( + HEAP_GROWABLE | HEAP_CLASS_1, + NULL, + HeapReserveSize ? HeapReserveSize : 2 * 1024 * 1024, // 2 MB + HeapCommitSize ? HeapCommitSize : 1024 * 1024, // 1 MB + NULL, + NULL + ); + + if (!PhHeapHandle) + return STATUS_INSUFFICIENT_RESOURCES; + + PhLibImageBase = NtCurrentPeb()->ImageBaseAddress; + + PhInitializeWindowsVersion(); + PhInitializeSystemInformation(); + + if (!PhQueuedLockInitialization()) + return STATUS_UNSUCCESSFUL; + + if (!NT_SUCCESS(PhRefInitialization())) + return STATUS_UNSUCCESSFUL; + if (!PhBaseInitialization()) + return STATUS_UNSUCCESSFUL; + + if (!PhInitializeSystem(Flags)) + return STATUS_UNSUCCESSFUL; + + return STATUS_SUCCESS; +} + +#ifndef _WIN64 +BOOLEAN PhIsExecutingInWow64( + VOID + ) +{ + static BOOLEAN valid = FALSE; + static BOOLEAN isWow64; + + if (!valid) + { + PhGetProcessIsWow64(NtCurrentProcess(), &isWow64); + MemoryBarrier(); + valid = TRUE; + } + + return isWow64; +} +#endif + +static BOOLEAN PhInitializeSystem( + _In_ ULONG Flags + ) +{ + if (Flags & PHLIB_INIT_MODULE_FILE_STREAM) + { + if (!PhFileStreamInitialization()) + return FALSE; + } + + if (Flags & PHLIB_INIT_MODULE_SYMBOL_PROVIDER) + { + if (!PhSymbolProviderInitialization()) + return FALSE; + } + + return TRUE; +} + +static VOID PhInitializeSystemInformation( + VOID + ) +{ + NtQuerySystemInformation( + SystemBasicInformation, + &PhSystemBasicInformation, + sizeof(SYSTEM_BASIC_INFORMATION), + NULL + ); +} + +static VOID PhInitializeWindowsVersion( + VOID + ) +{ + RTL_OSVERSIONINFOEXW versionInfo; + ULONG majorVersion; + ULONG minorVersion; + + versionInfo.dwOSVersionInfoSize = sizeof(RTL_OSVERSIONINFOEXW); + + if (!NT_SUCCESS(RtlGetVersion((PRTL_OSVERSIONINFOW)&versionInfo))) + { + WindowsVersion = WINDOWS_NEW; + return; + } + + memcpy(&PhOsVersion, &versionInfo, sizeof(RTL_OSVERSIONINFOEXW)); + majorVersion = versionInfo.dwMajorVersion; + minorVersion = versionInfo.dwMinorVersion; + + if (majorVersion == 5 && minorVersion < 1 || majorVersion < 5) + { + WindowsVersion = WINDOWS_ANCIENT; + } + /* Windows XP */ + else if (majorVersion == 5 && minorVersion == 1) + { + WindowsVersion = WINDOWS_XP; + } + /* Windows Server 2003 */ + else if (majorVersion == 5 && minorVersion == 2) + { + WindowsVersion = WINDOWS_SERVER_2003; + } + /* Windows Vista, Windows Server 2008 */ + else if (majorVersion == 6 && minorVersion == 0) + { + WindowsVersion = WINDOWS_VISTA; + } + /* Windows 7, Windows Server 2008 R2 */ + else if (majorVersion == 6 && minorVersion == 1) + { + WindowsVersion = WINDOWS_7; + } + /* Windows 8 */ + else if (majorVersion == 6 && minorVersion == 2) + { + WindowsVersion = WINDOWS_8; + } + /* Windows 8.1 */ + else if (majorVersion == 6 && minorVersion == 3) + { + WindowsVersion = WINDOWS_8_1; + } + /* Windows 10 */ + else if (majorVersion == 10 && minorVersion == 0) + { + WindowsVersion = WINDOWS_10; + } + else if (majorVersion == 10 && minorVersion > 0 || majorVersion > 10) + { + WindowsVersion = WINDOWS_NEW; + } + + if (WINDOWS_HAS_LIMITED_ACCESS) + { + ProcessQueryAccess = PROCESS_QUERY_LIMITED_INFORMATION; + ProcessAllAccess = STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x1fff; + ThreadQueryAccess = THREAD_QUERY_LIMITED_INFORMATION; + ThreadSetAccess = THREAD_SET_LIMITED_INFORMATION; + ThreadAllAccess = STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xfff; + } + else + { + ProcessQueryAccess = PROCESS_QUERY_INFORMATION; + ProcessAllAccess = STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xfff; + ThreadQueryAccess = THREAD_QUERY_INFORMATION; + ThreadSetAccess = THREAD_SET_INFORMATION; + ThreadAllAccess = STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x3ff; + } +} diff --git a/phlib/graph.c b/phlib/graph.c index 27dfb6359b3a..8c47136d2ead 100644 --- a/phlib/graph.c +++ b/phlib/graph.c @@ -1,1335 +1,1335 @@ -/* - * Process Hacker - - * graph control - * - * Copyright (C) 2010-2016 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include - -#include - -#include -#include - -#define COLORREF_TO_BITS(Color) (_byteswap_ulong(Color) >> 8) - -typedef struct _PHP_GRAPH_CONTEXT -{ - HWND Handle; - ULONG Style; - ULONG_PTR Id; - PH_GRAPH_DRAW_INFO DrawInfo; - PH_GRAPH_OPTIONS Options; - BOOLEAN NeedsUpdate; - BOOLEAN NeedsDraw; - - HDC BufferedContext; - HBITMAP BufferedOldBitmap; - HBITMAP BufferedBitmap; - PVOID BufferedBits; - RECT BufferedContextRect; - - HDC FadeOutContext; - HBITMAP FadeOutOldBitmap; - HBITMAP FadeOutBitmap; - PVOID FadeOutBits; - RECT FadeOutContextRect; - - HWND TooltipHandle; - WNDPROC TooltipOldWndProc; - POINT LastCursorLocation; -} PHP_GRAPH_CONTEXT, *PPHP_GRAPH_CONTEXT; - -LRESULT CALLBACK PhpGraphWndProc( - _In_ HWND hwnd, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -RECT PhNormalGraphTextMargin = { 5, 5, 5, 5 }; -RECT PhNormalGraphTextPadding = { 3, 3, 3, 3 }; - -BOOLEAN PhGraphControlInitialization( - VOID - ) -{ - WNDCLASSEX c = { sizeof(c) }; - - c.style = CS_GLOBALCLASS | CS_DBLCLKS; - c.lpfnWndProc = PhpGraphWndProc; - c.cbClsExtra = 0; - c.cbWndExtra = sizeof(PVOID); - c.hInstance = PhLibImageBase; - c.hIcon = NULL; - c.hCursor = LoadCursor(NULL, IDC_ARROW); - c.hbrBackground = NULL; - c.lpszMenuName = NULL; - c.lpszClassName = PH_GRAPH_CLASSNAME; - c.hIconSm = NULL; - - if (!RegisterClassEx(&c)) - return FALSE; - - return TRUE; -} - -FORCEINLINE VOID PhpGetGraphPoint( - _In_ PPH_GRAPH_DRAW_INFO DrawInfo, - _In_ ULONG Index, - _Out_ PULONG H1, - _Out_ PULONG H2 - ) -{ - if (Index < DrawInfo->LineDataCount) - { - FLOAT f1; - FLOAT f2; - - f1 = DrawInfo->LineData1[Index]; - - if (f1 < 0) - f1 = 0; - if (f1 > 1) - f1 = 1; - - *H1 = (ULONG)(f1 * (DrawInfo->Height - 1)); - - if (DrawInfo->Flags & PH_GRAPH_USE_LINE_2) - { - f2 = f1 + DrawInfo->LineData2[Index]; - - if (f2 < 0) - f2 = 0; - if (f2 > 1) - f2 = 1; - - *H2 = (ULONG)(f2 * (DrawInfo->Height - 1)); - } - else - { - *H2 = *H1; - } - } - else - { - *H1 = 0; - *H2 = 0; - } -} - -/** - * Draws a graph directly to memory. - * - * \param hdc The DC to draw to. This is only used when drawing text. - * \param Bits The bits in a bitmap. - * \param DrawInfo A structure which contains graphing information. - * - * \remarks The following information is fixed: - * \li The graph is fixed to the origin (0, 0). - * \li The total size of the bitmap is assumed to be \a Width and \a Height in \a DrawInfo. - * \li \a Step is fixed at 2. - * \li If \ref PH_GRAPH_USE_LINE_2 is specified in \a Flags, \ref PH_GRAPH_OVERLAY_LINE_2 is never - * used. - */ -VOID PhDrawGraphDirect( - _In_ HDC hdc, - _In_ PVOID Bits, - _In_ PPH_GRAPH_DRAW_INFO DrawInfo - ) -{ - PULONG bits = Bits; - LONG width = DrawInfo->Width; - LONG height = DrawInfo->Height; - LONG numberOfPixels = width * height; - ULONG flags = DrawInfo->Flags; - LONG i; - LONG x; - - BOOLEAN intermediate = FALSE; // whether we are currently between two data positions - ULONG dataIndex = 0; // the data index of the current position - ULONG h1_i; // the line 1 height value to the left of the current position - ULONG h1_o; // the line 1 height value at the current position - ULONG h2_i; // the line 1 + line 2 height value to the left of the current position - ULONG h2_o; // the line 1 + line 2 height value at the current position - ULONG h1; // current pixel - ULONG h1_left; // current pixel - ULONG h2; // current pixel - ULONG h2_left; // current pixel - - LONG mid; - LONG h1_low1; - LONG h1_high1; - LONG h1_low2; - LONG h1_high2; - LONG h2_low1; - LONG h2_high1; - LONG h2_low2; - LONG h2_high2; - LONG old_low2; - LONG old_high2; - - ULONG lineColor1; - ULONG lineBackColor1; - ULONG lineColor2; - ULONG lineBackColor2; - FLOAT gridHeight; - LONG gridYThreshold; - ULONG gridYCounter; - ULONG gridColor; - FLOAT gridBase; - FLOAT gridLevel; - - ULONG yLabelMax; - ULONG yLabelDataIndex; - - lineColor1 = COLORREF_TO_BITS(DrawInfo->LineColor1); - lineBackColor1 = COLORREF_TO_BITS(DrawInfo->LineBackColor1); - lineColor2 = COLORREF_TO_BITS(DrawInfo->LineColor2); - lineBackColor2 = COLORREF_TO_BITS(DrawInfo->LineBackColor2); - - if (DrawInfo->BackColor == 0) - { - memset(bits, 0, numberOfPixels * 4); - } - else - { - PhFillMemoryUlong(bits, COLORREF_TO_BITS(DrawInfo->BackColor), numberOfPixels); - } - - x = width - 1; - h1_low2 = MAXLONG; - h1_high2 = 0; - h2_low2 = MAXLONG; - h2_high2 = 0; - - PhpGetGraphPoint(DrawInfo, 0, &h1_i, &h2_i); - - if (flags & (PH_GRAPH_USE_GRID_X | PH_GRAPH_USE_GRID_Y)) - { - gridHeight = max(DrawInfo->GridHeight, 0); - gridLevel = gridHeight; - gridYThreshold = DrawInfo->GridYThreshold; - gridYCounter = DrawInfo->GridWidth - (DrawInfo->GridXOffset * DrawInfo->Step) % DrawInfo->GridWidth - 1; - gridColor = COLORREF_TO_BITS(DrawInfo->GridColor); - } - - if ((flags & (PH_GRAPH_USE_GRID_Y | PH_GRAPH_LOGARITHMIC_GRID_Y)) == (PH_GRAPH_USE_GRID_Y | PH_GRAPH_LOGARITHMIC_GRID_Y)) - { - // Pre-process to find the largest integer n such that GridHeight*GridBase^n < 1. - - gridBase = DrawInfo->GridBase; - - if (gridBase > 1) - { - DOUBLE logBase; - DOUBLE exponent; - DOUBLE high; - - logBase = log(gridBase); - exponent = ceil(-log(gridHeight) / logBase) - 1; // Works for both GridHeight > 1 and GridHeight < 1 - high = exp(exponent * logBase); - gridLevel = (FLOAT)(gridHeight * high); - - if (gridLevel < 0 || !isfinite(gridLevel)) - gridLevel = 0; - if (gridLevel > 1) - gridLevel = 1; - } - else - { - // This is an error. - gridLevel = 0; - } - } - - if (flags & PH_GRAPH_LABEL_MAX_Y) - { - yLabelMax = h2_i; - yLabelDataIndex = 0; - } - - while (x >= 0) - { - // Calculate the height of the graph at this point. - - if (!intermediate) - { - h1_o = h1_i; - h2_o = h2_i; - - // Pull in new data. - dataIndex++; - PhpGetGraphPoint(DrawInfo, dataIndex, &h1_i, &h2_i); - - h1 = h1_o; - h1_left = (h1_i + h1_o) / 2; - h2 = h2_o; - h2_left = (h2_i + h2_o) / 2; - - if ((flags & PH_GRAPH_LABEL_MAX_Y) && dataIndex < DrawInfo->LabelMaxYIndexLimit) - { - if (yLabelMax <= h2_i) - { - yLabelMax = h2_i; - yLabelDataIndex = dataIndex; - } - } - } - else - { - h1 = h1_left; - h1_left = h1_i; - h2 = h2_left; - h2_left = h2_i; - } - - // The graph is drawn right-to-left. There is one iteration of the loop per horizontal pixel. - // There is a fixed step value of 2, so every other iteration is a mid-point (intermediate) - // iteration with a height value of (left + right) / 2. In order to rasterize the outline, - // effectively in each iteration half of the line is drawn at the current column and the other - // half is drawn in the column to the left. - - // Rasterize the data outline. - // h?_low2 to h?_high2 is the vertical line to the left of the current pixel. - // h?_low1 to h?_high1 is the vertical line at the current pixel. - // We merge (union) the old h?_low2 to h?_high2 line with the current line in each iteration. - // - // For example: - // - // X represents a data point. M represents the mid-point between two data points ("intermediate"). - // X, M and x are all part of the outline. # represents the background filled in during - // the current loop iteration. - // - // slope > 0: slope < 0: - // - // X < high1 X < high2 (of next loop iteration) - // x x - // x < low1 x < low2 (of next loop iteration) - // x# < high2 x < high1 (of next loop iteration) - // M# < low2 M < low1 (of next loop iteration) - // x# < high1 (of next loop iteration) x < high2 - // x# < low1 (of next loop iteration) x < low2 - // x # < high2 (of next loop iteration) x < high1 - // x # x - // X # < low2 (of next loop iteration) X < low1 - // # # - // ^ ^ - // ^| current pixel ^| current pixel - // | | - // | left of current pixel | left of current pixel - // - // In both examples above, the line low2-high2 will be merged with the line low1-high1 of - // the next iteration. - - mid = ((h1_left + h1) / 2) * width; - old_low2 = h1_low2; - old_high2 = h1_high2; - - if (h1_left < h1) // slope > 0 - { - h1_low2 = h1_left * width; - h1_high2 = mid; - h1_low1 = mid + width; - h1_high1 = h1 * width; - } - else // slope < 0 - { - h1_high2 = h1_left * width; - h1_low2 = mid + width; - h1_high1 = mid; - h1_low1 = h1 * width; - } - - // Merge the lines. - if (h1_low1 > old_low2) - h1_low1 = old_low2; - if (h1_high1 < old_high2) - h1_high1 = old_high2; - - // Fix up values for the current horizontal offset. - h1_low1 += x; - h1_high1 += x; - - if (flags & PH_GRAPH_USE_LINE_2) - { - mid = ((h2_left + h2) / 2) * width; - old_low2 = h2_low2; - old_high2 = h2_high2; - - if (h2_left < h2) // slope > 0 - { - h2_low2 = h2_left * width; - h2_high2 = mid; - h2_low1 = mid + width; - h2_high1 = h2 * width; - } - else // slope < 0 - { - h2_high2 = h2_left * width; - h2_low2 = mid + width; - h2_high1 = mid; - h2_low1 = h2 * width; - } - - // Merge the lines. - if (h2_low1 > old_low2) - h2_low1 = old_low2; - if (h2_high1 < old_high2) - h2_high1 = old_high2; - - // Fix up values for the current horizontal offset. - h2_low1 += x; - h2_high1 += x; - } - - // Fill in the background. - - if (flags & PH_GRAPH_USE_LINE_2) - { - for (i = h1_high1 + width; i < h2_low1; i += width) - { - bits[i] = lineBackColor2; - } - } - - for (i = x; i < h1_low1; i += width) - { - bits[i] = lineBackColor1; - } - - // Draw the grid. - - if (flags & PH_GRAPH_USE_GRID_X) - { - // Draw the vertical grid line. - if (gridYCounter == 0) - { - for (i = x; i < numberOfPixels; i += width) - { - bits[i] = gridColor; - } - } - - gridYCounter++; - - if (gridYCounter == DrawInfo->GridWidth) - gridYCounter = 0; - } - - if (flags & PH_GRAPH_USE_GRID_Y) - { - FLOAT level; - LONG h; - LONG h_last; - - // Draw the horizontal grid line. - if (flags & PH_GRAPH_LOGARITHMIC_GRID_Y) - { - level = gridLevel; - h = (LONG)(level * (height - 1)); - h_last = height + gridYThreshold - 1; - - while (TRUE) - { - if (h <= h_last - gridYThreshold) - { - bits[x + h * width] = gridColor; - h_last = h; - } - else - { - break; - } - - level /= gridBase; - h = (LONG)(level * (height - 1)); - } - } - else - { - level = gridHeight; - h = (LONG)(level * (height - 1)); - h_last = 0; - - while (h < height - 1) - { - if (h >= h_last + gridYThreshold) - { - bits[x + h * width] = gridColor; - h_last = h; - } - - level += gridHeight; - h = (LONG)(level * (height - 1)); - } - } - } - - // Draw the outline (line 1 is allowed to paint over line 2). - - if (flags & PH_GRAPH_USE_LINE_2) - { - for (i = h2_low1; i <= h2_high1; i += width) // exclude pixel in the middle - { - bits[i] = lineColor2; - } - } - - for (i = h1_low1; i <= h1_high1; i += width) - { - bits[i] = lineColor1; - } - - intermediate = !intermediate; - x--; - } - - if ((flags & PH_GRAPH_LABEL_MAX_Y) && yLabelDataIndex < DrawInfo->LineDataCount) - { - FLOAT value; - PPH_STRING label; - - value = DrawInfo->LineData1[yLabelDataIndex]; - - if (flags & PH_GRAPH_USE_LINE_2) - value += DrawInfo->LineData2[yLabelDataIndex]; - - if (label = DrawInfo->LabelYFunction(DrawInfo, yLabelDataIndex, value, DrawInfo->LabelYFunctionParameter)) - { - HFONT oldFont = NULL; - SIZE textSize; - RECT rect; - - if (DrawInfo->LabelYFont) - oldFont = SelectObject(hdc, DrawInfo->LabelYFont); - - SetTextColor(hdc, DrawInfo->LabelYColor); - SetBkMode(hdc, TRANSPARENT); - - GetTextExtentPoint32(hdc, label->Buffer, (ULONG)label->Length / 2, &textSize); - - rect.bottom = height - yLabelMax - PhNormalGraphTextPadding.top; - rect.top = rect.bottom - textSize.cy; - - if (rect.top < PhNormalGraphTextPadding.top) - { - rect.top = PhNormalGraphTextPadding.top; - rect.bottom = rect.top + textSize.cy; - } - - rect.left = 0; - rect.right = width - min((LONG)yLabelDataIndex * 2, width) - PhNormalGraphTextPadding.right; - DrawText(hdc, label->Buffer, (ULONG)label->Length / 2, &rect, DT_NOCLIP | DT_RIGHT); - - if (oldFont) - SelectObject(hdc, oldFont); - - PhDereferenceObject(label); - } - } - - if (DrawInfo->Text.Buffer) - { - HFONT oldFont = NULL; - - if (DrawInfo->TextFont) - oldFont = SelectObject(hdc, DrawInfo->TextFont); - - // Fill in the text box. - SetDCBrushColor(hdc, DrawInfo->TextBoxColor); - FillRect(hdc, &DrawInfo->TextBoxRect, GetStockObject(DC_BRUSH)); - - // Draw the text. - SetTextColor(hdc, DrawInfo->TextColor); - SetBkMode(hdc, TRANSPARENT); - DrawText(hdc, DrawInfo->Text.Buffer, (ULONG)DrawInfo->Text.Length / 2, &DrawInfo->TextRect, DT_NOCLIP); - - if (oldFont) - SelectObject(hdc, oldFont); - } -} - -/** - * Sets the text in a graphing information structure. - * - * \param hdc The DC to perform calculations from. - * \param DrawInfo A structure which contains graphing information. The structure is modified to - * contain the new text information. - * \param Text The text. - * \param Margin The margins of the text box from the edges of the graph. - * \param Padding The padding within the text box. - * \param Align The alignment of the text box. - */ -VOID PhSetGraphText( - _In_ HDC hdc, - _Inout_ PPH_GRAPH_DRAW_INFO DrawInfo, - _In_ PPH_STRINGREF Text, - _In_ PRECT Margin, - _In_ PRECT Padding, - _In_ ULONG Align - ) -{ - HFONT oldFont = NULL; - SIZE textSize; - PH_RECTANGLE boxRectangle; - PH_RECTANGLE textRectangle; - - if (DrawInfo->TextFont) - oldFont = SelectObject(hdc, DrawInfo->TextFont); - - DrawInfo->Text = *Text; - GetTextExtentPoint32(hdc, Text->Buffer, (ULONG)Text->Length / 2, &textSize); - - if (oldFont) - SelectObject(hdc, oldFont); - - // Calculate the box rectangle. - - boxRectangle.Width = textSize.cx + Padding->left + Padding->right; - boxRectangle.Height = textSize.cy + Padding->top + Padding->bottom; - - if (Align & PH_ALIGN_LEFT) - boxRectangle.Left = Margin->left; - else if (Align & PH_ALIGN_RIGHT) - boxRectangle.Left = DrawInfo->Width - boxRectangle.Width - Margin->right; - else - boxRectangle.Left = (DrawInfo->Width - boxRectangle.Width) / 2; - - if (Align & PH_ALIGN_TOP) - boxRectangle.Top = Margin->top; - else if (Align & PH_ALIGN_BOTTOM) - boxRectangle.Top = DrawInfo->Height - boxRectangle.Height - Margin->bottom; - else - boxRectangle.Top = (DrawInfo->Height - boxRectangle.Height) / 2; - - // Calculate the text rectangle. - - textRectangle.Left = boxRectangle.Left + Padding->left; - textRectangle.Top = boxRectangle.Top + Padding->top; - textRectangle.Width = textSize.cx; - textRectangle.Height = textSize.cy; - - // Save the rectangles. - DrawInfo->TextRect = PhRectangleToRect(textRectangle); - DrawInfo->TextBoxRect = PhRectangleToRect(boxRectangle); -} - -VOID PhpCreateGraphContext( - _Out_ PPHP_GRAPH_CONTEXT *Context - ) -{ - PPHP_GRAPH_CONTEXT context; - - context = PhAllocate(sizeof(PHP_GRAPH_CONTEXT)); - memset(context, 0, sizeof(PHP_GRAPH_CONTEXT)); - - context->DrawInfo.Width = 3; - context->DrawInfo.Height = 3; - context->DrawInfo.Flags = PH_GRAPH_USE_GRID_X; - context->DrawInfo.Step = 2; - context->DrawInfo.BackColor = RGB(0xef, 0xef, 0xef); - context->DrawInfo.LineDataCount = 0; - context->DrawInfo.LineData1 = NULL; - context->DrawInfo.LineData2 = NULL; - context->DrawInfo.LineColor1 = RGB(0x00, 0xff, 0x00); - context->DrawInfo.LineColor2 = RGB(0xff, 0x00, 0x00); - context->DrawInfo.LineBackColor1 = RGB(0x00, 0x77, 0x00); - context->DrawInfo.LineBackColor2 = RGB(0x77, 0x00, 0x00); - context->DrawInfo.GridColor = RGB(0xc7, 0xc7, 0xc7); - context->DrawInfo.GridWidth = 20; - context->DrawInfo.GridHeight = 0.25f; - context->DrawInfo.GridXOffset = 0; - context->DrawInfo.GridYThreshold = 10; - context->DrawInfo.GridBase = 2.0f; - context->DrawInfo.LabelYColor = RGB(0x77, 0x77, 0x77); - context->DrawInfo.LabelMaxYIndexLimit = -1; - context->DrawInfo.TextColor = RGB(0x00, 0xff, 0x00); - context->DrawInfo.TextBoxColor = RGB(0x00, 0x22, 0x00); - - context->Options.FadeOutBackColor = RGB(0xef, 0xef, 0xef); - context->Options.FadeOutWidth = 100; - - *Context = context; -} - -VOID PhpFreeGraphContext( - _Inout_ _Post_invalid_ PPHP_GRAPH_CONTEXT Context - ) -{ - PhFree(Context); -} - -static PWSTR PhpMakeGraphTooltipContextAtom( - VOID - ) -{ - PH_DEFINE_MAKE_ATOM(L"PhLib_GraphTooltipContext"); -} - -static VOID PhpDeleteBufferedContext( - _In_ PPHP_GRAPH_CONTEXT Context - ) -{ - if (Context->BufferedContext) - { - // The original bitmap must be selected back into the context, otherwise the bitmap can't be - // deleted. - SelectObject(Context->BufferedContext, Context->BufferedOldBitmap); - DeleteObject(Context->BufferedBitmap); - DeleteDC(Context->BufferedContext); - - Context->BufferedContext = NULL; - Context->BufferedBitmap = NULL; - Context->BufferedBits = NULL; - } -} - -static VOID PhpCreateBufferedContext( - _In_ PPHP_GRAPH_CONTEXT Context - ) -{ - HDC hdc; - BITMAPINFOHEADER header; - - PhpDeleteBufferedContext(Context); - - GetClientRect(Context->Handle, &Context->BufferedContextRect); - - hdc = GetDC(Context->Handle); - Context->BufferedContext = CreateCompatibleDC(hdc); - - memset(&header, 0, sizeof(BITMAPINFOHEADER)); - header.biSize = sizeof(BITMAPINFOHEADER); - header.biWidth = Context->BufferedContextRect.right; - header.biHeight = Context->BufferedContextRect.bottom; - header.biPlanes = 1; - header.biBitCount = 32; - - Context->BufferedBitmap = CreateDIBSection(hdc, (BITMAPINFO *)&header, DIB_RGB_COLORS, &Context->BufferedBits, NULL, 0); - - ReleaseDC(Context->Handle, hdc); - Context->BufferedOldBitmap = SelectObject(Context->BufferedContext, Context->BufferedBitmap); -} - -static VOID PhpDeleteFadeOutContext( - _In_ PPHP_GRAPH_CONTEXT Context - ) -{ - if (Context->FadeOutContext) - { - SelectObject(Context->FadeOutContext, Context->FadeOutOldBitmap); - DeleteObject(Context->FadeOutBitmap); - DeleteDC(Context->FadeOutContext); - - Context->FadeOutContext = NULL; - Context->FadeOutBitmap = NULL; - Context->FadeOutBits = NULL; - } -} - -static VOID PhpCreateFadeOutContext( - _In_ PPHP_GRAPH_CONTEXT Context - ) -{ - HDC hdc; - BITMAPINFOHEADER header; - ULONG i; - ULONG j; - ULONG height; - COLORREF backColor; - ULONG fadeOutWidth; - FLOAT fadeOutWidthSquared; - ULONG currentAlpha; - ULONG currentColor; - - PhpDeleteFadeOutContext(Context); - - GetClientRect(Context->Handle, &Context->FadeOutContextRect); - Context->FadeOutContextRect.right = Context->Options.FadeOutWidth; - - hdc = GetDC(Context->Handle); - Context->FadeOutContext = CreateCompatibleDC(hdc); - - memset(&header, 0, sizeof(BITMAPINFOHEADER)); - header.biSize = sizeof(BITMAPINFOHEADER); - header.biWidth = Context->FadeOutContextRect.right; - header.biHeight = Context->FadeOutContextRect.bottom; - header.biPlanes = 1; - header.biBitCount = 32; - - Context->FadeOutBitmap = CreateDIBSection(hdc, (BITMAPINFO *)&header, DIB_RGB_COLORS, &Context->FadeOutBits, NULL, 0); - - ReleaseDC(Context->Handle, hdc); - Context->FadeOutOldBitmap = SelectObject(Context->FadeOutContext, Context->FadeOutBitmap); - - if (!Context->FadeOutBits) - return; - - height = Context->FadeOutContextRect.bottom; - backColor = Context->Options.FadeOutBackColor; - fadeOutWidth = Context->Options.FadeOutWidth; - fadeOutWidthSquared = (FLOAT)fadeOutWidth * fadeOutWidth; - - for (i = 0; i < fadeOutWidth; i++) - { - currentAlpha = 255 - (ULONG)((FLOAT)(i * i) / fadeOutWidthSquared * 255); - currentColor = - ((backColor & 0xff) * currentAlpha / 255) + - ((((backColor >> 8) & 0xff) * currentAlpha / 255) << 8) + - ((((backColor >> 16) & 0xff) * currentAlpha / 255) << 16) + - (currentAlpha << 24); - - for (j = i; j < height * fadeOutWidth; j += fadeOutWidth) - { - ((PULONG)Context->FadeOutBits)[j] = currentColor; - } - } -} - -VOID PhpUpdateDrawInfo( - _In_ HWND hwnd, - _In_ PPHP_GRAPH_CONTEXT Context - ) -{ - PH_GRAPH_GETDRAWINFO getDrawInfo; - - Context->DrawInfo.Width = Context->BufferedContextRect.right; - Context->DrawInfo.Height = Context->BufferedContextRect.bottom; - - getDrawInfo.Header.hwndFrom = hwnd; - getDrawInfo.Header.idFrom = Context->Id; - getDrawInfo.Header.code = GCN_GETDRAWINFO; - getDrawInfo.DrawInfo = &Context->DrawInfo; - - SendMessage(GetParent(hwnd), WM_NOTIFY, 0, (LPARAM)&getDrawInfo); -} - -VOID PhpDrawGraphControl( - _In_ HWND hwnd, - _In_ PPHP_GRAPH_CONTEXT Context - ) -{ - if (Context->BufferedBits) - PhDrawGraphDirect(Context->BufferedContext, Context->BufferedBits, &Context->DrawInfo); - - if (Context->Style & GC_STYLE_FADEOUT) - { - BLENDFUNCTION blendFunction; - - if (!Context->FadeOutContext) - PhpCreateFadeOutContext(Context); - - blendFunction.BlendOp = AC_SRC_OVER; - blendFunction.BlendFlags = 0; - blendFunction.SourceConstantAlpha = 255; - blendFunction.AlphaFormat = AC_SRC_ALPHA; - GdiAlphaBlend( - Context->BufferedContext, - 0, - 0, - Context->Options.FadeOutWidth, - Context->FadeOutContextRect.bottom, - Context->FadeOutContext, - 0, - 0, - Context->Options.FadeOutWidth, - Context->FadeOutContextRect.bottom, - blendFunction - ); - } - - if (Context->Style & GC_STYLE_DRAW_PANEL) - { - PH_GRAPH_DRAWPANEL drawPanel; - - drawPanel.Header.hwndFrom = hwnd; - drawPanel.Header.idFrom = Context->Id; - drawPanel.Header.code = GCN_DRAWPANEL; - drawPanel.hdc = Context->BufferedContext; - drawPanel.Rect = Context->BufferedContextRect; - - SendMessage(GetParent(hwnd), WM_NOTIFY, 0, (LPARAM)&drawPanel); - } -} - -LRESULT CALLBACK PhpGraphWndProc( - _In_ HWND hwnd, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - PPHP_GRAPH_CONTEXT context; - - context = (PPHP_GRAPH_CONTEXT)GetWindowLongPtr(hwnd, 0); - - if (uMsg == WM_CREATE) - { - PhpCreateGraphContext(&context); - SetWindowLongPtr(hwnd, 0, (LONG_PTR)context); - } - - if (!context) - return DefWindowProc(hwnd, uMsg, wParam, lParam); - - switch (uMsg) - { - case WM_MOUSEMOVE: - case WM_LBUTTONDOWN: - case WM_LBUTTONUP: - case WM_RBUTTONDOWN: - case WM_RBUTTONUP: - case WM_MBUTTONDOWN: - case WM_MBUTTONUP: - { - if (context->TooltipHandle) - { - MSG message; - - message.hwnd = hwnd; - message.message = uMsg; - message.wParam = wParam; - message.lParam = lParam; - SendMessage(context->TooltipHandle, TTM_RELAYEVENT, 0, (LPARAM)&message); - } - } - break; - } - - switch (uMsg) - { - case WM_CREATE: - { - CREATESTRUCT *createStruct = (CREATESTRUCT *)lParam; - - context->Handle = hwnd; - context->Style = createStruct->style; - context->Id = (ULONG_PTR)createStruct->hMenu; - } - break; - case WM_DESTROY: - { - SetWindowLongPtr(hwnd, 0, (LONG_PTR)NULL); - - if (context->TooltipHandle) - DestroyWindow(context->TooltipHandle); - - PhpDeleteFadeOutContext(context); - PhpDeleteBufferedContext(context); - PhpFreeGraphContext(context); - } - break; - case WM_STYLECHANGED: - { - STYLESTRUCT *styleStruct = (STYLESTRUCT *)lParam; - - if (wParam == GWL_STYLE) - { - context->Style = styleStruct->styleNew; - context->NeedsDraw = TRUE; - } - } - break; - case WM_SIZE: - { - // Force a re-create of the buffered context. - PhpCreateBufferedContext(context); - PhpDeleteFadeOutContext(context); - - PhpUpdateDrawInfo(hwnd, context); - context->NeedsDraw = TRUE; - InvalidateRect(hwnd, NULL, FALSE); - - if (context->TooltipHandle) - { - TOOLINFO toolInfo; - - memset(&toolInfo, 0, sizeof(TOOLINFO)); - toolInfo.cbSize = sizeof(TOOLINFO); - toolInfo.hwnd = hwnd; - toolInfo.uId = 1; - GetClientRect(hwnd, &toolInfo.rect); - SendMessage(context->TooltipHandle, TTM_NEWTOOLRECT, 0, (LPARAM)&toolInfo); - } - } - break; - case WM_PAINT: - { - PAINTSTRUCT paintStruct; - HDC hdc; - - if (hdc = BeginPaint(hwnd, &paintStruct)) - { - if (!context->BufferedContext) - PhpCreateBufferedContext(context); - - if (context->NeedsUpdate) - { - PhpUpdateDrawInfo(hwnd, context); - context->NeedsUpdate = FALSE; - } - - if (context->NeedsDraw) - { - PhpDrawGraphControl(hwnd, context); - context->NeedsDraw = FALSE; - } - - BitBlt( - hdc, - paintStruct.rcPaint.left, - paintStruct.rcPaint.top, - paintStruct.rcPaint.right - paintStruct.rcPaint.left, - paintStruct.rcPaint.bottom - paintStruct.rcPaint.top, - context->BufferedContext, - paintStruct.rcPaint.left, - paintStruct.rcPaint.top, - SRCCOPY - ); - - EndPaint(hwnd, &paintStruct); - } - } - return 0; - case WM_ERASEBKGND: - return 1; - case WM_NCPAINT: - { - HRGN updateRegion; - - updateRegion = (HRGN)wParam; - - if (updateRegion == (HRGN)1) // HRGN_FULL - updateRegion = NULL; - - // Themed border - if (context->Style & WS_BORDER) - { - HDC hdc; - ULONG flags; - RECT rect; - - // Note the use of undocumented flags below. GetDCEx doesn't work without these. - - flags = DCX_WINDOW | DCX_LOCKWINDOWUPDATE | 0x10000; - - if (updateRegion) - flags |= DCX_INTERSECTRGN | 0x40000; - - if (hdc = GetDCEx(hwnd, updateRegion, flags)) - { - GetClientRect(hwnd, &rect); - rect.right += 2; - rect.bottom += 2; - SetDCBrushColor(hdc, RGB(0x8f, 0x8f, 0x8f)); - FrameRect(hdc, &rect, GetStockObject(DC_BRUSH)); - - ReleaseDC(hwnd, hdc); - return 0; - } - } - } - break; - case WM_NOTIFY: - { - LPNMHDR header = (LPNMHDR)lParam; - - if (header->hwndFrom == context->TooltipHandle) - { - switch (header->code) - { - case TTN_GETDISPINFO: - { - LPNMTTDISPINFO dispInfo = (LPNMTTDISPINFO)header; - POINT point; - RECT clientRect; - PH_GRAPH_GETTOOLTIPTEXT getTooltipText; - - GetCursorPos(&point); - ScreenToClient(hwnd, &point); - GetClientRect(hwnd, &clientRect); - - getTooltipText.Header.hwndFrom = hwnd; - getTooltipText.Header.idFrom = context->Id; - getTooltipText.Header.code = GCN_GETTOOLTIPTEXT; - getTooltipText.Index = (clientRect.right - point.x - 1) / context->DrawInfo.Step; - getTooltipText.TotalCount = context->DrawInfo.LineDataCount; - getTooltipText.Text.Buffer = NULL; - getTooltipText.Text.Length = 0; - - SendMessage(GetParent(hwnd), WM_NOTIFY, 0, (LPARAM)&getTooltipText); - - if (getTooltipText.Text.Buffer) - { - dispInfo->lpszText = getTooltipText.Text.Buffer; - } - } - break; - } - } - } - break; - case WM_SETCURSOR: - { - if (context->Options.DefaultCursor) - { - SetCursor(context->Options.DefaultCursor); - return TRUE; - } - } - break; - case WM_MOUSEMOVE: - { - if (context->TooltipHandle) - { - POINT point; - - GetCursorPos(&point); - ScreenToClient(hwnd, &point); - - if (context->LastCursorLocation.x != point.x || context->LastCursorLocation.y != point.y) - { - SendMessage(context->TooltipHandle, TTM_UPDATE, 0, 0); - context->LastCursorLocation = point; - } - } - } - break; - case WM_LBUTTONDOWN: - case WM_LBUTTONUP: - case WM_LBUTTONDBLCLK: - case WM_RBUTTONDOWN: - case WM_RBUTTONUP: - case WM_RBUTTONDBLCLK: - { - PH_GRAPH_MOUSEEVENT mouseEvent; - RECT clientRect; - - GetClientRect(hwnd, &clientRect); - - mouseEvent.Header.hwndFrom = hwnd; - mouseEvent.Header.idFrom = context->Id; - mouseEvent.Header.code = GCN_MOUSEEVENT; - mouseEvent.Message = uMsg; - mouseEvent.Keys = (ULONG)wParam; - mouseEvent.Point.x = LOWORD(lParam); - mouseEvent.Point.y = HIWORD(lParam); - - mouseEvent.Index = (clientRect.right - mouseEvent.Point.x - 1) / context->DrawInfo.Step; - mouseEvent.TotalCount = context->DrawInfo.LineDataCount; - - SendMessage(GetParent(hwnd), WM_NOTIFY, 0, (LPARAM)&mouseEvent); - } - break; - case GCM_GETDRAWINFO: - { - PPH_GRAPH_DRAW_INFO drawInfo = (PPH_GRAPH_DRAW_INFO)lParam; - - memcpy(drawInfo, &context->DrawInfo, sizeof(PH_GRAPH_DRAW_INFO)); - } - return TRUE; - case GCM_SETDRAWINFO: - { - PPH_GRAPH_DRAW_INFO drawInfo = (PPH_GRAPH_DRAW_INFO)lParam; - ULONG width; - ULONG height; - - width = context->DrawInfo.Width; - height = context->DrawInfo.Height; - memcpy(&context->DrawInfo, drawInfo, sizeof(PH_GRAPH_DRAW_INFO)); - context->DrawInfo.Width = width; - context->DrawInfo.Height = height; - } - return TRUE; - case GCM_DRAW: - { - PhpUpdateDrawInfo(hwnd, context); - context->NeedsDraw = TRUE; - } - return TRUE; - case GCM_MOVEGRID: - { - LONG increment = (LONG)wParam; - - context->DrawInfo.GridXOffset += increment; - } - return TRUE; - case GCM_GETBUFFEREDCONTEXT: - return (LRESULT)context->BufferedContext; - case GCM_SETTOOLTIP: - { - if (wParam) - { - TOOLINFO toolInfo = { sizeof(toolInfo) }; - - context->TooltipHandle = CreateWindow( - TOOLTIPS_CLASS, - NULL, - WS_POPUP | WS_EX_TRANSPARENT | TTS_NOPREFIX, - CW_USEDEFAULT, - CW_USEDEFAULT, - CW_USEDEFAULT, - CW_USEDEFAULT, - NULL, - NULL, - PhLibImageBase, - NULL - ); - - SetWindowPos(context->TooltipHandle, HWND_TOPMOST, 0, 0, 0, 0, - SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); - - toolInfo.uFlags = 0; - toolInfo.hwnd = hwnd; - toolInfo.uId = 1; - toolInfo.lpszText = LPSTR_TEXTCALLBACK; - GetClientRect(hwnd, &toolInfo.rect); - SendMessage(context->TooltipHandle, TTM_ADDTOOL, 0, (LPARAM)&toolInfo); - - SendMessage(context->TooltipHandle, TTM_SETDELAYTIME, TTDT_INITIAL, 0); - SendMessage(context->TooltipHandle, TTM_SETDELAYTIME, TTDT_AUTOPOP, MAXSHORT); - // Allow newlines (-1 doesn't work) - SendMessage(context->TooltipHandle, TTM_SETMAXTIPWIDTH, 0, MAXSHORT); - } - else - { - DestroyWindow(context->TooltipHandle); - context->TooltipHandle = NULL; - } - } - return TRUE; - case GCM_UPDATETOOLTIP: - { - if (!context->TooltipHandle) - return FALSE; - - SendMessage(context->TooltipHandle, TTM_UPDATE, 0, 0); - } - return TRUE; - case GCM_GETOPTIONS: - memcpy((PPH_GRAPH_OPTIONS)lParam, &context->Options, sizeof(PH_GRAPH_OPTIONS)); - return TRUE; - case GCM_SETOPTIONS: - memcpy(&context->Options, (PPH_GRAPH_OPTIONS)lParam, sizeof(PH_GRAPH_OPTIONS)); - PhpDeleteFadeOutContext(context); - return TRUE; - } - - return DefWindowProc(hwnd, uMsg, wParam, lParam); -} - -/** - * Initializes a graph buffer management structure. - * - * \param Buffers The buffer management structure. - */ -VOID PhInitializeGraphBuffers( - _Out_ PPH_GRAPH_BUFFERS Buffers - ) -{ - Buffers->AllocatedCount = 0; - Buffers->Data1 = NULL; - Buffers->Data2 = NULL; - Buffers->Valid = FALSE; -} - -/** - * Frees resources used by a graph buffer management structure. - * - * \param Buffers The buffer management structure. - */ -VOID PhDeleteGraphBuffers( - _Inout_ PPH_GRAPH_BUFFERS Buffers - ) -{ - if (Buffers->Data1) PhFree(Buffers->Data1); - if (Buffers->Data2) PhFree(Buffers->Data2); -} - -/** - * Sets up a graphing information structure with information from a graph buffer management - * structure. - * - * \param Buffers The buffer management structure. - * \param DrawInfo The graphing information structure. - * \param DataCount The number of data points currently required. The buffers are resized if needed. - */ -VOID PhGetDrawInfoGraphBuffers( - _Inout_ PPH_GRAPH_BUFFERS Buffers, - _Inout_ PPH_GRAPH_DRAW_INFO DrawInfo, - _In_ ULONG DataCount - ) -{ - DrawInfo->LineDataCount = min(DataCount, PH_GRAPH_DATA_COUNT(DrawInfo->Width, DrawInfo->Step)); - - // Do we need to allocate or re-allocate the data buffers? - if (Buffers->AllocatedCount < DrawInfo->LineDataCount) - { - if (Buffers->Data1) - PhFree(Buffers->Data1); - if ((DrawInfo->Flags & PH_GRAPH_USE_LINE_2) && Buffers->Data2) - PhFree(Buffers->Data2); - - Buffers->AllocatedCount *= 2; - - if (Buffers->AllocatedCount < DrawInfo->LineDataCount) - Buffers->AllocatedCount = DrawInfo->LineDataCount; - - Buffers->Data1 = PhAllocate(Buffers->AllocatedCount * sizeof(FLOAT)); - - if (DrawInfo->Flags & PH_GRAPH_USE_LINE_2) - { - Buffers->Data2 = PhAllocate(Buffers->AllocatedCount * sizeof(FLOAT)); - } - - Buffers->Valid = FALSE; - } - - DrawInfo->LineData1 = Buffers->Data1; - DrawInfo->LineData2 = Buffers->Data2; -} - -VOID PhInitializeGraphState( - _Out_ PPH_GRAPH_STATE State - ) -{ - PhInitializeGraphBuffers(&State->Buffers); - State->Text = NULL; - State->TooltipText = NULL; - State->TooltipIndex = -1; -} - -VOID PhDeleteGraphState( - _Inout_ PPH_GRAPH_STATE State - ) -{ - PhDeleteGraphBuffers(&State->Buffers); - if (State->Text) PhDereferenceObject(State->Text); - if (State->TooltipText) PhDereferenceObject(State->TooltipText); -} - -VOID PhGraphStateGetDrawInfo( - _Inout_ PPH_GRAPH_STATE State, - _In_ PPH_GRAPH_GETDRAWINFO GetDrawInfo, - _In_ ULONG DataCount - ) -{ - PhGetDrawInfoGraphBuffers(&State->Buffers, GetDrawInfo->DrawInfo, DataCount); -} +/* + * Process Hacker - + * graph control + * + * Copyright (C) 2010-2016 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include + +#include + +#include +#include + +#define COLORREF_TO_BITS(Color) (_byteswap_ulong(Color) >> 8) + +typedef struct _PHP_GRAPH_CONTEXT +{ + HWND Handle; + ULONG Style; + ULONG_PTR Id; + PH_GRAPH_DRAW_INFO DrawInfo; + PH_GRAPH_OPTIONS Options; + BOOLEAN NeedsUpdate; + BOOLEAN NeedsDraw; + + HDC BufferedContext; + HBITMAP BufferedOldBitmap; + HBITMAP BufferedBitmap; + PVOID BufferedBits; + RECT BufferedContextRect; + + HDC FadeOutContext; + HBITMAP FadeOutOldBitmap; + HBITMAP FadeOutBitmap; + PVOID FadeOutBits; + RECT FadeOutContextRect; + + HWND TooltipHandle; + WNDPROC TooltipOldWndProc; + POINT LastCursorLocation; +} PHP_GRAPH_CONTEXT, *PPHP_GRAPH_CONTEXT; + +LRESULT CALLBACK PhpGraphWndProc( + _In_ HWND hwnd, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +RECT PhNormalGraphTextMargin = { 5, 5, 5, 5 }; +RECT PhNormalGraphTextPadding = { 3, 3, 3, 3 }; + +BOOLEAN PhGraphControlInitialization( + VOID + ) +{ + WNDCLASSEX c = { sizeof(c) }; + + c.style = CS_GLOBALCLASS | CS_DBLCLKS; + c.lpfnWndProc = PhpGraphWndProc; + c.cbClsExtra = 0; + c.cbWndExtra = sizeof(PVOID); + c.hInstance = PhLibImageBase; + c.hIcon = NULL; + c.hCursor = LoadCursor(NULL, IDC_ARROW); + c.hbrBackground = NULL; + c.lpszMenuName = NULL; + c.lpszClassName = PH_GRAPH_CLASSNAME; + c.hIconSm = NULL; + + if (!RegisterClassEx(&c)) + return FALSE; + + return TRUE; +} + +FORCEINLINE VOID PhpGetGraphPoint( + _In_ PPH_GRAPH_DRAW_INFO DrawInfo, + _In_ ULONG Index, + _Out_ PULONG H1, + _Out_ PULONG H2 + ) +{ + if (Index < DrawInfo->LineDataCount) + { + FLOAT f1; + FLOAT f2; + + f1 = DrawInfo->LineData1[Index]; + + if (f1 < 0) + f1 = 0; + if (f1 > 1) + f1 = 1; + + *H1 = (ULONG)(f1 * (DrawInfo->Height - 1)); + + if (DrawInfo->Flags & PH_GRAPH_USE_LINE_2) + { + f2 = f1 + DrawInfo->LineData2[Index]; + + if (f2 < 0) + f2 = 0; + if (f2 > 1) + f2 = 1; + + *H2 = (ULONG)(f2 * (DrawInfo->Height - 1)); + } + else + { + *H2 = *H1; + } + } + else + { + *H1 = 0; + *H2 = 0; + } +} + +/** + * Draws a graph directly to memory. + * + * \param hdc The DC to draw to. This is only used when drawing text. + * \param Bits The bits in a bitmap. + * \param DrawInfo A structure which contains graphing information. + * + * \remarks The following information is fixed: + * \li The graph is fixed to the origin (0, 0). + * \li The total size of the bitmap is assumed to be \a Width and \a Height in \a DrawInfo. + * \li \a Step is fixed at 2. + * \li If \ref PH_GRAPH_USE_LINE_2 is specified in \a Flags, \ref PH_GRAPH_OVERLAY_LINE_2 is never + * used. + */ +VOID PhDrawGraphDirect( + _In_ HDC hdc, + _In_ PVOID Bits, + _In_ PPH_GRAPH_DRAW_INFO DrawInfo + ) +{ + PULONG bits = Bits; + LONG width = DrawInfo->Width; + LONG height = DrawInfo->Height; + LONG numberOfPixels = width * height; + ULONG flags = DrawInfo->Flags; + LONG i; + LONG x; + + BOOLEAN intermediate = FALSE; // whether we are currently between two data positions + ULONG dataIndex = 0; // the data index of the current position + ULONG h1_i; // the line 1 height value to the left of the current position + ULONG h1_o; // the line 1 height value at the current position + ULONG h2_i; // the line 1 + line 2 height value to the left of the current position + ULONG h2_o; // the line 1 + line 2 height value at the current position + ULONG h1; // current pixel + ULONG h1_left; // current pixel + ULONG h2; // current pixel + ULONG h2_left; // current pixel + + LONG mid; + LONG h1_low1; + LONG h1_high1; + LONG h1_low2; + LONG h1_high2; + LONG h2_low1; + LONG h2_high1; + LONG h2_low2; + LONG h2_high2; + LONG old_low2; + LONG old_high2; + + ULONG lineColor1; + ULONG lineBackColor1; + ULONG lineColor2; + ULONG lineBackColor2; + FLOAT gridHeight; + LONG gridYThreshold; + ULONG gridYCounter; + ULONG gridColor; + FLOAT gridBase; + FLOAT gridLevel; + + ULONG yLabelMax; + ULONG yLabelDataIndex; + + lineColor1 = COLORREF_TO_BITS(DrawInfo->LineColor1); + lineBackColor1 = COLORREF_TO_BITS(DrawInfo->LineBackColor1); + lineColor2 = COLORREF_TO_BITS(DrawInfo->LineColor2); + lineBackColor2 = COLORREF_TO_BITS(DrawInfo->LineBackColor2); + + if (DrawInfo->BackColor == 0) + { + memset(bits, 0, numberOfPixels * 4); + } + else + { + PhFillMemoryUlong(bits, COLORREF_TO_BITS(DrawInfo->BackColor), numberOfPixels); + } + + x = width - 1; + h1_low2 = MAXLONG; + h1_high2 = 0; + h2_low2 = MAXLONG; + h2_high2 = 0; + + PhpGetGraphPoint(DrawInfo, 0, &h1_i, &h2_i); + + if (flags & (PH_GRAPH_USE_GRID_X | PH_GRAPH_USE_GRID_Y)) + { + gridHeight = max(DrawInfo->GridHeight, 0); + gridLevel = gridHeight; + gridYThreshold = DrawInfo->GridYThreshold; + gridYCounter = DrawInfo->GridWidth - (DrawInfo->GridXOffset * DrawInfo->Step) % DrawInfo->GridWidth - 1; + gridColor = COLORREF_TO_BITS(DrawInfo->GridColor); + } + + if ((flags & (PH_GRAPH_USE_GRID_Y | PH_GRAPH_LOGARITHMIC_GRID_Y)) == (PH_GRAPH_USE_GRID_Y | PH_GRAPH_LOGARITHMIC_GRID_Y)) + { + // Pre-process to find the largest integer n such that GridHeight*GridBase^n < 1. + + gridBase = DrawInfo->GridBase; + + if (gridBase > 1) + { + DOUBLE logBase; + DOUBLE exponent; + DOUBLE high; + + logBase = log(gridBase); + exponent = ceil(-log(gridHeight) / logBase) - 1; // Works for both GridHeight > 1 and GridHeight < 1 + high = exp(exponent * logBase); + gridLevel = (FLOAT)(gridHeight * high); + + if (gridLevel < 0 || !isfinite(gridLevel)) + gridLevel = 0; + if (gridLevel > 1) + gridLevel = 1; + } + else + { + // This is an error. + gridLevel = 0; + } + } + + if (flags & PH_GRAPH_LABEL_MAX_Y) + { + yLabelMax = h2_i; + yLabelDataIndex = 0; + } + + while (x >= 0) + { + // Calculate the height of the graph at this point. + + if (!intermediate) + { + h1_o = h1_i; + h2_o = h2_i; + + // Pull in new data. + dataIndex++; + PhpGetGraphPoint(DrawInfo, dataIndex, &h1_i, &h2_i); + + h1 = h1_o; + h1_left = (h1_i + h1_o) / 2; + h2 = h2_o; + h2_left = (h2_i + h2_o) / 2; + + if ((flags & PH_GRAPH_LABEL_MAX_Y) && dataIndex < DrawInfo->LabelMaxYIndexLimit) + { + if (yLabelMax <= h2_i) + { + yLabelMax = h2_i; + yLabelDataIndex = dataIndex; + } + } + } + else + { + h1 = h1_left; + h1_left = h1_i; + h2 = h2_left; + h2_left = h2_i; + } + + // The graph is drawn right-to-left. There is one iteration of the loop per horizontal pixel. + // There is a fixed step value of 2, so every other iteration is a mid-point (intermediate) + // iteration with a height value of (left + right) / 2. In order to rasterize the outline, + // effectively in each iteration half of the line is drawn at the current column and the other + // half is drawn in the column to the left. + + // Rasterize the data outline. + // h?_low2 to h?_high2 is the vertical line to the left of the current pixel. + // h?_low1 to h?_high1 is the vertical line at the current pixel. + // We merge (union) the old h?_low2 to h?_high2 line with the current line in each iteration. + // + // For example: + // + // X represents a data point. M represents the mid-point between two data points ("intermediate"). + // X, M and x are all part of the outline. # represents the background filled in during + // the current loop iteration. + // + // slope > 0: slope < 0: + // + // X < high1 X < high2 (of next loop iteration) + // x x + // x < low1 x < low2 (of next loop iteration) + // x# < high2 x < high1 (of next loop iteration) + // M# < low2 M < low1 (of next loop iteration) + // x# < high1 (of next loop iteration) x < high2 + // x# < low1 (of next loop iteration) x < low2 + // x # < high2 (of next loop iteration) x < high1 + // x # x + // X # < low2 (of next loop iteration) X < low1 + // # # + // ^ ^ + // ^| current pixel ^| current pixel + // | | + // | left of current pixel | left of current pixel + // + // In both examples above, the line low2-high2 will be merged with the line low1-high1 of + // the next iteration. + + mid = ((h1_left + h1) / 2) * width; + old_low2 = h1_low2; + old_high2 = h1_high2; + + if (h1_left < h1) // slope > 0 + { + h1_low2 = h1_left * width; + h1_high2 = mid; + h1_low1 = mid + width; + h1_high1 = h1 * width; + } + else // slope < 0 + { + h1_high2 = h1_left * width; + h1_low2 = mid + width; + h1_high1 = mid; + h1_low1 = h1 * width; + } + + // Merge the lines. + if (h1_low1 > old_low2) + h1_low1 = old_low2; + if (h1_high1 < old_high2) + h1_high1 = old_high2; + + // Fix up values for the current horizontal offset. + h1_low1 += x; + h1_high1 += x; + + if (flags & PH_GRAPH_USE_LINE_2) + { + mid = ((h2_left + h2) / 2) * width; + old_low2 = h2_low2; + old_high2 = h2_high2; + + if (h2_left < h2) // slope > 0 + { + h2_low2 = h2_left * width; + h2_high2 = mid; + h2_low1 = mid + width; + h2_high1 = h2 * width; + } + else // slope < 0 + { + h2_high2 = h2_left * width; + h2_low2 = mid + width; + h2_high1 = mid; + h2_low1 = h2 * width; + } + + // Merge the lines. + if (h2_low1 > old_low2) + h2_low1 = old_low2; + if (h2_high1 < old_high2) + h2_high1 = old_high2; + + // Fix up values for the current horizontal offset. + h2_low1 += x; + h2_high1 += x; + } + + // Fill in the background. + + if (flags & PH_GRAPH_USE_LINE_2) + { + for (i = h1_high1 + width; i < h2_low1; i += width) + { + bits[i] = lineBackColor2; + } + } + + for (i = x; i < h1_low1; i += width) + { + bits[i] = lineBackColor1; + } + + // Draw the grid. + + if (flags & PH_GRAPH_USE_GRID_X) + { + // Draw the vertical grid line. + if (gridYCounter == 0) + { + for (i = x; i < numberOfPixels; i += width) + { + bits[i] = gridColor; + } + } + + gridYCounter++; + + if (gridYCounter == DrawInfo->GridWidth) + gridYCounter = 0; + } + + if (flags & PH_GRAPH_USE_GRID_Y) + { + FLOAT level; + LONG h; + LONG h_last; + + // Draw the horizontal grid line. + if (flags & PH_GRAPH_LOGARITHMIC_GRID_Y) + { + level = gridLevel; + h = (LONG)(level * (height - 1)); + h_last = height + gridYThreshold - 1; + + while (TRUE) + { + if (h <= h_last - gridYThreshold) + { + bits[x + h * width] = gridColor; + h_last = h; + } + else + { + break; + } + + level /= gridBase; + h = (LONG)(level * (height - 1)); + } + } + else + { + level = gridHeight; + h = (LONG)(level * (height - 1)); + h_last = 0; + + while (h < height - 1) + { + if (h >= h_last + gridYThreshold) + { + bits[x + h * width] = gridColor; + h_last = h; + } + + level += gridHeight; + h = (LONG)(level * (height - 1)); + } + } + } + + // Draw the outline (line 1 is allowed to paint over line 2). + + if (flags & PH_GRAPH_USE_LINE_2) + { + for (i = h2_low1; i <= h2_high1; i += width) // exclude pixel in the middle + { + bits[i] = lineColor2; + } + } + + for (i = h1_low1; i <= h1_high1; i += width) + { + bits[i] = lineColor1; + } + + intermediate = !intermediate; + x--; + } + + if ((flags & PH_GRAPH_LABEL_MAX_Y) && yLabelDataIndex < DrawInfo->LineDataCount) + { + FLOAT value; + PPH_STRING label; + + value = DrawInfo->LineData1[yLabelDataIndex]; + + if (flags & PH_GRAPH_USE_LINE_2) + value += DrawInfo->LineData2[yLabelDataIndex]; + + if (label = DrawInfo->LabelYFunction(DrawInfo, yLabelDataIndex, value, DrawInfo->LabelYFunctionParameter)) + { + HFONT oldFont = NULL; + SIZE textSize; + RECT rect; + + if (DrawInfo->LabelYFont) + oldFont = SelectObject(hdc, DrawInfo->LabelYFont); + + SetTextColor(hdc, DrawInfo->LabelYColor); + SetBkMode(hdc, TRANSPARENT); + + GetTextExtentPoint32(hdc, label->Buffer, (ULONG)label->Length / 2, &textSize); + + rect.bottom = height - yLabelMax - PhNormalGraphTextPadding.top; + rect.top = rect.bottom - textSize.cy; + + if (rect.top < PhNormalGraphTextPadding.top) + { + rect.top = PhNormalGraphTextPadding.top; + rect.bottom = rect.top + textSize.cy; + } + + rect.left = 0; + rect.right = width - min((LONG)yLabelDataIndex * 2, width) - PhNormalGraphTextPadding.right; + DrawText(hdc, label->Buffer, (ULONG)label->Length / 2, &rect, DT_NOCLIP | DT_RIGHT); + + if (oldFont) + SelectObject(hdc, oldFont); + + PhDereferenceObject(label); + } + } + + if (DrawInfo->Text.Buffer) + { + HFONT oldFont = NULL; + + if (DrawInfo->TextFont) + oldFont = SelectObject(hdc, DrawInfo->TextFont); + + // Fill in the text box. + SetDCBrushColor(hdc, DrawInfo->TextBoxColor); + FillRect(hdc, &DrawInfo->TextBoxRect, GetStockObject(DC_BRUSH)); + + // Draw the text. + SetTextColor(hdc, DrawInfo->TextColor); + SetBkMode(hdc, TRANSPARENT); + DrawText(hdc, DrawInfo->Text.Buffer, (ULONG)DrawInfo->Text.Length / 2, &DrawInfo->TextRect, DT_NOCLIP); + + if (oldFont) + SelectObject(hdc, oldFont); + } +} + +/** + * Sets the text in a graphing information structure. + * + * \param hdc The DC to perform calculations from. + * \param DrawInfo A structure which contains graphing information. The structure is modified to + * contain the new text information. + * \param Text The text. + * \param Margin The margins of the text box from the edges of the graph. + * \param Padding The padding within the text box. + * \param Align The alignment of the text box. + */ +VOID PhSetGraphText( + _In_ HDC hdc, + _Inout_ PPH_GRAPH_DRAW_INFO DrawInfo, + _In_ PPH_STRINGREF Text, + _In_ PRECT Margin, + _In_ PRECT Padding, + _In_ ULONG Align + ) +{ + HFONT oldFont = NULL; + SIZE textSize; + PH_RECTANGLE boxRectangle; + PH_RECTANGLE textRectangle; + + if (DrawInfo->TextFont) + oldFont = SelectObject(hdc, DrawInfo->TextFont); + + DrawInfo->Text = *Text; + GetTextExtentPoint32(hdc, Text->Buffer, (ULONG)Text->Length / 2, &textSize); + + if (oldFont) + SelectObject(hdc, oldFont); + + // Calculate the box rectangle. + + boxRectangle.Width = textSize.cx + Padding->left + Padding->right; + boxRectangle.Height = textSize.cy + Padding->top + Padding->bottom; + + if (Align & PH_ALIGN_LEFT) + boxRectangle.Left = Margin->left; + else if (Align & PH_ALIGN_RIGHT) + boxRectangle.Left = DrawInfo->Width - boxRectangle.Width - Margin->right; + else + boxRectangle.Left = (DrawInfo->Width - boxRectangle.Width) / 2; + + if (Align & PH_ALIGN_TOP) + boxRectangle.Top = Margin->top; + else if (Align & PH_ALIGN_BOTTOM) + boxRectangle.Top = DrawInfo->Height - boxRectangle.Height - Margin->bottom; + else + boxRectangle.Top = (DrawInfo->Height - boxRectangle.Height) / 2; + + // Calculate the text rectangle. + + textRectangle.Left = boxRectangle.Left + Padding->left; + textRectangle.Top = boxRectangle.Top + Padding->top; + textRectangle.Width = textSize.cx; + textRectangle.Height = textSize.cy; + + // Save the rectangles. + DrawInfo->TextRect = PhRectangleToRect(textRectangle); + DrawInfo->TextBoxRect = PhRectangleToRect(boxRectangle); +} + +VOID PhpCreateGraphContext( + _Out_ PPHP_GRAPH_CONTEXT *Context + ) +{ + PPHP_GRAPH_CONTEXT context; + + context = PhAllocate(sizeof(PHP_GRAPH_CONTEXT)); + memset(context, 0, sizeof(PHP_GRAPH_CONTEXT)); + + context->DrawInfo.Width = 3; + context->DrawInfo.Height = 3; + context->DrawInfo.Flags = PH_GRAPH_USE_GRID_X; + context->DrawInfo.Step = 2; + context->DrawInfo.BackColor = RGB(0xef, 0xef, 0xef); + context->DrawInfo.LineDataCount = 0; + context->DrawInfo.LineData1 = NULL; + context->DrawInfo.LineData2 = NULL; + context->DrawInfo.LineColor1 = RGB(0x00, 0xff, 0x00); + context->DrawInfo.LineColor2 = RGB(0xff, 0x00, 0x00); + context->DrawInfo.LineBackColor1 = RGB(0x00, 0x77, 0x00); + context->DrawInfo.LineBackColor2 = RGB(0x77, 0x00, 0x00); + context->DrawInfo.GridColor = RGB(0xc7, 0xc7, 0xc7); + context->DrawInfo.GridWidth = 20; + context->DrawInfo.GridHeight = 0.25f; + context->DrawInfo.GridXOffset = 0; + context->DrawInfo.GridYThreshold = 10; + context->DrawInfo.GridBase = 2.0f; + context->DrawInfo.LabelYColor = RGB(0x77, 0x77, 0x77); + context->DrawInfo.LabelMaxYIndexLimit = -1; + context->DrawInfo.TextColor = RGB(0x00, 0xff, 0x00); + context->DrawInfo.TextBoxColor = RGB(0x00, 0x22, 0x00); + + context->Options.FadeOutBackColor = RGB(0xef, 0xef, 0xef); + context->Options.FadeOutWidth = 100; + + *Context = context; +} + +VOID PhpFreeGraphContext( + _Inout_ _Post_invalid_ PPHP_GRAPH_CONTEXT Context + ) +{ + PhFree(Context); +} + +static PWSTR PhpMakeGraphTooltipContextAtom( + VOID + ) +{ + PH_DEFINE_MAKE_ATOM(L"PhLib_GraphTooltipContext"); +} + +static VOID PhpDeleteBufferedContext( + _In_ PPHP_GRAPH_CONTEXT Context + ) +{ + if (Context->BufferedContext) + { + // The original bitmap must be selected back into the context, otherwise the bitmap can't be + // deleted. + SelectObject(Context->BufferedContext, Context->BufferedOldBitmap); + DeleteObject(Context->BufferedBitmap); + DeleteDC(Context->BufferedContext); + + Context->BufferedContext = NULL; + Context->BufferedBitmap = NULL; + Context->BufferedBits = NULL; + } +} + +static VOID PhpCreateBufferedContext( + _In_ PPHP_GRAPH_CONTEXT Context + ) +{ + HDC hdc; + BITMAPINFOHEADER header; + + PhpDeleteBufferedContext(Context); + + GetClientRect(Context->Handle, &Context->BufferedContextRect); + + hdc = GetDC(Context->Handle); + Context->BufferedContext = CreateCompatibleDC(hdc); + + memset(&header, 0, sizeof(BITMAPINFOHEADER)); + header.biSize = sizeof(BITMAPINFOHEADER); + header.biWidth = Context->BufferedContextRect.right; + header.biHeight = Context->BufferedContextRect.bottom; + header.biPlanes = 1; + header.biBitCount = 32; + + Context->BufferedBitmap = CreateDIBSection(hdc, (BITMAPINFO *)&header, DIB_RGB_COLORS, &Context->BufferedBits, NULL, 0); + + ReleaseDC(Context->Handle, hdc); + Context->BufferedOldBitmap = SelectObject(Context->BufferedContext, Context->BufferedBitmap); +} + +static VOID PhpDeleteFadeOutContext( + _In_ PPHP_GRAPH_CONTEXT Context + ) +{ + if (Context->FadeOutContext) + { + SelectObject(Context->FadeOutContext, Context->FadeOutOldBitmap); + DeleteObject(Context->FadeOutBitmap); + DeleteDC(Context->FadeOutContext); + + Context->FadeOutContext = NULL; + Context->FadeOutBitmap = NULL; + Context->FadeOutBits = NULL; + } +} + +static VOID PhpCreateFadeOutContext( + _In_ PPHP_GRAPH_CONTEXT Context + ) +{ + HDC hdc; + BITMAPINFOHEADER header; + ULONG i; + ULONG j; + ULONG height; + COLORREF backColor; + ULONG fadeOutWidth; + FLOAT fadeOutWidthSquared; + ULONG currentAlpha; + ULONG currentColor; + + PhpDeleteFadeOutContext(Context); + + GetClientRect(Context->Handle, &Context->FadeOutContextRect); + Context->FadeOutContextRect.right = Context->Options.FadeOutWidth; + + hdc = GetDC(Context->Handle); + Context->FadeOutContext = CreateCompatibleDC(hdc); + + memset(&header, 0, sizeof(BITMAPINFOHEADER)); + header.biSize = sizeof(BITMAPINFOHEADER); + header.biWidth = Context->FadeOutContextRect.right; + header.biHeight = Context->FadeOutContextRect.bottom; + header.biPlanes = 1; + header.biBitCount = 32; + + Context->FadeOutBitmap = CreateDIBSection(hdc, (BITMAPINFO *)&header, DIB_RGB_COLORS, &Context->FadeOutBits, NULL, 0); + + ReleaseDC(Context->Handle, hdc); + Context->FadeOutOldBitmap = SelectObject(Context->FadeOutContext, Context->FadeOutBitmap); + + if (!Context->FadeOutBits) + return; + + height = Context->FadeOutContextRect.bottom; + backColor = Context->Options.FadeOutBackColor; + fadeOutWidth = Context->Options.FadeOutWidth; + fadeOutWidthSquared = (FLOAT)fadeOutWidth * fadeOutWidth; + + for (i = 0; i < fadeOutWidth; i++) + { + currentAlpha = 255 - (ULONG)((FLOAT)(i * i) / fadeOutWidthSquared * 255); + currentColor = + ((backColor & 0xff) * currentAlpha / 255) + + ((((backColor >> 8) & 0xff) * currentAlpha / 255) << 8) + + ((((backColor >> 16) & 0xff) * currentAlpha / 255) << 16) + + (currentAlpha << 24); + + for (j = i; j < height * fadeOutWidth; j += fadeOutWidth) + { + ((PULONG)Context->FadeOutBits)[j] = currentColor; + } + } +} + +VOID PhpUpdateDrawInfo( + _In_ HWND hwnd, + _In_ PPHP_GRAPH_CONTEXT Context + ) +{ + PH_GRAPH_GETDRAWINFO getDrawInfo; + + Context->DrawInfo.Width = Context->BufferedContextRect.right; + Context->DrawInfo.Height = Context->BufferedContextRect.bottom; + + getDrawInfo.Header.hwndFrom = hwnd; + getDrawInfo.Header.idFrom = Context->Id; + getDrawInfo.Header.code = GCN_GETDRAWINFO; + getDrawInfo.DrawInfo = &Context->DrawInfo; + + SendMessage(GetParent(hwnd), WM_NOTIFY, 0, (LPARAM)&getDrawInfo); +} + +VOID PhpDrawGraphControl( + _In_ HWND hwnd, + _In_ PPHP_GRAPH_CONTEXT Context + ) +{ + if (Context->BufferedBits) + PhDrawGraphDirect(Context->BufferedContext, Context->BufferedBits, &Context->DrawInfo); + + if (Context->Style & GC_STYLE_FADEOUT) + { + BLENDFUNCTION blendFunction; + + if (!Context->FadeOutContext) + PhpCreateFadeOutContext(Context); + + blendFunction.BlendOp = AC_SRC_OVER; + blendFunction.BlendFlags = 0; + blendFunction.SourceConstantAlpha = 255; + blendFunction.AlphaFormat = AC_SRC_ALPHA; + GdiAlphaBlend( + Context->BufferedContext, + 0, + 0, + Context->Options.FadeOutWidth, + Context->FadeOutContextRect.bottom, + Context->FadeOutContext, + 0, + 0, + Context->Options.FadeOutWidth, + Context->FadeOutContextRect.bottom, + blendFunction + ); + } + + if (Context->Style & GC_STYLE_DRAW_PANEL) + { + PH_GRAPH_DRAWPANEL drawPanel; + + drawPanel.Header.hwndFrom = hwnd; + drawPanel.Header.idFrom = Context->Id; + drawPanel.Header.code = GCN_DRAWPANEL; + drawPanel.hdc = Context->BufferedContext; + drawPanel.Rect = Context->BufferedContextRect; + + SendMessage(GetParent(hwnd), WM_NOTIFY, 0, (LPARAM)&drawPanel); + } +} + +LRESULT CALLBACK PhpGraphWndProc( + _In_ HWND hwnd, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + PPHP_GRAPH_CONTEXT context; + + context = (PPHP_GRAPH_CONTEXT)GetWindowLongPtr(hwnd, 0); + + if (uMsg == WM_CREATE) + { + PhpCreateGraphContext(&context); + SetWindowLongPtr(hwnd, 0, (LONG_PTR)context); + } + + if (!context) + return DefWindowProc(hwnd, uMsg, wParam, lParam); + + switch (uMsg) + { + case WM_MOUSEMOVE: + case WM_LBUTTONDOWN: + case WM_LBUTTONUP: + case WM_RBUTTONDOWN: + case WM_RBUTTONUP: + case WM_MBUTTONDOWN: + case WM_MBUTTONUP: + { + if (context->TooltipHandle) + { + MSG message; + + message.hwnd = hwnd; + message.message = uMsg; + message.wParam = wParam; + message.lParam = lParam; + SendMessage(context->TooltipHandle, TTM_RELAYEVENT, 0, (LPARAM)&message); + } + } + break; + } + + switch (uMsg) + { + case WM_CREATE: + { + CREATESTRUCT *createStruct = (CREATESTRUCT *)lParam; + + context->Handle = hwnd; + context->Style = createStruct->style; + context->Id = (ULONG_PTR)createStruct->hMenu; + } + break; + case WM_DESTROY: + { + SetWindowLongPtr(hwnd, 0, (LONG_PTR)NULL); + + if (context->TooltipHandle) + DestroyWindow(context->TooltipHandle); + + PhpDeleteFadeOutContext(context); + PhpDeleteBufferedContext(context); + PhpFreeGraphContext(context); + } + break; + case WM_STYLECHANGED: + { + STYLESTRUCT *styleStruct = (STYLESTRUCT *)lParam; + + if (wParam == GWL_STYLE) + { + context->Style = styleStruct->styleNew; + context->NeedsDraw = TRUE; + } + } + break; + case WM_SIZE: + { + // Force a re-create of the buffered context. + PhpCreateBufferedContext(context); + PhpDeleteFadeOutContext(context); + + PhpUpdateDrawInfo(hwnd, context); + context->NeedsDraw = TRUE; + InvalidateRect(hwnd, NULL, FALSE); + + if (context->TooltipHandle) + { + TOOLINFO toolInfo; + + memset(&toolInfo, 0, sizeof(TOOLINFO)); + toolInfo.cbSize = sizeof(TOOLINFO); + toolInfo.hwnd = hwnd; + toolInfo.uId = 1; + GetClientRect(hwnd, &toolInfo.rect); + SendMessage(context->TooltipHandle, TTM_NEWTOOLRECT, 0, (LPARAM)&toolInfo); + } + } + break; + case WM_PAINT: + { + PAINTSTRUCT paintStruct; + HDC hdc; + + if (hdc = BeginPaint(hwnd, &paintStruct)) + { + if (!context->BufferedContext) + PhpCreateBufferedContext(context); + + if (context->NeedsUpdate) + { + PhpUpdateDrawInfo(hwnd, context); + context->NeedsUpdate = FALSE; + } + + if (context->NeedsDraw) + { + PhpDrawGraphControl(hwnd, context); + context->NeedsDraw = FALSE; + } + + BitBlt( + hdc, + paintStruct.rcPaint.left, + paintStruct.rcPaint.top, + paintStruct.rcPaint.right - paintStruct.rcPaint.left, + paintStruct.rcPaint.bottom - paintStruct.rcPaint.top, + context->BufferedContext, + paintStruct.rcPaint.left, + paintStruct.rcPaint.top, + SRCCOPY + ); + + EndPaint(hwnd, &paintStruct); + } + } + return 0; + case WM_ERASEBKGND: + return 1; + case WM_NCPAINT: + { + HRGN updateRegion; + + updateRegion = (HRGN)wParam; + + if (updateRegion == (HRGN)1) // HRGN_FULL + updateRegion = NULL; + + // Themed border + if (context->Style & WS_BORDER) + { + HDC hdc; + ULONG flags; + RECT rect; + + // Note the use of undocumented flags below. GetDCEx doesn't work without these. + + flags = DCX_WINDOW | DCX_LOCKWINDOWUPDATE | 0x10000; + + if (updateRegion) + flags |= DCX_INTERSECTRGN | 0x40000; + + if (hdc = GetDCEx(hwnd, updateRegion, flags)) + { + GetClientRect(hwnd, &rect); + rect.right += 2; + rect.bottom += 2; + SetDCBrushColor(hdc, RGB(0x8f, 0x8f, 0x8f)); + FrameRect(hdc, &rect, GetStockObject(DC_BRUSH)); + + ReleaseDC(hwnd, hdc); + return 0; + } + } + } + break; + case WM_NOTIFY: + { + LPNMHDR header = (LPNMHDR)lParam; + + if (header->hwndFrom == context->TooltipHandle) + { + switch (header->code) + { + case TTN_GETDISPINFO: + { + LPNMTTDISPINFO dispInfo = (LPNMTTDISPINFO)header; + POINT point; + RECT clientRect; + PH_GRAPH_GETTOOLTIPTEXT getTooltipText; + + GetCursorPos(&point); + ScreenToClient(hwnd, &point); + GetClientRect(hwnd, &clientRect); + + getTooltipText.Header.hwndFrom = hwnd; + getTooltipText.Header.idFrom = context->Id; + getTooltipText.Header.code = GCN_GETTOOLTIPTEXT; + getTooltipText.Index = (clientRect.right - point.x - 1) / context->DrawInfo.Step; + getTooltipText.TotalCount = context->DrawInfo.LineDataCount; + getTooltipText.Text.Buffer = NULL; + getTooltipText.Text.Length = 0; + + SendMessage(GetParent(hwnd), WM_NOTIFY, 0, (LPARAM)&getTooltipText); + + if (getTooltipText.Text.Buffer) + { + dispInfo->lpszText = getTooltipText.Text.Buffer; + } + } + break; + } + } + } + break; + case WM_SETCURSOR: + { + if (context->Options.DefaultCursor) + { + SetCursor(context->Options.DefaultCursor); + return TRUE; + } + } + break; + case WM_MOUSEMOVE: + { + if (context->TooltipHandle) + { + POINT point; + + GetCursorPos(&point); + ScreenToClient(hwnd, &point); + + if (context->LastCursorLocation.x != point.x || context->LastCursorLocation.y != point.y) + { + SendMessage(context->TooltipHandle, TTM_UPDATE, 0, 0); + context->LastCursorLocation = point; + } + } + } + break; + case WM_LBUTTONDOWN: + case WM_LBUTTONUP: + case WM_LBUTTONDBLCLK: + case WM_RBUTTONDOWN: + case WM_RBUTTONUP: + case WM_RBUTTONDBLCLK: + { + PH_GRAPH_MOUSEEVENT mouseEvent; + RECT clientRect; + + GetClientRect(hwnd, &clientRect); + + mouseEvent.Header.hwndFrom = hwnd; + mouseEvent.Header.idFrom = context->Id; + mouseEvent.Header.code = GCN_MOUSEEVENT; + mouseEvent.Message = uMsg; + mouseEvent.Keys = (ULONG)wParam; + mouseEvent.Point.x = LOWORD(lParam); + mouseEvent.Point.y = HIWORD(lParam); + + mouseEvent.Index = (clientRect.right - mouseEvent.Point.x - 1) / context->DrawInfo.Step; + mouseEvent.TotalCount = context->DrawInfo.LineDataCount; + + SendMessage(GetParent(hwnd), WM_NOTIFY, 0, (LPARAM)&mouseEvent); + } + break; + case GCM_GETDRAWINFO: + { + PPH_GRAPH_DRAW_INFO drawInfo = (PPH_GRAPH_DRAW_INFO)lParam; + + memcpy(drawInfo, &context->DrawInfo, sizeof(PH_GRAPH_DRAW_INFO)); + } + return TRUE; + case GCM_SETDRAWINFO: + { + PPH_GRAPH_DRAW_INFO drawInfo = (PPH_GRAPH_DRAW_INFO)lParam; + ULONG width; + ULONG height; + + width = context->DrawInfo.Width; + height = context->DrawInfo.Height; + memcpy(&context->DrawInfo, drawInfo, sizeof(PH_GRAPH_DRAW_INFO)); + context->DrawInfo.Width = width; + context->DrawInfo.Height = height; + } + return TRUE; + case GCM_DRAW: + { + PhpUpdateDrawInfo(hwnd, context); + context->NeedsDraw = TRUE; + } + return TRUE; + case GCM_MOVEGRID: + { + LONG increment = (LONG)wParam; + + context->DrawInfo.GridXOffset += increment; + } + return TRUE; + case GCM_GETBUFFEREDCONTEXT: + return (LRESULT)context->BufferedContext; + case GCM_SETTOOLTIP: + { + if (wParam) + { + TOOLINFO toolInfo = { sizeof(toolInfo) }; + + context->TooltipHandle = CreateWindow( + TOOLTIPS_CLASS, + NULL, + WS_POPUP | WS_EX_TRANSPARENT | TTS_NOPREFIX, + CW_USEDEFAULT, + CW_USEDEFAULT, + CW_USEDEFAULT, + CW_USEDEFAULT, + NULL, + NULL, + PhLibImageBase, + NULL + ); + + SetWindowPos(context->TooltipHandle, HWND_TOPMOST, 0, 0, 0, 0, + SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); + + toolInfo.uFlags = 0; + toolInfo.hwnd = hwnd; + toolInfo.uId = 1; + toolInfo.lpszText = LPSTR_TEXTCALLBACK; + GetClientRect(hwnd, &toolInfo.rect); + SendMessage(context->TooltipHandle, TTM_ADDTOOL, 0, (LPARAM)&toolInfo); + + SendMessage(context->TooltipHandle, TTM_SETDELAYTIME, TTDT_INITIAL, 0); + SendMessage(context->TooltipHandle, TTM_SETDELAYTIME, TTDT_AUTOPOP, MAXSHORT); + // Allow newlines (-1 doesn't work) + SendMessage(context->TooltipHandle, TTM_SETMAXTIPWIDTH, 0, MAXSHORT); + } + else + { + DestroyWindow(context->TooltipHandle); + context->TooltipHandle = NULL; + } + } + return TRUE; + case GCM_UPDATETOOLTIP: + { + if (!context->TooltipHandle) + return FALSE; + + SendMessage(context->TooltipHandle, TTM_UPDATE, 0, 0); + } + return TRUE; + case GCM_GETOPTIONS: + memcpy((PPH_GRAPH_OPTIONS)lParam, &context->Options, sizeof(PH_GRAPH_OPTIONS)); + return TRUE; + case GCM_SETOPTIONS: + memcpy(&context->Options, (PPH_GRAPH_OPTIONS)lParam, sizeof(PH_GRAPH_OPTIONS)); + PhpDeleteFadeOutContext(context); + return TRUE; + } + + return DefWindowProc(hwnd, uMsg, wParam, lParam); +} + +/** + * Initializes a graph buffer management structure. + * + * \param Buffers The buffer management structure. + */ +VOID PhInitializeGraphBuffers( + _Out_ PPH_GRAPH_BUFFERS Buffers + ) +{ + Buffers->AllocatedCount = 0; + Buffers->Data1 = NULL; + Buffers->Data2 = NULL; + Buffers->Valid = FALSE; +} + +/** + * Frees resources used by a graph buffer management structure. + * + * \param Buffers The buffer management structure. + */ +VOID PhDeleteGraphBuffers( + _Inout_ PPH_GRAPH_BUFFERS Buffers + ) +{ + if (Buffers->Data1) PhFree(Buffers->Data1); + if (Buffers->Data2) PhFree(Buffers->Data2); +} + +/** + * Sets up a graphing information structure with information from a graph buffer management + * structure. + * + * \param Buffers The buffer management structure. + * \param DrawInfo The graphing information structure. + * \param DataCount The number of data points currently required. The buffers are resized if needed. + */ +VOID PhGetDrawInfoGraphBuffers( + _Inout_ PPH_GRAPH_BUFFERS Buffers, + _Inout_ PPH_GRAPH_DRAW_INFO DrawInfo, + _In_ ULONG DataCount + ) +{ + DrawInfo->LineDataCount = min(DataCount, PH_GRAPH_DATA_COUNT(DrawInfo->Width, DrawInfo->Step)); + + // Do we need to allocate or re-allocate the data buffers? + if (Buffers->AllocatedCount < DrawInfo->LineDataCount) + { + if (Buffers->Data1) + PhFree(Buffers->Data1); + if ((DrawInfo->Flags & PH_GRAPH_USE_LINE_2) && Buffers->Data2) + PhFree(Buffers->Data2); + + Buffers->AllocatedCount *= 2; + + if (Buffers->AllocatedCount < DrawInfo->LineDataCount) + Buffers->AllocatedCount = DrawInfo->LineDataCount; + + Buffers->Data1 = PhAllocate(Buffers->AllocatedCount * sizeof(FLOAT)); + + if (DrawInfo->Flags & PH_GRAPH_USE_LINE_2) + { + Buffers->Data2 = PhAllocate(Buffers->AllocatedCount * sizeof(FLOAT)); + } + + Buffers->Valid = FALSE; + } + + DrawInfo->LineData1 = Buffers->Data1; + DrawInfo->LineData2 = Buffers->Data2; +} + +VOID PhInitializeGraphState( + _Out_ PPH_GRAPH_STATE State + ) +{ + PhInitializeGraphBuffers(&State->Buffers); + State->Text = NULL; + State->TooltipText = NULL; + State->TooltipIndex = -1; +} + +VOID PhDeleteGraphState( + _Inout_ PPH_GRAPH_STATE State + ) +{ + PhDeleteGraphBuffers(&State->Buffers); + if (State->Text) PhDereferenceObject(State->Text); + if (State->TooltipText) PhDereferenceObject(State->TooltipText); +} + +VOID PhGraphStateGetDrawInfo( + _Inout_ PPH_GRAPH_STATE State, + _In_ PPH_GRAPH_GETDRAWINFO GetDrawInfo, + _In_ ULONG DataCount + ) +{ + PhGetDrawInfoGraphBuffers(&State->Buffers, GetDrawInfo->DrawInfo, DataCount); +} diff --git a/phlib/guisup.c b/phlib/guisup.c index 60c354eec614..a9e1436ab891 100644 --- a/phlib/guisup.c +++ b/phlib/guisup.c @@ -1,1374 +1,1374 @@ -/* - * Process Hacker - - * GUI support functions - * - * Copyright (C) 2009-2016 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include -#include - -#include -#include -#include - -#include - -#define SCALE_DPI(Value) PhMultiplyDivide(Value, PhGlobalDpi, 96) - -_ChangeWindowMessageFilter ChangeWindowMessageFilter_I; -_IsImmersiveProcess IsImmersiveProcess_I; -_RunFileDlg RunFileDlg; -_SHAutoComplete SHAutoComplete_I; - -static PH_INITONCE SharedIconCacheInitOnce = PH_INITONCE_INIT; -static PPH_HASHTABLE SharedIconCacheHashtable; -static PH_QUEUED_LOCK SharedIconCacheLock = PH_QUEUED_LOCK_INIT; - -VOID PhGuiSupportInitialization( - VOID - ) -{ - HMODULE shell32Handle; - HMODULE shlwapiHandle; - - shell32Handle = LoadLibrary(L"shell32.dll"); - shlwapiHandle = LoadLibrary(L"shlwapi.dll"); - - if (WINDOWS_HAS_UAC) - ChangeWindowMessageFilter_I = PhGetModuleProcAddress(L"user32.dll", "ChangeWindowMessageFilter"); - if (WINDOWS_HAS_IMMERSIVE) - IsImmersiveProcess_I = PhGetModuleProcAddress(L"user32.dll", "IsImmersiveProcess"); - RunFileDlg = PhGetProcedureAddress(shell32Handle, NULL, 61); - SHAutoComplete_I = PhGetProcedureAddress(shlwapiHandle, "SHAutoComplete", 0); -} - -VOID PhSetControlTheme( - _In_ HWND Handle, - _In_ PWSTR Theme - ) -{ - if (WindowsVersion >= WINDOWS_VISTA) - { - SetWindowTheme(Handle, Theme, NULL); - } -} - -INT PhAddListViewColumn( - _In_ HWND ListViewHandle, - _In_ INT Index, - _In_ INT DisplayIndex, - _In_ INT SubItemIndex, - _In_ INT Format, - _In_ INT Width, - _In_ PWSTR Text - ) -{ - LVCOLUMN column; - - column.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM | LVCF_ORDER; - column.fmt = Format; - column.cx = Width < 0 ? -Width : SCALE_DPI(Width); - column.pszText = Text; - column.iSubItem = SubItemIndex; - column.iOrder = DisplayIndex; - - return ListView_InsertColumn(ListViewHandle, Index, &column); -} - -INT PhAddListViewItem( - _In_ HWND ListViewHandle, - _In_ INT Index, - _In_ PWSTR Text, - _In_opt_ PVOID Param - ) -{ - LVITEM item; - - item.mask = LVIF_TEXT | LVIF_PARAM; - item.iItem = Index; - item.iSubItem = 0; - item.pszText = Text; - item.lParam = (LPARAM)Param; - - return ListView_InsertItem(ListViewHandle, &item); -} - -INT PhFindListViewItemByFlags( - _In_ HWND ListViewHandle, - _In_ INT StartIndex, - _In_ ULONG Flags - ) -{ - return ListView_GetNextItem(ListViewHandle, StartIndex, Flags); -} - -INT PhFindListViewItemByParam( - _In_ HWND ListViewHandle, - _In_ INT StartIndex, - _In_opt_ PVOID Param - ) -{ - LVFINDINFO findInfo; - - findInfo.flags = LVFI_PARAM; - findInfo.lParam = (LPARAM)Param; - - return ListView_FindItem(ListViewHandle, StartIndex, &findInfo); -} - -LOGICAL PhGetListViewItemImageIndex( - _In_ HWND ListViewHandle, - _In_ INT Index, - _Out_ PINT ImageIndex - ) -{ - LOGICAL result; - LVITEM item; - - item.mask = LVIF_IMAGE; - item.iItem = Index; - item.iSubItem = 0; - - result = ListView_GetItem(ListViewHandle, &item); - - if (!result) - return result; - - *ImageIndex = item.iImage; - - return result; -} - -LOGICAL PhGetListViewItemParam( - _In_ HWND ListViewHandle, - _In_ INT Index, - _Out_ PVOID *Param - ) -{ - LOGICAL result; - LVITEM item; - - item.mask = LVIF_PARAM; - item.iItem = Index; - item.iSubItem = 0; - - result = ListView_GetItem(ListViewHandle, &item); - - if (!result) - return result; - - *Param = (PVOID)item.lParam; - - return result; -} - -VOID PhRemoveListViewItem( - _In_ HWND ListViewHandle, - _In_ INT Index - ) -{ - ListView_DeleteItem(ListViewHandle, Index); -} - -VOID PhSetListViewItemImageIndex( - _In_ HWND ListViewHandle, - _In_ INT Index, - _In_ INT ImageIndex - ) -{ - LVITEM item; - - item.mask = LVIF_IMAGE; - item.iItem = Index; - item.iSubItem = 0; - item.iImage = ImageIndex; - - ListView_SetItem(ListViewHandle, &item); -} - -VOID PhSetListViewSubItem( - _In_ HWND ListViewHandle, - _In_ INT Index, - _In_ INT SubItemIndex, - _In_ PWSTR Text - ) -{ - LVITEM item; - - item.mask = LVIF_TEXT; - item.iItem = Index; - item.iSubItem = SubItemIndex; - item.pszText = Text; - - ListView_SetItem(ListViewHandle, &item); -} - -BOOLEAN PhLoadListViewColumnSettings( - _In_ HWND ListViewHandle, - _In_ PPH_STRING Settings - ) -{ -#define ORDER_LIMIT 50 - PH_STRINGREF remainingPart; - ULONG columnIndex; - ULONG orderArray[ORDER_LIMIT]; // HACK, but reasonable limit - ULONG maxOrder; - ULONG scale; - - if (Settings->Length == 0) - return FALSE; - - remainingPart = Settings->sr; - columnIndex = 0; - memset(orderArray, 0, sizeof(orderArray)); - maxOrder = 0; - - if (remainingPart.Length != 0 && remainingPart.Buffer[0] == '@') - { - PH_STRINGREF scalePart; - ULONG64 integer; - - PhSkipStringRef(&remainingPart, sizeof(WCHAR)); - PhSplitStringRefAtChar(&remainingPart, '|', &scalePart, &remainingPart); - - if (scalePart.Length == 0 || !PhStringToInteger64(&scalePart, 10, &integer)) - return FALSE; - - scale = (ULONG)integer; - } - else - { - scale = PhGlobalDpi; - } - - while (remainingPart.Length != 0) - { - PH_STRINGREF columnPart; - PH_STRINGREF orderPart; - PH_STRINGREF widthPart; - ULONG64 integer; - ULONG order; - ULONG width; - LVCOLUMN lvColumn; - - PhSplitStringRefAtChar(&remainingPart, '|', &columnPart, &remainingPart); - - if (columnPart.Length == 0) - return FALSE; - - PhSplitStringRefAtChar(&columnPart, ',', &orderPart, &widthPart); - - if (orderPart.Length == 0 || widthPart.Length == 0) - return FALSE; - - // Order - - if (!PhStringToInteger64(&orderPart, 10, &integer)) - return FALSE; - - order = (ULONG)integer; - - if (order < ORDER_LIMIT) - { - orderArray[order] = columnIndex; - - if (maxOrder < order + 1) - maxOrder = order + 1; - } - - // Width - - if (!PhStringToInteger64(&widthPart, 10, &integer)) - return FALSE; - - width = (ULONG)integer; - - if (scale != PhGlobalDpi && scale != 0) - width = PhMultiplyDivide(width, PhGlobalDpi, scale); - - lvColumn.mask = LVCF_WIDTH; - lvColumn.cx = width; - ListView_SetColumn(ListViewHandle, columnIndex, &lvColumn); - - columnIndex++; - } - - ListView_SetColumnOrderArray(ListViewHandle, maxOrder, orderArray); - - return TRUE; -} - -PPH_STRING PhSaveListViewColumnSettings( - _In_ HWND ListViewHandle - ) -{ - PH_STRING_BUILDER stringBuilder; - ULONG i = 0; - LVCOLUMN lvColumn; - - PhInitializeStringBuilder(&stringBuilder, 20); - - PhAppendFormatStringBuilder(&stringBuilder, L"@%u|", PhGlobalDpi); - - lvColumn.mask = LVCF_WIDTH | LVCF_ORDER; - - while (ListView_GetColumn(ListViewHandle, i, &lvColumn)) - { - PhAppendFormatStringBuilder( - &stringBuilder, - L"%u,%u|", - lvColumn.iOrder, - lvColumn.cx - ); - i++; - } - - if (stringBuilder.String->Length != 0) - PhRemoveEndStringBuilder(&stringBuilder, 1); - - return PhFinalStringBuilderString(&stringBuilder); -} - -INT PhAddTabControlTab( - _In_ HWND TabControlHandle, - _In_ INT Index, - _In_ PWSTR Text - ) -{ - TCITEM item; - - item.mask = TCIF_TEXT; - item.pszText = Text; - - return TabCtrl_InsertItem(TabControlHandle, Index, &item); -} - -PPH_STRING PhGetWindowText( - _In_ HWND hwnd - ) -{ - PPH_STRING text; - - PhGetWindowTextEx(hwnd, 0, &text); - return text; -} - -ULONG PhGetWindowTextEx( - _In_ HWND hwnd, - _In_ ULONG Flags, - _Out_opt_ PPH_STRING *Text - ) -{ - PPH_STRING string; - ULONG length; - - if (Flags & PH_GET_WINDOW_TEXT_INTERNAL) - { - if (Flags & PH_GET_WINDOW_TEXT_LENGTH_ONLY) - { - WCHAR buffer[32]; - length = InternalGetWindowText(hwnd, buffer, sizeof(buffer) / sizeof(WCHAR)); - } - else - { - // TODO: Resize the buffer until we get the entire thing. - string = PhCreateStringEx(NULL, 256 * sizeof(WCHAR)); - length = InternalGetWindowText(hwnd, string->Buffer, (ULONG)string->Length / sizeof(WCHAR) + 1); - string->Length = length * sizeof(WCHAR); - - if (Text) - *Text = string; - else - PhDereferenceObject(string); - } - - return length; - } - else - { - length = GetWindowTextLength(hwnd); - - if (length == 0 || (Flags & PH_GET_WINDOW_TEXT_LENGTH_ONLY)) - { - if (Text) - *Text = PhReferenceEmptyString(); - - return length; - } - - string = PhCreateStringEx(NULL, length * sizeof(WCHAR)); - - if (GetWindowText(hwnd, string->Buffer, (ULONG)string->Length / sizeof(WCHAR) + 1)) - { - if (Text) - *Text = string; - else - PhDereferenceObject(string); - - return length; - } - else - { - if (Text) - *Text = PhReferenceEmptyString(); - - PhDereferenceObject(string); - - return 0; - } - } -} - -VOID PhAddComboBoxStrings( - _In_ HWND hWnd, - _In_ PWSTR *Strings, - _In_ ULONG NumberOfStrings - ) -{ - ULONG i; - - for (i = 0; i < NumberOfStrings; i++) - ComboBox_AddString(hWnd, Strings[i]); -} - -PPH_STRING PhGetComboBoxString( - _In_ HWND hwnd, - _In_ INT Index - ) -{ - PPH_STRING string; - ULONG length; - - if (Index == -1) - { - Index = ComboBox_GetCurSel(hwnd); - - if (Index == -1) - return NULL; - } - - length = ComboBox_GetLBTextLen(hwnd, Index); - - if (length == CB_ERR) - return NULL; - if (length == 0) - return PhReferenceEmptyString(); - - string = PhCreateStringEx(NULL, length * 2); - - if (ComboBox_GetLBText(hwnd, Index, string->Buffer) != CB_ERR) - { - return string; - } - else - { - PhDereferenceObject(string); - return NULL; - } -} - -INT PhSelectComboBoxString( - _In_ HWND hwnd, - _In_ PWSTR String, - _In_ BOOLEAN Partial - ) -{ - if (Partial) - { - return ComboBox_SelectString(hwnd, -1, String); - } - else - { - INT index; - - index = ComboBox_FindStringExact(hwnd, -1, String); - - if (index == CB_ERR) - return CB_ERR; - - ComboBox_SetCurSel(hwnd, index); - - return index; - } -} - -PPH_STRING PhGetListBoxString( - _In_ HWND hwnd, - _In_ INT Index - ) -{ - PPH_STRING string; - ULONG length; - - if (Index == -1) - { - Index = ListBox_GetCurSel(hwnd); - - if (Index == -1) - return NULL; - } - - length = ListBox_GetTextLen(hwnd, Index); - - if (length == LB_ERR) - return NULL; - if (length == 0) - return PhReferenceEmptyString(); - - string = PhCreateStringEx(NULL, length * 2); - - if (ListBox_GetText(hwnd, Index, string->Buffer) != LB_ERR) - { - return string; - } - else - { - PhDereferenceObject(string); - return NULL; - } -} - -VOID PhSetStateAllListViewItems( - _In_ HWND hWnd, - _In_ ULONG State, - _In_ ULONG Mask - ) -{ - ULONG i; - ULONG count; - - count = ListView_GetItemCount(hWnd); - - if (count == -1) - return; - - for (i = 0; i < count; i++) - { - ListView_SetItemState(hWnd, i, State, Mask); - } -} - -PVOID PhGetSelectedListViewItemParam( - _In_ HWND hWnd - ) -{ - INT index; - PVOID param; - - index = PhFindListViewItemByFlags( - hWnd, - -1, - LVNI_SELECTED - ); - - if (index != -1) - { - if (PhGetListViewItemParam( - hWnd, - index, - ¶m - )) - { - return param; - } - } - - return NULL; -} - -VOID PhGetSelectedListViewItemParams( - _In_ HWND hWnd, - _Out_ PVOID **Items, - _Out_ PULONG NumberOfItems - ) -{ - PH_ARRAY array; - ULONG index; - PVOID param; - - PhInitializeArray(&array, sizeof(PVOID), 2); - index = -1; - - while ((index = PhFindListViewItemByFlags( - hWnd, - index, - LVNI_SELECTED - )) != -1) - { - if (PhGetListViewItemParam(hWnd, index, ¶m)) - PhAddItemArray(&array, ¶m); - } - - *NumberOfItems = (ULONG)array.Count; - *Items = PhFinalArrayItems(&array); -} - -VOID PhSetImageListBitmap( - _In_ HIMAGELIST ImageList, - _In_ INT Index, - _In_ HINSTANCE InstanceHandle, - _In_ LPCWSTR BitmapName - ) -{ - HBITMAP bitmap; - - bitmap = LoadImage(InstanceHandle, BitmapName, IMAGE_BITMAP, 0, 0, 0); - - if (bitmap) - { - ImageList_Replace(ImageList, Index, bitmap, NULL); - DeleteObject(bitmap); - } -} - -static BOOLEAN SharedIconCacheHashtableEqualFunction( - _In_ PVOID Entry1, - _In_ PVOID Entry2 - ) -{ - PPHP_ICON_ENTRY entry1 = Entry1; - PPHP_ICON_ENTRY entry2 = Entry2; - - if (entry1->InstanceHandle != entry2->InstanceHandle || - entry1->Width != entry2->Width || - entry1->Height != entry2->Height) - { - return FALSE; - } - - if (IS_INTRESOURCE(entry1->Name)) - { - if (IS_INTRESOURCE(entry2->Name)) - return entry1->Name == entry2->Name; - else - return FALSE; - } - else - { - if (!IS_INTRESOURCE(entry2->Name)) - return PhEqualStringZ(entry1->Name, entry2->Name, FALSE); - else - return FALSE; - } -} - -static ULONG SharedIconCacheHashtableHashFunction( - _In_ PVOID Entry - ) -{ - PPHP_ICON_ENTRY entry = Entry; - ULONG nameHash; - - if (IS_INTRESOURCE(entry->Name)) - nameHash = PtrToUlong(entry->Name); - else - nameHash = PhHashBytes((PUCHAR)entry->Name, PhCountStringZ(entry->Name)); - - return nameHash ^ (PtrToUlong(entry->InstanceHandle) >> 5) ^ (entry->Width << 3) ^ entry->Height; -} - -HICON PhLoadIcon( - _In_opt_ HINSTANCE InstanceHandle, - _In_ PWSTR Name, - _In_ ULONG Flags, - _In_opt_ ULONG Width, - _In_opt_ ULONG Height - ) -{ - static _LoadIconMetric loadIconMetric; - static _LoadIconWithScaleDown loadIconWithScaleDown; - - PHP_ICON_ENTRY entry; - PPHP_ICON_ENTRY actualEntry; - HICON icon = NULL; - - if (PhBeginInitOnce(&SharedIconCacheInitOnce)) - { - loadIconMetric = (_LoadIconMetric)PhGetModuleProcAddress(L"comctl32.dll", "LoadIconMetric"); - loadIconWithScaleDown = (_LoadIconWithScaleDown)PhGetModuleProcAddress(L"comctl32.dll", "LoadIconWithScaleDown"); - SharedIconCacheHashtable = PhCreateHashtable(sizeof(PHP_ICON_ENTRY), - SharedIconCacheHashtableEqualFunction, SharedIconCacheHashtableHashFunction, 10); - PhEndInitOnce(&SharedIconCacheInitOnce); - } - - if (Flags & PH_LOAD_ICON_SHARED) - { - PhAcquireQueuedLockExclusive(&SharedIconCacheLock); - - entry.InstanceHandle = InstanceHandle; - entry.Name = Name; - entry.Width = PhpGetIconEntrySize(Width, Flags); - entry.Height = PhpGetIconEntrySize(Height, Flags); - actualEntry = PhFindEntryHashtable(SharedIconCacheHashtable, &entry); - - if (actualEntry) - { - icon = actualEntry->Icon; - PhReleaseQueuedLockExclusive(&SharedIconCacheLock); - return icon; - } - } - - if (Flags & (PH_LOAD_ICON_SIZE_SMALL | PH_LOAD_ICON_SIZE_LARGE)) - { - if (loadIconMetric) - loadIconMetric(InstanceHandle, Name, (Flags & PH_LOAD_ICON_SIZE_SMALL) ? LIM_SMALL : LIM_LARGE, &icon); - } - else - { - if (loadIconWithScaleDown) - loadIconWithScaleDown(InstanceHandle, Name, Width, Height, &icon); - } - - if (!icon && !(Flags & PH_LOAD_ICON_STRICT)) - { - if (Flags & PH_LOAD_ICON_SIZE_SMALL) - { - static ULONG smallWidth = 0; - static ULONG smallHeight = 0; - - if (!smallWidth) - smallWidth = GetSystemMetrics(SM_CXSMICON); - if (!smallHeight) - smallHeight = GetSystemMetrics(SM_CYSMICON); - - Width = smallWidth; - Height = smallHeight; - } - else if (Flags & PH_LOAD_ICON_SIZE_LARGE) - { - static ULONG largeWidth = 0; - static ULONG largeHeight = 0; - - if (!largeWidth) - largeWidth = GetSystemMetrics(SM_CXICON); - if (!largeHeight) - largeHeight = GetSystemMetrics(SM_CYICON); - - Width = largeWidth; - Height = largeHeight; - } - - icon = LoadImage(InstanceHandle, Name, IMAGE_ICON, Width, Height, 0); - } - - if (Flags & PH_LOAD_ICON_SHARED) - { - if (icon) - { - if (!IS_INTRESOURCE(Name)) - entry.Name = PhDuplicateStringZ(Name); - entry.Icon = icon; - PhAddEntryHashtable(SharedIconCacheHashtable, &entry); - } - - PhReleaseQueuedLockExclusive(&SharedIconCacheLock); - } - - return icon; -} - -/** - * Gets the default icon used for executable files. - * - * \param SmallIcon A variable which receives the small default executable icon. Do not destroy the - * icon using DestroyIcon(); it is shared between callers. - * \param LargeIcon A variable which receives the large default executable icon. Do not destroy the - * icon using DestroyIcon(); it is shared between callers. - */ -VOID PhGetStockApplicationIcon( - _Out_opt_ HICON *SmallIcon, - _Out_opt_ HICON *LargeIcon - ) -{ - static PH_INITONCE initOnce = PH_INITONCE_INIT; - static HICON smallIcon = NULL; - static HICON largeIcon = NULL; - - // This no longer uses SHGetFileInfo because it is *very* slow and causes many other DLLs to be - // loaded, increasing memory usage. The worst thing about it, however, is that it is horribly - // incompatible with multi-threading. The first time it is called, it tries to perform some - // one-time initialization. It guards this with a lock, but when multiple threads try to call - // the function at the same time, instead of waiting for initialization to finish it simply - // fails the other threads. - - if (PhBeginInitOnce(&initOnce)) - { - PPH_STRING systemDirectory; - PPH_STRING dllFileName; - - // imageres,11 (Windows 10 and above), user32,0 (Vista and above) or shell32,2 (XP) contains - // the default application icon. - - if (systemDirectory = PhGetSystemDirectory()) - { - PH_STRINGREF dllBaseName; - ULONG index; - - // TODO: Find a better solution. - if (WindowsVersion >= WINDOWS_10) - { - PhInitializeStringRef(&dllBaseName, L"\\imageres.dll"); - index = 11; - } - else if (WindowsVersion >= WINDOWS_VISTA) - { - PhInitializeStringRef(&dllBaseName, L"\\user32.dll"); - index = 0; - } - else - { - PhInitializeStringRef(&dllBaseName, L"\\shell32.dll"); - index = 2; - } - - dllFileName = PhConcatStringRef2(&systemDirectory->sr, &dllBaseName); - PhDereferenceObject(systemDirectory); - - ExtractIconEx(dllFileName->Buffer, index, &largeIcon, &smallIcon, 1); - PhDereferenceObject(dllFileName); - } - - // Fallback icons - if (!smallIcon) - smallIcon = PhLoadIcon(NULL, MAKEINTRESOURCE(IDI_APPLICATION), PH_LOAD_ICON_SIZE_SMALL, 0, 0); - if (!largeIcon) - largeIcon = PhLoadIcon(NULL, MAKEINTRESOURCE(IDI_APPLICATION), PH_LOAD_ICON_SIZE_LARGE, 0, 0); - - PhEndInitOnce(&initOnce); - } - - if (SmallIcon) - *SmallIcon = smallIcon; - if (LargeIcon) - *LargeIcon = largeIcon; -} - -HICON PhGetFileShellIcon( - _In_opt_ PWSTR FileName, - _In_opt_ PWSTR DefaultExtension, - _In_ BOOLEAN LargeIcon - ) -{ - SHFILEINFO fileInfo; - ULONG iconFlag; - HICON icon; - - if (DefaultExtension && PhEqualStringZ(DefaultExtension, L".exe", TRUE)) - { - // Special case for executable files (see above for reasoning). - - icon = NULL; - - if (FileName) - { - ExtractIconEx( - FileName, - 0, - LargeIcon ? &icon : NULL, - !LargeIcon ? &icon : NULL, - 1 - ); - } - - if (!icon) - { - PhGetStockApplicationIcon( - !LargeIcon ? &icon : NULL, - LargeIcon ? &icon : NULL - ); - - if (icon) - icon = DuplicateIcon(NULL, icon); - } - - return icon; - } - - iconFlag = LargeIcon ? SHGFI_LARGEICON : SHGFI_SMALLICON; - icon = NULL; - - if (FileName && SHGetFileInfo( - FileName, - 0, - &fileInfo, - sizeof(SHFILEINFO), - SHGFI_ICON | iconFlag - )) - { - icon = fileInfo.hIcon; - } - - if (!icon && DefaultExtension) - { - if (SHGetFileInfo( - DefaultExtension, - FILE_ATTRIBUTE_NORMAL, - &fileInfo, - sizeof(SHFILEINFO), - SHGFI_ICON | iconFlag | SHGFI_USEFILEATTRIBUTES - )) - icon = fileInfo.hIcon; - } - - return icon; -} - -VOID PhpSetClipboardData( - _In_ HWND hWnd, - _In_ ULONG Format, - _In_ HANDLE Data - ) -{ - if (OpenClipboard(hWnd)) - { - if (!EmptyClipboard()) - goto Fail; - - if (!SetClipboardData(Format, Data)) - goto Fail; - - CloseClipboard(); - - return; - } - -Fail: - GlobalFree(Data); -} - -VOID PhSetClipboardString( - _In_ HWND hWnd, - _In_ PPH_STRINGREF String - ) -{ - HANDLE data; - PVOID memory; - - data = GlobalAlloc(GMEM_MOVEABLE, String->Length + sizeof(WCHAR)); - memory = GlobalLock(data); - - memcpy(memory, String->Buffer, String->Length); - *(PWCHAR)((PCHAR)memory + String->Length) = 0; - - GlobalUnlock(memory); - - PhpSetClipboardData(hWnd, CF_UNICODETEXT, data); -} - -HWND PhCreateDialogFromTemplate( - _In_ HWND Parent, - _In_ ULONG Style, - _In_ PVOID Instance, - _In_ PWSTR Template, - _In_ DLGPROC DialogProc, - _In_ PVOID Parameter - ) -{ - HRSRC resourceInfo; - ULONG resourceSize; - HGLOBAL resourceHandle; - PDLGTEMPLATEEX dialog; - PDLGTEMPLATEEX dialogCopy; - HWND dialogHandle; - - resourceInfo = FindResource(Instance, Template, MAKEINTRESOURCE(RT_DIALOG)); - - if (!resourceInfo) - return NULL; - - resourceSize = SizeofResource(Instance, resourceInfo); - - if (resourceSize == 0) - return NULL; - - resourceHandle = LoadResource(Instance, resourceInfo); - - if (!resourceHandle) - return NULL; - - dialog = LockResource(resourceHandle); - - if (!dialog) - return NULL; - - dialogCopy = PhAllocateCopy(dialog, resourceSize); - - if (dialogCopy->signature == 0xffff) - { - dialogCopy->style = Style; - } - else - { - ((DLGTEMPLATE *)dialogCopy)->style = Style; - } - - dialogHandle = CreateDialogIndirectParam(Instance, (DLGTEMPLATE *)dialogCopy, Parent, DialogProc, (LPARAM)Parameter); - - PhFree(dialogCopy); - - return dialogHandle; -} - -BOOLEAN PhModalPropertySheet( - _Inout_ PROPSHEETHEADER *Header - ) -{ - // PropertySheet incorrectly discards WM_QUIT messages in certain cases, so we will use our own - // message loop. An example of this is when GetMessage (called by PropertySheet's message loop) - // dispatches a message directly from kernel-mode that causes the property sheet to close. In - // that case PropertySheet will retrieve the WM_QUIT message but will ignore it because of its - // buggy logic. - - // This is also a good opportunity to introduce an auto-pool. - - PH_AUTO_POOL autoPool; - HWND oldFocus; - HWND topLevelOwner; - HWND hwnd; - BOOL result; - MSG message; - - PhInitializeAutoPool(&autoPool); - - oldFocus = GetFocus(); - topLevelOwner = Header->hwndParent; - - while (topLevelOwner && (GetWindowLong(topLevelOwner, GWL_STYLE) & WS_CHILD)) - topLevelOwner = GetParent(topLevelOwner); - - if (topLevelOwner && (topLevelOwner == GetDesktopWindow() || EnableWindow(topLevelOwner, FALSE))) - topLevelOwner = NULL; - - Header->dwFlags |= PSH_MODELESS; - hwnd = (HWND)PropertySheet(Header); - - if (!hwnd) - { - if (topLevelOwner) - EnableWindow(topLevelOwner, TRUE); - - return FALSE; - } - - while (result = GetMessage(&message, NULL, 0, 0)) - { - if (result == -1) - break; - - if (!PropSheet_IsDialogMessage(hwnd, &message)) - { - TranslateMessage(&message); - DispatchMessage(&message); - } - - PhDrainAutoPool(&autoPool); - - // Destroy the window when necessary. - if (!PropSheet_GetCurrentPageHwnd(hwnd)) - break; - } - - if (result == 0) - PostQuitMessage((INT)message.wParam); - if (Header->hwndParent && GetActiveWindow() == hwnd) - SetActiveWindow(Header->hwndParent); - if (topLevelOwner) - EnableWindow(topLevelOwner, TRUE); - if (oldFocus && IsWindow(oldFocus)) - SetFocus(oldFocus); - - DestroyWindow(hwnd); - PhDeleteAutoPool(&autoPool); - - return TRUE; -} - -VOID PhInitializeLayoutManager( - _Out_ PPH_LAYOUT_MANAGER Manager, - _In_ HWND RootWindowHandle - ) -{ - Manager->List = PhCreateList(4); - Manager->LayoutNumber = 0; - - Manager->RootItem.Handle = RootWindowHandle; - GetClientRect(Manager->RootItem.Handle, &Manager->RootItem.Rect); - Manager->RootItem.OrigRect = Manager->RootItem.Rect; - Manager->RootItem.ParentItem = NULL; - Manager->RootItem.LayoutParentItem = NULL; - Manager->RootItem.LayoutNumber = 0; - Manager->RootItem.NumberOfChildren = 0; - Manager->RootItem.DeferHandle = NULL; -} - -VOID PhDeleteLayoutManager( - _Inout_ PPH_LAYOUT_MANAGER Manager - ) -{ - ULONG i; - - for (i = 0; i < Manager->List->Count; i++) - PhFree(Manager->List->Items[i]); - - PhDereferenceObject(Manager->List); -} - -// HACK: The math below is all horribly broken, especially the HACK for multiline tab controls. - -PPH_LAYOUT_ITEM PhAddLayoutItem( - _Inout_ PPH_LAYOUT_MANAGER Manager, - _In_ HWND Handle, - _In_opt_ PPH_LAYOUT_ITEM ParentItem, - _In_ ULONG Anchor - ) -{ - PPH_LAYOUT_ITEM layoutItem; - RECT dummy = { 0 }; - - layoutItem = PhAddLayoutItemEx( - Manager, - Handle, - ParentItem, - Anchor, - dummy - ); - - layoutItem->Margin = layoutItem->Rect; - PhConvertRect(&layoutItem->Margin, &layoutItem->ParentItem->Rect); - - if (layoutItem->ParentItem != layoutItem->LayoutParentItem) - { - // Fix the margin because the item has a dummy parent. They share the same layout parent - // item. - layoutItem->Margin.top -= layoutItem->ParentItem->Rect.top; - layoutItem->Margin.left -= layoutItem->ParentItem->Rect.left; - layoutItem->Margin.right = layoutItem->ParentItem->Margin.right; - layoutItem->Margin.bottom = layoutItem->ParentItem->Margin.bottom; - } - - return layoutItem; -} - -PPH_LAYOUT_ITEM PhAddLayoutItemEx( - _Inout_ PPH_LAYOUT_MANAGER Manager, - _In_ HWND Handle, - _In_opt_ PPH_LAYOUT_ITEM ParentItem, - _In_ ULONG Anchor, - _In_ RECT Margin - ) -{ - PPH_LAYOUT_ITEM item; - - if (!ParentItem) - ParentItem = &Manager->RootItem; - - item = PhAllocate(sizeof(PH_LAYOUT_ITEM)); - item->Handle = Handle; - item->ParentItem = ParentItem; - item->LayoutNumber = Manager->LayoutNumber; - item->NumberOfChildren = 0; - item->DeferHandle = NULL; - item->Anchor = Anchor; - - item->LayoutParentItem = item->ParentItem; - - while ((item->LayoutParentItem->Anchor & PH_LAYOUT_DUMMY_MASK) && - item->LayoutParentItem->LayoutParentItem) - { - item->LayoutParentItem = item->LayoutParentItem->LayoutParentItem; - } - - item->LayoutParentItem->NumberOfChildren++; - - GetWindowRect(Handle, &item->Rect); - MapWindowPoints(NULL, item->LayoutParentItem->Handle, (POINT *)&item->Rect, 2); - - if (item->Anchor & PH_LAYOUT_TAB_CONTROL) - { - // We want to convert the tab control rectangle to the tab page display rectangle. - TabCtrl_AdjustRect(Handle, FALSE, &item->Rect); - } - - item->Margin = Margin; - - item->OrigRect = item->Rect; - - PhAddItemList(Manager->List, item); - - return item; -} - -VOID PhpLayoutItemLayout( - _Inout_ PPH_LAYOUT_MANAGER Manager, - _Inout_ PPH_LAYOUT_ITEM Item - ) -{ - RECT rect; - BOOLEAN hasDummyParent; - - if (Item->NumberOfChildren > 0 && !Item->DeferHandle) - Item->DeferHandle = BeginDeferWindowPos(Item->NumberOfChildren); - - if (Item->LayoutNumber == Manager->LayoutNumber) - return; - - // If this is the root item we must stop here. - if (!Item->ParentItem) - return; - - PhpLayoutItemLayout(Manager, Item->ParentItem); - - if (Item->ParentItem != Item->LayoutParentItem) - { - PhpLayoutItemLayout(Manager, Item->LayoutParentItem); - hasDummyParent = TRUE; - } - else - { - hasDummyParent = FALSE; - } - - GetWindowRect(Item->Handle, &Item->Rect); - MapWindowPoints(NULL, Item->LayoutParentItem->Handle, (POINT *)&Item->Rect, 2); - - if (Item->Anchor & PH_LAYOUT_TAB_CONTROL) - { - // We want to convert the tab control rectangle to the tab page display rectangle. - TabCtrl_AdjustRect(Item->Handle, FALSE, &Item->Rect); - } - - if (!(Item->Anchor & PH_LAYOUT_DUMMY_MASK)) - { - // Convert right/bottom into margins to make the calculations - // easier. - rect = Item->Rect; - PhConvertRect(&rect, &Item->LayoutParentItem->Rect); - - if (!(Item->Anchor & (PH_ANCHOR_LEFT | PH_ANCHOR_RIGHT))) - { - // TODO - PhRaiseStatus(STATUS_NOT_IMPLEMENTED); - } - else if (Item->Anchor & PH_ANCHOR_RIGHT) - { - if (Item->Anchor & PH_ANCHOR_LEFT) - { - rect.left = (hasDummyParent ? Item->ParentItem->Rect.left : 0) + Item->Margin.left; - rect.right = Item->Margin.right; - } - else - { - ULONG diff = Item->Margin.right - rect.right; - - rect.left -= diff; - rect.right += diff; - } - } - - if (!(Item->Anchor & (PH_ANCHOR_TOP | PH_ANCHOR_BOTTOM))) - { - // TODO - PhRaiseStatus(STATUS_NOT_IMPLEMENTED); - } - else if (Item->Anchor & PH_ANCHOR_BOTTOM) - { - if (Item->Anchor & PH_ANCHOR_TOP) - { - // tab control hack - rect.top = (hasDummyParent ? Item->ParentItem->Rect.top : 0) + Item->Margin.top; - rect.bottom = Item->Margin.bottom; - } - else - { - ULONG diff = Item->Margin.bottom - rect.bottom; - - rect.top -= diff; - rect.bottom += diff; - } - } - - // Convert the right/bottom back into co-ordinates. - PhConvertRect(&rect, &Item->LayoutParentItem->Rect); - Item->Rect = rect; - - if (!(Item->Anchor & PH_LAYOUT_IMMEDIATE_RESIZE)) - { - Item->LayoutParentItem->DeferHandle = DeferWindowPos( - Item->LayoutParentItem->DeferHandle, Item->Handle, - NULL, rect.left, rect.top, - rect.right - rect.left, rect.bottom - rect.top, - SWP_NOACTIVATE | SWP_NOZORDER - ); - } - else - { - // This is needed for tab controls, so that TabCtrl_AdjustRect will give us an - // up-to-date result. - SetWindowPos( - Item->Handle, - NULL, rect.left, rect.top, - rect.right - rect.left, rect.bottom - rect.top, - SWP_NOACTIVATE | SWP_NOZORDER - ); - } - } - - Item->LayoutNumber = Manager->LayoutNumber; -} - -VOID PhLayoutManagerLayout( - _Inout_ PPH_LAYOUT_MANAGER Manager - ) -{ - ULONG i; - - Manager->LayoutNumber++; - - GetClientRect(Manager->RootItem.Handle, &Manager->RootItem.Rect); - - for (i = 0; i < Manager->List->Count; i++) - { - PPH_LAYOUT_ITEM item = (PPH_LAYOUT_ITEM)Manager->List->Items[i]; - - PhpLayoutItemLayout(Manager, item); - } - - for (i = 0; i < Manager->List->Count; i++) - { - PPH_LAYOUT_ITEM item = (PPH_LAYOUT_ITEM)Manager->List->Items[i]; - - if (item->DeferHandle) - { - EndDeferWindowPos(item->DeferHandle); - item->DeferHandle = NULL; - } - - if (item->Anchor & PH_LAYOUT_FORCE_INVALIDATE) - { - InvalidateRect(item->Handle, NULL, FALSE); - } - } - - if (Manager->RootItem.DeferHandle) - { - EndDeferWindowPos(Manager->RootItem.DeferHandle); - Manager->RootItem.DeferHandle = NULL; - } -} +/* + * Process Hacker - + * GUI support functions + * + * Copyright (C) 2009-2016 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include +#include + +#include +#include +#include + +#include + +#define SCALE_DPI(Value) PhMultiplyDivide(Value, PhGlobalDpi, 96) + +_ChangeWindowMessageFilter ChangeWindowMessageFilter_I; +_IsImmersiveProcess IsImmersiveProcess_I; +_RunFileDlg RunFileDlg; +_SHAutoComplete SHAutoComplete_I; + +static PH_INITONCE SharedIconCacheInitOnce = PH_INITONCE_INIT; +static PPH_HASHTABLE SharedIconCacheHashtable; +static PH_QUEUED_LOCK SharedIconCacheLock = PH_QUEUED_LOCK_INIT; + +VOID PhGuiSupportInitialization( + VOID + ) +{ + HMODULE shell32Handle; + HMODULE shlwapiHandle; + + shell32Handle = LoadLibrary(L"shell32.dll"); + shlwapiHandle = LoadLibrary(L"shlwapi.dll"); + + if (WINDOWS_HAS_UAC) + ChangeWindowMessageFilter_I = PhGetModuleProcAddress(L"user32.dll", "ChangeWindowMessageFilter"); + if (WINDOWS_HAS_IMMERSIVE) + IsImmersiveProcess_I = PhGetModuleProcAddress(L"user32.dll", "IsImmersiveProcess"); + RunFileDlg = PhGetProcedureAddress(shell32Handle, NULL, 61); + SHAutoComplete_I = PhGetProcedureAddress(shlwapiHandle, "SHAutoComplete", 0); +} + +VOID PhSetControlTheme( + _In_ HWND Handle, + _In_ PWSTR Theme + ) +{ + if (WindowsVersion >= WINDOWS_VISTA) + { + SetWindowTheme(Handle, Theme, NULL); + } +} + +INT PhAddListViewColumn( + _In_ HWND ListViewHandle, + _In_ INT Index, + _In_ INT DisplayIndex, + _In_ INT SubItemIndex, + _In_ INT Format, + _In_ INT Width, + _In_ PWSTR Text + ) +{ + LVCOLUMN column; + + column.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM | LVCF_ORDER; + column.fmt = Format; + column.cx = Width < 0 ? -Width : SCALE_DPI(Width); + column.pszText = Text; + column.iSubItem = SubItemIndex; + column.iOrder = DisplayIndex; + + return ListView_InsertColumn(ListViewHandle, Index, &column); +} + +INT PhAddListViewItem( + _In_ HWND ListViewHandle, + _In_ INT Index, + _In_ PWSTR Text, + _In_opt_ PVOID Param + ) +{ + LVITEM item; + + item.mask = LVIF_TEXT | LVIF_PARAM; + item.iItem = Index; + item.iSubItem = 0; + item.pszText = Text; + item.lParam = (LPARAM)Param; + + return ListView_InsertItem(ListViewHandle, &item); +} + +INT PhFindListViewItemByFlags( + _In_ HWND ListViewHandle, + _In_ INT StartIndex, + _In_ ULONG Flags + ) +{ + return ListView_GetNextItem(ListViewHandle, StartIndex, Flags); +} + +INT PhFindListViewItemByParam( + _In_ HWND ListViewHandle, + _In_ INT StartIndex, + _In_opt_ PVOID Param + ) +{ + LVFINDINFO findInfo; + + findInfo.flags = LVFI_PARAM; + findInfo.lParam = (LPARAM)Param; + + return ListView_FindItem(ListViewHandle, StartIndex, &findInfo); +} + +LOGICAL PhGetListViewItemImageIndex( + _In_ HWND ListViewHandle, + _In_ INT Index, + _Out_ PINT ImageIndex + ) +{ + LOGICAL result; + LVITEM item; + + item.mask = LVIF_IMAGE; + item.iItem = Index; + item.iSubItem = 0; + + result = ListView_GetItem(ListViewHandle, &item); + + if (!result) + return result; + + *ImageIndex = item.iImage; + + return result; +} + +LOGICAL PhGetListViewItemParam( + _In_ HWND ListViewHandle, + _In_ INT Index, + _Out_ PVOID *Param + ) +{ + LOGICAL result; + LVITEM item; + + item.mask = LVIF_PARAM; + item.iItem = Index; + item.iSubItem = 0; + + result = ListView_GetItem(ListViewHandle, &item); + + if (!result) + return result; + + *Param = (PVOID)item.lParam; + + return result; +} + +VOID PhRemoveListViewItem( + _In_ HWND ListViewHandle, + _In_ INT Index + ) +{ + ListView_DeleteItem(ListViewHandle, Index); +} + +VOID PhSetListViewItemImageIndex( + _In_ HWND ListViewHandle, + _In_ INT Index, + _In_ INT ImageIndex + ) +{ + LVITEM item; + + item.mask = LVIF_IMAGE; + item.iItem = Index; + item.iSubItem = 0; + item.iImage = ImageIndex; + + ListView_SetItem(ListViewHandle, &item); +} + +VOID PhSetListViewSubItem( + _In_ HWND ListViewHandle, + _In_ INT Index, + _In_ INT SubItemIndex, + _In_ PWSTR Text + ) +{ + LVITEM item; + + item.mask = LVIF_TEXT; + item.iItem = Index; + item.iSubItem = SubItemIndex; + item.pszText = Text; + + ListView_SetItem(ListViewHandle, &item); +} + +BOOLEAN PhLoadListViewColumnSettings( + _In_ HWND ListViewHandle, + _In_ PPH_STRING Settings + ) +{ +#define ORDER_LIMIT 50 + PH_STRINGREF remainingPart; + ULONG columnIndex; + ULONG orderArray[ORDER_LIMIT]; // HACK, but reasonable limit + ULONG maxOrder; + ULONG scale; + + if (Settings->Length == 0) + return FALSE; + + remainingPart = Settings->sr; + columnIndex = 0; + memset(orderArray, 0, sizeof(orderArray)); + maxOrder = 0; + + if (remainingPart.Length != 0 && remainingPart.Buffer[0] == '@') + { + PH_STRINGREF scalePart; + ULONG64 integer; + + PhSkipStringRef(&remainingPart, sizeof(WCHAR)); + PhSplitStringRefAtChar(&remainingPart, '|', &scalePart, &remainingPart); + + if (scalePart.Length == 0 || !PhStringToInteger64(&scalePart, 10, &integer)) + return FALSE; + + scale = (ULONG)integer; + } + else + { + scale = PhGlobalDpi; + } + + while (remainingPart.Length != 0) + { + PH_STRINGREF columnPart; + PH_STRINGREF orderPart; + PH_STRINGREF widthPart; + ULONG64 integer; + ULONG order; + ULONG width; + LVCOLUMN lvColumn; + + PhSplitStringRefAtChar(&remainingPart, '|', &columnPart, &remainingPart); + + if (columnPart.Length == 0) + return FALSE; + + PhSplitStringRefAtChar(&columnPart, ',', &orderPart, &widthPart); + + if (orderPart.Length == 0 || widthPart.Length == 0) + return FALSE; + + // Order + + if (!PhStringToInteger64(&orderPart, 10, &integer)) + return FALSE; + + order = (ULONG)integer; + + if (order < ORDER_LIMIT) + { + orderArray[order] = columnIndex; + + if (maxOrder < order + 1) + maxOrder = order + 1; + } + + // Width + + if (!PhStringToInteger64(&widthPart, 10, &integer)) + return FALSE; + + width = (ULONG)integer; + + if (scale != PhGlobalDpi && scale != 0) + width = PhMultiplyDivide(width, PhGlobalDpi, scale); + + lvColumn.mask = LVCF_WIDTH; + lvColumn.cx = width; + ListView_SetColumn(ListViewHandle, columnIndex, &lvColumn); + + columnIndex++; + } + + ListView_SetColumnOrderArray(ListViewHandle, maxOrder, orderArray); + + return TRUE; +} + +PPH_STRING PhSaveListViewColumnSettings( + _In_ HWND ListViewHandle + ) +{ + PH_STRING_BUILDER stringBuilder; + ULONG i = 0; + LVCOLUMN lvColumn; + + PhInitializeStringBuilder(&stringBuilder, 20); + + PhAppendFormatStringBuilder(&stringBuilder, L"@%u|", PhGlobalDpi); + + lvColumn.mask = LVCF_WIDTH | LVCF_ORDER; + + while (ListView_GetColumn(ListViewHandle, i, &lvColumn)) + { + PhAppendFormatStringBuilder( + &stringBuilder, + L"%u,%u|", + lvColumn.iOrder, + lvColumn.cx + ); + i++; + } + + if (stringBuilder.String->Length != 0) + PhRemoveEndStringBuilder(&stringBuilder, 1); + + return PhFinalStringBuilderString(&stringBuilder); +} + +INT PhAddTabControlTab( + _In_ HWND TabControlHandle, + _In_ INT Index, + _In_ PWSTR Text + ) +{ + TCITEM item; + + item.mask = TCIF_TEXT; + item.pszText = Text; + + return TabCtrl_InsertItem(TabControlHandle, Index, &item); +} + +PPH_STRING PhGetWindowText( + _In_ HWND hwnd + ) +{ + PPH_STRING text; + + PhGetWindowTextEx(hwnd, 0, &text); + return text; +} + +ULONG PhGetWindowTextEx( + _In_ HWND hwnd, + _In_ ULONG Flags, + _Out_opt_ PPH_STRING *Text + ) +{ + PPH_STRING string; + ULONG length; + + if (Flags & PH_GET_WINDOW_TEXT_INTERNAL) + { + if (Flags & PH_GET_WINDOW_TEXT_LENGTH_ONLY) + { + WCHAR buffer[32]; + length = InternalGetWindowText(hwnd, buffer, sizeof(buffer) / sizeof(WCHAR)); + } + else + { + // TODO: Resize the buffer until we get the entire thing. + string = PhCreateStringEx(NULL, 256 * sizeof(WCHAR)); + length = InternalGetWindowText(hwnd, string->Buffer, (ULONG)string->Length / sizeof(WCHAR) + 1); + string->Length = length * sizeof(WCHAR); + + if (Text) + *Text = string; + else + PhDereferenceObject(string); + } + + return length; + } + else + { + length = GetWindowTextLength(hwnd); + + if (length == 0 || (Flags & PH_GET_WINDOW_TEXT_LENGTH_ONLY)) + { + if (Text) + *Text = PhReferenceEmptyString(); + + return length; + } + + string = PhCreateStringEx(NULL, length * sizeof(WCHAR)); + + if (GetWindowText(hwnd, string->Buffer, (ULONG)string->Length / sizeof(WCHAR) + 1)) + { + if (Text) + *Text = string; + else + PhDereferenceObject(string); + + return length; + } + else + { + if (Text) + *Text = PhReferenceEmptyString(); + + PhDereferenceObject(string); + + return 0; + } + } +} + +VOID PhAddComboBoxStrings( + _In_ HWND hWnd, + _In_ PWSTR *Strings, + _In_ ULONG NumberOfStrings + ) +{ + ULONG i; + + for (i = 0; i < NumberOfStrings; i++) + ComboBox_AddString(hWnd, Strings[i]); +} + +PPH_STRING PhGetComboBoxString( + _In_ HWND hwnd, + _In_ INT Index + ) +{ + PPH_STRING string; + ULONG length; + + if (Index == -1) + { + Index = ComboBox_GetCurSel(hwnd); + + if (Index == -1) + return NULL; + } + + length = ComboBox_GetLBTextLen(hwnd, Index); + + if (length == CB_ERR) + return NULL; + if (length == 0) + return PhReferenceEmptyString(); + + string = PhCreateStringEx(NULL, length * 2); + + if (ComboBox_GetLBText(hwnd, Index, string->Buffer) != CB_ERR) + { + return string; + } + else + { + PhDereferenceObject(string); + return NULL; + } +} + +INT PhSelectComboBoxString( + _In_ HWND hwnd, + _In_ PWSTR String, + _In_ BOOLEAN Partial + ) +{ + if (Partial) + { + return ComboBox_SelectString(hwnd, -1, String); + } + else + { + INT index; + + index = ComboBox_FindStringExact(hwnd, -1, String); + + if (index == CB_ERR) + return CB_ERR; + + ComboBox_SetCurSel(hwnd, index); + + return index; + } +} + +PPH_STRING PhGetListBoxString( + _In_ HWND hwnd, + _In_ INT Index + ) +{ + PPH_STRING string; + ULONG length; + + if (Index == -1) + { + Index = ListBox_GetCurSel(hwnd); + + if (Index == -1) + return NULL; + } + + length = ListBox_GetTextLen(hwnd, Index); + + if (length == LB_ERR) + return NULL; + if (length == 0) + return PhReferenceEmptyString(); + + string = PhCreateStringEx(NULL, length * 2); + + if (ListBox_GetText(hwnd, Index, string->Buffer) != LB_ERR) + { + return string; + } + else + { + PhDereferenceObject(string); + return NULL; + } +} + +VOID PhSetStateAllListViewItems( + _In_ HWND hWnd, + _In_ ULONG State, + _In_ ULONG Mask + ) +{ + ULONG i; + ULONG count; + + count = ListView_GetItemCount(hWnd); + + if (count == -1) + return; + + for (i = 0; i < count; i++) + { + ListView_SetItemState(hWnd, i, State, Mask); + } +} + +PVOID PhGetSelectedListViewItemParam( + _In_ HWND hWnd + ) +{ + INT index; + PVOID param; + + index = PhFindListViewItemByFlags( + hWnd, + -1, + LVNI_SELECTED + ); + + if (index != -1) + { + if (PhGetListViewItemParam( + hWnd, + index, + ¶m + )) + { + return param; + } + } + + return NULL; +} + +VOID PhGetSelectedListViewItemParams( + _In_ HWND hWnd, + _Out_ PVOID **Items, + _Out_ PULONG NumberOfItems + ) +{ + PH_ARRAY array; + ULONG index; + PVOID param; + + PhInitializeArray(&array, sizeof(PVOID), 2); + index = -1; + + while ((index = PhFindListViewItemByFlags( + hWnd, + index, + LVNI_SELECTED + )) != -1) + { + if (PhGetListViewItemParam(hWnd, index, ¶m)) + PhAddItemArray(&array, ¶m); + } + + *NumberOfItems = (ULONG)array.Count; + *Items = PhFinalArrayItems(&array); +} + +VOID PhSetImageListBitmap( + _In_ HIMAGELIST ImageList, + _In_ INT Index, + _In_ HINSTANCE InstanceHandle, + _In_ LPCWSTR BitmapName + ) +{ + HBITMAP bitmap; + + bitmap = LoadImage(InstanceHandle, BitmapName, IMAGE_BITMAP, 0, 0, 0); + + if (bitmap) + { + ImageList_Replace(ImageList, Index, bitmap, NULL); + DeleteObject(bitmap); + } +} + +static BOOLEAN SharedIconCacheHashtableEqualFunction( + _In_ PVOID Entry1, + _In_ PVOID Entry2 + ) +{ + PPHP_ICON_ENTRY entry1 = Entry1; + PPHP_ICON_ENTRY entry2 = Entry2; + + if (entry1->InstanceHandle != entry2->InstanceHandle || + entry1->Width != entry2->Width || + entry1->Height != entry2->Height) + { + return FALSE; + } + + if (IS_INTRESOURCE(entry1->Name)) + { + if (IS_INTRESOURCE(entry2->Name)) + return entry1->Name == entry2->Name; + else + return FALSE; + } + else + { + if (!IS_INTRESOURCE(entry2->Name)) + return PhEqualStringZ(entry1->Name, entry2->Name, FALSE); + else + return FALSE; + } +} + +static ULONG SharedIconCacheHashtableHashFunction( + _In_ PVOID Entry + ) +{ + PPHP_ICON_ENTRY entry = Entry; + ULONG nameHash; + + if (IS_INTRESOURCE(entry->Name)) + nameHash = PtrToUlong(entry->Name); + else + nameHash = PhHashBytes((PUCHAR)entry->Name, PhCountStringZ(entry->Name)); + + return nameHash ^ (PtrToUlong(entry->InstanceHandle) >> 5) ^ (entry->Width << 3) ^ entry->Height; +} + +HICON PhLoadIcon( + _In_opt_ HINSTANCE InstanceHandle, + _In_ PWSTR Name, + _In_ ULONG Flags, + _In_opt_ ULONG Width, + _In_opt_ ULONG Height + ) +{ + static _LoadIconMetric loadIconMetric; + static _LoadIconWithScaleDown loadIconWithScaleDown; + + PHP_ICON_ENTRY entry; + PPHP_ICON_ENTRY actualEntry; + HICON icon = NULL; + + if (PhBeginInitOnce(&SharedIconCacheInitOnce)) + { + loadIconMetric = (_LoadIconMetric)PhGetModuleProcAddress(L"comctl32.dll", "LoadIconMetric"); + loadIconWithScaleDown = (_LoadIconWithScaleDown)PhGetModuleProcAddress(L"comctl32.dll", "LoadIconWithScaleDown"); + SharedIconCacheHashtable = PhCreateHashtable(sizeof(PHP_ICON_ENTRY), + SharedIconCacheHashtableEqualFunction, SharedIconCacheHashtableHashFunction, 10); + PhEndInitOnce(&SharedIconCacheInitOnce); + } + + if (Flags & PH_LOAD_ICON_SHARED) + { + PhAcquireQueuedLockExclusive(&SharedIconCacheLock); + + entry.InstanceHandle = InstanceHandle; + entry.Name = Name; + entry.Width = PhpGetIconEntrySize(Width, Flags); + entry.Height = PhpGetIconEntrySize(Height, Flags); + actualEntry = PhFindEntryHashtable(SharedIconCacheHashtable, &entry); + + if (actualEntry) + { + icon = actualEntry->Icon; + PhReleaseQueuedLockExclusive(&SharedIconCacheLock); + return icon; + } + } + + if (Flags & (PH_LOAD_ICON_SIZE_SMALL | PH_LOAD_ICON_SIZE_LARGE)) + { + if (loadIconMetric) + loadIconMetric(InstanceHandle, Name, (Flags & PH_LOAD_ICON_SIZE_SMALL) ? LIM_SMALL : LIM_LARGE, &icon); + } + else + { + if (loadIconWithScaleDown) + loadIconWithScaleDown(InstanceHandle, Name, Width, Height, &icon); + } + + if (!icon && !(Flags & PH_LOAD_ICON_STRICT)) + { + if (Flags & PH_LOAD_ICON_SIZE_SMALL) + { + static ULONG smallWidth = 0; + static ULONG smallHeight = 0; + + if (!smallWidth) + smallWidth = GetSystemMetrics(SM_CXSMICON); + if (!smallHeight) + smallHeight = GetSystemMetrics(SM_CYSMICON); + + Width = smallWidth; + Height = smallHeight; + } + else if (Flags & PH_LOAD_ICON_SIZE_LARGE) + { + static ULONG largeWidth = 0; + static ULONG largeHeight = 0; + + if (!largeWidth) + largeWidth = GetSystemMetrics(SM_CXICON); + if (!largeHeight) + largeHeight = GetSystemMetrics(SM_CYICON); + + Width = largeWidth; + Height = largeHeight; + } + + icon = LoadImage(InstanceHandle, Name, IMAGE_ICON, Width, Height, 0); + } + + if (Flags & PH_LOAD_ICON_SHARED) + { + if (icon) + { + if (!IS_INTRESOURCE(Name)) + entry.Name = PhDuplicateStringZ(Name); + entry.Icon = icon; + PhAddEntryHashtable(SharedIconCacheHashtable, &entry); + } + + PhReleaseQueuedLockExclusive(&SharedIconCacheLock); + } + + return icon; +} + +/** + * Gets the default icon used for executable files. + * + * \param SmallIcon A variable which receives the small default executable icon. Do not destroy the + * icon using DestroyIcon(); it is shared between callers. + * \param LargeIcon A variable which receives the large default executable icon. Do not destroy the + * icon using DestroyIcon(); it is shared between callers. + */ +VOID PhGetStockApplicationIcon( + _Out_opt_ HICON *SmallIcon, + _Out_opt_ HICON *LargeIcon + ) +{ + static PH_INITONCE initOnce = PH_INITONCE_INIT; + static HICON smallIcon = NULL; + static HICON largeIcon = NULL; + + // This no longer uses SHGetFileInfo because it is *very* slow and causes many other DLLs to be + // loaded, increasing memory usage. The worst thing about it, however, is that it is horribly + // incompatible with multi-threading. The first time it is called, it tries to perform some + // one-time initialization. It guards this with a lock, but when multiple threads try to call + // the function at the same time, instead of waiting for initialization to finish it simply + // fails the other threads. + + if (PhBeginInitOnce(&initOnce)) + { + PPH_STRING systemDirectory; + PPH_STRING dllFileName; + + // imageres,11 (Windows 10 and above), user32,0 (Vista and above) or shell32,2 (XP) contains + // the default application icon. + + if (systemDirectory = PhGetSystemDirectory()) + { + PH_STRINGREF dllBaseName; + ULONG index; + + // TODO: Find a better solution. + if (WindowsVersion >= WINDOWS_10) + { + PhInitializeStringRef(&dllBaseName, L"\\imageres.dll"); + index = 11; + } + else if (WindowsVersion >= WINDOWS_VISTA) + { + PhInitializeStringRef(&dllBaseName, L"\\user32.dll"); + index = 0; + } + else + { + PhInitializeStringRef(&dllBaseName, L"\\shell32.dll"); + index = 2; + } + + dllFileName = PhConcatStringRef2(&systemDirectory->sr, &dllBaseName); + PhDereferenceObject(systemDirectory); + + ExtractIconEx(dllFileName->Buffer, index, &largeIcon, &smallIcon, 1); + PhDereferenceObject(dllFileName); + } + + // Fallback icons + if (!smallIcon) + smallIcon = PhLoadIcon(NULL, MAKEINTRESOURCE(IDI_APPLICATION), PH_LOAD_ICON_SIZE_SMALL, 0, 0); + if (!largeIcon) + largeIcon = PhLoadIcon(NULL, MAKEINTRESOURCE(IDI_APPLICATION), PH_LOAD_ICON_SIZE_LARGE, 0, 0); + + PhEndInitOnce(&initOnce); + } + + if (SmallIcon) + *SmallIcon = smallIcon; + if (LargeIcon) + *LargeIcon = largeIcon; +} + +HICON PhGetFileShellIcon( + _In_opt_ PWSTR FileName, + _In_opt_ PWSTR DefaultExtension, + _In_ BOOLEAN LargeIcon + ) +{ + SHFILEINFO fileInfo; + ULONG iconFlag; + HICON icon; + + if (DefaultExtension && PhEqualStringZ(DefaultExtension, L".exe", TRUE)) + { + // Special case for executable files (see above for reasoning). + + icon = NULL; + + if (FileName) + { + ExtractIconEx( + FileName, + 0, + LargeIcon ? &icon : NULL, + !LargeIcon ? &icon : NULL, + 1 + ); + } + + if (!icon) + { + PhGetStockApplicationIcon( + !LargeIcon ? &icon : NULL, + LargeIcon ? &icon : NULL + ); + + if (icon) + icon = DuplicateIcon(NULL, icon); + } + + return icon; + } + + iconFlag = LargeIcon ? SHGFI_LARGEICON : SHGFI_SMALLICON; + icon = NULL; + + if (FileName && SHGetFileInfo( + FileName, + 0, + &fileInfo, + sizeof(SHFILEINFO), + SHGFI_ICON | iconFlag + )) + { + icon = fileInfo.hIcon; + } + + if (!icon && DefaultExtension) + { + if (SHGetFileInfo( + DefaultExtension, + FILE_ATTRIBUTE_NORMAL, + &fileInfo, + sizeof(SHFILEINFO), + SHGFI_ICON | iconFlag | SHGFI_USEFILEATTRIBUTES + )) + icon = fileInfo.hIcon; + } + + return icon; +} + +VOID PhpSetClipboardData( + _In_ HWND hWnd, + _In_ ULONG Format, + _In_ HANDLE Data + ) +{ + if (OpenClipboard(hWnd)) + { + if (!EmptyClipboard()) + goto Fail; + + if (!SetClipboardData(Format, Data)) + goto Fail; + + CloseClipboard(); + + return; + } + +Fail: + GlobalFree(Data); +} + +VOID PhSetClipboardString( + _In_ HWND hWnd, + _In_ PPH_STRINGREF String + ) +{ + HANDLE data; + PVOID memory; + + data = GlobalAlloc(GMEM_MOVEABLE, String->Length + sizeof(WCHAR)); + memory = GlobalLock(data); + + memcpy(memory, String->Buffer, String->Length); + *(PWCHAR)((PCHAR)memory + String->Length) = 0; + + GlobalUnlock(memory); + + PhpSetClipboardData(hWnd, CF_UNICODETEXT, data); +} + +HWND PhCreateDialogFromTemplate( + _In_ HWND Parent, + _In_ ULONG Style, + _In_ PVOID Instance, + _In_ PWSTR Template, + _In_ DLGPROC DialogProc, + _In_ PVOID Parameter + ) +{ + HRSRC resourceInfo; + ULONG resourceSize; + HGLOBAL resourceHandle; + PDLGTEMPLATEEX dialog; + PDLGTEMPLATEEX dialogCopy; + HWND dialogHandle; + + resourceInfo = FindResource(Instance, Template, MAKEINTRESOURCE(RT_DIALOG)); + + if (!resourceInfo) + return NULL; + + resourceSize = SizeofResource(Instance, resourceInfo); + + if (resourceSize == 0) + return NULL; + + resourceHandle = LoadResource(Instance, resourceInfo); + + if (!resourceHandle) + return NULL; + + dialog = LockResource(resourceHandle); + + if (!dialog) + return NULL; + + dialogCopy = PhAllocateCopy(dialog, resourceSize); + + if (dialogCopy->signature == 0xffff) + { + dialogCopy->style = Style; + } + else + { + ((DLGTEMPLATE *)dialogCopy)->style = Style; + } + + dialogHandle = CreateDialogIndirectParam(Instance, (DLGTEMPLATE *)dialogCopy, Parent, DialogProc, (LPARAM)Parameter); + + PhFree(dialogCopy); + + return dialogHandle; +} + +BOOLEAN PhModalPropertySheet( + _Inout_ PROPSHEETHEADER *Header + ) +{ + // PropertySheet incorrectly discards WM_QUIT messages in certain cases, so we will use our own + // message loop. An example of this is when GetMessage (called by PropertySheet's message loop) + // dispatches a message directly from kernel-mode that causes the property sheet to close. In + // that case PropertySheet will retrieve the WM_QUIT message but will ignore it because of its + // buggy logic. + + // This is also a good opportunity to introduce an auto-pool. + + PH_AUTO_POOL autoPool; + HWND oldFocus; + HWND topLevelOwner; + HWND hwnd; + BOOL result; + MSG message; + + PhInitializeAutoPool(&autoPool); + + oldFocus = GetFocus(); + topLevelOwner = Header->hwndParent; + + while (topLevelOwner && (GetWindowLong(topLevelOwner, GWL_STYLE) & WS_CHILD)) + topLevelOwner = GetParent(topLevelOwner); + + if (topLevelOwner && (topLevelOwner == GetDesktopWindow() || EnableWindow(topLevelOwner, FALSE))) + topLevelOwner = NULL; + + Header->dwFlags |= PSH_MODELESS; + hwnd = (HWND)PropertySheet(Header); + + if (!hwnd) + { + if (topLevelOwner) + EnableWindow(topLevelOwner, TRUE); + + return FALSE; + } + + while (result = GetMessage(&message, NULL, 0, 0)) + { + if (result == -1) + break; + + if (!PropSheet_IsDialogMessage(hwnd, &message)) + { + TranslateMessage(&message); + DispatchMessage(&message); + } + + PhDrainAutoPool(&autoPool); + + // Destroy the window when necessary. + if (!PropSheet_GetCurrentPageHwnd(hwnd)) + break; + } + + if (result == 0) + PostQuitMessage((INT)message.wParam); + if (Header->hwndParent && GetActiveWindow() == hwnd) + SetActiveWindow(Header->hwndParent); + if (topLevelOwner) + EnableWindow(topLevelOwner, TRUE); + if (oldFocus && IsWindow(oldFocus)) + SetFocus(oldFocus); + + DestroyWindow(hwnd); + PhDeleteAutoPool(&autoPool); + + return TRUE; +} + +VOID PhInitializeLayoutManager( + _Out_ PPH_LAYOUT_MANAGER Manager, + _In_ HWND RootWindowHandle + ) +{ + Manager->List = PhCreateList(4); + Manager->LayoutNumber = 0; + + Manager->RootItem.Handle = RootWindowHandle; + GetClientRect(Manager->RootItem.Handle, &Manager->RootItem.Rect); + Manager->RootItem.OrigRect = Manager->RootItem.Rect; + Manager->RootItem.ParentItem = NULL; + Manager->RootItem.LayoutParentItem = NULL; + Manager->RootItem.LayoutNumber = 0; + Manager->RootItem.NumberOfChildren = 0; + Manager->RootItem.DeferHandle = NULL; +} + +VOID PhDeleteLayoutManager( + _Inout_ PPH_LAYOUT_MANAGER Manager + ) +{ + ULONG i; + + for (i = 0; i < Manager->List->Count; i++) + PhFree(Manager->List->Items[i]); + + PhDereferenceObject(Manager->List); +} + +// HACK: The math below is all horribly broken, especially the HACK for multiline tab controls. + +PPH_LAYOUT_ITEM PhAddLayoutItem( + _Inout_ PPH_LAYOUT_MANAGER Manager, + _In_ HWND Handle, + _In_opt_ PPH_LAYOUT_ITEM ParentItem, + _In_ ULONG Anchor + ) +{ + PPH_LAYOUT_ITEM layoutItem; + RECT dummy = { 0 }; + + layoutItem = PhAddLayoutItemEx( + Manager, + Handle, + ParentItem, + Anchor, + dummy + ); + + layoutItem->Margin = layoutItem->Rect; + PhConvertRect(&layoutItem->Margin, &layoutItem->ParentItem->Rect); + + if (layoutItem->ParentItem != layoutItem->LayoutParentItem) + { + // Fix the margin because the item has a dummy parent. They share the same layout parent + // item. + layoutItem->Margin.top -= layoutItem->ParentItem->Rect.top; + layoutItem->Margin.left -= layoutItem->ParentItem->Rect.left; + layoutItem->Margin.right = layoutItem->ParentItem->Margin.right; + layoutItem->Margin.bottom = layoutItem->ParentItem->Margin.bottom; + } + + return layoutItem; +} + +PPH_LAYOUT_ITEM PhAddLayoutItemEx( + _Inout_ PPH_LAYOUT_MANAGER Manager, + _In_ HWND Handle, + _In_opt_ PPH_LAYOUT_ITEM ParentItem, + _In_ ULONG Anchor, + _In_ RECT Margin + ) +{ + PPH_LAYOUT_ITEM item; + + if (!ParentItem) + ParentItem = &Manager->RootItem; + + item = PhAllocate(sizeof(PH_LAYOUT_ITEM)); + item->Handle = Handle; + item->ParentItem = ParentItem; + item->LayoutNumber = Manager->LayoutNumber; + item->NumberOfChildren = 0; + item->DeferHandle = NULL; + item->Anchor = Anchor; + + item->LayoutParentItem = item->ParentItem; + + while ((item->LayoutParentItem->Anchor & PH_LAYOUT_DUMMY_MASK) && + item->LayoutParentItem->LayoutParentItem) + { + item->LayoutParentItem = item->LayoutParentItem->LayoutParentItem; + } + + item->LayoutParentItem->NumberOfChildren++; + + GetWindowRect(Handle, &item->Rect); + MapWindowPoints(NULL, item->LayoutParentItem->Handle, (POINT *)&item->Rect, 2); + + if (item->Anchor & PH_LAYOUT_TAB_CONTROL) + { + // We want to convert the tab control rectangle to the tab page display rectangle. + TabCtrl_AdjustRect(Handle, FALSE, &item->Rect); + } + + item->Margin = Margin; + + item->OrigRect = item->Rect; + + PhAddItemList(Manager->List, item); + + return item; +} + +VOID PhpLayoutItemLayout( + _Inout_ PPH_LAYOUT_MANAGER Manager, + _Inout_ PPH_LAYOUT_ITEM Item + ) +{ + RECT rect; + BOOLEAN hasDummyParent; + + if (Item->NumberOfChildren > 0 && !Item->DeferHandle) + Item->DeferHandle = BeginDeferWindowPos(Item->NumberOfChildren); + + if (Item->LayoutNumber == Manager->LayoutNumber) + return; + + // If this is the root item we must stop here. + if (!Item->ParentItem) + return; + + PhpLayoutItemLayout(Manager, Item->ParentItem); + + if (Item->ParentItem != Item->LayoutParentItem) + { + PhpLayoutItemLayout(Manager, Item->LayoutParentItem); + hasDummyParent = TRUE; + } + else + { + hasDummyParent = FALSE; + } + + GetWindowRect(Item->Handle, &Item->Rect); + MapWindowPoints(NULL, Item->LayoutParentItem->Handle, (POINT *)&Item->Rect, 2); + + if (Item->Anchor & PH_LAYOUT_TAB_CONTROL) + { + // We want to convert the tab control rectangle to the tab page display rectangle. + TabCtrl_AdjustRect(Item->Handle, FALSE, &Item->Rect); + } + + if (!(Item->Anchor & PH_LAYOUT_DUMMY_MASK)) + { + // Convert right/bottom into margins to make the calculations + // easier. + rect = Item->Rect; + PhConvertRect(&rect, &Item->LayoutParentItem->Rect); + + if (!(Item->Anchor & (PH_ANCHOR_LEFT | PH_ANCHOR_RIGHT))) + { + // TODO + PhRaiseStatus(STATUS_NOT_IMPLEMENTED); + } + else if (Item->Anchor & PH_ANCHOR_RIGHT) + { + if (Item->Anchor & PH_ANCHOR_LEFT) + { + rect.left = (hasDummyParent ? Item->ParentItem->Rect.left : 0) + Item->Margin.left; + rect.right = Item->Margin.right; + } + else + { + ULONG diff = Item->Margin.right - rect.right; + + rect.left -= diff; + rect.right += diff; + } + } + + if (!(Item->Anchor & (PH_ANCHOR_TOP | PH_ANCHOR_BOTTOM))) + { + // TODO + PhRaiseStatus(STATUS_NOT_IMPLEMENTED); + } + else if (Item->Anchor & PH_ANCHOR_BOTTOM) + { + if (Item->Anchor & PH_ANCHOR_TOP) + { + // tab control hack + rect.top = (hasDummyParent ? Item->ParentItem->Rect.top : 0) + Item->Margin.top; + rect.bottom = Item->Margin.bottom; + } + else + { + ULONG diff = Item->Margin.bottom - rect.bottom; + + rect.top -= diff; + rect.bottom += diff; + } + } + + // Convert the right/bottom back into co-ordinates. + PhConvertRect(&rect, &Item->LayoutParentItem->Rect); + Item->Rect = rect; + + if (!(Item->Anchor & PH_LAYOUT_IMMEDIATE_RESIZE)) + { + Item->LayoutParentItem->DeferHandle = DeferWindowPos( + Item->LayoutParentItem->DeferHandle, Item->Handle, + NULL, rect.left, rect.top, + rect.right - rect.left, rect.bottom - rect.top, + SWP_NOACTIVATE | SWP_NOZORDER + ); + } + else + { + // This is needed for tab controls, so that TabCtrl_AdjustRect will give us an + // up-to-date result. + SetWindowPos( + Item->Handle, + NULL, rect.left, rect.top, + rect.right - rect.left, rect.bottom - rect.top, + SWP_NOACTIVATE | SWP_NOZORDER + ); + } + } + + Item->LayoutNumber = Manager->LayoutNumber; +} + +VOID PhLayoutManagerLayout( + _Inout_ PPH_LAYOUT_MANAGER Manager + ) +{ + ULONG i; + + Manager->LayoutNumber++; + + GetClientRect(Manager->RootItem.Handle, &Manager->RootItem.Rect); + + for (i = 0; i < Manager->List->Count; i++) + { + PPH_LAYOUT_ITEM item = (PPH_LAYOUT_ITEM)Manager->List->Items[i]; + + PhpLayoutItemLayout(Manager, item); + } + + for (i = 0; i < Manager->List->Count; i++) + { + PPH_LAYOUT_ITEM item = (PPH_LAYOUT_ITEM)Manager->List->Items[i]; + + if (item->DeferHandle) + { + EndDeferWindowPos(item->DeferHandle); + item->DeferHandle = NULL; + } + + if (item->Anchor & PH_LAYOUT_FORCE_INVALIDATE) + { + InvalidateRect(item->Handle, NULL, FALSE); + } + } + + if (Manager->RootItem.DeferHandle) + { + EndDeferWindowPos(Manager->RootItem.DeferHandle); + Manager->RootItem.DeferHandle = NULL; + } +} diff --git a/phlib/handle.c b/phlib/handle.c index d3708b25b6f7..6f7d5fe505a3 100644 --- a/phlib/handle.c +++ b/phlib/handle.c @@ -1,1097 +1,1097 @@ -/* - * Process Hacker - - * handle table - * - * Copyright (C) 2010-2011 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include -#include -#include - -static PH_INITONCE PhHandleTableInitOnce = PH_INITONCE_INIT; -static PH_FREE_LIST PhHandleTableLevel0FreeList; -static PH_FREE_LIST PhHandleTableLevel1FreeList; - -PPH_HANDLE_TABLE PhCreateHandleTable( - VOID - ) -{ - PPH_HANDLE_TABLE handleTable; - ULONG i; - - if (PhBeginInitOnce(&PhHandleTableInitOnce)) - { - PhInitializeFreeList( - &PhHandleTableLevel0FreeList, - sizeof(PH_HANDLE_TABLE_ENTRY) * PH_HANDLE_TABLE_LEVEL_ENTRIES, - 64 - ); - PhInitializeFreeList( - &PhHandleTableLevel1FreeList, - sizeof(PPH_HANDLE_TABLE_ENTRY) * PH_HANDLE_TABLE_LEVEL_ENTRIES, - 64 - ); - PhEndInitOnce(&PhHandleTableInitOnce); - } - -#ifdef PH_HANDLE_TABLE_SAFE - handleTable = PhAllocateSafe(sizeof(PH_HANDLE_TABLE)); - - if (!handleTable) - return NULL; -#else - handleTable = PhAllocate(sizeof(PH_HANDLE_TABLE)); -#endif - - PhInitializeQueuedLock(&handleTable->Lock); - PhInitializeWakeEvent(&handleTable->HandleWakeEvent); - - handleTable->NextValue = 0; - - handleTable->Count = 0; - handleTable->TableValue = (ULONG_PTR)PhpCreateHandleTableLevel0(handleTable, TRUE); - -#ifdef PH_HANDLE_TABLE_SAFE - if (!handleTable->TableValue) - { - PhFree(handleTable); - return NULL; - } -#endif - - // We have now created the level 0 table. The free list can now be set up to point to handle 0, - // which points to the rest of the free list (1 -> 2 -> 3 -> ...). The next batch of handles - // that need to be created start at PH_HANDLE_TABLE_LEVEL_ENTRIES. - - handleTable->FreeValue = 0; - handleTable->NextValue = PH_HANDLE_TABLE_LEVEL_ENTRIES; - - handleTable->FreeValueAlt = PH_HANDLE_VALUE_INVALID; // no entries in alt. free list - - handleTable->Flags = 0; - - for (i = 0; i < PH_HANDLE_TABLE_LOCKS; i++) - PhInitializeQueuedLock(&handleTable->Locks[i]); - - return handleTable; -} - -VOID PhDestroyHandleTable( - _In_ _Post_invalid_ PPH_HANDLE_TABLE HandleTable - ) -{ - ULONG_PTR tableValue; - ULONG tableLevel; - PPH_HANDLE_TABLE_ENTRY table0; - PPH_HANDLE_TABLE_ENTRY *table1; - PPH_HANDLE_TABLE_ENTRY **table2; - ULONG i; - ULONG j; - - tableValue = HandleTable->TableValue; - tableLevel = tableValue & PH_HANDLE_TABLE_LEVEL_MASK; - tableValue -= tableLevel; - - switch (tableLevel) - { - case 0: - { - table0 = (PPH_HANDLE_TABLE_ENTRY)tableValue; - - PhpFreeHandleTableLevel0(table0); - } - break; - case 1: - { - table1 = (PPH_HANDLE_TABLE_ENTRY *)tableValue; - - for (i = 0; i < PH_HANDLE_TABLE_LEVEL_ENTRIES; i++) - { - if (!table1[i]) - break; - - PhpFreeHandleTableLevel0(table1[i]); - } - - PhpFreeHandleTableLevel1(table1); - } - break; - case 2: - { - table2 = (PPH_HANDLE_TABLE_ENTRY **)tableValue; - - for (i = 0; i < PH_HANDLE_TABLE_LEVEL_ENTRIES; i++) - { - if (!table2[i]) - break; - - for (j = 0; j < PH_HANDLE_TABLE_LEVEL_ENTRIES; j++) - { - if (!table2[i][j]) - break; - - PhpFreeHandleTableLevel0(table2[i][j]); - } - - PhpFreeHandleTableLevel1(table2[i]); - } - - PhpFreeHandleTableLevel2(table2); - } - break; - default: - ASSUME_NO_DEFAULT; - } - - PhFree(HandleTable); -} - -VOID PhpBlockOnLockedHandleTableEntry( - _Inout_ PPH_HANDLE_TABLE HandleTable, - _In_ PPH_HANDLE_TABLE_ENTRY HandleTableEntry - ) -{ - PH_QUEUED_WAIT_BLOCK waitBlock; - ULONG_PTR value; - - PhQueueWakeEvent(&HandleTable->HandleWakeEvent, &waitBlock); - - value = HandleTableEntry->Value; - - if ( - (value & PH_HANDLE_TABLE_ENTRY_TYPE) != PH_HANDLE_TABLE_ENTRY_IN_USE || - (value & PH_HANDLE_TABLE_ENTRY_LOCKED) - ) - { - // Entry is not in use or has been unlocked; cancel the wait. - PhSetWakeEvent(&HandleTable->HandleWakeEvent, &waitBlock); - } - else - { - PhWaitForWakeEvent(&HandleTable->HandleWakeEvent, &waitBlock, TRUE, NULL); - } -} - -BOOLEAN PhLockHandleTableEntry( - _Inout_ PPH_HANDLE_TABLE HandleTable, - _Inout_ PPH_HANDLE_TABLE_ENTRY HandleTableEntry - ) -{ - ULONG_PTR value; - - while (TRUE) - { - value = HandleTableEntry->Value; - - if ((value & PH_HANDLE_TABLE_ENTRY_TYPE) != PH_HANDLE_TABLE_ENTRY_IN_USE) - return FALSE; - - if (value & PH_HANDLE_TABLE_ENTRY_LOCKED) - { - if ((ULONG_PTR)_InterlockedCompareExchangePointer( - (PVOID *)&HandleTableEntry->Value, - (PVOID)(value - PH_HANDLE_TABLE_ENTRY_LOCKED), - (PVOID)value - ) == value) - { - return TRUE; - } - } - - PhpBlockOnLockedHandleTableEntry(HandleTable, HandleTableEntry); - } -} - -VOID PhUnlockHandleTableEntry( - _Inout_ PPH_HANDLE_TABLE HandleTable, - _Inout_ PPH_HANDLE_TABLE_ENTRY HandleTableEntry - ) -{ - _interlockedbittestandset( - (PLONG)&HandleTableEntry->Value, - PH_HANDLE_TABLE_ENTRY_LOCKED_SHIFT - ); - PhSetWakeEvent(&HandleTable->HandleWakeEvent, NULL); -} - -HANDLE PhCreateHandle( - _Inout_ PPH_HANDLE_TABLE HandleTable, - _In_ PPH_HANDLE_TABLE_ENTRY HandleTableEntry - ) -{ - PPH_HANDLE_TABLE_ENTRY entry; - ULONG handleValue; - - entry = PhpAllocateHandleTableEntry(HandleTable, &handleValue); - - if (!entry) - return NULL; - - // Copy the given handle table entry to the allocated entry. - - // All free entries have the Free type and have the (not) locked bit clear. There is no problem - // with setting the Type now; the entry is still locked, so they will block. - entry->TypeAndValue.Type = PH_HANDLE_TABLE_ENTRY_IN_USE; - entry->TypeAndValue.Value = HandleTableEntry->TypeAndValue.Value; - entry->Value2 = HandleTableEntry->Value2; - - // Now we unlock this entry, waking anyone who was caught back there before we had finished - // setting up the entry. - PhUnlockHandleTableEntry(HandleTable, entry); - - return PhpEncodeHandle(handleValue); -} - -BOOLEAN PhDestroyHandle( - _Inout_ PPH_HANDLE_TABLE HandleTable, - _In_ HANDLE Handle, - _In_opt_ PPH_HANDLE_TABLE_ENTRY HandleTableEntry - ) -{ - ULONG handleValue; - - handleValue = PhpDecodeHandle(Handle); - - if (!HandleTableEntry) - { - HandleTableEntry = PhpLookupHandleTableEntry(HandleTable, handleValue); - - if (!HandleTableEntry) - return FALSE; - - if (!PhLockHandleTableEntry(HandleTable, HandleTableEntry)) - return FALSE; - } - - _InterlockedExchangePointer( - (PVOID *)&HandleTableEntry->Value, - (PVOID)PH_HANDLE_TABLE_ENTRY_FREE - ); - - // The handle table entry is now free; wake any waiters because they can't lock the entry now. - // Any future lock attempts will fail because the entry is marked as being free. - PhSetWakeEvent(&HandleTable->HandleWakeEvent, NULL); - - PhpFreeHandleTableEntry(HandleTable, handleValue, HandleTableEntry); - - return TRUE; -} - -PPH_HANDLE_TABLE_ENTRY PhLookupHandleTableEntry( - _In_ PPH_HANDLE_TABLE HandleTable, - _In_ HANDLE Handle - ) -{ - PPH_HANDLE_TABLE_ENTRY entry; - - entry = PhpLookupHandleTableEntry(HandleTable, PhpDecodeHandle(Handle)); - - if (!entry) - return NULL; - - if (!PhLockHandleTableEntry(HandleTable, entry)) - return NULL; - - return entry; -} - -VOID PhEnumHandleTable( - _In_ PPH_HANDLE_TABLE HandleTable, - _In_ PPH_ENUM_HANDLE_TABLE_CALLBACK Callback, - _In_opt_ PVOID Context - ) -{ - ULONG handleValue; - PPH_HANDLE_TABLE_ENTRY entry; - BOOLEAN cont; - - handleValue = 0; - - while (entry = PhpLookupHandleTableEntry(HandleTable, handleValue)) - { - if (PhLockHandleTableEntry(HandleTable, entry)) - { - cont = Callback( - HandleTable, - PhpEncodeHandle(handleValue), - entry, - Context - ); - PhUnlockHandleTableEntry(HandleTable, entry); - - if (!cont) - break; - } - - handleValue++; - } -} - -VOID PhSweepHandleTable( - _In_ PPH_HANDLE_TABLE HandleTable, - _In_ PPH_ENUM_HANDLE_TABLE_CALLBACK Callback, - _In_opt_ PVOID Context - ) -{ - ULONG handleValue; - PPH_HANDLE_TABLE_ENTRY entry; - BOOLEAN cont; - - handleValue = 0; - - while (entry = PhpLookupHandleTableEntry(HandleTable, handleValue)) - { - if (entry->TypeAndValue.Type == PH_HANDLE_TABLE_ENTRY_IN_USE) - { - cont = Callback( - HandleTable, - PhpEncodeHandle(handleValue), - entry, - Context - ); - - if (!cont) - break; - } - - handleValue++; - } -} - -NTSTATUS PhQueryInformationHandleTable( - _In_ PPH_HANDLE_TABLE HandleTable, - _In_ PH_HANDLE_TABLE_INFORMATION_CLASS InformationClass, - _Out_writes_bytes_opt_(BufferLength) PVOID Buffer, - _In_ ULONG BufferLength, - _Out_opt_ PULONG ReturnLength - ) -{ - NTSTATUS status = STATUS_SUCCESS; - ULONG returnLength; - - switch (InformationClass) - { - case HandleTableBasicInformation: - { - PPH_HANDLE_TABLE_BASIC_INFORMATION basicInfo = Buffer; - - if (BufferLength == sizeof(PH_HANDLE_TABLE_BASIC_INFORMATION)) - { - basicInfo->Count = HandleTable->Count; - basicInfo->Flags = HandleTable->Flags; - basicInfo->TableLevel = HandleTable->TableValue & PH_HANDLE_TABLE_LEVEL_MASK; - } - else - { - status = STATUS_INFO_LENGTH_MISMATCH; - } - - returnLength = sizeof(PH_HANDLE_TABLE_BASIC_INFORMATION); - } - break; - case HandleTableFlagsInformation: - { - PPH_HANDLE_TABLE_FLAGS_INFORMATION flagsInfo = Buffer; - - if (BufferLength == sizeof(PH_HANDLE_TABLE_FLAGS_INFORMATION)) - { - flagsInfo->Flags = HandleTable->Flags; - } - else - { - status = STATUS_INFO_LENGTH_MISMATCH; - } - - returnLength = sizeof(PH_HANDLE_TABLE_FLAGS_INFORMATION); - } - break; - default: - status = STATUS_INVALID_INFO_CLASS; - returnLength = 0; - break; - } - - if (ReturnLength) - *ReturnLength = returnLength; - - return status; -} - -NTSTATUS PhSetInformationHandleTable( - _Inout_ PPH_HANDLE_TABLE HandleTable, - _In_ PH_HANDLE_TABLE_INFORMATION_CLASS InformationClass, - _In_reads_bytes_(BufferLength) PVOID Buffer, - _In_ ULONG BufferLength - ) -{ - NTSTATUS status = STATUS_SUCCESS; - - switch (InformationClass) - { - case HandleTableFlagsInformation: - { - PPH_HANDLE_TABLE_FLAGS_INFORMATION flagsInfo = Buffer; - ULONG flags; - - if (BufferLength == sizeof(PH_HANDLE_TABLE_FLAGS_INFORMATION)) - { - flags = flagsInfo->Flags; - - if ((flags & PH_HANDLE_TABLE_VALID_FLAGS) == flags) - HandleTable->Flags = flags; - else - status = STATUS_INVALID_PARAMETER; - } - else - { - status = STATUS_INFO_LENGTH_MISMATCH; - } - } - break; - default: - status = STATUS_INVALID_INFO_CLASS; - } - - return status; -} - -PPH_HANDLE_TABLE_ENTRY PhpAllocateHandleTableEntry( - _Inout_ PPH_HANDLE_TABLE HandleTable, - _Out_ PULONG HandleValue - ) -{ - PPH_HANDLE_TABLE_ENTRY entry; - ULONG freeValue; - ULONG lockIndex; - ULONG nextFreeValue; - ULONG oldFreeValue; - BOOLEAN result; - - while (TRUE) - { - freeValue = HandleTable->FreeValue; - - while (freeValue == PH_HANDLE_VALUE_INVALID) - { - PhAcquireQueuedLockExclusive(&HandleTable->Lock); - - // Check again to see if we have free handles. - - freeValue = HandleTable->FreeValue; - - if (freeValue != PH_HANDLE_VALUE_INVALID) - { - PhReleaseQueuedLockExclusive(&HandleTable->Lock); - break; - } - - // Move handles from the alt. free list to the main free list, and check again. - - freeValue = PhpMoveFreeHandleTableEntries(HandleTable); - - if (freeValue != PH_HANDLE_VALUE_INVALID) - { - PhReleaseQueuedLockExclusive(&HandleTable->Lock); - break; - } - - result = PhpAllocateMoreHandleTableEntries(HandleTable, TRUE); - - PhReleaseQueuedLockExclusive(&HandleTable->Lock); - - freeValue = HandleTable->FreeValue; - - // Note that PhpAllocateMoreHandleTableEntries only returns FALSE if it failed to - // allocate memory. Success does not guarantee a free handle to be allocated, as they - // may have been all used up (however unlikely) when we reach this point. Success simply - // means to retry the allocation using the fast path. - - if (!result && freeValue == PH_HANDLE_VALUE_INVALID) - return NULL; - } - - entry = PhpLookupHandleTableEntry(HandleTable, freeValue); - lockIndex = PH_HANDLE_TABLE_LOCK_INDEX(freeValue); - - // To avoid the ABA problem, we would ideally have one queued lock per handle table entry. - // That would make the overhead too large, so instead there is a fixed number of locks, - // indexed by the handle value (mod no. locks). - - // Possibilities at this point: - // 1. freeValue != A (our copy), but the other thread has freed A, so FreeValue = A. No ABA - // problem since freeValue != A. - // 2. freeValue != A, and FreeValue != A. No ABA problem. - // 3. freeValue = A, and the other thread has freed A, so FreeValue = A. No ABA problem - // since we haven't read NextFreeValue yet. - // 4. freeValue = A, and FreeValue != A. No problem if this stays the same later, as the CAS - // will take care of it. - - PhpLockHandleTableShared(HandleTable, lockIndex); - - if (HandleTable->FreeValue != freeValue) - { - PhpUnlockHandleTableShared(HandleTable, lockIndex); - continue; - } - - MemoryBarrier(); - - nextFreeValue = entry->NextFreeValue; - - // Possibilities/non-possibilities at this point: - // 1. freeValue != A (our copy), but the other thread has freed A, so FreeValue = A. This is - // actually impossible since we have acquired the lock on A and the free code checks that - // and uses the alt. free list instead. - // 2. freeValue != A, and FreeValue != A. No ABA problem. - // 3. freeValue = A, and the other thread has freed A, so FreeValue = A. Impossible like - // above. This is *the* ABA problem which we have now prevented. - // 4. freeValue = A, and FreeValue != A. CAS will take care of it. - - oldFreeValue = _InterlockedCompareExchange( - &HandleTable->FreeValue, - nextFreeValue, - freeValue - ); - - PhpUnlockHandleTableShared(HandleTable, lockIndex); - - if (oldFreeValue == freeValue) - break; - } - - _InterlockedIncrement((PLONG)&HandleTable->Count); - - *HandleValue = freeValue; - - return entry; -} - -VOID PhpFreeHandleTableEntry( - _Inout_ PPH_HANDLE_TABLE HandleTable, - _In_ ULONG HandleValue, - _Inout_ PPH_HANDLE_TABLE_ENTRY HandleTableEntry - ) -{ - PULONG freeList; - ULONG flags; - ULONG oldValue; - - _InterlockedDecrement((PLONG)&HandleTable->Count); - - flags = HandleTable->Flags; - - // Choose the free list to use depending on whether someone is popping from the main free list - // (see PhpAllocateHandleTableEntry for details). We always use the alt. free list if strict - // FIFO is enabled. - if (!(flags & PH_HANDLE_TABLE_STRICT_FIFO) && - PhTryAcquireReleaseQueuedLockExclusive( - &HandleTable->Locks[PH_HANDLE_TABLE_LOCK_INDEX(HandleValue)])) - { - freeList = &HandleTable->FreeValue; - } - else - { - freeList = &HandleTable->FreeValueAlt; - } - - while (TRUE) - { - oldValue = *freeList; - HandleTableEntry->NextFreeValue = oldValue; - - if (_InterlockedCompareExchange( - freeList, - HandleValue, - oldValue - ) == oldValue) - { - break; - } - } -} - -BOOLEAN PhpAllocateMoreHandleTableEntries( - _In_ PPH_HANDLE_TABLE HandleTable, - _In_ BOOLEAN Initialize - ) -{ - ULONG_PTR tableValue; - ULONG tableLevel; - PPH_HANDLE_TABLE_ENTRY table0; - PPH_HANDLE_TABLE_ENTRY *table1; - PPH_HANDLE_TABLE_ENTRY **table2; - ULONG i; - ULONG j; - ULONG oldNextValue; - ULONG freeValue; - - // Get a pointer to the table, and its level. - - tableValue = HandleTable->TableValue; - tableLevel = tableValue & PH_HANDLE_TABLE_LEVEL_MASK; - tableValue -= tableLevel; - - switch (tableLevel) - { - case 0: - { - // Create a level 1 table. - - table1 = PhpCreateHandleTableLevel1(HandleTable); - -#ifdef PH_HANDLE_TABLE_SAFE - if (!table1) - return FALSE; -#endif - - // Create a new level 0 table and move the existing level into the new level 1 table. - - table0 = PhpCreateHandleTableLevel0(HandleTable, Initialize); - -#ifdef PH_HANDLE_TABLE_SAFE - if (!table0) - { - PhpFreeHandleTableLevel1(table1); - return FALSE; - } -#endif - - table1[0] = (PPH_HANDLE_TABLE_ENTRY)tableValue; - table1[1] = table0; - - tableValue = (ULONG_PTR)table1 | 1; - //_InterlockedExchangePointer((PVOID *)&HandleTable->TableValue, (PVOID)tableValue); - HandleTable->TableValue = tableValue; - } - break; - case 1: - { - table1 = (PPH_HANDLE_TABLE_ENTRY *)tableValue; - - // Determine whether we need to create a new level 0 table or create a level 2 table. - - i = HandleTable->NextValue / PH_HANDLE_TABLE_LEVEL_ENTRIES; - - if (i < PH_HANDLE_TABLE_LEVEL_ENTRIES) - { - table0 = PhpCreateHandleTableLevel0(HandleTable, TRUE); - -#ifdef PH_HANDLE_TABLE_SAFE - if (!table0) - return FALSE; -#endif - - //_InterlockedExchangePointer((PVOID *)&table1[i], table0); - table1[i] = table0; - } - else - { - // Create a level 2 table. - - table2 = PhpCreateHandleTableLevel2(HandleTable); - -#ifdef PH_HANDLE_TABLE_SAFE - if (!table2) - return FALSE; -#endif - - // Create a new level 1 table and move the existing level into the new level 2 - // table. - - table1 = PhpCreateHandleTableLevel1(HandleTable); - -#ifdef PH_HANDLE_TABLE_SAFE - if (!table1) - { - PhpFreeHandleTableLevel2(table2); - return FALSE; - } -#endif - - table0 = PhpCreateHandleTableLevel0(HandleTable, Initialize); - -#ifdef PH_HANDLE_TABLE_SAFE - if (!table0) - { - PhpFreeHandleTableLevel1(table1); - PhpFreeHandleTableLevel2(table2); - return FALSE; - } -#endif - - table1[0] = table0; - - table2[0] = (PPH_HANDLE_TABLE_ENTRY *)tableValue; - table2[1] = table1; - - tableValue = (ULONG_PTR)table2 | 2; - //_InterlockedExchangePointer((PVOID *)&HandleTable->TableValue, (PVOID)tableValue); - HandleTable->TableValue = tableValue; - } - } - break; - case 2: - { - table2 = (PPH_HANDLE_TABLE_ENTRY **)tableValue; - - i = HandleTable->NextValue / - (PH_HANDLE_TABLE_LEVEL_ENTRIES * PH_HANDLE_TABLE_LEVEL_ENTRIES); - // i contains an index into the level 2 table, of the containing level 1 table. - - // Check if we have exceeded the maximum number of handles. - - if (i >= PH_HANDLE_TABLE_LEVEL_ENTRIES) - return FALSE; - - // Check if we should create a new level 0 table or a new level 2 table. - if (table2[i]) - { - table0 = PhpCreateHandleTableLevel0(HandleTable, Initialize); - -#ifdef PH_HANDLE_TABLE_SAFE - if (!table0) - return FALSE; -#endif - - // Same as j = HandleTable->NextValue % (no. entries * no. entries), but we already - // calculated i so just use it. - j = HandleTable->NextValue - i * - (PH_HANDLE_TABLE_LEVEL_ENTRIES * PH_HANDLE_TABLE_LEVEL_ENTRIES); - j /= PH_HANDLE_TABLE_LEVEL_ENTRIES; - // j now contains an index into the level 1 table, of the containing level 0 table - // (the one which was created). - - //_InterlockedExchangePointer((PVOID *)&table2[i][j], table0); - table2[i][j] = table0; - } - else - { - table1 = PhpCreateHandleTableLevel1(HandleTable); - -#ifdef PH_HANDLE_TABLE_SAFE - if (!table1) - return FALSE; -#endif - - table0 = PhpCreateHandleTableLevel0(HandleTable, TRUE); - -#ifdef PH_HANDLE_TABLE_SAFE - if (!table0) - { - PhpFreeHandleTableLevel1(table1); - return FALSE; - } -#endif - - table1[0] = table0; - - //_InterlockedExchangePointer((PVOID *)&table2[i], table1); - table2[i] = table1; - } - } - break; - default: - ASSUME_NO_DEFAULT; - } - - // In each of the cases above, we allocated one additional level 0 table. - oldNextValue = _InterlockedExchangeAdd( - (PLONG)&HandleTable->NextValue, - PH_HANDLE_TABLE_LEVEL_ENTRIES - ); - - if (Initialize) - { - // No ABA problem since these are new handles being pushed. - - while (TRUE) - { - freeValue = HandleTable->FreeValue; - table0[PH_HANDLE_TABLE_LEVEL_ENTRIES - 1].NextFreeValue = freeValue; - - if (_InterlockedCompareExchange( - &HandleTable->FreeValue, - oldNextValue, - freeValue - ) == freeValue) - { - break; - } - } - } - - return TRUE; -} - -PPH_HANDLE_TABLE_ENTRY PhpLookupHandleTableEntry( - _In_ PPH_HANDLE_TABLE HandleTable, - _In_ ULONG HandleValue - ) -{ - ULONG_PTR tableValue; - ULONG tableLevel; - PPH_HANDLE_TABLE_ENTRY table0; - PPH_HANDLE_TABLE_ENTRY *table1; - PPH_HANDLE_TABLE_ENTRY **table2; - PPH_HANDLE_TABLE_ENTRY entry; - - if (HandleValue >= HandleTable->NextValue) - return NULL; - - // Get a pointer to the table, and its level. - - tableValue = HandleTable->TableValue; - tableLevel = tableValue & PH_HANDLE_TABLE_LEVEL_MASK; - tableValue -= tableLevel; - - // No additional checking needed; aleady checked against NextValue. - - switch (tableLevel) - { - case 0: - { - table0 = (PPH_HANDLE_TABLE_ENTRY)tableValue; - entry = &table0[HandleValue]; - } - break; - case 1: - { - table1 = (PPH_HANDLE_TABLE_ENTRY *)tableValue; - table0 = table1[PH_HANDLE_VALUE_LEVEL1_U(HandleValue)]; - entry = &table0[PH_HANDLE_VALUE_LEVEL0(HandleValue)]; - } - break; - case 2: - { - table2 = (PPH_HANDLE_TABLE_ENTRY **)tableValue; - table1 = table2[PH_HANDLE_VALUE_LEVEL2_U(HandleValue)]; - table0 = table1[PH_HANDLE_VALUE_LEVEL1(HandleValue)]; - entry = &table0[PH_HANDLE_VALUE_LEVEL0(HandleValue)]; - } - break; - default: - ASSUME_NO_DEFAULT; - } - - return entry; -} - -ULONG PhpMoveFreeHandleTableEntries( - _Inout_ PPH_HANDLE_TABLE HandleTable - ) -{ - ULONG freeValueAlt; - ULONG flags; - ULONG i; - ULONG index; - ULONG nextIndex; - ULONG lastIndex; - PPH_HANDLE_TABLE_ENTRY entry; - PPH_HANDLE_TABLE_ENTRY firstEntry; - ULONG count; - ULONG freeValue; - - // Remove all entries from the alt. free list. - freeValueAlt = _InterlockedExchange(&HandleTable->FreeValueAlt, PH_HANDLE_VALUE_INVALID); - - if (freeValueAlt == PH_HANDLE_VALUE_INVALID) - { - // No handles on the alt. free list. - return PH_HANDLE_VALUE_INVALID; - } - - // Avoid the ABA problem by testing all locks (see PhpAllocateHandleTableEntry for details). - // Unlike in PhpFreeHandleTableEntry we have no "alternative" list, so we must allow blocking. - for (i = 0; i < PH_HANDLE_TABLE_LOCKS; i++) - PhAcquireReleaseQueuedLockExclusive(&HandleTable->Locks[i]); - - flags = HandleTable->Flags; - - if (!(flags & PH_HANDLE_TABLE_STRICT_FIFO)) - { - // Shortcut: if there are no entries in the main free list and we don't need to reverse the - // chain, just return. - if (_InterlockedCompareExchange( - &HandleTable->FreeValue, - freeValueAlt, - PH_HANDLE_VALUE_INVALID - ) == PH_HANDLE_VALUE_INVALID) - return freeValueAlt; - } - - // Reverse the chain (even if strict FIFO is off; we have to traverse the list to find the last - // entry, so we might as well reverse it along the way). - - index = freeValueAlt; - lastIndex = PH_HANDLE_VALUE_INVALID; - count = 0; - - while (TRUE) - { - entry = PhpLookupHandleTableEntry(HandleTable, index); - count++; - - if (lastIndex == PH_HANDLE_VALUE_INVALID) - firstEntry = entry; - - nextIndex = entry->NextFreeValue; - entry->NextFreeValue = lastIndex; - lastIndex = index; - - if (nextIndex == PH_HANDLE_VALUE_INVALID) - break; - - index = nextIndex; - } - - // Note that firstEntry actually contains the last free entry, since we reversed the list. - // Similarly index/lastIndex both contain the index of the first free entry. - - // Push the entries onto the free list. - while (TRUE) - { - freeValue = HandleTable->FreeValue; - firstEntry->NextFreeValue = freeValue; - - if (_InterlockedCompareExchange( - &HandleTable->FreeValue, - index, - freeValue - ) == freeValue) - break; - } - - // Force expansion if we don't have enough free handles. - if ( - (flags & PH_HANDLE_TABLE_STRICT_FIFO) && - count < PH_HANDLE_TABLE_FREE_COUNT - ) - { - index = PH_HANDLE_VALUE_INVALID; - } - - return index; -} - -PPH_HANDLE_TABLE_ENTRY PhpCreateHandleTableLevel0( - _In_ PPH_HANDLE_TABLE HandleTable, - _In_ BOOLEAN Initialize - ) -{ - PPH_HANDLE_TABLE_ENTRY table; - PPH_HANDLE_TABLE_ENTRY entry; - ULONG baseValue; - ULONG i; - -#ifdef PH_HANDLE_TABLE_SAFE - __try - { - table = PhAllocateFromFreeList(&PhHandleTableLevel0FreeList); - } - __except (SIMPLE_EXCEPTION_FILTER(GetExceptionCode() == STATUS_NO_MEMORY)) - { - return NULL; - } -#else - table = PhAllocateFromFreeList(&PhHandleTableLevel0FreeList); -#endif - - if (Initialize) - { - entry = &table[0]; - baseValue = HandleTable->NextValue; - - for (i = baseValue + 1; i < baseValue + PH_HANDLE_TABLE_LEVEL_ENTRIES; i++) - { - entry->Value = PH_HANDLE_TABLE_ENTRY_FREE; - entry->NextFreeValue = i; - entry++; - } - - entry->Value = PH_HANDLE_TABLE_ENTRY_FREE; - entry->NextFreeValue = PH_HANDLE_VALUE_INVALID; - } - - return table; -} - -VOID PhpFreeHandleTableLevel0( - _In_ PPH_HANDLE_TABLE_ENTRY Table - ) -{ - PhFreeToFreeList(&PhHandleTableLevel0FreeList, Table); -} - -PPH_HANDLE_TABLE_ENTRY *PhpCreateHandleTableLevel1( - _In_ PPH_HANDLE_TABLE HandleTable - ) -{ - PPH_HANDLE_TABLE_ENTRY *table; - -#ifdef PH_HANDLE_TABLE_SAFE - __try - { - table = PhAllocateFromFreeList(&PhHandleTableLevel1FreeList); - } - __except (SIMPLE_EXCEPTION_FILTER(GetExceptionCode() == STATUS_NO_MEMORY)) - { - return NULL; - } -#else - table = PhAllocateFromFreeList(&PhHandleTableLevel1FreeList); -#endif - - memset(table, 0, sizeof(PPH_HANDLE_TABLE_ENTRY) * PH_HANDLE_TABLE_LEVEL_ENTRIES); - - return table; -} - -VOID PhpFreeHandleTableLevel1( - _In_ PPH_HANDLE_TABLE_ENTRY *Table - ) -{ - PhFreeToFreeList(&PhHandleTableLevel1FreeList, Table); -} - -PPH_HANDLE_TABLE_ENTRY **PhpCreateHandleTableLevel2( - _In_ PPH_HANDLE_TABLE HandleTable - ) -{ - PPH_HANDLE_TABLE_ENTRY **table; - -#ifdef PH_HANDLE_TABLE_SAFE - table = PhAllocateSafe(sizeof(PPH_HANDLE_TABLE_ENTRY *) * PH_HANDLE_TABLE_LEVEL_ENTRIES); - - if (!table) - return NULL; -#else - table = PhAllocate(sizeof(PPH_HANDLE_TABLE_ENTRY *) * PH_HANDLE_TABLE_LEVEL_ENTRIES); -#endif - - memset(table, 0, sizeof(PPH_HANDLE_TABLE_ENTRY *) * PH_HANDLE_TABLE_LEVEL_ENTRIES); - - return table; -} - -VOID PhpFreeHandleTableLevel2( - _In_ PPH_HANDLE_TABLE_ENTRY **Table - ) -{ - PhFree(Table); -} +/* + * Process Hacker - + * handle table + * + * Copyright (C) 2010-2011 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include +#include +#include + +static PH_INITONCE PhHandleTableInitOnce = PH_INITONCE_INIT; +static PH_FREE_LIST PhHandleTableLevel0FreeList; +static PH_FREE_LIST PhHandleTableLevel1FreeList; + +PPH_HANDLE_TABLE PhCreateHandleTable( + VOID + ) +{ + PPH_HANDLE_TABLE handleTable; + ULONG i; + + if (PhBeginInitOnce(&PhHandleTableInitOnce)) + { + PhInitializeFreeList( + &PhHandleTableLevel0FreeList, + sizeof(PH_HANDLE_TABLE_ENTRY) * PH_HANDLE_TABLE_LEVEL_ENTRIES, + 64 + ); + PhInitializeFreeList( + &PhHandleTableLevel1FreeList, + sizeof(PPH_HANDLE_TABLE_ENTRY) * PH_HANDLE_TABLE_LEVEL_ENTRIES, + 64 + ); + PhEndInitOnce(&PhHandleTableInitOnce); + } + +#ifdef PH_HANDLE_TABLE_SAFE + handleTable = PhAllocateSafe(sizeof(PH_HANDLE_TABLE)); + + if (!handleTable) + return NULL; +#else + handleTable = PhAllocate(sizeof(PH_HANDLE_TABLE)); +#endif + + PhInitializeQueuedLock(&handleTable->Lock); + PhInitializeWakeEvent(&handleTable->HandleWakeEvent); + + handleTable->NextValue = 0; + + handleTable->Count = 0; + handleTable->TableValue = (ULONG_PTR)PhpCreateHandleTableLevel0(handleTable, TRUE); + +#ifdef PH_HANDLE_TABLE_SAFE + if (!handleTable->TableValue) + { + PhFree(handleTable); + return NULL; + } +#endif + + // We have now created the level 0 table. The free list can now be set up to point to handle 0, + // which points to the rest of the free list (1 -> 2 -> 3 -> ...). The next batch of handles + // that need to be created start at PH_HANDLE_TABLE_LEVEL_ENTRIES. + + handleTable->FreeValue = 0; + handleTable->NextValue = PH_HANDLE_TABLE_LEVEL_ENTRIES; + + handleTable->FreeValueAlt = PH_HANDLE_VALUE_INVALID; // no entries in alt. free list + + handleTable->Flags = 0; + + for (i = 0; i < PH_HANDLE_TABLE_LOCKS; i++) + PhInitializeQueuedLock(&handleTable->Locks[i]); + + return handleTable; +} + +VOID PhDestroyHandleTable( + _In_ _Post_invalid_ PPH_HANDLE_TABLE HandleTable + ) +{ + ULONG_PTR tableValue; + ULONG tableLevel; + PPH_HANDLE_TABLE_ENTRY table0; + PPH_HANDLE_TABLE_ENTRY *table1; + PPH_HANDLE_TABLE_ENTRY **table2; + ULONG i; + ULONG j; + + tableValue = HandleTable->TableValue; + tableLevel = tableValue & PH_HANDLE_TABLE_LEVEL_MASK; + tableValue -= tableLevel; + + switch (tableLevel) + { + case 0: + { + table0 = (PPH_HANDLE_TABLE_ENTRY)tableValue; + + PhpFreeHandleTableLevel0(table0); + } + break; + case 1: + { + table1 = (PPH_HANDLE_TABLE_ENTRY *)tableValue; + + for (i = 0; i < PH_HANDLE_TABLE_LEVEL_ENTRIES; i++) + { + if (!table1[i]) + break; + + PhpFreeHandleTableLevel0(table1[i]); + } + + PhpFreeHandleTableLevel1(table1); + } + break; + case 2: + { + table2 = (PPH_HANDLE_TABLE_ENTRY **)tableValue; + + for (i = 0; i < PH_HANDLE_TABLE_LEVEL_ENTRIES; i++) + { + if (!table2[i]) + break; + + for (j = 0; j < PH_HANDLE_TABLE_LEVEL_ENTRIES; j++) + { + if (!table2[i][j]) + break; + + PhpFreeHandleTableLevel0(table2[i][j]); + } + + PhpFreeHandleTableLevel1(table2[i]); + } + + PhpFreeHandleTableLevel2(table2); + } + break; + default: + ASSUME_NO_DEFAULT; + } + + PhFree(HandleTable); +} + +VOID PhpBlockOnLockedHandleTableEntry( + _Inout_ PPH_HANDLE_TABLE HandleTable, + _In_ PPH_HANDLE_TABLE_ENTRY HandleTableEntry + ) +{ + PH_QUEUED_WAIT_BLOCK waitBlock; + ULONG_PTR value; + + PhQueueWakeEvent(&HandleTable->HandleWakeEvent, &waitBlock); + + value = HandleTableEntry->Value; + + if ( + (value & PH_HANDLE_TABLE_ENTRY_TYPE) != PH_HANDLE_TABLE_ENTRY_IN_USE || + (value & PH_HANDLE_TABLE_ENTRY_LOCKED) + ) + { + // Entry is not in use or has been unlocked; cancel the wait. + PhSetWakeEvent(&HandleTable->HandleWakeEvent, &waitBlock); + } + else + { + PhWaitForWakeEvent(&HandleTable->HandleWakeEvent, &waitBlock, TRUE, NULL); + } +} + +BOOLEAN PhLockHandleTableEntry( + _Inout_ PPH_HANDLE_TABLE HandleTable, + _Inout_ PPH_HANDLE_TABLE_ENTRY HandleTableEntry + ) +{ + ULONG_PTR value; + + while (TRUE) + { + value = HandleTableEntry->Value; + + if ((value & PH_HANDLE_TABLE_ENTRY_TYPE) != PH_HANDLE_TABLE_ENTRY_IN_USE) + return FALSE; + + if (value & PH_HANDLE_TABLE_ENTRY_LOCKED) + { + if ((ULONG_PTR)_InterlockedCompareExchangePointer( + (PVOID *)&HandleTableEntry->Value, + (PVOID)(value - PH_HANDLE_TABLE_ENTRY_LOCKED), + (PVOID)value + ) == value) + { + return TRUE; + } + } + + PhpBlockOnLockedHandleTableEntry(HandleTable, HandleTableEntry); + } +} + +VOID PhUnlockHandleTableEntry( + _Inout_ PPH_HANDLE_TABLE HandleTable, + _Inout_ PPH_HANDLE_TABLE_ENTRY HandleTableEntry + ) +{ + _interlockedbittestandset( + (PLONG)&HandleTableEntry->Value, + PH_HANDLE_TABLE_ENTRY_LOCKED_SHIFT + ); + PhSetWakeEvent(&HandleTable->HandleWakeEvent, NULL); +} + +HANDLE PhCreateHandle( + _Inout_ PPH_HANDLE_TABLE HandleTable, + _In_ PPH_HANDLE_TABLE_ENTRY HandleTableEntry + ) +{ + PPH_HANDLE_TABLE_ENTRY entry; + ULONG handleValue; + + entry = PhpAllocateHandleTableEntry(HandleTable, &handleValue); + + if (!entry) + return NULL; + + // Copy the given handle table entry to the allocated entry. + + // All free entries have the Free type and have the (not) locked bit clear. There is no problem + // with setting the Type now; the entry is still locked, so they will block. + entry->TypeAndValue.Type = PH_HANDLE_TABLE_ENTRY_IN_USE; + entry->TypeAndValue.Value = HandleTableEntry->TypeAndValue.Value; + entry->Value2 = HandleTableEntry->Value2; + + // Now we unlock this entry, waking anyone who was caught back there before we had finished + // setting up the entry. + PhUnlockHandleTableEntry(HandleTable, entry); + + return PhpEncodeHandle(handleValue); +} + +BOOLEAN PhDestroyHandle( + _Inout_ PPH_HANDLE_TABLE HandleTable, + _In_ HANDLE Handle, + _In_opt_ PPH_HANDLE_TABLE_ENTRY HandleTableEntry + ) +{ + ULONG handleValue; + + handleValue = PhpDecodeHandle(Handle); + + if (!HandleTableEntry) + { + HandleTableEntry = PhpLookupHandleTableEntry(HandleTable, handleValue); + + if (!HandleTableEntry) + return FALSE; + + if (!PhLockHandleTableEntry(HandleTable, HandleTableEntry)) + return FALSE; + } + + _InterlockedExchangePointer( + (PVOID *)&HandleTableEntry->Value, + (PVOID)PH_HANDLE_TABLE_ENTRY_FREE + ); + + // The handle table entry is now free; wake any waiters because they can't lock the entry now. + // Any future lock attempts will fail because the entry is marked as being free. + PhSetWakeEvent(&HandleTable->HandleWakeEvent, NULL); + + PhpFreeHandleTableEntry(HandleTable, handleValue, HandleTableEntry); + + return TRUE; +} + +PPH_HANDLE_TABLE_ENTRY PhLookupHandleTableEntry( + _In_ PPH_HANDLE_TABLE HandleTable, + _In_ HANDLE Handle + ) +{ + PPH_HANDLE_TABLE_ENTRY entry; + + entry = PhpLookupHandleTableEntry(HandleTable, PhpDecodeHandle(Handle)); + + if (!entry) + return NULL; + + if (!PhLockHandleTableEntry(HandleTable, entry)) + return NULL; + + return entry; +} + +VOID PhEnumHandleTable( + _In_ PPH_HANDLE_TABLE HandleTable, + _In_ PPH_ENUM_HANDLE_TABLE_CALLBACK Callback, + _In_opt_ PVOID Context + ) +{ + ULONG handleValue; + PPH_HANDLE_TABLE_ENTRY entry; + BOOLEAN cont; + + handleValue = 0; + + while (entry = PhpLookupHandleTableEntry(HandleTable, handleValue)) + { + if (PhLockHandleTableEntry(HandleTable, entry)) + { + cont = Callback( + HandleTable, + PhpEncodeHandle(handleValue), + entry, + Context + ); + PhUnlockHandleTableEntry(HandleTable, entry); + + if (!cont) + break; + } + + handleValue++; + } +} + +VOID PhSweepHandleTable( + _In_ PPH_HANDLE_TABLE HandleTable, + _In_ PPH_ENUM_HANDLE_TABLE_CALLBACK Callback, + _In_opt_ PVOID Context + ) +{ + ULONG handleValue; + PPH_HANDLE_TABLE_ENTRY entry; + BOOLEAN cont; + + handleValue = 0; + + while (entry = PhpLookupHandleTableEntry(HandleTable, handleValue)) + { + if (entry->TypeAndValue.Type == PH_HANDLE_TABLE_ENTRY_IN_USE) + { + cont = Callback( + HandleTable, + PhpEncodeHandle(handleValue), + entry, + Context + ); + + if (!cont) + break; + } + + handleValue++; + } +} + +NTSTATUS PhQueryInformationHandleTable( + _In_ PPH_HANDLE_TABLE HandleTable, + _In_ PH_HANDLE_TABLE_INFORMATION_CLASS InformationClass, + _Out_writes_bytes_opt_(BufferLength) PVOID Buffer, + _In_ ULONG BufferLength, + _Out_opt_ PULONG ReturnLength + ) +{ + NTSTATUS status = STATUS_SUCCESS; + ULONG returnLength; + + switch (InformationClass) + { + case HandleTableBasicInformation: + { + PPH_HANDLE_TABLE_BASIC_INFORMATION basicInfo = Buffer; + + if (BufferLength == sizeof(PH_HANDLE_TABLE_BASIC_INFORMATION)) + { + basicInfo->Count = HandleTable->Count; + basicInfo->Flags = HandleTable->Flags; + basicInfo->TableLevel = HandleTable->TableValue & PH_HANDLE_TABLE_LEVEL_MASK; + } + else + { + status = STATUS_INFO_LENGTH_MISMATCH; + } + + returnLength = sizeof(PH_HANDLE_TABLE_BASIC_INFORMATION); + } + break; + case HandleTableFlagsInformation: + { + PPH_HANDLE_TABLE_FLAGS_INFORMATION flagsInfo = Buffer; + + if (BufferLength == sizeof(PH_HANDLE_TABLE_FLAGS_INFORMATION)) + { + flagsInfo->Flags = HandleTable->Flags; + } + else + { + status = STATUS_INFO_LENGTH_MISMATCH; + } + + returnLength = sizeof(PH_HANDLE_TABLE_FLAGS_INFORMATION); + } + break; + default: + status = STATUS_INVALID_INFO_CLASS; + returnLength = 0; + break; + } + + if (ReturnLength) + *ReturnLength = returnLength; + + return status; +} + +NTSTATUS PhSetInformationHandleTable( + _Inout_ PPH_HANDLE_TABLE HandleTable, + _In_ PH_HANDLE_TABLE_INFORMATION_CLASS InformationClass, + _In_reads_bytes_(BufferLength) PVOID Buffer, + _In_ ULONG BufferLength + ) +{ + NTSTATUS status = STATUS_SUCCESS; + + switch (InformationClass) + { + case HandleTableFlagsInformation: + { + PPH_HANDLE_TABLE_FLAGS_INFORMATION flagsInfo = Buffer; + ULONG flags; + + if (BufferLength == sizeof(PH_HANDLE_TABLE_FLAGS_INFORMATION)) + { + flags = flagsInfo->Flags; + + if ((flags & PH_HANDLE_TABLE_VALID_FLAGS) == flags) + HandleTable->Flags = flags; + else + status = STATUS_INVALID_PARAMETER; + } + else + { + status = STATUS_INFO_LENGTH_MISMATCH; + } + } + break; + default: + status = STATUS_INVALID_INFO_CLASS; + } + + return status; +} + +PPH_HANDLE_TABLE_ENTRY PhpAllocateHandleTableEntry( + _Inout_ PPH_HANDLE_TABLE HandleTable, + _Out_ PULONG HandleValue + ) +{ + PPH_HANDLE_TABLE_ENTRY entry; + ULONG freeValue; + ULONG lockIndex; + ULONG nextFreeValue; + ULONG oldFreeValue; + BOOLEAN result; + + while (TRUE) + { + freeValue = HandleTable->FreeValue; + + while (freeValue == PH_HANDLE_VALUE_INVALID) + { + PhAcquireQueuedLockExclusive(&HandleTable->Lock); + + // Check again to see if we have free handles. + + freeValue = HandleTable->FreeValue; + + if (freeValue != PH_HANDLE_VALUE_INVALID) + { + PhReleaseQueuedLockExclusive(&HandleTable->Lock); + break; + } + + // Move handles from the alt. free list to the main free list, and check again. + + freeValue = PhpMoveFreeHandleTableEntries(HandleTable); + + if (freeValue != PH_HANDLE_VALUE_INVALID) + { + PhReleaseQueuedLockExclusive(&HandleTable->Lock); + break; + } + + result = PhpAllocateMoreHandleTableEntries(HandleTable, TRUE); + + PhReleaseQueuedLockExclusive(&HandleTable->Lock); + + freeValue = HandleTable->FreeValue; + + // Note that PhpAllocateMoreHandleTableEntries only returns FALSE if it failed to + // allocate memory. Success does not guarantee a free handle to be allocated, as they + // may have been all used up (however unlikely) when we reach this point. Success simply + // means to retry the allocation using the fast path. + + if (!result && freeValue == PH_HANDLE_VALUE_INVALID) + return NULL; + } + + entry = PhpLookupHandleTableEntry(HandleTable, freeValue); + lockIndex = PH_HANDLE_TABLE_LOCK_INDEX(freeValue); + + // To avoid the ABA problem, we would ideally have one queued lock per handle table entry. + // That would make the overhead too large, so instead there is a fixed number of locks, + // indexed by the handle value (mod no. locks). + + // Possibilities at this point: + // 1. freeValue != A (our copy), but the other thread has freed A, so FreeValue = A. No ABA + // problem since freeValue != A. + // 2. freeValue != A, and FreeValue != A. No ABA problem. + // 3. freeValue = A, and the other thread has freed A, so FreeValue = A. No ABA problem + // since we haven't read NextFreeValue yet. + // 4. freeValue = A, and FreeValue != A. No problem if this stays the same later, as the CAS + // will take care of it. + + PhpLockHandleTableShared(HandleTable, lockIndex); + + if (HandleTable->FreeValue != freeValue) + { + PhpUnlockHandleTableShared(HandleTable, lockIndex); + continue; + } + + MemoryBarrier(); + + nextFreeValue = entry->NextFreeValue; + + // Possibilities/non-possibilities at this point: + // 1. freeValue != A (our copy), but the other thread has freed A, so FreeValue = A. This is + // actually impossible since we have acquired the lock on A and the free code checks that + // and uses the alt. free list instead. + // 2. freeValue != A, and FreeValue != A. No ABA problem. + // 3. freeValue = A, and the other thread has freed A, so FreeValue = A. Impossible like + // above. This is *the* ABA problem which we have now prevented. + // 4. freeValue = A, and FreeValue != A. CAS will take care of it. + + oldFreeValue = _InterlockedCompareExchange( + &HandleTable->FreeValue, + nextFreeValue, + freeValue + ); + + PhpUnlockHandleTableShared(HandleTable, lockIndex); + + if (oldFreeValue == freeValue) + break; + } + + _InterlockedIncrement((PLONG)&HandleTable->Count); + + *HandleValue = freeValue; + + return entry; +} + +VOID PhpFreeHandleTableEntry( + _Inout_ PPH_HANDLE_TABLE HandleTable, + _In_ ULONG HandleValue, + _Inout_ PPH_HANDLE_TABLE_ENTRY HandleTableEntry + ) +{ + PULONG freeList; + ULONG flags; + ULONG oldValue; + + _InterlockedDecrement((PLONG)&HandleTable->Count); + + flags = HandleTable->Flags; + + // Choose the free list to use depending on whether someone is popping from the main free list + // (see PhpAllocateHandleTableEntry for details). We always use the alt. free list if strict + // FIFO is enabled. + if (!(flags & PH_HANDLE_TABLE_STRICT_FIFO) && + PhTryAcquireReleaseQueuedLockExclusive( + &HandleTable->Locks[PH_HANDLE_TABLE_LOCK_INDEX(HandleValue)])) + { + freeList = &HandleTable->FreeValue; + } + else + { + freeList = &HandleTable->FreeValueAlt; + } + + while (TRUE) + { + oldValue = *freeList; + HandleTableEntry->NextFreeValue = oldValue; + + if (_InterlockedCompareExchange( + freeList, + HandleValue, + oldValue + ) == oldValue) + { + break; + } + } +} + +BOOLEAN PhpAllocateMoreHandleTableEntries( + _In_ PPH_HANDLE_TABLE HandleTable, + _In_ BOOLEAN Initialize + ) +{ + ULONG_PTR tableValue; + ULONG tableLevel; + PPH_HANDLE_TABLE_ENTRY table0; + PPH_HANDLE_TABLE_ENTRY *table1; + PPH_HANDLE_TABLE_ENTRY **table2; + ULONG i; + ULONG j; + ULONG oldNextValue; + ULONG freeValue; + + // Get a pointer to the table, and its level. + + tableValue = HandleTable->TableValue; + tableLevel = tableValue & PH_HANDLE_TABLE_LEVEL_MASK; + tableValue -= tableLevel; + + switch (tableLevel) + { + case 0: + { + // Create a level 1 table. + + table1 = PhpCreateHandleTableLevel1(HandleTable); + +#ifdef PH_HANDLE_TABLE_SAFE + if (!table1) + return FALSE; +#endif + + // Create a new level 0 table and move the existing level into the new level 1 table. + + table0 = PhpCreateHandleTableLevel0(HandleTable, Initialize); + +#ifdef PH_HANDLE_TABLE_SAFE + if (!table0) + { + PhpFreeHandleTableLevel1(table1); + return FALSE; + } +#endif + + table1[0] = (PPH_HANDLE_TABLE_ENTRY)tableValue; + table1[1] = table0; + + tableValue = (ULONG_PTR)table1 | 1; + //_InterlockedExchangePointer((PVOID *)&HandleTable->TableValue, (PVOID)tableValue); + HandleTable->TableValue = tableValue; + } + break; + case 1: + { + table1 = (PPH_HANDLE_TABLE_ENTRY *)tableValue; + + // Determine whether we need to create a new level 0 table or create a level 2 table. + + i = HandleTable->NextValue / PH_HANDLE_TABLE_LEVEL_ENTRIES; + + if (i < PH_HANDLE_TABLE_LEVEL_ENTRIES) + { + table0 = PhpCreateHandleTableLevel0(HandleTable, TRUE); + +#ifdef PH_HANDLE_TABLE_SAFE + if (!table0) + return FALSE; +#endif + + //_InterlockedExchangePointer((PVOID *)&table1[i], table0); + table1[i] = table0; + } + else + { + // Create a level 2 table. + + table2 = PhpCreateHandleTableLevel2(HandleTable); + +#ifdef PH_HANDLE_TABLE_SAFE + if (!table2) + return FALSE; +#endif + + // Create a new level 1 table and move the existing level into the new level 2 + // table. + + table1 = PhpCreateHandleTableLevel1(HandleTable); + +#ifdef PH_HANDLE_TABLE_SAFE + if (!table1) + { + PhpFreeHandleTableLevel2(table2); + return FALSE; + } +#endif + + table0 = PhpCreateHandleTableLevel0(HandleTable, Initialize); + +#ifdef PH_HANDLE_TABLE_SAFE + if (!table0) + { + PhpFreeHandleTableLevel1(table1); + PhpFreeHandleTableLevel2(table2); + return FALSE; + } +#endif + + table1[0] = table0; + + table2[0] = (PPH_HANDLE_TABLE_ENTRY *)tableValue; + table2[1] = table1; + + tableValue = (ULONG_PTR)table2 | 2; + //_InterlockedExchangePointer((PVOID *)&HandleTable->TableValue, (PVOID)tableValue); + HandleTable->TableValue = tableValue; + } + } + break; + case 2: + { + table2 = (PPH_HANDLE_TABLE_ENTRY **)tableValue; + + i = HandleTable->NextValue / + (PH_HANDLE_TABLE_LEVEL_ENTRIES * PH_HANDLE_TABLE_LEVEL_ENTRIES); + // i contains an index into the level 2 table, of the containing level 1 table. + + // Check if we have exceeded the maximum number of handles. + + if (i >= PH_HANDLE_TABLE_LEVEL_ENTRIES) + return FALSE; + + // Check if we should create a new level 0 table or a new level 2 table. + if (table2[i]) + { + table0 = PhpCreateHandleTableLevel0(HandleTable, Initialize); + +#ifdef PH_HANDLE_TABLE_SAFE + if (!table0) + return FALSE; +#endif + + // Same as j = HandleTable->NextValue % (no. entries * no. entries), but we already + // calculated i so just use it. + j = HandleTable->NextValue - i * + (PH_HANDLE_TABLE_LEVEL_ENTRIES * PH_HANDLE_TABLE_LEVEL_ENTRIES); + j /= PH_HANDLE_TABLE_LEVEL_ENTRIES; + // j now contains an index into the level 1 table, of the containing level 0 table + // (the one which was created). + + //_InterlockedExchangePointer((PVOID *)&table2[i][j], table0); + table2[i][j] = table0; + } + else + { + table1 = PhpCreateHandleTableLevel1(HandleTable); + +#ifdef PH_HANDLE_TABLE_SAFE + if (!table1) + return FALSE; +#endif + + table0 = PhpCreateHandleTableLevel0(HandleTable, TRUE); + +#ifdef PH_HANDLE_TABLE_SAFE + if (!table0) + { + PhpFreeHandleTableLevel1(table1); + return FALSE; + } +#endif + + table1[0] = table0; + + //_InterlockedExchangePointer((PVOID *)&table2[i], table1); + table2[i] = table1; + } + } + break; + default: + ASSUME_NO_DEFAULT; + } + + // In each of the cases above, we allocated one additional level 0 table. + oldNextValue = _InterlockedExchangeAdd( + (PLONG)&HandleTable->NextValue, + PH_HANDLE_TABLE_LEVEL_ENTRIES + ); + + if (Initialize) + { + // No ABA problem since these are new handles being pushed. + + while (TRUE) + { + freeValue = HandleTable->FreeValue; + table0[PH_HANDLE_TABLE_LEVEL_ENTRIES - 1].NextFreeValue = freeValue; + + if (_InterlockedCompareExchange( + &HandleTable->FreeValue, + oldNextValue, + freeValue + ) == freeValue) + { + break; + } + } + } + + return TRUE; +} + +PPH_HANDLE_TABLE_ENTRY PhpLookupHandleTableEntry( + _In_ PPH_HANDLE_TABLE HandleTable, + _In_ ULONG HandleValue + ) +{ + ULONG_PTR tableValue; + ULONG tableLevel; + PPH_HANDLE_TABLE_ENTRY table0; + PPH_HANDLE_TABLE_ENTRY *table1; + PPH_HANDLE_TABLE_ENTRY **table2; + PPH_HANDLE_TABLE_ENTRY entry; + + if (HandleValue >= HandleTable->NextValue) + return NULL; + + // Get a pointer to the table, and its level. + + tableValue = HandleTable->TableValue; + tableLevel = tableValue & PH_HANDLE_TABLE_LEVEL_MASK; + tableValue -= tableLevel; + + // No additional checking needed; aleady checked against NextValue. + + switch (tableLevel) + { + case 0: + { + table0 = (PPH_HANDLE_TABLE_ENTRY)tableValue; + entry = &table0[HandleValue]; + } + break; + case 1: + { + table1 = (PPH_HANDLE_TABLE_ENTRY *)tableValue; + table0 = table1[PH_HANDLE_VALUE_LEVEL1_U(HandleValue)]; + entry = &table0[PH_HANDLE_VALUE_LEVEL0(HandleValue)]; + } + break; + case 2: + { + table2 = (PPH_HANDLE_TABLE_ENTRY **)tableValue; + table1 = table2[PH_HANDLE_VALUE_LEVEL2_U(HandleValue)]; + table0 = table1[PH_HANDLE_VALUE_LEVEL1(HandleValue)]; + entry = &table0[PH_HANDLE_VALUE_LEVEL0(HandleValue)]; + } + break; + default: + ASSUME_NO_DEFAULT; + } + + return entry; +} + +ULONG PhpMoveFreeHandleTableEntries( + _Inout_ PPH_HANDLE_TABLE HandleTable + ) +{ + ULONG freeValueAlt; + ULONG flags; + ULONG i; + ULONG index; + ULONG nextIndex; + ULONG lastIndex; + PPH_HANDLE_TABLE_ENTRY entry; + PPH_HANDLE_TABLE_ENTRY firstEntry; + ULONG count; + ULONG freeValue; + + // Remove all entries from the alt. free list. + freeValueAlt = _InterlockedExchange(&HandleTable->FreeValueAlt, PH_HANDLE_VALUE_INVALID); + + if (freeValueAlt == PH_HANDLE_VALUE_INVALID) + { + // No handles on the alt. free list. + return PH_HANDLE_VALUE_INVALID; + } + + // Avoid the ABA problem by testing all locks (see PhpAllocateHandleTableEntry for details). + // Unlike in PhpFreeHandleTableEntry we have no "alternative" list, so we must allow blocking. + for (i = 0; i < PH_HANDLE_TABLE_LOCKS; i++) + PhAcquireReleaseQueuedLockExclusive(&HandleTable->Locks[i]); + + flags = HandleTable->Flags; + + if (!(flags & PH_HANDLE_TABLE_STRICT_FIFO)) + { + // Shortcut: if there are no entries in the main free list and we don't need to reverse the + // chain, just return. + if (_InterlockedCompareExchange( + &HandleTable->FreeValue, + freeValueAlt, + PH_HANDLE_VALUE_INVALID + ) == PH_HANDLE_VALUE_INVALID) + return freeValueAlt; + } + + // Reverse the chain (even if strict FIFO is off; we have to traverse the list to find the last + // entry, so we might as well reverse it along the way). + + index = freeValueAlt; + lastIndex = PH_HANDLE_VALUE_INVALID; + count = 0; + + while (TRUE) + { + entry = PhpLookupHandleTableEntry(HandleTable, index); + count++; + + if (lastIndex == PH_HANDLE_VALUE_INVALID) + firstEntry = entry; + + nextIndex = entry->NextFreeValue; + entry->NextFreeValue = lastIndex; + lastIndex = index; + + if (nextIndex == PH_HANDLE_VALUE_INVALID) + break; + + index = nextIndex; + } + + // Note that firstEntry actually contains the last free entry, since we reversed the list. + // Similarly index/lastIndex both contain the index of the first free entry. + + // Push the entries onto the free list. + while (TRUE) + { + freeValue = HandleTable->FreeValue; + firstEntry->NextFreeValue = freeValue; + + if (_InterlockedCompareExchange( + &HandleTable->FreeValue, + index, + freeValue + ) == freeValue) + break; + } + + // Force expansion if we don't have enough free handles. + if ( + (flags & PH_HANDLE_TABLE_STRICT_FIFO) && + count < PH_HANDLE_TABLE_FREE_COUNT + ) + { + index = PH_HANDLE_VALUE_INVALID; + } + + return index; +} + +PPH_HANDLE_TABLE_ENTRY PhpCreateHandleTableLevel0( + _In_ PPH_HANDLE_TABLE HandleTable, + _In_ BOOLEAN Initialize + ) +{ + PPH_HANDLE_TABLE_ENTRY table; + PPH_HANDLE_TABLE_ENTRY entry; + ULONG baseValue; + ULONG i; + +#ifdef PH_HANDLE_TABLE_SAFE + __try + { + table = PhAllocateFromFreeList(&PhHandleTableLevel0FreeList); + } + __except (SIMPLE_EXCEPTION_FILTER(GetExceptionCode() == STATUS_NO_MEMORY)) + { + return NULL; + } +#else + table = PhAllocateFromFreeList(&PhHandleTableLevel0FreeList); +#endif + + if (Initialize) + { + entry = &table[0]; + baseValue = HandleTable->NextValue; + + for (i = baseValue + 1; i < baseValue + PH_HANDLE_TABLE_LEVEL_ENTRIES; i++) + { + entry->Value = PH_HANDLE_TABLE_ENTRY_FREE; + entry->NextFreeValue = i; + entry++; + } + + entry->Value = PH_HANDLE_TABLE_ENTRY_FREE; + entry->NextFreeValue = PH_HANDLE_VALUE_INVALID; + } + + return table; +} + +VOID PhpFreeHandleTableLevel0( + _In_ PPH_HANDLE_TABLE_ENTRY Table + ) +{ + PhFreeToFreeList(&PhHandleTableLevel0FreeList, Table); +} + +PPH_HANDLE_TABLE_ENTRY *PhpCreateHandleTableLevel1( + _In_ PPH_HANDLE_TABLE HandleTable + ) +{ + PPH_HANDLE_TABLE_ENTRY *table; + +#ifdef PH_HANDLE_TABLE_SAFE + __try + { + table = PhAllocateFromFreeList(&PhHandleTableLevel1FreeList); + } + __except (SIMPLE_EXCEPTION_FILTER(GetExceptionCode() == STATUS_NO_MEMORY)) + { + return NULL; + } +#else + table = PhAllocateFromFreeList(&PhHandleTableLevel1FreeList); +#endif + + memset(table, 0, sizeof(PPH_HANDLE_TABLE_ENTRY) * PH_HANDLE_TABLE_LEVEL_ENTRIES); + + return table; +} + +VOID PhpFreeHandleTableLevel1( + _In_ PPH_HANDLE_TABLE_ENTRY *Table + ) +{ + PhFreeToFreeList(&PhHandleTableLevel1FreeList, Table); +} + +PPH_HANDLE_TABLE_ENTRY **PhpCreateHandleTableLevel2( + _In_ PPH_HANDLE_TABLE HandleTable + ) +{ + PPH_HANDLE_TABLE_ENTRY **table; + +#ifdef PH_HANDLE_TABLE_SAFE + table = PhAllocateSafe(sizeof(PPH_HANDLE_TABLE_ENTRY *) * PH_HANDLE_TABLE_LEVEL_ENTRIES); + + if (!table) + return NULL; +#else + table = PhAllocate(sizeof(PPH_HANDLE_TABLE_ENTRY *) * PH_HANDLE_TABLE_LEVEL_ENTRIES); +#endif + + memset(table, 0, sizeof(PPH_HANDLE_TABLE_ENTRY *) * PH_HANDLE_TABLE_LEVEL_ENTRIES); + + return table; +} + +VOID PhpFreeHandleTableLevel2( + _In_ PPH_HANDLE_TABLE_ENTRY **Table + ) +{ + PhFree(Table); +} diff --git a/phlib/hexedit.c b/phlib/hexedit.c index 2dea6c9f4a7b..edd89248995d 100644 --- a/phlib/hexedit.c +++ b/phlib/hexedit.c @@ -1,1868 +1,1868 @@ -/* - * Process Hacker - - * hex editor control - * - * Copyright (C) 2010-2015 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include -#include - -#include - -#include - -// Code originally from http://www.codeguru.com/Cpp/controls/editctrl/article.php/c539 - -BOOLEAN PhHexEditInitialization( - VOID - ) -{ - WNDCLASSEX c = { sizeof(c) }; - - c.style = CS_GLOBALCLASS; - c.lpfnWndProc = PhpHexEditWndProc; - c.cbClsExtra = 0; - c.cbWndExtra = sizeof(PVOID); - c.hInstance = PhLibImageBase; - c.hIcon = NULL; - c.hCursor = LoadCursor(NULL, IDC_ARROW); - c.hbrBackground = NULL; - c.lpszMenuName = NULL; - c.lpszClassName = PH_HEXEDIT_CLASSNAME; - c.hIconSm = NULL; - - if (!RegisterClassEx(&c)) - return FALSE; - - return TRUE; -} - -VOID PhpCreateHexEditContext( - _Out_ PPHP_HEXEDIT_CONTEXT *Context - ) -{ - PPHP_HEXEDIT_CONTEXT context; - - context = PhAllocate(sizeof(PHP_HEXEDIT_CONTEXT)); - memset(context, 0, sizeof(PHP_HEXEDIT_CONTEXT)); // important, set NullWidth to 0 - - context->Data = NULL; - context->Length = 0; - context->TopIndex = 0; - context->BytesPerRow = 16; - context->LinesPerPage = 1; - - context->ShowHex = TRUE; - context->ShowAscii = TRUE; - context->ShowAddress = TRUE; - context->AddressIsWide = TRUE; - context->AllowLengthChange = FALSE; - - context->AddressOffset = 0; - context->HexOffset = 0; - context->AsciiOffset = 0; - - context->Update = TRUE; - context->NoAddressChange = FALSE; - context->CurrentMode = EDIT_NONE; - - context->EditPosition.x = 0; - context->EditPosition.y = 0; - context->CurrentAddress = 0; - context->HalfPage = TRUE; - - context->SelStart = -1; - context->SelEnd = -1; - - *Context = context; -} - -VOID PhpFreeHexEditContext( - _In_ _Post_invalid_ PPHP_HEXEDIT_CONTEXT Context - ) -{ - if (!Context->UserBuffer && Context->Data) PhFree(Context->Data); - if (Context->CharBuffer) PhFree(Context->CharBuffer); - if (Context->Font) DeleteObject(Context->Font); - PhFree(Context); -} - -LRESULT CALLBACK PhpHexEditWndProc( - _In_ HWND hwnd, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - PPHP_HEXEDIT_CONTEXT context; - - context = (PPHP_HEXEDIT_CONTEXT)GetWindowLongPtr(hwnd, 0); - - if (uMsg == WM_CREATE) - { - PhpCreateHexEditContext(&context); - SetWindowLongPtr(hwnd, 0, (LONG_PTR)context); - } - - if (!context) - return DefWindowProc(hwnd, uMsg, wParam, lParam); - - switch (uMsg) - { - case WM_CREATE: - { - context->Font = CreateFont(-(LONG)PhMultiplyDivide(12, PhGlobalDpi, 96), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, L"Courier New"); - } - break; - case WM_DESTROY: - { - SetWindowLongPtr(hwnd, 0, (LONG_PTR)NULL); - PhpFreeHexEditContext(context); - } - break; - case WM_PAINT: - { - PAINTSTRUCT paintStruct; - HDC hdc; - - if (hdc = BeginPaint(hwnd, &paintStruct)) - { - PhpHexEditOnPaint(hwnd, context, &paintStruct, hdc); - EndPaint(hwnd, &paintStruct); - } - } - break; - case WM_SIZE: - { - PhpHexEditUpdateMetrics(hwnd, context, FALSE, NULL); - } - break; - case WM_SETFOCUS: - { - if (context->Data && !PhpHexEditHasSelected(context)) - { - if (context->EditPosition.x == 0 && context->ShowAddress) - PhpHexEditCreateAddressCaret(hwnd, context); - else - PhpHexEditCreateEditCaret(hwnd, context); - - SetCaretPos(context->EditPosition.x, context->EditPosition.y); - ShowCaret(hwnd); - } - } - break; - case WM_KILLFOCUS: - { - DestroyCaret(); - } - break; - case WM_VSCROLL: - { - SHORT scrollRequest = LOWORD(wParam); - LONG currentPosition; - LONG originalTopIndex; - SCROLLINFO scrollInfo = { sizeof(scrollInfo) }; - - originalTopIndex = context->TopIndex; - - scrollInfo.fMask = SIF_TRACKPOS; - GetScrollInfo(hwnd, SB_VERT, &scrollInfo); - currentPosition = scrollInfo.nTrackPos; - - if (context->Data) - { - LONG mult; - - mult = context->LinesPerPage * context->BytesPerRow; - - switch (scrollRequest) - { - case SB_LINEDOWN: - if (context->TopIndex < context->Length - mult) - { - context->TopIndex += context->BytesPerRow; - REDRAW_WINDOW(hwnd); - } - break; - case SB_LINEUP: - if (context->TopIndex >= context->BytesPerRow) - { - context->TopIndex -= context->BytesPerRow; - REDRAW_WINDOW(hwnd); - } - break; - case SB_PAGEDOWN: - if (context->TopIndex < context->Length - mult) - { - context->TopIndex += mult; - - if (context->TopIndex > context->Length - mult) - context->TopIndex = context->Length - mult; - - REDRAW_WINDOW(hwnd); - } - break; - case SB_PAGEUP: - if (context->TopIndex > 0) - { - context->TopIndex -= mult; - - if (context->TopIndex < 0) - context->TopIndex = 0; - - REDRAW_WINDOW(hwnd); - } - break; - case SB_THUMBTRACK: - context->TopIndex = currentPosition * context->BytesPerRow; - REDRAW_WINDOW(hwnd); - break; - } - - SetScrollPos(hwnd, SB_VERT, context->TopIndex / context->BytesPerRow, TRUE); - - if (!context->NoAddressChange && FALSE) // this behaviour sucks, so just leave it out - context->CurrentAddress += context->TopIndex - originalTopIndex; - - PhpHexEditRepositionCaret(hwnd, context, context->CurrentAddress); - } - } - break; - case WM_MOUSEWHEEL: - { - SHORT wheelDelta = GET_WHEEL_DELTA_WPARAM(wParam); - - if (context->Data) - { - ULONG wheelScrollLines; - - if (!SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &wheelScrollLines, 0)) - wheelScrollLines = 3; - - context->TopIndex += context->BytesPerRow * (LONG)wheelScrollLines * -wheelDelta / WHEEL_DELTA; - - if (context->TopIndex < 0) - context->TopIndex = 0; - - if (context->Length >= context->LinesPerPage * context->BytesPerRow) - { - if (context->TopIndex > context->Length - context->LinesPerPage * context->BytesPerRow) - context->TopIndex = context->Length - context->LinesPerPage * context->BytesPerRow; - } - - REDRAW_WINDOW(hwnd); - - SetScrollPos(hwnd, SB_VERT, context->TopIndex / context->BytesPerRow, TRUE); - - PhpHexEditRepositionCaret(hwnd, context, context->CurrentAddress); - } - } - break; - case WM_GETDLGCODE: - if (wParam != VK_ESCAPE) - return DLGC_WANTALLKEYS; - break; - case WM_ERASEBKGND: - return 1; - case WM_LBUTTONDOWN: - { - ULONG flags = (ULONG)wParam; - POINT cursorPos; - - cursorPos.x = (LONG)(SHORT)LOWORD(lParam); - cursorPos.y = (LONG)(SHORT)HIWORD(lParam); - - SetFocus(hwnd); - - if (context->Data) - { - POINT point; - - if (wParam & MK_SHIFT) - context->SelStart = context->CurrentAddress; - - PhpHexEditCalculatePosition(hwnd, context, cursorPos.x, cursorPos.y, &point); - - if (point.x > -1) - { - context->EditPosition = point; - - point.x *= context->NullWidth; - point.y *= context->LineHeight; - - if (point.x == 0 && context->ShowAddress) - PhpHexEditCreateAddressCaret(hwnd, context); - else - PhpHexEditCreateEditCaret(hwnd, context); - - SetCaretPos(point.x, point.y); - - if (flags & MK_SHIFT) - { - context->SelEnd = context->CurrentAddress; - - if (context->CurrentMode == EDIT_HIGH || context->CurrentMode == EDIT_LOW) - context->SelEnd++; - - REDRAW_WINDOW(hwnd); - } - } - - if (!(flags & MK_SHIFT)) - { - if (DragDetect(hwnd, cursorPos)) - { - context->SelStart = context->CurrentAddress; - context->SelEnd = context->SelStart; - SetCapture(hwnd); - context->HasCapture = TRUE; - } - else - { - BOOLEAN selected; - - selected = context->SelStart != -1; - context->SelStart = -1; - context->SelEnd = -1; - - if (selected) - REDRAW_WINDOW(hwnd); - } - } - - if (!PhpHexEditHasSelected(context)) - ShowCaret(hwnd); - } - } - break; - case WM_LBUTTONUP: - { - if (context->HasCapture && PhpHexEditHasSelected(context)) - ReleaseCapture(); - - context->HasCapture = FALSE; - } - break; - case WM_MOUSEMOVE: - { - ULONG flags = (ULONG)wParam; - POINT cursorPos; - - cursorPos.x = (LONG)(SHORT)LOWORD(lParam); - cursorPos.y = (LONG)(SHORT)HIWORD(lParam); - - if ( - context->Data && - context->HasCapture && - context->SelStart != -1 - ) - { - RECT rect; - POINT point; - ULONG oldSelEnd; - - // User is dragging. - - GetClientRect(hwnd, &rect); - - if (!PtInRect(&rect, cursorPos)) - { - if (cursorPos.y < 0) - { - SendMessage(hwnd, WM_VSCROLL, SB_LINEUP, 0); - cursorPos.y = 0; - } - else if (cursorPos.y > rect.bottom) - { - SendMessage(hwnd, WM_VSCROLL, SB_LINEDOWN, 0); - cursorPos.y = rect.bottom - 1; - } - } - - oldSelEnd = context->SelEnd; - PhpHexEditCalculatePosition(hwnd, context, cursorPos.x, cursorPos.y, &point); - - if (point.x > -1) - { - context->SelEnd = context->CurrentAddress; - - if (context->CurrentMode == EDIT_HIGH || context->CurrentMode == EDIT_LOW) - context->SelEnd++; - } - - if (PhpHexEditHasSelected(context)) - DestroyCaret(); - - if (context->SelEnd != oldSelEnd) - REDRAW_WINDOW(hwnd); - } - } - break; - case WM_CHAR: - { - ULONG c = (ULONG)wParam; - - if (!context->Data) - goto DefaultHandler; - if (c == '\t') - goto DefaultHandler; - - if (GetKeyState(VK_CONTROL) < 0) - { - switch (c) - { - case 0x3: - if (PhpHexEditHasSelected(context)) - PhpHexEditCopyEdit(hwnd, context); - goto DefaultHandler; - case 0x16: - PhpHexEditPasteEdit(hwnd, context); - goto DefaultHandler; - case 0x18: - if (PhpHexEditHasSelected(context)) - PhpHexEditCutEdit(hwnd, context); - goto DefaultHandler; - case 0x1a: - PhpHexEditUndoEdit(hwnd, context); - goto DefaultHandler; - } - } - - // Disallow editing beyond the end of the data. - if (context->CurrentAddress >= context->Length) - goto DefaultHandler; - - if (c == 0x8) - { - if (context->CurrentAddress != 0) - { - context->CurrentAddress--; - PhpHexEditSelDelete(hwnd, context, context->CurrentAddress, context->CurrentAddress + 1); - PhpHexEditRepositionCaret(hwnd, context, context->CurrentAddress); - REDRAW_WINDOW(hwnd); - } - - goto DefaultHandler; - } - - PhpHexEditSetSel(hwnd, context, -1, -1); - - switch (context->CurrentMode) - { - case EDIT_NONE: - goto DefaultHandler; - case EDIT_HIGH: - case EDIT_LOW: - if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f')) - { - ULONG b = c - '0'; - - if (b > 9) - b = 10 + c - 'a'; - - if (context->CurrentMode == EDIT_HIGH) - { - context->Data[context->CurrentAddress] = - (UCHAR)((context->Data[context->CurrentAddress] & 0x0f) | (b << 4)); - } - else - { - context->Data[context->CurrentAddress] = - (UCHAR)((context->Data[context->CurrentAddress] & 0xf0) | b); - } - - PhpHexEditMove(hwnd, context, 1, 0); - } - break; - case EDIT_ASCII: - context->Data[context->CurrentAddress] = (UCHAR)c; - PhpHexEditMove(hwnd, context, 1, 0); - break; - } - - REDRAW_WINDOW(hwnd); - } - break; - case WM_KEYDOWN: - { - ULONG vk = (ULONG)wParam; - BOOLEAN shift = GetKeyState(VK_SHIFT) < 0; - BOOLEAN oldNoAddressChange = context->NoAddressChange; - BOOLEAN noScrollIntoView = FALSE; - - context->NoAddressChange = TRUE; - - switch (vk) - { - case VK_DOWN: - if (context->CurrentMode != EDIT_NONE) - { - if (shift) - { - if (!PhpHexEditHasSelected(context)) - context->SelStart = context->CurrentAddress; - - PhpHexEditMove(hwnd, context, 0, 1); - context->SelEnd = context->CurrentAddress; - - if (context->CurrentMode == EDIT_HIGH || context->CurrentMode == EDIT_LOW) - context->SelEnd++; - - REDRAW_WINDOW(hwnd); - break; - } - else - { - PhpHexEditSetSel(hwnd, context, -1, -1); - } - - PhpHexEditMove(hwnd, context, 0, 1); - noScrollIntoView = TRUE; - } - else - { - PhpHexEditMove(hwnd, context, 0, 1); - } - break; - case VK_UP: - if (context->CurrentMode != EDIT_NONE) - { - if (shift) - { - if (!PhpHexEditHasSelected(context)) - context->SelStart = context->CurrentAddress; - - PhpHexEditMove(hwnd, context, 0, -1); - context->SelEnd = context->CurrentAddress; - - REDRAW_WINDOW(hwnd); - break; - } - else - { - PhpHexEditSetSel(hwnd, context, -1, -1); - } - - PhpHexEditMove(hwnd, context, 0, -1); - noScrollIntoView = TRUE; - } - else - { - PhpHexEditMove(hwnd, context, 0, -1); - } - break; - case VK_LEFT: - if (context->CurrentMode != EDIT_NONE) - { - if (shift) - { - if (!PhpHexEditHasSelected(context)) - context->SelStart = context->CurrentAddress; - - PhpHexEditMove(hwnd, context, -1, 0); - context->SelEnd = context->CurrentAddress; - - REDRAW_WINDOW(hwnd); - break; - } - else - { - PhpHexEditSetSel(hwnd, context, -1, -1); - } - - PhpHexEditMove(hwnd, context, -1, 0); - noScrollIntoView = TRUE; - } - break; - case VK_RIGHT: - if (context->CurrentMode != EDIT_NONE) - { - if (shift) - { - if (!PhpHexEditHasSelected(context)) - context->SelStart = context->CurrentAddress; - - PhpHexEditMove(hwnd, context, 1, 0); - context->SelEnd = context->CurrentAddress; - - if (context->CurrentMode == EDIT_HIGH || context->CurrentMode == EDIT_LOW) - context->SelEnd++; - - REDRAW_WINDOW(hwnd); - break; - } - else - { - PhpHexEditSetSel(hwnd, context, -1, -1); - } - - PhpHexEditMove(hwnd, context, 1, 0); - noScrollIntoView = TRUE; - } - break; - case VK_PRIOR: - if (shift) - { - if (!PhpHexEditHasSelected(context)) - context->SelStart = context->CurrentAddress; - - SendMessage(hwnd, WM_VSCROLL, SB_PAGEUP, 0); - PhpHexEditMove(hwnd, context, 0, 0); - context->SelEnd = context->CurrentAddress; - - REDRAW_WINDOW(hwnd); - break; - } - else - { - PhpHexEditSetSel(hwnd, context, -1, -1); - } - - SendMessage(hwnd, WM_VSCROLL, SB_PAGEUP, 0); - PhpHexEditMove(hwnd, context, 0, 0); - noScrollIntoView = TRUE; - break; - case VK_NEXT: - if (shift) - { - if (!PhpHexEditHasSelected(context)) - context->SelStart = context->CurrentAddress; - - SendMessage(hwnd, WM_VSCROLL, SB_PAGEDOWN, 0); - PhpHexEditMove(hwnd, context, 0, 0); - context->SelEnd = context->CurrentAddress; - - REDRAW_WINDOW(hwnd); - break; - } - else - { - PhpHexEditSetSel(hwnd, context, -1, -1); - } - - SendMessage(hwnd, WM_VSCROLL, SB_PAGEDOWN, 0); - PhpHexEditMove(hwnd, context, 0, 0); - noScrollIntoView = TRUE; - break; - case VK_HOME: - if (shift) - { - if (!PhpHexEditHasSelected(context)) - context->SelStart = context->CurrentAddress; - - if (GetKeyState(VK_CONTROL) < 0) - { - SendMessage(hwnd, WM_VSCROLL, SB_THUMBTRACK, 0); - } - else - { - // Round down. - context->CurrentAddress /= context->BytesPerRow; - context->CurrentAddress *= context->BytesPerRow; - } - - PhpHexEditMove(hwnd, context, 0, 0); - context->SelEnd = context->CurrentAddress; - - REDRAW_WINDOW(hwnd); - break; - } - else - { - PhpHexEditSetSel(hwnd, context, -1, -1); - } - - if (GetKeyState(VK_CONTROL) < 0) - { - SendMessage(hwnd, WM_VSCROLL, SB_THUMBTRACK, 0); - context->CurrentAddress = 0; - } - else - { - // Round down. - context->CurrentAddress /= context->BytesPerRow; - context->CurrentAddress *= context->BytesPerRow; - } - - PhpHexEditMove(hwnd, context, 0, 0); - noScrollIntoView = TRUE; - - break; - case VK_END: - if (shift) - { - if (!PhpHexEditHasSelected(context)) - context->SelStart = context->CurrentAddress; - - if (GetKeyState(VK_CONTROL) < 0) - { - context->CurrentAddress = context->Length - 1; - SendMessage(hwnd, WM_VSCROLL, - MAKEWPARAM(SB_THUMBTRACK, ((context->Length + (context->BytesPerRow / 2)) / context->BytesPerRow) - context->LinesPerPage), - 0); - } - else - { - context->CurrentAddress /= context->BytesPerRow; - context->CurrentAddress *= context->BytesPerRow; - context->CurrentAddress += context->BytesPerRow - 1; - - if (context->CurrentAddress > context->Length) - context->CurrentAddress = context->Length - 1; - } - - PhpHexEditMove(hwnd, context, 0, 0); - context->SelEnd = context->CurrentAddress; - - REDRAW_WINDOW(hwnd); - break; - } - else - { - PhpHexEditSetSel(hwnd, context, -1, -1); - } - - if (GetKeyState(VK_CONTROL) < 0) - { - context->CurrentAddress = context->Length - 1; - - if (context->HalfPage) - { - SendMessage(hwnd, WM_VSCROLL, 0, 0); - } - else - { - SendMessage(hwnd, WM_VSCROLL, - MAKEWPARAM(SB_THUMBTRACK, ((context->Length + (context->BytesPerRow / 2)) / context->BytesPerRow) - context->LinesPerPage), - 0); - } - } - else - { - context->CurrentAddress /= context->BytesPerRow; - context->CurrentAddress *= context->BytesPerRow; - context->CurrentAddress += context->BytesPerRow - 1; - - if (context->CurrentAddress > context->Length) - context->CurrentAddress = context->Length - 1; - } - - PhpHexEditMove(hwnd, context, 0, 0); - noScrollIntoView = TRUE; - - break; - case VK_INSERT: - PhpHexEditSelInsert(hwnd, context, context->CurrentAddress, - max(1, context->SelEnd - context->SelStart)); - REDRAW_WINDOW(hwnd); - break; - case VK_DELETE: - if (PhpHexEditHasSelected(context)) - { - PhpHexEditClearEdit(hwnd, context); - } - else - { - PhpHexEditSelDelete(hwnd, context, context->CurrentAddress, context->CurrentAddress + 1); - REDRAW_WINDOW(hwnd); - } - break; - case '\t': - switch (context->CurrentMode) - { - case EDIT_NONE: - context->CurrentMode = EDIT_HIGH; - break; - case EDIT_HIGH: - case EDIT_LOW: - context->CurrentMode = EDIT_ASCII; - break; - case EDIT_ASCII: - context->CurrentMode = EDIT_HIGH; - break; - } - - PhpHexEditMove(hwnd, context, 0, 0); - - break; - } - - // Scroll into view if not in view. - if ( - !noScrollIntoView && - (context->CurrentAddress < context->TopIndex || - context->CurrentAddress >= context->TopIndex + context->LinesPerPage * context->BytesPerRow) - ) - { - PhpHexEditScrollTo(hwnd, context, context->CurrentAddress); - } - - context->NoAddressChange = oldNoAddressChange; - } - break; - case HEM_SETBUFFER: - { - PhpHexEditSetBuffer(hwnd, context, (PUCHAR)lParam, (ULONG)wParam); - } - return TRUE; - case HEM_SETDATA: - { - PhpHexEditSetData(hwnd, context, (PUCHAR)lParam, (ULONG)wParam); - } - return TRUE; - case HEM_GETBUFFER: - { - PULONG length = (PULONG)wParam; - - if (length) - *length = context->Length; - - return (LPARAM)context->Data; - } - case HEM_SETSEL: - { - LONG selStart = (LONG)wParam; - LONG selEnd = (LONG)lParam; - - if (selStart <= 0) - return FALSE; - if (selEnd > context->Length) - return FALSE; - - PhpHexEditScrollTo(hwnd, context, selStart); - PhpHexEditSetSel(hwnd, context, selStart, selEnd); - PhpHexEditRepositionCaret(hwnd, context, selStart); - REDRAW_WINDOW(hwnd); - } - return TRUE; - case HEM_SETEDITMODE: - { - context->CurrentMode = (LONG)wParam; - REDRAW_WINDOW(hwnd); - } - return TRUE; - case HEM_SETBYTESPERROW: - { - LONG bytesPerRow = (LONG)wParam; - - if (bytesPerRow >= 4) - { - context->BytesPerRow = bytesPerRow; - PhpHexEditUpdateMetrics(hwnd, context, TRUE, NULL); - PhpHexEditUpdateScrollbars(hwnd, context); - PhpHexEditScrollTo(hwnd, context, context->CurrentAddress); - PhpHexEditRepositionCaret(hwnd, context, context->CurrentAddress); - REDRAW_WINDOW(hwnd); - } - } - return TRUE; - } - -DefaultHandler: - return DefWindowProc(hwnd, uMsg, wParam, lParam); -} - -FORCEINLINE VOID PhpPrintHex( - _In_ HDC hdc, - _In_ PPHP_HEXEDIT_CONTEXT Context, - _Inout_ PWCHAR Buffer, - _In_ UCHAR Byte, - _Inout_ PLONG X, - _Inout_ PLONG Y, - _Inout_ PULONG N - ) -{ - PWCHAR p = Buffer; - - TO_HEX(p, Byte); - *p++ = ' '; - TextOut(hdc, *X, *Y, Buffer, 3); - *X += Context->NullWidth * 3; - (*N)++; - - if (*N == Context->BytesPerRow) - { - *N = 0; - *X = Context->HexOffset; - *Y += Context->LineHeight; - } -} - -FORCEINLINE VOID PhpPrintAscii( - _In_ HDC hdc, - _In_ PPHP_HEXEDIT_CONTEXT Context, - _In_ UCHAR Byte, - _Inout_ PLONG X, - _Inout_ PLONG Y, - _Inout_ PULONG N - ) -{ - WCHAR c; - - c = IS_PRINTABLE(Byte) ? Byte : '.'; - TextOut(hdc, *X, *Y, &c, 1); - *X += Context->NullWidth; - (*N)++; - - if (*N == Context->BytesPerRow) - { - *N = 0; - *X = Context->AsciiOffset; - *Y += Context->LineHeight; - } -} - -FORCEINLINE COLORREF GetLighterHighlightColor( - VOID - ) -{ - COLORREF color; - UCHAR r; - UCHAR g; - UCHAR b; - - color = GetSysColor(COLOR_HIGHLIGHT); - r = (UCHAR)color; - g = (UCHAR)(color >> 8); - b = (UCHAR)(color >> 16); - - if (r <= 255 - 64) - r += 64; - else - r = 255; - - if (g <= 255 - 64) - g += 64; - else - g = 255; - - if (b <= 255 - 64) - b += 64; - else - b = 255; - - return RGB(r, g, b); -} - -VOID PhpHexEditUpdateMetrics( - _In_ HWND hwnd, - _In_ PPHP_HEXEDIT_CONTEXT Context, - _In_ BOOLEAN UpdateLineHeight, - _In_opt_ HDC hdc - ) -{ - BOOLEAN freeHdc = FALSE; - RECT clientRect; - SIZE size; - - if (!hdc && UpdateLineHeight) - { - hdc = CreateCompatibleDC(hdc); - SelectObject(hdc, Context->Font); - freeHdc = TRUE; - } - - GetClientRect(hwnd, &clientRect); - - if (UpdateLineHeight) - { - GetCharWidth(hdc, '0', '0', &Context->NullWidth); - GetTextExtentPoint32(hdc, L"0", 1, &size); - Context->LineHeight = size.cy; - } - - Context->HexOffset = Context->ShowAddress ? (Context->AddressIsWide ? Context->NullWidth * 9 : Context->NullWidth * 5) : 0; - Context->AsciiOffset = Context->HexOffset + (Context->ShowHex ? (Context->BytesPerRow * 3 * Context->NullWidth) : 0); - - if (Context->LineHeight != 0) - { - Context->LinesPerPage = clientRect.bottom / Context->LineHeight; - Context->HalfPage = FALSE; - - if (Context->LinesPerPage * Context->BytesPerRow > Context->Length) - { - Context->LinesPerPage = (Context->Length + Context->BytesPerRow / 2) / Context->BytesPerRow; - - if (Context->Length % Context->BytesPerRow != 0) - { - Context->HalfPage = TRUE; - Context->LinesPerPage++; - } - } - } - - if (freeHdc && hdc) - DeleteDC(hdc); -} - -VOID PhpHexEditOnPaint( - _In_ HWND hwnd, - _In_ PPHP_HEXEDIT_CONTEXT Context, - _In_ PAINTSTRUCT *PaintStruct, - _In_ HDC hdc - ) -{ - RECT clientRect; - HDC bufferDc; - HBITMAP bufferBitmap; - HBITMAP oldBufferBitmap; - LONG height; - LONG x; - LONG y; - LONG i; - ULONG requiredBufferLength; - PWCHAR buffer; - - GetClientRect(hwnd, &clientRect); - - bufferDc = CreateCompatibleDC(hdc); - bufferBitmap = CreateCompatibleBitmap(hdc, clientRect.right, clientRect.bottom); - oldBufferBitmap = SelectObject(bufferDc, bufferBitmap); - - SetDCBrushColor(bufferDc, GetSysColor(COLOR_WINDOW)); - FillRect(bufferDc, &clientRect, GetStockObject(DC_BRUSH)); - SelectObject(bufferDc, Context->Font); - SetBoundsRect(bufferDc, &clientRect, DCB_DISABLE); - - requiredBufferLength = (max(8, Context->BytesPerRow * 3) + 1) * sizeof(WCHAR); - - if (Context->CharBufferLength < requiredBufferLength) - { - if (Context->CharBuffer) - PhFree(Context->CharBuffer); - - Context->CharBuffer = PhAllocate(requiredBufferLength); - Context->CharBufferLength = requiredBufferLength; - buffer = Context->CharBuffer; - } - - buffer = Context->CharBuffer; - - if (Context->Data) - { - // Get character dimensions. - if (Context->Update) - { - PhpHexEditUpdateMetrics(hwnd, Context, TRUE, bufferDc); - Context->Update = FALSE; - PhpHexEditUpdateScrollbars(hwnd, Context); - } - - height = (clientRect.bottom + Context->LineHeight - 1) / Context->LineHeight * Context->LineHeight; // round up to height - - if (Context->ShowAddress) - { - PH_FORMAT format; - ULONG w; - RECT rect; - - PhInitFormatX(&format, 0); - format.Type |= FormatPadZeros; - format.Width = Context->AddressIsWide ? 8 : 4; - - w = Context->AddressIsWide ? 8 : 4; - - rect = clientRect; - rect.left = Context->AddressOffset; - rect.top = 0; - - for (i = Context->TopIndex; i < Context->Length && rect.top < height; i += Context->BytesPerRow) - { - format.u.Int32 = i; - PhFormatToBuffer(&format, 1, buffer, requiredBufferLength, NULL); - DrawText(bufferDc, buffer, w, &rect, DT_LEFT | DT_TOP | DT_SINGLELINE | DT_NOPREFIX | DT_NOCLIP); - rect.top += Context->LineHeight; - } - } - - if (Context->ShowHex) - { - RECT rect; - LONG n = 0; - - x = Context->HexOffset; - y = 0; - rect = clientRect; - rect.left = x; - rect.top = 0; - - if (Context->SelStart != -1) - { - COLORREF highlightColor; - LONG selStart; - LONG selEnd; - - if (Context->CurrentMode == EDIT_HIGH || Context->CurrentMode == EDIT_LOW) - highlightColor = GetSysColor(COLOR_HIGHLIGHT); - else - highlightColor = GetLighterHighlightColor(); - - selStart = Context->SelStart; - selEnd = Context->SelEnd; - - if (selStart > selEnd) - { - ULONG t; - - t = selEnd; - selEnd = selStart; - selStart = t; - } - - if (selStart >= Context->Length) - selStart = Context->Length - 1; - if (selEnd > Context->Length) - selEnd = Context->Length; - - // Bytes before the selection - - for (i = Context->TopIndex; i < selStart && y < height; i++) - { - PhpPrintHex(bufferDc, Context, buffer, Context->Data[i], &x, &y, &n); - } - - // Bytes in the selection - - SetTextColor(bufferDc, GetSysColor(COLOR_HIGHLIGHTTEXT)); - SetBkColor(bufferDc, highlightColor); - - for (; i < selEnd && i < Context->Length && y < height; i++) - { - PhpPrintHex(bufferDc, Context, buffer, Context->Data[i], &x, &y, &n); - } - - // Bytes after the selection - - SetTextColor(bufferDc, GetSysColor(COLOR_WINDOWTEXT)); - SetBkColor(bufferDc, GetSysColor(COLOR_WINDOW)); - - for (; i < Context->Length && y < height; i++) - { - PhpPrintHex(bufferDc, Context, buffer, Context->Data[i], &x, &y, &n); - } - } - else - { - i = Context->TopIndex; - - while (i < Context->Length && rect.top < height) - { - PWCHAR p = buffer; - - for (n = 0; n < Context->BytesPerRow && i < Context->Length; n++) - { - TO_HEX(p, Context->Data[i]); - *p++ = ' '; - i++; - } - - while (n < Context->BytesPerRow) - { - p[0] = ' '; - p[1] = ' '; - p[2] = ' '; - p += 3; - n++; - } - - DrawText(bufferDc, buffer, Context->BytesPerRow * 3, &rect, DT_LEFT | DT_TOP | DT_SINGLELINE | DT_NOPREFIX | DT_NOCLIP); - rect.top += Context->LineHeight; - } - } - } - - if (Context->ShowAscii) - { - RECT rect; - LONG n = 0; - - x = Context->AsciiOffset; - y = 0; - rect = clientRect; - rect.left = x; - rect.top = 0; - - if (Context->SelStart != -1) - { - COLORREF highlightColor; - LONG selStart; - LONG selEnd; - - if (Context->CurrentMode == EDIT_ASCII) - highlightColor = GetSysColor(COLOR_HIGHLIGHT); - else - highlightColor = GetLighterHighlightColor(); - - selStart = Context->SelStart; - selEnd = Context->SelEnd; - - if (selStart > selEnd) - { - LONG t; - - t = selEnd; - selEnd = selStart; - selStart = t; - } - - if (selStart >= Context->Length) - selStart = Context->Length - 1; - if (selEnd > Context->Length) - selEnd = Context->Length; - - // Bytes before the selection - - for (i = Context->TopIndex; i < selStart && y < height; i++) - { - PhpPrintAscii(bufferDc, Context, Context->Data[i], &x, &y, &n); - } - - // Bytes in the selection - - SetTextColor(bufferDc, GetSysColor(COLOR_HIGHLIGHTTEXT)); - SetBkColor(bufferDc, highlightColor); - - for (; i < selEnd && i < Context->Length && y < height; i++) - { - PhpPrintAscii(bufferDc, Context, Context->Data[i], &x, &y, &n); - } - - // Bytes after the selection - - SetTextColor(bufferDc, GetSysColor(COLOR_WINDOWTEXT)); - SetBkColor(bufferDc, GetSysColor(COLOR_WINDOW)); - - for (; i < Context->Length && y < height; i++) - { - PhpPrintAscii(bufferDc, Context, Context->Data[i], &x, &y, &n); - } - } - else - { - i = Context->TopIndex; - - while (i < Context->Length && rect.top < height) - { - PWCHAR p = buffer; - - for (n = 0; n < Context->BytesPerRow && i < Context->Length; n++) - { - *p++ = IS_PRINTABLE(Context->Data[i]) ? Context->Data[i] : '.'; // 1 - i++; - } - - DrawText(bufferDc, buffer, n, &rect, DT_LEFT | DT_TOP | DT_SINGLELINE | DT_NOPREFIX | DT_NOCLIP); - rect.top += Context->LineHeight; - } - } - } - } - - BitBlt(hdc, 0, 0, clientRect.right, clientRect.bottom, bufferDc, 0, 0, SRCCOPY); - SelectObject(bufferDc, oldBufferBitmap); - DeleteObject(bufferBitmap); - DeleteDC(bufferDc); -} - -VOID PhpHexEditUpdateScrollbars( - _In_ HWND hwnd, - _In_ PPHP_HEXEDIT_CONTEXT Context - ) -{ - SCROLLINFO si = { sizeof(si) }; - - si.fMask = SIF_ALL; - si.nMin = 0; - si.nMax = (Context->Length / Context->BytesPerRow) - 1; - si.nPage = Context->LinesPerPage; - si.nPos = Context->TopIndex / Context->BytesPerRow; - SetScrollInfo(hwnd, SB_VERT, &si, TRUE); - - if (si.nMax > (LONG)si.nPage) - EnableScrollBar(hwnd, SB_VERT, ESB_ENABLE_BOTH); - - // No horizontal scrollbar please. - /*si.nMin = 0; - si.nMax = ((Context->ShowAddress ? (Context->AddressIsWide ? 8 : 4) : 0) + - (Context->ShowHex ? Context->BytesPerRow * 3 : 0) + - (Context->ShowAscii ? Context->BytesPerRow : 0)) * Context->NullWidth; - si.nPage = 1; - si.nPos = 0; - SetScrollInfo(hwnd, SB_HORZ, &si, TRUE);*/ -} - -VOID PhpHexEditCreateAddressCaret( - _In_ HWND hwnd, - _In_ PPHP_HEXEDIT_CONTEXT Context - ) -{ - DestroyCaret(); - CreateCaret(hwnd, NULL, Context->NullWidth * (Context->AddressIsWide ? 8 : 4), Context->LineHeight); -} - -VOID PhpHexEditCreateEditCaret( - _In_ HWND hwnd, - _In_ PPHP_HEXEDIT_CONTEXT Context - ) -{ - DestroyCaret(); - CreateCaret(hwnd, NULL, Context->NullWidth, Context->LineHeight); -} - -VOID PhpHexEditRepositionCaret( - _In_ HWND hwnd, - _In_ PPHP_HEXEDIT_CONTEXT Context, - _In_ LONG Position - ) -{ - ULONG x; - ULONG y; - RECT rect; - - x = (Position - Context->TopIndex) % Context->BytesPerRow; - y = (Position - Context->TopIndex) / Context->BytesPerRow; - - switch (Context->CurrentMode) - { - case EDIT_NONE: - PhpHexEditCreateAddressCaret(hwnd, Context); - x = 0; - break; - case EDIT_HIGH: - PhpHexEditCreateEditCaret(hwnd, Context); - x *= Context->NullWidth * 3; - x += Context->HexOffset; - break; - case EDIT_LOW: - PhpHexEditCreateEditCaret(hwnd, Context); - x *= Context->NullWidth * 3; - x += Context->NullWidth; - x += Context->HexOffset; - break; - case EDIT_ASCII: - PhpHexEditCreateEditCaret(hwnd, Context); - x *= Context->NullWidth; - x += Context->AsciiOffset; - break; - } - - Context->EditPosition.x = x; - Context->EditPosition.y = y * Context->LineHeight; - - GetClientRect(hwnd, &rect); - - if (PtInRect(&rect, Context->EditPosition)) - { - SetCaretPos(Context->EditPosition.x, Context->EditPosition.y); - ShowCaret(hwnd); - } -} - -VOID PhpHexEditCalculatePosition( - _In_ HWND hwnd, - _In_ PPHP_HEXEDIT_CONTEXT Context, - _In_ LONG X, - _In_ LONG Y, - _Out_ POINT *Point - ) -{ - LONG xp; - - Y /= Context->LineHeight; - - if (Y < 0 || Y >= Context->LinesPerPage) - { - Point->x = -1; - Point->y = -1; - return; - } - - if (Y * Context->BytesPerRow >= Context->Length) - { - Point->x = -1; - Point->y = -1; - return; - } - - X += Context->NullWidth; - X /= Context->NullWidth; - - if (Context->ShowAddress && X <= (Context->AddressIsWide ? 8 : 4)) - { - Context->CurrentAddress = Context->TopIndex + Context->BytesPerRow * Y; - Context->CurrentMode = EDIT_NONE; - - Point->x = 0; - Point->y = Y; - return; - } - - xp = Context->HexOffset / Context->NullWidth + Context->BytesPerRow * 3; - - if (Context->ShowHex && X < xp) - { - if (X % 3) - X--; - - Context->CurrentAddress = Context->TopIndex + - Context->BytesPerRow * Y + - (X - (Context->HexOffset / Context->NullWidth)) / 3; - Context->CurrentMode = ((X % 3) & 1) ? EDIT_LOW : EDIT_HIGH; - - Point->x = X; - Point->y = Y; - return; - } - - X--; // fix selection problem - - xp = Context->AsciiOffset / Context->NullWidth + Context->BytesPerRow; - - if (Context->ShowAscii && X * Context->NullWidth >= Context->AsciiOffset && X <= xp) - { - Context->CurrentAddress = Context->TopIndex + - Context->BytesPerRow * Y + - (X - (Context->AsciiOffset / Context->NullWidth)); - Context->CurrentMode = EDIT_ASCII; - - Point->x = X; - Point->y = Y; - return; - } - - Point->x = -1; - Point->y = -1; -} - -VOID PhpHexEditMove( - _In_ HWND hwnd, - _In_ PPHP_HEXEDIT_CONTEXT Context, - _In_ LONG X, - _In_ LONG Y - ) -{ - switch (Context->CurrentMode) - { - case EDIT_NONE: - Context->CurrentAddress += Y * Context->BytesPerRow; - break; - case EDIT_HIGH: - if (X != 0) - Context->CurrentMode = EDIT_LOW; - if (X == -1) - Context->CurrentAddress--; - Context->CurrentAddress += Y * Context->BytesPerRow; - break; - case EDIT_LOW: - if (X != 0) - Context->CurrentMode = EDIT_HIGH; - if (X == 1) - Context->CurrentAddress++; - Context->CurrentAddress += Y * Context->BytesPerRow; - break; - case EDIT_ASCII: - Context->CurrentAddress += X; - Context->CurrentAddress += Y * Context->BytesPerRow; - break; - } - - if (Context->CurrentAddress < 0) - Context->CurrentAddress = 0; - - if (Context->CurrentAddress >= Context->Length) - { - Context->CurrentAddress -= X; - Context->CurrentAddress -= Y * Context->BytesPerRow; - } - - Context->NoAddressChange = TRUE; - - if (Context->CurrentAddress < Context->TopIndex) - SendMessage(hwnd, WM_VSCROLL, SB_LINEUP, 0); - if (Context->CurrentAddress >= Context->TopIndex + Context->LinesPerPage * Context->BytesPerRow) - SendMessage(hwnd, WM_VSCROLL, SB_LINEDOWN, 0); - - Context->NoAddressChange = FALSE; - PhpHexEditRepositionCaret(hwnd, Context, Context->CurrentAddress); -} - -VOID PhpHexEditSetSel( - _In_ HWND hwnd, - _In_ PPHP_HEXEDIT_CONTEXT Context, - _In_ LONG S, - _In_ LONG E - ) -{ - DestroyCaret(); - Context->SelStart = S; - Context->SelEnd = E; - REDRAW_WINDOW(hwnd); - - if (S != -1 && E != -1) - { - Context->CurrentAddress = S; - } - else - { - if (Context->EditPosition.x == 0 && Context->ShowAddress) - PhpHexEditCreateAddressCaret(hwnd, Context); - else - PhpHexEditCreateEditCaret(hwnd, Context); - - SetCaretPos(Context->EditPosition.x, Context->EditPosition.y); - ShowCaret(hwnd); - } -} - -VOID PhpHexEditScrollTo( - _In_ HWND hwnd, - _In_ PPHP_HEXEDIT_CONTEXT Context, - _In_ LONG Position - ) -{ - if (Position < Context->TopIndex || Position > Context->TopIndex + Context->LinesPerPage * Context->BytesPerRow) - { - Context->TopIndex = Position / Context->BytesPerRow * Context->BytesPerRow; // round down - Context->TopIndex -= Context->LinesPerPage / 3 * Context->BytesPerRow; - - if (Context->TopIndex < 0) - Context->TopIndex = 0; - - if (Context->Length >= Context->LinesPerPage * Context->BytesPerRow) - { - if (Context->TopIndex > Context->Length - Context->LinesPerPage * Context->BytesPerRow) - Context->TopIndex = Context->Length - Context->LinesPerPage * Context->BytesPerRow; - } - - PhpHexEditUpdateScrollbars(hwnd, Context); - REDRAW_WINDOW(hwnd); - } -} - -VOID PhpHexEditClearEdit( - _In_ HWND hwnd, - _In_ PPHP_HEXEDIT_CONTEXT Context - ) -{ - if (Context->AllowLengthChange) - { - Context->CurrentAddress = Context->SelStart; - PhpHexEditSelDelete(hwnd, Context, Context->SelStart, Context->SelEnd); - PhpHexEditRepositionCaret(hwnd, Context, Context->CurrentAddress); - REDRAW_WINDOW(hwnd); - } -} - -VOID PhpHexEditCopyEdit( - _In_ HWND hwnd, - _In_ PPHP_HEXEDIT_CONTEXT Context - ) -{ - if (OpenClipboard(hwnd)) - { - EmptyClipboard(); - PhpHexEditNormalizeSel(hwnd, Context); - - if (Context->CurrentMode != EDIT_ASCII) - { - ULONG length = Context->SelEnd - Context->SelStart; - HGLOBAL binaryMemory; - HGLOBAL hexMemory; - - binaryMemory = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, length); - - if (binaryMemory) - { - PUCHAR p = GlobalLock(binaryMemory); - memcpy(p, &Context->Data[Context->SelStart], length); - GlobalUnlock(binaryMemory); - - hexMemory = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, (length * 3 + 1) * sizeof(WCHAR)); - - if (hexMemory) - { - PWCHAR pw; - ULONG i; - - pw = GlobalLock(hexMemory); - - for (i = 0; i < length; i++) - { - TO_HEX(pw, Context->Data[Context->SelStart + i]); - *pw++ = ' '; - } - *pw = 0; - - GlobalUnlock(hexMemory); - - SetClipboardData(CF_UNICODETEXT, hexMemory); - } - - SetClipboardData(RegisterClipboardFormat(L"BinaryData"), binaryMemory); - } - } - else - { - ULONG length = Context->SelEnd - Context->SelStart; - HGLOBAL binaryMemory; - HGLOBAL asciiMemory; - - binaryMemory = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, length); - asciiMemory = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, length + 1); - - if (binaryMemory) - { - PUCHAR p = GlobalLock(binaryMemory); - memcpy(p, &Context->Data[Context->SelStart], length); - GlobalUnlock(binaryMemory); - - if (asciiMemory) - { - ULONG i; - - p = GlobalLock(asciiMemory); - memcpy(p, &Context->Data[Context->SelStart], length); - - for (i = 0; i < length; i++) - { - if (!IS_PRINTABLE(*p)) - *p = '.'; - p++; - } - *p = 0; - - GlobalUnlock(asciiMemory); - - SetClipboardData(CF_TEXT, asciiMemory); - } - - SetClipboardData(RegisterClipboardFormat(L"BinaryData"), binaryMemory); - } - } - - CloseClipboard(); - } -} - -VOID PhpHexEditCutEdit( - _In_ HWND hwnd, - _In_ PPHP_HEXEDIT_CONTEXT Context - ) -{ - if (Context->AllowLengthChange) - { - PhpHexEditCopyEdit(hwnd, Context); - PhpHexEditSelDelete(hwnd, Context, Context->SelStart, Context->SelEnd); - REDRAW_WINDOW(hwnd); - } -} - -VOID PhpHexEditPasteEdit( - _In_ HWND hwnd, - _In_ PPHP_HEXEDIT_CONTEXT Context - ) -{ - if (OpenClipboard(hwnd)) - { - HANDLE memory; - - memory = GetClipboardData(RegisterClipboardFormat(L"BinaryData")); - - if (!memory) - memory = GetClipboardData(CF_TEXT); - - if (memory) - { - PUCHAR p = GlobalLock(memory); - ULONG length = (ULONG)GlobalSize(memory); - ULONG paste; - ULONG oldCurrentAddress = Context->CurrentAddress; - - PhpHexEditNormalizeSel(hwnd, Context); - - if (Context->AllowLengthChange) - { - if (Context->SelStart == -1) - { - if (Context->CurrentMode == EDIT_LOW) - Context->CurrentAddress++; - - paste = Context->CurrentAddress; - PhpHexEditSelInsert(hwnd, Context, Context->CurrentAddress, length); - } - else - { - paste = Context->SelStart; - PhpHexEditSelDelete(hwnd, Context, Context->SelStart, Context->SelEnd); - PhpHexEditSelInsert(hwnd, Context, paste, length); - PhpHexEditSetSel(hwnd, Context, -1, -1); - } - } - else - { - if (Context->SelStart == -1) - { - if (Context->CurrentMode == EDIT_LOW) - Context->CurrentAddress++; - - paste = Context->CurrentAddress; - } - else - { - paste = Context->SelStart; - } - - if (length > Context->Length - paste) - length = Context->Length - paste; - } - - memcpy(&Context->Data[paste], p, length); - GlobalUnlock(memory); - - Context->CurrentAddress = oldCurrentAddress; - REDRAW_WINDOW(hwnd); - } - - CloseClipboard(); - } -} - -VOID PhpHexEditSelectAll( - _In_ HWND hwnd, - _In_ PPHP_HEXEDIT_CONTEXT Context - ) -{ - Context->SelStart = 0; - Context->SelEnd = Context->Length; - DestroyCaret(); - REDRAW_WINDOW(hwnd); -} - -VOID PhpHexEditUndoEdit( - _In_ HWND hwnd, - _In_ PPHP_HEXEDIT_CONTEXT Context - ) -{ - // TODO -} - -VOID PhpHexEditNormalizeSel( - _In_ HWND hwnd, - _In_ PPHP_HEXEDIT_CONTEXT Context - ) -{ - if (Context->SelStart > Context->SelEnd) - { - LONG t; - - t = Context->SelEnd; - Context->SelEnd = Context->SelStart; - Context->SelStart = t; - } -} - -VOID PhpHexEditSelDelete( - _In_ HWND hwnd, - _In_ PPHP_HEXEDIT_CONTEXT Context, - _In_ LONG S, - _In_ LONG E - ) -{ - if (Context->AllowLengthChange && Context->Length > 0) - { - PUCHAR p = PhAllocate(Context->Length - (E - S) + 1); - - memcpy(p, Context->Data, S); - - if (S < Context->Length - (E - S)) - memcpy(&p[S], &Context->Data[E], Context->Length - E); - - PhFree(Context->Data); - Context->Data = p; - PhpHexEditSetSel(hwnd, Context, -1, -1); - Context->Length -= E - S; - - if (Context->CurrentAddress > Context->Length) - { - Context->CurrentAddress = Context->Length; - PhpHexEditRepositionCaret(hwnd, Context, Context->CurrentAddress); - } - - Context->Update = TRUE; - } -} - -VOID PhpHexEditSelInsert( - _In_ HWND hwnd, - _In_ PPHP_HEXEDIT_CONTEXT Context, - _In_ LONG S, - _In_ LONG L - ) -{ - if (Context->AllowLengthChange) - { - PUCHAR p = PhAllocate(Context->Length + L); - - memset(p, 0, Context->Length + L); - memcpy(p, Context->Data, S); - memcpy(&p[S + L], &Context->Data[S], Context->Length - S); - - PhFree(Context->Data); - Context->Data = p; - PhpHexEditSetSel(hwnd, Context, -1, -1); - Context->Length += L; - - Context->Update = TRUE; - } -} - -VOID PhpHexEditSetBuffer( - _In_ HWND hwnd, - _In_ PPHP_HEXEDIT_CONTEXT Context, - _In_ PUCHAR Data, - _In_ ULONG Length - ) -{ - Context->Data = Data; - PhpHexEditSetSel(hwnd, Context, -1, -1); - Context->Length = Length; - Context->CurrentAddress = 0; - Context->EditPosition.x = Context->EditPosition.y = 0; - Context->CurrentMode = EDIT_HIGH; - Context->TopIndex = 0; - Context->Update = TRUE; - - Context->UserBuffer = TRUE; - Context->AllowLengthChange = FALSE; -} - -VOID PhpHexEditSetData( - _In_ HWND hwnd, - _In_ PPHP_HEXEDIT_CONTEXT Context, - _In_ PUCHAR Data, - _In_ ULONG Length - ) -{ - if (Context->Data) PhFree(Context->Data); - Context->Data = PhAllocate(Length); - memcpy(Context->Data, Data, Length); - PhpHexEditSetBuffer(hwnd, Context, Context->Data, Length); - Context->UserBuffer = FALSE; - Context->AllowLengthChange = TRUE; -} +/* + * Process Hacker - + * hex editor control + * + * Copyright (C) 2010-2015 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include +#include + +#include + +#include + +// Code originally from http://www.codeguru.com/Cpp/controls/editctrl/article.php/c539 + +BOOLEAN PhHexEditInitialization( + VOID + ) +{ + WNDCLASSEX c = { sizeof(c) }; + + c.style = CS_GLOBALCLASS; + c.lpfnWndProc = PhpHexEditWndProc; + c.cbClsExtra = 0; + c.cbWndExtra = sizeof(PVOID); + c.hInstance = PhLibImageBase; + c.hIcon = NULL; + c.hCursor = LoadCursor(NULL, IDC_ARROW); + c.hbrBackground = NULL; + c.lpszMenuName = NULL; + c.lpszClassName = PH_HEXEDIT_CLASSNAME; + c.hIconSm = NULL; + + if (!RegisterClassEx(&c)) + return FALSE; + + return TRUE; +} + +VOID PhpCreateHexEditContext( + _Out_ PPHP_HEXEDIT_CONTEXT *Context + ) +{ + PPHP_HEXEDIT_CONTEXT context; + + context = PhAllocate(sizeof(PHP_HEXEDIT_CONTEXT)); + memset(context, 0, sizeof(PHP_HEXEDIT_CONTEXT)); // important, set NullWidth to 0 + + context->Data = NULL; + context->Length = 0; + context->TopIndex = 0; + context->BytesPerRow = 16; + context->LinesPerPage = 1; + + context->ShowHex = TRUE; + context->ShowAscii = TRUE; + context->ShowAddress = TRUE; + context->AddressIsWide = TRUE; + context->AllowLengthChange = FALSE; + + context->AddressOffset = 0; + context->HexOffset = 0; + context->AsciiOffset = 0; + + context->Update = TRUE; + context->NoAddressChange = FALSE; + context->CurrentMode = EDIT_NONE; + + context->EditPosition.x = 0; + context->EditPosition.y = 0; + context->CurrentAddress = 0; + context->HalfPage = TRUE; + + context->SelStart = -1; + context->SelEnd = -1; + + *Context = context; +} + +VOID PhpFreeHexEditContext( + _In_ _Post_invalid_ PPHP_HEXEDIT_CONTEXT Context + ) +{ + if (!Context->UserBuffer && Context->Data) PhFree(Context->Data); + if (Context->CharBuffer) PhFree(Context->CharBuffer); + if (Context->Font) DeleteObject(Context->Font); + PhFree(Context); +} + +LRESULT CALLBACK PhpHexEditWndProc( + _In_ HWND hwnd, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + PPHP_HEXEDIT_CONTEXT context; + + context = (PPHP_HEXEDIT_CONTEXT)GetWindowLongPtr(hwnd, 0); + + if (uMsg == WM_CREATE) + { + PhpCreateHexEditContext(&context); + SetWindowLongPtr(hwnd, 0, (LONG_PTR)context); + } + + if (!context) + return DefWindowProc(hwnd, uMsg, wParam, lParam); + + switch (uMsg) + { + case WM_CREATE: + { + context->Font = CreateFont(-(LONG)PhMultiplyDivide(12, PhGlobalDpi, 96), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, L"Courier New"); + } + break; + case WM_DESTROY: + { + SetWindowLongPtr(hwnd, 0, (LONG_PTR)NULL); + PhpFreeHexEditContext(context); + } + break; + case WM_PAINT: + { + PAINTSTRUCT paintStruct; + HDC hdc; + + if (hdc = BeginPaint(hwnd, &paintStruct)) + { + PhpHexEditOnPaint(hwnd, context, &paintStruct, hdc); + EndPaint(hwnd, &paintStruct); + } + } + break; + case WM_SIZE: + { + PhpHexEditUpdateMetrics(hwnd, context, FALSE, NULL); + } + break; + case WM_SETFOCUS: + { + if (context->Data && !PhpHexEditHasSelected(context)) + { + if (context->EditPosition.x == 0 && context->ShowAddress) + PhpHexEditCreateAddressCaret(hwnd, context); + else + PhpHexEditCreateEditCaret(hwnd, context); + + SetCaretPos(context->EditPosition.x, context->EditPosition.y); + ShowCaret(hwnd); + } + } + break; + case WM_KILLFOCUS: + { + DestroyCaret(); + } + break; + case WM_VSCROLL: + { + SHORT scrollRequest = LOWORD(wParam); + LONG currentPosition; + LONG originalTopIndex; + SCROLLINFO scrollInfo = { sizeof(scrollInfo) }; + + originalTopIndex = context->TopIndex; + + scrollInfo.fMask = SIF_TRACKPOS; + GetScrollInfo(hwnd, SB_VERT, &scrollInfo); + currentPosition = scrollInfo.nTrackPos; + + if (context->Data) + { + LONG mult; + + mult = context->LinesPerPage * context->BytesPerRow; + + switch (scrollRequest) + { + case SB_LINEDOWN: + if (context->TopIndex < context->Length - mult) + { + context->TopIndex += context->BytesPerRow; + REDRAW_WINDOW(hwnd); + } + break; + case SB_LINEUP: + if (context->TopIndex >= context->BytesPerRow) + { + context->TopIndex -= context->BytesPerRow; + REDRAW_WINDOW(hwnd); + } + break; + case SB_PAGEDOWN: + if (context->TopIndex < context->Length - mult) + { + context->TopIndex += mult; + + if (context->TopIndex > context->Length - mult) + context->TopIndex = context->Length - mult; + + REDRAW_WINDOW(hwnd); + } + break; + case SB_PAGEUP: + if (context->TopIndex > 0) + { + context->TopIndex -= mult; + + if (context->TopIndex < 0) + context->TopIndex = 0; + + REDRAW_WINDOW(hwnd); + } + break; + case SB_THUMBTRACK: + context->TopIndex = currentPosition * context->BytesPerRow; + REDRAW_WINDOW(hwnd); + break; + } + + SetScrollPos(hwnd, SB_VERT, context->TopIndex / context->BytesPerRow, TRUE); + + if (!context->NoAddressChange && FALSE) // this behaviour sucks, so just leave it out + context->CurrentAddress += context->TopIndex - originalTopIndex; + + PhpHexEditRepositionCaret(hwnd, context, context->CurrentAddress); + } + } + break; + case WM_MOUSEWHEEL: + { + SHORT wheelDelta = GET_WHEEL_DELTA_WPARAM(wParam); + + if (context->Data) + { + ULONG wheelScrollLines; + + if (!SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &wheelScrollLines, 0)) + wheelScrollLines = 3; + + context->TopIndex += context->BytesPerRow * (LONG)wheelScrollLines * -wheelDelta / WHEEL_DELTA; + + if (context->TopIndex < 0) + context->TopIndex = 0; + + if (context->Length >= context->LinesPerPage * context->BytesPerRow) + { + if (context->TopIndex > context->Length - context->LinesPerPage * context->BytesPerRow) + context->TopIndex = context->Length - context->LinesPerPage * context->BytesPerRow; + } + + REDRAW_WINDOW(hwnd); + + SetScrollPos(hwnd, SB_VERT, context->TopIndex / context->BytesPerRow, TRUE); + + PhpHexEditRepositionCaret(hwnd, context, context->CurrentAddress); + } + } + break; + case WM_GETDLGCODE: + if (wParam != VK_ESCAPE) + return DLGC_WANTALLKEYS; + break; + case WM_ERASEBKGND: + return 1; + case WM_LBUTTONDOWN: + { + ULONG flags = (ULONG)wParam; + POINT cursorPos; + + cursorPos.x = (LONG)(SHORT)LOWORD(lParam); + cursorPos.y = (LONG)(SHORT)HIWORD(lParam); + + SetFocus(hwnd); + + if (context->Data) + { + POINT point; + + if (wParam & MK_SHIFT) + context->SelStart = context->CurrentAddress; + + PhpHexEditCalculatePosition(hwnd, context, cursorPos.x, cursorPos.y, &point); + + if (point.x > -1) + { + context->EditPosition = point; + + point.x *= context->NullWidth; + point.y *= context->LineHeight; + + if (point.x == 0 && context->ShowAddress) + PhpHexEditCreateAddressCaret(hwnd, context); + else + PhpHexEditCreateEditCaret(hwnd, context); + + SetCaretPos(point.x, point.y); + + if (flags & MK_SHIFT) + { + context->SelEnd = context->CurrentAddress; + + if (context->CurrentMode == EDIT_HIGH || context->CurrentMode == EDIT_LOW) + context->SelEnd++; + + REDRAW_WINDOW(hwnd); + } + } + + if (!(flags & MK_SHIFT)) + { + if (DragDetect(hwnd, cursorPos)) + { + context->SelStart = context->CurrentAddress; + context->SelEnd = context->SelStart; + SetCapture(hwnd); + context->HasCapture = TRUE; + } + else + { + BOOLEAN selected; + + selected = context->SelStart != -1; + context->SelStart = -1; + context->SelEnd = -1; + + if (selected) + REDRAW_WINDOW(hwnd); + } + } + + if (!PhpHexEditHasSelected(context)) + ShowCaret(hwnd); + } + } + break; + case WM_LBUTTONUP: + { + if (context->HasCapture && PhpHexEditHasSelected(context)) + ReleaseCapture(); + + context->HasCapture = FALSE; + } + break; + case WM_MOUSEMOVE: + { + ULONG flags = (ULONG)wParam; + POINT cursorPos; + + cursorPos.x = (LONG)(SHORT)LOWORD(lParam); + cursorPos.y = (LONG)(SHORT)HIWORD(lParam); + + if ( + context->Data && + context->HasCapture && + context->SelStart != -1 + ) + { + RECT rect; + POINT point; + ULONG oldSelEnd; + + // User is dragging. + + GetClientRect(hwnd, &rect); + + if (!PtInRect(&rect, cursorPos)) + { + if (cursorPos.y < 0) + { + SendMessage(hwnd, WM_VSCROLL, SB_LINEUP, 0); + cursorPos.y = 0; + } + else if (cursorPos.y > rect.bottom) + { + SendMessage(hwnd, WM_VSCROLL, SB_LINEDOWN, 0); + cursorPos.y = rect.bottom - 1; + } + } + + oldSelEnd = context->SelEnd; + PhpHexEditCalculatePosition(hwnd, context, cursorPos.x, cursorPos.y, &point); + + if (point.x > -1) + { + context->SelEnd = context->CurrentAddress; + + if (context->CurrentMode == EDIT_HIGH || context->CurrentMode == EDIT_LOW) + context->SelEnd++; + } + + if (PhpHexEditHasSelected(context)) + DestroyCaret(); + + if (context->SelEnd != oldSelEnd) + REDRAW_WINDOW(hwnd); + } + } + break; + case WM_CHAR: + { + ULONG c = (ULONG)wParam; + + if (!context->Data) + goto DefaultHandler; + if (c == '\t') + goto DefaultHandler; + + if (GetKeyState(VK_CONTROL) < 0) + { + switch (c) + { + case 0x3: + if (PhpHexEditHasSelected(context)) + PhpHexEditCopyEdit(hwnd, context); + goto DefaultHandler; + case 0x16: + PhpHexEditPasteEdit(hwnd, context); + goto DefaultHandler; + case 0x18: + if (PhpHexEditHasSelected(context)) + PhpHexEditCutEdit(hwnd, context); + goto DefaultHandler; + case 0x1a: + PhpHexEditUndoEdit(hwnd, context); + goto DefaultHandler; + } + } + + // Disallow editing beyond the end of the data. + if (context->CurrentAddress >= context->Length) + goto DefaultHandler; + + if (c == 0x8) + { + if (context->CurrentAddress != 0) + { + context->CurrentAddress--; + PhpHexEditSelDelete(hwnd, context, context->CurrentAddress, context->CurrentAddress + 1); + PhpHexEditRepositionCaret(hwnd, context, context->CurrentAddress); + REDRAW_WINDOW(hwnd); + } + + goto DefaultHandler; + } + + PhpHexEditSetSel(hwnd, context, -1, -1); + + switch (context->CurrentMode) + { + case EDIT_NONE: + goto DefaultHandler; + case EDIT_HIGH: + case EDIT_LOW: + if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f')) + { + ULONG b = c - '0'; + + if (b > 9) + b = 10 + c - 'a'; + + if (context->CurrentMode == EDIT_HIGH) + { + context->Data[context->CurrentAddress] = + (UCHAR)((context->Data[context->CurrentAddress] & 0x0f) | (b << 4)); + } + else + { + context->Data[context->CurrentAddress] = + (UCHAR)((context->Data[context->CurrentAddress] & 0xf0) | b); + } + + PhpHexEditMove(hwnd, context, 1, 0); + } + break; + case EDIT_ASCII: + context->Data[context->CurrentAddress] = (UCHAR)c; + PhpHexEditMove(hwnd, context, 1, 0); + break; + } + + REDRAW_WINDOW(hwnd); + } + break; + case WM_KEYDOWN: + { + ULONG vk = (ULONG)wParam; + BOOLEAN shift = GetKeyState(VK_SHIFT) < 0; + BOOLEAN oldNoAddressChange = context->NoAddressChange; + BOOLEAN noScrollIntoView = FALSE; + + context->NoAddressChange = TRUE; + + switch (vk) + { + case VK_DOWN: + if (context->CurrentMode != EDIT_NONE) + { + if (shift) + { + if (!PhpHexEditHasSelected(context)) + context->SelStart = context->CurrentAddress; + + PhpHexEditMove(hwnd, context, 0, 1); + context->SelEnd = context->CurrentAddress; + + if (context->CurrentMode == EDIT_HIGH || context->CurrentMode == EDIT_LOW) + context->SelEnd++; + + REDRAW_WINDOW(hwnd); + break; + } + else + { + PhpHexEditSetSel(hwnd, context, -1, -1); + } + + PhpHexEditMove(hwnd, context, 0, 1); + noScrollIntoView = TRUE; + } + else + { + PhpHexEditMove(hwnd, context, 0, 1); + } + break; + case VK_UP: + if (context->CurrentMode != EDIT_NONE) + { + if (shift) + { + if (!PhpHexEditHasSelected(context)) + context->SelStart = context->CurrentAddress; + + PhpHexEditMove(hwnd, context, 0, -1); + context->SelEnd = context->CurrentAddress; + + REDRAW_WINDOW(hwnd); + break; + } + else + { + PhpHexEditSetSel(hwnd, context, -1, -1); + } + + PhpHexEditMove(hwnd, context, 0, -1); + noScrollIntoView = TRUE; + } + else + { + PhpHexEditMove(hwnd, context, 0, -1); + } + break; + case VK_LEFT: + if (context->CurrentMode != EDIT_NONE) + { + if (shift) + { + if (!PhpHexEditHasSelected(context)) + context->SelStart = context->CurrentAddress; + + PhpHexEditMove(hwnd, context, -1, 0); + context->SelEnd = context->CurrentAddress; + + REDRAW_WINDOW(hwnd); + break; + } + else + { + PhpHexEditSetSel(hwnd, context, -1, -1); + } + + PhpHexEditMove(hwnd, context, -1, 0); + noScrollIntoView = TRUE; + } + break; + case VK_RIGHT: + if (context->CurrentMode != EDIT_NONE) + { + if (shift) + { + if (!PhpHexEditHasSelected(context)) + context->SelStart = context->CurrentAddress; + + PhpHexEditMove(hwnd, context, 1, 0); + context->SelEnd = context->CurrentAddress; + + if (context->CurrentMode == EDIT_HIGH || context->CurrentMode == EDIT_LOW) + context->SelEnd++; + + REDRAW_WINDOW(hwnd); + break; + } + else + { + PhpHexEditSetSel(hwnd, context, -1, -1); + } + + PhpHexEditMove(hwnd, context, 1, 0); + noScrollIntoView = TRUE; + } + break; + case VK_PRIOR: + if (shift) + { + if (!PhpHexEditHasSelected(context)) + context->SelStart = context->CurrentAddress; + + SendMessage(hwnd, WM_VSCROLL, SB_PAGEUP, 0); + PhpHexEditMove(hwnd, context, 0, 0); + context->SelEnd = context->CurrentAddress; + + REDRAW_WINDOW(hwnd); + break; + } + else + { + PhpHexEditSetSel(hwnd, context, -1, -1); + } + + SendMessage(hwnd, WM_VSCROLL, SB_PAGEUP, 0); + PhpHexEditMove(hwnd, context, 0, 0); + noScrollIntoView = TRUE; + break; + case VK_NEXT: + if (shift) + { + if (!PhpHexEditHasSelected(context)) + context->SelStart = context->CurrentAddress; + + SendMessage(hwnd, WM_VSCROLL, SB_PAGEDOWN, 0); + PhpHexEditMove(hwnd, context, 0, 0); + context->SelEnd = context->CurrentAddress; + + REDRAW_WINDOW(hwnd); + break; + } + else + { + PhpHexEditSetSel(hwnd, context, -1, -1); + } + + SendMessage(hwnd, WM_VSCROLL, SB_PAGEDOWN, 0); + PhpHexEditMove(hwnd, context, 0, 0); + noScrollIntoView = TRUE; + break; + case VK_HOME: + if (shift) + { + if (!PhpHexEditHasSelected(context)) + context->SelStart = context->CurrentAddress; + + if (GetKeyState(VK_CONTROL) < 0) + { + SendMessage(hwnd, WM_VSCROLL, SB_THUMBTRACK, 0); + } + else + { + // Round down. + context->CurrentAddress /= context->BytesPerRow; + context->CurrentAddress *= context->BytesPerRow; + } + + PhpHexEditMove(hwnd, context, 0, 0); + context->SelEnd = context->CurrentAddress; + + REDRAW_WINDOW(hwnd); + break; + } + else + { + PhpHexEditSetSel(hwnd, context, -1, -1); + } + + if (GetKeyState(VK_CONTROL) < 0) + { + SendMessage(hwnd, WM_VSCROLL, SB_THUMBTRACK, 0); + context->CurrentAddress = 0; + } + else + { + // Round down. + context->CurrentAddress /= context->BytesPerRow; + context->CurrentAddress *= context->BytesPerRow; + } + + PhpHexEditMove(hwnd, context, 0, 0); + noScrollIntoView = TRUE; + + break; + case VK_END: + if (shift) + { + if (!PhpHexEditHasSelected(context)) + context->SelStart = context->CurrentAddress; + + if (GetKeyState(VK_CONTROL) < 0) + { + context->CurrentAddress = context->Length - 1; + SendMessage(hwnd, WM_VSCROLL, + MAKEWPARAM(SB_THUMBTRACK, ((context->Length + (context->BytesPerRow / 2)) / context->BytesPerRow) - context->LinesPerPage), + 0); + } + else + { + context->CurrentAddress /= context->BytesPerRow; + context->CurrentAddress *= context->BytesPerRow; + context->CurrentAddress += context->BytesPerRow - 1; + + if (context->CurrentAddress > context->Length) + context->CurrentAddress = context->Length - 1; + } + + PhpHexEditMove(hwnd, context, 0, 0); + context->SelEnd = context->CurrentAddress; + + REDRAW_WINDOW(hwnd); + break; + } + else + { + PhpHexEditSetSel(hwnd, context, -1, -1); + } + + if (GetKeyState(VK_CONTROL) < 0) + { + context->CurrentAddress = context->Length - 1; + + if (context->HalfPage) + { + SendMessage(hwnd, WM_VSCROLL, 0, 0); + } + else + { + SendMessage(hwnd, WM_VSCROLL, + MAKEWPARAM(SB_THUMBTRACK, ((context->Length + (context->BytesPerRow / 2)) / context->BytesPerRow) - context->LinesPerPage), + 0); + } + } + else + { + context->CurrentAddress /= context->BytesPerRow; + context->CurrentAddress *= context->BytesPerRow; + context->CurrentAddress += context->BytesPerRow - 1; + + if (context->CurrentAddress > context->Length) + context->CurrentAddress = context->Length - 1; + } + + PhpHexEditMove(hwnd, context, 0, 0); + noScrollIntoView = TRUE; + + break; + case VK_INSERT: + PhpHexEditSelInsert(hwnd, context, context->CurrentAddress, + max(1, context->SelEnd - context->SelStart)); + REDRAW_WINDOW(hwnd); + break; + case VK_DELETE: + if (PhpHexEditHasSelected(context)) + { + PhpHexEditClearEdit(hwnd, context); + } + else + { + PhpHexEditSelDelete(hwnd, context, context->CurrentAddress, context->CurrentAddress + 1); + REDRAW_WINDOW(hwnd); + } + break; + case '\t': + switch (context->CurrentMode) + { + case EDIT_NONE: + context->CurrentMode = EDIT_HIGH; + break; + case EDIT_HIGH: + case EDIT_LOW: + context->CurrentMode = EDIT_ASCII; + break; + case EDIT_ASCII: + context->CurrentMode = EDIT_HIGH; + break; + } + + PhpHexEditMove(hwnd, context, 0, 0); + + break; + } + + // Scroll into view if not in view. + if ( + !noScrollIntoView && + (context->CurrentAddress < context->TopIndex || + context->CurrentAddress >= context->TopIndex + context->LinesPerPage * context->BytesPerRow) + ) + { + PhpHexEditScrollTo(hwnd, context, context->CurrentAddress); + } + + context->NoAddressChange = oldNoAddressChange; + } + break; + case HEM_SETBUFFER: + { + PhpHexEditSetBuffer(hwnd, context, (PUCHAR)lParam, (ULONG)wParam); + } + return TRUE; + case HEM_SETDATA: + { + PhpHexEditSetData(hwnd, context, (PUCHAR)lParam, (ULONG)wParam); + } + return TRUE; + case HEM_GETBUFFER: + { + PULONG length = (PULONG)wParam; + + if (length) + *length = context->Length; + + return (LPARAM)context->Data; + } + case HEM_SETSEL: + { + LONG selStart = (LONG)wParam; + LONG selEnd = (LONG)lParam; + + if (selStart <= 0) + return FALSE; + if (selEnd > context->Length) + return FALSE; + + PhpHexEditScrollTo(hwnd, context, selStart); + PhpHexEditSetSel(hwnd, context, selStart, selEnd); + PhpHexEditRepositionCaret(hwnd, context, selStart); + REDRAW_WINDOW(hwnd); + } + return TRUE; + case HEM_SETEDITMODE: + { + context->CurrentMode = (LONG)wParam; + REDRAW_WINDOW(hwnd); + } + return TRUE; + case HEM_SETBYTESPERROW: + { + LONG bytesPerRow = (LONG)wParam; + + if (bytesPerRow >= 4) + { + context->BytesPerRow = bytesPerRow; + PhpHexEditUpdateMetrics(hwnd, context, TRUE, NULL); + PhpHexEditUpdateScrollbars(hwnd, context); + PhpHexEditScrollTo(hwnd, context, context->CurrentAddress); + PhpHexEditRepositionCaret(hwnd, context, context->CurrentAddress); + REDRAW_WINDOW(hwnd); + } + } + return TRUE; + } + +DefaultHandler: + return DefWindowProc(hwnd, uMsg, wParam, lParam); +} + +FORCEINLINE VOID PhpPrintHex( + _In_ HDC hdc, + _In_ PPHP_HEXEDIT_CONTEXT Context, + _Inout_ PWCHAR Buffer, + _In_ UCHAR Byte, + _Inout_ PLONG X, + _Inout_ PLONG Y, + _Inout_ PULONG N + ) +{ + PWCHAR p = Buffer; + + TO_HEX(p, Byte); + *p++ = ' '; + TextOut(hdc, *X, *Y, Buffer, 3); + *X += Context->NullWidth * 3; + (*N)++; + + if (*N == Context->BytesPerRow) + { + *N = 0; + *X = Context->HexOffset; + *Y += Context->LineHeight; + } +} + +FORCEINLINE VOID PhpPrintAscii( + _In_ HDC hdc, + _In_ PPHP_HEXEDIT_CONTEXT Context, + _In_ UCHAR Byte, + _Inout_ PLONG X, + _Inout_ PLONG Y, + _Inout_ PULONG N + ) +{ + WCHAR c; + + c = IS_PRINTABLE(Byte) ? Byte : '.'; + TextOut(hdc, *X, *Y, &c, 1); + *X += Context->NullWidth; + (*N)++; + + if (*N == Context->BytesPerRow) + { + *N = 0; + *X = Context->AsciiOffset; + *Y += Context->LineHeight; + } +} + +FORCEINLINE COLORREF GetLighterHighlightColor( + VOID + ) +{ + COLORREF color; + UCHAR r; + UCHAR g; + UCHAR b; + + color = GetSysColor(COLOR_HIGHLIGHT); + r = (UCHAR)color; + g = (UCHAR)(color >> 8); + b = (UCHAR)(color >> 16); + + if (r <= 255 - 64) + r += 64; + else + r = 255; + + if (g <= 255 - 64) + g += 64; + else + g = 255; + + if (b <= 255 - 64) + b += 64; + else + b = 255; + + return RGB(r, g, b); +} + +VOID PhpHexEditUpdateMetrics( + _In_ HWND hwnd, + _In_ PPHP_HEXEDIT_CONTEXT Context, + _In_ BOOLEAN UpdateLineHeight, + _In_opt_ HDC hdc + ) +{ + BOOLEAN freeHdc = FALSE; + RECT clientRect; + SIZE size; + + if (!hdc && UpdateLineHeight) + { + hdc = CreateCompatibleDC(hdc); + SelectObject(hdc, Context->Font); + freeHdc = TRUE; + } + + GetClientRect(hwnd, &clientRect); + + if (UpdateLineHeight) + { + GetCharWidth(hdc, '0', '0', &Context->NullWidth); + GetTextExtentPoint32(hdc, L"0", 1, &size); + Context->LineHeight = size.cy; + } + + Context->HexOffset = Context->ShowAddress ? (Context->AddressIsWide ? Context->NullWidth * 9 : Context->NullWidth * 5) : 0; + Context->AsciiOffset = Context->HexOffset + (Context->ShowHex ? (Context->BytesPerRow * 3 * Context->NullWidth) : 0); + + if (Context->LineHeight != 0) + { + Context->LinesPerPage = clientRect.bottom / Context->LineHeight; + Context->HalfPage = FALSE; + + if (Context->LinesPerPage * Context->BytesPerRow > Context->Length) + { + Context->LinesPerPage = (Context->Length + Context->BytesPerRow / 2) / Context->BytesPerRow; + + if (Context->Length % Context->BytesPerRow != 0) + { + Context->HalfPage = TRUE; + Context->LinesPerPage++; + } + } + } + + if (freeHdc && hdc) + DeleteDC(hdc); +} + +VOID PhpHexEditOnPaint( + _In_ HWND hwnd, + _In_ PPHP_HEXEDIT_CONTEXT Context, + _In_ PAINTSTRUCT *PaintStruct, + _In_ HDC hdc + ) +{ + RECT clientRect; + HDC bufferDc; + HBITMAP bufferBitmap; + HBITMAP oldBufferBitmap; + LONG height; + LONG x; + LONG y; + LONG i; + ULONG requiredBufferLength; + PWCHAR buffer; + + GetClientRect(hwnd, &clientRect); + + bufferDc = CreateCompatibleDC(hdc); + bufferBitmap = CreateCompatibleBitmap(hdc, clientRect.right, clientRect.bottom); + oldBufferBitmap = SelectObject(bufferDc, bufferBitmap); + + SetDCBrushColor(bufferDc, GetSysColor(COLOR_WINDOW)); + FillRect(bufferDc, &clientRect, GetStockObject(DC_BRUSH)); + SelectObject(bufferDc, Context->Font); + SetBoundsRect(bufferDc, &clientRect, DCB_DISABLE); + + requiredBufferLength = (max(8, Context->BytesPerRow * 3) + 1) * sizeof(WCHAR); + + if (Context->CharBufferLength < requiredBufferLength) + { + if (Context->CharBuffer) + PhFree(Context->CharBuffer); + + Context->CharBuffer = PhAllocate(requiredBufferLength); + Context->CharBufferLength = requiredBufferLength; + buffer = Context->CharBuffer; + } + + buffer = Context->CharBuffer; + + if (Context->Data) + { + // Get character dimensions. + if (Context->Update) + { + PhpHexEditUpdateMetrics(hwnd, Context, TRUE, bufferDc); + Context->Update = FALSE; + PhpHexEditUpdateScrollbars(hwnd, Context); + } + + height = (clientRect.bottom + Context->LineHeight - 1) / Context->LineHeight * Context->LineHeight; // round up to height + + if (Context->ShowAddress) + { + PH_FORMAT format; + ULONG w; + RECT rect; + + PhInitFormatX(&format, 0); + format.Type |= FormatPadZeros; + format.Width = Context->AddressIsWide ? 8 : 4; + + w = Context->AddressIsWide ? 8 : 4; + + rect = clientRect; + rect.left = Context->AddressOffset; + rect.top = 0; + + for (i = Context->TopIndex; i < Context->Length && rect.top < height; i += Context->BytesPerRow) + { + format.u.Int32 = i; + PhFormatToBuffer(&format, 1, buffer, requiredBufferLength, NULL); + DrawText(bufferDc, buffer, w, &rect, DT_LEFT | DT_TOP | DT_SINGLELINE | DT_NOPREFIX | DT_NOCLIP); + rect.top += Context->LineHeight; + } + } + + if (Context->ShowHex) + { + RECT rect; + LONG n = 0; + + x = Context->HexOffset; + y = 0; + rect = clientRect; + rect.left = x; + rect.top = 0; + + if (Context->SelStart != -1) + { + COLORREF highlightColor; + LONG selStart; + LONG selEnd; + + if (Context->CurrentMode == EDIT_HIGH || Context->CurrentMode == EDIT_LOW) + highlightColor = GetSysColor(COLOR_HIGHLIGHT); + else + highlightColor = GetLighterHighlightColor(); + + selStart = Context->SelStart; + selEnd = Context->SelEnd; + + if (selStart > selEnd) + { + ULONG t; + + t = selEnd; + selEnd = selStart; + selStart = t; + } + + if (selStart >= Context->Length) + selStart = Context->Length - 1; + if (selEnd > Context->Length) + selEnd = Context->Length; + + // Bytes before the selection + + for (i = Context->TopIndex; i < selStart && y < height; i++) + { + PhpPrintHex(bufferDc, Context, buffer, Context->Data[i], &x, &y, &n); + } + + // Bytes in the selection + + SetTextColor(bufferDc, GetSysColor(COLOR_HIGHLIGHTTEXT)); + SetBkColor(bufferDc, highlightColor); + + for (; i < selEnd && i < Context->Length && y < height; i++) + { + PhpPrintHex(bufferDc, Context, buffer, Context->Data[i], &x, &y, &n); + } + + // Bytes after the selection + + SetTextColor(bufferDc, GetSysColor(COLOR_WINDOWTEXT)); + SetBkColor(bufferDc, GetSysColor(COLOR_WINDOW)); + + for (; i < Context->Length && y < height; i++) + { + PhpPrintHex(bufferDc, Context, buffer, Context->Data[i], &x, &y, &n); + } + } + else + { + i = Context->TopIndex; + + while (i < Context->Length && rect.top < height) + { + PWCHAR p = buffer; + + for (n = 0; n < Context->BytesPerRow && i < Context->Length; n++) + { + TO_HEX(p, Context->Data[i]); + *p++ = ' '; + i++; + } + + while (n < Context->BytesPerRow) + { + p[0] = ' '; + p[1] = ' '; + p[2] = ' '; + p += 3; + n++; + } + + DrawText(bufferDc, buffer, Context->BytesPerRow * 3, &rect, DT_LEFT | DT_TOP | DT_SINGLELINE | DT_NOPREFIX | DT_NOCLIP); + rect.top += Context->LineHeight; + } + } + } + + if (Context->ShowAscii) + { + RECT rect; + LONG n = 0; + + x = Context->AsciiOffset; + y = 0; + rect = clientRect; + rect.left = x; + rect.top = 0; + + if (Context->SelStart != -1) + { + COLORREF highlightColor; + LONG selStart; + LONG selEnd; + + if (Context->CurrentMode == EDIT_ASCII) + highlightColor = GetSysColor(COLOR_HIGHLIGHT); + else + highlightColor = GetLighterHighlightColor(); + + selStart = Context->SelStart; + selEnd = Context->SelEnd; + + if (selStart > selEnd) + { + LONG t; + + t = selEnd; + selEnd = selStart; + selStart = t; + } + + if (selStart >= Context->Length) + selStart = Context->Length - 1; + if (selEnd > Context->Length) + selEnd = Context->Length; + + // Bytes before the selection + + for (i = Context->TopIndex; i < selStart && y < height; i++) + { + PhpPrintAscii(bufferDc, Context, Context->Data[i], &x, &y, &n); + } + + // Bytes in the selection + + SetTextColor(bufferDc, GetSysColor(COLOR_HIGHLIGHTTEXT)); + SetBkColor(bufferDc, highlightColor); + + for (; i < selEnd && i < Context->Length && y < height; i++) + { + PhpPrintAscii(bufferDc, Context, Context->Data[i], &x, &y, &n); + } + + // Bytes after the selection + + SetTextColor(bufferDc, GetSysColor(COLOR_WINDOWTEXT)); + SetBkColor(bufferDc, GetSysColor(COLOR_WINDOW)); + + for (; i < Context->Length && y < height; i++) + { + PhpPrintAscii(bufferDc, Context, Context->Data[i], &x, &y, &n); + } + } + else + { + i = Context->TopIndex; + + while (i < Context->Length && rect.top < height) + { + PWCHAR p = buffer; + + for (n = 0; n < Context->BytesPerRow && i < Context->Length; n++) + { + *p++ = IS_PRINTABLE(Context->Data[i]) ? Context->Data[i] : '.'; // 1 + i++; + } + + DrawText(bufferDc, buffer, n, &rect, DT_LEFT | DT_TOP | DT_SINGLELINE | DT_NOPREFIX | DT_NOCLIP); + rect.top += Context->LineHeight; + } + } + } + } + + BitBlt(hdc, 0, 0, clientRect.right, clientRect.bottom, bufferDc, 0, 0, SRCCOPY); + SelectObject(bufferDc, oldBufferBitmap); + DeleteObject(bufferBitmap); + DeleteDC(bufferDc); +} + +VOID PhpHexEditUpdateScrollbars( + _In_ HWND hwnd, + _In_ PPHP_HEXEDIT_CONTEXT Context + ) +{ + SCROLLINFO si = { sizeof(si) }; + + si.fMask = SIF_ALL; + si.nMin = 0; + si.nMax = (Context->Length / Context->BytesPerRow) - 1; + si.nPage = Context->LinesPerPage; + si.nPos = Context->TopIndex / Context->BytesPerRow; + SetScrollInfo(hwnd, SB_VERT, &si, TRUE); + + if (si.nMax > (LONG)si.nPage) + EnableScrollBar(hwnd, SB_VERT, ESB_ENABLE_BOTH); + + // No horizontal scrollbar please. + /*si.nMin = 0; + si.nMax = ((Context->ShowAddress ? (Context->AddressIsWide ? 8 : 4) : 0) + + (Context->ShowHex ? Context->BytesPerRow * 3 : 0) + + (Context->ShowAscii ? Context->BytesPerRow : 0)) * Context->NullWidth; + si.nPage = 1; + si.nPos = 0; + SetScrollInfo(hwnd, SB_HORZ, &si, TRUE);*/ +} + +VOID PhpHexEditCreateAddressCaret( + _In_ HWND hwnd, + _In_ PPHP_HEXEDIT_CONTEXT Context + ) +{ + DestroyCaret(); + CreateCaret(hwnd, NULL, Context->NullWidth * (Context->AddressIsWide ? 8 : 4), Context->LineHeight); +} + +VOID PhpHexEditCreateEditCaret( + _In_ HWND hwnd, + _In_ PPHP_HEXEDIT_CONTEXT Context + ) +{ + DestroyCaret(); + CreateCaret(hwnd, NULL, Context->NullWidth, Context->LineHeight); +} + +VOID PhpHexEditRepositionCaret( + _In_ HWND hwnd, + _In_ PPHP_HEXEDIT_CONTEXT Context, + _In_ LONG Position + ) +{ + ULONG x; + ULONG y; + RECT rect; + + x = (Position - Context->TopIndex) % Context->BytesPerRow; + y = (Position - Context->TopIndex) / Context->BytesPerRow; + + switch (Context->CurrentMode) + { + case EDIT_NONE: + PhpHexEditCreateAddressCaret(hwnd, Context); + x = 0; + break; + case EDIT_HIGH: + PhpHexEditCreateEditCaret(hwnd, Context); + x *= Context->NullWidth * 3; + x += Context->HexOffset; + break; + case EDIT_LOW: + PhpHexEditCreateEditCaret(hwnd, Context); + x *= Context->NullWidth * 3; + x += Context->NullWidth; + x += Context->HexOffset; + break; + case EDIT_ASCII: + PhpHexEditCreateEditCaret(hwnd, Context); + x *= Context->NullWidth; + x += Context->AsciiOffset; + break; + } + + Context->EditPosition.x = x; + Context->EditPosition.y = y * Context->LineHeight; + + GetClientRect(hwnd, &rect); + + if (PtInRect(&rect, Context->EditPosition)) + { + SetCaretPos(Context->EditPosition.x, Context->EditPosition.y); + ShowCaret(hwnd); + } +} + +VOID PhpHexEditCalculatePosition( + _In_ HWND hwnd, + _In_ PPHP_HEXEDIT_CONTEXT Context, + _In_ LONG X, + _In_ LONG Y, + _Out_ POINT *Point + ) +{ + LONG xp; + + Y /= Context->LineHeight; + + if (Y < 0 || Y >= Context->LinesPerPage) + { + Point->x = -1; + Point->y = -1; + return; + } + + if (Y * Context->BytesPerRow >= Context->Length) + { + Point->x = -1; + Point->y = -1; + return; + } + + X += Context->NullWidth; + X /= Context->NullWidth; + + if (Context->ShowAddress && X <= (Context->AddressIsWide ? 8 : 4)) + { + Context->CurrentAddress = Context->TopIndex + Context->BytesPerRow * Y; + Context->CurrentMode = EDIT_NONE; + + Point->x = 0; + Point->y = Y; + return; + } + + xp = Context->HexOffset / Context->NullWidth + Context->BytesPerRow * 3; + + if (Context->ShowHex && X < xp) + { + if (X % 3) + X--; + + Context->CurrentAddress = Context->TopIndex + + Context->BytesPerRow * Y + + (X - (Context->HexOffset / Context->NullWidth)) / 3; + Context->CurrentMode = ((X % 3) & 1) ? EDIT_LOW : EDIT_HIGH; + + Point->x = X; + Point->y = Y; + return; + } + + X--; // fix selection problem + + xp = Context->AsciiOffset / Context->NullWidth + Context->BytesPerRow; + + if (Context->ShowAscii && X * Context->NullWidth >= Context->AsciiOffset && X <= xp) + { + Context->CurrentAddress = Context->TopIndex + + Context->BytesPerRow * Y + + (X - (Context->AsciiOffset / Context->NullWidth)); + Context->CurrentMode = EDIT_ASCII; + + Point->x = X; + Point->y = Y; + return; + } + + Point->x = -1; + Point->y = -1; +} + +VOID PhpHexEditMove( + _In_ HWND hwnd, + _In_ PPHP_HEXEDIT_CONTEXT Context, + _In_ LONG X, + _In_ LONG Y + ) +{ + switch (Context->CurrentMode) + { + case EDIT_NONE: + Context->CurrentAddress += Y * Context->BytesPerRow; + break; + case EDIT_HIGH: + if (X != 0) + Context->CurrentMode = EDIT_LOW; + if (X == -1) + Context->CurrentAddress--; + Context->CurrentAddress += Y * Context->BytesPerRow; + break; + case EDIT_LOW: + if (X != 0) + Context->CurrentMode = EDIT_HIGH; + if (X == 1) + Context->CurrentAddress++; + Context->CurrentAddress += Y * Context->BytesPerRow; + break; + case EDIT_ASCII: + Context->CurrentAddress += X; + Context->CurrentAddress += Y * Context->BytesPerRow; + break; + } + + if (Context->CurrentAddress < 0) + Context->CurrentAddress = 0; + + if (Context->CurrentAddress >= Context->Length) + { + Context->CurrentAddress -= X; + Context->CurrentAddress -= Y * Context->BytesPerRow; + } + + Context->NoAddressChange = TRUE; + + if (Context->CurrentAddress < Context->TopIndex) + SendMessage(hwnd, WM_VSCROLL, SB_LINEUP, 0); + if (Context->CurrentAddress >= Context->TopIndex + Context->LinesPerPage * Context->BytesPerRow) + SendMessage(hwnd, WM_VSCROLL, SB_LINEDOWN, 0); + + Context->NoAddressChange = FALSE; + PhpHexEditRepositionCaret(hwnd, Context, Context->CurrentAddress); +} + +VOID PhpHexEditSetSel( + _In_ HWND hwnd, + _In_ PPHP_HEXEDIT_CONTEXT Context, + _In_ LONG S, + _In_ LONG E + ) +{ + DestroyCaret(); + Context->SelStart = S; + Context->SelEnd = E; + REDRAW_WINDOW(hwnd); + + if (S != -1 && E != -1) + { + Context->CurrentAddress = S; + } + else + { + if (Context->EditPosition.x == 0 && Context->ShowAddress) + PhpHexEditCreateAddressCaret(hwnd, Context); + else + PhpHexEditCreateEditCaret(hwnd, Context); + + SetCaretPos(Context->EditPosition.x, Context->EditPosition.y); + ShowCaret(hwnd); + } +} + +VOID PhpHexEditScrollTo( + _In_ HWND hwnd, + _In_ PPHP_HEXEDIT_CONTEXT Context, + _In_ LONG Position + ) +{ + if (Position < Context->TopIndex || Position > Context->TopIndex + Context->LinesPerPage * Context->BytesPerRow) + { + Context->TopIndex = Position / Context->BytesPerRow * Context->BytesPerRow; // round down + Context->TopIndex -= Context->LinesPerPage / 3 * Context->BytesPerRow; + + if (Context->TopIndex < 0) + Context->TopIndex = 0; + + if (Context->Length >= Context->LinesPerPage * Context->BytesPerRow) + { + if (Context->TopIndex > Context->Length - Context->LinesPerPage * Context->BytesPerRow) + Context->TopIndex = Context->Length - Context->LinesPerPage * Context->BytesPerRow; + } + + PhpHexEditUpdateScrollbars(hwnd, Context); + REDRAW_WINDOW(hwnd); + } +} + +VOID PhpHexEditClearEdit( + _In_ HWND hwnd, + _In_ PPHP_HEXEDIT_CONTEXT Context + ) +{ + if (Context->AllowLengthChange) + { + Context->CurrentAddress = Context->SelStart; + PhpHexEditSelDelete(hwnd, Context, Context->SelStart, Context->SelEnd); + PhpHexEditRepositionCaret(hwnd, Context, Context->CurrentAddress); + REDRAW_WINDOW(hwnd); + } +} + +VOID PhpHexEditCopyEdit( + _In_ HWND hwnd, + _In_ PPHP_HEXEDIT_CONTEXT Context + ) +{ + if (OpenClipboard(hwnd)) + { + EmptyClipboard(); + PhpHexEditNormalizeSel(hwnd, Context); + + if (Context->CurrentMode != EDIT_ASCII) + { + ULONG length = Context->SelEnd - Context->SelStart; + HGLOBAL binaryMemory; + HGLOBAL hexMemory; + + binaryMemory = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, length); + + if (binaryMemory) + { + PUCHAR p = GlobalLock(binaryMemory); + memcpy(p, &Context->Data[Context->SelStart], length); + GlobalUnlock(binaryMemory); + + hexMemory = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, (length * 3 + 1) * sizeof(WCHAR)); + + if (hexMemory) + { + PWCHAR pw; + ULONG i; + + pw = GlobalLock(hexMemory); + + for (i = 0; i < length; i++) + { + TO_HEX(pw, Context->Data[Context->SelStart + i]); + *pw++ = ' '; + } + *pw = 0; + + GlobalUnlock(hexMemory); + + SetClipboardData(CF_UNICODETEXT, hexMemory); + } + + SetClipboardData(RegisterClipboardFormat(L"BinaryData"), binaryMemory); + } + } + else + { + ULONG length = Context->SelEnd - Context->SelStart; + HGLOBAL binaryMemory; + HGLOBAL asciiMemory; + + binaryMemory = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, length); + asciiMemory = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, length + 1); + + if (binaryMemory) + { + PUCHAR p = GlobalLock(binaryMemory); + memcpy(p, &Context->Data[Context->SelStart], length); + GlobalUnlock(binaryMemory); + + if (asciiMemory) + { + ULONG i; + + p = GlobalLock(asciiMemory); + memcpy(p, &Context->Data[Context->SelStart], length); + + for (i = 0; i < length; i++) + { + if (!IS_PRINTABLE(*p)) + *p = '.'; + p++; + } + *p = 0; + + GlobalUnlock(asciiMemory); + + SetClipboardData(CF_TEXT, asciiMemory); + } + + SetClipboardData(RegisterClipboardFormat(L"BinaryData"), binaryMemory); + } + } + + CloseClipboard(); + } +} + +VOID PhpHexEditCutEdit( + _In_ HWND hwnd, + _In_ PPHP_HEXEDIT_CONTEXT Context + ) +{ + if (Context->AllowLengthChange) + { + PhpHexEditCopyEdit(hwnd, Context); + PhpHexEditSelDelete(hwnd, Context, Context->SelStart, Context->SelEnd); + REDRAW_WINDOW(hwnd); + } +} + +VOID PhpHexEditPasteEdit( + _In_ HWND hwnd, + _In_ PPHP_HEXEDIT_CONTEXT Context + ) +{ + if (OpenClipboard(hwnd)) + { + HANDLE memory; + + memory = GetClipboardData(RegisterClipboardFormat(L"BinaryData")); + + if (!memory) + memory = GetClipboardData(CF_TEXT); + + if (memory) + { + PUCHAR p = GlobalLock(memory); + ULONG length = (ULONG)GlobalSize(memory); + ULONG paste; + ULONG oldCurrentAddress = Context->CurrentAddress; + + PhpHexEditNormalizeSel(hwnd, Context); + + if (Context->AllowLengthChange) + { + if (Context->SelStart == -1) + { + if (Context->CurrentMode == EDIT_LOW) + Context->CurrentAddress++; + + paste = Context->CurrentAddress; + PhpHexEditSelInsert(hwnd, Context, Context->CurrentAddress, length); + } + else + { + paste = Context->SelStart; + PhpHexEditSelDelete(hwnd, Context, Context->SelStart, Context->SelEnd); + PhpHexEditSelInsert(hwnd, Context, paste, length); + PhpHexEditSetSel(hwnd, Context, -1, -1); + } + } + else + { + if (Context->SelStart == -1) + { + if (Context->CurrentMode == EDIT_LOW) + Context->CurrentAddress++; + + paste = Context->CurrentAddress; + } + else + { + paste = Context->SelStart; + } + + if (length > Context->Length - paste) + length = Context->Length - paste; + } + + memcpy(&Context->Data[paste], p, length); + GlobalUnlock(memory); + + Context->CurrentAddress = oldCurrentAddress; + REDRAW_WINDOW(hwnd); + } + + CloseClipboard(); + } +} + +VOID PhpHexEditSelectAll( + _In_ HWND hwnd, + _In_ PPHP_HEXEDIT_CONTEXT Context + ) +{ + Context->SelStart = 0; + Context->SelEnd = Context->Length; + DestroyCaret(); + REDRAW_WINDOW(hwnd); +} + +VOID PhpHexEditUndoEdit( + _In_ HWND hwnd, + _In_ PPHP_HEXEDIT_CONTEXT Context + ) +{ + // TODO +} + +VOID PhpHexEditNormalizeSel( + _In_ HWND hwnd, + _In_ PPHP_HEXEDIT_CONTEXT Context + ) +{ + if (Context->SelStart > Context->SelEnd) + { + LONG t; + + t = Context->SelEnd; + Context->SelEnd = Context->SelStart; + Context->SelStart = t; + } +} + +VOID PhpHexEditSelDelete( + _In_ HWND hwnd, + _In_ PPHP_HEXEDIT_CONTEXT Context, + _In_ LONG S, + _In_ LONG E + ) +{ + if (Context->AllowLengthChange && Context->Length > 0) + { + PUCHAR p = PhAllocate(Context->Length - (E - S) + 1); + + memcpy(p, Context->Data, S); + + if (S < Context->Length - (E - S)) + memcpy(&p[S], &Context->Data[E], Context->Length - E); + + PhFree(Context->Data); + Context->Data = p; + PhpHexEditSetSel(hwnd, Context, -1, -1); + Context->Length -= E - S; + + if (Context->CurrentAddress > Context->Length) + { + Context->CurrentAddress = Context->Length; + PhpHexEditRepositionCaret(hwnd, Context, Context->CurrentAddress); + } + + Context->Update = TRUE; + } +} + +VOID PhpHexEditSelInsert( + _In_ HWND hwnd, + _In_ PPHP_HEXEDIT_CONTEXT Context, + _In_ LONG S, + _In_ LONG L + ) +{ + if (Context->AllowLengthChange) + { + PUCHAR p = PhAllocate(Context->Length + L); + + memset(p, 0, Context->Length + L); + memcpy(p, Context->Data, S); + memcpy(&p[S + L], &Context->Data[S], Context->Length - S); + + PhFree(Context->Data); + Context->Data = p; + PhpHexEditSetSel(hwnd, Context, -1, -1); + Context->Length += L; + + Context->Update = TRUE; + } +} + +VOID PhpHexEditSetBuffer( + _In_ HWND hwnd, + _In_ PPHP_HEXEDIT_CONTEXT Context, + _In_ PUCHAR Data, + _In_ ULONG Length + ) +{ + Context->Data = Data; + PhpHexEditSetSel(hwnd, Context, -1, -1); + Context->Length = Length; + Context->CurrentAddress = 0; + Context->EditPosition.x = Context->EditPosition.y = 0; + Context->CurrentMode = EDIT_HIGH; + Context->TopIndex = 0; + Context->Update = TRUE; + + Context->UserBuffer = TRUE; + Context->AllowLengthChange = FALSE; +} + +VOID PhpHexEditSetData( + _In_ HWND hwnd, + _In_ PPHP_HEXEDIT_CONTEXT Context, + _In_ PUCHAR Data, + _In_ ULONG Length + ) +{ + if (Context->Data) PhFree(Context->Data); + Context->Data = PhAllocate(Length); + memcpy(Context->Data, Data, Length); + PhpHexEditSetBuffer(hwnd, Context, Context->Data, Length); + Context->UserBuffer = FALSE; + Context->AllowLengthChange = TRUE; +} diff --git a/phlib/hndlinfo.c b/phlib/hndlinfo.c index 5c0109acc8d0..749a6d91ccb9 100644 --- a/phlib/hndlinfo.c +++ b/phlib/hndlinfo.c @@ -1,1776 +1,1776 @@ -/* - * Process Hacker - - * handle information - * - * Copyright (C) 2010-2015 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include -#include - -#include -#include - -#define PH_QUERY_HACK_MAX_THREADS 20 - -typedef struct _PHP_CALL_WITH_TIMEOUT_THREAD_CONTEXT -{ - SLIST_ENTRY ListEntry; - - PUSER_THREAD_START_ROUTINE Routine; - PVOID Context; - - HANDLE StartEventHandle; - HANDLE CompletedEventHandle; - HANDLE ThreadHandle; -} PHP_CALL_WITH_TIMEOUT_THREAD_CONTEXT, *PPHP_CALL_WITH_TIMEOUT_THREAD_CONTEXT; - -typedef enum _PHP_QUERY_OBJECT_WORK -{ - NtQueryObjectWork, - NtQuerySecurityObjectWork, - NtSetSecurityObjectWork -} PHP_QUERY_OBJECT_WORK; - -typedef struct _PHP_QUERY_OBJECT_COMMON_CONTEXT -{ - PHP_QUERY_OBJECT_WORK Work; - NTSTATUS Status; - - union - { - struct - { - HANDLE Handle; - OBJECT_INFORMATION_CLASS ObjectInformationClass; - PVOID ObjectInformation; - ULONG ObjectInformationLength; - PULONG ReturnLength; - } NtQueryObject; - struct - { - HANDLE Handle; - SECURITY_INFORMATION SecurityInformation; - PSECURITY_DESCRIPTOR SecurityDescriptor; - ULONG Length; - PULONG LengthNeeded; - } NtQuerySecurityObject; - struct - { - HANDLE Handle; - SECURITY_INFORMATION SecurityInformation; - PSECURITY_DESCRIPTOR SecurityDescriptor; - } NtSetSecurityObject; - } u; -} PHP_QUERY_OBJECT_COMMON_CONTEXT, *PPHP_QUERY_OBJECT_COMMON_CONTEXT; - -PPHP_CALL_WITH_TIMEOUT_THREAD_CONTEXT PhpAcquireCallWithTimeoutThread( - _In_opt_ PLARGE_INTEGER Timeout - ); - -VOID PhpReleaseCallWithTimeoutThread( - _Inout_ PPHP_CALL_WITH_TIMEOUT_THREAD_CONTEXT ThreadContext - ); - -NTSTATUS PhpCallWithTimeout( - _Inout_ PPHP_CALL_WITH_TIMEOUT_THREAD_CONTEXT ThreadContext, - _In_ PUSER_THREAD_START_ROUTINE Routine, - _In_opt_ PVOID Context, - _In_ PLARGE_INTEGER Timeout - ); - -NTSTATUS PhpCallWithTimeoutThreadStart( - _In_ PVOID Parameter - ); - -static PPH_STRING PhObjectTypeNames[MAX_OBJECT_TYPE_NUMBER] = { 0 }; -static PPH_GET_CLIENT_ID_NAME PhHandleGetClientIdName = PhStdGetClientIdName; - -static SLIST_HEADER PhpCallWithTimeoutThreadListHead; -static PH_WAKE_EVENT PhpCallWithTimeoutThreadReleaseEvent = PH_WAKE_EVENT_INIT; - -PPH_GET_CLIENT_ID_NAME PhSetHandleClientIdFunction( - _In_ PPH_GET_CLIENT_ID_NAME GetClientIdName - ) -{ - return _InterlockedExchangePointer( - (PVOID *)&PhHandleGetClientIdName, - GetClientIdName - ); -} - -NTSTATUS PhpGetObjectBasicInformation( - _In_ HANDLE ProcessHandle, - _In_ HANDLE Handle, - _Out_ POBJECT_BASIC_INFORMATION BasicInformation - ) -{ - NTSTATUS status; - - if (KphIsConnected()) - { - status = KphQueryInformationObject( - ProcessHandle, - Handle, - KphObjectBasicInformation, - BasicInformation, - sizeof(OBJECT_BASIC_INFORMATION), - NULL - ); - - if (NT_SUCCESS(status)) - { - // The object was referenced in KProcessHacker, so we need to subtract 1 from the - // pointer count. - BasicInformation->PointerCount -= 1; - } - } - else - { - status = NtQueryObject( - Handle, - ObjectBasicInformation, - BasicInformation, - sizeof(OBJECT_BASIC_INFORMATION), - NULL - ); - - if (NT_SUCCESS(status)) - { - // The object was referenced in NtQueryObject and a handle was opened to the object. We - // need to subtract 1 from the pointer count, then subtract 1 from both counts. - BasicInformation->HandleCount -= 1; - BasicInformation->PointerCount -= 2; - } - } - - return status; -} - -NTSTATUS PhpGetObjectTypeName( - _In_ HANDLE ProcessHandle, - _In_ HANDLE Handle, - _In_ ULONG ObjectTypeNumber, - _Out_ PPH_STRING *TypeName - ) -{ - NTSTATUS status = STATUS_SUCCESS; - PPH_STRING typeName = NULL; - - // If the cache contains the object type name, use it. Otherwise, query the type name. - - if (ObjectTypeNumber != -1 && ObjectTypeNumber < MAX_OBJECT_TYPE_NUMBER) - typeName = PhObjectTypeNames[ObjectTypeNumber]; - - if (typeName) - { - PhReferenceObject(typeName); - } - else - { - POBJECT_TYPE_INFORMATION buffer; - ULONG returnLength = 0; - PPH_STRING oldTypeName; - - // Get the needed buffer size. - if (KphIsConnected()) - { - status = KphQueryInformationObject( - ProcessHandle, - Handle, - KphObjectTypeInformation, - NULL, - 0, - &returnLength - ); - } - else - { - status = NtQueryObject( - Handle, - ObjectTypeInformation, - NULL, - 0, - &returnLength - ); - } - - if (returnLength == 0) - return status; - - buffer = PhAllocate(returnLength); - - if (KphIsConnected()) - { - status = KphQueryInformationObject( - ProcessHandle, - Handle, - KphObjectTypeInformation, - buffer, - returnLength, - &returnLength - ); - } - else - { - status = NtQueryObject( - Handle, - ObjectTypeInformation, - buffer, - returnLength, - &returnLength - ); - } - - if (!NT_SUCCESS(status)) - { - PhFree(buffer); - return status; - } - - // Create a copy of the type name. - typeName = PhCreateStringFromUnicodeString(&buffer->TypeName); - - if (ObjectTypeNumber != -1 && ObjectTypeNumber < MAX_OBJECT_TYPE_NUMBER) - { - // Try to store the type name in the cache. - oldTypeName = _InterlockedCompareExchangePointer( - &PhObjectTypeNames[ObjectTypeNumber], - typeName, - NULL - ); - - // Add a reference if we stored the type name - // successfully. - if (!oldTypeName) - PhReferenceObject(typeName); - } - - PhFree(buffer); - } - - // At this point typeName should contain a type name with one additional reference. - - *TypeName = typeName; - - return status; -} - -NTSTATUS PhpGetObjectName( - _In_ HANDLE ProcessHandle, - _In_ HANDLE Handle, - _In_ BOOLEAN WithTimeout, - _Out_ PPH_STRING *ObjectName - ) -{ - NTSTATUS status; - POBJECT_NAME_INFORMATION buffer; - ULONG bufferSize; - ULONG attempts = 8; - - bufferSize = 0x200; - buffer = PhAllocate(bufferSize); - - // A loop is needed because the I/O subsystem likes to give us the wrong return lengths... - do - { - if (KphIsConnected()) - { - status = KphQueryInformationObject( - ProcessHandle, - Handle, - KphObjectNameInformation, - buffer, - bufferSize, - &bufferSize - ); - } - else - { - if (WithTimeout) - { - status = PhCallNtQueryObjectWithTimeout( - Handle, - ObjectNameInformation, - buffer, - bufferSize, - &bufferSize - ); - } - else - { - status = NtQueryObject( - Handle, - ObjectNameInformation, - buffer, - bufferSize, - &bufferSize - ); - } - } - - if (status == STATUS_BUFFER_OVERFLOW || status == STATUS_INFO_LENGTH_MISMATCH || - status == STATUS_BUFFER_TOO_SMALL) - { - PhFree(buffer); - buffer = PhAllocate(bufferSize); - } - else - { - break; - } - } while (--attempts); - - if (NT_SUCCESS(status)) - { - *ObjectName = PhCreateStringFromUnicodeString(&buffer->Name); - } - - PhFree(buffer); - - return status; -} - -PPH_STRING PhFormatNativeKeyName( - _In_ PPH_STRING Name - ) -{ - static PH_STRINGREF hklmPrefix = PH_STRINGREF_INIT(L"\\Registry\\Machine"); - static PH_STRINGREF hkcrPrefix = PH_STRINGREF_INIT(L"\\Registry\\Machine\\Software\\Classes"); - static PH_STRINGREF hkuPrefix = PH_STRINGREF_INIT(L"\\Registry\\User"); - static PPH_STRING hkcuPrefix; - static PPH_STRING hkcucrPrefix; - - static PH_STRINGREF hklmString = PH_STRINGREF_INIT(L"HKLM"); - static PH_STRINGREF hkcrString = PH_STRINGREF_INIT(L"HKCR"); - static PH_STRINGREF hkuString = PH_STRINGREF_INIT(L"HKU"); - static PH_STRINGREF hkcuString = PH_STRINGREF_INIT(L"HKCU"); - static PH_STRINGREF hkcucrString = PH_STRINGREF_INIT(L"HKCU\\Software\\Classes"); - - static PH_INITONCE initOnce = PH_INITONCE_INIT; - - PPH_STRING newName; - PH_STRINGREF name; - - if (PhBeginInitOnce(&initOnce)) - { - HANDLE currentTokenHandle; - PTOKEN_USER tokenUser; - PPH_STRING stringSid = NULL; - - currentTokenHandle = PhGetOwnTokenAttributes().TokenHandle; - - if (currentTokenHandle && NT_SUCCESS(PhGetTokenUser( - currentTokenHandle, - &tokenUser - ))) - { - stringSid = PhSidToStringSid(tokenUser->User.Sid); - PhFree(tokenUser); - } - - if (stringSid) - { - static PH_STRINGREF registryUserPrefix = PH_STRINGREF_INIT(L"\\Registry\\User\\"); - static PH_STRINGREF classesString = PH_STRINGREF_INIT(L"_Classes"); - - hkcuPrefix = PhConcatStringRef2(®istryUserPrefix, &stringSid->sr); - hkcucrPrefix = PhConcatStringRef2(&hkcuPrefix->sr, &classesString); - - PhDereferenceObject(stringSid); - } - else - { - hkcuPrefix = PhCreateString(L"..."); // some random string that won't ever get matched - hkcucrPrefix = PhCreateString(L"..."); - } - - PhEndInitOnce(&initOnce); - } - - name = Name->sr; - - if (PhStartsWithStringRef(&name, &hkcrPrefix, TRUE)) - { - PhSkipStringRef(&name, hkcrPrefix.Length); - newName = PhConcatStringRef2(&hkcrString, &name); - } - else if (PhStartsWithStringRef(&name, &hklmPrefix, TRUE)) - { - PhSkipStringRef(&name, hklmPrefix.Length); - newName = PhConcatStringRef2(&hklmString, &name); - } - else if (PhStartsWithStringRef(&name, &hkcucrPrefix->sr, TRUE)) - { - PhSkipStringRef(&name, hkcucrPrefix->Length); - newName = PhConcatStringRef2(&hkcucrString, &name); - } - else if (PhStartsWithStringRef(&name, &hkcuPrefix->sr, TRUE)) - { - PhSkipStringRef(&name, hkcuPrefix->Length); - newName = PhConcatStringRef2(&hkcuString, &name); - } - else if (PhStartsWithStringRef(&name, &hkuPrefix, TRUE)) - { - PhSkipStringRef(&name, hkuPrefix.Length); - newName = PhConcatStringRef2(&hkuString, &name); - } - else - { - PhSetReference(&newName, Name); - } - - return newName; -} - -NTSTATUS PhGetSectionFileName( - _In_ HANDLE SectionHandle, - _Out_ PPH_STRING *FileName - ) -{ - NTSTATUS status; - SIZE_T viewSize; - PVOID viewBase; - - viewSize = 1; - viewBase = NULL; - - status = NtMapViewOfSection( - SectionHandle, - NtCurrentProcess(), - &viewBase, - 0, - 0, - NULL, - &viewSize, - ViewShare, - 0, - PAGE_READONLY - ); - - if (!NT_SUCCESS(status)) - return status; - - status = PhGetProcessMappedFileName(NtCurrentProcess(), viewBase, FileName); - NtUnmapViewOfSection(NtCurrentProcess(), viewBase); - - return status; -} - -_Callback_ PPH_STRING PhStdGetClientIdName( - _In_ PCLIENT_ID ClientId - ) -{ - static PH_QUEUED_LOCK cachedProcessesLock = PH_QUEUED_LOCK_INIT; - static PVOID processes = NULL; - static ULONG lastProcessesTickCount = 0; - - PPH_STRING name; - ULONG tickCount; - PSYSTEM_PROCESS_INFORMATION processInfo; - - // Get a new process list only if 2 seconds have passed since the last update. - - tickCount = GetTickCount(); - - if (tickCount - lastProcessesTickCount >= 2000) - { - PhAcquireQueuedLockExclusive(&cachedProcessesLock); - - // Re-check the tick count. - if (tickCount - lastProcessesTickCount >= 2000) - { - if (processes) - { - PhFree(processes); - processes = NULL; - } - - if (!NT_SUCCESS(PhEnumProcesses(&processes))) - { - PhReleaseQueuedLockExclusive(&cachedProcessesLock); - return PhCreateString(L"(Error querying processes)"); - } - - lastProcessesTickCount = tickCount; - } - - PhReleaseQueuedLockExclusive(&cachedProcessesLock); - } - - // Get a lock on the process list and get a name for the client ID. - - PhAcquireQueuedLockShared(&cachedProcessesLock); - - if (!processes) - { - PhReleaseQueuedLockShared(&cachedProcessesLock); - return NULL; - } - - processInfo = PhFindProcessInformation(processes, ClientId->UniqueProcess); - - if (ClientId->UniqueThread) - { - if (processInfo) - { - name = PhFormatString( - L"%.*s (%u): %u", - processInfo->ImageName.Length / 2, - processInfo->ImageName.Buffer, - HandleToUlong(ClientId->UniqueProcess), - HandleToUlong(ClientId->UniqueThread) - ); - } - else - { - name = PhFormatString( - L"Non-existent process (%u): %u", - HandleToUlong(ClientId->UniqueProcess), - HandleToUlong(ClientId->UniqueThread) - ); - } - } - else - { - if (processInfo) - { - name = PhFormatString( - L"%.*s (%u)", - processInfo->ImageName.Length / 2, - processInfo->ImageName.Buffer, - HandleToUlong(ClientId->UniqueProcess) - ); - } - else - { - name = PhFormatString(L"Non-existent process (%u)", HandleToUlong(ClientId->UniqueProcess)); - } - } - - PhReleaseQueuedLockShared(&cachedProcessesLock); - - return name; -} - -NTSTATUS PhpGetBestObjectName( - _In_ HANDLE ProcessHandle, - _In_ HANDLE Handle, - _In_ PPH_STRING ObjectName, - _In_ PPH_STRING TypeName, - _Out_ PPH_STRING *BestObjectName - ) -{ - NTSTATUS status; - PPH_STRING bestObjectName = NULL; - PPH_GET_CLIENT_ID_NAME handleGetClientIdName = PhHandleGetClientIdName; - - if (PhEqualString2(TypeName, L"EtwRegistration", TRUE)) - { - if (KphIsConnected()) - { - ETWREG_BASIC_INFORMATION basicInfo; - - status = KphQueryInformationObject( - ProcessHandle, - Handle, - KphObjectEtwRegBasicInformation, - &basicInfo, - sizeof(ETWREG_BASIC_INFORMATION), - NULL - ); - - if (NT_SUCCESS(status)) - { - static PH_STRINGREF publishersKeyName = PH_STRINGREF_INIT(L"Software\\Microsoft\\Windows\\CurrentVersion\\WINEVT\\Publishers\\"); - - PPH_STRING guidString; - PPH_STRING keyName; - HANDLE keyHandle; - PPH_STRING publisherName = NULL; - - guidString = PhFormatGuid(&basicInfo.Guid); - - // We should perform a lookup on the GUID to get the publisher name. - - keyName = PhConcatStringRef2(&publishersKeyName, &guidString->sr); - - if (NT_SUCCESS(PhOpenKey( - &keyHandle, - KEY_READ, - PH_KEY_LOCAL_MACHINE, - &keyName->sr, - 0 - ))) - { - publisherName = PhQueryRegistryString(keyHandle, NULL); - - if (publisherName && publisherName->Length == 0) - { - PhDereferenceObject(publisherName); - publisherName = NULL; - } - - NtClose(keyHandle); - } - - PhDereferenceObject(keyName); - - if (publisherName) - { - bestObjectName = publisherName; - PhDereferenceObject(guidString); - } - else - { - bestObjectName = guidString; - } - } - } - } - else if (PhEqualString2(TypeName, L"File", TRUE)) - { - // Convert the file name to a DOS file name. - bestObjectName = PhResolveDevicePrefix(ObjectName); - - if (!bestObjectName) - { - // The file doesn't have a DOS name. - PhSetReference(&bestObjectName, ObjectName); - } - - if (PhIsNullOrEmptyString(bestObjectName) && KphIsConnected()) - { - KPH_FILE_OBJECT_DRIVER fileObjectDriver; - PPH_STRING driverName; - - status = KphQueryInformationObject( - ProcessHandle, - Handle, - KphObjectFileObjectDriver, - &fileObjectDriver, - sizeof(KPH_FILE_OBJECT_DRIVER), - NULL - ); - - if (NT_SUCCESS(status) && fileObjectDriver.DriverHandle) - { - if (NT_SUCCESS(PhGetDriverName(fileObjectDriver.DriverHandle, &driverName))) - { - static PH_STRINGREF prefix = PH_STRINGREF_INIT(L"Unnamed file: "); - - PhMoveReference(&bestObjectName, PhConcatStringRef2(&prefix, &driverName->sr)); - PhDereferenceObject(driverName); - } - - NtClose(fileObjectDriver.DriverHandle); - } - } - } - else if (PhEqualString2(TypeName, L"Job", TRUE)) - { - HANDLE dupHandle; - PJOBOBJECT_BASIC_PROCESS_ID_LIST processIdList; - - status = NtDuplicateObject( - ProcessHandle, - Handle, - NtCurrentProcess(), - &dupHandle, - JOB_OBJECT_QUERY, - 0, - 0 - ); - - if (!NT_SUCCESS(status)) - goto CleanupExit; - - if (handleGetClientIdName && NT_SUCCESS(PhGetJobProcessIdList(dupHandle, &processIdList))) - { - PH_STRING_BUILDER sb; - ULONG i; - CLIENT_ID clientId; - PPH_STRING name; - - PhInitializeStringBuilder(&sb, 40); - clientId.UniqueThread = NULL; - - for (i = 0; i < processIdList->NumberOfProcessIdsInList; i++) - { - clientId.UniqueProcess = (HANDLE)processIdList->ProcessIdList[i]; - name = handleGetClientIdName(&clientId); - - if (name) - { - PhAppendStringBuilder(&sb, &name->sr); - PhAppendStringBuilder2(&sb, L"; "); - PhDereferenceObject(name); - } - } - - PhFree(processIdList); - - if (sb.String->Length != 0) - PhRemoveEndStringBuilder(&sb, 2); - - if (sb.String->Length == 0) - PhAppendStringBuilder2(&sb, L"(No processes)"); - - bestObjectName = PhFinalStringBuilderString(&sb); - } - - NtClose(dupHandle); - } - else if (PhEqualString2(TypeName, L"Key", TRUE)) - { - bestObjectName = PhFormatNativeKeyName(ObjectName); - } - else if (PhEqualString2(TypeName, L"Process", TRUE)) - { - CLIENT_ID clientId; - - clientId.UniqueThread = NULL; - - if (KphIsConnected()) - { - PROCESS_BASIC_INFORMATION basicInfo; - - status = KphQueryInformationObject( - ProcessHandle, - Handle, - KphObjectProcessBasicInformation, - &basicInfo, - sizeof(PROCESS_BASIC_INFORMATION), - NULL - ); - - if (!NT_SUCCESS(status)) - goto CleanupExit; - - clientId.UniqueProcess = basicInfo.UniqueProcessId; - } - else - { - HANDLE dupHandle; - PROCESS_BASIC_INFORMATION basicInfo; - - status = NtDuplicateObject( - ProcessHandle, - Handle, - NtCurrentProcess(), - &dupHandle, - ProcessQueryAccess, - 0, - 0 - ); - - if (!NT_SUCCESS(status)) - goto CleanupExit; - - status = PhGetProcessBasicInformation(dupHandle, &basicInfo); - NtClose(dupHandle); - - if (!NT_SUCCESS(status)) - goto CleanupExit; - - clientId.UniqueProcess = basicInfo.UniqueProcessId; - } - - if (handleGetClientIdName) - bestObjectName = handleGetClientIdName(&clientId); - } - else if (PhEqualString2(TypeName, L"Section", TRUE)) - { - HANDLE dupHandle; - PPH_STRING fileName; - - if (!PhIsNullOrEmptyString(ObjectName)) - goto CleanupExit; - - status = NtDuplicateObject( - ProcessHandle, - Handle, - NtCurrentProcess(), - &dupHandle, - SECTION_QUERY | SECTION_MAP_READ, - 0, - 0 - ); - - if (!NT_SUCCESS(status)) - goto CleanupExit; - - status = PhGetSectionFileName(dupHandle, &fileName); - - if (NT_SUCCESS(status)) - { - bestObjectName = PhResolveDevicePrefix(fileName); - PhDereferenceObject(fileName); - } - else - { - SECTION_BASIC_INFORMATION basicInfo; - - if (NT_SUCCESS(PhGetSectionBasicInformation(dupHandle, &basicInfo))) - { - PH_FORMAT format[4]; - PWSTR sectionType = L"Unknown"; - - if (basicInfo.AllocationAttributes & SEC_COMMIT) - sectionType = L"Commit"; - else if (basicInfo.AllocationAttributes & SEC_FILE) - sectionType = L"File"; - else if (basicInfo.AllocationAttributes & SEC_IMAGE) - sectionType = L"Image"; - else if (basicInfo.AllocationAttributes & SEC_RESERVE) - sectionType = L"Reserve"; - - PhInitFormatS(&format[0], sectionType); - PhInitFormatS(&format[1], L" ("); - PhInitFormatSize(&format[2], basicInfo.MaximumSize.QuadPart); - PhInitFormatC(&format[3], ')'); - bestObjectName = PhFormat(format, 4, 20); - } - } - - NtClose(dupHandle); - } - else if (PhEqualString2(TypeName, L"Thread", TRUE)) - { - CLIENT_ID clientId; - - if (KphIsConnected()) - { - THREAD_BASIC_INFORMATION basicInfo; - - status = KphQueryInformationObject( - ProcessHandle, - Handle, - KphObjectThreadBasicInformation, - &basicInfo, - sizeof(THREAD_BASIC_INFORMATION), - NULL - ); - - if (!NT_SUCCESS(status)) - goto CleanupExit; - - clientId = basicInfo.ClientId; - } - else - { - HANDLE dupHandle; - THREAD_BASIC_INFORMATION basicInfo; - - status = NtDuplicateObject( - ProcessHandle, - Handle, - NtCurrentProcess(), - &dupHandle, - ThreadQueryAccess, - 0, - 0 - ); - - if (!NT_SUCCESS(status)) - goto CleanupExit; - - status = PhGetThreadBasicInformation(dupHandle, &basicInfo); - NtClose(dupHandle); - - if (!NT_SUCCESS(status)) - goto CleanupExit; - - clientId = basicInfo.ClientId; - } - - if (handleGetClientIdName) - bestObjectName = handleGetClientIdName(&clientId); - } - else if (PhEqualString2(TypeName, L"TmEn", TRUE)) - { - HANDLE dupHandle; - ENLISTMENT_BASIC_INFORMATION basicInfo; - - status = NtDuplicateObject( - ProcessHandle, - Handle, - NtCurrentProcess(), - &dupHandle, - ENLISTMENT_QUERY_INFORMATION, - 0, - 0 - ); - - if (!NT_SUCCESS(status)) - goto CleanupExit; - - status = PhGetEnlistmentBasicInformation(dupHandle, &basicInfo); - NtClose(dupHandle); - - if (NT_SUCCESS(status)) - { - bestObjectName = PhFormatGuid(&basicInfo.EnlistmentId); - } - } - else if (PhEqualString2(TypeName, L"TmRm", TRUE)) - { - HANDLE dupHandle; - GUID guid; - PPH_STRING description; - - status = NtDuplicateObject( - ProcessHandle, - Handle, - NtCurrentProcess(), - &dupHandle, - RESOURCEMANAGER_QUERY_INFORMATION, - 0, - 0 - ); - - if (!NT_SUCCESS(status)) - goto CleanupExit; - - status = PhGetResourceManagerBasicInformation( - dupHandle, - &guid, - &description - ); - NtClose(dupHandle); - - if (NT_SUCCESS(status)) - { - if (!PhIsNullOrEmptyString(description)) - { - bestObjectName = description; - } - else - { - bestObjectName = PhFormatGuid(&guid); - - if (description) - PhDereferenceObject(description); - } - } - } - else if (PhEqualString2(TypeName, L"TmTm", TRUE)) - { - HANDLE dupHandle; - PPH_STRING logFileName = NULL; - TRANSACTIONMANAGER_BASIC_INFORMATION basicInfo; - - status = NtDuplicateObject( - ProcessHandle, - Handle, - NtCurrentProcess(), - &dupHandle, - TRANSACTIONMANAGER_QUERY_INFORMATION, - 0, - 0 - ); - - if (!NT_SUCCESS(status)) - goto CleanupExit; - - status = PhGetTransactionManagerLogFileName( - dupHandle, - &logFileName - ); - - if (NT_SUCCESS(status) && !PhIsNullOrEmptyString(logFileName)) - { - bestObjectName = PhGetFileName(logFileName); - PhDereferenceObject(logFileName); - } - else - { - if (logFileName) - PhDereferenceObject(logFileName); - - status = PhGetTransactionManagerBasicInformation( - dupHandle, - &basicInfo - ); - - if (NT_SUCCESS(status)) - { - bestObjectName = PhFormatGuid(&basicInfo.TmIdentity); - } - } - - NtClose(dupHandle); - } - else if (PhEqualString2(TypeName, L"TmTx", TRUE)) - { - HANDLE dupHandle; - PPH_STRING description = NULL; - TRANSACTION_BASIC_INFORMATION basicInfo; - - status = NtDuplicateObject( - ProcessHandle, - Handle, - NtCurrentProcess(), - &dupHandle, - TRANSACTION_QUERY_INFORMATION, - 0, - 0 - ); - - if (!NT_SUCCESS(status)) - goto CleanupExit; - - status = PhGetTransactionPropertiesInformation( - dupHandle, - NULL, - NULL, - &description - ); - - if (NT_SUCCESS(status) && !PhIsNullOrEmptyString(description)) - { - bestObjectName = description; - } - else - { - if (description) - PhDereferenceObject(description); - - status = PhGetTransactionBasicInformation( - dupHandle, - &basicInfo - ); - - if (NT_SUCCESS(status)) - { - bestObjectName = PhFormatGuid(&basicInfo.TransactionId); - } - } - - NtClose(dupHandle); - } - else if (PhEqualString2(TypeName, L"Token", TRUE)) - { - HANDLE dupHandle; - PTOKEN_USER tokenUser = NULL; - TOKEN_STATISTICS statistics = { 0 }; - - status = NtDuplicateObject( - ProcessHandle, - Handle, - NtCurrentProcess(), - &dupHandle, - TOKEN_QUERY, - 0, - 0 - ); - - if (!NT_SUCCESS(status)) - goto CleanupExit; - - status = PhGetTokenUser(dupHandle, &tokenUser); - PhGetTokenStatistics(dupHandle, &statistics); - - if (NT_SUCCESS(status)) - { - PPH_STRING fullName; - - fullName = PhGetSidFullName(tokenUser->User.Sid, TRUE, NULL); - - if (fullName) - { - PH_FORMAT format[4]; - - PhInitFormatSR(&format[0], fullName->sr); - PhInitFormatS(&format[1], L": 0x"); - PhInitFormatX(&format[2], statistics.AuthenticationId.LowPart); - PhInitFormatS(&format[3], statistics.TokenType == TokenPrimary ? L" (Primary)" : L" (Impersonation)"); - - bestObjectName = PhFormat(format, 4, fullName->Length + 8 + 16 + 16); - PhDereferenceObject(fullName); - } - - PhFree(tokenUser); - } - - NtClose(dupHandle); - } - -CleanupExit: - - if (!bestObjectName) - PhSetReference(&bestObjectName, ObjectName); - - *BestObjectName = bestObjectName; - - return STATUS_SUCCESS; -} - -/** - * Gets information for a handle. - * - * \param ProcessHandle A handle to the process in which the handle resides. - * \param Handle The handle value. - * \param ObjectTypeNumber The object type number of the handle. You can specify -1 for this - * parameter if the object type number is not known. - * \param BasicInformation A variable which receives basic information about the object. - * \param TypeName A variable which receives the object type name. - * \param ObjectName A variable which receives the object name. - * \param BestObjectName A variable which receives the formatted object name. - * - * \retval STATUS_INVALID_HANDLE The handle specified in \c ProcessHandle or \c Handle is invalid. - * \retval STATUS_INVALID_PARAMETER_3 The value specified in \c ObjectTypeNumber is invalid. - */ -NTSTATUS PhGetHandleInformation( - _In_ HANDLE ProcessHandle, - _In_ HANDLE Handle, - _In_ ULONG ObjectTypeNumber, - _Out_opt_ POBJECT_BASIC_INFORMATION BasicInformation, - _Out_opt_ PPH_STRING *TypeName, - _Out_opt_ PPH_STRING *ObjectName, - _Out_opt_ PPH_STRING *BestObjectName - ) -{ - NTSTATUS status; - NTSTATUS subStatus; - - status = PhGetHandleInformationEx( - ProcessHandle, - Handle, - ObjectTypeNumber, - 0, - &subStatus, - BasicInformation, - TypeName, - ObjectName, - BestObjectName, - NULL - ); - - if (!NT_SUCCESS(status)) - return status; - - // Fail if any component failed, for compatibility reasons. - if (!NT_SUCCESS(subStatus)) - { - if (TypeName) - PhClearReference(TypeName); - if (ObjectName) - PhClearReference(ObjectName); - if (BestObjectName) - PhClearReference(BestObjectName); - - return subStatus; - } - - return status; -} - -/** - * Gets information for a handle. - * - * \param ProcessHandle A handle to the process in which the handle resides. - * \param Handle The handle value. - * \param ObjectTypeNumber The object type number of the handle. You can specify -1 for this - * parameter if the object type number is not known. - * \param Flags Reserved. - * \param SubStatus A variable which receives the NTSTATUS value of the last component that fails. - * If all operations succeed, the value will be STATUS_SUCCESS. If the function returns an error - * status, this variable is not set. - * \param BasicInformation A variable which receives basic information about the object. - * \param TypeName A variable which receives the object type name. - * \param ObjectName A variable which receives the object name. - * \param BestObjectName A variable which receives the formatted object name. - * \param ExtraInformation Reserved. - * - * \retval STATUS_INVALID_HANDLE The handle specified in \c ProcessHandle or \c Handle is invalid. - * \retval STATUS_INVALID_PARAMETER_3 The value specified in \c ObjectTypeNumber is invalid. - * - * \remarks If \a BasicInformation or \a TypeName are specified, the function will fail if either - * cannot be queried. \a ObjectName, \a BestObjectName and \a ExtraInformation will be NULL if they - * cannot be queried. - */ -NTSTATUS PhGetHandleInformationEx( - _In_ HANDLE ProcessHandle, - _In_ HANDLE Handle, - _In_ ULONG ObjectTypeNumber, - _Reserved_ ULONG Flags, - _Out_opt_ PNTSTATUS SubStatus, - _Out_opt_ POBJECT_BASIC_INFORMATION BasicInformation, - _Out_opt_ PPH_STRING *TypeName, - _Out_opt_ PPH_STRING *ObjectName, - _Out_opt_ PPH_STRING *BestObjectName, - _Reserved_ PVOID *ExtraInformation - ) -{ - NTSTATUS status = STATUS_SUCCESS; - NTSTATUS subStatus = STATUS_SUCCESS; - HANDLE dupHandle = NULL; - PPH_STRING typeName = NULL; - PPH_STRING objectName = NULL; - PPH_STRING bestObjectName = NULL; - - if (Handle == NULL || Handle == NtCurrentProcess() || Handle == NtCurrentThread()) - return STATUS_INVALID_HANDLE; - if (ObjectTypeNumber != -1 && ObjectTypeNumber >= MAX_OBJECT_TYPE_NUMBER) - return STATUS_INVALID_PARAMETER_3; - - // Duplicate the handle if we're not using KPH. - if (!KphIsConnected()) - { - // However, we obviously don't need to duplicate it - // if the handle is in the current process. - if (ProcessHandle != NtCurrentProcess()) - { - status = NtDuplicateObject( - ProcessHandle, - Handle, - NtCurrentProcess(), - &dupHandle, - 0, - 0, - 0 - ); - - if (!NT_SUCCESS(status)) - return status; - } - else - { - dupHandle = Handle; - } - } - - // Get basic information. - if (BasicInformation) - { - status = PhpGetObjectBasicInformation( - ProcessHandle, - KphIsConnected() ? Handle : dupHandle, - BasicInformation - ); - - if (!NT_SUCCESS(status)) - goto CleanupExit; - } - - // Exit early if we don't need to get any other information. - if (!TypeName && !ObjectName && !BestObjectName) - goto CleanupExit; - - // Get the type name. - status = PhpGetObjectTypeName( - ProcessHandle, - KphIsConnected() ? Handle : dupHandle, - ObjectTypeNumber, - &typeName - ); - - if (!NT_SUCCESS(status)) - goto CleanupExit; - - // Exit early if we don't need to get the object name. - if (!ObjectName && !BestObjectName) - goto CleanupExit; - - // Get the object name. - // If we're dealing with a file handle we must take special precautions so we don't hang. - if (PhEqualString2(typeName, L"File", TRUE) && !KphIsConnected()) - { -#define QUERY_NORMALLY 0 -#define QUERY_WITH_TIMEOUT 1 -#define QUERY_FAIL 2 - - ULONG hackLevel = QUERY_WITH_TIMEOUT; - - // We can't use the timeout method on XP because hanging threads can't even be terminated! - if (WindowsVersion <= WINDOWS_XP) - hackLevel = QUERY_FAIL; - - if (hackLevel == QUERY_NORMALLY || hackLevel == QUERY_WITH_TIMEOUT) - { - status = PhpGetObjectName( - ProcessHandle, - KphIsConnected() ? Handle : dupHandle, - hackLevel == QUERY_WITH_TIMEOUT, - &objectName - ); - } - else - { - // Pretend the file object has no name. - objectName = PhReferenceEmptyString(); - status = STATUS_SUCCESS; - } - } - else - { - // Query the object normally. - status = PhpGetObjectName( - ProcessHandle, - KphIsConnected() ? Handle : dupHandle, - FALSE, - &objectName - ); - } - - if (!NT_SUCCESS(status)) - { - if (PhEqualString2(typeName, L"File", TRUE) && KphIsConnected()) - { - // PhpGetBestObjectName can provide us with a name. - objectName = PhReferenceEmptyString(); - status = STATUS_SUCCESS; - } - else - { - subStatus = status; - status = STATUS_SUCCESS; - goto CleanupExit; - } - } - - // Exit early if we don't need to get the best object name. - if (!BestObjectName) - goto CleanupExit; - - status = PhpGetBestObjectName( - ProcessHandle, - Handle, - objectName, - typeName, - &bestObjectName - ); - - if (!NT_SUCCESS(status)) - { - subStatus = status; - status = STATUS_SUCCESS; - goto CleanupExit; - } - -CleanupExit: - - if (NT_SUCCESS(status)) - { - if (SubStatus) - *SubStatus = subStatus; - if (TypeName) - PhSetReference(TypeName, typeName); - if (ObjectName) - PhSetReference(ObjectName, objectName); - if (BestObjectName) - PhSetReference(BestObjectName, bestObjectName); - } - - if (dupHandle && ProcessHandle != NtCurrentProcess()) - NtClose(dupHandle); - - PhClearReference(&typeName); - PhClearReference(&objectName); - PhClearReference(&bestObjectName); - - return status; -} - -NTSTATUS PhEnumObjectTypes( - _Out_ POBJECT_TYPES_INFORMATION *ObjectTypes - ) -{ - NTSTATUS status; - PVOID buffer; - ULONG bufferSize; - - bufferSize = 0x1000; - buffer = PhAllocate(bufferSize); - - while ((status = NtQueryObject( - NULL, - ObjectTypesInformation, - buffer, - bufferSize, - NULL - )) == STATUS_INFO_LENGTH_MISMATCH) - { - PhFree(buffer); - bufferSize *= 2; - - // Fail if we're resizing the buffer to something very large. - if (bufferSize > PH_LARGE_BUFFER_SIZE) - return STATUS_INSUFFICIENT_RESOURCES; - - buffer = PhAllocate(bufferSize); - } - - if (!NT_SUCCESS(status)) - { - PhFree(buffer); - return status; - } - - *ObjectTypes = (POBJECT_TYPES_INFORMATION)buffer; - - return status; -} - -ULONG PhGetObjectTypeNumber( - _In_ PUNICODE_STRING TypeName - ) -{ - POBJECT_TYPES_INFORMATION objectTypes; - POBJECT_TYPE_INFORMATION objectType; - ULONG objectIndex = -1; - ULONG i; - - if (NT_SUCCESS(PhEnumObjectTypes(&objectTypes))) - { - objectType = PH_FIRST_OBJECT_TYPE(objectTypes); - - for (i = 0; i < objectTypes->NumberOfTypes; i++) - { - if (RtlEqualUnicodeString(&objectType->TypeName, TypeName, TRUE)) - { - if (WindowsVersion >= WINDOWS_8_1) - { - objectIndex = objectType->TypeIndex; - break; - } - else if (WindowsVersion >= WINDOWS_7) - { - objectIndex = i + 2; - break; - } - else - { - objectIndex = i + 1; - break; - } - } - - objectType = PH_NEXT_OBJECT_TYPE(objectType); - } - - PhFree(objectTypes); - } - - return objectIndex; -} - -PPHP_CALL_WITH_TIMEOUT_THREAD_CONTEXT PhpAcquireCallWithTimeoutThread( - _In_opt_ PLARGE_INTEGER Timeout - ) -{ - static PH_INITONCE initOnce = PH_INITONCE_INIT; - - PPHP_CALL_WITH_TIMEOUT_THREAD_CONTEXT threadContext; - PSLIST_ENTRY listEntry; - PH_QUEUED_WAIT_BLOCK waitBlock; - - if (PhBeginInitOnce(&initOnce)) - { - ULONG i; - - for (i = 0; i < PH_QUERY_HACK_MAX_THREADS; i++) - { - threadContext = PhAllocate(sizeof(PHP_CALL_WITH_TIMEOUT_THREAD_CONTEXT)); - memset(threadContext, 0, sizeof(PHP_CALL_WITH_TIMEOUT_THREAD_CONTEXT)); - RtlInterlockedPushEntrySList(&PhpCallWithTimeoutThreadListHead, &threadContext->ListEntry); - } - - PhEndInitOnce(&initOnce); - } - - while (TRUE) - { - if (listEntry = RtlInterlockedPopEntrySList(&PhpCallWithTimeoutThreadListHead)) - break; - - if (!Timeout || Timeout->QuadPart != 0) - { - PhQueueWakeEvent(&PhpCallWithTimeoutThreadReleaseEvent, &waitBlock); - - if (listEntry = RtlInterlockedPopEntrySList(&PhpCallWithTimeoutThreadListHead)) - { - // A new entry has just become available; cancel the wait. - PhSetWakeEvent(&PhpCallWithTimeoutThreadReleaseEvent, &waitBlock); - break; - } - else - { - PhWaitForWakeEvent(&PhpCallWithTimeoutThreadReleaseEvent, &waitBlock, FALSE, Timeout); - // TODO: Recompute the timeout value. - } - } - else - { - return NULL; - } - } - - return CONTAINING_RECORD(listEntry, PHP_CALL_WITH_TIMEOUT_THREAD_CONTEXT, ListEntry); -} - -VOID PhpReleaseCallWithTimeoutThread( - _Inout_ PPHP_CALL_WITH_TIMEOUT_THREAD_CONTEXT ThreadContext - ) -{ - RtlInterlockedPushEntrySList(&PhpCallWithTimeoutThreadListHead, &ThreadContext->ListEntry); - PhSetWakeEvent(&PhpCallWithTimeoutThreadReleaseEvent, NULL); -} - -NTSTATUS PhpCallWithTimeout( - _Inout_ PPHP_CALL_WITH_TIMEOUT_THREAD_CONTEXT ThreadContext, - _In_ PUSER_THREAD_START_ROUTINE Routine, - _In_opt_ PVOID Context, - _In_ PLARGE_INTEGER Timeout - ) -{ - NTSTATUS status; - - // Create objects if necessary. - - if (!ThreadContext->StartEventHandle) - { - if (!NT_SUCCESS(status = NtCreateEvent(&ThreadContext->StartEventHandle, EVENT_ALL_ACCESS, NULL, SynchronizationEvent, FALSE))) - return status; - } - - if (!ThreadContext->CompletedEventHandle) - { - if (!NT_SUCCESS(status = NtCreateEvent(&ThreadContext->CompletedEventHandle, EVENT_ALL_ACCESS, NULL, SynchronizationEvent, FALSE))) - return status; - } - - // Create a query thread if we don't have one. - if (!ThreadContext->ThreadHandle) - { - CLIENT_ID clientId; - - NtClearEvent(ThreadContext->StartEventHandle); - NtClearEvent(ThreadContext->CompletedEventHandle); - - if (!NT_SUCCESS(status = RtlCreateUserThread( - NtCurrentProcess(), - NULL, - FALSE, - 0, - 0, - 32 * 1024, - PhpCallWithTimeoutThreadStart, - ThreadContext, - &ThreadContext->ThreadHandle, - &clientId - ))) - { - return status; - } - - // Wait for the thread to initialize. - NtWaitForSingleObject(ThreadContext->CompletedEventHandle, FALSE, NULL); - } - - ThreadContext->Routine = Routine; - ThreadContext->Context = Context; - - NtSetEvent(ThreadContext->StartEventHandle, NULL); - status = NtWaitForSingleObject(ThreadContext->CompletedEventHandle, FALSE, Timeout); - - ThreadContext->Routine = NULL; - MemoryBarrier(); - ThreadContext->Context = NULL; - - if (status != STATUS_WAIT_0) - { - // The operation timed out, or there was an error. Kill the thread. On Vista and above, the - // thread stack is freed automatically. - NtTerminateThread(ThreadContext->ThreadHandle, STATUS_UNSUCCESSFUL); - status = NtWaitForSingleObject(ThreadContext->ThreadHandle, FALSE, NULL); - NtClose(ThreadContext->ThreadHandle); - ThreadContext->ThreadHandle = NULL; - - status = STATUS_UNSUCCESSFUL; - } - - return status; -} - -NTSTATUS PhpCallWithTimeoutThreadStart( - _In_ PVOID Parameter - ) -{ - PPHP_CALL_WITH_TIMEOUT_THREAD_CONTEXT threadContext = Parameter; - - NtSetEvent(threadContext->CompletedEventHandle, NULL); - - while (TRUE) - { - if (NtWaitForSingleObject(threadContext->StartEventHandle, FALSE, NULL) != STATUS_WAIT_0) - continue; - - if (threadContext->Routine) - threadContext->Routine(threadContext->Context); - - NtSetEvent(threadContext->CompletedEventHandle, NULL); - } - - return STATUS_SUCCESS; -} - -NTSTATUS PhCallWithTimeout( - _In_ PUSER_THREAD_START_ROUTINE Routine, - _In_opt_ PVOID Context, - _In_opt_ PLARGE_INTEGER AcquireTimeout, - _In_ PLARGE_INTEGER CallTimeout - ) -{ - NTSTATUS status; - PPHP_CALL_WITH_TIMEOUT_THREAD_CONTEXT threadContext; - - if (threadContext = PhpAcquireCallWithTimeoutThread(AcquireTimeout)) - { - status = PhpCallWithTimeout(threadContext, Routine, Context, CallTimeout); - PhpReleaseCallWithTimeoutThread(threadContext); - } - else - { - status = STATUS_UNSUCCESSFUL; - } - - return status; -} - -NTSTATUS PhpCommonQueryObjectRoutine( - _In_ PVOID Parameter - ) -{ - PPHP_QUERY_OBJECT_COMMON_CONTEXT context = Parameter; - - switch (context->Work) - { - case NtQueryObjectWork: - context->Status = NtQueryObject( - context->u.NtQueryObject.Handle, - context->u.NtQueryObject.ObjectInformationClass, - context->u.NtQueryObject.ObjectInformation, - context->u.NtQueryObject.ObjectInformationLength, - context->u.NtQueryObject.ReturnLength - ); - break; - case NtQuerySecurityObjectWork: - context->Status = NtQuerySecurityObject( - context->u.NtQuerySecurityObject.Handle, - context->u.NtQuerySecurityObject.SecurityInformation, - context->u.NtQuerySecurityObject.SecurityDescriptor, - context->u.NtQuerySecurityObject.Length, - context->u.NtQuerySecurityObject.LengthNeeded - ); - break; - case NtSetSecurityObjectWork: - context->Status = NtSetSecurityObject( - context->u.NtSetSecurityObject.Handle, - context->u.NtSetSecurityObject.SecurityInformation, - context->u.NtSetSecurityObject.SecurityDescriptor - ); - break; - default: - context->Status = STATUS_INVALID_PARAMETER; - break; - } - - return STATUS_SUCCESS; -} - -NTSTATUS PhpCommonQueryObjectWithTimeout( - _In_ PPHP_QUERY_OBJECT_COMMON_CONTEXT Context - ) -{ - NTSTATUS status; - LARGE_INTEGER timeout; - - timeout.QuadPart = -1 * PH_TIMEOUT_SEC; - status = PhCallWithTimeout(PhpCommonQueryObjectRoutine, Context, NULL, &timeout); - - if (NT_SUCCESS(status)) - status = Context->Status; - - PhFree(Context); - - return status; -} - -NTSTATUS PhCallNtQueryObjectWithTimeout( - _In_ HANDLE Handle, - _In_ OBJECT_INFORMATION_CLASS ObjectInformationClass, - _Out_writes_bytes_opt_(ObjectInformationLength) PVOID ObjectInformation, - _In_ ULONG ObjectInformationLength, - _Out_opt_ PULONG ReturnLength - ) -{ - PPHP_QUERY_OBJECT_COMMON_CONTEXT context; - - context = PhAllocate(sizeof(PHP_QUERY_OBJECT_COMMON_CONTEXT)); - context->Work = NtQueryObjectWork; - context->Status = STATUS_UNSUCCESSFUL; - context->u.NtQueryObject.Handle = Handle; - context->u.NtQueryObject.ObjectInformationClass = ObjectInformationClass; - context->u.NtQueryObject.ObjectInformation = ObjectInformation; - context->u.NtQueryObject.ObjectInformationLength = ObjectInformationLength; - context->u.NtQueryObject.ReturnLength = ReturnLength; - - return PhpCommonQueryObjectWithTimeout(context); -} - -NTSTATUS PhCallNtQuerySecurityObjectWithTimeout( - _In_ HANDLE Handle, - _In_ SECURITY_INFORMATION SecurityInformation, - _Out_writes_bytes_opt_(Length) PSECURITY_DESCRIPTOR SecurityDescriptor, - _In_ ULONG Length, - _Out_ PULONG LengthNeeded - ) -{ - PPHP_QUERY_OBJECT_COMMON_CONTEXT context; - - context = PhAllocate(sizeof(PHP_QUERY_OBJECT_COMMON_CONTEXT)); - context->Work = NtQuerySecurityObjectWork; - context->Status = STATUS_UNSUCCESSFUL; - context->u.NtQuerySecurityObject.Handle = Handle; - context->u.NtQuerySecurityObject.SecurityInformation = SecurityInformation; - context->u.NtQuerySecurityObject.SecurityDescriptor = SecurityDescriptor; - context->u.NtQuerySecurityObject.Length = Length; - context->u.NtQuerySecurityObject.LengthNeeded = LengthNeeded; - - return PhpCommonQueryObjectWithTimeout(context); -} - -NTSTATUS PhCallNtSetSecurityObjectWithTimeout( - _In_ HANDLE Handle, - _In_ SECURITY_INFORMATION SecurityInformation, - _In_ PSECURITY_DESCRIPTOR SecurityDescriptor - ) -{ - PPHP_QUERY_OBJECT_COMMON_CONTEXT context; - - context = PhAllocate(sizeof(PHP_QUERY_OBJECT_COMMON_CONTEXT)); - context->Work = NtSetSecurityObjectWork; - context->Status = STATUS_UNSUCCESSFUL; - context->u.NtSetSecurityObject.Handle = Handle; - context->u.NtSetSecurityObject.SecurityInformation = SecurityInformation; - context->u.NtSetSecurityObject.SecurityDescriptor = SecurityDescriptor; - - return PhpCommonQueryObjectWithTimeout(context); -} +/* + * Process Hacker - + * handle information + * + * Copyright (C) 2010-2015 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include +#include + +#include +#include + +#define PH_QUERY_HACK_MAX_THREADS 20 + +typedef struct _PHP_CALL_WITH_TIMEOUT_THREAD_CONTEXT +{ + SLIST_ENTRY ListEntry; + + PUSER_THREAD_START_ROUTINE Routine; + PVOID Context; + + HANDLE StartEventHandle; + HANDLE CompletedEventHandle; + HANDLE ThreadHandle; +} PHP_CALL_WITH_TIMEOUT_THREAD_CONTEXT, *PPHP_CALL_WITH_TIMEOUT_THREAD_CONTEXT; + +typedef enum _PHP_QUERY_OBJECT_WORK +{ + NtQueryObjectWork, + NtQuerySecurityObjectWork, + NtSetSecurityObjectWork +} PHP_QUERY_OBJECT_WORK; + +typedef struct _PHP_QUERY_OBJECT_COMMON_CONTEXT +{ + PHP_QUERY_OBJECT_WORK Work; + NTSTATUS Status; + + union + { + struct + { + HANDLE Handle; + OBJECT_INFORMATION_CLASS ObjectInformationClass; + PVOID ObjectInformation; + ULONG ObjectInformationLength; + PULONG ReturnLength; + } NtQueryObject; + struct + { + HANDLE Handle; + SECURITY_INFORMATION SecurityInformation; + PSECURITY_DESCRIPTOR SecurityDescriptor; + ULONG Length; + PULONG LengthNeeded; + } NtQuerySecurityObject; + struct + { + HANDLE Handle; + SECURITY_INFORMATION SecurityInformation; + PSECURITY_DESCRIPTOR SecurityDescriptor; + } NtSetSecurityObject; + } u; +} PHP_QUERY_OBJECT_COMMON_CONTEXT, *PPHP_QUERY_OBJECT_COMMON_CONTEXT; + +PPHP_CALL_WITH_TIMEOUT_THREAD_CONTEXT PhpAcquireCallWithTimeoutThread( + _In_opt_ PLARGE_INTEGER Timeout + ); + +VOID PhpReleaseCallWithTimeoutThread( + _Inout_ PPHP_CALL_WITH_TIMEOUT_THREAD_CONTEXT ThreadContext + ); + +NTSTATUS PhpCallWithTimeout( + _Inout_ PPHP_CALL_WITH_TIMEOUT_THREAD_CONTEXT ThreadContext, + _In_ PUSER_THREAD_START_ROUTINE Routine, + _In_opt_ PVOID Context, + _In_ PLARGE_INTEGER Timeout + ); + +NTSTATUS PhpCallWithTimeoutThreadStart( + _In_ PVOID Parameter + ); + +static PPH_STRING PhObjectTypeNames[MAX_OBJECT_TYPE_NUMBER] = { 0 }; +static PPH_GET_CLIENT_ID_NAME PhHandleGetClientIdName = PhStdGetClientIdName; + +static SLIST_HEADER PhpCallWithTimeoutThreadListHead; +static PH_WAKE_EVENT PhpCallWithTimeoutThreadReleaseEvent = PH_WAKE_EVENT_INIT; + +PPH_GET_CLIENT_ID_NAME PhSetHandleClientIdFunction( + _In_ PPH_GET_CLIENT_ID_NAME GetClientIdName + ) +{ + return _InterlockedExchangePointer( + (PVOID *)&PhHandleGetClientIdName, + GetClientIdName + ); +} + +NTSTATUS PhpGetObjectBasicInformation( + _In_ HANDLE ProcessHandle, + _In_ HANDLE Handle, + _Out_ POBJECT_BASIC_INFORMATION BasicInformation + ) +{ + NTSTATUS status; + + if (KphIsConnected()) + { + status = KphQueryInformationObject( + ProcessHandle, + Handle, + KphObjectBasicInformation, + BasicInformation, + sizeof(OBJECT_BASIC_INFORMATION), + NULL + ); + + if (NT_SUCCESS(status)) + { + // The object was referenced in KProcessHacker, so we need to subtract 1 from the + // pointer count. + BasicInformation->PointerCount -= 1; + } + } + else + { + status = NtQueryObject( + Handle, + ObjectBasicInformation, + BasicInformation, + sizeof(OBJECT_BASIC_INFORMATION), + NULL + ); + + if (NT_SUCCESS(status)) + { + // The object was referenced in NtQueryObject and a handle was opened to the object. We + // need to subtract 1 from the pointer count, then subtract 1 from both counts. + BasicInformation->HandleCount -= 1; + BasicInformation->PointerCount -= 2; + } + } + + return status; +} + +NTSTATUS PhpGetObjectTypeName( + _In_ HANDLE ProcessHandle, + _In_ HANDLE Handle, + _In_ ULONG ObjectTypeNumber, + _Out_ PPH_STRING *TypeName + ) +{ + NTSTATUS status = STATUS_SUCCESS; + PPH_STRING typeName = NULL; + + // If the cache contains the object type name, use it. Otherwise, query the type name. + + if (ObjectTypeNumber != -1 && ObjectTypeNumber < MAX_OBJECT_TYPE_NUMBER) + typeName = PhObjectTypeNames[ObjectTypeNumber]; + + if (typeName) + { + PhReferenceObject(typeName); + } + else + { + POBJECT_TYPE_INFORMATION buffer; + ULONG returnLength = 0; + PPH_STRING oldTypeName; + + // Get the needed buffer size. + if (KphIsConnected()) + { + status = KphQueryInformationObject( + ProcessHandle, + Handle, + KphObjectTypeInformation, + NULL, + 0, + &returnLength + ); + } + else + { + status = NtQueryObject( + Handle, + ObjectTypeInformation, + NULL, + 0, + &returnLength + ); + } + + if (returnLength == 0) + return status; + + buffer = PhAllocate(returnLength); + + if (KphIsConnected()) + { + status = KphQueryInformationObject( + ProcessHandle, + Handle, + KphObjectTypeInformation, + buffer, + returnLength, + &returnLength + ); + } + else + { + status = NtQueryObject( + Handle, + ObjectTypeInformation, + buffer, + returnLength, + &returnLength + ); + } + + if (!NT_SUCCESS(status)) + { + PhFree(buffer); + return status; + } + + // Create a copy of the type name. + typeName = PhCreateStringFromUnicodeString(&buffer->TypeName); + + if (ObjectTypeNumber != -1 && ObjectTypeNumber < MAX_OBJECT_TYPE_NUMBER) + { + // Try to store the type name in the cache. + oldTypeName = _InterlockedCompareExchangePointer( + &PhObjectTypeNames[ObjectTypeNumber], + typeName, + NULL + ); + + // Add a reference if we stored the type name + // successfully. + if (!oldTypeName) + PhReferenceObject(typeName); + } + + PhFree(buffer); + } + + // At this point typeName should contain a type name with one additional reference. + + *TypeName = typeName; + + return status; +} + +NTSTATUS PhpGetObjectName( + _In_ HANDLE ProcessHandle, + _In_ HANDLE Handle, + _In_ BOOLEAN WithTimeout, + _Out_ PPH_STRING *ObjectName + ) +{ + NTSTATUS status; + POBJECT_NAME_INFORMATION buffer; + ULONG bufferSize; + ULONG attempts = 8; + + bufferSize = 0x200; + buffer = PhAllocate(bufferSize); + + // A loop is needed because the I/O subsystem likes to give us the wrong return lengths... + do + { + if (KphIsConnected()) + { + status = KphQueryInformationObject( + ProcessHandle, + Handle, + KphObjectNameInformation, + buffer, + bufferSize, + &bufferSize + ); + } + else + { + if (WithTimeout) + { + status = PhCallNtQueryObjectWithTimeout( + Handle, + ObjectNameInformation, + buffer, + bufferSize, + &bufferSize + ); + } + else + { + status = NtQueryObject( + Handle, + ObjectNameInformation, + buffer, + bufferSize, + &bufferSize + ); + } + } + + if (status == STATUS_BUFFER_OVERFLOW || status == STATUS_INFO_LENGTH_MISMATCH || + status == STATUS_BUFFER_TOO_SMALL) + { + PhFree(buffer); + buffer = PhAllocate(bufferSize); + } + else + { + break; + } + } while (--attempts); + + if (NT_SUCCESS(status)) + { + *ObjectName = PhCreateStringFromUnicodeString(&buffer->Name); + } + + PhFree(buffer); + + return status; +} + +PPH_STRING PhFormatNativeKeyName( + _In_ PPH_STRING Name + ) +{ + static PH_STRINGREF hklmPrefix = PH_STRINGREF_INIT(L"\\Registry\\Machine"); + static PH_STRINGREF hkcrPrefix = PH_STRINGREF_INIT(L"\\Registry\\Machine\\Software\\Classes"); + static PH_STRINGREF hkuPrefix = PH_STRINGREF_INIT(L"\\Registry\\User"); + static PPH_STRING hkcuPrefix; + static PPH_STRING hkcucrPrefix; + + static PH_STRINGREF hklmString = PH_STRINGREF_INIT(L"HKLM"); + static PH_STRINGREF hkcrString = PH_STRINGREF_INIT(L"HKCR"); + static PH_STRINGREF hkuString = PH_STRINGREF_INIT(L"HKU"); + static PH_STRINGREF hkcuString = PH_STRINGREF_INIT(L"HKCU"); + static PH_STRINGREF hkcucrString = PH_STRINGREF_INIT(L"HKCU\\Software\\Classes"); + + static PH_INITONCE initOnce = PH_INITONCE_INIT; + + PPH_STRING newName; + PH_STRINGREF name; + + if (PhBeginInitOnce(&initOnce)) + { + HANDLE currentTokenHandle; + PTOKEN_USER tokenUser; + PPH_STRING stringSid = NULL; + + currentTokenHandle = PhGetOwnTokenAttributes().TokenHandle; + + if (currentTokenHandle && NT_SUCCESS(PhGetTokenUser( + currentTokenHandle, + &tokenUser + ))) + { + stringSid = PhSidToStringSid(tokenUser->User.Sid); + PhFree(tokenUser); + } + + if (stringSid) + { + static PH_STRINGREF registryUserPrefix = PH_STRINGREF_INIT(L"\\Registry\\User\\"); + static PH_STRINGREF classesString = PH_STRINGREF_INIT(L"_Classes"); + + hkcuPrefix = PhConcatStringRef2(®istryUserPrefix, &stringSid->sr); + hkcucrPrefix = PhConcatStringRef2(&hkcuPrefix->sr, &classesString); + + PhDereferenceObject(stringSid); + } + else + { + hkcuPrefix = PhCreateString(L"..."); // some random string that won't ever get matched + hkcucrPrefix = PhCreateString(L"..."); + } + + PhEndInitOnce(&initOnce); + } + + name = Name->sr; + + if (PhStartsWithStringRef(&name, &hkcrPrefix, TRUE)) + { + PhSkipStringRef(&name, hkcrPrefix.Length); + newName = PhConcatStringRef2(&hkcrString, &name); + } + else if (PhStartsWithStringRef(&name, &hklmPrefix, TRUE)) + { + PhSkipStringRef(&name, hklmPrefix.Length); + newName = PhConcatStringRef2(&hklmString, &name); + } + else if (PhStartsWithStringRef(&name, &hkcucrPrefix->sr, TRUE)) + { + PhSkipStringRef(&name, hkcucrPrefix->Length); + newName = PhConcatStringRef2(&hkcucrString, &name); + } + else if (PhStartsWithStringRef(&name, &hkcuPrefix->sr, TRUE)) + { + PhSkipStringRef(&name, hkcuPrefix->Length); + newName = PhConcatStringRef2(&hkcuString, &name); + } + else if (PhStartsWithStringRef(&name, &hkuPrefix, TRUE)) + { + PhSkipStringRef(&name, hkuPrefix.Length); + newName = PhConcatStringRef2(&hkuString, &name); + } + else + { + PhSetReference(&newName, Name); + } + + return newName; +} + +NTSTATUS PhGetSectionFileName( + _In_ HANDLE SectionHandle, + _Out_ PPH_STRING *FileName + ) +{ + NTSTATUS status; + SIZE_T viewSize; + PVOID viewBase; + + viewSize = 1; + viewBase = NULL; + + status = NtMapViewOfSection( + SectionHandle, + NtCurrentProcess(), + &viewBase, + 0, + 0, + NULL, + &viewSize, + ViewShare, + 0, + PAGE_READONLY + ); + + if (!NT_SUCCESS(status)) + return status; + + status = PhGetProcessMappedFileName(NtCurrentProcess(), viewBase, FileName); + NtUnmapViewOfSection(NtCurrentProcess(), viewBase); + + return status; +} + +_Callback_ PPH_STRING PhStdGetClientIdName( + _In_ PCLIENT_ID ClientId + ) +{ + static PH_QUEUED_LOCK cachedProcessesLock = PH_QUEUED_LOCK_INIT; + static PVOID processes = NULL; + static ULONG lastProcessesTickCount = 0; + + PPH_STRING name; + ULONG tickCount; + PSYSTEM_PROCESS_INFORMATION processInfo; + + // Get a new process list only if 2 seconds have passed since the last update. + + tickCount = GetTickCount(); + + if (tickCount - lastProcessesTickCount >= 2000) + { + PhAcquireQueuedLockExclusive(&cachedProcessesLock); + + // Re-check the tick count. + if (tickCount - lastProcessesTickCount >= 2000) + { + if (processes) + { + PhFree(processes); + processes = NULL; + } + + if (!NT_SUCCESS(PhEnumProcesses(&processes))) + { + PhReleaseQueuedLockExclusive(&cachedProcessesLock); + return PhCreateString(L"(Error querying processes)"); + } + + lastProcessesTickCount = tickCount; + } + + PhReleaseQueuedLockExclusive(&cachedProcessesLock); + } + + // Get a lock on the process list and get a name for the client ID. + + PhAcquireQueuedLockShared(&cachedProcessesLock); + + if (!processes) + { + PhReleaseQueuedLockShared(&cachedProcessesLock); + return NULL; + } + + processInfo = PhFindProcessInformation(processes, ClientId->UniqueProcess); + + if (ClientId->UniqueThread) + { + if (processInfo) + { + name = PhFormatString( + L"%.*s (%u): %u", + processInfo->ImageName.Length / 2, + processInfo->ImageName.Buffer, + HandleToUlong(ClientId->UniqueProcess), + HandleToUlong(ClientId->UniqueThread) + ); + } + else + { + name = PhFormatString( + L"Non-existent process (%u): %u", + HandleToUlong(ClientId->UniqueProcess), + HandleToUlong(ClientId->UniqueThread) + ); + } + } + else + { + if (processInfo) + { + name = PhFormatString( + L"%.*s (%u)", + processInfo->ImageName.Length / 2, + processInfo->ImageName.Buffer, + HandleToUlong(ClientId->UniqueProcess) + ); + } + else + { + name = PhFormatString(L"Non-existent process (%u)", HandleToUlong(ClientId->UniqueProcess)); + } + } + + PhReleaseQueuedLockShared(&cachedProcessesLock); + + return name; +} + +NTSTATUS PhpGetBestObjectName( + _In_ HANDLE ProcessHandle, + _In_ HANDLE Handle, + _In_ PPH_STRING ObjectName, + _In_ PPH_STRING TypeName, + _Out_ PPH_STRING *BestObjectName + ) +{ + NTSTATUS status; + PPH_STRING bestObjectName = NULL; + PPH_GET_CLIENT_ID_NAME handleGetClientIdName = PhHandleGetClientIdName; + + if (PhEqualString2(TypeName, L"EtwRegistration", TRUE)) + { + if (KphIsConnected()) + { + ETWREG_BASIC_INFORMATION basicInfo; + + status = KphQueryInformationObject( + ProcessHandle, + Handle, + KphObjectEtwRegBasicInformation, + &basicInfo, + sizeof(ETWREG_BASIC_INFORMATION), + NULL + ); + + if (NT_SUCCESS(status)) + { + static PH_STRINGREF publishersKeyName = PH_STRINGREF_INIT(L"Software\\Microsoft\\Windows\\CurrentVersion\\WINEVT\\Publishers\\"); + + PPH_STRING guidString; + PPH_STRING keyName; + HANDLE keyHandle; + PPH_STRING publisherName = NULL; + + guidString = PhFormatGuid(&basicInfo.Guid); + + // We should perform a lookup on the GUID to get the publisher name. + + keyName = PhConcatStringRef2(&publishersKeyName, &guidString->sr); + + if (NT_SUCCESS(PhOpenKey( + &keyHandle, + KEY_READ, + PH_KEY_LOCAL_MACHINE, + &keyName->sr, + 0 + ))) + { + publisherName = PhQueryRegistryString(keyHandle, NULL); + + if (publisherName && publisherName->Length == 0) + { + PhDereferenceObject(publisherName); + publisherName = NULL; + } + + NtClose(keyHandle); + } + + PhDereferenceObject(keyName); + + if (publisherName) + { + bestObjectName = publisherName; + PhDereferenceObject(guidString); + } + else + { + bestObjectName = guidString; + } + } + } + } + else if (PhEqualString2(TypeName, L"File", TRUE)) + { + // Convert the file name to a DOS file name. + bestObjectName = PhResolveDevicePrefix(ObjectName); + + if (!bestObjectName) + { + // The file doesn't have a DOS name. + PhSetReference(&bestObjectName, ObjectName); + } + + if (PhIsNullOrEmptyString(bestObjectName) && KphIsConnected()) + { + KPH_FILE_OBJECT_DRIVER fileObjectDriver; + PPH_STRING driverName; + + status = KphQueryInformationObject( + ProcessHandle, + Handle, + KphObjectFileObjectDriver, + &fileObjectDriver, + sizeof(KPH_FILE_OBJECT_DRIVER), + NULL + ); + + if (NT_SUCCESS(status) && fileObjectDriver.DriverHandle) + { + if (NT_SUCCESS(PhGetDriverName(fileObjectDriver.DriverHandle, &driverName))) + { + static PH_STRINGREF prefix = PH_STRINGREF_INIT(L"Unnamed file: "); + + PhMoveReference(&bestObjectName, PhConcatStringRef2(&prefix, &driverName->sr)); + PhDereferenceObject(driverName); + } + + NtClose(fileObjectDriver.DriverHandle); + } + } + } + else if (PhEqualString2(TypeName, L"Job", TRUE)) + { + HANDLE dupHandle; + PJOBOBJECT_BASIC_PROCESS_ID_LIST processIdList; + + status = NtDuplicateObject( + ProcessHandle, + Handle, + NtCurrentProcess(), + &dupHandle, + JOB_OBJECT_QUERY, + 0, + 0 + ); + + if (!NT_SUCCESS(status)) + goto CleanupExit; + + if (handleGetClientIdName && NT_SUCCESS(PhGetJobProcessIdList(dupHandle, &processIdList))) + { + PH_STRING_BUILDER sb; + ULONG i; + CLIENT_ID clientId; + PPH_STRING name; + + PhInitializeStringBuilder(&sb, 40); + clientId.UniqueThread = NULL; + + for (i = 0; i < processIdList->NumberOfProcessIdsInList; i++) + { + clientId.UniqueProcess = (HANDLE)processIdList->ProcessIdList[i]; + name = handleGetClientIdName(&clientId); + + if (name) + { + PhAppendStringBuilder(&sb, &name->sr); + PhAppendStringBuilder2(&sb, L"; "); + PhDereferenceObject(name); + } + } + + PhFree(processIdList); + + if (sb.String->Length != 0) + PhRemoveEndStringBuilder(&sb, 2); + + if (sb.String->Length == 0) + PhAppendStringBuilder2(&sb, L"(No processes)"); + + bestObjectName = PhFinalStringBuilderString(&sb); + } + + NtClose(dupHandle); + } + else if (PhEqualString2(TypeName, L"Key", TRUE)) + { + bestObjectName = PhFormatNativeKeyName(ObjectName); + } + else if (PhEqualString2(TypeName, L"Process", TRUE)) + { + CLIENT_ID clientId; + + clientId.UniqueThread = NULL; + + if (KphIsConnected()) + { + PROCESS_BASIC_INFORMATION basicInfo; + + status = KphQueryInformationObject( + ProcessHandle, + Handle, + KphObjectProcessBasicInformation, + &basicInfo, + sizeof(PROCESS_BASIC_INFORMATION), + NULL + ); + + if (!NT_SUCCESS(status)) + goto CleanupExit; + + clientId.UniqueProcess = basicInfo.UniqueProcessId; + } + else + { + HANDLE dupHandle; + PROCESS_BASIC_INFORMATION basicInfo; + + status = NtDuplicateObject( + ProcessHandle, + Handle, + NtCurrentProcess(), + &dupHandle, + ProcessQueryAccess, + 0, + 0 + ); + + if (!NT_SUCCESS(status)) + goto CleanupExit; + + status = PhGetProcessBasicInformation(dupHandle, &basicInfo); + NtClose(dupHandle); + + if (!NT_SUCCESS(status)) + goto CleanupExit; + + clientId.UniqueProcess = basicInfo.UniqueProcessId; + } + + if (handleGetClientIdName) + bestObjectName = handleGetClientIdName(&clientId); + } + else if (PhEqualString2(TypeName, L"Section", TRUE)) + { + HANDLE dupHandle; + PPH_STRING fileName; + + if (!PhIsNullOrEmptyString(ObjectName)) + goto CleanupExit; + + status = NtDuplicateObject( + ProcessHandle, + Handle, + NtCurrentProcess(), + &dupHandle, + SECTION_QUERY | SECTION_MAP_READ, + 0, + 0 + ); + + if (!NT_SUCCESS(status)) + goto CleanupExit; + + status = PhGetSectionFileName(dupHandle, &fileName); + + if (NT_SUCCESS(status)) + { + bestObjectName = PhResolveDevicePrefix(fileName); + PhDereferenceObject(fileName); + } + else + { + SECTION_BASIC_INFORMATION basicInfo; + + if (NT_SUCCESS(PhGetSectionBasicInformation(dupHandle, &basicInfo))) + { + PH_FORMAT format[4]; + PWSTR sectionType = L"Unknown"; + + if (basicInfo.AllocationAttributes & SEC_COMMIT) + sectionType = L"Commit"; + else if (basicInfo.AllocationAttributes & SEC_FILE) + sectionType = L"File"; + else if (basicInfo.AllocationAttributes & SEC_IMAGE) + sectionType = L"Image"; + else if (basicInfo.AllocationAttributes & SEC_RESERVE) + sectionType = L"Reserve"; + + PhInitFormatS(&format[0], sectionType); + PhInitFormatS(&format[1], L" ("); + PhInitFormatSize(&format[2], basicInfo.MaximumSize.QuadPart); + PhInitFormatC(&format[3], ')'); + bestObjectName = PhFormat(format, 4, 20); + } + } + + NtClose(dupHandle); + } + else if (PhEqualString2(TypeName, L"Thread", TRUE)) + { + CLIENT_ID clientId; + + if (KphIsConnected()) + { + THREAD_BASIC_INFORMATION basicInfo; + + status = KphQueryInformationObject( + ProcessHandle, + Handle, + KphObjectThreadBasicInformation, + &basicInfo, + sizeof(THREAD_BASIC_INFORMATION), + NULL + ); + + if (!NT_SUCCESS(status)) + goto CleanupExit; + + clientId = basicInfo.ClientId; + } + else + { + HANDLE dupHandle; + THREAD_BASIC_INFORMATION basicInfo; + + status = NtDuplicateObject( + ProcessHandle, + Handle, + NtCurrentProcess(), + &dupHandle, + ThreadQueryAccess, + 0, + 0 + ); + + if (!NT_SUCCESS(status)) + goto CleanupExit; + + status = PhGetThreadBasicInformation(dupHandle, &basicInfo); + NtClose(dupHandle); + + if (!NT_SUCCESS(status)) + goto CleanupExit; + + clientId = basicInfo.ClientId; + } + + if (handleGetClientIdName) + bestObjectName = handleGetClientIdName(&clientId); + } + else if (PhEqualString2(TypeName, L"TmEn", TRUE)) + { + HANDLE dupHandle; + ENLISTMENT_BASIC_INFORMATION basicInfo; + + status = NtDuplicateObject( + ProcessHandle, + Handle, + NtCurrentProcess(), + &dupHandle, + ENLISTMENT_QUERY_INFORMATION, + 0, + 0 + ); + + if (!NT_SUCCESS(status)) + goto CleanupExit; + + status = PhGetEnlistmentBasicInformation(dupHandle, &basicInfo); + NtClose(dupHandle); + + if (NT_SUCCESS(status)) + { + bestObjectName = PhFormatGuid(&basicInfo.EnlistmentId); + } + } + else if (PhEqualString2(TypeName, L"TmRm", TRUE)) + { + HANDLE dupHandle; + GUID guid; + PPH_STRING description; + + status = NtDuplicateObject( + ProcessHandle, + Handle, + NtCurrentProcess(), + &dupHandle, + RESOURCEMANAGER_QUERY_INFORMATION, + 0, + 0 + ); + + if (!NT_SUCCESS(status)) + goto CleanupExit; + + status = PhGetResourceManagerBasicInformation( + dupHandle, + &guid, + &description + ); + NtClose(dupHandle); + + if (NT_SUCCESS(status)) + { + if (!PhIsNullOrEmptyString(description)) + { + bestObjectName = description; + } + else + { + bestObjectName = PhFormatGuid(&guid); + + if (description) + PhDereferenceObject(description); + } + } + } + else if (PhEqualString2(TypeName, L"TmTm", TRUE)) + { + HANDLE dupHandle; + PPH_STRING logFileName = NULL; + TRANSACTIONMANAGER_BASIC_INFORMATION basicInfo; + + status = NtDuplicateObject( + ProcessHandle, + Handle, + NtCurrentProcess(), + &dupHandle, + TRANSACTIONMANAGER_QUERY_INFORMATION, + 0, + 0 + ); + + if (!NT_SUCCESS(status)) + goto CleanupExit; + + status = PhGetTransactionManagerLogFileName( + dupHandle, + &logFileName + ); + + if (NT_SUCCESS(status) && !PhIsNullOrEmptyString(logFileName)) + { + bestObjectName = PhGetFileName(logFileName); + PhDereferenceObject(logFileName); + } + else + { + if (logFileName) + PhDereferenceObject(logFileName); + + status = PhGetTransactionManagerBasicInformation( + dupHandle, + &basicInfo + ); + + if (NT_SUCCESS(status)) + { + bestObjectName = PhFormatGuid(&basicInfo.TmIdentity); + } + } + + NtClose(dupHandle); + } + else if (PhEqualString2(TypeName, L"TmTx", TRUE)) + { + HANDLE dupHandle; + PPH_STRING description = NULL; + TRANSACTION_BASIC_INFORMATION basicInfo; + + status = NtDuplicateObject( + ProcessHandle, + Handle, + NtCurrentProcess(), + &dupHandle, + TRANSACTION_QUERY_INFORMATION, + 0, + 0 + ); + + if (!NT_SUCCESS(status)) + goto CleanupExit; + + status = PhGetTransactionPropertiesInformation( + dupHandle, + NULL, + NULL, + &description + ); + + if (NT_SUCCESS(status) && !PhIsNullOrEmptyString(description)) + { + bestObjectName = description; + } + else + { + if (description) + PhDereferenceObject(description); + + status = PhGetTransactionBasicInformation( + dupHandle, + &basicInfo + ); + + if (NT_SUCCESS(status)) + { + bestObjectName = PhFormatGuid(&basicInfo.TransactionId); + } + } + + NtClose(dupHandle); + } + else if (PhEqualString2(TypeName, L"Token", TRUE)) + { + HANDLE dupHandle; + PTOKEN_USER tokenUser = NULL; + TOKEN_STATISTICS statistics = { 0 }; + + status = NtDuplicateObject( + ProcessHandle, + Handle, + NtCurrentProcess(), + &dupHandle, + TOKEN_QUERY, + 0, + 0 + ); + + if (!NT_SUCCESS(status)) + goto CleanupExit; + + status = PhGetTokenUser(dupHandle, &tokenUser); + PhGetTokenStatistics(dupHandle, &statistics); + + if (NT_SUCCESS(status)) + { + PPH_STRING fullName; + + fullName = PhGetSidFullName(tokenUser->User.Sid, TRUE, NULL); + + if (fullName) + { + PH_FORMAT format[4]; + + PhInitFormatSR(&format[0], fullName->sr); + PhInitFormatS(&format[1], L": 0x"); + PhInitFormatX(&format[2], statistics.AuthenticationId.LowPart); + PhInitFormatS(&format[3], statistics.TokenType == TokenPrimary ? L" (Primary)" : L" (Impersonation)"); + + bestObjectName = PhFormat(format, 4, fullName->Length + 8 + 16 + 16); + PhDereferenceObject(fullName); + } + + PhFree(tokenUser); + } + + NtClose(dupHandle); + } + +CleanupExit: + + if (!bestObjectName) + PhSetReference(&bestObjectName, ObjectName); + + *BestObjectName = bestObjectName; + + return STATUS_SUCCESS; +} + +/** + * Gets information for a handle. + * + * \param ProcessHandle A handle to the process in which the handle resides. + * \param Handle The handle value. + * \param ObjectTypeNumber The object type number of the handle. You can specify -1 for this + * parameter if the object type number is not known. + * \param BasicInformation A variable which receives basic information about the object. + * \param TypeName A variable which receives the object type name. + * \param ObjectName A variable which receives the object name. + * \param BestObjectName A variable which receives the formatted object name. + * + * \retval STATUS_INVALID_HANDLE The handle specified in \c ProcessHandle or \c Handle is invalid. + * \retval STATUS_INVALID_PARAMETER_3 The value specified in \c ObjectTypeNumber is invalid. + */ +NTSTATUS PhGetHandleInformation( + _In_ HANDLE ProcessHandle, + _In_ HANDLE Handle, + _In_ ULONG ObjectTypeNumber, + _Out_opt_ POBJECT_BASIC_INFORMATION BasicInformation, + _Out_opt_ PPH_STRING *TypeName, + _Out_opt_ PPH_STRING *ObjectName, + _Out_opt_ PPH_STRING *BestObjectName + ) +{ + NTSTATUS status; + NTSTATUS subStatus; + + status = PhGetHandleInformationEx( + ProcessHandle, + Handle, + ObjectTypeNumber, + 0, + &subStatus, + BasicInformation, + TypeName, + ObjectName, + BestObjectName, + NULL + ); + + if (!NT_SUCCESS(status)) + return status; + + // Fail if any component failed, for compatibility reasons. + if (!NT_SUCCESS(subStatus)) + { + if (TypeName) + PhClearReference(TypeName); + if (ObjectName) + PhClearReference(ObjectName); + if (BestObjectName) + PhClearReference(BestObjectName); + + return subStatus; + } + + return status; +} + +/** + * Gets information for a handle. + * + * \param ProcessHandle A handle to the process in which the handle resides. + * \param Handle The handle value. + * \param ObjectTypeNumber The object type number of the handle. You can specify -1 for this + * parameter if the object type number is not known. + * \param Flags Reserved. + * \param SubStatus A variable which receives the NTSTATUS value of the last component that fails. + * If all operations succeed, the value will be STATUS_SUCCESS. If the function returns an error + * status, this variable is not set. + * \param BasicInformation A variable which receives basic information about the object. + * \param TypeName A variable which receives the object type name. + * \param ObjectName A variable which receives the object name. + * \param BestObjectName A variable which receives the formatted object name. + * \param ExtraInformation Reserved. + * + * \retval STATUS_INVALID_HANDLE The handle specified in \c ProcessHandle or \c Handle is invalid. + * \retval STATUS_INVALID_PARAMETER_3 The value specified in \c ObjectTypeNumber is invalid. + * + * \remarks If \a BasicInformation or \a TypeName are specified, the function will fail if either + * cannot be queried. \a ObjectName, \a BestObjectName and \a ExtraInformation will be NULL if they + * cannot be queried. + */ +NTSTATUS PhGetHandleInformationEx( + _In_ HANDLE ProcessHandle, + _In_ HANDLE Handle, + _In_ ULONG ObjectTypeNumber, + _Reserved_ ULONG Flags, + _Out_opt_ PNTSTATUS SubStatus, + _Out_opt_ POBJECT_BASIC_INFORMATION BasicInformation, + _Out_opt_ PPH_STRING *TypeName, + _Out_opt_ PPH_STRING *ObjectName, + _Out_opt_ PPH_STRING *BestObjectName, + _Reserved_ PVOID *ExtraInformation + ) +{ + NTSTATUS status = STATUS_SUCCESS; + NTSTATUS subStatus = STATUS_SUCCESS; + HANDLE dupHandle = NULL; + PPH_STRING typeName = NULL; + PPH_STRING objectName = NULL; + PPH_STRING bestObjectName = NULL; + + if (Handle == NULL || Handle == NtCurrentProcess() || Handle == NtCurrentThread()) + return STATUS_INVALID_HANDLE; + if (ObjectTypeNumber != -1 && ObjectTypeNumber >= MAX_OBJECT_TYPE_NUMBER) + return STATUS_INVALID_PARAMETER_3; + + // Duplicate the handle if we're not using KPH. + if (!KphIsConnected()) + { + // However, we obviously don't need to duplicate it + // if the handle is in the current process. + if (ProcessHandle != NtCurrentProcess()) + { + status = NtDuplicateObject( + ProcessHandle, + Handle, + NtCurrentProcess(), + &dupHandle, + 0, + 0, + 0 + ); + + if (!NT_SUCCESS(status)) + return status; + } + else + { + dupHandle = Handle; + } + } + + // Get basic information. + if (BasicInformation) + { + status = PhpGetObjectBasicInformation( + ProcessHandle, + KphIsConnected() ? Handle : dupHandle, + BasicInformation + ); + + if (!NT_SUCCESS(status)) + goto CleanupExit; + } + + // Exit early if we don't need to get any other information. + if (!TypeName && !ObjectName && !BestObjectName) + goto CleanupExit; + + // Get the type name. + status = PhpGetObjectTypeName( + ProcessHandle, + KphIsConnected() ? Handle : dupHandle, + ObjectTypeNumber, + &typeName + ); + + if (!NT_SUCCESS(status)) + goto CleanupExit; + + // Exit early if we don't need to get the object name. + if (!ObjectName && !BestObjectName) + goto CleanupExit; + + // Get the object name. + // If we're dealing with a file handle we must take special precautions so we don't hang. + if (PhEqualString2(typeName, L"File", TRUE) && !KphIsConnected()) + { +#define QUERY_NORMALLY 0 +#define QUERY_WITH_TIMEOUT 1 +#define QUERY_FAIL 2 + + ULONG hackLevel = QUERY_WITH_TIMEOUT; + + // We can't use the timeout method on XP because hanging threads can't even be terminated! + if (WindowsVersion <= WINDOWS_XP) + hackLevel = QUERY_FAIL; + + if (hackLevel == QUERY_NORMALLY || hackLevel == QUERY_WITH_TIMEOUT) + { + status = PhpGetObjectName( + ProcessHandle, + KphIsConnected() ? Handle : dupHandle, + hackLevel == QUERY_WITH_TIMEOUT, + &objectName + ); + } + else + { + // Pretend the file object has no name. + objectName = PhReferenceEmptyString(); + status = STATUS_SUCCESS; + } + } + else + { + // Query the object normally. + status = PhpGetObjectName( + ProcessHandle, + KphIsConnected() ? Handle : dupHandle, + FALSE, + &objectName + ); + } + + if (!NT_SUCCESS(status)) + { + if (PhEqualString2(typeName, L"File", TRUE) && KphIsConnected()) + { + // PhpGetBestObjectName can provide us with a name. + objectName = PhReferenceEmptyString(); + status = STATUS_SUCCESS; + } + else + { + subStatus = status; + status = STATUS_SUCCESS; + goto CleanupExit; + } + } + + // Exit early if we don't need to get the best object name. + if (!BestObjectName) + goto CleanupExit; + + status = PhpGetBestObjectName( + ProcessHandle, + Handle, + objectName, + typeName, + &bestObjectName + ); + + if (!NT_SUCCESS(status)) + { + subStatus = status; + status = STATUS_SUCCESS; + goto CleanupExit; + } + +CleanupExit: + + if (NT_SUCCESS(status)) + { + if (SubStatus) + *SubStatus = subStatus; + if (TypeName) + PhSetReference(TypeName, typeName); + if (ObjectName) + PhSetReference(ObjectName, objectName); + if (BestObjectName) + PhSetReference(BestObjectName, bestObjectName); + } + + if (dupHandle && ProcessHandle != NtCurrentProcess()) + NtClose(dupHandle); + + PhClearReference(&typeName); + PhClearReference(&objectName); + PhClearReference(&bestObjectName); + + return status; +} + +NTSTATUS PhEnumObjectTypes( + _Out_ POBJECT_TYPES_INFORMATION *ObjectTypes + ) +{ + NTSTATUS status; + PVOID buffer; + ULONG bufferSize; + + bufferSize = 0x1000; + buffer = PhAllocate(bufferSize); + + while ((status = NtQueryObject( + NULL, + ObjectTypesInformation, + buffer, + bufferSize, + NULL + )) == STATUS_INFO_LENGTH_MISMATCH) + { + PhFree(buffer); + bufferSize *= 2; + + // Fail if we're resizing the buffer to something very large. + if (bufferSize > PH_LARGE_BUFFER_SIZE) + return STATUS_INSUFFICIENT_RESOURCES; + + buffer = PhAllocate(bufferSize); + } + + if (!NT_SUCCESS(status)) + { + PhFree(buffer); + return status; + } + + *ObjectTypes = (POBJECT_TYPES_INFORMATION)buffer; + + return status; +} + +ULONG PhGetObjectTypeNumber( + _In_ PUNICODE_STRING TypeName + ) +{ + POBJECT_TYPES_INFORMATION objectTypes; + POBJECT_TYPE_INFORMATION objectType; + ULONG objectIndex = -1; + ULONG i; + + if (NT_SUCCESS(PhEnumObjectTypes(&objectTypes))) + { + objectType = PH_FIRST_OBJECT_TYPE(objectTypes); + + for (i = 0; i < objectTypes->NumberOfTypes; i++) + { + if (RtlEqualUnicodeString(&objectType->TypeName, TypeName, TRUE)) + { + if (WindowsVersion >= WINDOWS_8_1) + { + objectIndex = objectType->TypeIndex; + break; + } + else if (WindowsVersion >= WINDOWS_7) + { + objectIndex = i + 2; + break; + } + else + { + objectIndex = i + 1; + break; + } + } + + objectType = PH_NEXT_OBJECT_TYPE(objectType); + } + + PhFree(objectTypes); + } + + return objectIndex; +} + +PPHP_CALL_WITH_TIMEOUT_THREAD_CONTEXT PhpAcquireCallWithTimeoutThread( + _In_opt_ PLARGE_INTEGER Timeout + ) +{ + static PH_INITONCE initOnce = PH_INITONCE_INIT; + + PPHP_CALL_WITH_TIMEOUT_THREAD_CONTEXT threadContext; + PSLIST_ENTRY listEntry; + PH_QUEUED_WAIT_BLOCK waitBlock; + + if (PhBeginInitOnce(&initOnce)) + { + ULONG i; + + for (i = 0; i < PH_QUERY_HACK_MAX_THREADS; i++) + { + threadContext = PhAllocate(sizeof(PHP_CALL_WITH_TIMEOUT_THREAD_CONTEXT)); + memset(threadContext, 0, sizeof(PHP_CALL_WITH_TIMEOUT_THREAD_CONTEXT)); + RtlInterlockedPushEntrySList(&PhpCallWithTimeoutThreadListHead, &threadContext->ListEntry); + } + + PhEndInitOnce(&initOnce); + } + + while (TRUE) + { + if (listEntry = RtlInterlockedPopEntrySList(&PhpCallWithTimeoutThreadListHead)) + break; + + if (!Timeout || Timeout->QuadPart != 0) + { + PhQueueWakeEvent(&PhpCallWithTimeoutThreadReleaseEvent, &waitBlock); + + if (listEntry = RtlInterlockedPopEntrySList(&PhpCallWithTimeoutThreadListHead)) + { + // A new entry has just become available; cancel the wait. + PhSetWakeEvent(&PhpCallWithTimeoutThreadReleaseEvent, &waitBlock); + break; + } + else + { + PhWaitForWakeEvent(&PhpCallWithTimeoutThreadReleaseEvent, &waitBlock, FALSE, Timeout); + // TODO: Recompute the timeout value. + } + } + else + { + return NULL; + } + } + + return CONTAINING_RECORD(listEntry, PHP_CALL_WITH_TIMEOUT_THREAD_CONTEXT, ListEntry); +} + +VOID PhpReleaseCallWithTimeoutThread( + _Inout_ PPHP_CALL_WITH_TIMEOUT_THREAD_CONTEXT ThreadContext + ) +{ + RtlInterlockedPushEntrySList(&PhpCallWithTimeoutThreadListHead, &ThreadContext->ListEntry); + PhSetWakeEvent(&PhpCallWithTimeoutThreadReleaseEvent, NULL); +} + +NTSTATUS PhpCallWithTimeout( + _Inout_ PPHP_CALL_WITH_TIMEOUT_THREAD_CONTEXT ThreadContext, + _In_ PUSER_THREAD_START_ROUTINE Routine, + _In_opt_ PVOID Context, + _In_ PLARGE_INTEGER Timeout + ) +{ + NTSTATUS status; + + // Create objects if necessary. + + if (!ThreadContext->StartEventHandle) + { + if (!NT_SUCCESS(status = NtCreateEvent(&ThreadContext->StartEventHandle, EVENT_ALL_ACCESS, NULL, SynchronizationEvent, FALSE))) + return status; + } + + if (!ThreadContext->CompletedEventHandle) + { + if (!NT_SUCCESS(status = NtCreateEvent(&ThreadContext->CompletedEventHandle, EVENT_ALL_ACCESS, NULL, SynchronizationEvent, FALSE))) + return status; + } + + // Create a query thread if we don't have one. + if (!ThreadContext->ThreadHandle) + { + CLIENT_ID clientId; + + NtClearEvent(ThreadContext->StartEventHandle); + NtClearEvent(ThreadContext->CompletedEventHandle); + + if (!NT_SUCCESS(status = RtlCreateUserThread( + NtCurrentProcess(), + NULL, + FALSE, + 0, + 0, + 32 * 1024, + PhpCallWithTimeoutThreadStart, + ThreadContext, + &ThreadContext->ThreadHandle, + &clientId + ))) + { + return status; + } + + // Wait for the thread to initialize. + NtWaitForSingleObject(ThreadContext->CompletedEventHandle, FALSE, NULL); + } + + ThreadContext->Routine = Routine; + ThreadContext->Context = Context; + + NtSetEvent(ThreadContext->StartEventHandle, NULL); + status = NtWaitForSingleObject(ThreadContext->CompletedEventHandle, FALSE, Timeout); + + ThreadContext->Routine = NULL; + MemoryBarrier(); + ThreadContext->Context = NULL; + + if (status != STATUS_WAIT_0) + { + // The operation timed out, or there was an error. Kill the thread. On Vista and above, the + // thread stack is freed automatically. + NtTerminateThread(ThreadContext->ThreadHandle, STATUS_UNSUCCESSFUL); + status = NtWaitForSingleObject(ThreadContext->ThreadHandle, FALSE, NULL); + NtClose(ThreadContext->ThreadHandle); + ThreadContext->ThreadHandle = NULL; + + status = STATUS_UNSUCCESSFUL; + } + + return status; +} + +NTSTATUS PhpCallWithTimeoutThreadStart( + _In_ PVOID Parameter + ) +{ + PPHP_CALL_WITH_TIMEOUT_THREAD_CONTEXT threadContext = Parameter; + + NtSetEvent(threadContext->CompletedEventHandle, NULL); + + while (TRUE) + { + if (NtWaitForSingleObject(threadContext->StartEventHandle, FALSE, NULL) != STATUS_WAIT_0) + continue; + + if (threadContext->Routine) + threadContext->Routine(threadContext->Context); + + NtSetEvent(threadContext->CompletedEventHandle, NULL); + } + + return STATUS_SUCCESS; +} + +NTSTATUS PhCallWithTimeout( + _In_ PUSER_THREAD_START_ROUTINE Routine, + _In_opt_ PVOID Context, + _In_opt_ PLARGE_INTEGER AcquireTimeout, + _In_ PLARGE_INTEGER CallTimeout + ) +{ + NTSTATUS status; + PPHP_CALL_WITH_TIMEOUT_THREAD_CONTEXT threadContext; + + if (threadContext = PhpAcquireCallWithTimeoutThread(AcquireTimeout)) + { + status = PhpCallWithTimeout(threadContext, Routine, Context, CallTimeout); + PhpReleaseCallWithTimeoutThread(threadContext); + } + else + { + status = STATUS_UNSUCCESSFUL; + } + + return status; +} + +NTSTATUS PhpCommonQueryObjectRoutine( + _In_ PVOID Parameter + ) +{ + PPHP_QUERY_OBJECT_COMMON_CONTEXT context = Parameter; + + switch (context->Work) + { + case NtQueryObjectWork: + context->Status = NtQueryObject( + context->u.NtQueryObject.Handle, + context->u.NtQueryObject.ObjectInformationClass, + context->u.NtQueryObject.ObjectInformation, + context->u.NtQueryObject.ObjectInformationLength, + context->u.NtQueryObject.ReturnLength + ); + break; + case NtQuerySecurityObjectWork: + context->Status = NtQuerySecurityObject( + context->u.NtQuerySecurityObject.Handle, + context->u.NtQuerySecurityObject.SecurityInformation, + context->u.NtQuerySecurityObject.SecurityDescriptor, + context->u.NtQuerySecurityObject.Length, + context->u.NtQuerySecurityObject.LengthNeeded + ); + break; + case NtSetSecurityObjectWork: + context->Status = NtSetSecurityObject( + context->u.NtSetSecurityObject.Handle, + context->u.NtSetSecurityObject.SecurityInformation, + context->u.NtSetSecurityObject.SecurityDescriptor + ); + break; + default: + context->Status = STATUS_INVALID_PARAMETER; + break; + } + + return STATUS_SUCCESS; +} + +NTSTATUS PhpCommonQueryObjectWithTimeout( + _In_ PPHP_QUERY_OBJECT_COMMON_CONTEXT Context + ) +{ + NTSTATUS status; + LARGE_INTEGER timeout; + + timeout.QuadPart = -1 * PH_TIMEOUT_SEC; + status = PhCallWithTimeout(PhpCommonQueryObjectRoutine, Context, NULL, &timeout); + + if (NT_SUCCESS(status)) + status = Context->Status; + + PhFree(Context); + + return status; +} + +NTSTATUS PhCallNtQueryObjectWithTimeout( + _In_ HANDLE Handle, + _In_ OBJECT_INFORMATION_CLASS ObjectInformationClass, + _Out_writes_bytes_opt_(ObjectInformationLength) PVOID ObjectInformation, + _In_ ULONG ObjectInformationLength, + _Out_opt_ PULONG ReturnLength + ) +{ + PPHP_QUERY_OBJECT_COMMON_CONTEXT context; + + context = PhAllocate(sizeof(PHP_QUERY_OBJECT_COMMON_CONTEXT)); + context->Work = NtQueryObjectWork; + context->Status = STATUS_UNSUCCESSFUL; + context->u.NtQueryObject.Handle = Handle; + context->u.NtQueryObject.ObjectInformationClass = ObjectInformationClass; + context->u.NtQueryObject.ObjectInformation = ObjectInformation; + context->u.NtQueryObject.ObjectInformationLength = ObjectInformationLength; + context->u.NtQueryObject.ReturnLength = ReturnLength; + + return PhpCommonQueryObjectWithTimeout(context); +} + +NTSTATUS PhCallNtQuerySecurityObjectWithTimeout( + _In_ HANDLE Handle, + _In_ SECURITY_INFORMATION SecurityInformation, + _Out_writes_bytes_opt_(Length) PSECURITY_DESCRIPTOR SecurityDescriptor, + _In_ ULONG Length, + _Out_ PULONG LengthNeeded + ) +{ + PPHP_QUERY_OBJECT_COMMON_CONTEXT context; + + context = PhAllocate(sizeof(PHP_QUERY_OBJECT_COMMON_CONTEXT)); + context->Work = NtQuerySecurityObjectWork; + context->Status = STATUS_UNSUCCESSFUL; + context->u.NtQuerySecurityObject.Handle = Handle; + context->u.NtQuerySecurityObject.SecurityInformation = SecurityInformation; + context->u.NtQuerySecurityObject.SecurityDescriptor = SecurityDescriptor; + context->u.NtQuerySecurityObject.Length = Length; + context->u.NtQuerySecurityObject.LengthNeeded = LengthNeeded; + + return PhpCommonQueryObjectWithTimeout(context); +} + +NTSTATUS PhCallNtSetSecurityObjectWithTimeout( + _In_ HANDLE Handle, + _In_ SECURITY_INFORMATION SecurityInformation, + _In_ PSECURITY_DESCRIPTOR SecurityDescriptor + ) +{ + PPHP_QUERY_OBJECT_COMMON_CONTEXT context; + + context = PhAllocate(sizeof(PHP_QUERY_OBJECT_COMMON_CONTEXT)); + context->Work = NtSetSecurityObjectWork; + context->Status = STATUS_UNSUCCESSFUL; + context->u.NtSetSecurityObject.Handle = Handle; + context->u.NtSetSecurityObject.SecurityInformation = SecurityInformation; + context->u.NtSetSecurityObject.SecurityDescriptor = SecurityDescriptor; + + return PhpCommonQueryObjectWithTimeout(context); +} diff --git a/phlib/icotobmp.c b/phlib/icotobmp.c index c969a01b5e19..9d4ce2878c84 100644 --- a/phlib/icotobmp.c +++ b/phlib/icotobmp.c @@ -1,192 +1,192 @@ -#include -#include -#include - -// code from http://msdn.microsoft.com/en-us/library/bb757020.aspx - -static HBITMAP PhpCreateBitmap32( - _In_ HDC hdc, - _In_ ULONG Width, - _In_ ULONG Height, - _Outptr_opt_ PVOID *Bits - ) -{ - BITMAPINFO bitmapInfo; - - memset(&bitmapInfo, 0, sizeof(BITMAPINFO)); - bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); - bitmapInfo.bmiHeader.biPlanes = 1; - bitmapInfo.bmiHeader.biCompression = BI_RGB; - - bitmapInfo.bmiHeader.biWidth = Width; - bitmapInfo.bmiHeader.biHeight = Height; - bitmapInfo.bmiHeader.biBitCount = 32; - - return CreateDIBSection(hdc, &bitmapInfo, DIB_RGB_COLORS, Bits, NULL, 0); -} - -static BOOLEAN PhpHasAlpha( - _In_ PULONG Argb, - _In_ ULONG Width, - _In_ ULONG Height, - _In_ ULONG RowWidth - ) -{ - ULONG delta; - ULONG x; - ULONG y; - - delta = RowWidth - Width; - - for (y = Width; y; y--) - { - for (x = Height; x; x--) - { - if (*Argb++ & 0xff000000) - return TRUE; - } - - Argb += delta; - } - - return FALSE; -} - -static VOID PhpConvertToPArgb32( - _In_ HDC hdc, - _Inout_ PULONG Argb, - _In_ HBITMAP Bitmap, - _In_ ULONG Width, - _In_ ULONG Height, - _In_ ULONG RowWidth - ) -{ - BITMAPINFO bitmapInfo; - PVOID bits; - - memset(&bitmapInfo, 0, sizeof(BITMAPINFO)); - bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); - bitmapInfo.bmiHeader.biPlanes = 1; - bitmapInfo.bmiHeader.biCompression = BI_RGB; - - bitmapInfo.bmiHeader.biWidth = Width; - bitmapInfo.bmiHeader.biHeight = Height; - bitmapInfo.bmiHeader.biBitCount = 32; - - bits = PhAllocate(Width * sizeof(ULONG) * Height); - - if (GetDIBits(hdc, Bitmap, 0, Height, bits, &bitmapInfo, DIB_RGB_COLORS) == Height) - { - PULONG argbMask; - ULONG delta; - ULONG x; - ULONG y; - - argbMask = (PULONG)bits; - delta = RowWidth - Width; - - for (y = Height; y; y--) - { - for (x = Width; x; x--) - { - if (*argbMask++) - { - *Argb++ = 0; // transparent - } - else - { - *Argb++ |= 0xff000000; // opaque - } - } - - Argb += delta; - } - } - - PhFree(bits); -} - -static VOID PhpConvertToPArgb32IfNeeded( - _In_ HPAINTBUFFER PaintBuffer, - _In_ HDC hdc, - _In_ HICON Icon, - _In_ ULONG Width, - _In_ ULONG Height - ) -{ - RGBQUAD *quad; - ULONG rowWidth; - - if (SUCCEEDED(GetBufferedPaintBits(PaintBuffer, &quad, &rowWidth))) - { - PULONG argb = (PULONG)quad; - - if (!PhpHasAlpha(argb, Width, Height, rowWidth)) - { - ICONINFO iconInfo; - - if (GetIconInfo(Icon, &iconInfo)) - { - if (iconInfo.hbmMask) - { - PhpConvertToPArgb32(hdc, argb, iconInfo.hbmMask, Width, Height, rowWidth); - } - - DeleteObject(iconInfo.hbmColor); - DeleteObject(iconInfo.hbmMask); - } - } - } -} - -HBITMAP PhIconToBitmap( - _In_ HICON Icon, - _In_ ULONG Width, - _In_ ULONG Height - ) -{ - HBITMAP bitmap; - RECT iconRectangle; - HDC screenHdc; - HDC hdc; - HBITMAP oldBitmap; - BLENDFUNCTION blendFunction = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA }; - BP_PAINTPARAMS paintParams = { sizeof(paintParams) }; - HDC bufferHdc; - HPAINTBUFFER paintBuffer; - - iconRectangle.left = 0; - iconRectangle.top = 0; - iconRectangle.right = Width; - iconRectangle.bottom = Height; - - screenHdc = GetDC(NULL); - hdc = CreateCompatibleDC(screenHdc); - bitmap = PhpCreateBitmap32(screenHdc, Width, Height, NULL); - ReleaseDC(NULL, screenHdc); - oldBitmap = SelectObject(hdc, bitmap); - - paintParams.dwFlags = BPPF_ERASE; - paintParams.pBlendFunction = &blendFunction; - - if (paintBuffer = BeginBufferedPaint(hdc, &iconRectangle, BPBF_DIB, &paintParams, &bufferHdc)) - { - DrawIconEx(bufferHdc, 0, 0, Icon, Width, Height, 0, NULL, DI_NORMAL); - // If the icon did not have an alpha channel, we need to convert the buffer to PARGB. - PhpConvertToPArgb32IfNeeded(paintBuffer, hdc, Icon, Width, Height); - // This will write the buffer contents to the destination bitmap. - EndBufferedPaint(paintBuffer, TRUE); - } - else - { - // Default to unbuffered painting. - FillRect(hdc, &iconRectangle, (HBRUSH)(COLOR_WINDOW + 1)); - DrawIconEx(hdc, 0, 0, Icon, Width, Height, 0, NULL, DI_NORMAL); - SelectObject(hdc, oldBitmap); - } - - SelectObject(hdc, oldBitmap); - DeleteDC(hdc); - - return bitmap; -} +#include +#include +#include + +// code from http://msdn.microsoft.com/en-us/library/bb757020.aspx + +static HBITMAP PhpCreateBitmap32( + _In_ HDC hdc, + _In_ ULONG Width, + _In_ ULONG Height, + _Outptr_opt_ PVOID *Bits + ) +{ + BITMAPINFO bitmapInfo; + + memset(&bitmapInfo, 0, sizeof(BITMAPINFO)); + bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bitmapInfo.bmiHeader.biPlanes = 1; + bitmapInfo.bmiHeader.biCompression = BI_RGB; + + bitmapInfo.bmiHeader.biWidth = Width; + bitmapInfo.bmiHeader.biHeight = Height; + bitmapInfo.bmiHeader.biBitCount = 32; + + return CreateDIBSection(hdc, &bitmapInfo, DIB_RGB_COLORS, Bits, NULL, 0); +} + +static BOOLEAN PhpHasAlpha( + _In_ PULONG Argb, + _In_ ULONG Width, + _In_ ULONG Height, + _In_ ULONG RowWidth + ) +{ + ULONG delta; + ULONG x; + ULONG y; + + delta = RowWidth - Width; + + for (y = Width; y; y--) + { + for (x = Height; x; x--) + { + if (*Argb++ & 0xff000000) + return TRUE; + } + + Argb += delta; + } + + return FALSE; +} + +static VOID PhpConvertToPArgb32( + _In_ HDC hdc, + _Inout_ PULONG Argb, + _In_ HBITMAP Bitmap, + _In_ ULONG Width, + _In_ ULONG Height, + _In_ ULONG RowWidth + ) +{ + BITMAPINFO bitmapInfo; + PVOID bits; + + memset(&bitmapInfo, 0, sizeof(BITMAPINFO)); + bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bitmapInfo.bmiHeader.biPlanes = 1; + bitmapInfo.bmiHeader.biCompression = BI_RGB; + + bitmapInfo.bmiHeader.biWidth = Width; + bitmapInfo.bmiHeader.biHeight = Height; + bitmapInfo.bmiHeader.biBitCount = 32; + + bits = PhAllocate(Width * sizeof(ULONG) * Height); + + if (GetDIBits(hdc, Bitmap, 0, Height, bits, &bitmapInfo, DIB_RGB_COLORS) == Height) + { + PULONG argbMask; + ULONG delta; + ULONG x; + ULONG y; + + argbMask = (PULONG)bits; + delta = RowWidth - Width; + + for (y = Height; y; y--) + { + for (x = Width; x; x--) + { + if (*argbMask++) + { + *Argb++ = 0; // transparent + } + else + { + *Argb++ |= 0xff000000; // opaque + } + } + + Argb += delta; + } + } + + PhFree(bits); +} + +static VOID PhpConvertToPArgb32IfNeeded( + _In_ HPAINTBUFFER PaintBuffer, + _In_ HDC hdc, + _In_ HICON Icon, + _In_ ULONG Width, + _In_ ULONG Height + ) +{ + RGBQUAD *quad; + ULONG rowWidth; + + if (SUCCEEDED(GetBufferedPaintBits(PaintBuffer, &quad, &rowWidth))) + { + PULONG argb = (PULONG)quad; + + if (!PhpHasAlpha(argb, Width, Height, rowWidth)) + { + ICONINFO iconInfo; + + if (GetIconInfo(Icon, &iconInfo)) + { + if (iconInfo.hbmMask) + { + PhpConvertToPArgb32(hdc, argb, iconInfo.hbmMask, Width, Height, rowWidth); + } + + DeleteObject(iconInfo.hbmColor); + DeleteObject(iconInfo.hbmMask); + } + } + } +} + +HBITMAP PhIconToBitmap( + _In_ HICON Icon, + _In_ ULONG Width, + _In_ ULONG Height + ) +{ + HBITMAP bitmap; + RECT iconRectangle; + HDC screenHdc; + HDC hdc; + HBITMAP oldBitmap; + BLENDFUNCTION blendFunction = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA }; + BP_PAINTPARAMS paintParams = { sizeof(paintParams) }; + HDC bufferHdc; + HPAINTBUFFER paintBuffer; + + iconRectangle.left = 0; + iconRectangle.top = 0; + iconRectangle.right = Width; + iconRectangle.bottom = Height; + + screenHdc = GetDC(NULL); + hdc = CreateCompatibleDC(screenHdc); + bitmap = PhpCreateBitmap32(screenHdc, Width, Height, NULL); + ReleaseDC(NULL, screenHdc); + oldBitmap = SelectObject(hdc, bitmap); + + paintParams.dwFlags = BPPF_ERASE; + paintParams.pBlendFunction = &blendFunction; + + if (paintBuffer = BeginBufferedPaint(hdc, &iconRectangle, BPBF_DIB, &paintParams, &bufferHdc)) + { + DrawIconEx(bufferHdc, 0, 0, Icon, Width, Height, 0, NULL, DI_NORMAL); + // If the icon did not have an alpha channel, we need to convert the buffer to PARGB. + PhpConvertToPArgb32IfNeeded(paintBuffer, hdc, Icon, Width, Height); + // This will write the buffer contents to the destination bitmap. + EndBufferedPaint(paintBuffer, TRUE); + } + else + { + // Default to unbuffered painting. + FillRect(hdc, &iconRectangle, (HBRUSH)(COLOR_WINDOW + 1)); + DrawIconEx(hdc, 0, 0, Icon, Width, Height, 0, NULL, DI_NORMAL); + SelectObject(hdc, oldBitmap); + } + + SelectObject(hdc, oldBitmap); + DeleteDC(hdc); + + return bitmap; +} diff --git a/phlib/include/apiimport.h b/phlib/include/apiimport.h index 8a046e762054..80769e38bc04 100644 --- a/phlib/include/apiimport.h +++ b/phlib/include/apiimport.h @@ -1,86 +1,86 @@ -#ifndef _PH_APIIMPORT_H -#define _PH_APIIMPORT_H - -// comctl32 - -typedef HRESULT (WINAPI *_TaskDialogIndirect)( - _In_ const struct _TASKDIALOGCONFIG *pTaskConfig, - _In_ int *pnButton, - _In_ int *pnRadioButton, - _In_ BOOL *pfVerificationFlagChecked - ); - -// ntdll - -typedef NTSTATUS (NTAPI *_NtQueryInformationEnlistment)( - _In_ HANDLE EnlistmentHandle, - _In_ ENLISTMENT_INFORMATION_CLASS EnlistmentInformationClass, - _Out_writes_bytes_(EnlistmentInformationLength) PVOID EnlistmentInformation, - _In_ ULONG EnlistmentInformationLength, - _Out_opt_ PULONG ReturnLength - ); - -typedef NTSTATUS (NTAPI *_NtQueryInformationResourceManager)( - _In_ HANDLE ResourceManagerHandle, - _In_ RESOURCEMANAGER_INFORMATION_CLASS ResourceManagerInformationClass, - _Out_writes_bytes_(ResourceManagerInformationLength) PVOID ResourceManagerInformation, - _In_ ULONG ResourceManagerInformationLength, - _Out_opt_ PULONG ReturnLength - ); - -typedef NTSTATUS (NTAPI *_NtQueryInformationTransaction)( - _In_ HANDLE TransactionHandle, - _In_ TRANSACTION_INFORMATION_CLASS TransactionInformationClass, - _Out_writes_bytes_(TransactionInformationLength) PVOID TransactionInformation, - _In_ ULONG TransactionInformationLength, - _Out_opt_ PULONG ReturnLength - ); - -typedef NTSTATUS (NTAPI *_NtQueryInformationTransactionManager)( - _In_ HANDLE TransactionManagerHandle, - _In_ TRANSACTIONMANAGER_INFORMATION_CLASS TransactionManagerInformationClass, - _Out_writes_bytes_(TransactionManagerInformationLength) PVOID TransactionManagerInformation, - _In_ ULONG TransactionManagerInformationLength, - _Out_opt_ PULONG ReturnLength - ); - -// shell32 - -#if defined(_M_IX86) -#define __unaligned -#endif - -typedef HRESULT (WINAPI *_SHCreateShellItem)( - _In_opt_ const struct _ITEMIDLIST __unaligned *pidlParent, - _In_opt_ struct IShellFolder *psfParent, - _In_ const struct _ITEMIDLIST __unaligned *pidl, - _Out_ struct IShellItem **ppsi - ); - -typedef HRESULT (WINAPI *_SHOpenFolderAndSelectItems)( - _In_ const struct _ITEMIDLIST __unaligned *pidlFolder, - _In_ UINT cidl, - _In_reads_opt_(cidl) const struct _ITEMIDLIST __unaligned **apidl, - _In_ DWORD dwFlags - ); - -typedef HRESULT (WINAPI *_SHParseDisplayName)( - _In_ LPCWSTR pszName, - _In_opt_ struct IBindCtx *pbc, - _Out_ const struct _ITEMIDLIST __unaligned **ppidl, - _In_ ULONG sfgaoIn, - _Out_ ULONG *psfgaoOut - ); - -#define PH_DECLARE_IMPORT(Name) _##Name Name##_Import(VOID) - -PH_DECLARE_IMPORT(TaskDialogIndirect); -PH_DECLARE_IMPORT(NtQueryInformationEnlistment); -PH_DECLARE_IMPORT(NtQueryInformationResourceManager); -PH_DECLARE_IMPORT(NtQueryInformationTransaction); -PH_DECLARE_IMPORT(NtQueryInformationTransactionManager); -PH_DECLARE_IMPORT(SHCreateShellItem); -PH_DECLARE_IMPORT(SHOpenFolderAndSelectItems); -PH_DECLARE_IMPORT(SHParseDisplayName); - -#endif +#ifndef _PH_APIIMPORT_H +#define _PH_APIIMPORT_H + +// comctl32 + +typedef HRESULT (WINAPI *_TaskDialogIndirect)( + _In_ const struct _TASKDIALOGCONFIG *pTaskConfig, + _In_ int *pnButton, + _In_ int *pnRadioButton, + _In_ BOOL *pfVerificationFlagChecked + ); + +// ntdll + +typedef NTSTATUS (NTAPI *_NtQueryInformationEnlistment)( + _In_ HANDLE EnlistmentHandle, + _In_ ENLISTMENT_INFORMATION_CLASS EnlistmentInformationClass, + _Out_writes_bytes_(EnlistmentInformationLength) PVOID EnlistmentInformation, + _In_ ULONG EnlistmentInformationLength, + _Out_opt_ PULONG ReturnLength + ); + +typedef NTSTATUS (NTAPI *_NtQueryInformationResourceManager)( + _In_ HANDLE ResourceManagerHandle, + _In_ RESOURCEMANAGER_INFORMATION_CLASS ResourceManagerInformationClass, + _Out_writes_bytes_(ResourceManagerInformationLength) PVOID ResourceManagerInformation, + _In_ ULONG ResourceManagerInformationLength, + _Out_opt_ PULONG ReturnLength + ); + +typedef NTSTATUS (NTAPI *_NtQueryInformationTransaction)( + _In_ HANDLE TransactionHandle, + _In_ TRANSACTION_INFORMATION_CLASS TransactionInformationClass, + _Out_writes_bytes_(TransactionInformationLength) PVOID TransactionInformation, + _In_ ULONG TransactionInformationLength, + _Out_opt_ PULONG ReturnLength + ); + +typedef NTSTATUS (NTAPI *_NtQueryInformationTransactionManager)( + _In_ HANDLE TransactionManagerHandle, + _In_ TRANSACTIONMANAGER_INFORMATION_CLASS TransactionManagerInformationClass, + _Out_writes_bytes_(TransactionManagerInformationLength) PVOID TransactionManagerInformation, + _In_ ULONG TransactionManagerInformationLength, + _Out_opt_ PULONG ReturnLength + ); + +// shell32 + +#if defined(_M_IX86) +#define __unaligned +#endif + +typedef HRESULT (WINAPI *_SHCreateShellItem)( + _In_opt_ const struct _ITEMIDLIST __unaligned *pidlParent, + _In_opt_ struct IShellFolder *psfParent, + _In_ const struct _ITEMIDLIST __unaligned *pidl, + _Out_ struct IShellItem **ppsi + ); + +typedef HRESULT (WINAPI *_SHOpenFolderAndSelectItems)( + _In_ const struct _ITEMIDLIST __unaligned *pidlFolder, + _In_ UINT cidl, + _In_reads_opt_(cidl) const struct _ITEMIDLIST __unaligned **apidl, + _In_ DWORD dwFlags + ); + +typedef HRESULT (WINAPI *_SHParseDisplayName)( + _In_ LPCWSTR pszName, + _In_opt_ struct IBindCtx *pbc, + _Out_ const struct _ITEMIDLIST __unaligned **ppidl, + _In_ ULONG sfgaoIn, + _Out_ ULONG *psfgaoOut + ); + +#define PH_DECLARE_IMPORT(Name) _##Name Name##_Import(VOID) + +PH_DECLARE_IMPORT(TaskDialogIndirect); +PH_DECLARE_IMPORT(NtQueryInformationEnlistment); +PH_DECLARE_IMPORT(NtQueryInformationResourceManager); +PH_DECLARE_IMPORT(NtQueryInformationTransaction); +PH_DECLARE_IMPORT(NtQueryInformationTransactionManager); +PH_DECLARE_IMPORT(SHCreateShellItem); +PH_DECLARE_IMPORT(SHOpenFolderAndSelectItems); +PH_DECLARE_IMPORT(SHParseDisplayName); + +#endif diff --git a/phlib/include/circbuf.h b/phlib/include/circbuf.h index 9c3564cfc183..b3e0d761651b 100644 --- a/phlib/include/circbuf.h +++ b/phlib/include/circbuf.h @@ -1,26 +1,26 @@ -#ifndef _PH_CIRCBUF_H -#define _PH_CIRCBUF_H - -#define PH_CIRCULAR_BUFFER_POWER_OF_TWO_SIZE - -#undef T -#define T ULONG -#include "circbuf_h.h" - -#undef T -#define T ULONG64 -#include "circbuf_h.h" - -#undef T -#define T PVOID -#include "circbuf_h.h" - -#undef T -#define T SIZE_T -#include "circbuf_h.h" - -#undef T -#define T FLOAT -#include "circbuf_h.h" - -#endif +#ifndef _PH_CIRCBUF_H +#define _PH_CIRCBUF_H + +#define PH_CIRCULAR_BUFFER_POWER_OF_TWO_SIZE + +#undef T +#define T ULONG +#include "circbuf_h.h" + +#undef T +#define T ULONG64 +#include "circbuf_h.h" + +#undef T +#define T PVOID +#include "circbuf_h.h" + +#undef T +#define T SIZE_T +#include "circbuf_h.h" + +#undef T +#define T FLOAT +#include "circbuf_h.h" + +#endif diff --git a/phlib/include/circbuf_h.h b/phlib/include/circbuf_h.h index 7b775b956000..84b9c105257f 100644 --- a/phlib/include/circbuf_h.h +++ b/phlib/include/circbuf_h.h @@ -1,140 +1,140 @@ -#ifdef T - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct T___(_PH_CIRCULAR_BUFFER, T) -{ - ULONG Size; -#ifdef PH_CIRCULAR_BUFFER_POWER_OF_TWO_SIZE - ULONG SizeMinusOne; -#endif - ULONG Count; - LONG Index; - T *Data; -} T___(PH_CIRCULAR_BUFFER, T), *T___(PPH_CIRCULAR_BUFFER, T); - -PHLIBAPI -VOID -NTAPI -T___(PhInitializeCircularBuffer, T)( - _Out_ T___(PPH_CIRCULAR_BUFFER, T) Buffer, - _In_ ULONG Size - ); - -PHLIBAPI -VOID -NTAPI -T___(PhDeleteCircularBuffer, T)( - _Inout_ T___(PPH_CIRCULAR_BUFFER, T) Buffer - ); - -PHLIBAPI -VOID -NTAPI -T___(PhResizeCircularBuffer, T)( - _Inout_ T___(PPH_CIRCULAR_BUFFER, T) Buffer, - _In_ ULONG NewSize - ); - -PHLIBAPI -VOID -NTAPI -T___(PhClearCircularBuffer, T)( - _Inout_ T___(PPH_CIRCULAR_BUFFER, T) Buffer - ); - -PHLIBAPI -VOID -NTAPI -T___(PhCopyCircularBuffer, T)( - _Inout_ T___(PPH_CIRCULAR_BUFFER, T) Buffer, - _Out_writes_(Count) T *Destination, - _In_ ULONG Count - ); - -FORCEINLINE T T___(PhGetItemCircularBuffer, T)( - _In_ T___(PPH_CIRCULAR_BUFFER, T) Buffer, - _In_ LONG Index - ) -{ -#ifdef PH_CIRCULAR_BUFFER_POWER_OF_TWO_SIZE - return Buffer->Data[(Buffer->Index + Index) & Buffer->SizeMinusOne]; -#else - ULONG size; - - size = Buffer->Size; - // Modulo is dividend-based. - return Buffer->Data[(((Buffer->Index + Index) % size) + size) % size]; -#endif -} - -FORCEINLINE VOID T___(PhSetItemCircularBuffer, T)( - _Inout_ T___(PPH_CIRCULAR_BUFFER, T) Buffer, - _In_ LONG Index, - _In_ T Value - ) -{ -#ifdef PH_CIRCULAR_BUFFER_POWER_OF_TWO_SIZE - Buffer->Data[(Buffer->Index + Index) & Buffer->SizeMinusOne] = Value; -#else - ULONG size; - - size = Buffer->Size; - Buffer->Data[(((Buffer->Index + Index) % size) + size) % size] = Value; -#endif -} - -FORCEINLINE VOID T___(PhAddItemCircularBuffer, T)( - _Inout_ T___(PPH_CIRCULAR_BUFFER, T) Buffer, - _In_ T Value - ) -{ -#ifdef PH_CIRCULAR_BUFFER_POWER_OF_TWO_SIZE - Buffer->Data[Buffer->Index = ((Buffer->Index - 1) & Buffer->SizeMinusOne)] = Value; -#else - ULONG size; - - size = Buffer->Size; - Buffer->Data[Buffer->Index = (((Buffer->Index - 1) % size) + size) % size] = Value; -#endif - - if (Buffer->Count < Buffer->Size) - Buffer->Count++; -} - -FORCEINLINE T T___(PhAddItemCircularBuffer2, T)( - _Inout_ T___(PPH_CIRCULAR_BUFFER, T) Buffer, - _In_ T Value - ) -{ - LONG index; - T oldValue; - -#ifdef PH_CIRCULAR_BUFFER_POWER_OF_TWO_SIZE - index = ((Buffer->Index - 1) & Buffer->SizeMinusOne); -#else - ULONG size; - - size = Buffer->Size; - index = (((Buffer->Index - 1) % size) + size) % size; -#endif - - Buffer->Index = index; - oldValue = Buffer->Data[index]; - Buffer->Data[index] = Value; - - if (Buffer->Count < Buffer->Size) - Buffer->Count++; - - return oldValue; -} - -#ifdef __cplusplus -} -#endif - -#endif +#ifdef T + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct T___(_PH_CIRCULAR_BUFFER, T) +{ + ULONG Size; +#ifdef PH_CIRCULAR_BUFFER_POWER_OF_TWO_SIZE + ULONG SizeMinusOne; +#endif + ULONG Count; + LONG Index; + T *Data; +} T___(PH_CIRCULAR_BUFFER, T), *T___(PPH_CIRCULAR_BUFFER, T); + +PHLIBAPI +VOID +NTAPI +T___(PhInitializeCircularBuffer, T)( + _Out_ T___(PPH_CIRCULAR_BUFFER, T) Buffer, + _In_ ULONG Size + ); + +PHLIBAPI +VOID +NTAPI +T___(PhDeleteCircularBuffer, T)( + _Inout_ T___(PPH_CIRCULAR_BUFFER, T) Buffer + ); + +PHLIBAPI +VOID +NTAPI +T___(PhResizeCircularBuffer, T)( + _Inout_ T___(PPH_CIRCULAR_BUFFER, T) Buffer, + _In_ ULONG NewSize + ); + +PHLIBAPI +VOID +NTAPI +T___(PhClearCircularBuffer, T)( + _Inout_ T___(PPH_CIRCULAR_BUFFER, T) Buffer + ); + +PHLIBAPI +VOID +NTAPI +T___(PhCopyCircularBuffer, T)( + _Inout_ T___(PPH_CIRCULAR_BUFFER, T) Buffer, + _Out_writes_(Count) T *Destination, + _In_ ULONG Count + ); + +FORCEINLINE T T___(PhGetItemCircularBuffer, T)( + _In_ T___(PPH_CIRCULAR_BUFFER, T) Buffer, + _In_ LONG Index + ) +{ +#ifdef PH_CIRCULAR_BUFFER_POWER_OF_TWO_SIZE + return Buffer->Data[(Buffer->Index + Index) & Buffer->SizeMinusOne]; +#else + ULONG size; + + size = Buffer->Size; + // Modulo is dividend-based. + return Buffer->Data[(((Buffer->Index + Index) % size) + size) % size]; +#endif +} + +FORCEINLINE VOID T___(PhSetItemCircularBuffer, T)( + _Inout_ T___(PPH_CIRCULAR_BUFFER, T) Buffer, + _In_ LONG Index, + _In_ T Value + ) +{ +#ifdef PH_CIRCULAR_BUFFER_POWER_OF_TWO_SIZE + Buffer->Data[(Buffer->Index + Index) & Buffer->SizeMinusOne] = Value; +#else + ULONG size; + + size = Buffer->Size; + Buffer->Data[(((Buffer->Index + Index) % size) + size) % size] = Value; +#endif +} + +FORCEINLINE VOID T___(PhAddItemCircularBuffer, T)( + _Inout_ T___(PPH_CIRCULAR_BUFFER, T) Buffer, + _In_ T Value + ) +{ +#ifdef PH_CIRCULAR_BUFFER_POWER_OF_TWO_SIZE + Buffer->Data[Buffer->Index = ((Buffer->Index - 1) & Buffer->SizeMinusOne)] = Value; +#else + ULONG size; + + size = Buffer->Size; + Buffer->Data[Buffer->Index = (((Buffer->Index - 1) % size) + size) % size] = Value; +#endif + + if (Buffer->Count < Buffer->Size) + Buffer->Count++; +} + +FORCEINLINE T T___(PhAddItemCircularBuffer2, T)( + _Inout_ T___(PPH_CIRCULAR_BUFFER, T) Buffer, + _In_ T Value + ) +{ + LONG index; + T oldValue; + +#ifdef PH_CIRCULAR_BUFFER_POWER_OF_TWO_SIZE + index = ((Buffer->Index - 1) & Buffer->SizeMinusOne); +#else + ULONG size; + + size = Buffer->Size; + index = (((Buffer->Index - 1) % size) + size) % size; +#endif + + Buffer->Index = index; + oldValue = Buffer->Data[index]; + Buffer->Data[index] = Value; + + if (Buffer->Count < Buffer->Size) + Buffer->Count++; + + return oldValue; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/phlib/include/colorbox.h b/phlib/include/colorbox.h index 2a489b32199a..b6ec680d7dd3 100644 --- a/phlib/include/colorbox.h +++ b/phlib/include/colorbox.h @@ -1,30 +1,30 @@ -#ifndef _PH_COLORBOX_H -#define _PH_COLORBOX_H - -#ifdef __cplusplus -extern "C" { -#endif - -#define PH_COLORBOX_CLASSNAME L"PhColorBox" - -PHLIBAPI -BOOLEAN -NTAPI -PhColorBoxInitialization( - VOID - ); - -#define CBCM_SETCOLOR (WM_APP + 1501) -#define CBCM_GETCOLOR (WM_APP + 1502) - -#define ColorBox_SetColor(hWnd, Color) \ - SendMessage((hWnd), CBCM_SETCOLOR, (WPARAM)(Color), 0) - -#define ColorBox_GetColor(hWnd) \ - ((COLORREF)SendMessage((hWnd), CBCM_GETCOLOR, 0, 0)) - -#ifdef __cplusplus -} -#endif - -#endif +#ifndef _PH_COLORBOX_H +#define _PH_COLORBOX_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define PH_COLORBOX_CLASSNAME L"PhColorBox" + +PHLIBAPI +BOOLEAN +NTAPI +PhColorBoxInitialization( + VOID + ); + +#define CBCM_SETCOLOR (WM_APP + 1501) +#define CBCM_GETCOLOR (WM_APP + 1502) + +#define ColorBox_SetColor(hWnd, Color) \ + SendMessage((hWnd), CBCM_SETCOLOR, (WPARAM)(Color), 0) + +#define ColorBox_GetColor(hWnd) \ + ((COLORREF)SendMessage((hWnd), CBCM_GETCOLOR, 0, 0)) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/phlib/include/cpysave.h b/phlib/include/cpysave.h index 5ed893b581d1..5b91b605536e 100644 --- a/phlib/include/cpysave.h +++ b/phlib/include/cpysave.h @@ -1,78 +1,78 @@ -#ifndef _PH_CPYSAVE_H -#define _PH_CPYSAVE_H - -#ifdef __cplusplus -extern "C" { -#endif - -#define PH_EXPORT_MODE_TABS 0 -#define PH_EXPORT_MODE_SPACES 1 -#define PH_EXPORT_MODE_CSV 2 - -PHLIBAPI -VOID PhaCreateTextTable( - _Out_ PPH_STRING ***Table, - _In_ ULONG Rows, - _In_ ULONG Columns - ); - -PHLIBAPI -PPH_LIST PhaFormatTextTable( - _In_ PPH_STRING **Table, - _In_ ULONG Rows, - _In_ ULONG Columns, - _In_ ULONG Mode - ); - -PHLIBAPI -VOID PhMapDisplayIndexTreeNew( - _In_ HWND TreeNewHandle, - _Out_opt_ PULONG *DisplayToId, - _Out_opt_ PWSTR **DisplayToText, - _Out_ PULONG NumberOfColumns - ); - -PHLIBAPI -PPH_STRING PhGetTreeNewText( - _In_ HWND TreeNewHandle, - _Reserved_ ULONG Reserved - ); - -PHLIBAPI -PPH_LIST PhGetGenericTreeNewLines( - _In_ HWND TreeNewHandle, - _In_ ULONG Mode - ); - -PHLIBAPI -VOID PhaMapDisplayIndexListView( - _In_ HWND ListViewHandle, - _Out_writes_(Count) PULONG DisplayToId, - _Out_writes_opt_(Count) PPH_STRING *DisplayToText, - _In_ ULONG Count, - _Out_ PULONG NumberOfColumns - ); - -PHLIBAPI -PPH_STRING PhaGetListViewItemText( - _In_ HWND ListViewHandle, - _In_ INT Index, - _In_ INT SubItemIndex - ); - -PHLIBAPI -PPH_STRING PhGetListViewText( - _In_ HWND ListViewHandle - ); - -PHLIBAPI -PPH_LIST PhGetListViewLines( - _In_ HWND ListViewHandle, - _In_ ULONG Mode - ); - -#ifdef __cplusplus -} -#endif - -#endif +#ifndef _PH_CPYSAVE_H +#define _PH_CPYSAVE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define PH_EXPORT_MODE_TABS 0 +#define PH_EXPORT_MODE_SPACES 1 +#define PH_EXPORT_MODE_CSV 2 + +PHLIBAPI +VOID PhaCreateTextTable( + _Out_ PPH_STRING ***Table, + _In_ ULONG Rows, + _In_ ULONG Columns + ); + +PHLIBAPI +PPH_LIST PhaFormatTextTable( + _In_ PPH_STRING **Table, + _In_ ULONG Rows, + _In_ ULONG Columns, + _In_ ULONG Mode + ); + +PHLIBAPI +VOID PhMapDisplayIndexTreeNew( + _In_ HWND TreeNewHandle, + _Out_opt_ PULONG *DisplayToId, + _Out_opt_ PWSTR **DisplayToText, + _Out_ PULONG NumberOfColumns + ); + +PHLIBAPI +PPH_STRING PhGetTreeNewText( + _In_ HWND TreeNewHandle, + _Reserved_ ULONG Reserved + ); + +PHLIBAPI +PPH_LIST PhGetGenericTreeNewLines( + _In_ HWND TreeNewHandle, + _In_ ULONG Mode + ); + +PHLIBAPI +VOID PhaMapDisplayIndexListView( + _In_ HWND ListViewHandle, + _Out_writes_(Count) PULONG DisplayToId, + _Out_writes_opt_(Count) PPH_STRING *DisplayToText, + _In_ ULONG Count, + _Out_ PULONG NumberOfColumns + ); + +PHLIBAPI +PPH_STRING PhaGetListViewItemText( + _In_ HWND ListViewHandle, + _In_ INT Index, + _In_ INT SubItemIndex + ); + +PHLIBAPI +PPH_STRING PhGetListViewText( + _In_ HWND ListViewHandle + ); + +PHLIBAPI +PPH_LIST PhGetListViewLines( + _In_ HWND ListViewHandle, + _In_ ULONG Mode + ); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/phlib/include/dltmgr.h b/phlib/include/dltmgr.h index 593f4763bddc..f292bd770312 100644 --- a/phlib/include/dltmgr.h +++ b/phlib/include/dltmgr.h @@ -1,35 +1,35 @@ -#ifndef _PH_DLTMGR_H -#define _PH_DLTMGR_H - -typedef struct _PH_SINGLE_DELTA -{ - FLOAT Value; - FLOAT Delta; -} PH_SINGLE_DELTA, *PPH_SINGLE_DELTA; - -typedef struct _PH_UINT32_DELTA -{ - ULONG Value; - ULONG Delta; -} PH_UINT32_DELTA, *PPH_UINT32_DELTA; - -typedef struct _PH_UINT64_DELTA -{ - ULONG64 Value; - ULONG64 Delta; -} PH_UINT64_DELTA, *PPH_UINT64_DELTA; - -typedef struct _PH_UINTPTR_DELTA -{ - ULONG_PTR Value; - ULONG_PTR Delta; -} PH_UINTPTR_DELTA, *PPH_UINTPTR_DELTA; - -#define PhInitializeDelta(DltMgr) \ - ((DltMgr)->Value = 0, (DltMgr)->Delta = 0) - -#define PhUpdateDelta(DltMgr, NewValue) \ - ((DltMgr)->Delta = (NewValue) - (DltMgr)->Value, \ - (DltMgr)->Value = (NewValue), (DltMgr)->Delta) - -#endif +#ifndef _PH_DLTMGR_H +#define _PH_DLTMGR_H + +typedef struct _PH_SINGLE_DELTA +{ + FLOAT Value; + FLOAT Delta; +} PH_SINGLE_DELTA, *PPH_SINGLE_DELTA; + +typedef struct _PH_UINT32_DELTA +{ + ULONG Value; + ULONG Delta; +} PH_UINT32_DELTA, *PPH_UINT32_DELTA; + +typedef struct _PH_UINT64_DELTA +{ + ULONG64 Value; + ULONG64 Delta; +} PH_UINT64_DELTA, *PPH_UINT64_DELTA; + +typedef struct _PH_UINTPTR_DELTA +{ + ULONG_PTR Value; + ULONG_PTR Delta; +} PH_UINTPTR_DELTA, *PPH_UINTPTR_DELTA; + +#define PhInitializeDelta(DltMgr) \ + ((DltMgr)->Value = 0, (DltMgr)->Delta = 0) + +#define PhUpdateDelta(DltMgr, NewValue) \ + ((DltMgr)->Delta = (NewValue) - (DltMgr)->Value, \ + (DltMgr)->Value = (NewValue), (DltMgr)->Delta) + +#endif diff --git a/phlib/include/dspick.h b/phlib/include/dspick.h index c99a80bed4c2..e0a945caf3a5 100644 --- a/phlib/include/dspick.h +++ b/phlib/include/dspick.h @@ -1,48 +1,48 @@ -#ifndef _PH_DSPICK_H -#define _PH_DSPICK_H - -#ifdef __cplusplus -extern "C" { -#endif - -#define PH_DSPICK_MULTISELECT 0x1 - -typedef struct _PH_DSPICK_OBJECT -{ - PPH_STRING Name; - PSID Sid; -} PH_DSPICK_OBJECT, *PPH_DSPICK_OBJECT; - -typedef struct _PH_DSPICK_OBJECTS -{ - ULONG NumberOfObjects; - PH_DSPICK_OBJECT Objects[1]; -} PH_DSPICK_OBJECTS, *PPH_DSPICK_OBJECTS; - -PHLIBAPI -VOID PhFreeDsObjectPickerDialog( - _In_ PVOID PickerDialog - ); - -PHLIBAPI -PVOID PhCreateDsObjectPickerDialog( - _In_ ULONG Flags - ); - -PHLIBAPI -BOOLEAN PhShowDsObjectPickerDialog( - _In_ HWND hWnd, - _In_ PVOID PickerDialog, - _Out_ PPH_DSPICK_OBJECTS *Objects - ); - -PHLIBAPI -VOID PhFreeDsObjectPickerObjects( - _In_ PPH_DSPICK_OBJECTS Objects - ); - -#ifdef __cplusplus -} -#endif - -#endif +#ifndef _PH_DSPICK_H +#define _PH_DSPICK_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define PH_DSPICK_MULTISELECT 0x1 + +typedef struct _PH_DSPICK_OBJECT +{ + PPH_STRING Name; + PSID Sid; +} PH_DSPICK_OBJECT, *PPH_DSPICK_OBJECT; + +typedef struct _PH_DSPICK_OBJECTS +{ + ULONG NumberOfObjects; + PH_DSPICK_OBJECT Objects[1]; +} PH_DSPICK_OBJECTS, *PPH_DSPICK_OBJECTS; + +PHLIBAPI +VOID PhFreeDsObjectPickerDialog( + _In_ PVOID PickerDialog + ); + +PHLIBAPI +PVOID PhCreateDsObjectPickerDialog( + _In_ ULONG Flags + ); + +PHLIBAPI +BOOLEAN PhShowDsObjectPickerDialog( + _In_ HWND hWnd, + _In_ PVOID PickerDialog, + _Out_ PPH_DSPICK_OBJECTS *Objects + ); + +PHLIBAPI +VOID PhFreeDsObjectPickerObjects( + _In_ PPH_DSPICK_OBJECTS Objects + ); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/phlib/include/emenu.h b/phlib/include/emenu.h index 42955abce781..95c39f355d64 100644 --- a/phlib/include/emenu.h +++ b/phlib/include/emenu.h @@ -1,219 +1,219 @@ -#ifndef _PH_EMENU_H -#define _PH_EMENU_H - -#ifdef __cplusplus -extern "C" { -#endif - -#define PH_EMENU_DISABLED 0x1 -#define PH_EMENU_CHECKED 0x2 -#define PH_EMENU_HIGHLIGHT 0x4 -#define PH_EMENU_MENUBARBREAK 0x8 -#define PH_EMENU_MENUBREAK 0x10 -#define PH_EMENU_DEFAULT 0x20 -#define PH_EMENU_MOUSESELECT 0x40 -#define PH_EMENU_RADIOCHECK 0x80 - -#define PH_EMENU_SEPARATECHECKSPACE 0x100000 -#define PH_EMENU_SEPARATOR 0x200000 - -#define PH_EMENU_TEXT_OWNED 0x80000000 -#define PH_EMENU_BITMAP_OWNED 0x40000000 - -struct _PH_EMENU_ITEM; - -typedef VOID (NTAPI *PPH_EMENU_ITEM_DELETE_FUNCTION)( - _In_ struct _PH_EMENU_ITEM *Item - ); - -typedef struct _PH_EMENU_ITEM -{ - ULONG Flags; - ULONG Id; - PWSTR Text; - HBITMAP Bitmap; - - PVOID Parameter; - PVOID Context; - PPH_EMENU_ITEM_DELETE_FUNCTION DeleteFunction; - PVOID Reserved; - - struct _PH_EMENU_ITEM *Parent; - PPH_LIST Items; -} PH_EMENU_ITEM, *PPH_EMENU_ITEM; - -typedef struct _PH_EMENU_ITEM PH_EMENU, *PPH_EMENU; - -PHLIBAPI -PPH_EMENU_ITEM PhCreateEMenuItem( - _In_ ULONG Flags, - _In_ ULONG Id, - _In_ PWSTR Text, - _In_opt_ HBITMAP Bitmap, - _In_opt_ PVOID Context - ); - -PHLIBAPI -VOID PhDestroyEMenuItem( - _In_ PPH_EMENU_ITEM Item - ); - -#define PH_EMENU_FIND_DESCEND 0x1 -#define PH_EMENU_FIND_STARTSWITH 0x2 -#define PH_EMENU_FIND_LITERAL 0x4 - -PHLIBAPI -PPH_EMENU_ITEM PhFindEMenuItem( - _In_ PPH_EMENU_ITEM Item, - _In_ ULONG Flags, - _In_opt_ PWSTR Text, - _In_opt_ ULONG Id - ); - -PHLIBAPI -PPH_EMENU_ITEM PhFindEMenuItemEx( - _In_ PPH_EMENU_ITEM Item, - _In_ ULONG Flags, - _In_opt_ PWSTR Text, - _In_opt_ ULONG Id, - _Out_opt_ PPH_EMENU_ITEM *FoundParent, - _Out_opt_ PULONG FoundIndex - ); - -PHLIBAPI -ULONG PhIndexOfEMenuItem( - _In_ PPH_EMENU_ITEM Parent, - _In_ PPH_EMENU_ITEM Item - ); - -PHLIBAPI -VOID PhInsertEMenuItem( - _Inout_ PPH_EMENU_ITEM Parent, - _Inout_ PPH_EMENU_ITEM Item, - _In_ ULONG Index - ); - -PHLIBAPI -BOOLEAN PhRemoveEMenuItem( - _Inout_opt_ PPH_EMENU_ITEM Parent, - _In_opt_ PPH_EMENU_ITEM Item, - _In_opt_ ULONG Index - ); - -PHLIBAPI -VOID PhRemoveAllEMenuItems( - _Inout_ PPH_EMENU_ITEM Parent - ); - -PHLIBAPI -PPH_EMENU PhCreateEMenu( - VOID - ); - -PHLIBAPI -VOID PhDestroyEMenu( - _In_ PPH_EMENU Menu - ); - -#define PH_EMENU_CONVERT_ID 0x1 - -typedef struct _PH_EMENU_DATA -{ - PPH_LIST IdToItem; -} PH_EMENU_DATA, *PPH_EMENU_DATA; - -PHLIBAPI -VOID PhInitializeEMenuData( - _Out_ PPH_EMENU_DATA Data - ); - -PHLIBAPI -VOID PhDeleteEMenuData( - _Inout_ PPH_EMENU_DATA Data - ); - -PHLIBAPI -HMENU PhEMenuToHMenu( - _In_ PPH_EMENU_ITEM Menu, - _In_ ULONG Flags, - _Inout_opt_ PPH_EMENU_DATA Data - ); - -PHLIBAPI -VOID PhEMenuToHMenu2( - _In_ HMENU MenuHandle, - _In_ PPH_EMENU_ITEM Menu, - _In_ ULONG Flags, - _Inout_opt_ PPH_EMENU_DATA Data - ); - -PHLIBAPI -VOID PhHMenuToEMenuItem( - _Inout_ PPH_EMENU_ITEM MenuItem, - _In_ HMENU MenuHandle - ); - -PHLIBAPI -VOID PhLoadResourceEMenuItem( - _Inout_ PPH_EMENU_ITEM MenuItem, - _In_ HINSTANCE InstanceHandle, - _In_ PWSTR Resource, - _In_ ULONG SubMenuIndex - ); - -#define PH_EMENU_SHOW_SEND_COMMAND 0x1 -#define PH_EMENU_SHOW_LEFTRIGHT 0x2 - -PHLIBAPI -PPH_EMENU_ITEM PhShowEMenu( - _In_ PPH_EMENU Menu, - _In_ HWND WindowHandle, - _In_ ULONG Flags, - _In_ ULONG Align, - _In_ ULONG X, - _In_ ULONG Y - ); - -// Convenience functions - -PHLIBAPI -BOOLEAN PhSetFlagsEMenuItem( - _Inout_ PPH_EMENU_ITEM Item, - _In_ ULONG Id, - _In_ ULONG Mask, - _In_ ULONG Value - ); - -FORCEINLINE BOOLEAN PhEnableEMenuItem( - _Inout_ PPH_EMENU_ITEM Item, - _In_ ULONG Id, - _In_ BOOLEAN Enable - ) -{ - return PhSetFlagsEMenuItem(Item, Id, PH_EMENU_DISABLED, Enable ? 0 : PH_EMENU_DISABLED); -} - -PHLIBAPI -VOID PhSetFlagsAllEMenuItems( - _In_ PPH_EMENU_ITEM Item, - _In_ ULONG Mask, - _In_ ULONG Value - ); - -#define PH_EMENU_MODIFY_TEXT 0x1 -#define PH_EMENU_MODIFY_BITMAP 0x2 - -PHLIBAPI -VOID PhModifyEMenuItem( - _Inout_ PPH_EMENU_ITEM Item, - _In_ ULONG ModifyFlags, - _In_ ULONG OwnedFlags, - _In_opt_ PWSTR Text, - _In_opt_ HBITMAP Bitmap - ); - -#ifdef __cplusplus -} -#endif - -#endif +#ifndef _PH_EMENU_H +#define _PH_EMENU_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define PH_EMENU_DISABLED 0x1 +#define PH_EMENU_CHECKED 0x2 +#define PH_EMENU_HIGHLIGHT 0x4 +#define PH_EMENU_MENUBARBREAK 0x8 +#define PH_EMENU_MENUBREAK 0x10 +#define PH_EMENU_DEFAULT 0x20 +#define PH_EMENU_MOUSESELECT 0x40 +#define PH_EMENU_RADIOCHECK 0x80 + +#define PH_EMENU_SEPARATECHECKSPACE 0x100000 +#define PH_EMENU_SEPARATOR 0x200000 + +#define PH_EMENU_TEXT_OWNED 0x80000000 +#define PH_EMENU_BITMAP_OWNED 0x40000000 + +struct _PH_EMENU_ITEM; + +typedef VOID (NTAPI *PPH_EMENU_ITEM_DELETE_FUNCTION)( + _In_ struct _PH_EMENU_ITEM *Item + ); + +typedef struct _PH_EMENU_ITEM +{ + ULONG Flags; + ULONG Id; + PWSTR Text; + HBITMAP Bitmap; + + PVOID Parameter; + PVOID Context; + PPH_EMENU_ITEM_DELETE_FUNCTION DeleteFunction; + PVOID Reserved; + + struct _PH_EMENU_ITEM *Parent; + PPH_LIST Items; +} PH_EMENU_ITEM, *PPH_EMENU_ITEM; + +typedef struct _PH_EMENU_ITEM PH_EMENU, *PPH_EMENU; + +PHLIBAPI +PPH_EMENU_ITEM PhCreateEMenuItem( + _In_ ULONG Flags, + _In_ ULONG Id, + _In_ PWSTR Text, + _In_opt_ HBITMAP Bitmap, + _In_opt_ PVOID Context + ); + +PHLIBAPI +VOID PhDestroyEMenuItem( + _In_ PPH_EMENU_ITEM Item + ); + +#define PH_EMENU_FIND_DESCEND 0x1 +#define PH_EMENU_FIND_STARTSWITH 0x2 +#define PH_EMENU_FIND_LITERAL 0x4 + +PHLIBAPI +PPH_EMENU_ITEM PhFindEMenuItem( + _In_ PPH_EMENU_ITEM Item, + _In_ ULONG Flags, + _In_opt_ PWSTR Text, + _In_opt_ ULONG Id + ); + +PHLIBAPI +PPH_EMENU_ITEM PhFindEMenuItemEx( + _In_ PPH_EMENU_ITEM Item, + _In_ ULONG Flags, + _In_opt_ PWSTR Text, + _In_opt_ ULONG Id, + _Out_opt_ PPH_EMENU_ITEM *FoundParent, + _Out_opt_ PULONG FoundIndex + ); + +PHLIBAPI +ULONG PhIndexOfEMenuItem( + _In_ PPH_EMENU_ITEM Parent, + _In_ PPH_EMENU_ITEM Item + ); + +PHLIBAPI +VOID PhInsertEMenuItem( + _Inout_ PPH_EMENU_ITEM Parent, + _Inout_ PPH_EMENU_ITEM Item, + _In_ ULONG Index + ); + +PHLIBAPI +BOOLEAN PhRemoveEMenuItem( + _Inout_opt_ PPH_EMENU_ITEM Parent, + _In_opt_ PPH_EMENU_ITEM Item, + _In_opt_ ULONG Index + ); + +PHLIBAPI +VOID PhRemoveAllEMenuItems( + _Inout_ PPH_EMENU_ITEM Parent + ); + +PHLIBAPI +PPH_EMENU PhCreateEMenu( + VOID + ); + +PHLIBAPI +VOID PhDestroyEMenu( + _In_ PPH_EMENU Menu + ); + +#define PH_EMENU_CONVERT_ID 0x1 + +typedef struct _PH_EMENU_DATA +{ + PPH_LIST IdToItem; +} PH_EMENU_DATA, *PPH_EMENU_DATA; + +PHLIBAPI +VOID PhInitializeEMenuData( + _Out_ PPH_EMENU_DATA Data + ); + +PHLIBAPI +VOID PhDeleteEMenuData( + _Inout_ PPH_EMENU_DATA Data + ); + +PHLIBAPI +HMENU PhEMenuToHMenu( + _In_ PPH_EMENU_ITEM Menu, + _In_ ULONG Flags, + _Inout_opt_ PPH_EMENU_DATA Data + ); + +PHLIBAPI +VOID PhEMenuToHMenu2( + _In_ HMENU MenuHandle, + _In_ PPH_EMENU_ITEM Menu, + _In_ ULONG Flags, + _Inout_opt_ PPH_EMENU_DATA Data + ); + +PHLIBAPI +VOID PhHMenuToEMenuItem( + _Inout_ PPH_EMENU_ITEM MenuItem, + _In_ HMENU MenuHandle + ); + +PHLIBAPI +VOID PhLoadResourceEMenuItem( + _Inout_ PPH_EMENU_ITEM MenuItem, + _In_ HINSTANCE InstanceHandle, + _In_ PWSTR Resource, + _In_ ULONG SubMenuIndex + ); + +#define PH_EMENU_SHOW_SEND_COMMAND 0x1 +#define PH_EMENU_SHOW_LEFTRIGHT 0x2 + +PHLIBAPI +PPH_EMENU_ITEM PhShowEMenu( + _In_ PPH_EMENU Menu, + _In_ HWND WindowHandle, + _In_ ULONG Flags, + _In_ ULONG Align, + _In_ ULONG X, + _In_ ULONG Y + ); + +// Convenience functions + +PHLIBAPI +BOOLEAN PhSetFlagsEMenuItem( + _Inout_ PPH_EMENU_ITEM Item, + _In_ ULONG Id, + _In_ ULONG Mask, + _In_ ULONG Value + ); + +FORCEINLINE BOOLEAN PhEnableEMenuItem( + _Inout_ PPH_EMENU_ITEM Item, + _In_ ULONG Id, + _In_ BOOLEAN Enable + ) +{ + return PhSetFlagsEMenuItem(Item, Id, PH_EMENU_DISABLED, Enable ? 0 : PH_EMENU_DISABLED); +} + +PHLIBAPI +VOID PhSetFlagsAllEMenuItems( + _In_ PPH_EMENU_ITEM Item, + _In_ ULONG Mask, + _In_ ULONG Value + ); + +#define PH_EMENU_MODIFY_TEXT 0x1 +#define PH_EMENU_MODIFY_BITMAP 0x2 + +PHLIBAPI +VOID PhModifyEMenuItem( + _Inout_ PPH_EMENU_ITEM Item, + _In_ ULONG ModifyFlags, + _In_ ULONG OwnedFlags, + _In_opt_ PWSTR Text, + _In_opt_ HBITMAP Bitmap + ); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/phlib/include/fastlock.h b/phlib/include/fastlock.h index f817a2be1c39..d059e6160390 100644 --- a/phlib/include/fastlock.h +++ b/phlib/include/fastlock.h @@ -1,93 +1,93 @@ -#ifndef _PH_FASTLOCK_H -#define _PH_FASTLOCK_H - -// FastLock is a port of FastResourceLock from PH 1.x. - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct _PH_FAST_LOCK -{ - ULONG Value; - HANDLE ExclusiveWakeEvent; - HANDLE SharedWakeEvent; -} PH_FAST_LOCK, *PPH_FAST_LOCK; - -#define PH_FAST_LOCK_INIT { 0, NULL, NULL } - -PHLIBAPI -VOID -NTAPI -PhInitializeFastLock( - _Out_ PPH_FAST_LOCK FastLock - ); - -PHLIBAPI -VOID -NTAPI -PhDeleteFastLock( - _Inout_ PPH_FAST_LOCK FastLock - ); - -#define PhAcquireFastLockExclusive PhfAcquireFastLockExclusive -_May_raise_ -_Acquires_exclusive_lock_(*FastLock) -PHLIBAPI -VOID -FASTCALL -PhfAcquireFastLockExclusive( - _Inout_ PPH_FAST_LOCK FastLock - ); - -#define PhAcquireFastLockShared PhfAcquireFastLockShared -_May_raise_ -_Acquires_shared_lock_(*FastLock) -PHLIBAPI -VOID -FASTCALL -PhfAcquireFastLockShared( - _Inout_ PPH_FAST_LOCK FastLock - ); - -#define PhReleaseFastLockExclusive PhfReleaseFastLockExclusive -_Releases_exclusive_lock_(*FastLock) -PHLIBAPI -VOID -FASTCALL -PhfReleaseFastLockExclusive( - _Inout_ PPH_FAST_LOCK FastLock - ); - -#define PhReleaseFastLockShared PhfReleaseFastLockShared -_Releases_shared_lock_(*FastLock) -PHLIBAPI -VOID -FASTCALL -PhfReleaseFastLockShared( - _Inout_ PPH_FAST_LOCK FastLock - ); - -#define PhTryAcquireFastLockExclusive PhfTryAcquireFastLockExclusive -_When_(return != 0, _Acquires_exclusive_lock_(*FastLock)) -PHLIBAPI -BOOLEAN -FASTCALL -PhfTryAcquireFastLockExclusive( - _Inout_ PPH_FAST_LOCK FastLock - ); - -#define PhTryAcquireFastLockShared PhfTryAcquireFastLockShared -_When_(return != 0, _Acquires_shared_lock_(*FastLock)) -PHLIBAPI -BOOLEAN -FASTCALL -PhfTryAcquireFastLockShared( - _Inout_ PPH_FAST_LOCK FastLock - ); - -#ifdef __cplusplus -} -#endif - -#endif +#ifndef _PH_FASTLOCK_H +#define _PH_FASTLOCK_H + +// FastLock is a port of FastResourceLock from PH 1.x. + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct _PH_FAST_LOCK +{ + ULONG Value; + HANDLE ExclusiveWakeEvent; + HANDLE SharedWakeEvent; +} PH_FAST_LOCK, *PPH_FAST_LOCK; + +#define PH_FAST_LOCK_INIT { 0, NULL, NULL } + +PHLIBAPI +VOID +NTAPI +PhInitializeFastLock( + _Out_ PPH_FAST_LOCK FastLock + ); + +PHLIBAPI +VOID +NTAPI +PhDeleteFastLock( + _Inout_ PPH_FAST_LOCK FastLock + ); + +#define PhAcquireFastLockExclusive PhfAcquireFastLockExclusive +_May_raise_ +_Acquires_exclusive_lock_(*FastLock) +PHLIBAPI +VOID +FASTCALL +PhfAcquireFastLockExclusive( + _Inout_ PPH_FAST_LOCK FastLock + ); + +#define PhAcquireFastLockShared PhfAcquireFastLockShared +_May_raise_ +_Acquires_shared_lock_(*FastLock) +PHLIBAPI +VOID +FASTCALL +PhfAcquireFastLockShared( + _Inout_ PPH_FAST_LOCK FastLock + ); + +#define PhReleaseFastLockExclusive PhfReleaseFastLockExclusive +_Releases_exclusive_lock_(*FastLock) +PHLIBAPI +VOID +FASTCALL +PhfReleaseFastLockExclusive( + _Inout_ PPH_FAST_LOCK FastLock + ); + +#define PhReleaseFastLockShared PhfReleaseFastLockShared +_Releases_shared_lock_(*FastLock) +PHLIBAPI +VOID +FASTCALL +PhfReleaseFastLockShared( + _Inout_ PPH_FAST_LOCK FastLock + ); + +#define PhTryAcquireFastLockExclusive PhfTryAcquireFastLockExclusive +_When_(return != 0, _Acquires_exclusive_lock_(*FastLock)) +PHLIBAPI +BOOLEAN +FASTCALL +PhfTryAcquireFastLockExclusive( + _Inout_ PPH_FAST_LOCK FastLock + ); + +#define PhTryAcquireFastLockShared PhfTryAcquireFastLockShared +_When_(return != 0, _Acquires_shared_lock_(*FastLock)) +PHLIBAPI +BOOLEAN +FASTCALL +PhfTryAcquireFastLockShared( + _Inout_ PPH_FAST_LOCK FastLock + ); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/phlib/include/filepool.h b/phlib/include/filepool.h index 2d2263b5d674..26fa765bc503 100644 --- a/phlib/include/filepool.h +++ b/phlib/include/filepool.h @@ -1,196 +1,196 @@ -#ifndef _PH_FILEPOOL_H -#define _PH_FILEPOOL_H - -#ifdef __cplusplus -extern "C" { -#endif - -// On-disk structures - -// Each file has at least one segment. Each segment has a number of blocks, which are allocated from -// a bitmap. The segment header is always in the first block of each segment, except for the first -// segment. In the first segment, the file header is in the first few blocks, followed by the -// segment header. -// -// The segments are placed in a particular free list depending on how many blocks they have free; -// this allows allocators to simply skip the segments which don't have enough segments free, and -// allocate new segments if necessary. The free list does not however guarantee that a particular -// segment has a particular number of contiguous blocks free; low performance can still occur when -// there is fragmentation. - -/** The number of 32-bit integers used for each allocation bitmap. */ -#define PH_FP_BITMAP_SIZE 64 -/** The power-of-two index of the bitmap size. */ -#define PH_FP_BITMAP_SIZE_SHIFT 6 -/** The number of blocks that are available in each segment. */ -#define PH_FP_BLOCK_COUNT (PH_FP_BITMAP_SIZE * 32) -/** The power-of-two index of the block count. */ -#define PH_FP_BLOCK_COUNT_SHIFT (PH_FP_BITMAP_SIZE_SHIFT + 5) -/** The number of free lists for segments. */ -#define PH_FP_FREE_LIST_COUNT 8 - -// Block flags -/** The block is the beginning of a large allocation (one that spans several segments). */ -#define PH_FP_BLOCK_LARGE_ALLOCATION 0x1 - -typedef struct _PH_FP_BLOCK_HEADER -{ - ULONG Flags; // PH_FP_BLOCK_* - /** The number of blocks in the entire logical block, or the number - * of segments in a large allocation. */ - ULONG Span; - ULONGLONG Body; -} PH_FP_BLOCK_HEADER, *PPH_FP_BLOCK_HEADER; - -typedef struct _PH_FP_SEGMENT_HEADER -{ - ULONG Bitmap[PH_FP_BITMAP_SIZE]; - ULONG FreeBlocks; - ULONG FreeFlink; - ULONG FreeBlink; - ULONG Reserved[13]; -} PH_FP_SEGMENT_HEADER, *PPH_FP_SEGMENT_HEADER; - -#define PH_FP_MAGIC ('loPF') - -typedef struct _PH_FP_FILE_HEADER -{ - ULONG Magic; - ULONG SegmentShift; - ULONG SegmentCount; - ULONGLONG UserContext; - ULONG FreeLists[PH_FP_FREE_LIST_COUNT]; -} PH_FP_FILE_HEADER, *PPH_FP_FILE_HEADER; - -// Runtime - -typedef struct _PH_FILE_POOL_PARAMETERS -{ - // File options - - /** - * The base-2 logarithm of the size of each segment. This value must be between 16 and 28, - * inclusive. - */ - ULONG SegmentShift; - - // Runtime options - - /** The maximum number of inactive segments to keep mapped. */ - ULONG MaximumInactiveViews; -} PH_FILE_POOL_PARAMETERS, *PPH_FILE_POOL_PARAMETERS; - -typedef struct _PH_FILE_POOL -{ - HANDLE FileHandle; - HANDLE SectionHandle; - BOOLEAN ReadOnly; - - PH_FREE_LIST ViewFreeList; - PLIST_ENTRY *ByIndexBuckets; - ULONG ByIndexSize; - PH_AVL_TREE ByBaseSet; - - ULONG MaximumInactiveViews; - ULONG NumberOfInactiveViews; - LIST_ENTRY InactiveViewsListHead; - - PPH_FP_BLOCK_HEADER FirstBlockOfFirstSegment; - PPH_FP_FILE_HEADER Header; - ULONG SegmentShift; // The power-of-two size of each segment - ULONG SegmentSize; // The size of each segment - ULONG BlockShift; // The power-of-two size of each block in each segment - ULONG BlockSize; // The size of each block in each segment - ULONG FileHeaderBlockSpan; // The number of blocks needed to store a file header - ULONG SegmentHeaderBlockSpan; // The number of blocks needed to store a segment header -} PH_FILE_POOL, *PPH_FILE_POOL; - -PHLIBAPI -NTSTATUS PhCreateFilePool( - _Out_ PPH_FILE_POOL *Pool, - _In_ HANDLE FileHandle, - _In_ BOOLEAN ReadOnly, - _In_opt_ PPH_FILE_POOL_PARAMETERS Parameters - ); - -PHLIBAPI -NTSTATUS PhCreateFilePool2( - _Out_ PPH_FILE_POOL *Pool, - _In_ PWSTR FileName, - _In_ BOOLEAN ReadOnly, - _In_ ULONG ShareAccess, - _In_ ULONG CreateDisposition, - _In_opt_ PPH_FILE_POOL_PARAMETERS Parameters - ); - -PHLIBAPI -VOID PhDestroyFilePool( - _In_ _Post_invalid_ PPH_FILE_POOL Pool - ); - -PHLIBAPI -PVOID PhAllocateFilePool( - _Inout_ PPH_FILE_POOL Pool, - _In_ ULONG Size, - _Out_opt_ PULONG Rva - ); - -PHLIBAPI -VOID PhFreeFilePool( - _Inout_ PPH_FILE_POOL Pool, - _In_ PVOID Block - ); - -PHLIBAPI -BOOLEAN PhFreeFilePoolByRva( - _Inout_ PPH_FILE_POOL Pool, - _In_ ULONG Rva - ); - -PHLIBAPI -VOID PhReferenceFilePool( - _Inout_ PPH_FILE_POOL Pool, - _In_ PVOID Address - ); - -PHLIBAPI -VOID PhDereferenceFilePool( - _Inout_ PPH_FILE_POOL Pool, - _In_ PVOID Address - ); - -PHLIBAPI -PVOID PhReferenceFilePoolByRva( - _Inout_ PPH_FILE_POOL Pool, - _In_ ULONG Rva - ); - -PHLIBAPI -BOOLEAN PhDereferenceFilePoolByRva( - _Inout_ PPH_FILE_POOL Pool, - _In_ ULONG Rva - ); - -PHLIBAPI -ULONG PhEncodeRvaFilePool( - _In_ PPH_FILE_POOL Pool, - _In_ PVOID Address - ); - -PHLIBAPI -VOID PhGetUserContextFilePool( - _In_ PPH_FILE_POOL Pool, - _Out_ PULONGLONG Context - ); - -PHLIBAPI -VOID PhSetUserContextFilePool( - _Inout_ PPH_FILE_POOL Pool, - _In_ PULONGLONG Context - ); - -#ifdef __cplusplus -} -#endif - -#endif +#ifndef _PH_FILEPOOL_H +#define _PH_FILEPOOL_H + +#ifdef __cplusplus +extern "C" { +#endif + +// On-disk structures + +// Each file has at least one segment. Each segment has a number of blocks, which are allocated from +// a bitmap. The segment header is always in the first block of each segment, except for the first +// segment. In the first segment, the file header is in the first few blocks, followed by the +// segment header. +// +// The segments are placed in a particular free list depending on how many blocks they have free; +// this allows allocators to simply skip the segments which don't have enough segments free, and +// allocate new segments if necessary. The free list does not however guarantee that a particular +// segment has a particular number of contiguous blocks free; low performance can still occur when +// there is fragmentation. + +/** The number of 32-bit integers used for each allocation bitmap. */ +#define PH_FP_BITMAP_SIZE 64 +/** The power-of-two index of the bitmap size. */ +#define PH_FP_BITMAP_SIZE_SHIFT 6 +/** The number of blocks that are available in each segment. */ +#define PH_FP_BLOCK_COUNT (PH_FP_BITMAP_SIZE * 32) +/** The power-of-two index of the block count. */ +#define PH_FP_BLOCK_COUNT_SHIFT (PH_FP_BITMAP_SIZE_SHIFT + 5) +/** The number of free lists for segments. */ +#define PH_FP_FREE_LIST_COUNT 8 + +// Block flags +/** The block is the beginning of a large allocation (one that spans several segments). */ +#define PH_FP_BLOCK_LARGE_ALLOCATION 0x1 + +typedef struct _PH_FP_BLOCK_HEADER +{ + ULONG Flags; // PH_FP_BLOCK_* + /** The number of blocks in the entire logical block, or the number + * of segments in a large allocation. */ + ULONG Span; + ULONGLONG Body; +} PH_FP_BLOCK_HEADER, *PPH_FP_BLOCK_HEADER; + +typedef struct _PH_FP_SEGMENT_HEADER +{ + ULONG Bitmap[PH_FP_BITMAP_SIZE]; + ULONG FreeBlocks; + ULONG FreeFlink; + ULONG FreeBlink; + ULONG Reserved[13]; +} PH_FP_SEGMENT_HEADER, *PPH_FP_SEGMENT_HEADER; + +#define PH_FP_MAGIC ('loPF') + +typedef struct _PH_FP_FILE_HEADER +{ + ULONG Magic; + ULONG SegmentShift; + ULONG SegmentCount; + ULONGLONG UserContext; + ULONG FreeLists[PH_FP_FREE_LIST_COUNT]; +} PH_FP_FILE_HEADER, *PPH_FP_FILE_HEADER; + +// Runtime + +typedef struct _PH_FILE_POOL_PARAMETERS +{ + // File options + + /** + * The base-2 logarithm of the size of each segment. This value must be between 16 and 28, + * inclusive. + */ + ULONG SegmentShift; + + // Runtime options + + /** The maximum number of inactive segments to keep mapped. */ + ULONG MaximumInactiveViews; +} PH_FILE_POOL_PARAMETERS, *PPH_FILE_POOL_PARAMETERS; + +typedef struct _PH_FILE_POOL +{ + HANDLE FileHandle; + HANDLE SectionHandle; + BOOLEAN ReadOnly; + + PH_FREE_LIST ViewFreeList; + PLIST_ENTRY *ByIndexBuckets; + ULONG ByIndexSize; + PH_AVL_TREE ByBaseSet; + + ULONG MaximumInactiveViews; + ULONG NumberOfInactiveViews; + LIST_ENTRY InactiveViewsListHead; + + PPH_FP_BLOCK_HEADER FirstBlockOfFirstSegment; + PPH_FP_FILE_HEADER Header; + ULONG SegmentShift; // The power-of-two size of each segment + ULONG SegmentSize; // The size of each segment + ULONG BlockShift; // The power-of-two size of each block in each segment + ULONG BlockSize; // The size of each block in each segment + ULONG FileHeaderBlockSpan; // The number of blocks needed to store a file header + ULONG SegmentHeaderBlockSpan; // The number of blocks needed to store a segment header +} PH_FILE_POOL, *PPH_FILE_POOL; + +PHLIBAPI +NTSTATUS PhCreateFilePool( + _Out_ PPH_FILE_POOL *Pool, + _In_ HANDLE FileHandle, + _In_ BOOLEAN ReadOnly, + _In_opt_ PPH_FILE_POOL_PARAMETERS Parameters + ); + +PHLIBAPI +NTSTATUS PhCreateFilePool2( + _Out_ PPH_FILE_POOL *Pool, + _In_ PWSTR FileName, + _In_ BOOLEAN ReadOnly, + _In_ ULONG ShareAccess, + _In_ ULONG CreateDisposition, + _In_opt_ PPH_FILE_POOL_PARAMETERS Parameters + ); + +PHLIBAPI +VOID PhDestroyFilePool( + _In_ _Post_invalid_ PPH_FILE_POOL Pool + ); + +PHLIBAPI +PVOID PhAllocateFilePool( + _Inout_ PPH_FILE_POOL Pool, + _In_ ULONG Size, + _Out_opt_ PULONG Rva + ); + +PHLIBAPI +VOID PhFreeFilePool( + _Inout_ PPH_FILE_POOL Pool, + _In_ PVOID Block + ); + +PHLIBAPI +BOOLEAN PhFreeFilePoolByRva( + _Inout_ PPH_FILE_POOL Pool, + _In_ ULONG Rva + ); + +PHLIBAPI +VOID PhReferenceFilePool( + _Inout_ PPH_FILE_POOL Pool, + _In_ PVOID Address + ); + +PHLIBAPI +VOID PhDereferenceFilePool( + _Inout_ PPH_FILE_POOL Pool, + _In_ PVOID Address + ); + +PHLIBAPI +PVOID PhReferenceFilePoolByRva( + _Inout_ PPH_FILE_POOL Pool, + _In_ ULONG Rva + ); + +PHLIBAPI +BOOLEAN PhDereferenceFilePoolByRva( + _Inout_ PPH_FILE_POOL Pool, + _In_ ULONG Rva + ); + +PHLIBAPI +ULONG PhEncodeRvaFilePool( + _In_ PPH_FILE_POOL Pool, + _In_ PVOID Address + ); + +PHLIBAPI +VOID PhGetUserContextFilePool( + _In_ PPH_FILE_POOL Pool, + _Out_ PULONGLONG Context + ); + +PHLIBAPI +VOID PhSetUserContextFilePool( + _Inout_ PPH_FILE_POOL Pool, + _In_ PULONGLONG Context + ); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/phlib/include/filepoolp.h b/phlib/include/filepoolp.h index 0a823ea60e41..f11cc0f902f0 100644 --- a/phlib/include/filepoolp.h +++ b/phlib/include/filepoolp.h @@ -1,204 +1,204 @@ -#ifndef _PH_FILEPOOLP_H -#define _PH_FILEPOOLP_H - -typedef struct _PH_FILE_POOL_VIEW -{ - LIST_ENTRY ByIndexListEntry; - PH_AVL_LINKS ByBaseLinks; - LIST_ENTRY InactiveViewsListEntry; - - ULONG RefCount; - ULONG SegmentIndex; - PVOID Base; -} PH_FILE_POOL_VIEW, *PPH_FILE_POOL_VIEW; - -NTSTATUS PhpValidateFilePoolParameters( - _Inout_ PPH_FILE_POOL_PARAMETERS Parameters - ); - -VOID PhpSetDefaultFilePoolParameters( - _Out_ PPH_FILE_POOL_PARAMETERS Parameters - ); - -// Range mapping - -NTSTATUS PhFppExtendRange( - _Inout_ PPH_FILE_POOL Pool, - _In_ ULONG NewSize - ); - -NTSTATUS PhFppMapRange( - _Inout_ PPH_FILE_POOL Pool, - _In_ ULONG Offset, - _In_ ULONG Size, - _Out_ PVOID *Base - ); - -NTSTATUS PhFppUnmapRange( - _Inout_ PPH_FILE_POOL Pool, - _In_ PVOID Base - ); - -// Segments - -VOID PhFppInitializeSegment( - _Inout_ PPH_FILE_POOL Pool, - _Out_ PPH_FP_BLOCK_HEADER BlockOfSegmentHeader, - _In_ ULONG AdditionalBlocksUsed - ); - -PPH_FP_BLOCK_HEADER PhFppAllocateSegment( - _Inout_ PPH_FILE_POOL Pool, - _Out_ PULONG NewSegmentIndex - ); - -PPH_FP_SEGMENT_HEADER PhFppGetHeaderSegment( - _Inout_ PPH_FILE_POOL Pool, - _In_ PPH_FP_BLOCK_HEADER FirstBlock - ); - -// Views - -VOID PhFppAddViewByIndex( - _Inout_ PPH_FILE_POOL Pool, - _Inout_ PPH_FILE_POOL_VIEW View - ); - -VOID PhFppRemoveViewByIndex( - _Inout_ PPH_FILE_POOL Pool, - _Inout_ PPH_FILE_POOL_VIEW View - ); - -PPH_FILE_POOL_VIEW PhFppFindViewByIndex( - _Inout_ PPH_FILE_POOL Pool, - _In_ ULONG SegmentIndex - ); - -LONG NTAPI PhpFilePoolViewByBaseCompareFunction( - _In_ PPH_AVL_LINKS Links1, - _In_ PPH_AVL_LINKS Links2 - ); - -VOID PhFppAddViewByBase( - _Inout_ PPH_FILE_POOL Pool, - _Inout_ PPH_FILE_POOL_VIEW View - ); - -VOID PhFppRemoveViewByBase( - _Inout_ PPH_FILE_POOL Pool, - _Inout_ PPH_FILE_POOL_VIEW View - ); - -PPH_FILE_POOL_VIEW PhFppFindViewByBase( - _Inout_ PPH_FILE_POOL Pool, - _In_ PVOID Base - ); - -PPH_FILE_POOL_VIEW PhFppCreateView( - _Inout_ PPH_FILE_POOL Pool, - _In_ ULONG SegmentIndex - ); - -VOID PhFppDestroyView( - _Inout_ PPH_FILE_POOL Pool, - _Inout_ PPH_FILE_POOL_VIEW View - ); - -VOID PhFppActivateView( - _Inout_ PPH_FILE_POOL Pool, - _Inout_ PPH_FILE_POOL_VIEW View - ); - -VOID PhFppDeactivateView( - _Inout_ PPH_FILE_POOL Pool, - _Inout_ PPH_FILE_POOL_VIEW View - ); - -VOID PhFppReferenceView( - _Inout_ PPH_FILE_POOL Pool, - _Inout_ PPH_FILE_POOL_VIEW View - ); - -VOID PhFppDereferenceView( - _Inout_ PPH_FILE_POOL Pool, - _Inout_ PPH_FILE_POOL_VIEW View - ); - -PPH_FP_BLOCK_HEADER PhFppReferenceSegment( - _Inout_ PPH_FILE_POOL Pool, - _In_ ULONG SegmentIndex - ); - -VOID PhFppDereferenceSegment( - _Inout_ PPH_FILE_POOL Pool, - _In_ ULONG SegmentIndex - ); - -VOID PhFppReferenceSegmentByBase( - _Inout_ PPH_FILE_POOL Pool, - _In_ PVOID Base - ); - -VOID PhFppDereferenceSegmentByBase( - _Inout_ PPH_FILE_POOL Pool, - _In_ PVOID Base - ); - -// Bitmap allocation - -PPH_FP_BLOCK_HEADER PhFppAllocateBlocks( - _Inout_ PPH_FILE_POOL Pool, - _In_ PPH_FP_BLOCK_HEADER FirstBlock, - _Inout_ PPH_FP_SEGMENT_HEADER SegmentHeader, - _In_ ULONG NumberOfBlocks - ); - -VOID PhFppFreeBlocks( - _Inout_ PPH_FILE_POOL Pool, - _In_ PPH_FP_BLOCK_HEADER FirstBlock, - _Inout_ PPH_FP_SEGMENT_HEADER SegmentHeader, - _In_ PPH_FP_BLOCK_HEADER BlockHeader - ); - -// Free list - -ULONG PhFppComputeFreeListIndex( - _In_ PPH_FILE_POOL Pool, - _In_ ULONG NumberOfBlocks - ); - -BOOLEAN PhFppInsertFreeList( - _Inout_ PPH_FILE_POOL Pool, - _In_ ULONG FreeListIndex, - _In_ ULONG SegmentIndex, - _In_ PPH_FP_SEGMENT_HEADER SegmentHeader - ); - -BOOLEAN PhFppRemoveFreeList( - _Inout_ PPH_FILE_POOL Pool, - _In_ ULONG FreeListIndex, - _In_ ULONG SegmentIndex, - _In_ PPH_FP_SEGMENT_HEADER SegmentHeader - ); - -// Misc. - -PPH_FP_BLOCK_HEADER PhFppGetHeaderBlock( - _In_ PPH_FILE_POOL Pool, - _In_ PVOID Block - ); - -ULONG PhFppEncodeRva( - _In_ PPH_FILE_POOL Pool, - _In_ ULONG SegmentIndex, - _In_ PPH_FP_BLOCK_HEADER FirstBlock, - _In_ PVOID Address - ); - -ULONG PhFppDecodeRva( - _In_ PPH_FILE_POOL Pool, - _In_ ULONG Rva, - _Out_ PULONG SegmentIndex - ); - -#endif +#ifndef _PH_FILEPOOLP_H +#define _PH_FILEPOOLP_H + +typedef struct _PH_FILE_POOL_VIEW +{ + LIST_ENTRY ByIndexListEntry; + PH_AVL_LINKS ByBaseLinks; + LIST_ENTRY InactiveViewsListEntry; + + ULONG RefCount; + ULONG SegmentIndex; + PVOID Base; +} PH_FILE_POOL_VIEW, *PPH_FILE_POOL_VIEW; + +NTSTATUS PhpValidateFilePoolParameters( + _Inout_ PPH_FILE_POOL_PARAMETERS Parameters + ); + +VOID PhpSetDefaultFilePoolParameters( + _Out_ PPH_FILE_POOL_PARAMETERS Parameters + ); + +// Range mapping + +NTSTATUS PhFppExtendRange( + _Inout_ PPH_FILE_POOL Pool, + _In_ ULONG NewSize + ); + +NTSTATUS PhFppMapRange( + _Inout_ PPH_FILE_POOL Pool, + _In_ ULONG Offset, + _In_ ULONG Size, + _Out_ PVOID *Base + ); + +NTSTATUS PhFppUnmapRange( + _Inout_ PPH_FILE_POOL Pool, + _In_ PVOID Base + ); + +// Segments + +VOID PhFppInitializeSegment( + _Inout_ PPH_FILE_POOL Pool, + _Out_ PPH_FP_BLOCK_HEADER BlockOfSegmentHeader, + _In_ ULONG AdditionalBlocksUsed + ); + +PPH_FP_BLOCK_HEADER PhFppAllocateSegment( + _Inout_ PPH_FILE_POOL Pool, + _Out_ PULONG NewSegmentIndex + ); + +PPH_FP_SEGMENT_HEADER PhFppGetHeaderSegment( + _Inout_ PPH_FILE_POOL Pool, + _In_ PPH_FP_BLOCK_HEADER FirstBlock + ); + +// Views + +VOID PhFppAddViewByIndex( + _Inout_ PPH_FILE_POOL Pool, + _Inout_ PPH_FILE_POOL_VIEW View + ); + +VOID PhFppRemoveViewByIndex( + _Inout_ PPH_FILE_POOL Pool, + _Inout_ PPH_FILE_POOL_VIEW View + ); + +PPH_FILE_POOL_VIEW PhFppFindViewByIndex( + _Inout_ PPH_FILE_POOL Pool, + _In_ ULONG SegmentIndex + ); + +LONG NTAPI PhpFilePoolViewByBaseCompareFunction( + _In_ PPH_AVL_LINKS Links1, + _In_ PPH_AVL_LINKS Links2 + ); + +VOID PhFppAddViewByBase( + _Inout_ PPH_FILE_POOL Pool, + _Inout_ PPH_FILE_POOL_VIEW View + ); + +VOID PhFppRemoveViewByBase( + _Inout_ PPH_FILE_POOL Pool, + _Inout_ PPH_FILE_POOL_VIEW View + ); + +PPH_FILE_POOL_VIEW PhFppFindViewByBase( + _Inout_ PPH_FILE_POOL Pool, + _In_ PVOID Base + ); + +PPH_FILE_POOL_VIEW PhFppCreateView( + _Inout_ PPH_FILE_POOL Pool, + _In_ ULONG SegmentIndex + ); + +VOID PhFppDestroyView( + _Inout_ PPH_FILE_POOL Pool, + _Inout_ PPH_FILE_POOL_VIEW View + ); + +VOID PhFppActivateView( + _Inout_ PPH_FILE_POOL Pool, + _Inout_ PPH_FILE_POOL_VIEW View + ); + +VOID PhFppDeactivateView( + _Inout_ PPH_FILE_POOL Pool, + _Inout_ PPH_FILE_POOL_VIEW View + ); + +VOID PhFppReferenceView( + _Inout_ PPH_FILE_POOL Pool, + _Inout_ PPH_FILE_POOL_VIEW View + ); + +VOID PhFppDereferenceView( + _Inout_ PPH_FILE_POOL Pool, + _Inout_ PPH_FILE_POOL_VIEW View + ); + +PPH_FP_BLOCK_HEADER PhFppReferenceSegment( + _Inout_ PPH_FILE_POOL Pool, + _In_ ULONG SegmentIndex + ); + +VOID PhFppDereferenceSegment( + _Inout_ PPH_FILE_POOL Pool, + _In_ ULONG SegmentIndex + ); + +VOID PhFppReferenceSegmentByBase( + _Inout_ PPH_FILE_POOL Pool, + _In_ PVOID Base + ); + +VOID PhFppDereferenceSegmentByBase( + _Inout_ PPH_FILE_POOL Pool, + _In_ PVOID Base + ); + +// Bitmap allocation + +PPH_FP_BLOCK_HEADER PhFppAllocateBlocks( + _Inout_ PPH_FILE_POOL Pool, + _In_ PPH_FP_BLOCK_HEADER FirstBlock, + _Inout_ PPH_FP_SEGMENT_HEADER SegmentHeader, + _In_ ULONG NumberOfBlocks + ); + +VOID PhFppFreeBlocks( + _Inout_ PPH_FILE_POOL Pool, + _In_ PPH_FP_BLOCK_HEADER FirstBlock, + _Inout_ PPH_FP_SEGMENT_HEADER SegmentHeader, + _In_ PPH_FP_BLOCK_HEADER BlockHeader + ); + +// Free list + +ULONG PhFppComputeFreeListIndex( + _In_ PPH_FILE_POOL Pool, + _In_ ULONG NumberOfBlocks + ); + +BOOLEAN PhFppInsertFreeList( + _Inout_ PPH_FILE_POOL Pool, + _In_ ULONG FreeListIndex, + _In_ ULONG SegmentIndex, + _In_ PPH_FP_SEGMENT_HEADER SegmentHeader + ); + +BOOLEAN PhFppRemoveFreeList( + _Inout_ PPH_FILE_POOL Pool, + _In_ ULONG FreeListIndex, + _In_ ULONG SegmentIndex, + _In_ PPH_FP_SEGMENT_HEADER SegmentHeader + ); + +// Misc. + +PPH_FP_BLOCK_HEADER PhFppGetHeaderBlock( + _In_ PPH_FILE_POOL Pool, + _In_ PVOID Block + ); + +ULONG PhFppEncodeRva( + _In_ PPH_FILE_POOL Pool, + _In_ ULONG SegmentIndex, + _In_ PPH_FP_BLOCK_HEADER FirstBlock, + _In_ PVOID Address + ); + +ULONG PhFppDecodeRva( + _In_ PPH_FILE_POOL Pool, + _In_ ULONG Rva, + _Out_ PULONG SegmentIndex + ); + +#endif diff --git a/phlib/include/graph.h b/phlib/include/graph.h index 87dc2209483e..bc15a12d6039 100644 --- a/phlib/include/graph.h +++ b/phlib/include/graph.h @@ -1,255 +1,255 @@ -#ifndef _PH_GRAPH_H -#define _PH_GRAPH_H - -#ifdef __cplusplus -extern "C" { -#endif - -// Graph drawing - -extern RECT PhNormalGraphTextMargin; -extern RECT PhNormalGraphTextPadding; - -#define PH_GRAPH_USE_GRID_X 0x1 -#define PH_GRAPH_USE_GRID_Y 0x2 -#define PH_GRAPH_LOGARITHMIC_GRID_Y 0x4 -#define PH_GRAPH_USE_LINE_2 0x10 -#define PH_GRAPH_OVERLAY_LINE_2 0x20 -#define PH_GRAPH_LABEL_MAX_Y 0x1000 - -typedef PPH_STRING (NTAPI *PPH_GRAPH_LABEL_Y_FUNCTION)( - _In_ struct _PH_GRAPH_DRAW_INFO *DrawInfo, - _In_ ULONG DataIndex, - _In_ FLOAT Value, - _In_ FLOAT Parameter - ); - -typedef struct _PH_GRAPH_DRAW_INFO -{ - // Basic - ULONG Width; - ULONG Height; - ULONG Flags; - ULONG Step; - COLORREF BackColor; - - // Data/lines - ULONG LineDataCount; - PFLOAT LineData1; - PFLOAT LineData2; - COLORREF LineColor1; - COLORREF LineColor2; - COLORREF LineBackColor1; - COLORREF LineBackColor2; - - // Grid - COLORREF GridColor; - ULONG GridWidth; - FLOAT GridHeight; - ULONG GridXOffset; - ULONG GridYThreshold; - FLOAT GridBase; // Base for logarithmic grid - - // y-axis label - PPH_GRAPH_LABEL_Y_FUNCTION LabelYFunction; - FLOAT LabelYFunctionParameter; - HFONT LabelYFont; - COLORREF LabelYColor; - ULONG LabelMaxYIndexLimit; - - // Text - PH_STRINGREF Text; - RECT TextRect; - RECT TextBoxRect; - HFONT TextFont; - COLORREF TextColor; - COLORREF TextBoxColor; -} PH_GRAPH_DRAW_INFO, *PPH_GRAPH_DRAW_INFO; - -// Graph control - -#define PH_GRAPH_CLASSNAME L"PhGraph" - -PHLIBAPI -BOOLEAN PhGraphControlInitialization( - VOID - ); - -PHLIBAPI -VOID PhDrawGraphDirect( - _In_ HDC hdc, - _In_ PVOID Bits, - _In_ PPH_GRAPH_DRAW_INFO DrawInfo - ); - -PHLIBAPI -VOID PhSetGraphText( - _In_ HDC hdc, - _Inout_ PPH_GRAPH_DRAW_INFO DrawInfo, - _In_ PPH_STRINGREF Text, - _In_ PRECT Margin, - _In_ PRECT Padding, - _In_ ULONG Align - ); - -// Configuration - -typedef struct _PH_GRAPH_OPTIONS -{ - COLORREF FadeOutBackColor; - ULONG FadeOutWidth; - HCURSOR DefaultCursor; -} PH_GRAPH_OPTIONS, *PPH_GRAPH_OPTIONS; - -// Styles - -#define GC_STYLE_FADEOUT 0x1 -#define GC_STYLE_DRAW_PANEL 0x2 - -// Messages - -#define GCM_GETDRAWINFO (WM_USER + 1301) -#define GCM_SETDRAWINFO (WM_USER + 1302) -#define GCM_DRAW (WM_USER + 1303) -#define GCM_MOVEGRID (WM_USER + 1304) -#define GCM_GETBUFFEREDCONTEXT (WM_USER + 1305) -#define GCM_SETTOOLTIP (WM_USER + 1306) -#define GCM_UPDATETOOLTIP (WM_USER + 1307) -#define GCM_GETOPTIONS (WM_USER + 1308) -#define GCM_SETOPTIONS (WM_USER + 1309) - -#define Graph_GetDrawInfo(hWnd, DrawInfo) \ - SendMessage((hWnd), GCM_GETDRAWINFO, 0, (LPARAM)(DrawInfo)) -#define Graph_SetDrawInfo(hWnd, DrawInfo) \ - SendMessage((hWnd), GCM_SETDRAWINFO, 0, (LPARAM)(DrawInfo)) -#define Graph_Draw(hWnd) \ - SendMessage((hWnd), GCM_DRAW, 0, 0) -#define Graph_MoveGrid(hWnd, Increment) \ - SendMessage((hWnd), GCM_MOVEGRID, (WPARAM)(Increment), 0) -#define Graph_GetBufferedContext(hWnd) \ - ((HDC)SendMessage((hWnd), GCM_GETBUFFEREDCONTEXT, 0, 0)) -#define Graph_SetTooltip(hWnd, Enable) \ - ((HDC)SendMessage((hWnd), GCM_SETTOOLTIP, (WPARAM)(Enable), 0)) -#define Graph_UpdateTooltip(hWnd) \ - ((HDC)SendMessage((hWnd), GCM_UPDATETOOLTIP, 0, 0)) -#define Graph_GetOptions(hWnd, Options) \ - SendMessage((hWnd), GCM_GETOPTIONS, 0, (LPARAM)(Options)) -#define Graph_SetOptions(hWnd, Options) \ - SendMessage((hWnd), GCM_SETOPTIONS, 0, (LPARAM)(Options)) - -// Notifications - -#define GCN_GETDRAWINFO (WM_USER + 1351) -#define GCN_GETTOOLTIPTEXT (WM_USER + 1352) -#define GCN_MOUSEEVENT (WM_USER + 1353) -#define GCN_DRAWPANEL (WM_USER + 1354) - -typedef struct _PH_GRAPH_GETDRAWINFO -{ - NMHDR Header; - PPH_GRAPH_DRAW_INFO DrawInfo; -} PH_GRAPH_GETDRAWINFO, *PPH_GRAPH_GETDRAWINFO; - -typedef struct _PH_GRAPH_GETTOOLTIPTEXT -{ - NMHDR Header; - ULONG Index; - ULONG TotalCount; - - PH_STRINGREF Text; // must be null-terminated -} PH_GRAPH_GETTOOLTIPTEXT, *PPH_GRAPH_GETTOOLTIPTEXT; - -typedef struct _PH_GRAPH_MOUSEEVENT -{ - NMHDR Header; - ULONG Index; - ULONG TotalCount; - - ULONG Message; - ULONG Keys; - POINT Point; -} PH_GRAPH_MOUSEEVENT, *PPH_GRAPH_MOUSEEVENT; - -typedef struct _PH_GRAPH_DRAWPANEL -{ - NMHDR Header; - HDC hdc; - RECT Rect; -} PH_GRAPH_DRAWPANEL, *PPH_GRAPH_DRAWPANEL; - -// Graph buffer management - -#define PH_GRAPH_DATA_COUNT(Width, Step) (((Width) + (Step) - 1) / (Step) + 1) // round up in division - -typedef struct _PH_GRAPH_BUFFERS -{ - PFLOAT Data1; // invalidate by setting Valid to FALSE - PFLOAT Data2; // invalidate by setting Valid to FALSE - ULONG AllocatedCount; - BOOLEAN Valid; // indicates the data is valid -} PH_GRAPH_BUFFERS, *PPH_GRAPH_BUFFERS; - -PHLIBAPI -VOID PhInitializeGraphBuffers( - _Out_ PPH_GRAPH_BUFFERS Buffers - ); - -PHLIBAPI -VOID PhDeleteGraphBuffers( - _Inout_ PPH_GRAPH_BUFFERS Buffers - ); - -PHLIBAPI -VOID PhGetDrawInfoGraphBuffers( - _Inout_ PPH_GRAPH_BUFFERS Buffers, - _Inout_ PPH_GRAPH_DRAW_INFO DrawInfo, - _In_ ULONG DataCount - ); - -// Graph control state - -// The basic buffer management structure was moved out of this section because -// the text management is not needed for most cases. - -typedef struct _PH_GRAPH_STATE -{ - // Union for compatibility - union - { - struct - { - PFLOAT Data1; // invalidate by setting Valid to FALSE - PFLOAT Data2; // invalidate by setting Valid to FALSE - ULONG AllocatedCount; - BOOLEAN Valid; // indicates the data is valid - }; - PH_GRAPH_BUFFERS Buffers; - }; - - PPH_STRING Text; - PPH_STRING TooltipText; // invalidate by setting TooltipIndex to -1 - ULONG TooltipIndex; // indicates the tooltip text is valid for this index -} PH_GRAPH_STATE, *PPH_GRAPH_STATE; - -PHLIBAPI -VOID PhInitializeGraphState( - _Out_ PPH_GRAPH_STATE State - ); - -PHLIBAPI -VOID PhDeleteGraphState( - _Inout_ PPH_GRAPH_STATE State - ); - -PHLIBAPI -VOID PhGraphStateGetDrawInfo( - _Inout_ PPH_GRAPH_STATE State, - _In_ PPH_GRAPH_GETDRAWINFO GetDrawInfo, - _In_ ULONG DataCount - ); - -#ifdef __cplusplus -} -#endif - -#endif +#ifndef _PH_GRAPH_H +#define _PH_GRAPH_H + +#ifdef __cplusplus +extern "C" { +#endif + +// Graph drawing + +extern RECT PhNormalGraphTextMargin; +extern RECT PhNormalGraphTextPadding; + +#define PH_GRAPH_USE_GRID_X 0x1 +#define PH_GRAPH_USE_GRID_Y 0x2 +#define PH_GRAPH_LOGARITHMIC_GRID_Y 0x4 +#define PH_GRAPH_USE_LINE_2 0x10 +#define PH_GRAPH_OVERLAY_LINE_2 0x20 +#define PH_GRAPH_LABEL_MAX_Y 0x1000 + +typedef PPH_STRING (NTAPI *PPH_GRAPH_LABEL_Y_FUNCTION)( + _In_ struct _PH_GRAPH_DRAW_INFO *DrawInfo, + _In_ ULONG DataIndex, + _In_ FLOAT Value, + _In_ FLOAT Parameter + ); + +typedef struct _PH_GRAPH_DRAW_INFO +{ + // Basic + ULONG Width; + ULONG Height; + ULONG Flags; + ULONG Step; + COLORREF BackColor; + + // Data/lines + ULONG LineDataCount; + PFLOAT LineData1; + PFLOAT LineData2; + COLORREF LineColor1; + COLORREF LineColor2; + COLORREF LineBackColor1; + COLORREF LineBackColor2; + + // Grid + COLORREF GridColor; + ULONG GridWidth; + FLOAT GridHeight; + ULONG GridXOffset; + ULONG GridYThreshold; + FLOAT GridBase; // Base for logarithmic grid + + // y-axis label + PPH_GRAPH_LABEL_Y_FUNCTION LabelYFunction; + FLOAT LabelYFunctionParameter; + HFONT LabelYFont; + COLORREF LabelYColor; + ULONG LabelMaxYIndexLimit; + + // Text + PH_STRINGREF Text; + RECT TextRect; + RECT TextBoxRect; + HFONT TextFont; + COLORREF TextColor; + COLORREF TextBoxColor; +} PH_GRAPH_DRAW_INFO, *PPH_GRAPH_DRAW_INFO; + +// Graph control + +#define PH_GRAPH_CLASSNAME L"PhGraph" + +PHLIBAPI +BOOLEAN PhGraphControlInitialization( + VOID + ); + +PHLIBAPI +VOID PhDrawGraphDirect( + _In_ HDC hdc, + _In_ PVOID Bits, + _In_ PPH_GRAPH_DRAW_INFO DrawInfo + ); + +PHLIBAPI +VOID PhSetGraphText( + _In_ HDC hdc, + _Inout_ PPH_GRAPH_DRAW_INFO DrawInfo, + _In_ PPH_STRINGREF Text, + _In_ PRECT Margin, + _In_ PRECT Padding, + _In_ ULONG Align + ); + +// Configuration + +typedef struct _PH_GRAPH_OPTIONS +{ + COLORREF FadeOutBackColor; + ULONG FadeOutWidth; + HCURSOR DefaultCursor; +} PH_GRAPH_OPTIONS, *PPH_GRAPH_OPTIONS; + +// Styles + +#define GC_STYLE_FADEOUT 0x1 +#define GC_STYLE_DRAW_PANEL 0x2 + +// Messages + +#define GCM_GETDRAWINFO (WM_USER + 1301) +#define GCM_SETDRAWINFO (WM_USER + 1302) +#define GCM_DRAW (WM_USER + 1303) +#define GCM_MOVEGRID (WM_USER + 1304) +#define GCM_GETBUFFEREDCONTEXT (WM_USER + 1305) +#define GCM_SETTOOLTIP (WM_USER + 1306) +#define GCM_UPDATETOOLTIP (WM_USER + 1307) +#define GCM_GETOPTIONS (WM_USER + 1308) +#define GCM_SETOPTIONS (WM_USER + 1309) + +#define Graph_GetDrawInfo(hWnd, DrawInfo) \ + SendMessage((hWnd), GCM_GETDRAWINFO, 0, (LPARAM)(DrawInfo)) +#define Graph_SetDrawInfo(hWnd, DrawInfo) \ + SendMessage((hWnd), GCM_SETDRAWINFO, 0, (LPARAM)(DrawInfo)) +#define Graph_Draw(hWnd) \ + SendMessage((hWnd), GCM_DRAW, 0, 0) +#define Graph_MoveGrid(hWnd, Increment) \ + SendMessage((hWnd), GCM_MOVEGRID, (WPARAM)(Increment), 0) +#define Graph_GetBufferedContext(hWnd) \ + ((HDC)SendMessage((hWnd), GCM_GETBUFFEREDCONTEXT, 0, 0)) +#define Graph_SetTooltip(hWnd, Enable) \ + ((HDC)SendMessage((hWnd), GCM_SETTOOLTIP, (WPARAM)(Enable), 0)) +#define Graph_UpdateTooltip(hWnd) \ + ((HDC)SendMessage((hWnd), GCM_UPDATETOOLTIP, 0, 0)) +#define Graph_GetOptions(hWnd, Options) \ + SendMessage((hWnd), GCM_GETOPTIONS, 0, (LPARAM)(Options)) +#define Graph_SetOptions(hWnd, Options) \ + SendMessage((hWnd), GCM_SETOPTIONS, 0, (LPARAM)(Options)) + +// Notifications + +#define GCN_GETDRAWINFO (WM_USER + 1351) +#define GCN_GETTOOLTIPTEXT (WM_USER + 1352) +#define GCN_MOUSEEVENT (WM_USER + 1353) +#define GCN_DRAWPANEL (WM_USER + 1354) + +typedef struct _PH_GRAPH_GETDRAWINFO +{ + NMHDR Header; + PPH_GRAPH_DRAW_INFO DrawInfo; +} PH_GRAPH_GETDRAWINFO, *PPH_GRAPH_GETDRAWINFO; + +typedef struct _PH_GRAPH_GETTOOLTIPTEXT +{ + NMHDR Header; + ULONG Index; + ULONG TotalCount; + + PH_STRINGREF Text; // must be null-terminated +} PH_GRAPH_GETTOOLTIPTEXT, *PPH_GRAPH_GETTOOLTIPTEXT; + +typedef struct _PH_GRAPH_MOUSEEVENT +{ + NMHDR Header; + ULONG Index; + ULONG TotalCount; + + ULONG Message; + ULONG Keys; + POINT Point; +} PH_GRAPH_MOUSEEVENT, *PPH_GRAPH_MOUSEEVENT; + +typedef struct _PH_GRAPH_DRAWPANEL +{ + NMHDR Header; + HDC hdc; + RECT Rect; +} PH_GRAPH_DRAWPANEL, *PPH_GRAPH_DRAWPANEL; + +// Graph buffer management + +#define PH_GRAPH_DATA_COUNT(Width, Step) (((Width) + (Step) - 1) / (Step) + 1) // round up in division + +typedef struct _PH_GRAPH_BUFFERS +{ + PFLOAT Data1; // invalidate by setting Valid to FALSE + PFLOAT Data2; // invalidate by setting Valid to FALSE + ULONG AllocatedCount; + BOOLEAN Valid; // indicates the data is valid +} PH_GRAPH_BUFFERS, *PPH_GRAPH_BUFFERS; + +PHLIBAPI +VOID PhInitializeGraphBuffers( + _Out_ PPH_GRAPH_BUFFERS Buffers + ); + +PHLIBAPI +VOID PhDeleteGraphBuffers( + _Inout_ PPH_GRAPH_BUFFERS Buffers + ); + +PHLIBAPI +VOID PhGetDrawInfoGraphBuffers( + _Inout_ PPH_GRAPH_BUFFERS Buffers, + _Inout_ PPH_GRAPH_DRAW_INFO DrawInfo, + _In_ ULONG DataCount + ); + +// Graph control state + +// The basic buffer management structure was moved out of this section because +// the text management is not needed for most cases. + +typedef struct _PH_GRAPH_STATE +{ + // Union for compatibility + union + { + struct + { + PFLOAT Data1; // invalidate by setting Valid to FALSE + PFLOAT Data2; // invalidate by setting Valid to FALSE + ULONG AllocatedCount; + BOOLEAN Valid; // indicates the data is valid + }; + PH_GRAPH_BUFFERS Buffers; + }; + + PPH_STRING Text; + PPH_STRING TooltipText; // invalidate by setting TooltipIndex to -1 + ULONG TooltipIndex; // indicates the tooltip text is valid for this index +} PH_GRAPH_STATE, *PPH_GRAPH_STATE; + +PHLIBAPI +VOID PhInitializeGraphState( + _Out_ PPH_GRAPH_STATE State + ); + +PHLIBAPI +VOID PhDeleteGraphState( + _Inout_ PPH_GRAPH_STATE State + ); + +PHLIBAPI +VOID PhGraphStateGetDrawInfo( + _Inout_ PPH_GRAPH_STATE State, + _In_ PPH_GRAPH_GETDRAWINFO GetDrawInfo, + _In_ ULONG DataCount + ); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/phlib/include/guisupp.h b/phlib/include/guisupp.h index e5e8a5e0daa2..a2372bd3ddb5 100644 --- a/phlib/include/guisupp.h +++ b/phlib/include/guisupp.h @@ -1,43 +1,43 @@ -#ifndef _PH_GUISUPP_H -#define _PH_GUISUPP_H - -typedef HRESULT (WINAPI *_LoadIconMetric)( - _In_ HINSTANCE hinst, - _In_ PCWSTR pszName, - _In_ int lims, - _Out_ HICON *phico - ); - -typedef HRESULT (WINAPI *_LoadIconWithScaleDown)( - _In_ HINSTANCE hinst, - _In_ PCWSTR pszName, - _In_ int cx, - _In_ int cy, - _Out_ HICON *phico - ); - -typedef struct _PHP_ICON_ENTRY -{ - HINSTANCE InstanceHandle; - PWSTR Name; - ULONG Width; - ULONG Height; - HICON Icon; -} PHP_ICON_ENTRY, *PPHP_ICON_ENTRY; - -#define PHP_ICON_ENTRY_SIZE_SMALL (-1) -#define PHP_ICON_ENTRY_SIZE_LARGE (-2) - -FORCEINLINE ULONG PhpGetIconEntrySize( - _In_ ULONG InputSize, - _In_ ULONG Flags - ) -{ - if (Flags & PH_LOAD_ICON_SIZE_SMALL) - return PHP_ICON_ENTRY_SIZE_SMALL; - if (Flags & PH_LOAD_ICON_SIZE_LARGE) - return PHP_ICON_ENTRY_SIZE_LARGE; - return InputSize; -} - -#endif +#ifndef _PH_GUISUPP_H +#define _PH_GUISUPP_H + +typedef HRESULT (WINAPI *_LoadIconMetric)( + _In_ HINSTANCE hinst, + _In_ PCWSTR pszName, + _In_ int lims, + _Out_ HICON *phico + ); + +typedef HRESULT (WINAPI *_LoadIconWithScaleDown)( + _In_ HINSTANCE hinst, + _In_ PCWSTR pszName, + _In_ int cx, + _In_ int cy, + _Out_ HICON *phico + ); + +typedef struct _PHP_ICON_ENTRY +{ + HINSTANCE InstanceHandle; + PWSTR Name; + ULONG Width; + ULONG Height; + HICON Icon; +} PHP_ICON_ENTRY, *PPHP_ICON_ENTRY; + +#define PHP_ICON_ENTRY_SIZE_SMALL (-1) +#define PHP_ICON_ENTRY_SIZE_LARGE (-2) + +FORCEINLINE ULONG PhpGetIconEntrySize( + _In_ ULONG InputSize, + _In_ ULONG Flags + ) +{ + if (Flags & PH_LOAD_ICON_SIZE_SMALL) + return PHP_ICON_ENTRY_SIZE_SMALL; + if (Flags & PH_LOAD_ICON_SIZE_LARGE) + return PHP_ICON_ENTRY_SIZE_LARGE; + return InputSize; +} + +#endif diff --git a/phlib/include/handlep.h b/phlib/include/handlep.h index 06cf2cf899f4..ed1b69dae068 100644 --- a/phlib/include/handlep.h +++ b/phlib/include/handlep.h @@ -1,147 +1,147 @@ -#ifndef _PH_HANDLEP_H -#define _PH_HANDLEP_H - -#define PH_HANDLE_TABLE_ENTRY_TYPE 0x1 -#define PH_HANDLE_TABLE_ENTRY_IN_USE 0x0 -#define PH_HANDLE_TABLE_ENTRY_FREE 0x1 - -// Locked actually means Not Locked. This means that an in use, locked handle table entry can be -// used as-is. -#define PH_HANDLE_TABLE_ENTRY_LOCKED 0x2 -#define PH_HANDLE_TABLE_ENTRY_LOCKED_SHIFT 1 - -// There is initially one handle table level, with 256 entries. When the handle table is expanded, -// the table is replaced with a level 1 table, which contains 256 pointers to level 0 tables (the -// first entry already points to the initial level 0 table). Similarly, when the handle table is -// expanded a second time, the table is replaced with a level 2 table, which contains 256 pointers -// to level 1 tables. -// -// This provides a maximum of 16,777,216 handles. - -#define PH_HANDLE_TABLE_LEVEL_ENTRIES 256 -#define PH_HANDLE_TABLE_LEVEL_MASK 0x3 - -#define PH_HANDLE_TABLE_LOCKS 8 -#define PH_HANDLE_TABLE_LOCK_INDEX(HandleValue) ((HandleValue) % PH_HANDLE_TABLE_LOCKS) - -typedef struct _PH_HANDLE_TABLE -{ - PH_QUEUED_LOCK Lock; - PH_WAKE_EVENT HandleWakeEvent; - - ULONG Count; - ULONG_PTR TableValue; - ULONG FreeValue; - ULONG NextValue; - ULONG FreeValueAlt; - - ULONG Flags; - - PH_QUEUED_LOCK Locks[PH_HANDLE_TABLE_LOCKS]; -} PH_HANDLE_TABLE, *PPH_HANDLE_TABLE; - -FORCEINLINE VOID PhpLockHandleTableShared( - _Inout_ PPH_HANDLE_TABLE HandleTable, - _In_ ULONG Index - ) -{ - PhAcquireQueuedLockShared(&HandleTable->Locks[Index]); -} - -FORCEINLINE VOID PhpUnlockHandleTableShared( - _Inout_ PPH_HANDLE_TABLE HandleTable, - _In_ ULONG Index - ) -{ - PhReleaseQueuedLockShared(&HandleTable->Locks[Index]); -} - -// Handle values work by specifying indicies into each -// level. -// -// Bits 0-7: level 0 -// Bits 8-15: level 1 -// Bits 16-23: level 2 -// Bits 24-31: reserved - -#define PH_HANDLE_VALUE_INVALID ((ULONG)-1) -#define PH_HANDLE_VALUE_SHIFT 2 -#define PH_HANDLE_VALUE_BIAS 4 - -#define PH_HANDLE_VALUE_LEVEL0(HandleValue) ((HandleValue) & 0xff) -#define PH_HANDLE_VALUE_LEVEL1_U(HandleValue) ((HandleValue) >> 8) -#define PH_HANDLE_VALUE_LEVEL1(HandleValue) (PH_HANDLE_VALUE_LEVEL1_U(HandleValue) & 0xff) -#define PH_HANDLE_VALUE_LEVEL2_U(HandleValue) ((HandleValue) >> 16) -#define PH_HANDLE_VALUE_LEVEL2(HandleValue) (PH_HANDLE_VALUE_LEVEL2_U(HandleValue) & 0xff) -#define PH_HANDLE_VALUE_IS_INVALID(HandleValue) (((HandleValue) >> 24) != 0) - -FORCEINLINE HANDLE PhpEncodeHandle( - _In_ ULONG HandleValue - ) -{ - return UlongToHandle(((HandleValue << PH_HANDLE_VALUE_SHIFT) + PH_HANDLE_VALUE_BIAS)); -} - -FORCEINLINE ULONG PhpDecodeHandle( - _In_ HANDLE Handle - ) -{ - return (HandleToUlong(Handle) - PH_HANDLE_VALUE_BIAS) >> PH_HANDLE_VALUE_SHIFT; -} - -VOID PhpBlockOnLockedHandleTableEntry( - _Inout_ PPH_HANDLE_TABLE HandleTable, - _In_ PPH_HANDLE_TABLE_ENTRY HandleTableEntry - ); - -PPH_HANDLE_TABLE_ENTRY PhpAllocateHandleTableEntry( - _Inout_ PPH_HANDLE_TABLE HandleTable, - _Out_ PULONG HandleValue - ); - -VOID PhpFreeHandleTableEntry( - _Inout_ PPH_HANDLE_TABLE HandleTable, - _In_ ULONG HandleValue, - _Inout_ PPH_HANDLE_TABLE_ENTRY HandleTableEntry - ); - -BOOLEAN PhpAllocateMoreHandleTableEntries( - _In_ PPH_HANDLE_TABLE HandleTable, - _In_ BOOLEAN Initialize - ); - -PPH_HANDLE_TABLE_ENTRY PhpLookupHandleTableEntry( - _In_ PPH_HANDLE_TABLE HandleTable, - _In_ ULONG HandleValue - ); - -ULONG PhpMoveFreeHandleTableEntries( - _Inout_ PPH_HANDLE_TABLE HandleTable - ); - -PPH_HANDLE_TABLE_ENTRY PhpCreateHandleTableLevel0( - _In_ PPH_HANDLE_TABLE HandleTable, - _In_ BOOLEAN Initialize - ); - -VOID PhpFreeHandleTableLevel0( - _In_ PPH_HANDLE_TABLE_ENTRY Table - ); - -PPH_HANDLE_TABLE_ENTRY *PhpCreateHandleTableLevel1( - _In_ PPH_HANDLE_TABLE HandleTable - ); - -VOID PhpFreeHandleTableLevel1( - _In_ PPH_HANDLE_TABLE_ENTRY *Table - ); - -PPH_HANDLE_TABLE_ENTRY **PhpCreateHandleTableLevel2( - _In_ PPH_HANDLE_TABLE HandleTable - ); - -VOID PhpFreeHandleTableLevel2( - _In_ PPH_HANDLE_TABLE_ENTRY **Table - ); - -#endif +#ifndef _PH_HANDLEP_H +#define _PH_HANDLEP_H + +#define PH_HANDLE_TABLE_ENTRY_TYPE 0x1 +#define PH_HANDLE_TABLE_ENTRY_IN_USE 0x0 +#define PH_HANDLE_TABLE_ENTRY_FREE 0x1 + +// Locked actually means Not Locked. This means that an in use, locked handle table entry can be +// used as-is. +#define PH_HANDLE_TABLE_ENTRY_LOCKED 0x2 +#define PH_HANDLE_TABLE_ENTRY_LOCKED_SHIFT 1 + +// There is initially one handle table level, with 256 entries. When the handle table is expanded, +// the table is replaced with a level 1 table, which contains 256 pointers to level 0 tables (the +// first entry already points to the initial level 0 table). Similarly, when the handle table is +// expanded a second time, the table is replaced with a level 2 table, which contains 256 pointers +// to level 1 tables. +// +// This provides a maximum of 16,777,216 handles. + +#define PH_HANDLE_TABLE_LEVEL_ENTRIES 256 +#define PH_HANDLE_TABLE_LEVEL_MASK 0x3 + +#define PH_HANDLE_TABLE_LOCKS 8 +#define PH_HANDLE_TABLE_LOCK_INDEX(HandleValue) ((HandleValue) % PH_HANDLE_TABLE_LOCKS) + +typedef struct _PH_HANDLE_TABLE +{ + PH_QUEUED_LOCK Lock; + PH_WAKE_EVENT HandleWakeEvent; + + ULONG Count; + ULONG_PTR TableValue; + ULONG FreeValue; + ULONG NextValue; + ULONG FreeValueAlt; + + ULONG Flags; + + PH_QUEUED_LOCK Locks[PH_HANDLE_TABLE_LOCKS]; +} PH_HANDLE_TABLE, *PPH_HANDLE_TABLE; + +FORCEINLINE VOID PhpLockHandleTableShared( + _Inout_ PPH_HANDLE_TABLE HandleTable, + _In_ ULONG Index + ) +{ + PhAcquireQueuedLockShared(&HandleTable->Locks[Index]); +} + +FORCEINLINE VOID PhpUnlockHandleTableShared( + _Inout_ PPH_HANDLE_TABLE HandleTable, + _In_ ULONG Index + ) +{ + PhReleaseQueuedLockShared(&HandleTable->Locks[Index]); +} + +// Handle values work by specifying indicies into each +// level. +// +// Bits 0-7: level 0 +// Bits 8-15: level 1 +// Bits 16-23: level 2 +// Bits 24-31: reserved + +#define PH_HANDLE_VALUE_INVALID ((ULONG)-1) +#define PH_HANDLE_VALUE_SHIFT 2 +#define PH_HANDLE_VALUE_BIAS 4 + +#define PH_HANDLE_VALUE_LEVEL0(HandleValue) ((HandleValue) & 0xff) +#define PH_HANDLE_VALUE_LEVEL1_U(HandleValue) ((HandleValue) >> 8) +#define PH_HANDLE_VALUE_LEVEL1(HandleValue) (PH_HANDLE_VALUE_LEVEL1_U(HandleValue) & 0xff) +#define PH_HANDLE_VALUE_LEVEL2_U(HandleValue) ((HandleValue) >> 16) +#define PH_HANDLE_VALUE_LEVEL2(HandleValue) (PH_HANDLE_VALUE_LEVEL2_U(HandleValue) & 0xff) +#define PH_HANDLE_VALUE_IS_INVALID(HandleValue) (((HandleValue) >> 24) != 0) + +FORCEINLINE HANDLE PhpEncodeHandle( + _In_ ULONG HandleValue + ) +{ + return UlongToHandle(((HandleValue << PH_HANDLE_VALUE_SHIFT) + PH_HANDLE_VALUE_BIAS)); +} + +FORCEINLINE ULONG PhpDecodeHandle( + _In_ HANDLE Handle + ) +{ + return (HandleToUlong(Handle) - PH_HANDLE_VALUE_BIAS) >> PH_HANDLE_VALUE_SHIFT; +} + +VOID PhpBlockOnLockedHandleTableEntry( + _Inout_ PPH_HANDLE_TABLE HandleTable, + _In_ PPH_HANDLE_TABLE_ENTRY HandleTableEntry + ); + +PPH_HANDLE_TABLE_ENTRY PhpAllocateHandleTableEntry( + _Inout_ PPH_HANDLE_TABLE HandleTable, + _Out_ PULONG HandleValue + ); + +VOID PhpFreeHandleTableEntry( + _Inout_ PPH_HANDLE_TABLE HandleTable, + _In_ ULONG HandleValue, + _Inout_ PPH_HANDLE_TABLE_ENTRY HandleTableEntry + ); + +BOOLEAN PhpAllocateMoreHandleTableEntries( + _In_ PPH_HANDLE_TABLE HandleTable, + _In_ BOOLEAN Initialize + ); + +PPH_HANDLE_TABLE_ENTRY PhpLookupHandleTableEntry( + _In_ PPH_HANDLE_TABLE HandleTable, + _In_ ULONG HandleValue + ); + +ULONG PhpMoveFreeHandleTableEntries( + _Inout_ PPH_HANDLE_TABLE HandleTable + ); + +PPH_HANDLE_TABLE_ENTRY PhpCreateHandleTableLevel0( + _In_ PPH_HANDLE_TABLE HandleTable, + _In_ BOOLEAN Initialize + ); + +VOID PhpFreeHandleTableLevel0( + _In_ PPH_HANDLE_TABLE_ENTRY Table + ); + +PPH_HANDLE_TABLE_ENTRY *PhpCreateHandleTableLevel1( + _In_ PPH_HANDLE_TABLE HandleTable + ); + +VOID PhpFreeHandleTableLevel1( + _In_ PPH_HANDLE_TABLE_ENTRY *Table + ); + +PPH_HANDLE_TABLE_ENTRY **PhpCreateHandleTableLevel2( + _In_ PPH_HANDLE_TABLE HandleTable + ); + +VOID PhpFreeHandleTableLevel2( + _In_ PPH_HANDLE_TABLE_ENTRY **Table + ); + +#endif diff --git a/phlib/include/hexedit.h b/phlib/include/hexedit.h index 93287013fb32..3fbd74ac32ce 100644 --- a/phlib/include/hexedit.h +++ b/phlib/include/hexedit.h @@ -1,49 +1,49 @@ -#ifndef _PH_HEXEDIT_H -#define _PH_HEXEDIT_H - -#ifdef __cplusplus -extern "C" { -#endif - -#define PH_HEXEDIT_CLASSNAME L"PhHexEdit" - -#define EDIT_NONE 0 -#define EDIT_ASCII 1 -#define EDIT_HIGH 2 -#define EDIT_LOW 3 - -PHLIBAPI -BOOLEAN PhHexEditInitialization( - VOID - ); - -#define HEM_SETBUFFER (WM_USER + 1) -#define HEM_SETDATA (WM_USER + 2) -#define HEM_GETBUFFER (WM_USER + 3) -#define HEM_SETSEL (WM_USER + 4) -#define HEM_SETEDITMODE (WM_USER + 5) -#define HEM_SETBYTESPERROW (WM_USER + 6) - -#define HexEdit_SetBuffer(hWnd, Buffer, Length) \ - SendMessage((hWnd), HEM_SETBUFFER, (WPARAM)(Length), (LPARAM)(Buffer)) - -#define HexEdit_SetData(hWnd, Buffer, Length) \ - SendMessage((hWnd), HEM_SETDATA, (WPARAM)(Length), (LPARAM)(Buffer)) - -#define HexEdit_GetBuffer(hWnd, Length) \ - ((PUCHAR)SendMessage((hWnd), HEM_GETBUFFER, (WPARAM)(Length), 0)) - -#define HexEdit_SetSel(hWnd, Start, End) \ - SendMessage((hWnd), HEM_SETSEL, (WPARAM)(Start), (LPARAM)(End)) - -#define HexEdit_SetEditMode(hWnd, Mode) \ - SendMessage((hWnd), HEM_SETEDITMODE, (WPARAM)(Mode), 0) - -#define HexEdit_SetBytesPerRow(hWnd, BytesPerRow) \ - SendMessage((hWnd), HEM_SETBYTESPERROW, (WPARAM)(BytesPerRow), 0) - -#ifdef __cplusplus -} -#endif - -#endif +#ifndef _PH_HEXEDIT_H +#define _PH_HEXEDIT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define PH_HEXEDIT_CLASSNAME L"PhHexEdit" + +#define EDIT_NONE 0 +#define EDIT_ASCII 1 +#define EDIT_HIGH 2 +#define EDIT_LOW 3 + +PHLIBAPI +BOOLEAN PhHexEditInitialization( + VOID + ); + +#define HEM_SETBUFFER (WM_USER + 1) +#define HEM_SETDATA (WM_USER + 2) +#define HEM_GETBUFFER (WM_USER + 3) +#define HEM_SETSEL (WM_USER + 4) +#define HEM_SETEDITMODE (WM_USER + 5) +#define HEM_SETBYTESPERROW (WM_USER + 6) + +#define HexEdit_SetBuffer(hWnd, Buffer, Length) \ + SendMessage((hWnd), HEM_SETBUFFER, (WPARAM)(Length), (LPARAM)(Buffer)) + +#define HexEdit_SetData(hWnd, Buffer, Length) \ + SendMessage((hWnd), HEM_SETDATA, (WPARAM)(Length), (LPARAM)(Buffer)) + +#define HexEdit_GetBuffer(hWnd, Length) \ + ((PUCHAR)SendMessage((hWnd), HEM_GETBUFFER, (WPARAM)(Length), 0)) + +#define HexEdit_SetSel(hWnd, Start, End) \ + SendMessage((hWnd), HEM_SETSEL, (WPARAM)(Start), (LPARAM)(End)) + +#define HexEdit_SetEditMode(hWnd, Mode) \ + SendMessage((hWnd), HEM_SETEDITMODE, (WPARAM)(Mode), 0) + +#define HexEdit_SetBytesPerRow(hWnd, BytesPerRow) \ + SendMessage((hWnd), HEM_SETBYTESPERROW, (WPARAM)(BytesPerRow), 0) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/phlib/include/hexeditp.h b/phlib/include/hexeditp.h index f7c59bba41ab..53bb4f0d0029 100644 --- a/phlib/include/hexeditp.h +++ b/phlib/include/hexeditp.h @@ -1,201 +1,201 @@ -#ifndef _PH_HEXEDITP_H -#define _PH_HEXEDITP_H - -typedef struct _PHP_HEXEDIT_CONTEXT -{ - PUCHAR Data; - LONG Length; - BOOLEAN UserBuffer; - LONG TopIndex; // index of first visible byte on screen - - LONG CurrentAddress; - LONG CurrentMode; - LONG SelStart; - LONG SelEnd; - - LONG BytesPerRow; - LONG LinesPerPage; - BOOLEAN ShowAddress; - BOOLEAN ShowAscii; - BOOLEAN ShowHex; - BOOLEAN AddressIsWide; - BOOLEAN AllowLengthChange; - - BOOLEAN NoAddressChange; - BOOLEAN HalfPage; - - HFONT Font; - LONG LineHeight; - LONG NullWidth; - PWCHAR CharBuffer; - ULONG CharBufferLength; - BOOLEAN Update; - - LONG HexOffset; - LONG AsciiOffset; - LONG AddressOffset; - - BOOLEAN HasCapture; - POINT EditPosition; -} PHP_HEXEDIT_CONTEXT, *PPHP_HEXEDIT_CONTEXT; - -#define IS_PRINTABLE(Byte) ((ULONG)((Byte) - ' ') <= (ULONG)('~' - ' ')) - -#define TO_HEX(Buffer, Byte) \ -{ \ - *(Buffer)++ = PhIntegerToChar[(Byte) >> 4]; \ - *(Buffer)++ = PhIntegerToChar[(Byte) & 0xf]; \ -} - -#define REDRAW_WINDOW(hwnd) \ - RedrawWindow((hwnd), NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW | RDW_ERASE) - -VOID PhpCreateHexEditContext( - _Out_ PPHP_HEXEDIT_CONTEXT *Context - ); - -VOID PhpFreeHexEditContext( - _In_ _Post_invalid_ PPHP_HEXEDIT_CONTEXT Context - ); - -LRESULT CALLBACK PhpHexEditWndProc( - _In_ HWND hwnd, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -VOID PhpHexEditUpdateMetrics( - _In_ HWND hwnd, - _In_ PPHP_HEXEDIT_CONTEXT Context, - _In_ BOOLEAN UpdateLineHeight, - _In_opt_ HDC hdc - ); - -VOID PhpHexEditOnPaint( - _In_ HWND hwnd, - _In_ PPHP_HEXEDIT_CONTEXT Context, - _In_ PAINTSTRUCT *PaintStruct, - _In_ HDC hdc - ); - -VOID PhpHexEditUpdateScrollbars( - _In_ HWND hwnd, - _In_ PPHP_HEXEDIT_CONTEXT Context - ); - -FORCEINLINE BOOLEAN PhpHexEditHasSelected( - _In_ PPHP_HEXEDIT_CONTEXT Context - ) -{ - return Context->SelStart != -1; -} - -VOID PhpHexEditCreateAddressCaret( - _In_ HWND hwnd, - _In_ PPHP_HEXEDIT_CONTEXT Context - ); - -VOID PhpHexEditCreateEditCaret( - _In_ HWND hwnd, - _In_ PPHP_HEXEDIT_CONTEXT Context - ); - -VOID PhpHexEditRepositionCaret( - _In_ HWND hwnd, - _In_ PPHP_HEXEDIT_CONTEXT Context, - _In_ LONG Position - ); - -VOID PhpHexEditCalculatePosition( - _In_ HWND hwnd, - _In_ PPHP_HEXEDIT_CONTEXT Context, - _In_ LONG X, - _In_ LONG Y, - _Out_ POINT *Point - ); - -VOID PhpHexEditMove( - _In_ HWND hwnd, - _In_ PPHP_HEXEDIT_CONTEXT Context, - _In_ LONG X, - _In_ LONG Y - ); - -VOID PhpHexEditSetSel( - _In_ HWND hwnd, - _In_ PPHP_HEXEDIT_CONTEXT Context, - _In_ LONG S, - _In_ LONG E - ); - -VOID PhpHexEditScrollTo( - _In_ HWND hwnd, - _In_ PPHP_HEXEDIT_CONTEXT Context, - _In_ LONG Position - ); - -VOID PhpHexEditClearEdit( - _In_ HWND hwnd, - _In_ PPHP_HEXEDIT_CONTEXT Context - ); - -VOID PhpHexEditCopyEdit( - _In_ HWND hwnd, - _In_ PPHP_HEXEDIT_CONTEXT Context - ); - -VOID PhpHexEditCutEdit( - _In_ HWND hwnd, - _In_ PPHP_HEXEDIT_CONTEXT Context - ); - -VOID PhpHexEditPasteEdit( - _In_ HWND hwnd, - _In_ PPHP_HEXEDIT_CONTEXT Context - ); - -VOID PhpHexEditSelectAll( - _In_ HWND hwnd, - _In_ PPHP_HEXEDIT_CONTEXT Context - ); - -VOID PhpHexEditUndoEdit( - _In_ HWND hwnd, - _In_ PPHP_HEXEDIT_CONTEXT Context - ); - -VOID PhpHexEditNormalizeSel( - _In_ HWND hwnd, - _In_ PPHP_HEXEDIT_CONTEXT Context - ); - -VOID PhpHexEditSelDelete( - _In_ HWND hwnd, - _In_ PPHP_HEXEDIT_CONTEXT Context, - _In_ LONG S, - _In_ LONG E - ); - -VOID PhpHexEditSelInsert( - _In_ HWND hwnd, - _In_ PPHP_HEXEDIT_CONTEXT Context, - _In_ LONG S, - _In_ LONG L - ); - -VOID PhpHexEditSetBuffer( - _In_ HWND hwnd, - _In_ PPHP_HEXEDIT_CONTEXT Context, - _In_ PUCHAR Data, - _In_ ULONG Length - ); - -VOID PhpHexEditSetData( - _In_ HWND hwnd, - _In_ PPHP_HEXEDIT_CONTEXT Context, - _In_ PUCHAR Data, - _In_ ULONG Length - ); - -#endif +#ifndef _PH_HEXEDITP_H +#define _PH_HEXEDITP_H + +typedef struct _PHP_HEXEDIT_CONTEXT +{ + PUCHAR Data; + LONG Length; + BOOLEAN UserBuffer; + LONG TopIndex; // index of first visible byte on screen + + LONG CurrentAddress; + LONG CurrentMode; + LONG SelStart; + LONG SelEnd; + + LONG BytesPerRow; + LONG LinesPerPage; + BOOLEAN ShowAddress; + BOOLEAN ShowAscii; + BOOLEAN ShowHex; + BOOLEAN AddressIsWide; + BOOLEAN AllowLengthChange; + + BOOLEAN NoAddressChange; + BOOLEAN HalfPage; + + HFONT Font; + LONG LineHeight; + LONG NullWidth; + PWCHAR CharBuffer; + ULONG CharBufferLength; + BOOLEAN Update; + + LONG HexOffset; + LONG AsciiOffset; + LONG AddressOffset; + + BOOLEAN HasCapture; + POINT EditPosition; +} PHP_HEXEDIT_CONTEXT, *PPHP_HEXEDIT_CONTEXT; + +#define IS_PRINTABLE(Byte) ((ULONG)((Byte) - ' ') <= (ULONG)('~' - ' ')) + +#define TO_HEX(Buffer, Byte) \ +{ \ + *(Buffer)++ = PhIntegerToChar[(Byte) >> 4]; \ + *(Buffer)++ = PhIntegerToChar[(Byte) & 0xf]; \ +} + +#define REDRAW_WINDOW(hwnd) \ + RedrawWindow((hwnd), NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW | RDW_ERASE) + +VOID PhpCreateHexEditContext( + _Out_ PPHP_HEXEDIT_CONTEXT *Context + ); + +VOID PhpFreeHexEditContext( + _In_ _Post_invalid_ PPHP_HEXEDIT_CONTEXT Context + ); + +LRESULT CALLBACK PhpHexEditWndProc( + _In_ HWND hwnd, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +VOID PhpHexEditUpdateMetrics( + _In_ HWND hwnd, + _In_ PPHP_HEXEDIT_CONTEXT Context, + _In_ BOOLEAN UpdateLineHeight, + _In_opt_ HDC hdc + ); + +VOID PhpHexEditOnPaint( + _In_ HWND hwnd, + _In_ PPHP_HEXEDIT_CONTEXT Context, + _In_ PAINTSTRUCT *PaintStruct, + _In_ HDC hdc + ); + +VOID PhpHexEditUpdateScrollbars( + _In_ HWND hwnd, + _In_ PPHP_HEXEDIT_CONTEXT Context + ); + +FORCEINLINE BOOLEAN PhpHexEditHasSelected( + _In_ PPHP_HEXEDIT_CONTEXT Context + ) +{ + return Context->SelStart != -1; +} + +VOID PhpHexEditCreateAddressCaret( + _In_ HWND hwnd, + _In_ PPHP_HEXEDIT_CONTEXT Context + ); + +VOID PhpHexEditCreateEditCaret( + _In_ HWND hwnd, + _In_ PPHP_HEXEDIT_CONTEXT Context + ); + +VOID PhpHexEditRepositionCaret( + _In_ HWND hwnd, + _In_ PPHP_HEXEDIT_CONTEXT Context, + _In_ LONG Position + ); + +VOID PhpHexEditCalculatePosition( + _In_ HWND hwnd, + _In_ PPHP_HEXEDIT_CONTEXT Context, + _In_ LONG X, + _In_ LONG Y, + _Out_ POINT *Point + ); + +VOID PhpHexEditMove( + _In_ HWND hwnd, + _In_ PPHP_HEXEDIT_CONTEXT Context, + _In_ LONG X, + _In_ LONG Y + ); + +VOID PhpHexEditSetSel( + _In_ HWND hwnd, + _In_ PPHP_HEXEDIT_CONTEXT Context, + _In_ LONG S, + _In_ LONG E + ); + +VOID PhpHexEditScrollTo( + _In_ HWND hwnd, + _In_ PPHP_HEXEDIT_CONTEXT Context, + _In_ LONG Position + ); + +VOID PhpHexEditClearEdit( + _In_ HWND hwnd, + _In_ PPHP_HEXEDIT_CONTEXT Context + ); + +VOID PhpHexEditCopyEdit( + _In_ HWND hwnd, + _In_ PPHP_HEXEDIT_CONTEXT Context + ); + +VOID PhpHexEditCutEdit( + _In_ HWND hwnd, + _In_ PPHP_HEXEDIT_CONTEXT Context + ); + +VOID PhpHexEditPasteEdit( + _In_ HWND hwnd, + _In_ PPHP_HEXEDIT_CONTEXT Context + ); + +VOID PhpHexEditSelectAll( + _In_ HWND hwnd, + _In_ PPHP_HEXEDIT_CONTEXT Context + ); + +VOID PhpHexEditUndoEdit( + _In_ HWND hwnd, + _In_ PPHP_HEXEDIT_CONTEXT Context + ); + +VOID PhpHexEditNormalizeSel( + _In_ HWND hwnd, + _In_ PPHP_HEXEDIT_CONTEXT Context + ); + +VOID PhpHexEditSelDelete( + _In_ HWND hwnd, + _In_ PPHP_HEXEDIT_CONTEXT Context, + _In_ LONG S, + _In_ LONG E + ); + +VOID PhpHexEditSelInsert( + _In_ HWND hwnd, + _In_ PPHP_HEXEDIT_CONTEXT Context, + _In_ LONG S, + _In_ LONG L + ); + +VOID PhpHexEditSetBuffer( + _In_ HWND hwnd, + _In_ PPHP_HEXEDIT_CONTEXT Context, + _In_ PUCHAR Data, + _In_ ULONG Length + ); + +VOID PhpHexEditSetData( + _In_ HWND hwnd, + _In_ PPHP_HEXEDIT_CONTEXT Context, + _In_ PUCHAR Data, + _In_ ULONG Length + ); + +#endif diff --git a/phlib/include/kphapi.h b/phlib/include/kphapi.h index e8a41992b376..f905de9a09d3 100644 --- a/phlib/include/kphapi.h +++ b/phlib/include/kphapi.h @@ -1,241 +1,241 @@ -#ifndef _KPHAPI_H -#define _KPHAPI_H - -// This file contains KProcessHacker definitions shared across kernel-mode and user-mode. - -// Process information - -typedef enum _KPH_PROCESS_INFORMATION_CLASS -{ - KphProcessReserved1 = 1, - KphProcessReserved2 = 2, - KphProcessReserved3 = 3, - MaxKphProcessInfoClass -} KPH_PROCESS_INFORMATION_CLASS; - -// Thread information - -typedef enum _KPH_THREAD_INFORMATION_CLASS -{ - KphThreadReserved1 = 1, - KphThreadReserved2 = 2, - KphThreadReserved3 = 3, - MaxKphThreadInfoClass -} KPH_THREAD_INFORMATION_CLASS; - -// Process handle information - -typedef struct _KPH_PROCESS_HANDLE -{ - HANDLE Handle; - PVOID Object; - ACCESS_MASK GrantedAccess; - USHORT ObjectTypeIndex; - USHORT Reserved1; - ULONG HandleAttributes; - ULONG Reserved2; -} KPH_PROCESS_HANDLE, *PKPH_PROCESS_HANDLE; - -typedef struct _KPH_PROCESS_HANDLE_INFORMATION -{ - ULONG HandleCount; - KPH_PROCESS_HANDLE Handles[1]; -} KPH_PROCESS_HANDLE_INFORMATION, *PKPH_PROCESS_HANDLE_INFORMATION; - -// Object information - -typedef enum _KPH_OBJECT_INFORMATION_CLASS -{ - KphObjectBasicInformation, // q: OBJECT_BASIC_INFORMATION - KphObjectNameInformation, // q: OBJECT_NAME_INFORMATION - KphObjectTypeInformation, // q: OBJECT_TYPE_INFORMATION - KphObjectHandleFlagInformation, // qs: OBJECT_HANDLE_FLAG_INFORMATION - KphObjectProcessBasicInformation, // q: PROCESS_BASIC_INFORMATION - KphObjectThreadBasicInformation, // q: THREAD_BASIC_INFORMATION - KphObjectEtwRegBasicInformation, // q: ETWREG_BASIC_INFORMATION - KphObjectFileObjectInformation, // q: KPH_FILE_OBJECT_INFORMATION - KphObjectFileObjectDriver, // q: KPH_FILE_OBJECT_DRIVER - MaxKphObjectInfoClass -} KPH_OBJECT_INFORMATION_CLASS; - -typedef struct _KPH_FILE_OBJECT_INFORMATION -{ - BOOLEAN LockOperation; - BOOLEAN DeletePending; - BOOLEAN ReadAccess; - BOOLEAN WriteAccess; - BOOLEAN DeleteAccess; - BOOLEAN SharedRead; - BOOLEAN SharedWrite; - BOOLEAN SharedDelete; - LARGE_INTEGER CurrentByteOffset; - ULONG Flags; -} KPH_FILE_OBJECT_INFORMATION, *PKPH_FILE_OBJECT_INFORMATION; - -typedef struct _KPH_FILE_OBJECT_DRIVER -{ - HANDLE DriverHandle; -} KPH_FILE_OBJECT_DRIVER, *PKPH_FILE_OBJECT_DRIVER; - -// Driver information - -typedef enum _DRIVER_INFORMATION_CLASS -{ - DriverBasicInformation, - DriverNameInformation, - DriverServiceKeyNameInformation, - MaxDriverInfoClass -} DRIVER_INFORMATION_CLASS; - -typedef struct _DRIVER_BASIC_INFORMATION -{ - ULONG Flags; - PVOID DriverStart; - ULONG DriverSize; -} DRIVER_BASIC_INFORMATION, *PDRIVER_BASIC_INFORMATION; - -typedef struct _DRIVER_NAME_INFORMATION -{ - UNICODE_STRING DriverName; -} DRIVER_NAME_INFORMATION, *PDRIVER_NAME_INFORMATION; - -typedef struct _DRIVER_SERVICE_KEY_NAME_INFORMATION -{ - UNICODE_STRING ServiceKeyName; -} DRIVER_SERVICE_KEY_NAME_INFORMATION, *PDRIVER_SERVICE_KEY_NAME_INFORMATION; - -// ETW registration object information - -typedef struct _ETWREG_BASIC_INFORMATION -{ - GUID Guid; - ULONG_PTR SessionId; -} ETWREG_BASIC_INFORMATION, *PETWREG_BASIC_INFORMATION; - -// Device - -#define KPH_DEVICE_SHORT_NAME L"KProcessHacker3" -#define KPH_DEVICE_TYPE 0x9999 -#define KPH_DEVICE_NAME (L"\\Device\\" KPH_DEVICE_SHORT_NAME) - -// Parameters - -typedef enum _KPH_SECURITY_LEVEL -{ - KphSecurityNone = 0, // all clients are allowed - KphSecurityPrivilegeCheck = 1, // require SeDebugPrivilege - KphSecuritySignatureCheck = 2, // require trusted signature - KphSecuritySignatureAndPrivilegeCheck = 3, // require trusted signature and SeDebugPrivilege - KphMaxSecurityLevel -} KPH_SECURITY_LEVEL, *PKPH_SECURITY_LEVEL; - -typedef struct _KPH_DYN_STRUCT_DATA -{ - SHORT EgeGuid; - SHORT EpObjectTable; - SHORT Reserved0; - SHORT Reserved1; - SHORT Reserved2; - SHORT EreGuidEntry; - SHORT HtHandleContentionEvent; - SHORT OtName; - SHORT OtIndex; - SHORT ObDecodeShift; - SHORT ObAttributesShift; -} KPH_DYN_STRUCT_DATA, *PKPH_DYN_STRUCT_DATA; - -typedef struct _KPH_DYN_PACKAGE -{ - USHORT MajorVersion; - USHORT MinorVersion; - USHORT ServicePackMajor; // -1 to ignore - USHORT BuildNumber; // -1 to ignore - ULONG ResultingNtVersion; // PHNT_* - KPH_DYN_STRUCT_DATA StructData; -} KPH_DYN_PACKAGE, *PKPH_DYN_PACKAGE; - -#define KPH_DYN_CONFIGURATION_VERSION 3 -#define KPH_DYN_MAXIMUM_PACKAGES 64 - -typedef struct _KPH_DYN_CONFIGURATION -{ - ULONG Version; - ULONG NumberOfPackages; - KPH_DYN_PACKAGE Packages[1]; -} KPH_DYN_CONFIGURATION, *PKPH_DYN_CONFIGURATION; - -// Verification - -#ifdef __BCRYPT_H__ -#define KPH_SIGN_ALGORITHM BCRYPT_ECDSA_P256_ALGORITHM -#define KPH_SIGN_ALGORITHM_BITS 256 -#define KPH_HASH_ALGORITHM BCRYPT_SHA256_ALGORITHM -#define KPH_BLOB_PUBLIC BCRYPT_ECCPUBLIC_BLOB -#endif - -#define KPH_SIGNATURE_MAX_SIZE (128 * 1024) // 128 kB - -typedef ULONG KPH_KEY, *PKPH_KEY; - -typedef enum _KPH_KEY_LEVEL -{ - KphKeyLevel1 = 1, - KphKeyLevel2 = 2 -} KPH_KEY_LEVEL; - -#define KPH_KEY_BACKOFF_TIME ((LONGLONG)(100 * 1000 * 10)) // 100ms - -#define KPH_PROCESS_READ_ACCESS (STANDARD_RIGHTS_READ | SYNCHRONIZE | PROCESS_QUERY_INFORMATION | \ - PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_VM_READ) -#define KPH_THREAD_READ_ACCESS (STANDARD_RIGHTS_READ | SYNCHRONIZE | THREAD_QUERY_INFORMATION | \ - THREAD_QUERY_LIMITED_INFORMATION | THREAD_GET_CONTEXT) -#define KPH_TOKEN_READ_ACCESS TOKEN_READ - -// Features - -// No features defined. - -// Control codes - -#define KPH_CTL_CODE(x) CTL_CODE(KPH_DEVICE_TYPE, 0x800 + x, METHOD_NEITHER, FILE_ANY_ACCESS) - -// General -#define KPH_GETFEATURES KPH_CTL_CODE(0) -#define KPH_VERIFYCLIENT KPH_CTL_CODE(1) -#define KPH_RETRIEVEKEY KPH_CTL_CODE(2) // User-mode only - -// Processes -#define KPH_OPENPROCESS KPH_CTL_CODE(50) // L1/L2 protected API -#define KPH_OPENPROCESSTOKEN KPH_CTL_CODE(51) // L1/L2 protected API -#define KPH_OPENPROCESSJOB KPH_CTL_CODE(52) -#define KPH_RESERVED53 KPH_CTL_CODE(53) -#define KPH_RESERVED54 KPH_CTL_CODE(54) -#define KPH_TERMINATEPROCESS KPH_CTL_CODE(55) // L2 protected API -#define KPH_RESERVED56 KPH_CTL_CODE(56) -#define KPH_RESERVED57 KPH_CTL_CODE(57) -#define KPH_READVIRTUALMEMORYUNSAFE KPH_CTL_CODE(58) // L2 protected API -#define KPH_QUERYINFORMATIONPROCESS KPH_CTL_CODE(59) -#define KPH_SETINFORMATIONPROCESS KPH_CTL_CODE(60) - -// Threads -#define KPH_OPENTHREAD KPH_CTL_CODE(100) // L1/L2 protected API -#define KPH_OPENTHREADPROCESS KPH_CTL_CODE(101) -#define KPH_RESERVED102 KPH_CTL_CODE(102) -#define KPH_RESERVED103 KPH_CTL_CODE(103) -#define KPH_RESERVED104 KPH_CTL_CODE(104) -#define KPH_RESERVED105 KPH_CTL_CODE(105) -#define KPH_CAPTURESTACKBACKTRACETHREAD KPH_CTL_CODE(106) -#define KPH_QUERYINFORMATIONTHREAD KPH_CTL_CODE(107) -#define KPH_SETINFORMATIONTHREAD KPH_CTL_CODE(108) - -// Handles -#define KPH_ENUMERATEPROCESSHANDLES KPH_CTL_CODE(150) -#define KPH_QUERYINFORMATIONOBJECT KPH_CTL_CODE(151) -#define KPH_SETINFORMATIONOBJECT KPH_CTL_CODE(152) -#define KPH_RESERVED153 KPH_CTL_CODE(153) - -// Misc. -#define KPH_OPENDRIVER KPH_CTL_CODE(200) -#define KPH_QUERYINFORMATIONDRIVER KPH_CTL_CODE(201) - +#ifndef _KPHAPI_H +#define _KPHAPI_H + +// This file contains KProcessHacker definitions shared across kernel-mode and user-mode. + +// Process information + +typedef enum _KPH_PROCESS_INFORMATION_CLASS +{ + KphProcessReserved1 = 1, + KphProcessReserved2 = 2, + KphProcessReserved3 = 3, + MaxKphProcessInfoClass +} KPH_PROCESS_INFORMATION_CLASS; + +// Thread information + +typedef enum _KPH_THREAD_INFORMATION_CLASS +{ + KphThreadReserved1 = 1, + KphThreadReserved2 = 2, + KphThreadReserved3 = 3, + MaxKphThreadInfoClass +} KPH_THREAD_INFORMATION_CLASS; + +// Process handle information + +typedef struct _KPH_PROCESS_HANDLE +{ + HANDLE Handle; + PVOID Object; + ACCESS_MASK GrantedAccess; + USHORT ObjectTypeIndex; + USHORT Reserved1; + ULONG HandleAttributes; + ULONG Reserved2; +} KPH_PROCESS_HANDLE, *PKPH_PROCESS_HANDLE; + +typedef struct _KPH_PROCESS_HANDLE_INFORMATION +{ + ULONG HandleCount; + KPH_PROCESS_HANDLE Handles[1]; +} KPH_PROCESS_HANDLE_INFORMATION, *PKPH_PROCESS_HANDLE_INFORMATION; + +// Object information + +typedef enum _KPH_OBJECT_INFORMATION_CLASS +{ + KphObjectBasicInformation, // q: OBJECT_BASIC_INFORMATION + KphObjectNameInformation, // q: OBJECT_NAME_INFORMATION + KphObjectTypeInformation, // q: OBJECT_TYPE_INFORMATION + KphObjectHandleFlagInformation, // qs: OBJECT_HANDLE_FLAG_INFORMATION + KphObjectProcessBasicInformation, // q: PROCESS_BASIC_INFORMATION + KphObjectThreadBasicInformation, // q: THREAD_BASIC_INFORMATION + KphObjectEtwRegBasicInformation, // q: ETWREG_BASIC_INFORMATION + KphObjectFileObjectInformation, // q: KPH_FILE_OBJECT_INFORMATION + KphObjectFileObjectDriver, // q: KPH_FILE_OBJECT_DRIVER + MaxKphObjectInfoClass +} KPH_OBJECT_INFORMATION_CLASS; + +typedef struct _KPH_FILE_OBJECT_INFORMATION +{ + BOOLEAN LockOperation; + BOOLEAN DeletePending; + BOOLEAN ReadAccess; + BOOLEAN WriteAccess; + BOOLEAN DeleteAccess; + BOOLEAN SharedRead; + BOOLEAN SharedWrite; + BOOLEAN SharedDelete; + LARGE_INTEGER CurrentByteOffset; + ULONG Flags; +} KPH_FILE_OBJECT_INFORMATION, *PKPH_FILE_OBJECT_INFORMATION; + +typedef struct _KPH_FILE_OBJECT_DRIVER +{ + HANDLE DriverHandle; +} KPH_FILE_OBJECT_DRIVER, *PKPH_FILE_OBJECT_DRIVER; + +// Driver information + +typedef enum _DRIVER_INFORMATION_CLASS +{ + DriverBasicInformation, + DriverNameInformation, + DriverServiceKeyNameInformation, + MaxDriverInfoClass +} DRIVER_INFORMATION_CLASS; + +typedef struct _DRIVER_BASIC_INFORMATION +{ + ULONG Flags; + PVOID DriverStart; + ULONG DriverSize; +} DRIVER_BASIC_INFORMATION, *PDRIVER_BASIC_INFORMATION; + +typedef struct _DRIVER_NAME_INFORMATION +{ + UNICODE_STRING DriverName; +} DRIVER_NAME_INFORMATION, *PDRIVER_NAME_INFORMATION; + +typedef struct _DRIVER_SERVICE_KEY_NAME_INFORMATION +{ + UNICODE_STRING ServiceKeyName; +} DRIVER_SERVICE_KEY_NAME_INFORMATION, *PDRIVER_SERVICE_KEY_NAME_INFORMATION; + +// ETW registration object information + +typedef struct _ETWREG_BASIC_INFORMATION +{ + GUID Guid; + ULONG_PTR SessionId; +} ETWREG_BASIC_INFORMATION, *PETWREG_BASIC_INFORMATION; + +// Device + +#define KPH_DEVICE_SHORT_NAME L"KProcessHacker3" +#define KPH_DEVICE_TYPE 0x9999 +#define KPH_DEVICE_NAME (L"\\Device\\" KPH_DEVICE_SHORT_NAME) + +// Parameters + +typedef enum _KPH_SECURITY_LEVEL +{ + KphSecurityNone = 0, // all clients are allowed + KphSecurityPrivilegeCheck = 1, // require SeDebugPrivilege + KphSecuritySignatureCheck = 2, // require trusted signature + KphSecuritySignatureAndPrivilegeCheck = 3, // require trusted signature and SeDebugPrivilege + KphMaxSecurityLevel +} KPH_SECURITY_LEVEL, *PKPH_SECURITY_LEVEL; + +typedef struct _KPH_DYN_STRUCT_DATA +{ + SHORT EgeGuid; + SHORT EpObjectTable; + SHORT Reserved0; + SHORT Reserved1; + SHORT Reserved2; + SHORT EreGuidEntry; + SHORT HtHandleContentionEvent; + SHORT OtName; + SHORT OtIndex; + SHORT ObDecodeShift; + SHORT ObAttributesShift; +} KPH_DYN_STRUCT_DATA, *PKPH_DYN_STRUCT_DATA; + +typedef struct _KPH_DYN_PACKAGE +{ + USHORT MajorVersion; + USHORT MinorVersion; + USHORT ServicePackMajor; // -1 to ignore + USHORT BuildNumber; // -1 to ignore + ULONG ResultingNtVersion; // PHNT_* + KPH_DYN_STRUCT_DATA StructData; +} KPH_DYN_PACKAGE, *PKPH_DYN_PACKAGE; + +#define KPH_DYN_CONFIGURATION_VERSION 3 +#define KPH_DYN_MAXIMUM_PACKAGES 64 + +typedef struct _KPH_DYN_CONFIGURATION +{ + ULONG Version; + ULONG NumberOfPackages; + KPH_DYN_PACKAGE Packages[1]; +} KPH_DYN_CONFIGURATION, *PKPH_DYN_CONFIGURATION; + +// Verification + +#ifdef __BCRYPT_H__ +#define KPH_SIGN_ALGORITHM BCRYPT_ECDSA_P256_ALGORITHM +#define KPH_SIGN_ALGORITHM_BITS 256 +#define KPH_HASH_ALGORITHM BCRYPT_SHA256_ALGORITHM +#define KPH_BLOB_PUBLIC BCRYPT_ECCPUBLIC_BLOB +#endif + +#define KPH_SIGNATURE_MAX_SIZE (128 * 1024) // 128 kB + +typedef ULONG KPH_KEY, *PKPH_KEY; + +typedef enum _KPH_KEY_LEVEL +{ + KphKeyLevel1 = 1, + KphKeyLevel2 = 2 +} KPH_KEY_LEVEL; + +#define KPH_KEY_BACKOFF_TIME ((LONGLONG)(100 * 1000 * 10)) // 100ms + +#define KPH_PROCESS_READ_ACCESS (STANDARD_RIGHTS_READ | SYNCHRONIZE | PROCESS_QUERY_INFORMATION | \ + PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_VM_READ) +#define KPH_THREAD_READ_ACCESS (STANDARD_RIGHTS_READ | SYNCHRONIZE | THREAD_QUERY_INFORMATION | \ + THREAD_QUERY_LIMITED_INFORMATION | THREAD_GET_CONTEXT) +#define KPH_TOKEN_READ_ACCESS TOKEN_READ + +// Features + +// No features defined. + +// Control codes + +#define KPH_CTL_CODE(x) CTL_CODE(KPH_DEVICE_TYPE, 0x800 + x, METHOD_NEITHER, FILE_ANY_ACCESS) + +// General +#define KPH_GETFEATURES KPH_CTL_CODE(0) +#define KPH_VERIFYCLIENT KPH_CTL_CODE(1) +#define KPH_RETRIEVEKEY KPH_CTL_CODE(2) // User-mode only + +// Processes +#define KPH_OPENPROCESS KPH_CTL_CODE(50) // L1/L2 protected API +#define KPH_OPENPROCESSTOKEN KPH_CTL_CODE(51) // L1/L2 protected API +#define KPH_OPENPROCESSJOB KPH_CTL_CODE(52) +#define KPH_RESERVED53 KPH_CTL_CODE(53) +#define KPH_RESERVED54 KPH_CTL_CODE(54) +#define KPH_TERMINATEPROCESS KPH_CTL_CODE(55) // L2 protected API +#define KPH_RESERVED56 KPH_CTL_CODE(56) +#define KPH_RESERVED57 KPH_CTL_CODE(57) +#define KPH_READVIRTUALMEMORYUNSAFE KPH_CTL_CODE(58) // L2 protected API +#define KPH_QUERYINFORMATIONPROCESS KPH_CTL_CODE(59) +#define KPH_SETINFORMATIONPROCESS KPH_CTL_CODE(60) + +// Threads +#define KPH_OPENTHREAD KPH_CTL_CODE(100) // L1/L2 protected API +#define KPH_OPENTHREADPROCESS KPH_CTL_CODE(101) +#define KPH_RESERVED102 KPH_CTL_CODE(102) +#define KPH_RESERVED103 KPH_CTL_CODE(103) +#define KPH_RESERVED104 KPH_CTL_CODE(104) +#define KPH_RESERVED105 KPH_CTL_CODE(105) +#define KPH_CAPTURESTACKBACKTRACETHREAD KPH_CTL_CODE(106) +#define KPH_QUERYINFORMATIONTHREAD KPH_CTL_CODE(107) +#define KPH_SETINFORMATIONTHREAD KPH_CTL_CODE(108) + +// Handles +#define KPH_ENUMERATEPROCESSHANDLES KPH_CTL_CODE(150) +#define KPH_QUERYINFORMATIONOBJECT KPH_CTL_CODE(151) +#define KPH_SETINFORMATIONOBJECT KPH_CTL_CODE(152) +#define KPH_RESERVED153 KPH_CTL_CODE(153) + +// Misc. +#define KPH_OPENDRIVER KPH_CTL_CODE(200) +#define KPH_QUERYINFORMATIONDRIVER KPH_CTL_CODE(201) + #endif \ No newline at end of file diff --git a/phlib/include/kphuser.h b/phlib/include/kphuser.h index 55c90b84db5b..102534b55a62 100644 --- a/phlib/include/kphuser.h +++ b/phlib/include/kphuser.h @@ -1,300 +1,300 @@ -#ifndef _PH_KPHUSER_H -#define _PH_KPHUSER_H - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct _KPH_PARAMETERS -{ - KPH_SECURITY_LEVEL SecurityLevel; - BOOLEAN CreateDynamicConfiguration; -} KPH_PARAMETERS, *PKPH_PARAMETERS; - -PHLIBAPI -NTSTATUS -NTAPI -KphConnect( - _In_opt_ PWSTR DeviceName - ); - -PHLIBAPI -NTSTATUS -NTAPI -KphConnect2( - _In_opt_ PWSTR DeviceName, - _In_ PWSTR FileName - ); - -PHLIBAPI -NTSTATUS -NTAPI -KphConnect2Ex( - _In_opt_ PWSTR DeviceName, - _In_ PWSTR FileName, - _In_opt_ PKPH_PARAMETERS Parameters - ); - -PHLIBAPI -NTSTATUS -NTAPI -KphDisconnect( - VOID - ); - -PHLIBAPI -BOOLEAN -NTAPI -KphIsConnected( - VOID - ); - -PHLIBAPI -BOOLEAN -NTAPI -KphIsVerified( - VOID - ); - -PHLIBAPI -NTSTATUS -NTAPI -KphSetParameters( - _In_opt_ PWSTR DeviceName, - _In_ PKPH_PARAMETERS Parameters - ); - -PHLIBAPI -NTSTATUS -NTAPI -KphInstall( - _In_opt_ PWSTR DeviceName, - _In_ PWSTR FileName - ); - -PHLIBAPI -NTSTATUS -NTAPI -KphInstallEx( - _In_opt_ PWSTR DeviceName, - _In_ PWSTR FileName, - _In_opt_ PKPH_PARAMETERS Parameters - ); - -PHLIBAPI -NTSTATUS -NTAPI -KphUninstall( - _In_opt_ PWSTR DeviceName - ); - -PHLIBAPI -NTSTATUS -NTAPI -KphGetFeatures( - _Out_ PULONG Features - ); - -PHLIBAPI -NTSTATUS -NTAPI -KphVerifyClient( - _In_reads_bytes_(SignatureSize) PUCHAR Signature, - _In_ ULONG SignatureSize - ); - -PHLIBAPI -NTSTATUS -NTAPI -KphOpenProcess( - _Out_ PHANDLE ProcessHandle, - _In_ ACCESS_MASK DesiredAccess, - _In_ PCLIENT_ID ClientId - ); - -PHLIBAPI -NTSTATUS -NTAPI -KphOpenProcessToken( - _In_ HANDLE ProcessHandle, - _In_ ACCESS_MASK DesiredAccess, - _Out_ PHANDLE TokenHandle - ); - -PHLIBAPI -NTSTATUS -NTAPI -KphOpenProcessJob( - _In_ HANDLE ProcessHandle, - _In_ ACCESS_MASK DesiredAccess, - _Out_ PHANDLE JobHandle - ); - -PHLIBAPI -NTSTATUS -NTAPI -KphTerminateProcess( - _In_ HANDLE ProcessHandle, - _In_ NTSTATUS ExitStatus - ); - -PHLIBAPI -NTSTATUS -NTAPI -KphReadVirtualMemoryUnsafe( - _In_opt_ HANDLE ProcessHandle, - _In_ PVOID BaseAddress, - _Out_writes_bytes_(BufferSize) PVOID Buffer, - _In_ SIZE_T BufferSize, - _Out_opt_ PSIZE_T NumberOfBytesRead - ); - -PHLIBAPI -NTSTATUS -NTAPI -KphQueryInformationProcess( - _In_ HANDLE ProcessHandle, - _In_ KPH_PROCESS_INFORMATION_CLASS ProcessInformationClass, - _Out_writes_bytes_(ProcessInformationLength) PVOID ProcessInformation, - _In_ ULONG ProcessInformationLength, - _Out_opt_ PULONG ReturnLength - ); - -PHLIBAPI -NTSTATUS -NTAPI -KphSetInformationProcess( - _In_ HANDLE ProcessHandle, - _In_ KPH_PROCESS_INFORMATION_CLASS ProcessInformationClass, - _In_reads_bytes_(ProcessInformationLength) PVOID ProcessInformation, - _In_ ULONG ProcessInformationLength - ); - -PHLIBAPI -NTSTATUS -NTAPI -KphOpenThread( - _Out_ PHANDLE ThreadHandle, - _In_ ACCESS_MASK DesiredAccess, - _In_ PCLIENT_ID ClientId - ); - -PHLIBAPI -NTSTATUS -NTAPI -KphOpenThreadProcess( - _In_ HANDLE ThreadHandle, - _In_ ACCESS_MASK DesiredAccess, - _Out_ PHANDLE ProcessHandle - ); - -PHLIBAPI -NTSTATUS -NTAPI -KphCaptureStackBackTraceThread( - _In_ HANDLE ThreadHandle, - _In_ ULONG FramesToSkip, - _In_ ULONG FramesToCapture, - _Out_writes_(FramesToCapture) PVOID *BackTrace, - _Out_opt_ PULONG CapturedFrames, - _Out_opt_ PULONG BackTraceHash - ); - -PHLIBAPI -NTSTATUS -NTAPI -KphQueryInformationThread( - _In_ HANDLE ThreadHandle, - _In_ KPH_THREAD_INFORMATION_CLASS ThreadInformationClass, - _Out_writes_bytes_(ThreadInformationLength) PVOID ThreadInformation, - _In_ ULONG ThreadInformationLength, - _Out_opt_ PULONG ReturnLength - ); - -PHLIBAPI -NTSTATUS -NTAPI -KphSetInformationThread( - _In_ HANDLE ThreadHandle, - _In_ KPH_THREAD_INFORMATION_CLASS ThreadInformationClass, - _In_reads_bytes_(ThreadInformationLength) PVOID ThreadInformation, - _In_ ULONG ThreadInformationLength - ); - -PHLIBAPI -NTSTATUS -NTAPI -KphEnumerateProcessHandles( - _In_ HANDLE ProcessHandle, - _Out_writes_bytes_(BufferLength) PVOID Buffer, - _In_opt_ ULONG BufferLength, - _Out_opt_ PULONG ReturnLength - ); - -PHLIBAPI -NTSTATUS -NTAPI -KphEnumerateProcessHandles2( - _In_ HANDLE ProcessHandle, - _Out_ PKPH_PROCESS_HANDLE_INFORMATION *Handles - ); - -PHLIBAPI -NTSTATUS -NTAPI -KphQueryInformationObject( - _In_ HANDLE ProcessHandle, - _In_ HANDLE Handle, - _In_ KPH_OBJECT_INFORMATION_CLASS ObjectInformationClass, - _Out_writes_bytes_(ObjectInformationLength) PVOID ObjectInformation, - _In_ ULONG ObjectInformationLength, - _Out_opt_ PULONG ReturnLength - ); - -PHLIBAPI -NTSTATUS -NTAPI -KphSetInformationObject( - _In_ HANDLE ProcessHandle, - _In_ HANDLE Handle, - _In_ KPH_OBJECT_INFORMATION_CLASS ObjectInformationClass, - _In_reads_bytes_(ObjectInformationLength) PVOID ObjectInformation, - _In_ ULONG ObjectInformationLength - ); - -PHLIBAPI -NTSTATUS -NTAPI -KphOpenDriver( - _Out_ PHANDLE DriverHandle, - _In_ ACCESS_MASK DesiredAccess, - _In_ POBJECT_ATTRIBUTES ObjectAttributes - ); - -PHLIBAPI -NTSTATUS -NTAPI -KphQueryInformationDriver( - _In_ HANDLE DriverHandle, - _In_ DRIVER_INFORMATION_CLASS DriverInformationClass, - _Out_writes_bytes_(DriverInformationLength) PVOID DriverInformation, - _In_ ULONG DriverInformationLength, - _Out_opt_ PULONG ReturnLength - ); - -// kphdata - -PHLIBAPI -NTSTATUS -NTAPI -KphInitializeDynamicPackage( - _Out_ PKPH_DYN_PACKAGE Package - ); - -#ifdef __cplusplus -} -#endif - -#endif +#ifndef _PH_KPHUSER_H +#define _PH_KPHUSER_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct _KPH_PARAMETERS +{ + KPH_SECURITY_LEVEL SecurityLevel; + BOOLEAN CreateDynamicConfiguration; +} KPH_PARAMETERS, *PKPH_PARAMETERS; + +PHLIBAPI +NTSTATUS +NTAPI +KphConnect( + _In_opt_ PWSTR DeviceName + ); + +PHLIBAPI +NTSTATUS +NTAPI +KphConnect2( + _In_opt_ PWSTR DeviceName, + _In_ PWSTR FileName + ); + +PHLIBAPI +NTSTATUS +NTAPI +KphConnect2Ex( + _In_opt_ PWSTR DeviceName, + _In_ PWSTR FileName, + _In_opt_ PKPH_PARAMETERS Parameters + ); + +PHLIBAPI +NTSTATUS +NTAPI +KphDisconnect( + VOID + ); + +PHLIBAPI +BOOLEAN +NTAPI +KphIsConnected( + VOID + ); + +PHLIBAPI +BOOLEAN +NTAPI +KphIsVerified( + VOID + ); + +PHLIBAPI +NTSTATUS +NTAPI +KphSetParameters( + _In_opt_ PWSTR DeviceName, + _In_ PKPH_PARAMETERS Parameters + ); + +PHLIBAPI +NTSTATUS +NTAPI +KphInstall( + _In_opt_ PWSTR DeviceName, + _In_ PWSTR FileName + ); + +PHLIBAPI +NTSTATUS +NTAPI +KphInstallEx( + _In_opt_ PWSTR DeviceName, + _In_ PWSTR FileName, + _In_opt_ PKPH_PARAMETERS Parameters + ); + +PHLIBAPI +NTSTATUS +NTAPI +KphUninstall( + _In_opt_ PWSTR DeviceName + ); + +PHLIBAPI +NTSTATUS +NTAPI +KphGetFeatures( + _Out_ PULONG Features + ); + +PHLIBAPI +NTSTATUS +NTAPI +KphVerifyClient( + _In_reads_bytes_(SignatureSize) PUCHAR Signature, + _In_ ULONG SignatureSize + ); + +PHLIBAPI +NTSTATUS +NTAPI +KphOpenProcess( + _Out_ PHANDLE ProcessHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ PCLIENT_ID ClientId + ); + +PHLIBAPI +NTSTATUS +NTAPI +KphOpenProcessToken( + _In_ HANDLE ProcessHandle, + _In_ ACCESS_MASK DesiredAccess, + _Out_ PHANDLE TokenHandle + ); + +PHLIBAPI +NTSTATUS +NTAPI +KphOpenProcessJob( + _In_ HANDLE ProcessHandle, + _In_ ACCESS_MASK DesiredAccess, + _Out_ PHANDLE JobHandle + ); + +PHLIBAPI +NTSTATUS +NTAPI +KphTerminateProcess( + _In_ HANDLE ProcessHandle, + _In_ NTSTATUS ExitStatus + ); + +PHLIBAPI +NTSTATUS +NTAPI +KphReadVirtualMemoryUnsafe( + _In_opt_ HANDLE ProcessHandle, + _In_ PVOID BaseAddress, + _Out_writes_bytes_(BufferSize) PVOID Buffer, + _In_ SIZE_T BufferSize, + _Out_opt_ PSIZE_T NumberOfBytesRead + ); + +PHLIBAPI +NTSTATUS +NTAPI +KphQueryInformationProcess( + _In_ HANDLE ProcessHandle, + _In_ KPH_PROCESS_INFORMATION_CLASS ProcessInformationClass, + _Out_writes_bytes_(ProcessInformationLength) PVOID ProcessInformation, + _In_ ULONG ProcessInformationLength, + _Out_opt_ PULONG ReturnLength + ); + +PHLIBAPI +NTSTATUS +NTAPI +KphSetInformationProcess( + _In_ HANDLE ProcessHandle, + _In_ KPH_PROCESS_INFORMATION_CLASS ProcessInformationClass, + _In_reads_bytes_(ProcessInformationLength) PVOID ProcessInformation, + _In_ ULONG ProcessInformationLength + ); + +PHLIBAPI +NTSTATUS +NTAPI +KphOpenThread( + _Out_ PHANDLE ThreadHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ PCLIENT_ID ClientId + ); + +PHLIBAPI +NTSTATUS +NTAPI +KphOpenThreadProcess( + _In_ HANDLE ThreadHandle, + _In_ ACCESS_MASK DesiredAccess, + _Out_ PHANDLE ProcessHandle + ); + +PHLIBAPI +NTSTATUS +NTAPI +KphCaptureStackBackTraceThread( + _In_ HANDLE ThreadHandle, + _In_ ULONG FramesToSkip, + _In_ ULONG FramesToCapture, + _Out_writes_(FramesToCapture) PVOID *BackTrace, + _Out_opt_ PULONG CapturedFrames, + _Out_opt_ PULONG BackTraceHash + ); + +PHLIBAPI +NTSTATUS +NTAPI +KphQueryInformationThread( + _In_ HANDLE ThreadHandle, + _In_ KPH_THREAD_INFORMATION_CLASS ThreadInformationClass, + _Out_writes_bytes_(ThreadInformationLength) PVOID ThreadInformation, + _In_ ULONG ThreadInformationLength, + _Out_opt_ PULONG ReturnLength + ); + +PHLIBAPI +NTSTATUS +NTAPI +KphSetInformationThread( + _In_ HANDLE ThreadHandle, + _In_ KPH_THREAD_INFORMATION_CLASS ThreadInformationClass, + _In_reads_bytes_(ThreadInformationLength) PVOID ThreadInformation, + _In_ ULONG ThreadInformationLength + ); + +PHLIBAPI +NTSTATUS +NTAPI +KphEnumerateProcessHandles( + _In_ HANDLE ProcessHandle, + _Out_writes_bytes_(BufferLength) PVOID Buffer, + _In_opt_ ULONG BufferLength, + _Out_opt_ PULONG ReturnLength + ); + +PHLIBAPI +NTSTATUS +NTAPI +KphEnumerateProcessHandles2( + _In_ HANDLE ProcessHandle, + _Out_ PKPH_PROCESS_HANDLE_INFORMATION *Handles + ); + +PHLIBAPI +NTSTATUS +NTAPI +KphQueryInformationObject( + _In_ HANDLE ProcessHandle, + _In_ HANDLE Handle, + _In_ KPH_OBJECT_INFORMATION_CLASS ObjectInformationClass, + _Out_writes_bytes_(ObjectInformationLength) PVOID ObjectInformation, + _In_ ULONG ObjectInformationLength, + _Out_opt_ PULONG ReturnLength + ); + +PHLIBAPI +NTSTATUS +NTAPI +KphSetInformationObject( + _In_ HANDLE ProcessHandle, + _In_ HANDLE Handle, + _In_ KPH_OBJECT_INFORMATION_CLASS ObjectInformationClass, + _In_reads_bytes_(ObjectInformationLength) PVOID ObjectInformation, + _In_ ULONG ObjectInformationLength + ); + +PHLIBAPI +NTSTATUS +NTAPI +KphOpenDriver( + _Out_ PHANDLE DriverHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes + ); + +PHLIBAPI +NTSTATUS +NTAPI +KphQueryInformationDriver( + _In_ HANDLE DriverHandle, + _In_ DRIVER_INFORMATION_CLASS DriverInformationClass, + _Out_writes_bytes_(DriverInformationLength) PVOID DriverInformation, + _In_ ULONG DriverInformationLength, + _Out_opt_ PULONG ReturnLength + ); + +// kphdata + +PHLIBAPI +NTSTATUS +NTAPI +KphInitializeDynamicPackage( + _Out_ PKPH_DYN_PACKAGE Package + ); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/phlib/include/ph.h b/phlib/include/ph.h index eba1c5032fd1..632ee40d2c57 100644 --- a/phlib/include/ph.h +++ b/phlib/include/ph.h @@ -1,11 +1,11 @@ -#ifndef _PH_PH_H -#define _PH_PH_H - -#pragma once - -#include -#include -#include -#include - -#endif +#ifndef _PH_PH_H +#define _PH_PH_H + +#pragma once + +#include +#include +#include +#include + +#endif diff --git a/phlib/include/phbase.h b/phlib/include/phbase.h index 9dd78bc0b8f7..15ad67e42a4d 100644 --- a/phlib/include/phbase.h +++ b/phlib/include/phbase.h @@ -1,37 +1,37 @@ -#ifndef _PH_PHBASE_H -#define _PH_PHBASE_H - -#pragma once - -#ifndef PHLIB_NO_DEFAULT_LIB -#pragma comment(lib, "ntdll.lib") -#pragma comment(lib, "comctl32.lib") -#pragma comment(lib, "version.lib") -#endif - -#ifndef UNICODE -#define UNICODE -#endif - -#ifndef _CRT_SECURE_NO_WARNINGS -#define _CRT_SECURE_NO_WARNINGS -#endif - -#if !defined(_PHLIB_) -#define PHLIBAPI __declspec(dllimport) -#else -#define PHLIBAPI -#endif - -#include -#include -#include -#include -#include -#include - -#include -#include -#include - +#ifndef _PH_PHBASE_H +#define _PH_PHBASE_H + +#pragma once + +#ifndef PHLIB_NO_DEFAULT_LIB +#pragma comment(lib, "ntdll.lib") +#pragma comment(lib, "comctl32.lib") +#pragma comment(lib, "version.lib") +#endif + +#ifndef UNICODE +#define UNICODE +#endif + +#ifndef _CRT_SECURE_NO_WARNINGS +#define _CRT_SECURE_NO_WARNINGS +#endif + +#if !defined(_PHLIB_) +#define PHLIBAPI __declspec(dllimport) +#else +#define PHLIBAPI +#endif + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + #endif \ No newline at end of file diff --git a/phlib/include/phintrnl.h b/phlib/include/phintrnl.h index 55f6629232b4..2fe39cfed1e2 100644 --- a/phlib/include/phintrnl.h +++ b/phlib/include/phintrnl.h @@ -1,49 +1,49 @@ -#ifndef _PH_PHINTRNL_H -#define _PH_PHINTRNL_H - -typedef struct _PHLIB_STATISTICS_BLOCK -{ - // basesup - ULONG BaseThreadsCreated; - ULONG BaseThreadsCreateFailed; - ULONG BaseStringBuildersCreated; - ULONG BaseStringBuildersResized; - - // ref - ULONG RefObjectsCreated; - ULONG RefObjectsDestroyed; - ULONG RefObjectsAllocated; - ULONG RefObjectsFreed; - ULONG RefObjectsAllocatedFromSmallFreeList; - ULONG RefObjectsFreedToSmallFreeList; - ULONG RefObjectsAllocatedFromTypeFreeList; - ULONG RefObjectsFreedToTypeFreeList; - ULONG RefObjectsDeleteDeferred; - ULONG RefAutoPoolsCreated; - ULONG RefAutoPoolsDestroyed; - ULONG RefAutoPoolsDynamicAllocated; - ULONG RefAutoPoolsDynamicResized; - - // queuedlock - ULONG QlBlockSpins; - ULONG QlBlockWaits; - ULONG QlAcquireExclusiveBlocks; - ULONG QlAcquireSharedBlocks; - - // workqueue - ULONG WqWorkQueueThreadsCreated; - ULONG WqWorkQueueThreadsCreateFailed; - ULONG WqWorkItemsQueued; -} PHLIB_STATISTICS_BLOCK; - -#ifdef DEBUG -extern PHLIB_STATISTICS_BLOCK PhLibStatisticsBlock; -#endif - -#ifdef DEBUG -#define PHLIB_INC_STATISTIC(Name) (_InterlockedIncrement(&PhLibStatisticsBlock.Name)) -#else -#define PHLIB_INC_STATISTIC(Name) -#endif - -#endif +#ifndef _PH_PHINTRNL_H +#define _PH_PHINTRNL_H + +typedef struct _PHLIB_STATISTICS_BLOCK +{ + // basesup + ULONG BaseThreadsCreated; + ULONG BaseThreadsCreateFailed; + ULONG BaseStringBuildersCreated; + ULONG BaseStringBuildersResized; + + // ref + ULONG RefObjectsCreated; + ULONG RefObjectsDestroyed; + ULONG RefObjectsAllocated; + ULONG RefObjectsFreed; + ULONG RefObjectsAllocatedFromSmallFreeList; + ULONG RefObjectsFreedToSmallFreeList; + ULONG RefObjectsAllocatedFromTypeFreeList; + ULONG RefObjectsFreedToTypeFreeList; + ULONG RefObjectsDeleteDeferred; + ULONG RefAutoPoolsCreated; + ULONG RefAutoPoolsDestroyed; + ULONG RefAutoPoolsDynamicAllocated; + ULONG RefAutoPoolsDynamicResized; + + // queuedlock + ULONG QlBlockSpins; + ULONG QlBlockWaits; + ULONG QlAcquireExclusiveBlocks; + ULONG QlAcquireSharedBlocks; + + // workqueue + ULONG WqWorkQueueThreadsCreated; + ULONG WqWorkQueueThreadsCreateFailed; + ULONG WqWorkItemsQueued; +} PHLIB_STATISTICS_BLOCK; + +#ifdef DEBUG +extern PHLIB_STATISTICS_BLOCK PhLibStatisticsBlock; +#endif + +#ifdef DEBUG +#define PHLIB_INC_STATISTIC(Name) (_InterlockedIncrement(&PhLibStatisticsBlock.Name)) +#else +#define PHLIB_INC_STATISTIC(Name) +#endif + +#endif diff --git a/phlib/include/phnet.h b/phlib/include/phnet.h index 6c4dcbf8f95d..50394dfd0258 100644 --- a/phlib/include/phnet.h +++ b/phlib/include/phnet.h @@ -1,139 +1,139 @@ -#ifndef _PH_PHNET_H -#define _PH_PHNET_H - -#include -#include - -#define PH_IPV4_NETWORK_TYPE 0x1 -#define PH_IPV6_NETWORK_TYPE 0x2 -#define PH_NETWORK_TYPE_MASK 0x3 - -#define PH_TCP_PROTOCOL_TYPE 0x10 -#define PH_UDP_PROTOCOL_TYPE 0x20 -#define PH_PROTOCOL_TYPE_MASK 0x30 - -#define PH_NO_NETWORK_PROTOCOL 0x0 -#define PH_TCP4_NETWORK_PROTOCOL (PH_IPV4_NETWORK_TYPE | PH_TCP_PROTOCOL_TYPE) -#define PH_TCP6_NETWORK_PROTOCOL (PH_IPV6_NETWORK_TYPE | PH_TCP_PROTOCOL_TYPE) -#define PH_UDP4_NETWORK_PROTOCOL (PH_IPV4_NETWORK_TYPE | PH_UDP_PROTOCOL_TYPE) -#define PH_UDP6_NETWORK_PROTOCOL (PH_IPV6_NETWORK_TYPE | PH_UDP_PROTOCOL_TYPE) - -typedef struct _PH_IP_ADDRESS -{ - ULONG Type; - union - { - ULONG Ipv4; - struct in_addr InAddr; - UCHAR Ipv6[16]; - struct in6_addr In6Addr; - }; -} PH_IP_ADDRESS, *PPH_IP_ADDRESS; - -FORCEINLINE BOOLEAN PhEqualIpAddress( - _In_ PPH_IP_ADDRESS Address1, - _In_ PPH_IP_ADDRESS Address2 - ) -{ - if ((Address1->Type | Address2->Type) == 0) // don't check addresses if both are invalid - return TRUE; - if (Address1->Type != Address2->Type) - return FALSE; - - if (Address1->Type == PH_IPV4_NETWORK_TYPE) - { - return Address1->Ipv4 == Address2->Ipv4; - } - else - { -#ifdef _WIN64 - return - *(PULONG64)(Address1->Ipv6) == *(PULONG64)(Address2->Ipv6) && - *(PULONG64)(Address1->Ipv6 + 8) == *(PULONG64)(Address2->Ipv6 + 8); -#else - return - *(PULONG)(Address1->Ipv6) == *(PULONG)(Address2->Ipv6) && - *(PULONG)(Address1->Ipv6 + 4) == *(PULONG)(Address2->Ipv6 + 4) && - *(PULONG)(Address1->Ipv6 + 8) == *(PULONG)(Address2->Ipv6 + 8) && - *(PULONG)(Address1->Ipv6 + 12) == *(PULONG)(Address2->Ipv6 + 12); -#endif - } -} - -FORCEINLINE ULONG PhHashIpAddress( - _In_ PPH_IP_ADDRESS Address - ) -{ - ULONG hash = 0; - - if (Address->Type == 0) - return 0; - - hash = Address->Type | (Address->Type << 16); - - if (Address->Type == PH_IPV4_NETWORK_TYPE) - { - hash ^= Address->Ipv4; - } - else - { - hash += *(PULONG)(Address->Ipv6); - hash ^= *(PULONG)(Address->Ipv6 + 4); - hash += *(PULONG)(Address->Ipv6 + 8); - hash ^= *(PULONG)(Address->Ipv6 + 12); - } - - return hash; -} - -FORCEINLINE BOOLEAN PhIsNullIpAddress( - _In_ PPH_IP_ADDRESS Address - ) -{ - if (Address->Type == 0) - { - return TRUE; - } - else if (Address->Type == PH_IPV4_NETWORK_TYPE) - { - return Address->Ipv4 == 0; - } - else if (Address->Type == PH_IPV6_NETWORK_TYPE) - { -#ifdef _WIN64 - return (*(PULONG64)(Address->Ipv6) | *(PULONG64)(Address->Ipv6 + 8)) == 0; -#else - return (*(PULONG)(Address->Ipv6) | *(PULONG)(Address->Ipv6 + 4) | - *(PULONG)(Address->Ipv6 + 8) | *(PULONG)(Address->Ipv6 + 12)) == 0; -#endif - } - else - { - return TRUE; - } -} - -typedef struct _PH_IP_ENDPOINT -{ - PH_IP_ADDRESS Address; - ULONG Port; -} PH_IP_ENDPOINT, *PPH_IP_ENDPOINT; - -FORCEINLINE BOOLEAN PhEqualIpEndpoint( - _In_ PPH_IP_ENDPOINT Endpoint1, - _In_ PPH_IP_ENDPOINT Endpoint2 - ) -{ - return - PhEqualIpAddress(&Endpoint1->Address, &Endpoint2->Address) && - Endpoint1->Port == Endpoint2->Port; -} - -FORCEINLINE ULONG PhHashIpEndpoint( - _In_ PPH_IP_ENDPOINT Endpoint - ) -{ - return PhHashIpAddress(&Endpoint->Address) ^ Endpoint->Port; -} - -#endif +#ifndef _PH_PHNET_H +#define _PH_PHNET_H + +#include +#include + +#define PH_IPV4_NETWORK_TYPE 0x1 +#define PH_IPV6_NETWORK_TYPE 0x2 +#define PH_NETWORK_TYPE_MASK 0x3 + +#define PH_TCP_PROTOCOL_TYPE 0x10 +#define PH_UDP_PROTOCOL_TYPE 0x20 +#define PH_PROTOCOL_TYPE_MASK 0x30 + +#define PH_NO_NETWORK_PROTOCOL 0x0 +#define PH_TCP4_NETWORK_PROTOCOL (PH_IPV4_NETWORK_TYPE | PH_TCP_PROTOCOL_TYPE) +#define PH_TCP6_NETWORK_PROTOCOL (PH_IPV6_NETWORK_TYPE | PH_TCP_PROTOCOL_TYPE) +#define PH_UDP4_NETWORK_PROTOCOL (PH_IPV4_NETWORK_TYPE | PH_UDP_PROTOCOL_TYPE) +#define PH_UDP6_NETWORK_PROTOCOL (PH_IPV6_NETWORK_TYPE | PH_UDP_PROTOCOL_TYPE) + +typedef struct _PH_IP_ADDRESS +{ + ULONG Type; + union + { + ULONG Ipv4; + struct in_addr InAddr; + UCHAR Ipv6[16]; + struct in6_addr In6Addr; + }; +} PH_IP_ADDRESS, *PPH_IP_ADDRESS; + +FORCEINLINE BOOLEAN PhEqualIpAddress( + _In_ PPH_IP_ADDRESS Address1, + _In_ PPH_IP_ADDRESS Address2 + ) +{ + if ((Address1->Type | Address2->Type) == 0) // don't check addresses if both are invalid + return TRUE; + if (Address1->Type != Address2->Type) + return FALSE; + + if (Address1->Type == PH_IPV4_NETWORK_TYPE) + { + return Address1->Ipv4 == Address2->Ipv4; + } + else + { +#ifdef _WIN64 + return + *(PULONG64)(Address1->Ipv6) == *(PULONG64)(Address2->Ipv6) && + *(PULONG64)(Address1->Ipv6 + 8) == *(PULONG64)(Address2->Ipv6 + 8); +#else + return + *(PULONG)(Address1->Ipv6) == *(PULONG)(Address2->Ipv6) && + *(PULONG)(Address1->Ipv6 + 4) == *(PULONG)(Address2->Ipv6 + 4) && + *(PULONG)(Address1->Ipv6 + 8) == *(PULONG)(Address2->Ipv6 + 8) && + *(PULONG)(Address1->Ipv6 + 12) == *(PULONG)(Address2->Ipv6 + 12); +#endif + } +} + +FORCEINLINE ULONG PhHashIpAddress( + _In_ PPH_IP_ADDRESS Address + ) +{ + ULONG hash = 0; + + if (Address->Type == 0) + return 0; + + hash = Address->Type | (Address->Type << 16); + + if (Address->Type == PH_IPV4_NETWORK_TYPE) + { + hash ^= Address->Ipv4; + } + else + { + hash += *(PULONG)(Address->Ipv6); + hash ^= *(PULONG)(Address->Ipv6 + 4); + hash += *(PULONG)(Address->Ipv6 + 8); + hash ^= *(PULONG)(Address->Ipv6 + 12); + } + + return hash; +} + +FORCEINLINE BOOLEAN PhIsNullIpAddress( + _In_ PPH_IP_ADDRESS Address + ) +{ + if (Address->Type == 0) + { + return TRUE; + } + else if (Address->Type == PH_IPV4_NETWORK_TYPE) + { + return Address->Ipv4 == 0; + } + else if (Address->Type == PH_IPV6_NETWORK_TYPE) + { +#ifdef _WIN64 + return (*(PULONG64)(Address->Ipv6) | *(PULONG64)(Address->Ipv6 + 8)) == 0; +#else + return (*(PULONG)(Address->Ipv6) | *(PULONG)(Address->Ipv6 + 4) | + *(PULONG)(Address->Ipv6 + 8) | *(PULONG)(Address->Ipv6 + 12)) == 0; +#endif + } + else + { + return TRUE; + } +} + +typedef struct _PH_IP_ENDPOINT +{ + PH_IP_ADDRESS Address; + ULONG Port; +} PH_IP_ENDPOINT, *PPH_IP_ENDPOINT; + +FORCEINLINE BOOLEAN PhEqualIpEndpoint( + _In_ PPH_IP_ENDPOINT Endpoint1, + _In_ PPH_IP_ENDPOINT Endpoint2 + ) +{ + return + PhEqualIpAddress(&Endpoint1->Address, &Endpoint2->Address) && + Endpoint1->Port == Endpoint2->Port; +} + +FORCEINLINE ULONG PhHashIpEndpoint( + _In_ PPH_IP_ENDPOINT Endpoint + ) +{ + return PhHashIpAddress(&Endpoint->Address) ^ Endpoint->Port; +} + +#endif diff --git a/phlib/include/phsup.h b/phlib/include/phsup.h index 3985914d1f49..55e36cf5160f 100644 --- a/phlib/include/phsup.h +++ b/phlib/include/phsup.h @@ -1,546 +1,546 @@ -#ifndef _PH_PHSUP_H -#define _PH_PHSUP_H - -// This header file provides some useful definitions specific to phlib. - -#include -#include -#include -#include - -// Memory - -#define PTR_ADD_OFFSET(Pointer, Offset) ((PVOID)((ULONG_PTR)(Pointer) + (ULONG_PTR)(Offset))) -#define PTR_SUB_OFFSET(Pointer, Offset) ((PVOID)((ULONG_PTR)(Pointer) - (ULONG_PTR)(Offset))) -#define ALIGN_UP_BY(Address, Align) (((ULONG_PTR)(Address) + (Align) - 1) & ~((Align) - 1)) -#define ALIGN_UP_POINTER_BY(Pointer, Align) ((PVOID)ALIGN_UP_BY(Pointer, Align)) -#define ALIGN_UP(Address, Type) ALIGN_UP_BY(Address, sizeof(Type)) -#define ALIGN_UP_POINTER(Pointer, Type) ((PVOID)ALIGN_UP(Pointer, Type)) - -#define PAGE_SIZE 0x1000 - -#define PH_LARGE_BUFFER_SIZE (256 * 1024 * 1024) - -// Exceptions - -#define PhRaiseStatus(Status) RtlRaiseStatus(Status) - -#define SIMPLE_EXCEPTION_FILTER(Condition) \ - ((Condition) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) - -// Compiler - -#ifdef DEBUG -#define ASSUME_ASSERT(Expression) assert(Expression) -#define ASSUME_NO_DEFAULT assert(FALSE) -#else -#define ASSUME_ASSERT(Expression) __assume(Expression) -#define ASSUME_NO_DEFAULT __assume(FALSE) -#endif - -// Time - -#define PH_TICKS_PER_NS ((LONG64)1 * 10) -#define PH_TICKS_PER_MS (PH_TICKS_PER_NS * 1000) -#define PH_TICKS_PER_SEC (PH_TICKS_PER_MS * 1000) -#define PH_TICKS_PER_MIN (PH_TICKS_PER_SEC * 60) -#define PH_TICKS_PER_HOUR (PH_TICKS_PER_MIN * 60) -#define PH_TICKS_PER_DAY (PH_TICKS_PER_HOUR * 24) - -#define PH_TICKS_PARTIAL_MS(Ticks) (((ULONG64)(Ticks) / PH_TICKS_PER_MS) % 1000) -#define PH_TICKS_PARTIAL_SEC(Ticks) (((ULONG64)(Ticks) / PH_TICKS_PER_SEC) % 60) -#define PH_TICKS_PARTIAL_MIN(Ticks) (((ULONG64)(Ticks) / PH_TICKS_PER_MIN) % 60) -#define PH_TICKS_PARTIAL_HOURS(Ticks) (((ULONG64)(Ticks) / PH_TICKS_PER_HOUR) % 24) -#define PH_TICKS_PARTIAL_DAYS(Ticks) ((ULONG64)(Ticks) / PH_TICKS_PER_DAY) - -#define PH_TIMEOUT_MS PH_TICKS_PER_MS -#define PH_TIMEOUT_SEC PH_TICKS_PER_SEC - -// Annotations - -/** - * Indicates that a function assumes the specified number of references are available for the - * object. - * - * \remarks Usually functions reference objects if they store them for later usage; this annotation - * specifies that the caller must supply these extra references itself. In effect these references - * are "transferred" to the function and must not be used. E.g. if you create an object and - * immediately call a function with _Assume_refs_(1), you may no longer use the object since that - * one reference you held is no longer yours. - */ -#define _Assume_refs_(count) - -#define _Callback_ - -/** - * Indicates that a function may raise a software exception. - * - * \remarks Do not use this annotation for temporary usages of exceptions, e.g. unimplemented - * functions. - */ -#define _May_raise_ - -/** - * Indicates that a function requires the specified value to be aligned at the specified number of - * bytes. - */ -#define _Needs_align_(align) - -// Casts - -// Zero extension and sign extension macros -#define C_1uTo2(x) ((unsigned short)(unsigned char)(x)) -#define C_1sTo2(x) ((unsigned short)(signed char)(x)) -#define C_1uTo4(x) ((unsigned int)(unsigned char)(x)) -#define C_1sTo4(x) ((unsigned int)(signed char)(x)) -#define C_2uTo4(x) ((unsigned int)(unsigned short)(x)) -#define C_2sTo4(x) ((unsigned int)(signed short)(x)) -#define C_4uTo8(x) ((unsigned __int64)(unsigned int)(x)) -#define C_4sTo8(x) ((unsigned __int64)(signed int)(x)) - -// Sorting - -typedef enum _PH_SORT_ORDER -{ - NoSortOrder = 0, - AscendingSortOrder, - DescendingSortOrder -} PH_SORT_ORDER, *PPH_SORT_ORDER; - -FORCEINLINE LONG PhModifySort( - _In_ LONG Result, - _In_ PH_SORT_ORDER Order - ) -{ - if (Order == AscendingSortOrder) - return Result; - else if (Order == DescendingSortOrder) - return -Result; - else - return Result; -} - -#define PH_BUILTIN_COMPARE(value1, value2) \ - if (value1 > value2) \ - return 1; \ - else if (value1 < value2) \ - return -1; \ - \ - return 0 - -FORCEINLINE int charcmp( - _In_ signed char value1, - _In_ signed char value2 - ) -{ - return C_1sTo4(value1 - value2); -} - -FORCEINLINE int ucharcmp( - _In_ unsigned char value1, - _In_ unsigned char value2 - ) -{ - PH_BUILTIN_COMPARE(value1, value2); -} - -FORCEINLINE int shortcmp( - _In_ signed short value1, - _In_ signed short value2 - ) -{ - return C_2sTo4(value1 - value2); -} - -FORCEINLINE int ushortcmp( - _In_ unsigned short value1, - _In_ unsigned short value2 - ) -{ - PH_BUILTIN_COMPARE(value1, value2); -} - -FORCEINLINE int intcmp( - _In_ int value1, - _In_ int value2 - ) -{ - return value1 - value2; -} - -FORCEINLINE int uintcmp( - _In_ unsigned int value1, - _In_ unsigned int value2 - ) -{ - PH_BUILTIN_COMPARE(value1, value2); -} - -FORCEINLINE int int64cmp( - _In_ __int64 value1, - _In_ __int64 value2 - ) -{ - PH_BUILTIN_COMPARE(value1, value2); -} - -FORCEINLINE int uint64cmp( - _In_ unsigned __int64 value1, - _In_ unsigned __int64 value2 - ) -{ - PH_BUILTIN_COMPARE(value1, value2); -} - -FORCEINLINE int intptrcmp( - _In_ LONG_PTR value1, - _In_ LONG_PTR value2 - ) -{ - PH_BUILTIN_COMPARE(value1, value2); -} - -FORCEINLINE int uintptrcmp( - _In_ ULONG_PTR value1, - _In_ ULONG_PTR value2 - ) -{ - PH_BUILTIN_COMPARE(value1, value2); -} - -FORCEINLINE int singlecmp( - _In_ float value1, - _In_ float value2 - ) -{ - PH_BUILTIN_COMPARE(value1, value2); -} - -FORCEINLINE int doublecmp( - _In_ double value1, - _In_ double value2 - ) -{ - PH_BUILTIN_COMPARE(value1, value2); -} - -FORCEINLINE int wcsicmp2( - _In_opt_ PWSTR Value1, - _In_opt_ PWSTR Value2 - ) -{ - if (Value1 && Value2) - return _wcsicmp(Value1, Value2); - else if (!Value1) - return !Value2 ? 0 : -1; - else - return 1; -} - -typedef int (__cdecl *PC_COMPARE_FUNCTION)(void *, const void *, const void *); - -// Synchronization - -#ifndef _WIN64 - -#ifndef _InterlockedCompareExchangePointer -void *_InterlockedCompareExchangePointer( - void *volatile *Destination, - void *Exchange, - void *Comparand - ); -#endif - -#if (_MSC_VER < 1900) -#ifndef _InterlockedExchangePointer -FORCEINLINE void *_InterlockedExchangePointer( - void *volatile *Destination, - void *Exchange - ) -{ - return (PVOID)_InterlockedExchange( - (PLONG_PTR)Destination, - (LONG_PTR)Exchange - ); -} -#endif -#endif - -#endif - -FORCEINLINE LONG_PTR _InterlockedExchangeAddPointer( - _Inout_ _Interlocked_operand_ LONG_PTR volatile *Addend, - _In_ LONG_PTR Value - ) -{ -#ifdef _WIN64 - return (LONG_PTR)_InterlockedExchangeAdd64((PLONG64)Addend, (LONG64)Value); -#else - return (LONG_PTR)_InterlockedExchangeAdd((PLONG)Addend, (LONG)Value); -#endif -} - -FORCEINLINE LONG_PTR _InterlockedIncrementPointer( - _Inout_ _Interlocked_operand_ LONG_PTR volatile *Addend - ) -{ -#ifdef _WIN64 - return (LONG_PTR)_InterlockedIncrement64((PLONG64)Addend); -#else - return (LONG_PTR)_InterlockedIncrement((PLONG)Addend); -#endif -} - -FORCEINLINE LONG_PTR _InterlockedDecrementPointer( - _Inout_ _Interlocked_operand_ LONG_PTR volatile *Addend - ) -{ -#ifdef _WIN64 - return (LONG_PTR)_InterlockedDecrement64((PLONG64)Addend); -#else - return (LONG_PTR)_InterlockedDecrement((PLONG)Addend); -#endif -} - -FORCEINLINE BOOLEAN _InterlockedBitTestAndResetPointer( - _Inout_ _Interlocked_operand_ LONG_PTR volatile *Base, - _In_ LONG_PTR Bit - ) -{ -#ifdef _WIN64 - return _interlockedbittestandreset64((PLONG64)Base, (LONG64)Bit); -#else - return _interlockedbittestandreset((PLONG)Base, (LONG)Bit); -#endif -} - -FORCEINLINE BOOLEAN _InterlockedBitTestAndSetPointer( - _Inout_ _Interlocked_operand_ LONG_PTR volatile *Base, - _In_ LONG_PTR Bit - ) -{ -#ifdef _WIN64 - return _interlockedbittestandset64((PLONG64)Base, (LONG64)Bit); -#else - return _interlockedbittestandset((PLONG)Base, (LONG)Bit); -#endif -} - -FORCEINLINE BOOLEAN _InterlockedIncrementNoZero( - _Inout_ _Interlocked_operand_ LONG volatile *Addend - ) -{ - LONG value; - LONG newValue; - - value = *Addend; - - while (TRUE) - { - if (value == 0) - return FALSE; - - if ((newValue = _InterlockedCompareExchange( - Addend, - value + 1, - value - )) == value) - { - return TRUE; - } - - value = newValue; - } -} - -FORCEINLINE BOOLEAN _InterlockedIncrementPositive( - _Inout_ _Interlocked_operand_ LONG volatile *Addend - ) -{ - LONG value; - LONG newValue; - - value = *Addend; - - while (TRUE) - { - if (value <= 0) - return FALSE; - - if ((newValue = _InterlockedCompareExchange( - Addend, - value + 1, - value - )) == value) - { - return TRUE; - } - - value = newValue; - } -} - -// Strings - -#define PH_INT32_STR_LEN 12 -#define PH_INT32_STR_LEN_1 (PH_INT32_STR_LEN + 1) - -#define PH_INT64_STR_LEN 50 -#define PH_INT64_STR_LEN_1 (PH_INT64_STR_LEN + 1) - -#define PH_PTR_STR_LEN 24 -#define PH_PTR_STR_LEN_1 (PH_PTR_STR_LEN + 1) - -FORCEINLINE VOID PhPrintInt32( - _Out_writes_(PH_INT32_STR_LEN_1) PWSTR Destination, - _In_ LONG Int32 - ) -{ - _ltow(Int32, Destination, 10); -} - -FORCEINLINE VOID PhPrintUInt32( - _Out_writes_(PH_INT32_STR_LEN_1) PWSTR Destination, - _In_ ULONG UInt32 - ) -{ - _ultow(UInt32, Destination, 10); -} - -FORCEINLINE VOID PhPrintInt64( - _Out_writes_(PH_INT64_STR_LEN_1) PWSTR Destination, - _In_ LONG64 Int64 - ) -{ - _i64tow(Int64, Destination, 10); -} - -FORCEINLINE VOID PhPrintUInt64( - _Out_writes_(PH_INT64_STR_LEN_1) PWSTR Destination, - _In_ ULONG64 UInt64 - ) -{ - _ui64tow(UInt64, Destination, 10); -} - -FORCEINLINE VOID PhPrintPointer( - _Out_writes_(PH_PTR_STR_LEN_1) PWSTR Destination, - _In_ PVOID Pointer - ) -{ - Destination[0] = '0'; - Destination[1] = 'x'; -#ifdef _WIN64 - _ui64tow((ULONG64)Pointer, &Destination[2], 16); -#else - _ultow((ULONG)Pointer, &Destination[2], 16); -#endif -} - -// Misc. - -FORCEINLINE ULONG PhCountBits( - _In_ ULONG Value - ) -{ - ULONG count = 0; - - while (Value) - { - count++; - Value &= Value - 1; - } - - return count; -} - -FORCEINLINE ULONG PhRoundNumber( - _In_ ULONG Value, - _In_ ULONG Granularity - ) -{ - return (Value + Granularity / 2) / Granularity * Granularity; -} - -FORCEINLINE ULONG PhMultiplyDivide( - _In_ ULONG Number, - _In_ ULONG Numerator, - _In_ ULONG Denominator - ) -{ - return (ULONG)(((ULONG64)Number * (ULONG64)Numerator + Denominator / 2) / (ULONG64)Denominator); -} - -FORCEINLINE LONG PhMultiplyDivideSigned( - _In_ LONG Number, - _In_ ULONG Numerator, - _In_ ULONG Denominator - ) -{ - if (Number >= 0) - return PhMultiplyDivide(Number, Numerator, Denominator); - else - return -(LONG)PhMultiplyDivide(-Number, Numerator, Denominator); -} - -FORCEINLINE VOID PhProbeAddress( - _In_ PVOID UserAddress, - _In_ SIZE_T UserLength, - _In_ PVOID BufferAddress, - _In_ SIZE_T BufferLength, - _In_ ULONG Alignment - ) -{ - if (UserLength != 0) - { - if (((ULONG_PTR)UserAddress & (Alignment - 1)) != 0) - PhRaiseStatus(STATUS_DATATYPE_MISALIGNMENT); - - if ( - ((ULONG_PTR)UserAddress + UserLength < (ULONG_PTR)UserAddress) || - ((ULONG_PTR)UserAddress < (ULONG_PTR)BufferAddress) || - ((ULONG_PTR)UserAddress + UserLength > (ULONG_PTR)BufferAddress + BufferLength) - ) - PhRaiseStatus(STATUS_ACCESS_VIOLATION); - } -} - -FORCEINLINE PLARGE_INTEGER PhTimeoutFromMilliseconds( - _Out_ PLARGE_INTEGER Timeout, - _In_ ULONG Milliseconds - ) -{ - if (Milliseconds == INFINITE) - return NULL; - - Timeout->QuadPart = -(LONGLONG)UInt32x32To64(Milliseconds, PH_TIMEOUT_MS); - - return Timeout; -} - -FORCEINLINE NTSTATUS PhGetLastWin32ErrorAsNtStatus() -{ - ULONG win32Result; - - // This is needed because NTSTATUS_FROM_WIN32 uses the argument multiple times. - win32Result = GetLastError(); - - return NTSTATUS_FROM_WIN32(win32Result); -} - -FORCEINLINE PVOID PhGetModuleProcAddress( - _In_ PWSTR ModuleName, - _In_ PSTR ProcName - ) -{ - HMODULE module; - - module = GetModuleHandle(ModuleName); - - if (module) - return GetProcAddress(module, ProcName); - else - return NULL; -} - -#endif +#ifndef _PH_PHSUP_H +#define _PH_PHSUP_H + +// This header file provides some useful definitions specific to phlib. + +#include +#include +#include +#include + +// Memory + +#define PTR_ADD_OFFSET(Pointer, Offset) ((PVOID)((ULONG_PTR)(Pointer) + (ULONG_PTR)(Offset))) +#define PTR_SUB_OFFSET(Pointer, Offset) ((PVOID)((ULONG_PTR)(Pointer) - (ULONG_PTR)(Offset))) +#define ALIGN_UP_BY(Address, Align) (((ULONG_PTR)(Address) + (Align) - 1) & ~((Align) - 1)) +#define ALIGN_UP_POINTER_BY(Pointer, Align) ((PVOID)ALIGN_UP_BY(Pointer, Align)) +#define ALIGN_UP(Address, Type) ALIGN_UP_BY(Address, sizeof(Type)) +#define ALIGN_UP_POINTER(Pointer, Type) ((PVOID)ALIGN_UP(Pointer, Type)) + +#define PAGE_SIZE 0x1000 + +#define PH_LARGE_BUFFER_SIZE (256 * 1024 * 1024) + +// Exceptions + +#define PhRaiseStatus(Status) RtlRaiseStatus(Status) + +#define SIMPLE_EXCEPTION_FILTER(Condition) \ + ((Condition) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) + +// Compiler + +#ifdef DEBUG +#define ASSUME_ASSERT(Expression) assert(Expression) +#define ASSUME_NO_DEFAULT assert(FALSE) +#else +#define ASSUME_ASSERT(Expression) __assume(Expression) +#define ASSUME_NO_DEFAULT __assume(FALSE) +#endif + +// Time + +#define PH_TICKS_PER_NS ((LONG64)1 * 10) +#define PH_TICKS_PER_MS (PH_TICKS_PER_NS * 1000) +#define PH_TICKS_PER_SEC (PH_TICKS_PER_MS * 1000) +#define PH_TICKS_PER_MIN (PH_TICKS_PER_SEC * 60) +#define PH_TICKS_PER_HOUR (PH_TICKS_PER_MIN * 60) +#define PH_TICKS_PER_DAY (PH_TICKS_PER_HOUR * 24) + +#define PH_TICKS_PARTIAL_MS(Ticks) (((ULONG64)(Ticks) / PH_TICKS_PER_MS) % 1000) +#define PH_TICKS_PARTIAL_SEC(Ticks) (((ULONG64)(Ticks) / PH_TICKS_PER_SEC) % 60) +#define PH_TICKS_PARTIAL_MIN(Ticks) (((ULONG64)(Ticks) / PH_TICKS_PER_MIN) % 60) +#define PH_TICKS_PARTIAL_HOURS(Ticks) (((ULONG64)(Ticks) / PH_TICKS_PER_HOUR) % 24) +#define PH_TICKS_PARTIAL_DAYS(Ticks) ((ULONG64)(Ticks) / PH_TICKS_PER_DAY) + +#define PH_TIMEOUT_MS PH_TICKS_PER_MS +#define PH_TIMEOUT_SEC PH_TICKS_PER_SEC + +// Annotations + +/** + * Indicates that a function assumes the specified number of references are available for the + * object. + * + * \remarks Usually functions reference objects if they store them for later usage; this annotation + * specifies that the caller must supply these extra references itself. In effect these references + * are "transferred" to the function and must not be used. E.g. if you create an object and + * immediately call a function with _Assume_refs_(1), you may no longer use the object since that + * one reference you held is no longer yours. + */ +#define _Assume_refs_(count) + +#define _Callback_ + +/** + * Indicates that a function may raise a software exception. + * + * \remarks Do not use this annotation for temporary usages of exceptions, e.g. unimplemented + * functions. + */ +#define _May_raise_ + +/** + * Indicates that a function requires the specified value to be aligned at the specified number of + * bytes. + */ +#define _Needs_align_(align) + +// Casts + +// Zero extension and sign extension macros +#define C_1uTo2(x) ((unsigned short)(unsigned char)(x)) +#define C_1sTo2(x) ((unsigned short)(signed char)(x)) +#define C_1uTo4(x) ((unsigned int)(unsigned char)(x)) +#define C_1sTo4(x) ((unsigned int)(signed char)(x)) +#define C_2uTo4(x) ((unsigned int)(unsigned short)(x)) +#define C_2sTo4(x) ((unsigned int)(signed short)(x)) +#define C_4uTo8(x) ((unsigned __int64)(unsigned int)(x)) +#define C_4sTo8(x) ((unsigned __int64)(signed int)(x)) + +// Sorting + +typedef enum _PH_SORT_ORDER +{ + NoSortOrder = 0, + AscendingSortOrder, + DescendingSortOrder +} PH_SORT_ORDER, *PPH_SORT_ORDER; + +FORCEINLINE LONG PhModifySort( + _In_ LONG Result, + _In_ PH_SORT_ORDER Order + ) +{ + if (Order == AscendingSortOrder) + return Result; + else if (Order == DescendingSortOrder) + return -Result; + else + return Result; +} + +#define PH_BUILTIN_COMPARE(value1, value2) \ + if (value1 > value2) \ + return 1; \ + else if (value1 < value2) \ + return -1; \ + \ + return 0 + +FORCEINLINE int charcmp( + _In_ signed char value1, + _In_ signed char value2 + ) +{ + return C_1sTo4(value1 - value2); +} + +FORCEINLINE int ucharcmp( + _In_ unsigned char value1, + _In_ unsigned char value2 + ) +{ + PH_BUILTIN_COMPARE(value1, value2); +} + +FORCEINLINE int shortcmp( + _In_ signed short value1, + _In_ signed short value2 + ) +{ + return C_2sTo4(value1 - value2); +} + +FORCEINLINE int ushortcmp( + _In_ unsigned short value1, + _In_ unsigned short value2 + ) +{ + PH_BUILTIN_COMPARE(value1, value2); +} + +FORCEINLINE int intcmp( + _In_ int value1, + _In_ int value2 + ) +{ + return value1 - value2; +} + +FORCEINLINE int uintcmp( + _In_ unsigned int value1, + _In_ unsigned int value2 + ) +{ + PH_BUILTIN_COMPARE(value1, value2); +} + +FORCEINLINE int int64cmp( + _In_ __int64 value1, + _In_ __int64 value2 + ) +{ + PH_BUILTIN_COMPARE(value1, value2); +} + +FORCEINLINE int uint64cmp( + _In_ unsigned __int64 value1, + _In_ unsigned __int64 value2 + ) +{ + PH_BUILTIN_COMPARE(value1, value2); +} + +FORCEINLINE int intptrcmp( + _In_ LONG_PTR value1, + _In_ LONG_PTR value2 + ) +{ + PH_BUILTIN_COMPARE(value1, value2); +} + +FORCEINLINE int uintptrcmp( + _In_ ULONG_PTR value1, + _In_ ULONG_PTR value2 + ) +{ + PH_BUILTIN_COMPARE(value1, value2); +} + +FORCEINLINE int singlecmp( + _In_ float value1, + _In_ float value2 + ) +{ + PH_BUILTIN_COMPARE(value1, value2); +} + +FORCEINLINE int doublecmp( + _In_ double value1, + _In_ double value2 + ) +{ + PH_BUILTIN_COMPARE(value1, value2); +} + +FORCEINLINE int wcsicmp2( + _In_opt_ PWSTR Value1, + _In_opt_ PWSTR Value2 + ) +{ + if (Value1 && Value2) + return _wcsicmp(Value1, Value2); + else if (!Value1) + return !Value2 ? 0 : -1; + else + return 1; +} + +typedef int (__cdecl *PC_COMPARE_FUNCTION)(void *, const void *, const void *); + +// Synchronization + +#ifndef _WIN64 + +#ifndef _InterlockedCompareExchangePointer +void *_InterlockedCompareExchangePointer( + void *volatile *Destination, + void *Exchange, + void *Comparand + ); +#endif + +#if (_MSC_VER < 1900) +#ifndef _InterlockedExchangePointer +FORCEINLINE void *_InterlockedExchangePointer( + void *volatile *Destination, + void *Exchange + ) +{ + return (PVOID)_InterlockedExchange( + (PLONG_PTR)Destination, + (LONG_PTR)Exchange + ); +} +#endif +#endif + +#endif + +FORCEINLINE LONG_PTR _InterlockedExchangeAddPointer( + _Inout_ _Interlocked_operand_ LONG_PTR volatile *Addend, + _In_ LONG_PTR Value + ) +{ +#ifdef _WIN64 + return (LONG_PTR)_InterlockedExchangeAdd64((PLONG64)Addend, (LONG64)Value); +#else + return (LONG_PTR)_InterlockedExchangeAdd((PLONG)Addend, (LONG)Value); +#endif +} + +FORCEINLINE LONG_PTR _InterlockedIncrementPointer( + _Inout_ _Interlocked_operand_ LONG_PTR volatile *Addend + ) +{ +#ifdef _WIN64 + return (LONG_PTR)_InterlockedIncrement64((PLONG64)Addend); +#else + return (LONG_PTR)_InterlockedIncrement((PLONG)Addend); +#endif +} + +FORCEINLINE LONG_PTR _InterlockedDecrementPointer( + _Inout_ _Interlocked_operand_ LONG_PTR volatile *Addend + ) +{ +#ifdef _WIN64 + return (LONG_PTR)_InterlockedDecrement64((PLONG64)Addend); +#else + return (LONG_PTR)_InterlockedDecrement((PLONG)Addend); +#endif +} + +FORCEINLINE BOOLEAN _InterlockedBitTestAndResetPointer( + _Inout_ _Interlocked_operand_ LONG_PTR volatile *Base, + _In_ LONG_PTR Bit + ) +{ +#ifdef _WIN64 + return _interlockedbittestandreset64((PLONG64)Base, (LONG64)Bit); +#else + return _interlockedbittestandreset((PLONG)Base, (LONG)Bit); +#endif +} + +FORCEINLINE BOOLEAN _InterlockedBitTestAndSetPointer( + _Inout_ _Interlocked_operand_ LONG_PTR volatile *Base, + _In_ LONG_PTR Bit + ) +{ +#ifdef _WIN64 + return _interlockedbittestandset64((PLONG64)Base, (LONG64)Bit); +#else + return _interlockedbittestandset((PLONG)Base, (LONG)Bit); +#endif +} + +FORCEINLINE BOOLEAN _InterlockedIncrementNoZero( + _Inout_ _Interlocked_operand_ LONG volatile *Addend + ) +{ + LONG value; + LONG newValue; + + value = *Addend; + + while (TRUE) + { + if (value == 0) + return FALSE; + + if ((newValue = _InterlockedCompareExchange( + Addend, + value + 1, + value + )) == value) + { + return TRUE; + } + + value = newValue; + } +} + +FORCEINLINE BOOLEAN _InterlockedIncrementPositive( + _Inout_ _Interlocked_operand_ LONG volatile *Addend + ) +{ + LONG value; + LONG newValue; + + value = *Addend; + + while (TRUE) + { + if (value <= 0) + return FALSE; + + if ((newValue = _InterlockedCompareExchange( + Addend, + value + 1, + value + )) == value) + { + return TRUE; + } + + value = newValue; + } +} + +// Strings + +#define PH_INT32_STR_LEN 12 +#define PH_INT32_STR_LEN_1 (PH_INT32_STR_LEN + 1) + +#define PH_INT64_STR_LEN 50 +#define PH_INT64_STR_LEN_1 (PH_INT64_STR_LEN + 1) + +#define PH_PTR_STR_LEN 24 +#define PH_PTR_STR_LEN_1 (PH_PTR_STR_LEN + 1) + +FORCEINLINE VOID PhPrintInt32( + _Out_writes_(PH_INT32_STR_LEN_1) PWSTR Destination, + _In_ LONG Int32 + ) +{ + _ltow(Int32, Destination, 10); +} + +FORCEINLINE VOID PhPrintUInt32( + _Out_writes_(PH_INT32_STR_LEN_1) PWSTR Destination, + _In_ ULONG UInt32 + ) +{ + _ultow(UInt32, Destination, 10); +} + +FORCEINLINE VOID PhPrintInt64( + _Out_writes_(PH_INT64_STR_LEN_1) PWSTR Destination, + _In_ LONG64 Int64 + ) +{ + _i64tow(Int64, Destination, 10); +} + +FORCEINLINE VOID PhPrintUInt64( + _Out_writes_(PH_INT64_STR_LEN_1) PWSTR Destination, + _In_ ULONG64 UInt64 + ) +{ + _ui64tow(UInt64, Destination, 10); +} + +FORCEINLINE VOID PhPrintPointer( + _Out_writes_(PH_PTR_STR_LEN_1) PWSTR Destination, + _In_ PVOID Pointer + ) +{ + Destination[0] = '0'; + Destination[1] = 'x'; +#ifdef _WIN64 + _ui64tow((ULONG64)Pointer, &Destination[2], 16); +#else + _ultow((ULONG)Pointer, &Destination[2], 16); +#endif +} + +// Misc. + +FORCEINLINE ULONG PhCountBits( + _In_ ULONG Value + ) +{ + ULONG count = 0; + + while (Value) + { + count++; + Value &= Value - 1; + } + + return count; +} + +FORCEINLINE ULONG PhRoundNumber( + _In_ ULONG Value, + _In_ ULONG Granularity + ) +{ + return (Value + Granularity / 2) / Granularity * Granularity; +} + +FORCEINLINE ULONG PhMultiplyDivide( + _In_ ULONG Number, + _In_ ULONG Numerator, + _In_ ULONG Denominator + ) +{ + return (ULONG)(((ULONG64)Number * (ULONG64)Numerator + Denominator / 2) / (ULONG64)Denominator); +} + +FORCEINLINE LONG PhMultiplyDivideSigned( + _In_ LONG Number, + _In_ ULONG Numerator, + _In_ ULONG Denominator + ) +{ + if (Number >= 0) + return PhMultiplyDivide(Number, Numerator, Denominator); + else + return -(LONG)PhMultiplyDivide(-Number, Numerator, Denominator); +} + +FORCEINLINE VOID PhProbeAddress( + _In_ PVOID UserAddress, + _In_ SIZE_T UserLength, + _In_ PVOID BufferAddress, + _In_ SIZE_T BufferLength, + _In_ ULONG Alignment + ) +{ + if (UserLength != 0) + { + if (((ULONG_PTR)UserAddress & (Alignment - 1)) != 0) + PhRaiseStatus(STATUS_DATATYPE_MISALIGNMENT); + + if ( + ((ULONG_PTR)UserAddress + UserLength < (ULONG_PTR)UserAddress) || + ((ULONG_PTR)UserAddress < (ULONG_PTR)BufferAddress) || + ((ULONG_PTR)UserAddress + UserLength > (ULONG_PTR)BufferAddress + BufferLength) + ) + PhRaiseStatus(STATUS_ACCESS_VIOLATION); + } +} + +FORCEINLINE PLARGE_INTEGER PhTimeoutFromMilliseconds( + _Out_ PLARGE_INTEGER Timeout, + _In_ ULONG Milliseconds + ) +{ + if (Milliseconds == INFINITE) + return NULL; + + Timeout->QuadPart = -(LONGLONG)UInt32x32To64(Milliseconds, PH_TIMEOUT_MS); + + return Timeout; +} + +FORCEINLINE NTSTATUS PhGetLastWin32ErrorAsNtStatus() +{ + ULONG win32Result; + + // This is needed because NTSTATUS_FROM_WIN32 uses the argument multiple times. + win32Result = GetLastError(); + + return NTSTATUS_FROM_WIN32(win32Result); +} + +FORCEINLINE PVOID PhGetModuleProcAddress( + _In_ PWSTR ModuleName, + _In_ PSTR ProcName + ) +{ + HMODULE module; + + module = GetModuleHandle(ModuleName); + + if (module) + return GetProcAddress(module, ProcName); + else + return NULL; +} + +#endif diff --git a/phlib/include/queuedlock.h b/phlib/include/queuedlock.h index 2066b1bb2ee2..dd96ea0ecb36 100644 --- a/phlib/include/queuedlock.h +++ b/phlib/include/queuedlock.h @@ -1,349 +1,349 @@ -#ifndef _PH_QUEUEDLOCK_H -#define _PH_QUEUEDLOCK_H - -#ifdef __cplusplus -extern "C" { -#endif - -#define PH_QUEUED_LOCK_OWNED ((ULONG_PTR)0x1) -#define PH_QUEUED_LOCK_OWNED_SHIFT 0 -#define PH_QUEUED_LOCK_WAITERS ((ULONG_PTR)0x2) - -// Valid only if Waiters = 0 -#define PH_QUEUED_LOCK_SHARED_INC ((ULONG_PTR)0x4) -#define PH_QUEUED_LOCK_SHARED_SHIFT 2 - -// Valid only if Waiters = 1 -#define PH_QUEUED_LOCK_TRAVERSING ((ULONG_PTR)0x4) -#define PH_QUEUED_LOCK_MULTIPLE_SHARED ((ULONG_PTR)0x8) - -#define PH_QUEUED_LOCK_FLAGS ((ULONG_PTR)0xf) - -#define PhGetQueuedLockSharedOwners(Value) \ - ((ULONG_PTR)(Value) >> PH_QUEUED_LOCK_SHARED_SHIFT) -#define PhGetQueuedLockWaitBlock(Value) \ - ((PPH_QUEUED_WAIT_BLOCK)((ULONG_PTR)(Value) & ~PH_QUEUED_LOCK_FLAGS)) - -typedef struct _PH_QUEUED_LOCK -{ - ULONG_PTR Value; -} PH_QUEUED_LOCK, *PPH_QUEUED_LOCK; - -#define PH_QUEUED_LOCK_INIT { 0 } - -#define PH_QUEUED_WAITER_EXCLUSIVE 0x1 -#define PH_QUEUED_WAITER_SPINNING 0x2 -#define PH_QUEUED_WAITER_SPINNING_SHIFT 1 - -typedef struct DECLSPEC_ALIGN(16) _PH_QUEUED_WAIT_BLOCK -{ - /** A pointer to the next wait block, i.e. the wait block pushed onto the list before this one. */ - struct _PH_QUEUED_WAIT_BLOCK *Next; - /** - * A pointer to the previous wait block, i.e. the wait block pushed onto the list after this - * one. - */ - struct _PH_QUEUED_WAIT_BLOCK *Previous; - /** A pointer to the last wait block, i.e. the first waiter pushed onto the list. */ - struct _PH_QUEUED_WAIT_BLOCK *Last; - - ULONG SharedOwners; - ULONG Flags; -} PH_QUEUED_WAIT_BLOCK, *PPH_QUEUED_WAIT_BLOCK; - -BOOLEAN PhQueuedLockInitialization( - VOID - ); - -// Queued lock - -FORCEINLINE -VOID -PhInitializeQueuedLock( - _Out_ PPH_QUEUED_LOCK QueuedLock - ) -{ - QueuedLock->Value = 0; -} - -PHLIBAPI -VOID -FASTCALL -PhfAcquireQueuedLockExclusive( - _Inout_ PPH_QUEUED_LOCK QueuedLock - ); - -_Acquires_exclusive_lock_(*QueuedLock) -FORCEINLINE -VOID -PhAcquireQueuedLockExclusive( - _Inout_ PPH_QUEUED_LOCK QueuedLock - ) -{ - if (_InterlockedBitTestAndSetPointer((PLONG_PTR)&QueuedLock->Value, PH_QUEUED_LOCK_OWNED_SHIFT)) - { - // Owned bit was already set. Slow path. - PhfAcquireQueuedLockExclusive(QueuedLock); - } -} - -PHLIBAPI -VOID -FASTCALL -PhfAcquireQueuedLockShared( - _Inout_ PPH_QUEUED_LOCK QueuedLock - ); - -_Acquires_shared_lock_(*QueuedLock) -FORCEINLINE -VOID -PhAcquireQueuedLockShared( - _Inout_ PPH_QUEUED_LOCK QueuedLock - ) -{ - if ((ULONG_PTR)_InterlockedCompareExchangePointer( - (PVOID *)&QueuedLock->Value, - (PVOID)(PH_QUEUED_LOCK_OWNED | PH_QUEUED_LOCK_SHARED_INC), - (PVOID)0 - ) != 0) - { - PhfAcquireQueuedLockShared(QueuedLock); - } -} - -_When_(return != 0, _Acquires_exclusive_lock_(*QueuedLock)) -FORCEINLINE -BOOLEAN -PhTryAcquireQueuedLockExclusive( - _Inout_ PPH_QUEUED_LOCK QueuedLock - ) -{ - if (!_InterlockedBitTestAndSetPointer((PLONG_PTR)&QueuedLock->Value, PH_QUEUED_LOCK_OWNED_SHIFT)) - { - return TRUE; - } - else - { - return FALSE; - } -} - -PHLIBAPI -VOID -FASTCALL -PhfReleaseQueuedLockExclusive( - _Inout_ PPH_QUEUED_LOCK QueuedLock - ); - -PHLIBAPI -VOID -FASTCALL -PhfWakeForReleaseQueuedLock( - _Inout_ PPH_QUEUED_LOCK QueuedLock, - _In_ ULONG_PTR Value - ); - -_Releases_exclusive_lock_(*QueuedLock) -FORCEINLINE -VOID -PhReleaseQueuedLockExclusive( - _Inout_ PPH_QUEUED_LOCK QueuedLock - ) -{ - ULONG_PTR value; - - value = (ULONG_PTR)_InterlockedExchangeAddPointer((PLONG_PTR)&QueuedLock->Value, -(LONG_PTR)PH_QUEUED_LOCK_OWNED); - - if ((value & (PH_QUEUED_LOCK_WAITERS | PH_QUEUED_LOCK_TRAVERSING)) == PH_QUEUED_LOCK_WAITERS) - { - PhfWakeForReleaseQueuedLock(QueuedLock, value - PH_QUEUED_LOCK_OWNED); - } -} - -PHLIBAPI -VOID -FASTCALL -PhfReleaseQueuedLockShared( - _Inout_ PPH_QUEUED_LOCK QueuedLock - ); - -_Releases_shared_lock_(*QueuedLock) -FORCEINLINE -VOID -PhReleaseQueuedLockShared( - _Inout_ PPH_QUEUED_LOCK QueuedLock - ) -{ - ULONG_PTR value; - - value = PH_QUEUED_LOCK_OWNED | PH_QUEUED_LOCK_SHARED_INC; - - if ((ULONG_PTR)_InterlockedCompareExchangePointer( - (PVOID *)&QueuedLock->Value, - (PVOID)0, - (PVOID)value - ) != value) - { - PhfReleaseQueuedLockShared(QueuedLock); - } -} - -FORCEINLINE -VOID -PhAcquireReleaseQueuedLockExclusive( - _Inout_ PPH_QUEUED_LOCK QueuedLock - ) -{ - BOOLEAN owned; - - MemoryBarrier(); - owned = !!(QueuedLock->Value & PH_QUEUED_LOCK_OWNED); - MemoryBarrier(); - - if (owned) - { - PhAcquireQueuedLockExclusive(QueuedLock); - PhReleaseQueuedLockExclusive(QueuedLock); - } -} - -FORCEINLINE -BOOLEAN -PhTryAcquireReleaseQueuedLockExclusive( - _Inout_ PPH_QUEUED_LOCK QueuedLock - ) -{ - BOOLEAN owned; - - // Need two memory barriers because we don't want the compiler re-ordering the following check - // in either direction. - MemoryBarrier(); - owned = !(QueuedLock->Value & PH_QUEUED_LOCK_OWNED); - MemoryBarrier(); - - return owned; -} - -// Condition variable - -typedef struct _PH_QUEUED_LOCK PH_CONDITION, *PPH_CONDITION; - -#define PH_CONDITION_INIT PH_QUEUED_LOCK_INIT - -FORCEINLINE -VOID -PhInitializeCondition( - _Out_ PPH_CONDITION Condition - ) -{ - PhInitializeQueuedLock(Condition); -} - -#define PhPulseCondition PhfPulseCondition -PHLIBAPI -VOID -FASTCALL -PhfPulseCondition( - _Inout_ PPH_CONDITION Condition - ); - -#define PhPulseAllCondition PhfPulseAllCondition -PHLIBAPI -VOID -FASTCALL -PhfPulseAllCondition( - _Inout_ PPH_CONDITION Condition - ); - -#define PhWaitForCondition PhfWaitForCondition -PHLIBAPI -VOID -FASTCALL -PhfWaitForCondition( - _Inout_ PPH_CONDITION Condition, - _Inout_ PPH_QUEUED_LOCK Lock, - _In_opt_ PLARGE_INTEGER Timeout - ); - -#define PH_CONDITION_WAIT_QUEUED_LOCK 0x1 -#define PH_CONDITION_WAIT_CRITICAL_SECTION 0x2 -#define PH_CONDITION_WAIT_FAST_LOCK 0x4 -#define PH_CONDITION_WAIT_LOCK_TYPE_MASK 0xfff - -#define PH_CONDITION_WAIT_SHARED 0x1000 -#define PH_CONDITION_WAIT_SPIN 0x2000 - -#define PhWaitForConditionEx PhfWaitForConditionEx -PHLIBAPI -VOID -FASTCALL -PhfWaitForConditionEx( - _Inout_ PPH_CONDITION Condition, - _Inout_ PVOID Lock, - _In_ ULONG Flags, - _In_opt_ PLARGE_INTEGER Timeout - ); - -// Wake event - -typedef struct _PH_QUEUED_LOCK PH_WAKE_EVENT, *PPH_WAKE_EVENT; - -#define PH_WAKE_EVENT_INIT PH_QUEUED_LOCK_INIT - -FORCEINLINE -VOID -PhInitializeWakeEvent( - _Out_ PPH_WAKE_EVENT WakeEvent - ) -{ - PhInitializeQueuedLock(WakeEvent); -} - -#define PhQueueWakeEvent PhfQueueWakeEvent -PHLIBAPI -VOID -FASTCALL -PhfQueueWakeEvent( - _Inout_ PPH_WAKE_EVENT WakeEvent, - _Out_ PPH_QUEUED_WAIT_BLOCK WaitBlock - ); - -PHLIBAPI -VOID -FASTCALL -PhfSetWakeEvent( - _Inout_ PPH_WAKE_EVENT WakeEvent, - _Inout_opt_ PPH_QUEUED_WAIT_BLOCK WaitBlock - ); - -FORCEINLINE -VOID -PhSetWakeEvent( - _Inout_ PPH_WAKE_EVENT WakeEvent, - _Inout_opt_ PPH_QUEUED_WAIT_BLOCK WaitBlock - ) -{ - // The wake event is similar to a synchronization event in that it does not have thread-safe - // pulsing; we can simply skip the function call if there's nothing to wake. However, if we're - // cancelling a wait (WaitBlock != NULL) we need to make the call. - - if (WakeEvent->Value || WaitBlock) - PhfSetWakeEvent(WakeEvent, WaitBlock); -} - -#define PhWaitForWakeEvent PhfWaitForWakeEvent -PHLIBAPI -NTSTATUS -FASTCALL -PhfWaitForWakeEvent( - _Inout_ PPH_WAKE_EVENT WakeEvent, - _Inout_ PPH_QUEUED_WAIT_BLOCK WaitBlock, - _In_ BOOLEAN Spin, - _In_opt_ PLARGE_INTEGER Timeout - ); - -#ifdef __cplusplus -} -#endif - -#endif +#ifndef _PH_QUEUEDLOCK_H +#define _PH_QUEUEDLOCK_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define PH_QUEUED_LOCK_OWNED ((ULONG_PTR)0x1) +#define PH_QUEUED_LOCK_OWNED_SHIFT 0 +#define PH_QUEUED_LOCK_WAITERS ((ULONG_PTR)0x2) + +// Valid only if Waiters = 0 +#define PH_QUEUED_LOCK_SHARED_INC ((ULONG_PTR)0x4) +#define PH_QUEUED_LOCK_SHARED_SHIFT 2 + +// Valid only if Waiters = 1 +#define PH_QUEUED_LOCK_TRAVERSING ((ULONG_PTR)0x4) +#define PH_QUEUED_LOCK_MULTIPLE_SHARED ((ULONG_PTR)0x8) + +#define PH_QUEUED_LOCK_FLAGS ((ULONG_PTR)0xf) + +#define PhGetQueuedLockSharedOwners(Value) \ + ((ULONG_PTR)(Value) >> PH_QUEUED_LOCK_SHARED_SHIFT) +#define PhGetQueuedLockWaitBlock(Value) \ + ((PPH_QUEUED_WAIT_BLOCK)((ULONG_PTR)(Value) & ~PH_QUEUED_LOCK_FLAGS)) + +typedef struct _PH_QUEUED_LOCK +{ + ULONG_PTR Value; +} PH_QUEUED_LOCK, *PPH_QUEUED_LOCK; + +#define PH_QUEUED_LOCK_INIT { 0 } + +#define PH_QUEUED_WAITER_EXCLUSIVE 0x1 +#define PH_QUEUED_WAITER_SPINNING 0x2 +#define PH_QUEUED_WAITER_SPINNING_SHIFT 1 + +typedef struct DECLSPEC_ALIGN(16) _PH_QUEUED_WAIT_BLOCK +{ + /** A pointer to the next wait block, i.e. the wait block pushed onto the list before this one. */ + struct _PH_QUEUED_WAIT_BLOCK *Next; + /** + * A pointer to the previous wait block, i.e. the wait block pushed onto the list after this + * one. + */ + struct _PH_QUEUED_WAIT_BLOCK *Previous; + /** A pointer to the last wait block, i.e. the first waiter pushed onto the list. */ + struct _PH_QUEUED_WAIT_BLOCK *Last; + + ULONG SharedOwners; + ULONG Flags; +} PH_QUEUED_WAIT_BLOCK, *PPH_QUEUED_WAIT_BLOCK; + +BOOLEAN PhQueuedLockInitialization( + VOID + ); + +// Queued lock + +FORCEINLINE +VOID +PhInitializeQueuedLock( + _Out_ PPH_QUEUED_LOCK QueuedLock + ) +{ + QueuedLock->Value = 0; +} + +PHLIBAPI +VOID +FASTCALL +PhfAcquireQueuedLockExclusive( + _Inout_ PPH_QUEUED_LOCK QueuedLock + ); + +_Acquires_exclusive_lock_(*QueuedLock) +FORCEINLINE +VOID +PhAcquireQueuedLockExclusive( + _Inout_ PPH_QUEUED_LOCK QueuedLock + ) +{ + if (_InterlockedBitTestAndSetPointer((PLONG_PTR)&QueuedLock->Value, PH_QUEUED_LOCK_OWNED_SHIFT)) + { + // Owned bit was already set. Slow path. + PhfAcquireQueuedLockExclusive(QueuedLock); + } +} + +PHLIBAPI +VOID +FASTCALL +PhfAcquireQueuedLockShared( + _Inout_ PPH_QUEUED_LOCK QueuedLock + ); + +_Acquires_shared_lock_(*QueuedLock) +FORCEINLINE +VOID +PhAcquireQueuedLockShared( + _Inout_ PPH_QUEUED_LOCK QueuedLock + ) +{ + if ((ULONG_PTR)_InterlockedCompareExchangePointer( + (PVOID *)&QueuedLock->Value, + (PVOID)(PH_QUEUED_LOCK_OWNED | PH_QUEUED_LOCK_SHARED_INC), + (PVOID)0 + ) != 0) + { + PhfAcquireQueuedLockShared(QueuedLock); + } +} + +_When_(return != 0, _Acquires_exclusive_lock_(*QueuedLock)) +FORCEINLINE +BOOLEAN +PhTryAcquireQueuedLockExclusive( + _Inout_ PPH_QUEUED_LOCK QueuedLock + ) +{ + if (!_InterlockedBitTestAndSetPointer((PLONG_PTR)&QueuedLock->Value, PH_QUEUED_LOCK_OWNED_SHIFT)) + { + return TRUE; + } + else + { + return FALSE; + } +} + +PHLIBAPI +VOID +FASTCALL +PhfReleaseQueuedLockExclusive( + _Inout_ PPH_QUEUED_LOCK QueuedLock + ); + +PHLIBAPI +VOID +FASTCALL +PhfWakeForReleaseQueuedLock( + _Inout_ PPH_QUEUED_LOCK QueuedLock, + _In_ ULONG_PTR Value + ); + +_Releases_exclusive_lock_(*QueuedLock) +FORCEINLINE +VOID +PhReleaseQueuedLockExclusive( + _Inout_ PPH_QUEUED_LOCK QueuedLock + ) +{ + ULONG_PTR value; + + value = (ULONG_PTR)_InterlockedExchangeAddPointer((PLONG_PTR)&QueuedLock->Value, -(LONG_PTR)PH_QUEUED_LOCK_OWNED); + + if ((value & (PH_QUEUED_LOCK_WAITERS | PH_QUEUED_LOCK_TRAVERSING)) == PH_QUEUED_LOCK_WAITERS) + { + PhfWakeForReleaseQueuedLock(QueuedLock, value - PH_QUEUED_LOCK_OWNED); + } +} + +PHLIBAPI +VOID +FASTCALL +PhfReleaseQueuedLockShared( + _Inout_ PPH_QUEUED_LOCK QueuedLock + ); + +_Releases_shared_lock_(*QueuedLock) +FORCEINLINE +VOID +PhReleaseQueuedLockShared( + _Inout_ PPH_QUEUED_LOCK QueuedLock + ) +{ + ULONG_PTR value; + + value = PH_QUEUED_LOCK_OWNED | PH_QUEUED_LOCK_SHARED_INC; + + if ((ULONG_PTR)_InterlockedCompareExchangePointer( + (PVOID *)&QueuedLock->Value, + (PVOID)0, + (PVOID)value + ) != value) + { + PhfReleaseQueuedLockShared(QueuedLock); + } +} + +FORCEINLINE +VOID +PhAcquireReleaseQueuedLockExclusive( + _Inout_ PPH_QUEUED_LOCK QueuedLock + ) +{ + BOOLEAN owned; + + MemoryBarrier(); + owned = !!(QueuedLock->Value & PH_QUEUED_LOCK_OWNED); + MemoryBarrier(); + + if (owned) + { + PhAcquireQueuedLockExclusive(QueuedLock); + PhReleaseQueuedLockExclusive(QueuedLock); + } +} + +FORCEINLINE +BOOLEAN +PhTryAcquireReleaseQueuedLockExclusive( + _Inout_ PPH_QUEUED_LOCK QueuedLock + ) +{ + BOOLEAN owned; + + // Need two memory barriers because we don't want the compiler re-ordering the following check + // in either direction. + MemoryBarrier(); + owned = !(QueuedLock->Value & PH_QUEUED_LOCK_OWNED); + MemoryBarrier(); + + return owned; +} + +// Condition variable + +typedef struct _PH_QUEUED_LOCK PH_CONDITION, *PPH_CONDITION; + +#define PH_CONDITION_INIT PH_QUEUED_LOCK_INIT + +FORCEINLINE +VOID +PhInitializeCondition( + _Out_ PPH_CONDITION Condition + ) +{ + PhInitializeQueuedLock(Condition); +} + +#define PhPulseCondition PhfPulseCondition +PHLIBAPI +VOID +FASTCALL +PhfPulseCondition( + _Inout_ PPH_CONDITION Condition + ); + +#define PhPulseAllCondition PhfPulseAllCondition +PHLIBAPI +VOID +FASTCALL +PhfPulseAllCondition( + _Inout_ PPH_CONDITION Condition + ); + +#define PhWaitForCondition PhfWaitForCondition +PHLIBAPI +VOID +FASTCALL +PhfWaitForCondition( + _Inout_ PPH_CONDITION Condition, + _Inout_ PPH_QUEUED_LOCK Lock, + _In_opt_ PLARGE_INTEGER Timeout + ); + +#define PH_CONDITION_WAIT_QUEUED_LOCK 0x1 +#define PH_CONDITION_WAIT_CRITICAL_SECTION 0x2 +#define PH_CONDITION_WAIT_FAST_LOCK 0x4 +#define PH_CONDITION_WAIT_LOCK_TYPE_MASK 0xfff + +#define PH_CONDITION_WAIT_SHARED 0x1000 +#define PH_CONDITION_WAIT_SPIN 0x2000 + +#define PhWaitForConditionEx PhfWaitForConditionEx +PHLIBAPI +VOID +FASTCALL +PhfWaitForConditionEx( + _Inout_ PPH_CONDITION Condition, + _Inout_ PVOID Lock, + _In_ ULONG Flags, + _In_opt_ PLARGE_INTEGER Timeout + ); + +// Wake event + +typedef struct _PH_QUEUED_LOCK PH_WAKE_EVENT, *PPH_WAKE_EVENT; + +#define PH_WAKE_EVENT_INIT PH_QUEUED_LOCK_INIT + +FORCEINLINE +VOID +PhInitializeWakeEvent( + _Out_ PPH_WAKE_EVENT WakeEvent + ) +{ + PhInitializeQueuedLock(WakeEvent); +} + +#define PhQueueWakeEvent PhfQueueWakeEvent +PHLIBAPI +VOID +FASTCALL +PhfQueueWakeEvent( + _Inout_ PPH_WAKE_EVENT WakeEvent, + _Out_ PPH_QUEUED_WAIT_BLOCK WaitBlock + ); + +PHLIBAPI +VOID +FASTCALL +PhfSetWakeEvent( + _Inout_ PPH_WAKE_EVENT WakeEvent, + _Inout_opt_ PPH_QUEUED_WAIT_BLOCK WaitBlock + ); + +FORCEINLINE +VOID +PhSetWakeEvent( + _Inout_ PPH_WAKE_EVENT WakeEvent, + _Inout_opt_ PPH_QUEUED_WAIT_BLOCK WaitBlock + ) +{ + // The wake event is similar to a synchronization event in that it does not have thread-safe + // pulsing; we can simply skip the function call if there's nothing to wake. However, if we're + // cancelling a wait (WaitBlock != NULL) we need to make the call. + + if (WakeEvent->Value || WaitBlock) + PhfSetWakeEvent(WakeEvent, WaitBlock); +} + +#define PhWaitForWakeEvent PhfWaitForWakeEvent +PHLIBAPI +NTSTATUS +FASTCALL +PhfWaitForWakeEvent( + _Inout_ PPH_WAKE_EVENT WakeEvent, + _Inout_ PPH_QUEUED_WAIT_BLOCK WaitBlock, + _In_ BOOLEAN Spin, + _In_opt_ PLARGE_INTEGER Timeout + ); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/phlib/include/ref.h b/phlib/include/ref.h index 266b82cce516..4f3bb1389ae9 100644 --- a/phlib/include/ref.h +++ b/phlib/include/ref.h @@ -1,309 +1,309 @@ -/* - * Process Hacker - - * internal object manager - * - * Copyright (C) 2009-2016 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#ifndef _PH_REF_H -#define _PH_REF_H - -#ifdef __cplusplus -extern "C" { -#endif - -// Configuration - -#define PH_OBJECT_SMALL_OBJECT_SIZE 48 -#define PH_OBJECT_SMALL_OBJECT_COUNT 512 - -// Object type flags -#define PH_OBJECT_TYPE_USE_FREE_LIST 0x00000001 -#define PH_OBJECT_TYPE_VALID_FLAGS 0x00000001 - -// Object type callbacks - -/** - * The delete procedure for an object type, called when an object of the type is being freed. - * - * \param Object A pointer to the object being freed. - * \param Flags Reserved. - */ -typedef VOID (NTAPI *PPH_TYPE_DELETE_PROCEDURE)( - _In_ PVOID Object, - _In_ ULONG Flags - ); - -struct _PH_OBJECT_TYPE; -typedef struct _PH_OBJECT_TYPE *PPH_OBJECT_TYPE; - -struct _PH_QUEUED_LOCK; -typedef struct _PH_QUEUED_LOCK PH_QUEUED_LOCK, *PPH_QUEUED_LOCK; - -#ifdef DEBUG -typedef VOID (NTAPI *PPH_CREATE_OBJECT_HOOK)( - _In_ PVOID Object, - _In_ SIZE_T Size, - _In_ ULONG Flags, - _In_ PPH_OBJECT_TYPE ObjectType - ); -#endif - -typedef struct _PH_OBJECT_TYPE_PARAMETERS -{ - SIZE_T FreeListSize; - ULONG FreeListCount; -} PH_OBJECT_TYPE_PARAMETERS, *PPH_OBJECT_TYPE_PARAMETERS; - -typedef struct _PH_OBJECT_TYPE_INFORMATION -{ - PWSTR Name; - ULONG NumberOfObjects; - USHORT Flags; - UCHAR TypeIndex; - UCHAR Reserved; -} PH_OBJECT_TYPE_INFORMATION, *PPH_OBJECT_TYPE_INFORMATION; - -extern PPH_OBJECT_TYPE PhObjectTypeObject; -extern PPH_OBJECT_TYPE PhAllocType; - -#ifdef DEBUG -extern LIST_ENTRY PhDbgObjectListHead; -extern PH_QUEUED_LOCK PhDbgObjectListLock; -extern PPH_CREATE_OBJECT_HOOK PhDbgCreateObjectHook; -#endif - -NTSTATUS PhRefInitialization( - VOID - ); - -_May_raise_ -PHLIBAPI -PVOID -NTAPI -PhCreateObject( - _In_ SIZE_T ObjectSize, - _In_ PPH_OBJECT_TYPE ObjectType - ); - -PHLIBAPI -PVOID -NTAPI -PhReferenceObject( - _In_ PVOID Object - ); - -_May_raise_ -PHLIBAPI -PVOID -NTAPI -PhReferenceObjectEx( - _In_ PVOID Object, - _In_ LONG RefCount - ); - -PHLIBAPI -PVOID -NTAPI -PhReferenceObjectSafe( - _In_ PVOID Object - ); - -PHLIBAPI -VOID -NTAPI -PhDereferenceObject( - _In_ PVOID Object - ); - -PHLIBAPI -VOID -NTAPI -PhDereferenceObjectDeferDelete( - _In_ PVOID Object - ); - -_May_raise_ -PHLIBAPI -VOID -NTAPI -PhDereferenceObjectEx( - _In_ PVOID Object, - _In_ LONG RefCount, - _In_ BOOLEAN DeferDelete - ); - -PHLIBAPI -PPH_OBJECT_TYPE -NTAPI -PhGetObjectType( - _In_ PVOID Object - ); - -PHLIBAPI -PPH_OBJECT_TYPE -NTAPI -PhCreateObjectType( - _In_ PWSTR Name, - _In_ ULONG Flags, - _In_opt_ PPH_TYPE_DELETE_PROCEDURE DeleteProcedure - ); - -PHLIBAPI -PPH_OBJECT_TYPE -NTAPI -PhCreateObjectTypeEx( - _In_ PWSTR Name, - _In_ ULONG Flags, - _In_opt_ PPH_TYPE_DELETE_PROCEDURE DeleteProcedure, - _In_opt_ PPH_OBJECT_TYPE_PARAMETERS Parameters - ); - -PHLIBAPI -VOID -NTAPI -PhGetObjectTypeInformation( - _In_ PPH_OBJECT_TYPE ObjectType, - _Out_ PPH_OBJECT_TYPE_INFORMATION Information - ); - -PHLIBAPI -PVOID -NTAPI -PhCreateAlloc( - _In_ SIZE_T Size - ); - -// Object reference functions - -FORCEINLINE -VOID -PhSwapReference( - _Inout_ PVOID *ObjectReference, - _In_opt_ PVOID NewObject - ) -{ - PVOID oldObject; - - oldObject = *ObjectReference; - *ObjectReference = NewObject; - - if (NewObject) PhReferenceObject(NewObject); - if (oldObject) PhDereferenceObject(oldObject); -} - -FORCEINLINE -VOID -PhMoveReference( - _Inout_ PVOID *ObjectReference, - _In_opt_ _Assume_refs_(1) PVOID NewObject - ) -{ - PVOID oldObject; - - oldObject = *ObjectReference; - *ObjectReference = NewObject; - - if (oldObject) PhDereferenceObject(oldObject); -} - -FORCEINLINE -VOID -PhSetReference( - _Out_ PVOID *ObjectReference, - _In_opt_ PVOID NewObject - ) -{ - *ObjectReference = NewObject; - - if (NewObject) PhReferenceObject(NewObject); -} - -FORCEINLINE -VOID -PhClearReference( - _Inout_ PVOID *ObjectReference - ) -{ - PhMoveReference(ObjectReference, NULL); -} - -// Auto-dereference pool - -/** The size of the static array in an auto-release pool. */ -#define PH_AUTO_POOL_STATIC_SIZE 64 -/** The maximum size of the dynamic array for it to be kept after the auto-release pool is drained. */ -#define PH_AUTO_POOL_DYNAMIC_BIG_SIZE 256 - -/** - * An auto-dereference pool can be used for semi-automatic reference counting. Batches of objects - * are dereferenced at a certain time. - * - * This object is not thread-safe and cannot be used across thread boundaries. Always store them as - * local variables. - */ -typedef struct _PH_AUTO_POOL -{ - ULONG StaticCount; - PVOID StaticObjects[PH_AUTO_POOL_STATIC_SIZE]; - - ULONG DynamicCount; - ULONG DynamicAllocated; - PVOID *DynamicObjects; - - struct _PH_AUTO_POOL *NextPool; -} PH_AUTO_POOL, *PPH_AUTO_POOL; - -PHLIBAPI -VOID -NTAPI -PhInitializeAutoPool( - _Out_ PPH_AUTO_POOL AutoPool - ); - -_May_raise_ -PHLIBAPI -VOID -NTAPI -PhDeleteAutoPool( - _Inout_ PPH_AUTO_POOL AutoPool - ); - -PHLIBAPI -VOID -NTAPI -PhDrainAutoPool( - _In_ PPH_AUTO_POOL AutoPool - ); - -_May_raise_ -PHLIBAPI -PVOID -NTAPI -PhAutoDereferenceObject( - _In_opt_ PVOID Object - ); - -#define PH_AUTO PhAutoDereferenceObject -#define PH_AUTO_T(Type, Object) ((Type *)PH_AUTO(Object)) - -#ifdef __cplusplus -} -#endif - -#endif +/* + * Process Hacker - + * internal object manager + * + * Copyright (C) 2009-2016 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#ifndef _PH_REF_H +#define _PH_REF_H + +#ifdef __cplusplus +extern "C" { +#endif + +// Configuration + +#define PH_OBJECT_SMALL_OBJECT_SIZE 48 +#define PH_OBJECT_SMALL_OBJECT_COUNT 512 + +// Object type flags +#define PH_OBJECT_TYPE_USE_FREE_LIST 0x00000001 +#define PH_OBJECT_TYPE_VALID_FLAGS 0x00000001 + +// Object type callbacks + +/** + * The delete procedure for an object type, called when an object of the type is being freed. + * + * \param Object A pointer to the object being freed. + * \param Flags Reserved. + */ +typedef VOID (NTAPI *PPH_TYPE_DELETE_PROCEDURE)( + _In_ PVOID Object, + _In_ ULONG Flags + ); + +struct _PH_OBJECT_TYPE; +typedef struct _PH_OBJECT_TYPE *PPH_OBJECT_TYPE; + +struct _PH_QUEUED_LOCK; +typedef struct _PH_QUEUED_LOCK PH_QUEUED_LOCK, *PPH_QUEUED_LOCK; + +#ifdef DEBUG +typedef VOID (NTAPI *PPH_CREATE_OBJECT_HOOK)( + _In_ PVOID Object, + _In_ SIZE_T Size, + _In_ ULONG Flags, + _In_ PPH_OBJECT_TYPE ObjectType + ); +#endif + +typedef struct _PH_OBJECT_TYPE_PARAMETERS +{ + SIZE_T FreeListSize; + ULONG FreeListCount; +} PH_OBJECT_TYPE_PARAMETERS, *PPH_OBJECT_TYPE_PARAMETERS; + +typedef struct _PH_OBJECT_TYPE_INFORMATION +{ + PWSTR Name; + ULONG NumberOfObjects; + USHORT Flags; + UCHAR TypeIndex; + UCHAR Reserved; +} PH_OBJECT_TYPE_INFORMATION, *PPH_OBJECT_TYPE_INFORMATION; + +extern PPH_OBJECT_TYPE PhObjectTypeObject; +extern PPH_OBJECT_TYPE PhAllocType; + +#ifdef DEBUG +extern LIST_ENTRY PhDbgObjectListHead; +extern PH_QUEUED_LOCK PhDbgObjectListLock; +extern PPH_CREATE_OBJECT_HOOK PhDbgCreateObjectHook; +#endif + +NTSTATUS PhRefInitialization( + VOID + ); + +_May_raise_ +PHLIBAPI +PVOID +NTAPI +PhCreateObject( + _In_ SIZE_T ObjectSize, + _In_ PPH_OBJECT_TYPE ObjectType + ); + +PHLIBAPI +PVOID +NTAPI +PhReferenceObject( + _In_ PVOID Object + ); + +_May_raise_ +PHLIBAPI +PVOID +NTAPI +PhReferenceObjectEx( + _In_ PVOID Object, + _In_ LONG RefCount + ); + +PHLIBAPI +PVOID +NTAPI +PhReferenceObjectSafe( + _In_ PVOID Object + ); + +PHLIBAPI +VOID +NTAPI +PhDereferenceObject( + _In_ PVOID Object + ); + +PHLIBAPI +VOID +NTAPI +PhDereferenceObjectDeferDelete( + _In_ PVOID Object + ); + +_May_raise_ +PHLIBAPI +VOID +NTAPI +PhDereferenceObjectEx( + _In_ PVOID Object, + _In_ LONG RefCount, + _In_ BOOLEAN DeferDelete + ); + +PHLIBAPI +PPH_OBJECT_TYPE +NTAPI +PhGetObjectType( + _In_ PVOID Object + ); + +PHLIBAPI +PPH_OBJECT_TYPE +NTAPI +PhCreateObjectType( + _In_ PWSTR Name, + _In_ ULONG Flags, + _In_opt_ PPH_TYPE_DELETE_PROCEDURE DeleteProcedure + ); + +PHLIBAPI +PPH_OBJECT_TYPE +NTAPI +PhCreateObjectTypeEx( + _In_ PWSTR Name, + _In_ ULONG Flags, + _In_opt_ PPH_TYPE_DELETE_PROCEDURE DeleteProcedure, + _In_opt_ PPH_OBJECT_TYPE_PARAMETERS Parameters + ); + +PHLIBAPI +VOID +NTAPI +PhGetObjectTypeInformation( + _In_ PPH_OBJECT_TYPE ObjectType, + _Out_ PPH_OBJECT_TYPE_INFORMATION Information + ); + +PHLIBAPI +PVOID +NTAPI +PhCreateAlloc( + _In_ SIZE_T Size + ); + +// Object reference functions + +FORCEINLINE +VOID +PhSwapReference( + _Inout_ PVOID *ObjectReference, + _In_opt_ PVOID NewObject + ) +{ + PVOID oldObject; + + oldObject = *ObjectReference; + *ObjectReference = NewObject; + + if (NewObject) PhReferenceObject(NewObject); + if (oldObject) PhDereferenceObject(oldObject); +} + +FORCEINLINE +VOID +PhMoveReference( + _Inout_ PVOID *ObjectReference, + _In_opt_ _Assume_refs_(1) PVOID NewObject + ) +{ + PVOID oldObject; + + oldObject = *ObjectReference; + *ObjectReference = NewObject; + + if (oldObject) PhDereferenceObject(oldObject); +} + +FORCEINLINE +VOID +PhSetReference( + _Out_ PVOID *ObjectReference, + _In_opt_ PVOID NewObject + ) +{ + *ObjectReference = NewObject; + + if (NewObject) PhReferenceObject(NewObject); +} + +FORCEINLINE +VOID +PhClearReference( + _Inout_ PVOID *ObjectReference + ) +{ + PhMoveReference(ObjectReference, NULL); +} + +// Auto-dereference pool + +/** The size of the static array in an auto-release pool. */ +#define PH_AUTO_POOL_STATIC_SIZE 64 +/** The maximum size of the dynamic array for it to be kept after the auto-release pool is drained. */ +#define PH_AUTO_POOL_DYNAMIC_BIG_SIZE 256 + +/** + * An auto-dereference pool can be used for semi-automatic reference counting. Batches of objects + * are dereferenced at a certain time. + * + * This object is not thread-safe and cannot be used across thread boundaries. Always store them as + * local variables. + */ +typedef struct _PH_AUTO_POOL +{ + ULONG StaticCount; + PVOID StaticObjects[PH_AUTO_POOL_STATIC_SIZE]; + + ULONG DynamicCount; + ULONG DynamicAllocated; + PVOID *DynamicObjects; + + struct _PH_AUTO_POOL *NextPool; +} PH_AUTO_POOL, *PPH_AUTO_POOL; + +PHLIBAPI +VOID +NTAPI +PhInitializeAutoPool( + _Out_ PPH_AUTO_POOL AutoPool + ); + +_May_raise_ +PHLIBAPI +VOID +NTAPI +PhDeleteAutoPool( + _Inout_ PPH_AUTO_POOL AutoPool + ); + +PHLIBAPI +VOID +NTAPI +PhDrainAutoPool( + _In_ PPH_AUTO_POOL AutoPool + ); + +_May_raise_ +PHLIBAPI +PVOID +NTAPI +PhAutoDereferenceObject( + _In_opt_ PVOID Object + ); + +#define PH_AUTO PhAutoDereferenceObject +#define PH_AUTO_T(Type, Object) ((Type *)PH_AUTO(Object)) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/phlib/include/refp.h b/phlib/include/refp.h index f1059d9e4d36..dfa9478f9768 100644 --- a/phlib/include/refp.h +++ b/phlib/include/refp.h @@ -1,175 +1,175 @@ -/* - * Process Hacker - - * internal object manager - * - * Copyright (C) 2009-2016 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#ifndef _PH_REFP_H -#define _PH_REFP_H - -#define PH_OBJECT_TYPE_TABLE_SIZE 256 - -/** The object was allocated from the small free list. */ -#define PH_OBJECT_FROM_SMALL_FREE_LIST 0x1 -/** The object was allocated from the type free list. */ -#define PH_OBJECT_FROM_TYPE_FREE_LIST 0x2 - -/** - * The object header contains object manager information including the reference count of an object - * and its type. - */ -typedef struct _PH_OBJECT_HEADER -{ - union - { - struct - { - USHORT TypeIndex; - UCHAR Flags; - UCHAR Reserved1; -#ifdef _WIN64 - ULONG Reserved2; -#endif - union - { - LONG RefCount; - struct - { - LONG SavedTypeIndex : 16; - LONG SavedFlags : 8; - LONG Reserved : 7; - LONG DeferDelete : 1; // MUST be the high bit, so that RefCount < 0 when deferring delete - }; - }; -#ifdef _WIN64 - ULONG Reserved3; -#endif - }; - SLIST_ENTRY DeferDeleteListEntry; - }; - -#ifdef DEBUG - PVOID StackBackTrace[16]; - LIST_ENTRY ObjectListEntry; -#endif - - /** - * The body of the object. For use by the \ref PhObjectToObjectHeader and - * \ref PhObjectHeaderToObject macros. - */ - QUAD_PTR Body; -} PH_OBJECT_HEADER, *PPH_OBJECT_HEADER; - -#ifndef DEBUG -#ifdef _WIN64 -C_ASSERT(FIELD_OFFSET(PH_OBJECT_HEADER, TypeIndex) == 0x0); -C_ASSERT(FIELD_OFFSET(PH_OBJECT_HEADER, Flags) == 0x2); -C_ASSERT(FIELD_OFFSET(PH_OBJECT_HEADER, Reserved1) == 0x3); -C_ASSERT(FIELD_OFFSET(PH_OBJECT_HEADER, Reserved2) == 0x4); -C_ASSERT(FIELD_OFFSET(PH_OBJECT_HEADER, RefCount) == 0x8); -C_ASSERT(FIELD_OFFSET(PH_OBJECT_HEADER, Reserved3) == 0xc); -C_ASSERT(FIELD_OFFSET(PH_OBJECT_HEADER, DeferDeleteListEntry) == 0x0); -C_ASSERT(FIELD_OFFSET(PH_OBJECT_HEADER, Body) == 0x10); -#else -C_ASSERT(FIELD_OFFSET(PH_OBJECT_HEADER, TypeIndex) == 0x0); -C_ASSERT(FIELD_OFFSET(PH_OBJECT_HEADER, Flags) == 0x2); -C_ASSERT(FIELD_OFFSET(PH_OBJECT_HEADER, Reserved1) == 0x3); -C_ASSERT(FIELD_OFFSET(PH_OBJECT_HEADER, RefCount) == 0x4); -C_ASSERT(FIELD_OFFSET(PH_OBJECT_HEADER, DeferDeleteListEntry) == 0x0); -C_ASSERT(FIELD_OFFSET(PH_OBJECT_HEADER, Body) == 0x8); -#endif -#endif - -/** - * Gets a pointer to the object header for an object. - * - * \param Object A pointer to an object. - * - * \return A pointer to the object header of the object. - */ -#define PhObjectToObjectHeader(Object) ((PPH_OBJECT_HEADER)CONTAINING_RECORD((PCHAR)(Object), PH_OBJECT_HEADER, Body)) - -/** - * Gets a pointer to an object from an object header. - * - * \param ObjectHeader A pointer to an object header. - * - * \return A pointer to an object. - */ -#define PhObjectHeaderToObject(ObjectHeader) ((PVOID)&((PPH_OBJECT_HEADER)(ObjectHeader))->Body) - -/** - * Calculates the total size to allocate for an object. - * - * \param Size The size of the object to allocate. - * - * \return The new size, including space for the object header. - */ -#define PhAddObjectHeaderSize(Size) ((Size) + FIELD_OFFSET(PH_OBJECT_HEADER, Body)) - -/** An object type specifies a kind of object and its delete procedure. */ -typedef struct _PH_OBJECT_TYPE -{ - /** The flags that were used to create the object type. */ - USHORT Flags; - UCHAR TypeIndex; - UCHAR Reserved; - /** The total number of objects of this type that are alive. */ - ULONG NumberOfObjects; - /** An optional procedure called when objects of this type are freed. */ - PPH_TYPE_DELETE_PROCEDURE DeleteProcedure; - /** The name of the type. */ - PWSTR Name; - /** A free list to use when allocating for this type. */ - PH_FREE_LIST FreeList; -} PH_OBJECT_TYPE, *PPH_OBJECT_TYPE; - -/** - * Increments a reference count, but will never increment from a nonpositive value to 1. - * - * \param RefCount A pointer to a reference count. - */ -FORCEINLINE -BOOLEAN -PhpInterlockedIncrementSafe( - _Inout_ PLONG RefCount - ) -{ - /* Here we will attempt to increment the reference count, making sure that it is positive. */ - return _InterlockedIncrementPositive(RefCount); -} - -PPH_OBJECT_HEADER PhpAllocateObject( - _In_ PPH_OBJECT_TYPE ObjectType, - _In_ SIZE_T ObjectSize - ); - -VOID PhpFreeObject( - _In_ PPH_OBJECT_HEADER ObjectHeader - ); - -VOID PhpDeferDeleteObject( - _In_ PPH_OBJECT_HEADER ObjectHeader - ); - -NTSTATUS PhpDeferDeleteObjectRoutine( - _In_ PVOID Parameter - ); - -#endif +/* + * Process Hacker - + * internal object manager + * + * Copyright (C) 2009-2016 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#ifndef _PH_REFP_H +#define _PH_REFP_H + +#define PH_OBJECT_TYPE_TABLE_SIZE 256 + +/** The object was allocated from the small free list. */ +#define PH_OBJECT_FROM_SMALL_FREE_LIST 0x1 +/** The object was allocated from the type free list. */ +#define PH_OBJECT_FROM_TYPE_FREE_LIST 0x2 + +/** + * The object header contains object manager information including the reference count of an object + * and its type. + */ +typedef struct _PH_OBJECT_HEADER +{ + union + { + struct + { + USHORT TypeIndex; + UCHAR Flags; + UCHAR Reserved1; +#ifdef _WIN64 + ULONG Reserved2; +#endif + union + { + LONG RefCount; + struct + { + LONG SavedTypeIndex : 16; + LONG SavedFlags : 8; + LONG Reserved : 7; + LONG DeferDelete : 1; // MUST be the high bit, so that RefCount < 0 when deferring delete + }; + }; +#ifdef _WIN64 + ULONG Reserved3; +#endif + }; + SLIST_ENTRY DeferDeleteListEntry; + }; + +#ifdef DEBUG + PVOID StackBackTrace[16]; + LIST_ENTRY ObjectListEntry; +#endif + + /** + * The body of the object. For use by the \ref PhObjectToObjectHeader and + * \ref PhObjectHeaderToObject macros. + */ + QUAD_PTR Body; +} PH_OBJECT_HEADER, *PPH_OBJECT_HEADER; + +#ifndef DEBUG +#ifdef _WIN64 +C_ASSERT(FIELD_OFFSET(PH_OBJECT_HEADER, TypeIndex) == 0x0); +C_ASSERT(FIELD_OFFSET(PH_OBJECT_HEADER, Flags) == 0x2); +C_ASSERT(FIELD_OFFSET(PH_OBJECT_HEADER, Reserved1) == 0x3); +C_ASSERT(FIELD_OFFSET(PH_OBJECT_HEADER, Reserved2) == 0x4); +C_ASSERT(FIELD_OFFSET(PH_OBJECT_HEADER, RefCount) == 0x8); +C_ASSERT(FIELD_OFFSET(PH_OBJECT_HEADER, Reserved3) == 0xc); +C_ASSERT(FIELD_OFFSET(PH_OBJECT_HEADER, DeferDeleteListEntry) == 0x0); +C_ASSERT(FIELD_OFFSET(PH_OBJECT_HEADER, Body) == 0x10); +#else +C_ASSERT(FIELD_OFFSET(PH_OBJECT_HEADER, TypeIndex) == 0x0); +C_ASSERT(FIELD_OFFSET(PH_OBJECT_HEADER, Flags) == 0x2); +C_ASSERT(FIELD_OFFSET(PH_OBJECT_HEADER, Reserved1) == 0x3); +C_ASSERT(FIELD_OFFSET(PH_OBJECT_HEADER, RefCount) == 0x4); +C_ASSERT(FIELD_OFFSET(PH_OBJECT_HEADER, DeferDeleteListEntry) == 0x0); +C_ASSERT(FIELD_OFFSET(PH_OBJECT_HEADER, Body) == 0x8); +#endif +#endif + +/** + * Gets a pointer to the object header for an object. + * + * \param Object A pointer to an object. + * + * \return A pointer to the object header of the object. + */ +#define PhObjectToObjectHeader(Object) ((PPH_OBJECT_HEADER)CONTAINING_RECORD((PCHAR)(Object), PH_OBJECT_HEADER, Body)) + +/** + * Gets a pointer to an object from an object header. + * + * \param ObjectHeader A pointer to an object header. + * + * \return A pointer to an object. + */ +#define PhObjectHeaderToObject(ObjectHeader) ((PVOID)&((PPH_OBJECT_HEADER)(ObjectHeader))->Body) + +/** + * Calculates the total size to allocate for an object. + * + * \param Size The size of the object to allocate. + * + * \return The new size, including space for the object header. + */ +#define PhAddObjectHeaderSize(Size) ((Size) + FIELD_OFFSET(PH_OBJECT_HEADER, Body)) + +/** An object type specifies a kind of object and its delete procedure. */ +typedef struct _PH_OBJECT_TYPE +{ + /** The flags that were used to create the object type. */ + USHORT Flags; + UCHAR TypeIndex; + UCHAR Reserved; + /** The total number of objects of this type that are alive. */ + ULONG NumberOfObjects; + /** An optional procedure called when objects of this type are freed. */ + PPH_TYPE_DELETE_PROCEDURE DeleteProcedure; + /** The name of the type. */ + PWSTR Name; + /** A free list to use when allocating for this type. */ + PH_FREE_LIST FreeList; +} PH_OBJECT_TYPE, *PPH_OBJECT_TYPE; + +/** + * Increments a reference count, but will never increment from a nonpositive value to 1. + * + * \param RefCount A pointer to a reference count. + */ +FORCEINLINE +BOOLEAN +PhpInterlockedIncrementSafe( + _Inout_ PLONG RefCount + ) +{ + /* Here we will attempt to increment the reference count, making sure that it is positive. */ + return _InterlockedIncrementPositive(RefCount); +} + +PPH_OBJECT_HEADER PhpAllocateObject( + _In_ PPH_OBJECT_TYPE ObjectType, + _In_ SIZE_T ObjectSize + ); + +VOID PhpFreeObject( + _In_ PPH_OBJECT_HEADER ObjectHeader + ); + +VOID PhpDeferDeleteObject( + _In_ PPH_OBJECT_HEADER ObjectHeader + ); + +NTSTATUS PhpDeferDeleteObjectRoutine( + _In_ PVOID Parameter + ); + +#endif diff --git a/phlib/include/secedit.h b/phlib/include/secedit.h index 18bf0322632d..50090d4452b1 100644 --- a/phlib/include/secedit.h +++ b/phlib/include/secedit.h @@ -1,165 +1,165 @@ -#ifndef _PH_SECEDIT_H -#define _PH_SECEDIT_H - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct _PSP *HPROPSHEETPAGE; - -// secedit - -typedef struct _PH_ACCESS_ENTRY -{ - PWSTR Name; - ACCESS_MASK Access; - BOOLEAN General; - BOOLEAN Specific; - PWSTR ShortName; -} PH_ACCESS_ENTRY, *PPH_ACCESS_ENTRY; - -PHLIBAPI -HPROPSHEETPAGE -NTAPI -PhCreateSecurityPage( - _In_ PWSTR ObjectName, - _In_ PPH_GET_OBJECT_SECURITY GetObjectSecurity, - _In_ PPH_SET_OBJECT_SECURITY SetObjectSecurity, - _In_opt_ PVOID Context, - _In_ PPH_ACCESS_ENTRY AccessEntries, - _In_ ULONG NumberOfAccessEntries - ); - -PHLIBAPI -VOID -NTAPI -PhEditSecurity( - _In_ HWND hWnd, - _In_ PWSTR ObjectName, - _In_ PPH_GET_OBJECT_SECURITY GetObjectSecurity, - _In_ PPH_SET_OBJECT_SECURITY SetObjectSecurity, - _In_opt_ PVOID Context, - _In_ PPH_ACCESS_ENTRY AccessEntries, - _In_ ULONG NumberOfAccessEntries - ); - -typedef struct _PH_STD_OBJECT_SECURITY -{ - PPH_OPEN_OBJECT OpenObject; - PWSTR ObjectType; - PVOID Context; -} PH_STD_OBJECT_SECURITY, *PPH_STD_OBJECT_SECURITY; - -FORCEINLINE ACCESS_MASK PhGetAccessForGetSecurity( - _In_ SECURITY_INFORMATION SecurityInformation - ) -{ - ACCESS_MASK access = 0; - - if ( - (SecurityInformation & OWNER_SECURITY_INFORMATION) || - (SecurityInformation & GROUP_SECURITY_INFORMATION) || - (SecurityInformation & DACL_SECURITY_INFORMATION) - ) - { - access |= READ_CONTROL; - } - - if (SecurityInformation & SACL_SECURITY_INFORMATION) - { - access |= ACCESS_SYSTEM_SECURITY; - } - - return access; -} - -FORCEINLINE ACCESS_MASK PhGetAccessForSetSecurity( - _In_ SECURITY_INFORMATION SecurityInformation - ) -{ - ACCESS_MASK access = 0; - - if ( - (SecurityInformation & OWNER_SECURITY_INFORMATION) || - (SecurityInformation & GROUP_SECURITY_INFORMATION) - ) - { - access |= WRITE_OWNER; - } - - if (SecurityInformation & DACL_SECURITY_INFORMATION) - { - access |= WRITE_DAC; - } - - if (SecurityInformation & SACL_SECURITY_INFORMATION) - { - access |= ACCESS_SYSTEM_SECURITY; - } - - return access; -} - -PHLIBAPI -_Callback_ NTSTATUS -NTAPI -PhStdGetObjectSecurity( - _Out_ PSECURITY_DESCRIPTOR *SecurityDescriptor, - _In_ SECURITY_INFORMATION SecurityInformation, - _In_opt_ PVOID Context - ); - -PHLIBAPI -_Callback_ NTSTATUS -NTAPI -PhStdSetObjectSecurity( - _In_ PSECURITY_DESCRIPTOR SecurityDescriptor, - _In_ SECURITY_INFORMATION SecurityInformation, - _In_opt_ PVOID Context - ); - -PHLIBAPI -NTSTATUS -NTAPI -PhGetSeObjectSecurity( - _In_ HANDLE Handle, - _In_ ULONG ObjectType, - _In_ SECURITY_INFORMATION SecurityInformation, - _Out_ PSECURITY_DESCRIPTOR *SecurityDescriptor - ); - -PHLIBAPI -NTSTATUS -NTAPI -PhSetSeObjectSecurity( - _In_ HANDLE Handle, - _In_ ULONG ObjectType, - _In_ SECURITY_INFORMATION SecurityInformation, - _In_ PSECURITY_DESCRIPTOR SecurityDescriptor - ); - -// secdata - -PHLIBAPI -BOOLEAN -NTAPI -PhGetAccessEntries( - _In_ PWSTR Type, - _Out_ PPH_ACCESS_ENTRY *AccessEntries, - _Out_ PULONG NumberOfAccessEntries - ); - -PHLIBAPI -PPH_STRING -NTAPI -PhGetAccessString( - _In_ ACCESS_MASK Access, - _In_ PPH_ACCESS_ENTRY AccessEntries, - _In_ ULONG NumberOfAccessEntries - ); - -#ifdef __cplusplus -} -#endif - +#ifndef _PH_SECEDIT_H +#define _PH_SECEDIT_H + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct _PSP *HPROPSHEETPAGE; + +// secedit + +typedef struct _PH_ACCESS_ENTRY +{ + PWSTR Name; + ACCESS_MASK Access; + BOOLEAN General; + BOOLEAN Specific; + PWSTR ShortName; +} PH_ACCESS_ENTRY, *PPH_ACCESS_ENTRY; + +PHLIBAPI +HPROPSHEETPAGE +NTAPI +PhCreateSecurityPage( + _In_ PWSTR ObjectName, + _In_ PPH_GET_OBJECT_SECURITY GetObjectSecurity, + _In_ PPH_SET_OBJECT_SECURITY SetObjectSecurity, + _In_opt_ PVOID Context, + _In_ PPH_ACCESS_ENTRY AccessEntries, + _In_ ULONG NumberOfAccessEntries + ); + +PHLIBAPI +VOID +NTAPI +PhEditSecurity( + _In_ HWND hWnd, + _In_ PWSTR ObjectName, + _In_ PPH_GET_OBJECT_SECURITY GetObjectSecurity, + _In_ PPH_SET_OBJECT_SECURITY SetObjectSecurity, + _In_opt_ PVOID Context, + _In_ PPH_ACCESS_ENTRY AccessEntries, + _In_ ULONG NumberOfAccessEntries + ); + +typedef struct _PH_STD_OBJECT_SECURITY +{ + PPH_OPEN_OBJECT OpenObject; + PWSTR ObjectType; + PVOID Context; +} PH_STD_OBJECT_SECURITY, *PPH_STD_OBJECT_SECURITY; + +FORCEINLINE ACCESS_MASK PhGetAccessForGetSecurity( + _In_ SECURITY_INFORMATION SecurityInformation + ) +{ + ACCESS_MASK access = 0; + + if ( + (SecurityInformation & OWNER_SECURITY_INFORMATION) || + (SecurityInformation & GROUP_SECURITY_INFORMATION) || + (SecurityInformation & DACL_SECURITY_INFORMATION) + ) + { + access |= READ_CONTROL; + } + + if (SecurityInformation & SACL_SECURITY_INFORMATION) + { + access |= ACCESS_SYSTEM_SECURITY; + } + + return access; +} + +FORCEINLINE ACCESS_MASK PhGetAccessForSetSecurity( + _In_ SECURITY_INFORMATION SecurityInformation + ) +{ + ACCESS_MASK access = 0; + + if ( + (SecurityInformation & OWNER_SECURITY_INFORMATION) || + (SecurityInformation & GROUP_SECURITY_INFORMATION) + ) + { + access |= WRITE_OWNER; + } + + if (SecurityInformation & DACL_SECURITY_INFORMATION) + { + access |= WRITE_DAC; + } + + if (SecurityInformation & SACL_SECURITY_INFORMATION) + { + access |= ACCESS_SYSTEM_SECURITY; + } + + return access; +} + +PHLIBAPI +_Callback_ NTSTATUS +NTAPI +PhStdGetObjectSecurity( + _Out_ PSECURITY_DESCRIPTOR *SecurityDescriptor, + _In_ SECURITY_INFORMATION SecurityInformation, + _In_opt_ PVOID Context + ); + +PHLIBAPI +_Callback_ NTSTATUS +NTAPI +PhStdSetObjectSecurity( + _In_ PSECURITY_DESCRIPTOR SecurityDescriptor, + _In_ SECURITY_INFORMATION SecurityInformation, + _In_opt_ PVOID Context + ); + +PHLIBAPI +NTSTATUS +NTAPI +PhGetSeObjectSecurity( + _In_ HANDLE Handle, + _In_ ULONG ObjectType, + _In_ SECURITY_INFORMATION SecurityInformation, + _Out_ PSECURITY_DESCRIPTOR *SecurityDescriptor + ); + +PHLIBAPI +NTSTATUS +NTAPI +PhSetSeObjectSecurity( + _In_ HANDLE Handle, + _In_ ULONG ObjectType, + _In_ SECURITY_INFORMATION SecurityInformation, + _In_ PSECURITY_DESCRIPTOR SecurityDescriptor + ); + +// secdata + +PHLIBAPI +BOOLEAN +NTAPI +PhGetAccessEntries( + _In_ PWSTR Type, + _Out_ PPH_ACCESS_ENTRY *AccessEntries, + _Out_ PULONG NumberOfAccessEntries + ); + +PHLIBAPI +PPH_STRING +NTAPI +PhGetAccessString( + _In_ ACCESS_MASK Access, + _In_ PPH_ACCESS_ENTRY AccessEntries, + _In_ ULONG NumberOfAccessEntries + ); + +#ifdef __cplusplus +} +#endif + #endif \ No newline at end of file diff --git a/phlib/include/seceditp.h b/phlib/include/seceditp.h index e2773866fc1c..d90cfd43d76c 100644 --- a/phlib/include/seceditp.h +++ b/phlib/include/seceditp.h @@ -1,93 +1,93 @@ -#ifndef _PH_SECEDITP_H -#define _PH_SECEDITP_H - -#include -#include - -typedef struct -{ - ISecurityInformationVtbl *VTable; - - ULONG RefCount; - - PPH_STRING ObjectName; - PPH_GET_OBJECT_SECURITY GetObjectSecurity; - PPH_SET_OBJECT_SECURITY SetObjectSecurity; - PVOID Context; - PSI_ACCESS AccessEntries; - ULONG NumberOfAccessEntries; - BOOLEAN IsPage; -} PhSecurityInformation; - -ISecurityInformation *PhSecurityInformation_Create( - _In_ PWSTR ObjectName, - _In_ PPH_GET_OBJECT_SECURITY GetObjectSecurity, - _In_ PPH_SET_OBJECT_SECURITY SetObjectSecurity, - _In_opt_ PVOID Context, - _In_ PPH_ACCESS_ENTRY AccessEntries, - _In_ ULONG NumberOfAccessEntries, - _In_ BOOLEAN IsPage - ); - -HRESULT STDMETHODCALLTYPE PhSecurityInformation_QueryInterface( - _In_ ISecurityInformation *This, - _In_ REFIID Riid, - _Out_ PVOID *Object - ); - -ULONG STDMETHODCALLTYPE PhSecurityInformation_AddRef( - _In_ ISecurityInformation *This - ); - -ULONG STDMETHODCALLTYPE PhSecurityInformation_Release( - _In_ ISecurityInformation *This - ); - -HRESULT STDMETHODCALLTYPE PhSecurityInformation_GetObjectInformation( - _In_ ISecurityInformation *This, - _Out_ PSI_OBJECT_INFO ObjectInfo - ); - -HRESULT STDMETHODCALLTYPE PhSecurityInformation_GetSecurity( - _In_ ISecurityInformation *This, - _In_ SECURITY_INFORMATION RequestedInformation, - _Out_ PSECURITY_DESCRIPTOR *SecurityDescriptor, - _In_ BOOL Default - ); - -HRESULT STDMETHODCALLTYPE PhSecurityInformation_SetSecurity( - _In_ ISecurityInformation *This, - _In_ SECURITY_INFORMATION SecurityInformation, - _In_ PSECURITY_DESCRIPTOR SecurityDescriptor - ); - -HRESULT STDMETHODCALLTYPE PhSecurityInformation_GetAccessRights( - _In_ ISecurityInformation *This, - _In_ const GUID *ObjectType, - _In_ ULONG Flags, - _Out_ PSI_ACCESS *Access, - _Out_ PULONG Accesses, - _Out_ PULONG DefaultAccess - ); - -HRESULT STDMETHODCALLTYPE PhSecurityInformation_MapGeneric( - _In_ ISecurityInformation *This, - _In_ const GUID *ObjectType, - _In_ PUCHAR AceFlags, - _Inout_ PACCESS_MASK Mask - ); - -HRESULT STDMETHODCALLTYPE PhSecurityInformation_GetInheritTypes( - _In_ ISecurityInformation *This, - _Out_ PSI_INHERIT_TYPE *InheritTypes, - _Out_ PULONG InheritTypesCount - ); - -HRESULT STDMETHODCALLTYPE PhSecurityInformation_PropertySheetPageCallback( - _In_ ISecurityInformation *This, - _In_ HWND hwnd, - _In_ UINT uMsg, - _In_ SI_PAGE_TYPE uPage - ); - -#endif +#ifndef _PH_SECEDITP_H +#define _PH_SECEDITP_H + +#include +#include + +typedef struct +{ + ISecurityInformationVtbl *VTable; + + ULONG RefCount; + + PPH_STRING ObjectName; + PPH_GET_OBJECT_SECURITY GetObjectSecurity; + PPH_SET_OBJECT_SECURITY SetObjectSecurity; + PVOID Context; + PSI_ACCESS AccessEntries; + ULONG NumberOfAccessEntries; + BOOLEAN IsPage; +} PhSecurityInformation; + +ISecurityInformation *PhSecurityInformation_Create( + _In_ PWSTR ObjectName, + _In_ PPH_GET_OBJECT_SECURITY GetObjectSecurity, + _In_ PPH_SET_OBJECT_SECURITY SetObjectSecurity, + _In_opt_ PVOID Context, + _In_ PPH_ACCESS_ENTRY AccessEntries, + _In_ ULONG NumberOfAccessEntries, + _In_ BOOLEAN IsPage + ); + +HRESULT STDMETHODCALLTYPE PhSecurityInformation_QueryInterface( + _In_ ISecurityInformation *This, + _In_ REFIID Riid, + _Out_ PVOID *Object + ); + +ULONG STDMETHODCALLTYPE PhSecurityInformation_AddRef( + _In_ ISecurityInformation *This + ); + +ULONG STDMETHODCALLTYPE PhSecurityInformation_Release( + _In_ ISecurityInformation *This + ); + +HRESULT STDMETHODCALLTYPE PhSecurityInformation_GetObjectInformation( + _In_ ISecurityInformation *This, + _Out_ PSI_OBJECT_INFO ObjectInfo + ); + +HRESULT STDMETHODCALLTYPE PhSecurityInformation_GetSecurity( + _In_ ISecurityInformation *This, + _In_ SECURITY_INFORMATION RequestedInformation, + _Out_ PSECURITY_DESCRIPTOR *SecurityDescriptor, + _In_ BOOL Default + ); + +HRESULT STDMETHODCALLTYPE PhSecurityInformation_SetSecurity( + _In_ ISecurityInformation *This, + _In_ SECURITY_INFORMATION SecurityInformation, + _In_ PSECURITY_DESCRIPTOR SecurityDescriptor + ); + +HRESULT STDMETHODCALLTYPE PhSecurityInformation_GetAccessRights( + _In_ ISecurityInformation *This, + _In_ const GUID *ObjectType, + _In_ ULONG Flags, + _Out_ PSI_ACCESS *Access, + _Out_ PULONG Accesses, + _Out_ PULONG DefaultAccess + ); + +HRESULT STDMETHODCALLTYPE PhSecurityInformation_MapGeneric( + _In_ ISecurityInformation *This, + _In_ const GUID *ObjectType, + _In_ PUCHAR AceFlags, + _Inout_ PACCESS_MASK Mask + ); + +HRESULT STDMETHODCALLTYPE PhSecurityInformation_GetInheritTypes( + _In_ ISecurityInformation *This, + _Out_ PSI_INHERIT_TYPE *InheritTypes, + _Out_ PULONG InheritTypesCount + ); + +HRESULT STDMETHODCALLTYPE PhSecurityInformation_PropertySheetPageCallback( + _In_ ISecurityInformation *This, + _In_ HWND hwnd, + _In_ UINT uMsg, + _In_ SI_PAGE_TYPE uPage + ); + +#endif diff --git a/phlib/include/symprv.h b/phlib/include/symprv.h index 742f1148d39f..4d02924180bf 100644 --- a/phlib/include/symprv.h +++ b/phlib/include/symprv.h @@ -1,303 +1,303 @@ -#ifndef _PH_SYMPRV_H -#define _PH_SYMPRV_H - -#ifdef __cplusplus -extern "C" { -#endif - -extern PPH_OBJECT_TYPE PhSymbolProviderType; -extern PH_CALLBACK PhSymInitCallback; - -#define PH_MAX_SYMBOL_NAME_LEN 128 - -typedef struct _PH_SYMBOL_PROVIDER -{ - LIST_ENTRY ModulesListHead; - PH_QUEUED_LOCK ModulesListLock; - HANDLE ProcessHandle; - BOOLEAN IsRealHandle; - BOOLEAN IsRegistered; - - PH_INITONCE InitOnce; - PH_AVL_TREE ModulesSet; - PH_CALLBACK EventCallback; -} PH_SYMBOL_PROVIDER, *PPH_SYMBOL_PROVIDER; - -typedef enum _PH_SYMBOL_RESOLVE_LEVEL -{ - PhsrlFunction, - PhsrlModule, - PhsrlAddress, - PhsrlInvalid -} PH_SYMBOL_RESOLVE_LEVEL, *PPH_SYMBOL_RESOLVE_LEVEL; - -typedef struct _PH_SYMBOL_INFORMATION -{ - ULONG64 Address; - ULONG64 ModuleBase; - ULONG Index; - ULONG Size; -} PH_SYMBOL_INFORMATION, *PPH_SYMBOL_INFORMATION; - -typedef struct _PH_SYMBOL_LINE_INFORMATION -{ - ULONG LineNumber; - ULONG64 Address; -} PH_SYMBOL_LINE_INFORMATION, *PPH_SYMBOL_LINE_INFORMATION; - -typedef enum _PH_SYMBOL_EVENT_TYPE -{ - SymbolDeferredSymbolLoadStart = 1, - SymbolDeferredSymbolLoadComplete = 2, - SymbolDeferredSymbolLoadFailure = 3, - SymbolSymbolsUnloaded = 4, - SymbolDeferredSymbolLoadCancel = 7 -} PH_SYMBOL_EVENT_TYPE; - -typedef struct _PH_SYMBOL_EVENT_DATA -{ - PPH_SYMBOL_PROVIDER SymbolProvider; - PH_SYMBOL_EVENT_TYPE Type; - - ULONG64 BaseAddress; - ULONG CheckSum; - ULONG TimeStamp; - PPH_STRING FileName; -} PH_SYMBOL_EVENT_DATA, *PPH_SYMBOL_EVENT_DATA; - -PHLIBAPI -BOOLEAN -NTAPI -PhSymbolProviderInitialization( - VOID - ); - -PHLIBAPI -VOID -NTAPI -PhSymbolProviderCompleteInitialization( - _In_opt_ PVOID DbgHelpBase - ); - -PHLIBAPI -PPH_SYMBOL_PROVIDER -NTAPI -PhCreateSymbolProvider( - _In_opt_ HANDLE ProcessId - ); - -PHLIBAPI -BOOLEAN -NTAPI -PhGetLineFromAddress( - _In_ PPH_SYMBOL_PROVIDER SymbolProvider, - _In_ ULONG64 Address, - _Out_ PPH_STRING *FileName, - _Out_opt_ PULONG Displacement, - _Out_opt_ PPH_SYMBOL_LINE_INFORMATION Information - ); - -PHLIBAPI -ULONG64 -NTAPI -PhGetModuleFromAddress( - _In_ PPH_SYMBOL_PROVIDER SymbolProvider, - _In_ ULONG64 Address, - _Out_opt_ PPH_STRING *FileName - ); - -PHLIBAPI -PPH_STRING -NTAPI -PhGetSymbolFromAddress( - _In_ PPH_SYMBOL_PROVIDER SymbolProvider, - _In_ ULONG64 Address, - _Out_opt_ PPH_SYMBOL_RESOLVE_LEVEL ResolveLevel, - _Out_opt_ PPH_STRING *FileName, - _Out_opt_ PPH_STRING *SymbolName, - _Out_opt_ PULONG64 Displacement - ); - -PHLIBAPI -BOOLEAN -NTAPI -PhGetSymbolFromName( - _In_ PPH_SYMBOL_PROVIDER SymbolProvider, - _In_ PWSTR Name, - _Out_ PPH_SYMBOL_INFORMATION Information - ); - -PHLIBAPI -BOOLEAN -NTAPI -PhLoadModuleSymbolProvider( - _In_ PPH_SYMBOL_PROVIDER SymbolProvider, - _In_ PWSTR FileName, - _In_ ULONG64 BaseAddress, - _In_ ULONG Size - ); - -PHLIBAPI -VOID -NTAPI -PhSetOptionsSymbolProvider( - _In_ ULONG Mask, - _In_ ULONG Value - ); - -PHLIBAPI -VOID -NTAPI -PhSetSearchPathSymbolProvider( - _In_ PPH_SYMBOL_PROVIDER SymbolProvider, - _In_ PWSTR Path - ); - -#ifdef _WIN64 -PHLIBAPI -NTSTATUS -NTAPI -PhAccessOutOfProcessFunctionEntry( - _In_ HANDLE ProcessHandle, - _In_ ULONG64 ControlPc, - _Out_ PRUNTIME_FUNCTION Function - ); -#endif - -PHLIBAPI -ULONG64 -__stdcall -PhGetModuleBase64( - _In_ HANDLE hProcess, - _In_ DWORD64 dwAddr - ); - -PHLIBAPI -PVOID -__stdcall -PhFunctionTableAccess64( - _In_ HANDLE hProcess, - _In_ DWORD64 AddrBase - ); - -#ifndef _DBGHELP_ - -// Some of the types used below are defined in dbghelp.h. - -typedef struct _tagSTACKFRAME64 *LPSTACKFRAME64; -typedef struct _tagADDRESS64 *LPADDRESS64; - -typedef BOOL (__stdcall *PREAD_PROCESS_MEMORY_ROUTINE64)( - _In_ HANDLE hProcess, - _In_ DWORD64 qwBaseAddress, - _Out_writes_bytes_(nSize) PVOID lpBuffer, - _In_ DWORD nSize, - _Out_ LPDWORD lpNumberOfBytesRead - ); - -typedef PVOID (__stdcall *PFUNCTION_TABLE_ACCESS_ROUTINE64)( - _In_ HANDLE ahProcess, - _In_ DWORD64 AddrBase - ); - -typedef DWORD64 (__stdcall *PGET_MODULE_BASE_ROUTINE64)( - _In_ HANDLE hProcess, - _In_ DWORD64 Address - ); - -typedef DWORD64 (__stdcall *PTRANSLATE_ADDRESS_ROUTINE64)( - _In_ HANDLE hProcess, - _In_ HANDLE hThread, - _In_ LPADDRESS64 lpaddr - ); - -typedef enum _MINIDUMP_TYPE MINIDUMP_TYPE; -typedef struct _MINIDUMP_EXCEPTION_INFORMATION *PMINIDUMP_EXCEPTION_INFORMATION; -typedef struct _MINIDUMP_USER_STREAM_INFORMATION *PMINIDUMP_USER_STREAM_INFORMATION; -typedef struct _MINIDUMP_CALLBACK_INFORMATION *PMINIDUMP_CALLBACK_INFORMATION; - -#endif - -PHLIBAPI -BOOLEAN -NTAPI -PhStackWalk( - _In_ ULONG MachineType, - _In_ HANDLE ProcessHandle, - _In_ HANDLE ThreadHandle, - _Inout_ LPSTACKFRAME64 StackFrame, - _Inout_ PVOID ContextRecord, - _In_opt_ PPH_SYMBOL_PROVIDER SymbolProvider, - _In_opt_ PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine, - _In_opt_ PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine, - _In_opt_ PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine, - _In_opt_ PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress - ); - -PHLIBAPI -BOOLEAN -NTAPI -PhWriteMiniDumpProcess( - _In_ HANDLE ProcessHandle, - _In_ HANDLE ProcessId, - _In_ HANDLE FileHandle, - _In_ MINIDUMP_TYPE DumpType, - _In_opt_ PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, - _In_opt_ PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam, - _In_opt_ PMINIDUMP_CALLBACK_INFORMATION CallbackParam - ); - -// High-level stack walking - -#define PH_THREAD_STACK_FRAME_I386 0x1 -#define PH_THREAD_STACK_FRAME_AMD64 0x2 -#define PH_THREAD_STACK_FRAME_KERNEL 0x4 -#define PH_THREAD_STACK_FRAME_FPO_DATA_PRESENT 0x100 - -/** Contains information about a thread stack frame. */ -typedef struct _PH_THREAD_STACK_FRAME -{ - PVOID PcAddress; - PVOID ReturnAddress; - PVOID FrameAddress; - PVOID StackAddress; - PVOID BStoreAddress; - PVOID Params[4]; - ULONG Flags; -} PH_THREAD_STACK_FRAME, *PPH_THREAD_STACK_FRAME; - -#define PH_WALK_I386_STACK 0x1 -#define PH_WALK_AMD64_STACK 0x2 -#define PH_WALK_KERNEL_STACK 0x10 - -/** - * A callback function passed to PhWalkThreadStack() and called for each stack frame. - * - * \param StackFrame A structure providing information about the stack frame. - * \param Context A user-defined value passed to PhWalkThreadStack(). - * - * \return TRUE to continue the stack walk, FALSE to stop. - */ -typedef BOOLEAN (NTAPI *PPH_WALK_THREAD_STACK_CALLBACK)( - _In_ PPH_THREAD_STACK_FRAME StackFrame, - _In_opt_ PVOID Context - ); - -PHLIBAPI -NTSTATUS -NTAPI -PhWalkThreadStack( - _In_ HANDLE ThreadHandle, - _In_opt_ HANDLE ProcessHandle, - _In_opt_ PCLIENT_ID ClientId, - _In_opt_ PPH_SYMBOL_PROVIDER SymbolProvider, - _In_ ULONG Flags, - _In_ PPH_WALK_THREAD_STACK_CALLBACK Callback, - _In_opt_ PVOID Context - ); - -#ifdef __cplusplus -} -#endif - -#endif +#ifndef _PH_SYMPRV_H +#define _PH_SYMPRV_H + +#ifdef __cplusplus +extern "C" { +#endif + +extern PPH_OBJECT_TYPE PhSymbolProviderType; +extern PH_CALLBACK PhSymInitCallback; + +#define PH_MAX_SYMBOL_NAME_LEN 128 + +typedef struct _PH_SYMBOL_PROVIDER +{ + LIST_ENTRY ModulesListHead; + PH_QUEUED_LOCK ModulesListLock; + HANDLE ProcessHandle; + BOOLEAN IsRealHandle; + BOOLEAN IsRegistered; + + PH_INITONCE InitOnce; + PH_AVL_TREE ModulesSet; + PH_CALLBACK EventCallback; +} PH_SYMBOL_PROVIDER, *PPH_SYMBOL_PROVIDER; + +typedef enum _PH_SYMBOL_RESOLVE_LEVEL +{ + PhsrlFunction, + PhsrlModule, + PhsrlAddress, + PhsrlInvalid +} PH_SYMBOL_RESOLVE_LEVEL, *PPH_SYMBOL_RESOLVE_LEVEL; + +typedef struct _PH_SYMBOL_INFORMATION +{ + ULONG64 Address; + ULONG64 ModuleBase; + ULONG Index; + ULONG Size; +} PH_SYMBOL_INFORMATION, *PPH_SYMBOL_INFORMATION; + +typedef struct _PH_SYMBOL_LINE_INFORMATION +{ + ULONG LineNumber; + ULONG64 Address; +} PH_SYMBOL_LINE_INFORMATION, *PPH_SYMBOL_LINE_INFORMATION; + +typedef enum _PH_SYMBOL_EVENT_TYPE +{ + SymbolDeferredSymbolLoadStart = 1, + SymbolDeferredSymbolLoadComplete = 2, + SymbolDeferredSymbolLoadFailure = 3, + SymbolSymbolsUnloaded = 4, + SymbolDeferredSymbolLoadCancel = 7 +} PH_SYMBOL_EVENT_TYPE; + +typedef struct _PH_SYMBOL_EVENT_DATA +{ + PPH_SYMBOL_PROVIDER SymbolProvider; + PH_SYMBOL_EVENT_TYPE Type; + + ULONG64 BaseAddress; + ULONG CheckSum; + ULONG TimeStamp; + PPH_STRING FileName; +} PH_SYMBOL_EVENT_DATA, *PPH_SYMBOL_EVENT_DATA; + +PHLIBAPI +BOOLEAN +NTAPI +PhSymbolProviderInitialization( + VOID + ); + +PHLIBAPI +VOID +NTAPI +PhSymbolProviderCompleteInitialization( + _In_opt_ PVOID DbgHelpBase + ); + +PHLIBAPI +PPH_SYMBOL_PROVIDER +NTAPI +PhCreateSymbolProvider( + _In_opt_ HANDLE ProcessId + ); + +PHLIBAPI +BOOLEAN +NTAPI +PhGetLineFromAddress( + _In_ PPH_SYMBOL_PROVIDER SymbolProvider, + _In_ ULONG64 Address, + _Out_ PPH_STRING *FileName, + _Out_opt_ PULONG Displacement, + _Out_opt_ PPH_SYMBOL_LINE_INFORMATION Information + ); + +PHLIBAPI +ULONG64 +NTAPI +PhGetModuleFromAddress( + _In_ PPH_SYMBOL_PROVIDER SymbolProvider, + _In_ ULONG64 Address, + _Out_opt_ PPH_STRING *FileName + ); + +PHLIBAPI +PPH_STRING +NTAPI +PhGetSymbolFromAddress( + _In_ PPH_SYMBOL_PROVIDER SymbolProvider, + _In_ ULONG64 Address, + _Out_opt_ PPH_SYMBOL_RESOLVE_LEVEL ResolveLevel, + _Out_opt_ PPH_STRING *FileName, + _Out_opt_ PPH_STRING *SymbolName, + _Out_opt_ PULONG64 Displacement + ); + +PHLIBAPI +BOOLEAN +NTAPI +PhGetSymbolFromName( + _In_ PPH_SYMBOL_PROVIDER SymbolProvider, + _In_ PWSTR Name, + _Out_ PPH_SYMBOL_INFORMATION Information + ); + +PHLIBAPI +BOOLEAN +NTAPI +PhLoadModuleSymbolProvider( + _In_ PPH_SYMBOL_PROVIDER SymbolProvider, + _In_ PWSTR FileName, + _In_ ULONG64 BaseAddress, + _In_ ULONG Size + ); + +PHLIBAPI +VOID +NTAPI +PhSetOptionsSymbolProvider( + _In_ ULONG Mask, + _In_ ULONG Value + ); + +PHLIBAPI +VOID +NTAPI +PhSetSearchPathSymbolProvider( + _In_ PPH_SYMBOL_PROVIDER SymbolProvider, + _In_ PWSTR Path + ); + +#ifdef _WIN64 +PHLIBAPI +NTSTATUS +NTAPI +PhAccessOutOfProcessFunctionEntry( + _In_ HANDLE ProcessHandle, + _In_ ULONG64 ControlPc, + _Out_ PRUNTIME_FUNCTION Function + ); +#endif + +PHLIBAPI +ULONG64 +__stdcall +PhGetModuleBase64( + _In_ HANDLE hProcess, + _In_ DWORD64 dwAddr + ); + +PHLIBAPI +PVOID +__stdcall +PhFunctionTableAccess64( + _In_ HANDLE hProcess, + _In_ DWORD64 AddrBase + ); + +#ifndef _DBGHELP_ + +// Some of the types used below are defined in dbghelp.h. + +typedef struct _tagSTACKFRAME64 *LPSTACKFRAME64; +typedef struct _tagADDRESS64 *LPADDRESS64; + +typedef BOOL (__stdcall *PREAD_PROCESS_MEMORY_ROUTINE64)( + _In_ HANDLE hProcess, + _In_ DWORD64 qwBaseAddress, + _Out_writes_bytes_(nSize) PVOID lpBuffer, + _In_ DWORD nSize, + _Out_ LPDWORD lpNumberOfBytesRead + ); + +typedef PVOID (__stdcall *PFUNCTION_TABLE_ACCESS_ROUTINE64)( + _In_ HANDLE ahProcess, + _In_ DWORD64 AddrBase + ); + +typedef DWORD64 (__stdcall *PGET_MODULE_BASE_ROUTINE64)( + _In_ HANDLE hProcess, + _In_ DWORD64 Address + ); + +typedef DWORD64 (__stdcall *PTRANSLATE_ADDRESS_ROUTINE64)( + _In_ HANDLE hProcess, + _In_ HANDLE hThread, + _In_ LPADDRESS64 lpaddr + ); + +typedef enum _MINIDUMP_TYPE MINIDUMP_TYPE; +typedef struct _MINIDUMP_EXCEPTION_INFORMATION *PMINIDUMP_EXCEPTION_INFORMATION; +typedef struct _MINIDUMP_USER_STREAM_INFORMATION *PMINIDUMP_USER_STREAM_INFORMATION; +typedef struct _MINIDUMP_CALLBACK_INFORMATION *PMINIDUMP_CALLBACK_INFORMATION; + +#endif + +PHLIBAPI +BOOLEAN +NTAPI +PhStackWalk( + _In_ ULONG MachineType, + _In_ HANDLE ProcessHandle, + _In_ HANDLE ThreadHandle, + _Inout_ LPSTACKFRAME64 StackFrame, + _Inout_ PVOID ContextRecord, + _In_opt_ PPH_SYMBOL_PROVIDER SymbolProvider, + _In_opt_ PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine, + _In_opt_ PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine, + _In_opt_ PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine, + _In_opt_ PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress + ); + +PHLIBAPI +BOOLEAN +NTAPI +PhWriteMiniDumpProcess( + _In_ HANDLE ProcessHandle, + _In_ HANDLE ProcessId, + _In_ HANDLE FileHandle, + _In_ MINIDUMP_TYPE DumpType, + _In_opt_ PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, + _In_opt_ PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam, + _In_opt_ PMINIDUMP_CALLBACK_INFORMATION CallbackParam + ); + +// High-level stack walking + +#define PH_THREAD_STACK_FRAME_I386 0x1 +#define PH_THREAD_STACK_FRAME_AMD64 0x2 +#define PH_THREAD_STACK_FRAME_KERNEL 0x4 +#define PH_THREAD_STACK_FRAME_FPO_DATA_PRESENT 0x100 + +/** Contains information about a thread stack frame. */ +typedef struct _PH_THREAD_STACK_FRAME +{ + PVOID PcAddress; + PVOID ReturnAddress; + PVOID FrameAddress; + PVOID StackAddress; + PVOID BStoreAddress; + PVOID Params[4]; + ULONG Flags; +} PH_THREAD_STACK_FRAME, *PPH_THREAD_STACK_FRAME; + +#define PH_WALK_I386_STACK 0x1 +#define PH_WALK_AMD64_STACK 0x2 +#define PH_WALK_KERNEL_STACK 0x10 + +/** + * A callback function passed to PhWalkThreadStack() and called for each stack frame. + * + * \param StackFrame A structure providing information about the stack frame. + * \param Context A user-defined value passed to PhWalkThreadStack(). + * + * \return TRUE to continue the stack walk, FALSE to stop. + */ +typedef BOOLEAN (NTAPI *PPH_WALK_THREAD_STACK_CALLBACK)( + _In_ PPH_THREAD_STACK_FRAME StackFrame, + _In_opt_ PVOID Context + ); + +PHLIBAPI +NTSTATUS +NTAPI +PhWalkThreadStack( + _In_ HANDLE ThreadHandle, + _In_opt_ HANDLE ProcessHandle, + _In_opt_ PCLIENT_ID ClientId, + _In_opt_ PPH_SYMBOL_PROVIDER SymbolProvider, + _In_ ULONG Flags, + _In_ PPH_WALK_THREAD_STACK_CALLBACK Callback, + _In_opt_ PVOID Context + ); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/phlib/include/symprvp.h b/phlib/include/symprvp.h index 8f6bd6bb580e..e4435bfc9bb0 100644 --- a/phlib/include/symprvp.h +++ b/phlib/include/symprvp.h @@ -1,170 +1,170 @@ -#ifndef _PH_SYMPRVP_H -#define _PH_SYMPRVP_H - -typedef BOOL (WINAPI *_SymInitialize)( - _In_ HANDLE hProcess, - _In_opt_ PCSTR UserSearchPath, - _In_ BOOL fInvadeProcess - ); - -typedef BOOL (WINAPI *_SymCleanup)( - _In_ HANDLE hProcess - ); - -typedef BOOL (WINAPI *_SymEnumSymbols)( - _In_ HANDLE hProcess, - _In_ ULONG64 BaseOfDll, - _In_opt_ PCSTR Mask, - _In_ PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback, - _In_opt_ const PVOID UserContext - ); - -typedef BOOL (WINAPI *_SymEnumSymbolsW)( - _In_ HANDLE hProcess, - _In_ ULONG64 BaseOfDll, - _In_opt_ PCWSTR Mask, - _In_ PSYM_ENUMERATESYMBOLS_CALLBACKW EnumSymbolsCallback, - _In_opt_ const PVOID UserContext - ); - -typedef BOOL (WINAPI *_SymFromAddr)( - _In_ HANDLE hProcess, - _In_ DWORD64 Address, - _Out_opt_ PDWORD64 Displacement, - _Inout_ PSYMBOL_INFO Symbol - ); - -typedef BOOL (WINAPI *_SymFromAddrW)( - _In_ HANDLE hProcess, - _In_ DWORD64 Address, - _Out_opt_ PDWORD64 Displacement, - _Inout_ PSYMBOL_INFOW Symbol - ); - -typedef BOOL (WINAPI *_SymFromName)( - _In_ HANDLE hProcess, - _In_ PCSTR Name, - _Inout_ PSYMBOL_INFO Symbol - ); - -typedef BOOL (WINAPI *_SymFromNameW)( - _In_ HANDLE hProcess, - _In_ PCWSTR Name, - _Inout_ PSYMBOL_INFOW Symbol - ); - -typedef BOOL (WINAPI *_SymGetLineFromAddr64)( - _In_ HANDLE hProcess, - _In_ DWORD64 dwAddr, - _Out_ PDWORD pdwDisplacement, - _Out_ PIMAGEHLP_LINE64 Line - ); - -typedef BOOL (WINAPI *_SymGetLineFromAddrW64)( - _In_ HANDLE hProcess, - _In_ DWORD64 dwAddr, - _Out_ PDWORD pdwDisplacement, - _Out_ PIMAGEHLP_LINEW64 Line - ); - -typedef DWORD64 (WINAPI *_SymLoadModule64)( - _In_ HANDLE hProcess, - _In_opt_ HANDLE hFile, - _In_opt_ PCSTR ImageName, - _In_opt_ PCSTR ModuleName, - _In_ DWORD64 BaseOfDll, - _In_ DWORD SizeOfDll - ); - -typedef DWORD64 (WINAPI *_SymLoadModuleExW)( - _In_ HANDLE hProcess, - _In_ HANDLE hFile, - _In_ PCWSTR ImageName, - _In_ PCWSTR ModuleName, - _In_ DWORD64 BaseOfDll, - _In_ DWORD DllSize, - _In_ PMODLOAD_DATA Data, - _In_ DWORD Flags - ); - -typedef DWORD (WINAPI *_SymGetOptions)(); - -typedef DWORD (WINAPI *_SymSetOptions)( - _In_ DWORD SymOptions - ); - -typedef BOOL (WINAPI *_SymGetSearchPath)( - _In_ HANDLE hProcess, - _Out_ PSTR SearchPath, - _In_ DWORD SearchPathLength - ); - -typedef BOOL (WINAPI *_SymGetSearchPathW)( - _In_ HANDLE hProcess, - _Out_ PWSTR SearchPath, - _In_ DWORD SearchPathLength - ); - -typedef BOOL (WINAPI *_SymSetSearchPath)( - _In_ HANDLE hProcess, - _In_opt_ PCSTR SearchPath - ); - -typedef BOOL (WINAPI *_SymSetSearchPathW)( - _In_ HANDLE hProcess, - _In_opt_ PCWSTR SearchPath - ); - -typedef BOOL (WINAPI *_SymUnloadModule64)( - _In_ HANDLE hProcess, - _In_ DWORD64 BaseOfDll - ); - -typedef PVOID (WINAPI *_SymFunctionTableAccess64)( - _In_ HANDLE hProcess, - _In_ DWORD64 AddrBase - ); - -typedef DWORD64 (WINAPI *_SymGetModuleBase64)( - _In_ HANDLE hProcess, - _In_ DWORD64 dwAddr - ); - -typedef BOOL (WINAPI *_SymRegisterCallbackW64)( - _In_ HANDLE hProcess, - _In_ PSYMBOL_REGISTERED_CALLBACK64 CallbackFunction, - _In_ ULONG64 UserContext - ); - -typedef BOOL (WINAPI *_StackWalk64)( - _In_ DWORD MachineType, - _In_ HANDLE hProcess, - _In_ HANDLE hThread, - _Inout_ LPSTACKFRAME64 StackFrame, - _Inout_ PVOID ContextRecord, - _In_opt_ PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine, - _In_opt_ PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine, - _In_opt_ PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine, - _In_opt_ PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress - ); - -typedef BOOL (WINAPI *_MiniDumpWriteDump)( - _In_ HANDLE hProcess, - _In_ DWORD ProcessId, - _In_ HANDLE hFile, - _In_ MINIDUMP_TYPE DumpType, - _In_ PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, - _In_ PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam, - _In_ PMINIDUMP_CALLBACK_INFORMATION CallbackParam - ); - -typedef UINT_PTR (CALLBACK *_SymbolServerGetOptions)( - VOID - ); - -typedef BOOL (CALLBACK *_SymbolServerSetOptions)( - _In_ UINT_PTR options, - _In_ ULONG64 data - ); - +#ifndef _PH_SYMPRVP_H +#define _PH_SYMPRVP_H + +typedef BOOL (WINAPI *_SymInitialize)( + _In_ HANDLE hProcess, + _In_opt_ PCSTR UserSearchPath, + _In_ BOOL fInvadeProcess + ); + +typedef BOOL (WINAPI *_SymCleanup)( + _In_ HANDLE hProcess + ); + +typedef BOOL (WINAPI *_SymEnumSymbols)( + _In_ HANDLE hProcess, + _In_ ULONG64 BaseOfDll, + _In_opt_ PCSTR Mask, + _In_ PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback, + _In_opt_ const PVOID UserContext + ); + +typedef BOOL (WINAPI *_SymEnumSymbolsW)( + _In_ HANDLE hProcess, + _In_ ULONG64 BaseOfDll, + _In_opt_ PCWSTR Mask, + _In_ PSYM_ENUMERATESYMBOLS_CALLBACKW EnumSymbolsCallback, + _In_opt_ const PVOID UserContext + ); + +typedef BOOL (WINAPI *_SymFromAddr)( + _In_ HANDLE hProcess, + _In_ DWORD64 Address, + _Out_opt_ PDWORD64 Displacement, + _Inout_ PSYMBOL_INFO Symbol + ); + +typedef BOOL (WINAPI *_SymFromAddrW)( + _In_ HANDLE hProcess, + _In_ DWORD64 Address, + _Out_opt_ PDWORD64 Displacement, + _Inout_ PSYMBOL_INFOW Symbol + ); + +typedef BOOL (WINAPI *_SymFromName)( + _In_ HANDLE hProcess, + _In_ PCSTR Name, + _Inout_ PSYMBOL_INFO Symbol + ); + +typedef BOOL (WINAPI *_SymFromNameW)( + _In_ HANDLE hProcess, + _In_ PCWSTR Name, + _Inout_ PSYMBOL_INFOW Symbol + ); + +typedef BOOL (WINAPI *_SymGetLineFromAddr64)( + _In_ HANDLE hProcess, + _In_ DWORD64 dwAddr, + _Out_ PDWORD pdwDisplacement, + _Out_ PIMAGEHLP_LINE64 Line + ); + +typedef BOOL (WINAPI *_SymGetLineFromAddrW64)( + _In_ HANDLE hProcess, + _In_ DWORD64 dwAddr, + _Out_ PDWORD pdwDisplacement, + _Out_ PIMAGEHLP_LINEW64 Line + ); + +typedef DWORD64 (WINAPI *_SymLoadModule64)( + _In_ HANDLE hProcess, + _In_opt_ HANDLE hFile, + _In_opt_ PCSTR ImageName, + _In_opt_ PCSTR ModuleName, + _In_ DWORD64 BaseOfDll, + _In_ DWORD SizeOfDll + ); + +typedef DWORD64 (WINAPI *_SymLoadModuleExW)( + _In_ HANDLE hProcess, + _In_ HANDLE hFile, + _In_ PCWSTR ImageName, + _In_ PCWSTR ModuleName, + _In_ DWORD64 BaseOfDll, + _In_ DWORD DllSize, + _In_ PMODLOAD_DATA Data, + _In_ DWORD Flags + ); + +typedef DWORD (WINAPI *_SymGetOptions)(); + +typedef DWORD (WINAPI *_SymSetOptions)( + _In_ DWORD SymOptions + ); + +typedef BOOL (WINAPI *_SymGetSearchPath)( + _In_ HANDLE hProcess, + _Out_ PSTR SearchPath, + _In_ DWORD SearchPathLength + ); + +typedef BOOL (WINAPI *_SymGetSearchPathW)( + _In_ HANDLE hProcess, + _Out_ PWSTR SearchPath, + _In_ DWORD SearchPathLength + ); + +typedef BOOL (WINAPI *_SymSetSearchPath)( + _In_ HANDLE hProcess, + _In_opt_ PCSTR SearchPath + ); + +typedef BOOL (WINAPI *_SymSetSearchPathW)( + _In_ HANDLE hProcess, + _In_opt_ PCWSTR SearchPath + ); + +typedef BOOL (WINAPI *_SymUnloadModule64)( + _In_ HANDLE hProcess, + _In_ DWORD64 BaseOfDll + ); + +typedef PVOID (WINAPI *_SymFunctionTableAccess64)( + _In_ HANDLE hProcess, + _In_ DWORD64 AddrBase + ); + +typedef DWORD64 (WINAPI *_SymGetModuleBase64)( + _In_ HANDLE hProcess, + _In_ DWORD64 dwAddr + ); + +typedef BOOL (WINAPI *_SymRegisterCallbackW64)( + _In_ HANDLE hProcess, + _In_ PSYMBOL_REGISTERED_CALLBACK64 CallbackFunction, + _In_ ULONG64 UserContext + ); + +typedef BOOL (WINAPI *_StackWalk64)( + _In_ DWORD MachineType, + _In_ HANDLE hProcess, + _In_ HANDLE hThread, + _Inout_ LPSTACKFRAME64 StackFrame, + _Inout_ PVOID ContextRecord, + _In_opt_ PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine, + _In_opt_ PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine, + _In_opt_ PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine, + _In_opt_ PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress + ); + +typedef BOOL (WINAPI *_MiniDumpWriteDump)( + _In_ HANDLE hProcess, + _In_ DWORD ProcessId, + _In_ HANDLE hFile, + _In_ MINIDUMP_TYPE DumpType, + _In_ PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, + _In_ PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam, + _In_ PMINIDUMP_CALLBACK_INFORMATION CallbackParam + ); + +typedef UINT_PTR (CALLBACK *_SymbolServerGetOptions)( + VOID + ); + +typedef BOOL (CALLBACK *_SymbolServerSetOptions)( + _In_ UINT_PTR options, + _In_ ULONG64 data + ); + #endif \ No newline at end of file diff --git a/phlib/include/templ.h b/phlib/include/templ.h index 7a61f9a359f6..7cff6a1469a6 100644 --- a/phlib/include/templ.h +++ b/phlib/include/templ.h @@ -1,7 +1,7 @@ -#ifndef _PH_TEMPL_H -#define _PH_TEMPL_H - -#define TEMPLATE_(f,T) f##_##T -#define T___(f,T) TEMPLATE_(f,T) - -#endif +#ifndef _PH_TEMPL_H +#define _PH_TEMPL_H + +#define TEMPLATE_(f,T) f##_##T +#define T___(f,T) TEMPLATE_(f,T) + +#endif diff --git a/phlib/include/treenew.h b/phlib/include/treenew.h index bc4c649cfca3..51e24253eaa3 100644 --- a/phlib/include/treenew.h +++ b/phlib/include/treenew.h @@ -1,672 +1,672 @@ -#ifndef _PH_TREENEW_H -#define _PH_TREENEW_H - -#ifdef __cplusplus -extern "C" { -#endif - -#define PH_TREENEW_CLASSNAME L"PhTreeNew" - -#define PH_TREENEW_SEARCH_TIMEOUT 1000 -#define PH_TREENEW_SEARCH_MAXIMUM_LENGTH 1023 - -typedef struct _PH_TREENEW_COLUMN -{ - union - { - ULONG Flags; - struct - { - ULONG Visible : 1; - ULONG CustomDraw : 1; - ULONG Fixed : 1; // Whether this is the fixed column - ULONG SortDescending : 1; // Sort descending on initial click rather than ascending - ULONG DpiScaleOnAdd : 1; // Whether to DPI scale the width (only when adding) - ULONG SpareFlags : 27; - }; - }; - ULONG Id; - PVOID Context; - PWSTR Text; - LONG Width; - ULONG Alignment; - ULONG DisplayIndex; // -1 for fixed column or invalid - - ULONG TextFlags; - - struct - { - LONG ViewIndex; // Actual index in header control - LONG ViewX; // 0 for the fixed column, and an offset from the divider for normal columns - } s; -} PH_TREENEW_COLUMN, *PPH_TREENEW_COLUMN; - -typedef struct _PH_TREENEW_NODE -{ - union - { - ULONG Flags; - struct - { - ULONG Visible : 1; - ULONG Selected : 1; - ULONG Expanded : 1; - ULONG UseAutoForeColor : 1; - ULONG UseTempBackColor : 1; - ULONG Unselectable : 1; - ULONG SpareFlags : 26; - }; - }; - - COLORREF BackColor; - COLORREF ForeColor; - COLORREF TempBackColor; - HFONT Font; - HICON Icon; - - PPH_STRINGREF TextCache; - ULONG TextCacheSize; - - ULONG Index; // Index within the flat list - ULONG Level; // 0 for root, 1, 2, ... - - struct - { - union - { - ULONG Flags2; - struct - { - ULONG IsLeaf : 1; - ULONG CachedColorValid : 1; - ULONG CachedFontValid : 1; - ULONG CachedIconValid : 1; - ULONG PlusMinusHot : 1; - ULONG SpareFlags2 : 27; - }; - }; - - // Temp. drawing data - COLORREF DrawBackColor; - COLORREF DrawForeColor; - } s; -} PH_TREENEW_NODE, *PPH_TREENEW_NODE; - -// Styles -#define TN_STYLE_ICONS 0x1 -#define TN_STYLE_DOUBLE_BUFFERED 0x2 -#define TN_STYLE_NO_DIVIDER 0x4 -#define TN_STYLE_ANIMATE_DIVIDER 0x8 -#define TN_STYLE_NO_COLUMN_SORT 0x10 -#define TN_STYLE_NO_COLUMN_REORDER 0x20 -#define TN_STYLE_THIN_ROWS 0x40 -#define TN_STYLE_NO_COLUMN_HEADER 0x80 - -// Extended flags -#define TN_FLAG_ITEM_DRAG_SELECT 0x1 -#define TN_FLAG_NO_UNFOLDING_TOOLTIPS 0x2 - -// Callback flags -#define TN_CACHE 0x1 -#define TN_AUTO_FORECOLOR 0x1000 - -// Column change flags -#define TN_COLUMN_CONTEXT 0x1 -#define TN_COLUMN_TEXT 0x2 -#define TN_COLUMN_WIDTH 0x4 -#define TN_COLUMN_ALIGNMENT 0x8 -#define TN_COLUMN_DISPLAYINDEX 0x10 -#define TN_COLUMN_TEXTFLAGS 0x20 -#define TN_COLUMN_FLAG_VISIBLE 0x100000 -#define TN_COLUMN_FLAG_CUSTOMDRAW 0x200000 -#define TN_COLUMN_FLAG_FIXED 0x400000 -#define TN_COLUMN_FLAG_SORTDESCENDING 0x800000 -#define TN_COLUMN_FLAG_NODPISCALEONADD 0x1000000 -#define TN_COLUMN_FLAGS 0xfff00000 - -// Cache flags -#define TN_CACHE_COLOR 0x1 -#define TN_CACHE_FONT 0x2 -#define TN_CACHE_ICON 0x4 - -// Cell part input flags -#define TN_MEASURE_TEXT 0x1 - -// Cell part flags -#define TN_PART_CELL 0x1 -#define TN_PART_PLUSMINUS 0x2 -#define TN_PART_ICON 0x4 -#define TN_PART_CONTENT 0x8 -#define TN_PART_TEXT 0x10 - -// Hit test input flags -#define TN_TEST_COLUMN 0x1 -#define TN_TEST_SUBITEM 0x2 // requires TN_TEST_COLUMN - -// Hit test flags -#define TN_HIT_LEFT 0x1 -#define TN_HIT_RIGHT 0x2 -#define TN_HIT_ABOVE 0x4 -#define TN_HIT_BELOW 0x8 -#define TN_HIT_ITEM 0x10 -#define TN_HIT_ITEM_PLUSMINUS 0x20 // requires TN_TEST_SUBITEM -#define TN_HIT_ITEM_ICON 0x40 // requires TN_TEST_SUBITEM -#define TN_HIT_ITEM_CONTENT 0x80 // requires TN_TEST_SUBITEM -#define TN_HIT_DIVIDER 0x100 - -// Selection flags -#define TN_SELECT_DESELECT 0x1 -#define TN_SELECT_TOGGLE 0x2 -#define TN_SELECT_RESET 0x4 - -// Auto-size flags -#define TN_AUTOSIZE_REMAINING_SPACE 0x1 - -typedef struct _PH_TREENEW_CELL_PARTS -{ - ULONG Flags; - RECT RowRect; - RECT CellRect; // TN_PART_CELL - RECT PlusMinusRect; // TN_PART_PLUSMINUS - RECT IconRect; // TN_PART_ICON - RECT ContentRect; // TN_PART_CONTENT - RECT TextRect; // TN_PART_TEXT - PH_STRINGREF Text; // TN_PART_TEXT - HFONT Font; // TN_PART_TEXT -} PH_TREENEW_CELL_PARTS, *PPH_TREENEW_CELL_PARTS; - -typedef struct _PH_TREENEW_HIT_TEST -{ - POINT Point; - ULONG InFlags; - - ULONG Flags; - PPH_TREENEW_NODE Node; - PPH_TREENEW_COLUMN Column; // requires TN_TEST_COLUMN -} PH_TREENEW_HIT_TEST, *PPH_TREENEW_HIT_TEST; - -typedef enum _PH_TREENEW_MESSAGE -{ - TreeNewGetChildren, // PPH_TREENEW_GET_CHILDREN Parameter1 - TreeNewIsLeaf, // PPH_TREENEW_IS_LEAF Parameter1 - TreeNewGetCellText, // PPH_TREENEW_GET_CELL_TEXT Parameter1 - TreeNewGetNodeColor, // PPH_TREENEW_GET_NODE_COLOR Parameter1 - TreeNewGetNodeFont, // PPH_TREENEW_GET_NODE_FONT Parameter1 - TreeNewGetNodeIcon, // PPH_TREENEW_GET_NODE_ICON Parameter1 - TreeNewGetCellTooltip, // PPH_TREENEW_GET_CELL_TOOLTIP Parameter1 - TreeNewCustomDraw, // PPH_TREENEW_CUSTOM_DRAW Parameter1 - - // Notifications - TreeNewNodeExpanding, // PPH_TREENEW_NODE Parameter1, PPH_TREENEW_NODE_EVENT Parameter2 - TreeNewNodeSelecting, // PPH_TREENEW_NODE Parameter1 - - TreeNewSortChanged, - TreeNewSelectionChanged, - - TreeNewKeyDown, // PPH_TREENEW_KEY_EVENT Parameter1 - TreeNewLeftClick, // PPH_TREENEW_MOUSE_EVENT Parameter1 - TreeNewRightClick, // PPH_TREENEW_MOUSE_EVENT Parameter1 - TreeNewLeftDoubleClick, // PPH_TREENEW_MOUSE_EVENT Parameter1 - TreeNewRightDoubleClick, // PPH_TREENEW_MOUSE_EVENT Parameter1 - TreeNewContextMenu, // PPH_TREENEW_CONTEXT_MENU Parameter1 - - TreeNewHeaderRightClick, // PPH_TREENEW_HEADER_MOUSE_EVENT Parameter1 - TreeNewIncrementalSearch, // PPH_TREENEW_SEARCH_EVENT Parameter1 - - TreeNewColumnResized, // PPH_TREENEW_COLUMN Parameter1 - TreeNewColumnReordered, - - TreeNewDestroying, - TreeNewGetDialogCode, // ULONG Parameter1, PULONG Parameter2 - - MaxTreeNewMessage -} PH_TREENEW_MESSAGE; - -typedef BOOLEAN (NTAPI *PPH_TREENEW_CALLBACK)( - _In_ HWND hwnd, - _In_ PH_TREENEW_MESSAGE Message, - _In_opt_ PVOID Parameter1, - _In_opt_ PVOID Parameter2, - _In_opt_ PVOID Context - ); - -typedef struct _PH_TREENEW_GET_CHILDREN -{ - ULONG Flags; - PPH_TREENEW_NODE Node; - - ULONG NumberOfChildren; - PPH_TREENEW_NODE *Children; // can be NULL if no children -} PH_TREENEW_GET_CHILDREN, *PPH_TREENEW_GET_CHILDREN; - -typedef struct _PH_TREENEW_IS_LEAF -{ - ULONG Flags; - PPH_TREENEW_NODE Node; - - BOOLEAN IsLeaf; -} PH_TREENEW_IS_LEAF, *PPH_TREENEW_IS_LEAF; - -typedef struct _PH_TREENEW_GET_CELL_TEXT -{ - ULONG Flags; - PPH_TREENEW_NODE Node; - ULONG Id; - - PH_STRINGREF Text; -} PH_TREENEW_GET_CELL_TEXT, *PPH_TREENEW_GET_CELL_TEXT; - -typedef struct _PH_TREENEW_GET_NODE_COLOR -{ - ULONG Flags; - PPH_TREENEW_NODE Node; - - COLORREF BackColor; - COLORREF ForeColor; -} PH_TREENEW_GET_NODE_COLOR, *PPH_TREENEW_GET_NODE_COLOR; - -typedef struct _PH_TREENEW_GET_NODE_FONT -{ - ULONG Flags; - PPH_TREENEW_NODE Node; - - HFONT Font; -} PH_TREENEW_GET_NODE_FONT, *PPH_TREENEW_GET_NODE_FONT; - -typedef struct _PH_TREENEW_GET_NODE_ICON -{ - ULONG Flags; - PPH_TREENEW_NODE Node; - - HICON Icon; -} PH_TREENEW_GET_NODE_ICON, *PPH_TREENEW_GET_NODE_ICON; - -typedef struct _PH_TREENEW_GET_CELL_TOOLTIP -{ - ULONG Flags; - PPH_TREENEW_NODE Node; - PPH_TREENEW_COLUMN Column; - - BOOLEAN Unfolding; - PH_STRINGREF Text; - HFONT Font; - ULONG MaximumWidth; -} PH_TREENEW_GET_CELL_TOOLTIP, *PPH_TREENEW_GET_CELL_TOOLTIP; - -typedef struct _PH_TREENEW_CUSTOM_DRAW -{ - PPH_TREENEW_NODE Node; - PPH_TREENEW_COLUMN Column; - - HDC Dc; - RECT CellRect; - RECT TextRect; -} PH_TREENEW_CUSTOM_DRAW, *PPH_TREENEW_CUSTOM_DRAW; - -typedef struct _PH_TREENEW_MOUSE_EVENT -{ - POINT Location; - PPH_TREENEW_NODE Node; - PPH_TREENEW_COLUMN Column; - ULONG KeyFlags; -} PH_TREENEW_MOUSE_EVENT, *PPH_TREENEW_MOUSE_EVENT; - -typedef struct _PH_TREENEW_KEY_EVENT -{ - BOOLEAN Handled; - ULONG VirtualKey; - ULONG Data; -} PH_TREENEW_KEY_EVENT, *PPH_TREENEW_KEY_EVENT; - -typedef struct _PH_TREENEW_NODE_EVENT -{ - BOOLEAN Handled; - ULONG Flags; - PVOID Reserved1; - PVOID Reserved2; -} PH_TREENEW_NODE_EVENT, *PPH_TREENEW_NODE_EVENT; - -typedef struct _PH_TREENEW_CONTEXT_MENU -{ - POINT Location; - POINT ClientLocation; - PPH_TREENEW_NODE Node; - PPH_TREENEW_COLUMN Column; - BOOLEAN KeyboardInvoked; -} PH_TREENEW_CONTEXT_MENU, *PPH_TREENEW_CONTEXT_MENU; - -typedef struct _PH_TREENEW_HEADER_MOUSE_EVENT -{ - POINT ScreenLocation; - POINT Location; - POINT HeaderLocation; - PPH_TREENEW_COLUMN Column; -} PH_TREENEW_HEADER_MOUSE_EVENT, *PPH_TREENEW_HEADER_MOUSE_EVENT; - -typedef struct _PH_TREENEW_SEARCH_EVENT -{ - LONG FoundIndex; - LONG StartIndex; - PH_STRINGREF String; -} PH_TREENEW_SEARCH_EVENT, *PPH_TREENEW_SEARCH_EVENT; - -#define TNM_FIRST (WM_USER + 1) -#define TNM_SETCALLBACK (WM_USER + 1) -#define TNM_NODESADDED (WM_USER + 2) // unimplemented -#define TNM_NODESREMOVED (WM_USER + 3) // unimplemented -#define TNM_NODESSTRUCTURED (WM_USER + 4) -#define TNM_ADDCOLUMN (WM_USER + 5) -#define TNM_REMOVECOLUMN (WM_USER + 6) -#define TNM_GETCOLUMN (WM_USER + 7) -#define TNM_SETCOLUMN (WM_USER + 8) -#define TNM_GETCOLUMNORDERARRAY (WM_USER + 9) -#define TNM_SETCOLUMNORDERARRAY (WM_USER + 10) -#define TNM_SETCURSOR (WM_USER + 11) -#define TNM_GETSORT (WM_USER + 12) -#define TNM_SETSORT (WM_USER + 13) -#define TNM_SETTRISTATE (WM_USER + 14) -#define TNM_ENSUREVISIBLE (WM_USER + 15) -#define TNM_SCROLL (WM_USER + 16) -#define TNM_GETFLATNODECOUNT (WM_USER + 17) -#define TNM_GETFLATNODE (WM_USER + 18) -#define TNM_GETCELLTEXT (WM_USER + 19) -#define TNM_SETNODEEXPANDED (WM_USER + 20) -#define TNM_GETMAXID (WM_USER + 21) -#define TNM_SETMAXID (WM_USER + 22) -#define TNM_INVALIDATENODE (WM_USER + 23) -#define TNM_INVALIDATENODES (WM_USER + 24) -#define TNM_GETFIXEDHEADER (WM_USER + 25) -#define TNM_GETHEADER (WM_USER + 26) -#define TNM_GETTOOLTIPS (WM_USER + 27) -#define TNM_SELECTRANGE (WM_USER + 28) -#define TNM_DESELECTRANGE (WM_USER + 29) -#define TNM_GETCOLUMNCOUNT (WM_USER + 30) -#define TNM_SETREDRAW (WM_USER + 31) -#define TNM_GETVIEWPARTS (WM_USER + 32) -#define TNM_GETFIXEDCOLUMN (WM_USER + 33) -#define TNM_GETFIRSTCOLUMN (WM_USER + 34) -#define TNM_SETFOCUSNODE (WM_USER + 35) -#define TNM_SETMARKNODE (WM_USER + 36) -#define TNM_SETHOTNODE (WM_USER + 37) -#define TNM_SETEXTENDEDFLAGS (WM_USER + 38) -#define TNM_GETCALLBACK (WM_USER + 39) -#define TNM_HITTEST (WM_USER + 40) -#define TNM_GETVISIBLECOLUMNCOUNT (WM_USER + 41) -#define TNM_AUTOSIZECOLUMN (WM_USER + 42) -#define TNM_SETEMPTYTEXT (WM_USER + 43) -#define TNM_SETROWHEIGHT (WM_USER + 44) -#define TNM_ISFLATNODEVALID (WM_USER + 45) -#define TNM_LAST (WM_USER + 45) - -#define TreeNew_SetCallback(hWnd, Callback, Context) \ - SendMessage((hWnd), TNM_SETCALLBACK, (WPARAM)(Context), (LPARAM)(Callback)) - -#define TreeNew_NodesStructured(hWnd) \ - SendMessage((hWnd), TNM_NODESSTRUCTURED, 0, 0) - -#define TreeNew_AddColumn(hWnd, Column) \ - SendMessage((hWnd), TNM_ADDCOLUMN, 0, (LPARAM)(Column)) - -#define TreeNew_RemoveColumn(hWnd, Id) \ - SendMessage((hWnd), TNM_REMOVECOLUMN, (WPARAM)(Id), 0) - -#define TreeNew_GetColumn(hWnd, Id, Column) \ - SendMessage((hWnd), TNM_GETCOLUMN, (WPARAM)(Id), (LPARAM)(Column)) - -#define TreeNew_SetColumn(hWnd, Mask, Column) \ - SendMessage((hWnd), TNM_SETCOLUMN, (WPARAM)(Mask), (LPARAM)(Column)) - -#define TreeNew_GetColumnOrderArray(hWnd, Count, Array) \ - SendMessage((hWnd), TNM_GETCOLUMNORDERARRAY, (WPARAM)(Count), (LPARAM)(Array)) - -#define TreeNew_SetColumnOrderArray(hWnd, Count, Array) \ - SendMessage((hWnd), TNM_SETCOLUMNORDERARRAY, (WPARAM)(Count), (LPARAM)(Array)) - -#define TreeNew_SetCursor(hWnd, Cursor) \ - SendMessage((hWnd), TNM_SETCURSOR, 0, (LPARAM)(Cursor)) - -#define TreeNew_GetSort(hWnd, Column, Order) \ - SendMessage((hWnd), TNM_GETSORT, (WPARAM)(Column), (LPARAM)(Order)) - -#define TreeNew_SetSort(hWnd, Column, Order) \ - SendMessage((hWnd), TNM_SETSORT, (WPARAM)(Column), (LPARAM)(Order)) - -#define TreeNew_SetTriState(hWnd, TriState) \ - SendMessage((hWnd), TNM_SETTRISTATE, (WPARAM)(TriState), 0) - -#define TreeNew_EnsureVisible(hWnd, Node) \ - SendMessage((hWnd), TNM_ENSUREVISIBLE, 0, (LPARAM)(Node)) - -#define TreeNew_Scroll(hWnd, DeltaRows, DeltaX) \ - SendMessage((hWnd), TNM_SCROLL, (WPARAM)(DeltaRows), (LPARAM)(DeltaX)) - -#define TreeNew_GetFlatNodeCount(hWnd) \ - ((ULONG)SendMessage((hWnd), TNM_GETFLATNODECOUNT, 0, 0)) - -#define TreeNew_GetFlatNode(hWnd, Index) \ - ((PPH_TREENEW_NODE)SendMessage((hWnd), TNM_GETFLATNODE, (WPARAM)(Index), 0)) - -#define TreeNew_GetCellText(hWnd, GetCellText) \ - SendMessage((hWnd), TNM_GETCELLTEXT, 0, (LPARAM)(GetCellText)) - -#define TreeNew_SetNodeExpanded(hWnd, Node, Expanded) \ - SendMessage((hWnd), TNM_SETNODEEXPANDED, (WPARAM)(Expanded), (LPARAM)(Node)) - -#define TreeNew_GetMaxId(hWnd) \ - ((ULONG)SendMessage((hWnd), TNM_GETMAXID, 0, 0)) - -#define TreeNew_SetMaxId(hWnd, MaxId) \ - SendMessage((hWnd), TNM_SETMAXID, (WPARAM)(MaxId), 0) - -#define TreeNew_InvalidateNode(hWnd, Node) \ - SendMessage((hWnd), TNM_INVALIDATENODE, 0, (LPARAM)(Node)) - -#define TreeNew_InvalidateNodes(hWnd, Start, End) \ - SendMessage((hWnd), TNM_INVALIDATENODES, (WPARAM)(Start), (LPARAM)(End)) - -#define TreeNew_GetFixedHeader(hWnd) \ - ((HWND)SendMessage((hWnd), TNM_GETFIXEDHEADER, 0, 0)) - -#define TreeNew_GetHeader(hWnd) \ - ((HWND)SendMessage((hWnd), TNM_GETHEADER, 0, 0)) - -#define TreeNew_GetTooltips(hWnd) \ - ((HWND)SendMessage((hWnd), TNM_GETTOOLTIPS, 0, 0)) - -#define TreeNew_SelectRange(hWnd, Start, End) \ - SendMessage((hWnd), TNM_SELECTRANGE, (WPARAM)(Start), (LPARAM)(End)) - -#define TreeNew_DeselectRange(hWnd, Start, End) \ - SendMessage((hWnd), TNM_DESELECTRANGE, (WPARAM)(Start), (LPARAM)(End)) - -#define TreeNew_GetColumnCount(hWnd) \ - ((ULONG)SendMessage((hWnd), TNM_GETCOLUMNCOUNT, 0, 0)) - -#define TreeNew_SetRedraw(hWnd, Redraw) \ - ((LONG)SendMessage((hWnd), TNM_SETREDRAW, (WPARAM)(Redraw), 0)) - -#define TreeNew_GetViewParts(hWnd, Parts) \ - SendMessage((hWnd), TNM_GETVIEWPARTS, 0, (LPARAM)(Parts)) - -#define TreeNew_GetFixedColumn(hWnd) \ - ((PPH_TREENEW_COLUMN)SendMessage((hWnd), TNM_GETFIXEDCOLUMN, 0, 0)) - -#define TreeNew_GetFirstColumn(hWnd) \ - ((PPH_TREENEW_COLUMN)SendMessage((hWnd), TNM_GETFIRSTCOLUMN, 0, 0)) - -#define TreeNew_SetFocusNode(hWnd, Node) \ - SendMessage((hWnd), TNM_SETFOCUSNODE, 0, (LPARAM)(Node)) - -#define TreeNew_SetMarkNode(hWnd, Node) \ - SendMessage((hWnd), TNM_SETMARKNODE, 0, (LPARAM)(Node)) - -#define TreeNew_SetHotNode(hWnd, Node) \ - SendMessage((hWnd), TNM_SETHOTNODE, 0, (LPARAM)(Node)) - -#define TreeNew_SetExtendedFlags(hWnd, Mask, Value) \ - SendMessage((hWnd), TNM_SETEXTENDEDFLAGS, (WPARAM)(Mask), (LPARAM)(Value)) - -#define TreeNew_GetCallback(hWnd, Callback, Context) \ - SendMessage((hWnd), TNM_GETCALLBACK, (WPARAM)(Context), (LPARAM)(Callback)) - -#define TreeNew_HitTest(hWnd, HitTest) \ - SendMessage((hWnd), TNM_HITTEST, 0, (LPARAM)(HitTest)) - -#define TreeNew_GetVisibleColumnCount(hWnd) \ - ((ULONG)SendMessage((hWnd), TNM_GETVISIBLECOLUMNCOUNT, 0, 0)) - -#define TreeNew_AutoSizeColumn(hWnd, Id, Flags) \ - SendMessage((hWnd), TNM_AUTOSIZECOLUMN, (WPARAM)(Id), (LPARAM)(Flags)) - -#define TreeNew_SetEmptyText(hWnd, Text, Flags) \ - SendMessage((hWnd), TNM_SETEMPTYTEXT, (WPARAM)(Flags), (LPARAM)(Text)) - -#define TreeNew_SetRowHeight(hWnd, RowHeight) \ - SendMessage((hWnd), TNM_SETROWHEIGHT, (WPARAM)(RowHeight), 0) - -#define TreeNew_IsFlatNodeValid(hWnd) \ - ((BOOLEAN)SendMessage((hWnd), TNM_ISFLATNODEVALID, 0, 0)) - -typedef struct _PH_TREENEW_VIEW_PARTS -{ - RECT ClientRect; - LONG HeaderHeight; - LONG RowHeight; - ULONG VScrollWidth; - ULONG HScrollHeight; - LONG VScrollPosition; - LONG HScrollPosition; - LONG FixedWidth; - LONG NormalLeft; - LONG NormalWidth; -} PH_TREENEW_VIEW_PARTS, *PPH_TREENEW_VIEW_PARTS; - -PHLIBAPI -BOOLEAN PhTreeNewInitialization( - VOID - ); - -FORCEINLINE VOID PhInitializeTreeNewNode( - _In_ PPH_TREENEW_NODE Node - ) -{ - memset(Node, 0, sizeof(PH_TREENEW_NODE)); - - Node->Visible = TRUE; - Node->Expanded = TRUE; -} - -FORCEINLINE VOID PhInvalidateTreeNewNode( - _Inout_ PPH_TREENEW_NODE Node, - _In_ ULONG Flags - ) -{ - if (Flags & TN_CACHE_COLOR) - Node->s.CachedColorValid = FALSE; - if (Flags & TN_CACHE_FONT) - Node->s.CachedFontValid = FALSE; - if (Flags & TN_CACHE_ICON) - Node->s.CachedIconValid = FALSE; -} - -FORCEINLINE BOOLEAN PhAddTreeNewColumn( - _In_ HWND hwnd, - _In_ ULONG Id, - _In_ BOOLEAN Visible, - _In_ PWSTR Text, - _In_ ULONG Width, - _In_ ULONG Alignment, - _In_ ULONG DisplayIndex, - _In_ ULONG TextFlags - ) -{ - PH_TREENEW_COLUMN column; - - memset(&column, 0, sizeof(PH_TREENEW_COLUMN)); - column.Id = Id; - column.Visible = Visible; - column.Text = Text; - column.Width = Width; - column.Alignment = Alignment; - column.DisplayIndex = DisplayIndex; - column.TextFlags = TextFlags; - column.DpiScaleOnAdd = TRUE; - - if (DisplayIndex == -2) - column.Fixed = TRUE; - - return !!TreeNew_AddColumn(hwnd, &column); -} - -FORCEINLINE BOOLEAN PhAddTreeNewColumnEx( - _In_ HWND hwnd, - _In_ ULONG Id, - _In_ BOOLEAN Visible, - _In_ PWSTR Text, - _In_ ULONG Width, - _In_ ULONG Alignment, - _In_ ULONG DisplayIndex, - _In_ ULONG TextFlags, - _In_ BOOLEAN SortDescending - ) -{ - PH_TREENEW_COLUMN column; - - memset(&column, 0, sizeof(PH_TREENEW_COLUMN)); - column.Id = Id; - column.Visible = Visible; - column.Text = Text; - column.Width = Width; - column.Alignment = Alignment; - column.DisplayIndex = DisplayIndex; - column.TextFlags = TextFlags; - column.DpiScaleOnAdd = TRUE; - - if (DisplayIndex == -2) - column.Fixed = TRUE; - if (SortDescending) - column.SortDescending = TRUE; - - return !!TreeNew_AddColumn(hwnd, &column); -} - -FORCEINLINE BOOLEAN PhAddTreeNewColumnEx2( - _In_ HWND hwnd, - _In_ ULONG Id, - _In_ BOOLEAN Visible, - _In_ PWSTR Text, - _In_ ULONG Width, - _In_ ULONG Alignment, - _In_ ULONG DisplayIndex, - _In_ ULONG TextFlags, - _In_ ULONG ExtraFlags - ) -{ - PH_TREENEW_COLUMN column; - - memset(&column, 0, sizeof(PH_TREENEW_COLUMN)); - column.Id = Id; - column.Visible = Visible; - column.Text = Text; - column.Width = Width; - column.Alignment = Alignment; - column.DisplayIndex = DisplayIndex; - column.TextFlags = TextFlags; - - if (DisplayIndex == -2) - column.Fixed = TRUE; - if (ExtraFlags & TN_COLUMN_FLAG_CUSTOMDRAW) - column.CustomDraw = TRUE; - if (ExtraFlags & TN_COLUMN_FLAG_SORTDESCENDING) - column.SortDescending = TRUE; - if (!(ExtraFlags & TN_COLUMN_FLAG_NODPISCALEONADD)) - column.DpiScaleOnAdd = TRUE; - - return !!TreeNew_AddColumn(hwnd, &column); -} - -#ifdef __cplusplus -} -#endif - -#endif +#ifndef _PH_TREENEW_H +#define _PH_TREENEW_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define PH_TREENEW_CLASSNAME L"PhTreeNew" + +#define PH_TREENEW_SEARCH_TIMEOUT 1000 +#define PH_TREENEW_SEARCH_MAXIMUM_LENGTH 1023 + +typedef struct _PH_TREENEW_COLUMN +{ + union + { + ULONG Flags; + struct + { + ULONG Visible : 1; + ULONG CustomDraw : 1; + ULONG Fixed : 1; // Whether this is the fixed column + ULONG SortDescending : 1; // Sort descending on initial click rather than ascending + ULONG DpiScaleOnAdd : 1; // Whether to DPI scale the width (only when adding) + ULONG SpareFlags : 27; + }; + }; + ULONG Id; + PVOID Context; + PWSTR Text; + LONG Width; + ULONG Alignment; + ULONG DisplayIndex; // -1 for fixed column or invalid + + ULONG TextFlags; + + struct + { + LONG ViewIndex; // Actual index in header control + LONG ViewX; // 0 for the fixed column, and an offset from the divider for normal columns + } s; +} PH_TREENEW_COLUMN, *PPH_TREENEW_COLUMN; + +typedef struct _PH_TREENEW_NODE +{ + union + { + ULONG Flags; + struct + { + ULONG Visible : 1; + ULONG Selected : 1; + ULONG Expanded : 1; + ULONG UseAutoForeColor : 1; + ULONG UseTempBackColor : 1; + ULONG Unselectable : 1; + ULONG SpareFlags : 26; + }; + }; + + COLORREF BackColor; + COLORREF ForeColor; + COLORREF TempBackColor; + HFONT Font; + HICON Icon; + + PPH_STRINGREF TextCache; + ULONG TextCacheSize; + + ULONG Index; // Index within the flat list + ULONG Level; // 0 for root, 1, 2, ... + + struct + { + union + { + ULONG Flags2; + struct + { + ULONG IsLeaf : 1; + ULONG CachedColorValid : 1; + ULONG CachedFontValid : 1; + ULONG CachedIconValid : 1; + ULONG PlusMinusHot : 1; + ULONG SpareFlags2 : 27; + }; + }; + + // Temp. drawing data + COLORREF DrawBackColor; + COLORREF DrawForeColor; + } s; +} PH_TREENEW_NODE, *PPH_TREENEW_NODE; + +// Styles +#define TN_STYLE_ICONS 0x1 +#define TN_STYLE_DOUBLE_BUFFERED 0x2 +#define TN_STYLE_NO_DIVIDER 0x4 +#define TN_STYLE_ANIMATE_DIVIDER 0x8 +#define TN_STYLE_NO_COLUMN_SORT 0x10 +#define TN_STYLE_NO_COLUMN_REORDER 0x20 +#define TN_STYLE_THIN_ROWS 0x40 +#define TN_STYLE_NO_COLUMN_HEADER 0x80 + +// Extended flags +#define TN_FLAG_ITEM_DRAG_SELECT 0x1 +#define TN_FLAG_NO_UNFOLDING_TOOLTIPS 0x2 + +// Callback flags +#define TN_CACHE 0x1 +#define TN_AUTO_FORECOLOR 0x1000 + +// Column change flags +#define TN_COLUMN_CONTEXT 0x1 +#define TN_COLUMN_TEXT 0x2 +#define TN_COLUMN_WIDTH 0x4 +#define TN_COLUMN_ALIGNMENT 0x8 +#define TN_COLUMN_DISPLAYINDEX 0x10 +#define TN_COLUMN_TEXTFLAGS 0x20 +#define TN_COLUMN_FLAG_VISIBLE 0x100000 +#define TN_COLUMN_FLAG_CUSTOMDRAW 0x200000 +#define TN_COLUMN_FLAG_FIXED 0x400000 +#define TN_COLUMN_FLAG_SORTDESCENDING 0x800000 +#define TN_COLUMN_FLAG_NODPISCALEONADD 0x1000000 +#define TN_COLUMN_FLAGS 0xfff00000 + +// Cache flags +#define TN_CACHE_COLOR 0x1 +#define TN_CACHE_FONT 0x2 +#define TN_CACHE_ICON 0x4 + +// Cell part input flags +#define TN_MEASURE_TEXT 0x1 + +// Cell part flags +#define TN_PART_CELL 0x1 +#define TN_PART_PLUSMINUS 0x2 +#define TN_PART_ICON 0x4 +#define TN_PART_CONTENT 0x8 +#define TN_PART_TEXT 0x10 + +// Hit test input flags +#define TN_TEST_COLUMN 0x1 +#define TN_TEST_SUBITEM 0x2 // requires TN_TEST_COLUMN + +// Hit test flags +#define TN_HIT_LEFT 0x1 +#define TN_HIT_RIGHT 0x2 +#define TN_HIT_ABOVE 0x4 +#define TN_HIT_BELOW 0x8 +#define TN_HIT_ITEM 0x10 +#define TN_HIT_ITEM_PLUSMINUS 0x20 // requires TN_TEST_SUBITEM +#define TN_HIT_ITEM_ICON 0x40 // requires TN_TEST_SUBITEM +#define TN_HIT_ITEM_CONTENT 0x80 // requires TN_TEST_SUBITEM +#define TN_HIT_DIVIDER 0x100 + +// Selection flags +#define TN_SELECT_DESELECT 0x1 +#define TN_SELECT_TOGGLE 0x2 +#define TN_SELECT_RESET 0x4 + +// Auto-size flags +#define TN_AUTOSIZE_REMAINING_SPACE 0x1 + +typedef struct _PH_TREENEW_CELL_PARTS +{ + ULONG Flags; + RECT RowRect; + RECT CellRect; // TN_PART_CELL + RECT PlusMinusRect; // TN_PART_PLUSMINUS + RECT IconRect; // TN_PART_ICON + RECT ContentRect; // TN_PART_CONTENT + RECT TextRect; // TN_PART_TEXT + PH_STRINGREF Text; // TN_PART_TEXT + HFONT Font; // TN_PART_TEXT +} PH_TREENEW_CELL_PARTS, *PPH_TREENEW_CELL_PARTS; + +typedef struct _PH_TREENEW_HIT_TEST +{ + POINT Point; + ULONG InFlags; + + ULONG Flags; + PPH_TREENEW_NODE Node; + PPH_TREENEW_COLUMN Column; // requires TN_TEST_COLUMN +} PH_TREENEW_HIT_TEST, *PPH_TREENEW_HIT_TEST; + +typedef enum _PH_TREENEW_MESSAGE +{ + TreeNewGetChildren, // PPH_TREENEW_GET_CHILDREN Parameter1 + TreeNewIsLeaf, // PPH_TREENEW_IS_LEAF Parameter1 + TreeNewGetCellText, // PPH_TREENEW_GET_CELL_TEXT Parameter1 + TreeNewGetNodeColor, // PPH_TREENEW_GET_NODE_COLOR Parameter1 + TreeNewGetNodeFont, // PPH_TREENEW_GET_NODE_FONT Parameter1 + TreeNewGetNodeIcon, // PPH_TREENEW_GET_NODE_ICON Parameter1 + TreeNewGetCellTooltip, // PPH_TREENEW_GET_CELL_TOOLTIP Parameter1 + TreeNewCustomDraw, // PPH_TREENEW_CUSTOM_DRAW Parameter1 + + // Notifications + TreeNewNodeExpanding, // PPH_TREENEW_NODE Parameter1, PPH_TREENEW_NODE_EVENT Parameter2 + TreeNewNodeSelecting, // PPH_TREENEW_NODE Parameter1 + + TreeNewSortChanged, + TreeNewSelectionChanged, + + TreeNewKeyDown, // PPH_TREENEW_KEY_EVENT Parameter1 + TreeNewLeftClick, // PPH_TREENEW_MOUSE_EVENT Parameter1 + TreeNewRightClick, // PPH_TREENEW_MOUSE_EVENT Parameter1 + TreeNewLeftDoubleClick, // PPH_TREENEW_MOUSE_EVENT Parameter1 + TreeNewRightDoubleClick, // PPH_TREENEW_MOUSE_EVENT Parameter1 + TreeNewContextMenu, // PPH_TREENEW_CONTEXT_MENU Parameter1 + + TreeNewHeaderRightClick, // PPH_TREENEW_HEADER_MOUSE_EVENT Parameter1 + TreeNewIncrementalSearch, // PPH_TREENEW_SEARCH_EVENT Parameter1 + + TreeNewColumnResized, // PPH_TREENEW_COLUMN Parameter1 + TreeNewColumnReordered, + + TreeNewDestroying, + TreeNewGetDialogCode, // ULONG Parameter1, PULONG Parameter2 + + MaxTreeNewMessage +} PH_TREENEW_MESSAGE; + +typedef BOOLEAN (NTAPI *PPH_TREENEW_CALLBACK)( + _In_ HWND hwnd, + _In_ PH_TREENEW_MESSAGE Message, + _In_opt_ PVOID Parameter1, + _In_opt_ PVOID Parameter2, + _In_opt_ PVOID Context + ); + +typedef struct _PH_TREENEW_GET_CHILDREN +{ + ULONG Flags; + PPH_TREENEW_NODE Node; + + ULONG NumberOfChildren; + PPH_TREENEW_NODE *Children; // can be NULL if no children +} PH_TREENEW_GET_CHILDREN, *PPH_TREENEW_GET_CHILDREN; + +typedef struct _PH_TREENEW_IS_LEAF +{ + ULONG Flags; + PPH_TREENEW_NODE Node; + + BOOLEAN IsLeaf; +} PH_TREENEW_IS_LEAF, *PPH_TREENEW_IS_LEAF; + +typedef struct _PH_TREENEW_GET_CELL_TEXT +{ + ULONG Flags; + PPH_TREENEW_NODE Node; + ULONG Id; + + PH_STRINGREF Text; +} PH_TREENEW_GET_CELL_TEXT, *PPH_TREENEW_GET_CELL_TEXT; + +typedef struct _PH_TREENEW_GET_NODE_COLOR +{ + ULONG Flags; + PPH_TREENEW_NODE Node; + + COLORREF BackColor; + COLORREF ForeColor; +} PH_TREENEW_GET_NODE_COLOR, *PPH_TREENEW_GET_NODE_COLOR; + +typedef struct _PH_TREENEW_GET_NODE_FONT +{ + ULONG Flags; + PPH_TREENEW_NODE Node; + + HFONT Font; +} PH_TREENEW_GET_NODE_FONT, *PPH_TREENEW_GET_NODE_FONT; + +typedef struct _PH_TREENEW_GET_NODE_ICON +{ + ULONG Flags; + PPH_TREENEW_NODE Node; + + HICON Icon; +} PH_TREENEW_GET_NODE_ICON, *PPH_TREENEW_GET_NODE_ICON; + +typedef struct _PH_TREENEW_GET_CELL_TOOLTIP +{ + ULONG Flags; + PPH_TREENEW_NODE Node; + PPH_TREENEW_COLUMN Column; + + BOOLEAN Unfolding; + PH_STRINGREF Text; + HFONT Font; + ULONG MaximumWidth; +} PH_TREENEW_GET_CELL_TOOLTIP, *PPH_TREENEW_GET_CELL_TOOLTIP; + +typedef struct _PH_TREENEW_CUSTOM_DRAW +{ + PPH_TREENEW_NODE Node; + PPH_TREENEW_COLUMN Column; + + HDC Dc; + RECT CellRect; + RECT TextRect; +} PH_TREENEW_CUSTOM_DRAW, *PPH_TREENEW_CUSTOM_DRAW; + +typedef struct _PH_TREENEW_MOUSE_EVENT +{ + POINT Location; + PPH_TREENEW_NODE Node; + PPH_TREENEW_COLUMN Column; + ULONG KeyFlags; +} PH_TREENEW_MOUSE_EVENT, *PPH_TREENEW_MOUSE_EVENT; + +typedef struct _PH_TREENEW_KEY_EVENT +{ + BOOLEAN Handled; + ULONG VirtualKey; + ULONG Data; +} PH_TREENEW_KEY_EVENT, *PPH_TREENEW_KEY_EVENT; + +typedef struct _PH_TREENEW_NODE_EVENT +{ + BOOLEAN Handled; + ULONG Flags; + PVOID Reserved1; + PVOID Reserved2; +} PH_TREENEW_NODE_EVENT, *PPH_TREENEW_NODE_EVENT; + +typedef struct _PH_TREENEW_CONTEXT_MENU +{ + POINT Location; + POINT ClientLocation; + PPH_TREENEW_NODE Node; + PPH_TREENEW_COLUMN Column; + BOOLEAN KeyboardInvoked; +} PH_TREENEW_CONTEXT_MENU, *PPH_TREENEW_CONTEXT_MENU; + +typedef struct _PH_TREENEW_HEADER_MOUSE_EVENT +{ + POINT ScreenLocation; + POINT Location; + POINT HeaderLocation; + PPH_TREENEW_COLUMN Column; +} PH_TREENEW_HEADER_MOUSE_EVENT, *PPH_TREENEW_HEADER_MOUSE_EVENT; + +typedef struct _PH_TREENEW_SEARCH_EVENT +{ + LONG FoundIndex; + LONG StartIndex; + PH_STRINGREF String; +} PH_TREENEW_SEARCH_EVENT, *PPH_TREENEW_SEARCH_EVENT; + +#define TNM_FIRST (WM_USER + 1) +#define TNM_SETCALLBACK (WM_USER + 1) +#define TNM_NODESADDED (WM_USER + 2) // unimplemented +#define TNM_NODESREMOVED (WM_USER + 3) // unimplemented +#define TNM_NODESSTRUCTURED (WM_USER + 4) +#define TNM_ADDCOLUMN (WM_USER + 5) +#define TNM_REMOVECOLUMN (WM_USER + 6) +#define TNM_GETCOLUMN (WM_USER + 7) +#define TNM_SETCOLUMN (WM_USER + 8) +#define TNM_GETCOLUMNORDERARRAY (WM_USER + 9) +#define TNM_SETCOLUMNORDERARRAY (WM_USER + 10) +#define TNM_SETCURSOR (WM_USER + 11) +#define TNM_GETSORT (WM_USER + 12) +#define TNM_SETSORT (WM_USER + 13) +#define TNM_SETTRISTATE (WM_USER + 14) +#define TNM_ENSUREVISIBLE (WM_USER + 15) +#define TNM_SCROLL (WM_USER + 16) +#define TNM_GETFLATNODECOUNT (WM_USER + 17) +#define TNM_GETFLATNODE (WM_USER + 18) +#define TNM_GETCELLTEXT (WM_USER + 19) +#define TNM_SETNODEEXPANDED (WM_USER + 20) +#define TNM_GETMAXID (WM_USER + 21) +#define TNM_SETMAXID (WM_USER + 22) +#define TNM_INVALIDATENODE (WM_USER + 23) +#define TNM_INVALIDATENODES (WM_USER + 24) +#define TNM_GETFIXEDHEADER (WM_USER + 25) +#define TNM_GETHEADER (WM_USER + 26) +#define TNM_GETTOOLTIPS (WM_USER + 27) +#define TNM_SELECTRANGE (WM_USER + 28) +#define TNM_DESELECTRANGE (WM_USER + 29) +#define TNM_GETCOLUMNCOUNT (WM_USER + 30) +#define TNM_SETREDRAW (WM_USER + 31) +#define TNM_GETVIEWPARTS (WM_USER + 32) +#define TNM_GETFIXEDCOLUMN (WM_USER + 33) +#define TNM_GETFIRSTCOLUMN (WM_USER + 34) +#define TNM_SETFOCUSNODE (WM_USER + 35) +#define TNM_SETMARKNODE (WM_USER + 36) +#define TNM_SETHOTNODE (WM_USER + 37) +#define TNM_SETEXTENDEDFLAGS (WM_USER + 38) +#define TNM_GETCALLBACK (WM_USER + 39) +#define TNM_HITTEST (WM_USER + 40) +#define TNM_GETVISIBLECOLUMNCOUNT (WM_USER + 41) +#define TNM_AUTOSIZECOLUMN (WM_USER + 42) +#define TNM_SETEMPTYTEXT (WM_USER + 43) +#define TNM_SETROWHEIGHT (WM_USER + 44) +#define TNM_ISFLATNODEVALID (WM_USER + 45) +#define TNM_LAST (WM_USER + 45) + +#define TreeNew_SetCallback(hWnd, Callback, Context) \ + SendMessage((hWnd), TNM_SETCALLBACK, (WPARAM)(Context), (LPARAM)(Callback)) + +#define TreeNew_NodesStructured(hWnd) \ + SendMessage((hWnd), TNM_NODESSTRUCTURED, 0, 0) + +#define TreeNew_AddColumn(hWnd, Column) \ + SendMessage((hWnd), TNM_ADDCOLUMN, 0, (LPARAM)(Column)) + +#define TreeNew_RemoveColumn(hWnd, Id) \ + SendMessage((hWnd), TNM_REMOVECOLUMN, (WPARAM)(Id), 0) + +#define TreeNew_GetColumn(hWnd, Id, Column) \ + SendMessage((hWnd), TNM_GETCOLUMN, (WPARAM)(Id), (LPARAM)(Column)) + +#define TreeNew_SetColumn(hWnd, Mask, Column) \ + SendMessage((hWnd), TNM_SETCOLUMN, (WPARAM)(Mask), (LPARAM)(Column)) + +#define TreeNew_GetColumnOrderArray(hWnd, Count, Array) \ + SendMessage((hWnd), TNM_GETCOLUMNORDERARRAY, (WPARAM)(Count), (LPARAM)(Array)) + +#define TreeNew_SetColumnOrderArray(hWnd, Count, Array) \ + SendMessage((hWnd), TNM_SETCOLUMNORDERARRAY, (WPARAM)(Count), (LPARAM)(Array)) + +#define TreeNew_SetCursor(hWnd, Cursor) \ + SendMessage((hWnd), TNM_SETCURSOR, 0, (LPARAM)(Cursor)) + +#define TreeNew_GetSort(hWnd, Column, Order) \ + SendMessage((hWnd), TNM_GETSORT, (WPARAM)(Column), (LPARAM)(Order)) + +#define TreeNew_SetSort(hWnd, Column, Order) \ + SendMessage((hWnd), TNM_SETSORT, (WPARAM)(Column), (LPARAM)(Order)) + +#define TreeNew_SetTriState(hWnd, TriState) \ + SendMessage((hWnd), TNM_SETTRISTATE, (WPARAM)(TriState), 0) + +#define TreeNew_EnsureVisible(hWnd, Node) \ + SendMessage((hWnd), TNM_ENSUREVISIBLE, 0, (LPARAM)(Node)) + +#define TreeNew_Scroll(hWnd, DeltaRows, DeltaX) \ + SendMessage((hWnd), TNM_SCROLL, (WPARAM)(DeltaRows), (LPARAM)(DeltaX)) + +#define TreeNew_GetFlatNodeCount(hWnd) \ + ((ULONG)SendMessage((hWnd), TNM_GETFLATNODECOUNT, 0, 0)) + +#define TreeNew_GetFlatNode(hWnd, Index) \ + ((PPH_TREENEW_NODE)SendMessage((hWnd), TNM_GETFLATNODE, (WPARAM)(Index), 0)) + +#define TreeNew_GetCellText(hWnd, GetCellText) \ + SendMessage((hWnd), TNM_GETCELLTEXT, 0, (LPARAM)(GetCellText)) + +#define TreeNew_SetNodeExpanded(hWnd, Node, Expanded) \ + SendMessage((hWnd), TNM_SETNODEEXPANDED, (WPARAM)(Expanded), (LPARAM)(Node)) + +#define TreeNew_GetMaxId(hWnd) \ + ((ULONG)SendMessage((hWnd), TNM_GETMAXID, 0, 0)) + +#define TreeNew_SetMaxId(hWnd, MaxId) \ + SendMessage((hWnd), TNM_SETMAXID, (WPARAM)(MaxId), 0) + +#define TreeNew_InvalidateNode(hWnd, Node) \ + SendMessage((hWnd), TNM_INVALIDATENODE, 0, (LPARAM)(Node)) + +#define TreeNew_InvalidateNodes(hWnd, Start, End) \ + SendMessage((hWnd), TNM_INVALIDATENODES, (WPARAM)(Start), (LPARAM)(End)) + +#define TreeNew_GetFixedHeader(hWnd) \ + ((HWND)SendMessage((hWnd), TNM_GETFIXEDHEADER, 0, 0)) + +#define TreeNew_GetHeader(hWnd) \ + ((HWND)SendMessage((hWnd), TNM_GETHEADER, 0, 0)) + +#define TreeNew_GetTooltips(hWnd) \ + ((HWND)SendMessage((hWnd), TNM_GETTOOLTIPS, 0, 0)) + +#define TreeNew_SelectRange(hWnd, Start, End) \ + SendMessage((hWnd), TNM_SELECTRANGE, (WPARAM)(Start), (LPARAM)(End)) + +#define TreeNew_DeselectRange(hWnd, Start, End) \ + SendMessage((hWnd), TNM_DESELECTRANGE, (WPARAM)(Start), (LPARAM)(End)) + +#define TreeNew_GetColumnCount(hWnd) \ + ((ULONG)SendMessage((hWnd), TNM_GETCOLUMNCOUNT, 0, 0)) + +#define TreeNew_SetRedraw(hWnd, Redraw) \ + ((LONG)SendMessage((hWnd), TNM_SETREDRAW, (WPARAM)(Redraw), 0)) + +#define TreeNew_GetViewParts(hWnd, Parts) \ + SendMessage((hWnd), TNM_GETVIEWPARTS, 0, (LPARAM)(Parts)) + +#define TreeNew_GetFixedColumn(hWnd) \ + ((PPH_TREENEW_COLUMN)SendMessage((hWnd), TNM_GETFIXEDCOLUMN, 0, 0)) + +#define TreeNew_GetFirstColumn(hWnd) \ + ((PPH_TREENEW_COLUMN)SendMessage((hWnd), TNM_GETFIRSTCOLUMN, 0, 0)) + +#define TreeNew_SetFocusNode(hWnd, Node) \ + SendMessage((hWnd), TNM_SETFOCUSNODE, 0, (LPARAM)(Node)) + +#define TreeNew_SetMarkNode(hWnd, Node) \ + SendMessage((hWnd), TNM_SETMARKNODE, 0, (LPARAM)(Node)) + +#define TreeNew_SetHotNode(hWnd, Node) \ + SendMessage((hWnd), TNM_SETHOTNODE, 0, (LPARAM)(Node)) + +#define TreeNew_SetExtendedFlags(hWnd, Mask, Value) \ + SendMessage((hWnd), TNM_SETEXTENDEDFLAGS, (WPARAM)(Mask), (LPARAM)(Value)) + +#define TreeNew_GetCallback(hWnd, Callback, Context) \ + SendMessage((hWnd), TNM_GETCALLBACK, (WPARAM)(Context), (LPARAM)(Callback)) + +#define TreeNew_HitTest(hWnd, HitTest) \ + SendMessage((hWnd), TNM_HITTEST, 0, (LPARAM)(HitTest)) + +#define TreeNew_GetVisibleColumnCount(hWnd) \ + ((ULONG)SendMessage((hWnd), TNM_GETVISIBLECOLUMNCOUNT, 0, 0)) + +#define TreeNew_AutoSizeColumn(hWnd, Id, Flags) \ + SendMessage((hWnd), TNM_AUTOSIZECOLUMN, (WPARAM)(Id), (LPARAM)(Flags)) + +#define TreeNew_SetEmptyText(hWnd, Text, Flags) \ + SendMessage((hWnd), TNM_SETEMPTYTEXT, (WPARAM)(Flags), (LPARAM)(Text)) + +#define TreeNew_SetRowHeight(hWnd, RowHeight) \ + SendMessage((hWnd), TNM_SETROWHEIGHT, (WPARAM)(RowHeight), 0) + +#define TreeNew_IsFlatNodeValid(hWnd) \ + ((BOOLEAN)SendMessage((hWnd), TNM_ISFLATNODEVALID, 0, 0)) + +typedef struct _PH_TREENEW_VIEW_PARTS +{ + RECT ClientRect; + LONG HeaderHeight; + LONG RowHeight; + ULONG VScrollWidth; + ULONG HScrollHeight; + LONG VScrollPosition; + LONG HScrollPosition; + LONG FixedWidth; + LONG NormalLeft; + LONG NormalWidth; +} PH_TREENEW_VIEW_PARTS, *PPH_TREENEW_VIEW_PARTS; + +PHLIBAPI +BOOLEAN PhTreeNewInitialization( + VOID + ); + +FORCEINLINE VOID PhInitializeTreeNewNode( + _In_ PPH_TREENEW_NODE Node + ) +{ + memset(Node, 0, sizeof(PH_TREENEW_NODE)); + + Node->Visible = TRUE; + Node->Expanded = TRUE; +} + +FORCEINLINE VOID PhInvalidateTreeNewNode( + _Inout_ PPH_TREENEW_NODE Node, + _In_ ULONG Flags + ) +{ + if (Flags & TN_CACHE_COLOR) + Node->s.CachedColorValid = FALSE; + if (Flags & TN_CACHE_FONT) + Node->s.CachedFontValid = FALSE; + if (Flags & TN_CACHE_ICON) + Node->s.CachedIconValid = FALSE; +} + +FORCEINLINE BOOLEAN PhAddTreeNewColumn( + _In_ HWND hwnd, + _In_ ULONG Id, + _In_ BOOLEAN Visible, + _In_ PWSTR Text, + _In_ ULONG Width, + _In_ ULONG Alignment, + _In_ ULONG DisplayIndex, + _In_ ULONG TextFlags + ) +{ + PH_TREENEW_COLUMN column; + + memset(&column, 0, sizeof(PH_TREENEW_COLUMN)); + column.Id = Id; + column.Visible = Visible; + column.Text = Text; + column.Width = Width; + column.Alignment = Alignment; + column.DisplayIndex = DisplayIndex; + column.TextFlags = TextFlags; + column.DpiScaleOnAdd = TRUE; + + if (DisplayIndex == -2) + column.Fixed = TRUE; + + return !!TreeNew_AddColumn(hwnd, &column); +} + +FORCEINLINE BOOLEAN PhAddTreeNewColumnEx( + _In_ HWND hwnd, + _In_ ULONG Id, + _In_ BOOLEAN Visible, + _In_ PWSTR Text, + _In_ ULONG Width, + _In_ ULONG Alignment, + _In_ ULONG DisplayIndex, + _In_ ULONG TextFlags, + _In_ BOOLEAN SortDescending + ) +{ + PH_TREENEW_COLUMN column; + + memset(&column, 0, sizeof(PH_TREENEW_COLUMN)); + column.Id = Id; + column.Visible = Visible; + column.Text = Text; + column.Width = Width; + column.Alignment = Alignment; + column.DisplayIndex = DisplayIndex; + column.TextFlags = TextFlags; + column.DpiScaleOnAdd = TRUE; + + if (DisplayIndex == -2) + column.Fixed = TRUE; + if (SortDescending) + column.SortDescending = TRUE; + + return !!TreeNew_AddColumn(hwnd, &column); +} + +FORCEINLINE BOOLEAN PhAddTreeNewColumnEx2( + _In_ HWND hwnd, + _In_ ULONG Id, + _In_ BOOLEAN Visible, + _In_ PWSTR Text, + _In_ ULONG Width, + _In_ ULONG Alignment, + _In_ ULONG DisplayIndex, + _In_ ULONG TextFlags, + _In_ ULONG ExtraFlags + ) +{ + PH_TREENEW_COLUMN column; + + memset(&column, 0, sizeof(PH_TREENEW_COLUMN)); + column.Id = Id; + column.Visible = Visible; + column.Text = Text; + column.Width = Width; + column.Alignment = Alignment; + column.DisplayIndex = DisplayIndex; + column.TextFlags = TextFlags; + + if (DisplayIndex == -2) + column.Fixed = TRUE; + if (ExtraFlags & TN_COLUMN_FLAG_CUSTOMDRAW) + column.CustomDraw = TRUE; + if (ExtraFlags & TN_COLUMN_FLAG_SORTDESCENDING) + column.SortDescending = TRUE; + if (!(ExtraFlags & TN_COLUMN_FLAG_NODPISCALEONADD)) + column.DpiScaleOnAdd = TRUE; + + return !!TreeNew_AddColumn(hwnd, &column); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/phlib/include/treenewp.h b/phlib/include/treenewp.h index b8f1d8472ae3..8904a3a1a7cb 100644 --- a/phlib/include/treenewp.h +++ b/phlib/include/treenewp.h @@ -1,799 +1,799 @@ -#ifndef _PH_TREENEWP_H -#define _PH_TREENEWP_H - -// Important notes about pointers: -// -// All memory allocation for nodes and strings is handled by the user. This usually means there is a -// very limited time during which they can be safely accessed. -// -// Node pointers are valid through the duration of message processing, and also up to the next -// restructure operation, either user- or control- initiated. This means that state such as the -// focused node, hot node and mark node must be carefully preserved through restructuring. If -// restructuring is suspended by a set-redraw call, all nodes must be considered invalid and no user -// input can be handled. -// -// Strings are valid only through the duration of message processing. - -typedef struct _PH_TREENEW_CONTEXT -{ - HWND Handle; - PVOID InstanceHandle; - HWND FixedHeaderHandle; - HWND HeaderHandle; - HWND VScrollHandle; - HWND HScrollHandle; - HWND FillerBoxHandle; - HWND TooltipsHandle; - - union - { - struct - { - ULONG FontOwned : 1; - ULONG Tracking : 1; // tracking for fixed divider - ULONG VScrollVisible : 1; - ULONG HScrollVisible : 1; - ULONG FixedColumnVisible : 1; - ULONG FixedDividerVisible : 1; - ULONG AnimateDivider : 1; - ULONG AnimateDividerFadingIn : 1; - ULONG AnimateDividerFadingOut : 1; - ULONG CanAnyExpand : 1; - ULONG TriState : 1; - ULONG HasFocus : 1; - ULONG ThemeInitialized : 1; // delay load theme data - ULONG ThemeActive : 1; - ULONG ThemeHasItemBackground : 1; - ULONG ThemeHasGlyph : 1; - ULONG ThemeHasHotGlyph : 1; - ULONG FocusNodeFound : 1; // used to preserve the focused node across restructuring - ULONG SearchFailed : 1; // used to prevent multiple beeps - ULONG SearchSingleCharMode : 1; // LV style single-character search - ULONG TooltipUnfolding : 1; // whether the current tooltip is unfolding - ULONG DoubleBuffered : 1; - ULONG SuspendUpdateStructure : 1; - ULONG SuspendUpdateLayout : 1; - ULONG SuspendUpdateMoveMouse : 1; - ULONG DragSelectionActive : 1; - ULONG SelectionRectangleAlpha : 1; // use alpha blending for the selection rectangle - ULONG CustomRowHeight : 1; - ULONG Spare : 4; - }; - ULONG Flags; - }; - ULONG Style; - ULONG ExtendedStyle; - ULONG ExtendedFlags; - - HFONT Font; - HCURSOR Cursor; - HCURSOR DividerCursor; - - RECT ClientRect; - LONG HeaderHeight; - LONG RowHeight; - ULONG VScrollWidth; - ULONG HScrollHeight; - LONG VScrollPosition; - LONG HScrollPosition; - LONG FixedWidth; // width of the fixed part of the tree list - LONG FixedWidthMinimum; - LONG NormalLeft; // FixedWidth + 1 if there is a fixed column, otherwise 0 - - PPH_TREENEW_NODE FocusNode; - ULONG HotNodeIndex; - ULONG MarkNodeIndex; // selection mark - - ULONG MouseDownLast; - POINT MouseDownLocation; - - PPH_TREENEW_CALLBACK Callback; - PVOID CallbackContext; - - PPH_TREENEW_COLUMN *Columns; // columns, indexed by ID - ULONG NextId; - ULONG AllocatedColumns; - ULONG NumberOfColumns; // just a statistic; do not use for actual logic - - PPH_TREENEW_COLUMN *ColumnsByDisplay; // columns, indexed by display order (excluding the fixed column) - ULONG AllocatedColumnsByDisplay; - ULONG NumberOfColumnsByDisplay; // the number of visible columns (excluding the fixed column) - LONG TotalViewX; // total width of normal columns - PPH_TREENEW_COLUMN FixedColumn; - PPH_TREENEW_COLUMN FirstColumn; // first column, by display order (including the fixed column) - PPH_TREENEW_COLUMN LastColumn; // last column, by display order (including the fixed column) - - PPH_TREENEW_COLUMN ResizingColumn; - LONG OldColumnWidth; - LONG TrackStartX; - LONG TrackOldFixedWidth; - ULONG DividerHot; // 0 for un-hot, 100 for completely hot - - PPH_LIST FlatList; - - ULONG SortColumn; // ID of the column to sort by - PH_SORT_ORDER SortOrder; - - FLOAT VScrollRemainder; - FLOAT HScrollRemainder; - - LONG SearchMessageTime; - PWSTR SearchString; - ULONG SearchStringCount; - ULONG AllocatedSearchString; - - ULONG TooltipIndex; - ULONG TooltipId; - PPH_STRING TooltipText; - RECT TooltipRect; // text rectangle of an unfolding tooltip - HFONT TooltipFont; - HFONT NewTooltipFont; - ULONG TooltipColumnId; - - TEXTMETRIC TextMetrics; - HTHEME ThemeData; - LONG SystemBorderX; - LONG SystemBorderY; - LONG SystemEdgeX; - LONG SystemEdgeY; - - HDC BufferedContext; - HBITMAP BufferedOldBitmap; - HBITMAP BufferedBitmap; - RECT BufferedContextRect; - - LONG SystemDragX; - LONG SystemDragY; - RECT DragRect; - - LONG EnableRedraw; - HRGN SuspendUpdateRegion; - - PH_STRINGREF EmptyText; -} PH_TREENEW_CONTEXT, *PPH_TREENEW_CONTEXT; - -LRESULT CALLBACK PhTnpWndProc( - _In_ HWND hwnd, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -BOOLEAN NTAPI PhTnpNullCallback( - _In_ HWND hwnd, - _In_ PH_TREENEW_MESSAGE Message, - _In_opt_ PVOID Parameter1, - _In_opt_ PVOID Parameter2, - _In_opt_ PVOID Context - ); - -VOID PhTnpCreateTreeNewContext( - _Out_ PPH_TREENEW_CONTEXT *Context - ); - -VOID PhTnpDestroyTreeNewContext( - _In_ PPH_TREENEW_CONTEXT Context - ); - -// Event handlers - -BOOLEAN PhTnpOnCreate( - _In_ HWND hwnd, - _In_ PPH_TREENEW_CONTEXT Context, - _In_ CREATESTRUCT *CreateStruct - ); - -VOID PhTnpOnSize( - _In_ HWND hwnd, - _In_ PPH_TREENEW_CONTEXT Context - ); - -VOID PhTnpOnSetFont( - _In_ HWND hwnd, - _In_ PPH_TREENEW_CONTEXT Context, - _In_opt_ HFONT Font, - _In_ LOGICAL Redraw - ); - -VOID PhTnpOnStyleChanged( - _In_ HWND hwnd, - _In_ PPH_TREENEW_CONTEXT Context, - _In_ LONG Type, - _In_ STYLESTRUCT *StyleStruct - ); - -VOID PhTnpOnSettingChange( - _In_ HWND hwnd, - _In_ PPH_TREENEW_CONTEXT Context - ); - -VOID PhTnpOnThemeChanged( - _In_ HWND hwnd, - _In_ PPH_TREENEW_CONTEXT Context - ); - -ULONG PhTnpOnGetDlgCode( - _In_ HWND hwnd, - _In_ PPH_TREENEW_CONTEXT Context, - _In_ ULONG VirtualKey, - _In_opt_ PMSG Message - ); - -VOID PhTnpOnPaint( - _In_ HWND hwnd, - _In_ PPH_TREENEW_CONTEXT Context - ); - -VOID PhTnpOnPrintClient( - _In_ HWND hwnd, - _In_ PPH_TREENEW_CONTEXT Context, - _In_ HDC hdc, - _In_ ULONG Flags - ); - -BOOLEAN PhTnpOnNcPaint( - _In_ HWND hwnd, - _In_ PPH_TREENEW_CONTEXT Context, - _In_opt_ HRGN UpdateRegion - ); - -BOOLEAN PhTnpOnSetCursor( - _In_ HWND hwnd, - _In_ PPH_TREENEW_CONTEXT Context, - _In_ HWND CursorWindowHandle - ); - -VOID PhTnpOnTimer( - _In_ HWND hwnd, - _In_ PPH_TREENEW_CONTEXT Context, - _In_ ULONG Id - ); - -VOID PhTnpOnMouseMove( - _In_ HWND hwnd, - _In_ PPH_TREENEW_CONTEXT Context, - _In_ ULONG VirtualKeys, - _In_ LONG CursorX, - _In_ LONG CursorY - ); - -VOID PhTnpOnMouseLeave( - _In_ HWND hwnd, - _In_ PPH_TREENEW_CONTEXT Context - ); - -VOID PhTnpOnXxxButtonXxx( - _In_ HWND hwnd, - _In_ PPH_TREENEW_CONTEXT Context, - _In_ ULONG Message, - _In_ ULONG VirtualKeys, - _In_ LONG CursorX, - _In_ LONG CursorY - ); - -VOID PhTnpOnCaptureChanged( - _In_ HWND hwnd, - _In_ PPH_TREENEW_CONTEXT Context - ); - -VOID PhTnpOnKeyDown( - _In_ HWND hwnd, - _In_ PPH_TREENEW_CONTEXT Context, - _In_ ULONG VirtualKey, - _In_ ULONG Data - ); - -VOID PhTnpOnChar( - _In_ HWND hwnd, - _In_ PPH_TREENEW_CONTEXT Context, - _In_ ULONG Character, - _In_ ULONG Data - ); - -VOID PhTnpOnMouseWheel( - _In_ HWND hwnd, - _In_ PPH_TREENEW_CONTEXT Context, - _In_ LONG Distance, - _In_ ULONG VirtualKeys, - _In_ LONG CursorX, - _In_ LONG CursorY - ); - -VOID PhTnpOnMouseHWheel( - _In_ HWND hwnd, - _In_ PPH_TREENEW_CONTEXT Context, - _In_ LONG Distance, - _In_ ULONG VirtualKeys, - _In_ LONG CursorX, - _In_ LONG CursorY - ); - -VOID PhTnpOnContextMenu( - _In_ HWND hwnd, - _In_ PPH_TREENEW_CONTEXT Context, - _In_ LONG CursorScreenX, - _In_ LONG CursorScreenY - ); - -VOID PhTnpOnVScroll( - _In_ HWND hwnd, - _In_ PPH_TREENEW_CONTEXT Context, - _In_ ULONG Request, - _In_ USHORT Position - ); - -VOID PhTnpOnHScroll( - _In_ HWND hwnd, - _In_ PPH_TREENEW_CONTEXT Context, - _In_ ULONG Request, - _In_ USHORT Position - ); - -BOOLEAN PhTnpOnNotify( - _In_ HWND hwnd, - _In_ PPH_TREENEW_CONTEXT Context, - _In_ NMHDR *Header, - _Out_ LRESULT *Result - ); - -ULONG_PTR PhTnpOnUserMessage( - _In_ HWND hwnd, - _In_ PPH_TREENEW_CONTEXT Context, - _In_ ULONG Message, - _In_ ULONG_PTR WParam, - _In_ ULONG_PTR LParam - ); - -// Misc. - -VOID PhTnpSetFont( - _In_ PPH_TREENEW_CONTEXT Context, - _In_opt_ HFONT Font, - _In_ BOOLEAN Redraw - ); - -VOID PhTnpUpdateSystemMetrics( - _In_ PPH_TREENEW_CONTEXT Context - ); - -VOID PhTnpUpdateTextMetrics( - _In_ PPH_TREENEW_CONTEXT Context - ); - -VOID PhTnpUpdateThemeData( - _In_ PPH_TREENEW_CONTEXT Context - ); - -VOID PhTnpInitializeThemeData( - _In_ PPH_TREENEW_CONTEXT Context - ); - -VOID PhTnpCancelTrack( - _In_ PPH_TREENEW_CONTEXT Context - ); - -VOID PhTnpLayout( - _In_ PPH_TREENEW_CONTEXT Context - ); - -VOID PhTnpLayoutHeader( - _In_ PPH_TREENEW_CONTEXT Context - ); - -VOID PhTnpSetFixedWidth( - _In_ PPH_TREENEW_CONTEXT Context, - _In_ ULONG FixedWidth - ); - -VOID PhTnpSetRedraw( - _In_ PPH_TREENEW_CONTEXT Context, - _In_ BOOLEAN Redraw - ); - -VOID PhTnpSendMouseEvent( - _In_ PPH_TREENEW_CONTEXT Context, - _In_ PH_TREENEW_MESSAGE Message, - _In_ LONG CursorX, - _In_ LONG CursorY, - _In_ PPH_TREENEW_NODE Node, - _In_ PPH_TREENEW_COLUMN Column, - _In_ ULONG VirtualKeys - ); - -// Columns - -PPH_TREENEW_COLUMN PhTnpLookupColumnById( - _In_ PPH_TREENEW_CONTEXT Context, - _In_ ULONG Id - ); - -BOOLEAN PhTnpAddColumn( - _In_ PPH_TREENEW_CONTEXT Context, - _In_ PPH_TREENEW_COLUMN Column - ); - -BOOLEAN PhTnpRemoveColumn( - _In_ PPH_TREENEW_CONTEXT Context, - _In_ ULONG Id - ); - -BOOLEAN PhTnpCopyColumn( - _In_ PPH_TREENEW_CONTEXT Context, - _In_ ULONG Id, - _Out_ PPH_TREENEW_COLUMN Column - ); - -BOOLEAN PhTnpChangeColumn( - _In_ PPH_TREENEW_CONTEXT Context, - _In_ ULONG Mask, - _In_ ULONG Id, - _In_ PPH_TREENEW_COLUMN Column - ); - -VOID PhTnpExpandAllocatedColumns( - _In_ PPH_TREENEW_CONTEXT Context - ); - -VOID PhTnpUpdateColumnMaps( - _In_ PPH_TREENEW_CONTEXT Context - ); - -// Columns (header control) - -LONG PhTnpInsertColumnHeader( - _In_ PPH_TREENEW_CONTEXT Context, - _In_ PPH_TREENEW_COLUMN Column - ); - -VOID PhTnpChangeColumnHeader( - _In_ PPH_TREENEW_CONTEXT Context, - _In_ ULONG Mask, - _In_ PPH_TREENEW_COLUMN Column - ); - -VOID PhTnpDeleteColumnHeader( - _In_ PPH_TREENEW_CONTEXT Context, - _Inout_ PPH_TREENEW_COLUMN Column - ); - -VOID PhTnpUpdateColumnHeaders( - _In_ PPH_TREENEW_CONTEXT Context - ); - -VOID PhTnpProcessResizeColumn( - _In_ PPH_TREENEW_CONTEXT Context, - _In_ PPH_TREENEW_COLUMN Column, - _In_ LONG Delta - ); - -VOID PhTnpProcessSortColumn( - _In_ PPH_TREENEW_CONTEXT Context, - _In_ PPH_TREENEW_COLUMN NewColumn - ); - -BOOLEAN PhTnpSetColumnHeaderSortIcon( - _In_ PPH_TREENEW_CONTEXT Context, - _In_opt_ PPH_TREENEW_COLUMN SortColumnPointer - ); - -VOID PhTnpAutoSizeColumnHeader( - _In_ PPH_TREENEW_CONTEXT Context, - _In_ HWND HeaderHandle, - _In_ PPH_TREENEW_COLUMN Column, - _In_ ULONG Flags - ); - -// Nodes - -BOOLEAN PhTnpGetNodeChildren( - _In_ PPH_TREENEW_CONTEXT Context, - _In_opt_ PPH_TREENEW_NODE Node, - _Out_ PPH_TREENEW_NODE **Children, - _Out_ PULONG NumberOfChildren - ); - -BOOLEAN PhTnpIsNodeLeaf( - _In_ PPH_TREENEW_CONTEXT Context, - _In_ PPH_TREENEW_NODE Node - ); - -BOOLEAN PhTnpGetCellText( - _In_ PPH_TREENEW_CONTEXT Context, - _In_ PPH_TREENEW_NODE Node, - _In_ ULONG Id, - _Out_ PPH_STRINGREF Text - ); - -VOID PhTnpRestructureNodes( - _In_ PPH_TREENEW_CONTEXT Context - ); - -VOID PhTnpInsertNodeChildren( - _In_ PPH_TREENEW_CONTEXT Context, - _In_ PPH_TREENEW_NODE Node, - _In_ ULONG Level - ); - -VOID PhTnpSetExpandedNode( - _In_ PPH_TREENEW_CONTEXT Context, - _In_ PPH_TREENEW_NODE Node, - _In_ BOOLEAN Expanded - ); - -BOOLEAN PhTnpGetCellParts( - _In_ PPH_TREENEW_CONTEXT Context, - _In_ ULONG Index, - _In_opt_ PPH_TREENEW_COLUMN Column, - _In_ ULONG Flags, - _Out_ PPH_TREENEW_CELL_PARTS Parts - ); - -BOOLEAN PhTnpGetRowRects( - _In_ PPH_TREENEW_CONTEXT Context, - _In_ ULONG Start, - _In_ ULONG End, - _In_ BOOLEAN Clip, - _Out_ PRECT Rect - ); - -VOID PhTnpHitTest( - _In_ PPH_TREENEW_CONTEXT Context, - _Inout_ PPH_TREENEW_HIT_TEST HitTest - ); - -VOID PhTnpSelectRange( - _In_ PPH_TREENEW_CONTEXT Context, - _In_ ULONG Start, - _In_ ULONG End, - _In_ ULONG Flags, - _Out_opt_ PULONG ChangedStart, - _Out_opt_ PULONG ChangedEnd - ); - -VOID PhTnpSetHotNode( - _In_ PPH_TREENEW_CONTEXT Context, - _In_opt_ PPH_TREENEW_NODE NewHotNode, - _In_ BOOLEAN NewPlusMinusHot - ); - -VOID PhTnpProcessSelectNode( - _In_ PPH_TREENEW_CONTEXT Context, - _In_ PPH_TREENEW_NODE Node, - _In_ LOGICAL ControlKey, - _In_ LOGICAL ShiftKey, - _In_ LOGICAL RightButton - ); - -BOOLEAN PhTnpEnsureVisibleNode( - _In_ PPH_TREENEW_CONTEXT Context, - _In_ ULONG Index - ); - -// Mouse - -VOID PhTnpProcessMoveMouse( - _In_ PPH_TREENEW_CONTEXT Context, - _In_ LONG CursorX, - _In_ LONG CursorY - ); - -VOID PhTnpProcessMouseVWheel( - _In_ PPH_TREENEW_CONTEXT Context, - _In_ LONG Distance - ); - -VOID PhTnpProcessMouseHWheel( - _In_ PPH_TREENEW_CONTEXT Context, - _In_ LONG Distance - ); - -// Keyboard - -BOOLEAN PhTnpProcessFocusKey( - _In_ PPH_TREENEW_CONTEXT Context, - _In_ ULONG VirtualKey - ); - -BOOLEAN PhTnpProcessNodeKey( - _In_ PPH_TREENEW_CONTEXT Context, - _In_ ULONG VirtualKey - ); - -VOID PhTnpProcessSearchKey( - _In_ PPH_TREENEW_CONTEXT Context, - _In_ ULONG Character - ); - -BOOLEAN PhTnpDefaultIncrementalSearch( - _In_ PPH_TREENEW_CONTEXT Context, - _Inout_ PPH_TREENEW_SEARCH_EVENT SearchEvent, - _In_ BOOLEAN Partial, - _In_ BOOLEAN Wrap - ); - -// Scrolling - -VOID PhTnpUpdateScrollBars( - _In_ PPH_TREENEW_CONTEXT Context - ); - -VOID PhTnpScroll( - _In_ PPH_TREENEW_CONTEXT Context, - _In_ LONG DeltaRows, - _In_ LONG DeltaX - ); - -VOID PhTnpProcessScroll( - _In_ PPH_TREENEW_CONTEXT Context, - _In_ LONG DeltaRows, - _In_ LONG DeltaX - ); - -BOOLEAN PhTnpCanScroll( - _In_ PPH_TREENEW_CONTEXT Context, - _In_ BOOLEAN Horizontal, - _In_ BOOLEAN Positive - ); - -// Drawing - -VOID PhTnpPaint( - _In_ HWND hwnd, - _In_ PPH_TREENEW_CONTEXT Context, - _In_ HDC hdc, - _In_ PRECT PaintRect - ); - -VOID PhTnpPrepareRowForDraw( - _In_ PPH_TREENEW_CONTEXT Context, - _In_ HDC hdc, - _Inout_ PPH_TREENEW_NODE Node - ); - -VOID PhTnpDrawCell( - _In_ PPH_TREENEW_CONTEXT Context, - _In_ HDC hdc, - _In_ PRECT CellRect, - _In_ PPH_TREENEW_NODE Node, - _In_ PPH_TREENEW_COLUMN Column, - _In_ LONG RowIndex, - _In_ LONG ColumnIndex - ); - -VOID PhTnpDrawDivider( - _In_ PPH_TREENEW_CONTEXT Context, - _In_ HDC hdc - ); - -VOID PhTnpDrawPlusMinusGlyph( - _In_ HDC hdc, - _In_ PRECT Rect, - _In_ BOOLEAN Plus - ); - -VOID PhTnpDrawSelectionRectangle( - _In_ PPH_TREENEW_CONTEXT Context, - _In_ HDC hdc, - _In_ PRECT Rect - ); - -VOID PhTnpDrawThemedBorder( - _In_ PPH_TREENEW_CONTEXT Context, - _In_ HDC hdc - ); - -// Tooltips - -VOID PhTnpInitializeTooltips( - _In_ PPH_TREENEW_CONTEXT Context - ); - -VOID PhTnpGetTooltipText( - _In_ PPH_TREENEW_CONTEXT Context, - _In_ PPOINT Point, - _Out_ PWSTR *Text - ); - -BOOLEAN PhTnpPrepareTooltipShow( - _In_ PPH_TREENEW_CONTEXT Context - ); - -VOID PhTnpPrepareTooltipPop( - _In_ PPH_TREENEW_CONTEXT Context - ); - -VOID PhTnpPopTooltip( - _In_ PPH_TREENEW_CONTEXT Context - ); - -PPH_TREENEW_COLUMN PhTnpHitTestHeader( - _In_ PPH_TREENEW_CONTEXT Context, - _In_ BOOLEAN Fixed, - _In_ PPOINT Point, - _Out_opt_ PRECT ItemRect - ); - -VOID PhTnpGetHeaderTooltipText( - _In_ PPH_TREENEW_CONTEXT Context, - _In_ BOOLEAN Fixed, - _In_ PPOINT Point, - _Out_ PWSTR *Text - ); - - -LRESULT CALLBACK PhTnpHeaderHookWndProc( - _In_ HWND hwnd, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam, - _In_ UINT_PTR uIdSubclass, - _In_ ULONG_PTR dwRefData - ); - -// Drag selection - -BOOLEAN PhTnpDetectDrag( - _In_ PPH_TREENEW_CONTEXT Context, - _In_ LONG CursorX, - _In_ LONG CursorY, - _In_ BOOLEAN DispatchMessages, - _Out_opt_ PULONG CancelledByMessage - ); - -VOID PhTnpDragSelect( - _In_ PPH_TREENEW_CONTEXT Context, - _In_ LONG CursorX, - _In_ LONG CursorY - ); - -VOID PhTnpProcessDragSelect( - _In_ PPH_TREENEW_CONTEXT Context, - _In_ ULONG VirtualKeys, - _In_ PRECT OldRect, - _In_ PRECT NewRect, - _In_ PRECT TotalRect - ); - -// Double buffering - -VOID PhTnpCreateBufferedContext( - _In_ PPH_TREENEW_CONTEXT Context - ); - -VOID PhTnpDestroyBufferedContext( - _In_ PPH_TREENEW_CONTEXT Context - ); - -// Support functions - -VOID PhTnpGetMessagePos( - _In_ HWND hwnd, - _Out_ PPOINT ClientPoint - ); - -// Macros - -#define HRGN_FULL ((HRGN)1) // passed by WM_NCPAINT even though it's completely undocumented - -#define TNP_CELL_LEFT_MARGIN 6 -#define TNP_CELL_RIGHT_MARGIN 6 -#define TNP_ICON_RIGHT_PADDING 4 - -#define TNP_TIMER_NULL 1 -#define TNP_TIMER_ANIMATE_DIVIDER 2 - -#define TNP_TOOLTIPS_ITEM 0 -#define TNP_TOOLTIPS_FIXED_HEADER 1 -#define TNP_TOOLTIPS_HEADER 2 -#define TNP_TOOLTIPS_DEFAULT_MAXIMUM_WIDTH 550 - -#define TNP_ANIMATE_DIVIDER_INTERVAL 10 -#define TNP_ANIMATE_DIVIDER_INCREMENT 17 -#define TNP_ANIMATE_DIVIDER_DECREMENT 2 - -#define TNP_HIT_TEST_FIXED_DIVIDER(X, Context) \ - ((Context)->FixedDividerVisible && (X) >= (Context)->FixedWidth - 8 && (X) < (Context)->FixedWidth + 8) -#define TNP_HIT_TEST_PLUS_MINUS_GLYPH(X, NodeLevel) \ - (((X) >= TNP_CELL_LEFT_MARGIN + ((LONG)(NodeLevel) * SmallIconWidth)) && ((X) < TNP_CELL_LEFT_MARGIN + ((LONG)(NodeLevel) * SmallIconWidth) + SmallIconWidth)) - -#endif +#ifndef _PH_TREENEWP_H +#define _PH_TREENEWP_H + +// Important notes about pointers: +// +// All memory allocation for nodes and strings is handled by the user. This usually means there is a +// very limited time during which they can be safely accessed. +// +// Node pointers are valid through the duration of message processing, and also up to the next +// restructure operation, either user- or control- initiated. This means that state such as the +// focused node, hot node and mark node must be carefully preserved through restructuring. If +// restructuring is suspended by a set-redraw call, all nodes must be considered invalid and no user +// input can be handled. +// +// Strings are valid only through the duration of message processing. + +typedef struct _PH_TREENEW_CONTEXT +{ + HWND Handle; + PVOID InstanceHandle; + HWND FixedHeaderHandle; + HWND HeaderHandle; + HWND VScrollHandle; + HWND HScrollHandle; + HWND FillerBoxHandle; + HWND TooltipsHandle; + + union + { + struct + { + ULONG FontOwned : 1; + ULONG Tracking : 1; // tracking for fixed divider + ULONG VScrollVisible : 1; + ULONG HScrollVisible : 1; + ULONG FixedColumnVisible : 1; + ULONG FixedDividerVisible : 1; + ULONG AnimateDivider : 1; + ULONG AnimateDividerFadingIn : 1; + ULONG AnimateDividerFadingOut : 1; + ULONG CanAnyExpand : 1; + ULONG TriState : 1; + ULONG HasFocus : 1; + ULONG ThemeInitialized : 1; // delay load theme data + ULONG ThemeActive : 1; + ULONG ThemeHasItemBackground : 1; + ULONG ThemeHasGlyph : 1; + ULONG ThemeHasHotGlyph : 1; + ULONG FocusNodeFound : 1; // used to preserve the focused node across restructuring + ULONG SearchFailed : 1; // used to prevent multiple beeps + ULONG SearchSingleCharMode : 1; // LV style single-character search + ULONG TooltipUnfolding : 1; // whether the current tooltip is unfolding + ULONG DoubleBuffered : 1; + ULONG SuspendUpdateStructure : 1; + ULONG SuspendUpdateLayout : 1; + ULONG SuspendUpdateMoveMouse : 1; + ULONG DragSelectionActive : 1; + ULONG SelectionRectangleAlpha : 1; // use alpha blending for the selection rectangle + ULONG CustomRowHeight : 1; + ULONG Spare : 4; + }; + ULONG Flags; + }; + ULONG Style; + ULONG ExtendedStyle; + ULONG ExtendedFlags; + + HFONT Font; + HCURSOR Cursor; + HCURSOR DividerCursor; + + RECT ClientRect; + LONG HeaderHeight; + LONG RowHeight; + ULONG VScrollWidth; + ULONG HScrollHeight; + LONG VScrollPosition; + LONG HScrollPosition; + LONG FixedWidth; // width of the fixed part of the tree list + LONG FixedWidthMinimum; + LONG NormalLeft; // FixedWidth + 1 if there is a fixed column, otherwise 0 + + PPH_TREENEW_NODE FocusNode; + ULONG HotNodeIndex; + ULONG MarkNodeIndex; // selection mark + + ULONG MouseDownLast; + POINT MouseDownLocation; + + PPH_TREENEW_CALLBACK Callback; + PVOID CallbackContext; + + PPH_TREENEW_COLUMN *Columns; // columns, indexed by ID + ULONG NextId; + ULONG AllocatedColumns; + ULONG NumberOfColumns; // just a statistic; do not use for actual logic + + PPH_TREENEW_COLUMN *ColumnsByDisplay; // columns, indexed by display order (excluding the fixed column) + ULONG AllocatedColumnsByDisplay; + ULONG NumberOfColumnsByDisplay; // the number of visible columns (excluding the fixed column) + LONG TotalViewX; // total width of normal columns + PPH_TREENEW_COLUMN FixedColumn; + PPH_TREENEW_COLUMN FirstColumn; // first column, by display order (including the fixed column) + PPH_TREENEW_COLUMN LastColumn; // last column, by display order (including the fixed column) + + PPH_TREENEW_COLUMN ResizingColumn; + LONG OldColumnWidth; + LONG TrackStartX; + LONG TrackOldFixedWidth; + ULONG DividerHot; // 0 for un-hot, 100 for completely hot + + PPH_LIST FlatList; + + ULONG SortColumn; // ID of the column to sort by + PH_SORT_ORDER SortOrder; + + FLOAT VScrollRemainder; + FLOAT HScrollRemainder; + + LONG SearchMessageTime; + PWSTR SearchString; + ULONG SearchStringCount; + ULONG AllocatedSearchString; + + ULONG TooltipIndex; + ULONG TooltipId; + PPH_STRING TooltipText; + RECT TooltipRect; // text rectangle of an unfolding tooltip + HFONT TooltipFont; + HFONT NewTooltipFont; + ULONG TooltipColumnId; + + TEXTMETRIC TextMetrics; + HTHEME ThemeData; + LONG SystemBorderX; + LONG SystemBorderY; + LONG SystemEdgeX; + LONG SystemEdgeY; + + HDC BufferedContext; + HBITMAP BufferedOldBitmap; + HBITMAP BufferedBitmap; + RECT BufferedContextRect; + + LONG SystemDragX; + LONG SystemDragY; + RECT DragRect; + + LONG EnableRedraw; + HRGN SuspendUpdateRegion; + + PH_STRINGREF EmptyText; +} PH_TREENEW_CONTEXT, *PPH_TREENEW_CONTEXT; + +LRESULT CALLBACK PhTnpWndProc( + _In_ HWND hwnd, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +BOOLEAN NTAPI PhTnpNullCallback( + _In_ HWND hwnd, + _In_ PH_TREENEW_MESSAGE Message, + _In_opt_ PVOID Parameter1, + _In_opt_ PVOID Parameter2, + _In_opt_ PVOID Context + ); + +VOID PhTnpCreateTreeNewContext( + _Out_ PPH_TREENEW_CONTEXT *Context + ); + +VOID PhTnpDestroyTreeNewContext( + _In_ PPH_TREENEW_CONTEXT Context + ); + +// Event handlers + +BOOLEAN PhTnpOnCreate( + _In_ HWND hwnd, + _In_ PPH_TREENEW_CONTEXT Context, + _In_ CREATESTRUCT *CreateStruct + ); + +VOID PhTnpOnSize( + _In_ HWND hwnd, + _In_ PPH_TREENEW_CONTEXT Context + ); + +VOID PhTnpOnSetFont( + _In_ HWND hwnd, + _In_ PPH_TREENEW_CONTEXT Context, + _In_opt_ HFONT Font, + _In_ LOGICAL Redraw + ); + +VOID PhTnpOnStyleChanged( + _In_ HWND hwnd, + _In_ PPH_TREENEW_CONTEXT Context, + _In_ LONG Type, + _In_ STYLESTRUCT *StyleStruct + ); + +VOID PhTnpOnSettingChange( + _In_ HWND hwnd, + _In_ PPH_TREENEW_CONTEXT Context + ); + +VOID PhTnpOnThemeChanged( + _In_ HWND hwnd, + _In_ PPH_TREENEW_CONTEXT Context + ); + +ULONG PhTnpOnGetDlgCode( + _In_ HWND hwnd, + _In_ PPH_TREENEW_CONTEXT Context, + _In_ ULONG VirtualKey, + _In_opt_ PMSG Message + ); + +VOID PhTnpOnPaint( + _In_ HWND hwnd, + _In_ PPH_TREENEW_CONTEXT Context + ); + +VOID PhTnpOnPrintClient( + _In_ HWND hwnd, + _In_ PPH_TREENEW_CONTEXT Context, + _In_ HDC hdc, + _In_ ULONG Flags + ); + +BOOLEAN PhTnpOnNcPaint( + _In_ HWND hwnd, + _In_ PPH_TREENEW_CONTEXT Context, + _In_opt_ HRGN UpdateRegion + ); + +BOOLEAN PhTnpOnSetCursor( + _In_ HWND hwnd, + _In_ PPH_TREENEW_CONTEXT Context, + _In_ HWND CursorWindowHandle + ); + +VOID PhTnpOnTimer( + _In_ HWND hwnd, + _In_ PPH_TREENEW_CONTEXT Context, + _In_ ULONG Id + ); + +VOID PhTnpOnMouseMove( + _In_ HWND hwnd, + _In_ PPH_TREENEW_CONTEXT Context, + _In_ ULONG VirtualKeys, + _In_ LONG CursorX, + _In_ LONG CursorY + ); + +VOID PhTnpOnMouseLeave( + _In_ HWND hwnd, + _In_ PPH_TREENEW_CONTEXT Context + ); + +VOID PhTnpOnXxxButtonXxx( + _In_ HWND hwnd, + _In_ PPH_TREENEW_CONTEXT Context, + _In_ ULONG Message, + _In_ ULONG VirtualKeys, + _In_ LONG CursorX, + _In_ LONG CursorY + ); + +VOID PhTnpOnCaptureChanged( + _In_ HWND hwnd, + _In_ PPH_TREENEW_CONTEXT Context + ); + +VOID PhTnpOnKeyDown( + _In_ HWND hwnd, + _In_ PPH_TREENEW_CONTEXT Context, + _In_ ULONG VirtualKey, + _In_ ULONG Data + ); + +VOID PhTnpOnChar( + _In_ HWND hwnd, + _In_ PPH_TREENEW_CONTEXT Context, + _In_ ULONG Character, + _In_ ULONG Data + ); + +VOID PhTnpOnMouseWheel( + _In_ HWND hwnd, + _In_ PPH_TREENEW_CONTEXT Context, + _In_ LONG Distance, + _In_ ULONG VirtualKeys, + _In_ LONG CursorX, + _In_ LONG CursorY + ); + +VOID PhTnpOnMouseHWheel( + _In_ HWND hwnd, + _In_ PPH_TREENEW_CONTEXT Context, + _In_ LONG Distance, + _In_ ULONG VirtualKeys, + _In_ LONG CursorX, + _In_ LONG CursorY + ); + +VOID PhTnpOnContextMenu( + _In_ HWND hwnd, + _In_ PPH_TREENEW_CONTEXT Context, + _In_ LONG CursorScreenX, + _In_ LONG CursorScreenY + ); + +VOID PhTnpOnVScroll( + _In_ HWND hwnd, + _In_ PPH_TREENEW_CONTEXT Context, + _In_ ULONG Request, + _In_ USHORT Position + ); + +VOID PhTnpOnHScroll( + _In_ HWND hwnd, + _In_ PPH_TREENEW_CONTEXT Context, + _In_ ULONG Request, + _In_ USHORT Position + ); + +BOOLEAN PhTnpOnNotify( + _In_ HWND hwnd, + _In_ PPH_TREENEW_CONTEXT Context, + _In_ NMHDR *Header, + _Out_ LRESULT *Result + ); + +ULONG_PTR PhTnpOnUserMessage( + _In_ HWND hwnd, + _In_ PPH_TREENEW_CONTEXT Context, + _In_ ULONG Message, + _In_ ULONG_PTR WParam, + _In_ ULONG_PTR LParam + ); + +// Misc. + +VOID PhTnpSetFont( + _In_ PPH_TREENEW_CONTEXT Context, + _In_opt_ HFONT Font, + _In_ BOOLEAN Redraw + ); + +VOID PhTnpUpdateSystemMetrics( + _In_ PPH_TREENEW_CONTEXT Context + ); + +VOID PhTnpUpdateTextMetrics( + _In_ PPH_TREENEW_CONTEXT Context + ); + +VOID PhTnpUpdateThemeData( + _In_ PPH_TREENEW_CONTEXT Context + ); + +VOID PhTnpInitializeThemeData( + _In_ PPH_TREENEW_CONTEXT Context + ); + +VOID PhTnpCancelTrack( + _In_ PPH_TREENEW_CONTEXT Context + ); + +VOID PhTnpLayout( + _In_ PPH_TREENEW_CONTEXT Context + ); + +VOID PhTnpLayoutHeader( + _In_ PPH_TREENEW_CONTEXT Context + ); + +VOID PhTnpSetFixedWidth( + _In_ PPH_TREENEW_CONTEXT Context, + _In_ ULONG FixedWidth + ); + +VOID PhTnpSetRedraw( + _In_ PPH_TREENEW_CONTEXT Context, + _In_ BOOLEAN Redraw + ); + +VOID PhTnpSendMouseEvent( + _In_ PPH_TREENEW_CONTEXT Context, + _In_ PH_TREENEW_MESSAGE Message, + _In_ LONG CursorX, + _In_ LONG CursorY, + _In_ PPH_TREENEW_NODE Node, + _In_ PPH_TREENEW_COLUMN Column, + _In_ ULONG VirtualKeys + ); + +// Columns + +PPH_TREENEW_COLUMN PhTnpLookupColumnById( + _In_ PPH_TREENEW_CONTEXT Context, + _In_ ULONG Id + ); + +BOOLEAN PhTnpAddColumn( + _In_ PPH_TREENEW_CONTEXT Context, + _In_ PPH_TREENEW_COLUMN Column + ); + +BOOLEAN PhTnpRemoveColumn( + _In_ PPH_TREENEW_CONTEXT Context, + _In_ ULONG Id + ); + +BOOLEAN PhTnpCopyColumn( + _In_ PPH_TREENEW_CONTEXT Context, + _In_ ULONG Id, + _Out_ PPH_TREENEW_COLUMN Column + ); + +BOOLEAN PhTnpChangeColumn( + _In_ PPH_TREENEW_CONTEXT Context, + _In_ ULONG Mask, + _In_ ULONG Id, + _In_ PPH_TREENEW_COLUMN Column + ); + +VOID PhTnpExpandAllocatedColumns( + _In_ PPH_TREENEW_CONTEXT Context + ); + +VOID PhTnpUpdateColumnMaps( + _In_ PPH_TREENEW_CONTEXT Context + ); + +// Columns (header control) + +LONG PhTnpInsertColumnHeader( + _In_ PPH_TREENEW_CONTEXT Context, + _In_ PPH_TREENEW_COLUMN Column + ); + +VOID PhTnpChangeColumnHeader( + _In_ PPH_TREENEW_CONTEXT Context, + _In_ ULONG Mask, + _In_ PPH_TREENEW_COLUMN Column + ); + +VOID PhTnpDeleteColumnHeader( + _In_ PPH_TREENEW_CONTEXT Context, + _Inout_ PPH_TREENEW_COLUMN Column + ); + +VOID PhTnpUpdateColumnHeaders( + _In_ PPH_TREENEW_CONTEXT Context + ); + +VOID PhTnpProcessResizeColumn( + _In_ PPH_TREENEW_CONTEXT Context, + _In_ PPH_TREENEW_COLUMN Column, + _In_ LONG Delta + ); + +VOID PhTnpProcessSortColumn( + _In_ PPH_TREENEW_CONTEXT Context, + _In_ PPH_TREENEW_COLUMN NewColumn + ); + +BOOLEAN PhTnpSetColumnHeaderSortIcon( + _In_ PPH_TREENEW_CONTEXT Context, + _In_opt_ PPH_TREENEW_COLUMN SortColumnPointer + ); + +VOID PhTnpAutoSizeColumnHeader( + _In_ PPH_TREENEW_CONTEXT Context, + _In_ HWND HeaderHandle, + _In_ PPH_TREENEW_COLUMN Column, + _In_ ULONG Flags + ); + +// Nodes + +BOOLEAN PhTnpGetNodeChildren( + _In_ PPH_TREENEW_CONTEXT Context, + _In_opt_ PPH_TREENEW_NODE Node, + _Out_ PPH_TREENEW_NODE **Children, + _Out_ PULONG NumberOfChildren + ); + +BOOLEAN PhTnpIsNodeLeaf( + _In_ PPH_TREENEW_CONTEXT Context, + _In_ PPH_TREENEW_NODE Node + ); + +BOOLEAN PhTnpGetCellText( + _In_ PPH_TREENEW_CONTEXT Context, + _In_ PPH_TREENEW_NODE Node, + _In_ ULONG Id, + _Out_ PPH_STRINGREF Text + ); + +VOID PhTnpRestructureNodes( + _In_ PPH_TREENEW_CONTEXT Context + ); + +VOID PhTnpInsertNodeChildren( + _In_ PPH_TREENEW_CONTEXT Context, + _In_ PPH_TREENEW_NODE Node, + _In_ ULONG Level + ); + +VOID PhTnpSetExpandedNode( + _In_ PPH_TREENEW_CONTEXT Context, + _In_ PPH_TREENEW_NODE Node, + _In_ BOOLEAN Expanded + ); + +BOOLEAN PhTnpGetCellParts( + _In_ PPH_TREENEW_CONTEXT Context, + _In_ ULONG Index, + _In_opt_ PPH_TREENEW_COLUMN Column, + _In_ ULONG Flags, + _Out_ PPH_TREENEW_CELL_PARTS Parts + ); + +BOOLEAN PhTnpGetRowRects( + _In_ PPH_TREENEW_CONTEXT Context, + _In_ ULONG Start, + _In_ ULONG End, + _In_ BOOLEAN Clip, + _Out_ PRECT Rect + ); + +VOID PhTnpHitTest( + _In_ PPH_TREENEW_CONTEXT Context, + _Inout_ PPH_TREENEW_HIT_TEST HitTest + ); + +VOID PhTnpSelectRange( + _In_ PPH_TREENEW_CONTEXT Context, + _In_ ULONG Start, + _In_ ULONG End, + _In_ ULONG Flags, + _Out_opt_ PULONG ChangedStart, + _Out_opt_ PULONG ChangedEnd + ); + +VOID PhTnpSetHotNode( + _In_ PPH_TREENEW_CONTEXT Context, + _In_opt_ PPH_TREENEW_NODE NewHotNode, + _In_ BOOLEAN NewPlusMinusHot + ); + +VOID PhTnpProcessSelectNode( + _In_ PPH_TREENEW_CONTEXT Context, + _In_ PPH_TREENEW_NODE Node, + _In_ LOGICAL ControlKey, + _In_ LOGICAL ShiftKey, + _In_ LOGICAL RightButton + ); + +BOOLEAN PhTnpEnsureVisibleNode( + _In_ PPH_TREENEW_CONTEXT Context, + _In_ ULONG Index + ); + +// Mouse + +VOID PhTnpProcessMoveMouse( + _In_ PPH_TREENEW_CONTEXT Context, + _In_ LONG CursorX, + _In_ LONG CursorY + ); + +VOID PhTnpProcessMouseVWheel( + _In_ PPH_TREENEW_CONTEXT Context, + _In_ LONG Distance + ); + +VOID PhTnpProcessMouseHWheel( + _In_ PPH_TREENEW_CONTEXT Context, + _In_ LONG Distance + ); + +// Keyboard + +BOOLEAN PhTnpProcessFocusKey( + _In_ PPH_TREENEW_CONTEXT Context, + _In_ ULONG VirtualKey + ); + +BOOLEAN PhTnpProcessNodeKey( + _In_ PPH_TREENEW_CONTEXT Context, + _In_ ULONG VirtualKey + ); + +VOID PhTnpProcessSearchKey( + _In_ PPH_TREENEW_CONTEXT Context, + _In_ ULONG Character + ); + +BOOLEAN PhTnpDefaultIncrementalSearch( + _In_ PPH_TREENEW_CONTEXT Context, + _Inout_ PPH_TREENEW_SEARCH_EVENT SearchEvent, + _In_ BOOLEAN Partial, + _In_ BOOLEAN Wrap + ); + +// Scrolling + +VOID PhTnpUpdateScrollBars( + _In_ PPH_TREENEW_CONTEXT Context + ); + +VOID PhTnpScroll( + _In_ PPH_TREENEW_CONTEXT Context, + _In_ LONG DeltaRows, + _In_ LONG DeltaX + ); + +VOID PhTnpProcessScroll( + _In_ PPH_TREENEW_CONTEXT Context, + _In_ LONG DeltaRows, + _In_ LONG DeltaX + ); + +BOOLEAN PhTnpCanScroll( + _In_ PPH_TREENEW_CONTEXT Context, + _In_ BOOLEAN Horizontal, + _In_ BOOLEAN Positive + ); + +// Drawing + +VOID PhTnpPaint( + _In_ HWND hwnd, + _In_ PPH_TREENEW_CONTEXT Context, + _In_ HDC hdc, + _In_ PRECT PaintRect + ); + +VOID PhTnpPrepareRowForDraw( + _In_ PPH_TREENEW_CONTEXT Context, + _In_ HDC hdc, + _Inout_ PPH_TREENEW_NODE Node + ); + +VOID PhTnpDrawCell( + _In_ PPH_TREENEW_CONTEXT Context, + _In_ HDC hdc, + _In_ PRECT CellRect, + _In_ PPH_TREENEW_NODE Node, + _In_ PPH_TREENEW_COLUMN Column, + _In_ LONG RowIndex, + _In_ LONG ColumnIndex + ); + +VOID PhTnpDrawDivider( + _In_ PPH_TREENEW_CONTEXT Context, + _In_ HDC hdc + ); + +VOID PhTnpDrawPlusMinusGlyph( + _In_ HDC hdc, + _In_ PRECT Rect, + _In_ BOOLEAN Plus + ); + +VOID PhTnpDrawSelectionRectangle( + _In_ PPH_TREENEW_CONTEXT Context, + _In_ HDC hdc, + _In_ PRECT Rect + ); + +VOID PhTnpDrawThemedBorder( + _In_ PPH_TREENEW_CONTEXT Context, + _In_ HDC hdc + ); + +// Tooltips + +VOID PhTnpInitializeTooltips( + _In_ PPH_TREENEW_CONTEXT Context + ); + +VOID PhTnpGetTooltipText( + _In_ PPH_TREENEW_CONTEXT Context, + _In_ PPOINT Point, + _Out_ PWSTR *Text + ); + +BOOLEAN PhTnpPrepareTooltipShow( + _In_ PPH_TREENEW_CONTEXT Context + ); + +VOID PhTnpPrepareTooltipPop( + _In_ PPH_TREENEW_CONTEXT Context + ); + +VOID PhTnpPopTooltip( + _In_ PPH_TREENEW_CONTEXT Context + ); + +PPH_TREENEW_COLUMN PhTnpHitTestHeader( + _In_ PPH_TREENEW_CONTEXT Context, + _In_ BOOLEAN Fixed, + _In_ PPOINT Point, + _Out_opt_ PRECT ItemRect + ); + +VOID PhTnpGetHeaderTooltipText( + _In_ PPH_TREENEW_CONTEXT Context, + _In_ BOOLEAN Fixed, + _In_ PPOINT Point, + _Out_ PWSTR *Text + ); + + +LRESULT CALLBACK PhTnpHeaderHookWndProc( + _In_ HWND hwnd, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam, + _In_ UINT_PTR uIdSubclass, + _In_ ULONG_PTR dwRefData + ); + +// Drag selection + +BOOLEAN PhTnpDetectDrag( + _In_ PPH_TREENEW_CONTEXT Context, + _In_ LONG CursorX, + _In_ LONG CursorY, + _In_ BOOLEAN DispatchMessages, + _Out_opt_ PULONG CancelledByMessage + ); + +VOID PhTnpDragSelect( + _In_ PPH_TREENEW_CONTEXT Context, + _In_ LONG CursorX, + _In_ LONG CursorY + ); + +VOID PhTnpProcessDragSelect( + _In_ PPH_TREENEW_CONTEXT Context, + _In_ ULONG VirtualKeys, + _In_ PRECT OldRect, + _In_ PRECT NewRect, + _In_ PRECT TotalRect + ); + +// Double buffering + +VOID PhTnpCreateBufferedContext( + _In_ PPH_TREENEW_CONTEXT Context + ); + +VOID PhTnpDestroyBufferedContext( + _In_ PPH_TREENEW_CONTEXT Context + ); + +// Support functions + +VOID PhTnpGetMessagePos( + _In_ HWND hwnd, + _Out_ PPOINT ClientPoint + ); + +// Macros + +#define HRGN_FULL ((HRGN)1) // passed by WM_NCPAINT even though it's completely undocumented + +#define TNP_CELL_LEFT_MARGIN 6 +#define TNP_CELL_RIGHT_MARGIN 6 +#define TNP_ICON_RIGHT_PADDING 4 + +#define TNP_TIMER_NULL 1 +#define TNP_TIMER_ANIMATE_DIVIDER 2 + +#define TNP_TOOLTIPS_ITEM 0 +#define TNP_TOOLTIPS_FIXED_HEADER 1 +#define TNP_TOOLTIPS_HEADER 2 +#define TNP_TOOLTIPS_DEFAULT_MAXIMUM_WIDTH 550 + +#define TNP_ANIMATE_DIVIDER_INTERVAL 10 +#define TNP_ANIMATE_DIVIDER_INCREMENT 17 +#define TNP_ANIMATE_DIVIDER_DECREMENT 2 + +#define TNP_HIT_TEST_FIXED_DIVIDER(X, Context) \ + ((Context)->FixedDividerVisible && (X) >= (Context)->FixedWidth - 8 && (X) < (Context)->FixedWidth + 8) +#define TNP_HIT_TEST_PLUS_MINUS_GLYPH(X, NodeLevel) \ + (((X) >= TNP_CELL_LEFT_MARGIN + ((LONG)(NodeLevel) * SmallIconWidth)) && ((X) < TNP_CELL_LEFT_MARGIN + ((LONG)(NodeLevel) * SmallIconWidth) + SmallIconWidth)) + +#endif diff --git a/phlib/include/verify.h b/phlib/include/verify.h index 741feb9f7b89..f18a20450b53 100644 --- a/phlib/include/verify.h +++ b/phlib/include/verify.h @@ -1,77 +1,77 @@ -#ifndef _PH_VERIFY_H -#define _PH_VERIFY_H - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#define PH_VERIFY_DEFAULT_SIZE_LIMIT (32 * 1024 * 1024) - -typedef enum _VERIFY_RESULT -{ - VrUnknown = 0, - VrNoSignature, - VrTrusted, - VrExpired, - VrRevoked, - VrDistrust, - VrSecuritySettings, - VrBadSignature -} VERIFY_RESULT, *PVERIFY_RESULT; - -#define PH_VERIFY_PREVENT_NETWORK_ACCESS 0x1 -#define PH_VERIFY_VIEW_PROPERTIES 0x2 - -typedef struct _PH_VERIFY_FILE_INFO -{ - PWSTR FileName; - ULONG Flags; // PH_VERIFY_* - - ULONG FileSizeLimitForHash; // 0 for PH_VERIFY_DEFAULT_SIZE_LIMIT, -1 for unlimited - ULONG NumberOfCatalogFileNames; - PWSTR *CatalogFileNames; - - HWND hWnd; // for PH_VERIFY_VIEW_PROPERTIES -} PH_VERIFY_FILE_INFO, *PPH_VERIFY_FILE_INFO; - -PHLIBAPI -VERIFY_RESULT -NTAPI -PhVerifyFile( - _In_ PWSTR FileName, - _Out_opt_ PPH_STRING *SignerName - ); - -PHLIBAPI -NTSTATUS -NTAPI -PhVerifyFileEx( - _In_ PPH_VERIFY_FILE_INFO Information, - _Out_ VERIFY_RESULT *VerifyResult, - _Out_opt_ PCERT_CONTEXT **Signatures, - _Out_opt_ PULONG NumberOfSignatures - ); - -PHLIBAPI -VOID -NTAPI -PhFreeVerifySignatures( - _In_ PCERT_CONTEXT *Signatures, - _In_ ULONG NumberOfSignatures - ); - -PHLIBAPI -PPH_STRING -NTAPI -PhGetSignerNameFromCertificate( - _In_ PCERT_CONTEXT Certificate - ); - -#ifdef __cplusplus -} -#endif - -#endif +#ifndef _PH_VERIFY_H +#define _PH_VERIFY_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define PH_VERIFY_DEFAULT_SIZE_LIMIT (32 * 1024 * 1024) + +typedef enum _VERIFY_RESULT +{ + VrUnknown = 0, + VrNoSignature, + VrTrusted, + VrExpired, + VrRevoked, + VrDistrust, + VrSecuritySettings, + VrBadSignature +} VERIFY_RESULT, *PVERIFY_RESULT; + +#define PH_VERIFY_PREVENT_NETWORK_ACCESS 0x1 +#define PH_VERIFY_VIEW_PROPERTIES 0x2 + +typedef struct _PH_VERIFY_FILE_INFO +{ + PWSTR FileName; + ULONG Flags; // PH_VERIFY_* + + ULONG FileSizeLimitForHash; // 0 for PH_VERIFY_DEFAULT_SIZE_LIMIT, -1 for unlimited + ULONG NumberOfCatalogFileNames; + PWSTR *CatalogFileNames; + + HWND hWnd; // for PH_VERIFY_VIEW_PROPERTIES +} PH_VERIFY_FILE_INFO, *PPH_VERIFY_FILE_INFO; + +PHLIBAPI +VERIFY_RESULT +NTAPI +PhVerifyFile( + _In_ PWSTR FileName, + _Out_opt_ PPH_STRING *SignerName + ); + +PHLIBAPI +NTSTATUS +NTAPI +PhVerifyFileEx( + _In_ PPH_VERIFY_FILE_INFO Information, + _Out_ VERIFY_RESULT *VerifyResult, + _Out_opt_ PCERT_CONTEXT **Signatures, + _Out_opt_ PULONG NumberOfSignatures + ); + +PHLIBAPI +VOID +NTAPI +PhFreeVerifySignatures( + _In_ PCERT_CONTEXT *Signatures, + _In_ ULONG NumberOfSignatures + ); + +PHLIBAPI +PPH_STRING +NTAPI +PhGetSignerNameFromCertificate( + _In_ PCERT_CONTEXT Certificate + ); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/phlib/include/verifyp.h b/phlib/include/verifyp.h index 7a709f74203e..8a9dbdca2d40 100644 --- a/phlib/include/verifyp.h +++ b/phlib/include/verifyp.h @@ -1,118 +1,118 @@ -#ifndef _PH_VERIFYP_H -#define _PH_VERIFYP_H - -#include - -typedef struct _CATALOG_INFO -{ - DWORD cbStruct; - WCHAR wszCatalogFile[MAX_PATH]; -} CATALOG_INFO, *PCATALOG_INFO; - -typedef struct tagCRYPTUI_VIEWSIGNERINFO_STRUCT { - DWORD dwSize; - HWND hwndParent; - DWORD dwFlags; - LPCTSTR szTitle; - CMSG_SIGNER_INFO *pSignerInfo; - HCRYPTMSG hMsg; - LPCSTR pszOID; - DWORD_PTR dwReserved; - DWORD cStores; - HCERTSTORE *rghStores; - DWORD cPropSheetPages; - LPCPROPSHEETPAGE rgPropSheetPages; -} CRYPTUI_VIEWSIGNERINFO_STRUCT, *PCRYPTUI_VIEWSIGNERINFO_STRUCT; - -typedef BOOL (WINAPI *_CryptCATAdminCalcHashFromFileHandle)( - HANDLE hFile, - DWORD *pcbHash, - BYTE *pbHash, - DWORD dwFlags - ); - -typedef BOOL (WINAPI *_CryptCATAdminCalcHashFromFileHandle2)( - HCATADMIN hCatAdmin, - HANDLE hFile, - DWORD *pcbHash, - BYTE *pbHash, - DWORD dwFlags - ); - -typedef BOOL (WINAPI *_CryptCATAdminAcquireContext)( - HANDLE *phCatAdmin, - GUID *pgSubsystem, - DWORD dwFlags - ); - -typedef BOOL (WINAPI *_CryptCATAdminAcquireContext2)( - HCATADMIN *phCatAdmin, - const GUID *pgSubsystem, - PCWSTR pwszHashAlgorithm, - PCCERT_STRONG_SIGN_PARA pStrongHashPolicy, - DWORD dwFlags - ); - -typedef HANDLE (WINAPI *_CryptCATAdminEnumCatalogFromHash)( - HANDLE hCatAdmin, - BYTE *pbHash, - DWORD cbHash, - DWORD dwFlags, - HANDLE *phPrevCatInfo - ); - -typedef BOOL (WINAPI *_CryptCATCatalogInfoFromContext)( - HANDLE hCatInfo, - CATALOG_INFO *psCatInfo, - DWORD dwFlags - ); - -typedef BOOL (WINAPI *_CryptCATAdminReleaseCatalogContext)( - HANDLE hCatAdmin, - HANDLE hCatInfo, - DWORD dwFlags - ); - -typedef BOOL (WINAPI *_CryptCATAdminReleaseContext)( - HANDLE hCatAdmin, - DWORD dwFlags - ); - -typedef PCRYPT_PROVIDER_DATA (WINAPI *_WTHelperProvDataFromStateData)( - HANDLE hStateData - ); - -typedef PCRYPT_PROVIDER_SGNR (WINAPI *_WTHelperGetProvSignerFromChain)( - CRYPT_PROVIDER_DATA *pProvData, - DWORD idxSigner, - BOOL fCounterSigner, - DWORD idxCounterSigner - ); - -typedef LONG (WINAPI *_WinVerifyTrust)( - HWND hWnd, - GUID *pgActionID, - LPVOID pWVTData - ); - -typedef DWORD (WINAPI *_CertNameToStr)( - DWORD dwCertEncodingType, - PCERT_NAME_BLOB pName, - DWORD dwStrType, - LPTSTR psz, - DWORD csz - ); - -typedef PCCERT_CONTEXT (WINAPI *_CertDuplicateCertificateContext)( - _In_ PCCERT_CONTEXT pCertContext - ); - -typedef BOOL (WINAPI *_CertFreeCertificateContext)( - _In_ PCCERT_CONTEXT pCertContext - ); - -typedef BOOL (WINAPI *_CryptUIDlgViewSignerInfo)( - _In_ CRYPTUI_VIEWSIGNERINFO_STRUCT *pcvsi - ); - -#endif +#ifndef _PH_VERIFYP_H +#define _PH_VERIFYP_H + +#include + +typedef struct _CATALOG_INFO +{ + DWORD cbStruct; + WCHAR wszCatalogFile[MAX_PATH]; +} CATALOG_INFO, *PCATALOG_INFO; + +typedef struct tagCRYPTUI_VIEWSIGNERINFO_STRUCT { + DWORD dwSize; + HWND hwndParent; + DWORD dwFlags; + LPCTSTR szTitle; + CMSG_SIGNER_INFO *pSignerInfo; + HCRYPTMSG hMsg; + LPCSTR pszOID; + DWORD_PTR dwReserved; + DWORD cStores; + HCERTSTORE *rghStores; + DWORD cPropSheetPages; + LPCPROPSHEETPAGE rgPropSheetPages; +} CRYPTUI_VIEWSIGNERINFO_STRUCT, *PCRYPTUI_VIEWSIGNERINFO_STRUCT; + +typedef BOOL (WINAPI *_CryptCATAdminCalcHashFromFileHandle)( + HANDLE hFile, + DWORD *pcbHash, + BYTE *pbHash, + DWORD dwFlags + ); + +typedef BOOL (WINAPI *_CryptCATAdminCalcHashFromFileHandle2)( + HCATADMIN hCatAdmin, + HANDLE hFile, + DWORD *pcbHash, + BYTE *pbHash, + DWORD dwFlags + ); + +typedef BOOL (WINAPI *_CryptCATAdminAcquireContext)( + HANDLE *phCatAdmin, + GUID *pgSubsystem, + DWORD dwFlags + ); + +typedef BOOL (WINAPI *_CryptCATAdminAcquireContext2)( + HCATADMIN *phCatAdmin, + const GUID *pgSubsystem, + PCWSTR pwszHashAlgorithm, + PCCERT_STRONG_SIGN_PARA pStrongHashPolicy, + DWORD dwFlags + ); + +typedef HANDLE (WINAPI *_CryptCATAdminEnumCatalogFromHash)( + HANDLE hCatAdmin, + BYTE *pbHash, + DWORD cbHash, + DWORD dwFlags, + HANDLE *phPrevCatInfo + ); + +typedef BOOL (WINAPI *_CryptCATCatalogInfoFromContext)( + HANDLE hCatInfo, + CATALOG_INFO *psCatInfo, + DWORD dwFlags + ); + +typedef BOOL (WINAPI *_CryptCATAdminReleaseCatalogContext)( + HANDLE hCatAdmin, + HANDLE hCatInfo, + DWORD dwFlags + ); + +typedef BOOL (WINAPI *_CryptCATAdminReleaseContext)( + HANDLE hCatAdmin, + DWORD dwFlags + ); + +typedef PCRYPT_PROVIDER_DATA (WINAPI *_WTHelperProvDataFromStateData)( + HANDLE hStateData + ); + +typedef PCRYPT_PROVIDER_SGNR (WINAPI *_WTHelperGetProvSignerFromChain)( + CRYPT_PROVIDER_DATA *pProvData, + DWORD idxSigner, + BOOL fCounterSigner, + DWORD idxCounterSigner + ); + +typedef LONG (WINAPI *_WinVerifyTrust)( + HWND hWnd, + GUID *pgActionID, + LPVOID pWVTData + ); + +typedef DWORD (WINAPI *_CertNameToStr)( + DWORD dwCertEncodingType, + PCERT_NAME_BLOB pName, + DWORD dwStrType, + LPTSTR psz, + DWORD csz + ); + +typedef PCCERT_CONTEXT (WINAPI *_CertDuplicateCertificateContext)( + _In_ PCCERT_CONTEXT pCertContext + ); + +typedef BOOL (WINAPI *_CertFreeCertificateContext)( + _In_ PCCERT_CONTEXT pCertContext + ); + +typedef BOOL (WINAPI *_CryptUIDlgViewSignerInfo)( + _In_ CRYPTUI_VIEWSIGNERINFO_STRUCT *pcvsi + ); + +#endif diff --git a/phlib/kph.c b/phlib/kph.c index 3e427585210f..0acd7d0baa27 100644 --- a/phlib/kph.c +++ b/phlib/kph.c @@ -1,1102 +1,1102 @@ -/* - * Process Hacker - - * KProcessHacker API - * - * Copyright (C) 2009-2016 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include -#include -#include - -HANDLE PhKphHandle = NULL; -BOOLEAN PhKphVerified; -KPH_KEY PhKphL1Key; - -NTSTATUS KphConnect( - _In_opt_ PWSTR DeviceName - ) -{ - NTSTATUS status; - HANDLE kphHandle; - UNICODE_STRING objectName; - OBJECT_ATTRIBUTES objectAttributes; - IO_STATUS_BLOCK isb; - OBJECT_HANDLE_FLAG_INFORMATION handleFlagInfo; - - if (PhKphHandle) - return STATUS_ADDRESS_ALREADY_EXISTS; - - if (DeviceName) - RtlInitUnicodeString(&objectName, DeviceName); - else - RtlInitUnicodeString(&objectName, KPH_DEVICE_NAME); - - InitializeObjectAttributes( - &objectAttributes, - &objectName, - OBJ_CASE_INSENSITIVE, - NULL, - NULL - ); - - status = NtOpenFile( - &kphHandle, - FILE_GENERIC_READ | FILE_GENERIC_WRITE, - &objectAttributes, - &isb, - FILE_SHARE_READ | FILE_SHARE_WRITE, - FILE_NON_DIRECTORY_FILE - ); - - if (NT_SUCCESS(status)) - { - // Protect the handle from being closed. - - handleFlagInfo.Inherit = FALSE; - handleFlagInfo.ProtectFromClose = TRUE; - - NtSetInformationObject( - kphHandle, - ObjectHandleFlagInformation, - &handleFlagInfo, - sizeof(OBJECT_HANDLE_FLAG_INFORMATION) - ); - - PhKphHandle = kphHandle; - PhKphVerified = FALSE; - PhKphL1Key = 0; - } - - return status; -} - -NTSTATUS KphConnect2( - _In_opt_ PWSTR DeviceName, - _In_ PWSTR FileName - ) -{ - return KphConnect2Ex(DeviceName, FileName, NULL); -} - -NTSTATUS KphConnect2Ex( - _In_opt_ PWSTR DeviceName, - _In_ PWSTR FileName, - _In_opt_ PKPH_PARAMETERS Parameters - ) -{ - NTSTATUS status; - WCHAR fullDeviceName[256]; - PH_FORMAT format[2]; - SC_HANDLE scmHandle; - SC_HANDLE serviceHandle; - BOOLEAN started = FALSE; - BOOLEAN created = FALSE; - - if (!DeviceName) - DeviceName = KPH_DEVICE_SHORT_NAME; - - PhInitFormatS(&format[0], L"\\Device\\"); - PhInitFormatS(&format[1], DeviceName); - - if (!PhFormatToBuffer(format, 2, fullDeviceName, sizeof(fullDeviceName), NULL)) - return STATUS_NAME_TOO_LONG; - - // Try to open the device. - status = KphConnect(fullDeviceName); - - if (NT_SUCCESS(status) || status == STATUS_ADDRESS_ALREADY_EXISTS) - return status; - - if ( - status != STATUS_NO_SUCH_DEVICE && - status != STATUS_NO_SUCH_FILE && - status != STATUS_OBJECT_NAME_NOT_FOUND && - status != STATUS_OBJECT_PATH_NOT_FOUND - ) - return status; - - // Load the driver, and try again. - - // Try to start the service, if it exists. - - scmHandle = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT); - - if (scmHandle) - { - serviceHandle = OpenService(scmHandle, DeviceName, SERVICE_START); - - if (serviceHandle) - { - if (StartService(serviceHandle, 0, NULL)) - started = TRUE; - - CloseServiceHandle(serviceHandle); - } - - CloseServiceHandle(scmHandle); - } - - if (!started && RtlDoesFileExists_U(FileName)) - { - // Try to create the service. - - scmHandle = OpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE); - - if (scmHandle) - { - serviceHandle = CreateService( - scmHandle, - DeviceName, - DeviceName, - SERVICE_ALL_ACCESS, - SERVICE_KERNEL_DRIVER, - SERVICE_DEMAND_START, - SERVICE_ERROR_IGNORE, - FileName, - NULL, - NULL, - NULL, - NULL, - L"" - ); - - if (serviceHandle) - { - created = TRUE; - - // Set parameters if the caller supplied them. Note that we fail the entire function - // if this fails, because failing to set parameters like SecurityLevel may result in - // security vulnerabilities. - if (Parameters) - { - status = KphSetParameters(DeviceName, Parameters); - - if (!NT_SUCCESS(status)) - { - // Delete the service and fail. - goto CreateAndConnectEnd; - } - } - - if (StartService(serviceHandle, 0, NULL)) - started = TRUE; - } - - CloseServiceHandle(scmHandle); - } - } - - if (started) - { - // Try to open the device again. - status = KphConnect(fullDeviceName); - } - -CreateAndConnectEnd: - if (created) - { - // "Delete" the service. Since we (may) have a handle to the device, the SCM will delete the - // service automatically when it is stopped (upon reboot). If we don't have a handle to the - // device, the service will get deleted immediately, which is a good thing anyway. - DeleteService(serviceHandle); - CloseServiceHandle(serviceHandle); - } - - return status; -} - -NTSTATUS KphDisconnect( - VOID - ) -{ - NTSTATUS status; - OBJECT_HANDLE_FLAG_INFORMATION handleFlagInfo; - - if (!PhKphHandle) - return STATUS_ALREADY_DISCONNECTED; - - // Unprotect the handle. - - handleFlagInfo.Inherit = FALSE; - handleFlagInfo.ProtectFromClose = FALSE; - - NtSetInformationObject( - PhKphHandle, - ObjectHandleFlagInformation, - &handleFlagInfo, - sizeof(OBJECT_HANDLE_FLAG_INFORMATION) - ); - - status = NtClose(PhKphHandle); - PhKphHandle = NULL; - PhKphVerified = FALSE; - PhKphL1Key = 0; - - return status; -} - -BOOLEAN KphIsConnected( - VOID - ) -{ - return PhKphHandle != NULL; -} - -BOOLEAN KphIsVerified( - VOID - ) -{ - return PhKphVerified; -} - -NTSTATUS KphSetParameters( - _In_opt_ PWSTR DeviceName, - _In_ PKPH_PARAMETERS Parameters - ) -{ - NTSTATUS status; - HANDLE parametersKeyHandle = NULL; - PPH_STRING parametersKeyName; - ULONG disposition; - UNICODE_STRING valueName; - - if (!DeviceName) - DeviceName = KPH_DEVICE_SHORT_NAME; - - parametersKeyName = PhConcatStrings( - 3, - L"System\\CurrentControlSet\\Services\\", - DeviceName, - L"\\Parameters" - ); - status = PhCreateKey( - ¶metersKeyHandle, - KEY_WRITE | DELETE, - PH_KEY_LOCAL_MACHINE, - ¶metersKeyName->sr, - 0, - 0, - &disposition - ); - PhDereferenceObject(parametersKeyName); - - if (!NT_SUCCESS(status)) - return status; - - RtlInitUnicodeString(&valueName, L"SecurityLevel"); - status = NtSetValueKey(parametersKeyHandle, &valueName, 0, REG_DWORD, &Parameters->SecurityLevel, sizeof(ULONG)); - - if (!NT_SUCCESS(status)) - goto SetValuesEnd; - - if (Parameters->CreateDynamicConfiguration) - { - KPH_DYN_CONFIGURATION configuration; - - RtlInitUnicodeString(&valueName, L"DynamicConfiguration"); - - configuration.Version = KPH_DYN_CONFIGURATION_VERSION; - configuration.NumberOfPackages = 1; - - if (NT_SUCCESS(KphInitializeDynamicPackage(&configuration.Packages[0]))) - { - status = NtSetValueKey(parametersKeyHandle, &valueName, 0, REG_BINARY, &configuration, sizeof(KPH_DYN_CONFIGURATION)); - - if (!NT_SUCCESS(status)) - goto SetValuesEnd; - } - } - - // Put more parameters here... - -SetValuesEnd: - if (!NT_SUCCESS(status)) - { - // Delete the key if we created it. - if (disposition == REG_CREATED_NEW_KEY) - NtDeleteKey(parametersKeyHandle); - } - - NtClose(parametersKeyHandle); - - return status; -} - -NTSTATUS KphInstall( - _In_opt_ PWSTR DeviceName, - _In_ PWSTR FileName - ) -{ - return KphInstallEx(DeviceName, FileName, NULL); -} - -NTSTATUS KphInstallEx( - _In_opt_ PWSTR DeviceName, - _In_ PWSTR FileName, - _In_opt_ PKPH_PARAMETERS Parameters - ) -{ - NTSTATUS status = STATUS_SUCCESS; - SC_HANDLE scmHandle; - SC_HANDLE serviceHandle; - - if (!DeviceName) - DeviceName = KPH_DEVICE_SHORT_NAME; - - scmHandle = OpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE); - - if (!scmHandle) - return PhGetLastWin32ErrorAsNtStatus(); - - serviceHandle = CreateService( - scmHandle, - DeviceName, - DeviceName, - SERVICE_ALL_ACCESS, - SERVICE_KERNEL_DRIVER, - SERVICE_SYSTEM_START, - SERVICE_ERROR_IGNORE, - FileName, - NULL, - NULL, - NULL, - NULL, - L"" - ); - - if (serviceHandle) - { - // See KphConnect2Ex for more details. - if (Parameters) - { - status = KphSetParameters(DeviceName, Parameters); - - if (!NT_SUCCESS(status)) - { - DeleteService(serviceHandle); - goto CreateEnd; - } - } - - if (!StartService(serviceHandle, 0, NULL)) - status = PhGetLastWin32ErrorAsNtStatus(); - -CreateEnd: - CloseServiceHandle(serviceHandle); - } - else - { - status = PhGetLastWin32ErrorAsNtStatus(); - } - - CloseServiceHandle(scmHandle); - - return status; -} - -NTSTATUS KphUninstall( - _In_opt_ PWSTR DeviceName - ) -{ - NTSTATUS status = STATUS_SUCCESS; - SC_HANDLE scmHandle; - SC_HANDLE serviceHandle; - - if (!DeviceName) - DeviceName = KPH_DEVICE_SHORT_NAME; - - scmHandle = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT); - - if (!scmHandle) - return PhGetLastWin32ErrorAsNtStatus(); - - serviceHandle = OpenService(scmHandle, DeviceName, SERVICE_STOP | DELETE); - - if (serviceHandle) - { - SERVICE_STATUS serviceStatus; - - ControlService(serviceHandle, SERVICE_CONTROL_STOP, &serviceStatus); - - if (!DeleteService(serviceHandle)) - status = PhGetLastWin32ErrorAsNtStatus(); - - CloseServiceHandle(serviceHandle); - } - else - { - status = PhGetLastWin32ErrorAsNtStatus(); - } - - CloseServiceHandle(scmHandle); - - return status; -} - -NTSTATUS KphGetFeatures( - _Out_ PULONG Features - ) -{ - struct - { - PULONG Features; - } input = { Features }; - - return KphpDeviceIoControl( - KPH_GETFEATURES, - &input, - sizeof(input) - ); -} - -NTSTATUS KphVerifyClient( - _In_reads_bytes_(SignatureSize) PUCHAR Signature, - _In_ ULONG SignatureSize - ) -{ - NTSTATUS status; - struct - { - PVOID CodeAddress; - PUCHAR Signature; - ULONG SignatureSize; - } input = { KphpWithKeyApcRoutine, Signature, SignatureSize }; - - status = KphpDeviceIoControl( - KPH_VERIFYCLIENT, - &input, - sizeof(input) - ); - - if (NT_SUCCESS(status)) - PhKphVerified = TRUE; - - return status; -} - -NTSTATUS KphOpenProcess( - _Out_ PHANDLE ProcessHandle, - _In_ ACCESS_MASK DesiredAccess, - _In_ PCLIENT_ID ClientId - ) -{ - KPH_OPEN_PROCESS_INPUT input = { ProcessHandle, DesiredAccess, ClientId, 0 }; - - if ((DesiredAccess & KPH_PROCESS_READ_ACCESS) == DesiredAccess) - { - KphpGetL1Key(&input.Key); - return KphpDeviceIoControl( - KPH_OPENPROCESS, - &input, - sizeof(input) - ); - } - else - { - return KphpWithKey(KphKeyLevel2, KphpOpenProcessContinuation, &input); - } -} - -NTSTATUS KphOpenProcessToken( - _In_ HANDLE ProcessHandle, - _In_ ACCESS_MASK DesiredAccess, - _Out_ PHANDLE TokenHandle - ) -{ - KPH_OPEN_PROCESS_TOKEN_INPUT input = { ProcessHandle, DesiredAccess, TokenHandle, 0 }; - - if ((DesiredAccess & KPH_TOKEN_READ_ACCESS) == DesiredAccess) - { - KphpGetL1Key(&input.Key); - return KphpDeviceIoControl( - KPH_OPENPROCESSTOKEN, - &input, - sizeof(input) - ); - } - else - { - return KphpWithKey(KphKeyLevel2, KphpOpenProcessTokenContinuation, &input); - } -} - -NTSTATUS KphOpenProcessJob( - _In_ HANDLE ProcessHandle, - _In_ ACCESS_MASK DesiredAccess, - _Out_ PHANDLE JobHandle - ) -{ - struct - { - HANDLE ProcessHandle; - ACCESS_MASK DesiredAccess; - PHANDLE JobHandle; - } input = { ProcessHandle, DesiredAccess, JobHandle }; - - return KphpDeviceIoControl( - KPH_OPENPROCESSJOB, - &input, - sizeof(input) - ); -} - -NTSTATUS KphTerminateProcess( - _In_ HANDLE ProcessHandle, - _In_ NTSTATUS ExitStatus - ) -{ - NTSTATUS status; - KPH_TERMINATE_PROCESS_INPUT input = { ProcessHandle, ExitStatus, 0 }; - - status = KphpWithKey(KphKeyLevel2, KphpTerminateProcessContinuation, &input); - - // Check if we're trying to terminate the current process, because kernel-mode can't do it. - if (status == STATUS_CANT_TERMINATE_SELF) - { - RtlExitUserProcess(ExitStatus); - } - - return status; -} - -NTSTATUS KphReadVirtualMemoryUnsafe( - _In_opt_ HANDLE ProcessHandle, - _In_ PVOID BaseAddress, - _Out_writes_bytes_(BufferSize) PVOID Buffer, - _In_ SIZE_T BufferSize, - _Out_opt_ PSIZE_T NumberOfBytesRead - ) -{ - KPH_READ_VIRTUAL_MEMORY_UNSAFE_INPUT input = { ProcessHandle, BaseAddress, Buffer, BufferSize, NumberOfBytesRead, 0 }; - - return KphpWithKey(KphKeyLevel2, KphpReadVirtualMemoryUnsafeContinuation, &input); -} - -NTSTATUS KphQueryInformationProcess( - _In_ HANDLE ProcessHandle, - _In_ KPH_PROCESS_INFORMATION_CLASS ProcessInformationClass, - _Out_writes_bytes_(ProcessInformationLength) PVOID ProcessInformation, - _In_ ULONG ProcessInformationLength, - _Out_opt_ PULONG ReturnLength - ) -{ - struct - { - HANDLE ProcessHandle; - KPH_PROCESS_INFORMATION_CLASS ProcessInformationClass; - PVOID ProcessInformation; - ULONG ProcessInformationLength; - PULONG ReturnLength; - } input = { ProcessHandle, ProcessInformationClass, ProcessInformation, ProcessInformationLength, ReturnLength }; - - return KphpDeviceIoControl( - KPH_QUERYINFORMATIONPROCESS, - &input, - sizeof(input) - ); -} - -NTSTATUS KphSetInformationProcess( - _In_ HANDLE ProcessHandle, - _In_ KPH_PROCESS_INFORMATION_CLASS ProcessInformationClass, - _In_reads_bytes_(ProcessInformationLength) PVOID ProcessInformation, - _In_ ULONG ProcessInformationLength - ) -{ - struct - { - HANDLE ProcessHandle; - KPH_PROCESS_INFORMATION_CLASS ProcessInformationClass; - PVOID ProcessInformation; - ULONG ProcessInformationLength; - } input = { ProcessHandle, ProcessInformationClass, ProcessInformation, ProcessInformationLength }; - - return KphpDeviceIoControl( - KPH_SETINFORMATIONPROCESS, - &input, - sizeof(input) - ); -} - -NTSTATUS KphOpenThread( - _Out_ PHANDLE ThreadHandle, - _In_ ACCESS_MASK DesiredAccess, - _In_ PCLIENT_ID ClientId - ) -{ - KPH_OPEN_THREAD_INPUT input = { ThreadHandle, DesiredAccess, ClientId, 0 }; - - if ((DesiredAccess & KPH_THREAD_READ_ACCESS) == DesiredAccess) - { - KphpGetL1Key(&input.Key); - return KphpDeviceIoControl( - KPH_OPENTHREAD, - &input, - sizeof(input) - ); - } - else - { - return KphpWithKey(KphKeyLevel2, KphpOpenThreadContinuation, &input); - } -} - -NTSTATUS KphOpenThreadProcess( - _In_ HANDLE ThreadHandle, - _In_ ACCESS_MASK DesiredAccess, - _Out_ PHANDLE ProcessHandle - ) -{ - struct - { - HANDLE ThreadHandle; - ACCESS_MASK DesiredAccess; - PHANDLE ProcessHandle; - } input = { ThreadHandle, DesiredAccess, ProcessHandle }; - - return KphpDeviceIoControl( - KPH_OPENTHREADPROCESS, - &input, - sizeof(input) - ); -} - -NTSTATUS KphCaptureStackBackTraceThread( - _In_ HANDLE ThreadHandle, - _In_ ULONG FramesToSkip, - _In_ ULONG FramesToCapture, - _Out_writes_(FramesToCapture) PVOID *BackTrace, - _Out_opt_ PULONG CapturedFrames, - _Out_opt_ PULONG BackTraceHash - ) -{ - struct - { - HANDLE ThreadHandle; - ULONG FramesToSkip; - ULONG FramesToCapture; - PVOID *BackTrace; - PULONG CapturedFrames; - PULONG BackTraceHash; - } input = { ThreadHandle, FramesToSkip, FramesToCapture, BackTrace, CapturedFrames, BackTraceHash }; - - return KphpDeviceIoControl( - KPH_CAPTURESTACKBACKTRACETHREAD, - &input, - sizeof(input) - ); -} - -NTSTATUS KphQueryInformationThread( - _In_ HANDLE ThreadHandle, - _In_ KPH_THREAD_INFORMATION_CLASS ThreadInformationClass, - _Out_writes_bytes_(ThreadInformationLength) PVOID ThreadInformation, - _In_ ULONG ThreadInformationLength, - _Out_opt_ PULONG ReturnLength - ) -{ - struct - { - HANDLE ThreadHandle; - KPH_THREAD_INFORMATION_CLASS ThreadInformationClass; - PVOID ThreadInformation; - ULONG ThreadInformationLength; - PULONG ReturnLength; - } input = { ThreadHandle, ThreadInformationClass, ThreadInformation, ThreadInformationLength, ReturnLength }; - - return KphpDeviceIoControl( - KPH_QUERYINFORMATIONTHREAD, - &input, - sizeof(input) - ); -} - -NTSTATUS KphSetInformationThread( - _In_ HANDLE ThreadHandle, - _In_ KPH_THREAD_INFORMATION_CLASS ThreadInformationClass, - _In_reads_bytes_(ThreadInformationLength) PVOID ThreadInformation, - _In_ ULONG ThreadInformationLength - ) -{ - struct - { - HANDLE ThreadHandle; - KPH_THREAD_INFORMATION_CLASS ThreadInformationClass; - PVOID ThreadInformation; - ULONG ThreadInformationLength; - } input = { ThreadHandle, ThreadInformationClass, ThreadInformation, ThreadInformationLength }; - - return KphpDeviceIoControl( - KPH_SETINFORMATIONTHREAD, - &input, - sizeof(input) - ); -} - -NTSTATUS KphEnumerateProcessHandles( - _In_ HANDLE ProcessHandle, - _Out_writes_bytes_(BufferLength) PVOID Buffer, - _In_opt_ ULONG BufferLength, - _Out_opt_ PULONG ReturnLength - ) -{ - struct - { - HANDLE ProcessHandle; - PVOID Buffer; - ULONG BufferLength; - PULONG ReturnLength; - } input = { ProcessHandle, Buffer, BufferLength, ReturnLength }; - - return KphpDeviceIoControl( - KPH_ENUMERATEPROCESSHANDLES, - &input, - sizeof(input) - ); -} - -NTSTATUS KphEnumerateProcessHandles2( - _In_ HANDLE ProcessHandle, - _Out_ PKPH_PROCESS_HANDLE_INFORMATION *Handles - ) -{ - NTSTATUS status; - PVOID buffer; - ULONG bufferSize = 2048; - - buffer = PhAllocate(bufferSize); - - while (TRUE) - { - status = KphEnumerateProcessHandles( - ProcessHandle, - buffer, - bufferSize, - &bufferSize - ); - - if (status == STATUS_BUFFER_TOO_SMALL) - { - PhFree(buffer); - buffer = PhAllocate(bufferSize); - } - else - { - break; - } - } - - if (!NT_SUCCESS(status)) - { - PhFree(buffer); - return status; - } - - *Handles = buffer; - - return status; -} - -NTSTATUS KphQueryInformationObject( - _In_ HANDLE ProcessHandle, - _In_ HANDLE Handle, - _In_ KPH_OBJECT_INFORMATION_CLASS ObjectInformationClass, - _Out_writes_bytes_(ObjectInformationLength) PVOID ObjectInformation, - _In_ ULONG ObjectInformationLength, - _Out_opt_ PULONG ReturnLength - ) -{ - struct - { - HANDLE ProcessHandle; - HANDLE Handle; - KPH_OBJECT_INFORMATION_CLASS ObjectInformationClass; - PVOID ObjectInformation; - ULONG ObjectInformationLength; - PULONG ReturnLength; - } input = { ProcessHandle, Handle, ObjectInformationClass, ObjectInformation, ObjectInformationLength, ReturnLength }; - - return KphpDeviceIoControl( - KPH_QUERYINFORMATIONOBJECT, - &input, - sizeof(input) - ); -} - -NTSTATUS KphSetInformationObject( - _In_ HANDLE ProcessHandle, - _In_ HANDLE Handle, - _In_ KPH_OBJECT_INFORMATION_CLASS ObjectInformationClass, - _In_reads_bytes_(ObjectInformationLength) PVOID ObjectInformation, - _In_ ULONG ObjectInformationLength - ) -{ - struct - { - HANDLE ProcessHandle; - HANDLE Handle; - KPH_OBJECT_INFORMATION_CLASS ObjectInformationClass; - PVOID ObjectInformation; - ULONG ObjectInformationLength; - } input = { ProcessHandle, Handle, ObjectInformationClass, ObjectInformation, ObjectInformationLength }; - - return KphpDeviceIoControl( - KPH_SETINFORMATIONOBJECT, - &input, - sizeof(input) - ); -} - -NTSTATUS KphOpenDriver( - _Out_ PHANDLE DriverHandle, - _In_ ACCESS_MASK DesiredAccess, - _In_ POBJECT_ATTRIBUTES ObjectAttributes - ) -{ - struct - { - PHANDLE DriverHandle; - ACCESS_MASK DesiredAccess; - POBJECT_ATTRIBUTES ObjectAttributes; - } input = { DriverHandle, DesiredAccess, ObjectAttributes }; - - return KphpDeviceIoControl( - KPH_OPENDRIVER, - &input, - sizeof(input) - ); -} - -NTSTATUS KphQueryInformationDriver( - _In_ HANDLE DriverHandle, - _In_ DRIVER_INFORMATION_CLASS DriverInformationClass, - _Out_writes_bytes_(DriverInformationLength) PVOID DriverInformation, - _In_ ULONG DriverInformationLength, - _Out_opt_ PULONG ReturnLength - ) -{ - struct - { - HANDLE DriverHandle; - DRIVER_INFORMATION_CLASS DriverInformationClass; - PVOID DriverInformation; - ULONG DriverInformationLength; - PULONG ReturnLength; - } input = { DriverHandle, DriverInformationClass, DriverInformation, DriverInformationLength, ReturnLength }; - - return KphpDeviceIoControl( - KPH_QUERYINFORMATIONDRIVER, - &input, - sizeof(input) - ); -} - -NTSTATUS KphpDeviceIoControl( - _In_ ULONG KphControlCode, - _In_ PVOID InBuffer, - _In_ ULONG InBufferLength - ) -{ - IO_STATUS_BLOCK iosb; - - return NtDeviceIoControlFile( - PhKphHandle, - NULL, - NULL, - NULL, - &iosb, - KphControlCode, - InBuffer, - InBufferLength, - NULL, - 0 - ); -} - -VOID KphpWithKeyApcRoutine( - _In_ PVOID ApcContext, - _In_ PIO_STATUS_BLOCK IoStatusBlock, - _In_ ULONG Reserved - ) -{ - PKPHP_RETRIEVE_KEY_CONTEXT context = CONTAINING_RECORD(IoStatusBlock, KPHP_RETRIEVE_KEY_CONTEXT, Iosb); - KPH_KEY key = PtrToUlong(ApcContext); - - if (context->Continuation != KphpGetL1KeyContinuation && - context->Continuation != KphpOpenProcessContinuation && - context->Continuation != KphpOpenProcessTokenContinuation && - context->Continuation != KphpTerminateProcessContinuation && - context->Continuation != KphpReadVirtualMemoryUnsafeContinuation && - context->Continuation != KphpOpenThreadContinuation) - { - PhRaiseStatus(STATUS_ACCESS_DENIED); - context->Status = STATUS_ACCESS_DENIED; - return; - } - - context->Status = context->Continuation(key, context->Context); -} - -NTSTATUS KphpWithKey( - _In_ KPH_KEY_LEVEL KeyLevel, - _In_ PKPHP_WITH_KEY_CONTINUATION Continuation, - _In_ PVOID Context - ) -{ - NTSTATUS status; - struct - { - KPH_KEY_LEVEL KeyLevel; - } input = { KeyLevel }; - KPHP_RETRIEVE_KEY_CONTEXT context; - - context.Continuation = Continuation; - context.Context = Context; - context.Status = STATUS_UNSUCCESSFUL; - - status = NtDeviceIoControlFile( - PhKphHandle, - NULL, - KphpWithKeyApcRoutine, - NULL, - &context.Iosb, - KPH_RETRIEVEKEY, - &input, - sizeof(input), - NULL, - 0 - ); - - NtTestAlert(); - - if (!NT_SUCCESS(status)) - return status; - - return context.Status; -} - -NTSTATUS KphpGetL1KeyContinuation( - _In_ KPH_KEY Key, - _In_ PVOID Context - ) -{ - PKPHP_GET_L1_KEY_CONTEXT context = Context; - - *context->Key = Key; - PhKphL1Key = Key; - - return STATUS_SUCCESS; -} - -NTSTATUS KphpGetL1Key( - _Out_ PKPH_KEY Key - ) -{ - KPHP_GET_L1_KEY_CONTEXT context; - - if (PhKphL1Key) - { - *Key = PhKphL1Key; - return STATUS_SUCCESS; - } - - context.Key = Key; - - return KphpWithKey(KphKeyLevel1, KphpGetL1KeyContinuation, &context); -} - -NTSTATUS KphpOpenProcessContinuation( - _In_ KPH_KEY Key, - _In_ PVOID Context - ) -{ - PKPH_OPEN_PROCESS_INPUT input = Context; - - input->Key = Key; - - return KphpDeviceIoControl( - KPH_OPENPROCESS, - input, - sizeof(*input) - ); -} - -NTSTATUS KphpOpenProcessTokenContinuation( - _In_ KPH_KEY Key, - _In_ PVOID Context - ) -{ - PKPH_OPEN_PROCESS_TOKEN_INPUT input = Context; - - input->Key = Key; - - return KphpDeviceIoControl( - KPH_OPENPROCESSTOKEN, - input, - sizeof(*input) - ); -} - -NTSTATUS KphpTerminateProcessContinuation( - _In_ KPH_KEY Key, - _In_ PVOID Context - ) -{ - PKPH_TERMINATE_PROCESS_INPUT input = Context; - - input->Key = Key; - - return KphpDeviceIoControl( - KPH_TERMINATEPROCESS, - input, - sizeof(*input) - ); -} - -NTSTATUS KphpReadVirtualMemoryUnsafeContinuation( - _In_ KPH_KEY Key, - _In_ PVOID Context - ) -{ - PKPH_READ_VIRTUAL_MEMORY_UNSAFE_INPUT input = Context; - - input->Key = Key; - - return KphpDeviceIoControl( - KPH_READVIRTUALMEMORYUNSAFE, - input, - sizeof(*input) - ); -} - -NTSTATUS KphpOpenThreadContinuation( - _In_ KPH_KEY Key, - _In_ PVOID Context - ) -{ - PKPH_OPEN_PROCESS_INPUT input = Context; - - input->Key = Key; - - return KphpDeviceIoControl( - KPH_OPENTHREAD, - input, - sizeof(*input) - ); -} +/* + * Process Hacker - + * KProcessHacker API + * + * Copyright (C) 2009-2016 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include +#include +#include + +HANDLE PhKphHandle = NULL; +BOOLEAN PhKphVerified; +KPH_KEY PhKphL1Key; + +NTSTATUS KphConnect( + _In_opt_ PWSTR DeviceName + ) +{ + NTSTATUS status; + HANDLE kphHandle; + UNICODE_STRING objectName; + OBJECT_ATTRIBUTES objectAttributes; + IO_STATUS_BLOCK isb; + OBJECT_HANDLE_FLAG_INFORMATION handleFlagInfo; + + if (PhKphHandle) + return STATUS_ADDRESS_ALREADY_EXISTS; + + if (DeviceName) + RtlInitUnicodeString(&objectName, DeviceName); + else + RtlInitUnicodeString(&objectName, KPH_DEVICE_NAME); + + InitializeObjectAttributes( + &objectAttributes, + &objectName, + OBJ_CASE_INSENSITIVE, + NULL, + NULL + ); + + status = NtOpenFile( + &kphHandle, + FILE_GENERIC_READ | FILE_GENERIC_WRITE, + &objectAttributes, + &isb, + FILE_SHARE_READ | FILE_SHARE_WRITE, + FILE_NON_DIRECTORY_FILE + ); + + if (NT_SUCCESS(status)) + { + // Protect the handle from being closed. + + handleFlagInfo.Inherit = FALSE; + handleFlagInfo.ProtectFromClose = TRUE; + + NtSetInformationObject( + kphHandle, + ObjectHandleFlagInformation, + &handleFlagInfo, + sizeof(OBJECT_HANDLE_FLAG_INFORMATION) + ); + + PhKphHandle = kphHandle; + PhKphVerified = FALSE; + PhKphL1Key = 0; + } + + return status; +} + +NTSTATUS KphConnect2( + _In_opt_ PWSTR DeviceName, + _In_ PWSTR FileName + ) +{ + return KphConnect2Ex(DeviceName, FileName, NULL); +} + +NTSTATUS KphConnect2Ex( + _In_opt_ PWSTR DeviceName, + _In_ PWSTR FileName, + _In_opt_ PKPH_PARAMETERS Parameters + ) +{ + NTSTATUS status; + WCHAR fullDeviceName[256]; + PH_FORMAT format[2]; + SC_HANDLE scmHandle; + SC_HANDLE serviceHandle; + BOOLEAN started = FALSE; + BOOLEAN created = FALSE; + + if (!DeviceName) + DeviceName = KPH_DEVICE_SHORT_NAME; + + PhInitFormatS(&format[0], L"\\Device\\"); + PhInitFormatS(&format[1], DeviceName); + + if (!PhFormatToBuffer(format, 2, fullDeviceName, sizeof(fullDeviceName), NULL)) + return STATUS_NAME_TOO_LONG; + + // Try to open the device. + status = KphConnect(fullDeviceName); + + if (NT_SUCCESS(status) || status == STATUS_ADDRESS_ALREADY_EXISTS) + return status; + + if ( + status != STATUS_NO_SUCH_DEVICE && + status != STATUS_NO_SUCH_FILE && + status != STATUS_OBJECT_NAME_NOT_FOUND && + status != STATUS_OBJECT_PATH_NOT_FOUND + ) + return status; + + // Load the driver, and try again. + + // Try to start the service, if it exists. + + scmHandle = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT); + + if (scmHandle) + { + serviceHandle = OpenService(scmHandle, DeviceName, SERVICE_START); + + if (serviceHandle) + { + if (StartService(serviceHandle, 0, NULL)) + started = TRUE; + + CloseServiceHandle(serviceHandle); + } + + CloseServiceHandle(scmHandle); + } + + if (!started && RtlDoesFileExists_U(FileName)) + { + // Try to create the service. + + scmHandle = OpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE); + + if (scmHandle) + { + serviceHandle = CreateService( + scmHandle, + DeviceName, + DeviceName, + SERVICE_ALL_ACCESS, + SERVICE_KERNEL_DRIVER, + SERVICE_DEMAND_START, + SERVICE_ERROR_IGNORE, + FileName, + NULL, + NULL, + NULL, + NULL, + L"" + ); + + if (serviceHandle) + { + created = TRUE; + + // Set parameters if the caller supplied them. Note that we fail the entire function + // if this fails, because failing to set parameters like SecurityLevel may result in + // security vulnerabilities. + if (Parameters) + { + status = KphSetParameters(DeviceName, Parameters); + + if (!NT_SUCCESS(status)) + { + // Delete the service and fail. + goto CreateAndConnectEnd; + } + } + + if (StartService(serviceHandle, 0, NULL)) + started = TRUE; + } + + CloseServiceHandle(scmHandle); + } + } + + if (started) + { + // Try to open the device again. + status = KphConnect(fullDeviceName); + } + +CreateAndConnectEnd: + if (created) + { + // "Delete" the service. Since we (may) have a handle to the device, the SCM will delete the + // service automatically when it is stopped (upon reboot). If we don't have a handle to the + // device, the service will get deleted immediately, which is a good thing anyway. + DeleteService(serviceHandle); + CloseServiceHandle(serviceHandle); + } + + return status; +} + +NTSTATUS KphDisconnect( + VOID + ) +{ + NTSTATUS status; + OBJECT_HANDLE_FLAG_INFORMATION handleFlagInfo; + + if (!PhKphHandle) + return STATUS_ALREADY_DISCONNECTED; + + // Unprotect the handle. + + handleFlagInfo.Inherit = FALSE; + handleFlagInfo.ProtectFromClose = FALSE; + + NtSetInformationObject( + PhKphHandle, + ObjectHandleFlagInformation, + &handleFlagInfo, + sizeof(OBJECT_HANDLE_FLAG_INFORMATION) + ); + + status = NtClose(PhKphHandle); + PhKphHandle = NULL; + PhKphVerified = FALSE; + PhKphL1Key = 0; + + return status; +} + +BOOLEAN KphIsConnected( + VOID + ) +{ + return PhKphHandle != NULL; +} + +BOOLEAN KphIsVerified( + VOID + ) +{ + return PhKphVerified; +} + +NTSTATUS KphSetParameters( + _In_opt_ PWSTR DeviceName, + _In_ PKPH_PARAMETERS Parameters + ) +{ + NTSTATUS status; + HANDLE parametersKeyHandle = NULL; + PPH_STRING parametersKeyName; + ULONG disposition; + UNICODE_STRING valueName; + + if (!DeviceName) + DeviceName = KPH_DEVICE_SHORT_NAME; + + parametersKeyName = PhConcatStrings( + 3, + L"System\\CurrentControlSet\\Services\\", + DeviceName, + L"\\Parameters" + ); + status = PhCreateKey( + ¶metersKeyHandle, + KEY_WRITE | DELETE, + PH_KEY_LOCAL_MACHINE, + ¶metersKeyName->sr, + 0, + 0, + &disposition + ); + PhDereferenceObject(parametersKeyName); + + if (!NT_SUCCESS(status)) + return status; + + RtlInitUnicodeString(&valueName, L"SecurityLevel"); + status = NtSetValueKey(parametersKeyHandle, &valueName, 0, REG_DWORD, &Parameters->SecurityLevel, sizeof(ULONG)); + + if (!NT_SUCCESS(status)) + goto SetValuesEnd; + + if (Parameters->CreateDynamicConfiguration) + { + KPH_DYN_CONFIGURATION configuration; + + RtlInitUnicodeString(&valueName, L"DynamicConfiguration"); + + configuration.Version = KPH_DYN_CONFIGURATION_VERSION; + configuration.NumberOfPackages = 1; + + if (NT_SUCCESS(KphInitializeDynamicPackage(&configuration.Packages[0]))) + { + status = NtSetValueKey(parametersKeyHandle, &valueName, 0, REG_BINARY, &configuration, sizeof(KPH_DYN_CONFIGURATION)); + + if (!NT_SUCCESS(status)) + goto SetValuesEnd; + } + } + + // Put more parameters here... + +SetValuesEnd: + if (!NT_SUCCESS(status)) + { + // Delete the key if we created it. + if (disposition == REG_CREATED_NEW_KEY) + NtDeleteKey(parametersKeyHandle); + } + + NtClose(parametersKeyHandle); + + return status; +} + +NTSTATUS KphInstall( + _In_opt_ PWSTR DeviceName, + _In_ PWSTR FileName + ) +{ + return KphInstallEx(DeviceName, FileName, NULL); +} + +NTSTATUS KphInstallEx( + _In_opt_ PWSTR DeviceName, + _In_ PWSTR FileName, + _In_opt_ PKPH_PARAMETERS Parameters + ) +{ + NTSTATUS status = STATUS_SUCCESS; + SC_HANDLE scmHandle; + SC_HANDLE serviceHandle; + + if (!DeviceName) + DeviceName = KPH_DEVICE_SHORT_NAME; + + scmHandle = OpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE); + + if (!scmHandle) + return PhGetLastWin32ErrorAsNtStatus(); + + serviceHandle = CreateService( + scmHandle, + DeviceName, + DeviceName, + SERVICE_ALL_ACCESS, + SERVICE_KERNEL_DRIVER, + SERVICE_SYSTEM_START, + SERVICE_ERROR_IGNORE, + FileName, + NULL, + NULL, + NULL, + NULL, + L"" + ); + + if (serviceHandle) + { + // See KphConnect2Ex for more details. + if (Parameters) + { + status = KphSetParameters(DeviceName, Parameters); + + if (!NT_SUCCESS(status)) + { + DeleteService(serviceHandle); + goto CreateEnd; + } + } + + if (!StartService(serviceHandle, 0, NULL)) + status = PhGetLastWin32ErrorAsNtStatus(); + +CreateEnd: + CloseServiceHandle(serviceHandle); + } + else + { + status = PhGetLastWin32ErrorAsNtStatus(); + } + + CloseServiceHandle(scmHandle); + + return status; +} + +NTSTATUS KphUninstall( + _In_opt_ PWSTR DeviceName + ) +{ + NTSTATUS status = STATUS_SUCCESS; + SC_HANDLE scmHandle; + SC_HANDLE serviceHandle; + + if (!DeviceName) + DeviceName = KPH_DEVICE_SHORT_NAME; + + scmHandle = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT); + + if (!scmHandle) + return PhGetLastWin32ErrorAsNtStatus(); + + serviceHandle = OpenService(scmHandle, DeviceName, SERVICE_STOP | DELETE); + + if (serviceHandle) + { + SERVICE_STATUS serviceStatus; + + ControlService(serviceHandle, SERVICE_CONTROL_STOP, &serviceStatus); + + if (!DeleteService(serviceHandle)) + status = PhGetLastWin32ErrorAsNtStatus(); + + CloseServiceHandle(serviceHandle); + } + else + { + status = PhGetLastWin32ErrorAsNtStatus(); + } + + CloseServiceHandle(scmHandle); + + return status; +} + +NTSTATUS KphGetFeatures( + _Out_ PULONG Features + ) +{ + struct + { + PULONG Features; + } input = { Features }; + + return KphpDeviceIoControl( + KPH_GETFEATURES, + &input, + sizeof(input) + ); +} + +NTSTATUS KphVerifyClient( + _In_reads_bytes_(SignatureSize) PUCHAR Signature, + _In_ ULONG SignatureSize + ) +{ + NTSTATUS status; + struct + { + PVOID CodeAddress; + PUCHAR Signature; + ULONG SignatureSize; + } input = { KphpWithKeyApcRoutine, Signature, SignatureSize }; + + status = KphpDeviceIoControl( + KPH_VERIFYCLIENT, + &input, + sizeof(input) + ); + + if (NT_SUCCESS(status)) + PhKphVerified = TRUE; + + return status; +} + +NTSTATUS KphOpenProcess( + _Out_ PHANDLE ProcessHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ PCLIENT_ID ClientId + ) +{ + KPH_OPEN_PROCESS_INPUT input = { ProcessHandle, DesiredAccess, ClientId, 0 }; + + if ((DesiredAccess & KPH_PROCESS_READ_ACCESS) == DesiredAccess) + { + KphpGetL1Key(&input.Key); + return KphpDeviceIoControl( + KPH_OPENPROCESS, + &input, + sizeof(input) + ); + } + else + { + return KphpWithKey(KphKeyLevel2, KphpOpenProcessContinuation, &input); + } +} + +NTSTATUS KphOpenProcessToken( + _In_ HANDLE ProcessHandle, + _In_ ACCESS_MASK DesiredAccess, + _Out_ PHANDLE TokenHandle + ) +{ + KPH_OPEN_PROCESS_TOKEN_INPUT input = { ProcessHandle, DesiredAccess, TokenHandle, 0 }; + + if ((DesiredAccess & KPH_TOKEN_READ_ACCESS) == DesiredAccess) + { + KphpGetL1Key(&input.Key); + return KphpDeviceIoControl( + KPH_OPENPROCESSTOKEN, + &input, + sizeof(input) + ); + } + else + { + return KphpWithKey(KphKeyLevel2, KphpOpenProcessTokenContinuation, &input); + } +} + +NTSTATUS KphOpenProcessJob( + _In_ HANDLE ProcessHandle, + _In_ ACCESS_MASK DesiredAccess, + _Out_ PHANDLE JobHandle + ) +{ + struct + { + HANDLE ProcessHandle; + ACCESS_MASK DesiredAccess; + PHANDLE JobHandle; + } input = { ProcessHandle, DesiredAccess, JobHandle }; + + return KphpDeviceIoControl( + KPH_OPENPROCESSJOB, + &input, + sizeof(input) + ); +} + +NTSTATUS KphTerminateProcess( + _In_ HANDLE ProcessHandle, + _In_ NTSTATUS ExitStatus + ) +{ + NTSTATUS status; + KPH_TERMINATE_PROCESS_INPUT input = { ProcessHandle, ExitStatus, 0 }; + + status = KphpWithKey(KphKeyLevel2, KphpTerminateProcessContinuation, &input); + + // Check if we're trying to terminate the current process, because kernel-mode can't do it. + if (status == STATUS_CANT_TERMINATE_SELF) + { + RtlExitUserProcess(ExitStatus); + } + + return status; +} + +NTSTATUS KphReadVirtualMemoryUnsafe( + _In_opt_ HANDLE ProcessHandle, + _In_ PVOID BaseAddress, + _Out_writes_bytes_(BufferSize) PVOID Buffer, + _In_ SIZE_T BufferSize, + _Out_opt_ PSIZE_T NumberOfBytesRead + ) +{ + KPH_READ_VIRTUAL_MEMORY_UNSAFE_INPUT input = { ProcessHandle, BaseAddress, Buffer, BufferSize, NumberOfBytesRead, 0 }; + + return KphpWithKey(KphKeyLevel2, KphpReadVirtualMemoryUnsafeContinuation, &input); +} + +NTSTATUS KphQueryInformationProcess( + _In_ HANDLE ProcessHandle, + _In_ KPH_PROCESS_INFORMATION_CLASS ProcessInformationClass, + _Out_writes_bytes_(ProcessInformationLength) PVOID ProcessInformation, + _In_ ULONG ProcessInformationLength, + _Out_opt_ PULONG ReturnLength + ) +{ + struct + { + HANDLE ProcessHandle; + KPH_PROCESS_INFORMATION_CLASS ProcessInformationClass; + PVOID ProcessInformation; + ULONG ProcessInformationLength; + PULONG ReturnLength; + } input = { ProcessHandle, ProcessInformationClass, ProcessInformation, ProcessInformationLength, ReturnLength }; + + return KphpDeviceIoControl( + KPH_QUERYINFORMATIONPROCESS, + &input, + sizeof(input) + ); +} + +NTSTATUS KphSetInformationProcess( + _In_ HANDLE ProcessHandle, + _In_ KPH_PROCESS_INFORMATION_CLASS ProcessInformationClass, + _In_reads_bytes_(ProcessInformationLength) PVOID ProcessInformation, + _In_ ULONG ProcessInformationLength + ) +{ + struct + { + HANDLE ProcessHandle; + KPH_PROCESS_INFORMATION_CLASS ProcessInformationClass; + PVOID ProcessInformation; + ULONG ProcessInformationLength; + } input = { ProcessHandle, ProcessInformationClass, ProcessInformation, ProcessInformationLength }; + + return KphpDeviceIoControl( + KPH_SETINFORMATIONPROCESS, + &input, + sizeof(input) + ); +} + +NTSTATUS KphOpenThread( + _Out_ PHANDLE ThreadHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ PCLIENT_ID ClientId + ) +{ + KPH_OPEN_THREAD_INPUT input = { ThreadHandle, DesiredAccess, ClientId, 0 }; + + if ((DesiredAccess & KPH_THREAD_READ_ACCESS) == DesiredAccess) + { + KphpGetL1Key(&input.Key); + return KphpDeviceIoControl( + KPH_OPENTHREAD, + &input, + sizeof(input) + ); + } + else + { + return KphpWithKey(KphKeyLevel2, KphpOpenThreadContinuation, &input); + } +} + +NTSTATUS KphOpenThreadProcess( + _In_ HANDLE ThreadHandle, + _In_ ACCESS_MASK DesiredAccess, + _Out_ PHANDLE ProcessHandle + ) +{ + struct + { + HANDLE ThreadHandle; + ACCESS_MASK DesiredAccess; + PHANDLE ProcessHandle; + } input = { ThreadHandle, DesiredAccess, ProcessHandle }; + + return KphpDeviceIoControl( + KPH_OPENTHREADPROCESS, + &input, + sizeof(input) + ); +} + +NTSTATUS KphCaptureStackBackTraceThread( + _In_ HANDLE ThreadHandle, + _In_ ULONG FramesToSkip, + _In_ ULONG FramesToCapture, + _Out_writes_(FramesToCapture) PVOID *BackTrace, + _Out_opt_ PULONG CapturedFrames, + _Out_opt_ PULONG BackTraceHash + ) +{ + struct + { + HANDLE ThreadHandle; + ULONG FramesToSkip; + ULONG FramesToCapture; + PVOID *BackTrace; + PULONG CapturedFrames; + PULONG BackTraceHash; + } input = { ThreadHandle, FramesToSkip, FramesToCapture, BackTrace, CapturedFrames, BackTraceHash }; + + return KphpDeviceIoControl( + KPH_CAPTURESTACKBACKTRACETHREAD, + &input, + sizeof(input) + ); +} + +NTSTATUS KphQueryInformationThread( + _In_ HANDLE ThreadHandle, + _In_ KPH_THREAD_INFORMATION_CLASS ThreadInformationClass, + _Out_writes_bytes_(ThreadInformationLength) PVOID ThreadInformation, + _In_ ULONG ThreadInformationLength, + _Out_opt_ PULONG ReturnLength + ) +{ + struct + { + HANDLE ThreadHandle; + KPH_THREAD_INFORMATION_CLASS ThreadInformationClass; + PVOID ThreadInformation; + ULONG ThreadInformationLength; + PULONG ReturnLength; + } input = { ThreadHandle, ThreadInformationClass, ThreadInformation, ThreadInformationLength, ReturnLength }; + + return KphpDeviceIoControl( + KPH_QUERYINFORMATIONTHREAD, + &input, + sizeof(input) + ); +} + +NTSTATUS KphSetInformationThread( + _In_ HANDLE ThreadHandle, + _In_ KPH_THREAD_INFORMATION_CLASS ThreadInformationClass, + _In_reads_bytes_(ThreadInformationLength) PVOID ThreadInformation, + _In_ ULONG ThreadInformationLength + ) +{ + struct + { + HANDLE ThreadHandle; + KPH_THREAD_INFORMATION_CLASS ThreadInformationClass; + PVOID ThreadInformation; + ULONG ThreadInformationLength; + } input = { ThreadHandle, ThreadInformationClass, ThreadInformation, ThreadInformationLength }; + + return KphpDeviceIoControl( + KPH_SETINFORMATIONTHREAD, + &input, + sizeof(input) + ); +} + +NTSTATUS KphEnumerateProcessHandles( + _In_ HANDLE ProcessHandle, + _Out_writes_bytes_(BufferLength) PVOID Buffer, + _In_opt_ ULONG BufferLength, + _Out_opt_ PULONG ReturnLength + ) +{ + struct + { + HANDLE ProcessHandle; + PVOID Buffer; + ULONG BufferLength; + PULONG ReturnLength; + } input = { ProcessHandle, Buffer, BufferLength, ReturnLength }; + + return KphpDeviceIoControl( + KPH_ENUMERATEPROCESSHANDLES, + &input, + sizeof(input) + ); +} + +NTSTATUS KphEnumerateProcessHandles2( + _In_ HANDLE ProcessHandle, + _Out_ PKPH_PROCESS_HANDLE_INFORMATION *Handles + ) +{ + NTSTATUS status; + PVOID buffer; + ULONG bufferSize = 2048; + + buffer = PhAllocate(bufferSize); + + while (TRUE) + { + status = KphEnumerateProcessHandles( + ProcessHandle, + buffer, + bufferSize, + &bufferSize + ); + + if (status == STATUS_BUFFER_TOO_SMALL) + { + PhFree(buffer); + buffer = PhAllocate(bufferSize); + } + else + { + break; + } + } + + if (!NT_SUCCESS(status)) + { + PhFree(buffer); + return status; + } + + *Handles = buffer; + + return status; +} + +NTSTATUS KphQueryInformationObject( + _In_ HANDLE ProcessHandle, + _In_ HANDLE Handle, + _In_ KPH_OBJECT_INFORMATION_CLASS ObjectInformationClass, + _Out_writes_bytes_(ObjectInformationLength) PVOID ObjectInformation, + _In_ ULONG ObjectInformationLength, + _Out_opt_ PULONG ReturnLength + ) +{ + struct + { + HANDLE ProcessHandle; + HANDLE Handle; + KPH_OBJECT_INFORMATION_CLASS ObjectInformationClass; + PVOID ObjectInformation; + ULONG ObjectInformationLength; + PULONG ReturnLength; + } input = { ProcessHandle, Handle, ObjectInformationClass, ObjectInformation, ObjectInformationLength, ReturnLength }; + + return KphpDeviceIoControl( + KPH_QUERYINFORMATIONOBJECT, + &input, + sizeof(input) + ); +} + +NTSTATUS KphSetInformationObject( + _In_ HANDLE ProcessHandle, + _In_ HANDLE Handle, + _In_ KPH_OBJECT_INFORMATION_CLASS ObjectInformationClass, + _In_reads_bytes_(ObjectInformationLength) PVOID ObjectInformation, + _In_ ULONG ObjectInformationLength + ) +{ + struct + { + HANDLE ProcessHandle; + HANDLE Handle; + KPH_OBJECT_INFORMATION_CLASS ObjectInformationClass; + PVOID ObjectInformation; + ULONG ObjectInformationLength; + } input = { ProcessHandle, Handle, ObjectInformationClass, ObjectInformation, ObjectInformationLength }; + + return KphpDeviceIoControl( + KPH_SETINFORMATIONOBJECT, + &input, + sizeof(input) + ); +} + +NTSTATUS KphOpenDriver( + _Out_ PHANDLE DriverHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes + ) +{ + struct + { + PHANDLE DriverHandle; + ACCESS_MASK DesiredAccess; + POBJECT_ATTRIBUTES ObjectAttributes; + } input = { DriverHandle, DesiredAccess, ObjectAttributes }; + + return KphpDeviceIoControl( + KPH_OPENDRIVER, + &input, + sizeof(input) + ); +} + +NTSTATUS KphQueryInformationDriver( + _In_ HANDLE DriverHandle, + _In_ DRIVER_INFORMATION_CLASS DriverInformationClass, + _Out_writes_bytes_(DriverInformationLength) PVOID DriverInformation, + _In_ ULONG DriverInformationLength, + _Out_opt_ PULONG ReturnLength + ) +{ + struct + { + HANDLE DriverHandle; + DRIVER_INFORMATION_CLASS DriverInformationClass; + PVOID DriverInformation; + ULONG DriverInformationLength; + PULONG ReturnLength; + } input = { DriverHandle, DriverInformationClass, DriverInformation, DriverInformationLength, ReturnLength }; + + return KphpDeviceIoControl( + KPH_QUERYINFORMATIONDRIVER, + &input, + sizeof(input) + ); +} + +NTSTATUS KphpDeviceIoControl( + _In_ ULONG KphControlCode, + _In_ PVOID InBuffer, + _In_ ULONG InBufferLength + ) +{ + IO_STATUS_BLOCK iosb; + + return NtDeviceIoControlFile( + PhKphHandle, + NULL, + NULL, + NULL, + &iosb, + KphControlCode, + InBuffer, + InBufferLength, + NULL, + 0 + ); +} + +VOID KphpWithKeyApcRoutine( + _In_ PVOID ApcContext, + _In_ PIO_STATUS_BLOCK IoStatusBlock, + _In_ ULONG Reserved + ) +{ + PKPHP_RETRIEVE_KEY_CONTEXT context = CONTAINING_RECORD(IoStatusBlock, KPHP_RETRIEVE_KEY_CONTEXT, Iosb); + KPH_KEY key = PtrToUlong(ApcContext); + + if (context->Continuation != KphpGetL1KeyContinuation && + context->Continuation != KphpOpenProcessContinuation && + context->Continuation != KphpOpenProcessTokenContinuation && + context->Continuation != KphpTerminateProcessContinuation && + context->Continuation != KphpReadVirtualMemoryUnsafeContinuation && + context->Continuation != KphpOpenThreadContinuation) + { + PhRaiseStatus(STATUS_ACCESS_DENIED); + context->Status = STATUS_ACCESS_DENIED; + return; + } + + context->Status = context->Continuation(key, context->Context); +} + +NTSTATUS KphpWithKey( + _In_ KPH_KEY_LEVEL KeyLevel, + _In_ PKPHP_WITH_KEY_CONTINUATION Continuation, + _In_ PVOID Context + ) +{ + NTSTATUS status; + struct + { + KPH_KEY_LEVEL KeyLevel; + } input = { KeyLevel }; + KPHP_RETRIEVE_KEY_CONTEXT context; + + context.Continuation = Continuation; + context.Context = Context; + context.Status = STATUS_UNSUCCESSFUL; + + status = NtDeviceIoControlFile( + PhKphHandle, + NULL, + KphpWithKeyApcRoutine, + NULL, + &context.Iosb, + KPH_RETRIEVEKEY, + &input, + sizeof(input), + NULL, + 0 + ); + + NtTestAlert(); + + if (!NT_SUCCESS(status)) + return status; + + return context.Status; +} + +NTSTATUS KphpGetL1KeyContinuation( + _In_ KPH_KEY Key, + _In_ PVOID Context + ) +{ + PKPHP_GET_L1_KEY_CONTEXT context = Context; + + *context->Key = Key; + PhKphL1Key = Key; + + return STATUS_SUCCESS; +} + +NTSTATUS KphpGetL1Key( + _Out_ PKPH_KEY Key + ) +{ + KPHP_GET_L1_KEY_CONTEXT context; + + if (PhKphL1Key) + { + *Key = PhKphL1Key; + return STATUS_SUCCESS; + } + + context.Key = Key; + + return KphpWithKey(KphKeyLevel1, KphpGetL1KeyContinuation, &context); +} + +NTSTATUS KphpOpenProcessContinuation( + _In_ KPH_KEY Key, + _In_ PVOID Context + ) +{ + PKPH_OPEN_PROCESS_INPUT input = Context; + + input->Key = Key; + + return KphpDeviceIoControl( + KPH_OPENPROCESS, + input, + sizeof(*input) + ); +} + +NTSTATUS KphpOpenProcessTokenContinuation( + _In_ KPH_KEY Key, + _In_ PVOID Context + ) +{ + PKPH_OPEN_PROCESS_TOKEN_INPUT input = Context; + + input->Key = Key; + + return KphpDeviceIoControl( + KPH_OPENPROCESSTOKEN, + input, + sizeof(*input) + ); +} + +NTSTATUS KphpTerminateProcessContinuation( + _In_ KPH_KEY Key, + _In_ PVOID Context + ) +{ + PKPH_TERMINATE_PROCESS_INPUT input = Context; + + input->Key = Key; + + return KphpDeviceIoControl( + KPH_TERMINATEPROCESS, + input, + sizeof(*input) + ); +} + +NTSTATUS KphpReadVirtualMemoryUnsafeContinuation( + _In_ KPH_KEY Key, + _In_ PVOID Context + ) +{ + PKPH_READ_VIRTUAL_MEMORY_UNSAFE_INPUT input = Context; + + input->Key = Key; + + return KphpDeviceIoControl( + KPH_READVIRTUALMEMORYUNSAFE, + input, + sizeof(*input) + ); +} + +NTSTATUS KphpOpenThreadContinuation( + _In_ KPH_KEY Key, + _In_ PVOID Context + ) +{ + PKPH_OPEN_PROCESS_INPUT input = Context; + + input->Key = Key; + + return KphpDeviceIoControl( + KPH_OPENTHREAD, + input, + sizeof(*input) + ); +} diff --git a/phlib/kphdata.c b/phlib/kphdata.c index 179d0df5c90f..1ec3c206008b 100644 --- a/phlib/kphdata.c +++ b/phlib/kphdata.c @@ -1,329 +1,329 @@ -/* - * Process Hacker - - * KProcessHacker dynamic data definitions - * - * Copyright (C) 2011-2016 wj32 - * Copyright (C) 2017 dmex - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include -#include - -#ifdef _WIN64 - -ULONG KphpGetKernelRevisionNumber( - VOID - ) -{ - ULONG result; - PPH_STRING kernelFileName; - PVOID versionInfo; - VS_FIXEDFILEINFO *rootBlock; - ULONG rootBlockLength; - - result = 0; - kernelFileName = PhGetKernelFileName(); - PhMoveReference(&kernelFileName, PhGetFileName(kernelFileName)); - versionInfo = PhGetFileVersionInfo(kernelFileName->Buffer); - PhDereferenceObject(kernelFileName); - - if (versionInfo && VerQueryValue(versionInfo, L"\\", &rootBlock, &rootBlockLength) && rootBlockLength != 0) - result = rootBlock->dwFileVersionLS & 0xffff; - - PhFree(versionInfo); - - return result; -} - -NTSTATUS KphInitializeDynamicPackage( - _Out_ PKPH_DYN_PACKAGE Package - ) -{ - ULONG majorVersion, minorVersion, servicePack, buildNumber; - - majorVersion = PhOsVersion.dwMajorVersion; - minorVersion = PhOsVersion.dwMinorVersion; - servicePack = PhOsVersion.wServicePackMajor; - buildNumber = PhOsVersion.dwBuildNumber; - - memset(&Package->StructData, -1, sizeof(KPH_DYN_STRUCT_DATA)); - - Package->MajorVersion = (USHORT)majorVersion; - Package->MinorVersion = (USHORT)minorVersion; - Package->ServicePackMajor = (USHORT)servicePack; - Package->BuildNumber = -1; - - // Windows 7, Windows Server 2008 R2 - if (majorVersion == 6 && minorVersion == 1) - { - ULONG revisionNumber = KphpGetKernelRevisionNumber(); - - Package->ResultingNtVersion = PHNT_WIN7; - - if (servicePack == 0) - { - } - else if (servicePack == 1) - { - } - else - { - return STATUS_NOT_SUPPORTED; - } - - Package->StructData.EgeGuid = 0x14; - Package->StructData.EpObjectTable = 0x200; - Package->StructData.EreGuidEntry = revisionNumber >= 19160 ? 0x20 : 0x10; - Package->StructData.OtName = 0x10; - Package->StructData.OtIndex = 0x28; // now only a UCHAR, not a ULONG - } - // Windows 8, Windows Server 2012 - else if (majorVersion == 6 && minorVersion == 2 && buildNumber == 9200) - { - Package->BuildNumber = 9200; - Package->ResultingNtVersion = PHNT_WIN8; - - Package->StructData.EgeGuid = 0x14; - Package->StructData.EpObjectTable = 0x408; - Package->StructData.EreGuidEntry = 0x10; - Package->StructData.HtHandleContentionEvent = 0x30; - Package->StructData.OtName = 0x10; - Package->StructData.OtIndex = 0x28; - Package->StructData.ObDecodeShift = 19; - Package->StructData.ObAttributesShift = 20; - } - // Windows 8.1, Windows Server 2012 R2 - else if (majorVersion == 6 && minorVersion == 3 && buildNumber == 9600) - { - ULONG revisionNumber = KphpGetKernelRevisionNumber(); - - Package->BuildNumber = 9600; - Package->ResultingNtVersion = PHNT_WINBLUE; - - Package->StructData.EgeGuid = 0x18; - Package->StructData.EpObjectTable = 0x408; - Package->StructData.EreGuidEntry = revisionNumber >= 17736 ? 0x20 : 0x10; - Package->StructData.HtHandleContentionEvent = 0x30; - Package->StructData.OtName = 0x10; - Package->StructData.OtIndex = 0x28; - Package->StructData.ObDecodeShift = 16; - Package->StructData.ObAttributesShift = 17; - } - // Windows 10 - else if (majorVersion == 10 && minorVersion == 0 && buildNumber == 10240) - { - Package->BuildNumber = 10240; - Package->ResultingNtVersion = PHNT_THRESHOLD; - - Package->StructData.EgeGuid = 0x18; - Package->StructData.EpObjectTable = 0x418; - Package->StructData.EreGuidEntry = 0x20; - Package->StructData.HtHandleContentionEvent = 0x30; - Package->StructData.OtName = 0x10; - Package->StructData.OtIndex = 0x28; - Package->StructData.ObDecodeShift = 16; - Package->StructData.ObAttributesShift = 17; - } - else if (majorVersion == 10 && minorVersion == 0 && buildNumber == 10586) - { - Package->BuildNumber = 10586; - Package->ResultingNtVersion = PHNT_THRESHOLD2; - - Package->StructData.EgeGuid = 0x18; - Package->StructData.EpObjectTable = 0x418; - Package->StructData.EreGuidEntry = 0x20; - Package->StructData.HtHandleContentionEvent = 0x30; - Package->StructData.OtName = 0x10; - Package->StructData.OtIndex = 0x28; - Package->StructData.ObDecodeShift = 16; - Package->StructData.ObAttributesShift = 17; - } - else if (majorVersion == 10 && minorVersion == 0 && buildNumber == 14393) - { - Package->BuildNumber = 14393; - Package->ResultingNtVersion = PHNT_REDSTONE; - - Package->StructData.EgeGuid = 0x18; - Package->StructData.EpObjectTable = 0x418; - Package->StructData.EreGuidEntry = 0x20; - Package->StructData.HtHandleContentionEvent = 0x30; - Package->StructData.OtName = 0x10; - Package->StructData.OtIndex = 0x28; - Package->StructData.ObDecodeShift = 16; - Package->StructData.ObAttributesShift = 17; - } - else if (majorVersion == 10 && minorVersion == 0 && buildNumber == 15063) - { - Package->BuildNumber = 15063; - Package->ResultingNtVersion = PHNT_REDSTONE2; - - Package->StructData.EgeGuid = 0x18; - Package->StructData.EpObjectTable = 0x418; - Package->StructData.EreGuidEntry = 0x20; - Package->StructData.HtHandleContentionEvent = 0x30; - Package->StructData.OtName = 0x10; - Package->StructData.OtIndex = 0x28; - Package->StructData.ObDecodeShift = 16; - Package->StructData.ObAttributesShift = 17; - } - else - { - return STATUS_NOT_SUPPORTED; - } - - return STATUS_SUCCESS; -} - -#else - -NTSTATUS KphInitializeDynamicPackage( - _Out_ PKPH_DYN_PACKAGE Package - ) -{ - ULONG majorVersion, minorVersion, servicePack, buildNumber; - - majorVersion = PhOsVersion.dwMajorVersion; - minorVersion = PhOsVersion.dwMinorVersion; - servicePack = PhOsVersion.wServicePackMajor; - buildNumber = PhOsVersion.dwBuildNumber; - - memset(&Package->StructData, -1, sizeof(KPH_DYN_STRUCT_DATA)); - - Package->MajorVersion = (USHORT)majorVersion; - Package->MinorVersion = (USHORT)minorVersion; - Package->ServicePackMajor = (USHORT)servicePack; - Package->BuildNumber = -1; - - // Windows 7, Windows Server 2008 R2 - if (majorVersion == 6 && minorVersion == 1) - { - Package->ResultingNtVersion = PHNT_WIN7; - - if (servicePack == 0) - { - NOTHING; - } - else if (servicePack == 1) - { - NOTHING; - } - else - { - return STATUS_NOT_SUPPORTED; - } - - Package->StructData.EgeGuid = 0xc; - Package->StructData.EpObjectTable = 0xf4; - Package->StructData.EreGuidEntry = 0x8; - Package->StructData.OtName = 0x8; - Package->StructData.OtIndex = 0x14; // now only a UCHAR, not a ULONG - } - // Windows 8, Windows Server 2012 - else if (majorVersion == 6 && minorVersion == 2) - { - Package->ResultingNtVersion = PHNT_WIN8; - - if (servicePack == 0) - { - NOTHING; - } - else - { - return STATUS_NOT_SUPPORTED; - } - - Package->StructData.EgeGuid = 0xc; - Package->StructData.EpObjectTable = 0x150; - Package->StructData.EreGuidEntry = 0x8; - Package->StructData.OtName = 0x8; - Package->StructData.OtIndex = 0x14; - } - // Windows 8.1, Windows Server 2012 R2 - else if (majorVersion == 6 && minorVersion == 3) - { - Package->ResultingNtVersion = PHNT_WINBLUE; - - if (servicePack == 0) - { - NOTHING; - } - else - { - return STATUS_NOT_SUPPORTED; - } - - Package->StructData.EgeGuid = 0xc; - Package->StructData.EpObjectTable = 0x150; - Package->StructData.EreGuidEntry = 0x8; - Package->StructData.OtName = 0x8; - Package->StructData.OtIndex = 0x14; - } - // Windows 10 - else if (majorVersion == 10 && minorVersion == 0 && buildNumber == 10240) - { - Package->BuildNumber = 10240; - Package->ResultingNtVersion = PHNT_THRESHOLD; - - Package->StructData.EgeGuid = 0xc; - Package->StructData.EpObjectTable = 0x154; - Package->StructData.EreGuidEntry = 0x10; - Package->StructData.OtName = 0x8; - Package->StructData.OtIndex = 0x14; - } - else if (majorVersion == 10 && minorVersion == 0 && buildNumber == 10586) - { - Package->BuildNumber = 10586; - Package->ResultingNtVersion = PHNT_THRESHOLD2; - - Package->StructData.EgeGuid = 0xc; - Package->StructData.EpObjectTable = 0x154; - Package->StructData.EreGuidEntry = 0x10; - Package->StructData.OtName = 0x8; - Package->StructData.OtIndex = 0x14; - } - else if (majorVersion == 10 && minorVersion == 0 && buildNumber == 14393) - { - Package->BuildNumber = 14393; - Package->ResultingNtVersion = PHNT_REDSTONE; - - Package->StructData.EgeGuid = 0xc; - Package->StructData.EpObjectTable = 0x154; - Package->StructData.EreGuidEntry = 0x10; - Package->StructData.OtName = 0x8; - Package->StructData.OtIndex = 0x14; - } - else if (majorVersion == 10 && minorVersion == 0 && buildNumber == 15063) - { - Package->BuildNumber = 15063; - Package->ResultingNtVersion = PHNT_REDSTONE2; - - Package->StructData.EgeGuid = 0xc; - Package->StructData.EpObjectTable = 0x154; - Package->StructData.EreGuidEntry = 0x10; - Package->StructData.OtName = 0x8; - Package->StructData.OtIndex = 0x14; - } - else - { - return STATUS_NOT_SUPPORTED; - } - - return STATUS_SUCCESS; -} - -#endif +/* + * Process Hacker - + * KProcessHacker dynamic data definitions + * + * Copyright (C) 2011-2016 wj32 + * Copyright (C) 2017 dmex + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include +#include + +#ifdef _WIN64 + +ULONG KphpGetKernelRevisionNumber( + VOID + ) +{ + ULONG result; + PPH_STRING kernelFileName; + PVOID versionInfo; + VS_FIXEDFILEINFO *rootBlock; + ULONG rootBlockLength; + + result = 0; + kernelFileName = PhGetKernelFileName(); + PhMoveReference(&kernelFileName, PhGetFileName(kernelFileName)); + versionInfo = PhGetFileVersionInfo(kernelFileName->Buffer); + PhDereferenceObject(kernelFileName); + + if (versionInfo && VerQueryValue(versionInfo, L"\\", &rootBlock, &rootBlockLength) && rootBlockLength != 0) + result = rootBlock->dwFileVersionLS & 0xffff; + + PhFree(versionInfo); + + return result; +} + +NTSTATUS KphInitializeDynamicPackage( + _Out_ PKPH_DYN_PACKAGE Package + ) +{ + ULONG majorVersion, minorVersion, servicePack, buildNumber; + + majorVersion = PhOsVersion.dwMajorVersion; + minorVersion = PhOsVersion.dwMinorVersion; + servicePack = PhOsVersion.wServicePackMajor; + buildNumber = PhOsVersion.dwBuildNumber; + + memset(&Package->StructData, -1, sizeof(KPH_DYN_STRUCT_DATA)); + + Package->MajorVersion = (USHORT)majorVersion; + Package->MinorVersion = (USHORT)minorVersion; + Package->ServicePackMajor = (USHORT)servicePack; + Package->BuildNumber = -1; + + // Windows 7, Windows Server 2008 R2 + if (majorVersion == 6 && minorVersion == 1) + { + ULONG revisionNumber = KphpGetKernelRevisionNumber(); + + Package->ResultingNtVersion = PHNT_WIN7; + + if (servicePack == 0) + { + } + else if (servicePack == 1) + { + } + else + { + return STATUS_NOT_SUPPORTED; + } + + Package->StructData.EgeGuid = 0x14; + Package->StructData.EpObjectTable = 0x200; + Package->StructData.EreGuidEntry = revisionNumber >= 19160 ? 0x20 : 0x10; + Package->StructData.OtName = 0x10; + Package->StructData.OtIndex = 0x28; // now only a UCHAR, not a ULONG + } + // Windows 8, Windows Server 2012 + else if (majorVersion == 6 && minorVersion == 2 && buildNumber == 9200) + { + Package->BuildNumber = 9200; + Package->ResultingNtVersion = PHNT_WIN8; + + Package->StructData.EgeGuid = 0x14; + Package->StructData.EpObjectTable = 0x408; + Package->StructData.EreGuidEntry = 0x10; + Package->StructData.HtHandleContentionEvent = 0x30; + Package->StructData.OtName = 0x10; + Package->StructData.OtIndex = 0x28; + Package->StructData.ObDecodeShift = 19; + Package->StructData.ObAttributesShift = 20; + } + // Windows 8.1, Windows Server 2012 R2 + else if (majorVersion == 6 && minorVersion == 3 && buildNumber == 9600) + { + ULONG revisionNumber = KphpGetKernelRevisionNumber(); + + Package->BuildNumber = 9600; + Package->ResultingNtVersion = PHNT_WINBLUE; + + Package->StructData.EgeGuid = 0x18; + Package->StructData.EpObjectTable = 0x408; + Package->StructData.EreGuidEntry = revisionNumber >= 17736 ? 0x20 : 0x10; + Package->StructData.HtHandleContentionEvent = 0x30; + Package->StructData.OtName = 0x10; + Package->StructData.OtIndex = 0x28; + Package->StructData.ObDecodeShift = 16; + Package->StructData.ObAttributesShift = 17; + } + // Windows 10 + else if (majorVersion == 10 && minorVersion == 0 && buildNumber == 10240) + { + Package->BuildNumber = 10240; + Package->ResultingNtVersion = PHNT_THRESHOLD; + + Package->StructData.EgeGuid = 0x18; + Package->StructData.EpObjectTable = 0x418; + Package->StructData.EreGuidEntry = 0x20; + Package->StructData.HtHandleContentionEvent = 0x30; + Package->StructData.OtName = 0x10; + Package->StructData.OtIndex = 0x28; + Package->StructData.ObDecodeShift = 16; + Package->StructData.ObAttributesShift = 17; + } + else if (majorVersion == 10 && minorVersion == 0 && buildNumber == 10586) + { + Package->BuildNumber = 10586; + Package->ResultingNtVersion = PHNT_THRESHOLD2; + + Package->StructData.EgeGuid = 0x18; + Package->StructData.EpObjectTable = 0x418; + Package->StructData.EreGuidEntry = 0x20; + Package->StructData.HtHandleContentionEvent = 0x30; + Package->StructData.OtName = 0x10; + Package->StructData.OtIndex = 0x28; + Package->StructData.ObDecodeShift = 16; + Package->StructData.ObAttributesShift = 17; + } + else if (majorVersion == 10 && minorVersion == 0 && buildNumber == 14393) + { + Package->BuildNumber = 14393; + Package->ResultingNtVersion = PHNT_REDSTONE; + + Package->StructData.EgeGuid = 0x18; + Package->StructData.EpObjectTable = 0x418; + Package->StructData.EreGuidEntry = 0x20; + Package->StructData.HtHandleContentionEvent = 0x30; + Package->StructData.OtName = 0x10; + Package->StructData.OtIndex = 0x28; + Package->StructData.ObDecodeShift = 16; + Package->StructData.ObAttributesShift = 17; + } + else if (majorVersion == 10 && minorVersion == 0 && buildNumber == 15063) + { + Package->BuildNumber = 15063; + Package->ResultingNtVersion = PHNT_REDSTONE2; + + Package->StructData.EgeGuid = 0x18; + Package->StructData.EpObjectTable = 0x418; + Package->StructData.EreGuidEntry = 0x20; + Package->StructData.HtHandleContentionEvent = 0x30; + Package->StructData.OtName = 0x10; + Package->StructData.OtIndex = 0x28; + Package->StructData.ObDecodeShift = 16; + Package->StructData.ObAttributesShift = 17; + } + else + { + return STATUS_NOT_SUPPORTED; + } + + return STATUS_SUCCESS; +} + +#else + +NTSTATUS KphInitializeDynamicPackage( + _Out_ PKPH_DYN_PACKAGE Package + ) +{ + ULONG majorVersion, minorVersion, servicePack, buildNumber; + + majorVersion = PhOsVersion.dwMajorVersion; + minorVersion = PhOsVersion.dwMinorVersion; + servicePack = PhOsVersion.wServicePackMajor; + buildNumber = PhOsVersion.dwBuildNumber; + + memset(&Package->StructData, -1, sizeof(KPH_DYN_STRUCT_DATA)); + + Package->MajorVersion = (USHORT)majorVersion; + Package->MinorVersion = (USHORT)minorVersion; + Package->ServicePackMajor = (USHORT)servicePack; + Package->BuildNumber = -1; + + // Windows 7, Windows Server 2008 R2 + if (majorVersion == 6 && minorVersion == 1) + { + Package->ResultingNtVersion = PHNT_WIN7; + + if (servicePack == 0) + { + NOTHING; + } + else if (servicePack == 1) + { + NOTHING; + } + else + { + return STATUS_NOT_SUPPORTED; + } + + Package->StructData.EgeGuid = 0xc; + Package->StructData.EpObjectTable = 0xf4; + Package->StructData.EreGuidEntry = 0x8; + Package->StructData.OtName = 0x8; + Package->StructData.OtIndex = 0x14; // now only a UCHAR, not a ULONG + } + // Windows 8, Windows Server 2012 + else if (majorVersion == 6 && minorVersion == 2) + { + Package->ResultingNtVersion = PHNT_WIN8; + + if (servicePack == 0) + { + NOTHING; + } + else + { + return STATUS_NOT_SUPPORTED; + } + + Package->StructData.EgeGuid = 0xc; + Package->StructData.EpObjectTable = 0x150; + Package->StructData.EreGuidEntry = 0x8; + Package->StructData.OtName = 0x8; + Package->StructData.OtIndex = 0x14; + } + // Windows 8.1, Windows Server 2012 R2 + else if (majorVersion == 6 && minorVersion == 3) + { + Package->ResultingNtVersion = PHNT_WINBLUE; + + if (servicePack == 0) + { + NOTHING; + } + else + { + return STATUS_NOT_SUPPORTED; + } + + Package->StructData.EgeGuid = 0xc; + Package->StructData.EpObjectTable = 0x150; + Package->StructData.EreGuidEntry = 0x8; + Package->StructData.OtName = 0x8; + Package->StructData.OtIndex = 0x14; + } + // Windows 10 + else if (majorVersion == 10 && minorVersion == 0 && buildNumber == 10240) + { + Package->BuildNumber = 10240; + Package->ResultingNtVersion = PHNT_THRESHOLD; + + Package->StructData.EgeGuid = 0xc; + Package->StructData.EpObjectTable = 0x154; + Package->StructData.EreGuidEntry = 0x10; + Package->StructData.OtName = 0x8; + Package->StructData.OtIndex = 0x14; + } + else if (majorVersion == 10 && minorVersion == 0 && buildNumber == 10586) + { + Package->BuildNumber = 10586; + Package->ResultingNtVersion = PHNT_THRESHOLD2; + + Package->StructData.EgeGuid = 0xc; + Package->StructData.EpObjectTable = 0x154; + Package->StructData.EreGuidEntry = 0x10; + Package->StructData.OtName = 0x8; + Package->StructData.OtIndex = 0x14; + } + else if (majorVersion == 10 && minorVersion == 0 && buildNumber == 14393) + { + Package->BuildNumber = 14393; + Package->ResultingNtVersion = PHNT_REDSTONE; + + Package->StructData.EgeGuid = 0xc; + Package->StructData.EpObjectTable = 0x154; + Package->StructData.EreGuidEntry = 0x10; + Package->StructData.OtName = 0x8; + Package->StructData.OtIndex = 0x14; + } + else if (majorVersion == 10 && minorVersion == 0 && buildNumber == 15063) + { + Package->BuildNumber = 15063; + Package->ResultingNtVersion = PHNT_REDSTONE2; + + Package->StructData.EgeGuid = 0xc; + Package->StructData.EpObjectTable = 0x154; + Package->StructData.EreGuidEntry = 0x10; + Package->StructData.OtName = 0x8; + Package->StructData.OtIndex = 0x14; + } + else + { + return STATUS_NOT_SUPPORTED; + } + + return STATUS_SUCCESS; +} + +#endif diff --git a/phlib/maplib.c b/phlib/maplib.c index 3d01feddb655..41b80cdfbafc 100644 --- a/phlib/maplib.c +++ b/phlib/maplib.c @@ -1,402 +1,402 @@ -/* - * Process Hacker - - * mapped library - * - * Copyright (C) 2010 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -/* - * This file contains functions to load and retrieve information for library/archive files (lib). - * The file format for archive files is explained in the PE/COFF specification located at: - * - * http://www.microsoft.com/whdc/system/platform/firmware/PECOFF.mspx - */ - -#include -#include - -VOID PhpMappedArchiveProbe( - _In_ PPH_MAPPED_ARCHIVE MappedArchive, - _In_ PVOID Address, - _In_ SIZE_T Length - ); - -NTSTATUS PhpGetMappedArchiveMemberFromHeader( - _In_ PPH_MAPPED_ARCHIVE MappedArchive, - _In_ PIMAGE_ARCHIVE_MEMBER_HEADER Header, - _Out_ PPH_MAPPED_ARCHIVE_MEMBER Member - ); - -NTSTATUS PhInitializeMappedArchive( - _Out_ PPH_MAPPED_ARCHIVE MappedArchive, - _In_ PVOID ViewBase, - _In_ SIZE_T Size - ) -{ - NTSTATUS status; - PCHAR start; - - start = (PCHAR)ViewBase; - - memset(MappedArchive, 0, sizeof(PH_MAPPED_ARCHIVE)); - MappedArchive->ViewBase = ViewBase; - MappedArchive->Size = Size; - - __try - { - // Verify the file signature. - - PhpMappedArchiveProbe(MappedArchive, start, IMAGE_ARCHIVE_START_SIZE); - - if (memcmp(start, IMAGE_ARCHIVE_START, IMAGE_ARCHIVE_START_SIZE) != 0) - PhRaiseStatus(STATUS_INVALID_IMAGE_FORMAT); - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - return GetExceptionCode(); - } - - // Get the members. - // Note: the names are checked. - - // First linker member - - status = PhpGetMappedArchiveMemberFromHeader( - MappedArchive, - (PIMAGE_ARCHIVE_MEMBER_HEADER)(start + IMAGE_ARCHIVE_START_SIZE), - &MappedArchive->FirstLinkerMember - ); - - if (!NT_SUCCESS(status)) - return status; - - if (MappedArchive->FirstLinkerMember.Type != LinkerArchiveMemberType) - return STATUS_INVALID_PARAMETER; - - MappedArchive->FirstStandardMember = &MappedArchive->FirstLinkerMember; - - // Second linker member - - status = PhGetNextMappedArchiveMember( - &MappedArchive->FirstLinkerMember, - &MappedArchive->SecondLinkerMember - ); - - if (!NT_SUCCESS(status)) - return status; - - if (MappedArchive->SecondLinkerMember.Type != LinkerArchiveMemberType) - return STATUS_INVALID_PARAMETER; - - // Longnames member - // This member doesn't seem to be mandatory, contrary to the specification. - // So we'll check if it's actually a longnames member, and if not, ignore it. - - status = PhGetNextMappedArchiveMember( - &MappedArchive->SecondLinkerMember, - &MappedArchive->LongnamesMember - ); - - if ( - NT_SUCCESS(status) && - MappedArchive->LongnamesMember.Type == LongnamesArchiveMemberType - ) - { - MappedArchive->HasLongnamesMember = TRUE; - MappedArchive->LastStandardMember = &MappedArchive->LongnamesMember; - } - else - { - MappedArchive->LastStandardMember = &MappedArchive->SecondLinkerMember; - } - - return STATUS_SUCCESS; -} - -NTSTATUS PhLoadMappedArchive( - _In_opt_ PWSTR FileName, - _In_opt_ HANDLE FileHandle, - _In_ BOOLEAN ReadOnly, - _Out_ PPH_MAPPED_ARCHIVE MappedArchive - ) -{ - NTSTATUS status; - - status = PhMapViewOfEntireFile( - FileName, - FileHandle, - ReadOnly, - &MappedArchive->ViewBase, - &MappedArchive->Size - ); - - if (NT_SUCCESS(status)) - { - status = PhInitializeMappedArchive( - MappedArchive, - MappedArchive->ViewBase, - MappedArchive->Size - ); - - if (!NT_SUCCESS(status)) - { - NtUnmapViewOfSection(NtCurrentProcess(), MappedArchive->ViewBase); - } - } - - return status; -} - -NTSTATUS PhUnloadMappedArchive( - _Inout_ PPH_MAPPED_ARCHIVE MappedArchive - ) -{ - return NtUnmapViewOfSection( - NtCurrentProcess(), - MappedArchive->ViewBase - ); -} - -VOID PhpMappedArchiveProbe( - _In_ PPH_MAPPED_ARCHIVE MappedArchive, - _In_ PVOID Address, - _In_ SIZE_T Length - ) -{ - PhProbeAddress(Address, Length, MappedArchive->ViewBase, MappedArchive->Size, 1); -} - -/** - * Gets the next archive member. - * - * \param Member An archive member structure. - * \param NextMember A variable which receives a structure describing the next archive member. This - * pointer may be the same as the pointer specified in \a Member. - */ -NTSTATUS PhGetNextMappedArchiveMember( - _In_ PPH_MAPPED_ARCHIVE_MEMBER Member, - _Out_ PPH_MAPPED_ARCHIVE_MEMBER NextMember - ) -{ - PIMAGE_ARCHIVE_MEMBER_HEADER nextHeader; - - nextHeader = (PIMAGE_ARCHIVE_MEMBER_HEADER)PTR_ADD_OFFSET( - Member->Data, - Member->Size - ); - - // 2 byte alignment. - if ((ULONG_PTR)nextHeader & 0x1) - nextHeader = (PIMAGE_ARCHIVE_MEMBER_HEADER)PTR_ADD_OFFSET(nextHeader, 1); - - return PhpGetMappedArchiveMemberFromHeader( - Member->MappedArchive, - nextHeader, - NextMember - ); -} - -NTSTATUS PhpGetMappedArchiveMemberFromHeader( - _In_ PPH_MAPPED_ARCHIVE MappedArchive, - _In_ PIMAGE_ARCHIVE_MEMBER_HEADER Header, - _Out_ PPH_MAPPED_ARCHIVE_MEMBER Member - ) -{ - WCHAR integerString[11]; - ULONG64 size; - PH_STRINGREF string; - PWSTR digit; - PSTR slash; - - if ((ULONG_PTR)Header >= (ULONG_PTR)MappedArchive->ViewBase + MappedArchive->Size) - return STATUS_NO_MORE_ENTRIES; - - __try - { - PhpMappedArchiveProbe(MappedArchive, Header, sizeof(IMAGE_ARCHIVE_MEMBER_HEADER)); - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - return GetExceptionCode(); - } - - Member->MappedArchive = MappedArchive; - Member->Header = Header; - Member->Data = PTR_ADD_OFFSET(Header, sizeof(IMAGE_ARCHIVE_MEMBER_HEADER)); - Member->Type = NormalArchiveMemberType; - - // Read the size string, terminate it after the last digit and parse it. - - if (!PhCopyStringZFromBytes(Header->Size, 10, integerString, 11, NULL)) - return STATUS_INVALID_PARAMETER; - - string.Buffer = integerString; - string.Length = 0; - digit = string.Buffer; - - while (iswdigit(*digit++)) - string.Length += sizeof(WCHAR); - - if (!PhStringToInteger64(&string, 10, &size)) - return STATUS_INVALID_PARAMETER; - - Member->Size = (ULONG)size; - - __try - { - PhpMappedArchiveProbe(MappedArchive, Member->Data, Member->Size); - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - return GetExceptionCode(); - } - - // Parse the name. - - if (!PhCopyBytesZ(Header->Name, 16, Member->NameBuffer, 20, NULL)) - return STATUS_INVALID_PARAMETER; - - Member->Name = Member->NameBuffer; - - slash = strchr(Member->NameBuffer, '/'); - - if (!slash) - return STATUS_INVALID_PARAMETER; - - // Special names: - // * If the slash is the first character, then this is a linker member. - // * If there is a slash after the slash which is a first character, then this is the longnames - // member. - // * If there are digits after the slash, then the real name is stored in the longnames member. - - if (slash == Member->NameBuffer) - { - if (Member->NameBuffer[1] == '/') - { - // Longnames member. Set the name to "/". - Member->NameBuffer[0] = '/'; - Member->NameBuffer[1] = 0; - - Member->Type = LongnamesArchiveMemberType; - } - else - { - // Linker member. Set the name to "". - Member->NameBuffer[0] = 0; - - Member->Type = LinkerArchiveMemberType; - } - } - else - { - if (isdigit(slash[1])) - { - PSTR digita; - ULONG64 offset64; - ULONG offset; - - // The name is stored in the longnames member. - // Note: we make sure we have the longnames member first. - - if (!MappedArchive->LongnamesMember.Header) - return STATUS_INVALID_PARAMETER; - - // Find the last digit and null terminate the string there. - - digita = slash + 2; - - while (isdigit(*digita)) - digita++; - - *digita = 0; - - // Parse the offset and make sure it lies within the longnames member. - - if (!PhCopyStringZFromBytes(slash + 1, -1, integerString, 11, NULL)) - return STATUS_INVALID_PARAMETER; - PhInitializeStringRefLongHint(&string, integerString); - if (!PhStringToInteger64(&string, 10, &offset64)) - return STATUS_INVALID_PARAMETER; - - offset = (ULONG)offset64; - - if (offset >= MappedArchive->LongnamesMember.Size) - return STATUS_INVALID_PARAMETER; - - // TODO: Probe the name. - Member->Name = (PSTR)PTR_ADD_OFFSET(MappedArchive->LongnamesMember.Data, offset); - } - else - { - // Null terminate the string. - slash[0] = 0; - } - } - - return STATUS_SUCCESS; -} - -BOOLEAN PhIsMappedArchiveMemberShortFormat( - _In_ PPH_MAPPED_ARCHIVE_MEMBER Member - ) -{ - PIMAGE_FILE_HEADER header; - - header = (PIMAGE_FILE_HEADER)Member->Data; - - return header->Machine != IMAGE_FILE_MACHINE_UNKNOWN; -} - -NTSTATUS PhGetMappedArchiveImportEntry( - _In_ PPH_MAPPED_ARCHIVE_MEMBER Member, - _Out_ PPH_MAPPED_ARCHIVE_IMPORT_ENTRY Entry - ) -{ - IMPORT_OBJECT_HEADER *importHeader; - - importHeader = (IMPORT_OBJECT_HEADER *)Member->Data; - - if (Member->Type != NormalArchiveMemberType) - return STATUS_INVALID_PARAMETER; - if ( - importHeader->Sig1 != IMAGE_FILE_MACHINE_UNKNOWN || - importHeader->Sig2 != IMPORT_OBJECT_HDR_SIG2 - ) - return STATUS_INVALID_PARAMETER; - - Entry->Type = (BYTE)importHeader->Type; - Entry->NameType = (BYTE)importHeader->NameType; - Entry->Machine = importHeader->Machine; - - // TODO: Probe the name. - Entry->Name = (PSTR)PTR_ADD_OFFSET(importHeader, sizeof(IMPORT_OBJECT_HEADER)); - Entry->DllName = (PSTR)PTR_ADD_OFFSET(Entry->Name, strlen(Entry->Name) + 1); - - // Ordinal/NameHint are union'ed, so these statements are exactly the same. - // It's there in case this changes in the future. - if (Entry->NameType == IMPORT_OBJECT_ORDINAL) - { - Entry->Ordinal = importHeader->Ordinal; - } - else - { - Entry->NameHint = importHeader->Hint; - } - - return STATUS_SUCCESS; -} +/* + * Process Hacker - + * mapped library + * + * Copyright (C) 2010 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +/* + * This file contains functions to load and retrieve information for library/archive files (lib). + * The file format for archive files is explained in the PE/COFF specification located at: + * + * http://www.microsoft.com/whdc/system/platform/firmware/PECOFF.mspx + */ + +#include +#include + +VOID PhpMappedArchiveProbe( + _In_ PPH_MAPPED_ARCHIVE MappedArchive, + _In_ PVOID Address, + _In_ SIZE_T Length + ); + +NTSTATUS PhpGetMappedArchiveMemberFromHeader( + _In_ PPH_MAPPED_ARCHIVE MappedArchive, + _In_ PIMAGE_ARCHIVE_MEMBER_HEADER Header, + _Out_ PPH_MAPPED_ARCHIVE_MEMBER Member + ); + +NTSTATUS PhInitializeMappedArchive( + _Out_ PPH_MAPPED_ARCHIVE MappedArchive, + _In_ PVOID ViewBase, + _In_ SIZE_T Size + ) +{ + NTSTATUS status; + PCHAR start; + + start = (PCHAR)ViewBase; + + memset(MappedArchive, 0, sizeof(PH_MAPPED_ARCHIVE)); + MappedArchive->ViewBase = ViewBase; + MappedArchive->Size = Size; + + __try + { + // Verify the file signature. + + PhpMappedArchiveProbe(MappedArchive, start, IMAGE_ARCHIVE_START_SIZE); + + if (memcmp(start, IMAGE_ARCHIVE_START, IMAGE_ARCHIVE_START_SIZE) != 0) + PhRaiseStatus(STATUS_INVALID_IMAGE_FORMAT); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + return GetExceptionCode(); + } + + // Get the members. + // Note: the names are checked. + + // First linker member + + status = PhpGetMappedArchiveMemberFromHeader( + MappedArchive, + (PIMAGE_ARCHIVE_MEMBER_HEADER)(start + IMAGE_ARCHIVE_START_SIZE), + &MappedArchive->FirstLinkerMember + ); + + if (!NT_SUCCESS(status)) + return status; + + if (MappedArchive->FirstLinkerMember.Type != LinkerArchiveMemberType) + return STATUS_INVALID_PARAMETER; + + MappedArchive->FirstStandardMember = &MappedArchive->FirstLinkerMember; + + // Second linker member + + status = PhGetNextMappedArchiveMember( + &MappedArchive->FirstLinkerMember, + &MappedArchive->SecondLinkerMember + ); + + if (!NT_SUCCESS(status)) + return status; + + if (MappedArchive->SecondLinkerMember.Type != LinkerArchiveMemberType) + return STATUS_INVALID_PARAMETER; + + // Longnames member + // This member doesn't seem to be mandatory, contrary to the specification. + // So we'll check if it's actually a longnames member, and if not, ignore it. + + status = PhGetNextMappedArchiveMember( + &MappedArchive->SecondLinkerMember, + &MappedArchive->LongnamesMember + ); + + if ( + NT_SUCCESS(status) && + MappedArchive->LongnamesMember.Type == LongnamesArchiveMemberType + ) + { + MappedArchive->HasLongnamesMember = TRUE; + MappedArchive->LastStandardMember = &MappedArchive->LongnamesMember; + } + else + { + MappedArchive->LastStandardMember = &MappedArchive->SecondLinkerMember; + } + + return STATUS_SUCCESS; +} + +NTSTATUS PhLoadMappedArchive( + _In_opt_ PWSTR FileName, + _In_opt_ HANDLE FileHandle, + _In_ BOOLEAN ReadOnly, + _Out_ PPH_MAPPED_ARCHIVE MappedArchive + ) +{ + NTSTATUS status; + + status = PhMapViewOfEntireFile( + FileName, + FileHandle, + ReadOnly, + &MappedArchive->ViewBase, + &MappedArchive->Size + ); + + if (NT_SUCCESS(status)) + { + status = PhInitializeMappedArchive( + MappedArchive, + MappedArchive->ViewBase, + MappedArchive->Size + ); + + if (!NT_SUCCESS(status)) + { + NtUnmapViewOfSection(NtCurrentProcess(), MappedArchive->ViewBase); + } + } + + return status; +} + +NTSTATUS PhUnloadMappedArchive( + _Inout_ PPH_MAPPED_ARCHIVE MappedArchive + ) +{ + return NtUnmapViewOfSection( + NtCurrentProcess(), + MappedArchive->ViewBase + ); +} + +VOID PhpMappedArchiveProbe( + _In_ PPH_MAPPED_ARCHIVE MappedArchive, + _In_ PVOID Address, + _In_ SIZE_T Length + ) +{ + PhProbeAddress(Address, Length, MappedArchive->ViewBase, MappedArchive->Size, 1); +} + +/** + * Gets the next archive member. + * + * \param Member An archive member structure. + * \param NextMember A variable which receives a structure describing the next archive member. This + * pointer may be the same as the pointer specified in \a Member. + */ +NTSTATUS PhGetNextMappedArchiveMember( + _In_ PPH_MAPPED_ARCHIVE_MEMBER Member, + _Out_ PPH_MAPPED_ARCHIVE_MEMBER NextMember + ) +{ + PIMAGE_ARCHIVE_MEMBER_HEADER nextHeader; + + nextHeader = (PIMAGE_ARCHIVE_MEMBER_HEADER)PTR_ADD_OFFSET( + Member->Data, + Member->Size + ); + + // 2 byte alignment. + if ((ULONG_PTR)nextHeader & 0x1) + nextHeader = (PIMAGE_ARCHIVE_MEMBER_HEADER)PTR_ADD_OFFSET(nextHeader, 1); + + return PhpGetMappedArchiveMemberFromHeader( + Member->MappedArchive, + nextHeader, + NextMember + ); +} + +NTSTATUS PhpGetMappedArchiveMemberFromHeader( + _In_ PPH_MAPPED_ARCHIVE MappedArchive, + _In_ PIMAGE_ARCHIVE_MEMBER_HEADER Header, + _Out_ PPH_MAPPED_ARCHIVE_MEMBER Member + ) +{ + WCHAR integerString[11]; + ULONG64 size; + PH_STRINGREF string; + PWSTR digit; + PSTR slash; + + if ((ULONG_PTR)Header >= (ULONG_PTR)MappedArchive->ViewBase + MappedArchive->Size) + return STATUS_NO_MORE_ENTRIES; + + __try + { + PhpMappedArchiveProbe(MappedArchive, Header, sizeof(IMAGE_ARCHIVE_MEMBER_HEADER)); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + return GetExceptionCode(); + } + + Member->MappedArchive = MappedArchive; + Member->Header = Header; + Member->Data = PTR_ADD_OFFSET(Header, sizeof(IMAGE_ARCHIVE_MEMBER_HEADER)); + Member->Type = NormalArchiveMemberType; + + // Read the size string, terminate it after the last digit and parse it. + + if (!PhCopyStringZFromBytes(Header->Size, 10, integerString, 11, NULL)) + return STATUS_INVALID_PARAMETER; + + string.Buffer = integerString; + string.Length = 0; + digit = string.Buffer; + + while (iswdigit(*digit++)) + string.Length += sizeof(WCHAR); + + if (!PhStringToInteger64(&string, 10, &size)) + return STATUS_INVALID_PARAMETER; + + Member->Size = (ULONG)size; + + __try + { + PhpMappedArchiveProbe(MappedArchive, Member->Data, Member->Size); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + return GetExceptionCode(); + } + + // Parse the name. + + if (!PhCopyBytesZ(Header->Name, 16, Member->NameBuffer, 20, NULL)) + return STATUS_INVALID_PARAMETER; + + Member->Name = Member->NameBuffer; + + slash = strchr(Member->NameBuffer, '/'); + + if (!slash) + return STATUS_INVALID_PARAMETER; + + // Special names: + // * If the slash is the first character, then this is a linker member. + // * If there is a slash after the slash which is a first character, then this is the longnames + // member. + // * If there are digits after the slash, then the real name is stored in the longnames member. + + if (slash == Member->NameBuffer) + { + if (Member->NameBuffer[1] == '/') + { + // Longnames member. Set the name to "/". + Member->NameBuffer[0] = '/'; + Member->NameBuffer[1] = 0; + + Member->Type = LongnamesArchiveMemberType; + } + else + { + // Linker member. Set the name to "". + Member->NameBuffer[0] = 0; + + Member->Type = LinkerArchiveMemberType; + } + } + else + { + if (isdigit(slash[1])) + { + PSTR digita; + ULONG64 offset64; + ULONG offset; + + // The name is stored in the longnames member. + // Note: we make sure we have the longnames member first. + + if (!MappedArchive->LongnamesMember.Header) + return STATUS_INVALID_PARAMETER; + + // Find the last digit and null terminate the string there. + + digita = slash + 2; + + while (isdigit(*digita)) + digita++; + + *digita = 0; + + // Parse the offset and make sure it lies within the longnames member. + + if (!PhCopyStringZFromBytes(slash + 1, -1, integerString, 11, NULL)) + return STATUS_INVALID_PARAMETER; + PhInitializeStringRefLongHint(&string, integerString); + if (!PhStringToInteger64(&string, 10, &offset64)) + return STATUS_INVALID_PARAMETER; + + offset = (ULONG)offset64; + + if (offset >= MappedArchive->LongnamesMember.Size) + return STATUS_INVALID_PARAMETER; + + // TODO: Probe the name. + Member->Name = (PSTR)PTR_ADD_OFFSET(MappedArchive->LongnamesMember.Data, offset); + } + else + { + // Null terminate the string. + slash[0] = 0; + } + } + + return STATUS_SUCCESS; +} + +BOOLEAN PhIsMappedArchiveMemberShortFormat( + _In_ PPH_MAPPED_ARCHIVE_MEMBER Member + ) +{ + PIMAGE_FILE_HEADER header; + + header = (PIMAGE_FILE_HEADER)Member->Data; + + return header->Machine != IMAGE_FILE_MACHINE_UNKNOWN; +} + +NTSTATUS PhGetMappedArchiveImportEntry( + _In_ PPH_MAPPED_ARCHIVE_MEMBER Member, + _Out_ PPH_MAPPED_ARCHIVE_IMPORT_ENTRY Entry + ) +{ + IMPORT_OBJECT_HEADER *importHeader; + + importHeader = (IMPORT_OBJECT_HEADER *)Member->Data; + + if (Member->Type != NormalArchiveMemberType) + return STATUS_INVALID_PARAMETER; + if ( + importHeader->Sig1 != IMAGE_FILE_MACHINE_UNKNOWN || + importHeader->Sig2 != IMPORT_OBJECT_HDR_SIG2 + ) + return STATUS_INVALID_PARAMETER; + + Entry->Type = (BYTE)importHeader->Type; + Entry->NameType = (BYTE)importHeader->NameType; + Entry->Machine = importHeader->Machine; + + // TODO: Probe the name. + Entry->Name = (PSTR)PTR_ADD_OFFSET(importHeader, sizeof(IMPORT_OBJECT_HEADER)); + Entry->DllName = (PSTR)PTR_ADD_OFFSET(Entry->Name, strlen(Entry->Name) + 1); + + // Ordinal/NameHint are union'ed, so these statements are exactly the same. + // It's there in case this changes in the future. + if (Entry->NameType == IMPORT_OBJECT_ORDINAL) + { + Entry->Ordinal = importHeader->Ordinal; + } + else + { + Entry->NameHint = importHeader->Hint; + } + + return STATUS_SUCCESS; +} diff --git a/phlib/md5.c b/phlib/md5.c index 8752c08c1b13..b984655e6220 100644 --- a/phlib/md5.c +++ b/phlib/md5.c @@ -1,225 +1,225 @@ -/* - * MD5 hash implementation and interface functions - * Copyright (c) 2003-2005, Jouni Malinen - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -/* This code was modified for Process Hacker. */ - -#include -#include "md5.h" - -void MD5Transform(ULONG buf[4], ULONG in[16]); - -/* - * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious - * initialization constants. - */ -VOID MD5Init( - _Out_ MD5_CTX *Context - ) -{ - Context->buf[0] = 0x67452301; - Context->buf[1] = 0xefcdab89; - Context->buf[2] = 0x98badcfe; - Context->buf[3] = 0x10325476; - - Context->i[0] = 0; - Context->i[1] = 0; -} - -/* - * Update context to reflect the concatenation of another buffer full - * of bytes. - */ -VOID MD5Update( - _Inout_ MD5_CTX *Context, - _In_reads_bytes_(Length) UCHAR *Input, - _In_ ULONG Length - ) -{ - ULONG t; - - /* Update bitcount */ - - t = Context->i[0]; - if ((Context->i[0] = t + ((ULONG) Length << 3)) < t) - Context->i[1]++; /* Carry from low to high */ - Context->i[1] += Length >> 29; - - t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */ - - /* Handle any leading odd-sized chunks */ - - if (t) { - unsigned char *p = (unsigned char *) Context->in + t; - - t = 64 - t; - if (Length < t) { - memcpy(p, Input, Length); - return; - } - memcpy(p, Input, t); - MD5Transform(Context->buf, (ULONG *) Context->in); - Input += t; - Length -= t; - } - /* Process data in 64-byte chunks */ - - while (Length >= 64) { - memcpy(Context->in, Input, 64); - MD5Transform(Context->buf, (ULONG *) Context->in); - Input += 64; - Length -= 64; - } - - /* Handle any remaining bytes of data. */ - - memcpy(Context->in, Input, Length); -} - -/* - * Final wrapup - pad to 64-byte boundary with the bit pattern - * 1 0* (64-bit count of bits processed, MSB-first) - */ -VOID MD5Final( - _Inout_ MD5_CTX *Context - ) -{ - unsigned int count; - unsigned char *p; - - /* Compute number of bytes mod 64 */ - count = (Context->i[0] >> 3) & 0x3F; - - /* Set the first char of padding to 0x80. This is safe since there is - always at least one byte free */ - p = Context->in + count; - *p++ = 0x80; - - /* Bytes of padding needed to make 64 bytes */ - count = 64 - 1 - count; - - /* Pad out to 56 mod 64 */ - if (count < 8) { - /* Two lots of padding: Pad the first block to 64 bytes */ - memset(p, 0, count); - MD5Transform(Context->buf, (ULONG *) Context->in); - - /* Now fill the next block with 56 bytes */ - memset(Context->in, 0, 56); - } else { - /* Pad block to 56 bytes */ - memset(p, 0, count - 8); - } - - /* Append length in bits and transform */ - ((ULONG *) Context->in)[14] = Context->i[0]; - ((ULONG *) Context->in)[15] = Context->i[1]; - - MD5Transform(Context->buf, (ULONG *) Context->in); - memcpy(Context->digest, Context->buf, 16); -} - -/* The four core functions - F1 is optimized somewhat */ - -/* #define F1(x, y, z) (x & y | ~x & z) */ -#define F1(x, y, z) (z ^ (x & (y ^ z))) -#define F2(x, y, z) F1(z, x, y) -#define F3(x, y, z) (x ^ y ^ z) -#define F4(x, y, z) (y ^ (x | ~z)) - -/* This is the central step in the MD5 algorithm. */ -#define MD5STEP(f, w, x, y, z, data, s) \ - ( w += f(x, y, z) + data, w = _rotl(w, s), w += x ) - -/* - * The core of the MD5 algorithm, this alters an existing MD5 hash to - * reflect the addition of 16 longwords of new data. MD5Update blocks - * the data and converts bytes into longwords for this routine. - */ -void MD5Transform(ULONG buf[4], ULONG in[16]) -{ - register ULONG a, b, c, d; - - a = buf[0]; - b = buf[1]; - c = buf[2]; - d = buf[3]; - - MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); - MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); - MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); - MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); - MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); - MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); - MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); - MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); - MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); - MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); - MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); - MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); - MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); - MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); - MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); - MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); - - MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); - MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); - MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); - MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); - MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); - MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); - MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); - MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); - MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); - MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); - MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); - MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); - MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); - MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); - MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); - MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); - - MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); - MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); - MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); - MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); - MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); - MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); - MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); - MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); - MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); - MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); - MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); - MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); - MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); - MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); - MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); - MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); - - MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); - MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); - MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); - MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); - MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); - MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); - MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); - MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); - MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); - MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); - MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); - MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); - MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); - MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); - MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); - MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); - - buf[0] += a; - buf[1] += b; - buf[2] += c; - buf[3] += d; -} +/* + * MD5 hash implementation and interface functions + * Copyright (c) 2003-2005, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/* This code was modified for Process Hacker. */ + +#include +#include "md5.h" + +void MD5Transform(ULONG buf[4], ULONG in[16]); + +/* + * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious + * initialization constants. + */ +VOID MD5Init( + _Out_ MD5_CTX *Context + ) +{ + Context->buf[0] = 0x67452301; + Context->buf[1] = 0xefcdab89; + Context->buf[2] = 0x98badcfe; + Context->buf[3] = 0x10325476; + + Context->i[0] = 0; + Context->i[1] = 0; +} + +/* + * Update context to reflect the concatenation of another buffer full + * of bytes. + */ +VOID MD5Update( + _Inout_ MD5_CTX *Context, + _In_reads_bytes_(Length) UCHAR *Input, + _In_ ULONG Length + ) +{ + ULONG t; + + /* Update bitcount */ + + t = Context->i[0]; + if ((Context->i[0] = t + ((ULONG) Length << 3)) < t) + Context->i[1]++; /* Carry from low to high */ + Context->i[1] += Length >> 29; + + t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */ + + /* Handle any leading odd-sized chunks */ + + if (t) { + unsigned char *p = (unsigned char *) Context->in + t; + + t = 64 - t; + if (Length < t) { + memcpy(p, Input, Length); + return; + } + memcpy(p, Input, t); + MD5Transform(Context->buf, (ULONG *) Context->in); + Input += t; + Length -= t; + } + /* Process data in 64-byte chunks */ + + while (Length >= 64) { + memcpy(Context->in, Input, 64); + MD5Transform(Context->buf, (ULONG *) Context->in); + Input += 64; + Length -= 64; + } + + /* Handle any remaining bytes of data. */ + + memcpy(Context->in, Input, Length); +} + +/* + * Final wrapup - pad to 64-byte boundary with the bit pattern + * 1 0* (64-bit count of bits processed, MSB-first) + */ +VOID MD5Final( + _Inout_ MD5_CTX *Context + ) +{ + unsigned int count; + unsigned char *p; + + /* Compute number of bytes mod 64 */ + count = (Context->i[0] >> 3) & 0x3F; + + /* Set the first char of padding to 0x80. This is safe since there is + always at least one byte free */ + p = Context->in + count; + *p++ = 0x80; + + /* Bytes of padding needed to make 64 bytes */ + count = 64 - 1 - count; + + /* Pad out to 56 mod 64 */ + if (count < 8) { + /* Two lots of padding: Pad the first block to 64 bytes */ + memset(p, 0, count); + MD5Transform(Context->buf, (ULONG *) Context->in); + + /* Now fill the next block with 56 bytes */ + memset(Context->in, 0, 56); + } else { + /* Pad block to 56 bytes */ + memset(p, 0, count - 8); + } + + /* Append length in bits and transform */ + ((ULONG *) Context->in)[14] = Context->i[0]; + ((ULONG *) Context->in)[15] = Context->i[1]; + + MD5Transform(Context->buf, (ULONG *) Context->in); + memcpy(Context->digest, Context->buf, 16); +} + +/* The four core functions - F1 is optimized somewhat */ + +/* #define F1(x, y, z) (x & y | ~x & z) */ +#define F1(x, y, z) (z ^ (x & (y ^ z))) +#define F2(x, y, z) F1(z, x, y) +#define F3(x, y, z) (x ^ y ^ z) +#define F4(x, y, z) (y ^ (x | ~z)) + +/* This is the central step in the MD5 algorithm. */ +#define MD5STEP(f, w, x, y, z, data, s) \ + ( w += f(x, y, z) + data, w = _rotl(w, s), w += x ) + +/* + * The core of the MD5 algorithm, this alters an existing MD5 hash to + * reflect the addition of 16 longwords of new data. MD5Update blocks + * the data and converts bytes into longwords for this routine. + */ +void MD5Transform(ULONG buf[4], ULONG in[16]) +{ + register ULONG a, b, c, d; + + a = buf[0]; + b = buf[1]; + c = buf[2]; + d = buf[3]; + + MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); + MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); + MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); + MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); + MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); + MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); + MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); + MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); + MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); + MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); + MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); + MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); + MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); + MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); + MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); + MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); + + MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); + MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); + MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); + MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); + MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); + MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); + MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); + MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); + MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); + MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); + MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); + MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); + MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); + MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); + MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); + MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); + + MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); + MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); + MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); + MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); + MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); + MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); + MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); + MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); + MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); + MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); + MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); + MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); + MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); + MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); + MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); + MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); + + MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); + MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); + MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); + MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); + MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); + MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); + MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); + MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); + MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); + MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); + MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); + MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); + MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); + MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); + MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); + MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; +} diff --git a/phlib/native.c b/phlib/native.c index 5173837f70b6..169bcf5d01a1 100644 --- a/phlib/native.c +++ b/phlib/native.c @@ -1,6462 +1,6462 @@ -/* - * Process Hacker - - * native wrapper and support functions - * - * Copyright (C) 2009-2016 wj32 - * Copyright (C) 2017 dmex - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include - -#include -#include -#include -#include - -#define PH_DEVICE_PREFIX_LENGTH 64 -#define PH_DEVICE_MUP_PREFIX_MAX_COUNT 16 - -typedef BOOLEAN (NTAPI *PPHP_ENUM_PROCESS_MODULES_CALLBACK)( - _In_ HANDLE ProcessHandle, - _In_ PLDR_DATA_TABLE_ENTRY Entry, - _In_ PVOID AddressOfEntry, - _In_opt_ PVOID Context1, - _In_opt_ PVOID Context2 - ); - -typedef BOOLEAN (NTAPI *PPHP_ENUM_PROCESS_MODULES32_CALLBACK)( - _In_ HANDLE ProcessHandle, - _In_ PLDR_DATA_TABLE_ENTRY32 Entry, - _In_ ULONG AddressOfEntry, - _In_opt_ PVOID Context1, - _In_opt_ PVOID Context2 - ); - -static PH_INITONCE PhDevicePrefixesInitOnce = PH_INITONCE_INIT; - -static UNICODE_STRING PhDevicePrefixes[26]; -static PH_QUEUED_LOCK PhDevicePrefixesLock = PH_QUEUED_LOCK_INIT; - -static PPH_STRING PhDeviceMupPrefixes[PH_DEVICE_MUP_PREFIX_MAX_COUNT] = { 0 }; -static ULONG PhDeviceMupPrefixesCount = 0; -static PH_QUEUED_LOCK PhDeviceMupPrefixesLock = PH_QUEUED_LOCK_INIT; - -static PH_INITONCE PhPredefineKeyInitOnce = PH_INITONCE_INIT; -static UNICODE_STRING PhPredefineKeyNames[PH_KEY_MAXIMUM_PREDEFINE] = -{ - RTL_CONSTANT_STRING(L"\\Registry\\Machine"), - RTL_CONSTANT_STRING(L"\\Registry\\User"), - RTL_CONSTANT_STRING(L"\\Registry\\Machine\\Software\\Classes"), - { 0, 0, NULL } -}; -static HANDLE PhPredefineKeyHandles[PH_KEY_MAXIMUM_PREDEFINE] = { 0 }; - -/** - * Queries information about the token of the current process. - */ -PH_TOKEN_ATTRIBUTES PhGetOwnTokenAttributes( - VOID - ) -{ - static PH_INITONCE initOnce = PH_INITONCE_INIT; - static PH_TOKEN_ATTRIBUTES attributes; - - if (PhBeginInitOnce(&initOnce)) - { - if (NT_SUCCESS(NtOpenProcessToken( - NtCurrentProcess(), - TOKEN_QUERY, - &attributes.TokenHandle - ))) - { - BOOLEAN elevated = TRUE; - TOKEN_ELEVATION_TYPE elevationType = TokenElevationTypeFull; - - if (WINDOWS_HAS_UAC) - { - PhGetTokenIsElevated(attributes.TokenHandle, &elevated); - PhGetTokenElevationType(attributes.TokenHandle, &elevationType); - } - - attributes.Elevated = elevated; - attributes.ElevationType = elevationType; - } - - PhEndInitOnce(&initOnce); - } - - return attributes; -} - -/** - * Opens a process. - * - * \param ProcessHandle A variable which receives a handle to the process. - * \param DesiredAccess The desired access to the process. - * \param ProcessId The ID of the process. - */ -NTSTATUS PhOpenProcess( - _Out_ PHANDLE ProcessHandle, - _In_ ACCESS_MASK DesiredAccess, - _In_ HANDLE ProcessId - ) -{ - NTSTATUS status; - OBJECT_ATTRIBUTES objectAttributes; - CLIENT_ID clientId; - - clientId.UniqueProcess = ProcessId; - clientId.UniqueThread = NULL; - - if (KphIsVerified() && (DesiredAccess & KPH_PROCESS_READ_ACCESS) == DesiredAccess) - { - status = KphOpenProcess( - ProcessHandle, - DesiredAccess, - &clientId - ); - } - else - { - InitializeObjectAttributes(&objectAttributes, NULL, 0, NULL, NULL); - status = NtOpenProcess( - ProcessHandle, - DesiredAccess, - &objectAttributes, - &clientId - ); - - if (status == STATUS_ACCESS_DENIED && KphIsVerified()) - { - status = KphOpenProcess( - ProcessHandle, - DesiredAccess, - &clientId - ); - } - } - - return status; -} - -/** Limited API for untrusted/external code. */ -NTSTATUS PhOpenProcessPublic( - _Out_ PHANDLE ProcessHandle, - _In_ ACCESS_MASK DesiredAccess, - _In_ HANDLE ProcessId - ) -{ - OBJECT_ATTRIBUTES objectAttributes; - CLIENT_ID clientId; - - InitializeObjectAttributes(&objectAttributes, NULL, 0, NULL, NULL); - clientId.UniqueProcess = ProcessId; - clientId.UniqueThread = NULL; - - return NtOpenProcess( - ProcessHandle, - DesiredAccess, - &objectAttributes, - &clientId - ); -} - -/** - * Opens a thread. - * - * \param ThreadHandle A variable which receives a handle to the thread. - * \param DesiredAccess The desired access to the thread. - * \param ThreadId The ID of the thread. - */ -NTSTATUS PhOpenThread( - _Out_ PHANDLE ThreadHandle, - _In_ ACCESS_MASK DesiredAccess, - _In_ HANDLE ThreadId - ) -{ - NTSTATUS status; - OBJECT_ATTRIBUTES objectAttributes; - CLIENT_ID clientId; - - clientId.UniqueProcess = NULL; - clientId.UniqueThread = ThreadId; - - if (KphIsVerified() && (DesiredAccess & KPH_THREAD_READ_ACCESS) == DesiredAccess) - { - status = KphOpenThread( - ThreadHandle, - DesiredAccess, - &clientId - ); - } - else - { - InitializeObjectAttributes(&objectAttributes, NULL, 0, NULL, NULL); - status = NtOpenThread( - ThreadHandle, - DesiredAccess, - &objectAttributes, - &clientId - ); - - if (status == STATUS_ACCESS_DENIED && KphIsVerified()) - { - status = KphOpenThread( - ThreadHandle, - DesiredAccess, - &clientId - ); - } - } - - return status; -} - -/** Limited API for untrusted/external code. */ -NTSTATUS PhOpenThreadPublic( - _Out_ PHANDLE ThreadHandle, - _In_ ACCESS_MASK DesiredAccess, - _In_ HANDLE ThreadId - ) -{ - OBJECT_ATTRIBUTES objectAttributes; - CLIENT_ID clientId; - - clientId.UniqueProcess = NULL; - clientId.UniqueThread = ThreadId; - - InitializeObjectAttributes(&objectAttributes, NULL, 0, NULL, NULL); - - return NtOpenThread( - ThreadHandle, - DesiredAccess, - &objectAttributes, - &clientId - ); -} - -NTSTATUS PhOpenThreadProcess( - _In_ HANDLE ThreadHandle, - _In_ ACCESS_MASK DesiredAccess, - _Out_ PHANDLE ProcessHandle - ) -{ - if (KphIsConnected()) - { - return KphOpenThreadProcess( - ThreadHandle, - DesiredAccess, - ProcessHandle - ); - } - else - { - NTSTATUS status; - THREAD_BASIC_INFORMATION basicInfo; - - if (!NT_SUCCESS(status = PhGetThreadBasicInformation( - ThreadHandle, - &basicInfo - ))) - return status; - - return PhOpenProcess( - ProcessHandle, - DesiredAccess, - basicInfo.ClientId.UniqueProcess - ); - } -} - -/** - * Opens a process token. - * - * \param ProcessHandle A handle to a process. - * \param DesiredAccess The desired access to the token. - * \param TokenHandle A variable which receives a handle to the token. - */ -NTSTATUS PhOpenProcessToken( - _In_ HANDLE ProcessHandle, - _In_ ACCESS_MASK DesiredAccess, - _Out_ PHANDLE TokenHandle - ) -{ - NTSTATUS status; - - if (KphIsVerified() && (DesiredAccess & KPH_TOKEN_READ_ACCESS) == DesiredAccess) - { - status = KphOpenProcessToken( - ProcessHandle, - DesiredAccess, - TokenHandle - ); - } - else - { - status = NtOpenProcessToken( - ProcessHandle, - DesiredAccess, - TokenHandle - ); - - if (status == STATUS_ACCESS_DENIED && KphIsVerified()) - { - status = KphOpenProcessToken( - ProcessHandle, - DesiredAccess, - TokenHandle - ); - } - } - - return status; -} - -NTSTATUS PhGetObjectSecurity( - _In_ HANDLE Handle, - _In_ SECURITY_INFORMATION SecurityInformation, - _Out_ PSECURITY_DESCRIPTOR *SecurityDescriptor - ) -{ - NTSTATUS status; - ULONG bufferSize; - PVOID buffer; - - bufferSize = 0x100; - buffer = PhAllocate(bufferSize); - // This is required (especially for File objects) because some drivers don't seem to handle - // QuerySecurity properly. - memset(buffer, 0, bufferSize); - - status = NtQuerySecurityObject( - Handle, - SecurityInformation, - buffer, - bufferSize, - &bufferSize - ); - - if (status == STATUS_BUFFER_TOO_SMALL) - { - PhFree(buffer); - buffer = PhAllocate(bufferSize); - memset(buffer, 0, bufferSize); - - status = NtQuerySecurityObject( - Handle, - SecurityInformation, - buffer, - bufferSize, - &bufferSize - ); - } - - if (!NT_SUCCESS(status)) - { - PhFree(buffer); - return status; - } - - *SecurityDescriptor = (PSECURITY_DESCRIPTOR)buffer; - - return status; -} - -NTSTATUS PhSetObjectSecurity( - _In_ HANDLE Handle, - _In_ SECURITY_INFORMATION SecurityInformation, - _In_ PSECURITY_DESCRIPTOR SecurityDescriptor - ) -{ - return NtSetSecurityObject( - Handle, - SecurityInformation, - SecurityDescriptor - ); -} - -/** - * Terminates a process. - * - * \param ProcessHandle A handle to a process. The handle must have PROCESS_TERMINATE access. - * \param ExitStatus A status value that indicates why the process is being terminated. - */ -NTSTATUS PhTerminateProcess( - _In_ HANDLE ProcessHandle, - _In_ NTSTATUS ExitStatus - ) -{ - NTSTATUS status; - - if (KphIsVerified()) - { - status = KphTerminateProcess( - ProcessHandle, - ExitStatus - ); - - if (status != STATUS_NOT_SUPPORTED) - return status; - } - - return NtTerminateProcess( - ProcessHandle, - ExitStatus - ); -} - -/** Limited API for untrusted/external code. */ -NTSTATUS PhTerminateProcessPublic( - _In_ HANDLE ProcessHandle, - _In_ NTSTATUS ExitStatus - ) -{ - return NtTerminateProcess( - ProcessHandle, - ExitStatus - ); -} - -/** - * Queries variable-sized information for a process. The function allocates a buffer to contain the - * information. - * - * \param ProcessHandle A handle to a process. The access required depends on the information class - * specified. - * \param ProcessInformationClass The information class to retrieve. - * \param Buffer A variable which receives a pointer to a buffer containing the information. You - * must free the buffer using PhFree() when you no longer need it. - */ -NTSTATUS PhpQueryProcessVariableSize( - _In_ HANDLE ProcessHandle, - _In_ PROCESSINFOCLASS ProcessInformationClass, - _Out_ PVOID *Buffer - ) -{ - NTSTATUS status; - PVOID buffer; - ULONG returnLength = 0; - - status = NtQueryInformationProcess( - ProcessHandle, - ProcessInformationClass, - NULL, - 0, - &returnLength - ); - - if (status != STATUS_BUFFER_OVERFLOW && status != STATUS_BUFFER_TOO_SMALL && status != STATUS_INFO_LENGTH_MISMATCH) - return status; - - buffer = PhAllocate(returnLength); - status = NtQueryInformationProcess( - ProcessHandle, - ProcessInformationClass, - buffer, - returnLength, - &returnLength - ); - - if (NT_SUCCESS(status)) - { - *Buffer = buffer; - } - else - { - PhFree(buffer); - } - - return status; -} - -/** - * Gets the file name of the process' image. - * - * \param ProcessHandle A handle to a process. The handle must have - * PROCESS_QUERY_LIMITED_INFORMATION access. - * \param FileName A variable which receives a pointer to a string containing the file name. You - * must free the string using PhDereferenceObject() when you no longer need it. - */ -NTSTATUS PhGetProcessImageFileName( - _In_ HANDLE ProcessHandle, - _Out_ PPH_STRING *FileName - ) -{ - NTSTATUS status; - PUNICODE_STRING fileName; - - status = PhpQueryProcessVariableSize( - ProcessHandle, - ProcessImageFileName, - &fileName - ); - - if (!NT_SUCCESS(status)) - return status; - - *FileName = PhCreateStringFromUnicodeString(fileName); - PhFree(fileName); - - return status; -} - -/** - * Gets the Win32 file name of the process' image. - * - * \param ProcessHandle A handle to a process. The handle must have - * PROCESS_QUERY_LIMITED_INFORMATION access. - * \param FileName A variable which receives a pointer to a string containing the file name. You - * must free the string using PhDereferenceObject() when you no longer need it. - * - * \remarks This function is only available on Windows Vista and above. - */ -NTSTATUS PhGetProcessImageFileNameWin32( - _In_ HANDLE ProcessHandle, - _Out_ PPH_STRING *FileName - ) -{ - NTSTATUS status; - PUNICODE_STRING fileName; - - status = PhpQueryProcessVariableSize( - ProcessHandle, - ProcessImageFileNameWin32, - &fileName - ); - - if (!NT_SUCCESS(status)) - return status; - - *FileName = PhCreateStringFromUnicodeString(fileName); - PhFree(fileName); - - return status; -} - -/** - * Gets a string stored in a process' parameters structure. - * - * \param ProcessHandle A handle to a process. The handle must have - * PROCESS_QUERY_LIMITED_INFORMATION and PROCESS_VM_READ access. - * \param Offset The string to retrieve. - * \param String A variable which receives a pointer to the requested string. You must free the - * string using PhDereferenceObject() when you no longer need it. - * - * \retval STATUS_INVALID_PARAMETER_2 An invalid value was specified in the Offset parameter. - */ -NTSTATUS PhGetProcessPebString( - _In_ HANDLE ProcessHandle, - _In_ PH_PEB_OFFSET Offset, - _Out_ PPH_STRING *String - ) -{ - NTSTATUS status; - PPH_STRING string; - ULONG offset; - -#define PEB_OFFSET_CASE(Enum, Field) \ - case Enum: offset = FIELD_OFFSET(RTL_USER_PROCESS_PARAMETERS, Field); break; \ - case Enum | PhpoWow64: offset = FIELD_OFFSET(RTL_USER_PROCESS_PARAMETERS32, Field); break - - switch (Offset) - { - PEB_OFFSET_CASE(PhpoCurrentDirectory, CurrentDirectory); - PEB_OFFSET_CASE(PhpoDllPath, DllPath); - PEB_OFFSET_CASE(PhpoImagePathName, ImagePathName); - PEB_OFFSET_CASE(PhpoCommandLine, CommandLine); - PEB_OFFSET_CASE(PhpoWindowTitle, WindowTitle); - PEB_OFFSET_CASE(PhpoDesktopInfo, DesktopInfo); - PEB_OFFSET_CASE(PhpoShellInfo, ShellInfo); - PEB_OFFSET_CASE(PhpoRuntimeData, RuntimeData); - default: - return STATUS_INVALID_PARAMETER_2; - } - - if (!(Offset & PhpoWow64)) - { - PROCESS_BASIC_INFORMATION basicInfo; - PVOID processParameters; - UNICODE_STRING unicodeString; - - // Get the PEB address. - if (!NT_SUCCESS(status = PhGetProcessBasicInformation(ProcessHandle, &basicInfo))) - return status; - - // Read the address of the process parameters. - if (!NT_SUCCESS(status = NtReadVirtualMemory( - ProcessHandle, - PTR_ADD_OFFSET(basicInfo.PebBaseAddress, FIELD_OFFSET(PEB, ProcessParameters)), - &processParameters, - sizeof(PVOID), - NULL - ))) - return status; - - // Read the string structure. - if (!NT_SUCCESS(status = NtReadVirtualMemory( - ProcessHandle, - PTR_ADD_OFFSET(processParameters, offset), - &unicodeString, - sizeof(UNICODE_STRING), - NULL - ))) - return status; - - string = PhCreateStringEx(NULL, unicodeString.Length); - - // Read the string contents. - if (!NT_SUCCESS(status = NtReadVirtualMemory( - ProcessHandle, - unicodeString.Buffer, - string->Buffer, - string->Length, - NULL - ))) - { - PhDereferenceObject(string); - return status; - } - } - else - { - PVOID peb32; - ULONG processParameters32; - UNICODE_STRING32 unicodeString32; - - if (!NT_SUCCESS(status = PhGetProcessPeb32(ProcessHandle, &peb32))) - return status; - - if (!NT_SUCCESS(status = NtReadVirtualMemory( - ProcessHandle, - PTR_ADD_OFFSET(peb32, FIELD_OFFSET(PEB32, ProcessParameters)), - &processParameters32, - sizeof(ULONG), - NULL - ))) - return status; - - if (!NT_SUCCESS(status = NtReadVirtualMemory( - ProcessHandle, - PTR_ADD_OFFSET(processParameters32, offset), - &unicodeString32, - sizeof(UNICODE_STRING32), - NULL - ))) - return status; - - string = PhCreateStringEx(NULL, unicodeString32.Length); - - // Read the string contents. - if (!NT_SUCCESS(status = NtReadVirtualMemory( - ProcessHandle, - UlongToPtr(unicodeString32.Buffer), - string->Buffer, - string->Length, - NULL - ))) - { - PhDereferenceObject(string); - return status; - } - } - - *String = string; - - return status; -} - -/** - * Gets a process' command line. - * - * \param ProcessHandle A handle to a process. The handle must have - * PROCESS_QUERY_LIMITED_INFORMATION. Before Windows 8.1, the handle must also have PROCESS_VM_READ - * access. - * \param String A variable which receives a pointer to a string containing the command line. You - * must free the string using PhDereferenceObject() when you no longer need it. - */ -NTSTATUS PhGetProcessCommandLine( - _In_ HANDLE ProcessHandle, - _Out_ PPH_STRING *CommandLine - ) -{ - NTSTATUS status; - - if (WindowsVersion >= WINDOWS_8_1) - { - PUNICODE_STRING commandLine; - - status = PhpQueryProcessVariableSize( - ProcessHandle, - ProcessCommandLineInformation, - &commandLine - ); - - if (NT_SUCCESS(status)) - { - *CommandLine = PhCreateStringFromUnicodeString(commandLine); - PhFree(commandLine); - - return status; - } - } - - return PhGetProcessPebString(ProcessHandle, PhpoCommandLine, CommandLine); -} - -/** - * Gets the window flags and window title of a process. - * - * \param ProcessHandle A handle to a process. The handle must have - * PROCESS_QUERY_LIMITED_INFORMATION. Before Windows 7 SP1, the handle must also have - * PROCESS_VM_READ access. - * \param WindowFlags A variable which receives the window flags. - * \param WindowTitle A variable which receives a pointer to the window title. You must free the - * string using PhDereferenceObject() when you no longer need it. - */ -NTSTATUS PhGetProcessWindowTitle( - _In_ HANDLE ProcessHandle, - _Out_ PULONG WindowFlags, - _Out_ PPH_STRING *WindowTitle - ) -{ - NTSTATUS status; -#ifdef _WIN64 - BOOLEAN isWow64 = FALSE; -#endif - ULONG windowFlags; - - if (WindowsVersion >= WINDOWS_7) - { - PPROCESS_WINDOW_INFORMATION windowInfo; - - status = PhpQueryProcessVariableSize( - ProcessHandle, - ProcessWindowInformation, - &windowInfo - ); - - if (NT_SUCCESS(status)) - { - *WindowFlags = windowInfo->WindowFlags; - *WindowTitle = PhCreateStringEx(windowInfo->WindowTitle, windowInfo->WindowTitleLength); - PhFree(windowInfo); - - return status; - } - } - -#ifdef _WIN64 - PhGetProcessIsWow64(ProcessHandle, &isWow64); - - if (!isWow64) -#endif - { - PROCESS_BASIC_INFORMATION basicInfo; - PVOID processParameters; - - // Get the PEB address. - if (!NT_SUCCESS(status = PhGetProcessBasicInformation(ProcessHandle, &basicInfo))) - return status; - - // Read the address of the process parameters. - if (!NT_SUCCESS(status = NtReadVirtualMemory( - ProcessHandle, - PTR_ADD_OFFSET(basicInfo.PebBaseAddress, FIELD_OFFSET(PEB, ProcessParameters)), - &processParameters, - sizeof(PVOID), - NULL - ))) - return status; - - // Read the window flags. - if (!NT_SUCCESS(status = NtReadVirtualMemory( - ProcessHandle, - PTR_ADD_OFFSET(processParameters, FIELD_OFFSET(RTL_USER_PROCESS_PARAMETERS, WindowFlags)), - &windowFlags, - sizeof(ULONG), - NULL - ))) - return status; - } -#ifdef _WIN64 - else - { - PVOID peb32; - ULONG processParameters32; - - if (!NT_SUCCESS(status = PhGetProcessPeb32(ProcessHandle, &peb32))) - return status; - - if (!NT_SUCCESS(status = NtReadVirtualMemory( - ProcessHandle, - PTR_ADD_OFFSET(peb32, FIELD_OFFSET(PEB32, ProcessParameters)), - &processParameters32, - sizeof(ULONG), - NULL - ))) - return status; - - if (!NT_SUCCESS(status = NtReadVirtualMemory( - ProcessHandle, - PTR_ADD_OFFSET(processParameters32, FIELD_OFFSET(RTL_USER_PROCESS_PARAMETERS32, WindowFlags)), - &windowFlags, - sizeof(ULONG), - NULL - ))) - return status; - } -#endif - -#ifdef _WIN64 - status = PhGetProcessPebString(ProcessHandle, PhpoWindowTitle | (isWow64 ? PhpoWow64 : 0), WindowTitle); -#else - status = PhGetProcessPebString(ProcessHandle, PhpoWindowTitle, WindowTitle); -#endif - - if (NT_SUCCESS(status)) - *WindowFlags = windowFlags; - - return status; -} - -NTSTATUS PhGetProcessDepStatus( - _In_ HANDLE ProcessHandle, - _Out_ PULONG DepStatus - ) -{ - NTSTATUS status; - ULONG executeFlags; - ULONG depStatus; - - if (!NT_SUCCESS(status = PhGetProcessExecuteFlags( - ProcessHandle, - &executeFlags - ))) - return status; - - // Check if execution of data pages is enabled. - if (executeFlags & MEM_EXECUTE_OPTION_ENABLE) - depStatus = 0; - else - depStatus = PH_PROCESS_DEP_ENABLED; - - if (executeFlags & MEM_EXECUTE_OPTION_DISABLE_THUNK_EMULATION) - depStatus |= PH_PROCESS_DEP_ATL_THUNK_EMULATION_DISABLED; - if (executeFlags & MEM_EXECUTE_OPTION_PERMANENT) - depStatus |= PH_PROCESS_DEP_PERMANENT; - - *DepStatus = depStatus; - - return status; -} - -/** - * Gets a process' environment block. - * - * \param ProcessHandle A handle to a process. The handle must have PROCESS_QUERY_INFORMATION and - * PROCESS_VM_READ access. - * \param Flags A combination of flags. - * \li \c PH_GET_PROCESS_ENVIRONMENT_WOW64 Retrieve the environment block from the WOW64 PEB. - * \param Environment A variable which will receive a pointer to the environment block copied from - * the process. You must free the block using PhFreePage() when you no longer need it. - * \param EnvironmentLength A variable which will receive the length of the environment block, in - * bytes. - */ -NTSTATUS PhGetProcessEnvironment( - _In_ HANDLE ProcessHandle, - _In_ ULONG Flags, - _Out_ PVOID *Environment, - _Out_ PULONG EnvironmentLength - ) -{ - NTSTATUS status; - PVOID environmentRemote; - MEMORY_BASIC_INFORMATION mbi; - PVOID environment; - ULONG environmentLength; - - if (!(Flags & PH_GET_PROCESS_ENVIRONMENT_WOW64)) - { - PROCESS_BASIC_INFORMATION basicInfo; - PVOID processParameters; - - status = PhGetProcessBasicInformation(ProcessHandle, &basicInfo); - - if (!NT_SUCCESS(status)) - return status; - - if (!NT_SUCCESS(status = NtReadVirtualMemory( - ProcessHandle, - PTR_ADD_OFFSET(basicInfo.PebBaseAddress, FIELD_OFFSET(PEB, ProcessParameters)), - &processParameters, - sizeof(PVOID), - NULL - ))) - return status; - - if (!NT_SUCCESS(status = NtReadVirtualMemory( - ProcessHandle, - PTR_ADD_OFFSET(processParameters, FIELD_OFFSET(RTL_USER_PROCESS_PARAMETERS, Environment)), - &environmentRemote, - sizeof(PVOID), - NULL - ))) - return status; - } - else - { - PVOID peb32; - ULONG processParameters32; - ULONG environmentRemote32; - - status = PhGetProcessPeb32(ProcessHandle, &peb32); - - if (!NT_SUCCESS(status)) - return status; - - if (!NT_SUCCESS(status = NtReadVirtualMemory( - ProcessHandle, - PTR_ADD_OFFSET(peb32, FIELD_OFFSET(PEB32, ProcessParameters)), - &processParameters32, - sizeof(ULONG), - NULL - ))) - return status; - - if (!NT_SUCCESS(status = NtReadVirtualMemory( - ProcessHandle, - PTR_ADD_OFFSET(processParameters32, FIELD_OFFSET(RTL_USER_PROCESS_PARAMETERS32, Environment)), - &environmentRemote32, - sizeof(ULONG), - NULL - ))) - return status; - - environmentRemote = UlongToPtr(environmentRemote32); - } - - if (!NT_SUCCESS(status = NtQueryVirtualMemory( - ProcessHandle, - environmentRemote, - MemoryBasicInformation, - &mbi, - sizeof(MEMORY_BASIC_INFORMATION), - NULL - ))) - return status; - - environmentLength = (ULONG)(mbi.RegionSize - - ((ULONG_PTR)environmentRemote - (ULONG_PTR)mbi.BaseAddress)); - - // Read in the entire region of memory. - - environment = PhAllocatePage(environmentLength, NULL); - - if (!environment) - return STATUS_NO_MEMORY; - - if (!NT_SUCCESS(status = NtReadVirtualMemory( - ProcessHandle, - environmentRemote, - environment, - environmentLength, - NULL - ))) - { - PhFreePage(environment); - return status; - } - - *Environment = environment; - - if (EnvironmentLength) - *EnvironmentLength = environmentLength; - - return status; -} - -BOOLEAN PhEnumProcessEnvironmentVariables( - _In_ PVOID Environment, - _In_ ULONG EnvironmentLength, - _Inout_ PULONG EnumerationKey, - _Out_ PPH_ENVIRONMENT_VARIABLE Variable - ) -{ - ULONG length; - ULONG startIndex; - PWCHAR name; - ULONG nameLength; - PWCHAR value; - ULONG valueLength; - PWCHAR currentChar; - ULONG currentIndex; - - length = EnvironmentLength / sizeof(WCHAR); - - currentIndex = *EnumerationKey; - currentChar = (PWCHAR)Environment + currentIndex; - startIndex = currentIndex; - name = currentChar; - - // Find the end of the name. - while (TRUE) - { - if (currentIndex >= length) - return FALSE; - if (*currentChar == '=') - break; - if (*currentChar == 0) - return FALSE; // no more variables - - currentIndex++; - currentChar++; - } - - nameLength = currentIndex - startIndex; - - currentIndex++; - currentChar++; - startIndex = currentIndex; - value = currentChar; - - // Find the end of the value. - while (TRUE) - { - if (currentIndex >= length) - return FALSE; - if (*currentChar == 0) - break; - - currentIndex++; - currentChar++; - } - - valueLength = currentIndex - startIndex; - - currentIndex++; - *EnumerationKey = currentIndex; - - Variable->Name.Buffer = name; - Variable->Name.Length = nameLength * sizeof(WCHAR); - Variable->Value.Buffer = value; - Variable->Value.Length = valueLength * sizeof(WCHAR); - - return TRUE; -} - -/** - * Gets the file name of a mapped section. - * - * \param ProcessHandle A handle to a process. The handle must have PROCESS_QUERY_INFORMATION - * access. - * \param BaseAddress The base address of the section view. - * \param FileName A variable which receives a pointer to a string containing the file name of the - * section. You must free the string using PhDereferenceObject() when you no longer need it. - */ -NTSTATUS PhGetProcessMappedFileName( - _In_ HANDLE ProcessHandle, - _In_ PVOID BaseAddress, - _Out_ PPH_STRING *FileName - ) -{ - NTSTATUS status; - PVOID buffer; - SIZE_T bufferSize; - SIZE_T returnLength; - PUNICODE_STRING unicodeString; - - bufferSize = 0x100; - buffer = PhAllocate(bufferSize); - - status = NtQueryVirtualMemory( - ProcessHandle, - BaseAddress, - MemoryMappedFilenameInformation, - buffer, - bufferSize, - &returnLength - ); - - if (status == STATUS_BUFFER_OVERFLOW) - { - PhFree(buffer); - bufferSize = returnLength; - buffer = PhAllocate(bufferSize); - - status = NtQueryVirtualMemory( - ProcessHandle, - BaseAddress, - MemoryMappedFilenameInformation, - buffer, - bufferSize, - &returnLength - ); - } - - if (!NT_SUCCESS(status)) - { - PhFree(buffer); - return status; - } - - unicodeString = (PUNICODE_STRING)buffer; - *FileName = PhCreateStringEx( - unicodeString->Buffer, - unicodeString->Length - ); - PhFree(buffer); - - return status; -} - -/** - * Gets working set information for a process. - * - * \param ProcessHandle A handle to a process. The handle must have PROCESS_QUERY_INFORMATION - * access. - * \param WorkingSetInformation A variable which receives a pointer to the information. You must - * free the buffer using PhFree() when you no longer need it. - */ -NTSTATUS PhGetProcessWorkingSetInformation( - _In_ HANDLE ProcessHandle, - _Out_ PMEMORY_WORKING_SET_INFORMATION *WorkingSetInformation - ) -{ - NTSTATUS status; - PVOID buffer; - SIZE_T bufferSize; - - bufferSize = 0x8000; - buffer = PhAllocate(bufferSize); - - while ((status = NtQueryVirtualMemory( - ProcessHandle, - NULL, - MemoryWorkingSetInformation, - buffer, - bufferSize, - NULL - )) == STATUS_INFO_LENGTH_MISMATCH) - { - PhFree(buffer); - bufferSize *= 2; - - // Fail if we're resizing the buffer to something very large. - if (bufferSize > PH_LARGE_BUFFER_SIZE) - return STATUS_INSUFFICIENT_RESOURCES; - - buffer = PhAllocate(bufferSize); - } - - if (!NT_SUCCESS(status)) - { - PhFree(buffer); - return status; - } - - *WorkingSetInformation = (PMEMORY_WORKING_SET_INFORMATION)buffer; - - return status; -} - -/** - * Gets working set counters for a process. - * - * \param ProcessHandle A handle to a process. The handle must have PROCESS_QUERY_INFORMATION - * access. - * \param WsCounters A variable which receives the counters. - */ -NTSTATUS PhGetProcessWsCounters( - _In_ HANDLE ProcessHandle, - _Out_ PPH_PROCESS_WS_COUNTERS WsCounters - ) -{ - NTSTATUS status; - PMEMORY_WORKING_SET_INFORMATION wsInfo; - PH_PROCESS_WS_COUNTERS wsCounters; - ULONG_PTR i; - - if (!NT_SUCCESS(status = PhGetProcessWorkingSetInformation( - ProcessHandle, - &wsInfo - ))) - return status; - - memset(&wsCounters, 0, sizeof(PH_PROCESS_WS_COUNTERS)); - - for (i = 0; i < wsInfo->NumberOfEntries; i++) - { - wsCounters.NumberOfPages++; - - if (wsInfo->WorkingSetInfo[i].ShareCount > 1) - wsCounters.NumberOfSharedPages++; - if (wsInfo->WorkingSetInfo[i].ShareCount == 0) - wsCounters.NumberOfPrivatePages++; - if (wsInfo->WorkingSetInfo[i].Shared) - wsCounters.NumberOfShareablePages++; - } - - PhFree(wsInfo); - - *WsCounters = wsCounters; - - return status; -} - -/** - * Causes a process to load a DLL. - * - * \param ProcessHandle A handle to a process. The handle must have - * PROCESS_QUERY_LIMITED_INFORMATION, PROCESS_CREATE_THREAD, PROCESS_VM_OPERATION, PROCESS_VM_READ - * and PROCESS_VM_WRITE access. - * \param FileName The file name of the DLL to inject. - * \param Timeout The timeout, in milliseconds, for the process to load the DLL. - * - * \remarks If the process does not load the DLL before the timeout expires it may crash. Choose the - * timeout value carefully. - */ -NTSTATUS PhInjectDllProcess( - _In_ HANDLE ProcessHandle, - _In_ PWSTR FileName, - _In_opt_ PLARGE_INTEGER Timeout - ) -{ -#ifdef _WIN64 - static PVOID loadLibraryW32 = NULL; -#endif - - NTSTATUS status; -#ifdef _WIN64 - BOOLEAN isWow64 = FALSE; - BOOLEAN isModule32 = FALSE; - PH_MAPPED_IMAGE mappedImage; -#endif - PVOID threadStart; - PH_STRINGREF fileName; - PVOID baseAddress = NULL; - SIZE_T allocSize; - HANDLE threadHandle; - -#ifdef _WIN64 - PhGetProcessIsWow64(ProcessHandle, &isWow64); - - if (isWow64) - { - if (!NT_SUCCESS(status = PhLoadMappedImage(FileName, NULL, TRUE, &mappedImage))) - return status; - - isModule32 = mappedImage.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC; - PhUnloadMappedImage(&mappedImage); - } - - if (!isModule32) - { -#endif - threadStart = PhGetModuleProcAddress(L"kernel32.dll", "LoadLibraryW"); -#ifdef _WIN64 - } - else - { - threadStart = loadLibraryW32; - - if (!threadStart) - { - PPH_STRING kernel32FileName; - - kernel32FileName = PhConcatStrings2(USER_SHARED_DATA->NtSystemRoot, L"\\SysWow64\\kernel32.dll"); - status = PhGetProcedureAddressRemote( - ProcessHandle, - kernel32FileName->Buffer, - "LoadLibraryW", - 0, - &loadLibraryW32, - NULL - ); - PhDereferenceObject(kernel32FileName); - - if (!NT_SUCCESS(status)) - return status; - - threadStart = loadLibraryW32; - } - } -#endif - - PhInitializeStringRefLongHint(&fileName, FileName); - allocSize = fileName.Length + sizeof(WCHAR); - - if (!NT_SUCCESS(status = NtAllocateVirtualMemory( - ProcessHandle, - &baseAddress, - 0, - &allocSize, - MEM_COMMIT, - PAGE_READWRITE - ))) - return status; - - if (!NT_SUCCESS(status = NtWriteVirtualMemory( - ProcessHandle, - baseAddress, - fileName.Buffer, - fileName.Length + sizeof(WCHAR), - NULL - ))) - goto FreeExit; - - // Vista seems to support native threads better than XP. - if (WindowsVersion >= WINDOWS_VISTA) - { - if (!NT_SUCCESS(status = RtlCreateUserThread( - ProcessHandle, - NULL, - FALSE, - 0, - 0, - 0, - (PUSER_THREAD_START_ROUTINE)threadStart, - baseAddress, - &threadHandle, - NULL - ))) - goto FreeExit; - } - else - { - if (!(threadHandle = CreateRemoteThread( - ProcessHandle, - NULL, - 0, - (PTHREAD_START_ROUTINE)threadStart, - baseAddress, - 0, - NULL - ))) - { - status = PhGetLastWin32ErrorAsNtStatus(); - goto FreeExit; - } - } - - // Wait for the thread to finish. - status = NtWaitForSingleObject(threadHandle, FALSE, Timeout); - NtClose(threadHandle); - -FreeExit: - // Size needs to be zero if we're freeing. - allocSize = 0; - NtFreeVirtualMemory( - ProcessHandle, - &baseAddress, - &allocSize, - MEM_RELEASE - ); - - return status; -} - -/** - * Causes a process to unload a DLL. - * - * \param ProcessHandle A handle to a process. The handle must have - * PROCESS_QUERY_LIMITED_INFORMATION, PROCESS_CREATE_THREAD, PROCESS_VM_OPERATION, PROCESS_VM_READ - * and PROCESS_VM_WRITE access. - * \param BaseAddress The base address of the DLL to unload. - * \param Timeout The timeout, in milliseconds, for the process to unload the DLL. - */ -NTSTATUS PhUnloadDllProcess( - _In_ HANDLE ProcessHandle, - _In_ PVOID BaseAddress, - _In_opt_ PLARGE_INTEGER Timeout - ) -{ -#ifdef _WIN64 - static PVOID ldrUnloadDll32 = NULL; -#endif - - NTSTATUS status; -#ifdef _WIN64 - BOOLEAN isWow64 = FALSE; - BOOLEAN isModule32 = FALSE; -#endif - HANDLE threadHandle; - THREAD_BASIC_INFORMATION basicInfo; - PVOID threadStart; - -#ifdef _WIN64 - PhGetProcessIsWow64(ProcessHandle, &isWow64); -#endif - - // No point trying to set the load count on Windows 8 and higher, because NT now uses a DAG of - // loader nodes. - if (WindowsVersion < WINDOWS_8) - { - status = PhSetProcessModuleLoadCount( - ProcessHandle, - BaseAddress, - 1 - ); - -#ifdef _WIN64 - if (isWow64 && status == STATUS_DLL_NOT_FOUND) - { - // The DLL might be 32-bit. - status = PhSetProcessModuleLoadCount32( - ProcessHandle, - BaseAddress, - 1 - ); - - if (NT_SUCCESS(status)) - isModule32 = TRUE; - } -#endif - - if (!NT_SUCCESS(status)) - return status; - } - -#ifdef _WIN64 - if (!isModule32) - { -#endif - threadStart = PhGetModuleProcAddress(L"ntdll.dll", "LdrUnloadDll"); -#ifdef _WIN64 - } - else - { - threadStart = ldrUnloadDll32; - - if (!threadStart) - { - PPH_STRING ntdll32FileName; - - ntdll32FileName = PhConcatStrings2(USER_SHARED_DATA->NtSystemRoot, L"\\SysWow64\\ntdll.dll"); - status = PhGetProcedureAddressRemote( - ProcessHandle, - ntdll32FileName->Buffer, - "LdrUnloadDll", - 0, - &ldrUnloadDll32, - NULL - ); - PhDereferenceObject(ntdll32FileName); - - if (!NT_SUCCESS(status)) - return status; - - threadStart = ldrUnloadDll32; - } - } -#endif - - if (WindowsVersion >= WINDOWS_VISTA) - { - status = RtlCreateUserThread( - ProcessHandle, - NULL, - FALSE, - 0, - 0, - 0, - (PUSER_THREAD_START_ROUTINE)threadStart, - BaseAddress, - &threadHandle, - NULL - ); - } - else - { - if (!(threadHandle = CreateRemoteThread( - ProcessHandle, - NULL, - 0, - (PTHREAD_START_ROUTINE)threadStart, - BaseAddress, - 0, - NULL - ))) - { - status = PhGetLastWin32ErrorAsNtStatus(); - } - } - - if (!NT_SUCCESS(status)) - return status; - - status = NtWaitForSingleObject(threadHandle, FALSE, Timeout); - - if (status == STATUS_WAIT_0) - { - status = PhGetThreadBasicInformation(threadHandle, &basicInfo); - - if (NT_SUCCESS(status)) - status = basicInfo.ExitStatus; - } - - NtClose(threadHandle); - - return status; -} - -// Contributed by dmex -/** - * Sets an environment variable in a process. - * - * \param ProcessHandle A handle to a process. The handle must have - * PROCESS_QUERY_LIMITED_INFORMATION, PROCESS_CREATE_THREAD, PROCESS_VM_OPERATION, PROCESS_VM_READ - * and PROCESS_VM_WRITE access. - * \param Name The name of the environment variable to set. - * \param Value The new value of the environment variable. If this parameter is NULL, the - * environment variable is deleted. - * \param Timeout The timeout, in milliseconds, for the process to set the environment variable. - */ -NTSTATUS PhSetEnvironmentVariableRemote( - _In_ HANDLE ProcessHandle, - _In_ PPH_STRINGREF Name, - _In_opt_ PPH_STRINGREF Value, - _In_opt_ PLARGE_INTEGER Timeout - ) -{ - NTSTATUS status; -#ifdef _WIN64 - BOOLEAN isWow64; -#endif - PPH_STRING ntdllFileName = NULL; - PPH_STRING kernel32FileName = NULL; - PVOID nameBaseAddress = NULL; - PVOID valueBaseAddress = NULL; - SIZE_T nameAllocationSize = 0; - SIZE_T valueAllocationSize = 0; - PVOID rtlExitUserThread = NULL; - PVOID setEnvironmentVariableW = NULL; - HANDLE threadHandle = NULL; - - nameAllocationSize = Name->Length + sizeof(WCHAR); - - if (Value) - valueAllocationSize = Value->Length + sizeof(WCHAR); - -#ifdef _WIN64 - if (!NT_SUCCESS(status = PhGetProcessIsWow64(ProcessHandle, &isWow64))) - goto CleanupExit; - - if (isWow64) - { - ntdllFileName = PhConcatStrings2(USER_SHARED_DATA->NtSystemRoot, L"\\SysWow64\\ntdll.dll"); - kernel32FileName = PhConcatStrings2(USER_SHARED_DATA->NtSystemRoot, L"\\SysWow64\\kernel32.dll"); - } - else - { -#endif - ntdllFileName = PhConcatStrings2(USER_SHARED_DATA->NtSystemRoot, L"\\System32\\ntdll.dll"); - kernel32FileName = PhConcatStrings2(USER_SHARED_DATA->NtSystemRoot, L"\\System32\\kernel32.dll"); -#ifdef _WIN64 - } -#endif - - if (!NT_SUCCESS(status = PhGetProcedureAddressRemote( - ProcessHandle, - ntdllFileName->Buffer, - "RtlExitUserThread", - 0, - &rtlExitUserThread, - NULL - ))) - { - goto CleanupExit; - } - if (!NT_SUCCESS(status = PhGetProcedureAddressRemote( - ProcessHandle, - kernel32FileName->Buffer, - "SetEnvironmentVariableW", - 0, - &setEnvironmentVariableW, - NULL - ))) - { - goto CleanupExit; - } - if (!NT_SUCCESS(status = NtAllocateVirtualMemory( - ProcessHandle, - &nameBaseAddress, - 0, - &nameAllocationSize, - MEM_COMMIT, - PAGE_READWRITE - ))) - { - goto CleanupExit; - } - if (!NT_SUCCESS(status = NtWriteVirtualMemory( - ProcessHandle, - nameBaseAddress, - Name->Buffer, - Name->Length, - NULL - ))) - { - goto CleanupExit; - } - - if (Value) - { - if (!NT_SUCCESS(status = NtAllocateVirtualMemory( - ProcessHandle, - &valueBaseAddress, - 0, - &valueAllocationSize, - MEM_COMMIT, - PAGE_READWRITE - ))) - { - goto CleanupExit; - } - if (!NT_SUCCESS(status = NtWriteVirtualMemory( - ProcessHandle, - valueBaseAddress, - Value->Buffer, - Value->Length, - NULL - ))) - { - goto CleanupExit; - } - } - - if (WindowsVersion >= WINDOWS_VISTA) - { - if (!NT_SUCCESS(status = RtlCreateUserThread( - ProcessHandle, - NULL, - TRUE, - 0, - 0, - 0, - (PUSER_THREAD_START_ROUTINE)rtlExitUserThread, - NULL, - &threadHandle, - NULL - ))) - { - goto CleanupExit; - } - } - else - { - if (!(threadHandle = CreateRemoteThread( - ProcessHandle, - NULL, - 0, - (PTHREAD_START_ROUTINE)rtlExitUserThread, - NULL, - CREATE_SUSPENDED, - NULL - ))) - { - status = PhGetLastWin32ErrorAsNtStatus(); - goto CleanupExit; - } - } - -#ifdef _WIN64 - if (isWow64) - { - // NtQueueApcThread doesn't work for WOW64 processes - we need to use RtlQueueApcWow64Thread - // instead. - if (!NT_SUCCESS(status = RtlQueueApcWow64Thread( - threadHandle, - setEnvironmentVariableW, - nameBaseAddress, - valueBaseAddress, - NULL - ))) - { - goto CleanupExit; - } - } - else - { -#endif - if (!NT_SUCCESS(status = NtQueueApcThread( - threadHandle, - setEnvironmentVariableW, - nameBaseAddress, - valueBaseAddress, - NULL - ))) - { - goto CleanupExit; - } -#ifdef _WIN64 - } -#endif - - // This causes our APC to be executed. - NtResumeThread(threadHandle, NULL); - status = NtWaitForSingleObject(threadHandle, FALSE, Timeout); - -CleanupExit: - if (threadHandle) - NtClose(threadHandle); - if (nameBaseAddress) - { - nameAllocationSize = 0; - NtFreeVirtualMemory( - ProcessHandle, - &nameBaseAddress, - &nameAllocationSize, - MEM_RELEASE - ); - } - if (valueBaseAddress) - { - valueAllocationSize = 0; - NtFreeVirtualMemory( - ProcessHandle, - &valueBaseAddress, - &valueAllocationSize, - MEM_RELEASE - ); - } - PhClearReference(&ntdllFileName); - PhClearReference(&kernel32FileName); - - return status; -} - -NTSTATUS PhGetJobProcessIdList( - _In_ HANDLE JobHandle, - _Out_ PJOBOBJECT_BASIC_PROCESS_ID_LIST *ProcessIdList - ) -{ - NTSTATUS status; - PVOID buffer; - ULONG bufferSize; - - bufferSize = 0x100; - buffer = PhAllocate(bufferSize); - - status = NtQueryInformationJobObject( - JobHandle, - JobObjectBasicProcessIdList, - buffer, - bufferSize, - &bufferSize - ); - - if (status == STATUS_BUFFER_OVERFLOW) - { - PhFree(buffer); - buffer = PhAllocate(bufferSize); - - status = NtQueryInformationJobObject( - JobHandle, - JobObjectBasicProcessIdList, - buffer, - bufferSize, - NULL - ); - } - - if (!NT_SUCCESS(status)) - { - PhFree(buffer); - return status; - } - - *ProcessIdList = (PJOBOBJECT_BASIC_PROCESS_ID_LIST)buffer; - - return status; -} - -/** - * Queries variable-sized information for a token. The function allocates a buffer to contain the - * information. - * - * \param TokenHandle A handle to a token. The access required depends on the information class - * specified. - * \param TokenInformationClass The information class to retrieve. - * \param Buffer A variable which receives a pointer to a buffer containing the information. You - * must free the buffer using PhFree() when you no longer need it. - */ -NTSTATUS PhpQueryTokenVariableSize( - _In_ HANDLE TokenHandle, - _In_ TOKEN_INFORMATION_CLASS TokenInformationClass, - _Out_ PVOID *Buffer - ) -{ - NTSTATUS status; - PVOID buffer; - ULONG returnLength = 0; - - NtQueryInformationToken( - TokenHandle, - TokenInformationClass, - NULL, - 0, - &returnLength - ); - buffer = PhAllocate(returnLength); - status = NtQueryInformationToken( - TokenHandle, - TokenInformationClass, - buffer, - returnLength, - &returnLength - ); - - if (NT_SUCCESS(status)) - { - *Buffer = buffer; - } - else - { - PhFree(buffer); - } - - return status; -} - -/** - * Queries variable-sized information for a token. The function allocates a buffer to contain the - * information. - * - * \param TokenHandle A handle to a token. The access required depends on the information class - * specified. - * \param TokenInformationClass The information class to retrieve. - * \param Buffer A variable which receives a pointer to a buffer containing the information. You - * must free the buffer using PhFree() when you no longer need it. - */ -NTSTATUS PhQueryTokenVariableSize( - _In_ HANDLE TokenHandle, - _In_ TOKEN_INFORMATION_CLASS TokenInformationClass, - _Out_ PVOID *Buffer - ) -{ - return PhpQueryTokenVariableSize( - TokenHandle, - TokenInformationClass, - Buffer - ); -} - -/** - * Gets a token's user. - * - * \param TokenHandle A handle to a token. The handle must have TOKEN_QUERY access. - * \param User A variable which receives a pointer to a structure containing the token's user. You - * must free the structure using PhFree() when you no longer need it. - */ -NTSTATUS PhGetTokenUser( - _In_ HANDLE TokenHandle, - _Out_ PTOKEN_USER *User - ) -{ - return PhpQueryTokenVariableSize( - TokenHandle, - TokenUser, - User - ); -} - -/** - * Gets a token's owner. - * - * \param TokenHandle A handle to a token. The handle must have TOKEN_QUERY access. - * \param Owner A variable which receives a pointer to a structure containing the token's owner. You - * must free the structure using PhFree() when you no longer need it. - */ -NTSTATUS PhGetTokenOwner( - _In_ HANDLE TokenHandle, - _Out_ PTOKEN_OWNER *Owner - ) -{ - return PhpQueryTokenVariableSize( - TokenHandle, - TokenOwner, - Owner - ); -} - -/** - * Gets a token's primary group. - * - * \param TokenHandle A handle to a token. The handle must have TOKEN_QUERY access. - * \param PrimaryGroup A variable which receives a pointer to a structure containing the token's - * primary group. You must free the structure using PhFree() when you no longer need it. - */ -NTSTATUS PhGetTokenPrimaryGroup( - _In_ HANDLE TokenHandle, - _Out_ PTOKEN_PRIMARY_GROUP *PrimaryGroup - ) -{ - return PhpQueryTokenVariableSize( - TokenHandle, - TokenPrimaryGroup, - PrimaryGroup - ); -} - -/** - * Gets a token's groups. - * - * \param TokenHandle A handle to a token. The handle must have TOKEN_QUERY access. - * \param Groups A variable which receives a pointer to a structure containing the token's groups. - * You must free the structure using PhFree() when you no longer need it. - */ -NTSTATUS PhGetTokenGroups( - _In_ HANDLE TokenHandle, - _Out_ PTOKEN_GROUPS *Groups - ) -{ - return PhpQueryTokenVariableSize( - TokenHandle, - TokenGroups, - Groups - ); -} - -/** - * Gets a token's privileges. - * - * \param TokenHandle A handle to a token. The handle must have TOKEN_QUERY access. - * \param Privileges A variable which receives a pointer to a structure containing the token's - * privileges. You must free the structure using PhFree() when you no longer need it. - */ -NTSTATUS PhGetTokenPrivileges( - _In_ HANDLE TokenHandle, - _Out_ PTOKEN_PRIVILEGES *Privileges - ) -{ - return PhpQueryTokenVariableSize( - TokenHandle, - TokenPrivileges, - Privileges - ); -} - -NTSTATUS PhSetTokenSessionId( - _In_ HANDLE TokenHandle, - _In_ ULONG SessionId - ) -{ - return NtSetInformationToken( - TokenHandle, - TokenSessionId, - &SessionId, - sizeof(ULONG) - ); -} - -/** - * Modifies a token privilege. - * - * \param TokenHandle A handle to a token. The handle must have TOKEN_ADJUST_PRIVILEGES access. - * \param PrivilegeName The name of the privilege to modify. If this parameter is NULL, you must - * specify a LUID in the \a PrivilegeLuid parameter. - * \param PrivilegeLuid The LUID of the privilege to modify. If this parameter is NULL, you must - * specify a name in the \a PrivilegeName parameter. - * \param Attributes The new attributes of the privilege. - */ -BOOLEAN PhSetTokenPrivilege( - _In_ HANDLE TokenHandle, - _In_opt_ PWSTR PrivilegeName, - _In_opt_ PLUID PrivilegeLuid, - _In_ ULONG Attributes - ) -{ - NTSTATUS status; - TOKEN_PRIVILEGES privileges; - - privileges.PrivilegeCount = 1; - privileges.Privileges[0].Attributes = Attributes; - - if (PrivilegeLuid) - { - privileges.Privileges[0].Luid = *PrivilegeLuid; - } - else if (PrivilegeName) - { - PH_STRINGREF privilegeName; - - PhInitializeStringRef(&privilegeName, PrivilegeName); - - if (!PhLookupPrivilegeValue( - &privilegeName, - &privileges.Privileges[0].Luid - )) - return FALSE; - } - else - { - return FALSE; - } - - if (!NT_SUCCESS(status = NtAdjustPrivilegesToken( - TokenHandle, - FALSE, - &privileges, - 0, - NULL, - NULL - ))) - return FALSE; - - if (status == STATUS_NOT_ALL_ASSIGNED) - return FALSE; - - return TRUE; -} - -BOOLEAN PhSetTokenPrivilege2( - _In_ HANDLE TokenHandle, - _In_ LONG Privilege, - _In_ ULONG Attributes - ) -{ - LUID privilegeLuid; - - privilegeLuid = RtlConvertLongToLuid(Privilege); - - return PhSetTokenPrivilege(TokenHandle, NULL, &privilegeLuid, Attributes); -} - -/** - * Sets whether virtualization is enabled for a token. - * - * \param TokenHandle A handle to a token. The handle must have TOKEN_WRITE access. - * \param IsVirtualizationEnabled A boolean indicating whether virtualization is to be enabled for - * the token. - */ -NTSTATUS PhSetTokenIsVirtualizationEnabled( - _In_ HANDLE TokenHandle, - _In_ BOOLEAN IsVirtualizationEnabled - ) -{ - ULONG virtualizationEnabled; - - virtualizationEnabled = IsVirtualizationEnabled; - - return NtSetInformationToken( - TokenHandle, - TokenVirtualizationEnabled, - &virtualizationEnabled, - sizeof(ULONG) - ); -} - -/** - * Gets a token's integrity level. - * - * \param TokenHandle A handle to a token. The handle must have TOKEN_QUERY access. - * \param IntegrityLevel A variable which receives the integrity level of the token. - * \param IntegrityString A variable which receives a pointer to a string containing a string - * representation of the integrity level. - */ -NTSTATUS PhGetTokenIntegrityLevel( - _In_ HANDLE TokenHandle, - _Out_opt_ PMANDATORY_LEVEL IntegrityLevel, - _Out_opt_ PWSTR *IntegrityString - ) -{ - NTSTATUS status; - PTOKEN_MANDATORY_LABEL mandatoryLabel; - ULONG subAuthority; - MANDATORY_LEVEL integrityLevel; - PWSTR integrityString; - - status = PhpQueryTokenVariableSize(TokenHandle, TokenIntegrityLevel, &mandatoryLabel); - - if (!NT_SUCCESS(status)) - return status; - - subAuthority = *RtlSubAuthoritySid(mandatoryLabel->Label.Sid, 0); - PhFree(mandatoryLabel); - - switch (subAuthority) - { - case SECURITY_MANDATORY_UNTRUSTED_RID: - integrityLevel = MandatoryLevelUntrusted; - integrityString = L"Untrusted"; - break; - case SECURITY_MANDATORY_LOW_RID: - integrityLevel = MandatoryLevelLow; - integrityString = L"Low"; - break; - case SECURITY_MANDATORY_MEDIUM_RID: - integrityLevel = MandatoryLevelMedium; - integrityString = L"Medium"; - break; - case SECURITY_MANDATORY_HIGH_RID: - integrityLevel = MandatoryLevelHigh; - integrityString = L"High"; - break; - case SECURITY_MANDATORY_SYSTEM_RID: - integrityLevel = MandatoryLevelSystem; - integrityString = L"System"; - break; - case SECURITY_MANDATORY_PROTECTED_PROCESS_RID: - integrityLevel = MandatoryLevelSecureProcess; - integrityString = L"Protected"; - break; - default: - return STATUS_UNSUCCESSFUL; - } - - if (IntegrityLevel) - *IntegrityLevel = integrityLevel; - if (IntegrityString) - *IntegrityString = integrityString; - - return status; -} - -NTSTATUS PhpQueryFileVariableSize( - _In_ HANDLE FileHandle, - _In_ FILE_INFORMATION_CLASS FileInformationClass, - _Out_ PVOID *Buffer - ) -{ - NTSTATUS status; - IO_STATUS_BLOCK isb; - PVOID buffer; - ULONG bufferSize = 0x200; - - buffer = PhAllocate(bufferSize); - - while (TRUE) - { - status = NtQueryInformationFile( - FileHandle, - &isb, - buffer, - bufferSize, - FileInformationClass - ); - - if (status == STATUS_BUFFER_OVERFLOW || status == STATUS_BUFFER_TOO_SMALL || status == STATUS_INFO_LENGTH_MISMATCH) - { - PhFree(buffer); - bufferSize *= 2; - buffer = PhAllocate(bufferSize); - } - else - { - break; - } - } - - if (NT_SUCCESS(status)) - { - *Buffer = buffer; - } - else - { - PhFree(buffer); - } - - return status; -} - -NTSTATUS PhGetFileSize( - _In_ HANDLE FileHandle, - _Out_ PLARGE_INTEGER Size - ) -{ - NTSTATUS status; - FILE_STANDARD_INFORMATION standardInfo; - IO_STATUS_BLOCK isb; - - status = NtQueryInformationFile( - FileHandle, - &isb, - &standardInfo, - sizeof(FILE_STANDARD_INFORMATION), - FileStandardInformation - ); - - if (!NT_SUCCESS(status)) - return status; - - *Size = standardInfo.EndOfFile; - - return status; -} - -NTSTATUS PhSetFileSize( - _In_ HANDLE FileHandle, - _In_ PLARGE_INTEGER Size - ) -{ - FILE_END_OF_FILE_INFORMATION endOfFileInfo; - IO_STATUS_BLOCK isb; - - endOfFileInfo.EndOfFile = *Size; - - return NtSetInformationFile( - FileHandle, - &isb, - &endOfFileInfo, - sizeof(FILE_END_OF_FILE_INFORMATION), - FileEndOfFileInformation - ); -} - -NTSTATUS PhpQueryTransactionManagerVariableSize( - _In_ HANDLE TransactionManagerHandle, - _In_ TRANSACTIONMANAGER_INFORMATION_CLASS TransactionManagerInformationClass, - _Out_ PVOID *Buffer - ) -{ - NTSTATUS status; - PVOID buffer; - ULONG bufferSize = 0x100; - - if (!NtQueryInformationTransactionManager_Import()) - return STATUS_NOT_SUPPORTED; - - buffer = PhAllocate(bufferSize); - - while (TRUE) - { - status = NtQueryInformationTransactionManager_Import()( - TransactionManagerHandle, - TransactionManagerInformationClass, - buffer, - bufferSize, - NULL - ); - - if (status == STATUS_BUFFER_OVERFLOW) - { - PhFree(buffer); - bufferSize *= 2; - - if (bufferSize > 1 * 1024 * 1024) - return STATUS_INSUFFICIENT_RESOURCES; - - buffer = PhAllocate(bufferSize); - } - else - { - break; - } - } - - if (NT_SUCCESS(status)) - { - *Buffer = buffer; - } - else - { - PhFree(buffer); - } - - return status; -} - -NTSTATUS PhGetTransactionManagerBasicInformation( - _In_ HANDLE TransactionManagerHandle, - _Out_ PTRANSACTIONMANAGER_BASIC_INFORMATION BasicInformation - ) -{ - if (NtQueryInformationTransactionManager_Import()) - { - return NtQueryInformationTransactionManager_Import()( - TransactionManagerHandle, - TransactionManagerBasicInformation, - BasicInformation, - sizeof(TRANSACTIONMANAGER_BASIC_INFORMATION), - NULL - ); - } - else - { - return STATUS_NOT_SUPPORTED; - } -} - -NTSTATUS PhGetTransactionManagerLogFileName( - _In_ HANDLE TransactionManagerHandle, - _Out_ PPH_STRING *LogFileName - ) -{ - NTSTATUS status; - PTRANSACTIONMANAGER_LOGPATH_INFORMATION logPathInfo; - - status = PhpQueryTransactionManagerVariableSize( - TransactionManagerHandle, - TransactionManagerLogPathInformation, - &logPathInfo - ); - - if (!NT_SUCCESS(status)) - return status; - - *LogFileName = PhCreateStringEx( - logPathInfo->LogPath, - logPathInfo->LogPathLength - ); - PhFree(logPathInfo); - - return status; -} - -NTSTATUS PhpQueryTransactionVariableSize( - _In_ HANDLE TransactionHandle, - _In_ TRANSACTION_INFORMATION_CLASS TransactionInformationClass, - _Out_ PVOID *Buffer - ) -{ - NTSTATUS status; - PVOID buffer; - ULONG bufferSize = 0x100; - - if (!NtQueryInformationTransaction_Import()) - return STATUS_NOT_SUPPORTED; - - buffer = PhAllocate(bufferSize); - - while (TRUE) - { - status = NtQueryInformationTransaction_Import()( - TransactionHandle, - TransactionInformationClass, - buffer, - bufferSize, - NULL - ); - - if (status == STATUS_BUFFER_OVERFLOW) - { - PhFree(buffer); - bufferSize *= 2; - - if (bufferSize > 1 * 1024 * 1024) - return STATUS_INSUFFICIENT_RESOURCES; - - buffer = PhAllocate(bufferSize); - } - else - { - break; - } - } - - if (NT_SUCCESS(status)) - { - *Buffer = buffer; - } - else - { - PhFree(buffer); - } - - return status; -} - -NTSTATUS PhGetTransactionBasicInformation( - _In_ HANDLE TransactionHandle, - _Out_ PTRANSACTION_BASIC_INFORMATION BasicInformation - ) -{ - if (NtQueryInformationTransaction_Import()) - { - return NtQueryInformationTransaction_Import()( - TransactionHandle, - TransactionBasicInformation, - BasicInformation, - sizeof(TRANSACTION_BASIC_INFORMATION), - NULL - ); - } - else - { - return STATUS_NOT_SUPPORTED; - } -} - -NTSTATUS PhGetTransactionPropertiesInformation( - _In_ HANDLE TransactionHandle, - _Out_opt_ PLARGE_INTEGER Timeout, - _Out_opt_ TRANSACTION_OUTCOME *Outcome, - _Out_opt_ PPH_STRING *Description - ) -{ - NTSTATUS status; - PTRANSACTION_PROPERTIES_INFORMATION propertiesInfo; - - status = PhpQueryTransactionVariableSize( - TransactionHandle, - TransactionPropertiesInformation, - &propertiesInfo - ); - - if (!NT_SUCCESS(status)) - return status; - - if (Timeout) - { - *Timeout = propertiesInfo->Timeout; - } - - if (Outcome) - { - *Outcome = propertiesInfo->Outcome; - } - - if (Description) - { - *Description = PhCreateStringEx( - propertiesInfo->Description, - propertiesInfo->DescriptionLength - ); - } - - PhFree(propertiesInfo); - - return status; -} - -NTSTATUS PhpQueryResourceManagerVariableSize( - _In_ HANDLE ResourceManagerHandle, - _In_ RESOURCEMANAGER_INFORMATION_CLASS ResourceManagerInformationClass, - _Out_ PVOID *Buffer - ) -{ - NTSTATUS status; - PVOID buffer; - ULONG bufferSize = 0x100; - - if (!NtQueryInformationResourceManager_Import()) - return STATUS_NOT_SUPPORTED; - - buffer = PhAllocate(bufferSize); - - while (TRUE) - { - status = NtQueryInformationResourceManager_Import()( - ResourceManagerHandle, - ResourceManagerInformationClass, - buffer, - bufferSize, - NULL - ); - - if (status == STATUS_BUFFER_OVERFLOW) - { - PhFree(buffer); - bufferSize *= 2; - - if (bufferSize > 1 * 1024 * 1024) - return STATUS_INSUFFICIENT_RESOURCES; - - buffer = PhAllocate(bufferSize); - } - else - { - break; - } - } - - if (NT_SUCCESS(status)) - { - *Buffer = buffer; - } - else - { - PhFree(buffer); - } - - return status; -} - -NTSTATUS PhGetResourceManagerBasicInformation( - _In_ HANDLE ResourceManagerHandle, - _Out_opt_ PGUID Guid, - _Out_opt_ PPH_STRING *Description - ) -{ - NTSTATUS status; - PRESOURCEMANAGER_BASIC_INFORMATION basicInfo; - - status = PhpQueryResourceManagerVariableSize( - ResourceManagerHandle, - ResourceManagerBasicInformation, - &basicInfo - ); - - if (!NT_SUCCESS(status)) - return status; - - if (Guid) - { - *Guid = basicInfo->ResourceManagerId; - } - - if (Description) - { - *Description = PhCreateStringEx( - basicInfo->Description, - basicInfo->DescriptionLength - ); - } - - PhFree(basicInfo); - - return status; -} - -NTSTATUS PhGetEnlistmentBasicInformation( - _In_ HANDLE EnlistmentHandle, - _Out_ PENLISTMENT_BASIC_INFORMATION BasicInformation - ) -{ - if (NtQueryInformationEnlistment_Import()) - { - return NtQueryInformationEnlistment_Import()( - EnlistmentHandle, - EnlistmentBasicInformation, - BasicInformation, - sizeof(ENLISTMENT_BASIC_INFORMATION), - NULL - ); - } - else - { - return STATUS_NOT_SUPPORTED; - } -} - -typedef struct _OPEN_DRIVER_BY_BASE_ADDRESS_CONTEXT -{ - NTSTATUS Status; - PVOID BaseAddress; - HANDLE DriverHandle; -} OPEN_DRIVER_BY_BASE_ADDRESS_CONTEXT, *POPEN_DRIVER_BY_BASE_ADDRESS_CONTEXT; - -BOOLEAN NTAPI PhpOpenDriverByBaseAddressCallback( - _In_ PPH_STRINGREF Name, - _In_ PPH_STRINGREF TypeName, - _In_opt_ PVOID Context - ) -{ - static PH_STRINGREF driverDirectoryName = PH_STRINGREF_INIT(L"\\Driver\\"); - - NTSTATUS status; - POPEN_DRIVER_BY_BASE_ADDRESS_CONTEXT context = Context; - PPH_STRING driverName; - UNICODE_STRING driverNameUs; - OBJECT_ATTRIBUTES objectAttributes; - HANDLE driverHandle; - DRIVER_BASIC_INFORMATION basicInfo; - - driverName = PhConcatStringRef2(&driverDirectoryName, Name); - - if (!PhStringRefToUnicodeString(&driverName->sr, &driverNameUs)) - { - PhDereferenceObject(driverName); - return TRUE; - } - - InitializeObjectAttributes( - &objectAttributes, - &driverNameUs, - 0, - NULL, - NULL - ); - - status = KphOpenDriver(&driverHandle, SYNCHRONIZE, &objectAttributes); - PhDereferenceObject(driverName); - - if (!NT_SUCCESS(status)) - return TRUE; - - status = KphQueryInformationDriver( - driverHandle, - DriverBasicInformation, - &basicInfo, - sizeof(DRIVER_BASIC_INFORMATION), - NULL - ); - - if (NT_SUCCESS(status)) - { - if (basicInfo.DriverStart == context->BaseAddress) - { - context->Status = STATUS_SUCCESS; - context->DriverHandle = driverHandle; - - return FALSE; - } - } - - NtClose(driverHandle); - - return TRUE; -} - -/** - * Opens a driver object using a base address. - * - * \param DriverHandle A variable which receives a handle to the driver object. - * \param BaseAddress The base address of the driver to open. - * - * \retval STATUS_OBJECT_NAME_NOT_FOUND The driver could not be found. - * - * \remarks This function requires a valid KProcessHacker handle. - */ -NTSTATUS PhOpenDriverByBaseAddress( - _Out_ PHANDLE DriverHandle, - _In_ PVOID BaseAddress - ) -{ - NTSTATUS status; - UNICODE_STRING driverDirectoryName; - OBJECT_ATTRIBUTES objectAttributes; - HANDLE driverDirectoryHandle; - OPEN_DRIVER_BY_BASE_ADDRESS_CONTEXT context; - - RtlInitUnicodeString( - &driverDirectoryName, - L"\\Driver" - ); - InitializeObjectAttributes( - &objectAttributes, - &driverDirectoryName, - 0, - NULL, - NULL - ); - - if (!NT_SUCCESS(status = NtOpenDirectoryObject( - &driverDirectoryHandle, - DIRECTORY_QUERY, - &objectAttributes - ))) - return status; - - context.Status = STATUS_OBJECT_NAME_NOT_FOUND; - context.BaseAddress = BaseAddress; - - status = PhEnumDirectoryObjects( - driverDirectoryHandle, - PhpOpenDriverByBaseAddressCallback, - &context - ); - NtClose(driverDirectoryHandle); - - if (!NT_SUCCESS(status) && !NT_SUCCESS(context.Status)) - return status; - - if (NT_SUCCESS(context.Status)) - { - *DriverHandle = context.DriverHandle; - } - - return context.Status; -} - -/** - * Queries variable-sized information for a driver. The function allocates a buffer to contain the - * information. - * - * \param DriverHandle A handle to a driver. The access required depends on the information class - * specified. - * \param DriverInformationClass The information class to retrieve. - * \param Buffer A variable which receives a pointer to a buffer containing the information. You - * must free the buffer using PhFree() when you no longer need it. - * - * \remarks This function requires a valid KProcessHacker handle. - */ -NTSTATUS PhpQueryDriverVariableSize( - _In_ HANDLE DriverHandle, - _In_ DRIVER_INFORMATION_CLASS DriverInformationClass, - _Out_ PVOID *Buffer - ) -{ - NTSTATUS status; - PVOID buffer; - ULONG returnLength = 0; - - KphQueryInformationDriver( - DriverHandle, - DriverInformationClass, - NULL, - 0, - &returnLength - ); - buffer = PhAllocate(returnLength); - status = KphQueryInformationDriver( - DriverHandle, - DriverInformationClass, - buffer, - returnLength, - &returnLength - ); - - if (NT_SUCCESS(status)) - { - *Buffer = buffer; - } - else - { - PhFree(buffer); - } - - return status; -} - -/** - * Gets the object name of a driver. - * - * \param DriverHandle A handle to a driver. - * \param Name A variable which receives a pointer to a string containing the object name. You must - * free the string using PhDereferenceObject() when you no longer need it. - * - * \remarks This function requires a valid KProcessHacker handle. - */ -NTSTATUS PhGetDriverName( - _In_ HANDLE DriverHandle, - _Out_ PPH_STRING *Name - ) -{ - NTSTATUS status; - PUNICODE_STRING unicodeString; - - if (!NT_SUCCESS(status = PhpQueryDriverVariableSize( - DriverHandle, - DriverNameInformation, - &unicodeString - ))) - return status; - - *Name = PhCreateStringEx( - unicodeString->Buffer, - unicodeString->Length - ); - PhFree(unicodeString); - - return status; -} - -/** - * Gets the service key name of a driver. - * - * \param DriverHandle A handle to a driver. - * \param ServiceKeyName A variable which receives a pointer to a string containing the service key - * name. You must free the string using PhDereferenceObject() when you no longer need it. - * - * \remarks This function requires a valid KProcessHacker handle. - */ -NTSTATUS PhGetDriverServiceKeyName( - _In_ HANDLE DriverHandle, - _Out_ PPH_STRING *ServiceKeyName - ) -{ - NTSTATUS status; - PUNICODE_STRING unicodeString; - - if (!NT_SUCCESS(status = PhpQueryDriverVariableSize( - DriverHandle, - DriverServiceKeyNameInformation, - &unicodeString - ))) - return status; - - *ServiceKeyName = PhCreateStringEx( - unicodeString->Buffer, - unicodeString->Length - ); - PhFree(unicodeString); - - return status; -} - -NTSTATUS PhpUnloadDriver( - _In_ PPH_STRING ServiceKeyName - ) -{ - static PH_STRINGREF fullServicesKeyName = PH_STRINGREF_INIT(L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\"); - - NTSTATUS status; - PPH_STRING fullServiceKeyName; - UNICODE_STRING fullServiceKeyNameUs; - HANDLE serviceKeyHandle; - ULONG disposition; - - fullServiceKeyName = PhConcatStringRef2(&fullServicesKeyName, &ServiceKeyName->sr); - - if (!PhStringRefToUnicodeString(&fullServiceKeyName->sr, &fullServiceKeyNameUs)) - { - PhDereferenceObject(fullServiceKeyName); - return STATUS_NAME_TOO_LONG; - } - - if (NT_SUCCESS(status = PhCreateKey( - &serviceKeyHandle, - KEY_WRITE | DELETE, - NULL, - &fullServiceKeyName->sr, - 0, - 0, - &disposition - ))) - { - if (disposition == REG_CREATED_NEW_KEY) - { - static UNICODE_STRING imagePath = RTL_CONSTANT_STRING(L"\\SystemRoot\\system32\\drivers\\ntfs.sys"); - - UNICODE_STRING valueName; - ULONG dword; - - // Set up the required values. - dword = 1; - RtlInitUnicodeString(&valueName, L"ErrorControl"); - NtSetValueKey(serviceKeyHandle, &valueName, 0, REG_DWORD, &dword, sizeof(ULONG)); - RtlInitUnicodeString(&valueName, L"Start"); - NtSetValueKey(serviceKeyHandle, &valueName, 0, REG_DWORD, &dword, sizeof(ULONG)); - RtlInitUnicodeString(&valueName, L"Type"); - NtSetValueKey(serviceKeyHandle, &valueName, 0, REG_DWORD, &dword, sizeof(ULONG)); - - // Use a bogus name. - RtlInitUnicodeString(&valueName, L"ImagePath"); - NtSetValueKey(serviceKeyHandle, &valueName, 0, REG_SZ, imagePath.Buffer, imagePath.Length + 2); - } - - status = NtUnloadDriver(&fullServiceKeyNameUs); - - if (disposition == REG_CREATED_NEW_KEY) - { - // We added values, not subkeys, so this function will work correctly. - NtDeleteKey(serviceKeyHandle); - } - - NtClose(serviceKeyHandle); - } - - PhDereferenceObject(fullServiceKeyName); - - return status; -} - -/** - * Unloads a driver. - * - * \param BaseAddress The base address of the driver. This parameter can be NULL if a value is - * specified in \c Name. - * \param Name The base name of the driver. This parameter can be NULL if a value is specified in - * \c BaseAddress and KProcessHacker is loaded. - * - * \retval STATUS_INVALID_PARAMETER_MIX Both \c BaseAddress and \c Name were null, or \c Name was - * not specified and KProcessHacker is not loaded. - * \retval STATUS_OBJECT_NAME_NOT_FOUND The driver could not be found. - */ -NTSTATUS PhUnloadDriver( - _In_opt_ PVOID BaseAddress, - _In_opt_ PWSTR Name - ) -{ - NTSTATUS status; - HANDLE driverHandle; - PPH_STRING serviceKeyName = NULL; - - if (!BaseAddress && !Name) - return STATUS_INVALID_PARAMETER_MIX; - if (!Name && !KphIsConnected()) - return STATUS_INVALID_PARAMETER_MIX; - - // Try to get the service key name by scanning the Driver directory. - - if (KphIsConnected() && BaseAddress) - { - if (NT_SUCCESS(PhOpenDriverByBaseAddress( - &driverHandle, - BaseAddress - ))) - { - PhGetDriverServiceKeyName(driverHandle, &serviceKeyName); - NtClose(driverHandle); - } - } - - // Use the base name if we didn't get the service key name. - - if (!serviceKeyName && Name) - { - PPH_STRING name; - - name = PhCreateString(Name); - - // Remove the extension if it is present. - if (PhEndsWithString2(name, L".sys", TRUE)) - { - serviceKeyName = PhSubstring(name, 0, name->Length / 2 - 4); - PhDereferenceObject(name); - } - else - { - serviceKeyName = name; - } - } - - if (!serviceKeyName) - return STATUS_OBJECT_NAME_NOT_FOUND; - - status = PhpUnloadDriver(serviceKeyName); - PhDereferenceObject(serviceKeyName); - - return status; -} - -NTSTATUS PhpEnumProcessModules( - _In_ HANDLE ProcessHandle, - _In_ PPHP_ENUM_PROCESS_MODULES_CALLBACK Callback, - _In_opt_ PVOID Context1, - _In_opt_ PVOID Context2 - ) -{ - NTSTATUS status; - PROCESS_BASIC_INFORMATION basicInfo; - PPEB_LDR_DATA ldr; - PEB_LDR_DATA pebLdrData; - PLIST_ENTRY startLink; - PLIST_ENTRY currentLink; - ULONG dataTableEntrySize; - LDR_DATA_TABLE_ENTRY currentEntry; - ULONG i; - - // Get the PEB address. - status = PhGetProcessBasicInformation(ProcessHandle, &basicInfo); - - if (!NT_SUCCESS(status)) - return status; - - // Read the address of the loader data. - status = NtReadVirtualMemory( - ProcessHandle, - PTR_ADD_OFFSET(basicInfo.PebBaseAddress, FIELD_OFFSET(PEB, Ldr)), - &ldr, - sizeof(PVOID), - NULL - ); - - if (!NT_SUCCESS(status)) - return status; - - // Read the loader data. - status = NtReadVirtualMemory( - ProcessHandle, - ldr, - &pebLdrData, - sizeof(PEB_LDR_DATA), - NULL - ); - - if (!NT_SUCCESS(status)) - return status; - - if (!pebLdrData.Initialized) - return STATUS_UNSUCCESSFUL; - - if (WindowsVersion >= WINDOWS_8) - dataTableEntrySize = LDR_DATA_TABLE_ENTRY_SIZE_WIN8; - else if (WindowsVersion >= WINDOWS_7) - dataTableEntrySize = LDR_DATA_TABLE_ENTRY_SIZE_WIN7; - else - dataTableEntrySize = LDR_DATA_TABLE_ENTRY_SIZE_WINXP; - - // Traverse the linked list (in load order). - - i = 0; - startLink = PTR_ADD_OFFSET(ldr, FIELD_OFFSET(PEB_LDR_DATA, InLoadOrderModuleList)); - currentLink = pebLdrData.InLoadOrderModuleList.Flink; - - while ( - currentLink != startLink && - i <= PH_ENUM_PROCESS_MODULES_LIMIT - ) - { - PVOID addressOfEntry; - - addressOfEntry = CONTAINING_RECORD(currentLink, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks); - status = NtReadVirtualMemory( - ProcessHandle, - addressOfEntry, - ¤tEntry, - dataTableEntrySize, - NULL - ); - - if (!NT_SUCCESS(status)) - return status; - - // Make sure the entry is valid. - if (currentEntry.DllBase) - { - // Execute the callback. - if (!Callback( - ProcessHandle, - ¤tEntry, - addressOfEntry, - Context1, - Context2 - )) - break; - } - - currentLink = currentEntry.InLoadOrderLinks.Flink; - i++; - } - - return status; -} - -BOOLEAN NTAPI PhpEnumProcessModulesCallback( - _In_ HANDLE ProcessHandle, - _In_ PLDR_DATA_TABLE_ENTRY Entry, - _In_ PVOID AddressOfEntry, - _In_opt_ PVOID Context1, - _In_opt_ PVOID Context2 - ) -{ - NTSTATUS status; - PPH_ENUM_PROCESS_MODULES_PARAMETERS parameters; - BOOLEAN cont; - PPH_STRING mappedFileName; - PWSTR fullDllNameOriginal; - PWSTR fullDllNameBuffer; - PWSTR baseDllNameOriginal; - PWSTR baseDllNameBuffer; - - parameters = Context1; - mappedFileName = NULL; - - if (parameters->Flags & PH_ENUM_PROCESS_MODULES_TRY_MAPPED_FILE_NAME) - { - PhGetProcessMappedFileName(ProcessHandle, Entry->DllBase, &mappedFileName); - } - - if (mappedFileName) - { - ULONG_PTR indexOfLastBackslash; - - PhStringRefToUnicodeString(&mappedFileName->sr, &Entry->FullDllName); - indexOfLastBackslash = PhFindLastCharInString(mappedFileName, 0, '\\'); - - if (indexOfLastBackslash != -1) - { - Entry->BaseDllName.Buffer = Entry->FullDllName.Buffer + indexOfLastBackslash + 1; - Entry->BaseDllName.Length = Entry->FullDllName.Length - (USHORT)indexOfLastBackslash * 2 - 2; - Entry->BaseDllName.MaximumLength = Entry->BaseDllName.Length; - } - else - { - Entry->BaseDllName = Entry->FullDllName; - } - } - else - { - // Read the full DLL name string and add a null terminator. - - fullDllNameOriginal = Entry->FullDllName.Buffer; - fullDllNameBuffer = PhAllocate(Entry->FullDllName.Length + 2); - Entry->FullDllName.Buffer = fullDllNameBuffer; - - if (NT_SUCCESS(status = NtReadVirtualMemory( - ProcessHandle, - fullDllNameOriginal, - fullDllNameBuffer, - Entry->FullDllName.Length, - NULL - ))) - { - fullDllNameBuffer[Entry->FullDllName.Length / 2] = 0; - } - else - { - fullDllNameBuffer[0] = 0; - Entry->FullDllName.Length = 0; - } - - baseDllNameOriginal = Entry->BaseDllName.Buffer; - - // Try to use the buffer we just read in. - if ( - NT_SUCCESS(status) && - (ULONG_PTR)baseDllNameOriginal >= (ULONG_PTR)fullDllNameOriginal && - (ULONG_PTR)baseDllNameOriginal + Entry->BaseDllName.Length >= (ULONG_PTR)baseDllNameOriginal && - (ULONG_PTR)baseDllNameOriginal + Entry->BaseDllName.Length <= (ULONG_PTR)fullDllNameOriginal + Entry->FullDllName.Length - ) - { - baseDllNameBuffer = NULL; - - Entry->BaseDllName.Buffer = (PWCHAR)((ULONG_PTR)Entry->FullDllName.Buffer + - ((ULONG_PTR)baseDllNameOriginal - (ULONG_PTR)fullDllNameOriginal)); - } - else - { - // Read the base DLL name string and add a null terminator. - - baseDllNameBuffer = PhAllocate(Entry->BaseDllName.Length + 2); - Entry->BaseDllName.Buffer = baseDllNameBuffer; - - if (NT_SUCCESS(NtReadVirtualMemory( - ProcessHandle, - baseDllNameOriginal, - baseDllNameBuffer, - Entry->BaseDllName.Length, - NULL - ))) - { - baseDllNameBuffer[Entry->BaseDllName.Length / 2] = 0; - } - else - { - baseDllNameBuffer[0] = 0; - Entry->BaseDllName.Length = 0; - } - } - } - - // Execute the callback. - cont = parameters->Callback(Entry, parameters->Context); - - if (mappedFileName) - { - PhDereferenceObject(mappedFileName); - } - else - { - PhFree(fullDllNameBuffer); - - if (baseDllNameBuffer) - PhFree(baseDllNameBuffer); - } - - return cont; -} - -/** - * Enumerates the modules loaded by a process. - * - * \param ProcessHandle A handle to a process. The handle must have - * PROCESS_QUERY_LIMITED_INFORMATION and PROCESS_VM_READ access. - * \param Callback A callback function which is executed for each process module. - * \param Context A user-defined value to pass to the callback function. - */ -NTSTATUS PhEnumProcessModules( - _In_ HANDLE ProcessHandle, - _In_ PPH_ENUM_PROCESS_MODULES_CALLBACK Callback, - _In_opt_ PVOID Context - ) -{ - PH_ENUM_PROCESS_MODULES_PARAMETERS parameters; - - parameters.Callback = Callback; - parameters.Context = Context; - parameters.Flags = 0; - - return PhEnumProcessModulesEx(ProcessHandle, ¶meters); -} - -/** - * Enumerates the modules loaded by a process. - * - * \param ProcessHandle A handle to a process. The handle must have - * PROCESS_QUERY_LIMITED_INFORMATION and PROCESS_VM_READ access. If - * \c PH_ENUM_PROCESS_MODULES_TRY_MAPPED_FILE_NAME is specified in \a Parameters, the handle should - * have PROCESS_QUERY_INFORMATION access. - * \param Parameters The enumeration parameters. - */ -NTSTATUS PhEnumProcessModulesEx( - _In_ HANDLE ProcessHandle, - _In_ PPH_ENUM_PROCESS_MODULES_PARAMETERS Parameters - ) -{ - return PhpEnumProcessModules( - ProcessHandle, - PhpEnumProcessModulesCallback, - Parameters, - NULL - ); -} - -typedef struct _SET_PROCESS_MODULE_LOAD_COUNT_CONTEXT -{ - NTSTATUS Status; - PVOID BaseAddress; - ULONG LoadCount; -} SET_PROCESS_MODULE_LOAD_COUNT_CONTEXT, *PSET_PROCESS_MODULE_LOAD_COUNT_CONTEXT; - -BOOLEAN NTAPI PhpSetProcessModuleLoadCountCallback( - _In_ HANDLE ProcessHandle, - _In_ PLDR_DATA_TABLE_ENTRY Entry, - _In_ PVOID AddressOfEntry, - _In_opt_ PVOID Context1, - _In_opt_ PVOID Context2 - ) -{ - PSET_PROCESS_MODULE_LOAD_COUNT_CONTEXT context = Context1; - - if (Entry->DllBase == context->BaseAddress) - { - context->Status = NtWriteVirtualMemory( - ProcessHandle, - PTR_ADD_OFFSET(AddressOfEntry, FIELD_OFFSET(LDR_DATA_TABLE_ENTRY, ObsoleteLoadCount)), - &context->LoadCount, - sizeof(USHORT), - NULL - ); - - return FALSE; - } - - return TRUE; -} - -/** - * Sets the load count of a process module. - * - * \param ProcessHandle A handle to a process. The handle must have - * PROCESS_QUERY_LIMITED_INFORMATION, PROCESS_VM_READ and PROCESS_VM_WRITE access. - * \param BaseAddress The base address of a module. - * \param LoadCount The new load count of the module. - * - * \retval STATUS_DLL_NOT_FOUND The module was not found. - */ -NTSTATUS PhSetProcessModuleLoadCount( - _In_ HANDLE ProcessHandle, - _In_ PVOID BaseAddress, - _In_ ULONG LoadCount - ) -{ - NTSTATUS status; - SET_PROCESS_MODULE_LOAD_COUNT_CONTEXT context; - - context.Status = STATUS_DLL_NOT_FOUND; - context.BaseAddress = BaseAddress; - context.LoadCount = LoadCount; - - status = PhpEnumProcessModules( - ProcessHandle, - PhpSetProcessModuleLoadCountCallback, - &context, - NULL - ); - - if (!NT_SUCCESS(status)) - return status; - - return context.Status; -} - -NTSTATUS PhpEnumProcessModules32( - _In_ HANDLE ProcessHandle, - _In_ PPHP_ENUM_PROCESS_MODULES32_CALLBACK Callback, - _In_opt_ PVOID Context1, - _In_opt_ PVOID Context2 - ) -{ - NTSTATUS status; - PPEB32 peb; - ULONG ldr; // PEB_LDR_DATA32 *32 - PEB_LDR_DATA32 pebLdrData; - ULONG startLink; // LIST_ENTRY32 *32 - ULONG currentLink; // LIST_ENTRY32 *32 - ULONG dataTableEntrySize; - LDR_DATA_TABLE_ENTRY32 currentEntry; - ULONG i; - - // Get the 32-bit PEB address. - status = PhGetProcessPeb32(ProcessHandle, &peb); - - if (!NT_SUCCESS(status)) - return status; - - if (!peb) - return STATUS_NOT_SUPPORTED; // not a WOW64 process - - // Read the address of the loader data. - status = NtReadVirtualMemory( - ProcessHandle, - PTR_ADD_OFFSET(peb, FIELD_OFFSET(PEB32, Ldr)), - &ldr, - sizeof(ULONG), - NULL - ); - - if (!NT_SUCCESS(status)) - return status; - - // Read the loader data. - status = NtReadVirtualMemory( - ProcessHandle, - UlongToPtr(ldr), - &pebLdrData, - sizeof(PEB_LDR_DATA32), - NULL - ); - - if (!NT_SUCCESS(status)) - return status; - - if (!pebLdrData.Initialized) - return STATUS_UNSUCCESSFUL; - - if (WindowsVersion >= WINDOWS_8) - dataTableEntrySize = LDR_DATA_TABLE_ENTRY_SIZE_WIN8_32; - else if (WindowsVersion >= WINDOWS_7) - dataTableEntrySize = LDR_DATA_TABLE_ENTRY_SIZE_WIN7_32; - else - dataTableEntrySize = LDR_DATA_TABLE_ENTRY_SIZE_WINXP_32; - - // Traverse the linked list (in load order). - - i = 0; - startLink = (ULONG)(ldr + FIELD_OFFSET(PEB_LDR_DATA32, InLoadOrderModuleList)); - currentLink = pebLdrData.InLoadOrderModuleList.Flink; - - while ( - currentLink != startLink && - i <= PH_ENUM_PROCESS_MODULES_LIMIT - ) - { - ULONG addressOfEntry; - - addressOfEntry = PtrToUlong(CONTAINING_RECORD(UlongToPtr(currentLink), LDR_DATA_TABLE_ENTRY32, InLoadOrderLinks)); - status = NtReadVirtualMemory( - ProcessHandle, - UlongToPtr(addressOfEntry), - ¤tEntry, - dataTableEntrySize, - NULL - ); - - if (!NT_SUCCESS(status)) - return status; - - // Make sure the entry is valid. - if (currentEntry.DllBase) - { - // Execute the callback. - if (!Callback( - ProcessHandle, - ¤tEntry, - addressOfEntry, - Context1, - Context2 - )) - break; - } - - currentLink = currentEntry.InLoadOrderLinks.Flink; - i++; - } - - return status; -} - -BOOLEAN NTAPI PhpEnumProcessModules32Callback( - _In_ HANDLE ProcessHandle, - _In_ PLDR_DATA_TABLE_ENTRY32 Entry, - _In_ ULONG AddressOfEntry, - _In_opt_ PVOID Context1, - _In_opt_ PVOID Context2 - ) -{ - static PH_STRINGREF system32String = PH_STRINGREF_INIT(L"\\system32\\"); - - PPH_ENUM_PROCESS_MODULES_PARAMETERS parameters; - BOOLEAN cont; - LDR_DATA_TABLE_ENTRY nativeEntry; - PPH_STRING mappedFileName; - PWSTR baseDllNameBuffer; - PWSTR fullDllNameBuffer; - PH_STRINGREF fullDllName; - PH_STRINGREF systemRootString; - - parameters = Context1; - - // Convert the 32-bit entry to a native-sized entry. - - memset(&nativeEntry, 0, sizeof(LDR_DATA_TABLE_ENTRY)); - nativeEntry.DllBase = UlongToPtr(Entry->DllBase); - nativeEntry.EntryPoint = UlongToPtr(Entry->EntryPoint); - nativeEntry.SizeOfImage = Entry->SizeOfImage; - UStr32ToUStr(&nativeEntry.FullDllName, &Entry->FullDllName); - UStr32ToUStr(&nativeEntry.BaseDllName, &Entry->BaseDllName); - nativeEntry.Flags = Entry->Flags; - nativeEntry.ObsoleteLoadCount = Entry->ObsoleteLoadCount; - nativeEntry.TlsIndex = Entry->TlsIndex; - nativeEntry.TimeDateStamp = Entry->TimeDateStamp; - nativeEntry.OriginalBase = Entry->OriginalBase; - nativeEntry.LoadTime = Entry->LoadTime; - nativeEntry.BaseNameHashValue = Entry->BaseNameHashValue; - nativeEntry.LoadReason = Entry->LoadReason; - - mappedFileName = NULL; - - if (parameters->Flags & PH_ENUM_PROCESS_MODULES_TRY_MAPPED_FILE_NAME) - { - PhGetProcessMappedFileName(ProcessHandle, nativeEntry.DllBase, &mappedFileName); - } - - if (mappedFileName) - { - ULONG_PTR indexOfLastBackslash; - - PhStringRefToUnicodeString(&mappedFileName->sr, &nativeEntry.FullDllName); - indexOfLastBackslash = PhFindLastCharInString(mappedFileName, 0, '\\'); - - if (indexOfLastBackslash != -1) - { - nativeEntry.BaseDllName.Buffer = nativeEntry.FullDllName.Buffer + indexOfLastBackslash + 1; - nativeEntry.BaseDllName.Length = nativeEntry.FullDllName.Length - (USHORT)indexOfLastBackslash * 2 - 2; - nativeEntry.BaseDllName.MaximumLength = nativeEntry.BaseDllName.Length; - } - else - { - nativeEntry.BaseDllName = nativeEntry.FullDllName; - } - } - else - { - // Read the base DLL name string and add a null terminator. - - baseDllNameBuffer = PhAllocate(nativeEntry.BaseDllName.Length + 2); - - if (NT_SUCCESS(NtReadVirtualMemory( - ProcessHandle, - nativeEntry.BaseDllName.Buffer, - baseDllNameBuffer, - nativeEntry.BaseDllName.Length, - NULL - ))) - { - baseDllNameBuffer[nativeEntry.BaseDllName.Length / 2] = 0; - } - else - { - baseDllNameBuffer[0] = 0; - nativeEntry.BaseDllName.Length = 0; - } - - nativeEntry.BaseDllName.Buffer = baseDllNameBuffer; - - // Read the full DLL name string and add a null terminator. - - fullDllNameBuffer = PhAllocate(nativeEntry.FullDllName.Length + 2); - - if (NT_SUCCESS(NtReadVirtualMemory( - ProcessHandle, - nativeEntry.FullDllName.Buffer, - fullDllNameBuffer, - nativeEntry.FullDllName.Length, - NULL - ))) - { - fullDllNameBuffer[nativeEntry.FullDllName.Length / 2] = 0; - - if (!(parameters->Flags & PH_ENUM_PROCESS_MODULES_DONT_RESOLVE_WOW64_FS)) - { - // WOW64 file system redirection - convert "system32" to "SysWOW64". - if (!(nativeEntry.FullDllName.Length & 1)) // validate the string length - { - fullDllName.Buffer = fullDllNameBuffer; - fullDllName.Length = nativeEntry.FullDllName.Length; - - PhGetSystemRoot(&systemRootString); - - if (PhStartsWithStringRef(&fullDllName, &systemRootString, TRUE)) - { - PhSkipStringRef(&fullDllName, systemRootString.Length); - - if (PhStartsWithStringRef(&fullDllName, &system32String, TRUE)) - { - fullDllName.Buffer[1] = 'S'; - fullDllName.Buffer[4] = 'W'; - fullDllName.Buffer[5] = 'O'; - fullDllName.Buffer[6] = 'W'; - fullDllName.Buffer[7] = '6'; - fullDllName.Buffer[8] = '4'; - } - } - } - } - } - else - { - fullDllNameBuffer[0] = 0; - nativeEntry.FullDllName.Length = 0; - } - - nativeEntry.FullDllName.Buffer = fullDllNameBuffer; - } - - // Execute the callback. - cont = parameters->Callback(&nativeEntry, parameters->Context); - - if (mappedFileName) - { - PhDereferenceObject(mappedFileName); - } - else - { - PhFree(baseDllNameBuffer); - PhFree(fullDllNameBuffer); - } - - return cont; -} - -/** - * Enumerates the 32-bit modules loaded by a process. - * - * \param ProcessHandle A handle to a process. The handle must have - * PROCESS_QUERY_LIMITED_INFORMATION and PROCESS_VM_READ access. - * \param Callback A callback function which is executed for each process module. - * \param Context A user-defined value to pass to the callback function. - * - * \retval STATUS_NOT_SUPPORTED The process is not running under WOW64. - * - * \remarks Do not use this function under a 32-bit environment. - */ -NTSTATUS PhEnumProcessModules32( - _In_ HANDLE ProcessHandle, - _In_ PPH_ENUM_PROCESS_MODULES_CALLBACK Callback, - _In_opt_ PVOID Context - ) -{ - PH_ENUM_PROCESS_MODULES_PARAMETERS parameters; - - parameters.Callback = Callback; - parameters.Context = Context; - parameters.Flags = 0; - - return PhEnumProcessModules32Ex(ProcessHandle, ¶meters); -} - -/** - * Enumerates the 32-bit modules loaded by a process. - * - * \param ProcessHandle A handle to a process. The handle must have - * PROCESS_QUERY_LIMITED_INFORMATION and PROCESS_VM_READ access. If - * \c PH_ENUM_PROCESS_MODULES_TRY_MAPPED_FILE_NAME is specified in \a Parameters, the handle should - * have PROCESS_QUERY_INFORMATION access. - * \param Parameters The enumeration parameters. - * - * \retval STATUS_NOT_SUPPORTED The process is not running under WOW64. - * - * \remarks Do not use this function under a 32-bit environment. - */ -NTSTATUS PhEnumProcessModules32Ex( - _In_ HANDLE ProcessHandle, - _In_ PPH_ENUM_PROCESS_MODULES_PARAMETERS Parameters - ) -{ - return PhpEnumProcessModules32( - ProcessHandle, - PhpEnumProcessModules32Callback, - Parameters, - NULL - ); -} - -BOOLEAN NTAPI PhpSetProcessModuleLoadCount32Callback( - _In_ HANDLE ProcessHandle, - _In_ PLDR_DATA_TABLE_ENTRY32 Entry, - _In_ ULONG AddressOfEntry, - _In_opt_ PVOID Context1, - _In_opt_ PVOID Context2 - ) -{ - PSET_PROCESS_MODULE_LOAD_COUNT_CONTEXT context = Context1; - - if (UlongToPtr(Entry->DllBase) == context->BaseAddress) - { - context->Status = NtWriteVirtualMemory( - ProcessHandle, - UlongToPtr(AddressOfEntry + FIELD_OFFSET(LDR_DATA_TABLE_ENTRY32, ObsoleteLoadCount)), - &context->LoadCount, - sizeof(USHORT), - NULL - ); - - return FALSE; - } - - return TRUE; -} - -/** - * Sets the load count of a 32-bit process module. - * - * \param ProcessHandle A handle to a process. The handle must have - * PROCESS_QUERY_LIMITED_INFORMATION, PROCESS_VM_READ and PROCESS_VM_WRITE access. - * \param BaseAddress The base address of a module. - * \param LoadCount The new load count of the module. - * - * \retval STATUS_DLL_NOT_FOUND The module was not found. - * \retval STATUS_NOT_SUPPORTED The process is not running under WOW64. - * - * \remarks Do not use this function under a 32-bit environment. - */ -NTSTATUS PhSetProcessModuleLoadCount32( - _In_ HANDLE ProcessHandle, - _In_ PVOID BaseAddress, - _In_ ULONG LoadCount - ) -{ - NTSTATUS status; - SET_PROCESS_MODULE_LOAD_COUNT_CONTEXT context; - - context.Status = STATUS_DLL_NOT_FOUND; - context.BaseAddress = BaseAddress; - context.LoadCount = LoadCount; - - status = PhpEnumProcessModules32( - ProcessHandle, - PhpSetProcessModuleLoadCount32Callback, - &context, - NULL - ); - - if (!NT_SUCCESS(status)) - return status; - - return context.Status; -} - -typedef struct _GET_PROCEDURE_ADDRESS_REMOTE_CONTEXT -{ - PH_STRINGREF FileName; - PVOID DllBase; -} GET_PROCEDURE_ADDRESS_REMOTE_CONTEXT, *PGET_PROCEDURE_ADDRESS_REMOTE_CONTEXT; - -static BOOLEAN PhpGetProcedureAddressRemoteCallback( - _In_ PLDR_DATA_TABLE_ENTRY Module, - _In_opt_ PVOID Context - ) -{ - PGET_PROCEDURE_ADDRESS_REMOTE_CONTEXT context = Context; - PH_STRINGREF fullDllName; - - PhUnicodeStringToStringRef(&Module->FullDllName, &fullDllName); - - if (PhEqualStringRef(&fullDllName, &context->FileName, TRUE)) - { - context->DllBase = Module->DllBase; - return FALSE; - } - - return TRUE; -} - -/** - * Gets the address of a procedure in a process. - * - * \param ProcessHandle A handle to a process. The handle must have - * PROCESS_QUERY_LIMITED_INFORMATION and PROCESS_VM_READ access. - * \param FileName The file name of the DLL containing the procedure. - * \param ProcedureName The name of the procedure. - * \param ProcedureNumber The ordinal of the procedure. - * \param ProcedureAddress A variable which receives the address of the procedure in the address - * space of the process. - * \param DllBase A variable which receives the base address of the DLL containing the procedure. - */ -NTSTATUS PhGetProcedureAddressRemote( - _In_ HANDLE ProcessHandle, - _In_ PWSTR FileName, - _In_opt_ PSTR ProcedureName, - _In_opt_ ULONG ProcedureNumber, - _Out_ PVOID *ProcedureAddress, - _Out_opt_ PVOID *DllBase - ) -{ - NTSTATUS status; - PH_MAPPED_IMAGE mappedImage; - PH_MAPPED_IMAGE_EXPORTS exports; - GET_PROCEDURE_ADDRESS_REMOTE_CONTEXT context; - - if (!NT_SUCCESS(status = PhLoadMappedImage(FileName, NULL, TRUE, &mappedImage))) - return status; - - PhInitializeStringRef(&context.FileName, FileName); - context.DllBase = NULL; - - if (mappedImage.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) - { -#ifdef _WIN64 - status = PhEnumProcessModules32(ProcessHandle, PhpGetProcedureAddressRemoteCallback, &context); -#else - status = PhEnumProcessModules(ProcessHandle, PhpGetProcedureAddressRemoteCallback, &context); -#endif - } - else - { -#ifdef _WIN64 - status = PhEnumProcessModules(ProcessHandle, PhpGetProcedureAddressRemoteCallback, &context); -#else - status = STATUS_NOT_SUPPORTED; -#endif - } - - if (!NT_SUCCESS(status)) - goto CleanupExit; - - if (!NT_SUCCESS(status = PhGetMappedImageExports(&exports, &mappedImage))) - goto CleanupExit; - - status = PhGetMappedImageExportFunctionRemote( - &exports, - ProcedureName, - (USHORT)ProcedureNumber, - context.DllBase, - ProcedureAddress - ); - - if (NT_SUCCESS(status)) - { - if (DllBase) - *DllBase = context.DllBase; - } - -CleanupExit: - PhUnloadMappedImage(&mappedImage); - - return status; -} - -/** - * Enumerates the modules loaded by the kernel. - * - * \param Modules A variable which receives a pointer to a structure containing information about - * the kernel modules. You must free the structure using PhFree() when you no longer need it. - */ -NTSTATUS PhEnumKernelModules( - _Out_ PRTL_PROCESS_MODULES *Modules - ) -{ - NTSTATUS status; - PVOID buffer; - ULONG bufferSize = 2048; - - buffer = PhAllocate(bufferSize); - - status = NtQuerySystemInformation( - SystemModuleInformation, - buffer, - bufferSize, - &bufferSize - ); - - if (status == STATUS_INFO_LENGTH_MISMATCH) - { - PhFree(buffer); - buffer = PhAllocate(bufferSize); - - status = NtQuerySystemInformation( - SystemModuleInformation, - buffer, - bufferSize, - &bufferSize - ); - } - - if (!NT_SUCCESS(status)) - return status; - - *Modules = buffer; - - return status; -} - -/** - * Enumerates the modules loaded by the kernel. - * - * \param Modules A variable which receives a pointer to a structure containing information about - * the kernel modules. You must free the structure using PhFree() when you no longer need it. - */ -NTSTATUS PhEnumKernelModulesEx( - _Out_ PRTL_PROCESS_MODULE_INFORMATION_EX *Modules - ) -{ - NTSTATUS status; - PVOID buffer; - ULONG bufferSize = 2048; - - buffer = PhAllocate(bufferSize); - - status = NtQuerySystemInformation( - SystemModuleInformationEx, - buffer, - bufferSize, - &bufferSize - ); - - if (status == STATUS_INFO_LENGTH_MISMATCH) - { - PhFree(buffer); - buffer = PhAllocate(bufferSize); - - status = NtQuerySystemInformation( - SystemModuleInformationEx, - buffer, - bufferSize, - &bufferSize - ); - } - - if (!NT_SUCCESS(status)) - return status; - - *Modules = buffer; - - return status; -} - -/** - * Gets the file name of the kernel image. - * - * \return A pointer to a string containing the kernel image file name. You must free the string - * using PhDereferenceObject() when you no longer need it. - */ -PPH_STRING PhGetKernelFileName( - VOID - ) -{ - PRTL_PROCESS_MODULES modules; - PPH_STRING fileName = NULL; - - if (!NT_SUCCESS(PhEnumKernelModules(&modules))) - return NULL; - - if (modules->NumberOfModules >= 1) - { - fileName = PhConvertMultiByteToUtf16(modules->Modules[0].FullPathName); - } - - PhFree(modules); - - return fileName; -} - -/** - * Enumerates the running processes. - * - * \param Processes A variable which receives a pointer to a buffer containing process information. - * You must free the buffer using PhFree() when you no longer need it. - * - * \remarks You can use the \ref PH_FIRST_PROCESS and \ref PH_NEXT_PROCESS macros to process the - * information contained in the buffer. - */ -NTSTATUS PhEnumProcesses( - _Out_ PVOID *Processes - ) -{ - return PhEnumProcessesEx(Processes, SystemProcessInformation); -} - -/** - * Enumerates the running processes. - * - * \param Processes A variable which receives a pointer to a buffer containing process information. - * You must free the buffer using PhFree() when you no longer need it. - * - * \remarks You can use the \ref PH_FIRST_PROCESS and \ref PH_NEXT_PROCESS macros to process the - * information contained in the buffer. - */ -NTSTATUS PhEnumProcessesEx( - _Out_ PVOID *Processes, - _In_ SYSTEM_INFORMATION_CLASS SystemInformationClass - ) -{ - static ULONG initialBufferSize[3] = { 0x4000, 0x4000, 0x4000 }; - NTSTATUS status; - ULONG classIndex; - PVOID buffer; - ULONG bufferSize; - - switch (SystemInformationClass) - { - case SystemProcessInformation: - classIndex = 0; - break; - case SystemExtendedProcessInformation: - classIndex = 1; - break; - case SystemFullProcessInformation: - classIndex = 2; - break; - default: - return STATUS_INVALID_INFO_CLASS; - } - - bufferSize = initialBufferSize[classIndex]; - buffer = PhAllocate(bufferSize); - - while (TRUE) - { - status = NtQuerySystemInformation( - SystemInformationClass, - buffer, - bufferSize, - &bufferSize - ); - - if (status == STATUS_BUFFER_TOO_SMALL || status == STATUS_INFO_LENGTH_MISMATCH) - { - PhFree(buffer); - buffer = PhAllocate(bufferSize); - } - else - { - break; - } - } - - if (!NT_SUCCESS(status)) - { - PhFree(buffer); - return status; - } - - if (bufferSize <= 0x100000) initialBufferSize[classIndex] = bufferSize; - *Processes = buffer; - - return status; -} - -/** - * Enumerates the running processes for a session. - * - * \param Processes A variable which receives a pointer to a buffer containing process information. - * You must free the buffer using PhFree() when you no longer need it. - * \param SessionId A session ID. - * - * \remarks You can use the \ref PH_FIRST_PROCESS and \ref PH_NEXT_PROCESS macros to process the - * information contained in the buffer. - */ -NTSTATUS PhEnumProcessesForSession( - _Out_ PVOID *Processes, - _In_ ULONG SessionId - ) -{ - static ULONG initialBufferSize = 0x4000; - NTSTATUS status; - SYSTEM_SESSION_PROCESS_INFORMATION sessionProcessInfo; - PVOID buffer; - ULONG bufferSize; - - bufferSize = initialBufferSize; - buffer = PhAllocate(bufferSize); - - sessionProcessInfo.SessionId = SessionId; - - while (TRUE) - { - sessionProcessInfo.SizeOfBuf = bufferSize; - sessionProcessInfo.Buffer = buffer; - - status = NtQuerySystemInformation( - SystemSessionProcessInformation, - &sessionProcessInfo, - sizeof(SYSTEM_SESSION_PROCESS_INFORMATION), - &bufferSize // size of the inner buffer gets returned - ); - - if (status == STATUS_BUFFER_TOO_SMALL || status == STATUS_INFO_LENGTH_MISMATCH) - { - PhFree(buffer); - buffer = PhAllocate(bufferSize); - } - else - { - break; - } - } - - if (!NT_SUCCESS(status)) - { - PhFree(buffer); - return status; - } - - if (bufferSize <= 0x100000) initialBufferSize = bufferSize; - *Processes = buffer; - - return status; -} - -/** - * Finds the process information structure for a specific process. - * - * \param Processes A pointer to a buffer returned by PhEnumProcesses(). - * \param ProcessId The ID of the process. - * - * \return A pointer to the process information structure for the specified process, or NULL if the - * structure could not be found. - */ -PSYSTEM_PROCESS_INFORMATION PhFindProcessInformation( - _In_ PVOID Processes, - _In_ HANDLE ProcessId - ) -{ - PSYSTEM_PROCESS_INFORMATION process; - - process = PH_FIRST_PROCESS(Processes); - - do - { - if (process->UniqueProcessId == ProcessId) - return process; - } while (process = PH_NEXT_PROCESS(process)); - - return NULL; -} - -/** - * Finds the process information structure for a specific process. - * - * \param Processes A pointer to a buffer returned by PhEnumProcesses(). - * \param ImageName The image name to search for. - * - * \return A pointer to the process information structure for the specified process, or NULL if the - * structure could not be found. - */ -PSYSTEM_PROCESS_INFORMATION PhFindProcessInformationByImageName( - _In_ PVOID Processes, - _In_ PPH_STRINGREF ImageName - ) -{ - PSYSTEM_PROCESS_INFORMATION process; - PH_STRINGREF processImageName; - - process = PH_FIRST_PROCESS(Processes); - - do - { - PhUnicodeStringToStringRef(&process->ImageName, &processImageName); - - if (PhEqualStringRef(&processImageName, ImageName, TRUE)) - return process; - } while (process = PH_NEXT_PROCESS(process)); - - return NULL; -} - -/** - * Enumerates all open handles. - * - * \param Handles A variable which receives a pointer to a structure containing information about - * all opened handles. You must free the structure using PhFree() when you no longer need it. - * - * \retval STATUS_INSUFFICIENT_RESOURCES The handle information returned by the kernel is too large. - */ -NTSTATUS PhEnumHandles( - _Out_ PSYSTEM_HANDLE_INFORMATION *Handles - ) -{ - static ULONG initialBufferSize = 0x4000; - NTSTATUS status; - PVOID buffer; - ULONG bufferSize; - - bufferSize = initialBufferSize; - buffer = PhAllocate(bufferSize); - - while ((status = NtQuerySystemInformation( - SystemHandleInformation, - buffer, - bufferSize, - NULL - )) == STATUS_INFO_LENGTH_MISMATCH) - { - PhFree(buffer); - bufferSize *= 2; - - // Fail if we're resizing the buffer to something very large. - if (bufferSize > PH_LARGE_BUFFER_SIZE) - return STATUS_INSUFFICIENT_RESOURCES; - - buffer = PhAllocate(bufferSize); - } - - if (!NT_SUCCESS(status)) - { - PhFree(buffer); - return status; - } - - if (bufferSize <= 0x100000) initialBufferSize = bufferSize; - *Handles = (PSYSTEM_HANDLE_INFORMATION)buffer; - - return status; -} - -/** - * Enumerates all open handles. - * - * \param Handles A variable which receives a pointer to a structure containing information about - * all opened handles. You must free the structure using PhFree() when you no longer need it. - * - * \retval STATUS_INSUFFICIENT_RESOURCES The handle information returned by the kernel is too large. - * - * \remarks This function is only available starting with Windows XP. - */ -NTSTATUS PhEnumHandlesEx( - _Out_ PSYSTEM_HANDLE_INFORMATION_EX *Handles - ) -{ - static ULONG initialBufferSize = 0x10000; - NTSTATUS status; - PVOID buffer; - ULONG bufferSize; - - bufferSize = initialBufferSize; - buffer = PhAllocate(bufferSize); - - while ((status = NtQuerySystemInformation( - SystemExtendedHandleInformation, - buffer, - bufferSize, - NULL - )) == STATUS_INFO_LENGTH_MISMATCH) - { - PhFree(buffer); - bufferSize *= 2; - - // Fail if we're resizing the buffer to something very large. - if (bufferSize > PH_LARGE_BUFFER_SIZE) - return STATUS_INSUFFICIENT_RESOURCES; - - buffer = PhAllocate(bufferSize); - } - - if (!NT_SUCCESS(status)) - { - PhFree(buffer); - return status; - } - - if (bufferSize <= 0x200000) initialBufferSize = bufferSize; - *Handles = (PSYSTEM_HANDLE_INFORMATION_EX)buffer; - - return status; -} - -/** - * Enumerates all pagefiles. - * - * \param Pagefiles A variable which receives a pointer to a buffer containing information about all - * active pagefiles. You must free the structure using PhFree() when you no longer need it. - * - * \retval STATUS_INSUFFICIENT_RESOURCES The handle information returned by the kernel is too large. - */ -NTSTATUS PhEnumPagefiles( - _Out_ PVOID *Pagefiles - ) -{ - NTSTATUS status; - PVOID buffer; - ULONG bufferSize = 0x200; - - buffer = PhAllocate(bufferSize); - - while ((status = NtQuerySystemInformation( - SystemPageFileInformation, - buffer, - bufferSize, - NULL - )) == STATUS_INFO_LENGTH_MISMATCH) - { - PhFree(buffer); - bufferSize *= 2; - - // Fail if we're resizing the buffer to something very large. - if (bufferSize > PH_LARGE_BUFFER_SIZE) - return STATUS_INSUFFICIENT_RESOURCES; - - buffer = PhAllocate(bufferSize); - } - - if (!NT_SUCCESS(status)) - { - PhFree(buffer); - return status; - } - - *Pagefiles = buffer; - - return status; -} - -/** - * Gets the file name of a process' image. - * - * \param ProcessId The ID of the process. - * \param FileName A variable which receives a pointer to a string containing the file name. You - * must free the string using PhDereferenceObject() when you no longer need it. - * - * \remarks This function only works on Windows Vista and above. There does not appear to be any - * access checking performed by the kernel for this. - */ -NTSTATUS PhGetProcessImageFileNameByProcessId( - _In_ HANDLE ProcessId, - _Out_ PPH_STRING *FileName - ) -{ - NTSTATUS status; - PVOID buffer; - ULONG bufferSize = 0x100; - SYSTEM_PROCESS_ID_INFORMATION processIdInfo; - - buffer = PhAllocate(bufferSize); - - processIdInfo.ProcessId = ProcessId; - processIdInfo.ImageName.Length = 0; - processIdInfo.ImageName.MaximumLength = (USHORT)bufferSize; - processIdInfo.ImageName.Buffer = buffer; - - status = NtQuerySystemInformation( - SystemProcessIdInformation, - &processIdInfo, - sizeof(SYSTEM_PROCESS_ID_INFORMATION), - NULL - ); - - if (status == STATUS_INFO_LENGTH_MISMATCH) - { - // Required length is stored in MaximumLength. - - PhFree(buffer); - buffer = PhAllocate(processIdInfo.ImageName.MaximumLength); - processIdInfo.ImageName.Buffer = buffer; - - status = NtQuerySystemInformation( - SystemProcessIdInformation, - &processIdInfo, - sizeof(SYSTEM_PROCESS_ID_INFORMATION), - NULL - ); - } - - if (!NT_SUCCESS(status)) - { - PhFree(buffer); - return status; - } - - *FileName = PhCreateStringFromUnicodeString(&processIdInfo.ImageName); - PhFree(buffer); - - return status; -} - -/** - * Determines if a process is managed. - * - * \param ProcessId The ID of the process. - * \param IsDotNet A variable which receives a boolean indicating whether the process is managed. - */ -NTSTATUS PhGetProcessIsDotNet( - _In_ HANDLE ProcessId, - _Out_ PBOOLEAN IsDotNet - ) -{ - return PhGetProcessIsDotNetEx(ProcessId, NULL, 0, IsDotNet, NULL); -} - -BOOLEAN NTAPI PhpIsDotNetEnumProcessModulesCallback( - _In_ PLDR_DATA_TABLE_ENTRY Module, - _In_opt_ PVOID Context - ) -{ - static UNICODE_STRING clrString = RTL_CONSTANT_STRING(L"clr.dll"); - static UNICODE_STRING mscorwksString = RTL_CONSTANT_STRING(L"mscorwks.dll"); - static UNICODE_STRING mscorsvrString = RTL_CONSTANT_STRING(L"mscorsvr.dll"); - static UNICODE_STRING mscorlibString = RTL_CONSTANT_STRING(L"mscorlib.dll"); - static UNICODE_STRING mscorlibNiString = RTL_CONSTANT_STRING(L"mscorlib.ni.dll"); - static UNICODE_STRING clrjitString = RTL_CONSTANT_STRING(L"clrjit.dll"); - static UNICODE_STRING frameworkString = RTL_CONSTANT_STRING(L"\\Microsoft.NET\\Framework\\"); - static UNICODE_STRING framework64String = RTL_CONSTANT_STRING(L"\\Microsoft.NET\\Framework64\\"); - - if ( - RtlEqualUnicodeString(&Module->BaseDllName, &clrString, TRUE) || - RtlEqualUnicodeString(&Module->BaseDllName, &mscorwksString, TRUE) || - RtlEqualUnicodeString(&Module->BaseDllName, &mscorsvrString, TRUE) - ) - { - UNICODE_STRING fileName; - PH_STRINGREF systemRootSr; - UNICODE_STRING systemRoot; - PUNICODE_STRING frameworkPart; - -#ifdef _WIN64 - if (*(PULONG)Context & PH_CLR_PROCESS_IS_WOW64) - { -#endif - frameworkPart = &frameworkString; -#ifdef _WIN64 - } - else - { - frameworkPart = &framework64String; - } -#endif - - fileName = Module->FullDllName; - PhGetSystemRoot(&systemRootSr); - PhStringRefToUnicodeString(&systemRootSr, &systemRoot); - - if (RtlPrefixUnicodeString(&systemRoot, &fileName, TRUE)) - { - fileName.Buffer = (PWCHAR)((PCHAR)fileName.Buffer + systemRoot.Length); - fileName.Length -= systemRoot.Length; - - if (RtlPrefixUnicodeString(frameworkPart, &fileName, TRUE)) - { - fileName.Buffer = (PWCHAR)((PCHAR)fileName.Buffer + frameworkPart->Length); - fileName.Length -= frameworkPart->Length; - - if (fileName.Length >= 4 * sizeof(WCHAR)) // vx.x - { - if (fileName.Buffer[1] == '1') - { - if (fileName.Buffer[3] == '0') - *(PULONG)Context |= PH_CLR_VERSION_1_0; - else if (fileName.Buffer[3] == '1') - *(PULONG)Context |= PH_CLR_VERSION_1_1; - } - else if (fileName.Buffer[1] == '2') - { - *(PULONG)Context |= PH_CLR_VERSION_2_0; - } - else if (fileName.Buffer[1] >= '4' && fileName.Buffer[1] <= '9') - { - *(PULONG)Context |= PH_CLR_VERSION_4_ABOVE; - } - } - } - } - } - else if ( - RtlEqualUnicodeString(&Module->BaseDllName, &mscorlibString, TRUE) || - RtlEqualUnicodeString(&Module->BaseDllName, &mscorlibNiString, TRUE) - ) - { - *(PULONG)Context |= PH_CLR_MSCORLIB_PRESENT; - } - else if (RtlEqualUnicodeString(&Module->BaseDllName, &clrjitString, TRUE)) - { - *(PULONG)Context |= PH_CLR_JIT_PRESENT; - } - - return TRUE; -} - -/** - * Determines if a process is managed. - * - * \param ProcessId The ID of the process. - * \param ProcessHandle An optional handle to the process. The handle must have - * PROCESS_QUERY_LIMITED_INFORMATION and PROCESS_VM_READ access. - * \param InFlags A combination of flags. - * \li \c PH_CLR_USE_SECTION_CHECK Checks for the existence of related section objects to determine - * whether the process is managed. - * \li \c PH_CLR_NO_WOW64_CHECK Instead of a separate query, uses the presence of the - * \c PH_CLR_KNOWN_IS_WOW64 flag to determine whether the process is running under WOW64. - * \li \c PH_CLR_KNOWN_IS_WOW64 When \c PH_CLR_NO_WOW64_CHECK is specified, indicates that the - * process is managed. - * \param IsDotNet A variable which receives a boolean indicating whether the process is managed. - * \param Flags A variable which receives additional flags. - */ -NTSTATUS PhGetProcessIsDotNetEx( - _In_ HANDLE ProcessId, - _In_opt_ HANDLE ProcessHandle, - _In_ ULONG InFlags, - _Out_opt_ PBOOLEAN IsDotNet, - _Out_opt_ PULONG Flags - ) -{ - NTSTATUS status = STATUS_SUCCESS; - HANDLE processHandle; - ULONG flags; -#ifdef _WIN64 - BOOLEAN isWow64; -#endif - - if (InFlags & PH_CLR_USE_SECTION_CHECK) - { - HANDLE sectionHandle; - OBJECT_ATTRIBUTES objectAttributes; - PPH_STRING sectionName; - UNICODE_STRING sectionNameUs; - PH_FORMAT format[2]; - - // Most .NET processes have a handle open to a section named - // \BaseNamedObjects\Cor_Private_IPCBlock(_v4)_. This is the same object used by - // the ICorPublish::GetProcess function. Instead of calling that function, we simply check - // for the existence of that section object. This means: - // * Better performance. - // * No need for admin rights to get .NET status of processes owned by other users. - - PhInitFormatIU(&format[1], (ULONG_PTR)ProcessId); - - // Version 4 section object - - PhInitFormatS(&format[0], L"\\BaseNamedObjects\\Cor_Private_IPCBlock_v4_"); - sectionName = PhFormat(format, 2, 96); - PhStringRefToUnicodeString(§ionName->sr, §ionNameUs); - - InitializeObjectAttributes( - &objectAttributes, - §ionNameUs, - OBJ_CASE_INSENSITIVE, - NULL, - NULL - ); - status = NtOpenSection( - §ionHandle, - SECTION_QUERY, - &objectAttributes - ); - PhDereferenceObject(sectionName); - - if (NT_SUCCESS(status) || status == STATUS_ACCESS_DENIED) - { - if (NT_SUCCESS(status)) - NtClose(sectionHandle); - - if (IsDotNet) - *IsDotNet = TRUE; - - if (Flags) - *Flags = PH_CLR_VERSION_4_ABOVE; - - return STATUS_SUCCESS; - } - - // Version 2 section object - - PhInitFormatS(&format[0], L"\\BaseNamedObjects\\Cor_Private_IPCBlock_"); - sectionName = PhFormat(format, 2, 90); - PhStringRefToUnicodeString(§ionName->sr, §ionNameUs); - - InitializeObjectAttributes( - &objectAttributes, - §ionNameUs, - OBJ_CASE_INSENSITIVE, - NULL, - NULL - ); - status = NtOpenSection( - §ionHandle, - SECTION_QUERY, - &objectAttributes - ); - PhDereferenceObject(sectionName); - - if (NT_SUCCESS(status) || status == STATUS_ACCESS_DENIED) - { - if (NT_SUCCESS(status)) - NtClose(sectionHandle); - - if (IsDotNet) - *IsDotNet = TRUE; - - if (Flags) - *Flags = PH_CLR_VERSION_2_0; - - return STATUS_SUCCESS; - } - } - - flags = 0; - processHandle = NULL; - - if (!ProcessHandle) - { - if (!NT_SUCCESS(status = PhOpenProcess(&processHandle, ProcessQueryAccess | PROCESS_VM_READ, ProcessId))) - return status; - - ProcessHandle = processHandle; - } - -#ifdef _WIN64 - if (InFlags & PH_CLR_NO_WOW64_CHECK) - { - isWow64 = !!(InFlags & PH_CLR_KNOWN_IS_WOW64); - } - else - { - isWow64 = FALSE; - PhGetProcessIsWow64(ProcessHandle, &isWow64); - } - - if (isWow64) - { - flags |= PH_CLR_PROCESS_IS_WOW64; - PhEnumProcessModules32(ProcessHandle, PhpIsDotNetEnumProcessModulesCallback, &flags); - } - else - { -#endif - PhEnumProcessModules(ProcessHandle, PhpIsDotNetEnumProcessModulesCallback, &flags); -#ifdef _WIN64 - } -#endif - - if (processHandle) - NtClose(processHandle); - - if (IsDotNet) - *IsDotNet = (flags & PH_CLR_VERSION_MASK) && (flags & (PH_CLR_MSCORLIB_PRESENT | PH_CLR_JIT_PRESENT)); - - if (Flags) - *Flags = flags; - - return status; -} - -/** - * Enumerates the objects in a directory object. - * - * \param DirectoryHandle A handle to a directory. The handle must have DIRECTORY_QUERY access. - * \param Callback A callback function which is executed for each object. - * \param Context A user-defined value to pass to the callback function. - */ -NTSTATUS PhEnumDirectoryObjects( - _In_ HANDLE DirectoryHandle, - _In_ PPH_ENUM_DIRECTORY_OBJECTS Callback, - _In_opt_ PVOID Context - ) -{ - NTSTATUS status; - ULONG context = 0; - BOOLEAN firstTime = TRUE; - ULONG bufferSize; - POBJECT_DIRECTORY_INFORMATION buffer; - ULONG i; - BOOLEAN cont; - - bufferSize = 0x200; - buffer = PhAllocate(bufferSize); - - while (TRUE) - { - // Get a batch of entries. - - while ((status = NtQueryDirectoryObject( - DirectoryHandle, - buffer, - bufferSize, - FALSE, - firstTime, - &context, - NULL - )) == STATUS_MORE_ENTRIES) - { - // Check if we have at least one entry. If not, we'll double the buffer size and try - // again. - if (buffer[0].Name.Buffer) - break; - - // Make sure we don't use too much memory. - if (bufferSize > PH_LARGE_BUFFER_SIZE) - { - PhFree(buffer); - return STATUS_INSUFFICIENT_RESOURCES; - } - - PhFree(buffer); - bufferSize *= 2; - buffer = PhAllocate(bufferSize); - } - - if (!NT_SUCCESS(status)) - { - PhFree(buffer); - return status; - } - - // Read the batch and execute the callback function for each object. - - i = 0; - cont = TRUE; - - while (TRUE) - { - POBJECT_DIRECTORY_INFORMATION info; - PH_STRINGREF name; - PH_STRINGREF typeName; - - info = &buffer[i]; - - if (!info->Name.Buffer) - break; - - PhUnicodeStringToStringRef(&info->Name, &name); - PhUnicodeStringToStringRef(&info->TypeName, &typeName); - - cont = Callback(&name, &typeName, Context); - - if (!cont) - break; - - i++; - } - - if (!cont) - break; - - if (status != STATUS_MORE_ENTRIES) - break; - - firstTime = FALSE; - } - - PhFree(buffer); - - return STATUS_SUCCESS; -} - -NTSTATUS PhEnumDirectoryFile( - _In_ HANDLE FileHandle, - _In_opt_ PUNICODE_STRING SearchPattern, - _In_ PPH_ENUM_DIRECTORY_FILE Callback, - _In_opt_ PVOID Context - ) -{ - NTSTATUS status; - IO_STATUS_BLOCK isb; - BOOLEAN firstTime = TRUE; - PVOID buffer; - ULONG bufferSize = 0x400; - ULONG i; - BOOLEAN cont; - - buffer = PhAllocate(bufferSize); - - while (TRUE) - { - // Query the directory, doubling the buffer each time NtQueryDirectoryFile fails. - while (TRUE) - { - status = NtQueryDirectoryFile( - FileHandle, - NULL, - NULL, - NULL, - &isb, - buffer, - bufferSize, - FileDirectoryInformation, - FALSE, - SearchPattern, - firstTime - ); - - // Our ISB is on the stack, so we have to wait for the operation to complete before - // continuing. - if (status == STATUS_PENDING) - { - status = NtWaitForSingleObject(FileHandle, FALSE, NULL); - - if (NT_SUCCESS(status)) - status = isb.Status; - } - - if (status == STATUS_BUFFER_OVERFLOW || status == STATUS_INFO_LENGTH_MISMATCH) - { - PhFree(buffer); - bufferSize *= 2; - buffer = PhAllocate(bufferSize); - } - else - { - break; - } - } - - // If we don't have any entries to read, exit. - if (status == STATUS_NO_MORE_FILES) - { - status = STATUS_SUCCESS; - break; - } - - if (!NT_SUCCESS(status)) - break; - - // Read the batch and execute the callback function for each file. - - i = 0; - cont = TRUE; - - while (TRUE) - { - PFILE_DIRECTORY_INFORMATION information; - - information = (PFILE_DIRECTORY_INFORMATION)(PTR_ADD_OFFSET(buffer, i)); - - if (!Callback( - information, - Context - )) - { - cont = FALSE; - break; - } - - if (information->NextEntryOffset != 0) - i += information->NextEntryOffset; - else - break; - } - - if (!cont) - break; - - firstTime = FALSE; - } - - PhFree(buffer); - - return status; -} - -NTSTATUS PhEnumFileStreams( - _In_ HANDLE FileHandle, - _Out_ PVOID *Streams - ) -{ - return PhpQueryFileVariableSize( - FileHandle, - FileStreamInformation, - Streams - ); -} - -/** - * Initializes the device prefixes module. - */ -VOID PhpInitializeDevicePrefixes( - VOID - ) -{ - ULONG i; - PUCHAR buffer; - - // Allocate one buffer for all 26 prefixes to reduce overhead. - buffer = PhAllocate(PH_DEVICE_PREFIX_LENGTH * sizeof(WCHAR) * 26); - - for (i = 0; i < 26; i++) - { - PhDevicePrefixes[i].Length = 0; - PhDevicePrefixes[i].MaximumLength = PH_DEVICE_PREFIX_LENGTH * sizeof(WCHAR); - PhDevicePrefixes[i].Buffer = (PWCHAR)buffer; - buffer += PH_DEVICE_PREFIX_LENGTH * sizeof(WCHAR); - } -} - -VOID PhUpdateMupDevicePrefixes( - VOID - ) -{ - static PH_STRINGREF orderKeyName = PH_STRINGREF_INIT(L"System\\CurrentControlSet\\Control\\NetworkProvider\\Order"); - static PH_STRINGREF servicesStringPart = PH_STRINGREF_INIT(L"System\\CurrentControlSet\\Services\\"); - static PH_STRINGREF networkProviderStringPart = PH_STRINGREF_INIT(L"\\NetworkProvider"); - - HANDLE orderKeyHandle; - PPH_STRING providerOrder = NULL; - ULONG i; - PH_STRINGREF remainingPart; - PH_STRINGREF part; - - // The provider names are stored in the ProviderOrder value in this key: - // HKLM\System\CurrentControlSet\Control\NetworkProvider\Order - // Each name can then be looked up, its device name in the DeviceName value in: - // HKLM\System\CurrentControlSet\Services\\NetworkProvider - - // Note that we assume the providers only claim their device name. Some providers such as DFS - // claim an extra part, and are not resolved correctly here. - - if (NT_SUCCESS(PhOpenKey( - &orderKeyHandle, - KEY_READ, - PH_KEY_LOCAL_MACHINE, - &orderKeyName, - 0 - ))) - { - providerOrder = PhQueryRegistryString(orderKeyHandle, L"ProviderOrder"); - NtClose(orderKeyHandle); - } - - if (!providerOrder) - return; - - PhAcquireQueuedLockExclusive(&PhDeviceMupPrefixesLock); - - for (i = 0; i < PhDeviceMupPrefixesCount; i++) - { - PhDereferenceObject(PhDeviceMupPrefixes[i]); - PhDeviceMupPrefixes[i] = NULL; - } - - PhDeviceMupPrefixesCount = 0; - - PhDeviceMupPrefixes[PhDeviceMupPrefixesCount++] = PhCreateString(L"\\Device\\Mup"); - - // DFS claims an extra part of file names, which we don't handle. - /*if (WindowsVersion >= WINDOWS_VISTA) - PhDeviceMupPrefixes[PhDeviceMupPrefixesCount++] = PhCreateString(L"\\Device\\DfsClient"); - else - PhDeviceMupPrefixes[PhDeviceMupPrefixesCount++] = PhCreateString(L"\\Device\\WinDfs");*/ - - remainingPart = providerOrder->sr; - - while (remainingPart.Length != 0) - { - PPH_STRING serviceKeyName; - HANDLE networkProviderKeyHandle; - PPH_STRING deviceName; - - if (PhDeviceMupPrefixesCount == PH_DEVICE_MUP_PREFIX_MAX_COUNT) - break; - - PhSplitStringRefAtChar(&remainingPart, ',', &part, &remainingPart); - - if (part.Length != 0) - { - serviceKeyName = PhConcatStringRef3(&servicesStringPart, &part, &networkProviderStringPart); - - if (NT_SUCCESS(PhOpenKey( - &networkProviderKeyHandle, - KEY_READ, - PH_KEY_LOCAL_MACHINE, - &serviceKeyName->sr, - 0 - ))) - { - if (deviceName = PhQueryRegistryString(networkProviderKeyHandle, L"DeviceName")) - { - PhDeviceMupPrefixes[PhDeviceMupPrefixesCount] = deviceName; - PhDeviceMupPrefixesCount++; - } - - NtClose(networkProviderKeyHandle); - } - - PhDereferenceObject(serviceKeyName); - } - } - - PhReleaseQueuedLockExclusive(&PhDeviceMupPrefixesLock); - - PhDereferenceObject(providerOrder); -} - -/** - * Updates the DOS device names array. - */ -VOID PhUpdateDosDevicePrefixes( - VOID - ) -{ - WCHAR deviceNameBuffer[7] = L"\\??\\ :"; - ULONG i; - - for (i = 0; i < 26; i++) - { - HANDLE linkHandle; - OBJECT_ATTRIBUTES oa; - UNICODE_STRING deviceName; - - deviceNameBuffer[4] = (WCHAR)('A' + i); - deviceName.Buffer = deviceNameBuffer; - deviceName.Length = 6 * sizeof(WCHAR); - - InitializeObjectAttributes( - &oa, - &deviceName, - OBJ_CASE_INSENSITIVE, - NULL, - NULL - ); - - if (NT_SUCCESS(NtOpenSymbolicLinkObject( - &linkHandle, - SYMBOLIC_LINK_QUERY, - &oa - ))) - { - PhAcquireQueuedLockExclusive(&PhDevicePrefixesLock); - - if (!NT_SUCCESS(NtQuerySymbolicLinkObject( - linkHandle, - &PhDevicePrefixes[i], - NULL - ))) - { - PhDevicePrefixes[i].Length = 0; - } - - PhReleaseQueuedLockExclusive(&PhDevicePrefixesLock); - - NtClose(linkHandle); - } - else - { - PhDevicePrefixes[i].Length = 0; - } - } -} - -/** - * Resolves a NT path into a Win32 path. - * - * \param Name A string containing the path to resolve. - * - * \return A pointer to a string containing the Win32 path. You must free the string using - * PhDereferenceObject() when you no longer need it. - */ -PPH_STRING PhResolveDevicePrefix( - _In_ PPH_STRING Name - ) -{ - ULONG i; - PPH_STRING newName = NULL; - - if (PhBeginInitOnce(&PhDevicePrefixesInitOnce)) - { - PhpInitializeDevicePrefixes(); - PhUpdateDosDevicePrefixes(); - PhUpdateMupDevicePrefixes(); - - PhEndInitOnce(&PhDevicePrefixesInitOnce); - } - - // Go through the DOS devices and try to find a matching prefix. - for (i = 0; i < 26; i++) - { - BOOLEAN isPrefix = FALSE; - PH_STRINGREF prefix; - - PhAcquireQueuedLockShared(&PhDevicePrefixesLock); - - PhUnicodeStringToStringRef(&PhDevicePrefixes[i], &prefix); - - if (prefix.Length != 0) - { - if (PhStartsWithStringRef(&Name->sr, &prefix, TRUE)) - { - // To ensure we match the longest prefix, make sure the next character is a - // backslash or the path is equal to the prefix. - if (Name->Length == prefix.Length || Name->Buffer[prefix.Length / sizeof(WCHAR)] == '\\') - { - isPrefix = TRUE; - } - } - } - - PhReleaseQueuedLockShared(&PhDevicePrefixesLock); - - if (isPrefix) - { - // :path - newName = PhCreateStringEx(NULL, 2 * sizeof(WCHAR) + Name->Length - prefix.Length); - newName->Buffer[0] = (WCHAR)('A' + i); - newName->Buffer[1] = ':'; - memcpy( - &newName->Buffer[2], - &Name->Buffer[prefix.Length / sizeof(WCHAR)], - Name->Length - prefix.Length - ); - - break; - } - } - - if (i == 26) - { - // Resolve network providers. - - PhAcquireQueuedLockShared(&PhDeviceMupPrefixesLock); - - for (i = 0; i < PhDeviceMupPrefixesCount; i++) - { - BOOLEAN isPrefix = FALSE; - SIZE_T prefixLength; - - prefixLength = PhDeviceMupPrefixes[i]->Length; - - if (prefixLength != 0) - { - if (PhStartsWithString(Name, PhDeviceMupPrefixes[i], TRUE)) - { - // To ensure we match the longest prefix, make sure the next character is a - // backslash. Don't resolve if the name *is* the prefix. Otherwise, we will end - // up with a useless string like "\". - if (Name->Length != prefixLength && Name->Buffer[prefixLength / sizeof(WCHAR)] == '\\') - { - isPrefix = TRUE; - } - } - } - - if (isPrefix) - { - // \path - newName = PhCreateStringEx(NULL, 1 * sizeof(WCHAR) + Name->Length - prefixLength); - newName->Buffer[0] = '\\'; - memcpy( - &newName->Buffer[1], - &Name->Buffer[prefixLength / sizeof(WCHAR)], - Name->Length - prefixLength - ); - - break; - } - } - - PhReleaseQueuedLockShared(&PhDeviceMupPrefixesLock); - } - - return newName; -} - -/** - * Converts a file name into Win32 format. - * - * \param FileName A string containing a file name. - * - * \return A pointer to a string containing the Win32 file name. You must free the string using - * PhDereferenceObject() when you no longer need it. - * - * \remarks This function may convert NT object name paths to invalid ones. If the path to be - * converted is not necessarily a file name, use PhResolveDevicePrefix(). - */ -PPH_STRING PhGetFileName( - _In_ PPH_STRING FileName - ) -{ - PPH_STRING newFileName; - - newFileName = FileName; - - // "\??\" refers to \GLOBAL??\. Just remove it. - if (PhStartsWithString2(FileName, L"\\??\\", FALSE)) - { - newFileName = PhCreateStringEx(NULL, FileName->Length - 4 * 2); - memcpy(newFileName->Buffer, &FileName->Buffer[4], FileName->Length - 4 * 2); - } - // "\SystemRoot" means "C:\Windows". - else if (PhStartsWithString2(FileName, L"\\SystemRoot", TRUE)) - { - PH_STRINGREF systemRoot; - - PhGetSystemRoot(&systemRoot); - newFileName = PhCreateStringEx(NULL, systemRoot.Length + FileName->Length - 11 * 2); - memcpy(newFileName->Buffer, systemRoot.Buffer, systemRoot.Length); - memcpy((PCHAR)newFileName->Buffer + systemRoot.Length, &FileName->Buffer[11], FileName->Length - 11 * 2); - } - // "system32\" means "C:\Windows\system32\". - else if (PhStartsWithString2(FileName, L"system32\\", TRUE)) - { - PH_STRINGREF systemRoot; - - PhGetSystemRoot(&systemRoot); - newFileName = PhCreateStringEx(NULL, systemRoot.Length + 2 + FileName->Length); - memcpy(newFileName->Buffer, systemRoot.Buffer, systemRoot.Length); - newFileName->Buffer[systemRoot.Length / 2] = '\\'; - memcpy((PCHAR)newFileName->Buffer + systemRoot.Length + 2, FileName->Buffer, FileName->Length); - } - else if (FileName->Length != 0 && FileName->Buffer[0] == '\\') - { - PPH_STRING resolvedName; - - resolvedName = PhResolveDevicePrefix(FileName); - - if (resolvedName) - { - newFileName = resolvedName; - } - else - { - // We didn't find a match. - // If the file name starts with "\Windows", prepend the system drive. - if (PhStartsWithString2(newFileName, L"\\Windows", TRUE)) - { - newFileName = PhCreateStringEx(NULL, FileName->Length + 2 * 2); - newFileName->Buffer[0] = USER_SHARED_DATA->NtSystemRoot[0]; - newFileName->Buffer[1] = ':'; - memcpy(&newFileName->Buffer[2], FileName->Buffer, FileName->Length); - } - else - { - PhReferenceObject(newFileName); - } - } - } - else - { - // Just return the supplied file name. Note that we need to add a reference. - PhReferenceObject(newFileName); - } - - return newFileName; -} - -typedef struct _ENUM_GENERIC_PROCESS_MODULES_CONTEXT -{ - PPH_ENUM_GENERIC_MODULES_CALLBACK Callback; - PVOID Context; - ULONG Type; - PPH_HASHTABLE BaseAddressHashtable; - - ULONG LoadOrderIndex; -} ENUM_GENERIC_PROCESS_MODULES_CONTEXT, *PENUM_GENERIC_PROCESS_MODULES_CONTEXT; - -static BOOLEAN EnumGenericProcessModulesCallback( - _In_ PLDR_DATA_TABLE_ENTRY Module, - _In_opt_ PVOID Context - ) -{ - PENUM_GENERIC_PROCESS_MODULES_CONTEXT context; - PH_MODULE_INFO moduleInfo; - PPH_STRING fileName; - BOOLEAN cont; - - context = (PENUM_GENERIC_PROCESS_MODULES_CONTEXT)Context; - - // Check if we have a duplicate base address. - if (PhFindEntryHashtable(context->BaseAddressHashtable, &Module->DllBase)) - { - return TRUE; - } - else - { - PhAddEntryHashtable(context->BaseAddressHashtable, &Module->DllBase); - } - - fileName = PhCreateStringFromUnicodeString(&Module->FullDllName); - - moduleInfo.Type = context->Type; - moduleInfo.BaseAddress = Module->DllBase; - moduleInfo.Size = Module->SizeOfImage; - moduleInfo.EntryPoint = Module->EntryPoint; - moduleInfo.Flags = Module->Flags; - moduleInfo.Name = PhCreateStringFromUnicodeString(&Module->BaseDllName); - moduleInfo.FileName = PhGetFileName(fileName); - moduleInfo.LoadOrderIndex = (USHORT)(context->LoadOrderIndex++); - moduleInfo.LoadCount = Module->ObsoleteLoadCount; - - if (WindowsVersion >= WINDOWS_8) - { - moduleInfo.LoadReason = (USHORT)Module->LoadReason; - moduleInfo.LoadTime = Module->LoadTime; - } - else - { - moduleInfo.LoadReason = -1; - moduleInfo.LoadTime.QuadPart = 0; - } - - PhDereferenceObject(fileName); - - cont = context->Callback(&moduleInfo, context->Context); - - PhDereferenceObject(moduleInfo.Name); - PhDereferenceObject(moduleInfo.FileName); - - return cont; -} - -VOID PhpRtlModulesToGenericModules( - _In_ PRTL_PROCESS_MODULES Modules, - _In_ PPH_ENUM_GENERIC_MODULES_CALLBACK Callback, - _In_opt_ PVOID Context, - _In_ PPH_HASHTABLE BaseAddressHashtable - ) -{ - PRTL_PROCESS_MODULE_INFORMATION module; - ULONG i; - PH_MODULE_INFO moduleInfo; - BOOLEAN cont; - - for (i = 0; i < Modules->NumberOfModules; i++) - { - PPH_STRING fileName; - - module = &Modules->Modules[i]; - - // Check if we have a duplicate base address. - if (PhFindEntryHashtable(BaseAddressHashtable, &module->ImageBase)) - { - continue; - } - else - { - PhAddEntryHashtable(BaseAddressHashtable, &module->ImageBase); - } - - fileName = PhConvertMultiByteToUtf16(module->FullPathName); - - if ((ULONG_PTR)module->ImageBase <= PhSystemBasicInformation.MaximumUserModeAddress) - moduleInfo.Type = PH_MODULE_TYPE_MODULE; - else - moduleInfo.Type = PH_MODULE_TYPE_KERNEL_MODULE; - - moduleInfo.BaseAddress = module->ImageBase; - moduleInfo.Size = module->ImageSize; - moduleInfo.EntryPoint = NULL; - moduleInfo.Flags = module->Flags; - moduleInfo.Name = PhConvertMultiByteToUtf16(&module->FullPathName[module->OffsetToFileName]); - moduleInfo.FileName = PhGetFileName(fileName); // convert to DOS file name - moduleInfo.LoadOrderIndex = module->LoadOrderIndex; - moduleInfo.LoadCount = module->LoadCount; - moduleInfo.LoadReason = -1; - moduleInfo.LoadTime.QuadPart = 0; - - PhDereferenceObject(fileName); - - if (module->OffsetToFileName == 0) - { - static PH_STRINGREF driversString = PH_STRINGREF_INIT(L"\\System32\\Drivers\\"); - PH_STRINGREF systemRoot; - PPH_STRING newFileName; - - // We only have the file name, without a path. The driver must be in the default drivers - // directory. - PhGetSystemRoot(&systemRoot); - newFileName = PhConcatStringRef3(&systemRoot, &driversString, &moduleInfo.Name->sr); - PhDereferenceObject(moduleInfo.FileName); - moduleInfo.FileName = newFileName; - } - - cont = Callback(&moduleInfo, Context); - - PhDereferenceObject(moduleInfo.Name); - PhDereferenceObject(moduleInfo.FileName); - - if (!cont) - break; - } -} - -VOID PhpRtlModulesExToGenericModules( - _In_ PRTL_PROCESS_MODULE_INFORMATION_EX Modules, - _In_ PPH_ENUM_GENERIC_MODULES_CALLBACK Callback, - _In_opt_ PVOID Context, - _In_ PPH_HASHTABLE BaseAddressHashtable - ) -{ - PRTL_PROCESS_MODULE_INFORMATION_EX module; - PH_MODULE_INFO moduleInfo; - BOOLEAN cont; - - module = Modules; - - while (module->NextOffset != 0) - { - PPH_STRING fileName; - - // Check if we have a duplicate base address. - if (PhFindEntryHashtable(BaseAddressHashtable, &module->BaseInfo.ImageBase)) - { - continue; - } - else - { - PhAddEntryHashtable(BaseAddressHashtable, &module->BaseInfo.ImageBase); - } - - fileName = PhConvertMultiByteToUtf16(module->BaseInfo.FullPathName); - - if ((ULONG_PTR)module->BaseInfo.ImageBase <= PhSystemBasicInformation.MaximumUserModeAddress) - moduleInfo.Type = PH_MODULE_TYPE_MODULE; - else - moduleInfo.Type = PH_MODULE_TYPE_KERNEL_MODULE; - - moduleInfo.BaseAddress = module->BaseInfo.ImageBase; - moduleInfo.Size = module->BaseInfo.ImageSize; - moduleInfo.EntryPoint = NULL; - moduleInfo.Flags = module->BaseInfo.Flags; - moduleInfo.Name = PhConvertMultiByteToUtf16(&module->BaseInfo.FullPathName[module->BaseInfo.OffsetToFileName]); - moduleInfo.FileName = PhGetFileName(fileName); // convert to DOS file name - moduleInfo.LoadOrderIndex = module->BaseInfo.LoadOrderIndex; - moduleInfo.LoadCount = module->BaseInfo.LoadCount; - moduleInfo.LoadReason = -1; - moduleInfo.LoadTime.QuadPart = 0; - - PhDereferenceObject(fileName); - - cont = Callback(&moduleInfo, Context); - - PhDereferenceObject(moduleInfo.Name); - PhDereferenceObject(moduleInfo.FileName); - - if (!cont) - break; - - module = PTR_ADD_OFFSET(module, module->NextOffset); - } -} - -BOOLEAN PhpCallbackMappedFileOrImage( - _In_ PVOID AllocationBase, - _In_ SIZE_T AllocationSize, - _In_ ULONG Type, - _In_ PPH_STRING FileName, - _In_ PPH_ENUM_GENERIC_MODULES_CALLBACK Callback, - _In_opt_ PVOID Context, - _In_ PPH_HASHTABLE BaseAddressHashtable - ) -{ - PH_MODULE_INFO moduleInfo; - BOOLEAN cont; - - moduleInfo.Type = Type; - moduleInfo.BaseAddress = AllocationBase; - moduleInfo.Size = (ULONG)AllocationSize; - moduleInfo.EntryPoint = NULL; - moduleInfo.Flags = 0; - moduleInfo.FileName = PhGetFileName(FileName); - moduleInfo.Name = PhGetBaseName(moduleInfo.FileName); - moduleInfo.LoadOrderIndex = -1; - moduleInfo.LoadCount = -1; - moduleInfo.LoadReason = -1; - moduleInfo.LoadTime.QuadPart = 0; - - cont = Callback(&moduleInfo, Context); - - PhDereferenceObject(moduleInfo.FileName); - PhDereferenceObject(moduleInfo.Name); - - return cont; -} - -VOID PhpEnumGenericMappedFilesAndImages( - _In_ HANDLE ProcessHandle, - _In_ ULONG Flags, - _In_ PPH_ENUM_GENERIC_MODULES_CALLBACK Callback, - _In_opt_ PVOID Context, - _In_ PPH_HASHTABLE BaseAddressHashtable - ) -{ - BOOLEAN querySucceeded; - PVOID baseAddress; - MEMORY_BASIC_INFORMATION basicInfo; - - baseAddress = (PVOID)0; - - if (!NT_SUCCESS(NtQueryVirtualMemory( - ProcessHandle, - baseAddress, - MemoryBasicInformation, - &basicInfo, - sizeof(MEMORY_BASIC_INFORMATION), - NULL - ))) - { - return; - } - - querySucceeded = TRUE; - - while (querySucceeded) - { - PVOID allocationBase; - SIZE_T allocationSize; - ULONG type; - PPH_STRING fileName; - BOOLEAN cont; - - if (basicInfo.Type == MEM_MAPPED || basicInfo.Type == MEM_IMAGE) - { - if (basicInfo.Type == MEM_MAPPED) - type = PH_MODULE_TYPE_MAPPED_FILE; - else - type = PH_MODULE_TYPE_MAPPED_IMAGE; - - // Find the total allocation size. - - allocationBase = basicInfo.AllocationBase; - allocationSize = 0; - - do - { - baseAddress = (PVOID)((ULONG_PTR)baseAddress + basicInfo.RegionSize); - allocationSize += basicInfo.RegionSize; - - if (!NT_SUCCESS(NtQueryVirtualMemory( - ProcessHandle, - baseAddress, - MemoryBasicInformation, - &basicInfo, - sizeof(MEMORY_BASIC_INFORMATION), - NULL - ))) - { - querySucceeded = FALSE; - break; - } - } while (basicInfo.AllocationBase == allocationBase); - - if ((type == PH_MODULE_TYPE_MAPPED_FILE && !(Flags & PH_ENUM_GENERIC_MAPPED_FILES)) || - (type == PH_MODULE_TYPE_MAPPED_IMAGE && !(Flags & PH_ENUM_GENERIC_MAPPED_IMAGES))) - { - // The user doesn't want this type of entry. - continue; - } - - // Check if we have a duplicate base address. - if (PhFindEntryHashtable(BaseAddressHashtable, &allocationBase)) - { - continue; - } - - if (!NT_SUCCESS(PhGetProcessMappedFileName( - ProcessHandle, - allocationBase, - &fileName - ))) - { - continue; - } - - PhAddEntryHashtable(BaseAddressHashtable, &allocationBase); - - cont = PhpCallbackMappedFileOrImage( - allocationBase, - allocationSize, - type, - fileName, - Callback, - Context, - BaseAddressHashtable - ); - - PhDereferenceObject(fileName); - - if (!cont) - break; - } - else - { - baseAddress = (PVOID)((ULONG_PTR)baseAddress + basicInfo.RegionSize); - - if (!NT_SUCCESS(NtQueryVirtualMemory( - ProcessHandle, - baseAddress, - MemoryBasicInformation, - &basicInfo, - sizeof(MEMORY_BASIC_INFORMATION), - NULL - ))) - { - querySucceeded = FALSE; - } - } - } -} - -BOOLEAN NTAPI PhpBaseAddressHashtableEqualFunction( - _In_ PVOID Entry1, - _In_ PVOID Entry2 - ) -{ - return *(PVOID *)Entry1 == *(PVOID *)Entry2; -} - -ULONG NTAPI PhpBaseAddressHashtableHashFunction( - _In_ PVOID Entry - ) -{ - return PhHashIntPtr((ULONG_PTR)*(PVOID *)Entry); -} - -/** - * Enumerates the modules loaded by a process. - * - * \param ProcessId The ID of a process. If \ref SYSTEM_PROCESS_ID is specified the function - * enumerates the kernel modules. - * \param ProcessHandle A handle to the process. - * \param Flags Flags controlling the information to retrieve. - * \li \c PH_ENUM_GENERIC_MAPPED_FILES Enumerate mapped files. - * \li \c PH_ENUM_GENERIC_MAPPED_IMAGES Enumerate mapped images (those which are not mapped by the - * loader). - * \param Callback A callback function which is executed for each module. - * \param Context A user-defined value to pass to the callback function. - */ -NTSTATUS PhEnumGenericModules( - _In_ HANDLE ProcessId, - _In_opt_ HANDLE ProcessHandle, - _In_ ULONG Flags, - _In_ PPH_ENUM_GENERIC_MODULES_CALLBACK Callback, - _In_opt_ PVOID Context - ) -{ - NTSTATUS status; - PPH_HASHTABLE baseAddressHashtable; - - baseAddressHashtable = PhCreateHashtable( - sizeof(PVOID), - PhpBaseAddressHashtableEqualFunction, - PhpBaseAddressHashtableHashFunction, - 32 - ); - - if (ProcessId == SYSTEM_PROCESS_ID) - { - // Kernel modules - - PVOID modules; - - if (NT_SUCCESS(status = PhEnumKernelModules((PRTL_PROCESS_MODULES *)&modules))) - { - PhpRtlModulesToGenericModules( - modules, - Callback, - Context, - baseAddressHashtable - ); - PhFree(modules); - } - } - else - { - // Process modules - - BOOLEAN opened = FALSE; -#ifdef _WIN64 - BOOLEAN isWow64 = FALSE; -#endif - ENUM_GENERIC_PROCESS_MODULES_CONTEXT context; - PH_ENUM_PROCESS_MODULES_PARAMETERS parameters; - - if (!ProcessHandle) - { - if (!NT_SUCCESS(status = PhOpenProcess( - &ProcessHandle, - PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, // needed for enumerating mapped files - ProcessId - ))) - { - if (!NT_SUCCESS(status = PhOpenProcess( - &ProcessHandle, - ProcessQueryAccess | PROCESS_VM_READ, - ProcessId - ))) - { - goto CleanupExit; - } - } - - opened = TRUE; - } - - context.Callback = Callback; - context.Context = Context; - context.Type = PH_MODULE_TYPE_MODULE; - context.BaseAddressHashtable = baseAddressHashtable; - context.LoadOrderIndex = 0; - - parameters.Callback = EnumGenericProcessModulesCallback; - parameters.Context = &context; - parameters.Flags = PH_ENUM_PROCESS_MODULES_TRY_MAPPED_FILE_NAME; - - status = PhEnumProcessModulesEx( - ProcessHandle, - ¶meters - ); - -#ifdef _WIN64 - PhGetProcessIsWow64(ProcessHandle, &isWow64); - - // 32-bit process modules - if (isWow64) - { - context.Callback = Callback; - context.Context = Context; - context.Type = PH_MODULE_TYPE_WOW64_MODULE; - context.BaseAddressHashtable = baseAddressHashtable; - context.LoadOrderIndex = 0; - - status = PhEnumProcessModules32Ex( - ProcessHandle, - ¶meters - ); - } -#endif - - // Mapped files and mapped images - // This is done last because it provides the least amount of information. - - if (Flags & (PH_ENUM_GENERIC_MAPPED_FILES | PH_ENUM_GENERIC_MAPPED_IMAGES)) - { - PhpEnumGenericMappedFilesAndImages( - ProcessHandle, - Flags, - Callback, - Context, - baseAddressHashtable - ); - } - - if (opened) - NtClose(ProcessHandle); - } - -CleanupExit: - PhDereferenceObject(baseAddressHashtable); - - return status; -} - -/** - * Initializes usage of predefined keys. - */ -VOID PhpInitializePredefineKeys( - VOID - ) -{ - static UNICODE_STRING currentUserPrefix = RTL_CONSTANT_STRING(L"\\Registry\\User\\"); - - NTSTATUS status; - HANDLE tokenHandle; - PTOKEN_USER tokenUser; - UNICODE_STRING stringSid; - WCHAR stringSidBuffer[MAX_UNICODE_STACK_BUFFER_LENGTH]; - PUNICODE_STRING currentUserKeyName; - - // Get the string SID of the current user. - if (NT_SUCCESS(status = NtOpenProcessToken(NtCurrentProcess(), TOKEN_QUERY, &tokenHandle))) - { - if (NT_SUCCESS(status = PhGetTokenUser(tokenHandle, &tokenUser))) - { - stringSid.Buffer = stringSidBuffer; - stringSid.MaximumLength = sizeof(stringSidBuffer); - - status = RtlConvertSidToUnicodeString( - &stringSid, - tokenUser->User.Sid, - FALSE - ); - - PhFree(tokenUser); - } - - NtClose(tokenHandle); - } - - // Construct the current user key name. - if (NT_SUCCESS(status)) - { - currentUserKeyName = &PhPredefineKeyNames[PH_KEY_CURRENT_USER_NUMBER]; - currentUserKeyName->Length = currentUserPrefix.Length + stringSid.Length; - currentUserKeyName->Buffer = PhAllocate(currentUserKeyName->Length + sizeof(WCHAR)); - memcpy(currentUserKeyName->Buffer, currentUserPrefix.Buffer, currentUserPrefix.Length); - memcpy(¤tUserKeyName->Buffer[currentUserPrefix.Length / sizeof(WCHAR)], stringSid.Buffer, stringSid.Length); - } -} - -/** - * Initializes the attributes of a key object for creating/opening. - * - * \param RootDirectory A handle to a root key, or one of the predefined keys. See PhCreateKey() for - * details. - * \param ObjectName The path to the key. - * \param Attributes Additional object flags. - * \param ObjectAttributes The OBJECT_ATTRIBUTES structure to initialize. - * \param NeedsClose A variable which receives a handle that must be closed when the create/open - * operation is finished. The variable may be set to NULL if no handle needs to be closed. - */ -NTSTATUS PhpInitializeKeyObjectAttributes( - _In_opt_ HANDLE RootDirectory, - _In_ PUNICODE_STRING ObjectName, - _In_ ULONG Attributes, - _Out_ POBJECT_ATTRIBUTES ObjectAttributes, - _Out_ PHANDLE NeedsClose - ) -{ - NTSTATUS status; - ULONG predefineIndex; - HANDLE predefineHandle; - OBJECT_ATTRIBUTES predefineObjectAttributes; - - InitializeObjectAttributes( - ObjectAttributes, - ObjectName, - Attributes | OBJ_CASE_INSENSITIVE, - RootDirectory, - NULL - ); - - *NeedsClose = NULL; - - if (RootDirectory && PH_KEY_IS_PREDEFINED(RootDirectory)) - { - predefineIndex = PH_KEY_PREDEFINE_TO_NUMBER(RootDirectory); - - if (predefineIndex < PH_KEY_MAXIMUM_PREDEFINE) - { - if (PhBeginInitOnce(&PhPredefineKeyInitOnce)) - { - PhpInitializePredefineKeys(); - PhEndInitOnce(&PhPredefineKeyInitOnce); - } - - predefineHandle = PhPredefineKeyHandles[predefineIndex]; - - if (!predefineHandle) - { - // The predefined key has not been opened yet. Do so now. - - if (!PhPredefineKeyNames[predefineIndex].Buffer) // we may have failed in getting the current user key name - return STATUS_UNSUCCESSFUL; - - InitializeObjectAttributes( - &predefineObjectAttributes, - &PhPredefineKeyNames[predefineIndex], - OBJ_CASE_INSENSITIVE, - NULL, - NULL - ); - - status = NtOpenKey( - &predefineHandle, - KEY_READ, - &predefineObjectAttributes - ); - - if (!NT_SUCCESS(status)) - return status; - - if (_InterlockedCompareExchangePointer( - &PhPredefineKeyHandles[predefineIndex], - predefineHandle, - NULL - ) != NULL) - { - // Someone else already opened the key and cached it. Indicate that the caller - // needs to close the handle later, since it isn't shared. - *NeedsClose = predefineHandle; - } - } - - ObjectAttributes->RootDirectory = predefineHandle; - } - } - - return STATUS_SUCCESS; -} - -/** - * Creates or opens a registry key. - * - * \param KeyHandle A variable which receives a handle to the key. - * \param DesiredAccess The desired access to the key. - * \param RootDirectory A handle to a root key, or one of the following predefined keys: - * \li \c PH_KEY_LOCAL_MACHINE Represents \\Registry\\Machine. - * \li \c PH_KEY_USERS Represents \\Registry\\User. - * \li \c PH_KEY_CLASSES_ROOT Represents \\Registry\\Machine\\Software\\Classes. - * \li \c PH_KEY_CURRENT_USER Represents \\Registry\\User\\[SID of current user]. - * \param ObjectName The path to the key. - * \param Attributes Additional object flags. - * \param CreateOptions The options to apply when creating or opening the key. - * \param Disposition A variable which receives a value indicating whether a new key was created or - * an existing key was opened: - * \li \c REG_CREATED_NEW_KEY A new key was created. - * \li \c REG_OPENED_EXISTING_KEY An existing key was opened. - */ -NTSTATUS PhCreateKey( - _Out_ PHANDLE KeyHandle, - _In_ ACCESS_MASK DesiredAccess, - _In_opt_ HANDLE RootDirectory, - _In_ PPH_STRINGREF ObjectName, - _In_ ULONG Attributes, - _In_ ULONG CreateOptions, - _Out_opt_ PULONG Disposition - ) -{ - NTSTATUS status; - UNICODE_STRING objectName; - OBJECT_ATTRIBUTES objectAttributes; - HANDLE needsClose; - - if (!PhStringRefToUnicodeString(ObjectName, &objectName)) - return STATUS_NAME_TOO_LONG; - - if (!NT_SUCCESS(status = PhpInitializeKeyObjectAttributes( - RootDirectory, - &objectName, - Attributes, - &objectAttributes, - &needsClose - ))) - { - return status; - } - - status = NtCreateKey( - KeyHandle, - DesiredAccess, - &objectAttributes, - 0, - NULL, - CreateOptions, - Disposition - ); - - if (needsClose) - NtClose(needsClose); - - return status; -} - -/** - * Opens a registry key. - * - * \param KeyHandle A variable which receives a handle to the key. - * \param DesiredAccess The desired access to the key. - * \param RootDirectory A handle to a root key, or one of the predefined keys. See PhCreateKey() for - * details. - * \param ObjectName The path to the key. - * \param Attributes Additional object flags. - */ -NTSTATUS PhOpenKey( - _Out_ PHANDLE KeyHandle, - _In_ ACCESS_MASK DesiredAccess, - _In_opt_ HANDLE RootDirectory, - _In_ PPH_STRINGREF ObjectName, - _In_ ULONG Attributes - ) -{ - NTSTATUS status; - UNICODE_STRING objectName; - OBJECT_ATTRIBUTES objectAttributes; - HANDLE needsClose; - - if (!PhStringRefToUnicodeString(ObjectName, &objectName)) - return STATUS_NAME_TOO_LONG; - - if (!NT_SUCCESS(status = PhpInitializeKeyObjectAttributes( - RootDirectory, - &objectName, - Attributes, - &objectAttributes, - &needsClose - ))) - { - return status; - } - - status = NtOpenKey( - KeyHandle, - DesiredAccess, - &objectAttributes - ); - - if (needsClose) - NtClose(needsClose); - - return status; -} - -/** - * Gets information about a registry key. - * - * \param KeyHandle A handle to the key. - * \param KeyInformationClass The information class to query. - * \param Buffer A variable which receives a pointer to a buffer containing information about the - * registry key. You must free the buffer with PhFree() when you no longer need it. - */ -NTSTATUS PhQueryKey( - _In_ HANDLE KeyHandle, - _In_ KEY_INFORMATION_CLASS KeyInformationClass, - _Out_ PVOID *Buffer - ) -{ - NTSTATUS status; - PVOID buffer; - ULONG bufferSize; - ULONG attempts = 16; - - bufferSize = 0x100; - buffer = PhAllocate(bufferSize); - - do - { - status = NtQueryKey( - KeyHandle, - KeyInformationClass, - buffer, - bufferSize, - &bufferSize - ); - - if (NT_SUCCESS(status)) - break; - - if (status == STATUS_BUFFER_OVERFLOW) - { - PhFree(buffer); - buffer = PhAllocate(bufferSize); - } - else - { - PhFree(buffer); - return status; - } - } while (--attempts); - - *Buffer = buffer; - - return status; -} - -/** - * Gets a registry value of any type. - * - * \param KeyHandle A handle to the key. - * \param ValueName The name of the value. - * \param KeyValueInformationClass The information class to query. - * \param Buffer A variable which receives a pointer to a buffer containing information about the - * registry value. You must free the buffer with PhFree() when you no longer need it. - */ -NTSTATUS PhQueryValueKey( - _In_ HANDLE KeyHandle, - _In_opt_ PPH_STRINGREF ValueName, - _In_ KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass, - _Out_ PVOID *Buffer - ) -{ - NTSTATUS status; - UNICODE_STRING valueName; - PVOID buffer; - ULONG bufferSize; - ULONG attempts = 16; - - if (ValueName) - { - if (!PhStringRefToUnicodeString(ValueName, &valueName)) - return STATUS_NAME_TOO_LONG; - } - else - { - RtlInitUnicodeString(&valueName, NULL); - } - - bufferSize = 0x100; - buffer = PhAllocate(bufferSize); - - do - { - status = NtQueryValueKey( - KeyHandle, - &valueName, - KeyValueInformationClass, - buffer, - bufferSize, - &bufferSize - ); - - if (NT_SUCCESS(status)) - break; - - if (status == STATUS_BUFFER_OVERFLOW) - { - PhFree(buffer); - buffer = PhAllocate(bufferSize); - } - else - { - PhFree(buffer); - return status; - } - } while (--attempts); - - *Buffer = buffer; - - return status; -} - -/** - * Creates or opens a file. - * - * \param FileHandle A variable that receives the file handle. - * \param FileName The Win32 file name. - * \param DesiredAccess The desired access to the file. - * \param FileAttributes File attributes applied if the file is created or overwritten. - * \param ShareAccess The file access granted to other threads. - * \li \c FILE_SHARE_READ Allows other threads to read from the file. - * \li \c FILE_SHARE_WRITE Allows other threads to write to the file. - * \li \c FILE_SHARE_DELETE Allows other threads to delete the file. - * \param CreateDisposition The action to perform if the file does or does not exist. - * \li \c FILE_SUPERSEDE If the file exists, replace it. Otherwise, create the file. - * \li \c FILE_CREATE If the file exists, fail. Otherwise, create the file. - * \li \c FILE_OPEN If the file exists, open it. Otherwise, fail. - * \li \c FILE_OPEN_IF If the file exists, open it. Otherwise, create the file. - * \li \c FILE_OVERWRITE If the file exists, open and overwrite it. Otherwise, fail. - * \li \c FILE_OVERWRITE_IF If the file exists, open and overwrite it. Otherwise, create the file. - * \param CreateOptions The options to apply when the file is opened or created. - */ -NTSTATUS PhCreateFileWin32( - _Out_ PHANDLE FileHandle, - _In_ PWSTR FileName, - _In_ ACCESS_MASK DesiredAccess, - _In_opt_ ULONG FileAttributes, - _In_ ULONG ShareAccess, - _In_ ULONG CreateDisposition, - _In_ ULONG CreateOptions - ) -{ - return PhCreateFileWin32Ex( - FileHandle, - FileName, - DesiredAccess, - FileAttributes, - ShareAccess, - CreateDisposition, - CreateOptions, - NULL - ); -} - -/** - * Creates or opens a file. - * - * \param FileHandle A variable that receives the file handle. - * \param FileName The Win32 file name. - * \param DesiredAccess The desired access to the file. - * \param FileAttributes File attributes applied if the file is created or overwritten. - * \param ShareAccess The file access granted to other threads. - * \li \c FILE_SHARE_READ Allows other threads to read from the file. - * \li \c FILE_SHARE_WRITE Allows other threads to write to the file. - * \li \c FILE_SHARE_DELETE Allows other threads to delete the file. - * \param CreateDisposition The action to perform if the file does or does not exist. - * \li \c FILE_SUPERSEDE If the file exists, replace it. Otherwise, create the file. - * \li \c FILE_CREATE If the file exists, fail. Otherwise, create the file. - * \li \c FILE_OPEN If the file exists, open it. Otherwise, fail. - * \li \c FILE_OPEN_IF If the file exists, open it. Otherwise, create the file. - * \li \c FILE_OVERWRITE If the file exists, open and overwrite it. Otherwise, fail. - * \li \c FILE_OVERWRITE_IF If the file exists, open and overwrite it. Otherwise, create the file. - * \param CreateOptions The options to apply when the file is opened or created. - * \param CreateStatus A variable that receives creation information. - * \li \c FILE_SUPERSEDED The file was replaced because \c FILE_SUPERSEDE was specified in - * \a CreateDisposition. - * \li \c FILE_OPENED The file was opened because \c FILE_OPEN or \c FILE_OPEN_IF was specified in - * \a CreateDisposition. - * \li \c FILE_CREATED The file was created because \c FILE_CREATE or \c FILE_OPEN_IF was specified - * in \a CreateDisposition. - * \li \c FILE_OVERWRITTEN The file was overwritten because \c FILE_OVERWRITE or - * \c FILE_OVERWRITE_IF was specified in \a CreateDisposition. - * \li \c FILE_EXISTS The file was not opened because it already existed and \c FILE_CREATE was - * specified in \a CreateDisposition. - * \li \c FILE_DOES_NOT_EXIST The file was not opened because it did not exist and \c FILE_OPEN or - * \c FILE_OVERWRITE was specified in \a CreateDisposition. - */ -NTSTATUS PhCreateFileWin32Ex( - _Out_ PHANDLE FileHandle, - _In_ PWSTR FileName, - _In_ ACCESS_MASK DesiredAccess, - _In_opt_ ULONG FileAttributes, - _In_ ULONG ShareAccess, - _In_ ULONG CreateDisposition, - _In_ ULONG CreateOptions, - _Out_opt_ PULONG CreateStatus - ) -{ - NTSTATUS status; - HANDLE fileHandle; - UNICODE_STRING fileName; - OBJECT_ATTRIBUTES oa; - IO_STATUS_BLOCK isb; - - if (!FileAttributes) - FileAttributes = FILE_ATTRIBUTE_NORMAL; - - if (!NT_SUCCESS(status = RtlDosPathNameToNtPathName_U_WithStatus( - FileName, - &fileName, - NULL, - NULL - ))) - return status; - - InitializeObjectAttributes( - &oa, - &fileName, - OBJ_CASE_INSENSITIVE, - NULL, - NULL - ); - - status = NtCreateFile( - &fileHandle, - DesiredAccess, - &oa, - &isb, - NULL, - FileAttributes, - ShareAccess, - CreateDisposition, - CreateOptions, - NULL, - 0 - ); - - RtlFreeUnicodeString(&fileName); - - if (NT_SUCCESS(status)) - { - *FileHandle = fileHandle; - } - - if (CreateStatus) - *CreateStatus = (ULONG)isb.Information; - - return status; -} - -/** - * Queries file attributes. - * - * \param FileName The Win32 file name. - * \param FileInformation A variable that receives the file information. - */ -NTSTATUS PhQueryFullAttributesFileWin32( - _In_ PWSTR FileName, - _Out_ PFILE_NETWORK_OPEN_INFORMATION FileInformation - ) -{ - NTSTATUS status; - UNICODE_STRING fileName; - OBJECT_ATTRIBUTES oa; - - if (!NT_SUCCESS(status = RtlDosPathNameToNtPathName_U_WithStatus( - FileName, - &fileName, - NULL, - NULL - ))) - return status; - - InitializeObjectAttributes( - &oa, - &fileName, - OBJ_CASE_INSENSITIVE, - NULL, - NULL - ); - - status = NtQueryFullAttributesFile(&oa, FileInformation); - RtlFreeUnicodeString(&fileName); - - return status; -} - -/** - * Deletes a file. - * - * \param FileName The Win32 file name. - */ -NTSTATUS PhDeleteFileWin32( - _In_ PWSTR FileName - ) -{ - NTSTATUS status; - HANDLE fileHandle; - - status = PhCreateFileWin32( - &fileHandle, - FileName, - DELETE, - 0, - FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, - FILE_OPEN, - FILE_DELETE_ON_CLOSE - ); - - if (!NT_SUCCESS(status)) - return status; - - NtClose(fileHandle); - - return status; -} - -NTSTATUS PhListenNamedPipe( - _In_ HANDLE FileHandle, - _In_opt_ HANDLE Event, - _In_opt_ PIO_APC_ROUTINE ApcRoutine, - _In_opt_ PVOID ApcContext, - _Out_ PIO_STATUS_BLOCK IoStatusBlock - ) -{ - return NtFsControlFile( - FileHandle, - Event, - ApcRoutine, - ApcContext, - IoStatusBlock, - FSCTL_PIPE_LISTEN, - NULL, - 0, - NULL, - 0 - ); -} - -NTSTATUS PhDisconnectNamedPipe( - _In_ HANDLE FileHandle - ) -{ - NTSTATUS status; - IO_STATUS_BLOCK isb; - - status = NtFsControlFile( - FileHandle, - NULL, - NULL, - NULL, - &isb, - FSCTL_PIPE_DISCONNECT, - NULL, - 0, - NULL, - 0 - ); - - if (status == STATUS_PENDING) - { - status = NtWaitForSingleObject(FileHandle, FALSE, NULL); - - if (NT_SUCCESS(status)) - status = isb.Status; - } - - return status; -} - -NTSTATUS PhPeekNamedPipe( - _In_ HANDLE FileHandle, - _Out_writes_bytes_opt_(Length) PVOID Buffer, - _In_ ULONG Length, - _Out_opt_ PULONG NumberOfBytesRead, - _Out_opt_ PULONG NumberOfBytesAvailable, - _Out_opt_ PULONG NumberOfBytesLeftInMessage - ) -{ - NTSTATUS status; - IO_STATUS_BLOCK isb; - PFILE_PIPE_PEEK_BUFFER peekBuffer; - ULONG peekBufferLength; - - peekBufferLength = FIELD_OFFSET(FILE_PIPE_PEEK_BUFFER, Data) + Length; - peekBuffer = PhAllocate(peekBufferLength); - - status = NtFsControlFile( - FileHandle, - NULL, - NULL, - NULL, - &isb, - FSCTL_PIPE_PEEK, - NULL, - 0, - peekBuffer, - peekBufferLength - ); - - if (status == STATUS_PENDING) - { - status = NtWaitForSingleObject(FileHandle, FALSE, NULL); - - if (NT_SUCCESS(status)) - status = isb.Status; - } - - // STATUS_BUFFER_OVERFLOW means that there is data remaining; this is normal. - if (status == STATUS_BUFFER_OVERFLOW) - status = STATUS_SUCCESS; - - if (NT_SUCCESS(status)) - { - ULONG numberOfBytesRead; - - if (Buffer || NumberOfBytesRead || NumberOfBytesLeftInMessage) - numberOfBytesRead = (ULONG)(isb.Information - FIELD_OFFSET(FILE_PIPE_PEEK_BUFFER, Data)); - - if (Buffer) - memcpy(Buffer, peekBuffer->Data, numberOfBytesRead); - - if (NumberOfBytesRead) - *NumberOfBytesRead = numberOfBytesRead; - - if (NumberOfBytesAvailable) - *NumberOfBytesAvailable = peekBuffer->ReadDataAvailable; - - if (NumberOfBytesLeftInMessage) - *NumberOfBytesLeftInMessage = peekBuffer->MessageLength - numberOfBytesRead; - } - - PhFree(peekBuffer); - - return status; -} - -NTSTATUS PhTransceiveNamedPipe( - _In_ HANDLE FileHandle, - _In_opt_ HANDLE Event, - _In_opt_ PIO_APC_ROUTINE ApcRoutine, - _In_opt_ PVOID ApcContext, - _Out_ PIO_STATUS_BLOCK IoStatusBlock, - _In_reads_bytes_(InputBufferLength) PVOID InputBuffer, - _In_ ULONG InputBufferLength, - _Out_writes_bytes_(OutputBufferLength) PVOID OutputBuffer, - _In_ ULONG OutputBufferLength - ) -{ - return NtFsControlFile( - FileHandle, - Event, - ApcRoutine, - ApcContext, - IoStatusBlock, - FSCTL_PIPE_TRANSCEIVE, - InputBuffer, - InputBufferLength, - OutputBuffer, - OutputBufferLength - ); -} - -NTSTATUS PhWaitForNamedPipe( - _In_opt_ PUNICODE_STRING FileSystemName, - _In_ PUNICODE_STRING Name, - _In_opt_ PLARGE_INTEGER Timeout, - _In_ BOOLEAN UseDefaultTimeout - ) -{ - NTSTATUS status; - IO_STATUS_BLOCK isb; - UNICODE_STRING localNpfsName; - HANDLE fileSystemHandle; - OBJECT_ATTRIBUTES oa; - PFILE_PIPE_WAIT_FOR_BUFFER waitForBuffer; - ULONG waitForBufferLength; - - if (!FileSystemName) - { - RtlInitUnicodeString(&localNpfsName, L"\\Device\\NamedPipe"); - FileSystemName = &localNpfsName; - } - - InitializeObjectAttributes( - &oa, - FileSystemName, - OBJ_CASE_INSENSITIVE, - NULL, - NULL - ); - - status = NtOpenFile( - &fileSystemHandle, - FILE_READ_ATTRIBUTES | SYNCHRONIZE, - &oa, - &isb, - FILE_SHARE_READ | FILE_SHARE_WRITE, - FILE_SYNCHRONOUS_IO_NONALERT - ); - - if (!NT_SUCCESS(status)) - return status; - - waitForBufferLength = FIELD_OFFSET(FILE_PIPE_WAIT_FOR_BUFFER, Name) + Name->Length; - waitForBuffer = PhAllocate(waitForBufferLength); - - if (UseDefaultTimeout) - { - waitForBuffer->TimeoutSpecified = FALSE; - } - else - { - if (Timeout) - { - waitForBuffer->Timeout = *Timeout; - } - else - { - waitForBuffer->Timeout.LowPart = 0; - waitForBuffer->Timeout.HighPart = MINLONG; // a very long time - } - - waitForBuffer->TimeoutSpecified = TRUE; - } - - waitForBuffer->NameLength = (ULONG)Name->Length; - memcpy(waitForBuffer->Name, Name->Buffer, Name->Length); - - status = NtFsControlFile( - fileSystemHandle, - NULL, - NULL, - NULL, - &isb, - FSCTL_PIPE_WAIT, - waitForBuffer, - waitForBufferLength, - NULL, - 0 - ); - - PhFree(waitForBuffer); - NtClose(fileSystemHandle); - - return status; -} - -NTSTATUS PhImpersonateClientOfNamedPipe( - _In_ HANDLE FileHandle - ) -{ - NTSTATUS status; - IO_STATUS_BLOCK isb; - - status = NtFsControlFile( - FileHandle, - NULL, - NULL, - NULL, - &isb, - FSCTL_PIPE_IMPERSONATE, - NULL, - 0, - NULL, - 0 - ); - - return status; -} +/* + * Process Hacker - + * native wrapper and support functions + * + * Copyright (C) 2009-2016 wj32 + * Copyright (C) 2017 dmex + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include + +#include +#include +#include +#include + +#define PH_DEVICE_PREFIX_LENGTH 64 +#define PH_DEVICE_MUP_PREFIX_MAX_COUNT 16 + +typedef BOOLEAN (NTAPI *PPHP_ENUM_PROCESS_MODULES_CALLBACK)( + _In_ HANDLE ProcessHandle, + _In_ PLDR_DATA_TABLE_ENTRY Entry, + _In_ PVOID AddressOfEntry, + _In_opt_ PVOID Context1, + _In_opt_ PVOID Context2 + ); + +typedef BOOLEAN (NTAPI *PPHP_ENUM_PROCESS_MODULES32_CALLBACK)( + _In_ HANDLE ProcessHandle, + _In_ PLDR_DATA_TABLE_ENTRY32 Entry, + _In_ ULONG AddressOfEntry, + _In_opt_ PVOID Context1, + _In_opt_ PVOID Context2 + ); + +static PH_INITONCE PhDevicePrefixesInitOnce = PH_INITONCE_INIT; + +static UNICODE_STRING PhDevicePrefixes[26]; +static PH_QUEUED_LOCK PhDevicePrefixesLock = PH_QUEUED_LOCK_INIT; + +static PPH_STRING PhDeviceMupPrefixes[PH_DEVICE_MUP_PREFIX_MAX_COUNT] = { 0 }; +static ULONG PhDeviceMupPrefixesCount = 0; +static PH_QUEUED_LOCK PhDeviceMupPrefixesLock = PH_QUEUED_LOCK_INIT; + +static PH_INITONCE PhPredefineKeyInitOnce = PH_INITONCE_INIT; +static UNICODE_STRING PhPredefineKeyNames[PH_KEY_MAXIMUM_PREDEFINE] = +{ + RTL_CONSTANT_STRING(L"\\Registry\\Machine"), + RTL_CONSTANT_STRING(L"\\Registry\\User"), + RTL_CONSTANT_STRING(L"\\Registry\\Machine\\Software\\Classes"), + { 0, 0, NULL } +}; +static HANDLE PhPredefineKeyHandles[PH_KEY_MAXIMUM_PREDEFINE] = { 0 }; + +/** + * Queries information about the token of the current process. + */ +PH_TOKEN_ATTRIBUTES PhGetOwnTokenAttributes( + VOID + ) +{ + static PH_INITONCE initOnce = PH_INITONCE_INIT; + static PH_TOKEN_ATTRIBUTES attributes; + + if (PhBeginInitOnce(&initOnce)) + { + if (NT_SUCCESS(NtOpenProcessToken( + NtCurrentProcess(), + TOKEN_QUERY, + &attributes.TokenHandle + ))) + { + BOOLEAN elevated = TRUE; + TOKEN_ELEVATION_TYPE elevationType = TokenElevationTypeFull; + + if (WINDOWS_HAS_UAC) + { + PhGetTokenIsElevated(attributes.TokenHandle, &elevated); + PhGetTokenElevationType(attributes.TokenHandle, &elevationType); + } + + attributes.Elevated = elevated; + attributes.ElevationType = elevationType; + } + + PhEndInitOnce(&initOnce); + } + + return attributes; +} + +/** + * Opens a process. + * + * \param ProcessHandle A variable which receives a handle to the process. + * \param DesiredAccess The desired access to the process. + * \param ProcessId The ID of the process. + */ +NTSTATUS PhOpenProcess( + _Out_ PHANDLE ProcessHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ HANDLE ProcessId + ) +{ + NTSTATUS status; + OBJECT_ATTRIBUTES objectAttributes; + CLIENT_ID clientId; + + clientId.UniqueProcess = ProcessId; + clientId.UniqueThread = NULL; + + if (KphIsVerified() && (DesiredAccess & KPH_PROCESS_READ_ACCESS) == DesiredAccess) + { + status = KphOpenProcess( + ProcessHandle, + DesiredAccess, + &clientId + ); + } + else + { + InitializeObjectAttributes(&objectAttributes, NULL, 0, NULL, NULL); + status = NtOpenProcess( + ProcessHandle, + DesiredAccess, + &objectAttributes, + &clientId + ); + + if (status == STATUS_ACCESS_DENIED && KphIsVerified()) + { + status = KphOpenProcess( + ProcessHandle, + DesiredAccess, + &clientId + ); + } + } + + return status; +} + +/** Limited API for untrusted/external code. */ +NTSTATUS PhOpenProcessPublic( + _Out_ PHANDLE ProcessHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ HANDLE ProcessId + ) +{ + OBJECT_ATTRIBUTES objectAttributes; + CLIENT_ID clientId; + + InitializeObjectAttributes(&objectAttributes, NULL, 0, NULL, NULL); + clientId.UniqueProcess = ProcessId; + clientId.UniqueThread = NULL; + + return NtOpenProcess( + ProcessHandle, + DesiredAccess, + &objectAttributes, + &clientId + ); +} + +/** + * Opens a thread. + * + * \param ThreadHandle A variable which receives a handle to the thread. + * \param DesiredAccess The desired access to the thread. + * \param ThreadId The ID of the thread. + */ +NTSTATUS PhOpenThread( + _Out_ PHANDLE ThreadHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ HANDLE ThreadId + ) +{ + NTSTATUS status; + OBJECT_ATTRIBUTES objectAttributes; + CLIENT_ID clientId; + + clientId.UniqueProcess = NULL; + clientId.UniqueThread = ThreadId; + + if (KphIsVerified() && (DesiredAccess & KPH_THREAD_READ_ACCESS) == DesiredAccess) + { + status = KphOpenThread( + ThreadHandle, + DesiredAccess, + &clientId + ); + } + else + { + InitializeObjectAttributes(&objectAttributes, NULL, 0, NULL, NULL); + status = NtOpenThread( + ThreadHandle, + DesiredAccess, + &objectAttributes, + &clientId + ); + + if (status == STATUS_ACCESS_DENIED && KphIsVerified()) + { + status = KphOpenThread( + ThreadHandle, + DesiredAccess, + &clientId + ); + } + } + + return status; +} + +/** Limited API for untrusted/external code. */ +NTSTATUS PhOpenThreadPublic( + _Out_ PHANDLE ThreadHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ HANDLE ThreadId + ) +{ + OBJECT_ATTRIBUTES objectAttributes; + CLIENT_ID clientId; + + clientId.UniqueProcess = NULL; + clientId.UniqueThread = ThreadId; + + InitializeObjectAttributes(&objectAttributes, NULL, 0, NULL, NULL); + + return NtOpenThread( + ThreadHandle, + DesiredAccess, + &objectAttributes, + &clientId + ); +} + +NTSTATUS PhOpenThreadProcess( + _In_ HANDLE ThreadHandle, + _In_ ACCESS_MASK DesiredAccess, + _Out_ PHANDLE ProcessHandle + ) +{ + if (KphIsConnected()) + { + return KphOpenThreadProcess( + ThreadHandle, + DesiredAccess, + ProcessHandle + ); + } + else + { + NTSTATUS status; + THREAD_BASIC_INFORMATION basicInfo; + + if (!NT_SUCCESS(status = PhGetThreadBasicInformation( + ThreadHandle, + &basicInfo + ))) + return status; + + return PhOpenProcess( + ProcessHandle, + DesiredAccess, + basicInfo.ClientId.UniqueProcess + ); + } +} + +/** + * Opens a process token. + * + * \param ProcessHandle A handle to a process. + * \param DesiredAccess The desired access to the token. + * \param TokenHandle A variable which receives a handle to the token. + */ +NTSTATUS PhOpenProcessToken( + _In_ HANDLE ProcessHandle, + _In_ ACCESS_MASK DesiredAccess, + _Out_ PHANDLE TokenHandle + ) +{ + NTSTATUS status; + + if (KphIsVerified() && (DesiredAccess & KPH_TOKEN_READ_ACCESS) == DesiredAccess) + { + status = KphOpenProcessToken( + ProcessHandle, + DesiredAccess, + TokenHandle + ); + } + else + { + status = NtOpenProcessToken( + ProcessHandle, + DesiredAccess, + TokenHandle + ); + + if (status == STATUS_ACCESS_DENIED && KphIsVerified()) + { + status = KphOpenProcessToken( + ProcessHandle, + DesiredAccess, + TokenHandle + ); + } + } + + return status; +} + +NTSTATUS PhGetObjectSecurity( + _In_ HANDLE Handle, + _In_ SECURITY_INFORMATION SecurityInformation, + _Out_ PSECURITY_DESCRIPTOR *SecurityDescriptor + ) +{ + NTSTATUS status; + ULONG bufferSize; + PVOID buffer; + + bufferSize = 0x100; + buffer = PhAllocate(bufferSize); + // This is required (especially for File objects) because some drivers don't seem to handle + // QuerySecurity properly. + memset(buffer, 0, bufferSize); + + status = NtQuerySecurityObject( + Handle, + SecurityInformation, + buffer, + bufferSize, + &bufferSize + ); + + if (status == STATUS_BUFFER_TOO_SMALL) + { + PhFree(buffer); + buffer = PhAllocate(bufferSize); + memset(buffer, 0, bufferSize); + + status = NtQuerySecurityObject( + Handle, + SecurityInformation, + buffer, + bufferSize, + &bufferSize + ); + } + + if (!NT_SUCCESS(status)) + { + PhFree(buffer); + return status; + } + + *SecurityDescriptor = (PSECURITY_DESCRIPTOR)buffer; + + return status; +} + +NTSTATUS PhSetObjectSecurity( + _In_ HANDLE Handle, + _In_ SECURITY_INFORMATION SecurityInformation, + _In_ PSECURITY_DESCRIPTOR SecurityDescriptor + ) +{ + return NtSetSecurityObject( + Handle, + SecurityInformation, + SecurityDescriptor + ); +} + +/** + * Terminates a process. + * + * \param ProcessHandle A handle to a process. The handle must have PROCESS_TERMINATE access. + * \param ExitStatus A status value that indicates why the process is being terminated. + */ +NTSTATUS PhTerminateProcess( + _In_ HANDLE ProcessHandle, + _In_ NTSTATUS ExitStatus + ) +{ + NTSTATUS status; + + if (KphIsVerified()) + { + status = KphTerminateProcess( + ProcessHandle, + ExitStatus + ); + + if (status != STATUS_NOT_SUPPORTED) + return status; + } + + return NtTerminateProcess( + ProcessHandle, + ExitStatus + ); +} + +/** Limited API for untrusted/external code. */ +NTSTATUS PhTerminateProcessPublic( + _In_ HANDLE ProcessHandle, + _In_ NTSTATUS ExitStatus + ) +{ + return NtTerminateProcess( + ProcessHandle, + ExitStatus + ); +} + +/** + * Queries variable-sized information for a process. The function allocates a buffer to contain the + * information. + * + * \param ProcessHandle A handle to a process. The access required depends on the information class + * specified. + * \param ProcessInformationClass The information class to retrieve. + * \param Buffer A variable which receives a pointer to a buffer containing the information. You + * must free the buffer using PhFree() when you no longer need it. + */ +NTSTATUS PhpQueryProcessVariableSize( + _In_ HANDLE ProcessHandle, + _In_ PROCESSINFOCLASS ProcessInformationClass, + _Out_ PVOID *Buffer + ) +{ + NTSTATUS status; + PVOID buffer; + ULONG returnLength = 0; + + status = NtQueryInformationProcess( + ProcessHandle, + ProcessInformationClass, + NULL, + 0, + &returnLength + ); + + if (status != STATUS_BUFFER_OVERFLOW && status != STATUS_BUFFER_TOO_SMALL && status != STATUS_INFO_LENGTH_MISMATCH) + return status; + + buffer = PhAllocate(returnLength); + status = NtQueryInformationProcess( + ProcessHandle, + ProcessInformationClass, + buffer, + returnLength, + &returnLength + ); + + if (NT_SUCCESS(status)) + { + *Buffer = buffer; + } + else + { + PhFree(buffer); + } + + return status; +} + +/** + * Gets the file name of the process' image. + * + * \param ProcessHandle A handle to a process. The handle must have + * PROCESS_QUERY_LIMITED_INFORMATION access. + * \param FileName A variable which receives a pointer to a string containing the file name. You + * must free the string using PhDereferenceObject() when you no longer need it. + */ +NTSTATUS PhGetProcessImageFileName( + _In_ HANDLE ProcessHandle, + _Out_ PPH_STRING *FileName + ) +{ + NTSTATUS status; + PUNICODE_STRING fileName; + + status = PhpQueryProcessVariableSize( + ProcessHandle, + ProcessImageFileName, + &fileName + ); + + if (!NT_SUCCESS(status)) + return status; + + *FileName = PhCreateStringFromUnicodeString(fileName); + PhFree(fileName); + + return status; +} + +/** + * Gets the Win32 file name of the process' image. + * + * \param ProcessHandle A handle to a process. The handle must have + * PROCESS_QUERY_LIMITED_INFORMATION access. + * \param FileName A variable which receives a pointer to a string containing the file name. You + * must free the string using PhDereferenceObject() when you no longer need it. + * + * \remarks This function is only available on Windows Vista and above. + */ +NTSTATUS PhGetProcessImageFileNameWin32( + _In_ HANDLE ProcessHandle, + _Out_ PPH_STRING *FileName + ) +{ + NTSTATUS status; + PUNICODE_STRING fileName; + + status = PhpQueryProcessVariableSize( + ProcessHandle, + ProcessImageFileNameWin32, + &fileName + ); + + if (!NT_SUCCESS(status)) + return status; + + *FileName = PhCreateStringFromUnicodeString(fileName); + PhFree(fileName); + + return status; +} + +/** + * Gets a string stored in a process' parameters structure. + * + * \param ProcessHandle A handle to a process. The handle must have + * PROCESS_QUERY_LIMITED_INFORMATION and PROCESS_VM_READ access. + * \param Offset The string to retrieve. + * \param String A variable which receives a pointer to the requested string. You must free the + * string using PhDereferenceObject() when you no longer need it. + * + * \retval STATUS_INVALID_PARAMETER_2 An invalid value was specified in the Offset parameter. + */ +NTSTATUS PhGetProcessPebString( + _In_ HANDLE ProcessHandle, + _In_ PH_PEB_OFFSET Offset, + _Out_ PPH_STRING *String + ) +{ + NTSTATUS status; + PPH_STRING string; + ULONG offset; + +#define PEB_OFFSET_CASE(Enum, Field) \ + case Enum: offset = FIELD_OFFSET(RTL_USER_PROCESS_PARAMETERS, Field); break; \ + case Enum | PhpoWow64: offset = FIELD_OFFSET(RTL_USER_PROCESS_PARAMETERS32, Field); break + + switch (Offset) + { + PEB_OFFSET_CASE(PhpoCurrentDirectory, CurrentDirectory); + PEB_OFFSET_CASE(PhpoDllPath, DllPath); + PEB_OFFSET_CASE(PhpoImagePathName, ImagePathName); + PEB_OFFSET_CASE(PhpoCommandLine, CommandLine); + PEB_OFFSET_CASE(PhpoWindowTitle, WindowTitle); + PEB_OFFSET_CASE(PhpoDesktopInfo, DesktopInfo); + PEB_OFFSET_CASE(PhpoShellInfo, ShellInfo); + PEB_OFFSET_CASE(PhpoRuntimeData, RuntimeData); + default: + return STATUS_INVALID_PARAMETER_2; + } + + if (!(Offset & PhpoWow64)) + { + PROCESS_BASIC_INFORMATION basicInfo; + PVOID processParameters; + UNICODE_STRING unicodeString; + + // Get the PEB address. + if (!NT_SUCCESS(status = PhGetProcessBasicInformation(ProcessHandle, &basicInfo))) + return status; + + // Read the address of the process parameters. + if (!NT_SUCCESS(status = NtReadVirtualMemory( + ProcessHandle, + PTR_ADD_OFFSET(basicInfo.PebBaseAddress, FIELD_OFFSET(PEB, ProcessParameters)), + &processParameters, + sizeof(PVOID), + NULL + ))) + return status; + + // Read the string structure. + if (!NT_SUCCESS(status = NtReadVirtualMemory( + ProcessHandle, + PTR_ADD_OFFSET(processParameters, offset), + &unicodeString, + sizeof(UNICODE_STRING), + NULL + ))) + return status; + + string = PhCreateStringEx(NULL, unicodeString.Length); + + // Read the string contents. + if (!NT_SUCCESS(status = NtReadVirtualMemory( + ProcessHandle, + unicodeString.Buffer, + string->Buffer, + string->Length, + NULL + ))) + { + PhDereferenceObject(string); + return status; + } + } + else + { + PVOID peb32; + ULONG processParameters32; + UNICODE_STRING32 unicodeString32; + + if (!NT_SUCCESS(status = PhGetProcessPeb32(ProcessHandle, &peb32))) + return status; + + if (!NT_SUCCESS(status = NtReadVirtualMemory( + ProcessHandle, + PTR_ADD_OFFSET(peb32, FIELD_OFFSET(PEB32, ProcessParameters)), + &processParameters32, + sizeof(ULONG), + NULL + ))) + return status; + + if (!NT_SUCCESS(status = NtReadVirtualMemory( + ProcessHandle, + PTR_ADD_OFFSET(processParameters32, offset), + &unicodeString32, + sizeof(UNICODE_STRING32), + NULL + ))) + return status; + + string = PhCreateStringEx(NULL, unicodeString32.Length); + + // Read the string contents. + if (!NT_SUCCESS(status = NtReadVirtualMemory( + ProcessHandle, + UlongToPtr(unicodeString32.Buffer), + string->Buffer, + string->Length, + NULL + ))) + { + PhDereferenceObject(string); + return status; + } + } + + *String = string; + + return status; +} + +/** + * Gets a process' command line. + * + * \param ProcessHandle A handle to a process. The handle must have + * PROCESS_QUERY_LIMITED_INFORMATION. Before Windows 8.1, the handle must also have PROCESS_VM_READ + * access. + * \param String A variable which receives a pointer to a string containing the command line. You + * must free the string using PhDereferenceObject() when you no longer need it. + */ +NTSTATUS PhGetProcessCommandLine( + _In_ HANDLE ProcessHandle, + _Out_ PPH_STRING *CommandLine + ) +{ + NTSTATUS status; + + if (WindowsVersion >= WINDOWS_8_1) + { + PUNICODE_STRING commandLine; + + status = PhpQueryProcessVariableSize( + ProcessHandle, + ProcessCommandLineInformation, + &commandLine + ); + + if (NT_SUCCESS(status)) + { + *CommandLine = PhCreateStringFromUnicodeString(commandLine); + PhFree(commandLine); + + return status; + } + } + + return PhGetProcessPebString(ProcessHandle, PhpoCommandLine, CommandLine); +} + +/** + * Gets the window flags and window title of a process. + * + * \param ProcessHandle A handle to a process. The handle must have + * PROCESS_QUERY_LIMITED_INFORMATION. Before Windows 7 SP1, the handle must also have + * PROCESS_VM_READ access. + * \param WindowFlags A variable which receives the window flags. + * \param WindowTitle A variable which receives a pointer to the window title. You must free the + * string using PhDereferenceObject() when you no longer need it. + */ +NTSTATUS PhGetProcessWindowTitle( + _In_ HANDLE ProcessHandle, + _Out_ PULONG WindowFlags, + _Out_ PPH_STRING *WindowTitle + ) +{ + NTSTATUS status; +#ifdef _WIN64 + BOOLEAN isWow64 = FALSE; +#endif + ULONG windowFlags; + + if (WindowsVersion >= WINDOWS_7) + { + PPROCESS_WINDOW_INFORMATION windowInfo; + + status = PhpQueryProcessVariableSize( + ProcessHandle, + ProcessWindowInformation, + &windowInfo + ); + + if (NT_SUCCESS(status)) + { + *WindowFlags = windowInfo->WindowFlags; + *WindowTitle = PhCreateStringEx(windowInfo->WindowTitle, windowInfo->WindowTitleLength); + PhFree(windowInfo); + + return status; + } + } + +#ifdef _WIN64 + PhGetProcessIsWow64(ProcessHandle, &isWow64); + + if (!isWow64) +#endif + { + PROCESS_BASIC_INFORMATION basicInfo; + PVOID processParameters; + + // Get the PEB address. + if (!NT_SUCCESS(status = PhGetProcessBasicInformation(ProcessHandle, &basicInfo))) + return status; + + // Read the address of the process parameters. + if (!NT_SUCCESS(status = NtReadVirtualMemory( + ProcessHandle, + PTR_ADD_OFFSET(basicInfo.PebBaseAddress, FIELD_OFFSET(PEB, ProcessParameters)), + &processParameters, + sizeof(PVOID), + NULL + ))) + return status; + + // Read the window flags. + if (!NT_SUCCESS(status = NtReadVirtualMemory( + ProcessHandle, + PTR_ADD_OFFSET(processParameters, FIELD_OFFSET(RTL_USER_PROCESS_PARAMETERS, WindowFlags)), + &windowFlags, + sizeof(ULONG), + NULL + ))) + return status; + } +#ifdef _WIN64 + else + { + PVOID peb32; + ULONG processParameters32; + + if (!NT_SUCCESS(status = PhGetProcessPeb32(ProcessHandle, &peb32))) + return status; + + if (!NT_SUCCESS(status = NtReadVirtualMemory( + ProcessHandle, + PTR_ADD_OFFSET(peb32, FIELD_OFFSET(PEB32, ProcessParameters)), + &processParameters32, + sizeof(ULONG), + NULL + ))) + return status; + + if (!NT_SUCCESS(status = NtReadVirtualMemory( + ProcessHandle, + PTR_ADD_OFFSET(processParameters32, FIELD_OFFSET(RTL_USER_PROCESS_PARAMETERS32, WindowFlags)), + &windowFlags, + sizeof(ULONG), + NULL + ))) + return status; + } +#endif + +#ifdef _WIN64 + status = PhGetProcessPebString(ProcessHandle, PhpoWindowTitle | (isWow64 ? PhpoWow64 : 0), WindowTitle); +#else + status = PhGetProcessPebString(ProcessHandle, PhpoWindowTitle, WindowTitle); +#endif + + if (NT_SUCCESS(status)) + *WindowFlags = windowFlags; + + return status; +} + +NTSTATUS PhGetProcessDepStatus( + _In_ HANDLE ProcessHandle, + _Out_ PULONG DepStatus + ) +{ + NTSTATUS status; + ULONG executeFlags; + ULONG depStatus; + + if (!NT_SUCCESS(status = PhGetProcessExecuteFlags( + ProcessHandle, + &executeFlags + ))) + return status; + + // Check if execution of data pages is enabled. + if (executeFlags & MEM_EXECUTE_OPTION_ENABLE) + depStatus = 0; + else + depStatus = PH_PROCESS_DEP_ENABLED; + + if (executeFlags & MEM_EXECUTE_OPTION_DISABLE_THUNK_EMULATION) + depStatus |= PH_PROCESS_DEP_ATL_THUNK_EMULATION_DISABLED; + if (executeFlags & MEM_EXECUTE_OPTION_PERMANENT) + depStatus |= PH_PROCESS_DEP_PERMANENT; + + *DepStatus = depStatus; + + return status; +} + +/** + * Gets a process' environment block. + * + * \param ProcessHandle A handle to a process. The handle must have PROCESS_QUERY_INFORMATION and + * PROCESS_VM_READ access. + * \param Flags A combination of flags. + * \li \c PH_GET_PROCESS_ENVIRONMENT_WOW64 Retrieve the environment block from the WOW64 PEB. + * \param Environment A variable which will receive a pointer to the environment block copied from + * the process. You must free the block using PhFreePage() when you no longer need it. + * \param EnvironmentLength A variable which will receive the length of the environment block, in + * bytes. + */ +NTSTATUS PhGetProcessEnvironment( + _In_ HANDLE ProcessHandle, + _In_ ULONG Flags, + _Out_ PVOID *Environment, + _Out_ PULONG EnvironmentLength + ) +{ + NTSTATUS status; + PVOID environmentRemote; + MEMORY_BASIC_INFORMATION mbi; + PVOID environment; + ULONG environmentLength; + + if (!(Flags & PH_GET_PROCESS_ENVIRONMENT_WOW64)) + { + PROCESS_BASIC_INFORMATION basicInfo; + PVOID processParameters; + + status = PhGetProcessBasicInformation(ProcessHandle, &basicInfo); + + if (!NT_SUCCESS(status)) + return status; + + if (!NT_SUCCESS(status = NtReadVirtualMemory( + ProcessHandle, + PTR_ADD_OFFSET(basicInfo.PebBaseAddress, FIELD_OFFSET(PEB, ProcessParameters)), + &processParameters, + sizeof(PVOID), + NULL + ))) + return status; + + if (!NT_SUCCESS(status = NtReadVirtualMemory( + ProcessHandle, + PTR_ADD_OFFSET(processParameters, FIELD_OFFSET(RTL_USER_PROCESS_PARAMETERS, Environment)), + &environmentRemote, + sizeof(PVOID), + NULL + ))) + return status; + } + else + { + PVOID peb32; + ULONG processParameters32; + ULONG environmentRemote32; + + status = PhGetProcessPeb32(ProcessHandle, &peb32); + + if (!NT_SUCCESS(status)) + return status; + + if (!NT_SUCCESS(status = NtReadVirtualMemory( + ProcessHandle, + PTR_ADD_OFFSET(peb32, FIELD_OFFSET(PEB32, ProcessParameters)), + &processParameters32, + sizeof(ULONG), + NULL + ))) + return status; + + if (!NT_SUCCESS(status = NtReadVirtualMemory( + ProcessHandle, + PTR_ADD_OFFSET(processParameters32, FIELD_OFFSET(RTL_USER_PROCESS_PARAMETERS32, Environment)), + &environmentRemote32, + sizeof(ULONG), + NULL + ))) + return status; + + environmentRemote = UlongToPtr(environmentRemote32); + } + + if (!NT_SUCCESS(status = NtQueryVirtualMemory( + ProcessHandle, + environmentRemote, + MemoryBasicInformation, + &mbi, + sizeof(MEMORY_BASIC_INFORMATION), + NULL + ))) + return status; + + environmentLength = (ULONG)(mbi.RegionSize - + ((ULONG_PTR)environmentRemote - (ULONG_PTR)mbi.BaseAddress)); + + // Read in the entire region of memory. + + environment = PhAllocatePage(environmentLength, NULL); + + if (!environment) + return STATUS_NO_MEMORY; + + if (!NT_SUCCESS(status = NtReadVirtualMemory( + ProcessHandle, + environmentRemote, + environment, + environmentLength, + NULL + ))) + { + PhFreePage(environment); + return status; + } + + *Environment = environment; + + if (EnvironmentLength) + *EnvironmentLength = environmentLength; + + return status; +} + +BOOLEAN PhEnumProcessEnvironmentVariables( + _In_ PVOID Environment, + _In_ ULONG EnvironmentLength, + _Inout_ PULONG EnumerationKey, + _Out_ PPH_ENVIRONMENT_VARIABLE Variable + ) +{ + ULONG length; + ULONG startIndex; + PWCHAR name; + ULONG nameLength; + PWCHAR value; + ULONG valueLength; + PWCHAR currentChar; + ULONG currentIndex; + + length = EnvironmentLength / sizeof(WCHAR); + + currentIndex = *EnumerationKey; + currentChar = (PWCHAR)Environment + currentIndex; + startIndex = currentIndex; + name = currentChar; + + // Find the end of the name. + while (TRUE) + { + if (currentIndex >= length) + return FALSE; + if (*currentChar == '=') + break; + if (*currentChar == 0) + return FALSE; // no more variables + + currentIndex++; + currentChar++; + } + + nameLength = currentIndex - startIndex; + + currentIndex++; + currentChar++; + startIndex = currentIndex; + value = currentChar; + + // Find the end of the value. + while (TRUE) + { + if (currentIndex >= length) + return FALSE; + if (*currentChar == 0) + break; + + currentIndex++; + currentChar++; + } + + valueLength = currentIndex - startIndex; + + currentIndex++; + *EnumerationKey = currentIndex; + + Variable->Name.Buffer = name; + Variable->Name.Length = nameLength * sizeof(WCHAR); + Variable->Value.Buffer = value; + Variable->Value.Length = valueLength * sizeof(WCHAR); + + return TRUE; +} + +/** + * Gets the file name of a mapped section. + * + * \param ProcessHandle A handle to a process. The handle must have PROCESS_QUERY_INFORMATION + * access. + * \param BaseAddress The base address of the section view. + * \param FileName A variable which receives a pointer to a string containing the file name of the + * section. You must free the string using PhDereferenceObject() when you no longer need it. + */ +NTSTATUS PhGetProcessMappedFileName( + _In_ HANDLE ProcessHandle, + _In_ PVOID BaseAddress, + _Out_ PPH_STRING *FileName + ) +{ + NTSTATUS status; + PVOID buffer; + SIZE_T bufferSize; + SIZE_T returnLength; + PUNICODE_STRING unicodeString; + + bufferSize = 0x100; + buffer = PhAllocate(bufferSize); + + status = NtQueryVirtualMemory( + ProcessHandle, + BaseAddress, + MemoryMappedFilenameInformation, + buffer, + bufferSize, + &returnLength + ); + + if (status == STATUS_BUFFER_OVERFLOW) + { + PhFree(buffer); + bufferSize = returnLength; + buffer = PhAllocate(bufferSize); + + status = NtQueryVirtualMemory( + ProcessHandle, + BaseAddress, + MemoryMappedFilenameInformation, + buffer, + bufferSize, + &returnLength + ); + } + + if (!NT_SUCCESS(status)) + { + PhFree(buffer); + return status; + } + + unicodeString = (PUNICODE_STRING)buffer; + *FileName = PhCreateStringEx( + unicodeString->Buffer, + unicodeString->Length + ); + PhFree(buffer); + + return status; +} + +/** + * Gets working set information for a process. + * + * \param ProcessHandle A handle to a process. The handle must have PROCESS_QUERY_INFORMATION + * access. + * \param WorkingSetInformation A variable which receives a pointer to the information. You must + * free the buffer using PhFree() when you no longer need it. + */ +NTSTATUS PhGetProcessWorkingSetInformation( + _In_ HANDLE ProcessHandle, + _Out_ PMEMORY_WORKING_SET_INFORMATION *WorkingSetInformation + ) +{ + NTSTATUS status; + PVOID buffer; + SIZE_T bufferSize; + + bufferSize = 0x8000; + buffer = PhAllocate(bufferSize); + + while ((status = NtQueryVirtualMemory( + ProcessHandle, + NULL, + MemoryWorkingSetInformation, + buffer, + bufferSize, + NULL + )) == STATUS_INFO_LENGTH_MISMATCH) + { + PhFree(buffer); + bufferSize *= 2; + + // Fail if we're resizing the buffer to something very large. + if (bufferSize > PH_LARGE_BUFFER_SIZE) + return STATUS_INSUFFICIENT_RESOURCES; + + buffer = PhAllocate(bufferSize); + } + + if (!NT_SUCCESS(status)) + { + PhFree(buffer); + return status; + } + + *WorkingSetInformation = (PMEMORY_WORKING_SET_INFORMATION)buffer; + + return status; +} + +/** + * Gets working set counters for a process. + * + * \param ProcessHandle A handle to a process. The handle must have PROCESS_QUERY_INFORMATION + * access. + * \param WsCounters A variable which receives the counters. + */ +NTSTATUS PhGetProcessWsCounters( + _In_ HANDLE ProcessHandle, + _Out_ PPH_PROCESS_WS_COUNTERS WsCounters + ) +{ + NTSTATUS status; + PMEMORY_WORKING_SET_INFORMATION wsInfo; + PH_PROCESS_WS_COUNTERS wsCounters; + ULONG_PTR i; + + if (!NT_SUCCESS(status = PhGetProcessWorkingSetInformation( + ProcessHandle, + &wsInfo + ))) + return status; + + memset(&wsCounters, 0, sizeof(PH_PROCESS_WS_COUNTERS)); + + for (i = 0; i < wsInfo->NumberOfEntries; i++) + { + wsCounters.NumberOfPages++; + + if (wsInfo->WorkingSetInfo[i].ShareCount > 1) + wsCounters.NumberOfSharedPages++; + if (wsInfo->WorkingSetInfo[i].ShareCount == 0) + wsCounters.NumberOfPrivatePages++; + if (wsInfo->WorkingSetInfo[i].Shared) + wsCounters.NumberOfShareablePages++; + } + + PhFree(wsInfo); + + *WsCounters = wsCounters; + + return status; +} + +/** + * Causes a process to load a DLL. + * + * \param ProcessHandle A handle to a process. The handle must have + * PROCESS_QUERY_LIMITED_INFORMATION, PROCESS_CREATE_THREAD, PROCESS_VM_OPERATION, PROCESS_VM_READ + * and PROCESS_VM_WRITE access. + * \param FileName The file name of the DLL to inject. + * \param Timeout The timeout, in milliseconds, for the process to load the DLL. + * + * \remarks If the process does not load the DLL before the timeout expires it may crash. Choose the + * timeout value carefully. + */ +NTSTATUS PhInjectDllProcess( + _In_ HANDLE ProcessHandle, + _In_ PWSTR FileName, + _In_opt_ PLARGE_INTEGER Timeout + ) +{ +#ifdef _WIN64 + static PVOID loadLibraryW32 = NULL; +#endif + + NTSTATUS status; +#ifdef _WIN64 + BOOLEAN isWow64 = FALSE; + BOOLEAN isModule32 = FALSE; + PH_MAPPED_IMAGE mappedImage; +#endif + PVOID threadStart; + PH_STRINGREF fileName; + PVOID baseAddress = NULL; + SIZE_T allocSize; + HANDLE threadHandle; + +#ifdef _WIN64 + PhGetProcessIsWow64(ProcessHandle, &isWow64); + + if (isWow64) + { + if (!NT_SUCCESS(status = PhLoadMappedImage(FileName, NULL, TRUE, &mappedImage))) + return status; + + isModule32 = mappedImage.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC; + PhUnloadMappedImage(&mappedImage); + } + + if (!isModule32) + { +#endif + threadStart = PhGetModuleProcAddress(L"kernel32.dll", "LoadLibraryW"); +#ifdef _WIN64 + } + else + { + threadStart = loadLibraryW32; + + if (!threadStart) + { + PPH_STRING kernel32FileName; + + kernel32FileName = PhConcatStrings2(USER_SHARED_DATA->NtSystemRoot, L"\\SysWow64\\kernel32.dll"); + status = PhGetProcedureAddressRemote( + ProcessHandle, + kernel32FileName->Buffer, + "LoadLibraryW", + 0, + &loadLibraryW32, + NULL + ); + PhDereferenceObject(kernel32FileName); + + if (!NT_SUCCESS(status)) + return status; + + threadStart = loadLibraryW32; + } + } +#endif + + PhInitializeStringRefLongHint(&fileName, FileName); + allocSize = fileName.Length + sizeof(WCHAR); + + if (!NT_SUCCESS(status = NtAllocateVirtualMemory( + ProcessHandle, + &baseAddress, + 0, + &allocSize, + MEM_COMMIT, + PAGE_READWRITE + ))) + return status; + + if (!NT_SUCCESS(status = NtWriteVirtualMemory( + ProcessHandle, + baseAddress, + fileName.Buffer, + fileName.Length + sizeof(WCHAR), + NULL + ))) + goto FreeExit; + + // Vista seems to support native threads better than XP. + if (WindowsVersion >= WINDOWS_VISTA) + { + if (!NT_SUCCESS(status = RtlCreateUserThread( + ProcessHandle, + NULL, + FALSE, + 0, + 0, + 0, + (PUSER_THREAD_START_ROUTINE)threadStart, + baseAddress, + &threadHandle, + NULL + ))) + goto FreeExit; + } + else + { + if (!(threadHandle = CreateRemoteThread( + ProcessHandle, + NULL, + 0, + (PTHREAD_START_ROUTINE)threadStart, + baseAddress, + 0, + NULL + ))) + { + status = PhGetLastWin32ErrorAsNtStatus(); + goto FreeExit; + } + } + + // Wait for the thread to finish. + status = NtWaitForSingleObject(threadHandle, FALSE, Timeout); + NtClose(threadHandle); + +FreeExit: + // Size needs to be zero if we're freeing. + allocSize = 0; + NtFreeVirtualMemory( + ProcessHandle, + &baseAddress, + &allocSize, + MEM_RELEASE + ); + + return status; +} + +/** + * Causes a process to unload a DLL. + * + * \param ProcessHandle A handle to a process. The handle must have + * PROCESS_QUERY_LIMITED_INFORMATION, PROCESS_CREATE_THREAD, PROCESS_VM_OPERATION, PROCESS_VM_READ + * and PROCESS_VM_WRITE access. + * \param BaseAddress The base address of the DLL to unload. + * \param Timeout The timeout, in milliseconds, for the process to unload the DLL. + */ +NTSTATUS PhUnloadDllProcess( + _In_ HANDLE ProcessHandle, + _In_ PVOID BaseAddress, + _In_opt_ PLARGE_INTEGER Timeout + ) +{ +#ifdef _WIN64 + static PVOID ldrUnloadDll32 = NULL; +#endif + + NTSTATUS status; +#ifdef _WIN64 + BOOLEAN isWow64 = FALSE; + BOOLEAN isModule32 = FALSE; +#endif + HANDLE threadHandle; + THREAD_BASIC_INFORMATION basicInfo; + PVOID threadStart; + +#ifdef _WIN64 + PhGetProcessIsWow64(ProcessHandle, &isWow64); +#endif + + // No point trying to set the load count on Windows 8 and higher, because NT now uses a DAG of + // loader nodes. + if (WindowsVersion < WINDOWS_8) + { + status = PhSetProcessModuleLoadCount( + ProcessHandle, + BaseAddress, + 1 + ); + +#ifdef _WIN64 + if (isWow64 && status == STATUS_DLL_NOT_FOUND) + { + // The DLL might be 32-bit. + status = PhSetProcessModuleLoadCount32( + ProcessHandle, + BaseAddress, + 1 + ); + + if (NT_SUCCESS(status)) + isModule32 = TRUE; + } +#endif + + if (!NT_SUCCESS(status)) + return status; + } + +#ifdef _WIN64 + if (!isModule32) + { +#endif + threadStart = PhGetModuleProcAddress(L"ntdll.dll", "LdrUnloadDll"); +#ifdef _WIN64 + } + else + { + threadStart = ldrUnloadDll32; + + if (!threadStart) + { + PPH_STRING ntdll32FileName; + + ntdll32FileName = PhConcatStrings2(USER_SHARED_DATA->NtSystemRoot, L"\\SysWow64\\ntdll.dll"); + status = PhGetProcedureAddressRemote( + ProcessHandle, + ntdll32FileName->Buffer, + "LdrUnloadDll", + 0, + &ldrUnloadDll32, + NULL + ); + PhDereferenceObject(ntdll32FileName); + + if (!NT_SUCCESS(status)) + return status; + + threadStart = ldrUnloadDll32; + } + } +#endif + + if (WindowsVersion >= WINDOWS_VISTA) + { + status = RtlCreateUserThread( + ProcessHandle, + NULL, + FALSE, + 0, + 0, + 0, + (PUSER_THREAD_START_ROUTINE)threadStart, + BaseAddress, + &threadHandle, + NULL + ); + } + else + { + if (!(threadHandle = CreateRemoteThread( + ProcessHandle, + NULL, + 0, + (PTHREAD_START_ROUTINE)threadStart, + BaseAddress, + 0, + NULL + ))) + { + status = PhGetLastWin32ErrorAsNtStatus(); + } + } + + if (!NT_SUCCESS(status)) + return status; + + status = NtWaitForSingleObject(threadHandle, FALSE, Timeout); + + if (status == STATUS_WAIT_0) + { + status = PhGetThreadBasicInformation(threadHandle, &basicInfo); + + if (NT_SUCCESS(status)) + status = basicInfo.ExitStatus; + } + + NtClose(threadHandle); + + return status; +} + +// Contributed by dmex +/** + * Sets an environment variable in a process. + * + * \param ProcessHandle A handle to a process. The handle must have + * PROCESS_QUERY_LIMITED_INFORMATION, PROCESS_CREATE_THREAD, PROCESS_VM_OPERATION, PROCESS_VM_READ + * and PROCESS_VM_WRITE access. + * \param Name The name of the environment variable to set. + * \param Value The new value of the environment variable. If this parameter is NULL, the + * environment variable is deleted. + * \param Timeout The timeout, in milliseconds, for the process to set the environment variable. + */ +NTSTATUS PhSetEnvironmentVariableRemote( + _In_ HANDLE ProcessHandle, + _In_ PPH_STRINGREF Name, + _In_opt_ PPH_STRINGREF Value, + _In_opt_ PLARGE_INTEGER Timeout + ) +{ + NTSTATUS status; +#ifdef _WIN64 + BOOLEAN isWow64; +#endif + PPH_STRING ntdllFileName = NULL; + PPH_STRING kernel32FileName = NULL; + PVOID nameBaseAddress = NULL; + PVOID valueBaseAddress = NULL; + SIZE_T nameAllocationSize = 0; + SIZE_T valueAllocationSize = 0; + PVOID rtlExitUserThread = NULL; + PVOID setEnvironmentVariableW = NULL; + HANDLE threadHandle = NULL; + + nameAllocationSize = Name->Length + sizeof(WCHAR); + + if (Value) + valueAllocationSize = Value->Length + sizeof(WCHAR); + +#ifdef _WIN64 + if (!NT_SUCCESS(status = PhGetProcessIsWow64(ProcessHandle, &isWow64))) + goto CleanupExit; + + if (isWow64) + { + ntdllFileName = PhConcatStrings2(USER_SHARED_DATA->NtSystemRoot, L"\\SysWow64\\ntdll.dll"); + kernel32FileName = PhConcatStrings2(USER_SHARED_DATA->NtSystemRoot, L"\\SysWow64\\kernel32.dll"); + } + else + { +#endif + ntdllFileName = PhConcatStrings2(USER_SHARED_DATA->NtSystemRoot, L"\\System32\\ntdll.dll"); + kernel32FileName = PhConcatStrings2(USER_SHARED_DATA->NtSystemRoot, L"\\System32\\kernel32.dll"); +#ifdef _WIN64 + } +#endif + + if (!NT_SUCCESS(status = PhGetProcedureAddressRemote( + ProcessHandle, + ntdllFileName->Buffer, + "RtlExitUserThread", + 0, + &rtlExitUserThread, + NULL + ))) + { + goto CleanupExit; + } + if (!NT_SUCCESS(status = PhGetProcedureAddressRemote( + ProcessHandle, + kernel32FileName->Buffer, + "SetEnvironmentVariableW", + 0, + &setEnvironmentVariableW, + NULL + ))) + { + goto CleanupExit; + } + if (!NT_SUCCESS(status = NtAllocateVirtualMemory( + ProcessHandle, + &nameBaseAddress, + 0, + &nameAllocationSize, + MEM_COMMIT, + PAGE_READWRITE + ))) + { + goto CleanupExit; + } + if (!NT_SUCCESS(status = NtWriteVirtualMemory( + ProcessHandle, + nameBaseAddress, + Name->Buffer, + Name->Length, + NULL + ))) + { + goto CleanupExit; + } + + if (Value) + { + if (!NT_SUCCESS(status = NtAllocateVirtualMemory( + ProcessHandle, + &valueBaseAddress, + 0, + &valueAllocationSize, + MEM_COMMIT, + PAGE_READWRITE + ))) + { + goto CleanupExit; + } + if (!NT_SUCCESS(status = NtWriteVirtualMemory( + ProcessHandle, + valueBaseAddress, + Value->Buffer, + Value->Length, + NULL + ))) + { + goto CleanupExit; + } + } + + if (WindowsVersion >= WINDOWS_VISTA) + { + if (!NT_SUCCESS(status = RtlCreateUserThread( + ProcessHandle, + NULL, + TRUE, + 0, + 0, + 0, + (PUSER_THREAD_START_ROUTINE)rtlExitUserThread, + NULL, + &threadHandle, + NULL + ))) + { + goto CleanupExit; + } + } + else + { + if (!(threadHandle = CreateRemoteThread( + ProcessHandle, + NULL, + 0, + (PTHREAD_START_ROUTINE)rtlExitUserThread, + NULL, + CREATE_SUSPENDED, + NULL + ))) + { + status = PhGetLastWin32ErrorAsNtStatus(); + goto CleanupExit; + } + } + +#ifdef _WIN64 + if (isWow64) + { + // NtQueueApcThread doesn't work for WOW64 processes - we need to use RtlQueueApcWow64Thread + // instead. + if (!NT_SUCCESS(status = RtlQueueApcWow64Thread( + threadHandle, + setEnvironmentVariableW, + nameBaseAddress, + valueBaseAddress, + NULL + ))) + { + goto CleanupExit; + } + } + else + { +#endif + if (!NT_SUCCESS(status = NtQueueApcThread( + threadHandle, + setEnvironmentVariableW, + nameBaseAddress, + valueBaseAddress, + NULL + ))) + { + goto CleanupExit; + } +#ifdef _WIN64 + } +#endif + + // This causes our APC to be executed. + NtResumeThread(threadHandle, NULL); + status = NtWaitForSingleObject(threadHandle, FALSE, Timeout); + +CleanupExit: + if (threadHandle) + NtClose(threadHandle); + if (nameBaseAddress) + { + nameAllocationSize = 0; + NtFreeVirtualMemory( + ProcessHandle, + &nameBaseAddress, + &nameAllocationSize, + MEM_RELEASE + ); + } + if (valueBaseAddress) + { + valueAllocationSize = 0; + NtFreeVirtualMemory( + ProcessHandle, + &valueBaseAddress, + &valueAllocationSize, + MEM_RELEASE + ); + } + PhClearReference(&ntdllFileName); + PhClearReference(&kernel32FileName); + + return status; +} + +NTSTATUS PhGetJobProcessIdList( + _In_ HANDLE JobHandle, + _Out_ PJOBOBJECT_BASIC_PROCESS_ID_LIST *ProcessIdList + ) +{ + NTSTATUS status; + PVOID buffer; + ULONG bufferSize; + + bufferSize = 0x100; + buffer = PhAllocate(bufferSize); + + status = NtQueryInformationJobObject( + JobHandle, + JobObjectBasicProcessIdList, + buffer, + bufferSize, + &bufferSize + ); + + if (status == STATUS_BUFFER_OVERFLOW) + { + PhFree(buffer); + buffer = PhAllocate(bufferSize); + + status = NtQueryInformationJobObject( + JobHandle, + JobObjectBasicProcessIdList, + buffer, + bufferSize, + NULL + ); + } + + if (!NT_SUCCESS(status)) + { + PhFree(buffer); + return status; + } + + *ProcessIdList = (PJOBOBJECT_BASIC_PROCESS_ID_LIST)buffer; + + return status; +} + +/** + * Queries variable-sized information for a token. The function allocates a buffer to contain the + * information. + * + * \param TokenHandle A handle to a token. The access required depends on the information class + * specified. + * \param TokenInformationClass The information class to retrieve. + * \param Buffer A variable which receives a pointer to a buffer containing the information. You + * must free the buffer using PhFree() when you no longer need it. + */ +NTSTATUS PhpQueryTokenVariableSize( + _In_ HANDLE TokenHandle, + _In_ TOKEN_INFORMATION_CLASS TokenInformationClass, + _Out_ PVOID *Buffer + ) +{ + NTSTATUS status; + PVOID buffer; + ULONG returnLength = 0; + + NtQueryInformationToken( + TokenHandle, + TokenInformationClass, + NULL, + 0, + &returnLength + ); + buffer = PhAllocate(returnLength); + status = NtQueryInformationToken( + TokenHandle, + TokenInformationClass, + buffer, + returnLength, + &returnLength + ); + + if (NT_SUCCESS(status)) + { + *Buffer = buffer; + } + else + { + PhFree(buffer); + } + + return status; +} + +/** + * Queries variable-sized information for a token. The function allocates a buffer to contain the + * information. + * + * \param TokenHandle A handle to a token. The access required depends on the information class + * specified. + * \param TokenInformationClass The information class to retrieve. + * \param Buffer A variable which receives a pointer to a buffer containing the information. You + * must free the buffer using PhFree() when you no longer need it. + */ +NTSTATUS PhQueryTokenVariableSize( + _In_ HANDLE TokenHandle, + _In_ TOKEN_INFORMATION_CLASS TokenInformationClass, + _Out_ PVOID *Buffer + ) +{ + return PhpQueryTokenVariableSize( + TokenHandle, + TokenInformationClass, + Buffer + ); +} + +/** + * Gets a token's user. + * + * \param TokenHandle A handle to a token. The handle must have TOKEN_QUERY access. + * \param User A variable which receives a pointer to a structure containing the token's user. You + * must free the structure using PhFree() when you no longer need it. + */ +NTSTATUS PhGetTokenUser( + _In_ HANDLE TokenHandle, + _Out_ PTOKEN_USER *User + ) +{ + return PhpQueryTokenVariableSize( + TokenHandle, + TokenUser, + User + ); +} + +/** + * Gets a token's owner. + * + * \param TokenHandle A handle to a token. The handle must have TOKEN_QUERY access. + * \param Owner A variable which receives a pointer to a structure containing the token's owner. You + * must free the structure using PhFree() when you no longer need it. + */ +NTSTATUS PhGetTokenOwner( + _In_ HANDLE TokenHandle, + _Out_ PTOKEN_OWNER *Owner + ) +{ + return PhpQueryTokenVariableSize( + TokenHandle, + TokenOwner, + Owner + ); +} + +/** + * Gets a token's primary group. + * + * \param TokenHandle A handle to a token. The handle must have TOKEN_QUERY access. + * \param PrimaryGroup A variable which receives a pointer to a structure containing the token's + * primary group. You must free the structure using PhFree() when you no longer need it. + */ +NTSTATUS PhGetTokenPrimaryGroup( + _In_ HANDLE TokenHandle, + _Out_ PTOKEN_PRIMARY_GROUP *PrimaryGroup + ) +{ + return PhpQueryTokenVariableSize( + TokenHandle, + TokenPrimaryGroup, + PrimaryGroup + ); +} + +/** + * Gets a token's groups. + * + * \param TokenHandle A handle to a token. The handle must have TOKEN_QUERY access. + * \param Groups A variable which receives a pointer to a structure containing the token's groups. + * You must free the structure using PhFree() when you no longer need it. + */ +NTSTATUS PhGetTokenGroups( + _In_ HANDLE TokenHandle, + _Out_ PTOKEN_GROUPS *Groups + ) +{ + return PhpQueryTokenVariableSize( + TokenHandle, + TokenGroups, + Groups + ); +} + +/** + * Gets a token's privileges. + * + * \param TokenHandle A handle to a token. The handle must have TOKEN_QUERY access. + * \param Privileges A variable which receives a pointer to a structure containing the token's + * privileges. You must free the structure using PhFree() when you no longer need it. + */ +NTSTATUS PhGetTokenPrivileges( + _In_ HANDLE TokenHandle, + _Out_ PTOKEN_PRIVILEGES *Privileges + ) +{ + return PhpQueryTokenVariableSize( + TokenHandle, + TokenPrivileges, + Privileges + ); +} + +NTSTATUS PhSetTokenSessionId( + _In_ HANDLE TokenHandle, + _In_ ULONG SessionId + ) +{ + return NtSetInformationToken( + TokenHandle, + TokenSessionId, + &SessionId, + sizeof(ULONG) + ); +} + +/** + * Modifies a token privilege. + * + * \param TokenHandle A handle to a token. The handle must have TOKEN_ADJUST_PRIVILEGES access. + * \param PrivilegeName The name of the privilege to modify. If this parameter is NULL, you must + * specify a LUID in the \a PrivilegeLuid parameter. + * \param PrivilegeLuid The LUID of the privilege to modify. If this parameter is NULL, you must + * specify a name in the \a PrivilegeName parameter. + * \param Attributes The new attributes of the privilege. + */ +BOOLEAN PhSetTokenPrivilege( + _In_ HANDLE TokenHandle, + _In_opt_ PWSTR PrivilegeName, + _In_opt_ PLUID PrivilegeLuid, + _In_ ULONG Attributes + ) +{ + NTSTATUS status; + TOKEN_PRIVILEGES privileges; + + privileges.PrivilegeCount = 1; + privileges.Privileges[0].Attributes = Attributes; + + if (PrivilegeLuid) + { + privileges.Privileges[0].Luid = *PrivilegeLuid; + } + else if (PrivilegeName) + { + PH_STRINGREF privilegeName; + + PhInitializeStringRef(&privilegeName, PrivilegeName); + + if (!PhLookupPrivilegeValue( + &privilegeName, + &privileges.Privileges[0].Luid + )) + return FALSE; + } + else + { + return FALSE; + } + + if (!NT_SUCCESS(status = NtAdjustPrivilegesToken( + TokenHandle, + FALSE, + &privileges, + 0, + NULL, + NULL + ))) + return FALSE; + + if (status == STATUS_NOT_ALL_ASSIGNED) + return FALSE; + + return TRUE; +} + +BOOLEAN PhSetTokenPrivilege2( + _In_ HANDLE TokenHandle, + _In_ LONG Privilege, + _In_ ULONG Attributes + ) +{ + LUID privilegeLuid; + + privilegeLuid = RtlConvertLongToLuid(Privilege); + + return PhSetTokenPrivilege(TokenHandle, NULL, &privilegeLuid, Attributes); +} + +/** + * Sets whether virtualization is enabled for a token. + * + * \param TokenHandle A handle to a token. The handle must have TOKEN_WRITE access. + * \param IsVirtualizationEnabled A boolean indicating whether virtualization is to be enabled for + * the token. + */ +NTSTATUS PhSetTokenIsVirtualizationEnabled( + _In_ HANDLE TokenHandle, + _In_ BOOLEAN IsVirtualizationEnabled + ) +{ + ULONG virtualizationEnabled; + + virtualizationEnabled = IsVirtualizationEnabled; + + return NtSetInformationToken( + TokenHandle, + TokenVirtualizationEnabled, + &virtualizationEnabled, + sizeof(ULONG) + ); +} + +/** + * Gets a token's integrity level. + * + * \param TokenHandle A handle to a token. The handle must have TOKEN_QUERY access. + * \param IntegrityLevel A variable which receives the integrity level of the token. + * \param IntegrityString A variable which receives a pointer to a string containing a string + * representation of the integrity level. + */ +NTSTATUS PhGetTokenIntegrityLevel( + _In_ HANDLE TokenHandle, + _Out_opt_ PMANDATORY_LEVEL IntegrityLevel, + _Out_opt_ PWSTR *IntegrityString + ) +{ + NTSTATUS status; + PTOKEN_MANDATORY_LABEL mandatoryLabel; + ULONG subAuthority; + MANDATORY_LEVEL integrityLevel; + PWSTR integrityString; + + status = PhpQueryTokenVariableSize(TokenHandle, TokenIntegrityLevel, &mandatoryLabel); + + if (!NT_SUCCESS(status)) + return status; + + subAuthority = *RtlSubAuthoritySid(mandatoryLabel->Label.Sid, 0); + PhFree(mandatoryLabel); + + switch (subAuthority) + { + case SECURITY_MANDATORY_UNTRUSTED_RID: + integrityLevel = MandatoryLevelUntrusted; + integrityString = L"Untrusted"; + break; + case SECURITY_MANDATORY_LOW_RID: + integrityLevel = MandatoryLevelLow; + integrityString = L"Low"; + break; + case SECURITY_MANDATORY_MEDIUM_RID: + integrityLevel = MandatoryLevelMedium; + integrityString = L"Medium"; + break; + case SECURITY_MANDATORY_HIGH_RID: + integrityLevel = MandatoryLevelHigh; + integrityString = L"High"; + break; + case SECURITY_MANDATORY_SYSTEM_RID: + integrityLevel = MandatoryLevelSystem; + integrityString = L"System"; + break; + case SECURITY_MANDATORY_PROTECTED_PROCESS_RID: + integrityLevel = MandatoryLevelSecureProcess; + integrityString = L"Protected"; + break; + default: + return STATUS_UNSUCCESSFUL; + } + + if (IntegrityLevel) + *IntegrityLevel = integrityLevel; + if (IntegrityString) + *IntegrityString = integrityString; + + return status; +} + +NTSTATUS PhpQueryFileVariableSize( + _In_ HANDLE FileHandle, + _In_ FILE_INFORMATION_CLASS FileInformationClass, + _Out_ PVOID *Buffer + ) +{ + NTSTATUS status; + IO_STATUS_BLOCK isb; + PVOID buffer; + ULONG bufferSize = 0x200; + + buffer = PhAllocate(bufferSize); + + while (TRUE) + { + status = NtQueryInformationFile( + FileHandle, + &isb, + buffer, + bufferSize, + FileInformationClass + ); + + if (status == STATUS_BUFFER_OVERFLOW || status == STATUS_BUFFER_TOO_SMALL || status == STATUS_INFO_LENGTH_MISMATCH) + { + PhFree(buffer); + bufferSize *= 2; + buffer = PhAllocate(bufferSize); + } + else + { + break; + } + } + + if (NT_SUCCESS(status)) + { + *Buffer = buffer; + } + else + { + PhFree(buffer); + } + + return status; +} + +NTSTATUS PhGetFileSize( + _In_ HANDLE FileHandle, + _Out_ PLARGE_INTEGER Size + ) +{ + NTSTATUS status; + FILE_STANDARD_INFORMATION standardInfo; + IO_STATUS_BLOCK isb; + + status = NtQueryInformationFile( + FileHandle, + &isb, + &standardInfo, + sizeof(FILE_STANDARD_INFORMATION), + FileStandardInformation + ); + + if (!NT_SUCCESS(status)) + return status; + + *Size = standardInfo.EndOfFile; + + return status; +} + +NTSTATUS PhSetFileSize( + _In_ HANDLE FileHandle, + _In_ PLARGE_INTEGER Size + ) +{ + FILE_END_OF_FILE_INFORMATION endOfFileInfo; + IO_STATUS_BLOCK isb; + + endOfFileInfo.EndOfFile = *Size; + + return NtSetInformationFile( + FileHandle, + &isb, + &endOfFileInfo, + sizeof(FILE_END_OF_FILE_INFORMATION), + FileEndOfFileInformation + ); +} + +NTSTATUS PhpQueryTransactionManagerVariableSize( + _In_ HANDLE TransactionManagerHandle, + _In_ TRANSACTIONMANAGER_INFORMATION_CLASS TransactionManagerInformationClass, + _Out_ PVOID *Buffer + ) +{ + NTSTATUS status; + PVOID buffer; + ULONG bufferSize = 0x100; + + if (!NtQueryInformationTransactionManager_Import()) + return STATUS_NOT_SUPPORTED; + + buffer = PhAllocate(bufferSize); + + while (TRUE) + { + status = NtQueryInformationTransactionManager_Import()( + TransactionManagerHandle, + TransactionManagerInformationClass, + buffer, + bufferSize, + NULL + ); + + if (status == STATUS_BUFFER_OVERFLOW) + { + PhFree(buffer); + bufferSize *= 2; + + if (bufferSize > 1 * 1024 * 1024) + return STATUS_INSUFFICIENT_RESOURCES; + + buffer = PhAllocate(bufferSize); + } + else + { + break; + } + } + + if (NT_SUCCESS(status)) + { + *Buffer = buffer; + } + else + { + PhFree(buffer); + } + + return status; +} + +NTSTATUS PhGetTransactionManagerBasicInformation( + _In_ HANDLE TransactionManagerHandle, + _Out_ PTRANSACTIONMANAGER_BASIC_INFORMATION BasicInformation + ) +{ + if (NtQueryInformationTransactionManager_Import()) + { + return NtQueryInformationTransactionManager_Import()( + TransactionManagerHandle, + TransactionManagerBasicInformation, + BasicInformation, + sizeof(TRANSACTIONMANAGER_BASIC_INFORMATION), + NULL + ); + } + else + { + return STATUS_NOT_SUPPORTED; + } +} + +NTSTATUS PhGetTransactionManagerLogFileName( + _In_ HANDLE TransactionManagerHandle, + _Out_ PPH_STRING *LogFileName + ) +{ + NTSTATUS status; + PTRANSACTIONMANAGER_LOGPATH_INFORMATION logPathInfo; + + status = PhpQueryTransactionManagerVariableSize( + TransactionManagerHandle, + TransactionManagerLogPathInformation, + &logPathInfo + ); + + if (!NT_SUCCESS(status)) + return status; + + *LogFileName = PhCreateStringEx( + logPathInfo->LogPath, + logPathInfo->LogPathLength + ); + PhFree(logPathInfo); + + return status; +} + +NTSTATUS PhpQueryTransactionVariableSize( + _In_ HANDLE TransactionHandle, + _In_ TRANSACTION_INFORMATION_CLASS TransactionInformationClass, + _Out_ PVOID *Buffer + ) +{ + NTSTATUS status; + PVOID buffer; + ULONG bufferSize = 0x100; + + if (!NtQueryInformationTransaction_Import()) + return STATUS_NOT_SUPPORTED; + + buffer = PhAllocate(bufferSize); + + while (TRUE) + { + status = NtQueryInformationTransaction_Import()( + TransactionHandle, + TransactionInformationClass, + buffer, + bufferSize, + NULL + ); + + if (status == STATUS_BUFFER_OVERFLOW) + { + PhFree(buffer); + bufferSize *= 2; + + if (bufferSize > 1 * 1024 * 1024) + return STATUS_INSUFFICIENT_RESOURCES; + + buffer = PhAllocate(bufferSize); + } + else + { + break; + } + } + + if (NT_SUCCESS(status)) + { + *Buffer = buffer; + } + else + { + PhFree(buffer); + } + + return status; +} + +NTSTATUS PhGetTransactionBasicInformation( + _In_ HANDLE TransactionHandle, + _Out_ PTRANSACTION_BASIC_INFORMATION BasicInformation + ) +{ + if (NtQueryInformationTransaction_Import()) + { + return NtQueryInformationTransaction_Import()( + TransactionHandle, + TransactionBasicInformation, + BasicInformation, + sizeof(TRANSACTION_BASIC_INFORMATION), + NULL + ); + } + else + { + return STATUS_NOT_SUPPORTED; + } +} + +NTSTATUS PhGetTransactionPropertiesInformation( + _In_ HANDLE TransactionHandle, + _Out_opt_ PLARGE_INTEGER Timeout, + _Out_opt_ TRANSACTION_OUTCOME *Outcome, + _Out_opt_ PPH_STRING *Description + ) +{ + NTSTATUS status; + PTRANSACTION_PROPERTIES_INFORMATION propertiesInfo; + + status = PhpQueryTransactionVariableSize( + TransactionHandle, + TransactionPropertiesInformation, + &propertiesInfo + ); + + if (!NT_SUCCESS(status)) + return status; + + if (Timeout) + { + *Timeout = propertiesInfo->Timeout; + } + + if (Outcome) + { + *Outcome = propertiesInfo->Outcome; + } + + if (Description) + { + *Description = PhCreateStringEx( + propertiesInfo->Description, + propertiesInfo->DescriptionLength + ); + } + + PhFree(propertiesInfo); + + return status; +} + +NTSTATUS PhpQueryResourceManagerVariableSize( + _In_ HANDLE ResourceManagerHandle, + _In_ RESOURCEMANAGER_INFORMATION_CLASS ResourceManagerInformationClass, + _Out_ PVOID *Buffer + ) +{ + NTSTATUS status; + PVOID buffer; + ULONG bufferSize = 0x100; + + if (!NtQueryInformationResourceManager_Import()) + return STATUS_NOT_SUPPORTED; + + buffer = PhAllocate(bufferSize); + + while (TRUE) + { + status = NtQueryInformationResourceManager_Import()( + ResourceManagerHandle, + ResourceManagerInformationClass, + buffer, + bufferSize, + NULL + ); + + if (status == STATUS_BUFFER_OVERFLOW) + { + PhFree(buffer); + bufferSize *= 2; + + if (bufferSize > 1 * 1024 * 1024) + return STATUS_INSUFFICIENT_RESOURCES; + + buffer = PhAllocate(bufferSize); + } + else + { + break; + } + } + + if (NT_SUCCESS(status)) + { + *Buffer = buffer; + } + else + { + PhFree(buffer); + } + + return status; +} + +NTSTATUS PhGetResourceManagerBasicInformation( + _In_ HANDLE ResourceManagerHandle, + _Out_opt_ PGUID Guid, + _Out_opt_ PPH_STRING *Description + ) +{ + NTSTATUS status; + PRESOURCEMANAGER_BASIC_INFORMATION basicInfo; + + status = PhpQueryResourceManagerVariableSize( + ResourceManagerHandle, + ResourceManagerBasicInformation, + &basicInfo + ); + + if (!NT_SUCCESS(status)) + return status; + + if (Guid) + { + *Guid = basicInfo->ResourceManagerId; + } + + if (Description) + { + *Description = PhCreateStringEx( + basicInfo->Description, + basicInfo->DescriptionLength + ); + } + + PhFree(basicInfo); + + return status; +} + +NTSTATUS PhGetEnlistmentBasicInformation( + _In_ HANDLE EnlistmentHandle, + _Out_ PENLISTMENT_BASIC_INFORMATION BasicInformation + ) +{ + if (NtQueryInformationEnlistment_Import()) + { + return NtQueryInformationEnlistment_Import()( + EnlistmentHandle, + EnlistmentBasicInformation, + BasicInformation, + sizeof(ENLISTMENT_BASIC_INFORMATION), + NULL + ); + } + else + { + return STATUS_NOT_SUPPORTED; + } +} + +typedef struct _OPEN_DRIVER_BY_BASE_ADDRESS_CONTEXT +{ + NTSTATUS Status; + PVOID BaseAddress; + HANDLE DriverHandle; +} OPEN_DRIVER_BY_BASE_ADDRESS_CONTEXT, *POPEN_DRIVER_BY_BASE_ADDRESS_CONTEXT; + +BOOLEAN NTAPI PhpOpenDriverByBaseAddressCallback( + _In_ PPH_STRINGREF Name, + _In_ PPH_STRINGREF TypeName, + _In_opt_ PVOID Context + ) +{ + static PH_STRINGREF driverDirectoryName = PH_STRINGREF_INIT(L"\\Driver\\"); + + NTSTATUS status; + POPEN_DRIVER_BY_BASE_ADDRESS_CONTEXT context = Context; + PPH_STRING driverName; + UNICODE_STRING driverNameUs; + OBJECT_ATTRIBUTES objectAttributes; + HANDLE driverHandle; + DRIVER_BASIC_INFORMATION basicInfo; + + driverName = PhConcatStringRef2(&driverDirectoryName, Name); + + if (!PhStringRefToUnicodeString(&driverName->sr, &driverNameUs)) + { + PhDereferenceObject(driverName); + return TRUE; + } + + InitializeObjectAttributes( + &objectAttributes, + &driverNameUs, + 0, + NULL, + NULL + ); + + status = KphOpenDriver(&driverHandle, SYNCHRONIZE, &objectAttributes); + PhDereferenceObject(driverName); + + if (!NT_SUCCESS(status)) + return TRUE; + + status = KphQueryInformationDriver( + driverHandle, + DriverBasicInformation, + &basicInfo, + sizeof(DRIVER_BASIC_INFORMATION), + NULL + ); + + if (NT_SUCCESS(status)) + { + if (basicInfo.DriverStart == context->BaseAddress) + { + context->Status = STATUS_SUCCESS; + context->DriverHandle = driverHandle; + + return FALSE; + } + } + + NtClose(driverHandle); + + return TRUE; +} + +/** + * Opens a driver object using a base address. + * + * \param DriverHandle A variable which receives a handle to the driver object. + * \param BaseAddress The base address of the driver to open. + * + * \retval STATUS_OBJECT_NAME_NOT_FOUND The driver could not be found. + * + * \remarks This function requires a valid KProcessHacker handle. + */ +NTSTATUS PhOpenDriverByBaseAddress( + _Out_ PHANDLE DriverHandle, + _In_ PVOID BaseAddress + ) +{ + NTSTATUS status; + UNICODE_STRING driverDirectoryName; + OBJECT_ATTRIBUTES objectAttributes; + HANDLE driverDirectoryHandle; + OPEN_DRIVER_BY_BASE_ADDRESS_CONTEXT context; + + RtlInitUnicodeString( + &driverDirectoryName, + L"\\Driver" + ); + InitializeObjectAttributes( + &objectAttributes, + &driverDirectoryName, + 0, + NULL, + NULL + ); + + if (!NT_SUCCESS(status = NtOpenDirectoryObject( + &driverDirectoryHandle, + DIRECTORY_QUERY, + &objectAttributes + ))) + return status; + + context.Status = STATUS_OBJECT_NAME_NOT_FOUND; + context.BaseAddress = BaseAddress; + + status = PhEnumDirectoryObjects( + driverDirectoryHandle, + PhpOpenDriverByBaseAddressCallback, + &context + ); + NtClose(driverDirectoryHandle); + + if (!NT_SUCCESS(status) && !NT_SUCCESS(context.Status)) + return status; + + if (NT_SUCCESS(context.Status)) + { + *DriverHandle = context.DriverHandle; + } + + return context.Status; +} + +/** + * Queries variable-sized information for a driver. The function allocates a buffer to contain the + * information. + * + * \param DriverHandle A handle to a driver. The access required depends on the information class + * specified. + * \param DriverInformationClass The information class to retrieve. + * \param Buffer A variable which receives a pointer to a buffer containing the information. You + * must free the buffer using PhFree() when you no longer need it. + * + * \remarks This function requires a valid KProcessHacker handle. + */ +NTSTATUS PhpQueryDriverVariableSize( + _In_ HANDLE DriverHandle, + _In_ DRIVER_INFORMATION_CLASS DriverInformationClass, + _Out_ PVOID *Buffer + ) +{ + NTSTATUS status; + PVOID buffer; + ULONG returnLength = 0; + + KphQueryInformationDriver( + DriverHandle, + DriverInformationClass, + NULL, + 0, + &returnLength + ); + buffer = PhAllocate(returnLength); + status = KphQueryInformationDriver( + DriverHandle, + DriverInformationClass, + buffer, + returnLength, + &returnLength + ); + + if (NT_SUCCESS(status)) + { + *Buffer = buffer; + } + else + { + PhFree(buffer); + } + + return status; +} + +/** + * Gets the object name of a driver. + * + * \param DriverHandle A handle to a driver. + * \param Name A variable which receives a pointer to a string containing the object name. You must + * free the string using PhDereferenceObject() when you no longer need it. + * + * \remarks This function requires a valid KProcessHacker handle. + */ +NTSTATUS PhGetDriverName( + _In_ HANDLE DriverHandle, + _Out_ PPH_STRING *Name + ) +{ + NTSTATUS status; + PUNICODE_STRING unicodeString; + + if (!NT_SUCCESS(status = PhpQueryDriverVariableSize( + DriverHandle, + DriverNameInformation, + &unicodeString + ))) + return status; + + *Name = PhCreateStringEx( + unicodeString->Buffer, + unicodeString->Length + ); + PhFree(unicodeString); + + return status; +} + +/** + * Gets the service key name of a driver. + * + * \param DriverHandle A handle to a driver. + * \param ServiceKeyName A variable which receives a pointer to a string containing the service key + * name. You must free the string using PhDereferenceObject() when you no longer need it. + * + * \remarks This function requires a valid KProcessHacker handle. + */ +NTSTATUS PhGetDriverServiceKeyName( + _In_ HANDLE DriverHandle, + _Out_ PPH_STRING *ServiceKeyName + ) +{ + NTSTATUS status; + PUNICODE_STRING unicodeString; + + if (!NT_SUCCESS(status = PhpQueryDriverVariableSize( + DriverHandle, + DriverServiceKeyNameInformation, + &unicodeString + ))) + return status; + + *ServiceKeyName = PhCreateStringEx( + unicodeString->Buffer, + unicodeString->Length + ); + PhFree(unicodeString); + + return status; +} + +NTSTATUS PhpUnloadDriver( + _In_ PPH_STRING ServiceKeyName + ) +{ + static PH_STRINGREF fullServicesKeyName = PH_STRINGREF_INIT(L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\"); + + NTSTATUS status; + PPH_STRING fullServiceKeyName; + UNICODE_STRING fullServiceKeyNameUs; + HANDLE serviceKeyHandle; + ULONG disposition; + + fullServiceKeyName = PhConcatStringRef2(&fullServicesKeyName, &ServiceKeyName->sr); + + if (!PhStringRefToUnicodeString(&fullServiceKeyName->sr, &fullServiceKeyNameUs)) + { + PhDereferenceObject(fullServiceKeyName); + return STATUS_NAME_TOO_LONG; + } + + if (NT_SUCCESS(status = PhCreateKey( + &serviceKeyHandle, + KEY_WRITE | DELETE, + NULL, + &fullServiceKeyName->sr, + 0, + 0, + &disposition + ))) + { + if (disposition == REG_CREATED_NEW_KEY) + { + static UNICODE_STRING imagePath = RTL_CONSTANT_STRING(L"\\SystemRoot\\system32\\drivers\\ntfs.sys"); + + UNICODE_STRING valueName; + ULONG dword; + + // Set up the required values. + dword = 1; + RtlInitUnicodeString(&valueName, L"ErrorControl"); + NtSetValueKey(serviceKeyHandle, &valueName, 0, REG_DWORD, &dword, sizeof(ULONG)); + RtlInitUnicodeString(&valueName, L"Start"); + NtSetValueKey(serviceKeyHandle, &valueName, 0, REG_DWORD, &dword, sizeof(ULONG)); + RtlInitUnicodeString(&valueName, L"Type"); + NtSetValueKey(serviceKeyHandle, &valueName, 0, REG_DWORD, &dword, sizeof(ULONG)); + + // Use a bogus name. + RtlInitUnicodeString(&valueName, L"ImagePath"); + NtSetValueKey(serviceKeyHandle, &valueName, 0, REG_SZ, imagePath.Buffer, imagePath.Length + 2); + } + + status = NtUnloadDriver(&fullServiceKeyNameUs); + + if (disposition == REG_CREATED_NEW_KEY) + { + // We added values, not subkeys, so this function will work correctly. + NtDeleteKey(serviceKeyHandle); + } + + NtClose(serviceKeyHandle); + } + + PhDereferenceObject(fullServiceKeyName); + + return status; +} + +/** + * Unloads a driver. + * + * \param BaseAddress The base address of the driver. This parameter can be NULL if a value is + * specified in \c Name. + * \param Name The base name of the driver. This parameter can be NULL if a value is specified in + * \c BaseAddress and KProcessHacker is loaded. + * + * \retval STATUS_INVALID_PARAMETER_MIX Both \c BaseAddress and \c Name were null, or \c Name was + * not specified and KProcessHacker is not loaded. + * \retval STATUS_OBJECT_NAME_NOT_FOUND The driver could not be found. + */ +NTSTATUS PhUnloadDriver( + _In_opt_ PVOID BaseAddress, + _In_opt_ PWSTR Name + ) +{ + NTSTATUS status; + HANDLE driverHandle; + PPH_STRING serviceKeyName = NULL; + + if (!BaseAddress && !Name) + return STATUS_INVALID_PARAMETER_MIX; + if (!Name && !KphIsConnected()) + return STATUS_INVALID_PARAMETER_MIX; + + // Try to get the service key name by scanning the Driver directory. + + if (KphIsConnected() && BaseAddress) + { + if (NT_SUCCESS(PhOpenDriverByBaseAddress( + &driverHandle, + BaseAddress + ))) + { + PhGetDriverServiceKeyName(driverHandle, &serviceKeyName); + NtClose(driverHandle); + } + } + + // Use the base name if we didn't get the service key name. + + if (!serviceKeyName && Name) + { + PPH_STRING name; + + name = PhCreateString(Name); + + // Remove the extension if it is present. + if (PhEndsWithString2(name, L".sys", TRUE)) + { + serviceKeyName = PhSubstring(name, 0, name->Length / 2 - 4); + PhDereferenceObject(name); + } + else + { + serviceKeyName = name; + } + } + + if (!serviceKeyName) + return STATUS_OBJECT_NAME_NOT_FOUND; + + status = PhpUnloadDriver(serviceKeyName); + PhDereferenceObject(serviceKeyName); + + return status; +} + +NTSTATUS PhpEnumProcessModules( + _In_ HANDLE ProcessHandle, + _In_ PPHP_ENUM_PROCESS_MODULES_CALLBACK Callback, + _In_opt_ PVOID Context1, + _In_opt_ PVOID Context2 + ) +{ + NTSTATUS status; + PROCESS_BASIC_INFORMATION basicInfo; + PPEB_LDR_DATA ldr; + PEB_LDR_DATA pebLdrData; + PLIST_ENTRY startLink; + PLIST_ENTRY currentLink; + ULONG dataTableEntrySize; + LDR_DATA_TABLE_ENTRY currentEntry; + ULONG i; + + // Get the PEB address. + status = PhGetProcessBasicInformation(ProcessHandle, &basicInfo); + + if (!NT_SUCCESS(status)) + return status; + + // Read the address of the loader data. + status = NtReadVirtualMemory( + ProcessHandle, + PTR_ADD_OFFSET(basicInfo.PebBaseAddress, FIELD_OFFSET(PEB, Ldr)), + &ldr, + sizeof(PVOID), + NULL + ); + + if (!NT_SUCCESS(status)) + return status; + + // Read the loader data. + status = NtReadVirtualMemory( + ProcessHandle, + ldr, + &pebLdrData, + sizeof(PEB_LDR_DATA), + NULL + ); + + if (!NT_SUCCESS(status)) + return status; + + if (!pebLdrData.Initialized) + return STATUS_UNSUCCESSFUL; + + if (WindowsVersion >= WINDOWS_8) + dataTableEntrySize = LDR_DATA_TABLE_ENTRY_SIZE_WIN8; + else if (WindowsVersion >= WINDOWS_7) + dataTableEntrySize = LDR_DATA_TABLE_ENTRY_SIZE_WIN7; + else + dataTableEntrySize = LDR_DATA_TABLE_ENTRY_SIZE_WINXP; + + // Traverse the linked list (in load order). + + i = 0; + startLink = PTR_ADD_OFFSET(ldr, FIELD_OFFSET(PEB_LDR_DATA, InLoadOrderModuleList)); + currentLink = pebLdrData.InLoadOrderModuleList.Flink; + + while ( + currentLink != startLink && + i <= PH_ENUM_PROCESS_MODULES_LIMIT + ) + { + PVOID addressOfEntry; + + addressOfEntry = CONTAINING_RECORD(currentLink, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks); + status = NtReadVirtualMemory( + ProcessHandle, + addressOfEntry, + ¤tEntry, + dataTableEntrySize, + NULL + ); + + if (!NT_SUCCESS(status)) + return status; + + // Make sure the entry is valid. + if (currentEntry.DllBase) + { + // Execute the callback. + if (!Callback( + ProcessHandle, + ¤tEntry, + addressOfEntry, + Context1, + Context2 + )) + break; + } + + currentLink = currentEntry.InLoadOrderLinks.Flink; + i++; + } + + return status; +} + +BOOLEAN NTAPI PhpEnumProcessModulesCallback( + _In_ HANDLE ProcessHandle, + _In_ PLDR_DATA_TABLE_ENTRY Entry, + _In_ PVOID AddressOfEntry, + _In_opt_ PVOID Context1, + _In_opt_ PVOID Context2 + ) +{ + NTSTATUS status; + PPH_ENUM_PROCESS_MODULES_PARAMETERS parameters; + BOOLEAN cont; + PPH_STRING mappedFileName; + PWSTR fullDllNameOriginal; + PWSTR fullDllNameBuffer; + PWSTR baseDllNameOriginal; + PWSTR baseDllNameBuffer; + + parameters = Context1; + mappedFileName = NULL; + + if (parameters->Flags & PH_ENUM_PROCESS_MODULES_TRY_MAPPED_FILE_NAME) + { + PhGetProcessMappedFileName(ProcessHandle, Entry->DllBase, &mappedFileName); + } + + if (mappedFileName) + { + ULONG_PTR indexOfLastBackslash; + + PhStringRefToUnicodeString(&mappedFileName->sr, &Entry->FullDllName); + indexOfLastBackslash = PhFindLastCharInString(mappedFileName, 0, '\\'); + + if (indexOfLastBackslash != -1) + { + Entry->BaseDllName.Buffer = Entry->FullDllName.Buffer + indexOfLastBackslash + 1; + Entry->BaseDllName.Length = Entry->FullDllName.Length - (USHORT)indexOfLastBackslash * 2 - 2; + Entry->BaseDllName.MaximumLength = Entry->BaseDllName.Length; + } + else + { + Entry->BaseDllName = Entry->FullDllName; + } + } + else + { + // Read the full DLL name string and add a null terminator. + + fullDllNameOriginal = Entry->FullDllName.Buffer; + fullDllNameBuffer = PhAllocate(Entry->FullDllName.Length + 2); + Entry->FullDllName.Buffer = fullDllNameBuffer; + + if (NT_SUCCESS(status = NtReadVirtualMemory( + ProcessHandle, + fullDllNameOriginal, + fullDllNameBuffer, + Entry->FullDllName.Length, + NULL + ))) + { + fullDllNameBuffer[Entry->FullDllName.Length / 2] = 0; + } + else + { + fullDllNameBuffer[0] = 0; + Entry->FullDllName.Length = 0; + } + + baseDllNameOriginal = Entry->BaseDllName.Buffer; + + // Try to use the buffer we just read in. + if ( + NT_SUCCESS(status) && + (ULONG_PTR)baseDllNameOriginal >= (ULONG_PTR)fullDllNameOriginal && + (ULONG_PTR)baseDllNameOriginal + Entry->BaseDllName.Length >= (ULONG_PTR)baseDllNameOriginal && + (ULONG_PTR)baseDllNameOriginal + Entry->BaseDllName.Length <= (ULONG_PTR)fullDllNameOriginal + Entry->FullDllName.Length + ) + { + baseDllNameBuffer = NULL; + + Entry->BaseDllName.Buffer = (PWCHAR)((ULONG_PTR)Entry->FullDllName.Buffer + + ((ULONG_PTR)baseDllNameOriginal - (ULONG_PTR)fullDllNameOriginal)); + } + else + { + // Read the base DLL name string and add a null terminator. + + baseDllNameBuffer = PhAllocate(Entry->BaseDllName.Length + 2); + Entry->BaseDllName.Buffer = baseDllNameBuffer; + + if (NT_SUCCESS(NtReadVirtualMemory( + ProcessHandle, + baseDllNameOriginal, + baseDllNameBuffer, + Entry->BaseDllName.Length, + NULL + ))) + { + baseDllNameBuffer[Entry->BaseDllName.Length / 2] = 0; + } + else + { + baseDllNameBuffer[0] = 0; + Entry->BaseDllName.Length = 0; + } + } + } + + // Execute the callback. + cont = parameters->Callback(Entry, parameters->Context); + + if (mappedFileName) + { + PhDereferenceObject(mappedFileName); + } + else + { + PhFree(fullDllNameBuffer); + + if (baseDllNameBuffer) + PhFree(baseDllNameBuffer); + } + + return cont; +} + +/** + * Enumerates the modules loaded by a process. + * + * \param ProcessHandle A handle to a process. The handle must have + * PROCESS_QUERY_LIMITED_INFORMATION and PROCESS_VM_READ access. + * \param Callback A callback function which is executed for each process module. + * \param Context A user-defined value to pass to the callback function. + */ +NTSTATUS PhEnumProcessModules( + _In_ HANDLE ProcessHandle, + _In_ PPH_ENUM_PROCESS_MODULES_CALLBACK Callback, + _In_opt_ PVOID Context + ) +{ + PH_ENUM_PROCESS_MODULES_PARAMETERS parameters; + + parameters.Callback = Callback; + parameters.Context = Context; + parameters.Flags = 0; + + return PhEnumProcessModulesEx(ProcessHandle, ¶meters); +} + +/** + * Enumerates the modules loaded by a process. + * + * \param ProcessHandle A handle to a process. The handle must have + * PROCESS_QUERY_LIMITED_INFORMATION and PROCESS_VM_READ access. If + * \c PH_ENUM_PROCESS_MODULES_TRY_MAPPED_FILE_NAME is specified in \a Parameters, the handle should + * have PROCESS_QUERY_INFORMATION access. + * \param Parameters The enumeration parameters. + */ +NTSTATUS PhEnumProcessModulesEx( + _In_ HANDLE ProcessHandle, + _In_ PPH_ENUM_PROCESS_MODULES_PARAMETERS Parameters + ) +{ + return PhpEnumProcessModules( + ProcessHandle, + PhpEnumProcessModulesCallback, + Parameters, + NULL + ); +} + +typedef struct _SET_PROCESS_MODULE_LOAD_COUNT_CONTEXT +{ + NTSTATUS Status; + PVOID BaseAddress; + ULONG LoadCount; +} SET_PROCESS_MODULE_LOAD_COUNT_CONTEXT, *PSET_PROCESS_MODULE_LOAD_COUNT_CONTEXT; + +BOOLEAN NTAPI PhpSetProcessModuleLoadCountCallback( + _In_ HANDLE ProcessHandle, + _In_ PLDR_DATA_TABLE_ENTRY Entry, + _In_ PVOID AddressOfEntry, + _In_opt_ PVOID Context1, + _In_opt_ PVOID Context2 + ) +{ + PSET_PROCESS_MODULE_LOAD_COUNT_CONTEXT context = Context1; + + if (Entry->DllBase == context->BaseAddress) + { + context->Status = NtWriteVirtualMemory( + ProcessHandle, + PTR_ADD_OFFSET(AddressOfEntry, FIELD_OFFSET(LDR_DATA_TABLE_ENTRY, ObsoleteLoadCount)), + &context->LoadCount, + sizeof(USHORT), + NULL + ); + + return FALSE; + } + + return TRUE; +} + +/** + * Sets the load count of a process module. + * + * \param ProcessHandle A handle to a process. The handle must have + * PROCESS_QUERY_LIMITED_INFORMATION, PROCESS_VM_READ and PROCESS_VM_WRITE access. + * \param BaseAddress The base address of a module. + * \param LoadCount The new load count of the module. + * + * \retval STATUS_DLL_NOT_FOUND The module was not found. + */ +NTSTATUS PhSetProcessModuleLoadCount( + _In_ HANDLE ProcessHandle, + _In_ PVOID BaseAddress, + _In_ ULONG LoadCount + ) +{ + NTSTATUS status; + SET_PROCESS_MODULE_LOAD_COUNT_CONTEXT context; + + context.Status = STATUS_DLL_NOT_FOUND; + context.BaseAddress = BaseAddress; + context.LoadCount = LoadCount; + + status = PhpEnumProcessModules( + ProcessHandle, + PhpSetProcessModuleLoadCountCallback, + &context, + NULL + ); + + if (!NT_SUCCESS(status)) + return status; + + return context.Status; +} + +NTSTATUS PhpEnumProcessModules32( + _In_ HANDLE ProcessHandle, + _In_ PPHP_ENUM_PROCESS_MODULES32_CALLBACK Callback, + _In_opt_ PVOID Context1, + _In_opt_ PVOID Context2 + ) +{ + NTSTATUS status; + PPEB32 peb; + ULONG ldr; // PEB_LDR_DATA32 *32 + PEB_LDR_DATA32 pebLdrData; + ULONG startLink; // LIST_ENTRY32 *32 + ULONG currentLink; // LIST_ENTRY32 *32 + ULONG dataTableEntrySize; + LDR_DATA_TABLE_ENTRY32 currentEntry; + ULONG i; + + // Get the 32-bit PEB address. + status = PhGetProcessPeb32(ProcessHandle, &peb); + + if (!NT_SUCCESS(status)) + return status; + + if (!peb) + return STATUS_NOT_SUPPORTED; // not a WOW64 process + + // Read the address of the loader data. + status = NtReadVirtualMemory( + ProcessHandle, + PTR_ADD_OFFSET(peb, FIELD_OFFSET(PEB32, Ldr)), + &ldr, + sizeof(ULONG), + NULL + ); + + if (!NT_SUCCESS(status)) + return status; + + // Read the loader data. + status = NtReadVirtualMemory( + ProcessHandle, + UlongToPtr(ldr), + &pebLdrData, + sizeof(PEB_LDR_DATA32), + NULL + ); + + if (!NT_SUCCESS(status)) + return status; + + if (!pebLdrData.Initialized) + return STATUS_UNSUCCESSFUL; + + if (WindowsVersion >= WINDOWS_8) + dataTableEntrySize = LDR_DATA_TABLE_ENTRY_SIZE_WIN8_32; + else if (WindowsVersion >= WINDOWS_7) + dataTableEntrySize = LDR_DATA_TABLE_ENTRY_SIZE_WIN7_32; + else + dataTableEntrySize = LDR_DATA_TABLE_ENTRY_SIZE_WINXP_32; + + // Traverse the linked list (in load order). + + i = 0; + startLink = (ULONG)(ldr + FIELD_OFFSET(PEB_LDR_DATA32, InLoadOrderModuleList)); + currentLink = pebLdrData.InLoadOrderModuleList.Flink; + + while ( + currentLink != startLink && + i <= PH_ENUM_PROCESS_MODULES_LIMIT + ) + { + ULONG addressOfEntry; + + addressOfEntry = PtrToUlong(CONTAINING_RECORD(UlongToPtr(currentLink), LDR_DATA_TABLE_ENTRY32, InLoadOrderLinks)); + status = NtReadVirtualMemory( + ProcessHandle, + UlongToPtr(addressOfEntry), + ¤tEntry, + dataTableEntrySize, + NULL + ); + + if (!NT_SUCCESS(status)) + return status; + + // Make sure the entry is valid. + if (currentEntry.DllBase) + { + // Execute the callback. + if (!Callback( + ProcessHandle, + ¤tEntry, + addressOfEntry, + Context1, + Context2 + )) + break; + } + + currentLink = currentEntry.InLoadOrderLinks.Flink; + i++; + } + + return status; +} + +BOOLEAN NTAPI PhpEnumProcessModules32Callback( + _In_ HANDLE ProcessHandle, + _In_ PLDR_DATA_TABLE_ENTRY32 Entry, + _In_ ULONG AddressOfEntry, + _In_opt_ PVOID Context1, + _In_opt_ PVOID Context2 + ) +{ + static PH_STRINGREF system32String = PH_STRINGREF_INIT(L"\\system32\\"); + + PPH_ENUM_PROCESS_MODULES_PARAMETERS parameters; + BOOLEAN cont; + LDR_DATA_TABLE_ENTRY nativeEntry; + PPH_STRING mappedFileName; + PWSTR baseDllNameBuffer; + PWSTR fullDllNameBuffer; + PH_STRINGREF fullDllName; + PH_STRINGREF systemRootString; + + parameters = Context1; + + // Convert the 32-bit entry to a native-sized entry. + + memset(&nativeEntry, 0, sizeof(LDR_DATA_TABLE_ENTRY)); + nativeEntry.DllBase = UlongToPtr(Entry->DllBase); + nativeEntry.EntryPoint = UlongToPtr(Entry->EntryPoint); + nativeEntry.SizeOfImage = Entry->SizeOfImage; + UStr32ToUStr(&nativeEntry.FullDllName, &Entry->FullDllName); + UStr32ToUStr(&nativeEntry.BaseDllName, &Entry->BaseDllName); + nativeEntry.Flags = Entry->Flags; + nativeEntry.ObsoleteLoadCount = Entry->ObsoleteLoadCount; + nativeEntry.TlsIndex = Entry->TlsIndex; + nativeEntry.TimeDateStamp = Entry->TimeDateStamp; + nativeEntry.OriginalBase = Entry->OriginalBase; + nativeEntry.LoadTime = Entry->LoadTime; + nativeEntry.BaseNameHashValue = Entry->BaseNameHashValue; + nativeEntry.LoadReason = Entry->LoadReason; + + mappedFileName = NULL; + + if (parameters->Flags & PH_ENUM_PROCESS_MODULES_TRY_MAPPED_FILE_NAME) + { + PhGetProcessMappedFileName(ProcessHandle, nativeEntry.DllBase, &mappedFileName); + } + + if (mappedFileName) + { + ULONG_PTR indexOfLastBackslash; + + PhStringRefToUnicodeString(&mappedFileName->sr, &nativeEntry.FullDllName); + indexOfLastBackslash = PhFindLastCharInString(mappedFileName, 0, '\\'); + + if (indexOfLastBackslash != -1) + { + nativeEntry.BaseDllName.Buffer = nativeEntry.FullDllName.Buffer + indexOfLastBackslash + 1; + nativeEntry.BaseDllName.Length = nativeEntry.FullDllName.Length - (USHORT)indexOfLastBackslash * 2 - 2; + nativeEntry.BaseDllName.MaximumLength = nativeEntry.BaseDllName.Length; + } + else + { + nativeEntry.BaseDllName = nativeEntry.FullDllName; + } + } + else + { + // Read the base DLL name string and add a null terminator. + + baseDllNameBuffer = PhAllocate(nativeEntry.BaseDllName.Length + 2); + + if (NT_SUCCESS(NtReadVirtualMemory( + ProcessHandle, + nativeEntry.BaseDllName.Buffer, + baseDllNameBuffer, + nativeEntry.BaseDllName.Length, + NULL + ))) + { + baseDllNameBuffer[nativeEntry.BaseDllName.Length / 2] = 0; + } + else + { + baseDllNameBuffer[0] = 0; + nativeEntry.BaseDllName.Length = 0; + } + + nativeEntry.BaseDllName.Buffer = baseDllNameBuffer; + + // Read the full DLL name string and add a null terminator. + + fullDllNameBuffer = PhAllocate(nativeEntry.FullDllName.Length + 2); + + if (NT_SUCCESS(NtReadVirtualMemory( + ProcessHandle, + nativeEntry.FullDllName.Buffer, + fullDllNameBuffer, + nativeEntry.FullDllName.Length, + NULL + ))) + { + fullDllNameBuffer[nativeEntry.FullDllName.Length / 2] = 0; + + if (!(parameters->Flags & PH_ENUM_PROCESS_MODULES_DONT_RESOLVE_WOW64_FS)) + { + // WOW64 file system redirection - convert "system32" to "SysWOW64". + if (!(nativeEntry.FullDllName.Length & 1)) // validate the string length + { + fullDllName.Buffer = fullDllNameBuffer; + fullDllName.Length = nativeEntry.FullDllName.Length; + + PhGetSystemRoot(&systemRootString); + + if (PhStartsWithStringRef(&fullDllName, &systemRootString, TRUE)) + { + PhSkipStringRef(&fullDllName, systemRootString.Length); + + if (PhStartsWithStringRef(&fullDllName, &system32String, TRUE)) + { + fullDllName.Buffer[1] = 'S'; + fullDllName.Buffer[4] = 'W'; + fullDllName.Buffer[5] = 'O'; + fullDllName.Buffer[6] = 'W'; + fullDllName.Buffer[7] = '6'; + fullDllName.Buffer[8] = '4'; + } + } + } + } + } + else + { + fullDllNameBuffer[0] = 0; + nativeEntry.FullDllName.Length = 0; + } + + nativeEntry.FullDllName.Buffer = fullDllNameBuffer; + } + + // Execute the callback. + cont = parameters->Callback(&nativeEntry, parameters->Context); + + if (mappedFileName) + { + PhDereferenceObject(mappedFileName); + } + else + { + PhFree(baseDllNameBuffer); + PhFree(fullDllNameBuffer); + } + + return cont; +} + +/** + * Enumerates the 32-bit modules loaded by a process. + * + * \param ProcessHandle A handle to a process. The handle must have + * PROCESS_QUERY_LIMITED_INFORMATION and PROCESS_VM_READ access. + * \param Callback A callback function which is executed for each process module. + * \param Context A user-defined value to pass to the callback function. + * + * \retval STATUS_NOT_SUPPORTED The process is not running under WOW64. + * + * \remarks Do not use this function under a 32-bit environment. + */ +NTSTATUS PhEnumProcessModules32( + _In_ HANDLE ProcessHandle, + _In_ PPH_ENUM_PROCESS_MODULES_CALLBACK Callback, + _In_opt_ PVOID Context + ) +{ + PH_ENUM_PROCESS_MODULES_PARAMETERS parameters; + + parameters.Callback = Callback; + parameters.Context = Context; + parameters.Flags = 0; + + return PhEnumProcessModules32Ex(ProcessHandle, ¶meters); +} + +/** + * Enumerates the 32-bit modules loaded by a process. + * + * \param ProcessHandle A handle to a process. The handle must have + * PROCESS_QUERY_LIMITED_INFORMATION and PROCESS_VM_READ access. If + * \c PH_ENUM_PROCESS_MODULES_TRY_MAPPED_FILE_NAME is specified in \a Parameters, the handle should + * have PROCESS_QUERY_INFORMATION access. + * \param Parameters The enumeration parameters. + * + * \retval STATUS_NOT_SUPPORTED The process is not running under WOW64. + * + * \remarks Do not use this function under a 32-bit environment. + */ +NTSTATUS PhEnumProcessModules32Ex( + _In_ HANDLE ProcessHandle, + _In_ PPH_ENUM_PROCESS_MODULES_PARAMETERS Parameters + ) +{ + return PhpEnumProcessModules32( + ProcessHandle, + PhpEnumProcessModules32Callback, + Parameters, + NULL + ); +} + +BOOLEAN NTAPI PhpSetProcessModuleLoadCount32Callback( + _In_ HANDLE ProcessHandle, + _In_ PLDR_DATA_TABLE_ENTRY32 Entry, + _In_ ULONG AddressOfEntry, + _In_opt_ PVOID Context1, + _In_opt_ PVOID Context2 + ) +{ + PSET_PROCESS_MODULE_LOAD_COUNT_CONTEXT context = Context1; + + if (UlongToPtr(Entry->DllBase) == context->BaseAddress) + { + context->Status = NtWriteVirtualMemory( + ProcessHandle, + UlongToPtr(AddressOfEntry + FIELD_OFFSET(LDR_DATA_TABLE_ENTRY32, ObsoleteLoadCount)), + &context->LoadCount, + sizeof(USHORT), + NULL + ); + + return FALSE; + } + + return TRUE; +} + +/** + * Sets the load count of a 32-bit process module. + * + * \param ProcessHandle A handle to a process. The handle must have + * PROCESS_QUERY_LIMITED_INFORMATION, PROCESS_VM_READ and PROCESS_VM_WRITE access. + * \param BaseAddress The base address of a module. + * \param LoadCount The new load count of the module. + * + * \retval STATUS_DLL_NOT_FOUND The module was not found. + * \retval STATUS_NOT_SUPPORTED The process is not running under WOW64. + * + * \remarks Do not use this function under a 32-bit environment. + */ +NTSTATUS PhSetProcessModuleLoadCount32( + _In_ HANDLE ProcessHandle, + _In_ PVOID BaseAddress, + _In_ ULONG LoadCount + ) +{ + NTSTATUS status; + SET_PROCESS_MODULE_LOAD_COUNT_CONTEXT context; + + context.Status = STATUS_DLL_NOT_FOUND; + context.BaseAddress = BaseAddress; + context.LoadCount = LoadCount; + + status = PhpEnumProcessModules32( + ProcessHandle, + PhpSetProcessModuleLoadCount32Callback, + &context, + NULL + ); + + if (!NT_SUCCESS(status)) + return status; + + return context.Status; +} + +typedef struct _GET_PROCEDURE_ADDRESS_REMOTE_CONTEXT +{ + PH_STRINGREF FileName; + PVOID DllBase; +} GET_PROCEDURE_ADDRESS_REMOTE_CONTEXT, *PGET_PROCEDURE_ADDRESS_REMOTE_CONTEXT; + +static BOOLEAN PhpGetProcedureAddressRemoteCallback( + _In_ PLDR_DATA_TABLE_ENTRY Module, + _In_opt_ PVOID Context + ) +{ + PGET_PROCEDURE_ADDRESS_REMOTE_CONTEXT context = Context; + PH_STRINGREF fullDllName; + + PhUnicodeStringToStringRef(&Module->FullDllName, &fullDllName); + + if (PhEqualStringRef(&fullDllName, &context->FileName, TRUE)) + { + context->DllBase = Module->DllBase; + return FALSE; + } + + return TRUE; +} + +/** + * Gets the address of a procedure in a process. + * + * \param ProcessHandle A handle to a process. The handle must have + * PROCESS_QUERY_LIMITED_INFORMATION and PROCESS_VM_READ access. + * \param FileName The file name of the DLL containing the procedure. + * \param ProcedureName The name of the procedure. + * \param ProcedureNumber The ordinal of the procedure. + * \param ProcedureAddress A variable which receives the address of the procedure in the address + * space of the process. + * \param DllBase A variable which receives the base address of the DLL containing the procedure. + */ +NTSTATUS PhGetProcedureAddressRemote( + _In_ HANDLE ProcessHandle, + _In_ PWSTR FileName, + _In_opt_ PSTR ProcedureName, + _In_opt_ ULONG ProcedureNumber, + _Out_ PVOID *ProcedureAddress, + _Out_opt_ PVOID *DllBase + ) +{ + NTSTATUS status; + PH_MAPPED_IMAGE mappedImage; + PH_MAPPED_IMAGE_EXPORTS exports; + GET_PROCEDURE_ADDRESS_REMOTE_CONTEXT context; + + if (!NT_SUCCESS(status = PhLoadMappedImage(FileName, NULL, TRUE, &mappedImage))) + return status; + + PhInitializeStringRef(&context.FileName, FileName); + context.DllBase = NULL; + + if (mappedImage.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) + { +#ifdef _WIN64 + status = PhEnumProcessModules32(ProcessHandle, PhpGetProcedureAddressRemoteCallback, &context); +#else + status = PhEnumProcessModules(ProcessHandle, PhpGetProcedureAddressRemoteCallback, &context); +#endif + } + else + { +#ifdef _WIN64 + status = PhEnumProcessModules(ProcessHandle, PhpGetProcedureAddressRemoteCallback, &context); +#else + status = STATUS_NOT_SUPPORTED; +#endif + } + + if (!NT_SUCCESS(status)) + goto CleanupExit; + + if (!NT_SUCCESS(status = PhGetMappedImageExports(&exports, &mappedImage))) + goto CleanupExit; + + status = PhGetMappedImageExportFunctionRemote( + &exports, + ProcedureName, + (USHORT)ProcedureNumber, + context.DllBase, + ProcedureAddress + ); + + if (NT_SUCCESS(status)) + { + if (DllBase) + *DllBase = context.DllBase; + } + +CleanupExit: + PhUnloadMappedImage(&mappedImage); + + return status; +} + +/** + * Enumerates the modules loaded by the kernel. + * + * \param Modules A variable which receives a pointer to a structure containing information about + * the kernel modules. You must free the structure using PhFree() when you no longer need it. + */ +NTSTATUS PhEnumKernelModules( + _Out_ PRTL_PROCESS_MODULES *Modules + ) +{ + NTSTATUS status; + PVOID buffer; + ULONG bufferSize = 2048; + + buffer = PhAllocate(bufferSize); + + status = NtQuerySystemInformation( + SystemModuleInformation, + buffer, + bufferSize, + &bufferSize + ); + + if (status == STATUS_INFO_LENGTH_MISMATCH) + { + PhFree(buffer); + buffer = PhAllocate(bufferSize); + + status = NtQuerySystemInformation( + SystemModuleInformation, + buffer, + bufferSize, + &bufferSize + ); + } + + if (!NT_SUCCESS(status)) + return status; + + *Modules = buffer; + + return status; +} + +/** + * Enumerates the modules loaded by the kernel. + * + * \param Modules A variable which receives a pointer to a structure containing information about + * the kernel modules. You must free the structure using PhFree() when you no longer need it. + */ +NTSTATUS PhEnumKernelModulesEx( + _Out_ PRTL_PROCESS_MODULE_INFORMATION_EX *Modules + ) +{ + NTSTATUS status; + PVOID buffer; + ULONG bufferSize = 2048; + + buffer = PhAllocate(bufferSize); + + status = NtQuerySystemInformation( + SystemModuleInformationEx, + buffer, + bufferSize, + &bufferSize + ); + + if (status == STATUS_INFO_LENGTH_MISMATCH) + { + PhFree(buffer); + buffer = PhAllocate(bufferSize); + + status = NtQuerySystemInformation( + SystemModuleInformationEx, + buffer, + bufferSize, + &bufferSize + ); + } + + if (!NT_SUCCESS(status)) + return status; + + *Modules = buffer; + + return status; +} + +/** + * Gets the file name of the kernel image. + * + * \return A pointer to a string containing the kernel image file name. You must free the string + * using PhDereferenceObject() when you no longer need it. + */ +PPH_STRING PhGetKernelFileName( + VOID + ) +{ + PRTL_PROCESS_MODULES modules; + PPH_STRING fileName = NULL; + + if (!NT_SUCCESS(PhEnumKernelModules(&modules))) + return NULL; + + if (modules->NumberOfModules >= 1) + { + fileName = PhConvertMultiByteToUtf16(modules->Modules[0].FullPathName); + } + + PhFree(modules); + + return fileName; +} + +/** + * Enumerates the running processes. + * + * \param Processes A variable which receives a pointer to a buffer containing process information. + * You must free the buffer using PhFree() when you no longer need it. + * + * \remarks You can use the \ref PH_FIRST_PROCESS and \ref PH_NEXT_PROCESS macros to process the + * information contained in the buffer. + */ +NTSTATUS PhEnumProcesses( + _Out_ PVOID *Processes + ) +{ + return PhEnumProcessesEx(Processes, SystemProcessInformation); +} + +/** + * Enumerates the running processes. + * + * \param Processes A variable which receives a pointer to a buffer containing process information. + * You must free the buffer using PhFree() when you no longer need it. + * + * \remarks You can use the \ref PH_FIRST_PROCESS and \ref PH_NEXT_PROCESS macros to process the + * information contained in the buffer. + */ +NTSTATUS PhEnumProcessesEx( + _Out_ PVOID *Processes, + _In_ SYSTEM_INFORMATION_CLASS SystemInformationClass + ) +{ + static ULONG initialBufferSize[3] = { 0x4000, 0x4000, 0x4000 }; + NTSTATUS status; + ULONG classIndex; + PVOID buffer; + ULONG bufferSize; + + switch (SystemInformationClass) + { + case SystemProcessInformation: + classIndex = 0; + break; + case SystemExtendedProcessInformation: + classIndex = 1; + break; + case SystemFullProcessInformation: + classIndex = 2; + break; + default: + return STATUS_INVALID_INFO_CLASS; + } + + bufferSize = initialBufferSize[classIndex]; + buffer = PhAllocate(bufferSize); + + while (TRUE) + { + status = NtQuerySystemInformation( + SystemInformationClass, + buffer, + bufferSize, + &bufferSize + ); + + if (status == STATUS_BUFFER_TOO_SMALL || status == STATUS_INFO_LENGTH_MISMATCH) + { + PhFree(buffer); + buffer = PhAllocate(bufferSize); + } + else + { + break; + } + } + + if (!NT_SUCCESS(status)) + { + PhFree(buffer); + return status; + } + + if (bufferSize <= 0x100000) initialBufferSize[classIndex] = bufferSize; + *Processes = buffer; + + return status; +} + +/** + * Enumerates the running processes for a session. + * + * \param Processes A variable which receives a pointer to a buffer containing process information. + * You must free the buffer using PhFree() when you no longer need it. + * \param SessionId A session ID. + * + * \remarks You can use the \ref PH_FIRST_PROCESS and \ref PH_NEXT_PROCESS macros to process the + * information contained in the buffer. + */ +NTSTATUS PhEnumProcessesForSession( + _Out_ PVOID *Processes, + _In_ ULONG SessionId + ) +{ + static ULONG initialBufferSize = 0x4000; + NTSTATUS status; + SYSTEM_SESSION_PROCESS_INFORMATION sessionProcessInfo; + PVOID buffer; + ULONG bufferSize; + + bufferSize = initialBufferSize; + buffer = PhAllocate(bufferSize); + + sessionProcessInfo.SessionId = SessionId; + + while (TRUE) + { + sessionProcessInfo.SizeOfBuf = bufferSize; + sessionProcessInfo.Buffer = buffer; + + status = NtQuerySystemInformation( + SystemSessionProcessInformation, + &sessionProcessInfo, + sizeof(SYSTEM_SESSION_PROCESS_INFORMATION), + &bufferSize // size of the inner buffer gets returned + ); + + if (status == STATUS_BUFFER_TOO_SMALL || status == STATUS_INFO_LENGTH_MISMATCH) + { + PhFree(buffer); + buffer = PhAllocate(bufferSize); + } + else + { + break; + } + } + + if (!NT_SUCCESS(status)) + { + PhFree(buffer); + return status; + } + + if (bufferSize <= 0x100000) initialBufferSize = bufferSize; + *Processes = buffer; + + return status; +} + +/** + * Finds the process information structure for a specific process. + * + * \param Processes A pointer to a buffer returned by PhEnumProcesses(). + * \param ProcessId The ID of the process. + * + * \return A pointer to the process information structure for the specified process, or NULL if the + * structure could not be found. + */ +PSYSTEM_PROCESS_INFORMATION PhFindProcessInformation( + _In_ PVOID Processes, + _In_ HANDLE ProcessId + ) +{ + PSYSTEM_PROCESS_INFORMATION process; + + process = PH_FIRST_PROCESS(Processes); + + do + { + if (process->UniqueProcessId == ProcessId) + return process; + } while (process = PH_NEXT_PROCESS(process)); + + return NULL; +} + +/** + * Finds the process information structure for a specific process. + * + * \param Processes A pointer to a buffer returned by PhEnumProcesses(). + * \param ImageName The image name to search for. + * + * \return A pointer to the process information structure for the specified process, or NULL if the + * structure could not be found. + */ +PSYSTEM_PROCESS_INFORMATION PhFindProcessInformationByImageName( + _In_ PVOID Processes, + _In_ PPH_STRINGREF ImageName + ) +{ + PSYSTEM_PROCESS_INFORMATION process; + PH_STRINGREF processImageName; + + process = PH_FIRST_PROCESS(Processes); + + do + { + PhUnicodeStringToStringRef(&process->ImageName, &processImageName); + + if (PhEqualStringRef(&processImageName, ImageName, TRUE)) + return process; + } while (process = PH_NEXT_PROCESS(process)); + + return NULL; +} + +/** + * Enumerates all open handles. + * + * \param Handles A variable which receives a pointer to a structure containing information about + * all opened handles. You must free the structure using PhFree() when you no longer need it. + * + * \retval STATUS_INSUFFICIENT_RESOURCES The handle information returned by the kernel is too large. + */ +NTSTATUS PhEnumHandles( + _Out_ PSYSTEM_HANDLE_INFORMATION *Handles + ) +{ + static ULONG initialBufferSize = 0x4000; + NTSTATUS status; + PVOID buffer; + ULONG bufferSize; + + bufferSize = initialBufferSize; + buffer = PhAllocate(bufferSize); + + while ((status = NtQuerySystemInformation( + SystemHandleInformation, + buffer, + bufferSize, + NULL + )) == STATUS_INFO_LENGTH_MISMATCH) + { + PhFree(buffer); + bufferSize *= 2; + + // Fail if we're resizing the buffer to something very large. + if (bufferSize > PH_LARGE_BUFFER_SIZE) + return STATUS_INSUFFICIENT_RESOURCES; + + buffer = PhAllocate(bufferSize); + } + + if (!NT_SUCCESS(status)) + { + PhFree(buffer); + return status; + } + + if (bufferSize <= 0x100000) initialBufferSize = bufferSize; + *Handles = (PSYSTEM_HANDLE_INFORMATION)buffer; + + return status; +} + +/** + * Enumerates all open handles. + * + * \param Handles A variable which receives a pointer to a structure containing information about + * all opened handles. You must free the structure using PhFree() when you no longer need it. + * + * \retval STATUS_INSUFFICIENT_RESOURCES The handle information returned by the kernel is too large. + * + * \remarks This function is only available starting with Windows XP. + */ +NTSTATUS PhEnumHandlesEx( + _Out_ PSYSTEM_HANDLE_INFORMATION_EX *Handles + ) +{ + static ULONG initialBufferSize = 0x10000; + NTSTATUS status; + PVOID buffer; + ULONG bufferSize; + + bufferSize = initialBufferSize; + buffer = PhAllocate(bufferSize); + + while ((status = NtQuerySystemInformation( + SystemExtendedHandleInformation, + buffer, + bufferSize, + NULL + )) == STATUS_INFO_LENGTH_MISMATCH) + { + PhFree(buffer); + bufferSize *= 2; + + // Fail if we're resizing the buffer to something very large. + if (bufferSize > PH_LARGE_BUFFER_SIZE) + return STATUS_INSUFFICIENT_RESOURCES; + + buffer = PhAllocate(bufferSize); + } + + if (!NT_SUCCESS(status)) + { + PhFree(buffer); + return status; + } + + if (bufferSize <= 0x200000) initialBufferSize = bufferSize; + *Handles = (PSYSTEM_HANDLE_INFORMATION_EX)buffer; + + return status; +} + +/** + * Enumerates all pagefiles. + * + * \param Pagefiles A variable which receives a pointer to a buffer containing information about all + * active pagefiles. You must free the structure using PhFree() when you no longer need it. + * + * \retval STATUS_INSUFFICIENT_RESOURCES The handle information returned by the kernel is too large. + */ +NTSTATUS PhEnumPagefiles( + _Out_ PVOID *Pagefiles + ) +{ + NTSTATUS status; + PVOID buffer; + ULONG bufferSize = 0x200; + + buffer = PhAllocate(bufferSize); + + while ((status = NtQuerySystemInformation( + SystemPageFileInformation, + buffer, + bufferSize, + NULL + )) == STATUS_INFO_LENGTH_MISMATCH) + { + PhFree(buffer); + bufferSize *= 2; + + // Fail if we're resizing the buffer to something very large. + if (bufferSize > PH_LARGE_BUFFER_SIZE) + return STATUS_INSUFFICIENT_RESOURCES; + + buffer = PhAllocate(bufferSize); + } + + if (!NT_SUCCESS(status)) + { + PhFree(buffer); + return status; + } + + *Pagefiles = buffer; + + return status; +} + +/** + * Gets the file name of a process' image. + * + * \param ProcessId The ID of the process. + * \param FileName A variable which receives a pointer to a string containing the file name. You + * must free the string using PhDereferenceObject() when you no longer need it. + * + * \remarks This function only works on Windows Vista and above. There does not appear to be any + * access checking performed by the kernel for this. + */ +NTSTATUS PhGetProcessImageFileNameByProcessId( + _In_ HANDLE ProcessId, + _Out_ PPH_STRING *FileName + ) +{ + NTSTATUS status; + PVOID buffer; + ULONG bufferSize = 0x100; + SYSTEM_PROCESS_ID_INFORMATION processIdInfo; + + buffer = PhAllocate(bufferSize); + + processIdInfo.ProcessId = ProcessId; + processIdInfo.ImageName.Length = 0; + processIdInfo.ImageName.MaximumLength = (USHORT)bufferSize; + processIdInfo.ImageName.Buffer = buffer; + + status = NtQuerySystemInformation( + SystemProcessIdInformation, + &processIdInfo, + sizeof(SYSTEM_PROCESS_ID_INFORMATION), + NULL + ); + + if (status == STATUS_INFO_LENGTH_MISMATCH) + { + // Required length is stored in MaximumLength. + + PhFree(buffer); + buffer = PhAllocate(processIdInfo.ImageName.MaximumLength); + processIdInfo.ImageName.Buffer = buffer; + + status = NtQuerySystemInformation( + SystemProcessIdInformation, + &processIdInfo, + sizeof(SYSTEM_PROCESS_ID_INFORMATION), + NULL + ); + } + + if (!NT_SUCCESS(status)) + { + PhFree(buffer); + return status; + } + + *FileName = PhCreateStringFromUnicodeString(&processIdInfo.ImageName); + PhFree(buffer); + + return status; +} + +/** + * Determines if a process is managed. + * + * \param ProcessId The ID of the process. + * \param IsDotNet A variable which receives a boolean indicating whether the process is managed. + */ +NTSTATUS PhGetProcessIsDotNet( + _In_ HANDLE ProcessId, + _Out_ PBOOLEAN IsDotNet + ) +{ + return PhGetProcessIsDotNetEx(ProcessId, NULL, 0, IsDotNet, NULL); +} + +BOOLEAN NTAPI PhpIsDotNetEnumProcessModulesCallback( + _In_ PLDR_DATA_TABLE_ENTRY Module, + _In_opt_ PVOID Context + ) +{ + static UNICODE_STRING clrString = RTL_CONSTANT_STRING(L"clr.dll"); + static UNICODE_STRING mscorwksString = RTL_CONSTANT_STRING(L"mscorwks.dll"); + static UNICODE_STRING mscorsvrString = RTL_CONSTANT_STRING(L"mscorsvr.dll"); + static UNICODE_STRING mscorlibString = RTL_CONSTANT_STRING(L"mscorlib.dll"); + static UNICODE_STRING mscorlibNiString = RTL_CONSTANT_STRING(L"mscorlib.ni.dll"); + static UNICODE_STRING clrjitString = RTL_CONSTANT_STRING(L"clrjit.dll"); + static UNICODE_STRING frameworkString = RTL_CONSTANT_STRING(L"\\Microsoft.NET\\Framework\\"); + static UNICODE_STRING framework64String = RTL_CONSTANT_STRING(L"\\Microsoft.NET\\Framework64\\"); + + if ( + RtlEqualUnicodeString(&Module->BaseDllName, &clrString, TRUE) || + RtlEqualUnicodeString(&Module->BaseDllName, &mscorwksString, TRUE) || + RtlEqualUnicodeString(&Module->BaseDllName, &mscorsvrString, TRUE) + ) + { + UNICODE_STRING fileName; + PH_STRINGREF systemRootSr; + UNICODE_STRING systemRoot; + PUNICODE_STRING frameworkPart; + +#ifdef _WIN64 + if (*(PULONG)Context & PH_CLR_PROCESS_IS_WOW64) + { +#endif + frameworkPart = &frameworkString; +#ifdef _WIN64 + } + else + { + frameworkPart = &framework64String; + } +#endif + + fileName = Module->FullDllName; + PhGetSystemRoot(&systemRootSr); + PhStringRefToUnicodeString(&systemRootSr, &systemRoot); + + if (RtlPrefixUnicodeString(&systemRoot, &fileName, TRUE)) + { + fileName.Buffer = (PWCHAR)((PCHAR)fileName.Buffer + systemRoot.Length); + fileName.Length -= systemRoot.Length; + + if (RtlPrefixUnicodeString(frameworkPart, &fileName, TRUE)) + { + fileName.Buffer = (PWCHAR)((PCHAR)fileName.Buffer + frameworkPart->Length); + fileName.Length -= frameworkPart->Length; + + if (fileName.Length >= 4 * sizeof(WCHAR)) // vx.x + { + if (fileName.Buffer[1] == '1') + { + if (fileName.Buffer[3] == '0') + *(PULONG)Context |= PH_CLR_VERSION_1_0; + else if (fileName.Buffer[3] == '1') + *(PULONG)Context |= PH_CLR_VERSION_1_1; + } + else if (fileName.Buffer[1] == '2') + { + *(PULONG)Context |= PH_CLR_VERSION_2_0; + } + else if (fileName.Buffer[1] >= '4' && fileName.Buffer[1] <= '9') + { + *(PULONG)Context |= PH_CLR_VERSION_4_ABOVE; + } + } + } + } + } + else if ( + RtlEqualUnicodeString(&Module->BaseDllName, &mscorlibString, TRUE) || + RtlEqualUnicodeString(&Module->BaseDllName, &mscorlibNiString, TRUE) + ) + { + *(PULONG)Context |= PH_CLR_MSCORLIB_PRESENT; + } + else if (RtlEqualUnicodeString(&Module->BaseDllName, &clrjitString, TRUE)) + { + *(PULONG)Context |= PH_CLR_JIT_PRESENT; + } + + return TRUE; +} + +/** + * Determines if a process is managed. + * + * \param ProcessId The ID of the process. + * \param ProcessHandle An optional handle to the process. The handle must have + * PROCESS_QUERY_LIMITED_INFORMATION and PROCESS_VM_READ access. + * \param InFlags A combination of flags. + * \li \c PH_CLR_USE_SECTION_CHECK Checks for the existence of related section objects to determine + * whether the process is managed. + * \li \c PH_CLR_NO_WOW64_CHECK Instead of a separate query, uses the presence of the + * \c PH_CLR_KNOWN_IS_WOW64 flag to determine whether the process is running under WOW64. + * \li \c PH_CLR_KNOWN_IS_WOW64 When \c PH_CLR_NO_WOW64_CHECK is specified, indicates that the + * process is managed. + * \param IsDotNet A variable which receives a boolean indicating whether the process is managed. + * \param Flags A variable which receives additional flags. + */ +NTSTATUS PhGetProcessIsDotNetEx( + _In_ HANDLE ProcessId, + _In_opt_ HANDLE ProcessHandle, + _In_ ULONG InFlags, + _Out_opt_ PBOOLEAN IsDotNet, + _Out_opt_ PULONG Flags + ) +{ + NTSTATUS status = STATUS_SUCCESS; + HANDLE processHandle; + ULONG flags; +#ifdef _WIN64 + BOOLEAN isWow64; +#endif + + if (InFlags & PH_CLR_USE_SECTION_CHECK) + { + HANDLE sectionHandle; + OBJECT_ATTRIBUTES objectAttributes; + PPH_STRING sectionName; + UNICODE_STRING sectionNameUs; + PH_FORMAT format[2]; + + // Most .NET processes have a handle open to a section named + // \BaseNamedObjects\Cor_Private_IPCBlock(_v4)_. This is the same object used by + // the ICorPublish::GetProcess function. Instead of calling that function, we simply check + // for the existence of that section object. This means: + // * Better performance. + // * No need for admin rights to get .NET status of processes owned by other users. + + PhInitFormatIU(&format[1], (ULONG_PTR)ProcessId); + + // Version 4 section object + + PhInitFormatS(&format[0], L"\\BaseNamedObjects\\Cor_Private_IPCBlock_v4_"); + sectionName = PhFormat(format, 2, 96); + PhStringRefToUnicodeString(§ionName->sr, §ionNameUs); + + InitializeObjectAttributes( + &objectAttributes, + §ionNameUs, + OBJ_CASE_INSENSITIVE, + NULL, + NULL + ); + status = NtOpenSection( + §ionHandle, + SECTION_QUERY, + &objectAttributes + ); + PhDereferenceObject(sectionName); + + if (NT_SUCCESS(status) || status == STATUS_ACCESS_DENIED) + { + if (NT_SUCCESS(status)) + NtClose(sectionHandle); + + if (IsDotNet) + *IsDotNet = TRUE; + + if (Flags) + *Flags = PH_CLR_VERSION_4_ABOVE; + + return STATUS_SUCCESS; + } + + // Version 2 section object + + PhInitFormatS(&format[0], L"\\BaseNamedObjects\\Cor_Private_IPCBlock_"); + sectionName = PhFormat(format, 2, 90); + PhStringRefToUnicodeString(§ionName->sr, §ionNameUs); + + InitializeObjectAttributes( + &objectAttributes, + §ionNameUs, + OBJ_CASE_INSENSITIVE, + NULL, + NULL + ); + status = NtOpenSection( + §ionHandle, + SECTION_QUERY, + &objectAttributes + ); + PhDereferenceObject(sectionName); + + if (NT_SUCCESS(status) || status == STATUS_ACCESS_DENIED) + { + if (NT_SUCCESS(status)) + NtClose(sectionHandle); + + if (IsDotNet) + *IsDotNet = TRUE; + + if (Flags) + *Flags = PH_CLR_VERSION_2_0; + + return STATUS_SUCCESS; + } + } + + flags = 0; + processHandle = NULL; + + if (!ProcessHandle) + { + if (!NT_SUCCESS(status = PhOpenProcess(&processHandle, ProcessQueryAccess | PROCESS_VM_READ, ProcessId))) + return status; + + ProcessHandle = processHandle; + } + +#ifdef _WIN64 + if (InFlags & PH_CLR_NO_WOW64_CHECK) + { + isWow64 = !!(InFlags & PH_CLR_KNOWN_IS_WOW64); + } + else + { + isWow64 = FALSE; + PhGetProcessIsWow64(ProcessHandle, &isWow64); + } + + if (isWow64) + { + flags |= PH_CLR_PROCESS_IS_WOW64; + PhEnumProcessModules32(ProcessHandle, PhpIsDotNetEnumProcessModulesCallback, &flags); + } + else + { +#endif + PhEnumProcessModules(ProcessHandle, PhpIsDotNetEnumProcessModulesCallback, &flags); +#ifdef _WIN64 + } +#endif + + if (processHandle) + NtClose(processHandle); + + if (IsDotNet) + *IsDotNet = (flags & PH_CLR_VERSION_MASK) && (flags & (PH_CLR_MSCORLIB_PRESENT | PH_CLR_JIT_PRESENT)); + + if (Flags) + *Flags = flags; + + return status; +} + +/** + * Enumerates the objects in a directory object. + * + * \param DirectoryHandle A handle to a directory. The handle must have DIRECTORY_QUERY access. + * \param Callback A callback function which is executed for each object. + * \param Context A user-defined value to pass to the callback function. + */ +NTSTATUS PhEnumDirectoryObjects( + _In_ HANDLE DirectoryHandle, + _In_ PPH_ENUM_DIRECTORY_OBJECTS Callback, + _In_opt_ PVOID Context + ) +{ + NTSTATUS status; + ULONG context = 0; + BOOLEAN firstTime = TRUE; + ULONG bufferSize; + POBJECT_DIRECTORY_INFORMATION buffer; + ULONG i; + BOOLEAN cont; + + bufferSize = 0x200; + buffer = PhAllocate(bufferSize); + + while (TRUE) + { + // Get a batch of entries. + + while ((status = NtQueryDirectoryObject( + DirectoryHandle, + buffer, + bufferSize, + FALSE, + firstTime, + &context, + NULL + )) == STATUS_MORE_ENTRIES) + { + // Check if we have at least one entry. If not, we'll double the buffer size and try + // again. + if (buffer[0].Name.Buffer) + break; + + // Make sure we don't use too much memory. + if (bufferSize > PH_LARGE_BUFFER_SIZE) + { + PhFree(buffer); + return STATUS_INSUFFICIENT_RESOURCES; + } + + PhFree(buffer); + bufferSize *= 2; + buffer = PhAllocate(bufferSize); + } + + if (!NT_SUCCESS(status)) + { + PhFree(buffer); + return status; + } + + // Read the batch and execute the callback function for each object. + + i = 0; + cont = TRUE; + + while (TRUE) + { + POBJECT_DIRECTORY_INFORMATION info; + PH_STRINGREF name; + PH_STRINGREF typeName; + + info = &buffer[i]; + + if (!info->Name.Buffer) + break; + + PhUnicodeStringToStringRef(&info->Name, &name); + PhUnicodeStringToStringRef(&info->TypeName, &typeName); + + cont = Callback(&name, &typeName, Context); + + if (!cont) + break; + + i++; + } + + if (!cont) + break; + + if (status != STATUS_MORE_ENTRIES) + break; + + firstTime = FALSE; + } + + PhFree(buffer); + + return STATUS_SUCCESS; +} + +NTSTATUS PhEnumDirectoryFile( + _In_ HANDLE FileHandle, + _In_opt_ PUNICODE_STRING SearchPattern, + _In_ PPH_ENUM_DIRECTORY_FILE Callback, + _In_opt_ PVOID Context + ) +{ + NTSTATUS status; + IO_STATUS_BLOCK isb; + BOOLEAN firstTime = TRUE; + PVOID buffer; + ULONG bufferSize = 0x400; + ULONG i; + BOOLEAN cont; + + buffer = PhAllocate(bufferSize); + + while (TRUE) + { + // Query the directory, doubling the buffer each time NtQueryDirectoryFile fails. + while (TRUE) + { + status = NtQueryDirectoryFile( + FileHandle, + NULL, + NULL, + NULL, + &isb, + buffer, + bufferSize, + FileDirectoryInformation, + FALSE, + SearchPattern, + firstTime + ); + + // Our ISB is on the stack, so we have to wait for the operation to complete before + // continuing. + if (status == STATUS_PENDING) + { + status = NtWaitForSingleObject(FileHandle, FALSE, NULL); + + if (NT_SUCCESS(status)) + status = isb.Status; + } + + if (status == STATUS_BUFFER_OVERFLOW || status == STATUS_INFO_LENGTH_MISMATCH) + { + PhFree(buffer); + bufferSize *= 2; + buffer = PhAllocate(bufferSize); + } + else + { + break; + } + } + + // If we don't have any entries to read, exit. + if (status == STATUS_NO_MORE_FILES) + { + status = STATUS_SUCCESS; + break; + } + + if (!NT_SUCCESS(status)) + break; + + // Read the batch and execute the callback function for each file. + + i = 0; + cont = TRUE; + + while (TRUE) + { + PFILE_DIRECTORY_INFORMATION information; + + information = (PFILE_DIRECTORY_INFORMATION)(PTR_ADD_OFFSET(buffer, i)); + + if (!Callback( + information, + Context + )) + { + cont = FALSE; + break; + } + + if (information->NextEntryOffset != 0) + i += information->NextEntryOffset; + else + break; + } + + if (!cont) + break; + + firstTime = FALSE; + } + + PhFree(buffer); + + return status; +} + +NTSTATUS PhEnumFileStreams( + _In_ HANDLE FileHandle, + _Out_ PVOID *Streams + ) +{ + return PhpQueryFileVariableSize( + FileHandle, + FileStreamInformation, + Streams + ); +} + +/** + * Initializes the device prefixes module. + */ +VOID PhpInitializeDevicePrefixes( + VOID + ) +{ + ULONG i; + PUCHAR buffer; + + // Allocate one buffer for all 26 prefixes to reduce overhead. + buffer = PhAllocate(PH_DEVICE_PREFIX_LENGTH * sizeof(WCHAR) * 26); + + for (i = 0; i < 26; i++) + { + PhDevicePrefixes[i].Length = 0; + PhDevicePrefixes[i].MaximumLength = PH_DEVICE_PREFIX_LENGTH * sizeof(WCHAR); + PhDevicePrefixes[i].Buffer = (PWCHAR)buffer; + buffer += PH_DEVICE_PREFIX_LENGTH * sizeof(WCHAR); + } +} + +VOID PhUpdateMupDevicePrefixes( + VOID + ) +{ + static PH_STRINGREF orderKeyName = PH_STRINGREF_INIT(L"System\\CurrentControlSet\\Control\\NetworkProvider\\Order"); + static PH_STRINGREF servicesStringPart = PH_STRINGREF_INIT(L"System\\CurrentControlSet\\Services\\"); + static PH_STRINGREF networkProviderStringPart = PH_STRINGREF_INIT(L"\\NetworkProvider"); + + HANDLE orderKeyHandle; + PPH_STRING providerOrder = NULL; + ULONG i; + PH_STRINGREF remainingPart; + PH_STRINGREF part; + + // The provider names are stored in the ProviderOrder value in this key: + // HKLM\System\CurrentControlSet\Control\NetworkProvider\Order + // Each name can then be looked up, its device name in the DeviceName value in: + // HKLM\System\CurrentControlSet\Services\\NetworkProvider + + // Note that we assume the providers only claim their device name. Some providers such as DFS + // claim an extra part, and are not resolved correctly here. + + if (NT_SUCCESS(PhOpenKey( + &orderKeyHandle, + KEY_READ, + PH_KEY_LOCAL_MACHINE, + &orderKeyName, + 0 + ))) + { + providerOrder = PhQueryRegistryString(orderKeyHandle, L"ProviderOrder"); + NtClose(orderKeyHandle); + } + + if (!providerOrder) + return; + + PhAcquireQueuedLockExclusive(&PhDeviceMupPrefixesLock); + + for (i = 0; i < PhDeviceMupPrefixesCount; i++) + { + PhDereferenceObject(PhDeviceMupPrefixes[i]); + PhDeviceMupPrefixes[i] = NULL; + } + + PhDeviceMupPrefixesCount = 0; + + PhDeviceMupPrefixes[PhDeviceMupPrefixesCount++] = PhCreateString(L"\\Device\\Mup"); + + // DFS claims an extra part of file names, which we don't handle. + /*if (WindowsVersion >= WINDOWS_VISTA) + PhDeviceMupPrefixes[PhDeviceMupPrefixesCount++] = PhCreateString(L"\\Device\\DfsClient"); + else + PhDeviceMupPrefixes[PhDeviceMupPrefixesCount++] = PhCreateString(L"\\Device\\WinDfs");*/ + + remainingPart = providerOrder->sr; + + while (remainingPart.Length != 0) + { + PPH_STRING serviceKeyName; + HANDLE networkProviderKeyHandle; + PPH_STRING deviceName; + + if (PhDeviceMupPrefixesCount == PH_DEVICE_MUP_PREFIX_MAX_COUNT) + break; + + PhSplitStringRefAtChar(&remainingPart, ',', &part, &remainingPart); + + if (part.Length != 0) + { + serviceKeyName = PhConcatStringRef3(&servicesStringPart, &part, &networkProviderStringPart); + + if (NT_SUCCESS(PhOpenKey( + &networkProviderKeyHandle, + KEY_READ, + PH_KEY_LOCAL_MACHINE, + &serviceKeyName->sr, + 0 + ))) + { + if (deviceName = PhQueryRegistryString(networkProviderKeyHandle, L"DeviceName")) + { + PhDeviceMupPrefixes[PhDeviceMupPrefixesCount] = deviceName; + PhDeviceMupPrefixesCount++; + } + + NtClose(networkProviderKeyHandle); + } + + PhDereferenceObject(serviceKeyName); + } + } + + PhReleaseQueuedLockExclusive(&PhDeviceMupPrefixesLock); + + PhDereferenceObject(providerOrder); +} + +/** + * Updates the DOS device names array. + */ +VOID PhUpdateDosDevicePrefixes( + VOID + ) +{ + WCHAR deviceNameBuffer[7] = L"\\??\\ :"; + ULONG i; + + for (i = 0; i < 26; i++) + { + HANDLE linkHandle; + OBJECT_ATTRIBUTES oa; + UNICODE_STRING deviceName; + + deviceNameBuffer[4] = (WCHAR)('A' + i); + deviceName.Buffer = deviceNameBuffer; + deviceName.Length = 6 * sizeof(WCHAR); + + InitializeObjectAttributes( + &oa, + &deviceName, + OBJ_CASE_INSENSITIVE, + NULL, + NULL + ); + + if (NT_SUCCESS(NtOpenSymbolicLinkObject( + &linkHandle, + SYMBOLIC_LINK_QUERY, + &oa + ))) + { + PhAcquireQueuedLockExclusive(&PhDevicePrefixesLock); + + if (!NT_SUCCESS(NtQuerySymbolicLinkObject( + linkHandle, + &PhDevicePrefixes[i], + NULL + ))) + { + PhDevicePrefixes[i].Length = 0; + } + + PhReleaseQueuedLockExclusive(&PhDevicePrefixesLock); + + NtClose(linkHandle); + } + else + { + PhDevicePrefixes[i].Length = 0; + } + } +} + +/** + * Resolves a NT path into a Win32 path. + * + * \param Name A string containing the path to resolve. + * + * \return A pointer to a string containing the Win32 path. You must free the string using + * PhDereferenceObject() when you no longer need it. + */ +PPH_STRING PhResolveDevicePrefix( + _In_ PPH_STRING Name + ) +{ + ULONG i; + PPH_STRING newName = NULL; + + if (PhBeginInitOnce(&PhDevicePrefixesInitOnce)) + { + PhpInitializeDevicePrefixes(); + PhUpdateDosDevicePrefixes(); + PhUpdateMupDevicePrefixes(); + + PhEndInitOnce(&PhDevicePrefixesInitOnce); + } + + // Go through the DOS devices and try to find a matching prefix. + for (i = 0; i < 26; i++) + { + BOOLEAN isPrefix = FALSE; + PH_STRINGREF prefix; + + PhAcquireQueuedLockShared(&PhDevicePrefixesLock); + + PhUnicodeStringToStringRef(&PhDevicePrefixes[i], &prefix); + + if (prefix.Length != 0) + { + if (PhStartsWithStringRef(&Name->sr, &prefix, TRUE)) + { + // To ensure we match the longest prefix, make sure the next character is a + // backslash or the path is equal to the prefix. + if (Name->Length == prefix.Length || Name->Buffer[prefix.Length / sizeof(WCHAR)] == '\\') + { + isPrefix = TRUE; + } + } + } + + PhReleaseQueuedLockShared(&PhDevicePrefixesLock); + + if (isPrefix) + { + // :path + newName = PhCreateStringEx(NULL, 2 * sizeof(WCHAR) + Name->Length - prefix.Length); + newName->Buffer[0] = (WCHAR)('A' + i); + newName->Buffer[1] = ':'; + memcpy( + &newName->Buffer[2], + &Name->Buffer[prefix.Length / sizeof(WCHAR)], + Name->Length - prefix.Length + ); + + break; + } + } + + if (i == 26) + { + // Resolve network providers. + + PhAcquireQueuedLockShared(&PhDeviceMupPrefixesLock); + + for (i = 0; i < PhDeviceMupPrefixesCount; i++) + { + BOOLEAN isPrefix = FALSE; + SIZE_T prefixLength; + + prefixLength = PhDeviceMupPrefixes[i]->Length; + + if (prefixLength != 0) + { + if (PhStartsWithString(Name, PhDeviceMupPrefixes[i], TRUE)) + { + // To ensure we match the longest prefix, make sure the next character is a + // backslash. Don't resolve if the name *is* the prefix. Otherwise, we will end + // up with a useless string like "\". + if (Name->Length != prefixLength && Name->Buffer[prefixLength / sizeof(WCHAR)] == '\\') + { + isPrefix = TRUE; + } + } + } + + if (isPrefix) + { + // \path + newName = PhCreateStringEx(NULL, 1 * sizeof(WCHAR) + Name->Length - prefixLength); + newName->Buffer[0] = '\\'; + memcpy( + &newName->Buffer[1], + &Name->Buffer[prefixLength / sizeof(WCHAR)], + Name->Length - prefixLength + ); + + break; + } + } + + PhReleaseQueuedLockShared(&PhDeviceMupPrefixesLock); + } + + return newName; +} + +/** + * Converts a file name into Win32 format. + * + * \param FileName A string containing a file name. + * + * \return A pointer to a string containing the Win32 file name. You must free the string using + * PhDereferenceObject() when you no longer need it. + * + * \remarks This function may convert NT object name paths to invalid ones. If the path to be + * converted is not necessarily a file name, use PhResolveDevicePrefix(). + */ +PPH_STRING PhGetFileName( + _In_ PPH_STRING FileName + ) +{ + PPH_STRING newFileName; + + newFileName = FileName; + + // "\??\" refers to \GLOBAL??\. Just remove it. + if (PhStartsWithString2(FileName, L"\\??\\", FALSE)) + { + newFileName = PhCreateStringEx(NULL, FileName->Length - 4 * 2); + memcpy(newFileName->Buffer, &FileName->Buffer[4], FileName->Length - 4 * 2); + } + // "\SystemRoot" means "C:\Windows". + else if (PhStartsWithString2(FileName, L"\\SystemRoot", TRUE)) + { + PH_STRINGREF systemRoot; + + PhGetSystemRoot(&systemRoot); + newFileName = PhCreateStringEx(NULL, systemRoot.Length + FileName->Length - 11 * 2); + memcpy(newFileName->Buffer, systemRoot.Buffer, systemRoot.Length); + memcpy((PCHAR)newFileName->Buffer + systemRoot.Length, &FileName->Buffer[11], FileName->Length - 11 * 2); + } + // "system32\" means "C:\Windows\system32\". + else if (PhStartsWithString2(FileName, L"system32\\", TRUE)) + { + PH_STRINGREF systemRoot; + + PhGetSystemRoot(&systemRoot); + newFileName = PhCreateStringEx(NULL, systemRoot.Length + 2 + FileName->Length); + memcpy(newFileName->Buffer, systemRoot.Buffer, systemRoot.Length); + newFileName->Buffer[systemRoot.Length / 2] = '\\'; + memcpy((PCHAR)newFileName->Buffer + systemRoot.Length + 2, FileName->Buffer, FileName->Length); + } + else if (FileName->Length != 0 && FileName->Buffer[0] == '\\') + { + PPH_STRING resolvedName; + + resolvedName = PhResolveDevicePrefix(FileName); + + if (resolvedName) + { + newFileName = resolvedName; + } + else + { + // We didn't find a match. + // If the file name starts with "\Windows", prepend the system drive. + if (PhStartsWithString2(newFileName, L"\\Windows", TRUE)) + { + newFileName = PhCreateStringEx(NULL, FileName->Length + 2 * 2); + newFileName->Buffer[0] = USER_SHARED_DATA->NtSystemRoot[0]; + newFileName->Buffer[1] = ':'; + memcpy(&newFileName->Buffer[2], FileName->Buffer, FileName->Length); + } + else + { + PhReferenceObject(newFileName); + } + } + } + else + { + // Just return the supplied file name. Note that we need to add a reference. + PhReferenceObject(newFileName); + } + + return newFileName; +} + +typedef struct _ENUM_GENERIC_PROCESS_MODULES_CONTEXT +{ + PPH_ENUM_GENERIC_MODULES_CALLBACK Callback; + PVOID Context; + ULONG Type; + PPH_HASHTABLE BaseAddressHashtable; + + ULONG LoadOrderIndex; +} ENUM_GENERIC_PROCESS_MODULES_CONTEXT, *PENUM_GENERIC_PROCESS_MODULES_CONTEXT; + +static BOOLEAN EnumGenericProcessModulesCallback( + _In_ PLDR_DATA_TABLE_ENTRY Module, + _In_opt_ PVOID Context + ) +{ + PENUM_GENERIC_PROCESS_MODULES_CONTEXT context; + PH_MODULE_INFO moduleInfo; + PPH_STRING fileName; + BOOLEAN cont; + + context = (PENUM_GENERIC_PROCESS_MODULES_CONTEXT)Context; + + // Check if we have a duplicate base address. + if (PhFindEntryHashtable(context->BaseAddressHashtable, &Module->DllBase)) + { + return TRUE; + } + else + { + PhAddEntryHashtable(context->BaseAddressHashtable, &Module->DllBase); + } + + fileName = PhCreateStringFromUnicodeString(&Module->FullDllName); + + moduleInfo.Type = context->Type; + moduleInfo.BaseAddress = Module->DllBase; + moduleInfo.Size = Module->SizeOfImage; + moduleInfo.EntryPoint = Module->EntryPoint; + moduleInfo.Flags = Module->Flags; + moduleInfo.Name = PhCreateStringFromUnicodeString(&Module->BaseDllName); + moduleInfo.FileName = PhGetFileName(fileName); + moduleInfo.LoadOrderIndex = (USHORT)(context->LoadOrderIndex++); + moduleInfo.LoadCount = Module->ObsoleteLoadCount; + + if (WindowsVersion >= WINDOWS_8) + { + moduleInfo.LoadReason = (USHORT)Module->LoadReason; + moduleInfo.LoadTime = Module->LoadTime; + } + else + { + moduleInfo.LoadReason = -1; + moduleInfo.LoadTime.QuadPart = 0; + } + + PhDereferenceObject(fileName); + + cont = context->Callback(&moduleInfo, context->Context); + + PhDereferenceObject(moduleInfo.Name); + PhDereferenceObject(moduleInfo.FileName); + + return cont; +} + +VOID PhpRtlModulesToGenericModules( + _In_ PRTL_PROCESS_MODULES Modules, + _In_ PPH_ENUM_GENERIC_MODULES_CALLBACK Callback, + _In_opt_ PVOID Context, + _In_ PPH_HASHTABLE BaseAddressHashtable + ) +{ + PRTL_PROCESS_MODULE_INFORMATION module; + ULONG i; + PH_MODULE_INFO moduleInfo; + BOOLEAN cont; + + for (i = 0; i < Modules->NumberOfModules; i++) + { + PPH_STRING fileName; + + module = &Modules->Modules[i]; + + // Check if we have a duplicate base address. + if (PhFindEntryHashtable(BaseAddressHashtable, &module->ImageBase)) + { + continue; + } + else + { + PhAddEntryHashtable(BaseAddressHashtable, &module->ImageBase); + } + + fileName = PhConvertMultiByteToUtf16(module->FullPathName); + + if ((ULONG_PTR)module->ImageBase <= PhSystemBasicInformation.MaximumUserModeAddress) + moduleInfo.Type = PH_MODULE_TYPE_MODULE; + else + moduleInfo.Type = PH_MODULE_TYPE_KERNEL_MODULE; + + moduleInfo.BaseAddress = module->ImageBase; + moduleInfo.Size = module->ImageSize; + moduleInfo.EntryPoint = NULL; + moduleInfo.Flags = module->Flags; + moduleInfo.Name = PhConvertMultiByteToUtf16(&module->FullPathName[module->OffsetToFileName]); + moduleInfo.FileName = PhGetFileName(fileName); // convert to DOS file name + moduleInfo.LoadOrderIndex = module->LoadOrderIndex; + moduleInfo.LoadCount = module->LoadCount; + moduleInfo.LoadReason = -1; + moduleInfo.LoadTime.QuadPart = 0; + + PhDereferenceObject(fileName); + + if (module->OffsetToFileName == 0) + { + static PH_STRINGREF driversString = PH_STRINGREF_INIT(L"\\System32\\Drivers\\"); + PH_STRINGREF systemRoot; + PPH_STRING newFileName; + + // We only have the file name, without a path. The driver must be in the default drivers + // directory. + PhGetSystemRoot(&systemRoot); + newFileName = PhConcatStringRef3(&systemRoot, &driversString, &moduleInfo.Name->sr); + PhDereferenceObject(moduleInfo.FileName); + moduleInfo.FileName = newFileName; + } + + cont = Callback(&moduleInfo, Context); + + PhDereferenceObject(moduleInfo.Name); + PhDereferenceObject(moduleInfo.FileName); + + if (!cont) + break; + } +} + +VOID PhpRtlModulesExToGenericModules( + _In_ PRTL_PROCESS_MODULE_INFORMATION_EX Modules, + _In_ PPH_ENUM_GENERIC_MODULES_CALLBACK Callback, + _In_opt_ PVOID Context, + _In_ PPH_HASHTABLE BaseAddressHashtable + ) +{ + PRTL_PROCESS_MODULE_INFORMATION_EX module; + PH_MODULE_INFO moduleInfo; + BOOLEAN cont; + + module = Modules; + + while (module->NextOffset != 0) + { + PPH_STRING fileName; + + // Check if we have a duplicate base address. + if (PhFindEntryHashtable(BaseAddressHashtable, &module->BaseInfo.ImageBase)) + { + continue; + } + else + { + PhAddEntryHashtable(BaseAddressHashtable, &module->BaseInfo.ImageBase); + } + + fileName = PhConvertMultiByteToUtf16(module->BaseInfo.FullPathName); + + if ((ULONG_PTR)module->BaseInfo.ImageBase <= PhSystemBasicInformation.MaximumUserModeAddress) + moduleInfo.Type = PH_MODULE_TYPE_MODULE; + else + moduleInfo.Type = PH_MODULE_TYPE_KERNEL_MODULE; + + moduleInfo.BaseAddress = module->BaseInfo.ImageBase; + moduleInfo.Size = module->BaseInfo.ImageSize; + moduleInfo.EntryPoint = NULL; + moduleInfo.Flags = module->BaseInfo.Flags; + moduleInfo.Name = PhConvertMultiByteToUtf16(&module->BaseInfo.FullPathName[module->BaseInfo.OffsetToFileName]); + moduleInfo.FileName = PhGetFileName(fileName); // convert to DOS file name + moduleInfo.LoadOrderIndex = module->BaseInfo.LoadOrderIndex; + moduleInfo.LoadCount = module->BaseInfo.LoadCount; + moduleInfo.LoadReason = -1; + moduleInfo.LoadTime.QuadPart = 0; + + PhDereferenceObject(fileName); + + cont = Callback(&moduleInfo, Context); + + PhDereferenceObject(moduleInfo.Name); + PhDereferenceObject(moduleInfo.FileName); + + if (!cont) + break; + + module = PTR_ADD_OFFSET(module, module->NextOffset); + } +} + +BOOLEAN PhpCallbackMappedFileOrImage( + _In_ PVOID AllocationBase, + _In_ SIZE_T AllocationSize, + _In_ ULONG Type, + _In_ PPH_STRING FileName, + _In_ PPH_ENUM_GENERIC_MODULES_CALLBACK Callback, + _In_opt_ PVOID Context, + _In_ PPH_HASHTABLE BaseAddressHashtable + ) +{ + PH_MODULE_INFO moduleInfo; + BOOLEAN cont; + + moduleInfo.Type = Type; + moduleInfo.BaseAddress = AllocationBase; + moduleInfo.Size = (ULONG)AllocationSize; + moduleInfo.EntryPoint = NULL; + moduleInfo.Flags = 0; + moduleInfo.FileName = PhGetFileName(FileName); + moduleInfo.Name = PhGetBaseName(moduleInfo.FileName); + moduleInfo.LoadOrderIndex = -1; + moduleInfo.LoadCount = -1; + moduleInfo.LoadReason = -1; + moduleInfo.LoadTime.QuadPart = 0; + + cont = Callback(&moduleInfo, Context); + + PhDereferenceObject(moduleInfo.FileName); + PhDereferenceObject(moduleInfo.Name); + + return cont; +} + +VOID PhpEnumGenericMappedFilesAndImages( + _In_ HANDLE ProcessHandle, + _In_ ULONG Flags, + _In_ PPH_ENUM_GENERIC_MODULES_CALLBACK Callback, + _In_opt_ PVOID Context, + _In_ PPH_HASHTABLE BaseAddressHashtable + ) +{ + BOOLEAN querySucceeded; + PVOID baseAddress; + MEMORY_BASIC_INFORMATION basicInfo; + + baseAddress = (PVOID)0; + + if (!NT_SUCCESS(NtQueryVirtualMemory( + ProcessHandle, + baseAddress, + MemoryBasicInformation, + &basicInfo, + sizeof(MEMORY_BASIC_INFORMATION), + NULL + ))) + { + return; + } + + querySucceeded = TRUE; + + while (querySucceeded) + { + PVOID allocationBase; + SIZE_T allocationSize; + ULONG type; + PPH_STRING fileName; + BOOLEAN cont; + + if (basicInfo.Type == MEM_MAPPED || basicInfo.Type == MEM_IMAGE) + { + if (basicInfo.Type == MEM_MAPPED) + type = PH_MODULE_TYPE_MAPPED_FILE; + else + type = PH_MODULE_TYPE_MAPPED_IMAGE; + + // Find the total allocation size. + + allocationBase = basicInfo.AllocationBase; + allocationSize = 0; + + do + { + baseAddress = (PVOID)((ULONG_PTR)baseAddress + basicInfo.RegionSize); + allocationSize += basicInfo.RegionSize; + + if (!NT_SUCCESS(NtQueryVirtualMemory( + ProcessHandle, + baseAddress, + MemoryBasicInformation, + &basicInfo, + sizeof(MEMORY_BASIC_INFORMATION), + NULL + ))) + { + querySucceeded = FALSE; + break; + } + } while (basicInfo.AllocationBase == allocationBase); + + if ((type == PH_MODULE_TYPE_MAPPED_FILE && !(Flags & PH_ENUM_GENERIC_MAPPED_FILES)) || + (type == PH_MODULE_TYPE_MAPPED_IMAGE && !(Flags & PH_ENUM_GENERIC_MAPPED_IMAGES))) + { + // The user doesn't want this type of entry. + continue; + } + + // Check if we have a duplicate base address. + if (PhFindEntryHashtable(BaseAddressHashtable, &allocationBase)) + { + continue; + } + + if (!NT_SUCCESS(PhGetProcessMappedFileName( + ProcessHandle, + allocationBase, + &fileName + ))) + { + continue; + } + + PhAddEntryHashtable(BaseAddressHashtable, &allocationBase); + + cont = PhpCallbackMappedFileOrImage( + allocationBase, + allocationSize, + type, + fileName, + Callback, + Context, + BaseAddressHashtable + ); + + PhDereferenceObject(fileName); + + if (!cont) + break; + } + else + { + baseAddress = (PVOID)((ULONG_PTR)baseAddress + basicInfo.RegionSize); + + if (!NT_SUCCESS(NtQueryVirtualMemory( + ProcessHandle, + baseAddress, + MemoryBasicInformation, + &basicInfo, + sizeof(MEMORY_BASIC_INFORMATION), + NULL + ))) + { + querySucceeded = FALSE; + } + } + } +} + +BOOLEAN NTAPI PhpBaseAddressHashtableEqualFunction( + _In_ PVOID Entry1, + _In_ PVOID Entry2 + ) +{ + return *(PVOID *)Entry1 == *(PVOID *)Entry2; +} + +ULONG NTAPI PhpBaseAddressHashtableHashFunction( + _In_ PVOID Entry + ) +{ + return PhHashIntPtr((ULONG_PTR)*(PVOID *)Entry); +} + +/** + * Enumerates the modules loaded by a process. + * + * \param ProcessId The ID of a process. If \ref SYSTEM_PROCESS_ID is specified the function + * enumerates the kernel modules. + * \param ProcessHandle A handle to the process. + * \param Flags Flags controlling the information to retrieve. + * \li \c PH_ENUM_GENERIC_MAPPED_FILES Enumerate mapped files. + * \li \c PH_ENUM_GENERIC_MAPPED_IMAGES Enumerate mapped images (those which are not mapped by the + * loader). + * \param Callback A callback function which is executed for each module. + * \param Context A user-defined value to pass to the callback function. + */ +NTSTATUS PhEnumGenericModules( + _In_ HANDLE ProcessId, + _In_opt_ HANDLE ProcessHandle, + _In_ ULONG Flags, + _In_ PPH_ENUM_GENERIC_MODULES_CALLBACK Callback, + _In_opt_ PVOID Context + ) +{ + NTSTATUS status; + PPH_HASHTABLE baseAddressHashtable; + + baseAddressHashtable = PhCreateHashtable( + sizeof(PVOID), + PhpBaseAddressHashtableEqualFunction, + PhpBaseAddressHashtableHashFunction, + 32 + ); + + if (ProcessId == SYSTEM_PROCESS_ID) + { + // Kernel modules + + PVOID modules; + + if (NT_SUCCESS(status = PhEnumKernelModules((PRTL_PROCESS_MODULES *)&modules))) + { + PhpRtlModulesToGenericModules( + modules, + Callback, + Context, + baseAddressHashtable + ); + PhFree(modules); + } + } + else + { + // Process modules + + BOOLEAN opened = FALSE; +#ifdef _WIN64 + BOOLEAN isWow64 = FALSE; +#endif + ENUM_GENERIC_PROCESS_MODULES_CONTEXT context; + PH_ENUM_PROCESS_MODULES_PARAMETERS parameters; + + if (!ProcessHandle) + { + if (!NT_SUCCESS(status = PhOpenProcess( + &ProcessHandle, + PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, // needed for enumerating mapped files + ProcessId + ))) + { + if (!NT_SUCCESS(status = PhOpenProcess( + &ProcessHandle, + ProcessQueryAccess | PROCESS_VM_READ, + ProcessId + ))) + { + goto CleanupExit; + } + } + + opened = TRUE; + } + + context.Callback = Callback; + context.Context = Context; + context.Type = PH_MODULE_TYPE_MODULE; + context.BaseAddressHashtable = baseAddressHashtable; + context.LoadOrderIndex = 0; + + parameters.Callback = EnumGenericProcessModulesCallback; + parameters.Context = &context; + parameters.Flags = PH_ENUM_PROCESS_MODULES_TRY_MAPPED_FILE_NAME; + + status = PhEnumProcessModulesEx( + ProcessHandle, + ¶meters + ); + +#ifdef _WIN64 + PhGetProcessIsWow64(ProcessHandle, &isWow64); + + // 32-bit process modules + if (isWow64) + { + context.Callback = Callback; + context.Context = Context; + context.Type = PH_MODULE_TYPE_WOW64_MODULE; + context.BaseAddressHashtable = baseAddressHashtable; + context.LoadOrderIndex = 0; + + status = PhEnumProcessModules32Ex( + ProcessHandle, + ¶meters + ); + } +#endif + + // Mapped files and mapped images + // This is done last because it provides the least amount of information. + + if (Flags & (PH_ENUM_GENERIC_MAPPED_FILES | PH_ENUM_GENERIC_MAPPED_IMAGES)) + { + PhpEnumGenericMappedFilesAndImages( + ProcessHandle, + Flags, + Callback, + Context, + baseAddressHashtable + ); + } + + if (opened) + NtClose(ProcessHandle); + } + +CleanupExit: + PhDereferenceObject(baseAddressHashtable); + + return status; +} + +/** + * Initializes usage of predefined keys. + */ +VOID PhpInitializePredefineKeys( + VOID + ) +{ + static UNICODE_STRING currentUserPrefix = RTL_CONSTANT_STRING(L"\\Registry\\User\\"); + + NTSTATUS status; + HANDLE tokenHandle; + PTOKEN_USER tokenUser; + UNICODE_STRING stringSid; + WCHAR stringSidBuffer[MAX_UNICODE_STACK_BUFFER_LENGTH]; + PUNICODE_STRING currentUserKeyName; + + // Get the string SID of the current user. + if (NT_SUCCESS(status = NtOpenProcessToken(NtCurrentProcess(), TOKEN_QUERY, &tokenHandle))) + { + if (NT_SUCCESS(status = PhGetTokenUser(tokenHandle, &tokenUser))) + { + stringSid.Buffer = stringSidBuffer; + stringSid.MaximumLength = sizeof(stringSidBuffer); + + status = RtlConvertSidToUnicodeString( + &stringSid, + tokenUser->User.Sid, + FALSE + ); + + PhFree(tokenUser); + } + + NtClose(tokenHandle); + } + + // Construct the current user key name. + if (NT_SUCCESS(status)) + { + currentUserKeyName = &PhPredefineKeyNames[PH_KEY_CURRENT_USER_NUMBER]; + currentUserKeyName->Length = currentUserPrefix.Length + stringSid.Length; + currentUserKeyName->Buffer = PhAllocate(currentUserKeyName->Length + sizeof(WCHAR)); + memcpy(currentUserKeyName->Buffer, currentUserPrefix.Buffer, currentUserPrefix.Length); + memcpy(¤tUserKeyName->Buffer[currentUserPrefix.Length / sizeof(WCHAR)], stringSid.Buffer, stringSid.Length); + } +} + +/** + * Initializes the attributes of a key object for creating/opening. + * + * \param RootDirectory A handle to a root key, or one of the predefined keys. See PhCreateKey() for + * details. + * \param ObjectName The path to the key. + * \param Attributes Additional object flags. + * \param ObjectAttributes The OBJECT_ATTRIBUTES structure to initialize. + * \param NeedsClose A variable which receives a handle that must be closed when the create/open + * operation is finished. The variable may be set to NULL if no handle needs to be closed. + */ +NTSTATUS PhpInitializeKeyObjectAttributes( + _In_opt_ HANDLE RootDirectory, + _In_ PUNICODE_STRING ObjectName, + _In_ ULONG Attributes, + _Out_ POBJECT_ATTRIBUTES ObjectAttributes, + _Out_ PHANDLE NeedsClose + ) +{ + NTSTATUS status; + ULONG predefineIndex; + HANDLE predefineHandle; + OBJECT_ATTRIBUTES predefineObjectAttributes; + + InitializeObjectAttributes( + ObjectAttributes, + ObjectName, + Attributes | OBJ_CASE_INSENSITIVE, + RootDirectory, + NULL + ); + + *NeedsClose = NULL; + + if (RootDirectory && PH_KEY_IS_PREDEFINED(RootDirectory)) + { + predefineIndex = PH_KEY_PREDEFINE_TO_NUMBER(RootDirectory); + + if (predefineIndex < PH_KEY_MAXIMUM_PREDEFINE) + { + if (PhBeginInitOnce(&PhPredefineKeyInitOnce)) + { + PhpInitializePredefineKeys(); + PhEndInitOnce(&PhPredefineKeyInitOnce); + } + + predefineHandle = PhPredefineKeyHandles[predefineIndex]; + + if (!predefineHandle) + { + // The predefined key has not been opened yet. Do so now. + + if (!PhPredefineKeyNames[predefineIndex].Buffer) // we may have failed in getting the current user key name + return STATUS_UNSUCCESSFUL; + + InitializeObjectAttributes( + &predefineObjectAttributes, + &PhPredefineKeyNames[predefineIndex], + OBJ_CASE_INSENSITIVE, + NULL, + NULL + ); + + status = NtOpenKey( + &predefineHandle, + KEY_READ, + &predefineObjectAttributes + ); + + if (!NT_SUCCESS(status)) + return status; + + if (_InterlockedCompareExchangePointer( + &PhPredefineKeyHandles[predefineIndex], + predefineHandle, + NULL + ) != NULL) + { + // Someone else already opened the key and cached it. Indicate that the caller + // needs to close the handle later, since it isn't shared. + *NeedsClose = predefineHandle; + } + } + + ObjectAttributes->RootDirectory = predefineHandle; + } + } + + return STATUS_SUCCESS; +} + +/** + * Creates or opens a registry key. + * + * \param KeyHandle A variable which receives a handle to the key. + * \param DesiredAccess The desired access to the key. + * \param RootDirectory A handle to a root key, or one of the following predefined keys: + * \li \c PH_KEY_LOCAL_MACHINE Represents \\Registry\\Machine. + * \li \c PH_KEY_USERS Represents \\Registry\\User. + * \li \c PH_KEY_CLASSES_ROOT Represents \\Registry\\Machine\\Software\\Classes. + * \li \c PH_KEY_CURRENT_USER Represents \\Registry\\User\\[SID of current user]. + * \param ObjectName The path to the key. + * \param Attributes Additional object flags. + * \param CreateOptions The options to apply when creating or opening the key. + * \param Disposition A variable which receives a value indicating whether a new key was created or + * an existing key was opened: + * \li \c REG_CREATED_NEW_KEY A new key was created. + * \li \c REG_OPENED_EXISTING_KEY An existing key was opened. + */ +NTSTATUS PhCreateKey( + _Out_ PHANDLE KeyHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_opt_ HANDLE RootDirectory, + _In_ PPH_STRINGREF ObjectName, + _In_ ULONG Attributes, + _In_ ULONG CreateOptions, + _Out_opt_ PULONG Disposition + ) +{ + NTSTATUS status; + UNICODE_STRING objectName; + OBJECT_ATTRIBUTES objectAttributes; + HANDLE needsClose; + + if (!PhStringRefToUnicodeString(ObjectName, &objectName)) + return STATUS_NAME_TOO_LONG; + + if (!NT_SUCCESS(status = PhpInitializeKeyObjectAttributes( + RootDirectory, + &objectName, + Attributes, + &objectAttributes, + &needsClose + ))) + { + return status; + } + + status = NtCreateKey( + KeyHandle, + DesiredAccess, + &objectAttributes, + 0, + NULL, + CreateOptions, + Disposition + ); + + if (needsClose) + NtClose(needsClose); + + return status; +} + +/** + * Opens a registry key. + * + * \param KeyHandle A variable which receives a handle to the key. + * \param DesiredAccess The desired access to the key. + * \param RootDirectory A handle to a root key, or one of the predefined keys. See PhCreateKey() for + * details. + * \param ObjectName The path to the key. + * \param Attributes Additional object flags. + */ +NTSTATUS PhOpenKey( + _Out_ PHANDLE KeyHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_opt_ HANDLE RootDirectory, + _In_ PPH_STRINGREF ObjectName, + _In_ ULONG Attributes + ) +{ + NTSTATUS status; + UNICODE_STRING objectName; + OBJECT_ATTRIBUTES objectAttributes; + HANDLE needsClose; + + if (!PhStringRefToUnicodeString(ObjectName, &objectName)) + return STATUS_NAME_TOO_LONG; + + if (!NT_SUCCESS(status = PhpInitializeKeyObjectAttributes( + RootDirectory, + &objectName, + Attributes, + &objectAttributes, + &needsClose + ))) + { + return status; + } + + status = NtOpenKey( + KeyHandle, + DesiredAccess, + &objectAttributes + ); + + if (needsClose) + NtClose(needsClose); + + return status; +} + +/** + * Gets information about a registry key. + * + * \param KeyHandle A handle to the key. + * \param KeyInformationClass The information class to query. + * \param Buffer A variable which receives a pointer to a buffer containing information about the + * registry key. You must free the buffer with PhFree() when you no longer need it. + */ +NTSTATUS PhQueryKey( + _In_ HANDLE KeyHandle, + _In_ KEY_INFORMATION_CLASS KeyInformationClass, + _Out_ PVOID *Buffer + ) +{ + NTSTATUS status; + PVOID buffer; + ULONG bufferSize; + ULONG attempts = 16; + + bufferSize = 0x100; + buffer = PhAllocate(bufferSize); + + do + { + status = NtQueryKey( + KeyHandle, + KeyInformationClass, + buffer, + bufferSize, + &bufferSize + ); + + if (NT_SUCCESS(status)) + break; + + if (status == STATUS_BUFFER_OVERFLOW) + { + PhFree(buffer); + buffer = PhAllocate(bufferSize); + } + else + { + PhFree(buffer); + return status; + } + } while (--attempts); + + *Buffer = buffer; + + return status; +} + +/** + * Gets a registry value of any type. + * + * \param KeyHandle A handle to the key. + * \param ValueName The name of the value. + * \param KeyValueInformationClass The information class to query. + * \param Buffer A variable which receives a pointer to a buffer containing information about the + * registry value. You must free the buffer with PhFree() when you no longer need it. + */ +NTSTATUS PhQueryValueKey( + _In_ HANDLE KeyHandle, + _In_opt_ PPH_STRINGREF ValueName, + _In_ KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass, + _Out_ PVOID *Buffer + ) +{ + NTSTATUS status; + UNICODE_STRING valueName; + PVOID buffer; + ULONG bufferSize; + ULONG attempts = 16; + + if (ValueName) + { + if (!PhStringRefToUnicodeString(ValueName, &valueName)) + return STATUS_NAME_TOO_LONG; + } + else + { + RtlInitUnicodeString(&valueName, NULL); + } + + bufferSize = 0x100; + buffer = PhAllocate(bufferSize); + + do + { + status = NtQueryValueKey( + KeyHandle, + &valueName, + KeyValueInformationClass, + buffer, + bufferSize, + &bufferSize + ); + + if (NT_SUCCESS(status)) + break; + + if (status == STATUS_BUFFER_OVERFLOW) + { + PhFree(buffer); + buffer = PhAllocate(bufferSize); + } + else + { + PhFree(buffer); + return status; + } + } while (--attempts); + + *Buffer = buffer; + + return status; +} + +/** + * Creates or opens a file. + * + * \param FileHandle A variable that receives the file handle. + * \param FileName The Win32 file name. + * \param DesiredAccess The desired access to the file. + * \param FileAttributes File attributes applied if the file is created or overwritten. + * \param ShareAccess The file access granted to other threads. + * \li \c FILE_SHARE_READ Allows other threads to read from the file. + * \li \c FILE_SHARE_WRITE Allows other threads to write to the file. + * \li \c FILE_SHARE_DELETE Allows other threads to delete the file. + * \param CreateDisposition The action to perform if the file does or does not exist. + * \li \c FILE_SUPERSEDE If the file exists, replace it. Otherwise, create the file. + * \li \c FILE_CREATE If the file exists, fail. Otherwise, create the file. + * \li \c FILE_OPEN If the file exists, open it. Otherwise, fail. + * \li \c FILE_OPEN_IF If the file exists, open it. Otherwise, create the file. + * \li \c FILE_OVERWRITE If the file exists, open and overwrite it. Otherwise, fail. + * \li \c FILE_OVERWRITE_IF If the file exists, open and overwrite it. Otherwise, create the file. + * \param CreateOptions The options to apply when the file is opened or created. + */ +NTSTATUS PhCreateFileWin32( + _Out_ PHANDLE FileHandle, + _In_ PWSTR FileName, + _In_ ACCESS_MASK DesiredAccess, + _In_opt_ ULONG FileAttributes, + _In_ ULONG ShareAccess, + _In_ ULONG CreateDisposition, + _In_ ULONG CreateOptions + ) +{ + return PhCreateFileWin32Ex( + FileHandle, + FileName, + DesiredAccess, + FileAttributes, + ShareAccess, + CreateDisposition, + CreateOptions, + NULL + ); +} + +/** + * Creates or opens a file. + * + * \param FileHandle A variable that receives the file handle. + * \param FileName The Win32 file name. + * \param DesiredAccess The desired access to the file. + * \param FileAttributes File attributes applied if the file is created or overwritten. + * \param ShareAccess The file access granted to other threads. + * \li \c FILE_SHARE_READ Allows other threads to read from the file. + * \li \c FILE_SHARE_WRITE Allows other threads to write to the file. + * \li \c FILE_SHARE_DELETE Allows other threads to delete the file. + * \param CreateDisposition The action to perform if the file does or does not exist. + * \li \c FILE_SUPERSEDE If the file exists, replace it. Otherwise, create the file. + * \li \c FILE_CREATE If the file exists, fail. Otherwise, create the file. + * \li \c FILE_OPEN If the file exists, open it. Otherwise, fail. + * \li \c FILE_OPEN_IF If the file exists, open it. Otherwise, create the file. + * \li \c FILE_OVERWRITE If the file exists, open and overwrite it. Otherwise, fail. + * \li \c FILE_OVERWRITE_IF If the file exists, open and overwrite it. Otherwise, create the file. + * \param CreateOptions The options to apply when the file is opened or created. + * \param CreateStatus A variable that receives creation information. + * \li \c FILE_SUPERSEDED The file was replaced because \c FILE_SUPERSEDE was specified in + * \a CreateDisposition. + * \li \c FILE_OPENED The file was opened because \c FILE_OPEN or \c FILE_OPEN_IF was specified in + * \a CreateDisposition. + * \li \c FILE_CREATED The file was created because \c FILE_CREATE or \c FILE_OPEN_IF was specified + * in \a CreateDisposition. + * \li \c FILE_OVERWRITTEN The file was overwritten because \c FILE_OVERWRITE or + * \c FILE_OVERWRITE_IF was specified in \a CreateDisposition. + * \li \c FILE_EXISTS The file was not opened because it already existed and \c FILE_CREATE was + * specified in \a CreateDisposition. + * \li \c FILE_DOES_NOT_EXIST The file was not opened because it did not exist and \c FILE_OPEN or + * \c FILE_OVERWRITE was specified in \a CreateDisposition. + */ +NTSTATUS PhCreateFileWin32Ex( + _Out_ PHANDLE FileHandle, + _In_ PWSTR FileName, + _In_ ACCESS_MASK DesiredAccess, + _In_opt_ ULONG FileAttributes, + _In_ ULONG ShareAccess, + _In_ ULONG CreateDisposition, + _In_ ULONG CreateOptions, + _Out_opt_ PULONG CreateStatus + ) +{ + NTSTATUS status; + HANDLE fileHandle; + UNICODE_STRING fileName; + OBJECT_ATTRIBUTES oa; + IO_STATUS_BLOCK isb; + + if (!FileAttributes) + FileAttributes = FILE_ATTRIBUTE_NORMAL; + + if (!NT_SUCCESS(status = RtlDosPathNameToNtPathName_U_WithStatus( + FileName, + &fileName, + NULL, + NULL + ))) + return status; + + InitializeObjectAttributes( + &oa, + &fileName, + OBJ_CASE_INSENSITIVE, + NULL, + NULL + ); + + status = NtCreateFile( + &fileHandle, + DesiredAccess, + &oa, + &isb, + NULL, + FileAttributes, + ShareAccess, + CreateDisposition, + CreateOptions, + NULL, + 0 + ); + + RtlFreeUnicodeString(&fileName); + + if (NT_SUCCESS(status)) + { + *FileHandle = fileHandle; + } + + if (CreateStatus) + *CreateStatus = (ULONG)isb.Information; + + return status; +} + +/** + * Queries file attributes. + * + * \param FileName The Win32 file name. + * \param FileInformation A variable that receives the file information. + */ +NTSTATUS PhQueryFullAttributesFileWin32( + _In_ PWSTR FileName, + _Out_ PFILE_NETWORK_OPEN_INFORMATION FileInformation + ) +{ + NTSTATUS status; + UNICODE_STRING fileName; + OBJECT_ATTRIBUTES oa; + + if (!NT_SUCCESS(status = RtlDosPathNameToNtPathName_U_WithStatus( + FileName, + &fileName, + NULL, + NULL + ))) + return status; + + InitializeObjectAttributes( + &oa, + &fileName, + OBJ_CASE_INSENSITIVE, + NULL, + NULL + ); + + status = NtQueryFullAttributesFile(&oa, FileInformation); + RtlFreeUnicodeString(&fileName); + + return status; +} + +/** + * Deletes a file. + * + * \param FileName The Win32 file name. + */ +NTSTATUS PhDeleteFileWin32( + _In_ PWSTR FileName + ) +{ + NTSTATUS status; + HANDLE fileHandle; + + status = PhCreateFileWin32( + &fileHandle, + FileName, + DELETE, + 0, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + FILE_OPEN, + FILE_DELETE_ON_CLOSE + ); + + if (!NT_SUCCESS(status)) + return status; + + NtClose(fileHandle); + + return status; +} + +NTSTATUS PhListenNamedPipe( + _In_ HANDLE FileHandle, + _In_opt_ HANDLE Event, + _In_opt_ PIO_APC_ROUTINE ApcRoutine, + _In_opt_ PVOID ApcContext, + _Out_ PIO_STATUS_BLOCK IoStatusBlock + ) +{ + return NtFsControlFile( + FileHandle, + Event, + ApcRoutine, + ApcContext, + IoStatusBlock, + FSCTL_PIPE_LISTEN, + NULL, + 0, + NULL, + 0 + ); +} + +NTSTATUS PhDisconnectNamedPipe( + _In_ HANDLE FileHandle + ) +{ + NTSTATUS status; + IO_STATUS_BLOCK isb; + + status = NtFsControlFile( + FileHandle, + NULL, + NULL, + NULL, + &isb, + FSCTL_PIPE_DISCONNECT, + NULL, + 0, + NULL, + 0 + ); + + if (status == STATUS_PENDING) + { + status = NtWaitForSingleObject(FileHandle, FALSE, NULL); + + if (NT_SUCCESS(status)) + status = isb.Status; + } + + return status; +} + +NTSTATUS PhPeekNamedPipe( + _In_ HANDLE FileHandle, + _Out_writes_bytes_opt_(Length) PVOID Buffer, + _In_ ULONG Length, + _Out_opt_ PULONG NumberOfBytesRead, + _Out_opt_ PULONG NumberOfBytesAvailable, + _Out_opt_ PULONG NumberOfBytesLeftInMessage + ) +{ + NTSTATUS status; + IO_STATUS_BLOCK isb; + PFILE_PIPE_PEEK_BUFFER peekBuffer; + ULONG peekBufferLength; + + peekBufferLength = FIELD_OFFSET(FILE_PIPE_PEEK_BUFFER, Data) + Length; + peekBuffer = PhAllocate(peekBufferLength); + + status = NtFsControlFile( + FileHandle, + NULL, + NULL, + NULL, + &isb, + FSCTL_PIPE_PEEK, + NULL, + 0, + peekBuffer, + peekBufferLength + ); + + if (status == STATUS_PENDING) + { + status = NtWaitForSingleObject(FileHandle, FALSE, NULL); + + if (NT_SUCCESS(status)) + status = isb.Status; + } + + // STATUS_BUFFER_OVERFLOW means that there is data remaining; this is normal. + if (status == STATUS_BUFFER_OVERFLOW) + status = STATUS_SUCCESS; + + if (NT_SUCCESS(status)) + { + ULONG numberOfBytesRead; + + if (Buffer || NumberOfBytesRead || NumberOfBytesLeftInMessage) + numberOfBytesRead = (ULONG)(isb.Information - FIELD_OFFSET(FILE_PIPE_PEEK_BUFFER, Data)); + + if (Buffer) + memcpy(Buffer, peekBuffer->Data, numberOfBytesRead); + + if (NumberOfBytesRead) + *NumberOfBytesRead = numberOfBytesRead; + + if (NumberOfBytesAvailable) + *NumberOfBytesAvailable = peekBuffer->ReadDataAvailable; + + if (NumberOfBytesLeftInMessage) + *NumberOfBytesLeftInMessage = peekBuffer->MessageLength - numberOfBytesRead; + } + + PhFree(peekBuffer); + + return status; +} + +NTSTATUS PhTransceiveNamedPipe( + _In_ HANDLE FileHandle, + _In_opt_ HANDLE Event, + _In_opt_ PIO_APC_ROUTINE ApcRoutine, + _In_opt_ PVOID ApcContext, + _Out_ PIO_STATUS_BLOCK IoStatusBlock, + _In_reads_bytes_(InputBufferLength) PVOID InputBuffer, + _In_ ULONG InputBufferLength, + _Out_writes_bytes_(OutputBufferLength) PVOID OutputBuffer, + _In_ ULONG OutputBufferLength + ) +{ + return NtFsControlFile( + FileHandle, + Event, + ApcRoutine, + ApcContext, + IoStatusBlock, + FSCTL_PIPE_TRANSCEIVE, + InputBuffer, + InputBufferLength, + OutputBuffer, + OutputBufferLength + ); +} + +NTSTATUS PhWaitForNamedPipe( + _In_opt_ PUNICODE_STRING FileSystemName, + _In_ PUNICODE_STRING Name, + _In_opt_ PLARGE_INTEGER Timeout, + _In_ BOOLEAN UseDefaultTimeout + ) +{ + NTSTATUS status; + IO_STATUS_BLOCK isb; + UNICODE_STRING localNpfsName; + HANDLE fileSystemHandle; + OBJECT_ATTRIBUTES oa; + PFILE_PIPE_WAIT_FOR_BUFFER waitForBuffer; + ULONG waitForBufferLength; + + if (!FileSystemName) + { + RtlInitUnicodeString(&localNpfsName, L"\\Device\\NamedPipe"); + FileSystemName = &localNpfsName; + } + + InitializeObjectAttributes( + &oa, + FileSystemName, + OBJ_CASE_INSENSITIVE, + NULL, + NULL + ); + + status = NtOpenFile( + &fileSystemHandle, + FILE_READ_ATTRIBUTES | SYNCHRONIZE, + &oa, + &isb, + FILE_SHARE_READ | FILE_SHARE_WRITE, + FILE_SYNCHRONOUS_IO_NONALERT + ); + + if (!NT_SUCCESS(status)) + return status; + + waitForBufferLength = FIELD_OFFSET(FILE_PIPE_WAIT_FOR_BUFFER, Name) + Name->Length; + waitForBuffer = PhAllocate(waitForBufferLength); + + if (UseDefaultTimeout) + { + waitForBuffer->TimeoutSpecified = FALSE; + } + else + { + if (Timeout) + { + waitForBuffer->Timeout = *Timeout; + } + else + { + waitForBuffer->Timeout.LowPart = 0; + waitForBuffer->Timeout.HighPart = MINLONG; // a very long time + } + + waitForBuffer->TimeoutSpecified = TRUE; + } + + waitForBuffer->NameLength = (ULONG)Name->Length; + memcpy(waitForBuffer->Name, Name->Buffer, Name->Length); + + status = NtFsControlFile( + fileSystemHandle, + NULL, + NULL, + NULL, + &isb, + FSCTL_PIPE_WAIT, + waitForBuffer, + waitForBufferLength, + NULL, + 0 + ); + + PhFree(waitForBuffer); + NtClose(fileSystemHandle); + + return status; +} + +NTSTATUS PhImpersonateClientOfNamedPipe( + _In_ HANDLE FileHandle + ) +{ + NTSTATUS status; + IO_STATUS_BLOCK isb; + + status = NtFsControlFile( + FileHandle, + NULL, + NULL, + NULL, + &isb, + FSCTL_PIPE_IMPERSONATE, + NULL, + 0, + NULL, + 0 + ); + + return status; +} diff --git a/phlib/phlib.vcxproj b/phlib/phlib.vcxproj index 38d58d7a1bfe..aba1e17fe699 100644 --- a/phlib/phlib.vcxproj +++ b/phlib/phlib.vcxproj @@ -1,249 +1,249 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {477D0215-F252-41A1-874B-F27E3EA1ED17} - phlib - Win32Proj - 10.0.15063.0 - - - - StaticLibrary - Unicode - true - v141 - - - StaticLibrary - Unicode - v141 - - - StaticLibrary - Unicode - true - v141 - - - StaticLibrary - Unicode - v141 - - - - - - - - - - - - - - - - - - - $(ProjectDir)bin\$(Configuration)$(PlatformArchitecture)\ - $(ProjectDir)obj\$(Configuration)$(PlatformArchitecture)\ - $(ProjectDir)bin\$(Configuration)$(PlatformArchitecture)\ - $(ProjectDir)obj\$(Configuration)$(PlatformArchitecture)\ - $(ProjectDir)bin\$(Configuration)$(PlatformArchitecture)\ - $(ProjectDir)obj\$(Configuration)$(PlatformArchitecture)\ - $(ProjectDir)bin\$(Configuration)$(PlatformArchitecture)\ - $(ProjectDir)obj\$(Configuration)$(PlatformArchitecture)\ - - - - Disabled - ..\phnt\include;include;%(AdditionalIncludeDirectories) - DEBUG;_PHLIB_;%(PreprocessorDefinitions) - true - EnableFastChecks - MultiThreadedDebug - Level3 - ProgramDatabase - StdCall - true - true - - - - - Disabled - ..\phnt\include;include;%(AdditionalIncludeDirectories) - DEBUG;_PHLIB_;%(PreprocessorDefinitions) - true - EnableFastChecks - MultiThreadedDebug - Level3 - ProgramDatabase - StdCall - true - true - - - - - MaxSpeed - true - ..\phnt\include;include;%(AdditionalIncludeDirectories) - WIN32;NDEBUG;_WINDOWS;_PHLIB_;%(PreprocessorDefinitions) - true - MultiThreaded - false - true - Level3 - ProgramDatabase - StdCall - true - true - StreamingSIMDExtensions - - - - - MaxSpeed - true - ..\phnt\include;include;%(AdditionalIncludeDirectories) - WIN64;NDEBUG;_WINDOWS;_PHLIB_;%(PreprocessorDefinitions) - true - MultiThreaded - false - true - Level3 - ProgramDatabase - StdCall - true - true - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {477D0215-F252-41A1-874B-F27E3EA1ED17} + phlib + Win32Proj + 10.0.15063.0 + + + + StaticLibrary + Unicode + true + v141 + + + StaticLibrary + Unicode + v141 + + + StaticLibrary + Unicode + true + v141 + + + StaticLibrary + Unicode + v141 + + + + + + + + + + + + + + + + + + + $(ProjectDir)bin\$(Configuration)$(PlatformArchitecture)\ + $(ProjectDir)obj\$(Configuration)$(PlatformArchitecture)\ + $(ProjectDir)bin\$(Configuration)$(PlatformArchitecture)\ + $(ProjectDir)obj\$(Configuration)$(PlatformArchitecture)\ + $(ProjectDir)bin\$(Configuration)$(PlatformArchitecture)\ + $(ProjectDir)obj\$(Configuration)$(PlatformArchitecture)\ + $(ProjectDir)bin\$(Configuration)$(PlatformArchitecture)\ + $(ProjectDir)obj\$(Configuration)$(PlatformArchitecture)\ + + + + Disabled + ..\phnt\include;include;%(AdditionalIncludeDirectories) + DEBUG;_PHLIB_;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + Level3 + ProgramDatabase + StdCall + true + true + + + + + Disabled + ..\phnt\include;include;%(AdditionalIncludeDirectories) + DEBUG;_PHLIB_;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + Level3 + ProgramDatabase + StdCall + true + true + + + + + MaxSpeed + true + ..\phnt\include;include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;_PHLIB_;%(PreprocessorDefinitions) + true + MultiThreaded + false + true + Level3 + ProgramDatabase + StdCall + true + true + StreamingSIMDExtensions + + + + + MaxSpeed + true + ..\phnt\include;include;%(AdditionalIncludeDirectories) + WIN64;NDEBUG;_WINDOWS;_PHLIB_;%(PreprocessorDefinitions) + true + MultiThreaded + false + true + Level3 + ProgramDatabase + StdCall + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/phlib/provider.c b/phlib/provider.c index 2e5366a806aa..99d97a85a450 100644 --- a/phlib/provider.c +++ b/phlib/provider.c @@ -1,470 +1,470 @@ -/* - * Process Hacker - - * provider system - * - * Copyright (C) 2009-2016 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -/* - * Provider objects allow a function to be executed periodically. This is managed by a - * synchronization timer object which is signaled periodically. The use of a timer object as opposed - * to a simple sleep call means that the length of time a provider function takes to execute has no - * effect on the interval between runs. - * - * In contrast to callback objects, the context passed to provider functions must be - * reference-counted objects. This means that it is not guaranteed that the function will not be in - * execution after the unregister operation is complete. However, the since the context object is - * reference-counted, there are no safety issues. - * - * Providers can be boosted, which causes them to be run immediately ignoring the interval. This is - * separate to the periodic runs, and does not cause the next periodic run to be missed. Providers, - * even when boosted, always run on the same provider thread. The other option would be to have the - * boosting thread run the provider function directly, which would involve unnecessary blocking and - * synchronization. - */ - -#include -#include - -#ifdef DEBUG -PPH_LIST PhDbgProviderList; -PH_QUEUED_LOCK PhDbgProviderListLock = PH_QUEUED_LOCK_INIT; -#endif - -/** - * Initializes a provider thread. - * - * \param ProviderThread A pointer to a provider thread object. - * \param Interval The interval between each run, in milliseconds. - */ -VOID PhInitializeProviderThread( - _Out_ PPH_PROVIDER_THREAD ProviderThread, - _In_ ULONG Interval - ) -{ - ProviderThread->ThreadHandle = NULL; - ProviderThread->TimerHandle = NULL; - ProviderThread->Interval = Interval; - ProviderThread->State = ProviderThreadStopped; - - PhInitializeQueuedLock(&ProviderThread->Lock); - InitializeListHead(&ProviderThread->ListHead); - ProviderThread->BoostCount = 0; - -#ifdef DEBUG - PhAcquireQueuedLockExclusive(&PhDbgProviderListLock); - if (!PhDbgProviderList) - PhDbgProviderList = PhCreateList(4); - PhAddItemList(PhDbgProviderList, ProviderThread); - PhReleaseQueuedLockExclusive(&PhDbgProviderListLock); -#endif -} - -/** - * Frees resources used by a provider thread. - * - * \param ProviderThread A pointer to a provider thread object. - */ -VOID PhDeleteProviderThread( - _Inout_ PPH_PROVIDER_THREAD ProviderThread - ) -{ -#ifdef DEBUG - ULONG index; -#endif - // Nothing - -#ifdef DEBUG - PhAcquireQueuedLockExclusive(&PhDbgProviderListLock); - if ((index = PhFindItemList(PhDbgProviderList, ProviderThread)) != -1) - PhRemoveItemList(PhDbgProviderList, index); - PhReleaseQueuedLockExclusive(&PhDbgProviderListLock); -#endif -} - -NTSTATUS NTAPI PhpProviderThreadStart( - _In_ PVOID Parameter - ) -{ - PH_AUTO_POOL autoPool; - PPH_PROVIDER_THREAD providerThread = (PPH_PROVIDER_THREAD)Parameter; - NTSTATUS status = STATUS_SUCCESS; - PLIST_ENTRY listEntry; - PPH_PROVIDER_REGISTRATION registration; - PPH_PROVIDER_FUNCTION providerFunction; - PVOID object; - LIST_ENTRY tempListHead; - - PhInitializeAutoPool(&autoPool); - - while (providerThread->State != ProviderThreadStopping) - { - // Keep removing and executing providers from the list until there are no more. Each removed - // provider will be placed on the temporary list. After this is done, all providers on the - // temporary list will be re-added to the list again. - // - // The key to this working safely with the other functions (boost, register, unregister) is - // that at all times when the mutex is not acquired every single provider must be in a list - // (main list or the temp list). - - InitializeListHead(&tempListHead); - - PhAcquireQueuedLockExclusive(&providerThread->Lock); - - // Main loop. - - // We check the status variable for STATUS_ALERTED, which means that someone is requesting - // that a provider be boosted. Note that if they alert this thread while we are not waiting - // on the timer, when we do perform the wait it will return immediately with STATUS_ALERTED. - - while (TRUE) - { - if (status == STATUS_ALERTED) - { - // Check if we have any more providers to boost. Note that this always works because - // boosted providers are always in front of normal providers. Therefore we will - // never mistakenly boost normal providers. - - if (providerThread->BoostCount == 0) - break; - } - - listEntry = RemoveHeadList(&providerThread->ListHead); - - if (listEntry == &providerThread->ListHead) - break; - - registration = CONTAINING_RECORD(listEntry, PH_PROVIDER_REGISTRATION, ListEntry); - - // Add the provider to the temp list. - InsertTailList(&tempListHead, listEntry); - - if (status != STATUS_ALERTED) - { - if (!registration->Enabled || registration->Unregistering) - continue; - } - else - { - // If we're boosting providers, we don't care if they are enabled or not. However, - // we have to make sure any providers which are being unregistered get a chance to - // fix the boost count. - - if (registration->Unregistering) - { - PhReleaseQueuedLockExclusive(&providerThread->Lock); - PhAcquireQueuedLockExclusive(&providerThread->Lock); - - continue; - } - } - - if (status == STATUS_ALERTED) - { - assert(registration->Boosting); - registration->Boosting = FALSE; - providerThread->BoostCount--; - } - - providerFunction = registration->Function; - object = registration->Object; - - if (object) - PhReferenceObject(object); - - registration->RunId++; - - PhReleaseQueuedLockExclusive(&providerThread->Lock); - providerFunction(object); - PhDrainAutoPool(&autoPool); - PhAcquireQueuedLockExclusive(&providerThread->Lock); - - if (object) - PhDereferenceObject(object); - } - - // Re-add the items in the temp list to the main list. - - while ((listEntry = RemoveHeadList(&tempListHead)) != &tempListHead) - { - registration = CONTAINING_RECORD(listEntry, PH_PROVIDER_REGISTRATION, ListEntry); - - // We must insert boosted providers at the front of the list in order to maintain the - // condition that boosted providers are always in front of normal providers. This occurs - // when the timer is signaled just before a boosting provider alerts our thread. - if (!registration->Boosting) - InsertTailList(&providerThread->ListHead, listEntry); - else - InsertHeadList(&providerThread->ListHead, listEntry); - } - - PhReleaseQueuedLockExclusive(&providerThread->Lock); - - // Perform an alertable wait so we can be woken up by someone telling us to boost providers, - // or to terminate. - status = NtWaitForSingleObject( - providerThread->TimerHandle, - TRUE, - NULL - ); - } - - PhDeleteAutoPool(&autoPool); - - return STATUS_SUCCESS; -} - -/** - * Starts a provider thread. - * - * \param ProviderThread A pointer to a provider thread object. - */ -VOID PhStartProviderThread( - _Inout_ PPH_PROVIDER_THREAD ProviderThread - ) -{ - if (ProviderThread->State != ProviderThreadStopped) - return; - - // Create and set the timer. - NtCreateTimer(&ProviderThread->TimerHandle, TIMER_ALL_ACCESS, NULL, SynchronizationTimer); - PhSetIntervalProviderThread(ProviderThread, ProviderThread->Interval); - - // Create and start the thread. - ProviderThread->ThreadHandle = PhCreateThread( - 0, - PhpProviderThreadStart, - ProviderThread - ); - - ProviderThread->State = ProviderThreadRunning; -} - -/** - * Stops a provider thread. - * - * \param ProviderThread A pointer to a provider thread object. - */ -VOID PhStopProviderThread( - _Inout_ PPH_PROVIDER_THREAD ProviderThread - ) -{ - if (ProviderThread->State != ProviderThreadRunning) - return; - - // Signal to the thread that we are shutting down, and wait for it to exit. - ProviderThread->State = ProviderThreadStopping; - NtAlertThread(ProviderThread->ThreadHandle); // wake it up - NtWaitForSingleObject(ProviderThread->ThreadHandle, FALSE, NULL); - - // Free resources. - NtClose(ProviderThread->ThreadHandle); - NtClose(ProviderThread->TimerHandle); - ProviderThread->ThreadHandle = NULL; - ProviderThread->TimerHandle = NULL; - - ProviderThread->State = ProviderThreadStopped; -} - -/** - * Sets the run interval for a provider thread. - * - * \param ProviderThread A pointer to a provider thread object. - * \param Interval The interval between each run, in milliseconds. - */ -VOID PhSetIntervalProviderThread( - _Inout_ PPH_PROVIDER_THREAD ProviderThread, - _In_ ULONG Interval - ) -{ - ProviderThread->Interval = Interval; - - if (ProviderThread->TimerHandle) - { - LARGE_INTEGER interval; - - interval.QuadPart = -(LONGLONG)Interval * PH_TIMEOUT_MS; - NtSetTimer(ProviderThread->TimerHandle, &interval, NULL, NULL, FALSE, Interval, NULL); - } -} - -/** - * Registers a provider with a provider thread. - * - * \param ProviderThread A pointer to a provider thread object. - * \param Function The provider function. - * \param Object A pointer to an object to pass to the provider function. The object must be managed - * by the reference-counting system. - * \param Registration A variable which receives registration information for the provider. - * - * \remarks The provider is initially disabled. Call PhSetEnabledProvider() to enable it. - */ -VOID PhRegisterProvider( - _Inout_ PPH_PROVIDER_THREAD ProviderThread, - _In_ PPH_PROVIDER_FUNCTION Function, - _In_opt_ PVOID Object, - _Out_ PPH_PROVIDER_REGISTRATION Registration - ) -{ - Registration->ProviderThread = ProviderThread; - Registration->Function = Function; - Registration->Object = Object; - Registration->RunId = 0; - Registration->Enabled = FALSE; - Registration->Unregistering = FALSE; - Registration->Boosting = FALSE; - - if (Object) - PhReferenceObject(Object); - - PhAcquireQueuedLockExclusive(&ProviderThread->Lock); - InsertTailList(&ProviderThread->ListHead, &Registration->ListEntry); - PhReleaseQueuedLockExclusive(&ProviderThread->Lock); -} - -/** - * Unregisters a provider. - * - * \param Registration A pointer to the registration object for a provider. - * - * \remarks The provider function may still be in execution once this function returns. - */ -VOID PhUnregisterProvider( - _Inout_ PPH_PROVIDER_REGISTRATION Registration - ) -{ - PPH_PROVIDER_THREAD providerThread; - - providerThread = Registration->ProviderThread; - - Registration->Unregistering = TRUE; - - // There are two possibilities for removal: - // 1. The provider is removed while the thread is not in the main loop. This is the normal case. - // 2. The provider is removed while the thread is in the main loop. In that case the provider - // will be removed from the temp list and so it won't be re-added to the main list. - - PhAcquireQueuedLockExclusive(&providerThread->Lock); - - RemoveEntryList(&Registration->ListEntry); - - // Fix the boost count. - if (Registration->Boosting) - providerThread->BoostCount--; - - // The user-supplied object must be dereferenced - // while the mutex is held. - if (Registration->Object) - PhDereferenceObject(Registration->Object); - - PhReleaseQueuedLockExclusive(&providerThread->Lock); -} - -/** - * Causes a provider to be queued for immediate execution. - * - * \param Registration A pointer to the registration object for a provider. - * \param FutureRunId A variable which receives the run ID of the future run. - * - * \return TRUE if the operation was successful; FALSE if the provider is being unregistered, the - * provider is already being boosted, or the provider thread is not running. - * - * \remarks Boosted providers will be run immediately, ignoring the run interval. Boosting will not - * however affect the normal runs. - */ -BOOLEAN PhBoostProvider( - _Inout_ PPH_PROVIDER_REGISTRATION Registration, - _Out_opt_ PULONG FutureRunId - ) -{ - PPH_PROVIDER_THREAD providerThread; - ULONG futureRunId; - - if (Registration->Unregistering) - return FALSE; - - providerThread = Registration->ProviderThread; - - // Simply move to the provider to the front of the list. This works even if the provider is - // currently in the temp list. - - PhAcquireQueuedLockExclusive(&providerThread->Lock); - - // Abort if the provider is already being boosted or the provider thread is stopping/stopped. - if (Registration->Boosting || providerThread->State != ProviderThreadRunning) - { - PhReleaseQueuedLockExclusive(&providerThread->Lock); - return FALSE; - } - - RemoveEntryList(&Registration->ListEntry); - InsertHeadList(&providerThread->ListHead, &Registration->ListEntry); - - Registration->Boosting = TRUE; - providerThread->BoostCount++; - - futureRunId = Registration->RunId + 1; - - PhReleaseQueuedLockExclusive(&providerThread->Lock); - - // Wake up the thread. - NtAlertThread(providerThread->ThreadHandle); - - if (FutureRunId) - *FutureRunId = futureRunId; - - return TRUE; -} - -/** - * Gets the current run ID of a provider. - * - * \param Registration A pointer to the registration object for a provider. - */ -ULONG PhGetRunIdProvider( - _In_ PPH_PROVIDER_REGISTRATION Registration - ) -{ - return Registration->RunId; -} - -/** - * Gets whether a provider is enabled. - * - * \param Registration A pointer to the registration object for a provider. - */ -BOOLEAN PhGetEnabledProvider( - _In_ PPH_PROVIDER_REGISTRATION Registration - ) -{ - return Registration->Enabled; -} - -/** - * Sets whether a provider is enabled. - * - * \param Registration A pointer to the registration object for a provider. - * \param Enabled TRUE if the provider is enabled, otherwise FALSE. - */ -VOID PhSetEnabledProvider( - _Inout_ PPH_PROVIDER_REGISTRATION Registration, - _In_ BOOLEAN Enabled - ) -{ - Registration->Enabled = Enabled; -} +/* + * Process Hacker - + * provider system + * + * Copyright (C) 2009-2016 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +/* + * Provider objects allow a function to be executed periodically. This is managed by a + * synchronization timer object which is signaled periodically. The use of a timer object as opposed + * to a simple sleep call means that the length of time a provider function takes to execute has no + * effect on the interval between runs. + * + * In contrast to callback objects, the context passed to provider functions must be + * reference-counted objects. This means that it is not guaranteed that the function will not be in + * execution after the unregister operation is complete. However, the since the context object is + * reference-counted, there are no safety issues. + * + * Providers can be boosted, which causes them to be run immediately ignoring the interval. This is + * separate to the periodic runs, and does not cause the next periodic run to be missed. Providers, + * even when boosted, always run on the same provider thread. The other option would be to have the + * boosting thread run the provider function directly, which would involve unnecessary blocking and + * synchronization. + */ + +#include +#include + +#ifdef DEBUG +PPH_LIST PhDbgProviderList; +PH_QUEUED_LOCK PhDbgProviderListLock = PH_QUEUED_LOCK_INIT; +#endif + +/** + * Initializes a provider thread. + * + * \param ProviderThread A pointer to a provider thread object. + * \param Interval The interval between each run, in milliseconds. + */ +VOID PhInitializeProviderThread( + _Out_ PPH_PROVIDER_THREAD ProviderThread, + _In_ ULONG Interval + ) +{ + ProviderThread->ThreadHandle = NULL; + ProviderThread->TimerHandle = NULL; + ProviderThread->Interval = Interval; + ProviderThread->State = ProviderThreadStopped; + + PhInitializeQueuedLock(&ProviderThread->Lock); + InitializeListHead(&ProviderThread->ListHead); + ProviderThread->BoostCount = 0; + +#ifdef DEBUG + PhAcquireQueuedLockExclusive(&PhDbgProviderListLock); + if (!PhDbgProviderList) + PhDbgProviderList = PhCreateList(4); + PhAddItemList(PhDbgProviderList, ProviderThread); + PhReleaseQueuedLockExclusive(&PhDbgProviderListLock); +#endif +} + +/** + * Frees resources used by a provider thread. + * + * \param ProviderThread A pointer to a provider thread object. + */ +VOID PhDeleteProviderThread( + _Inout_ PPH_PROVIDER_THREAD ProviderThread + ) +{ +#ifdef DEBUG + ULONG index; +#endif + // Nothing + +#ifdef DEBUG + PhAcquireQueuedLockExclusive(&PhDbgProviderListLock); + if ((index = PhFindItemList(PhDbgProviderList, ProviderThread)) != -1) + PhRemoveItemList(PhDbgProviderList, index); + PhReleaseQueuedLockExclusive(&PhDbgProviderListLock); +#endif +} + +NTSTATUS NTAPI PhpProviderThreadStart( + _In_ PVOID Parameter + ) +{ + PH_AUTO_POOL autoPool; + PPH_PROVIDER_THREAD providerThread = (PPH_PROVIDER_THREAD)Parameter; + NTSTATUS status = STATUS_SUCCESS; + PLIST_ENTRY listEntry; + PPH_PROVIDER_REGISTRATION registration; + PPH_PROVIDER_FUNCTION providerFunction; + PVOID object; + LIST_ENTRY tempListHead; + + PhInitializeAutoPool(&autoPool); + + while (providerThread->State != ProviderThreadStopping) + { + // Keep removing and executing providers from the list until there are no more. Each removed + // provider will be placed on the temporary list. After this is done, all providers on the + // temporary list will be re-added to the list again. + // + // The key to this working safely with the other functions (boost, register, unregister) is + // that at all times when the mutex is not acquired every single provider must be in a list + // (main list or the temp list). + + InitializeListHead(&tempListHead); + + PhAcquireQueuedLockExclusive(&providerThread->Lock); + + // Main loop. + + // We check the status variable for STATUS_ALERTED, which means that someone is requesting + // that a provider be boosted. Note that if they alert this thread while we are not waiting + // on the timer, when we do perform the wait it will return immediately with STATUS_ALERTED. + + while (TRUE) + { + if (status == STATUS_ALERTED) + { + // Check if we have any more providers to boost. Note that this always works because + // boosted providers are always in front of normal providers. Therefore we will + // never mistakenly boost normal providers. + + if (providerThread->BoostCount == 0) + break; + } + + listEntry = RemoveHeadList(&providerThread->ListHead); + + if (listEntry == &providerThread->ListHead) + break; + + registration = CONTAINING_RECORD(listEntry, PH_PROVIDER_REGISTRATION, ListEntry); + + // Add the provider to the temp list. + InsertTailList(&tempListHead, listEntry); + + if (status != STATUS_ALERTED) + { + if (!registration->Enabled || registration->Unregistering) + continue; + } + else + { + // If we're boosting providers, we don't care if they are enabled or not. However, + // we have to make sure any providers which are being unregistered get a chance to + // fix the boost count. + + if (registration->Unregistering) + { + PhReleaseQueuedLockExclusive(&providerThread->Lock); + PhAcquireQueuedLockExclusive(&providerThread->Lock); + + continue; + } + } + + if (status == STATUS_ALERTED) + { + assert(registration->Boosting); + registration->Boosting = FALSE; + providerThread->BoostCount--; + } + + providerFunction = registration->Function; + object = registration->Object; + + if (object) + PhReferenceObject(object); + + registration->RunId++; + + PhReleaseQueuedLockExclusive(&providerThread->Lock); + providerFunction(object); + PhDrainAutoPool(&autoPool); + PhAcquireQueuedLockExclusive(&providerThread->Lock); + + if (object) + PhDereferenceObject(object); + } + + // Re-add the items in the temp list to the main list. + + while ((listEntry = RemoveHeadList(&tempListHead)) != &tempListHead) + { + registration = CONTAINING_RECORD(listEntry, PH_PROVIDER_REGISTRATION, ListEntry); + + // We must insert boosted providers at the front of the list in order to maintain the + // condition that boosted providers are always in front of normal providers. This occurs + // when the timer is signaled just before a boosting provider alerts our thread. + if (!registration->Boosting) + InsertTailList(&providerThread->ListHead, listEntry); + else + InsertHeadList(&providerThread->ListHead, listEntry); + } + + PhReleaseQueuedLockExclusive(&providerThread->Lock); + + // Perform an alertable wait so we can be woken up by someone telling us to boost providers, + // or to terminate. + status = NtWaitForSingleObject( + providerThread->TimerHandle, + TRUE, + NULL + ); + } + + PhDeleteAutoPool(&autoPool); + + return STATUS_SUCCESS; +} + +/** + * Starts a provider thread. + * + * \param ProviderThread A pointer to a provider thread object. + */ +VOID PhStartProviderThread( + _Inout_ PPH_PROVIDER_THREAD ProviderThread + ) +{ + if (ProviderThread->State != ProviderThreadStopped) + return; + + // Create and set the timer. + NtCreateTimer(&ProviderThread->TimerHandle, TIMER_ALL_ACCESS, NULL, SynchronizationTimer); + PhSetIntervalProviderThread(ProviderThread, ProviderThread->Interval); + + // Create and start the thread. + ProviderThread->ThreadHandle = PhCreateThread( + 0, + PhpProviderThreadStart, + ProviderThread + ); + + ProviderThread->State = ProviderThreadRunning; +} + +/** + * Stops a provider thread. + * + * \param ProviderThread A pointer to a provider thread object. + */ +VOID PhStopProviderThread( + _Inout_ PPH_PROVIDER_THREAD ProviderThread + ) +{ + if (ProviderThread->State != ProviderThreadRunning) + return; + + // Signal to the thread that we are shutting down, and wait for it to exit. + ProviderThread->State = ProviderThreadStopping; + NtAlertThread(ProviderThread->ThreadHandle); // wake it up + NtWaitForSingleObject(ProviderThread->ThreadHandle, FALSE, NULL); + + // Free resources. + NtClose(ProviderThread->ThreadHandle); + NtClose(ProviderThread->TimerHandle); + ProviderThread->ThreadHandle = NULL; + ProviderThread->TimerHandle = NULL; + + ProviderThread->State = ProviderThreadStopped; +} + +/** + * Sets the run interval for a provider thread. + * + * \param ProviderThread A pointer to a provider thread object. + * \param Interval The interval between each run, in milliseconds. + */ +VOID PhSetIntervalProviderThread( + _Inout_ PPH_PROVIDER_THREAD ProviderThread, + _In_ ULONG Interval + ) +{ + ProviderThread->Interval = Interval; + + if (ProviderThread->TimerHandle) + { + LARGE_INTEGER interval; + + interval.QuadPart = -(LONGLONG)Interval * PH_TIMEOUT_MS; + NtSetTimer(ProviderThread->TimerHandle, &interval, NULL, NULL, FALSE, Interval, NULL); + } +} + +/** + * Registers a provider with a provider thread. + * + * \param ProviderThread A pointer to a provider thread object. + * \param Function The provider function. + * \param Object A pointer to an object to pass to the provider function. The object must be managed + * by the reference-counting system. + * \param Registration A variable which receives registration information for the provider. + * + * \remarks The provider is initially disabled. Call PhSetEnabledProvider() to enable it. + */ +VOID PhRegisterProvider( + _Inout_ PPH_PROVIDER_THREAD ProviderThread, + _In_ PPH_PROVIDER_FUNCTION Function, + _In_opt_ PVOID Object, + _Out_ PPH_PROVIDER_REGISTRATION Registration + ) +{ + Registration->ProviderThread = ProviderThread; + Registration->Function = Function; + Registration->Object = Object; + Registration->RunId = 0; + Registration->Enabled = FALSE; + Registration->Unregistering = FALSE; + Registration->Boosting = FALSE; + + if (Object) + PhReferenceObject(Object); + + PhAcquireQueuedLockExclusive(&ProviderThread->Lock); + InsertTailList(&ProviderThread->ListHead, &Registration->ListEntry); + PhReleaseQueuedLockExclusive(&ProviderThread->Lock); +} + +/** + * Unregisters a provider. + * + * \param Registration A pointer to the registration object for a provider. + * + * \remarks The provider function may still be in execution once this function returns. + */ +VOID PhUnregisterProvider( + _Inout_ PPH_PROVIDER_REGISTRATION Registration + ) +{ + PPH_PROVIDER_THREAD providerThread; + + providerThread = Registration->ProviderThread; + + Registration->Unregistering = TRUE; + + // There are two possibilities for removal: + // 1. The provider is removed while the thread is not in the main loop. This is the normal case. + // 2. The provider is removed while the thread is in the main loop. In that case the provider + // will be removed from the temp list and so it won't be re-added to the main list. + + PhAcquireQueuedLockExclusive(&providerThread->Lock); + + RemoveEntryList(&Registration->ListEntry); + + // Fix the boost count. + if (Registration->Boosting) + providerThread->BoostCount--; + + // The user-supplied object must be dereferenced + // while the mutex is held. + if (Registration->Object) + PhDereferenceObject(Registration->Object); + + PhReleaseQueuedLockExclusive(&providerThread->Lock); +} + +/** + * Causes a provider to be queued for immediate execution. + * + * \param Registration A pointer to the registration object for a provider. + * \param FutureRunId A variable which receives the run ID of the future run. + * + * \return TRUE if the operation was successful; FALSE if the provider is being unregistered, the + * provider is already being boosted, or the provider thread is not running. + * + * \remarks Boosted providers will be run immediately, ignoring the run interval. Boosting will not + * however affect the normal runs. + */ +BOOLEAN PhBoostProvider( + _Inout_ PPH_PROVIDER_REGISTRATION Registration, + _Out_opt_ PULONG FutureRunId + ) +{ + PPH_PROVIDER_THREAD providerThread; + ULONG futureRunId; + + if (Registration->Unregistering) + return FALSE; + + providerThread = Registration->ProviderThread; + + // Simply move to the provider to the front of the list. This works even if the provider is + // currently in the temp list. + + PhAcquireQueuedLockExclusive(&providerThread->Lock); + + // Abort if the provider is already being boosted or the provider thread is stopping/stopped. + if (Registration->Boosting || providerThread->State != ProviderThreadRunning) + { + PhReleaseQueuedLockExclusive(&providerThread->Lock); + return FALSE; + } + + RemoveEntryList(&Registration->ListEntry); + InsertHeadList(&providerThread->ListHead, &Registration->ListEntry); + + Registration->Boosting = TRUE; + providerThread->BoostCount++; + + futureRunId = Registration->RunId + 1; + + PhReleaseQueuedLockExclusive(&providerThread->Lock); + + // Wake up the thread. + NtAlertThread(providerThread->ThreadHandle); + + if (FutureRunId) + *FutureRunId = futureRunId; + + return TRUE; +} + +/** + * Gets the current run ID of a provider. + * + * \param Registration A pointer to the registration object for a provider. + */ +ULONG PhGetRunIdProvider( + _In_ PPH_PROVIDER_REGISTRATION Registration + ) +{ + return Registration->RunId; +} + +/** + * Gets whether a provider is enabled. + * + * \param Registration A pointer to the registration object for a provider. + */ +BOOLEAN PhGetEnabledProvider( + _In_ PPH_PROVIDER_REGISTRATION Registration + ) +{ + return Registration->Enabled; +} + +/** + * Sets whether a provider is enabled. + * + * \param Registration A pointer to the registration object for a provider. + * \param Enabled TRUE if the provider is enabled, otherwise FALSE. + */ +VOID PhSetEnabledProvider( + _Inout_ PPH_PROVIDER_REGISTRATION Registration, + _In_ BOOLEAN Enabled + ) +{ + Registration->Enabled = Enabled; +} diff --git a/phlib/queuedlock.c b/phlib/queuedlock.c index 957a32a4bd3a..22d9602b1ce0 100644 --- a/phlib/queuedlock.c +++ b/phlib/queuedlock.c @@ -1,1202 +1,1202 @@ -/* - * Process Hacker - - * queued lock - * - * Copyright (C) 2010-2016 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -/* - * Queued lock, a.k.a. push lock (kernel-mode) or slim reader-writer lock (user-mode). - * - * The queued lock is: - * * Around 10% faster than the fast lock. - * * Only the size of a pointer. - * * Low on resource usage (no additional kernel objects are created for blocking). - * - * The usual flags are used for contention-free acquire/release. When there is contention, - * stack-based wait blocks are chained. The first wait block contains the shared owners count which - * is decremented by shared releasers. - * - * Naturally these wait blocks would be chained in FILO order, but list optimization is done for two - * purposes: - * * Finding the last wait block (where the shared owners count is stored). This is implemented by - * the Last pointer. - * * Unblocking the wait blocks in FIFO order. This is implemented by the Previous pointer. - * - * The optimization is incremental - each optimization run will stop at the first optimized wait - * block. Any needed optimization is completed just before waking waiters. - * - * The waiters list/chain has the following restrictions: - * * At any time wait blocks may be pushed onto the list. - * * While waking waiters, the list may not be traversed nor optimized. - * * When there are multiple shared owners, shared releasers may traverse the list (to find the last - * wait block). This is not an issue because waiters wouldn't be woken until there are no more - * shared owners. - * * List optimization may be done at any time except for when someone else is waking waiters. This - * is controlled by the traversing bit. - * - * The traversing bit has the following rules: - * * The list may be optimized only after the traversing bit is set, checking that it wasn't set - * already. If it was set, it would indicate that someone else is optimizing the list or waking - * waiters. - * * Before waking waiters the traversing bit must be set. If it was set already, just clear the - * owned bit. - * * If during list optimization the owned bit is detected to be cleared, the function begins waking - * waiters. This is because the owned bit is cleared when a releaser fails to set the traversing - * bit. - * - * Blocking is implemented through a process-wide keyed event. A spin count is also used before - * blocking on the keyed event. - * - * Queued locks can act as condition variables, with wait, pulse and pulse all support. Waiters are - * released in FIFO order. - * - * Queued locks can act as wake events. These are designed for tiny one-bit locks which share a - * single event to block on. Spurious wake-ups are a part of normal operation. - */ - -#include - -#include -#include -#include - -VOID FASTCALL PhpfOptimizeQueuedLockList( - _Inout_ PPH_QUEUED_LOCK QueuedLock, - _In_ ULONG_PTR Value - ); - -VOID FASTCALL PhpfWakeQueuedLock( - _Inout_ PPH_QUEUED_LOCK QueuedLock, - _In_ ULONG_PTR Value - ); - -VOID FASTCALL PhpfWakeQueuedLockEx( - _Inout_ PPH_QUEUED_LOCK QueuedLock, - _In_ ULONG_PTR Value, - _In_ BOOLEAN IgnoreOwned, - _In_ BOOLEAN WakeAll - ); - -static HANDLE PhQueuedLockKeyedEventHandle; -static ULONG PhQueuedLockSpinCount = 2000; - -BOOLEAN PhQueuedLockInitialization( - VOID - ) -{ - if (!NT_SUCCESS(NtCreateKeyedEvent( - &PhQueuedLockKeyedEventHandle, - KEYEDEVENT_ALL_ACCESS, - NULL, - 0 - ))) - return FALSE; - - if ((ULONG)PhSystemBasicInformation.NumberOfProcessors > 1) - PhQueuedLockSpinCount = 4000; - else - PhQueuedLockSpinCount = 0; - - return TRUE; -} - -/** - * Pushes a wait block onto a queued lock's waiters list. - * - * \param QueuedLock A queued lock. - * \param Value The current value of the queued lock. - * \param Exclusive Whether the wait block is in exclusive mode. - * \param WaitBlock A variable which receives the resulting wait block structure. - * \param Optimize A variable which receives a boolean indicating whether to optimize the waiters - * list. - * \param NewValue The old value of the queued lock. This value is useful only if the function - * returns FALSE. - * \param CurrentValue The new value of the queued lock. This value is useful only if the function - * returns TRUE. - * - * \return TRUE if the wait block was pushed onto the waiters list, otherwise FALSE. - * - * \remarks - * \li The function assumes the following flags are set: - * \ref PH_QUEUED_LOCK_OWNED. - * \li Do not move the wait block location after this function is called. - * \li The \a Optimize boolean is a hint to call PhpfOptimizeQueuedLockList() if the function - * succeeds. It is recommended, but not essential that this occurs. - * \li Call PhpBlockOnQueuedWaitBlock() to wait for the wait block to be unblocked. - */ -FORCEINLINE BOOLEAN PhpPushQueuedWaitBlock( - _Inout_ PPH_QUEUED_LOCK QueuedLock, - _In_ ULONG_PTR Value, - _In_ BOOLEAN Exclusive, - _Out_ PPH_QUEUED_WAIT_BLOCK WaitBlock, - _Out_ PBOOLEAN Optimize, - _Out_ PULONG_PTR NewValue, - _Out_ PULONG_PTR CurrentValue - ) -{ - ULONG_PTR newValue; - BOOLEAN optimize; - - WaitBlock->Previous = NULL; // set later by optimization - optimize = FALSE; - - if (Exclusive) - WaitBlock->Flags = PH_QUEUED_WAITER_EXCLUSIVE | PH_QUEUED_WAITER_SPINNING; - else - WaitBlock->Flags = PH_QUEUED_WAITER_SPINNING; - - if (Value & PH_QUEUED_LOCK_WAITERS) - { - // We're not the first waiter. - - WaitBlock->Last = NULL; // set later by optimization - WaitBlock->Next = PhGetQueuedLockWaitBlock(Value); - WaitBlock->SharedOwners = 0; - - // Push our wait block onto the list. - // Set the traversing bit because we'll be optimizing the list. - newValue = ((ULONG_PTR)WaitBlock) | (Value & PH_QUEUED_LOCK_FLAGS) | - PH_QUEUED_LOCK_TRAVERSING; - - if (!(Value & PH_QUEUED_LOCK_TRAVERSING)) - optimize = TRUE; - } - else - { - // We're the first waiter. - - WaitBlock->Last = WaitBlock; // indicate that this is the last wait block - - if (Exclusive) - { - // We're the first waiter. Save the shared owners count. - WaitBlock->SharedOwners = (ULONG)PhGetQueuedLockSharedOwners(Value); - - if (WaitBlock->SharedOwners > 1) - { - newValue = ((ULONG_PTR)WaitBlock) | PH_QUEUED_LOCK_OWNED | - PH_QUEUED_LOCK_WAITERS | PH_QUEUED_LOCK_MULTIPLE_SHARED; - } - else - { - newValue = ((ULONG_PTR)WaitBlock) | PH_QUEUED_LOCK_OWNED | - PH_QUEUED_LOCK_WAITERS; - } - } - else - { - // We're waiting in shared mode, which means there can't be any shared owners (otherwise - // we would've acquired the lock already). - - WaitBlock->SharedOwners = 0; - - newValue = ((ULONG_PTR)WaitBlock) | PH_QUEUED_LOCK_OWNED | - PH_QUEUED_LOCK_WAITERS; - } - } - - *Optimize = optimize; - *CurrentValue = newValue; - - newValue = (ULONG_PTR)_InterlockedCompareExchangePointer( - (PVOID *)&QueuedLock->Value, - (PVOID)newValue, - (PVOID)Value - ); - - *NewValue = newValue; - - return newValue == Value; -} - -/** - * Finds the last wait block in the waiters list. - * - * \param Value The current value of the queued lock. - * - * \return A pointer to the last wait block. - * - * \remarks The function assumes the following flags are set: - * \ref PH_QUEUED_LOCK_WAITERS, - * \ref PH_QUEUED_LOCK_MULTIPLE_SHARED or - * \ref PH_QUEUED_LOCK_TRAVERSING. - */ -FORCEINLINE PPH_QUEUED_WAIT_BLOCK PhpFindLastQueuedWaitBlock( - _In_ ULONG_PTR Value - ) -{ - PPH_QUEUED_WAIT_BLOCK waitBlock; - PPH_QUEUED_WAIT_BLOCK lastWaitBlock; - - waitBlock = PhGetQueuedLockWaitBlock(Value); - - // Traverse the list until we find the last wait block. - // The Last pointer should be set by list optimization, allowing us to skip all, if not most of - // the wait blocks. - - while (TRUE) - { - lastWaitBlock = waitBlock->Last; - - if (lastWaitBlock) - { - // Follow the Last pointer. This can mean two things: the pointer was set by list - // optimization, or this wait block is actually the last wait block (set when it was - // pushed onto the list). - waitBlock = lastWaitBlock; - break; - } - - waitBlock = waitBlock->Next; - } - - return waitBlock; -} - -/** - * Waits for a wait block to be unblocked. - * - * \param WaitBlock A wait block. - * \param Spin TRUE to spin, FALSE to block immediately. - * \param Timeout A timeout value. - */ -_May_raise_ FORCEINLINE NTSTATUS PhpBlockOnQueuedWaitBlock( - _Inout_ PPH_QUEUED_WAIT_BLOCK WaitBlock, - _In_ BOOLEAN Spin, - _In_opt_ PLARGE_INTEGER Timeout - ) -{ - NTSTATUS status; - ULONG i; - - if (Spin) - { - PHLIB_INC_STATISTIC(QlBlockSpins); - - for (i = PhQueuedLockSpinCount; i != 0; i--) - { - if (!(*(volatile ULONG *)&WaitBlock->Flags & PH_QUEUED_WAITER_SPINNING)) - return STATUS_SUCCESS; - - YieldProcessor(); - } - } - - if (_interlockedbittestandreset((PLONG)&WaitBlock->Flags, PH_QUEUED_WAITER_SPINNING_SHIFT)) - { - PHLIB_INC_STATISTIC(QlBlockWaits); - - status = NtWaitForKeyedEvent( - PhQueuedLockKeyedEventHandle, - WaitBlock, - FALSE, - Timeout - ); - - // If an error occurred (timeout is not an error), raise an exception as it is nearly - // impossible to recover from this situation. - if (!NT_SUCCESS(status)) - PhRaiseStatus(status); - } - else - { - status = STATUS_SUCCESS; - } - - return status; -} - -/** - * Unblocks a wait block. - * - * \param WaitBlock A wait block. - * - * \remarks The wait block is in an undefined state after it is unblocked. Do not attempt to read - * any values from it. All relevant information should be saved before unblocking the wait block. - */ -_May_raise_ FORCEINLINE VOID PhpUnblockQueuedWaitBlock( - _Inout_ PPH_QUEUED_WAIT_BLOCK WaitBlock - ) -{ - NTSTATUS status; - - if (!_interlockedbittestandreset((PLONG)&WaitBlock->Flags, PH_QUEUED_WAITER_SPINNING_SHIFT)) - { - if (!NT_SUCCESS(status = NtReleaseKeyedEvent( - PhQueuedLockKeyedEventHandle, - WaitBlock, - FALSE, - NULL - ))) - PhRaiseStatus(status); - } -} - -/** - * Optimizes a queued lock waiters list. - * - * \param QueuedLock A queued lock. - * \param Value The current value of the queued lock. - * \param IgnoreOwned TRUE to ignore lock state, FALSE to conduct normal checks. - * - * \remarks The function assumes the following flags are set: - * \ref PH_QUEUED_LOCK_WAITERS, \ref PH_QUEUED_LOCK_TRAVERSING. - */ -FORCEINLINE VOID PhpOptimizeQueuedLockListEx( - _Inout_ PPH_QUEUED_LOCK QueuedLock, - _In_ ULONG_PTR Value, - _In_ BOOLEAN IgnoreOwned - ) -{ - ULONG_PTR value; - ULONG_PTR newValue; - PPH_QUEUED_WAIT_BLOCK waitBlock; - PPH_QUEUED_WAIT_BLOCK firstWaitBlock; - PPH_QUEUED_WAIT_BLOCK lastWaitBlock; - PPH_QUEUED_WAIT_BLOCK previousWaitBlock; - - value = Value; - - while (TRUE) - { - assert(value & PH_QUEUED_LOCK_TRAVERSING); - - if (!IgnoreOwned && !(value & PH_QUEUED_LOCK_OWNED)) - { - // Someone has requested that we wake waiters. - PhpfWakeQueuedLock(QueuedLock, value); - break; - } - - // Perform the optimization. - - waitBlock = PhGetQueuedLockWaitBlock(value); - firstWaitBlock = waitBlock; - - while (TRUE) - { - lastWaitBlock = waitBlock->Last; - - if (lastWaitBlock) - { - // Save a pointer to the last wait block in the first wait block and stop - // optimizing. - // - // We don't need to continue setting Previous pointers because the last optimization - // run would have set them already. - - firstWaitBlock->Last = lastWaitBlock; - break; - } - - previousWaitBlock = waitBlock; - waitBlock = waitBlock->Next; - waitBlock->Previous = previousWaitBlock; - } - - // Try to clear the traversing bit. - - newValue = value - PH_QUEUED_LOCK_TRAVERSING; - - if ((newValue = (ULONG_PTR)_InterlockedCompareExchangePointer( - (PVOID *)&QueuedLock->Value, - (PVOID)newValue, - (PVOID)value - )) == value) - break; - - // Either someone pushed a wait block onto the list or someone released ownership. In either - // case we need to go back. - - value = newValue; - } -} - -/** - * Optimizes a queued lock waiters list. - * - * \param QueuedLock A queued lock. - * \param Value The current value of the queued lock. - * - * \remarks The function assumes the following flags are set: - * \ref PH_QUEUED_LOCK_WAITERS, \ref PH_QUEUED_LOCK_TRAVERSING. - */ -VOID FASTCALL PhpfOptimizeQueuedLockList( - _Inout_ PPH_QUEUED_LOCK QueuedLock, - _In_ ULONG_PTR Value - ) -{ - PhpOptimizeQueuedLockListEx(QueuedLock, Value, FALSE); -} - -/** - * Dequeues the appropriate number of wait blocks in a queued lock. - * - * \param QueuedLock A queued lock. - * \param Value The current value of the queued lock. - * \param IgnoreOwned TRUE to ignore lock state, FALSE to conduct normal checks. - * \param WakeAll TRUE to remove all wait blocks, FALSE to decide based on the wait block type. - */ -FORCEINLINE PPH_QUEUED_WAIT_BLOCK PhpPrepareToWakeQueuedLock( - _Inout_ PPH_QUEUED_LOCK QueuedLock, - _In_ ULONG_PTR Value, - _In_ BOOLEAN IgnoreOwned, - _In_ BOOLEAN WakeAll - ) -{ - ULONG_PTR value; - ULONG_PTR newValue; - PPH_QUEUED_WAIT_BLOCK waitBlock; - PPH_QUEUED_WAIT_BLOCK firstWaitBlock; - PPH_QUEUED_WAIT_BLOCK lastWaitBlock; - PPH_QUEUED_WAIT_BLOCK previousWaitBlock; - - value = Value; - - while (TRUE) - { - // If there are multiple shared owners, no one is going to wake waiters since the lock would - // still be owned. Also if there are multiple shared owners they may be traversing the list. - // While that is safe when done concurrently with list optimization, we may be removing and - // waking waiters. - assert(!(value & PH_QUEUED_LOCK_MULTIPLE_SHARED)); - assert(IgnoreOwned || (value & PH_QUEUED_LOCK_TRAVERSING)); - - // There's no point in waking a waiter if the lock is owned. Clear the traversing bit. - while (!IgnoreOwned && (value & PH_QUEUED_LOCK_OWNED)) - { - newValue = value - PH_QUEUED_LOCK_TRAVERSING; - - if ((newValue = (ULONG_PTR)_InterlockedCompareExchangePointer( - (PVOID *)&QueuedLock->Value, - (PVOID)newValue, - (PVOID)value - )) == value) - return NULL; - - value = newValue; - } - - // Finish up any needed optimization (setting the Previous pointers) while finding the last - // wait block. - - waitBlock = PhGetQueuedLockWaitBlock(value); - firstWaitBlock = waitBlock; - - while (TRUE) - { - lastWaitBlock = waitBlock->Last; - - if (lastWaitBlock) - { - waitBlock = lastWaitBlock; - break; - } - - previousWaitBlock = waitBlock; - waitBlock = waitBlock->Next; - waitBlock->Previous = previousWaitBlock; - } - - // Unlink the relevant wait blocks and clear the traversing bit before we wake waiters. - - if ( - !WakeAll && - (waitBlock->Flags & PH_QUEUED_WAITER_EXCLUSIVE) && - (previousWaitBlock = waitBlock->Previous) - ) - { - // We have an exclusive waiter and there are multiple waiters. We'll only be waking this - // waiter. - - // Unlink the wait block from the list. Although other wait blocks may have their Last - // pointers set to this wait block, the algorithm to find the last wait block will stop - // here. Likewise the Next pointers are never followed beyond this point, so we don't - // need to clear those. - firstWaitBlock->Last = previousWaitBlock; - - // Make sure we only wake this waiter. - waitBlock->Previous = NULL; - - if (!IgnoreOwned) - { - // Clear the traversing bit. - _InterlockedExchangeAddPointer((PLONG_PTR)&QueuedLock->Value, -(LONG_PTR)PH_QUEUED_LOCK_TRAVERSING); - } - - break; - } - else - { - // We're waking an exclusive waiter and there is only one waiter, or we are waking a - // shared waiter and possibly others. - - newValue = 0; - - if ((newValue = (ULONG_PTR)_InterlockedCompareExchangePointer( - (PVOID *)&QueuedLock->Value, - (PVOID)newValue, - (PVOID)value - )) == value) - break; - - // Someone changed the lock (acquired it or pushed a wait block). - - value = newValue; - } - } - - return waitBlock; -} - -/** - * Wakes waiters in a queued lock. - * - * \param QueuedLock A queued lock. - * \param Value The current value of the queued lock. - * - * \remarks The function assumes the following flags are set: - * \ref PH_QUEUED_LOCK_WAITERS, \ref PH_QUEUED_LOCK_TRAVERSING. The function assumes the following - * flags are not set: - * \ref PH_QUEUED_LOCK_MULTIPLE_SHARED. - */ -VOID FASTCALL PhpfWakeQueuedLock( - _Inout_ PPH_QUEUED_LOCK QueuedLock, - _In_ ULONG_PTR Value - ) -{ - PPH_QUEUED_WAIT_BLOCK waitBlock; - PPH_QUEUED_WAIT_BLOCK previousWaitBlock; - - waitBlock = PhpPrepareToWakeQueuedLock(QueuedLock, Value, FALSE, FALSE); - - // Wake waiters. - - while (waitBlock) - { - previousWaitBlock = waitBlock->Previous; - PhpUnblockQueuedWaitBlock(waitBlock); - waitBlock = previousWaitBlock; - } -} - -/** - * Wakes waiters in a queued lock. - * - * \param QueuedLock A queued lock. - * \param Value The current value of the queued lock. - * \param IgnoreOwned TRUE to ignore lock state, FALSE to conduct normal checks. - * \param WakeAll TRUE to wake all waiters, FALSE to decide based on the wait block type. - * - * \remarks The function assumes the following flags are set: - * \ref PH_QUEUED_LOCK_WAITERS, \ref PH_QUEUED_LOCK_TRAVERSING. The function assumes the following - * flags are not set: - * \ref PH_QUEUED_LOCK_MULTIPLE_SHARED. - */ -VOID FASTCALL PhpfWakeQueuedLockEx( - _Inout_ PPH_QUEUED_LOCK QueuedLock, - _In_ ULONG_PTR Value, - _In_ BOOLEAN IgnoreOwned, - _In_ BOOLEAN WakeAll - ) -{ - PPH_QUEUED_WAIT_BLOCK waitBlock; - PPH_QUEUED_WAIT_BLOCK previousWaitBlock; - - waitBlock = PhpPrepareToWakeQueuedLock(QueuedLock, Value, IgnoreOwned, WakeAll); - - // Wake waiters. - - while (waitBlock) - { - previousWaitBlock = waitBlock->Previous; - PhpUnblockQueuedWaitBlock(waitBlock); - waitBlock = previousWaitBlock; - } -} - -/** - * Acquires a queued lock in exclusive mode. - * - * \param QueuedLock A queued lock. - */ -VOID FASTCALL PhfAcquireQueuedLockExclusive( - _Inout_ PPH_QUEUED_LOCK QueuedLock - ) -{ - ULONG_PTR value; - ULONG_PTR newValue; - ULONG_PTR currentValue; - BOOLEAN optimize; - PH_QUEUED_WAIT_BLOCK waitBlock; - - value = QueuedLock->Value; - - while (TRUE) - { - if (!(value & PH_QUEUED_LOCK_OWNED)) - { - if ((newValue = (ULONG_PTR)_InterlockedCompareExchangePointer( - (PVOID *)&QueuedLock->Value, - (PVOID)(value + PH_QUEUED_LOCK_OWNED), - (PVOID)value - )) == value) - break; - } - else - { - if (PhpPushQueuedWaitBlock( - QueuedLock, - value, - TRUE, - &waitBlock, - &optimize, - &newValue, - ¤tValue - )) - { - if (optimize) - PhpfOptimizeQueuedLockList(QueuedLock, currentValue); - - PHLIB_INC_STATISTIC(QlAcquireExclusiveBlocks); - PhpBlockOnQueuedWaitBlock(&waitBlock, TRUE, NULL); - } - } - - value = newValue; - } -} - -/** - * Acquires a queued lock in shared mode. - * - * \param QueuedLock A queued lock. - */ -VOID FASTCALL PhfAcquireQueuedLockShared( - _Inout_ PPH_QUEUED_LOCK QueuedLock - ) -{ - ULONG_PTR value; - ULONG_PTR newValue; - ULONG_PTR currentValue; - BOOLEAN optimize; - PH_QUEUED_WAIT_BLOCK waitBlock; - - value = QueuedLock->Value; - - while (TRUE) - { - // We can't acquire if there are waiters for two reasons: - // - // We want to prioritize exclusive acquires over shared acquires. There's currently no fast, - // safe way of finding the last wait block and incrementing the shared owners count here. - if ( - !(value & PH_QUEUED_LOCK_WAITERS) && - (!(value & PH_QUEUED_LOCK_OWNED) || (PhGetQueuedLockSharedOwners(value) > 0)) - ) - { - newValue = (value + PH_QUEUED_LOCK_SHARED_INC) | PH_QUEUED_LOCK_OWNED; - - if ((newValue = (ULONG_PTR)_InterlockedCompareExchangePointer( - (PVOID *)&QueuedLock->Value, - (PVOID)newValue, - (PVOID)value - )) == value) - break; - } - else - { - if (PhpPushQueuedWaitBlock( - QueuedLock, - value, - FALSE, - &waitBlock, - &optimize, - &newValue, - ¤tValue - )) - { - if (optimize) - PhpfOptimizeQueuedLockList(QueuedLock, currentValue); - - PHLIB_INC_STATISTIC(QlAcquireSharedBlocks); - PhpBlockOnQueuedWaitBlock(&waitBlock, TRUE, NULL); - } - } - - value = newValue; - } -} - -/** - * Releases a queued lock in exclusive mode. - * - * \param QueuedLock A queued lock. - */ -VOID FASTCALL PhfReleaseQueuedLockExclusive( - _Inout_ PPH_QUEUED_LOCK QueuedLock - ) -{ - ULONG_PTR value; - ULONG_PTR newValue; - ULONG_PTR currentValue; - - value = QueuedLock->Value; - - while (TRUE) - { - assert(value & PH_QUEUED_LOCK_OWNED); - assert((value & PH_QUEUED_LOCK_WAITERS) || (PhGetQueuedLockSharedOwners(value) == 0)); - - if ((value & (PH_QUEUED_LOCK_WAITERS | PH_QUEUED_LOCK_TRAVERSING)) != PH_QUEUED_LOCK_WAITERS) - { - // There are no waiters or someone is traversing the list. - // - // If there are no waiters, we're simply releasing ownership. If someone is traversing - // the list, clearing the owned bit is a signal for them to wake waiters. - - newValue = value - PH_QUEUED_LOCK_OWNED; - - if ((newValue = (ULONG_PTR)_InterlockedCompareExchangePointer( - (PVOID *)&QueuedLock->Value, - (PVOID)newValue, - (PVOID)value - )) == value) - break; - } - else - { - // We need to wake waiters and no one is traversing the list. - // Try to set the traversing bit and wake waiters. - - newValue = value - PH_QUEUED_LOCK_OWNED + PH_QUEUED_LOCK_TRAVERSING; - currentValue = newValue; - - if ((newValue = (ULONG_PTR)_InterlockedCompareExchangePointer( - (PVOID *)&QueuedLock->Value, - (PVOID)newValue, - (PVOID)value - )) == value) - { - PhpfWakeQueuedLock(QueuedLock, currentValue); - break; - } - } - - value = newValue; - } -} - -/** - * Wakes waiters in a queued lock for releasing it in exclusive mode. - * - * \param QueuedLock A queued lock. - * \param Value The current value of the queued lock. - * - * \remarks The function assumes the following flags are set: - * \ref PH_QUEUED_LOCK_WAITERS. The function assumes the following flags are not set: - * \ref PH_QUEUED_LOCK_MULTIPLE_SHARED, \ref PH_QUEUED_LOCK_TRAVERSING. - */ -VOID FASTCALL PhfWakeForReleaseQueuedLock( - _Inout_ PPH_QUEUED_LOCK QueuedLock, - _In_ ULONG_PTR Value - ) -{ - ULONG_PTR newValue; - - newValue = Value + PH_QUEUED_LOCK_TRAVERSING; - - if ((ULONG_PTR)_InterlockedCompareExchangePointer( - (PVOID *)&QueuedLock->Value, - (PVOID)newValue, - (PVOID)Value - ) == Value) - { - PhpfWakeQueuedLock(QueuedLock, newValue); - } -} - -/** - * Releases a queued lock in shared mode. - * - * \param QueuedLock A queued lock. - */ -VOID FASTCALL PhfReleaseQueuedLockShared( - _Inout_ PPH_QUEUED_LOCK QueuedLock - ) -{ - ULONG_PTR value; - ULONG_PTR newValue; - ULONG_PTR currentValue; - PPH_QUEUED_WAIT_BLOCK waitBlock; - - value = QueuedLock->Value; - - while (!(value & PH_QUEUED_LOCK_WAITERS)) - { - assert(value & PH_QUEUED_LOCK_OWNED); - assert((value & PH_QUEUED_LOCK_WAITERS) || (PhGetQueuedLockSharedOwners(value) > 0)); - - if (PhGetQueuedLockSharedOwners(value) > 1) - newValue = value - PH_QUEUED_LOCK_SHARED_INC; - else - newValue = 0; - - if ((newValue = (ULONG_PTR)_InterlockedCompareExchangePointer( - (PVOID *)&QueuedLock->Value, - (PVOID)newValue, - (PVOID)value - )) == value) - return; - - value = newValue; - } - - if (value & PH_QUEUED_LOCK_MULTIPLE_SHARED) - { - // Unfortunately we have to find the last wait block and decrement the shared owners count. - waitBlock = PhpFindLastQueuedWaitBlock(value); - - if ((ULONG)_InterlockedDecrement((PLONG)&waitBlock->SharedOwners) > 0) - return; - } - - while (TRUE) - { - if (value & PH_QUEUED_LOCK_TRAVERSING) - { - newValue = value & ~(PH_QUEUED_LOCK_OWNED | PH_QUEUED_LOCK_MULTIPLE_SHARED); - - if ((newValue = (ULONG_PTR)_InterlockedCompareExchangePointer( - (PVOID *)&QueuedLock->Value, - (PVOID)newValue, - (PVOID)value - )) == value) - break; - } - else - { - newValue = (value & ~(PH_QUEUED_LOCK_OWNED | PH_QUEUED_LOCK_MULTIPLE_SHARED)) | - PH_QUEUED_LOCK_TRAVERSING; - currentValue = newValue; - - if ((newValue = (ULONG_PTR)_InterlockedCompareExchangePointer( - (PVOID *)&QueuedLock->Value, - (PVOID)newValue, - (PVOID)value - )) == value) - { - PhpfWakeQueuedLock(QueuedLock, currentValue); - break; - } - } - - value = newValue; - } -} - -/** - * Wakes one thread sleeping on a condition variable. - * - * \param Condition A condition variable. - * - * \remarks The associated lock must be acquired before calling the function. - */ -VOID FASTCALL PhfPulseCondition( - _Inout_ PPH_CONDITION Condition - ) -{ - if (Condition->Value & PH_QUEUED_LOCK_WAITERS) - PhpfWakeQueuedLockEx(Condition, Condition->Value, TRUE, FALSE); -} - -/** - * Wakes all threads sleeping on a condition variable. - * - * \param Condition A condition variable. - * - * \remarks The associated lock must be acquired before calling the function. - */ -VOID FASTCALL PhfPulseAllCondition( - _Inout_ PPH_CONDITION Condition - ) -{ - if (Condition->Value & PH_QUEUED_LOCK_WAITERS) - PhpfWakeQueuedLockEx(Condition, Condition->Value, TRUE, TRUE); -} - -/** - * Sleeps on a condition variable. - * - * \param Condition A condition variable. - * \param Lock A queued lock to release/acquire in exclusive mode. - * \param Timeout Not implemented. - * - * \remarks The associated lock must be acquired before calling the function. - */ -VOID FASTCALL PhfWaitForCondition( - _Inout_ PPH_CONDITION Condition, - _Inout_ PPH_QUEUED_LOCK Lock, - _In_opt_ PLARGE_INTEGER Timeout - ) -{ - ULONG_PTR value; - ULONG_PTR currentValue; - PH_QUEUED_WAIT_BLOCK waitBlock; - BOOLEAN optimize; - - value = Condition->Value; - - while (TRUE) - { - if (PhpPushQueuedWaitBlock( - Condition, - value, - TRUE, - &waitBlock, - &optimize, - &value, - ¤tValue - )) - { - if (optimize) - { - PhpOptimizeQueuedLockListEx(Condition, currentValue, TRUE); - } - - PhReleaseQueuedLockExclusive(Lock); - - PhpBlockOnQueuedWaitBlock(&waitBlock, FALSE, NULL); - - // Don't use the inline variant; it is extremely likely that the lock is still owned. - PhfAcquireQueuedLockExclusive(Lock); - - break; - } - } -} - -/** - * Sleeps on a condition variable. - * - * \param Condition A condition variable. - * \param Lock A pointer to a lock. - * \param Flags A combination of flags controlling the operation. - * \param Timeout Not implemented. - */ -VOID FASTCALL PhfWaitForConditionEx( - _Inout_ PPH_CONDITION Condition, - _Inout_ PVOID Lock, - _In_ ULONG Flags, - _In_opt_ PLARGE_INTEGER Timeout - ) -{ - ULONG_PTR value; - ULONG_PTR currentValue; - PH_QUEUED_WAIT_BLOCK waitBlock; - BOOLEAN optimize; - - value = Condition->Value; - - while (TRUE) - { - if (PhpPushQueuedWaitBlock( - Condition, - value, - TRUE, - &waitBlock, - &optimize, - &value, - ¤tValue - )) - { - if (optimize) - { - PhpOptimizeQueuedLockListEx(Condition, currentValue, TRUE); - } - - switch (Flags & PH_CONDITION_WAIT_LOCK_TYPE_MASK) - { - case PH_CONDITION_WAIT_QUEUED_LOCK: - if (!(Flags & PH_CONDITION_WAIT_SHARED)) - PhReleaseQueuedLockExclusive((PPH_QUEUED_LOCK)Lock); - else - PhReleaseQueuedLockShared((PPH_QUEUED_LOCK)Lock); - break; - case PH_CONDITION_WAIT_CRITICAL_SECTION: - RtlLeaveCriticalSection((PRTL_CRITICAL_SECTION)Lock); - break; - case PH_CONDITION_WAIT_FAST_LOCK: - if (!(Flags & PH_CONDITION_WAIT_SHARED)) - PhReleaseFastLockExclusive((PPH_FAST_LOCK)Lock); - else - PhReleaseFastLockShared((PPH_FAST_LOCK)Lock); - break; - } - - if (!(Flags & PH_CONDITION_WAIT_SPIN)) - { - PhpBlockOnQueuedWaitBlock(&waitBlock, FALSE, NULL); - } - else - { - PhpBlockOnQueuedWaitBlock(&waitBlock, TRUE, NULL); - } - - switch (Flags & PH_CONDITION_WAIT_LOCK_TYPE_MASK) - { - case PH_CONDITION_WAIT_QUEUED_LOCK: - if (!(Flags & PH_CONDITION_WAIT_SHARED)) - PhfAcquireQueuedLockExclusive((PPH_QUEUED_LOCK)Lock); - else - PhfAcquireQueuedLockShared((PPH_QUEUED_LOCK)Lock); - break; - case PH_CONDITION_WAIT_CRITICAL_SECTION: - RtlEnterCriticalSection((PRTL_CRITICAL_SECTION)Lock); - break; - case PH_CONDITION_WAIT_FAST_LOCK: - if (!(Flags & PH_CONDITION_WAIT_SHARED)) - PhAcquireFastLockExclusive((PPH_FAST_LOCK)Lock); - else - PhAcquireFastLockShared((PPH_FAST_LOCK)Lock); - break; - } - - break; - } - } -} - -/** - * Queues a wait block to a wake event. - * - * \param WakeEvent A wake event. - * \param WaitBlock A wait block. - * - * \remarks If you later determine that the wait should not occur, you must call PhfSetWakeEvent() - * to dequeue the wait block. - */ -VOID FASTCALL PhfQueueWakeEvent( - _Inout_ PPH_WAKE_EVENT WakeEvent, - _Out_ PPH_QUEUED_WAIT_BLOCK WaitBlock - ) -{ - PPH_QUEUED_WAIT_BLOCK value; - PPH_QUEUED_WAIT_BLOCK newValue; - - WaitBlock->Flags = PH_QUEUED_WAITER_SPINNING; - - value = (PPH_QUEUED_WAIT_BLOCK)WakeEvent->Value; - - while (TRUE) - { - WaitBlock->Next = value; - - if ((newValue = _InterlockedCompareExchangePointer( - (PVOID *)&WakeEvent->Value, - WaitBlock, - value - )) == value) - break; - - value = newValue; - } -} - -/** - * Sets a wake event, unblocking all queued wait blocks. - * - * \param WakeEvent A wake event. - * \param WaitBlock A wait block for a cancelled wait, otherwise NULL. - */ -VOID FASTCALL PhfSetWakeEvent( - _Inout_ PPH_WAKE_EVENT WakeEvent, - _Inout_opt_ PPH_QUEUED_WAIT_BLOCK WaitBlock - ) -{ - PPH_QUEUED_WAIT_BLOCK waitBlock; - PPH_QUEUED_WAIT_BLOCK nextWaitBlock; - - // Pop all waiters and unblock them. - - waitBlock = _InterlockedExchangePointer((PVOID *)&WakeEvent->Value, NULL); - - while (waitBlock) - { - nextWaitBlock = waitBlock->Next; - PhpUnblockQueuedWaitBlock(waitBlock); - waitBlock = nextWaitBlock; - } - - if (WaitBlock) - { - // We're cancelling a wait; the thread called this function instead of PhfWaitForWakeEvent. - // This will remove all waiters from the list. However, we may not have popped and unblocked - // the cancelled wait block ourselves. Another thread may have popped all waiters but not - // unblocked them yet at this point: - // - // 1. This thread: calls PhfQueueWakeEvent. - // 2. This thread: code determines that the wait should be cancelled. - // 3. Other thread: calls PhfSetWakeEvent and pops our wait block off. It hasn't unblocked - // any wait blocks yet. - // 4. This thread: calls PhfSetWakeEvent. Since all wait blocks have been popped, we don't - // do anything. The caller function exits, making our wait block invalid. - // 5. Other thread: tries to unblock our wait block. Anything could happen, since our caller - // already returned. - // - // The solution is to (always) wait for an unblock. Note that the check below for the - // spinning flag is not required, but it is a small optimization. If the wait block has been - // unblocked (i.e. the spinning flag is cleared), then there's no danger. - - if (WaitBlock->Flags & PH_QUEUED_WAITER_SPINNING) - PhpBlockOnQueuedWaitBlock(WaitBlock, FALSE, NULL); - } -} - -/** - * Waits for a wake event to be set. - * - * \param WakeEvent A wake event. - * \param WaitBlock A wait block previously queued to the wake event using PhfQueueWakeEvent(). - * \param Spin TRUE to spin on the wake event before blocking, FALSE to block immediately. - * \param Timeout A timeout value. - * - * \remarks Wake events are subject to spurious wakeups. You should call this function in a loop - * which checks a predicate. - */ -NTSTATUS FASTCALL PhfWaitForWakeEvent( - _Inout_ PPH_WAKE_EVENT WakeEvent, - _Inout_ PPH_QUEUED_WAIT_BLOCK WaitBlock, - _In_ BOOLEAN Spin, - _In_opt_ PLARGE_INTEGER Timeout - ) -{ - NTSTATUS status; - - status = PhpBlockOnQueuedWaitBlock(WaitBlock, Spin, Timeout); - - if (status != STATUS_SUCCESS) - { - // Probably a timeout. There's no way of unlinking the wait block safely, so just wake - // everyone. - PhSetWakeEvent(WakeEvent, WaitBlock); - } - - return status; -} +/* + * Process Hacker - + * queued lock + * + * Copyright (C) 2010-2016 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +/* + * Queued lock, a.k.a. push lock (kernel-mode) or slim reader-writer lock (user-mode). + * + * The queued lock is: + * * Around 10% faster than the fast lock. + * * Only the size of a pointer. + * * Low on resource usage (no additional kernel objects are created for blocking). + * + * The usual flags are used for contention-free acquire/release. When there is contention, + * stack-based wait blocks are chained. The first wait block contains the shared owners count which + * is decremented by shared releasers. + * + * Naturally these wait blocks would be chained in FILO order, but list optimization is done for two + * purposes: + * * Finding the last wait block (where the shared owners count is stored). This is implemented by + * the Last pointer. + * * Unblocking the wait blocks in FIFO order. This is implemented by the Previous pointer. + * + * The optimization is incremental - each optimization run will stop at the first optimized wait + * block. Any needed optimization is completed just before waking waiters. + * + * The waiters list/chain has the following restrictions: + * * At any time wait blocks may be pushed onto the list. + * * While waking waiters, the list may not be traversed nor optimized. + * * When there are multiple shared owners, shared releasers may traverse the list (to find the last + * wait block). This is not an issue because waiters wouldn't be woken until there are no more + * shared owners. + * * List optimization may be done at any time except for when someone else is waking waiters. This + * is controlled by the traversing bit. + * + * The traversing bit has the following rules: + * * The list may be optimized only after the traversing bit is set, checking that it wasn't set + * already. If it was set, it would indicate that someone else is optimizing the list or waking + * waiters. + * * Before waking waiters the traversing bit must be set. If it was set already, just clear the + * owned bit. + * * If during list optimization the owned bit is detected to be cleared, the function begins waking + * waiters. This is because the owned bit is cleared when a releaser fails to set the traversing + * bit. + * + * Blocking is implemented through a process-wide keyed event. A spin count is also used before + * blocking on the keyed event. + * + * Queued locks can act as condition variables, with wait, pulse and pulse all support. Waiters are + * released in FIFO order. + * + * Queued locks can act as wake events. These are designed for tiny one-bit locks which share a + * single event to block on. Spurious wake-ups are a part of normal operation. + */ + +#include + +#include +#include +#include + +VOID FASTCALL PhpfOptimizeQueuedLockList( + _Inout_ PPH_QUEUED_LOCK QueuedLock, + _In_ ULONG_PTR Value + ); + +VOID FASTCALL PhpfWakeQueuedLock( + _Inout_ PPH_QUEUED_LOCK QueuedLock, + _In_ ULONG_PTR Value + ); + +VOID FASTCALL PhpfWakeQueuedLockEx( + _Inout_ PPH_QUEUED_LOCK QueuedLock, + _In_ ULONG_PTR Value, + _In_ BOOLEAN IgnoreOwned, + _In_ BOOLEAN WakeAll + ); + +static HANDLE PhQueuedLockKeyedEventHandle; +static ULONG PhQueuedLockSpinCount = 2000; + +BOOLEAN PhQueuedLockInitialization( + VOID + ) +{ + if (!NT_SUCCESS(NtCreateKeyedEvent( + &PhQueuedLockKeyedEventHandle, + KEYEDEVENT_ALL_ACCESS, + NULL, + 0 + ))) + return FALSE; + + if ((ULONG)PhSystemBasicInformation.NumberOfProcessors > 1) + PhQueuedLockSpinCount = 4000; + else + PhQueuedLockSpinCount = 0; + + return TRUE; +} + +/** + * Pushes a wait block onto a queued lock's waiters list. + * + * \param QueuedLock A queued lock. + * \param Value The current value of the queued lock. + * \param Exclusive Whether the wait block is in exclusive mode. + * \param WaitBlock A variable which receives the resulting wait block structure. + * \param Optimize A variable which receives a boolean indicating whether to optimize the waiters + * list. + * \param NewValue The old value of the queued lock. This value is useful only if the function + * returns FALSE. + * \param CurrentValue The new value of the queued lock. This value is useful only if the function + * returns TRUE. + * + * \return TRUE if the wait block was pushed onto the waiters list, otherwise FALSE. + * + * \remarks + * \li The function assumes the following flags are set: + * \ref PH_QUEUED_LOCK_OWNED. + * \li Do not move the wait block location after this function is called. + * \li The \a Optimize boolean is a hint to call PhpfOptimizeQueuedLockList() if the function + * succeeds. It is recommended, but not essential that this occurs. + * \li Call PhpBlockOnQueuedWaitBlock() to wait for the wait block to be unblocked. + */ +FORCEINLINE BOOLEAN PhpPushQueuedWaitBlock( + _Inout_ PPH_QUEUED_LOCK QueuedLock, + _In_ ULONG_PTR Value, + _In_ BOOLEAN Exclusive, + _Out_ PPH_QUEUED_WAIT_BLOCK WaitBlock, + _Out_ PBOOLEAN Optimize, + _Out_ PULONG_PTR NewValue, + _Out_ PULONG_PTR CurrentValue + ) +{ + ULONG_PTR newValue; + BOOLEAN optimize; + + WaitBlock->Previous = NULL; // set later by optimization + optimize = FALSE; + + if (Exclusive) + WaitBlock->Flags = PH_QUEUED_WAITER_EXCLUSIVE | PH_QUEUED_WAITER_SPINNING; + else + WaitBlock->Flags = PH_QUEUED_WAITER_SPINNING; + + if (Value & PH_QUEUED_LOCK_WAITERS) + { + // We're not the first waiter. + + WaitBlock->Last = NULL; // set later by optimization + WaitBlock->Next = PhGetQueuedLockWaitBlock(Value); + WaitBlock->SharedOwners = 0; + + // Push our wait block onto the list. + // Set the traversing bit because we'll be optimizing the list. + newValue = ((ULONG_PTR)WaitBlock) | (Value & PH_QUEUED_LOCK_FLAGS) | + PH_QUEUED_LOCK_TRAVERSING; + + if (!(Value & PH_QUEUED_LOCK_TRAVERSING)) + optimize = TRUE; + } + else + { + // We're the first waiter. + + WaitBlock->Last = WaitBlock; // indicate that this is the last wait block + + if (Exclusive) + { + // We're the first waiter. Save the shared owners count. + WaitBlock->SharedOwners = (ULONG)PhGetQueuedLockSharedOwners(Value); + + if (WaitBlock->SharedOwners > 1) + { + newValue = ((ULONG_PTR)WaitBlock) | PH_QUEUED_LOCK_OWNED | + PH_QUEUED_LOCK_WAITERS | PH_QUEUED_LOCK_MULTIPLE_SHARED; + } + else + { + newValue = ((ULONG_PTR)WaitBlock) | PH_QUEUED_LOCK_OWNED | + PH_QUEUED_LOCK_WAITERS; + } + } + else + { + // We're waiting in shared mode, which means there can't be any shared owners (otherwise + // we would've acquired the lock already). + + WaitBlock->SharedOwners = 0; + + newValue = ((ULONG_PTR)WaitBlock) | PH_QUEUED_LOCK_OWNED | + PH_QUEUED_LOCK_WAITERS; + } + } + + *Optimize = optimize; + *CurrentValue = newValue; + + newValue = (ULONG_PTR)_InterlockedCompareExchangePointer( + (PVOID *)&QueuedLock->Value, + (PVOID)newValue, + (PVOID)Value + ); + + *NewValue = newValue; + + return newValue == Value; +} + +/** + * Finds the last wait block in the waiters list. + * + * \param Value The current value of the queued lock. + * + * \return A pointer to the last wait block. + * + * \remarks The function assumes the following flags are set: + * \ref PH_QUEUED_LOCK_WAITERS, + * \ref PH_QUEUED_LOCK_MULTIPLE_SHARED or + * \ref PH_QUEUED_LOCK_TRAVERSING. + */ +FORCEINLINE PPH_QUEUED_WAIT_BLOCK PhpFindLastQueuedWaitBlock( + _In_ ULONG_PTR Value + ) +{ + PPH_QUEUED_WAIT_BLOCK waitBlock; + PPH_QUEUED_WAIT_BLOCK lastWaitBlock; + + waitBlock = PhGetQueuedLockWaitBlock(Value); + + // Traverse the list until we find the last wait block. + // The Last pointer should be set by list optimization, allowing us to skip all, if not most of + // the wait blocks. + + while (TRUE) + { + lastWaitBlock = waitBlock->Last; + + if (lastWaitBlock) + { + // Follow the Last pointer. This can mean two things: the pointer was set by list + // optimization, or this wait block is actually the last wait block (set when it was + // pushed onto the list). + waitBlock = lastWaitBlock; + break; + } + + waitBlock = waitBlock->Next; + } + + return waitBlock; +} + +/** + * Waits for a wait block to be unblocked. + * + * \param WaitBlock A wait block. + * \param Spin TRUE to spin, FALSE to block immediately. + * \param Timeout A timeout value. + */ +_May_raise_ FORCEINLINE NTSTATUS PhpBlockOnQueuedWaitBlock( + _Inout_ PPH_QUEUED_WAIT_BLOCK WaitBlock, + _In_ BOOLEAN Spin, + _In_opt_ PLARGE_INTEGER Timeout + ) +{ + NTSTATUS status; + ULONG i; + + if (Spin) + { + PHLIB_INC_STATISTIC(QlBlockSpins); + + for (i = PhQueuedLockSpinCount; i != 0; i--) + { + if (!(*(volatile ULONG *)&WaitBlock->Flags & PH_QUEUED_WAITER_SPINNING)) + return STATUS_SUCCESS; + + YieldProcessor(); + } + } + + if (_interlockedbittestandreset((PLONG)&WaitBlock->Flags, PH_QUEUED_WAITER_SPINNING_SHIFT)) + { + PHLIB_INC_STATISTIC(QlBlockWaits); + + status = NtWaitForKeyedEvent( + PhQueuedLockKeyedEventHandle, + WaitBlock, + FALSE, + Timeout + ); + + // If an error occurred (timeout is not an error), raise an exception as it is nearly + // impossible to recover from this situation. + if (!NT_SUCCESS(status)) + PhRaiseStatus(status); + } + else + { + status = STATUS_SUCCESS; + } + + return status; +} + +/** + * Unblocks a wait block. + * + * \param WaitBlock A wait block. + * + * \remarks The wait block is in an undefined state after it is unblocked. Do not attempt to read + * any values from it. All relevant information should be saved before unblocking the wait block. + */ +_May_raise_ FORCEINLINE VOID PhpUnblockQueuedWaitBlock( + _Inout_ PPH_QUEUED_WAIT_BLOCK WaitBlock + ) +{ + NTSTATUS status; + + if (!_interlockedbittestandreset((PLONG)&WaitBlock->Flags, PH_QUEUED_WAITER_SPINNING_SHIFT)) + { + if (!NT_SUCCESS(status = NtReleaseKeyedEvent( + PhQueuedLockKeyedEventHandle, + WaitBlock, + FALSE, + NULL + ))) + PhRaiseStatus(status); + } +} + +/** + * Optimizes a queued lock waiters list. + * + * \param QueuedLock A queued lock. + * \param Value The current value of the queued lock. + * \param IgnoreOwned TRUE to ignore lock state, FALSE to conduct normal checks. + * + * \remarks The function assumes the following flags are set: + * \ref PH_QUEUED_LOCK_WAITERS, \ref PH_QUEUED_LOCK_TRAVERSING. + */ +FORCEINLINE VOID PhpOptimizeQueuedLockListEx( + _Inout_ PPH_QUEUED_LOCK QueuedLock, + _In_ ULONG_PTR Value, + _In_ BOOLEAN IgnoreOwned + ) +{ + ULONG_PTR value; + ULONG_PTR newValue; + PPH_QUEUED_WAIT_BLOCK waitBlock; + PPH_QUEUED_WAIT_BLOCK firstWaitBlock; + PPH_QUEUED_WAIT_BLOCK lastWaitBlock; + PPH_QUEUED_WAIT_BLOCK previousWaitBlock; + + value = Value; + + while (TRUE) + { + assert(value & PH_QUEUED_LOCK_TRAVERSING); + + if (!IgnoreOwned && !(value & PH_QUEUED_LOCK_OWNED)) + { + // Someone has requested that we wake waiters. + PhpfWakeQueuedLock(QueuedLock, value); + break; + } + + // Perform the optimization. + + waitBlock = PhGetQueuedLockWaitBlock(value); + firstWaitBlock = waitBlock; + + while (TRUE) + { + lastWaitBlock = waitBlock->Last; + + if (lastWaitBlock) + { + // Save a pointer to the last wait block in the first wait block and stop + // optimizing. + // + // We don't need to continue setting Previous pointers because the last optimization + // run would have set them already. + + firstWaitBlock->Last = lastWaitBlock; + break; + } + + previousWaitBlock = waitBlock; + waitBlock = waitBlock->Next; + waitBlock->Previous = previousWaitBlock; + } + + // Try to clear the traversing bit. + + newValue = value - PH_QUEUED_LOCK_TRAVERSING; + + if ((newValue = (ULONG_PTR)_InterlockedCompareExchangePointer( + (PVOID *)&QueuedLock->Value, + (PVOID)newValue, + (PVOID)value + )) == value) + break; + + // Either someone pushed a wait block onto the list or someone released ownership. In either + // case we need to go back. + + value = newValue; + } +} + +/** + * Optimizes a queued lock waiters list. + * + * \param QueuedLock A queued lock. + * \param Value The current value of the queued lock. + * + * \remarks The function assumes the following flags are set: + * \ref PH_QUEUED_LOCK_WAITERS, \ref PH_QUEUED_LOCK_TRAVERSING. + */ +VOID FASTCALL PhpfOptimizeQueuedLockList( + _Inout_ PPH_QUEUED_LOCK QueuedLock, + _In_ ULONG_PTR Value + ) +{ + PhpOptimizeQueuedLockListEx(QueuedLock, Value, FALSE); +} + +/** + * Dequeues the appropriate number of wait blocks in a queued lock. + * + * \param QueuedLock A queued lock. + * \param Value The current value of the queued lock. + * \param IgnoreOwned TRUE to ignore lock state, FALSE to conduct normal checks. + * \param WakeAll TRUE to remove all wait blocks, FALSE to decide based on the wait block type. + */ +FORCEINLINE PPH_QUEUED_WAIT_BLOCK PhpPrepareToWakeQueuedLock( + _Inout_ PPH_QUEUED_LOCK QueuedLock, + _In_ ULONG_PTR Value, + _In_ BOOLEAN IgnoreOwned, + _In_ BOOLEAN WakeAll + ) +{ + ULONG_PTR value; + ULONG_PTR newValue; + PPH_QUEUED_WAIT_BLOCK waitBlock; + PPH_QUEUED_WAIT_BLOCK firstWaitBlock; + PPH_QUEUED_WAIT_BLOCK lastWaitBlock; + PPH_QUEUED_WAIT_BLOCK previousWaitBlock; + + value = Value; + + while (TRUE) + { + // If there are multiple shared owners, no one is going to wake waiters since the lock would + // still be owned. Also if there are multiple shared owners they may be traversing the list. + // While that is safe when done concurrently with list optimization, we may be removing and + // waking waiters. + assert(!(value & PH_QUEUED_LOCK_MULTIPLE_SHARED)); + assert(IgnoreOwned || (value & PH_QUEUED_LOCK_TRAVERSING)); + + // There's no point in waking a waiter if the lock is owned. Clear the traversing bit. + while (!IgnoreOwned && (value & PH_QUEUED_LOCK_OWNED)) + { + newValue = value - PH_QUEUED_LOCK_TRAVERSING; + + if ((newValue = (ULONG_PTR)_InterlockedCompareExchangePointer( + (PVOID *)&QueuedLock->Value, + (PVOID)newValue, + (PVOID)value + )) == value) + return NULL; + + value = newValue; + } + + // Finish up any needed optimization (setting the Previous pointers) while finding the last + // wait block. + + waitBlock = PhGetQueuedLockWaitBlock(value); + firstWaitBlock = waitBlock; + + while (TRUE) + { + lastWaitBlock = waitBlock->Last; + + if (lastWaitBlock) + { + waitBlock = lastWaitBlock; + break; + } + + previousWaitBlock = waitBlock; + waitBlock = waitBlock->Next; + waitBlock->Previous = previousWaitBlock; + } + + // Unlink the relevant wait blocks and clear the traversing bit before we wake waiters. + + if ( + !WakeAll && + (waitBlock->Flags & PH_QUEUED_WAITER_EXCLUSIVE) && + (previousWaitBlock = waitBlock->Previous) + ) + { + // We have an exclusive waiter and there are multiple waiters. We'll only be waking this + // waiter. + + // Unlink the wait block from the list. Although other wait blocks may have their Last + // pointers set to this wait block, the algorithm to find the last wait block will stop + // here. Likewise the Next pointers are never followed beyond this point, so we don't + // need to clear those. + firstWaitBlock->Last = previousWaitBlock; + + // Make sure we only wake this waiter. + waitBlock->Previous = NULL; + + if (!IgnoreOwned) + { + // Clear the traversing bit. + _InterlockedExchangeAddPointer((PLONG_PTR)&QueuedLock->Value, -(LONG_PTR)PH_QUEUED_LOCK_TRAVERSING); + } + + break; + } + else + { + // We're waking an exclusive waiter and there is only one waiter, or we are waking a + // shared waiter and possibly others. + + newValue = 0; + + if ((newValue = (ULONG_PTR)_InterlockedCompareExchangePointer( + (PVOID *)&QueuedLock->Value, + (PVOID)newValue, + (PVOID)value + )) == value) + break; + + // Someone changed the lock (acquired it or pushed a wait block). + + value = newValue; + } + } + + return waitBlock; +} + +/** + * Wakes waiters in a queued lock. + * + * \param QueuedLock A queued lock. + * \param Value The current value of the queued lock. + * + * \remarks The function assumes the following flags are set: + * \ref PH_QUEUED_LOCK_WAITERS, \ref PH_QUEUED_LOCK_TRAVERSING. The function assumes the following + * flags are not set: + * \ref PH_QUEUED_LOCK_MULTIPLE_SHARED. + */ +VOID FASTCALL PhpfWakeQueuedLock( + _Inout_ PPH_QUEUED_LOCK QueuedLock, + _In_ ULONG_PTR Value + ) +{ + PPH_QUEUED_WAIT_BLOCK waitBlock; + PPH_QUEUED_WAIT_BLOCK previousWaitBlock; + + waitBlock = PhpPrepareToWakeQueuedLock(QueuedLock, Value, FALSE, FALSE); + + // Wake waiters. + + while (waitBlock) + { + previousWaitBlock = waitBlock->Previous; + PhpUnblockQueuedWaitBlock(waitBlock); + waitBlock = previousWaitBlock; + } +} + +/** + * Wakes waiters in a queued lock. + * + * \param QueuedLock A queued lock. + * \param Value The current value of the queued lock. + * \param IgnoreOwned TRUE to ignore lock state, FALSE to conduct normal checks. + * \param WakeAll TRUE to wake all waiters, FALSE to decide based on the wait block type. + * + * \remarks The function assumes the following flags are set: + * \ref PH_QUEUED_LOCK_WAITERS, \ref PH_QUEUED_LOCK_TRAVERSING. The function assumes the following + * flags are not set: + * \ref PH_QUEUED_LOCK_MULTIPLE_SHARED. + */ +VOID FASTCALL PhpfWakeQueuedLockEx( + _Inout_ PPH_QUEUED_LOCK QueuedLock, + _In_ ULONG_PTR Value, + _In_ BOOLEAN IgnoreOwned, + _In_ BOOLEAN WakeAll + ) +{ + PPH_QUEUED_WAIT_BLOCK waitBlock; + PPH_QUEUED_WAIT_BLOCK previousWaitBlock; + + waitBlock = PhpPrepareToWakeQueuedLock(QueuedLock, Value, IgnoreOwned, WakeAll); + + // Wake waiters. + + while (waitBlock) + { + previousWaitBlock = waitBlock->Previous; + PhpUnblockQueuedWaitBlock(waitBlock); + waitBlock = previousWaitBlock; + } +} + +/** + * Acquires a queued lock in exclusive mode. + * + * \param QueuedLock A queued lock. + */ +VOID FASTCALL PhfAcquireQueuedLockExclusive( + _Inout_ PPH_QUEUED_LOCK QueuedLock + ) +{ + ULONG_PTR value; + ULONG_PTR newValue; + ULONG_PTR currentValue; + BOOLEAN optimize; + PH_QUEUED_WAIT_BLOCK waitBlock; + + value = QueuedLock->Value; + + while (TRUE) + { + if (!(value & PH_QUEUED_LOCK_OWNED)) + { + if ((newValue = (ULONG_PTR)_InterlockedCompareExchangePointer( + (PVOID *)&QueuedLock->Value, + (PVOID)(value + PH_QUEUED_LOCK_OWNED), + (PVOID)value + )) == value) + break; + } + else + { + if (PhpPushQueuedWaitBlock( + QueuedLock, + value, + TRUE, + &waitBlock, + &optimize, + &newValue, + ¤tValue + )) + { + if (optimize) + PhpfOptimizeQueuedLockList(QueuedLock, currentValue); + + PHLIB_INC_STATISTIC(QlAcquireExclusiveBlocks); + PhpBlockOnQueuedWaitBlock(&waitBlock, TRUE, NULL); + } + } + + value = newValue; + } +} + +/** + * Acquires a queued lock in shared mode. + * + * \param QueuedLock A queued lock. + */ +VOID FASTCALL PhfAcquireQueuedLockShared( + _Inout_ PPH_QUEUED_LOCK QueuedLock + ) +{ + ULONG_PTR value; + ULONG_PTR newValue; + ULONG_PTR currentValue; + BOOLEAN optimize; + PH_QUEUED_WAIT_BLOCK waitBlock; + + value = QueuedLock->Value; + + while (TRUE) + { + // We can't acquire if there are waiters for two reasons: + // + // We want to prioritize exclusive acquires over shared acquires. There's currently no fast, + // safe way of finding the last wait block and incrementing the shared owners count here. + if ( + !(value & PH_QUEUED_LOCK_WAITERS) && + (!(value & PH_QUEUED_LOCK_OWNED) || (PhGetQueuedLockSharedOwners(value) > 0)) + ) + { + newValue = (value + PH_QUEUED_LOCK_SHARED_INC) | PH_QUEUED_LOCK_OWNED; + + if ((newValue = (ULONG_PTR)_InterlockedCompareExchangePointer( + (PVOID *)&QueuedLock->Value, + (PVOID)newValue, + (PVOID)value + )) == value) + break; + } + else + { + if (PhpPushQueuedWaitBlock( + QueuedLock, + value, + FALSE, + &waitBlock, + &optimize, + &newValue, + ¤tValue + )) + { + if (optimize) + PhpfOptimizeQueuedLockList(QueuedLock, currentValue); + + PHLIB_INC_STATISTIC(QlAcquireSharedBlocks); + PhpBlockOnQueuedWaitBlock(&waitBlock, TRUE, NULL); + } + } + + value = newValue; + } +} + +/** + * Releases a queued lock in exclusive mode. + * + * \param QueuedLock A queued lock. + */ +VOID FASTCALL PhfReleaseQueuedLockExclusive( + _Inout_ PPH_QUEUED_LOCK QueuedLock + ) +{ + ULONG_PTR value; + ULONG_PTR newValue; + ULONG_PTR currentValue; + + value = QueuedLock->Value; + + while (TRUE) + { + assert(value & PH_QUEUED_LOCK_OWNED); + assert((value & PH_QUEUED_LOCK_WAITERS) || (PhGetQueuedLockSharedOwners(value) == 0)); + + if ((value & (PH_QUEUED_LOCK_WAITERS | PH_QUEUED_LOCK_TRAVERSING)) != PH_QUEUED_LOCK_WAITERS) + { + // There are no waiters or someone is traversing the list. + // + // If there are no waiters, we're simply releasing ownership. If someone is traversing + // the list, clearing the owned bit is a signal for them to wake waiters. + + newValue = value - PH_QUEUED_LOCK_OWNED; + + if ((newValue = (ULONG_PTR)_InterlockedCompareExchangePointer( + (PVOID *)&QueuedLock->Value, + (PVOID)newValue, + (PVOID)value + )) == value) + break; + } + else + { + // We need to wake waiters and no one is traversing the list. + // Try to set the traversing bit and wake waiters. + + newValue = value - PH_QUEUED_LOCK_OWNED + PH_QUEUED_LOCK_TRAVERSING; + currentValue = newValue; + + if ((newValue = (ULONG_PTR)_InterlockedCompareExchangePointer( + (PVOID *)&QueuedLock->Value, + (PVOID)newValue, + (PVOID)value + )) == value) + { + PhpfWakeQueuedLock(QueuedLock, currentValue); + break; + } + } + + value = newValue; + } +} + +/** + * Wakes waiters in a queued lock for releasing it in exclusive mode. + * + * \param QueuedLock A queued lock. + * \param Value The current value of the queued lock. + * + * \remarks The function assumes the following flags are set: + * \ref PH_QUEUED_LOCK_WAITERS. The function assumes the following flags are not set: + * \ref PH_QUEUED_LOCK_MULTIPLE_SHARED, \ref PH_QUEUED_LOCK_TRAVERSING. + */ +VOID FASTCALL PhfWakeForReleaseQueuedLock( + _Inout_ PPH_QUEUED_LOCK QueuedLock, + _In_ ULONG_PTR Value + ) +{ + ULONG_PTR newValue; + + newValue = Value + PH_QUEUED_LOCK_TRAVERSING; + + if ((ULONG_PTR)_InterlockedCompareExchangePointer( + (PVOID *)&QueuedLock->Value, + (PVOID)newValue, + (PVOID)Value + ) == Value) + { + PhpfWakeQueuedLock(QueuedLock, newValue); + } +} + +/** + * Releases a queued lock in shared mode. + * + * \param QueuedLock A queued lock. + */ +VOID FASTCALL PhfReleaseQueuedLockShared( + _Inout_ PPH_QUEUED_LOCK QueuedLock + ) +{ + ULONG_PTR value; + ULONG_PTR newValue; + ULONG_PTR currentValue; + PPH_QUEUED_WAIT_BLOCK waitBlock; + + value = QueuedLock->Value; + + while (!(value & PH_QUEUED_LOCK_WAITERS)) + { + assert(value & PH_QUEUED_LOCK_OWNED); + assert((value & PH_QUEUED_LOCK_WAITERS) || (PhGetQueuedLockSharedOwners(value) > 0)); + + if (PhGetQueuedLockSharedOwners(value) > 1) + newValue = value - PH_QUEUED_LOCK_SHARED_INC; + else + newValue = 0; + + if ((newValue = (ULONG_PTR)_InterlockedCompareExchangePointer( + (PVOID *)&QueuedLock->Value, + (PVOID)newValue, + (PVOID)value + )) == value) + return; + + value = newValue; + } + + if (value & PH_QUEUED_LOCK_MULTIPLE_SHARED) + { + // Unfortunately we have to find the last wait block and decrement the shared owners count. + waitBlock = PhpFindLastQueuedWaitBlock(value); + + if ((ULONG)_InterlockedDecrement((PLONG)&waitBlock->SharedOwners) > 0) + return; + } + + while (TRUE) + { + if (value & PH_QUEUED_LOCK_TRAVERSING) + { + newValue = value & ~(PH_QUEUED_LOCK_OWNED | PH_QUEUED_LOCK_MULTIPLE_SHARED); + + if ((newValue = (ULONG_PTR)_InterlockedCompareExchangePointer( + (PVOID *)&QueuedLock->Value, + (PVOID)newValue, + (PVOID)value + )) == value) + break; + } + else + { + newValue = (value & ~(PH_QUEUED_LOCK_OWNED | PH_QUEUED_LOCK_MULTIPLE_SHARED)) | + PH_QUEUED_LOCK_TRAVERSING; + currentValue = newValue; + + if ((newValue = (ULONG_PTR)_InterlockedCompareExchangePointer( + (PVOID *)&QueuedLock->Value, + (PVOID)newValue, + (PVOID)value + )) == value) + { + PhpfWakeQueuedLock(QueuedLock, currentValue); + break; + } + } + + value = newValue; + } +} + +/** + * Wakes one thread sleeping on a condition variable. + * + * \param Condition A condition variable. + * + * \remarks The associated lock must be acquired before calling the function. + */ +VOID FASTCALL PhfPulseCondition( + _Inout_ PPH_CONDITION Condition + ) +{ + if (Condition->Value & PH_QUEUED_LOCK_WAITERS) + PhpfWakeQueuedLockEx(Condition, Condition->Value, TRUE, FALSE); +} + +/** + * Wakes all threads sleeping on a condition variable. + * + * \param Condition A condition variable. + * + * \remarks The associated lock must be acquired before calling the function. + */ +VOID FASTCALL PhfPulseAllCondition( + _Inout_ PPH_CONDITION Condition + ) +{ + if (Condition->Value & PH_QUEUED_LOCK_WAITERS) + PhpfWakeQueuedLockEx(Condition, Condition->Value, TRUE, TRUE); +} + +/** + * Sleeps on a condition variable. + * + * \param Condition A condition variable. + * \param Lock A queued lock to release/acquire in exclusive mode. + * \param Timeout Not implemented. + * + * \remarks The associated lock must be acquired before calling the function. + */ +VOID FASTCALL PhfWaitForCondition( + _Inout_ PPH_CONDITION Condition, + _Inout_ PPH_QUEUED_LOCK Lock, + _In_opt_ PLARGE_INTEGER Timeout + ) +{ + ULONG_PTR value; + ULONG_PTR currentValue; + PH_QUEUED_WAIT_BLOCK waitBlock; + BOOLEAN optimize; + + value = Condition->Value; + + while (TRUE) + { + if (PhpPushQueuedWaitBlock( + Condition, + value, + TRUE, + &waitBlock, + &optimize, + &value, + ¤tValue + )) + { + if (optimize) + { + PhpOptimizeQueuedLockListEx(Condition, currentValue, TRUE); + } + + PhReleaseQueuedLockExclusive(Lock); + + PhpBlockOnQueuedWaitBlock(&waitBlock, FALSE, NULL); + + // Don't use the inline variant; it is extremely likely that the lock is still owned. + PhfAcquireQueuedLockExclusive(Lock); + + break; + } + } +} + +/** + * Sleeps on a condition variable. + * + * \param Condition A condition variable. + * \param Lock A pointer to a lock. + * \param Flags A combination of flags controlling the operation. + * \param Timeout Not implemented. + */ +VOID FASTCALL PhfWaitForConditionEx( + _Inout_ PPH_CONDITION Condition, + _Inout_ PVOID Lock, + _In_ ULONG Flags, + _In_opt_ PLARGE_INTEGER Timeout + ) +{ + ULONG_PTR value; + ULONG_PTR currentValue; + PH_QUEUED_WAIT_BLOCK waitBlock; + BOOLEAN optimize; + + value = Condition->Value; + + while (TRUE) + { + if (PhpPushQueuedWaitBlock( + Condition, + value, + TRUE, + &waitBlock, + &optimize, + &value, + ¤tValue + )) + { + if (optimize) + { + PhpOptimizeQueuedLockListEx(Condition, currentValue, TRUE); + } + + switch (Flags & PH_CONDITION_WAIT_LOCK_TYPE_MASK) + { + case PH_CONDITION_WAIT_QUEUED_LOCK: + if (!(Flags & PH_CONDITION_WAIT_SHARED)) + PhReleaseQueuedLockExclusive((PPH_QUEUED_LOCK)Lock); + else + PhReleaseQueuedLockShared((PPH_QUEUED_LOCK)Lock); + break; + case PH_CONDITION_WAIT_CRITICAL_SECTION: + RtlLeaveCriticalSection((PRTL_CRITICAL_SECTION)Lock); + break; + case PH_CONDITION_WAIT_FAST_LOCK: + if (!(Flags & PH_CONDITION_WAIT_SHARED)) + PhReleaseFastLockExclusive((PPH_FAST_LOCK)Lock); + else + PhReleaseFastLockShared((PPH_FAST_LOCK)Lock); + break; + } + + if (!(Flags & PH_CONDITION_WAIT_SPIN)) + { + PhpBlockOnQueuedWaitBlock(&waitBlock, FALSE, NULL); + } + else + { + PhpBlockOnQueuedWaitBlock(&waitBlock, TRUE, NULL); + } + + switch (Flags & PH_CONDITION_WAIT_LOCK_TYPE_MASK) + { + case PH_CONDITION_WAIT_QUEUED_LOCK: + if (!(Flags & PH_CONDITION_WAIT_SHARED)) + PhfAcquireQueuedLockExclusive((PPH_QUEUED_LOCK)Lock); + else + PhfAcquireQueuedLockShared((PPH_QUEUED_LOCK)Lock); + break; + case PH_CONDITION_WAIT_CRITICAL_SECTION: + RtlEnterCriticalSection((PRTL_CRITICAL_SECTION)Lock); + break; + case PH_CONDITION_WAIT_FAST_LOCK: + if (!(Flags & PH_CONDITION_WAIT_SHARED)) + PhAcquireFastLockExclusive((PPH_FAST_LOCK)Lock); + else + PhAcquireFastLockShared((PPH_FAST_LOCK)Lock); + break; + } + + break; + } + } +} + +/** + * Queues a wait block to a wake event. + * + * \param WakeEvent A wake event. + * \param WaitBlock A wait block. + * + * \remarks If you later determine that the wait should not occur, you must call PhfSetWakeEvent() + * to dequeue the wait block. + */ +VOID FASTCALL PhfQueueWakeEvent( + _Inout_ PPH_WAKE_EVENT WakeEvent, + _Out_ PPH_QUEUED_WAIT_BLOCK WaitBlock + ) +{ + PPH_QUEUED_WAIT_BLOCK value; + PPH_QUEUED_WAIT_BLOCK newValue; + + WaitBlock->Flags = PH_QUEUED_WAITER_SPINNING; + + value = (PPH_QUEUED_WAIT_BLOCK)WakeEvent->Value; + + while (TRUE) + { + WaitBlock->Next = value; + + if ((newValue = _InterlockedCompareExchangePointer( + (PVOID *)&WakeEvent->Value, + WaitBlock, + value + )) == value) + break; + + value = newValue; + } +} + +/** + * Sets a wake event, unblocking all queued wait blocks. + * + * \param WakeEvent A wake event. + * \param WaitBlock A wait block for a cancelled wait, otherwise NULL. + */ +VOID FASTCALL PhfSetWakeEvent( + _Inout_ PPH_WAKE_EVENT WakeEvent, + _Inout_opt_ PPH_QUEUED_WAIT_BLOCK WaitBlock + ) +{ + PPH_QUEUED_WAIT_BLOCK waitBlock; + PPH_QUEUED_WAIT_BLOCK nextWaitBlock; + + // Pop all waiters and unblock them. + + waitBlock = _InterlockedExchangePointer((PVOID *)&WakeEvent->Value, NULL); + + while (waitBlock) + { + nextWaitBlock = waitBlock->Next; + PhpUnblockQueuedWaitBlock(waitBlock); + waitBlock = nextWaitBlock; + } + + if (WaitBlock) + { + // We're cancelling a wait; the thread called this function instead of PhfWaitForWakeEvent. + // This will remove all waiters from the list. However, we may not have popped and unblocked + // the cancelled wait block ourselves. Another thread may have popped all waiters but not + // unblocked them yet at this point: + // + // 1. This thread: calls PhfQueueWakeEvent. + // 2. This thread: code determines that the wait should be cancelled. + // 3. Other thread: calls PhfSetWakeEvent and pops our wait block off. It hasn't unblocked + // any wait blocks yet. + // 4. This thread: calls PhfSetWakeEvent. Since all wait blocks have been popped, we don't + // do anything. The caller function exits, making our wait block invalid. + // 5. Other thread: tries to unblock our wait block. Anything could happen, since our caller + // already returned. + // + // The solution is to (always) wait for an unblock. Note that the check below for the + // spinning flag is not required, but it is a small optimization. If the wait block has been + // unblocked (i.e. the spinning flag is cleared), then there's no danger. + + if (WaitBlock->Flags & PH_QUEUED_WAITER_SPINNING) + PhpBlockOnQueuedWaitBlock(WaitBlock, FALSE, NULL); + } +} + +/** + * Waits for a wake event to be set. + * + * \param WakeEvent A wake event. + * \param WaitBlock A wait block previously queued to the wake event using PhfQueueWakeEvent(). + * \param Spin TRUE to spin on the wake event before blocking, FALSE to block immediately. + * \param Timeout A timeout value. + * + * \remarks Wake events are subject to spurious wakeups. You should call this function in a loop + * which checks a predicate. + */ +NTSTATUS FASTCALL PhfWaitForWakeEvent( + _Inout_ PPH_WAKE_EVENT WakeEvent, + _Inout_ PPH_QUEUED_WAIT_BLOCK WaitBlock, + _In_ BOOLEAN Spin, + _In_opt_ PLARGE_INTEGER Timeout + ) +{ + NTSTATUS status; + + status = PhpBlockOnQueuedWaitBlock(WaitBlock, Spin, Timeout); + + if (status != STATUS_SUCCESS) + { + // Probably a timeout. There's no way of unlinking the wait block safely, so just wake + // everyone. + PhSetWakeEvent(WakeEvent, WaitBlock); + } + + return status; +} diff --git a/phlib/ref.c b/phlib/ref.c index faea6188bf42..53af1c79c325 100644 --- a/phlib/ref.c +++ b/phlib/ref.c @@ -1,754 +1,754 @@ -/* - * Process Hacker - - * object manager - * - * Copyright (C) 2009-2016 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include -#include - -#include -#include - -PPH_OBJECT_TYPE PhObjectTypeObject = NULL; -SLIST_HEADER PhObjectDeferDeleteListHead; -PH_FREE_LIST PhObjectSmallFreeList; -PPH_OBJECT_TYPE PhAllocType = NULL; - -ULONG PhObjectTypeCount = 0; -PPH_OBJECT_TYPE PhObjectTypeTable[PH_OBJECT_TYPE_TABLE_SIZE]; - -static ULONG PhpAutoPoolTlsIndex; - -#ifdef DEBUG -LIST_ENTRY PhDbgObjectListHead; -PH_QUEUED_LOCK PhDbgObjectListLock = PH_QUEUED_LOCK_INIT; -PPH_CREATE_OBJECT_HOOK PhDbgCreateObjectHook = NULL; -#endif - -#define REF_STAT_UP(Name) PHLIB_INC_STATISTIC(Name) - -/** - * Initializes the object manager module. - */ -NTSTATUS PhRefInitialization( - VOID - ) -{ - PH_OBJECT_TYPE dummyObjectType; - -#ifdef DEBUG - InitializeListHead(&PhDbgObjectListHead); -#endif - - RtlInitializeSListHead(&PhObjectDeferDeleteListHead); - PhInitializeFreeList( - &PhObjectSmallFreeList, - PhAddObjectHeaderSize(PH_OBJECT_SMALL_OBJECT_SIZE), - PH_OBJECT_SMALL_OBJECT_COUNT - ); - - // Create the fundamental object type. - - memset(&dummyObjectType, 0, sizeof(PH_OBJECT_TYPE)); - PhObjectTypeObject = &dummyObjectType; // PhCreateObject expects an object type. - PhObjectTypeTable[0] = &dummyObjectType; // PhCreateObject also expects PhObjectTypeTable[0] to be filled in. - PhObjectTypeObject = PhCreateObjectType(L"Type", 0, NULL); - - // Now that the fundamental object type exists, fix it up. - PhObjectToObjectHeader(PhObjectTypeObject)->TypeIndex = PhObjectTypeObject->TypeIndex; - PhObjectTypeObject->NumberOfObjects = 1; - - // Create the allocated memory object type. - PhAllocType = PhCreateObjectType(L"Alloc", 0, NULL); - - // Reserve a slot for the auto pool. - PhpAutoPoolTlsIndex = TlsAlloc(); - - if (PhpAutoPoolTlsIndex == TLS_OUT_OF_INDEXES) - return STATUS_INSUFFICIENT_RESOURCES; - - return STATUS_SUCCESS; -} - -/** - * Allocates a object. - * - * \param ObjectSize The size of the object. - * \param ObjectType The type of the object. - * - * \return A pointer to the newly allocated object. - */ -_May_raise_ PVOID PhCreateObject( - _In_ SIZE_T ObjectSize, - _In_ PPH_OBJECT_TYPE ObjectType - ) -{ - NTSTATUS status = STATUS_SUCCESS; - PPH_OBJECT_HEADER objectHeader; - - // Allocate storage for the object. Note that this includes the object header followed by the - // object body. - objectHeader = PhpAllocateObject(ObjectType, ObjectSize); - - // Object type statistics. - _InterlockedIncrement((PLONG)&ObjectType->NumberOfObjects); - - // Initialize the object header. - objectHeader->RefCount = 1; - objectHeader->TypeIndex = ObjectType->TypeIndex; - // objectHeader->Flags is set by PhpAllocateObject. - - REF_STAT_UP(RefObjectsCreated); - -#ifdef DEBUG - { - USHORT capturedFrames; - - capturedFrames = RtlCaptureStackBackTrace(1, 16, objectHeader->StackBackTrace, NULL); - memset( - &objectHeader->StackBackTrace[capturedFrames], - 0, - sizeof(objectHeader->StackBackTrace) - capturedFrames * sizeof(PVOID) - ); - } - - PhAcquireQueuedLockExclusive(&PhDbgObjectListLock); - InsertTailList(&PhDbgObjectListHead, &objectHeader->ObjectListEntry); - PhReleaseQueuedLockExclusive(&PhDbgObjectListLock); - - { - PPH_CREATE_OBJECT_HOOK dbgCreateObjectHook; - - dbgCreateObjectHook = PhDbgCreateObjectHook; - - if (dbgCreateObjectHook) - { - dbgCreateObjectHook( - PhObjectHeaderToObject(objectHeader), - ObjectSize, - 0, - ObjectType - ); - } - } -#endif - - return PhObjectHeaderToObject(objectHeader); -} - -/** - * References the specified object. - * - * \param Object A pointer to the object to reference. - * - * \return The object. - */ -PVOID PhReferenceObject( - _In_ PVOID Object - ) -{ - PPH_OBJECT_HEADER objectHeader; - - objectHeader = PhObjectToObjectHeader(Object); - // Increment the reference count. - _InterlockedIncrement(&objectHeader->RefCount); - - return Object; -} - -/** - * References the specified object. - * - * \param Object A pointer to the object to reference. - * \param RefCount The number of references to add. - * - * \return The object. - */ -_May_raise_ PVOID PhReferenceObjectEx( - _In_ PVOID Object, - _In_ LONG RefCount - ) -{ - PPH_OBJECT_HEADER objectHeader; - LONG oldRefCount; - - assert(!(RefCount < 0)); - - objectHeader = PhObjectToObjectHeader(Object); - // Increase the reference count. - oldRefCount = _InterlockedExchangeAdd(&objectHeader->RefCount, RefCount); - - return Object; -} - -/** - * Attempts to reference an object and fails if it is being destroyed. - * - * \param Object The object to reference if it is not being deleted. - * - * \return The object itself if the object was referenced, NULL if it was being deleted and was not - * referenced. - * - * \remarks This function is useful if a reference to an object is held, protected by a mutex, and - * the delete procedure of the object's type attempts to acquire the mutex. If this function is - * called while the mutex is owned, you can avoid referencing an object that is being destroyed. - */ -PVOID PhReferenceObjectSafe( - _In_ PVOID Object - ) -{ - PPH_OBJECT_HEADER objectHeader; - - objectHeader = PhObjectToObjectHeader(Object); - - // Increase the reference count only if it positive already (atomically). - if (PhpInterlockedIncrementSafe(&objectHeader->RefCount)) - return Object; - else - return NULL; -} - -/** - * Dereferences the specified object. - * The object will be freed if its reference count reaches 0. - * - * \param Object A pointer to the object to dereference. - */ -VOID PhDereferenceObject( - _In_ PVOID Object - ) -{ - PPH_OBJECT_HEADER objectHeader; - LONG newRefCount; - - objectHeader = PhObjectToObjectHeader(Object); - // Decrement the reference count. - newRefCount = _InterlockedDecrement(&objectHeader->RefCount); - ASSUME_ASSERT(newRefCount >= 0); - - // Free the object if it has 0 references. - if (newRefCount == 0) - { - PhpFreeObject(objectHeader); - } -} - -/** - * Dereferences the specified object. - * The object will be freed in a worker thread if its reference count reaches 0. - * - * \param Object A pointer to the object to dereference. - */ -VOID PhDereferenceObjectDeferDelete( - _In_ PVOID Object - ) -{ - PhDereferenceObjectEx(Object, 1, TRUE); -} - -/** - * Dereferences the specified object. - * The object will be freed if its reference count reaches 0. - * - * \param Object A pointer to the object to dereference. - * \param RefCount The number of references to remove. - * \param DeferDelete Whether to defer deletion of the object. - */ -_May_raise_ VOID PhDereferenceObjectEx( - _In_ PVOID Object, - _In_ LONG RefCount, - _In_ BOOLEAN DeferDelete - ) -{ - PPH_OBJECT_HEADER objectHeader; - LONG oldRefCount; - LONG newRefCount; - - assert(!(RefCount < 0)); - - objectHeader = PhObjectToObjectHeader(Object); - - // Decrease the reference count. - oldRefCount = _InterlockedExchangeAdd(&objectHeader->RefCount, -RefCount); - newRefCount = oldRefCount - RefCount; - - // Free the object if it has 0 references. - if (newRefCount == 0) - { - if (DeferDelete) - { - PhpDeferDeleteObject(objectHeader); - } - else - { - // Free the object. - PhpFreeObject(objectHeader); - } - } - else if (newRefCount < 0) - { - PhRaiseStatus(STATUS_INVALID_PARAMETER); - } -} - -/** - * Gets an object's type. - * - * \param Object A pointer to an object. - * - * \return A pointer to a type object. - */ -PPH_OBJECT_TYPE PhGetObjectType( - _In_ PVOID Object - ) -{ - return PhObjectTypeTable[PhObjectToObjectHeader(Object)->TypeIndex]; -} - -/** - * Creates an object type. - * - * \param Name The name of the type. - * \param Flags A combination of flags affecting the behaviour of the object type. - * \param DeleteProcedure A callback function that is executed when an object of this type is about - * to be freed (i.e. when its reference count is 0). - * - * \return A pointer to the newly created object type. - * - * \remarks Do not reference or dereference the object type once it is created. - */ -PPH_OBJECT_TYPE PhCreateObjectType( - _In_ PWSTR Name, - _In_ ULONG Flags, - _In_opt_ PPH_TYPE_DELETE_PROCEDURE DeleteProcedure - ) -{ - return PhCreateObjectTypeEx( - Name, - Flags, - DeleteProcedure, - NULL - ); -} - -/** - * Creates an object type. - * - * \param Name The name of the type. - * \param Flags A combination of flags affecting the behaviour of the object type. - * \param DeleteProcedure A callback function that is executed when an object of this type is about - * to be freed (i.e. when its reference count is 0). - * \param Parameters A structure containing additional parameters for the object type. - * - * \return A pointer to the newly created object type. - * - * \remarks Do not reference or dereference the object type once it is created. - */ -PPH_OBJECT_TYPE PhCreateObjectTypeEx( - _In_ PWSTR Name, - _In_ ULONG Flags, - _In_opt_ PPH_TYPE_DELETE_PROCEDURE DeleteProcedure, - _In_opt_ PPH_OBJECT_TYPE_PARAMETERS Parameters - ) -{ - NTSTATUS status = STATUS_SUCCESS; - PPH_OBJECT_TYPE objectType; - - // Check the flags. - if ((Flags & PH_OBJECT_TYPE_VALID_FLAGS) != Flags) /* Valid flag mask */ - PhRaiseStatus(STATUS_INVALID_PARAMETER_3); - if ((Flags & PH_OBJECT_TYPE_USE_FREE_LIST) && !Parameters) - PhRaiseStatus(STATUS_INVALID_PARAMETER_MIX); - - // Create the type object. - objectType = PhCreateObject(sizeof(PH_OBJECT_TYPE), PhObjectTypeObject); - - // Initialize the type object. - objectType->Flags = (USHORT)Flags; - objectType->TypeIndex = (USHORT)_InterlockedIncrement(&PhObjectTypeCount) - 1; - objectType->NumberOfObjects = 0; - objectType->DeleteProcedure = DeleteProcedure; - objectType->Name = Name; - - if (objectType->TypeIndex < PH_OBJECT_TYPE_TABLE_SIZE) - PhObjectTypeTable[objectType->TypeIndex] = objectType; - else - PhRaiseStatus(STATUS_UNSUCCESSFUL); - - if (Parameters) - { - if (Flags & PH_OBJECT_TYPE_USE_FREE_LIST) - { - PhInitializeFreeList( - &objectType->FreeList, - PhAddObjectHeaderSize(Parameters->FreeListSize), - Parameters->FreeListCount - ); - } - } - - return objectType; -} - -/** - * Gets information about an object type. - * - * \param ObjectType A pointer to an object type. - * \param Information A variable which receives information about the object type. - */ -VOID PhGetObjectTypeInformation( - _In_ PPH_OBJECT_TYPE ObjectType, - _Out_ PPH_OBJECT_TYPE_INFORMATION Information - ) -{ - Information->Name = ObjectType->Name; - Information->NumberOfObjects = ObjectType->NumberOfObjects; - Information->Flags = ObjectType->Flags; - Information->TypeIndex = ObjectType->TypeIndex; -} - -/** - * Allocates storage for an object. - * - * \param ObjectType The type of the object. - * \param ObjectSize The size of the object, excluding the header. - */ -PPH_OBJECT_HEADER PhpAllocateObject( - _In_ PPH_OBJECT_TYPE ObjectType, - _In_ SIZE_T ObjectSize - ) -{ - PPH_OBJECT_HEADER objectHeader; - - if (ObjectType->Flags & PH_OBJECT_TYPE_USE_FREE_LIST) - { - assert(ObjectType->FreeList.Size == PhAddObjectHeaderSize(ObjectSize)); - - objectHeader = PhAllocateFromFreeList(&ObjectType->FreeList); - objectHeader->Flags = PH_OBJECT_FROM_TYPE_FREE_LIST; - REF_STAT_UP(RefObjectsAllocatedFromTypeFreeList); - } - else if (ObjectSize <= PH_OBJECT_SMALL_OBJECT_SIZE) - { - objectHeader = PhAllocateFromFreeList(&PhObjectSmallFreeList); - objectHeader->Flags = PH_OBJECT_FROM_SMALL_FREE_LIST; - REF_STAT_UP(RefObjectsAllocatedFromSmallFreeList); - } - else - { - objectHeader = PhAllocate(PhAddObjectHeaderSize(ObjectSize)); - objectHeader->Flags = 0; - REF_STAT_UP(RefObjectsAllocated); - } - - return objectHeader; -} - -/** - * Calls the delete procedure for an object and frees its allocated storage. - * - * \param ObjectHeader A pointer to the object header of an allocated object. - */ -VOID PhpFreeObject( - _In_ PPH_OBJECT_HEADER ObjectHeader - ) -{ - PPH_OBJECT_TYPE objectType; - - objectType = PhObjectTypeTable[ObjectHeader->TypeIndex]; - - // Object type statistics. - _InterlockedDecrement(&objectType->NumberOfObjects); - -#ifdef DEBUG - PhAcquireQueuedLockExclusive(&PhDbgObjectListLock); - RemoveEntryList(&ObjectHeader->ObjectListEntry); - PhReleaseQueuedLockExclusive(&PhDbgObjectListLock); -#endif - - REF_STAT_UP(RefObjectsDestroyed); - - // Call the delete procedure if we have one. - if (objectType->DeleteProcedure) - { - objectType->DeleteProcedure(PhObjectHeaderToObject(ObjectHeader), 0); - } - - if (ObjectHeader->Flags & PH_OBJECT_FROM_TYPE_FREE_LIST) - { - PhFreeToFreeList(&objectType->FreeList, ObjectHeader); - REF_STAT_UP(RefObjectsFreedToTypeFreeList); - } - else if (ObjectHeader->Flags & PH_OBJECT_FROM_SMALL_FREE_LIST) - { - PhFreeToFreeList(&PhObjectSmallFreeList, ObjectHeader); - REF_STAT_UP(RefObjectsFreedToSmallFreeList); - } - else - { - PhFree(ObjectHeader); - REF_STAT_UP(RefObjectsFreed); - } -} - -/** - * Queues an object for deletion. - * - * \param ObjectHeader A pointer to the object header of the object to delete. - */ -VOID PhpDeferDeleteObject( - _In_ PPH_OBJECT_HEADER ObjectHeader - ) -{ - PSLIST_ENTRY oldFirstEntry; - - // Save TypeIndex and Flags since they get overwritten when we push the object onto the defer - // delete list. - ObjectHeader->DeferDelete = 1; - MemoryBarrier(); - ObjectHeader->SavedTypeIndex = ObjectHeader->TypeIndex; - ObjectHeader->SavedFlags = ObjectHeader->Flags; - - oldFirstEntry = RtlFirstEntrySList(&PhObjectDeferDeleteListHead); - RtlInterlockedPushEntrySList(&PhObjectDeferDeleteListHead, &ObjectHeader->DeferDeleteListEntry); - REF_STAT_UP(RefObjectsDeleteDeferred); - - // Was the to-free list empty before? If so, we need to queue a work item. - if (!oldFirstEntry) - { - PhQueueItemWorkQueue(PhGetGlobalWorkQueue(), PhpDeferDeleteObjectRoutine, NULL); - } -} - -/** - * Removes and frees objects from the to-free list. - */ -NTSTATUS PhpDeferDeleteObjectRoutine( - _In_ PVOID Parameter - ) -{ - PSLIST_ENTRY listEntry; - PPH_OBJECT_HEADER objectHeader; - - // Clear the list and obtain the first object to free. - listEntry = RtlInterlockedFlushSList(&PhObjectDeferDeleteListHead); - - while (listEntry) - { - objectHeader = CONTAINING_RECORD(listEntry, PH_OBJECT_HEADER, DeferDeleteListEntry); - listEntry = listEntry->Next; - - // Restore TypeIndex and Flags. - objectHeader->TypeIndex = (USHORT)objectHeader->SavedTypeIndex; - objectHeader->Flags = (UCHAR)objectHeader->SavedFlags; - - PhpFreeObject(objectHeader); - } - - return STATUS_SUCCESS; -} - -/** - * Creates a reference-counted memory block. - * - * \param Size The number of bytes to allocate. - * - * \return A pointer to the memory block. - */ -PVOID PhCreateAlloc( - _In_ SIZE_T Size - ) -{ - return PhCreateObject(Size, PhAllocType); -} - -/** - * Gets the current auto-dereference pool for the current thread. - */ -FORCEINLINE PPH_AUTO_POOL PhpGetCurrentAutoPool( - VOID - ) -{ - return (PPH_AUTO_POOL)TlsGetValue(PhpAutoPoolTlsIndex); -} - -/** - * Sets the current auto-dereference pool for the current thread. - */ -_May_raise_ FORCEINLINE VOID PhpSetCurrentAutoPool( - _In_ PPH_AUTO_POOL AutoPool - ) -{ - if (!TlsSetValue(PhpAutoPoolTlsIndex, AutoPool)) - PhRaiseStatus(STATUS_UNSUCCESSFUL); - -#ifdef DEBUG - { - PPHP_BASE_THREAD_DBG dbg; - - dbg = (PPHP_BASE_THREAD_DBG)TlsGetValue(PhDbgThreadDbgTlsIndex); - - if (dbg) - { - dbg->CurrentAutoPool = AutoPool; - } - } -#endif -} - -/** - * Initializes an auto-dereference pool and sets it as the current pool for the current thread. You - * must call PhDeleteAutoPool() before storage for the auto-dereference pool is freed. - * - * \remarks Always store auto-dereference pools in local variables, and do not share the pool with - * any other functions. - */ -VOID PhInitializeAutoPool( - _Out_ PPH_AUTO_POOL AutoPool - ) -{ - AutoPool->StaticCount = 0; - AutoPool->DynamicCount = 0; - AutoPool->DynamicAllocated = 0; - AutoPool->DynamicObjects = NULL; - - // Add the pool to the stack. - AutoPool->NextPool = PhpGetCurrentAutoPool(); - PhpSetCurrentAutoPool(AutoPool); - - REF_STAT_UP(RefAutoPoolsCreated); -} - -/** - * Deletes an auto-dereference pool. The function will dereference any objects currently in the - * pool. If a pool other than the current pool is passed to the function, an exception is raised. - * - * \param AutoPool The auto-dereference pool to delete. - */ -_May_raise_ VOID PhDeleteAutoPool( - _Inout_ PPH_AUTO_POOL AutoPool - ) -{ - PhDrainAutoPool(AutoPool); - - if (PhpGetCurrentAutoPool() != AutoPool) - PhRaiseStatus(STATUS_UNSUCCESSFUL); - - // Remove the pool from the stack. - PhpSetCurrentAutoPool(AutoPool->NextPool); - - // Free the dynamic array if it hasn't been freed yet. - if (AutoPool->DynamicObjects) - PhFree(AutoPool->DynamicObjects); - - REF_STAT_UP(RefAutoPoolsDestroyed); -} - -/** - * Dereferences and removes all objects in an auto-release pool. - * - * \param AutoPool The auto-release pool to drain. - */ -VOID PhDrainAutoPool( - _In_ PPH_AUTO_POOL AutoPool - ) -{ - ULONG i; - - for (i = 0; i < AutoPool->StaticCount; i++) - PhDereferenceObject(AutoPool->StaticObjects[i]); - - AutoPool->StaticCount = 0; - - if (AutoPool->DynamicObjects) - { - for (i = 0; i < AutoPool->DynamicCount; i++) - { - PhDereferenceObject(AutoPool->DynamicObjects[i]); - } - - AutoPool->DynamicCount = 0; - - if (AutoPool->DynamicAllocated > PH_AUTO_POOL_DYNAMIC_BIG_SIZE) - { - AutoPool->DynamicAllocated = 0; - PhFree(AutoPool->DynamicObjects); - AutoPool->DynamicObjects = NULL; - } - } -} - -/** - * Adds an object to the current auto-dereference pool for the current thread. If the current thread - * does not have an auto-dereference pool, the function raises an exception. - * - * \param Object A pointer to an object. The object will be dereferenced when the current - * auto-dereference pool is drained or freed. - */ -_May_raise_ PVOID PhAutoDereferenceObject( - _In_opt_ PVOID Object - ) -{ - PPH_AUTO_POOL autoPool = PhpGetCurrentAutoPool(); - -#ifdef DEBUG - // If we don't have an auto-dereference pool, we don't want to leak the object (unlike what - // Apple does with NSAutoreleasePool). - if (!autoPool) - PhRaiseStatus(STATUS_UNSUCCESSFUL); -#endif - - if (!Object) - return NULL; - - // See if we can use the static array. - if (autoPool->StaticCount < PH_AUTO_POOL_STATIC_SIZE) - { - autoPool->StaticObjects[autoPool->StaticCount++] = Object; - return Object; - } - - // Use the dynamic array. - - // Allocate the array if we haven't already. - if (!autoPool->DynamicObjects) - { - autoPool->DynamicAllocated = 64; - autoPool->DynamicObjects = PhAllocate( - sizeof(PVOID) * autoPool->DynamicAllocated - ); - REF_STAT_UP(RefAutoPoolsDynamicAllocated); - } - - // See if we need to resize the array. - if (autoPool->DynamicCount == autoPool->DynamicAllocated) - { - autoPool->DynamicAllocated *= 2; - autoPool->DynamicObjects = PhReAllocate( - autoPool->DynamicObjects, - sizeof(PVOID) * autoPool->DynamicAllocated - ); - REF_STAT_UP(RefAutoPoolsDynamicResized); - } - - autoPool->DynamicObjects[autoPool->DynamicCount++] = Object; - - return Object; -} +/* + * Process Hacker - + * object manager + * + * Copyright (C) 2009-2016 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include +#include + +#include +#include + +PPH_OBJECT_TYPE PhObjectTypeObject = NULL; +SLIST_HEADER PhObjectDeferDeleteListHead; +PH_FREE_LIST PhObjectSmallFreeList; +PPH_OBJECT_TYPE PhAllocType = NULL; + +ULONG PhObjectTypeCount = 0; +PPH_OBJECT_TYPE PhObjectTypeTable[PH_OBJECT_TYPE_TABLE_SIZE]; + +static ULONG PhpAutoPoolTlsIndex; + +#ifdef DEBUG +LIST_ENTRY PhDbgObjectListHead; +PH_QUEUED_LOCK PhDbgObjectListLock = PH_QUEUED_LOCK_INIT; +PPH_CREATE_OBJECT_HOOK PhDbgCreateObjectHook = NULL; +#endif + +#define REF_STAT_UP(Name) PHLIB_INC_STATISTIC(Name) + +/** + * Initializes the object manager module. + */ +NTSTATUS PhRefInitialization( + VOID + ) +{ + PH_OBJECT_TYPE dummyObjectType; + +#ifdef DEBUG + InitializeListHead(&PhDbgObjectListHead); +#endif + + RtlInitializeSListHead(&PhObjectDeferDeleteListHead); + PhInitializeFreeList( + &PhObjectSmallFreeList, + PhAddObjectHeaderSize(PH_OBJECT_SMALL_OBJECT_SIZE), + PH_OBJECT_SMALL_OBJECT_COUNT + ); + + // Create the fundamental object type. + + memset(&dummyObjectType, 0, sizeof(PH_OBJECT_TYPE)); + PhObjectTypeObject = &dummyObjectType; // PhCreateObject expects an object type. + PhObjectTypeTable[0] = &dummyObjectType; // PhCreateObject also expects PhObjectTypeTable[0] to be filled in. + PhObjectTypeObject = PhCreateObjectType(L"Type", 0, NULL); + + // Now that the fundamental object type exists, fix it up. + PhObjectToObjectHeader(PhObjectTypeObject)->TypeIndex = PhObjectTypeObject->TypeIndex; + PhObjectTypeObject->NumberOfObjects = 1; + + // Create the allocated memory object type. + PhAllocType = PhCreateObjectType(L"Alloc", 0, NULL); + + // Reserve a slot for the auto pool. + PhpAutoPoolTlsIndex = TlsAlloc(); + + if (PhpAutoPoolTlsIndex == TLS_OUT_OF_INDEXES) + return STATUS_INSUFFICIENT_RESOURCES; + + return STATUS_SUCCESS; +} + +/** + * Allocates a object. + * + * \param ObjectSize The size of the object. + * \param ObjectType The type of the object. + * + * \return A pointer to the newly allocated object. + */ +_May_raise_ PVOID PhCreateObject( + _In_ SIZE_T ObjectSize, + _In_ PPH_OBJECT_TYPE ObjectType + ) +{ + NTSTATUS status = STATUS_SUCCESS; + PPH_OBJECT_HEADER objectHeader; + + // Allocate storage for the object. Note that this includes the object header followed by the + // object body. + objectHeader = PhpAllocateObject(ObjectType, ObjectSize); + + // Object type statistics. + _InterlockedIncrement((PLONG)&ObjectType->NumberOfObjects); + + // Initialize the object header. + objectHeader->RefCount = 1; + objectHeader->TypeIndex = ObjectType->TypeIndex; + // objectHeader->Flags is set by PhpAllocateObject. + + REF_STAT_UP(RefObjectsCreated); + +#ifdef DEBUG + { + USHORT capturedFrames; + + capturedFrames = RtlCaptureStackBackTrace(1, 16, objectHeader->StackBackTrace, NULL); + memset( + &objectHeader->StackBackTrace[capturedFrames], + 0, + sizeof(objectHeader->StackBackTrace) - capturedFrames * sizeof(PVOID) + ); + } + + PhAcquireQueuedLockExclusive(&PhDbgObjectListLock); + InsertTailList(&PhDbgObjectListHead, &objectHeader->ObjectListEntry); + PhReleaseQueuedLockExclusive(&PhDbgObjectListLock); + + { + PPH_CREATE_OBJECT_HOOK dbgCreateObjectHook; + + dbgCreateObjectHook = PhDbgCreateObjectHook; + + if (dbgCreateObjectHook) + { + dbgCreateObjectHook( + PhObjectHeaderToObject(objectHeader), + ObjectSize, + 0, + ObjectType + ); + } + } +#endif + + return PhObjectHeaderToObject(objectHeader); +} + +/** + * References the specified object. + * + * \param Object A pointer to the object to reference. + * + * \return The object. + */ +PVOID PhReferenceObject( + _In_ PVOID Object + ) +{ + PPH_OBJECT_HEADER objectHeader; + + objectHeader = PhObjectToObjectHeader(Object); + // Increment the reference count. + _InterlockedIncrement(&objectHeader->RefCount); + + return Object; +} + +/** + * References the specified object. + * + * \param Object A pointer to the object to reference. + * \param RefCount The number of references to add. + * + * \return The object. + */ +_May_raise_ PVOID PhReferenceObjectEx( + _In_ PVOID Object, + _In_ LONG RefCount + ) +{ + PPH_OBJECT_HEADER objectHeader; + LONG oldRefCount; + + assert(!(RefCount < 0)); + + objectHeader = PhObjectToObjectHeader(Object); + // Increase the reference count. + oldRefCount = _InterlockedExchangeAdd(&objectHeader->RefCount, RefCount); + + return Object; +} + +/** + * Attempts to reference an object and fails if it is being destroyed. + * + * \param Object The object to reference if it is not being deleted. + * + * \return The object itself if the object was referenced, NULL if it was being deleted and was not + * referenced. + * + * \remarks This function is useful if a reference to an object is held, protected by a mutex, and + * the delete procedure of the object's type attempts to acquire the mutex. If this function is + * called while the mutex is owned, you can avoid referencing an object that is being destroyed. + */ +PVOID PhReferenceObjectSafe( + _In_ PVOID Object + ) +{ + PPH_OBJECT_HEADER objectHeader; + + objectHeader = PhObjectToObjectHeader(Object); + + // Increase the reference count only if it positive already (atomically). + if (PhpInterlockedIncrementSafe(&objectHeader->RefCount)) + return Object; + else + return NULL; +} + +/** + * Dereferences the specified object. + * The object will be freed if its reference count reaches 0. + * + * \param Object A pointer to the object to dereference. + */ +VOID PhDereferenceObject( + _In_ PVOID Object + ) +{ + PPH_OBJECT_HEADER objectHeader; + LONG newRefCount; + + objectHeader = PhObjectToObjectHeader(Object); + // Decrement the reference count. + newRefCount = _InterlockedDecrement(&objectHeader->RefCount); + ASSUME_ASSERT(newRefCount >= 0); + + // Free the object if it has 0 references. + if (newRefCount == 0) + { + PhpFreeObject(objectHeader); + } +} + +/** + * Dereferences the specified object. + * The object will be freed in a worker thread if its reference count reaches 0. + * + * \param Object A pointer to the object to dereference. + */ +VOID PhDereferenceObjectDeferDelete( + _In_ PVOID Object + ) +{ + PhDereferenceObjectEx(Object, 1, TRUE); +} + +/** + * Dereferences the specified object. + * The object will be freed if its reference count reaches 0. + * + * \param Object A pointer to the object to dereference. + * \param RefCount The number of references to remove. + * \param DeferDelete Whether to defer deletion of the object. + */ +_May_raise_ VOID PhDereferenceObjectEx( + _In_ PVOID Object, + _In_ LONG RefCount, + _In_ BOOLEAN DeferDelete + ) +{ + PPH_OBJECT_HEADER objectHeader; + LONG oldRefCount; + LONG newRefCount; + + assert(!(RefCount < 0)); + + objectHeader = PhObjectToObjectHeader(Object); + + // Decrease the reference count. + oldRefCount = _InterlockedExchangeAdd(&objectHeader->RefCount, -RefCount); + newRefCount = oldRefCount - RefCount; + + // Free the object if it has 0 references. + if (newRefCount == 0) + { + if (DeferDelete) + { + PhpDeferDeleteObject(objectHeader); + } + else + { + // Free the object. + PhpFreeObject(objectHeader); + } + } + else if (newRefCount < 0) + { + PhRaiseStatus(STATUS_INVALID_PARAMETER); + } +} + +/** + * Gets an object's type. + * + * \param Object A pointer to an object. + * + * \return A pointer to a type object. + */ +PPH_OBJECT_TYPE PhGetObjectType( + _In_ PVOID Object + ) +{ + return PhObjectTypeTable[PhObjectToObjectHeader(Object)->TypeIndex]; +} + +/** + * Creates an object type. + * + * \param Name The name of the type. + * \param Flags A combination of flags affecting the behaviour of the object type. + * \param DeleteProcedure A callback function that is executed when an object of this type is about + * to be freed (i.e. when its reference count is 0). + * + * \return A pointer to the newly created object type. + * + * \remarks Do not reference or dereference the object type once it is created. + */ +PPH_OBJECT_TYPE PhCreateObjectType( + _In_ PWSTR Name, + _In_ ULONG Flags, + _In_opt_ PPH_TYPE_DELETE_PROCEDURE DeleteProcedure + ) +{ + return PhCreateObjectTypeEx( + Name, + Flags, + DeleteProcedure, + NULL + ); +} + +/** + * Creates an object type. + * + * \param Name The name of the type. + * \param Flags A combination of flags affecting the behaviour of the object type. + * \param DeleteProcedure A callback function that is executed when an object of this type is about + * to be freed (i.e. when its reference count is 0). + * \param Parameters A structure containing additional parameters for the object type. + * + * \return A pointer to the newly created object type. + * + * \remarks Do not reference or dereference the object type once it is created. + */ +PPH_OBJECT_TYPE PhCreateObjectTypeEx( + _In_ PWSTR Name, + _In_ ULONG Flags, + _In_opt_ PPH_TYPE_DELETE_PROCEDURE DeleteProcedure, + _In_opt_ PPH_OBJECT_TYPE_PARAMETERS Parameters + ) +{ + NTSTATUS status = STATUS_SUCCESS; + PPH_OBJECT_TYPE objectType; + + // Check the flags. + if ((Flags & PH_OBJECT_TYPE_VALID_FLAGS) != Flags) /* Valid flag mask */ + PhRaiseStatus(STATUS_INVALID_PARAMETER_3); + if ((Flags & PH_OBJECT_TYPE_USE_FREE_LIST) && !Parameters) + PhRaiseStatus(STATUS_INVALID_PARAMETER_MIX); + + // Create the type object. + objectType = PhCreateObject(sizeof(PH_OBJECT_TYPE), PhObjectTypeObject); + + // Initialize the type object. + objectType->Flags = (USHORT)Flags; + objectType->TypeIndex = (USHORT)_InterlockedIncrement(&PhObjectTypeCount) - 1; + objectType->NumberOfObjects = 0; + objectType->DeleteProcedure = DeleteProcedure; + objectType->Name = Name; + + if (objectType->TypeIndex < PH_OBJECT_TYPE_TABLE_SIZE) + PhObjectTypeTable[objectType->TypeIndex] = objectType; + else + PhRaiseStatus(STATUS_UNSUCCESSFUL); + + if (Parameters) + { + if (Flags & PH_OBJECT_TYPE_USE_FREE_LIST) + { + PhInitializeFreeList( + &objectType->FreeList, + PhAddObjectHeaderSize(Parameters->FreeListSize), + Parameters->FreeListCount + ); + } + } + + return objectType; +} + +/** + * Gets information about an object type. + * + * \param ObjectType A pointer to an object type. + * \param Information A variable which receives information about the object type. + */ +VOID PhGetObjectTypeInformation( + _In_ PPH_OBJECT_TYPE ObjectType, + _Out_ PPH_OBJECT_TYPE_INFORMATION Information + ) +{ + Information->Name = ObjectType->Name; + Information->NumberOfObjects = ObjectType->NumberOfObjects; + Information->Flags = ObjectType->Flags; + Information->TypeIndex = ObjectType->TypeIndex; +} + +/** + * Allocates storage for an object. + * + * \param ObjectType The type of the object. + * \param ObjectSize The size of the object, excluding the header. + */ +PPH_OBJECT_HEADER PhpAllocateObject( + _In_ PPH_OBJECT_TYPE ObjectType, + _In_ SIZE_T ObjectSize + ) +{ + PPH_OBJECT_HEADER objectHeader; + + if (ObjectType->Flags & PH_OBJECT_TYPE_USE_FREE_LIST) + { + assert(ObjectType->FreeList.Size == PhAddObjectHeaderSize(ObjectSize)); + + objectHeader = PhAllocateFromFreeList(&ObjectType->FreeList); + objectHeader->Flags = PH_OBJECT_FROM_TYPE_FREE_LIST; + REF_STAT_UP(RefObjectsAllocatedFromTypeFreeList); + } + else if (ObjectSize <= PH_OBJECT_SMALL_OBJECT_SIZE) + { + objectHeader = PhAllocateFromFreeList(&PhObjectSmallFreeList); + objectHeader->Flags = PH_OBJECT_FROM_SMALL_FREE_LIST; + REF_STAT_UP(RefObjectsAllocatedFromSmallFreeList); + } + else + { + objectHeader = PhAllocate(PhAddObjectHeaderSize(ObjectSize)); + objectHeader->Flags = 0; + REF_STAT_UP(RefObjectsAllocated); + } + + return objectHeader; +} + +/** + * Calls the delete procedure for an object and frees its allocated storage. + * + * \param ObjectHeader A pointer to the object header of an allocated object. + */ +VOID PhpFreeObject( + _In_ PPH_OBJECT_HEADER ObjectHeader + ) +{ + PPH_OBJECT_TYPE objectType; + + objectType = PhObjectTypeTable[ObjectHeader->TypeIndex]; + + // Object type statistics. + _InterlockedDecrement(&objectType->NumberOfObjects); + +#ifdef DEBUG + PhAcquireQueuedLockExclusive(&PhDbgObjectListLock); + RemoveEntryList(&ObjectHeader->ObjectListEntry); + PhReleaseQueuedLockExclusive(&PhDbgObjectListLock); +#endif + + REF_STAT_UP(RefObjectsDestroyed); + + // Call the delete procedure if we have one. + if (objectType->DeleteProcedure) + { + objectType->DeleteProcedure(PhObjectHeaderToObject(ObjectHeader), 0); + } + + if (ObjectHeader->Flags & PH_OBJECT_FROM_TYPE_FREE_LIST) + { + PhFreeToFreeList(&objectType->FreeList, ObjectHeader); + REF_STAT_UP(RefObjectsFreedToTypeFreeList); + } + else if (ObjectHeader->Flags & PH_OBJECT_FROM_SMALL_FREE_LIST) + { + PhFreeToFreeList(&PhObjectSmallFreeList, ObjectHeader); + REF_STAT_UP(RefObjectsFreedToSmallFreeList); + } + else + { + PhFree(ObjectHeader); + REF_STAT_UP(RefObjectsFreed); + } +} + +/** + * Queues an object for deletion. + * + * \param ObjectHeader A pointer to the object header of the object to delete. + */ +VOID PhpDeferDeleteObject( + _In_ PPH_OBJECT_HEADER ObjectHeader + ) +{ + PSLIST_ENTRY oldFirstEntry; + + // Save TypeIndex and Flags since they get overwritten when we push the object onto the defer + // delete list. + ObjectHeader->DeferDelete = 1; + MemoryBarrier(); + ObjectHeader->SavedTypeIndex = ObjectHeader->TypeIndex; + ObjectHeader->SavedFlags = ObjectHeader->Flags; + + oldFirstEntry = RtlFirstEntrySList(&PhObjectDeferDeleteListHead); + RtlInterlockedPushEntrySList(&PhObjectDeferDeleteListHead, &ObjectHeader->DeferDeleteListEntry); + REF_STAT_UP(RefObjectsDeleteDeferred); + + // Was the to-free list empty before? If so, we need to queue a work item. + if (!oldFirstEntry) + { + PhQueueItemWorkQueue(PhGetGlobalWorkQueue(), PhpDeferDeleteObjectRoutine, NULL); + } +} + +/** + * Removes and frees objects from the to-free list. + */ +NTSTATUS PhpDeferDeleteObjectRoutine( + _In_ PVOID Parameter + ) +{ + PSLIST_ENTRY listEntry; + PPH_OBJECT_HEADER objectHeader; + + // Clear the list and obtain the first object to free. + listEntry = RtlInterlockedFlushSList(&PhObjectDeferDeleteListHead); + + while (listEntry) + { + objectHeader = CONTAINING_RECORD(listEntry, PH_OBJECT_HEADER, DeferDeleteListEntry); + listEntry = listEntry->Next; + + // Restore TypeIndex and Flags. + objectHeader->TypeIndex = (USHORT)objectHeader->SavedTypeIndex; + objectHeader->Flags = (UCHAR)objectHeader->SavedFlags; + + PhpFreeObject(objectHeader); + } + + return STATUS_SUCCESS; +} + +/** + * Creates a reference-counted memory block. + * + * \param Size The number of bytes to allocate. + * + * \return A pointer to the memory block. + */ +PVOID PhCreateAlloc( + _In_ SIZE_T Size + ) +{ + return PhCreateObject(Size, PhAllocType); +} + +/** + * Gets the current auto-dereference pool for the current thread. + */ +FORCEINLINE PPH_AUTO_POOL PhpGetCurrentAutoPool( + VOID + ) +{ + return (PPH_AUTO_POOL)TlsGetValue(PhpAutoPoolTlsIndex); +} + +/** + * Sets the current auto-dereference pool for the current thread. + */ +_May_raise_ FORCEINLINE VOID PhpSetCurrentAutoPool( + _In_ PPH_AUTO_POOL AutoPool + ) +{ + if (!TlsSetValue(PhpAutoPoolTlsIndex, AutoPool)) + PhRaiseStatus(STATUS_UNSUCCESSFUL); + +#ifdef DEBUG + { + PPHP_BASE_THREAD_DBG dbg; + + dbg = (PPHP_BASE_THREAD_DBG)TlsGetValue(PhDbgThreadDbgTlsIndex); + + if (dbg) + { + dbg->CurrentAutoPool = AutoPool; + } + } +#endif +} + +/** + * Initializes an auto-dereference pool and sets it as the current pool for the current thread. You + * must call PhDeleteAutoPool() before storage for the auto-dereference pool is freed. + * + * \remarks Always store auto-dereference pools in local variables, and do not share the pool with + * any other functions. + */ +VOID PhInitializeAutoPool( + _Out_ PPH_AUTO_POOL AutoPool + ) +{ + AutoPool->StaticCount = 0; + AutoPool->DynamicCount = 0; + AutoPool->DynamicAllocated = 0; + AutoPool->DynamicObjects = NULL; + + // Add the pool to the stack. + AutoPool->NextPool = PhpGetCurrentAutoPool(); + PhpSetCurrentAutoPool(AutoPool); + + REF_STAT_UP(RefAutoPoolsCreated); +} + +/** + * Deletes an auto-dereference pool. The function will dereference any objects currently in the + * pool. If a pool other than the current pool is passed to the function, an exception is raised. + * + * \param AutoPool The auto-dereference pool to delete. + */ +_May_raise_ VOID PhDeleteAutoPool( + _Inout_ PPH_AUTO_POOL AutoPool + ) +{ + PhDrainAutoPool(AutoPool); + + if (PhpGetCurrentAutoPool() != AutoPool) + PhRaiseStatus(STATUS_UNSUCCESSFUL); + + // Remove the pool from the stack. + PhpSetCurrentAutoPool(AutoPool->NextPool); + + // Free the dynamic array if it hasn't been freed yet. + if (AutoPool->DynamicObjects) + PhFree(AutoPool->DynamicObjects); + + REF_STAT_UP(RefAutoPoolsDestroyed); +} + +/** + * Dereferences and removes all objects in an auto-release pool. + * + * \param AutoPool The auto-release pool to drain. + */ +VOID PhDrainAutoPool( + _In_ PPH_AUTO_POOL AutoPool + ) +{ + ULONG i; + + for (i = 0; i < AutoPool->StaticCount; i++) + PhDereferenceObject(AutoPool->StaticObjects[i]); + + AutoPool->StaticCount = 0; + + if (AutoPool->DynamicObjects) + { + for (i = 0; i < AutoPool->DynamicCount; i++) + { + PhDereferenceObject(AutoPool->DynamicObjects[i]); + } + + AutoPool->DynamicCount = 0; + + if (AutoPool->DynamicAllocated > PH_AUTO_POOL_DYNAMIC_BIG_SIZE) + { + AutoPool->DynamicAllocated = 0; + PhFree(AutoPool->DynamicObjects); + AutoPool->DynamicObjects = NULL; + } + } +} + +/** + * Adds an object to the current auto-dereference pool for the current thread. If the current thread + * does not have an auto-dereference pool, the function raises an exception. + * + * \param Object A pointer to an object. The object will be dereferenced when the current + * auto-dereference pool is drained or freed. + */ +_May_raise_ PVOID PhAutoDereferenceObject( + _In_opt_ PVOID Object + ) +{ + PPH_AUTO_POOL autoPool = PhpGetCurrentAutoPool(); + +#ifdef DEBUG + // If we don't have an auto-dereference pool, we don't want to leak the object (unlike what + // Apple does with NSAutoreleasePool). + if (!autoPool) + PhRaiseStatus(STATUS_UNSUCCESSFUL); +#endif + + if (!Object) + return NULL; + + // See if we can use the static array. + if (autoPool->StaticCount < PH_AUTO_POOL_STATIC_SIZE) + { + autoPool->StaticObjects[autoPool->StaticCount++] = Object; + return Object; + } + + // Use the dynamic array. + + // Allocate the array if we haven't already. + if (!autoPool->DynamicObjects) + { + autoPool->DynamicAllocated = 64; + autoPool->DynamicObjects = PhAllocate( + sizeof(PVOID) * autoPool->DynamicAllocated + ); + REF_STAT_UP(RefAutoPoolsDynamicAllocated); + } + + // See if we need to resize the array. + if (autoPool->DynamicCount == autoPool->DynamicAllocated) + { + autoPool->DynamicAllocated *= 2; + autoPool->DynamicObjects = PhReAllocate( + autoPool->DynamicObjects, + sizeof(PVOID) * autoPool->DynamicAllocated + ); + REF_STAT_UP(RefAutoPoolsDynamicResized); + } + + autoPool->DynamicObjects[autoPool->DynamicCount++] = Object; + + return Object; +} diff --git a/phlib/secdata.c b/phlib/secdata.c index 43b9e2c72b82..fe08d207ac82 100644 --- a/phlib/secdata.c +++ b/phlib/secdata.c @@ -1,788 +1,788 @@ -/* - * Process Hacker - - * object security data - * - * Copyright (C) 2010-2016 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include -#include - -#include - -#include - -#define ACCESS_ENTRIES(Type) static PH_ACCESS_ENTRY Ph##Type##AccessEntries[] = -#define ACCESS_ENTRY(Type, HasSynchronize) \ - { L#Type, Ph##Type##AccessEntries, sizeof(Ph##Type##AccessEntries), HasSynchronize } - -typedef struct _PH_SPECIFIC_TYPE -{ - PWSTR Type; - PPH_ACCESS_ENTRY AccessEntries; - ULONG SizeOfAccessEntries; - BOOLEAN HasSynchronize; -} PH_SPECIFIC_TYPE, *PPH_SPECIFIC_TYPE; - -ACCESS_ENTRIES(Standard) -{ - { L"Synchronize", SYNCHRONIZE, FALSE, TRUE }, - { L"Delete", DELETE, FALSE, TRUE }, - { L"Read permissions", READ_CONTROL, FALSE, TRUE, L"Read control" }, - { L"Change permissions", WRITE_DAC, FALSE, TRUE, L"Write DAC" }, - { L"Take ownership", WRITE_OWNER, FALSE, TRUE, L"Write owner" } -}; - -ACCESS_ENTRIES(AlpcPort) -{ - { L"Full control", PORT_ALL_ACCESS, TRUE, TRUE }, - { L"Connect", PORT_CONNECT, TRUE, TRUE } -}; - -ACCESS_ENTRIES(DebugObject) -{ - { L"Full control", DEBUG_ALL_ACCESS, TRUE, TRUE }, - { L"Read events", DEBUG_READ_EVENT, TRUE, TRUE }, - { L"Assign processes", DEBUG_PROCESS_ASSIGN, TRUE, TRUE }, - { L"Query information", DEBUG_QUERY_INFORMATION, TRUE, TRUE }, - { L"Set information", DEBUG_SET_INFORMATION, TRUE, TRUE } -}; - -ACCESS_ENTRIES(Desktop) -{ - { L"Full control", DESKTOP_ALL_ACCESS, TRUE, TRUE }, - { L"Read", DESKTOP_GENERIC_READ, TRUE, FALSE }, - { L"Write", DESKTOP_GENERIC_WRITE, TRUE, FALSE }, - { L"Execute", DESKTOP_GENERIC_EXECUTE, TRUE, FALSE }, - { L"Enumerate", DESKTOP_ENUMERATE, FALSE, TRUE }, - { L"Read objects", DESKTOP_READOBJECTS, FALSE, TRUE }, - { L"Playback journals", DESKTOP_JOURNALPLAYBACK, FALSE, TRUE }, - { L"Write objects", DESKTOP_WRITEOBJECTS, FALSE, TRUE }, - { L"Create windows", DESKTOP_CREATEWINDOW, FALSE, TRUE }, - { L"Create menus", DESKTOP_CREATEMENU, FALSE, TRUE }, - { L"Create window hooks", DESKTOP_HOOKCONTROL, FALSE, TRUE }, - { L"Record journals", DESKTOP_JOURNALRECORD, FALSE, TRUE }, - { L"Switch desktop", DESKTOP_SWITCHDESKTOP, FALSE, TRUE } -}; - -ACCESS_ENTRIES(Directory) -{ - { L"Full control", DIRECTORY_ALL_ACCESS, TRUE, TRUE }, - { L"Query", DIRECTORY_QUERY, TRUE, TRUE}, - { L"Traverse", DIRECTORY_TRAVERSE, TRUE, TRUE}, - { L"Create objects", DIRECTORY_CREATE_OBJECT, TRUE, TRUE}, - { L"Create subdirectories", DIRECTORY_CREATE_SUBDIRECTORY, TRUE, TRUE} -}; - -ACCESS_ENTRIES(Event) -{ - { L"Full control", EVENT_ALL_ACCESS, TRUE, TRUE }, - { L"Query", EVENT_QUERY_STATE, TRUE, TRUE }, - { L"Modify", EVENT_MODIFY_STATE, TRUE, TRUE } -}; - -ACCESS_ENTRIES(EventPair) -{ - { L"Full control", EVENT_PAIR_ALL_ACCESS, TRUE, TRUE } -}; - -ACCESS_ENTRIES(File) -{ - { L"Full control", FILE_ALL_ACCESS, TRUE, TRUE }, - { L"Read & execute", FILE_GENERIC_READ | FILE_GENERIC_EXECUTE, TRUE, FALSE }, - { L"Read", FILE_GENERIC_READ, TRUE, FALSE }, - { L"Write", FILE_GENERIC_WRITE, TRUE, FALSE }, - { L"Traverse folder / execute file", FILE_EXECUTE, FALSE, TRUE, L"Execute" }, - { L"List folder / read data", FILE_READ_DATA, FALSE, TRUE, L"Read data" }, - { L"Read attributes", FILE_READ_ATTRIBUTES, FALSE, TRUE }, - { L"Read extended attributes", FILE_READ_EA, FALSE, TRUE, L"Read EA" }, - { L"Create files / write data", FILE_WRITE_DATA, FALSE, TRUE, L"Write data" }, - { L"Create folders / append data", FILE_APPEND_DATA, FALSE, TRUE, L"Append data" }, - { L"Write attributes", FILE_WRITE_ATTRIBUTES, FALSE, TRUE }, - { L"Write extended attributes", FILE_WRITE_EA, FALSE, TRUE, L"Write EA" }, - { L"Delete subfolders and files", FILE_DELETE_CHILD, FALSE, TRUE, L"Delete child" } -}; - -ACCESS_ENTRIES(FilterConnectionPort) -{ - { L"Full control", FLT_PORT_ALL_ACCESS, TRUE, TRUE }, - { L"Connect", FLT_PORT_CONNECT, TRUE, TRUE } -}; - -ACCESS_ENTRIES(IoCompletion) -{ - { L"Full control", IO_COMPLETION_ALL_ACCESS, TRUE, TRUE }, - { L"Query", IO_COMPLETION_QUERY_STATE, TRUE, TRUE }, - { L"Modify", IO_COMPLETION_MODIFY_STATE, TRUE, TRUE } -}; - -ACCESS_ENTRIES(Job) -{ - { L"Full control", JOB_OBJECT_ALL_ACCESS, TRUE, TRUE }, - { L"Query", JOB_OBJECT_QUERY, TRUE, TRUE }, - { L"Assign processes", JOB_OBJECT_ASSIGN_PROCESS, TRUE, TRUE }, - { L"Set attributes", JOB_OBJECT_SET_ATTRIBUTES, TRUE, TRUE }, - { L"Set security attributes", JOB_OBJECT_SET_SECURITY_ATTRIBUTES, TRUE, TRUE }, - { L"Terminate", JOB_OBJECT_TERMINATE, TRUE, TRUE } -}; - -ACCESS_ENTRIES(Key) -{ - { L"Full control", KEY_ALL_ACCESS, TRUE, TRUE }, - { L"Read", KEY_READ, TRUE, FALSE }, - { L"Write", KEY_WRITE, TRUE, FALSE }, - { L"Execute", KEY_EXECUTE, TRUE, FALSE }, - { L"Enumerate subkeys", KEY_ENUMERATE_SUB_KEYS, FALSE, TRUE }, - { L"Query values", KEY_QUERY_VALUE, FALSE, TRUE }, - { L"Notify", KEY_NOTIFY, FALSE, TRUE }, - { L"Set values", KEY_SET_VALUE, FALSE, TRUE }, - { L"Create subkeys", KEY_CREATE_SUB_KEY, FALSE, TRUE }, - { L"Create links", KEY_CREATE_LINK, FALSE, TRUE } -}; - -ACCESS_ENTRIES(KeyedEvent) -{ - { L"Full control", KEYEDEVENT_ALL_ACCESS, TRUE, TRUE }, - { L"Wait", KEYEDEVENT_WAIT, TRUE, TRUE }, - { L"Wake", KEYEDEVENT_WAKE, TRUE, TRUE } -}; - -ACCESS_ENTRIES(LsaAccount) -{ - { L"Full control", ACCOUNT_ALL_ACCESS, TRUE, TRUE }, - { L"Read", ACCOUNT_READ, TRUE, FALSE }, - { L"Write", ACCOUNT_WRITE, TRUE, FALSE }, - { L"Execute", ACCOUNT_EXECUTE, TRUE, FALSE }, - { L"View", ACCOUNT_VIEW, FALSE, TRUE }, - { L"Adjust privileges", ACCOUNT_ADJUST_PRIVILEGES, FALSE, TRUE }, - { L"Adjust quotas", ACCOUNT_ADJUST_QUOTAS, FALSE, TRUE }, - { L"Adjust system access", ACCOUNT_ADJUST_SYSTEM_ACCESS, FALSE, TRUE } -}; - -ACCESS_ENTRIES(LsaPolicy) -{ - { L"Full control", POLICY_ALL_ACCESS | POLICY_NOTIFICATION, TRUE, TRUE }, - { L"Read", POLICY_READ, TRUE, FALSE }, - { L"Write", POLICY_WRITE, TRUE, FALSE }, - { L"Execute", POLICY_EXECUTE | POLICY_NOTIFICATION, TRUE, FALSE }, - { L"View local information", POLICY_VIEW_LOCAL_INFORMATION, FALSE, TRUE }, - { L"View audit information", POLICY_VIEW_AUDIT_INFORMATION, FALSE, TRUE }, - { L"Get private information", POLICY_GET_PRIVATE_INFORMATION, FALSE, TRUE }, - { L"Administer trust", POLICY_TRUST_ADMIN, FALSE, TRUE }, - { L"Create account", POLICY_CREATE_ACCOUNT, FALSE, TRUE }, - { L"Create secret", POLICY_CREATE_SECRET, FALSE, TRUE }, - { L"Create privilege", POLICY_CREATE_PRIVILEGE, FALSE, TRUE }, - { L"Set default quota limits", POLICY_SET_DEFAULT_QUOTA_LIMITS, FALSE, TRUE }, - { L"Set audit requirements", POLICY_SET_AUDIT_REQUIREMENTS, FALSE, TRUE }, - { L"Administer audit log", POLICY_AUDIT_LOG_ADMIN, FALSE, TRUE }, - { L"Administer server", POLICY_SERVER_ADMIN, FALSE, TRUE }, - { L"Lookup names", POLICY_LOOKUP_NAMES, FALSE, TRUE }, - { L"Get notifications", POLICY_NOTIFICATION, FALSE, TRUE } -}; - -ACCESS_ENTRIES(LsaSecret) -{ - { L"Full control", SECRET_ALL_ACCESS, TRUE, TRUE }, - { L"Read", SECRET_READ, TRUE, FALSE }, - { L"Write", SECRET_WRITE, TRUE, FALSE }, - { L"Execute", SECRET_EXECUTE, TRUE, FALSE }, - { L"Set value", SECRET_SET_VALUE, FALSE, TRUE }, - { L"Query value", SECRET_QUERY_VALUE, FALSE, TRUE } -}; - -ACCESS_ENTRIES(LsaTrusted) -{ - { L"Full control", TRUSTED_ALL_ACCESS, TRUE, TRUE }, - { L"Read", TRUSTED_READ, TRUE, FALSE }, - { L"Write", TRUSTED_WRITE, TRUE, FALSE }, - { L"Execute", TRUSTED_EXECUTE, TRUE, FALSE }, - { L"Query domain name", TRUSTED_QUERY_DOMAIN_NAME, FALSE, TRUE }, - { L"Query controllers", TRUSTED_QUERY_CONTROLLERS, FALSE, TRUE }, - { L"Set controllers", TRUSTED_SET_CONTROLLERS, FALSE, TRUE }, - { L"Query POSIX", TRUSTED_QUERY_POSIX, FALSE, TRUE }, - { L"Set POSIX", TRUSTED_SET_POSIX, FALSE, TRUE }, - { L"Query authentication", TRUSTED_QUERY_AUTH, FALSE, TRUE }, - { L"Set authentication", TRUSTED_SET_AUTH, FALSE, TRUE } -}; - -ACCESS_ENTRIES(Mutant) -{ - { L"Full control", MUTANT_ALL_ACCESS, TRUE, TRUE }, - { L"Query", MUTANT_QUERY_STATE, TRUE, TRUE } -}; - -ACCESS_ENTRIES(Partition) -{ - { L"Full control", MEMORY_PARTITION_ALL_ACCESS, TRUE, TRUE }, - { L"Query", MEMORY_PARTITION_QUERY_ACCESS, TRUE, TRUE }, - { L"Modify", MEMORY_PARTITION_MODIFY_ACCESS, TRUE, TRUE } -}; - -ACCESS_ENTRIES(Process) -{ - { L"Full control", STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xfff, TRUE, TRUE }, - { L"Query information", PROCESS_QUERY_INFORMATION, TRUE, TRUE }, - { L"Set information", PROCESS_SET_INFORMATION, TRUE, TRUE }, - { L"Set quotas", PROCESS_SET_QUOTA, TRUE, TRUE }, - { L"Set session ID", PROCESS_SET_SESSIONID, TRUE, TRUE }, - { L"Create threads", PROCESS_CREATE_THREAD, TRUE, TRUE }, - { L"Create processes", PROCESS_CREATE_PROCESS, TRUE, TRUE }, - { L"Modify memory", PROCESS_VM_OPERATION, TRUE, TRUE, L"VM operation" }, - { L"Read memory", PROCESS_VM_READ, TRUE, TRUE, L"VM read" }, - { L"Write memory", PROCESS_VM_WRITE, TRUE, TRUE, L"VM write" }, - { L"Duplicate handles", PROCESS_DUP_HANDLE, TRUE, TRUE }, - { L"Suspend / resume / set port", PROCESS_SUSPEND_RESUME, TRUE, TRUE, L"Suspend/resume" }, - { L"Terminate", PROCESS_TERMINATE, TRUE, TRUE } -}; - -ACCESS_ENTRIES(Process60) -{ - { L"Full control", STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xffff, TRUE, TRUE }, // PROCESS_ALL_ACCESS - { L"Query limited information", PROCESS_QUERY_LIMITED_INFORMATION, TRUE, TRUE }, - { L"Query information", PROCESS_QUERY_INFORMATION | PROCESS_QUERY_LIMITED_INFORMATION, TRUE, TRUE }, - { L"Set information", PROCESS_SET_INFORMATION, TRUE, TRUE }, - { L"Set quotas", PROCESS_SET_QUOTA, TRUE, TRUE }, - { L"Set session ID", PROCESS_SET_SESSIONID, TRUE, TRUE }, - { L"Create threads", PROCESS_CREATE_THREAD, TRUE, TRUE }, - { L"Create processes", PROCESS_CREATE_PROCESS, TRUE, TRUE }, - { L"Modify memory", PROCESS_VM_OPERATION, TRUE, TRUE, L"VM operation" }, - { L"Read memory", PROCESS_VM_READ, TRUE, TRUE, L"VM read" }, - { L"Write memory", PROCESS_VM_WRITE, TRUE, TRUE, L"VM write" }, - { L"Duplicate handles", PROCESS_DUP_HANDLE, TRUE, TRUE }, - { L"Suspend / resume / set port", PROCESS_SUSPEND_RESUME, TRUE, TRUE, L"Suspend/resume" }, - { L"Terminate", PROCESS_TERMINATE, TRUE, TRUE } -}; - -ACCESS_ENTRIES(Profile) -{ - { L"Full control", PROFILE_ALL_ACCESS, TRUE, TRUE }, - { L"Control", PROFILE_CONTROL, TRUE, TRUE } -}; - -ACCESS_ENTRIES(SamAlias) -{ - { L"Full control", ALIAS_ALL_ACCESS, TRUE, TRUE }, - { L"Read", ALIAS_READ, TRUE, FALSE }, - { L"Write", ALIAS_WRITE, TRUE, FALSE }, - { L"Execute", ALIAS_EXECUTE, TRUE, FALSE }, - { L"Read information", ALIAS_READ_INFORMATION, FALSE, TRUE }, - { L"Write account", ALIAS_WRITE_ACCOUNT, FALSE, TRUE }, - { L"Add member", ALIAS_ADD_MEMBER, FALSE, TRUE }, - { L"Remove member", ALIAS_REMOVE_MEMBER, FALSE, TRUE }, - { L"List members", ALIAS_LIST_MEMBERS, FALSE, TRUE } -}; - -ACCESS_ENTRIES(SamDomain) -{ - { L"Full control", DOMAIN_ALL_ACCESS, TRUE, TRUE }, - { L"Read", DOMAIN_READ, TRUE, FALSE }, - { L"Write", DOMAIN_WRITE, TRUE, FALSE }, - { L"Execute", DOMAIN_EXECUTE, TRUE, FALSE }, - { L"Read password parameters", DOMAIN_READ_PASSWORD_PARAMETERS, FALSE, TRUE }, - { L"Write password parameters", DOMAIN_WRITE_PASSWORD_PARAMS, FALSE, TRUE }, - { L"Read other parameters", DOMAIN_READ_OTHER_PARAMETERS, FALSE, TRUE }, - { L"Write other parameters", DOMAIN_WRITE_OTHER_PARAMETERS, FALSE, TRUE }, - { L"Create user", DOMAIN_CREATE_USER, FALSE, TRUE }, - { L"Create group", DOMAIN_CREATE_GROUP, FALSE, TRUE }, - { L"Create alias", DOMAIN_CREATE_ALIAS, FALSE, TRUE }, - { L"Get alias membership", DOMAIN_GET_ALIAS_MEMBERSHIP, FALSE, TRUE }, - { L"List accounts", DOMAIN_LIST_ACCOUNTS, FALSE, TRUE }, - { L"Lookup", DOMAIN_LOOKUP, FALSE, TRUE }, - { L"Administer server", DOMAIN_ADMINISTER_SERVER, FALSE, TRUE } -}; - -ACCESS_ENTRIES(SamGroup) -{ - { L"Full control", GROUP_ALL_ACCESS, TRUE, TRUE }, - { L"Read", GROUP_READ, TRUE, FALSE }, - { L"Write", GROUP_WRITE, TRUE, FALSE }, - { L"Execute", GROUP_EXECUTE, TRUE, FALSE }, - { L"Read information", GROUP_READ_INFORMATION, FALSE, TRUE }, - { L"Write account", GROUP_WRITE_ACCOUNT, FALSE, TRUE }, - { L"Add member", GROUP_ADD_MEMBER, FALSE, TRUE }, - { L"Remove member", GROUP_REMOVE_MEMBER, FALSE, TRUE }, - { L"List members", GROUP_LIST_MEMBERS, FALSE, TRUE } -}; - -ACCESS_ENTRIES(SamServer) -{ - { L"Full control", SAM_SERVER_ALL_ACCESS, TRUE, TRUE }, - { L"Read", SAM_SERVER_READ, TRUE, FALSE }, - { L"Write", SAM_SERVER_WRITE, TRUE, FALSE }, - { L"Execute", SAM_SERVER_EXECUTE, TRUE, FALSE }, - { L"Connect", SAM_SERVER_CONNECT, FALSE, TRUE }, - { L"Shutdown", SAM_SERVER_SHUTDOWN, FALSE, TRUE }, - { L"Initialize", SAM_SERVER_INITIALIZE, FALSE, TRUE }, - { L"Create domain", SAM_SERVER_CREATE_DOMAIN, FALSE, TRUE }, - { L"Enumerate domains", SAM_SERVER_ENUMERATE_DOMAINS, FALSE, TRUE }, - { L"Lookup domain", SAM_SERVER_LOOKUP_DOMAIN, FALSE, TRUE } -}; - -ACCESS_ENTRIES(SamUser) -{ - { L"Full control", USER_ALL_ACCESS, TRUE, TRUE }, - { L"Read", USER_READ, TRUE, FALSE }, - { L"Write", USER_WRITE, TRUE, FALSE }, - { L"Execute", USER_EXECUTE, TRUE, FALSE }, - { L"Read general", USER_READ_GENERAL, FALSE, TRUE }, - { L"Read preferences", USER_READ_PREFERENCES, FALSE, TRUE }, - { L"Write preferences", USER_WRITE_PREFERENCES, FALSE, TRUE }, - { L"Read logon", USER_READ_LOGON, FALSE, TRUE }, - { L"Read account", USER_READ_ACCOUNT, FALSE, TRUE }, - { L"Write account", USER_WRITE_ACCOUNT, FALSE, TRUE }, - { L"Change password", USER_CHANGE_PASSWORD, FALSE, TRUE }, - { L"Force password change", USER_FORCE_PASSWORD_CHANGE, FALSE, TRUE }, - { L"List groups", USER_LIST_GROUPS, FALSE, TRUE }, - { L"Read group information", USER_READ_GROUP_INFORMATION, FALSE, TRUE }, - { L"Write group information", USER_WRITE_GROUP_INFORMATION, FALSE, TRUE } -}; - -ACCESS_ENTRIES(Section) -{ - { L"Full control", SECTION_ALL_ACCESS, TRUE, TRUE }, - { L"Query", SECTION_QUERY, TRUE, TRUE }, - { L"Map for read", SECTION_MAP_READ, TRUE, TRUE, L"Map read" }, - { L"Map for write", SECTION_MAP_WRITE, TRUE, TRUE, L"Map write" }, - { L"Map for execute", SECTION_MAP_EXECUTE, TRUE, TRUE, L"Map execute" }, - { L"Map for execute (explicit)", SECTION_MAP_EXECUTE_EXPLICIT, TRUE, TRUE, L"Map execute explicit" }, - { L"Extend size", SECTION_EXTEND_SIZE, TRUE, TRUE } -}; - -ACCESS_ENTRIES(Semaphore) -{ - { L"Full control", SEMAPHORE_ALL_ACCESS, TRUE, TRUE }, - { L"Query", SEMAPHORE_QUERY_STATE, TRUE, TRUE }, - { L"Modify", SEMAPHORE_MODIFY_STATE, TRUE, TRUE } -}; - -ACCESS_ENTRIES(Service) -{ - { L"Full control", SERVICE_ALL_ACCESS, TRUE, TRUE }, - { L"Query status", SERVICE_QUERY_STATUS, TRUE, TRUE }, - { L"Query configuration", SERVICE_QUERY_CONFIG, TRUE, TRUE }, - { L"Modify configuration", SERVICE_CHANGE_CONFIG, TRUE, TRUE }, - { L"Enumerate dependents", SERVICE_ENUMERATE_DEPENDENTS, TRUE, TRUE }, - { L"Start", SERVICE_START, TRUE, TRUE }, - { L"Stop", SERVICE_STOP, TRUE, TRUE }, - { L"Pause / continue", SERVICE_PAUSE_CONTINUE, TRUE, TRUE, L"Pause/continue" }, - { L"Interrogate", SERVICE_INTERROGATE, TRUE, TRUE }, - { L"User-defined control", SERVICE_USER_DEFINED_CONTROL, TRUE, TRUE } -}; - -ACCESS_ENTRIES(Session) -{ - { L"Full control", SESSION_ALL_ACCESS, TRUE, TRUE }, - { L"Query", SESSION_QUERY_ACCESS, TRUE, TRUE }, - { L"Modify", SESSION_MODIFY_ACCESS, TRUE, TRUE } -}; - -ACCESS_ENTRIES(SymbolicLink) -{ - { L"Full control", SYMBOLIC_LINK_ALL_ACCESS, TRUE, TRUE }, - { L"Query", SYMBOLIC_LINK_QUERY, TRUE, TRUE } -}; - -ACCESS_ENTRIES(Thread) -{ - { L"Full control", STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x3ff, TRUE, TRUE }, - { L"Query information", THREAD_QUERY_INFORMATION, TRUE, TRUE }, - { L"Set information", THREAD_SET_INFORMATION, TRUE, TRUE }, - { L"Get context", THREAD_GET_CONTEXT, TRUE, TRUE }, - { L"Set context", THREAD_SET_CONTEXT, TRUE, TRUE }, - { L"Set token", THREAD_SET_THREAD_TOKEN, TRUE, TRUE }, - { L"Alert", THREAD_ALERT, TRUE, TRUE }, - { L"Impersonate", THREAD_IMPERSONATE, TRUE, TRUE }, - { L"Direct impersonate", THREAD_DIRECT_IMPERSONATION, TRUE, TRUE }, - { L"Suspend / resume", THREAD_SUSPEND_RESUME, TRUE, TRUE, L"Suspend/resume" }, - { L"Terminate", THREAD_TERMINATE, TRUE, TRUE }, -}; - -ACCESS_ENTRIES(Thread60) -{ - { L"Full control", STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xffff, TRUE, TRUE }, // THREAD_ALL_ACCESS - { L"Query limited information", THREAD_QUERY_LIMITED_INFORMATION, TRUE, TRUE }, - { L"Query information", THREAD_QUERY_INFORMATION | THREAD_QUERY_LIMITED_INFORMATION, TRUE, TRUE }, - { L"Set limited information", THREAD_SET_LIMITED_INFORMATION, TRUE, TRUE }, - { L"Set information", THREAD_SET_INFORMATION | THREAD_SET_LIMITED_INFORMATION, TRUE, TRUE }, - { L"Get context", THREAD_GET_CONTEXT, TRUE, TRUE }, - { L"Set context", THREAD_SET_CONTEXT, TRUE, TRUE }, - { L"Set token", THREAD_SET_THREAD_TOKEN, TRUE, TRUE }, - { L"Alert", THREAD_ALERT, TRUE, TRUE }, - { L"Impersonate", THREAD_IMPERSONATE, TRUE, TRUE }, - { L"Direct impersonate", THREAD_DIRECT_IMPERSONATION, TRUE, TRUE }, - { L"Suspend / resume", THREAD_SUSPEND_RESUME, TRUE, TRUE, L"Suspend/resume" }, - { L"Terminate", THREAD_TERMINATE, TRUE, TRUE }, -}; - -ACCESS_ENTRIES(Timer) -{ - { L"Full control", TIMER_ALL_ACCESS, TRUE, TRUE }, - { L"Query", TIMER_QUERY_STATE, TRUE, TRUE }, - { L"Modify", TIMER_MODIFY_STATE, TRUE, TRUE } -}; - -ACCESS_ENTRIES(TmEn) -{ - { L"Full control", ENLISTMENT_ALL_ACCESS, TRUE, TRUE }, - { L"Read", ENLISTMENT_GENERIC_READ, TRUE, FALSE }, - { L"Write", ENLISTMENT_GENERIC_WRITE, TRUE, FALSE }, - { L"Execute", ENLISTMENT_GENERIC_EXECUTE, TRUE, FALSE }, - { L"Query information", ENLISTMENT_QUERY_INFORMATION, FALSE, TRUE }, - { L"Set information", ENLISTMENT_SET_INFORMATION, FALSE, TRUE }, - { L"Recover", ENLISTMENT_RECOVER, FALSE, TRUE }, - { L"Subordinate rights", ENLISTMENT_SUBORDINATE_RIGHTS, FALSE, TRUE }, - { L"Superior rights", ENLISTMENT_SUPERIOR_RIGHTS, FALSE, TRUE } -}; - -ACCESS_ENTRIES(TmRm) -{ - { L"Full control", RESOURCEMANAGER_ALL_ACCESS, TRUE, TRUE }, - { L"Read", RESOURCEMANAGER_GENERIC_READ, TRUE, FALSE }, - { L"Write", RESOURCEMANAGER_GENERIC_WRITE, TRUE, FALSE }, - { L"Execute", RESOURCEMANAGER_GENERIC_EXECUTE, TRUE, FALSE }, - { L"Query information", RESOURCEMANAGER_QUERY_INFORMATION, FALSE, TRUE }, - { L"Set information", RESOURCEMANAGER_SET_INFORMATION, FALSE, TRUE }, - { L"Get notifications", RESOURCEMANAGER_GET_NOTIFICATION, FALSE, TRUE }, - { L"Enlist", RESOURCEMANAGER_ENLIST, FALSE, TRUE }, - { L"Recover", RESOURCEMANAGER_RECOVER, FALSE, TRUE }, - { L"Register protocols", RESOURCEMANAGER_REGISTER_PROTOCOL, FALSE, TRUE }, - { L"Complete propagation", RESOURCEMANAGER_COMPLETE_PROPAGATION, FALSE, TRUE } -}; - -ACCESS_ENTRIES(TmTm) -{ - { L"Full control", TRANSACTIONMANAGER_ALL_ACCESS, TRUE, TRUE }, - { L"Read", TRANSACTIONMANAGER_GENERIC_READ, TRUE, FALSE }, - { L"Write", TRANSACTIONMANAGER_GENERIC_WRITE, TRUE, FALSE }, - { L"Execute", TRANSACTIONMANAGER_GENERIC_EXECUTE, TRUE, FALSE }, - { L"Query information", TRANSACTIONMANAGER_QUERY_INFORMATION, FALSE, TRUE }, - { L"Set information", TRANSACTIONMANAGER_SET_INFORMATION, FALSE, TRUE }, - { L"Recover", TRANSACTIONMANAGER_RECOVER, FALSE, TRUE }, - { L"Rename", TRANSACTIONMANAGER_RENAME, FALSE, TRUE }, - { L"Create resource manager", TRANSACTIONMANAGER_CREATE_RM, FALSE, TRUE }, - { L"Bind transactions", TRANSACTIONMANAGER_BIND_TRANSACTION, FALSE, TRUE } -}; - -ACCESS_ENTRIES(TmTx) -{ - { L"Full control", TRANSACTION_ALL_ACCESS, TRUE, TRUE }, - { L"Read", TRANSACTION_GENERIC_READ, TRUE, FALSE }, - { L"Write", TRANSACTION_GENERIC_WRITE, TRUE, FALSE }, - { L"Execute", TRANSACTION_GENERIC_EXECUTE, TRUE, FALSE }, - { L"Query information", TRANSACTION_QUERY_INFORMATION, FALSE, TRUE }, - { L"Set information", TRANSACTION_SET_INFORMATION, FALSE, TRUE }, - { L"Enlist", TRANSACTION_ENLIST, FALSE, TRUE }, - { L"Commit", TRANSACTION_COMMIT, FALSE, TRUE }, - { L"Rollback", TRANSACTION_ROLLBACK, FALSE, TRUE }, - { L"Propagate", TRANSACTION_PROPAGATE, FALSE, TRUE } -}; - -ACCESS_ENTRIES(Token) -{ - { L"Full control", TOKEN_ALL_ACCESS, TRUE, TRUE }, - { L"Read", TOKEN_READ, TRUE, FALSE }, - { L"Write", TOKEN_WRITE, TRUE, FALSE }, - { L"Execute", TOKEN_EXECUTE, TRUE, FALSE }, - { L"Adjust privileges", TOKEN_ADJUST_PRIVILEGES, FALSE, TRUE }, - { L"Adjust groups", TOKEN_ADJUST_GROUPS, FALSE, TRUE }, - { L"Adjust defaults", TOKEN_ADJUST_DEFAULT, FALSE, TRUE }, - { L"Adjust session ID", TOKEN_ADJUST_SESSIONID, FALSE, TRUE }, - { L"Assign as primary token", TOKEN_ASSIGN_PRIMARY, FALSE, TRUE, L"Assign primary" }, - { L"Duplicate", TOKEN_DUPLICATE, FALSE, TRUE }, - { L"Impersonate", TOKEN_IMPERSONATE, FALSE, TRUE }, - { L"Query", TOKEN_QUERY, FALSE, TRUE }, - { L"Query source", TOKEN_QUERY_SOURCE, FALSE, TRUE } -}; - -ACCESS_ENTRIES(TpWorkerFactory) -{ - { L"Full control", WORKER_FACTORY_ALL_ACCESS, TRUE, TRUE }, - { L"Release worker", WORKER_FACTORY_RELEASE_WORKER, FALSE, TRUE }, - { L"Ready worker", WORKER_FACTORY_READY_WORKER, FALSE, TRUE }, - { L"Wait", WORKER_FACTORY_WAIT, FALSE, TRUE }, - { L"Set information", WORKER_FACTORY_SET_INFORMATION, FALSE, TRUE }, - { L"Query information", WORKER_FACTORY_QUERY_INFORMATION, FALSE, TRUE }, - { L"Shutdown", WORKER_FACTORY_SHUTDOWN, FALSE, TRUE } -}; - -ACCESS_ENTRIES(Type) -{ - { L"Full control", OBJECT_TYPE_ALL_ACCESS, TRUE, TRUE }, - { L"Create", OBJECT_TYPE_CREATE, TRUE, TRUE } -}; - -ACCESS_ENTRIES(WindowStation) -{ - { L"Full control", WINSTA_ALL_ACCESS | STANDARD_RIGHTS_REQUIRED, TRUE, TRUE }, - { L"Read", WINSTA_GENERIC_READ, TRUE, FALSE }, - { L"Write", WINSTA_GENERIC_WRITE, TRUE, FALSE }, - { L"Execute", WINSTA_GENERIC_EXECUTE, TRUE, FALSE }, - { L"Enumerate", WINSTA_ENUMERATE, FALSE, TRUE }, - { L"Enumerate desktops", WINSTA_ENUMDESKTOPS, FALSE, TRUE }, - { L"Read attributes", WINSTA_READATTRIBUTES, FALSE, TRUE }, - { L"Read screen", WINSTA_READSCREEN, FALSE, TRUE }, - { L"Access clipboard", WINSTA_ACCESSCLIPBOARD, FALSE, TRUE }, - { L"Access global atoms", WINSTA_ACCESSGLOBALATOMS, FALSE, TRUE }, - { L"Create desktop", WINSTA_CREATEDESKTOP, FALSE, TRUE }, - { L"Write attributes", WINSTA_WRITEATTRIBUTES, FALSE, TRUE }, - { L"Exit windows", WINSTA_EXITWINDOWS, FALSE, TRUE } -}; - -ACCESS_ENTRIES(WmiGuid) -{ - { L"Full control", WMIGUID_ALL_ACCESS, TRUE, TRUE }, - { L"Read", WMIGUID_GENERIC_READ, TRUE, FALSE }, - { L"Write", WMIGUID_GENERIC_WRITE, TRUE, FALSE }, - { L"Execute", WMIGUID_GENERIC_EXECUTE, TRUE, FALSE }, - { L"Query information", WMIGUID_QUERY, FALSE, TRUE }, - { L"Set information", WMIGUID_SET, FALSE, TRUE }, - { L"Get notifications", WMIGUID_NOTIFICATION, FALSE, TRUE }, - { L"Read description", WMIGUID_READ_DESCRIPTION, FALSE, TRUE }, - { L"Execute", WMIGUID_EXECUTE, FALSE, TRUE }, - { L"Create real-time logs", TRACELOG_CREATE_REALTIME, FALSE, TRUE, L"Create real-time" }, - { L"Create on disk logs", TRACELOG_CREATE_ONDISK, FALSE, TRUE, L"Create on disk" }, - { L"Enable provider GUIDs", TRACELOG_GUID_ENABLE, FALSE, TRUE, L"Enable GUIDs" }, - { L"Access kernel logger", TRACELOG_ACCESS_KERNEL_LOGGER, FALSE, TRUE }, - { L"Log events", TRACELOG_LOG_EVENT, FALSE, TRUE }, - { L"Access real-time events", TRACELOG_ACCESS_REALTIME, FALSE, TRUE, L"Access real-time" }, - { L"Register provider GUIDs", TRACELOG_REGISTER_GUIDS, FALSE, TRUE, L"Register GUIDs" } -}; - -static PH_SPECIFIC_TYPE PhSpecificTypes[] = -{ - ACCESS_ENTRY(AlpcPort, TRUE), - ACCESS_ENTRY(DebugObject, TRUE), - ACCESS_ENTRY(Desktop, FALSE), - ACCESS_ENTRY(Directory, FALSE), - ACCESS_ENTRY(Event, TRUE), - ACCESS_ENTRY(EventPair, TRUE), - ACCESS_ENTRY(File, TRUE), - ACCESS_ENTRY(FilterConnectionPort, FALSE), - ACCESS_ENTRY(IoCompletion, TRUE), - ACCESS_ENTRY(Job, TRUE), - ACCESS_ENTRY(Key, FALSE), - ACCESS_ENTRY(KeyedEvent, FALSE), - ACCESS_ENTRY(LsaAccount, FALSE), - ACCESS_ENTRY(LsaPolicy, FALSE), - ACCESS_ENTRY(LsaSecret, FALSE), - ACCESS_ENTRY(LsaTrusted, FALSE), - ACCESS_ENTRY(Mutant, TRUE), - ACCESS_ENTRY(Partition, TRUE), - ACCESS_ENTRY(Process, TRUE), - ACCESS_ENTRY(Process60, TRUE), - ACCESS_ENTRY(Profile, FALSE), - ACCESS_ENTRY(SamAlias, FALSE), - ACCESS_ENTRY(SamDomain, FALSE), - ACCESS_ENTRY(SamGroup, FALSE), - ACCESS_ENTRY(SamServer, FALSE), - ACCESS_ENTRY(SamUser, FALSE), - ACCESS_ENTRY(Section, FALSE), - ACCESS_ENTRY(Semaphore, TRUE), - ACCESS_ENTRY(Service, FALSE), - ACCESS_ENTRY(Session, FALSE), - ACCESS_ENTRY(SymbolicLink, FALSE), - ACCESS_ENTRY(Thread, TRUE), - ACCESS_ENTRY(Thread60, TRUE), - ACCESS_ENTRY(Timer, TRUE), - ACCESS_ENTRY(TmEn, FALSE), - ACCESS_ENTRY(TmRm, FALSE), - ACCESS_ENTRY(TmTm, FALSE), - ACCESS_ENTRY(TmTx, FALSE), - ACCESS_ENTRY(Token, FALSE), - ACCESS_ENTRY(TpWorkerFactory, FALSE), - ACCESS_ENTRY(Type, FALSE), - ACCESS_ENTRY(WindowStation, FALSE), - ACCESS_ENTRY(WmiGuid, TRUE) -}; - -/** - * Gets access entries for an object type. - * - * \param Type The name of the object type. - * \param AccessEntries A variable which receives an array of access entry structures. You must free - * the buffer with PhFree() when you no longer need it. - * \param NumberOfAccessEntries A variable which receives the number of access entry structures - * returned in - * \a AccessEntries. - */ -BOOLEAN PhGetAccessEntries( - _In_ PWSTR Type, - _Out_ PPH_ACCESS_ENTRY *AccessEntries, - _Out_ PULONG NumberOfAccessEntries - ) -{ - ULONG i; - PPH_SPECIFIC_TYPE specificType = NULL; - PPH_ACCESS_ENTRY accessEntries; - - if (PhEqualStringZ(Type, L"ALPC Port", TRUE)) - { - Type = L"AlpcPort"; - } - else if (PhEqualStringZ(Type, L"Port", TRUE)) - { - Type = L"AlpcPort"; - } - else if (PhEqualStringZ(Type, L"WaitablePort", TRUE)) - { - Type = L"AlpcPort"; - } - else if (PhEqualStringZ(Type, L"Process", TRUE)) - { - if (WindowsVersion >= WINDOWS_VISTA) - Type = L"Process60"; - } - else if (PhEqualStringZ(Type, L"Thread", TRUE)) - { - if (WindowsVersion >= WINDOWS_VISTA) - Type = L"Thread60"; - } - - // Find the specific type. - for (i = 0; i < sizeof(PhSpecificTypes) / sizeof(PH_SPECIFIC_TYPE); i++) - { - if (PhEqualStringZ(PhSpecificTypes[i].Type, Type, TRUE)) - { - specificType = &PhSpecificTypes[i]; - break; - } - } - - if (specificType) - { - ULONG sizeOfEntries; - - // Copy the specific access entries and append the standard access entries. - - if (specificType->HasSynchronize) - sizeOfEntries = specificType->SizeOfAccessEntries + sizeof(PhStandardAccessEntries); - else - sizeOfEntries = specificType->SizeOfAccessEntries + sizeof(PhStandardAccessEntries) - sizeof(PH_ACCESS_ENTRY); - - accessEntries = PhAllocate(sizeOfEntries); - memcpy(accessEntries, specificType->AccessEntries, specificType->SizeOfAccessEntries); - - if (specificType->HasSynchronize) - { - memcpy( - PTR_ADD_OFFSET(accessEntries, specificType->SizeOfAccessEntries), - PhStandardAccessEntries, - sizeof(PhStandardAccessEntries) - ); - } - else - { - memcpy( - PTR_ADD_OFFSET(accessEntries, specificType->SizeOfAccessEntries), - &PhStandardAccessEntries[1], - sizeof(PhStandardAccessEntries) - sizeof(PH_ACCESS_ENTRY) - ); - } - - *AccessEntries = accessEntries; - *NumberOfAccessEntries = sizeOfEntries / sizeof(PH_ACCESS_ENTRY); - } - else - { - accessEntries = PhAllocate(sizeof(PhStandardAccessEntries)); - memcpy(accessEntries, PhStandardAccessEntries, sizeof(PhStandardAccessEntries)); - - *AccessEntries = accessEntries; - *NumberOfAccessEntries = sizeof(PhStandardAccessEntries) / sizeof(PH_ACCESS_ENTRY); - } - - return TRUE; -} - -static int __cdecl PhpAccessEntryCompare( - _In_ const void *elem1, - _In_ const void *elem2 - ) -{ - PPH_ACCESS_ENTRY entry1 = (PPH_ACCESS_ENTRY)elem1; - PPH_ACCESS_ENTRY entry2 = (PPH_ACCESS_ENTRY)elem2; - - return intcmp(PhCountBits(entry2->Access), PhCountBits(entry1->Access)); -} - -/** - * Creates a string representation of an access mask. - * - * \param Access The access mask. - * \param AccessEntries An array of access entry structures. You can call PhGetAccessEntries() to - * retrieve the access entry structures for a standard object type. - * \param NumberOfAccessEntries The number of elements in \a AccessEntries. - * - * \return The string representation of \a Access. - */ -PPH_STRING PhGetAccessString( - _In_ ACCESS_MASK Access, - _In_ PPH_ACCESS_ENTRY AccessEntries, - _In_ ULONG NumberOfAccessEntries - ) -{ - PH_STRING_BUILDER stringBuilder; - PPH_ACCESS_ENTRY accessEntries; - PBOOLEAN matched; - ULONG i; - ULONG j; - - PhInitializeStringBuilder(&stringBuilder, 32); - - // Sort the access entries according to how many access rights they include. - accessEntries = PhAllocateCopy(AccessEntries, NumberOfAccessEntries * sizeof(PH_ACCESS_ENTRY)); - qsort(accessEntries, NumberOfAccessEntries, sizeof(PH_ACCESS_ENTRY), PhpAccessEntryCompare); - - matched = PhAllocate(NumberOfAccessEntries * sizeof(BOOLEAN)); - memset(matched, 0, NumberOfAccessEntries * sizeof(BOOLEAN)); - - for (i = 0; i < NumberOfAccessEntries; i++) - { - // We make sure we haven't matched this access entry yet. This ensures that we won't get - // duplicates, e.g. FILE_GENERIC_READ includes FILE_READ_DATA, and we don't want to display - // both to the user. - if ( - !matched[i] && - ((Access & accessEntries[i].Access) == accessEntries[i].Access) - ) - { - if (accessEntries[i].ShortName) - PhAppendStringBuilder2(&stringBuilder, accessEntries[i].ShortName); - else - PhAppendStringBuilder2(&stringBuilder, accessEntries[i].Name); - - PhAppendStringBuilder2(&stringBuilder, L", "); - - // Disable equal or more specific entries. - for (j = i; j < NumberOfAccessEntries; j++) - { - if ((accessEntries[i].Access | accessEntries[j].Access) == accessEntries[i].Access) - matched[j] = TRUE; - } - } - } - - // Remove the trailing ", ". - if (PhEndsWithString2(stringBuilder.String, L", ", FALSE)) - PhRemoveEndStringBuilder(&stringBuilder, 2); - - PhFree(matched); - PhFree(accessEntries); - - return PhFinalStringBuilderString(&stringBuilder); -} +/* + * Process Hacker - + * object security data + * + * Copyright (C) 2010-2016 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include +#include + +#include + +#include + +#define ACCESS_ENTRIES(Type) static PH_ACCESS_ENTRY Ph##Type##AccessEntries[] = +#define ACCESS_ENTRY(Type, HasSynchronize) \ + { L#Type, Ph##Type##AccessEntries, sizeof(Ph##Type##AccessEntries), HasSynchronize } + +typedef struct _PH_SPECIFIC_TYPE +{ + PWSTR Type; + PPH_ACCESS_ENTRY AccessEntries; + ULONG SizeOfAccessEntries; + BOOLEAN HasSynchronize; +} PH_SPECIFIC_TYPE, *PPH_SPECIFIC_TYPE; + +ACCESS_ENTRIES(Standard) +{ + { L"Synchronize", SYNCHRONIZE, FALSE, TRUE }, + { L"Delete", DELETE, FALSE, TRUE }, + { L"Read permissions", READ_CONTROL, FALSE, TRUE, L"Read control" }, + { L"Change permissions", WRITE_DAC, FALSE, TRUE, L"Write DAC" }, + { L"Take ownership", WRITE_OWNER, FALSE, TRUE, L"Write owner" } +}; + +ACCESS_ENTRIES(AlpcPort) +{ + { L"Full control", PORT_ALL_ACCESS, TRUE, TRUE }, + { L"Connect", PORT_CONNECT, TRUE, TRUE } +}; + +ACCESS_ENTRIES(DebugObject) +{ + { L"Full control", DEBUG_ALL_ACCESS, TRUE, TRUE }, + { L"Read events", DEBUG_READ_EVENT, TRUE, TRUE }, + { L"Assign processes", DEBUG_PROCESS_ASSIGN, TRUE, TRUE }, + { L"Query information", DEBUG_QUERY_INFORMATION, TRUE, TRUE }, + { L"Set information", DEBUG_SET_INFORMATION, TRUE, TRUE } +}; + +ACCESS_ENTRIES(Desktop) +{ + { L"Full control", DESKTOP_ALL_ACCESS, TRUE, TRUE }, + { L"Read", DESKTOP_GENERIC_READ, TRUE, FALSE }, + { L"Write", DESKTOP_GENERIC_WRITE, TRUE, FALSE }, + { L"Execute", DESKTOP_GENERIC_EXECUTE, TRUE, FALSE }, + { L"Enumerate", DESKTOP_ENUMERATE, FALSE, TRUE }, + { L"Read objects", DESKTOP_READOBJECTS, FALSE, TRUE }, + { L"Playback journals", DESKTOP_JOURNALPLAYBACK, FALSE, TRUE }, + { L"Write objects", DESKTOP_WRITEOBJECTS, FALSE, TRUE }, + { L"Create windows", DESKTOP_CREATEWINDOW, FALSE, TRUE }, + { L"Create menus", DESKTOP_CREATEMENU, FALSE, TRUE }, + { L"Create window hooks", DESKTOP_HOOKCONTROL, FALSE, TRUE }, + { L"Record journals", DESKTOP_JOURNALRECORD, FALSE, TRUE }, + { L"Switch desktop", DESKTOP_SWITCHDESKTOP, FALSE, TRUE } +}; + +ACCESS_ENTRIES(Directory) +{ + { L"Full control", DIRECTORY_ALL_ACCESS, TRUE, TRUE }, + { L"Query", DIRECTORY_QUERY, TRUE, TRUE}, + { L"Traverse", DIRECTORY_TRAVERSE, TRUE, TRUE}, + { L"Create objects", DIRECTORY_CREATE_OBJECT, TRUE, TRUE}, + { L"Create subdirectories", DIRECTORY_CREATE_SUBDIRECTORY, TRUE, TRUE} +}; + +ACCESS_ENTRIES(Event) +{ + { L"Full control", EVENT_ALL_ACCESS, TRUE, TRUE }, + { L"Query", EVENT_QUERY_STATE, TRUE, TRUE }, + { L"Modify", EVENT_MODIFY_STATE, TRUE, TRUE } +}; + +ACCESS_ENTRIES(EventPair) +{ + { L"Full control", EVENT_PAIR_ALL_ACCESS, TRUE, TRUE } +}; + +ACCESS_ENTRIES(File) +{ + { L"Full control", FILE_ALL_ACCESS, TRUE, TRUE }, + { L"Read & execute", FILE_GENERIC_READ | FILE_GENERIC_EXECUTE, TRUE, FALSE }, + { L"Read", FILE_GENERIC_READ, TRUE, FALSE }, + { L"Write", FILE_GENERIC_WRITE, TRUE, FALSE }, + { L"Traverse folder / execute file", FILE_EXECUTE, FALSE, TRUE, L"Execute" }, + { L"List folder / read data", FILE_READ_DATA, FALSE, TRUE, L"Read data" }, + { L"Read attributes", FILE_READ_ATTRIBUTES, FALSE, TRUE }, + { L"Read extended attributes", FILE_READ_EA, FALSE, TRUE, L"Read EA" }, + { L"Create files / write data", FILE_WRITE_DATA, FALSE, TRUE, L"Write data" }, + { L"Create folders / append data", FILE_APPEND_DATA, FALSE, TRUE, L"Append data" }, + { L"Write attributes", FILE_WRITE_ATTRIBUTES, FALSE, TRUE }, + { L"Write extended attributes", FILE_WRITE_EA, FALSE, TRUE, L"Write EA" }, + { L"Delete subfolders and files", FILE_DELETE_CHILD, FALSE, TRUE, L"Delete child" } +}; + +ACCESS_ENTRIES(FilterConnectionPort) +{ + { L"Full control", FLT_PORT_ALL_ACCESS, TRUE, TRUE }, + { L"Connect", FLT_PORT_CONNECT, TRUE, TRUE } +}; + +ACCESS_ENTRIES(IoCompletion) +{ + { L"Full control", IO_COMPLETION_ALL_ACCESS, TRUE, TRUE }, + { L"Query", IO_COMPLETION_QUERY_STATE, TRUE, TRUE }, + { L"Modify", IO_COMPLETION_MODIFY_STATE, TRUE, TRUE } +}; + +ACCESS_ENTRIES(Job) +{ + { L"Full control", JOB_OBJECT_ALL_ACCESS, TRUE, TRUE }, + { L"Query", JOB_OBJECT_QUERY, TRUE, TRUE }, + { L"Assign processes", JOB_OBJECT_ASSIGN_PROCESS, TRUE, TRUE }, + { L"Set attributes", JOB_OBJECT_SET_ATTRIBUTES, TRUE, TRUE }, + { L"Set security attributes", JOB_OBJECT_SET_SECURITY_ATTRIBUTES, TRUE, TRUE }, + { L"Terminate", JOB_OBJECT_TERMINATE, TRUE, TRUE } +}; + +ACCESS_ENTRIES(Key) +{ + { L"Full control", KEY_ALL_ACCESS, TRUE, TRUE }, + { L"Read", KEY_READ, TRUE, FALSE }, + { L"Write", KEY_WRITE, TRUE, FALSE }, + { L"Execute", KEY_EXECUTE, TRUE, FALSE }, + { L"Enumerate subkeys", KEY_ENUMERATE_SUB_KEYS, FALSE, TRUE }, + { L"Query values", KEY_QUERY_VALUE, FALSE, TRUE }, + { L"Notify", KEY_NOTIFY, FALSE, TRUE }, + { L"Set values", KEY_SET_VALUE, FALSE, TRUE }, + { L"Create subkeys", KEY_CREATE_SUB_KEY, FALSE, TRUE }, + { L"Create links", KEY_CREATE_LINK, FALSE, TRUE } +}; + +ACCESS_ENTRIES(KeyedEvent) +{ + { L"Full control", KEYEDEVENT_ALL_ACCESS, TRUE, TRUE }, + { L"Wait", KEYEDEVENT_WAIT, TRUE, TRUE }, + { L"Wake", KEYEDEVENT_WAKE, TRUE, TRUE } +}; + +ACCESS_ENTRIES(LsaAccount) +{ + { L"Full control", ACCOUNT_ALL_ACCESS, TRUE, TRUE }, + { L"Read", ACCOUNT_READ, TRUE, FALSE }, + { L"Write", ACCOUNT_WRITE, TRUE, FALSE }, + { L"Execute", ACCOUNT_EXECUTE, TRUE, FALSE }, + { L"View", ACCOUNT_VIEW, FALSE, TRUE }, + { L"Adjust privileges", ACCOUNT_ADJUST_PRIVILEGES, FALSE, TRUE }, + { L"Adjust quotas", ACCOUNT_ADJUST_QUOTAS, FALSE, TRUE }, + { L"Adjust system access", ACCOUNT_ADJUST_SYSTEM_ACCESS, FALSE, TRUE } +}; + +ACCESS_ENTRIES(LsaPolicy) +{ + { L"Full control", POLICY_ALL_ACCESS | POLICY_NOTIFICATION, TRUE, TRUE }, + { L"Read", POLICY_READ, TRUE, FALSE }, + { L"Write", POLICY_WRITE, TRUE, FALSE }, + { L"Execute", POLICY_EXECUTE | POLICY_NOTIFICATION, TRUE, FALSE }, + { L"View local information", POLICY_VIEW_LOCAL_INFORMATION, FALSE, TRUE }, + { L"View audit information", POLICY_VIEW_AUDIT_INFORMATION, FALSE, TRUE }, + { L"Get private information", POLICY_GET_PRIVATE_INFORMATION, FALSE, TRUE }, + { L"Administer trust", POLICY_TRUST_ADMIN, FALSE, TRUE }, + { L"Create account", POLICY_CREATE_ACCOUNT, FALSE, TRUE }, + { L"Create secret", POLICY_CREATE_SECRET, FALSE, TRUE }, + { L"Create privilege", POLICY_CREATE_PRIVILEGE, FALSE, TRUE }, + { L"Set default quota limits", POLICY_SET_DEFAULT_QUOTA_LIMITS, FALSE, TRUE }, + { L"Set audit requirements", POLICY_SET_AUDIT_REQUIREMENTS, FALSE, TRUE }, + { L"Administer audit log", POLICY_AUDIT_LOG_ADMIN, FALSE, TRUE }, + { L"Administer server", POLICY_SERVER_ADMIN, FALSE, TRUE }, + { L"Lookup names", POLICY_LOOKUP_NAMES, FALSE, TRUE }, + { L"Get notifications", POLICY_NOTIFICATION, FALSE, TRUE } +}; + +ACCESS_ENTRIES(LsaSecret) +{ + { L"Full control", SECRET_ALL_ACCESS, TRUE, TRUE }, + { L"Read", SECRET_READ, TRUE, FALSE }, + { L"Write", SECRET_WRITE, TRUE, FALSE }, + { L"Execute", SECRET_EXECUTE, TRUE, FALSE }, + { L"Set value", SECRET_SET_VALUE, FALSE, TRUE }, + { L"Query value", SECRET_QUERY_VALUE, FALSE, TRUE } +}; + +ACCESS_ENTRIES(LsaTrusted) +{ + { L"Full control", TRUSTED_ALL_ACCESS, TRUE, TRUE }, + { L"Read", TRUSTED_READ, TRUE, FALSE }, + { L"Write", TRUSTED_WRITE, TRUE, FALSE }, + { L"Execute", TRUSTED_EXECUTE, TRUE, FALSE }, + { L"Query domain name", TRUSTED_QUERY_DOMAIN_NAME, FALSE, TRUE }, + { L"Query controllers", TRUSTED_QUERY_CONTROLLERS, FALSE, TRUE }, + { L"Set controllers", TRUSTED_SET_CONTROLLERS, FALSE, TRUE }, + { L"Query POSIX", TRUSTED_QUERY_POSIX, FALSE, TRUE }, + { L"Set POSIX", TRUSTED_SET_POSIX, FALSE, TRUE }, + { L"Query authentication", TRUSTED_QUERY_AUTH, FALSE, TRUE }, + { L"Set authentication", TRUSTED_SET_AUTH, FALSE, TRUE } +}; + +ACCESS_ENTRIES(Mutant) +{ + { L"Full control", MUTANT_ALL_ACCESS, TRUE, TRUE }, + { L"Query", MUTANT_QUERY_STATE, TRUE, TRUE } +}; + +ACCESS_ENTRIES(Partition) +{ + { L"Full control", MEMORY_PARTITION_ALL_ACCESS, TRUE, TRUE }, + { L"Query", MEMORY_PARTITION_QUERY_ACCESS, TRUE, TRUE }, + { L"Modify", MEMORY_PARTITION_MODIFY_ACCESS, TRUE, TRUE } +}; + +ACCESS_ENTRIES(Process) +{ + { L"Full control", STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xfff, TRUE, TRUE }, + { L"Query information", PROCESS_QUERY_INFORMATION, TRUE, TRUE }, + { L"Set information", PROCESS_SET_INFORMATION, TRUE, TRUE }, + { L"Set quotas", PROCESS_SET_QUOTA, TRUE, TRUE }, + { L"Set session ID", PROCESS_SET_SESSIONID, TRUE, TRUE }, + { L"Create threads", PROCESS_CREATE_THREAD, TRUE, TRUE }, + { L"Create processes", PROCESS_CREATE_PROCESS, TRUE, TRUE }, + { L"Modify memory", PROCESS_VM_OPERATION, TRUE, TRUE, L"VM operation" }, + { L"Read memory", PROCESS_VM_READ, TRUE, TRUE, L"VM read" }, + { L"Write memory", PROCESS_VM_WRITE, TRUE, TRUE, L"VM write" }, + { L"Duplicate handles", PROCESS_DUP_HANDLE, TRUE, TRUE }, + { L"Suspend / resume / set port", PROCESS_SUSPEND_RESUME, TRUE, TRUE, L"Suspend/resume" }, + { L"Terminate", PROCESS_TERMINATE, TRUE, TRUE } +}; + +ACCESS_ENTRIES(Process60) +{ + { L"Full control", STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xffff, TRUE, TRUE }, // PROCESS_ALL_ACCESS + { L"Query limited information", PROCESS_QUERY_LIMITED_INFORMATION, TRUE, TRUE }, + { L"Query information", PROCESS_QUERY_INFORMATION | PROCESS_QUERY_LIMITED_INFORMATION, TRUE, TRUE }, + { L"Set information", PROCESS_SET_INFORMATION, TRUE, TRUE }, + { L"Set quotas", PROCESS_SET_QUOTA, TRUE, TRUE }, + { L"Set session ID", PROCESS_SET_SESSIONID, TRUE, TRUE }, + { L"Create threads", PROCESS_CREATE_THREAD, TRUE, TRUE }, + { L"Create processes", PROCESS_CREATE_PROCESS, TRUE, TRUE }, + { L"Modify memory", PROCESS_VM_OPERATION, TRUE, TRUE, L"VM operation" }, + { L"Read memory", PROCESS_VM_READ, TRUE, TRUE, L"VM read" }, + { L"Write memory", PROCESS_VM_WRITE, TRUE, TRUE, L"VM write" }, + { L"Duplicate handles", PROCESS_DUP_HANDLE, TRUE, TRUE }, + { L"Suspend / resume / set port", PROCESS_SUSPEND_RESUME, TRUE, TRUE, L"Suspend/resume" }, + { L"Terminate", PROCESS_TERMINATE, TRUE, TRUE } +}; + +ACCESS_ENTRIES(Profile) +{ + { L"Full control", PROFILE_ALL_ACCESS, TRUE, TRUE }, + { L"Control", PROFILE_CONTROL, TRUE, TRUE } +}; + +ACCESS_ENTRIES(SamAlias) +{ + { L"Full control", ALIAS_ALL_ACCESS, TRUE, TRUE }, + { L"Read", ALIAS_READ, TRUE, FALSE }, + { L"Write", ALIAS_WRITE, TRUE, FALSE }, + { L"Execute", ALIAS_EXECUTE, TRUE, FALSE }, + { L"Read information", ALIAS_READ_INFORMATION, FALSE, TRUE }, + { L"Write account", ALIAS_WRITE_ACCOUNT, FALSE, TRUE }, + { L"Add member", ALIAS_ADD_MEMBER, FALSE, TRUE }, + { L"Remove member", ALIAS_REMOVE_MEMBER, FALSE, TRUE }, + { L"List members", ALIAS_LIST_MEMBERS, FALSE, TRUE } +}; + +ACCESS_ENTRIES(SamDomain) +{ + { L"Full control", DOMAIN_ALL_ACCESS, TRUE, TRUE }, + { L"Read", DOMAIN_READ, TRUE, FALSE }, + { L"Write", DOMAIN_WRITE, TRUE, FALSE }, + { L"Execute", DOMAIN_EXECUTE, TRUE, FALSE }, + { L"Read password parameters", DOMAIN_READ_PASSWORD_PARAMETERS, FALSE, TRUE }, + { L"Write password parameters", DOMAIN_WRITE_PASSWORD_PARAMS, FALSE, TRUE }, + { L"Read other parameters", DOMAIN_READ_OTHER_PARAMETERS, FALSE, TRUE }, + { L"Write other parameters", DOMAIN_WRITE_OTHER_PARAMETERS, FALSE, TRUE }, + { L"Create user", DOMAIN_CREATE_USER, FALSE, TRUE }, + { L"Create group", DOMAIN_CREATE_GROUP, FALSE, TRUE }, + { L"Create alias", DOMAIN_CREATE_ALIAS, FALSE, TRUE }, + { L"Get alias membership", DOMAIN_GET_ALIAS_MEMBERSHIP, FALSE, TRUE }, + { L"List accounts", DOMAIN_LIST_ACCOUNTS, FALSE, TRUE }, + { L"Lookup", DOMAIN_LOOKUP, FALSE, TRUE }, + { L"Administer server", DOMAIN_ADMINISTER_SERVER, FALSE, TRUE } +}; + +ACCESS_ENTRIES(SamGroup) +{ + { L"Full control", GROUP_ALL_ACCESS, TRUE, TRUE }, + { L"Read", GROUP_READ, TRUE, FALSE }, + { L"Write", GROUP_WRITE, TRUE, FALSE }, + { L"Execute", GROUP_EXECUTE, TRUE, FALSE }, + { L"Read information", GROUP_READ_INFORMATION, FALSE, TRUE }, + { L"Write account", GROUP_WRITE_ACCOUNT, FALSE, TRUE }, + { L"Add member", GROUP_ADD_MEMBER, FALSE, TRUE }, + { L"Remove member", GROUP_REMOVE_MEMBER, FALSE, TRUE }, + { L"List members", GROUP_LIST_MEMBERS, FALSE, TRUE } +}; + +ACCESS_ENTRIES(SamServer) +{ + { L"Full control", SAM_SERVER_ALL_ACCESS, TRUE, TRUE }, + { L"Read", SAM_SERVER_READ, TRUE, FALSE }, + { L"Write", SAM_SERVER_WRITE, TRUE, FALSE }, + { L"Execute", SAM_SERVER_EXECUTE, TRUE, FALSE }, + { L"Connect", SAM_SERVER_CONNECT, FALSE, TRUE }, + { L"Shutdown", SAM_SERVER_SHUTDOWN, FALSE, TRUE }, + { L"Initialize", SAM_SERVER_INITIALIZE, FALSE, TRUE }, + { L"Create domain", SAM_SERVER_CREATE_DOMAIN, FALSE, TRUE }, + { L"Enumerate domains", SAM_SERVER_ENUMERATE_DOMAINS, FALSE, TRUE }, + { L"Lookup domain", SAM_SERVER_LOOKUP_DOMAIN, FALSE, TRUE } +}; + +ACCESS_ENTRIES(SamUser) +{ + { L"Full control", USER_ALL_ACCESS, TRUE, TRUE }, + { L"Read", USER_READ, TRUE, FALSE }, + { L"Write", USER_WRITE, TRUE, FALSE }, + { L"Execute", USER_EXECUTE, TRUE, FALSE }, + { L"Read general", USER_READ_GENERAL, FALSE, TRUE }, + { L"Read preferences", USER_READ_PREFERENCES, FALSE, TRUE }, + { L"Write preferences", USER_WRITE_PREFERENCES, FALSE, TRUE }, + { L"Read logon", USER_READ_LOGON, FALSE, TRUE }, + { L"Read account", USER_READ_ACCOUNT, FALSE, TRUE }, + { L"Write account", USER_WRITE_ACCOUNT, FALSE, TRUE }, + { L"Change password", USER_CHANGE_PASSWORD, FALSE, TRUE }, + { L"Force password change", USER_FORCE_PASSWORD_CHANGE, FALSE, TRUE }, + { L"List groups", USER_LIST_GROUPS, FALSE, TRUE }, + { L"Read group information", USER_READ_GROUP_INFORMATION, FALSE, TRUE }, + { L"Write group information", USER_WRITE_GROUP_INFORMATION, FALSE, TRUE } +}; + +ACCESS_ENTRIES(Section) +{ + { L"Full control", SECTION_ALL_ACCESS, TRUE, TRUE }, + { L"Query", SECTION_QUERY, TRUE, TRUE }, + { L"Map for read", SECTION_MAP_READ, TRUE, TRUE, L"Map read" }, + { L"Map for write", SECTION_MAP_WRITE, TRUE, TRUE, L"Map write" }, + { L"Map for execute", SECTION_MAP_EXECUTE, TRUE, TRUE, L"Map execute" }, + { L"Map for execute (explicit)", SECTION_MAP_EXECUTE_EXPLICIT, TRUE, TRUE, L"Map execute explicit" }, + { L"Extend size", SECTION_EXTEND_SIZE, TRUE, TRUE } +}; + +ACCESS_ENTRIES(Semaphore) +{ + { L"Full control", SEMAPHORE_ALL_ACCESS, TRUE, TRUE }, + { L"Query", SEMAPHORE_QUERY_STATE, TRUE, TRUE }, + { L"Modify", SEMAPHORE_MODIFY_STATE, TRUE, TRUE } +}; + +ACCESS_ENTRIES(Service) +{ + { L"Full control", SERVICE_ALL_ACCESS, TRUE, TRUE }, + { L"Query status", SERVICE_QUERY_STATUS, TRUE, TRUE }, + { L"Query configuration", SERVICE_QUERY_CONFIG, TRUE, TRUE }, + { L"Modify configuration", SERVICE_CHANGE_CONFIG, TRUE, TRUE }, + { L"Enumerate dependents", SERVICE_ENUMERATE_DEPENDENTS, TRUE, TRUE }, + { L"Start", SERVICE_START, TRUE, TRUE }, + { L"Stop", SERVICE_STOP, TRUE, TRUE }, + { L"Pause / continue", SERVICE_PAUSE_CONTINUE, TRUE, TRUE, L"Pause/continue" }, + { L"Interrogate", SERVICE_INTERROGATE, TRUE, TRUE }, + { L"User-defined control", SERVICE_USER_DEFINED_CONTROL, TRUE, TRUE } +}; + +ACCESS_ENTRIES(Session) +{ + { L"Full control", SESSION_ALL_ACCESS, TRUE, TRUE }, + { L"Query", SESSION_QUERY_ACCESS, TRUE, TRUE }, + { L"Modify", SESSION_MODIFY_ACCESS, TRUE, TRUE } +}; + +ACCESS_ENTRIES(SymbolicLink) +{ + { L"Full control", SYMBOLIC_LINK_ALL_ACCESS, TRUE, TRUE }, + { L"Query", SYMBOLIC_LINK_QUERY, TRUE, TRUE } +}; + +ACCESS_ENTRIES(Thread) +{ + { L"Full control", STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x3ff, TRUE, TRUE }, + { L"Query information", THREAD_QUERY_INFORMATION, TRUE, TRUE }, + { L"Set information", THREAD_SET_INFORMATION, TRUE, TRUE }, + { L"Get context", THREAD_GET_CONTEXT, TRUE, TRUE }, + { L"Set context", THREAD_SET_CONTEXT, TRUE, TRUE }, + { L"Set token", THREAD_SET_THREAD_TOKEN, TRUE, TRUE }, + { L"Alert", THREAD_ALERT, TRUE, TRUE }, + { L"Impersonate", THREAD_IMPERSONATE, TRUE, TRUE }, + { L"Direct impersonate", THREAD_DIRECT_IMPERSONATION, TRUE, TRUE }, + { L"Suspend / resume", THREAD_SUSPEND_RESUME, TRUE, TRUE, L"Suspend/resume" }, + { L"Terminate", THREAD_TERMINATE, TRUE, TRUE }, +}; + +ACCESS_ENTRIES(Thread60) +{ + { L"Full control", STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xffff, TRUE, TRUE }, // THREAD_ALL_ACCESS + { L"Query limited information", THREAD_QUERY_LIMITED_INFORMATION, TRUE, TRUE }, + { L"Query information", THREAD_QUERY_INFORMATION | THREAD_QUERY_LIMITED_INFORMATION, TRUE, TRUE }, + { L"Set limited information", THREAD_SET_LIMITED_INFORMATION, TRUE, TRUE }, + { L"Set information", THREAD_SET_INFORMATION | THREAD_SET_LIMITED_INFORMATION, TRUE, TRUE }, + { L"Get context", THREAD_GET_CONTEXT, TRUE, TRUE }, + { L"Set context", THREAD_SET_CONTEXT, TRUE, TRUE }, + { L"Set token", THREAD_SET_THREAD_TOKEN, TRUE, TRUE }, + { L"Alert", THREAD_ALERT, TRUE, TRUE }, + { L"Impersonate", THREAD_IMPERSONATE, TRUE, TRUE }, + { L"Direct impersonate", THREAD_DIRECT_IMPERSONATION, TRUE, TRUE }, + { L"Suspend / resume", THREAD_SUSPEND_RESUME, TRUE, TRUE, L"Suspend/resume" }, + { L"Terminate", THREAD_TERMINATE, TRUE, TRUE }, +}; + +ACCESS_ENTRIES(Timer) +{ + { L"Full control", TIMER_ALL_ACCESS, TRUE, TRUE }, + { L"Query", TIMER_QUERY_STATE, TRUE, TRUE }, + { L"Modify", TIMER_MODIFY_STATE, TRUE, TRUE } +}; + +ACCESS_ENTRIES(TmEn) +{ + { L"Full control", ENLISTMENT_ALL_ACCESS, TRUE, TRUE }, + { L"Read", ENLISTMENT_GENERIC_READ, TRUE, FALSE }, + { L"Write", ENLISTMENT_GENERIC_WRITE, TRUE, FALSE }, + { L"Execute", ENLISTMENT_GENERIC_EXECUTE, TRUE, FALSE }, + { L"Query information", ENLISTMENT_QUERY_INFORMATION, FALSE, TRUE }, + { L"Set information", ENLISTMENT_SET_INFORMATION, FALSE, TRUE }, + { L"Recover", ENLISTMENT_RECOVER, FALSE, TRUE }, + { L"Subordinate rights", ENLISTMENT_SUBORDINATE_RIGHTS, FALSE, TRUE }, + { L"Superior rights", ENLISTMENT_SUPERIOR_RIGHTS, FALSE, TRUE } +}; + +ACCESS_ENTRIES(TmRm) +{ + { L"Full control", RESOURCEMANAGER_ALL_ACCESS, TRUE, TRUE }, + { L"Read", RESOURCEMANAGER_GENERIC_READ, TRUE, FALSE }, + { L"Write", RESOURCEMANAGER_GENERIC_WRITE, TRUE, FALSE }, + { L"Execute", RESOURCEMANAGER_GENERIC_EXECUTE, TRUE, FALSE }, + { L"Query information", RESOURCEMANAGER_QUERY_INFORMATION, FALSE, TRUE }, + { L"Set information", RESOURCEMANAGER_SET_INFORMATION, FALSE, TRUE }, + { L"Get notifications", RESOURCEMANAGER_GET_NOTIFICATION, FALSE, TRUE }, + { L"Enlist", RESOURCEMANAGER_ENLIST, FALSE, TRUE }, + { L"Recover", RESOURCEMANAGER_RECOVER, FALSE, TRUE }, + { L"Register protocols", RESOURCEMANAGER_REGISTER_PROTOCOL, FALSE, TRUE }, + { L"Complete propagation", RESOURCEMANAGER_COMPLETE_PROPAGATION, FALSE, TRUE } +}; + +ACCESS_ENTRIES(TmTm) +{ + { L"Full control", TRANSACTIONMANAGER_ALL_ACCESS, TRUE, TRUE }, + { L"Read", TRANSACTIONMANAGER_GENERIC_READ, TRUE, FALSE }, + { L"Write", TRANSACTIONMANAGER_GENERIC_WRITE, TRUE, FALSE }, + { L"Execute", TRANSACTIONMANAGER_GENERIC_EXECUTE, TRUE, FALSE }, + { L"Query information", TRANSACTIONMANAGER_QUERY_INFORMATION, FALSE, TRUE }, + { L"Set information", TRANSACTIONMANAGER_SET_INFORMATION, FALSE, TRUE }, + { L"Recover", TRANSACTIONMANAGER_RECOVER, FALSE, TRUE }, + { L"Rename", TRANSACTIONMANAGER_RENAME, FALSE, TRUE }, + { L"Create resource manager", TRANSACTIONMANAGER_CREATE_RM, FALSE, TRUE }, + { L"Bind transactions", TRANSACTIONMANAGER_BIND_TRANSACTION, FALSE, TRUE } +}; + +ACCESS_ENTRIES(TmTx) +{ + { L"Full control", TRANSACTION_ALL_ACCESS, TRUE, TRUE }, + { L"Read", TRANSACTION_GENERIC_READ, TRUE, FALSE }, + { L"Write", TRANSACTION_GENERIC_WRITE, TRUE, FALSE }, + { L"Execute", TRANSACTION_GENERIC_EXECUTE, TRUE, FALSE }, + { L"Query information", TRANSACTION_QUERY_INFORMATION, FALSE, TRUE }, + { L"Set information", TRANSACTION_SET_INFORMATION, FALSE, TRUE }, + { L"Enlist", TRANSACTION_ENLIST, FALSE, TRUE }, + { L"Commit", TRANSACTION_COMMIT, FALSE, TRUE }, + { L"Rollback", TRANSACTION_ROLLBACK, FALSE, TRUE }, + { L"Propagate", TRANSACTION_PROPAGATE, FALSE, TRUE } +}; + +ACCESS_ENTRIES(Token) +{ + { L"Full control", TOKEN_ALL_ACCESS, TRUE, TRUE }, + { L"Read", TOKEN_READ, TRUE, FALSE }, + { L"Write", TOKEN_WRITE, TRUE, FALSE }, + { L"Execute", TOKEN_EXECUTE, TRUE, FALSE }, + { L"Adjust privileges", TOKEN_ADJUST_PRIVILEGES, FALSE, TRUE }, + { L"Adjust groups", TOKEN_ADJUST_GROUPS, FALSE, TRUE }, + { L"Adjust defaults", TOKEN_ADJUST_DEFAULT, FALSE, TRUE }, + { L"Adjust session ID", TOKEN_ADJUST_SESSIONID, FALSE, TRUE }, + { L"Assign as primary token", TOKEN_ASSIGN_PRIMARY, FALSE, TRUE, L"Assign primary" }, + { L"Duplicate", TOKEN_DUPLICATE, FALSE, TRUE }, + { L"Impersonate", TOKEN_IMPERSONATE, FALSE, TRUE }, + { L"Query", TOKEN_QUERY, FALSE, TRUE }, + { L"Query source", TOKEN_QUERY_SOURCE, FALSE, TRUE } +}; + +ACCESS_ENTRIES(TpWorkerFactory) +{ + { L"Full control", WORKER_FACTORY_ALL_ACCESS, TRUE, TRUE }, + { L"Release worker", WORKER_FACTORY_RELEASE_WORKER, FALSE, TRUE }, + { L"Ready worker", WORKER_FACTORY_READY_WORKER, FALSE, TRUE }, + { L"Wait", WORKER_FACTORY_WAIT, FALSE, TRUE }, + { L"Set information", WORKER_FACTORY_SET_INFORMATION, FALSE, TRUE }, + { L"Query information", WORKER_FACTORY_QUERY_INFORMATION, FALSE, TRUE }, + { L"Shutdown", WORKER_FACTORY_SHUTDOWN, FALSE, TRUE } +}; + +ACCESS_ENTRIES(Type) +{ + { L"Full control", OBJECT_TYPE_ALL_ACCESS, TRUE, TRUE }, + { L"Create", OBJECT_TYPE_CREATE, TRUE, TRUE } +}; + +ACCESS_ENTRIES(WindowStation) +{ + { L"Full control", WINSTA_ALL_ACCESS | STANDARD_RIGHTS_REQUIRED, TRUE, TRUE }, + { L"Read", WINSTA_GENERIC_READ, TRUE, FALSE }, + { L"Write", WINSTA_GENERIC_WRITE, TRUE, FALSE }, + { L"Execute", WINSTA_GENERIC_EXECUTE, TRUE, FALSE }, + { L"Enumerate", WINSTA_ENUMERATE, FALSE, TRUE }, + { L"Enumerate desktops", WINSTA_ENUMDESKTOPS, FALSE, TRUE }, + { L"Read attributes", WINSTA_READATTRIBUTES, FALSE, TRUE }, + { L"Read screen", WINSTA_READSCREEN, FALSE, TRUE }, + { L"Access clipboard", WINSTA_ACCESSCLIPBOARD, FALSE, TRUE }, + { L"Access global atoms", WINSTA_ACCESSGLOBALATOMS, FALSE, TRUE }, + { L"Create desktop", WINSTA_CREATEDESKTOP, FALSE, TRUE }, + { L"Write attributes", WINSTA_WRITEATTRIBUTES, FALSE, TRUE }, + { L"Exit windows", WINSTA_EXITWINDOWS, FALSE, TRUE } +}; + +ACCESS_ENTRIES(WmiGuid) +{ + { L"Full control", WMIGUID_ALL_ACCESS, TRUE, TRUE }, + { L"Read", WMIGUID_GENERIC_READ, TRUE, FALSE }, + { L"Write", WMIGUID_GENERIC_WRITE, TRUE, FALSE }, + { L"Execute", WMIGUID_GENERIC_EXECUTE, TRUE, FALSE }, + { L"Query information", WMIGUID_QUERY, FALSE, TRUE }, + { L"Set information", WMIGUID_SET, FALSE, TRUE }, + { L"Get notifications", WMIGUID_NOTIFICATION, FALSE, TRUE }, + { L"Read description", WMIGUID_READ_DESCRIPTION, FALSE, TRUE }, + { L"Execute", WMIGUID_EXECUTE, FALSE, TRUE }, + { L"Create real-time logs", TRACELOG_CREATE_REALTIME, FALSE, TRUE, L"Create real-time" }, + { L"Create on disk logs", TRACELOG_CREATE_ONDISK, FALSE, TRUE, L"Create on disk" }, + { L"Enable provider GUIDs", TRACELOG_GUID_ENABLE, FALSE, TRUE, L"Enable GUIDs" }, + { L"Access kernel logger", TRACELOG_ACCESS_KERNEL_LOGGER, FALSE, TRUE }, + { L"Log events", TRACELOG_LOG_EVENT, FALSE, TRUE }, + { L"Access real-time events", TRACELOG_ACCESS_REALTIME, FALSE, TRUE, L"Access real-time" }, + { L"Register provider GUIDs", TRACELOG_REGISTER_GUIDS, FALSE, TRUE, L"Register GUIDs" } +}; + +static PH_SPECIFIC_TYPE PhSpecificTypes[] = +{ + ACCESS_ENTRY(AlpcPort, TRUE), + ACCESS_ENTRY(DebugObject, TRUE), + ACCESS_ENTRY(Desktop, FALSE), + ACCESS_ENTRY(Directory, FALSE), + ACCESS_ENTRY(Event, TRUE), + ACCESS_ENTRY(EventPair, TRUE), + ACCESS_ENTRY(File, TRUE), + ACCESS_ENTRY(FilterConnectionPort, FALSE), + ACCESS_ENTRY(IoCompletion, TRUE), + ACCESS_ENTRY(Job, TRUE), + ACCESS_ENTRY(Key, FALSE), + ACCESS_ENTRY(KeyedEvent, FALSE), + ACCESS_ENTRY(LsaAccount, FALSE), + ACCESS_ENTRY(LsaPolicy, FALSE), + ACCESS_ENTRY(LsaSecret, FALSE), + ACCESS_ENTRY(LsaTrusted, FALSE), + ACCESS_ENTRY(Mutant, TRUE), + ACCESS_ENTRY(Partition, TRUE), + ACCESS_ENTRY(Process, TRUE), + ACCESS_ENTRY(Process60, TRUE), + ACCESS_ENTRY(Profile, FALSE), + ACCESS_ENTRY(SamAlias, FALSE), + ACCESS_ENTRY(SamDomain, FALSE), + ACCESS_ENTRY(SamGroup, FALSE), + ACCESS_ENTRY(SamServer, FALSE), + ACCESS_ENTRY(SamUser, FALSE), + ACCESS_ENTRY(Section, FALSE), + ACCESS_ENTRY(Semaphore, TRUE), + ACCESS_ENTRY(Service, FALSE), + ACCESS_ENTRY(Session, FALSE), + ACCESS_ENTRY(SymbolicLink, FALSE), + ACCESS_ENTRY(Thread, TRUE), + ACCESS_ENTRY(Thread60, TRUE), + ACCESS_ENTRY(Timer, TRUE), + ACCESS_ENTRY(TmEn, FALSE), + ACCESS_ENTRY(TmRm, FALSE), + ACCESS_ENTRY(TmTm, FALSE), + ACCESS_ENTRY(TmTx, FALSE), + ACCESS_ENTRY(Token, FALSE), + ACCESS_ENTRY(TpWorkerFactory, FALSE), + ACCESS_ENTRY(Type, FALSE), + ACCESS_ENTRY(WindowStation, FALSE), + ACCESS_ENTRY(WmiGuid, TRUE) +}; + +/** + * Gets access entries for an object type. + * + * \param Type The name of the object type. + * \param AccessEntries A variable which receives an array of access entry structures. You must free + * the buffer with PhFree() when you no longer need it. + * \param NumberOfAccessEntries A variable which receives the number of access entry structures + * returned in + * \a AccessEntries. + */ +BOOLEAN PhGetAccessEntries( + _In_ PWSTR Type, + _Out_ PPH_ACCESS_ENTRY *AccessEntries, + _Out_ PULONG NumberOfAccessEntries + ) +{ + ULONG i; + PPH_SPECIFIC_TYPE specificType = NULL; + PPH_ACCESS_ENTRY accessEntries; + + if (PhEqualStringZ(Type, L"ALPC Port", TRUE)) + { + Type = L"AlpcPort"; + } + else if (PhEqualStringZ(Type, L"Port", TRUE)) + { + Type = L"AlpcPort"; + } + else if (PhEqualStringZ(Type, L"WaitablePort", TRUE)) + { + Type = L"AlpcPort"; + } + else if (PhEqualStringZ(Type, L"Process", TRUE)) + { + if (WindowsVersion >= WINDOWS_VISTA) + Type = L"Process60"; + } + else if (PhEqualStringZ(Type, L"Thread", TRUE)) + { + if (WindowsVersion >= WINDOWS_VISTA) + Type = L"Thread60"; + } + + // Find the specific type. + for (i = 0; i < sizeof(PhSpecificTypes) / sizeof(PH_SPECIFIC_TYPE); i++) + { + if (PhEqualStringZ(PhSpecificTypes[i].Type, Type, TRUE)) + { + specificType = &PhSpecificTypes[i]; + break; + } + } + + if (specificType) + { + ULONG sizeOfEntries; + + // Copy the specific access entries and append the standard access entries. + + if (specificType->HasSynchronize) + sizeOfEntries = specificType->SizeOfAccessEntries + sizeof(PhStandardAccessEntries); + else + sizeOfEntries = specificType->SizeOfAccessEntries + sizeof(PhStandardAccessEntries) - sizeof(PH_ACCESS_ENTRY); + + accessEntries = PhAllocate(sizeOfEntries); + memcpy(accessEntries, specificType->AccessEntries, specificType->SizeOfAccessEntries); + + if (specificType->HasSynchronize) + { + memcpy( + PTR_ADD_OFFSET(accessEntries, specificType->SizeOfAccessEntries), + PhStandardAccessEntries, + sizeof(PhStandardAccessEntries) + ); + } + else + { + memcpy( + PTR_ADD_OFFSET(accessEntries, specificType->SizeOfAccessEntries), + &PhStandardAccessEntries[1], + sizeof(PhStandardAccessEntries) - sizeof(PH_ACCESS_ENTRY) + ); + } + + *AccessEntries = accessEntries; + *NumberOfAccessEntries = sizeOfEntries / sizeof(PH_ACCESS_ENTRY); + } + else + { + accessEntries = PhAllocate(sizeof(PhStandardAccessEntries)); + memcpy(accessEntries, PhStandardAccessEntries, sizeof(PhStandardAccessEntries)); + + *AccessEntries = accessEntries; + *NumberOfAccessEntries = sizeof(PhStandardAccessEntries) / sizeof(PH_ACCESS_ENTRY); + } + + return TRUE; +} + +static int __cdecl PhpAccessEntryCompare( + _In_ const void *elem1, + _In_ const void *elem2 + ) +{ + PPH_ACCESS_ENTRY entry1 = (PPH_ACCESS_ENTRY)elem1; + PPH_ACCESS_ENTRY entry2 = (PPH_ACCESS_ENTRY)elem2; + + return intcmp(PhCountBits(entry2->Access), PhCountBits(entry1->Access)); +} + +/** + * Creates a string representation of an access mask. + * + * \param Access The access mask. + * \param AccessEntries An array of access entry structures. You can call PhGetAccessEntries() to + * retrieve the access entry structures for a standard object type. + * \param NumberOfAccessEntries The number of elements in \a AccessEntries. + * + * \return The string representation of \a Access. + */ +PPH_STRING PhGetAccessString( + _In_ ACCESS_MASK Access, + _In_ PPH_ACCESS_ENTRY AccessEntries, + _In_ ULONG NumberOfAccessEntries + ) +{ + PH_STRING_BUILDER stringBuilder; + PPH_ACCESS_ENTRY accessEntries; + PBOOLEAN matched; + ULONG i; + ULONG j; + + PhInitializeStringBuilder(&stringBuilder, 32); + + // Sort the access entries according to how many access rights they include. + accessEntries = PhAllocateCopy(AccessEntries, NumberOfAccessEntries * sizeof(PH_ACCESS_ENTRY)); + qsort(accessEntries, NumberOfAccessEntries, sizeof(PH_ACCESS_ENTRY), PhpAccessEntryCompare); + + matched = PhAllocate(NumberOfAccessEntries * sizeof(BOOLEAN)); + memset(matched, 0, NumberOfAccessEntries * sizeof(BOOLEAN)); + + for (i = 0; i < NumberOfAccessEntries; i++) + { + // We make sure we haven't matched this access entry yet. This ensures that we won't get + // duplicates, e.g. FILE_GENERIC_READ includes FILE_READ_DATA, and we don't want to display + // both to the user. + if ( + !matched[i] && + ((Access & accessEntries[i].Access) == accessEntries[i].Access) + ) + { + if (accessEntries[i].ShortName) + PhAppendStringBuilder2(&stringBuilder, accessEntries[i].ShortName); + else + PhAppendStringBuilder2(&stringBuilder, accessEntries[i].Name); + + PhAppendStringBuilder2(&stringBuilder, L", "); + + // Disable equal or more specific entries. + for (j = i; j < NumberOfAccessEntries; j++) + { + if ((accessEntries[i].Access | accessEntries[j].Access) == accessEntries[i].Access) + matched[j] = TRUE; + } + } + } + + // Remove the trailing ", ". + if (PhEndsWithString2(stringBuilder.String, L", ", FALSE)) + PhRemoveEndStringBuilder(&stringBuilder, 2); + + PhFree(matched); + PhFree(accessEntries); + + return PhFinalStringBuilderString(&stringBuilder); +} diff --git a/phlib/secedit.c b/phlib/secedit.c index d1641425a106..f1c09a04cb80 100644 --- a/phlib/secedit.c +++ b/phlib/secedit.c @@ -1,577 +1,577 @@ -/* - * Process Hacker - - * object security editor - * - * Copyright (C) 2010-2016 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include -#include - -#include -#include - -#include - -static ISecurityInformationVtbl PhSecurityInformation_VTable = -{ - PhSecurityInformation_QueryInterface, - PhSecurityInformation_AddRef, - PhSecurityInformation_Release, - PhSecurityInformation_GetObjectInformation, - PhSecurityInformation_GetSecurity, - PhSecurityInformation_SetSecurity, - PhSecurityInformation_GetAccessRights, - PhSecurityInformation_MapGeneric, - PhSecurityInformation_GetInheritTypes, - PhSecurityInformation_PropertySheetPageCallback -}; - -/** - * Creates a security editor page. - * - * \param ObjectName The name of the object. - * \param GetObjectSecurity A callback function executed to retrieve the security descriptor of the - * object. - * \param SetObjectSecurity A callback function executed to modify the security descriptor of the - * object. - * \param Context A user-defined value to pass to the callback functions. - * \param AccessEntries An array of access mask descriptors. - * \param NumberOfAccessEntries The number of elements in \a AccessEntries. - */ -HPROPSHEETPAGE PhCreateSecurityPage( - _In_ PWSTR ObjectName, - _In_ PPH_GET_OBJECT_SECURITY GetObjectSecurity, - _In_ PPH_SET_OBJECT_SECURITY SetObjectSecurity, - _In_opt_ PVOID Context, - _In_ PPH_ACCESS_ENTRY AccessEntries, - _In_ ULONG NumberOfAccessEntries - ) -{ - ISecurityInformation *info; - HPROPSHEETPAGE page; - - info = PhSecurityInformation_Create( - ObjectName, - GetObjectSecurity, - SetObjectSecurity, - Context, - AccessEntries, - NumberOfAccessEntries, - TRUE - ); - - page = CreateSecurityPage(info); - - PhSecurityInformation_Release(info); - - return page; -} - -/** - * Displays a security editor dialog. - * - * \param hWnd The parent window of the dialog. - * \param ObjectName The name of the object. - * \param GetObjectSecurity A callback function executed to retrieve the security descriptor of the - * object. - * \param SetObjectSecurity A callback function executed to modify the security descriptor of the - * object. - * \param Context A user-defined value to pass to the callback functions. - * \param AccessEntries An array of access mask descriptors. - * \param NumberOfAccessEntries The number of elements in \a AccessEntries. - */ -VOID PhEditSecurity( - _In_ HWND hWnd, - _In_ PWSTR ObjectName, - _In_ PPH_GET_OBJECT_SECURITY GetObjectSecurity, - _In_ PPH_SET_OBJECT_SECURITY SetObjectSecurity, - _In_opt_ PVOID Context, - _In_ PPH_ACCESS_ENTRY AccessEntries, - _In_ ULONG NumberOfAccessEntries - ) -{ - ISecurityInformation *info; - - info = PhSecurityInformation_Create( - ObjectName, - GetObjectSecurity, - SetObjectSecurity, - Context, - AccessEntries, - NumberOfAccessEntries, - FALSE - ); - - EditSecurity(hWnd, info); - - PhSecurityInformation_Release(info); -} - -ISecurityInformation *PhSecurityInformation_Create( - _In_ PWSTR ObjectName, - _In_ PPH_GET_OBJECT_SECURITY GetObjectSecurity, - _In_ PPH_SET_OBJECT_SECURITY SetObjectSecurity, - _In_opt_ PVOID Context, - _In_ PPH_ACCESS_ENTRY AccessEntries, - _In_ ULONG NumberOfAccessEntries, - _In_ BOOLEAN IsPage - ) -{ - PhSecurityInformation *info; - ULONG i; - - info = PhAllocate(sizeof(PhSecurityInformation)); - info->VTable = &PhSecurityInformation_VTable; - info->RefCount = 1; - - info->ObjectName = PhCreateString(ObjectName); - info->GetObjectSecurity = GetObjectSecurity; - info->SetObjectSecurity = SetObjectSecurity; - info->Context = Context; - info->AccessEntries = PhAllocate(sizeof(SI_ACCESS) * NumberOfAccessEntries); - info->NumberOfAccessEntries = NumberOfAccessEntries; - info->IsPage = IsPage; - - for (i = 0; i < NumberOfAccessEntries; i++) - { - memset(&info->AccessEntries[i], 0, sizeof(SI_ACCESS)); - info->AccessEntries[i].pszName = AccessEntries[i].Name; - info->AccessEntries[i].mask = AccessEntries[i].Access; - - if (AccessEntries[i].General) - info->AccessEntries[i].dwFlags |= SI_ACCESS_GENERAL; - if (AccessEntries[i].Specific) - info->AccessEntries[i].dwFlags |= SI_ACCESS_SPECIFIC; - } - - return (ISecurityInformation *)info; -} - -HRESULT STDMETHODCALLTYPE PhSecurityInformation_QueryInterface( - _In_ ISecurityInformation *This, - _In_ REFIID Riid, - _Out_ PVOID *Object - ) -{ - if ( - IsEqualIID(Riid, &IID_IUnknown) || - IsEqualIID(Riid, &IID_ISecurityInformation) - ) - { - PhSecurityInformation_AddRef(This); - *Object = This; - return S_OK; - } - - *Object = NULL; - return E_NOINTERFACE; -} - -ULONG STDMETHODCALLTYPE PhSecurityInformation_AddRef( - _In_ ISecurityInformation *This - ) -{ - PhSecurityInformation *this = (PhSecurityInformation *)This; - - this->RefCount++; - - return this->RefCount; -} - -ULONG STDMETHODCALLTYPE PhSecurityInformation_Release( - _In_ ISecurityInformation *This - ) -{ - PhSecurityInformation *this = (PhSecurityInformation *)This; - - this->RefCount--; - - if (this->RefCount == 0) - { - if (this->ObjectName) PhDereferenceObject(this->ObjectName); - PhFree(this->AccessEntries); - - PhFree(this); - - return 0; - } - - return this->RefCount; -} - -HRESULT STDMETHODCALLTYPE PhSecurityInformation_GetObjectInformation( - _In_ ISecurityInformation *This, - _Out_ PSI_OBJECT_INFO ObjectInfo - ) -{ - PhSecurityInformation *this = (PhSecurityInformation *)This; - - memset(ObjectInfo, 0, sizeof(SI_OBJECT_INFO)); - ObjectInfo->dwFlags = - SI_EDIT_AUDITS | - SI_EDIT_OWNER | - SI_EDIT_PERMS | - SI_ADVANCED | - SI_NO_ACL_PROTECT | - SI_NO_TREE_APPLY; - ObjectInfo->hInstance = NULL; - ObjectInfo->pszObjectName = this->ObjectName->Buffer; - - return S_OK; -} - -HRESULT STDMETHODCALLTYPE PhSecurityInformation_GetSecurity( - _In_ ISecurityInformation *This, - _In_ SECURITY_INFORMATION RequestedInformation, - _Out_ PSECURITY_DESCRIPTOR *SecurityDescriptor, - _In_ BOOL Default - ) -{ - PhSecurityInformation *this = (PhSecurityInformation *)This; - NTSTATUS status; - PSECURITY_DESCRIPTOR securityDescriptor; - ULONG sdLength; - PSECURITY_DESCRIPTOR newSd; - - status = this->GetObjectSecurity( - &securityDescriptor, - RequestedInformation, - this->Context - ); - - if (!NT_SUCCESS(status)) - return HRESULT_FROM_WIN32(PhNtStatusToDosError(status)); - - sdLength = RtlLengthSecurityDescriptor(securityDescriptor); - newSd = LocalAlloc(0, sdLength); - memcpy(newSd, securityDescriptor, sdLength); - PhFree(securityDescriptor); - - *SecurityDescriptor = newSd; - - return S_OK; -} - -HRESULT STDMETHODCALLTYPE PhSecurityInformation_SetSecurity( - _In_ ISecurityInformation *This, - _In_ SECURITY_INFORMATION SecurityInformation, - _In_ PSECURITY_DESCRIPTOR SecurityDescriptor - ) -{ - PhSecurityInformation *this = (PhSecurityInformation *)This; - NTSTATUS status; - - status = this->SetObjectSecurity( - SecurityDescriptor, - SecurityInformation, - this->Context - ); - - if (!NT_SUCCESS(status)) - return HRESULT_FROM_WIN32(PhNtStatusToDosError(status)); - - return S_OK; -} - -HRESULT STDMETHODCALLTYPE PhSecurityInformation_GetAccessRights( - _In_ ISecurityInformation *This, - _In_ const GUID *ObjectType, - _In_ ULONG Flags, - _Out_ PSI_ACCESS *Access, - _Out_ PULONG Accesses, - _Out_ PULONG DefaultAccess - ) -{ - PhSecurityInformation *this = (PhSecurityInformation *)This; - - *Access = this->AccessEntries; - *Accesses = this->NumberOfAccessEntries; - *DefaultAccess = 0; - - return S_OK; -} - -HRESULT STDMETHODCALLTYPE PhSecurityInformation_MapGeneric( - _In_ ISecurityInformation *This, - _In_ const GUID *ObjectType, - _In_ PUCHAR AceFlags, - _Inout_ PACCESS_MASK Mask - ) -{ - return S_OK; -} - -HRESULT STDMETHODCALLTYPE PhSecurityInformation_GetInheritTypes( - _In_ ISecurityInformation *This, - _Out_ PSI_INHERIT_TYPE *InheritTypes, - _Out_ PULONG InheritTypesCount - ) -{ - return E_NOTIMPL; -} - -HRESULT STDMETHODCALLTYPE PhSecurityInformation_PropertySheetPageCallback( - _In_ ISecurityInformation *This, - _In_ HWND hwnd, - _In_ UINT uMsg, - _In_ SI_PAGE_TYPE uPage - ) -{ - PhSecurityInformation *this = (PhSecurityInformation *)This; - - if (uMsg == PSPCB_SI_INITDIALOG && !this->IsPage) - { - // Center the security editor window. - PhCenterWindow(GetParent(hwnd), GetParent(GetParent(hwnd))); - } - - return E_NOTIMPL; -} - -NTSTATUS PhpGetObjectSecurityWithTimeout( - _In_ HANDLE Handle, - _In_ SECURITY_INFORMATION SecurityInformation, - _Out_ PSECURITY_DESCRIPTOR *SecurityDescriptor - ) -{ - NTSTATUS status; - ULONG bufferSize; - PVOID buffer; - - bufferSize = 0x100; - buffer = PhAllocate(bufferSize); - // This is required (especially for File objects) because some drivers don't seem to handle - // QuerySecurity properly. - memset(buffer, 0, bufferSize); - - status = PhCallNtQuerySecurityObjectWithTimeout( - Handle, - SecurityInformation, - buffer, - bufferSize, - &bufferSize - ); - - if (status == STATUS_BUFFER_TOO_SMALL) - { - PhFree(buffer); - buffer = PhAllocate(bufferSize); - memset(buffer, 0, bufferSize); - - status = PhCallNtQuerySecurityObjectWithTimeout( - Handle, - SecurityInformation, - buffer, - bufferSize, - &bufferSize - ); - } - - if (!NT_SUCCESS(status)) - { - PhFree(buffer); - return status; - } - - *SecurityDescriptor = (PSECURITY_DESCRIPTOR)buffer; - - return status; -} - -/** - * Retrieves the security descriptor of an object. - * - * \param SecurityDescriptor A variable which receives a pointer to the security descriptor of the - * object. The security descriptor must be freed using PhFree() when no longer needed. - * \param SecurityInformation The security information to retrieve. - * \param Context A pointer to a PH_STD_OBJECT_SECURITY structure describing the object. - * - * \remarks This function may be used for the \a GetObjectSecurity callback in - * PhCreateSecurityPage() or PhEditSecurity(). - */ -_Callback_ NTSTATUS PhStdGetObjectSecurity( - _Out_ PSECURITY_DESCRIPTOR *SecurityDescriptor, - _In_ SECURITY_INFORMATION SecurityInformation, - _In_opt_ PVOID Context - ) -{ - NTSTATUS status; - PPH_STD_OBJECT_SECURITY stdObjectSecurity; - HANDLE handle; - - stdObjectSecurity = (PPH_STD_OBJECT_SECURITY)Context; - - status = stdObjectSecurity->OpenObject( - &handle, - PhGetAccessForGetSecurity(SecurityInformation), - stdObjectSecurity->Context - ); - - if (!NT_SUCCESS(status)) - return status; - - if (PhEqualStringZ(stdObjectSecurity->ObjectType, L"Service", TRUE)) - { - status = PhGetSeObjectSecurity(handle, SE_SERVICE, SecurityInformation, SecurityDescriptor); - CloseServiceHandle(handle); - } - else if (PhEqualStringZ(stdObjectSecurity->ObjectType, L"File", TRUE)) - { - status = PhpGetObjectSecurityWithTimeout(handle, SecurityInformation, SecurityDescriptor); - NtClose(handle); - } - else - { - status = PhGetObjectSecurity(handle, SecurityInformation, SecurityDescriptor); - NtClose(handle); - } - - return status; -} - -/** - * Modifies the security descriptor of an object. - * - * \param SecurityDescriptor A security descriptor containing security information to set. - * \param SecurityInformation The security information to retrieve. - * \param Context A pointer to a PH_STD_OBJECT_SECURITY structure describing the object. - * - * \remarks This function may be used for the \a SetObjectSecurity callback in - * PhCreateSecurityPage() or PhEditSecurity(). - */ -_Callback_ NTSTATUS PhStdSetObjectSecurity( - _In_ PSECURITY_DESCRIPTOR SecurityDescriptor, - _In_ SECURITY_INFORMATION SecurityInformation, - _In_opt_ PVOID Context - ) -{ - NTSTATUS status; - PPH_STD_OBJECT_SECURITY stdObjectSecurity; - HANDLE handle; - - stdObjectSecurity = (PPH_STD_OBJECT_SECURITY)Context; - - status = stdObjectSecurity->OpenObject( - &handle, - PhGetAccessForSetSecurity(SecurityInformation), - stdObjectSecurity->Context - ); - - if (!NT_SUCCESS(status)) - return status; - - if (PhEqualStringZ(stdObjectSecurity->ObjectType, L"Service", TRUE)) - { - status = PhSetSeObjectSecurity(handle, SE_SERVICE, SecurityInformation, SecurityDescriptor); - CloseServiceHandle(handle); - } - else - { - status = PhSetObjectSecurity(handle, SecurityInformation, SecurityDescriptor); - NtClose(handle); - } - - return status; -} - -NTSTATUS PhGetSeObjectSecurity( - _In_ HANDLE Handle, - _In_ ULONG ObjectType, - _In_ SECURITY_INFORMATION SecurityInformation, - _Out_ PSECURITY_DESCRIPTOR *SecurityDescriptor - ) -{ - ULONG win32Result; - PSECURITY_DESCRIPTOR securityDescriptor; - - win32Result = GetSecurityInfo( - Handle, - ObjectType, - SecurityInformation, - NULL, - NULL, - NULL, - NULL, - &securityDescriptor - ); - - if (win32Result != ERROR_SUCCESS) - return NTSTATUS_FROM_WIN32(win32Result); - - *SecurityDescriptor = PhAllocateCopy(securityDescriptor, RtlLengthSecurityDescriptor(securityDescriptor)); - LocalFree(securityDescriptor); - - return STATUS_SUCCESS; -} - -NTSTATUS PhSetSeObjectSecurity( - _In_ HANDLE Handle, - _In_ ULONG ObjectType, - _In_ SECURITY_INFORMATION SecurityInformation, - _In_ PSECURITY_DESCRIPTOR SecurityDescriptor - ) -{ - ULONG win32Result; - SECURITY_INFORMATION securityInformation = 0; - BOOLEAN present; - BOOLEAN defaulted; - PSID owner = NULL; - PSID group = NULL; - PACL dacl = NULL; - PACL sacl = NULL; - - if (SecurityInformation & OWNER_SECURITY_INFORMATION) - { - if (NT_SUCCESS(RtlGetOwnerSecurityDescriptor(SecurityDescriptor, &owner, &defaulted))) - securityInformation |= OWNER_SECURITY_INFORMATION; - } - - if (SecurityInformation & GROUP_SECURITY_INFORMATION) - { - if (NT_SUCCESS(RtlGetGroupSecurityDescriptor(SecurityDescriptor, &group, &defaulted))) - securityInformation |= GROUP_SECURITY_INFORMATION; - } - - if (SecurityInformation & DACL_SECURITY_INFORMATION) - { - if (NT_SUCCESS(RtlGetDaclSecurityDescriptor(SecurityDescriptor, &present, &dacl, &defaulted)) && present) - securityInformation |= DACL_SECURITY_INFORMATION; - } - - if (SecurityInformation & SACL_SECURITY_INFORMATION) - { - if (NT_SUCCESS(RtlGetSaclSecurityDescriptor(SecurityDescriptor, &present, &sacl, &defaulted)) && present) - securityInformation |= SACL_SECURITY_INFORMATION; - } - - win32Result = SetSecurityInfo( - Handle, - ObjectType, - SecurityInformation, - owner, - group, - dacl, - sacl - ); - - if (win32Result != ERROR_SUCCESS) - return NTSTATUS_FROM_WIN32(win32Result); - - return STATUS_SUCCESS; -} +/* + * Process Hacker - + * object security editor + * + * Copyright (C) 2010-2016 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include +#include + +#include +#include + +#include + +static ISecurityInformationVtbl PhSecurityInformation_VTable = +{ + PhSecurityInformation_QueryInterface, + PhSecurityInformation_AddRef, + PhSecurityInformation_Release, + PhSecurityInformation_GetObjectInformation, + PhSecurityInformation_GetSecurity, + PhSecurityInformation_SetSecurity, + PhSecurityInformation_GetAccessRights, + PhSecurityInformation_MapGeneric, + PhSecurityInformation_GetInheritTypes, + PhSecurityInformation_PropertySheetPageCallback +}; + +/** + * Creates a security editor page. + * + * \param ObjectName The name of the object. + * \param GetObjectSecurity A callback function executed to retrieve the security descriptor of the + * object. + * \param SetObjectSecurity A callback function executed to modify the security descriptor of the + * object. + * \param Context A user-defined value to pass to the callback functions. + * \param AccessEntries An array of access mask descriptors. + * \param NumberOfAccessEntries The number of elements in \a AccessEntries. + */ +HPROPSHEETPAGE PhCreateSecurityPage( + _In_ PWSTR ObjectName, + _In_ PPH_GET_OBJECT_SECURITY GetObjectSecurity, + _In_ PPH_SET_OBJECT_SECURITY SetObjectSecurity, + _In_opt_ PVOID Context, + _In_ PPH_ACCESS_ENTRY AccessEntries, + _In_ ULONG NumberOfAccessEntries + ) +{ + ISecurityInformation *info; + HPROPSHEETPAGE page; + + info = PhSecurityInformation_Create( + ObjectName, + GetObjectSecurity, + SetObjectSecurity, + Context, + AccessEntries, + NumberOfAccessEntries, + TRUE + ); + + page = CreateSecurityPage(info); + + PhSecurityInformation_Release(info); + + return page; +} + +/** + * Displays a security editor dialog. + * + * \param hWnd The parent window of the dialog. + * \param ObjectName The name of the object. + * \param GetObjectSecurity A callback function executed to retrieve the security descriptor of the + * object. + * \param SetObjectSecurity A callback function executed to modify the security descriptor of the + * object. + * \param Context A user-defined value to pass to the callback functions. + * \param AccessEntries An array of access mask descriptors. + * \param NumberOfAccessEntries The number of elements in \a AccessEntries. + */ +VOID PhEditSecurity( + _In_ HWND hWnd, + _In_ PWSTR ObjectName, + _In_ PPH_GET_OBJECT_SECURITY GetObjectSecurity, + _In_ PPH_SET_OBJECT_SECURITY SetObjectSecurity, + _In_opt_ PVOID Context, + _In_ PPH_ACCESS_ENTRY AccessEntries, + _In_ ULONG NumberOfAccessEntries + ) +{ + ISecurityInformation *info; + + info = PhSecurityInformation_Create( + ObjectName, + GetObjectSecurity, + SetObjectSecurity, + Context, + AccessEntries, + NumberOfAccessEntries, + FALSE + ); + + EditSecurity(hWnd, info); + + PhSecurityInformation_Release(info); +} + +ISecurityInformation *PhSecurityInformation_Create( + _In_ PWSTR ObjectName, + _In_ PPH_GET_OBJECT_SECURITY GetObjectSecurity, + _In_ PPH_SET_OBJECT_SECURITY SetObjectSecurity, + _In_opt_ PVOID Context, + _In_ PPH_ACCESS_ENTRY AccessEntries, + _In_ ULONG NumberOfAccessEntries, + _In_ BOOLEAN IsPage + ) +{ + PhSecurityInformation *info; + ULONG i; + + info = PhAllocate(sizeof(PhSecurityInformation)); + info->VTable = &PhSecurityInformation_VTable; + info->RefCount = 1; + + info->ObjectName = PhCreateString(ObjectName); + info->GetObjectSecurity = GetObjectSecurity; + info->SetObjectSecurity = SetObjectSecurity; + info->Context = Context; + info->AccessEntries = PhAllocate(sizeof(SI_ACCESS) * NumberOfAccessEntries); + info->NumberOfAccessEntries = NumberOfAccessEntries; + info->IsPage = IsPage; + + for (i = 0; i < NumberOfAccessEntries; i++) + { + memset(&info->AccessEntries[i], 0, sizeof(SI_ACCESS)); + info->AccessEntries[i].pszName = AccessEntries[i].Name; + info->AccessEntries[i].mask = AccessEntries[i].Access; + + if (AccessEntries[i].General) + info->AccessEntries[i].dwFlags |= SI_ACCESS_GENERAL; + if (AccessEntries[i].Specific) + info->AccessEntries[i].dwFlags |= SI_ACCESS_SPECIFIC; + } + + return (ISecurityInformation *)info; +} + +HRESULT STDMETHODCALLTYPE PhSecurityInformation_QueryInterface( + _In_ ISecurityInformation *This, + _In_ REFIID Riid, + _Out_ PVOID *Object + ) +{ + if ( + IsEqualIID(Riid, &IID_IUnknown) || + IsEqualIID(Riid, &IID_ISecurityInformation) + ) + { + PhSecurityInformation_AddRef(This); + *Object = This; + return S_OK; + } + + *Object = NULL; + return E_NOINTERFACE; +} + +ULONG STDMETHODCALLTYPE PhSecurityInformation_AddRef( + _In_ ISecurityInformation *This + ) +{ + PhSecurityInformation *this = (PhSecurityInformation *)This; + + this->RefCount++; + + return this->RefCount; +} + +ULONG STDMETHODCALLTYPE PhSecurityInformation_Release( + _In_ ISecurityInformation *This + ) +{ + PhSecurityInformation *this = (PhSecurityInformation *)This; + + this->RefCount--; + + if (this->RefCount == 0) + { + if (this->ObjectName) PhDereferenceObject(this->ObjectName); + PhFree(this->AccessEntries); + + PhFree(this); + + return 0; + } + + return this->RefCount; +} + +HRESULT STDMETHODCALLTYPE PhSecurityInformation_GetObjectInformation( + _In_ ISecurityInformation *This, + _Out_ PSI_OBJECT_INFO ObjectInfo + ) +{ + PhSecurityInformation *this = (PhSecurityInformation *)This; + + memset(ObjectInfo, 0, sizeof(SI_OBJECT_INFO)); + ObjectInfo->dwFlags = + SI_EDIT_AUDITS | + SI_EDIT_OWNER | + SI_EDIT_PERMS | + SI_ADVANCED | + SI_NO_ACL_PROTECT | + SI_NO_TREE_APPLY; + ObjectInfo->hInstance = NULL; + ObjectInfo->pszObjectName = this->ObjectName->Buffer; + + return S_OK; +} + +HRESULT STDMETHODCALLTYPE PhSecurityInformation_GetSecurity( + _In_ ISecurityInformation *This, + _In_ SECURITY_INFORMATION RequestedInformation, + _Out_ PSECURITY_DESCRIPTOR *SecurityDescriptor, + _In_ BOOL Default + ) +{ + PhSecurityInformation *this = (PhSecurityInformation *)This; + NTSTATUS status; + PSECURITY_DESCRIPTOR securityDescriptor; + ULONG sdLength; + PSECURITY_DESCRIPTOR newSd; + + status = this->GetObjectSecurity( + &securityDescriptor, + RequestedInformation, + this->Context + ); + + if (!NT_SUCCESS(status)) + return HRESULT_FROM_WIN32(PhNtStatusToDosError(status)); + + sdLength = RtlLengthSecurityDescriptor(securityDescriptor); + newSd = LocalAlloc(0, sdLength); + memcpy(newSd, securityDescriptor, sdLength); + PhFree(securityDescriptor); + + *SecurityDescriptor = newSd; + + return S_OK; +} + +HRESULT STDMETHODCALLTYPE PhSecurityInformation_SetSecurity( + _In_ ISecurityInformation *This, + _In_ SECURITY_INFORMATION SecurityInformation, + _In_ PSECURITY_DESCRIPTOR SecurityDescriptor + ) +{ + PhSecurityInformation *this = (PhSecurityInformation *)This; + NTSTATUS status; + + status = this->SetObjectSecurity( + SecurityDescriptor, + SecurityInformation, + this->Context + ); + + if (!NT_SUCCESS(status)) + return HRESULT_FROM_WIN32(PhNtStatusToDosError(status)); + + return S_OK; +} + +HRESULT STDMETHODCALLTYPE PhSecurityInformation_GetAccessRights( + _In_ ISecurityInformation *This, + _In_ const GUID *ObjectType, + _In_ ULONG Flags, + _Out_ PSI_ACCESS *Access, + _Out_ PULONG Accesses, + _Out_ PULONG DefaultAccess + ) +{ + PhSecurityInformation *this = (PhSecurityInformation *)This; + + *Access = this->AccessEntries; + *Accesses = this->NumberOfAccessEntries; + *DefaultAccess = 0; + + return S_OK; +} + +HRESULT STDMETHODCALLTYPE PhSecurityInformation_MapGeneric( + _In_ ISecurityInformation *This, + _In_ const GUID *ObjectType, + _In_ PUCHAR AceFlags, + _Inout_ PACCESS_MASK Mask + ) +{ + return S_OK; +} + +HRESULT STDMETHODCALLTYPE PhSecurityInformation_GetInheritTypes( + _In_ ISecurityInformation *This, + _Out_ PSI_INHERIT_TYPE *InheritTypes, + _Out_ PULONG InheritTypesCount + ) +{ + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE PhSecurityInformation_PropertySheetPageCallback( + _In_ ISecurityInformation *This, + _In_ HWND hwnd, + _In_ UINT uMsg, + _In_ SI_PAGE_TYPE uPage + ) +{ + PhSecurityInformation *this = (PhSecurityInformation *)This; + + if (uMsg == PSPCB_SI_INITDIALOG && !this->IsPage) + { + // Center the security editor window. + PhCenterWindow(GetParent(hwnd), GetParent(GetParent(hwnd))); + } + + return E_NOTIMPL; +} + +NTSTATUS PhpGetObjectSecurityWithTimeout( + _In_ HANDLE Handle, + _In_ SECURITY_INFORMATION SecurityInformation, + _Out_ PSECURITY_DESCRIPTOR *SecurityDescriptor + ) +{ + NTSTATUS status; + ULONG bufferSize; + PVOID buffer; + + bufferSize = 0x100; + buffer = PhAllocate(bufferSize); + // This is required (especially for File objects) because some drivers don't seem to handle + // QuerySecurity properly. + memset(buffer, 0, bufferSize); + + status = PhCallNtQuerySecurityObjectWithTimeout( + Handle, + SecurityInformation, + buffer, + bufferSize, + &bufferSize + ); + + if (status == STATUS_BUFFER_TOO_SMALL) + { + PhFree(buffer); + buffer = PhAllocate(bufferSize); + memset(buffer, 0, bufferSize); + + status = PhCallNtQuerySecurityObjectWithTimeout( + Handle, + SecurityInformation, + buffer, + bufferSize, + &bufferSize + ); + } + + if (!NT_SUCCESS(status)) + { + PhFree(buffer); + return status; + } + + *SecurityDescriptor = (PSECURITY_DESCRIPTOR)buffer; + + return status; +} + +/** + * Retrieves the security descriptor of an object. + * + * \param SecurityDescriptor A variable which receives a pointer to the security descriptor of the + * object. The security descriptor must be freed using PhFree() when no longer needed. + * \param SecurityInformation The security information to retrieve. + * \param Context A pointer to a PH_STD_OBJECT_SECURITY structure describing the object. + * + * \remarks This function may be used for the \a GetObjectSecurity callback in + * PhCreateSecurityPage() or PhEditSecurity(). + */ +_Callback_ NTSTATUS PhStdGetObjectSecurity( + _Out_ PSECURITY_DESCRIPTOR *SecurityDescriptor, + _In_ SECURITY_INFORMATION SecurityInformation, + _In_opt_ PVOID Context + ) +{ + NTSTATUS status; + PPH_STD_OBJECT_SECURITY stdObjectSecurity; + HANDLE handle; + + stdObjectSecurity = (PPH_STD_OBJECT_SECURITY)Context; + + status = stdObjectSecurity->OpenObject( + &handle, + PhGetAccessForGetSecurity(SecurityInformation), + stdObjectSecurity->Context + ); + + if (!NT_SUCCESS(status)) + return status; + + if (PhEqualStringZ(stdObjectSecurity->ObjectType, L"Service", TRUE)) + { + status = PhGetSeObjectSecurity(handle, SE_SERVICE, SecurityInformation, SecurityDescriptor); + CloseServiceHandle(handle); + } + else if (PhEqualStringZ(stdObjectSecurity->ObjectType, L"File", TRUE)) + { + status = PhpGetObjectSecurityWithTimeout(handle, SecurityInformation, SecurityDescriptor); + NtClose(handle); + } + else + { + status = PhGetObjectSecurity(handle, SecurityInformation, SecurityDescriptor); + NtClose(handle); + } + + return status; +} + +/** + * Modifies the security descriptor of an object. + * + * \param SecurityDescriptor A security descriptor containing security information to set. + * \param SecurityInformation The security information to retrieve. + * \param Context A pointer to a PH_STD_OBJECT_SECURITY structure describing the object. + * + * \remarks This function may be used for the \a SetObjectSecurity callback in + * PhCreateSecurityPage() or PhEditSecurity(). + */ +_Callback_ NTSTATUS PhStdSetObjectSecurity( + _In_ PSECURITY_DESCRIPTOR SecurityDescriptor, + _In_ SECURITY_INFORMATION SecurityInformation, + _In_opt_ PVOID Context + ) +{ + NTSTATUS status; + PPH_STD_OBJECT_SECURITY stdObjectSecurity; + HANDLE handle; + + stdObjectSecurity = (PPH_STD_OBJECT_SECURITY)Context; + + status = stdObjectSecurity->OpenObject( + &handle, + PhGetAccessForSetSecurity(SecurityInformation), + stdObjectSecurity->Context + ); + + if (!NT_SUCCESS(status)) + return status; + + if (PhEqualStringZ(stdObjectSecurity->ObjectType, L"Service", TRUE)) + { + status = PhSetSeObjectSecurity(handle, SE_SERVICE, SecurityInformation, SecurityDescriptor); + CloseServiceHandle(handle); + } + else + { + status = PhSetObjectSecurity(handle, SecurityInformation, SecurityDescriptor); + NtClose(handle); + } + + return status; +} + +NTSTATUS PhGetSeObjectSecurity( + _In_ HANDLE Handle, + _In_ ULONG ObjectType, + _In_ SECURITY_INFORMATION SecurityInformation, + _Out_ PSECURITY_DESCRIPTOR *SecurityDescriptor + ) +{ + ULONG win32Result; + PSECURITY_DESCRIPTOR securityDescriptor; + + win32Result = GetSecurityInfo( + Handle, + ObjectType, + SecurityInformation, + NULL, + NULL, + NULL, + NULL, + &securityDescriptor + ); + + if (win32Result != ERROR_SUCCESS) + return NTSTATUS_FROM_WIN32(win32Result); + + *SecurityDescriptor = PhAllocateCopy(securityDescriptor, RtlLengthSecurityDescriptor(securityDescriptor)); + LocalFree(securityDescriptor); + + return STATUS_SUCCESS; +} + +NTSTATUS PhSetSeObjectSecurity( + _In_ HANDLE Handle, + _In_ ULONG ObjectType, + _In_ SECURITY_INFORMATION SecurityInformation, + _In_ PSECURITY_DESCRIPTOR SecurityDescriptor + ) +{ + ULONG win32Result; + SECURITY_INFORMATION securityInformation = 0; + BOOLEAN present; + BOOLEAN defaulted; + PSID owner = NULL; + PSID group = NULL; + PACL dacl = NULL; + PACL sacl = NULL; + + if (SecurityInformation & OWNER_SECURITY_INFORMATION) + { + if (NT_SUCCESS(RtlGetOwnerSecurityDescriptor(SecurityDescriptor, &owner, &defaulted))) + securityInformation |= OWNER_SECURITY_INFORMATION; + } + + if (SecurityInformation & GROUP_SECURITY_INFORMATION) + { + if (NT_SUCCESS(RtlGetGroupSecurityDescriptor(SecurityDescriptor, &group, &defaulted))) + securityInformation |= GROUP_SECURITY_INFORMATION; + } + + if (SecurityInformation & DACL_SECURITY_INFORMATION) + { + if (NT_SUCCESS(RtlGetDaclSecurityDescriptor(SecurityDescriptor, &present, &dacl, &defaulted)) && present) + securityInformation |= DACL_SECURITY_INFORMATION; + } + + if (SecurityInformation & SACL_SECURITY_INFORMATION) + { + if (NT_SUCCESS(RtlGetSaclSecurityDescriptor(SecurityDescriptor, &present, &sacl, &defaulted)) && present) + securityInformation |= SACL_SECURITY_INFORMATION; + } + + win32Result = SetSecurityInfo( + Handle, + ObjectType, + SecurityInformation, + owner, + group, + dacl, + sacl + ); + + if (win32Result != ERROR_SUCCESS) + return NTSTATUS_FROM_WIN32(win32Result); + + return STATUS_SUCCESS; +} diff --git a/phlib/sha.c b/phlib/sha.c index 00cc9bd5a292..6b69ddee5c18 100644 --- a/phlib/sha.c +++ b/phlib/sha.c @@ -1,172 +1,172 @@ -/* - * Copyright 2004 Filip Navara - * Based on public domain SHA code by Steve Reid - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -/* This code was modified for Process Hacker. */ - -#include -#include "sha.h" - -/* SHA1 Helper Macros */ - -//#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) -#define rol(value, bits) (_rotl((value), (bits))) -#define DWORD2BE(x) (((x) >> 24) & 0xff) | (((x) >> 8) & 0xff00) | (((x) << 8) & 0xff0000) | (((x) << 24) & 0xff000000); -#define blk0(i) (Block[i] = (rol(Block[i],24)&0xFF00FF00)|(rol(Block[i],8)&0x00FF00FF)) -#define blk1(i) (Block[i&15] = rol(Block[(i+13)&15]^Block[(i+8)&15]^Block[(i+2)&15]^Block[i&15],1)) -#define f1(x,y,z) (z^(x&(y^z))) -#define f2(x,y,z) (x^y^z) -#define f3(x,y,z) ((x&y)|(z&(x|y))) -#define f4(x,y,z) (x^y^z) -/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ -#define R0(v,w,x,y,z,i) z+=f1(w,x,y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30); -#define R1(v,w,x,y,z,i) z+=f1(w,x,y)+blk1(i)+0x5A827999+rol(v,5);w=rol(w,30); -#define R2(v,w,x,y,z,i) z+=f2(w,x,y)+blk1(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30); -#define R3(v,w,x,y,z,i) z+=f3(w,x,y)+blk1(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30); -#define R4(v,w,x,y,z,i) z+=f4(w,x,y)+blk1(i)+0xCA62C1D6+rol(v,5);w=rol(w,30); - -/* Hash a single 512-bit block. This is the core of the algorithm. */ -static void SHATransform(ULONG State[5], UCHAR Buffer[64]) -{ - ULONG a, b, c, d, e; - ULONG *Block; - - Block = (ULONG*)Buffer; - - /* Copy Context->State[] to working variables */ - a = State[0]; - b = State[1]; - c = State[2]; - d = State[3]; - e = State[4]; - - /* 4 rounds of 20 operations each. Loop unrolled. */ - R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3); - R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7); - R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11); - R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15); - R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19); - R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23); - R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27); - R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31); - R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35); - R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39); - R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43); - R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47); - R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51); - R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55); - R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59); - R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63); - R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67); - R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71); - R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75); - R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79); - - /* Add the working variables back into Context->State[] */ - State[0] += a; - State[1] += b; - State[2] += c; - State[3] += d; - State[4] += e; - - /* Wipe variables */ - a = b = c = d = e = 0; -} - -VOID A_SHAInit( - _Out_ A_SHA_CTX *Context - ) -{ - /* SHA1 initialization constants */ - Context->state[0] = 0x67452301; - Context->state[1] = 0xEFCDAB89; - Context->state[2] = 0x98BADCFE; - Context->state[3] = 0x10325476; - Context->state[4] = 0xC3D2E1F0; - Context->count[0] = 0; - Context->count[1] = 0; -} - -VOID A_SHAUpdate( - _Inout_ A_SHA_CTX *Context, - _In_reads_bytes_(Length) UCHAR *Input, - _In_ ULONG Length - ) -{ - ULONG InputContentSize; - - InputContentSize = Context->count[1] & 63; - Context->count[1] += Length; - if (Context->count[1] < Length) - Context->count[0]++; - Context->count[0] += (Length >> 29); - - if (InputContentSize + Length < 64) - { - RtlCopyMemory(&Context->buffer[InputContentSize], Input, - Length); - } - else - { - while (InputContentSize + Length >= 64) - { - RtlCopyMemory(Context->buffer + InputContentSize, Input, - 64 - InputContentSize); - Input += 64 - InputContentSize; - Length -= 64 - InputContentSize; - SHATransform(Context->state, Context->buffer); - InputContentSize = 0; - } - RtlCopyMemory(Context->buffer + InputContentSize, Input, Length); - } -} - -VOID A_SHAFinal( - _Inout_ A_SHA_CTX *Context, - _Out_writes_bytes_(20) UCHAR *Hash - ) -{ - INT Pad, Index; - UCHAR Buffer[72]; - ULONG *Count; - ULONG BufferContentSize, LengthHi, LengthLo; - ULONG *Result; - - BufferContentSize = Context->count[1] & 63; - if (BufferContentSize >= 56) - Pad = 56 + 64 - BufferContentSize; - else - Pad = 56 - BufferContentSize; - - LengthHi = (Context->count[0] << 3) | (Context->count[1] >> (32 - 3)); - LengthLo = (Context->count[1] << 3); - - RtlZeroMemory(Buffer + 1, Pad - 1); - Buffer[0] = 0x80; - Count = (ULONG*)(Buffer + Pad); - Count[0] = DWORD2BE(LengthHi); - Count[1] = DWORD2BE(LengthLo); - A_SHAUpdate(Context, Buffer, Pad + 8); - - Result = (ULONG *)Hash; - - for (Index = 0; Index < 5; Index++) - Result[Index] = DWORD2BE(Context->state[Index]); - - A_SHAInit(Context); -} +/* + * Copyright 2004 Filip Navara + * Based on public domain SHA code by Steve Reid + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +/* This code was modified for Process Hacker. */ + +#include +#include "sha.h" + +/* SHA1 Helper Macros */ + +//#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) +#define rol(value, bits) (_rotl((value), (bits))) +#define DWORD2BE(x) (((x) >> 24) & 0xff) | (((x) >> 8) & 0xff00) | (((x) << 8) & 0xff0000) | (((x) << 24) & 0xff000000); +#define blk0(i) (Block[i] = (rol(Block[i],24)&0xFF00FF00)|(rol(Block[i],8)&0x00FF00FF)) +#define blk1(i) (Block[i&15] = rol(Block[(i+13)&15]^Block[(i+8)&15]^Block[(i+2)&15]^Block[i&15],1)) +#define f1(x,y,z) (z^(x&(y^z))) +#define f2(x,y,z) (x^y^z) +#define f3(x,y,z) ((x&y)|(z&(x|y))) +#define f4(x,y,z) (x^y^z) +/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ +#define R0(v,w,x,y,z,i) z+=f1(w,x,y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30); +#define R1(v,w,x,y,z,i) z+=f1(w,x,y)+blk1(i)+0x5A827999+rol(v,5);w=rol(w,30); +#define R2(v,w,x,y,z,i) z+=f2(w,x,y)+blk1(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30); +#define R3(v,w,x,y,z,i) z+=f3(w,x,y)+blk1(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30); +#define R4(v,w,x,y,z,i) z+=f4(w,x,y)+blk1(i)+0xCA62C1D6+rol(v,5);w=rol(w,30); + +/* Hash a single 512-bit block. This is the core of the algorithm. */ +static void SHATransform(ULONG State[5], UCHAR Buffer[64]) +{ + ULONG a, b, c, d, e; + ULONG *Block; + + Block = (ULONG*)Buffer; + + /* Copy Context->State[] to working variables */ + a = State[0]; + b = State[1]; + c = State[2]; + d = State[3]; + e = State[4]; + + /* 4 rounds of 20 operations each. Loop unrolled. */ + R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3); + R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7); + R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11); + R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15); + R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19); + R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23); + R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27); + R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31); + R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35); + R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39); + R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43); + R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47); + R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51); + R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55); + R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59); + R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63); + R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67); + R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71); + R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75); + R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79); + + /* Add the working variables back into Context->State[] */ + State[0] += a; + State[1] += b; + State[2] += c; + State[3] += d; + State[4] += e; + + /* Wipe variables */ + a = b = c = d = e = 0; +} + +VOID A_SHAInit( + _Out_ A_SHA_CTX *Context + ) +{ + /* SHA1 initialization constants */ + Context->state[0] = 0x67452301; + Context->state[1] = 0xEFCDAB89; + Context->state[2] = 0x98BADCFE; + Context->state[3] = 0x10325476; + Context->state[4] = 0xC3D2E1F0; + Context->count[0] = 0; + Context->count[1] = 0; +} + +VOID A_SHAUpdate( + _Inout_ A_SHA_CTX *Context, + _In_reads_bytes_(Length) UCHAR *Input, + _In_ ULONG Length + ) +{ + ULONG InputContentSize; + + InputContentSize = Context->count[1] & 63; + Context->count[1] += Length; + if (Context->count[1] < Length) + Context->count[0]++; + Context->count[0] += (Length >> 29); + + if (InputContentSize + Length < 64) + { + RtlCopyMemory(&Context->buffer[InputContentSize], Input, + Length); + } + else + { + while (InputContentSize + Length >= 64) + { + RtlCopyMemory(Context->buffer + InputContentSize, Input, + 64 - InputContentSize); + Input += 64 - InputContentSize; + Length -= 64 - InputContentSize; + SHATransform(Context->state, Context->buffer); + InputContentSize = 0; + } + RtlCopyMemory(Context->buffer + InputContentSize, Input, Length); + } +} + +VOID A_SHAFinal( + _Inout_ A_SHA_CTX *Context, + _Out_writes_bytes_(20) UCHAR *Hash + ) +{ + INT Pad, Index; + UCHAR Buffer[72]; + ULONG *Count; + ULONG BufferContentSize, LengthHi, LengthLo; + ULONG *Result; + + BufferContentSize = Context->count[1] & 63; + if (BufferContentSize >= 56) + Pad = 56 + 64 - BufferContentSize; + else + Pad = 56 - BufferContentSize; + + LengthHi = (Context->count[0] << 3) | (Context->count[1] >> (32 - 3)); + LengthLo = (Context->count[1] << 3); + + RtlZeroMemory(Buffer + 1, Pad - 1); + Buffer[0] = 0x80; + Count = (ULONG*)(Buffer + Pad); + Count[0] = DWORD2BE(LengthHi); + Count[1] = DWORD2BE(LengthLo); + A_SHAUpdate(Context, Buffer, Pad + 8); + + Result = (ULONG *)Hash; + + for (Index = 0; Index < 5; Index++) + Result[Index] = DWORD2BE(Context->state[Index]); + + A_SHAInit(Context); +} diff --git a/phlib/svcsup.c b/phlib/svcsup.c index 2df8df0baa6b..cd796658aca7 100644 --- a/phlib/svcsup.c +++ b/phlib/svcsup.c @@ -1,554 +1,554 @@ -/* - * Process Hacker - - * service support functions - * - * Copyright (C) 2010-2012 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include - -#include - -#include - -#define SIP(String, Integer) { (String), (PVOID)(Integer) } - -static PH_KEY_VALUE_PAIR PhpServiceStatePairs[] = -{ - SIP(L"Stopped", SERVICE_STOPPED), - SIP(L"Start pending", SERVICE_START_PENDING), - SIP(L"Stop pending", SERVICE_STOP_PENDING), - SIP(L"Running", SERVICE_RUNNING), - SIP(L"Continue pending", SERVICE_CONTINUE_PENDING), - SIP(L"Pause pending", SERVICE_PAUSE_PENDING), - SIP(L"Paused", SERVICE_PAUSED) -}; - -static PH_KEY_VALUE_PAIR PhpServiceTypePairs[] = -{ - SIP(L"Driver", SERVICE_KERNEL_DRIVER), - SIP(L"FS driver", SERVICE_FILE_SYSTEM_DRIVER), - SIP(L"Own process", SERVICE_WIN32_OWN_PROCESS), - SIP(L"Share process", SERVICE_WIN32_SHARE_PROCESS), - SIP(L"Own interactive process", SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS), - SIP(L"Share interactive process", SERVICE_WIN32_SHARE_PROCESS | SERVICE_INTERACTIVE_PROCESS), - SIP(L"User own process", SERVICE_USER_OWN_PROCESS), - SIP(L"User own process (instance)", SERVICE_USER_OWN_PROCESS | SERVICE_USERSERVICE_INSTANCE), - SIP(L"User share process", SERVICE_USER_SHARE_PROCESS), - SIP(L"User share process (instance)", SERVICE_USER_SHARE_PROCESS | SERVICE_USERSERVICE_INSTANCE), -}; - -static PH_KEY_VALUE_PAIR PhpServiceStartTypePairs[] = -{ - SIP(L"Disabled", SERVICE_DISABLED), - SIP(L"Boot start", SERVICE_BOOT_START), - SIP(L"System start", SERVICE_SYSTEM_START), - SIP(L"Auto start", SERVICE_AUTO_START), - SIP(L"Demand start", SERVICE_DEMAND_START) -}; - -static PH_KEY_VALUE_PAIR PhpServiceErrorControlPairs[] = -{ - SIP(L"Ignore", SERVICE_ERROR_IGNORE), - SIP(L"Normal", SERVICE_ERROR_NORMAL), - SIP(L"Severe", SERVICE_ERROR_SEVERE), - SIP(L"Critical", SERVICE_ERROR_CRITICAL) -}; - -WCHAR *PhServiceTypeStrings[10] = { L"Driver", L"FS driver", L"Own process", L"Share process", - L"Own interactive process", L"Share interactive process", L"User own process", L"User own process (instance)", - L"User share process", L"User share process (instance)" }; -WCHAR *PhServiceStartTypeStrings[5] = { L"Disabled", L"Boot start", L"System start", - L"Auto start", L"Demand start" }; -WCHAR *PhServiceErrorControlStrings[4] = { L"Ignore", L"Normal", L"Severe", L"Critical" }; - -PVOID PhEnumServices( - _In_ SC_HANDLE ScManagerHandle, - _In_opt_ ULONG Type, - _In_opt_ ULONG State, - _Out_ PULONG Count - ) -{ - static ULONG initialBufferSize = 0x8000; - LOGICAL result; - PVOID buffer; - ULONG bufferSize; - ULONG returnLength; - ULONG servicesReturned; - - if (!Type) - { - if (WindowsVersion >= WINDOWS_10) - { - if (PhOsVersion.dwBuildNumber >= 14393) - { - Type = SERVICE_TYPE_ALL; - } - else - { - Type = SERVICE_WIN32 | - SERVICE_ADAPTER | - SERVICE_DRIVER | - SERVICE_INTERACTIVE_PROCESS | - SERVICE_USER_SERVICE | - SERVICE_USERSERVICE_INSTANCE; - } - } - else - { - Type = SERVICE_DRIVER | SERVICE_WIN32; - } - } - - if (!State) - State = SERVICE_STATE_ALL; - - bufferSize = initialBufferSize; - buffer = PhAllocate(bufferSize); - - if (!(result = EnumServicesStatusEx( - ScManagerHandle, - SC_ENUM_PROCESS_INFO, - Type, - State, - buffer, - bufferSize, - &returnLength, - &servicesReturned, - NULL, - NULL - ))) - { - if (GetLastError() == ERROR_MORE_DATA) - { - PhFree(buffer); - bufferSize += returnLength; - buffer = PhAllocate(bufferSize); - - result = EnumServicesStatusEx( - ScManagerHandle, - SC_ENUM_PROCESS_INFO, - Type, - State, - buffer, - bufferSize, - &returnLength, - &servicesReturned, - NULL, - NULL - ); - } - - if (!result) - { - PhFree(buffer); - return NULL; - } - } - - if (bufferSize <= 0x20000) initialBufferSize = bufferSize; - *Count = servicesReturned; - - return buffer; -} - -SC_HANDLE PhOpenService( - _In_ PWSTR ServiceName, - _In_ ACCESS_MASK DesiredAccess - ) -{ - SC_HANDLE scManagerHandle; - SC_HANDLE serviceHandle; - - scManagerHandle = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT); - - if (!scManagerHandle) - return NULL; - - serviceHandle = OpenService(scManagerHandle, ServiceName, DesiredAccess); - CloseServiceHandle(scManagerHandle); - - return serviceHandle; -} - -PVOID PhGetServiceConfig( - _In_ SC_HANDLE ServiceHandle - ) -{ - PVOID buffer; - ULONG bufferSize = 0x200; - - buffer = PhAllocate(bufferSize); - - if (!QueryServiceConfig(ServiceHandle, buffer, bufferSize, &bufferSize)) - { - PhFree(buffer); - buffer = PhAllocate(bufferSize); - - if (!QueryServiceConfig(ServiceHandle, buffer, bufferSize, &bufferSize)) - { - PhFree(buffer); - return NULL; - } - } - - return buffer; -} - -PVOID PhQueryServiceVariableSize( - _In_ SC_HANDLE ServiceHandle, - _In_ ULONG InfoLevel - ) -{ - PVOID buffer; - ULONG bufferSize = 0x100; - - buffer = PhAllocate(bufferSize); - - if (!QueryServiceConfig2( - ServiceHandle, - InfoLevel, - (BYTE *)buffer, - bufferSize, - &bufferSize - )) - { - PhFree(buffer); - buffer = PhAllocate(bufferSize); - - if (!QueryServiceConfig2( - ServiceHandle, - InfoLevel, - (BYTE *)buffer, - bufferSize, - &bufferSize - )) - { - PhFree(buffer); - return NULL; - } - } - - return buffer; -} - -PPH_STRING PhGetServiceDescription( - _In_ SC_HANDLE ServiceHandle - ) -{ - PPH_STRING description = NULL; - LPSERVICE_DESCRIPTION serviceDescription; - - serviceDescription = PhQueryServiceVariableSize(ServiceHandle, SERVICE_CONFIG_DESCRIPTION); - - if (serviceDescription) - { - if (serviceDescription->lpDescription) - description = PhCreateString(serviceDescription->lpDescription); - - PhFree(serviceDescription); - - return description; - } - else - { - return NULL; - } -} - -BOOLEAN PhGetServiceDelayedAutoStart( - _In_ SC_HANDLE ServiceHandle, - _Out_ PBOOLEAN DelayedAutoStart - ) -{ - SERVICE_DELAYED_AUTO_START_INFO delayedAutoStartInfo; - ULONG returnLength; - - if (QueryServiceConfig2( - ServiceHandle, - SERVICE_CONFIG_DELAYED_AUTO_START_INFO, - (BYTE *)&delayedAutoStartInfo, - sizeof(SERVICE_DELAYED_AUTO_START_INFO), - &returnLength - )) - { - *DelayedAutoStart = !!delayedAutoStartInfo.fDelayedAutostart; - return TRUE; - } - else - { - return FALSE; - } -} - -BOOLEAN PhSetServiceDelayedAutoStart( - _In_ SC_HANDLE ServiceHandle, - _In_ BOOLEAN DelayedAutoStart - ) -{ - SERVICE_DELAYED_AUTO_START_INFO delayedAutoStartInfo; - - delayedAutoStartInfo.fDelayedAutostart = DelayedAutoStart; - - return !!ChangeServiceConfig2( - ServiceHandle, - SERVICE_CONFIG_DELAYED_AUTO_START_INFO, - &delayedAutoStartInfo - ); -} - -PWSTR PhGetServiceStateString( - _In_ ULONG ServiceState - ) -{ - PWSTR string; - - if (PhFindStringSiKeyValuePairs( - PhpServiceStatePairs, - sizeof(PhpServiceStatePairs), - ServiceState, - &string - )) - return string; - else - return L"Unknown"; -} - -PWSTR PhGetServiceTypeString( - _In_ ULONG ServiceType - ) -{ - PWSTR string; - - if (PhFindStringSiKeyValuePairs( - PhpServiceTypePairs, - sizeof(PhpServiceTypePairs), - ServiceType, - &string - )) - return string; - else - return L"Unknown"; -} - -ULONG PhGetServiceTypeInteger( - _In_ PWSTR ServiceType - ) -{ - ULONG integer; - - if (PhFindIntegerSiKeyValuePairs( - PhpServiceTypePairs, - sizeof(PhpServiceTypePairs), - ServiceType, - &integer - )) - return integer; - else - return -1; -} - -PWSTR PhGetServiceStartTypeString( - _In_ ULONG ServiceStartType - ) -{ - PWSTR string; - - if (PhFindStringSiKeyValuePairs( - PhpServiceStartTypePairs, - sizeof(PhpServiceStartTypePairs), - ServiceStartType, - &string - )) - return string; - else - return L"Unknown"; -} - -ULONG PhGetServiceStartTypeInteger( - _In_ PWSTR ServiceStartType - ) -{ - ULONG integer; - - if (PhFindIntegerSiKeyValuePairs( - PhpServiceStartTypePairs, - sizeof(PhpServiceStartTypePairs), - ServiceStartType, - &integer - )) - return integer; - else - return -1; -} - -PWSTR PhGetServiceErrorControlString( - _In_ ULONG ServiceErrorControl - ) -{ - PWSTR string; - - if (PhFindStringSiKeyValuePairs( - PhpServiceErrorControlPairs, - sizeof(PhpServiceErrorControlPairs), - ServiceErrorControl, - &string - )) - return string; - else - return L"Unknown"; -} - -ULONG PhGetServiceErrorControlInteger( - _In_ PWSTR ServiceErrorControl - ) -{ - ULONG integer; - - if (PhFindIntegerSiKeyValuePairs( - PhpServiceErrorControlPairs, - sizeof(PhpServiceErrorControlPairs), - ServiceErrorControl, - &integer - )) - return integer; - else - return -1; -} - -PPH_STRING PhGetServiceNameFromTag( - _In_ HANDLE ProcessId, - _In_ PVOID ServiceTag - ) -{ - static PQUERY_TAG_INFORMATION I_QueryTagInformation = NULL; - PPH_STRING serviceName = NULL; - TAG_INFO_NAME_FROM_TAG nameFromTag; - - if (!I_QueryTagInformation) - { - I_QueryTagInformation = PhGetModuleProcAddress(L"advapi32.dll", "I_QueryTagInformation"); - - if (!I_QueryTagInformation) - return NULL; - } - - memset(&nameFromTag, 0, sizeof(TAG_INFO_NAME_FROM_TAG)); - nameFromTag.InParams.dwPid = HandleToUlong(ProcessId); - nameFromTag.InParams.dwTag = PtrToUlong(ServiceTag); - - I_QueryTagInformation(NULL, eTagInfoLevelNameFromTag, &nameFromTag); - - if (nameFromTag.OutParams.pszName) - { - serviceName = PhCreateString(nameFromTag.OutParams.pszName); - LocalFree(nameFromTag.OutParams.pszName); - } - - return serviceName; -} - -NTSTATUS PhGetThreadServiceTag( - _In_ HANDLE ThreadHandle, - _In_opt_ HANDLE ProcessHandle, - _Out_ PVOID *ServiceTag - ) -{ - NTSTATUS status; - THREAD_BASIC_INFORMATION basicInfo; - BOOLEAN openedProcessHandle = FALSE; - - if (!NT_SUCCESS(status = PhGetThreadBasicInformation(ThreadHandle, &basicInfo))) - return status; - - if (!ProcessHandle) - { - if (!NT_SUCCESS(status = PhOpenThreadProcess( - ThreadHandle, - PROCESS_VM_READ, - &ProcessHandle - ))) - return status; - - openedProcessHandle = TRUE; - } - - status = NtReadVirtualMemory( - ProcessHandle, - PTR_ADD_OFFSET(basicInfo.TebBaseAddress, FIELD_OFFSET(TEB, SubProcessTag)), - ServiceTag, - sizeof(PVOID), - NULL - ); - - if (openedProcessHandle) - NtClose(ProcessHandle); - - return status; -} - -NTSTATUS PhGetServiceDllParameter( - _In_ PPH_STRINGREF ServiceName, - _Out_ PPH_STRING *ServiceDll - ) -{ - static PH_STRINGREF servicesKeyName = PH_STRINGREF_INIT(L"System\\CurrentControlSet\\Services\\"); - static PH_STRINGREF parameters = PH_STRINGREF_INIT(L"\\Parameters"); - - NTSTATUS status; - HANDLE keyHandle; - PPH_STRING keyName; - - keyName = PhConcatStringRef3(&servicesKeyName, ServiceName, ¶meters); - - if (NT_SUCCESS(status = PhOpenKey( - &keyHandle, - KEY_READ, - PH_KEY_LOCAL_MACHINE, - &keyName->sr, - 0 - ))) - { - PPH_STRING serviceDllString; - - if (serviceDllString = PhQueryRegistryString(keyHandle, L"ServiceDll")) - { - PPH_STRING expandedString; - - if (expandedString = PhExpandEnvironmentStrings(&serviceDllString->sr)) - { - *ServiceDll = expandedString; - PhDereferenceObject(serviceDllString); - } - else - { - *ServiceDll = serviceDllString; - } - } - else - { - status = STATUS_NOT_FOUND; - } - - NtClose(keyHandle); - } - - PhDereferenceObject(keyName); - - return status; -} +/* + * Process Hacker - + * service support functions + * + * Copyright (C) 2010-2012 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include + +#include + +#include + +#define SIP(String, Integer) { (String), (PVOID)(Integer) } + +static PH_KEY_VALUE_PAIR PhpServiceStatePairs[] = +{ + SIP(L"Stopped", SERVICE_STOPPED), + SIP(L"Start pending", SERVICE_START_PENDING), + SIP(L"Stop pending", SERVICE_STOP_PENDING), + SIP(L"Running", SERVICE_RUNNING), + SIP(L"Continue pending", SERVICE_CONTINUE_PENDING), + SIP(L"Pause pending", SERVICE_PAUSE_PENDING), + SIP(L"Paused", SERVICE_PAUSED) +}; + +static PH_KEY_VALUE_PAIR PhpServiceTypePairs[] = +{ + SIP(L"Driver", SERVICE_KERNEL_DRIVER), + SIP(L"FS driver", SERVICE_FILE_SYSTEM_DRIVER), + SIP(L"Own process", SERVICE_WIN32_OWN_PROCESS), + SIP(L"Share process", SERVICE_WIN32_SHARE_PROCESS), + SIP(L"Own interactive process", SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS), + SIP(L"Share interactive process", SERVICE_WIN32_SHARE_PROCESS | SERVICE_INTERACTIVE_PROCESS), + SIP(L"User own process", SERVICE_USER_OWN_PROCESS), + SIP(L"User own process (instance)", SERVICE_USER_OWN_PROCESS | SERVICE_USERSERVICE_INSTANCE), + SIP(L"User share process", SERVICE_USER_SHARE_PROCESS), + SIP(L"User share process (instance)", SERVICE_USER_SHARE_PROCESS | SERVICE_USERSERVICE_INSTANCE), +}; + +static PH_KEY_VALUE_PAIR PhpServiceStartTypePairs[] = +{ + SIP(L"Disabled", SERVICE_DISABLED), + SIP(L"Boot start", SERVICE_BOOT_START), + SIP(L"System start", SERVICE_SYSTEM_START), + SIP(L"Auto start", SERVICE_AUTO_START), + SIP(L"Demand start", SERVICE_DEMAND_START) +}; + +static PH_KEY_VALUE_PAIR PhpServiceErrorControlPairs[] = +{ + SIP(L"Ignore", SERVICE_ERROR_IGNORE), + SIP(L"Normal", SERVICE_ERROR_NORMAL), + SIP(L"Severe", SERVICE_ERROR_SEVERE), + SIP(L"Critical", SERVICE_ERROR_CRITICAL) +}; + +WCHAR *PhServiceTypeStrings[10] = { L"Driver", L"FS driver", L"Own process", L"Share process", + L"Own interactive process", L"Share interactive process", L"User own process", L"User own process (instance)", + L"User share process", L"User share process (instance)" }; +WCHAR *PhServiceStartTypeStrings[5] = { L"Disabled", L"Boot start", L"System start", + L"Auto start", L"Demand start" }; +WCHAR *PhServiceErrorControlStrings[4] = { L"Ignore", L"Normal", L"Severe", L"Critical" }; + +PVOID PhEnumServices( + _In_ SC_HANDLE ScManagerHandle, + _In_opt_ ULONG Type, + _In_opt_ ULONG State, + _Out_ PULONG Count + ) +{ + static ULONG initialBufferSize = 0x8000; + LOGICAL result; + PVOID buffer; + ULONG bufferSize; + ULONG returnLength; + ULONG servicesReturned; + + if (!Type) + { + if (WindowsVersion >= WINDOWS_10) + { + if (PhOsVersion.dwBuildNumber >= 14393) + { + Type = SERVICE_TYPE_ALL; + } + else + { + Type = SERVICE_WIN32 | + SERVICE_ADAPTER | + SERVICE_DRIVER | + SERVICE_INTERACTIVE_PROCESS | + SERVICE_USER_SERVICE | + SERVICE_USERSERVICE_INSTANCE; + } + } + else + { + Type = SERVICE_DRIVER | SERVICE_WIN32; + } + } + + if (!State) + State = SERVICE_STATE_ALL; + + bufferSize = initialBufferSize; + buffer = PhAllocate(bufferSize); + + if (!(result = EnumServicesStatusEx( + ScManagerHandle, + SC_ENUM_PROCESS_INFO, + Type, + State, + buffer, + bufferSize, + &returnLength, + &servicesReturned, + NULL, + NULL + ))) + { + if (GetLastError() == ERROR_MORE_DATA) + { + PhFree(buffer); + bufferSize += returnLength; + buffer = PhAllocate(bufferSize); + + result = EnumServicesStatusEx( + ScManagerHandle, + SC_ENUM_PROCESS_INFO, + Type, + State, + buffer, + bufferSize, + &returnLength, + &servicesReturned, + NULL, + NULL + ); + } + + if (!result) + { + PhFree(buffer); + return NULL; + } + } + + if (bufferSize <= 0x20000) initialBufferSize = bufferSize; + *Count = servicesReturned; + + return buffer; +} + +SC_HANDLE PhOpenService( + _In_ PWSTR ServiceName, + _In_ ACCESS_MASK DesiredAccess + ) +{ + SC_HANDLE scManagerHandle; + SC_HANDLE serviceHandle; + + scManagerHandle = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT); + + if (!scManagerHandle) + return NULL; + + serviceHandle = OpenService(scManagerHandle, ServiceName, DesiredAccess); + CloseServiceHandle(scManagerHandle); + + return serviceHandle; +} + +PVOID PhGetServiceConfig( + _In_ SC_HANDLE ServiceHandle + ) +{ + PVOID buffer; + ULONG bufferSize = 0x200; + + buffer = PhAllocate(bufferSize); + + if (!QueryServiceConfig(ServiceHandle, buffer, bufferSize, &bufferSize)) + { + PhFree(buffer); + buffer = PhAllocate(bufferSize); + + if (!QueryServiceConfig(ServiceHandle, buffer, bufferSize, &bufferSize)) + { + PhFree(buffer); + return NULL; + } + } + + return buffer; +} + +PVOID PhQueryServiceVariableSize( + _In_ SC_HANDLE ServiceHandle, + _In_ ULONG InfoLevel + ) +{ + PVOID buffer; + ULONG bufferSize = 0x100; + + buffer = PhAllocate(bufferSize); + + if (!QueryServiceConfig2( + ServiceHandle, + InfoLevel, + (BYTE *)buffer, + bufferSize, + &bufferSize + )) + { + PhFree(buffer); + buffer = PhAllocate(bufferSize); + + if (!QueryServiceConfig2( + ServiceHandle, + InfoLevel, + (BYTE *)buffer, + bufferSize, + &bufferSize + )) + { + PhFree(buffer); + return NULL; + } + } + + return buffer; +} + +PPH_STRING PhGetServiceDescription( + _In_ SC_HANDLE ServiceHandle + ) +{ + PPH_STRING description = NULL; + LPSERVICE_DESCRIPTION serviceDescription; + + serviceDescription = PhQueryServiceVariableSize(ServiceHandle, SERVICE_CONFIG_DESCRIPTION); + + if (serviceDescription) + { + if (serviceDescription->lpDescription) + description = PhCreateString(serviceDescription->lpDescription); + + PhFree(serviceDescription); + + return description; + } + else + { + return NULL; + } +} + +BOOLEAN PhGetServiceDelayedAutoStart( + _In_ SC_HANDLE ServiceHandle, + _Out_ PBOOLEAN DelayedAutoStart + ) +{ + SERVICE_DELAYED_AUTO_START_INFO delayedAutoStartInfo; + ULONG returnLength; + + if (QueryServiceConfig2( + ServiceHandle, + SERVICE_CONFIG_DELAYED_AUTO_START_INFO, + (BYTE *)&delayedAutoStartInfo, + sizeof(SERVICE_DELAYED_AUTO_START_INFO), + &returnLength + )) + { + *DelayedAutoStart = !!delayedAutoStartInfo.fDelayedAutostart; + return TRUE; + } + else + { + return FALSE; + } +} + +BOOLEAN PhSetServiceDelayedAutoStart( + _In_ SC_HANDLE ServiceHandle, + _In_ BOOLEAN DelayedAutoStart + ) +{ + SERVICE_DELAYED_AUTO_START_INFO delayedAutoStartInfo; + + delayedAutoStartInfo.fDelayedAutostart = DelayedAutoStart; + + return !!ChangeServiceConfig2( + ServiceHandle, + SERVICE_CONFIG_DELAYED_AUTO_START_INFO, + &delayedAutoStartInfo + ); +} + +PWSTR PhGetServiceStateString( + _In_ ULONG ServiceState + ) +{ + PWSTR string; + + if (PhFindStringSiKeyValuePairs( + PhpServiceStatePairs, + sizeof(PhpServiceStatePairs), + ServiceState, + &string + )) + return string; + else + return L"Unknown"; +} + +PWSTR PhGetServiceTypeString( + _In_ ULONG ServiceType + ) +{ + PWSTR string; + + if (PhFindStringSiKeyValuePairs( + PhpServiceTypePairs, + sizeof(PhpServiceTypePairs), + ServiceType, + &string + )) + return string; + else + return L"Unknown"; +} + +ULONG PhGetServiceTypeInteger( + _In_ PWSTR ServiceType + ) +{ + ULONG integer; + + if (PhFindIntegerSiKeyValuePairs( + PhpServiceTypePairs, + sizeof(PhpServiceTypePairs), + ServiceType, + &integer + )) + return integer; + else + return -1; +} + +PWSTR PhGetServiceStartTypeString( + _In_ ULONG ServiceStartType + ) +{ + PWSTR string; + + if (PhFindStringSiKeyValuePairs( + PhpServiceStartTypePairs, + sizeof(PhpServiceStartTypePairs), + ServiceStartType, + &string + )) + return string; + else + return L"Unknown"; +} + +ULONG PhGetServiceStartTypeInteger( + _In_ PWSTR ServiceStartType + ) +{ + ULONG integer; + + if (PhFindIntegerSiKeyValuePairs( + PhpServiceStartTypePairs, + sizeof(PhpServiceStartTypePairs), + ServiceStartType, + &integer + )) + return integer; + else + return -1; +} + +PWSTR PhGetServiceErrorControlString( + _In_ ULONG ServiceErrorControl + ) +{ + PWSTR string; + + if (PhFindStringSiKeyValuePairs( + PhpServiceErrorControlPairs, + sizeof(PhpServiceErrorControlPairs), + ServiceErrorControl, + &string + )) + return string; + else + return L"Unknown"; +} + +ULONG PhGetServiceErrorControlInteger( + _In_ PWSTR ServiceErrorControl + ) +{ + ULONG integer; + + if (PhFindIntegerSiKeyValuePairs( + PhpServiceErrorControlPairs, + sizeof(PhpServiceErrorControlPairs), + ServiceErrorControl, + &integer + )) + return integer; + else + return -1; +} + +PPH_STRING PhGetServiceNameFromTag( + _In_ HANDLE ProcessId, + _In_ PVOID ServiceTag + ) +{ + static PQUERY_TAG_INFORMATION I_QueryTagInformation = NULL; + PPH_STRING serviceName = NULL; + TAG_INFO_NAME_FROM_TAG nameFromTag; + + if (!I_QueryTagInformation) + { + I_QueryTagInformation = PhGetModuleProcAddress(L"advapi32.dll", "I_QueryTagInformation"); + + if (!I_QueryTagInformation) + return NULL; + } + + memset(&nameFromTag, 0, sizeof(TAG_INFO_NAME_FROM_TAG)); + nameFromTag.InParams.dwPid = HandleToUlong(ProcessId); + nameFromTag.InParams.dwTag = PtrToUlong(ServiceTag); + + I_QueryTagInformation(NULL, eTagInfoLevelNameFromTag, &nameFromTag); + + if (nameFromTag.OutParams.pszName) + { + serviceName = PhCreateString(nameFromTag.OutParams.pszName); + LocalFree(nameFromTag.OutParams.pszName); + } + + return serviceName; +} + +NTSTATUS PhGetThreadServiceTag( + _In_ HANDLE ThreadHandle, + _In_opt_ HANDLE ProcessHandle, + _Out_ PVOID *ServiceTag + ) +{ + NTSTATUS status; + THREAD_BASIC_INFORMATION basicInfo; + BOOLEAN openedProcessHandle = FALSE; + + if (!NT_SUCCESS(status = PhGetThreadBasicInformation(ThreadHandle, &basicInfo))) + return status; + + if (!ProcessHandle) + { + if (!NT_SUCCESS(status = PhOpenThreadProcess( + ThreadHandle, + PROCESS_VM_READ, + &ProcessHandle + ))) + return status; + + openedProcessHandle = TRUE; + } + + status = NtReadVirtualMemory( + ProcessHandle, + PTR_ADD_OFFSET(basicInfo.TebBaseAddress, FIELD_OFFSET(TEB, SubProcessTag)), + ServiceTag, + sizeof(PVOID), + NULL + ); + + if (openedProcessHandle) + NtClose(ProcessHandle); + + return status; +} + +NTSTATUS PhGetServiceDllParameter( + _In_ PPH_STRINGREF ServiceName, + _Out_ PPH_STRING *ServiceDll + ) +{ + static PH_STRINGREF servicesKeyName = PH_STRINGREF_INIT(L"System\\CurrentControlSet\\Services\\"); + static PH_STRINGREF parameters = PH_STRINGREF_INIT(L"\\Parameters"); + + NTSTATUS status; + HANDLE keyHandle; + PPH_STRING keyName; + + keyName = PhConcatStringRef3(&servicesKeyName, ServiceName, ¶meters); + + if (NT_SUCCESS(status = PhOpenKey( + &keyHandle, + KEY_READ, + PH_KEY_LOCAL_MACHINE, + &keyName->sr, + 0 + ))) + { + PPH_STRING serviceDllString; + + if (serviceDllString = PhQueryRegistryString(keyHandle, L"ServiceDll")) + { + PPH_STRING expandedString; + + if (expandedString = PhExpandEnvironmentStrings(&serviceDllString->sr)) + { + *ServiceDll = expandedString; + PhDereferenceObject(serviceDllString); + } + else + { + *ServiceDll = serviceDllString; + } + } + else + { + status = STATUS_NOT_FOUND; + } + + NtClose(keyHandle); + } + + PhDereferenceObject(keyName); + + return status; +} diff --git a/phlib/symprv.c b/phlib/symprv.c index 633be28a2d33..837c92c65efb 100644 --- a/phlib/symprv.c +++ b/phlib/symprv.c @@ -1,1760 +1,1760 @@ -/* - * Process Hacker - - * symbol provider - * - * Copyright (C) 2010-2015 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include -#include - -#include - -#include -#include -#include - -#include - -typedef struct _PH_SYMBOL_MODULE -{ - LIST_ENTRY ListEntry; - PH_AVL_LINKS Links; - ULONG64 BaseAddress; - ULONG Size; - PPH_STRING FileName; - ULONG BaseNameIndex; -} PH_SYMBOL_MODULE, *PPH_SYMBOL_MODULE; - -VOID NTAPI PhpSymbolProviderDeleteProcedure( - _In_ PVOID Object, - _In_ ULONG Flags - ); - -VOID PhpRegisterSymbolProvider( - _In_opt_ PPH_SYMBOL_PROVIDER SymbolProvider - ); - -VOID PhpFreeSymbolModule( - _In_ PPH_SYMBOL_MODULE SymbolModule - ); - -LONG NTAPI PhpSymbolModuleCompareFunction( - _In_ PPH_AVL_LINKS Links1, - _In_ PPH_AVL_LINKS Links2 - ); - -PPH_OBJECT_TYPE PhSymbolProviderType; - -static PH_INITONCE PhSymInitOnce = PH_INITONCE_INIT; -DECLSPEC_SELECTANY PH_CALLBACK_DECLARE(PhSymInitCallback); - -static HANDLE PhNextFakeHandle = (HANDLE)0; -static PH_FAST_LOCK PhSymMutex = PH_FAST_LOCK_INIT; - -#define PH_LOCK_SYMBOLS() PhAcquireFastLockExclusive(&PhSymMutex) -#define PH_UNLOCK_SYMBOLS() PhReleaseFastLockExclusive(&PhSymMutex) - -_SymInitialize SymInitialize_I; -_SymCleanup SymCleanup_I; -_SymEnumSymbols SymEnumSymbols_I; -_SymEnumSymbolsW SymEnumSymbolsW_I; -_SymFromAddr SymFromAddr_I; -_SymFromAddrW SymFromAddrW_I; -_SymFromName SymFromName_I; -_SymFromNameW SymFromNameW_I; -_SymGetLineFromAddr64 SymGetLineFromAddr64_I; -_SymGetLineFromAddrW64 SymGetLineFromAddrW64_I; -_SymLoadModule64 SymLoadModule64_I; -_SymLoadModuleExW SymLoadModuleExW_I; -_SymGetOptions SymGetOptions_I; -_SymSetOptions SymSetOptions_I; -_SymGetSearchPath SymGetSearchPath_I; -_SymGetSearchPathW SymGetSearchPathW_I; -_SymSetSearchPath SymSetSearchPath_I; -_SymSetSearchPathW SymSetSearchPathW_I; -_SymUnloadModule64 SymUnloadModule64_I; -_SymFunctionTableAccess64 SymFunctionTableAccess64_I; -_SymGetModuleBase64 SymGetModuleBase64_I; -_SymRegisterCallbackW64 SymRegisterCallbackW64_I; -_StackWalk64 StackWalk64_I; -_MiniDumpWriteDump MiniDumpWriteDump_I; -_SymbolServerGetOptions SymbolServerGetOptions; -_SymbolServerSetOptions SymbolServerSetOptions; - -BOOLEAN PhSymbolProviderInitialization( - VOID - ) -{ - PhSymbolProviderType = PhCreateObjectType(L"SymbolProvider", 0, PhpSymbolProviderDeleteProcedure); - - return TRUE; -} - -VOID PhSymbolProviderCompleteInitialization( - _In_opt_ PVOID DbgHelpBase - ) -{ - HMODULE dbghelpHandle; - HMODULE symsrvHandle; - - // The user should have loaded dbghelp.dll and symsrv.dll already. If not, it's not our problem. - - // The Unicode versions aren't available in dbghelp.dll 5.1, so we fallback on the ANSI versions. - - if (DbgHelpBase) - dbghelpHandle = DbgHelpBase; - else - dbghelpHandle = GetModuleHandle(L"dbghelp.dll"); - - symsrvHandle = GetModuleHandle(L"symsrv.dll"); - - SymInitialize_I = PhGetProcedureAddress(dbghelpHandle, "SymInitialize", 0); - SymCleanup_I = PhGetProcedureAddress(dbghelpHandle, "SymCleanup", 0); - if (!(SymEnumSymbolsW_I = PhGetProcedureAddress(dbghelpHandle, "SymEnumSymbolsW", 0))) - SymEnumSymbols_I = PhGetProcedureAddress(dbghelpHandle, "SymEnumSymbols", 0); - if (!(SymFromAddrW_I = PhGetProcedureAddress(dbghelpHandle, "SymFromAddrW", 0))) - SymFromAddr_I = PhGetProcedureAddress(dbghelpHandle, "SymFromAddr", 0); - if (!(SymFromNameW_I = PhGetProcedureAddress(dbghelpHandle, "SymFromNameW", 0))) - SymFromName_I = PhGetProcedureAddress(dbghelpHandle, "SymFromName", 0); - if (!(SymGetLineFromAddrW64_I = PhGetProcedureAddress(dbghelpHandle, "SymGetLineFromAddrW64", 0))) - SymGetLineFromAddr64_I = PhGetProcedureAddress(dbghelpHandle, "SymGetLineFromAddr64", 0); - if (!(SymLoadModuleExW_I = PhGetProcedureAddress(dbghelpHandle, "SymLoadModuleExW", 0))) - SymLoadModule64_I = PhGetProcedureAddress(dbghelpHandle, "SymLoadModule64", 0); - SymGetOptions_I = PhGetProcedureAddress(dbghelpHandle, "SymGetOptions", 0); - SymSetOptions_I = PhGetProcedureAddress(dbghelpHandle, "SymSetOptions", 0); - if (!(SymGetSearchPathW_I = PhGetProcedureAddress(dbghelpHandle, "SymGetSearchPathW", 0))) - SymGetSearchPath_I = PhGetProcedureAddress(dbghelpHandle, "SymGetSearchPath", 0); - if (!(SymSetSearchPathW_I = PhGetProcedureAddress(dbghelpHandle, "SymSetSearchPathW", 0))) - SymSetSearchPath_I = PhGetProcedureAddress(dbghelpHandle, "SymSetSearchPath", 0); - SymUnloadModule64_I = PhGetProcedureAddress(dbghelpHandle, "SymUnloadModule64", 0); - SymFunctionTableAccess64_I = PhGetProcedureAddress(dbghelpHandle, "SymFunctionTableAccess64", 0); - SymGetModuleBase64_I = PhGetProcedureAddress(dbghelpHandle, "SymGetModuleBase64", 0); - SymRegisterCallbackW64_I = PhGetProcedureAddress(dbghelpHandle, "SymRegisterCallbackW64", 0); - StackWalk64_I = PhGetProcedureAddress(dbghelpHandle, "StackWalk64", 0); - MiniDumpWriteDump_I = PhGetProcedureAddress(dbghelpHandle, "MiniDumpWriteDump", 0); - SymbolServerGetOptions = PhGetProcedureAddress(symsrvHandle, "SymbolServerGetOptions", 0); - SymbolServerSetOptions = PhGetProcedureAddress(symsrvHandle, "SymbolServerSetOptions", 0); - - if (SymGetOptions_I && SymSetOptions_I) - SymSetOptions_I(SymGetOptions_I() | SYMOPT_DEFERRED_LOADS | SYMOPT_FAVOR_COMPRESSED); -} - -PPH_SYMBOL_PROVIDER PhCreateSymbolProvider( - _In_opt_ HANDLE ProcessId - ) -{ - PPH_SYMBOL_PROVIDER symbolProvider; - - symbolProvider = PhCreateObject(sizeof(PH_SYMBOL_PROVIDER), PhSymbolProviderType); - memset(symbolProvider, 0, sizeof(PH_SYMBOL_PROVIDER)); - InitializeListHead(&symbolProvider->ModulesListHead); - PhInitializeQueuedLock(&symbolProvider->ModulesListLock); - PhInitializeAvlTree(&symbolProvider->ModulesSet, PhpSymbolModuleCompareFunction); - PhInitializeCallback(&symbolProvider->EventCallback); - PhInitializeInitOnce(&symbolProvider->InitOnce); - - if (ProcessId) - { - static ACCESS_MASK accesses[] = - { - STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xfff, // pre-Vista full access - PROCESS_QUERY_INFORMATION | PROCESS_VM_READ | PROCESS_DUP_HANDLE, - PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, - MAXIMUM_ALLOWED - }; - - ULONG i; - - // Try to open the process with many different accesses. - // This handle will be re-used when walking stacks, and doing various other things. - for (i = 0; i < sizeof(accesses) / sizeof(ACCESS_MASK); i++) - { - if (NT_SUCCESS(PhOpenProcess(&symbolProvider->ProcessHandle, accesses[i], ProcessId))) - { - symbolProvider->IsRealHandle = TRUE; - break; - } - } - } - - if (!symbolProvider->IsRealHandle) - { - HANDLE fakeHandle; - - // Just generate a fake handle. - fakeHandle = (HANDLE)_InterlockedExchangeAddPointer((PLONG_PTR)&PhNextFakeHandle, 4); - // Add one to make sure it isn't divisible by 4 (so it can't be mistaken for a real handle). - symbolProvider->ProcessHandle = (HANDLE)((ULONG_PTR)fakeHandle + 1); - } - - return symbolProvider; -} - -VOID NTAPI PhpSymbolProviderDeleteProcedure( - _In_ PVOID Object, - _In_ ULONG Flags - ) -{ - PPH_SYMBOL_PROVIDER symbolProvider = (PPH_SYMBOL_PROVIDER)Object; - PLIST_ENTRY listEntry; - - PhDeleteCallback(&symbolProvider->EventCallback); - - if (SymCleanup_I) - { - PH_LOCK_SYMBOLS(); - - if (symbolProvider->IsRegistered) - SymCleanup_I(symbolProvider->ProcessHandle); - - PH_UNLOCK_SYMBOLS(); - } - - listEntry = symbolProvider->ModulesListHead.Flink; - - while (listEntry != &symbolProvider->ModulesListHead) - { - PPH_SYMBOL_MODULE module; - - module = CONTAINING_RECORD(listEntry, PH_SYMBOL_MODULE, ListEntry); - listEntry = listEntry->Flink; - - PhpFreeSymbolModule(module); - } - - if (symbolProvider->IsRealHandle) NtClose(symbolProvider->ProcessHandle); -} - -NTSTATUS PhpSymbolCallbackWorker( - _In_ PVOID Parameter - ) -{ - PPH_SYMBOL_EVENT_DATA data = Parameter; - - dprintf("symbol event %d: %S\n", data->Type, data->FileName->Buffer); - PhInvokeCallback(&data->SymbolProvider->EventCallback, data); - PhClearReference(&data->FileName); - PhDereferenceObject(data); - - return STATUS_SUCCESS; -} - -BOOL CALLBACK PhpSymbolCallbackFunction( - _In_ HANDLE hProcess, - _In_ ULONG ActionCode, - _In_opt_ ULONG64 CallbackData, - _In_opt_ ULONG64 UserContext - ) -{ - PPH_SYMBOL_PROVIDER symbolProvider = (PPH_SYMBOL_PROVIDER)UserContext; - PPH_SYMBOL_EVENT_DATA data; - PIMAGEHLP_DEFERRED_SYMBOL_LOADW64 callbackData; - - if (!IsListEmpty(&symbolProvider->EventCallback.ListHead)) - { - switch (ActionCode) - { - case SymbolDeferredSymbolLoadStart: - case SymbolDeferredSymbolLoadComplete: - case SymbolDeferredSymbolLoadFailure: - case SymbolSymbolsUnloaded: - case SymbolDeferredSymbolLoadCancel: - data = PhCreateAlloc(sizeof(PH_SYMBOL_EVENT_DATA)); - memset(data, 0, sizeof(PH_SYMBOL_EVENT_DATA)); - data->SymbolProvider = symbolProvider; - data->Type = ActionCode; - - if (ActionCode != SymbolSymbolsUnloaded) - { - callbackData = (PIMAGEHLP_DEFERRED_SYMBOL_LOADW64)CallbackData; - data->BaseAddress = callbackData->BaseOfImage; - data->CheckSum = callbackData->CheckSum; - data->TimeStamp = callbackData->TimeDateStamp; - data->FileName = PhCreateString(callbackData->FileName); - } - - PhQueueItemWorkQueue(PhGetGlobalWorkQueue(), PhpSymbolCallbackWorker, data); - - break; - } - } - - return FALSE; -} - -VOID PhpRegisterSymbolProvider( - _In_opt_ PPH_SYMBOL_PROVIDER SymbolProvider - ) -{ - if (PhBeginInitOnce(&PhSymInitOnce)) - { - PhInvokeCallback(&PhSymInitCallback, NULL); - PhEndInitOnce(&PhSymInitOnce); - } - - if (!SymbolProvider) - return; - - if (PhBeginInitOnce(&SymbolProvider->InitOnce)) - { - if (SymInitialize_I) - { - PH_LOCK_SYMBOLS(); - - SymInitialize_I(SymbolProvider->ProcessHandle, NULL, FALSE); - - if (SymRegisterCallbackW64_I) - SymRegisterCallbackW64_I(SymbolProvider->ProcessHandle, PhpSymbolCallbackFunction, (ULONG64)SymbolProvider); - - PH_UNLOCK_SYMBOLS(); - - SymbolProvider->IsRegistered = TRUE; - } - - PhEndInitOnce(&SymbolProvider->InitOnce); - } -} - -VOID PhpFreeSymbolModule( - _In_ PPH_SYMBOL_MODULE SymbolModule - ) -{ - if (SymbolModule->FileName) PhDereferenceObject(SymbolModule->FileName); - - PhFree(SymbolModule); -} - -static LONG NTAPI PhpSymbolModuleCompareFunction( - _In_ PPH_AVL_LINKS Links1, - _In_ PPH_AVL_LINKS Links2 - ) -{ - PPH_SYMBOL_MODULE symbolModule1 = CONTAINING_RECORD(Links1, PH_SYMBOL_MODULE, Links); - PPH_SYMBOL_MODULE symbolModule2 = CONTAINING_RECORD(Links2, PH_SYMBOL_MODULE, Links); - - return uint64cmp(symbolModule1->BaseAddress, symbolModule2->BaseAddress); -} - -BOOLEAN PhGetLineFromAddress( - _In_ PPH_SYMBOL_PROVIDER SymbolProvider, - _In_ ULONG64 Address, - _Out_ PPH_STRING *FileName, - _Out_opt_ PULONG Displacement, - _Out_opt_ PPH_SYMBOL_LINE_INFORMATION Information - ) -{ - IMAGEHLP_LINEW64 line; - BOOL result; - ULONG displacement; - PPH_STRING fileName; - - PhpRegisterSymbolProvider(SymbolProvider); - - if (!SymGetLineFromAddrW64_I && !SymGetLineFromAddr64_I) - return FALSE; - - line.SizeOfStruct = sizeof(IMAGEHLP_LINEW64); - - PH_LOCK_SYMBOLS(); - - if (SymGetLineFromAddrW64_I) - { - result = SymGetLineFromAddrW64_I( - SymbolProvider->ProcessHandle, - Address, - &displacement, - &line - ); - - if (result) - fileName = PhCreateString(line.FileName); - } - else - { - IMAGEHLP_LINE64 lineA; - - lineA.SizeOfStruct = sizeof(IMAGEHLP_LINE64); - - result = SymGetLineFromAddr64_I( - SymbolProvider->ProcessHandle, - Address, - &displacement, - &lineA - ); - - if (result) - { - fileName = PhConvertMultiByteToUtf16(lineA.FileName); - line.LineNumber = lineA.LineNumber; - line.Address = lineA.Address; - } - } - - PH_UNLOCK_SYMBOLS(); - - if (!result) - return FALSE; - - *FileName = fileName; - - if (Displacement) - *Displacement = displacement; - - if (Information) - { - Information->LineNumber = line.LineNumber; - Information->Address = line.Address; - } - - return TRUE; -} - -ULONG64 PhGetModuleFromAddress( - _In_ PPH_SYMBOL_PROVIDER SymbolProvider, - _In_ ULONG64 Address, - _Out_opt_ PPH_STRING *FileName - ) -{ - PH_SYMBOL_MODULE lookupModule; - PPH_AVL_LINKS links; - PPH_SYMBOL_MODULE module; - PPH_STRING foundFileName; - ULONG64 foundBaseAddress; - - foundFileName = NULL; - foundBaseAddress = 0; - - PhAcquireQueuedLockShared(&SymbolProvider->ModulesListLock); - - // Do an approximate search on the modules set to locate the module with the largest - // base address that is still smaller than the given address. - lookupModule.BaseAddress = Address; - links = PhUpperDualBoundElementAvlTree(&SymbolProvider->ModulesSet, &lookupModule.Links); - - if (links) - { - module = CONTAINING_RECORD(links, PH_SYMBOL_MODULE, Links); - - if (Address < module->BaseAddress + module->Size) - { - PhSetReference(&foundFileName, module->FileName); - foundBaseAddress = module->BaseAddress; - } - } - - PhReleaseQueuedLockShared(&SymbolProvider->ModulesListLock); - - if (foundFileName) - { - if (FileName) - { - *FileName = foundFileName; - } - else - { - PhDereferenceObject(foundFileName); - } - } - - return foundBaseAddress; -} - -VOID PhpSymbolInfoAnsiToUnicode( - _Out_ PSYMBOL_INFOW SymbolInfoW, - _In_ PSYMBOL_INFO SymbolInfoA - ) -{ - SymbolInfoW->TypeIndex = SymbolInfoA->TypeIndex; - SymbolInfoW->Index = SymbolInfoA->Index; - SymbolInfoW->Size = SymbolInfoA->Size; - SymbolInfoW->ModBase = SymbolInfoA->ModBase; - SymbolInfoW->Flags = SymbolInfoA->Flags; - SymbolInfoW->Value = SymbolInfoA->Value; - SymbolInfoW->Address = SymbolInfoA->Address; - SymbolInfoW->Register = SymbolInfoA->Register; - SymbolInfoW->Scope = SymbolInfoA->Scope; - SymbolInfoW->Tag = SymbolInfoA->Tag; - SymbolInfoW->NameLen = 0; - - if (SymbolInfoA->NameLen != 0 && SymbolInfoW->MaxNameLen != 0) - { - ULONG copyCount; - - copyCount = min(SymbolInfoA->NameLen, SymbolInfoW->MaxNameLen - 1); - - if (PhCopyStringZFromMultiByte( - SymbolInfoA->Name, - copyCount, - SymbolInfoW->Name, - SymbolInfoW->MaxNameLen, - NULL - )) - { - SymbolInfoW->NameLen = copyCount; - } - } -} - -PPH_STRING PhGetSymbolFromAddress( - _In_ PPH_SYMBOL_PROVIDER SymbolProvider, - _In_ ULONG64 Address, - _Out_opt_ PPH_SYMBOL_RESOLVE_LEVEL ResolveLevel, - _Out_opt_ PPH_STRING *FileName, - _Out_opt_ PPH_STRING *SymbolName, - _Out_opt_ PULONG64 Displacement - ) -{ - PSYMBOL_INFOW symbolInfo; - ULONG nameLength; - PPH_STRING symbol = NULL; - PH_SYMBOL_RESOLVE_LEVEL resolveLevel; - ULONG64 displacement; - PPH_STRING modFileName = NULL; - PPH_STRING modBaseName = NULL; - ULONG64 modBase; - PPH_STRING symbolName = NULL; - - if (Address == 0) - { - if (ResolveLevel) *ResolveLevel = PhsrlInvalid; - if (FileName) *FileName = NULL; - if (SymbolName) *SymbolName = NULL; - if (Displacement) *Displacement = 0; - - return NULL; - } - - PhpRegisterSymbolProvider(SymbolProvider); - - if (!SymFromAddrW_I && !SymFromAddr_I) - return NULL; - - symbolInfo = PhAllocate(FIELD_OFFSET(SYMBOL_INFOW, Name) + PH_MAX_SYMBOL_NAME_LEN * 2); - memset(symbolInfo, 0, sizeof(SYMBOL_INFOW)); - symbolInfo->SizeOfStruct = sizeof(SYMBOL_INFOW); - symbolInfo->MaxNameLen = PH_MAX_SYMBOL_NAME_LEN; - - // Get the symbol name. - - PH_LOCK_SYMBOLS(); - - // Note that we don't care whether this call succeeds or not, based on the assumption that it - // will not write to the symbolInfo structure if it fails. We've already zeroed the structure, - // so we can deal with it. - - if (SymFromAddrW_I) - { - SymFromAddrW_I( - SymbolProvider->ProcessHandle, - Address, - &displacement, - symbolInfo - ); - nameLength = symbolInfo->NameLen; - - if (nameLength + 1 > PH_MAX_SYMBOL_NAME_LEN) - { - PhFree(symbolInfo); - symbolInfo = PhAllocate(FIELD_OFFSET(SYMBOL_INFOW, Name) + nameLength * 2 + 2); - memset(symbolInfo, 0, sizeof(SYMBOL_INFOW)); - symbolInfo->SizeOfStruct = sizeof(SYMBOL_INFOW); - symbolInfo->MaxNameLen = nameLength + 1; - - SymFromAddrW_I( - SymbolProvider->ProcessHandle, - Address, - &displacement, - symbolInfo - ); - } - } - else if (SymFromAddr_I) - { - PSYMBOL_INFO symbolInfoA; - - symbolInfoA = PhAllocate(FIELD_OFFSET(SYMBOL_INFO, Name) + PH_MAX_SYMBOL_NAME_LEN); - memset(symbolInfoA, 0, sizeof(SYMBOL_INFO)); - symbolInfoA->SizeOfStruct = sizeof(SYMBOL_INFO); - symbolInfoA->MaxNameLen = PH_MAX_SYMBOL_NAME_LEN; - - SymFromAddr_I( - SymbolProvider->ProcessHandle, - Address, - &displacement, - symbolInfoA - ); - nameLength = symbolInfoA->NameLen; - - if (nameLength + 1 > PH_MAX_SYMBOL_NAME_LEN) - { - PhFree(symbolInfoA); - symbolInfoA = PhAllocate(FIELD_OFFSET(SYMBOL_INFO, Name) + nameLength + 1); - memset(symbolInfoA, 0, sizeof(SYMBOL_INFO)); - symbolInfoA->SizeOfStruct = sizeof(SYMBOL_INFO); - symbolInfoA->MaxNameLen = nameLength + 1; - - SymFromAddr_I( - SymbolProvider->ProcessHandle, - Address, - &displacement, - symbolInfoA - ); - - // Also reallocate the Unicode-based buffer. - PhFree(symbolInfo); - symbolInfo = PhAllocate(FIELD_OFFSET(SYMBOL_INFOW, Name) + nameLength * 2 + 2); - memset(symbolInfo, 0, sizeof(SYMBOL_INFOW)); - symbolInfo->SizeOfStruct = sizeof(SYMBOL_INFOW); - symbolInfo->MaxNameLen = nameLength + 1; - } - - PhpSymbolInfoAnsiToUnicode(symbolInfo, symbolInfoA); - PhFree(symbolInfoA); - } - - PH_UNLOCK_SYMBOLS(); - - // Find the module name. - - if (symbolInfo->ModBase == 0) - { - modBase = PhGetModuleFromAddress( - SymbolProvider, - Address, - &modFileName - ); - } - else - { - PH_SYMBOL_MODULE lookupSymbolModule; - PPH_AVL_LINKS existingLinks; - PPH_SYMBOL_MODULE symbolModule; - - lookupSymbolModule.BaseAddress = symbolInfo->ModBase; - - PhAcquireQueuedLockShared(&SymbolProvider->ModulesListLock); - - existingLinks = PhFindElementAvlTree(&SymbolProvider->ModulesSet, &lookupSymbolModule.Links); - - if (existingLinks) - { - symbolModule = CONTAINING_RECORD(existingLinks, PH_SYMBOL_MODULE, Links); - PhSetReference(&modFileName, symbolModule->FileName); - } - - PhReleaseQueuedLockShared(&SymbolProvider->ModulesListLock); - } - - // If we don't have a module name, return an address. - if (!modFileName) - { - resolveLevel = PhsrlAddress; - symbol = PhCreateStringEx(NULL, PH_PTR_STR_LEN * 2); - PhPrintPointer(symbol->Buffer, (PVOID)Address); - PhTrimToNullTerminatorString(symbol); - - goto CleanupExit; - } - - modBaseName = PhGetBaseName(modFileName); - - // If we have a module name but not a symbol name, return the module plus an offset: - // module+offset. - - if (symbolInfo->NameLen == 0) - { - PH_FORMAT format[3]; - - resolveLevel = PhsrlModule; - - PhInitFormatSR(&format[0], modBaseName->sr); - PhInitFormatS(&format[1], L"+0x"); - PhInitFormatIX(&format[2], (ULONG_PTR)(Address - modBase)); - symbol = PhFormat(format, 3, modBaseName->Length + 6 + 32); - - goto CleanupExit; - } - - // If we have everything, return the full symbol name: module!symbol+offset. - - symbolName = PhCreateStringEx(symbolInfo->Name, symbolInfo->NameLen * 2); - resolveLevel = PhsrlFunction; - - if (displacement == 0) - { - PH_FORMAT format[3]; - - PhInitFormatSR(&format[0], modBaseName->sr); - PhInitFormatC(&format[1], '!'); - PhInitFormatSR(&format[2], symbolName->sr); - - symbol = PhFormat(format, 3, modBaseName->Length + 2 + symbolName->Length); - } - else - { - PH_FORMAT format[5]; - - PhInitFormatSR(&format[0], modBaseName->sr); - PhInitFormatC(&format[1], '!'); - PhInitFormatSR(&format[2], symbolName->sr); - PhInitFormatS(&format[3], L"+0x"); - PhInitFormatIX(&format[4], (ULONG_PTR)displacement); - - symbol = PhFormat(format, 5, modBaseName->Length + 2 + symbolName->Length + 6 + 32); - } - -CleanupExit: - - if (ResolveLevel) - *ResolveLevel = resolveLevel; - if (FileName) - PhSetReference(FileName, modFileName); - if (SymbolName) - PhSetReference(SymbolName, symbolName); - if (Displacement) - *Displacement = displacement; - - PhClearReference(&modFileName); - PhClearReference(&modBaseName); - PhClearReference(&symbolName); - PhFree(symbolInfo); - - return symbol; -} - -BOOLEAN PhGetSymbolFromName( - _In_ PPH_SYMBOL_PROVIDER SymbolProvider, - _In_ PWSTR Name, - _Out_ PPH_SYMBOL_INFORMATION Information - ) -{ - PSYMBOL_INFOW symbolInfo; - UCHAR symbolInfoBuffer[FIELD_OFFSET(SYMBOL_INFOW, Name) + PH_MAX_SYMBOL_NAME_LEN * 2]; - BOOL result; - - PhpRegisterSymbolProvider(SymbolProvider); - - if (!SymFromNameW_I && !SymFromName_I) - return FALSE; - - symbolInfo = (PSYMBOL_INFOW)symbolInfoBuffer; - memset(symbolInfo, 0, sizeof(SYMBOL_INFOW)); - symbolInfo->SizeOfStruct = sizeof(SYMBOL_INFOW); - symbolInfo->MaxNameLen = PH_MAX_SYMBOL_NAME_LEN; - - // Get the symbol information. - - PH_LOCK_SYMBOLS(); - - if (SymFromNameW_I) - { - result = SymFromNameW_I( - SymbolProvider->ProcessHandle, - Name, - symbolInfo - ); - } - else if (SymFromName_I) - { - UCHAR buffer[FIELD_OFFSET(SYMBOL_INFO, Name) + PH_MAX_SYMBOL_NAME_LEN]; - PSYMBOL_INFO symbolInfoA; - PPH_BYTES name; - - symbolInfoA = (PSYMBOL_INFO)buffer; - memset(symbolInfoA, 0, sizeof(SYMBOL_INFO)); - symbolInfoA->SizeOfStruct = sizeof(SYMBOL_INFO); - symbolInfoA->MaxNameLen = PH_MAX_SYMBOL_NAME_LEN; - - name = PhConvertUtf16ToMultiByte(Name); - - if (result = SymFromName_I( - SymbolProvider->ProcessHandle, - name->Buffer, - symbolInfoA - )) - { - PhpSymbolInfoAnsiToUnicode(symbolInfo, symbolInfoA); - } - - PhDereferenceObject(name); - } - else - { - result = FALSE; - } - - PH_UNLOCK_SYMBOLS(); - - if (!result) - return FALSE; - - Information->Address = symbolInfo->Address; - Information->ModuleBase = symbolInfo->ModBase; - Information->Index = symbolInfo->Index; - Information->Size = symbolInfo->Size; - - return TRUE; -} - -BOOLEAN PhLoadModuleSymbolProvider( - _In_ PPH_SYMBOL_PROVIDER SymbolProvider, - _In_ PWSTR FileName, - _In_ ULONG64 BaseAddress, - _In_ ULONG Size - ) -{ - ULONG64 baseAddress; - PPH_SYMBOL_MODULE symbolModule = NULL; - PPH_AVL_LINKS existingLinks; - PH_SYMBOL_MODULE lookupSymbolModule; - - PhpRegisterSymbolProvider(SymbolProvider); - - if (!SymLoadModuleExW_I && !SymLoadModule64_I) - return FALSE; - - // Check for duplicates. It is better to do this before calling SymLoadModuleExW, because it - // seems to force symbol loading when it is called twice on the same module even if deferred - // loading is enabled. - PhAcquireQueuedLockExclusive(&SymbolProvider->ModulesListLock); - lookupSymbolModule.BaseAddress = BaseAddress; - existingLinks = PhFindElementAvlTree(&SymbolProvider->ModulesSet, &lookupSymbolModule.Links); - PhReleaseQueuedLockExclusive(&SymbolProvider->ModulesListLock); - - if (existingLinks) - return TRUE; - - PH_LOCK_SYMBOLS(); - - if (SymLoadModuleExW_I) - { - baseAddress = SymLoadModuleExW_I( - SymbolProvider->ProcessHandle, - NULL, - FileName, - NULL, - BaseAddress, - Size, - NULL, - 0 - ); - } - else - { - PPH_BYTES fileName; - - fileName = PhConvertUtf16ToMultiByte(FileName); - baseAddress = SymLoadModule64_I( - SymbolProvider->ProcessHandle, - NULL, - fileName->Buffer, - NULL, - BaseAddress, - Size - ); - PhDereferenceObject(fileName); - } - - PH_UNLOCK_SYMBOLS(); - - // Add the module to the list, even if we couldn't load symbols for the module. - - PhAcquireQueuedLockExclusive(&SymbolProvider->ModulesListLock); - - // Check for duplicates again. - lookupSymbolModule.BaseAddress = BaseAddress; - existingLinks = PhFindElementAvlTree(&SymbolProvider->ModulesSet, &lookupSymbolModule.Links); - - if (!existingLinks) - { - symbolModule = PhAllocate(sizeof(PH_SYMBOL_MODULE)); - symbolModule->BaseAddress = BaseAddress; - symbolModule->Size = Size; - symbolModule->FileName = PhGetFullPath(FileName, &symbolModule->BaseNameIndex); - - existingLinks = PhAddElementAvlTree(&SymbolProvider->ModulesSet, &symbolModule->Links); - assert(!existingLinks); - InsertTailList(&SymbolProvider->ModulesListHead, &symbolModule->ListEntry); - } - - PhReleaseQueuedLockExclusive(&SymbolProvider->ModulesListLock); - - if (!baseAddress) - { - if (GetLastError() != ERROR_SUCCESS) - return FALSE; - else - return TRUE; - } - - return TRUE; -} - -VOID PhSetOptionsSymbolProvider( - _In_ ULONG Mask, - _In_ ULONG Value - ) -{ - ULONG options; - - PhpRegisterSymbolProvider(NULL); - - if (!SymGetOptions_I || !SymSetOptions_I) - return; - - PH_LOCK_SYMBOLS(); - - options = SymGetOptions_I(); - options &= ~Mask; - options |= Value; - SymSetOptions_I(options); - - PH_UNLOCK_SYMBOLS(); -} - -VOID PhSetSearchPathSymbolProvider( - _In_ PPH_SYMBOL_PROVIDER SymbolProvider, - _In_ PWSTR Path - ) -{ - PhpRegisterSymbolProvider(SymbolProvider); - - if (!SymSetSearchPathW_I && !SymSetSearchPath_I) - return; - - PH_LOCK_SYMBOLS(); - - if (SymSetSearchPathW_I) - { - SymSetSearchPathW_I(SymbolProvider->ProcessHandle, Path); - } - else if (SymSetSearchPath_I) - { - PPH_BYTES path; - - path = PhConvertUtf16ToMultiByte(Path); - SymSetSearchPath_I(SymbolProvider->ProcessHandle, path->Buffer); - PhDereferenceObject(path); - } - - PH_UNLOCK_SYMBOLS(); -} - -#ifdef _WIN64 - -NTSTATUS PhpLookupDynamicFunctionTable( - _In_ HANDLE ProcessHandle, - _In_ ULONG64 Address, - _Out_opt_ PDYNAMIC_FUNCTION_TABLE *FunctionTableAddress, - _Out_opt_ PDYNAMIC_FUNCTION_TABLE FunctionTable, - _Out_writes_bytes_opt_(OutOfProcessCallbackDllBufferSize) PWCHAR OutOfProcessCallbackDllBuffer, - _In_ ULONG OutOfProcessCallbackDllBufferSize, - _Out_opt_ PUNICODE_STRING OutOfProcessCallbackDllString - ) -{ - NTSTATUS status; - PLIST_ENTRY (NTAPI *rtlGetFunctionTableListHead)(VOID); - PLIST_ENTRY tableListHead; - LIST_ENTRY tableListHeadEntry; - PLIST_ENTRY tableListEntry; - PDYNAMIC_FUNCTION_TABLE functionTableAddress; - DYNAMIC_FUNCTION_TABLE functionTable; - ULONG count; - SIZE_T numberOfBytesRead; - ULONG i; - BOOLEAN foundNull; - - rtlGetFunctionTableListHead = PhGetModuleProcAddress(L"ntdll.dll", "RtlGetFunctionTableListHead"); - - if (!rtlGetFunctionTableListHead) - return STATUS_PROCEDURE_NOT_FOUND; - - tableListHead = rtlGetFunctionTableListHead(); - - // Find the function table entry for this address. - - if (!NT_SUCCESS(status = NtReadVirtualMemory( - ProcessHandle, - tableListHead, - &tableListHeadEntry, - sizeof(LIST_ENTRY), - NULL - ))) - return status; - - tableListEntry = tableListHeadEntry.Flink; - count = 0; // make sure we can't be forced into an infinite loop by crafted data - - while (tableListEntry != tableListHead && count < PH_ENUM_PROCESS_MODULES_LIMIT) - { - functionTableAddress = CONTAINING_RECORD(tableListEntry, DYNAMIC_FUNCTION_TABLE, ListEntry); - - if (!NT_SUCCESS(status = NtReadVirtualMemory( - ProcessHandle, - functionTableAddress, - &functionTable, - sizeof(DYNAMIC_FUNCTION_TABLE), - NULL - ))) - return status; - - if (Address >= functionTable.MinimumAddress && Address < functionTable.MaximumAddress) - { - if (OutOfProcessCallbackDllBuffer) - { - if (functionTable.OutOfProcessCallbackDll) - { - // Read the out-of-process callback DLL path. We don't have a length, so we'll - // just have to read as much as possible. - - memset(OutOfProcessCallbackDllBuffer, 0xff, OutOfProcessCallbackDllBufferSize); - status = NtReadVirtualMemory( - ProcessHandle, - functionTable.OutOfProcessCallbackDll, - OutOfProcessCallbackDllBuffer, - OutOfProcessCallbackDllBufferSize, - &numberOfBytesRead - ); - - if (status != STATUS_PARTIAL_COPY && !NT_SUCCESS(status)) - return status; - - foundNull = FALSE; - - for (i = 0; i < OutOfProcessCallbackDllBufferSize / sizeof(WCHAR); i++) - { - if (OutOfProcessCallbackDllBuffer[i] == 0) - { - foundNull = TRUE; - - if (OutOfProcessCallbackDllString) - { - OutOfProcessCallbackDllString->Buffer = OutOfProcessCallbackDllBuffer; - OutOfProcessCallbackDllString->Length = (USHORT)(i * sizeof(WCHAR)); - OutOfProcessCallbackDllString->MaximumLength = OutOfProcessCallbackDllString->Length; - } - - break; - } - } - - // If there was no null terminator, then we didn't read the whole string in. - // Fail the operation. - if (!foundNull) - return STATUS_BUFFER_OVERFLOW; - } - else - { - OutOfProcessCallbackDllBuffer[0] = 0; - - if (OutOfProcessCallbackDllString) - { - OutOfProcessCallbackDllString->Buffer = NULL; - OutOfProcessCallbackDllString->Length = 0; - OutOfProcessCallbackDllString->MaximumLength = 0; - } - } - } - - if (FunctionTableAddress) - *FunctionTableAddress = functionTableAddress; - - if (FunctionTable) - *FunctionTable = functionTable; - - return STATUS_SUCCESS; - } - - tableListEntry = functionTable.ListEntry.Flink; - count++; - } - - return STATUS_NOT_FOUND; -} - -PRUNTIME_FUNCTION PhpLookupFunctionEntry( - _In_ PRUNTIME_FUNCTION Functions, - _In_ ULONG NumberOfFunctions, - _In_ BOOLEAN Sorted, - _In_ ULONG64 RelativeControlPc - ) -{ - LONG low; - LONG high; - ULONG i; - - if (Sorted) - { - if (NumberOfFunctions == 0) - return NULL; - - low = 0; - high = NumberOfFunctions - 1; - - do - { - i = (low + high) / 2; - - if (RelativeControlPc < Functions[i].BeginAddress) - high = i - 1; - else if (RelativeControlPc >= Functions[i].EndAddress) - low = i + 1; - else - return &Functions[i]; - } while (low <= high); - } - else - { - for (i = 0; i < NumberOfFunctions; i++) - { - if (RelativeControlPc >= Functions[i].BeginAddress && RelativeControlPc < Functions[i].EndAddress) - return &Functions[i]; - } - } - - return NULL; -} - -NTSTATUS PhpAccessCallbackFunctionTable( - _In_ HANDLE ProcessHandle, - _In_ PVOID FunctionTableAddress, - _In_ PUNICODE_STRING OutOfProcessCallbackDllString, - _Out_ PRUNTIME_FUNCTION *Functions, - _Out_ PULONG NumberOfFunctions - ) -{ - static PH_STRINGREF knownFunctionTableDllsKeyName = PH_STRINGREF_INIT(L"Software\\Microsoft\\Windows NT\\CurrentVersion\\KnownFunctionTableDlls"); - - NTSTATUS status; - HANDLE keyHandle; - ULONG returnLength; - PVOID dllHandle; - ANSI_STRING outOfProcessFunctionTableCallbackName; - POUT_OF_PROCESS_FUNCTION_TABLE_CALLBACK outOfProcessFunctionTableCallback; - - if (!OutOfProcessCallbackDllString->Buffer) - return STATUS_INVALID_PARAMETER; - - // Don't load DLLs from arbitrary locations. Check if this is a known function table DLL. - - if (!NT_SUCCESS(status = PhOpenKey( - &keyHandle, - KEY_READ, - PH_KEY_LOCAL_MACHINE, - &knownFunctionTableDllsKeyName, - 0 - ))) - return status; - - status = NtQueryValueKey(keyHandle, OutOfProcessCallbackDllString, KeyValuePartialInformation, NULL, 0, &returnLength); - NtClose(keyHandle); - - if (status == STATUS_OBJECT_NAME_NOT_FOUND) - return STATUS_ACCESS_DISABLED_BY_POLICY_DEFAULT; - - status = LdrLoadDll(NULL, NULL, OutOfProcessCallbackDllString, &dllHandle); - - if (!NT_SUCCESS(status)) - return status; - - RtlInitAnsiString(&outOfProcessFunctionTableCallbackName, OUT_OF_PROCESS_FUNCTION_TABLE_CALLBACK_EXPORT_NAME); - status = LdrGetProcedureAddress(dllHandle, &outOfProcessFunctionTableCallbackName, 0, (PVOID *)&outOfProcessFunctionTableCallback); - - if (NT_SUCCESS(status)) - { - status = outOfProcessFunctionTableCallback( - ProcessHandle, - FunctionTableAddress, - NumberOfFunctions, - Functions - ); - } - - LdrUnloadDll(dllHandle); - - return status; -} - -NTSTATUS PhpAccessNormalFunctionTable( - _In_ HANDLE ProcessHandle, - _In_ PDYNAMIC_FUNCTION_TABLE FunctionTable, - _Out_ PRUNTIME_FUNCTION *Functions, - _Out_ PULONG NumberOfFunctions - ) -{ - NTSTATUS status; - SIZE_T bufferSize; - PRUNTIME_FUNCTION functions; - - // Put a reasonable limit on the number of entries we read. - if (FunctionTable->EntryCount > 0x100000) - return STATUS_BUFFER_OVERFLOW; - - bufferSize = FunctionTable->EntryCount * sizeof(RUNTIME_FUNCTION); - functions = PhAllocatePage(bufferSize, NULL); - - if (!functions) - return STATUS_NO_MEMORY; - - status = NtReadVirtualMemory(ProcessHandle, FunctionTable->FunctionTable, functions, bufferSize, NULL); - - if (NT_SUCCESS(status)) - { - *Functions = functions; - *NumberOfFunctions = FunctionTable->EntryCount; - } - else - { - PhFreePage(functions); - } - - return status; -} - -NTSTATUS PhAccessOutOfProcessFunctionEntry( - _In_ HANDLE ProcessHandle, - _In_ ULONG64 ControlPc, - _Out_ PRUNTIME_FUNCTION Function - ) -{ - NTSTATUS status; - PDYNAMIC_FUNCTION_TABLE functionTableAddress; - DYNAMIC_FUNCTION_TABLE functionTable; - WCHAR outOfProcessCallbackDll[512]; - UNICODE_STRING outOfProcessCallbackDllString; - PRUNTIME_FUNCTION functions; - ULONG numberOfFunctions; - PRUNTIME_FUNCTION function; - - if (!NT_SUCCESS(status = PhpLookupDynamicFunctionTable( - ProcessHandle, - ControlPc, - &functionTableAddress, - &functionTable, - outOfProcessCallbackDll, - sizeof(outOfProcessCallbackDll), - &outOfProcessCallbackDllString - ))) - { - return status; - } - - if (functionTable.Type == RF_CALLBACK) - { - if (!NT_SUCCESS(status = PhpAccessCallbackFunctionTable( - ProcessHandle, - functionTableAddress, - &outOfProcessCallbackDllString, - &functions, - &numberOfFunctions - ))) - { - return status; - } - - function = PhpLookupFunctionEntry(functions, numberOfFunctions, FALSE, ControlPc - functionTable.BaseAddress); - - if (function) - *Function = *function; - else - status = STATUS_NOT_FOUND; - - RtlFreeHeap(RtlProcessHeap(), 0, functions); - } - else - { - if (!NT_SUCCESS(status = PhpAccessNormalFunctionTable( - ProcessHandle, - &functionTable, - &functions, - &numberOfFunctions - ))) - { - return status; - } - - function = PhpLookupFunctionEntry(functions, numberOfFunctions, functionTable.Type == RF_SORTED, ControlPc - functionTable.BaseAddress); - - if (function) - *Function = *function; - else - status = STATUS_NOT_FOUND; - - PhFreePage(functions); - } - - return status; -} - -#endif - -ULONG64 __stdcall PhGetModuleBase64( - _In_ HANDLE hProcess, - _In_ DWORD64 dwAddr - ) -{ - ULONG64 base; -#ifdef _WIN64 - DYNAMIC_FUNCTION_TABLE functionTable; -#endif - -#ifdef _WIN64 - if (NT_SUCCESS(PhpLookupDynamicFunctionTable( - hProcess, - dwAddr, - NULL, - &functionTable, - NULL, - 0, - NULL - ))) - { - base = functionTable.BaseAddress; - } - else - { - base = 0; - } -#else - base = 0; -#endif - - if (base == 0 && SymGetModuleBase64_I) - base = SymGetModuleBase64_I(hProcess, dwAddr); - - return base; -} - -PVOID __stdcall PhFunctionTableAccess64( - _In_ HANDLE hProcess, - _In_ DWORD64 AddrBase - ) -{ -#ifdef _WIN64 - static RUNTIME_FUNCTION lastRuntimeFunction; -#endif - - PVOID entry; - -#ifdef _WIN64 - if (NT_SUCCESS(PhAccessOutOfProcessFunctionEntry(hProcess, AddrBase, &lastRuntimeFunction))) - entry = &lastRuntimeFunction; - else - entry = NULL; -#else - entry = NULL; -#endif - - if (!entry && SymFunctionTableAccess64_I) - entry = SymFunctionTableAccess64_I(hProcess, AddrBase); - - return entry; -} - -BOOLEAN PhStackWalk( - _In_ ULONG MachineType, - _In_ HANDLE ProcessHandle, - _In_ HANDLE ThreadHandle, - _Inout_ LPSTACKFRAME64 StackFrame, - _Inout_ PVOID ContextRecord, - _In_opt_ PPH_SYMBOL_PROVIDER SymbolProvider, - _In_opt_ PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine, - _In_opt_ PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine, - _In_opt_ PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine, - _In_opt_ PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress - ) -{ - BOOLEAN result; - - PhpRegisterSymbolProvider(SymbolProvider); - - if (!StackWalk64_I) - return FALSE; - - if (!FunctionTableAccessRoutine) - { - if (MachineType == IMAGE_FILE_MACHINE_AMD64) - FunctionTableAccessRoutine = PhFunctionTableAccess64; - else - FunctionTableAccessRoutine = SymFunctionTableAccess64_I; - } - - if (!GetModuleBaseRoutine) - { - if (MachineType == IMAGE_FILE_MACHINE_AMD64) - GetModuleBaseRoutine = PhGetModuleBase64; - else - GetModuleBaseRoutine = SymGetModuleBase64_I; - } - - PH_LOCK_SYMBOLS(); - result = StackWalk64_I( - MachineType, - ProcessHandle, - ThreadHandle, - StackFrame, - ContextRecord, - ReadMemoryRoutine, - FunctionTableAccessRoutine, - GetModuleBaseRoutine, - TranslateAddress - ); - PH_UNLOCK_SYMBOLS(); - - return result; -} - -BOOLEAN PhWriteMiniDumpProcess( - _In_ HANDLE ProcessHandle, - _In_ HANDLE ProcessId, - _In_ HANDLE FileHandle, - _In_ MINIDUMP_TYPE DumpType, - _In_opt_ PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, - _In_opt_ PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam, - _In_opt_ PMINIDUMP_CALLBACK_INFORMATION CallbackParam - ) -{ - PhpRegisterSymbolProvider(NULL); - - if (!MiniDumpWriteDump_I) - { - SetLastError(ERROR_PROC_NOT_FOUND); - return FALSE; - } - - return MiniDumpWriteDump_I( - ProcessHandle, - HandleToUlong(ProcessId), - FileHandle, - DumpType, - ExceptionParam, - UserStreamParam, - CallbackParam - ); -} - -/** - * Converts a STACKFRAME64 structure to a PH_THREAD_STACK_FRAME structure. - * - * \param StackFrame64 A pointer to the STACKFRAME64 structure to convert. - * \param Flags Flags to set in the resulting structure. - * \param ThreadStackFrame A pointer to the resulting PH_THREAD_STACK_FRAME structure. - */ -VOID PhpConvertStackFrame( - _In_ STACKFRAME64 *StackFrame64, - _In_ ULONG Flags, - _Out_ PPH_THREAD_STACK_FRAME ThreadStackFrame - ) -{ - ULONG i; - - ThreadStackFrame->PcAddress = (PVOID)StackFrame64->AddrPC.Offset; - ThreadStackFrame->ReturnAddress = (PVOID)StackFrame64->AddrReturn.Offset; - ThreadStackFrame->FrameAddress = (PVOID)StackFrame64->AddrFrame.Offset; - ThreadStackFrame->StackAddress = (PVOID)StackFrame64->AddrStack.Offset; - ThreadStackFrame->BStoreAddress = (PVOID)StackFrame64->AddrBStore.Offset; - - for (i = 0; i < 4; i++) - ThreadStackFrame->Params[i] = (PVOID)StackFrame64->Params[i]; - - ThreadStackFrame->Flags = Flags; - - if (StackFrame64->FuncTableEntry) - ThreadStackFrame->Flags |= PH_THREAD_STACK_FRAME_FPO_DATA_PRESENT; -} - -/** - * Walks a thread's stack. - * - * \param ThreadHandle A handle to a thread. The handle must have THREAD_QUERY_LIMITED_INFORMATION, - * THREAD_GET_CONTEXT and THREAD_SUSPEND_RESUME access. The handle can have any access for kernel - * stack walking. - * \param ProcessHandle A handle to the thread's parent process. The handle must have - * PROCESS_QUERY_INFORMATION and PROCESS_VM_READ access. If a symbol provider is being used, pass - * its process handle and specify the symbol provider in \a SymbolProvider. - * \param ClientId The client ID identifying the thread. - * \param SymbolProvider The associated symbol provider. - * \param Flags A combination of flags. - * \li \c PH_WALK_I386_STACK Walks the x86 stack. On AMD64 systems this flag walks the WOW64 stack. - * \li \c PH_WALK_AMD64_STACK Walks the AMD64 stack. On x86 systems this flag is ignored. - * \li \c PH_WALK_KERNEL_STACK Walks the kernel stack. This flag is ignored if there is no active - * KProcessHacker connection. - * \param Callback A callback function which is executed for each stack frame. - * \param Context A user-defined value to pass to the callback function. - */ -NTSTATUS PhWalkThreadStack( - _In_ HANDLE ThreadHandle, - _In_opt_ HANDLE ProcessHandle, - _In_opt_ PCLIENT_ID ClientId, - _In_opt_ PPH_SYMBOL_PROVIDER SymbolProvider, - _In_ ULONG Flags, - _In_ PPH_WALK_THREAD_STACK_CALLBACK Callback, - _In_opt_ PVOID Context - ) -{ - NTSTATUS status = STATUS_SUCCESS; - BOOLEAN suspended = FALSE; - BOOLEAN processOpened = FALSE; - BOOLEAN isCurrentThread = FALSE; - BOOLEAN isSystemThread = FALSE; - THREAD_BASIC_INFORMATION basicInfo; - - // Open a handle to the process if we weren't given one. - if (!ProcessHandle) - { - if (KphIsConnected() || !ClientId) - { - if (!NT_SUCCESS(status = PhOpenThreadProcess( - ThreadHandle, - PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, - &ProcessHandle - ))) - return status; - } - else - { - if (!NT_SUCCESS(status = PhOpenProcess( - &ProcessHandle, - PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, - ClientId->UniqueProcess - ))) - return status; - } - - processOpened = TRUE; - } - - // Determine if the caller specified the current thread. - if (ClientId) - { - if (ClientId->UniqueThread == NtCurrentTeb()->ClientId.UniqueThread) - isCurrentThread = TRUE; - if (ClientId->UniqueProcess == SYSTEM_PROCESS_ID) - isSystemThread = TRUE; - } - else - { - if (ThreadHandle == NtCurrentThread()) - { - isCurrentThread = TRUE; - } - else if (NT_SUCCESS(PhGetThreadBasicInformation(ThreadHandle, &basicInfo))) - { - if (basicInfo.ClientId.UniqueThread == NtCurrentTeb()->ClientId.UniqueThread) - isCurrentThread = TRUE; - if (basicInfo.ClientId.UniqueProcess == SYSTEM_PROCESS_ID) - isSystemThread = TRUE; - } - } - - // Make sure this isn't a kernel-mode thread. - if (!isSystemThread) - { - PVOID startAddress; - - if (NT_SUCCESS(NtQueryInformationThread(ThreadHandle, ThreadQuerySetWin32StartAddress, - &startAddress, sizeof(PVOID), NULL))) - { - if ((ULONG_PTR)startAddress > PhSystemBasicInformation.MaximumUserModeAddress) - isSystemThread = TRUE; - } - } - - // Suspend the thread to avoid inaccurate results. Don't suspend if we're walking the stack of - // the current thread or this is a kernel-mode thread. - if (!isCurrentThread && !isSystemThread) - { - if (NT_SUCCESS(NtSuspendThread(ThreadHandle, NULL))) - suspended = TRUE; - } - - // Kernel stack walk. - if ((Flags & PH_WALK_KERNEL_STACK) && KphIsConnected()) - { - PVOID stack[256 - 2]; // See MAX_STACK_DEPTH - ULONG capturedFrames; - ULONG i; - - if (NT_SUCCESS(KphCaptureStackBackTraceThread( - ThreadHandle, - 1, - sizeof(stack) / sizeof(PVOID), - stack, - &capturedFrames, - NULL - ))) - { - PH_THREAD_STACK_FRAME threadStackFrame; - - memset(&threadStackFrame, 0, sizeof(PH_THREAD_STACK_FRAME)); - - for (i = 0; i < capturedFrames; i++) - { - threadStackFrame.PcAddress = stack[i]; - threadStackFrame.Flags = PH_THREAD_STACK_FRAME_KERNEL; - - if (!Callback(&threadStackFrame, Context)) - { - goto ResumeExit; - } - } - } - } - -#ifdef _WIN64 - if (Flags & PH_WALK_AMD64_STACK) - { - STACKFRAME64 stackFrame; - PH_THREAD_STACK_FRAME threadStackFrame; - CONTEXT context; - - context.ContextFlags = CONTEXT_ALL; - - if (!NT_SUCCESS(status = NtGetContextThread( - ThreadHandle, - &context - ))) - goto SkipAmd64Stack; - - memset(&stackFrame, 0, sizeof(STACKFRAME64)); - stackFrame.AddrPC.Mode = AddrModeFlat; - stackFrame.AddrPC.Offset = context.Rip; - stackFrame.AddrStack.Mode = AddrModeFlat; - stackFrame.AddrStack.Offset = context.Rsp; - stackFrame.AddrFrame.Mode = AddrModeFlat; - stackFrame.AddrFrame.Offset = context.Rbp; - - while (TRUE) - { - if (!PhStackWalk( - IMAGE_FILE_MACHINE_AMD64, - ProcessHandle, - ThreadHandle, - &stackFrame, - &context, - SymbolProvider, - NULL, - NULL, - NULL, - NULL - )) - break; - - // If we have an invalid instruction pointer, break. - if (!stackFrame.AddrPC.Offset || stackFrame.AddrPC.Offset == -1) - break; - - // Convert the stack frame and execute the callback. - - PhpConvertStackFrame(&stackFrame, PH_THREAD_STACK_FRAME_AMD64, &threadStackFrame); - - if (!Callback(&threadStackFrame, Context)) - goto ResumeExit; - } - } - -SkipAmd64Stack: -#endif - - // x86/WOW64 stack walk. - if (Flags & PH_WALK_I386_STACK) - { - STACKFRAME64 stackFrame; - PH_THREAD_STACK_FRAME threadStackFrame; -#ifndef _WIN64 - CONTEXT context; - - context.ContextFlags = CONTEXT_ALL; - - if (!NT_SUCCESS(status = NtGetContextThread( - ThreadHandle, - &context - ))) - goto SkipI386Stack; -#else - WOW64_CONTEXT context; - - context.ContextFlags = WOW64_CONTEXT_ALL; - - if (!NT_SUCCESS(status = NtQueryInformationThread( - ThreadHandle, - ThreadWow64Context, - &context, - sizeof(WOW64_CONTEXT), - NULL - ))) - goto SkipI386Stack; -#endif - - memset(&stackFrame, 0, sizeof(STACKFRAME64)); - stackFrame.AddrPC.Mode = AddrModeFlat; - stackFrame.AddrPC.Offset = context.Eip; - stackFrame.AddrStack.Mode = AddrModeFlat; - stackFrame.AddrStack.Offset = context.Esp; - stackFrame.AddrFrame.Mode = AddrModeFlat; - stackFrame.AddrFrame.Offset = context.Ebp; - - while (TRUE) - { - if (!PhStackWalk( - IMAGE_FILE_MACHINE_I386, - ProcessHandle, - ThreadHandle, - &stackFrame, - &context, - SymbolProvider, - NULL, - NULL, - NULL, - NULL - )) - break; - - // If we have an invalid instruction pointer, break. - if (!stackFrame.AddrPC.Offset || stackFrame.AddrPC.Offset == -1) - break; - - // Convert the stack frame and execute the callback. - - PhpConvertStackFrame(&stackFrame, PH_THREAD_STACK_FRAME_I386, &threadStackFrame); - - if (!Callback(&threadStackFrame, Context)) - goto ResumeExit; - - // (x86 only) Allow the user to change Eip, Esp and Ebp. - context.Eip = PtrToUlong(threadStackFrame.PcAddress); - stackFrame.AddrPC.Offset = PtrToUlong(threadStackFrame.PcAddress); - context.Ebp = PtrToUlong(threadStackFrame.FrameAddress); - stackFrame.AddrFrame.Offset = PtrToUlong(threadStackFrame.FrameAddress); - context.Esp = PtrToUlong(threadStackFrame.StackAddress); - stackFrame.AddrStack.Offset = PtrToUlong(threadStackFrame.StackAddress); - } - } - -SkipI386Stack: - -ResumeExit: - if (suspended) - NtResumeThread(ThreadHandle, NULL); - - if (processOpened) - NtClose(ProcessHandle); - - return status; -} +/* + * Process Hacker - + * symbol provider + * + * Copyright (C) 2010-2015 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include +#include + +#include + +#include +#include +#include + +#include + +typedef struct _PH_SYMBOL_MODULE +{ + LIST_ENTRY ListEntry; + PH_AVL_LINKS Links; + ULONG64 BaseAddress; + ULONG Size; + PPH_STRING FileName; + ULONG BaseNameIndex; +} PH_SYMBOL_MODULE, *PPH_SYMBOL_MODULE; + +VOID NTAPI PhpSymbolProviderDeleteProcedure( + _In_ PVOID Object, + _In_ ULONG Flags + ); + +VOID PhpRegisterSymbolProvider( + _In_opt_ PPH_SYMBOL_PROVIDER SymbolProvider + ); + +VOID PhpFreeSymbolModule( + _In_ PPH_SYMBOL_MODULE SymbolModule + ); + +LONG NTAPI PhpSymbolModuleCompareFunction( + _In_ PPH_AVL_LINKS Links1, + _In_ PPH_AVL_LINKS Links2 + ); + +PPH_OBJECT_TYPE PhSymbolProviderType; + +static PH_INITONCE PhSymInitOnce = PH_INITONCE_INIT; +DECLSPEC_SELECTANY PH_CALLBACK_DECLARE(PhSymInitCallback); + +static HANDLE PhNextFakeHandle = (HANDLE)0; +static PH_FAST_LOCK PhSymMutex = PH_FAST_LOCK_INIT; + +#define PH_LOCK_SYMBOLS() PhAcquireFastLockExclusive(&PhSymMutex) +#define PH_UNLOCK_SYMBOLS() PhReleaseFastLockExclusive(&PhSymMutex) + +_SymInitialize SymInitialize_I; +_SymCleanup SymCleanup_I; +_SymEnumSymbols SymEnumSymbols_I; +_SymEnumSymbolsW SymEnumSymbolsW_I; +_SymFromAddr SymFromAddr_I; +_SymFromAddrW SymFromAddrW_I; +_SymFromName SymFromName_I; +_SymFromNameW SymFromNameW_I; +_SymGetLineFromAddr64 SymGetLineFromAddr64_I; +_SymGetLineFromAddrW64 SymGetLineFromAddrW64_I; +_SymLoadModule64 SymLoadModule64_I; +_SymLoadModuleExW SymLoadModuleExW_I; +_SymGetOptions SymGetOptions_I; +_SymSetOptions SymSetOptions_I; +_SymGetSearchPath SymGetSearchPath_I; +_SymGetSearchPathW SymGetSearchPathW_I; +_SymSetSearchPath SymSetSearchPath_I; +_SymSetSearchPathW SymSetSearchPathW_I; +_SymUnloadModule64 SymUnloadModule64_I; +_SymFunctionTableAccess64 SymFunctionTableAccess64_I; +_SymGetModuleBase64 SymGetModuleBase64_I; +_SymRegisterCallbackW64 SymRegisterCallbackW64_I; +_StackWalk64 StackWalk64_I; +_MiniDumpWriteDump MiniDumpWriteDump_I; +_SymbolServerGetOptions SymbolServerGetOptions; +_SymbolServerSetOptions SymbolServerSetOptions; + +BOOLEAN PhSymbolProviderInitialization( + VOID + ) +{ + PhSymbolProviderType = PhCreateObjectType(L"SymbolProvider", 0, PhpSymbolProviderDeleteProcedure); + + return TRUE; +} + +VOID PhSymbolProviderCompleteInitialization( + _In_opt_ PVOID DbgHelpBase + ) +{ + HMODULE dbghelpHandle; + HMODULE symsrvHandle; + + // The user should have loaded dbghelp.dll and symsrv.dll already. If not, it's not our problem. + + // The Unicode versions aren't available in dbghelp.dll 5.1, so we fallback on the ANSI versions. + + if (DbgHelpBase) + dbghelpHandle = DbgHelpBase; + else + dbghelpHandle = GetModuleHandle(L"dbghelp.dll"); + + symsrvHandle = GetModuleHandle(L"symsrv.dll"); + + SymInitialize_I = PhGetProcedureAddress(dbghelpHandle, "SymInitialize", 0); + SymCleanup_I = PhGetProcedureAddress(dbghelpHandle, "SymCleanup", 0); + if (!(SymEnumSymbolsW_I = PhGetProcedureAddress(dbghelpHandle, "SymEnumSymbolsW", 0))) + SymEnumSymbols_I = PhGetProcedureAddress(dbghelpHandle, "SymEnumSymbols", 0); + if (!(SymFromAddrW_I = PhGetProcedureAddress(dbghelpHandle, "SymFromAddrW", 0))) + SymFromAddr_I = PhGetProcedureAddress(dbghelpHandle, "SymFromAddr", 0); + if (!(SymFromNameW_I = PhGetProcedureAddress(dbghelpHandle, "SymFromNameW", 0))) + SymFromName_I = PhGetProcedureAddress(dbghelpHandle, "SymFromName", 0); + if (!(SymGetLineFromAddrW64_I = PhGetProcedureAddress(dbghelpHandle, "SymGetLineFromAddrW64", 0))) + SymGetLineFromAddr64_I = PhGetProcedureAddress(dbghelpHandle, "SymGetLineFromAddr64", 0); + if (!(SymLoadModuleExW_I = PhGetProcedureAddress(dbghelpHandle, "SymLoadModuleExW", 0))) + SymLoadModule64_I = PhGetProcedureAddress(dbghelpHandle, "SymLoadModule64", 0); + SymGetOptions_I = PhGetProcedureAddress(dbghelpHandle, "SymGetOptions", 0); + SymSetOptions_I = PhGetProcedureAddress(dbghelpHandle, "SymSetOptions", 0); + if (!(SymGetSearchPathW_I = PhGetProcedureAddress(dbghelpHandle, "SymGetSearchPathW", 0))) + SymGetSearchPath_I = PhGetProcedureAddress(dbghelpHandle, "SymGetSearchPath", 0); + if (!(SymSetSearchPathW_I = PhGetProcedureAddress(dbghelpHandle, "SymSetSearchPathW", 0))) + SymSetSearchPath_I = PhGetProcedureAddress(dbghelpHandle, "SymSetSearchPath", 0); + SymUnloadModule64_I = PhGetProcedureAddress(dbghelpHandle, "SymUnloadModule64", 0); + SymFunctionTableAccess64_I = PhGetProcedureAddress(dbghelpHandle, "SymFunctionTableAccess64", 0); + SymGetModuleBase64_I = PhGetProcedureAddress(dbghelpHandle, "SymGetModuleBase64", 0); + SymRegisterCallbackW64_I = PhGetProcedureAddress(dbghelpHandle, "SymRegisterCallbackW64", 0); + StackWalk64_I = PhGetProcedureAddress(dbghelpHandle, "StackWalk64", 0); + MiniDumpWriteDump_I = PhGetProcedureAddress(dbghelpHandle, "MiniDumpWriteDump", 0); + SymbolServerGetOptions = PhGetProcedureAddress(symsrvHandle, "SymbolServerGetOptions", 0); + SymbolServerSetOptions = PhGetProcedureAddress(symsrvHandle, "SymbolServerSetOptions", 0); + + if (SymGetOptions_I && SymSetOptions_I) + SymSetOptions_I(SymGetOptions_I() | SYMOPT_DEFERRED_LOADS | SYMOPT_FAVOR_COMPRESSED); +} + +PPH_SYMBOL_PROVIDER PhCreateSymbolProvider( + _In_opt_ HANDLE ProcessId + ) +{ + PPH_SYMBOL_PROVIDER symbolProvider; + + symbolProvider = PhCreateObject(sizeof(PH_SYMBOL_PROVIDER), PhSymbolProviderType); + memset(symbolProvider, 0, sizeof(PH_SYMBOL_PROVIDER)); + InitializeListHead(&symbolProvider->ModulesListHead); + PhInitializeQueuedLock(&symbolProvider->ModulesListLock); + PhInitializeAvlTree(&symbolProvider->ModulesSet, PhpSymbolModuleCompareFunction); + PhInitializeCallback(&symbolProvider->EventCallback); + PhInitializeInitOnce(&symbolProvider->InitOnce); + + if (ProcessId) + { + static ACCESS_MASK accesses[] = + { + STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xfff, // pre-Vista full access + PROCESS_QUERY_INFORMATION | PROCESS_VM_READ | PROCESS_DUP_HANDLE, + PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, + MAXIMUM_ALLOWED + }; + + ULONG i; + + // Try to open the process with many different accesses. + // This handle will be re-used when walking stacks, and doing various other things. + for (i = 0; i < sizeof(accesses) / sizeof(ACCESS_MASK); i++) + { + if (NT_SUCCESS(PhOpenProcess(&symbolProvider->ProcessHandle, accesses[i], ProcessId))) + { + symbolProvider->IsRealHandle = TRUE; + break; + } + } + } + + if (!symbolProvider->IsRealHandle) + { + HANDLE fakeHandle; + + // Just generate a fake handle. + fakeHandle = (HANDLE)_InterlockedExchangeAddPointer((PLONG_PTR)&PhNextFakeHandle, 4); + // Add one to make sure it isn't divisible by 4 (so it can't be mistaken for a real handle). + symbolProvider->ProcessHandle = (HANDLE)((ULONG_PTR)fakeHandle + 1); + } + + return symbolProvider; +} + +VOID NTAPI PhpSymbolProviderDeleteProcedure( + _In_ PVOID Object, + _In_ ULONG Flags + ) +{ + PPH_SYMBOL_PROVIDER symbolProvider = (PPH_SYMBOL_PROVIDER)Object; + PLIST_ENTRY listEntry; + + PhDeleteCallback(&symbolProvider->EventCallback); + + if (SymCleanup_I) + { + PH_LOCK_SYMBOLS(); + + if (symbolProvider->IsRegistered) + SymCleanup_I(symbolProvider->ProcessHandle); + + PH_UNLOCK_SYMBOLS(); + } + + listEntry = symbolProvider->ModulesListHead.Flink; + + while (listEntry != &symbolProvider->ModulesListHead) + { + PPH_SYMBOL_MODULE module; + + module = CONTAINING_RECORD(listEntry, PH_SYMBOL_MODULE, ListEntry); + listEntry = listEntry->Flink; + + PhpFreeSymbolModule(module); + } + + if (symbolProvider->IsRealHandle) NtClose(symbolProvider->ProcessHandle); +} + +NTSTATUS PhpSymbolCallbackWorker( + _In_ PVOID Parameter + ) +{ + PPH_SYMBOL_EVENT_DATA data = Parameter; + + dprintf("symbol event %d: %S\n", data->Type, data->FileName->Buffer); + PhInvokeCallback(&data->SymbolProvider->EventCallback, data); + PhClearReference(&data->FileName); + PhDereferenceObject(data); + + return STATUS_SUCCESS; +} + +BOOL CALLBACK PhpSymbolCallbackFunction( + _In_ HANDLE hProcess, + _In_ ULONG ActionCode, + _In_opt_ ULONG64 CallbackData, + _In_opt_ ULONG64 UserContext + ) +{ + PPH_SYMBOL_PROVIDER symbolProvider = (PPH_SYMBOL_PROVIDER)UserContext; + PPH_SYMBOL_EVENT_DATA data; + PIMAGEHLP_DEFERRED_SYMBOL_LOADW64 callbackData; + + if (!IsListEmpty(&symbolProvider->EventCallback.ListHead)) + { + switch (ActionCode) + { + case SymbolDeferredSymbolLoadStart: + case SymbolDeferredSymbolLoadComplete: + case SymbolDeferredSymbolLoadFailure: + case SymbolSymbolsUnloaded: + case SymbolDeferredSymbolLoadCancel: + data = PhCreateAlloc(sizeof(PH_SYMBOL_EVENT_DATA)); + memset(data, 0, sizeof(PH_SYMBOL_EVENT_DATA)); + data->SymbolProvider = symbolProvider; + data->Type = ActionCode; + + if (ActionCode != SymbolSymbolsUnloaded) + { + callbackData = (PIMAGEHLP_DEFERRED_SYMBOL_LOADW64)CallbackData; + data->BaseAddress = callbackData->BaseOfImage; + data->CheckSum = callbackData->CheckSum; + data->TimeStamp = callbackData->TimeDateStamp; + data->FileName = PhCreateString(callbackData->FileName); + } + + PhQueueItemWorkQueue(PhGetGlobalWorkQueue(), PhpSymbolCallbackWorker, data); + + break; + } + } + + return FALSE; +} + +VOID PhpRegisterSymbolProvider( + _In_opt_ PPH_SYMBOL_PROVIDER SymbolProvider + ) +{ + if (PhBeginInitOnce(&PhSymInitOnce)) + { + PhInvokeCallback(&PhSymInitCallback, NULL); + PhEndInitOnce(&PhSymInitOnce); + } + + if (!SymbolProvider) + return; + + if (PhBeginInitOnce(&SymbolProvider->InitOnce)) + { + if (SymInitialize_I) + { + PH_LOCK_SYMBOLS(); + + SymInitialize_I(SymbolProvider->ProcessHandle, NULL, FALSE); + + if (SymRegisterCallbackW64_I) + SymRegisterCallbackW64_I(SymbolProvider->ProcessHandle, PhpSymbolCallbackFunction, (ULONG64)SymbolProvider); + + PH_UNLOCK_SYMBOLS(); + + SymbolProvider->IsRegistered = TRUE; + } + + PhEndInitOnce(&SymbolProvider->InitOnce); + } +} + +VOID PhpFreeSymbolModule( + _In_ PPH_SYMBOL_MODULE SymbolModule + ) +{ + if (SymbolModule->FileName) PhDereferenceObject(SymbolModule->FileName); + + PhFree(SymbolModule); +} + +static LONG NTAPI PhpSymbolModuleCompareFunction( + _In_ PPH_AVL_LINKS Links1, + _In_ PPH_AVL_LINKS Links2 + ) +{ + PPH_SYMBOL_MODULE symbolModule1 = CONTAINING_RECORD(Links1, PH_SYMBOL_MODULE, Links); + PPH_SYMBOL_MODULE symbolModule2 = CONTAINING_RECORD(Links2, PH_SYMBOL_MODULE, Links); + + return uint64cmp(symbolModule1->BaseAddress, symbolModule2->BaseAddress); +} + +BOOLEAN PhGetLineFromAddress( + _In_ PPH_SYMBOL_PROVIDER SymbolProvider, + _In_ ULONG64 Address, + _Out_ PPH_STRING *FileName, + _Out_opt_ PULONG Displacement, + _Out_opt_ PPH_SYMBOL_LINE_INFORMATION Information + ) +{ + IMAGEHLP_LINEW64 line; + BOOL result; + ULONG displacement; + PPH_STRING fileName; + + PhpRegisterSymbolProvider(SymbolProvider); + + if (!SymGetLineFromAddrW64_I && !SymGetLineFromAddr64_I) + return FALSE; + + line.SizeOfStruct = sizeof(IMAGEHLP_LINEW64); + + PH_LOCK_SYMBOLS(); + + if (SymGetLineFromAddrW64_I) + { + result = SymGetLineFromAddrW64_I( + SymbolProvider->ProcessHandle, + Address, + &displacement, + &line + ); + + if (result) + fileName = PhCreateString(line.FileName); + } + else + { + IMAGEHLP_LINE64 lineA; + + lineA.SizeOfStruct = sizeof(IMAGEHLP_LINE64); + + result = SymGetLineFromAddr64_I( + SymbolProvider->ProcessHandle, + Address, + &displacement, + &lineA + ); + + if (result) + { + fileName = PhConvertMultiByteToUtf16(lineA.FileName); + line.LineNumber = lineA.LineNumber; + line.Address = lineA.Address; + } + } + + PH_UNLOCK_SYMBOLS(); + + if (!result) + return FALSE; + + *FileName = fileName; + + if (Displacement) + *Displacement = displacement; + + if (Information) + { + Information->LineNumber = line.LineNumber; + Information->Address = line.Address; + } + + return TRUE; +} + +ULONG64 PhGetModuleFromAddress( + _In_ PPH_SYMBOL_PROVIDER SymbolProvider, + _In_ ULONG64 Address, + _Out_opt_ PPH_STRING *FileName + ) +{ + PH_SYMBOL_MODULE lookupModule; + PPH_AVL_LINKS links; + PPH_SYMBOL_MODULE module; + PPH_STRING foundFileName; + ULONG64 foundBaseAddress; + + foundFileName = NULL; + foundBaseAddress = 0; + + PhAcquireQueuedLockShared(&SymbolProvider->ModulesListLock); + + // Do an approximate search on the modules set to locate the module with the largest + // base address that is still smaller than the given address. + lookupModule.BaseAddress = Address; + links = PhUpperDualBoundElementAvlTree(&SymbolProvider->ModulesSet, &lookupModule.Links); + + if (links) + { + module = CONTAINING_RECORD(links, PH_SYMBOL_MODULE, Links); + + if (Address < module->BaseAddress + module->Size) + { + PhSetReference(&foundFileName, module->FileName); + foundBaseAddress = module->BaseAddress; + } + } + + PhReleaseQueuedLockShared(&SymbolProvider->ModulesListLock); + + if (foundFileName) + { + if (FileName) + { + *FileName = foundFileName; + } + else + { + PhDereferenceObject(foundFileName); + } + } + + return foundBaseAddress; +} + +VOID PhpSymbolInfoAnsiToUnicode( + _Out_ PSYMBOL_INFOW SymbolInfoW, + _In_ PSYMBOL_INFO SymbolInfoA + ) +{ + SymbolInfoW->TypeIndex = SymbolInfoA->TypeIndex; + SymbolInfoW->Index = SymbolInfoA->Index; + SymbolInfoW->Size = SymbolInfoA->Size; + SymbolInfoW->ModBase = SymbolInfoA->ModBase; + SymbolInfoW->Flags = SymbolInfoA->Flags; + SymbolInfoW->Value = SymbolInfoA->Value; + SymbolInfoW->Address = SymbolInfoA->Address; + SymbolInfoW->Register = SymbolInfoA->Register; + SymbolInfoW->Scope = SymbolInfoA->Scope; + SymbolInfoW->Tag = SymbolInfoA->Tag; + SymbolInfoW->NameLen = 0; + + if (SymbolInfoA->NameLen != 0 && SymbolInfoW->MaxNameLen != 0) + { + ULONG copyCount; + + copyCount = min(SymbolInfoA->NameLen, SymbolInfoW->MaxNameLen - 1); + + if (PhCopyStringZFromMultiByte( + SymbolInfoA->Name, + copyCount, + SymbolInfoW->Name, + SymbolInfoW->MaxNameLen, + NULL + )) + { + SymbolInfoW->NameLen = copyCount; + } + } +} + +PPH_STRING PhGetSymbolFromAddress( + _In_ PPH_SYMBOL_PROVIDER SymbolProvider, + _In_ ULONG64 Address, + _Out_opt_ PPH_SYMBOL_RESOLVE_LEVEL ResolveLevel, + _Out_opt_ PPH_STRING *FileName, + _Out_opt_ PPH_STRING *SymbolName, + _Out_opt_ PULONG64 Displacement + ) +{ + PSYMBOL_INFOW symbolInfo; + ULONG nameLength; + PPH_STRING symbol = NULL; + PH_SYMBOL_RESOLVE_LEVEL resolveLevel; + ULONG64 displacement; + PPH_STRING modFileName = NULL; + PPH_STRING modBaseName = NULL; + ULONG64 modBase; + PPH_STRING symbolName = NULL; + + if (Address == 0) + { + if (ResolveLevel) *ResolveLevel = PhsrlInvalid; + if (FileName) *FileName = NULL; + if (SymbolName) *SymbolName = NULL; + if (Displacement) *Displacement = 0; + + return NULL; + } + + PhpRegisterSymbolProvider(SymbolProvider); + + if (!SymFromAddrW_I && !SymFromAddr_I) + return NULL; + + symbolInfo = PhAllocate(FIELD_OFFSET(SYMBOL_INFOW, Name) + PH_MAX_SYMBOL_NAME_LEN * 2); + memset(symbolInfo, 0, sizeof(SYMBOL_INFOW)); + symbolInfo->SizeOfStruct = sizeof(SYMBOL_INFOW); + symbolInfo->MaxNameLen = PH_MAX_SYMBOL_NAME_LEN; + + // Get the symbol name. + + PH_LOCK_SYMBOLS(); + + // Note that we don't care whether this call succeeds or not, based on the assumption that it + // will not write to the symbolInfo structure if it fails. We've already zeroed the structure, + // so we can deal with it. + + if (SymFromAddrW_I) + { + SymFromAddrW_I( + SymbolProvider->ProcessHandle, + Address, + &displacement, + symbolInfo + ); + nameLength = symbolInfo->NameLen; + + if (nameLength + 1 > PH_MAX_SYMBOL_NAME_LEN) + { + PhFree(symbolInfo); + symbolInfo = PhAllocate(FIELD_OFFSET(SYMBOL_INFOW, Name) + nameLength * 2 + 2); + memset(symbolInfo, 0, sizeof(SYMBOL_INFOW)); + symbolInfo->SizeOfStruct = sizeof(SYMBOL_INFOW); + symbolInfo->MaxNameLen = nameLength + 1; + + SymFromAddrW_I( + SymbolProvider->ProcessHandle, + Address, + &displacement, + symbolInfo + ); + } + } + else if (SymFromAddr_I) + { + PSYMBOL_INFO symbolInfoA; + + symbolInfoA = PhAllocate(FIELD_OFFSET(SYMBOL_INFO, Name) + PH_MAX_SYMBOL_NAME_LEN); + memset(symbolInfoA, 0, sizeof(SYMBOL_INFO)); + symbolInfoA->SizeOfStruct = sizeof(SYMBOL_INFO); + symbolInfoA->MaxNameLen = PH_MAX_SYMBOL_NAME_LEN; + + SymFromAddr_I( + SymbolProvider->ProcessHandle, + Address, + &displacement, + symbolInfoA + ); + nameLength = symbolInfoA->NameLen; + + if (nameLength + 1 > PH_MAX_SYMBOL_NAME_LEN) + { + PhFree(symbolInfoA); + symbolInfoA = PhAllocate(FIELD_OFFSET(SYMBOL_INFO, Name) + nameLength + 1); + memset(symbolInfoA, 0, sizeof(SYMBOL_INFO)); + symbolInfoA->SizeOfStruct = sizeof(SYMBOL_INFO); + symbolInfoA->MaxNameLen = nameLength + 1; + + SymFromAddr_I( + SymbolProvider->ProcessHandle, + Address, + &displacement, + symbolInfoA + ); + + // Also reallocate the Unicode-based buffer. + PhFree(symbolInfo); + symbolInfo = PhAllocate(FIELD_OFFSET(SYMBOL_INFOW, Name) + nameLength * 2 + 2); + memset(symbolInfo, 0, sizeof(SYMBOL_INFOW)); + symbolInfo->SizeOfStruct = sizeof(SYMBOL_INFOW); + symbolInfo->MaxNameLen = nameLength + 1; + } + + PhpSymbolInfoAnsiToUnicode(symbolInfo, symbolInfoA); + PhFree(symbolInfoA); + } + + PH_UNLOCK_SYMBOLS(); + + // Find the module name. + + if (symbolInfo->ModBase == 0) + { + modBase = PhGetModuleFromAddress( + SymbolProvider, + Address, + &modFileName + ); + } + else + { + PH_SYMBOL_MODULE lookupSymbolModule; + PPH_AVL_LINKS existingLinks; + PPH_SYMBOL_MODULE symbolModule; + + lookupSymbolModule.BaseAddress = symbolInfo->ModBase; + + PhAcquireQueuedLockShared(&SymbolProvider->ModulesListLock); + + existingLinks = PhFindElementAvlTree(&SymbolProvider->ModulesSet, &lookupSymbolModule.Links); + + if (existingLinks) + { + symbolModule = CONTAINING_RECORD(existingLinks, PH_SYMBOL_MODULE, Links); + PhSetReference(&modFileName, symbolModule->FileName); + } + + PhReleaseQueuedLockShared(&SymbolProvider->ModulesListLock); + } + + // If we don't have a module name, return an address. + if (!modFileName) + { + resolveLevel = PhsrlAddress; + symbol = PhCreateStringEx(NULL, PH_PTR_STR_LEN * 2); + PhPrintPointer(symbol->Buffer, (PVOID)Address); + PhTrimToNullTerminatorString(symbol); + + goto CleanupExit; + } + + modBaseName = PhGetBaseName(modFileName); + + // If we have a module name but not a symbol name, return the module plus an offset: + // module+offset. + + if (symbolInfo->NameLen == 0) + { + PH_FORMAT format[3]; + + resolveLevel = PhsrlModule; + + PhInitFormatSR(&format[0], modBaseName->sr); + PhInitFormatS(&format[1], L"+0x"); + PhInitFormatIX(&format[2], (ULONG_PTR)(Address - modBase)); + symbol = PhFormat(format, 3, modBaseName->Length + 6 + 32); + + goto CleanupExit; + } + + // If we have everything, return the full symbol name: module!symbol+offset. + + symbolName = PhCreateStringEx(symbolInfo->Name, symbolInfo->NameLen * 2); + resolveLevel = PhsrlFunction; + + if (displacement == 0) + { + PH_FORMAT format[3]; + + PhInitFormatSR(&format[0], modBaseName->sr); + PhInitFormatC(&format[1], '!'); + PhInitFormatSR(&format[2], symbolName->sr); + + symbol = PhFormat(format, 3, modBaseName->Length + 2 + symbolName->Length); + } + else + { + PH_FORMAT format[5]; + + PhInitFormatSR(&format[0], modBaseName->sr); + PhInitFormatC(&format[1], '!'); + PhInitFormatSR(&format[2], symbolName->sr); + PhInitFormatS(&format[3], L"+0x"); + PhInitFormatIX(&format[4], (ULONG_PTR)displacement); + + symbol = PhFormat(format, 5, modBaseName->Length + 2 + symbolName->Length + 6 + 32); + } + +CleanupExit: + + if (ResolveLevel) + *ResolveLevel = resolveLevel; + if (FileName) + PhSetReference(FileName, modFileName); + if (SymbolName) + PhSetReference(SymbolName, symbolName); + if (Displacement) + *Displacement = displacement; + + PhClearReference(&modFileName); + PhClearReference(&modBaseName); + PhClearReference(&symbolName); + PhFree(symbolInfo); + + return symbol; +} + +BOOLEAN PhGetSymbolFromName( + _In_ PPH_SYMBOL_PROVIDER SymbolProvider, + _In_ PWSTR Name, + _Out_ PPH_SYMBOL_INFORMATION Information + ) +{ + PSYMBOL_INFOW symbolInfo; + UCHAR symbolInfoBuffer[FIELD_OFFSET(SYMBOL_INFOW, Name) + PH_MAX_SYMBOL_NAME_LEN * 2]; + BOOL result; + + PhpRegisterSymbolProvider(SymbolProvider); + + if (!SymFromNameW_I && !SymFromName_I) + return FALSE; + + symbolInfo = (PSYMBOL_INFOW)symbolInfoBuffer; + memset(symbolInfo, 0, sizeof(SYMBOL_INFOW)); + symbolInfo->SizeOfStruct = sizeof(SYMBOL_INFOW); + symbolInfo->MaxNameLen = PH_MAX_SYMBOL_NAME_LEN; + + // Get the symbol information. + + PH_LOCK_SYMBOLS(); + + if (SymFromNameW_I) + { + result = SymFromNameW_I( + SymbolProvider->ProcessHandle, + Name, + symbolInfo + ); + } + else if (SymFromName_I) + { + UCHAR buffer[FIELD_OFFSET(SYMBOL_INFO, Name) + PH_MAX_SYMBOL_NAME_LEN]; + PSYMBOL_INFO symbolInfoA; + PPH_BYTES name; + + symbolInfoA = (PSYMBOL_INFO)buffer; + memset(symbolInfoA, 0, sizeof(SYMBOL_INFO)); + symbolInfoA->SizeOfStruct = sizeof(SYMBOL_INFO); + symbolInfoA->MaxNameLen = PH_MAX_SYMBOL_NAME_LEN; + + name = PhConvertUtf16ToMultiByte(Name); + + if (result = SymFromName_I( + SymbolProvider->ProcessHandle, + name->Buffer, + symbolInfoA + )) + { + PhpSymbolInfoAnsiToUnicode(symbolInfo, symbolInfoA); + } + + PhDereferenceObject(name); + } + else + { + result = FALSE; + } + + PH_UNLOCK_SYMBOLS(); + + if (!result) + return FALSE; + + Information->Address = symbolInfo->Address; + Information->ModuleBase = symbolInfo->ModBase; + Information->Index = symbolInfo->Index; + Information->Size = symbolInfo->Size; + + return TRUE; +} + +BOOLEAN PhLoadModuleSymbolProvider( + _In_ PPH_SYMBOL_PROVIDER SymbolProvider, + _In_ PWSTR FileName, + _In_ ULONG64 BaseAddress, + _In_ ULONG Size + ) +{ + ULONG64 baseAddress; + PPH_SYMBOL_MODULE symbolModule = NULL; + PPH_AVL_LINKS existingLinks; + PH_SYMBOL_MODULE lookupSymbolModule; + + PhpRegisterSymbolProvider(SymbolProvider); + + if (!SymLoadModuleExW_I && !SymLoadModule64_I) + return FALSE; + + // Check for duplicates. It is better to do this before calling SymLoadModuleExW, because it + // seems to force symbol loading when it is called twice on the same module even if deferred + // loading is enabled. + PhAcquireQueuedLockExclusive(&SymbolProvider->ModulesListLock); + lookupSymbolModule.BaseAddress = BaseAddress; + existingLinks = PhFindElementAvlTree(&SymbolProvider->ModulesSet, &lookupSymbolModule.Links); + PhReleaseQueuedLockExclusive(&SymbolProvider->ModulesListLock); + + if (existingLinks) + return TRUE; + + PH_LOCK_SYMBOLS(); + + if (SymLoadModuleExW_I) + { + baseAddress = SymLoadModuleExW_I( + SymbolProvider->ProcessHandle, + NULL, + FileName, + NULL, + BaseAddress, + Size, + NULL, + 0 + ); + } + else + { + PPH_BYTES fileName; + + fileName = PhConvertUtf16ToMultiByte(FileName); + baseAddress = SymLoadModule64_I( + SymbolProvider->ProcessHandle, + NULL, + fileName->Buffer, + NULL, + BaseAddress, + Size + ); + PhDereferenceObject(fileName); + } + + PH_UNLOCK_SYMBOLS(); + + // Add the module to the list, even if we couldn't load symbols for the module. + + PhAcquireQueuedLockExclusive(&SymbolProvider->ModulesListLock); + + // Check for duplicates again. + lookupSymbolModule.BaseAddress = BaseAddress; + existingLinks = PhFindElementAvlTree(&SymbolProvider->ModulesSet, &lookupSymbolModule.Links); + + if (!existingLinks) + { + symbolModule = PhAllocate(sizeof(PH_SYMBOL_MODULE)); + symbolModule->BaseAddress = BaseAddress; + symbolModule->Size = Size; + symbolModule->FileName = PhGetFullPath(FileName, &symbolModule->BaseNameIndex); + + existingLinks = PhAddElementAvlTree(&SymbolProvider->ModulesSet, &symbolModule->Links); + assert(!existingLinks); + InsertTailList(&SymbolProvider->ModulesListHead, &symbolModule->ListEntry); + } + + PhReleaseQueuedLockExclusive(&SymbolProvider->ModulesListLock); + + if (!baseAddress) + { + if (GetLastError() != ERROR_SUCCESS) + return FALSE; + else + return TRUE; + } + + return TRUE; +} + +VOID PhSetOptionsSymbolProvider( + _In_ ULONG Mask, + _In_ ULONG Value + ) +{ + ULONG options; + + PhpRegisterSymbolProvider(NULL); + + if (!SymGetOptions_I || !SymSetOptions_I) + return; + + PH_LOCK_SYMBOLS(); + + options = SymGetOptions_I(); + options &= ~Mask; + options |= Value; + SymSetOptions_I(options); + + PH_UNLOCK_SYMBOLS(); +} + +VOID PhSetSearchPathSymbolProvider( + _In_ PPH_SYMBOL_PROVIDER SymbolProvider, + _In_ PWSTR Path + ) +{ + PhpRegisterSymbolProvider(SymbolProvider); + + if (!SymSetSearchPathW_I && !SymSetSearchPath_I) + return; + + PH_LOCK_SYMBOLS(); + + if (SymSetSearchPathW_I) + { + SymSetSearchPathW_I(SymbolProvider->ProcessHandle, Path); + } + else if (SymSetSearchPath_I) + { + PPH_BYTES path; + + path = PhConvertUtf16ToMultiByte(Path); + SymSetSearchPath_I(SymbolProvider->ProcessHandle, path->Buffer); + PhDereferenceObject(path); + } + + PH_UNLOCK_SYMBOLS(); +} + +#ifdef _WIN64 + +NTSTATUS PhpLookupDynamicFunctionTable( + _In_ HANDLE ProcessHandle, + _In_ ULONG64 Address, + _Out_opt_ PDYNAMIC_FUNCTION_TABLE *FunctionTableAddress, + _Out_opt_ PDYNAMIC_FUNCTION_TABLE FunctionTable, + _Out_writes_bytes_opt_(OutOfProcessCallbackDllBufferSize) PWCHAR OutOfProcessCallbackDllBuffer, + _In_ ULONG OutOfProcessCallbackDllBufferSize, + _Out_opt_ PUNICODE_STRING OutOfProcessCallbackDllString + ) +{ + NTSTATUS status; + PLIST_ENTRY (NTAPI *rtlGetFunctionTableListHead)(VOID); + PLIST_ENTRY tableListHead; + LIST_ENTRY tableListHeadEntry; + PLIST_ENTRY tableListEntry; + PDYNAMIC_FUNCTION_TABLE functionTableAddress; + DYNAMIC_FUNCTION_TABLE functionTable; + ULONG count; + SIZE_T numberOfBytesRead; + ULONG i; + BOOLEAN foundNull; + + rtlGetFunctionTableListHead = PhGetModuleProcAddress(L"ntdll.dll", "RtlGetFunctionTableListHead"); + + if (!rtlGetFunctionTableListHead) + return STATUS_PROCEDURE_NOT_FOUND; + + tableListHead = rtlGetFunctionTableListHead(); + + // Find the function table entry for this address. + + if (!NT_SUCCESS(status = NtReadVirtualMemory( + ProcessHandle, + tableListHead, + &tableListHeadEntry, + sizeof(LIST_ENTRY), + NULL + ))) + return status; + + tableListEntry = tableListHeadEntry.Flink; + count = 0; // make sure we can't be forced into an infinite loop by crafted data + + while (tableListEntry != tableListHead && count < PH_ENUM_PROCESS_MODULES_LIMIT) + { + functionTableAddress = CONTAINING_RECORD(tableListEntry, DYNAMIC_FUNCTION_TABLE, ListEntry); + + if (!NT_SUCCESS(status = NtReadVirtualMemory( + ProcessHandle, + functionTableAddress, + &functionTable, + sizeof(DYNAMIC_FUNCTION_TABLE), + NULL + ))) + return status; + + if (Address >= functionTable.MinimumAddress && Address < functionTable.MaximumAddress) + { + if (OutOfProcessCallbackDllBuffer) + { + if (functionTable.OutOfProcessCallbackDll) + { + // Read the out-of-process callback DLL path. We don't have a length, so we'll + // just have to read as much as possible. + + memset(OutOfProcessCallbackDllBuffer, 0xff, OutOfProcessCallbackDllBufferSize); + status = NtReadVirtualMemory( + ProcessHandle, + functionTable.OutOfProcessCallbackDll, + OutOfProcessCallbackDllBuffer, + OutOfProcessCallbackDllBufferSize, + &numberOfBytesRead + ); + + if (status != STATUS_PARTIAL_COPY && !NT_SUCCESS(status)) + return status; + + foundNull = FALSE; + + for (i = 0; i < OutOfProcessCallbackDllBufferSize / sizeof(WCHAR); i++) + { + if (OutOfProcessCallbackDllBuffer[i] == 0) + { + foundNull = TRUE; + + if (OutOfProcessCallbackDllString) + { + OutOfProcessCallbackDllString->Buffer = OutOfProcessCallbackDllBuffer; + OutOfProcessCallbackDllString->Length = (USHORT)(i * sizeof(WCHAR)); + OutOfProcessCallbackDllString->MaximumLength = OutOfProcessCallbackDllString->Length; + } + + break; + } + } + + // If there was no null terminator, then we didn't read the whole string in. + // Fail the operation. + if (!foundNull) + return STATUS_BUFFER_OVERFLOW; + } + else + { + OutOfProcessCallbackDllBuffer[0] = 0; + + if (OutOfProcessCallbackDllString) + { + OutOfProcessCallbackDllString->Buffer = NULL; + OutOfProcessCallbackDllString->Length = 0; + OutOfProcessCallbackDllString->MaximumLength = 0; + } + } + } + + if (FunctionTableAddress) + *FunctionTableAddress = functionTableAddress; + + if (FunctionTable) + *FunctionTable = functionTable; + + return STATUS_SUCCESS; + } + + tableListEntry = functionTable.ListEntry.Flink; + count++; + } + + return STATUS_NOT_FOUND; +} + +PRUNTIME_FUNCTION PhpLookupFunctionEntry( + _In_ PRUNTIME_FUNCTION Functions, + _In_ ULONG NumberOfFunctions, + _In_ BOOLEAN Sorted, + _In_ ULONG64 RelativeControlPc + ) +{ + LONG low; + LONG high; + ULONG i; + + if (Sorted) + { + if (NumberOfFunctions == 0) + return NULL; + + low = 0; + high = NumberOfFunctions - 1; + + do + { + i = (low + high) / 2; + + if (RelativeControlPc < Functions[i].BeginAddress) + high = i - 1; + else if (RelativeControlPc >= Functions[i].EndAddress) + low = i + 1; + else + return &Functions[i]; + } while (low <= high); + } + else + { + for (i = 0; i < NumberOfFunctions; i++) + { + if (RelativeControlPc >= Functions[i].BeginAddress && RelativeControlPc < Functions[i].EndAddress) + return &Functions[i]; + } + } + + return NULL; +} + +NTSTATUS PhpAccessCallbackFunctionTable( + _In_ HANDLE ProcessHandle, + _In_ PVOID FunctionTableAddress, + _In_ PUNICODE_STRING OutOfProcessCallbackDllString, + _Out_ PRUNTIME_FUNCTION *Functions, + _Out_ PULONG NumberOfFunctions + ) +{ + static PH_STRINGREF knownFunctionTableDllsKeyName = PH_STRINGREF_INIT(L"Software\\Microsoft\\Windows NT\\CurrentVersion\\KnownFunctionTableDlls"); + + NTSTATUS status; + HANDLE keyHandle; + ULONG returnLength; + PVOID dllHandle; + ANSI_STRING outOfProcessFunctionTableCallbackName; + POUT_OF_PROCESS_FUNCTION_TABLE_CALLBACK outOfProcessFunctionTableCallback; + + if (!OutOfProcessCallbackDllString->Buffer) + return STATUS_INVALID_PARAMETER; + + // Don't load DLLs from arbitrary locations. Check if this is a known function table DLL. + + if (!NT_SUCCESS(status = PhOpenKey( + &keyHandle, + KEY_READ, + PH_KEY_LOCAL_MACHINE, + &knownFunctionTableDllsKeyName, + 0 + ))) + return status; + + status = NtQueryValueKey(keyHandle, OutOfProcessCallbackDllString, KeyValuePartialInformation, NULL, 0, &returnLength); + NtClose(keyHandle); + + if (status == STATUS_OBJECT_NAME_NOT_FOUND) + return STATUS_ACCESS_DISABLED_BY_POLICY_DEFAULT; + + status = LdrLoadDll(NULL, NULL, OutOfProcessCallbackDllString, &dllHandle); + + if (!NT_SUCCESS(status)) + return status; + + RtlInitAnsiString(&outOfProcessFunctionTableCallbackName, OUT_OF_PROCESS_FUNCTION_TABLE_CALLBACK_EXPORT_NAME); + status = LdrGetProcedureAddress(dllHandle, &outOfProcessFunctionTableCallbackName, 0, (PVOID *)&outOfProcessFunctionTableCallback); + + if (NT_SUCCESS(status)) + { + status = outOfProcessFunctionTableCallback( + ProcessHandle, + FunctionTableAddress, + NumberOfFunctions, + Functions + ); + } + + LdrUnloadDll(dllHandle); + + return status; +} + +NTSTATUS PhpAccessNormalFunctionTable( + _In_ HANDLE ProcessHandle, + _In_ PDYNAMIC_FUNCTION_TABLE FunctionTable, + _Out_ PRUNTIME_FUNCTION *Functions, + _Out_ PULONG NumberOfFunctions + ) +{ + NTSTATUS status; + SIZE_T bufferSize; + PRUNTIME_FUNCTION functions; + + // Put a reasonable limit on the number of entries we read. + if (FunctionTable->EntryCount > 0x100000) + return STATUS_BUFFER_OVERFLOW; + + bufferSize = FunctionTable->EntryCount * sizeof(RUNTIME_FUNCTION); + functions = PhAllocatePage(bufferSize, NULL); + + if (!functions) + return STATUS_NO_MEMORY; + + status = NtReadVirtualMemory(ProcessHandle, FunctionTable->FunctionTable, functions, bufferSize, NULL); + + if (NT_SUCCESS(status)) + { + *Functions = functions; + *NumberOfFunctions = FunctionTable->EntryCount; + } + else + { + PhFreePage(functions); + } + + return status; +} + +NTSTATUS PhAccessOutOfProcessFunctionEntry( + _In_ HANDLE ProcessHandle, + _In_ ULONG64 ControlPc, + _Out_ PRUNTIME_FUNCTION Function + ) +{ + NTSTATUS status; + PDYNAMIC_FUNCTION_TABLE functionTableAddress; + DYNAMIC_FUNCTION_TABLE functionTable; + WCHAR outOfProcessCallbackDll[512]; + UNICODE_STRING outOfProcessCallbackDllString; + PRUNTIME_FUNCTION functions; + ULONG numberOfFunctions; + PRUNTIME_FUNCTION function; + + if (!NT_SUCCESS(status = PhpLookupDynamicFunctionTable( + ProcessHandle, + ControlPc, + &functionTableAddress, + &functionTable, + outOfProcessCallbackDll, + sizeof(outOfProcessCallbackDll), + &outOfProcessCallbackDllString + ))) + { + return status; + } + + if (functionTable.Type == RF_CALLBACK) + { + if (!NT_SUCCESS(status = PhpAccessCallbackFunctionTable( + ProcessHandle, + functionTableAddress, + &outOfProcessCallbackDllString, + &functions, + &numberOfFunctions + ))) + { + return status; + } + + function = PhpLookupFunctionEntry(functions, numberOfFunctions, FALSE, ControlPc - functionTable.BaseAddress); + + if (function) + *Function = *function; + else + status = STATUS_NOT_FOUND; + + RtlFreeHeap(RtlProcessHeap(), 0, functions); + } + else + { + if (!NT_SUCCESS(status = PhpAccessNormalFunctionTable( + ProcessHandle, + &functionTable, + &functions, + &numberOfFunctions + ))) + { + return status; + } + + function = PhpLookupFunctionEntry(functions, numberOfFunctions, functionTable.Type == RF_SORTED, ControlPc - functionTable.BaseAddress); + + if (function) + *Function = *function; + else + status = STATUS_NOT_FOUND; + + PhFreePage(functions); + } + + return status; +} + +#endif + +ULONG64 __stdcall PhGetModuleBase64( + _In_ HANDLE hProcess, + _In_ DWORD64 dwAddr + ) +{ + ULONG64 base; +#ifdef _WIN64 + DYNAMIC_FUNCTION_TABLE functionTable; +#endif + +#ifdef _WIN64 + if (NT_SUCCESS(PhpLookupDynamicFunctionTable( + hProcess, + dwAddr, + NULL, + &functionTable, + NULL, + 0, + NULL + ))) + { + base = functionTable.BaseAddress; + } + else + { + base = 0; + } +#else + base = 0; +#endif + + if (base == 0 && SymGetModuleBase64_I) + base = SymGetModuleBase64_I(hProcess, dwAddr); + + return base; +} + +PVOID __stdcall PhFunctionTableAccess64( + _In_ HANDLE hProcess, + _In_ DWORD64 AddrBase + ) +{ +#ifdef _WIN64 + static RUNTIME_FUNCTION lastRuntimeFunction; +#endif + + PVOID entry; + +#ifdef _WIN64 + if (NT_SUCCESS(PhAccessOutOfProcessFunctionEntry(hProcess, AddrBase, &lastRuntimeFunction))) + entry = &lastRuntimeFunction; + else + entry = NULL; +#else + entry = NULL; +#endif + + if (!entry && SymFunctionTableAccess64_I) + entry = SymFunctionTableAccess64_I(hProcess, AddrBase); + + return entry; +} + +BOOLEAN PhStackWalk( + _In_ ULONG MachineType, + _In_ HANDLE ProcessHandle, + _In_ HANDLE ThreadHandle, + _Inout_ LPSTACKFRAME64 StackFrame, + _Inout_ PVOID ContextRecord, + _In_opt_ PPH_SYMBOL_PROVIDER SymbolProvider, + _In_opt_ PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine, + _In_opt_ PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine, + _In_opt_ PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine, + _In_opt_ PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress + ) +{ + BOOLEAN result; + + PhpRegisterSymbolProvider(SymbolProvider); + + if (!StackWalk64_I) + return FALSE; + + if (!FunctionTableAccessRoutine) + { + if (MachineType == IMAGE_FILE_MACHINE_AMD64) + FunctionTableAccessRoutine = PhFunctionTableAccess64; + else + FunctionTableAccessRoutine = SymFunctionTableAccess64_I; + } + + if (!GetModuleBaseRoutine) + { + if (MachineType == IMAGE_FILE_MACHINE_AMD64) + GetModuleBaseRoutine = PhGetModuleBase64; + else + GetModuleBaseRoutine = SymGetModuleBase64_I; + } + + PH_LOCK_SYMBOLS(); + result = StackWalk64_I( + MachineType, + ProcessHandle, + ThreadHandle, + StackFrame, + ContextRecord, + ReadMemoryRoutine, + FunctionTableAccessRoutine, + GetModuleBaseRoutine, + TranslateAddress + ); + PH_UNLOCK_SYMBOLS(); + + return result; +} + +BOOLEAN PhWriteMiniDumpProcess( + _In_ HANDLE ProcessHandle, + _In_ HANDLE ProcessId, + _In_ HANDLE FileHandle, + _In_ MINIDUMP_TYPE DumpType, + _In_opt_ PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, + _In_opt_ PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam, + _In_opt_ PMINIDUMP_CALLBACK_INFORMATION CallbackParam + ) +{ + PhpRegisterSymbolProvider(NULL); + + if (!MiniDumpWriteDump_I) + { + SetLastError(ERROR_PROC_NOT_FOUND); + return FALSE; + } + + return MiniDumpWriteDump_I( + ProcessHandle, + HandleToUlong(ProcessId), + FileHandle, + DumpType, + ExceptionParam, + UserStreamParam, + CallbackParam + ); +} + +/** + * Converts a STACKFRAME64 structure to a PH_THREAD_STACK_FRAME structure. + * + * \param StackFrame64 A pointer to the STACKFRAME64 structure to convert. + * \param Flags Flags to set in the resulting structure. + * \param ThreadStackFrame A pointer to the resulting PH_THREAD_STACK_FRAME structure. + */ +VOID PhpConvertStackFrame( + _In_ STACKFRAME64 *StackFrame64, + _In_ ULONG Flags, + _Out_ PPH_THREAD_STACK_FRAME ThreadStackFrame + ) +{ + ULONG i; + + ThreadStackFrame->PcAddress = (PVOID)StackFrame64->AddrPC.Offset; + ThreadStackFrame->ReturnAddress = (PVOID)StackFrame64->AddrReturn.Offset; + ThreadStackFrame->FrameAddress = (PVOID)StackFrame64->AddrFrame.Offset; + ThreadStackFrame->StackAddress = (PVOID)StackFrame64->AddrStack.Offset; + ThreadStackFrame->BStoreAddress = (PVOID)StackFrame64->AddrBStore.Offset; + + for (i = 0; i < 4; i++) + ThreadStackFrame->Params[i] = (PVOID)StackFrame64->Params[i]; + + ThreadStackFrame->Flags = Flags; + + if (StackFrame64->FuncTableEntry) + ThreadStackFrame->Flags |= PH_THREAD_STACK_FRAME_FPO_DATA_PRESENT; +} + +/** + * Walks a thread's stack. + * + * \param ThreadHandle A handle to a thread. The handle must have THREAD_QUERY_LIMITED_INFORMATION, + * THREAD_GET_CONTEXT and THREAD_SUSPEND_RESUME access. The handle can have any access for kernel + * stack walking. + * \param ProcessHandle A handle to the thread's parent process. The handle must have + * PROCESS_QUERY_INFORMATION and PROCESS_VM_READ access. If a symbol provider is being used, pass + * its process handle and specify the symbol provider in \a SymbolProvider. + * \param ClientId The client ID identifying the thread. + * \param SymbolProvider The associated symbol provider. + * \param Flags A combination of flags. + * \li \c PH_WALK_I386_STACK Walks the x86 stack. On AMD64 systems this flag walks the WOW64 stack. + * \li \c PH_WALK_AMD64_STACK Walks the AMD64 stack. On x86 systems this flag is ignored. + * \li \c PH_WALK_KERNEL_STACK Walks the kernel stack. This flag is ignored if there is no active + * KProcessHacker connection. + * \param Callback A callback function which is executed for each stack frame. + * \param Context A user-defined value to pass to the callback function. + */ +NTSTATUS PhWalkThreadStack( + _In_ HANDLE ThreadHandle, + _In_opt_ HANDLE ProcessHandle, + _In_opt_ PCLIENT_ID ClientId, + _In_opt_ PPH_SYMBOL_PROVIDER SymbolProvider, + _In_ ULONG Flags, + _In_ PPH_WALK_THREAD_STACK_CALLBACK Callback, + _In_opt_ PVOID Context + ) +{ + NTSTATUS status = STATUS_SUCCESS; + BOOLEAN suspended = FALSE; + BOOLEAN processOpened = FALSE; + BOOLEAN isCurrentThread = FALSE; + BOOLEAN isSystemThread = FALSE; + THREAD_BASIC_INFORMATION basicInfo; + + // Open a handle to the process if we weren't given one. + if (!ProcessHandle) + { + if (KphIsConnected() || !ClientId) + { + if (!NT_SUCCESS(status = PhOpenThreadProcess( + ThreadHandle, + PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, + &ProcessHandle + ))) + return status; + } + else + { + if (!NT_SUCCESS(status = PhOpenProcess( + &ProcessHandle, + PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, + ClientId->UniqueProcess + ))) + return status; + } + + processOpened = TRUE; + } + + // Determine if the caller specified the current thread. + if (ClientId) + { + if (ClientId->UniqueThread == NtCurrentTeb()->ClientId.UniqueThread) + isCurrentThread = TRUE; + if (ClientId->UniqueProcess == SYSTEM_PROCESS_ID) + isSystemThread = TRUE; + } + else + { + if (ThreadHandle == NtCurrentThread()) + { + isCurrentThread = TRUE; + } + else if (NT_SUCCESS(PhGetThreadBasicInformation(ThreadHandle, &basicInfo))) + { + if (basicInfo.ClientId.UniqueThread == NtCurrentTeb()->ClientId.UniqueThread) + isCurrentThread = TRUE; + if (basicInfo.ClientId.UniqueProcess == SYSTEM_PROCESS_ID) + isSystemThread = TRUE; + } + } + + // Make sure this isn't a kernel-mode thread. + if (!isSystemThread) + { + PVOID startAddress; + + if (NT_SUCCESS(NtQueryInformationThread(ThreadHandle, ThreadQuerySetWin32StartAddress, + &startAddress, sizeof(PVOID), NULL))) + { + if ((ULONG_PTR)startAddress > PhSystemBasicInformation.MaximumUserModeAddress) + isSystemThread = TRUE; + } + } + + // Suspend the thread to avoid inaccurate results. Don't suspend if we're walking the stack of + // the current thread or this is a kernel-mode thread. + if (!isCurrentThread && !isSystemThread) + { + if (NT_SUCCESS(NtSuspendThread(ThreadHandle, NULL))) + suspended = TRUE; + } + + // Kernel stack walk. + if ((Flags & PH_WALK_KERNEL_STACK) && KphIsConnected()) + { + PVOID stack[256 - 2]; // See MAX_STACK_DEPTH + ULONG capturedFrames; + ULONG i; + + if (NT_SUCCESS(KphCaptureStackBackTraceThread( + ThreadHandle, + 1, + sizeof(stack) / sizeof(PVOID), + stack, + &capturedFrames, + NULL + ))) + { + PH_THREAD_STACK_FRAME threadStackFrame; + + memset(&threadStackFrame, 0, sizeof(PH_THREAD_STACK_FRAME)); + + for (i = 0; i < capturedFrames; i++) + { + threadStackFrame.PcAddress = stack[i]; + threadStackFrame.Flags = PH_THREAD_STACK_FRAME_KERNEL; + + if (!Callback(&threadStackFrame, Context)) + { + goto ResumeExit; + } + } + } + } + +#ifdef _WIN64 + if (Flags & PH_WALK_AMD64_STACK) + { + STACKFRAME64 stackFrame; + PH_THREAD_STACK_FRAME threadStackFrame; + CONTEXT context; + + context.ContextFlags = CONTEXT_ALL; + + if (!NT_SUCCESS(status = NtGetContextThread( + ThreadHandle, + &context + ))) + goto SkipAmd64Stack; + + memset(&stackFrame, 0, sizeof(STACKFRAME64)); + stackFrame.AddrPC.Mode = AddrModeFlat; + stackFrame.AddrPC.Offset = context.Rip; + stackFrame.AddrStack.Mode = AddrModeFlat; + stackFrame.AddrStack.Offset = context.Rsp; + stackFrame.AddrFrame.Mode = AddrModeFlat; + stackFrame.AddrFrame.Offset = context.Rbp; + + while (TRUE) + { + if (!PhStackWalk( + IMAGE_FILE_MACHINE_AMD64, + ProcessHandle, + ThreadHandle, + &stackFrame, + &context, + SymbolProvider, + NULL, + NULL, + NULL, + NULL + )) + break; + + // If we have an invalid instruction pointer, break. + if (!stackFrame.AddrPC.Offset || stackFrame.AddrPC.Offset == -1) + break; + + // Convert the stack frame and execute the callback. + + PhpConvertStackFrame(&stackFrame, PH_THREAD_STACK_FRAME_AMD64, &threadStackFrame); + + if (!Callback(&threadStackFrame, Context)) + goto ResumeExit; + } + } + +SkipAmd64Stack: +#endif + + // x86/WOW64 stack walk. + if (Flags & PH_WALK_I386_STACK) + { + STACKFRAME64 stackFrame; + PH_THREAD_STACK_FRAME threadStackFrame; +#ifndef _WIN64 + CONTEXT context; + + context.ContextFlags = CONTEXT_ALL; + + if (!NT_SUCCESS(status = NtGetContextThread( + ThreadHandle, + &context + ))) + goto SkipI386Stack; +#else + WOW64_CONTEXT context; + + context.ContextFlags = WOW64_CONTEXT_ALL; + + if (!NT_SUCCESS(status = NtQueryInformationThread( + ThreadHandle, + ThreadWow64Context, + &context, + sizeof(WOW64_CONTEXT), + NULL + ))) + goto SkipI386Stack; +#endif + + memset(&stackFrame, 0, sizeof(STACKFRAME64)); + stackFrame.AddrPC.Mode = AddrModeFlat; + stackFrame.AddrPC.Offset = context.Eip; + stackFrame.AddrStack.Mode = AddrModeFlat; + stackFrame.AddrStack.Offset = context.Esp; + stackFrame.AddrFrame.Mode = AddrModeFlat; + stackFrame.AddrFrame.Offset = context.Ebp; + + while (TRUE) + { + if (!PhStackWalk( + IMAGE_FILE_MACHINE_I386, + ProcessHandle, + ThreadHandle, + &stackFrame, + &context, + SymbolProvider, + NULL, + NULL, + NULL, + NULL + )) + break; + + // If we have an invalid instruction pointer, break. + if (!stackFrame.AddrPC.Offset || stackFrame.AddrPC.Offset == -1) + break; + + // Convert the stack frame and execute the callback. + + PhpConvertStackFrame(&stackFrame, PH_THREAD_STACK_FRAME_I386, &threadStackFrame); + + if (!Callback(&threadStackFrame, Context)) + goto ResumeExit; + + // (x86 only) Allow the user to change Eip, Esp and Ebp. + context.Eip = PtrToUlong(threadStackFrame.PcAddress); + stackFrame.AddrPC.Offset = PtrToUlong(threadStackFrame.PcAddress); + context.Ebp = PtrToUlong(threadStackFrame.FrameAddress); + stackFrame.AddrFrame.Offset = PtrToUlong(threadStackFrame.FrameAddress); + context.Esp = PtrToUlong(threadStackFrame.StackAddress); + stackFrame.AddrStack.Offset = PtrToUlong(threadStackFrame.StackAddress); + } + } + +SkipI386Stack: + +ResumeExit: + if (suspended) + NtResumeThread(ThreadHandle, NULL); + + if (processOpened) + NtClose(ProcessHandle); + + return status; +} diff --git a/phlib/sync.c b/phlib/sync.c index 0c946e66727a..f624bd060841 100644 --- a/phlib/sync.c +++ b/phlib/sync.c @@ -1,496 +1,496 @@ -/* - * Process Hacker - - * misc. synchronization utilities - * - * Copyright (C) 2010-2015 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -/* - * This file contains code for several synchronization objects. - * - * Event. This is a lightweight notification event object that does not create a kernel event object - * until needed. Additionally the kernel event object is automatically freed when no longer needed. - * Note that PhfResetEvent is NOT thread-safe. - * - * Barrier. This is a non-traditional implementation of a barrier, built on the wake event object. I - * have identified three types of participants in this process: - * 1. The slaves, who wait for the master to release them. This is the main mechanism through which - * the threads are synchronized. - * 2. The master, who is the last thread to wait on the barrier. This thread triggers the waking - * process, and waits until all slaves have woken. - * 3. The observers, who are simply threads which were slaves before, were woken, and have tried to - * wait on the barrier again before all other slaves have woken. - * - * Rundown protection. This object allows a thread to wait until all other threads have finished - * using a particular resource before freeing the resource. - * - * Init-once. This is a lightweight one-time initialization mechanism which uses the event object - * for any required blocking. The overhead is very small - only a single inlined comparison. - */ - -#include - -/** - * Initializes an event object. - * - * \param Event A pointer to an event object. - */ -VOID FASTCALL PhfInitializeEvent( - _Out_ PPH_EVENT Event - ) -{ - Event->Value = PH_EVENT_REFCOUNT_INC; - Event->EventHandle = NULL; -} - -/** - * Dereferences the event object used by an event. - * - * \param Event A pointer to an event object. - * \param EventHandle The current value of the event object. - */ -FORCEINLINE VOID PhpDereferenceEvent( - _Inout_ PPH_EVENT Event, - _In_opt_ HANDLE EventHandle - ) -{ - ULONG_PTR value; - - value = _InterlockedExchangeAddPointer((PLONG_PTR)&Event->Value, -PH_EVENT_REFCOUNT_INC); - - // See if the reference count has become 0. - if (((value >> PH_EVENT_REFCOUNT_SHIFT) & PH_EVENT_REFCOUNT_MASK) - 1 == 0) - { - if (EventHandle) - { - NtClose(EventHandle); - Event->EventHandle = NULL; - } - } -} - -/** - * References the event object used by an event. - * - * \param Event A pointer to an event object. - */ -FORCEINLINE VOID PhpReferenceEvent( - _Inout_ PPH_EVENT Event - ) -{ - _InterlockedExchangeAddPointer((PLONG_PTR)&Event->Value, PH_EVENT_REFCOUNT_INC); -} - -/** - * Sets an event object. Any threads waiting on the event will be released. - * - * \param Event A pointer to an event object. - */ -VOID FASTCALL PhfSetEvent( - _Inout_ PPH_EVENT Event - ) -{ - HANDLE eventHandle; - - // Only proceed if the event isn't set already. - if (!_InterlockedBitTestAndSetPointer((PLONG_PTR)&Event->Value, PH_EVENT_SET_SHIFT)) - { - eventHandle = Event->EventHandle; - - if (eventHandle) - { - NtSetEvent(eventHandle, NULL); - } - - PhpDereferenceEvent(Event, eventHandle); - } -} - -/** - * Waits for an event object to be set. - * - * \param Event A pointer to an event object. - * \param Timeout The timeout value. - * - * \return TRUE if the event object was set before the timeout period expired, otherwise FALSE. - * - * \remarks To test the event, use PhTestEvent() instead of using a timeout of zero. - */ -BOOLEAN FASTCALL PhfWaitForEvent( - _Inout_ PPH_EVENT Event, - _In_opt_ PLARGE_INTEGER Timeout - ) -{ - BOOLEAN result; - ULONG_PTR value; - HANDLE eventHandle; - - value = Event->Value; - - // Shortcut: if the event is set, return immediately. - if (value & PH_EVENT_SET) - return TRUE; - - // Shortcut: if the timeout is 0, return immediately if the event isn't set. - if (Timeout && Timeout->QuadPart == 0) - return FALSE; - - // Prevent the event from being invalidated. - PhpReferenceEvent(Event); - - eventHandle = Event->EventHandle; - - if (!eventHandle) - { - NtCreateEvent(&eventHandle, EVENT_ALL_ACCESS, NULL, NotificationEvent, FALSE); - assert(eventHandle); - - // Try to set the event handle to our event. - if (_InterlockedCompareExchangePointer( - &Event->EventHandle, - eventHandle, - NULL - ) != NULL) - { - // Someone else set the event before we did. - NtClose(eventHandle); - eventHandle = Event->EventHandle; - } - } - - // Essential: check the event one last time to see if it is set. - if (!(Event->Value & PH_EVENT_SET)) - { - result = NtWaitForSingleObject(eventHandle, FALSE, Timeout) == STATUS_WAIT_0; - } - else - { - result = TRUE; - } - - PhpDereferenceEvent(Event, eventHandle); - - return result; -} - -/** - * Resets an event's state. - * - * \param Event A pointer to an event object. - * - * \remarks This function is not thread-safe. Make sure no other threads are using the event when - * you call this function. - */ -VOID FASTCALL PhfResetEvent( - _Inout_ PPH_EVENT Event - ) -{ - assert(!Event->EventHandle); - - if (PhTestEvent(Event)) - Event->Value = PH_EVENT_REFCOUNT_INC; -} - -VOID FASTCALL PhfInitializeBarrier( - _Out_ PPH_BARRIER Barrier, - _In_ ULONG_PTR Target - ) -{ - Barrier->Value = Target << PH_BARRIER_TARGET_SHIFT; - PhInitializeWakeEvent(&Barrier->WakeEvent); -} - -FORCEINLINE VOID PhpBlockOnBarrier( - _Inout_ PPH_BARRIER Barrier, - _In_ ULONG Role, - _In_ BOOLEAN Spin - ) -{ - PH_QUEUED_WAIT_BLOCK waitBlock; - ULONG_PTR cancel; - - PhQueueWakeEvent(&Barrier->WakeEvent, &waitBlock); - - cancel = 0; - - switch (Role) - { - case PH_BARRIER_MASTER: - cancel = ((Barrier->Value >> PH_BARRIER_COUNT_SHIFT) & PH_BARRIER_COUNT_MASK) == 1; - break; - case PH_BARRIER_SLAVE: - cancel = Barrier->Value & PH_BARRIER_WAKING; - break; - case PH_BARRIER_OBSERVER: - cancel = !(Barrier->Value & PH_BARRIER_WAKING); - break; - default: - ASSUME_NO_DEFAULT; - } - - if (cancel) - { - PhSetWakeEvent(&Barrier->WakeEvent, &waitBlock); - return; - } - - PhWaitForWakeEvent(&Barrier->WakeEvent, &waitBlock, Spin, NULL); -} - -/** - * Waits until all threads are blocking on the barrier, and resets the state of the barrier. - * - * \param Barrier A barrier. - * \param Spin TRUE to spin on the barrier before blocking, FALSE to block immediately. - * - * \return TRUE for an unspecified thread after each phase, and FALSE for all other threads. - * - * \remarks By checking the return value of the function, in each phase an action can be performed - * exactly once. This could, for example, involve merging the results of calculations. - */ -BOOLEAN FASTCALL PhfWaitForBarrier( - _Inout_ PPH_BARRIER Barrier, - _In_ BOOLEAN Spin - ) -{ - ULONG_PTR value; - ULONG_PTR newValue; - ULONG_PTR count; - ULONG_PTR target; - - value = Barrier->Value; - - while (TRUE) - { - if (!(value & PH_BARRIER_WAKING)) - { - count = (value >> PH_BARRIER_COUNT_SHIFT) & PH_BARRIER_COUNT_MASK; - target = (value >> PH_BARRIER_TARGET_SHIFT) & PH_BARRIER_TARGET_MASK; - assert(count != target); - - count++; - - if (count != target) - newValue = value + PH_BARRIER_COUNT_INC; - else - newValue = value + PH_BARRIER_COUNT_INC + PH_BARRIER_WAKING; - - if ((newValue = (ULONG_PTR)_InterlockedCompareExchangePointer( - (PVOID *)&Barrier->Value, - (PVOID)newValue, - (PVOID)value - )) == value) - { - if (count != target) - { - // Wait for the master signal (the last thread to reach the barrier). - // Once we get it, decrement the count to allow the master to continue. - - do - { - PhpBlockOnBarrier(Barrier, PH_BARRIER_SLAVE, Spin); - } while (!(Barrier->Value & PH_BARRIER_WAKING)); - - value = _InterlockedExchangeAddPointer((PLONG_PTR)&Barrier->Value, -PH_BARRIER_COUNT_INC); - - if (((value >> PH_BARRIER_COUNT_SHIFT) & PH_BARRIER_COUNT_MASK) - 1 == 1) - { - PhSetWakeEvent(&Barrier->WakeEvent, NULL); // for the master - } - - return FALSE; - } - else - { - // We're the last one to reach the barrier, so we become the master. - // Wake the slaves and wait for them to decrease the count to 1. This is so that - // we know the slaves have woken and we don't clear the waking bit before they - // wake. - - PhSetWakeEvent(&Barrier->WakeEvent, NULL); // for slaves - - do - { - PhpBlockOnBarrier(Barrier, PH_BARRIER_MASTER, Spin); - } while (((Barrier->Value >> PH_BARRIER_COUNT_SHIFT) & PH_BARRIER_COUNT_MASK) != 1); - - _InterlockedExchangeAddPointer((PLONG_PTR)&Barrier->Value, -(PH_BARRIER_WAKING + PH_BARRIER_COUNT_INC)); - PhSetWakeEvent(&Barrier->WakeEvent, NULL); // for observers - - return TRUE; - } - } - } - else - { - // We're too early; other threads are still waking. Wait for them to finish. - - PhpBlockOnBarrier(Barrier, PH_BARRIER_OBSERVER, Spin); - newValue = Barrier->Value; - } - - value = newValue; - } -} - -VOID FASTCALL PhfInitializeRundownProtection( - _Out_ PPH_RUNDOWN_PROTECT Protection - ) -{ - Protection->Value = 0; -} - -BOOLEAN FASTCALL PhfAcquireRundownProtection( - _Inout_ PPH_RUNDOWN_PROTECT Protection - ) -{ - ULONG_PTR value; - - // Increment the reference count only if rundown has not started. - - while (TRUE) - { - value = Protection->Value; - - if (value & PH_RUNDOWN_ACTIVE) - return FALSE; - - if ((ULONG_PTR)_InterlockedCompareExchangePointer( - (PVOID *)&Protection->Value, - (PVOID)(value + PH_RUNDOWN_REF_INC), - (PVOID)value - ) == value) - return TRUE; - } -} - -VOID FASTCALL PhfReleaseRundownProtection( - _Inout_ PPH_RUNDOWN_PROTECT Protection - ) -{ - ULONG_PTR value; - - while (TRUE) - { - value = Protection->Value; - - if (value & PH_RUNDOWN_ACTIVE) - { - PPH_RUNDOWN_WAIT_BLOCK waitBlock; - - // Since rundown is active, the reference count has been moved to the waiter's wait - // block. If we are the last user, we must wake up the waiter. - - waitBlock = (PPH_RUNDOWN_WAIT_BLOCK)(value & ~PH_RUNDOWN_ACTIVE); - - if (_InterlockedDecrementPointer(&waitBlock->Count) == 0) - { - PhSetEvent(&waitBlock->WakeEvent); - } - - break; - } - else - { - // Decrement the reference count normally. - - if ((ULONG_PTR)_InterlockedCompareExchangePointer( - (PVOID *)&Protection->Value, - (PVOID)(value - PH_RUNDOWN_REF_INC), - (PVOID)value - ) == value) - break; - } - } -} - -VOID FASTCALL PhfWaitForRundownProtection( - _Inout_ PPH_RUNDOWN_PROTECT Protection - ) -{ - ULONG_PTR value; - ULONG_PTR count; - PH_RUNDOWN_WAIT_BLOCK waitBlock; - BOOLEAN waitBlockInitialized; - - // Fast path. If the reference count is 0 or rundown has already been completed, return. - value = (ULONG_PTR)_InterlockedCompareExchangePointer( - (PVOID *)&Protection->Value, - (PVOID)PH_RUNDOWN_ACTIVE, - (PVOID)0 - ); - - if (value == 0 || value == PH_RUNDOWN_ACTIVE) - return; - - waitBlockInitialized = FALSE; - - while (TRUE) - { - value = Protection->Value; - count = value >> PH_RUNDOWN_REF_SHIFT; - - // Initialize the wait block if necessary. - if (count != 0 && !waitBlockInitialized) - { - PhInitializeEvent(&waitBlock.WakeEvent); - waitBlockInitialized = TRUE; - } - - // Save the existing reference count. - waitBlock.Count = count; - - if ((ULONG_PTR)_InterlockedCompareExchangePointer( - (PVOID *)&Protection->Value, - (PVOID)((ULONG_PTR)&waitBlock | PH_RUNDOWN_ACTIVE), - (PVOID)value - ) == value) - { - if (count != 0) - PhWaitForEvent(&waitBlock.WakeEvent, NULL); - - break; - } - } -} - -VOID FASTCALL PhfInitializeInitOnce( - _Out_ PPH_INITONCE InitOnce - ) -{ - PhInitializeEvent(&InitOnce->Event); -} - -BOOLEAN FASTCALL PhfBeginInitOnce( - _Inout_ PPH_INITONCE InitOnce - ) -{ - if (!_InterlockedBitTestAndSetPointer(&InitOnce->Event.Value, PH_INITONCE_INITIALIZING_SHIFT)) - return TRUE; - - PhWaitForEvent(&InitOnce->Event, NULL); - - return FALSE; -} - -VOID FASTCALL PhfEndInitOnce( - _Inout_ PPH_INITONCE InitOnce - ) -{ - PhSetEvent(&InitOnce->Event); -} +/* + * Process Hacker - + * misc. synchronization utilities + * + * Copyright (C) 2010-2015 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +/* + * This file contains code for several synchronization objects. + * + * Event. This is a lightweight notification event object that does not create a kernel event object + * until needed. Additionally the kernel event object is automatically freed when no longer needed. + * Note that PhfResetEvent is NOT thread-safe. + * + * Barrier. This is a non-traditional implementation of a barrier, built on the wake event object. I + * have identified three types of participants in this process: + * 1. The slaves, who wait for the master to release them. This is the main mechanism through which + * the threads are synchronized. + * 2. The master, who is the last thread to wait on the barrier. This thread triggers the waking + * process, and waits until all slaves have woken. + * 3. The observers, who are simply threads which were slaves before, were woken, and have tried to + * wait on the barrier again before all other slaves have woken. + * + * Rundown protection. This object allows a thread to wait until all other threads have finished + * using a particular resource before freeing the resource. + * + * Init-once. This is a lightweight one-time initialization mechanism which uses the event object + * for any required blocking. The overhead is very small - only a single inlined comparison. + */ + +#include + +/** + * Initializes an event object. + * + * \param Event A pointer to an event object. + */ +VOID FASTCALL PhfInitializeEvent( + _Out_ PPH_EVENT Event + ) +{ + Event->Value = PH_EVENT_REFCOUNT_INC; + Event->EventHandle = NULL; +} + +/** + * Dereferences the event object used by an event. + * + * \param Event A pointer to an event object. + * \param EventHandle The current value of the event object. + */ +FORCEINLINE VOID PhpDereferenceEvent( + _Inout_ PPH_EVENT Event, + _In_opt_ HANDLE EventHandle + ) +{ + ULONG_PTR value; + + value = _InterlockedExchangeAddPointer((PLONG_PTR)&Event->Value, -PH_EVENT_REFCOUNT_INC); + + // See if the reference count has become 0. + if (((value >> PH_EVENT_REFCOUNT_SHIFT) & PH_EVENT_REFCOUNT_MASK) - 1 == 0) + { + if (EventHandle) + { + NtClose(EventHandle); + Event->EventHandle = NULL; + } + } +} + +/** + * References the event object used by an event. + * + * \param Event A pointer to an event object. + */ +FORCEINLINE VOID PhpReferenceEvent( + _Inout_ PPH_EVENT Event + ) +{ + _InterlockedExchangeAddPointer((PLONG_PTR)&Event->Value, PH_EVENT_REFCOUNT_INC); +} + +/** + * Sets an event object. Any threads waiting on the event will be released. + * + * \param Event A pointer to an event object. + */ +VOID FASTCALL PhfSetEvent( + _Inout_ PPH_EVENT Event + ) +{ + HANDLE eventHandle; + + // Only proceed if the event isn't set already. + if (!_InterlockedBitTestAndSetPointer((PLONG_PTR)&Event->Value, PH_EVENT_SET_SHIFT)) + { + eventHandle = Event->EventHandle; + + if (eventHandle) + { + NtSetEvent(eventHandle, NULL); + } + + PhpDereferenceEvent(Event, eventHandle); + } +} + +/** + * Waits for an event object to be set. + * + * \param Event A pointer to an event object. + * \param Timeout The timeout value. + * + * \return TRUE if the event object was set before the timeout period expired, otherwise FALSE. + * + * \remarks To test the event, use PhTestEvent() instead of using a timeout of zero. + */ +BOOLEAN FASTCALL PhfWaitForEvent( + _Inout_ PPH_EVENT Event, + _In_opt_ PLARGE_INTEGER Timeout + ) +{ + BOOLEAN result; + ULONG_PTR value; + HANDLE eventHandle; + + value = Event->Value; + + // Shortcut: if the event is set, return immediately. + if (value & PH_EVENT_SET) + return TRUE; + + // Shortcut: if the timeout is 0, return immediately if the event isn't set. + if (Timeout && Timeout->QuadPart == 0) + return FALSE; + + // Prevent the event from being invalidated. + PhpReferenceEvent(Event); + + eventHandle = Event->EventHandle; + + if (!eventHandle) + { + NtCreateEvent(&eventHandle, EVENT_ALL_ACCESS, NULL, NotificationEvent, FALSE); + assert(eventHandle); + + // Try to set the event handle to our event. + if (_InterlockedCompareExchangePointer( + &Event->EventHandle, + eventHandle, + NULL + ) != NULL) + { + // Someone else set the event before we did. + NtClose(eventHandle); + eventHandle = Event->EventHandle; + } + } + + // Essential: check the event one last time to see if it is set. + if (!(Event->Value & PH_EVENT_SET)) + { + result = NtWaitForSingleObject(eventHandle, FALSE, Timeout) == STATUS_WAIT_0; + } + else + { + result = TRUE; + } + + PhpDereferenceEvent(Event, eventHandle); + + return result; +} + +/** + * Resets an event's state. + * + * \param Event A pointer to an event object. + * + * \remarks This function is not thread-safe. Make sure no other threads are using the event when + * you call this function. + */ +VOID FASTCALL PhfResetEvent( + _Inout_ PPH_EVENT Event + ) +{ + assert(!Event->EventHandle); + + if (PhTestEvent(Event)) + Event->Value = PH_EVENT_REFCOUNT_INC; +} + +VOID FASTCALL PhfInitializeBarrier( + _Out_ PPH_BARRIER Barrier, + _In_ ULONG_PTR Target + ) +{ + Barrier->Value = Target << PH_BARRIER_TARGET_SHIFT; + PhInitializeWakeEvent(&Barrier->WakeEvent); +} + +FORCEINLINE VOID PhpBlockOnBarrier( + _Inout_ PPH_BARRIER Barrier, + _In_ ULONG Role, + _In_ BOOLEAN Spin + ) +{ + PH_QUEUED_WAIT_BLOCK waitBlock; + ULONG_PTR cancel; + + PhQueueWakeEvent(&Barrier->WakeEvent, &waitBlock); + + cancel = 0; + + switch (Role) + { + case PH_BARRIER_MASTER: + cancel = ((Barrier->Value >> PH_BARRIER_COUNT_SHIFT) & PH_BARRIER_COUNT_MASK) == 1; + break; + case PH_BARRIER_SLAVE: + cancel = Barrier->Value & PH_BARRIER_WAKING; + break; + case PH_BARRIER_OBSERVER: + cancel = !(Barrier->Value & PH_BARRIER_WAKING); + break; + default: + ASSUME_NO_DEFAULT; + } + + if (cancel) + { + PhSetWakeEvent(&Barrier->WakeEvent, &waitBlock); + return; + } + + PhWaitForWakeEvent(&Barrier->WakeEvent, &waitBlock, Spin, NULL); +} + +/** + * Waits until all threads are blocking on the barrier, and resets the state of the barrier. + * + * \param Barrier A barrier. + * \param Spin TRUE to spin on the barrier before blocking, FALSE to block immediately. + * + * \return TRUE for an unspecified thread after each phase, and FALSE for all other threads. + * + * \remarks By checking the return value of the function, in each phase an action can be performed + * exactly once. This could, for example, involve merging the results of calculations. + */ +BOOLEAN FASTCALL PhfWaitForBarrier( + _Inout_ PPH_BARRIER Barrier, + _In_ BOOLEAN Spin + ) +{ + ULONG_PTR value; + ULONG_PTR newValue; + ULONG_PTR count; + ULONG_PTR target; + + value = Barrier->Value; + + while (TRUE) + { + if (!(value & PH_BARRIER_WAKING)) + { + count = (value >> PH_BARRIER_COUNT_SHIFT) & PH_BARRIER_COUNT_MASK; + target = (value >> PH_BARRIER_TARGET_SHIFT) & PH_BARRIER_TARGET_MASK; + assert(count != target); + + count++; + + if (count != target) + newValue = value + PH_BARRIER_COUNT_INC; + else + newValue = value + PH_BARRIER_COUNT_INC + PH_BARRIER_WAKING; + + if ((newValue = (ULONG_PTR)_InterlockedCompareExchangePointer( + (PVOID *)&Barrier->Value, + (PVOID)newValue, + (PVOID)value + )) == value) + { + if (count != target) + { + // Wait for the master signal (the last thread to reach the barrier). + // Once we get it, decrement the count to allow the master to continue. + + do + { + PhpBlockOnBarrier(Barrier, PH_BARRIER_SLAVE, Spin); + } while (!(Barrier->Value & PH_BARRIER_WAKING)); + + value = _InterlockedExchangeAddPointer((PLONG_PTR)&Barrier->Value, -PH_BARRIER_COUNT_INC); + + if (((value >> PH_BARRIER_COUNT_SHIFT) & PH_BARRIER_COUNT_MASK) - 1 == 1) + { + PhSetWakeEvent(&Barrier->WakeEvent, NULL); // for the master + } + + return FALSE; + } + else + { + // We're the last one to reach the barrier, so we become the master. + // Wake the slaves and wait for them to decrease the count to 1. This is so that + // we know the slaves have woken and we don't clear the waking bit before they + // wake. + + PhSetWakeEvent(&Barrier->WakeEvent, NULL); // for slaves + + do + { + PhpBlockOnBarrier(Barrier, PH_BARRIER_MASTER, Spin); + } while (((Barrier->Value >> PH_BARRIER_COUNT_SHIFT) & PH_BARRIER_COUNT_MASK) != 1); + + _InterlockedExchangeAddPointer((PLONG_PTR)&Barrier->Value, -(PH_BARRIER_WAKING + PH_BARRIER_COUNT_INC)); + PhSetWakeEvent(&Barrier->WakeEvent, NULL); // for observers + + return TRUE; + } + } + } + else + { + // We're too early; other threads are still waking. Wait for them to finish. + + PhpBlockOnBarrier(Barrier, PH_BARRIER_OBSERVER, Spin); + newValue = Barrier->Value; + } + + value = newValue; + } +} + +VOID FASTCALL PhfInitializeRundownProtection( + _Out_ PPH_RUNDOWN_PROTECT Protection + ) +{ + Protection->Value = 0; +} + +BOOLEAN FASTCALL PhfAcquireRundownProtection( + _Inout_ PPH_RUNDOWN_PROTECT Protection + ) +{ + ULONG_PTR value; + + // Increment the reference count only if rundown has not started. + + while (TRUE) + { + value = Protection->Value; + + if (value & PH_RUNDOWN_ACTIVE) + return FALSE; + + if ((ULONG_PTR)_InterlockedCompareExchangePointer( + (PVOID *)&Protection->Value, + (PVOID)(value + PH_RUNDOWN_REF_INC), + (PVOID)value + ) == value) + return TRUE; + } +} + +VOID FASTCALL PhfReleaseRundownProtection( + _Inout_ PPH_RUNDOWN_PROTECT Protection + ) +{ + ULONG_PTR value; + + while (TRUE) + { + value = Protection->Value; + + if (value & PH_RUNDOWN_ACTIVE) + { + PPH_RUNDOWN_WAIT_BLOCK waitBlock; + + // Since rundown is active, the reference count has been moved to the waiter's wait + // block. If we are the last user, we must wake up the waiter. + + waitBlock = (PPH_RUNDOWN_WAIT_BLOCK)(value & ~PH_RUNDOWN_ACTIVE); + + if (_InterlockedDecrementPointer(&waitBlock->Count) == 0) + { + PhSetEvent(&waitBlock->WakeEvent); + } + + break; + } + else + { + // Decrement the reference count normally. + + if ((ULONG_PTR)_InterlockedCompareExchangePointer( + (PVOID *)&Protection->Value, + (PVOID)(value - PH_RUNDOWN_REF_INC), + (PVOID)value + ) == value) + break; + } + } +} + +VOID FASTCALL PhfWaitForRundownProtection( + _Inout_ PPH_RUNDOWN_PROTECT Protection + ) +{ + ULONG_PTR value; + ULONG_PTR count; + PH_RUNDOWN_WAIT_BLOCK waitBlock; + BOOLEAN waitBlockInitialized; + + // Fast path. If the reference count is 0 or rundown has already been completed, return. + value = (ULONG_PTR)_InterlockedCompareExchangePointer( + (PVOID *)&Protection->Value, + (PVOID)PH_RUNDOWN_ACTIVE, + (PVOID)0 + ); + + if (value == 0 || value == PH_RUNDOWN_ACTIVE) + return; + + waitBlockInitialized = FALSE; + + while (TRUE) + { + value = Protection->Value; + count = value >> PH_RUNDOWN_REF_SHIFT; + + // Initialize the wait block if necessary. + if (count != 0 && !waitBlockInitialized) + { + PhInitializeEvent(&waitBlock.WakeEvent); + waitBlockInitialized = TRUE; + } + + // Save the existing reference count. + waitBlock.Count = count; + + if ((ULONG_PTR)_InterlockedCompareExchangePointer( + (PVOID *)&Protection->Value, + (PVOID)((ULONG_PTR)&waitBlock | PH_RUNDOWN_ACTIVE), + (PVOID)value + ) == value) + { + if (count != 0) + PhWaitForEvent(&waitBlock.WakeEvent, NULL); + + break; + } + } +} + +VOID FASTCALL PhfInitializeInitOnce( + _Out_ PPH_INITONCE InitOnce + ) +{ + PhInitializeEvent(&InitOnce->Event); +} + +BOOLEAN FASTCALL PhfBeginInitOnce( + _Inout_ PPH_INITONCE InitOnce + ) +{ + if (!_InterlockedBitTestAndSetPointer(&InitOnce->Event.Value, PH_INITONCE_INITIALIZING_SHIFT)) + return TRUE; + + PhWaitForEvent(&InitOnce->Event, NULL); + + return FALSE; +} + +VOID FASTCALL PhfEndInitOnce( + _Inout_ PPH_INITONCE InitOnce + ) +{ + PhSetEvent(&InitOnce->Event); +} diff --git a/phlib/treenew.c b/phlib/treenew.c index 0132a52bb4bb..c3e63846612b 100644 --- a/phlib/treenew.c +++ b/phlib/treenew.c @@ -1,6645 +1,6645 @@ -/* - * Process Hacker - - * tree new (tree list control) - * - * Copyright (C) 2011-2016 wj32 - * Copyright (C) 2017 dmex - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -/* - * The tree new is a tree view with columns. Unlike the old tree list control, which was a wrapper - * around the list view control, this control was written from scratch. - * - * Current issues not included in any comments: - * * Adding, removing or changing columns does not cause invalidation. - * * It is not possible to change a column to make it fixed. The current fixed column must be - * removed and the new fixed column must then be added. - * * When there are no visible normal columns, the space usually occupied by the normal column - * headers is filled with a solid background color. We should catch this and paint the usual - * themed background there instead. - * * It is not possible to update any TN_STYLE_* flags after the control is created. - * - * Possible additions: - * * More flexible mouse input callbacks to allow custom controls inside columns. - * * Allow custom drawn columns to customize their behaviour when TN_FLAG_ITEM_DRAG_SELECT is set - * (e.g. disable drag selection over certain areas). - * * Virtual mode - */ - -#include -#include - -#include -#include -#include - -#include - -#include - -static PVOID ComCtl32Handle; -static LONG SmallIconWidth; -static LONG SmallIconHeight; - -BOOLEAN PhTreeNewInitialization( - VOID - ) -{ - WNDCLASSEX c = { sizeof(c) }; - - c.style = CS_DBLCLKS | CS_GLOBALCLASS; - c.lpfnWndProc = PhTnpWndProc; - c.cbClsExtra = 0; - c.cbWndExtra = sizeof(PVOID); - c.hInstance = PhLibImageBase; - c.hIcon = NULL; - c.hCursor = LoadCursor(NULL, IDC_ARROW); - c.hbrBackground = NULL; - c.lpszMenuName = NULL; - c.lpszClassName = PH_TREENEW_CLASSNAME; - c.hIconSm = NULL; - - if (!RegisterClassEx(&c)) - return FALSE; - - ComCtl32Handle = GetModuleHandle(L"comctl32.dll"); - SmallIconWidth = GetSystemMetrics(SM_CXSMICON); - SmallIconHeight = GetSystemMetrics(SM_CYSMICON); - - return TRUE; -} - -LRESULT CALLBACK PhTnpWndProc( - _In_ HWND hwnd, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - PPH_TREENEW_CONTEXT context; - - context = (PPH_TREENEW_CONTEXT)GetWindowLongPtr(hwnd, 0); - - if (uMsg == WM_CREATE) - { - PhTnpCreateTreeNewContext(&context); - SetWindowLongPtr(hwnd, 0, (LONG_PTR)context); - } - - if (!context) - return DefWindowProc(hwnd, uMsg, wParam, lParam); - - if (context->Tracking && (GetAsyncKeyState(VK_ESCAPE) & 0x1)) - { - PhTnpCancelTrack(context); - } - - // Note: if we have suspended restructuring, we *cannot* access any nodes, because all node - // pointers are now invalid. Below, we disable all input. - - switch (uMsg) - { - case WM_CREATE: - { - if (!PhTnpOnCreate(hwnd, context, (CREATESTRUCT *)lParam)) - return -1; - } - return 0; - case WM_NCDESTROY: - { - context->Callback(hwnd, TreeNewDestroying, NULL, NULL, context->CallbackContext); - PhTnpDestroyTreeNewContext(context); - SetWindowLongPtr(hwnd, 0, (LONG_PTR)NULL); - } - return 0; - case WM_SIZE: - { - PhTnpOnSize(hwnd, context); - } - break; - case WM_ERASEBKGND: - return TRUE; - case WM_PAINT: - { - PhTnpOnPaint(hwnd, context); - } - return 0; - case WM_PRINTCLIENT: - { - if (!context->SuspendUpdateStructure) - PhTnpOnPrintClient(hwnd, context, (HDC)wParam, (ULONG)lParam); - } - return 0; - case WM_NCPAINT: - { - if (PhTnpOnNcPaint(hwnd, context, (HRGN)wParam)) - return 0; - } - break; - case WM_GETFONT: - return (LRESULT)context->Font; - case WM_SETFONT: - { - PhTnpOnSetFont(hwnd, context, (HFONT)wParam, LOWORD(lParam)); - } - break; - case WM_STYLECHANGED: - { - PhTnpOnStyleChanged(hwnd, context, (LONG)wParam, (STYLESTRUCT *)lParam); - } - break; - case WM_SETTINGCHANGE: - { - PhTnpOnSettingChange(hwnd, context); - } - break; - case WM_THEMECHANGED: - { - PhTnpOnThemeChanged(hwnd, context); - } - break; - case WM_GETDLGCODE: - return PhTnpOnGetDlgCode(hwnd, context, (ULONG)wParam, (PMSG)lParam); - case WM_SETFOCUS: - { - context->HasFocus = TRUE; - InvalidateRect(context->Handle, NULL, FALSE); - } - return 0; - case WM_KILLFOCUS: - { - context->HasFocus = FALSE; - InvalidateRect(context->Handle, NULL, FALSE); - } - return 0; - case WM_SETCURSOR: - { - if (PhTnpOnSetCursor(hwnd, context, (HWND)wParam)) - return TRUE; - } - break; - case WM_TIMER: - { - PhTnpOnTimer(hwnd, context, (ULONG)wParam); - } - return 0; - case WM_MOUSEMOVE: - { - if (!context->SuspendUpdateStructure) - PhTnpOnMouseMove(hwnd, context, (ULONG)wParam, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); - else - context->SuspendUpdateMoveMouse = TRUE; - } - break; - case WM_MOUSELEAVE: - { - if (!context->SuspendUpdateStructure) - PhTnpOnMouseLeave(hwnd, context); - } - break; - case WM_LBUTTONDOWN: - case WM_LBUTTONUP: - case WM_LBUTTONDBLCLK: - case WM_RBUTTONDOWN: - case WM_RBUTTONUP: - case WM_RBUTTONDBLCLK: - case WM_MBUTTONDOWN: - case WM_MBUTTONUP: - case WM_MBUTTONDBLCLK: - { - if (!context->SuspendUpdateStructure) - PhTnpOnXxxButtonXxx(hwnd, context, uMsg, (ULONG)wParam, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); - } - break; - case WM_CAPTURECHANGED: - { - PhTnpOnCaptureChanged(hwnd, context); - } - break; - case WM_KEYDOWN: - { - if (!context->SuspendUpdateStructure) - PhTnpOnKeyDown(hwnd, context, (ULONG)wParam, (ULONG)lParam); - } - break; - case WM_CHAR: - { - if (!context->SuspendUpdateStructure) - PhTnpOnChar(hwnd, context, (ULONG)wParam, (ULONG)lParam); - } - return 0; - case WM_MOUSEWHEEL: - { - PhTnpOnMouseWheel(hwnd, context, (SHORT)HIWORD(wParam), LOWORD(wParam), GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); - } - break; - case WM_MOUSEHWHEEL: - { - PhTnpOnMouseHWheel(hwnd, context, (SHORT)HIWORD(wParam), LOWORD(wParam), GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); - } - break; - case WM_CONTEXTMENU: - { - if (!context->SuspendUpdateStructure) - PhTnpOnContextMenu(hwnd, context, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); - } - return 0; - case WM_VSCROLL: - { - PhTnpOnVScroll(hwnd, context, LOWORD(wParam), HIWORD(wParam)); - } - return 0; - case WM_HSCROLL: - { - PhTnpOnHScroll(hwnd, context, LOWORD(wParam), HIWORD(wParam)); - } - return 0; - case WM_NOTIFY: - { - LRESULT result; - - if (PhTnpOnNotify(hwnd, context, (NMHDR *)lParam, &result)) - return result; - } - break; - } - - if (uMsg >= TNM_FIRST && uMsg <= TNM_LAST) - { - return PhTnpOnUserMessage(hwnd, context, uMsg, wParam, lParam); - } - - switch (uMsg) - { - case WM_MOUSEMOVE: - case WM_LBUTTONDOWN: - case WM_LBUTTONUP: - case WM_RBUTTONDOWN: - case WM_RBUTTONUP: - case WM_MBUTTONDOWN: - case WM_MBUTTONUP: - { - if (context->TooltipsHandle) - { - MSG message; - - message.hwnd = hwnd; - message.message = uMsg; - message.wParam = wParam; - message.lParam = lParam; - SendMessage(context->TooltipsHandle, TTM_RELAYEVENT, 0, (LPARAM)&message); - } - } - break; - } - - return DefWindowProc(hwnd, uMsg, wParam, lParam); -} - -BOOLEAN NTAPI PhTnpNullCallback( - _In_ HWND hwnd, - _In_ PH_TREENEW_MESSAGE Message, - _In_opt_ PVOID Parameter1, - _In_opt_ PVOID Parameter2, - _In_opt_ PVOID Context - ) -{ - return FALSE; -} - -VOID PhTnpCreateTreeNewContext( - _Out_ PPH_TREENEW_CONTEXT *Context - ) -{ - PPH_TREENEW_CONTEXT context; - - context = PhAllocate(sizeof(PH_TREENEW_CONTEXT)); - memset(context, 0, sizeof(PH_TREENEW_CONTEXT)); - - context->FixedWidthMinimum = 20; - context->RowHeight = 1; // must never be 0 - context->HotNodeIndex = -1; - context->Callback = PhTnpNullCallback; - context->FlatList = PhCreateList(64); - context->TooltipIndex = -1; - context->TooltipId = -1; - context->TooltipColumnId = -1; - context->EnableRedraw = 1; - - *Context = context; -} - -VOID PhTnpDestroyTreeNewContext( - _In_ PPH_TREENEW_CONTEXT Context - ) -{ - ULONG i; - - if (Context->Columns) - { - for (i = 0; i < Context->NextId; i++) - { - if (Context->Columns[i]) - PhFree(Context->Columns[i]); - } - - PhFree(Context->Columns); - } - - if (Context->ColumnsByDisplay) - PhFree(Context->ColumnsByDisplay); - - PhDereferenceObject(Context->FlatList); - - if (Context->FontOwned) - DeleteObject(Context->Font); - - if (Context->ThemeData) - CloseThemeData(Context->ThemeData); - - if (Context->SearchString) - PhFree(Context->SearchString); - - if (Context->TooltipText) - PhDereferenceObject(Context->TooltipText); - - if (Context->BufferedContext) - PhTnpDestroyBufferedContext(Context); - - if (Context->SuspendUpdateRegion) - DeleteObject(Context->SuspendUpdateRegion); - - PhFree(Context); -} - -BOOLEAN PhTnpOnCreate( - _In_ HWND hwnd, - _In_ PPH_TREENEW_CONTEXT Context, - _In_ CREATESTRUCT *CreateStruct - ) -{ - ULONG headerStyle; - - Context->Handle = hwnd; - Context->InstanceHandle = CreateStruct->hInstance; - Context->Style = CreateStruct->style; - Context->ExtendedStyle = CreateStruct->dwExStyle; - - if (Context->Style & TN_STYLE_DOUBLE_BUFFERED) - Context->DoubleBuffered = TRUE; - if ((Context->Style & TN_STYLE_ANIMATE_DIVIDER) && Context->DoubleBuffered) - Context->AnimateDivider = TRUE; - - headerStyle = HDS_HORZ | HDS_FULLDRAG; - - if (!(Context->Style & TN_STYLE_NO_COLUMN_SORT)) - headerStyle |= HDS_BUTTONS; - if (!(Context->Style & TN_STYLE_NO_COLUMN_HEADER)) - headerStyle |= WS_VISIBLE; - - if (!(Context->FixedHeaderHandle = CreateWindow( - WC_HEADER, - NULL, - WS_CHILD | WS_CLIPSIBLINGS | headerStyle, - 0, - 0, - 0, - 0, - hwnd, - NULL, - CreateStruct->hInstance, - NULL - ))) - { - return FALSE; - } - - if (!(Context->Style & TN_STYLE_NO_COLUMN_REORDER)) - headerStyle |= HDS_DRAGDROP; - - if (!(Context->HeaderHandle = CreateWindow( - WC_HEADER, - NULL, - WS_CHILD | WS_CLIPSIBLINGS | headerStyle, - 0, - 0, - 0, - 0, - hwnd, - NULL, - CreateStruct->hInstance, - NULL - ))) - { - return FALSE; - } - - if (!(Context->VScrollHandle = CreateWindow( - L"SCROLLBAR", - NULL, - WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | SBS_VERT, - 0, - 0, - 0, - 0, - hwnd, - NULL, - CreateStruct->hInstance, - NULL - ))) - { - return FALSE; - } - - if (!(Context->HScrollHandle = CreateWindow( - L"SCROLLBAR", - NULL, - WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | SBS_HORZ, - 0, - 0, - 0, - 0, - hwnd, - NULL, - CreateStruct->hInstance, - NULL - ))) - { - return FALSE; - } - - if (!(Context->FillerBoxHandle = CreateWindow( - L"STATIC", - NULL, - WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE, - 0, - 0, - 0, - 0, - hwnd, - NULL, - CreateStruct->hInstance, - NULL - ))) - { - return FALSE; - } - - PhTnpSetFont(Context, NULL, FALSE); // use default font - PhTnpUpdateSystemMetrics(Context); - PhTnpInitializeTooltips(Context); - - return TRUE; -} - -VOID PhTnpOnSize( - _In_ HWND hwnd, - _In_ PPH_TREENEW_CONTEXT Context - ) -{ - GetClientRect(hwnd, &Context->ClientRect); - - if (Context->BufferedContext && ( - Context->BufferedContextRect.right < Context->ClientRect.right || - Context->BufferedContextRect.bottom < Context->ClientRect.bottom)) - { - // Invalidate the buffered context because the client size has increased. - PhTnpDestroyBufferedContext(Context); - } - - PhTnpLayout(Context); - - if (Context->TooltipsHandle) - { - TOOLINFO toolInfo; - - memset(&toolInfo, 0, sizeof(TOOLINFO)); - toolInfo.cbSize = sizeof(TOOLINFO); - toolInfo.hwnd = hwnd; - toolInfo.uId = TNP_TOOLTIPS_ITEM; - toolInfo.rect = Context->ClientRect; - SendMessage(Context->TooltipsHandle, TTM_NEWTOOLRECT, 0, (LPARAM)&toolInfo); - } -} - -VOID PhTnpOnSetFont( - _In_ HWND hwnd, - _In_ PPH_TREENEW_CONTEXT Context, - _In_opt_ HFONT Font, - _In_ LOGICAL Redraw - ) -{ - PhTnpSetFont(Context, Font, !!Redraw); - PhTnpLayout(Context); -} - -VOID PhTnpOnStyleChanged( - _In_ HWND hwnd, - _In_ PPH_TREENEW_CONTEXT Context, - _In_ LONG Type, - _In_ STYLESTRUCT *StyleStruct - ) -{ - if (Type == GWL_EXSTYLE) - Context->ExtendedStyle = StyleStruct->styleNew; -} - -VOID PhTnpOnSettingChange( - _In_ HWND hwnd, - _In_ PPH_TREENEW_CONTEXT Context - ) -{ - PhTnpUpdateSystemMetrics(Context); - PhTnpUpdateTextMetrics(Context); - PhTnpLayout(Context); -} - -VOID PhTnpOnThemeChanged( - _In_ HWND hwnd, - _In_ PPH_TREENEW_CONTEXT Context - ) -{ - PhTnpUpdateThemeData(Context); -} - -ULONG PhTnpOnGetDlgCode( - _In_ HWND hwnd, - _In_ PPH_TREENEW_CONTEXT Context, - _In_ ULONG VirtualKey, - _In_opt_ PMSG Message - ) -{ - ULONG code; - - if (Context->Callback(hwnd, TreeNewGetDialogCode, UlongToPtr(VirtualKey), &code, Context->CallbackContext)) - { - return code; - } - - return DLGC_WANTARROWS | DLGC_WANTCHARS; -} - -VOID PhTnpOnPaint( - _In_ HWND hwnd, - _In_ PPH_TREENEW_CONTEXT Context - ) -{ - RECT updateRect; - HDC hdc; - PAINTSTRUCT paintStruct; - - if (GetUpdateRect(hwnd, &updateRect, FALSE) && (updateRect.left | updateRect.right | updateRect.top | updateRect.bottom)) - { - if (Context->EnableRedraw <= 0) - { - HRGN updateRegion; - - updateRegion = CreateRectRgn(0, 0, 0, 0); - GetUpdateRgn(hwnd, updateRegion, FALSE); - - if (!Context->SuspendUpdateRegion) - { - Context->SuspendUpdateRegion = updateRegion; - } - else - { - CombineRgn(Context->SuspendUpdateRegion, Context->SuspendUpdateRegion, updateRegion, RGN_OR); - DeleteObject(updateRegion); - } - - // Pretend we painted something; this ensures the update region is validated properly. - if (BeginPaint(hwnd, &paintStruct)) - EndPaint(hwnd, &paintStruct); - - return; - } - - if (Context->DoubleBuffered) - { - if (!Context->BufferedContext) - { - PhTnpCreateBufferedContext(Context); - } - } - - if (hdc = BeginPaint(hwnd, &paintStruct)) - { - updateRect = paintStruct.rcPaint; - - if (Context->BufferedContext) - { - PhTnpPaint(hwnd, Context, Context->BufferedContext, &updateRect); - BitBlt( - hdc, - updateRect.left, - updateRect.top, - updateRect.right - updateRect.left, - updateRect.bottom - updateRect.top, - Context->BufferedContext, - updateRect.left, - updateRect.top, - SRCCOPY - ); - } - else - { - PhTnpPaint(hwnd, Context, hdc, &updateRect); - } - - EndPaint(hwnd, &paintStruct); - } - } -} - -VOID PhTnpOnPrintClient( - _In_ HWND hwnd, - _In_ PPH_TREENEW_CONTEXT Context, - _In_ HDC hdc, - _In_ ULONG Flags - ) -{ - PhTnpPaint(hwnd, Context, hdc, &Context->ClientRect); -} - -BOOLEAN PhTnpOnNcPaint( - _In_ HWND hwnd, - _In_ PPH_TREENEW_CONTEXT Context, - _In_opt_ HRGN UpdateRegion - ) -{ - PhTnpInitializeThemeData(Context); - - // Themed border - if ((Context->ExtendedStyle & WS_EX_CLIENTEDGE) && Context->ThemeData) - { - HDC hdc; - ULONG flags; - - if (UpdateRegion == HRGN_FULL) - UpdateRegion = NULL; - - // Note the use of undocumented flags below. GetDCEx doesn't work without these. - - flags = DCX_WINDOW | DCX_LOCKWINDOWUPDATE | 0x10000; - - if (UpdateRegion) - flags |= DCX_INTERSECTRGN | 0x40000; - - if (hdc = GetDCEx(hwnd, UpdateRegion, flags)) - { - PhTnpDrawThemedBorder(Context, hdc); - ReleaseDC(hwnd, hdc); - return TRUE; - } - } - - return FALSE; -} - -BOOLEAN PhTnpOnSetCursor( - _In_ HWND hwnd, - _In_ PPH_TREENEW_CONTEXT Context, - _In_ HWND CursorWindowHandle - ) -{ - POINT point; - - PhTnpGetMessagePos(hwnd, &point); - - if (TNP_HIT_TEST_FIXED_DIVIDER(point.x, Context)) - { - if (!Context->DividerCursor) - Context->DividerCursor = LoadCursor(ComCtl32Handle, MAKEINTRESOURCE(106)); // HACK (the divider icon resource has been 106 for quite a while...) - - SetCursor(Context->DividerCursor); - return TRUE; - } - - if (Context->Cursor) - { - SetCursor(Context->Cursor); - return TRUE; - } - - return FALSE; -} - -VOID PhTnpOnTimer( - _In_ HWND hwnd, - _In_ PPH_TREENEW_CONTEXT Context, - _In_ ULONG Id - ) -{ - if (Id == TNP_TIMER_ANIMATE_DIVIDER) - { - RECT dividerRect; - - dividerRect.left = Context->FixedWidth; - dividerRect.top = Context->HeaderHeight; - dividerRect.right = Context->FixedWidth + 1; - dividerRect.bottom = Context->ClientRect.bottom; - - if (Context->AnimateDividerFadingIn) - { - Context->DividerHot += TNP_ANIMATE_DIVIDER_INCREMENT; - - if (Context->DividerHot >= 100) - { - Context->DividerHot = 100; - Context->AnimateDividerFadingIn = FALSE; - KillTimer(hwnd, TNP_TIMER_ANIMATE_DIVIDER); - } - - InvalidateRect(hwnd, ÷rRect, FALSE); - } - else if (Context->AnimateDividerFadingOut) - { - if (Context->DividerHot <= TNP_ANIMATE_DIVIDER_DECREMENT) - { - Context->DividerHot = 0; - Context->AnimateDividerFadingOut = FALSE; - KillTimer(hwnd, TNP_TIMER_ANIMATE_DIVIDER); - } - else - { - Context->DividerHot -= TNP_ANIMATE_DIVIDER_DECREMENT; - } - - InvalidateRect(hwnd, ÷rRect, FALSE); - } - } -} - -VOID PhTnpOnMouseMove( - _In_ HWND hwnd, - _In_ PPH_TREENEW_CONTEXT Context, - _In_ ULONG VirtualKeys, - _In_ LONG CursorX, - _In_ LONG CursorY - ) -{ - TRACKMOUSEEVENT trackMouseEvent; - - trackMouseEvent.cbSize = sizeof(TRACKMOUSEEVENT); - trackMouseEvent.dwFlags = TME_LEAVE; - trackMouseEvent.hwndTrack = hwnd; - trackMouseEvent.dwHoverTime = 0; - TrackMouseEvent(&trackMouseEvent); - - if (Context->Tracking) - { - ULONG newFixedWidth; - - newFixedWidth = Context->TrackOldFixedWidth + (CursorX - Context->TrackStartX); - PhTnpSetFixedWidth(Context, newFixedWidth); - } - - PhTnpProcessMoveMouse(Context, CursorX, CursorY); -} - -VOID PhTnpOnMouseLeave( - _In_ HWND hwnd, - _In_ PPH_TREENEW_CONTEXT Context - ) -{ - RECT rect; - - if (Context->HotNodeIndex != -1 && Context->ThemeData) - { - // Update the old hot node because it may have a different non-hot background and plus minus part. - if (PhTnpGetRowRects(Context, Context->HotNodeIndex, Context->HotNodeIndex, TRUE, &rect)) - { - InvalidateRect(Context->Handle, &rect, FALSE); - } - } - - Context->HotNodeIndex = -1; - - if (Context->AnimateDivider && Context->FixedDividerVisible) - { - if ((Context->DividerHot != 0 || Context->AnimateDividerFadingIn) && !Context->AnimateDividerFadingOut) - { - // Fade out the divider. - Context->AnimateDividerFadingOut = TRUE; - Context->AnimateDividerFadingIn = FALSE; - SetTimer(Context->Handle, TNP_TIMER_ANIMATE_DIVIDER, TNP_ANIMATE_DIVIDER_INTERVAL, NULL); - } - } -} - -VOID PhTnpOnXxxButtonXxx( - _In_ HWND hwnd, - _In_ PPH_TREENEW_CONTEXT Context, - _In_ ULONG Message, - _In_ ULONG VirtualKeys, - _In_ LONG CursorX, - _In_ LONG CursorY - ) -{ - BOOLEAN startingTracking; - PH_TREENEW_HIT_TEST hitTest; - LOGICAL controlKey; - LOGICAL shiftKey; - RECT rect; - ULONG changedStart; - ULONG changedEnd; - PH_TREENEW_MESSAGE clickMessage; - - // Focus - - if (Message == WM_LBUTTONDOWN || Message == WM_RBUTTONDOWN) - SetFocus(hwnd); - - // Divider tracking - - startingTracking = FALSE; - - switch (Message) - { - case WM_LBUTTONDOWN: - { - if (TNP_HIT_TEST_FIXED_DIVIDER(CursorX, Context)) - { - startingTracking = TRUE; - Context->Tracking = TRUE; - Context->TrackStartX = CursorX; - Context->TrackOldFixedWidth = Context->FixedWidth; - SetCapture(hwnd); - - SetTimer(hwnd, TNP_TIMER_NULL, 100, NULL); // make sure we get messages once in a while so we can detect the escape key - GetAsyncKeyState(VK_ESCAPE); - } - } - break; - case WM_LBUTTONUP: - { - if (Context->Tracking) - { - ReleaseCapture(); - } - } - break; - case WM_RBUTTONDOWN: - { - if (Context->Tracking) - { - PhTnpCancelTrack(Context); - } - } - break; - } - - if (!startingTracking && Context->Tracking) // still OK to process further if the user is only starting to drag the divider - return; - - hitTest.Point.x = CursorX; - hitTest.Point.y = CursorY; - hitTest.InFlags = TN_TEST_COLUMN | TN_TEST_SUBITEM; - PhTnpHitTest(Context, &hitTest); - - controlKey = VirtualKeys & MK_CONTROL; - shiftKey = VirtualKeys & MK_SHIFT; - - // Plus minus glyph - - if ((hitTest.Flags & TN_HIT_ITEM_PLUSMINUS) && Message == WM_LBUTTONDOWN) - { - PhTnpSetExpandedNode(Context, hitTest.Node, !hitTest.Node->Expanded); - } - - // Selection - - if (!(hitTest.Flags & TN_HIT_ITEM_PLUSMINUS) && (Message == WM_LBUTTONDOWN || Message == WM_RBUTTONDOWN)) - { - LOGICAL allowDragSelect; - PH_TREENEW_CELL_PARTS parts; - - PhTnpPopTooltip(Context); - allowDragSelect = TRUE; - - if (hitTest.Flags & TN_HIT_ITEM) - { - allowDragSelect = FALSE; - Context->FocusNode = hitTest.Node; - - if (Context->ExtendedFlags & TN_FLAG_ITEM_DRAG_SELECT) - { - // To allow drag selection to begin even if the cursor is on an item, we check if - // the cursor is on the item icon or text. Exceptions are: - // * When the item is already selected - // * When user is beginning to drag the divider - - if (!hitTest.Node->Selected && !startingTracking) - { - if (PhTnpGetCellParts(Context, hitTest.Node->Index, hitTest.Column, TN_MEASURE_TEXT, &parts)) - { - allowDragSelect = TRUE; - - if ((parts.Flags & TN_PART_ICON) && CursorX >= parts.IconRect.left && CursorX < parts.IconRect.right) - allowDragSelect = FALSE; - - if ((parts.Flags & TN_PART_CONTENT) && (parts.Flags & TN_PART_TEXT)) - { - if (CursorX >= parts.TextRect.left && CursorX < parts.TextRect.right) - allowDragSelect = FALSE; - } - } - } - } - - PhTnpProcessSelectNode(Context, hitTest.Node, controlKey, shiftKey, Message == WM_RBUTTONDOWN); - } - - if (allowDragSelect) - { - BOOLEAN dragSelect; - ULONG indexToSelect; - BOOLEAN selectionProcessed; - BOOLEAN showContextMenu; - - dragSelect = FALSE; - indexToSelect = -1; - selectionProcessed = FALSE; - showContextMenu = FALSE; - - if (!(hitTest.Flags & (TN_HIT_LEFT | TN_HIT_RIGHT | TN_HIT_ABOVE | TN_HIT_BELOW)) && !startingTracking) // don't interfere with divider - { - BOOLEAN result; - ULONG saveIndex; - ULONG saveId; - ULONG cancelledByMessage; - - // Check for drag selection. PhTnpDetectDrag has its own message loop, so we need to - // clear our pointers before we continue or we will have some access violations when - // items get deleted. - - if (hitTest.Node) - saveIndex = hitTest.Node->Index; - else - saveIndex = -1; - - if (hitTest.Column) - saveId = hitTest.Column->Id; - else - saveId = -1; - - result = PhTnpDetectDrag(Context, CursorX, CursorY, TRUE, &cancelledByMessage); - - // Restore the pointers. - - if (saveIndex == -1) - hitTest.Node = NULL; - else if (saveIndex < Context->FlatList->Count) - hitTest.Node = Context->FlatList->Items[saveIndex]; - else - return; - - if (saveId != -1 && !(hitTest.Column = PhTnpLookupColumnById(Context, saveId))) - return; - - if (result) - { - dragSelect = TRUE; - - if ((hitTest.Flags & TN_HIT_ITEM) && (Context->ExtendedFlags & TN_FLAG_ITEM_DRAG_SELECT)) - { - // Include the current node before starting the drag selection, otherwise - // the user will never be able to select the current node. - indexToSelect = hitTest.Node->Index; - } - } - else - { - if ((Message == WM_LBUTTONDOWN && cancelledByMessage == WM_LBUTTONUP) || - (Message == WM_RBUTTONDOWN && cancelledByMessage == WM_RBUTTONUP)) - { - POINT point; - - if ((hitTest.Flags & TN_HIT_ITEM) && (Context->ExtendedFlags & TN_FLAG_ITEM_DRAG_SELECT)) - { - // The user isn't performing a drag selection, so prevent deselection. - selectionProcessed = TRUE; - } - - // The button up message gets consumed by PhTnpDetectDrag, so send the mouse - // event here. - // Check if the cursor stayed in the same place. - - PhTnpGetMessagePos(Context->Handle, &point); - - if (point.x == CursorX && point.y == CursorY) - { - PhTnpSendMouseEvent( - Context, - Message == WM_LBUTTONDOWN ? TreeNewLeftClick : TreeNewRightClick, - CursorX, - CursorY, - hitTest.Node, - hitTest.Column, - VirtualKeys - ); - } - - if (Message == WM_RBUTTONDOWN) - showContextMenu = TRUE; - } - } - } - - if (!selectionProcessed && !controlKey && !shiftKey) - { - // Nothing: deselect everything. - - PhTnpSelectRange(Context, indexToSelect, indexToSelect, TN_SELECT_RESET, &changedStart, &changedEnd); - - if (PhTnpGetRowRects(Context, changedStart, changedEnd, TRUE, &rect)) - { - InvalidateRect(hwnd, &rect, FALSE); - } - } - - if (dragSelect) - { - PhTnpDragSelect(Context, CursorX, CursorY); - } - - if (showContextMenu) - { - SendMessage(Context->Handle, WM_CONTEXTMENU, (WPARAM)Context->Handle, GetMessagePos()); - } - - return; - } - } - - // Click, double-click - // Note: If TN_FLAG_ITEM_DRAG_SELECT is enabled, the code below that processes WM_xBUTTONDOWN - // and WM_xBUTTONUP messages only takes effect when the user clicks directly on an item's icon - // or text. - - clickMessage = -1; - - if (Message == WM_LBUTTONDOWN || Message == WM_RBUTTONDOWN) - { - if (Context->MouseDownLast != 0 && Context->MouseDownLast != Message) - { - // User pressed one button and pressed the other without letting go of the first one. - // This counts as a click. - - if (Context->MouseDownLast == WM_LBUTTONDOWN) - clickMessage = TreeNewLeftClick; - else - clickMessage = TreeNewRightClick; - } - - Context->MouseDownLast = Message; - Context->MouseDownLocation.x = CursorX; - Context->MouseDownLocation.y = CursorY; - } - else if (Message == WM_LBUTTONUP || Message == WM_RBUTTONUP) - { - if (Context->MouseDownLast != 0 && - Context->MouseDownLocation.x == CursorX && Context->MouseDownLocation.y == CursorY) - { - if (Context->MouseDownLast == WM_LBUTTONDOWN) - clickMessage = TreeNewLeftClick; - else - clickMessage = TreeNewRightClick; - } - - Context->MouseDownLast = 0; - } - else if (Message == WM_LBUTTONDBLCLK) - { - clickMessage = TreeNewLeftDoubleClick; - } - else if (Message == WM_RBUTTONDBLCLK) - { - clickMessage = TreeNewRightDoubleClick; - } - - if (!(hitTest.Flags & TN_HIT_ITEM_PLUSMINUS) && clickMessage != -1) - { - PhTnpSendMouseEvent(Context, clickMessage, CursorX, CursorY, hitTest.Node, hitTest.Column, VirtualKeys); - } -} - -VOID PhTnpOnCaptureChanged( - _In_ HWND hwnd, - _In_ PPH_TREENEW_CONTEXT Context - ) -{ - Context->Tracking = FALSE; - KillTimer(hwnd, TNP_TIMER_NULL); -} - -VOID PhTnpOnKeyDown( - _In_ HWND hwnd, - _In_ PPH_TREENEW_CONTEXT Context, - _In_ ULONG VirtualKey, - _In_ ULONG Data - ) -{ - PH_TREENEW_KEY_EVENT keyEvent; - - keyEvent.Handled = FALSE; - keyEvent.VirtualKey = VirtualKey; - keyEvent.Data = Data; - Context->Callback(Context->Handle, TreeNewKeyDown, &keyEvent, NULL, Context->CallbackContext); - - if (keyEvent.Handled) - return; - - if (PhTnpProcessFocusKey(Context, VirtualKey)) - return; - if (PhTnpProcessNodeKey(Context, VirtualKey)) - return; -} - -VOID PhTnpOnChar( - _In_ HWND hwnd, - _In_ PPH_TREENEW_CONTEXT Context, - _In_ ULONG Character, - _In_ ULONG Data - ) -{ - // Make sure the character is printable. - if (Character >= ' ' && Character <= '~') - { - PhTnpProcessSearchKey(Context, Character); - } -} - -VOID PhTnpOnMouseWheel( - _In_ HWND hwnd, - _In_ PPH_TREENEW_CONTEXT Context, - _In_ LONG Distance, - _In_ ULONG VirtualKeys, - _In_ LONG CursorX, - _In_ LONG CursorY - ) -{ - // The normal mouse wheel can affect both the vertical scrollbar and the horizontal scrollbar, - // but the vertical scrollbar takes precedence. - if (Context->VScrollVisible) - { - PhTnpProcessMouseVWheel(Context, -Distance); - } - else if (Context->HScrollVisible) - { - PhTnpProcessMouseHWheel(Context, -Distance); - } -} - -VOID PhTnpOnMouseHWheel( - _In_ HWND hwnd, - _In_ PPH_TREENEW_CONTEXT Context, - _In_ LONG Distance, - _In_ ULONG VirtualKeys, - _In_ LONG CursorX, - _In_ LONG CursorY - ) -{ - PhTnpProcessMouseHWheel(Context, Distance); -} - -VOID PhTnpOnContextMenu( - _In_ HWND hwnd, - _In_ PPH_TREENEW_CONTEXT Context, - _In_ LONG CursorScreenX, - _In_ LONG CursorScreenY - ) -{ - POINT clientPoint; - BOOLEAN keyboardInvoked; - PH_TREENEW_HIT_TEST hitTest; - PH_TREENEW_CONTEXT_MENU contextMenu; - - if (CursorScreenX == -1 && CursorScreenY == -1) - { - ULONG i; - BOOLEAN found; - RECT windowRect; - RECT rect; - - keyboardInvoked = TRUE; - - // Context menu was invoked via keyboard. Display the context menu at the selected item. - - found = FALSE; - - for (i = 0; i < Context->FlatList->Count; i++) - { - if (((PPH_TREENEW_NODE)Context->FlatList->Items[i])->Selected) - { - found = TRUE; - break; - } - } - - if (found && PhTnpGetRowRects(Context, i, i, FALSE, &rect) && - rect.top >= Context->ClientRect.top && rect.top < Context->ClientRect.bottom) - { - clientPoint.x = rect.left + SmallIconWidth / 2; - clientPoint.y = rect.top + Context->RowHeight / 2; - } - else - { - clientPoint.x = 0; - clientPoint.y = 0; - } - - GetWindowRect(hwnd, &windowRect); - CursorScreenX = windowRect.left + clientPoint.x; - CursorScreenY = windowRect.top + clientPoint.y; - } - else - { - keyboardInvoked = FALSE; - - clientPoint.x = CursorScreenX; - clientPoint.y = CursorScreenY; - ScreenToClient(hwnd, &clientPoint); - - if (clientPoint.y < Context->HeaderHeight) - { - // Already handled by TreeNewHeaderRightClick. - return; - } - } - - hitTest.Point = clientPoint; - hitTest.InFlags = TN_TEST_COLUMN; - PhTnpHitTest(Context, &hitTest); - - contextMenu.Location.x = CursorScreenX; - contextMenu.Location.y = CursorScreenY; - contextMenu.ClientLocation = clientPoint; - contextMenu.Node = hitTest.Node; - contextMenu.Column = hitTest.Column; - contextMenu.KeyboardInvoked = keyboardInvoked; - Context->Callback(hwnd, TreeNewContextMenu, &contextMenu, NULL, Context->CallbackContext); -} - -VOID PhTnpOnVScroll( - _In_ HWND hwnd, - _In_ PPH_TREENEW_CONTEXT Context, - _In_ ULONG Request, - _In_ USHORT Position - ) -{ - SCROLLINFO scrollInfo; - LONG oldPosition; - - scrollInfo.cbSize = sizeof(SCROLLINFO); - scrollInfo.fMask = SIF_ALL; - GetScrollInfo(Context->VScrollHandle, SB_CTL, &scrollInfo); - oldPosition = scrollInfo.nPos; - - switch (Request) - { - case SB_LINEUP: - scrollInfo.nPos--; - break; - case SB_LINEDOWN: - scrollInfo.nPos++; - break; - case SB_PAGEUP: - scrollInfo.nPos -= scrollInfo.nPage; - break; - case SB_PAGEDOWN: - scrollInfo.nPos += scrollInfo.nPage; - break; - case SB_THUMBPOSITION: - // Touch scrolling seems to give us Position but not nTrackPos. The problem is that Position - // is a 16-bit value, so don't use it if we have too many rows. - if (Context->FlatList->Count <= 0xffff) - scrollInfo.nPos = Position; - break; - case SB_THUMBTRACK: - scrollInfo.nPos = scrollInfo.nTrackPos; - break; - case SB_TOP: - scrollInfo.nPos = 0; - break; - case SB_BOTTOM: - scrollInfo.nPos = MAXINT; - break; - } - - scrollInfo.fMask = SIF_POS; - SetScrollInfo(Context->VScrollHandle, SB_CTL, &scrollInfo, TRUE); - GetScrollInfo(Context->VScrollHandle, SB_CTL, &scrollInfo); - - if (scrollInfo.nPos != oldPosition) - { - Context->VScrollPosition = scrollInfo.nPos; - PhTnpProcessScroll(Context, scrollInfo.nPos - oldPosition, 0); - } -} - -VOID PhTnpOnHScroll( - _In_ HWND hwnd, - _In_ PPH_TREENEW_CONTEXT Context, - _In_ ULONG Request, - _In_ USHORT Position - ) -{ - SCROLLINFO scrollInfo; - LONG oldPosition; - - scrollInfo.cbSize = sizeof(SCROLLINFO); - scrollInfo.fMask = SIF_ALL; - GetScrollInfo(Context->HScrollHandle, SB_CTL, &scrollInfo); - oldPosition = scrollInfo.nPos; - - switch (Request) - { - case SB_LINELEFT: - scrollInfo.nPos -= Context->TextMetrics.tmAveCharWidth; - break; - case SB_LINERIGHT: - scrollInfo.nPos += Context->TextMetrics.tmAveCharWidth; - break; - case SB_PAGELEFT: - scrollInfo.nPos -= scrollInfo.nPage; - break; - case SB_PAGERIGHT: - scrollInfo.nPos += scrollInfo.nPage; - break; - case SB_THUMBPOSITION: - // Touch scrolling seems to give us Position but not nTrackPos. The problem is that Position - // is a 16-bit value, so don't use it if we have too many rows. - if (Context->FlatList->Count <= 0xffff) - scrollInfo.nPos = Position; - break; - case SB_THUMBTRACK: - scrollInfo.nPos = scrollInfo.nTrackPos; - break; - case SB_LEFT: - scrollInfo.nPos = 0; - break; - case SB_RIGHT: - scrollInfo.nPos = MAXINT; - break; - } - - scrollInfo.fMask = SIF_POS; - SetScrollInfo(Context->HScrollHandle, SB_CTL, &scrollInfo, TRUE); - GetScrollInfo(Context->HScrollHandle, SB_CTL, &scrollInfo); - - if (scrollInfo.nPos != oldPosition) - { - Context->HScrollPosition = scrollInfo.nPos; - PhTnpProcessScroll(Context, 0, scrollInfo.nPos - oldPosition); - } -} - -BOOLEAN PhTnpOnNotify( - _In_ HWND hwnd, - _In_ PPH_TREENEW_CONTEXT Context, - _In_ NMHDR *Header, - _Out_ LRESULT *Result - ) -{ - switch (Header->code) - { - case HDN_ITEMCHANGING: - case HDN_ITEMCHANGED: - { - NMHEADER *nmHeader = (NMHEADER *)Header; - - if (Header->code == HDN_ITEMCHANGING && Header->hwndFrom == Context->FixedHeaderHandle) - { - if (nmHeader->pitem->mask & HDI_WIDTH) - { - if (Context->FixedColumnVisible) - { - Context->FixedWidth = nmHeader->pitem->cxy - 1; - - if (Context->FixedWidth < Context->FixedWidthMinimum) - Context->FixedWidth = Context->FixedWidthMinimum; - - Context->NormalLeft = Context->FixedWidth + 1; - nmHeader->pitem->cxy = Context->FixedWidth + 1; - } - else - { - Context->FixedWidth = 0; - Context->NormalLeft = 0; - } - } - } - - if (Header->hwndFrom == Context->FixedHeaderHandle || Header->hwndFrom == Context->HeaderHandle) - { - if (nmHeader->pitem->mask & HDI_WIDTH) - { - // A column has been resized. Update our stored information. - PhTnpUpdateColumnHeaders(Context); - PhTnpUpdateColumnMaps(Context); - - if (Header->code == HDN_ITEMCHANGING) - { - HDITEM item; - - item.mask = HDI_WIDTH | HDI_LPARAM; - - if (Header_GetItem(Header->hwndFrom, nmHeader->iItem, &item)) - { - Context->ResizingColumn = (PPH_TREENEW_COLUMN)item.lParam; - Context->OldColumnWidth = item.cxy; - } - else - { - Context->ResizingColumn = NULL; - Context->OldColumnWidth = -1; - } - } - else if (Header->code == HDN_ITEMCHANGED) - { - if (Context->ResizingColumn) - { - LONG delta; - - delta = nmHeader->pitem->cxy - Context->OldColumnWidth; - - if (delta != 0) - { - PhTnpProcessResizeColumn(Context, Context->ResizingColumn, delta); - Context->Callback(Context->Handle, TreeNewColumnResized, Context->ResizingColumn, NULL, Context->CallbackContext); - } - - Context->ResizingColumn = NULL; - - // Redraw the entire window if we are displaying empty text. - if (Context->FlatList->Count == 0 && Context->EmptyText.Length != 0) - InvalidateRect(Context->Handle, NULL, FALSE); - } - else - { - // An error occurred during HDN_ITEMCHANGED, so redraw the entire window. - InvalidateRect(Context->Handle, NULL, FALSE); - } - } - } - } - } - break; - case HDN_ITEMCLICK: - { - if ((Header->hwndFrom == Context->FixedHeaderHandle || Header->hwndFrom == Context->HeaderHandle) && - !(Context->Style & TN_STYLE_NO_COLUMN_SORT)) - { - NMHEADER *nmHeader = (NMHEADER *)Header; - HDITEM item; - PPH_TREENEW_COLUMN column; - - // A column has been clicked, so update the sort state. - - item.mask = HDI_LPARAM; - - if (Header_GetItem(Header->hwndFrom, nmHeader->iItem, &item)) - { - column = (PPH_TREENEW_COLUMN)item.lParam; - PhTnpProcessSortColumn(Context, column); - } - } - } - break; - case HDN_ENDDRAG: - case NM_RELEASEDCAPTURE: - { - if (Header->hwndFrom == Context->HeaderHandle) - { - // Columns have been re-ordered, so refresh our information. - // Note: The fixed column cannot be re-ordered. - PhTnpUpdateColumnHeaders(Context); - PhTnpUpdateColumnMaps(Context); - Context->Callback(Context->Handle, TreeNewColumnReordered, NULL, NULL, Context->CallbackContext); - InvalidateRect(Context->Handle, NULL, FALSE); - } - } - break; - case HDN_DIVIDERDBLCLICK: - { - if (Header->hwndFrom == Context->FixedHeaderHandle || Header->hwndFrom == Context->HeaderHandle) - { - NMHEADER *nmHeader = (NMHEADER *)Header; - HDITEM item; - - if (Context->SuspendUpdateStructure) - break; - - item.mask = HDI_LPARAM; - - if (Header_GetItem(Header->hwndFrom, nmHeader->iItem, &item)) - { - PhTnpAutoSizeColumnHeader( - Context, - Header->hwndFrom, - (PPH_TREENEW_COLUMN)item.lParam, - 0 - ); - } - } - } - break; - case NM_RCLICK: - { - if (Header->hwndFrom == Context->FixedHeaderHandle || Header->hwndFrom == Context->HeaderHandle) - { - PH_TREENEW_HEADER_MOUSE_EVENT mouseEvent; - ULONG position; - - position = GetMessagePos(); - mouseEvent.ScreenLocation.x = GET_X_LPARAM(position); - mouseEvent.ScreenLocation.y = GET_Y_LPARAM(position); - - mouseEvent.Location = mouseEvent.ScreenLocation; - ScreenToClient(hwnd, &mouseEvent.Location); - mouseEvent.HeaderLocation = mouseEvent.ScreenLocation; - ScreenToClient(Header->hwndFrom, &mouseEvent.HeaderLocation); - mouseEvent.Column = PhTnpHitTestHeader(Context, Header->hwndFrom == Context->FixedHeaderHandle, &mouseEvent.HeaderLocation, NULL); - Context->Callback(hwnd, TreeNewHeaderRightClick, &mouseEvent, NULL, Context->CallbackContext); - } - } - break; - case TTN_GETDISPINFO: - { - if (Header->hwndFrom == Context->TooltipsHandle) - { - NMTTDISPINFO *info = (NMTTDISPINFO *)Header; - POINT point; - - PhTnpGetMessagePos(hwnd, &point); - PhTnpGetTooltipText(Context, &point, &info->lpszText); - } - } - break; - case TTN_SHOW: - { - if (Header->hwndFrom == Context->TooltipsHandle) - { - *Result = PhTnpPrepareTooltipShow(Context); - return TRUE; - } - } - break; - case TTN_POP: - { - if (Header->hwndFrom == Context->TooltipsHandle) - { - PhTnpPrepareTooltipPop(Context); - } - } - break; - } - - return FALSE; -} - -ULONG_PTR PhTnpOnUserMessage( - _In_ HWND hwnd, - _In_ PPH_TREENEW_CONTEXT Context, - _In_ ULONG Message, - _In_ ULONG_PTR WParam, - _In_ ULONG_PTR LParam - ) -{ - switch (Message) - { - case TNM_SETCALLBACK: - { - Context->Callback = (PPH_TREENEW_CALLBACK)LParam; - Context->CallbackContext = (PVOID)WParam; - - if (!Context->Callback) - Context->Callback = PhTnpNullCallback; - } - return TRUE; - case TNM_NODESSTRUCTURED: - { - if (Context->EnableRedraw <= 0) - { - Context->SuspendUpdateStructure = TRUE; - Context->SuspendUpdateLayout = TRUE; - InvalidateRect(Context->Handle, NULL, FALSE); - return TRUE; - } - - PhTnpRestructureNodes(Context); - PhTnpLayout(Context); - InvalidateRect(Context->Handle, NULL, FALSE); - } - return TRUE; - case TNM_ADDCOLUMN: - return PhTnpAddColumn(Context, (PPH_TREENEW_COLUMN)LParam); - case TNM_REMOVECOLUMN: - return PhTnpRemoveColumn(Context, (ULONG)WParam); - case TNM_GETCOLUMN: - return PhTnpCopyColumn(Context, (ULONG)WParam, (PPH_TREENEW_COLUMN)LParam); - case TNM_SETCOLUMN: - { - PPH_TREENEW_COLUMN column = (PPH_TREENEW_COLUMN)LParam; - - return PhTnpChangeColumn(Context, (ULONG)WParam, column->Id, column); - } - break; - case TNM_GETCOLUMNORDERARRAY: - { - ULONG count = (ULONG)WParam; - PULONG order = (PULONG)LParam; - ULONG i; - - if (count != Context->NumberOfColumnsByDisplay) - return FALSE; - - for (i = 0; i < count; i++) - { - order[i] = Context->ColumnsByDisplay[i]->Id; - } - } - return TRUE; - case TNM_SETCOLUMNORDERARRAY: - { - ULONG count = (ULONG)WParam; - PULONG order = (PULONG)LParam; - ULONG i; - PULONG newOrder; - PPH_TREENEW_COLUMN column; - - newOrder = PhAllocate(count * sizeof(ULONG)); - - for (i = 0; i < count; i++) - { - if (!(column = PhTnpLookupColumnById(Context, order[i]))) - { - PhFree(newOrder); - return FALSE; - } - - newOrder[i] = column->s.ViewIndex; - } - - if (!Header_SetOrderArray(Context->HeaderHandle, count, newOrder)) - { - PhFree(newOrder); - return FALSE; - } - - PhFree(newOrder); - - PhTnpUpdateColumnHeaders(Context); - PhTnpUpdateColumnMaps(Context); - } - return TRUE; - case TNM_SETCURSOR: - { - Context->Cursor = (HCURSOR)LParam; - } - return TRUE; - case TNM_GETSORT: - { - PULONG sortColumn = (PULONG)WParam; - PPH_SORT_ORDER sortOrder = (PPH_SORT_ORDER)LParam; - - if (sortColumn) - *sortColumn = Context->SortColumn; - if (sortOrder) - *sortOrder = Context->SortOrder; - } - return TRUE; - case TNM_SETSORT: - { - ULONG sortColumn = (ULONG)WParam; - PH_SORT_ORDER sortOrder = (PH_SORT_ORDER)LParam; - PPH_TREENEW_COLUMN column; - - if (sortOrder != NoSortOrder) - { - if (!(column = PhTnpLookupColumnById(Context, sortColumn))) - return FALSE; - } - else - { - sortColumn = 0; - column = NULL; - } - - Context->SortColumn = sortColumn; - Context->SortOrder = sortOrder; - - PhTnpSetColumnHeaderSortIcon(Context, column); - - Context->Callback(Context->Handle, TreeNewSortChanged, NULL, NULL, Context->CallbackContext); - } - return TRUE; - case TNM_SETTRISTATE: - Context->TriState = !!WParam; - return TRUE; - case TNM_ENSUREVISIBLE: - return PhTnpEnsureVisibleNode(Context, ((PPH_TREENEW_NODE)LParam)->Index); - case TNM_SCROLL: - PhTnpScroll(Context, (LONG)WParam, (LONG)LParam); - return TRUE; - case TNM_GETFLATNODECOUNT: - if (!Context->SuspendUpdateStructure) - return (LRESULT)Context->FlatList->Count; - else - return 0; - case TNM_GETFLATNODE: - { - ULONG index = (ULONG)WParam; - - if (index >= Context->FlatList->Count) - return (LRESULT)NULL; - - return (LRESULT)Context->FlatList->Items[index]; - } - break; - case TNM_GETCELLTEXT: - { - PPH_TREENEW_GET_CELL_TEXT getCellText = (PPH_TREENEW_GET_CELL_TEXT)LParam; - - return PhTnpGetCellText( - Context, - getCellText->Node, - getCellText->Id, - &getCellText->Text - ); - } - break; - case TNM_SETNODEEXPANDED: - PhTnpSetExpandedNode(Context, (PPH_TREENEW_NODE)LParam, !!WParam); - return TRUE; - case TNM_GETMAXID: - return (LRESULT)(Context->NextId - 1); - case TNM_SETMAXID: - { - ULONG maxId = (ULONG)WParam; - - if (Context->NextId < maxId + 1) - { - Context->NextId = maxId + 1; - - if (Context->AllocatedColumns < Context->NextId) - { - PhTnpExpandAllocatedColumns(Context); - } - } - } - return TRUE; - case TNM_INVALIDATENODE: - { - PPH_TREENEW_NODE node = (PPH_TREENEW_NODE)LParam; - RECT rect; - - if (!node->Visible) - return FALSE; - - if (!PhTnpGetRowRects(Context, node->Index, node->Index, TRUE, &rect)) - return FALSE; - - InvalidateRect(hwnd, &rect, FALSE); - } - return TRUE; - case TNM_INVALIDATENODES: - { - RECT rect; - - if (!PhTnpGetRowRects(Context, (ULONG)WParam, (ULONG)LParam, TRUE, &rect)) - return FALSE; - - InvalidateRect(hwnd, &rect, FALSE); - } - return TRUE; - case TNM_GETFIXEDHEADER: - return (LRESULT)Context->FixedHeaderHandle; - case TNM_GETHEADER: - return (LRESULT)Context->HeaderHandle; - case TNM_GETTOOLTIPS: - return (LRESULT)Context->TooltipsHandle; - case TNM_SELECTRANGE: - case TNM_DESELECTRANGE: - { - ULONG flags; - ULONG changedStart; - ULONG changedEnd; - RECT rect; - - flags = 0; - - if (Message == TNM_DESELECTRANGE) - flags |= TN_SELECT_DESELECT; - - PhTnpSelectRange(Context, (ULONG)WParam, (ULONG)LParam, flags, &changedStart, &changedEnd); - - if (PhTnpGetRowRects(Context, changedStart, changedEnd, TRUE, &rect)) - { - InvalidateRect(hwnd, &rect, FALSE); - } - } - return TRUE; - case TNM_GETCOLUMNCOUNT: - return (LRESULT)Context->NumberOfColumns; - case TNM_SETREDRAW: - PhTnpSetRedraw(Context, !!WParam); - return (LRESULT)Context->EnableRedraw; - case TNM_GETVIEWPARTS: - { - PPH_TREENEW_VIEW_PARTS parts = (PPH_TREENEW_VIEW_PARTS)LParam; - - parts->ClientRect = Context->ClientRect; - parts->HeaderHeight = Context->HeaderHeight; - parts->RowHeight = Context->RowHeight; - parts->VScrollWidth = Context->VScrollVisible ? Context->VScrollWidth : 0; - parts->HScrollHeight = Context->HScrollHeight ? Context->HScrollHeight : 0; - parts->VScrollPosition = Context->VScrollPosition; - parts->HScrollPosition = Context->HScrollPosition; - parts->FixedWidth = Context->FixedWidth; - parts->NormalLeft = Context->NormalLeft; - parts->NormalWidth = Context->TotalViewX; - } - return TRUE; - case TNM_GETFIXEDCOLUMN: - return (LRESULT)Context->FixedColumn; - case TNM_GETFIRSTCOLUMN: - return (LRESULT)Context->FirstColumn; - case TNM_SETFOCUSNODE: - Context->FocusNode = (PPH_TREENEW_NODE)LParam; - return TRUE; - case TNM_SETMARKNODE: - Context->MarkNodeIndex = ((PPH_TREENEW_NODE)LParam)->Index; - return TRUE; - case TNM_SETHOTNODE: - PhTnpSetHotNode(Context, (PPH_TREENEW_NODE)LParam, FALSE); - return TRUE; - case TNM_SETEXTENDEDFLAGS: - Context->ExtendedFlags = (Context->ExtendedFlags & ~(ULONG)WParam) | ((ULONG)LParam & (ULONG)WParam); - return TRUE; - case TNM_GETCALLBACK: - { - PPH_TREENEW_CALLBACK *callback = (PPH_TREENEW_CALLBACK *)LParam; - PVOID *callbackContext = (PVOID *)WParam; - - if (callback) - { - if (Context->Callback != PhTnpNullCallback) - *callback = Context->Callback; - else - *callback = NULL; - } - - if (callbackContext) - { - *callbackContext = Context->CallbackContext; - } - } - return TRUE; - case TNM_HITTEST: - PhTnpHitTest(Context, (PPH_TREENEW_HIT_TEST)LParam); - return TRUE; - case TNM_GETVISIBLECOLUMNCOUNT: - return Context->NumberOfColumnsByDisplay + (Context->FixedColumnVisible ? 1 : 0); - case TNM_AUTOSIZECOLUMN: - { - ULONG id = (ULONG)WParam; - ULONG flags = (ULONG)LParam; - PPH_TREENEW_COLUMN column; - - if (!(column = PhTnpLookupColumnById(Context, id))) - return FALSE; - - if (!column->Visible) - return FALSE; - - PhTnpAutoSizeColumnHeader( - Context, - column->Fixed ? Context->FixedHeaderHandle : Context->HeaderHandle, - column, - flags - ); - } - return TRUE; - case TNM_SETEMPTYTEXT: - { - PPH_STRINGREF text = (PPH_STRINGREF)LParam; - ULONG flags = (ULONG)WParam; - - Context->EmptyText = *text; - } - return TRUE; - case TNM_SETROWHEIGHT: - { - LONG rowHeight = (LONG)WParam; - - if (rowHeight != 0) - { - Context->CustomRowHeight = TRUE; - Context->RowHeight = rowHeight; - } - else - { - Context->CustomRowHeight = FALSE; - PhTnpUpdateTextMetrics(Context); - } - } - return TRUE; - case TNM_ISFLATNODEVALID: - return !Context->SuspendUpdateStructure; - } - - return 0; -} - -VOID PhTnpSetFont( - _In_ PPH_TREENEW_CONTEXT Context, - _In_opt_ HFONT Font, - _In_ BOOLEAN Redraw - ) -{ - if (Context->FontOwned) - { - DeleteObject(Context->Font); - Context->FontOwned = FALSE; - } - - Context->Font = Font; - - if (!Context->Font) - { - LOGFONT logFont; - - if (SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(LOGFONT), &logFont, 0)) - { - Context->Font = CreateFontIndirect(&logFont); - Context->FontOwned = TRUE; - } - } - - SendMessage(Context->FixedHeaderHandle, WM_SETFONT, (WPARAM)Context->Font, Redraw); - SendMessage(Context->HeaderHandle, WM_SETFONT, (WPARAM)Context->Font, Redraw); - - if (Context->TooltipsHandle) - { - SendMessage(Context->TooltipsHandle, WM_SETFONT, (WPARAM)Context->Font, FALSE); - Context->TooltipFont = Context->Font; - } - - PhTnpUpdateTextMetrics(Context); -} - -VOID PhTnpUpdateSystemMetrics( - _In_ PPH_TREENEW_CONTEXT Context - ) -{ - Context->VScrollWidth = GetSystemMetrics(SM_CXVSCROLL); - Context->HScrollHeight = GetSystemMetrics(SM_CYHSCROLL); - Context->SystemBorderX = GetSystemMetrics(SM_CXBORDER); - Context->SystemBorderY = GetSystemMetrics(SM_CYBORDER); - Context->SystemEdgeX = GetSystemMetrics(SM_CXEDGE); - Context->SystemEdgeY = GetSystemMetrics(SM_CYEDGE); - Context->SystemDragX = GetSystemMetrics(SM_CXDRAG); - Context->SystemDragY = GetSystemMetrics(SM_CYDRAG); - - if (Context->SystemDragX < 2) - Context->SystemDragX = 2; - if (Context->SystemDragY < 2) - Context->SystemDragY = 2; -} - -VOID PhTnpUpdateTextMetrics( - _In_ PPH_TREENEW_CONTEXT Context - ) -{ - HDC hdc; - - if (hdc = GetDC(Context->Handle)) - { - SelectObject(hdc, Context->Font); - GetTextMetrics(hdc, &Context->TextMetrics); - - if (!Context->CustomRowHeight) - { - // Below we try to match the row height as calculated by the list view, even if it - // involves magic numbers. On Vista and above there seems to be extra padding. - - Context->RowHeight = Context->TextMetrics.tmHeight; - - if (Context->Style & TN_STYLE_ICONS) - { - if (Context->RowHeight < SmallIconHeight) - Context->RowHeight = SmallIconHeight; - } - else - { - if (WindowsVersion >= WINDOWS_VISTA && !(Context->Style & TN_STYLE_THIN_ROWS)) - Context->RowHeight += 1; // HACK - } - - Context->RowHeight += 1; // HACK - - if (WindowsVersion >= WINDOWS_VISTA && !(Context->Style & TN_STYLE_THIN_ROWS)) - Context->RowHeight += 2; // HACK - } - - ReleaseDC(Context->Handle, hdc); - } -} - -VOID PhTnpUpdateThemeData( - _In_ PPH_TREENEW_CONTEXT Context - ) -{ - Context->ThemeActive = !!IsThemeActive(); - - if (Context->ThemeData) - { - CloseThemeData(Context->ThemeData); - Context->ThemeData = NULL; - } - - Context->ThemeData = OpenThemeData(Context->Handle, L"TREEVIEW"); - - if (Context->ThemeData) - { - Context->ThemeHasItemBackground = !!IsThemePartDefined(Context->ThemeData, TVP_TREEITEM, 0); - Context->ThemeHasGlyph = !!IsThemePartDefined(Context->ThemeData, TVP_GLYPH, 0); - Context->ThemeHasHotGlyph = !!IsThemePartDefined(Context->ThemeData, TVP_HOTGLYPH, 0); - } - else - { - Context->ThemeHasItemBackground = FALSE; - Context->ThemeHasGlyph = FALSE; - Context->ThemeHasHotGlyph = FALSE; - } -} - -VOID PhTnpInitializeThemeData( - _In_ PPH_TREENEW_CONTEXT Context - ) -{ - if (!Context->ThemeInitialized) - { - PhTnpUpdateThemeData(Context); - Context->ThemeInitialized = TRUE; - } -} - -VOID PhTnpCancelTrack( - _In_ PPH_TREENEW_CONTEXT Context - ) -{ - PhTnpSetFixedWidth(Context, Context->TrackOldFixedWidth); - ReleaseCapture(); -} - -VOID PhTnpLayout( - _In_ PPH_TREENEW_CONTEXT Context - ) -{ - RECT clientRect; - - if (Context->EnableRedraw <= 0) - { - Context->SuspendUpdateLayout = TRUE; - return; - } - - clientRect = Context->ClientRect; - - PhTnpUpdateScrollBars(Context); - - // Vertical scroll bar - if (Context->VScrollVisible) - { - MoveWindow( - Context->VScrollHandle, - clientRect.right - Context->VScrollWidth, - 0, - Context->VScrollWidth, - clientRect.bottom - (Context->HScrollVisible ? Context->HScrollHeight : 0), - TRUE - ); - } - - // Horizontal scroll bar - if (Context->HScrollVisible) - { - MoveWindow( - Context->HScrollHandle, - Context->NormalLeft, - clientRect.bottom - Context->HScrollHeight, - clientRect.right - Context->NormalLeft - (Context->VScrollVisible ? Context->VScrollWidth : 0), - Context->HScrollHeight, - TRUE - ); - } - - // Filler box - if (Context->VScrollVisible && Context->HScrollVisible) - { - MoveWindow( - Context->FillerBoxHandle, - clientRect.right - Context->VScrollWidth, - clientRect.bottom - Context->HScrollHeight, - Context->VScrollWidth, - Context->HScrollHeight, - TRUE - ); - } - - PhTnpLayoutHeader(Context); - - // Redraw the entire window if we are displaying empty text. - if (Context->FlatList->Count == 0 && Context->EmptyText.Length != 0) - InvalidateRect(Context->Handle, NULL, FALSE); -} - -VOID PhTnpLayoutHeader( - _In_ PPH_TREENEW_CONTEXT Context - ) -{ - RECT rect; - HDLAYOUT hdl; - WINDOWPOS windowPos; - - hdl.prc = ▭ - hdl.pwpos = &windowPos; - - if (!(Context->Style & TN_STYLE_NO_COLUMN_HEADER)) - { - // Fixed portion header control - rect.left = 0; - rect.top = 0; - rect.right = Context->NormalLeft; - rect.bottom = Context->ClientRect.bottom; - Header_Layout(Context->FixedHeaderHandle, &hdl); - SetWindowPos(Context->FixedHeaderHandle, NULL, windowPos.x, windowPos.y, windowPos.cx, windowPos.cy, windowPos.flags); - Context->HeaderHeight = windowPos.cy; - - // Normal portion header control - rect.left = Context->NormalLeft - Context->HScrollPosition; - rect.top = 0; - rect.right = Context->ClientRect.right - (Context->VScrollVisible ? Context->VScrollWidth : 0); - rect.bottom = Context->ClientRect.bottom; - Header_Layout(Context->HeaderHandle, &hdl); - SetWindowPos(Context->HeaderHandle, NULL, windowPos.x, windowPos.y, windowPos.cx, windowPos.cy, windowPos.flags); - } - else - { - Context->HeaderHeight = 0; - } - - if (Context->TooltipsHandle) - { - TOOLINFO toolInfo; - - memset(&toolInfo, 0, sizeof(TOOLINFO)); - toolInfo.cbSize = sizeof(TOOLINFO); - toolInfo.hwnd = Context->FixedHeaderHandle; - toolInfo.uId = TNP_TOOLTIPS_FIXED_HEADER; - GetClientRect(Context->FixedHeaderHandle, &toolInfo.rect); - SendMessage(Context->TooltipsHandle, TTM_NEWTOOLRECT, 0, (LPARAM)&toolInfo); - - toolInfo.hwnd = Context->HeaderHandle; - toolInfo.uId = TNP_TOOLTIPS_HEADER; - GetClientRect(Context->HeaderHandle, &toolInfo.rect); - SendMessage(Context->TooltipsHandle, TTM_NEWTOOLRECT, 0, (LPARAM)&toolInfo); - } -} - -VOID PhTnpSetFixedWidth( - _In_ PPH_TREENEW_CONTEXT Context, - _In_ ULONG FixedWidth - ) -{ - HDITEM item; - - if (Context->FixedColumnVisible) - { - Context->FixedWidth = FixedWidth; - - if (Context->FixedWidth < Context->FixedWidthMinimum) - Context->FixedWidth = Context->FixedWidthMinimum; - - Context->NormalLeft = Context->FixedWidth + 1; - - item.mask = HDI_WIDTH; - item.cxy = Context->FixedWidth + 1; - Header_SetItem(Context->FixedHeaderHandle, 0, &item); - } - else - { - Context->FixedWidth = 0; - Context->NormalLeft = 0; - } -} - -VOID PhTnpSetRedraw( - _In_ PPH_TREENEW_CONTEXT Context, - _In_ BOOLEAN Redraw - ) -{ - if (Redraw) - Context->EnableRedraw++; - else - Context->EnableRedraw--; - - if (Context->EnableRedraw == 1) - { - if (Context->SuspendUpdateStructure) - { - PhTnpRestructureNodes(Context); - } - - if (Context->SuspendUpdateLayout) - { - PhTnpLayout(Context); - } - - if (Context->SuspendUpdateMoveMouse) - { - POINT point; - - PhTnpGetMessagePos(Context->Handle, &point); - PhTnpProcessMoveMouse(Context, point.x, point.y); - } - - Context->SuspendUpdateStructure = FALSE; - Context->SuspendUpdateLayout = FALSE; - Context->SuspendUpdateMoveMouse = FALSE; - - if (Context->SuspendUpdateRegion) - { - InvalidateRgn(Context->Handle, Context->SuspendUpdateRegion, FALSE); - DeleteObject(Context->SuspendUpdateRegion); - Context->SuspendUpdateRegion = NULL; - } - } -} - -VOID PhTnpSendMouseEvent( - _In_ PPH_TREENEW_CONTEXT Context, - _In_ PH_TREENEW_MESSAGE Message, - _In_ LONG CursorX, - _In_ LONG CursorY, - _In_ PPH_TREENEW_NODE Node, - _In_ PPH_TREENEW_COLUMN Column, - _In_ ULONG VirtualKeys - ) -{ - PH_TREENEW_MOUSE_EVENT mouseEvent; - - mouseEvent.Location.x = CursorX; - mouseEvent.Location.y = CursorY; - mouseEvent.Node = Node; - mouseEvent.Column = Column; - mouseEvent.KeyFlags = VirtualKeys; - Context->Callback(Context->Handle, Message, &mouseEvent, NULL, Context->CallbackContext); -} - -PPH_TREENEW_COLUMN PhTnpLookupColumnById( - _In_ PPH_TREENEW_CONTEXT Context, - _In_ ULONG Id - ) -{ - if (Id >= Context->AllocatedColumns) - return NULL; - - return Context->Columns[Id]; -} - -BOOLEAN PhTnpAddColumn( - _In_ PPH_TREENEW_CONTEXT Context, - _In_ PPH_TREENEW_COLUMN Column - ) -{ - PPH_TREENEW_COLUMN realColumn; - - // Check if a column with the same ID already exists. - if (Column->Id < Context->AllocatedColumns && Context->Columns[Column->Id]) - return FALSE; - - if (Context->NextId < Column->Id + 1) - Context->NextId = Column->Id + 1; - - realColumn = PhAllocateCopy(Column, sizeof(PH_TREENEW_COLUMN)); - - if (realColumn->DpiScaleOnAdd) - { - realColumn->Width = PhMultiplyDivide(realColumn->Width, PhGlobalDpi, 96); - realColumn->DpiScaleOnAdd = FALSE; - } - - if (Context->AllocatedColumns < Context->NextId) - { - PhTnpExpandAllocatedColumns(Context); - } - - Context->Columns[Column->Id] = realColumn; - Context->NumberOfColumns++; - - if (realColumn->Fixed) - { - if (Context->FixedColumn) - { - // We already have a fixed column, and we can't have two. Make this new column un-fixed. - realColumn->Fixed = FALSE; - } - else - { - Context->FixedColumn = realColumn; - } - - realColumn->DisplayIndex = 0; - realColumn->s.ViewX = 0; - } - - if (realColumn->Visible) - { - BOOLEAN updateHeaders; - - updateHeaders = FALSE; - - if (!realColumn->Fixed && realColumn->DisplayIndex != Header_GetItemCount(Context->HeaderHandle)) - updateHeaders = TRUE; - - realColumn->s.ViewIndex = PhTnpInsertColumnHeader(Context, realColumn); - - if (updateHeaders) - PhTnpUpdateColumnHeaders(Context); - } - else - { - realColumn->s.ViewIndex = -1; - } - - PhTnpUpdateColumnMaps(Context); - - if (realColumn->Visible) - PhTnpLayout(Context); - - return TRUE; -} - -BOOLEAN PhTnpRemoveColumn( - _In_ PPH_TREENEW_CONTEXT Context, - _In_ ULONG Id - ) -{ - PPH_TREENEW_COLUMN realColumn; - BOOLEAN updateLayout; - - if (!(realColumn = PhTnpLookupColumnById(Context, Id))) - return FALSE; - - updateLayout = FALSE; - - if (realColumn->Visible) - updateLayout = TRUE; - - PhTnpDeleteColumnHeader(Context, realColumn); - Context->Columns[realColumn->Id] = NULL; - PhFree(realColumn); - PhTnpUpdateColumnMaps(Context); - - if (updateLayout) - PhTnpLayout(Context); - - Context->NumberOfColumns--; - - return TRUE; -} - -BOOLEAN PhTnpCopyColumn( - _In_ PPH_TREENEW_CONTEXT Context, - _In_ ULONG Id, - _Out_ PPH_TREENEW_COLUMN Column - ) -{ - PPH_TREENEW_COLUMN realColumn; - - if (!(realColumn = PhTnpLookupColumnById(Context, Id))) - return FALSE; - - memcpy(Column, realColumn, sizeof(PH_TREENEW_COLUMN)); - - return TRUE; -} - -BOOLEAN PhTnpChangeColumn( - _In_ PPH_TREENEW_CONTEXT Context, - _In_ ULONG Mask, - _In_ ULONG Id, - _In_ PPH_TREENEW_COLUMN Column - ) -{ - PPH_TREENEW_COLUMN realColumn; - BOOLEAN addingOrRemoving; - - if (!(realColumn = PhTnpLookupColumnById(Context, Id))) - return FALSE; - - addingOrRemoving = FALSE; - - if (Mask & TN_COLUMN_FLAG_VISIBLE) - { - if (realColumn->Visible != Column->Visible) - { - addingOrRemoving = TRUE; - } - } - - if (Mask & TN_COLUMN_FLAG_CUSTOMDRAW) - { - realColumn->CustomDraw = Column->CustomDraw; - } - - if (Mask & TN_COLUMN_FLAG_SORTDESCENDING) - { - realColumn->SortDescending = Column->SortDescending; - } - - if (Mask & (TN_COLUMN_TEXT | TN_COLUMN_WIDTH | TN_COLUMN_ALIGNMENT | TN_COLUMN_DISPLAYINDEX)) - { - BOOLEAN updateHeaders; - BOOLEAN updateMaps; - BOOLEAN updateLayout; - - updateHeaders = FALSE; - updateMaps = FALSE; - updateLayout = FALSE; - - if (Mask & TN_COLUMN_TEXT) - { - realColumn->Text = Column->Text; - } - - if (Mask & TN_COLUMN_WIDTH) - { - realColumn->Width = Column->Width; - updateMaps = TRUE; - } - - if (Mask & TN_COLUMN_ALIGNMENT) - { - realColumn->Alignment = Column->Alignment; - } - - if (Mask & TN_COLUMN_DISPLAYINDEX) - { - realColumn->DisplayIndex = Column->DisplayIndex; - updateHeaders = TRUE; - updateMaps = TRUE; - updateLayout = TRUE; - } - - if (!addingOrRemoving && realColumn->Visible) - { - PhTnpChangeColumnHeader(Context, Mask, realColumn); - - if (updateHeaders) - PhTnpUpdateColumnHeaders(Context); - if (updateMaps) - PhTnpUpdateColumnMaps(Context); - if (updateLayout) - PhTnpLayout(Context); - } - } - - if (Mask & TN_COLUMN_CONTEXT) - { - realColumn->Context = Column->Context; - } - - if (Mask & TN_COLUMN_TEXTFLAGS) - { - realColumn->TextFlags = Column->TextFlags; - } - - if (addingOrRemoving) - { - if (Column->Visible) - { - BOOLEAN updateHeaders; - - updateHeaders = FALSE; - - if (realColumn->Fixed) - { - realColumn->DisplayIndex = 0; - } - else - { - if (Mask & TN_COLUMN_DISPLAYINDEX) - updateHeaders = TRUE; - else - realColumn->DisplayIndex = Header_GetItemCount(Context->HeaderHandle); - } - - realColumn->s.ViewIndex = PhTnpInsertColumnHeader(Context, realColumn); - - if (updateHeaders) - PhTnpUpdateColumnHeaders(Context); - } - else - { - PhTnpDeleteColumnHeader(Context, realColumn); - } - - PhTnpUpdateColumnMaps(Context); - PhTnpLayout(Context); - } - - return TRUE; -} - -VOID PhTnpExpandAllocatedColumns( - _In_ PPH_TREENEW_CONTEXT Context - ) -{ - if (Context->Columns) - { - ULONG oldAllocatedColumns; - - oldAllocatedColumns = Context->AllocatedColumns; - Context->AllocatedColumns *= 2; - - if (Context->AllocatedColumns < Context->NextId) - Context->AllocatedColumns = Context->NextId; - - Context->Columns = PhReAllocate( - Context->Columns, - Context->AllocatedColumns * sizeof(PPH_TREENEW_COLUMN) - ); - - // Zero the newly allocated portion. - memset( - &Context->Columns[oldAllocatedColumns], - 0, - (Context->AllocatedColumns - oldAllocatedColumns) * sizeof(PPH_TREENEW_COLUMN) - ); - } - else - { - Context->AllocatedColumns = 16; - - if (Context->AllocatedColumns < Context->NextId) - Context->AllocatedColumns = Context->NextId; - - Context->Columns = PhAllocate( - Context->AllocatedColumns * sizeof(PPH_TREENEW_COLUMN) - ); - memset(Context->Columns, 0, Context->AllocatedColumns * sizeof(PPH_TREENEW_COLUMN)); - } -} - -VOID PhTnpUpdateColumnMaps( - _In_ PPH_TREENEW_CONTEXT Context - ) -{ - ULONG i; - LONG x; - - if (Context->AllocatedColumnsByDisplay < Context->NumberOfColumns) - { - if (Context->ColumnsByDisplay) - PhFree(Context->ColumnsByDisplay); - - Context->ColumnsByDisplay = PhAllocate(sizeof(PPH_TREENEW_COLUMN) * Context->NumberOfColumns); - Context->AllocatedColumnsByDisplay = Context->NumberOfColumns; - } - - memset(Context->ColumnsByDisplay, 0, sizeof(PPH_TREENEW_COLUMN) * Context->AllocatedColumnsByDisplay); - - for (i = 0; i < Context->NextId; i++) - { - if (!Context->Columns[i]) - continue; - - if (Context->Columns[i]->Visible && !Context->Columns[i]->Fixed && Context->Columns[i]->DisplayIndex != -1) - { - if (Context->Columns[i]->DisplayIndex >= Context->NumberOfColumns) - PhRaiseStatus(STATUS_INTERNAL_ERROR); - - Context->ColumnsByDisplay[Context->Columns[i]->DisplayIndex] = Context->Columns[i]; - } - } - - x = 0; - - for (i = 0; i < Context->AllocatedColumnsByDisplay; i++) - { - if (!Context->ColumnsByDisplay[i]) - break; - - Context->ColumnsByDisplay[i]->s.ViewX = x; - x += Context->ColumnsByDisplay[i]->Width; - } - - Context->NumberOfColumnsByDisplay = i; - Context->TotalViewX = x; - - if (Context->FixedColumnVisible) - Context->FirstColumn = Context->FixedColumn; - else if (Context->NumberOfColumnsByDisplay != 0) - Context->FirstColumn = Context->ColumnsByDisplay[0]; - else - Context->FirstColumn = NULL; - - if (Context->NumberOfColumnsByDisplay != 0) - Context->LastColumn = Context->ColumnsByDisplay[Context->NumberOfColumnsByDisplay - 1]; - else if (Context->FixedColumnVisible) - Context->LastColumn = Context->FixedColumn; - else - Context->LastColumn = NULL; -} - -LONG PhTnpInsertColumnHeader( - _In_ PPH_TREENEW_CONTEXT Context, - _In_ PPH_TREENEW_COLUMN Column - ) -{ - HDITEM item; - - if (Column->Fixed) - { - if (Column->Width < Context->FixedWidthMinimum) - Column->Width = Context->FixedWidthMinimum; - - Context->FixedWidth = Column->Width; - Context->NormalLeft = Context->FixedWidth + 1; - Context->FixedColumnVisible = TRUE; - - if (!(Context->Style & TN_STYLE_NO_DIVIDER)) - Context->FixedDividerVisible = TRUE; - } - - memset(&item, 0, sizeof(HDITEM)); - item.mask = HDI_WIDTH | HDI_TEXT | HDI_FORMAT | HDI_LPARAM | HDI_ORDER; - item.cxy = Column->Width; - item.pszText = Column->Text; - item.fmt = 0; - item.lParam = (LPARAM)Column; - - if (Column->Fixed) - item.cxy++; - - if (Column->Fixed) - item.iOrder = 0; - else - item.iOrder = Column->DisplayIndex; - - if (Column->Alignment & PH_ALIGN_LEFT) - item.fmt |= HDF_LEFT; - else if (Column->Alignment & PH_ALIGN_RIGHT) - item.fmt |= HDF_RIGHT; - else - item.fmt |= HDF_CENTER; - - if (Column->Id == Context->SortColumn) - { - if (Context->SortOrder == AscendingSortOrder) - item.fmt |= HDF_SORTUP; - else if (Context->SortOrder == DescendingSortOrder) - item.fmt |= HDF_SORTDOWN; - } - - Column->Visible = TRUE; - - if (Column->Fixed) - return Header_InsertItem(Context->FixedHeaderHandle, 0, &item); - else - return Header_InsertItem(Context->HeaderHandle, MAXINT, &item); -} - -VOID PhTnpChangeColumnHeader( - _In_ PPH_TREENEW_CONTEXT Context, - _In_ ULONG Mask, - _In_ PPH_TREENEW_COLUMN Column - ) -{ - HDITEM item; - - memset(&item, 0, sizeof(HDITEM)); - item.mask = 0; - - if (Mask & TN_COLUMN_TEXT) - { - item.mask |= HDI_TEXT; - item.pszText = Column->Text; - } - - if (Mask & TN_COLUMN_WIDTH) - { - item.mask |= HDI_WIDTH; - item.cxy = Column->Width; - - if (Column->Fixed) - item.cxy++; - } - - if (Mask & TN_COLUMN_ALIGNMENT) - { - item.mask |= HDI_FORMAT; - item.fmt = 0; - - if (Column->Alignment & PH_ALIGN_LEFT) - item.fmt |= HDF_LEFT; - else if (Column->Alignment & PH_ALIGN_RIGHT) - item.fmt |= HDF_RIGHT; - else - item.fmt |= HDF_CENTER; - - if (Column->Id == Context->SortColumn) - { - if (Context->SortOrder == AscendingSortOrder) - item.fmt |= HDF_SORTUP; - else if (Context->SortOrder == DescendingSortOrder) - item.fmt |= HDF_SORTDOWN; - } - } - - if (Mask & TN_COLUMN_DISPLAYINDEX) - { - item.mask |= HDI_ORDER; - - if (Column->Fixed) - item.iOrder = 0; - else - item.iOrder = Column->DisplayIndex; - } - - if (Column->Fixed) - Header_SetItem(Context->FixedHeaderHandle, 0, &item); - else - Header_SetItem(Context->HeaderHandle, Column->s.ViewIndex, &item); -} - -VOID PhTnpDeleteColumnHeader( - _In_ PPH_TREENEW_CONTEXT Context, - _Inout_ PPH_TREENEW_COLUMN Column - ) -{ - if (Column->Fixed) - { - Context->FixedColumn = NULL; - Context->FixedWidth = 0; - Context->NormalLeft = 0; - Context->FixedColumnVisible = FALSE; - Context->FixedDividerVisible = FALSE; - } - - if (Column->Fixed) - Header_DeleteItem(Context->FixedHeaderHandle, Column->s.ViewIndex); - else - Header_DeleteItem(Context->HeaderHandle, Column->s.ViewIndex); - - Column->Visible = FALSE; - Column->s.ViewIndex = -1; - PhTnpUpdateColumnHeaders(Context); -} - -VOID PhTnpUpdateColumnHeaders( - _In_ PPH_TREENEW_CONTEXT Context - ) -{ - ULONG count; - ULONG i; - HDITEM item; - PPH_TREENEW_COLUMN column; - - item.mask = HDI_WIDTH | HDI_LPARAM | HDI_ORDER; - - // Fixed column - - if (Context->FixedColumnVisible && Header_GetItem(Context->FixedHeaderHandle, 0, &item)) - { - column = Context->FixedColumn; - column->Width = item.cxy - 1; - } - - // Normal columns - - count = Header_GetItemCount(Context->HeaderHandle); - - if (count != -1) - { - for (i = 0; i < count; i++) - { - if (Header_GetItem(Context->HeaderHandle, i, &item)) - { - column = (PPH_TREENEW_COLUMN)item.lParam; - column->s.ViewIndex = i; - column->Width = item.cxy; - column->DisplayIndex = item.iOrder; - } - } - } -} - -VOID PhTnpProcessResizeColumn( - _In_ PPH_TREENEW_CONTEXT Context, - _In_ PPH_TREENEW_COLUMN Column, - _In_ LONG Delta - ) -{ - RECT rect; - LONG columnLeft; - - if (Column->Fixed) - { - columnLeft = 0; - } - else - { - columnLeft = Context->NormalLeft + Column->s.ViewX - Context->HScrollPosition; - } - - // Scroll the content to the right of the column. - // - // Clip the scroll area to the new width, or the old width if that is further to the left. We - // may have the WS_CLIPCHILDREN style set, so we need to remove the horizontal scrollbar from - // the rectangle, otherwise ScrollWindowEx will want to invalidate the entire region! (The - // horizontal scrollbar is an overlapping child control.) - rect.left = columnLeft + Column->Width; - rect.top = Context->HeaderHeight; - rect.right = Context->ClientRect.right - (Context->VScrollVisible ? Context->VScrollWidth : 0); - rect.bottom = Context->ClientRect.bottom - (Context->HScrollVisible ? Context->HScrollHeight : 0); - - if (Delta > 0) - rect.left -= Delta; // old width - - // Scroll the window. - ScrollWindowEx( - Context->Handle, - Delta, - 0, - &rect, - &rect, - NULL, - NULL, - SW_INVALIDATE - ); - - UpdateWindow(Context->Handle); // required - - if (Context->HScrollVisible) - { - // We excluded the bottom region - invalidate it now. - rect.top = rect.bottom; - rect.bottom = Context->ClientRect.bottom; - InvalidateRect(Context->Handle, &rect, FALSE); - } - - PhTnpLayout(Context); - - // Redraw the whole column because the content may depend on the width (e.g. text ellipsis). - rect.left = columnLeft; - rect.top = Context->HeaderHeight; - rect.right = columnLeft + Column->Width; - RedrawWindow(Context->Handle, &rect, NULL, RDW_INVALIDATE | RDW_UPDATENOW); // must be RedrawWindow -} - -VOID PhTnpProcessSortColumn( - _In_ PPH_TREENEW_CONTEXT Context, - _In_ PPH_TREENEW_COLUMN NewColumn - ) -{ - if (NewColumn->Id == Context->SortColumn) - { - if (Context->TriState) - { - if (!NewColumn->SortDescending) - { - // Ascending -> Descending -> None - - if (Context->SortOrder == AscendingSortOrder) - Context->SortOrder = DescendingSortOrder; - else if (Context->SortOrder == DescendingSortOrder) - Context->SortOrder = NoSortOrder; - else - Context->SortOrder = AscendingSortOrder; - } - else - { - // Descending -> Ascending -> None - - if (Context->SortOrder == DescendingSortOrder) - Context->SortOrder = AscendingSortOrder; - else if (Context->SortOrder == AscendingSortOrder) - Context->SortOrder = NoSortOrder; - else - Context->SortOrder = DescendingSortOrder; - } - } - else - { - if (Context->SortOrder == AscendingSortOrder) - Context->SortOrder = DescendingSortOrder; - else - Context->SortOrder = AscendingSortOrder; - } - } - else - { - Context->SortColumn = NewColumn->Id; - - if (!NewColumn->SortDescending) - Context->SortOrder = AscendingSortOrder; - else - Context->SortOrder = DescendingSortOrder; - } - - PhTnpSetColumnHeaderSortIcon(Context, NewColumn); - - Context->Callback(Context->Handle, TreeNewSortChanged, NULL, NULL, Context->CallbackContext); -} - -BOOLEAN PhTnpSetColumnHeaderSortIcon( - _In_ PPH_TREENEW_CONTEXT Context, - _In_opt_ PPH_TREENEW_COLUMN SortColumnPointer - ) -{ - if (Context->SortOrder == NoSortOrder) - { - PhSetHeaderSortIcon( - Context->FixedHeaderHandle, - -1, - NoSortOrder - ); - PhSetHeaderSortIcon( - Context->HeaderHandle, - -1, - NoSortOrder - ); - - return TRUE; - } - - if (!SortColumnPointer) - { - if (!(SortColumnPointer = PhTnpLookupColumnById(Context, Context->SortColumn))) - return FALSE; - } - - if (SortColumnPointer->Fixed) - { - PhSetHeaderSortIcon( - Context->FixedHeaderHandle, - 0, - Context->SortOrder - ); - PhSetHeaderSortIcon( - Context->HeaderHandle, - -1, - NoSortOrder - ); - } - else - { - PhSetHeaderSortIcon( - Context->FixedHeaderHandle, - -1, - NoSortOrder - ); - PhSetHeaderSortIcon( - Context->HeaderHandle, - SortColumnPointer->s.ViewIndex, - Context->SortOrder - ); - } - - return TRUE; -} - -VOID PhTnpAutoSizeColumnHeader( - _In_ PPH_TREENEW_CONTEXT Context, - _In_ HWND HeaderHandle, - _In_ PPH_TREENEW_COLUMN Column, - _In_ ULONG Flags - ) -{ - LONG newWidth; - HDITEM item; - - if (Flags & TN_AUTOSIZE_REMAINING_SPACE) - { - newWidth = Context->ClientRect.right - (Context->TotalViewX - Column->Width); - - if (Context->FixedColumn) - newWidth -= Context->FixedColumn->Width; - if (Context->VScrollVisible) - newWidth -= Context->VScrollWidth; - - if (newWidth <= 0) - return; - } - else - { - ULONG i; - LONG maximumWidth; - PH_TREENEW_CELL_PARTS parts; - LONG width; - - if (Context->FlatList->Count == 0) - return; - if (Column->CustomDraw) - return; - - maximumWidth = 0; - - for (i = 0; i < Context->FlatList->Count; i++) - { - if (PhTnpGetCellParts(Context, i, Column, TN_MEASURE_TEXT, &parts) && - (parts.Flags & TN_PART_CELL) && (parts.Flags & TN_PART_CONTENT) && (parts.Flags & TN_PART_TEXT)) - { - width = parts.TextRect.right - parts.TextRect.left; // text width - width += parts.ContentRect.left - parts.CellRect.left; // left padding - - if (maximumWidth < width) - maximumWidth = width; - } - } - - newWidth = maximumWidth + TNP_CELL_RIGHT_MARGIN; // right padding - - if (Column->Fixed) - newWidth++; - } - - item.mask = HDI_WIDTH; - item.cxy = newWidth; - - Header_SetItem(HeaderHandle, Column->s.ViewIndex, &item); -} - -BOOLEAN PhTnpGetNodeChildren( - _In_ PPH_TREENEW_CONTEXT Context, - _In_opt_ PPH_TREENEW_NODE Node, - _Out_ PPH_TREENEW_NODE **Children, - _Out_ PULONG NumberOfChildren - ) -{ - PH_TREENEW_GET_CHILDREN getChildren; - - getChildren.Flags = 0; - getChildren.Node = Node; - getChildren.Children = NULL; - getChildren.NumberOfChildren = 0; - - if (Context->Callback( - Context->Handle, - TreeNewGetChildren, - &getChildren, - NULL, - Context->CallbackContext - )) - { - *Children = getChildren.Children; - *NumberOfChildren = getChildren.NumberOfChildren; - - return TRUE; - } - - return FALSE; -} - -BOOLEAN PhTnpIsNodeLeaf( - _In_ PPH_TREENEW_CONTEXT Context, - _In_ PPH_TREENEW_NODE Node - ) -{ - PH_TREENEW_IS_LEAF isLeaf; - - isLeaf.Flags = 0; - isLeaf.Node = Node; - isLeaf.IsLeaf = TRUE; - - if (Context->Callback( - Context->Handle, - TreeNewIsLeaf, - &isLeaf, - NULL, - Context->CallbackContext - )) - { - return isLeaf.IsLeaf; - } - - // Doesn't matter, decide when we do the get-children callback. - return FALSE; -} - -BOOLEAN PhTnpGetCellText( - _In_ PPH_TREENEW_CONTEXT Context, - _In_ PPH_TREENEW_NODE Node, - _In_ ULONG Id, - _Out_ PPH_STRINGREF Text - ) -{ - PH_TREENEW_GET_CELL_TEXT getCellText; - - if (Id < Node->TextCacheSize && Node->TextCache[Id].Buffer) - { - *Text = Node->TextCache[Id]; - return TRUE; - } - - getCellText.Flags = 0; - getCellText.Node = Node; - getCellText.Id = Id; - PhInitializeEmptyStringRef(&getCellText.Text); - - if (Context->Callback( - Context->Handle, - TreeNewGetCellText, - &getCellText, - NULL, - Context->CallbackContext - ) && getCellText.Text.Buffer) - { - *Text = getCellText.Text; - - if ((getCellText.Flags & TN_CACHE) && Id < Node->TextCacheSize) - Node->TextCache[Id] = getCellText.Text; - - return TRUE; - } - - return FALSE; -} - -VOID PhTnpRestructureNodes( - _In_ PPH_TREENEW_CONTEXT Context - ) -{ - PPH_TREENEW_NODE *children; - ULONG numberOfChildren; - ULONG i; - - if (!PhTnpGetNodeChildren(Context, NULL, &children, &numberOfChildren)) - return; - - // We try to preserve the hot node, the focused node and the selection mark node. At this point - // all node pointers must be regarded as invalid, so we must not follow any pointers. - - Context->FocusNodeFound = FALSE; - - PhClearList(Context->FlatList); - Context->CanAnyExpand = FALSE; - - for (i = 0; i < numberOfChildren; i++) - { - PhTnpInsertNodeChildren(Context, children[i], 0); - } - - if (!Context->FocusNodeFound) - Context->FocusNode = NULL; // focused node is no longer present - - if (Context->HotNodeIndex >= Context->FlatList->Count) // covers -1 case as well - Context->HotNodeIndex = -1; - - if (Context->MarkNodeIndex >= Context->FlatList->Count) - Context->MarkNodeIndex = -1; -} - -VOID PhTnpInsertNodeChildren( - _In_ PPH_TREENEW_CONTEXT Context, - _In_ PPH_TREENEW_NODE Node, - _In_ ULONG Level - ) -{ - PPH_TREENEW_NODE *children; - ULONG numberOfChildren; - ULONG i; - ULONG nextLevel; - - if (Node->Visible) - { - Node->Level = Level; - - Node->Index = Context->FlatList->Count; - PhAddItemList(Context->FlatList, Node); - - if (Context->FocusNode == Node) - Context->FocusNodeFound = TRUE; - - nextLevel = Level + 1; - } - else - { - nextLevel = 0; // children of this node should be level 0 - } - - if (!(Node->s.IsLeaf = PhTnpIsNodeLeaf(Context, Node))) - { - Context->CanAnyExpand = TRUE; - - if (Node->Expanded) - { - if (PhTnpGetNodeChildren(Context, Node, &children, &numberOfChildren)) - { - for (i = 0; i < numberOfChildren; i++) - { - PhTnpInsertNodeChildren(Context, children[i], nextLevel); - } - - if (numberOfChildren == 0) - Node->s.IsLeaf = TRUE; - } - } - } -} - -VOID PhTnpSetExpandedNode( - _In_ PPH_TREENEW_CONTEXT Context, - _In_ PPH_TREENEW_NODE Node, - _In_ BOOLEAN Expanded - ) -{ - if (Node->Expanded != Expanded) - { - PH_TREENEW_NODE_EVENT nodeEvent; - - memset(&nodeEvent, 0, sizeof(PH_TREENEW_NODE_EVENT)); - Context->Callback(Context->Handle, TreeNewNodeExpanding, Node, &nodeEvent, Context->CallbackContext); - - if (!nodeEvent.Handled) - { - if (!Expanded) - { - ULONG i; - PPH_TREENEW_NODE node; - BOOLEAN changed; - - // Make sure no children are selected - we don't want invisible selected nodes. Note - // that this does not cause any UI changes by itself, since we are hiding the nodes. - - changed = FALSE; - - for (i = Node->Index + 1; i < Context->FlatList->Count; i++) - { - node = Context->FlatList->Items[i]; - - if (node->Level <= Node->Level) - break; // no more children - - if (node->Selected) - { - node->Selected = FALSE; - changed = TRUE; - } - } - - if (changed) - { - Context->Callback(Context->Handle, TreeNewSelectionChanged, NULL, NULL, Context->CallbackContext); - } - } - - Node->Expanded = Expanded; - PhTnpRestructureNodes(Context); - // We need to update the window before the scrollbars get updated in order for the - // scroll processing to work properly. - InvalidateRect(Context->Handle, NULL, FALSE); - UpdateWindow(Context->Handle); - PhTnpLayout(Context); - } - } -} - -BOOLEAN PhTnpGetCellParts( - _In_ PPH_TREENEW_CONTEXT Context, - _In_ ULONG Index, - _In_opt_ PPH_TREENEW_COLUMN Column, - _In_ ULONG Flags, - _Out_ PPH_TREENEW_CELL_PARTS Parts - ) -{ - PPH_TREENEW_NODE node; - LONG viewWidth; - LONG nodeY; - LONG iconVerticalMargin; - LONG currentX; - - if (Index >= Context->FlatList->Count) - return FALSE; - - node = Context->FlatList->Items[Index]; - nodeY = Context->HeaderHeight + ((LONG)Index - Context->VScrollPosition) * Context->RowHeight; - - Parts->Flags = 0; - Parts->RowRect.left = 0; - Parts->RowRect.right = Context->NormalLeft + Context->TotalViewX - Context->HScrollPosition; - Parts->RowRect.top = nodeY; - Parts->RowRect.bottom = nodeY + Context->RowHeight; - - viewWidth = Context->ClientRect.right - (Context->VScrollVisible ? Context->VScrollWidth : 0); - - if (Parts->RowRect.right > viewWidth) - Parts->RowRect.right = viewWidth; - - if (!Column) - return TRUE; - if (!Column->Visible) - return FALSE; - - iconVerticalMargin = (Context->RowHeight - SmallIconHeight) / 2; - - if (Column->Fixed) - { - currentX = 0; - } - else - { - currentX = Context->NormalLeft + Column->s.ViewX - Context->HScrollPosition; - } - - Parts->Flags |= TN_PART_CELL; - Parts->CellRect.left = currentX; - Parts->CellRect.right = currentX + Column->Width; - Parts->CellRect.top = Parts->RowRect.top; - Parts->CellRect.bottom = Parts->RowRect.bottom; - - currentX += TNP_CELL_LEFT_MARGIN; - - if (Column == Context->FirstColumn) - { - currentX += (LONG)node->Level * SmallIconWidth; - - if (Context->CanAnyExpand) - { - if (!node->s.IsLeaf) - { - Parts->Flags |= TN_PART_PLUSMINUS; - Parts->PlusMinusRect.left = currentX; - Parts->PlusMinusRect.right = currentX + SmallIconWidth; - Parts->PlusMinusRect.top = Parts->RowRect.top + iconVerticalMargin; - Parts->PlusMinusRect.bottom = Parts->RowRect.bottom - iconVerticalMargin; - } - - currentX += SmallIconWidth; - } - - if (node->Icon) - { - Parts->Flags |= TN_PART_ICON; - Parts->IconRect.left = currentX; - Parts->IconRect.right = currentX + SmallIconWidth; - Parts->IconRect.top = Parts->RowRect.top + iconVerticalMargin; - Parts->IconRect.bottom = Parts->RowRect.bottom - iconVerticalMargin; - - currentX += SmallIconWidth + TNP_ICON_RIGHT_PADDING; - } - } - - Parts->Flags |= TN_PART_CONTENT; - Parts->ContentRect.left = currentX; - Parts->ContentRect.right = Parts->CellRect.right - TNP_CELL_RIGHT_MARGIN; - Parts->ContentRect.top = Parts->RowRect.top; - Parts->ContentRect.bottom = Parts->RowRect.bottom; - - if (Flags & TN_MEASURE_TEXT) - { - HDC hdc; - PH_STRINGREF text; - HFONT font; - SIZE textSize; - - if (hdc = GetDC(Context->Handle)) - { - PhTnpPrepareRowForDraw(Context, hdc, node); - - if (PhTnpGetCellText(Context, node, Column->Id, &text)) - { - if (node->Font) - font = node->Font; - else - font = Context->Font; - - SelectObject(hdc, font); - - if (GetTextExtentPoint32(hdc, text.Buffer, (ULONG)text.Length / sizeof(WCHAR), &textSize)) - { - Parts->Flags |= TN_PART_TEXT; - Parts->TextRect.left = currentX; - Parts->TextRect.right = currentX + textSize.cx; - Parts->TextRect.top = Parts->RowRect.top + (Context->RowHeight - textSize.cy) / 2; - Parts->TextRect.bottom = Parts->RowRect.bottom - (Context->RowHeight - textSize.cy) / 2; - - if (Column->TextFlags & DT_CENTER) - { - Parts->TextRect.left = Parts->ContentRect.left / 2 + (Parts->ContentRect.right - textSize.cx) / 2; - Parts->TextRect.right = Parts->ContentRect.left + textSize.cx; - } - else if (Column->TextFlags & DT_RIGHT) - { - Parts->TextRect.right = Parts->ContentRect.right; - Parts->TextRect.left = Parts->TextRect.right - textSize.cx; - } - - Parts->Text = text; - Parts->Font = font; - } - } - - ReleaseDC(Context->Handle, hdc); - } - } - - return TRUE; -} - -BOOLEAN PhTnpGetRowRects( - _In_ PPH_TREENEW_CONTEXT Context, - _In_ ULONG Start, - _In_ ULONG End, - _In_ BOOLEAN Clip, - _Out_ PRECT Rect - ) -{ - LONG startY; - LONG endY; - LONG viewWidth; - - if (End >= Context->FlatList->Count) - return FALSE; - if (Start > End) - return FALSE; - - startY = Context->HeaderHeight + ((LONG)Start - Context->VScrollPosition) * Context->RowHeight; - endY = Context->HeaderHeight + ((LONG)End - Context->VScrollPosition) * Context->RowHeight; - - Rect->left = 0; - Rect->right = Context->NormalLeft + Context->TotalViewX - Context->HScrollPosition; - Rect->top = startY; - Rect->bottom = endY + Context->RowHeight; - - viewWidth = Context->ClientRect.right - (Context->VScrollVisible ? Context->VScrollWidth : 0); - - if (Rect->right > viewWidth) - Rect->right = viewWidth; - - if (Clip) - { - if (Rect->top < Context->HeaderHeight) - Rect->top = Context->HeaderHeight; - if (Rect->bottom > Context->ClientRect.bottom) - Rect->bottom = Context->ClientRect.bottom; - } - - return TRUE; -} - -VOID PhTnpHitTest( - _In_ PPH_TREENEW_CONTEXT Context, - _Inout_ PPH_TREENEW_HIT_TEST HitTest - ) -{ - RECT clientRect; - LONG x; - LONG y; - ULONG index; - PPH_TREENEW_NODE node; - - HitTest->Flags = 0; - HitTest->Node = NULL; - HitTest->Column = NULL; - - clientRect = Context->ClientRect; - x = HitTest->Point.x; - y = HitTest->Point.y; - - if (x < 0) - HitTest->Flags |= TN_HIT_LEFT; - if (x >= clientRect.right) - HitTest->Flags |= TN_HIT_RIGHT; - if (y < 0) - HitTest->Flags |= TN_HIT_ABOVE; - if (y >= clientRect.bottom) - HitTest->Flags |= TN_HIT_BELOW; - - if (HitTest->Flags == 0) - { - if (TNP_HIT_TEST_FIXED_DIVIDER(x, Context)) - { - HitTest->Flags |= TN_HIT_DIVIDER; - } - - if (y >= Context->HeaderHeight && x < Context->FixedWidth + Context->TotalViewX) - { - index = (y - Context->HeaderHeight) / Context->RowHeight + Context->VScrollPosition; - - if (index < Context->FlatList->Count) - { - HitTest->Flags |= TN_HIT_ITEM; - node = Context->FlatList->Items[index]; - HitTest->Node = node; - - if (HitTest->InFlags & TN_TEST_COLUMN) - { - PPH_TREENEW_COLUMN column; - LONG columnX; - - column = NULL; - - if (x < Context->FixedWidth && Context->FixedColumnVisible) - { - column = Context->FixedColumn; - columnX = 0; - } - else - { - LONG currentX; - ULONG i; - PPH_TREENEW_COLUMN currentColumn; - - currentX = Context->NormalLeft - Context->HScrollPosition; - - for (i = 0; i < Context->NumberOfColumnsByDisplay; i++) - { - currentColumn = Context->ColumnsByDisplay[i]; - - if (x >= currentX && x < currentX + currentColumn->Width) - { - column = currentColumn; - columnX = currentX; - break; - } - - currentX += currentColumn->Width; - } - } - - HitTest->Column = column; - - if (column && (HitTest->InFlags & TN_TEST_SUBITEM)) - { - BOOLEAN isFirstColumn; - LONG currentX; - - isFirstColumn = HitTest->Column == Context->FirstColumn; - - currentX = columnX; - currentX += TNP_CELL_LEFT_MARGIN; - - if (isFirstColumn) - { - currentX += (LONG)node->Level * SmallIconWidth; - - if (!node->s.IsLeaf) - { - if (x >= currentX && x < currentX + SmallIconWidth) - HitTest->Flags |= TN_HIT_ITEM_PLUSMINUS; - - currentX += SmallIconWidth; - } - - if (node->Icon) - { - if (x >= currentX && x < currentX + SmallIconWidth) - HitTest->Flags |= TN_HIT_ITEM_ICON; - - currentX += SmallIconWidth + TNP_ICON_RIGHT_PADDING; - } - } - - if (x >= currentX) - { - HitTest->Flags |= TN_HIT_ITEM_CONTENT; - } - } - } - } - } - } -} - -VOID PhTnpSelectRange( - _In_ PPH_TREENEW_CONTEXT Context, - _In_ ULONG Start, - _In_ ULONG End, - _In_ ULONG Flags, - _Out_opt_ PULONG ChangedStart, - _Out_opt_ PULONG ChangedEnd - ) -{ - ULONG maximum; - ULONG i; - PPH_TREENEW_NODE node; - BOOLEAN targetValue; - ULONG changedStart; - ULONG changedEnd; - - if (Context->FlatList->Count == 0) - return; - - maximum = Context->FlatList->Count - 1; - - if (End > maximum) - { - End = maximum; - } - - if (Start > End) - { - // Start is too big, so the selection range becomes empty. - // Set it to max + 1 so that Reset still works. - Start = maximum + 1; - End = 0; - } - - targetValue = !(Flags & TN_SELECT_DESELECT); - changedStart = maximum; - changedEnd = 0; - - if (Flags & TN_SELECT_RESET) - { - for (i = 0; i < Start; i++) - { - node = Context->FlatList->Items[i]; - - if (node->Selected) - { - node->Selected = FALSE; - - if (changedStart > i) - changedStart = i; - if (changedEnd < i) - changedEnd = i; - } - } - } - - for (i = Start; i <= End; i++) - { - node = Context->FlatList->Items[i]; - - if (!node->Unselectable && ((Flags & TN_SELECT_TOGGLE) || node->Selected != targetValue)) - { - node->Selected = !node->Selected; - - if (changedStart > i) - changedStart = i; - if (changedEnd < i) - changedEnd = i; - } - } - - if (Flags & TN_SELECT_RESET) - { - for (i = End + 1; i <= maximum; i++) - { - node = Context->FlatList->Items[i]; - - if (node->Selected) - { - node->Selected = FALSE; - - if (changedStart > i) - changedStart = i; - if (changedEnd < i) - changedEnd = i; - } - } - } - - if (changedStart <= changedEnd) - { - Context->Callback(Context->Handle, TreeNewSelectionChanged, NULL, NULL, Context->CallbackContext); - } - - if (ChangedStart) - *ChangedStart = changedStart; - if (ChangedEnd) - *ChangedEnd = changedEnd; -} - -VOID PhTnpSetHotNode( - _In_ PPH_TREENEW_CONTEXT Context, - _In_opt_ PPH_TREENEW_NODE NewHotNode, - _In_ BOOLEAN NewPlusMinusHot - ) -{ - ULONG newHotNodeIndex; - RECT rowRect; - BOOLEAN needsInvalidate; - - if (NewHotNode) - newHotNodeIndex = NewHotNode->Index; - else - newHotNodeIndex = -1; - - needsInvalidate = FALSE; - - if (Context->HotNodeIndex != newHotNodeIndex) - { - if (Context->HotNodeIndex != -1) - { - if (Context->ThemeData && PhTnpGetRowRects(Context, Context->HotNodeIndex, Context->HotNodeIndex, TRUE, &rowRect)) - { - // Update the old hot node because it may have a different non-hot background and - // plus minus part. - InvalidateRect(Context->Handle, &rowRect, FALSE); - } - } - - Context->HotNodeIndex = newHotNodeIndex; - - if (NewHotNode) - { - needsInvalidate = TRUE; - } - } - - if (NewHotNode) - { - if (NewHotNode->s.PlusMinusHot != NewPlusMinusHot) - { - NewHotNode->s.PlusMinusHot = NewPlusMinusHot; - needsInvalidate = TRUE; - } - - if (needsInvalidate && Context->ThemeData && PhTnpGetRowRects(Context, newHotNodeIndex, newHotNodeIndex, TRUE, &rowRect)) - { - InvalidateRect(Context->Handle, &rowRect, FALSE); - } - } -} - -VOID PhTnpProcessSelectNode( - _In_ PPH_TREENEW_CONTEXT Context, - _In_ PPH_TREENEW_NODE Node, - _In_ LOGICAL ControlKey, - _In_ LOGICAL ShiftKey, - _In_ LOGICAL RightButton - ) -{ - ULONG changedStart; - ULONG changedEnd; - RECT rect; - - if (RightButton) - { - // Right button: - // If the current node is selected, then do nothing. This is to allow context menus to - // operate on multiple items. - // If the current node is not selected, select only that node. - - if (!ControlKey && !ShiftKey && !Node->Selected) - { - PhTnpSelectRange(Context, Node->Index, Node->Index, TN_SELECT_RESET, &changedStart, &changedEnd); - Context->MarkNodeIndex = Node->Index; - - if (PhTnpGetRowRects(Context, changedStart, changedEnd, TRUE, &rect)) - { - InvalidateRect(Context->Handle, &rect, FALSE); - } - } - } - else if (ShiftKey && Context->MarkNodeIndex != -1) - { - ULONG start; - ULONG end; - - // Shift key: select a range from the selection mark node to the current node. - - if (Node->Index > Context->MarkNodeIndex) - { - start = Context->MarkNodeIndex; - end = Node->Index; - } - else - { - start = Node->Index; - end = Context->MarkNodeIndex; - } - - PhTnpSelectRange(Context, start, end, TN_SELECT_RESET, &changedStart, &changedEnd); - - if (PhTnpGetRowRects(Context, changedStart, changedEnd, TRUE, &rect)) - { - InvalidateRect(Context->Handle, &rect, FALSE); - } - } - else if (ControlKey) - { - // Control key: toggle the selection on the current node, and also make it the selection - // mark. - - PhTnpSelectRange(Context, Node->Index, Node->Index, TN_SELECT_TOGGLE, NULL, NULL); - Context->MarkNodeIndex = Node->Index; - - if (PhTnpGetRowRects(Context, Node->Index, Node->Index, TRUE, &rect)) - { - InvalidateRect(Context->Handle, &rect, FALSE); - } - } - else - { - // Normal: select the current node, and also make it the selection mark. - - PhTnpSelectRange(Context, Node->Index, Node->Index, TN_SELECT_RESET, &changedStart, &changedEnd); - Context->MarkNodeIndex = Node->Index; - - if (PhTnpGetRowRects(Context, changedStart, changedEnd, TRUE, &rect)) - { - InvalidateRect(Context->Handle, &rect, FALSE); - } - } -} - -BOOLEAN PhTnpEnsureVisibleNode( - _In_ PPH_TREENEW_CONTEXT Context, - _In_ ULONG Index - ) -{ - LONG viewTop; - LONG viewBottom; - LONG rowTop; - LONG rowBottom; - LONG deltaY; - LONG deltaRows; - - if (Index >= Context->FlatList->Count) - return FALSE; - - viewTop = Context->HeaderHeight; - viewBottom = Context->ClientRect.bottom - (Context->HScrollVisible ? Context->HScrollHeight : 0); - rowTop = Context->HeaderHeight + ((LONG)Index - Context->VScrollPosition) * Context->RowHeight; - rowBottom = rowTop + Context->RowHeight; - - // Check if the row is fully visible. - if (rowTop >= viewTop && rowBottom <= viewBottom) - return TRUE; - - deltaY = rowTop - viewTop; - - if (deltaY > 0) - { - // The row is below the view area. We want to scroll the row into view at the bottom of the - // screen. We need to round up when dividing to make sure the node becomes fully visible. - deltaY = rowBottom - viewBottom; - deltaRows = (deltaY + Context->RowHeight - 1) / Context->RowHeight; // divide, round up - } - else - { - deltaRows = deltaY / Context->RowHeight; - } - - PhTnpScroll(Context, deltaRows, 0); - - return TRUE; -} - -VOID PhTnpProcessMoveMouse( - _In_ PPH_TREENEW_CONTEXT Context, - _In_ LONG CursorX, - _In_ LONG CursorY - ) -{ - PH_TREENEW_HIT_TEST hitTest; - PPH_TREENEW_NODE hotNode; - - hitTest.Point.x = CursorX; - hitTest.Point.y = CursorY; - hitTest.InFlags = TN_TEST_COLUMN | TN_TEST_SUBITEM; - PhTnpHitTest(Context, &hitTest); - - if (hitTest.Flags & TN_HIT_ITEM) - hotNode = hitTest.Node; - else - hotNode = NULL; - - PhTnpSetHotNode(Context, hotNode, !!(hitTest.Flags & TN_HIT_ITEM_PLUSMINUS)); - - if (Context->AnimateDivider && Context->FixedDividerVisible) - { - if (hitTest.Flags & TN_HIT_DIVIDER) - { - if ((Context->DividerHot < 100 || Context->AnimateDividerFadingOut) && !Context->AnimateDividerFadingIn) - { - // Begin fading in the divider. - Context->AnimateDividerFadingIn = TRUE; - Context->AnimateDividerFadingOut = FALSE; - SetTimer(Context->Handle, TNP_TIMER_ANIMATE_DIVIDER, TNP_ANIMATE_DIVIDER_INTERVAL, NULL); - } - } - else - { - if ((Context->DividerHot != 0 || Context->AnimateDividerFadingIn) && !Context->AnimateDividerFadingOut) - { - Context->AnimateDividerFadingOut = TRUE; - Context->AnimateDividerFadingIn = FALSE; - SetTimer(Context->Handle, TNP_TIMER_ANIMATE_DIVIDER, TNP_ANIMATE_DIVIDER_INTERVAL, NULL); - } - } - } - - if (Context->TooltipsHandle) - { - ULONG index; - ULONG id; - - if (!(hitTest.Flags & TN_HIT_DIVIDER)) - { - index = hitTest.Node ? hitTest.Node->Index : -1; - id = hitTest.Column ? hitTest.Column->Id : -1; - } - else - { - index = -1; - id = -1; - } - - // This pops unnecessarily - when the cell has no tooltip text, and the user is moving the - // mouse over it. However these unnecessary calls seem to fix a certain tooltip bug (move - // the mouse around very quickly over the last column and the blank space to the right, and - // no more tooltips will appear). - if (Context->TooltipIndex != index || Context->TooltipId != id) - { - PhTnpPopTooltip(Context); - } - } -} - -VOID PhTnpProcessMouseVWheel( - _In_ PPH_TREENEW_CONTEXT Context, - _In_ LONG Distance - ) -{ - ULONG wheelScrollLines; - FLOAT linesToScroll; - LONG wholeLinesToScroll; - SCROLLINFO scrollInfo; - LONG oldPosition; - - if (!SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &wheelScrollLines, 0)) - wheelScrollLines = 3; - - // If page scrolling is enabled, use the number of visible rows. - if (wheelScrollLines == -1) - wheelScrollLines = (Context->ClientRect.bottom - Context->HeaderHeight - (Context->HScrollVisible ? Context->HScrollHeight : 0)) / Context->RowHeight; - - // Zero the remainder if the direction changed. - if ((Context->VScrollRemainder > 0) != (Distance > 0)) - Context->VScrollRemainder = 0; - - linesToScroll = (FLOAT)wheelScrollLines * Distance / WHEEL_DELTA + Context->VScrollRemainder; - wholeLinesToScroll = (LONG)linesToScroll; - Context->VScrollRemainder = linesToScroll - wholeLinesToScroll; - - scrollInfo.cbSize = sizeof(SCROLLINFO); - scrollInfo.fMask = SIF_ALL; - GetScrollInfo(Context->VScrollHandle, SB_CTL, &scrollInfo); - oldPosition = scrollInfo.nPos; - - scrollInfo.nPos += wholeLinesToScroll; - - scrollInfo.fMask = SIF_POS; - SetScrollInfo(Context->VScrollHandle, SB_CTL, &scrollInfo, TRUE); - GetScrollInfo(Context->VScrollHandle, SB_CTL, &scrollInfo); - - if (scrollInfo.nPos != oldPosition) - { - Context->VScrollPosition = scrollInfo.nPos; - PhTnpProcessScroll(Context, scrollInfo.nPos - oldPosition, 0); - - if (Context->TooltipsHandle) - { - MSG message; - POINT point; - - PhTnpPopTooltip(Context); - PhTnpGetMessagePos(Context->Handle, &point); - - if (point.x >= 0 && point.y >= 0 && point.x < Context->ClientRect.right && point.y < Context->ClientRect.bottom) - { - // Send a fake mouse move message for the new node that the mouse may be hovering over. - message.hwnd = Context->Handle; - message.message = WM_MOUSEMOVE; - message.wParam = 0; - message.lParam = MAKELPARAM(point.x, point.y); - SendMessage(Context->TooltipsHandle, TTM_RELAYEVENT, 0, (LPARAM)&message); - } - } - } -} - -VOID PhTnpProcessMouseHWheel( - _In_ PPH_TREENEW_CONTEXT Context, - _In_ LONG Distance - ) -{ - ULONG wheelScrollChars; - FLOAT pixelsToScroll; - LONG wholePixelsToScroll; - SCROLLINFO scrollInfo; - LONG oldPosition; - - if (!SystemParametersInfo(SPI_GETWHEELSCROLLCHARS, 0, &wheelScrollChars, 0)) - wheelScrollChars = 3; - - // Zero the remainder if the direction changed. - if ((Context->HScrollRemainder > 0) != (Distance > 0)) - Context->HScrollRemainder = 0; - - pixelsToScroll = (FLOAT)wheelScrollChars * Context->TextMetrics.tmAveCharWidth * Distance / WHEEL_DELTA + Context->HScrollRemainder; - wholePixelsToScroll = (LONG)pixelsToScroll; - Context->HScrollRemainder = pixelsToScroll - wholePixelsToScroll; - - scrollInfo.cbSize = sizeof(SCROLLINFO); - scrollInfo.fMask = SIF_ALL; - GetScrollInfo(Context->HScrollHandle, SB_CTL, &scrollInfo); - oldPosition = scrollInfo.nPos; - - scrollInfo.nPos += wholePixelsToScroll; - - scrollInfo.fMask = SIF_POS; - SetScrollInfo(Context->HScrollHandle, SB_CTL, &scrollInfo, TRUE); - GetScrollInfo(Context->HScrollHandle, SB_CTL, &scrollInfo); - - if (scrollInfo.nPos != oldPosition) - { - Context->HScrollPosition = scrollInfo.nPos; - PhTnpProcessScroll(Context, 0, scrollInfo.nPos - oldPosition); - } -} - -BOOLEAN PhTnpProcessFocusKey( - _In_ PPH_TREENEW_CONTEXT Context, - _In_ ULONG VirtualKey - ) -{ - ULONG count; - ULONG index; - BOOLEAN controlKey; - BOOLEAN shiftKey; - ULONG start; - ULONG end; - ULONG changedStart; - ULONG changedEnd; - RECT rect; - - if (VirtualKey != VK_UP && VirtualKey != VK_DOWN && - VirtualKey != VK_HOME && VirtualKey != VK_END && - VirtualKey != VK_PRIOR && VirtualKey != VK_NEXT) - { - return FALSE; - } - - count = Context->FlatList->Count; - - if (count == 0) - return TRUE; - - // Find the new node to focus. - - switch (VirtualKey) - { - case VK_UP: - { - if (Context->FocusNode && Context->FocusNode->Index > 0) - { - index = Context->FocusNode->Index - 1; - } - else - { - index = 0; - } - } - break; - case VK_DOWN: - { - if (Context->FocusNode) - { - index = Context->FocusNode->Index + 1; - - if (index >= count) - index = count - 1; - } - else - { - index = 0; - } - } - break; - case VK_HOME: - index = 0; - break; - case VK_END: - index = count - 1; - break; - case VK_PRIOR: - case VK_NEXT: - { - LONG rowsPerPage; - - if (Context->FocusNode) - index = Context->FocusNode->Index; - else - index = 0; - - rowsPerPage = Context->ClientRect.bottom - Context->HeaderHeight - (Context->HScrollVisible ? Context->HScrollHeight : 0); - - if (rowsPerPage < 0) - return TRUE; - - rowsPerPage = rowsPerPage / Context->RowHeight - 1; - - if (rowsPerPage < 0) - return TRUE; - - if (VirtualKey == VK_PRIOR) - { - ULONG startOfPageIndex; - - startOfPageIndex = Context->VScrollPosition; - - if (index > startOfPageIndex) - { - index = startOfPageIndex; - } - else - { - // Already at or before the start of the page. Go back a page. - if (index >= (ULONG)rowsPerPage) - index -= rowsPerPage; - else - index = 0; - } - } - else - { - ULONG endOfPageIndex; - - endOfPageIndex = Context->VScrollPosition + rowsPerPage; - - if (endOfPageIndex >= count) - endOfPageIndex = count - 1; - - if (index < endOfPageIndex) - { - index = endOfPageIndex; - } - else - { - // Already at or after the end of the page. Go forward a page. - index += rowsPerPage; - - if (index >= count) - index = count - 1; - } - } - } - break; - } - - // Select the relevant nodes. - - controlKey = GetKeyState(VK_CONTROL) < 0; - shiftKey = GetKeyState(VK_SHIFT) < 0; - - Context->FocusNode = Context->FlatList->Items[index]; - PhTnpSetHotNode(Context, Context->FocusNode, FALSE); - - if (shiftKey && Context->MarkNodeIndex != -1) - { - if (index > Context->MarkNodeIndex) - { - start = Context->MarkNodeIndex; - end = index; - } - else - { - start = index; - end = Context->MarkNodeIndex; - } - - PhTnpSelectRange(Context, start, end, TN_SELECT_RESET, &changedStart, &changedEnd); - - if (PhTnpGetRowRects(Context, changedStart, changedEnd, TRUE, &rect)) - { - InvalidateRect(Context->Handle, &rect, FALSE); - } - } - else if (!controlKey) - { - Context->MarkNodeIndex = Context->FocusNode->Index; - PhTnpSelectRange(Context, index, index, TN_SELECT_RESET, &changedStart, &changedEnd); - - if (PhTnpGetRowRects(Context, changedStart, changedEnd, TRUE, &rect)) - { - InvalidateRect(Context->Handle, &rect, FALSE); - } - } - - PhTnpEnsureVisibleNode(Context, index); - PhTnpPopTooltip(Context); - - return TRUE; -} - -BOOLEAN PhTnpProcessNodeKey( - _In_ PPH_TREENEW_CONTEXT Context, - _In_ ULONG VirtualKey - ) -{ - BOOLEAN controlKey; - BOOLEAN shiftKey; - ULONG changedStart; - ULONG changedEnd; - RECT rect; - - if (VirtualKey != VK_SPACE && VirtualKey != VK_LEFT && VirtualKey != VK_RIGHT && VirtualKey != VK_ADD && VirtualKey != VK_OEM_PLUS) - { - return FALSE; - } - - if (!Context->FocusNode) - return TRUE; - - controlKey = GetKeyState(VK_CONTROL) < 0; - shiftKey = GetKeyState(VK_SHIFT) < 0; - - switch (VirtualKey) - { - case VK_SPACE: - { - if (controlKey) - { - // Control key: toggle the selection on the focused node. - - Context->MarkNodeIndex = Context->FocusNode->Index; - PhTnpSelectRange(Context, Context->FocusNode->Index, Context->FocusNode->Index, TN_SELECT_TOGGLE, &changedStart, &changedEnd); - - if (PhTnpGetRowRects(Context, changedStart, changedEnd, TRUE, &rect)) - { - InvalidateRect(Context->Handle, &rect, FALSE); - } - } - else if (shiftKey) - { - ULONG start; - ULONG end; - - // Shift key: select a range from the selection mark node to the focused node. - - if (Context->FocusNode->Index > Context->MarkNodeIndex) - { - start = Context->MarkNodeIndex; - end = Context->FocusNode->Index; - } - else - { - start = Context->FocusNode->Index; - end = Context->MarkNodeIndex; - } - - PhTnpSelectRange(Context, start, end, TN_SELECT_RESET, &changedStart, &changedEnd); - - if (PhTnpGetRowRects(Context, changedStart, changedEnd, TRUE, &rect)) - { - InvalidateRect(Context->Handle, &rect, FALSE); - } - } - } - break; - case VK_LEFT: - { - ULONG i; - ULONG targetLevel; - PPH_TREENEW_NODE newNode; - - // If the node is expanded, collapse it. Otherwise, select the node's parent. - if (!Context->FocusNode->s.IsLeaf && Context->FocusNode->Expanded) - { - PhTnpSetExpandedNode(Context, Context->FocusNode, FALSE); - } - else if (Context->FocusNode->Level != 0) - { - i = Context->FocusNode->Index; - targetLevel = Context->FocusNode->Level - 1; - - while (i != 0) - { - i--; - newNode = Context->FlatList->Items[i]; - - if (newNode->Level == targetLevel) - { - Context->FocusNode = newNode; - Context->MarkNodeIndex = newNode->Index; - PhTnpEnsureVisibleNode(Context, i); - PhTnpSetHotNode(Context, newNode, FALSE); - PhTnpSelectRange(Context, i, i, TN_SELECT_RESET, &changedStart, &changedEnd); - - if (PhTnpGetRowRects(Context, changedStart, changedEnd, TRUE, &rect)) - { - InvalidateRect(Context->Handle, &rect, FALSE); - } - - PhTnpPopTooltip(Context); - - break; - } - } - } - } - break; - case VK_RIGHT: - { - PPH_TREENEW_NODE newNode; - - if (!Context->FocusNode->s.IsLeaf) - { - // If the node is collapsed, expand it. Otherwise, select the node's first child. - if (!Context->FocusNode->Expanded) - { - PhTnpSetExpandedNode(Context, Context->FocusNode, TRUE); - } - else - { - if (Context->FocusNode->Index + 1 < Context->FlatList->Count) - { - newNode = Context->FlatList->Items[Context->FocusNode->Index + 1]; - - if (newNode->Level == Context->FocusNode->Level + 1) - { - Context->FocusNode = newNode; - Context->MarkNodeIndex = newNode->Index; - PhTnpEnsureVisibleNode(Context, Context->FocusNode->Index + 1); - PhTnpSetHotNode(Context, newNode, FALSE); - PhTnpSelectRange(Context, Context->FocusNode->Index, Context->FocusNode->Index, TN_SELECT_RESET, &changedStart, &changedEnd); - - if (PhTnpGetRowRects(Context, changedStart, changedEnd, TRUE, &rect)) - { - InvalidateRect(Context->Handle, &rect, FALSE); - } - - PhTnpPopTooltip(Context); - } - } - } - } - } - break; - case VK_ADD: - case VK_OEM_PLUS: - { - if ((VirtualKey == VK_ADD && controlKey) || - (VirtualKey == VK_OEM_PLUS && controlKey && shiftKey)) - { - ULONG i; - - if (Context->FixedColumnVisible) - PhTnpAutoSizeColumnHeader(Context, Context->FixedHeaderHandle, Context->FixedColumn, 0); - - for (i = 0; i < Context->NumberOfColumnsByDisplay; i++) - PhTnpAutoSizeColumnHeader(Context, Context->HeaderHandle, Context->ColumnsByDisplay[i], 0); - } - } - break; - } - - return TRUE; -} - -VOID PhTnpProcessSearchKey( - _In_ PPH_TREENEW_CONTEXT Context, - _In_ ULONG Character - ) -{ - LONG messageTime; - BOOLEAN newSearch; - PH_TREENEW_SEARCH_EVENT searchEvent; - PPH_TREENEW_NODE foundNode; - ULONG changedStart; - ULONG changedEnd; - RECT rect; - - if (Context->FlatList->Count == 0) - return; - - messageTime = GetMessageTime(); - newSearch = FALSE; - - // Check if the search timed out. - if (messageTime - Context->SearchMessageTime > PH_TREENEW_SEARCH_TIMEOUT) - { - Context->SearchStringCount = 0; - Context->SearchFailed = FALSE; - newSearch = TRUE; - Context->SearchSingleCharMode = TRUE; - } - - Context->SearchMessageTime = messageTime; - - // Append the character to the search buffer. - - if (!Context->SearchString) - { - Context->AllocatedSearchString = 32; - Context->SearchString = PhAllocate(Context->AllocatedSearchString * sizeof(WCHAR)); - newSearch = TRUE; - Context->SearchSingleCharMode = TRUE; - } - - if (Context->SearchStringCount > PH_TREENEW_SEARCH_MAXIMUM_LENGTH) - { - // The search string has become too long. Fail the search. - if (!Context->SearchFailed) - { - MessageBeep(0); - Context->SearchFailed = TRUE; - return; - } - } - else if (Context->SearchStringCount == Context->AllocatedSearchString) - { - Context->AllocatedSearchString *= 2; - Context->SearchString = PhReAllocate(Context->SearchString, Context->AllocatedSearchString * sizeof(WCHAR)); - } - - Context->SearchString[Context->SearchStringCount++] = (WCHAR)Character; - - if (Context->SearchString[Context->SearchStringCount - 1] != Context->SearchString[0]) - { - // The user has stopped typing the same character (or never started). Turn single-character - // search off. - Context->SearchSingleCharMode = FALSE; - } - - searchEvent.FoundIndex = -1; - - if (Context->FocusNode) - { - searchEvent.StartIndex = Context->FocusNode->Index; - - if (newSearch || Context->SearchSingleCharMode) - { - // If it's a new search, start at the next item so the user doesn't find the same item - // again. - searchEvent.StartIndex++; - - if (searchEvent.StartIndex == Context->FlatList->Count) - searchEvent.StartIndex = 0; - } - } - else - { - searchEvent.StartIndex = 0; - } - - searchEvent.String.Buffer = Context->SearchString; - - if (!Context->SearchSingleCharMode) - searchEvent.String.Length = Context->SearchStringCount * sizeof(WCHAR); - else - searchEvent.String.Length = sizeof(WCHAR); - - // Give the user a chance to modify how the search is performed. - if (!Context->Callback(Context->Handle, TreeNewIncrementalSearch, &searchEvent, NULL, Context->CallbackContext)) - { - // Use the default search function. - if (!PhTnpDefaultIncrementalSearch(Context, &searchEvent, TRUE, TRUE)) - { - return; - } - } - - if (searchEvent.FoundIndex == -1 && !Context->SearchFailed) - { - // No search result. Beep to indicate an error, and set the flag so we don't beep again. But - // don't beep if the first character was a space, because that's used for other purposes - // elsewhere (see PhTnpProcessNodeKey). - if (searchEvent.String.Buffer[0] != ' ') - { - MessageBeep(0); - } - - Context->SearchFailed = TRUE; - return; - } - - if (searchEvent.FoundIndex < 0 || searchEvent.FoundIndex >= (LONG)Context->FlatList->Count) - return; - - foundNode = Context->FlatList->Items[searchEvent.FoundIndex]; - Context->FocusNode = foundNode; - PhTnpEnsureVisibleNode(Context, searchEvent.FoundIndex); - PhTnpSetHotNode(Context, foundNode, FALSE); - PhTnpSelectRange(Context, searchEvent.FoundIndex, searchEvent.FoundIndex, TN_SELECT_RESET, &changedStart, &changedEnd); - - if (PhTnpGetRowRects(Context, changedStart, changedEnd, TRUE, &rect)) - { - InvalidateRect(Context->Handle, &rect, FALSE); - } - - PhTnpPopTooltip(Context); -} - -BOOLEAN PhTnpDefaultIncrementalSearch( - _In_ PPH_TREENEW_CONTEXT Context, - _Inout_ PPH_TREENEW_SEARCH_EVENT SearchEvent, - _In_ BOOLEAN Partial, - _In_ BOOLEAN Wrap - ) -{ - LONG startIndex; - LONG currentIndex; - LONG foundIndex; - BOOLEAN firstTime; - - if (Context->FlatList->Count == 0) - return FALSE; - if (!Context->FirstColumn) - return FALSE; - - startIndex = SearchEvent->StartIndex; - currentIndex = startIndex; - foundIndex = -1; - firstTime = TRUE; - - while (TRUE) - { - PH_STRINGREF text; - - if (currentIndex >= (LONG)Context->FlatList->Count) - { - if (Wrap) - currentIndex = 0; - else - break; - } - - // We use the firstTime variable instead of a simpler check because we want to include the - // current item in the search. E.g. the current item is the only item beginning with "Z". If - // the user searches for "Z", we want to return the current item as being found. - if (!firstTime && currentIndex == startIndex) - break; - - if (PhTnpGetCellText(Context, Context->FlatList->Items[currentIndex], Context->FirstColumn->Id, &text)) - { - if (Partial) - { - if (PhStartsWithStringRef(&text, &SearchEvent->String, TRUE)) - { - foundIndex = currentIndex; - break; - } - } - else - { - if (PhEqualStringRef(&text, &SearchEvent->String, TRUE)) - { - foundIndex = currentIndex; - break; - } - } - } - - currentIndex++; - firstTime = FALSE; - } - - SearchEvent->FoundIndex = foundIndex; - - return TRUE; -} - -VOID PhTnpUpdateScrollBars( - _In_ PPH_TREENEW_CONTEXT Context - ) -{ - RECT clientRect; - LONG width; - LONG height; - LONG contentWidth; - LONG contentHeight; - SCROLLINFO scrollInfo; - LONG oldPosition; - LONG deltaRows; - LONG deltaX; - LOGICAL oldHScrollVisible; - RECT rect; - - clientRect = Context->ClientRect; - width = clientRect.right - Context->FixedWidth; - height = clientRect.bottom - Context->HeaderHeight; - - contentWidth = Context->TotalViewX; - contentHeight = (LONG)Context->FlatList->Count * Context->RowHeight; - - if (contentHeight > height) - { - // We need a vertical scrollbar, so we can't use that area of the screen for content. - width -= Context->VScrollWidth; - } - - if (contentWidth > width) - { - height -= Context->HScrollHeight; - } - - deltaRows = 0; - deltaX = 0; - - // Vertical scroll bar - - scrollInfo.cbSize = sizeof(SCROLLINFO); - scrollInfo.fMask = SIF_POS; - GetScrollInfo(Context->VScrollHandle, SB_CTL, &scrollInfo); - oldPosition = scrollInfo.nPos; - - scrollInfo.fMask = SIF_RANGE | SIF_PAGE; - scrollInfo.nMin = 0; - scrollInfo.nMax = Context->FlatList->Count != 0 ? Context->FlatList->Count - 1 : 0; - scrollInfo.nPage = height / Context->RowHeight; - SetScrollInfo(Context->VScrollHandle, SB_CTL, &scrollInfo, TRUE); - - // The scroll position may have changed due to the modified scroll range. - scrollInfo.fMask = SIF_POS; - GetScrollInfo(Context->VScrollHandle, SB_CTL, &scrollInfo); - deltaRows = scrollInfo.nPos - oldPosition; - Context->VScrollPosition = scrollInfo.nPos; - - if (contentHeight > height && contentHeight != 0) - { - ShowWindow(Context->VScrollHandle, SW_SHOW); - Context->VScrollVisible = TRUE; - } - else - { - ShowWindow(Context->VScrollHandle, SW_HIDE); - Context->VScrollVisible = FALSE; - } - - // Horizontal scroll bar - - scrollInfo.cbSize = sizeof(SCROLLINFO); - scrollInfo.fMask = SIF_POS; - GetScrollInfo(Context->HScrollHandle, SB_CTL, &scrollInfo); - oldPosition = scrollInfo.nPos; - - scrollInfo.fMask = SIF_RANGE | SIF_PAGE; - scrollInfo.nMin = 0; - scrollInfo.nMax = contentWidth != 0 ? contentWidth - 1 : 0; - scrollInfo.nPage = width; - SetScrollInfo(Context->HScrollHandle, SB_CTL, &scrollInfo, TRUE); - - scrollInfo.fMask = SIF_POS; - GetScrollInfo(Context->HScrollHandle, SB_CTL, &scrollInfo); - deltaX = scrollInfo.nPos - oldPosition; - Context->HScrollPosition = scrollInfo.nPos; - - oldHScrollVisible = Context->HScrollVisible; - - if (contentWidth > width && contentWidth != 0) - { - ShowWindow(Context->HScrollHandle, SW_SHOW); - Context->HScrollVisible = TRUE; - } - else - { - ShowWindow(Context->HScrollHandle, SW_HIDE); - Context->HScrollVisible = FALSE; - } - - if ((Context->HScrollVisible != oldHScrollVisible) && Context->FixedDividerVisible && Context->AnimateDivider) - { - rect.left = Context->FixedWidth; - rect.top = Context->HeaderHeight; - rect.right = Context->FixedWidth + 1; - rect.bottom = Context->ClientRect.bottom; - InvalidateRect(Context->Handle, &rect, FALSE); - } - - if (deltaRows != 0 || deltaX != 0) - PhTnpProcessScroll(Context, deltaRows, deltaX); - - ShowWindow(Context->FillerBoxHandle, (Context->VScrollVisible && Context->HScrollVisible) ? SW_SHOW : SW_HIDE); -} - -VOID PhTnpScroll( - _In_ PPH_TREENEW_CONTEXT Context, - _In_ LONG DeltaRows, - _In_ LONG DeltaX - ) -{ - SCROLLINFO scrollInfo; - LONG oldPosition; - LONG deltaRows; - LONG deltaX; - - deltaRows = 0; - deltaX = 0; - - scrollInfo.cbSize = sizeof(SCROLLINFO); - scrollInfo.fMask = SIF_POS; - - if (DeltaRows != 0 && Context->VScrollVisible) - { - GetScrollInfo(Context->VScrollHandle, SB_CTL, &scrollInfo); - oldPosition = scrollInfo.nPos; - - if (DeltaRows == MINLONG) - scrollInfo.nPos = 0; - else if (DeltaRows == MAXLONG) - scrollInfo.nPos = Context->FlatList->Count - 1; - else - scrollInfo.nPos += DeltaRows; - - SetScrollInfo(Context->VScrollHandle, SB_CTL, &scrollInfo, TRUE); - GetScrollInfo(Context->VScrollHandle, SB_CTL, &scrollInfo); - Context->VScrollPosition = scrollInfo.nPos; - deltaRows = scrollInfo.nPos - oldPosition; - } - - if (DeltaX != 0 && Context->HScrollVisible) - { - GetScrollInfo(Context->HScrollHandle, SB_CTL, &scrollInfo); - oldPosition = scrollInfo.nPos; - - if (DeltaX == MINLONG) - scrollInfo.nPos = 0; - else if (DeltaX == MAXLONG) - scrollInfo.nPos = Context->TotalViewX; - else - scrollInfo.nPos += DeltaX; - - SetScrollInfo(Context->HScrollHandle, SB_CTL, &scrollInfo, TRUE); - GetScrollInfo(Context->HScrollHandle, SB_CTL, &scrollInfo); - Context->HScrollPosition = scrollInfo.nPos; - deltaX = scrollInfo.nPos - oldPosition; - } - - if (deltaRows != 0 || deltaX != 0) - PhTnpProcessScroll(Context, deltaRows, deltaX); -} - -VOID PhTnpProcessScroll( - _In_ PPH_TREENEW_CONTEXT Context, - _In_ LONG DeltaRows, - _In_ LONG DeltaX - ) -{ - RECT rect; - LONG deltaY; - - rect.top = Context->HeaderHeight; - rect.bottom = Context->ClientRect.bottom; - - if (DeltaX == 0) - { - rect.left = 0; - rect.right = Context->ClientRect.right - (Context->VScrollVisible ? Context->VScrollWidth : 0); - ScrollWindowEx( - Context->Handle, - 0, - -DeltaRows * Context->RowHeight, - &rect, - NULL, - NULL, - NULL, - SW_INVALIDATE - ); - } - else - { - // Don't scroll if there are no rows. This is especially important if the user wants us to - // display empty text. - if (Context->FlatList->Count != 0) - { - deltaY = DeltaRows * Context->RowHeight; - - // If we're scrolling vertically as well, we need to scroll the fixed part and the - // normal part separately. - - if (DeltaRows != 0) - { - rect.left = 0; - rect.right = Context->NormalLeft; - ScrollWindowEx( - Context->Handle, - 0, - -deltaY, - &rect, - &rect, - NULL, - NULL, - SW_INVALIDATE - ); - } - - rect.left = Context->NormalLeft; - rect.right = Context->ClientRect.right - (Context->VScrollVisible ? Context->VScrollWidth : 0); - ScrollWindowEx( - Context->Handle, - -DeltaX, - -deltaY, - &rect, - &rect, - NULL, - NULL, - SW_INVALIDATE - ); - } - - PhTnpLayoutHeader(Context); - } -} - -BOOLEAN PhTnpCanScroll( - _In_ PPH_TREENEW_CONTEXT Context, - _In_ BOOLEAN Horizontal, - _In_ BOOLEAN Positive - ) -{ - SCROLLINFO scrollInfo; - - scrollInfo.cbSize = sizeof(SCROLLINFO); - scrollInfo.fMask = SIF_RANGE | SIF_PAGE | SIF_POS; - - if (!Horizontal) - GetScrollInfo(Context->VScrollHandle, SB_CTL, &scrollInfo); - else - GetScrollInfo(Context->HScrollHandle, SB_CTL, &scrollInfo); - - if (Positive) - { - if (scrollInfo.nPage != 0) - scrollInfo.nMax -= scrollInfo.nPage - 1; - - return scrollInfo.nPos < scrollInfo.nMax; - } - else - { - return scrollInfo.nPos > scrollInfo.nMin; - } -} - -VOID PhTnpPaint( - _In_ HWND hwnd, - _In_ PPH_TREENEW_CONTEXT Context, - _In_ HDC hdc, - _In_ PRECT PaintRect - ) -{ - RECT viewRect; - LONG vScrollPosition; - LONG hScrollPosition; - LONG firstRowToUpdate; - LONG lastRowToUpdate; - LONG i; - LONG j; - PPH_TREENEW_NODE node; - PPH_TREENEW_COLUMN column; - RECT rowRect; - LONG x; - BOOLEAN fixedUpdate; - LONG normalUpdateLeftX; - LONG normalUpdateRightX; - LONG normalUpdateLeftIndex; - LONG normalUpdateRightIndex; - LONG normalTotalX; - RECT cellRect; - HBRUSH backBrush; - HRGN oldClipRegion; - - PhTnpInitializeThemeData(Context); - - viewRect = Context->ClientRect; - - if (Context->VScrollVisible) - viewRect.right -= Context->VScrollWidth; - - vScrollPosition = Context->VScrollPosition; - hScrollPosition = Context->HScrollPosition; - - // Calculate the indicies of the first and last rows that need painting. These indicies are - // relative to the top of the view area. - - firstRowToUpdate = (PaintRect->top - Context->HeaderHeight) / Context->RowHeight; - lastRowToUpdate = (PaintRect->bottom - 1 - Context->HeaderHeight) / Context->RowHeight; // minus one since bottom is exclusive - - if (firstRowToUpdate < 0) - firstRowToUpdate = 0; - - rowRect.left = 0; - rowRect.top = Context->HeaderHeight + firstRowToUpdate * Context->RowHeight; - rowRect.right = Context->NormalLeft + Context->TotalViewX - Context->HScrollPosition; - rowRect.bottom = rowRect.top + Context->RowHeight; - - // Change the indicies to absolute row indicies. - - firstRowToUpdate += vScrollPosition; - lastRowToUpdate += vScrollPosition; - - if (lastRowToUpdate >= (LONG)Context->FlatList->Count) - lastRowToUpdate = Context->FlatList->Count - 1; // becomes -1 when there are no items, handled correctly by loop below - - // Determine whether the fixed column needs painting, and which normal columns need painting. - - fixedUpdate = FALSE; - - if (Context->FixedColumnVisible && PaintRect->left < Context->FixedWidth) - fixedUpdate = TRUE; - - x = Context->NormalLeft - hScrollPosition; - normalUpdateLeftX = viewRect.right; - normalUpdateLeftIndex = 0; - normalUpdateRightX = 0; - normalUpdateRightIndex = -1; - - for (j = 0; j < (LONG)Context->NumberOfColumnsByDisplay; j++) - { - column = Context->ColumnsByDisplay[j]; - - if (x + column->Width >= Context->NormalLeft && x + column->Width > PaintRect->left && x < PaintRect->right) - { - if (normalUpdateLeftX > x) - { - normalUpdateLeftX = x; - normalUpdateLeftIndex = j; - } - - if (normalUpdateRightX < x + column->Width) - { - normalUpdateRightX = x + column->Width; - normalUpdateRightIndex = j; - } - } - - x += column->Width; - } - - normalTotalX = x; - - if (normalUpdateRightIndex >= (LONG)Context->NumberOfColumnsByDisplay) - normalUpdateRightIndex = Context->NumberOfColumnsByDisplay - 1; - - // Paint the rows. - - SelectObject(hdc, Context->Font); - SetBkMode(hdc, TRANSPARENT); - - for (i = firstRowToUpdate; i <= lastRowToUpdate; i++) - { - node = Context->FlatList->Items[i]; - - // Prepare the row for drawing. - - PhTnpPrepareRowForDraw(Context, hdc, node); - - if (node->Selected && !Context->ThemeHasItemBackground) - { - // Non-themed background - if (Context->HasFocus) - { - SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT)); - backBrush = GetSysColorBrush(COLOR_HIGHLIGHT); - } - else - { - SetTextColor(hdc, GetSysColor(COLOR_BTNTEXT)); - backBrush = GetSysColorBrush(COLOR_BTNFACE); - } - } - else - { - SetTextColor(hdc, node->s.DrawForeColor); - SetDCBrushColor(hdc, node->s.DrawBackColor); - backBrush = GetStockObject(DC_BRUSH); - } - - FillRect(hdc, &rowRect, backBrush); - - if (Context->ThemeHasItemBackground) - { - INT stateId; - - // Themed background - - if (node->Selected) - { - if (i == Context->HotNodeIndex) - stateId = TREIS_HOTSELECTED; - else if (!Context->HasFocus) - stateId = TREIS_SELECTEDNOTFOCUS; - else - stateId = TREIS_SELECTED; - } - else - { - if (i == Context->HotNodeIndex) - stateId = TREIS_HOT; - else - stateId = -1; - } - - if (stateId != -1) - { - if (!Context->FixedColumnVisible) - { - rowRect.left = Context->NormalLeft - hScrollPosition; - } - - DrawThemeBackground( - Context->ThemeData, - hdc, - TVP_TREEITEM, - stateId, - &rowRect, - PaintRect - ); - } - } - - // Paint the fixed column. - - cellRect.top = rowRect.top; - cellRect.bottom = rowRect.bottom; - - if (fixedUpdate) - { - cellRect.left = 0; - cellRect.right = Context->FixedWidth; - PhTnpDrawCell(Context, hdc, &cellRect, node, Context->FixedColumn, i, -1); - } - - // Paint the normal columns. - - if (normalUpdateLeftX < normalUpdateRightX) - { - cellRect.left = normalUpdateLeftX; - cellRect.right = cellRect.left; - - oldClipRegion = CreateRectRgn(0, 0, 0, 0); - - if (GetClipRgn(hdc, oldClipRegion) != 1) - { - DeleteObject(oldClipRegion); - oldClipRegion = NULL; - } - - IntersectClipRect(hdc, Context->NormalLeft, cellRect.top, viewRect.right, cellRect.bottom); - - for (j = normalUpdateLeftIndex; j <= normalUpdateRightIndex; j++) - { - column = Context->ColumnsByDisplay[j]; - - cellRect.left = cellRect.right; - cellRect.right = cellRect.left + column->Width; - PhTnpDrawCell(Context, hdc, &cellRect, node, column, i, j); - } - - SelectClipRgn(hdc, oldClipRegion); - - if (oldClipRegion) - { - DeleteObject(oldClipRegion); - } - } - - rowRect.top += Context->RowHeight; - rowRect.bottom += Context->RowHeight; - } - - if (lastRowToUpdate == Context->FlatList->Count - 1) // works even if there are no items - { - // Fill the rest of the space on the bottom with the window color. - rowRect.bottom = viewRect.bottom; - FillRect(hdc, &rowRect, GetSysColorBrush(COLOR_WINDOW)); - } - - if (normalTotalX < viewRect.right && viewRect.right > PaintRect->left && normalTotalX < PaintRect->right) - { - // Fill the rest of the space on the right with the window color. - rowRect.left = normalTotalX; - rowRect.top = Context->HeaderHeight; - rowRect.right = viewRect.right; - rowRect.bottom = viewRect.bottom; - FillRect(hdc, &rowRect, GetSysColorBrush(COLOR_WINDOW)); - } - - if (Context->FlatList->Count == 0 && Context->EmptyText.Length != 0) - { - RECT textRect; - - textRect.left = 20; - textRect.top = Context->HeaderHeight + 10; - textRect.right = viewRect.right - 20; - textRect.bottom = viewRect.bottom - 5; - - SetTextColor(hdc, GetSysColor(COLOR_GRAYTEXT)); - DrawText( - hdc, - Context->EmptyText.Buffer, - (ULONG)Context->EmptyText.Length / 2, - &textRect, - DT_NOPREFIX | DT_CENTER | DT_END_ELLIPSIS - ); - } - - if (Context->FixedDividerVisible && Context->FixedWidth >= PaintRect->left && Context->FixedWidth < PaintRect->right) - { - PhTnpDrawDivider(Context, hdc); - } - - if (Context->DragSelectionActive) - { - PhTnpDrawSelectionRectangle(Context, hdc, &Context->DragRect); - } -} - -VOID PhTnpPrepareRowForDraw( - _In_ PPH_TREENEW_CONTEXT Context, - _In_ HDC hdc, - _Inout_ PPH_TREENEW_NODE Node - ) -{ - if (!Node->s.CachedColorValid) - { - PH_TREENEW_GET_NODE_COLOR getNodeColor; - - getNodeColor.Flags = 0; - getNodeColor.Node = Node; - getNodeColor.BackColor = RGB(0xff, 0xff, 0xff); - getNodeColor.ForeColor = RGB(0x00, 0x00, 0x00); - - if (Context->Callback( - Context->Handle, - TreeNewGetNodeColor, - &getNodeColor, - NULL, - Context->CallbackContext - )) - { - Node->BackColor = getNodeColor.BackColor; - Node->ForeColor = getNodeColor.ForeColor; - Node->UseAutoForeColor = !!(getNodeColor.Flags & TN_AUTO_FORECOLOR); - - if (getNodeColor.Flags & TN_CACHE) - Node->s.CachedColorValid = TRUE; - } - else - { - Node->BackColor = getNodeColor.BackColor; - Node->ForeColor = getNodeColor.ForeColor; - } - } - - Node->s.DrawForeColor = Node->ForeColor; - - if (Node->UseTempBackColor) - Node->s.DrawBackColor = Node->TempBackColor; - else - Node->s.DrawBackColor = Node->BackColor; - - if (!Node->s.CachedFontValid) - { - PH_TREENEW_GET_NODE_FONT getNodeFont; - - getNodeFont.Flags = 0; - getNodeFont.Node = Node; - getNodeFont.Font = NULL; - - if (Context->Callback( - Context->Handle, - TreeNewGetNodeFont, - &getNodeFont, - NULL, - Context->CallbackContext - )) - { - Node->Font = getNodeFont.Font; - - if (getNodeFont.Flags & TN_CACHE) - Node->s.CachedFontValid = TRUE; - } - else - { - Node->Font = NULL; - } - } - - if (!Node->s.CachedIconValid) - { - PH_TREENEW_GET_NODE_ICON getNodeIcon; - - getNodeIcon.Flags = 0; - getNodeIcon.Node = Node; - getNodeIcon.Icon = NULL; - - if (Context->Callback( - Context->Handle, - TreeNewGetNodeIcon, - &getNodeIcon, - NULL, - Context->CallbackContext - )) - { - Node->Icon = getNodeIcon.Icon; - - if (getNodeIcon.Flags & TN_CACHE) - Node->s.CachedIconValid = TRUE; - } - else - { - Node->Icon = NULL; - } - } - - if (Node->UseAutoForeColor || Node->UseTempBackColor) - { - if (PhGetColorBrightness(Node->s.DrawBackColor) > 100) // slightly less than half - Node->s.DrawForeColor = RGB(0x00, 0x00, 0x00); - else - Node->s.DrawForeColor = RGB(0xff, 0xff, 0xff); - } -} - -VOID PhTnpDrawCell( - _In_ PPH_TREENEW_CONTEXT Context, - _In_ HDC hdc, - _In_ PRECT CellRect, - _In_ PPH_TREENEW_NODE Node, - _In_ PPH_TREENEW_COLUMN Column, - _In_ LONG RowIndex, - _In_ LONG ColumnIndex - ) -{ - HFONT font; // font to use - HFONT oldFont; - PH_STRINGREF text; // text to draw - RECT textRect; // working rectangle, modified as needed - ULONG textFlags; // DT_* flags - LONG iconVerticalMargin; // top/bottom margin for icons (determined using height of small icon) - - font = Node->Font; - textFlags = Column->TextFlags; - - textRect = *CellRect; - - // Initial margins used by default list view - textRect.left += TNP_CELL_LEFT_MARGIN; - textRect.right -= TNP_CELL_RIGHT_MARGIN; - - // icon margin = (height of row - height of small icon) / 2 - iconVerticalMargin = ((textRect.bottom - textRect.top) - SmallIconHeight) / 2; - - textRect.top += iconVerticalMargin; - textRect.bottom -= iconVerticalMargin; - - if (Column == Context->FirstColumn) - { - BOOLEAN needsClip; - HRGN oldClipRegion; - - textRect.left += Node->Level * SmallIconWidth; - - // The icon may need to be clipped if the column is too small. - needsClip = Column->Width < textRect.left + (Context->CanAnyExpand ? SmallIconWidth : 0) + (Node->Icon ? SmallIconWidth : 0); - - if (needsClip) - { - oldClipRegion = CreateRectRgn(0, 0, 0, 0); - - if (GetClipRgn(hdc, oldClipRegion) != 1) - { - DeleteObject(oldClipRegion); - oldClipRegion = NULL; - } - - // Clip contents to the column. - IntersectClipRect(hdc, CellRect->left, textRect.top, CellRect->right, textRect.bottom); - } - - if (Context->CanAnyExpand) // flag is used so we can avoid indenting when it's a flat list - { - BOOLEAN drewUsingTheme = FALSE; - RECT themeRect; - - if (!Node->s.IsLeaf) - { - // Draw the plus/minus glyph. - - themeRect.left = textRect.left; - themeRect.right = themeRect.left + SmallIconWidth; - themeRect.top = textRect.top; - themeRect.bottom = themeRect.top + SmallIconHeight; - - if (Context->ThemeHasGlyph) - { - INT partId; - INT stateId; - - partId = (RowIndex == Context->HotNodeIndex && Node->s.PlusMinusHot && Context->ThemeHasHotGlyph) ? TVP_HOTGLYPH : TVP_GLYPH; - stateId = Node->Expanded ? GLPS_OPENED : GLPS_CLOSED; - - if (SUCCEEDED(DrawThemeBackground( - Context->ThemeData, - hdc, - partId, - stateId, - &themeRect, - NULL - ))) - drewUsingTheme = TRUE; - } - - if (!drewUsingTheme) - { - ULONG glyphWidth; - ULONG glyphHeight; - RECT glyphRect; - - glyphWidth = SmallIconWidth / 2; - glyphHeight = SmallIconHeight / 2; - - glyphRect.left = textRect.left + (SmallIconWidth - glyphWidth) / 2; - glyphRect.right = glyphRect.left + glyphWidth; - glyphRect.top = textRect.top + (SmallIconHeight - glyphHeight) / 2; - glyphRect.bottom = glyphRect.top + glyphHeight; - - PhTnpDrawPlusMinusGlyph(hdc, &glyphRect, !Node->Expanded); - } - } - - textRect.left += SmallIconWidth; - } - - // Draw the icon. - if (Node->Icon) - { - DrawIconEx( - hdc, - textRect.left, - textRect.top, - Node->Icon, - SmallIconWidth, - SmallIconHeight, - 0, - NULL, - DI_NORMAL - ); - - textRect.left += SmallIconWidth + TNP_ICON_RIGHT_PADDING; - } - - if (needsClip) - { - SelectClipRgn(hdc, oldClipRegion); - - if (oldClipRegion) - DeleteObject(oldClipRegion); - } - - if (textRect.left > textRect.right) - textRect.left = textRect.right; - } - - if (Column->CustomDraw) - { - BOOLEAN result; - PH_TREENEW_CUSTOM_DRAW customDraw; - INT savedDc; - - customDraw.Node = Node; - customDraw.Column = Column; - customDraw.Dc = hdc; - customDraw.CellRect = *CellRect; - customDraw.TextRect = textRect; - - // Fix up the rectangles before giving them to the user. - if (customDraw.CellRect.left > customDraw.CellRect.right) - customDraw.CellRect.left = customDraw.CellRect.right; - if (customDraw.TextRect.left > customDraw.TextRect.right) - customDraw.TextRect.left = customDraw.TextRect.right; - - savedDc = SaveDC(hdc); - result = Context->Callback(Context->Handle, TreeNewCustomDraw, &customDraw, NULL, Context->CallbackContext); - RestoreDC(hdc, savedDc); - - if (result) - return; - } - - if (PhTnpGetCellText(Context, Node, Column->Id, &text)) - { - if (!(textFlags & (DT_PATH_ELLIPSIS | DT_WORD_ELLIPSIS))) - textFlags |= DT_END_ELLIPSIS; - - textFlags |= DT_NOPREFIX | DT_VCENTER | DT_SINGLELINE; - - textRect.top = CellRect->top; - textRect.bottom = CellRect->bottom; - - if (font) - oldFont = SelectObject(hdc, font); - - DrawText( - hdc, - text.Buffer, - (ULONG)text.Length / 2, - &textRect, - textFlags - ); - - if (font) - SelectObject(hdc, oldFont); - } -} - -VOID PhTnpDrawDivider( - _In_ PPH_TREENEW_CONTEXT Context, - _In_ HDC hdc - ) -{ - POINT points[2]; - - if (Context->AnimateDivider) - { - if (Context->DividerHot == 0 && !Context->HScrollVisible) - return; // divider is invisible - - if (Context->DividerHot < 100) - { - BLENDFUNCTION blendFunction; - - // We need to draw and alpha blend the divider. - // We can use the extra column allocated in the buffered context to initially draw the - // divider. - - points[0].x = Context->ClientRect.right; - points[0].y = Context->HeaderHeight; - points[1].x = Context->ClientRect.right; - points[1].y = Context->ClientRect.bottom; - SetDCPenColor(Context->BufferedContext, RGB(0x77, 0x77, 0x77)); - SelectObject(Context->BufferedContext, GetStockObject(DC_PEN)); - Polyline(Context->BufferedContext, points, 2); - - blendFunction.BlendOp = AC_SRC_OVER; - blendFunction.BlendFlags = 0; - blendFunction.AlphaFormat = 0; - - // If the horizontal scroll bar is visible, we need to display a line even if the - // divider is not hot. In this case we increase the base alpha value. - if (!Context->HScrollVisible) - blendFunction.SourceConstantAlpha = (UCHAR)(Context->DividerHot * 255 / 100); - else - blendFunction.SourceConstantAlpha = 55 + (UCHAR)(Context->DividerHot * 2); - - GdiAlphaBlend( - hdc, - Context->FixedWidth, - Context->HeaderHeight, - 1, - Context->ClientRect.bottom - Context->HeaderHeight, - Context->BufferedContext, - Context->ClientRect.right, - Context->HeaderHeight, - 1, - Context->ClientRect.bottom - Context->HeaderHeight, - blendFunction - ); - - return; - } - } - - points[0].x = Context->FixedWidth; - points[0].y = Context->HeaderHeight; - points[1].x = Context->FixedWidth; - points[1].y = Context->ClientRect.bottom; - SetDCPenColor(hdc, RGB(0x77, 0x77, 0x77)); - SelectObject(hdc, GetStockObject(DC_PEN)); - Polyline(hdc, points, 2); -} - -VOID PhTnpDrawPlusMinusGlyph( - _In_ HDC hdc, - _In_ PRECT Rect, - _In_ BOOLEAN Plus - ) -{ - INT savedDc; - ULONG width; - ULONG height; - POINT points[2]; - - savedDc = SaveDC(hdc); - - SelectObject(hdc, GetStockObject(DC_PEN)); - SetDCPenColor(hdc, RGB(0x55, 0x55, 0x55)); - SelectObject(hdc, GetStockObject(DC_BRUSH)); - SetDCBrushColor(hdc, RGB(0xff, 0xff, 0xff)); - - width = Rect->right - Rect->left; - height = Rect->bottom - Rect->top; - - // Draw the rectangle. - Rectangle(hdc, Rect->left, Rect->top, Rect->right + 1, Rect->bottom + 1); - - SetDCPenColor(hdc, RGB(0x00, 0x00, 0x00)); - - // Draw the horizontal line. - points[0].x = Rect->left + 2; - points[0].y = Rect->top + height / 2; - points[1].x = Rect->right - 2 + 1; - points[1].y = points[0].y; - Polyline(hdc, points, 2); - - if (Plus) - { - // Draw the vertical line. - points[0].x = Rect->left + width / 2; - points[0].y = Rect->top + 2; - points[1].x = points[0].x; - points[1].y = Rect->bottom - 2 + 1; - Polyline(hdc, points, 2); - } - - RestoreDC(hdc, savedDc); -} - -VOID PhTnpDrawSelectionRectangle( - _In_ PPH_TREENEW_CONTEXT Context, - _In_ HDC hdc, - _In_ PRECT Rect - ) -{ - RECT rect; - BOOLEAN drewWithAlpha; - - rect = *Rect; - - // MSDN says FrameRect/DrawFocusRect doesn't draw anything if bottom <= top or right <= left. - // That's complete rubbish. - if (rect.right - rect.left == 0 || rect.bottom - rect.top == 0) - return; - - drewWithAlpha = FALSE; - - if (Context->SelectionRectangleAlpha) - { - HDC tempDc; - BITMAPINFOHEADER header; - HBITMAP bitmap; - HBITMAP oldBitmap; - PVOID bits; - RECT tempRect; - BLENDFUNCTION blendFunction; - - tempDc = CreateCompatibleDC(hdc); - - if (tempDc) - { - memset(&header, 0, sizeof(BITMAPINFOHEADER)); - header.biSize = sizeof(BITMAPINFOHEADER); - header.biWidth = 1; - header.biHeight = 1; - header.biPlanes = 1; - header.biBitCount = 24; - bitmap = CreateDIBSection(tempDc, (BITMAPINFO *)&header, DIB_RGB_COLORS, &bits, NULL, 0); - - if (bitmap) - { - // Draw the outline of the selection rectangle. - FrameRect(hdc, &rect, GetSysColorBrush(COLOR_HIGHLIGHT)); - - // Fill in the selection rectangle. - - oldBitmap = SelectObject(tempDc, bitmap); - tempRect.left = 0; - tempRect.top = 0; - tempRect.right = 1; - tempRect.bottom = 1; - FillRect(tempDc, &tempRect, GetSysColorBrush(COLOR_HOTLIGHT)); - - blendFunction.BlendOp = AC_SRC_OVER; - blendFunction.BlendFlags = 0; - blendFunction.SourceConstantAlpha = 70; - blendFunction.AlphaFormat = 0; - - GdiAlphaBlend( - hdc, - rect.left, - rect.top, - rect.right - rect.left, - rect.bottom - rect.top, - tempDc, - 0, - 0, - 1, - 1, - blendFunction - ); - - drewWithAlpha = TRUE; - - SelectObject(tempDc, oldBitmap); - DeleteObject(bitmap); - } - - DeleteDC(tempDc); - } - } - - if (!drewWithAlpha) - { - DrawFocusRect(hdc, &rect); - } -} - -VOID PhTnpDrawThemedBorder( - _In_ PPH_TREENEW_CONTEXT Context, - _In_ HDC hdc - ) -{ - RECT windowRect; - RECT clientRect; - LONG sizingBorderWidth; - LONG borderX; - LONG borderY; - - GetWindowRect(Context->Handle, &windowRect); - windowRect.right -= windowRect.left; - windowRect.bottom -= windowRect.top; - windowRect.left = 0; - windowRect.top = 0; - - clientRect.left = windowRect.left + Context->SystemEdgeX; - clientRect.top = windowRect.top + Context->SystemEdgeY; - clientRect.right = windowRect.right - Context->SystemEdgeX; - clientRect.bottom = windowRect.bottom - Context->SystemEdgeY; - - // Make sure we don't paint in the client area. - ExcludeClipRect(hdc, clientRect.left, clientRect.top, clientRect.right, clientRect.bottom); - - // Draw the themed border. - DrawThemeBackground(Context->ThemeData, hdc, 0, 0, &windowRect, NULL); - - // Calculate the size of the border we just drew, and fill in the rest of the space if we didn't - // fully paint the region. - - if (SUCCEEDED(GetThemeInt(Context->ThemeData, 0, 0, TMT_SIZINGBORDERWIDTH, &sizingBorderWidth))) - { - borderX = sizingBorderWidth; - borderY = sizingBorderWidth; - } - else - { - borderX = Context->SystemBorderX; - borderY = Context->SystemBorderY; - } - - if (borderX < Context->SystemEdgeX || borderY < Context->SystemEdgeY) - { - windowRect.left += Context->SystemEdgeX - borderX; - windowRect.top += Context->SystemEdgeY - borderY; - windowRect.right -= Context->SystemEdgeX - borderX; - windowRect.bottom -= Context->SystemEdgeY - borderY; - FillRect(hdc, &windowRect, GetSysColorBrush(COLOR_WINDOW)); - } -} - -VOID PhTnpInitializeTooltips( - _In_ PPH_TREENEW_CONTEXT Context - ) -{ - TOOLINFO toolInfo; - - Context->TooltipsHandle = CreateWindowEx( - WS_EX_TRANSPARENT, // solves double-click problem - TOOLTIPS_CLASS, - NULL, - WS_POPUP | TTS_NOPREFIX, - 0, - 0, - 0, - 0, - NULL, - NULL, - Context->InstanceHandle, - NULL - ); - - if (!Context->TooltipsHandle) - return; - - // Item tooltips - memset(&toolInfo, 0, sizeof(TOOLINFO)); - toolInfo.cbSize = sizeof(TOOLINFO); - toolInfo.uFlags = TTF_TRANSPARENT; - toolInfo.hwnd = Context->Handle; - toolInfo.uId = TNP_TOOLTIPS_ITEM; - toolInfo.lpszText = LPSTR_TEXTCALLBACK; - toolInfo.lParam = TNP_TOOLTIPS_ITEM; - SendMessage(Context->TooltipsHandle, TTM_ADDTOOL, 0, (LPARAM)&toolInfo); - - // Fixed column tooltips - toolInfo.uFlags = 0; - toolInfo.hwnd = Context->FixedHeaderHandle; - toolInfo.uId = TNP_TOOLTIPS_FIXED_HEADER; - toolInfo.lpszText = LPSTR_TEXTCALLBACK; - toolInfo.lParam = TNP_TOOLTIPS_FIXED_HEADER; - SendMessage(Context->TooltipsHandle, TTM_ADDTOOL, 0, (LPARAM)&toolInfo); - - // Normal column tooltips - toolInfo.uFlags = 0; - toolInfo.hwnd = Context->HeaderHandle; - toolInfo.uId = TNP_TOOLTIPS_HEADER; - toolInfo.lpszText = LPSTR_TEXTCALLBACK; - toolInfo.lParam = TNP_TOOLTIPS_HEADER; - SendMessage(Context->TooltipsHandle, TTM_ADDTOOL, 0, (LPARAM)&toolInfo); - - // Hook the header control window procedures so we can forward mouse messages to the tooltip - // control. - SetWindowSubclass(Context->FixedHeaderHandle, PhTnpHeaderHookWndProc, 0, (ULONG_PTR)Context); - SetWindowSubclass(Context->HeaderHandle, PhTnpHeaderHookWndProc, 0, (ULONG_PTR)Context); - - SendMessage(Context->TooltipsHandle, TTM_SETMAXTIPWIDTH, 0, MAXSHORT); // no limit - SendMessage(Context->TooltipsHandle, WM_SETFONT, (WPARAM)Context->Font, FALSE); - Context->TooltipFont = Context->Font; -} - -VOID PhTnpGetTooltipText( - _In_ PPH_TREENEW_CONTEXT Context, - _In_ PPOINT Point, - _Out_ PWSTR *Text - ) -{ - PH_TREENEW_HIT_TEST hitTest; - BOOLEAN unfoldingTooltip; - BOOLEAN unfoldingTooltipFromViewCancelled; - PH_TREENEW_CELL_PARTS parts; - LONG viewRight; - PH_TREENEW_GET_CELL_TOOLTIP getCellTooltip; - - hitTest.Point = *Point; - hitTest.InFlags = TN_TEST_COLUMN | TN_TEST_SUBITEM; - PhTnpHitTest(Context, &hitTest); - - if (Context->DragSelectionActive) - return; - if (!(hitTest.Flags & TN_HIT_ITEM)) - return; - if (hitTest.Flags & (TN_HIT_ITEM_PLUSMINUS | TN_HIT_DIVIDER)) - return; - if (!hitTest.Column) - return; - - if (Context->TooltipIndex != hitTest.Node->Index || Context->TooltipId != hitTest.Column->Id) - { - Context->TooltipIndex = hitTest.Node->Index; - Context->TooltipId = hitTest.Column->Id; - - getCellTooltip.Flags = 0; - getCellTooltip.Node = hitTest.Node; - getCellTooltip.Column = hitTest.Column; - getCellTooltip.Unfolding = FALSE; - PhInitializeEmptyStringRef(&getCellTooltip.Text); - getCellTooltip.Font = Context->Font; - getCellTooltip.MaximumWidth = -1; - - unfoldingTooltip = FALSE; - unfoldingTooltipFromViewCancelled = FALSE; - - if (!(Context->ExtendedFlags & TN_FLAG_NO_UNFOLDING_TOOLTIPS) && - PhTnpGetCellParts(Context, hitTest.Node->Index, hitTest.Column, TN_MEASURE_TEXT, &parts) && - (parts.Flags & TN_PART_CONTENT) && (parts.Flags & TN_PART_TEXT)) - { - viewRight = Context->ClientRect.right - (Context->VScrollVisible ? Context->VScrollWidth : 0); - - // Use an unfolding tooltip if the text was truncated within the column, or the text - // extends beyond the view area in either direction. - - if (parts.TextRect.left < parts.ContentRect.left || parts.TextRect.right > parts.ContentRect.right) - { - unfoldingTooltip = TRUE; - } - else if ((!hitTest.Column->Fixed && parts.TextRect.left < Context->NormalLeft) || parts.TextRect.right > viewRight) - { - // Only show view-based unfolding tooltips if the mouse is over the text itself. - if (Point->x >= parts.TextRect.left && Point->x < parts.TextRect.right) - unfoldingTooltip = TRUE; - else - unfoldingTooltipFromViewCancelled = TRUE; - } - - if (unfoldingTooltip) - { - getCellTooltip.Unfolding = TRUE; - getCellTooltip.Text = parts.Text; - getCellTooltip.Font = parts.Font; // try to use the same font as the cell - - Context->TooltipRect = parts.TextRect; - } - } - - Context->Callback(Context->Handle, TreeNewGetCellTooltip, &getCellTooltip, NULL, Context->CallbackContext); - - Context->TooltipUnfolding = getCellTooltip.Unfolding; - - if (getCellTooltip.Text.Buffer && getCellTooltip.Text.Length != 0) - { - PhMoveReference(&Context->TooltipText, PhCreateString2(&getCellTooltip.Text)); - } - else - { - PhClearReference(&Context->TooltipText); - - if (unfoldingTooltipFromViewCancelled) - { - // We may need to show the view-based unfolding tooltip if the mouse moves over the - // text in the future. Reset the index and ID to make sure we keep checking. - Context->TooltipIndex = -1; - Context->TooltipId = -1; - } - } - - Context->NewTooltipFont = getCellTooltip.Font; - - if (!Context->NewTooltipFont) - Context->NewTooltipFont = Context->Font; - - if (getCellTooltip.MaximumWidth <= MAXSHORT) // seems to be the maximum value that the tooltip control supports - SendMessage(Context->TooltipsHandle, TTM_SETMAXTIPWIDTH, 0, getCellTooltip.MaximumWidth); - else - SendMessage(Context->TooltipsHandle, TTM_SETMAXTIPWIDTH, 0, MAXSHORT); - } - - if (Context->TooltipText) - *Text = Context->TooltipText->Buffer; -} - -BOOLEAN PhTnpPrepareTooltipShow( - _In_ PPH_TREENEW_CONTEXT Context - ) -{ - RECT rect; - - if (Context->TooltipFont != Context->NewTooltipFont) - { - Context->TooltipFont = Context->NewTooltipFont; - SendMessage(Context->TooltipsHandle, WM_SETFONT, (WPARAM)Context->TooltipFont, FALSE); - } - - if (!Context->TooltipUnfolding) - { - SetWindowPos( - Context->TooltipsHandle, - HWND_TOPMOST, - 0, - 0, - 0, - 0, - SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_HIDEWINDOW - ); - - return FALSE; - } - - rect = Context->TooltipRect; - SendMessage(Context->TooltipsHandle, TTM_ADJUSTRECT, TRUE, (LPARAM)&rect); - MapWindowPoints(Context->Handle, NULL, (POINT *)&rect, 2); - SetWindowPos( - Context->TooltipsHandle, - HWND_TOPMOST, - rect.left, - rect.top, - 0, - 0, - SWP_NOSIZE | SWP_NOACTIVATE | SWP_HIDEWINDOW - ); - - return TRUE; -} - -VOID PhTnpPrepareTooltipPop( - _In_ PPH_TREENEW_CONTEXT Context - ) -{ - Context->TooltipIndex = -1; - Context->TooltipId = -1; - Context->TooltipColumnId = -1; -} - -VOID PhTnpPopTooltip( - _In_ PPH_TREENEW_CONTEXT Context - ) -{ - if (Context->TooltipsHandle) - { - SendMessage(Context->TooltipsHandle, TTM_POP, 0, 0); - PhTnpPrepareTooltipPop(Context); - } -} - -PPH_TREENEW_COLUMN PhTnpHitTestHeader( - _In_ PPH_TREENEW_CONTEXT Context, - _In_ BOOLEAN Fixed, - _In_ PPOINT Point, - _Out_opt_ PRECT ItemRect - ) -{ - PPH_TREENEW_COLUMN column; - RECT itemRect; - - if (Fixed) - { - if (!Context->FixedColumnVisible) - return NULL; - - column = Context->FixedColumn; - - if (!Header_GetItemRect(Context->FixedHeaderHandle, 0, &itemRect)) - return NULL; - } - else - { - HDHITTESTINFO hitTestInfo; - - hitTestInfo.pt = *Point; - hitTestInfo.flags = 0; - hitTestInfo.iItem = -1; - - if (SendMessage(Context->HeaderHandle, HDM_HITTEST, 0, (LPARAM)&hitTestInfo) != -1 && hitTestInfo.iItem != -1) - { - HDITEM item; - - item.mask = HDI_LPARAM; - - if (!Header_GetItem(Context->HeaderHandle, hitTestInfo.iItem, &item)) - return NULL; - - column = (PPH_TREENEW_COLUMN)item.lParam; - - if (!Header_GetItemRect(Context->HeaderHandle, hitTestInfo.iItem, &itemRect)) - return NULL; - } - else - { - return NULL; - } - } - - if (ItemRect) - *ItemRect = itemRect; - - return column; -} - -VOID PhTnpGetHeaderTooltipText( - _In_ PPH_TREENEW_CONTEXT Context, - _In_ BOOLEAN Fixed, - _In_ PPOINT Point, - _Out_ PWSTR *Text - ) -{ - LOGICAL result; - PPH_TREENEW_COLUMN column; - RECT itemRect; - PWSTR text; - SIZE_T textCount; - HDC hdc; - SIZE textSize; - - column = PhTnpHitTestHeader(Context, Fixed, Point, &itemRect); - - if (!column) - return; - - if (Context->TooltipColumnId != column->Id) - { - // Determine if the tooltip needs to be shown. - - text = column->Text; - textCount = PhCountStringZ(text); - - if (!(hdc = GetDC(Context->Handle))) - return; - - SelectObject(hdc, Context->Font); - - result = GetTextExtentPoint32(hdc, text, (ULONG)textCount, &textSize); - ReleaseDC(Context->Handle, hdc); - - if (!result) - return; - - if (textSize.cx + 6 + 6 <= itemRect.right - itemRect.left) // HACK: Magic values (same as our cell margins?) - return; - - Context->TooltipColumnId = column->Id; - PhMoveReference(&Context->TooltipText, PhCreateStringEx(text, textCount * sizeof(WCHAR))); - } - - *Text = Context->TooltipText->Buffer; - - // Always use the default parameters for column header tooltips. - Context->NewTooltipFont = Context->Font; - Context->TooltipUnfolding = FALSE; - SendMessage(Context->TooltipsHandle, TTM_SETMAXTIPWIDTH, 0, TNP_TOOLTIPS_DEFAULT_MAXIMUM_WIDTH); -} - -LRESULT CALLBACK PhTnpHeaderHookWndProc( - _In_ HWND hwnd, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam, - _In_ UINT_PTR uIdSubclass, - _In_ ULONG_PTR dwRefData - ) -{ - PPH_TREENEW_CONTEXT context = (PPH_TREENEW_CONTEXT)dwRefData; - - switch (uMsg) - { - case WM_DESTROY: - RemoveWindowSubclass(hwnd, PhTnpHeaderHookWndProc, uIdSubclass); - break; - case WM_MOUSEMOVE: - { - POINT point; - PPH_TREENEW_COLUMN column; - ULONG id; - - point.x = GET_X_LPARAM(lParam); - point.y = GET_Y_LPARAM(lParam); - column = PhTnpHitTestHeader(context, hwnd == context->FixedHeaderHandle, &point, NULL); - - if (column) - id = column->Id; - else - id = -1; - - if (context->TooltipColumnId != id) - { - PhTnpPopTooltip(context); - } - } - break; - case WM_NOTIFY: - { - NMHDR *header = (NMHDR *)lParam; - - switch (header->code) - { - case TTN_GETDISPINFO: - { - if (header->hwndFrom == context->TooltipsHandle) - { - NMTTDISPINFO *info = (NMTTDISPINFO *)header; - POINT point; - - PhTnpGetMessagePos(hwnd, &point); - PhTnpGetHeaderTooltipText(context, info->lParam == TNP_TOOLTIPS_FIXED_HEADER, &point, &info->lpszText); - } - } - break; - case TTN_SHOW: - { - if (header->hwndFrom == context->TooltipsHandle) - { - return PhTnpPrepareTooltipShow(context); - } - } - break; - case TTN_POP: - { - if (header->hwndFrom == context->TooltipsHandle) - { - PhTnpPrepareTooltipPop(context); - } - } - break; - } - } - break; - } - - switch (uMsg) - { - case WM_MOUSEMOVE: - case WM_LBUTTONDOWN: - case WM_LBUTTONUP: - case WM_RBUTTONDOWN: - case WM_RBUTTONUP: - case WM_MBUTTONDOWN: - case WM_MBUTTONUP: - { - if (context->TooltipsHandle) - { - MSG message; - - message.hwnd = hwnd; - message.message = uMsg; - message.wParam = wParam; - message.lParam = lParam; - SendMessage(context->TooltipsHandle, TTM_RELAYEVENT, 0, (LPARAM)&message); - } - } - break; - } - - return DefSubclassProc(hwnd, uMsg, wParam, lParam); -} - -BOOLEAN PhTnpDetectDrag( - _In_ PPH_TREENEW_CONTEXT Context, - _In_ LONG CursorX, - _In_ LONG CursorY, - _In_ BOOLEAN DispatchMessages, - _Out_opt_ PULONG CancelledByMessage - ) -{ - RECT dragRect; - MSG msg; - - // Capture mouse input and see if the user moves the mouse beyond the drag rectangle. - - dragRect.left = CursorX - Context->SystemDragX; - dragRect.top = CursorY - Context->SystemDragY; - dragRect.right = CursorX + Context->SystemDragX; - dragRect.bottom = CursorY + Context->SystemDragY; - MapWindowPoints(Context->Handle, NULL, (POINT *)&dragRect, 2); - - SetCapture(Context->Handle); - - if (CancelledByMessage) - *CancelledByMessage = 0; - - do - { - // It seems that GetMessage dispatches nonqueued messages directly from kernel-mode, so we - // have to use PeekMessage and WaitMessage in order to process WM_CAPTURECHANGED messages. - if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) - { - switch (msg.message) - { - case WM_LBUTTONDOWN: - case WM_LBUTTONUP: - case WM_RBUTTONDOWN: - case WM_RBUTTONUP: - ReleaseCapture(); - - if (CancelledByMessage) - *CancelledByMessage = msg.message; - - break; - case WM_MOUSEMOVE: - if (msg.pt.x < dragRect.left || msg.pt.x >= dragRect.right || - msg.pt.y < dragRect.top || msg.pt.y >= dragRect.bottom) - { - if (IsWindow(Context->Handle)) - return TRUE; - else - return FALSE; - } - break; - default: - if (DispatchMessages) - { - TranslateMessage(&msg); - DispatchMessage(&msg); - } - break; - } - } - else - { - WaitMessage(); - } - } while (IsWindow(Context->Handle) && GetCapture() == Context->Handle); - - return FALSE; -} - -VOID PhTnpDragSelect( - _In_ PPH_TREENEW_CONTEXT Context, - _In_ LONG CursorX, - _In_ LONG CursorY - ) -{ - MSG msg; - LONG cursorX; - LONG cursorY; - BOOLEAN originFixed; - RECT dragRect; - RECT oldDragRect; - RECT windowRect; - POINT cursorPoint; - BOOLEAN showContextMenu; - - cursorX = CursorX; - cursorY = CursorY; - originFixed = cursorX < Context->FixedWidth; - - dragRect.left = cursorX; - dragRect.top = cursorY; - dragRect.right = cursorX; - dragRect.bottom = cursorY; - oldDragRect = dragRect; - Context->DragRect = dragRect; - Context->DragSelectionActive = TRUE; - - if (Context->DoubleBuffered) - Context->SelectionRectangleAlpha = TRUE; - // TODO: Make sure the monitor's color depth is sufficient for alpha-blended selection - // rectangles. - - GetWindowRect(Context->Handle, &windowRect); - - cursorPoint.x = windowRect.left + cursorX; - cursorPoint.y = windowRect.top + cursorY; - - showContextMenu = FALSE; - - SetCapture(Context->Handle); - - while (TRUE) - { - if (!PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) - { - BOOLEAN leftOrRight; - BOOLEAN aboveOrBelow; - - // If the cursor is outside of the window, generate some messages so the window keeps - // scrolling. - - leftOrRight = cursorPoint.x < windowRect.left || cursorPoint.x > windowRect.right; - aboveOrBelow = cursorPoint.y < windowRect.top || cursorPoint.y > windowRect.bottom; - - if ((Context->VScrollVisible && aboveOrBelow && PhTnpCanScroll(Context, FALSE, cursorPoint.y > windowRect.bottom)) || - (Context->HScrollVisible && leftOrRight && PhTnpCanScroll(Context, TRUE, cursorPoint.x > windowRect.right))) - { - SetCursorPos(cursorPoint.x, cursorPoint.y); - } - else - { - WaitMessage(); - } - - goto EndOfLoop; - } - - cursorPoint = msg.pt; - - switch (msg.message) - { - case WM_LBUTTONDOWN: - case WM_LBUTTONUP: - case WM_RBUTTONDOWN: - case WM_MBUTTONDOWN: - case WM_MBUTTONUP: - ReleaseCapture(); - goto EndOfLoop; - case WM_RBUTTONUP: - ReleaseCapture(); - showContextMenu = TRUE; - goto EndOfLoop; - case WM_MOUSEMOVE: - { - LONG newCursorX; - LONG newCursorY; - LONG deltaRows; - LONG deltaX; - LONG oldVScrollPosition; - LONG oldHScrollPosition; - LONG newDeltaX; - LONG newDeltaY; - LONG viewLeft; - LONG viewTop; - LONG viewRight; - LONG viewBottom; - LONG temp; - RECT totalRect; - - newCursorX = GET_X_LPARAM(msg.lParam); - newCursorY = GET_Y_LPARAM(msg.lParam); - - // Scroll the window if the cursor is outside of it. - - deltaRows = 0; - deltaX = 0; - - if (Context->VScrollVisible) - { - if (cursorPoint.y < windowRect.top) - deltaRows = -(windowRect.top - cursorPoint.y + Context->RowHeight - 1) / Context->RowHeight; // scroll up - else if (cursorPoint.y >= windowRect.bottom) - deltaRows = (cursorPoint.y - windowRect.bottom + Context->RowHeight - 1) / Context->RowHeight; // scroll down - } - - if (Context->HScrollVisible) - { - if (cursorPoint.x < windowRect.left) - deltaX = -(windowRect.left - cursorPoint.x); // scroll left - else if (cursorPoint.x >= windowRect.right) - deltaX = cursorPoint.x - windowRect.right; // scroll right - } - - oldVScrollPosition = Context->VScrollPosition; - oldHScrollPosition = Context->HScrollPosition; - - if (deltaRows != 0 || deltaX != 0) - PhTnpScroll(Context, deltaRows, deltaX); - - newDeltaX = oldHScrollPosition - Context->HScrollPosition; - newDeltaY = (oldVScrollPosition - Context->VScrollPosition) * Context->RowHeight; - - // Adjust our original drag point for the scrolling. - if (!originFixed) - cursorX += newDeltaX; - cursorY += newDeltaY; - - // Adjust the old drag rectangle for the scrolling. - if (!originFixed) - oldDragRect.left += newDeltaX; - oldDragRect.top += newDeltaY; - if (!originFixed) - oldDragRect.right += newDeltaX; - oldDragRect.bottom += newDeltaY; - - // Ensure that the new cursor position is within the content area. - - viewLeft = Context->FixedColumnVisible ? 0 : -Context->HScrollPosition; - viewTop = Context->HeaderHeight - Context->VScrollPosition; - viewRight = Context->NormalLeft + Context->TotalViewX - Context->HScrollPosition; - viewBottom = Context->HeaderHeight + ((LONG)Context->FlatList->Count - Context->VScrollPosition) * Context->RowHeight; - - temp = Context->ClientRect.right - (Context->VScrollVisible ? Context->VScrollWidth : 0); - viewRight = max(viewRight, temp); - temp = Context->ClientRect.bottom - ((!Context->FixedColumnVisible && Context->HScrollVisible) ? Context->HScrollHeight : 0); - viewBottom = max(viewBottom, temp); - - if (newCursorX < viewLeft) - newCursorX = viewLeft; - if (newCursorX > viewRight) - newCursorX = viewRight; - if (newCursorY < viewTop) - newCursorY = viewTop; - if (newCursorY > viewBottom) - newCursorY = viewBottom; - - // Create the new drag rectangle. - - if (cursorX < newCursorX) - { - dragRect.left = cursorX; - dragRect.right = newCursorX; - } - else - { - dragRect.left = newCursorX; - dragRect.right = cursorX; - } - - if (cursorY < newCursorY) - { - dragRect.top = cursorY; - dragRect.bottom = newCursorY; - } - else - { - dragRect.top = newCursorY; - dragRect.bottom = cursorY; - } - - // Has anything changed from before? - if (dragRect.left == oldDragRect.left && dragRect.top == oldDragRect.top && - dragRect.right == oldDragRect.right && dragRect.bottom == oldDragRect.bottom) - { - break; - } - - Context->DragRect = dragRect; - - // Process the selection. - totalRect.left = min(dragRect.left, oldDragRect.left); - totalRect.top = min(dragRect.top, oldDragRect.top); - totalRect.right = max(dragRect.right, oldDragRect.right); - totalRect.bottom = max(dragRect.bottom, oldDragRect.bottom); - PhTnpProcessDragSelect(Context, (ULONG)msg.wParam, &oldDragRect, &dragRect, &totalRect); - - // Redraw the drag rectangle. - RedrawWindow(Context->Handle, &totalRect, NULL, RDW_INVALIDATE | RDW_UPDATENOW); - - oldDragRect = dragRect; - } - break; - case WM_MOUSELEAVE: - break; // don't process - case WM_MOUSEWHEEL: - break; // don't process - case WM_KEYDOWN: - if (msg.wParam == VK_ESCAPE) - { - ULONG changedStart; - ULONG changedEnd; - RECT rect; - - PhTnpSelectRange(Context, -1, -1, TN_SELECT_RESET, &changedStart, &changedEnd); - - if (PhTnpGetRowRects(Context, changedStart, changedEnd, TRUE, &rect)) - { - InvalidateRect(Context->Handle, &rect, FALSE); - } - - ReleaseCapture(); - } - break; // don't process - case WM_CHAR: - break; // don't process - default: - TranslateMessage(&msg); - DispatchMessage(&msg); - break; - } - -EndOfLoop: - if (GetCapture() != Context->Handle) - break; - } - - Context->DragSelectionActive = FALSE; - RedrawWindow(Context->Handle, &dragRect, NULL, RDW_INVALIDATE | RDW_UPDATENOW); - - if (showContextMenu) - { - // Display a context menu at the original drag point. - SendMessage(Context->Handle, WM_CONTEXTMENU, (WPARAM)Context->Handle, MAKELPARAM(windowRect.left + CursorX, windowRect.top + CursorY)); - } -} - -VOID PhTnpProcessDragSelect( - _In_ PPH_TREENEW_CONTEXT Context, - _In_ ULONG VirtualKeys, - _In_ PRECT OldRect, - _In_ PRECT NewRect, - _In_ PRECT TotalRect - ) -{ - LONG firstRow; - LONG lastRow; - RECT rowRect; - LONG i; - PPH_TREENEW_NODE node; - LONG changedStart; - LONG changedEnd; - RECT rect; - - // Determine which rows we need to test. The divisions below must be done on positive integers - // to ensure correct rounding. - - firstRow = (TotalRect->top - Context->HeaderHeight + Context->VScrollPosition * Context->RowHeight) / Context->RowHeight; - lastRow = (TotalRect->bottom - 1 - Context->HeaderHeight + Context->VScrollPosition * Context->RowHeight) / Context->RowHeight; - - if (firstRow < 0) - firstRow = 0; - if (lastRow >= (LONG)Context->FlatList->Count) - lastRow = Context->FlatList->Count - 1; - - rowRect.left = 0; - rowRect.top = Context->HeaderHeight + (firstRow - Context->VScrollPosition) * Context->RowHeight; - rowRect.right = Context->NormalLeft + Context->TotalViewX - Context->HScrollPosition; - rowRect.bottom = rowRect.top + Context->RowHeight; - - changedStart = lastRow; - changedEnd = firstRow; - - // Process the rows. - for (i = firstRow; i <= lastRow; i++) - { - BOOLEAN inOldRect; - BOOLEAN inNewRect; - - node = Context->FlatList->Items[i]; - - inOldRect = rowRect.top < OldRect->bottom && rowRect.bottom > OldRect->top && - rowRect.left < OldRect->right && rowRect.right > OldRect->left; - inNewRect = rowRect.top < NewRect->bottom && rowRect.bottom > NewRect->top && - rowRect.left < NewRect->right && rowRect.right > NewRect->left; - - if (VirtualKeys & MK_CONTROL) - { - if (!node->Unselectable && inOldRect != inNewRect) - { - node->Selected = !node->Selected; - - if (changedStart > i) - changedStart = i; - if (changedEnd < i) - changedEnd = i; - } - } - else - { - if (!node->Unselectable && inOldRect != inNewRect) - { - node->Selected = inNewRect; - - if (changedStart > i) - changedStart = i; - if (changedEnd < i) - changedEnd = i; - } - } - - rowRect.top = rowRect.bottom; - rowRect.bottom += Context->RowHeight; - } - - if (changedStart <= changedEnd) - { - Context->Callback(Context->Handle, TreeNewSelectionChanged, NULL, NULL, Context->CallbackContext); - } - - if (PhTnpGetRowRects(Context, changedStart, changedEnd, TRUE, &rect)) - { - InvalidateRect(Context->Handle, &rect, FALSE); - } -} - -VOID PhTnpCreateBufferedContext( - _In_ PPH_TREENEW_CONTEXT Context - ) -{ - HDC hdc; - - if (hdc = GetDC(Context->Handle)) - { - Context->BufferedContext = CreateCompatibleDC(hdc); - - if (!Context->BufferedContext) - return; - - Context->BufferedContextRect = Context->ClientRect; - Context->BufferedBitmap = CreateCompatibleBitmap( - hdc, - Context->BufferedContextRect.right + 1, // leave one extra pixel for divider animation - Context->BufferedContextRect.bottom - ); - - if (!Context->BufferedBitmap) - { - DeleteDC(Context->BufferedContext); - Context->BufferedContext = NULL; - return; - } - - ReleaseDC(Context->Handle, hdc); - Context->BufferedOldBitmap = SelectObject(Context->BufferedContext, Context->BufferedBitmap); - } -} - -VOID PhTnpDestroyBufferedContext( - _In_ PPH_TREENEW_CONTEXT Context - ) -{ - // The original bitmap must be selected back into the context, otherwise the bitmap can't be - // deleted. - SelectObject(Context->BufferedContext, Context->BufferedOldBitmap); - DeleteObject(Context->BufferedBitmap); - DeleteDC(Context->BufferedContext); - - Context->BufferedContext = NULL; - Context->BufferedBitmap = NULL; -} - -VOID PhTnpGetMessagePos( - _In_ HWND hwnd, - _Out_ PPOINT ClientPoint - ) -{ - ULONG position; - POINT point; - - position = GetMessagePos(); - point.x = GET_X_LPARAM(position); - point.y = GET_Y_LPARAM(position); - ScreenToClient(hwnd, &point); - - *ClientPoint = point; -} +/* + * Process Hacker - + * tree new (tree list control) + * + * Copyright (C) 2011-2016 wj32 + * Copyright (C) 2017 dmex + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +/* + * The tree new is a tree view with columns. Unlike the old tree list control, which was a wrapper + * around the list view control, this control was written from scratch. + * + * Current issues not included in any comments: + * * Adding, removing or changing columns does not cause invalidation. + * * It is not possible to change a column to make it fixed. The current fixed column must be + * removed and the new fixed column must then be added. + * * When there are no visible normal columns, the space usually occupied by the normal column + * headers is filled with a solid background color. We should catch this and paint the usual + * themed background there instead. + * * It is not possible to update any TN_STYLE_* flags after the control is created. + * + * Possible additions: + * * More flexible mouse input callbacks to allow custom controls inside columns. + * * Allow custom drawn columns to customize their behaviour when TN_FLAG_ITEM_DRAG_SELECT is set + * (e.g. disable drag selection over certain areas). + * * Virtual mode + */ + +#include +#include + +#include +#include +#include + +#include + +#include + +static PVOID ComCtl32Handle; +static LONG SmallIconWidth; +static LONG SmallIconHeight; + +BOOLEAN PhTreeNewInitialization( + VOID + ) +{ + WNDCLASSEX c = { sizeof(c) }; + + c.style = CS_DBLCLKS | CS_GLOBALCLASS; + c.lpfnWndProc = PhTnpWndProc; + c.cbClsExtra = 0; + c.cbWndExtra = sizeof(PVOID); + c.hInstance = PhLibImageBase; + c.hIcon = NULL; + c.hCursor = LoadCursor(NULL, IDC_ARROW); + c.hbrBackground = NULL; + c.lpszMenuName = NULL; + c.lpszClassName = PH_TREENEW_CLASSNAME; + c.hIconSm = NULL; + + if (!RegisterClassEx(&c)) + return FALSE; + + ComCtl32Handle = GetModuleHandle(L"comctl32.dll"); + SmallIconWidth = GetSystemMetrics(SM_CXSMICON); + SmallIconHeight = GetSystemMetrics(SM_CYSMICON); + + return TRUE; +} + +LRESULT CALLBACK PhTnpWndProc( + _In_ HWND hwnd, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + PPH_TREENEW_CONTEXT context; + + context = (PPH_TREENEW_CONTEXT)GetWindowLongPtr(hwnd, 0); + + if (uMsg == WM_CREATE) + { + PhTnpCreateTreeNewContext(&context); + SetWindowLongPtr(hwnd, 0, (LONG_PTR)context); + } + + if (!context) + return DefWindowProc(hwnd, uMsg, wParam, lParam); + + if (context->Tracking && (GetAsyncKeyState(VK_ESCAPE) & 0x1)) + { + PhTnpCancelTrack(context); + } + + // Note: if we have suspended restructuring, we *cannot* access any nodes, because all node + // pointers are now invalid. Below, we disable all input. + + switch (uMsg) + { + case WM_CREATE: + { + if (!PhTnpOnCreate(hwnd, context, (CREATESTRUCT *)lParam)) + return -1; + } + return 0; + case WM_NCDESTROY: + { + context->Callback(hwnd, TreeNewDestroying, NULL, NULL, context->CallbackContext); + PhTnpDestroyTreeNewContext(context); + SetWindowLongPtr(hwnd, 0, (LONG_PTR)NULL); + } + return 0; + case WM_SIZE: + { + PhTnpOnSize(hwnd, context); + } + break; + case WM_ERASEBKGND: + return TRUE; + case WM_PAINT: + { + PhTnpOnPaint(hwnd, context); + } + return 0; + case WM_PRINTCLIENT: + { + if (!context->SuspendUpdateStructure) + PhTnpOnPrintClient(hwnd, context, (HDC)wParam, (ULONG)lParam); + } + return 0; + case WM_NCPAINT: + { + if (PhTnpOnNcPaint(hwnd, context, (HRGN)wParam)) + return 0; + } + break; + case WM_GETFONT: + return (LRESULT)context->Font; + case WM_SETFONT: + { + PhTnpOnSetFont(hwnd, context, (HFONT)wParam, LOWORD(lParam)); + } + break; + case WM_STYLECHANGED: + { + PhTnpOnStyleChanged(hwnd, context, (LONG)wParam, (STYLESTRUCT *)lParam); + } + break; + case WM_SETTINGCHANGE: + { + PhTnpOnSettingChange(hwnd, context); + } + break; + case WM_THEMECHANGED: + { + PhTnpOnThemeChanged(hwnd, context); + } + break; + case WM_GETDLGCODE: + return PhTnpOnGetDlgCode(hwnd, context, (ULONG)wParam, (PMSG)lParam); + case WM_SETFOCUS: + { + context->HasFocus = TRUE; + InvalidateRect(context->Handle, NULL, FALSE); + } + return 0; + case WM_KILLFOCUS: + { + context->HasFocus = FALSE; + InvalidateRect(context->Handle, NULL, FALSE); + } + return 0; + case WM_SETCURSOR: + { + if (PhTnpOnSetCursor(hwnd, context, (HWND)wParam)) + return TRUE; + } + break; + case WM_TIMER: + { + PhTnpOnTimer(hwnd, context, (ULONG)wParam); + } + return 0; + case WM_MOUSEMOVE: + { + if (!context->SuspendUpdateStructure) + PhTnpOnMouseMove(hwnd, context, (ULONG)wParam, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); + else + context->SuspendUpdateMoveMouse = TRUE; + } + break; + case WM_MOUSELEAVE: + { + if (!context->SuspendUpdateStructure) + PhTnpOnMouseLeave(hwnd, context); + } + break; + case WM_LBUTTONDOWN: + case WM_LBUTTONUP: + case WM_LBUTTONDBLCLK: + case WM_RBUTTONDOWN: + case WM_RBUTTONUP: + case WM_RBUTTONDBLCLK: + case WM_MBUTTONDOWN: + case WM_MBUTTONUP: + case WM_MBUTTONDBLCLK: + { + if (!context->SuspendUpdateStructure) + PhTnpOnXxxButtonXxx(hwnd, context, uMsg, (ULONG)wParam, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); + } + break; + case WM_CAPTURECHANGED: + { + PhTnpOnCaptureChanged(hwnd, context); + } + break; + case WM_KEYDOWN: + { + if (!context->SuspendUpdateStructure) + PhTnpOnKeyDown(hwnd, context, (ULONG)wParam, (ULONG)lParam); + } + break; + case WM_CHAR: + { + if (!context->SuspendUpdateStructure) + PhTnpOnChar(hwnd, context, (ULONG)wParam, (ULONG)lParam); + } + return 0; + case WM_MOUSEWHEEL: + { + PhTnpOnMouseWheel(hwnd, context, (SHORT)HIWORD(wParam), LOWORD(wParam), GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); + } + break; + case WM_MOUSEHWHEEL: + { + PhTnpOnMouseHWheel(hwnd, context, (SHORT)HIWORD(wParam), LOWORD(wParam), GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); + } + break; + case WM_CONTEXTMENU: + { + if (!context->SuspendUpdateStructure) + PhTnpOnContextMenu(hwnd, context, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); + } + return 0; + case WM_VSCROLL: + { + PhTnpOnVScroll(hwnd, context, LOWORD(wParam), HIWORD(wParam)); + } + return 0; + case WM_HSCROLL: + { + PhTnpOnHScroll(hwnd, context, LOWORD(wParam), HIWORD(wParam)); + } + return 0; + case WM_NOTIFY: + { + LRESULT result; + + if (PhTnpOnNotify(hwnd, context, (NMHDR *)lParam, &result)) + return result; + } + break; + } + + if (uMsg >= TNM_FIRST && uMsg <= TNM_LAST) + { + return PhTnpOnUserMessage(hwnd, context, uMsg, wParam, lParam); + } + + switch (uMsg) + { + case WM_MOUSEMOVE: + case WM_LBUTTONDOWN: + case WM_LBUTTONUP: + case WM_RBUTTONDOWN: + case WM_RBUTTONUP: + case WM_MBUTTONDOWN: + case WM_MBUTTONUP: + { + if (context->TooltipsHandle) + { + MSG message; + + message.hwnd = hwnd; + message.message = uMsg; + message.wParam = wParam; + message.lParam = lParam; + SendMessage(context->TooltipsHandle, TTM_RELAYEVENT, 0, (LPARAM)&message); + } + } + break; + } + + return DefWindowProc(hwnd, uMsg, wParam, lParam); +} + +BOOLEAN NTAPI PhTnpNullCallback( + _In_ HWND hwnd, + _In_ PH_TREENEW_MESSAGE Message, + _In_opt_ PVOID Parameter1, + _In_opt_ PVOID Parameter2, + _In_opt_ PVOID Context + ) +{ + return FALSE; +} + +VOID PhTnpCreateTreeNewContext( + _Out_ PPH_TREENEW_CONTEXT *Context + ) +{ + PPH_TREENEW_CONTEXT context; + + context = PhAllocate(sizeof(PH_TREENEW_CONTEXT)); + memset(context, 0, sizeof(PH_TREENEW_CONTEXT)); + + context->FixedWidthMinimum = 20; + context->RowHeight = 1; // must never be 0 + context->HotNodeIndex = -1; + context->Callback = PhTnpNullCallback; + context->FlatList = PhCreateList(64); + context->TooltipIndex = -1; + context->TooltipId = -1; + context->TooltipColumnId = -1; + context->EnableRedraw = 1; + + *Context = context; +} + +VOID PhTnpDestroyTreeNewContext( + _In_ PPH_TREENEW_CONTEXT Context + ) +{ + ULONG i; + + if (Context->Columns) + { + for (i = 0; i < Context->NextId; i++) + { + if (Context->Columns[i]) + PhFree(Context->Columns[i]); + } + + PhFree(Context->Columns); + } + + if (Context->ColumnsByDisplay) + PhFree(Context->ColumnsByDisplay); + + PhDereferenceObject(Context->FlatList); + + if (Context->FontOwned) + DeleteObject(Context->Font); + + if (Context->ThemeData) + CloseThemeData(Context->ThemeData); + + if (Context->SearchString) + PhFree(Context->SearchString); + + if (Context->TooltipText) + PhDereferenceObject(Context->TooltipText); + + if (Context->BufferedContext) + PhTnpDestroyBufferedContext(Context); + + if (Context->SuspendUpdateRegion) + DeleteObject(Context->SuspendUpdateRegion); + + PhFree(Context); +} + +BOOLEAN PhTnpOnCreate( + _In_ HWND hwnd, + _In_ PPH_TREENEW_CONTEXT Context, + _In_ CREATESTRUCT *CreateStruct + ) +{ + ULONG headerStyle; + + Context->Handle = hwnd; + Context->InstanceHandle = CreateStruct->hInstance; + Context->Style = CreateStruct->style; + Context->ExtendedStyle = CreateStruct->dwExStyle; + + if (Context->Style & TN_STYLE_DOUBLE_BUFFERED) + Context->DoubleBuffered = TRUE; + if ((Context->Style & TN_STYLE_ANIMATE_DIVIDER) && Context->DoubleBuffered) + Context->AnimateDivider = TRUE; + + headerStyle = HDS_HORZ | HDS_FULLDRAG; + + if (!(Context->Style & TN_STYLE_NO_COLUMN_SORT)) + headerStyle |= HDS_BUTTONS; + if (!(Context->Style & TN_STYLE_NO_COLUMN_HEADER)) + headerStyle |= WS_VISIBLE; + + if (!(Context->FixedHeaderHandle = CreateWindow( + WC_HEADER, + NULL, + WS_CHILD | WS_CLIPSIBLINGS | headerStyle, + 0, + 0, + 0, + 0, + hwnd, + NULL, + CreateStruct->hInstance, + NULL + ))) + { + return FALSE; + } + + if (!(Context->Style & TN_STYLE_NO_COLUMN_REORDER)) + headerStyle |= HDS_DRAGDROP; + + if (!(Context->HeaderHandle = CreateWindow( + WC_HEADER, + NULL, + WS_CHILD | WS_CLIPSIBLINGS | headerStyle, + 0, + 0, + 0, + 0, + hwnd, + NULL, + CreateStruct->hInstance, + NULL + ))) + { + return FALSE; + } + + if (!(Context->VScrollHandle = CreateWindow( + L"SCROLLBAR", + NULL, + WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | SBS_VERT, + 0, + 0, + 0, + 0, + hwnd, + NULL, + CreateStruct->hInstance, + NULL + ))) + { + return FALSE; + } + + if (!(Context->HScrollHandle = CreateWindow( + L"SCROLLBAR", + NULL, + WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | SBS_HORZ, + 0, + 0, + 0, + 0, + hwnd, + NULL, + CreateStruct->hInstance, + NULL + ))) + { + return FALSE; + } + + if (!(Context->FillerBoxHandle = CreateWindow( + L"STATIC", + NULL, + WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE, + 0, + 0, + 0, + 0, + hwnd, + NULL, + CreateStruct->hInstance, + NULL + ))) + { + return FALSE; + } + + PhTnpSetFont(Context, NULL, FALSE); // use default font + PhTnpUpdateSystemMetrics(Context); + PhTnpInitializeTooltips(Context); + + return TRUE; +} + +VOID PhTnpOnSize( + _In_ HWND hwnd, + _In_ PPH_TREENEW_CONTEXT Context + ) +{ + GetClientRect(hwnd, &Context->ClientRect); + + if (Context->BufferedContext && ( + Context->BufferedContextRect.right < Context->ClientRect.right || + Context->BufferedContextRect.bottom < Context->ClientRect.bottom)) + { + // Invalidate the buffered context because the client size has increased. + PhTnpDestroyBufferedContext(Context); + } + + PhTnpLayout(Context); + + if (Context->TooltipsHandle) + { + TOOLINFO toolInfo; + + memset(&toolInfo, 0, sizeof(TOOLINFO)); + toolInfo.cbSize = sizeof(TOOLINFO); + toolInfo.hwnd = hwnd; + toolInfo.uId = TNP_TOOLTIPS_ITEM; + toolInfo.rect = Context->ClientRect; + SendMessage(Context->TooltipsHandle, TTM_NEWTOOLRECT, 0, (LPARAM)&toolInfo); + } +} + +VOID PhTnpOnSetFont( + _In_ HWND hwnd, + _In_ PPH_TREENEW_CONTEXT Context, + _In_opt_ HFONT Font, + _In_ LOGICAL Redraw + ) +{ + PhTnpSetFont(Context, Font, !!Redraw); + PhTnpLayout(Context); +} + +VOID PhTnpOnStyleChanged( + _In_ HWND hwnd, + _In_ PPH_TREENEW_CONTEXT Context, + _In_ LONG Type, + _In_ STYLESTRUCT *StyleStruct + ) +{ + if (Type == GWL_EXSTYLE) + Context->ExtendedStyle = StyleStruct->styleNew; +} + +VOID PhTnpOnSettingChange( + _In_ HWND hwnd, + _In_ PPH_TREENEW_CONTEXT Context + ) +{ + PhTnpUpdateSystemMetrics(Context); + PhTnpUpdateTextMetrics(Context); + PhTnpLayout(Context); +} + +VOID PhTnpOnThemeChanged( + _In_ HWND hwnd, + _In_ PPH_TREENEW_CONTEXT Context + ) +{ + PhTnpUpdateThemeData(Context); +} + +ULONG PhTnpOnGetDlgCode( + _In_ HWND hwnd, + _In_ PPH_TREENEW_CONTEXT Context, + _In_ ULONG VirtualKey, + _In_opt_ PMSG Message + ) +{ + ULONG code; + + if (Context->Callback(hwnd, TreeNewGetDialogCode, UlongToPtr(VirtualKey), &code, Context->CallbackContext)) + { + return code; + } + + return DLGC_WANTARROWS | DLGC_WANTCHARS; +} + +VOID PhTnpOnPaint( + _In_ HWND hwnd, + _In_ PPH_TREENEW_CONTEXT Context + ) +{ + RECT updateRect; + HDC hdc; + PAINTSTRUCT paintStruct; + + if (GetUpdateRect(hwnd, &updateRect, FALSE) && (updateRect.left | updateRect.right | updateRect.top | updateRect.bottom)) + { + if (Context->EnableRedraw <= 0) + { + HRGN updateRegion; + + updateRegion = CreateRectRgn(0, 0, 0, 0); + GetUpdateRgn(hwnd, updateRegion, FALSE); + + if (!Context->SuspendUpdateRegion) + { + Context->SuspendUpdateRegion = updateRegion; + } + else + { + CombineRgn(Context->SuspendUpdateRegion, Context->SuspendUpdateRegion, updateRegion, RGN_OR); + DeleteObject(updateRegion); + } + + // Pretend we painted something; this ensures the update region is validated properly. + if (BeginPaint(hwnd, &paintStruct)) + EndPaint(hwnd, &paintStruct); + + return; + } + + if (Context->DoubleBuffered) + { + if (!Context->BufferedContext) + { + PhTnpCreateBufferedContext(Context); + } + } + + if (hdc = BeginPaint(hwnd, &paintStruct)) + { + updateRect = paintStruct.rcPaint; + + if (Context->BufferedContext) + { + PhTnpPaint(hwnd, Context, Context->BufferedContext, &updateRect); + BitBlt( + hdc, + updateRect.left, + updateRect.top, + updateRect.right - updateRect.left, + updateRect.bottom - updateRect.top, + Context->BufferedContext, + updateRect.left, + updateRect.top, + SRCCOPY + ); + } + else + { + PhTnpPaint(hwnd, Context, hdc, &updateRect); + } + + EndPaint(hwnd, &paintStruct); + } + } +} + +VOID PhTnpOnPrintClient( + _In_ HWND hwnd, + _In_ PPH_TREENEW_CONTEXT Context, + _In_ HDC hdc, + _In_ ULONG Flags + ) +{ + PhTnpPaint(hwnd, Context, hdc, &Context->ClientRect); +} + +BOOLEAN PhTnpOnNcPaint( + _In_ HWND hwnd, + _In_ PPH_TREENEW_CONTEXT Context, + _In_opt_ HRGN UpdateRegion + ) +{ + PhTnpInitializeThemeData(Context); + + // Themed border + if ((Context->ExtendedStyle & WS_EX_CLIENTEDGE) && Context->ThemeData) + { + HDC hdc; + ULONG flags; + + if (UpdateRegion == HRGN_FULL) + UpdateRegion = NULL; + + // Note the use of undocumented flags below. GetDCEx doesn't work without these. + + flags = DCX_WINDOW | DCX_LOCKWINDOWUPDATE | 0x10000; + + if (UpdateRegion) + flags |= DCX_INTERSECTRGN | 0x40000; + + if (hdc = GetDCEx(hwnd, UpdateRegion, flags)) + { + PhTnpDrawThemedBorder(Context, hdc); + ReleaseDC(hwnd, hdc); + return TRUE; + } + } + + return FALSE; +} + +BOOLEAN PhTnpOnSetCursor( + _In_ HWND hwnd, + _In_ PPH_TREENEW_CONTEXT Context, + _In_ HWND CursorWindowHandle + ) +{ + POINT point; + + PhTnpGetMessagePos(hwnd, &point); + + if (TNP_HIT_TEST_FIXED_DIVIDER(point.x, Context)) + { + if (!Context->DividerCursor) + Context->DividerCursor = LoadCursor(ComCtl32Handle, MAKEINTRESOURCE(106)); // HACK (the divider icon resource has been 106 for quite a while...) + + SetCursor(Context->DividerCursor); + return TRUE; + } + + if (Context->Cursor) + { + SetCursor(Context->Cursor); + return TRUE; + } + + return FALSE; +} + +VOID PhTnpOnTimer( + _In_ HWND hwnd, + _In_ PPH_TREENEW_CONTEXT Context, + _In_ ULONG Id + ) +{ + if (Id == TNP_TIMER_ANIMATE_DIVIDER) + { + RECT dividerRect; + + dividerRect.left = Context->FixedWidth; + dividerRect.top = Context->HeaderHeight; + dividerRect.right = Context->FixedWidth + 1; + dividerRect.bottom = Context->ClientRect.bottom; + + if (Context->AnimateDividerFadingIn) + { + Context->DividerHot += TNP_ANIMATE_DIVIDER_INCREMENT; + + if (Context->DividerHot >= 100) + { + Context->DividerHot = 100; + Context->AnimateDividerFadingIn = FALSE; + KillTimer(hwnd, TNP_TIMER_ANIMATE_DIVIDER); + } + + InvalidateRect(hwnd, ÷rRect, FALSE); + } + else if (Context->AnimateDividerFadingOut) + { + if (Context->DividerHot <= TNP_ANIMATE_DIVIDER_DECREMENT) + { + Context->DividerHot = 0; + Context->AnimateDividerFadingOut = FALSE; + KillTimer(hwnd, TNP_TIMER_ANIMATE_DIVIDER); + } + else + { + Context->DividerHot -= TNP_ANIMATE_DIVIDER_DECREMENT; + } + + InvalidateRect(hwnd, ÷rRect, FALSE); + } + } +} + +VOID PhTnpOnMouseMove( + _In_ HWND hwnd, + _In_ PPH_TREENEW_CONTEXT Context, + _In_ ULONG VirtualKeys, + _In_ LONG CursorX, + _In_ LONG CursorY + ) +{ + TRACKMOUSEEVENT trackMouseEvent; + + trackMouseEvent.cbSize = sizeof(TRACKMOUSEEVENT); + trackMouseEvent.dwFlags = TME_LEAVE; + trackMouseEvent.hwndTrack = hwnd; + trackMouseEvent.dwHoverTime = 0; + TrackMouseEvent(&trackMouseEvent); + + if (Context->Tracking) + { + ULONG newFixedWidth; + + newFixedWidth = Context->TrackOldFixedWidth + (CursorX - Context->TrackStartX); + PhTnpSetFixedWidth(Context, newFixedWidth); + } + + PhTnpProcessMoveMouse(Context, CursorX, CursorY); +} + +VOID PhTnpOnMouseLeave( + _In_ HWND hwnd, + _In_ PPH_TREENEW_CONTEXT Context + ) +{ + RECT rect; + + if (Context->HotNodeIndex != -1 && Context->ThemeData) + { + // Update the old hot node because it may have a different non-hot background and plus minus part. + if (PhTnpGetRowRects(Context, Context->HotNodeIndex, Context->HotNodeIndex, TRUE, &rect)) + { + InvalidateRect(Context->Handle, &rect, FALSE); + } + } + + Context->HotNodeIndex = -1; + + if (Context->AnimateDivider && Context->FixedDividerVisible) + { + if ((Context->DividerHot != 0 || Context->AnimateDividerFadingIn) && !Context->AnimateDividerFadingOut) + { + // Fade out the divider. + Context->AnimateDividerFadingOut = TRUE; + Context->AnimateDividerFadingIn = FALSE; + SetTimer(Context->Handle, TNP_TIMER_ANIMATE_DIVIDER, TNP_ANIMATE_DIVIDER_INTERVAL, NULL); + } + } +} + +VOID PhTnpOnXxxButtonXxx( + _In_ HWND hwnd, + _In_ PPH_TREENEW_CONTEXT Context, + _In_ ULONG Message, + _In_ ULONG VirtualKeys, + _In_ LONG CursorX, + _In_ LONG CursorY + ) +{ + BOOLEAN startingTracking; + PH_TREENEW_HIT_TEST hitTest; + LOGICAL controlKey; + LOGICAL shiftKey; + RECT rect; + ULONG changedStart; + ULONG changedEnd; + PH_TREENEW_MESSAGE clickMessage; + + // Focus + + if (Message == WM_LBUTTONDOWN || Message == WM_RBUTTONDOWN) + SetFocus(hwnd); + + // Divider tracking + + startingTracking = FALSE; + + switch (Message) + { + case WM_LBUTTONDOWN: + { + if (TNP_HIT_TEST_FIXED_DIVIDER(CursorX, Context)) + { + startingTracking = TRUE; + Context->Tracking = TRUE; + Context->TrackStartX = CursorX; + Context->TrackOldFixedWidth = Context->FixedWidth; + SetCapture(hwnd); + + SetTimer(hwnd, TNP_TIMER_NULL, 100, NULL); // make sure we get messages once in a while so we can detect the escape key + GetAsyncKeyState(VK_ESCAPE); + } + } + break; + case WM_LBUTTONUP: + { + if (Context->Tracking) + { + ReleaseCapture(); + } + } + break; + case WM_RBUTTONDOWN: + { + if (Context->Tracking) + { + PhTnpCancelTrack(Context); + } + } + break; + } + + if (!startingTracking && Context->Tracking) // still OK to process further if the user is only starting to drag the divider + return; + + hitTest.Point.x = CursorX; + hitTest.Point.y = CursorY; + hitTest.InFlags = TN_TEST_COLUMN | TN_TEST_SUBITEM; + PhTnpHitTest(Context, &hitTest); + + controlKey = VirtualKeys & MK_CONTROL; + shiftKey = VirtualKeys & MK_SHIFT; + + // Plus minus glyph + + if ((hitTest.Flags & TN_HIT_ITEM_PLUSMINUS) && Message == WM_LBUTTONDOWN) + { + PhTnpSetExpandedNode(Context, hitTest.Node, !hitTest.Node->Expanded); + } + + // Selection + + if (!(hitTest.Flags & TN_HIT_ITEM_PLUSMINUS) && (Message == WM_LBUTTONDOWN || Message == WM_RBUTTONDOWN)) + { + LOGICAL allowDragSelect; + PH_TREENEW_CELL_PARTS parts; + + PhTnpPopTooltip(Context); + allowDragSelect = TRUE; + + if (hitTest.Flags & TN_HIT_ITEM) + { + allowDragSelect = FALSE; + Context->FocusNode = hitTest.Node; + + if (Context->ExtendedFlags & TN_FLAG_ITEM_DRAG_SELECT) + { + // To allow drag selection to begin even if the cursor is on an item, we check if + // the cursor is on the item icon or text. Exceptions are: + // * When the item is already selected + // * When user is beginning to drag the divider + + if (!hitTest.Node->Selected && !startingTracking) + { + if (PhTnpGetCellParts(Context, hitTest.Node->Index, hitTest.Column, TN_MEASURE_TEXT, &parts)) + { + allowDragSelect = TRUE; + + if ((parts.Flags & TN_PART_ICON) && CursorX >= parts.IconRect.left && CursorX < parts.IconRect.right) + allowDragSelect = FALSE; + + if ((parts.Flags & TN_PART_CONTENT) && (parts.Flags & TN_PART_TEXT)) + { + if (CursorX >= parts.TextRect.left && CursorX < parts.TextRect.right) + allowDragSelect = FALSE; + } + } + } + } + + PhTnpProcessSelectNode(Context, hitTest.Node, controlKey, shiftKey, Message == WM_RBUTTONDOWN); + } + + if (allowDragSelect) + { + BOOLEAN dragSelect; + ULONG indexToSelect; + BOOLEAN selectionProcessed; + BOOLEAN showContextMenu; + + dragSelect = FALSE; + indexToSelect = -1; + selectionProcessed = FALSE; + showContextMenu = FALSE; + + if (!(hitTest.Flags & (TN_HIT_LEFT | TN_HIT_RIGHT | TN_HIT_ABOVE | TN_HIT_BELOW)) && !startingTracking) // don't interfere with divider + { + BOOLEAN result; + ULONG saveIndex; + ULONG saveId; + ULONG cancelledByMessage; + + // Check for drag selection. PhTnpDetectDrag has its own message loop, so we need to + // clear our pointers before we continue or we will have some access violations when + // items get deleted. + + if (hitTest.Node) + saveIndex = hitTest.Node->Index; + else + saveIndex = -1; + + if (hitTest.Column) + saveId = hitTest.Column->Id; + else + saveId = -1; + + result = PhTnpDetectDrag(Context, CursorX, CursorY, TRUE, &cancelledByMessage); + + // Restore the pointers. + + if (saveIndex == -1) + hitTest.Node = NULL; + else if (saveIndex < Context->FlatList->Count) + hitTest.Node = Context->FlatList->Items[saveIndex]; + else + return; + + if (saveId != -1 && !(hitTest.Column = PhTnpLookupColumnById(Context, saveId))) + return; + + if (result) + { + dragSelect = TRUE; + + if ((hitTest.Flags & TN_HIT_ITEM) && (Context->ExtendedFlags & TN_FLAG_ITEM_DRAG_SELECT)) + { + // Include the current node before starting the drag selection, otherwise + // the user will never be able to select the current node. + indexToSelect = hitTest.Node->Index; + } + } + else + { + if ((Message == WM_LBUTTONDOWN && cancelledByMessage == WM_LBUTTONUP) || + (Message == WM_RBUTTONDOWN && cancelledByMessage == WM_RBUTTONUP)) + { + POINT point; + + if ((hitTest.Flags & TN_HIT_ITEM) && (Context->ExtendedFlags & TN_FLAG_ITEM_DRAG_SELECT)) + { + // The user isn't performing a drag selection, so prevent deselection. + selectionProcessed = TRUE; + } + + // The button up message gets consumed by PhTnpDetectDrag, so send the mouse + // event here. + // Check if the cursor stayed in the same place. + + PhTnpGetMessagePos(Context->Handle, &point); + + if (point.x == CursorX && point.y == CursorY) + { + PhTnpSendMouseEvent( + Context, + Message == WM_LBUTTONDOWN ? TreeNewLeftClick : TreeNewRightClick, + CursorX, + CursorY, + hitTest.Node, + hitTest.Column, + VirtualKeys + ); + } + + if (Message == WM_RBUTTONDOWN) + showContextMenu = TRUE; + } + } + } + + if (!selectionProcessed && !controlKey && !shiftKey) + { + // Nothing: deselect everything. + + PhTnpSelectRange(Context, indexToSelect, indexToSelect, TN_SELECT_RESET, &changedStart, &changedEnd); + + if (PhTnpGetRowRects(Context, changedStart, changedEnd, TRUE, &rect)) + { + InvalidateRect(hwnd, &rect, FALSE); + } + } + + if (dragSelect) + { + PhTnpDragSelect(Context, CursorX, CursorY); + } + + if (showContextMenu) + { + SendMessage(Context->Handle, WM_CONTEXTMENU, (WPARAM)Context->Handle, GetMessagePos()); + } + + return; + } + } + + // Click, double-click + // Note: If TN_FLAG_ITEM_DRAG_SELECT is enabled, the code below that processes WM_xBUTTONDOWN + // and WM_xBUTTONUP messages only takes effect when the user clicks directly on an item's icon + // or text. + + clickMessage = -1; + + if (Message == WM_LBUTTONDOWN || Message == WM_RBUTTONDOWN) + { + if (Context->MouseDownLast != 0 && Context->MouseDownLast != Message) + { + // User pressed one button and pressed the other without letting go of the first one. + // This counts as a click. + + if (Context->MouseDownLast == WM_LBUTTONDOWN) + clickMessage = TreeNewLeftClick; + else + clickMessage = TreeNewRightClick; + } + + Context->MouseDownLast = Message; + Context->MouseDownLocation.x = CursorX; + Context->MouseDownLocation.y = CursorY; + } + else if (Message == WM_LBUTTONUP || Message == WM_RBUTTONUP) + { + if (Context->MouseDownLast != 0 && + Context->MouseDownLocation.x == CursorX && Context->MouseDownLocation.y == CursorY) + { + if (Context->MouseDownLast == WM_LBUTTONDOWN) + clickMessage = TreeNewLeftClick; + else + clickMessage = TreeNewRightClick; + } + + Context->MouseDownLast = 0; + } + else if (Message == WM_LBUTTONDBLCLK) + { + clickMessage = TreeNewLeftDoubleClick; + } + else if (Message == WM_RBUTTONDBLCLK) + { + clickMessage = TreeNewRightDoubleClick; + } + + if (!(hitTest.Flags & TN_HIT_ITEM_PLUSMINUS) && clickMessage != -1) + { + PhTnpSendMouseEvent(Context, clickMessage, CursorX, CursorY, hitTest.Node, hitTest.Column, VirtualKeys); + } +} + +VOID PhTnpOnCaptureChanged( + _In_ HWND hwnd, + _In_ PPH_TREENEW_CONTEXT Context + ) +{ + Context->Tracking = FALSE; + KillTimer(hwnd, TNP_TIMER_NULL); +} + +VOID PhTnpOnKeyDown( + _In_ HWND hwnd, + _In_ PPH_TREENEW_CONTEXT Context, + _In_ ULONG VirtualKey, + _In_ ULONG Data + ) +{ + PH_TREENEW_KEY_EVENT keyEvent; + + keyEvent.Handled = FALSE; + keyEvent.VirtualKey = VirtualKey; + keyEvent.Data = Data; + Context->Callback(Context->Handle, TreeNewKeyDown, &keyEvent, NULL, Context->CallbackContext); + + if (keyEvent.Handled) + return; + + if (PhTnpProcessFocusKey(Context, VirtualKey)) + return; + if (PhTnpProcessNodeKey(Context, VirtualKey)) + return; +} + +VOID PhTnpOnChar( + _In_ HWND hwnd, + _In_ PPH_TREENEW_CONTEXT Context, + _In_ ULONG Character, + _In_ ULONG Data + ) +{ + // Make sure the character is printable. + if (Character >= ' ' && Character <= '~') + { + PhTnpProcessSearchKey(Context, Character); + } +} + +VOID PhTnpOnMouseWheel( + _In_ HWND hwnd, + _In_ PPH_TREENEW_CONTEXT Context, + _In_ LONG Distance, + _In_ ULONG VirtualKeys, + _In_ LONG CursorX, + _In_ LONG CursorY + ) +{ + // The normal mouse wheel can affect both the vertical scrollbar and the horizontal scrollbar, + // but the vertical scrollbar takes precedence. + if (Context->VScrollVisible) + { + PhTnpProcessMouseVWheel(Context, -Distance); + } + else if (Context->HScrollVisible) + { + PhTnpProcessMouseHWheel(Context, -Distance); + } +} + +VOID PhTnpOnMouseHWheel( + _In_ HWND hwnd, + _In_ PPH_TREENEW_CONTEXT Context, + _In_ LONG Distance, + _In_ ULONG VirtualKeys, + _In_ LONG CursorX, + _In_ LONG CursorY + ) +{ + PhTnpProcessMouseHWheel(Context, Distance); +} + +VOID PhTnpOnContextMenu( + _In_ HWND hwnd, + _In_ PPH_TREENEW_CONTEXT Context, + _In_ LONG CursorScreenX, + _In_ LONG CursorScreenY + ) +{ + POINT clientPoint; + BOOLEAN keyboardInvoked; + PH_TREENEW_HIT_TEST hitTest; + PH_TREENEW_CONTEXT_MENU contextMenu; + + if (CursorScreenX == -1 && CursorScreenY == -1) + { + ULONG i; + BOOLEAN found; + RECT windowRect; + RECT rect; + + keyboardInvoked = TRUE; + + // Context menu was invoked via keyboard. Display the context menu at the selected item. + + found = FALSE; + + for (i = 0; i < Context->FlatList->Count; i++) + { + if (((PPH_TREENEW_NODE)Context->FlatList->Items[i])->Selected) + { + found = TRUE; + break; + } + } + + if (found && PhTnpGetRowRects(Context, i, i, FALSE, &rect) && + rect.top >= Context->ClientRect.top && rect.top < Context->ClientRect.bottom) + { + clientPoint.x = rect.left + SmallIconWidth / 2; + clientPoint.y = rect.top + Context->RowHeight / 2; + } + else + { + clientPoint.x = 0; + clientPoint.y = 0; + } + + GetWindowRect(hwnd, &windowRect); + CursorScreenX = windowRect.left + clientPoint.x; + CursorScreenY = windowRect.top + clientPoint.y; + } + else + { + keyboardInvoked = FALSE; + + clientPoint.x = CursorScreenX; + clientPoint.y = CursorScreenY; + ScreenToClient(hwnd, &clientPoint); + + if (clientPoint.y < Context->HeaderHeight) + { + // Already handled by TreeNewHeaderRightClick. + return; + } + } + + hitTest.Point = clientPoint; + hitTest.InFlags = TN_TEST_COLUMN; + PhTnpHitTest(Context, &hitTest); + + contextMenu.Location.x = CursorScreenX; + contextMenu.Location.y = CursorScreenY; + contextMenu.ClientLocation = clientPoint; + contextMenu.Node = hitTest.Node; + contextMenu.Column = hitTest.Column; + contextMenu.KeyboardInvoked = keyboardInvoked; + Context->Callback(hwnd, TreeNewContextMenu, &contextMenu, NULL, Context->CallbackContext); +} + +VOID PhTnpOnVScroll( + _In_ HWND hwnd, + _In_ PPH_TREENEW_CONTEXT Context, + _In_ ULONG Request, + _In_ USHORT Position + ) +{ + SCROLLINFO scrollInfo; + LONG oldPosition; + + scrollInfo.cbSize = sizeof(SCROLLINFO); + scrollInfo.fMask = SIF_ALL; + GetScrollInfo(Context->VScrollHandle, SB_CTL, &scrollInfo); + oldPosition = scrollInfo.nPos; + + switch (Request) + { + case SB_LINEUP: + scrollInfo.nPos--; + break; + case SB_LINEDOWN: + scrollInfo.nPos++; + break; + case SB_PAGEUP: + scrollInfo.nPos -= scrollInfo.nPage; + break; + case SB_PAGEDOWN: + scrollInfo.nPos += scrollInfo.nPage; + break; + case SB_THUMBPOSITION: + // Touch scrolling seems to give us Position but not nTrackPos. The problem is that Position + // is a 16-bit value, so don't use it if we have too many rows. + if (Context->FlatList->Count <= 0xffff) + scrollInfo.nPos = Position; + break; + case SB_THUMBTRACK: + scrollInfo.nPos = scrollInfo.nTrackPos; + break; + case SB_TOP: + scrollInfo.nPos = 0; + break; + case SB_BOTTOM: + scrollInfo.nPos = MAXINT; + break; + } + + scrollInfo.fMask = SIF_POS; + SetScrollInfo(Context->VScrollHandle, SB_CTL, &scrollInfo, TRUE); + GetScrollInfo(Context->VScrollHandle, SB_CTL, &scrollInfo); + + if (scrollInfo.nPos != oldPosition) + { + Context->VScrollPosition = scrollInfo.nPos; + PhTnpProcessScroll(Context, scrollInfo.nPos - oldPosition, 0); + } +} + +VOID PhTnpOnHScroll( + _In_ HWND hwnd, + _In_ PPH_TREENEW_CONTEXT Context, + _In_ ULONG Request, + _In_ USHORT Position + ) +{ + SCROLLINFO scrollInfo; + LONG oldPosition; + + scrollInfo.cbSize = sizeof(SCROLLINFO); + scrollInfo.fMask = SIF_ALL; + GetScrollInfo(Context->HScrollHandle, SB_CTL, &scrollInfo); + oldPosition = scrollInfo.nPos; + + switch (Request) + { + case SB_LINELEFT: + scrollInfo.nPos -= Context->TextMetrics.tmAveCharWidth; + break; + case SB_LINERIGHT: + scrollInfo.nPos += Context->TextMetrics.tmAveCharWidth; + break; + case SB_PAGELEFT: + scrollInfo.nPos -= scrollInfo.nPage; + break; + case SB_PAGERIGHT: + scrollInfo.nPos += scrollInfo.nPage; + break; + case SB_THUMBPOSITION: + // Touch scrolling seems to give us Position but not nTrackPos. The problem is that Position + // is a 16-bit value, so don't use it if we have too many rows. + if (Context->FlatList->Count <= 0xffff) + scrollInfo.nPos = Position; + break; + case SB_THUMBTRACK: + scrollInfo.nPos = scrollInfo.nTrackPos; + break; + case SB_LEFT: + scrollInfo.nPos = 0; + break; + case SB_RIGHT: + scrollInfo.nPos = MAXINT; + break; + } + + scrollInfo.fMask = SIF_POS; + SetScrollInfo(Context->HScrollHandle, SB_CTL, &scrollInfo, TRUE); + GetScrollInfo(Context->HScrollHandle, SB_CTL, &scrollInfo); + + if (scrollInfo.nPos != oldPosition) + { + Context->HScrollPosition = scrollInfo.nPos; + PhTnpProcessScroll(Context, 0, scrollInfo.nPos - oldPosition); + } +} + +BOOLEAN PhTnpOnNotify( + _In_ HWND hwnd, + _In_ PPH_TREENEW_CONTEXT Context, + _In_ NMHDR *Header, + _Out_ LRESULT *Result + ) +{ + switch (Header->code) + { + case HDN_ITEMCHANGING: + case HDN_ITEMCHANGED: + { + NMHEADER *nmHeader = (NMHEADER *)Header; + + if (Header->code == HDN_ITEMCHANGING && Header->hwndFrom == Context->FixedHeaderHandle) + { + if (nmHeader->pitem->mask & HDI_WIDTH) + { + if (Context->FixedColumnVisible) + { + Context->FixedWidth = nmHeader->pitem->cxy - 1; + + if (Context->FixedWidth < Context->FixedWidthMinimum) + Context->FixedWidth = Context->FixedWidthMinimum; + + Context->NormalLeft = Context->FixedWidth + 1; + nmHeader->pitem->cxy = Context->FixedWidth + 1; + } + else + { + Context->FixedWidth = 0; + Context->NormalLeft = 0; + } + } + } + + if (Header->hwndFrom == Context->FixedHeaderHandle || Header->hwndFrom == Context->HeaderHandle) + { + if (nmHeader->pitem->mask & HDI_WIDTH) + { + // A column has been resized. Update our stored information. + PhTnpUpdateColumnHeaders(Context); + PhTnpUpdateColumnMaps(Context); + + if (Header->code == HDN_ITEMCHANGING) + { + HDITEM item; + + item.mask = HDI_WIDTH | HDI_LPARAM; + + if (Header_GetItem(Header->hwndFrom, nmHeader->iItem, &item)) + { + Context->ResizingColumn = (PPH_TREENEW_COLUMN)item.lParam; + Context->OldColumnWidth = item.cxy; + } + else + { + Context->ResizingColumn = NULL; + Context->OldColumnWidth = -1; + } + } + else if (Header->code == HDN_ITEMCHANGED) + { + if (Context->ResizingColumn) + { + LONG delta; + + delta = nmHeader->pitem->cxy - Context->OldColumnWidth; + + if (delta != 0) + { + PhTnpProcessResizeColumn(Context, Context->ResizingColumn, delta); + Context->Callback(Context->Handle, TreeNewColumnResized, Context->ResizingColumn, NULL, Context->CallbackContext); + } + + Context->ResizingColumn = NULL; + + // Redraw the entire window if we are displaying empty text. + if (Context->FlatList->Count == 0 && Context->EmptyText.Length != 0) + InvalidateRect(Context->Handle, NULL, FALSE); + } + else + { + // An error occurred during HDN_ITEMCHANGED, so redraw the entire window. + InvalidateRect(Context->Handle, NULL, FALSE); + } + } + } + } + } + break; + case HDN_ITEMCLICK: + { + if ((Header->hwndFrom == Context->FixedHeaderHandle || Header->hwndFrom == Context->HeaderHandle) && + !(Context->Style & TN_STYLE_NO_COLUMN_SORT)) + { + NMHEADER *nmHeader = (NMHEADER *)Header; + HDITEM item; + PPH_TREENEW_COLUMN column; + + // A column has been clicked, so update the sort state. + + item.mask = HDI_LPARAM; + + if (Header_GetItem(Header->hwndFrom, nmHeader->iItem, &item)) + { + column = (PPH_TREENEW_COLUMN)item.lParam; + PhTnpProcessSortColumn(Context, column); + } + } + } + break; + case HDN_ENDDRAG: + case NM_RELEASEDCAPTURE: + { + if (Header->hwndFrom == Context->HeaderHandle) + { + // Columns have been re-ordered, so refresh our information. + // Note: The fixed column cannot be re-ordered. + PhTnpUpdateColumnHeaders(Context); + PhTnpUpdateColumnMaps(Context); + Context->Callback(Context->Handle, TreeNewColumnReordered, NULL, NULL, Context->CallbackContext); + InvalidateRect(Context->Handle, NULL, FALSE); + } + } + break; + case HDN_DIVIDERDBLCLICK: + { + if (Header->hwndFrom == Context->FixedHeaderHandle || Header->hwndFrom == Context->HeaderHandle) + { + NMHEADER *nmHeader = (NMHEADER *)Header; + HDITEM item; + + if (Context->SuspendUpdateStructure) + break; + + item.mask = HDI_LPARAM; + + if (Header_GetItem(Header->hwndFrom, nmHeader->iItem, &item)) + { + PhTnpAutoSizeColumnHeader( + Context, + Header->hwndFrom, + (PPH_TREENEW_COLUMN)item.lParam, + 0 + ); + } + } + } + break; + case NM_RCLICK: + { + if (Header->hwndFrom == Context->FixedHeaderHandle || Header->hwndFrom == Context->HeaderHandle) + { + PH_TREENEW_HEADER_MOUSE_EVENT mouseEvent; + ULONG position; + + position = GetMessagePos(); + mouseEvent.ScreenLocation.x = GET_X_LPARAM(position); + mouseEvent.ScreenLocation.y = GET_Y_LPARAM(position); + + mouseEvent.Location = mouseEvent.ScreenLocation; + ScreenToClient(hwnd, &mouseEvent.Location); + mouseEvent.HeaderLocation = mouseEvent.ScreenLocation; + ScreenToClient(Header->hwndFrom, &mouseEvent.HeaderLocation); + mouseEvent.Column = PhTnpHitTestHeader(Context, Header->hwndFrom == Context->FixedHeaderHandle, &mouseEvent.HeaderLocation, NULL); + Context->Callback(hwnd, TreeNewHeaderRightClick, &mouseEvent, NULL, Context->CallbackContext); + } + } + break; + case TTN_GETDISPINFO: + { + if (Header->hwndFrom == Context->TooltipsHandle) + { + NMTTDISPINFO *info = (NMTTDISPINFO *)Header; + POINT point; + + PhTnpGetMessagePos(hwnd, &point); + PhTnpGetTooltipText(Context, &point, &info->lpszText); + } + } + break; + case TTN_SHOW: + { + if (Header->hwndFrom == Context->TooltipsHandle) + { + *Result = PhTnpPrepareTooltipShow(Context); + return TRUE; + } + } + break; + case TTN_POP: + { + if (Header->hwndFrom == Context->TooltipsHandle) + { + PhTnpPrepareTooltipPop(Context); + } + } + break; + } + + return FALSE; +} + +ULONG_PTR PhTnpOnUserMessage( + _In_ HWND hwnd, + _In_ PPH_TREENEW_CONTEXT Context, + _In_ ULONG Message, + _In_ ULONG_PTR WParam, + _In_ ULONG_PTR LParam + ) +{ + switch (Message) + { + case TNM_SETCALLBACK: + { + Context->Callback = (PPH_TREENEW_CALLBACK)LParam; + Context->CallbackContext = (PVOID)WParam; + + if (!Context->Callback) + Context->Callback = PhTnpNullCallback; + } + return TRUE; + case TNM_NODESSTRUCTURED: + { + if (Context->EnableRedraw <= 0) + { + Context->SuspendUpdateStructure = TRUE; + Context->SuspendUpdateLayout = TRUE; + InvalidateRect(Context->Handle, NULL, FALSE); + return TRUE; + } + + PhTnpRestructureNodes(Context); + PhTnpLayout(Context); + InvalidateRect(Context->Handle, NULL, FALSE); + } + return TRUE; + case TNM_ADDCOLUMN: + return PhTnpAddColumn(Context, (PPH_TREENEW_COLUMN)LParam); + case TNM_REMOVECOLUMN: + return PhTnpRemoveColumn(Context, (ULONG)WParam); + case TNM_GETCOLUMN: + return PhTnpCopyColumn(Context, (ULONG)WParam, (PPH_TREENEW_COLUMN)LParam); + case TNM_SETCOLUMN: + { + PPH_TREENEW_COLUMN column = (PPH_TREENEW_COLUMN)LParam; + + return PhTnpChangeColumn(Context, (ULONG)WParam, column->Id, column); + } + break; + case TNM_GETCOLUMNORDERARRAY: + { + ULONG count = (ULONG)WParam; + PULONG order = (PULONG)LParam; + ULONG i; + + if (count != Context->NumberOfColumnsByDisplay) + return FALSE; + + for (i = 0; i < count; i++) + { + order[i] = Context->ColumnsByDisplay[i]->Id; + } + } + return TRUE; + case TNM_SETCOLUMNORDERARRAY: + { + ULONG count = (ULONG)WParam; + PULONG order = (PULONG)LParam; + ULONG i; + PULONG newOrder; + PPH_TREENEW_COLUMN column; + + newOrder = PhAllocate(count * sizeof(ULONG)); + + for (i = 0; i < count; i++) + { + if (!(column = PhTnpLookupColumnById(Context, order[i]))) + { + PhFree(newOrder); + return FALSE; + } + + newOrder[i] = column->s.ViewIndex; + } + + if (!Header_SetOrderArray(Context->HeaderHandle, count, newOrder)) + { + PhFree(newOrder); + return FALSE; + } + + PhFree(newOrder); + + PhTnpUpdateColumnHeaders(Context); + PhTnpUpdateColumnMaps(Context); + } + return TRUE; + case TNM_SETCURSOR: + { + Context->Cursor = (HCURSOR)LParam; + } + return TRUE; + case TNM_GETSORT: + { + PULONG sortColumn = (PULONG)WParam; + PPH_SORT_ORDER sortOrder = (PPH_SORT_ORDER)LParam; + + if (sortColumn) + *sortColumn = Context->SortColumn; + if (sortOrder) + *sortOrder = Context->SortOrder; + } + return TRUE; + case TNM_SETSORT: + { + ULONG sortColumn = (ULONG)WParam; + PH_SORT_ORDER sortOrder = (PH_SORT_ORDER)LParam; + PPH_TREENEW_COLUMN column; + + if (sortOrder != NoSortOrder) + { + if (!(column = PhTnpLookupColumnById(Context, sortColumn))) + return FALSE; + } + else + { + sortColumn = 0; + column = NULL; + } + + Context->SortColumn = sortColumn; + Context->SortOrder = sortOrder; + + PhTnpSetColumnHeaderSortIcon(Context, column); + + Context->Callback(Context->Handle, TreeNewSortChanged, NULL, NULL, Context->CallbackContext); + } + return TRUE; + case TNM_SETTRISTATE: + Context->TriState = !!WParam; + return TRUE; + case TNM_ENSUREVISIBLE: + return PhTnpEnsureVisibleNode(Context, ((PPH_TREENEW_NODE)LParam)->Index); + case TNM_SCROLL: + PhTnpScroll(Context, (LONG)WParam, (LONG)LParam); + return TRUE; + case TNM_GETFLATNODECOUNT: + if (!Context->SuspendUpdateStructure) + return (LRESULT)Context->FlatList->Count; + else + return 0; + case TNM_GETFLATNODE: + { + ULONG index = (ULONG)WParam; + + if (index >= Context->FlatList->Count) + return (LRESULT)NULL; + + return (LRESULT)Context->FlatList->Items[index]; + } + break; + case TNM_GETCELLTEXT: + { + PPH_TREENEW_GET_CELL_TEXT getCellText = (PPH_TREENEW_GET_CELL_TEXT)LParam; + + return PhTnpGetCellText( + Context, + getCellText->Node, + getCellText->Id, + &getCellText->Text + ); + } + break; + case TNM_SETNODEEXPANDED: + PhTnpSetExpandedNode(Context, (PPH_TREENEW_NODE)LParam, !!WParam); + return TRUE; + case TNM_GETMAXID: + return (LRESULT)(Context->NextId - 1); + case TNM_SETMAXID: + { + ULONG maxId = (ULONG)WParam; + + if (Context->NextId < maxId + 1) + { + Context->NextId = maxId + 1; + + if (Context->AllocatedColumns < Context->NextId) + { + PhTnpExpandAllocatedColumns(Context); + } + } + } + return TRUE; + case TNM_INVALIDATENODE: + { + PPH_TREENEW_NODE node = (PPH_TREENEW_NODE)LParam; + RECT rect; + + if (!node->Visible) + return FALSE; + + if (!PhTnpGetRowRects(Context, node->Index, node->Index, TRUE, &rect)) + return FALSE; + + InvalidateRect(hwnd, &rect, FALSE); + } + return TRUE; + case TNM_INVALIDATENODES: + { + RECT rect; + + if (!PhTnpGetRowRects(Context, (ULONG)WParam, (ULONG)LParam, TRUE, &rect)) + return FALSE; + + InvalidateRect(hwnd, &rect, FALSE); + } + return TRUE; + case TNM_GETFIXEDHEADER: + return (LRESULT)Context->FixedHeaderHandle; + case TNM_GETHEADER: + return (LRESULT)Context->HeaderHandle; + case TNM_GETTOOLTIPS: + return (LRESULT)Context->TooltipsHandle; + case TNM_SELECTRANGE: + case TNM_DESELECTRANGE: + { + ULONG flags; + ULONG changedStart; + ULONG changedEnd; + RECT rect; + + flags = 0; + + if (Message == TNM_DESELECTRANGE) + flags |= TN_SELECT_DESELECT; + + PhTnpSelectRange(Context, (ULONG)WParam, (ULONG)LParam, flags, &changedStart, &changedEnd); + + if (PhTnpGetRowRects(Context, changedStart, changedEnd, TRUE, &rect)) + { + InvalidateRect(hwnd, &rect, FALSE); + } + } + return TRUE; + case TNM_GETCOLUMNCOUNT: + return (LRESULT)Context->NumberOfColumns; + case TNM_SETREDRAW: + PhTnpSetRedraw(Context, !!WParam); + return (LRESULT)Context->EnableRedraw; + case TNM_GETVIEWPARTS: + { + PPH_TREENEW_VIEW_PARTS parts = (PPH_TREENEW_VIEW_PARTS)LParam; + + parts->ClientRect = Context->ClientRect; + parts->HeaderHeight = Context->HeaderHeight; + parts->RowHeight = Context->RowHeight; + parts->VScrollWidth = Context->VScrollVisible ? Context->VScrollWidth : 0; + parts->HScrollHeight = Context->HScrollHeight ? Context->HScrollHeight : 0; + parts->VScrollPosition = Context->VScrollPosition; + parts->HScrollPosition = Context->HScrollPosition; + parts->FixedWidth = Context->FixedWidth; + parts->NormalLeft = Context->NormalLeft; + parts->NormalWidth = Context->TotalViewX; + } + return TRUE; + case TNM_GETFIXEDCOLUMN: + return (LRESULT)Context->FixedColumn; + case TNM_GETFIRSTCOLUMN: + return (LRESULT)Context->FirstColumn; + case TNM_SETFOCUSNODE: + Context->FocusNode = (PPH_TREENEW_NODE)LParam; + return TRUE; + case TNM_SETMARKNODE: + Context->MarkNodeIndex = ((PPH_TREENEW_NODE)LParam)->Index; + return TRUE; + case TNM_SETHOTNODE: + PhTnpSetHotNode(Context, (PPH_TREENEW_NODE)LParam, FALSE); + return TRUE; + case TNM_SETEXTENDEDFLAGS: + Context->ExtendedFlags = (Context->ExtendedFlags & ~(ULONG)WParam) | ((ULONG)LParam & (ULONG)WParam); + return TRUE; + case TNM_GETCALLBACK: + { + PPH_TREENEW_CALLBACK *callback = (PPH_TREENEW_CALLBACK *)LParam; + PVOID *callbackContext = (PVOID *)WParam; + + if (callback) + { + if (Context->Callback != PhTnpNullCallback) + *callback = Context->Callback; + else + *callback = NULL; + } + + if (callbackContext) + { + *callbackContext = Context->CallbackContext; + } + } + return TRUE; + case TNM_HITTEST: + PhTnpHitTest(Context, (PPH_TREENEW_HIT_TEST)LParam); + return TRUE; + case TNM_GETVISIBLECOLUMNCOUNT: + return Context->NumberOfColumnsByDisplay + (Context->FixedColumnVisible ? 1 : 0); + case TNM_AUTOSIZECOLUMN: + { + ULONG id = (ULONG)WParam; + ULONG flags = (ULONG)LParam; + PPH_TREENEW_COLUMN column; + + if (!(column = PhTnpLookupColumnById(Context, id))) + return FALSE; + + if (!column->Visible) + return FALSE; + + PhTnpAutoSizeColumnHeader( + Context, + column->Fixed ? Context->FixedHeaderHandle : Context->HeaderHandle, + column, + flags + ); + } + return TRUE; + case TNM_SETEMPTYTEXT: + { + PPH_STRINGREF text = (PPH_STRINGREF)LParam; + ULONG flags = (ULONG)WParam; + + Context->EmptyText = *text; + } + return TRUE; + case TNM_SETROWHEIGHT: + { + LONG rowHeight = (LONG)WParam; + + if (rowHeight != 0) + { + Context->CustomRowHeight = TRUE; + Context->RowHeight = rowHeight; + } + else + { + Context->CustomRowHeight = FALSE; + PhTnpUpdateTextMetrics(Context); + } + } + return TRUE; + case TNM_ISFLATNODEVALID: + return !Context->SuspendUpdateStructure; + } + + return 0; +} + +VOID PhTnpSetFont( + _In_ PPH_TREENEW_CONTEXT Context, + _In_opt_ HFONT Font, + _In_ BOOLEAN Redraw + ) +{ + if (Context->FontOwned) + { + DeleteObject(Context->Font); + Context->FontOwned = FALSE; + } + + Context->Font = Font; + + if (!Context->Font) + { + LOGFONT logFont; + + if (SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(LOGFONT), &logFont, 0)) + { + Context->Font = CreateFontIndirect(&logFont); + Context->FontOwned = TRUE; + } + } + + SendMessage(Context->FixedHeaderHandle, WM_SETFONT, (WPARAM)Context->Font, Redraw); + SendMessage(Context->HeaderHandle, WM_SETFONT, (WPARAM)Context->Font, Redraw); + + if (Context->TooltipsHandle) + { + SendMessage(Context->TooltipsHandle, WM_SETFONT, (WPARAM)Context->Font, FALSE); + Context->TooltipFont = Context->Font; + } + + PhTnpUpdateTextMetrics(Context); +} + +VOID PhTnpUpdateSystemMetrics( + _In_ PPH_TREENEW_CONTEXT Context + ) +{ + Context->VScrollWidth = GetSystemMetrics(SM_CXVSCROLL); + Context->HScrollHeight = GetSystemMetrics(SM_CYHSCROLL); + Context->SystemBorderX = GetSystemMetrics(SM_CXBORDER); + Context->SystemBorderY = GetSystemMetrics(SM_CYBORDER); + Context->SystemEdgeX = GetSystemMetrics(SM_CXEDGE); + Context->SystemEdgeY = GetSystemMetrics(SM_CYEDGE); + Context->SystemDragX = GetSystemMetrics(SM_CXDRAG); + Context->SystemDragY = GetSystemMetrics(SM_CYDRAG); + + if (Context->SystemDragX < 2) + Context->SystemDragX = 2; + if (Context->SystemDragY < 2) + Context->SystemDragY = 2; +} + +VOID PhTnpUpdateTextMetrics( + _In_ PPH_TREENEW_CONTEXT Context + ) +{ + HDC hdc; + + if (hdc = GetDC(Context->Handle)) + { + SelectObject(hdc, Context->Font); + GetTextMetrics(hdc, &Context->TextMetrics); + + if (!Context->CustomRowHeight) + { + // Below we try to match the row height as calculated by the list view, even if it + // involves magic numbers. On Vista and above there seems to be extra padding. + + Context->RowHeight = Context->TextMetrics.tmHeight; + + if (Context->Style & TN_STYLE_ICONS) + { + if (Context->RowHeight < SmallIconHeight) + Context->RowHeight = SmallIconHeight; + } + else + { + if (WindowsVersion >= WINDOWS_VISTA && !(Context->Style & TN_STYLE_THIN_ROWS)) + Context->RowHeight += 1; // HACK + } + + Context->RowHeight += 1; // HACK + + if (WindowsVersion >= WINDOWS_VISTA && !(Context->Style & TN_STYLE_THIN_ROWS)) + Context->RowHeight += 2; // HACK + } + + ReleaseDC(Context->Handle, hdc); + } +} + +VOID PhTnpUpdateThemeData( + _In_ PPH_TREENEW_CONTEXT Context + ) +{ + Context->ThemeActive = !!IsThemeActive(); + + if (Context->ThemeData) + { + CloseThemeData(Context->ThemeData); + Context->ThemeData = NULL; + } + + Context->ThemeData = OpenThemeData(Context->Handle, L"TREEVIEW"); + + if (Context->ThemeData) + { + Context->ThemeHasItemBackground = !!IsThemePartDefined(Context->ThemeData, TVP_TREEITEM, 0); + Context->ThemeHasGlyph = !!IsThemePartDefined(Context->ThemeData, TVP_GLYPH, 0); + Context->ThemeHasHotGlyph = !!IsThemePartDefined(Context->ThemeData, TVP_HOTGLYPH, 0); + } + else + { + Context->ThemeHasItemBackground = FALSE; + Context->ThemeHasGlyph = FALSE; + Context->ThemeHasHotGlyph = FALSE; + } +} + +VOID PhTnpInitializeThemeData( + _In_ PPH_TREENEW_CONTEXT Context + ) +{ + if (!Context->ThemeInitialized) + { + PhTnpUpdateThemeData(Context); + Context->ThemeInitialized = TRUE; + } +} + +VOID PhTnpCancelTrack( + _In_ PPH_TREENEW_CONTEXT Context + ) +{ + PhTnpSetFixedWidth(Context, Context->TrackOldFixedWidth); + ReleaseCapture(); +} + +VOID PhTnpLayout( + _In_ PPH_TREENEW_CONTEXT Context + ) +{ + RECT clientRect; + + if (Context->EnableRedraw <= 0) + { + Context->SuspendUpdateLayout = TRUE; + return; + } + + clientRect = Context->ClientRect; + + PhTnpUpdateScrollBars(Context); + + // Vertical scroll bar + if (Context->VScrollVisible) + { + MoveWindow( + Context->VScrollHandle, + clientRect.right - Context->VScrollWidth, + 0, + Context->VScrollWidth, + clientRect.bottom - (Context->HScrollVisible ? Context->HScrollHeight : 0), + TRUE + ); + } + + // Horizontal scroll bar + if (Context->HScrollVisible) + { + MoveWindow( + Context->HScrollHandle, + Context->NormalLeft, + clientRect.bottom - Context->HScrollHeight, + clientRect.right - Context->NormalLeft - (Context->VScrollVisible ? Context->VScrollWidth : 0), + Context->HScrollHeight, + TRUE + ); + } + + // Filler box + if (Context->VScrollVisible && Context->HScrollVisible) + { + MoveWindow( + Context->FillerBoxHandle, + clientRect.right - Context->VScrollWidth, + clientRect.bottom - Context->HScrollHeight, + Context->VScrollWidth, + Context->HScrollHeight, + TRUE + ); + } + + PhTnpLayoutHeader(Context); + + // Redraw the entire window if we are displaying empty text. + if (Context->FlatList->Count == 0 && Context->EmptyText.Length != 0) + InvalidateRect(Context->Handle, NULL, FALSE); +} + +VOID PhTnpLayoutHeader( + _In_ PPH_TREENEW_CONTEXT Context + ) +{ + RECT rect; + HDLAYOUT hdl; + WINDOWPOS windowPos; + + hdl.prc = ▭ + hdl.pwpos = &windowPos; + + if (!(Context->Style & TN_STYLE_NO_COLUMN_HEADER)) + { + // Fixed portion header control + rect.left = 0; + rect.top = 0; + rect.right = Context->NormalLeft; + rect.bottom = Context->ClientRect.bottom; + Header_Layout(Context->FixedHeaderHandle, &hdl); + SetWindowPos(Context->FixedHeaderHandle, NULL, windowPos.x, windowPos.y, windowPos.cx, windowPos.cy, windowPos.flags); + Context->HeaderHeight = windowPos.cy; + + // Normal portion header control + rect.left = Context->NormalLeft - Context->HScrollPosition; + rect.top = 0; + rect.right = Context->ClientRect.right - (Context->VScrollVisible ? Context->VScrollWidth : 0); + rect.bottom = Context->ClientRect.bottom; + Header_Layout(Context->HeaderHandle, &hdl); + SetWindowPos(Context->HeaderHandle, NULL, windowPos.x, windowPos.y, windowPos.cx, windowPos.cy, windowPos.flags); + } + else + { + Context->HeaderHeight = 0; + } + + if (Context->TooltipsHandle) + { + TOOLINFO toolInfo; + + memset(&toolInfo, 0, sizeof(TOOLINFO)); + toolInfo.cbSize = sizeof(TOOLINFO); + toolInfo.hwnd = Context->FixedHeaderHandle; + toolInfo.uId = TNP_TOOLTIPS_FIXED_HEADER; + GetClientRect(Context->FixedHeaderHandle, &toolInfo.rect); + SendMessage(Context->TooltipsHandle, TTM_NEWTOOLRECT, 0, (LPARAM)&toolInfo); + + toolInfo.hwnd = Context->HeaderHandle; + toolInfo.uId = TNP_TOOLTIPS_HEADER; + GetClientRect(Context->HeaderHandle, &toolInfo.rect); + SendMessage(Context->TooltipsHandle, TTM_NEWTOOLRECT, 0, (LPARAM)&toolInfo); + } +} + +VOID PhTnpSetFixedWidth( + _In_ PPH_TREENEW_CONTEXT Context, + _In_ ULONG FixedWidth + ) +{ + HDITEM item; + + if (Context->FixedColumnVisible) + { + Context->FixedWidth = FixedWidth; + + if (Context->FixedWidth < Context->FixedWidthMinimum) + Context->FixedWidth = Context->FixedWidthMinimum; + + Context->NormalLeft = Context->FixedWidth + 1; + + item.mask = HDI_WIDTH; + item.cxy = Context->FixedWidth + 1; + Header_SetItem(Context->FixedHeaderHandle, 0, &item); + } + else + { + Context->FixedWidth = 0; + Context->NormalLeft = 0; + } +} + +VOID PhTnpSetRedraw( + _In_ PPH_TREENEW_CONTEXT Context, + _In_ BOOLEAN Redraw + ) +{ + if (Redraw) + Context->EnableRedraw++; + else + Context->EnableRedraw--; + + if (Context->EnableRedraw == 1) + { + if (Context->SuspendUpdateStructure) + { + PhTnpRestructureNodes(Context); + } + + if (Context->SuspendUpdateLayout) + { + PhTnpLayout(Context); + } + + if (Context->SuspendUpdateMoveMouse) + { + POINT point; + + PhTnpGetMessagePos(Context->Handle, &point); + PhTnpProcessMoveMouse(Context, point.x, point.y); + } + + Context->SuspendUpdateStructure = FALSE; + Context->SuspendUpdateLayout = FALSE; + Context->SuspendUpdateMoveMouse = FALSE; + + if (Context->SuspendUpdateRegion) + { + InvalidateRgn(Context->Handle, Context->SuspendUpdateRegion, FALSE); + DeleteObject(Context->SuspendUpdateRegion); + Context->SuspendUpdateRegion = NULL; + } + } +} + +VOID PhTnpSendMouseEvent( + _In_ PPH_TREENEW_CONTEXT Context, + _In_ PH_TREENEW_MESSAGE Message, + _In_ LONG CursorX, + _In_ LONG CursorY, + _In_ PPH_TREENEW_NODE Node, + _In_ PPH_TREENEW_COLUMN Column, + _In_ ULONG VirtualKeys + ) +{ + PH_TREENEW_MOUSE_EVENT mouseEvent; + + mouseEvent.Location.x = CursorX; + mouseEvent.Location.y = CursorY; + mouseEvent.Node = Node; + mouseEvent.Column = Column; + mouseEvent.KeyFlags = VirtualKeys; + Context->Callback(Context->Handle, Message, &mouseEvent, NULL, Context->CallbackContext); +} + +PPH_TREENEW_COLUMN PhTnpLookupColumnById( + _In_ PPH_TREENEW_CONTEXT Context, + _In_ ULONG Id + ) +{ + if (Id >= Context->AllocatedColumns) + return NULL; + + return Context->Columns[Id]; +} + +BOOLEAN PhTnpAddColumn( + _In_ PPH_TREENEW_CONTEXT Context, + _In_ PPH_TREENEW_COLUMN Column + ) +{ + PPH_TREENEW_COLUMN realColumn; + + // Check if a column with the same ID already exists. + if (Column->Id < Context->AllocatedColumns && Context->Columns[Column->Id]) + return FALSE; + + if (Context->NextId < Column->Id + 1) + Context->NextId = Column->Id + 1; + + realColumn = PhAllocateCopy(Column, sizeof(PH_TREENEW_COLUMN)); + + if (realColumn->DpiScaleOnAdd) + { + realColumn->Width = PhMultiplyDivide(realColumn->Width, PhGlobalDpi, 96); + realColumn->DpiScaleOnAdd = FALSE; + } + + if (Context->AllocatedColumns < Context->NextId) + { + PhTnpExpandAllocatedColumns(Context); + } + + Context->Columns[Column->Id] = realColumn; + Context->NumberOfColumns++; + + if (realColumn->Fixed) + { + if (Context->FixedColumn) + { + // We already have a fixed column, and we can't have two. Make this new column un-fixed. + realColumn->Fixed = FALSE; + } + else + { + Context->FixedColumn = realColumn; + } + + realColumn->DisplayIndex = 0; + realColumn->s.ViewX = 0; + } + + if (realColumn->Visible) + { + BOOLEAN updateHeaders; + + updateHeaders = FALSE; + + if (!realColumn->Fixed && realColumn->DisplayIndex != Header_GetItemCount(Context->HeaderHandle)) + updateHeaders = TRUE; + + realColumn->s.ViewIndex = PhTnpInsertColumnHeader(Context, realColumn); + + if (updateHeaders) + PhTnpUpdateColumnHeaders(Context); + } + else + { + realColumn->s.ViewIndex = -1; + } + + PhTnpUpdateColumnMaps(Context); + + if (realColumn->Visible) + PhTnpLayout(Context); + + return TRUE; +} + +BOOLEAN PhTnpRemoveColumn( + _In_ PPH_TREENEW_CONTEXT Context, + _In_ ULONG Id + ) +{ + PPH_TREENEW_COLUMN realColumn; + BOOLEAN updateLayout; + + if (!(realColumn = PhTnpLookupColumnById(Context, Id))) + return FALSE; + + updateLayout = FALSE; + + if (realColumn->Visible) + updateLayout = TRUE; + + PhTnpDeleteColumnHeader(Context, realColumn); + Context->Columns[realColumn->Id] = NULL; + PhFree(realColumn); + PhTnpUpdateColumnMaps(Context); + + if (updateLayout) + PhTnpLayout(Context); + + Context->NumberOfColumns--; + + return TRUE; +} + +BOOLEAN PhTnpCopyColumn( + _In_ PPH_TREENEW_CONTEXT Context, + _In_ ULONG Id, + _Out_ PPH_TREENEW_COLUMN Column + ) +{ + PPH_TREENEW_COLUMN realColumn; + + if (!(realColumn = PhTnpLookupColumnById(Context, Id))) + return FALSE; + + memcpy(Column, realColumn, sizeof(PH_TREENEW_COLUMN)); + + return TRUE; +} + +BOOLEAN PhTnpChangeColumn( + _In_ PPH_TREENEW_CONTEXT Context, + _In_ ULONG Mask, + _In_ ULONG Id, + _In_ PPH_TREENEW_COLUMN Column + ) +{ + PPH_TREENEW_COLUMN realColumn; + BOOLEAN addingOrRemoving; + + if (!(realColumn = PhTnpLookupColumnById(Context, Id))) + return FALSE; + + addingOrRemoving = FALSE; + + if (Mask & TN_COLUMN_FLAG_VISIBLE) + { + if (realColumn->Visible != Column->Visible) + { + addingOrRemoving = TRUE; + } + } + + if (Mask & TN_COLUMN_FLAG_CUSTOMDRAW) + { + realColumn->CustomDraw = Column->CustomDraw; + } + + if (Mask & TN_COLUMN_FLAG_SORTDESCENDING) + { + realColumn->SortDescending = Column->SortDescending; + } + + if (Mask & (TN_COLUMN_TEXT | TN_COLUMN_WIDTH | TN_COLUMN_ALIGNMENT | TN_COLUMN_DISPLAYINDEX)) + { + BOOLEAN updateHeaders; + BOOLEAN updateMaps; + BOOLEAN updateLayout; + + updateHeaders = FALSE; + updateMaps = FALSE; + updateLayout = FALSE; + + if (Mask & TN_COLUMN_TEXT) + { + realColumn->Text = Column->Text; + } + + if (Mask & TN_COLUMN_WIDTH) + { + realColumn->Width = Column->Width; + updateMaps = TRUE; + } + + if (Mask & TN_COLUMN_ALIGNMENT) + { + realColumn->Alignment = Column->Alignment; + } + + if (Mask & TN_COLUMN_DISPLAYINDEX) + { + realColumn->DisplayIndex = Column->DisplayIndex; + updateHeaders = TRUE; + updateMaps = TRUE; + updateLayout = TRUE; + } + + if (!addingOrRemoving && realColumn->Visible) + { + PhTnpChangeColumnHeader(Context, Mask, realColumn); + + if (updateHeaders) + PhTnpUpdateColumnHeaders(Context); + if (updateMaps) + PhTnpUpdateColumnMaps(Context); + if (updateLayout) + PhTnpLayout(Context); + } + } + + if (Mask & TN_COLUMN_CONTEXT) + { + realColumn->Context = Column->Context; + } + + if (Mask & TN_COLUMN_TEXTFLAGS) + { + realColumn->TextFlags = Column->TextFlags; + } + + if (addingOrRemoving) + { + if (Column->Visible) + { + BOOLEAN updateHeaders; + + updateHeaders = FALSE; + + if (realColumn->Fixed) + { + realColumn->DisplayIndex = 0; + } + else + { + if (Mask & TN_COLUMN_DISPLAYINDEX) + updateHeaders = TRUE; + else + realColumn->DisplayIndex = Header_GetItemCount(Context->HeaderHandle); + } + + realColumn->s.ViewIndex = PhTnpInsertColumnHeader(Context, realColumn); + + if (updateHeaders) + PhTnpUpdateColumnHeaders(Context); + } + else + { + PhTnpDeleteColumnHeader(Context, realColumn); + } + + PhTnpUpdateColumnMaps(Context); + PhTnpLayout(Context); + } + + return TRUE; +} + +VOID PhTnpExpandAllocatedColumns( + _In_ PPH_TREENEW_CONTEXT Context + ) +{ + if (Context->Columns) + { + ULONG oldAllocatedColumns; + + oldAllocatedColumns = Context->AllocatedColumns; + Context->AllocatedColumns *= 2; + + if (Context->AllocatedColumns < Context->NextId) + Context->AllocatedColumns = Context->NextId; + + Context->Columns = PhReAllocate( + Context->Columns, + Context->AllocatedColumns * sizeof(PPH_TREENEW_COLUMN) + ); + + // Zero the newly allocated portion. + memset( + &Context->Columns[oldAllocatedColumns], + 0, + (Context->AllocatedColumns - oldAllocatedColumns) * sizeof(PPH_TREENEW_COLUMN) + ); + } + else + { + Context->AllocatedColumns = 16; + + if (Context->AllocatedColumns < Context->NextId) + Context->AllocatedColumns = Context->NextId; + + Context->Columns = PhAllocate( + Context->AllocatedColumns * sizeof(PPH_TREENEW_COLUMN) + ); + memset(Context->Columns, 0, Context->AllocatedColumns * sizeof(PPH_TREENEW_COLUMN)); + } +} + +VOID PhTnpUpdateColumnMaps( + _In_ PPH_TREENEW_CONTEXT Context + ) +{ + ULONG i; + LONG x; + + if (Context->AllocatedColumnsByDisplay < Context->NumberOfColumns) + { + if (Context->ColumnsByDisplay) + PhFree(Context->ColumnsByDisplay); + + Context->ColumnsByDisplay = PhAllocate(sizeof(PPH_TREENEW_COLUMN) * Context->NumberOfColumns); + Context->AllocatedColumnsByDisplay = Context->NumberOfColumns; + } + + memset(Context->ColumnsByDisplay, 0, sizeof(PPH_TREENEW_COLUMN) * Context->AllocatedColumnsByDisplay); + + for (i = 0; i < Context->NextId; i++) + { + if (!Context->Columns[i]) + continue; + + if (Context->Columns[i]->Visible && !Context->Columns[i]->Fixed && Context->Columns[i]->DisplayIndex != -1) + { + if (Context->Columns[i]->DisplayIndex >= Context->NumberOfColumns) + PhRaiseStatus(STATUS_INTERNAL_ERROR); + + Context->ColumnsByDisplay[Context->Columns[i]->DisplayIndex] = Context->Columns[i]; + } + } + + x = 0; + + for (i = 0; i < Context->AllocatedColumnsByDisplay; i++) + { + if (!Context->ColumnsByDisplay[i]) + break; + + Context->ColumnsByDisplay[i]->s.ViewX = x; + x += Context->ColumnsByDisplay[i]->Width; + } + + Context->NumberOfColumnsByDisplay = i; + Context->TotalViewX = x; + + if (Context->FixedColumnVisible) + Context->FirstColumn = Context->FixedColumn; + else if (Context->NumberOfColumnsByDisplay != 0) + Context->FirstColumn = Context->ColumnsByDisplay[0]; + else + Context->FirstColumn = NULL; + + if (Context->NumberOfColumnsByDisplay != 0) + Context->LastColumn = Context->ColumnsByDisplay[Context->NumberOfColumnsByDisplay - 1]; + else if (Context->FixedColumnVisible) + Context->LastColumn = Context->FixedColumn; + else + Context->LastColumn = NULL; +} + +LONG PhTnpInsertColumnHeader( + _In_ PPH_TREENEW_CONTEXT Context, + _In_ PPH_TREENEW_COLUMN Column + ) +{ + HDITEM item; + + if (Column->Fixed) + { + if (Column->Width < Context->FixedWidthMinimum) + Column->Width = Context->FixedWidthMinimum; + + Context->FixedWidth = Column->Width; + Context->NormalLeft = Context->FixedWidth + 1; + Context->FixedColumnVisible = TRUE; + + if (!(Context->Style & TN_STYLE_NO_DIVIDER)) + Context->FixedDividerVisible = TRUE; + } + + memset(&item, 0, sizeof(HDITEM)); + item.mask = HDI_WIDTH | HDI_TEXT | HDI_FORMAT | HDI_LPARAM | HDI_ORDER; + item.cxy = Column->Width; + item.pszText = Column->Text; + item.fmt = 0; + item.lParam = (LPARAM)Column; + + if (Column->Fixed) + item.cxy++; + + if (Column->Fixed) + item.iOrder = 0; + else + item.iOrder = Column->DisplayIndex; + + if (Column->Alignment & PH_ALIGN_LEFT) + item.fmt |= HDF_LEFT; + else if (Column->Alignment & PH_ALIGN_RIGHT) + item.fmt |= HDF_RIGHT; + else + item.fmt |= HDF_CENTER; + + if (Column->Id == Context->SortColumn) + { + if (Context->SortOrder == AscendingSortOrder) + item.fmt |= HDF_SORTUP; + else if (Context->SortOrder == DescendingSortOrder) + item.fmt |= HDF_SORTDOWN; + } + + Column->Visible = TRUE; + + if (Column->Fixed) + return Header_InsertItem(Context->FixedHeaderHandle, 0, &item); + else + return Header_InsertItem(Context->HeaderHandle, MAXINT, &item); +} + +VOID PhTnpChangeColumnHeader( + _In_ PPH_TREENEW_CONTEXT Context, + _In_ ULONG Mask, + _In_ PPH_TREENEW_COLUMN Column + ) +{ + HDITEM item; + + memset(&item, 0, sizeof(HDITEM)); + item.mask = 0; + + if (Mask & TN_COLUMN_TEXT) + { + item.mask |= HDI_TEXT; + item.pszText = Column->Text; + } + + if (Mask & TN_COLUMN_WIDTH) + { + item.mask |= HDI_WIDTH; + item.cxy = Column->Width; + + if (Column->Fixed) + item.cxy++; + } + + if (Mask & TN_COLUMN_ALIGNMENT) + { + item.mask |= HDI_FORMAT; + item.fmt = 0; + + if (Column->Alignment & PH_ALIGN_LEFT) + item.fmt |= HDF_LEFT; + else if (Column->Alignment & PH_ALIGN_RIGHT) + item.fmt |= HDF_RIGHT; + else + item.fmt |= HDF_CENTER; + + if (Column->Id == Context->SortColumn) + { + if (Context->SortOrder == AscendingSortOrder) + item.fmt |= HDF_SORTUP; + else if (Context->SortOrder == DescendingSortOrder) + item.fmt |= HDF_SORTDOWN; + } + } + + if (Mask & TN_COLUMN_DISPLAYINDEX) + { + item.mask |= HDI_ORDER; + + if (Column->Fixed) + item.iOrder = 0; + else + item.iOrder = Column->DisplayIndex; + } + + if (Column->Fixed) + Header_SetItem(Context->FixedHeaderHandle, 0, &item); + else + Header_SetItem(Context->HeaderHandle, Column->s.ViewIndex, &item); +} + +VOID PhTnpDeleteColumnHeader( + _In_ PPH_TREENEW_CONTEXT Context, + _Inout_ PPH_TREENEW_COLUMN Column + ) +{ + if (Column->Fixed) + { + Context->FixedColumn = NULL; + Context->FixedWidth = 0; + Context->NormalLeft = 0; + Context->FixedColumnVisible = FALSE; + Context->FixedDividerVisible = FALSE; + } + + if (Column->Fixed) + Header_DeleteItem(Context->FixedHeaderHandle, Column->s.ViewIndex); + else + Header_DeleteItem(Context->HeaderHandle, Column->s.ViewIndex); + + Column->Visible = FALSE; + Column->s.ViewIndex = -1; + PhTnpUpdateColumnHeaders(Context); +} + +VOID PhTnpUpdateColumnHeaders( + _In_ PPH_TREENEW_CONTEXT Context + ) +{ + ULONG count; + ULONG i; + HDITEM item; + PPH_TREENEW_COLUMN column; + + item.mask = HDI_WIDTH | HDI_LPARAM | HDI_ORDER; + + // Fixed column + + if (Context->FixedColumnVisible && Header_GetItem(Context->FixedHeaderHandle, 0, &item)) + { + column = Context->FixedColumn; + column->Width = item.cxy - 1; + } + + // Normal columns + + count = Header_GetItemCount(Context->HeaderHandle); + + if (count != -1) + { + for (i = 0; i < count; i++) + { + if (Header_GetItem(Context->HeaderHandle, i, &item)) + { + column = (PPH_TREENEW_COLUMN)item.lParam; + column->s.ViewIndex = i; + column->Width = item.cxy; + column->DisplayIndex = item.iOrder; + } + } + } +} + +VOID PhTnpProcessResizeColumn( + _In_ PPH_TREENEW_CONTEXT Context, + _In_ PPH_TREENEW_COLUMN Column, + _In_ LONG Delta + ) +{ + RECT rect; + LONG columnLeft; + + if (Column->Fixed) + { + columnLeft = 0; + } + else + { + columnLeft = Context->NormalLeft + Column->s.ViewX - Context->HScrollPosition; + } + + // Scroll the content to the right of the column. + // + // Clip the scroll area to the new width, or the old width if that is further to the left. We + // may have the WS_CLIPCHILDREN style set, so we need to remove the horizontal scrollbar from + // the rectangle, otherwise ScrollWindowEx will want to invalidate the entire region! (The + // horizontal scrollbar is an overlapping child control.) + rect.left = columnLeft + Column->Width; + rect.top = Context->HeaderHeight; + rect.right = Context->ClientRect.right - (Context->VScrollVisible ? Context->VScrollWidth : 0); + rect.bottom = Context->ClientRect.bottom - (Context->HScrollVisible ? Context->HScrollHeight : 0); + + if (Delta > 0) + rect.left -= Delta; // old width + + // Scroll the window. + ScrollWindowEx( + Context->Handle, + Delta, + 0, + &rect, + &rect, + NULL, + NULL, + SW_INVALIDATE + ); + + UpdateWindow(Context->Handle); // required + + if (Context->HScrollVisible) + { + // We excluded the bottom region - invalidate it now. + rect.top = rect.bottom; + rect.bottom = Context->ClientRect.bottom; + InvalidateRect(Context->Handle, &rect, FALSE); + } + + PhTnpLayout(Context); + + // Redraw the whole column because the content may depend on the width (e.g. text ellipsis). + rect.left = columnLeft; + rect.top = Context->HeaderHeight; + rect.right = columnLeft + Column->Width; + RedrawWindow(Context->Handle, &rect, NULL, RDW_INVALIDATE | RDW_UPDATENOW); // must be RedrawWindow +} + +VOID PhTnpProcessSortColumn( + _In_ PPH_TREENEW_CONTEXT Context, + _In_ PPH_TREENEW_COLUMN NewColumn + ) +{ + if (NewColumn->Id == Context->SortColumn) + { + if (Context->TriState) + { + if (!NewColumn->SortDescending) + { + // Ascending -> Descending -> None + + if (Context->SortOrder == AscendingSortOrder) + Context->SortOrder = DescendingSortOrder; + else if (Context->SortOrder == DescendingSortOrder) + Context->SortOrder = NoSortOrder; + else + Context->SortOrder = AscendingSortOrder; + } + else + { + // Descending -> Ascending -> None + + if (Context->SortOrder == DescendingSortOrder) + Context->SortOrder = AscendingSortOrder; + else if (Context->SortOrder == AscendingSortOrder) + Context->SortOrder = NoSortOrder; + else + Context->SortOrder = DescendingSortOrder; + } + } + else + { + if (Context->SortOrder == AscendingSortOrder) + Context->SortOrder = DescendingSortOrder; + else + Context->SortOrder = AscendingSortOrder; + } + } + else + { + Context->SortColumn = NewColumn->Id; + + if (!NewColumn->SortDescending) + Context->SortOrder = AscendingSortOrder; + else + Context->SortOrder = DescendingSortOrder; + } + + PhTnpSetColumnHeaderSortIcon(Context, NewColumn); + + Context->Callback(Context->Handle, TreeNewSortChanged, NULL, NULL, Context->CallbackContext); +} + +BOOLEAN PhTnpSetColumnHeaderSortIcon( + _In_ PPH_TREENEW_CONTEXT Context, + _In_opt_ PPH_TREENEW_COLUMN SortColumnPointer + ) +{ + if (Context->SortOrder == NoSortOrder) + { + PhSetHeaderSortIcon( + Context->FixedHeaderHandle, + -1, + NoSortOrder + ); + PhSetHeaderSortIcon( + Context->HeaderHandle, + -1, + NoSortOrder + ); + + return TRUE; + } + + if (!SortColumnPointer) + { + if (!(SortColumnPointer = PhTnpLookupColumnById(Context, Context->SortColumn))) + return FALSE; + } + + if (SortColumnPointer->Fixed) + { + PhSetHeaderSortIcon( + Context->FixedHeaderHandle, + 0, + Context->SortOrder + ); + PhSetHeaderSortIcon( + Context->HeaderHandle, + -1, + NoSortOrder + ); + } + else + { + PhSetHeaderSortIcon( + Context->FixedHeaderHandle, + -1, + NoSortOrder + ); + PhSetHeaderSortIcon( + Context->HeaderHandle, + SortColumnPointer->s.ViewIndex, + Context->SortOrder + ); + } + + return TRUE; +} + +VOID PhTnpAutoSizeColumnHeader( + _In_ PPH_TREENEW_CONTEXT Context, + _In_ HWND HeaderHandle, + _In_ PPH_TREENEW_COLUMN Column, + _In_ ULONG Flags + ) +{ + LONG newWidth; + HDITEM item; + + if (Flags & TN_AUTOSIZE_REMAINING_SPACE) + { + newWidth = Context->ClientRect.right - (Context->TotalViewX - Column->Width); + + if (Context->FixedColumn) + newWidth -= Context->FixedColumn->Width; + if (Context->VScrollVisible) + newWidth -= Context->VScrollWidth; + + if (newWidth <= 0) + return; + } + else + { + ULONG i; + LONG maximumWidth; + PH_TREENEW_CELL_PARTS parts; + LONG width; + + if (Context->FlatList->Count == 0) + return; + if (Column->CustomDraw) + return; + + maximumWidth = 0; + + for (i = 0; i < Context->FlatList->Count; i++) + { + if (PhTnpGetCellParts(Context, i, Column, TN_MEASURE_TEXT, &parts) && + (parts.Flags & TN_PART_CELL) && (parts.Flags & TN_PART_CONTENT) && (parts.Flags & TN_PART_TEXT)) + { + width = parts.TextRect.right - parts.TextRect.left; // text width + width += parts.ContentRect.left - parts.CellRect.left; // left padding + + if (maximumWidth < width) + maximumWidth = width; + } + } + + newWidth = maximumWidth + TNP_CELL_RIGHT_MARGIN; // right padding + + if (Column->Fixed) + newWidth++; + } + + item.mask = HDI_WIDTH; + item.cxy = newWidth; + + Header_SetItem(HeaderHandle, Column->s.ViewIndex, &item); +} + +BOOLEAN PhTnpGetNodeChildren( + _In_ PPH_TREENEW_CONTEXT Context, + _In_opt_ PPH_TREENEW_NODE Node, + _Out_ PPH_TREENEW_NODE **Children, + _Out_ PULONG NumberOfChildren + ) +{ + PH_TREENEW_GET_CHILDREN getChildren; + + getChildren.Flags = 0; + getChildren.Node = Node; + getChildren.Children = NULL; + getChildren.NumberOfChildren = 0; + + if (Context->Callback( + Context->Handle, + TreeNewGetChildren, + &getChildren, + NULL, + Context->CallbackContext + )) + { + *Children = getChildren.Children; + *NumberOfChildren = getChildren.NumberOfChildren; + + return TRUE; + } + + return FALSE; +} + +BOOLEAN PhTnpIsNodeLeaf( + _In_ PPH_TREENEW_CONTEXT Context, + _In_ PPH_TREENEW_NODE Node + ) +{ + PH_TREENEW_IS_LEAF isLeaf; + + isLeaf.Flags = 0; + isLeaf.Node = Node; + isLeaf.IsLeaf = TRUE; + + if (Context->Callback( + Context->Handle, + TreeNewIsLeaf, + &isLeaf, + NULL, + Context->CallbackContext + )) + { + return isLeaf.IsLeaf; + } + + // Doesn't matter, decide when we do the get-children callback. + return FALSE; +} + +BOOLEAN PhTnpGetCellText( + _In_ PPH_TREENEW_CONTEXT Context, + _In_ PPH_TREENEW_NODE Node, + _In_ ULONG Id, + _Out_ PPH_STRINGREF Text + ) +{ + PH_TREENEW_GET_CELL_TEXT getCellText; + + if (Id < Node->TextCacheSize && Node->TextCache[Id].Buffer) + { + *Text = Node->TextCache[Id]; + return TRUE; + } + + getCellText.Flags = 0; + getCellText.Node = Node; + getCellText.Id = Id; + PhInitializeEmptyStringRef(&getCellText.Text); + + if (Context->Callback( + Context->Handle, + TreeNewGetCellText, + &getCellText, + NULL, + Context->CallbackContext + ) && getCellText.Text.Buffer) + { + *Text = getCellText.Text; + + if ((getCellText.Flags & TN_CACHE) && Id < Node->TextCacheSize) + Node->TextCache[Id] = getCellText.Text; + + return TRUE; + } + + return FALSE; +} + +VOID PhTnpRestructureNodes( + _In_ PPH_TREENEW_CONTEXT Context + ) +{ + PPH_TREENEW_NODE *children; + ULONG numberOfChildren; + ULONG i; + + if (!PhTnpGetNodeChildren(Context, NULL, &children, &numberOfChildren)) + return; + + // We try to preserve the hot node, the focused node and the selection mark node. At this point + // all node pointers must be regarded as invalid, so we must not follow any pointers. + + Context->FocusNodeFound = FALSE; + + PhClearList(Context->FlatList); + Context->CanAnyExpand = FALSE; + + for (i = 0; i < numberOfChildren; i++) + { + PhTnpInsertNodeChildren(Context, children[i], 0); + } + + if (!Context->FocusNodeFound) + Context->FocusNode = NULL; // focused node is no longer present + + if (Context->HotNodeIndex >= Context->FlatList->Count) // covers -1 case as well + Context->HotNodeIndex = -1; + + if (Context->MarkNodeIndex >= Context->FlatList->Count) + Context->MarkNodeIndex = -1; +} + +VOID PhTnpInsertNodeChildren( + _In_ PPH_TREENEW_CONTEXT Context, + _In_ PPH_TREENEW_NODE Node, + _In_ ULONG Level + ) +{ + PPH_TREENEW_NODE *children; + ULONG numberOfChildren; + ULONG i; + ULONG nextLevel; + + if (Node->Visible) + { + Node->Level = Level; + + Node->Index = Context->FlatList->Count; + PhAddItemList(Context->FlatList, Node); + + if (Context->FocusNode == Node) + Context->FocusNodeFound = TRUE; + + nextLevel = Level + 1; + } + else + { + nextLevel = 0; // children of this node should be level 0 + } + + if (!(Node->s.IsLeaf = PhTnpIsNodeLeaf(Context, Node))) + { + Context->CanAnyExpand = TRUE; + + if (Node->Expanded) + { + if (PhTnpGetNodeChildren(Context, Node, &children, &numberOfChildren)) + { + for (i = 0; i < numberOfChildren; i++) + { + PhTnpInsertNodeChildren(Context, children[i], nextLevel); + } + + if (numberOfChildren == 0) + Node->s.IsLeaf = TRUE; + } + } + } +} + +VOID PhTnpSetExpandedNode( + _In_ PPH_TREENEW_CONTEXT Context, + _In_ PPH_TREENEW_NODE Node, + _In_ BOOLEAN Expanded + ) +{ + if (Node->Expanded != Expanded) + { + PH_TREENEW_NODE_EVENT nodeEvent; + + memset(&nodeEvent, 0, sizeof(PH_TREENEW_NODE_EVENT)); + Context->Callback(Context->Handle, TreeNewNodeExpanding, Node, &nodeEvent, Context->CallbackContext); + + if (!nodeEvent.Handled) + { + if (!Expanded) + { + ULONG i; + PPH_TREENEW_NODE node; + BOOLEAN changed; + + // Make sure no children are selected - we don't want invisible selected nodes. Note + // that this does not cause any UI changes by itself, since we are hiding the nodes. + + changed = FALSE; + + for (i = Node->Index + 1; i < Context->FlatList->Count; i++) + { + node = Context->FlatList->Items[i]; + + if (node->Level <= Node->Level) + break; // no more children + + if (node->Selected) + { + node->Selected = FALSE; + changed = TRUE; + } + } + + if (changed) + { + Context->Callback(Context->Handle, TreeNewSelectionChanged, NULL, NULL, Context->CallbackContext); + } + } + + Node->Expanded = Expanded; + PhTnpRestructureNodes(Context); + // We need to update the window before the scrollbars get updated in order for the + // scroll processing to work properly. + InvalidateRect(Context->Handle, NULL, FALSE); + UpdateWindow(Context->Handle); + PhTnpLayout(Context); + } + } +} + +BOOLEAN PhTnpGetCellParts( + _In_ PPH_TREENEW_CONTEXT Context, + _In_ ULONG Index, + _In_opt_ PPH_TREENEW_COLUMN Column, + _In_ ULONG Flags, + _Out_ PPH_TREENEW_CELL_PARTS Parts + ) +{ + PPH_TREENEW_NODE node; + LONG viewWidth; + LONG nodeY; + LONG iconVerticalMargin; + LONG currentX; + + if (Index >= Context->FlatList->Count) + return FALSE; + + node = Context->FlatList->Items[Index]; + nodeY = Context->HeaderHeight + ((LONG)Index - Context->VScrollPosition) * Context->RowHeight; + + Parts->Flags = 0; + Parts->RowRect.left = 0; + Parts->RowRect.right = Context->NormalLeft + Context->TotalViewX - Context->HScrollPosition; + Parts->RowRect.top = nodeY; + Parts->RowRect.bottom = nodeY + Context->RowHeight; + + viewWidth = Context->ClientRect.right - (Context->VScrollVisible ? Context->VScrollWidth : 0); + + if (Parts->RowRect.right > viewWidth) + Parts->RowRect.right = viewWidth; + + if (!Column) + return TRUE; + if (!Column->Visible) + return FALSE; + + iconVerticalMargin = (Context->RowHeight - SmallIconHeight) / 2; + + if (Column->Fixed) + { + currentX = 0; + } + else + { + currentX = Context->NormalLeft + Column->s.ViewX - Context->HScrollPosition; + } + + Parts->Flags |= TN_PART_CELL; + Parts->CellRect.left = currentX; + Parts->CellRect.right = currentX + Column->Width; + Parts->CellRect.top = Parts->RowRect.top; + Parts->CellRect.bottom = Parts->RowRect.bottom; + + currentX += TNP_CELL_LEFT_MARGIN; + + if (Column == Context->FirstColumn) + { + currentX += (LONG)node->Level * SmallIconWidth; + + if (Context->CanAnyExpand) + { + if (!node->s.IsLeaf) + { + Parts->Flags |= TN_PART_PLUSMINUS; + Parts->PlusMinusRect.left = currentX; + Parts->PlusMinusRect.right = currentX + SmallIconWidth; + Parts->PlusMinusRect.top = Parts->RowRect.top + iconVerticalMargin; + Parts->PlusMinusRect.bottom = Parts->RowRect.bottom - iconVerticalMargin; + } + + currentX += SmallIconWidth; + } + + if (node->Icon) + { + Parts->Flags |= TN_PART_ICON; + Parts->IconRect.left = currentX; + Parts->IconRect.right = currentX + SmallIconWidth; + Parts->IconRect.top = Parts->RowRect.top + iconVerticalMargin; + Parts->IconRect.bottom = Parts->RowRect.bottom - iconVerticalMargin; + + currentX += SmallIconWidth + TNP_ICON_RIGHT_PADDING; + } + } + + Parts->Flags |= TN_PART_CONTENT; + Parts->ContentRect.left = currentX; + Parts->ContentRect.right = Parts->CellRect.right - TNP_CELL_RIGHT_MARGIN; + Parts->ContentRect.top = Parts->RowRect.top; + Parts->ContentRect.bottom = Parts->RowRect.bottom; + + if (Flags & TN_MEASURE_TEXT) + { + HDC hdc; + PH_STRINGREF text; + HFONT font; + SIZE textSize; + + if (hdc = GetDC(Context->Handle)) + { + PhTnpPrepareRowForDraw(Context, hdc, node); + + if (PhTnpGetCellText(Context, node, Column->Id, &text)) + { + if (node->Font) + font = node->Font; + else + font = Context->Font; + + SelectObject(hdc, font); + + if (GetTextExtentPoint32(hdc, text.Buffer, (ULONG)text.Length / sizeof(WCHAR), &textSize)) + { + Parts->Flags |= TN_PART_TEXT; + Parts->TextRect.left = currentX; + Parts->TextRect.right = currentX + textSize.cx; + Parts->TextRect.top = Parts->RowRect.top + (Context->RowHeight - textSize.cy) / 2; + Parts->TextRect.bottom = Parts->RowRect.bottom - (Context->RowHeight - textSize.cy) / 2; + + if (Column->TextFlags & DT_CENTER) + { + Parts->TextRect.left = Parts->ContentRect.left / 2 + (Parts->ContentRect.right - textSize.cx) / 2; + Parts->TextRect.right = Parts->ContentRect.left + textSize.cx; + } + else if (Column->TextFlags & DT_RIGHT) + { + Parts->TextRect.right = Parts->ContentRect.right; + Parts->TextRect.left = Parts->TextRect.right - textSize.cx; + } + + Parts->Text = text; + Parts->Font = font; + } + } + + ReleaseDC(Context->Handle, hdc); + } + } + + return TRUE; +} + +BOOLEAN PhTnpGetRowRects( + _In_ PPH_TREENEW_CONTEXT Context, + _In_ ULONG Start, + _In_ ULONG End, + _In_ BOOLEAN Clip, + _Out_ PRECT Rect + ) +{ + LONG startY; + LONG endY; + LONG viewWidth; + + if (End >= Context->FlatList->Count) + return FALSE; + if (Start > End) + return FALSE; + + startY = Context->HeaderHeight + ((LONG)Start - Context->VScrollPosition) * Context->RowHeight; + endY = Context->HeaderHeight + ((LONG)End - Context->VScrollPosition) * Context->RowHeight; + + Rect->left = 0; + Rect->right = Context->NormalLeft + Context->TotalViewX - Context->HScrollPosition; + Rect->top = startY; + Rect->bottom = endY + Context->RowHeight; + + viewWidth = Context->ClientRect.right - (Context->VScrollVisible ? Context->VScrollWidth : 0); + + if (Rect->right > viewWidth) + Rect->right = viewWidth; + + if (Clip) + { + if (Rect->top < Context->HeaderHeight) + Rect->top = Context->HeaderHeight; + if (Rect->bottom > Context->ClientRect.bottom) + Rect->bottom = Context->ClientRect.bottom; + } + + return TRUE; +} + +VOID PhTnpHitTest( + _In_ PPH_TREENEW_CONTEXT Context, + _Inout_ PPH_TREENEW_HIT_TEST HitTest + ) +{ + RECT clientRect; + LONG x; + LONG y; + ULONG index; + PPH_TREENEW_NODE node; + + HitTest->Flags = 0; + HitTest->Node = NULL; + HitTest->Column = NULL; + + clientRect = Context->ClientRect; + x = HitTest->Point.x; + y = HitTest->Point.y; + + if (x < 0) + HitTest->Flags |= TN_HIT_LEFT; + if (x >= clientRect.right) + HitTest->Flags |= TN_HIT_RIGHT; + if (y < 0) + HitTest->Flags |= TN_HIT_ABOVE; + if (y >= clientRect.bottom) + HitTest->Flags |= TN_HIT_BELOW; + + if (HitTest->Flags == 0) + { + if (TNP_HIT_TEST_FIXED_DIVIDER(x, Context)) + { + HitTest->Flags |= TN_HIT_DIVIDER; + } + + if (y >= Context->HeaderHeight && x < Context->FixedWidth + Context->TotalViewX) + { + index = (y - Context->HeaderHeight) / Context->RowHeight + Context->VScrollPosition; + + if (index < Context->FlatList->Count) + { + HitTest->Flags |= TN_HIT_ITEM; + node = Context->FlatList->Items[index]; + HitTest->Node = node; + + if (HitTest->InFlags & TN_TEST_COLUMN) + { + PPH_TREENEW_COLUMN column; + LONG columnX; + + column = NULL; + + if (x < Context->FixedWidth && Context->FixedColumnVisible) + { + column = Context->FixedColumn; + columnX = 0; + } + else + { + LONG currentX; + ULONG i; + PPH_TREENEW_COLUMN currentColumn; + + currentX = Context->NormalLeft - Context->HScrollPosition; + + for (i = 0; i < Context->NumberOfColumnsByDisplay; i++) + { + currentColumn = Context->ColumnsByDisplay[i]; + + if (x >= currentX && x < currentX + currentColumn->Width) + { + column = currentColumn; + columnX = currentX; + break; + } + + currentX += currentColumn->Width; + } + } + + HitTest->Column = column; + + if (column && (HitTest->InFlags & TN_TEST_SUBITEM)) + { + BOOLEAN isFirstColumn; + LONG currentX; + + isFirstColumn = HitTest->Column == Context->FirstColumn; + + currentX = columnX; + currentX += TNP_CELL_LEFT_MARGIN; + + if (isFirstColumn) + { + currentX += (LONG)node->Level * SmallIconWidth; + + if (!node->s.IsLeaf) + { + if (x >= currentX && x < currentX + SmallIconWidth) + HitTest->Flags |= TN_HIT_ITEM_PLUSMINUS; + + currentX += SmallIconWidth; + } + + if (node->Icon) + { + if (x >= currentX && x < currentX + SmallIconWidth) + HitTest->Flags |= TN_HIT_ITEM_ICON; + + currentX += SmallIconWidth + TNP_ICON_RIGHT_PADDING; + } + } + + if (x >= currentX) + { + HitTest->Flags |= TN_HIT_ITEM_CONTENT; + } + } + } + } + } + } +} + +VOID PhTnpSelectRange( + _In_ PPH_TREENEW_CONTEXT Context, + _In_ ULONG Start, + _In_ ULONG End, + _In_ ULONG Flags, + _Out_opt_ PULONG ChangedStart, + _Out_opt_ PULONG ChangedEnd + ) +{ + ULONG maximum; + ULONG i; + PPH_TREENEW_NODE node; + BOOLEAN targetValue; + ULONG changedStart; + ULONG changedEnd; + + if (Context->FlatList->Count == 0) + return; + + maximum = Context->FlatList->Count - 1; + + if (End > maximum) + { + End = maximum; + } + + if (Start > End) + { + // Start is too big, so the selection range becomes empty. + // Set it to max + 1 so that Reset still works. + Start = maximum + 1; + End = 0; + } + + targetValue = !(Flags & TN_SELECT_DESELECT); + changedStart = maximum; + changedEnd = 0; + + if (Flags & TN_SELECT_RESET) + { + for (i = 0; i < Start; i++) + { + node = Context->FlatList->Items[i]; + + if (node->Selected) + { + node->Selected = FALSE; + + if (changedStart > i) + changedStart = i; + if (changedEnd < i) + changedEnd = i; + } + } + } + + for (i = Start; i <= End; i++) + { + node = Context->FlatList->Items[i]; + + if (!node->Unselectable && ((Flags & TN_SELECT_TOGGLE) || node->Selected != targetValue)) + { + node->Selected = !node->Selected; + + if (changedStart > i) + changedStart = i; + if (changedEnd < i) + changedEnd = i; + } + } + + if (Flags & TN_SELECT_RESET) + { + for (i = End + 1; i <= maximum; i++) + { + node = Context->FlatList->Items[i]; + + if (node->Selected) + { + node->Selected = FALSE; + + if (changedStart > i) + changedStart = i; + if (changedEnd < i) + changedEnd = i; + } + } + } + + if (changedStart <= changedEnd) + { + Context->Callback(Context->Handle, TreeNewSelectionChanged, NULL, NULL, Context->CallbackContext); + } + + if (ChangedStart) + *ChangedStart = changedStart; + if (ChangedEnd) + *ChangedEnd = changedEnd; +} + +VOID PhTnpSetHotNode( + _In_ PPH_TREENEW_CONTEXT Context, + _In_opt_ PPH_TREENEW_NODE NewHotNode, + _In_ BOOLEAN NewPlusMinusHot + ) +{ + ULONG newHotNodeIndex; + RECT rowRect; + BOOLEAN needsInvalidate; + + if (NewHotNode) + newHotNodeIndex = NewHotNode->Index; + else + newHotNodeIndex = -1; + + needsInvalidate = FALSE; + + if (Context->HotNodeIndex != newHotNodeIndex) + { + if (Context->HotNodeIndex != -1) + { + if (Context->ThemeData && PhTnpGetRowRects(Context, Context->HotNodeIndex, Context->HotNodeIndex, TRUE, &rowRect)) + { + // Update the old hot node because it may have a different non-hot background and + // plus minus part. + InvalidateRect(Context->Handle, &rowRect, FALSE); + } + } + + Context->HotNodeIndex = newHotNodeIndex; + + if (NewHotNode) + { + needsInvalidate = TRUE; + } + } + + if (NewHotNode) + { + if (NewHotNode->s.PlusMinusHot != NewPlusMinusHot) + { + NewHotNode->s.PlusMinusHot = NewPlusMinusHot; + needsInvalidate = TRUE; + } + + if (needsInvalidate && Context->ThemeData && PhTnpGetRowRects(Context, newHotNodeIndex, newHotNodeIndex, TRUE, &rowRect)) + { + InvalidateRect(Context->Handle, &rowRect, FALSE); + } + } +} + +VOID PhTnpProcessSelectNode( + _In_ PPH_TREENEW_CONTEXT Context, + _In_ PPH_TREENEW_NODE Node, + _In_ LOGICAL ControlKey, + _In_ LOGICAL ShiftKey, + _In_ LOGICAL RightButton + ) +{ + ULONG changedStart; + ULONG changedEnd; + RECT rect; + + if (RightButton) + { + // Right button: + // If the current node is selected, then do nothing. This is to allow context menus to + // operate on multiple items. + // If the current node is not selected, select only that node. + + if (!ControlKey && !ShiftKey && !Node->Selected) + { + PhTnpSelectRange(Context, Node->Index, Node->Index, TN_SELECT_RESET, &changedStart, &changedEnd); + Context->MarkNodeIndex = Node->Index; + + if (PhTnpGetRowRects(Context, changedStart, changedEnd, TRUE, &rect)) + { + InvalidateRect(Context->Handle, &rect, FALSE); + } + } + } + else if (ShiftKey && Context->MarkNodeIndex != -1) + { + ULONG start; + ULONG end; + + // Shift key: select a range from the selection mark node to the current node. + + if (Node->Index > Context->MarkNodeIndex) + { + start = Context->MarkNodeIndex; + end = Node->Index; + } + else + { + start = Node->Index; + end = Context->MarkNodeIndex; + } + + PhTnpSelectRange(Context, start, end, TN_SELECT_RESET, &changedStart, &changedEnd); + + if (PhTnpGetRowRects(Context, changedStart, changedEnd, TRUE, &rect)) + { + InvalidateRect(Context->Handle, &rect, FALSE); + } + } + else if (ControlKey) + { + // Control key: toggle the selection on the current node, and also make it the selection + // mark. + + PhTnpSelectRange(Context, Node->Index, Node->Index, TN_SELECT_TOGGLE, NULL, NULL); + Context->MarkNodeIndex = Node->Index; + + if (PhTnpGetRowRects(Context, Node->Index, Node->Index, TRUE, &rect)) + { + InvalidateRect(Context->Handle, &rect, FALSE); + } + } + else + { + // Normal: select the current node, and also make it the selection mark. + + PhTnpSelectRange(Context, Node->Index, Node->Index, TN_SELECT_RESET, &changedStart, &changedEnd); + Context->MarkNodeIndex = Node->Index; + + if (PhTnpGetRowRects(Context, changedStart, changedEnd, TRUE, &rect)) + { + InvalidateRect(Context->Handle, &rect, FALSE); + } + } +} + +BOOLEAN PhTnpEnsureVisibleNode( + _In_ PPH_TREENEW_CONTEXT Context, + _In_ ULONG Index + ) +{ + LONG viewTop; + LONG viewBottom; + LONG rowTop; + LONG rowBottom; + LONG deltaY; + LONG deltaRows; + + if (Index >= Context->FlatList->Count) + return FALSE; + + viewTop = Context->HeaderHeight; + viewBottom = Context->ClientRect.bottom - (Context->HScrollVisible ? Context->HScrollHeight : 0); + rowTop = Context->HeaderHeight + ((LONG)Index - Context->VScrollPosition) * Context->RowHeight; + rowBottom = rowTop + Context->RowHeight; + + // Check if the row is fully visible. + if (rowTop >= viewTop && rowBottom <= viewBottom) + return TRUE; + + deltaY = rowTop - viewTop; + + if (deltaY > 0) + { + // The row is below the view area. We want to scroll the row into view at the bottom of the + // screen. We need to round up when dividing to make sure the node becomes fully visible. + deltaY = rowBottom - viewBottom; + deltaRows = (deltaY + Context->RowHeight - 1) / Context->RowHeight; // divide, round up + } + else + { + deltaRows = deltaY / Context->RowHeight; + } + + PhTnpScroll(Context, deltaRows, 0); + + return TRUE; +} + +VOID PhTnpProcessMoveMouse( + _In_ PPH_TREENEW_CONTEXT Context, + _In_ LONG CursorX, + _In_ LONG CursorY + ) +{ + PH_TREENEW_HIT_TEST hitTest; + PPH_TREENEW_NODE hotNode; + + hitTest.Point.x = CursorX; + hitTest.Point.y = CursorY; + hitTest.InFlags = TN_TEST_COLUMN | TN_TEST_SUBITEM; + PhTnpHitTest(Context, &hitTest); + + if (hitTest.Flags & TN_HIT_ITEM) + hotNode = hitTest.Node; + else + hotNode = NULL; + + PhTnpSetHotNode(Context, hotNode, !!(hitTest.Flags & TN_HIT_ITEM_PLUSMINUS)); + + if (Context->AnimateDivider && Context->FixedDividerVisible) + { + if (hitTest.Flags & TN_HIT_DIVIDER) + { + if ((Context->DividerHot < 100 || Context->AnimateDividerFadingOut) && !Context->AnimateDividerFadingIn) + { + // Begin fading in the divider. + Context->AnimateDividerFadingIn = TRUE; + Context->AnimateDividerFadingOut = FALSE; + SetTimer(Context->Handle, TNP_TIMER_ANIMATE_DIVIDER, TNP_ANIMATE_DIVIDER_INTERVAL, NULL); + } + } + else + { + if ((Context->DividerHot != 0 || Context->AnimateDividerFadingIn) && !Context->AnimateDividerFadingOut) + { + Context->AnimateDividerFadingOut = TRUE; + Context->AnimateDividerFadingIn = FALSE; + SetTimer(Context->Handle, TNP_TIMER_ANIMATE_DIVIDER, TNP_ANIMATE_DIVIDER_INTERVAL, NULL); + } + } + } + + if (Context->TooltipsHandle) + { + ULONG index; + ULONG id; + + if (!(hitTest.Flags & TN_HIT_DIVIDER)) + { + index = hitTest.Node ? hitTest.Node->Index : -1; + id = hitTest.Column ? hitTest.Column->Id : -1; + } + else + { + index = -1; + id = -1; + } + + // This pops unnecessarily - when the cell has no tooltip text, and the user is moving the + // mouse over it. However these unnecessary calls seem to fix a certain tooltip bug (move + // the mouse around very quickly over the last column and the blank space to the right, and + // no more tooltips will appear). + if (Context->TooltipIndex != index || Context->TooltipId != id) + { + PhTnpPopTooltip(Context); + } + } +} + +VOID PhTnpProcessMouseVWheel( + _In_ PPH_TREENEW_CONTEXT Context, + _In_ LONG Distance + ) +{ + ULONG wheelScrollLines; + FLOAT linesToScroll; + LONG wholeLinesToScroll; + SCROLLINFO scrollInfo; + LONG oldPosition; + + if (!SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &wheelScrollLines, 0)) + wheelScrollLines = 3; + + // If page scrolling is enabled, use the number of visible rows. + if (wheelScrollLines == -1) + wheelScrollLines = (Context->ClientRect.bottom - Context->HeaderHeight - (Context->HScrollVisible ? Context->HScrollHeight : 0)) / Context->RowHeight; + + // Zero the remainder if the direction changed. + if ((Context->VScrollRemainder > 0) != (Distance > 0)) + Context->VScrollRemainder = 0; + + linesToScroll = (FLOAT)wheelScrollLines * Distance / WHEEL_DELTA + Context->VScrollRemainder; + wholeLinesToScroll = (LONG)linesToScroll; + Context->VScrollRemainder = linesToScroll - wholeLinesToScroll; + + scrollInfo.cbSize = sizeof(SCROLLINFO); + scrollInfo.fMask = SIF_ALL; + GetScrollInfo(Context->VScrollHandle, SB_CTL, &scrollInfo); + oldPosition = scrollInfo.nPos; + + scrollInfo.nPos += wholeLinesToScroll; + + scrollInfo.fMask = SIF_POS; + SetScrollInfo(Context->VScrollHandle, SB_CTL, &scrollInfo, TRUE); + GetScrollInfo(Context->VScrollHandle, SB_CTL, &scrollInfo); + + if (scrollInfo.nPos != oldPosition) + { + Context->VScrollPosition = scrollInfo.nPos; + PhTnpProcessScroll(Context, scrollInfo.nPos - oldPosition, 0); + + if (Context->TooltipsHandle) + { + MSG message; + POINT point; + + PhTnpPopTooltip(Context); + PhTnpGetMessagePos(Context->Handle, &point); + + if (point.x >= 0 && point.y >= 0 && point.x < Context->ClientRect.right && point.y < Context->ClientRect.bottom) + { + // Send a fake mouse move message for the new node that the mouse may be hovering over. + message.hwnd = Context->Handle; + message.message = WM_MOUSEMOVE; + message.wParam = 0; + message.lParam = MAKELPARAM(point.x, point.y); + SendMessage(Context->TooltipsHandle, TTM_RELAYEVENT, 0, (LPARAM)&message); + } + } + } +} + +VOID PhTnpProcessMouseHWheel( + _In_ PPH_TREENEW_CONTEXT Context, + _In_ LONG Distance + ) +{ + ULONG wheelScrollChars; + FLOAT pixelsToScroll; + LONG wholePixelsToScroll; + SCROLLINFO scrollInfo; + LONG oldPosition; + + if (!SystemParametersInfo(SPI_GETWHEELSCROLLCHARS, 0, &wheelScrollChars, 0)) + wheelScrollChars = 3; + + // Zero the remainder if the direction changed. + if ((Context->HScrollRemainder > 0) != (Distance > 0)) + Context->HScrollRemainder = 0; + + pixelsToScroll = (FLOAT)wheelScrollChars * Context->TextMetrics.tmAveCharWidth * Distance / WHEEL_DELTA + Context->HScrollRemainder; + wholePixelsToScroll = (LONG)pixelsToScroll; + Context->HScrollRemainder = pixelsToScroll - wholePixelsToScroll; + + scrollInfo.cbSize = sizeof(SCROLLINFO); + scrollInfo.fMask = SIF_ALL; + GetScrollInfo(Context->HScrollHandle, SB_CTL, &scrollInfo); + oldPosition = scrollInfo.nPos; + + scrollInfo.nPos += wholePixelsToScroll; + + scrollInfo.fMask = SIF_POS; + SetScrollInfo(Context->HScrollHandle, SB_CTL, &scrollInfo, TRUE); + GetScrollInfo(Context->HScrollHandle, SB_CTL, &scrollInfo); + + if (scrollInfo.nPos != oldPosition) + { + Context->HScrollPosition = scrollInfo.nPos; + PhTnpProcessScroll(Context, 0, scrollInfo.nPos - oldPosition); + } +} + +BOOLEAN PhTnpProcessFocusKey( + _In_ PPH_TREENEW_CONTEXT Context, + _In_ ULONG VirtualKey + ) +{ + ULONG count; + ULONG index; + BOOLEAN controlKey; + BOOLEAN shiftKey; + ULONG start; + ULONG end; + ULONG changedStart; + ULONG changedEnd; + RECT rect; + + if (VirtualKey != VK_UP && VirtualKey != VK_DOWN && + VirtualKey != VK_HOME && VirtualKey != VK_END && + VirtualKey != VK_PRIOR && VirtualKey != VK_NEXT) + { + return FALSE; + } + + count = Context->FlatList->Count; + + if (count == 0) + return TRUE; + + // Find the new node to focus. + + switch (VirtualKey) + { + case VK_UP: + { + if (Context->FocusNode && Context->FocusNode->Index > 0) + { + index = Context->FocusNode->Index - 1; + } + else + { + index = 0; + } + } + break; + case VK_DOWN: + { + if (Context->FocusNode) + { + index = Context->FocusNode->Index + 1; + + if (index >= count) + index = count - 1; + } + else + { + index = 0; + } + } + break; + case VK_HOME: + index = 0; + break; + case VK_END: + index = count - 1; + break; + case VK_PRIOR: + case VK_NEXT: + { + LONG rowsPerPage; + + if (Context->FocusNode) + index = Context->FocusNode->Index; + else + index = 0; + + rowsPerPage = Context->ClientRect.bottom - Context->HeaderHeight - (Context->HScrollVisible ? Context->HScrollHeight : 0); + + if (rowsPerPage < 0) + return TRUE; + + rowsPerPage = rowsPerPage / Context->RowHeight - 1; + + if (rowsPerPage < 0) + return TRUE; + + if (VirtualKey == VK_PRIOR) + { + ULONG startOfPageIndex; + + startOfPageIndex = Context->VScrollPosition; + + if (index > startOfPageIndex) + { + index = startOfPageIndex; + } + else + { + // Already at or before the start of the page. Go back a page. + if (index >= (ULONG)rowsPerPage) + index -= rowsPerPage; + else + index = 0; + } + } + else + { + ULONG endOfPageIndex; + + endOfPageIndex = Context->VScrollPosition + rowsPerPage; + + if (endOfPageIndex >= count) + endOfPageIndex = count - 1; + + if (index < endOfPageIndex) + { + index = endOfPageIndex; + } + else + { + // Already at or after the end of the page. Go forward a page. + index += rowsPerPage; + + if (index >= count) + index = count - 1; + } + } + } + break; + } + + // Select the relevant nodes. + + controlKey = GetKeyState(VK_CONTROL) < 0; + shiftKey = GetKeyState(VK_SHIFT) < 0; + + Context->FocusNode = Context->FlatList->Items[index]; + PhTnpSetHotNode(Context, Context->FocusNode, FALSE); + + if (shiftKey && Context->MarkNodeIndex != -1) + { + if (index > Context->MarkNodeIndex) + { + start = Context->MarkNodeIndex; + end = index; + } + else + { + start = index; + end = Context->MarkNodeIndex; + } + + PhTnpSelectRange(Context, start, end, TN_SELECT_RESET, &changedStart, &changedEnd); + + if (PhTnpGetRowRects(Context, changedStart, changedEnd, TRUE, &rect)) + { + InvalidateRect(Context->Handle, &rect, FALSE); + } + } + else if (!controlKey) + { + Context->MarkNodeIndex = Context->FocusNode->Index; + PhTnpSelectRange(Context, index, index, TN_SELECT_RESET, &changedStart, &changedEnd); + + if (PhTnpGetRowRects(Context, changedStart, changedEnd, TRUE, &rect)) + { + InvalidateRect(Context->Handle, &rect, FALSE); + } + } + + PhTnpEnsureVisibleNode(Context, index); + PhTnpPopTooltip(Context); + + return TRUE; +} + +BOOLEAN PhTnpProcessNodeKey( + _In_ PPH_TREENEW_CONTEXT Context, + _In_ ULONG VirtualKey + ) +{ + BOOLEAN controlKey; + BOOLEAN shiftKey; + ULONG changedStart; + ULONG changedEnd; + RECT rect; + + if (VirtualKey != VK_SPACE && VirtualKey != VK_LEFT && VirtualKey != VK_RIGHT && VirtualKey != VK_ADD && VirtualKey != VK_OEM_PLUS) + { + return FALSE; + } + + if (!Context->FocusNode) + return TRUE; + + controlKey = GetKeyState(VK_CONTROL) < 0; + shiftKey = GetKeyState(VK_SHIFT) < 0; + + switch (VirtualKey) + { + case VK_SPACE: + { + if (controlKey) + { + // Control key: toggle the selection on the focused node. + + Context->MarkNodeIndex = Context->FocusNode->Index; + PhTnpSelectRange(Context, Context->FocusNode->Index, Context->FocusNode->Index, TN_SELECT_TOGGLE, &changedStart, &changedEnd); + + if (PhTnpGetRowRects(Context, changedStart, changedEnd, TRUE, &rect)) + { + InvalidateRect(Context->Handle, &rect, FALSE); + } + } + else if (shiftKey) + { + ULONG start; + ULONG end; + + // Shift key: select a range from the selection mark node to the focused node. + + if (Context->FocusNode->Index > Context->MarkNodeIndex) + { + start = Context->MarkNodeIndex; + end = Context->FocusNode->Index; + } + else + { + start = Context->FocusNode->Index; + end = Context->MarkNodeIndex; + } + + PhTnpSelectRange(Context, start, end, TN_SELECT_RESET, &changedStart, &changedEnd); + + if (PhTnpGetRowRects(Context, changedStart, changedEnd, TRUE, &rect)) + { + InvalidateRect(Context->Handle, &rect, FALSE); + } + } + } + break; + case VK_LEFT: + { + ULONG i; + ULONG targetLevel; + PPH_TREENEW_NODE newNode; + + // If the node is expanded, collapse it. Otherwise, select the node's parent. + if (!Context->FocusNode->s.IsLeaf && Context->FocusNode->Expanded) + { + PhTnpSetExpandedNode(Context, Context->FocusNode, FALSE); + } + else if (Context->FocusNode->Level != 0) + { + i = Context->FocusNode->Index; + targetLevel = Context->FocusNode->Level - 1; + + while (i != 0) + { + i--; + newNode = Context->FlatList->Items[i]; + + if (newNode->Level == targetLevel) + { + Context->FocusNode = newNode; + Context->MarkNodeIndex = newNode->Index; + PhTnpEnsureVisibleNode(Context, i); + PhTnpSetHotNode(Context, newNode, FALSE); + PhTnpSelectRange(Context, i, i, TN_SELECT_RESET, &changedStart, &changedEnd); + + if (PhTnpGetRowRects(Context, changedStart, changedEnd, TRUE, &rect)) + { + InvalidateRect(Context->Handle, &rect, FALSE); + } + + PhTnpPopTooltip(Context); + + break; + } + } + } + } + break; + case VK_RIGHT: + { + PPH_TREENEW_NODE newNode; + + if (!Context->FocusNode->s.IsLeaf) + { + // If the node is collapsed, expand it. Otherwise, select the node's first child. + if (!Context->FocusNode->Expanded) + { + PhTnpSetExpandedNode(Context, Context->FocusNode, TRUE); + } + else + { + if (Context->FocusNode->Index + 1 < Context->FlatList->Count) + { + newNode = Context->FlatList->Items[Context->FocusNode->Index + 1]; + + if (newNode->Level == Context->FocusNode->Level + 1) + { + Context->FocusNode = newNode; + Context->MarkNodeIndex = newNode->Index; + PhTnpEnsureVisibleNode(Context, Context->FocusNode->Index + 1); + PhTnpSetHotNode(Context, newNode, FALSE); + PhTnpSelectRange(Context, Context->FocusNode->Index, Context->FocusNode->Index, TN_SELECT_RESET, &changedStart, &changedEnd); + + if (PhTnpGetRowRects(Context, changedStart, changedEnd, TRUE, &rect)) + { + InvalidateRect(Context->Handle, &rect, FALSE); + } + + PhTnpPopTooltip(Context); + } + } + } + } + } + break; + case VK_ADD: + case VK_OEM_PLUS: + { + if ((VirtualKey == VK_ADD && controlKey) || + (VirtualKey == VK_OEM_PLUS && controlKey && shiftKey)) + { + ULONG i; + + if (Context->FixedColumnVisible) + PhTnpAutoSizeColumnHeader(Context, Context->FixedHeaderHandle, Context->FixedColumn, 0); + + for (i = 0; i < Context->NumberOfColumnsByDisplay; i++) + PhTnpAutoSizeColumnHeader(Context, Context->HeaderHandle, Context->ColumnsByDisplay[i], 0); + } + } + break; + } + + return TRUE; +} + +VOID PhTnpProcessSearchKey( + _In_ PPH_TREENEW_CONTEXT Context, + _In_ ULONG Character + ) +{ + LONG messageTime; + BOOLEAN newSearch; + PH_TREENEW_SEARCH_EVENT searchEvent; + PPH_TREENEW_NODE foundNode; + ULONG changedStart; + ULONG changedEnd; + RECT rect; + + if (Context->FlatList->Count == 0) + return; + + messageTime = GetMessageTime(); + newSearch = FALSE; + + // Check if the search timed out. + if (messageTime - Context->SearchMessageTime > PH_TREENEW_SEARCH_TIMEOUT) + { + Context->SearchStringCount = 0; + Context->SearchFailed = FALSE; + newSearch = TRUE; + Context->SearchSingleCharMode = TRUE; + } + + Context->SearchMessageTime = messageTime; + + // Append the character to the search buffer. + + if (!Context->SearchString) + { + Context->AllocatedSearchString = 32; + Context->SearchString = PhAllocate(Context->AllocatedSearchString * sizeof(WCHAR)); + newSearch = TRUE; + Context->SearchSingleCharMode = TRUE; + } + + if (Context->SearchStringCount > PH_TREENEW_SEARCH_MAXIMUM_LENGTH) + { + // The search string has become too long. Fail the search. + if (!Context->SearchFailed) + { + MessageBeep(0); + Context->SearchFailed = TRUE; + return; + } + } + else if (Context->SearchStringCount == Context->AllocatedSearchString) + { + Context->AllocatedSearchString *= 2; + Context->SearchString = PhReAllocate(Context->SearchString, Context->AllocatedSearchString * sizeof(WCHAR)); + } + + Context->SearchString[Context->SearchStringCount++] = (WCHAR)Character; + + if (Context->SearchString[Context->SearchStringCount - 1] != Context->SearchString[0]) + { + // The user has stopped typing the same character (or never started). Turn single-character + // search off. + Context->SearchSingleCharMode = FALSE; + } + + searchEvent.FoundIndex = -1; + + if (Context->FocusNode) + { + searchEvent.StartIndex = Context->FocusNode->Index; + + if (newSearch || Context->SearchSingleCharMode) + { + // If it's a new search, start at the next item so the user doesn't find the same item + // again. + searchEvent.StartIndex++; + + if (searchEvent.StartIndex == Context->FlatList->Count) + searchEvent.StartIndex = 0; + } + } + else + { + searchEvent.StartIndex = 0; + } + + searchEvent.String.Buffer = Context->SearchString; + + if (!Context->SearchSingleCharMode) + searchEvent.String.Length = Context->SearchStringCount * sizeof(WCHAR); + else + searchEvent.String.Length = sizeof(WCHAR); + + // Give the user a chance to modify how the search is performed. + if (!Context->Callback(Context->Handle, TreeNewIncrementalSearch, &searchEvent, NULL, Context->CallbackContext)) + { + // Use the default search function. + if (!PhTnpDefaultIncrementalSearch(Context, &searchEvent, TRUE, TRUE)) + { + return; + } + } + + if (searchEvent.FoundIndex == -1 && !Context->SearchFailed) + { + // No search result. Beep to indicate an error, and set the flag so we don't beep again. But + // don't beep if the first character was a space, because that's used for other purposes + // elsewhere (see PhTnpProcessNodeKey). + if (searchEvent.String.Buffer[0] != ' ') + { + MessageBeep(0); + } + + Context->SearchFailed = TRUE; + return; + } + + if (searchEvent.FoundIndex < 0 || searchEvent.FoundIndex >= (LONG)Context->FlatList->Count) + return; + + foundNode = Context->FlatList->Items[searchEvent.FoundIndex]; + Context->FocusNode = foundNode; + PhTnpEnsureVisibleNode(Context, searchEvent.FoundIndex); + PhTnpSetHotNode(Context, foundNode, FALSE); + PhTnpSelectRange(Context, searchEvent.FoundIndex, searchEvent.FoundIndex, TN_SELECT_RESET, &changedStart, &changedEnd); + + if (PhTnpGetRowRects(Context, changedStart, changedEnd, TRUE, &rect)) + { + InvalidateRect(Context->Handle, &rect, FALSE); + } + + PhTnpPopTooltip(Context); +} + +BOOLEAN PhTnpDefaultIncrementalSearch( + _In_ PPH_TREENEW_CONTEXT Context, + _Inout_ PPH_TREENEW_SEARCH_EVENT SearchEvent, + _In_ BOOLEAN Partial, + _In_ BOOLEAN Wrap + ) +{ + LONG startIndex; + LONG currentIndex; + LONG foundIndex; + BOOLEAN firstTime; + + if (Context->FlatList->Count == 0) + return FALSE; + if (!Context->FirstColumn) + return FALSE; + + startIndex = SearchEvent->StartIndex; + currentIndex = startIndex; + foundIndex = -1; + firstTime = TRUE; + + while (TRUE) + { + PH_STRINGREF text; + + if (currentIndex >= (LONG)Context->FlatList->Count) + { + if (Wrap) + currentIndex = 0; + else + break; + } + + // We use the firstTime variable instead of a simpler check because we want to include the + // current item in the search. E.g. the current item is the only item beginning with "Z". If + // the user searches for "Z", we want to return the current item as being found. + if (!firstTime && currentIndex == startIndex) + break; + + if (PhTnpGetCellText(Context, Context->FlatList->Items[currentIndex], Context->FirstColumn->Id, &text)) + { + if (Partial) + { + if (PhStartsWithStringRef(&text, &SearchEvent->String, TRUE)) + { + foundIndex = currentIndex; + break; + } + } + else + { + if (PhEqualStringRef(&text, &SearchEvent->String, TRUE)) + { + foundIndex = currentIndex; + break; + } + } + } + + currentIndex++; + firstTime = FALSE; + } + + SearchEvent->FoundIndex = foundIndex; + + return TRUE; +} + +VOID PhTnpUpdateScrollBars( + _In_ PPH_TREENEW_CONTEXT Context + ) +{ + RECT clientRect; + LONG width; + LONG height; + LONG contentWidth; + LONG contentHeight; + SCROLLINFO scrollInfo; + LONG oldPosition; + LONG deltaRows; + LONG deltaX; + LOGICAL oldHScrollVisible; + RECT rect; + + clientRect = Context->ClientRect; + width = clientRect.right - Context->FixedWidth; + height = clientRect.bottom - Context->HeaderHeight; + + contentWidth = Context->TotalViewX; + contentHeight = (LONG)Context->FlatList->Count * Context->RowHeight; + + if (contentHeight > height) + { + // We need a vertical scrollbar, so we can't use that area of the screen for content. + width -= Context->VScrollWidth; + } + + if (contentWidth > width) + { + height -= Context->HScrollHeight; + } + + deltaRows = 0; + deltaX = 0; + + // Vertical scroll bar + + scrollInfo.cbSize = sizeof(SCROLLINFO); + scrollInfo.fMask = SIF_POS; + GetScrollInfo(Context->VScrollHandle, SB_CTL, &scrollInfo); + oldPosition = scrollInfo.nPos; + + scrollInfo.fMask = SIF_RANGE | SIF_PAGE; + scrollInfo.nMin = 0; + scrollInfo.nMax = Context->FlatList->Count != 0 ? Context->FlatList->Count - 1 : 0; + scrollInfo.nPage = height / Context->RowHeight; + SetScrollInfo(Context->VScrollHandle, SB_CTL, &scrollInfo, TRUE); + + // The scroll position may have changed due to the modified scroll range. + scrollInfo.fMask = SIF_POS; + GetScrollInfo(Context->VScrollHandle, SB_CTL, &scrollInfo); + deltaRows = scrollInfo.nPos - oldPosition; + Context->VScrollPosition = scrollInfo.nPos; + + if (contentHeight > height && contentHeight != 0) + { + ShowWindow(Context->VScrollHandle, SW_SHOW); + Context->VScrollVisible = TRUE; + } + else + { + ShowWindow(Context->VScrollHandle, SW_HIDE); + Context->VScrollVisible = FALSE; + } + + // Horizontal scroll bar + + scrollInfo.cbSize = sizeof(SCROLLINFO); + scrollInfo.fMask = SIF_POS; + GetScrollInfo(Context->HScrollHandle, SB_CTL, &scrollInfo); + oldPosition = scrollInfo.nPos; + + scrollInfo.fMask = SIF_RANGE | SIF_PAGE; + scrollInfo.nMin = 0; + scrollInfo.nMax = contentWidth != 0 ? contentWidth - 1 : 0; + scrollInfo.nPage = width; + SetScrollInfo(Context->HScrollHandle, SB_CTL, &scrollInfo, TRUE); + + scrollInfo.fMask = SIF_POS; + GetScrollInfo(Context->HScrollHandle, SB_CTL, &scrollInfo); + deltaX = scrollInfo.nPos - oldPosition; + Context->HScrollPosition = scrollInfo.nPos; + + oldHScrollVisible = Context->HScrollVisible; + + if (contentWidth > width && contentWidth != 0) + { + ShowWindow(Context->HScrollHandle, SW_SHOW); + Context->HScrollVisible = TRUE; + } + else + { + ShowWindow(Context->HScrollHandle, SW_HIDE); + Context->HScrollVisible = FALSE; + } + + if ((Context->HScrollVisible != oldHScrollVisible) && Context->FixedDividerVisible && Context->AnimateDivider) + { + rect.left = Context->FixedWidth; + rect.top = Context->HeaderHeight; + rect.right = Context->FixedWidth + 1; + rect.bottom = Context->ClientRect.bottom; + InvalidateRect(Context->Handle, &rect, FALSE); + } + + if (deltaRows != 0 || deltaX != 0) + PhTnpProcessScroll(Context, deltaRows, deltaX); + + ShowWindow(Context->FillerBoxHandle, (Context->VScrollVisible && Context->HScrollVisible) ? SW_SHOW : SW_HIDE); +} + +VOID PhTnpScroll( + _In_ PPH_TREENEW_CONTEXT Context, + _In_ LONG DeltaRows, + _In_ LONG DeltaX + ) +{ + SCROLLINFO scrollInfo; + LONG oldPosition; + LONG deltaRows; + LONG deltaX; + + deltaRows = 0; + deltaX = 0; + + scrollInfo.cbSize = sizeof(SCROLLINFO); + scrollInfo.fMask = SIF_POS; + + if (DeltaRows != 0 && Context->VScrollVisible) + { + GetScrollInfo(Context->VScrollHandle, SB_CTL, &scrollInfo); + oldPosition = scrollInfo.nPos; + + if (DeltaRows == MINLONG) + scrollInfo.nPos = 0; + else if (DeltaRows == MAXLONG) + scrollInfo.nPos = Context->FlatList->Count - 1; + else + scrollInfo.nPos += DeltaRows; + + SetScrollInfo(Context->VScrollHandle, SB_CTL, &scrollInfo, TRUE); + GetScrollInfo(Context->VScrollHandle, SB_CTL, &scrollInfo); + Context->VScrollPosition = scrollInfo.nPos; + deltaRows = scrollInfo.nPos - oldPosition; + } + + if (DeltaX != 0 && Context->HScrollVisible) + { + GetScrollInfo(Context->HScrollHandle, SB_CTL, &scrollInfo); + oldPosition = scrollInfo.nPos; + + if (DeltaX == MINLONG) + scrollInfo.nPos = 0; + else if (DeltaX == MAXLONG) + scrollInfo.nPos = Context->TotalViewX; + else + scrollInfo.nPos += DeltaX; + + SetScrollInfo(Context->HScrollHandle, SB_CTL, &scrollInfo, TRUE); + GetScrollInfo(Context->HScrollHandle, SB_CTL, &scrollInfo); + Context->HScrollPosition = scrollInfo.nPos; + deltaX = scrollInfo.nPos - oldPosition; + } + + if (deltaRows != 0 || deltaX != 0) + PhTnpProcessScroll(Context, deltaRows, deltaX); +} + +VOID PhTnpProcessScroll( + _In_ PPH_TREENEW_CONTEXT Context, + _In_ LONG DeltaRows, + _In_ LONG DeltaX + ) +{ + RECT rect; + LONG deltaY; + + rect.top = Context->HeaderHeight; + rect.bottom = Context->ClientRect.bottom; + + if (DeltaX == 0) + { + rect.left = 0; + rect.right = Context->ClientRect.right - (Context->VScrollVisible ? Context->VScrollWidth : 0); + ScrollWindowEx( + Context->Handle, + 0, + -DeltaRows * Context->RowHeight, + &rect, + NULL, + NULL, + NULL, + SW_INVALIDATE + ); + } + else + { + // Don't scroll if there are no rows. This is especially important if the user wants us to + // display empty text. + if (Context->FlatList->Count != 0) + { + deltaY = DeltaRows * Context->RowHeight; + + // If we're scrolling vertically as well, we need to scroll the fixed part and the + // normal part separately. + + if (DeltaRows != 0) + { + rect.left = 0; + rect.right = Context->NormalLeft; + ScrollWindowEx( + Context->Handle, + 0, + -deltaY, + &rect, + &rect, + NULL, + NULL, + SW_INVALIDATE + ); + } + + rect.left = Context->NormalLeft; + rect.right = Context->ClientRect.right - (Context->VScrollVisible ? Context->VScrollWidth : 0); + ScrollWindowEx( + Context->Handle, + -DeltaX, + -deltaY, + &rect, + &rect, + NULL, + NULL, + SW_INVALIDATE + ); + } + + PhTnpLayoutHeader(Context); + } +} + +BOOLEAN PhTnpCanScroll( + _In_ PPH_TREENEW_CONTEXT Context, + _In_ BOOLEAN Horizontal, + _In_ BOOLEAN Positive + ) +{ + SCROLLINFO scrollInfo; + + scrollInfo.cbSize = sizeof(SCROLLINFO); + scrollInfo.fMask = SIF_RANGE | SIF_PAGE | SIF_POS; + + if (!Horizontal) + GetScrollInfo(Context->VScrollHandle, SB_CTL, &scrollInfo); + else + GetScrollInfo(Context->HScrollHandle, SB_CTL, &scrollInfo); + + if (Positive) + { + if (scrollInfo.nPage != 0) + scrollInfo.nMax -= scrollInfo.nPage - 1; + + return scrollInfo.nPos < scrollInfo.nMax; + } + else + { + return scrollInfo.nPos > scrollInfo.nMin; + } +} + +VOID PhTnpPaint( + _In_ HWND hwnd, + _In_ PPH_TREENEW_CONTEXT Context, + _In_ HDC hdc, + _In_ PRECT PaintRect + ) +{ + RECT viewRect; + LONG vScrollPosition; + LONG hScrollPosition; + LONG firstRowToUpdate; + LONG lastRowToUpdate; + LONG i; + LONG j; + PPH_TREENEW_NODE node; + PPH_TREENEW_COLUMN column; + RECT rowRect; + LONG x; + BOOLEAN fixedUpdate; + LONG normalUpdateLeftX; + LONG normalUpdateRightX; + LONG normalUpdateLeftIndex; + LONG normalUpdateRightIndex; + LONG normalTotalX; + RECT cellRect; + HBRUSH backBrush; + HRGN oldClipRegion; + + PhTnpInitializeThemeData(Context); + + viewRect = Context->ClientRect; + + if (Context->VScrollVisible) + viewRect.right -= Context->VScrollWidth; + + vScrollPosition = Context->VScrollPosition; + hScrollPosition = Context->HScrollPosition; + + // Calculate the indicies of the first and last rows that need painting. These indicies are + // relative to the top of the view area. + + firstRowToUpdate = (PaintRect->top - Context->HeaderHeight) / Context->RowHeight; + lastRowToUpdate = (PaintRect->bottom - 1 - Context->HeaderHeight) / Context->RowHeight; // minus one since bottom is exclusive + + if (firstRowToUpdate < 0) + firstRowToUpdate = 0; + + rowRect.left = 0; + rowRect.top = Context->HeaderHeight + firstRowToUpdate * Context->RowHeight; + rowRect.right = Context->NormalLeft + Context->TotalViewX - Context->HScrollPosition; + rowRect.bottom = rowRect.top + Context->RowHeight; + + // Change the indicies to absolute row indicies. + + firstRowToUpdate += vScrollPosition; + lastRowToUpdate += vScrollPosition; + + if (lastRowToUpdate >= (LONG)Context->FlatList->Count) + lastRowToUpdate = Context->FlatList->Count - 1; // becomes -1 when there are no items, handled correctly by loop below + + // Determine whether the fixed column needs painting, and which normal columns need painting. + + fixedUpdate = FALSE; + + if (Context->FixedColumnVisible && PaintRect->left < Context->FixedWidth) + fixedUpdate = TRUE; + + x = Context->NormalLeft - hScrollPosition; + normalUpdateLeftX = viewRect.right; + normalUpdateLeftIndex = 0; + normalUpdateRightX = 0; + normalUpdateRightIndex = -1; + + for (j = 0; j < (LONG)Context->NumberOfColumnsByDisplay; j++) + { + column = Context->ColumnsByDisplay[j]; + + if (x + column->Width >= Context->NormalLeft && x + column->Width > PaintRect->left && x < PaintRect->right) + { + if (normalUpdateLeftX > x) + { + normalUpdateLeftX = x; + normalUpdateLeftIndex = j; + } + + if (normalUpdateRightX < x + column->Width) + { + normalUpdateRightX = x + column->Width; + normalUpdateRightIndex = j; + } + } + + x += column->Width; + } + + normalTotalX = x; + + if (normalUpdateRightIndex >= (LONG)Context->NumberOfColumnsByDisplay) + normalUpdateRightIndex = Context->NumberOfColumnsByDisplay - 1; + + // Paint the rows. + + SelectObject(hdc, Context->Font); + SetBkMode(hdc, TRANSPARENT); + + for (i = firstRowToUpdate; i <= lastRowToUpdate; i++) + { + node = Context->FlatList->Items[i]; + + // Prepare the row for drawing. + + PhTnpPrepareRowForDraw(Context, hdc, node); + + if (node->Selected && !Context->ThemeHasItemBackground) + { + // Non-themed background + if (Context->HasFocus) + { + SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT)); + backBrush = GetSysColorBrush(COLOR_HIGHLIGHT); + } + else + { + SetTextColor(hdc, GetSysColor(COLOR_BTNTEXT)); + backBrush = GetSysColorBrush(COLOR_BTNFACE); + } + } + else + { + SetTextColor(hdc, node->s.DrawForeColor); + SetDCBrushColor(hdc, node->s.DrawBackColor); + backBrush = GetStockObject(DC_BRUSH); + } + + FillRect(hdc, &rowRect, backBrush); + + if (Context->ThemeHasItemBackground) + { + INT stateId; + + // Themed background + + if (node->Selected) + { + if (i == Context->HotNodeIndex) + stateId = TREIS_HOTSELECTED; + else if (!Context->HasFocus) + stateId = TREIS_SELECTEDNOTFOCUS; + else + stateId = TREIS_SELECTED; + } + else + { + if (i == Context->HotNodeIndex) + stateId = TREIS_HOT; + else + stateId = -1; + } + + if (stateId != -1) + { + if (!Context->FixedColumnVisible) + { + rowRect.left = Context->NormalLeft - hScrollPosition; + } + + DrawThemeBackground( + Context->ThemeData, + hdc, + TVP_TREEITEM, + stateId, + &rowRect, + PaintRect + ); + } + } + + // Paint the fixed column. + + cellRect.top = rowRect.top; + cellRect.bottom = rowRect.bottom; + + if (fixedUpdate) + { + cellRect.left = 0; + cellRect.right = Context->FixedWidth; + PhTnpDrawCell(Context, hdc, &cellRect, node, Context->FixedColumn, i, -1); + } + + // Paint the normal columns. + + if (normalUpdateLeftX < normalUpdateRightX) + { + cellRect.left = normalUpdateLeftX; + cellRect.right = cellRect.left; + + oldClipRegion = CreateRectRgn(0, 0, 0, 0); + + if (GetClipRgn(hdc, oldClipRegion) != 1) + { + DeleteObject(oldClipRegion); + oldClipRegion = NULL; + } + + IntersectClipRect(hdc, Context->NormalLeft, cellRect.top, viewRect.right, cellRect.bottom); + + for (j = normalUpdateLeftIndex; j <= normalUpdateRightIndex; j++) + { + column = Context->ColumnsByDisplay[j]; + + cellRect.left = cellRect.right; + cellRect.right = cellRect.left + column->Width; + PhTnpDrawCell(Context, hdc, &cellRect, node, column, i, j); + } + + SelectClipRgn(hdc, oldClipRegion); + + if (oldClipRegion) + { + DeleteObject(oldClipRegion); + } + } + + rowRect.top += Context->RowHeight; + rowRect.bottom += Context->RowHeight; + } + + if (lastRowToUpdate == Context->FlatList->Count - 1) // works even if there are no items + { + // Fill the rest of the space on the bottom with the window color. + rowRect.bottom = viewRect.bottom; + FillRect(hdc, &rowRect, GetSysColorBrush(COLOR_WINDOW)); + } + + if (normalTotalX < viewRect.right && viewRect.right > PaintRect->left && normalTotalX < PaintRect->right) + { + // Fill the rest of the space on the right with the window color. + rowRect.left = normalTotalX; + rowRect.top = Context->HeaderHeight; + rowRect.right = viewRect.right; + rowRect.bottom = viewRect.bottom; + FillRect(hdc, &rowRect, GetSysColorBrush(COLOR_WINDOW)); + } + + if (Context->FlatList->Count == 0 && Context->EmptyText.Length != 0) + { + RECT textRect; + + textRect.left = 20; + textRect.top = Context->HeaderHeight + 10; + textRect.right = viewRect.right - 20; + textRect.bottom = viewRect.bottom - 5; + + SetTextColor(hdc, GetSysColor(COLOR_GRAYTEXT)); + DrawText( + hdc, + Context->EmptyText.Buffer, + (ULONG)Context->EmptyText.Length / 2, + &textRect, + DT_NOPREFIX | DT_CENTER | DT_END_ELLIPSIS + ); + } + + if (Context->FixedDividerVisible && Context->FixedWidth >= PaintRect->left && Context->FixedWidth < PaintRect->right) + { + PhTnpDrawDivider(Context, hdc); + } + + if (Context->DragSelectionActive) + { + PhTnpDrawSelectionRectangle(Context, hdc, &Context->DragRect); + } +} + +VOID PhTnpPrepareRowForDraw( + _In_ PPH_TREENEW_CONTEXT Context, + _In_ HDC hdc, + _Inout_ PPH_TREENEW_NODE Node + ) +{ + if (!Node->s.CachedColorValid) + { + PH_TREENEW_GET_NODE_COLOR getNodeColor; + + getNodeColor.Flags = 0; + getNodeColor.Node = Node; + getNodeColor.BackColor = RGB(0xff, 0xff, 0xff); + getNodeColor.ForeColor = RGB(0x00, 0x00, 0x00); + + if (Context->Callback( + Context->Handle, + TreeNewGetNodeColor, + &getNodeColor, + NULL, + Context->CallbackContext + )) + { + Node->BackColor = getNodeColor.BackColor; + Node->ForeColor = getNodeColor.ForeColor; + Node->UseAutoForeColor = !!(getNodeColor.Flags & TN_AUTO_FORECOLOR); + + if (getNodeColor.Flags & TN_CACHE) + Node->s.CachedColorValid = TRUE; + } + else + { + Node->BackColor = getNodeColor.BackColor; + Node->ForeColor = getNodeColor.ForeColor; + } + } + + Node->s.DrawForeColor = Node->ForeColor; + + if (Node->UseTempBackColor) + Node->s.DrawBackColor = Node->TempBackColor; + else + Node->s.DrawBackColor = Node->BackColor; + + if (!Node->s.CachedFontValid) + { + PH_TREENEW_GET_NODE_FONT getNodeFont; + + getNodeFont.Flags = 0; + getNodeFont.Node = Node; + getNodeFont.Font = NULL; + + if (Context->Callback( + Context->Handle, + TreeNewGetNodeFont, + &getNodeFont, + NULL, + Context->CallbackContext + )) + { + Node->Font = getNodeFont.Font; + + if (getNodeFont.Flags & TN_CACHE) + Node->s.CachedFontValid = TRUE; + } + else + { + Node->Font = NULL; + } + } + + if (!Node->s.CachedIconValid) + { + PH_TREENEW_GET_NODE_ICON getNodeIcon; + + getNodeIcon.Flags = 0; + getNodeIcon.Node = Node; + getNodeIcon.Icon = NULL; + + if (Context->Callback( + Context->Handle, + TreeNewGetNodeIcon, + &getNodeIcon, + NULL, + Context->CallbackContext + )) + { + Node->Icon = getNodeIcon.Icon; + + if (getNodeIcon.Flags & TN_CACHE) + Node->s.CachedIconValid = TRUE; + } + else + { + Node->Icon = NULL; + } + } + + if (Node->UseAutoForeColor || Node->UseTempBackColor) + { + if (PhGetColorBrightness(Node->s.DrawBackColor) > 100) // slightly less than half + Node->s.DrawForeColor = RGB(0x00, 0x00, 0x00); + else + Node->s.DrawForeColor = RGB(0xff, 0xff, 0xff); + } +} + +VOID PhTnpDrawCell( + _In_ PPH_TREENEW_CONTEXT Context, + _In_ HDC hdc, + _In_ PRECT CellRect, + _In_ PPH_TREENEW_NODE Node, + _In_ PPH_TREENEW_COLUMN Column, + _In_ LONG RowIndex, + _In_ LONG ColumnIndex + ) +{ + HFONT font; // font to use + HFONT oldFont; + PH_STRINGREF text; // text to draw + RECT textRect; // working rectangle, modified as needed + ULONG textFlags; // DT_* flags + LONG iconVerticalMargin; // top/bottom margin for icons (determined using height of small icon) + + font = Node->Font; + textFlags = Column->TextFlags; + + textRect = *CellRect; + + // Initial margins used by default list view + textRect.left += TNP_CELL_LEFT_MARGIN; + textRect.right -= TNP_CELL_RIGHT_MARGIN; + + // icon margin = (height of row - height of small icon) / 2 + iconVerticalMargin = ((textRect.bottom - textRect.top) - SmallIconHeight) / 2; + + textRect.top += iconVerticalMargin; + textRect.bottom -= iconVerticalMargin; + + if (Column == Context->FirstColumn) + { + BOOLEAN needsClip; + HRGN oldClipRegion; + + textRect.left += Node->Level * SmallIconWidth; + + // The icon may need to be clipped if the column is too small. + needsClip = Column->Width < textRect.left + (Context->CanAnyExpand ? SmallIconWidth : 0) + (Node->Icon ? SmallIconWidth : 0); + + if (needsClip) + { + oldClipRegion = CreateRectRgn(0, 0, 0, 0); + + if (GetClipRgn(hdc, oldClipRegion) != 1) + { + DeleteObject(oldClipRegion); + oldClipRegion = NULL; + } + + // Clip contents to the column. + IntersectClipRect(hdc, CellRect->left, textRect.top, CellRect->right, textRect.bottom); + } + + if (Context->CanAnyExpand) // flag is used so we can avoid indenting when it's a flat list + { + BOOLEAN drewUsingTheme = FALSE; + RECT themeRect; + + if (!Node->s.IsLeaf) + { + // Draw the plus/minus glyph. + + themeRect.left = textRect.left; + themeRect.right = themeRect.left + SmallIconWidth; + themeRect.top = textRect.top; + themeRect.bottom = themeRect.top + SmallIconHeight; + + if (Context->ThemeHasGlyph) + { + INT partId; + INT stateId; + + partId = (RowIndex == Context->HotNodeIndex && Node->s.PlusMinusHot && Context->ThemeHasHotGlyph) ? TVP_HOTGLYPH : TVP_GLYPH; + stateId = Node->Expanded ? GLPS_OPENED : GLPS_CLOSED; + + if (SUCCEEDED(DrawThemeBackground( + Context->ThemeData, + hdc, + partId, + stateId, + &themeRect, + NULL + ))) + drewUsingTheme = TRUE; + } + + if (!drewUsingTheme) + { + ULONG glyphWidth; + ULONG glyphHeight; + RECT glyphRect; + + glyphWidth = SmallIconWidth / 2; + glyphHeight = SmallIconHeight / 2; + + glyphRect.left = textRect.left + (SmallIconWidth - glyphWidth) / 2; + glyphRect.right = glyphRect.left + glyphWidth; + glyphRect.top = textRect.top + (SmallIconHeight - glyphHeight) / 2; + glyphRect.bottom = glyphRect.top + glyphHeight; + + PhTnpDrawPlusMinusGlyph(hdc, &glyphRect, !Node->Expanded); + } + } + + textRect.left += SmallIconWidth; + } + + // Draw the icon. + if (Node->Icon) + { + DrawIconEx( + hdc, + textRect.left, + textRect.top, + Node->Icon, + SmallIconWidth, + SmallIconHeight, + 0, + NULL, + DI_NORMAL + ); + + textRect.left += SmallIconWidth + TNP_ICON_RIGHT_PADDING; + } + + if (needsClip) + { + SelectClipRgn(hdc, oldClipRegion); + + if (oldClipRegion) + DeleteObject(oldClipRegion); + } + + if (textRect.left > textRect.right) + textRect.left = textRect.right; + } + + if (Column->CustomDraw) + { + BOOLEAN result; + PH_TREENEW_CUSTOM_DRAW customDraw; + INT savedDc; + + customDraw.Node = Node; + customDraw.Column = Column; + customDraw.Dc = hdc; + customDraw.CellRect = *CellRect; + customDraw.TextRect = textRect; + + // Fix up the rectangles before giving them to the user. + if (customDraw.CellRect.left > customDraw.CellRect.right) + customDraw.CellRect.left = customDraw.CellRect.right; + if (customDraw.TextRect.left > customDraw.TextRect.right) + customDraw.TextRect.left = customDraw.TextRect.right; + + savedDc = SaveDC(hdc); + result = Context->Callback(Context->Handle, TreeNewCustomDraw, &customDraw, NULL, Context->CallbackContext); + RestoreDC(hdc, savedDc); + + if (result) + return; + } + + if (PhTnpGetCellText(Context, Node, Column->Id, &text)) + { + if (!(textFlags & (DT_PATH_ELLIPSIS | DT_WORD_ELLIPSIS))) + textFlags |= DT_END_ELLIPSIS; + + textFlags |= DT_NOPREFIX | DT_VCENTER | DT_SINGLELINE; + + textRect.top = CellRect->top; + textRect.bottom = CellRect->bottom; + + if (font) + oldFont = SelectObject(hdc, font); + + DrawText( + hdc, + text.Buffer, + (ULONG)text.Length / 2, + &textRect, + textFlags + ); + + if (font) + SelectObject(hdc, oldFont); + } +} + +VOID PhTnpDrawDivider( + _In_ PPH_TREENEW_CONTEXT Context, + _In_ HDC hdc + ) +{ + POINT points[2]; + + if (Context->AnimateDivider) + { + if (Context->DividerHot == 0 && !Context->HScrollVisible) + return; // divider is invisible + + if (Context->DividerHot < 100) + { + BLENDFUNCTION blendFunction; + + // We need to draw and alpha blend the divider. + // We can use the extra column allocated in the buffered context to initially draw the + // divider. + + points[0].x = Context->ClientRect.right; + points[0].y = Context->HeaderHeight; + points[1].x = Context->ClientRect.right; + points[1].y = Context->ClientRect.bottom; + SetDCPenColor(Context->BufferedContext, RGB(0x77, 0x77, 0x77)); + SelectObject(Context->BufferedContext, GetStockObject(DC_PEN)); + Polyline(Context->BufferedContext, points, 2); + + blendFunction.BlendOp = AC_SRC_OVER; + blendFunction.BlendFlags = 0; + blendFunction.AlphaFormat = 0; + + // If the horizontal scroll bar is visible, we need to display a line even if the + // divider is not hot. In this case we increase the base alpha value. + if (!Context->HScrollVisible) + blendFunction.SourceConstantAlpha = (UCHAR)(Context->DividerHot * 255 / 100); + else + blendFunction.SourceConstantAlpha = 55 + (UCHAR)(Context->DividerHot * 2); + + GdiAlphaBlend( + hdc, + Context->FixedWidth, + Context->HeaderHeight, + 1, + Context->ClientRect.bottom - Context->HeaderHeight, + Context->BufferedContext, + Context->ClientRect.right, + Context->HeaderHeight, + 1, + Context->ClientRect.bottom - Context->HeaderHeight, + blendFunction + ); + + return; + } + } + + points[0].x = Context->FixedWidth; + points[0].y = Context->HeaderHeight; + points[1].x = Context->FixedWidth; + points[1].y = Context->ClientRect.bottom; + SetDCPenColor(hdc, RGB(0x77, 0x77, 0x77)); + SelectObject(hdc, GetStockObject(DC_PEN)); + Polyline(hdc, points, 2); +} + +VOID PhTnpDrawPlusMinusGlyph( + _In_ HDC hdc, + _In_ PRECT Rect, + _In_ BOOLEAN Plus + ) +{ + INT savedDc; + ULONG width; + ULONG height; + POINT points[2]; + + savedDc = SaveDC(hdc); + + SelectObject(hdc, GetStockObject(DC_PEN)); + SetDCPenColor(hdc, RGB(0x55, 0x55, 0x55)); + SelectObject(hdc, GetStockObject(DC_BRUSH)); + SetDCBrushColor(hdc, RGB(0xff, 0xff, 0xff)); + + width = Rect->right - Rect->left; + height = Rect->bottom - Rect->top; + + // Draw the rectangle. + Rectangle(hdc, Rect->left, Rect->top, Rect->right + 1, Rect->bottom + 1); + + SetDCPenColor(hdc, RGB(0x00, 0x00, 0x00)); + + // Draw the horizontal line. + points[0].x = Rect->left + 2; + points[0].y = Rect->top + height / 2; + points[1].x = Rect->right - 2 + 1; + points[1].y = points[0].y; + Polyline(hdc, points, 2); + + if (Plus) + { + // Draw the vertical line. + points[0].x = Rect->left + width / 2; + points[0].y = Rect->top + 2; + points[1].x = points[0].x; + points[1].y = Rect->bottom - 2 + 1; + Polyline(hdc, points, 2); + } + + RestoreDC(hdc, savedDc); +} + +VOID PhTnpDrawSelectionRectangle( + _In_ PPH_TREENEW_CONTEXT Context, + _In_ HDC hdc, + _In_ PRECT Rect + ) +{ + RECT rect; + BOOLEAN drewWithAlpha; + + rect = *Rect; + + // MSDN says FrameRect/DrawFocusRect doesn't draw anything if bottom <= top or right <= left. + // That's complete rubbish. + if (rect.right - rect.left == 0 || rect.bottom - rect.top == 0) + return; + + drewWithAlpha = FALSE; + + if (Context->SelectionRectangleAlpha) + { + HDC tempDc; + BITMAPINFOHEADER header; + HBITMAP bitmap; + HBITMAP oldBitmap; + PVOID bits; + RECT tempRect; + BLENDFUNCTION blendFunction; + + tempDc = CreateCompatibleDC(hdc); + + if (tempDc) + { + memset(&header, 0, sizeof(BITMAPINFOHEADER)); + header.biSize = sizeof(BITMAPINFOHEADER); + header.biWidth = 1; + header.biHeight = 1; + header.biPlanes = 1; + header.biBitCount = 24; + bitmap = CreateDIBSection(tempDc, (BITMAPINFO *)&header, DIB_RGB_COLORS, &bits, NULL, 0); + + if (bitmap) + { + // Draw the outline of the selection rectangle. + FrameRect(hdc, &rect, GetSysColorBrush(COLOR_HIGHLIGHT)); + + // Fill in the selection rectangle. + + oldBitmap = SelectObject(tempDc, bitmap); + tempRect.left = 0; + tempRect.top = 0; + tempRect.right = 1; + tempRect.bottom = 1; + FillRect(tempDc, &tempRect, GetSysColorBrush(COLOR_HOTLIGHT)); + + blendFunction.BlendOp = AC_SRC_OVER; + blendFunction.BlendFlags = 0; + blendFunction.SourceConstantAlpha = 70; + blendFunction.AlphaFormat = 0; + + GdiAlphaBlend( + hdc, + rect.left, + rect.top, + rect.right - rect.left, + rect.bottom - rect.top, + tempDc, + 0, + 0, + 1, + 1, + blendFunction + ); + + drewWithAlpha = TRUE; + + SelectObject(tempDc, oldBitmap); + DeleteObject(bitmap); + } + + DeleteDC(tempDc); + } + } + + if (!drewWithAlpha) + { + DrawFocusRect(hdc, &rect); + } +} + +VOID PhTnpDrawThemedBorder( + _In_ PPH_TREENEW_CONTEXT Context, + _In_ HDC hdc + ) +{ + RECT windowRect; + RECT clientRect; + LONG sizingBorderWidth; + LONG borderX; + LONG borderY; + + GetWindowRect(Context->Handle, &windowRect); + windowRect.right -= windowRect.left; + windowRect.bottom -= windowRect.top; + windowRect.left = 0; + windowRect.top = 0; + + clientRect.left = windowRect.left + Context->SystemEdgeX; + clientRect.top = windowRect.top + Context->SystemEdgeY; + clientRect.right = windowRect.right - Context->SystemEdgeX; + clientRect.bottom = windowRect.bottom - Context->SystemEdgeY; + + // Make sure we don't paint in the client area. + ExcludeClipRect(hdc, clientRect.left, clientRect.top, clientRect.right, clientRect.bottom); + + // Draw the themed border. + DrawThemeBackground(Context->ThemeData, hdc, 0, 0, &windowRect, NULL); + + // Calculate the size of the border we just drew, and fill in the rest of the space if we didn't + // fully paint the region. + + if (SUCCEEDED(GetThemeInt(Context->ThemeData, 0, 0, TMT_SIZINGBORDERWIDTH, &sizingBorderWidth))) + { + borderX = sizingBorderWidth; + borderY = sizingBorderWidth; + } + else + { + borderX = Context->SystemBorderX; + borderY = Context->SystemBorderY; + } + + if (borderX < Context->SystemEdgeX || borderY < Context->SystemEdgeY) + { + windowRect.left += Context->SystemEdgeX - borderX; + windowRect.top += Context->SystemEdgeY - borderY; + windowRect.right -= Context->SystemEdgeX - borderX; + windowRect.bottom -= Context->SystemEdgeY - borderY; + FillRect(hdc, &windowRect, GetSysColorBrush(COLOR_WINDOW)); + } +} + +VOID PhTnpInitializeTooltips( + _In_ PPH_TREENEW_CONTEXT Context + ) +{ + TOOLINFO toolInfo; + + Context->TooltipsHandle = CreateWindowEx( + WS_EX_TRANSPARENT, // solves double-click problem + TOOLTIPS_CLASS, + NULL, + WS_POPUP | TTS_NOPREFIX, + 0, + 0, + 0, + 0, + NULL, + NULL, + Context->InstanceHandle, + NULL + ); + + if (!Context->TooltipsHandle) + return; + + // Item tooltips + memset(&toolInfo, 0, sizeof(TOOLINFO)); + toolInfo.cbSize = sizeof(TOOLINFO); + toolInfo.uFlags = TTF_TRANSPARENT; + toolInfo.hwnd = Context->Handle; + toolInfo.uId = TNP_TOOLTIPS_ITEM; + toolInfo.lpszText = LPSTR_TEXTCALLBACK; + toolInfo.lParam = TNP_TOOLTIPS_ITEM; + SendMessage(Context->TooltipsHandle, TTM_ADDTOOL, 0, (LPARAM)&toolInfo); + + // Fixed column tooltips + toolInfo.uFlags = 0; + toolInfo.hwnd = Context->FixedHeaderHandle; + toolInfo.uId = TNP_TOOLTIPS_FIXED_HEADER; + toolInfo.lpszText = LPSTR_TEXTCALLBACK; + toolInfo.lParam = TNP_TOOLTIPS_FIXED_HEADER; + SendMessage(Context->TooltipsHandle, TTM_ADDTOOL, 0, (LPARAM)&toolInfo); + + // Normal column tooltips + toolInfo.uFlags = 0; + toolInfo.hwnd = Context->HeaderHandle; + toolInfo.uId = TNP_TOOLTIPS_HEADER; + toolInfo.lpszText = LPSTR_TEXTCALLBACK; + toolInfo.lParam = TNP_TOOLTIPS_HEADER; + SendMessage(Context->TooltipsHandle, TTM_ADDTOOL, 0, (LPARAM)&toolInfo); + + // Hook the header control window procedures so we can forward mouse messages to the tooltip + // control. + SetWindowSubclass(Context->FixedHeaderHandle, PhTnpHeaderHookWndProc, 0, (ULONG_PTR)Context); + SetWindowSubclass(Context->HeaderHandle, PhTnpHeaderHookWndProc, 0, (ULONG_PTR)Context); + + SendMessage(Context->TooltipsHandle, TTM_SETMAXTIPWIDTH, 0, MAXSHORT); // no limit + SendMessage(Context->TooltipsHandle, WM_SETFONT, (WPARAM)Context->Font, FALSE); + Context->TooltipFont = Context->Font; +} + +VOID PhTnpGetTooltipText( + _In_ PPH_TREENEW_CONTEXT Context, + _In_ PPOINT Point, + _Out_ PWSTR *Text + ) +{ + PH_TREENEW_HIT_TEST hitTest; + BOOLEAN unfoldingTooltip; + BOOLEAN unfoldingTooltipFromViewCancelled; + PH_TREENEW_CELL_PARTS parts; + LONG viewRight; + PH_TREENEW_GET_CELL_TOOLTIP getCellTooltip; + + hitTest.Point = *Point; + hitTest.InFlags = TN_TEST_COLUMN | TN_TEST_SUBITEM; + PhTnpHitTest(Context, &hitTest); + + if (Context->DragSelectionActive) + return; + if (!(hitTest.Flags & TN_HIT_ITEM)) + return; + if (hitTest.Flags & (TN_HIT_ITEM_PLUSMINUS | TN_HIT_DIVIDER)) + return; + if (!hitTest.Column) + return; + + if (Context->TooltipIndex != hitTest.Node->Index || Context->TooltipId != hitTest.Column->Id) + { + Context->TooltipIndex = hitTest.Node->Index; + Context->TooltipId = hitTest.Column->Id; + + getCellTooltip.Flags = 0; + getCellTooltip.Node = hitTest.Node; + getCellTooltip.Column = hitTest.Column; + getCellTooltip.Unfolding = FALSE; + PhInitializeEmptyStringRef(&getCellTooltip.Text); + getCellTooltip.Font = Context->Font; + getCellTooltip.MaximumWidth = -1; + + unfoldingTooltip = FALSE; + unfoldingTooltipFromViewCancelled = FALSE; + + if (!(Context->ExtendedFlags & TN_FLAG_NO_UNFOLDING_TOOLTIPS) && + PhTnpGetCellParts(Context, hitTest.Node->Index, hitTest.Column, TN_MEASURE_TEXT, &parts) && + (parts.Flags & TN_PART_CONTENT) && (parts.Flags & TN_PART_TEXT)) + { + viewRight = Context->ClientRect.right - (Context->VScrollVisible ? Context->VScrollWidth : 0); + + // Use an unfolding tooltip if the text was truncated within the column, or the text + // extends beyond the view area in either direction. + + if (parts.TextRect.left < parts.ContentRect.left || parts.TextRect.right > parts.ContentRect.right) + { + unfoldingTooltip = TRUE; + } + else if ((!hitTest.Column->Fixed && parts.TextRect.left < Context->NormalLeft) || parts.TextRect.right > viewRight) + { + // Only show view-based unfolding tooltips if the mouse is over the text itself. + if (Point->x >= parts.TextRect.left && Point->x < parts.TextRect.right) + unfoldingTooltip = TRUE; + else + unfoldingTooltipFromViewCancelled = TRUE; + } + + if (unfoldingTooltip) + { + getCellTooltip.Unfolding = TRUE; + getCellTooltip.Text = parts.Text; + getCellTooltip.Font = parts.Font; // try to use the same font as the cell + + Context->TooltipRect = parts.TextRect; + } + } + + Context->Callback(Context->Handle, TreeNewGetCellTooltip, &getCellTooltip, NULL, Context->CallbackContext); + + Context->TooltipUnfolding = getCellTooltip.Unfolding; + + if (getCellTooltip.Text.Buffer && getCellTooltip.Text.Length != 0) + { + PhMoveReference(&Context->TooltipText, PhCreateString2(&getCellTooltip.Text)); + } + else + { + PhClearReference(&Context->TooltipText); + + if (unfoldingTooltipFromViewCancelled) + { + // We may need to show the view-based unfolding tooltip if the mouse moves over the + // text in the future. Reset the index and ID to make sure we keep checking. + Context->TooltipIndex = -1; + Context->TooltipId = -1; + } + } + + Context->NewTooltipFont = getCellTooltip.Font; + + if (!Context->NewTooltipFont) + Context->NewTooltipFont = Context->Font; + + if (getCellTooltip.MaximumWidth <= MAXSHORT) // seems to be the maximum value that the tooltip control supports + SendMessage(Context->TooltipsHandle, TTM_SETMAXTIPWIDTH, 0, getCellTooltip.MaximumWidth); + else + SendMessage(Context->TooltipsHandle, TTM_SETMAXTIPWIDTH, 0, MAXSHORT); + } + + if (Context->TooltipText) + *Text = Context->TooltipText->Buffer; +} + +BOOLEAN PhTnpPrepareTooltipShow( + _In_ PPH_TREENEW_CONTEXT Context + ) +{ + RECT rect; + + if (Context->TooltipFont != Context->NewTooltipFont) + { + Context->TooltipFont = Context->NewTooltipFont; + SendMessage(Context->TooltipsHandle, WM_SETFONT, (WPARAM)Context->TooltipFont, FALSE); + } + + if (!Context->TooltipUnfolding) + { + SetWindowPos( + Context->TooltipsHandle, + HWND_TOPMOST, + 0, + 0, + 0, + 0, + SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_HIDEWINDOW + ); + + return FALSE; + } + + rect = Context->TooltipRect; + SendMessage(Context->TooltipsHandle, TTM_ADJUSTRECT, TRUE, (LPARAM)&rect); + MapWindowPoints(Context->Handle, NULL, (POINT *)&rect, 2); + SetWindowPos( + Context->TooltipsHandle, + HWND_TOPMOST, + rect.left, + rect.top, + 0, + 0, + SWP_NOSIZE | SWP_NOACTIVATE | SWP_HIDEWINDOW + ); + + return TRUE; +} + +VOID PhTnpPrepareTooltipPop( + _In_ PPH_TREENEW_CONTEXT Context + ) +{ + Context->TooltipIndex = -1; + Context->TooltipId = -1; + Context->TooltipColumnId = -1; +} + +VOID PhTnpPopTooltip( + _In_ PPH_TREENEW_CONTEXT Context + ) +{ + if (Context->TooltipsHandle) + { + SendMessage(Context->TooltipsHandle, TTM_POP, 0, 0); + PhTnpPrepareTooltipPop(Context); + } +} + +PPH_TREENEW_COLUMN PhTnpHitTestHeader( + _In_ PPH_TREENEW_CONTEXT Context, + _In_ BOOLEAN Fixed, + _In_ PPOINT Point, + _Out_opt_ PRECT ItemRect + ) +{ + PPH_TREENEW_COLUMN column; + RECT itemRect; + + if (Fixed) + { + if (!Context->FixedColumnVisible) + return NULL; + + column = Context->FixedColumn; + + if (!Header_GetItemRect(Context->FixedHeaderHandle, 0, &itemRect)) + return NULL; + } + else + { + HDHITTESTINFO hitTestInfo; + + hitTestInfo.pt = *Point; + hitTestInfo.flags = 0; + hitTestInfo.iItem = -1; + + if (SendMessage(Context->HeaderHandle, HDM_HITTEST, 0, (LPARAM)&hitTestInfo) != -1 && hitTestInfo.iItem != -1) + { + HDITEM item; + + item.mask = HDI_LPARAM; + + if (!Header_GetItem(Context->HeaderHandle, hitTestInfo.iItem, &item)) + return NULL; + + column = (PPH_TREENEW_COLUMN)item.lParam; + + if (!Header_GetItemRect(Context->HeaderHandle, hitTestInfo.iItem, &itemRect)) + return NULL; + } + else + { + return NULL; + } + } + + if (ItemRect) + *ItemRect = itemRect; + + return column; +} + +VOID PhTnpGetHeaderTooltipText( + _In_ PPH_TREENEW_CONTEXT Context, + _In_ BOOLEAN Fixed, + _In_ PPOINT Point, + _Out_ PWSTR *Text + ) +{ + LOGICAL result; + PPH_TREENEW_COLUMN column; + RECT itemRect; + PWSTR text; + SIZE_T textCount; + HDC hdc; + SIZE textSize; + + column = PhTnpHitTestHeader(Context, Fixed, Point, &itemRect); + + if (!column) + return; + + if (Context->TooltipColumnId != column->Id) + { + // Determine if the tooltip needs to be shown. + + text = column->Text; + textCount = PhCountStringZ(text); + + if (!(hdc = GetDC(Context->Handle))) + return; + + SelectObject(hdc, Context->Font); + + result = GetTextExtentPoint32(hdc, text, (ULONG)textCount, &textSize); + ReleaseDC(Context->Handle, hdc); + + if (!result) + return; + + if (textSize.cx + 6 + 6 <= itemRect.right - itemRect.left) // HACK: Magic values (same as our cell margins?) + return; + + Context->TooltipColumnId = column->Id; + PhMoveReference(&Context->TooltipText, PhCreateStringEx(text, textCount * sizeof(WCHAR))); + } + + *Text = Context->TooltipText->Buffer; + + // Always use the default parameters for column header tooltips. + Context->NewTooltipFont = Context->Font; + Context->TooltipUnfolding = FALSE; + SendMessage(Context->TooltipsHandle, TTM_SETMAXTIPWIDTH, 0, TNP_TOOLTIPS_DEFAULT_MAXIMUM_WIDTH); +} + +LRESULT CALLBACK PhTnpHeaderHookWndProc( + _In_ HWND hwnd, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam, + _In_ UINT_PTR uIdSubclass, + _In_ ULONG_PTR dwRefData + ) +{ + PPH_TREENEW_CONTEXT context = (PPH_TREENEW_CONTEXT)dwRefData; + + switch (uMsg) + { + case WM_DESTROY: + RemoveWindowSubclass(hwnd, PhTnpHeaderHookWndProc, uIdSubclass); + break; + case WM_MOUSEMOVE: + { + POINT point; + PPH_TREENEW_COLUMN column; + ULONG id; + + point.x = GET_X_LPARAM(lParam); + point.y = GET_Y_LPARAM(lParam); + column = PhTnpHitTestHeader(context, hwnd == context->FixedHeaderHandle, &point, NULL); + + if (column) + id = column->Id; + else + id = -1; + + if (context->TooltipColumnId != id) + { + PhTnpPopTooltip(context); + } + } + break; + case WM_NOTIFY: + { + NMHDR *header = (NMHDR *)lParam; + + switch (header->code) + { + case TTN_GETDISPINFO: + { + if (header->hwndFrom == context->TooltipsHandle) + { + NMTTDISPINFO *info = (NMTTDISPINFO *)header; + POINT point; + + PhTnpGetMessagePos(hwnd, &point); + PhTnpGetHeaderTooltipText(context, info->lParam == TNP_TOOLTIPS_FIXED_HEADER, &point, &info->lpszText); + } + } + break; + case TTN_SHOW: + { + if (header->hwndFrom == context->TooltipsHandle) + { + return PhTnpPrepareTooltipShow(context); + } + } + break; + case TTN_POP: + { + if (header->hwndFrom == context->TooltipsHandle) + { + PhTnpPrepareTooltipPop(context); + } + } + break; + } + } + break; + } + + switch (uMsg) + { + case WM_MOUSEMOVE: + case WM_LBUTTONDOWN: + case WM_LBUTTONUP: + case WM_RBUTTONDOWN: + case WM_RBUTTONUP: + case WM_MBUTTONDOWN: + case WM_MBUTTONUP: + { + if (context->TooltipsHandle) + { + MSG message; + + message.hwnd = hwnd; + message.message = uMsg; + message.wParam = wParam; + message.lParam = lParam; + SendMessage(context->TooltipsHandle, TTM_RELAYEVENT, 0, (LPARAM)&message); + } + } + break; + } + + return DefSubclassProc(hwnd, uMsg, wParam, lParam); +} + +BOOLEAN PhTnpDetectDrag( + _In_ PPH_TREENEW_CONTEXT Context, + _In_ LONG CursorX, + _In_ LONG CursorY, + _In_ BOOLEAN DispatchMessages, + _Out_opt_ PULONG CancelledByMessage + ) +{ + RECT dragRect; + MSG msg; + + // Capture mouse input and see if the user moves the mouse beyond the drag rectangle. + + dragRect.left = CursorX - Context->SystemDragX; + dragRect.top = CursorY - Context->SystemDragY; + dragRect.right = CursorX + Context->SystemDragX; + dragRect.bottom = CursorY + Context->SystemDragY; + MapWindowPoints(Context->Handle, NULL, (POINT *)&dragRect, 2); + + SetCapture(Context->Handle); + + if (CancelledByMessage) + *CancelledByMessage = 0; + + do + { + // It seems that GetMessage dispatches nonqueued messages directly from kernel-mode, so we + // have to use PeekMessage and WaitMessage in order to process WM_CAPTURECHANGED messages. + if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) + { + switch (msg.message) + { + case WM_LBUTTONDOWN: + case WM_LBUTTONUP: + case WM_RBUTTONDOWN: + case WM_RBUTTONUP: + ReleaseCapture(); + + if (CancelledByMessage) + *CancelledByMessage = msg.message; + + break; + case WM_MOUSEMOVE: + if (msg.pt.x < dragRect.left || msg.pt.x >= dragRect.right || + msg.pt.y < dragRect.top || msg.pt.y >= dragRect.bottom) + { + if (IsWindow(Context->Handle)) + return TRUE; + else + return FALSE; + } + break; + default: + if (DispatchMessages) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + break; + } + } + else + { + WaitMessage(); + } + } while (IsWindow(Context->Handle) && GetCapture() == Context->Handle); + + return FALSE; +} + +VOID PhTnpDragSelect( + _In_ PPH_TREENEW_CONTEXT Context, + _In_ LONG CursorX, + _In_ LONG CursorY + ) +{ + MSG msg; + LONG cursorX; + LONG cursorY; + BOOLEAN originFixed; + RECT dragRect; + RECT oldDragRect; + RECT windowRect; + POINT cursorPoint; + BOOLEAN showContextMenu; + + cursorX = CursorX; + cursorY = CursorY; + originFixed = cursorX < Context->FixedWidth; + + dragRect.left = cursorX; + dragRect.top = cursorY; + dragRect.right = cursorX; + dragRect.bottom = cursorY; + oldDragRect = dragRect; + Context->DragRect = dragRect; + Context->DragSelectionActive = TRUE; + + if (Context->DoubleBuffered) + Context->SelectionRectangleAlpha = TRUE; + // TODO: Make sure the monitor's color depth is sufficient for alpha-blended selection + // rectangles. + + GetWindowRect(Context->Handle, &windowRect); + + cursorPoint.x = windowRect.left + cursorX; + cursorPoint.y = windowRect.top + cursorY; + + showContextMenu = FALSE; + + SetCapture(Context->Handle); + + while (TRUE) + { + if (!PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) + { + BOOLEAN leftOrRight; + BOOLEAN aboveOrBelow; + + // If the cursor is outside of the window, generate some messages so the window keeps + // scrolling. + + leftOrRight = cursorPoint.x < windowRect.left || cursorPoint.x > windowRect.right; + aboveOrBelow = cursorPoint.y < windowRect.top || cursorPoint.y > windowRect.bottom; + + if ((Context->VScrollVisible && aboveOrBelow && PhTnpCanScroll(Context, FALSE, cursorPoint.y > windowRect.bottom)) || + (Context->HScrollVisible && leftOrRight && PhTnpCanScroll(Context, TRUE, cursorPoint.x > windowRect.right))) + { + SetCursorPos(cursorPoint.x, cursorPoint.y); + } + else + { + WaitMessage(); + } + + goto EndOfLoop; + } + + cursorPoint = msg.pt; + + switch (msg.message) + { + case WM_LBUTTONDOWN: + case WM_LBUTTONUP: + case WM_RBUTTONDOWN: + case WM_MBUTTONDOWN: + case WM_MBUTTONUP: + ReleaseCapture(); + goto EndOfLoop; + case WM_RBUTTONUP: + ReleaseCapture(); + showContextMenu = TRUE; + goto EndOfLoop; + case WM_MOUSEMOVE: + { + LONG newCursorX; + LONG newCursorY; + LONG deltaRows; + LONG deltaX; + LONG oldVScrollPosition; + LONG oldHScrollPosition; + LONG newDeltaX; + LONG newDeltaY; + LONG viewLeft; + LONG viewTop; + LONG viewRight; + LONG viewBottom; + LONG temp; + RECT totalRect; + + newCursorX = GET_X_LPARAM(msg.lParam); + newCursorY = GET_Y_LPARAM(msg.lParam); + + // Scroll the window if the cursor is outside of it. + + deltaRows = 0; + deltaX = 0; + + if (Context->VScrollVisible) + { + if (cursorPoint.y < windowRect.top) + deltaRows = -(windowRect.top - cursorPoint.y + Context->RowHeight - 1) / Context->RowHeight; // scroll up + else if (cursorPoint.y >= windowRect.bottom) + deltaRows = (cursorPoint.y - windowRect.bottom + Context->RowHeight - 1) / Context->RowHeight; // scroll down + } + + if (Context->HScrollVisible) + { + if (cursorPoint.x < windowRect.left) + deltaX = -(windowRect.left - cursorPoint.x); // scroll left + else if (cursorPoint.x >= windowRect.right) + deltaX = cursorPoint.x - windowRect.right; // scroll right + } + + oldVScrollPosition = Context->VScrollPosition; + oldHScrollPosition = Context->HScrollPosition; + + if (deltaRows != 0 || deltaX != 0) + PhTnpScroll(Context, deltaRows, deltaX); + + newDeltaX = oldHScrollPosition - Context->HScrollPosition; + newDeltaY = (oldVScrollPosition - Context->VScrollPosition) * Context->RowHeight; + + // Adjust our original drag point for the scrolling. + if (!originFixed) + cursorX += newDeltaX; + cursorY += newDeltaY; + + // Adjust the old drag rectangle for the scrolling. + if (!originFixed) + oldDragRect.left += newDeltaX; + oldDragRect.top += newDeltaY; + if (!originFixed) + oldDragRect.right += newDeltaX; + oldDragRect.bottom += newDeltaY; + + // Ensure that the new cursor position is within the content area. + + viewLeft = Context->FixedColumnVisible ? 0 : -Context->HScrollPosition; + viewTop = Context->HeaderHeight - Context->VScrollPosition; + viewRight = Context->NormalLeft + Context->TotalViewX - Context->HScrollPosition; + viewBottom = Context->HeaderHeight + ((LONG)Context->FlatList->Count - Context->VScrollPosition) * Context->RowHeight; + + temp = Context->ClientRect.right - (Context->VScrollVisible ? Context->VScrollWidth : 0); + viewRight = max(viewRight, temp); + temp = Context->ClientRect.bottom - ((!Context->FixedColumnVisible && Context->HScrollVisible) ? Context->HScrollHeight : 0); + viewBottom = max(viewBottom, temp); + + if (newCursorX < viewLeft) + newCursorX = viewLeft; + if (newCursorX > viewRight) + newCursorX = viewRight; + if (newCursorY < viewTop) + newCursorY = viewTop; + if (newCursorY > viewBottom) + newCursorY = viewBottom; + + // Create the new drag rectangle. + + if (cursorX < newCursorX) + { + dragRect.left = cursorX; + dragRect.right = newCursorX; + } + else + { + dragRect.left = newCursorX; + dragRect.right = cursorX; + } + + if (cursorY < newCursorY) + { + dragRect.top = cursorY; + dragRect.bottom = newCursorY; + } + else + { + dragRect.top = newCursorY; + dragRect.bottom = cursorY; + } + + // Has anything changed from before? + if (dragRect.left == oldDragRect.left && dragRect.top == oldDragRect.top && + dragRect.right == oldDragRect.right && dragRect.bottom == oldDragRect.bottom) + { + break; + } + + Context->DragRect = dragRect; + + // Process the selection. + totalRect.left = min(dragRect.left, oldDragRect.left); + totalRect.top = min(dragRect.top, oldDragRect.top); + totalRect.right = max(dragRect.right, oldDragRect.right); + totalRect.bottom = max(dragRect.bottom, oldDragRect.bottom); + PhTnpProcessDragSelect(Context, (ULONG)msg.wParam, &oldDragRect, &dragRect, &totalRect); + + // Redraw the drag rectangle. + RedrawWindow(Context->Handle, &totalRect, NULL, RDW_INVALIDATE | RDW_UPDATENOW); + + oldDragRect = dragRect; + } + break; + case WM_MOUSELEAVE: + break; // don't process + case WM_MOUSEWHEEL: + break; // don't process + case WM_KEYDOWN: + if (msg.wParam == VK_ESCAPE) + { + ULONG changedStart; + ULONG changedEnd; + RECT rect; + + PhTnpSelectRange(Context, -1, -1, TN_SELECT_RESET, &changedStart, &changedEnd); + + if (PhTnpGetRowRects(Context, changedStart, changedEnd, TRUE, &rect)) + { + InvalidateRect(Context->Handle, &rect, FALSE); + } + + ReleaseCapture(); + } + break; // don't process + case WM_CHAR: + break; // don't process + default: + TranslateMessage(&msg); + DispatchMessage(&msg); + break; + } + +EndOfLoop: + if (GetCapture() != Context->Handle) + break; + } + + Context->DragSelectionActive = FALSE; + RedrawWindow(Context->Handle, &dragRect, NULL, RDW_INVALIDATE | RDW_UPDATENOW); + + if (showContextMenu) + { + // Display a context menu at the original drag point. + SendMessage(Context->Handle, WM_CONTEXTMENU, (WPARAM)Context->Handle, MAKELPARAM(windowRect.left + CursorX, windowRect.top + CursorY)); + } +} + +VOID PhTnpProcessDragSelect( + _In_ PPH_TREENEW_CONTEXT Context, + _In_ ULONG VirtualKeys, + _In_ PRECT OldRect, + _In_ PRECT NewRect, + _In_ PRECT TotalRect + ) +{ + LONG firstRow; + LONG lastRow; + RECT rowRect; + LONG i; + PPH_TREENEW_NODE node; + LONG changedStart; + LONG changedEnd; + RECT rect; + + // Determine which rows we need to test. The divisions below must be done on positive integers + // to ensure correct rounding. + + firstRow = (TotalRect->top - Context->HeaderHeight + Context->VScrollPosition * Context->RowHeight) / Context->RowHeight; + lastRow = (TotalRect->bottom - 1 - Context->HeaderHeight + Context->VScrollPosition * Context->RowHeight) / Context->RowHeight; + + if (firstRow < 0) + firstRow = 0; + if (lastRow >= (LONG)Context->FlatList->Count) + lastRow = Context->FlatList->Count - 1; + + rowRect.left = 0; + rowRect.top = Context->HeaderHeight + (firstRow - Context->VScrollPosition) * Context->RowHeight; + rowRect.right = Context->NormalLeft + Context->TotalViewX - Context->HScrollPosition; + rowRect.bottom = rowRect.top + Context->RowHeight; + + changedStart = lastRow; + changedEnd = firstRow; + + // Process the rows. + for (i = firstRow; i <= lastRow; i++) + { + BOOLEAN inOldRect; + BOOLEAN inNewRect; + + node = Context->FlatList->Items[i]; + + inOldRect = rowRect.top < OldRect->bottom && rowRect.bottom > OldRect->top && + rowRect.left < OldRect->right && rowRect.right > OldRect->left; + inNewRect = rowRect.top < NewRect->bottom && rowRect.bottom > NewRect->top && + rowRect.left < NewRect->right && rowRect.right > NewRect->left; + + if (VirtualKeys & MK_CONTROL) + { + if (!node->Unselectable && inOldRect != inNewRect) + { + node->Selected = !node->Selected; + + if (changedStart > i) + changedStart = i; + if (changedEnd < i) + changedEnd = i; + } + } + else + { + if (!node->Unselectable && inOldRect != inNewRect) + { + node->Selected = inNewRect; + + if (changedStart > i) + changedStart = i; + if (changedEnd < i) + changedEnd = i; + } + } + + rowRect.top = rowRect.bottom; + rowRect.bottom += Context->RowHeight; + } + + if (changedStart <= changedEnd) + { + Context->Callback(Context->Handle, TreeNewSelectionChanged, NULL, NULL, Context->CallbackContext); + } + + if (PhTnpGetRowRects(Context, changedStart, changedEnd, TRUE, &rect)) + { + InvalidateRect(Context->Handle, &rect, FALSE); + } +} + +VOID PhTnpCreateBufferedContext( + _In_ PPH_TREENEW_CONTEXT Context + ) +{ + HDC hdc; + + if (hdc = GetDC(Context->Handle)) + { + Context->BufferedContext = CreateCompatibleDC(hdc); + + if (!Context->BufferedContext) + return; + + Context->BufferedContextRect = Context->ClientRect; + Context->BufferedBitmap = CreateCompatibleBitmap( + hdc, + Context->BufferedContextRect.right + 1, // leave one extra pixel for divider animation + Context->BufferedContextRect.bottom + ); + + if (!Context->BufferedBitmap) + { + DeleteDC(Context->BufferedContext); + Context->BufferedContext = NULL; + return; + } + + ReleaseDC(Context->Handle, hdc); + Context->BufferedOldBitmap = SelectObject(Context->BufferedContext, Context->BufferedBitmap); + } +} + +VOID PhTnpDestroyBufferedContext( + _In_ PPH_TREENEW_CONTEXT Context + ) +{ + // The original bitmap must be selected back into the context, otherwise the bitmap can't be + // deleted. + SelectObject(Context->BufferedContext, Context->BufferedOldBitmap); + DeleteObject(Context->BufferedBitmap); + DeleteDC(Context->BufferedContext); + + Context->BufferedContext = NULL; + Context->BufferedBitmap = NULL; +} + +VOID PhTnpGetMessagePos( + _In_ HWND hwnd, + _Out_ PPOINT ClientPoint + ) +{ + ULONG position; + POINT point; + + position = GetMessagePos(); + point.x = GET_X_LPARAM(position); + point.y = GET_Y_LPARAM(position); + ScreenToClient(hwnd, &point); + + *ClientPoint = point; +} diff --git a/phlib/verify.c b/phlib/verify.c index 17ee9c66bce8..518076a6971f 100644 --- a/phlib/verify.c +++ b/phlib/verify.c @@ -1,671 +1,671 @@ -/* - * Process Hacker - - * image verification - * - * Copyright (C) 2009-2013 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include -#include -#include - -_CryptCATAdminCalcHashFromFileHandle CryptCATAdminCalcHashFromFileHandle; -_CryptCATAdminCalcHashFromFileHandle2 CryptCATAdminCalcHashFromFileHandle2; -_CryptCATAdminAcquireContext CryptCATAdminAcquireContext; -_CryptCATAdminAcquireContext2 CryptCATAdminAcquireContext2; -_CryptCATAdminEnumCatalogFromHash CryptCATAdminEnumCatalogFromHash; -_CryptCATCatalogInfoFromContext CryptCATCatalogInfoFromContext; -_CryptCATAdminReleaseCatalogContext CryptCATAdminReleaseCatalogContext; -_CryptCATAdminReleaseContext CryptCATAdminReleaseContext; -_WTHelperProvDataFromStateData WTHelperProvDataFromStateData_I; -_WTHelperGetProvSignerFromChain WTHelperGetProvSignerFromChain_I; -_WinVerifyTrust WinVerifyTrust_I; -_CertNameToStr CertNameToStr_I; -_CertDuplicateCertificateContext CertDuplicateCertificateContext_I; -_CertFreeCertificateContext CertFreeCertificateContext_I; -static PH_INITONCE PhpVerifyInitOnce = PH_INITONCE_INIT; - -static GUID WinTrustActionGenericVerifyV2 = WINTRUST_ACTION_GENERIC_VERIFY_V2; -static GUID DriverActionVerify = DRIVER_ACTION_VERIFY; - -static VOID PhpVerifyInitialization( - VOID - ) -{ - HMODULE wintrust; - HMODULE crypt32; - - wintrust = LoadLibrary(L"wintrust.dll"); - crypt32 = LoadLibrary(L"crypt32.dll"); - - CryptCATAdminCalcHashFromFileHandle = PhGetProcedureAddress(wintrust, "CryptCATAdminCalcHashFromFileHandle", 0); - CryptCATAdminCalcHashFromFileHandle2 = PhGetProcedureAddress(wintrust, "CryptCATAdminCalcHashFromFileHandle2", 0); - CryptCATAdminAcquireContext = PhGetProcedureAddress(wintrust, "CryptCATAdminAcquireContext", 0); - CryptCATAdminAcquireContext2 = PhGetProcedureAddress(wintrust, "CryptCATAdminAcquireContext2", 0); - CryptCATAdminEnumCatalogFromHash = PhGetProcedureAddress(wintrust, "CryptCATAdminEnumCatalogFromHash", 0); - CryptCATCatalogInfoFromContext = PhGetProcedureAddress(wintrust, "CryptCATCatalogInfoFromContext", 0); - CryptCATAdminReleaseCatalogContext = PhGetProcedureAddress(wintrust, "CryptCATAdminReleaseCatalogContext", 0); - CryptCATAdminReleaseContext = PhGetProcedureAddress(wintrust, "CryptCATAdminReleaseContext", 0); - WTHelperProvDataFromStateData_I = PhGetProcedureAddress(wintrust, "WTHelperProvDataFromStateData", 0); - WTHelperGetProvSignerFromChain_I = PhGetProcedureAddress(wintrust, "WTHelperGetProvSignerFromChain", 0); - WinVerifyTrust_I = PhGetProcedureAddress(wintrust, "WinVerifyTrust", 0); - CertNameToStr_I = PhGetProcedureAddress(crypt32, "CertNameToStrW", 0); - CertDuplicateCertificateContext_I = PhGetProcedureAddress(crypt32, "CertDuplicateCertificateContext", 0); - CertFreeCertificateContext_I = PhGetProcedureAddress(crypt32, "CertFreeCertificateContext", 0); -} - -VERIFY_RESULT PhpStatusToVerifyResult( - _In_ LONG Status - ) -{ - switch (Status) - { - case 0: - return VrTrusted; - case TRUST_E_NOSIGNATURE: - return VrNoSignature; - case CERT_E_EXPIRED: - return VrExpired; - case CERT_E_REVOKED: - return VrRevoked; - case TRUST_E_EXPLICIT_DISTRUST: - return VrDistrust; - case CRYPT_E_SECURITY_SETTINGS: - return VrSecuritySettings; - case TRUST_E_BAD_DIGEST: - return VrBadSignature; - default: - return VrSecuritySettings; - } -} - -BOOLEAN PhpGetSignaturesFromStateData( - _In_ HANDLE StateData, - _Out_ PCERT_CONTEXT **Signatures, - _Out_ PULONG NumberOfSignatures - ) -{ - PCRYPT_PROVIDER_DATA provData; - PCRYPT_PROVIDER_SGNR sgnr; - PCERT_CONTEXT *signatures; - ULONG i; - ULONG numberOfSignatures; - ULONG index; - - provData = WTHelperProvDataFromStateData_I(StateData); - - if (!provData) - { - *Signatures = NULL; - *NumberOfSignatures = 0; - return FALSE; - } - - i = 0; - numberOfSignatures = 0; - - while (sgnr = WTHelperGetProvSignerFromChain_I(provData, i, FALSE, 0)) - { - if (sgnr->csCertChain != 0) - numberOfSignatures++; - - i++; - } - - if (numberOfSignatures != 0) - { - signatures = PhAllocate(numberOfSignatures * sizeof(PCERT_CONTEXT)); - i = 0; - index = 0; - - while (sgnr = WTHelperGetProvSignerFromChain_I(provData, i, FALSE, 0)) - { - if (sgnr->csCertChain != 0) - signatures[index++] = (PCERT_CONTEXT)CertDuplicateCertificateContext_I(sgnr->pasCertChain[0].pCert); - - i++; - } - } - else - { - signatures = NULL; - } - - *Signatures = signatures; - *NumberOfSignatures = numberOfSignatures; - - return TRUE; -} - -VOID PhpViewSignerInfo( - _In_ PPH_VERIFY_FILE_INFO Information, - _In_ HANDLE StateData - ) -{ - static PH_INITONCE initOnce = PH_INITONCE_INIT; - static _CryptUIDlgViewSignerInfo cryptUIDlgViewSignerInfo; - - if (PhBeginInitOnce(&initOnce)) - { - HMODULE cryptui = LoadLibrary(L"cryptui.dll"); - - cryptUIDlgViewSignerInfo = PhGetProcedureAddress(cryptui, "CryptUIDlgViewSignerInfoW", 0); - PhEndInitOnce(&initOnce); - } - - if (cryptUIDlgViewSignerInfo) - { - CRYPTUI_VIEWSIGNERINFO_STRUCT viewSignerInfo = { sizeof(CRYPTUI_VIEWSIGNERINFO_STRUCT) }; - PCRYPT_PROVIDER_DATA provData; - PCRYPT_PROVIDER_SGNR sgnr; - - if (!(provData = WTHelperProvDataFromStateData_I(StateData))) - return; - if (!(sgnr = WTHelperGetProvSignerFromChain_I(provData, 0, FALSE, 0))) - return; - - viewSignerInfo.hwndParent = Information->hWnd; - viewSignerInfo.pSignerInfo = sgnr->psSigner; - viewSignerInfo.hMsg = provData->hMsg; - viewSignerInfo.pszOID = szOID_PKIX_KP_CODE_SIGNING; - cryptUIDlgViewSignerInfo(&viewSignerInfo); - } -} - -VERIFY_RESULT PhpVerifyFile( - _In_ PPH_VERIFY_FILE_INFO Information, - _In_ HANDLE FileHandle, - _In_ ULONG UnionChoice, - _In_ PVOID UnionData, - _In_ PGUID ActionId, - _In_opt_ PVOID PolicyCallbackData, - _Out_ PCERT_CONTEXT **Signatures, - _Out_ PULONG NumberOfSignatures - ) -{ - LONG status; - WINTRUST_DATA trustData = { 0 }; - - trustData.cbStruct = sizeof(WINTRUST_DATA); - trustData.pPolicyCallbackData = PolicyCallbackData; - trustData.dwUIChoice = WTD_UI_NONE; - trustData.fdwRevocationChecks = WTD_REVOKE_WHOLECHAIN; - trustData.dwUnionChoice = UnionChoice; - trustData.dwStateAction = WTD_STATEACTION_VERIFY; - trustData.dwProvFlags = WTD_SAFER_FLAG; - - trustData.pFile = UnionData; - - if (UnionChoice == WTD_CHOICE_CATALOG) - trustData.pCatalog = UnionData; - - if (Information->Flags & PH_VERIFY_PREVENT_NETWORK_ACCESS) - { - trustData.fdwRevocationChecks = WTD_REVOKE_NONE; - - if (WindowsVersion >= WINDOWS_VISTA) - trustData.dwProvFlags |= WTD_CACHE_ONLY_URL_RETRIEVAL; - else - trustData.dwProvFlags |= WTD_REVOCATION_CHECK_NONE; - } - - status = WinVerifyTrust_I(NULL, ActionId, &trustData); - PhpGetSignaturesFromStateData(trustData.hWVTStateData, Signatures, NumberOfSignatures); - - if (status == 0 && (Information->Flags & PH_VERIFY_VIEW_PROPERTIES)) - PhpViewSignerInfo(Information, trustData.hWVTStateData); - - // Close the state data. - trustData.dwStateAction = WTD_STATEACTION_CLOSE; - WinVerifyTrust_I(NULL, ActionId, &trustData); - - return PhpStatusToVerifyResult(status); -} - -BOOLEAN PhpCalculateFileHash( - _In_ HANDLE FileHandle, - _In_ PWSTR HashAlgorithm, - _Out_ PUCHAR *FileHash, - _Out_ PULONG FileHashLength, - _Out_ HANDLE *CatAdminHandle - ) -{ - HANDLE catAdminHandle; - PUCHAR fileHash; - ULONG fileHashLength; - - if (CryptCATAdminAcquireContext2) - { - if (!CryptCATAdminAcquireContext2(&catAdminHandle, &DriverActionVerify, HashAlgorithm, NULL, 0)) - return FALSE; - } - else - { - if (!CryptCATAdminAcquireContext(&catAdminHandle, &DriverActionVerify, 0)) - return FALSE; - } - - fileHashLength = 32; - fileHash = PhAllocate(fileHashLength); - - if (CryptCATAdminCalcHashFromFileHandle2) - { - if (!CryptCATAdminCalcHashFromFileHandle2(catAdminHandle, FileHandle, &fileHashLength, fileHash, 0)) - { - PhFree(fileHash); - fileHash = PhAllocate(fileHashLength); - - if (!CryptCATAdminCalcHashFromFileHandle2(catAdminHandle, FileHandle, &fileHashLength, fileHash, 0)) - { - CryptCATAdminReleaseContext(catAdminHandle, 0); - PhFree(fileHash); - return FALSE; - } - } - } - else - { - if (!CryptCATAdminCalcHashFromFileHandle(FileHandle, &fileHashLength, fileHash, 0)) - { - PhFree(fileHash); - fileHash = PhAllocate(fileHashLength); - - if (!CryptCATAdminCalcHashFromFileHandle(FileHandle, &fileHashLength, fileHash, 0)) - { - CryptCATAdminReleaseContext(catAdminHandle, 0); - PhFree(fileHash); - return FALSE; - } - } - } - - *FileHash = fileHash; - *FileHashLength = fileHashLength; - *CatAdminHandle = catAdminHandle; - - return TRUE; -} - -VERIFY_RESULT PhpVerifyFileFromCatalog( - _In_ PPH_VERIFY_FILE_INFO Information, - _In_ HANDLE FileHandle, - _In_opt_ PWSTR HashAlgorithm, - _Out_ PCERT_CONTEXT **Signatures, - _Out_ PULONG NumberOfSignatures - ) -{ - VERIFY_RESULT verifyResult = VrNoSignature; - PCERT_CONTEXT *signatures; - ULONG numberOfSignatures; - WINTRUST_CATALOG_INFO catalogInfo = { 0 }; - LARGE_INTEGER fileSize; - ULONG fileSizeLimit; - PUCHAR fileHash; - ULONG fileHashLength; - PPH_STRING fileHashTag; - HANDLE catAdminHandle; - HANDLE catInfoHandle; - ULONG i; - - *Signatures = NULL; - *NumberOfSignatures = 0; - - if (!NT_SUCCESS(PhGetFileSize(FileHandle, &fileSize))) - return VrNoSignature; - - signatures = NULL; - numberOfSignatures = 0; - - if (Information->FileSizeLimitForHash != -1) - { - fileSizeLimit = PH_VERIFY_DEFAULT_SIZE_LIMIT; - - if (Information->FileSizeLimitForHash != 0) - fileSizeLimit = Information->FileSizeLimitForHash; - - if (fileSize.QuadPart > fileSizeLimit) - return VrNoSignature; - } - - if (PhpCalculateFileHash(FileHandle, HashAlgorithm, &fileHash, &fileHashLength, &catAdminHandle)) - { - fileHashTag = PhBufferToHexStringEx(fileHash, fileHashLength, TRUE); - - // Search the system catalogs. - - catInfoHandle = CryptCATAdminEnumCatalogFromHash( - catAdminHandle, - fileHash, - fileHashLength, - 0, - NULL - ); - - if (catInfoHandle) - { - CATALOG_INFO ci = { 0 }; - DRIVER_VER_INFO verInfo = { 0 }; - - if (CryptCATCatalogInfoFromContext(catInfoHandle, &ci, 0)) - { - // Disable OS version checking by passing in a DRIVER_VER_INFO structure. - verInfo.cbStruct = sizeof(DRIVER_VER_INFO); - - catalogInfo.cbStruct = sizeof(catalogInfo); - catalogInfo.pcwszCatalogFilePath = ci.wszCatalogFile; - catalogInfo.pcwszMemberFilePath = Information->FileName; - catalogInfo.pcwszMemberTag = fileHashTag->Buffer; - catalogInfo.pbCalculatedFileHash = fileHash; - catalogInfo.cbCalculatedFileHash = fileHashLength; - catalogInfo.hCatAdmin = catAdminHandle; - verifyResult = PhpVerifyFile(Information, FileHandle, WTD_CHOICE_CATALOG, &catalogInfo, &DriverActionVerify, &verInfo, &signatures, &numberOfSignatures); - - if (verInfo.pcSignerCertContext) - CertFreeCertificateContext_I(verInfo.pcSignerCertContext); - } - - CryptCATAdminReleaseCatalogContext(catAdminHandle, catInfoHandle, 0); - } - else - { - // Search any user-supplied catalogs. - - for (i = 0; i < Information->NumberOfCatalogFileNames; i++) - { - PhFreeVerifySignatures(signatures, numberOfSignatures); - - catalogInfo.cbStruct = sizeof(catalogInfo); - catalogInfo.pcwszCatalogFilePath = Information->CatalogFileNames[i]; - catalogInfo.pcwszMemberFilePath = Information->FileName; - catalogInfo.pcwszMemberTag = fileHashTag->Buffer; - catalogInfo.pbCalculatedFileHash = fileHash; - catalogInfo.cbCalculatedFileHash = fileHashLength; - catalogInfo.hCatAdmin = catAdminHandle; - verifyResult = PhpVerifyFile(Information, FileHandle, WTD_CHOICE_CATALOG, &catalogInfo, &WinTrustActionGenericVerifyV2, NULL, &signatures, &numberOfSignatures); - - if (verifyResult == VrTrusted) - break; - } - } - - PhDereferenceObject(fileHashTag); - PhFree(fileHash); - CryptCATAdminReleaseContext(catAdminHandle, 0); - } - - *Signatures = signatures; - *NumberOfSignatures = numberOfSignatures; - - return verifyResult; -} - -NTSTATUS PhVerifyFileEx( - _In_ PPH_VERIFY_FILE_INFO Information, - _Out_ VERIFY_RESULT *VerifyResult, - _Out_opt_ PCERT_CONTEXT **Signatures, - _Out_opt_ PULONG NumberOfSignatures - ) -{ - NTSTATUS status; - HANDLE fileHandle; - VERIFY_RESULT verifyResult; - PCERT_CONTEXT *signatures; - ULONG numberOfSignatures; - WINTRUST_FILE_INFO fileInfo = { 0 }; - - if (PhBeginInitOnce(&PhpVerifyInitOnce)) - { - PhpVerifyInitialization(); - PhEndInitOnce(&PhpVerifyInitOnce); - } - - // Make sure we have successfully imported the required functions. - if ( - !CryptCATAdminCalcHashFromFileHandle || - !CryptCATAdminAcquireContext || - !CryptCATAdminEnumCatalogFromHash || - !CryptCATCatalogInfoFromContext || - !CryptCATAdminReleaseCatalogContext || - !CryptCATAdminReleaseContext || - !WinVerifyTrust_I || - !WTHelperProvDataFromStateData_I || - !WTHelperGetProvSignerFromChain_I || - !CertNameToStr_I || - !CertDuplicateCertificateContext_I || - !CertFreeCertificateContext_I - ) - return STATUS_NOT_SUPPORTED; - - if (!NT_SUCCESS(status = PhCreateFileWin32( - &fileHandle, - Information->FileName, - FILE_GENERIC_READ, - 0, - FILE_SHARE_READ | FILE_SHARE_DELETE, - FILE_OPEN, - FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT - ))) - return status; - - fileInfo.cbStruct = sizeof(WINTRUST_FILE_INFO); - fileInfo.pcwszFilePath = Information->FileName; - fileInfo.hFile = fileHandle; - - verifyResult = PhpVerifyFile(Information, fileHandle, WTD_CHOICE_FILE, &fileInfo, &WinTrustActionGenericVerifyV2, NULL, &signatures, &numberOfSignatures); - - if (verifyResult == VrNoSignature) - { - if (CryptCATAdminAcquireContext2 && CryptCATAdminCalcHashFromFileHandle2) - { - PhFreeVerifySignatures(signatures, numberOfSignatures); - verifyResult = PhpVerifyFileFromCatalog(Information, fileHandle, BCRYPT_SHA256_ALGORITHM, &signatures, &numberOfSignatures); - } - - if (verifyResult != VrTrusted) - { - PhFreeVerifySignatures(signatures, numberOfSignatures); - verifyResult = PhpVerifyFileFromCatalog(Information, fileHandle, NULL, &signatures, &numberOfSignatures); - } - } - - *VerifyResult = verifyResult; - - if (Signatures) - *Signatures = signatures; - else - PhFreeVerifySignatures(signatures, numberOfSignatures); - - if (NumberOfSignatures) - *NumberOfSignatures = numberOfSignatures; - - NtClose(fileHandle); - - return STATUS_SUCCESS; -} - -VOID PhFreeVerifySignatures( - _In_ PCERT_CONTEXT *Signatures, - _In_ ULONG NumberOfSignatures - ) -{ - ULONG i; - - if (Signatures) - { - for (i = 0; i < NumberOfSignatures; i++) - CertFreeCertificateContext_I(Signatures[i]); - - PhFree(Signatures); - } -} - -PPH_STRING PhpGetCertNameString( - _In_ PCERT_NAME_BLOB Blob - ) -{ - PPH_STRING string; - ULONG bufferSize; - - // CertNameToStr doesn't give us the correct buffer size unless we don't provide a buffer at - // all. - bufferSize = CertNameToStr_I( - X509_ASN_ENCODING, - Blob, - CERT_X500_NAME_STR, - NULL, - 0 - ); - - string = PhCreateStringEx(NULL, bufferSize * sizeof(WCHAR)); - CertNameToStr_I( - X509_ASN_ENCODING, - Blob, - CERT_X500_NAME_STR, - string->Buffer, - bufferSize - ); - - PhTrimToNullTerminatorString(string); - - return string; -} - -PPH_STRING PhpGetX500Value( - _In_ PPH_STRINGREF String, - _In_ PPH_STRINGREF KeyName - ) -{ - WCHAR keyNamePlusEqualsBuffer[10]; - PH_STRINGREF keyNamePlusEquals; - SIZE_T keyNameLength; - PH_STRINGREF firstPart; - PH_STRINGREF remainingPart; - - keyNameLength = KeyName->Length / sizeof(WCHAR); - assert(!(keyNameLength > sizeof(keyNamePlusEquals) / sizeof(WCHAR) - 1)); - keyNamePlusEquals.Buffer = keyNamePlusEqualsBuffer; - keyNamePlusEquals.Length = (keyNameLength + 1) * sizeof(WCHAR); - - memcpy(keyNamePlusEquals.Buffer, KeyName->Buffer, KeyName->Length); - keyNamePlusEquals.Buffer[keyNameLength] = '='; - - // Find "Key=". - - if (!PhSplitStringRefAtString(String, &keyNamePlusEquals, FALSE, &firstPart, &remainingPart)) - return NULL; - if (remainingPart.Length == 0) - return NULL; - - // Is the value quoted? If so, return the part inside the quotes. - if (remainingPart.Buffer[0] == '"') - { - PhSkipStringRef(&remainingPart, sizeof(WCHAR)); - - if (!PhSplitStringRefAtChar(&remainingPart, '"', &firstPart, &remainingPart)) - return NULL; - - return PhCreateString2(&firstPart); - } - else - { - PhSplitStringRefAtChar(&remainingPart, ',', &firstPart, &remainingPart); - - return PhCreateString2(&firstPart); - } -} - -PPH_STRING PhGetSignerNameFromCertificate( - _In_ PCERT_CONTEXT Certificate - ) -{ - PCERT_INFO certInfo; - PH_STRINGREF keyName; - PPH_STRING name; - PPH_STRING value; - - // Cert context -> Cert info - - certInfo = Certificate->pCertInfo; - - if (!certInfo) - return NULL; - - // Cert info subject -> Subject X.500 string - - name = PhpGetCertNameString(&certInfo->Subject); - - // Subject X.500 string -> CN or OU value - - PhInitializeStringRef(&keyName, L"CN"); - value = PhpGetX500Value(&name->sr, &keyName); - - if (!value) - { - PhInitializeStringRef(&keyName, L"OU"); - value = PhpGetX500Value(&name->sr, &keyName); - } - - PhDereferenceObject(name); - - return value; -} - -/** - * Verifies a file's digital signature. - * - * \param FileName A file name. - * \param SignerName A variable which receives a pointer to a string containing the signer name. You - * must free the string using PhDereferenceObject() when you no longer need it. Note that the signer - * name may be NULL if it is not valid. - * - * \return A VERIFY_RESULT value. - */ -VERIFY_RESULT PhVerifyFile( - _In_ PWSTR FileName, - _Out_opt_ PPH_STRING *SignerName - ) -{ - PH_VERIFY_FILE_INFO info = { 0 }; - VERIFY_RESULT verifyResult; - PCERT_CONTEXT *signatures; - ULONG numberOfSignatures; - - info.FileName = FileName; - info.Flags = PH_VERIFY_PREVENT_NETWORK_ACCESS; - - if (NT_SUCCESS(PhVerifyFileEx(&info, &verifyResult, &signatures, &numberOfSignatures))) - { - if (SignerName) - { - *SignerName = NULL; - - if (numberOfSignatures != 0) - *SignerName = PhGetSignerNameFromCertificate(signatures[0]); - } - - PhFreeVerifySignatures(signatures, numberOfSignatures); - return verifyResult; - } - else - { - if (SignerName) - *SignerName = NULL; - - return VrNoSignature; - } -} +/* + * Process Hacker - + * image verification + * + * Copyright (C) 2009-2013 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include +#include +#include + +_CryptCATAdminCalcHashFromFileHandle CryptCATAdminCalcHashFromFileHandle; +_CryptCATAdminCalcHashFromFileHandle2 CryptCATAdminCalcHashFromFileHandle2; +_CryptCATAdminAcquireContext CryptCATAdminAcquireContext; +_CryptCATAdminAcquireContext2 CryptCATAdminAcquireContext2; +_CryptCATAdminEnumCatalogFromHash CryptCATAdminEnumCatalogFromHash; +_CryptCATCatalogInfoFromContext CryptCATCatalogInfoFromContext; +_CryptCATAdminReleaseCatalogContext CryptCATAdminReleaseCatalogContext; +_CryptCATAdminReleaseContext CryptCATAdminReleaseContext; +_WTHelperProvDataFromStateData WTHelperProvDataFromStateData_I; +_WTHelperGetProvSignerFromChain WTHelperGetProvSignerFromChain_I; +_WinVerifyTrust WinVerifyTrust_I; +_CertNameToStr CertNameToStr_I; +_CertDuplicateCertificateContext CertDuplicateCertificateContext_I; +_CertFreeCertificateContext CertFreeCertificateContext_I; +static PH_INITONCE PhpVerifyInitOnce = PH_INITONCE_INIT; + +static GUID WinTrustActionGenericVerifyV2 = WINTRUST_ACTION_GENERIC_VERIFY_V2; +static GUID DriverActionVerify = DRIVER_ACTION_VERIFY; + +static VOID PhpVerifyInitialization( + VOID + ) +{ + HMODULE wintrust; + HMODULE crypt32; + + wintrust = LoadLibrary(L"wintrust.dll"); + crypt32 = LoadLibrary(L"crypt32.dll"); + + CryptCATAdminCalcHashFromFileHandle = PhGetProcedureAddress(wintrust, "CryptCATAdminCalcHashFromFileHandle", 0); + CryptCATAdminCalcHashFromFileHandle2 = PhGetProcedureAddress(wintrust, "CryptCATAdminCalcHashFromFileHandle2", 0); + CryptCATAdminAcquireContext = PhGetProcedureAddress(wintrust, "CryptCATAdminAcquireContext", 0); + CryptCATAdminAcquireContext2 = PhGetProcedureAddress(wintrust, "CryptCATAdminAcquireContext2", 0); + CryptCATAdminEnumCatalogFromHash = PhGetProcedureAddress(wintrust, "CryptCATAdminEnumCatalogFromHash", 0); + CryptCATCatalogInfoFromContext = PhGetProcedureAddress(wintrust, "CryptCATCatalogInfoFromContext", 0); + CryptCATAdminReleaseCatalogContext = PhGetProcedureAddress(wintrust, "CryptCATAdminReleaseCatalogContext", 0); + CryptCATAdminReleaseContext = PhGetProcedureAddress(wintrust, "CryptCATAdminReleaseContext", 0); + WTHelperProvDataFromStateData_I = PhGetProcedureAddress(wintrust, "WTHelperProvDataFromStateData", 0); + WTHelperGetProvSignerFromChain_I = PhGetProcedureAddress(wintrust, "WTHelperGetProvSignerFromChain", 0); + WinVerifyTrust_I = PhGetProcedureAddress(wintrust, "WinVerifyTrust", 0); + CertNameToStr_I = PhGetProcedureAddress(crypt32, "CertNameToStrW", 0); + CertDuplicateCertificateContext_I = PhGetProcedureAddress(crypt32, "CertDuplicateCertificateContext", 0); + CertFreeCertificateContext_I = PhGetProcedureAddress(crypt32, "CertFreeCertificateContext", 0); +} + +VERIFY_RESULT PhpStatusToVerifyResult( + _In_ LONG Status + ) +{ + switch (Status) + { + case 0: + return VrTrusted; + case TRUST_E_NOSIGNATURE: + return VrNoSignature; + case CERT_E_EXPIRED: + return VrExpired; + case CERT_E_REVOKED: + return VrRevoked; + case TRUST_E_EXPLICIT_DISTRUST: + return VrDistrust; + case CRYPT_E_SECURITY_SETTINGS: + return VrSecuritySettings; + case TRUST_E_BAD_DIGEST: + return VrBadSignature; + default: + return VrSecuritySettings; + } +} + +BOOLEAN PhpGetSignaturesFromStateData( + _In_ HANDLE StateData, + _Out_ PCERT_CONTEXT **Signatures, + _Out_ PULONG NumberOfSignatures + ) +{ + PCRYPT_PROVIDER_DATA provData; + PCRYPT_PROVIDER_SGNR sgnr; + PCERT_CONTEXT *signatures; + ULONG i; + ULONG numberOfSignatures; + ULONG index; + + provData = WTHelperProvDataFromStateData_I(StateData); + + if (!provData) + { + *Signatures = NULL; + *NumberOfSignatures = 0; + return FALSE; + } + + i = 0; + numberOfSignatures = 0; + + while (sgnr = WTHelperGetProvSignerFromChain_I(provData, i, FALSE, 0)) + { + if (sgnr->csCertChain != 0) + numberOfSignatures++; + + i++; + } + + if (numberOfSignatures != 0) + { + signatures = PhAllocate(numberOfSignatures * sizeof(PCERT_CONTEXT)); + i = 0; + index = 0; + + while (sgnr = WTHelperGetProvSignerFromChain_I(provData, i, FALSE, 0)) + { + if (sgnr->csCertChain != 0) + signatures[index++] = (PCERT_CONTEXT)CertDuplicateCertificateContext_I(sgnr->pasCertChain[0].pCert); + + i++; + } + } + else + { + signatures = NULL; + } + + *Signatures = signatures; + *NumberOfSignatures = numberOfSignatures; + + return TRUE; +} + +VOID PhpViewSignerInfo( + _In_ PPH_VERIFY_FILE_INFO Information, + _In_ HANDLE StateData + ) +{ + static PH_INITONCE initOnce = PH_INITONCE_INIT; + static _CryptUIDlgViewSignerInfo cryptUIDlgViewSignerInfo; + + if (PhBeginInitOnce(&initOnce)) + { + HMODULE cryptui = LoadLibrary(L"cryptui.dll"); + + cryptUIDlgViewSignerInfo = PhGetProcedureAddress(cryptui, "CryptUIDlgViewSignerInfoW", 0); + PhEndInitOnce(&initOnce); + } + + if (cryptUIDlgViewSignerInfo) + { + CRYPTUI_VIEWSIGNERINFO_STRUCT viewSignerInfo = { sizeof(CRYPTUI_VIEWSIGNERINFO_STRUCT) }; + PCRYPT_PROVIDER_DATA provData; + PCRYPT_PROVIDER_SGNR sgnr; + + if (!(provData = WTHelperProvDataFromStateData_I(StateData))) + return; + if (!(sgnr = WTHelperGetProvSignerFromChain_I(provData, 0, FALSE, 0))) + return; + + viewSignerInfo.hwndParent = Information->hWnd; + viewSignerInfo.pSignerInfo = sgnr->psSigner; + viewSignerInfo.hMsg = provData->hMsg; + viewSignerInfo.pszOID = szOID_PKIX_KP_CODE_SIGNING; + cryptUIDlgViewSignerInfo(&viewSignerInfo); + } +} + +VERIFY_RESULT PhpVerifyFile( + _In_ PPH_VERIFY_FILE_INFO Information, + _In_ HANDLE FileHandle, + _In_ ULONG UnionChoice, + _In_ PVOID UnionData, + _In_ PGUID ActionId, + _In_opt_ PVOID PolicyCallbackData, + _Out_ PCERT_CONTEXT **Signatures, + _Out_ PULONG NumberOfSignatures + ) +{ + LONG status; + WINTRUST_DATA trustData = { 0 }; + + trustData.cbStruct = sizeof(WINTRUST_DATA); + trustData.pPolicyCallbackData = PolicyCallbackData; + trustData.dwUIChoice = WTD_UI_NONE; + trustData.fdwRevocationChecks = WTD_REVOKE_WHOLECHAIN; + trustData.dwUnionChoice = UnionChoice; + trustData.dwStateAction = WTD_STATEACTION_VERIFY; + trustData.dwProvFlags = WTD_SAFER_FLAG; + + trustData.pFile = UnionData; + + if (UnionChoice == WTD_CHOICE_CATALOG) + trustData.pCatalog = UnionData; + + if (Information->Flags & PH_VERIFY_PREVENT_NETWORK_ACCESS) + { + trustData.fdwRevocationChecks = WTD_REVOKE_NONE; + + if (WindowsVersion >= WINDOWS_VISTA) + trustData.dwProvFlags |= WTD_CACHE_ONLY_URL_RETRIEVAL; + else + trustData.dwProvFlags |= WTD_REVOCATION_CHECK_NONE; + } + + status = WinVerifyTrust_I(NULL, ActionId, &trustData); + PhpGetSignaturesFromStateData(trustData.hWVTStateData, Signatures, NumberOfSignatures); + + if (status == 0 && (Information->Flags & PH_VERIFY_VIEW_PROPERTIES)) + PhpViewSignerInfo(Information, trustData.hWVTStateData); + + // Close the state data. + trustData.dwStateAction = WTD_STATEACTION_CLOSE; + WinVerifyTrust_I(NULL, ActionId, &trustData); + + return PhpStatusToVerifyResult(status); +} + +BOOLEAN PhpCalculateFileHash( + _In_ HANDLE FileHandle, + _In_ PWSTR HashAlgorithm, + _Out_ PUCHAR *FileHash, + _Out_ PULONG FileHashLength, + _Out_ HANDLE *CatAdminHandle + ) +{ + HANDLE catAdminHandle; + PUCHAR fileHash; + ULONG fileHashLength; + + if (CryptCATAdminAcquireContext2) + { + if (!CryptCATAdminAcquireContext2(&catAdminHandle, &DriverActionVerify, HashAlgorithm, NULL, 0)) + return FALSE; + } + else + { + if (!CryptCATAdminAcquireContext(&catAdminHandle, &DriverActionVerify, 0)) + return FALSE; + } + + fileHashLength = 32; + fileHash = PhAllocate(fileHashLength); + + if (CryptCATAdminCalcHashFromFileHandle2) + { + if (!CryptCATAdminCalcHashFromFileHandle2(catAdminHandle, FileHandle, &fileHashLength, fileHash, 0)) + { + PhFree(fileHash); + fileHash = PhAllocate(fileHashLength); + + if (!CryptCATAdminCalcHashFromFileHandle2(catAdminHandle, FileHandle, &fileHashLength, fileHash, 0)) + { + CryptCATAdminReleaseContext(catAdminHandle, 0); + PhFree(fileHash); + return FALSE; + } + } + } + else + { + if (!CryptCATAdminCalcHashFromFileHandle(FileHandle, &fileHashLength, fileHash, 0)) + { + PhFree(fileHash); + fileHash = PhAllocate(fileHashLength); + + if (!CryptCATAdminCalcHashFromFileHandle(FileHandle, &fileHashLength, fileHash, 0)) + { + CryptCATAdminReleaseContext(catAdminHandle, 0); + PhFree(fileHash); + return FALSE; + } + } + } + + *FileHash = fileHash; + *FileHashLength = fileHashLength; + *CatAdminHandle = catAdminHandle; + + return TRUE; +} + +VERIFY_RESULT PhpVerifyFileFromCatalog( + _In_ PPH_VERIFY_FILE_INFO Information, + _In_ HANDLE FileHandle, + _In_opt_ PWSTR HashAlgorithm, + _Out_ PCERT_CONTEXT **Signatures, + _Out_ PULONG NumberOfSignatures + ) +{ + VERIFY_RESULT verifyResult = VrNoSignature; + PCERT_CONTEXT *signatures; + ULONG numberOfSignatures; + WINTRUST_CATALOG_INFO catalogInfo = { 0 }; + LARGE_INTEGER fileSize; + ULONG fileSizeLimit; + PUCHAR fileHash; + ULONG fileHashLength; + PPH_STRING fileHashTag; + HANDLE catAdminHandle; + HANDLE catInfoHandle; + ULONG i; + + *Signatures = NULL; + *NumberOfSignatures = 0; + + if (!NT_SUCCESS(PhGetFileSize(FileHandle, &fileSize))) + return VrNoSignature; + + signatures = NULL; + numberOfSignatures = 0; + + if (Information->FileSizeLimitForHash != -1) + { + fileSizeLimit = PH_VERIFY_DEFAULT_SIZE_LIMIT; + + if (Information->FileSizeLimitForHash != 0) + fileSizeLimit = Information->FileSizeLimitForHash; + + if (fileSize.QuadPart > fileSizeLimit) + return VrNoSignature; + } + + if (PhpCalculateFileHash(FileHandle, HashAlgorithm, &fileHash, &fileHashLength, &catAdminHandle)) + { + fileHashTag = PhBufferToHexStringEx(fileHash, fileHashLength, TRUE); + + // Search the system catalogs. + + catInfoHandle = CryptCATAdminEnumCatalogFromHash( + catAdminHandle, + fileHash, + fileHashLength, + 0, + NULL + ); + + if (catInfoHandle) + { + CATALOG_INFO ci = { 0 }; + DRIVER_VER_INFO verInfo = { 0 }; + + if (CryptCATCatalogInfoFromContext(catInfoHandle, &ci, 0)) + { + // Disable OS version checking by passing in a DRIVER_VER_INFO structure. + verInfo.cbStruct = sizeof(DRIVER_VER_INFO); + + catalogInfo.cbStruct = sizeof(catalogInfo); + catalogInfo.pcwszCatalogFilePath = ci.wszCatalogFile; + catalogInfo.pcwszMemberFilePath = Information->FileName; + catalogInfo.pcwszMemberTag = fileHashTag->Buffer; + catalogInfo.pbCalculatedFileHash = fileHash; + catalogInfo.cbCalculatedFileHash = fileHashLength; + catalogInfo.hCatAdmin = catAdminHandle; + verifyResult = PhpVerifyFile(Information, FileHandle, WTD_CHOICE_CATALOG, &catalogInfo, &DriverActionVerify, &verInfo, &signatures, &numberOfSignatures); + + if (verInfo.pcSignerCertContext) + CertFreeCertificateContext_I(verInfo.pcSignerCertContext); + } + + CryptCATAdminReleaseCatalogContext(catAdminHandle, catInfoHandle, 0); + } + else + { + // Search any user-supplied catalogs. + + for (i = 0; i < Information->NumberOfCatalogFileNames; i++) + { + PhFreeVerifySignatures(signatures, numberOfSignatures); + + catalogInfo.cbStruct = sizeof(catalogInfo); + catalogInfo.pcwszCatalogFilePath = Information->CatalogFileNames[i]; + catalogInfo.pcwszMemberFilePath = Information->FileName; + catalogInfo.pcwszMemberTag = fileHashTag->Buffer; + catalogInfo.pbCalculatedFileHash = fileHash; + catalogInfo.cbCalculatedFileHash = fileHashLength; + catalogInfo.hCatAdmin = catAdminHandle; + verifyResult = PhpVerifyFile(Information, FileHandle, WTD_CHOICE_CATALOG, &catalogInfo, &WinTrustActionGenericVerifyV2, NULL, &signatures, &numberOfSignatures); + + if (verifyResult == VrTrusted) + break; + } + } + + PhDereferenceObject(fileHashTag); + PhFree(fileHash); + CryptCATAdminReleaseContext(catAdminHandle, 0); + } + + *Signatures = signatures; + *NumberOfSignatures = numberOfSignatures; + + return verifyResult; +} + +NTSTATUS PhVerifyFileEx( + _In_ PPH_VERIFY_FILE_INFO Information, + _Out_ VERIFY_RESULT *VerifyResult, + _Out_opt_ PCERT_CONTEXT **Signatures, + _Out_opt_ PULONG NumberOfSignatures + ) +{ + NTSTATUS status; + HANDLE fileHandle; + VERIFY_RESULT verifyResult; + PCERT_CONTEXT *signatures; + ULONG numberOfSignatures; + WINTRUST_FILE_INFO fileInfo = { 0 }; + + if (PhBeginInitOnce(&PhpVerifyInitOnce)) + { + PhpVerifyInitialization(); + PhEndInitOnce(&PhpVerifyInitOnce); + } + + // Make sure we have successfully imported the required functions. + if ( + !CryptCATAdminCalcHashFromFileHandle || + !CryptCATAdminAcquireContext || + !CryptCATAdminEnumCatalogFromHash || + !CryptCATCatalogInfoFromContext || + !CryptCATAdminReleaseCatalogContext || + !CryptCATAdminReleaseContext || + !WinVerifyTrust_I || + !WTHelperProvDataFromStateData_I || + !WTHelperGetProvSignerFromChain_I || + !CertNameToStr_I || + !CertDuplicateCertificateContext_I || + !CertFreeCertificateContext_I + ) + return STATUS_NOT_SUPPORTED; + + if (!NT_SUCCESS(status = PhCreateFileWin32( + &fileHandle, + Information->FileName, + FILE_GENERIC_READ, + 0, + FILE_SHARE_READ | FILE_SHARE_DELETE, + FILE_OPEN, + FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT + ))) + return status; + + fileInfo.cbStruct = sizeof(WINTRUST_FILE_INFO); + fileInfo.pcwszFilePath = Information->FileName; + fileInfo.hFile = fileHandle; + + verifyResult = PhpVerifyFile(Information, fileHandle, WTD_CHOICE_FILE, &fileInfo, &WinTrustActionGenericVerifyV2, NULL, &signatures, &numberOfSignatures); + + if (verifyResult == VrNoSignature) + { + if (CryptCATAdminAcquireContext2 && CryptCATAdminCalcHashFromFileHandle2) + { + PhFreeVerifySignatures(signatures, numberOfSignatures); + verifyResult = PhpVerifyFileFromCatalog(Information, fileHandle, BCRYPT_SHA256_ALGORITHM, &signatures, &numberOfSignatures); + } + + if (verifyResult != VrTrusted) + { + PhFreeVerifySignatures(signatures, numberOfSignatures); + verifyResult = PhpVerifyFileFromCatalog(Information, fileHandle, NULL, &signatures, &numberOfSignatures); + } + } + + *VerifyResult = verifyResult; + + if (Signatures) + *Signatures = signatures; + else + PhFreeVerifySignatures(signatures, numberOfSignatures); + + if (NumberOfSignatures) + *NumberOfSignatures = numberOfSignatures; + + NtClose(fileHandle); + + return STATUS_SUCCESS; +} + +VOID PhFreeVerifySignatures( + _In_ PCERT_CONTEXT *Signatures, + _In_ ULONG NumberOfSignatures + ) +{ + ULONG i; + + if (Signatures) + { + for (i = 0; i < NumberOfSignatures; i++) + CertFreeCertificateContext_I(Signatures[i]); + + PhFree(Signatures); + } +} + +PPH_STRING PhpGetCertNameString( + _In_ PCERT_NAME_BLOB Blob + ) +{ + PPH_STRING string; + ULONG bufferSize; + + // CertNameToStr doesn't give us the correct buffer size unless we don't provide a buffer at + // all. + bufferSize = CertNameToStr_I( + X509_ASN_ENCODING, + Blob, + CERT_X500_NAME_STR, + NULL, + 0 + ); + + string = PhCreateStringEx(NULL, bufferSize * sizeof(WCHAR)); + CertNameToStr_I( + X509_ASN_ENCODING, + Blob, + CERT_X500_NAME_STR, + string->Buffer, + bufferSize + ); + + PhTrimToNullTerminatorString(string); + + return string; +} + +PPH_STRING PhpGetX500Value( + _In_ PPH_STRINGREF String, + _In_ PPH_STRINGREF KeyName + ) +{ + WCHAR keyNamePlusEqualsBuffer[10]; + PH_STRINGREF keyNamePlusEquals; + SIZE_T keyNameLength; + PH_STRINGREF firstPart; + PH_STRINGREF remainingPart; + + keyNameLength = KeyName->Length / sizeof(WCHAR); + assert(!(keyNameLength > sizeof(keyNamePlusEquals) / sizeof(WCHAR) - 1)); + keyNamePlusEquals.Buffer = keyNamePlusEqualsBuffer; + keyNamePlusEquals.Length = (keyNameLength + 1) * sizeof(WCHAR); + + memcpy(keyNamePlusEquals.Buffer, KeyName->Buffer, KeyName->Length); + keyNamePlusEquals.Buffer[keyNameLength] = '='; + + // Find "Key=". + + if (!PhSplitStringRefAtString(String, &keyNamePlusEquals, FALSE, &firstPart, &remainingPart)) + return NULL; + if (remainingPart.Length == 0) + return NULL; + + // Is the value quoted? If so, return the part inside the quotes. + if (remainingPart.Buffer[0] == '"') + { + PhSkipStringRef(&remainingPart, sizeof(WCHAR)); + + if (!PhSplitStringRefAtChar(&remainingPart, '"', &firstPart, &remainingPart)) + return NULL; + + return PhCreateString2(&firstPart); + } + else + { + PhSplitStringRefAtChar(&remainingPart, ',', &firstPart, &remainingPart); + + return PhCreateString2(&firstPart); + } +} + +PPH_STRING PhGetSignerNameFromCertificate( + _In_ PCERT_CONTEXT Certificate + ) +{ + PCERT_INFO certInfo; + PH_STRINGREF keyName; + PPH_STRING name; + PPH_STRING value; + + // Cert context -> Cert info + + certInfo = Certificate->pCertInfo; + + if (!certInfo) + return NULL; + + // Cert info subject -> Subject X.500 string + + name = PhpGetCertNameString(&certInfo->Subject); + + // Subject X.500 string -> CN or OU value + + PhInitializeStringRef(&keyName, L"CN"); + value = PhpGetX500Value(&name->sr, &keyName); + + if (!value) + { + PhInitializeStringRef(&keyName, L"OU"); + value = PhpGetX500Value(&name->sr, &keyName); + } + + PhDereferenceObject(name); + + return value; +} + +/** + * Verifies a file's digital signature. + * + * \param FileName A file name. + * \param SignerName A variable which receives a pointer to a string containing the signer name. You + * must free the string using PhDereferenceObject() when you no longer need it. Note that the signer + * name may be NULL if it is not valid. + * + * \return A VERIFY_RESULT value. + */ +VERIFY_RESULT PhVerifyFile( + _In_ PWSTR FileName, + _Out_opt_ PPH_STRING *SignerName + ) +{ + PH_VERIFY_FILE_INFO info = { 0 }; + VERIFY_RESULT verifyResult; + PCERT_CONTEXT *signatures; + ULONG numberOfSignatures; + + info.FileName = FileName; + info.Flags = PH_VERIFY_PREVENT_NETWORK_ACCESS; + + if (NT_SUCCESS(PhVerifyFileEx(&info, &verifyResult, &signatures, &numberOfSignatures))) + { + if (SignerName) + { + *SignerName = NULL; + + if (numberOfSignatures != 0) + *SignerName = PhGetSignerNameFromCertificate(signatures[0]); + } + + PhFreeVerifySignatures(signatures, numberOfSignatures); + return verifyResult; + } + else + { + if (SignerName) + *SignerName = NULL; + + return VrNoSignature; + } +} diff --git a/phlib/workqueue.c b/phlib/workqueue.c index d77e8104f2ee..b0f39740670f 100644 --- a/phlib/workqueue.c +++ b/phlib/workqueue.c @@ -1,506 +1,506 @@ -/* - * Process Hacker - - * thread pool / work queue - * - * Copyright (C) 2009-2016 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include -#include - -#include - -#include - -static PH_INITONCE PhWorkQueueInitOnce = PH_INITONCE_INIT; -static PH_FREE_LIST PhWorkQueueItemFreeList; -static PH_INITONCE PhGlobalWorkQueueInitOnce = PH_INITONCE_INIT; -static PH_WORK_QUEUE PhGlobalWorkQueue; -#ifdef DEBUG -PPH_LIST PhDbgWorkQueueList; -PH_QUEUED_LOCK PhDbgWorkQueueListLock = PH_QUEUED_LOCK_INIT; -#endif - -/** - * Initializes a work queue. - * - * \param WorkQueue A work queue object. - * \param MinimumThreads The suggested minimum number of threads to keep alive, even when there is - * no work to be performed. - * \param MaximumThreads The suggested maximum number of threads to create. - * \param NoWorkTimeout The number of milliseconds after which threads without work will terminate. - */ -VOID PhInitializeWorkQueue( - _Out_ PPH_WORK_QUEUE WorkQueue, - _In_ ULONG MinimumThreads, - _In_ ULONG MaximumThreads, - _In_ ULONG NoWorkTimeout - ) -{ - if (PhBeginInitOnce(&PhWorkQueueInitOnce)) - { - PhInitializeFreeList(&PhWorkQueueItemFreeList, sizeof(PH_WORK_QUEUE_ITEM), 32); -#ifdef DEBUG - PhDbgWorkQueueList = PhCreateList(4); -#endif - - PhEndInitOnce(&PhWorkQueueInitOnce); - } - - PhInitializeRundownProtection(&WorkQueue->RundownProtect); - WorkQueue->Terminating = FALSE; - - InitializeListHead(&WorkQueue->QueueListHead); - PhInitializeQueuedLock(&WorkQueue->QueueLock); - PhInitializeCondition(&WorkQueue->QueueEmptyCondition); - - WorkQueue->MinimumThreads = MinimumThreads; - WorkQueue->MaximumThreads = MaximumThreads; - WorkQueue->NoWorkTimeout = NoWorkTimeout; - - PhInitializeQueuedLock(&WorkQueue->StateLock); - - WorkQueue->SemaphoreHandle = NULL; - WorkQueue->CurrentThreads = 0; - WorkQueue->BusyCount = 0; - -#ifdef DEBUG - PhAcquireQueuedLockExclusive(&PhDbgWorkQueueListLock); - PhAddItemList(PhDbgWorkQueueList, WorkQueue); - PhReleaseQueuedLockExclusive(&PhDbgWorkQueueListLock); -#endif -} - -/** - * Frees resources used by a work queue. - * - * \param WorkQueue A work queue object. - */ -VOID PhDeleteWorkQueue( - _Inout_ PPH_WORK_QUEUE WorkQueue - ) -{ - PLIST_ENTRY listEntry; - PPH_WORK_QUEUE_ITEM workQueueItem; -#ifdef DEBUG - ULONG index; -#endif - -#ifdef DEBUG - PhAcquireQueuedLockExclusive(&PhDbgWorkQueueListLock); - if ((index = PhFindItemList(PhDbgWorkQueueList, WorkQueue)) != -1) - PhRemoveItemList(PhDbgWorkQueueList, index); - PhReleaseQueuedLockExclusive(&PhDbgWorkQueueListLock); -#endif - - // Wait for all worker threads to exit. - - WorkQueue->Terminating = TRUE; - MemoryBarrier(); - - if (WorkQueue->SemaphoreHandle) - NtReleaseSemaphore(WorkQueue->SemaphoreHandle, WorkQueue->CurrentThreads, NULL); - - PhWaitForRundownProtection(&WorkQueue->RundownProtect); - - // Free all un-executed work items. - - listEntry = WorkQueue->QueueListHead.Flink; - - while (listEntry != &WorkQueue->QueueListHead) - { - workQueueItem = CONTAINING_RECORD(listEntry, PH_WORK_QUEUE_ITEM, ListEntry); - listEntry = listEntry->Flink; - PhpDestroyWorkQueueItem(workQueueItem); - } - - if (WorkQueue->SemaphoreHandle) - NtClose(WorkQueue->SemaphoreHandle); -} - -/** - * Waits for all queued work items to be executed. - * - * \param WorkQueue A work queue object. - */ -VOID PhWaitForWorkQueue( - _Inout_ PPH_WORK_QUEUE WorkQueue - ) -{ - PhAcquireQueuedLockExclusive(&WorkQueue->QueueLock); - - while (!IsListEmpty(&WorkQueue->QueueListHead)) - PhWaitForCondition(&WorkQueue->QueueEmptyCondition, &WorkQueue->QueueLock, NULL); - - PhReleaseQueuedLockExclusive(&WorkQueue->QueueLock); -} - -/** - * Queues a work item to a work queue. - * - * \param WorkQueue A work queue object. - * \param Function A function to execute. - * \param Context A user-defined value to pass to the function. - */ -VOID PhQueueItemWorkQueue( - _Inout_ PPH_WORK_QUEUE WorkQueue, - _In_ PUSER_THREAD_START_ROUTINE Function, - _In_opt_ PVOID Context - ) -{ - PhQueueItemWorkQueueEx(WorkQueue, Function, Context, NULL, NULL); -} - -/** - * Queues a work item to a work queue. - * - * \param WorkQueue A work queue object. - * \param Function A function to execute. - * \param Context A user-defined value to pass to the function. - * \param DeleteFunction A callback function that is executed when the work queue item is about to - * be freed. - * \param Environment Execution environment parameters (e.g. priority). - */ -VOID PhQueueItemWorkQueueEx( - _Inout_ PPH_WORK_QUEUE WorkQueue, - _In_ PUSER_THREAD_START_ROUTINE Function, - _In_opt_ PVOID Context, - _In_opt_ PPH_WORK_QUEUE_ITEM_DELETE_FUNCTION DeleteFunction, - _In_opt_ PPH_WORK_QUEUE_ENVIRONMENT Environment - ) -{ - PPH_WORK_QUEUE_ITEM workQueueItem; - - workQueueItem = PhpCreateWorkQueueItem(Function, Context, DeleteFunction, Environment); - - // Enqueue the work item. - PhAcquireQueuedLockExclusive(&WorkQueue->QueueLock); - InsertTailList(&WorkQueue->QueueListHead, &workQueueItem->ListEntry); - _InterlockedIncrement(&WorkQueue->BusyCount); - PhReleaseQueuedLockExclusive(&WorkQueue->QueueLock); - // Signal the semaphore once to let a worker thread continue. - NtReleaseSemaphore(PhpGetSemaphoreWorkQueue(WorkQueue), 1, NULL); - - PHLIB_INC_STATISTIC(WqWorkItemsQueued); - - // Check if all worker threads are currently busy, and if we can create more threads. - if (WorkQueue->BusyCount >= WorkQueue->CurrentThreads && - WorkQueue->CurrentThreads < WorkQueue->MaximumThreads) - { - // Lock and re-check. - PhAcquireQueuedLockExclusive(&WorkQueue->StateLock); - - if (WorkQueue->CurrentThreads < WorkQueue->MaximumThreads) - PhpCreateWorkQueueThread(WorkQueue); - - PhReleaseQueuedLockExclusive(&WorkQueue->StateLock); - } -} - -VOID PhInitializeWorkQueueEnvironment( - _Out_ PPH_WORK_QUEUE_ENVIRONMENT Environment - ) -{ - PhpGetDefaultWorkQueueEnvironment(Environment); -} - -/** Returns a pointer to the default shared work queue. */ -PPH_WORK_QUEUE PhGetGlobalWorkQueue( - VOID - ) -{ - if (PhBeginInitOnce(&PhGlobalWorkQueueInitOnce)) - { - PhInitializeWorkQueue( - &PhGlobalWorkQueue, - 0, - 3, - 1000 - ); - PhEndInitOnce(&PhGlobalWorkQueueInitOnce); - } - - return &PhGlobalWorkQueue; -} - -VOID PhpGetDefaultWorkQueueEnvironment( - _Out_ PPH_WORK_QUEUE_ENVIRONMENT Environment - ) -{ - memset(Environment, 0, sizeof(PH_WORK_QUEUE_ENVIRONMENT)); - Environment->BasePriority = 0; - Environment->IoPriority = IoPriorityNormal; - Environment->PagePriority = MEMORY_PRIORITY_NORMAL; - Environment->ForceUpdate = FALSE; -} - -VOID PhpUpdateWorkQueueEnvironment( - _Inout_ PPH_WORK_QUEUE_ENVIRONMENT CurrentEnvironment, - _In_ PPH_WORK_QUEUE_ENVIRONMENT NewEnvironment - ) -{ - if (CurrentEnvironment->BasePriority != NewEnvironment->BasePriority || NewEnvironment->ForceUpdate) - { - LONG increment; - - increment = NewEnvironment->BasePriority; - - if (NT_SUCCESS(NtSetInformationThread(NtCurrentThread(), ThreadBasePriority, - &increment, sizeof(LONG)))) - { - CurrentEnvironment->BasePriority = NewEnvironment->BasePriority; - } - } - - if (WindowsVersion >= WINDOWS_VISTA) - { - if (CurrentEnvironment->IoPriority != NewEnvironment->IoPriority || NewEnvironment->ForceUpdate) - { - IO_PRIORITY_HINT ioPriority; - - ioPriority = NewEnvironment->IoPriority; - - if (NT_SUCCESS(NtSetInformationThread(NtCurrentThread(), ThreadIoPriority, - &ioPriority, sizeof(IO_PRIORITY_HINT)))) - { - CurrentEnvironment->IoPriority = NewEnvironment->IoPriority; - } - } - - if (CurrentEnvironment->PagePriority != NewEnvironment->PagePriority || NewEnvironment->ForceUpdate) - { - ULONG pagePriority; - - pagePriority = NewEnvironment->PagePriority; - - if (NT_SUCCESS(NtSetInformationThread(NtCurrentThread(), ThreadPagePriority, - &pagePriority, sizeof(ULONG)))) - { - CurrentEnvironment->PagePriority = NewEnvironment->PagePriority; - } - } - } -} - -PPH_WORK_QUEUE_ITEM PhpCreateWorkQueueItem( - _In_ PUSER_THREAD_START_ROUTINE Function, - _In_opt_ PVOID Context, - _In_opt_ PPH_WORK_QUEUE_ITEM_DELETE_FUNCTION DeleteFunction, - _In_opt_ PPH_WORK_QUEUE_ENVIRONMENT Environment - ) -{ - PPH_WORK_QUEUE_ITEM workQueueItem; - - workQueueItem = PhAllocateFromFreeList(&PhWorkQueueItemFreeList); - workQueueItem->Function = Function; - workQueueItem->Context = Context; - workQueueItem->DeleteFunction = DeleteFunction; - - if (Environment) - workQueueItem->Environment = *Environment; - else - PhpGetDefaultWorkQueueEnvironment(&workQueueItem->Environment); - - return workQueueItem; -} - -VOID PhpDestroyWorkQueueItem( - _In_ PPH_WORK_QUEUE_ITEM WorkQueueItem - ) -{ - if (WorkQueueItem->DeleteFunction) - WorkQueueItem->DeleteFunction(WorkQueueItem->Function, WorkQueueItem->Context); - - PhFreeToFreeList(&PhWorkQueueItemFreeList, WorkQueueItem); -} - -VOID PhpExecuteWorkQueueItem( - _Inout_ PPH_WORK_QUEUE_ITEM WorkQueueItem - ) -{ - WorkQueueItem->Function(WorkQueueItem->Context); -} - -HANDLE PhpGetSemaphoreWorkQueue( - _Inout_ PPH_WORK_QUEUE WorkQueue - ) -{ - HANDLE semaphoreHandle; - - semaphoreHandle = WorkQueue->SemaphoreHandle; - - if (!semaphoreHandle) - { - NtCreateSemaphore(&semaphoreHandle, SEMAPHORE_ALL_ACCESS, NULL, 0, MAXLONG); - assert(semaphoreHandle); - - if (_InterlockedCompareExchangePointer( - &WorkQueue->SemaphoreHandle, - semaphoreHandle, - NULL - ) != NULL) - { - // Someone else created the semaphore before we did. - NtClose(semaphoreHandle); - semaphoreHandle = WorkQueue->SemaphoreHandle; - } - } - - return semaphoreHandle; -} - -BOOLEAN PhpCreateWorkQueueThread( - _Inout_ PPH_WORK_QUEUE WorkQueue - ) -{ - HANDLE threadHandle; - - // Make sure the structure doesn't get deleted while the thread is running. - if (!PhAcquireRundownProtection(&WorkQueue->RundownProtect)) - return FALSE; - - threadHandle = PhCreateThread(0, PhpWorkQueueThreadStart, WorkQueue); - - if (threadHandle) - { - PHLIB_INC_STATISTIC(WqWorkQueueThreadsCreated); - WorkQueue->CurrentThreads++; - NtClose(threadHandle); - - return TRUE; - } - else - { - PHLIB_INC_STATISTIC(WqWorkQueueThreadsCreateFailed); - PhReleaseRundownProtection(&WorkQueue->RundownProtect); - return FALSE; - } -} - -NTSTATUS PhpWorkQueueThreadStart( - _In_ PVOID Parameter - ) -{ - PH_AUTO_POOL autoPool; - PPH_WORK_QUEUE workQueue = (PPH_WORK_QUEUE)Parameter; - PH_WORK_QUEUE_ENVIRONMENT currentEnvironment; - - PhInitializeAutoPool(&autoPool); - PhpGetDefaultWorkQueueEnvironment(¤tEnvironment); - - while (TRUE) - { - NTSTATUS status; - HANDLE semaphoreHandle; - LARGE_INTEGER timeout; - PPH_WORK_QUEUE_ITEM workQueueItem = NULL; - - // Check if we have more threads than the limit. - if (workQueue->CurrentThreads > workQueue->MaximumThreads) - { - BOOLEAN terminate = FALSE; - - // Lock and re-check. - PhAcquireQueuedLockExclusive(&workQueue->StateLock); - - // Check the minimum as well. - if (workQueue->CurrentThreads > workQueue->MaximumThreads && - workQueue->CurrentThreads > workQueue->MinimumThreads) - { - workQueue->CurrentThreads--; - terminate = TRUE; - } - - PhReleaseQueuedLockExclusive(&workQueue->StateLock); - - if (terminate) - break; - } - - semaphoreHandle = PhpGetSemaphoreWorkQueue(workQueue); - - if (!workQueue->Terminating) - { - // Wait for work. - status = NtWaitForSingleObject( - semaphoreHandle, - FALSE, - PhTimeoutFromMilliseconds(&timeout, workQueue->NoWorkTimeout) - ); - } - else - { - status = STATUS_UNSUCCESSFUL; - } - - if (status == STATUS_WAIT_0 && !workQueue->Terminating) - { - PLIST_ENTRY listEntry; - - // Dequeue the work item. - - PhAcquireQueuedLockExclusive(&workQueue->QueueLock); - - listEntry = RemoveHeadList(&workQueue->QueueListHead); - - if (IsListEmpty(&workQueue->QueueListHead)) - PhPulseCondition(&workQueue->QueueEmptyCondition); - - PhReleaseQueuedLockExclusive(&workQueue->QueueLock); - - // Make sure we got work. - if (listEntry != &workQueue->QueueListHead) - { - workQueueItem = CONTAINING_RECORD(listEntry, PH_WORK_QUEUE_ITEM, ListEntry); - - PhpUpdateWorkQueueEnvironment(¤tEnvironment, &workQueueItem->Environment); - PhpExecuteWorkQueueItem(workQueueItem); - _InterlockedDecrement(&workQueue->BusyCount); - - PhpDestroyWorkQueueItem(workQueueItem); - } - } - else - { - BOOLEAN terminate = FALSE; - - // No work arrived before the timeout passed, or we are terminating, or some error - // occurred. Terminate the thread. - - PhAcquireQueuedLockExclusive(&workQueue->StateLock); - - if (workQueue->Terminating || workQueue->CurrentThreads > workQueue->MinimumThreads) - { - workQueue->CurrentThreads--; - terminate = TRUE; - } - - PhReleaseQueuedLockExclusive(&workQueue->StateLock); - - if (terminate) - break; - } - - PhDrainAutoPool(&autoPool); - } - - PhReleaseRundownProtection(&workQueue->RundownProtect); - PhDeleteAutoPool(&autoPool); - - return STATUS_SUCCESS; -} +/* + * Process Hacker - + * thread pool / work queue + * + * Copyright (C) 2009-2016 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include +#include + +#include + +#include + +static PH_INITONCE PhWorkQueueInitOnce = PH_INITONCE_INIT; +static PH_FREE_LIST PhWorkQueueItemFreeList; +static PH_INITONCE PhGlobalWorkQueueInitOnce = PH_INITONCE_INIT; +static PH_WORK_QUEUE PhGlobalWorkQueue; +#ifdef DEBUG +PPH_LIST PhDbgWorkQueueList; +PH_QUEUED_LOCK PhDbgWorkQueueListLock = PH_QUEUED_LOCK_INIT; +#endif + +/** + * Initializes a work queue. + * + * \param WorkQueue A work queue object. + * \param MinimumThreads The suggested minimum number of threads to keep alive, even when there is + * no work to be performed. + * \param MaximumThreads The suggested maximum number of threads to create. + * \param NoWorkTimeout The number of milliseconds after which threads without work will terminate. + */ +VOID PhInitializeWorkQueue( + _Out_ PPH_WORK_QUEUE WorkQueue, + _In_ ULONG MinimumThreads, + _In_ ULONG MaximumThreads, + _In_ ULONG NoWorkTimeout + ) +{ + if (PhBeginInitOnce(&PhWorkQueueInitOnce)) + { + PhInitializeFreeList(&PhWorkQueueItemFreeList, sizeof(PH_WORK_QUEUE_ITEM), 32); +#ifdef DEBUG + PhDbgWorkQueueList = PhCreateList(4); +#endif + + PhEndInitOnce(&PhWorkQueueInitOnce); + } + + PhInitializeRundownProtection(&WorkQueue->RundownProtect); + WorkQueue->Terminating = FALSE; + + InitializeListHead(&WorkQueue->QueueListHead); + PhInitializeQueuedLock(&WorkQueue->QueueLock); + PhInitializeCondition(&WorkQueue->QueueEmptyCondition); + + WorkQueue->MinimumThreads = MinimumThreads; + WorkQueue->MaximumThreads = MaximumThreads; + WorkQueue->NoWorkTimeout = NoWorkTimeout; + + PhInitializeQueuedLock(&WorkQueue->StateLock); + + WorkQueue->SemaphoreHandle = NULL; + WorkQueue->CurrentThreads = 0; + WorkQueue->BusyCount = 0; + +#ifdef DEBUG + PhAcquireQueuedLockExclusive(&PhDbgWorkQueueListLock); + PhAddItemList(PhDbgWorkQueueList, WorkQueue); + PhReleaseQueuedLockExclusive(&PhDbgWorkQueueListLock); +#endif +} + +/** + * Frees resources used by a work queue. + * + * \param WorkQueue A work queue object. + */ +VOID PhDeleteWorkQueue( + _Inout_ PPH_WORK_QUEUE WorkQueue + ) +{ + PLIST_ENTRY listEntry; + PPH_WORK_QUEUE_ITEM workQueueItem; +#ifdef DEBUG + ULONG index; +#endif + +#ifdef DEBUG + PhAcquireQueuedLockExclusive(&PhDbgWorkQueueListLock); + if ((index = PhFindItemList(PhDbgWorkQueueList, WorkQueue)) != -1) + PhRemoveItemList(PhDbgWorkQueueList, index); + PhReleaseQueuedLockExclusive(&PhDbgWorkQueueListLock); +#endif + + // Wait for all worker threads to exit. + + WorkQueue->Terminating = TRUE; + MemoryBarrier(); + + if (WorkQueue->SemaphoreHandle) + NtReleaseSemaphore(WorkQueue->SemaphoreHandle, WorkQueue->CurrentThreads, NULL); + + PhWaitForRundownProtection(&WorkQueue->RundownProtect); + + // Free all un-executed work items. + + listEntry = WorkQueue->QueueListHead.Flink; + + while (listEntry != &WorkQueue->QueueListHead) + { + workQueueItem = CONTAINING_RECORD(listEntry, PH_WORK_QUEUE_ITEM, ListEntry); + listEntry = listEntry->Flink; + PhpDestroyWorkQueueItem(workQueueItem); + } + + if (WorkQueue->SemaphoreHandle) + NtClose(WorkQueue->SemaphoreHandle); +} + +/** + * Waits for all queued work items to be executed. + * + * \param WorkQueue A work queue object. + */ +VOID PhWaitForWorkQueue( + _Inout_ PPH_WORK_QUEUE WorkQueue + ) +{ + PhAcquireQueuedLockExclusive(&WorkQueue->QueueLock); + + while (!IsListEmpty(&WorkQueue->QueueListHead)) + PhWaitForCondition(&WorkQueue->QueueEmptyCondition, &WorkQueue->QueueLock, NULL); + + PhReleaseQueuedLockExclusive(&WorkQueue->QueueLock); +} + +/** + * Queues a work item to a work queue. + * + * \param WorkQueue A work queue object. + * \param Function A function to execute. + * \param Context A user-defined value to pass to the function. + */ +VOID PhQueueItemWorkQueue( + _Inout_ PPH_WORK_QUEUE WorkQueue, + _In_ PUSER_THREAD_START_ROUTINE Function, + _In_opt_ PVOID Context + ) +{ + PhQueueItemWorkQueueEx(WorkQueue, Function, Context, NULL, NULL); +} + +/** + * Queues a work item to a work queue. + * + * \param WorkQueue A work queue object. + * \param Function A function to execute. + * \param Context A user-defined value to pass to the function. + * \param DeleteFunction A callback function that is executed when the work queue item is about to + * be freed. + * \param Environment Execution environment parameters (e.g. priority). + */ +VOID PhQueueItemWorkQueueEx( + _Inout_ PPH_WORK_QUEUE WorkQueue, + _In_ PUSER_THREAD_START_ROUTINE Function, + _In_opt_ PVOID Context, + _In_opt_ PPH_WORK_QUEUE_ITEM_DELETE_FUNCTION DeleteFunction, + _In_opt_ PPH_WORK_QUEUE_ENVIRONMENT Environment + ) +{ + PPH_WORK_QUEUE_ITEM workQueueItem; + + workQueueItem = PhpCreateWorkQueueItem(Function, Context, DeleteFunction, Environment); + + // Enqueue the work item. + PhAcquireQueuedLockExclusive(&WorkQueue->QueueLock); + InsertTailList(&WorkQueue->QueueListHead, &workQueueItem->ListEntry); + _InterlockedIncrement(&WorkQueue->BusyCount); + PhReleaseQueuedLockExclusive(&WorkQueue->QueueLock); + // Signal the semaphore once to let a worker thread continue. + NtReleaseSemaphore(PhpGetSemaphoreWorkQueue(WorkQueue), 1, NULL); + + PHLIB_INC_STATISTIC(WqWorkItemsQueued); + + // Check if all worker threads are currently busy, and if we can create more threads. + if (WorkQueue->BusyCount >= WorkQueue->CurrentThreads && + WorkQueue->CurrentThreads < WorkQueue->MaximumThreads) + { + // Lock and re-check. + PhAcquireQueuedLockExclusive(&WorkQueue->StateLock); + + if (WorkQueue->CurrentThreads < WorkQueue->MaximumThreads) + PhpCreateWorkQueueThread(WorkQueue); + + PhReleaseQueuedLockExclusive(&WorkQueue->StateLock); + } +} + +VOID PhInitializeWorkQueueEnvironment( + _Out_ PPH_WORK_QUEUE_ENVIRONMENT Environment + ) +{ + PhpGetDefaultWorkQueueEnvironment(Environment); +} + +/** Returns a pointer to the default shared work queue. */ +PPH_WORK_QUEUE PhGetGlobalWorkQueue( + VOID + ) +{ + if (PhBeginInitOnce(&PhGlobalWorkQueueInitOnce)) + { + PhInitializeWorkQueue( + &PhGlobalWorkQueue, + 0, + 3, + 1000 + ); + PhEndInitOnce(&PhGlobalWorkQueueInitOnce); + } + + return &PhGlobalWorkQueue; +} + +VOID PhpGetDefaultWorkQueueEnvironment( + _Out_ PPH_WORK_QUEUE_ENVIRONMENT Environment + ) +{ + memset(Environment, 0, sizeof(PH_WORK_QUEUE_ENVIRONMENT)); + Environment->BasePriority = 0; + Environment->IoPriority = IoPriorityNormal; + Environment->PagePriority = MEMORY_PRIORITY_NORMAL; + Environment->ForceUpdate = FALSE; +} + +VOID PhpUpdateWorkQueueEnvironment( + _Inout_ PPH_WORK_QUEUE_ENVIRONMENT CurrentEnvironment, + _In_ PPH_WORK_QUEUE_ENVIRONMENT NewEnvironment + ) +{ + if (CurrentEnvironment->BasePriority != NewEnvironment->BasePriority || NewEnvironment->ForceUpdate) + { + LONG increment; + + increment = NewEnvironment->BasePriority; + + if (NT_SUCCESS(NtSetInformationThread(NtCurrentThread(), ThreadBasePriority, + &increment, sizeof(LONG)))) + { + CurrentEnvironment->BasePriority = NewEnvironment->BasePriority; + } + } + + if (WindowsVersion >= WINDOWS_VISTA) + { + if (CurrentEnvironment->IoPriority != NewEnvironment->IoPriority || NewEnvironment->ForceUpdate) + { + IO_PRIORITY_HINT ioPriority; + + ioPriority = NewEnvironment->IoPriority; + + if (NT_SUCCESS(NtSetInformationThread(NtCurrentThread(), ThreadIoPriority, + &ioPriority, sizeof(IO_PRIORITY_HINT)))) + { + CurrentEnvironment->IoPriority = NewEnvironment->IoPriority; + } + } + + if (CurrentEnvironment->PagePriority != NewEnvironment->PagePriority || NewEnvironment->ForceUpdate) + { + ULONG pagePriority; + + pagePriority = NewEnvironment->PagePriority; + + if (NT_SUCCESS(NtSetInformationThread(NtCurrentThread(), ThreadPagePriority, + &pagePriority, sizeof(ULONG)))) + { + CurrentEnvironment->PagePriority = NewEnvironment->PagePriority; + } + } + } +} + +PPH_WORK_QUEUE_ITEM PhpCreateWorkQueueItem( + _In_ PUSER_THREAD_START_ROUTINE Function, + _In_opt_ PVOID Context, + _In_opt_ PPH_WORK_QUEUE_ITEM_DELETE_FUNCTION DeleteFunction, + _In_opt_ PPH_WORK_QUEUE_ENVIRONMENT Environment + ) +{ + PPH_WORK_QUEUE_ITEM workQueueItem; + + workQueueItem = PhAllocateFromFreeList(&PhWorkQueueItemFreeList); + workQueueItem->Function = Function; + workQueueItem->Context = Context; + workQueueItem->DeleteFunction = DeleteFunction; + + if (Environment) + workQueueItem->Environment = *Environment; + else + PhpGetDefaultWorkQueueEnvironment(&workQueueItem->Environment); + + return workQueueItem; +} + +VOID PhpDestroyWorkQueueItem( + _In_ PPH_WORK_QUEUE_ITEM WorkQueueItem + ) +{ + if (WorkQueueItem->DeleteFunction) + WorkQueueItem->DeleteFunction(WorkQueueItem->Function, WorkQueueItem->Context); + + PhFreeToFreeList(&PhWorkQueueItemFreeList, WorkQueueItem); +} + +VOID PhpExecuteWorkQueueItem( + _Inout_ PPH_WORK_QUEUE_ITEM WorkQueueItem + ) +{ + WorkQueueItem->Function(WorkQueueItem->Context); +} + +HANDLE PhpGetSemaphoreWorkQueue( + _Inout_ PPH_WORK_QUEUE WorkQueue + ) +{ + HANDLE semaphoreHandle; + + semaphoreHandle = WorkQueue->SemaphoreHandle; + + if (!semaphoreHandle) + { + NtCreateSemaphore(&semaphoreHandle, SEMAPHORE_ALL_ACCESS, NULL, 0, MAXLONG); + assert(semaphoreHandle); + + if (_InterlockedCompareExchangePointer( + &WorkQueue->SemaphoreHandle, + semaphoreHandle, + NULL + ) != NULL) + { + // Someone else created the semaphore before we did. + NtClose(semaphoreHandle); + semaphoreHandle = WorkQueue->SemaphoreHandle; + } + } + + return semaphoreHandle; +} + +BOOLEAN PhpCreateWorkQueueThread( + _Inout_ PPH_WORK_QUEUE WorkQueue + ) +{ + HANDLE threadHandle; + + // Make sure the structure doesn't get deleted while the thread is running. + if (!PhAcquireRundownProtection(&WorkQueue->RundownProtect)) + return FALSE; + + threadHandle = PhCreateThread(0, PhpWorkQueueThreadStart, WorkQueue); + + if (threadHandle) + { + PHLIB_INC_STATISTIC(WqWorkQueueThreadsCreated); + WorkQueue->CurrentThreads++; + NtClose(threadHandle); + + return TRUE; + } + else + { + PHLIB_INC_STATISTIC(WqWorkQueueThreadsCreateFailed); + PhReleaseRundownProtection(&WorkQueue->RundownProtect); + return FALSE; + } +} + +NTSTATUS PhpWorkQueueThreadStart( + _In_ PVOID Parameter + ) +{ + PH_AUTO_POOL autoPool; + PPH_WORK_QUEUE workQueue = (PPH_WORK_QUEUE)Parameter; + PH_WORK_QUEUE_ENVIRONMENT currentEnvironment; + + PhInitializeAutoPool(&autoPool); + PhpGetDefaultWorkQueueEnvironment(¤tEnvironment); + + while (TRUE) + { + NTSTATUS status; + HANDLE semaphoreHandle; + LARGE_INTEGER timeout; + PPH_WORK_QUEUE_ITEM workQueueItem = NULL; + + // Check if we have more threads than the limit. + if (workQueue->CurrentThreads > workQueue->MaximumThreads) + { + BOOLEAN terminate = FALSE; + + // Lock and re-check. + PhAcquireQueuedLockExclusive(&workQueue->StateLock); + + // Check the minimum as well. + if (workQueue->CurrentThreads > workQueue->MaximumThreads && + workQueue->CurrentThreads > workQueue->MinimumThreads) + { + workQueue->CurrentThreads--; + terminate = TRUE; + } + + PhReleaseQueuedLockExclusive(&workQueue->StateLock); + + if (terminate) + break; + } + + semaphoreHandle = PhpGetSemaphoreWorkQueue(workQueue); + + if (!workQueue->Terminating) + { + // Wait for work. + status = NtWaitForSingleObject( + semaphoreHandle, + FALSE, + PhTimeoutFromMilliseconds(&timeout, workQueue->NoWorkTimeout) + ); + } + else + { + status = STATUS_UNSUCCESSFUL; + } + + if (status == STATUS_WAIT_0 && !workQueue->Terminating) + { + PLIST_ENTRY listEntry; + + // Dequeue the work item. + + PhAcquireQueuedLockExclusive(&workQueue->QueueLock); + + listEntry = RemoveHeadList(&workQueue->QueueListHead); + + if (IsListEmpty(&workQueue->QueueListHead)) + PhPulseCondition(&workQueue->QueueEmptyCondition); + + PhReleaseQueuedLockExclusive(&workQueue->QueueLock); + + // Make sure we got work. + if (listEntry != &workQueue->QueueListHead) + { + workQueueItem = CONTAINING_RECORD(listEntry, PH_WORK_QUEUE_ITEM, ListEntry); + + PhpUpdateWorkQueueEnvironment(¤tEnvironment, &workQueueItem->Environment); + PhpExecuteWorkQueueItem(workQueueItem); + _InterlockedDecrement(&workQueue->BusyCount); + + PhpDestroyWorkQueueItem(workQueueItem); + } + } + else + { + BOOLEAN terminate = FALSE; + + // No work arrived before the timeout passed, or we are terminating, or some error + // occurred. Terminate the thread. + + PhAcquireQueuedLockExclusive(&workQueue->StateLock); + + if (workQueue->Terminating || workQueue->CurrentThreads > workQueue->MinimumThreads) + { + workQueue->CurrentThreads--; + terminate = TRUE; + } + + PhReleaseQueuedLockExclusive(&workQueue->StateLock); + + if (terminate) + break; + } + + PhDrainAutoPool(&autoPool); + } + + PhReleaseRundownProtection(&workQueue->RundownProtect); + PhDeleteAutoPool(&autoPool); + + return STATUS_SUCCESS; +} diff --git a/plugins/DotNetTools/CHANGELOG.txt b/plugins/DotNetTools/CHANGELOG.txt index 371cc7efe9ae..c30876cbdd5c 100644 --- a/plugins/DotNetTools/CHANGELOG.txt +++ b/plugins/DotNetTools/CHANGELOG.txt @@ -1,26 +1,26 @@ -1.6 - * Fixed .NET assembly tab performance issues - * Added extra .NET memory counters to the .NET performance tab - * Added "Show sizes in bytes" checkbox to the .NET performance tab - * Added right-click menu to the .NET assembly tab - * Removed all Win32 functions for querying .NET process performance - -1.5 - * Rewrite of .NET Performance statistics and AppDomain enumeration - -1.4 - * Process Hacker now displays managed stack traces for 32-bit .NET processes on 64-bit Windows - * Fixed inaccurate stack traces when clicking Refresh - * Added AppDomain column for threads in .NET programs - -1.3 - * Improved .NET assembly enumeration timeout handling - -1.2 - * Fixed inaccurate stack traces for certain .NET programs - -1.1 - * Added managed symbol resolution for thread stacks - -1.0 +1.6 + * Fixed .NET assembly tab performance issues + * Added extra .NET memory counters to the .NET performance tab + * Added "Show sizes in bytes" checkbox to the .NET performance tab + * Added right-click menu to the .NET assembly tab + * Removed all Win32 functions for querying .NET process performance + +1.5 + * Rewrite of .NET Performance statistics and AppDomain enumeration + +1.4 + * Process Hacker now displays managed stack traces for 32-bit .NET processes on 64-bit Windows + * Fixed inaccurate stack traces when clicking Refresh + * Added AppDomain column for threads in .NET programs + +1.3 + * Improved .NET assembly enumeration timeout handling + +1.2 + * Fixed inaccurate stack traces for certain .NET programs + +1.1 + * Added managed symbol resolution for thread stacks + +1.0 * Initial release \ No newline at end of file diff --git a/plugins/DotNetTools/DotNetTools.rc b/plugins/DotNetTools/DotNetTools.rc index 7c8acce56e78..ded0cbd42baa 100644 --- a/plugins/DotNetTools/DotNetTools.rc +++ b/plugins/DotNetTools/DotNetTools.rc @@ -1,182 +1,182 @@ -// Microsoft Visual C++ generated resource script. -// -#include "resource.h" - -#define APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// -#include "winres.h" -///////////////////////////////////////////////////////////////////////////// -#undef APSTUDIO_READONLY_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -// English (Australia) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENA) -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_AUS -#pragma code_page(1252) - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -1 TEXTINCLUDE -BEGIN - "resource.h\0" -END - -2 TEXTINCLUDE -BEGIN - "#include ""winres.h""\0" -END - -3 TEXTINCLUDE -BEGIN - "\r\n" - "\0" -END - -#endif // APSTUDIO_INVOKED - - -///////////////////////////////////////////////////////////////////////////// -// -// Version -// - -VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,6,0,0 - PRODUCTVERSION 1,6,0,0 - FILEFLAGSMASK 0x3fL -#ifdef _DEBUG - FILEFLAGS 0x1L -#else - FILEFLAGS 0x0L -#endif - FILEOS 0x40004L - FILETYPE 0x2L - FILESUBTYPE 0x0L -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "0c0904b0" - BEGIN - VALUE "CompanyName", "wj32" - VALUE "FileDescription", ".NET tools plugin for Process Hacker" - VALUE "FileVersion", "1.6" - VALUE "InternalName", "ProcessHacker.DotNetTools" - VALUE "LegalCopyright", "Licensed under the GNU GPL, v3." - VALUE "OriginalFilename", "DotNetTools.dll" - VALUE "ProductName", ".NET tools plugin for Process Hacker" - VALUE "ProductVersion", "1.6" - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0xc09, 1200 - END -END - - -///////////////////////////////////////////////////////////////////////////// -// -// Dialog -// - -IDD_PROCDOTNETPERF DIALOGEX 0, 0, 260, 260 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION ".NET performance" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - CONTROL "",IDC_APPDOMAINS,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_SORTASCENDING | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,7,246,59 - LTEXT "Categories:",IDC_STATIC,7,72,38,8 - COMBOBOX IDC_CATEGORIES,49,70,204,30,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP - CONTROL "",IDC_COUNTERS,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,88,246,154 - CONTROL "Show sizes in bytes",IDC_DOTNET_PERF_SHOWBYTES,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,244,78,10 -END - -IDD_PROCDOTNETASM DIALOGEX 0, 0, 260, 260 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION ".NET assemblies" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - CONTROL ".NET assemblies",IDC_LIST,"PhTreeNew",WS_CLIPSIBLINGS | WS_CLIPCHILDREN | 0x1a,7,7,246,246,WS_EX_CLIENTEDGE -END - - -///////////////////////////////////////////////////////////////////////////// -// -// DESIGNINFO -// - -#ifdef APSTUDIO_INVOKED -GUIDELINES DESIGNINFO -BEGIN - IDD_PROCDOTNETPERF, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 253 - TOPMARGIN, 7 - BOTTOMMARGIN, 253 - END - - IDD_PROCDOTNETASM, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 253 - TOPMARGIN, 7 - BOTTOMMARGIN, 253 - END -END -#endif // APSTUDIO_INVOKED - - -///////////////////////////////////////////////////////////////////////////// -// -// AFX_DIALOG_LAYOUT -// - -IDD_PROCDOTNETASM AFX_DIALOG_LAYOUT -BEGIN - 0 -END - -IDD_PROCDOTNETPERF AFX_DIALOG_LAYOUT -BEGIN - 0 -END - - -///////////////////////////////////////////////////////////////////////////// -// -// Menu -// - -IDR_ASSEMBLY_MENU MENU -BEGIN - POPUP "CLR" - BEGIN - MENUITEM "Open &file location", ID_CLR_OPENFILELOCATION - MENUITEM "&Copy\aCtrl+C", ID_CLR_COPY - END -END - -#endif // English (Australia) resources -///////////////////////////////////////////////////////////////////////////// - - - -#ifndef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// - - -///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED - +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "winres.h" +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (Australia) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENA) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_AUS +#pragma code_page(1252) + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""winres.h""\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,6,0,0 + PRODUCTVERSION 1,6,0,0 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "0c0904b0" + BEGIN + VALUE "CompanyName", "wj32" + VALUE "FileDescription", ".NET tools plugin for Process Hacker" + VALUE "FileVersion", "1.6" + VALUE "InternalName", "ProcessHacker.DotNetTools" + VALUE "LegalCopyright", "Licensed under the GNU GPL, v3." + VALUE "OriginalFilename", "DotNetTools.dll" + VALUE "ProductName", ".NET tools plugin for Process Hacker" + VALUE "ProductVersion", "1.6" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0xc09, 1200 + END +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_PROCDOTNETPERF DIALOGEX 0, 0, 260, 260 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION ".NET performance" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + CONTROL "",IDC_APPDOMAINS,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_SORTASCENDING | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,7,246,59 + LTEXT "Categories:",IDC_STATIC,7,72,38,8 + COMBOBOX IDC_CATEGORIES,49,70,204,30,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP + CONTROL "",IDC_COUNTERS,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,88,246,154 + CONTROL "Show sizes in bytes",IDC_DOTNET_PERF_SHOWBYTES,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,244,78,10 +END + +IDD_PROCDOTNETASM DIALOGEX 0, 0, 260, 260 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION ".NET assemblies" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + CONTROL ".NET assemblies",IDC_LIST,"PhTreeNew",WS_CLIPSIBLINGS | WS_CLIPCHILDREN | 0x1a,7,7,246,246,WS_EX_CLIENTEDGE +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_PROCDOTNETPERF, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 253 + TOPMARGIN, 7 + BOTTOMMARGIN, 253 + END + + IDD_PROCDOTNETASM, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 253 + TOPMARGIN, 7 + BOTTOMMARGIN, 253 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// AFX_DIALOG_LAYOUT +// + +IDD_PROCDOTNETASM AFX_DIALOG_LAYOUT +BEGIN + 0 +END + +IDD_PROCDOTNETPERF AFX_DIALOG_LAYOUT +BEGIN + 0 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Menu +// + +IDR_ASSEMBLY_MENU MENU +BEGIN + POPUP "CLR" + BEGIN + MENUITEM "Open &file location", ID_CLR_OPENFILELOCATION + MENUITEM "&Copy\aCtrl+C", ID_CLR_COPY + END +END + +#endif // English (Australia) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/plugins/DotNetTools/DotNetTools.vcxproj b/plugins/DotNetTools/DotNetTools.vcxproj index 1c691037b766..f0b912ea36de 100644 --- a/plugins/DotNetTools/DotNetTools.vcxproj +++ b/plugins/DotNetTools/DotNetTools.vcxproj @@ -1,104 +1,104 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {2B3235B0-31E1-44DA-81A1-183F40517E47} - DotNetTools - Win32Proj - DotNetTools - 10.0.15063.0 - - - - DynamicLibrary - Unicode - v141 - - - DynamicLibrary - Unicode - v141 - - - DynamicLibrary - Unicode - v141 - - - DynamicLibrary - Unicode - v141 - - - - - - - - - - uxtheme.lib;%(AdditionalDependencies) - - - - - uxtheme.lib;%(AdditionalDependencies) - - - - - uxtheme.lib;%(AdditionalDependencies) - - - - - uxtheme.lib;%(AdditionalDependencies) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {2B3235B0-31E1-44DA-81A1-183F40517E47} + DotNetTools + Win32Proj + DotNetTools + 10.0.15063.0 + + + + DynamicLibrary + Unicode + v141 + + + DynamicLibrary + Unicode + v141 + + + DynamicLibrary + Unicode + v141 + + + DynamicLibrary + Unicode + v141 + + + + + + + + + + uxtheme.lib;%(AdditionalDependencies) + + + + + uxtheme.lib;%(AdditionalDependencies) + + + + + uxtheme.lib;%(AdditionalDependencies) + + + + + uxtheme.lib;%(AdditionalDependencies) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/plugins/DotNetTools/asmpage.c b/plugins/DotNetTools/asmpage.c index a66d44dbb4c2..6ead4b55596d 100644 --- a/plugins/DotNetTools/asmpage.c +++ b/plugins/DotNetTools/asmpage.c @@ -1,1314 +1,1314 @@ -/* - * Process Hacker .NET Tools - - * .NET Assemblies property page - * - * Copyright (C) 2011-2015 wj32 - * Copyright (C) 2016 dmex - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include "dn.h" -#include "clretw.h" -#include -#include - -#define DNATNC_STRUCTURE 0 -#define DNATNC_ID 1 -#define DNATNC_FLAGS 2 -#define DNATNC_PATH 3 -#define DNATNC_NATIVEPATH 4 -#define DNATNC_MAXIMUM 5 - -#define DNA_TYPE_CLR 1 -#define DNA_TYPE_APPDOMAIN 2 -#define DNA_TYPE_ASSEMBLY 3 - -#define UPDATE_MSG (WM_APP + 1) - -typedef struct _DNA_NODE -{ - PH_TREENEW_NODE Node; - - struct _DNA_NODE *Parent; - PPH_LIST Children; - - PH_STRINGREF TextCache[DNATNC_MAXIMUM]; - - ULONG Type; - BOOLEAN IsFakeClr; - - union - { - struct - { - USHORT ClrInstanceID; - PPH_STRING DisplayName; - } Clr; - struct - { - ULONG64 AppDomainID; - PPH_STRING DisplayName; - } AppDomain; - struct - { - ULONG64 AssemblyID; - PPH_STRING FullyQualifiedAssemblyName; - } Assembly; - } u; - - PH_STRINGREF StructureText; - PPH_STRING IdText; - PPH_STRING FlagsText; - PPH_STRING PathText; - PPH_STRING NativePathText; -} DNA_NODE, *PDNA_NODE; - -typedef struct _ASMPAGE_CONTEXT -{ - HWND WindowHandle; - PPH_PROCESS_ITEM ProcessItem; - ULONG ClrVersions; - PDNA_NODE ClrV2Node; - - HWND TnHandle; - PPH_STRING TnErrorMessage; - PPH_LIST NodeList; - PPH_LIST NodeRootList; -} ASMPAGE_CONTEXT, *PASMPAGE_CONTEXT; - -typedef struct _ASMPAGE_QUERY_CONTEXT -{ - HANDLE WindowHandle; - - HANDLE ProcessId; - ULONG ClrVersions; - PDNA_NODE ClrV2Node; - - BOOLEAN TraceClrV2; - ULONG TraceResult; - LONG TraceHandleActive; - TRACEHANDLE TraceHandle; - - PPH_LIST NodeList; - PPH_LIST NodeRootList; -} ASMPAGE_QUERY_CONTEXT, *PASMPAGE_QUERY_CONTEXT; - -typedef struct _FLAG_DEFINITION -{ - PWSTR Name; - ULONG Flag; -} FLAG_DEFINITION, *PFLAG_DEFINITION; - -typedef ULONG (__stdcall *_EnableTraceEx)( - _In_ LPCGUID ProviderId, - _In_opt_ LPCGUID SourceId, - _In_ TRACEHANDLE TraceHandle, - _In_ ULONG IsEnabled, - _In_ UCHAR Level, - _In_ ULONGLONG MatchAnyKeyword, - _In_ ULONGLONG MatchAllKeyword, - _In_ ULONG EnableProperty, - _In_opt_ PEVENT_FILTER_DESCRIPTOR EnableFilterDesc - ); - -VOID DestroyDotNetTraceQuery( - _In_ PASMPAGE_QUERY_CONTEXT Context - ); - -INT_PTR CALLBACK DotNetAsmPageDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -static UNICODE_STRING DotNetLoggerName = RTL_CONSTANT_STRING(L"PhDnLogger"); -static GUID ClrRuntimeProviderGuid = { 0xe13c0d23, 0xccbc, 0x4e12, { 0x93, 0x1b, 0xd9, 0xcc, 0x2e, 0xee, 0x27, 0xe4 } }; -static GUID ClrRundownProviderGuid = { 0xa669021c, 0xc450, 0x4609, { 0xa0, 0x35, 0x5a, 0xf5, 0x9a, 0xf4, 0xdf, 0x18 } }; - -static FLAG_DEFINITION AppDomainFlagsMap[] = -{ - { L"Default", 0x1 }, - { L"Executable", 0x2 }, - { L"Shared", 0x4 } -}; - -static FLAG_DEFINITION AssemblyFlagsMap[] = -{ - { L"DomainNeutral", 0x1 }, - { L"Dynamic", 0x2 }, - { L"Native", 0x4 }, - { L"Collectible", 0x8 } -}; - -static FLAG_DEFINITION ModuleFlagsMap[] = -{ - { L"DomainNeutral", 0x1 }, - { L"Native", 0x2 }, - { L"Dynamic", 0x4 }, - { L"Manifest", 0x8 } -}; - -static FLAG_DEFINITION StartupModeMap[] = -{ - { L"ManagedExe", 0x1 }, - { L"HostedCLR", 0x2 }, - { L"IjwDll", 0x4 }, - { L"ComActivated", 0x8 }, - { L"Other", 0x10 } -}; - -static FLAG_DEFINITION StartupFlagsMap[] = -{ - { L"CONCURRENT_GC", 0x1 }, - { L"LOADER_OPTIMIZATION_SINGLE_DOMAIN", 0x2 }, - { L"LOADER_OPTIMIZATION_MULTI_DOMAIN", 0x4 }, - { L"LOADER_SAFEMODE", 0x10 }, - { L"LOADER_SETPREFERENCE", 0x100 }, - { L"SERVER_GC", 0x1000 }, - { L"HOARD_GC_VM", 0x2000 }, - { L"SINGLE_VERSION_HOSTING_INTERFACE", 0x4000 }, - { L"LEGACY_IMPERSONATION", 0x10000 }, - { L"DISABLE_COMMITTHREADSTACK", 0x20000 }, - { L"ALWAYSFLOW_IMPERSONATION", 0x40000 }, - { L"TRIM_GC_COMMIT", 0x80000 }, - { L"ETW", 0x100000 }, - { L"SERVER_BUILD", 0x200000 }, - { L"ARM", 0x400000 } -}; - -VOID AddAsmPageToPropContext( - _In_ PPH_PLUGIN_PROCESS_PROPCONTEXT PropContext - ) -{ - PhAddProcessPropPage( - PropContext->PropContext, - PhCreateProcessPropPageContextEx(PluginInstance->DllBase, MAKEINTRESOURCE(IDD_PROCDOTNETASM), DotNetAsmPageDlgProc, NULL) - ); -} - -PPH_STRING FlagsToString( - _In_ ULONG Flags, - _In_ PFLAG_DEFINITION Map, - _In_ ULONG SizeOfMap - ) -{ - PH_STRING_BUILDER sb; - ULONG i; - - PhInitializeStringBuilder(&sb, 100); - - for (i = 0; i < SizeOfMap / sizeof(FLAG_DEFINITION); i++) - { - if (Flags & Map[i].Flag) - { - PhAppendStringBuilder2(&sb, Map[i].Name); - PhAppendStringBuilder2(&sb, L", "); - } - } - - if (sb.String->Length != 0) - PhRemoveEndStringBuilder(&sb, 2); - - return PhFinalStringBuilderString(&sb); -} - -PDNA_NODE AddNode( - _Inout_ PASMPAGE_QUERY_CONTEXT Context - ) -{ - PDNA_NODE node; - - node = PhAllocate(sizeof(DNA_NODE)); - memset(node, 0, sizeof(DNA_NODE)); - PhInitializeTreeNewNode(&node->Node); - - memset(node->TextCache, 0, sizeof(PH_STRINGREF) * DNATNC_MAXIMUM); - node->Node.TextCache = node->TextCache; - node->Node.TextCacheSize = DNATNC_MAXIMUM; - - node->Children = PhCreateList(1); - - PhAddItemList(Context->NodeList, node); - - return node; -} - -VOID DestroyNode( - _In_ PDNA_NODE Node - ) -{ - PhDereferenceObject(Node->Children); - - if (Node->Type == DNA_TYPE_CLR) - { - if (Node->u.Clr.DisplayName) PhDereferenceObject(Node->u.Clr.DisplayName); - } - else if (Node->Type == DNA_TYPE_APPDOMAIN) - { - if (Node->u.AppDomain.DisplayName) PhDereferenceObject(Node->u.AppDomain.DisplayName); - } - else if (Node->Type == DNA_TYPE_ASSEMBLY) - { - if (Node->u.Assembly.FullyQualifiedAssemblyName) PhDereferenceObject(Node->u.Assembly.FullyQualifiedAssemblyName); - } - - if (Node->IdText) PhDereferenceObject(Node->IdText); - if (Node->FlagsText) PhDereferenceObject(Node->FlagsText); - if (Node->PathText) PhDereferenceObject(Node->PathText); - if (Node->NativePathText) PhDereferenceObject(Node->NativePathText); - - PhFree(Node); -} - -PDNA_NODE AddFakeClrNode( - _In_ PASMPAGE_QUERY_CONTEXT Context, - _In_ PWSTR DisplayName - ) -{ - PDNA_NODE node; - - node = AddNode(Context); - node->Type = DNA_TYPE_CLR; - node->IsFakeClr = TRUE; - node->u.Clr.ClrInstanceID = 0; - node->u.Clr.DisplayName = NULL; - PhInitializeStringRef(&node->StructureText, DisplayName); - - PhAddItemList(Context->NodeRootList, node); - - return node; -} - -PDNA_NODE FindClrNode( - _In_ PASMPAGE_QUERY_CONTEXT Context, - _In_ USHORT ClrInstanceID - ) -{ - ULONG i; - - for (i = 0; i < Context->NodeRootList->Count; i++) - { - PDNA_NODE node = Context->NodeRootList->Items[i]; - - if (!node->IsFakeClr && node->u.Clr.ClrInstanceID == ClrInstanceID) - return node; - } - - return NULL; -} - -PDNA_NODE FindAppDomainNode( - _In_ PDNA_NODE ClrNode, - _In_ ULONG64 AppDomainID - ) -{ - ULONG i; - - for (i = 0; i < ClrNode->Children->Count; i++) - { - PDNA_NODE node = ClrNode->Children->Items[i]; - - if (node->u.AppDomain.AppDomainID == AppDomainID) - return node; - } - - return NULL; -} - -PDNA_NODE FindAssemblyNode( - _In_ PDNA_NODE AppDomainNode, - _In_ ULONG64 AssemblyID - ) -{ - ULONG i; - - for (i = 0; i < AppDomainNode->Children->Count; i++) - { - PDNA_NODE node = AppDomainNode->Children->Items[i]; - - if (node->u.Assembly.AssemblyID == AssemblyID) - return node; - } - - return NULL; -} - -PDNA_NODE FindAssemblyNode2( - _In_ PDNA_NODE ClrNode, - _In_ ULONG64 AssemblyID - ) -{ - ULONG i; - ULONG j; - - for (i = 0; i < ClrNode->Children->Count; i++) - { - PDNA_NODE appDomainNode = ClrNode->Children->Items[i]; - - for (j = 0; j < appDomainNode->Children->Count; j++) - { - PDNA_NODE assemblyNode = appDomainNode->Children->Items[j]; - - if (assemblyNode->u.Assembly.AssemblyID == AssemblyID) - return assemblyNode; - } - } - - return NULL; -} - -static int __cdecl AssemblyNodeNameCompareFunction( - _In_ const void *elem1, - _In_ const void *elem2 - ) -{ - PDNA_NODE node1 = *(PDNA_NODE *)elem1; - PDNA_NODE node2 = *(PDNA_NODE *)elem2; - - return PhCompareStringRef(&node1->StructureText, &node2->StructureText, TRUE); -} - -PDNA_NODE DotNetAsmGetSelectedEntry( - _In_ PASMPAGE_CONTEXT Context - ) -{ - if (Context->NodeList) - { - for (ULONG i = 0; i < Context->NodeList->Count; i++) - { - PDNA_NODE node = Context->NodeList->Items[i]; - - if (node->Node.Selected) - { - return node; - } - } - } - - return NULL; -} - -VOID DotNetAsmShowContextMenu( - _In_ PASMPAGE_CONTEXT Context, - _In_ POINT Location - ) -{ - PDNA_NODE node; - PPH_EMENU menu; - PPH_EMENU_ITEM selectedItem; - - if (!(node = DotNetAsmGetSelectedEntry(Context))) - return; - - menu = PhCreateEMenu(); - PhLoadResourceEMenuItem(menu, PluginInstance->DllBase, MAKEINTRESOURCE(IDR_ASSEMBLY_MENU), 0); - - if (PhIsNullOrEmptyString(node->PathText) || !RtlDoesFileExists_U(node->PathText->Buffer)) - { - PhSetFlagsEMenuItem(menu, ID_CLR_OPENFILELOCATION, PH_EMENU_DISABLED, PH_EMENU_DISABLED); - } - - selectedItem = PhShowEMenu( - menu, - Context->WindowHandle, - PH_EMENU_SHOW_LEFTRIGHT, - PH_ALIGN_LEFT | PH_ALIGN_TOP, - Location.x, - Location.y - ); - - if (selectedItem && selectedItem->Id != -1) - { - switch (selectedItem->Id) - { - case ID_CLR_OPENFILELOCATION: - { - if (!PhIsNullOrEmptyString(node->PathText) && RtlDoesFileExists_U(node->PathText->Buffer)) - { - PhShellExploreFile(Context->WindowHandle, node->PathText->Buffer); - } - } - break; - case ID_CLR_COPY: - { - PPH_STRING text; - - text = PhGetTreeNewText(Context->TnHandle, 0); - PhSetClipboardString(Context->TnHandle, &text->sr); - PhDereferenceObject(text); - } - break; - } - } - - PhDestroyEMenu(menu); -} - -BOOLEAN NTAPI DotNetAsmTreeNewCallback( - _In_ HWND hwnd, - _In_ PH_TREENEW_MESSAGE Message, - _In_opt_ PVOID Parameter1, - _In_opt_ PVOID Parameter2, - _In_opt_ PVOID Context - ) -{ - PASMPAGE_CONTEXT context; - PDNA_NODE node; - - context = Context; - - switch (Message) - { - case TreeNewGetChildren: - { - PPH_TREENEW_GET_CHILDREN getChildren = Parameter1; - - node = (PDNA_NODE)getChildren->Node; - - if (!node) - { - getChildren->Children = (PPH_TREENEW_NODE *)context->NodeRootList->Items; - getChildren->NumberOfChildren = context->NodeRootList->Count; - } - else - { - if (node->Type == DNA_TYPE_APPDOMAIN || node == context->ClrV2Node) - { - // Sort the assemblies. - qsort(node->Children->Items, node->Children->Count, sizeof(PVOID), AssemblyNodeNameCompareFunction); - } - - getChildren->Children = (PPH_TREENEW_NODE *)node->Children->Items; - getChildren->NumberOfChildren = node->Children->Count; - } - } - return TRUE; - case TreeNewIsLeaf: - { - PPH_TREENEW_IS_LEAF isLeaf = Parameter1; - - node = (PDNA_NODE)isLeaf->Node; - - isLeaf->IsLeaf = node->Children->Count == 0; - } - return TRUE; - case TreeNewGetCellText: - { - PPH_TREENEW_GET_CELL_TEXT getCellText = Parameter1; - - node = (PDNA_NODE)getCellText->Node; - - switch (getCellText->Id) - { - case DNATNC_STRUCTURE: - getCellText->Text = node->StructureText; - break; - case DNATNC_ID: - getCellText->Text = PhGetStringRef(node->IdText); - break; - case DNATNC_FLAGS: - getCellText->Text = PhGetStringRef(node->FlagsText); - break; - case DNATNC_PATH: - getCellText->Text = PhGetStringRef(node->PathText); - break; - case DNATNC_NATIVEPATH: - getCellText->Text = PhGetStringRef(node->NativePathText); - break; - default: - return FALSE; - } - - getCellText->Flags = TN_CACHE; - } - return TRUE; - case TreeNewGetCellTooltip: - { - PPH_TREENEW_GET_CELL_TOOLTIP getCellTooltip = Parameter1; - - node = (PDNA_NODE)getCellTooltip->Node; - - if (getCellTooltip->Column->Id != 0 || node->Type != DNA_TYPE_ASSEMBLY) - return FALSE; - - if (!PhIsNullOrEmptyString(node->u.Assembly.FullyQualifiedAssemblyName)) - { - getCellTooltip->Text = node->u.Assembly.FullyQualifiedAssemblyName->sr; - getCellTooltip->Unfolding = FALSE; - } - else - { - return FALSE; - } - } - return TRUE; - case TreeNewKeyDown: - { - PPH_TREENEW_KEY_EVENT keyEvent = Parameter1; - - switch (keyEvent->VirtualKey) - { - case 'C': - if (GetKeyState(VK_CONTROL) < 0) - SendMessage(context->WindowHandle, WM_COMMAND, ID_COPY, 0); - break; - } - } - return TRUE; - case TreeNewContextMenu: - { - PPH_TREENEW_MOUSE_EVENT mouseEvent = Parameter1; - - DotNetAsmShowContextMenu(context, mouseEvent->Location); - } - return TRUE; - } - - return FALSE; -} - -ULONG StartDotNetTrace( - _Out_ PTRACEHANDLE SessionHandle, - _Out_ PEVENT_TRACE_PROPERTIES *Properties - ) -{ - ULONG result; - ULONG bufferSize; - PEVENT_TRACE_PROPERTIES properties; - TRACEHANDLE sessionHandle; - - bufferSize = sizeof(EVENT_TRACE_PROPERTIES) + DotNetLoggerName.Length + sizeof(WCHAR); - properties = PhAllocate(bufferSize); - memset(properties, 0, sizeof(EVENT_TRACE_PROPERTIES)); - - properties->Wnode.BufferSize = bufferSize; - properties->Wnode.ClientContext = 2; // System time clock resolution - properties->Wnode.Flags = WNODE_FLAG_TRACED_GUID; - properties->LogFileMode = EVENT_TRACE_REAL_TIME_MODE | EVENT_TRACE_USE_PAGED_MEMORY; - properties->LogFileNameOffset = 0; - properties->LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES); - - result = StartTrace(&sessionHandle, DotNetLoggerName.Buffer, properties); - - if (result == ERROR_SUCCESS) - { - *SessionHandle = sessionHandle; - *Properties = properties; - - return ERROR_SUCCESS; - } - else if (result == ERROR_ALREADY_EXISTS) - { - // Session already exists, so use that. Get the existing session handle. - - result = ControlTrace(0, DotNetLoggerName.Buffer, properties, EVENT_TRACE_CONTROL_QUERY); - - if (result != ERROR_SUCCESS) - { - PhFree(properties); - return result; - } - - *SessionHandle = properties->Wnode.HistoricalContext; - *Properties = properties; - - return ERROR_SUCCESS; - } - else - { - PhFree(properties); - - return result; - } -} - -ULONG NTAPI DotNetBufferCallback( - _In_ PEVENT_TRACE_LOGFILE Buffer - ) -{ - return TRUE; -} - -VOID NTAPI DotNetEventCallback( - _In_ PEVENT_RECORD EventRecord - ) -{ - PASMPAGE_QUERY_CONTEXT context = EventRecord->UserContext; - PEVENT_HEADER eventHeader = &EventRecord->EventHeader; - PEVENT_DESCRIPTOR eventDescriptor = &eventHeader->EventDescriptor; - - if (UlongToHandle(eventHeader->ProcessId) == context->ProcessId) - { - // .NET 4.0+ - - switch (eventDescriptor->Id) - { - case RuntimeInformationDCStart: - { - PRuntimeInformationRundown data = EventRecord->UserData; - PDNA_NODE node; - PPH_STRING startupFlagsString; - PPH_STRING startupModeString; - - // Check for duplicates. - if (FindClrNode(context, data->ClrInstanceID)) - break; - - node = AddNode(context); - node->Type = DNA_TYPE_CLR; - node->u.Clr.ClrInstanceID = data->ClrInstanceID; - node->u.Clr.DisplayName = PhFormatString(L"CLR v%u.%u.%u.%u", data->VMMajorVersion, data->VMMinorVersion, data->VMBuildNumber, data->VMQfeNumber); - node->StructureText = node->u.Clr.DisplayName->sr; - node->IdText = PhFormatString(L"%u", data->ClrInstanceID); - - startupFlagsString = FlagsToString(data->StartupFlags, StartupFlagsMap, sizeof(StartupFlagsMap)); - startupModeString = FlagsToString(data->StartupMode, StartupModeMap, sizeof(StartupModeMap)); - - if (startupFlagsString->Length != 0 && startupModeString->Length != 0) - { - node->FlagsText = PhConcatStrings(3, startupFlagsString->Buffer, L", ", startupModeString->Buffer); - PhDereferenceObject(startupFlagsString); - PhDereferenceObject(startupModeString); - } - else if (startupFlagsString->Length != 0) - { - node->FlagsText = startupFlagsString; - PhDereferenceObject(startupModeString); - } - else if (startupModeString->Length != 0) - { - node->FlagsText = startupModeString; - PhDereferenceObject(startupFlagsString); - } - - if (data->CommandLine[0]) - node->PathText = PhCreateString(data->CommandLine); - - PhAddItemList(context->NodeRootList, node); - } - break; - case AppDomainDCStart_V1: - { - PAppDomainLoadUnloadRundown_V1 data = EventRecord->UserData; - SIZE_T appDomainNameLength; - USHORT clrInstanceID; - PDNA_NODE parentNode; - PDNA_NODE node; - - appDomainNameLength = PhCountStringZ(data->AppDomainName) * sizeof(WCHAR); - clrInstanceID = *(PUSHORT)((PCHAR)data + FIELD_OFFSET(AppDomainLoadUnloadRundown_V1, AppDomainName) + appDomainNameLength + sizeof(WCHAR) + sizeof(ULONG)); - - // Find the CLR node to add the AppDomain node to. - parentNode = FindClrNode(context, clrInstanceID); - - if (parentNode) - { - // Check for duplicates. - if (FindAppDomainNode(parentNode, data->AppDomainID)) - break; - - node = AddNode(context); - node->Type = DNA_TYPE_APPDOMAIN; - node->u.AppDomain.AppDomainID = data->AppDomainID; - node->u.AppDomain.DisplayName = PhConcatStrings2(L"AppDomain: ", data->AppDomainName); - node->StructureText = node->u.AppDomain.DisplayName->sr; - node->IdText = PhFormatString(L"%I64u", data->AppDomainID); - node->FlagsText = FlagsToString(data->AppDomainFlags, AppDomainFlagsMap, sizeof(AppDomainFlagsMap)); - - PhAddItemList(parentNode->Children, node); - } - } - break; - case AssemblyDCStart_V1: - { - PAssemblyLoadUnloadRundown_V1 data = EventRecord->UserData; - SIZE_T fullyQualifiedAssemblyNameLength; - USHORT clrInstanceID; - PDNA_NODE parentNode; - PDNA_NODE node; - PH_STRINGREF remainingPart; - - fullyQualifiedAssemblyNameLength = PhCountStringZ(data->FullyQualifiedAssemblyName) * sizeof(WCHAR); - clrInstanceID = *(PUSHORT)((PCHAR)data + FIELD_OFFSET(AssemblyLoadUnloadRundown_V1, FullyQualifiedAssemblyName) + fullyQualifiedAssemblyNameLength + sizeof(WCHAR)); - - // Find the AppDomain node to add the Assembly node to. - - parentNode = FindClrNode(context, clrInstanceID); - - if (parentNode) - parentNode = FindAppDomainNode(parentNode, data->AppDomainID); - - if (parentNode) - { - // Check for duplicates. - if (FindAssemblyNode(parentNode, data->AssemblyID)) - break; - - node = AddNode(context); - node->Type = DNA_TYPE_ASSEMBLY; - node->u.Assembly.AssemblyID = data->AssemblyID; - node->u.Assembly.FullyQualifiedAssemblyName = PhCreateStringEx(data->FullyQualifiedAssemblyName, fullyQualifiedAssemblyNameLength); - - // Display only the assembly name, not the whole fully qualified name. - if (!PhSplitStringRefAtChar(&node->u.Assembly.FullyQualifiedAssemblyName->sr, ',', &node->StructureText, &remainingPart)) - node->StructureText = node->u.Assembly.FullyQualifiedAssemblyName->sr; - - node->IdText = PhFormatString(L"%I64u", data->AssemblyID); - node->FlagsText = FlagsToString(data->AssemblyFlags, AssemblyFlagsMap, sizeof(AssemblyFlagsMap)); - - PhAddItemList(parentNode->Children, node); - } - } - break; - case ModuleDCStart_V1: - { - PModuleLoadUnloadRundown_V1 data = EventRecord->UserData; - PWSTR moduleILPath; - SIZE_T moduleILPathLength; - PWSTR moduleNativePath; - SIZE_T moduleNativePathLength; - USHORT clrInstanceID; - PDNA_NODE node; - - moduleILPath = data->ModuleILPath; - moduleILPathLength = PhCountStringZ(moduleILPath) * sizeof(WCHAR); - moduleNativePath = (PWSTR)((PCHAR)moduleILPath + moduleILPathLength + sizeof(WCHAR)); - moduleNativePathLength = PhCountStringZ(moduleNativePath) * sizeof(WCHAR); - clrInstanceID = *(PUSHORT)((PCHAR)moduleNativePath + moduleNativePathLength + sizeof(WCHAR)); - - // Find the Assembly node to set the path on. - - node = FindClrNode(context, clrInstanceID); - - if (node) - node = FindAssemblyNode2(node, data->AssemblyID); - - if (node) - { - PhMoveReference(&node->PathText, PhCreateStringEx(moduleILPath, moduleILPathLength)); - - if (moduleNativePathLength != 0) - PhMoveReference(&node->NativePathText, PhCreateStringEx(moduleNativePath, moduleNativePathLength)); - } - } - break; - case DCStartComplete_V1: - { - if (_InterlockedExchange(&context->TraceHandleActive, 0) == 1) - { - CloseTrace(context->TraceHandle); - } - } - break; - } - - // .NET 2.0 - - if (eventDescriptor->Id == 0) - { - switch (eventDescriptor->Opcode) - { - case CLR_MODULEDCSTART_OPCODE: - { - PModuleLoadUnloadRundown_V1 data = EventRecord->UserData; - PWSTR moduleILPath; - SIZE_T moduleILPathLength; - PWSTR moduleNativePath; - SIZE_T moduleNativePathLength; - PDNA_NODE node; - ULONG_PTR indexOfBackslash; - ULONG_PTR indexOfLastDot; - - moduleILPath = data->ModuleILPath; - moduleILPathLength = PhCountStringZ(moduleILPath) * sizeof(WCHAR); - moduleNativePath = (PWSTR)((PCHAR)moduleILPath + moduleILPathLength + sizeof(WCHAR)); - moduleNativePathLength = PhCountStringZ(moduleNativePath) * sizeof(WCHAR); - - if (context->ClrV2Node && (moduleILPathLength != 0 || moduleNativePathLength != 0)) - { - node = AddNode(context); - node->Type = DNA_TYPE_ASSEMBLY; - node->FlagsText = FlagsToString(data->ModuleFlags, ModuleFlagsMap, sizeof(ModuleFlagsMap)); - node->PathText = PhCreateStringEx(moduleILPath, moduleILPathLength); - - if (moduleNativePathLength != 0) - node->NativePathText = PhCreateStringEx(moduleNativePath, moduleNativePathLength); - - // Use the name between the last backslash and the last dot for the structure column text. - // (E.g. C:\...\AcmeSoft.BigLib.dll -> AcmeSoft.BigLib) - - indexOfBackslash = PhFindLastCharInString(node->PathText, 0, '\\'); - indexOfLastDot = PhFindLastCharInString(node->PathText, 0, '.'); - - if (indexOfBackslash != -1) - { - node->StructureText.Buffer = node->PathText->Buffer + indexOfBackslash + 1; - - if (indexOfLastDot != -1 && indexOfLastDot > indexOfBackslash) - { - node->StructureText.Length = (indexOfLastDot - indexOfBackslash - 1) * sizeof(WCHAR); - } - else - { - node->StructureText.Length = node->PathText->Length - indexOfBackslash * sizeof(WCHAR) - sizeof(WCHAR); - } - } - else - { - node->StructureText = node->PathText->sr; - } - - PhAddItemList(context->ClrV2Node->Children, node); - } - } - break; - case CLR_METHODDC_DCSTARTCOMPLETE_OPCODE: - { - if (_InterlockedExchange(&context->TraceHandleActive, 0) == 1) - { - CloseTrace(context->TraceHandle); - } - } - break; - } - } - } -} - -ULONG ProcessDotNetTrace( - _In_ PASMPAGE_QUERY_CONTEXT Context - ) -{ - ULONG result; - TRACEHANDLE traceHandle; - EVENT_TRACE_LOGFILE logFile; - - memset(&logFile, 0, sizeof(EVENT_TRACE_LOGFILE)); - logFile.LoggerName = DotNetLoggerName.Buffer; - logFile.ProcessTraceMode = PROCESS_TRACE_MODE_REAL_TIME | PROCESS_TRACE_MODE_EVENT_RECORD; - logFile.BufferCallback = DotNetBufferCallback; - logFile.EventRecordCallback = DotNetEventCallback; - logFile.Context = Context; - - traceHandle = OpenTrace(&logFile); - - if (traceHandle == INVALID_PROCESSTRACE_HANDLE) - return GetLastError(); - - Context->TraceHandleActive = 1; - Context->TraceHandle = traceHandle; - result = ProcessTrace(&traceHandle, 1, NULL, NULL); - - if (_InterlockedExchange(&Context->TraceHandleActive, 0) == 1) - { - CloseTrace(traceHandle); - } - - return result; -} - -NTSTATUS UpdateDotNetTraceInfoThreadStart( - _In_ PVOID Parameter - ) -{ - static _EnableTraceEx EnableTraceEx_I = NULL; - PASMPAGE_QUERY_CONTEXT context = Parameter; - TRACEHANDLE sessionHandle; - PEVENT_TRACE_PROPERTIES properties; - PGUID guidToEnable; - - if (!EnableTraceEx_I) - EnableTraceEx_I = PhGetModuleProcAddress(L"advapi32.dll", "EnableTraceEx"); - if (!EnableTraceEx_I) - return ERROR_NOT_SUPPORTED; - - context->TraceResult = StartDotNetTrace(&sessionHandle, &properties); - - if (context->TraceResult != 0) - return context->TraceResult; - - if (!context->TraceClrV2) - guidToEnable = &ClrRundownProviderGuid; - else - guidToEnable = &ClrRuntimeProviderGuid; - - EnableTraceEx_I( - guidToEnable, - NULL, - sessionHandle, - 1, - TRACE_LEVEL_INFORMATION, - CLR_LOADER_KEYWORD | CLR_STARTENUMERATION_KEYWORD, - 0, - 0, - NULL - ); - - context->TraceResult = ProcessDotNetTrace(context); - - ControlTrace(sessionHandle, NULL, properties, EVENT_TRACE_CONTROL_STOP); - PhFree(properties); - - return context->TraceResult; -} - -ULONG UpdateDotNetTraceInfoWithTimeout( - _In_ PASMPAGE_QUERY_CONTEXT Context, - _In_ BOOLEAN ClrV2, - _In_opt_ PLARGE_INTEGER Timeout - ) -{ - HANDLE threadHandle; - BOOLEAN timeout = FALSE; - - // ProcessDotNetTrace is not guaranteed to complete within any period of time, because - // the target process might terminate before it writes the DCStartComplete_V1 event. - // If the timeout is reached, the trace handle is closed, forcing ProcessTrace to stop - // processing. - - Context->TraceClrV2 = ClrV2; - Context->TraceResult = 0; - Context->TraceHandleActive = 0; - Context->TraceHandle = 0; - - threadHandle = PhCreateThread(0, UpdateDotNetTraceInfoThreadStart, Context); - - if (NtWaitForSingleObject(threadHandle, FALSE, Timeout) != STATUS_WAIT_0) - { - // Timeout has expired. Stop the trace processing if it's still active. - // BUG: This assumes that the thread is in ProcessTrace. It might still be - // setting up though! - if (_InterlockedExchange(&Context->TraceHandleActive, 0) == 1) - { - CloseTrace(Context->TraceHandle); - timeout = TRUE; - } - - NtWaitForSingleObject(threadHandle, FALSE, NULL); - } - - NtClose(threadHandle); - - if (timeout) - return ERROR_TIMEOUT; - - return Context->TraceResult; -} - -NTSTATUS DotNetTraceQueryThreadStart( - _In_ PVOID Parameter - ) -{ - LARGE_INTEGER timeout; - PASMPAGE_QUERY_CONTEXT context = Parameter; - BOOLEAN timeoutReached = FALSE; - BOOLEAN nonClrNode = FALSE; - ULONG i; - ULONG result = 0; - - if (context->ClrVersions & PH_CLR_VERSION_1_0) - { - AddFakeClrNode(context, L"CLR v1.0.3705"); // what PE displays - } - - if (context->ClrVersions & PH_CLR_VERSION_1_1) - { - AddFakeClrNode(context, L"CLR v1.1.4322"); - } - - timeout.QuadPart = -10 * PH_TIMEOUT_SEC; - - if (context->ClrVersions & PH_CLR_VERSION_2_0) - { - context->ClrV2Node = AddFakeClrNode(context, L"CLR v2.0.50727"); - result = UpdateDotNetTraceInfoWithTimeout(context, TRUE, &timeout); - - if (result == ERROR_TIMEOUT) - { - timeoutReached = TRUE; - result = ERROR_SUCCESS; - } - } - - if (context->ClrVersions & PH_CLR_VERSION_4_ABOVE) - { - result = UpdateDotNetTraceInfoWithTimeout(context, FALSE, &timeout); - - if (result == ERROR_TIMEOUT) - { - timeoutReached = TRUE; - result = ERROR_SUCCESS; - } - } - // If we reached the timeout, check whether we got any data back. - if (timeoutReached) - { - for (i = 0; i < context->NodeList->Count; i++) - { - PDNA_NODE node = context->NodeList->Items[i]; - - if (node->Type != DNA_TYPE_CLR) - { - nonClrNode = TRUE; - break; - } - } - - if (!nonClrNode) - result = ERROR_TIMEOUT; - } - - // If the process properties window has been closed, bail and cleanup. - // IsWindow should be safe from being called on this thread: - // https://blogs.msdn.microsoft.com/oldnewthing/20070717-00/?p=25983 - if (IsWindow(context->WindowHandle)) - { - PostMessage(context->WindowHandle, UPDATE_MSG, result, (LPARAM)context); - } - else - { - DestroyDotNetTraceQuery(context); - } - - return STATUS_SUCCESS; -} - -VOID CreateDotNetTraceQueryThread( - _In_ HWND WindowHandle, - _In_ ULONG ClrVersions, - _In_ HANDLE ProcessId - ) -{ - HANDLE threadHandle; - PASMPAGE_QUERY_CONTEXT context; - - context = PhAllocate(sizeof(ASMPAGE_QUERY_CONTEXT)); - memset(context, 0, sizeof(ASMPAGE_QUERY_CONTEXT)); - - context->WindowHandle = WindowHandle; - context->ClrVersions = ClrVersions; - context->ProcessId = ProcessId; - context->NodeList = PhCreateList(64); - context->NodeRootList = PhCreateList(2); - - if (threadHandle = PhCreateThread(0, DotNetTraceQueryThreadStart, context)) - { - NtClose(threadHandle); - } - else - { - DestroyDotNetTraceQuery(context); - } -} - -VOID DestroyDotNetTraceQuery( - _In_ PASMPAGE_QUERY_CONTEXT Context - ) -{ - if (Context->NodeList) - { - PhClearReference(&Context->NodeList); - } - - if (Context->NodeRootList) - { - PhClearReference(&Context->NodeRootList); - } - - PhFree(Context); -} - -BOOLEAN IsProcessSuspended( - _In_ HANDLE ProcessId - ) -{ - PVOID processes; - PSYSTEM_PROCESS_INFORMATION process; - - if (NT_SUCCESS(PhEnumProcesses(&processes))) - { - if (process = PhFindProcessInformation(processes, ProcessId)) - return PhGetProcessIsSuspended(process); - - PhFree(processes); - } - - return FALSE; -} - -INT_PTR CALLBACK DotNetAsmPageDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - LPPROPSHEETPAGE propSheetPage; - PPH_PROCESS_PROPPAGECONTEXT propPageContext; - PPH_PROCESS_ITEM processItem; - PASMPAGE_CONTEXT context; - - if (PhPropPageDlgProcHeader(hwndDlg, uMsg, lParam, &propSheetPage, &propPageContext, &processItem)) - { - context = propPageContext->Context; - } - else - { - return FALSE; - } - - switch (uMsg) - { - case WM_INITDIALOG: - { - PPH_STRING settings; - HWND tnHandle; - - context = PhAllocate(sizeof(ASMPAGE_CONTEXT)); - memset(context, 0, sizeof(ASMPAGE_CONTEXT)); - propPageContext->Context = context; - context->WindowHandle = hwndDlg; - context->ProcessItem = processItem; - - context->ClrVersions = 0; - PhGetProcessIsDotNetEx(processItem->ProcessId, NULL, 0, NULL, &context->ClrVersions); - - tnHandle = GetDlgItem(hwndDlg, IDC_LIST); - context->TnHandle = tnHandle; - - TreeNew_SetCallback(tnHandle, DotNetAsmTreeNewCallback, context); - TreeNew_SetExtendedFlags(tnHandle, TN_FLAG_ITEM_DRAG_SELECT, TN_FLAG_ITEM_DRAG_SELECT); - PhSetControlTheme(tnHandle, L"explorer"); - SendMessage(TreeNew_GetTooltips(tnHandle), TTM_SETMAXTIPWIDTH, 0, MAXSHORT); - PhAddTreeNewColumn(tnHandle, DNATNC_STRUCTURE, TRUE, L"Structure", 240, PH_ALIGN_LEFT, -2, 0); - PhAddTreeNewColumn(tnHandle, DNATNC_ID, TRUE, L"ID", 50, PH_ALIGN_RIGHT, 0, DT_RIGHT); - PhAddTreeNewColumn(tnHandle, DNATNC_FLAGS, TRUE, L"Flags", 120, PH_ALIGN_LEFT, 1, 0); - PhAddTreeNewColumn(tnHandle, DNATNC_PATH, TRUE, L"Path", 600, PH_ALIGN_LEFT, 2, 0); // don't use path ellipsis - the user already has the base file name - PhAddTreeNewColumn(tnHandle, DNATNC_NATIVEPATH, TRUE, L"Native image path", 600, PH_ALIGN_LEFT, 3, 0); - - settings = PhGetStringSetting(SETTING_NAME_ASM_TREE_LIST_COLUMNS); - PhCmLoadSettings(tnHandle, &settings->sr); - PhDereferenceObject(settings); - - PhMoveReference(&context->TnErrorMessage, PhCreateString(L"Loading .NET assemblies...")); - TreeNew_SetEmptyText(tnHandle, &context->TnErrorMessage->sr, 0); - - if ( - !IsProcessSuspended(processItem->ProcessId) || - PhShowMessage(hwndDlg, MB_ICONWARNING | MB_YESNO, L".NET assembly enumeration may not work properly because the process is currently suspended. Do you want to continue?") == IDYES - ) - { - CreateDotNetTraceQueryThread( - hwndDlg, - context->ClrVersions, - processItem->ProcessId - ); - } - else - { - PhMoveReference(&context->TnErrorMessage, - PhCreateString(L"Unable to start the event tracing session because the process is suspended.") - ); - TreeNew_SetEmptyText(tnHandle, &context->TnErrorMessage->sr, 0); - InvalidateRect(tnHandle, NULL, FALSE); - } - - EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); - } - break; - case WM_DESTROY: - { - PPH_STRING settings; - ULONG i; - - settings = PhCmSaveSettings(context->TnHandle); - PhSetStringSetting2(SETTING_NAME_ASM_TREE_LIST_COLUMNS, &settings->sr); - PhDereferenceObject(settings); - - if (context->NodeList) - { - for (i = 0; i < context->NodeList->Count; i++) - DestroyNode(context->NodeList->Items[i]); - - PhDereferenceObject(context->NodeList); - } - - if (context->NodeRootList) - PhDereferenceObject(context->NodeRootList); - - PhClearReference(&context->TnErrorMessage); - PhFree(context); - - PhPropPageDlgProcDestroy(hwndDlg); - } - break; - case WM_SHOWWINDOW: - { - PPH_LAYOUT_ITEM dialogItem; - - if (dialogItem = PhBeginPropPageLayout(hwndDlg, propPageContext)) - { - PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_LIST), dialogItem, PH_ANCHOR_ALL); - PhEndPropPageLayout(hwndDlg, propPageContext); - } - } - break; - case WM_COMMAND: - { - switch (LOWORD(wParam)) - { - case ID_COPY: - { - PPH_STRING text; - - text = PhGetTreeNewText(context->TnHandle, 0); - PhSetClipboardString(context->TnHandle, &text->sr); - PhDereferenceObject(text); - } - break; - } - } - break; - case UPDATE_MSG: - { - ULONG result = (ULONG)wParam; - PASMPAGE_QUERY_CONTEXT queryContext = (PASMPAGE_QUERY_CONTEXT)lParam; - - if (result == 0) - { - PhSwapReference(&context->NodeList, queryContext->NodeList); - PhSwapReference(&context->NodeRootList, queryContext->NodeRootList); - - DestroyDotNetTraceQuery(queryContext); - - TreeNew_NodesStructured(context->TnHandle); - } - else - { - PhMoveReference(&context->TnErrorMessage, - PhConcatStrings2(L"Unable to start the event tracing session: ", PhGetStringOrDefault(PhGetWin32Message(result), L"Unknown error")) - ); - TreeNew_SetEmptyText(context->TnHandle, &context->TnErrorMessage->sr, 0); - InvalidateRect(context->TnHandle, NULL, FALSE); - } - } - break; - } - - return FALSE; -} +/* + * Process Hacker .NET Tools - + * .NET Assemblies property page + * + * Copyright (C) 2011-2015 wj32 + * Copyright (C) 2016 dmex + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include "dn.h" +#include "clretw.h" +#include +#include + +#define DNATNC_STRUCTURE 0 +#define DNATNC_ID 1 +#define DNATNC_FLAGS 2 +#define DNATNC_PATH 3 +#define DNATNC_NATIVEPATH 4 +#define DNATNC_MAXIMUM 5 + +#define DNA_TYPE_CLR 1 +#define DNA_TYPE_APPDOMAIN 2 +#define DNA_TYPE_ASSEMBLY 3 + +#define UPDATE_MSG (WM_APP + 1) + +typedef struct _DNA_NODE +{ + PH_TREENEW_NODE Node; + + struct _DNA_NODE *Parent; + PPH_LIST Children; + + PH_STRINGREF TextCache[DNATNC_MAXIMUM]; + + ULONG Type; + BOOLEAN IsFakeClr; + + union + { + struct + { + USHORT ClrInstanceID; + PPH_STRING DisplayName; + } Clr; + struct + { + ULONG64 AppDomainID; + PPH_STRING DisplayName; + } AppDomain; + struct + { + ULONG64 AssemblyID; + PPH_STRING FullyQualifiedAssemblyName; + } Assembly; + } u; + + PH_STRINGREF StructureText; + PPH_STRING IdText; + PPH_STRING FlagsText; + PPH_STRING PathText; + PPH_STRING NativePathText; +} DNA_NODE, *PDNA_NODE; + +typedef struct _ASMPAGE_CONTEXT +{ + HWND WindowHandle; + PPH_PROCESS_ITEM ProcessItem; + ULONG ClrVersions; + PDNA_NODE ClrV2Node; + + HWND TnHandle; + PPH_STRING TnErrorMessage; + PPH_LIST NodeList; + PPH_LIST NodeRootList; +} ASMPAGE_CONTEXT, *PASMPAGE_CONTEXT; + +typedef struct _ASMPAGE_QUERY_CONTEXT +{ + HANDLE WindowHandle; + + HANDLE ProcessId; + ULONG ClrVersions; + PDNA_NODE ClrV2Node; + + BOOLEAN TraceClrV2; + ULONG TraceResult; + LONG TraceHandleActive; + TRACEHANDLE TraceHandle; + + PPH_LIST NodeList; + PPH_LIST NodeRootList; +} ASMPAGE_QUERY_CONTEXT, *PASMPAGE_QUERY_CONTEXT; + +typedef struct _FLAG_DEFINITION +{ + PWSTR Name; + ULONG Flag; +} FLAG_DEFINITION, *PFLAG_DEFINITION; + +typedef ULONG (__stdcall *_EnableTraceEx)( + _In_ LPCGUID ProviderId, + _In_opt_ LPCGUID SourceId, + _In_ TRACEHANDLE TraceHandle, + _In_ ULONG IsEnabled, + _In_ UCHAR Level, + _In_ ULONGLONG MatchAnyKeyword, + _In_ ULONGLONG MatchAllKeyword, + _In_ ULONG EnableProperty, + _In_opt_ PEVENT_FILTER_DESCRIPTOR EnableFilterDesc + ); + +VOID DestroyDotNetTraceQuery( + _In_ PASMPAGE_QUERY_CONTEXT Context + ); + +INT_PTR CALLBACK DotNetAsmPageDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +static UNICODE_STRING DotNetLoggerName = RTL_CONSTANT_STRING(L"PhDnLogger"); +static GUID ClrRuntimeProviderGuid = { 0xe13c0d23, 0xccbc, 0x4e12, { 0x93, 0x1b, 0xd9, 0xcc, 0x2e, 0xee, 0x27, 0xe4 } }; +static GUID ClrRundownProviderGuid = { 0xa669021c, 0xc450, 0x4609, { 0xa0, 0x35, 0x5a, 0xf5, 0x9a, 0xf4, 0xdf, 0x18 } }; + +static FLAG_DEFINITION AppDomainFlagsMap[] = +{ + { L"Default", 0x1 }, + { L"Executable", 0x2 }, + { L"Shared", 0x4 } +}; + +static FLAG_DEFINITION AssemblyFlagsMap[] = +{ + { L"DomainNeutral", 0x1 }, + { L"Dynamic", 0x2 }, + { L"Native", 0x4 }, + { L"Collectible", 0x8 } +}; + +static FLAG_DEFINITION ModuleFlagsMap[] = +{ + { L"DomainNeutral", 0x1 }, + { L"Native", 0x2 }, + { L"Dynamic", 0x4 }, + { L"Manifest", 0x8 } +}; + +static FLAG_DEFINITION StartupModeMap[] = +{ + { L"ManagedExe", 0x1 }, + { L"HostedCLR", 0x2 }, + { L"IjwDll", 0x4 }, + { L"ComActivated", 0x8 }, + { L"Other", 0x10 } +}; + +static FLAG_DEFINITION StartupFlagsMap[] = +{ + { L"CONCURRENT_GC", 0x1 }, + { L"LOADER_OPTIMIZATION_SINGLE_DOMAIN", 0x2 }, + { L"LOADER_OPTIMIZATION_MULTI_DOMAIN", 0x4 }, + { L"LOADER_SAFEMODE", 0x10 }, + { L"LOADER_SETPREFERENCE", 0x100 }, + { L"SERVER_GC", 0x1000 }, + { L"HOARD_GC_VM", 0x2000 }, + { L"SINGLE_VERSION_HOSTING_INTERFACE", 0x4000 }, + { L"LEGACY_IMPERSONATION", 0x10000 }, + { L"DISABLE_COMMITTHREADSTACK", 0x20000 }, + { L"ALWAYSFLOW_IMPERSONATION", 0x40000 }, + { L"TRIM_GC_COMMIT", 0x80000 }, + { L"ETW", 0x100000 }, + { L"SERVER_BUILD", 0x200000 }, + { L"ARM", 0x400000 } +}; + +VOID AddAsmPageToPropContext( + _In_ PPH_PLUGIN_PROCESS_PROPCONTEXT PropContext + ) +{ + PhAddProcessPropPage( + PropContext->PropContext, + PhCreateProcessPropPageContextEx(PluginInstance->DllBase, MAKEINTRESOURCE(IDD_PROCDOTNETASM), DotNetAsmPageDlgProc, NULL) + ); +} + +PPH_STRING FlagsToString( + _In_ ULONG Flags, + _In_ PFLAG_DEFINITION Map, + _In_ ULONG SizeOfMap + ) +{ + PH_STRING_BUILDER sb; + ULONG i; + + PhInitializeStringBuilder(&sb, 100); + + for (i = 0; i < SizeOfMap / sizeof(FLAG_DEFINITION); i++) + { + if (Flags & Map[i].Flag) + { + PhAppendStringBuilder2(&sb, Map[i].Name); + PhAppendStringBuilder2(&sb, L", "); + } + } + + if (sb.String->Length != 0) + PhRemoveEndStringBuilder(&sb, 2); + + return PhFinalStringBuilderString(&sb); +} + +PDNA_NODE AddNode( + _Inout_ PASMPAGE_QUERY_CONTEXT Context + ) +{ + PDNA_NODE node; + + node = PhAllocate(sizeof(DNA_NODE)); + memset(node, 0, sizeof(DNA_NODE)); + PhInitializeTreeNewNode(&node->Node); + + memset(node->TextCache, 0, sizeof(PH_STRINGREF) * DNATNC_MAXIMUM); + node->Node.TextCache = node->TextCache; + node->Node.TextCacheSize = DNATNC_MAXIMUM; + + node->Children = PhCreateList(1); + + PhAddItemList(Context->NodeList, node); + + return node; +} + +VOID DestroyNode( + _In_ PDNA_NODE Node + ) +{ + PhDereferenceObject(Node->Children); + + if (Node->Type == DNA_TYPE_CLR) + { + if (Node->u.Clr.DisplayName) PhDereferenceObject(Node->u.Clr.DisplayName); + } + else if (Node->Type == DNA_TYPE_APPDOMAIN) + { + if (Node->u.AppDomain.DisplayName) PhDereferenceObject(Node->u.AppDomain.DisplayName); + } + else if (Node->Type == DNA_TYPE_ASSEMBLY) + { + if (Node->u.Assembly.FullyQualifiedAssemblyName) PhDereferenceObject(Node->u.Assembly.FullyQualifiedAssemblyName); + } + + if (Node->IdText) PhDereferenceObject(Node->IdText); + if (Node->FlagsText) PhDereferenceObject(Node->FlagsText); + if (Node->PathText) PhDereferenceObject(Node->PathText); + if (Node->NativePathText) PhDereferenceObject(Node->NativePathText); + + PhFree(Node); +} + +PDNA_NODE AddFakeClrNode( + _In_ PASMPAGE_QUERY_CONTEXT Context, + _In_ PWSTR DisplayName + ) +{ + PDNA_NODE node; + + node = AddNode(Context); + node->Type = DNA_TYPE_CLR; + node->IsFakeClr = TRUE; + node->u.Clr.ClrInstanceID = 0; + node->u.Clr.DisplayName = NULL; + PhInitializeStringRef(&node->StructureText, DisplayName); + + PhAddItemList(Context->NodeRootList, node); + + return node; +} + +PDNA_NODE FindClrNode( + _In_ PASMPAGE_QUERY_CONTEXT Context, + _In_ USHORT ClrInstanceID + ) +{ + ULONG i; + + for (i = 0; i < Context->NodeRootList->Count; i++) + { + PDNA_NODE node = Context->NodeRootList->Items[i]; + + if (!node->IsFakeClr && node->u.Clr.ClrInstanceID == ClrInstanceID) + return node; + } + + return NULL; +} + +PDNA_NODE FindAppDomainNode( + _In_ PDNA_NODE ClrNode, + _In_ ULONG64 AppDomainID + ) +{ + ULONG i; + + for (i = 0; i < ClrNode->Children->Count; i++) + { + PDNA_NODE node = ClrNode->Children->Items[i]; + + if (node->u.AppDomain.AppDomainID == AppDomainID) + return node; + } + + return NULL; +} + +PDNA_NODE FindAssemblyNode( + _In_ PDNA_NODE AppDomainNode, + _In_ ULONG64 AssemblyID + ) +{ + ULONG i; + + for (i = 0; i < AppDomainNode->Children->Count; i++) + { + PDNA_NODE node = AppDomainNode->Children->Items[i]; + + if (node->u.Assembly.AssemblyID == AssemblyID) + return node; + } + + return NULL; +} + +PDNA_NODE FindAssemblyNode2( + _In_ PDNA_NODE ClrNode, + _In_ ULONG64 AssemblyID + ) +{ + ULONG i; + ULONG j; + + for (i = 0; i < ClrNode->Children->Count; i++) + { + PDNA_NODE appDomainNode = ClrNode->Children->Items[i]; + + for (j = 0; j < appDomainNode->Children->Count; j++) + { + PDNA_NODE assemblyNode = appDomainNode->Children->Items[j]; + + if (assemblyNode->u.Assembly.AssemblyID == AssemblyID) + return assemblyNode; + } + } + + return NULL; +} + +static int __cdecl AssemblyNodeNameCompareFunction( + _In_ const void *elem1, + _In_ const void *elem2 + ) +{ + PDNA_NODE node1 = *(PDNA_NODE *)elem1; + PDNA_NODE node2 = *(PDNA_NODE *)elem2; + + return PhCompareStringRef(&node1->StructureText, &node2->StructureText, TRUE); +} + +PDNA_NODE DotNetAsmGetSelectedEntry( + _In_ PASMPAGE_CONTEXT Context + ) +{ + if (Context->NodeList) + { + for (ULONG i = 0; i < Context->NodeList->Count; i++) + { + PDNA_NODE node = Context->NodeList->Items[i]; + + if (node->Node.Selected) + { + return node; + } + } + } + + return NULL; +} + +VOID DotNetAsmShowContextMenu( + _In_ PASMPAGE_CONTEXT Context, + _In_ POINT Location + ) +{ + PDNA_NODE node; + PPH_EMENU menu; + PPH_EMENU_ITEM selectedItem; + + if (!(node = DotNetAsmGetSelectedEntry(Context))) + return; + + menu = PhCreateEMenu(); + PhLoadResourceEMenuItem(menu, PluginInstance->DllBase, MAKEINTRESOURCE(IDR_ASSEMBLY_MENU), 0); + + if (PhIsNullOrEmptyString(node->PathText) || !RtlDoesFileExists_U(node->PathText->Buffer)) + { + PhSetFlagsEMenuItem(menu, ID_CLR_OPENFILELOCATION, PH_EMENU_DISABLED, PH_EMENU_DISABLED); + } + + selectedItem = PhShowEMenu( + menu, + Context->WindowHandle, + PH_EMENU_SHOW_LEFTRIGHT, + PH_ALIGN_LEFT | PH_ALIGN_TOP, + Location.x, + Location.y + ); + + if (selectedItem && selectedItem->Id != -1) + { + switch (selectedItem->Id) + { + case ID_CLR_OPENFILELOCATION: + { + if (!PhIsNullOrEmptyString(node->PathText) && RtlDoesFileExists_U(node->PathText->Buffer)) + { + PhShellExploreFile(Context->WindowHandle, node->PathText->Buffer); + } + } + break; + case ID_CLR_COPY: + { + PPH_STRING text; + + text = PhGetTreeNewText(Context->TnHandle, 0); + PhSetClipboardString(Context->TnHandle, &text->sr); + PhDereferenceObject(text); + } + break; + } + } + + PhDestroyEMenu(menu); +} + +BOOLEAN NTAPI DotNetAsmTreeNewCallback( + _In_ HWND hwnd, + _In_ PH_TREENEW_MESSAGE Message, + _In_opt_ PVOID Parameter1, + _In_opt_ PVOID Parameter2, + _In_opt_ PVOID Context + ) +{ + PASMPAGE_CONTEXT context; + PDNA_NODE node; + + context = Context; + + switch (Message) + { + case TreeNewGetChildren: + { + PPH_TREENEW_GET_CHILDREN getChildren = Parameter1; + + node = (PDNA_NODE)getChildren->Node; + + if (!node) + { + getChildren->Children = (PPH_TREENEW_NODE *)context->NodeRootList->Items; + getChildren->NumberOfChildren = context->NodeRootList->Count; + } + else + { + if (node->Type == DNA_TYPE_APPDOMAIN || node == context->ClrV2Node) + { + // Sort the assemblies. + qsort(node->Children->Items, node->Children->Count, sizeof(PVOID), AssemblyNodeNameCompareFunction); + } + + getChildren->Children = (PPH_TREENEW_NODE *)node->Children->Items; + getChildren->NumberOfChildren = node->Children->Count; + } + } + return TRUE; + case TreeNewIsLeaf: + { + PPH_TREENEW_IS_LEAF isLeaf = Parameter1; + + node = (PDNA_NODE)isLeaf->Node; + + isLeaf->IsLeaf = node->Children->Count == 0; + } + return TRUE; + case TreeNewGetCellText: + { + PPH_TREENEW_GET_CELL_TEXT getCellText = Parameter1; + + node = (PDNA_NODE)getCellText->Node; + + switch (getCellText->Id) + { + case DNATNC_STRUCTURE: + getCellText->Text = node->StructureText; + break; + case DNATNC_ID: + getCellText->Text = PhGetStringRef(node->IdText); + break; + case DNATNC_FLAGS: + getCellText->Text = PhGetStringRef(node->FlagsText); + break; + case DNATNC_PATH: + getCellText->Text = PhGetStringRef(node->PathText); + break; + case DNATNC_NATIVEPATH: + getCellText->Text = PhGetStringRef(node->NativePathText); + break; + default: + return FALSE; + } + + getCellText->Flags = TN_CACHE; + } + return TRUE; + case TreeNewGetCellTooltip: + { + PPH_TREENEW_GET_CELL_TOOLTIP getCellTooltip = Parameter1; + + node = (PDNA_NODE)getCellTooltip->Node; + + if (getCellTooltip->Column->Id != 0 || node->Type != DNA_TYPE_ASSEMBLY) + return FALSE; + + if (!PhIsNullOrEmptyString(node->u.Assembly.FullyQualifiedAssemblyName)) + { + getCellTooltip->Text = node->u.Assembly.FullyQualifiedAssemblyName->sr; + getCellTooltip->Unfolding = FALSE; + } + else + { + return FALSE; + } + } + return TRUE; + case TreeNewKeyDown: + { + PPH_TREENEW_KEY_EVENT keyEvent = Parameter1; + + switch (keyEvent->VirtualKey) + { + case 'C': + if (GetKeyState(VK_CONTROL) < 0) + SendMessage(context->WindowHandle, WM_COMMAND, ID_COPY, 0); + break; + } + } + return TRUE; + case TreeNewContextMenu: + { + PPH_TREENEW_MOUSE_EVENT mouseEvent = Parameter1; + + DotNetAsmShowContextMenu(context, mouseEvent->Location); + } + return TRUE; + } + + return FALSE; +} + +ULONG StartDotNetTrace( + _Out_ PTRACEHANDLE SessionHandle, + _Out_ PEVENT_TRACE_PROPERTIES *Properties + ) +{ + ULONG result; + ULONG bufferSize; + PEVENT_TRACE_PROPERTIES properties; + TRACEHANDLE sessionHandle; + + bufferSize = sizeof(EVENT_TRACE_PROPERTIES) + DotNetLoggerName.Length + sizeof(WCHAR); + properties = PhAllocate(bufferSize); + memset(properties, 0, sizeof(EVENT_TRACE_PROPERTIES)); + + properties->Wnode.BufferSize = bufferSize; + properties->Wnode.ClientContext = 2; // System time clock resolution + properties->Wnode.Flags = WNODE_FLAG_TRACED_GUID; + properties->LogFileMode = EVENT_TRACE_REAL_TIME_MODE | EVENT_TRACE_USE_PAGED_MEMORY; + properties->LogFileNameOffset = 0; + properties->LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES); + + result = StartTrace(&sessionHandle, DotNetLoggerName.Buffer, properties); + + if (result == ERROR_SUCCESS) + { + *SessionHandle = sessionHandle; + *Properties = properties; + + return ERROR_SUCCESS; + } + else if (result == ERROR_ALREADY_EXISTS) + { + // Session already exists, so use that. Get the existing session handle. + + result = ControlTrace(0, DotNetLoggerName.Buffer, properties, EVENT_TRACE_CONTROL_QUERY); + + if (result != ERROR_SUCCESS) + { + PhFree(properties); + return result; + } + + *SessionHandle = properties->Wnode.HistoricalContext; + *Properties = properties; + + return ERROR_SUCCESS; + } + else + { + PhFree(properties); + + return result; + } +} + +ULONG NTAPI DotNetBufferCallback( + _In_ PEVENT_TRACE_LOGFILE Buffer + ) +{ + return TRUE; +} + +VOID NTAPI DotNetEventCallback( + _In_ PEVENT_RECORD EventRecord + ) +{ + PASMPAGE_QUERY_CONTEXT context = EventRecord->UserContext; + PEVENT_HEADER eventHeader = &EventRecord->EventHeader; + PEVENT_DESCRIPTOR eventDescriptor = &eventHeader->EventDescriptor; + + if (UlongToHandle(eventHeader->ProcessId) == context->ProcessId) + { + // .NET 4.0+ + + switch (eventDescriptor->Id) + { + case RuntimeInformationDCStart: + { + PRuntimeInformationRundown data = EventRecord->UserData; + PDNA_NODE node; + PPH_STRING startupFlagsString; + PPH_STRING startupModeString; + + // Check for duplicates. + if (FindClrNode(context, data->ClrInstanceID)) + break; + + node = AddNode(context); + node->Type = DNA_TYPE_CLR; + node->u.Clr.ClrInstanceID = data->ClrInstanceID; + node->u.Clr.DisplayName = PhFormatString(L"CLR v%u.%u.%u.%u", data->VMMajorVersion, data->VMMinorVersion, data->VMBuildNumber, data->VMQfeNumber); + node->StructureText = node->u.Clr.DisplayName->sr; + node->IdText = PhFormatString(L"%u", data->ClrInstanceID); + + startupFlagsString = FlagsToString(data->StartupFlags, StartupFlagsMap, sizeof(StartupFlagsMap)); + startupModeString = FlagsToString(data->StartupMode, StartupModeMap, sizeof(StartupModeMap)); + + if (startupFlagsString->Length != 0 && startupModeString->Length != 0) + { + node->FlagsText = PhConcatStrings(3, startupFlagsString->Buffer, L", ", startupModeString->Buffer); + PhDereferenceObject(startupFlagsString); + PhDereferenceObject(startupModeString); + } + else if (startupFlagsString->Length != 0) + { + node->FlagsText = startupFlagsString; + PhDereferenceObject(startupModeString); + } + else if (startupModeString->Length != 0) + { + node->FlagsText = startupModeString; + PhDereferenceObject(startupFlagsString); + } + + if (data->CommandLine[0]) + node->PathText = PhCreateString(data->CommandLine); + + PhAddItemList(context->NodeRootList, node); + } + break; + case AppDomainDCStart_V1: + { + PAppDomainLoadUnloadRundown_V1 data = EventRecord->UserData; + SIZE_T appDomainNameLength; + USHORT clrInstanceID; + PDNA_NODE parentNode; + PDNA_NODE node; + + appDomainNameLength = PhCountStringZ(data->AppDomainName) * sizeof(WCHAR); + clrInstanceID = *(PUSHORT)((PCHAR)data + FIELD_OFFSET(AppDomainLoadUnloadRundown_V1, AppDomainName) + appDomainNameLength + sizeof(WCHAR) + sizeof(ULONG)); + + // Find the CLR node to add the AppDomain node to. + parentNode = FindClrNode(context, clrInstanceID); + + if (parentNode) + { + // Check for duplicates. + if (FindAppDomainNode(parentNode, data->AppDomainID)) + break; + + node = AddNode(context); + node->Type = DNA_TYPE_APPDOMAIN; + node->u.AppDomain.AppDomainID = data->AppDomainID; + node->u.AppDomain.DisplayName = PhConcatStrings2(L"AppDomain: ", data->AppDomainName); + node->StructureText = node->u.AppDomain.DisplayName->sr; + node->IdText = PhFormatString(L"%I64u", data->AppDomainID); + node->FlagsText = FlagsToString(data->AppDomainFlags, AppDomainFlagsMap, sizeof(AppDomainFlagsMap)); + + PhAddItemList(parentNode->Children, node); + } + } + break; + case AssemblyDCStart_V1: + { + PAssemblyLoadUnloadRundown_V1 data = EventRecord->UserData; + SIZE_T fullyQualifiedAssemblyNameLength; + USHORT clrInstanceID; + PDNA_NODE parentNode; + PDNA_NODE node; + PH_STRINGREF remainingPart; + + fullyQualifiedAssemblyNameLength = PhCountStringZ(data->FullyQualifiedAssemblyName) * sizeof(WCHAR); + clrInstanceID = *(PUSHORT)((PCHAR)data + FIELD_OFFSET(AssemblyLoadUnloadRundown_V1, FullyQualifiedAssemblyName) + fullyQualifiedAssemblyNameLength + sizeof(WCHAR)); + + // Find the AppDomain node to add the Assembly node to. + + parentNode = FindClrNode(context, clrInstanceID); + + if (parentNode) + parentNode = FindAppDomainNode(parentNode, data->AppDomainID); + + if (parentNode) + { + // Check for duplicates. + if (FindAssemblyNode(parentNode, data->AssemblyID)) + break; + + node = AddNode(context); + node->Type = DNA_TYPE_ASSEMBLY; + node->u.Assembly.AssemblyID = data->AssemblyID; + node->u.Assembly.FullyQualifiedAssemblyName = PhCreateStringEx(data->FullyQualifiedAssemblyName, fullyQualifiedAssemblyNameLength); + + // Display only the assembly name, not the whole fully qualified name. + if (!PhSplitStringRefAtChar(&node->u.Assembly.FullyQualifiedAssemblyName->sr, ',', &node->StructureText, &remainingPart)) + node->StructureText = node->u.Assembly.FullyQualifiedAssemblyName->sr; + + node->IdText = PhFormatString(L"%I64u", data->AssemblyID); + node->FlagsText = FlagsToString(data->AssemblyFlags, AssemblyFlagsMap, sizeof(AssemblyFlagsMap)); + + PhAddItemList(parentNode->Children, node); + } + } + break; + case ModuleDCStart_V1: + { + PModuleLoadUnloadRundown_V1 data = EventRecord->UserData; + PWSTR moduleILPath; + SIZE_T moduleILPathLength; + PWSTR moduleNativePath; + SIZE_T moduleNativePathLength; + USHORT clrInstanceID; + PDNA_NODE node; + + moduleILPath = data->ModuleILPath; + moduleILPathLength = PhCountStringZ(moduleILPath) * sizeof(WCHAR); + moduleNativePath = (PWSTR)((PCHAR)moduleILPath + moduleILPathLength + sizeof(WCHAR)); + moduleNativePathLength = PhCountStringZ(moduleNativePath) * sizeof(WCHAR); + clrInstanceID = *(PUSHORT)((PCHAR)moduleNativePath + moduleNativePathLength + sizeof(WCHAR)); + + // Find the Assembly node to set the path on. + + node = FindClrNode(context, clrInstanceID); + + if (node) + node = FindAssemblyNode2(node, data->AssemblyID); + + if (node) + { + PhMoveReference(&node->PathText, PhCreateStringEx(moduleILPath, moduleILPathLength)); + + if (moduleNativePathLength != 0) + PhMoveReference(&node->NativePathText, PhCreateStringEx(moduleNativePath, moduleNativePathLength)); + } + } + break; + case DCStartComplete_V1: + { + if (_InterlockedExchange(&context->TraceHandleActive, 0) == 1) + { + CloseTrace(context->TraceHandle); + } + } + break; + } + + // .NET 2.0 + + if (eventDescriptor->Id == 0) + { + switch (eventDescriptor->Opcode) + { + case CLR_MODULEDCSTART_OPCODE: + { + PModuleLoadUnloadRundown_V1 data = EventRecord->UserData; + PWSTR moduleILPath; + SIZE_T moduleILPathLength; + PWSTR moduleNativePath; + SIZE_T moduleNativePathLength; + PDNA_NODE node; + ULONG_PTR indexOfBackslash; + ULONG_PTR indexOfLastDot; + + moduleILPath = data->ModuleILPath; + moduleILPathLength = PhCountStringZ(moduleILPath) * sizeof(WCHAR); + moduleNativePath = (PWSTR)((PCHAR)moduleILPath + moduleILPathLength + sizeof(WCHAR)); + moduleNativePathLength = PhCountStringZ(moduleNativePath) * sizeof(WCHAR); + + if (context->ClrV2Node && (moduleILPathLength != 0 || moduleNativePathLength != 0)) + { + node = AddNode(context); + node->Type = DNA_TYPE_ASSEMBLY; + node->FlagsText = FlagsToString(data->ModuleFlags, ModuleFlagsMap, sizeof(ModuleFlagsMap)); + node->PathText = PhCreateStringEx(moduleILPath, moduleILPathLength); + + if (moduleNativePathLength != 0) + node->NativePathText = PhCreateStringEx(moduleNativePath, moduleNativePathLength); + + // Use the name between the last backslash and the last dot for the structure column text. + // (E.g. C:\...\AcmeSoft.BigLib.dll -> AcmeSoft.BigLib) + + indexOfBackslash = PhFindLastCharInString(node->PathText, 0, '\\'); + indexOfLastDot = PhFindLastCharInString(node->PathText, 0, '.'); + + if (indexOfBackslash != -1) + { + node->StructureText.Buffer = node->PathText->Buffer + indexOfBackslash + 1; + + if (indexOfLastDot != -1 && indexOfLastDot > indexOfBackslash) + { + node->StructureText.Length = (indexOfLastDot - indexOfBackslash - 1) * sizeof(WCHAR); + } + else + { + node->StructureText.Length = node->PathText->Length - indexOfBackslash * sizeof(WCHAR) - sizeof(WCHAR); + } + } + else + { + node->StructureText = node->PathText->sr; + } + + PhAddItemList(context->ClrV2Node->Children, node); + } + } + break; + case CLR_METHODDC_DCSTARTCOMPLETE_OPCODE: + { + if (_InterlockedExchange(&context->TraceHandleActive, 0) == 1) + { + CloseTrace(context->TraceHandle); + } + } + break; + } + } + } +} + +ULONG ProcessDotNetTrace( + _In_ PASMPAGE_QUERY_CONTEXT Context + ) +{ + ULONG result; + TRACEHANDLE traceHandle; + EVENT_TRACE_LOGFILE logFile; + + memset(&logFile, 0, sizeof(EVENT_TRACE_LOGFILE)); + logFile.LoggerName = DotNetLoggerName.Buffer; + logFile.ProcessTraceMode = PROCESS_TRACE_MODE_REAL_TIME | PROCESS_TRACE_MODE_EVENT_RECORD; + logFile.BufferCallback = DotNetBufferCallback; + logFile.EventRecordCallback = DotNetEventCallback; + logFile.Context = Context; + + traceHandle = OpenTrace(&logFile); + + if (traceHandle == INVALID_PROCESSTRACE_HANDLE) + return GetLastError(); + + Context->TraceHandleActive = 1; + Context->TraceHandle = traceHandle; + result = ProcessTrace(&traceHandle, 1, NULL, NULL); + + if (_InterlockedExchange(&Context->TraceHandleActive, 0) == 1) + { + CloseTrace(traceHandle); + } + + return result; +} + +NTSTATUS UpdateDotNetTraceInfoThreadStart( + _In_ PVOID Parameter + ) +{ + static _EnableTraceEx EnableTraceEx_I = NULL; + PASMPAGE_QUERY_CONTEXT context = Parameter; + TRACEHANDLE sessionHandle; + PEVENT_TRACE_PROPERTIES properties; + PGUID guidToEnable; + + if (!EnableTraceEx_I) + EnableTraceEx_I = PhGetModuleProcAddress(L"advapi32.dll", "EnableTraceEx"); + if (!EnableTraceEx_I) + return ERROR_NOT_SUPPORTED; + + context->TraceResult = StartDotNetTrace(&sessionHandle, &properties); + + if (context->TraceResult != 0) + return context->TraceResult; + + if (!context->TraceClrV2) + guidToEnable = &ClrRundownProviderGuid; + else + guidToEnable = &ClrRuntimeProviderGuid; + + EnableTraceEx_I( + guidToEnable, + NULL, + sessionHandle, + 1, + TRACE_LEVEL_INFORMATION, + CLR_LOADER_KEYWORD | CLR_STARTENUMERATION_KEYWORD, + 0, + 0, + NULL + ); + + context->TraceResult = ProcessDotNetTrace(context); + + ControlTrace(sessionHandle, NULL, properties, EVENT_TRACE_CONTROL_STOP); + PhFree(properties); + + return context->TraceResult; +} + +ULONG UpdateDotNetTraceInfoWithTimeout( + _In_ PASMPAGE_QUERY_CONTEXT Context, + _In_ BOOLEAN ClrV2, + _In_opt_ PLARGE_INTEGER Timeout + ) +{ + HANDLE threadHandle; + BOOLEAN timeout = FALSE; + + // ProcessDotNetTrace is not guaranteed to complete within any period of time, because + // the target process might terminate before it writes the DCStartComplete_V1 event. + // If the timeout is reached, the trace handle is closed, forcing ProcessTrace to stop + // processing. + + Context->TraceClrV2 = ClrV2; + Context->TraceResult = 0; + Context->TraceHandleActive = 0; + Context->TraceHandle = 0; + + threadHandle = PhCreateThread(0, UpdateDotNetTraceInfoThreadStart, Context); + + if (NtWaitForSingleObject(threadHandle, FALSE, Timeout) != STATUS_WAIT_0) + { + // Timeout has expired. Stop the trace processing if it's still active. + // BUG: This assumes that the thread is in ProcessTrace. It might still be + // setting up though! + if (_InterlockedExchange(&Context->TraceHandleActive, 0) == 1) + { + CloseTrace(Context->TraceHandle); + timeout = TRUE; + } + + NtWaitForSingleObject(threadHandle, FALSE, NULL); + } + + NtClose(threadHandle); + + if (timeout) + return ERROR_TIMEOUT; + + return Context->TraceResult; +} + +NTSTATUS DotNetTraceQueryThreadStart( + _In_ PVOID Parameter + ) +{ + LARGE_INTEGER timeout; + PASMPAGE_QUERY_CONTEXT context = Parameter; + BOOLEAN timeoutReached = FALSE; + BOOLEAN nonClrNode = FALSE; + ULONG i; + ULONG result = 0; + + if (context->ClrVersions & PH_CLR_VERSION_1_0) + { + AddFakeClrNode(context, L"CLR v1.0.3705"); // what PE displays + } + + if (context->ClrVersions & PH_CLR_VERSION_1_1) + { + AddFakeClrNode(context, L"CLR v1.1.4322"); + } + + timeout.QuadPart = -10 * PH_TIMEOUT_SEC; + + if (context->ClrVersions & PH_CLR_VERSION_2_0) + { + context->ClrV2Node = AddFakeClrNode(context, L"CLR v2.0.50727"); + result = UpdateDotNetTraceInfoWithTimeout(context, TRUE, &timeout); + + if (result == ERROR_TIMEOUT) + { + timeoutReached = TRUE; + result = ERROR_SUCCESS; + } + } + + if (context->ClrVersions & PH_CLR_VERSION_4_ABOVE) + { + result = UpdateDotNetTraceInfoWithTimeout(context, FALSE, &timeout); + + if (result == ERROR_TIMEOUT) + { + timeoutReached = TRUE; + result = ERROR_SUCCESS; + } + } + // If we reached the timeout, check whether we got any data back. + if (timeoutReached) + { + for (i = 0; i < context->NodeList->Count; i++) + { + PDNA_NODE node = context->NodeList->Items[i]; + + if (node->Type != DNA_TYPE_CLR) + { + nonClrNode = TRUE; + break; + } + } + + if (!nonClrNode) + result = ERROR_TIMEOUT; + } + + // If the process properties window has been closed, bail and cleanup. + // IsWindow should be safe from being called on this thread: + // https://blogs.msdn.microsoft.com/oldnewthing/20070717-00/?p=25983 + if (IsWindow(context->WindowHandle)) + { + PostMessage(context->WindowHandle, UPDATE_MSG, result, (LPARAM)context); + } + else + { + DestroyDotNetTraceQuery(context); + } + + return STATUS_SUCCESS; +} + +VOID CreateDotNetTraceQueryThread( + _In_ HWND WindowHandle, + _In_ ULONG ClrVersions, + _In_ HANDLE ProcessId + ) +{ + HANDLE threadHandle; + PASMPAGE_QUERY_CONTEXT context; + + context = PhAllocate(sizeof(ASMPAGE_QUERY_CONTEXT)); + memset(context, 0, sizeof(ASMPAGE_QUERY_CONTEXT)); + + context->WindowHandle = WindowHandle; + context->ClrVersions = ClrVersions; + context->ProcessId = ProcessId; + context->NodeList = PhCreateList(64); + context->NodeRootList = PhCreateList(2); + + if (threadHandle = PhCreateThread(0, DotNetTraceQueryThreadStart, context)) + { + NtClose(threadHandle); + } + else + { + DestroyDotNetTraceQuery(context); + } +} + +VOID DestroyDotNetTraceQuery( + _In_ PASMPAGE_QUERY_CONTEXT Context + ) +{ + if (Context->NodeList) + { + PhClearReference(&Context->NodeList); + } + + if (Context->NodeRootList) + { + PhClearReference(&Context->NodeRootList); + } + + PhFree(Context); +} + +BOOLEAN IsProcessSuspended( + _In_ HANDLE ProcessId + ) +{ + PVOID processes; + PSYSTEM_PROCESS_INFORMATION process; + + if (NT_SUCCESS(PhEnumProcesses(&processes))) + { + if (process = PhFindProcessInformation(processes, ProcessId)) + return PhGetProcessIsSuspended(process); + + PhFree(processes); + } + + return FALSE; +} + +INT_PTR CALLBACK DotNetAsmPageDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + LPPROPSHEETPAGE propSheetPage; + PPH_PROCESS_PROPPAGECONTEXT propPageContext; + PPH_PROCESS_ITEM processItem; + PASMPAGE_CONTEXT context; + + if (PhPropPageDlgProcHeader(hwndDlg, uMsg, lParam, &propSheetPage, &propPageContext, &processItem)) + { + context = propPageContext->Context; + } + else + { + return FALSE; + } + + switch (uMsg) + { + case WM_INITDIALOG: + { + PPH_STRING settings; + HWND tnHandle; + + context = PhAllocate(sizeof(ASMPAGE_CONTEXT)); + memset(context, 0, sizeof(ASMPAGE_CONTEXT)); + propPageContext->Context = context; + context->WindowHandle = hwndDlg; + context->ProcessItem = processItem; + + context->ClrVersions = 0; + PhGetProcessIsDotNetEx(processItem->ProcessId, NULL, 0, NULL, &context->ClrVersions); + + tnHandle = GetDlgItem(hwndDlg, IDC_LIST); + context->TnHandle = tnHandle; + + TreeNew_SetCallback(tnHandle, DotNetAsmTreeNewCallback, context); + TreeNew_SetExtendedFlags(tnHandle, TN_FLAG_ITEM_DRAG_SELECT, TN_FLAG_ITEM_DRAG_SELECT); + PhSetControlTheme(tnHandle, L"explorer"); + SendMessage(TreeNew_GetTooltips(tnHandle), TTM_SETMAXTIPWIDTH, 0, MAXSHORT); + PhAddTreeNewColumn(tnHandle, DNATNC_STRUCTURE, TRUE, L"Structure", 240, PH_ALIGN_LEFT, -2, 0); + PhAddTreeNewColumn(tnHandle, DNATNC_ID, TRUE, L"ID", 50, PH_ALIGN_RIGHT, 0, DT_RIGHT); + PhAddTreeNewColumn(tnHandle, DNATNC_FLAGS, TRUE, L"Flags", 120, PH_ALIGN_LEFT, 1, 0); + PhAddTreeNewColumn(tnHandle, DNATNC_PATH, TRUE, L"Path", 600, PH_ALIGN_LEFT, 2, 0); // don't use path ellipsis - the user already has the base file name + PhAddTreeNewColumn(tnHandle, DNATNC_NATIVEPATH, TRUE, L"Native image path", 600, PH_ALIGN_LEFT, 3, 0); + + settings = PhGetStringSetting(SETTING_NAME_ASM_TREE_LIST_COLUMNS); + PhCmLoadSettings(tnHandle, &settings->sr); + PhDereferenceObject(settings); + + PhMoveReference(&context->TnErrorMessage, PhCreateString(L"Loading .NET assemblies...")); + TreeNew_SetEmptyText(tnHandle, &context->TnErrorMessage->sr, 0); + + if ( + !IsProcessSuspended(processItem->ProcessId) || + PhShowMessage(hwndDlg, MB_ICONWARNING | MB_YESNO, L".NET assembly enumeration may not work properly because the process is currently suspended. Do you want to continue?") == IDYES + ) + { + CreateDotNetTraceQueryThread( + hwndDlg, + context->ClrVersions, + processItem->ProcessId + ); + } + else + { + PhMoveReference(&context->TnErrorMessage, + PhCreateString(L"Unable to start the event tracing session because the process is suspended.") + ); + TreeNew_SetEmptyText(tnHandle, &context->TnErrorMessage->sr, 0); + InvalidateRect(tnHandle, NULL, FALSE); + } + + EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); + } + break; + case WM_DESTROY: + { + PPH_STRING settings; + ULONG i; + + settings = PhCmSaveSettings(context->TnHandle); + PhSetStringSetting2(SETTING_NAME_ASM_TREE_LIST_COLUMNS, &settings->sr); + PhDereferenceObject(settings); + + if (context->NodeList) + { + for (i = 0; i < context->NodeList->Count; i++) + DestroyNode(context->NodeList->Items[i]); + + PhDereferenceObject(context->NodeList); + } + + if (context->NodeRootList) + PhDereferenceObject(context->NodeRootList); + + PhClearReference(&context->TnErrorMessage); + PhFree(context); + + PhPropPageDlgProcDestroy(hwndDlg); + } + break; + case WM_SHOWWINDOW: + { + PPH_LAYOUT_ITEM dialogItem; + + if (dialogItem = PhBeginPropPageLayout(hwndDlg, propPageContext)) + { + PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_LIST), dialogItem, PH_ANCHOR_ALL); + PhEndPropPageLayout(hwndDlg, propPageContext); + } + } + break; + case WM_COMMAND: + { + switch (LOWORD(wParam)) + { + case ID_COPY: + { + PPH_STRING text; + + text = PhGetTreeNewText(context->TnHandle, 0); + PhSetClipboardString(context->TnHandle, &text->sr); + PhDereferenceObject(text); + } + break; + } + } + break; + case UPDATE_MSG: + { + ULONG result = (ULONG)wParam; + PASMPAGE_QUERY_CONTEXT queryContext = (PASMPAGE_QUERY_CONTEXT)lParam; + + if (result == 0) + { + PhSwapReference(&context->NodeList, queryContext->NodeList); + PhSwapReference(&context->NodeRootList, queryContext->NodeRootList); + + DestroyDotNetTraceQuery(queryContext); + + TreeNew_NodesStructured(context->TnHandle); + } + else + { + PhMoveReference(&context->TnErrorMessage, + PhConcatStrings2(L"Unable to start the event tracing session: ", PhGetStringOrDefault(PhGetWin32Message(result), L"Unknown error")) + ); + TreeNew_SetEmptyText(context->TnHandle, &context->TnErrorMessage->sr, 0); + InvalidateRect(context->TnHandle, NULL, FALSE); + } + } + break; + } + + return FALSE; +} diff --git a/plugins/DotNetTools/clr/dbgappdomain.h b/plugins/DotNetTools/clr/dbgappdomain.h index e29ffdd764a0..86e59ff21d81 100644 --- a/plugins/DotNetTools/clr/dbgappdomain.h +++ b/plugins/DotNetTools/clr/dbgappdomain.h @@ -1,139 +1,139 @@ -/* - * Process Hacker .NET Tools - - * .NET Process IPC definitions - * - * Copyright (C) 2015-2016 dmex - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the current folder for more information. -//----------------------------------------------------------------------------- -// -// dmex: This header has been highly modified. -// Original: https://github.com/dotnet/coreclr/blob/master/src/debug/inc/dbgappdomain.h - -#ifndef _DBG_APPDOMAIN_H_ -#define _DBG_APPDOMAIN_H_ - -#ifndef _WIN64 -#include -#endif -typedef struct _AppDomainInfo -{ - ULONG Id; // unique identifier - INT NameLengthInBytes; - PWSTR AppDomainName; - PVOID AppDomains; -} AppDomainInfo; -#ifndef _WIN64 -#include -#endif - -#include -typedef struct _AppDomainInfo_Wow64 -{ - ULONG Id; // unique identifier - INT NameLengthInBytes; - ULONG AppDomainName; - ULONG AppDomains; -} AppDomainInfo_Wow64; -#include - -// AppDomain publishing server support: -// Information about all appdomains in the process will be maintained -// in the shared memory block for use by the debugger, etc. -#ifndef _WIN64 -#include -#endif -typedef struct _AppDomainEnumerationIPCBlock -{ - HANDLE Mutex; // lock for serialization while manipulating AppDomain list. - - INT TotalSlots; // Number of slots in AppDomainListElement array - INT NumOfUsedSlots; - INT LastFreedSlot; - INT SizeInBytes; // Size of AppDomainInfo in bytes - - INT ProcessNameLengthInBytes; // We can use psapi!GetModuleFileNameEx to get the module name. - PVOID ProcessName; // This provides an alternative. - - PVOID ListOfAppDomains; - BOOL LockInvalid; -} AppDomainEnumerationIPCBlock; -#ifndef _WIN64 -#include -#endif - -#include -typedef struct _AppDomainEnumerationIPCBlock_Wow64 -{ - ULONG Mutex; // lock for serialization while manipulating AppDomain list. - - INT TotalSlots; // Number of slots in AppDomainListElement array - INT NumOfUsedSlots; - INT LastFreedSlot; - INT SizeInBytes; // Size of AppDomainInfo in bytes - - INT ProcessNameLengthInBytes; // We can use psapi!GetModuleFileNameEx to get the module name. - ULONG ProcessName; // This provides an alternative. - - ULONG ListOfAppDomains; - BOOL LockInvalid; -} AppDomainEnumerationIPCBlock_Wow64; -#include - - -// Enforce the AppDomain IPC block binary layout. -C_ASSERT(FIELD_OFFSET(AppDomainInfo_Wow64, Id) == 0x0); -C_ASSERT(FIELD_OFFSET(AppDomainInfo_Wow64, NameLengthInBytes) == 0x4); -C_ASSERT(FIELD_OFFSET(AppDomainInfo_Wow64, AppDomainName) == 0x8); -C_ASSERT(FIELD_OFFSET(AppDomainInfo_Wow64, AppDomains) == 0xC); - -#if defined(_WIN64) -C_ASSERT(FIELD_OFFSET(AppDomainInfo, Id) == 0x0); -C_ASSERT(FIELD_OFFSET(AppDomainInfo, NameLengthInBytes) == 0x4); -C_ASSERT(FIELD_OFFSET(AppDomainInfo, AppDomainName) == 0x8); -C_ASSERT(FIELD_OFFSET(AppDomainInfo, AppDomains) == 0x10); -#endif - -// Enforce the AppDomain IPC block binary layout. -C_ASSERT(FIELD_OFFSET(AppDomainEnumerationIPCBlock_Wow64, Mutex) == 0x0); -C_ASSERT(FIELD_OFFSET(AppDomainEnumerationIPCBlock_Wow64, TotalSlots) == 0x4); -C_ASSERT(FIELD_OFFSET(AppDomainEnumerationIPCBlock_Wow64, NumOfUsedSlots) == 0x8); -C_ASSERT(FIELD_OFFSET(AppDomainEnumerationIPCBlock_Wow64, LastFreedSlot) == 0xC); -C_ASSERT(FIELD_OFFSET(AppDomainEnumerationIPCBlock_Wow64, SizeInBytes) == 0x10); -C_ASSERT(FIELD_OFFSET(AppDomainEnumerationIPCBlock_Wow64, ProcessNameLengthInBytes) == 0x14); -C_ASSERT(FIELD_OFFSET(AppDomainEnumerationIPCBlock_Wow64, ProcessName) == 0x18); -C_ASSERT(FIELD_OFFSET(AppDomainEnumerationIPCBlock_Wow64, ListOfAppDomains) == 0x1C); -C_ASSERT(FIELD_OFFSET(AppDomainEnumerationIPCBlock_Wow64, LockInvalid) == 0x20); - -#if defined(_WIN64) -C_ASSERT(FIELD_OFFSET(AppDomainEnumerationIPCBlock, Mutex) == 0x0); -C_ASSERT(FIELD_OFFSET(AppDomainEnumerationIPCBlock, TotalSlots) == 0x8); -C_ASSERT(FIELD_OFFSET(AppDomainEnumerationIPCBlock, NumOfUsedSlots) == 0xC); -C_ASSERT(FIELD_OFFSET(AppDomainEnumerationIPCBlock, LastFreedSlot) == 0x10); -C_ASSERT(FIELD_OFFSET(AppDomainEnumerationIPCBlock, SizeInBytes) == 0x14); -C_ASSERT(FIELD_OFFSET(AppDomainEnumerationIPCBlock, ProcessNameLengthInBytes) == 0x18); -// TODO: Why does Visual Studio have issues with these entries... -//C_ASSERT(FIELD_OFFSET(AppDomainEnumerationIPCBlock, ProcessName) == 0x20); -//C_ASSERT(FIELD_OFFSET(AppDomainEnumerationIPCBlock, ListOfAppDomains) == 0x28); -//C_ASSERT(FIELD_OFFSET(AppDomainEnumerationIPCBlock, LockInvalid) == 0x30); -#endif - +/* + * Process Hacker .NET Tools - + * .NET Process IPC definitions + * + * Copyright (C) 2015-2016 dmex + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the current folder for more information. +//----------------------------------------------------------------------------- +// +// dmex: This header has been highly modified. +// Original: https://github.com/dotnet/coreclr/blob/master/src/debug/inc/dbgappdomain.h + +#ifndef _DBG_APPDOMAIN_H_ +#define _DBG_APPDOMAIN_H_ + +#ifndef _WIN64 +#include +#endif +typedef struct _AppDomainInfo +{ + ULONG Id; // unique identifier + INT NameLengthInBytes; + PWSTR AppDomainName; + PVOID AppDomains; +} AppDomainInfo; +#ifndef _WIN64 +#include +#endif + +#include +typedef struct _AppDomainInfo_Wow64 +{ + ULONG Id; // unique identifier + INT NameLengthInBytes; + ULONG AppDomainName; + ULONG AppDomains; +} AppDomainInfo_Wow64; +#include + +// AppDomain publishing server support: +// Information about all appdomains in the process will be maintained +// in the shared memory block for use by the debugger, etc. +#ifndef _WIN64 +#include +#endif +typedef struct _AppDomainEnumerationIPCBlock +{ + HANDLE Mutex; // lock for serialization while manipulating AppDomain list. + + INT TotalSlots; // Number of slots in AppDomainListElement array + INT NumOfUsedSlots; + INT LastFreedSlot; + INT SizeInBytes; // Size of AppDomainInfo in bytes + + INT ProcessNameLengthInBytes; // We can use psapi!GetModuleFileNameEx to get the module name. + PVOID ProcessName; // This provides an alternative. + + PVOID ListOfAppDomains; + BOOL LockInvalid; +} AppDomainEnumerationIPCBlock; +#ifndef _WIN64 +#include +#endif + +#include +typedef struct _AppDomainEnumerationIPCBlock_Wow64 +{ + ULONG Mutex; // lock for serialization while manipulating AppDomain list. + + INT TotalSlots; // Number of slots in AppDomainListElement array + INT NumOfUsedSlots; + INT LastFreedSlot; + INT SizeInBytes; // Size of AppDomainInfo in bytes + + INT ProcessNameLengthInBytes; // We can use psapi!GetModuleFileNameEx to get the module name. + ULONG ProcessName; // This provides an alternative. + + ULONG ListOfAppDomains; + BOOL LockInvalid; +} AppDomainEnumerationIPCBlock_Wow64; +#include + + +// Enforce the AppDomain IPC block binary layout. +C_ASSERT(FIELD_OFFSET(AppDomainInfo_Wow64, Id) == 0x0); +C_ASSERT(FIELD_OFFSET(AppDomainInfo_Wow64, NameLengthInBytes) == 0x4); +C_ASSERT(FIELD_OFFSET(AppDomainInfo_Wow64, AppDomainName) == 0x8); +C_ASSERT(FIELD_OFFSET(AppDomainInfo_Wow64, AppDomains) == 0xC); + +#if defined(_WIN64) +C_ASSERT(FIELD_OFFSET(AppDomainInfo, Id) == 0x0); +C_ASSERT(FIELD_OFFSET(AppDomainInfo, NameLengthInBytes) == 0x4); +C_ASSERT(FIELD_OFFSET(AppDomainInfo, AppDomainName) == 0x8); +C_ASSERT(FIELD_OFFSET(AppDomainInfo, AppDomains) == 0x10); +#endif + +// Enforce the AppDomain IPC block binary layout. +C_ASSERT(FIELD_OFFSET(AppDomainEnumerationIPCBlock_Wow64, Mutex) == 0x0); +C_ASSERT(FIELD_OFFSET(AppDomainEnumerationIPCBlock_Wow64, TotalSlots) == 0x4); +C_ASSERT(FIELD_OFFSET(AppDomainEnumerationIPCBlock_Wow64, NumOfUsedSlots) == 0x8); +C_ASSERT(FIELD_OFFSET(AppDomainEnumerationIPCBlock_Wow64, LastFreedSlot) == 0xC); +C_ASSERT(FIELD_OFFSET(AppDomainEnumerationIPCBlock_Wow64, SizeInBytes) == 0x10); +C_ASSERT(FIELD_OFFSET(AppDomainEnumerationIPCBlock_Wow64, ProcessNameLengthInBytes) == 0x14); +C_ASSERT(FIELD_OFFSET(AppDomainEnumerationIPCBlock_Wow64, ProcessName) == 0x18); +C_ASSERT(FIELD_OFFSET(AppDomainEnumerationIPCBlock_Wow64, ListOfAppDomains) == 0x1C); +C_ASSERT(FIELD_OFFSET(AppDomainEnumerationIPCBlock_Wow64, LockInvalid) == 0x20); + +#if defined(_WIN64) +C_ASSERT(FIELD_OFFSET(AppDomainEnumerationIPCBlock, Mutex) == 0x0); +C_ASSERT(FIELD_OFFSET(AppDomainEnumerationIPCBlock, TotalSlots) == 0x8); +C_ASSERT(FIELD_OFFSET(AppDomainEnumerationIPCBlock, NumOfUsedSlots) == 0xC); +C_ASSERT(FIELD_OFFSET(AppDomainEnumerationIPCBlock, LastFreedSlot) == 0x10); +C_ASSERT(FIELD_OFFSET(AppDomainEnumerationIPCBlock, SizeInBytes) == 0x14); +C_ASSERT(FIELD_OFFSET(AppDomainEnumerationIPCBlock, ProcessNameLengthInBytes) == 0x18); +// TODO: Why does Visual Studio have issues with these entries... +//C_ASSERT(FIELD_OFFSET(AppDomainEnumerationIPCBlock, ProcessName) == 0x20); +//C_ASSERT(FIELD_OFFSET(AppDomainEnumerationIPCBlock, ListOfAppDomains) == 0x28); +//C_ASSERT(FIELD_OFFSET(AppDomainEnumerationIPCBlock, LockInvalid) == 0x30); +#endif + #endif _DBG_APPDOMAIN_H_ \ No newline at end of file diff --git a/plugins/DotNetTools/clr/ipcenums.h b/plugins/DotNetTools/clr/ipcenums.h index 4f8431abbda4..1d9434111933 100644 --- a/plugins/DotNetTools/clr/ipcenums.h +++ b/plugins/DotNetTools/clr/ipcenums.h @@ -1,77 +1,77 @@ -/* - * Process Hacker .NET Tools - - * .NET Process IPC definitions - * - * Copyright (C) 2015-2016 dmex - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the current folder for more information. -//----------------------------------------------------------------------------- -// IPCEnums.h -// -// Define various enums used by IPCMan. -//----------------------------------------------------------------------------- -// -// dmex: This header has been highly modified. -// Original: https://github.com/dotnet/coreclr/blob/master/src/ipcman/ipcenums.h - -#ifndef _IPC_ENUMS_H_ -#define _IPC_ENUMS_H_ - -//----------------------------------------------------------------------------- -// Each IPC client for an IPC block has one entry. -//----------------------------------------------------------------------------- -typedef enum _EIPCClient -{ - eIPC_PerfCounters = 0, - - // MAX used for arrays, insert above this. - eIPC_MAX -} EIPCClient; - -//----------------------------------------------------------------------------- -// Each IPC client for a LegacyPrivate block (debugging, perf counters, etc) has one entry. -//----------------------------------------------------------------------------- -typedef enum _ELegacyPrivateIPCClient -{ - eLegacyPrivateIPC_PerfCounters = 0, - eLegacyPrivateIPC_Obsolete_Debugger = 1, - eLegacyPrivateIPC_AppDomain = 2, - eLegacyPrivateIPC_Obsolete_Service = 3, - eLegacyPrivateIPC_Obsolete_ClassDump = 4, - eLegacyPrivateIPC_Obsolete_MiniDump = 5, - eLegacyPrivateIPC_InstancePath = 6, - - // MAX used for arrays, insert above this. - eLegacyPrivateIPC_MAX -} ELegacyPrivateIPCClient; - -//----------------------------------------------------------------------------- -// Each IPC client for a LegacyPublic block has one entry. -//----------------------------------------------------------------------------- -typedef enum _ELegacyPublicIPCClient -{ - eLegacyPublicIPC_PerfCounters = 0, - - // MAX used for arrays, insert above this. - eLegacyPublicIPC_MAX -} ELegacyPublicIPCClient; - +/* + * Process Hacker .NET Tools - + * .NET Process IPC definitions + * + * Copyright (C) 2015-2016 dmex + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the current folder for more information. +//----------------------------------------------------------------------------- +// IPCEnums.h +// +// Define various enums used by IPCMan. +//----------------------------------------------------------------------------- +// +// dmex: This header has been highly modified. +// Original: https://github.com/dotnet/coreclr/blob/master/src/ipcman/ipcenums.h + +#ifndef _IPC_ENUMS_H_ +#define _IPC_ENUMS_H_ + +//----------------------------------------------------------------------------- +// Each IPC client for an IPC block has one entry. +//----------------------------------------------------------------------------- +typedef enum _EIPCClient +{ + eIPC_PerfCounters = 0, + + // MAX used for arrays, insert above this. + eIPC_MAX +} EIPCClient; + +//----------------------------------------------------------------------------- +// Each IPC client for a LegacyPrivate block (debugging, perf counters, etc) has one entry. +//----------------------------------------------------------------------------- +typedef enum _ELegacyPrivateIPCClient +{ + eLegacyPrivateIPC_PerfCounters = 0, + eLegacyPrivateIPC_Obsolete_Debugger = 1, + eLegacyPrivateIPC_AppDomain = 2, + eLegacyPrivateIPC_Obsolete_Service = 3, + eLegacyPrivateIPC_Obsolete_ClassDump = 4, + eLegacyPrivateIPC_Obsolete_MiniDump = 5, + eLegacyPrivateIPC_InstancePath = 6, + + // MAX used for arrays, insert above this. + eLegacyPrivateIPC_MAX +} ELegacyPrivateIPCClient; + +//----------------------------------------------------------------------------- +// Each IPC client for a LegacyPublic block has one entry. +//----------------------------------------------------------------------------- +typedef enum _ELegacyPublicIPCClient +{ + eLegacyPublicIPC_PerfCounters = 0, + + // MAX used for arrays, insert above this. + eLegacyPublicIPC_MAX +} ELegacyPublicIPCClient; + #endif _IPC_ENUMS_H_ \ No newline at end of file diff --git a/plugins/DotNetTools/clr/ipcheader.h b/plugins/DotNetTools/clr/ipcheader.h index ba8318907f61..f565dd9a5154 100644 --- a/plugins/DotNetTools/clr/ipcheader.h +++ b/plugins/DotNetTools/clr/ipcheader.h @@ -1,545 +1,545 @@ -/* - * Process Hacker .NET Tools - - * .NET Process IPC definitions - * - * Copyright (C) 2015-2016 dmex - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the current folder for more information. -//----------------------------------------------------------------------------- -// IPCHeader.h -// -// Define the LegacyPrivate header format for IPC memory mapped files. -//----------------------------------------------------------------------------- -// -// dmex: This header has been highly modified. -// Original: https://github.com/dotnet/coreclr/blob/master/src/ipcman/ipcheader.h - -#ifndef _IPC_HEADER_H_ -#define _IPC_HEADER_H_ - -#include "perfcounterdefs.h" -#include "ipcenums.h" - -// Current version of the IPC Block -const USHORT VER_IPC_BLOCK = 4; -// Legacy version of the IPC Block -const USHORT VER_LEGACYPRIVATE_IPC_BLOCK = 2; -const USHORT VER_LEGACYPUBLIC_IPC_BLOCK = 3; - -//----------------------------------------------------------------------------- -// Entry in the IPC Directory. Ensure binary compatibility across versions -// if we add (or remove) entries. If we remove an block, the entry should -// be EMPTY_ENTRY_OFFSET -//----------------------------------------------------------------------------- - -const ULONG EMPTY_ENTRY_OFFSET = 0xFFFFFFFF; -const ULONG EMPTY_ENTRY_SIZE = 0; - -typedef struct IPCEntry -{ - ULONG Offset; // offset of the IPC Block from the end of the Full IPC Header - ULONG Size; // size (in bytes) of the block -} IPCEntry; - -// Newer versions of the CLR use Flags field -const USHORT IPC_FLAG_USES_FLAGS = 0x1; -const USHORT IPC_FLAG_INITIALIZED = 0x2; -const USHORT IPC_FLAG_X86 = 0x4; - -// In hindsight, we should have made the offsets be absolute, but we made them -// relative to the end of the FullIPCHeader. -// The problem is that as future versions added new Entries to the directory, -// the header size grew. -// Thus we make IPCEntry::Offset is relative to IPC_ENTRY_OFFSET_BASE, which -// corresponds to sizeof(PrivateIPCHeader) for an v1.0 /v1.1 build. -const ULONG IPC_ENTRY_OFFSET_BASE_X86 = 0x14; -const ULONG IPC_ENTRY_OFFSET_BASE_X64 = 0x0; - - -/****************************************************************************** - * The CLR opens memory mapped files to expose perfcounter values and other - * information to other processes. Historically there have been three memory - * mapped files: the BlockTable, the LegacyPrivateBlock, and the - * LegacyPublicBlock. - * - * BlockTable - The block table was designed to work with multiple runtimes - * running side by side in the same process (SxS in-proc). We have defined - * semantics using interlocked operations that allow a runtime to allocate - * a block from the block table in a thread-safe manner. - * - * LegacyPrivateBlock - The legacy private block was used by older versions - * of the runtime to expose various information to the debugger. The - * legacy private block is not compatible with in-proc SxS, and thus it - * must be removed in the near future. Currently it is being used to expose - * information about AppDomains to the debugger. We will need to keep the - * code that knows how to read the legacy private block as long as we - * continue to support .NET 3.5 SP1. - * - * LegacyPublicBlock - The legacy public block was used by older versions - * of the runtime to expose perfcounter values. The legacy public block is - * not compatible with in-proc SxS, and thus it has been removed. We will - * need to keep the code that knows how to read the legacy public block as - * long as we continue to support .NET 3.5 SP1. - ******************************************************************************/ - -/**************************************** BLOCK TABLE ****************************************/ - -#define IPC_BLOCK_TABLE_SIZE 65536 -#define IPC_BLOCK_SIZE 2048 -#define IPC_NUM_BLOCKS_IN_TABLE 32 - -C_ASSERT(IPC_BLOCK_TABLE_SIZE == IPC_NUM_BLOCKS_IN_TABLE * IPC_BLOCK_SIZE); - -typedef struct _IPCHeader -{ - // Chunk header - volatile LONG Counter; // *** Volatile *** value of 0 is special; means that this block has never been touched before by a writer - ULONG RuntimeId; // value of 0 is special; means that chunk is currently free (runtime ids are always greater than 0) - ULONG Reserved1; - ULONG Reserved2; - - // Standard header - USHORT Version; // version of the IPC Block - USHORT Flags; // flags field - ULONG blockSize; // Size of the entire shared memory block - USHORT BuildYear; // stamp for year built - USHORT BuildNumber; // stamp for Month/Day built - ULONG NumEntries; // Number of entries in the table - - // Directory - IPCEntry EntryTable[eIPC_MAX]; // entry describing each client's block -} IPCHeader; - -#define SXSPUBLIC_IPC_SIZE_NO_PADDING (sizeof(IPCHeader) + sizeof(PerfCounterIPCControlBlock)) -#define SXSPUBLIC_WOW64_IPC_SIZE_NO_PADDING (sizeof(IPCHeader) + sizeof(PerfCounterIPCControlBlock_Wow64)) - -#define SXSPUBLIC_IPC_PAD_SIZE (IPC_BLOCK_SIZE - SXSPUBLIC_IPC_SIZE_NO_PADDING) -#define SXSPUBLIC_WOW64_IPC_PAD_SIZE (IPC_BLOCK_SIZE - SXSPUBLIC_WOW64_IPC_SIZE_NO_PADDING) - -#ifndef _WIN64 -#include -#endif -typedef struct _IPCControlBlock -{ - // Header - IPCHeader Header; - - // Client blocks - PerfCounterIPCControlBlock PerfIpcBlock; - - // Padding - BYTE Padding[SXSPUBLIC_IPC_PAD_SIZE]; -} IPCControlBlock; -#ifndef _WIN64 -#include -#endif - -#include -typedef struct _IPCControlBlock_Wow64 -{ - // Header - IPCHeader Header; - - // Client blocks - PerfCounterIPCControlBlock_Wow64 PerfIpcBlock; - - // Padding - BYTE Padding[SXSPUBLIC_WOW64_IPC_PAD_SIZE]; -} IPCControlBlock_Wow64; -#include - -C_ASSERT(sizeof(IPCControlBlock) == IPC_BLOCK_SIZE); -C_ASSERT(sizeof(IPCControlBlock_Wow64) == IPC_BLOCK_SIZE); - -#ifndef _WIN64 -#include -#endif -typedef struct IPCControlBlockTable -{ - IPCControlBlock Blocks[IPC_NUM_BLOCKS_IN_TABLE]; -} IPCControlBlockTable; -#ifndef _WIN64 -#include -#endif - -#include -typedef struct IPCControlBlockTable_Wow64 -{ - IPCControlBlock_Wow64 Blocks[IPC_NUM_BLOCKS_IN_TABLE]; -} IPCControlBlockTable_Wow64; -#include - -C_ASSERT(sizeof(IPCControlBlockTable) == IPC_BLOCK_TABLE_SIZE); -C_ASSERT(sizeof(IPCControlBlockTable_Wow64) == IPC_BLOCK_TABLE_SIZE); - - -#ifndef _WIN64 -#include -#endif -typedef struct LegacyPrivateIPCHeader -{ - USHORT Version; // version of the IPC Block - USHORT Flags; // flags field - ULONG BlockSize; // Size of the entire shared memory block - HINSTANCE hInstance; // Instance of module that created this header - USHORT BuildYear; // stamp for year built - USHORT BuildNumber; // stamp for Month/Day built - ULONG NumEntries; // Number of entries in the table -} LegacyPrivateIPCHeader; -#ifndef _WIN64 -#include -#endif - -#include -typedef struct LegacyPrivateIPCHeader_Wow64 -{ - USHORT Version; // version of the IPC Block - USHORT Flags; // flags field - ULONG BlockSize; // Size of the entire shared memory block - ULONG hInstance; // Instance of module that created this header - USHORT BuildYear; // stamp for year built - USHORT BuildNumber; // stamp for Month/Day built - ULONG NumEntries; // Number of entries in the table -} LegacyPrivateIPCHeader_Wow64; -#include - -#ifndef _WIN64 -#include -#endif -typedef struct FullIPCHeaderLegacyPrivate -{ - // Header - LegacyPrivateIPCHeader Header; - - // Directory - IPCEntry EntryTable[eLegacyPrivateIPC_MAX]; // entry describing each client's block -} FullIPCHeaderLegacyPrivate; -#ifndef _WIN64 -#include -#endif - -#include -typedef struct FullIPCHeaderLegacyPrivate_Wow64 -{ - // Header - LegacyPrivateIPCHeader_Wow64 Header; - - // Directory - IPCEntry EntryTable[eLegacyPrivateIPC_MAX]; // entry describing each client's block -} FullIPCHeaderLegacyPrivate_Wow64; -#include - -#ifndef _WIN64 -#include -#endif -typedef struct FullIPCHeaderLegacyPublic -{ - // Header - LegacyPrivateIPCHeader Header; - - // Directory - IPCEntry EntryTable[eLegacyPublicIPC_MAX]; // entry describing each client's block -} FullIPCHeaderLegacyPublic; -#ifndef _WIN64 -#include -#endif - -#include -typedef struct FullIPCHeaderLegacyPublic_Wow64 -{ - // Header - LegacyPrivateIPCHeader_Wow64 Header; - - // Directory - IPCEntry EntryTable[eLegacyPublicIPC_MAX]; // entry describing each client's block -} FullIPCHeaderLegacyPublic_Wow64; -#include - - -//----------------------------------------------------------------------------- -// LegacyPrivate (per process) IPC Block for COM+ apps -//----------------------------------------------------------------------------- -#ifndef _WIN64 -#include -#endif -typedef struct _LegacyPrivateIPCControlBlock -{ - FullIPCHeaderLegacyPrivate FullIPCHeader; - - // Client blocks - PerfCounterIPCControlBlock PerfIpcBlock; // no longer used but kept for compat - AppDomainEnumerationIPCBlock AppDomainBlock; - WCHAR InstancePath[MAX_PATH]; -} LegacyPrivateIPCControlBlock; -#ifndef _WIN64 -#include -#endif - -#include -typedef struct _LegacyPrivateIPCControlBlock_Wow64 -{ - FullIPCHeaderLegacyPrivate_Wow64 FullIPCHeader; - - // Client blocks - PerfCounterIPCControlBlock_Wow64 PerfIpcBlock; // no longer used but kept for compat - AppDomainEnumerationIPCBlock_Wow64 AppDomainBlock; - WCHAR InstancePath[MAX_PATH]; -} LegacyPrivateIPCControlBlock_Wow64; -#include - - -//----------------------------------------------------------------------------- -// LegacyPublic (per process) IPC Block for CLR apps -//----------------------------------------------------------------------------- -#ifndef _WIN64 -#include -#endif -typedef struct LegacyPublicIPCControlBlock -{ - FullIPCHeaderLegacyPublic FullIPCHeaderLegacyPublic; - - // Client blocks - PerfCounterIPCControlBlock PerfIpcBlock; -} LegacyPublicIPCControlBlock; -#ifndef _WIN64 -#include -#endif - -#include -typedef struct _LegacyPublicIPCControlBlock_Wow64 -{ - FullIPCHeaderLegacyPublic_Wow64 FullIPCHeaderLegacyPublic; - - // Client blocks - PerfCounterIPCControlBlock_Wow64 PerfIpcBlock; -} LegacyPublicIPCControlBlock_Wow64; -#include - - -//class IPCHeaderLockHolder -//{ -// LONG Counter; -// BOOL HaveLock; -// IPCHeader & Header; -// -// public: -// -// IPCHeaderLockHolder(IPCHeader & header) : HaveLock(FALSE), Header(header) {} -// -// BOOL TryGetLock() -// { -// _ASSERTE(!HaveLock); -// LONG oldCounter = Header.Counter; -// if ((oldCounter & 1) != 0) -// return FALSE; -// Counter = oldCounter + 1; -// if (InterlockedCompareExchange((LONG *)(&(Header.Counter)), Counter, oldCounter) != oldCounter) -// return FALSE; -// HaveLock = TRUE; -// -// return TRUE; -// } -// -// BOOL TryGetLock(ULONG numRetries) -// { -// ULONG dwSwitchCount = 0; -// -// for (;;) -// { -// if (TryGetLock()) -// return TRUE; -// -// if (numRetries == 0) -// return FALSE; -// -// --numRetries; -// __SwitchToThread(0, ++dwSwitchCount); -// } -// } -// -// void FreeLock() -// { -// _ASSERTE(HaveLock); -// _ASSERTE(Header.Counter == Counter); -// ++Counter; -// Counter = (Counter == 0) ? 2 : Counter; -// Header.Counter = Counter; -// HaveLock = FALSE; -// } -// -// ~IPCHeaderLockHolder() -// { -// if (HaveLock) -// FreeLock(); -// } -//}; -// -//class IPCHeaderReadHelper -//{ -// IPCHeader CachedHeader; -// IPCHeader * pUnreliableHeader; -// BOOL IsOpen; -// -// public: -// -// IPCHeaderReadHelper() : pUnreliableHeader(NULL), IsOpen(FALSE) {} -// -// BOOL TryOpenHeader(IPCHeader * header) -// { -// _ASSERTE(!IsOpen); -// -// pUnreliableHeader = header; -// -// // Read the counter and the runtime ID from the header -// CachedHeader.Counter = pUnreliableHeader->Counter; -// if ((CachedHeader.Counter & 1) != 0) -// return FALSE; -// CachedHeader.RuntimeId = pUnreliableHeader->RuntimeId; -// -// // If runtime ID is 0, then this block is not allocated by -// // a runtime, and thus there is no further work to do -// if (CachedHeader.RuntimeId == 0) -// { -// IsOpen = TRUE; -// return TRUE; -// } -// -// // Read the rest of the values from the header -// CachedHeader.Reserved1 = pUnreliableHeader->Reserved1; -// CachedHeader.Reserved2 = pUnreliableHeader->Reserved2; -// CachedHeader.Version = pUnreliableHeader->Version; -// CachedHeader.Flags = pUnreliableHeader->Flags; -// CachedHeader.blockSize = pUnreliableHeader->blockSize; -// CachedHeader.BuildYear = pUnreliableHeader->BuildYear; -// CachedHeader.BuildNumber = pUnreliableHeader->BuildNumber; -// CachedHeader.numEntries = pUnreliableHeader->numEntries; -// -// // Verify that the header did not change during the read -// LONG counter = pUnreliableHeader->Counter; -// if (CachedHeader.Counter != counter) -// return FALSE; -// -// // Since we know we got a clean read of numEntries, we -// // should be able to assert this with confidence -// if (CachedHeader.numEntries == 0) -// { -// _ASSERTE(!"numEntries from IPCBlock is zero"); -// return FALSE; -// } -// else if (CachedHeader.numEntries > eIPC_MAX) -// { -// _ASSERTE(!"numEntries from IPCBlock is too big"); -// return FALSE; -// } -// -// if (CachedHeader.blockSize == 0) -// { -// _ASSERTE(!"blockSize from IPCBlock is zero"); -// return FALSE; -// } -// else if (CachedHeader.blockSize > IPC_BLOCK_SIZE) -// { -// _ASSERTE(!"blockSize from IPCBlock is too big"); -// return FALSE; -// } -// -// // Copy the table -// for (ULONG i = 0; i < CachedHeader.numEntries; ++i) -// { -// CachedHeader.EntryTable[i].Offset = pUnreliableHeader->EntryTable[i].Offset; -// CachedHeader.EntryTable[i].Size = pUnreliableHeader->EntryTable[i].Size; -// if (i == eIPC_PerfCounters) -// { -// if(!((SIZE_T)CachedHeader.EntryTable[i].Offset < IPC_BLOCK_SIZE) && ((SIZE_T)CachedHeader.EntryTable[i].Offset + CachedHeader.EntryTable[i].Size <= IPC_BLOCK_SIZE)) -// { -// _ASSERTE(!"PerfCounter section offset + size is too large"); -// return FALSE; -// } -// } -// } -// -// // If eIPC_MAX > numEntries, then mark the left over -// // slots in EntryTable as "empty". -// for (ULONG i = CachedHeader.numEntries; i < eIPC_MAX; ++i) -// { -// CachedHeader.EntryTable[i].Offset = EMPTY_ENTRY_OFFSET; -// CachedHeader.EntryTable[i].Size = EMPTY_ENTRY_SIZE; -// } -// -// // Verify again that the header did not change during the read -// counter = pUnreliableHeader->Counter; -// if (CachedHeader.Counter != counter) -// return FALSE; -// -// IsOpen = TRUE; -// return TRUE; -// } -// -// -// BOOL HeaderHasChanged() -// { -// _ASSERTE(IsOpen); -// LONG counter = pUnreliableHeader->Counter; -// return (CachedHeader.Counter != counter) ? TRUE : FALSE; -// } -// -// BOOL IsSentinal() -// { -// _ASSERTE(IsOpen); -// return (CachedHeader.Counter == 0); -// } -// -// -// BOOL UseWow64Structs() -// { -// _ASSERTE(IsOpen); -//#if !defined(_TARGET_X86_) -// return ((CachedHeader.Flags & IPC_FLAG_X86) != 0) ? TRUE : FALSE; -//#else -// return FALSE; -//#endif -// } -// -// void * GetUnreliableSection(EIPCClient eClient) -// { -// if (!IsOpen) -// { -// _ASSERTE(!"IPCHeaderReadHelper is not open"); -// return NULL; -// } -// -// if (eClient < 0 || eClient >= eIPC_MAX) -// { -// _ASSERTE(!"eClient is out of bounds"); -// return NULL; -// } -// -// if (CachedHeader.EntryTable[eClient].Offset == EMPTY_ENTRY_OFFSET) -// { -// _ASSERTE(!"Section is empty"); -// return NULL; -// } -// -// return (BYTE*)pUnreliableHeader + (SIZE_T)CachedHeader.EntryTable[eClient].Offset; -// } -//}; - +/* + * Process Hacker .NET Tools - + * .NET Process IPC definitions + * + * Copyright (C) 2015-2016 dmex + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the current folder for more information. +//----------------------------------------------------------------------------- +// IPCHeader.h +// +// Define the LegacyPrivate header format for IPC memory mapped files. +//----------------------------------------------------------------------------- +// +// dmex: This header has been highly modified. +// Original: https://github.com/dotnet/coreclr/blob/master/src/ipcman/ipcheader.h + +#ifndef _IPC_HEADER_H_ +#define _IPC_HEADER_H_ + +#include "perfcounterdefs.h" +#include "ipcenums.h" + +// Current version of the IPC Block +const USHORT VER_IPC_BLOCK = 4; +// Legacy version of the IPC Block +const USHORT VER_LEGACYPRIVATE_IPC_BLOCK = 2; +const USHORT VER_LEGACYPUBLIC_IPC_BLOCK = 3; + +//----------------------------------------------------------------------------- +// Entry in the IPC Directory. Ensure binary compatibility across versions +// if we add (or remove) entries. If we remove an block, the entry should +// be EMPTY_ENTRY_OFFSET +//----------------------------------------------------------------------------- + +const ULONG EMPTY_ENTRY_OFFSET = 0xFFFFFFFF; +const ULONG EMPTY_ENTRY_SIZE = 0; + +typedef struct IPCEntry +{ + ULONG Offset; // offset of the IPC Block from the end of the Full IPC Header + ULONG Size; // size (in bytes) of the block +} IPCEntry; + +// Newer versions of the CLR use Flags field +const USHORT IPC_FLAG_USES_FLAGS = 0x1; +const USHORT IPC_FLAG_INITIALIZED = 0x2; +const USHORT IPC_FLAG_X86 = 0x4; + +// In hindsight, we should have made the offsets be absolute, but we made them +// relative to the end of the FullIPCHeader. +// The problem is that as future versions added new Entries to the directory, +// the header size grew. +// Thus we make IPCEntry::Offset is relative to IPC_ENTRY_OFFSET_BASE, which +// corresponds to sizeof(PrivateIPCHeader) for an v1.0 /v1.1 build. +const ULONG IPC_ENTRY_OFFSET_BASE_X86 = 0x14; +const ULONG IPC_ENTRY_OFFSET_BASE_X64 = 0x0; + + +/****************************************************************************** + * The CLR opens memory mapped files to expose perfcounter values and other + * information to other processes. Historically there have been three memory + * mapped files: the BlockTable, the LegacyPrivateBlock, and the + * LegacyPublicBlock. + * + * BlockTable - The block table was designed to work with multiple runtimes + * running side by side in the same process (SxS in-proc). We have defined + * semantics using interlocked operations that allow a runtime to allocate + * a block from the block table in a thread-safe manner. + * + * LegacyPrivateBlock - The legacy private block was used by older versions + * of the runtime to expose various information to the debugger. The + * legacy private block is not compatible with in-proc SxS, and thus it + * must be removed in the near future. Currently it is being used to expose + * information about AppDomains to the debugger. We will need to keep the + * code that knows how to read the legacy private block as long as we + * continue to support .NET 3.5 SP1. + * + * LegacyPublicBlock - The legacy public block was used by older versions + * of the runtime to expose perfcounter values. The legacy public block is + * not compatible with in-proc SxS, and thus it has been removed. We will + * need to keep the code that knows how to read the legacy public block as + * long as we continue to support .NET 3.5 SP1. + ******************************************************************************/ + +/**************************************** BLOCK TABLE ****************************************/ + +#define IPC_BLOCK_TABLE_SIZE 65536 +#define IPC_BLOCK_SIZE 2048 +#define IPC_NUM_BLOCKS_IN_TABLE 32 + +C_ASSERT(IPC_BLOCK_TABLE_SIZE == IPC_NUM_BLOCKS_IN_TABLE * IPC_BLOCK_SIZE); + +typedef struct _IPCHeader +{ + // Chunk header + volatile LONG Counter; // *** Volatile *** value of 0 is special; means that this block has never been touched before by a writer + ULONG RuntimeId; // value of 0 is special; means that chunk is currently free (runtime ids are always greater than 0) + ULONG Reserved1; + ULONG Reserved2; + + // Standard header + USHORT Version; // version of the IPC Block + USHORT Flags; // flags field + ULONG blockSize; // Size of the entire shared memory block + USHORT BuildYear; // stamp for year built + USHORT BuildNumber; // stamp for Month/Day built + ULONG NumEntries; // Number of entries in the table + + // Directory + IPCEntry EntryTable[eIPC_MAX]; // entry describing each client's block +} IPCHeader; + +#define SXSPUBLIC_IPC_SIZE_NO_PADDING (sizeof(IPCHeader) + sizeof(PerfCounterIPCControlBlock)) +#define SXSPUBLIC_WOW64_IPC_SIZE_NO_PADDING (sizeof(IPCHeader) + sizeof(PerfCounterIPCControlBlock_Wow64)) + +#define SXSPUBLIC_IPC_PAD_SIZE (IPC_BLOCK_SIZE - SXSPUBLIC_IPC_SIZE_NO_PADDING) +#define SXSPUBLIC_WOW64_IPC_PAD_SIZE (IPC_BLOCK_SIZE - SXSPUBLIC_WOW64_IPC_SIZE_NO_PADDING) + +#ifndef _WIN64 +#include +#endif +typedef struct _IPCControlBlock +{ + // Header + IPCHeader Header; + + // Client blocks + PerfCounterIPCControlBlock PerfIpcBlock; + + // Padding + BYTE Padding[SXSPUBLIC_IPC_PAD_SIZE]; +} IPCControlBlock; +#ifndef _WIN64 +#include +#endif + +#include +typedef struct _IPCControlBlock_Wow64 +{ + // Header + IPCHeader Header; + + // Client blocks + PerfCounterIPCControlBlock_Wow64 PerfIpcBlock; + + // Padding + BYTE Padding[SXSPUBLIC_WOW64_IPC_PAD_SIZE]; +} IPCControlBlock_Wow64; +#include + +C_ASSERT(sizeof(IPCControlBlock) == IPC_BLOCK_SIZE); +C_ASSERT(sizeof(IPCControlBlock_Wow64) == IPC_BLOCK_SIZE); + +#ifndef _WIN64 +#include +#endif +typedef struct IPCControlBlockTable +{ + IPCControlBlock Blocks[IPC_NUM_BLOCKS_IN_TABLE]; +} IPCControlBlockTable; +#ifndef _WIN64 +#include +#endif + +#include +typedef struct IPCControlBlockTable_Wow64 +{ + IPCControlBlock_Wow64 Blocks[IPC_NUM_BLOCKS_IN_TABLE]; +} IPCControlBlockTable_Wow64; +#include + +C_ASSERT(sizeof(IPCControlBlockTable) == IPC_BLOCK_TABLE_SIZE); +C_ASSERT(sizeof(IPCControlBlockTable_Wow64) == IPC_BLOCK_TABLE_SIZE); + + +#ifndef _WIN64 +#include +#endif +typedef struct LegacyPrivateIPCHeader +{ + USHORT Version; // version of the IPC Block + USHORT Flags; // flags field + ULONG BlockSize; // Size of the entire shared memory block + HINSTANCE hInstance; // Instance of module that created this header + USHORT BuildYear; // stamp for year built + USHORT BuildNumber; // stamp for Month/Day built + ULONG NumEntries; // Number of entries in the table +} LegacyPrivateIPCHeader; +#ifndef _WIN64 +#include +#endif + +#include +typedef struct LegacyPrivateIPCHeader_Wow64 +{ + USHORT Version; // version of the IPC Block + USHORT Flags; // flags field + ULONG BlockSize; // Size of the entire shared memory block + ULONG hInstance; // Instance of module that created this header + USHORT BuildYear; // stamp for year built + USHORT BuildNumber; // stamp for Month/Day built + ULONG NumEntries; // Number of entries in the table +} LegacyPrivateIPCHeader_Wow64; +#include + +#ifndef _WIN64 +#include +#endif +typedef struct FullIPCHeaderLegacyPrivate +{ + // Header + LegacyPrivateIPCHeader Header; + + // Directory + IPCEntry EntryTable[eLegacyPrivateIPC_MAX]; // entry describing each client's block +} FullIPCHeaderLegacyPrivate; +#ifndef _WIN64 +#include +#endif + +#include +typedef struct FullIPCHeaderLegacyPrivate_Wow64 +{ + // Header + LegacyPrivateIPCHeader_Wow64 Header; + + // Directory + IPCEntry EntryTable[eLegacyPrivateIPC_MAX]; // entry describing each client's block +} FullIPCHeaderLegacyPrivate_Wow64; +#include + +#ifndef _WIN64 +#include +#endif +typedef struct FullIPCHeaderLegacyPublic +{ + // Header + LegacyPrivateIPCHeader Header; + + // Directory + IPCEntry EntryTable[eLegacyPublicIPC_MAX]; // entry describing each client's block +} FullIPCHeaderLegacyPublic; +#ifndef _WIN64 +#include +#endif + +#include +typedef struct FullIPCHeaderLegacyPublic_Wow64 +{ + // Header + LegacyPrivateIPCHeader_Wow64 Header; + + // Directory + IPCEntry EntryTable[eLegacyPublicIPC_MAX]; // entry describing each client's block +} FullIPCHeaderLegacyPublic_Wow64; +#include + + +//----------------------------------------------------------------------------- +// LegacyPrivate (per process) IPC Block for COM+ apps +//----------------------------------------------------------------------------- +#ifndef _WIN64 +#include +#endif +typedef struct _LegacyPrivateIPCControlBlock +{ + FullIPCHeaderLegacyPrivate FullIPCHeader; + + // Client blocks + PerfCounterIPCControlBlock PerfIpcBlock; // no longer used but kept for compat + AppDomainEnumerationIPCBlock AppDomainBlock; + WCHAR InstancePath[MAX_PATH]; +} LegacyPrivateIPCControlBlock; +#ifndef _WIN64 +#include +#endif + +#include +typedef struct _LegacyPrivateIPCControlBlock_Wow64 +{ + FullIPCHeaderLegacyPrivate_Wow64 FullIPCHeader; + + // Client blocks + PerfCounterIPCControlBlock_Wow64 PerfIpcBlock; // no longer used but kept for compat + AppDomainEnumerationIPCBlock_Wow64 AppDomainBlock; + WCHAR InstancePath[MAX_PATH]; +} LegacyPrivateIPCControlBlock_Wow64; +#include + + +//----------------------------------------------------------------------------- +// LegacyPublic (per process) IPC Block for CLR apps +//----------------------------------------------------------------------------- +#ifndef _WIN64 +#include +#endif +typedef struct LegacyPublicIPCControlBlock +{ + FullIPCHeaderLegacyPublic FullIPCHeaderLegacyPublic; + + // Client blocks + PerfCounterIPCControlBlock PerfIpcBlock; +} LegacyPublicIPCControlBlock; +#ifndef _WIN64 +#include +#endif + +#include +typedef struct _LegacyPublicIPCControlBlock_Wow64 +{ + FullIPCHeaderLegacyPublic_Wow64 FullIPCHeaderLegacyPublic; + + // Client blocks + PerfCounterIPCControlBlock_Wow64 PerfIpcBlock; +} LegacyPublicIPCControlBlock_Wow64; +#include + + +//class IPCHeaderLockHolder +//{ +// LONG Counter; +// BOOL HaveLock; +// IPCHeader & Header; +// +// public: +// +// IPCHeaderLockHolder(IPCHeader & header) : HaveLock(FALSE), Header(header) {} +// +// BOOL TryGetLock() +// { +// _ASSERTE(!HaveLock); +// LONG oldCounter = Header.Counter; +// if ((oldCounter & 1) != 0) +// return FALSE; +// Counter = oldCounter + 1; +// if (InterlockedCompareExchange((LONG *)(&(Header.Counter)), Counter, oldCounter) != oldCounter) +// return FALSE; +// HaveLock = TRUE; +// +// return TRUE; +// } +// +// BOOL TryGetLock(ULONG numRetries) +// { +// ULONG dwSwitchCount = 0; +// +// for (;;) +// { +// if (TryGetLock()) +// return TRUE; +// +// if (numRetries == 0) +// return FALSE; +// +// --numRetries; +// __SwitchToThread(0, ++dwSwitchCount); +// } +// } +// +// void FreeLock() +// { +// _ASSERTE(HaveLock); +// _ASSERTE(Header.Counter == Counter); +// ++Counter; +// Counter = (Counter == 0) ? 2 : Counter; +// Header.Counter = Counter; +// HaveLock = FALSE; +// } +// +// ~IPCHeaderLockHolder() +// { +// if (HaveLock) +// FreeLock(); +// } +//}; +// +//class IPCHeaderReadHelper +//{ +// IPCHeader CachedHeader; +// IPCHeader * pUnreliableHeader; +// BOOL IsOpen; +// +// public: +// +// IPCHeaderReadHelper() : pUnreliableHeader(NULL), IsOpen(FALSE) {} +// +// BOOL TryOpenHeader(IPCHeader * header) +// { +// _ASSERTE(!IsOpen); +// +// pUnreliableHeader = header; +// +// // Read the counter and the runtime ID from the header +// CachedHeader.Counter = pUnreliableHeader->Counter; +// if ((CachedHeader.Counter & 1) != 0) +// return FALSE; +// CachedHeader.RuntimeId = pUnreliableHeader->RuntimeId; +// +// // If runtime ID is 0, then this block is not allocated by +// // a runtime, and thus there is no further work to do +// if (CachedHeader.RuntimeId == 0) +// { +// IsOpen = TRUE; +// return TRUE; +// } +// +// // Read the rest of the values from the header +// CachedHeader.Reserved1 = pUnreliableHeader->Reserved1; +// CachedHeader.Reserved2 = pUnreliableHeader->Reserved2; +// CachedHeader.Version = pUnreliableHeader->Version; +// CachedHeader.Flags = pUnreliableHeader->Flags; +// CachedHeader.blockSize = pUnreliableHeader->blockSize; +// CachedHeader.BuildYear = pUnreliableHeader->BuildYear; +// CachedHeader.BuildNumber = pUnreliableHeader->BuildNumber; +// CachedHeader.numEntries = pUnreliableHeader->numEntries; +// +// // Verify that the header did not change during the read +// LONG counter = pUnreliableHeader->Counter; +// if (CachedHeader.Counter != counter) +// return FALSE; +// +// // Since we know we got a clean read of numEntries, we +// // should be able to assert this with confidence +// if (CachedHeader.numEntries == 0) +// { +// _ASSERTE(!"numEntries from IPCBlock is zero"); +// return FALSE; +// } +// else if (CachedHeader.numEntries > eIPC_MAX) +// { +// _ASSERTE(!"numEntries from IPCBlock is too big"); +// return FALSE; +// } +// +// if (CachedHeader.blockSize == 0) +// { +// _ASSERTE(!"blockSize from IPCBlock is zero"); +// return FALSE; +// } +// else if (CachedHeader.blockSize > IPC_BLOCK_SIZE) +// { +// _ASSERTE(!"blockSize from IPCBlock is too big"); +// return FALSE; +// } +// +// // Copy the table +// for (ULONG i = 0; i < CachedHeader.numEntries; ++i) +// { +// CachedHeader.EntryTable[i].Offset = pUnreliableHeader->EntryTable[i].Offset; +// CachedHeader.EntryTable[i].Size = pUnreliableHeader->EntryTable[i].Size; +// if (i == eIPC_PerfCounters) +// { +// if(!((SIZE_T)CachedHeader.EntryTable[i].Offset < IPC_BLOCK_SIZE) && ((SIZE_T)CachedHeader.EntryTable[i].Offset + CachedHeader.EntryTable[i].Size <= IPC_BLOCK_SIZE)) +// { +// _ASSERTE(!"PerfCounter section offset + size is too large"); +// return FALSE; +// } +// } +// } +// +// // If eIPC_MAX > numEntries, then mark the left over +// // slots in EntryTable as "empty". +// for (ULONG i = CachedHeader.numEntries; i < eIPC_MAX; ++i) +// { +// CachedHeader.EntryTable[i].Offset = EMPTY_ENTRY_OFFSET; +// CachedHeader.EntryTable[i].Size = EMPTY_ENTRY_SIZE; +// } +// +// // Verify again that the header did not change during the read +// counter = pUnreliableHeader->Counter; +// if (CachedHeader.Counter != counter) +// return FALSE; +// +// IsOpen = TRUE; +// return TRUE; +// } +// +// +// BOOL HeaderHasChanged() +// { +// _ASSERTE(IsOpen); +// LONG counter = pUnreliableHeader->Counter; +// return (CachedHeader.Counter != counter) ? TRUE : FALSE; +// } +// +// BOOL IsSentinal() +// { +// _ASSERTE(IsOpen); +// return (CachedHeader.Counter == 0); +// } +// +// +// BOOL UseWow64Structs() +// { +// _ASSERTE(IsOpen); +//#if !defined(_TARGET_X86_) +// return ((CachedHeader.Flags & IPC_FLAG_X86) != 0) ? TRUE : FALSE; +//#else +// return FALSE; +//#endif +// } +// +// void * GetUnreliableSection(EIPCClient eClient) +// { +// if (!IsOpen) +// { +// _ASSERTE(!"IPCHeaderReadHelper is not open"); +// return NULL; +// } +// +// if (eClient < 0 || eClient >= eIPC_MAX) +// { +// _ASSERTE(!"eClient is out of bounds"); +// return NULL; +// } +// +// if (CachedHeader.EntryTable[eClient].Offset == EMPTY_ENTRY_OFFSET) +// { +// _ASSERTE(!"Section is empty"); +// return NULL; +// } +// +// return (BYTE*)pUnreliableHeader + (SIZE_T)CachedHeader.EntryTable[eClient].Offset; +// } +//}; + #endif // _IPC_HEADER_H_ \ No newline at end of file diff --git a/plugins/DotNetTools/clr/ipcshared.h b/plugins/DotNetTools/clr/ipcshared.h index 25d67e851bf9..2650f1377479 100644 --- a/plugins/DotNetTools/clr/ipcshared.h +++ b/plugins/DotNetTools/clr/ipcshared.h @@ -1,57 +1,57 @@ -/* - * Process Hacker .NET Tools - - * .NET Process IPC definitions - * - * Copyright (C) 2015-2016 dmex - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the current folder for more information. -//----------------------------------------------------------------------------- -// IPCShared.h -// -// Shared LegacyPrivate utility functions for IPC operations. -//----------------------------------------------------------------------------- -// -// dmex: This header has been highly modified. -// Original: https://github.com/dotnet/coreclr/blob/master/src/ipcman/ipcshared.h - -#ifndef _IPC_SHARED_H_ -#define _IPC_SHARED_H_ - -// This is the name of the file backed session's name on the LS (debuggee) -// Name of the LegacyPrivate (per-process) block. %lu resolved to a PID -#define CorLegacyPrivateIPCBlock L"Cor_Private_IPCBlock_%lu" -#define CorLegacyPrivateIPCBlockTempV4 L"Cor_Private_IPCBlock_v4_%lu" -#define CorLegacyPublicIPCBlock L"Cor_Public_IPCBlock_%lu" -#define CorSxSPublicIPCBlock L"Cor_SxSPublic_IPCBlock_%lu" -#define CorSxSBoundaryDescriptor L"Cor_CLR_IPCBlock_%lu" -#define CorSxSWriterPrivateNamespacePrefix L"Cor_CLR_WRITER" -#define CorSxSReaderPrivateNamespacePrefix L"Cor_CLR_READER" -#define CorSxSVistaPublicIPCBlock L"Cor_SxSPublic_IPCBlock" - -#define CorLegacyPrivateIPCBlock_RS L"CLR_PRIVATE_RS_IPCBlock_%lu" -#define CorLegacyPrivateIPCBlock_RSTempV4 L"CLR_PRIVATE_RS_IPCBlock_v4_%lu" -#define CorLegacyPublicIPCBlock_RS L"CLR_PUBLIC_IPCBlock_%lu" -#define CorSxSPublicIPCBlock_RS L"CLR_SXSPUBLIC_IPCBlock_%lu" - -#define CorSxSPublicInstanceName L"%s_p%lu_r%lu" -#define CorSxSPublicInstanceNameWhidbey L"%s_p%lu" - +/* + * Process Hacker .NET Tools - + * .NET Process IPC definitions + * + * Copyright (C) 2015-2016 dmex + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the current folder for more information. +//----------------------------------------------------------------------------- +// IPCShared.h +// +// Shared LegacyPrivate utility functions for IPC operations. +//----------------------------------------------------------------------------- +// +// dmex: This header has been highly modified. +// Original: https://github.com/dotnet/coreclr/blob/master/src/ipcman/ipcshared.h + +#ifndef _IPC_SHARED_H_ +#define _IPC_SHARED_H_ + +// This is the name of the file backed session's name on the LS (debuggee) +// Name of the LegacyPrivate (per-process) block. %lu resolved to a PID +#define CorLegacyPrivateIPCBlock L"Cor_Private_IPCBlock_%lu" +#define CorLegacyPrivateIPCBlockTempV4 L"Cor_Private_IPCBlock_v4_%lu" +#define CorLegacyPublicIPCBlock L"Cor_Public_IPCBlock_%lu" +#define CorSxSPublicIPCBlock L"Cor_SxSPublic_IPCBlock_%lu" +#define CorSxSBoundaryDescriptor L"Cor_CLR_IPCBlock_%lu" +#define CorSxSWriterPrivateNamespacePrefix L"Cor_CLR_WRITER" +#define CorSxSReaderPrivateNamespacePrefix L"Cor_CLR_READER" +#define CorSxSVistaPublicIPCBlock L"Cor_SxSPublic_IPCBlock" + +#define CorLegacyPrivateIPCBlock_RS L"CLR_PRIVATE_RS_IPCBlock_%lu" +#define CorLegacyPrivateIPCBlock_RSTempV4 L"CLR_PRIVATE_RS_IPCBlock_v4_%lu" +#define CorLegacyPublicIPCBlock_RS L"CLR_PUBLIC_IPCBlock_%lu" +#define CorSxSPublicIPCBlock_RS L"CLR_SXSPUBLIC_IPCBlock_%lu" + +#define CorSxSPublicInstanceName L"%s_p%lu_r%lu" +#define CorSxSPublicInstanceNameWhidbey L"%s_p%lu" + #endif _IPC_SHARED_H_ \ No newline at end of file diff --git a/plugins/DotNetTools/clr/perfcounterdefs.h b/plugins/DotNetTools/clr/perfcounterdefs.h index bba5e237bfd2..baf11e2f4dcd 100644 --- a/plugins/DotNetTools/clr/perfcounterdefs.h +++ b/plugins/DotNetTools/clr/perfcounterdefs.h @@ -1,333 +1,333 @@ -/* - * Process Hacker .NET Tools - - * .NET Process IPC definitions - * - * Copyright (C) 2015-2016 dmex - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the current folder for more information. -//----------------------------------------------------------------------------- -// PerfCounterDefs.h -// -// Internal Interface for CLR to use Performance counters. -//----------------------------------------------------------------------------- -// -// dmex: This header has been highly modified. -// Original: https://github.com/dotnet/coreclr/blob/master/src/inc/perfcounterdefs.h - -#ifndef _PERF_COUNTERS_H_ -#define _PERF_COUNTERS_H_ - -//----------------------------------------------------------------------------- -// Name of global IPC block -#define SHARED_PERF_IPC_NAME "SharedPerfIPCBlock" - -//----------------------------------------------------------------------------- -// Attributes for the IPC block -#define PERF_ATTR_ON 0x0001 // Are we even updating any counters? -#define PERF_ATTR_GLOBAL 0x0002 // Is this a global or private block? - -//............................................................................. -// Tri Counter. Support for the common trio of counters (Total, Current, and Instantaneous). -typedef struct _TRICOUNT -{ - ULONG Current; // Current, has +, - - ULONG Total; // Total, has only + -} TRICOUNT; - -//............................................................................. -// Interlocked Tri Counter. Support for the common trio of counters (Total, Current, and Instantaneous). -typedef struct _TRICOUNT_IL -{ - ULONG Current; // Current, has +, - - ULONG Total; // Total, has only + -} TRICOUNT_IL; - - -//............................................................................. -// Dual Counter. Support for the (Total and Instantaneous (rate)). Helpful in cases -// where the current value is always same as the total value. ie. the counter is never -// decremented. -//............................................................................. -typedef struct _DUALCOUNT -{ - ULONG Total; -} DUALCOUNT; - -//----------------------------------------------------------------------------- -// Format for the Perf Counter IPC Block -// IPC block is broken up into sections. This marks it easier to marshall -// into different perfmon objects -// -//............................................................................. -// Naming convention (by prefix): -// c - Raw count of something. -// cb- count of bytes -// time - time value. -// depth - stack depth -//----------------------------------------------------------------------------- - -#define MAX_TRACKED_GENS 3 // number of generations we track - - -#ifndef _WIN64 -#include -#endif -typedef struct _Perf_GC -{ - size_t cGenCollections[MAX_TRACKED_GENS]; // count of collects per gen - size_t cbPromotedMem[MAX_TRACKED_GENS - 1]; // count of promoted memory - size_t cbPromotedFinalizationMem; // count of memory promoted due to finalization - size_t cProcessID; // process ID - size_t cGenHeapSize[MAX_TRACKED_GENS]; // size of heaps per gen - size_t cTotalCommittedBytes; // total number of committed bytes. - size_t cTotalReservedBytes; // bytes reserved via VirtualAlloc - size_t cLrgObjSize; // size of Large Object Heap - size_t cSurviveFinalize; // count of instances surviving from finalizing - size_t cHandles; // count of GC handles - size_t cbAlloc; // bytes allocated - size_t cbLargeAlloc; // bytes allocated for Large Objects - size_t cInducedGCs; // number of explicit GCs - ULONG timeInGC; // Time in GC - ULONG timeInGCBase; // must follow time in GC counter - size_t cPinnedObj; // # of Pinned Objects - size_t cSinkBlocks; // # of sink blocks -} Perf_GC; -#ifndef _WIN64 -#include -#endif - -// Perf_GC_Wow64 mimics in a 64 bit process, the layout of Perf_GC in a 32 bit process -// It does this by replacing all size_t by ULONG -#include -typedef struct _Perf_GC_Wow64 -{ - ULONG cGenCollections[MAX_TRACKED_GENS]; // count of collects per gen - ULONG cbPromotedMem[MAX_TRACKED_GENS - 1]; // count of promoted memory - ULONG cbPromotedFinalizationMem; // count of memory promoted due to finalization - ULONG cProcessID; // process ID - ULONG cGenHeapSize[MAX_TRACKED_GENS]; // size of heaps per gen - ULONG cTotalCommittedBytes; // total number of committed bytes. - ULONG cTotalReservedBytes; // bytes reserved via VirtualAlloc - ULONG cLrgObjSize; // size of Large Object Heap - ULONG cSurviveFinalize; // count of instances surviving from finalizing - ULONG cHandles; // count of GC handles - ULONG cbAlloc; // bytes allocated - ULONG cbLargeAlloc; // bytes allocated for Large Objects - ULONG cInducedGCs; // number of explicit GCs - ULONG timeInGC; // Time in GC - ULONG timeInGCBase; // must follow time in GC counter - ULONG cPinnedObj; // # of Pinned Objects - ULONG cSinkBlocks; // # of sink blocks -} Perf_GC_Wow64; -#include - - - -#ifndef _WIN64 -#include -#endif -typedef struct Perf_Loading -{ - TRICOUNT cClassesLoaded; - TRICOUNT_IL cAppDomains; // Current # of AppDomains - TRICOUNT cAssemblies; // Current # of Assemblies - UNALIGNED LONGLONG timeLoading; // % time loading - ULONG cAsmSearchLen; // Avg search length for assemblies - DUALCOUNT cLoadFailures; // Classes Failed to load - size_t cbLoaderHeapSize; // Total size of heap used by the loader - DUALCOUNT cAppDomainsUnloaded; // Rate at which app domains are unloaded -} Perf_Loading; -#ifndef _WIN64 -#include -#endif - -#include -typedef struct Perf_Loading_Wow64 -{ - TRICOUNT cClassesLoaded; - TRICOUNT_IL cAppDomains; // Current # of AppDomains - TRICOUNT cAssemblies; // Current # of Assemblies - UNALIGNED LONGLONG timeLoading; // % time loading - ULONG cAsmSearchLen; // Avg search length for assemblies - DUALCOUNT cLoadFailures; // Classes Failed to load - ULONG cbLoaderHeapSize; // Total size of heap used by the loader - DUALCOUNT cAppDomainsUnloaded; // Rate at which app domains are unloaded -} Perf_Loading_Wow64; -#include - - -#ifndef _WIN64 -#include -#endif -typedef struct Perf_Jit -{ - ULONG cMethodsJitted; // number of methods jitted - TRICOUNT cbILJitted; // IL jitted stats - //DUALCOUNT cbPitched; // Total bytes pitched - ULONG cJitFailures; // # of standard Jit failures - ULONG timeInJit; // Time in JIT since last sample - ULONG timeInJitBase; // Time in JIT base counter -} Perf_Jit; -#ifndef _WIN64 -#include -#endif - -#ifndef _WIN64 -#include -#endif -typedef struct Perf_Excep -{ - DUALCOUNT cThrown; // Number of Exceptions thrown - ULONG cFiltersExecuted; // Number of Filters executed - ULONG cFinallysExecuted; // Number of Finallys executed - ULONG cThrowToCatchStackDepth; // Delta from throw to catch site on stack -} Perf_Excep; -#ifndef _WIN64 -#include -#endif - -#ifndef _WIN64 -#include -#endif -typedef struct Perf_Interop -{ - ULONG cCCW; // Number of CCWs - ULONG cStubs; // Number of stubs - ULONG cMarshalling; // # of time marshalling args and return values. - ULONG cTLBImports; // Number of tlbs we import - ULONG cTLBExports; // Number of tlbs we export -} Perf_Interop; -#ifndef _WIN64 -#include -#endif - -#ifndef _WIN64 -#include -#endif -typedef struct Perf_LocksAndThreads -{ - // Locks - DUALCOUNT cContention; // # of times in AwareLock::EnterEpilogue() - TRICOUNT cQueueLength; // Lenght of queue - // Threads - ULONG cCurrentThreadsLogical; // Number (created - destroyed) of logical threads - ULONG cCurrentThreadsPhysical; // Number (created - destroyed) of OS threads - TRICOUNT cRecognizedThreads; // # of Threads execute in runtime's control -} Perf_LocksAndThreads; -#ifndef _WIN64 -#include -#endif - - -// IMPORTANT!!!!!!!: The first two fields in the struct have to be together -// and be the first two fields in the struct. The managed code in ChannelServices.cs -// depends on this. -#ifndef _WIN64 -#include -#endif -typedef struct Perf_Contexts -{ - // Contexts & Remoting - DUALCOUNT cRemoteCalls; // # of remote calls - ULONG cChannels; // Number of current channels - ULONG cProxies; // Number of context proxies. - ULONG cClasses; // # of Context-bound classes - ULONG cObjAlloc; // # of context bound objects allocated - ULONG cContexts; // The current number of contexts. -} Perf_Contexts; -#ifndef _WIN64 -#include -#endif - - -#ifndef _WIN64 -#include -#endif -typedef struct Perf_Security -{ - ULONG cTotalRTChecks; // Total runtime checks - UNALIGNED LONGLONG timeAuthorize; // % time authenticating - ULONG cLinkChecks; // link time checks - ULONG timeRTchecks; // % time in Runtime checks - ULONG timeRTchecksBase; // % time in Runtime checks base counter - ULONG stackWalkDepth; // depth of stack for security checks -} Perf_Security; -#ifndef _WIN64 -#include -#endif - -#include -typedef struct Perf_Security_Wow64 -{ - ULONG cTotalRTChecks; // Total runtime checks - UNALIGNED LONGLONG timeAuthorize; // % time authenticating - ULONG cLinkChecks; // link time checks - ULONG timeRTchecks; // % time in Runtime checks - ULONG timeRTchecksBase; // % time in Runtime checks base counter - ULONG stackWalkDepth; // depth of stack for security checks -} Perf_Security_Wow64; -#include - - -#ifndef _WIN64 -#include -#endif -typedef struct _PerfCounterIPCControlBlock -{ - // Versioning info - USHORT Bytes; // size of this entire block - USHORT Attributes; // attributes for this block - - // Counter Sections - Perf_GC GC; - Perf_Contexts Context; - Perf_Interop Interop; - Perf_Loading Loading; - Perf_Excep Excep; - Perf_LocksAndThreads LocksAndThreads; - Perf_Jit Jit; - Perf_Security Security; -} PerfCounterIPCControlBlock; -#ifndef _WIN64 -#include -#endif - -#include -typedef struct _PerfCounterIPCControlBlock_Wow64 -{ - // Versioning info - USHORT Bytes; // size of this entire block - USHORT Attributes; // attributes for this block - - // Counter Sections - Perf_GC_Wow64 GC; - Perf_Contexts Context; - Perf_Interop Interop; - Perf_Loading_Wow64 Loading; - Perf_Excep Excep; - Perf_LocksAndThreads LocksAndThreads; - Perf_Jit Jit; - Perf_Security_Wow64 Security; -} PerfCounterIPCControlBlock_Wow64; -#include - - +/* + * Process Hacker .NET Tools - + * .NET Process IPC definitions + * + * Copyright (C) 2015-2016 dmex + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the current folder for more information. +//----------------------------------------------------------------------------- +// PerfCounterDefs.h +// +// Internal Interface for CLR to use Performance counters. +//----------------------------------------------------------------------------- +// +// dmex: This header has been highly modified. +// Original: https://github.com/dotnet/coreclr/blob/master/src/inc/perfcounterdefs.h + +#ifndef _PERF_COUNTERS_H_ +#define _PERF_COUNTERS_H_ + +//----------------------------------------------------------------------------- +// Name of global IPC block +#define SHARED_PERF_IPC_NAME "SharedPerfIPCBlock" + +//----------------------------------------------------------------------------- +// Attributes for the IPC block +#define PERF_ATTR_ON 0x0001 // Are we even updating any counters? +#define PERF_ATTR_GLOBAL 0x0002 // Is this a global or private block? + +//............................................................................. +// Tri Counter. Support for the common trio of counters (Total, Current, and Instantaneous). +typedef struct _TRICOUNT +{ + ULONG Current; // Current, has +, - + ULONG Total; // Total, has only + +} TRICOUNT; + +//............................................................................. +// Interlocked Tri Counter. Support for the common trio of counters (Total, Current, and Instantaneous). +typedef struct _TRICOUNT_IL +{ + ULONG Current; // Current, has +, - + ULONG Total; // Total, has only + +} TRICOUNT_IL; + + +//............................................................................. +// Dual Counter. Support for the (Total and Instantaneous (rate)). Helpful in cases +// where the current value is always same as the total value. ie. the counter is never +// decremented. +//............................................................................. +typedef struct _DUALCOUNT +{ + ULONG Total; +} DUALCOUNT; + +//----------------------------------------------------------------------------- +// Format for the Perf Counter IPC Block +// IPC block is broken up into sections. This marks it easier to marshall +// into different perfmon objects +// +//............................................................................. +// Naming convention (by prefix): +// c - Raw count of something. +// cb- count of bytes +// time - time value. +// depth - stack depth +//----------------------------------------------------------------------------- + +#define MAX_TRACKED_GENS 3 // number of generations we track + + +#ifndef _WIN64 +#include +#endif +typedef struct _Perf_GC +{ + size_t cGenCollections[MAX_TRACKED_GENS]; // count of collects per gen + size_t cbPromotedMem[MAX_TRACKED_GENS - 1]; // count of promoted memory + size_t cbPromotedFinalizationMem; // count of memory promoted due to finalization + size_t cProcessID; // process ID + size_t cGenHeapSize[MAX_TRACKED_GENS]; // size of heaps per gen + size_t cTotalCommittedBytes; // total number of committed bytes. + size_t cTotalReservedBytes; // bytes reserved via VirtualAlloc + size_t cLrgObjSize; // size of Large Object Heap + size_t cSurviveFinalize; // count of instances surviving from finalizing + size_t cHandles; // count of GC handles + size_t cbAlloc; // bytes allocated + size_t cbLargeAlloc; // bytes allocated for Large Objects + size_t cInducedGCs; // number of explicit GCs + ULONG timeInGC; // Time in GC + ULONG timeInGCBase; // must follow time in GC counter + size_t cPinnedObj; // # of Pinned Objects + size_t cSinkBlocks; // # of sink blocks +} Perf_GC; +#ifndef _WIN64 +#include +#endif + +// Perf_GC_Wow64 mimics in a 64 bit process, the layout of Perf_GC in a 32 bit process +// It does this by replacing all size_t by ULONG +#include +typedef struct _Perf_GC_Wow64 +{ + ULONG cGenCollections[MAX_TRACKED_GENS]; // count of collects per gen + ULONG cbPromotedMem[MAX_TRACKED_GENS - 1]; // count of promoted memory + ULONG cbPromotedFinalizationMem; // count of memory promoted due to finalization + ULONG cProcessID; // process ID + ULONG cGenHeapSize[MAX_TRACKED_GENS]; // size of heaps per gen + ULONG cTotalCommittedBytes; // total number of committed bytes. + ULONG cTotalReservedBytes; // bytes reserved via VirtualAlloc + ULONG cLrgObjSize; // size of Large Object Heap + ULONG cSurviveFinalize; // count of instances surviving from finalizing + ULONG cHandles; // count of GC handles + ULONG cbAlloc; // bytes allocated + ULONG cbLargeAlloc; // bytes allocated for Large Objects + ULONG cInducedGCs; // number of explicit GCs + ULONG timeInGC; // Time in GC + ULONG timeInGCBase; // must follow time in GC counter + ULONG cPinnedObj; // # of Pinned Objects + ULONG cSinkBlocks; // # of sink blocks +} Perf_GC_Wow64; +#include + + + +#ifndef _WIN64 +#include +#endif +typedef struct Perf_Loading +{ + TRICOUNT cClassesLoaded; + TRICOUNT_IL cAppDomains; // Current # of AppDomains + TRICOUNT cAssemblies; // Current # of Assemblies + UNALIGNED LONGLONG timeLoading; // % time loading + ULONG cAsmSearchLen; // Avg search length for assemblies + DUALCOUNT cLoadFailures; // Classes Failed to load + size_t cbLoaderHeapSize; // Total size of heap used by the loader + DUALCOUNT cAppDomainsUnloaded; // Rate at which app domains are unloaded +} Perf_Loading; +#ifndef _WIN64 +#include +#endif + +#include +typedef struct Perf_Loading_Wow64 +{ + TRICOUNT cClassesLoaded; + TRICOUNT_IL cAppDomains; // Current # of AppDomains + TRICOUNT cAssemblies; // Current # of Assemblies + UNALIGNED LONGLONG timeLoading; // % time loading + ULONG cAsmSearchLen; // Avg search length for assemblies + DUALCOUNT cLoadFailures; // Classes Failed to load + ULONG cbLoaderHeapSize; // Total size of heap used by the loader + DUALCOUNT cAppDomainsUnloaded; // Rate at which app domains are unloaded +} Perf_Loading_Wow64; +#include + + +#ifndef _WIN64 +#include +#endif +typedef struct Perf_Jit +{ + ULONG cMethodsJitted; // number of methods jitted + TRICOUNT cbILJitted; // IL jitted stats + //DUALCOUNT cbPitched; // Total bytes pitched + ULONG cJitFailures; // # of standard Jit failures + ULONG timeInJit; // Time in JIT since last sample + ULONG timeInJitBase; // Time in JIT base counter +} Perf_Jit; +#ifndef _WIN64 +#include +#endif + +#ifndef _WIN64 +#include +#endif +typedef struct Perf_Excep +{ + DUALCOUNT cThrown; // Number of Exceptions thrown + ULONG cFiltersExecuted; // Number of Filters executed + ULONG cFinallysExecuted; // Number of Finallys executed + ULONG cThrowToCatchStackDepth; // Delta from throw to catch site on stack +} Perf_Excep; +#ifndef _WIN64 +#include +#endif + +#ifndef _WIN64 +#include +#endif +typedef struct Perf_Interop +{ + ULONG cCCW; // Number of CCWs + ULONG cStubs; // Number of stubs + ULONG cMarshalling; // # of time marshalling args and return values. + ULONG cTLBImports; // Number of tlbs we import + ULONG cTLBExports; // Number of tlbs we export +} Perf_Interop; +#ifndef _WIN64 +#include +#endif + +#ifndef _WIN64 +#include +#endif +typedef struct Perf_LocksAndThreads +{ + // Locks + DUALCOUNT cContention; // # of times in AwareLock::EnterEpilogue() + TRICOUNT cQueueLength; // Lenght of queue + // Threads + ULONG cCurrentThreadsLogical; // Number (created - destroyed) of logical threads + ULONG cCurrentThreadsPhysical; // Number (created - destroyed) of OS threads + TRICOUNT cRecognizedThreads; // # of Threads execute in runtime's control +} Perf_LocksAndThreads; +#ifndef _WIN64 +#include +#endif + + +// IMPORTANT!!!!!!!: The first two fields in the struct have to be together +// and be the first two fields in the struct. The managed code in ChannelServices.cs +// depends on this. +#ifndef _WIN64 +#include +#endif +typedef struct Perf_Contexts +{ + // Contexts & Remoting + DUALCOUNT cRemoteCalls; // # of remote calls + ULONG cChannels; // Number of current channels + ULONG cProxies; // Number of context proxies. + ULONG cClasses; // # of Context-bound classes + ULONG cObjAlloc; // # of context bound objects allocated + ULONG cContexts; // The current number of contexts. +} Perf_Contexts; +#ifndef _WIN64 +#include +#endif + + +#ifndef _WIN64 +#include +#endif +typedef struct Perf_Security +{ + ULONG cTotalRTChecks; // Total runtime checks + UNALIGNED LONGLONG timeAuthorize; // % time authenticating + ULONG cLinkChecks; // link time checks + ULONG timeRTchecks; // % time in Runtime checks + ULONG timeRTchecksBase; // % time in Runtime checks base counter + ULONG stackWalkDepth; // depth of stack for security checks +} Perf_Security; +#ifndef _WIN64 +#include +#endif + +#include +typedef struct Perf_Security_Wow64 +{ + ULONG cTotalRTChecks; // Total runtime checks + UNALIGNED LONGLONG timeAuthorize; // % time authenticating + ULONG cLinkChecks; // link time checks + ULONG timeRTchecks; // % time in Runtime checks + ULONG timeRTchecksBase; // % time in Runtime checks base counter + ULONG stackWalkDepth; // depth of stack for security checks +} Perf_Security_Wow64; +#include + + +#ifndef _WIN64 +#include +#endif +typedef struct _PerfCounterIPCControlBlock +{ + // Versioning info + USHORT Bytes; // size of this entire block + USHORT Attributes; // attributes for this block + + // Counter Sections + Perf_GC GC; + Perf_Contexts Context; + Perf_Interop Interop; + Perf_Loading Loading; + Perf_Excep Excep; + Perf_LocksAndThreads LocksAndThreads; + Perf_Jit Jit; + Perf_Security Security; +} PerfCounterIPCControlBlock; +#ifndef _WIN64 +#include +#endif + +#include +typedef struct _PerfCounterIPCControlBlock_Wow64 +{ + // Versioning info + USHORT Bytes; // size of this entire block + USHORT Attributes; // attributes for this block + + // Counter Sections + Perf_GC_Wow64 GC; + Perf_Contexts Context; + Perf_Interop Interop; + Perf_Loading_Wow64 Loading; + Perf_Excep Excep; + Perf_LocksAndThreads LocksAndThreads; + Perf_Jit Jit; + Perf_Security_Wow64 Security; +} PerfCounterIPCControlBlock_Wow64; +#include + + #endif _PERF_COUNTERS_H_ \ No newline at end of file diff --git a/plugins/DotNetTools/clretw.h b/plugins/DotNetTools/clretw.h index e82772d64571..289802e15ff2 100644 --- a/plugins/DotNetTools/clretw.h +++ b/plugins/DotNetTools/clretw.h @@ -1,146 +1,146 @@ -/* - * Process Hacker .NET Tools - * - * Copyright (C) 2011-2015 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#ifndef CLRETW_H -#define CLRETW_H - -// Keywords - -#define CLR_LOADER_KEYWORD 0x8 -#define CLR_STARTENUMERATION_KEYWORD 0x40 - -// Event IDs - -#define DCStartComplete_V1 145 -#define ModuleDCStart_V1 153 -#define AssemblyDCStart_V1 155 -#define AppDomainDCStart_V1 157 -#define RuntimeInformationDCStart 187 - -// Opcodes - -#define CLR_METHODDC_DCSTARTCOMPLETE_OPCODE 14 -#define CLR_MODULEDCSTART_OPCODE 35 - -// Bit maps - -// AppDomainFlags -#define AppDomainFlags_Default 0x1 -#define AppDomainFlags_Executable 0x2 -#define AppDomainFlags_Shared 0x4 - -// AssemblyFlags -#define AssemblyFlags_DomainNeutral 0x1 -#define AssemblyFlags_Dynamic 0x2 -#define AssemblyFlags_Native 0x4 -#define AssemblyFlags_Collectible 0x8 - -// ModuleFlags -#define ModuleFlags_DomainNeutral 0x1 -#define ModuleFlags_Native 0x2 -#define ModuleFlags_Dynamic 0x4 -#define ModuleFlags_Manifest 0x8 - -// StartupMode -#define StartupMode_ManagedExe 0x1 -#define StartupMode_HostedCLR 0x2 -#define StartupMode_IjwDll 0x4 -#define StartupMode_ComActivated 0x8 -#define StartupMode_Other 0x10 - -// StartupFlags -#define StartupFlags_CONCURRENT_GC 0x1 -#define StartupFlags_LOADER_OPTIMIZATION_SINGLE_DOMAIN 0x2 -#define StartupFlags_LOADER_OPTIMIZATION_MULTI_DOMAIN 0x4 -#define StartupFlags_LOADER_SAFEMODE 0x10 -#define StartupFlags_LOADER_SETPREFERENCE 0x100 -#define StartupFlags_SERVER_GC 0x1000 -#define StartupFlags_HOARD_GC_VM 0x2000 -#define StartupFlags_SINGLE_VERSION_HOSTING_INTERFACE 0x4000 -#define StartupFlags_LEGACY_IMPERSONATION 0x10000 -#define StartupFlags_DISABLE_COMMITTHREADSTACK 0x20000 -#define StartupFlags_ALWAYSFLOW_IMPERSONATION 0x40000 -#define StartupFlags_TRIM_GC_COMMIT 0x80000 -#define StartupFlags_ETW 0x100000 -#define StartupFlags_SERVER_BUILD 0x200000 -#define StartupFlags_ARM 0x400000 - -// Templates - -#include - -typedef struct _DCStartEnd -{ - USHORT ClrInstanceID; -} DCStartEnd, *PDCStartEnd; - -typedef struct _ModuleLoadUnloadRundown_V1 -{ - ULONG64 ModuleID; - ULONG64 AssemblyID; - ULONG ModuleFlags; // ModuleFlags - ULONG Reserved1; - WCHAR ModuleILPath[1]; - // WCHAR ModuleNativePath[1]; - // USHORT ClrInstanceID; -} ModuleLoadUnloadRundown_V1, *PModuleLoadUnloadRundown_V1; - -typedef struct _AssemblyLoadUnloadRundown_V1 -{ - ULONG64 AssemblyID; - ULONG64 AppDomainID; - ULONG64 BindingID; - ULONG AssemblyFlags; // AssemblyFlags - WCHAR FullyQualifiedAssemblyName[1]; - // USHORT ClrInstanceID; -} AssemblyLoadUnloadRundown_V1, *PAssemblyLoadUnloadRundown_V1; - -typedef struct _AppDomainLoadUnloadRundown_V1 -{ - ULONG64 AppDomainID; - ULONG AppDomainFlags; // AppDomainFlags - WCHAR AppDomainName[1]; - // ULONG AppDomainIndex; - // USHORT ClrInstanceID; -} AppDomainLoadUnloadRundown_V1, *PAppDomainLoadUnloadRundown_V1; - -typedef struct _RuntimeInformationRundown -{ - USHORT ClrInstanceID; - USHORT Sku; - USHORT BclMajorVersion; - USHORT BclMinorVersion; - USHORT BclBuildNumber; - USHORT BclQfeNumber; - USHORT VMMajorVersion; - USHORT VMMinorVersion; - USHORT VMBuildNumber; - USHORT VMQfeNumber; - ULONG StartupFlags; // StartupFlags - UCHAR StartupMode; // StartupMode - WCHAR CommandLine[1]; - // GUID ComObjectGuid; - // WCHAR RuntimeDllPath[1]; -} RuntimeInformationRundown, *PRuntimeInformationRundown; - -#include - -#endif +/* + * Process Hacker .NET Tools + * + * Copyright (C) 2011-2015 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#ifndef CLRETW_H +#define CLRETW_H + +// Keywords + +#define CLR_LOADER_KEYWORD 0x8 +#define CLR_STARTENUMERATION_KEYWORD 0x40 + +// Event IDs + +#define DCStartComplete_V1 145 +#define ModuleDCStart_V1 153 +#define AssemblyDCStart_V1 155 +#define AppDomainDCStart_V1 157 +#define RuntimeInformationDCStart 187 + +// Opcodes + +#define CLR_METHODDC_DCSTARTCOMPLETE_OPCODE 14 +#define CLR_MODULEDCSTART_OPCODE 35 + +// Bit maps + +// AppDomainFlags +#define AppDomainFlags_Default 0x1 +#define AppDomainFlags_Executable 0x2 +#define AppDomainFlags_Shared 0x4 + +// AssemblyFlags +#define AssemblyFlags_DomainNeutral 0x1 +#define AssemblyFlags_Dynamic 0x2 +#define AssemblyFlags_Native 0x4 +#define AssemblyFlags_Collectible 0x8 + +// ModuleFlags +#define ModuleFlags_DomainNeutral 0x1 +#define ModuleFlags_Native 0x2 +#define ModuleFlags_Dynamic 0x4 +#define ModuleFlags_Manifest 0x8 + +// StartupMode +#define StartupMode_ManagedExe 0x1 +#define StartupMode_HostedCLR 0x2 +#define StartupMode_IjwDll 0x4 +#define StartupMode_ComActivated 0x8 +#define StartupMode_Other 0x10 + +// StartupFlags +#define StartupFlags_CONCURRENT_GC 0x1 +#define StartupFlags_LOADER_OPTIMIZATION_SINGLE_DOMAIN 0x2 +#define StartupFlags_LOADER_OPTIMIZATION_MULTI_DOMAIN 0x4 +#define StartupFlags_LOADER_SAFEMODE 0x10 +#define StartupFlags_LOADER_SETPREFERENCE 0x100 +#define StartupFlags_SERVER_GC 0x1000 +#define StartupFlags_HOARD_GC_VM 0x2000 +#define StartupFlags_SINGLE_VERSION_HOSTING_INTERFACE 0x4000 +#define StartupFlags_LEGACY_IMPERSONATION 0x10000 +#define StartupFlags_DISABLE_COMMITTHREADSTACK 0x20000 +#define StartupFlags_ALWAYSFLOW_IMPERSONATION 0x40000 +#define StartupFlags_TRIM_GC_COMMIT 0x80000 +#define StartupFlags_ETW 0x100000 +#define StartupFlags_SERVER_BUILD 0x200000 +#define StartupFlags_ARM 0x400000 + +// Templates + +#include + +typedef struct _DCStartEnd +{ + USHORT ClrInstanceID; +} DCStartEnd, *PDCStartEnd; + +typedef struct _ModuleLoadUnloadRundown_V1 +{ + ULONG64 ModuleID; + ULONG64 AssemblyID; + ULONG ModuleFlags; // ModuleFlags + ULONG Reserved1; + WCHAR ModuleILPath[1]; + // WCHAR ModuleNativePath[1]; + // USHORT ClrInstanceID; +} ModuleLoadUnloadRundown_V1, *PModuleLoadUnloadRundown_V1; + +typedef struct _AssemblyLoadUnloadRundown_V1 +{ + ULONG64 AssemblyID; + ULONG64 AppDomainID; + ULONG64 BindingID; + ULONG AssemblyFlags; // AssemblyFlags + WCHAR FullyQualifiedAssemblyName[1]; + // USHORT ClrInstanceID; +} AssemblyLoadUnloadRundown_V1, *PAssemblyLoadUnloadRundown_V1; + +typedef struct _AppDomainLoadUnloadRundown_V1 +{ + ULONG64 AppDomainID; + ULONG AppDomainFlags; // AppDomainFlags + WCHAR AppDomainName[1]; + // ULONG AppDomainIndex; + // USHORT ClrInstanceID; +} AppDomainLoadUnloadRundown_V1, *PAppDomainLoadUnloadRundown_V1; + +typedef struct _RuntimeInformationRundown +{ + USHORT ClrInstanceID; + USHORT Sku; + USHORT BclMajorVersion; + USHORT BclMinorVersion; + USHORT BclBuildNumber; + USHORT BclQfeNumber; + USHORT VMMajorVersion; + USHORT VMMinorVersion; + USHORT VMBuildNumber; + USHORT VMQfeNumber; + ULONG StartupFlags; // StartupFlags + UCHAR StartupMode; // StartupMode + WCHAR CommandLine[1]; + // GUID ComObjectGuid; + // WCHAR RuntimeDllPath[1]; +} RuntimeInformationRundown, *PRuntimeInformationRundown; + +#include + +#endif diff --git a/plugins/DotNetTools/clrsup.c b/plugins/DotNetTools/clrsup.c index d5c33ae85e76..3fca660cb6ce 100644 --- a/plugins/DotNetTools/clrsup.c +++ b/plugins/DotNetTools/clrsup.c @@ -1,575 +1,575 @@ -/* - * Process Hacker .NET Tools - - * CLR data access functions - * - * Copyright (C) 2011-2015 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include "dn.h" -#include "clrsup.h" - -static GUID IID_ICLRDataTarget_I = { 0x3e11ccee, 0xd08b, 0x43e5, { 0xaf, 0x01, 0x32, 0x71, 0x7a, 0x64, 0xda, 0x03 } }; -static GUID IID_IXCLRDataProcess = { 0x5c552ab6, 0xfc09, 0x4cb3, { 0x8e, 0x36, 0x22, 0xfa, 0x03, 0xc7, 0x98, 0xb7 } }; - -static ICLRDataTargetVtbl DnCLRDataTarget_VTable = -{ - DnCLRDataTarget_QueryInterface, - DnCLRDataTarget_AddRef, - DnCLRDataTarget_Release, - DnCLRDataTarget_GetMachineType, - DnCLRDataTarget_GetPointerSize, - DnCLRDataTarget_GetImageBase, - DnCLRDataTarget_ReadVirtual, - DnCLRDataTarget_WriteVirtual, - DnCLRDataTarget_GetTLSValue, - DnCLRDataTarget_SetTLSValue, - DnCLRDataTarget_GetCurrentThreadID, - DnCLRDataTarget_GetThreadContext, - DnCLRDataTarget_SetThreadContext, - DnCLRDataTarget_Request -}; - -PCLR_PROCESS_SUPPORT CreateClrProcessSupport( - _In_ HANDLE ProcessId - ) -{ - PCLR_PROCESS_SUPPORT support; - ICLRDataTarget *dataTarget; - IXCLRDataProcess *dataProcess; - - dataTarget = DnCLRDataTarget_Create(ProcessId); - - if (!dataTarget) - return NULL; - - dataProcess = NULL; - CreateXCLRDataProcess(ProcessId, dataTarget, &dataProcess); - ICLRDataTarget_Release(dataTarget); - - if (!dataProcess) - return NULL; - - support = PhAllocate(sizeof(CLR_PROCESS_SUPPORT)); - support->DataProcess = dataProcess; - - return support; -} - -VOID FreeClrProcessSupport( - _In_ PCLR_PROCESS_SUPPORT Support - ) -{ - IXCLRDataProcess_Release(Support->DataProcess); - PhFree(Support); -} - -PPH_STRING GetRuntimeNameByAddressClrProcess( - _In_ PCLR_PROCESS_SUPPORT Support, - _In_ ULONG64 Address, - _Out_opt_ PULONG64 Displacement - ) -{ - PPH_STRING buffer; - ULONG bufferLength; - ULONG returnLength; - ULONG64 displacement; - - bufferLength = 33; - buffer = PhCreateStringEx(NULL, (bufferLength - 1) * 2); - - returnLength = 0; - - if (!SUCCEEDED(IXCLRDataProcess_GetRuntimeNameByAddress( - Support->DataProcess, - Address, - 0, - bufferLength, - &returnLength, - buffer->Buffer, - &displacement - ))) - { - PhDereferenceObject(buffer); - return NULL; - } - - // Try again if our buffer was too small. - if (returnLength > bufferLength) - { - PhDereferenceObject(buffer); - bufferLength = returnLength; - buffer = PhCreateStringEx(NULL, (bufferLength - 1) * 2); - - if (!SUCCEEDED(IXCLRDataProcess_GetRuntimeNameByAddress( - Support->DataProcess, - Address, - 0, - bufferLength, - &returnLength, - buffer->Buffer, - &displacement - ))) - { - PhDereferenceObject(buffer); - return NULL; - } - } - - if (Displacement) - *Displacement = displacement; - - buffer->Length = (returnLength - 1) * 2; - - return buffer; -} - -PPH_STRING GetNameXClrDataAppDomain( - _In_ PVOID AppDomain - ) -{ - IXCLRDataAppDomain *appDomain; - PPH_STRING buffer; - ULONG bufferLength; - ULONG returnLength; - - appDomain = AppDomain; - - bufferLength = 33; - buffer = PhCreateStringEx(NULL, (bufferLength - 1) * 2); - - returnLength = 0; - - if (!SUCCEEDED(IXCLRDataAppDomain_GetName(appDomain, bufferLength, &returnLength, buffer->Buffer))) - { - PhDereferenceObject(buffer); - return NULL; - } - - // Try again if our buffer was too small. - if (returnLength > bufferLength) - { - PhDereferenceObject(buffer); - bufferLength = returnLength; - buffer = PhCreateStringEx(NULL, (bufferLength - 1) * 2); - - if (!SUCCEEDED(IXCLRDataAppDomain_GetName(appDomain, bufferLength, &returnLength, buffer->Buffer))) - { - PhDereferenceObject(buffer); - return NULL; - } - } - - buffer->Length = (returnLength - 1) * 2; - - return buffer; -} - -PVOID LoadMscordacwks( - _In_ BOOLEAN IsClrV4 - ) -{ - PVOID dllBase; - PH_STRINGREF systemRootString; - PH_STRINGREF mscordacwksPathString; - PPH_STRING mscordacwksFileName; - - LoadLibrary(L"mscoree.dll"); - - PhGetSystemRoot(&systemRootString); - - if (IsClrV4) - { -#ifdef _WIN64 - PhInitializeStringRef(&mscordacwksPathString, L"\\Microsoft.NET\\Framework64\\v4.0.30319\\mscordacwks.dll"); -#else - PhInitializeStringRef(&mscordacwksPathString, L"\\Microsoft.NET\\Framework\\v4.0.30319\\mscordacwks.dll"); -#endif - } - else - { -#ifdef _WIN64 - PhInitializeStringRef(&mscordacwksPathString, L"\\Microsoft.NET\\Framework64\\v2.0.50727\\mscordacwks.dll"); -#else - PhInitializeStringRef(&mscordacwksPathString, L"\\Microsoft.NET\\Framework\\v2.0.50727\\mscordacwks.dll"); -#endif - } - - mscordacwksFileName = PhConcatStringRef2(&systemRootString, &mscordacwksPathString); - dllBase = LoadLibrary(mscordacwksFileName->Buffer); - PhDereferenceObject(mscordacwksFileName); - - return dllBase; -} - -HRESULT CreateXCLRDataProcess( - _In_ HANDLE ProcessId, - _In_ ICLRDataTarget *Target, - _Out_ struct IXCLRDataProcess **DataProcess - ) -{ - ULONG flags; - BOOLEAN clrV4; - HMODULE dllBase; - HRESULT (__stdcall *clrDataCreateInstance)(REFIID, ICLRDataTarget *, void **); - - clrV4 = FALSE; - - if (NT_SUCCESS(PhGetProcessIsDotNetEx(ProcessId, NULL, 0, NULL, &flags))) - { - if (flags & PH_CLR_VERSION_4_ABOVE) - clrV4 = TRUE; - } - - // Load the correct version of mscordacwks.dll. - - if (clrV4) - { - static PH_INITONCE initOnce = PH_INITONCE_INIT; - static HMODULE mscordacwksDllBase; - - if (PhBeginInitOnce(&initOnce)) - { - mscordacwksDllBase = LoadMscordacwks(TRUE); - PhEndInitOnce(&initOnce); - } - - dllBase = mscordacwksDllBase; - } - else - { - static PH_INITONCE initOnce = PH_INITONCE_INIT; - static HMODULE mscordacwksDllBase; - - if (PhBeginInitOnce(&initOnce)) - { - mscordacwksDllBase = LoadMscordacwks(FALSE); - PhEndInitOnce(&initOnce); - } - - dllBase = mscordacwksDllBase; - } - - if (!dllBase) - return E_FAIL; - - clrDataCreateInstance = PhGetProcedureAddress(dllBase, "CLRDataCreateInstance", 0); - - if (!clrDataCreateInstance) - return E_FAIL; - - return clrDataCreateInstance(&IID_IXCLRDataProcess, Target, DataProcess); -} - -ICLRDataTarget *DnCLRDataTarget_Create( - _In_ HANDLE ProcessId - ) -{ - DnCLRDataTarget *dataTarget; - HANDLE processHandle; - BOOLEAN isWow64; - - if (!NT_SUCCESS(PhOpenProcess(&processHandle, ProcessQueryAccess | PROCESS_VM_READ, ProcessId))) - return NULL; - -#ifdef _WIN64 - if (!NT_SUCCESS(PhGetProcessIsWow64(processHandle, &isWow64))) - { - NtClose(processHandle); - return NULL; - } -#else - isWow64 = FALSE; -#endif - - dataTarget = PhAllocate(sizeof(DnCLRDataTarget)); - dataTarget->VTable = &DnCLRDataTarget_VTable; - dataTarget->RefCount = 1; - - dataTarget->ProcessId = ProcessId; - dataTarget->ProcessHandle = processHandle; - dataTarget->IsWow64 = isWow64; - - return (ICLRDataTarget *)dataTarget; -} - -HRESULT STDMETHODCALLTYPE DnCLRDataTarget_QueryInterface( - _In_ ICLRDataTarget *This, - _In_ REFIID Riid, - _Out_ PVOID *Object - ) -{ - if ( - IsEqualIID(Riid, &IID_IUnknown) || - IsEqualIID(Riid, &IID_ICLRDataTarget_I) - ) - { - DnCLRDataTarget_AddRef(This); - *Object = This; - return S_OK; - } - - *Object = NULL; - return E_NOINTERFACE; -} - -ULONG STDMETHODCALLTYPE DnCLRDataTarget_AddRef( - _In_ ICLRDataTarget *This - ) -{ - DnCLRDataTarget *this = (DnCLRDataTarget *)This; - - this->RefCount++; - - return this->RefCount; -} - -ULONG STDMETHODCALLTYPE DnCLRDataTarget_Release( - _In_ ICLRDataTarget *This - ) -{ - DnCLRDataTarget *this = (DnCLRDataTarget *)This; - - this->RefCount--; - - if (this->RefCount == 0) - { - NtClose(this->ProcessHandle); - - PhFree(this); - - return 0; - } - - return this->RefCount; -} - -HRESULT STDMETHODCALLTYPE DnCLRDataTarget_GetMachineType( - _In_ ICLRDataTarget *This, - _Out_ ULONG32 *machineType - ) -{ - DnCLRDataTarget *this = (DnCLRDataTarget *)This; - -#ifdef _WIN64 - if (!this->IsWow64) - *machineType = IMAGE_FILE_MACHINE_AMD64; - else - *machineType = IMAGE_FILE_MACHINE_I386; -#else - *machineType = IMAGE_FILE_MACHINE_I386; -#endif - - return S_OK; -} - -HRESULT STDMETHODCALLTYPE DnCLRDataTarget_GetPointerSize( - _In_ ICLRDataTarget *This, - _Out_ ULONG32 *pointerSize - ) -{ - DnCLRDataTarget *this = (DnCLRDataTarget *)This; - -#ifdef _WIN64 - if (!this->IsWow64) -#endif - *pointerSize = sizeof(PVOID); -#ifdef _WIN64 - else - *pointerSize = sizeof(ULONG); -#endif - - return S_OK; -} - -BOOLEAN NTAPI PhpGetImageBaseCallback( - _In_ PLDR_DATA_TABLE_ENTRY Module, - _In_opt_ PVOID Context - ) -{ - PPHP_GET_IMAGE_BASE_CONTEXT context = Context; - - if (RtlEqualUnicodeString(&Module->FullDllName, &context->ImagePath, TRUE) || - RtlEqualUnicodeString(&Module->BaseDllName, &context->ImagePath, TRUE)) - { - context->BaseAddress = Module->DllBase; - return FALSE; - } - - return TRUE; -} - -HRESULT STDMETHODCALLTYPE DnCLRDataTarget_GetImageBase( - _In_ ICLRDataTarget *This, - _In_ LPCWSTR imagePath, - _Out_ CLRDATA_ADDRESS *baseAddress - ) -{ - DnCLRDataTarget *this = (DnCLRDataTarget *)This; - PHP_GET_IMAGE_BASE_CONTEXT context; - - RtlInitUnicodeString(&context.ImagePath, (PWSTR)imagePath); - context.BaseAddress = NULL; - PhEnumProcessModules(this->ProcessHandle, PhpGetImageBaseCallback, &context); - -#ifdef _WIN64 - if (this->IsWow64) - PhEnumProcessModules32(this->ProcessHandle, PhpGetImageBaseCallback, &context); -#endif - - if (context.BaseAddress) - { - *baseAddress = (CLRDATA_ADDRESS)context.BaseAddress; - - return S_OK; - } - else - { - return E_FAIL; - } -} - -HRESULT STDMETHODCALLTYPE DnCLRDataTarget_ReadVirtual( - _In_ ICLRDataTarget *This, - _In_ CLRDATA_ADDRESS address, - _Out_ BYTE *buffer, - _In_ ULONG32 bytesRequested, - _Out_ ULONG32 *bytesRead - ) -{ - DnCLRDataTarget *this = (DnCLRDataTarget *)This; - NTSTATUS status; - SIZE_T numberOfBytesRead; - - if (NT_SUCCESS(status = NtReadVirtualMemory( - this->ProcessHandle, - (PVOID)address, - buffer, - bytesRequested, - &numberOfBytesRead - ))) - { - *bytesRead = (ULONG32)numberOfBytesRead; - - return S_OK; - } - else - { - ULONG result; - - result = RtlNtStatusToDosError(status); - - return HRESULT_FROM_WIN32(result); - } -} - -HRESULT STDMETHODCALLTYPE DnCLRDataTarget_WriteVirtual( - _In_ ICLRDataTarget *This, - _In_ CLRDATA_ADDRESS address, - _In_ BYTE *buffer, - _In_ ULONG32 bytesRequested, - _Out_ ULONG32 *bytesWritten - ) -{ - return E_NOTIMPL; -} - -HRESULT STDMETHODCALLTYPE DnCLRDataTarget_GetTLSValue( - _In_ ICLRDataTarget *This, - _In_ ULONG32 threadID, - _In_ ULONG32 index, - _Out_ CLRDATA_ADDRESS *value - ) -{ - return E_NOTIMPL; -} - -HRESULT STDMETHODCALLTYPE DnCLRDataTarget_SetTLSValue( - _In_ ICLRDataTarget *This, - _In_ ULONG32 threadID, - _In_ ULONG32 index, - _In_ CLRDATA_ADDRESS value - ) -{ - return E_NOTIMPL; -} - -HRESULT STDMETHODCALLTYPE DnCLRDataTarget_GetCurrentThreadID( - _In_ ICLRDataTarget *This, - _Out_ ULONG32 *threadID - ) -{ - return E_NOTIMPL; -} - -HRESULT STDMETHODCALLTYPE DnCLRDataTarget_GetThreadContext( - _In_ ICLRDataTarget *This, - _In_ ULONG32 threadID, - _In_ ULONG32 contextFlags, - _In_ ULONG32 contextSize, - _Out_ BYTE *context - ) -{ - NTSTATUS status; - HANDLE threadHandle; - CONTEXT buffer; - - if (contextSize < sizeof(CONTEXT)) - return E_INVALIDARG; - - memset(&buffer, 0, sizeof(CONTEXT)); - buffer.ContextFlags = contextFlags; - - if (NT_SUCCESS(status = PhOpenThread(&threadHandle, THREAD_GET_CONTEXT, UlongToHandle(threadID)))) - { - status = NtGetContextThread(threadHandle, &buffer); - NtClose(threadHandle); - } - - if (NT_SUCCESS(status)) - { - memcpy(context, &buffer, sizeof(CONTEXT)); - - return S_OK; - } - else - { - return HRESULT_FROM_WIN32(RtlNtStatusToDosError(status)); - } -} - -HRESULT STDMETHODCALLTYPE DnCLRDataTarget_SetThreadContext( - _In_ ICLRDataTarget *This, - _In_ ULONG32 threadID, - _In_ ULONG32 contextSize, - _In_ BYTE *context - ) -{ - return E_NOTIMPL; -} - -HRESULT STDMETHODCALLTYPE DnCLRDataTarget_Request( - _In_ ICLRDataTarget *This, - _In_ ULONG32 reqCode, - _In_ ULONG32 inBufferSize, - _In_ BYTE *inBuffer, - _In_ ULONG32 outBufferSize, - _Out_ BYTE *outBuffer - ) -{ - return E_NOTIMPL; -} +/* + * Process Hacker .NET Tools - + * CLR data access functions + * + * Copyright (C) 2011-2015 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include "dn.h" +#include "clrsup.h" + +static GUID IID_ICLRDataTarget_I = { 0x3e11ccee, 0xd08b, 0x43e5, { 0xaf, 0x01, 0x32, 0x71, 0x7a, 0x64, 0xda, 0x03 } }; +static GUID IID_IXCLRDataProcess = { 0x5c552ab6, 0xfc09, 0x4cb3, { 0x8e, 0x36, 0x22, 0xfa, 0x03, 0xc7, 0x98, 0xb7 } }; + +static ICLRDataTargetVtbl DnCLRDataTarget_VTable = +{ + DnCLRDataTarget_QueryInterface, + DnCLRDataTarget_AddRef, + DnCLRDataTarget_Release, + DnCLRDataTarget_GetMachineType, + DnCLRDataTarget_GetPointerSize, + DnCLRDataTarget_GetImageBase, + DnCLRDataTarget_ReadVirtual, + DnCLRDataTarget_WriteVirtual, + DnCLRDataTarget_GetTLSValue, + DnCLRDataTarget_SetTLSValue, + DnCLRDataTarget_GetCurrentThreadID, + DnCLRDataTarget_GetThreadContext, + DnCLRDataTarget_SetThreadContext, + DnCLRDataTarget_Request +}; + +PCLR_PROCESS_SUPPORT CreateClrProcessSupport( + _In_ HANDLE ProcessId + ) +{ + PCLR_PROCESS_SUPPORT support; + ICLRDataTarget *dataTarget; + IXCLRDataProcess *dataProcess; + + dataTarget = DnCLRDataTarget_Create(ProcessId); + + if (!dataTarget) + return NULL; + + dataProcess = NULL; + CreateXCLRDataProcess(ProcessId, dataTarget, &dataProcess); + ICLRDataTarget_Release(dataTarget); + + if (!dataProcess) + return NULL; + + support = PhAllocate(sizeof(CLR_PROCESS_SUPPORT)); + support->DataProcess = dataProcess; + + return support; +} + +VOID FreeClrProcessSupport( + _In_ PCLR_PROCESS_SUPPORT Support + ) +{ + IXCLRDataProcess_Release(Support->DataProcess); + PhFree(Support); +} + +PPH_STRING GetRuntimeNameByAddressClrProcess( + _In_ PCLR_PROCESS_SUPPORT Support, + _In_ ULONG64 Address, + _Out_opt_ PULONG64 Displacement + ) +{ + PPH_STRING buffer; + ULONG bufferLength; + ULONG returnLength; + ULONG64 displacement; + + bufferLength = 33; + buffer = PhCreateStringEx(NULL, (bufferLength - 1) * 2); + + returnLength = 0; + + if (!SUCCEEDED(IXCLRDataProcess_GetRuntimeNameByAddress( + Support->DataProcess, + Address, + 0, + bufferLength, + &returnLength, + buffer->Buffer, + &displacement + ))) + { + PhDereferenceObject(buffer); + return NULL; + } + + // Try again if our buffer was too small. + if (returnLength > bufferLength) + { + PhDereferenceObject(buffer); + bufferLength = returnLength; + buffer = PhCreateStringEx(NULL, (bufferLength - 1) * 2); + + if (!SUCCEEDED(IXCLRDataProcess_GetRuntimeNameByAddress( + Support->DataProcess, + Address, + 0, + bufferLength, + &returnLength, + buffer->Buffer, + &displacement + ))) + { + PhDereferenceObject(buffer); + return NULL; + } + } + + if (Displacement) + *Displacement = displacement; + + buffer->Length = (returnLength - 1) * 2; + + return buffer; +} + +PPH_STRING GetNameXClrDataAppDomain( + _In_ PVOID AppDomain + ) +{ + IXCLRDataAppDomain *appDomain; + PPH_STRING buffer; + ULONG bufferLength; + ULONG returnLength; + + appDomain = AppDomain; + + bufferLength = 33; + buffer = PhCreateStringEx(NULL, (bufferLength - 1) * 2); + + returnLength = 0; + + if (!SUCCEEDED(IXCLRDataAppDomain_GetName(appDomain, bufferLength, &returnLength, buffer->Buffer))) + { + PhDereferenceObject(buffer); + return NULL; + } + + // Try again if our buffer was too small. + if (returnLength > bufferLength) + { + PhDereferenceObject(buffer); + bufferLength = returnLength; + buffer = PhCreateStringEx(NULL, (bufferLength - 1) * 2); + + if (!SUCCEEDED(IXCLRDataAppDomain_GetName(appDomain, bufferLength, &returnLength, buffer->Buffer))) + { + PhDereferenceObject(buffer); + return NULL; + } + } + + buffer->Length = (returnLength - 1) * 2; + + return buffer; +} + +PVOID LoadMscordacwks( + _In_ BOOLEAN IsClrV4 + ) +{ + PVOID dllBase; + PH_STRINGREF systemRootString; + PH_STRINGREF mscordacwksPathString; + PPH_STRING mscordacwksFileName; + + LoadLibrary(L"mscoree.dll"); + + PhGetSystemRoot(&systemRootString); + + if (IsClrV4) + { +#ifdef _WIN64 + PhInitializeStringRef(&mscordacwksPathString, L"\\Microsoft.NET\\Framework64\\v4.0.30319\\mscordacwks.dll"); +#else + PhInitializeStringRef(&mscordacwksPathString, L"\\Microsoft.NET\\Framework\\v4.0.30319\\mscordacwks.dll"); +#endif + } + else + { +#ifdef _WIN64 + PhInitializeStringRef(&mscordacwksPathString, L"\\Microsoft.NET\\Framework64\\v2.0.50727\\mscordacwks.dll"); +#else + PhInitializeStringRef(&mscordacwksPathString, L"\\Microsoft.NET\\Framework\\v2.0.50727\\mscordacwks.dll"); +#endif + } + + mscordacwksFileName = PhConcatStringRef2(&systemRootString, &mscordacwksPathString); + dllBase = LoadLibrary(mscordacwksFileName->Buffer); + PhDereferenceObject(mscordacwksFileName); + + return dllBase; +} + +HRESULT CreateXCLRDataProcess( + _In_ HANDLE ProcessId, + _In_ ICLRDataTarget *Target, + _Out_ struct IXCLRDataProcess **DataProcess + ) +{ + ULONG flags; + BOOLEAN clrV4; + HMODULE dllBase; + HRESULT (__stdcall *clrDataCreateInstance)(REFIID, ICLRDataTarget *, void **); + + clrV4 = FALSE; + + if (NT_SUCCESS(PhGetProcessIsDotNetEx(ProcessId, NULL, 0, NULL, &flags))) + { + if (flags & PH_CLR_VERSION_4_ABOVE) + clrV4 = TRUE; + } + + // Load the correct version of mscordacwks.dll. + + if (clrV4) + { + static PH_INITONCE initOnce = PH_INITONCE_INIT; + static HMODULE mscordacwksDllBase; + + if (PhBeginInitOnce(&initOnce)) + { + mscordacwksDllBase = LoadMscordacwks(TRUE); + PhEndInitOnce(&initOnce); + } + + dllBase = mscordacwksDllBase; + } + else + { + static PH_INITONCE initOnce = PH_INITONCE_INIT; + static HMODULE mscordacwksDllBase; + + if (PhBeginInitOnce(&initOnce)) + { + mscordacwksDllBase = LoadMscordacwks(FALSE); + PhEndInitOnce(&initOnce); + } + + dllBase = mscordacwksDllBase; + } + + if (!dllBase) + return E_FAIL; + + clrDataCreateInstance = PhGetProcedureAddress(dllBase, "CLRDataCreateInstance", 0); + + if (!clrDataCreateInstance) + return E_FAIL; + + return clrDataCreateInstance(&IID_IXCLRDataProcess, Target, DataProcess); +} + +ICLRDataTarget *DnCLRDataTarget_Create( + _In_ HANDLE ProcessId + ) +{ + DnCLRDataTarget *dataTarget; + HANDLE processHandle; + BOOLEAN isWow64; + + if (!NT_SUCCESS(PhOpenProcess(&processHandle, ProcessQueryAccess | PROCESS_VM_READ, ProcessId))) + return NULL; + +#ifdef _WIN64 + if (!NT_SUCCESS(PhGetProcessIsWow64(processHandle, &isWow64))) + { + NtClose(processHandle); + return NULL; + } +#else + isWow64 = FALSE; +#endif + + dataTarget = PhAllocate(sizeof(DnCLRDataTarget)); + dataTarget->VTable = &DnCLRDataTarget_VTable; + dataTarget->RefCount = 1; + + dataTarget->ProcessId = ProcessId; + dataTarget->ProcessHandle = processHandle; + dataTarget->IsWow64 = isWow64; + + return (ICLRDataTarget *)dataTarget; +} + +HRESULT STDMETHODCALLTYPE DnCLRDataTarget_QueryInterface( + _In_ ICLRDataTarget *This, + _In_ REFIID Riid, + _Out_ PVOID *Object + ) +{ + if ( + IsEqualIID(Riid, &IID_IUnknown) || + IsEqualIID(Riid, &IID_ICLRDataTarget_I) + ) + { + DnCLRDataTarget_AddRef(This); + *Object = This; + return S_OK; + } + + *Object = NULL; + return E_NOINTERFACE; +} + +ULONG STDMETHODCALLTYPE DnCLRDataTarget_AddRef( + _In_ ICLRDataTarget *This + ) +{ + DnCLRDataTarget *this = (DnCLRDataTarget *)This; + + this->RefCount++; + + return this->RefCount; +} + +ULONG STDMETHODCALLTYPE DnCLRDataTarget_Release( + _In_ ICLRDataTarget *This + ) +{ + DnCLRDataTarget *this = (DnCLRDataTarget *)This; + + this->RefCount--; + + if (this->RefCount == 0) + { + NtClose(this->ProcessHandle); + + PhFree(this); + + return 0; + } + + return this->RefCount; +} + +HRESULT STDMETHODCALLTYPE DnCLRDataTarget_GetMachineType( + _In_ ICLRDataTarget *This, + _Out_ ULONG32 *machineType + ) +{ + DnCLRDataTarget *this = (DnCLRDataTarget *)This; + +#ifdef _WIN64 + if (!this->IsWow64) + *machineType = IMAGE_FILE_MACHINE_AMD64; + else + *machineType = IMAGE_FILE_MACHINE_I386; +#else + *machineType = IMAGE_FILE_MACHINE_I386; +#endif + + return S_OK; +} + +HRESULT STDMETHODCALLTYPE DnCLRDataTarget_GetPointerSize( + _In_ ICLRDataTarget *This, + _Out_ ULONG32 *pointerSize + ) +{ + DnCLRDataTarget *this = (DnCLRDataTarget *)This; + +#ifdef _WIN64 + if (!this->IsWow64) +#endif + *pointerSize = sizeof(PVOID); +#ifdef _WIN64 + else + *pointerSize = sizeof(ULONG); +#endif + + return S_OK; +} + +BOOLEAN NTAPI PhpGetImageBaseCallback( + _In_ PLDR_DATA_TABLE_ENTRY Module, + _In_opt_ PVOID Context + ) +{ + PPHP_GET_IMAGE_BASE_CONTEXT context = Context; + + if (RtlEqualUnicodeString(&Module->FullDllName, &context->ImagePath, TRUE) || + RtlEqualUnicodeString(&Module->BaseDllName, &context->ImagePath, TRUE)) + { + context->BaseAddress = Module->DllBase; + return FALSE; + } + + return TRUE; +} + +HRESULT STDMETHODCALLTYPE DnCLRDataTarget_GetImageBase( + _In_ ICLRDataTarget *This, + _In_ LPCWSTR imagePath, + _Out_ CLRDATA_ADDRESS *baseAddress + ) +{ + DnCLRDataTarget *this = (DnCLRDataTarget *)This; + PHP_GET_IMAGE_BASE_CONTEXT context; + + RtlInitUnicodeString(&context.ImagePath, (PWSTR)imagePath); + context.BaseAddress = NULL; + PhEnumProcessModules(this->ProcessHandle, PhpGetImageBaseCallback, &context); + +#ifdef _WIN64 + if (this->IsWow64) + PhEnumProcessModules32(this->ProcessHandle, PhpGetImageBaseCallback, &context); +#endif + + if (context.BaseAddress) + { + *baseAddress = (CLRDATA_ADDRESS)context.BaseAddress; + + return S_OK; + } + else + { + return E_FAIL; + } +} + +HRESULT STDMETHODCALLTYPE DnCLRDataTarget_ReadVirtual( + _In_ ICLRDataTarget *This, + _In_ CLRDATA_ADDRESS address, + _Out_ BYTE *buffer, + _In_ ULONG32 bytesRequested, + _Out_ ULONG32 *bytesRead + ) +{ + DnCLRDataTarget *this = (DnCLRDataTarget *)This; + NTSTATUS status; + SIZE_T numberOfBytesRead; + + if (NT_SUCCESS(status = NtReadVirtualMemory( + this->ProcessHandle, + (PVOID)address, + buffer, + bytesRequested, + &numberOfBytesRead + ))) + { + *bytesRead = (ULONG32)numberOfBytesRead; + + return S_OK; + } + else + { + ULONG result; + + result = RtlNtStatusToDosError(status); + + return HRESULT_FROM_WIN32(result); + } +} + +HRESULT STDMETHODCALLTYPE DnCLRDataTarget_WriteVirtual( + _In_ ICLRDataTarget *This, + _In_ CLRDATA_ADDRESS address, + _In_ BYTE *buffer, + _In_ ULONG32 bytesRequested, + _Out_ ULONG32 *bytesWritten + ) +{ + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE DnCLRDataTarget_GetTLSValue( + _In_ ICLRDataTarget *This, + _In_ ULONG32 threadID, + _In_ ULONG32 index, + _Out_ CLRDATA_ADDRESS *value + ) +{ + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE DnCLRDataTarget_SetTLSValue( + _In_ ICLRDataTarget *This, + _In_ ULONG32 threadID, + _In_ ULONG32 index, + _In_ CLRDATA_ADDRESS value + ) +{ + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE DnCLRDataTarget_GetCurrentThreadID( + _In_ ICLRDataTarget *This, + _Out_ ULONG32 *threadID + ) +{ + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE DnCLRDataTarget_GetThreadContext( + _In_ ICLRDataTarget *This, + _In_ ULONG32 threadID, + _In_ ULONG32 contextFlags, + _In_ ULONG32 contextSize, + _Out_ BYTE *context + ) +{ + NTSTATUS status; + HANDLE threadHandle; + CONTEXT buffer; + + if (contextSize < sizeof(CONTEXT)) + return E_INVALIDARG; + + memset(&buffer, 0, sizeof(CONTEXT)); + buffer.ContextFlags = contextFlags; + + if (NT_SUCCESS(status = PhOpenThread(&threadHandle, THREAD_GET_CONTEXT, UlongToHandle(threadID)))) + { + status = NtGetContextThread(threadHandle, &buffer); + NtClose(threadHandle); + } + + if (NT_SUCCESS(status)) + { + memcpy(context, &buffer, sizeof(CONTEXT)); + + return S_OK; + } + else + { + return HRESULT_FROM_WIN32(RtlNtStatusToDosError(status)); + } +} + +HRESULT STDMETHODCALLTYPE DnCLRDataTarget_SetThreadContext( + _In_ ICLRDataTarget *This, + _In_ ULONG32 threadID, + _In_ ULONG32 contextSize, + _In_ BYTE *context + ) +{ + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE DnCLRDataTarget_Request( + _In_ ICLRDataTarget *This, + _In_ ULONG32 reqCode, + _In_ ULONG32 inBufferSize, + _In_ BYTE *inBuffer, + _In_ ULONG32 outBufferSize, + _Out_ BYTE *outBuffer + ) +{ + return E_NOTIMPL; +} diff --git a/plugins/DotNetTools/clrsup.h b/plugins/DotNetTools/clrsup.h index 27cc978e4f1d..82a0b13962ae 100644 --- a/plugins/DotNetTools/clrsup.h +++ b/plugins/DotNetTools/clrsup.h @@ -1,645 +1,645 @@ -/* - * Process Hacker .NET Tools - - * CLR data access functions - * - * Copyright (C) 2011-2015 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#ifndef CLRSUP_H -#define CLRSUP_H - -#define CINTERFACE -#define COBJMACROS -#include "clr/clrdata.h" -#undef CINTERFACE -#undef COBJMACROS - -// General interfaces - -typedef struct _CLR_PROCESS_SUPPORT -{ - struct IXCLRDataProcess *DataProcess; -} CLR_PROCESS_SUPPORT, *PCLR_PROCESS_SUPPORT; - -PCLR_PROCESS_SUPPORT CreateClrProcessSupport( - _In_ HANDLE ProcessId - ); - -VOID FreeClrProcessSupport( - _In_ PCLR_PROCESS_SUPPORT Support - ); - -PPH_STRING GetRuntimeNameByAddressClrProcess( - _In_ PCLR_PROCESS_SUPPORT Support, - _In_ ULONG64 Address, - _Out_opt_ PULONG64 Displacement - ); - -PPH_STRING GetNameXClrDataAppDomain( - _In_ PVOID AppDomain - ); - -PVOID LoadMscordacwks( - _In_ BOOLEAN IsClrV4 - ); - -HRESULT CreateXCLRDataProcess( - _In_ HANDLE ProcessId, - _In_ ICLRDataTarget *Target, - _Out_ struct IXCLRDataProcess **DataProcess - ); - -// xclrdata - -typedef ULONG64 CLRDATA_ENUM; - -typedef struct IXCLRDataProcess IXCLRDataProcess; -typedef struct IXCLRDataAppDomain IXCLRDataAppDomain; -typedef struct IXCLRDataTask IXCLRDataTask; -typedef struct IXCLRDataStackWalk IXCLRDataStackWalk; -typedef struct IXCLRDataFrame IXCLRDataFrame; - -typedef struct IXCLRDataProcessVtbl -{ - HRESULT (STDMETHODCALLTYPE *QueryInterface)( - _In_ IXCLRDataProcess *This, - _In_ REFIID riid, - _Outptr_ void **ppvObject - ); - - ULONG (STDMETHODCALLTYPE *AddRef)( - _In_ IXCLRDataProcess *This - ); - - ULONG (STDMETHODCALLTYPE *Release)( - _In_ IXCLRDataProcess *This - ); - - HRESULT (STDMETHODCALLTYPE *Flush)( - _In_ IXCLRDataProcess *This - ); - - HRESULT (STDMETHODCALLTYPE *StartEnumTasks)( - _In_ IXCLRDataProcess *This, - _Out_ CLRDATA_ENUM *handle - ); - - HRESULT (STDMETHODCALLTYPE *EnumTask)( - _In_ IXCLRDataProcess *This, - _Inout_ CLRDATA_ENUM *handle, - _Out_ IXCLRDataTask **task - ); - - HRESULT (STDMETHODCALLTYPE *EndEnumTasks)( - _In_ IXCLRDataProcess *This, - _In_ CLRDATA_ENUM handle - ); - - HRESULT (STDMETHODCALLTYPE *GetTaskByOSThreadID)( - _In_ IXCLRDataProcess *This, - _In_ ULONG32 osThreadID, - _Out_ IXCLRDataTask **task - ); - - PVOID GetTaskByUniqueID; - PVOID GetFlags; - PVOID IsSameObject; - PVOID GetManagedObject; - PVOID GetDesiredExecutionState; - PVOID SetDesiredExecutionState; - PVOID GetAddressType; - - HRESULT (STDMETHODCALLTYPE *GetRuntimeNameByAddress)( - _In_ IXCLRDataProcess *This, - _In_ CLRDATA_ADDRESS address, - _In_ ULONG32 flags, - _In_ ULONG32 bufLen, - _Out_ ULONG32 *nameLen, - _Out_ WCHAR *nameBuf, - _Out_ CLRDATA_ADDRESS *displacement - ); - - // ... -} IXCLRDataProcessVtbl; - -typedef struct IXCLRDataProcess -{ - struct IXCLRDataProcessVtbl *lpVtbl; -} IXCLRDataProcess; - -#define IXCLRDataProcess_QueryInterface(This, riid, ppvObject) \ - ((This)->lpVtbl->QueryInterface(This, riid, ppvObject)) - -#define IXCLRDataProcess_AddRef(This) \ - ((This)->lpVtbl->AddRef(This)) - -#define IXCLRDataProcess_Release(This) \ - ((This)->lpVtbl->Release(This)) - -#define IXCLRDataProcess_GetRuntimeNameByAddress(This, address, flags, bufLen, nameLen, nameBuf, displacement) \ - ((This)->lpVtbl->GetRuntimeNameByAddress(This, address, flags, bufLen, nameLen, nameBuf, displacement)) - -#define IXCLRDataProcess_Flush(This) \ - ((This)->lpVtbl->Flush(This)) - -#define IXCLRDataProcess_StartEnumTasks(This, handle) \ - ((This)->lpVtbl->StartEnumTasks(This, handle)) - -#define IXCLRDataProcess_EnumTask(This, handle, task) \ - ((This)->lpVtbl->EnumTask(This, handle, task)) - -#define IXCLRDataProcess_EndEnumTasks(This, handle) \ - ((This)->lpVtbl->EndEnumTasks(This, handle)) - -#define IXCLRDataProcess_GetTaskByOSThreadID(This, osThreadID, task) \ - ((This)->lpVtbl->GetTaskByOSThreadID(This, osThreadID, task)) - -typedef struct IXCLRDataAppDomainVtbl -{ - HRESULT (STDMETHODCALLTYPE *QueryInterface)( - _In_ IXCLRDataAppDomain *This, - _In_ REFIID riid, - _Outptr_ void **ppvObject - ); - - ULONG (STDMETHODCALLTYPE *AddRef)( - _In_ IXCLRDataAppDomain *This - ); - - ULONG (STDMETHODCALLTYPE *Release)( - _In_ IXCLRDataAppDomain *This - ); - - HRESULT (STDMETHODCALLTYPE *GetProcess)( - _In_ IXCLRDataAppDomain *This, - _Out_ IXCLRDataProcess **process - ); - - HRESULT (STDMETHODCALLTYPE *GetName)( - _In_ IXCLRDataAppDomain *This, - _In_ ULONG32 bufLen, - _Out_ ULONG32 *nameLen, - _Out_ WCHAR *name - ); - - HRESULT (STDMETHODCALLTYPE *GetUniqueID)( - _In_ IXCLRDataAppDomain *This, - _Out_ ULONG64 *id - ); - - // ... -} IXCLRDataAppDomainVtbl; - -typedef struct IXCLRDataAppDomain -{ - struct IXCLRDataAppDomainVtbl *lpVtbl; -} IXCLRDataAppDomain; - -#define IXCLRDataAppDomain_QueryInterface(This, riid, ppvObject) \ - ((This)->lpVtbl->QueryInterface(This, riid, ppvObject)) - -#define IXCLRDataAppDomain_AddRef(This) \ - ((This)->lpVtbl->AddRef(This)) - -#define IXCLRDataAppDomain_Release(This) \ - ((This)->lpVtbl->Release(This)) - -#define IXCLRDataAppDomain_GetProcess(This, process) \ - ((This)->lpVtbl->GetProcess(This, process)) - -#define IXCLRDataAppDomain_GetName(This, bufLen, nameLen, name) \ - ((This)->lpVtbl->GetName(This, bufLen, nameLen, name)) - -#define IXCLRDataAppDomain_GetUniqueID(This, id) \ - ((This)->lpVtbl->GetUniqueID(This, id)) - -typedef struct IXCLRDataTaskVtbl -{ - HRESULT (STDMETHODCALLTYPE *QueryInterface)( - _In_ IXCLRDataTask *This, - _In_ REFIID riid, - _Outptr_ void **ppvObject - ); - - ULONG (STDMETHODCALLTYPE *AddRef)( - _In_ IXCLRDataTask *This - ); - - ULONG (STDMETHODCALLTYPE *Release)( - _In_ IXCLRDataTask *This - ); - - HRESULT (STDMETHODCALLTYPE *GetProcess)( - _In_ IXCLRDataTask *This, - _Out_ IXCLRDataProcess **process - ); - - HRESULT (STDMETHODCALLTYPE *GetCurrentAppDomain)( - _In_ IXCLRDataTask *This, - _Out_ IXCLRDataAppDomain **appDomain - ); - - HRESULT (STDMETHODCALLTYPE *GetUniqueID)( - _In_ IXCLRDataTask *This, - _Out_ ULONG64 *id - ); - - HRESULT (STDMETHODCALLTYPE *GetFlags)( - _In_ IXCLRDataTask *This, - _Out_ ULONG32 *flags - ); - - PVOID IsSameObject; - PVOID GetManagedObject; - PVOID GetDesiredExecutionState; - PVOID SetDesiredExecutionState; - - HRESULT (STDMETHODCALLTYPE *CreateStackWalk)( - _In_ IXCLRDataTask *This, - _In_ ULONG32 flags, - _Out_ IXCLRDataStackWalk **stackWalk - ); - - HRESULT (STDMETHODCALLTYPE *GetOSThreadID)( - _In_ IXCLRDataTask *This, - _Out_ ULONG32 *id - ); - - PVOID GetContext; - PVOID SetContext; - PVOID GetCurrentExceptionState; - PVOID Request; - - HRESULT (STDMETHODCALLTYPE *GetName)( - _In_ IXCLRDataTask *This, - _In_ ULONG32 bufLen, - _Out_ ULONG32 *nameLen, - _Out_ WCHAR *name - ); - - PVOID GetLastExceptionState; -} IXCLRDataTaskVtbl; - -typedef struct IXCLRDataTask -{ - struct IXCLRDataTaskVtbl *lpVtbl; -} IXCLRDataTask; - -#define IXCLRDataTask_QueryInterface(This, riid, ppvObject) \ - ((This)->lpVtbl->QueryInterface(This, riid, ppvObject)) - -#define IXCLRDataTask_AddRef(This) \ - ((This)->lpVtbl->AddRef(This)) - -#define IXCLRDataTask_Release(This) \ - ((This)->lpVtbl->Release(This)) - -#define IXCLRDataTask_GetProcess(This, process) \ - ((This)->lpVtbl->GetProcess(This, process)) - -#define IXCLRDataTask_GetCurrentAppDomain(This, appDomain) \ - ((This)->lpVtbl->GetCurrentAppDomain(This, appDomain)) - -#define IXCLRDataTask_GetUniqueID(This, id) \ - ((This)->lpVtbl->GetUniqueID(This, id)) - -#define IXCLRDataTask_GetFlags(This, flags) \ - ((This)->lpVtbl->GetFlags(This, flags)) - -#define IXCLRDataTask_CreateStackWalk(This, flags, stackWalk) \ - ((This)->lpVtbl->CreateStackWalk(This, flags, stackWalk)) - -#define IXCLRDataTask_GetOSThreadID(This, id) \ - ((This)->lpVtbl->GetOSThreadID(This, id)) - -#define IXCLRDataTask_GetName(This, bufLen, nameLen, name) \ - ((This)->lpVtbl->GetName(This, bufLen, nameLen, name)) - -typedef enum -{ - CLRDATA_SIMPFRAME_UNRECOGNIZED = 0x1, - CLRDATA_SIMPFRAME_MANAGED_METHOD = 0x2, - CLRDATA_SIMPFRAME_RUNTIME_MANAGED_CODE = 0x4, - CLRDATA_SIMPFRAME_RUNTIME_UNMANAGED_CODE = 0x8 -} CLRDataSimpleFrameType; - -typedef enum -{ - CLRDATA_DETFRAME_UNRECOGNIZED, - CLRDATA_DETFRAME_UNKNOWN_STUB, - CLRDATA_DETFRAME_CLASS_INIT, - CLRDATA_DETFRAME_EXCEPTION_FILTER, - CLRDATA_DETFRAME_SECURITY, - CLRDATA_DETFRAME_CONTEXT_POLICY, - CLRDATA_DETFRAME_INTERCEPTION, - CLRDATA_DETFRAME_PROCESS_START, - CLRDATA_DETFRAME_THREAD_START, - CLRDATA_DETFRAME_TRANSITION_TO_MANAGED, - CLRDATA_DETFRAME_TRANSITION_TO_UNMANAGED, - CLRDATA_DETFRAME_COM_INTEROP_STUB, - CLRDATA_DETFRAME_DEBUGGER_EVAL, - CLRDATA_DETFRAME_CONTEXT_SWITCH, - CLRDATA_DETFRAME_FUNC_EVAL, - CLRDATA_DETFRAME_FINALLY -} CLRDataDetailedFrameType; - -typedef enum -{ - CLRDATA_STACK_SET_UNWIND_CONTEXT = 0x00000000, - CLRDATA_STACK_SET_CURRENT_CONTEXT = 0x00000001 -} CLRDataStackSetContextFlag; - -typedef struct IXCLRDataStackWalkVtbl -{ - HRESULT (STDMETHODCALLTYPE *QueryInterface)( - _In_ IXCLRDataStackWalk *This, - _In_ REFIID riid, - _Outptr_ void **ppvObject - ); - - ULONG (STDMETHODCALLTYPE *AddRef)( - _In_ IXCLRDataStackWalk *This - ); - - ULONG (STDMETHODCALLTYPE *Release)( - _In_ IXCLRDataStackWalk *This - ); - - HRESULT (STDMETHODCALLTYPE *GetContext)( - _In_ IXCLRDataStackWalk *This, - _In_ ULONG32 contextFlags, - _In_ ULONG32 contextBufSize, - _Out_ ULONG32 *contextSize, - _Out_ BYTE *contextBuf - ); - - PVOID SetContext; - - HRESULT (STDMETHODCALLTYPE *Next)( - _In_ IXCLRDataStackWalk *This - ); - - HRESULT (STDMETHODCALLTYPE *GetStackSizeSkipped)( - _In_ IXCLRDataStackWalk *This, - _Out_ ULONG64 *stackSizeSkipped - ); - - HRESULT (STDMETHODCALLTYPE *GetFrameType)( - _In_ IXCLRDataStackWalk *This, - _Out_ CLRDataSimpleFrameType *simpleType, - _Out_ CLRDataDetailedFrameType *detailedType - ); - - HRESULT (STDMETHODCALLTYPE *GetFrame)( - _In_ IXCLRDataStackWalk *This, - _Out_ PVOID *frame - ); - - HRESULT (STDMETHODCALLTYPE *Request)( - _In_ IXCLRDataStackWalk *This, - _In_ ULONG32 reqCode, - _In_ ULONG32 inBufferSize, - _In_ BYTE *inBuffer, - _In_ ULONG32 outBufferSize, - _Out_ BYTE *outBuffer - ); - - HRESULT (STDMETHODCALLTYPE *SetContext2)( - _In_ IXCLRDataStackWalk *This, - _In_ ULONG32 flags, - _In_ ULONG32 contextSize, - _In_ BYTE *context - ); -} IXCLRDataStackWalkVtbl; - -typedef struct IXCLRDataStackWalk -{ - struct IXCLRDataStackWalkVtbl *lpVtbl; -} IXCLRDataStackWalk; - -#define IXCLRDataStackWalk_QueryInterface(This, riid, ppvObject) \ - ((This)->lpVtbl->QueryInterface(This, riid, ppvObject)) - -#define IXCLRDataStackWalk_AddRef(This) \ - ((This)->lpVtbl->AddRef(This)) - -#define IXCLRDataStackWalk_Release(This) \ - ((This)->lpVtbl->Release(This)) - -#define IXCLRDataStackWalk_GetContext(This, contextFlags, contextBufSize, contextSize, contextBuf) \ - ((This)->lpVtbl->GetContext(This, contextFlags, contextBufSize, contextSize, contextBuf)) - -#define IXCLRDataStackWalk_Next(This) \ - ((This)->lpVtbl->Next(This)) - -#define IXCLRDataStackWalk_GetStackSizeSkipped(This, stackSizeSkipped) \ - ((This)->lpVtbl->GetStackSizeSkipped(This, stackSizeSkipped)) - -#define IXCLRDataStackWalk_GetFrameType(This, simpleType, detailedType) \ - ((This)->lpVtbl->GetFrameType(This, simpleType, detailedType)) - -#define IXCLRDataStackWalk_GetFrame(This, frame) \ - ((This)->lpVtbl->GetFrame(This, frame)) - -#define IXCLRDataStackWalk_Request(This, reqCode, inBufferSize, inBuffer, outBufferSize, outBuffer) \ - ((This)->lpVtbl->SetContext2(This, reqCode, inBufferSize, inBuffer, outBufferSize, outBuffer)) - -#define IXCLRDataStackWalk_SetContext2(This, flags, contextSize, context) \ - ((This)->lpVtbl->SetContext2(This, flags, contextSize, context)) - -typedef struct IXCLRDataFrameVtbl -{ - HRESULT (STDMETHODCALLTYPE *QueryInterface)( - _In_ IXCLRDataFrame *This, - _In_ REFIID riid, - _Outptr_ void **ppvObject - ); - - ULONG (STDMETHODCALLTYPE *AddRef)( - _In_ IXCLRDataFrame *This - ); - - ULONG (STDMETHODCALLTYPE *Release)( - _In_ IXCLRDataFrame *This - ); - - HRESULT (STDMETHODCALLTYPE *GetFrameType)( - _In_ IXCLRDataFrame *This, - _Out_ CLRDataSimpleFrameType *simpleType, - _Out_ CLRDataDetailedFrameType *detailedType - ); - - HRESULT (STDMETHODCALLTYPE *GetContext)( - _In_ IXCLRDataFrame *This, - _In_ ULONG32 contextFlags, - _In_ ULONG32 contextBufSize, - _Out_ ULONG32 *contextSize, - _Out_ BYTE *contextBuf - ); - - PVOID GetAppDomain; - PVOID GetNumArguments; - PVOID GetArgumentByIndex; - PVOID GetNumLocalVariables; - PVOID GetLocalVariableByIndex; - - HRESULT (STDMETHODCALLTYPE *GetCodeName)( - _In_ IXCLRDataFrame *This, - _In_ ULONG32 *flags, - _In_ ULONG32 *bufLen, - _Out_ ULONG32 *nameLen, - _Out_ WCHAR *nameBuf - ); -} IXCLRDataFrameVtbl; - -typedef struct IXCLRDataFrame -{ - IXCLRDataFrameVtbl *lpVtbl; -} IXCLRDataFrame; - -#define IXCLRDataFrame_QueryInterface(This, riid, ppvObject) \ - ((This)->lpVtbl->QueryInterface(This, riid, ppvObject)) - -#define IXCLRDataFrame_AddRef(This) \ - ((This)->lpVtbl->AddRef(This)) - -#define IXCLRDataFrame_Release(This) \ - ((This)->lpVtbl->Release(This)) - -#define IXCLRDataFrame_GetFrameType(This, simpleType, detailedType) \ - ((This)->lpVtbl->GetFrameType(This, simpleType, detailedType)) - -#define IXCLRDataFrame_GetContext(This, contextFlags, contextBufSize, contextSize, contextBuf) \ - ((This)->lpVtbl->GetContext(This, contextFlags, contextBufSize, contextSize, contextBuf)) - -#define IXCLRDataFrame_GetCodeName(This, flags, bufLen, nameLen, nameBuf) \ - ((This)->lpVtbl->GetCodeName(This, flags, bufLen, nameLen, nameBuf)) - -// DnCLRDataTarget - -typedef struct -{ - ICLRDataTargetVtbl *VTable; - - ULONG RefCount; - - HANDLE ProcessId; - HANDLE ProcessHandle; - BOOLEAN IsWow64; -} DnCLRDataTarget; - -ICLRDataTarget *DnCLRDataTarget_Create( - _In_ HANDLE ProcessId - ); - -HRESULT STDMETHODCALLTYPE DnCLRDataTarget_QueryInterface( - _In_ ICLRDataTarget *This, - _In_ REFIID Riid, - _Out_ PVOID *Object - ); - -ULONG STDMETHODCALLTYPE DnCLRDataTarget_AddRef( - _In_ ICLRDataTarget *This - ); - -ULONG STDMETHODCALLTYPE DnCLRDataTarget_Release( - _In_ ICLRDataTarget *This - ); - -HRESULT STDMETHODCALLTYPE DnCLRDataTarget_GetMachineType( - _In_ ICLRDataTarget *This, - _Out_ ULONG32 *machineType - ); - -HRESULT STDMETHODCALLTYPE DnCLRDataTarget_GetPointerSize( - _In_ ICLRDataTarget *This, - _Out_ ULONG32 *pointerSize - ); - -HRESULT STDMETHODCALLTYPE DnCLRDataTarget_GetImageBase( - _In_ ICLRDataTarget *This, - _In_ LPCWSTR imagePath, - _Out_ CLRDATA_ADDRESS *baseAddress - ); - -HRESULT STDMETHODCALLTYPE DnCLRDataTarget_ReadVirtual( - _In_ ICLRDataTarget *This, - _In_ CLRDATA_ADDRESS address, - _Out_ BYTE *buffer, - _In_ ULONG32 bytesRequested, - _Out_ ULONG32 *bytesRead - ); - -HRESULT STDMETHODCALLTYPE DnCLRDataTarget_WriteVirtual( - _In_ ICLRDataTarget *This, - _In_ CLRDATA_ADDRESS address, - _In_ BYTE *buffer, - _In_ ULONG32 bytesRequested, - _Out_ ULONG32 *bytesWritten - ); - -HRESULT STDMETHODCALLTYPE DnCLRDataTarget_GetTLSValue( - _In_ ICLRDataTarget *This, - _In_ ULONG32 threadID, - _In_ ULONG32 index, - _Out_ CLRDATA_ADDRESS *value - ); - -HRESULT STDMETHODCALLTYPE DnCLRDataTarget_SetTLSValue( - _In_ ICLRDataTarget *This, - _In_ ULONG32 threadID, - _In_ ULONG32 index, - _In_ CLRDATA_ADDRESS value - ); - -HRESULT STDMETHODCALLTYPE DnCLRDataTarget_GetCurrentThreadID( - _In_ ICLRDataTarget *This, - _Out_ ULONG32 *threadID - ); - -HRESULT STDMETHODCALLTYPE DnCLRDataTarget_GetThreadContext( - _In_ ICLRDataTarget *This, - _In_ ULONG32 threadID, - _In_ ULONG32 contextFlags, - _In_ ULONG32 contextSize, - _Out_ BYTE *context - ); - -HRESULT STDMETHODCALLTYPE DnCLRDataTarget_SetThreadContext( - _In_ ICLRDataTarget *This, - _In_ ULONG32 threadID, - _In_ ULONG32 contextSize, - _In_ BYTE *context - ); - -HRESULT STDMETHODCALLTYPE DnCLRDataTarget_Request( - _In_ ICLRDataTarget *This, - _In_ ULONG32 reqCode, - _In_ ULONG32 inBufferSize, - _In_ BYTE *inBuffer, - _In_ ULONG32 outBufferSize, - _Out_ BYTE *outBuffer - ); - -typedef struct _PHP_GET_IMAGE_BASE_CONTEXT -{ - UNICODE_STRING ImagePath; - PVOID BaseAddress; -} PHP_GET_IMAGE_BASE_CONTEXT, *PPHP_GET_IMAGE_BASE_CONTEXT; - -#endif +/* + * Process Hacker .NET Tools - + * CLR data access functions + * + * Copyright (C) 2011-2015 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#ifndef CLRSUP_H +#define CLRSUP_H + +#define CINTERFACE +#define COBJMACROS +#include "clr/clrdata.h" +#undef CINTERFACE +#undef COBJMACROS + +// General interfaces + +typedef struct _CLR_PROCESS_SUPPORT +{ + struct IXCLRDataProcess *DataProcess; +} CLR_PROCESS_SUPPORT, *PCLR_PROCESS_SUPPORT; + +PCLR_PROCESS_SUPPORT CreateClrProcessSupport( + _In_ HANDLE ProcessId + ); + +VOID FreeClrProcessSupport( + _In_ PCLR_PROCESS_SUPPORT Support + ); + +PPH_STRING GetRuntimeNameByAddressClrProcess( + _In_ PCLR_PROCESS_SUPPORT Support, + _In_ ULONG64 Address, + _Out_opt_ PULONG64 Displacement + ); + +PPH_STRING GetNameXClrDataAppDomain( + _In_ PVOID AppDomain + ); + +PVOID LoadMscordacwks( + _In_ BOOLEAN IsClrV4 + ); + +HRESULT CreateXCLRDataProcess( + _In_ HANDLE ProcessId, + _In_ ICLRDataTarget *Target, + _Out_ struct IXCLRDataProcess **DataProcess + ); + +// xclrdata + +typedef ULONG64 CLRDATA_ENUM; + +typedef struct IXCLRDataProcess IXCLRDataProcess; +typedef struct IXCLRDataAppDomain IXCLRDataAppDomain; +typedef struct IXCLRDataTask IXCLRDataTask; +typedef struct IXCLRDataStackWalk IXCLRDataStackWalk; +typedef struct IXCLRDataFrame IXCLRDataFrame; + +typedef struct IXCLRDataProcessVtbl +{ + HRESULT (STDMETHODCALLTYPE *QueryInterface)( + _In_ IXCLRDataProcess *This, + _In_ REFIID riid, + _Outptr_ void **ppvObject + ); + + ULONG (STDMETHODCALLTYPE *AddRef)( + _In_ IXCLRDataProcess *This + ); + + ULONG (STDMETHODCALLTYPE *Release)( + _In_ IXCLRDataProcess *This + ); + + HRESULT (STDMETHODCALLTYPE *Flush)( + _In_ IXCLRDataProcess *This + ); + + HRESULT (STDMETHODCALLTYPE *StartEnumTasks)( + _In_ IXCLRDataProcess *This, + _Out_ CLRDATA_ENUM *handle + ); + + HRESULT (STDMETHODCALLTYPE *EnumTask)( + _In_ IXCLRDataProcess *This, + _Inout_ CLRDATA_ENUM *handle, + _Out_ IXCLRDataTask **task + ); + + HRESULT (STDMETHODCALLTYPE *EndEnumTasks)( + _In_ IXCLRDataProcess *This, + _In_ CLRDATA_ENUM handle + ); + + HRESULT (STDMETHODCALLTYPE *GetTaskByOSThreadID)( + _In_ IXCLRDataProcess *This, + _In_ ULONG32 osThreadID, + _Out_ IXCLRDataTask **task + ); + + PVOID GetTaskByUniqueID; + PVOID GetFlags; + PVOID IsSameObject; + PVOID GetManagedObject; + PVOID GetDesiredExecutionState; + PVOID SetDesiredExecutionState; + PVOID GetAddressType; + + HRESULT (STDMETHODCALLTYPE *GetRuntimeNameByAddress)( + _In_ IXCLRDataProcess *This, + _In_ CLRDATA_ADDRESS address, + _In_ ULONG32 flags, + _In_ ULONG32 bufLen, + _Out_ ULONG32 *nameLen, + _Out_ WCHAR *nameBuf, + _Out_ CLRDATA_ADDRESS *displacement + ); + + // ... +} IXCLRDataProcessVtbl; + +typedef struct IXCLRDataProcess +{ + struct IXCLRDataProcessVtbl *lpVtbl; +} IXCLRDataProcess; + +#define IXCLRDataProcess_QueryInterface(This, riid, ppvObject) \ + ((This)->lpVtbl->QueryInterface(This, riid, ppvObject)) + +#define IXCLRDataProcess_AddRef(This) \ + ((This)->lpVtbl->AddRef(This)) + +#define IXCLRDataProcess_Release(This) \ + ((This)->lpVtbl->Release(This)) + +#define IXCLRDataProcess_GetRuntimeNameByAddress(This, address, flags, bufLen, nameLen, nameBuf, displacement) \ + ((This)->lpVtbl->GetRuntimeNameByAddress(This, address, flags, bufLen, nameLen, nameBuf, displacement)) + +#define IXCLRDataProcess_Flush(This) \ + ((This)->lpVtbl->Flush(This)) + +#define IXCLRDataProcess_StartEnumTasks(This, handle) \ + ((This)->lpVtbl->StartEnumTasks(This, handle)) + +#define IXCLRDataProcess_EnumTask(This, handle, task) \ + ((This)->lpVtbl->EnumTask(This, handle, task)) + +#define IXCLRDataProcess_EndEnumTasks(This, handle) \ + ((This)->lpVtbl->EndEnumTasks(This, handle)) + +#define IXCLRDataProcess_GetTaskByOSThreadID(This, osThreadID, task) \ + ((This)->lpVtbl->GetTaskByOSThreadID(This, osThreadID, task)) + +typedef struct IXCLRDataAppDomainVtbl +{ + HRESULT (STDMETHODCALLTYPE *QueryInterface)( + _In_ IXCLRDataAppDomain *This, + _In_ REFIID riid, + _Outptr_ void **ppvObject + ); + + ULONG (STDMETHODCALLTYPE *AddRef)( + _In_ IXCLRDataAppDomain *This + ); + + ULONG (STDMETHODCALLTYPE *Release)( + _In_ IXCLRDataAppDomain *This + ); + + HRESULT (STDMETHODCALLTYPE *GetProcess)( + _In_ IXCLRDataAppDomain *This, + _Out_ IXCLRDataProcess **process + ); + + HRESULT (STDMETHODCALLTYPE *GetName)( + _In_ IXCLRDataAppDomain *This, + _In_ ULONG32 bufLen, + _Out_ ULONG32 *nameLen, + _Out_ WCHAR *name + ); + + HRESULT (STDMETHODCALLTYPE *GetUniqueID)( + _In_ IXCLRDataAppDomain *This, + _Out_ ULONG64 *id + ); + + // ... +} IXCLRDataAppDomainVtbl; + +typedef struct IXCLRDataAppDomain +{ + struct IXCLRDataAppDomainVtbl *lpVtbl; +} IXCLRDataAppDomain; + +#define IXCLRDataAppDomain_QueryInterface(This, riid, ppvObject) \ + ((This)->lpVtbl->QueryInterface(This, riid, ppvObject)) + +#define IXCLRDataAppDomain_AddRef(This) \ + ((This)->lpVtbl->AddRef(This)) + +#define IXCLRDataAppDomain_Release(This) \ + ((This)->lpVtbl->Release(This)) + +#define IXCLRDataAppDomain_GetProcess(This, process) \ + ((This)->lpVtbl->GetProcess(This, process)) + +#define IXCLRDataAppDomain_GetName(This, bufLen, nameLen, name) \ + ((This)->lpVtbl->GetName(This, bufLen, nameLen, name)) + +#define IXCLRDataAppDomain_GetUniqueID(This, id) \ + ((This)->lpVtbl->GetUniqueID(This, id)) + +typedef struct IXCLRDataTaskVtbl +{ + HRESULT (STDMETHODCALLTYPE *QueryInterface)( + _In_ IXCLRDataTask *This, + _In_ REFIID riid, + _Outptr_ void **ppvObject + ); + + ULONG (STDMETHODCALLTYPE *AddRef)( + _In_ IXCLRDataTask *This + ); + + ULONG (STDMETHODCALLTYPE *Release)( + _In_ IXCLRDataTask *This + ); + + HRESULT (STDMETHODCALLTYPE *GetProcess)( + _In_ IXCLRDataTask *This, + _Out_ IXCLRDataProcess **process + ); + + HRESULT (STDMETHODCALLTYPE *GetCurrentAppDomain)( + _In_ IXCLRDataTask *This, + _Out_ IXCLRDataAppDomain **appDomain + ); + + HRESULT (STDMETHODCALLTYPE *GetUniqueID)( + _In_ IXCLRDataTask *This, + _Out_ ULONG64 *id + ); + + HRESULT (STDMETHODCALLTYPE *GetFlags)( + _In_ IXCLRDataTask *This, + _Out_ ULONG32 *flags + ); + + PVOID IsSameObject; + PVOID GetManagedObject; + PVOID GetDesiredExecutionState; + PVOID SetDesiredExecutionState; + + HRESULT (STDMETHODCALLTYPE *CreateStackWalk)( + _In_ IXCLRDataTask *This, + _In_ ULONG32 flags, + _Out_ IXCLRDataStackWalk **stackWalk + ); + + HRESULT (STDMETHODCALLTYPE *GetOSThreadID)( + _In_ IXCLRDataTask *This, + _Out_ ULONG32 *id + ); + + PVOID GetContext; + PVOID SetContext; + PVOID GetCurrentExceptionState; + PVOID Request; + + HRESULT (STDMETHODCALLTYPE *GetName)( + _In_ IXCLRDataTask *This, + _In_ ULONG32 bufLen, + _Out_ ULONG32 *nameLen, + _Out_ WCHAR *name + ); + + PVOID GetLastExceptionState; +} IXCLRDataTaskVtbl; + +typedef struct IXCLRDataTask +{ + struct IXCLRDataTaskVtbl *lpVtbl; +} IXCLRDataTask; + +#define IXCLRDataTask_QueryInterface(This, riid, ppvObject) \ + ((This)->lpVtbl->QueryInterface(This, riid, ppvObject)) + +#define IXCLRDataTask_AddRef(This) \ + ((This)->lpVtbl->AddRef(This)) + +#define IXCLRDataTask_Release(This) \ + ((This)->lpVtbl->Release(This)) + +#define IXCLRDataTask_GetProcess(This, process) \ + ((This)->lpVtbl->GetProcess(This, process)) + +#define IXCLRDataTask_GetCurrentAppDomain(This, appDomain) \ + ((This)->lpVtbl->GetCurrentAppDomain(This, appDomain)) + +#define IXCLRDataTask_GetUniqueID(This, id) \ + ((This)->lpVtbl->GetUniqueID(This, id)) + +#define IXCLRDataTask_GetFlags(This, flags) \ + ((This)->lpVtbl->GetFlags(This, flags)) + +#define IXCLRDataTask_CreateStackWalk(This, flags, stackWalk) \ + ((This)->lpVtbl->CreateStackWalk(This, flags, stackWalk)) + +#define IXCLRDataTask_GetOSThreadID(This, id) \ + ((This)->lpVtbl->GetOSThreadID(This, id)) + +#define IXCLRDataTask_GetName(This, bufLen, nameLen, name) \ + ((This)->lpVtbl->GetName(This, bufLen, nameLen, name)) + +typedef enum +{ + CLRDATA_SIMPFRAME_UNRECOGNIZED = 0x1, + CLRDATA_SIMPFRAME_MANAGED_METHOD = 0x2, + CLRDATA_SIMPFRAME_RUNTIME_MANAGED_CODE = 0x4, + CLRDATA_SIMPFRAME_RUNTIME_UNMANAGED_CODE = 0x8 +} CLRDataSimpleFrameType; + +typedef enum +{ + CLRDATA_DETFRAME_UNRECOGNIZED, + CLRDATA_DETFRAME_UNKNOWN_STUB, + CLRDATA_DETFRAME_CLASS_INIT, + CLRDATA_DETFRAME_EXCEPTION_FILTER, + CLRDATA_DETFRAME_SECURITY, + CLRDATA_DETFRAME_CONTEXT_POLICY, + CLRDATA_DETFRAME_INTERCEPTION, + CLRDATA_DETFRAME_PROCESS_START, + CLRDATA_DETFRAME_THREAD_START, + CLRDATA_DETFRAME_TRANSITION_TO_MANAGED, + CLRDATA_DETFRAME_TRANSITION_TO_UNMANAGED, + CLRDATA_DETFRAME_COM_INTEROP_STUB, + CLRDATA_DETFRAME_DEBUGGER_EVAL, + CLRDATA_DETFRAME_CONTEXT_SWITCH, + CLRDATA_DETFRAME_FUNC_EVAL, + CLRDATA_DETFRAME_FINALLY +} CLRDataDetailedFrameType; + +typedef enum +{ + CLRDATA_STACK_SET_UNWIND_CONTEXT = 0x00000000, + CLRDATA_STACK_SET_CURRENT_CONTEXT = 0x00000001 +} CLRDataStackSetContextFlag; + +typedef struct IXCLRDataStackWalkVtbl +{ + HRESULT (STDMETHODCALLTYPE *QueryInterface)( + _In_ IXCLRDataStackWalk *This, + _In_ REFIID riid, + _Outptr_ void **ppvObject + ); + + ULONG (STDMETHODCALLTYPE *AddRef)( + _In_ IXCLRDataStackWalk *This + ); + + ULONG (STDMETHODCALLTYPE *Release)( + _In_ IXCLRDataStackWalk *This + ); + + HRESULT (STDMETHODCALLTYPE *GetContext)( + _In_ IXCLRDataStackWalk *This, + _In_ ULONG32 contextFlags, + _In_ ULONG32 contextBufSize, + _Out_ ULONG32 *contextSize, + _Out_ BYTE *contextBuf + ); + + PVOID SetContext; + + HRESULT (STDMETHODCALLTYPE *Next)( + _In_ IXCLRDataStackWalk *This + ); + + HRESULT (STDMETHODCALLTYPE *GetStackSizeSkipped)( + _In_ IXCLRDataStackWalk *This, + _Out_ ULONG64 *stackSizeSkipped + ); + + HRESULT (STDMETHODCALLTYPE *GetFrameType)( + _In_ IXCLRDataStackWalk *This, + _Out_ CLRDataSimpleFrameType *simpleType, + _Out_ CLRDataDetailedFrameType *detailedType + ); + + HRESULT (STDMETHODCALLTYPE *GetFrame)( + _In_ IXCLRDataStackWalk *This, + _Out_ PVOID *frame + ); + + HRESULT (STDMETHODCALLTYPE *Request)( + _In_ IXCLRDataStackWalk *This, + _In_ ULONG32 reqCode, + _In_ ULONG32 inBufferSize, + _In_ BYTE *inBuffer, + _In_ ULONG32 outBufferSize, + _Out_ BYTE *outBuffer + ); + + HRESULT (STDMETHODCALLTYPE *SetContext2)( + _In_ IXCLRDataStackWalk *This, + _In_ ULONG32 flags, + _In_ ULONG32 contextSize, + _In_ BYTE *context + ); +} IXCLRDataStackWalkVtbl; + +typedef struct IXCLRDataStackWalk +{ + struct IXCLRDataStackWalkVtbl *lpVtbl; +} IXCLRDataStackWalk; + +#define IXCLRDataStackWalk_QueryInterface(This, riid, ppvObject) \ + ((This)->lpVtbl->QueryInterface(This, riid, ppvObject)) + +#define IXCLRDataStackWalk_AddRef(This) \ + ((This)->lpVtbl->AddRef(This)) + +#define IXCLRDataStackWalk_Release(This) \ + ((This)->lpVtbl->Release(This)) + +#define IXCLRDataStackWalk_GetContext(This, contextFlags, contextBufSize, contextSize, contextBuf) \ + ((This)->lpVtbl->GetContext(This, contextFlags, contextBufSize, contextSize, contextBuf)) + +#define IXCLRDataStackWalk_Next(This) \ + ((This)->lpVtbl->Next(This)) + +#define IXCLRDataStackWalk_GetStackSizeSkipped(This, stackSizeSkipped) \ + ((This)->lpVtbl->GetStackSizeSkipped(This, stackSizeSkipped)) + +#define IXCLRDataStackWalk_GetFrameType(This, simpleType, detailedType) \ + ((This)->lpVtbl->GetFrameType(This, simpleType, detailedType)) + +#define IXCLRDataStackWalk_GetFrame(This, frame) \ + ((This)->lpVtbl->GetFrame(This, frame)) + +#define IXCLRDataStackWalk_Request(This, reqCode, inBufferSize, inBuffer, outBufferSize, outBuffer) \ + ((This)->lpVtbl->SetContext2(This, reqCode, inBufferSize, inBuffer, outBufferSize, outBuffer)) + +#define IXCLRDataStackWalk_SetContext2(This, flags, contextSize, context) \ + ((This)->lpVtbl->SetContext2(This, flags, contextSize, context)) + +typedef struct IXCLRDataFrameVtbl +{ + HRESULT (STDMETHODCALLTYPE *QueryInterface)( + _In_ IXCLRDataFrame *This, + _In_ REFIID riid, + _Outptr_ void **ppvObject + ); + + ULONG (STDMETHODCALLTYPE *AddRef)( + _In_ IXCLRDataFrame *This + ); + + ULONG (STDMETHODCALLTYPE *Release)( + _In_ IXCLRDataFrame *This + ); + + HRESULT (STDMETHODCALLTYPE *GetFrameType)( + _In_ IXCLRDataFrame *This, + _Out_ CLRDataSimpleFrameType *simpleType, + _Out_ CLRDataDetailedFrameType *detailedType + ); + + HRESULT (STDMETHODCALLTYPE *GetContext)( + _In_ IXCLRDataFrame *This, + _In_ ULONG32 contextFlags, + _In_ ULONG32 contextBufSize, + _Out_ ULONG32 *contextSize, + _Out_ BYTE *contextBuf + ); + + PVOID GetAppDomain; + PVOID GetNumArguments; + PVOID GetArgumentByIndex; + PVOID GetNumLocalVariables; + PVOID GetLocalVariableByIndex; + + HRESULT (STDMETHODCALLTYPE *GetCodeName)( + _In_ IXCLRDataFrame *This, + _In_ ULONG32 *flags, + _In_ ULONG32 *bufLen, + _Out_ ULONG32 *nameLen, + _Out_ WCHAR *nameBuf + ); +} IXCLRDataFrameVtbl; + +typedef struct IXCLRDataFrame +{ + IXCLRDataFrameVtbl *lpVtbl; +} IXCLRDataFrame; + +#define IXCLRDataFrame_QueryInterface(This, riid, ppvObject) \ + ((This)->lpVtbl->QueryInterface(This, riid, ppvObject)) + +#define IXCLRDataFrame_AddRef(This) \ + ((This)->lpVtbl->AddRef(This)) + +#define IXCLRDataFrame_Release(This) \ + ((This)->lpVtbl->Release(This)) + +#define IXCLRDataFrame_GetFrameType(This, simpleType, detailedType) \ + ((This)->lpVtbl->GetFrameType(This, simpleType, detailedType)) + +#define IXCLRDataFrame_GetContext(This, contextFlags, contextBufSize, contextSize, contextBuf) \ + ((This)->lpVtbl->GetContext(This, contextFlags, contextBufSize, contextSize, contextBuf)) + +#define IXCLRDataFrame_GetCodeName(This, flags, bufLen, nameLen, nameBuf) \ + ((This)->lpVtbl->GetCodeName(This, flags, bufLen, nameLen, nameBuf)) + +// DnCLRDataTarget + +typedef struct +{ + ICLRDataTargetVtbl *VTable; + + ULONG RefCount; + + HANDLE ProcessId; + HANDLE ProcessHandle; + BOOLEAN IsWow64; +} DnCLRDataTarget; + +ICLRDataTarget *DnCLRDataTarget_Create( + _In_ HANDLE ProcessId + ); + +HRESULT STDMETHODCALLTYPE DnCLRDataTarget_QueryInterface( + _In_ ICLRDataTarget *This, + _In_ REFIID Riid, + _Out_ PVOID *Object + ); + +ULONG STDMETHODCALLTYPE DnCLRDataTarget_AddRef( + _In_ ICLRDataTarget *This + ); + +ULONG STDMETHODCALLTYPE DnCLRDataTarget_Release( + _In_ ICLRDataTarget *This + ); + +HRESULT STDMETHODCALLTYPE DnCLRDataTarget_GetMachineType( + _In_ ICLRDataTarget *This, + _Out_ ULONG32 *machineType + ); + +HRESULT STDMETHODCALLTYPE DnCLRDataTarget_GetPointerSize( + _In_ ICLRDataTarget *This, + _Out_ ULONG32 *pointerSize + ); + +HRESULT STDMETHODCALLTYPE DnCLRDataTarget_GetImageBase( + _In_ ICLRDataTarget *This, + _In_ LPCWSTR imagePath, + _Out_ CLRDATA_ADDRESS *baseAddress + ); + +HRESULT STDMETHODCALLTYPE DnCLRDataTarget_ReadVirtual( + _In_ ICLRDataTarget *This, + _In_ CLRDATA_ADDRESS address, + _Out_ BYTE *buffer, + _In_ ULONG32 bytesRequested, + _Out_ ULONG32 *bytesRead + ); + +HRESULT STDMETHODCALLTYPE DnCLRDataTarget_WriteVirtual( + _In_ ICLRDataTarget *This, + _In_ CLRDATA_ADDRESS address, + _In_ BYTE *buffer, + _In_ ULONG32 bytesRequested, + _Out_ ULONG32 *bytesWritten + ); + +HRESULT STDMETHODCALLTYPE DnCLRDataTarget_GetTLSValue( + _In_ ICLRDataTarget *This, + _In_ ULONG32 threadID, + _In_ ULONG32 index, + _Out_ CLRDATA_ADDRESS *value + ); + +HRESULT STDMETHODCALLTYPE DnCLRDataTarget_SetTLSValue( + _In_ ICLRDataTarget *This, + _In_ ULONG32 threadID, + _In_ ULONG32 index, + _In_ CLRDATA_ADDRESS value + ); + +HRESULT STDMETHODCALLTYPE DnCLRDataTarget_GetCurrentThreadID( + _In_ ICLRDataTarget *This, + _Out_ ULONG32 *threadID + ); + +HRESULT STDMETHODCALLTYPE DnCLRDataTarget_GetThreadContext( + _In_ ICLRDataTarget *This, + _In_ ULONG32 threadID, + _In_ ULONG32 contextFlags, + _In_ ULONG32 contextSize, + _Out_ BYTE *context + ); + +HRESULT STDMETHODCALLTYPE DnCLRDataTarget_SetThreadContext( + _In_ ICLRDataTarget *This, + _In_ ULONG32 threadID, + _In_ ULONG32 contextSize, + _In_ BYTE *context + ); + +HRESULT STDMETHODCALLTYPE DnCLRDataTarget_Request( + _In_ ICLRDataTarget *This, + _In_ ULONG32 reqCode, + _In_ ULONG32 inBufferSize, + _In_ BYTE *inBuffer, + _In_ ULONG32 outBufferSize, + _Out_ BYTE *outBuffer + ); + +typedef struct _PHP_GET_IMAGE_BASE_CONTEXT +{ + UNICODE_STRING ImagePath; + PVOID BaseAddress; +} PHP_GET_IMAGE_BASE_CONTEXT, *PPHP_GET_IMAGE_BASE_CONTEXT; + +#endif diff --git a/plugins/DotNetTools/counters.c b/plugins/DotNetTools/counters.c index bce3983bf243..2092908c9e35 100644 --- a/plugins/DotNetTools/counters.c +++ b/plugins/DotNetTools/counters.c @@ -1,929 +1,929 @@ -/* - * Process Hacker .NET Tools - - * IPC support functions - * - * Copyright (C) 2015-2016 dmex - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include "dn.h" -#include "clr/dbgappdomain.h" -#include "clr/ipcheader.h" -#include "clr/ipcshared.h" - -PPH_STRING GeneratePrivateName(_In_ HANDLE ProcessId) -{ - return PhaFormatString(L"\\BaseNamedObjects\\" CorLegacyPrivateIPCBlock, HandleToUlong(ProcessId)); -} - -PPH_STRING GeneratePrivateNameV4(_In_ HANDLE ProcessId) -{ - return PhaFormatString(L"\\BaseNamedObjects\\" CorLegacyPrivateIPCBlockTempV4, HandleToUlong(ProcessId)); -} - -PPH_STRING GenerateLegacyPublicName(_In_ HANDLE ProcessId) -{ - return PhaFormatString(L"\\BaseNamedObjects\\" CorLegacyPublicIPCBlock, HandleToUlong(ProcessId)); -} - -PPH_STRING GenerateBoundaryDescriptorName(_In_ HANDLE ProcessId) -{ - return PhaFormatString(CorSxSBoundaryDescriptor, HandleToUlong(ProcessId)); -} - -PVOID GetLegacyBlockTableEntry( - _In_ BOOLEAN Wow64, - _In_ PVOID IpcBlockAddress, - _In_ ULONG EntryId - ) -{ - if (Wow64) - { - LegacyPrivateIPCControlBlock_Wow64* IpcBlock = IpcBlockAddress; - - // skip over directory (variable size) - ULONG offsetBase = IPC_ENTRY_OFFSET_BASE_X86 + IpcBlock->FullIPCHeader.Header.NumEntries * sizeof(IPCEntry); - // Directory has offset in bytes of block - ULONG offsetEntry = IpcBlock->FullIPCHeader.EntryTable[EntryId].Offset; - - return ((PBYTE)IpcBlock) + offsetBase + offsetEntry; - } - else - { - LegacyPrivateIPCControlBlock* IpcBlock = IpcBlockAddress; - - // skip over directory (variable size) - ULONG offsetBase = IPC_ENTRY_OFFSET_BASE_X64 + IpcBlock->FullIPCHeader.Header.NumEntries * sizeof(IPCEntry); - // Directory has offset in bytes of block - ULONG offsetEntry = IpcBlock->FullIPCHeader.EntryTable[EntryId].Offset; - - return ((PBYTE)IpcBlock) + offsetBase + offsetEntry; - } -} - -PVOID GetPerfIpcBlock_V2( - _In_ BOOLEAN Wow64, - _In_ PVOID BlockTableAddress - ) -{ - if (Wow64) - { - LegacyPublicIPCControlBlock_Wow64* ipcLegacyBlockTable_Wow64 = BlockTableAddress; - - if (ipcLegacyBlockTable_Wow64->FullIPCHeaderLegacyPublic.Header.Version > VER_LEGACYPUBLIC_IPC_BLOCK) - { - return NULL; - } - - return &ipcLegacyBlockTable_Wow64->PerfIpcBlock; - } - else - { - LegacyPublicIPCControlBlock* ipcLegacyBlockTable = BlockTableAddress; - - if (ipcLegacyBlockTable->FullIPCHeaderLegacyPublic.Header.Version > VER_IPC_BLOCK) - { - return NULL; - } - - return &ipcLegacyBlockTable->PerfIpcBlock; - } -} - -PVOID GetPerfIpcBlock_V4( - _In_ BOOLEAN Wow64, - _In_ PVOID BlockTableAddress - ) -{ - if (Wow64) - { - IPCControlBlockTable_Wow64* ipcBlockTable_Wow64 = BlockTableAddress; - - if (ipcBlockTable_Wow64->Blocks->Header.Version > VER_IPC_BLOCK) - { - return NULL; - } - - return &ipcBlockTable_Wow64->Blocks->PerfIpcBlock; - } - else - { - IPCControlBlockTable_Wow64* ipcBlockTable = BlockTableAddress; - - if (ipcBlockTable->Blocks->Header.Version > VER_IPC_BLOCK) - { - return NULL; - } - - return &ipcBlockTable->Blocks->PerfIpcBlock; - } -} - -PPH_LIST EnumerateAppDomainIpcBlock( - _In_ HANDLE ProcessHandle, - _In_ AppDomainEnumerationIPCBlock* AppDomainIpcBlock - ) -{ - LARGE_INTEGER timeout; - SIZE_T appDomainInfoBlockLength; - HANDLE legacyPrivateBlockMutexHandle = NULL; - AppDomainEnumerationIPCBlock tempBlock; - AppDomainInfo* appDomainInfoBlock = NULL; - PPH_LIST appDomainsList = PhCreateList(1); - - // If the mutex isn't filled in, the CLR is either starting up or shutting down - if (!AppDomainIpcBlock->Mutex) - { - goto CleanupExit; - } - - // Dup the valid mutex handle into this process. - if (!NT_SUCCESS(NtDuplicateObject( - ProcessHandle, - AppDomainIpcBlock->Mutex, - NtCurrentProcess(), - &legacyPrivateBlockMutexHandle, - GENERIC_ALL, - 0, - DUPLICATE_SAME_ACCESS | DUPLICATE_SAME_ATTRIBUTES - ))) - { - goto CleanupExit; - } - - // Acquire the mutex, only waiting two seconds. - // We can't actually gaurantee that the target put a mutex object in here. - if (NtWaitForSingleObject( - legacyPrivateBlockMutexHandle, - FALSE, - PhTimeoutFromMilliseconds(&timeout, 2000) - ) == STATUS_WAIT_0) - { - // Make sure the mutex handle is still valid. If its not, then we lost a shutdown race. - if (!AppDomainIpcBlock->Mutex) - { - goto CleanupExit; - } - } - else - { - // Again, landing here is most probably a shutdown race. - goto CleanupExit; - } - - // Beware: If the target pid is not properly honoring the mutex, the data in the IPC block may still shift underneath us. - // If we get here, then hMutex is held by this process. - - // Make a copy of the IPC block so that we can gaurantee that it's not changing on us. - memcpy(&tempBlock, AppDomainIpcBlock, sizeof(AppDomainEnumerationIPCBlock)); - - // It's possible the process will not have any appdomains. - if ((tempBlock.ListOfAppDomains == NULL) != (tempBlock.SizeInBytes == 0)) - { - goto CleanupExit; - } - - // All the data in the IPC block is signed integers. They should never be negative, - // so check that now. - if ((tempBlock.TotalSlots < 0) || - (tempBlock.NumOfUsedSlots < 0) || - (tempBlock.LastFreedSlot < 0) || - (tempBlock.SizeInBytes < 0) || - (tempBlock.ProcessNameLengthInBytes < 0)) - { - goto CleanupExit; - } - - // Allocate memory to read the remote process' memory into - appDomainInfoBlockLength = tempBlock.SizeInBytes; - - // Check other invariants. - if (appDomainInfoBlockLength != tempBlock.TotalSlots * sizeof(AppDomainInfo)) - { - goto CleanupExit; - } - - appDomainInfoBlock = (AppDomainInfo*)PhAllocate(appDomainInfoBlockLength); - memset(appDomainInfoBlock, 0, appDomainInfoBlockLength); - - if (!NT_SUCCESS(NtReadVirtualMemory( - ProcessHandle, - tempBlock.ListOfAppDomains, - appDomainInfoBlock, - appDomainInfoBlockLength, - NULL - ))) - { - PhFree(appDomainInfoBlock); - goto CleanupExit; - } - - // Collect all the AppDomain names into a list of strings. - for (INT i = 0; i < tempBlock.NumOfUsedSlots; i++) - { - SIZE_T appDomainNameLength; - PVOID appDomainName; - - if (!appDomainInfoBlock[i].AppDomainName) - continue; - - // Should be positive, and at least have a null-terminator character. - if (appDomainInfoBlock[i].NameLengthInBytes <= 1) - continue; - - // Make sure buffer has right geometry. - if (appDomainInfoBlock[i].NameLengthInBytes < 0) - continue; - - // If it's not on a WCHAR boundary, then we may have a 1-byte buffer-overflow. - appDomainNameLength = appDomainInfoBlock[i].NameLengthInBytes / sizeof(WCHAR); - - if ((appDomainNameLength * sizeof(WCHAR)) != appDomainInfoBlock[i].NameLengthInBytes) - continue; - - // It should at least have 1 char for the null terminator. - if (appDomainNameLength < 1) - continue; - - // We know the string is a well-formed null-terminated string, - // but beyond that, we can't verify that the data is actually truthful. - appDomainName = PhAllocate(appDomainInfoBlock[i].NameLengthInBytes + 1); - memset(appDomainName, 0, appDomainInfoBlock[i].NameLengthInBytes + 1); - - if (!NT_SUCCESS(NtReadVirtualMemory( - ProcessHandle, - appDomainInfoBlock[i].AppDomainName, - appDomainName, - appDomainInfoBlock[i].NameLengthInBytes, - NULL - ))) - { - PhFree(appDomainName); - continue; - } - - PhAddItemList(appDomainsList, appDomainName); - } - -CleanupExit: - if (appDomainInfoBlock) - { - PhFree(appDomainInfoBlock); - } - - if (legacyPrivateBlockMutexHandle) - { - NtReleaseMutant(legacyPrivateBlockMutexHandle, NULL); - NtClose(legacyPrivateBlockMutexHandle); - } - - return appDomainsList; -} - -PPH_LIST EnumerateAppDomainIpcBlockWow64( - _In_ HANDLE ProcessHandle, - _In_ AppDomainEnumerationIPCBlock_Wow64* AppDomainIpcBlock - ) -{ - LARGE_INTEGER timeout; - SIZE_T appDomainInfoBlockLength; - HANDLE legacyPrivateBlockMutexHandle = NULL; - AppDomainEnumerationIPCBlock_Wow64 tempBlock; - AppDomainInfo_Wow64* appDomainInfoBlock = NULL; - PPH_LIST appDomainsList = PhCreateList(1); - - // If the mutex isn't filled in, the CLR is either starting up or shutting down - if (!AppDomainIpcBlock->Mutex) - { - goto CleanupExit; - } - - // Dup the valid mutex handle into this process. - if (!NT_SUCCESS(NtDuplicateObject( - ProcessHandle, - UlongToHandle(AppDomainIpcBlock->Mutex), - NtCurrentProcess(), - &legacyPrivateBlockMutexHandle, - GENERIC_ALL, - 0, - DUPLICATE_SAME_ACCESS | DUPLICATE_SAME_ATTRIBUTES - ))) - { - goto CleanupExit; - } - - // Acquire the mutex, only waiting two seconds. - // We can't actually gaurantee that the target put a mutex object in here. - if (NtWaitForSingleObject( - legacyPrivateBlockMutexHandle, - FALSE, - PhTimeoutFromMilliseconds(&timeout, 2000) - ) == STATUS_WAIT_0) - { - // Make sure the mutex handle is still valid. If its not, then we lost a shutdown race. - if (!AppDomainIpcBlock->Mutex) - { - goto CleanupExit; - } - } - else - { - // Again, landing here is most probably a shutdown race. - goto CleanupExit; - } - - // Beware: If the target pid is not properly honoring the mutex, the data in the IPC block may still shift underneath us. - // If we get here, then hMutex is held by this process. - - // Make a copy of the IPC block so that we can gaurantee that it's not changing on us. - memcpy(&tempBlock, AppDomainIpcBlock, sizeof(AppDomainEnumerationIPCBlock_Wow64)); - - // It's possible the process will not have any appdomains. - if ((tempBlock.ListOfAppDomains == 0) != (tempBlock.SizeInBytes == 0)) - { - goto CleanupExit; - } - - // All the data in the IPC block is signed integers. They should never be negative, - // so check that now. - if ((tempBlock.TotalSlots < 0) || - (tempBlock.NumOfUsedSlots < 0) || - (tempBlock.LastFreedSlot < 0) || - (tempBlock.SizeInBytes < 0) || - (tempBlock.ProcessNameLengthInBytes < 0)) - { - goto CleanupExit; - } - - // Allocate memory to read the remote process' memory into - appDomainInfoBlockLength = tempBlock.SizeInBytes; - - // Check other invariants. - if (appDomainInfoBlockLength != tempBlock.TotalSlots * sizeof(AppDomainInfo_Wow64)) - { - goto CleanupExit; - } - - appDomainInfoBlock = (AppDomainInfo_Wow64*)PhAllocate(appDomainInfoBlockLength); - memset(appDomainInfoBlock, 0, appDomainInfoBlockLength); - - if (!NT_SUCCESS(NtReadVirtualMemory( - ProcessHandle, - UlongToPtr(tempBlock.ListOfAppDomains), - appDomainInfoBlock, - appDomainInfoBlockLength, - NULL - ))) - { - PhFree(appDomainInfoBlock); - goto CleanupExit; - } - - // Collect all the AppDomain names into a list of strings. - for (INT i = 0; i < tempBlock.NumOfUsedSlots; i++) - { - SIZE_T appDomainNameLength; - PVOID appDomainName; - - if (!appDomainInfoBlock[i].AppDomainName) - continue; - - // Should be positive, and at least have a null-terminator character. - if (appDomainInfoBlock[i].NameLengthInBytes <= 1) - continue; - - // Make sure buffer has right geometry. - if (appDomainInfoBlock[i].NameLengthInBytes < 0) - continue; - - // If it's not on a WCHAR boundary, then we may have a 1-byte buffer-overflow. - appDomainNameLength = appDomainInfoBlock[i].NameLengthInBytes / sizeof(WCHAR); - - if ((appDomainNameLength * sizeof(WCHAR)) != appDomainInfoBlock[i].NameLengthInBytes) - continue; - - // It should at least have 1 char for the null terminator. - if (appDomainNameLength < 1) - continue; - - // We know the string is a well-formed null-terminated string, - // but beyond that, we can't verify that the data is actually truthful. - appDomainName = PhAllocate(appDomainInfoBlock[i].NameLengthInBytes + 1); - memset(appDomainName, 0, appDomainInfoBlock[i].NameLengthInBytes + 1); - - if (!NT_SUCCESS(NtReadVirtualMemory( - ProcessHandle, - UlongToPtr(appDomainInfoBlock[i].AppDomainName), - appDomainName, - appDomainInfoBlock[i].NameLengthInBytes, - NULL - ))) - { - PhFree(appDomainName); - continue; - } - - PhAddItemList(appDomainsList, appDomainName); - } - -CleanupExit: - - if (appDomainInfoBlock) - { - PhFree(appDomainInfoBlock); - } - - if (legacyPrivateBlockMutexHandle) - { - NtReleaseMutant(legacyPrivateBlockMutexHandle, NULL); - NtClose(legacyPrivateBlockMutexHandle); - } - - return appDomainsList; -} - -BOOLEAN OpenDotNetPublicControlBlock_V2( - _In_ HANDLE ProcessId, - _Out_ HANDLE* BlockTableHandle, - _Out_ PVOID* BlockTableAddress - ) -{ - BOOLEAN result = FALSE; - HANDLE blockTableHandle = NULL; - PVOID blockTableAddress = NULL; - UNICODE_STRING sectionNameUs; - OBJECT_ATTRIBUTES objectAttributes; - LARGE_INTEGER sectionOffset = { 0 }; - SIZE_T viewSize = 0; - - if (!PhStringRefToUnicodeString(&GenerateLegacyPublicName(ProcessId)->sr, §ionNameUs)) - return FALSE; - - InitializeObjectAttributes( - &objectAttributes, - §ionNameUs, - 0, - NULL, - NULL - ); - - if (!NT_SUCCESS(NtOpenSection( - &blockTableHandle, - SECTION_MAP_READ, - &objectAttributes - ))) - { - return FALSE; - } - - if (NT_SUCCESS(NtMapViewOfSection( - blockTableHandle, - NtCurrentProcess(), - &blockTableAddress, - 0, - viewSize, - §ionOffset, - &viewSize, - ViewShare, - 0, - PAGE_READONLY - ))) - { - *BlockTableHandle = blockTableHandle; - *BlockTableAddress = blockTableAddress; - - return TRUE; - } - - if (blockTableHandle) - NtClose(blockTableHandle); - - if (blockTableAddress) - NtUnmapViewOfSection(NtCurrentProcess(), blockTableAddress); - - return FALSE; -} - -BOOLEAN OpenDotNetPublicControlBlock_V4( - _In_ BOOLEAN IsImmersive, - _In_ HANDLE ProcessHandle, - _In_ HANDLE ProcessId, - _Out_ HANDLE* BlockTableHandle, - _Out_ PVOID* BlockTableAddress - ) -{ - BOOLEAN result = FALSE; - PVOID boundaryDescriptorHandle = NULL; - HANDLE privateNamespaceHandle = NULL; - HANDLE blockTableHandle = NULL; - HANDLE tokenHandle = NULL; - PSID everyoneSIDHandle = NULL; - PVOID blockTableAddress = NULL; - LARGE_INTEGER sectionOffset = { 0 }; - SIZE_T viewSize = 0; - UNICODE_STRING prefixNameUs; - UNICODE_STRING sectionNameUs; - UNICODE_STRING boundaryNameUs; - OBJECT_ATTRIBUTES namespaceObjectAttributes; - OBJECT_ATTRIBUTES sectionObjectAttributes; - PTOKEN_APPCONTAINER_INFORMATION appContainerInfo = NULL; - SID_IDENTIFIER_AUTHORITY SIDWorldAuth = SECURITY_WORLD_SID_AUTHORITY; - - if (!PhStringRefToUnicodeString(&GenerateBoundaryDescriptorName(ProcessId)->sr, &boundaryNameUs)) - goto CleanupExit; - - if (!(boundaryDescriptorHandle = RtlCreateBoundaryDescriptor(&boundaryNameUs, 0))) - goto CleanupExit; - - if (!NT_SUCCESS(RtlAllocateAndInitializeSid(&SIDWorldAuth, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, &everyoneSIDHandle))) - goto CleanupExit; - - if (!NT_SUCCESS(RtlAddSIDToBoundaryDescriptor(&boundaryDescriptorHandle, everyoneSIDHandle))) - goto CleanupExit; - - if (WINDOWS_HAS_IMMERSIVE && IsImmersive) - { - if (NT_SUCCESS(NtOpenProcessToken(&tokenHandle, TOKEN_QUERY, ProcessHandle))) - { - ULONG returnLength = 0; - - if (NtQueryInformationToken( - tokenHandle, - TokenAppContainerSid, - NULL, - 0, - &returnLength - ) != STATUS_BUFFER_TOO_SMALL) - { - goto CleanupExit; - } - - appContainerInfo = PhAllocate(returnLength); - - if (!NT_SUCCESS(NtQueryInformationToken( - tokenHandle, - TokenAppContainerSid, - appContainerInfo, - returnLength, - &returnLength - ))) - { - goto CleanupExit; - } - - if (!NT_SUCCESS(RtlAddSIDToBoundaryDescriptor(&boundaryDescriptorHandle, appContainerInfo->TokenAppContainer))) - goto CleanupExit; - } - } - - RtlInitUnicodeString(&prefixNameUs, CorSxSReaderPrivateNamespacePrefix); - InitializeObjectAttributes( - &namespaceObjectAttributes, - &prefixNameUs, - OBJ_CASE_INSENSITIVE, - boundaryDescriptorHandle, - NULL - ); - - if (!NT_SUCCESS(NtOpenPrivateNamespace( - &privateNamespaceHandle, - MAXIMUM_ALLOWED, - &namespaceObjectAttributes, - boundaryDescriptorHandle - ))) - { - goto CleanupExit; - } - - RtlInitUnicodeString(§ionNameUs, CorSxSVistaPublicIPCBlock); - InitializeObjectAttributes( - §ionObjectAttributes, - §ionNameUs, - OBJ_CASE_INSENSITIVE, - privateNamespaceHandle, - NULL - ); - - if (!NT_SUCCESS(NtOpenSection( - &blockTableHandle, - SECTION_MAP_READ, - §ionObjectAttributes - ))) - { - goto CleanupExit; - } - - if (!NT_SUCCESS(NtMapViewOfSection( - blockTableHandle, - NtCurrentProcess(), - &blockTableAddress, - 0, - viewSize, - §ionOffset, - &viewSize, - ViewShare, - 0, - PAGE_READONLY - ))) - { - goto CleanupExit; - } - - *BlockTableHandle = blockTableHandle; - *BlockTableAddress = blockTableAddress; - - result = TRUE; - -CleanupExit: - - if (!result) - { - if (blockTableHandle) - { - NtClose(blockTableHandle); - } - - if (blockTableAddress) - { - NtUnmapViewOfSection(NtCurrentProcess(), blockTableAddress); - } - - *BlockTableHandle = NULL; - *BlockTableAddress = NULL; - } - - if (tokenHandle) - { - NtClose(tokenHandle); - } - - if (appContainerInfo) - { - PhFree(appContainerInfo); - } - - if (privateNamespaceHandle) - { - NtClose(privateNamespaceHandle); - } - - if (everyoneSIDHandle) - { - RtlFreeSid(everyoneSIDHandle); - } - - if (boundaryDescriptorHandle) - { - RtlDeleteBoundaryDescriptor(boundaryDescriptorHandle); - } - - return result; -} - -PPH_LIST QueryDotNetAppDomainsForPid_V2( - _In_ BOOLEAN Wow64, - _In_ HANDLE ProcessHandle, - _In_ HANDLE ProcessId - ) -{ - LARGE_INTEGER sectionOffset = { 0 }; - SIZE_T viewSize = 0; - OBJECT_ATTRIBUTES objectAttributes; - UNICODE_STRING sectionNameUs; - HANDLE legacyPrivateBlockHandle = NULL; - PVOID ipcControlBlockTable = NULL; - PPH_LIST appDomainsList = NULL; - - if (!PhStringRefToUnicodeString(&GeneratePrivateName(ProcessId)->sr, §ionNameUs)) - goto CleanupExit; - - InitializeObjectAttributes( - &objectAttributes, - §ionNameUs, - 0, - NULL, - NULL - ); - - if (!NT_SUCCESS(NtOpenSection( - &legacyPrivateBlockHandle, - SECTION_MAP_READ, - &objectAttributes - ))) - { - goto CleanupExit; - } - - if (!NT_SUCCESS(NtMapViewOfSection( - legacyPrivateBlockHandle, - NtCurrentProcess(), - &ipcControlBlockTable, - 0, - viewSize, - §ionOffset, - &viewSize, - ViewShare, - 0, - PAGE_READONLY - ))) - { - goto CleanupExit; - } - - if (Wow64) - { - LegacyPrivateIPCControlBlock_Wow64* legacyPrivateBlock; - AppDomainEnumerationIPCBlock_Wow64* appDomainEnumBlock; - - legacyPrivateBlock = (LegacyPrivateIPCControlBlock_Wow64*)ipcControlBlockTable; - - // NOTE: .NET 2.0 processes do not have the IPC_FLAG_INITIALIZED flag. - - // Check the IPCControlBlock version is valid. - if (legacyPrivateBlock->FullIPCHeader.Header.Version > VER_LEGACYPRIVATE_IPC_BLOCK) - { - goto CleanupExit; - } - - appDomainEnumBlock = GetLegacyBlockTableEntry( - Wow64, - ipcControlBlockTable, - eLegacyPrivateIPC_AppDomain - ); - - appDomainsList = EnumerateAppDomainIpcBlockWow64( - ProcessHandle, - appDomainEnumBlock - ); - } - else - { - LegacyPrivateIPCControlBlock* legacyPrivateBlock; - AppDomainEnumerationIPCBlock* appDomainEnumBlock; - - legacyPrivateBlock = (LegacyPrivateIPCControlBlock*)ipcControlBlockTable; - - // NOTE: .NET 2.0 processes do not have the IPC_FLAG_INITIALIZED flag. - - // Check the IPCControlBlock version is valid. - if (legacyPrivateBlock->FullIPCHeader.Header.Version > VER_LEGACYPRIVATE_IPC_BLOCK) - { - goto CleanupExit; - } - - appDomainEnumBlock = GetLegacyBlockTableEntry( - Wow64, - ipcControlBlockTable, - eLegacyPrivateIPC_AppDomain - ); - - appDomainsList = EnumerateAppDomainIpcBlock( - ProcessHandle, - appDomainEnumBlock - ); - } - -CleanupExit: - - if (ipcControlBlockTable) - { - NtUnmapViewOfSection(NtCurrentProcess(), ipcControlBlockTable); - } - - if (legacyPrivateBlockHandle) - { - NtClose(legacyPrivateBlockHandle); - } - - return appDomainsList; -} - -PPH_LIST QueryDotNetAppDomainsForPid_V4( - _In_ BOOLEAN Wow64, - _In_ HANDLE ProcessHandle, - _In_ HANDLE ProcessId - ) -{ - HANDLE legacyPrivateBlockHandle = NULL; - PVOID ipcControlBlockTable = NULL; - LARGE_INTEGER sectionOffset = { 0 }; - SIZE_T viewSize = 0; - OBJECT_ATTRIBUTES objectAttributes; - UNICODE_STRING sectionNameUs; - PPH_LIST appDomainsList = NULL; - - if (!PhStringRefToUnicodeString(&GeneratePrivateNameV4(ProcessId)->sr, §ionNameUs)) - goto CleanupExit; - - InitializeObjectAttributes( - &objectAttributes, - §ionNameUs, - 0, - NULL, - NULL - ); - - if (!NT_SUCCESS(NtOpenSection( - &legacyPrivateBlockHandle, - SECTION_MAP_READ, - &objectAttributes - ))) - { - goto CleanupExit; - } - - if (!NT_SUCCESS(NtMapViewOfSection( - legacyPrivateBlockHandle, - NtCurrentProcess(), - &ipcControlBlockTable, - 0, - viewSize, - §ionOffset, - &viewSize, - ViewShare, - 0, - PAGE_READONLY - ))) - { - goto CleanupExit; - } - - if (Wow64) - { - LegacyPrivateIPCControlBlock_Wow64* legacyPrivateBlock; - AppDomainEnumerationIPCBlock_Wow64* appDomainEnumBlock; - - legacyPrivateBlock = (LegacyPrivateIPCControlBlock_Wow64*)ipcControlBlockTable; - appDomainEnumBlock = &legacyPrivateBlock->AppDomainBlock; - - // Check the IPCControlBlock is initialized. - if ((legacyPrivateBlock->FullIPCHeader.Header.Flags & IPC_FLAG_INITIALIZED) != IPC_FLAG_INITIALIZED) - { - goto CleanupExit; - } - - // Check the IPCControlBlock version is valid. - if (legacyPrivateBlock->FullIPCHeader.Header.Version > VER_LEGACYPRIVATE_IPC_BLOCK) - { - goto CleanupExit; - } - - appDomainsList = EnumerateAppDomainIpcBlockWow64( - ProcessHandle, - appDomainEnumBlock - ); - } - else - { - LegacyPrivateIPCControlBlock* legacyPrivateBlock; - AppDomainEnumerationIPCBlock* appDomainEnumBlock; - - legacyPrivateBlock = (LegacyPrivateIPCControlBlock*)ipcControlBlockTable; - appDomainEnumBlock = &legacyPrivateBlock->AppDomainBlock; - - // Check the IPCControlBlock is initialized. - if ((legacyPrivateBlock->FullIPCHeader.Header.Flags & IPC_FLAG_INITIALIZED) != IPC_FLAG_INITIALIZED) - { - goto CleanupExit; - } - - // Check the IPCControlBlock version is valid. - if (legacyPrivateBlock->FullIPCHeader.Header.Version > VER_LEGACYPRIVATE_IPC_BLOCK) - { - goto CleanupExit; - } - - appDomainsList = EnumerateAppDomainIpcBlock( - ProcessHandle, - appDomainEnumBlock - ); - } - -CleanupExit: - - if (ipcControlBlockTable) - { - NtUnmapViewOfSection(NtCurrentProcess(), ipcControlBlockTable); - } - - if (legacyPrivateBlockHandle) - { - NtClose(legacyPrivateBlockHandle); - } - - return appDomainsList; -} +/* + * Process Hacker .NET Tools - + * IPC support functions + * + * Copyright (C) 2015-2016 dmex + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include "dn.h" +#include "clr/dbgappdomain.h" +#include "clr/ipcheader.h" +#include "clr/ipcshared.h" + +PPH_STRING GeneratePrivateName(_In_ HANDLE ProcessId) +{ + return PhaFormatString(L"\\BaseNamedObjects\\" CorLegacyPrivateIPCBlock, HandleToUlong(ProcessId)); +} + +PPH_STRING GeneratePrivateNameV4(_In_ HANDLE ProcessId) +{ + return PhaFormatString(L"\\BaseNamedObjects\\" CorLegacyPrivateIPCBlockTempV4, HandleToUlong(ProcessId)); +} + +PPH_STRING GenerateLegacyPublicName(_In_ HANDLE ProcessId) +{ + return PhaFormatString(L"\\BaseNamedObjects\\" CorLegacyPublicIPCBlock, HandleToUlong(ProcessId)); +} + +PPH_STRING GenerateBoundaryDescriptorName(_In_ HANDLE ProcessId) +{ + return PhaFormatString(CorSxSBoundaryDescriptor, HandleToUlong(ProcessId)); +} + +PVOID GetLegacyBlockTableEntry( + _In_ BOOLEAN Wow64, + _In_ PVOID IpcBlockAddress, + _In_ ULONG EntryId + ) +{ + if (Wow64) + { + LegacyPrivateIPCControlBlock_Wow64* IpcBlock = IpcBlockAddress; + + // skip over directory (variable size) + ULONG offsetBase = IPC_ENTRY_OFFSET_BASE_X86 + IpcBlock->FullIPCHeader.Header.NumEntries * sizeof(IPCEntry); + // Directory has offset in bytes of block + ULONG offsetEntry = IpcBlock->FullIPCHeader.EntryTable[EntryId].Offset; + + return ((PBYTE)IpcBlock) + offsetBase + offsetEntry; + } + else + { + LegacyPrivateIPCControlBlock* IpcBlock = IpcBlockAddress; + + // skip over directory (variable size) + ULONG offsetBase = IPC_ENTRY_OFFSET_BASE_X64 + IpcBlock->FullIPCHeader.Header.NumEntries * sizeof(IPCEntry); + // Directory has offset in bytes of block + ULONG offsetEntry = IpcBlock->FullIPCHeader.EntryTable[EntryId].Offset; + + return ((PBYTE)IpcBlock) + offsetBase + offsetEntry; + } +} + +PVOID GetPerfIpcBlock_V2( + _In_ BOOLEAN Wow64, + _In_ PVOID BlockTableAddress + ) +{ + if (Wow64) + { + LegacyPublicIPCControlBlock_Wow64* ipcLegacyBlockTable_Wow64 = BlockTableAddress; + + if (ipcLegacyBlockTable_Wow64->FullIPCHeaderLegacyPublic.Header.Version > VER_LEGACYPUBLIC_IPC_BLOCK) + { + return NULL; + } + + return &ipcLegacyBlockTable_Wow64->PerfIpcBlock; + } + else + { + LegacyPublicIPCControlBlock* ipcLegacyBlockTable = BlockTableAddress; + + if (ipcLegacyBlockTable->FullIPCHeaderLegacyPublic.Header.Version > VER_IPC_BLOCK) + { + return NULL; + } + + return &ipcLegacyBlockTable->PerfIpcBlock; + } +} + +PVOID GetPerfIpcBlock_V4( + _In_ BOOLEAN Wow64, + _In_ PVOID BlockTableAddress + ) +{ + if (Wow64) + { + IPCControlBlockTable_Wow64* ipcBlockTable_Wow64 = BlockTableAddress; + + if (ipcBlockTable_Wow64->Blocks->Header.Version > VER_IPC_BLOCK) + { + return NULL; + } + + return &ipcBlockTable_Wow64->Blocks->PerfIpcBlock; + } + else + { + IPCControlBlockTable_Wow64* ipcBlockTable = BlockTableAddress; + + if (ipcBlockTable->Blocks->Header.Version > VER_IPC_BLOCK) + { + return NULL; + } + + return &ipcBlockTable->Blocks->PerfIpcBlock; + } +} + +PPH_LIST EnumerateAppDomainIpcBlock( + _In_ HANDLE ProcessHandle, + _In_ AppDomainEnumerationIPCBlock* AppDomainIpcBlock + ) +{ + LARGE_INTEGER timeout; + SIZE_T appDomainInfoBlockLength; + HANDLE legacyPrivateBlockMutexHandle = NULL; + AppDomainEnumerationIPCBlock tempBlock; + AppDomainInfo* appDomainInfoBlock = NULL; + PPH_LIST appDomainsList = PhCreateList(1); + + // If the mutex isn't filled in, the CLR is either starting up or shutting down + if (!AppDomainIpcBlock->Mutex) + { + goto CleanupExit; + } + + // Dup the valid mutex handle into this process. + if (!NT_SUCCESS(NtDuplicateObject( + ProcessHandle, + AppDomainIpcBlock->Mutex, + NtCurrentProcess(), + &legacyPrivateBlockMutexHandle, + GENERIC_ALL, + 0, + DUPLICATE_SAME_ACCESS | DUPLICATE_SAME_ATTRIBUTES + ))) + { + goto CleanupExit; + } + + // Acquire the mutex, only waiting two seconds. + // We can't actually gaurantee that the target put a mutex object in here. + if (NtWaitForSingleObject( + legacyPrivateBlockMutexHandle, + FALSE, + PhTimeoutFromMilliseconds(&timeout, 2000) + ) == STATUS_WAIT_0) + { + // Make sure the mutex handle is still valid. If its not, then we lost a shutdown race. + if (!AppDomainIpcBlock->Mutex) + { + goto CleanupExit; + } + } + else + { + // Again, landing here is most probably a shutdown race. + goto CleanupExit; + } + + // Beware: If the target pid is not properly honoring the mutex, the data in the IPC block may still shift underneath us. + // If we get here, then hMutex is held by this process. + + // Make a copy of the IPC block so that we can gaurantee that it's not changing on us. + memcpy(&tempBlock, AppDomainIpcBlock, sizeof(AppDomainEnumerationIPCBlock)); + + // It's possible the process will not have any appdomains. + if ((tempBlock.ListOfAppDomains == NULL) != (tempBlock.SizeInBytes == 0)) + { + goto CleanupExit; + } + + // All the data in the IPC block is signed integers. They should never be negative, + // so check that now. + if ((tempBlock.TotalSlots < 0) || + (tempBlock.NumOfUsedSlots < 0) || + (tempBlock.LastFreedSlot < 0) || + (tempBlock.SizeInBytes < 0) || + (tempBlock.ProcessNameLengthInBytes < 0)) + { + goto CleanupExit; + } + + // Allocate memory to read the remote process' memory into + appDomainInfoBlockLength = tempBlock.SizeInBytes; + + // Check other invariants. + if (appDomainInfoBlockLength != tempBlock.TotalSlots * sizeof(AppDomainInfo)) + { + goto CleanupExit; + } + + appDomainInfoBlock = (AppDomainInfo*)PhAllocate(appDomainInfoBlockLength); + memset(appDomainInfoBlock, 0, appDomainInfoBlockLength); + + if (!NT_SUCCESS(NtReadVirtualMemory( + ProcessHandle, + tempBlock.ListOfAppDomains, + appDomainInfoBlock, + appDomainInfoBlockLength, + NULL + ))) + { + PhFree(appDomainInfoBlock); + goto CleanupExit; + } + + // Collect all the AppDomain names into a list of strings. + for (INT i = 0; i < tempBlock.NumOfUsedSlots; i++) + { + SIZE_T appDomainNameLength; + PVOID appDomainName; + + if (!appDomainInfoBlock[i].AppDomainName) + continue; + + // Should be positive, and at least have a null-terminator character. + if (appDomainInfoBlock[i].NameLengthInBytes <= 1) + continue; + + // Make sure buffer has right geometry. + if (appDomainInfoBlock[i].NameLengthInBytes < 0) + continue; + + // If it's not on a WCHAR boundary, then we may have a 1-byte buffer-overflow. + appDomainNameLength = appDomainInfoBlock[i].NameLengthInBytes / sizeof(WCHAR); + + if ((appDomainNameLength * sizeof(WCHAR)) != appDomainInfoBlock[i].NameLengthInBytes) + continue; + + // It should at least have 1 char for the null terminator. + if (appDomainNameLength < 1) + continue; + + // We know the string is a well-formed null-terminated string, + // but beyond that, we can't verify that the data is actually truthful. + appDomainName = PhAllocate(appDomainInfoBlock[i].NameLengthInBytes + 1); + memset(appDomainName, 0, appDomainInfoBlock[i].NameLengthInBytes + 1); + + if (!NT_SUCCESS(NtReadVirtualMemory( + ProcessHandle, + appDomainInfoBlock[i].AppDomainName, + appDomainName, + appDomainInfoBlock[i].NameLengthInBytes, + NULL + ))) + { + PhFree(appDomainName); + continue; + } + + PhAddItemList(appDomainsList, appDomainName); + } + +CleanupExit: + if (appDomainInfoBlock) + { + PhFree(appDomainInfoBlock); + } + + if (legacyPrivateBlockMutexHandle) + { + NtReleaseMutant(legacyPrivateBlockMutexHandle, NULL); + NtClose(legacyPrivateBlockMutexHandle); + } + + return appDomainsList; +} + +PPH_LIST EnumerateAppDomainIpcBlockWow64( + _In_ HANDLE ProcessHandle, + _In_ AppDomainEnumerationIPCBlock_Wow64* AppDomainIpcBlock + ) +{ + LARGE_INTEGER timeout; + SIZE_T appDomainInfoBlockLength; + HANDLE legacyPrivateBlockMutexHandle = NULL; + AppDomainEnumerationIPCBlock_Wow64 tempBlock; + AppDomainInfo_Wow64* appDomainInfoBlock = NULL; + PPH_LIST appDomainsList = PhCreateList(1); + + // If the mutex isn't filled in, the CLR is either starting up or shutting down + if (!AppDomainIpcBlock->Mutex) + { + goto CleanupExit; + } + + // Dup the valid mutex handle into this process. + if (!NT_SUCCESS(NtDuplicateObject( + ProcessHandle, + UlongToHandle(AppDomainIpcBlock->Mutex), + NtCurrentProcess(), + &legacyPrivateBlockMutexHandle, + GENERIC_ALL, + 0, + DUPLICATE_SAME_ACCESS | DUPLICATE_SAME_ATTRIBUTES + ))) + { + goto CleanupExit; + } + + // Acquire the mutex, only waiting two seconds. + // We can't actually gaurantee that the target put a mutex object in here. + if (NtWaitForSingleObject( + legacyPrivateBlockMutexHandle, + FALSE, + PhTimeoutFromMilliseconds(&timeout, 2000) + ) == STATUS_WAIT_0) + { + // Make sure the mutex handle is still valid. If its not, then we lost a shutdown race. + if (!AppDomainIpcBlock->Mutex) + { + goto CleanupExit; + } + } + else + { + // Again, landing here is most probably a shutdown race. + goto CleanupExit; + } + + // Beware: If the target pid is not properly honoring the mutex, the data in the IPC block may still shift underneath us. + // If we get here, then hMutex is held by this process. + + // Make a copy of the IPC block so that we can gaurantee that it's not changing on us. + memcpy(&tempBlock, AppDomainIpcBlock, sizeof(AppDomainEnumerationIPCBlock_Wow64)); + + // It's possible the process will not have any appdomains. + if ((tempBlock.ListOfAppDomains == 0) != (tempBlock.SizeInBytes == 0)) + { + goto CleanupExit; + } + + // All the data in the IPC block is signed integers. They should never be negative, + // so check that now. + if ((tempBlock.TotalSlots < 0) || + (tempBlock.NumOfUsedSlots < 0) || + (tempBlock.LastFreedSlot < 0) || + (tempBlock.SizeInBytes < 0) || + (tempBlock.ProcessNameLengthInBytes < 0)) + { + goto CleanupExit; + } + + // Allocate memory to read the remote process' memory into + appDomainInfoBlockLength = tempBlock.SizeInBytes; + + // Check other invariants. + if (appDomainInfoBlockLength != tempBlock.TotalSlots * sizeof(AppDomainInfo_Wow64)) + { + goto CleanupExit; + } + + appDomainInfoBlock = (AppDomainInfo_Wow64*)PhAllocate(appDomainInfoBlockLength); + memset(appDomainInfoBlock, 0, appDomainInfoBlockLength); + + if (!NT_SUCCESS(NtReadVirtualMemory( + ProcessHandle, + UlongToPtr(tempBlock.ListOfAppDomains), + appDomainInfoBlock, + appDomainInfoBlockLength, + NULL + ))) + { + PhFree(appDomainInfoBlock); + goto CleanupExit; + } + + // Collect all the AppDomain names into a list of strings. + for (INT i = 0; i < tempBlock.NumOfUsedSlots; i++) + { + SIZE_T appDomainNameLength; + PVOID appDomainName; + + if (!appDomainInfoBlock[i].AppDomainName) + continue; + + // Should be positive, and at least have a null-terminator character. + if (appDomainInfoBlock[i].NameLengthInBytes <= 1) + continue; + + // Make sure buffer has right geometry. + if (appDomainInfoBlock[i].NameLengthInBytes < 0) + continue; + + // If it's not on a WCHAR boundary, then we may have a 1-byte buffer-overflow. + appDomainNameLength = appDomainInfoBlock[i].NameLengthInBytes / sizeof(WCHAR); + + if ((appDomainNameLength * sizeof(WCHAR)) != appDomainInfoBlock[i].NameLengthInBytes) + continue; + + // It should at least have 1 char for the null terminator. + if (appDomainNameLength < 1) + continue; + + // We know the string is a well-formed null-terminated string, + // but beyond that, we can't verify that the data is actually truthful. + appDomainName = PhAllocate(appDomainInfoBlock[i].NameLengthInBytes + 1); + memset(appDomainName, 0, appDomainInfoBlock[i].NameLengthInBytes + 1); + + if (!NT_SUCCESS(NtReadVirtualMemory( + ProcessHandle, + UlongToPtr(appDomainInfoBlock[i].AppDomainName), + appDomainName, + appDomainInfoBlock[i].NameLengthInBytes, + NULL + ))) + { + PhFree(appDomainName); + continue; + } + + PhAddItemList(appDomainsList, appDomainName); + } + +CleanupExit: + + if (appDomainInfoBlock) + { + PhFree(appDomainInfoBlock); + } + + if (legacyPrivateBlockMutexHandle) + { + NtReleaseMutant(legacyPrivateBlockMutexHandle, NULL); + NtClose(legacyPrivateBlockMutexHandle); + } + + return appDomainsList; +} + +BOOLEAN OpenDotNetPublicControlBlock_V2( + _In_ HANDLE ProcessId, + _Out_ HANDLE* BlockTableHandle, + _Out_ PVOID* BlockTableAddress + ) +{ + BOOLEAN result = FALSE; + HANDLE blockTableHandle = NULL; + PVOID blockTableAddress = NULL; + UNICODE_STRING sectionNameUs; + OBJECT_ATTRIBUTES objectAttributes; + LARGE_INTEGER sectionOffset = { 0 }; + SIZE_T viewSize = 0; + + if (!PhStringRefToUnicodeString(&GenerateLegacyPublicName(ProcessId)->sr, §ionNameUs)) + return FALSE; + + InitializeObjectAttributes( + &objectAttributes, + §ionNameUs, + 0, + NULL, + NULL + ); + + if (!NT_SUCCESS(NtOpenSection( + &blockTableHandle, + SECTION_MAP_READ, + &objectAttributes + ))) + { + return FALSE; + } + + if (NT_SUCCESS(NtMapViewOfSection( + blockTableHandle, + NtCurrentProcess(), + &blockTableAddress, + 0, + viewSize, + §ionOffset, + &viewSize, + ViewShare, + 0, + PAGE_READONLY + ))) + { + *BlockTableHandle = blockTableHandle; + *BlockTableAddress = blockTableAddress; + + return TRUE; + } + + if (blockTableHandle) + NtClose(blockTableHandle); + + if (blockTableAddress) + NtUnmapViewOfSection(NtCurrentProcess(), blockTableAddress); + + return FALSE; +} + +BOOLEAN OpenDotNetPublicControlBlock_V4( + _In_ BOOLEAN IsImmersive, + _In_ HANDLE ProcessHandle, + _In_ HANDLE ProcessId, + _Out_ HANDLE* BlockTableHandle, + _Out_ PVOID* BlockTableAddress + ) +{ + BOOLEAN result = FALSE; + PVOID boundaryDescriptorHandle = NULL; + HANDLE privateNamespaceHandle = NULL; + HANDLE blockTableHandle = NULL; + HANDLE tokenHandle = NULL; + PSID everyoneSIDHandle = NULL; + PVOID blockTableAddress = NULL; + LARGE_INTEGER sectionOffset = { 0 }; + SIZE_T viewSize = 0; + UNICODE_STRING prefixNameUs; + UNICODE_STRING sectionNameUs; + UNICODE_STRING boundaryNameUs; + OBJECT_ATTRIBUTES namespaceObjectAttributes; + OBJECT_ATTRIBUTES sectionObjectAttributes; + PTOKEN_APPCONTAINER_INFORMATION appContainerInfo = NULL; + SID_IDENTIFIER_AUTHORITY SIDWorldAuth = SECURITY_WORLD_SID_AUTHORITY; + + if (!PhStringRefToUnicodeString(&GenerateBoundaryDescriptorName(ProcessId)->sr, &boundaryNameUs)) + goto CleanupExit; + + if (!(boundaryDescriptorHandle = RtlCreateBoundaryDescriptor(&boundaryNameUs, 0))) + goto CleanupExit; + + if (!NT_SUCCESS(RtlAllocateAndInitializeSid(&SIDWorldAuth, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, &everyoneSIDHandle))) + goto CleanupExit; + + if (!NT_SUCCESS(RtlAddSIDToBoundaryDescriptor(&boundaryDescriptorHandle, everyoneSIDHandle))) + goto CleanupExit; + + if (WINDOWS_HAS_IMMERSIVE && IsImmersive) + { + if (NT_SUCCESS(NtOpenProcessToken(&tokenHandle, TOKEN_QUERY, ProcessHandle))) + { + ULONG returnLength = 0; + + if (NtQueryInformationToken( + tokenHandle, + TokenAppContainerSid, + NULL, + 0, + &returnLength + ) != STATUS_BUFFER_TOO_SMALL) + { + goto CleanupExit; + } + + appContainerInfo = PhAllocate(returnLength); + + if (!NT_SUCCESS(NtQueryInformationToken( + tokenHandle, + TokenAppContainerSid, + appContainerInfo, + returnLength, + &returnLength + ))) + { + goto CleanupExit; + } + + if (!NT_SUCCESS(RtlAddSIDToBoundaryDescriptor(&boundaryDescriptorHandle, appContainerInfo->TokenAppContainer))) + goto CleanupExit; + } + } + + RtlInitUnicodeString(&prefixNameUs, CorSxSReaderPrivateNamespacePrefix); + InitializeObjectAttributes( + &namespaceObjectAttributes, + &prefixNameUs, + OBJ_CASE_INSENSITIVE, + boundaryDescriptorHandle, + NULL + ); + + if (!NT_SUCCESS(NtOpenPrivateNamespace( + &privateNamespaceHandle, + MAXIMUM_ALLOWED, + &namespaceObjectAttributes, + boundaryDescriptorHandle + ))) + { + goto CleanupExit; + } + + RtlInitUnicodeString(§ionNameUs, CorSxSVistaPublicIPCBlock); + InitializeObjectAttributes( + §ionObjectAttributes, + §ionNameUs, + OBJ_CASE_INSENSITIVE, + privateNamespaceHandle, + NULL + ); + + if (!NT_SUCCESS(NtOpenSection( + &blockTableHandle, + SECTION_MAP_READ, + §ionObjectAttributes + ))) + { + goto CleanupExit; + } + + if (!NT_SUCCESS(NtMapViewOfSection( + blockTableHandle, + NtCurrentProcess(), + &blockTableAddress, + 0, + viewSize, + §ionOffset, + &viewSize, + ViewShare, + 0, + PAGE_READONLY + ))) + { + goto CleanupExit; + } + + *BlockTableHandle = blockTableHandle; + *BlockTableAddress = blockTableAddress; + + result = TRUE; + +CleanupExit: + + if (!result) + { + if (blockTableHandle) + { + NtClose(blockTableHandle); + } + + if (blockTableAddress) + { + NtUnmapViewOfSection(NtCurrentProcess(), blockTableAddress); + } + + *BlockTableHandle = NULL; + *BlockTableAddress = NULL; + } + + if (tokenHandle) + { + NtClose(tokenHandle); + } + + if (appContainerInfo) + { + PhFree(appContainerInfo); + } + + if (privateNamespaceHandle) + { + NtClose(privateNamespaceHandle); + } + + if (everyoneSIDHandle) + { + RtlFreeSid(everyoneSIDHandle); + } + + if (boundaryDescriptorHandle) + { + RtlDeleteBoundaryDescriptor(boundaryDescriptorHandle); + } + + return result; +} + +PPH_LIST QueryDotNetAppDomainsForPid_V2( + _In_ BOOLEAN Wow64, + _In_ HANDLE ProcessHandle, + _In_ HANDLE ProcessId + ) +{ + LARGE_INTEGER sectionOffset = { 0 }; + SIZE_T viewSize = 0; + OBJECT_ATTRIBUTES objectAttributes; + UNICODE_STRING sectionNameUs; + HANDLE legacyPrivateBlockHandle = NULL; + PVOID ipcControlBlockTable = NULL; + PPH_LIST appDomainsList = NULL; + + if (!PhStringRefToUnicodeString(&GeneratePrivateName(ProcessId)->sr, §ionNameUs)) + goto CleanupExit; + + InitializeObjectAttributes( + &objectAttributes, + §ionNameUs, + 0, + NULL, + NULL + ); + + if (!NT_SUCCESS(NtOpenSection( + &legacyPrivateBlockHandle, + SECTION_MAP_READ, + &objectAttributes + ))) + { + goto CleanupExit; + } + + if (!NT_SUCCESS(NtMapViewOfSection( + legacyPrivateBlockHandle, + NtCurrentProcess(), + &ipcControlBlockTable, + 0, + viewSize, + §ionOffset, + &viewSize, + ViewShare, + 0, + PAGE_READONLY + ))) + { + goto CleanupExit; + } + + if (Wow64) + { + LegacyPrivateIPCControlBlock_Wow64* legacyPrivateBlock; + AppDomainEnumerationIPCBlock_Wow64* appDomainEnumBlock; + + legacyPrivateBlock = (LegacyPrivateIPCControlBlock_Wow64*)ipcControlBlockTable; + + // NOTE: .NET 2.0 processes do not have the IPC_FLAG_INITIALIZED flag. + + // Check the IPCControlBlock version is valid. + if (legacyPrivateBlock->FullIPCHeader.Header.Version > VER_LEGACYPRIVATE_IPC_BLOCK) + { + goto CleanupExit; + } + + appDomainEnumBlock = GetLegacyBlockTableEntry( + Wow64, + ipcControlBlockTable, + eLegacyPrivateIPC_AppDomain + ); + + appDomainsList = EnumerateAppDomainIpcBlockWow64( + ProcessHandle, + appDomainEnumBlock + ); + } + else + { + LegacyPrivateIPCControlBlock* legacyPrivateBlock; + AppDomainEnumerationIPCBlock* appDomainEnumBlock; + + legacyPrivateBlock = (LegacyPrivateIPCControlBlock*)ipcControlBlockTable; + + // NOTE: .NET 2.0 processes do not have the IPC_FLAG_INITIALIZED flag. + + // Check the IPCControlBlock version is valid. + if (legacyPrivateBlock->FullIPCHeader.Header.Version > VER_LEGACYPRIVATE_IPC_BLOCK) + { + goto CleanupExit; + } + + appDomainEnumBlock = GetLegacyBlockTableEntry( + Wow64, + ipcControlBlockTable, + eLegacyPrivateIPC_AppDomain + ); + + appDomainsList = EnumerateAppDomainIpcBlock( + ProcessHandle, + appDomainEnumBlock + ); + } + +CleanupExit: + + if (ipcControlBlockTable) + { + NtUnmapViewOfSection(NtCurrentProcess(), ipcControlBlockTable); + } + + if (legacyPrivateBlockHandle) + { + NtClose(legacyPrivateBlockHandle); + } + + return appDomainsList; +} + +PPH_LIST QueryDotNetAppDomainsForPid_V4( + _In_ BOOLEAN Wow64, + _In_ HANDLE ProcessHandle, + _In_ HANDLE ProcessId + ) +{ + HANDLE legacyPrivateBlockHandle = NULL; + PVOID ipcControlBlockTable = NULL; + LARGE_INTEGER sectionOffset = { 0 }; + SIZE_T viewSize = 0; + OBJECT_ATTRIBUTES objectAttributes; + UNICODE_STRING sectionNameUs; + PPH_LIST appDomainsList = NULL; + + if (!PhStringRefToUnicodeString(&GeneratePrivateNameV4(ProcessId)->sr, §ionNameUs)) + goto CleanupExit; + + InitializeObjectAttributes( + &objectAttributes, + §ionNameUs, + 0, + NULL, + NULL + ); + + if (!NT_SUCCESS(NtOpenSection( + &legacyPrivateBlockHandle, + SECTION_MAP_READ, + &objectAttributes + ))) + { + goto CleanupExit; + } + + if (!NT_SUCCESS(NtMapViewOfSection( + legacyPrivateBlockHandle, + NtCurrentProcess(), + &ipcControlBlockTable, + 0, + viewSize, + §ionOffset, + &viewSize, + ViewShare, + 0, + PAGE_READONLY + ))) + { + goto CleanupExit; + } + + if (Wow64) + { + LegacyPrivateIPCControlBlock_Wow64* legacyPrivateBlock; + AppDomainEnumerationIPCBlock_Wow64* appDomainEnumBlock; + + legacyPrivateBlock = (LegacyPrivateIPCControlBlock_Wow64*)ipcControlBlockTable; + appDomainEnumBlock = &legacyPrivateBlock->AppDomainBlock; + + // Check the IPCControlBlock is initialized. + if ((legacyPrivateBlock->FullIPCHeader.Header.Flags & IPC_FLAG_INITIALIZED) != IPC_FLAG_INITIALIZED) + { + goto CleanupExit; + } + + // Check the IPCControlBlock version is valid. + if (legacyPrivateBlock->FullIPCHeader.Header.Version > VER_LEGACYPRIVATE_IPC_BLOCK) + { + goto CleanupExit; + } + + appDomainsList = EnumerateAppDomainIpcBlockWow64( + ProcessHandle, + appDomainEnumBlock + ); + } + else + { + LegacyPrivateIPCControlBlock* legacyPrivateBlock; + AppDomainEnumerationIPCBlock* appDomainEnumBlock; + + legacyPrivateBlock = (LegacyPrivateIPCControlBlock*)ipcControlBlockTable; + appDomainEnumBlock = &legacyPrivateBlock->AppDomainBlock; + + // Check the IPCControlBlock is initialized. + if ((legacyPrivateBlock->FullIPCHeader.Header.Flags & IPC_FLAG_INITIALIZED) != IPC_FLAG_INITIALIZED) + { + goto CleanupExit; + } + + // Check the IPCControlBlock version is valid. + if (legacyPrivateBlock->FullIPCHeader.Header.Version > VER_LEGACYPRIVATE_IPC_BLOCK) + { + goto CleanupExit; + } + + appDomainsList = EnumerateAppDomainIpcBlock( + ProcessHandle, + appDomainEnumBlock + ); + } + +CleanupExit: + + if (ipcControlBlockTable) + { + NtUnmapViewOfSection(NtCurrentProcess(), ipcControlBlockTable); + } + + if (legacyPrivateBlockHandle) + { + NtClose(legacyPrivateBlockHandle); + } + + return appDomainsList; +} diff --git a/plugins/DotNetTools/dn.h b/plugins/DotNetTools/dn.h index 23fd34947f91..72f7e24132f3 100644 --- a/plugins/DotNetTools/dn.h +++ b/plugins/DotNetTools/dn.h @@ -1,144 +1,144 @@ -/* - * Process Hacker .NET Tools - * - * Copyright (C) 2011-2015 wj32 - * Copyright (C) 2015-2016 dmex - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#ifndef DN_H -#define DN_H - -#define CINTERFACE -#define COBJMACROS -#include -#include - -#include "resource.h" - -#define PLUGIN_NAME L"ProcessHacker.DotNetTools" -#define SETTING_NAME_ASM_TREE_LIST_COLUMNS (PLUGIN_NAME L".AsmTreeListColumns") -#define SETTING_NAME_DOT_NET_CATEGORY_INDEX (PLUGIN_NAME L".DotNetCategoryIndex") -#define SETTING_NAME_DOT_NET_COUNTERS_COLUMNS (PLUGIN_NAME L".DotNetListColumns") -#define SETTING_NAME_DOT_NET_SHOW_BYTE_SIZE (PLUGIN_NAME L".DotNetShowByteSizes") - -#define MSG_UPDATE (WM_APP + 1) - -extern PPH_PLUGIN PluginInstance; - -typedef struct _DN_THREAD_ITEM -{ - PPH_THREAD_ITEM ThreadItem; - - BOOLEAN ClrDataValid; - PPH_STRING AppDomainText; -} DN_THREAD_ITEM, *PDN_THREAD_ITEM; - -// counters - -PVOID GetPerfIpcBlock_V2( - _In_ BOOLEAN Wow64, - _In_ PVOID BlockTableAddress - ); - -PVOID GetPerfIpcBlock_V4( - _In_ BOOLEAN Wow64, - _In_ PVOID BlockTableAddress - ); - -BOOLEAN OpenDotNetPublicControlBlock_V2( - _In_ HANDLE ProcessId, - _Out_ HANDLE* BlockTableHandle, - _Out_ PVOID* BlockTableAddress - ); - -BOOLEAN OpenDotNetPublicControlBlock_V4( - _In_ BOOLEAN IsImmersive, - _In_ HANDLE ProcessHandle, - _In_ HANDLE ProcessId, - _Out_ HANDLE* BlockTableHandle, - _Out_ PVOID* BlockTableAddress - ); - -PPH_LIST QueryDotNetAppDomainsForPid_V2( - _In_ BOOLEAN Wow64, - _In_ HANDLE ProcessHandle, - _In_ HANDLE ProcessId - ); - -PPH_LIST QueryDotNetAppDomainsForPid_V4( - _In_ BOOLEAN Wow64, - _In_ HANDLE ProcessHandle, - _In_ HANDLE ProcessId - ); - -// asmpage - -VOID AddAsmPageToPropContext( - _In_ PPH_PLUGIN_PROCESS_PROPCONTEXT PropContext - ); - -// perfpage - -VOID AddPerfPageToPropContext( - _In_ PPH_PLUGIN_PROCESS_PROPCONTEXT PropContext - ); - -// stackext - -VOID ProcessThreadStackControl( - _In_ PPH_PLUGIN_THREAD_STACK_CONTROL Control - ); - -VOID PredictAddressesFromClrData( - _In_ struct _CLR_PROCESS_SUPPORT *Support, - _In_ HANDLE ThreadId, - _In_ PVOID PcAddress, - _In_ PVOID FrameAddress, - _In_ PVOID StackAddress, - _Out_ PVOID *PredictedEip, - _Out_ PVOID *PredictedEbp, - _Out_ PVOID *PredictedEsp - ); - -// svcext - -VOID DispatchPhSvcRequest( - _In_ PVOID Parameter - ); - -// treeext - -VOID InitializeTreeNewObjectExtensions( - VOID - ); - -VOID DispatchTreeNewMessage( - __in PVOID Parameter - ); - -#define DNTHTNC_APPDOMAIN 1 - -VOID ThreadTreeNewInitializing( - __in PVOID Parameter - ); - -VOID ThreadTreeNewUninitializing( - __in PVOID Parameter - ); - -#endif +/* + * Process Hacker .NET Tools + * + * Copyright (C) 2011-2015 wj32 + * Copyright (C) 2015-2016 dmex + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#ifndef DN_H +#define DN_H + +#define CINTERFACE +#define COBJMACROS +#include +#include + +#include "resource.h" + +#define PLUGIN_NAME L"ProcessHacker.DotNetTools" +#define SETTING_NAME_ASM_TREE_LIST_COLUMNS (PLUGIN_NAME L".AsmTreeListColumns") +#define SETTING_NAME_DOT_NET_CATEGORY_INDEX (PLUGIN_NAME L".DotNetCategoryIndex") +#define SETTING_NAME_DOT_NET_COUNTERS_COLUMNS (PLUGIN_NAME L".DotNetListColumns") +#define SETTING_NAME_DOT_NET_SHOW_BYTE_SIZE (PLUGIN_NAME L".DotNetShowByteSizes") + +#define MSG_UPDATE (WM_APP + 1) + +extern PPH_PLUGIN PluginInstance; + +typedef struct _DN_THREAD_ITEM +{ + PPH_THREAD_ITEM ThreadItem; + + BOOLEAN ClrDataValid; + PPH_STRING AppDomainText; +} DN_THREAD_ITEM, *PDN_THREAD_ITEM; + +// counters + +PVOID GetPerfIpcBlock_V2( + _In_ BOOLEAN Wow64, + _In_ PVOID BlockTableAddress + ); + +PVOID GetPerfIpcBlock_V4( + _In_ BOOLEAN Wow64, + _In_ PVOID BlockTableAddress + ); + +BOOLEAN OpenDotNetPublicControlBlock_V2( + _In_ HANDLE ProcessId, + _Out_ HANDLE* BlockTableHandle, + _Out_ PVOID* BlockTableAddress + ); + +BOOLEAN OpenDotNetPublicControlBlock_V4( + _In_ BOOLEAN IsImmersive, + _In_ HANDLE ProcessHandle, + _In_ HANDLE ProcessId, + _Out_ HANDLE* BlockTableHandle, + _Out_ PVOID* BlockTableAddress + ); + +PPH_LIST QueryDotNetAppDomainsForPid_V2( + _In_ BOOLEAN Wow64, + _In_ HANDLE ProcessHandle, + _In_ HANDLE ProcessId + ); + +PPH_LIST QueryDotNetAppDomainsForPid_V4( + _In_ BOOLEAN Wow64, + _In_ HANDLE ProcessHandle, + _In_ HANDLE ProcessId + ); + +// asmpage + +VOID AddAsmPageToPropContext( + _In_ PPH_PLUGIN_PROCESS_PROPCONTEXT PropContext + ); + +// perfpage + +VOID AddPerfPageToPropContext( + _In_ PPH_PLUGIN_PROCESS_PROPCONTEXT PropContext + ); + +// stackext + +VOID ProcessThreadStackControl( + _In_ PPH_PLUGIN_THREAD_STACK_CONTROL Control + ); + +VOID PredictAddressesFromClrData( + _In_ struct _CLR_PROCESS_SUPPORT *Support, + _In_ HANDLE ThreadId, + _In_ PVOID PcAddress, + _In_ PVOID FrameAddress, + _In_ PVOID StackAddress, + _Out_ PVOID *PredictedEip, + _Out_ PVOID *PredictedEbp, + _Out_ PVOID *PredictedEsp + ); + +// svcext + +VOID DispatchPhSvcRequest( + _In_ PVOID Parameter + ); + +// treeext + +VOID InitializeTreeNewObjectExtensions( + VOID + ); + +VOID DispatchTreeNewMessage( + __in PVOID Parameter + ); + +#define DNTHTNC_APPDOMAIN 1 + +VOID ThreadTreeNewInitializing( + __in PVOID Parameter + ); + +VOID ThreadTreeNewUninitializing( + __in PVOID Parameter + ); + +#endif diff --git a/plugins/DotNetTools/main.c b/plugins/DotNetTools/main.c index 80118c7720f0..759559574503 100644 --- a/plugins/DotNetTools/main.c +++ b/plugins/DotNetTools/main.c @@ -1,335 +1,335 @@ -/* - * Process Hacker .NET Tools - - * main program - * - * Copyright (C) 2011-2015 wj32 - * Copyright (C) 2015-2016 dmex - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include "dn.h" - -PPH_PLUGIN PluginInstance; -static PH_CALLBACK_REGISTRATION PluginLoadCallbackRegistration; -static PH_CALLBACK_REGISTRATION PluginUnloadCallbackRegistration; -static PH_CALLBACK_REGISTRATION PluginShowOptionsCallbackRegistration; -static PH_CALLBACK_REGISTRATION PluginMenuItemCallbackRegistration; -static PH_CALLBACK_REGISTRATION PluginTreeNewMessageCallbackRegistration; -static PH_CALLBACK_REGISTRATION PluginPhSvcRequestCallbackRegistration; -static PH_CALLBACK_REGISTRATION MainWindowShowingCallbackRegistration; -static PH_CALLBACK_REGISTRATION ProcessPropertiesInitializingCallbackRegistration; -static PH_CALLBACK_REGISTRATION ProcessMenuInitializingCallbackRegistration; -static PH_CALLBACK_REGISTRATION ThreadMenuInitializingCallbackRegistration; -static PH_CALLBACK_REGISTRATION ModuleMenuInitializingCallbackRegistration; -static PH_CALLBACK_REGISTRATION ProcessTreeNewInitializingCallbackRegistration; -static PH_CALLBACK_REGISTRATION ThreadTreeNewInitializingCallbackRegistration; -static PH_CALLBACK_REGISTRATION ThreadTreeNewUninitializingCallbackRegistration; -static PH_CALLBACK_REGISTRATION ThreadStackControlCallbackRegistration; - -VOID NTAPI LoadCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - NOTHING; -} - -VOID NTAPI UnloadCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - NOTHING; -} - -VOID NTAPI ShowOptionsCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - NOTHING; -} - -VOID NTAPI MenuItemCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - PPH_PLUGIN_MENU_ITEM menuItem = Parameter; - - switch (menuItem->Id) - { - default: - NOTHING; - break; - } -} - -VOID NTAPI TreeNewMessageCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - DispatchTreeNewMessage(Parameter); -} - -VOID NTAPI PhSvcRequestCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - DispatchPhSvcRequest(Parameter); -} - -VOID NTAPI ThreadTreeNewInitializingCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - ThreadTreeNewInitializing(Parameter); -} - -VOID NTAPI ThreadTreeNewUninitializingCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - ThreadTreeNewUninitializing(Parameter); -} - -VOID NTAPI ProcessPropertiesInitializingCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - PPH_PLUGIN_PROCESS_PROPCONTEXT propContext = Parameter; - BOOLEAN isDotNet; - - if (NT_SUCCESS(PhGetProcessIsDotNet(propContext->ProcessItem->ProcessId, &isDotNet))) - { - if (isDotNet) - { - AddAsmPageToPropContext(propContext); - AddPerfPageToPropContext(propContext); - } - - if (propContext->ProcessItem->IsDotNet != isDotNet) - propContext->ProcessItem->UpdateIsDotNet = TRUE; // force a refresh - } -} - -VOID NTAPI ProcessMenuInitializingCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - NOTHING; -} - -VOID NTAPI ThreadMenuInitializingCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - NOTHING; -} - -VOID NTAPI ModuleMenuInitializingCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - NOTHING; -} - -VOID NTAPI ProcessTreeNewInitializingCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - NOTHING; -} - -VOID NTAPI ThreadStackControlCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - ProcessThreadStackControl(Parameter); -} - -VOID NTAPI ThreadItemCreateCallback( - _In_ PVOID Object, - _In_ PH_EM_OBJECT_TYPE ObjectType, - _In_ PVOID Extension - ) -{ - PDN_THREAD_ITEM dnThread = Extension; - - memset(dnThread, 0, sizeof(DN_THREAD_ITEM)); - dnThread->ThreadItem = Object; -} - -VOID NTAPI ThreadItemDeleteCallback( - _In_ PVOID Object, - _In_ PH_EM_OBJECT_TYPE ObjectType, - _In_ PVOID Extension - ) -{ - PDN_THREAD_ITEM dnThread = Extension; - - PhClearReference(&dnThread->AppDomainText); -} - -LOGICAL DllMain( - _In_ HINSTANCE Instance, - _In_ ULONG Reason, - _Reserved_ PVOID Reserved - ) -{ - switch (Reason) - { - case DLL_PROCESS_ATTACH: - { - PPH_PLUGIN_INFORMATION info; - PH_SETTING_CREATE settings[] = - { - { StringSettingType, SETTING_NAME_ASM_TREE_LIST_COLUMNS, L"" }, - { IntegerSettingType, SETTING_NAME_DOT_NET_CATEGORY_INDEX, L"5" }, - { StringSettingType, SETTING_NAME_DOT_NET_COUNTERS_COLUMNS, L"" }, - { IntegerSettingType, SETTING_NAME_DOT_NET_SHOW_BYTE_SIZE, L"1" } - }; - - PluginInstance = PhRegisterPlugin(PLUGIN_NAME, Instance, &info); - - if (!PluginInstance) - return FALSE; - - info->DisplayName = L".NET Tools"; - info->Author = L"dmex, wj32"; - info->Description = L"Adds .NET performance counters, assembly information, thread stack support, and more."; - info->Url = L"https://wj32.org/processhacker/forums/viewtopic.php?t=1111"; - info->HasOptions = FALSE; - - PhRegisterCallback( - PhGetPluginCallback(PluginInstance, PluginCallbackLoad), - LoadCallback, - NULL, - &PluginLoadCallbackRegistration - ); - PhRegisterCallback( - PhGetPluginCallback(PluginInstance, PluginCallbackUnload), - UnloadCallback, - NULL, - &PluginUnloadCallbackRegistration - ); - PhRegisterCallback( - PhGetPluginCallback(PluginInstance, PluginCallbackShowOptions), - ShowOptionsCallback, - NULL, - &PluginShowOptionsCallbackRegistration - ); - //PhRegisterCallback( - // PhGetPluginCallback(PluginInstance, PluginCallbackMenuItem), - // MenuItemCallback, - // NULL, - // &PluginMenuItemCallbackRegistration - // ); - PhRegisterCallback( - PhGetPluginCallback(PluginInstance, PluginCallbackTreeNewMessage), - TreeNewMessageCallback, - NULL, - &PluginTreeNewMessageCallbackRegistration - ); - PhRegisterCallback( - PhGetPluginCallback(PluginInstance, PluginCallbackPhSvcRequest), - PhSvcRequestCallback, - NULL, - &PluginPhSvcRequestCallbackRegistration - ); - - //PhRegisterCallback( - // PhGetGeneralCallback(GeneralCallbackMainWindowShowing), - // MainWindowShowingCallback, - // NULL, - // &MainWindowShowingCallbackRegistration - // ); - PhRegisterCallback( - PhGetGeneralCallback(GeneralCallbackProcessPropertiesInitializing), - ProcessPropertiesInitializingCallback, - NULL, - &ProcessPropertiesInitializingCallbackRegistration - ); - //PhRegisterCallback( - // PhGetGeneralCallback(GeneralCallbackProcessMenuInitializing), - // ProcessMenuInitializingCallback, - // NULL, - // &ProcessMenuInitializingCallbackRegistration - // ); - //PhRegisterCallback( - // PhGetGeneralCallback(GeneralCallbackThreadMenuInitializing), - // ThreadMenuInitializingCallback, - // NULL, - // &ThreadMenuInitializingCallbackRegistration - // ); - //PhRegisterCallback( - // PhGetGeneralCallback(GeneralCallbackModuleMenuInitializing), - // ModuleMenuInitializingCallback, - // NULL, - // &ModuleMenuInitializingCallbackRegistration - // ); - //PhRegisterCallback( - // PhGetGeneralCallback(GeneralCallbackProcessTreeNewInitializing), - // ProcessTreeNewInitializingCallback, - // NULL, - // &ProcessTreeNewInitializingCallbackRegistration - // ); - PhRegisterCallback( - PhGetGeneralCallback(GeneralCallbackThreadTreeNewInitializing), - ThreadTreeNewInitializingCallback, - NULL, - &ThreadTreeNewInitializingCallbackRegistration - ); - PhRegisterCallback( - PhGetGeneralCallback(GeneralCallbackThreadTreeNewUninitializing), - ThreadTreeNewUninitializingCallback, - NULL, - &ThreadTreeNewUninitializingCallbackRegistration - ); - PhRegisterCallback( - PhGetGeneralCallback(GeneralCallbackThreadStackControl), - ThreadStackControlCallback, - NULL, - &ThreadStackControlCallbackRegistration - ); - - PhPluginSetObjectExtension( - PluginInstance, - EmThreadItemType, - sizeof(DN_THREAD_ITEM), - ThreadItemCreateCallback, - ThreadItemDeleteCallback - ); - InitializeTreeNewObjectExtensions(); - - PhAddSettings(settings, ARRAYSIZE(settings)); - } - break; - } - - return TRUE; -} +/* + * Process Hacker .NET Tools - + * main program + * + * Copyright (C) 2011-2015 wj32 + * Copyright (C) 2015-2016 dmex + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include "dn.h" + +PPH_PLUGIN PluginInstance; +static PH_CALLBACK_REGISTRATION PluginLoadCallbackRegistration; +static PH_CALLBACK_REGISTRATION PluginUnloadCallbackRegistration; +static PH_CALLBACK_REGISTRATION PluginShowOptionsCallbackRegistration; +static PH_CALLBACK_REGISTRATION PluginMenuItemCallbackRegistration; +static PH_CALLBACK_REGISTRATION PluginTreeNewMessageCallbackRegistration; +static PH_CALLBACK_REGISTRATION PluginPhSvcRequestCallbackRegistration; +static PH_CALLBACK_REGISTRATION MainWindowShowingCallbackRegistration; +static PH_CALLBACK_REGISTRATION ProcessPropertiesInitializingCallbackRegistration; +static PH_CALLBACK_REGISTRATION ProcessMenuInitializingCallbackRegistration; +static PH_CALLBACK_REGISTRATION ThreadMenuInitializingCallbackRegistration; +static PH_CALLBACK_REGISTRATION ModuleMenuInitializingCallbackRegistration; +static PH_CALLBACK_REGISTRATION ProcessTreeNewInitializingCallbackRegistration; +static PH_CALLBACK_REGISTRATION ThreadTreeNewInitializingCallbackRegistration; +static PH_CALLBACK_REGISTRATION ThreadTreeNewUninitializingCallbackRegistration; +static PH_CALLBACK_REGISTRATION ThreadStackControlCallbackRegistration; + +VOID NTAPI LoadCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + NOTHING; +} + +VOID NTAPI UnloadCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + NOTHING; +} + +VOID NTAPI ShowOptionsCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + NOTHING; +} + +VOID NTAPI MenuItemCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + PPH_PLUGIN_MENU_ITEM menuItem = Parameter; + + switch (menuItem->Id) + { + default: + NOTHING; + break; + } +} + +VOID NTAPI TreeNewMessageCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + DispatchTreeNewMessage(Parameter); +} + +VOID NTAPI PhSvcRequestCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + DispatchPhSvcRequest(Parameter); +} + +VOID NTAPI ThreadTreeNewInitializingCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + ThreadTreeNewInitializing(Parameter); +} + +VOID NTAPI ThreadTreeNewUninitializingCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + ThreadTreeNewUninitializing(Parameter); +} + +VOID NTAPI ProcessPropertiesInitializingCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + PPH_PLUGIN_PROCESS_PROPCONTEXT propContext = Parameter; + BOOLEAN isDotNet; + + if (NT_SUCCESS(PhGetProcessIsDotNet(propContext->ProcessItem->ProcessId, &isDotNet))) + { + if (isDotNet) + { + AddAsmPageToPropContext(propContext); + AddPerfPageToPropContext(propContext); + } + + if (propContext->ProcessItem->IsDotNet != isDotNet) + propContext->ProcessItem->UpdateIsDotNet = TRUE; // force a refresh + } +} + +VOID NTAPI ProcessMenuInitializingCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + NOTHING; +} + +VOID NTAPI ThreadMenuInitializingCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + NOTHING; +} + +VOID NTAPI ModuleMenuInitializingCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + NOTHING; +} + +VOID NTAPI ProcessTreeNewInitializingCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + NOTHING; +} + +VOID NTAPI ThreadStackControlCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + ProcessThreadStackControl(Parameter); +} + +VOID NTAPI ThreadItemCreateCallback( + _In_ PVOID Object, + _In_ PH_EM_OBJECT_TYPE ObjectType, + _In_ PVOID Extension + ) +{ + PDN_THREAD_ITEM dnThread = Extension; + + memset(dnThread, 0, sizeof(DN_THREAD_ITEM)); + dnThread->ThreadItem = Object; +} + +VOID NTAPI ThreadItemDeleteCallback( + _In_ PVOID Object, + _In_ PH_EM_OBJECT_TYPE ObjectType, + _In_ PVOID Extension + ) +{ + PDN_THREAD_ITEM dnThread = Extension; + + PhClearReference(&dnThread->AppDomainText); +} + +LOGICAL DllMain( + _In_ HINSTANCE Instance, + _In_ ULONG Reason, + _Reserved_ PVOID Reserved + ) +{ + switch (Reason) + { + case DLL_PROCESS_ATTACH: + { + PPH_PLUGIN_INFORMATION info; + PH_SETTING_CREATE settings[] = + { + { StringSettingType, SETTING_NAME_ASM_TREE_LIST_COLUMNS, L"" }, + { IntegerSettingType, SETTING_NAME_DOT_NET_CATEGORY_INDEX, L"5" }, + { StringSettingType, SETTING_NAME_DOT_NET_COUNTERS_COLUMNS, L"" }, + { IntegerSettingType, SETTING_NAME_DOT_NET_SHOW_BYTE_SIZE, L"1" } + }; + + PluginInstance = PhRegisterPlugin(PLUGIN_NAME, Instance, &info); + + if (!PluginInstance) + return FALSE; + + info->DisplayName = L".NET Tools"; + info->Author = L"dmex, wj32"; + info->Description = L"Adds .NET performance counters, assembly information, thread stack support, and more."; + info->Url = L"https://wj32.org/processhacker/forums/viewtopic.php?t=1111"; + info->HasOptions = FALSE; + + PhRegisterCallback( + PhGetPluginCallback(PluginInstance, PluginCallbackLoad), + LoadCallback, + NULL, + &PluginLoadCallbackRegistration + ); + PhRegisterCallback( + PhGetPluginCallback(PluginInstance, PluginCallbackUnload), + UnloadCallback, + NULL, + &PluginUnloadCallbackRegistration + ); + PhRegisterCallback( + PhGetPluginCallback(PluginInstance, PluginCallbackShowOptions), + ShowOptionsCallback, + NULL, + &PluginShowOptionsCallbackRegistration + ); + //PhRegisterCallback( + // PhGetPluginCallback(PluginInstance, PluginCallbackMenuItem), + // MenuItemCallback, + // NULL, + // &PluginMenuItemCallbackRegistration + // ); + PhRegisterCallback( + PhGetPluginCallback(PluginInstance, PluginCallbackTreeNewMessage), + TreeNewMessageCallback, + NULL, + &PluginTreeNewMessageCallbackRegistration + ); + PhRegisterCallback( + PhGetPluginCallback(PluginInstance, PluginCallbackPhSvcRequest), + PhSvcRequestCallback, + NULL, + &PluginPhSvcRequestCallbackRegistration + ); + + //PhRegisterCallback( + // PhGetGeneralCallback(GeneralCallbackMainWindowShowing), + // MainWindowShowingCallback, + // NULL, + // &MainWindowShowingCallbackRegistration + // ); + PhRegisterCallback( + PhGetGeneralCallback(GeneralCallbackProcessPropertiesInitializing), + ProcessPropertiesInitializingCallback, + NULL, + &ProcessPropertiesInitializingCallbackRegistration + ); + //PhRegisterCallback( + // PhGetGeneralCallback(GeneralCallbackProcessMenuInitializing), + // ProcessMenuInitializingCallback, + // NULL, + // &ProcessMenuInitializingCallbackRegistration + // ); + //PhRegisterCallback( + // PhGetGeneralCallback(GeneralCallbackThreadMenuInitializing), + // ThreadMenuInitializingCallback, + // NULL, + // &ThreadMenuInitializingCallbackRegistration + // ); + //PhRegisterCallback( + // PhGetGeneralCallback(GeneralCallbackModuleMenuInitializing), + // ModuleMenuInitializingCallback, + // NULL, + // &ModuleMenuInitializingCallbackRegistration + // ); + //PhRegisterCallback( + // PhGetGeneralCallback(GeneralCallbackProcessTreeNewInitializing), + // ProcessTreeNewInitializingCallback, + // NULL, + // &ProcessTreeNewInitializingCallbackRegistration + // ); + PhRegisterCallback( + PhGetGeneralCallback(GeneralCallbackThreadTreeNewInitializing), + ThreadTreeNewInitializingCallback, + NULL, + &ThreadTreeNewInitializingCallbackRegistration + ); + PhRegisterCallback( + PhGetGeneralCallback(GeneralCallbackThreadTreeNewUninitializing), + ThreadTreeNewUninitializingCallback, + NULL, + &ThreadTreeNewUninitializingCallbackRegistration + ); + PhRegisterCallback( + PhGetGeneralCallback(GeneralCallbackThreadStackControl), + ThreadStackControlCallback, + NULL, + &ThreadStackControlCallbackRegistration + ); + + PhPluginSetObjectExtension( + PluginInstance, + EmThreadItemType, + sizeof(DN_THREAD_ITEM), + ThreadItemCreateCallback, + ThreadItemDeleteCallback + ); + InitializeTreeNewObjectExtensions(); + + PhAddSettings(settings, ARRAYSIZE(settings)); + } + break; + } + + return TRUE; +} diff --git a/plugins/DotNetTools/resource.h b/plugins/DotNetTools/resource.h index bffca0871ee0..62ce099e861b 100644 --- a/plugins/DotNetTools/resource.h +++ b/plugins/DotNetTools/resource.h @@ -1,26 +1,26 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by DotNetTools.rc -// -#define IDD_PROCDOTNETPERF 101 -#define ID_COPY 101 -#define IDD_PROCDOTNETASM 102 -#define IDR_ASSEMBLY_MENU 104 -#define IDC_APPDOMAINS 1001 -#define IDC_CATEGORIES 1002 -#define IDC_COUNTERS 1003 -#define IDC_LIST 1005 -#define IDC_DOTNET_PERF_SHOWBYTES 1006 -#define ID_CLR_OPENFILELOCATION 40001 -#define ID_CLR_COPY 40002 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 105 -#define _APS_NEXT_COMMAND_VALUE 40003 -#define _APS_NEXT_CONTROL_VALUE 1007 -#define _APS_NEXT_SYMED_VALUE 102 -#endif -#endif +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by DotNetTools.rc +// +#define IDD_PROCDOTNETPERF 101 +#define ID_COPY 101 +#define IDD_PROCDOTNETASM 102 +#define IDR_ASSEMBLY_MENU 104 +#define IDC_APPDOMAINS 1001 +#define IDC_CATEGORIES 1002 +#define IDC_COUNTERS 1003 +#define IDC_LIST 1005 +#define IDC_DOTNET_PERF_SHOWBYTES 1006 +#define ID_CLR_OPENFILELOCATION 40001 +#define ID_CLR_COPY 40002 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 105 +#define _APS_NEXT_COMMAND_VALUE 40003 +#define _APS_NEXT_CONTROL_VALUE 1007 +#define _APS_NEXT_SYMED_VALUE 102 +#endif +#endif diff --git a/plugins/DotNetTools/stackext.c b/plugins/DotNetTools/stackext.c index c5973a935dc0..13ef6a3aca5c 100644 --- a/plugins/DotNetTools/stackext.c +++ b/plugins/DotNetTools/stackext.c @@ -1,321 +1,321 @@ -/* - * Process Hacker .NET Tools - - * thread stack extensions - * - * Copyright (C) 2011-2015 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include "dn.h" -#include "clrsup.h" -#include "svcext.h" -#include - -typedef struct _THREAD_STACK_CONTEXT -{ - PCLR_PROCESS_SUPPORT Support; - HANDLE ProcessId; - HANDLE ThreadId; - HANDLE ThreadHandle; - - PVOID PredictedEip; - PVOID PredictedEbp; - PVOID PredictedEsp; - -#ifdef _WIN64 - BOOLEAN IsWow64; - BOOLEAN ConnectedToPhSvc; -#endif -} THREAD_STACK_CONTEXT, *PTHREAD_STACK_CONTEXT; - -static PPH_HASHTABLE ContextHashtable; -static PH_QUEUED_LOCK ContextHashtableLock = PH_QUEUED_LOCK_INIT; -static PH_INITONCE ContextHashtableInitOnce = PH_INITONCE_INIT; - -PTHREAD_STACK_CONTEXT FindThreadStackContext( - _In_ PVOID UniqueKey - ) -{ - PTHREAD_STACK_CONTEXT context; - PVOID *item; - - PhAcquireQueuedLockExclusive(&ContextHashtableLock); - - item = PhFindItemSimpleHashtable(ContextHashtable, UniqueKey); - - if (item) - context = *item; - else - context = NULL; - - PhReleaseQueuedLockExclusive(&ContextHashtableLock); - - return context; -} - -VOID ProcessThreadStackControl( - _In_ PPH_PLUGIN_THREAD_STACK_CONTROL Control - ) -{ - if (PhBeginInitOnce(&ContextHashtableInitOnce)) - { - ContextHashtable = PhCreateSimpleHashtable(4); - PhEndInitOnce(&ContextHashtableInitOnce); - } - - switch (Control->Type) - { - case PluginThreadStackInitializing: - { - PTHREAD_STACK_CONTEXT context; -#if _WIN64 - HANDLE processHandle; -#endif - - context = PhAllocate(sizeof(THREAD_STACK_CONTEXT)); - memset(context, 0, sizeof(THREAD_STACK_CONTEXT)); - context->ProcessId = Control->u.Initializing.ProcessId; - context->ThreadId = Control->u.Initializing.ThreadId; - context->ThreadHandle = Control->u.Initializing.ThreadHandle; - -#if _WIN64 - if (NT_SUCCESS(PhOpenProcess(&processHandle, ProcessQueryAccess, Control->u.Initializing.ProcessId))) - { - PhGetProcessIsWow64(processHandle, &context->IsWow64); - NtClose(processHandle); - } -#endif - - PhAcquireQueuedLockExclusive(&ContextHashtableLock); - PhAddItemSimpleHashtable(ContextHashtable, Control->UniqueKey, context); - PhReleaseQueuedLockExclusive(&ContextHashtableLock); - } - break; - case PluginThreadStackUninitializing: - { - PTHREAD_STACK_CONTEXT context = FindThreadStackContext(Control->UniqueKey); - - if (!context) - return; - - PhFree(context); - - PhAcquireQueuedLockExclusive(&ContextHashtableLock); - PhRemoveItemSimpleHashtable(ContextHashtable, Control->UniqueKey); - PhReleaseQueuedLockExclusive(&ContextHashtableLock); - } - break; - case PluginThreadStackResolveSymbol: - { - PTHREAD_STACK_CONTEXT context = FindThreadStackContext(Control->UniqueKey); - PPH_STRING managedSymbol = NULL; - ULONG64 displacement; - - if (!context) - return; - - if (context->Support) - { -#ifndef _WIN64 - PVOID predictedEip; - PVOID predictedEbp; - PVOID predictedEsp; - - predictedEip = context->PredictedEip; - predictedEbp = context->PredictedEbp; - predictedEsp = context->PredictedEsp; - - PredictAddressesFromClrData( - context->Support, - context->ThreadId, - Control->u.ResolveSymbol.StackFrame->PcAddress, - Control->u.ResolveSymbol.StackFrame->FrameAddress, - Control->u.ResolveSymbol.StackFrame->StackAddress, - &context->PredictedEip, - &context->PredictedEbp, - &context->PredictedEsp - ); - - // Fix up dbghelp EBP with real EBP given by the CLR data routines. - if (Control->u.ResolveSymbol.StackFrame->PcAddress == predictedEip) - { - Control->u.ResolveSymbol.StackFrame->FrameAddress = predictedEbp; - Control->u.ResolveSymbol.StackFrame->StackAddress = predictedEsp; - } -#endif - - managedSymbol = GetRuntimeNameByAddressClrProcess( - context->Support, - (ULONG64)Control->u.ResolveSymbol.StackFrame->PcAddress, - &displacement - ); - } -#ifdef _WIN64 - else if (context->IsWow64 && context->ConnectedToPhSvc) - { - PVOID predictedEip; - PVOID predictedEbp; - PVOID predictedEsp; - - predictedEip = context->PredictedEip; - predictedEbp = context->PredictedEbp; - predictedEsp = context->PredictedEsp; - - CallPredictAddressesFromClrData( - context->ProcessId, - context->ThreadId, - Control->u.ResolveSymbol.StackFrame->PcAddress, - Control->u.ResolveSymbol.StackFrame->FrameAddress, - Control->u.ResolveSymbol.StackFrame->StackAddress, - &context->PredictedEip, - &context->PredictedEbp, - &context->PredictedEsp - ); - - // Fix up dbghelp EBP with real EBP given by the CLR data routines. - if (Control->u.ResolveSymbol.StackFrame->PcAddress == predictedEip) - { - Control->u.ResolveSymbol.StackFrame->FrameAddress = predictedEbp; - Control->u.ResolveSymbol.StackFrame->StackAddress = predictedEsp; - } - - managedSymbol = CallGetRuntimeNameByAddress( - context->ProcessId, - (ULONG64)Control->u.ResolveSymbol.StackFrame->PcAddress, - &displacement - ); - } -#endif - - if (managedSymbol) - { - if (displacement != 0) - PhMoveReference(&managedSymbol, PhFormatString(L"%s + 0x%I64x", managedSymbol->Buffer, displacement)); - - if (Control->u.ResolveSymbol.Symbol) - PhMoveReference(&managedSymbol, PhFormatString(L"%s <-- %s", managedSymbol->Buffer, Control->u.ResolveSymbol.Symbol->Buffer)); - - PhMoveReference(&Control->u.ResolveSymbol.Symbol, managedSymbol); - } - } - break; - case PluginThreadStackBeginDefaultWalkStack: - { - PTHREAD_STACK_CONTEXT context = FindThreadStackContext(Control->UniqueKey); - BOOLEAN isDotNet; - - if (!context) - return; - - if (!NT_SUCCESS(PhGetProcessIsDotNet(context->ProcessId, &isDotNet)) || !isDotNet) - return; - - context->Support = CreateClrProcessSupport(context->ProcessId); - -#ifdef _WIN64 - if (context->IsWow64) - context->ConnectedToPhSvc = PhUiConnectToPhSvcEx(NULL, Wow64PhSvcMode, FALSE); -#endif - } - break; - case PluginThreadStackEndDefaultWalkStack: - { - PTHREAD_STACK_CONTEXT context = FindThreadStackContext(Control->UniqueKey); - - if (!context) - return; - - if (context->Support) - { - FreeClrProcessSupport(context->Support); - context->Support = NULL; - } - -#ifdef _WIN64 - if (context->ConnectedToPhSvc) - { - PhUiDisconnectFromPhSvc(); - context->ConnectedToPhSvc = FALSE; - } -#endif - } - break; - } -} - -VOID PredictAddressesFromClrData( - _In_ PCLR_PROCESS_SUPPORT Support, - _In_ HANDLE ThreadId, - _In_ PVOID PcAddress, - _In_ PVOID FrameAddress, - _In_ PVOID StackAddress, - _Out_ PVOID *PredictedEip, - _Out_ PVOID *PredictedEbp, - _Out_ PVOID *PredictedEsp - ) -{ -#ifdef _WIN64 - *PredictedEip = NULL; - *PredictedEbp = NULL; - *PredictedEsp = NULL; -#else - IXCLRDataTask *task; - - *PredictedEip = NULL; - *PredictedEbp = NULL; - *PredictedEsp = NULL; - - if (SUCCEEDED(IXCLRDataProcess_GetTaskByOSThreadID( - Support->DataProcess, - HandleToUlong(ThreadId), - &task - ))) - { - IXCLRDataStackWalk *stackWalk; - - if (SUCCEEDED(IXCLRDataTask_CreateStackWalk(task, 0xf, &stackWalk))) - { - HRESULT result; - BOOLEAN firstTime = TRUE; - CONTEXT context; - ULONG contextSize; - - memset(&context, 0, sizeof(CONTEXT)); - context.ContextFlags = CONTEXT_CONTROL; - context.Eip = PtrToUlong(PcAddress); - context.Ebp = PtrToUlong(FrameAddress); - context.Esp = PtrToUlong(StackAddress); - - result = IXCLRDataStackWalk_SetContext2(stackWalk, CLRDATA_STACK_SET_CURRENT_CONTEXT, sizeof(CONTEXT), (BYTE *)&context); - - if (SUCCEEDED(result = IXCLRDataStackWalk_Next(stackWalk)) && result != S_FALSE) - { - if (SUCCEEDED(IXCLRDataStackWalk_GetContext(stackWalk, CONTEXT_CONTROL, sizeof(CONTEXT), &contextSize, (BYTE *)&context))) - { - *PredictedEip = UlongToPtr(context.Eip); - *PredictedEbp = UlongToPtr(context.Ebp); - *PredictedEsp = UlongToPtr(context.Esp); - } - } - - IXCLRDataStackWalk_Release(stackWalk); - } - - IXCLRDataTask_Release(task); - } -#endif -} +/* + * Process Hacker .NET Tools - + * thread stack extensions + * + * Copyright (C) 2011-2015 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include "dn.h" +#include "clrsup.h" +#include "svcext.h" +#include + +typedef struct _THREAD_STACK_CONTEXT +{ + PCLR_PROCESS_SUPPORT Support; + HANDLE ProcessId; + HANDLE ThreadId; + HANDLE ThreadHandle; + + PVOID PredictedEip; + PVOID PredictedEbp; + PVOID PredictedEsp; + +#ifdef _WIN64 + BOOLEAN IsWow64; + BOOLEAN ConnectedToPhSvc; +#endif +} THREAD_STACK_CONTEXT, *PTHREAD_STACK_CONTEXT; + +static PPH_HASHTABLE ContextHashtable; +static PH_QUEUED_LOCK ContextHashtableLock = PH_QUEUED_LOCK_INIT; +static PH_INITONCE ContextHashtableInitOnce = PH_INITONCE_INIT; + +PTHREAD_STACK_CONTEXT FindThreadStackContext( + _In_ PVOID UniqueKey + ) +{ + PTHREAD_STACK_CONTEXT context; + PVOID *item; + + PhAcquireQueuedLockExclusive(&ContextHashtableLock); + + item = PhFindItemSimpleHashtable(ContextHashtable, UniqueKey); + + if (item) + context = *item; + else + context = NULL; + + PhReleaseQueuedLockExclusive(&ContextHashtableLock); + + return context; +} + +VOID ProcessThreadStackControl( + _In_ PPH_PLUGIN_THREAD_STACK_CONTROL Control + ) +{ + if (PhBeginInitOnce(&ContextHashtableInitOnce)) + { + ContextHashtable = PhCreateSimpleHashtable(4); + PhEndInitOnce(&ContextHashtableInitOnce); + } + + switch (Control->Type) + { + case PluginThreadStackInitializing: + { + PTHREAD_STACK_CONTEXT context; +#if _WIN64 + HANDLE processHandle; +#endif + + context = PhAllocate(sizeof(THREAD_STACK_CONTEXT)); + memset(context, 0, sizeof(THREAD_STACK_CONTEXT)); + context->ProcessId = Control->u.Initializing.ProcessId; + context->ThreadId = Control->u.Initializing.ThreadId; + context->ThreadHandle = Control->u.Initializing.ThreadHandle; + +#if _WIN64 + if (NT_SUCCESS(PhOpenProcess(&processHandle, ProcessQueryAccess, Control->u.Initializing.ProcessId))) + { + PhGetProcessIsWow64(processHandle, &context->IsWow64); + NtClose(processHandle); + } +#endif + + PhAcquireQueuedLockExclusive(&ContextHashtableLock); + PhAddItemSimpleHashtable(ContextHashtable, Control->UniqueKey, context); + PhReleaseQueuedLockExclusive(&ContextHashtableLock); + } + break; + case PluginThreadStackUninitializing: + { + PTHREAD_STACK_CONTEXT context = FindThreadStackContext(Control->UniqueKey); + + if (!context) + return; + + PhFree(context); + + PhAcquireQueuedLockExclusive(&ContextHashtableLock); + PhRemoveItemSimpleHashtable(ContextHashtable, Control->UniqueKey); + PhReleaseQueuedLockExclusive(&ContextHashtableLock); + } + break; + case PluginThreadStackResolveSymbol: + { + PTHREAD_STACK_CONTEXT context = FindThreadStackContext(Control->UniqueKey); + PPH_STRING managedSymbol = NULL; + ULONG64 displacement; + + if (!context) + return; + + if (context->Support) + { +#ifndef _WIN64 + PVOID predictedEip; + PVOID predictedEbp; + PVOID predictedEsp; + + predictedEip = context->PredictedEip; + predictedEbp = context->PredictedEbp; + predictedEsp = context->PredictedEsp; + + PredictAddressesFromClrData( + context->Support, + context->ThreadId, + Control->u.ResolveSymbol.StackFrame->PcAddress, + Control->u.ResolveSymbol.StackFrame->FrameAddress, + Control->u.ResolveSymbol.StackFrame->StackAddress, + &context->PredictedEip, + &context->PredictedEbp, + &context->PredictedEsp + ); + + // Fix up dbghelp EBP with real EBP given by the CLR data routines. + if (Control->u.ResolveSymbol.StackFrame->PcAddress == predictedEip) + { + Control->u.ResolveSymbol.StackFrame->FrameAddress = predictedEbp; + Control->u.ResolveSymbol.StackFrame->StackAddress = predictedEsp; + } +#endif + + managedSymbol = GetRuntimeNameByAddressClrProcess( + context->Support, + (ULONG64)Control->u.ResolveSymbol.StackFrame->PcAddress, + &displacement + ); + } +#ifdef _WIN64 + else if (context->IsWow64 && context->ConnectedToPhSvc) + { + PVOID predictedEip; + PVOID predictedEbp; + PVOID predictedEsp; + + predictedEip = context->PredictedEip; + predictedEbp = context->PredictedEbp; + predictedEsp = context->PredictedEsp; + + CallPredictAddressesFromClrData( + context->ProcessId, + context->ThreadId, + Control->u.ResolveSymbol.StackFrame->PcAddress, + Control->u.ResolveSymbol.StackFrame->FrameAddress, + Control->u.ResolveSymbol.StackFrame->StackAddress, + &context->PredictedEip, + &context->PredictedEbp, + &context->PredictedEsp + ); + + // Fix up dbghelp EBP with real EBP given by the CLR data routines. + if (Control->u.ResolveSymbol.StackFrame->PcAddress == predictedEip) + { + Control->u.ResolveSymbol.StackFrame->FrameAddress = predictedEbp; + Control->u.ResolveSymbol.StackFrame->StackAddress = predictedEsp; + } + + managedSymbol = CallGetRuntimeNameByAddress( + context->ProcessId, + (ULONG64)Control->u.ResolveSymbol.StackFrame->PcAddress, + &displacement + ); + } +#endif + + if (managedSymbol) + { + if (displacement != 0) + PhMoveReference(&managedSymbol, PhFormatString(L"%s + 0x%I64x", managedSymbol->Buffer, displacement)); + + if (Control->u.ResolveSymbol.Symbol) + PhMoveReference(&managedSymbol, PhFormatString(L"%s <-- %s", managedSymbol->Buffer, Control->u.ResolveSymbol.Symbol->Buffer)); + + PhMoveReference(&Control->u.ResolveSymbol.Symbol, managedSymbol); + } + } + break; + case PluginThreadStackBeginDefaultWalkStack: + { + PTHREAD_STACK_CONTEXT context = FindThreadStackContext(Control->UniqueKey); + BOOLEAN isDotNet; + + if (!context) + return; + + if (!NT_SUCCESS(PhGetProcessIsDotNet(context->ProcessId, &isDotNet)) || !isDotNet) + return; + + context->Support = CreateClrProcessSupport(context->ProcessId); + +#ifdef _WIN64 + if (context->IsWow64) + context->ConnectedToPhSvc = PhUiConnectToPhSvcEx(NULL, Wow64PhSvcMode, FALSE); +#endif + } + break; + case PluginThreadStackEndDefaultWalkStack: + { + PTHREAD_STACK_CONTEXT context = FindThreadStackContext(Control->UniqueKey); + + if (!context) + return; + + if (context->Support) + { + FreeClrProcessSupport(context->Support); + context->Support = NULL; + } + +#ifdef _WIN64 + if (context->ConnectedToPhSvc) + { + PhUiDisconnectFromPhSvc(); + context->ConnectedToPhSvc = FALSE; + } +#endif + } + break; + } +} + +VOID PredictAddressesFromClrData( + _In_ PCLR_PROCESS_SUPPORT Support, + _In_ HANDLE ThreadId, + _In_ PVOID PcAddress, + _In_ PVOID FrameAddress, + _In_ PVOID StackAddress, + _Out_ PVOID *PredictedEip, + _Out_ PVOID *PredictedEbp, + _Out_ PVOID *PredictedEsp + ) +{ +#ifdef _WIN64 + *PredictedEip = NULL; + *PredictedEbp = NULL; + *PredictedEsp = NULL; +#else + IXCLRDataTask *task; + + *PredictedEip = NULL; + *PredictedEbp = NULL; + *PredictedEsp = NULL; + + if (SUCCEEDED(IXCLRDataProcess_GetTaskByOSThreadID( + Support->DataProcess, + HandleToUlong(ThreadId), + &task + ))) + { + IXCLRDataStackWalk *stackWalk; + + if (SUCCEEDED(IXCLRDataTask_CreateStackWalk(task, 0xf, &stackWalk))) + { + HRESULT result; + BOOLEAN firstTime = TRUE; + CONTEXT context; + ULONG contextSize; + + memset(&context, 0, sizeof(CONTEXT)); + context.ContextFlags = CONTEXT_CONTROL; + context.Eip = PtrToUlong(PcAddress); + context.Ebp = PtrToUlong(FrameAddress); + context.Esp = PtrToUlong(StackAddress); + + result = IXCLRDataStackWalk_SetContext2(stackWalk, CLRDATA_STACK_SET_CURRENT_CONTEXT, sizeof(CONTEXT), (BYTE *)&context); + + if (SUCCEEDED(result = IXCLRDataStackWalk_Next(stackWalk)) && result != S_FALSE) + { + if (SUCCEEDED(IXCLRDataStackWalk_GetContext(stackWalk, CONTEXT_CONTROL, sizeof(CONTEXT), &contextSize, (BYTE *)&context))) + { + *PredictedEip = UlongToPtr(context.Eip); + *PredictedEbp = UlongToPtr(context.Ebp); + *PredictedEsp = UlongToPtr(context.Esp); + } + } + + IXCLRDataStackWalk_Release(stackWalk); + } + + IXCLRDataTask_Release(task); + } +#endif +} diff --git a/plugins/DotNetTools/svcext.c b/plugins/DotNetTools/svcext.c index 2cd5f14b9608..9606c84307b9 100644 --- a/plugins/DotNetTools/svcext.c +++ b/plugins/DotNetTools/svcext.c @@ -1,209 +1,209 @@ -/* - * Process Hacker .NET Tools - - * phsvc extensions - * - * Copyright (C) 2015 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include "dn.h" -#include "svcext.h" -#include "clrsup.h" - -PPH_STRING CallGetRuntimeNameByAddress( - _In_ HANDLE ProcessId, - _In_ ULONG64 Address, - _Out_opt_ PULONG64 Displacement - ) -{ - NTSTATUS status; - PH_PLUGIN_PHSVC_CLIENT client; - DN_API_GETRUNTIMENAMEBYADDRESS in; - DN_API_GETRUNTIMENAMEBYADDRESS out; - ULONG bufferSize; - PVOID buffer; - PPH_STRING name = NULL; - - if (!PhPluginQueryPhSvc(&client)) - return NULL; - - in.i.ProcessId = HandleToUlong(ProcessId); - in.i.Address = Address; - - bufferSize = 0x1000; - - if (!(buffer = client.CreateString(NULL, bufferSize, &in.i.Name))) - return NULL; - - status = PhPluginCallPhSvc(PluginInstance, DnGetRuntimeNameByAddressApiNumber, &in, sizeof(in), &out, sizeof(out)); - - if (status == STATUS_BUFFER_OVERFLOW) - { - client.FreeHeap(buffer); - bufferSize = out.o.NameLength; - - if (!(buffer = client.CreateString(NULL, bufferSize, &in.i.Name))) - return NULL; - - status = PhPluginCallPhSvc(PluginInstance, DnGetRuntimeNameByAddressApiNumber, &in, sizeof(in), &out, sizeof(out)); - } - - if (NT_SUCCESS(status)) - { - name = PhCreateStringEx(buffer, out.o.NameLength); - - if (Displacement) - *Displacement = out.o.Displacement; - } - - client.FreeHeap(buffer); - - return name; -} - -NTSTATUS DispatchGetRuntimeNameByAddress( - _In_ PPH_PLUGIN_PHSVC_REQUEST Request, - _In_ PDN_API_GETRUNTIMENAMEBYADDRESS In, - _Out_ PDN_API_GETRUNTIMENAMEBYADDRESS Out - ) -{ - NTSTATUS status = STATUS_SUCCESS; - PVOID nameBuffer; - PCLR_PROCESS_SUPPORT support; - PPH_STRING name; - - if (!NT_SUCCESS(status = Request->ProbeBuffer(&In->i.Name, sizeof(WCHAR), FALSE, &nameBuffer))) - return status; - - support = CreateClrProcessSupport(UlongToHandle(In->i.ProcessId)); - - if (!support) - return STATUS_UNSUCCESSFUL; - - name = GetRuntimeNameByAddressClrProcess(support, In->i.Address, &Out->o.Displacement); - - if (!name) - { - status = STATUS_UNSUCCESSFUL; - goto CleanupExit; - } - - memcpy(nameBuffer, name->Buffer, min(name->Length, In->i.Name.Length)); - Out->o.NameLength = (ULONG)name->Length; - - if (In->i.Name.Length < name->Length) - status = STATUS_BUFFER_OVERFLOW; - -CleanupExit: - FreeClrProcessSupport(support); - - return status; -} - -VOID CallPredictAddressesFromClrData( - _In_ HANDLE ProcessId, - _In_ HANDLE ThreadId, - _In_ PVOID PcAddress, - _In_ PVOID FrameAddress, - _In_ PVOID StackAddress, - _Out_ PVOID *PredictedEip, - _Out_ PVOID *PredictedEbp, - _Out_ PVOID *PredictedEsp - ) -{ - PH_PLUGIN_PHSVC_CLIENT client; - DN_API_PREDICTADDRESSESFROMCLRDATA in; - DN_API_PREDICTADDRESSESFROMCLRDATA out; - - *PredictedEip = NULL; - *PredictedEbp = NULL; - *PredictedEsp = NULL; - - if (!PhPluginQueryPhSvc(&client)) - return; - - in.i.ProcessId = HandleToUlong(ProcessId); - in.i.ThreadId = HandleToUlong(ThreadId); - in.i.PcAddress = PtrToUlong(PcAddress); - in.i.FrameAddress = PtrToUlong(FrameAddress); - in.i.StackAddress = PtrToUlong(StackAddress); - - if (NT_SUCCESS(PhPluginCallPhSvc(PluginInstance, DnPredictAddressesFromClrDataApiNumber, &in, sizeof(in), &out, sizeof(out)))) - { - *PredictedEip = UlongToPtr(out.o.PredictedEip); - *PredictedEbp = UlongToPtr(out.o.PredictedEbp); - *PredictedEsp = UlongToPtr(out.o.PredictedEsp); - } -} - -NTSTATUS DispatchPredictAddressesFromClrData( - _In_ PPH_PLUGIN_PHSVC_REQUEST Request, - _In_ PDN_API_PREDICTADDRESSESFROMCLRDATA In, - _Out_ PDN_API_PREDICTADDRESSESFROMCLRDATA Out - ) -{ - PCLR_PROCESS_SUPPORT support; - PVOID predictedEip; - PVOID predictedEbp; - PVOID predictedEsp; - - support = CreateClrProcessSupport(UlongToHandle(In->i.ProcessId)); - - if (!support) - return STATUS_UNSUCCESSFUL; - - PredictAddressesFromClrData( - support, - UlongToHandle(In->i.ThreadId), - UlongToPtr(In->i.PcAddress), - UlongToPtr(In->i.FrameAddress), - UlongToPtr(In->i.StackAddress), - &predictedEip, - &predictedEbp, - &predictedEsp - ); - FreeClrProcessSupport(support); - - Out->o.PredictedEip = PtrToUlong(predictedEip); - Out->o.PredictedEbp = PtrToUlong(predictedEbp); - Out->o.PredictedEsp = PtrToUlong(predictedEsp); - - return STATUS_SUCCESS; -} - -VOID DispatchPhSvcRequest( - _In_ PVOID Parameter - ) -{ - PPH_PLUGIN_PHSVC_REQUEST request = Parameter; - PVOID inBuffer; - - // InBuffer can alias OutBuffer, so make a copy of InBuffer. - inBuffer = PhAllocateCopy(request->InBuffer, request->InLength); - - switch (request->SubId) - { - case DnGetRuntimeNameByAddressApiNumber: - request->ReturnStatus = DispatchGetRuntimeNameByAddress(request, inBuffer, request->OutBuffer); - break; - case DnPredictAddressesFromClrDataApiNumber: - request->ReturnStatus = DispatchPredictAddressesFromClrData(request, inBuffer, request->OutBuffer); - break; - } - - PhFree(inBuffer); -} +/* + * Process Hacker .NET Tools - + * phsvc extensions + * + * Copyright (C) 2015 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include "dn.h" +#include "svcext.h" +#include "clrsup.h" + +PPH_STRING CallGetRuntimeNameByAddress( + _In_ HANDLE ProcessId, + _In_ ULONG64 Address, + _Out_opt_ PULONG64 Displacement + ) +{ + NTSTATUS status; + PH_PLUGIN_PHSVC_CLIENT client; + DN_API_GETRUNTIMENAMEBYADDRESS in; + DN_API_GETRUNTIMENAMEBYADDRESS out; + ULONG bufferSize; + PVOID buffer; + PPH_STRING name = NULL; + + if (!PhPluginQueryPhSvc(&client)) + return NULL; + + in.i.ProcessId = HandleToUlong(ProcessId); + in.i.Address = Address; + + bufferSize = 0x1000; + + if (!(buffer = client.CreateString(NULL, bufferSize, &in.i.Name))) + return NULL; + + status = PhPluginCallPhSvc(PluginInstance, DnGetRuntimeNameByAddressApiNumber, &in, sizeof(in), &out, sizeof(out)); + + if (status == STATUS_BUFFER_OVERFLOW) + { + client.FreeHeap(buffer); + bufferSize = out.o.NameLength; + + if (!(buffer = client.CreateString(NULL, bufferSize, &in.i.Name))) + return NULL; + + status = PhPluginCallPhSvc(PluginInstance, DnGetRuntimeNameByAddressApiNumber, &in, sizeof(in), &out, sizeof(out)); + } + + if (NT_SUCCESS(status)) + { + name = PhCreateStringEx(buffer, out.o.NameLength); + + if (Displacement) + *Displacement = out.o.Displacement; + } + + client.FreeHeap(buffer); + + return name; +} + +NTSTATUS DispatchGetRuntimeNameByAddress( + _In_ PPH_PLUGIN_PHSVC_REQUEST Request, + _In_ PDN_API_GETRUNTIMENAMEBYADDRESS In, + _Out_ PDN_API_GETRUNTIMENAMEBYADDRESS Out + ) +{ + NTSTATUS status = STATUS_SUCCESS; + PVOID nameBuffer; + PCLR_PROCESS_SUPPORT support; + PPH_STRING name; + + if (!NT_SUCCESS(status = Request->ProbeBuffer(&In->i.Name, sizeof(WCHAR), FALSE, &nameBuffer))) + return status; + + support = CreateClrProcessSupport(UlongToHandle(In->i.ProcessId)); + + if (!support) + return STATUS_UNSUCCESSFUL; + + name = GetRuntimeNameByAddressClrProcess(support, In->i.Address, &Out->o.Displacement); + + if (!name) + { + status = STATUS_UNSUCCESSFUL; + goto CleanupExit; + } + + memcpy(nameBuffer, name->Buffer, min(name->Length, In->i.Name.Length)); + Out->o.NameLength = (ULONG)name->Length; + + if (In->i.Name.Length < name->Length) + status = STATUS_BUFFER_OVERFLOW; + +CleanupExit: + FreeClrProcessSupport(support); + + return status; +} + +VOID CallPredictAddressesFromClrData( + _In_ HANDLE ProcessId, + _In_ HANDLE ThreadId, + _In_ PVOID PcAddress, + _In_ PVOID FrameAddress, + _In_ PVOID StackAddress, + _Out_ PVOID *PredictedEip, + _Out_ PVOID *PredictedEbp, + _Out_ PVOID *PredictedEsp + ) +{ + PH_PLUGIN_PHSVC_CLIENT client; + DN_API_PREDICTADDRESSESFROMCLRDATA in; + DN_API_PREDICTADDRESSESFROMCLRDATA out; + + *PredictedEip = NULL; + *PredictedEbp = NULL; + *PredictedEsp = NULL; + + if (!PhPluginQueryPhSvc(&client)) + return; + + in.i.ProcessId = HandleToUlong(ProcessId); + in.i.ThreadId = HandleToUlong(ThreadId); + in.i.PcAddress = PtrToUlong(PcAddress); + in.i.FrameAddress = PtrToUlong(FrameAddress); + in.i.StackAddress = PtrToUlong(StackAddress); + + if (NT_SUCCESS(PhPluginCallPhSvc(PluginInstance, DnPredictAddressesFromClrDataApiNumber, &in, sizeof(in), &out, sizeof(out)))) + { + *PredictedEip = UlongToPtr(out.o.PredictedEip); + *PredictedEbp = UlongToPtr(out.o.PredictedEbp); + *PredictedEsp = UlongToPtr(out.o.PredictedEsp); + } +} + +NTSTATUS DispatchPredictAddressesFromClrData( + _In_ PPH_PLUGIN_PHSVC_REQUEST Request, + _In_ PDN_API_PREDICTADDRESSESFROMCLRDATA In, + _Out_ PDN_API_PREDICTADDRESSESFROMCLRDATA Out + ) +{ + PCLR_PROCESS_SUPPORT support; + PVOID predictedEip; + PVOID predictedEbp; + PVOID predictedEsp; + + support = CreateClrProcessSupport(UlongToHandle(In->i.ProcessId)); + + if (!support) + return STATUS_UNSUCCESSFUL; + + PredictAddressesFromClrData( + support, + UlongToHandle(In->i.ThreadId), + UlongToPtr(In->i.PcAddress), + UlongToPtr(In->i.FrameAddress), + UlongToPtr(In->i.StackAddress), + &predictedEip, + &predictedEbp, + &predictedEsp + ); + FreeClrProcessSupport(support); + + Out->o.PredictedEip = PtrToUlong(predictedEip); + Out->o.PredictedEbp = PtrToUlong(predictedEbp); + Out->o.PredictedEsp = PtrToUlong(predictedEsp); + + return STATUS_SUCCESS; +} + +VOID DispatchPhSvcRequest( + _In_ PVOID Parameter + ) +{ + PPH_PLUGIN_PHSVC_REQUEST request = Parameter; + PVOID inBuffer; + + // InBuffer can alias OutBuffer, so make a copy of InBuffer. + inBuffer = PhAllocateCopy(request->InBuffer, request->InLength); + + switch (request->SubId) + { + case DnGetRuntimeNameByAddressApiNumber: + request->ReturnStatus = DispatchGetRuntimeNameByAddress(request, inBuffer, request->OutBuffer); + break; + case DnPredictAddressesFromClrDataApiNumber: + request->ReturnStatus = DispatchPredictAddressesFromClrData(request, inBuffer, request->OutBuffer); + break; + } + + PhFree(inBuffer); +} diff --git a/plugins/DotNetTools/svcext.h b/plugins/DotNetTools/svcext.h index fc5d63df0374..1600336277f0 100644 --- a/plugins/DotNetTools/svcext.h +++ b/plugins/DotNetTools/svcext.h @@ -1,87 +1,87 @@ -/* - * Process Hacker .NET Tools - - * phsvc extensions - * - * Copyright (C) 2015 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#ifndef SVCEXT_H -#define SVCEXT_H - -// API - -typedef enum _DN_API_NUMBER -{ - DnGetRuntimeNameByAddressApiNumber = 1, - DnPredictAddressesFromClrDataApiNumber = 2 -} DN_API_NUMBER; - -typedef union _DN_API_GETRUNTIMENAMEBYADDRESS -{ - struct - { - ULONG ProcessId; - ULONG Reserved; - ULONG64 Address; - PH_RELATIVE_STRINGREF Name; // out - } i; - struct - { - ULONG64 Displacement; - ULONG NameLength; - } o; -} DN_API_GETRUNTIMENAMEBYADDRESS, *PDN_API_GETRUNTIMENAMEBYADDRESS; - -typedef union _DN_API_PREDICTADDRESSESFROMCLRDATA -{ - struct - { - ULONG ProcessId; - ULONG ThreadId; - ULONG PcAddress; - ULONG FrameAddress; - ULONG StackAddress; - } i; - struct - { - ULONG PredictedEip; - ULONG PredictedEbp; - ULONG PredictedEsp; - } o; -} DN_API_PREDICTADDRESSESFROMCLRDATA, *PDN_API_PREDICTADDRESSESFROMCLRDATA; - -// Calls - -PPH_STRING CallGetRuntimeNameByAddress( - _In_ HANDLE ProcessId, - _In_ ULONG64 Address, - _Out_opt_ PULONG64 Displacement - ); - -VOID CallPredictAddressesFromClrData( - _In_ HANDLE ProcessId, - _In_ HANDLE ThreadId, - _In_ PVOID PcAddress, - _In_ PVOID FrameAddress, - _In_ PVOID StackAddress, - _Out_ PVOID *PredictedEip, - _Out_ PVOID *PredictedEbp, - _Out_ PVOID *PredictedEsp - ); - +/* + * Process Hacker .NET Tools - + * phsvc extensions + * + * Copyright (C) 2015 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#ifndef SVCEXT_H +#define SVCEXT_H + +// API + +typedef enum _DN_API_NUMBER +{ + DnGetRuntimeNameByAddressApiNumber = 1, + DnPredictAddressesFromClrDataApiNumber = 2 +} DN_API_NUMBER; + +typedef union _DN_API_GETRUNTIMENAMEBYADDRESS +{ + struct + { + ULONG ProcessId; + ULONG Reserved; + ULONG64 Address; + PH_RELATIVE_STRINGREF Name; // out + } i; + struct + { + ULONG64 Displacement; + ULONG NameLength; + } o; +} DN_API_GETRUNTIMENAMEBYADDRESS, *PDN_API_GETRUNTIMENAMEBYADDRESS; + +typedef union _DN_API_PREDICTADDRESSESFROMCLRDATA +{ + struct + { + ULONG ProcessId; + ULONG ThreadId; + ULONG PcAddress; + ULONG FrameAddress; + ULONG StackAddress; + } i; + struct + { + ULONG PredictedEip; + ULONG PredictedEbp; + ULONG PredictedEsp; + } o; +} DN_API_PREDICTADDRESSESFROMCLRDATA, *PDN_API_PREDICTADDRESSESFROMCLRDATA; + +// Calls + +PPH_STRING CallGetRuntimeNameByAddress( + _In_ HANDLE ProcessId, + _In_ ULONG64 Address, + _Out_opt_ PULONG64 Displacement + ); + +VOID CallPredictAddressesFromClrData( + _In_ HANDLE ProcessId, + _In_ HANDLE ThreadId, + _In_ PVOID PcAddress, + _In_ PVOID FrameAddress, + _In_ PVOID StackAddress, + _Out_ PVOID *PredictedEip, + _Out_ PVOID *PredictedEbp, + _Out_ PVOID *PredictedEsp + ); + #endif \ No newline at end of file diff --git a/plugins/DotNetTools/treeext.c b/plugins/DotNetTools/treeext.c index 74aea6f14b14..874e899718a9 100644 --- a/plugins/DotNetTools/treeext.c +++ b/plugins/DotNetTools/treeext.c @@ -1,296 +1,296 @@ -/* - * Process Hacker .NET Tools - - * thread list extensions - * - * Copyright (C) 2015 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include "dn.h" -#include "clrsup.h" - -VOID NTAPI ThreadsContextCreateCallback( - _In_ PVOID Object, - _In_ PH_EM_OBJECT_TYPE ObjectType, - _In_ PVOID Extension - ); - -VOID NTAPI ThreadsContextDeleteCallback( - _In_ PVOID Object, - _In_ PH_EM_OBJECT_TYPE ObjectType, - _In_ PVOID Extension - ); - -VOID ThreadTreeNewMessage( - _In_ PVOID Parameter - ); - -LONG ThreadTreeNewSortFunction( - _In_ PVOID Node1, - _In_ PVOID Node2, - _In_ ULONG SubId, - _In_ PVOID Context - ); - -#define THREAD_TREE_CONTEXT_TYPE 1 - -typedef struct _THREAD_TREE_CONTEXT -{ - ULONG Type; - HANDLE ProcessId; - PH_CALLBACK_REGISTRATION AddedCallbackRegistration; - PCLR_PROCESS_SUPPORT Support; -} THREAD_TREE_CONTEXT, *PTHREAD_TREE_CONTEXT; - -static PPH_HASHTABLE ContextHashtable; -static PH_QUEUED_LOCK ContextHashtableLock = PH_QUEUED_LOCK_INIT; -static PH_INITONCE ContextHashtableInitOnce = PH_INITONCE_INIT; - -VOID InitializeTreeNewObjectExtensions( - VOID - ) -{ - PhPluginSetObjectExtension( - PluginInstance, - EmThreadsContextType, - sizeof(THREAD_TREE_CONTEXT), - ThreadsContextCreateCallback, - ThreadsContextDeleteCallback - ); -} - -VOID AddTreeNewColumn( - _In_ PPH_PLUGIN_TREENEW_INFORMATION TreeNewInfo, - _In_ PVOID Context, - _In_ ULONG SubId, - _In_ BOOLEAN Visible, - _In_ PWSTR Text, - _In_ ULONG Width, - _In_ ULONG Alignment, - _In_ ULONG TextFlags, - _In_ BOOLEAN SortDescending, - _In_ PPH_PLUGIN_TREENEW_SORT_FUNCTION SortFunction - ) -{ - PH_TREENEW_COLUMN column; - - memset(&column, 0, sizeof(PH_TREENEW_COLUMN)); - column.Visible = Visible; - column.SortDescending = SortDescending; - column.Text = Text; - column.Width = Width; - column.Alignment = Alignment; - column.DisplayIndex = TreeNew_GetVisibleColumnCount(TreeNewInfo->TreeNewHandle); - column.TextFlags = TextFlags; - - PhPluginAddTreeNewColumn( - PluginInstance, - TreeNewInfo->CmData, - &column, - SubId, - Context, - SortFunction - ); -} - -VOID DispatchTreeNewMessage( - _In_ PVOID Parameter - ) -{ - PPH_PLUGIN_TREENEW_MESSAGE message = Parameter; - - switch (*(PULONG)message->Context) - { - case THREAD_TREE_CONTEXT_TYPE: - ThreadTreeNewMessage(Parameter); - break; - } -} - -static VOID ThreadAddedHandler( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - PPH_THREAD_ITEM threadItem = Parameter; - PDN_THREAD_ITEM dnThread; - PTHREAD_TREE_CONTEXT context = Context; - - dnThread = PhPluginGetObjectExtension(PluginInstance, threadItem, EmThreadItemType); - memset(dnThread, 0, sizeof(DN_THREAD_ITEM)); - dnThread->ThreadItem = threadItem; -} - -VOID NTAPI ThreadsContextCreateCallback( - _In_ PVOID Object, - _In_ PH_EM_OBJECT_TYPE ObjectType, - _In_ PVOID Extension - ) -{ - PPH_THREADS_CONTEXT threadsContext = Object; - PTHREAD_TREE_CONTEXT context = Extension; - - memset(context, 0, sizeof(THREAD_TREE_CONTEXT)); - context->Type = THREAD_TREE_CONTEXT_TYPE; - context->ProcessId = threadsContext->Provider->ProcessId; - - PhRegisterCallback( - &threadsContext->Provider->ThreadAddedEvent, - ThreadAddedHandler, - context, - &context->AddedCallbackRegistration - ); -} - -VOID NTAPI ThreadsContextDeleteCallback( - _In_ PVOID Object, - _In_ PH_EM_OBJECT_TYPE ObjectType, - _In_ PVOID Extension - ) -{ - PPH_THREADS_CONTEXT threadsContext = Object; - PTHREAD_TREE_CONTEXT context = Extension; - - PhUnregisterCallback( - &threadsContext->Provider->ThreadAddedEvent, - &context->AddedCallbackRegistration - ); - - if (context->Support) - FreeClrProcessSupport(context->Support); -} - -VOID ThreadTreeNewInitializing( - _In_ PVOID Parameter - ) -{ - PPH_PLUGIN_TREENEW_INFORMATION info = Parameter; - PPH_THREADS_CONTEXT threadsContext; - PTHREAD_TREE_CONTEXT context; - BOOLEAN isDotNet; - - threadsContext = info->SystemContext; - context = PhPluginGetObjectExtension(PluginInstance, threadsContext, EmThreadsContextType); - - if (NT_SUCCESS(PhGetProcessIsDotNet(threadsContext->Provider->ProcessId, &isDotNet)) && isDotNet) - { - PCLR_PROCESS_SUPPORT support; - - support = CreateClrProcessSupport(threadsContext->Provider->ProcessId); - - if (!support) - return; - - context->Support = support; - - AddTreeNewColumn(info, context, DNTHTNC_APPDOMAIN, TRUE, L"AppDomain", 120, PH_ALIGN_LEFT, 0, FALSE, ThreadTreeNewSortFunction); - } -} - -VOID ThreadTreeNewUninitializing( - _In_ PVOID Parameter - ) -{ - NOTHING; -} - -VOID UpdateThreadClrData( - _In_ PTHREAD_TREE_CONTEXT Context, - _Inout_ PDN_THREAD_ITEM DnThread - ) -{ - if (!DnThread->ClrDataValid) - { - IXCLRDataProcess *process; - IXCLRDataTask *task; - IXCLRDataAppDomain *appDomain; - - if (Context->Support) - process = Context->Support->DataProcess; - else - return; - - if (SUCCEEDED(IXCLRDataProcess_GetTaskByOSThreadID(process, HandleToUlong(DnThread->ThreadItem->ThreadId), &task))) - { - if (SUCCEEDED(IXCLRDataTask_GetCurrentAppDomain(task, &appDomain))) - { - DnThread->AppDomainText = GetNameXClrDataAppDomain(appDomain); - IXCLRDataAppDomain_Release(appDomain); - } - - IXCLRDataTask_Release(task); - } - - DnThread->ClrDataValid = TRUE; - } -} - -VOID ThreadTreeNewMessage( - _In_ PVOID Parameter - ) -{ - PPH_PLUGIN_TREENEW_MESSAGE message = Parameter; - PTHREAD_TREE_CONTEXT context = message->Context; - - if (message->Message == TreeNewGetCellText) - { - PPH_TREENEW_GET_CELL_TEXT getCellText = message->Parameter1; - PPH_THREAD_NODE threadNode = (PPH_THREAD_NODE)getCellText->Node; - PDN_THREAD_ITEM dnThread; - - dnThread = PhPluginGetObjectExtension(PluginInstance, threadNode->ThreadItem, EmThreadItemType); - - switch (message->SubId) - { - case DNTHTNC_APPDOMAIN: - UpdateThreadClrData(context, dnThread); - getCellText->Text = PhGetStringRef(dnThread->AppDomainText); - break; - } - } -} - -LONG ThreadTreeNewSortFunction( - _In_ PVOID Node1, - _In_ PVOID Node2, - _In_ ULONG SubId, - _In_ PVOID Context - ) -{ - PTHREAD_TREE_CONTEXT context = Context; - LONG result; - PPH_THREAD_NODE node1 = Node1; - PPH_THREAD_NODE node2 = Node2; - PDN_THREAD_ITEM dnThread1; - PDN_THREAD_ITEM dnThread2; - - dnThread1 = PhPluginGetObjectExtension(PluginInstance, node1->ThreadItem, EmThreadItemType); - dnThread2 = PhPluginGetObjectExtension(PluginInstance, node2->ThreadItem, EmThreadItemType); - - result = 0; - - switch (SubId) - { - case DNTHTNC_APPDOMAIN: - UpdateThreadClrData(context, dnThread1); - UpdateThreadClrData(context, dnThread2); - result = PhCompareStringWithNull(dnThread1->AppDomainText, dnThread2->AppDomainText, TRUE); - break; - } - - return result; -} +/* + * Process Hacker .NET Tools - + * thread list extensions + * + * Copyright (C) 2015 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include "dn.h" +#include "clrsup.h" + +VOID NTAPI ThreadsContextCreateCallback( + _In_ PVOID Object, + _In_ PH_EM_OBJECT_TYPE ObjectType, + _In_ PVOID Extension + ); + +VOID NTAPI ThreadsContextDeleteCallback( + _In_ PVOID Object, + _In_ PH_EM_OBJECT_TYPE ObjectType, + _In_ PVOID Extension + ); + +VOID ThreadTreeNewMessage( + _In_ PVOID Parameter + ); + +LONG ThreadTreeNewSortFunction( + _In_ PVOID Node1, + _In_ PVOID Node2, + _In_ ULONG SubId, + _In_ PVOID Context + ); + +#define THREAD_TREE_CONTEXT_TYPE 1 + +typedef struct _THREAD_TREE_CONTEXT +{ + ULONG Type; + HANDLE ProcessId; + PH_CALLBACK_REGISTRATION AddedCallbackRegistration; + PCLR_PROCESS_SUPPORT Support; +} THREAD_TREE_CONTEXT, *PTHREAD_TREE_CONTEXT; + +static PPH_HASHTABLE ContextHashtable; +static PH_QUEUED_LOCK ContextHashtableLock = PH_QUEUED_LOCK_INIT; +static PH_INITONCE ContextHashtableInitOnce = PH_INITONCE_INIT; + +VOID InitializeTreeNewObjectExtensions( + VOID + ) +{ + PhPluginSetObjectExtension( + PluginInstance, + EmThreadsContextType, + sizeof(THREAD_TREE_CONTEXT), + ThreadsContextCreateCallback, + ThreadsContextDeleteCallback + ); +} + +VOID AddTreeNewColumn( + _In_ PPH_PLUGIN_TREENEW_INFORMATION TreeNewInfo, + _In_ PVOID Context, + _In_ ULONG SubId, + _In_ BOOLEAN Visible, + _In_ PWSTR Text, + _In_ ULONG Width, + _In_ ULONG Alignment, + _In_ ULONG TextFlags, + _In_ BOOLEAN SortDescending, + _In_ PPH_PLUGIN_TREENEW_SORT_FUNCTION SortFunction + ) +{ + PH_TREENEW_COLUMN column; + + memset(&column, 0, sizeof(PH_TREENEW_COLUMN)); + column.Visible = Visible; + column.SortDescending = SortDescending; + column.Text = Text; + column.Width = Width; + column.Alignment = Alignment; + column.DisplayIndex = TreeNew_GetVisibleColumnCount(TreeNewInfo->TreeNewHandle); + column.TextFlags = TextFlags; + + PhPluginAddTreeNewColumn( + PluginInstance, + TreeNewInfo->CmData, + &column, + SubId, + Context, + SortFunction + ); +} + +VOID DispatchTreeNewMessage( + _In_ PVOID Parameter + ) +{ + PPH_PLUGIN_TREENEW_MESSAGE message = Parameter; + + switch (*(PULONG)message->Context) + { + case THREAD_TREE_CONTEXT_TYPE: + ThreadTreeNewMessage(Parameter); + break; + } +} + +static VOID ThreadAddedHandler( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + PPH_THREAD_ITEM threadItem = Parameter; + PDN_THREAD_ITEM dnThread; + PTHREAD_TREE_CONTEXT context = Context; + + dnThread = PhPluginGetObjectExtension(PluginInstance, threadItem, EmThreadItemType); + memset(dnThread, 0, sizeof(DN_THREAD_ITEM)); + dnThread->ThreadItem = threadItem; +} + +VOID NTAPI ThreadsContextCreateCallback( + _In_ PVOID Object, + _In_ PH_EM_OBJECT_TYPE ObjectType, + _In_ PVOID Extension + ) +{ + PPH_THREADS_CONTEXT threadsContext = Object; + PTHREAD_TREE_CONTEXT context = Extension; + + memset(context, 0, sizeof(THREAD_TREE_CONTEXT)); + context->Type = THREAD_TREE_CONTEXT_TYPE; + context->ProcessId = threadsContext->Provider->ProcessId; + + PhRegisterCallback( + &threadsContext->Provider->ThreadAddedEvent, + ThreadAddedHandler, + context, + &context->AddedCallbackRegistration + ); +} + +VOID NTAPI ThreadsContextDeleteCallback( + _In_ PVOID Object, + _In_ PH_EM_OBJECT_TYPE ObjectType, + _In_ PVOID Extension + ) +{ + PPH_THREADS_CONTEXT threadsContext = Object; + PTHREAD_TREE_CONTEXT context = Extension; + + PhUnregisterCallback( + &threadsContext->Provider->ThreadAddedEvent, + &context->AddedCallbackRegistration + ); + + if (context->Support) + FreeClrProcessSupport(context->Support); +} + +VOID ThreadTreeNewInitializing( + _In_ PVOID Parameter + ) +{ + PPH_PLUGIN_TREENEW_INFORMATION info = Parameter; + PPH_THREADS_CONTEXT threadsContext; + PTHREAD_TREE_CONTEXT context; + BOOLEAN isDotNet; + + threadsContext = info->SystemContext; + context = PhPluginGetObjectExtension(PluginInstance, threadsContext, EmThreadsContextType); + + if (NT_SUCCESS(PhGetProcessIsDotNet(threadsContext->Provider->ProcessId, &isDotNet)) && isDotNet) + { + PCLR_PROCESS_SUPPORT support; + + support = CreateClrProcessSupport(threadsContext->Provider->ProcessId); + + if (!support) + return; + + context->Support = support; + + AddTreeNewColumn(info, context, DNTHTNC_APPDOMAIN, TRUE, L"AppDomain", 120, PH_ALIGN_LEFT, 0, FALSE, ThreadTreeNewSortFunction); + } +} + +VOID ThreadTreeNewUninitializing( + _In_ PVOID Parameter + ) +{ + NOTHING; +} + +VOID UpdateThreadClrData( + _In_ PTHREAD_TREE_CONTEXT Context, + _Inout_ PDN_THREAD_ITEM DnThread + ) +{ + if (!DnThread->ClrDataValid) + { + IXCLRDataProcess *process; + IXCLRDataTask *task; + IXCLRDataAppDomain *appDomain; + + if (Context->Support) + process = Context->Support->DataProcess; + else + return; + + if (SUCCEEDED(IXCLRDataProcess_GetTaskByOSThreadID(process, HandleToUlong(DnThread->ThreadItem->ThreadId), &task))) + { + if (SUCCEEDED(IXCLRDataTask_GetCurrentAppDomain(task, &appDomain))) + { + DnThread->AppDomainText = GetNameXClrDataAppDomain(appDomain); + IXCLRDataAppDomain_Release(appDomain); + } + + IXCLRDataTask_Release(task); + } + + DnThread->ClrDataValid = TRUE; + } +} + +VOID ThreadTreeNewMessage( + _In_ PVOID Parameter + ) +{ + PPH_PLUGIN_TREENEW_MESSAGE message = Parameter; + PTHREAD_TREE_CONTEXT context = message->Context; + + if (message->Message == TreeNewGetCellText) + { + PPH_TREENEW_GET_CELL_TEXT getCellText = message->Parameter1; + PPH_THREAD_NODE threadNode = (PPH_THREAD_NODE)getCellText->Node; + PDN_THREAD_ITEM dnThread; + + dnThread = PhPluginGetObjectExtension(PluginInstance, threadNode->ThreadItem, EmThreadItemType); + + switch (message->SubId) + { + case DNTHTNC_APPDOMAIN: + UpdateThreadClrData(context, dnThread); + getCellText->Text = PhGetStringRef(dnThread->AppDomainText); + break; + } + } +} + +LONG ThreadTreeNewSortFunction( + _In_ PVOID Node1, + _In_ PVOID Node2, + _In_ ULONG SubId, + _In_ PVOID Context + ) +{ + PTHREAD_TREE_CONTEXT context = Context; + LONG result; + PPH_THREAD_NODE node1 = Node1; + PPH_THREAD_NODE node2 = Node2; + PDN_THREAD_ITEM dnThread1; + PDN_THREAD_ITEM dnThread2; + + dnThread1 = PhPluginGetObjectExtension(PluginInstance, node1->ThreadItem, EmThreadItemType); + dnThread2 = PhPluginGetObjectExtension(PluginInstance, node2->ThreadItem, EmThreadItemType); + + result = 0; + + switch (SubId) + { + case DNTHTNC_APPDOMAIN: + UpdateThreadClrData(context, dnThread1); + UpdateThreadClrData(context, dnThread2); + result = PhCompareStringWithNull(dnThread1->AppDomainText, dnThread2->AppDomainText, TRUE); + break; + } + + return result; +} diff --git a/plugins/ExtendedNotifications/CHANGELOG.txt b/plugins/ExtendedNotifications/CHANGELOG.txt index 7aa9f64a6466..6ac5c90393ec 100644 --- a/plugins/ExtendedNotifications/CHANGELOG.txt +++ b/plugins/ExtendedNotifications/CHANGELOG.txt @@ -1,11 +1,11 @@ -1.3 - * Added Growl support - -1.2 - * Added ability to log events to a file - -1.1 - * Fixed memory leak - -1.0 - * Initial release +1.3 + * Added Growl support + +1.2 + * Added ability to log events to a file + +1.1 + * Fixed memory leak + +1.0 + * Initial release diff --git a/plugins/ExtendedNotifications/ExtendedNotifications.rc b/plugins/ExtendedNotifications/ExtendedNotifications.rc index 63a61c3bfdc9..ce5be6f4bd35 100644 --- a/plugins/ExtendedNotifications/ExtendedNotifications.rc +++ b/plugins/ExtendedNotifications/ExtendedNotifications.rc @@ -1,214 +1,214 @@ -// Microsoft Visual C++ generated resource script. -// -#include "resource.h" - -#define APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// -#include "winres.h" -///////////////////////////////////////////////////////////////////////////// -#undef APSTUDIO_READONLY_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -// English (Australia) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENA) -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_AUS -#pragma code_page(1252) - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -1 TEXTINCLUDE -BEGIN - "resource.h\0" -END - -2 TEXTINCLUDE -BEGIN - "#include ""winres.h""\0" -END - -3 TEXTINCLUDE -BEGIN - "\r\n" - "\0" -END - -#endif // APSTUDIO_INVOKED - - -///////////////////////////////////////////////////////////////////////////// -// -// Version -// - -VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,3,0,0 - PRODUCTVERSION 1,3,0,0 - FILEFLAGSMASK 0x3fL -#ifdef _DEBUG - FILEFLAGS 0x1L -#else - FILEFLAGS 0x0L -#endif - FILEOS 0x40004L - FILETYPE 0x2L - FILESUBTYPE 0x0L -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "0c0904b0" - BEGIN - VALUE "CompanyName", "wj32" - VALUE "FileDescription", "Extended Notifications for Process Hacker" - VALUE "FileVersion", "1.3" - VALUE "InternalName", "ProcessHacker.ExtendedNotifications" - VALUE "LegalCopyright", "Licensed under the GNU GPL, v3." - VALUE "OriginalFilename", "ExtendedNotifications.dll" - VALUE "ProductName", "Extended Notifications for Process Hacker" - VALUE "ProductVersion", "1.3" - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0xc09, 1200 - END -END - - -///////////////////////////////////////////////////////////////////////////// -// -// Dialog -// - -IDD_PROCESSES DIALOGEX 0, 0, 255, 229 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Processes" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "You can configure processes for which notifications are displayed. Wildcards can be used, and ordering is considered.",IDC_STATIC,7,7,241,19 - LISTBOX IDC_LIST,7,30,187,118,LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP - PUSHBUTTON "Move up",IDC_MOVEUP,198,30,50,14 - PUSHBUTTON "Move down",IDC_MOVEDOWN,198,47,50,14 - EDITTEXT IDC_TEXT,7,152,147,12,ES_AUTOHSCROLL - CONTROL "Include",IDC_INCLUDE,"Button",BS_AUTORADIOBUTTON,163,153,39,10 - CONTROL "Exclude",IDC_EXCLUDE,"Button",BS_AUTORADIOBUTTON,207,153,41,10 - PUSHBUTTON "Add/Update",IDC_ADD,145,168,50,14 - PUSHBUTTON "Remove",IDC_REMOVE,198,168,50,14 - LTEXT "Examples:\nnote*.exe\nC:\\Windows\\system32\\cmd.exe\nC:\\Windows\\*",IDC_STATIC,7,186,241,36 -END - -IDD_SERVICES DIALOGEX 0, 0, 255, 229 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Services" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "You can configure services for which notifications are displayed. Wildcards can be used, and ordering is considered.",IDC_STATIC,7,7,241,19 - LISTBOX IDC_LIST,7,30,187,118,LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP - PUSHBUTTON "Move up",IDC_MOVEUP,198,30,50,14 - PUSHBUTTON "Move down",IDC_MOVEDOWN,198,47,50,14 - EDITTEXT IDC_TEXT,7,152,147,12,ES_AUTOHSCROLL - CONTROL "Include",IDC_INCLUDE,"Button",BS_AUTORADIOBUTTON,163,153,39,10 - CONTROL "Exclude",IDC_EXCLUDE,"Button",BS_AUTORADIOBUTTON,207,153,41,10 - PUSHBUTTON "Add/Update",IDC_ADD,145,168,50,14 - PUSHBUTTON "Remove",IDC_REMOVE,198,168,50,14 - LTEXT "Examples:\nWdi*\nseclogon",IDC_STATIC,7,186,241,36 -END - -IDD_LOGGING DIALOGEX 0, 0, 255, 229 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Logging" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - GROUPBOX "File",IDC_STATIC,7,7,241,53 - LTEXT "Log all events to this file (leave blank to disable this feature):",IDC_STATIC,13,18,196,8 - EDITTEXT IDC_LOGFILENAME,13,29,178,12,ES_AUTOHSCROLL - PUSHBUTTON "Browse...",IDC_BROWSE,194,28,50,14 - LTEXT "Changes will require a restart of Process Hacker.",IDC_STATIC,14,45,157,8 -END - -IDD_GROWL DIALOGEX 0, 0, 255, 229 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Growl" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - CONTROL "Send notifications to Growl",IDC_ENABLEGROWL,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,7,101,10 - LTEXT "gntp-send license:",IDC_STATIC,7,23,60,8 - EDITTEXT IDC_LICENSE,7,34,241,188,ES_MULTILINE | ES_AUTOHSCROLL | ES_READONLY | WS_VSCROLL | WS_HSCROLL -END - - -///////////////////////////////////////////////////////////////////////////// -// -// DESIGNINFO -// - -#ifdef APSTUDIO_INVOKED -GUIDELINES DESIGNINFO -BEGIN - IDD_PROCESSES, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 248 - TOPMARGIN, 7 - BOTTOMMARGIN, 222 - END - - IDD_SERVICES, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 248 - TOPMARGIN, 7 - BOTTOMMARGIN, 222 - END - - IDD_LOGGING, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 248 - TOPMARGIN, 7 - BOTTOMMARGIN, 222 - END - - IDD_GROWL, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 248 - TOPMARGIN, 7 - BOTTOMMARGIN, 222 - END -END -#endif // APSTUDIO_INVOKED - - -///////////////////////////////////////////////////////////////////////////// -// -// AFX_DIALOG_LAYOUT -// - -IDD_GROWL AFX_DIALOG_LAYOUT -BEGIN - 0 -END - -#endif // English (Australia) resources -///////////////////////////////////////////////////////////////////////////// - - - -#ifndef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// - - -///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED - +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "winres.h" +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (Australia) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENA) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_AUS +#pragma code_page(1252) + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""winres.h""\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,3,0,0 + PRODUCTVERSION 1,3,0,0 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "0c0904b0" + BEGIN + VALUE "CompanyName", "wj32" + VALUE "FileDescription", "Extended Notifications for Process Hacker" + VALUE "FileVersion", "1.3" + VALUE "InternalName", "ProcessHacker.ExtendedNotifications" + VALUE "LegalCopyright", "Licensed under the GNU GPL, v3." + VALUE "OriginalFilename", "ExtendedNotifications.dll" + VALUE "ProductName", "Extended Notifications for Process Hacker" + VALUE "ProductVersion", "1.3" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0xc09, 1200 + END +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_PROCESSES DIALOGEX 0, 0, 255, 229 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Processes" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "You can configure processes for which notifications are displayed. Wildcards can be used, and ordering is considered.",IDC_STATIC,7,7,241,19 + LISTBOX IDC_LIST,7,30,187,118,LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Move up",IDC_MOVEUP,198,30,50,14 + PUSHBUTTON "Move down",IDC_MOVEDOWN,198,47,50,14 + EDITTEXT IDC_TEXT,7,152,147,12,ES_AUTOHSCROLL + CONTROL "Include",IDC_INCLUDE,"Button",BS_AUTORADIOBUTTON,163,153,39,10 + CONTROL "Exclude",IDC_EXCLUDE,"Button",BS_AUTORADIOBUTTON,207,153,41,10 + PUSHBUTTON "Add/Update",IDC_ADD,145,168,50,14 + PUSHBUTTON "Remove",IDC_REMOVE,198,168,50,14 + LTEXT "Examples:\nnote*.exe\nC:\\Windows\\system32\\cmd.exe\nC:\\Windows\\*",IDC_STATIC,7,186,241,36 +END + +IDD_SERVICES DIALOGEX 0, 0, 255, 229 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Services" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "You can configure services for which notifications are displayed. Wildcards can be used, and ordering is considered.",IDC_STATIC,7,7,241,19 + LISTBOX IDC_LIST,7,30,187,118,LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Move up",IDC_MOVEUP,198,30,50,14 + PUSHBUTTON "Move down",IDC_MOVEDOWN,198,47,50,14 + EDITTEXT IDC_TEXT,7,152,147,12,ES_AUTOHSCROLL + CONTROL "Include",IDC_INCLUDE,"Button",BS_AUTORADIOBUTTON,163,153,39,10 + CONTROL "Exclude",IDC_EXCLUDE,"Button",BS_AUTORADIOBUTTON,207,153,41,10 + PUSHBUTTON "Add/Update",IDC_ADD,145,168,50,14 + PUSHBUTTON "Remove",IDC_REMOVE,198,168,50,14 + LTEXT "Examples:\nWdi*\nseclogon",IDC_STATIC,7,186,241,36 +END + +IDD_LOGGING DIALOGEX 0, 0, 255, 229 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Logging" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + GROUPBOX "File",IDC_STATIC,7,7,241,53 + LTEXT "Log all events to this file (leave blank to disable this feature):",IDC_STATIC,13,18,196,8 + EDITTEXT IDC_LOGFILENAME,13,29,178,12,ES_AUTOHSCROLL + PUSHBUTTON "Browse...",IDC_BROWSE,194,28,50,14 + LTEXT "Changes will require a restart of Process Hacker.",IDC_STATIC,14,45,157,8 +END + +IDD_GROWL DIALOGEX 0, 0, 255, 229 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Growl" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + CONTROL "Send notifications to Growl",IDC_ENABLEGROWL,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,7,101,10 + LTEXT "gntp-send license:",IDC_STATIC,7,23,60,8 + EDITTEXT IDC_LICENSE,7,34,241,188,ES_MULTILINE | ES_AUTOHSCROLL | ES_READONLY | WS_VSCROLL | WS_HSCROLL +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_PROCESSES, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 248 + TOPMARGIN, 7 + BOTTOMMARGIN, 222 + END + + IDD_SERVICES, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 248 + TOPMARGIN, 7 + BOTTOMMARGIN, 222 + END + + IDD_LOGGING, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 248 + TOPMARGIN, 7 + BOTTOMMARGIN, 222 + END + + IDD_GROWL, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 248 + TOPMARGIN, 7 + BOTTOMMARGIN, 222 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// AFX_DIALOG_LAYOUT +// + +IDD_GROWL AFX_DIALOG_LAYOUT +BEGIN + 0 +END + +#endif // English (Australia) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/plugins/ExtendedNotifications/ExtendedNotifications.vcxproj b/plugins/ExtendedNotifications/ExtendedNotifications.vcxproj index 7ad9d1b93021..348d996c5ca4 100644 --- a/plugins/ExtendedNotifications/ExtendedNotifications.vcxproj +++ b/plugins/ExtendedNotifications/ExtendedNotifications.vcxproj @@ -1,99 +1,99 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {80E791B8-AC98-407E-8FF9-5154AF50E887} - ExtendedNotifications - Win32Proj - ExtendedNotifications - 10.0.15063.0 - - - - DynamicLibrary - Unicode - v141 - - - DynamicLibrary - Unicode - v141 - - - DynamicLibrary - Unicode - v141 - - - DynamicLibrary - Unicode - v141 - - - - - - - - - ws2_32.lib;%(AdditionalDependencies) - ws2_32.dll;%(DelayLoadDLLs) - - - - - ws2_32.lib;%(AdditionalDependencies) - ws2_32.dll;%(DelayLoadDLLs) - - - - - ws2_32.lib;%(AdditionalDependencies) - ws2_32.dll;%(DelayLoadDLLs) - - - - - ws2_32.lib;%(AdditionalDependencies) - ws2_32.dll;%(DelayLoadDLLs) - - - - - - - - - - - - - - - - - - - - - - - + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {80E791B8-AC98-407E-8FF9-5154AF50E887} + ExtendedNotifications + Win32Proj + ExtendedNotifications + 10.0.15063.0 + + + + DynamicLibrary + Unicode + v141 + + + DynamicLibrary + Unicode + v141 + + + DynamicLibrary + Unicode + v141 + + + DynamicLibrary + Unicode + v141 + + + + + + + + + ws2_32.lib;%(AdditionalDependencies) + ws2_32.dll;%(DelayLoadDLLs) + + + + + ws2_32.lib;%(AdditionalDependencies) + ws2_32.dll;%(DelayLoadDLLs) + + + + + ws2_32.lib;%(AdditionalDependencies) + ws2_32.dll;%(DelayLoadDLLs) + + + + + ws2_32.lib;%(AdditionalDependencies) + ws2_32.dll;%(DelayLoadDLLs) + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/plugins/ExtendedNotifications/extnoti.h b/plugins/ExtendedNotifications/extnoti.h index d3661c27ff34..1f72045458ca 100644 --- a/plugins/ExtendedNotifications/extnoti.h +++ b/plugins/ExtendedNotifications/extnoti.h @@ -1,30 +1,30 @@ -#ifndef EXTNOTI_H -#define EXTNOTI_H - -#define PLUGIN_NAME L"ProcessHacker.ExtendedNotifications" -#define SETTING_NAME_ENABLE_GROWL (PLUGIN_NAME L".EnableGrowl") -#define SETTING_NAME_LOG_FILENAME (PLUGIN_NAME L".LogFileName") -#define SETTING_NAME_PROCESS_LIST (PLUGIN_NAME L".ProcessList") -#define SETTING_NAME_SERVICE_LIST (PLUGIN_NAME L".ServiceList") - -// main - -typedef enum _FILTER_TYPE -{ - FilterInclude, - FilterExclude -} FILTER_TYPE; - -typedef struct _FILTER_ENTRY -{ - FILTER_TYPE Type; - PPH_STRING Filter; -} FILTER_ENTRY, *PFILTER_ENTRY; - -// filelog - -VOID FileLogInitialization( - VOID - ); - -#endif +#ifndef EXTNOTI_H +#define EXTNOTI_H + +#define PLUGIN_NAME L"ProcessHacker.ExtendedNotifications" +#define SETTING_NAME_ENABLE_GROWL (PLUGIN_NAME L".EnableGrowl") +#define SETTING_NAME_LOG_FILENAME (PLUGIN_NAME L".LogFileName") +#define SETTING_NAME_PROCESS_LIST (PLUGIN_NAME L".ProcessList") +#define SETTING_NAME_SERVICE_LIST (PLUGIN_NAME L".ServiceList") + +// main + +typedef enum _FILTER_TYPE +{ + FilterInclude, + FilterExclude +} FILTER_TYPE; + +typedef struct _FILTER_ENTRY +{ + FILTER_TYPE Type; + PPH_STRING Filter; +} FILTER_ENTRY, *PFILTER_ENTRY; + +// filelog + +VOID FileLogInitialization( + VOID + ); + +#endif diff --git a/plugins/ExtendedNotifications/filelog.c b/plugins/ExtendedNotifications/filelog.c index b77492940100..372dc978958b 100644 --- a/plugins/ExtendedNotifications/filelog.c +++ b/plugins/ExtendedNotifications/filelog.c @@ -1,79 +1,79 @@ -/* - * Process Hacker Extended Notifications - - * file logging - * - * Copyright (C) 2010 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include -#include "extnoti.h" - -VOID NTAPI LoggedCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ); - -PPH_FILE_STREAM LogFileStream = NULL; -PH_CALLBACK_REGISTRATION LoggedCallbackRegistration; - -VOID FileLogInitialization( - VOID - ) -{ - NTSTATUS status; - PPH_STRING fileName; - - fileName = PhaGetStringSetting(SETTING_NAME_LOG_FILENAME); - - if (fileName->Length != 0) - { - status = PhCreateFileStream( - &LogFileStream, - fileName->Buffer, - FILE_GENERIC_WRITE, - FILE_SHARE_READ, - FILE_OPEN_IF, - PH_FILE_STREAM_APPEND | PH_FILE_STREAM_UNBUFFERED - ); - - if (NT_SUCCESS(status)) - { - PhRegisterCallback( - &PhLoggedCallback, - LoggedCallback, - NULL, - &LoggedCallbackRegistration - ); - } - } -} - -VOID NTAPI LoggedCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - PPH_LOG_ENTRY logEntry = Parameter; - - PhWriteStringFormatAsUtf8FileStream( - LogFileStream, - L"%s: %s\r\n", - PhaFormatDateTime(NULL)->Buffer, - PH_AUTO_T(PH_STRING, PhFormatLogEntry(logEntry))->Buffer - ); -} +/* + * Process Hacker Extended Notifications - + * file logging + * + * Copyright (C) 2010 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include +#include "extnoti.h" + +VOID NTAPI LoggedCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ); + +PPH_FILE_STREAM LogFileStream = NULL; +PH_CALLBACK_REGISTRATION LoggedCallbackRegistration; + +VOID FileLogInitialization( + VOID + ) +{ + NTSTATUS status; + PPH_STRING fileName; + + fileName = PhaGetStringSetting(SETTING_NAME_LOG_FILENAME); + + if (fileName->Length != 0) + { + status = PhCreateFileStream( + &LogFileStream, + fileName->Buffer, + FILE_GENERIC_WRITE, + FILE_SHARE_READ, + FILE_OPEN_IF, + PH_FILE_STREAM_APPEND | PH_FILE_STREAM_UNBUFFERED + ); + + if (NT_SUCCESS(status)) + { + PhRegisterCallback( + &PhLoggedCallback, + LoggedCallback, + NULL, + &LoggedCallbackRegistration + ); + } + } +} + +VOID NTAPI LoggedCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + PPH_LOG_ENTRY logEntry = Parameter; + + PhWriteStringFormatAsUtf8FileStream( + LogFileStream, + L"%s: %s\r\n", + PhaFormatDateTime(NULL)->Buffer, + PH_AUTO_T(PH_STRING, PhFormatLogEntry(logEntry))->Buffer + ); +} diff --git a/plugins/ExtendedNotifications/gntp-send/LICENSE.txt b/plugins/ExtendedNotifications/gntp-send/LICENSE.txt index 40b0fa4c4916..a7e6a122d3be 100644 --- a/plugins/ExtendedNotifications/gntp-send/LICENSE.txt +++ b/plugins/ExtendedNotifications/gntp-send/LICENSE.txt @@ -1,26 +1,26 @@ -[The "BSD licence"] -Copyright (c) 2009-2010 Yasuhiro Matsumoto -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: - - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - 3. The name of the author may not be used to endorse or promote products - derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +[The "BSD licence"] +Copyright (c) 2009-2010 Yasuhiro Matsumoto +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/plugins/ExtendedNotifications/gntp-send/growl.c b/plugins/ExtendedNotifications/gntp-send/growl.c index 86858a5b9b0f..4812ddaf061f 100644 --- a/plugins/ExtendedNotifications/gntp-send/growl.c +++ b/plugins/ExtendedNotifications/gntp-send/growl.c @@ -1,537 +1,537 @@ -#define _CRT_RAND_S -#include -#include -#include -#include -#include -#include - -#include "md5.h" -#include "tcp.h" -#include "growl.h" - -static const char hex_table[] = "0123456789ABCDEF"; -static char* string_to_hex_alloc(const char* str, int len) { - int n, l; - char* tmp = (char*)PhAllocateSafe(len * 2 + 1); - if (tmp) { - memset(tmp, 0, len * 2 + 1); - for (l = 0, n = 0; l < len; l++) { - tmp[n++] = hex_table[(str[l] & 0xF0) >> 4]; - tmp[n++] = hex_table[str[l] & 0x0F]; - } - } - return tmp; -} - -int growl_init_ = 0; - -/* dmex: modified to use latest Winsock version */ -int growl_init() -{ - if (growl_init_ == 0) - { -#ifdef _WIN32 - WSADATA wsaData; - if (WSAStartup(WINSOCK_VERSION, &wsaData) != 0) - { - return -1; - } -#endif - - growl_init_ = 1; - } - return 1; -} - - -void growl_shutdown() -{ - if (growl_init_ == 1) - { -#ifdef _WIN32 - WSACleanup(); -#endif - } -} - -/* dmex: modified with enhancements */ -PPH_BYTES gen_salt_alloc(int count) -{ - PPH_STRING saltString; - PPH_BYTES saltBytes; - - saltString = PhCreateStringEx(NULL, count * 2 + 2); - PhGenerateRandomAlphaString(saltString->Buffer, (ULONG)saltString->Length / sizeof(WCHAR)); - saltBytes = PhConvertUtf16ToUtf8(saltString->Buffer); - PhDereferenceObject(saltString); - - return saltBytes; -} - -char* gen_password_hash_alloc(const char* password, const char* salt) { - md5_context md5ctx; - char md5tmp[20]; - char* md5digest; - - memset(md5tmp, 0, sizeof(md5tmp)); - md5_starts(&md5ctx); - md5_update(&md5ctx, (uint8_t*)password, (uint32_t)strlen(password)); - md5_update(&md5ctx, (uint8_t*)salt, (uint32_t)strlen(salt)); - md5_finish(&md5ctx, (uint8_t*)md5tmp); - - md5_starts(&md5ctx); - md5_update(&md5ctx, (uint8_t*)md5tmp, 16); - md5_finish(&md5ctx, (uint8_t*)md5tmp); - md5digest = string_to_hex_alloc(md5tmp, 16); - - return md5digest; -} - -char *growl_generate_authheader_alloc(const char*const password) -{ - PPH_BYTES salt; - char* salthash; - char* keyhash; - char* authheader = NULL; - - if (password) { - salt = gen_salt_alloc(8); - if (salt) { - keyhash = gen_password_hash_alloc(password, salt->Buffer); - if (keyhash) { - salthash = string_to_hex_alloc(salt->Buffer, 8); - if (salthash) { - authheader = (char*)PhAllocateSafe(strlen(keyhash) + strlen(salthash) + 7); - if (authheader) { - sprintf(authheader, " MD5:%s.%s", keyhash, salthash); - } - PhFree(salthash); - } - PhFree(keyhash); - } - PhDereferenceObject(salt); - } - } - - return authheader; -} - -/* dmex: modified to use INVALID_SOCKET */ -int growl_tcp_register( const char *const server , const char *const appname , const char **const notifications , const int notifications_count , - const char *const password, const char* const icon ) -{ - SOCKET sock = INVALID_SOCKET; - int i=0; - char *authheader; - char *iconid = NULL; - FILE *iconfile = NULL; - size_t iconsize; - uint8_t buffer[1024]; - - growl_init(); - authheader = growl_generate_authheader_alloc(password); - sock = growl_tcp_open(server); - if (sock == INVALID_SOCKET) goto leave; - if (icon) { - size_t bytes_read; - md5_context md5ctx; - char md5tmp[20]; - iconfile = fopen(icon, "rb"); - if (iconfile) { - fseek(iconfile, 0, SEEK_END); - iconsize = ftell(iconfile); - fseek(iconfile, 0, SEEK_SET); - memset(md5tmp, 0, sizeof(md5tmp)); - md5_starts(&md5ctx); - while (!feof(iconfile)) { - bytes_read = fread(buffer, 1, 1024, iconfile); - if (bytes_read) md5_update(&md5ctx, buffer, (uint32_t)bytes_read); - } - fseek(iconfile, 0, SEEK_SET); - md5_finish(&md5ctx, md5tmp); - iconid = string_to_hex_alloc(md5tmp, 16); - } - } - - growl_tcp_write(sock, "GNTP/1.0 REGISTER NONE %s", authheader ? authheader : ""); - growl_tcp_write(sock, "Application-Name: %s", appname); - if(iconid) - { - growl_tcp_write(sock, "Application-Icon: x-growl-resource://%s", iconid); - } - else if(icon) - { - growl_tcp_write(sock, "Application-Icon: %s", icon ); - } - growl_tcp_write(sock, "Notifications-Count: %d", notifications_count); - growl_tcp_write(sock, "" ); - - for(i=0;i +#include +#include +#include +#include +#include + +#include "md5.h" +#include "tcp.h" +#include "growl.h" + +static const char hex_table[] = "0123456789ABCDEF"; +static char* string_to_hex_alloc(const char* str, int len) { + int n, l; + char* tmp = (char*)PhAllocateSafe(len * 2 + 1); + if (tmp) { + memset(tmp, 0, len * 2 + 1); + for (l = 0, n = 0; l < len; l++) { + tmp[n++] = hex_table[(str[l] & 0xF0) >> 4]; + tmp[n++] = hex_table[str[l] & 0x0F]; + } + } + return tmp; +} + +int growl_init_ = 0; + +/* dmex: modified to use latest Winsock version */ +int growl_init() +{ + if (growl_init_ == 0) + { +#ifdef _WIN32 + WSADATA wsaData; + if (WSAStartup(WINSOCK_VERSION, &wsaData) != 0) + { + return -1; + } +#endif + + growl_init_ = 1; + } + return 1; +} + + +void growl_shutdown() +{ + if (growl_init_ == 1) + { +#ifdef _WIN32 + WSACleanup(); +#endif + } +} + +/* dmex: modified with enhancements */ +PPH_BYTES gen_salt_alloc(int count) +{ + PPH_STRING saltString; + PPH_BYTES saltBytes; + + saltString = PhCreateStringEx(NULL, count * 2 + 2); + PhGenerateRandomAlphaString(saltString->Buffer, (ULONG)saltString->Length / sizeof(WCHAR)); + saltBytes = PhConvertUtf16ToUtf8(saltString->Buffer); + PhDereferenceObject(saltString); + + return saltBytes; +} + +char* gen_password_hash_alloc(const char* password, const char* salt) { + md5_context md5ctx; + char md5tmp[20]; + char* md5digest; + + memset(md5tmp, 0, sizeof(md5tmp)); + md5_starts(&md5ctx); + md5_update(&md5ctx, (uint8_t*)password, (uint32_t)strlen(password)); + md5_update(&md5ctx, (uint8_t*)salt, (uint32_t)strlen(salt)); + md5_finish(&md5ctx, (uint8_t*)md5tmp); + + md5_starts(&md5ctx); + md5_update(&md5ctx, (uint8_t*)md5tmp, 16); + md5_finish(&md5ctx, (uint8_t*)md5tmp); + md5digest = string_to_hex_alloc(md5tmp, 16); + + return md5digest; +} + +char *growl_generate_authheader_alloc(const char*const password) +{ + PPH_BYTES salt; + char* salthash; + char* keyhash; + char* authheader = NULL; + + if (password) { + salt = gen_salt_alloc(8); + if (salt) { + keyhash = gen_password_hash_alloc(password, salt->Buffer); + if (keyhash) { + salthash = string_to_hex_alloc(salt->Buffer, 8); + if (salthash) { + authheader = (char*)PhAllocateSafe(strlen(keyhash) + strlen(salthash) + 7); + if (authheader) { + sprintf(authheader, " MD5:%s.%s", keyhash, salthash); + } + PhFree(salthash); + } + PhFree(keyhash); + } + PhDereferenceObject(salt); + } + } + + return authheader; +} + +/* dmex: modified to use INVALID_SOCKET */ +int growl_tcp_register( const char *const server , const char *const appname , const char **const notifications , const int notifications_count , + const char *const password, const char* const icon ) +{ + SOCKET sock = INVALID_SOCKET; + int i=0; + char *authheader; + char *iconid = NULL; + FILE *iconfile = NULL; + size_t iconsize; + uint8_t buffer[1024]; + + growl_init(); + authheader = growl_generate_authheader_alloc(password); + sock = growl_tcp_open(server); + if (sock == INVALID_SOCKET) goto leave; + if (icon) { + size_t bytes_read; + md5_context md5ctx; + char md5tmp[20]; + iconfile = fopen(icon, "rb"); + if (iconfile) { + fseek(iconfile, 0, SEEK_END); + iconsize = ftell(iconfile); + fseek(iconfile, 0, SEEK_SET); + memset(md5tmp, 0, sizeof(md5tmp)); + md5_starts(&md5ctx); + while (!feof(iconfile)) { + bytes_read = fread(buffer, 1, 1024, iconfile); + if (bytes_read) md5_update(&md5ctx, buffer, (uint32_t)bytes_read); + } + fseek(iconfile, 0, SEEK_SET); + md5_finish(&md5ctx, md5tmp); + iconid = string_to_hex_alloc(md5tmp, 16); + } + } + + growl_tcp_write(sock, "GNTP/1.0 REGISTER NONE %s", authheader ? authheader : ""); + growl_tcp_write(sock, "Application-Name: %s", appname); + if(iconid) + { + growl_tcp_write(sock, "Application-Icon: x-growl-resource://%s", iconid); + } + else if(icon) + { + growl_tcp_write(sock, "Application-Icon: %s", icon ); + } + growl_tcp_write(sock, "Notifications-Count: %d", notifications_count); + growl_tcp_write(sock, "" ); + + for(i=0;i - -typedef struct { - PH_HASH_CONTEXT hc; -} md5_context; - -__forceinline void md5_starts(md5_context *ctx) -{ - PhInitializeHash(&ctx->hc, Md5HashAlgorithm); -} - -__forceinline void md5_update(md5_context *ctx, const uint8_t *input, uint32_t length) -{ - PhUpdateHash(&ctx->hc, (PVOID)input, length); -} - -__forceinline void md5_finish(md5_context *ctx, uint8_t digest[16]) -{ - if (!PhFinalHash(&ctx->hc, digest, 16, NULL)) - PhRaiseStatus(STATUS_INTERNAL_ERROR); -} - -#endif /* _MD5_H_ */ +#ifndef _MD5_H_ +#define _MD5_H_ + +#include + +typedef struct { + PH_HASH_CONTEXT hc; +} md5_context; + +__forceinline void md5_starts(md5_context *ctx) +{ + PhInitializeHash(&ctx->hc, Md5HashAlgorithm); +} + +__forceinline void md5_update(md5_context *ctx, const uint8_t *input, uint32_t length) +{ + PhUpdateHash(&ctx->hc, (PVOID)input, length); +} + +__forceinline void md5_finish(md5_context *ctx, uint8_t digest[16]) +{ + if (!PhFinalHash(&ctx->hc, digest, 16, NULL)) + PhRaiseStatus(STATUS_INTERNAL_ERROR); +} + +#endif /* _MD5_H_ */ diff --git a/plugins/ExtendedNotifications/gntp-send/tcp.c b/plugins/ExtendedNotifications/gntp-send/tcp.c index 8340ddc3397d..f47fa7f4fdd8 100644 --- a/plugins/ExtendedNotifications/gntp-send/tcp.c +++ b/plugins/ExtendedNotifications/gntp-send/tcp.c @@ -1,185 +1,185 @@ -#include -#include -#include -#include -#include - -#ifdef _WIN32 -#define _WINSOCK_DEPRECATED_NO_WARNINGS -#include -#else -#include -#include -#include -#include -#include -#endif - -#include "tcp.h" - -int growl_tcp_parse_hostname( const char *const server , int default_port , struct sockaddr_in *const sockaddr ); - -void growl_tcp_write_raw( SOCKET sock, const unsigned char * data, const int data_length ) -{ - send(sock, data, data_length, 0); -} - -void growl_tcp_write( SOCKET sock , const char *const format , ... ) -{ - int length; - char *output; - char *stop; - - va_list ap; - - va_start( ap , format ); - length = vsnprintf( NULL , 0 , format , ap ); - va_end(ap); - - va_start(ap,format); - output = (char*)PhAllocateSafe(length+1); - if (!output) { - va_end(ap); - return; - } - vsnprintf( output , length+1 , format , ap ); - va_end(ap); - - while ((stop = strstr(output, "\r\n"))) strcpy(stop, stop + 1); - - send( sock , output , length , 0 ); - send( sock , "\r\n" , 2 , 0 ); - - PhFree(output); -} - -char *growl_tcp_read(SOCKET sock) { - const int growsize = 80; - char c = 0; - char* line = (char*) PhAllocateSafe(growsize); - if (line) { - int len = growsize, pos = 0; - char* newline; - while (line) { - if (recv(sock, &c, 1, 0) <= 0) break; - if (c == '\r') continue; - if (c == '\n') break; - line[pos++] = c; - if (pos >= len) { - len += growsize; - newline = (char*) realloc(line, len); - if (!newline) { - PhFree(line); - return NULL; - } - line = newline; - } - } - line[pos] = 0; - } - return line; -} - -/* dmex: modified to use INVALID_SOCKET and SOCKET_ERROR */ -SOCKET growl_tcp_open(const char* server) { - SOCKET sock = INVALID_SOCKET; -#ifdef _WIN32 - char on; -#else - int on; -#endif - struct sockaddr_in serv_addr; - - if( growl_tcp_parse_hostname( server , 23053 , &serv_addr ) == -1 ) { - return INVALID_SOCKET; - } - - if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) { - perror("create socket"); - return INVALID_SOCKET; - } - - if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) == SOCKET_ERROR) { - perror("connect"); - closesocket(sock); // dmex: fixed handle leaking on error - return INVALID_SOCKET; - } - - on = 1; - if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)) == SOCKET_ERROR) { - perror("setsockopt"); - closesocket(sock); // dmex: fixed handle leaking on error - return INVALID_SOCKET; - } - - return sock; -} - -/* dmex: modified to use INVALID_SOCKET */ -void growl_tcp_close(SOCKET sock) { -#ifdef _WIN32 - if (sock != INVALID_SOCKET) closesocket(sock); -#else - if (sock > 0) close(sock); -#endif -} - -int growl_tcp_parse_hostname( const char *const server , int default_port , struct sockaddr_in *const sockaddr ) -{ - char *hostname = PhDuplicateBytesZSafe((PSTR)server); - char *port = strchr( hostname, ':' ); - struct hostent* host_ent; - if( port != NULL ) - { - *port = '\0'; - port++; - default_port = atoi(port); - } - - host_ent = gethostbyname(hostname); - if( host_ent == NULL ) - { - perror("gethostbyname"); - PhFree(hostname); - return -1; - } - - // dmex: fixed wrong sizeof argument - memset( sockaddr , 0 , sizeof(struct sockaddr_in) ); - sockaddr->sin_family = AF_INET; - memcpy( &sockaddr->sin_addr , host_ent->h_addr , host_ent->h_length ); - sockaddr->sin_port = htons(default_port); - - PhFree(hostname); - return 0; -} - -int growl_tcp_datagram( const char *server , const unsigned char *data , const int data_length ) -{ - int result; - struct sockaddr_in serv_addr; - SOCKET sock = 0; - - if( growl_tcp_parse_hostname( server , 9887 , &serv_addr ) == -1 ) - { - return -1; - } - - sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); - if( sock == INVALID_SOCKET ) - { - return -1; - } - - if( sendto(sock, (char*)data , data_length , 0 , (struct sockaddr*)&serv_addr , sizeof(serv_addr) ) > 0 ) - { - result = 0; - } - else - { - result = 1; - } - - closesocket(sock); - return result; -} +#include +#include +#include +#include +#include + +#ifdef _WIN32 +#define _WINSOCK_DEPRECATED_NO_WARNINGS +#include +#else +#include +#include +#include +#include +#include +#endif + +#include "tcp.h" + +int growl_tcp_parse_hostname( const char *const server , int default_port , struct sockaddr_in *const sockaddr ); + +void growl_tcp_write_raw( SOCKET sock, const unsigned char * data, const int data_length ) +{ + send(sock, data, data_length, 0); +} + +void growl_tcp_write( SOCKET sock , const char *const format , ... ) +{ + int length; + char *output; + char *stop; + + va_list ap; + + va_start( ap , format ); + length = vsnprintf( NULL , 0 , format , ap ); + va_end(ap); + + va_start(ap,format); + output = (char*)PhAllocateSafe(length+1); + if (!output) { + va_end(ap); + return; + } + vsnprintf( output , length+1 , format , ap ); + va_end(ap); + + while ((stop = strstr(output, "\r\n"))) strcpy(stop, stop + 1); + + send( sock , output , length , 0 ); + send( sock , "\r\n" , 2 , 0 ); + + PhFree(output); +} + +char *growl_tcp_read(SOCKET sock) { + const int growsize = 80; + char c = 0; + char* line = (char*) PhAllocateSafe(growsize); + if (line) { + int len = growsize, pos = 0; + char* newline; + while (line) { + if (recv(sock, &c, 1, 0) <= 0) break; + if (c == '\r') continue; + if (c == '\n') break; + line[pos++] = c; + if (pos >= len) { + len += growsize; + newline = (char*) realloc(line, len); + if (!newline) { + PhFree(line); + return NULL; + } + line = newline; + } + } + line[pos] = 0; + } + return line; +} + +/* dmex: modified to use INVALID_SOCKET and SOCKET_ERROR */ +SOCKET growl_tcp_open(const char* server) { + SOCKET sock = INVALID_SOCKET; +#ifdef _WIN32 + char on; +#else + int on; +#endif + struct sockaddr_in serv_addr; + + if( growl_tcp_parse_hostname( server , 23053 , &serv_addr ) == -1 ) { + return INVALID_SOCKET; + } + + if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) { + perror("create socket"); + return INVALID_SOCKET; + } + + if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) == SOCKET_ERROR) { + perror("connect"); + closesocket(sock); // dmex: fixed handle leaking on error + return INVALID_SOCKET; + } + + on = 1; + if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)) == SOCKET_ERROR) { + perror("setsockopt"); + closesocket(sock); // dmex: fixed handle leaking on error + return INVALID_SOCKET; + } + + return sock; +} + +/* dmex: modified to use INVALID_SOCKET */ +void growl_tcp_close(SOCKET sock) { +#ifdef _WIN32 + if (sock != INVALID_SOCKET) closesocket(sock); +#else + if (sock > 0) close(sock); +#endif +} + +int growl_tcp_parse_hostname( const char *const server , int default_port , struct sockaddr_in *const sockaddr ) +{ + char *hostname = PhDuplicateBytesZSafe((PSTR)server); + char *port = strchr( hostname, ':' ); + struct hostent* host_ent; + if( port != NULL ) + { + *port = '\0'; + port++; + default_port = atoi(port); + } + + host_ent = gethostbyname(hostname); + if( host_ent == NULL ) + { + perror("gethostbyname"); + PhFree(hostname); + return -1; + } + + // dmex: fixed wrong sizeof argument + memset( sockaddr , 0 , sizeof(struct sockaddr_in) ); + sockaddr->sin_family = AF_INET; + memcpy( &sockaddr->sin_addr , host_ent->h_addr , host_ent->h_length ); + sockaddr->sin_port = htons(default_port); + + PhFree(hostname); + return 0; +} + +int growl_tcp_datagram( const char *server , const unsigned char *data , const int data_length ) +{ + int result; + struct sockaddr_in serv_addr; + SOCKET sock = 0; + + if( growl_tcp_parse_hostname( server , 9887 , &serv_addr ) == -1 ) + { + return -1; + } + + sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); + if( sock == INVALID_SOCKET ) + { + return -1; + } + + if( sendto(sock, (char*)data , data_length , 0 , (struct sockaddr*)&serv_addr , sizeof(serv_addr) ) > 0 ) + { + result = 0; + } + else + { + result = 1; + } + + closesocket(sock); + return result; +} diff --git a/plugins/ExtendedNotifications/gntp-send/tcp.h b/plugins/ExtendedNotifications/gntp-send/tcp.h index eaf7f418fe3a..4e7e799fb9d1 100644 --- a/plugins/ExtendedNotifications/gntp-send/tcp.h +++ b/plugins/ExtendedNotifications/gntp-send/tcp.h @@ -1,14 +1,14 @@ -#ifndef _TCP_H_ -#define _TCP_H_ - -#ifdef _MSC_VER -#define __attribute__(x) -#endif -void growl_tcp_write_raw( SOCKET sock, const unsigned char * data, const int data_length ); -void growl_tcp_write( SOCKET sock , const char *const format , ... ) __attribute__ ((format (printf, 2, 3))); -char* growl_tcp_read(SOCKET sock); -SOCKET growl_tcp_open(const char* server); -void growl_tcp_close(SOCKET sock); -int growl_tcp_datagram( const char *server , const unsigned char *data , const int data_length ); - -#endif /* _TCP_H_ */ +#ifndef _TCP_H_ +#define _TCP_H_ + +#ifdef _MSC_VER +#define __attribute__(x) +#endif +void growl_tcp_write_raw( SOCKET sock, const unsigned char * data, const int data_length ); +void growl_tcp_write( SOCKET sock , const char *const format , ... ) __attribute__ ((format (printf, 2, 3))); +char* growl_tcp_read(SOCKET sock); +SOCKET growl_tcp_open(const char* server); +void growl_tcp_close(SOCKET sock); +int growl_tcp_datagram( const char *server , const unsigned char *data , const int data_length ); + +#endif /* _TCP_H_ */ diff --git a/plugins/ExtendedNotifications/main.c b/plugins/ExtendedNotifications/main.c index 34a0178a3e5f..293db5c4deab 100644 --- a/plugins/ExtendedNotifications/main.c +++ b/plugins/ExtendedNotifications/main.c @@ -1,1112 +1,1112 @@ -/* - * Process Hacker Extended Notifications - - * main program - * - * Copyright (C) 2010-2011 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include -#include -#include -#include "extnoti.h" -#include "resource.h" -#include "gntp-send/growl.h" - -VOID NTAPI LoadCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ); - -VOID NTAPI ShowOptionsCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ); - -VOID NTAPI NotifyEventCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ); - -VOID RegisterGrowl( - _In_ BOOLEAN Force - ); - -VOID NotifyGrowl( - _In_ PPH_PLUGIN_NOTIFY_EVENT NotifyEvent - ); - -NTSTATUS NTAPI RegisterGrowlCallback( - _In_ PVOID Parameter - ); - -INT_PTR CALLBACK ProcessesDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -INT_PTR CALLBACK ServicesDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -INT_PTR CALLBACK LoggingDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -INT_PTR CALLBACK GrowlDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -PPH_PLUGIN PluginInstance; -PH_CALLBACK_REGISTRATION PluginLoadCallbackRegistration; -PH_CALLBACK_REGISTRATION PluginShowOptionsCallbackRegistration; -PH_CALLBACK_REGISTRATION NotifyEventCallbackRegistration; - -PPH_LIST ProcessFilterList; -PPH_LIST ServiceFilterList; - -PSTR GrowlNotifications[] = -{ - "Process Created", - "Process Terminated", - "Service Created", - "Service Deleted", - "Service Started", - "Service Stopped" -}; - -LOGICAL DllMain( - _In_ HINSTANCE Instance, - _In_ ULONG Reason, - _Reserved_ PVOID Reserved - ) -{ - switch (Reason) - { - case DLL_PROCESS_ATTACH: - { - PPH_PLUGIN_INFORMATION info; - - PluginInstance = PhRegisterPlugin(PLUGIN_NAME, Instance, &info); - - if (!PluginInstance) - return FALSE; - - info->DisplayName = L"Extended Notifications"; - info->Author = L"wj32"; - info->Description = L"Filters notifications."; - info->Url = L"https://wj32.org/processhacker/forums/viewtopic.php?t=1112"; - info->HasOptions = TRUE; - - PhRegisterCallback( - PhGetPluginCallback(PluginInstance, PluginCallbackLoad), - LoadCallback, - NULL, - &PluginLoadCallbackRegistration - ); - PhRegisterCallback( - PhGetPluginCallback(PluginInstance, PluginCallbackShowOptions), - ShowOptionsCallback, - NULL, - &PluginShowOptionsCallbackRegistration - ); - - PhRegisterCallback( - PhGetGeneralCallback(GeneralCallbackNotifyEvent), - NotifyEventCallback, - NULL, - &NotifyEventCallbackRegistration - ); - - { - static PH_SETTING_CREATE settings[] = - { - { IntegerSettingType, SETTING_NAME_ENABLE_GROWL, L"0" }, - { StringSettingType, SETTING_NAME_LOG_FILENAME, L"" }, - { StringSettingType, SETTING_NAME_PROCESS_LIST, L"\\i*" }, - { StringSettingType, SETTING_NAME_SERVICE_LIST, L"\\i*" } - }; - - PhAddSettings(settings, sizeof(settings) / sizeof(PH_SETTING_CREATE)); - } - - ProcessFilterList = PhCreateList(10); - ServiceFilterList = PhCreateList(10); - } - break; - } - - return TRUE; -} - -VOID FreeFilterEntry( - _In_ PFILTER_ENTRY Entry - ) -{ - PhDereferenceObject(Entry->Filter); - PhFree(Entry); -} - -VOID ClearFilterList( - _Inout_ PPH_LIST FilterList - ) -{ - ULONG i; - - for (i = 0; i < FilterList->Count; i++) - FreeFilterEntry(FilterList->Items[i]); - - PhClearList(FilterList); -} - -VOID CopyFilterList( - _Inout_ PPH_LIST Destination, - _In_ PPH_LIST Source - ) -{ - ULONG i; - - for (i = 0; i < Source->Count; i++) - { - PFILTER_ENTRY entry = Source->Items[i]; - PFILTER_ENTRY newEntry; - - newEntry = PhAllocate(sizeof(FILTER_ENTRY)); - newEntry->Type = entry->Type; - newEntry->Filter = entry->Filter; - PhReferenceObject(newEntry->Filter); - - PhAddItemList(Destination, newEntry); - } -} - -VOID LoadFilterList( - _Inout_ PPH_LIST FilterList, - _In_ PPH_STRING String - ) -{ - PH_STRING_BUILDER stringBuilder; - SIZE_T length; - SIZE_T i; - PFILTER_ENTRY entry; - - length = String->Length / 2; - PhInitializeStringBuilder(&stringBuilder, 20); - - entry = NULL; - - for (i = 0; i < length; i++) - { - if (String->Buffer[i] == '\\') - { - if (i != length - 1) - { - i++; - - switch (String->Buffer[i]) - { - case 'i': - case 'e': - if (entry) - { - entry->Filter = PhFinalStringBuilderString(&stringBuilder); - PhAddItemList(FilterList, entry); - PhInitializeStringBuilder(&stringBuilder, 20); - } - - entry = PhAllocate(sizeof(FILTER_ENTRY)); - entry->Type = String->Buffer[i] == 'i' ? FilterInclude : FilterExclude; - - break; - - default: - PhAppendCharStringBuilder(&stringBuilder, String->Buffer[i]); - break; - } - } - else - { - // Trailing backslash. Just ignore it. - break; - } - } - else - { - PhAppendCharStringBuilder(&stringBuilder, String->Buffer[i]); - } - } - - if (entry) - { - entry->Filter = PhFinalStringBuilderString(&stringBuilder); - PhAddItemList(FilterList, entry); - } - else - { - PhDeleteStringBuilder(&stringBuilder); - } -} - -PPH_STRING SaveFilterList( - _Inout_ PPH_LIST FilterList - ) -{ - PH_STRING_BUILDER stringBuilder; - SIZE_T i; - SIZE_T j; - WCHAR temp[2]; - - PhInitializeStringBuilder(&stringBuilder, 100); - - temp[0] = '\\'; - - for (i = 0; i < FilterList->Count; i++) - { - PFILTER_ENTRY entry = FilterList->Items[i]; - SIZE_T length; - - // Write the entry type. - - temp[1] = entry->Type == FilterInclude ? 'i' : 'e'; - - PhAppendStringBuilderEx(&stringBuilder, temp, 4); - - // Write the filter string. - - length = entry->Filter->Length / 2; - - for (j = 0; j < length; j++) - { - if (entry->Filter->Buffer[j] == '\\') // escape backslashes - { - temp[1] = entry->Filter->Buffer[j]; - PhAppendStringBuilderEx(&stringBuilder, temp, 4); - } - else - { - PhAppendCharStringBuilder(&stringBuilder, entry->Filter->Buffer[j]); - } - } - } - - return PhFinalStringBuilderString(&stringBuilder); -} - -VOID NTAPI LoadCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - LoadFilterList(ProcessFilterList, PhaGetStringSetting(SETTING_NAME_PROCESS_LIST)); - LoadFilterList(ServiceFilterList, PhaGetStringSetting(SETTING_NAME_SERVICE_LIST)); - - FileLogInitialization(); - - if (PhGetIntegerSetting(SETTING_NAME_ENABLE_GROWL)) - { - PhQueueItemWorkQueue(PhGetGlobalWorkQueue(), RegisterGrowlCallback, NULL); - } -} - -VOID NTAPI ShowOptionsCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - PROPSHEETHEADER propSheetHeader = { sizeof(propSheetHeader) }; - PROPSHEETPAGE propSheetPage; - HPROPSHEETPAGE pages[4]; - - propSheetHeader.dwFlags = - PSH_NOAPPLYNOW | - PSH_NOCONTEXTHELP | - PSH_PROPTITLE; - propSheetHeader.hwndParent = (HWND)Parameter; - propSheetHeader.pszCaption = L"Extended Notifications"; - propSheetHeader.nPages = 0; - propSheetHeader.nStartPage = 0; - propSheetHeader.phpage = pages; - - // Processes - memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); - propSheetPage.dwSize = sizeof(PROPSHEETPAGE); - propSheetPage.hInstance = PluginInstance->DllBase; - propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_PROCESSES); - propSheetPage.pfnDlgProc = ProcessesDlgProc; - pages[propSheetHeader.nPages++] = CreatePropertySheetPage(&propSheetPage); - - // Services - memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); - propSheetPage.dwSize = sizeof(PROPSHEETPAGE); - propSheetPage.hInstance = PluginInstance->DllBase; - propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_SERVICES); - propSheetPage.pfnDlgProc = ServicesDlgProc; - pages[propSheetHeader.nPages++] = CreatePropertySheetPage(&propSheetPage); - - // Logging - memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); - propSheetPage.dwSize = sizeof(PROPSHEETPAGE); - propSheetPage.hInstance = PluginInstance->DllBase; - propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_LOGGING); - propSheetPage.pfnDlgProc = LoggingDlgProc; - pages[propSheetHeader.nPages++] = CreatePropertySheetPage(&propSheetPage); - - // Growl - memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); - propSheetPage.dwSize = sizeof(PROPSHEETPAGE); - propSheetPage.hInstance = PluginInstance->DllBase; - propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_GROWL); - propSheetPage.pfnDlgProc = GrowlDlgProc; - pages[propSheetHeader.nPages++] = CreatePropertySheetPage(&propSheetPage); - - PhModalPropertySheet(&propSheetHeader); -} - -BOOLEAN MatchFilterList( - _In_ PPH_LIST FilterList, - _In_ PPH_STRING String, - _Out_ FILTER_TYPE *FilterType - ) -{ - ULONG i; - BOOLEAN isFileName; - - isFileName = PhFindCharInString(String, 0, '\\') != -1; - - for (i = 0; i < FilterList->Count; i++) - { - PFILTER_ENTRY entry = FilterList->Items[i]; - - if (isFileName && PhFindCharInString(entry->Filter, 0, '\\') == -1) - continue; // ignore filters without backslashes if we're matching a file name - - if (entry->Filter->Length == 2 && entry->Filter->Buffer[0] == '*') // shortcut - { - *FilterType = entry->Type; - return TRUE; - } - - if (PhMatchWildcards(entry->Filter->Buffer, String->Buffer, TRUE)) - { - *FilterType = entry->Type; - return TRUE; - } - } - - return FALSE; -} - -VOID NTAPI NotifyEventCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - PPH_PLUGIN_NOTIFY_EVENT notifyEvent = Parameter; - PPH_PROCESS_ITEM processItem; - PPH_SERVICE_ITEM serviceItem; - FILTER_TYPE filterType; - BOOLEAN found = FALSE; - - filterType = FilterExclude; - - switch (notifyEvent->Type) - { - case PH_NOTIFY_PROCESS_CREATE: - case PH_NOTIFY_PROCESS_DELETE: - processItem = notifyEvent->Parameter; - - if (processItem->FileName) - found = MatchFilterList(ProcessFilterList, processItem->FileName, &filterType); - - if (!found) - MatchFilterList(ProcessFilterList, processItem->ProcessName, &filterType); - - break; - - case PH_NOTIFY_SERVICE_CREATE: - case PH_NOTIFY_SERVICE_DELETE: - case PH_NOTIFY_SERVICE_START: - case PH_NOTIFY_SERVICE_STOP: - serviceItem = notifyEvent->Parameter; - - MatchFilterList(ServiceFilterList, serviceItem->Name, &filterType); - - break; - } - - if (filterType == FilterExclude) - notifyEvent->Handled = TRUE; // pretend we handled the notification to prevent it from displaying - - if (PhGetIntegerSetting(SETTING_NAME_ENABLE_GROWL)) - NotifyGrowl(notifyEvent); -} - -VOID RegisterGrowl( - _In_ BOOLEAN Force - ) -{ - static BOOLEAN registered = FALSE; - - if (!Force && registered) - return; - - growl_tcp_register("127.0.0.1", "Process Hacker", GrowlNotifications, sizeof(GrowlNotifications) / sizeof(PSTR), NULL, NULL); - - registered = TRUE; -} - -VOID NotifyGrowl( - _In_ PPH_PLUGIN_NOTIFY_EVENT NotifyEvent - ) -{ - PSTR notification; - PPH_STRING title; - PPH_BYTES titleUtf8; - PPH_STRING message; - PPH_BYTES messageUtf8; - PPH_PROCESS_ITEM processItem; - PPH_SERVICE_ITEM serviceItem; - PPH_PROCESS_ITEM parentProcessItem; - - if (NotifyEvent->Handled) - return; - - switch (NotifyEvent->Type) - { - case PH_NOTIFY_PROCESS_CREATE: - processItem = NotifyEvent->Parameter; - notification = GrowlNotifications[0]; - title = processItem->ProcessName; - - parentProcessItem = PhReferenceProcessItemForParent( - processItem->ParentProcessId, - processItem->ProcessId, - &processItem->CreateTime - ); - - message = PhaFormatString( - L"The process %s (%lu) was started by %s.", - processItem->ProcessName->Buffer, - HandleToUlong(processItem->ProcessId), - parentProcessItem ? parentProcessItem->ProcessName->Buffer : L"an unknown process" - ); - - if (parentProcessItem) - PhDereferenceObject(parentProcessItem); - - break; - case PH_NOTIFY_PROCESS_DELETE: - processItem = NotifyEvent->Parameter; - notification = GrowlNotifications[1]; - title = processItem->ProcessName; - - message = PhaFormatString(L"The process %s (%lu) was terminated.", - processItem->ProcessName->Buffer, - HandleToUlong(processItem->ProcessId) - ); - - break; - case PH_NOTIFY_SERVICE_CREATE: - serviceItem = NotifyEvent->Parameter; - notification = GrowlNotifications[2]; - title = serviceItem->DisplayName; - - message = PhaFormatString(L"The service %s (%s) has been created.", - serviceItem->Name->Buffer, - serviceItem->DisplayName->Buffer - ); - - break; - case PH_NOTIFY_SERVICE_DELETE: - serviceItem = NotifyEvent->Parameter; - notification = GrowlNotifications[3]; - title = serviceItem->DisplayName; - - message = PhaFormatString(L"The service %s (%s) has been deleted.", - serviceItem->Name->Buffer, - serviceItem->DisplayName->Buffer - ); - - break; - case PH_NOTIFY_SERVICE_START: - serviceItem = NotifyEvent->Parameter; - notification = GrowlNotifications[4]; - title = serviceItem->DisplayName; - - message = PhaFormatString(L"The service %s (%s) has been started.", - serviceItem->Name->Buffer, - serviceItem->DisplayName->Buffer - ); - - break; - case PH_NOTIFY_SERVICE_STOP: - serviceItem = NotifyEvent->Parameter; - notification = GrowlNotifications[5]; - title = serviceItem->DisplayName; - - message = PhaFormatString(L"The service %s (%s) has been stopped.", - serviceItem->Name->Buffer, - serviceItem->DisplayName->Buffer - ); - - break; - default: - return; - } - - titleUtf8 = PH_AUTO(PhConvertUtf16ToUtf8Ex(title->Buffer, title->Length)); - messageUtf8 = PH_AUTO(PhConvertUtf16ToUtf8Ex(message->Buffer, message->Length)); - - RegisterGrowl(TRUE); - - if (growl_tcp_notify("127.0.0.1", "Process Hacker", notification, titleUtf8->Buffer, messageUtf8->Buffer, NULL, NULL, NULL) == 0) - NotifyEvent->Handled = TRUE; -} - -NTSTATUS NTAPI RegisterGrowlCallback( - _In_ PVOID Parameter - ) -{ - RegisterGrowl(FALSE); - - return STATUS_SUCCESS; -} - -PPH_STRING FormatFilterEntry( - _In_ PFILTER_ENTRY Entry - ) -{ - return PhConcatStrings2(Entry->Type == FilterInclude ? L"[Include] " : L"[Exclude] ", Entry->Filter->Buffer); -} - -VOID AddEntriesToListBox( - _In_ HWND ListBox, - _In_ PPH_LIST FilterList - ) -{ - ULONG i; - - for (i = 0; i < FilterList->Count; i++) - { - PFILTER_ENTRY entry = FilterList->Items[i]; - - ListBox_AddString(ListBox, PH_AUTO_T(PH_STRING, FormatFilterEntry(entry))->Buffer); - } -} - -PPH_LIST EditingProcessFilterList; -PPH_LIST EditingServiceFilterList; - -LRESULT CALLBACK TextBoxSubclassProc( - _In_ HWND hWnd, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam, - _In_ UINT_PTR uIdSubclass, - _In_ ULONG_PTR dwRefData - ) -{ - switch (uMsg) - { - case WM_NCDESTROY: - RemoveWindowSubclass(hWnd, TextBoxSubclassProc, uIdSubclass); - break; - case WM_GETDLGCODE: - { - if (wParam == VK_RETURN) - return DLGC_WANTALLKEYS; - } - break; - case WM_CHAR: - { - if (wParam == VK_RETURN) - { - SendMessage(GetParent(hWnd), WM_COMMAND, IDC_TEXT_RETURN, 0); - return 0; - } - } - break; - } - - return DefSubclassProc(hWnd, uMsg, wParam, lParam); -} - -VOID FixControlStates( - _In_ HWND hwndDlg, - _In_ HWND ListBox - ) -{ - ULONG i; - ULONG count; - - i = ListBox_GetCurSel(ListBox); - count = ListBox_GetCount(ListBox); - - EnableWindow(GetDlgItem(hwndDlg, IDC_REMOVE), i != LB_ERR); - EnableWindow(GetDlgItem(hwndDlg, IDC_MOVEUP), i != LB_ERR && i != 0); - EnableWindow(GetDlgItem(hwndDlg, IDC_MOVEDOWN), i != LB_ERR && i != count - 1); -} - -INT_PTR HandleCommonMessages( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam, - _In_ HWND ListBox, - _In_ PPH_LIST FilterList - ) -{ - switch (uMsg) - { - case WM_INITDIALOG: - { - SetWindowSubclass(GetDlgItem(hwndDlg, IDC_TEXT), TextBoxSubclassProc, 0, 0); - - Button_SetCheck(GetDlgItem(hwndDlg, IDC_INCLUDE), BST_CHECKED); - - FixControlStates(hwndDlg, ListBox); - } - break; - case WM_COMMAND: - { - switch (LOWORD(wParam)) - { - case IDC_LIST: - { - if (HIWORD(wParam) == LBN_SELCHANGE) - { - ULONG i; - - i = ListBox_GetCurSel(ListBox); - - if (i != LB_ERR) - { - PFILTER_ENTRY entry; - - entry = FilterList->Items[i]; - SetDlgItemText(hwndDlg, IDC_TEXT, entry->Filter->Buffer); - Button_SetCheck(GetDlgItem(hwndDlg, IDC_INCLUDE), - entry->Type == FilterInclude ? BST_CHECKED : BST_UNCHECKED); - Button_SetCheck(GetDlgItem(hwndDlg, IDC_EXCLUDE), - entry->Type == FilterExclude ? BST_CHECKED : BST_UNCHECKED); - } - - FixControlStates(hwndDlg, ListBox); - } - } - break; - case IDC_ADD: - case IDC_TEXT_RETURN: - { - ULONG i; - PPH_STRING string; - PFILTER_ENTRY entry = NULL; - FILTER_TYPE type; - PPH_STRING entryString; - - string = PhGetWindowText(GetDlgItem(hwndDlg, IDC_TEXT)); - - if (string->Length == 0) - { - PhDereferenceObject(string); - return FALSE; - } - - for (i = 0; i < FilterList->Count; i++) - { - entry = FilterList->Items[i]; - - if (PhEqualString(entry->Filter, string, TRUE)) - break; - } - - type = Button_GetCheck(GetDlgItem(hwndDlg, IDC_INCLUDE)) == BST_CHECKED ? FilterInclude : FilterExclude; - - if (i == FilterList->Count) - { - // No existing entry, so add a new one. - - entry = PhAllocate(sizeof(FILTER_ENTRY)); - entry->Type = type; - entry->Filter = string; - PhInsertItemList(FilterList, 0, entry); - - entryString = FormatFilterEntry(entry); - ListBox_InsertString(ListBox, 0, entryString->Buffer); - PhDereferenceObject(entryString); - - ListBox_SetCurSel(ListBox, 0); - } - else - { - entry->Type = type; - PhDereferenceObject(entry->Filter); - entry->Filter = string; - - ListBox_DeleteString(ListBox, i); - entryString = FormatFilterEntry(entry); - ListBox_InsertString(ListBox, i, entryString->Buffer); - PhDereferenceObject(entryString); - - ListBox_SetCurSel(ListBox, i); - } - - SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hwndDlg, IDC_TEXT), TRUE); - Edit_SetSel(GetDlgItem(hwndDlg, IDC_TEXT), 0, -1); - - FixControlStates(hwndDlg, ListBox); - } - break; - case IDC_REMOVE: - { - ULONG i; - PFILTER_ENTRY entry; - - i = ListBox_GetCurSel(ListBox); - - if (i != LB_ERR) - { - entry = FilterList->Items[i]; - FreeFilterEntry(entry); - PhRemoveItemList(FilterList, i); - ListBox_DeleteString(ListBox, i); - - if (i >= FilterList->Count) - i = FilterList->Count - 1; - - ListBox_SetCurSel(ListBox, i); - - FixControlStates(hwndDlg, ListBox); - } - } - break; - case IDC_MOVEUP: - { - ULONG i; - PFILTER_ENTRY entry; - PPH_STRING entryString; - - i = ListBox_GetCurSel(ListBox); - - if (i != LB_ERR && i != 0) - { - entry = FilterList->Items[i]; - - PhRemoveItemList(FilterList, i); - PhInsertItemList(FilterList, i - 1, entry); - - ListBox_DeleteString(ListBox, i); - entryString = FormatFilterEntry(entry); - ListBox_InsertString(ListBox, i - 1, entryString->Buffer); - PhDereferenceObject(entryString); - - i--; - ListBox_SetCurSel(ListBox, i); - - FixControlStates(hwndDlg, ListBox); - } - } - break; - case IDC_MOVEDOWN: - { - ULONG i; - PFILTER_ENTRY entry; - PPH_STRING entryString; - - i = ListBox_GetCurSel(ListBox); - - if (i != LB_ERR && i != FilterList->Count - 1) - { - entry = FilterList->Items[i]; - - PhRemoveItemList(FilterList, i); - PhInsertItemList(FilterList, i + 1, entry); - - ListBox_DeleteString(ListBox, i); - entryString = FormatFilterEntry(entry); - ListBox_InsertString(ListBox, i + 1, entryString->Buffer); - PhDereferenceObject(entryString); - - i++; - ListBox_SetCurSel(ListBox, i); - - FixControlStates(hwndDlg, ListBox); - } - } - break; - } - } - break; - } - - return FALSE; -} - -INT_PTR CALLBACK ProcessesDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - INT_PTR result; - - if (result = HandleCommonMessages(hwndDlg, uMsg, wParam, lParam, - GetDlgItem(hwndDlg, IDC_LIST), EditingProcessFilterList)) - return result; - - switch (uMsg) - { - case WM_INITDIALOG: - { - PhCenterWindow(GetParent(hwndDlg), GetParent(GetParent(hwndDlg))); - - EditingProcessFilterList = PhCreateList(ProcessFilterList->Count + 10); - CopyFilterList(EditingProcessFilterList, ProcessFilterList); - - AddEntriesToListBox(GetDlgItem(hwndDlg, IDC_LIST), EditingProcessFilterList); - } - break; - case WM_DESTROY: - { - ClearFilterList(EditingProcessFilterList); - PhDereferenceObject(EditingProcessFilterList); - EditingProcessFilterList = NULL; - } - break; - case WM_COMMAND: - { - switch (LOWORD(wParam)) - { - NOTHING; - } - } - break; - case WM_NOTIFY: - { - LPNMHDR header = (LPNMHDR)lParam; - - switch (header->code) - { - case PSN_APPLY: - { - PPH_STRING string; - - ClearFilterList(ProcessFilterList); - CopyFilterList(ProcessFilterList, EditingProcessFilterList); - - string = SaveFilterList(ProcessFilterList); - PhSetStringSetting2(SETTING_NAME_PROCESS_LIST, &string->sr); - PhDereferenceObject(string); - - SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_NOERROR); - } - return TRUE; - } - } - break; - } - - return FALSE; -} - -INT_PTR CALLBACK ServicesDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - if (HandleCommonMessages(hwndDlg, uMsg, wParam, lParam, - GetDlgItem(hwndDlg, IDC_LIST), EditingServiceFilterList)) - return FALSE; - - switch (uMsg) - { - case WM_INITDIALOG: - { - EditingServiceFilterList = PhCreateList(ServiceFilterList->Count + 10); - CopyFilterList(EditingServiceFilterList, ServiceFilterList); - - AddEntriesToListBox(GetDlgItem(hwndDlg, IDC_LIST), EditingServiceFilterList); - } - break; - case WM_DESTROY: - { - ClearFilterList(EditingServiceFilterList); - PhDereferenceObject(EditingServiceFilterList); - EditingServiceFilterList = NULL; - } - break; - case WM_COMMAND: - { - switch (LOWORD(wParam)) - { - NOTHING; - } - } - break; - case WM_NOTIFY: - { - LPNMHDR header = (LPNMHDR)lParam; - - switch (header->code) - { - case PSN_APPLY: - { - PPH_STRING string; - - ClearFilterList(ServiceFilterList); - CopyFilterList(ServiceFilterList, EditingServiceFilterList); - - string = SaveFilterList(ServiceFilterList); - PhSetStringSetting2(SETTING_NAME_SERVICE_LIST, &string->sr); - PhDereferenceObject(string); - - SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_NOERROR); - } - return TRUE; - } - } - break; - } - - return FALSE; -} - -INT_PTR CALLBACK LoggingDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - switch (uMsg) - { - case WM_INITDIALOG: - { - SetDlgItemText(hwndDlg, IDC_LOGFILENAME, ((PPH_STRING)PH_AUTO(PhGetStringSetting(SETTING_NAME_LOG_FILENAME)))->Buffer); - } - break; - case WM_COMMAND: - { - switch (LOWORD(wParam)) - { - case IDC_BROWSE: - { - static PH_FILETYPE_FILTER filters[] = - { - { L"Log files (*.txt;*.log)", L"*.txt;*.log" }, - { L"All files (*.*)", L"*.*" } - }; - PVOID fileDialog; - PPH_STRING fileName; - - fileDialog = PhCreateSaveFileDialog(); - PhSetFileDialogFilter(fileDialog, filters, sizeof(filters) / sizeof(PH_FILETYPE_FILTER)); - - fileName = PH_AUTO(PhGetFileName(PhaGetDlgItemText(hwndDlg, IDC_LOGFILENAME))); - PhSetFileDialogFileName(fileDialog, fileName->Buffer); - - if (PhShowFileDialog(hwndDlg, fileDialog)) - { - fileName = PH_AUTO(PhGetFileDialogFileName(fileDialog)); - SetDlgItemText(hwndDlg, IDC_LOGFILENAME, fileName->Buffer); - } - - PhFreeFileDialog(fileDialog); - } - break; - } - } - break; - case WM_NOTIFY: - { - LPNMHDR header = (LPNMHDR)lParam; - - switch (header->code) - { - case PSN_APPLY: - { - PhSetStringSetting2(SETTING_NAME_LOG_FILENAME, &PhaGetDlgItemText(hwndDlg, IDC_LOGFILENAME)->sr); - - SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_NOERROR); - } - return TRUE; - } - } - break; - } - - return FALSE; -} - -INT_PTR CALLBACK GrowlDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - switch (uMsg) - { - case WM_INITDIALOG: - { - SetDlgItemText(hwndDlg, IDC_LICENSE, PH_AUTO_T(PH_STRING, PhConvertUtf8ToUtf16(gntp_send_license_text))->Buffer); - - Button_SetCheck(GetDlgItem(hwndDlg, IDC_ENABLEGROWL), PhGetIntegerSetting(SETTING_NAME_ENABLE_GROWL) ? BST_CHECKED : BST_UNCHECKED); - } - break; - case WM_NOTIFY: - { - LPNMHDR header = (LPNMHDR)lParam; - - switch (header->code) - { - case PSN_QUERYINITIALFOCUS: - { - SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, (LONG_PTR)GetDlgItem(hwndDlg, IDC_ENABLEGROWL)); - } - return TRUE; - case PSN_APPLY: - { - PhSetIntegerSetting(SETTING_NAME_ENABLE_GROWL, Button_GetCheck(GetDlgItem(hwndDlg, IDC_ENABLEGROWL)) == BST_CHECKED); - - if (PhGetIntegerSetting(SETTING_NAME_ENABLE_GROWL)) - RegisterGrowl(FALSE); - - SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_NOERROR); - } - return TRUE; - } - } - break; - } - - return FALSE; -} +/* + * Process Hacker Extended Notifications - + * main program + * + * Copyright (C) 2010-2011 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include +#include +#include +#include "extnoti.h" +#include "resource.h" +#include "gntp-send/growl.h" + +VOID NTAPI LoadCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ); + +VOID NTAPI ShowOptionsCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ); + +VOID NTAPI NotifyEventCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ); + +VOID RegisterGrowl( + _In_ BOOLEAN Force + ); + +VOID NotifyGrowl( + _In_ PPH_PLUGIN_NOTIFY_EVENT NotifyEvent + ); + +NTSTATUS NTAPI RegisterGrowlCallback( + _In_ PVOID Parameter + ); + +INT_PTR CALLBACK ProcessesDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +INT_PTR CALLBACK ServicesDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +INT_PTR CALLBACK LoggingDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +INT_PTR CALLBACK GrowlDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +PPH_PLUGIN PluginInstance; +PH_CALLBACK_REGISTRATION PluginLoadCallbackRegistration; +PH_CALLBACK_REGISTRATION PluginShowOptionsCallbackRegistration; +PH_CALLBACK_REGISTRATION NotifyEventCallbackRegistration; + +PPH_LIST ProcessFilterList; +PPH_LIST ServiceFilterList; + +PSTR GrowlNotifications[] = +{ + "Process Created", + "Process Terminated", + "Service Created", + "Service Deleted", + "Service Started", + "Service Stopped" +}; + +LOGICAL DllMain( + _In_ HINSTANCE Instance, + _In_ ULONG Reason, + _Reserved_ PVOID Reserved + ) +{ + switch (Reason) + { + case DLL_PROCESS_ATTACH: + { + PPH_PLUGIN_INFORMATION info; + + PluginInstance = PhRegisterPlugin(PLUGIN_NAME, Instance, &info); + + if (!PluginInstance) + return FALSE; + + info->DisplayName = L"Extended Notifications"; + info->Author = L"wj32"; + info->Description = L"Filters notifications."; + info->Url = L"https://wj32.org/processhacker/forums/viewtopic.php?t=1112"; + info->HasOptions = TRUE; + + PhRegisterCallback( + PhGetPluginCallback(PluginInstance, PluginCallbackLoad), + LoadCallback, + NULL, + &PluginLoadCallbackRegistration + ); + PhRegisterCallback( + PhGetPluginCallback(PluginInstance, PluginCallbackShowOptions), + ShowOptionsCallback, + NULL, + &PluginShowOptionsCallbackRegistration + ); + + PhRegisterCallback( + PhGetGeneralCallback(GeneralCallbackNotifyEvent), + NotifyEventCallback, + NULL, + &NotifyEventCallbackRegistration + ); + + { + static PH_SETTING_CREATE settings[] = + { + { IntegerSettingType, SETTING_NAME_ENABLE_GROWL, L"0" }, + { StringSettingType, SETTING_NAME_LOG_FILENAME, L"" }, + { StringSettingType, SETTING_NAME_PROCESS_LIST, L"\\i*" }, + { StringSettingType, SETTING_NAME_SERVICE_LIST, L"\\i*" } + }; + + PhAddSettings(settings, sizeof(settings) / sizeof(PH_SETTING_CREATE)); + } + + ProcessFilterList = PhCreateList(10); + ServiceFilterList = PhCreateList(10); + } + break; + } + + return TRUE; +} + +VOID FreeFilterEntry( + _In_ PFILTER_ENTRY Entry + ) +{ + PhDereferenceObject(Entry->Filter); + PhFree(Entry); +} + +VOID ClearFilterList( + _Inout_ PPH_LIST FilterList + ) +{ + ULONG i; + + for (i = 0; i < FilterList->Count; i++) + FreeFilterEntry(FilterList->Items[i]); + + PhClearList(FilterList); +} + +VOID CopyFilterList( + _Inout_ PPH_LIST Destination, + _In_ PPH_LIST Source + ) +{ + ULONG i; + + for (i = 0; i < Source->Count; i++) + { + PFILTER_ENTRY entry = Source->Items[i]; + PFILTER_ENTRY newEntry; + + newEntry = PhAllocate(sizeof(FILTER_ENTRY)); + newEntry->Type = entry->Type; + newEntry->Filter = entry->Filter; + PhReferenceObject(newEntry->Filter); + + PhAddItemList(Destination, newEntry); + } +} + +VOID LoadFilterList( + _Inout_ PPH_LIST FilterList, + _In_ PPH_STRING String + ) +{ + PH_STRING_BUILDER stringBuilder; + SIZE_T length; + SIZE_T i; + PFILTER_ENTRY entry; + + length = String->Length / 2; + PhInitializeStringBuilder(&stringBuilder, 20); + + entry = NULL; + + for (i = 0; i < length; i++) + { + if (String->Buffer[i] == '\\') + { + if (i != length - 1) + { + i++; + + switch (String->Buffer[i]) + { + case 'i': + case 'e': + if (entry) + { + entry->Filter = PhFinalStringBuilderString(&stringBuilder); + PhAddItemList(FilterList, entry); + PhInitializeStringBuilder(&stringBuilder, 20); + } + + entry = PhAllocate(sizeof(FILTER_ENTRY)); + entry->Type = String->Buffer[i] == 'i' ? FilterInclude : FilterExclude; + + break; + + default: + PhAppendCharStringBuilder(&stringBuilder, String->Buffer[i]); + break; + } + } + else + { + // Trailing backslash. Just ignore it. + break; + } + } + else + { + PhAppendCharStringBuilder(&stringBuilder, String->Buffer[i]); + } + } + + if (entry) + { + entry->Filter = PhFinalStringBuilderString(&stringBuilder); + PhAddItemList(FilterList, entry); + } + else + { + PhDeleteStringBuilder(&stringBuilder); + } +} + +PPH_STRING SaveFilterList( + _Inout_ PPH_LIST FilterList + ) +{ + PH_STRING_BUILDER stringBuilder; + SIZE_T i; + SIZE_T j; + WCHAR temp[2]; + + PhInitializeStringBuilder(&stringBuilder, 100); + + temp[0] = '\\'; + + for (i = 0; i < FilterList->Count; i++) + { + PFILTER_ENTRY entry = FilterList->Items[i]; + SIZE_T length; + + // Write the entry type. + + temp[1] = entry->Type == FilterInclude ? 'i' : 'e'; + + PhAppendStringBuilderEx(&stringBuilder, temp, 4); + + // Write the filter string. + + length = entry->Filter->Length / 2; + + for (j = 0; j < length; j++) + { + if (entry->Filter->Buffer[j] == '\\') // escape backslashes + { + temp[1] = entry->Filter->Buffer[j]; + PhAppendStringBuilderEx(&stringBuilder, temp, 4); + } + else + { + PhAppendCharStringBuilder(&stringBuilder, entry->Filter->Buffer[j]); + } + } + } + + return PhFinalStringBuilderString(&stringBuilder); +} + +VOID NTAPI LoadCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + LoadFilterList(ProcessFilterList, PhaGetStringSetting(SETTING_NAME_PROCESS_LIST)); + LoadFilterList(ServiceFilterList, PhaGetStringSetting(SETTING_NAME_SERVICE_LIST)); + + FileLogInitialization(); + + if (PhGetIntegerSetting(SETTING_NAME_ENABLE_GROWL)) + { + PhQueueItemWorkQueue(PhGetGlobalWorkQueue(), RegisterGrowlCallback, NULL); + } +} + +VOID NTAPI ShowOptionsCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + PROPSHEETHEADER propSheetHeader = { sizeof(propSheetHeader) }; + PROPSHEETPAGE propSheetPage; + HPROPSHEETPAGE pages[4]; + + propSheetHeader.dwFlags = + PSH_NOAPPLYNOW | + PSH_NOCONTEXTHELP | + PSH_PROPTITLE; + propSheetHeader.hwndParent = (HWND)Parameter; + propSheetHeader.pszCaption = L"Extended Notifications"; + propSheetHeader.nPages = 0; + propSheetHeader.nStartPage = 0; + propSheetHeader.phpage = pages; + + // Processes + memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); + propSheetPage.dwSize = sizeof(PROPSHEETPAGE); + propSheetPage.hInstance = PluginInstance->DllBase; + propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_PROCESSES); + propSheetPage.pfnDlgProc = ProcessesDlgProc; + pages[propSheetHeader.nPages++] = CreatePropertySheetPage(&propSheetPage); + + // Services + memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); + propSheetPage.dwSize = sizeof(PROPSHEETPAGE); + propSheetPage.hInstance = PluginInstance->DllBase; + propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_SERVICES); + propSheetPage.pfnDlgProc = ServicesDlgProc; + pages[propSheetHeader.nPages++] = CreatePropertySheetPage(&propSheetPage); + + // Logging + memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); + propSheetPage.dwSize = sizeof(PROPSHEETPAGE); + propSheetPage.hInstance = PluginInstance->DllBase; + propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_LOGGING); + propSheetPage.pfnDlgProc = LoggingDlgProc; + pages[propSheetHeader.nPages++] = CreatePropertySheetPage(&propSheetPage); + + // Growl + memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); + propSheetPage.dwSize = sizeof(PROPSHEETPAGE); + propSheetPage.hInstance = PluginInstance->DllBase; + propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_GROWL); + propSheetPage.pfnDlgProc = GrowlDlgProc; + pages[propSheetHeader.nPages++] = CreatePropertySheetPage(&propSheetPage); + + PhModalPropertySheet(&propSheetHeader); +} + +BOOLEAN MatchFilterList( + _In_ PPH_LIST FilterList, + _In_ PPH_STRING String, + _Out_ FILTER_TYPE *FilterType + ) +{ + ULONG i; + BOOLEAN isFileName; + + isFileName = PhFindCharInString(String, 0, '\\') != -1; + + for (i = 0; i < FilterList->Count; i++) + { + PFILTER_ENTRY entry = FilterList->Items[i]; + + if (isFileName && PhFindCharInString(entry->Filter, 0, '\\') == -1) + continue; // ignore filters without backslashes if we're matching a file name + + if (entry->Filter->Length == 2 && entry->Filter->Buffer[0] == '*') // shortcut + { + *FilterType = entry->Type; + return TRUE; + } + + if (PhMatchWildcards(entry->Filter->Buffer, String->Buffer, TRUE)) + { + *FilterType = entry->Type; + return TRUE; + } + } + + return FALSE; +} + +VOID NTAPI NotifyEventCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + PPH_PLUGIN_NOTIFY_EVENT notifyEvent = Parameter; + PPH_PROCESS_ITEM processItem; + PPH_SERVICE_ITEM serviceItem; + FILTER_TYPE filterType; + BOOLEAN found = FALSE; + + filterType = FilterExclude; + + switch (notifyEvent->Type) + { + case PH_NOTIFY_PROCESS_CREATE: + case PH_NOTIFY_PROCESS_DELETE: + processItem = notifyEvent->Parameter; + + if (processItem->FileName) + found = MatchFilterList(ProcessFilterList, processItem->FileName, &filterType); + + if (!found) + MatchFilterList(ProcessFilterList, processItem->ProcessName, &filterType); + + break; + + case PH_NOTIFY_SERVICE_CREATE: + case PH_NOTIFY_SERVICE_DELETE: + case PH_NOTIFY_SERVICE_START: + case PH_NOTIFY_SERVICE_STOP: + serviceItem = notifyEvent->Parameter; + + MatchFilterList(ServiceFilterList, serviceItem->Name, &filterType); + + break; + } + + if (filterType == FilterExclude) + notifyEvent->Handled = TRUE; // pretend we handled the notification to prevent it from displaying + + if (PhGetIntegerSetting(SETTING_NAME_ENABLE_GROWL)) + NotifyGrowl(notifyEvent); +} + +VOID RegisterGrowl( + _In_ BOOLEAN Force + ) +{ + static BOOLEAN registered = FALSE; + + if (!Force && registered) + return; + + growl_tcp_register("127.0.0.1", "Process Hacker", GrowlNotifications, sizeof(GrowlNotifications) / sizeof(PSTR), NULL, NULL); + + registered = TRUE; +} + +VOID NotifyGrowl( + _In_ PPH_PLUGIN_NOTIFY_EVENT NotifyEvent + ) +{ + PSTR notification; + PPH_STRING title; + PPH_BYTES titleUtf8; + PPH_STRING message; + PPH_BYTES messageUtf8; + PPH_PROCESS_ITEM processItem; + PPH_SERVICE_ITEM serviceItem; + PPH_PROCESS_ITEM parentProcessItem; + + if (NotifyEvent->Handled) + return; + + switch (NotifyEvent->Type) + { + case PH_NOTIFY_PROCESS_CREATE: + processItem = NotifyEvent->Parameter; + notification = GrowlNotifications[0]; + title = processItem->ProcessName; + + parentProcessItem = PhReferenceProcessItemForParent( + processItem->ParentProcessId, + processItem->ProcessId, + &processItem->CreateTime + ); + + message = PhaFormatString( + L"The process %s (%lu) was started by %s.", + processItem->ProcessName->Buffer, + HandleToUlong(processItem->ProcessId), + parentProcessItem ? parentProcessItem->ProcessName->Buffer : L"an unknown process" + ); + + if (parentProcessItem) + PhDereferenceObject(parentProcessItem); + + break; + case PH_NOTIFY_PROCESS_DELETE: + processItem = NotifyEvent->Parameter; + notification = GrowlNotifications[1]; + title = processItem->ProcessName; + + message = PhaFormatString(L"The process %s (%lu) was terminated.", + processItem->ProcessName->Buffer, + HandleToUlong(processItem->ProcessId) + ); + + break; + case PH_NOTIFY_SERVICE_CREATE: + serviceItem = NotifyEvent->Parameter; + notification = GrowlNotifications[2]; + title = serviceItem->DisplayName; + + message = PhaFormatString(L"The service %s (%s) has been created.", + serviceItem->Name->Buffer, + serviceItem->DisplayName->Buffer + ); + + break; + case PH_NOTIFY_SERVICE_DELETE: + serviceItem = NotifyEvent->Parameter; + notification = GrowlNotifications[3]; + title = serviceItem->DisplayName; + + message = PhaFormatString(L"The service %s (%s) has been deleted.", + serviceItem->Name->Buffer, + serviceItem->DisplayName->Buffer + ); + + break; + case PH_NOTIFY_SERVICE_START: + serviceItem = NotifyEvent->Parameter; + notification = GrowlNotifications[4]; + title = serviceItem->DisplayName; + + message = PhaFormatString(L"The service %s (%s) has been started.", + serviceItem->Name->Buffer, + serviceItem->DisplayName->Buffer + ); + + break; + case PH_NOTIFY_SERVICE_STOP: + serviceItem = NotifyEvent->Parameter; + notification = GrowlNotifications[5]; + title = serviceItem->DisplayName; + + message = PhaFormatString(L"The service %s (%s) has been stopped.", + serviceItem->Name->Buffer, + serviceItem->DisplayName->Buffer + ); + + break; + default: + return; + } + + titleUtf8 = PH_AUTO(PhConvertUtf16ToUtf8Ex(title->Buffer, title->Length)); + messageUtf8 = PH_AUTO(PhConvertUtf16ToUtf8Ex(message->Buffer, message->Length)); + + RegisterGrowl(TRUE); + + if (growl_tcp_notify("127.0.0.1", "Process Hacker", notification, titleUtf8->Buffer, messageUtf8->Buffer, NULL, NULL, NULL) == 0) + NotifyEvent->Handled = TRUE; +} + +NTSTATUS NTAPI RegisterGrowlCallback( + _In_ PVOID Parameter + ) +{ + RegisterGrowl(FALSE); + + return STATUS_SUCCESS; +} + +PPH_STRING FormatFilterEntry( + _In_ PFILTER_ENTRY Entry + ) +{ + return PhConcatStrings2(Entry->Type == FilterInclude ? L"[Include] " : L"[Exclude] ", Entry->Filter->Buffer); +} + +VOID AddEntriesToListBox( + _In_ HWND ListBox, + _In_ PPH_LIST FilterList + ) +{ + ULONG i; + + for (i = 0; i < FilterList->Count; i++) + { + PFILTER_ENTRY entry = FilterList->Items[i]; + + ListBox_AddString(ListBox, PH_AUTO_T(PH_STRING, FormatFilterEntry(entry))->Buffer); + } +} + +PPH_LIST EditingProcessFilterList; +PPH_LIST EditingServiceFilterList; + +LRESULT CALLBACK TextBoxSubclassProc( + _In_ HWND hWnd, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam, + _In_ UINT_PTR uIdSubclass, + _In_ ULONG_PTR dwRefData + ) +{ + switch (uMsg) + { + case WM_NCDESTROY: + RemoveWindowSubclass(hWnd, TextBoxSubclassProc, uIdSubclass); + break; + case WM_GETDLGCODE: + { + if (wParam == VK_RETURN) + return DLGC_WANTALLKEYS; + } + break; + case WM_CHAR: + { + if (wParam == VK_RETURN) + { + SendMessage(GetParent(hWnd), WM_COMMAND, IDC_TEXT_RETURN, 0); + return 0; + } + } + break; + } + + return DefSubclassProc(hWnd, uMsg, wParam, lParam); +} + +VOID FixControlStates( + _In_ HWND hwndDlg, + _In_ HWND ListBox + ) +{ + ULONG i; + ULONG count; + + i = ListBox_GetCurSel(ListBox); + count = ListBox_GetCount(ListBox); + + EnableWindow(GetDlgItem(hwndDlg, IDC_REMOVE), i != LB_ERR); + EnableWindow(GetDlgItem(hwndDlg, IDC_MOVEUP), i != LB_ERR && i != 0); + EnableWindow(GetDlgItem(hwndDlg, IDC_MOVEDOWN), i != LB_ERR && i != count - 1); +} + +INT_PTR HandleCommonMessages( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam, + _In_ HWND ListBox, + _In_ PPH_LIST FilterList + ) +{ + switch (uMsg) + { + case WM_INITDIALOG: + { + SetWindowSubclass(GetDlgItem(hwndDlg, IDC_TEXT), TextBoxSubclassProc, 0, 0); + + Button_SetCheck(GetDlgItem(hwndDlg, IDC_INCLUDE), BST_CHECKED); + + FixControlStates(hwndDlg, ListBox); + } + break; + case WM_COMMAND: + { + switch (LOWORD(wParam)) + { + case IDC_LIST: + { + if (HIWORD(wParam) == LBN_SELCHANGE) + { + ULONG i; + + i = ListBox_GetCurSel(ListBox); + + if (i != LB_ERR) + { + PFILTER_ENTRY entry; + + entry = FilterList->Items[i]; + SetDlgItemText(hwndDlg, IDC_TEXT, entry->Filter->Buffer); + Button_SetCheck(GetDlgItem(hwndDlg, IDC_INCLUDE), + entry->Type == FilterInclude ? BST_CHECKED : BST_UNCHECKED); + Button_SetCheck(GetDlgItem(hwndDlg, IDC_EXCLUDE), + entry->Type == FilterExclude ? BST_CHECKED : BST_UNCHECKED); + } + + FixControlStates(hwndDlg, ListBox); + } + } + break; + case IDC_ADD: + case IDC_TEXT_RETURN: + { + ULONG i; + PPH_STRING string; + PFILTER_ENTRY entry = NULL; + FILTER_TYPE type; + PPH_STRING entryString; + + string = PhGetWindowText(GetDlgItem(hwndDlg, IDC_TEXT)); + + if (string->Length == 0) + { + PhDereferenceObject(string); + return FALSE; + } + + for (i = 0; i < FilterList->Count; i++) + { + entry = FilterList->Items[i]; + + if (PhEqualString(entry->Filter, string, TRUE)) + break; + } + + type = Button_GetCheck(GetDlgItem(hwndDlg, IDC_INCLUDE)) == BST_CHECKED ? FilterInclude : FilterExclude; + + if (i == FilterList->Count) + { + // No existing entry, so add a new one. + + entry = PhAllocate(sizeof(FILTER_ENTRY)); + entry->Type = type; + entry->Filter = string; + PhInsertItemList(FilterList, 0, entry); + + entryString = FormatFilterEntry(entry); + ListBox_InsertString(ListBox, 0, entryString->Buffer); + PhDereferenceObject(entryString); + + ListBox_SetCurSel(ListBox, 0); + } + else + { + entry->Type = type; + PhDereferenceObject(entry->Filter); + entry->Filter = string; + + ListBox_DeleteString(ListBox, i); + entryString = FormatFilterEntry(entry); + ListBox_InsertString(ListBox, i, entryString->Buffer); + PhDereferenceObject(entryString); + + ListBox_SetCurSel(ListBox, i); + } + + SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hwndDlg, IDC_TEXT), TRUE); + Edit_SetSel(GetDlgItem(hwndDlg, IDC_TEXT), 0, -1); + + FixControlStates(hwndDlg, ListBox); + } + break; + case IDC_REMOVE: + { + ULONG i; + PFILTER_ENTRY entry; + + i = ListBox_GetCurSel(ListBox); + + if (i != LB_ERR) + { + entry = FilterList->Items[i]; + FreeFilterEntry(entry); + PhRemoveItemList(FilterList, i); + ListBox_DeleteString(ListBox, i); + + if (i >= FilterList->Count) + i = FilterList->Count - 1; + + ListBox_SetCurSel(ListBox, i); + + FixControlStates(hwndDlg, ListBox); + } + } + break; + case IDC_MOVEUP: + { + ULONG i; + PFILTER_ENTRY entry; + PPH_STRING entryString; + + i = ListBox_GetCurSel(ListBox); + + if (i != LB_ERR && i != 0) + { + entry = FilterList->Items[i]; + + PhRemoveItemList(FilterList, i); + PhInsertItemList(FilterList, i - 1, entry); + + ListBox_DeleteString(ListBox, i); + entryString = FormatFilterEntry(entry); + ListBox_InsertString(ListBox, i - 1, entryString->Buffer); + PhDereferenceObject(entryString); + + i--; + ListBox_SetCurSel(ListBox, i); + + FixControlStates(hwndDlg, ListBox); + } + } + break; + case IDC_MOVEDOWN: + { + ULONG i; + PFILTER_ENTRY entry; + PPH_STRING entryString; + + i = ListBox_GetCurSel(ListBox); + + if (i != LB_ERR && i != FilterList->Count - 1) + { + entry = FilterList->Items[i]; + + PhRemoveItemList(FilterList, i); + PhInsertItemList(FilterList, i + 1, entry); + + ListBox_DeleteString(ListBox, i); + entryString = FormatFilterEntry(entry); + ListBox_InsertString(ListBox, i + 1, entryString->Buffer); + PhDereferenceObject(entryString); + + i++; + ListBox_SetCurSel(ListBox, i); + + FixControlStates(hwndDlg, ListBox); + } + } + break; + } + } + break; + } + + return FALSE; +} + +INT_PTR CALLBACK ProcessesDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + INT_PTR result; + + if (result = HandleCommonMessages(hwndDlg, uMsg, wParam, lParam, + GetDlgItem(hwndDlg, IDC_LIST), EditingProcessFilterList)) + return result; + + switch (uMsg) + { + case WM_INITDIALOG: + { + PhCenterWindow(GetParent(hwndDlg), GetParent(GetParent(hwndDlg))); + + EditingProcessFilterList = PhCreateList(ProcessFilterList->Count + 10); + CopyFilterList(EditingProcessFilterList, ProcessFilterList); + + AddEntriesToListBox(GetDlgItem(hwndDlg, IDC_LIST), EditingProcessFilterList); + } + break; + case WM_DESTROY: + { + ClearFilterList(EditingProcessFilterList); + PhDereferenceObject(EditingProcessFilterList); + EditingProcessFilterList = NULL; + } + break; + case WM_COMMAND: + { + switch (LOWORD(wParam)) + { + NOTHING; + } + } + break; + case WM_NOTIFY: + { + LPNMHDR header = (LPNMHDR)lParam; + + switch (header->code) + { + case PSN_APPLY: + { + PPH_STRING string; + + ClearFilterList(ProcessFilterList); + CopyFilterList(ProcessFilterList, EditingProcessFilterList); + + string = SaveFilterList(ProcessFilterList); + PhSetStringSetting2(SETTING_NAME_PROCESS_LIST, &string->sr); + PhDereferenceObject(string); + + SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_NOERROR); + } + return TRUE; + } + } + break; + } + + return FALSE; +} + +INT_PTR CALLBACK ServicesDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + if (HandleCommonMessages(hwndDlg, uMsg, wParam, lParam, + GetDlgItem(hwndDlg, IDC_LIST), EditingServiceFilterList)) + return FALSE; + + switch (uMsg) + { + case WM_INITDIALOG: + { + EditingServiceFilterList = PhCreateList(ServiceFilterList->Count + 10); + CopyFilterList(EditingServiceFilterList, ServiceFilterList); + + AddEntriesToListBox(GetDlgItem(hwndDlg, IDC_LIST), EditingServiceFilterList); + } + break; + case WM_DESTROY: + { + ClearFilterList(EditingServiceFilterList); + PhDereferenceObject(EditingServiceFilterList); + EditingServiceFilterList = NULL; + } + break; + case WM_COMMAND: + { + switch (LOWORD(wParam)) + { + NOTHING; + } + } + break; + case WM_NOTIFY: + { + LPNMHDR header = (LPNMHDR)lParam; + + switch (header->code) + { + case PSN_APPLY: + { + PPH_STRING string; + + ClearFilterList(ServiceFilterList); + CopyFilterList(ServiceFilterList, EditingServiceFilterList); + + string = SaveFilterList(ServiceFilterList); + PhSetStringSetting2(SETTING_NAME_SERVICE_LIST, &string->sr); + PhDereferenceObject(string); + + SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_NOERROR); + } + return TRUE; + } + } + break; + } + + return FALSE; +} + +INT_PTR CALLBACK LoggingDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + switch (uMsg) + { + case WM_INITDIALOG: + { + SetDlgItemText(hwndDlg, IDC_LOGFILENAME, ((PPH_STRING)PH_AUTO(PhGetStringSetting(SETTING_NAME_LOG_FILENAME)))->Buffer); + } + break; + case WM_COMMAND: + { + switch (LOWORD(wParam)) + { + case IDC_BROWSE: + { + static PH_FILETYPE_FILTER filters[] = + { + { L"Log files (*.txt;*.log)", L"*.txt;*.log" }, + { L"All files (*.*)", L"*.*" } + }; + PVOID fileDialog; + PPH_STRING fileName; + + fileDialog = PhCreateSaveFileDialog(); + PhSetFileDialogFilter(fileDialog, filters, sizeof(filters) / sizeof(PH_FILETYPE_FILTER)); + + fileName = PH_AUTO(PhGetFileName(PhaGetDlgItemText(hwndDlg, IDC_LOGFILENAME))); + PhSetFileDialogFileName(fileDialog, fileName->Buffer); + + if (PhShowFileDialog(hwndDlg, fileDialog)) + { + fileName = PH_AUTO(PhGetFileDialogFileName(fileDialog)); + SetDlgItemText(hwndDlg, IDC_LOGFILENAME, fileName->Buffer); + } + + PhFreeFileDialog(fileDialog); + } + break; + } + } + break; + case WM_NOTIFY: + { + LPNMHDR header = (LPNMHDR)lParam; + + switch (header->code) + { + case PSN_APPLY: + { + PhSetStringSetting2(SETTING_NAME_LOG_FILENAME, &PhaGetDlgItemText(hwndDlg, IDC_LOGFILENAME)->sr); + + SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_NOERROR); + } + return TRUE; + } + } + break; + } + + return FALSE; +} + +INT_PTR CALLBACK GrowlDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + switch (uMsg) + { + case WM_INITDIALOG: + { + SetDlgItemText(hwndDlg, IDC_LICENSE, PH_AUTO_T(PH_STRING, PhConvertUtf8ToUtf16(gntp_send_license_text))->Buffer); + + Button_SetCheck(GetDlgItem(hwndDlg, IDC_ENABLEGROWL), PhGetIntegerSetting(SETTING_NAME_ENABLE_GROWL) ? BST_CHECKED : BST_UNCHECKED); + } + break; + case WM_NOTIFY: + { + LPNMHDR header = (LPNMHDR)lParam; + + switch (header->code) + { + case PSN_QUERYINITIALFOCUS: + { + SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, (LONG_PTR)GetDlgItem(hwndDlg, IDC_ENABLEGROWL)); + } + return TRUE; + case PSN_APPLY: + { + PhSetIntegerSetting(SETTING_NAME_ENABLE_GROWL, Button_GetCheck(GetDlgItem(hwndDlg, IDC_ENABLEGROWL)) == BST_CHECKED); + + if (PhGetIntegerSetting(SETTING_NAME_ENABLE_GROWL)) + RegisterGrowl(FALSE); + + SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_NOERROR); + } + return TRUE; + } + } + break; + } + + return FALSE; +} diff --git a/plugins/ExtendedNotifications/resource.h b/plugins/ExtendedNotifications/resource.h index 2aee867c7e6a..7222e3a05259 100644 --- a/plugins/ExtendedNotifications/resource.h +++ b/plugins/ExtendedNotifications/resource.h @@ -1,33 +1,33 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by ExtendedNotifications.rc -// -#define IDD_PROCESSES 101 -#define IDC_TEXT_RETURN 101 -#define IDD_SERVICES 102 -#define IDD_LOGGING 103 -#define IDD_GROWL 104 -#define IDC_INCLUDE 1006 -#define IDC_EXCLUDE 1007 -#define IDC_REMOVE 1008 -#define IDC_ADD 1009 -#define IDC_MOVEUP 1010 -#define IDC_MOVEDOWN 1011 -#define IDC_LIST 1012 -#define IDC_TEXT 1013 -#define IDC_EDIT1 1014 -#define IDC_LOGFILENAME 1014 -#define IDC_LICENSE 1014 -#define IDC_BROWSE 1015 -#define IDC_ENABLEGROWL 1016 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 108 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1017 -#define _APS_NEXT_SYMED_VALUE 102 -#endif -#endif +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by ExtendedNotifications.rc +// +#define IDD_PROCESSES 101 +#define IDC_TEXT_RETURN 101 +#define IDD_SERVICES 102 +#define IDD_LOGGING 103 +#define IDD_GROWL 104 +#define IDC_INCLUDE 1006 +#define IDC_EXCLUDE 1007 +#define IDC_REMOVE 1008 +#define IDC_ADD 1009 +#define IDC_MOVEUP 1010 +#define IDC_MOVEDOWN 1011 +#define IDC_LIST 1012 +#define IDC_TEXT 1013 +#define IDC_EDIT1 1014 +#define IDC_LOGFILENAME 1014 +#define IDC_LICENSE 1014 +#define IDC_BROWSE 1015 +#define IDC_ENABLEGROWL 1016 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 108 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1017 +#define _APS_NEXT_SYMED_VALUE 102 +#endif +#endif diff --git a/plugins/ExtendedServices/CHANGELOG.txt b/plugins/ExtendedServices/CHANGELOG.txt index d67de79b3774..680ed4c8a80c 100644 --- a/plugins/ExtendedServices/CHANGELOG.txt +++ b/plugins/ExtendedServices/CHANGELOG.txt @@ -1,38 +1,38 @@ -1.10 - * Added service protection and SID information - * Added auto-elevation when saving recovery information, triggers and other service settings - -1.9 - * Added new trigger data types - -1.8 - * Fixed some bugs relating to Windows 8 - -1.7 - * Added new triggers for Windows 8 - * Fixed bug when restarting services - -1.6 - * Disabled editing of required privileges for drivers - -1.5 - * Added support for editing triggers - * Added support for editing preshutdown time-out - * Added support for editing required privileges - * Added elevation support for restarting services - -1.4 - * Improved Services submenu when there is only one service - -1.3 - * Added Services submenu for processes - -1.2 - * Added Other tab - -1.1 - * Added Restart menu item for services - * Fixed service handle leak - -1.0 - * Initial release +1.10 + * Added service protection and SID information + * Added auto-elevation when saving recovery information, triggers and other service settings + +1.9 + * Added new trigger data types + +1.8 + * Fixed some bugs relating to Windows 8 + +1.7 + * Added new triggers for Windows 8 + * Fixed bug when restarting services + +1.6 + * Disabled editing of required privileges for drivers + +1.5 + * Added support for editing triggers + * Added support for editing preshutdown time-out + * Added support for editing required privileges + * Added elevation support for restarting services + +1.4 + * Improved Services submenu when there is only one service + +1.3 + * Added Services submenu for processes + +1.2 + * Added Other tab + +1.1 + * Added Restart menu item for services + * Fixed service handle leak + +1.0 + * Initial release diff --git a/plugins/ExtendedServices/ExtendedServices.rc b/plugins/ExtendedServices/ExtendedServices.rc index 8a8257313de0..82d6e9477509 100644 --- a/plugins/ExtendedServices/ExtendedServices.rc +++ b/plugins/ExtendedServices/ExtendedServices.rc @@ -1,349 +1,349 @@ -// Microsoft Visual C++ generated resource script. -// -#include "resource.h" - -#define APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// -#include "winres.h" -///////////////////////////////////////////////////////////////////////////// -#undef APSTUDIO_READONLY_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -// English (Australia) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENA) -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_AUS -#pragma code_page(1252) - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -1 TEXTINCLUDE -BEGIN - "resource.h\0" -END - -2 TEXTINCLUDE -BEGIN - "#include ""winres.h""\0" -END - -3 TEXTINCLUDE -BEGIN - "\r\n" - "\0" -END - -#endif // APSTUDIO_INVOKED - - -///////////////////////////////////////////////////////////////////////////// -// -// Version -// - -VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,10,0,0 - PRODUCTVERSION 1,10,0,0 - FILEFLAGSMASK 0x3fL -#ifdef _DEBUG - FILEFLAGS 0x1L -#else - FILEFLAGS 0x0L -#endif - FILEOS 0x40004L - FILETYPE 0x2L - FILESUBTYPE 0x0L -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "0c0904b0" - BEGIN - VALUE "CompanyName", "wj32" - VALUE "FileDescription", "Extended Services for Process Hacker" - VALUE "FileVersion", "1.10" - VALUE "InternalName", "ProcessHacker.ExtendedServices" - VALUE "LegalCopyright", "Licensed under the GNU GPL, v3." - VALUE "OriginalFilename", "ExtendedServices.dll" - VALUE "ProductName", "Extended Services for Process Hacker" - VALUE "ProductVersion", "1.10" - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0xc09, 1200 - END -END - - -///////////////////////////////////////////////////////////////////////////// -// -// Dialog -// - -IDD_SRVLIST DIALOGEX 0, 0, 282, 183 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "List" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "Static",IDC_SERVICES_LAYOUT,7,19,268,157,NOT WS_VISIBLE - LTEXT "Static",IDC_MESSAGE,7,7,268,8 -END - -IDD_SRVRECOVERY DIALOGEX 0, 0, 282, 183 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Recovery" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "First failure:",IDC_STATIC,7,8,40,8 - COMBOBOX IDC_FIRSTFAILURE,85,7,103,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LTEXT "Second failure:",IDC_STATIC,7,24,49,8 - COMBOBOX IDC_SECONDFAILURE,85,23,103,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LTEXT "Subsequent failures:",IDC_STATIC,7,40,67,8 - COMBOBOX IDC_SUBSEQUENTFAILURES,85,39,103,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LTEXT "Reset fail count after:",IDC_STATIC,7,56,72,8 - EDITTEXT IDC_RESETFAILCOUNT,85,55,40,12,ES_AUTOHSCROLL | ES_NUMBER - LTEXT "days",IDC_STATIC,130,56,16,8 - LTEXT "Restart service after:",IDC_RESTARTSERVICEAFTER_LABEL,7,72,70,8 - EDITTEXT IDC_RESTARTSERVICEAFTER,85,71,40,12,ES_AUTOHSCROLL | ES_NUMBER - LTEXT "minutes",IDC_RESTARTSERVICEAFTER_MINUTES,130,72,26,8 - CONTROL "Enable actions for stops with errors",IDC_ENABLEFORERRORSTOPS, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,87,129,10 - PUSHBUTTON "Restart computer options...",IDC_RESTARTCOMPUTEROPTIONS,7,100,114,14 - GROUPBOX "Run program",IDC_RUNPROGRAM_GROUP,7,118,268,45 - LTEXT "Program:",IDC_RUNPROGRAM_LABEL,15,132,30,8 - EDITTEXT IDC_RUNPROGRAM,50,131,165,12,ES_AUTOHSCROLL - PUSHBUTTON "Browse...",IDC_BROWSE,220,130,50,14 - LTEXT "Append /fail=%1% to pass the fail count to the program.",IDC_RUNPROGRAM_INFO,15,148,186,8 -END - -IDD_RESTARTCOMP DIALOGEX 0, 0, 245, 137 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Dialog" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "Restart the computer after:",IDC_STATIC,7,8,90,8 - EDITTEXT IDC_RESTARTCOMPAFTER,102,7,40,12,ES_AUTOHSCROLL | ES_NUMBER - LTEXT "minutes",IDC_STATIC,147,8,26,8 - CONTROL "Before restarting, send this message to computers on the network:",IDC_ENABLERESTARTMESSAGE, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,23,231,10 - EDITTEXT IDC_RESTARTMESSAGE,7,36,231,76,ES_MULTILINE | ES_AUTOVSCROLL | ES_WANTRETURN | WS_VSCROLL - PUSHBUTTON "Use default message",IDC_USEDEFAULTMESSAGE,7,116,79,14 - DEFPUSHBUTTON "OK",IDOK,134,116,50,14 - PUSHBUTTON "Cancel",IDCANCEL,188,116,50,14 -END - -IDD_SRVRECOVERY2 DIALOGEX 0, 0, 282, 183 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Recovery" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - CTEXT "If this service fails, the computer will restart.\nRecovery actions are not supported for this service.",IDC_STATIC,51,80,179,21 -END - -IDD_SRVPROGRESS DIALOGEX 0, 0, 204, 61 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Progress" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - PUSHBUTTON "Cancel",IDCANCEL,147,40,50,14 - LTEXT "Progress",IDC_MESSAGE,7,7,190,8,SS_ENDELLIPSIS - CONTROL "",IDC_PROGRESS,"msctls_progress32",WS_BORDER,7,21,190,14 -END - -IDD_SRVOTHER DIALOGEX 0, 0, 282, 218 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Other" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "Preshutdown timeout:",IDC_STATIC,7,8,72,8 - EDITTEXT IDC_PRESHUTDOWNTIMEOUT,85,7,75,12,ES_AUTOHSCROLL - LTEXT "milliseconds",IDC_STATIC,166,8,38,8 - LTEXT "Service SID:",IDC_STATIC,7,24,40,8 - EDITTEXT IDC_SERVICESID,64,23,211,12,ES_AUTOHSCROLL | ES_READONLY - LTEXT "SID type:",IDC_STATIC,7,40,32,8 - COMBOBOX IDC_SIDTYPE,64,39,122,30,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP - LTEXT "Protection:",IDC_STATIC,7,57,36,8 - COMBOBOX IDC_PROTECTION,64,56,122,30,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP - LTEXT "Required privileges:",IDC_STATIC,7,77,64,8 - CONTROL "",IDC_PRIVILEGES,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,88,268,79 - PUSHBUTTON "Add...",IDC_ADD,171,171,50,14 - PUSHBUTTON "Remove",IDC_REMOVE,225,171,50,14 -END - -IDD_OPTIONS DIALOGEX 0, 0, 215, 54 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Options" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - CONTROL "Enable Services submenu for processes",IDC_ENABLESERVICESMENU, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,7,142,10 - PUSHBUTTON "Close",IDOK,158,33,50,14 -END - -IDD_SRVTRIGGER DIALOGEX 0, 0, 330, 196 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Trigger" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "Type:",IDC_STATIC,7,9,20,8 - COMBOBOX IDC_TYPE,52,7,271,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LTEXT "Subtype:",IDC_STATIC,7,26,30,8 - COMBOBOX IDC_SUBTYPE,52,24,271,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - EDITTEXT IDC_SUBTYPECUSTOM,52,41,271,12,ES_AUTOHSCROLL - LTEXT "Action:",IDC_STATIC,7,59,24,8 - COMBOBOX IDC_ACTION,52,58,72,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LTEXT "Data items:",IDC_STATIC,7,76,38,8 - CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,52,79,217,90 - PUSHBUTTON "New...",IDC_NEW,273,79,50,14 - PUSHBUTTON "Edit...",IDC_EDIT,273,96,50,14 - PUSHBUTTON "Delete",IDC_DELETE,273,113,50,14 - DEFPUSHBUTTON "OK",IDOK,219,175,50,14 - PUSHBUTTON "Cancel",IDCANCEL,273,175,50,14 -END - -IDD_VALUE DIALOGEX 0, 0, 267, 167 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Edit Data" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "Values (one per line):",IDC_STATIC,7,7,69,8 - EDITTEXT IDC_VALUES,7,18,253,124,ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_WANTRETURN | WS_VSCROLL - DEFPUSHBUTTON "OK",IDOK,156,146,50,14 - PUSHBUTTON "Cancel",IDCANCEL,210,146,50,14 -END - -IDD_SRVTRIGGERS DIALOGEX 0, 0, 282, 218 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Triggers" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - CONTROL "",IDC_TRIGGERS,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,7,268,186 - PUSHBUTTON "New...",IDC_NEW,117,197,50,14 - PUSHBUTTON "Edit...",IDC_EDIT,171,197,50,14 - PUSHBUTTON "Delete",IDC_DELETE,225,197,50,14 -END - - -///////////////////////////////////////////////////////////////////////////// -// -// DESIGNINFO -// - -#ifdef APSTUDIO_INVOKED -GUIDELINES DESIGNINFO -BEGIN - IDD_SRVLIST, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 275 - TOPMARGIN, 7 - BOTTOMMARGIN, 176 - END - - IDD_SRVRECOVERY, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 275 - TOPMARGIN, 7 - BOTTOMMARGIN, 176 - END - - IDD_RESTARTCOMP, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 238 - TOPMARGIN, 7 - BOTTOMMARGIN, 130 - END - - IDD_SRVRECOVERY2, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 275 - TOPMARGIN, 7 - BOTTOMMARGIN, 176 - END - - IDD_SRVPROGRESS, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 197 - TOPMARGIN, 7 - BOTTOMMARGIN, 54 - END - - IDD_SRVOTHER, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 275 - TOPMARGIN, 7 - BOTTOMMARGIN, 211 - END - - IDD_OPTIONS, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 208 - TOPMARGIN, 7 - BOTTOMMARGIN, 47 - END - - IDD_SRVTRIGGER, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 323 - TOPMARGIN, 7 - BOTTOMMARGIN, 189 - END - - IDD_VALUE, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 260 - TOPMARGIN, 7 - BOTTOMMARGIN, 160 - END - - IDD_SRVTRIGGERS, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 275 - TOPMARGIN, 7 - BOTTOMMARGIN, 211 - END -END -#endif // APSTUDIO_INVOKED - - -///////////////////////////////////////////////////////////////////////////// -// -// AFX_DIALOG_LAYOUT -// - -IDD_OPTIONS AFX_DIALOG_LAYOUT -BEGIN - 0 -END - -#endif // English (Australia) resources -///////////////////////////////////////////////////////////////////////////// - - - -#ifndef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// - - -///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED - +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "winres.h" +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (Australia) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENA) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_AUS +#pragma code_page(1252) + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""winres.h""\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,10,0,0 + PRODUCTVERSION 1,10,0,0 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "0c0904b0" + BEGIN + VALUE "CompanyName", "wj32" + VALUE "FileDescription", "Extended Services for Process Hacker" + VALUE "FileVersion", "1.10" + VALUE "InternalName", "ProcessHacker.ExtendedServices" + VALUE "LegalCopyright", "Licensed under the GNU GPL, v3." + VALUE "OriginalFilename", "ExtendedServices.dll" + VALUE "ProductName", "Extended Services for Process Hacker" + VALUE "ProductVersion", "1.10" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0xc09, 1200 + END +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_SRVLIST DIALOGEX 0, 0, 282, 183 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "List" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "Static",IDC_SERVICES_LAYOUT,7,19,268,157,NOT WS_VISIBLE + LTEXT "Static",IDC_MESSAGE,7,7,268,8 +END + +IDD_SRVRECOVERY DIALOGEX 0, 0, 282, 183 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Recovery" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "First failure:",IDC_STATIC,7,8,40,8 + COMBOBOX IDC_FIRSTFAILURE,85,7,103,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + LTEXT "Second failure:",IDC_STATIC,7,24,49,8 + COMBOBOX IDC_SECONDFAILURE,85,23,103,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + LTEXT "Subsequent failures:",IDC_STATIC,7,40,67,8 + COMBOBOX IDC_SUBSEQUENTFAILURES,85,39,103,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + LTEXT "Reset fail count after:",IDC_STATIC,7,56,72,8 + EDITTEXT IDC_RESETFAILCOUNT,85,55,40,12,ES_AUTOHSCROLL | ES_NUMBER + LTEXT "days",IDC_STATIC,130,56,16,8 + LTEXT "Restart service after:",IDC_RESTARTSERVICEAFTER_LABEL,7,72,70,8 + EDITTEXT IDC_RESTARTSERVICEAFTER,85,71,40,12,ES_AUTOHSCROLL | ES_NUMBER + LTEXT "minutes",IDC_RESTARTSERVICEAFTER_MINUTES,130,72,26,8 + CONTROL "Enable actions for stops with errors",IDC_ENABLEFORERRORSTOPS, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,87,129,10 + PUSHBUTTON "Restart computer options...",IDC_RESTARTCOMPUTEROPTIONS,7,100,114,14 + GROUPBOX "Run program",IDC_RUNPROGRAM_GROUP,7,118,268,45 + LTEXT "Program:",IDC_RUNPROGRAM_LABEL,15,132,30,8 + EDITTEXT IDC_RUNPROGRAM,50,131,165,12,ES_AUTOHSCROLL + PUSHBUTTON "Browse...",IDC_BROWSE,220,130,50,14 + LTEXT "Append /fail=%1% to pass the fail count to the program.",IDC_RUNPROGRAM_INFO,15,148,186,8 +END + +IDD_RESTARTCOMP DIALOGEX 0, 0, 245, 137 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Dialog" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "Restart the computer after:",IDC_STATIC,7,8,90,8 + EDITTEXT IDC_RESTARTCOMPAFTER,102,7,40,12,ES_AUTOHSCROLL | ES_NUMBER + LTEXT "minutes",IDC_STATIC,147,8,26,8 + CONTROL "Before restarting, send this message to computers on the network:",IDC_ENABLERESTARTMESSAGE, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,23,231,10 + EDITTEXT IDC_RESTARTMESSAGE,7,36,231,76,ES_MULTILINE | ES_AUTOVSCROLL | ES_WANTRETURN | WS_VSCROLL + PUSHBUTTON "Use default message",IDC_USEDEFAULTMESSAGE,7,116,79,14 + DEFPUSHBUTTON "OK",IDOK,134,116,50,14 + PUSHBUTTON "Cancel",IDCANCEL,188,116,50,14 +END + +IDD_SRVRECOVERY2 DIALOGEX 0, 0, 282, 183 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Recovery" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + CTEXT "If this service fails, the computer will restart.\nRecovery actions are not supported for this service.",IDC_STATIC,51,80,179,21 +END + +IDD_SRVPROGRESS DIALOGEX 0, 0, 204, 61 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Progress" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + PUSHBUTTON "Cancel",IDCANCEL,147,40,50,14 + LTEXT "Progress",IDC_MESSAGE,7,7,190,8,SS_ENDELLIPSIS + CONTROL "",IDC_PROGRESS,"msctls_progress32",WS_BORDER,7,21,190,14 +END + +IDD_SRVOTHER DIALOGEX 0, 0, 282, 218 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Other" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "Preshutdown timeout:",IDC_STATIC,7,8,72,8 + EDITTEXT IDC_PRESHUTDOWNTIMEOUT,85,7,75,12,ES_AUTOHSCROLL + LTEXT "milliseconds",IDC_STATIC,166,8,38,8 + LTEXT "Service SID:",IDC_STATIC,7,24,40,8 + EDITTEXT IDC_SERVICESID,64,23,211,12,ES_AUTOHSCROLL | ES_READONLY + LTEXT "SID type:",IDC_STATIC,7,40,32,8 + COMBOBOX IDC_SIDTYPE,64,39,122,30,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "Protection:",IDC_STATIC,7,57,36,8 + COMBOBOX IDC_PROTECTION,64,56,122,30,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "Required privileges:",IDC_STATIC,7,77,64,8 + CONTROL "",IDC_PRIVILEGES,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,88,268,79 + PUSHBUTTON "Add...",IDC_ADD,171,171,50,14 + PUSHBUTTON "Remove",IDC_REMOVE,225,171,50,14 +END + +IDD_OPTIONS DIALOGEX 0, 0, 215, 54 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Options" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + CONTROL "Enable Services submenu for processes",IDC_ENABLESERVICESMENU, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,7,142,10 + PUSHBUTTON "Close",IDOK,158,33,50,14 +END + +IDD_SRVTRIGGER DIALOGEX 0, 0, 330, 196 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Trigger" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "Type:",IDC_STATIC,7,9,20,8 + COMBOBOX IDC_TYPE,52,7,271,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + LTEXT "Subtype:",IDC_STATIC,7,26,30,8 + COMBOBOX IDC_SUBTYPE,52,24,271,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + EDITTEXT IDC_SUBTYPECUSTOM,52,41,271,12,ES_AUTOHSCROLL + LTEXT "Action:",IDC_STATIC,7,59,24,8 + COMBOBOX IDC_ACTION,52,58,72,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + LTEXT "Data items:",IDC_STATIC,7,76,38,8 + CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,52,79,217,90 + PUSHBUTTON "New...",IDC_NEW,273,79,50,14 + PUSHBUTTON "Edit...",IDC_EDIT,273,96,50,14 + PUSHBUTTON "Delete",IDC_DELETE,273,113,50,14 + DEFPUSHBUTTON "OK",IDOK,219,175,50,14 + PUSHBUTTON "Cancel",IDCANCEL,273,175,50,14 +END + +IDD_VALUE DIALOGEX 0, 0, 267, 167 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Edit Data" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "Values (one per line):",IDC_STATIC,7,7,69,8 + EDITTEXT IDC_VALUES,7,18,253,124,ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_WANTRETURN | WS_VSCROLL + DEFPUSHBUTTON "OK",IDOK,156,146,50,14 + PUSHBUTTON "Cancel",IDCANCEL,210,146,50,14 +END + +IDD_SRVTRIGGERS DIALOGEX 0, 0, 282, 218 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Triggers" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + CONTROL "",IDC_TRIGGERS,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,7,268,186 + PUSHBUTTON "New...",IDC_NEW,117,197,50,14 + PUSHBUTTON "Edit...",IDC_EDIT,171,197,50,14 + PUSHBUTTON "Delete",IDC_DELETE,225,197,50,14 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_SRVLIST, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 275 + TOPMARGIN, 7 + BOTTOMMARGIN, 176 + END + + IDD_SRVRECOVERY, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 275 + TOPMARGIN, 7 + BOTTOMMARGIN, 176 + END + + IDD_RESTARTCOMP, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 238 + TOPMARGIN, 7 + BOTTOMMARGIN, 130 + END + + IDD_SRVRECOVERY2, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 275 + TOPMARGIN, 7 + BOTTOMMARGIN, 176 + END + + IDD_SRVPROGRESS, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 197 + TOPMARGIN, 7 + BOTTOMMARGIN, 54 + END + + IDD_SRVOTHER, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 275 + TOPMARGIN, 7 + BOTTOMMARGIN, 211 + END + + IDD_OPTIONS, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 208 + TOPMARGIN, 7 + BOTTOMMARGIN, 47 + END + + IDD_SRVTRIGGER, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 323 + TOPMARGIN, 7 + BOTTOMMARGIN, 189 + END + + IDD_VALUE, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 260 + TOPMARGIN, 7 + BOTTOMMARGIN, 160 + END + + IDD_SRVTRIGGERS, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 275 + TOPMARGIN, 7 + BOTTOMMARGIN, 211 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// AFX_DIALOG_LAYOUT +// + +IDD_OPTIONS AFX_DIALOG_LAYOUT +BEGIN + 0 +END + +#endif // English (Australia) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/plugins/ExtendedServices/ExtendedServices.vcxproj b/plugins/ExtendedServices/ExtendedServices.vcxproj index e56beba514e7..55fd13d45770 100644 --- a/plugins/ExtendedServices/ExtendedServices.vcxproj +++ b/plugins/ExtendedServices/ExtendedServices.vcxproj @@ -1,75 +1,75 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {AC547368-D861-4B88-B5D4-E3B1F1AEEEDD} - ExtendedServices - Win32Proj - ExtendedServices - 10.0.15063.0 - - - - DynamicLibrary - Unicode - v141 - - - DynamicLibrary - Unicode - v141 - - - DynamicLibrary - Unicode - v141 - - - DynamicLibrary - Unicode - v141 - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {AC547368-D861-4B88-B5D4-E3B1F1AEEEDD} + ExtendedServices + Win32Proj + ExtendedServices + 10.0.15063.0 + + + + DynamicLibrary + Unicode + v141 + + + DynamicLibrary + Unicode + v141 + + + DynamicLibrary + Unicode + v141 + + + DynamicLibrary + Unicode + v141 + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/plugins/ExtendedServices/depend.c b/plugins/ExtendedServices/depend.c index b28b234085c2..dc15aa52f2ad 100644 --- a/plugins/ExtendedServices/depend.c +++ b/plugins/ExtendedServices/depend.c @@ -1,344 +1,344 @@ -/* - * Process Hacker Extended Services - - * dependencies and dependents - * - * Copyright (C) 2010 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include "extsrv.h" - -typedef struct _SERVICE_LIST_CONTEXT -{ - HWND ServiceListHandle; - PH_LAYOUT_MANAGER LayoutManager; -} SERVICE_LIST_CONTEXT, *PSERVICE_LIST_CONTEXT; - -LPENUM_SERVICE_STATUS EsEnumDependentServices( - _In_ SC_HANDLE ServiceHandle, - _In_opt_ ULONG State, - _Out_ PULONG Count - ) -{ - LOGICAL result; - PVOID buffer; - ULONG bufferSize; - ULONG returnLength; - ULONG servicesReturned; - - if (!State) - State = SERVICE_STATE_ALL; - - bufferSize = 0x800; - buffer = PhAllocate(bufferSize); - - if (!(result = EnumDependentServices( - ServiceHandle, - State, - buffer, - bufferSize, - &returnLength, - &servicesReturned - ))) - { - if (GetLastError() == ERROR_MORE_DATA) - { - PhFree(buffer); - bufferSize = returnLength; - buffer = PhAllocate(bufferSize); - - result = EnumDependentServices( - ServiceHandle, - State, - buffer, - bufferSize, - &returnLength, - &servicesReturned - ); - } - - if (!result) - { - PhFree(buffer); - return NULL; - } - } - - *Count = servicesReturned; - - return buffer; -} - -VOID EspLayoutServiceListControl( - _In_ HWND hwndDlg, - _In_ HWND ServiceListHandle - ) -{ - RECT rect; - - GetWindowRect(GetDlgItem(hwndDlg, IDC_SERVICES_LAYOUT), &rect); - MapWindowPoints(NULL, hwndDlg, (POINT *)&rect, 2); - - MoveWindow( - ServiceListHandle, - rect.left, - rect.top, - rect.right - rect.left, - rect.bottom - rect.top, - TRUE - ); -} - -INT_PTR CALLBACK EspServiceDependenciesDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - PSERVICE_LIST_CONTEXT context; - - if (uMsg == WM_INITDIALOG) - { - context = PhAllocate(sizeof(SERVICE_LIST_CONTEXT)); - memset(context, 0, sizeof(SERVICE_LIST_CONTEXT)); - - SetProp(hwndDlg, L"Context", (HANDLE)context); - } - else - { - context = (PSERVICE_LIST_CONTEXT)GetProp(hwndDlg, L"Context"); - - if (uMsg == WM_DESTROY) - RemoveProp(hwndDlg, L"Context"); - } - - if (!context) - return FALSE; - - switch (uMsg) - { - case WM_INITDIALOG: - { - LPPROPSHEETPAGE propSheetPage = (LPPROPSHEETPAGE)lParam; - PPH_SERVICE_ITEM serviceItem = (PPH_SERVICE_ITEM)propSheetPage->lParam; - HWND serviceListHandle; - PPH_LIST serviceList; - SC_HANDLE serviceHandle; - ULONG win32Result = 0; - BOOLEAN success = FALSE; - PPH_SERVICE_ITEM *services; - - SetDlgItemText(hwndDlg, IDC_MESSAGE, L"This service depends on the following services:"); - - PhInitializeLayoutManager(&context->LayoutManager, hwndDlg); - PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_SERVICES_LAYOUT), NULL, PH_ANCHOR_ALL); - - if (serviceHandle = PhOpenService(serviceItem->Name->Buffer, SERVICE_QUERY_CONFIG)) - { - LPQUERY_SERVICE_CONFIG serviceConfig; - - if (serviceConfig = PhGetServiceConfig(serviceHandle)) - { - PWSTR dependency; - PPH_SERVICE_ITEM dependencyService; - - dependency = serviceConfig->lpDependencies; - serviceList = PH_AUTO(PhCreateList(8)); - success = TRUE; - - if (dependency) - { - ULONG dependencyLength; - - while (TRUE) - { - dependencyLength = (ULONG)PhCountStringZ(dependency); - - if (dependencyLength == 0) - break; - - if (dependency[0] == SC_GROUP_IDENTIFIER) - goto ContinueLoop; - - if (dependencyService = PhReferenceServiceItem(dependency)) - PhAddItemList(serviceList, dependencyService); - -ContinueLoop: - dependency += dependencyLength + 1; - } - } - - services = PhAllocateCopy(serviceList->Items, sizeof(PPH_SERVICE_ITEM) * serviceList->Count); - - serviceListHandle = PhCreateServiceListControl(hwndDlg, services, serviceList->Count); - context->ServiceListHandle = serviceListHandle; - EspLayoutServiceListControl(hwndDlg, serviceListHandle); - ShowWindow(serviceListHandle, SW_SHOW); - - PhFree(serviceConfig); - } - else - { - win32Result = GetLastError(); - } - - CloseServiceHandle(serviceHandle); - } - else - { - win32Result = GetLastError(); - } - - if (!success) - { - SetDlgItemText(hwndDlg, IDC_SERVICES_LAYOUT, PhaConcatStrings2(L"Unable to enumerate dependencies: ", - ((PPH_STRING)PH_AUTO(PhGetWin32Message(win32Result)))->Buffer)->Buffer); - ShowWindow(GetDlgItem(hwndDlg, IDC_SERVICES_LAYOUT), SW_SHOW); - } - } - break; - case WM_DESTROY: - { - PhDeleteLayoutManager(&context->LayoutManager); - PhFree(context); - } - break; - case WM_SIZE: - { - PhLayoutManagerLayout(&context->LayoutManager); - - if (context->ServiceListHandle) - EspLayoutServiceListControl(hwndDlg, context->ServiceListHandle); - } - break; - } - - return FALSE; -} - -INT_PTR CALLBACK EspServiceDependentsDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - PSERVICE_LIST_CONTEXT context; - - if (uMsg == WM_INITDIALOG) - { - context = PhAllocate(sizeof(SERVICE_LIST_CONTEXT)); - memset(context, 0, sizeof(SERVICE_LIST_CONTEXT)); - - SetProp(hwndDlg, L"Context", (HANDLE)context); - } - else - { - context = (PSERVICE_LIST_CONTEXT)GetProp(hwndDlg, L"Context"); - - if (uMsg == WM_DESTROY) - RemoveProp(hwndDlg, L"Context"); - } - - if (!context) - return FALSE; - - switch (uMsg) - { - case WM_INITDIALOG: - { - LPPROPSHEETPAGE propSheetPage = (LPPROPSHEETPAGE)lParam; - PPH_SERVICE_ITEM serviceItem = (PPH_SERVICE_ITEM)propSheetPage->lParam; - HWND serviceListHandle; - PPH_LIST serviceList; - SC_HANDLE serviceHandle; - ULONG win32Result = 0; - BOOLEAN success = FALSE; - PPH_SERVICE_ITEM *services; - - SetDlgItemText(hwndDlg, IDC_MESSAGE, L"The following services depend on this service:"); - - PhInitializeLayoutManager(&context->LayoutManager, hwndDlg); - PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_SERVICES_LAYOUT), NULL, PH_ANCHOR_ALL); - - if (serviceHandle = PhOpenService(serviceItem->Name->Buffer, SERVICE_ENUMERATE_DEPENDENTS)) - { - LPENUM_SERVICE_STATUS dependentServices; - ULONG numberOfDependentServices; - - if (dependentServices = EsEnumDependentServices(serviceHandle, 0, &numberOfDependentServices)) - { - ULONG i; - PPH_SERVICE_ITEM dependentService; - - serviceList = PH_AUTO(PhCreateList(8)); - success = TRUE; - - for (i = 0; i < numberOfDependentServices; i++) - { - if (dependentService = PhReferenceServiceItem(dependentServices[i].lpServiceName)) - PhAddItemList(serviceList, dependentService); - } - - services = PhAllocateCopy(serviceList->Items, sizeof(PPH_SERVICE_ITEM) * serviceList->Count); - - serviceListHandle = PhCreateServiceListControl(hwndDlg, services, serviceList->Count); - context->ServiceListHandle = serviceListHandle; - EspLayoutServiceListControl(hwndDlg, serviceListHandle); - ShowWindow(serviceListHandle, SW_SHOW); - - PhFree(dependentServices); - } - else - { - win32Result = GetLastError(); - } - - CloseServiceHandle(serviceHandle); - } - else - { - win32Result = GetLastError(); - } - - if (!success) - { - SetDlgItemText(hwndDlg, IDC_SERVICES_LAYOUT, PhaConcatStrings2(L"Unable to enumerate dependents: ", - ((PPH_STRING)PH_AUTO(PhGetWin32Message(win32Result)))->Buffer)->Buffer); - ShowWindow(GetDlgItem(hwndDlg, IDC_SERVICES_LAYOUT), SW_SHOW); - } - } - break; - case WM_DESTROY: - { - PhDeleteLayoutManager(&context->LayoutManager); - PhFree(context); - } - break; - case WM_SIZE: - { - PhLayoutManagerLayout(&context->LayoutManager); - - if (context->ServiceListHandle) - EspLayoutServiceListControl(hwndDlg, context->ServiceListHandle); - } - break; - } - - return FALSE; -} +/* + * Process Hacker Extended Services - + * dependencies and dependents + * + * Copyright (C) 2010 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include "extsrv.h" + +typedef struct _SERVICE_LIST_CONTEXT +{ + HWND ServiceListHandle; + PH_LAYOUT_MANAGER LayoutManager; +} SERVICE_LIST_CONTEXT, *PSERVICE_LIST_CONTEXT; + +LPENUM_SERVICE_STATUS EsEnumDependentServices( + _In_ SC_HANDLE ServiceHandle, + _In_opt_ ULONG State, + _Out_ PULONG Count + ) +{ + LOGICAL result; + PVOID buffer; + ULONG bufferSize; + ULONG returnLength; + ULONG servicesReturned; + + if (!State) + State = SERVICE_STATE_ALL; + + bufferSize = 0x800; + buffer = PhAllocate(bufferSize); + + if (!(result = EnumDependentServices( + ServiceHandle, + State, + buffer, + bufferSize, + &returnLength, + &servicesReturned + ))) + { + if (GetLastError() == ERROR_MORE_DATA) + { + PhFree(buffer); + bufferSize = returnLength; + buffer = PhAllocate(bufferSize); + + result = EnumDependentServices( + ServiceHandle, + State, + buffer, + bufferSize, + &returnLength, + &servicesReturned + ); + } + + if (!result) + { + PhFree(buffer); + return NULL; + } + } + + *Count = servicesReturned; + + return buffer; +} + +VOID EspLayoutServiceListControl( + _In_ HWND hwndDlg, + _In_ HWND ServiceListHandle + ) +{ + RECT rect; + + GetWindowRect(GetDlgItem(hwndDlg, IDC_SERVICES_LAYOUT), &rect); + MapWindowPoints(NULL, hwndDlg, (POINT *)&rect, 2); + + MoveWindow( + ServiceListHandle, + rect.left, + rect.top, + rect.right - rect.left, + rect.bottom - rect.top, + TRUE + ); +} + +INT_PTR CALLBACK EspServiceDependenciesDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + PSERVICE_LIST_CONTEXT context; + + if (uMsg == WM_INITDIALOG) + { + context = PhAllocate(sizeof(SERVICE_LIST_CONTEXT)); + memset(context, 0, sizeof(SERVICE_LIST_CONTEXT)); + + SetProp(hwndDlg, L"Context", (HANDLE)context); + } + else + { + context = (PSERVICE_LIST_CONTEXT)GetProp(hwndDlg, L"Context"); + + if (uMsg == WM_DESTROY) + RemoveProp(hwndDlg, L"Context"); + } + + if (!context) + return FALSE; + + switch (uMsg) + { + case WM_INITDIALOG: + { + LPPROPSHEETPAGE propSheetPage = (LPPROPSHEETPAGE)lParam; + PPH_SERVICE_ITEM serviceItem = (PPH_SERVICE_ITEM)propSheetPage->lParam; + HWND serviceListHandle; + PPH_LIST serviceList; + SC_HANDLE serviceHandle; + ULONG win32Result = 0; + BOOLEAN success = FALSE; + PPH_SERVICE_ITEM *services; + + SetDlgItemText(hwndDlg, IDC_MESSAGE, L"This service depends on the following services:"); + + PhInitializeLayoutManager(&context->LayoutManager, hwndDlg); + PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_SERVICES_LAYOUT), NULL, PH_ANCHOR_ALL); + + if (serviceHandle = PhOpenService(serviceItem->Name->Buffer, SERVICE_QUERY_CONFIG)) + { + LPQUERY_SERVICE_CONFIG serviceConfig; + + if (serviceConfig = PhGetServiceConfig(serviceHandle)) + { + PWSTR dependency; + PPH_SERVICE_ITEM dependencyService; + + dependency = serviceConfig->lpDependencies; + serviceList = PH_AUTO(PhCreateList(8)); + success = TRUE; + + if (dependency) + { + ULONG dependencyLength; + + while (TRUE) + { + dependencyLength = (ULONG)PhCountStringZ(dependency); + + if (dependencyLength == 0) + break; + + if (dependency[0] == SC_GROUP_IDENTIFIER) + goto ContinueLoop; + + if (dependencyService = PhReferenceServiceItem(dependency)) + PhAddItemList(serviceList, dependencyService); + +ContinueLoop: + dependency += dependencyLength + 1; + } + } + + services = PhAllocateCopy(serviceList->Items, sizeof(PPH_SERVICE_ITEM) * serviceList->Count); + + serviceListHandle = PhCreateServiceListControl(hwndDlg, services, serviceList->Count); + context->ServiceListHandle = serviceListHandle; + EspLayoutServiceListControl(hwndDlg, serviceListHandle); + ShowWindow(serviceListHandle, SW_SHOW); + + PhFree(serviceConfig); + } + else + { + win32Result = GetLastError(); + } + + CloseServiceHandle(serviceHandle); + } + else + { + win32Result = GetLastError(); + } + + if (!success) + { + SetDlgItemText(hwndDlg, IDC_SERVICES_LAYOUT, PhaConcatStrings2(L"Unable to enumerate dependencies: ", + ((PPH_STRING)PH_AUTO(PhGetWin32Message(win32Result)))->Buffer)->Buffer); + ShowWindow(GetDlgItem(hwndDlg, IDC_SERVICES_LAYOUT), SW_SHOW); + } + } + break; + case WM_DESTROY: + { + PhDeleteLayoutManager(&context->LayoutManager); + PhFree(context); + } + break; + case WM_SIZE: + { + PhLayoutManagerLayout(&context->LayoutManager); + + if (context->ServiceListHandle) + EspLayoutServiceListControl(hwndDlg, context->ServiceListHandle); + } + break; + } + + return FALSE; +} + +INT_PTR CALLBACK EspServiceDependentsDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + PSERVICE_LIST_CONTEXT context; + + if (uMsg == WM_INITDIALOG) + { + context = PhAllocate(sizeof(SERVICE_LIST_CONTEXT)); + memset(context, 0, sizeof(SERVICE_LIST_CONTEXT)); + + SetProp(hwndDlg, L"Context", (HANDLE)context); + } + else + { + context = (PSERVICE_LIST_CONTEXT)GetProp(hwndDlg, L"Context"); + + if (uMsg == WM_DESTROY) + RemoveProp(hwndDlg, L"Context"); + } + + if (!context) + return FALSE; + + switch (uMsg) + { + case WM_INITDIALOG: + { + LPPROPSHEETPAGE propSheetPage = (LPPROPSHEETPAGE)lParam; + PPH_SERVICE_ITEM serviceItem = (PPH_SERVICE_ITEM)propSheetPage->lParam; + HWND serviceListHandle; + PPH_LIST serviceList; + SC_HANDLE serviceHandle; + ULONG win32Result = 0; + BOOLEAN success = FALSE; + PPH_SERVICE_ITEM *services; + + SetDlgItemText(hwndDlg, IDC_MESSAGE, L"The following services depend on this service:"); + + PhInitializeLayoutManager(&context->LayoutManager, hwndDlg); + PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_SERVICES_LAYOUT), NULL, PH_ANCHOR_ALL); + + if (serviceHandle = PhOpenService(serviceItem->Name->Buffer, SERVICE_ENUMERATE_DEPENDENTS)) + { + LPENUM_SERVICE_STATUS dependentServices; + ULONG numberOfDependentServices; + + if (dependentServices = EsEnumDependentServices(serviceHandle, 0, &numberOfDependentServices)) + { + ULONG i; + PPH_SERVICE_ITEM dependentService; + + serviceList = PH_AUTO(PhCreateList(8)); + success = TRUE; + + for (i = 0; i < numberOfDependentServices; i++) + { + if (dependentService = PhReferenceServiceItem(dependentServices[i].lpServiceName)) + PhAddItemList(serviceList, dependentService); + } + + services = PhAllocateCopy(serviceList->Items, sizeof(PPH_SERVICE_ITEM) * serviceList->Count); + + serviceListHandle = PhCreateServiceListControl(hwndDlg, services, serviceList->Count); + context->ServiceListHandle = serviceListHandle; + EspLayoutServiceListControl(hwndDlg, serviceListHandle); + ShowWindow(serviceListHandle, SW_SHOW); + + PhFree(dependentServices); + } + else + { + win32Result = GetLastError(); + } + + CloseServiceHandle(serviceHandle); + } + else + { + win32Result = GetLastError(); + } + + if (!success) + { + SetDlgItemText(hwndDlg, IDC_SERVICES_LAYOUT, PhaConcatStrings2(L"Unable to enumerate dependents: ", + ((PPH_STRING)PH_AUTO(PhGetWin32Message(win32Result)))->Buffer)->Buffer); + ShowWindow(GetDlgItem(hwndDlg, IDC_SERVICES_LAYOUT), SW_SHOW); + } + } + break; + case WM_DESTROY: + { + PhDeleteLayoutManager(&context->LayoutManager); + PhFree(context); + } + break; + case WM_SIZE: + { + PhLayoutManagerLayout(&context->LayoutManager); + + if (context->ServiceListHandle) + EspLayoutServiceListControl(hwndDlg, context->ServiceListHandle); + } + break; + } + + return FALSE; +} diff --git a/plugins/ExtendedServices/extsrv.h b/plugins/ExtendedServices/extsrv.h index 654d5db3637d..ff6ee0bd3648 100644 --- a/plugins/ExtendedServices/extsrv.h +++ b/plugins/ExtendedServices/extsrv.h @@ -1,128 +1,128 @@ -#ifndef ES_EXTSRV_H -#define ES_EXTSRV_H - -#include -#include - -#include "resource.h" - -// main - -extern PPH_PLUGIN PluginInstance; - -#define PLUGIN_NAME L"ProcessHacker.ExtendedServices" -#define SETTING_NAME_ENABLE_SERVICES_MENU (PLUGIN_NAME L".EnableServicesMenu") - -#define SIP(String, Integer) { (String), (PVOID)(Integer) } - -// depend - -LPENUM_SERVICE_STATUS EsEnumDependentServices( - _In_ SC_HANDLE ServiceHandle, - _In_opt_ ULONG State, - _Out_ PULONG Count - ); - -INT_PTR CALLBACK EspServiceDependenciesDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -INT_PTR CALLBACK EspServiceDependentsDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -// options - -VOID EsShowOptionsDialog( - _In_ HWND ParentWindowHandle - ); - -// other - -typedef NTSTATUS (NTAPI *_RtlCreateServiceSid)( - _In_ PUNICODE_STRING ServiceName, - _Out_writes_bytes_opt_(*ServiceSidLength) PSID ServiceSid, - _Inout_ PULONG ServiceSidLength - ); - -INT_PTR CALLBACK EspServiceOtherDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -// recovery - -INT_PTR CALLBACK EspServiceRecoveryDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -INT_PTR CALLBACK EspServiceRecovery2DlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -// srvprgrs - -VOID EsRestartServiceWithProgress( - _In_ HWND hWnd, - _In_ PPH_SERVICE_ITEM ServiceItem, - _In_ SC_HANDLE ServiceHandle - ); - -// trigger - -struct _ES_TRIGGER_CONTEXT; - -struct _ES_TRIGGER_CONTEXT *EsCreateServiceTriggerContext( - _In_ PPH_SERVICE_ITEM ServiceItem, - _In_ HWND WindowHandle, - _In_ HWND TriggersLv - ); - -VOID EsDestroyServiceTriggerContext( - _In_ struct _ES_TRIGGER_CONTEXT *Context - ); - -VOID EsLoadServiceTriggerInfo( - _In_ struct _ES_TRIGGER_CONTEXT *Context, - _In_ SC_HANDLE ServiceHandle - ); - -BOOLEAN EsSaveServiceTriggerInfo( - _In_ struct _ES_TRIGGER_CONTEXT *Context, - _Out_ PULONG Win32Result - ); - -#define ES_TRIGGER_EVENT_NEW 1 -#define ES_TRIGGER_EVENT_EDIT 2 -#define ES_TRIGGER_EVENT_DELETE 3 -#define ES_TRIGGER_EVENT_SELECTIONCHANGED 4 - -VOID EsHandleEventServiceTrigger( - _In_ struct _ES_TRIGGER_CONTEXT *Context, - _In_ ULONG Event - ); - -// triggpg - -INT_PTR CALLBACK EspServiceTriggersDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -#endif +#ifndef ES_EXTSRV_H +#define ES_EXTSRV_H + +#include +#include + +#include "resource.h" + +// main + +extern PPH_PLUGIN PluginInstance; + +#define PLUGIN_NAME L"ProcessHacker.ExtendedServices" +#define SETTING_NAME_ENABLE_SERVICES_MENU (PLUGIN_NAME L".EnableServicesMenu") + +#define SIP(String, Integer) { (String), (PVOID)(Integer) } + +// depend + +LPENUM_SERVICE_STATUS EsEnumDependentServices( + _In_ SC_HANDLE ServiceHandle, + _In_opt_ ULONG State, + _Out_ PULONG Count + ); + +INT_PTR CALLBACK EspServiceDependenciesDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +INT_PTR CALLBACK EspServiceDependentsDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +// options + +VOID EsShowOptionsDialog( + _In_ HWND ParentWindowHandle + ); + +// other + +typedef NTSTATUS (NTAPI *_RtlCreateServiceSid)( + _In_ PUNICODE_STRING ServiceName, + _Out_writes_bytes_opt_(*ServiceSidLength) PSID ServiceSid, + _Inout_ PULONG ServiceSidLength + ); + +INT_PTR CALLBACK EspServiceOtherDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +// recovery + +INT_PTR CALLBACK EspServiceRecoveryDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +INT_PTR CALLBACK EspServiceRecovery2DlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +// srvprgrs + +VOID EsRestartServiceWithProgress( + _In_ HWND hWnd, + _In_ PPH_SERVICE_ITEM ServiceItem, + _In_ SC_HANDLE ServiceHandle + ); + +// trigger + +struct _ES_TRIGGER_CONTEXT; + +struct _ES_TRIGGER_CONTEXT *EsCreateServiceTriggerContext( + _In_ PPH_SERVICE_ITEM ServiceItem, + _In_ HWND WindowHandle, + _In_ HWND TriggersLv + ); + +VOID EsDestroyServiceTriggerContext( + _In_ struct _ES_TRIGGER_CONTEXT *Context + ); + +VOID EsLoadServiceTriggerInfo( + _In_ struct _ES_TRIGGER_CONTEXT *Context, + _In_ SC_HANDLE ServiceHandle + ); + +BOOLEAN EsSaveServiceTriggerInfo( + _In_ struct _ES_TRIGGER_CONTEXT *Context, + _Out_ PULONG Win32Result + ); + +#define ES_TRIGGER_EVENT_NEW 1 +#define ES_TRIGGER_EVENT_EDIT 2 +#define ES_TRIGGER_EVENT_DELETE 3 +#define ES_TRIGGER_EVENT_SELECTIONCHANGED 4 + +VOID EsHandleEventServiceTrigger( + _In_ struct _ES_TRIGGER_CONTEXT *Context, + _In_ ULONG Event + ); + +// triggpg + +INT_PTR CALLBACK EspServiceTriggersDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +#endif diff --git a/plugins/ExtendedServices/main.c b/plugins/ExtendedServices/main.c index edd8f293477c..c36e3b8f38f7 100644 --- a/plugins/ExtendedServices/main.c +++ b/plugins/ExtendedServices/main.c @@ -1,481 +1,481 @@ -/* - * Process Hacker Extended Services - - * main program - * - * Copyright (C) 2010-2015 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include "extsrv.h" - -PPH_PLUGIN PluginInstance; -static PH_CALLBACK_REGISTRATION PluginLoadCallbackRegistration; -static PH_CALLBACK_REGISTRATION PluginShowOptionsCallbackRegistration; -static PH_CALLBACK_REGISTRATION PluginMenuItemCallbackRegistration; -static PH_CALLBACK_REGISTRATION ProcessMenuInitializingCallbackRegistration; -static PH_CALLBACK_REGISTRATION ServicePropertiesInitializingCallbackRegistration; -static PH_CALLBACK_REGISTRATION ServiceMenuInitializingCallbackRegistration; - -VOID NTAPI LoadCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - // Nothing -} - -VOID NTAPI ShowOptionsCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - EsShowOptionsDialog((HWND)Parameter); -} - -VOID NTAPI MenuItemCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - PPH_PLUGIN_MENU_ITEM menuItem = Parameter; - - switch (menuItem->Id) - { - case ID_SERVICE_GOTOSERVICE: - { - ProcessHacker_SelectTabPage(PhMainWndHandle, 1); - ProcessHacker_SelectServiceItem(PhMainWndHandle, (PPH_SERVICE_ITEM)menuItem->Context); - } - break; - case ID_SERVICE_START: - { - PhUiStartService(PhMainWndHandle, (PPH_SERVICE_ITEM)menuItem->Context); - } - break; - case ID_SERVICE_CONTINUE: - { - PhUiContinueService(PhMainWndHandle, (PPH_SERVICE_ITEM)menuItem->Context); - } - break; - case ID_SERVICE_PAUSE: - { - PhUiPauseService(PhMainWndHandle, (PPH_SERVICE_ITEM)menuItem->Context); - } - break; - case ID_SERVICE_STOP: - { - PhUiStopService(PhMainWndHandle, (PPH_SERVICE_ITEM)menuItem->Context); - } - break; - case ID_SERVICE_RESTART: - { - PPH_SERVICE_ITEM serviceItem = menuItem->Context; - SC_HANDLE serviceHandle; - ULONG win32Result = 0; - - if (serviceHandle = PhOpenService(serviceItem->Name->Buffer, SERVICE_QUERY_STATUS)) - { - EsRestartServiceWithProgress(PhMainWndHandle, serviceItem, serviceHandle); - CloseServiceHandle(serviceHandle); - } - else - { - win32Result = GetLastError(); - } - - if (win32Result != 0) - { - PhShowStatus( - PhMainWndHandle, - PhaFormatString(L"Unable to restart %s", serviceItem->Name->Buffer)->Buffer, - 0, - win32Result - ); - } - } - break; - } -} - -static int __cdecl ServiceForServicesMenuCompare( - _In_ const void *elem1, - _In_ const void *elem2 - ) -{ - PPH_SERVICE_ITEM serviceItem1 = *(PPH_SERVICE_ITEM *)elem1; - PPH_SERVICE_ITEM serviceItem2 = *(PPH_SERVICE_ITEM *)elem2; - - return PhCompareString(serviceItem1->Name, serviceItem2->Name, TRUE); -} - -VOID NTAPI ProcessMenuInitializingCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - PPH_PLUGIN_MENU_INFORMATION menuInfo = Parameter; - - if ( - PhGetIntegerSetting(SETTING_NAME_ENABLE_SERVICES_MENU) && - menuInfo->u.Process.NumberOfProcesses == 1 && - menuInfo->u.Process.Processes[0]->ServiceList && - menuInfo->u.Process.Processes[0]->ServiceList->Count != 0 - ) - { - PPH_PROCESS_ITEM processItem; - PPH_EMENU_ITEM servicesMenuItem = NULL; - ULONG enumerationKey; - PPH_SERVICE_ITEM serviceItem; - PPH_LIST serviceList; - ULONG i; - PPH_EMENU_ITEM priorityMenuItem; - ULONG insertIndex; - - processItem = menuInfo->u.Process.Processes[0]; - - // Create a service list so we can sort it. - - serviceList = PH_AUTO(PhCreateList(processItem->ServiceList->Count)); - enumerationKey = 0; - - PhAcquireQueuedLockShared(&processItem->ServiceListLock); - - while (PhEnumPointerList(processItem->ServiceList, &enumerationKey, &serviceItem)) - { - PhReferenceObject(serviceItem); - // We need to use the service item when the user chooses a menu item. - PH_AUTO(serviceItem); - PhAddItemList(serviceList, serviceItem); - } - - PhReleaseQueuedLockShared(&processItem->ServiceListLock); - - // Sort the service list. - qsort(serviceList->Items, serviceList->Count, sizeof(PPH_SERVICE_ITEM), ServiceForServicesMenuCompare); - - // If there is only one service: - // * We use the text "Service (Xxx)". - // * There are no extra submenus. - if (serviceList->Count != 1) - { - servicesMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, 0, L"Services", NULL); - } - - // Create and add a menu item for each service. - - for (i = 0; i < serviceList->Count; i++) - { - PPH_STRING escapedName; - PPH_EMENU_ITEM serviceMenuItem; - PPH_EMENU_ITEM startMenuItem; - PPH_EMENU_ITEM continueMenuItem; - PPH_EMENU_ITEM pauseMenuItem; - PPH_EMENU_ITEM stopMenuItem; - - serviceItem = serviceList->Items[i]; - escapedName = PH_AUTO(PhEscapeStringForMenuPrefix(&serviceItem->Name->sr)); - - if (serviceList->Count == 1) - { - // "Service (Xxx)" - escapedName = PhaFormatString(L"Service (%s)", escapedName->Buffer); - } - - serviceMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, 0, escapedName->Buffer, NULL); - - if (serviceList->Count == 1) - { - // Make this the root submenu that we will insert. - servicesMenuItem = serviceMenuItem; - } - - PhInsertEMenuItem(serviceMenuItem, PhPluginCreateEMenuItem(PluginInstance, 0, ID_SERVICE_GOTOSERVICE, L"Go to service", serviceItem), -1); - PhInsertEMenuItem(serviceMenuItem, startMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, ID_SERVICE_START, L"Start", serviceItem), -1); - PhInsertEMenuItem(serviceMenuItem, continueMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, ID_SERVICE_CONTINUE, L"Continue", serviceItem), -1); - PhInsertEMenuItem(serviceMenuItem, pauseMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, ID_SERVICE_PAUSE, L"Pause", serviceItem), -1); - PhInsertEMenuItem(serviceMenuItem, stopMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, ID_SERVICE_STOP, L"Stop", serviceItem), -1); - - // Massive copy and paste from mainwnd.c. - // == START == - -#define SET_MENU_ITEM_ENABLED(MenuItem, Enabled) if (!(Enabled)) (MenuItem)->Flags |= PH_EMENU_DISABLED; - - switch (serviceItem->State) - { - case SERVICE_RUNNING: - { - SET_MENU_ITEM_ENABLED(startMenuItem, FALSE); - SET_MENU_ITEM_ENABLED(continueMenuItem, FALSE); - SET_MENU_ITEM_ENABLED(pauseMenuItem, - serviceItem->ControlsAccepted & SERVICE_ACCEPT_PAUSE_CONTINUE); - SET_MENU_ITEM_ENABLED(stopMenuItem, - serviceItem->ControlsAccepted & SERVICE_ACCEPT_STOP); - } - break; - case SERVICE_PAUSED: - { - SET_MENU_ITEM_ENABLED(startMenuItem, FALSE); - SET_MENU_ITEM_ENABLED(continueMenuItem, - serviceItem->ControlsAccepted & SERVICE_ACCEPT_PAUSE_CONTINUE); - SET_MENU_ITEM_ENABLED(pauseMenuItem, FALSE); - SET_MENU_ITEM_ENABLED(stopMenuItem, - serviceItem->ControlsAccepted & SERVICE_ACCEPT_STOP); - } - break; - case SERVICE_STOPPED: - { - SET_MENU_ITEM_ENABLED(continueMenuItem, FALSE); - SET_MENU_ITEM_ENABLED(pauseMenuItem, FALSE); - SET_MENU_ITEM_ENABLED(stopMenuItem, FALSE); - } - break; - case SERVICE_START_PENDING: - case SERVICE_CONTINUE_PENDING: - case SERVICE_PAUSE_PENDING: - case SERVICE_STOP_PENDING: - { - SET_MENU_ITEM_ENABLED(startMenuItem, FALSE); - SET_MENU_ITEM_ENABLED(continueMenuItem, FALSE); - SET_MENU_ITEM_ENABLED(pauseMenuItem, FALSE); - SET_MENU_ITEM_ENABLED(stopMenuItem, FALSE); - } - break; - } - - if (!(serviceItem->ControlsAccepted & SERVICE_ACCEPT_PAUSE_CONTINUE)) - { - PhDestroyEMenuItem(continueMenuItem); - PhDestroyEMenuItem(pauseMenuItem); - } - - // == END == - - if (serviceList->Count != 1) - PhInsertEMenuItem(servicesMenuItem, serviceMenuItem, -1); - } - - // Insert our Services menu after the I/O Priority menu. - - priorityMenuItem = PhFindEMenuItem(menuInfo->Menu, 0, L"I/O Priority", 0); - - if (!priorityMenuItem) - priorityMenuItem = PhFindEMenuItem(menuInfo->Menu, 0, L"Priority", 0); - - if (priorityMenuItem) - insertIndex = PhIndexOfEMenuItem(menuInfo->Menu, priorityMenuItem) + 1; - else - insertIndex = 0; - - PhInsertEMenuItem(menuInfo->Menu, servicesMenuItem, insertIndex); - } -} - -NTAPI ServicePropertiesInitializingCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - PPH_PLUGIN_OBJECT_PROPERTIES objectProperties = Parameter; - PROPSHEETPAGE propSheetPage; - PPH_SERVICE_ITEM serviceItem; - - serviceItem = objectProperties->Parameter; - - // Recovery - if (objectProperties->NumberOfPages < objectProperties->MaximumNumberOfPages) - { - memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); - propSheetPage.dwSize = sizeof(PROPSHEETPAGE); - propSheetPage.hInstance = PluginInstance->DllBase; - propSheetPage.lParam = (LPARAM)serviceItem; - - if (!(serviceItem->Flags & SERVICE_RUNS_IN_SYSTEM_PROCESS)) - { - propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_SRVRECOVERY); - propSheetPage.pfnDlgProc = EspServiceRecoveryDlgProc; - } - else - { - // Services which run in system processes don't support failure actions. - // Create a different page with a message saying this. - propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_SRVRECOVERY2); - propSheetPage.pfnDlgProc = EspServiceRecovery2DlgProc; - } - - objectProperties->Pages[objectProperties->NumberOfPages++] = CreatePropertySheetPage(&propSheetPage); - } - - // Dependencies - if (objectProperties->NumberOfPages < objectProperties->MaximumNumberOfPages) - { - memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); - propSheetPage.dwSize = sizeof(PROPSHEETPAGE); - propSheetPage.dwFlags = PSP_USETITLE; - propSheetPage.hInstance = PluginInstance->DllBase; - propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_SRVLIST); - propSheetPage.pszTitle = L"Dependencies"; - propSheetPage.pfnDlgProc = EspServiceDependenciesDlgProc; - propSheetPage.lParam = (LPARAM)serviceItem; - objectProperties->Pages[objectProperties->NumberOfPages++] = CreatePropertySheetPage(&propSheetPage); - } - - // Dependents - if (objectProperties->NumberOfPages < objectProperties->MaximumNumberOfPages) - { - memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); - propSheetPage.dwSize = sizeof(PROPSHEETPAGE); - propSheetPage.dwFlags = PSP_USETITLE; - propSheetPage.hInstance = PluginInstance->DllBase; - propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_SRVLIST); - propSheetPage.pszTitle = L"Dependents"; - propSheetPage.pfnDlgProc = EspServiceDependentsDlgProc; - propSheetPage.lParam = (LPARAM)serviceItem; - objectProperties->Pages[objectProperties->NumberOfPages++] = CreatePropertySheetPage(&propSheetPage); - } - - // Other - if (WindowsVersion >= WINDOWS_7 && objectProperties->NumberOfPages < objectProperties->MaximumNumberOfPages) - { - memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); - propSheetPage.dwSize = sizeof(PROPSHEETPAGE); - propSheetPage.dwFlags = PSP_USETITLE; - propSheetPage.hInstance = PluginInstance->DllBase; - propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_SRVTRIGGERS); - propSheetPage.pszTitle = L"Triggers"; - propSheetPage.pfnDlgProc = EspServiceTriggersDlgProc; - propSheetPage.lParam = (LPARAM)serviceItem; - objectProperties->Pages[objectProperties->NumberOfPages++] = CreatePropertySheetPage(&propSheetPage); - } - - // Other - if (WindowsVersion >= WINDOWS_VISTA && objectProperties->NumberOfPages < objectProperties->MaximumNumberOfPages) - { - memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); - propSheetPage.dwSize = sizeof(PROPSHEETPAGE); - propSheetPage.dwFlags = PSP_USETITLE; - propSheetPage.hInstance = PluginInstance->DllBase; - propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_SRVOTHER); - propSheetPage.pszTitle = L"Other"; - propSheetPage.pfnDlgProc = EspServiceOtherDlgProc; - propSheetPage.lParam = (LPARAM)serviceItem; - objectProperties->Pages[objectProperties->NumberOfPages++] = CreatePropertySheetPage(&propSheetPage); - } -} - -VOID NTAPI ServiceMenuInitializingCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - PPH_PLUGIN_MENU_INFORMATION menuInfo = Parameter; - PPH_EMENU_ITEM menuItem; - ULONG indexOfMenuItem; - - if ( - menuInfo->u.Service.NumberOfServices == 1 && - (menuInfo->u.Service.Services[0]->State == SERVICE_RUNNING || menuInfo->u.Service.Services[0]->State == SERVICE_PAUSED) - ) - { - // Insert our Restart menu item after the Stop menu item. - - menuItem = PhFindEMenuItem(menuInfo->Menu, PH_EMENU_FIND_STARTSWITH, L"Stop", 0); - - if (menuItem) - indexOfMenuItem = PhIndexOfEMenuItem(menuInfo->Menu, menuItem); - else - indexOfMenuItem = -1; - - PhInsertEMenuItem( - menuInfo->Menu, - PhPluginCreateEMenuItem(PluginInstance, 0, ID_SERVICE_RESTART, L"Restart", menuInfo->u.Service.Services[0]), - indexOfMenuItem + 1 - ); - } -} - -LOGICAL DllMain( - _In_ HINSTANCE Instance, - _In_ ULONG Reason, - _Reserved_ PVOID Reserved - ) -{ - switch (Reason) - { - case DLL_PROCESS_ATTACH: - { - PPH_PLUGIN_INFORMATION info; - PH_SETTING_CREATE settings[] = - { - { IntegerSettingType, SETTING_NAME_ENABLE_SERVICES_MENU, L"1" } - }; - - PluginInstance = PhRegisterPlugin(PLUGIN_NAME, Instance, &info); - - if (!PluginInstance) - return FALSE; - - info->DisplayName = L"Extended Services"; - info->Author = L"wj32"; - info->Description = L"Extends service management capabilities."; - info->Url = L"https://wj32.org/processhacker/forums/viewtopic.php?t=1113"; - info->HasOptions = TRUE; - - PhRegisterCallback( - PhGetPluginCallback(PluginInstance, PluginCallbackLoad), - LoadCallback, - NULL, - &PluginLoadCallbackRegistration - ); - PhRegisterCallback( - PhGetPluginCallback(PluginInstance, PluginCallbackShowOptions), - ShowOptionsCallback, - NULL, - &PluginShowOptionsCallbackRegistration - ); - PhRegisterCallback( - PhGetPluginCallback(PluginInstance, PluginCallbackMenuItem), - MenuItemCallback, - NULL, - &PluginMenuItemCallbackRegistration - ); - - PhRegisterCallback( - PhGetGeneralCallback(GeneralCallbackProcessMenuInitializing), - ProcessMenuInitializingCallback, - NULL, - &ProcessMenuInitializingCallbackRegistration - ); - PhRegisterCallback( - PhGetGeneralCallback(GeneralCallbackServicePropertiesInitializing), - ServicePropertiesInitializingCallback, - NULL, - &ServicePropertiesInitializingCallbackRegistration - ); - PhRegisterCallback( - PhGetGeneralCallback(GeneralCallbackServiceMenuInitializing), - ServiceMenuInitializingCallback, - NULL, - &ServiceMenuInitializingCallbackRegistration - ); - - PhAddSettings(settings, ARRAYSIZE(settings)); - } - break; - } - - return TRUE; +/* + * Process Hacker Extended Services - + * main program + * + * Copyright (C) 2010-2015 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include "extsrv.h" + +PPH_PLUGIN PluginInstance; +static PH_CALLBACK_REGISTRATION PluginLoadCallbackRegistration; +static PH_CALLBACK_REGISTRATION PluginShowOptionsCallbackRegistration; +static PH_CALLBACK_REGISTRATION PluginMenuItemCallbackRegistration; +static PH_CALLBACK_REGISTRATION ProcessMenuInitializingCallbackRegistration; +static PH_CALLBACK_REGISTRATION ServicePropertiesInitializingCallbackRegistration; +static PH_CALLBACK_REGISTRATION ServiceMenuInitializingCallbackRegistration; + +VOID NTAPI LoadCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + // Nothing +} + +VOID NTAPI ShowOptionsCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + EsShowOptionsDialog((HWND)Parameter); +} + +VOID NTAPI MenuItemCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + PPH_PLUGIN_MENU_ITEM menuItem = Parameter; + + switch (menuItem->Id) + { + case ID_SERVICE_GOTOSERVICE: + { + ProcessHacker_SelectTabPage(PhMainWndHandle, 1); + ProcessHacker_SelectServiceItem(PhMainWndHandle, (PPH_SERVICE_ITEM)menuItem->Context); + } + break; + case ID_SERVICE_START: + { + PhUiStartService(PhMainWndHandle, (PPH_SERVICE_ITEM)menuItem->Context); + } + break; + case ID_SERVICE_CONTINUE: + { + PhUiContinueService(PhMainWndHandle, (PPH_SERVICE_ITEM)menuItem->Context); + } + break; + case ID_SERVICE_PAUSE: + { + PhUiPauseService(PhMainWndHandle, (PPH_SERVICE_ITEM)menuItem->Context); + } + break; + case ID_SERVICE_STOP: + { + PhUiStopService(PhMainWndHandle, (PPH_SERVICE_ITEM)menuItem->Context); + } + break; + case ID_SERVICE_RESTART: + { + PPH_SERVICE_ITEM serviceItem = menuItem->Context; + SC_HANDLE serviceHandle; + ULONG win32Result = 0; + + if (serviceHandle = PhOpenService(serviceItem->Name->Buffer, SERVICE_QUERY_STATUS)) + { + EsRestartServiceWithProgress(PhMainWndHandle, serviceItem, serviceHandle); + CloseServiceHandle(serviceHandle); + } + else + { + win32Result = GetLastError(); + } + + if (win32Result != 0) + { + PhShowStatus( + PhMainWndHandle, + PhaFormatString(L"Unable to restart %s", serviceItem->Name->Buffer)->Buffer, + 0, + win32Result + ); + } + } + break; + } +} + +static int __cdecl ServiceForServicesMenuCompare( + _In_ const void *elem1, + _In_ const void *elem2 + ) +{ + PPH_SERVICE_ITEM serviceItem1 = *(PPH_SERVICE_ITEM *)elem1; + PPH_SERVICE_ITEM serviceItem2 = *(PPH_SERVICE_ITEM *)elem2; + + return PhCompareString(serviceItem1->Name, serviceItem2->Name, TRUE); +} + +VOID NTAPI ProcessMenuInitializingCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + PPH_PLUGIN_MENU_INFORMATION menuInfo = Parameter; + + if ( + PhGetIntegerSetting(SETTING_NAME_ENABLE_SERVICES_MENU) && + menuInfo->u.Process.NumberOfProcesses == 1 && + menuInfo->u.Process.Processes[0]->ServiceList && + menuInfo->u.Process.Processes[0]->ServiceList->Count != 0 + ) + { + PPH_PROCESS_ITEM processItem; + PPH_EMENU_ITEM servicesMenuItem = NULL; + ULONG enumerationKey; + PPH_SERVICE_ITEM serviceItem; + PPH_LIST serviceList; + ULONG i; + PPH_EMENU_ITEM priorityMenuItem; + ULONG insertIndex; + + processItem = menuInfo->u.Process.Processes[0]; + + // Create a service list so we can sort it. + + serviceList = PH_AUTO(PhCreateList(processItem->ServiceList->Count)); + enumerationKey = 0; + + PhAcquireQueuedLockShared(&processItem->ServiceListLock); + + while (PhEnumPointerList(processItem->ServiceList, &enumerationKey, &serviceItem)) + { + PhReferenceObject(serviceItem); + // We need to use the service item when the user chooses a menu item. + PH_AUTO(serviceItem); + PhAddItemList(serviceList, serviceItem); + } + + PhReleaseQueuedLockShared(&processItem->ServiceListLock); + + // Sort the service list. + qsort(serviceList->Items, serviceList->Count, sizeof(PPH_SERVICE_ITEM), ServiceForServicesMenuCompare); + + // If there is only one service: + // * We use the text "Service (Xxx)". + // * There are no extra submenus. + if (serviceList->Count != 1) + { + servicesMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, 0, L"Services", NULL); + } + + // Create and add a menu item for each service. + + for (i = 0; i < serviceList->Count; i++) + { + PPH_STRING escapedName; + PPH_EMENU_ITEM serviceMenuItem; + PPH_EMENU_ITEM startMenuItem; + PPH_EMENU_ITEM continueMenuItem; + PPH_EMENU_ITEM pauseMenuItem; + PPH_EMENU_ITEM stopMenuItem; + + serviceItem = serviceList->Items[i]; + escapedName = PH_AUTO(PhEscapeStringForMenuPrefix(&serviceItem->Name->sr)); + + if (serviceList->Count == 1) + { + // "Service (Xxx)" + escapedName = PhaFormatString(L"Service (%s)", escapedName->Buffer); + } + + serviceMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, 0, escapedName->Buffer, NULL); + + if (serviceList->Count == 1) + { + // Make this the root submenu that we will insert. + servicesMenuItem = serviceMenuItem; + } + + PhInsertEMenuItem(serviceMenuItem, PhPluginCreateEMenuItem(PluginInstance, 0, ID_SERVICE_GOTOSERVICE, L"Go to service", serviceItem), -1); + PhInsertEMenuItem(serviceMenuItem, startMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, ID_SERVICE_START, L"Start", serviceItem), -1); + PhInsertEMenuItem(serviceMenuItem, continueMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, ID_SERVICE_CONTINUE, L"Continue", serviceItem), -1); + PhInsertEMenuItem(serviceMenuItem, pauseMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, ID_SERVICE_PAUSE, L"Pause", serviceItem), -1); + PhInsertEMenuItem(serviceMenuItem, stopMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, ID_SERVICE_STOP, L"Stop", serviceItem), -1); + + // Massive copy and paste from mainwnd.c. + // == START == + +#define SET_MENU_ITEM_ENABLED(MenuItem, Enabled) if (!(Enabled)) (MenuItem)->Flags |= PH_EMENU_DISABLED; + + switch (serviceItem->State) + { + case SERVICE_RUNNING: + { + SET_MENU_ITEM_ENABLED(startMenuItem, FALSE); + SET_MENU_ITEM_ENABLED(continueMenuItem, FALSE); + SET_MENU_ITEM_ENABLED(pauseMenuItem, + serviceItem->ControlsAccepted & SERVICE_ACCEPT_PAUSE_CONTINUE); + SET_MENU_ITEM_ENABLED(stopMenuItem, + serviceItem->ControlsAccepted & SERVICE_ACCEPT_STOP); + } + break; + case SERVICE_PAUSED: + { + SET_MENU_ITEM_ENABLED(startMenuItem, FALSE); + SET_MENU_ITEM_ENABLED(continueMenuItem, + serviceItem->ControlsAccepted & SERVICE_ACCEPT_PAUSE_CONTINUE); + SET_MENU_ITEM_ENABLED(pauseMenuItem, FALSE); + SET_MENU_ITEM_ENABLED(stopMenuItem, + serviceItem->ControlsAccepted & SERVICE_ACCEPT_STOP); + } + break; + case SERVICE_STOPPED: + { + SET_MENU_ITEM_ENABLED(continueMenuItem, FALSE); + SET_MENU_ITEM_ENABLED(pauseMenuItem, FALSE); + SET_MENU_ITEM_ENABLED(stopMenuItem, FALSE); + } + break; + case SERVICE_START_PENDING: + case SERVICE_CONTINUE_PENDING: + case SERVICE_PAUSE_PENDING: + case SERVICE_STOP_PENDING: + { + SET_MENU_ITEM_ENABLED(startMenuItem, FALSE); + SET_MENU_ITEM_ENABLED(continueMenuItem, FALSE); + SET_MENU_ITEM_ENABLED(pauseMenuItem, FALSE); + SET_MENU_ITEM_ENABLED(stopMenuItem, FALSE); + } + break; + } + + if (!(serviceItem->ControlsAccepted & SERVICE_ACCEPT_PAUSE_CONTINUE)) + { + PhDestroyEMenuItem(continueMenuItem); + PhDestroyEMenuItem(pauseMenuItem); + } + + // == END == + + if (serviceList->Count != 1) + PhInsertEMenuItem(servicesMenuItem, serviceMenuItem, -1); + } + + // Insert our Services menu after the I/O Priority menu. + + priorityMenuItem = PhFindEMenuItem(menuInfo->Menu, 0, L"I/O Priority", 0); + + if (!priorityMenuItem) + priorityMenuItem = PhFindEMenuItem(menuInfo->Menu, 0, L"Priority", 0); + + if (priorityMenuItem) + insertIndex = PhIndexOfEMenuItem(menuInfo->Menu, priorityMenuItem) + 1; + else + insertIndex = 0; + + PhInsertEMenuItem(menuInfo->Menu, servicesMenuItem, insertIndex); + } +} + +NTAPI ServicePropertiesInitializingCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + PPH_PLUGIN_OBJECT_PROPERTIES objectProperties = Parameter; + PROPSHEETPAGE propSheetPage; + PPH_SERVICE_ITEM serviceItem; + + serviceItem = objectProperties->Parameter; + + // Recovery + if (objectProperties->NumberOfPages < objectProperties->MaximumNumberOfPages) + { + memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); + propSheetPage.dwSize = sizeof(PROPSHEETPAGE); + propSheetPage.hInstance = PluginInstance->DllBase; + propSheetPage.lParam = (LPARAM)serviceItem; + + if (!(serviceItem->Flags & SERVICE_RUNS_IN_SYSTEM_PROCESS)) + { + propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_SRVRECOVERY); + propSheetPage.pfnDlgProc = EspServiceRecoveryDlgProc; + } + else + { + // Services which run in system processes don't support failure actions. + // Create a different page with a message saying this. + propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_SRVRECOVERY2); + propSheetPage.pfnDlgProc = EspServiceRecovery2DlgProc; + } + + objectProperties->Pages[objectProperties->NumberOfPages++] = CreatePropertySheetPage(&propSheetPage); + } + + // Dependencies + if (objectProperties->NumberOfPages < objectProperties->MaximumNumberOfPages) + { + memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); + propSheetPage.dwSize = sizeof(PROPSHEETPAGE); + propSheetPage.dwFlags = PSP_USETITLE; + propSheetPage.hInstance = PluginInstance->DllBase; + propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_SRVLIST); + propSheetPage.pszTitle = L"Dependencies"; + propSheetPage.pfnDlgProc = EspServiceDependenciesDlgProc; + propSheetPage.lParam = (LPARAM)serviceItem; + objectProperties->Pages[objectProperties->NumberOfPages++] = CreatePropertySheetPage(&propSheetPage); + } + + // Dependents + if (objectProperties->NumberOfPages < objectProperties->MaximumNumberOfPages) + { + memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); + propSheetPage.dwSize = sizeof(PROPSHEETPAGE); + propSheetPage.dwFlags = PSP_USETITLE; + propSheetPage.hInstance = PluginInstance->DllBase; + propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_SRVLIST); + propSheetPage.pszTitle = L"Dependents"; + propSheetPage.pfnDlgProc = EspServiceDependentsDlgProc; + propSheetPage.lParam = (LPARAM)serviceItem; + objectProperties->Pages[objectProperties->NumberOfPages++] = CreatePropertySheetPage(&propSheetPage); + } + + // Other + if (WindowsVersion >= WINDOWS_7 && objectProperties->NumberOfPages < objectProperties->MaximumNumberOfPages) + { + memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); + propSheetPage.dwSize = sizeof(PROPSHEETPAGE); + propSheetPage.dwFlags = PSP_USETITLE; + propSheetPage.hInstance = PluginInstance->DllBase; + propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_SRVTRIGGERS); + propSheetPage.pszTitle = L"Triggers"; + propSheetPage.pfnDlgProc = EspServiceTriggersDlgProc; + propSheetPage.lParam = (LPARAM)serviceItem; + objectProperties->Pages[objectProperties->NumberOfPages++] = CreatePropertySheetPage(&propSheetPage); + } + + // Other + if (WindowsVersion >= WINDOWS_VISTA && objectProperties->NumberOfPages < objectProperties->MaximumNumberOfPages) + { + memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); + propSheetPage.dwSize = sizeof(PROPSHEETPAGE); + propSheetPage.dwFlags = PSP_USETITLE; + propSheetPage.hInstance = PluginInstance->DllBase; + propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_SRVOTHER); + propSheetPage.pszTitle = L"Other"; + propSheetPage.pfnDlgProc = EspServiceOtherDlgProc; + propSheetPage.lParam = (LPARAM)serviceItem; + objectProperties->Pages[objectProperties->NumberOfPages++] = CreatePropertySheetPage(&propSheetPage); + } +} + +VOID NTAPI ServiceMenuInitializingCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + PPH_PLUGIN_MENU_INFORMATION menuInfo = Parameter; + PPH_EMENU_ITEM menuItem; + ULONG indexOfMenuItem; + + if ( + menuInfo->u.Service.NumberOfServices == 1 && + (menuInfo->u.Service.Services[0]->State == SERVICE_RUNNING || menuInfo->u.Service.Services[0]->State == SERVICE_PAUSED) + ) + { + // Insert our Restart menu item after the Stop menu item. + + menuItem = PhFindEMenuItem(menuInfo->Menu, PH_EMENU_FIND_STARTSWITH, L"Stop", 0); + + if (menuItem) + indexOfMenuItem = PhIndexOfEMenuItem(menuInfo->Menu, menuItem); + else + indexOfMenuItem = -1; + + PhInsertEMenuItem( + menuInfo->Menu, + PhPluginCreateEMenuItem(PluginInstance, 0, ID_SERVICE_RESTART, L"Restart", menuInfo->u.Service.Services[0]), + indexOfMenuItem + 1 + ); + } +} + +LOGICAL DllMain( + _In_ HINSTANCE Instance, + _In_ ULONG Reason, + _Reserved_ PVOID Reserved + ) +{ + switch (Reason) + { + case DLL_PROCESS_ATTACH: + { + PPH_PLUGIN_INFORMATION info; + PH_SETTING_CREATE settings[] = + { + { IntegerSettingType, SETTING_NAME_ENABLE_SERVICES_MENU, L"1" } + }; + + PluginInstance = PhRegisterPlugin(PLUGIN_NAME, Instance, &info); + + if (!PluginInstance) + return FALSE; + + info->DisplayName = L"Extended Services"; + info->Author = L"wj32"; + info->Description = L"Extends service management capabilities."; + info->Url = L"https://wj32.org/processhacker/forums/viewtopic.php?t=1113"; + info->HasOptions = TRUE; + + PhRegisterCallback( + PhGetPluginCallback(PluginInstance, PluginCallbackLoad), + LoadCallback, + NULL, + &PluginLoadCallbackRegistration + ); + PhRegisterCallback( + PhGetPluginCallback(PluginInstance, PluginCallbackShowOptions), + ShowOptionsCallback, + NULL, + &PluginShowOptionsCallbackRegistration + ); + PhRegisterCallback( + PhGetPluginCallback(PluginInstance, PluginCallbackMenuItem), + MenuItemCallback, + NULL, + &PluginMenuItemCallbackRegistration + ); + + PhRegisterCallback( + PhGetGeneralCallback(GeneralCallbackProcessMenuInitializing), + ProcessMenuInitializingCallback, + NULL, + &ProcessMenuInitializingCallbackRegistration + ); + PhRegisterCallback( + PhGetGeneralCallback(GeneralCallbackServicePropertiesInitializing), + ServicePropertiesInitializingCallback, + NULL, + &ServicePropertiesInitializingCallbackRegistration + ); + PhRegisterCallback( + PhGetGeneralCallback(GeneralCallbackServiceMenuInitializing), + ServiceMenuInitializingCallback, + NULL, + &ServiceMenuInitializingCallbackRegistration + ); + + PhAddSettings(settings, ARRAYSIZE(settings)); + } + break; + } + + return TRUE; } \ No newline at end of file diff --git a/plugins/ExtendedServices/options.c b/plugins/ExtendedServices/options.c index 42bc796d0951..51cb5d9ce2a1 100644 --- a/plugins/ExtendedServices/options.c +++ b/plugins/ExtendedServices/options.c @@ -1,74 +1,74 @@ -/* - * Process Hacker Extended Services - - * options dialog - * - * Copyright (C) 2011 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include "extsrv.h" - -INT_PTR CALLBACK OptionsDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - switch (uMsg) - { - case WM_INITDIALOG: - { - PhCenterWindow(hwndDlg, GetParent(hwndDlg)); - - Button_SetCheck(GetDlgItem(hwndDlg, IDC_ENABLESERVICESMENU), PhGetIntegerSetting(SETTING_NAME_ENABLE_SERVICES_MENU) ? BST_CHECKED : BST_UNCHECKED); - } - break; - case WM_COMMAND: - { - switch (LOWORD(wParam)) - { - case IDCANCEL: - EndDialog(hwndDlg, IDCANCEL); - break; - case IDOK: - { - PhSetIntegerSetting(SETTING_NAME_ENABLE_SERVICES_MENU, - Button_GetCheck(GetDlgItem(hwndDlg, IDC_ENABLESERVICESMENU)) == BST_CHECKED); - - EndDialog(hwndDlg, IDOK); - } - break; - } - } - break; - } - - return FALSE; -} - -VOID EsShowOptionsDialog( - _In_ HWND ParentWindowHandle - ) -{ - DialogBox( - PluginInstance->DllBase, - MAKEINTRESOURCE(IDD_OPTIONS), - ParentWindowHandle, - OptionsDlgProc - ); +/* + * Process Hacker Extended Services - + * options dialog + * + * Copyright (C) 2011 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include "extsrv.h" + +INT_PTR CALLBACK OptionsDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + switch (uMsg) + { + case WM_INITDIALOG: + { + PhCenterWindow(hwndDlg, GetParent(hwndDlg)); + + Button_SetCheck(GetDlgItem(hwndDlg, IDC_ENABLESERVICESMENU), PhGetIntegerSetting(SETTING_NAME_ENABLE_SERVICES_MENU) ? BST_CHECKED : BST_UNCHECKED); + } + break; + case WM_COMMAND: + { + switch (LOWORD(wParam)) + { + case IDCANCEL: + EndDialog(hwndDlg, IDCANCEL); + break; + case IDOK: + { + PhSetIntegerSetting(SETTING_NAME_ENABLE_SERVICES_MENU, + Button_GetCheck(GetDlgItem(hwndDlg, IDC_ENABLESERVICESMENU)) == BST_CHECKED); + + EndDialog(hwndDlg, IDOK); + } + break; + } + } + break; + } + + return FALSE; +} + +VOID EsShowOptionsDialog( + _In_ HWND ParentWindowHandle + ) +{ + DialogBox( + PluginInstance->DllBase, + MAKEINTRESOURCE(IDD_OPTIONS), + ParentWindowHandle, + OptionsDlgProc + ); } \ No newline at end of file diff --git a/plugins/ExtendedServices/other.c b/plugins/ExtendedServices/other.c index 59b33fbce9df..5b7957afa653 100644 --- a/plugins/ExtendedServices/other.c +++ b/plugins/ExtendedServices/other.c @@ -1,732 +1,732 @@ -/* - * Process Hacker Extended Services - - * other information - * - * Copyright (C) 2010-2015 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include "extsrv.h" - -typedef struct _SERVICE_OTHER_CONTEXT -{ - PPH_SERVICE_ITEM ServiceItem; - - struct - { - ULONG Ready : 1; - ULONG Dirty : 1; - ULONG PreshutdownTimeoutValid : 1; - ULONG RequiredPrivilegesValid : 1; - ULONG SidTypeValid : 1; - ULONG LaunchProtectedValid : 1; - }; - HWND PrivilegesLv; - PPH_LIST PrivilegeList; - - ULONG OriginalLaunchProtected; -} SERVICE_OTHER_CONTEXT, *PSERVICE_OTHER_CONTEXT; - -static _RtlCreateServiceSid RtlCreateServiceSid_I = NULL; - -static PH_KEY_VALUE_PAIR EspServiceSidTypePairs[] = -{ - SIP(L"None", SERVICE_SID_TYPE_NONE), - SIP(L"Restricted", SERVICE_SID_TYPE_RESTRICTED), - SIP(L"Unrestricted", SERVICE_SID_TYPE_UNRESTRICTED) -}; - -static PH_KEY_VALUE_PAIR EspServiceLaunchProtectedPairs[] = -{ - SIP(L"None", SERVICE_LAUNCH_PROTECTED_NONE), - SIP(L"Full (Windows)", SERVICE_LAUNCH_PROTECTED_WINDOWS), - SIP(L"Light (Windows)", SERVICE_LAUNCH_PROTECTED_WINDOWS_LIGHT), - SIP(L"Light (Antimalware)", SERVICE_LAUNCH_PROTECTED_ANTIMALWARE_LIGHT) -}; - -static WCHAR *EspServiceSidTypeStrings[3] = { L"None", L"Restricted", L"Unrestricted" }; -static WCHAR *EspServiceLaunchProtectedStrings[4] = { L"None", L"Full (Windows)", L"Light (Windows)", L"Light (Antimalware)" }; - -PWSTR EspGetServiceSidTypeString( - _In_ ULONG SidType - ) -{ - PWSTR string; - - if (PhFindStringSiKeyValuePairs( - EspServiceSidTypePairs, - sizeof(EspServiceSidTypePairs), - SidType, - &string - )) - return string; - else - return L"Unknown"; -} - -ULONG EspGetServiceSidTypeInteger( - _In_ PWSTR SidType - ) -{ - ULONG integer; - - if (PhFindIntegerSiKeyValuePairs( - EspServiceSidTypePairs, - sizeof(EspServiceSidTypePairs), - SidType, - &integer - )) - return integer; - else - return -1; -} - -PWSTR EspGetServiceLaunchProtectedString( - _In_ ULONG LaunchProtected - ) -{ - PWSTR string; - - if (PhFindStringSiKeyValuePairs( - EspServiceLaunchProtectedPairs, - sizeof(EspServiceLaunchProtectedPairs), - LaunchProtected, - &string - )) - return string; - else - return L"Unknown"; -} - -ULONG EspGetServiceLaunchProtectedInteger( - _In_ PWSTR LaunchProtected - ) -{ - ULONG integer; - - if (PhFindIntegerSiKeyValuePairs( - EspServiceLaunchProtectedPairs, - sizeof(EspServiceLaunchProtectedPairs), - LaunchProtected, - &integer - )) - return integer; - else - return -1; -} - -NTSTATUS EspLoadOtherInfo( - _In_ HWND hwndDlg, - _In_ PSERVICE_OTHER_CONTEXT Context - ) -{ - NTSTATUS status = STATUS_SUCCESS; - SC_HANDLE serviceHandle; - ULONG returnLength; - SERVICE_PRESHUTDOWN_INFO preshutdownInfo; - LPSERVICE_REQUIRED_PRIVILEGES_INFO requiredPrivilegesInfo; - SERVICE_SID_INFO sidInfo; - SERVICE_LAUNCH_PROTECTED_INFO launchProtectedInfo; - - if (!(serviceHandle = PhOpenService(Context->ServiceItem->Name->Buffer, SERVICE_QUERY_CONFIG))) - return NTSTATUS_FROM_WIN32(GetLastError()); - - // Preshutdown timeout - - if (QueryServiceConfig2(serviceHandle, - SERVICE_CONFIG_PRESHUTDOWN_INFO, - (PBYTE)&preshutdownInfo, - sizeof(SERVICE_PRESHUTDOWN_INFO), - &returnLength - )) - { - SetDlgItemInt(hwndDlg, IDC_PRESHUTDOWNTIMEOUT, preshutdownInfo.dwPreshutdownTimeout, FALSE); - Context->PreshutdownTimeoutValid = TRUE; - } - - // Required privileges - - if (requiredPrivilegesInfo = PhQueryServiceVariableSize(serviceHandle, SERVICE_CONFIG_REQUIRED_PRIVILEGES_INFO)) - { - PWSTR privilege; - ULONG privilegeLength; - INT lvItemIndex; - PH_STRINGREF privilegeSr; - PPH_STRING privilegeString; - PPH_STRING displayName; - - privilege = requiredPrivilegesInfo->pmszRequiredPrivileges; - - if (privilege) - { - while (TRUE) - { - privilegeLength = (ULONG)PhCountStringZ(privilege); - - if (privilegeLength == 0) - break; - - privilegeString = PhCreateStringEx(privilege, privilegeLength * sizeof(WCHAR)); - PhAddItemList(Context->PrivilegeList, privilegeString); - - lvItemIndex = PhAddListViewItem(Context->PrivilegesLv, MAXINT, privilege, privilegeString); - privilegeSr.Buffer = privilege; - privilegeSr.Length = privilegeLength * sizeof(WCHAR); - - if (PhLookupPrivilegeDisplayName(&privilegeSr, &displayName)) - { - PhSetListViewSubItem(Context->PrivilegesLv, lvItemIndex, 1, displayName->Buffer); - PhDereferenceObject(displayName); - } - - privilege += privilegeLength + 1; - } - } - - ExtendedListView_SortItems(Context->PrivilegesLv); - - PhFree(requiredPrivilegesInfo); - Context->RequiredPrivilegesValid = TRUE; - } - - // SID type - - if (QueryServiceConfig2(serviceHandle, - SERVICE_CONFIG_SERVICE_SID_INFO, - (PBYTE)&sidInfo, - sizeof(SERVICE_SID_INFO), - &returnLength - )) - { - PhSelectComboBoxString(GetDlgItem(hwndDlg, IDC_SIDTYPE), - EspGetServiceSidTypeString(sidInfo.dwServiceSidType), FALSE); - Context->SidTypeValid = TRUE; - } - - // Launch protected - - if (QueryServiceConfig2(serviceHandle, - SERVICE_CONFIG_LAUNCH_PROTECTED, - (PBYTE)&launchProtectedInfo, - sizeof(SERVICE_LAUNCH_PROTECTED_INFO), - &returnLength - )) - { - PhSelectComboBoxString(GetDlgItem(hwndDlg, IDC_PROTECTION), - EspGetServiceLaunchProtectedString(launchProtectedInfo.dwLaunchProtected), FALSE); - Context->LaunchProtectedValid = TRUE; - Context->OriginalLaunchProtected = launchProtectedInfo.dwLaunchProtected; - } - - CloseServiceHandle(serviceHandle); - - return status; -} - -PPH_STRING EspGetServiceSidString( - _In_ PPH_STRINGREF ServiceName - ) -{ - PSID serviceSid = NULL; - UNICODE_STRING serviceNameUs; - ULONG serviceSidLength = 0; - PPH_STRING sidString = NULL; - - if (!RtlCreateServiceSid_I) - { - if (!(RtlCreateServiceSid_I = PhGetModuleProcAddress(L"ntdll.dll", "RtlCreateServiceSid"))) - return NULL; - } - - PhStringRefToUnicodeString(ServiceName, &serviceNameUs); - - if (RtlCreateServiceSid_I(&serviceNameUs, serviceSid, &serviceSidLength) == STATUS_BUFFER_TOO_SMALL) - { - serviceSid = PhAllocate(serviceSidLength); - - if (NT_SUCCESS(RtlCreateServiceSid_I(&serviceNameUs, serviceSid, &serviceSidLength))) - sidString = PhSidToStringSid(serviceSid); - - PhFree(serviceSid); - } - - return sidString; -} - -BOOLEAN EspChangeServiceConfig2( - _In_ PWSTR ServiceName, - _In_opt_ SC_HANDLE ServiceHandle, - _In_ ULONG InfoLevel, - _In_ PVOID Info - ) -{ - if (ServiceHandle) - { - return !!ChangeServiceConfig2(ServiceHandle, InfoLevel, Info); - } - else - { - NTSTATUS status; - - if (NT_SUCCESS(status = PhSvcCallChangeServiceConfig2(ServiceName, InfoLevel, Info))) - { - return TRUE; - } - else - { - SetLastError(PhNtStatusToDosError(status)); - return FALSE; - } - } -} - -static int __cdecl PrivilegeNameCompareFunction( - _In_ const void *elem1, - _In_ const void *elem2 - ) -{ - PWSTR string1 = *(PWSTR *)elem1; - PWSTR string2 = *(PWSTR *)elem2; - - return PhCompareStringZ(string1, string2, TRUE); -} - -INT_PTR CALLBACK EspServiceOtherDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - PSERVICE_OTHER_CONTEXT context; - - if (uMsg == WM_INITDIALOG) - { - context = PhAllocate(sizeof(SERVICE_OTHER_CONTEXT)); - memset(context, 0, sizeof(SERVICE_OTHER_CONTEXT)); - - SetProp(hwndDlg, L"Context", (HANDLE)context); - } - else - { - context = (PSERVICE_OTHER_CONTEXT)GetProp(hwndDlg, L"Context"); - - if (uMsg == WM_DESTROY) - RemoveProp(hwndDlg, L"Context"); - } - - if (!context) - return FALSE; - - switch (uMsg) - { - case WM_INITDIALOG: - { - NTSTATUS status; - LPPROPSHEETPAGE propSheetPage = (LPPROPSHEETPAGE)lParam; - PPH_SERVICE_ITEM serviceItem = (PPH_SERVICE_ITEM)propSheetPage->lParam; - HWND privilegesLv; - - context->ServiceItem = serviceItem; - - context->PrivilegesLv = privilegesLv = GetDlgItem(hwndDlg, IDC_PRIVILEGES); - PhSetListViewStyle(privilegesLv, FALSE, TRUE); - PhSetControlTheme(privilegesLv, L"explorer"); - PhAddListViewColumn(privilegesLv, 0, 0, 0, LVCFMT_LEFT, 140, L"Name"); - PhAddListViewColumn(privilegesLv, 1, 1, 1, LVCFMT_LEFT, 220, L"Display name"); - PhSetExtendedListView(privilegesLv); - - context->PrivilegeList = PhCreateList(32); - - if (context->ServiceItem->Type == SERVICE_KERNEL_DRIVER || context->ServiceItem->Type == SERVICE_FILE_SYSTEM_DRIVER) - { - // Drivers don't support required privileges. - EnableWindow(GetDlgItem(hwndDlg, IDC_ADD), FALSE); - } - - EnableWindow(GetDlgItem(hwndDlg, IDC_REMOVE), FALSE); - - PhAddComboBoxStrings(GetDlgItem(hwndDlg, IDC_SIDTYPE), - EspServiceSidTypeStrings, sizeof(EspServiceSidTypeStrings) / sizeof(PWSTR)); - PhAddComboBoxStrings(GetDlgItem(hwndDlg, IDC_PROTECTION), - EspServiceLaunchProtectedStrings, sizeof(EspServiceLaunchProtectedStrings) / sizeof(PWSTR)); - - if (WindowsVersion < WINDOWS_8_1) - EnableWindow(GetDlgItem(hwndDlg, IDC_PROTECTION), FALSE); - - SetDlgItemText(hwndDlg, IDC_SERVICESID, - PhGetStringOrDefault(PH_AUTO(EspGetServiceSidString(&serviceItem->Name->sr)), L"N/A")); - - status = EspLoadOtherInfo(hwndDlg, context); - - if (!NT_SUCCESS(status)) - { - PhShowWarning(hwndDlg, L"Unable to query service information: %s", - ((PPH_STRING)PH_AUTO(PhGetNtMessage(status)))->Buffer); - } - - context->Ready = TRUE; - } - break; - case WM_DESTROY: - { - if (context->PrivilegeList) - { - PhDereferenceObjects(context->PrivilegeList->Items, context->PrivilegeList->Count); - PhDereferenceObject(context->PrivilegeList); - } - - PhFree(context); - } - break; - case WM_COMMAND: - { - switch (LOWORD(wParam)) - { - case IDC_ADD: - { - NTSTATUS status; - LSA_HANDLE policyHandle; - LSA_ENUMERATION_HANDLE enumContext; - PPOLICY_PRIVILEGE_DEFINITION buffer; - ULONG count; - ULONG i; - PPH_LIST choices; - PPH_STRING selectedChoice = NULL; - - choices = PH_AUTO(PhCreateList(100)); - - if (!NT_SUCCESS(status = PhOpenLsaPolicy(&policyHandle, POLICY_VIEW_LOCAL_INFORMATION, NULL))) - { - PhShowStatus(hwndDlg, L"Unable to open LSA policy", status, 0); - break; - } - - enumContext = 0; - - while (TRUE) - { - status = LsaEnumeratePrivileges( - policyHandle, - &enumContext, - &buffer, - 0x100, - &count - ); - - if (status == STATUS_NO_MORE_ENTRIES) - break; - if (!NT_SUCCESS(status)) - break; - - for (i = 0; i < count; i++) - { - PhAddItemList(choices, PhaCreateStringEx(buffer[i].Name.Buffer, buffer[i].Name.Length)->Buffer); - } - - LsaFreeMemory(buffer); - } - - LsaClose(policyHandle); - - qsort(choices->Items, choices->Count, sizeof(PWSTR), PrivilegeNameCompareFunction); - - while (PhaChoiceDialog( - hwndDlg, - L"Add privilege", - L"Select a privilege to add:", - (PWSTR *)choices->Items, - choices->Count, - NULL, - PH_CHOICE_DIALOG_CHOICE, - &selectedChoice, - NULL, - NULL - )) - { - BOOLEAN found = FALSE; - PPH_STRING privilegeString; - INT lvItemIndex; - PPH_STRING displayName; - - // Check for duplicates. - for (i = 0; i < context->PrivilegeList->Count; i++) - { - if (PhEqualString(context->PrivilegeList->Items[i], selectedChoice, FALSE)) - { - found = TRUE; - break; - } - } - - if (found) - { - if (PhShowMessage( - hwndDlg, - MB_OKCANCEL | MB_ICONERROR, - L"The selected privilege has already been added." - ) == IDOK) - { - continue; - } - else - { - break; - } - } - - PhSetReference(&privilegeString, selectedChoice); - PhAddItemList(context->PrivilegeList, privilegeString); - - lvItemIndex = PhAddListViewItem(context->PrivilegesLv, MAXINT, privilegeString->Buffer, privilegeString); - - if (PhLookupPrivilegeDisplayName(&privilegeString->sr, &displayName)) - { - PhSetListViewSubItem(context->PrivilegesLv, lvItemIndex, 1, displayName->Buffer); - PhDereferenceObject(displayName); - } - - ExtendedListView_SortItems(context->PrivilegesLv); - - context->Dirty = TRUE; - context->RequiredPrivilegesValid = TRUE; - - break; - } - } - break; - case IDC_REMOVE: - { - INT lvItemIndex; - PPH_STRING privilegeString; - ULONG index; - - lvItemIndex = ListView_GetNextItem(context->PrivilegesLv, -1, LVNI_SELECTED); - - if (lvItemIndex != -1 && PhGetListViewItemParam(context->PrivilegesLv, lvItemIndex, (PVOID *)&privilegeString)) - { - index = PhFindItemList(context->PrivilegeList, privilegeString); - - if (index != -1) - { - PhDereferenceObject(privilegeString); - PhRemoveItemList(context->PrivilegeList, index); - PhRemoveListViewItem(context->PrivilegesLv, lvItemIndex); - - context->Dirty = TRUE; - context->RequiredPrivilegesValid = TRUE; - } - } - } - break; - } - - switch (HIWORD(wParam)) - { - case EN_CHANGE: - case CBN_SELCHANGE: - { - if (context->Ready) - { - context->Dirty = TRUE; - - switch (LOWORD(wParam)) - { - case IDC_PRESHUTDOWNTIMEOUT: - context->PreshutdownTimeoutValid = TRUE; - break; - case IDC_SIDTYPE: - context->SidTypeValid = TRUE; - break; - case IDC_PROTECTION: - context->LaunchProtectedValid = TRUE; - break; - } - } - } - break; - } - } - break; - case WM_NOTIFY: - { - LPNMHDR header = (LPNMHDR)lParam; - - switch (header->code) - { - case PSN_KILLACTIVE: - { - SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, FALSE); - } - return TRUE; - case PSN_APPLY: - { - SC_HANDLE serviceHandle = NULL; - ULONG win32Result = 0; - BOOLEAN connectedToPhSvc = FALSE; - PPH_STRING launchProtectedString; - ULONG launchProtected; - - SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_NOERROR); - - launchProtectedString = PH_AUTO(PhGetWindowText(GetDlgItem(hwndDlg, IDC_PROTECTION))); - launchProtected = EspGetServiceLaunchProtectedInteger(launchProtectedString->Buffer); - - if (context->LaunchProtectedValid && launchProtected != 0 && launchProtected != context->OriginalLaunchProtected) - { - if (PhShowMessage( - hwndDlg, - MB_ICONWARNING | MB_YESNO | MB_DEFBUTTON2, - L"Setting service protection will prevent the service from being controlled, modified, or deleted. Do you want to continue?" - ) == IDNO) - { - SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_INVALID); - return TRUE; - } - } - - if (context->Dirty) - { - SERVICE_PRESHUTDOWN_INFO preshutdownInfo; - SERVICE_REQUIRED_PRIVILEGES_INFO requiredPrivilegesInfo; - SERVICE_SID_INFO sidInfo; - SERVICE_LAUNCH_PROTECTED_INFO launchProtectedInfo; - - if (!(serviceHandle = PhOpenService(context->ServiceItem->Name->Buffer, SERVICE_CHANGE_CONFIG))) - { - win32Result = GetLastError(); - - if (win32Result == ERROR_ACCESS_DENIED && !PhGetOwnTokenAttributes().Elevated) - { - // Elevate using phsvc. - if (PhUiConnectToPhSvc(hwndDlg, FALSE)) - { - win32Result = 0; - connectedToPhSvc = TRUE; - } - else - { - // User cancelled elevation. - win32Result = ERROR_CANCELLED; - goto Done; - } - } - else - { - goto Done; - } - } - - if (context->PreshutdownTimeoutValid) - { - preshutdownInfo.dwPreshutdownTimeout = GetDlgItemInt(hwndDlg, IDC_PRESHUTDOWNTIMEOUT, NULL, FALSE); - - if (!EspChangeServiceConfig2(context->ServiceItem->Name->Buffer, serviceHandle, - SERVICE_CONFIG_PRESHUTDOWN_INFO, &preshutdownInfo)) - { - win32Result = GetLastError(); - } - } - - if (context->RequiredPrivilegesValid) - { - PH_STRING_BUILDER sb; - ULONG i; - - PhInitializeStringBuilder(&sb, 100); - - for (i = 0; i < context->PrivilegeList->Count; i++) - { - PhAppendStringBuilder(&sb, &((PPH_STRING)context->PrivilegeList->Items[i])->sr); - PhAppendCharStringBuilder(&sb, 0); - } - - requiredPrivilegesInfo.pmszRequiredPrivileges = sb.String->Buffer; - - if (win32Result == 0 && !EspChangeServiceConfig2(context->ServiceItem->Name->Buffer, serviceHandle, - SERVICE_CONFIG_REQUIRED_PRIVILEGES_INFO, &requiredPrivilegesInfo)) - { - win32Result = GetLastError(); - } - - PhDeleteStringBuilder(&sb); - } - - if (context->SidTypeValid) - { - PPH_STRING sidTypeString; - - sidTypeString = PH_AUTO(PhGetWindowText(GetDlgItem(hwndDlg, IDC_SIDTYPE))); - sidInfo.dwServiceSidType = EspGetServiceSidTypeInteger(sidTypeString->Buffer); - - if (win32Result == 0 && !EspChangeServiceConfig2(context->ServiceItem->Name->Buffer, serviceHandle, - SERVICE_CONFIG_SERVICE_SID_INFO, &sidInfo)) - { - win32Result = GetLastError(); - } - } - - if (context->LaunchProtectedValid) - { - launchProtectedInfo.dwLaunchProtected = launchProtected; - - if (!EspChangeServiceConfig2(context->ServiceItem->Name->Buffer, serviceHandle, - SERVICE_CONFIG_LAUNCH_PROTECTED, &launchProtectedInfo)) - { - // For now, ignore errors here. - // win32Result = GetLastError(); - } - } - -Done: - if (connectedToPhSvc) - PhUiDisconnectFromPhSvc(); - if (serviceHandle) - CloseServiceHandle(serviceHandle); - - if (win32Result != 0) - { - if (win32Result == ERROR_CANCELLED || PhShowMessage( - hwndDlg, - MB_ICONERROR | MB_RETRYCANCEL, - L"Unable to change service information: %s", - ((PPH_STRING)PH_AUTO(PhGetWin32Message(win32Result)))->Buffer - ) == IDRETRY) - { - SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_INVALID); - } - } - } - - return TRUE; - } - break; - case LVN_ITEMCHANGED: - { - if (header->hwndFrom == context->PrivilegesLv) - { - EnableWindow(GetDlgItem(hwndDlg, IDC_REMOVE), ListView_GetSelectedCount(context->PrivilegesLv) == 1); - } - } - break; - } - } - break; - } - - return FALSE; +/* + * Process Hacker Extended Services - + * other information + * + * Copyright (C) 2010-2015 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include "extsrv.h" + +typedef struct _SERVICE_OTHER_CONTEXT +{ + PPH_SERVICE_ITEM ServiceItem; + + struct + { + ULONG Ready : 1; + ULONG Dirty : 1; + ULONG PreshutdownTimeoutValid : 1; + ULONG RequiredPrivilegesValid : 1; + ULONG SidTypeValid : 1; + ULONG LaunchProtectedValid : 1; + }; + HWND PrivilegesLv; + PPH_LIST PrivilegeList; + + ULONG OriginalLaunchProtected; +} SERVICE_OTHER_CONTEXT, *PSERVICE_OTHER_CONTEXT; + +static _RtlCreateServiceSid RtlCreateServiceSid_I = NULL; + +static PH_KEY_VALUE_PAIR EspServiceSidTypePairs[] = +{ + SIP(L"None", SERVICE_SID_TYPE_NONE), + SIP(L"Restricted", SERVICE_SID_TYPE_RESTRICTED), + SIP(L"Unrestricted", SERVICE_SID_TYPE_UNRESTRICTED) +}; + +static PH_KEY_VALUE_PAIR EspServiceLaunchProtectedPairs[] = +{ + SIP(L"None", SERVICE_LAUNCH_PROTECTED_NONE), + SIP(L"Full (Windows)", SERVICE_LAUNCH_PROTECTED_WINDOWS), + SIP(L"Light (Windows)", SERVICE_LAUNCH_PROTECTED_WINDOWS_LIGHT), + SIP(L"Light (Antimalware)", SERVICE_LAUNCH_PROTECTED_ANTIMALWARE_LIGHT) +}; + +static WCHAR *EspServiceSidTypeStrings[3] = { L"None", L"Restricted", L"Unrestricted" }; +static WCHAR *EspServiceLaunchProtectedStrings[4] = { L"None", L"Full (Windows)", L"Light (Windows)", L"Light (Antimalware)" }; + +PWSTR EspGetServiceSidTypeString( + _In_ ULONG SidType + ) +{ + PWSTR string; + + if (PhFindStringSiKeyValuePairs( + EspServiceSidTypePairs, + sizeof(EspServiceSidTypePairs), + SidType, + &string + )) + return string; + else + return L"Unknown"; +} + +ULONG EspGetServiceSidTypeInteger( + _In_ PWSTR SidType + ) +{ + ULONG integer; + + if (PhFindIntegerSiKeyValuePairs( + EspServiceSidTypePairs, + sizeof(EspServiceSidTypePairs), + SidType, + &integer + )) + return integer; + else + return -1; +} + +PWSTR EspGetServiceLaunchProtectedString( + _In_ ULONG LaunchProtected + ) +{ + PWSTR string; + + if (PhFindStringSiKeyValuePairs( + EspServiceLaunchProtectedPairs, + sizeof(EspServiceLaunchProtectedPairs), + LaunchProtected, + &string + )) + return string; + else + return L"Unknown"; +} + +ULONG EspGetServiceLaunchProtectedInteger( + _In_ PWSTR LaunchProtected + ) +{ + ULONG integer; + + if (PhFindIntegerSiKeyValuePairs( + EspServiceLaunchProtectedPairs, + sizeof(EspServiceLaunchProtectedPairs), + LaunchProtected, + &integer + )) + return integer; + else + return -1; +} + +NTSTATUS EspLoadOtherInfo( + _In_ HWND hwndDlg, + _In_ PSERVICE_OTHER_CONTEXT Context + ) +{ + NTSTATUS status = STATUS_SUCCESS; + SC_HANDLE serviceHandle; + ULONG returnLength; + SERVICE_PRESHUTDOWN_INFO preshutdownInfo; + LPSERVICE_REQUIRED_PRIVILEGES_INFO requiredPrivilegesInfo; + SERVICE_SID_INFO sidInfo; + SERVICE_LAUNCH_PROTECTED_INFO launchProtectedInfo; + + if (!(serviceHandle = PhOpenService(Context->ServiceItem->Name->Buffer, SERVICE_QUERY_CONFIG))) + return NTSTATUS_FROM_WIN32(GetLastError()); + + // Preshutdown timeout + + if (QueryServiceConfig2(serviceHandle, + SERVICE_CONFIG_PRESHUTDOWN_INFO, + (PBYTE)&preshutdownInfo, + sizeof(SERVICE_PRESHUTDOWN_INFO), + &returnLength + )) + { + SetDlgItemInt(hwndDlg, IDC_PRESHUTDOWNTIMEOUT, preshutdownInfo.dwPreshutdownTimeout, FALSE); + Context->PreshutdownTimeoutValid = TRUE; + } + + // Required privileges + + if (requiredPrivilegesInfo = PhQueryServiceVariableSize(serviceHandle, SERVICE_CONFIG_REQUIRED_PRIVILEGES_INFO)) + { + PWSTR privilege; + ULONG privilegeLength; + INT lvItemIndex; + PH_STRINGREF privilegeSr; + PPH_STRING privilegeString; + PPH_STRING displayName; + + privilege = requiredPrivilegesInfo->pmszRequiredPrivileges; + + if (privilege) + { + while (TRUE) + { + privilegeLength = (ULONG)PhCountStringZ(privilege); + + if (privilegeLength == 0) + break; + + privilegeString = PhCreateStringEx(privilege, privilegeLength * sizeof(WCHAR)); + PhAddItemList(Context->PrivilegeList, privilegeString); + + lvItemIndex = PhAddListViewItem(Context->PrivilegesLv, MAXINT, privilege, privilegeString); + privilegeSr.Buffer = privilege; + privilegeSr.Length = privilegeLength * sizeof(WCHAR); + + if (PhLookupPrivilegeDisplayName(&privilegeSr, &displayName)) + { + PhSetListViewSubItem(Context->PrivilegesLv, lvItemIndex, 1, displayName->Buffer); + PhDereferenceObject(displayName); + } + + privilege += privilegeLength + 1; + } + } + + ExtendedListView_SortItems(Context->PrivilegesLv); + + PhFree(requiredPrivilegesInfo); + Context->RequiredPrivilegesValid = TRUE; + } + + // SID type + + if (QueryServiceConfig2(serviceHandle, + SERVICE_CONFIG_SERVICE_SID_INFO, + (PBYTE)&sidInfo, + sizeof(SERVICE_SID_INFO), + &returnLength + )) + { + PhSelectComboBoxString(GetDlgItem(hwndDlg, IDC_SIDTYPE), + EspGetServiceSidTypeString(sidInfo.dwServiceSidType), FALSE); + Context->SidTypeValid = TRUE; + } + + // Launch protected + + if (QueryServiceConfig2(serviceHandle, + SERVICE_CONFIG_LAUNCH_PROTECTED, + (PBYTE)&launchProtectedInfo, + sizeof(SERVICE_LAUNCH_PROTECTED_INFO), + &returnLength + )) + { + PhSelectComboBoxString(GetDlgItem(hwndDlg, IDC_PROTECTION), + EspGetServiceLaunchProtectedString(launchProtectedInfo.dwLaunchProtected), FALSE); + Context->LaunchProtectedValid = TRUE; + Context->OriginalLaunchProtected = launchProtectedInfo.dwLaunchProtected; + } + + CloseServiceHandle(serviceHandle); + + return status; +} + +PPH_STRING EspGetServiceSidString( + _In_ PPH_STRINGREF ServiceName + ) +{ + PSID serviceSid = NULL; + UNICODE_STRING serviceNameUs; + ULONG serviceSidLength = 0; + PPH_STRING sidString = NULL; + + if (!RtlCreateServiceSid_I) + { + if (!(RtlCreateServiceSid_I = PhGetModuleProcAddress(L"ntdll.dll", "RtlCreateServiceSid"))) + return NULL; + } + + PhStringRefToUnicodeString(ServiceName, &serviceNameUs); + + if (RtlCreateServiceSid_I(&serviceNameUs, serviceSid, &serviceSidLength) == STATUS_BUFFER_TOO_SMALL) + { + serviceSid = PhAllocate(serviceSidLength); + + if (NT_SUCCESS(RtlCreateServiceSid_I(&serviceNameUs, serviceSid, &serviceSidLength))) + sidString = PhSidToStringSid(serviceSid); + + PhFree(serviceSid); + } + + return sidString; +} + +BOOLEAN EspChangeServiceConfig2( + _In_ PWSTR ServiceName, + _In_opt_ SC_HANDLE ServiceHandle, + _In_ ULONG InfoLevel, + _In_ PVOID Info + ) +{ + if (ServiceHandle) + { + return !!ChangeServiceConfig2(ServiceHandle, InfoLevel, Info); + } + else + { + NTSTATUS status; + + if (NT_SUCCESS(status = PhSvcCallChangeServiceConfig2(ServiceName, InfoLevel, Info))) + { + return TRUE; + } + else + { + SetLastError(PhNtStatusToDosError(status)); + return FALSE; + } + } +} + +static int __cdecl PrivilegeNameCompareFunction( + _In_ const void *elem1, + _In_ const void *elem2 + ) +{ + PWSTR string1 = *(PWSTR *)elem1; + PWSTR string2 = *(PWSTR *)elem2; + + return PhCompareStringZ(string1, string2, TRUE); +} + +INT_PTR CALLBACK EspServiceOtherDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + PSERVICE_OTHER_CONTEXT context; + + if (uMsg == WM_INITDIALOG) + { + context = PhAllocate(sizeof(SERVICE_OTHER_CONTEXT)); + memset(context, 0, sizeof(SERVICE_OTHER_CONTEXT)); + + SetProp(hwndDlg, L"Context", (HANDLE)context); + } + else + { + context = (PSERVICE_OTHER_CONTEXT)GetProp(hwndDlg, L"Context"); + + if (uMsg == WM_DESTROY) + RemoveProp(hwndDlg, L"Context"); + } + + if (!context) + return FALSE; + + switch (uMsg) + { + case WM_INITDIALOG: + { + NTSTATUS status; + LPPROPSHEETPAGE propSheetPage = (LPPROPSHEETPAGE)lParam; + PPH_SERVICE_ITEM serviceItem = (PPH_SERVICE_ITEM)propSheetPage->lParam; + HWND privilegesLv; + + context->ServiceItem = serviceItem; + + context->PrivilegesLv = privilegesLv = GetDlgItem(hwndDlg, IDC_PRIVILEGES); + PhSetListViewStyle(privilegesLv, FALSE, TRUE); + PhSetControlTheme(privilegesLv, L"explorer"); + PhAddListViewColumn(privilegesLv, 0, 0, 0, LVCFMT_LEFT, 140, L"Name"); + PhAddListViewColumn(privilegesLv, 1, 1, 1, LVCFMT_LEFT, 220, L"Display name"); + PhSetExtendedListView(privilegesLv); + + context->PrivilegeList = PhCreateList(32); + + if (context->ServiceItem->Type == SERVICE_KERNEL_DRIVER || context->ServiceItem->Type == SERVICE_FILE_SYSTEM_DRIVER) + { + // Drivers don't support required privileges. + EnableWindow(GetDlgItem(hwndDlg, IDC_ADD), FALSE); + } + + EnableWindow(GetDlgItem(hwndDlg, IDC_REMOVE), FALSE); + + PhAddComboBoxStrings(GetDlgItem(hwndDlg, IDC_SIDTYPE), + EspServiceSidTypeStrings, sizeof(EspServiceSidTypeStrings) / sizeof(PWSTR)); + PhAddComboBoxStrings(GetDlgItem(hwndDlg, IDC_PROTECTION), + EspServiceLaunchProtectedStrings, sizeof(EspServiceLaunchProtectedStrings) / sizeof(PWSTR)); + + if (WindowsVersion < WINDOWS_8_1) + EnableWindow(GetDlgItem(hwndDlg, IDC_PROTECTION), FALSE); + + SetDlgItemText(hwndDlg, IDC_SERVICESID, + PhGetStringOrDefault(PH_AUTO(EspGetServiceSidString(&serviceItem->Name->sr)), L"N/A")); + + status = EspLoadOtherInfo(hwndDlg, context); + + if (!NT_SUCCESS(status)) + { + PhShowWarning(hwndDlg, L"Unable to query service information: %s", + ((PPH_STRING)PH_AUTO(PhGetNtMessage(status)))->Buffer); + } + + context->Ready = TRUE; + } + break; + case WM_DESTROY: + { + if (context->PrivilegeList) + { + PhDereferenceObjects(context->PrivilegeList->Items, context->PrivilegeList->Count); + PhDereferenceObject(context->PrivilegeList); + } + + PhFree(context); + } + break; + case WM_COMMAND: + { + switch (LOWORD(wParam)) + { + case IDC_ADD: + { + NTSTATUS status; + LSA_HANDLE policyHandle; + LSA_ENUMERATION_HANDLE enumContext; + PPOLICY_PRIVILEGE_DEFINITION buffer; + ULONG count; + ULONG i; + PPH_LIST choices; + PPH_STRING selectedChoice = NULL; + + choices = PH_AUTO(PhCreateList(100)); + + if (!NT_SUCCESS(status = PhOpenLsaPolicy(&policyHandle, POLICY_VIEW_LOCAL_INFORMATION, NULL))) + { + PhShowStatus(hwndDlg, L"Unable to open LSA policy", status, 0); + break; + } + + enumContext = 0; + + while (TRUE) + { + status = LsaEnumeratePrivileges( + policyHandle, + &enumContext, + &buffer, + 0x100, + &count + ); + + if (status == STATUS_NO_MORE_ENTRIES) + break; + if (!NT_SUCCESS(status)) + break; + + for (i = 0; i < count; i++) + { + PhAddItemList(choices, PhaCreateStringEx(buffer[i].Name.Buffer, buffer[i].Name.Length)->Buffer); + } + + LsaFreeMemory(buffer); + } + + LsaClose(policyHandle); + + qsort(choices->Items, choices->Count, sizeof(PWSTR), PrivilegeNameCompareFunction); + + while (PhaChoiceDialog( + hwndDlg, + L"Add privilege", + L"Select a privilege to add:", + (PWSTR *)choices->Items, + choices->Count, + NULL, + PH_CHOICE_DIALOG_CHOICE, + &selectedChoice, + NULL, + NULL + )) + { + BOOLEAN found = FALSE; + PPH_STRING privilegeString; + INT lvItemIndex; + PPH_STRING displayName; + + // Check for duplicates. + for (i = 0; i < context->PrivilegeList->Count; i++) + { + if (PhEqualString(context->PrivilegeList->Items[i], selectedChoice, FALSE)) + { + found = TRUE; + break; + } + } + + if (found) + { + if (PhShowMessage( + hwndDlg, + MB_OKCANCEL | MB_ICONERROR, + L"The selected privilege has already been added." + ) == IDOK) + { + continue; + } + else + { + break; + } + } + + PhSetReference(&privilegeString, selectedChoice); + PhAddItemList(context->PrivilegeList, privilegeString); + + lvItemIndex = PhAddListViewItem(context->PrivilegesLv, MAXINT, privilegeString->Buffer, privilegeString); + + if (PhLookupPrivilegeDisplayName(&privilegeString->sr, &displayName)) + { + PhSetListViewSubItem(context->PrivilegesLv, lvItemIndex, 1, displayName->Buffer); + PhDereferenceObject(displayName); + } + + ExtendedListView_SortItems(context->PrivilegesLv); + + context->Dirty = TRUE; + context->RequiredPrivilegesValid = TRUE; + + break; + } + } + break; + case IDC_REMOVE: + { + INT lvItemIndex; + PPH_STRING privilegeString; + ULONG index; + + lvItemIndex = ListView_GetNextItem(context->PrivilegesLv, -1, LVNI_SELECTED); + + if (lvItemIndex != -1 && PhGetListViewItemParam(context->PrivilegesLv, lvItemIndex, (PVOID *)&privilegeString)) + { + index = PhFindItemList(context->PrivilegeList, privilegeString); + + if (index != -1) + { + PhDereferenceObject(privilegeString); + PhRemoveItemList(context->PrivilegeList, index); + PhRemoveListViewItem(context->PrivilegesLv, lvItemIndex); + + context->Dirty = TRUE; + context->RequiredPrivilegesValid = TRUE; + } + } + } + break; + } + + switch (HIWORD(wParam)) + { + case EN_CHANGE: + case CBN_SELCHANGE: + { + if (context->Ready) + { + context->Dirty = TRUE; + + switch (LOWORD(wParam)) + { + case IDC_PRESHUTDOWNTIMEOUT: + context->PreshutdownTimeoutValid = TRUE; + break; + case IDC_SIDTYPE: + context->SidTypeValid = TRUE; + break; + case IDC_PROTECTION: + context->LaunchProtectedValid = TRUE; + break; + } + } + } + break; + } + } + break; + case WM_NOTIFY: + { + LPNMHDR header = (LPNMHDR)lParam; + + switch (header->code) + { + case PSN_KILLACTIVE: + { + SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, FALSE); + } + return TRUE; + case PSN_APPLY: + { + SC_HANDLE serviceHandle = NULL; + ULONG win32Result = 0; + BOOLEAN connectedToPhSvc = FALSE; + PPH_STRING launchProtectedString; + ULONG launchProtected; + + SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_NOERROR); + + launchProtectedString = PH_AUTO(PhGetWindowText(GetDlgItem(hwndDlg, IDC_PROTECTION))); + launchProtected = EspGetServiceLaunchProtectedInteger(launchProtectedString->Buffer); + + if (context->LaunchProtectedValid && launchProtected != 0 && launchProtected != context->OriginalLaunchProtected) + { + if (PhShowMessage( + hwndDlg, + MB_ICONWARNING | MB_YESNO | MB_DEFBUTTON2, + L"Setting service protection will prevent the service from being controlled, modified, or deleted. Do you want to continue?" + ) == IDNO) + { + SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_INVALID); + return TRUE; + } + } + + if (context->Dirty) + { + SERVICE_PRESHUTDOWN_INFO preshutdownInfo; + SERVICE_REQUIRED_PRIVILEGES_INFO requiredPrivilegesInfo; + SERVICE_SID_INFO sidInfo; + SERVICE_LAUNCH_PROTECTED_INFO launchProtectedInfo; + + if (!(serviceHandle = PhOpenService(context->ServiceItem->Name->Buffer, SERVICE_CHANGE_CONFIG))) + { + win32Result = GetLastError(); + + if (win32Result == ERROR_ACCESS_DENIED && !PhGetOwnTokenAttributes().Elevated) + { + // Elevate using phsvc. + if (PhUiConnectToPhSvc(hwndDlg, FALSE)) + { + win32Result = 0; + connectedToPhSvc = TRUE; + } + else + { + // User cancelled elevation. + win32Result = ERROR_CANCELLED; + goto Done; + } + } + else + { + goto Done; + } + } + + if (context->PreshutdownTimeoutValid) + { + preshutdownInfo.dwPreshutdownTimeout = GetDlgItemInt(hwndDlg, IDC_PRESHUTDOWNTIMEOUT, NULL, FALSE); + + if (!EspChangeServiceConfig2(context->ServiceItem->Name->Buffer, serviceHandle, + SERVICE_CONFIG_PRESHUTDOWN_INFO, &preshutdownInfo)) + { + win32Result = GetLastError(); + } + } + + if (context->RequiredPrivilegesValid) + { + PH_STRING_BUILDER sb; + ULONG i; + + PhInitializeStringBuilder(&sb, 100); + + for (i = 0; i < context->PrivilegeList->Count; i++) + { + PhAppendStringBuilder(&sb, &((PPH_STRING)context->PrivilegeList->Items[i])->sr); + PhAppendCharStringBuilder(&sb, 0); + } + + requiredPrivilegesInfo.pmszRequiredPrivileges = sb.String->Buffer; + + if (win32Result == 0 && !EspChangeServiceConfig2(context->ServiceItem->Name->Buffer, serviceHandle, + SERVICE_CONFIG_REQUIRED_PRIVILEGES_INFO, &requiredPrivilegesInfo)) + { + win32Result = GetLastError(); + } + + PhDeleteStringBuilder(&sb); + } + + if (context->SidTypeValid) + { + PPH_STRING sidTypeString; + + sidTypeString = PH_AUTO(PhGetWindowText(GetDlgItem(hwndDlg, IDC_SIDTYPE))); + sidInfo.dwServiceSidType = EspGetServiceSidTypeInteger(sidTypeString->Buffer); + + if (win32Result == 0 && !EspChangeServiceConfig2(context->ServiceItem->Name->Buffer, serviceHandle, + SERVICE_CONFIG_SERVICE_SID_INFO, &sidInfo)) + { + win32Result = GetLastError(); + } + } + + if (context->LaunchProtectedValid) + { + launchProtectedInfo.dwLaunchProtected = launchProtected; + + if (!EspChangeServiceConfig2(context->ServiceItem->Name->Buffer, serviceHandle, + SERVICE_CONFIG_LAUNCH_PROTECTED, &launchProtectedInfo)) + { + // For now, ignore errors here. + // win32Result = GetLastError(); + } + } + +Done: + if (connectedToPhSvc) + PhUiDisconnectFromPhSvc(); + if (serviceHandle) + CloseServiceHandle(serviceHandle); + + if (win32Result != 0) + { + if (win32Result == ERROR_CANCELLED || PhShowMessage( + hwndDlg, + MB_ICONERROR | MB_RETRYCANCEL, + L"Unable to change service information: %s", + ((PPH_STRING)PH_AUTO(PhGetWin32Message(win32Result)))->Buffer + ) == IDRETRY) + { + SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_INVALID); + } + } + } + + return TRUE; + } + break; + case LVN_ITEMCHANGED: + { + if (header->hwndFrom == context->PrivilegesLv) + { + EnableWindow(GetDlgItem(hwndDlg, IDC_REMOVE), ListView_GetSelectedCount(context->PrivilegesLv) == 1); + } + } + break; + } + } + break; + } + + return FALSE; } \ No newline at end of file diff --git a/plugins/ExtendedServices/recovery.c b/plugins/ExtendedServices/recovery.c index 553095aaa1ee..b917b0334498 100644 --- a/plugins/ExtendedServices/recovery.c +++ b/plugins/ExtendedServices/recovery.c @@ -1,709 +1,709 @@ -/* - * Process Hacker Extended Services - - * recovery information - * - * Copyright (C) 2010-2011 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include "extsrv.h" - -typedef struct _SERVICE_RECOVERY_CONTEXT -{ - PPH_SERVICE_ITEM ServiceItem; - - ULONG NumberOfActions; - BOOLEAN EnableFlagCheckBox; - ULONG RebootAfter; // in ms - PPH_STRING RebootMessage; - - BOOLEAN Ready; - BOOLEAN Dirty; -} SERVICE_RECOVERY_CONTEXT, *PSERVICE_RECOVERY_CONTEXT; - -static PH_KEY_VALUE_PAIR ServiceActionPairs[] = -{ - SIP(L"Take no action", SC_ACTION_NONE), - SIP(L"Restart the service", SC_ACTION_RESTART), - SIP(L"Run a program", SC_ACTION_RUN_COMMAND), - SIP(L"Restart the computer", SC_ACTION_REBOOT) -}; - -INT_PTR CALLBACK RestartComputerDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -VOID EspAddServiceActionStrings( - _In_ HWND ComboBoxHandle - ) -{ - ULONG i; - - for (i = 0; i < sizeof(ServiceActionPairs) / sizeof(PH_KEY_VALUE_PAIR); i++) - ComboBox_AddString(ComboBoxHandle, (PWSTR)ServiceActionPairs[i].Key); - - PhSelectComboBoxString(ComboBoxHandle, (PWSTR)ServiceActionPairs[0].Key, FALSE); -} - -SC_ACTION_TYPE EspStringToServiceAction( - _In_ PWSTR String - ) -{ - ULONG integer; - - if (PhFindIntegerSiKeyValuePairs(ServiceActionPairs, sizeof(ServiceActionPairs), String, &integer)) - return integer; - else - return 0; -} - -PWSTR EspServiceActionToString( - _In_ SC_ACTION_TYPE ActionType - ) -{ - PWSTR string; - - if (PhFindStringSiKeyValuePairs(ServiceActionPairs, sizeof(ServiceActionPairs), ActionType, &string)) - return string; - else - return NULL; -} - -SC_ACTION_TYPE ComboBoxToServiceAction( - _In_ HWND ComboBoxHandle - ) -{ - PPH_STRING string; - - string = PH_AUTO(PhGetComboBoxString(ComboBoxHandle, ComboBox_GetCurSel(ComboBoxHandle))); - - if (!string) - return SC_ACTION_NONE; - - return EspStringToServiceAction(string->Buffer); -} - -VOID ServiceActionToComboBox( - _In_ HWND ComboBoxHandle, - _In_ SC_ACTION_TYPE ActionType - ) -{ - PWSTR string; - - if (string = EspServiceActionToString(ActionType)) - PhSelectComboBoxString(ComboBoxHandle, string, FALSE); - else - PhSelectComboBoxString(ComboBoxHandle, (PWSTR)ServiceActionPairs[0].Key, FALSE); -} - -VOID EspFixControls( - _In_ HWND hwndDlg, - _In_ PSERVICE_RECOVERY_CONTEXT Context - ) -{ - SC_ACTION_TYPE action1; - SC_ACTION_TYPE action2; - SC_ACTION_TYPE actionS; - BOOLEAN enableRestart; - BOOLEAN enableReboot; - BOOLEAN enableCommand; - - action1 = ComboBoxToServiceAction(GetDlgItem(hwndDlg, IDC_FIRSTFAILURE)); - action2 = ComboBoxToServiceAction(GetDlgItem(hwndDlg, IDC_SECONDFAILURE)); - actionS = ComboBoxToServiceAction(GetDlgItem(hwndDlg, IDC_SUBSEQUENTFAILURES)); - - EnableWindow(GetDlgItem(hwndDlg, IDC_ENABLEFORERRORSTOPS), Context->EnableFlagCheckBox); - - enableRestart = action1 == SC_ACTION_RESTART || action2 == SC_ACTION_RESTART || actionS == SC_ACTION_RESTART; - enableReboot = action1 == SC_ACTION_REBOOT || action2 == SC_ACTION_REBOOT || actionS == SC_ACTION_REBOOT; - enableCommand = action1 == SC_ACTION_RUN_COMMAND || action2 == SC_ACTION_RUN_COMMAND || actionS == SC_ACTION_RUN_COMMAND; - - EnableWindow(GetDlgItem(hwndDlg, IDC_RESTARTSERVICEAFTER_LABEL), enableRestart); - EnableWindow(GetDlgItem(hwndDlg, IDC_RESTARTSERVICEAFTER), enableRestart); - EnableWindow(GetDlgItem(hwndDlg, IDC_RESTARTSERVICEAFTER_MINUTES), enableRestart); - - EnableWindow(GetDlgItem(hwndDlg, IDC_RESTARTCOMPUTEROPTIONS), enableReboot); - - EnableWindow(GetDlgItem(hwndDlg, IDC_RUNPROGRAM_GROUP), enableCommand); - EnableWindow(GetDlgItem(hwndDlg, IDC_RUNPROGRAM_LABEL), enableCommand); - EnableWindow(GetDlgItem(hwndDlg, IDC_RUNPROGRAM), enableCommand); - EnableWindow(GetDlgItem(hwndDlg, IDC_BROWSE), enableCommand); - EnableWindow(GetDlgItem(hwndDlg, IDC_RUNPROGRAM_INFO), enableCommand); -} - -NTSTATUS EspLoadRecoveryInfo( - _In_ HWND hwndDlg, - _In_ PSERVICE_RECOVERY_CONTEXT Context - ) -{ - NTSTATUS status = STATUS_SUCCESS; - SC_HANDLE serviceHandle; - LPSERVICE_FAILURE_ACTIONS failureActions; - SERVICE_FAILURE_ACTIONS_FLAG failureActionsFlag; - SC_ACTION_TYPE lastType; - ULONG returnLength; - ULONG i; - - if (!(serviceHandle = PhOpenService(Context->ServiceItem->Name->Buffer, SERVICE_QUERY_CONFIG))) - return NTSTATUS_FROM_WIN32(GetLastError()); - - if (!(failureActions = PhQueryServiceVariableSize(serviceHandle, SERVICE_CONFIG_FAILURE_ACTIONS))) - { - CloseServiceHandle(serviceHandle); - return NTSTATUS_FROM_WIN32(GetLastError()); - } - - // Failure action types - - Context->NumberOfActions = failureActions->cActions; - - if (failureActions->cActions != 0 && failureActions->cActions != 3) - status = STATUS_SOME_NOT_MAPPED; - - // If failure actions are not defined for a particular fail count, the - // last failure action is used. Here we duplicate this behaviour when there - // are fewer than 3 failure actions. - lastType = SC_ACTION_NONE; - - ServiceActionToComboBox(GetDlgItem(hwndDlg, IDC_FIRSTFAILURE), - failureActions->cActions >= 1 ? (lastType = failureActions->lpsaActions[0].Type) : lastType); - ServiceActionToComboBox(GetDlgItem(hwndDlg, IDC_SECONDFAILURE), - failureActions->cActions >= 2 ? (lastType = failureActions->lpsaActions[1].Type) : lastType); - ServiceActionToComboBox(GetDlgItem(hwndDlg, IDC_SUBSEQUENTFAILURES), - failureActions->cActions >= 3 ? (lastType = failureActions->lpsaActions[2].Type) : lastType); - - // Reset fail count after - - SetDlgItemInt(hwndDlg, IDC_RESETFAILCOUNT, failureActions->dwResetPeriod / (60 * 60 * 24), FALSE); // s to days - - // Restart service after - - SetDlgItemText(hwndDlg, IDC_RESTARTSERVICEAFTER, L"1"); - - for (i = 0; i < failureActions->cActions; i++) - { - if (failureActions->lpsaActions[i].Type == SC_ACTION_RESTART) - { - if (failureActions->lpsaActions[i].Delay != 0) - { - SetDlgItemInt(hwndDlg, IDC_RESTARTSERVICEAFTER, - failureActions->lpsaActions[i].Delay / (1000 * 60), FALSE); // ms to min - } - - break; - } - } - - // Enable actions for stops with errors - - // This is Vista and above only. - if (WindowsVersion >= WINDOWS_VISTA && QueryServiceConfig2( - serviceHandle, - SERVICE_CONFIG_FAILURE_ACTIONS_FLAG, - (BYTE *)&failureActionsFlag, - sizeof(SERVICE_FAILURE_ACTIONS_FLAG), - &returnLength - )) - { - Button_SetCheck(GetDlgItem(hwndDlg, IDC_ENABLEFORERRORSTOPS), - failureActionsFlag.fFailureActionsOnNonCrashFailures ? BST_CHECKED : BST_UNCHECKED); - Context->EnableFlagCheckBox = TRUE; - } - else - { - Context->EnableFlagCheckBox = FALSE; - } - - // Restart computer options - - Context->RebootAfter = 1 * 1000 * 60; - - for (i = 0; i < failureActions->cActions; i++) - { - if (failureActions->lpsaActions[i].Type == SC_ACTION_REBOOT) - { - if (failureActions->lpsaActions[i].Delay != 0) - Context->RebootAfter = failureActions->lpsaActions[i].Delay; - - break; - } - } - - if (failureActions->lpRebootMsg && failureActions->lpRebootMsg[0] != 0) - PhMoveReference(&Context->RebootMessage, PhCreateString(failureActions->lpRebootMsg)); - else - PhClearReference(&Context->RebootMessage); - - // Run program - - SetDlgItemText(hwndDlg, IDC_RUNPROGRAM, failureActions->lpCommand); - - PhFree(failureActions); - CloseServiceHandle(serviceHandle); - - return status; -} - -INT_PTR CALLBACK EspServiceRecoveryDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - PSERVICE_RECOVERY_CONTEXT context; - - if (uMsg == WM_INITDIALOG) - { - context = PhAllocate(sizeof(SERVICE_RECOVERY_CONTEXT)); - memset(context, 0, sizeof(SERVICE_RECOVERY_CONTEXT)); - - SetProp(hwndDlg, L"Context", (HANDLE)context); - } - else - { - context = (PSERVICE_RECOVERY_CONTEXT)GetProp(hwndDlg, L"Context"); - - if (uMsg == WM_DESTROY) - RemoveProp(hwndDlg, L"Context"); - } - - if (!context) - return FALSE; - - switch (uMsg) - { - case WM_INITDIALOG: - { - NTSTATUS status; - LPPROPSHEETPAGE propSheetPage = (LPPROPSHEETPAGE)lParam; - PPH_SERVICE_ITEM serviceItem = (PPH_SERVICE_ITEM)propSheetPage->lParam; - - context->ServiceItem = serviceItem; - - EspAddServiceActionStrings(GetDlgItem(hwndDlg, IDC_FIRSTFAILURE)); - EspAddServiceActionStrings(GetDlgItem(hwndDlg, IDC_SECONDFAILURE)); - EspAddServiceActionStrings(GetDlgItem(hwndDlg, IDC_SUBSEQUENTFAILURES)); - - status = EspLoadRecoveryInfo(hwndDlg, context); - - if (status == STATUS_SOME_NOT_MAPPED) - { - if (context->NumberOfActions > 3) - { - PhShowWarning( - hwndDlg, - L"The service has %lu failure actions configured, but this program only supports editing 3. " - L"If you save the recovery information using this program, the additional failure actions will be lost.", - context->NumberOfActions - ); - } - } - else if (!NT_SUCCESS(status)) - { - SetDlgItemText(hwndDlg, IDC_RESETFAILCOUNT, L"0"); - - if (WindowsVersion >= WINDOWS_VISTA) - { - context->EnableFlagCheckBox = TRUE; - EnableWindow(GetDlgItem(hwndDlg, IDC_ENABLEFORERRORSTOPS), TRUE); - } - - PhShowWarning(hwndDlg, L"Unable to query service recovery information: %s", - ((PPH_STRING)PH_AUTO(PhGetNtMessage(status)))->Buffer); - } - - EspFixControls(hwndDlg, context); - - context->Ready = TRUE; - } - break; - case WM_DESTROY: - { - PhClearReference(&context->RebootMessage); - PhFree(context); - } - break; - case WM_COMMAND: - { - switch (LOWORD(wParam)) - { - case IDC_FIRSTFAILURE: - case IDC_SECONDFAILURE: - case IDC_SUBSEQUENTFAILURES: - { - if (HIWORD(wParam) == CBN_SELCHANGE) - { - EspFixControls(hwndDlg, context); - } - } - break; - case IDC_RESTARTCOMPUTEROPTIONS: - { - DialogBoxParam( - PluginInstance->DllBase, - MAKEINTRESOURCE(IDD_RESTARTCOMP), - hwndDlg, - RestartComputerDlgProc, - (LPARAM)context - ); - } - break; - case IDC_BROWSE: - { - static PH_FILETYPE_FILTER filters[] = - { - { L"Executable files (*.exe;*.cmd;*.bat)", L"*.exe;*.cmd;*.bat" }, - { L"All files (*.*)", L"*.*" } - }; - PVOID fileDialog; - PPH_STRING fileName; - - fileDialog = PhCreateOpenFileDialog(); - PhSetFileDialogFilter(fileDialog, filters, sizeof(filters) / sizeof(PH_FILETYPE_FILTER)); - - fileName = PhaGetDlgItemText(hwndDlg, IDC_RUNPROGRAM); - PhSetFileDialogFileName(fileDialog, fileName->Buffer); - - if (PhShowFileDialog(hwndDlg, fileDialog)) - { - fileName = PH_AUTO(PhGetFileDialogFileName(fileDialog)); - SetDlgItemText(hwndDlg, IDC_RUNPROGRAM, fileName->Buffer); - } - - PhFreeFileDialog(fileDialog); - } - break; - case IDC_ENABLEFORERRORSTOPS: - { - context->Dirty = TRUE; - } - break; - } - - switch (HIWORD(wParam)) - { - case EN_CHANGE: - case CBN_SELCHANGE: - { - if (context->Ready) - context->Dirty = TRUE; - } - break; - } - } - break; - case WM_NOTIFY: - { - LPNMHDR header = (LPNMHDR)lParam; - - switch (header->code) - { - case PSN_KILLACTIVE: - { - SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, FALSE); - } - return TRUE; - case PSN_APPLY: - { - NTSTATUS status; - PPH_SERVICE_ITEM serviceItem = context->ServiceItem; - SC_HANDLE serviceHandle; - ULONG restartServiceAfter; - SERVICE_FAILURE_ACTIONS failureActions; - SC_ACTION actions[3]; - ULONG i; - BOOLEAN enableRestart = FALSE; - - SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_NOERROR); - - if (!context->Dirty) - { - return TRUE; - } - - // Build the failure actions structure. - - failureActions.dwResetPeriod = GetDlgItemInt(hwndDlg, IDC_RESETFAILCOUNT, NULL, FALSE) * 60 * 60 * 24; - failureActions.lpRebootMsg = PhGetStringOrEmpty(context->RebootMessage); - failureActions.lpCommand = PhaGetDlgItemText(hwndDlg, IDC_RUNPROGRAM)->Buffer; - failureActions.cActions = 3; - failureActions.lpsaActions = actions; - - actions[0].Type = ComboBoxToServiceAction(GetDlgItem(hwndDlg, IDC_FIRSTFAILURE)); - actions[1].Type = ComboBoxToServiceAction(GetDlgItem(hwndDlg, IDC_SECONDFAILURE)); - actions[2].Type = ComboBoxToServiceAction(GetDlgItem(hwndDlg, IDC_SUBSEQUENTFAILURES)); - - restartServiceAfter = GetDlgItemInt(hwndDlg, IDC_RESTARTSERVICEAFTER, NULL, FALSE) * 1000 * 60; - - for (i = 0; i < 3; i++) - { - switch (actions[i].Type) - { - case SC_ACTION_RESTART: - actions[i].Delay = restartServiceAfter; - enableRestart = TRUE; - break; - case SC_ACTION_REBOOT: - actions[i].Delay = context->RebootAfter; - break; - case SC_ACTION_RUN_COMMAND: - actions[i].Delay = 0; - break; - } - } - - // Try to save the changes. - - serviceHandle = PhOpenService( - serviceItem->Name->Buffer, - SERVICE_CHANGE_CONFIG | (enableRestart ? SERVICE_START : 0) // SC_ACTION_RESTART requires SERVICE_START - ); - - if (serviceHandle) - { - if (ChangeServiceConfig2( - serviceHandle, - SERVICE_CONFIG_FAILURE_ACTIONS, - &failureActions - )) - { - if (context->EnableFlagCheckBox) - { - SERVICE_FAILURE_ACTIONS_FLAG failureActionsFlag; - - failureActionsFlag.fFailureActionsOnNonCrashFailures = - Button_GetCheck(GetDlgItem(hwndDlg, IDC_ENABLEFORERRORSTOPS)) == BST_CHECKED; - - ChangeServiceConfig2( - serviceHandle, - SERVICE_CONFIG_FAILURE_ACTIONS_FLAG, - &failureActionsFlag - ); - } - - CloseServiceHandle(serviceHandle); - } - else - { - CloseServiceHandle(serviceHandle); - goto ErrorCase; - } - } - else - { - if (GetLastError() == ERROR_ACCESS_DENIED && !PhGetOwnTokenAttributes().Elevated) - { - // Elevate using phsvc. - if (PhUiConnectToPhSvc(hwndDlg, FALSE)) - { - if (NT_SUCCESS(status = PhSvcCallChangeServiceConfig2( - serviceItem->Name->Buffer, - SERVICE_CONFIG_FAILURE_ACTIONS, - &failureActions - ))) - { - if (context->EnableFlagCheckBox) - { - SERVICE_FAILURE_ACTIONS_FLAG failureActionsFlag; - - failureActionsFlag.fFailureActionsOnNonCrashFailures = - Button_GetCheck(GetDlgItem(hwndDlg, IDC_ENABLEFORERRORSTOPS)) == BST_CHECKED; - - PhSvcCallChangeServiceConfig2( - serviceItem->Name->Buffer, - SERVICE_CONFIG_FAILURE_ACTIONS_FLAG, - &failureActionsFlag - ); - } - } - - PhUiDisconnectFromPhSvc(); - - if (!NT_SUCCESS(status)) - { - SetLastError(PhNtStatusToDosError(status)); - goto ErrorCase; - } - } - else - { - // User cancelled elevation. - SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_INVALID); - } - } - else - { - goto ErrorCase; - } - } - - return TRUE; -ErrorCase: - if (PhShowMessage( - hwndDlg, - MB_ICONERROR | MB_RETRYCANCEL, - L"Unable to change service recovery information: %s", - ((PPH_STRING)PH_AUTO(PhGetWin32Message(GetLastError())))->Buffer - ) == IDRETRY) - { - SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_INVALID); - } - } - return TRUE; - } - } - break; - } - - return FALSE; -} - -INT_PTR CALLBACK EspServiceRecovery2DlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - return FALSE; -} - -INT_PTR CALLBACK RestartComputerDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - PSERVICE_RECOVERY_CONTEXT context; - - if (uMsg == WM_INITDIALOG) - { - context = (PSERVICE_RECOVERY_CONTEXT)lParam; - SetProp(hwndDlg, L"Context", (HANDLE)context); - } - else - { - context = (PSERVICE_RECOVERY_CONTEXT)GetProp(hwndDlg, L"Context"); - - if (uMsg == WM_DESTROY) - RemoveProp(hwndDlg, L"Context"); - } - - if (!context) - return FALSE; - - switch (uMsg) - { - case WM_INITDIALOG: - { - PhCenterWindow(hwndDlg, GetParent(hwndDlg)); - - SetDlgItemInt(hwndDlg, IDC_RESTARTCOMPAFTER, context->RebootAfter / (1000 * 60), FALSE); // ms to min - Button_SetCheck(GetDlgItem(hwndDlg, IDC_ENABLERESTARTMESSAGE), context->RebootMessage ? BST_CHECKED : BST_UNCHECKED); - SetDlgItemText(hwndDlg, IDC_RESTARTMESSAGE, PhGetString(context->RebootMessage)); - - SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hwndDlg, IDC_RESTARTCOMPAFTER), TRUE); - Edit_SetSel(GetDlgItem(hwndDlg, IDC_RESTARTCOMPAFTER), 0, -1); - } - break; - case WM_COMMAND: - { - switch (LOWORD(wParam)) - { - case IDCANCEL: - EndDialog(hwndDlg, IDCANCEL); - break; - case IDOK: - { - context->RebootAfter = GetDlgItemInt(hwndDlg, IDC_RESTARTCOMPAFTER, NULL, FALSE) * 1000 * 60; - - if (Button_GetCheck(GetDlgItem(hwndDlg, IDC_ENABLERESTARTMESSAGE)) == BST_CHECKED) - PhMoveReference(&context->RebootMessage, PhGetWindowText(GetDlgItem(hwndDlg, IDC_RESTARTMESSAGE))); - else - PhClearReference(&context->RebootMessage); - - context->Dirty = TRUE; - - EndDialog(hwndDlg, IDOK); - } - break; - case IDC_USEDEFAULTMESSAGE: - { - PPH_STRING message; - PWSTR computerName; - ULONG bufferSize; - BOOLEAN allocated = TRUE; - - // Get the computer name. - - bufferSize = 64; - computerName = PhAllocate((bufferSize + 1) * sizeof(WCHAR)); - - if (!GetComputerName(computerName, &bufferSize)) - { - PhFree(computerName); - computerName = PhAllocate((bufferSize + 1) * sizeof(WCHAR)); - - if (!GetComputerName(computerName, &bufferSize)) - { - PhFree(computerName); - computerName = L"(unknown)"; - allocated = FALSE; - } - } - - // This message is exactly the same as the one in the Services console, - // except the double spaces are replaced by single spaces. - message = PhaFormatString( - L"Your computer is connected to the computer named %s. " - L"The %s service on %s has ended unexpectedly. " - L"%s will restart automatically, and then you can reestablish the connection.", - computerName, - context->ServiceItem->Name->Buffer, - computerName, - computerName - ); - SetDlgItemText(hwndDlg, IDC_RESTARTMESSAGE, message->Buffer); - - if (allocated) - PhFree(computerName); - - Button_SetCheck(GetDlgItem(hwndDlg, IDC_ENABLERESTARTMESSAGE), BST_CHECKED); - } - break; - case IDC_RESTARTMESSAGE: - { - if (HIWORD(wParam) == EN_CHANGE) - { - // A zero length restart message disables it, so we might as well uncheck the box. - Button_SetCheck(GetDlgItem(hwndDlg, IDC_ENABLERESTARTMESSAGE), - GetWindowTextLength(GetDlgItem(hwndDlg, IDC_RESTARTMESSAGE)) != 0 ? BST_CHECKED : BST_UNCHECKED); - } - } - break; - } - } - break; - } - - return FALSE; -} +/* + * Process Hacker Extended Services - + * recovery information + * + * Copyright (C) 2010-2011 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include "extsrv.h" + +typedef struct _SERVICE_RECOVERY_CONTEXT +{ + PPH_SERVICE_ITEM ServiceItem; + + ULONG NumberOfActions; + BOOLEAN EnableFlagCheckBox; + ULONG RebootAfter; // in ms + PPH_STRING RebootMessage; + + BOOLEAN Ready; + BOOLEAN Dirty; +} SERVICE_RECOVERY_CONTEXT, *PSERVICE_RECOVERY_CONTEXT; + +static PH_KEY_VALUE_PAIR ServiceActionPairs[] = +{ + SIP(L"Take no action", SC_ACTION_NONE), + SIP(L"Restart the service", SC_ACTION_RESTART), + SIP(L"Run a program", SC_ACTION_RUN_COMMAND), + SIP(L"Restart the computer", SC_ACTION_REBOOT) +}; + +INT_PTR CALLBACK RestartComputerDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +VOID EspAddServiceActionStrings( + _In_ HWND ComboBoxHandle + ) +{ + ULONG i; + + for (i = 0; i < sizeof(ServiceActionPairs) / sizeof(PH_KEY_VALUE_PAIR); i++) + ComboBox_AddString(ComboBoxHandle, (PWSTR)ServiceActionPairs[i].Key); + + PhSelectComboBoxString(ComboBoxHandle, (PWSTR)ServiceActionPairs[0].Key, FALSE); +} + +SC_ACTION_TYPE EspStringToServiceAction( + _In_ PWSTR String + ) +{ + ULONG integer; + + if (PhFindIntegerSiKeyValuePairs(ServiceActionPairs, sizeof(ServiceActionPairs), String, &integer)) + return integer; + else + return 0; +} + +PWSTR EspServiceActionToString( + _In_ SC_ACTION_TYPE ActionType + ) +{ + PWSTR string; + + if (PhFindStringSiKeyValuePairs(ServiceActionPairs, sizeof(ServiceActionPairs), ActionType, &string)) + return string; + else + return NULL; +} + +SC_ACTION_TYPE ComboBoxToServiceAction( + _In_ HWND ComboBoxHandle + ) +{ + PPH_STRING string; + + string = PH_AUTO(PhGetComboBoxString(ComboBoxHandle, ComboBox_GetCurSel(ComboBoxHandle))); + + if (!string) + return SC_ACTION_NONE; + + return EspStringToServiceAction(string->Buffer); +} + +VOID ServiceActionToComboBox( + _In_ HWND ComboBoxHandle, + _In_ SC_ACTION_TYPE ActionType + ) +{ + PWSTR string; + + if (string = EspServiceActionToString(ActionType)) + PhSelectComboBoxString(ComboBoxHandle, string, FALSE); + else + PhSelectComboBoxString(ComboBoxHandle, (PWSTR)ServiceActionPairs[0].Key, FALSE); +} + +VOID EspFixControls( + _In_ HWND hwndDlg, + _In_ PSERVICE_RECOVERY_CONTEXT Context + ) +{ + SC_ACTION_TYPE action1; + SC_ACTION_TYPE action2; + SC_ACTION_TYPE actionS; + BOOLEAN enableRestart; + BOOLEAN enableReboot; + BOOLEAN enableCommand; + + action1 = ComboBoxToServiceAction(GetDlgItem(hwndDlg, IDC_FIRSTFAILURE)); + action2 = ComboBoxToServiceAction(GetDlgItem(hwndDlg, IDC_SECONDFAILURE)); + actionS = ComboBoxToServiceAction(GetDlgItem(hwndDlg, IDC_SUBSEQUENTFAILURES)); + + EnableWindow(GetDlgItem(hwndDlg, IDC_ENABLEFORERRORSTOPS), Context->EnableFlagCheckBox); + + enableRestart = action1 == SC_ACTION_RESTART || action2 == SC_ACTION_RESTART || actionS == SC_ACTION_RESTART; + enableReboot = action1 == SC_ACTION_REBOOT || action2 == SC_ACTION_REBOOT || actionS == SC_ACTION_REBOOT; + enableCommand = action1 == SC_ACTION_RUN_COMMAND || action2 == SC_ACTION_RUN_COMMAND || actionS == SC_ACTION_RUN_COMMAND; + + EnableWindow(GetDlgItem(hwndDlg, IDC_RESTARTSERVICEAFTER_LABEL), enableRestart); + EnableWindow(GetDlgItem(hwndDlg, IDC_RESTARTSERVICEAFTER), enableRestart); + EnableWindow(GetDlgItem(hwndDlg, IDC_RESTARTSERVICEAFTER_MINUTES), enableRestart); + + EnableWindow(GetDlgItem(hwndDlg, IDC_RESTARTCOMPUTEROPTIONS), enableReboot); + + EnableWindow(GetDlgItem(hwndDlg, IDC_RUNPROGRAM_GROUP), enableCommand); + EnableWindow(GetDlgItem(hwndDlg, IDC_RUNPROGRAM_LABEL), enableCommand); + EnableWindow(GetDlgItem(hwndDlg, IDC_RUNPROGRAM), enableCommand); + EnableWindow(GetDlgItem(hwndDlg, IDC_BROWSE), enableCommand); + EnableWindow(GetDlgItem(hwndDlg, IDC_RUNPROGRAM_INFO), enableCommand); +} + +NTSTATUS EspLoadRecoveryInfo( + _In_ HWND hwndDlg, + _In_ PSERVICE_RECOVERY_CONTEXT Context + ) +{ + NTSTATUS status = STATUS_SUCCESS; + SC_HANDLE serviceHandle; + LPSERVICE_FAILURE_ACTIONS failureActions; + SERVICE_FAILURE_ACTIONS_FLAG failureActionsFlag; + SC_ACTION_TYPE lastType; + ULONG returnLength; + ULONG i; + + if (!(serviceHandle = PhOpenService(Context->ServiceItem->Name->Buffer, SERVICE_QUERY_CONFIG))) + return NTSTATUS_FROM_WIN32(GetLastError()); + + if (!(failureActions = PhQueryServiceVariableSize(serviceHandle, SERVICE_CONFIG_FAILURE_ACTIONS))) + { + CloseServiceHandle(serviceHandle); + return NTSTATUS_FROM_WIN32(GetLastError()); + } + + // Failure action types + + Context->NumberOfActions = failureActions->cActions; + + if (failureActions->cActions != 0 && failureActions->cActions != 3) + status = STATUS_SOME_NOT_MAPPED; + + // If failure actions are not defined for a particular fail count, the + // last failure action is used. Here we duplicate this behaviour when there + // are fewer than 3 failure actions. + lastType = SC_ACTION_NONE; + + ServiceActionToComboBox(GetDlgItem(hwndDlg, IDC_FIRSTFAILURE), + failureActions->cActions >= 1 ? (lastType = failureActions->lpsaActions[0].Type) : lastType); + ServiceActionToComboBox(GetDlgItem(hwndDlg, IDC_SECONDFAILURE), + failureActions->cActions >= 2 ? (lastType = failureActions->lpsaActions[1].Type) : lastType); + ServiceActionToComboBox(GetDlgItem(hwndDlg, IDC_SUBSEQUENTFAILURES), + failureActions->cActions >= 3 ? (lastType = failureActions->lpsaActions[2].Type) : lastType); + + // Reset fail count after + + SetDlgItemInt(hwndDlg, IDC_RESETFAILCOUNT, failureActions->dwResetPeriod / (60 * 60 * 24), FALSE); // s to days + + // Restart service after + + SetDlgItemText(hwndDlg, IDC_RESTARTSERVICEAFTER, L"1"); + + for (i = 0; i < failureActions->cActions; i++) + { + if (failureActions->lpsaActions[i].Type == SC_ACTION_RESTART) + { + if (failureActions->lpsaActions[i].Delay != 0) + { + SetDlgItemInt(hwndDlg, IDC_RESTARTSERVICEAFTER, + failureActions->lpsaActions[i].Delay / (1000 * 60), FALSE); // ms to min + } + + break; + } + } + + // Enable actions for stops with errors + + // This is Vista and above only. + if (WindowsVersion >= WINDOWS_VISTA && QueryServiceConfig2( + serviceHandle, + SERVICE_CONFIG_FAILURE_ACTIONS_FLAG, + (BYTE *)&failureActionsFlag, + sizeof(SERVICE_FAILURE_ACTIONS_FLAG), + &returnLength + )) + { + Button_SetCheck(GetDlgItem(hwndDlg, IDC_ENABLEFORERRORSTOPS), + failureActionsFlag.fFailureActionsOnNonCrashFailures ? BST_CHECKED : BST_UNCHECKED); + Context->EnableFlagCheckBox = TRUE; + } + else + { + Context->EnableFlagCheckBox = FALSE; + } + + // Restart computer options + + Context->RebootAfter = 1 * 1000 * 60; + + for (i = 0; i < failureActions->cActions; i++) + { + if (failureActions->lpsaActions[i].Type == SC_ACTION_REBOOT) + { + if (failureActions->lpsaActions[i].Delay != 0) + Context->RebootAfter = failureActions->lpsaActions[i].Delay; + + break; + } + } + + if (failureActions->lpRebootMsg && failureActions->lpRebootMsg[0] != 0) + PhMoveReference(&Context->RebootMessage, PhCreateString(failureActions->lpRebootMsg)); + else + PhClearReference(&Context->RebootMessage); + + // Run program + + SetDlgItemText(hwndDlg, IDC_RUNPROGRAM, failureActions->lpCommand); + + PhFree(failureActions); + CloseServiceHandle(serviceHandle); + + return status; +} + +INT_PTR CALLBACK EspServiceRecoveryDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + PSERVICE_RECOVERY_CONTEXT context; + + if (uMsg == WM_INITDIALOG) + { + context = PhAllocate(sizeof(SERVICE_RECOVERY_CONTEXT)); + memset(context, 0, sizeof(SERVICE_RECOVERY_CONTEXT)); + + SetProp(hwndDlg, L"Context", (HANDLE)context); + } + else + { + context = (PSERVICE_RECOVERY_CONTEXT)GetProp(hwndDlg, L"Context"); + + if (uMsg == WM_DESTROY) + RemoveProp(hwndDlg, L"Context"); + } + + if (!context) + return FALSE; + + switch (uMsg) + { + case WM_INITDIALOG: + { + NTSTATUS status; + LPPROPSHEETPAGE propSheetPage = (LPPROPSHEETPAGE)lParam; + PPH_SERVICE_ITEM serviceItem = (PPH_SERVICE_ITEM)propSheetPage->lParam; + + context->ServiceItem = serviceItem; + + EspAddServiceActionStrings(GetDlgItem(hwndDlg, IDC_FIRSTFAILURE)); + EspAddServiceActionStrings(GetDlgItem(hwndDlg, IDC_SECONDFAILURE)); + EspAddServiceActionStrings(GetDlgItem(hwndDlg, IDC_SUBSEQUENTFAILURES)); + + status = EspLoadRecoveryInfo(hwndDlg, context); + + if (status == STATUS_SOME_NOT_MAPPED) + { + if (context->NumberOfActions > 3) + { + PhShowWarning( + hwndDlg, + L"The service has %lu failure actions configured, but this program only supports editing 3. " + L"If you save the recovery information using this program, the additional failure actions will be lost.", + context->NumberOfActions + ); + } + } + else if (!NT_SUCCESS(status)) + { + SetDlgItemText(hwndDlg, IDC_RESETFAILCOUNT, L"0"); + + if (WindowsVersion >= WINDOWS_VISTA) + { + context->EnableFlagCheckBox = TRUE; + EnableWindow(GetDlgItem(hwndDlg, IDC_ENABLEFORERRORSTOPS), TRUE); + } + + PhShowWarning(hwndDlg, L"Unable to query service recovery information: %s", + ((PPH_STRING)PH_AUTO(PhGetNtMessage(status)))->Buffer); + } + + EspFixControls(hwndDlg, context); + + context->Ready = TRUE; + } + break; + case WM_DESTROY: + { + PhClearReference(&context->RebootMessage); + PhFree(context); + } + break; + case WM_COMMAND: + { + switch (LOWORD(wParam)) + { + case IDC_FIRSTFAILURE: + case IDC_SECONDFAILURE: + case IDC_SUBSEQUENTFAILURES: + { + if (HIWORD(wParam) == CBN_SELCHANGE) + { + EspFixControls(hwndDlg, context); + } + } + break; + case IDC_RESTARTCOMPUTEROPTIONS: + { + DialogBoxParam( + PluginInstance->DllBase, + MAKEINTRESOURCE(IDD_RESTARTCOMP), + hwndDlg, + RestartComputerDlgProc, + (LPARAM)context + ); + } + break; + case IDC_BROWSE: + { + static PH_FILETYPE_FILTER filters[] = + { + { L"Executable files (*.exe;*.cmd;*.bat)", L"*.exe;*.cmd;*.bat" }, + { L"All files (*.*)", L"*.*" } + }; + PVOID fileDialog; + PPH_STRING fileName; + + fileDialog = PhCreateOpenFileDialog(); + PhSetFileDialogFilter(fileDialog, filters, sizeof(filters) / sizeof(PH_FILETYPE_FILTER)); + + fileName = PhaGetDlgItemText(hwndDlg, IDC_RUNPROGRAM); + PhSetFileDialogFileName(fileDialog, fileName->Buffer); + + if (PhShowFileDialog(hwndDlg, fileDialog)) + { + fileName = PH_AUTO(PhGetFileDialogFileName(fileDialog)); + SetDlgItemText(hwndDlg, IDC_RUNPROGRAM, fileName->Buffer); + } + + PhFreeFileDialog(fileDialog); + } + break; + case IDC_ENABLEFORERRORSTOPS: + { + context->Dirty = TRUE; + } + break; + } + + switch (HIWORD(wParam)) + { + case EN_CHANGE: + case CBN_SELCHANGE: + { + if (context->Ready) + context->Dirty = TRUE; + } + break; + } + } + break; + case WM_NOTIFY: + { + LPNMHDR header = (LPNMHDR)lParam; + + switch (header->code) + { + case PSN_KILLACTIVE: + { + SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, FALSE); + } + return TRUE; + case PSN_APPLY: + { + NTSTATUS status; + PPH_SERVICE_ITEM serviceItem = context->ServiceItem; + SC_HANDLE serviceHandle; + ULONG restartServiceAfter; + SERVICE_FAILURE_ACTIONS failureActions; + SC_ACTION actions[3]; + ULONG i; + BOOLEAN enableRestart = FALSE; + + SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_NOERROR); + + if (!context->Dirty) + { + return TRUE; + } + + // Build the failure actions structure. + + failureActions.dwResetPeriod = GetDlgItemInt(hwndDlg, IDC_RESETFAILCOUNT, NULL, FALSE) * 60 * 60 * 24; + failureActions.lpRebootMsg = PhGetStringOrEmpty(context->RebootMessage); + failureActions.lpCommand = PhaGetDlgItemText(hwndDlg, IDC_RUNPROGRAM)->Buffer; + failureActions.cActions = 3; + failureActions.lpsaActions = actions; + + actions[0].Type = ComboBoxToServiceAction(GetDlgItem(hwndDlg, IDC_FIRSTFAILURE)); + actions[1].Type = ComboBoxToServiceAction(GetDlgItem(hwndDlg, IDC_SECONDFAILURE)); + actions[2].Type = ComboBoxToServiceAction(GetDlgItem(hwndDlg, IDC_SUBSEQUENTFAILURES)); + + restartServiceAfter = GetDlgItemInt(hwndDlg, IDC_RESTARTSERVICEAFTER, NULL, FALSE) * 1000 * 60; + + for (i = 0; i < 3; i++) + { + switch (actions[i].Type) + { + case SC_ACTION_RESTART: + actions[i].Delay = restartServiceAfter; + enableRestart = TRUE; + break; + case SC_ACTION_REBOOT: + actions[i].Delay = context->RebootAfter; + break; + case SC_ACTION_RUN_COMMAND: + actions[i].Delay = 0; + break; + } + } + + // Try to save the changes. + + serviceHandle = PhOpenService( + serviceItem->Name->Buffer, + SERVICE_CHANGE_CONFIG | (enableRestart ? SERVICE_START : 0) // SC_ACTION_RESTART requires SERVICE_START + ); + + if (serviceHandle) + { + if (ChangeServiceConfig2( + serviceHandle, + SERVICE_CONFIG_FAILURE_ACTIONS, + &failureActions + )) + { + if (context->EnableFlagCheckBox) + { + SERVICE_FAILURE_ACTIONS_FLAG failureActionsFlag; + + failureActionsFlag.fFailureActionsOnNonCrashFailures = + Button_GetCheck(GetDlgItem(hwndDlg, IDC_ENABLEFORERRORSTOPS)) == BST_CHECKED; + + ChangeServiceConfig2( + serviceHandle, + SERVICE_CONFIG_FAILURE_ACTIONS_FLAG, + &failureActionsFlag + ); + } + + CloseServiceHandle(serviceHandle); + } + else + { + CloseServiceHandle(serviceHandle); + goto ErrorCase; + } + } + else + { + if (GetLastError() == ERROR_ACCESS_DENIED && !PhGetOwnTokenAttributes().Elevated) + { + // Elevate using phsvc. + if (PhUiConnectToPhSvc(hwndDlg, FALSE)) + { + if (NT_SUCCESS(status = PhSvcCallChangeServiceConfig2( + serviceItem->Name->Buffer, + SERVICE_CONFIG_FAILURE_ACTIONS, + &failureActions + ))) + { + if (context->EnableFlagCheckBox) + { + SERVICE_FAILURE_ACTIONS_FLAG failureActionsFlag; + + failureActionsFlag.fFailureActionsOnNonCrashFailures = + Button_GetCheck(GetDlgItem(hwndDlg, IDC_ENABLEFORERRORSTOPS)) == BST_CHECKED; + + PhSvcCallChangeServiceConfig2( + serviceItem->Name->Buffer, + SERVICE_CONFIG_FAILURE_ACTIONS_FLAG, + &failureActionsFlag + ); + } + } + + PhUiDisconnectFromPhSvc(); + + if (!NT_SUCCESS(status)) + { + SetLastError(PhNtStatusToDosError(status)); + goto ErrorCase; + } + } + else + { + // User cancelled elevation. + SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_INVALID); + } + } + else + { + goto ErrorCase; + } + } + + return TRUE; +ErrorCase: + if (PhShowMessage( + hwndDlg, + MB_ICONERROR | MB_RETRYCANCEL, + L"Unable to change service recovery information: %s", + ((PPH_STRING)PH_AUTO(PhGetWin32Message(GetLastError())))->Buffer + ) == IDRETRY) + { + SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_INVALID); + } + } + return TRUE; + } + } + break; + } + + return FALSE; +} + +INT_PTR CALLBACK EspServiceRecovery2DlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + return FALSE; +} + +INT_PTR CALLBACK RestartComputerDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + PSERVICE_RECOVERY_CONTEXT context; + + if (uMsg == WM_INITDIALOG) + { + context = (PSERVICE_RECOVERY_CONTEXT)lParam; + SetProp(hwndDlg, L"Context", (HANDLE)context); + } + else + { + context = (PSERVICE_RECOVERY_CONTEXT)GetProp(hwndDlg, L"Context"); + + if (uMsg == WM_DESTROY) + RemoveProp(hwndDlg, L"Context"); + } + + if (!context) + return FALSE; + + switch (uMsg) + { + case WM_INITDIALOG: + { + PhCenterWindow(hwndDlg, GetParent(hwndDlg)); + + SetDlgItemInt(hwndDlg, IDC_RESTARTCOMPAFTER, context->RebootAfter / (1000 * 60), FALSE); // ms to min + Button_SetCheck(GetDlgItem(hwndDlg, IDC_ENABLERESTARTMESSAGE), context->RebootMessage ? BST_CHECKED : BST_UNCHECKED); + SetDlgItemText(hwndDlg, IDC_RESTARTMESSAGE, PhGetString(context->RebootMessage)); + + SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hwndDlg, IDC_RESTARTCOMPAFTER), TRUE); + Edit_SetSel(GetDlgItem(hwndDlg, IDC_RESTARTCOMPAFTER), 0, -1); + } + break; + case WM_COMMAND: + { + switch (LOWORD(wParam)) + { + case IDCANCEL: + EndDialog(hwndDlg, IDCANCEL); + break; + case IDOK: + { + context->RebootAfter = GetDlgItemInt(hwndDlg, IDC_RESTARTCOMPAFTER, NULL, FALSE) * 1000 * 60; + + if (Button_GetCheck(GetDlgItem(hwndDlg, IDC_ENABLERESTARTMESSAGE)) == BST_CHECKED) + PhMoveReference(&context->RebootMessage, PhGetWindowText(GetDlgItem(hwndDlg, IDC_RESTARTMESSAGE))); + else + PhClearReference(&context->RebootMessage); + + context->Dirty = TRUE; + + EndDialog(hwndDlg, IDOK); + } + break; + case IDC_USEDEFAULTMESSAGE: + { + PPH_STRING message; + PWSTR computerName; + ULONG bufferSize; + BOOLEAN allocated = TRUE; + + // Get the computer name. + + bufferSize = 64; + computerName = PhAllocate((bufferSize + 1) * sizeof(WCHAR)); + + if (!GetComputerName(computerName, &bufferSize)) + { + PhFree(computerName); + computerName = PhAllocate((bufferSize + 1) * sizeof(WCHAR)); + + if (!GetComputerName(computerName, &bufferSize)) + { + PhFree(computerName); + computerName = L"(unknown)"; + allocated = FALSE; + } + } + + // This message is exactly the same as the one in the Services console, + // except the double spaces are replaced by single spaces. + message = PhaFormatString( + L"Your computer is connected to the computer named %s. " + L"The %s service on %s has ended unexpectedly. " + L"%s will restart automatically, and then you can reestablish the connection.", + computerName, + context->ServiceItem->Name->Buffer, + computerName, + computerName + ); + SetDlgItemText(hwndDlg, IDC_RESTARTMESSAGE, message->Buffer); + + if (allocated) + PhFree(computerName); + + Button_SetCheck(GetDlgItem(hwndDlg, IDC_ENABLERESTARTMESSAGE), BST_CHECKED); + } + break; + case IDC_RESTARTMESSAGE: + { + if (HIWORD(wParam) == EN_CHANGE) + { + // A zero length restart message disables it, so we might as well uncheck the box. + Button_SetCheck(GetDlgItem(hwndDlg, IDC_ENABLERESTARTMESSAGE), + GetWindowTextLength(GetDlgItem(hwndDlg, IDC_RESTARTMESSAGE)) != 0 ? BST_CHECKED : BST_UNCHECKED); + } + } + break; + } + } + break; + } + + return FALSE; +} diff --git a/plugins/ExtendedServices/resource.h b/plugins/ExtendedServices/resource.h index 4473b8eb0e67..b54d8cd6f2f8 100644 --- a/plugins/ExtendedServices/resource.h +++ b/plugins/ExtendedServices/resource.h @@ -1,73 +1,73 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by ExtendedServices.rc -// -#define IDD_SVCLIST 101 -#define IDD_SRVLIST 101 -#define ID_SERVICE_RESTART 101 -#define IDD_SRVRECOVERY 102 -#define ID_SERVICE_START 102 -#define IDD_RESTARTCOMP 103 -#define ID_SERVICE_STOP 103 -#define IDD_SRVRECOVERY2 104 -#define ID_SERVICE_GOTOSERVICE 104 -#define IDD_SRVPROGRESS 105 -#define ID_SERVICE_CONTINUE 105 -#define IDD_SRVOTHER 106 -#define ID_SERVICE_PAUSE 106 -#define IDD_OPTIONS 107 -#define IDD_SRVTRIGGER 108 -#define IDD_VALUE 109 -#define IDD_SRVTRIGGERS 110 -#define IDC_SERVICES_LAYOUT 1001 -#define IDC_MESSAGE 1002 -#define IDC_FIRSTFAILURE 1003 -#define IDC_SECONDFAILURE 1004 -#define IDC_SUBSEQUENTFAILURES 1005 -#define IDC_RESETFAILCOUNT 1006 -#define IDC_RESTARTSERVICEAFTER 1007 -#define IDC_RESTARTSERVICEAFTER_LABEL 1008 -#define IDC_RESTARTSERVICEAFTER_MINUTES 1009 -#define IDC_ENABLEFORERRORSTOPS 1011 -#define IDC_RESTARTCOMPUTEROPTIONS 1012 -#define IDC_RUNPROGRAM 1014 -#define IDC_BROWSE 1015 -#define IDC_RESTARTCOMPAFTER 1016 -#define IDC_ENABLERESTARTMESSAGE 1017 -#define IDC_RESTARTMESSAGE 1018 -#define IDC_RUNPROGRAM_GROUP 1019 -#define IDC_RUNPROGRAM_LABEL 1020 -#define IDC_RUNPROGRAM_INFO 1021 -#define IDC_USEDEFAULTMESSAGE 1022 -#define IDC_PROGRESS 1023 -#define IDC_PRESHUTDOWNTIMEOUT 1024 -#define IDC_PRIVILEGES 1025 -#define IDC_TRIGGERS 1026 -#define IDC_TRIGGERS_LABEL 1027 -#define IDC_ENABLESERVICESMENU 1028 -#define IDC_TYPE 1029 -#define IDC_SUBTYPE 1030 -#define IDC_SUBTYPECUSTOM 1031 -#define IDC_ACTION 1032 -#define IDC_LIST 1033 -#define IDC_NEW 1034 -#define IDC_EDIT 1035 -#define IDC_DELETE 1037 -#define IDC_VALUES 1038 -#define IDC_REMOVE 1042 -#define IDC_ADD 1043 -#define IDC_SERVICESID 1044 -#define IDC_SIDTYPE 1045 -#define IDC_COMBO2 1046 -#define IDC_PROTECTION 1046 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 111 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1047 -#define _APS_NEXT_SYMED_VALUE 107 -#endif -#endif +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by ExtendedServices.rc +// +#define IDD_SVCLIST 101 +#define IDD_SRVLIST 101 +#define ID_SERVICE_RESTART 101 +#define IDD_SRVRECOVERY 102 +#define ID_SERVICE_START 102 +#define IDD_RESTARTCOMP 103 +#define ID_SERVICE_STOP 103 +#define IDD_SRVRECOVERY2 104 +#define ID_SERVICE_GOTOSERVICE 104 +#define IDD_SRVPROGRESS 105 +#define ID_SERVICE_CONTINUE 105 +#define IDD_SRVOTHER 106 +#define ID_SERVICE_PAUSE 106 +#define IDD_OPTIONS 107 +#define IDD_SRVTRIGGER 108 +#define IDD_VALUE 109 +#define IDD_SRVTRIGGERS 110 +#define IDC_SERVICES_LAYOUT 1001 +#define IDC_MESSAGE 1002 +#define IDC_FIRSTFAILURE 1003 +#define IDC_SECONDFAILURE 1004 +#define IDC_SUBSEQUENTFAILURES 1005 +#define IDC_RESETFAILCOUNT 1006 +#define IDC_RESTARTSERVICEAFTER 1007 +#define IDC_RESTARTSERVICEAFTER_LABEL 1008 +#define IDC_RESTARTSERVICEAFTER_MINUTES 1009 +#define IDC_ENABLEFORERRORSTOPS 1011 +#define IDC_RESTARTCOMPUTEROPTIONS 1012 +#define IDC_RUNPROGRAM 1014 +#define IDC_BROWSE 1015 +#define IDC_RESTARTCOMPAFTER 1016 +#define IDC_ENABLERESTARTMESSAGE 1017 +#define IDC_RESTARTMESSAGE 1018 +#define IDC_RUNPROGRAM_GROUP 1019 +#define IDC_RUNPROGRAM_LABEL 1020 +#define IDC_RUNPROGRAM_INFO 1021 +#define IDC_USEDEFAULTMESSAGE 1022 +#define IDC_PROGRESS 1023 +#define IDC_PRESHUTDOWNTIMEOUT 1024 +#define IDC_PRIVILEGES 1025 +#define IDC_TRIGGERS 1026 +#define IDC_TRIGGERS_LABEL 1027 +#define IDC_ENABLESERVICESMENU 1028 +#define IDC_TYPE 1029 +#define IDC_SUBTYPE 1030 +#define IDC_SUBTYPECUSTOM 1031 +#define IDC_ACTION 1032 +#define IDC_LIST 1033 +#define IDC_NEW 1034 +#define IDC_EDIT 1035 +#define IDC_DELETE 1037 +#define IDC_VALUES 1038 +#define IDC_REMOVE 1042 +#define IDC_ADD 1043 +#define IDC_SERVICESID 1044 +#define IDC_SIDTYPE 1045 +#define IDC_COMBO2 1046 +#define IDC_PROTECTION 1046 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 111 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1047 +#define _APS_NEXT_SYMED_VALUE 107 +#endif +#endif diff --git a/plugins/ExtendedServices/srvprgrs.c b/plugins/ExtendedServices/srvprgrs.c index 116957accf64..0cde80360efb 100644 --- a/plugins/ExtendedServices/srvprgrs.c +++ b/plugins/ExtendedServices/srvprgrs.c @@ -1,151 +1,151 @@ -/* - * Process Hacker Extended Services - - * progress dialog - * - * Copyright (C) 2010 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include "extsrv.h" - -typedef struct _RESTART_SERVICE_CONTEXT -{ - PPH_SERVICE_ITEM ServiceItem; - SC_HANDLE ServiceHandle; - BOOLEAN Starting; - BOOLEAN DisableTimer; -} RESTART_SERVICE_CONTEXT, *PRESTART_SERVICE_CONTEXT; - -INT_PTR CALLBACK EspRestartServiceDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - PRESTART_SERVICE_CONTEXT context; - - if (uMsg == WM_INITDIALOG) - { - context = (PRESTART_SERVICE_CONTEXT)lParam; - SetProp(hwndDlg, L"Context", (HANDLE)context); - } - else - { - context = (PRESTART_SERVICE_CONTEXT)GetProp(hwndDlg, L"Context"); - - if (uMsg == WM_DESTROY) - RemoveProp(hwndDlg, L"Context"); - } - - if (!context) - return FALSE; - - switch (uMsg) - { - case WM_INITDIALOG: - { - PhCenterWindow(hwndDlg, GetParent(hwndDlg)); - - // TODO: Use the progress information. - PhSetWindowStyle(GetDlgItem(hwndDlg, IDC_PROGRESS), PBS_MARQUEE, PBS_MARQUEE); - SendMessage(GetDlgItem(hwndDlg, IDC_PROGRESS), PBM_SETMARQUEE, TRUE, 75); - - SetDlgItemText(hwndDlg, IDC_MESSAGE, PhaFormatString(L"Attempting to stop %s...", context->ServiceItem->Name->Buffer)->Buffer); - - if (PhUiStopService(hwndDlg, context->ServiceItem)) - { - SetTimer(hwndDlg, 1, 250, NULL); - } - else - { - EndDialog(hwndDlg, IDCANCEL); - } - } - break; - case WM_COMMAND: - { - switch (LOWORD(wParam)) - { - case IDCANCEL: - { - EndDialog(hwndDlg, IDCANCEL); - } - break; - } - } - break; - case WM_TIMER: - { - if (wParam == 1 && !context->DisableTimer) - { - SERVICE_STATUS serviceStatus; - - if (QueryServiceStatus(context->ServiceHandle, &serviceStatus)) - { - if (!context->Starting && serviceStatus.dwCurrentState == SERVICE_STOPPED) - { - // The service is stopped, so start the service now. - - SetDlgItemText(hwndDlg, IDC_MESSAGE, - PhaFormatString(L"Attempting to start %s...", context->ServiceItem->Name->Buffer)->Buffer); - context->DisableTimer = TRUE; - - if (PhUiStartService(hwndDlg, context->ServiceItem)) - { - context->DisableTimer = FALSE; - context->Starting = TRUE; - } - else - { - EndDialog(hwndDlg, IDCANCEL); - } - } - else if (context->Starting && serviceStatus.dwCurrentState == SERVICE_RUNNING) - { - EndDialog(hwndDlg, IDOK); - } - } - } - } - break; - } - - return FALSE; -} - -VOID EsRestartServiceWithProgress( - _In_ HWND hWnd, - _In_ PPH_SERVICE_ITEM ServiceItem, - _In_ SC_HANDLE ServiceHandle - ) -{ - RESTART_SERVICE_CONTEXT context; - - context.ServiceItem = ServiceItem; - context.ServiceHandle = ServiceHandle; - context.Starting = FALSE; - context.DisableTimer = FALSE; - - DialogBoxParam( - PluginInstance->DllBase, - MAKEINTRESOURCE(IDD_SRVPROGRESS), - hWnd, - EspRestartServiceDlgProc, - (LPARAM)&context - ); +/* + * Process Hacker Extended Services - + * progress dialog + * + * Copyright (C) 2010 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include "extsrv.h" + +typedef struct _RESTART_SERVICE_CONTEXT +{ + PPH_SERVICE_ITEM ServiceItem; + SC_HANDLE ServiceHandle; + BOOLEAN Starting; + BOOLEAN DisableTimer; +} RESTART_SERVICE_CONTEXT, *PRESTART_SERVICE_CONTEXT; + +INT_PTR CALLBACK EspRestartServiceDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + PRESTART_SERVICE_CONTEXT context; + + if (uMsg == WM_INITDIALOG) + { + context = (PRESTART_SERVICE_CONTEXT)lParam; + SetProp(hwndDlg, L"Context", (HANDLE)context); + } + else + { + context = (PRESTART_SERVICE_CONTEXT)GetProp(hwndDlg, L"Context"); + + if (uMsg == WM_DESTROY) + RemoveProp(hwndDlg, L"Context"); + } + + if (!context) + return FALSE; + + switch (uMsg) + { + case WM_INITDIALOG: + { + PhCenterWindow(hwndDlg, GetParent(hwndDlg)); + + // TODO: Use the progress information. + PhSetWindowStyle(GetDlgItem(hwndDlg, IDC_PROGRESS), PBS_MARQUEE, PBS_MARQUEE); + SendMessage(GetDlgItem(hwndDlg, IDC_PROGRESS), PBM_SETMARQUEE, TRUE, 75); + + SetDlgItemText(hwndDlg, IDC_MESSAGE, PhaFormatString(L"Attempting to stop %s...", context->ServiceItem->Name->Buffer)->Buffer); + + if (PhUiStopService(hwndDlg, context->ServiceItem)) + { + SetTimer(hwndDlg, 1, 250, NULL); + } + else + { + EndDialog(hwndDlg, IDCANCEL); + } + } + break; + case WM_COMMAND: + { + switch (LOWORD(wParam)) + { + case IDCANCEL: + { + EndDialog(hwndDlg, IDCANCEL); + } + break; + } + } + break; + case WM_TIMER: + { + if (wParam == 1 && !context->DisableTimer) + { + SERVICE_STATUS serviceStatus; + + if (QueryServiceStatus(context->ServiceHandle, &serviceStatus)) + { + if (!context->Starting && serviceStatus.dwCurrentState == SERVICE_STOPPED) + { + // The service is stopped, so start the service now. + + SetDlgItemText(hwndDlg, IDC_MESSAGE, + PhaFormatString(L"Attempting to start %s...", context->ServiceItem->Name->Buffer)->Buffer); + context->DisableTimer = TRUE; + + if (PhUiStartService(hwndDlg, context->ServiceItem)) + { + context->DisableTimer = FALSE; + context->Starting = TRUE; + } + else + { + EndDialog(hwndDlg, IDCANCEL); + } + } + else if (context->Starting && serviceStatus.dwCurrentState == SERVICE_RUNNING) + { + EndDialog(hwndDlg, IDOK); + } + } + } + } + break; + } + + return FALSE; +} + +VOID EsRestartServiceWithProgress( + _In_ HWND hWnd, + _In_ PPH_SERVICE_ITEM ServiceItem, + _In_ SC_HANDLE ServiceHandle + ) +{ + RESTART_SERVICE_CONTEXT context; + + context.ServiceItem = ServiceItem; + context.ServiceHandle = ServiceHandle; + context.Starting = FALSE; + context.DisableTimer = FALSE; + + DialogBoxParam( + PluginInstance->DllBase, + MAKEINTRESOURCE(IDD_SRVPROGRESS), + hWnd, + EspRestartServiceDlgProc, + (LPARAM)&context + ); } \ No newline at end of file diff --git a/plugins/ExtendedServices/trigger.c b/plugins/ExtendedServices/trigger.c index b60fe1134721..e0aa2b667435 100644 --- a/plugins/ExtendedServices/trigger.c +++ b/plugins/ExtendedServices/trigger.c @@ -1,1720 +1,1720 @@ -/* - * Process Hacker Extended Services - - * trigger editor - * - * Copyright (C) 2011-2015 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include "extsrv.h" - -typedef struct _ES_TRIGGER_DATA -{ - ULONG Type; - union - { - PPH_STRING String; - struct - { - PVOID Binary; - ULONG BinaryLength; - }; - UCHAR Byte; - ULONG64 UInt64; - }; -} ES_TRIGGER_DATA, *PES_TRIGGER_DATA; - -typedef struct _ES_TRIGGER_INFO -{ - ULONG Type; - PGUID Subtype; - ULONG Action; - PPH_LIST DataList; - GUID SubtypeBuffer; -} ES_TRIGGER_INFO, *PES_TRIGGER_INFO; - -typedef struct _ES_TRIGGER_CONTEXT -{ - PPH_SERVICE_ITEM ServiceItem; - HWND WindowHandle; - HWND TriggersLv; - BOOLEAN Dirty; - ULONG InitialNumberOfTriggers; - PPH_LIST InfoList; - - // Trigger dialog box - PES_TRIGGER_INFO EditingInfo; - ULONG LastSelectedType; - PPH_STRING LastCustomSubType; - - // Value dialog box - PPH_STRING EditingValue; -} ES_TRIGGER_CONTEXT, *PES_TRIGGER_CONTEXT; - -typedef struct _TYPE_ENTRY -{ - ULONG Type; - PWSTR Name; -} TYPE_ENTRY, PTYPE_ENTRY; - -typedef struct _SUBTYPE_ENTRY -{ - ULONG Type; - PGUID Guid; - PWSTR Name; -} SUBTYPE_ENTRY, PSUBTYPE_ENTRY; - -typedef struct _ETW_PUBLISHER_ENTRY -{ - PPH_STRING PublisherName; - GUID Guid; -} ETW_PUBLISHER_ENTRY, *PETW_PUBLISHER_ENTRY; - -INT_PTR CALLBACK EspServiceTriggerDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -INT_PTR CALLBACK ValueDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -static GUID NetworkManagerFirstIpAddressArrivalGuid = { 0x4f27f2de, 0x14e2, 0x430b, { 0xa5, 0x49, 0x7c, 0xd4, 0x8c, 0xbc, 0x82, 0x45 } }; -static GUID NetworkManagerLastIpAddressRemovalGuid = { 0xcc4ba62a, 0x162e, 0x4648, { 0x84, 0x7a, 0xb6, 0xbd, 0xf9, 0x93, 0xe3, 0x35 } }; -static GUID DomainJoinGuid = { 0x1ce20aba, 0x9851, 0x4421, { 0x94, 0x30, 0x1d, 0xde, 0xb7, 0x66, 0xe8, 0x09 } }; -static GUID DomainLeaveGuid = { 0xddaf516e, 0x58c2, 0x4866, { 0x95, 0x74, 0xc3, 0xb6, 0x15, 0xd4, 0x2e, 0xa1 } }; -static GUID FirewallPortOpenGuid = { 0xb7569e07, 0x8421, 0x4ee0, { 0xad, 0x10, 0x86, 0x91, 0x5a, 0xfd, 0xad, 0x09 } }; -static GUID FirewallPortCloseGuid = { 0xa144ed38, 0x8e12, 0x4de4, { 0x9d, 0x96, 0xe6, 0x47, 0x40, 0xb1, 0xa5, 0x24 } }; -static GUID MachinePolicyPresentGuid = { 0x659fcae6, 0x5bdb, 0x4da9, { 0xb1, 0xff, 0xca, 0x2a, 0x17, 0x8d, 0x46, 0xe0 } }; -static GUID UserPolicyPresentGuid = { 0x54fb46c8, 0xf089, 0x464c, { 0xb1, 0xfd, 0x59, 0xd1, 0xb6, 0x2c, 0x3b, 0x50 } }; -static GUID RpcInterfaceEventGuid = { 0xbc90d167, 0x9470, 0x4139, { 0xa9, 0xba, 0xbe, 0x0b, 0xbb, 0xf5, 0xb7, 0x4d } }; -static GUID NamedPipeEventGuid = { 0x1f81d131, 0x3fac, 0x4537, { 0x9e, 0x0c, 0x7e, 0x7b, 0x0c, 0x2f, 0x4b, 0x55 } }; -static GUID SubTypeUnknownGuid; // dummy - -static TYPE_ENTRY TypeEntries[] = -{ - { SERVICE_TRIGGER_TYPE_DEVICE_INTERFACE_ARRIVAL, L"Device interface arrival" }, - { SERVICE_TRIGGER_TYPE_IP_ADDRESS_AVAILABILITY, L"IP address availability" }, - { SERVICE_TRIGGER_TYPE_DOMAIN_JOIN, L"Domain join" }, - { SERVICE_TRIGGER_TYPE_FIREWALL_PORT_EVENT, L"Firewall port event" }, - { SERVICE_TRIGGER_TYPE_GROUP_POLICY, L"Group policy" }, - { SERVICE_TRIGGER_TYPE_NETWORK_ENDPOINT, L"Network endpoint" }, - { SERVICE_TRIGGER_TYPE_CUSTOM_SYSTEM_STATE_CHANGE, L"Custom system state change" }, - { SERVICE_TRIGGER_TYPE_CUSTOM, L"Custom" } -}; - -static SUBTYPE_ENTRY SubTypeEntries[] = -{ - { SERVICE_TRIGGER_TYPE_IP_ADDRESS_AVAILABILITY, NULL, L"IP address" }, - { SERVICE_TRIGGER_TYPE_IP_ADDRESS_AVAILABILITY, &NetworkManagerFirstIpAddressArrivalGuid, L"IP address: First arrival" }, - { SERVICE_TRIGGER_TYPE_IP_ADDRESS_AVAILABILITY, &NetworkManagerLastIpAddressRemovalGuid, L"IP address: Last removal" }, - { SERVICE_TRIGGER_TYPE_IP_ADDRESS_AVAILABILITY, &SubTypeUnknownGuid, L"IP address: Unknown" }, - { SERVICE_TRIGGER_TYPE_DOMAIN_JOIN, NULL, L"Domain" }, - { SERVICE_TRIGGER_TYPE_DOMAIN_JOIN, &DomainJoinGuid, L"Domain: Join" }, - { SERVICE_TRIGGER_TYPE_DOMAIN_JOIN, &DomainLeaveGuid, L"Domain: Leave" }, - { SERVICE_TRIGGER_TYPE_DOMAIN_JOIN, &SubTypeUnknownGuid, L"Domain: Unknown" }, - { SERVICE_TRIGGER_TYPE_FIREWALL_PORT_EVENT, NULL, L"Firewall port" }, - { SERVICE_TRIGGER_TYPE_FIREWALL_PORT_EVENT, &FirewallPortOpenGuid, L"Firewall port: Open" }, - { SERVICE_TRIGGER_TYPE_FIREWALL_PORT_EVENT, &FirewallPortCloseGuid, L"Firewall port: Close" }, - { SERVICE_TRIGGER_TYPE_FIREWALL_PORT_EVENT, &SubTypeUnknownGuid, L"Firewall port: Unknown" }, - { SERVICE_TRIGGER_TYPE_GROUP_POLICY, NULL, L"Group policy change" }, - { SERVICE_TRIGGER_TYPE_GROUP_POLICY, &MachinePolicyPresentGuid, L"Group policy change: Machine" }, - { SERVICE_TRIGGER_TYPE_GROUP_POLICY, &UserPolicyPresentGuid, L"Group policy change: User" }, - { SERVICE_TRIGGER_TYPE_GROUP_POLICY, &SubTypeUnknownGuid, L"Group policy change: Unknown" }, - { SERVICE_TRIGGER_TYPE_NETWORK_ENDPOINT, NULL, L"Network endpoint" }, - { SERVICE_TRIGGER_TYPE_NETWORK_ENDPOINT, &RpcInterfaceEventGuid, L"Network endpoint: RPC interface" }, - { SERVICE_TRIGGER_TYPE_NETWORK_ENDPOINT, &NamedPipeEventGuid, L"Network endpoint: Named pipe" }, - { SERVICE_TRIGGER_TYPE_NETWORK_ENDPOINT, &SubTypeUnknownGuid, L"Network endpoint: Unknown" } -}; - -static PH_STRINGREF PublishersKeyName = PH_STRINGREF_INIT(L"Software\\Microsoft\\Windows\\CurrentVersion\\WINEVT\\Publishers\\"); - -PES_TRIGGER_DATA EspCreateTriggerData( - _In_opt_ PSERVICE_TRIGGER_SPECIFIC_DATA_ITEM DataItem - ) -{ - PES_TRIGGER_DATA data; - - data = PhAllocate(sizeof(ES_TRIGGER_DATA)); - memset(data, 0, sizeof(ES_TRIGGER_DATA)); - - if (DataItem) - { - data->Type = DataItem->dwDataType; - - if (data->Type == SERVICE_TRIGGER_DATA_TYPE_STRING) - { - if (DataItem->pData && DataItem->cbData >= 2) - data->String = PhCreateStringEx((PWSTR)DataItem->pData, DataItem->cbData - 2); // exclude final null terminator - else - data->String = PhReferenceEmptyString(); - } - else if (data->Type == SERVICE_TRIGGER_DATA_TYPE_BINARY) - { - data->BinaryLength = DataItem->cbData; - data->Binary = PhAllocateCopy(DataItem->pData, DataItem->cbData); - } - else if (data->Type == SERVICE_TRIGGER_DATA_TYPE_LEVEL) - { - if (DataItem->cbData == sizeof(UCHAR)) - data->Byte = *(PUCHAR)DataItem->pData; - } - else if (data->Type == SERVICE_TRIGGER_DATA_TYPE_KEYWORD_ANY || data->Type == SERVICE_TRIGGER_DATA_TYPE_KEYWORD_ALL) - { - if (DataItem->cbData == sizeof(ULONG64)) - data->UInt64 = *(PULONG64)DataItem->pData; - } - } - - return data; -} - -PES_TRIGGER_DATA EspCloneTriggerData( - _In_ PES_TRIGGER_DATA Data - ) -{ - PES_TRIGGER_DATA newData; - - newData = PhAllocateCopy(Data, sizeof(ES_TRIGGER_DATA)); - - if (newData->Type == SERVICE_TRIGGER_DATA_TYPE_STRING) - { - if (newData->String) - newData->String = PhDuplicateString(newData->String); - } - else if (newData->Type == SERVICE_TRIGGER_DATA_TYPE_BINARY) - { - if (newData->Binary) - newData->Binary = PhAllocateCopy(newData->Binary, newData->BinaryLength); - } - - return newData; -} - -VOID EspDestroyTriggerData( - _In_ PES_TRIGGER_DATA Data - ) -{ - if (Data->Type == SERVICE_TRIGGER_DATA_TYPE_STRING) - { - if (Data->String) - PhDereferenceObject(Data->String); - } - else if (Data->Type == SERVICE_TRIGGER_DATA_TYPE_BINARY) - { - if (Data->Binary) - PhFree(Data->Binary); - } - - PhFree(Data); -} - -PES_TRIGGER_INFO EspCreateTriggerInfo( - _In_opt_ PSERVICE_TRIGGER Trigger - ) -{ - PES_TRIGGER_INFO info; - - info = PhAllocate(sizeof(ES_TRIGGER_INFO)); - memset(info, 0, sizeof(ES_TRIGGER_INFO)); - - if (Trigger) - { - info->Type = Trigger->dwTriggerType; - - if (Trigger->pTriggerSubtype) - { - info->SubtypeBuffer = *Trigger->pTriggerSubtype; - info->Subtype = &info->SubtypeBuffer; - } - - info->Action = Trigger->dwAction; - - if ( - info->Type == SERVICE_TRIGGER_TYPE_CUSTOM || - info->Type == SERVICE_TRIGGER_TYPE_DEVICE_INTERFACE_ARRIVAL || - info->Type == SERVICE_TRIGGER_TYPE_FIREWALL_PORT_EVENT || - info->Type == SERVICE_TRIGGER_TYPE_NETWORK_ENDPOINT - ) - { - ULONG i; - - info->DataList = PhCreateList(Trigger->cDataItems); - - for (i = 0; i < Trigger->cDataItems; i++) - { - PhAddItemList(info->DataList, EspCreateTriggerData(&Trigger->pDataItems[i])); - } - } - } - - return info; -} - -PES_TRIGGER_INFO EspCloneTriggerInfo( - _In_ PES_TRIGGER_INFO Info - ) -{ - PES_TRIGGER_INFO newInfo; - - newInfo = PhAllocateCopy(Info, sizeof(ES_TRIGGER_INFO)); - - if (newInfo->Subtype == &Info->SubtypeBuffer) - newInfo->Subtype = &newInfo->SubtypeBuffer; - - if (newInfo->DataList) - { - ULONG i; - - newInfo->DataList = PhCreateList(Info->DataList->AllocatedCount); - newInfo->DataList->Count = Info->DataList->Count; - - for (i = 0; i < Info->DataList->Count; i++) - newInfo->DataList->Items[i] = EspCloneTriggerData(Info->DataList->Items[i]); - } - - return newInfo; -} - -VOID EspDestroyTriggerInfo( - _In_ PES_TRIGGER_INFO Info - ) -{ - if (Info->DataList) - { - ULONG i; - - for (i = 0; i < Info->DataList->Count; i++) - { - EspDestroyTriggerData(Info->DataList->Items[i]); - } - - PhDereferenceObject(Info->DataList); - } - - PhFree(Info); -} - -VOID EspClearTriggerInfoList( - _In_ PPH_LIST List - ) -{ - ULONG i; - - for (i = 0; i < List->Count; i++) - { - EspDestroyTriggerInfo(List->Items[i]); - } - - PhClearList(List); -} - -struct _ES_TRIGGER_CONTEXT *EsCreateServiceTriggerContext( - _In_ PPH_SERVICE_ITEM ServiceItem, - _In_ HWND WindowHandle, - _In_ HWND TriggersLv - ) -{ - PES_TRIGGER_CONTEXT context; - - context = PhAllocate(sizeof(ES_TRIGGER_CONTEXT)); - memset(context, 0, sizeof(ES_TRIGGER_CONTEXT)); - context->ServiceItem = ServiceItem; - context->WindowHandle = WindowHandle; - context->TriggersLv = TriggersLv; - context->InfoList = PhCreateList(4); - - PhSetListViewStyle(TriggersLv, FALSE, TRUE); - PhSetControlTheme(TriggersLv, L"explorer"); - PhAddListViewColumn(TriggersLv, 0, 0, 0, LVCFMT_LEFT, 300, L"Trigger"); - PhAddListViewColumn(TriggersLv, 1, 1, 1, LVCFMT_LEFT, 60, L"Action"); - PhSetExtendedListView(TriggersLv); - - EnableWindow(GetDlgItem(WindowHandle, IDC_EDIT), FALSE); - EnableWindow(GetDlgItem(WindowHandle, IDC_DELETE), FALSE); - - return context; -} - -VOID EsDestroyServiceTriggerContext( - _In_ struct _ES_TRIGGER_CONTEXT *Context - ) -{ - ULONG i; - - for (i = 0; i < Context->InfoList->Count; i++) - { - EspDestroyTriggerInfo(Context->InfoList->Items[i]); - } - - PhDereferenceObject(Context->InfoList); - PhFree(Context); -} - -PPH_STRING EspLookupEtwPublisherName( - _In_ PGUID Guid - ) -{ - PPH_STRING guidString; - PPH_STRING keyName; - HANDLE keyHandle; - PPH_STRING publisherName = NULL; - - // Copied from ProcessHacker\hndlinfo.c. - - guidString = PhFormatGuid(Guid); - - keyName = PhConcatStringRef2(&PublishersKeyName, &guidString->sr); - - if (NT_SUCCESS(PhOpenKey( - &keyHandle, - KEY_READ, - PH_KEY_LOCAL_MACHINE, - &keyName->sr, - 0 - ))) - { - publisherName = PhQueryRegistryString(keyHandle, NULL); - - if (publisherName && publisherName->Length == 0) - { - PhDereferenceObject(publisherName); - publisherName = NULL; - } - - NtClose(keyHandle); - } - - PhDereferenceObject(keyName); - - if (publisherName) - { - PhDereferenceObject(guidString); - return publisherName; - } - else - { - return guidString; - } -} - -BOOLEAN EspEnumerateEtwPublishers( - _Out_ PETW_PUBLISHER_ENTRY *Entries, - _Out_ PULONG NumberOfEntries - ) -{ - NTSTATUS status; - HANDLE publishersKeyHandle; - ULONG index; - PKEY_BASIC_INFORMATION buffer; - ULONG bufferSize; - PETW_PUBLISHER_ENTRY entries; - ULONG numberOfEntries; - ULONG allocatedEntries; - - if (!NT_SUCCESS(PhOpenKey( - &publishersKeyHandle, - KEY_READ, - PH_KEY_LOCAL_MACHINE, - &PublishersKeyName, - 0 - ))) - { - return FALSE; - } - - numberOfEntries = 0; - allocatedEntries = 256; - entries = PhAllocate(allocatedEntries * sizeof(ETW_PUBLISHER_ENTRY)); - - index = 0; - bufferSize = 0x100; - buffer = PhAllocate(0x100); - - while (TRUE) - { - status = NtEnumerateKey( - publishersKeyHandle, - index, - KeyBasicInformation, - buffer, - bufferSize, - &bufferSize - ); - - if (NT_SUCCESS(status)) - { - UNICODE_STRING nameUs; - PH_STRINGREF name; - HANDLE keyHandle; - GUID guid; - PPH_STRING publisherName; - - nameUs.Buffer = buffer->Name; - nameUs.Length = (USHORT)buffer->NameLength; - name.Buffer = buffer->Name; - name.Length = buffer->NameLength; - - // Make sure this is a valid publisher key. - if (NT_SUCCESS(RtlGUIDFromString(&nameUs, &guid))) - { - if (NT_SUCCESS(PhOpenKey( - &keyHandle, - KEY_READ, - publishersKeyHandle, - &name, - 0 - ))) - { - publisherName = PhQueryRegistryString(keyHandle, NULL); - - if (publisherName) - { - if (publisherName->Length != 0) - { - PETW_PUBLISHER_ENTRY entry; - - if (numberOfEntries == allocatedEntries) - { - allocatedEntries *= 2; - entries = PhReAllocate(entries, allocatedEntries * sizeof(ETW_PUBLISHER_ENTRY)); - } - - entry = &entries[numberOfEntries++]; - entry->PublisherName = publisherName; - entry->Guid = guid; - } - else - { - PhDereferenceObject(publisherName); - } - } - - NtClose(keyHandle); - } - } - - index++; - } - else if (status == STATUS_NO_MORE_ENTRIES) - { - break; - } - else if (status == STATUS_BUFFER_OVERFLOW || status == STATUS_BUFFER_TOO_SMALL) - { - PhFree(buffer); - buffer = PhAllocate(bufferSize); - } - else - { - break; - } - } - - PhFree(buffer); - NtClose(publishersKeyHandle); - - *Entries = entries; - *NumberOfEntries = numberOfEntries; - - return TRUE; -} - -BOOLEAN EspLookupEtwPublisherGuid( - _In_ PPH_STRINGREF PublisherName, - _Out_ PGUID Guid - ) -{ - BOOLEAN result; - PETW_PUBLISHER_ENTRY entries; - ULONG numberOfEntries; - ULONG i; - - if (!EspEnumerateEtwPublishers(&entries, &numberOfEntries)) - return FALSE; - - result = FALSE; - - for (i = 0; i < numberOfEntries; i++) - { - if (!result && PhEqualStringRef(&entries[i].PublisherName->sr, PublisherName, TRUE)) - { - *Guid = entries[i].Guid; - result = TRUE; - } - - PhDereferenceObject(entries[i].PublisherName); - } - - PhFree(entries); - - return result; -} - -VOID EspFormatTriggerInfo( - _In_ PES_TRIGGER_INFO Info, - _Out_ PWSTR *TriggerString, - _Out_ PWSTR *ActionString, - _Out_ PPH_STRING *StringUsed - ) -{ - PPH_STRING stringUsed = NULL; - PWSTR triggerString = NULL; - PWSTR actionString; - ULONG i; - BOOLEAN typeFound; - BOOLEAN subTypeFound; - - switch (Info->Type) - { - case SERVICE_TRIGGER_TYPE_DEVICE_INTERFACE_ARRIVAL: - { - PPH_STRING guidString; - - if (!Info->Subtype) - { - triggerString = L"Device interface arrival"; - } - else - { - guidString = PhFormatGuid(Info->Subtype); - stringUsed = PhConcatStrings2(L"Device interface arrival: ", guidString->Buffer); - triggerString = stringUsed->Buffer; - } - } - break; - case SERVICE_TRIGGER_TYPE_CUSTOM_SYSTEM_STATE_CHANGE: - { - PPH_STRING guidString; - - if (!Info->Subtype) - { - triggerString = L"Custom system state change"; - } - else - { - guidString = PhFormatGuid(Info->Subtype); - stringUsed = PhConcatStrings2(L"Custom system state change: ", guidString->Buffer); - triggerString = stringUsed->Buffer; - } - } - break; - case SERVICE_TRIGGER_TYPE_CUSTOM: - { - if (Info->Subtype) - { - PPH_STRING publisherName; - - // Try to lookup the publisher name from the GUID. - publisherName = EspLookupEtwPublisherName(Info->Subtype); - stringUsed = PhConcatStrings2(L"Custom: ", publisherName->Buffer); - PhDereferenceObject(publisherName); - triggerString = stringUsed->Buffer; - } - else - { - triggerString = L"Custom"; - } - } - break; - default: - { - typeFound = FALSE; - subTypeFound = FALSE; - - for (i = 0; i < sizeof(SubTypeEntries) / sizeof(SUBTYPE_ENTRY); i++) - { - if (SubTypeEntries[i].Type == Info->Type) - { - typeFound = TRUE; - - if (!Info->Subtype && !SubTypeEntries[i].Guid) - { - subTypeFound = TRUE; - triggerString = SubTypeEntries[i].Name; - break; - } - else if (Info->Subtype && SubTypeEntries[i].Guid && memcmp(Info->Subtype, SubTypeEntries[i].Guid, sizeof(GUID)) == 0) - { - subTypeFound = TRUE; - triggerString = SubTypeEntries[i].Name; - break; - } - else if (!subTypeFound && SubTypeEntries[i].Guid == &SubTypeUnknownGuid) - { - triggerString = SubTypeEntries[i].Name; - break; - } - } - } - - if (!typeFound) - { - triggerString = L"Unknown"; - } - } - break; - } - - switch (Info->Action) - { - case SERVICE_TRIGGER_ACTION_SERVICE_START: - actionString = L"Start"; - break; - case SERVICE_TRIGGER_ACTION_SERVICE_STOP: - actionString = L"Stop"; - break; - default: - actionString = L"Unknown"; - break; - } - - *TriggerString = triggerString; - *ActionString = actionString; - *StringUsed = stringUsed; -} - -VOID EsLoadServiceTriggerInfo( - _In_ struct _ES_TRIGGER_CONTEXT *Context, - _In_ SC_HANDLE ServiceHandle - ) -{ - PSERVICE_TRIGGER_INFO triggerInfo; - ULONG i; - - EspClearTriggerInfoList(Context->InfoList); - - if (triggerInfo = PhQueryServiceVariableSize(ServiceHandle, SERVICE_CONFIG_TRIGGER_INFO)) - { - for (i = 0; i < triggerInfo->cTriggers; i++) - { - PSERVICE_TRIGGER trigger = &triggerInfo->pTriggers[i]; - PES_TRIGGER_INFO info; - PWSTR triggerString; - PWSTR actionString; - PPH_STRING stringUsed; - INT lvItemIndex; - - info = EspCreateTriggerInfo(trigger); - PhAddItemList(Context->InfoList, info); - - EspFormatTriggerInfo(info, &triggerString, &actionString, &stringUsed); - - lvItemIndex = PhAddListViewItem(Context->TriggersLv, MAXINT, triggerString, info); - PhSetListViewSubItem(Context->TriggersLv, lvItemIndex, 1, actionString); - - if (stringUsed) - PhDereferenceObject(stringUsed); - } - - Context->InitialNumberOfTriggers = triggerInfo->cTriggers; - - ExtendedListView_SortItems(Context->TriggersLv); - - PhFree(triggerInfo); - } -} - -BOOLEAN EsSaveServiceTriggerInfo( - _In_ struct _ES_TRIGGER_CONTEXT *Context, - _Out_ PULONG Win32Result - ) -{ - BOOLEAN result = TRUE; - PH_AUTO_POOL autoPool; - SC_HANDLE serviceHandle; - SERVICE_TRIGGER_INFO triggerInfo; - ULONG i; - ULONG j; - - if (!Context->Dirty) - return TRUE; - - // Do not try to change trigger information if we didn't have any triggers before and we don't - // have any now. ChangeServiceConfig2 returns an error in this situation. - if (Context->InitialNumberOfTriggers == 0 && Context->InfoList->Count == 0) - return TRUE; - - PhInitializeAutoPool(&autoPool); - - memset(&triggerInfo, 0, sizeof(SERVICE_TRIGGER_INFO)); - triggerInfo.cTriggers = Context->InfoList->Count; - - // pTriggers needs to be NULL when there are no triggers. - if (Context->InfoList->Count != 0) - { - triggerInfo.pTriggers = PH_AUTO(PhCreateAlloc(Context->InfoList->Count * sizeof(SERVICE_TRIGGER))); - memset(triggerInfo.pTriggers, 0, Context->InfoList->Count * sizeof(SERVICE_TRIGGER)); - - for (i = 0; i < Context->InfoList->Count; i++) - { - PSERVICE_TRIGGER trigger = &triggerInfo.pTriggers[i]; - PES_TRIGGER_INFO info = Context->InfoList->Items[i]; - - trigger->dwTriggerType = info->Type; - trigger->dwAction = info->Action; - trigger->pTriggerSubtype = info->Subtype; - - if (info->DataList && info->DataList->Count != 0) - { - trigger->cDataItems = info->DataList->Count; - trigger->pDataItems = PH_AUTO(PhCreateAlloc(info->DataList->Count * sizeof(SERVICE_TRIGGER_SPECIFIC_DATA_ITEM))); - - for (j = 0; j < info->DataList->Count; j++) - { - PSERVICE_TRIGGER_SPECIFIC_DATA_ITEM dataItem = &trigger->pDataItems[j]; - PES_TRIGGER_DATA data = info->DataList->Items[j]; - - dataItem->dwDataType = data->Type; - - if (data->Type == SERVICE_TRIGGER_DATA_TYPE_STRING) - { - dataItem->cbData = (ULONG)data->String->Length + 2; // include null terminator - dataItem->pData = (PBYTE)data->String->Buffer; - } - else if (data->Type == SERVICE_TRIGGER_DATA_TYPE_BINARY) - { - dataItem->cbData = data->BinaryLength; - dataItem->pData = data->Binary; - } - else if (data->Type == SERVICE_TRIGGER_DATA_TYPE_LEVEL) - { - dataItem->cbData = sizeof(UCHAR); - dataItem->pData = (PBYTE)&data->Byte; - } - else if (data->Type == SERVICE_TRIGGER_DATA_TYPE_KEYWORD_ANY || data->Type == SERVICE_TRIGGER_DATA_TYPE_KEYWORD_ALL) - { - dataItem->cbData = sizeof(ULONG64); - dataItem->pData = (PBYTE)&data->UInt64; - } - } - } - } - } - - if (serviceHandle = PhOpenService(Context->ServiceItem->Name->Buffer, SERVICE_CHANGE_CONFIG)) - { - if (!ChangeServiceConfig2(serviceHandle, SERVICE_CONFIG_TRIGGER_INFO, &triggerInfo)) - { - result = FALSE; - *Win32Result = GetLastError(); - } - - CloseServiceHandle(serviceHandle); - } - else - { - result = FALSE; - *Win32Result = GetLastError(); - - if (*Win32Result == ERROR_ACCESS_DENIED && !PhGetOwnTokenAttributes().Elevated) - { - // Elevate using phsvc. - if (PhUiConnectToPhSvc(Context->WindowHandle, FALSE)) - { - NTSTATUS status; - - result = TRUE; - - if (!NT_SUCCESS(status = PhSvcCallChangeServiceConfig2(Context->ServiceItem->Name->Buffer, - SERVICE_CONFIG_TRIGGER_INFO, &triggerInfo))) - { - result = FALSE; - *Win32Result = PhNtStatusToDosError(status); - } - - PhUiDisconnectFromPhSvc(); - } - else - { - // User cancelled elevation. - *Win32Result = ERROR_CANCELLED; - } - } - } - - PhDeleteAutoPool(&autoPool); - - return result; -} - -LOGICAL EspSetListViewItemParam( - _In_ HWND ListViewHandle, - _In_ INT Index, - _In_ PVOID Param - ) -{ - LVITEM item; - - item.mask = LVIF_PARAM; - item.iItem = Index; - item.iSubItem = 0; - item.lParam = (LPARAM)Param; - - return ListView_SetItem(ListViewHandle, &item); -} - -VOID EsHandleEventServiceTrigger( - _In_ struct _ES_TRIGGER_CONTEXT *Context, - _In_ ULONG Event - ) -{ - switch (Event) - { - case ES_TRIGGER_EVENT_NEW: - { - Context->EditingInfo = EspCreateTriggerInfo(NULL); - Context->EditingInfo->Type = SERVICE_TRIGGER_TYPE_IP_ADDRESS_AVAILABILITY; - Context->EditingInfo->SubtypeBuffer = NetworkManagerFirstIpAddressArrivalGuid; - Context->EditingInfo->Subtype = &Context->EditingInfo->SubtypeBuffer; - Context->EditingInfo->Action = SERVICE_TRIGGER_ACTION_SERVICE_START; - - if (DialogBoxParam( - PluginInstance->DllBase, - MAKEINTRESOURCE(IDD_SRVTRIGGER), - Context->WindowHandle, - EspServiceTriggerDlgProc, - (LPARAM)Context - ) == IDOK) - { - PWSTR triggerString; - PWSTR actionString; - PPH_STRING stringUsed; - INT lvItemIndex; - - Context->Dirty = TRUE; - PhAddItemList(Context->InfoList, Context->EditingInfo); - - EspFormatTriggerInfo(Context->EditingInfo, &triggerString, &actionString, &stringUsed); - - lvItemIndex = PhAddListViewItem(Context->TriggersLv, MAXINT, triggerString, Context->EditingInfo); - PhSetListViewSubItem(Context->TriggersLv, lvItemIndex, 1, actionString); - - if (stringUsed) - PhDereferenceObject(stringUsed); - } - else - { - EspDestroyTriggerInfo(Context->EditingInfo); - } - - Context->EditingInfo = NULL; - } - break; - case ES_TRIGGER_EVENT_EDIT: - { - INT lvItemIndex; - PES_TRIGGER_INFO info; - ULONG index; - - lvItemIndex = ListView_GetNextItem(Context->TriggersLv, -1, LVNI_SELECTED); - - if (lvItemIndex != -1 && PhGetListViewItemParam(Context->TriggersLv, lvItemIndex, (PVOID *)&info)) - { - index = PhFindItemList(Context->InfoList, info); - - if (index != -1) - { - Context->EditingInfo = EspCloneTriggerInfo(info); - - if (DialogBoxParam( - PluginInstance->DllBase, - MAKEINTRESOURCE(IDD_SRVTRIGGER), - Context->WindowHandle, - EspServiceTriggerDlgProc, - (LPARAM)Context - ) == IDOK) - { - PWSTR triggerString; - PWSTR actionString; - PPH_STRING stringUsed; - - Context->Dirty = TRUE; - EspDestroyTriggerInfo(Context->InfoList->Items[index]); - Context->InfoList->Items[index] = Context->EditingInfo; - - EspFormatTriggerInfo(Context->EditingInfo, &triggerString, &actionString, &stringUsed); - PhSetListViewSubItem(Context->TriggersLv, lvItemIndex, 0, triggerString); - PhSetListViewSubItem(Context->TriggersLv, lvItemIndex, 1, actionString); - - if (stringUsed) - PhDereferenceObject(stringUsed); - - EspSetListViewItemParam(Context->TriggersLv, lvItemIndex, Context->EditingInfo); - } - else - { - EspDestroyTriggerInfo(Context->EditingInfo); - } - - Context->EditingInfo = NULL; - } - } - } - break; - case ES_TRIGGER_EVENT_DELETE: - { - INT lvItemIndex; - PES_TRIGGER_INFO info; - ULONG index; - - lvItemIndex = ListView_GetNextItem(Context->TriggersLv, -1, LVNI_SELECTED); - - if (lvItemIndex != -1 && PhGetListViewItemParam(Context->TriggersLv, lvItemIndex, (PVOID *)&info)) - { - index = PhFindItemList(Context->InfoList, info); - - if (index != -1) - { - EspDestroyTriggerInfo(info); - PhRemoveItemList(Context->InfoList, index); - PhRemoveListViewItem(Context->TriggersLv, lvItemIndex); - } - } - - Context->Dirty = TRUE; - } - break; - case ES_TRIGGER_EVENT_SELECTIONCHANGED: - { - ULONG selectedCount; - - selectedCount = ListView_GetSelectedCount(Context->TriggersLv); - - EnableWindow(GetDlgItem(Context->WindowHandle, IDC_EDIT), selectedCount == 1); - EnableWindow(GetDlgItem(Context->WindowHandle, IDC_DELETE), selectedCount == 1); - } - break; - } -} - -ULONG EspTriggerTypeStringToInteger( - _In_ PWSTR String - ) -{ - ULONG i; - - for (i = 0; i < sizeof(TypeEntries) / sizeof(TYPE_ENTRY); i++) - { - if (PhEqualStringZ(TypeEntries[i].Name, String, FALSE)) - return TypeEntries[i].Type; - } - - return 0; -} - -static int __cdecl EtwPublisherByNameCompareFunction( - _In_ const void *elem1, - _In_ const void *elem2 - ) -{ - PETW_PUBLISHER_ENTRY entry1 = (PETW_PUBLISHER_ENTRY)elem1; - PETW_PUBLISHER_ENTRY entry2 = (PETW_PUBLISHER_ENTRY)elem2; - - return PhCompareString(entry1->PublisherName, entry2->PublisherName, TRUE); -} - -VOID EspFixServiceTriggerControls( - _In_ HWND hwndDlg, - _In_ PES_TRIGGER_CONTEXT Context - ) -{ - HWND typeComboBox; - HWND subTypeComboBox; - ULONG i; - PPH_STRING selectedTypeString; - ULONG type; - PPH_STRING selectedSubTypeString; - - typeComboBox = GetDlgItem(hwndDlg, IDC_TYPE); - subTypeComboBox = GetDlgItem(hwndDlg, IDC_SUBTYPE); - - selectedTypeString = PhGetWindowText(typeComboBox); - type = EspTriggerTypeStringToInteger(selectedTypeString->Buffer); - PhDereferenceObject(selectedTypeString); - - if (Context->LastSelectedType != type) - { - // Change the contents of the subtype combo box based on the type. - - ComboBox_ResetContent(subTypeComboBox); - - switch (type) - { - case SERVICE_TRIGGER_TYPE_DEVICE_INTERFACE_ARRIVAL: - { - ComboBox_AddString(subTypeComboBox, L"Custom"); - } - break; - case SERVICE_TRIGGER_TYPE_CUSTOM_SYSTEM_STATE_CHANGE: - { - ComboBox_AddString(subTypeComboBox, L"Custom"); - } - break; - case SERVICE_TRIGGER_TYPE_CUSTOM: - { - PETW_PUBLISHER_ENTRY entries; - ULONG numberOfEntries; - ULONG i; - - ComboBox_AddString(subTypeComboBox, L"Custom"); - - // Display a list of publishers. - if (EspEnumerateEtwPublishers(&entries, &numberOfEntries)) - { - // Sort the list by name. - qsort(entries, numberOfEntries, sizeof(ETW_PUBLISHER_ENTRY), EtwPublisherByNameCompareFunction); - - for (i = 0; i < numberOfEntries; i++) - { - ComboBox_AddString(subTypeComboBox, entries[i].PublisherName->Buffer); - PhDereferenceObject(entries[i].PublisherName); - } - - PhFree(entries); - } - } - break; - default: - for (i = 0; i < sizeof(SubTypeEntries) / sizeof(SUBTYPE_ENTRY); i++) - { - if (SubTypeEntries[i].Type == type && SubTypeEntries[i].Guid && SubTypeEntries[i].Guid != &SubTypeUnknownGuid) - { - ComboBox_AddString(subTypeComboBox, SubTypeEntries[i].Name); - } - } - break; - } - - ComboBox_SetCurSel(subTypeComboBox, 0); - - Context->LastSelectedType = type; - } - - selectedSubTypeString = PhGetWindowText(subTypeComboBox); - - if (PhEqualString2(selectedSubTypeString, L"Custom", FALSE)) - { - EnableWindow(GetDlgItem(hwndDlg, IDC_SUBTYPECUSTOM), TRUE); - SetDlgItemText(hwndDlg, IDC_SUBTYPECUSTOM, Context->LastCustomSubType->Buffer); - } - else - { - if (IsWindowEnabled(GetDlgItem(hwndDlg, IDC_SUBTYPECUSTOM))) - { - EnableWindow(GetDlgItem(hwndDlg, IDC_SUBTYPECUSTOM), FALSE); - PhMoveReference(&Context->LastCustomSubType, PhGetWindowText(GetDlgItem(hwndDlg, IDC_SUBTYPECUSTOM))); - SetDlgItemText(hwndDlg, IDC_SUBTYPECUSTOM, L""); - } - } - - PhDereferenceObject(selectedSubTypeString); -} - -PPH_STRING EspConvertNullsToNewLines( - _In_ PPH_STRING String - ) -{ - PH_STRING_BUILDER sb; - ULONG i; - - PhInitializeStringBuilder(&sb, String->Length); - - for (i = 0; i < (ULONG)String->Length / 2; i++) - { - if (String->Buffer[i] == 0) - { - PhAppendStringBuilderEx(&sb, L"\r\n", 4); - continue; - } - - PhAppendCharStringBuilder(&sb, String->Buffer[i]); - } - - return PhFinalStringBuilderString(&sb); -} - -PPH_STRING EspConvertNewLinesToNulls( - _In_ PPH_STRING String - ) -{ - PPH_STRING text; - SIZE_T count; - SIZE_T i; - - text = PhCreateStringEx(NULL, String->Length + 2); // plus one character for an extra null terminator (see below) - text->Length = 0; - count = 0; - - for (i = 0; i < String->Length / 2; i++) - { - // Lines are terminated by "\r\n". - if (String->Buffer[i] == '\r') - { - continue; - } - - if (String->Buffer[i] == '\n') - { - text->Buffer[count++] = 0; - continue; - } - - text->Buffer[count++] = String->Buffer[i]; - } - - if (count != 0) - { - // Make sure we have an extra null terminator at the end, as required of multistrings. - if (text->Buffer[count - 1] != 0) - text->Buffer[count++] = 0; - } - - text->Length = count * 2; - - return text; -} - -PPH_STRING EspConvertNullsToSpaces( - _In_ PPH_STRING String - ) -{ - PPH_STRING text; - SIZE_T j; - - text = PhDuplicateString(String); - - for (j = 0; j < text->Length / 2; j++) - { - if (text->Buffer[j] == 0) - text->Buffer[j] = ' '; - } - - return text; -} - -VOID EspFormatTriggerData( - _In_ PES_TRIGGER_DATA Data, - _Out_ PPH_STRING *Text - ) -{ - if (Data->Type == SERVICE_TRIGGER_DATA_TYPE_STRING) - { - // This check works for both normal strings and multistrings. - if (Data->String->Length != 0) - { - // Prepare the text for display by replacing null characters with spaces. - *Text = EspConvertNullsToSpaces(Data->String); - } - else - { - *Text = PhCreateString(L"(empty string)"); - } - } - else if (Data->Type == SERVICE_TRIGGER_DATA_TYPE_BINARY) - { - *Text = PhCreateString(L"(binary data)"); - } - else if (Data->Type == SERVICE_TRIGGER_DATA_TYPE_LEVEL) - { - *Text = PhFormatString(L"(level) %u", Data->Byte); - } - else if (Data->Type == SERVICE_TRIGGER_DATA_TYPE_KEYWORD_ANY) - { - *Text = PhFormatString(L"(keyword any) 0x%I64x", Data->UInt64); - } - else if (Data->Type == SERVICE_TRIGGER_DATA_TYPE_KEYWORD_ALL) - { - *Text = PhFormatString(L"(keyword all) 0x%I64x", Data->UInt64); - } - else - { - *Text = PhCreateString(L"(unknown type)"); - } -} - -INT_PTR CALLBACK EspServiceTriggerDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - PES_TRIGGER_CONTEXT context; - - if (uMsg == WM_INITDIALOG) - { - context = (PES_TRIGGER_CONTEXT)lParam; - SetProp(hwndDlg, L"Context", (HANDLE)context); - } - else - { - context = (PES_TRIGGER_CONTEXT)GetProp(hwndDlg, L"Context"); - - if (uMsg == WM_DESTROY) - RemoveProp(hwndDlg, L"Context"); - } - - if (!context) - return FALSE; - - switch (uMsg) - { - case WM_INITDIALOG: - { - HWND typeComboBox; - HWND actionComboBox; - HWND lvHandle; - ULONG i; - - context->LastSelectedType = 0; - - if (context->EditingInfo->Subtype) - context->LastCustomSubType = PhFormatGuid(context->EditingInfo->Subtype); - else - context->LastCustomSubType = PhReferenceEmptyString(); - - typeComboBox = GetDlgItem(hwndDlg, IDC_TYPE); - actionComboBox = GetDlgItem(hwndDlg, IDC_ACTION); - - for (i = 0; i < sizeof(TypeEntries) / sizeof(TYPE_ENTRY); i++) - { - ComboBox_AddString(typeComboBox, TypeEntries[i].Name); - - if (TypeEntries[i].Type == context->EditingInfo->Type) - { - PhSelectComboBoxString(typeComboBox, TypeEntries[i].Name, FALSE); - } - } - - ComboBox_AddString(actionComboBox, L"Start"); - ComboBox_AddString(actionComboBox, L"Stop"); - ComboBox_SetCurSel(actionComboBox, context->EditingInfo->Action == SERVICE_TRIGGER_ACTION_SERVICE_START ? 0 : 1); - - EspFixServiceTriggerControls(hwndDlg, context); - - if (context->EditingInfo->Type != SERVICE_TRIGGER_TYPE_CUSTOM) - { - for (i = 0; i < sizeof(SubTypeEntries) / sizeof(SUBTYPE_ENTRY); i++) - { - if ( - SubTypeEntries[i].Type == context->EditingInfo->Type && - SubTypeEntries[i].Guid && - context->EditingInfo->Subtype && - memcmp(SubTypeEntries[i].Guid, context->EditingInfo->Subtype, sizeof(GUID)) == 0 - ) - { - PhSelectComboBoxString(GetDlgItem(hwndDlg, IDC_SUBTYPE), SubTypeEntries[i].Name, FALSE); - break; - } - } - } - else - { - if (context->EditingInfo->Subtype) - { - PPH_STRING publisherName; - - // Try to select the publisher name in the subtype list. - publisherName = EspLookupEtwPublisherName(context->EditingInfo->Subtype); - PhSelectComboBoxString(GetDlgItem(hwndDlg, IDC_SUBTYPE), publisherName->Buffer, FALSE); - PhDereferenceObject(publisherName); - } - } - - // Call a second time since the state of the custom subtype text box may have changed. - EspFixServiceTriggerControls(hwndDlg, context); - - lvHandle = GetDlgItem(hwndDlg, IDC_LIST); - PhSetListViewStyle(lvHandle, FALSE, TRUE); - PhSetControlTheme(lvHandle, L"explorer"); - PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 280, L"Data"); - - if (context->EditingInfo->DataList) - { - for (i = 0; i < context->EditingInfo->DataList->Count; i++) - { - PES_TRIGGER_DATA data; - PPH_STRING text; - INT lvItemIndex; - - data = context->EditingInfo->DataList->Items[i]; - - EspFormatTriggerData(data, &text); - lvItemIndex = PhAddListViewItem(lvHandle, MAXINT, text->Buffer, data); - PhDereferenceObject(text); - } - } - - EnableWindow(GetDlgItem(hwndDlg, IDC_EDIT), FALSE); - EnableWindow(GetDlgItem(hwndDlg, IDC_DELETE), FALSE); - } - break; - case WM_DESTROY: - { - PhClearReference(&context->LastCustomSubType); - } - break; - case WM_COMMAND: - { - switch (LOWORD(wParam)) - { - case IDC_TYPE: - if (HIWORD(wParam) == CBN_SELCHANGE) - { - EspFixServiceTriggerControls(hwndDlg, context); - } - break; - case IDC_SUBTYPE: - if (HIWORD(wParam) == CBN_SELCHANGE) - { - EspFixServiceTriggerControls(hwndDlg, context); - } - break; - case IDC_NEW: - { - HWND lvHandle; - - lvHandle = GetDlgItem(hwndDlg, IDC_LIST); - context->EditingValue = PhReferenceEmptyString(); - - if (DialogBoxParam( - PluginInstance->DllBase, - MAKEINTRESOURCE(IDD_VALUE), - hwndDlg, - ValueDlgProc, - (LPARAM)context - ) == IDOK) - { - PES_TRIGGER_DATA data; - PPH_STRING text; - INT lvItemIndex; - - data = EspCreateTriggerData(NULL); - data->Type = SERVICE_TRIGGER_DATA_TYPE_STRING; - data->String = EspConvertNewLinesToNulls(context->EditingValue); - - if (!context->EditingInfo->DataList) - context->EditingInfo->DataList = PhCreateList(4); - - PhAddItemList(context->EditingInfo->DataList, data); - - EspFormatTriggerData(data, &text); - lvItemIndex = PhAddListViewItem(lvHandle, MAXINT, text->Buffer, data); - PhDereferenceObject(text); - } - - PhClearReference(&context->EditingValue); - } - break; - case IDC_EDIT: - { - HWND lvHandle; - INT lvItemIndex; - PES_TRIGGER_DATA data; - ULONG index; - - lvHandle = GetDlgItem(hwndDlg, IDC_LIST); - lvItemIndex = ListView_GetNextItem(lvHandle, -1, LVNI_SELECTED); - - if ( - lvItemIndex != -1 && PhGetListViewItemParam(lvHandle, lvItemIndex, (PVOID *)&data) && - data->Type == SERVICE_TRIGGER_DATA_TYPE_STRING // editing binary values is not supported - ) - { - index = PhFindItemList(context->EditingInfo->DataList, data); - - if (index != -1) - { - context->EditingValue = EspConvertNullsToNewLines(data->String); - - if (DialogBoxParam( - PluginInstance->DllBase, - MAKEINTRESOURCE(IDD_VALUE), - hwndDlg, - ValueDlgProc, - (LPARAM)context - ) == IDOK) - { - PPH_STRING text; - - PhMoveReference(&data->String, EspConvertNewLinesToNulls(context->EditingValue)); - - EspFormatTriggerData(data, &text); - PhSetListViewSubItem(lvHandle, lvItemIndex, 0, text->Buffer); - PhDereferenceObject(text); - } - - PhClearReference(&context->EditingValue); - } - } - } - break; - case IDC_DELETE: - { - HWND lvHandle; - INT lvItemIndex; - PES_TRIGGER_DATA data; - ULONG index; - - lvHandle = GetDlgItem(hwndDlg, IDC_LIST); - lvItemIndex = ListView_GetNextItem(lvHandle, -1, LVNI_SELECTED); - - if (lvItemIndex != -1 && PhGetListViewItemParam(lvHandle, lvItemIndex, (PVOID *)&data)) - { - index = PhFindItemList(context->EditingInfo->DataList, data); - - if (index != -1) - { - EspDestroyTriggerData(data); - PhRemoveItemList(context->EditingInfo->DataList, index); - PhRemoveListViewItem(lvHandle, lvItemIndex); - } - } - } - break; - case IDCANCEL: - EndDialog(hwndDlg, IDCANCEL); - break; - case IDOK: - { - PH_AUTO_POOL autoPool; - PPH_STRING typeString; - PPH_STRING subTypeString; - PPH_STRING customSubTypeString; - PPH_STRING actionString; - ULONG i; - - PhInitializeAutoPool(&autoPool); - - typeString = PhaGetDlgItemText(hwndDlg, IDC_TYPE); - subTypeString = PhaGetDlgItemText(hwndDlg, IDC_SUBTYPE); - customSubTypeString = PhaGetDlgItemText(hwndDlg, IDC_SUBTYPECUSTOM); - actionString = PhaGetDlgItemText(hwndDlg, IDC_ACTION); - - for (i = 0; i < sizeof(TypeEntries) / sizeof(TYPE_ENTRY); i++) - { - if (PhEqualStringZ(TypeEntries[i].Name, typeString->Buffer, FALSE)) - { - context->EditingInfo->Type = TypeEntries[i].Type; - break; - } - } - - if (!PhEqualString2(subTypeString, L"Custom", FALSE)) - { - if (context->EditingInfo->Type != SERVICE_TRIGGER_TYPE_CUSTOM) - { - for (i = 0; i < sizeof(SubTypeEntries) / sizeof(SUBTYPE_ENTRY); i++) - { - if ( - SubTypeEntries[i].Type == context->EditingInfo->Type && - PhEqualString2(subTypeString, SubTypeEntries[i].Name, FALSE) - ) - { - context->EditingInfo->SubtypeBuffer = *SubTypeEntries[i].Guid; - context->EditingInfo->Subtype = &context->EditingInfo->SubtypeBuffer; - break; - } - } - } - else - { - if (!EspLookupEtwPublisherGuid(&subTypeString->sr, &context->EditingInfo->SubtypeBuffer)) - { - PhShowError(hwndDlg, L"Unable to find the ETW publisher GUID."); - goto DoNotClose; - } - - context->EditingInfo->Subtype = &context->EditingInfo->SubtypeBuffer; - } - } - else - { - UNICODE_STRING guidString; - - PhStringRefToUnicodeString(&customSubTypeString->sr, &guidString); - - // Trim whitespace. - - while (guidString.Length != 0 && *guidString.Buffer == ' ') - { - guidString.Buffer++; - guidString.Length -= 2; - } - - while (guidString.Length != 0 && guidString.Buffer[guidString.Length / 2 - 1] == ' ') - { - guidString.Length -= 2; - } - - if (NT_SUCCESS(RtlGUIDFromString(&guidString, &context->EditingInfo->SubtypeBuffer))) - { - context->EditingInfo->Subtype = &context->EditingInfo->SubtypeBuffer; - } - else - { - PhShowError(hwndDlg, L"The custom subtype is invalid. Please ensure that the string is a valid GUID: \"{x-x-x-x-x}\"."); - goto DoNotClose; - } - } - - if (PhEqualString2(actionString, L"Start", FALSE)) - context->EditingInfo->Action = SERVICE_TRIGGER_ACTION_SERVICE_START; - else - context->EditingInfo->Action = SERVICE_TRIGGER_ACTION_SERVICE_STOP; - - if ( - context->EditingInfo->DataList && - context->EditingInfo->DataList->Count != 0 && - context->EditingInfo->Type != SERVICE_TRIGGER_TYPE_DEVICE_INTERFACE_ARRIVAL && - context->EditingInfo->Type != SERVICE_TRIGGER_TYPE_FIREWALL_PORT_EVENT && - context->EditingInfo->Type != SERVICE_TRIGGER_TYPE_NETWORK_ENDPOINT && - context->EditingInfo->Type != SERVICE_TRIGGER_TYPE_CUSTOM - ) - { - // This trigger has data items, but the trigger type doesn't allow them. - if (PhShowMessage( - hwndDlg, - MB_OKCANCEL | MB_ICONWARNING, - L"The trigger type \"%s\" does not allow data items to be configured. " - L"If you continue, they will be removed.", - typeString->Buffer - ) != IDOK) - { - goto DoNotClose; - } - - for (i = 0; i < context->EditingInfo->DataList->Count; i++) - { - EspDestroyTriggerData(context->EditingInfo->DataList->Items[i]); - } - - PhClearReference(&context->EditingInfo->DataList); - } - - EndDialog(hwndDlg, IDOK); - -DoNotClose: - PhDeleteAutoPool(&autoPool); - } - break; - } - } - break; - case WM_NOTIFY: - { - LPNMHDR header = (LPNMHDR)lParam; - HWND lvHandle; - - lvHandle = GetDlgItem(hwndDlg, IDC_LIST); - - switch (header->code) - { - case LVN_ITEMCHANGED: - { - if (header->hwndFrom == lvHandle) - { - if (ListView_GetSelectedCount(lvHandle) == 1) - { - PES_TRIGGER_DATA data = PhGetSelectedListViewItemParam(GetDlgItem(hwndDlg, IDC_LIST)); - - // Editing binary data is not supported. - EnableWindow(GetDlgItem(hwndDlg, IDC_EDIT), data && data->Type == SERVICE_TRIGGER_DATA_TYPE_STRING); - EnableWindow(GetDlgItem(hwndDlg, IDC_DELETE), TRUE); - } - else - { - EnableWindow(GetDlgItem(hwndDlg, IDC_EDIT), FALSE); - EnableWindow(GetDlgItem(hwndDlg, IDC_DELETE), FALSE); - } - } - } - break; - case NM_DBLCLK: - { - if (header->hwndFrom == lvHandle) - { - SendMessage(hwndDlg, WM_COMMAND, IDC_EDIT, 0); - } - } - break; - } - } - break; - } - - return FALSE; -} - -INT_PTR CALLBACK ValueDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - PES_TRIGGER_CONTEXT context; - - if (uMsg == WM_INITDIALOG) - { - context = (PES_TRIGGER_CONTEXT)lParam; - SetProp(hwndDlg, L"Context", (HANDLE)context); - } - else - { - context = (PES_TRIGGER_CONTEXT)GetProp(hwndDlg, L"Context"); - - if (uMsg == WM_DESTROY) - RemoveProp(hwndDlg, L"Context"); - } - - if (!context) - return FALSE; - - switch (uMsg) - { - case WM_INITDIALOG: - { - SetDlgItemText(hwndDlg, IDC_VALUES, context->EditingValue->Buffer); - SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hwndDlg, IDC_VALUES), TRUE); - Edit_SetSel(GetDlgItem(hwndDlg, IDC_VALUES), 0, -1); - } - break; - case WM_COMMAND: - { - switch (LOWORD(wParam)) - { - case IDCANCEL: - EndDialog(hwndDlg, IDCANCEL); - break; - case IDOK: - PhMoveReference(&context->EditingValue, PhGetWindowText(GetDlgItem(hwndDlg, IDC_VALUES))); - EndDialog(hwndDlg, IDOK); - break; - } - } - break; - } - - return FALSE; -} +/* + * Process Hacker Extended Services - + * trigger editor + * + * Copyright (C) 2011-2015 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include "extsrv.h" + +typedef struct _ES_TRIGGER_DATA +{ + ULONG Type; + union + { + PPH_STRING String; + struct + { + PVOID Binary; + ULONG BinaryLength; + }; + UCHAR Byte; + ULONG64 UInt64; + }; +} ES_TRIGGER_DATA, *PES_TRIGGER_DATA; + +typedef struct _ES_TRIGGER_INFO +{ + ULONG Type; + PGUID Subtype; + ULONG Action; + PPH_LIST DataList; + GUID SubtypeBuffer; +} ES_TRIGGER_INFO, *PES_TRIGGER_INFO; + +typedef struct _ES_TRIGGER_CONTEXT +{ + PPH_SERVICE_ITEM ServiceItem; + HWND WindowHandle; + HWND TriggersLv; + BOOLEAN Dirty; + ULONG InitialNumberOfTriggers; + PPH_LIST InfoList; + + // Trigger dialog box + PES_TRIGGER_INFO EditingInfo; + ULONG LastSelectedType; + PPH_STRING LastCustomSubType; + + // Value dialog box + PPH_STRING EditingValue; +} ES_TRIGGER_CONTEXT, *PES_TRIGGER_CONTEXT; + +typedef struct _TYPE_ENTRY +{ + ULONG Type; + PWSTR Name; +} TYPE_ENTRY, PTYPE_ENTRY; + +typedef struct _SUBTYPE_ENTRY +{ + ULONG Type; + PGUID Guid; + PWSTR Name; +} SUBTYPE_ENTRY, PSUBTYPE_ENTRY; + +typedef struct _ETW_PUBLISHER_ENTRY +{ + PPH_STRING PublisherName; + GUID Guid; +} ETW_PUBLISHER_ENTRY, *PETW_PUBLISHER_ENTRY; + +INT_PTR CALLBACK EspServiceTriggerDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +INT_PTR CALLBACK ValueDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +static GUID NetworkManagerFirstIpAddressArrivalGuid = { 0x4f27f2de, 0x14e2, 0x430b, { 0xa5, 0x49, 0x7c, 0xd4, 0x8c, 0xbc, 0x82, 0x45 } }; +static GUID NetworkManagerLastIpAddressRemovalGuid = { 0xcc4ba62a, 0x162e, 0x4648, { 0x84, 0x7a, 0xb6, 0xbd, 0xf9, 0x93, 0xe3, 0x35 } }; +static GUID DomainJoinGuid = { 0x1ce20aba, 0x9851, 0x4421, { 0x94, 0x30, 0x1d, 0xde, 0xb7, 0x66, 0xe8, 0x09 } }; +static GUID DomainLeaveGuid = { 0xddaf516e, 0x58c2, 0x4866, { 0x95, 0x74, 0xc3, 0xb6, 0x15, 0xd4, 0x2e, 0xa1 } }; +static GUID FirewallPortOpenGuid = { 0xb7569e07, 0x8421, 0x4ee0, { 0xad, 0x10, 0x86, 0x91, 0x5a, 0xfd, 0xad, 0x09 } }; +static GUID FirewallPortCloseGuid = { 0xa144ed38, 0x8e12, 0x4de4, { 0x9d, 0x96, 0xe6, 0x47, 0x40, 0xb1, 0xa5, 0x24 } }; +static GUID MachinePolicyPresentGuid = { 0x659fcae6, 0x5bdb, 0x4da9, { 0xb1, 0xff, 0xca, 0x2a, 0x17, 0x8d, 0x46, 0xe0 } }; +static GUID UserPolicyPresentGuid = { 0x54fb46c8, 0xf089, 0x464c, { 0xb1, 0xfd, 0x59, 0xd1, 0xb6, 0x2c, 0x3b, 0x50 } }; +static GUID RpcInterfaceEventGuid = { 0xbc90d167, 0x9470, 0x4139, { 0xa9, 0xba, 0xbe, 0x0b, 0xbb, 0xf5, 0xb7, 0x4d } }; +static GUID NamedPipeEventGuid = { 0x1f81d131, 0x3fac, 0x4537, { 0x9e, 0x0c, 0x7e, 0x7b, 0x0c, 0x2f, 0x4b, 0x55 } }; +static GUID SubTypeUnknownGuid; // dummy + +static TYPE_ENTRY TypeEntries[] = +{ + { SERVICE_TRIGGER_TYPE_DEVICE_INTERFACE_ARRIVAL, L"Device interface arrival" }, + { SERVICE_TRIGGER_TYPE_IP_ADDRESS_AVAILABILITY, L"IP address availability" }, + { SERVICE_TRIGGER_TYPE_DOMAIN_JOIN, L"Domain join" }, + { SERVICE_TRIGGER_TYPE_FIREWALL_PORT_EVENT, L"Firewall port event" }, + { SERVICE_TRIGGER_TYPE_GROUP_POLICY, L"Group policy" }, + { SERVICE_TRIGGER_TYPE_NETWORK_ENDPOINT, L"Network endpoint" }, + { SERVICE_TRIGGER_TYPE_CUSTOM_SYSTEM_STATE_CHANGE, L"Custom system state change" }, + { SERVICE_TRIGGER_TYPE_CUSTOM, L"Custom" } +}; + +static SUBTYPE_ENTRY SubTypeEntries[] = +{ + { SERVICE_TRIGGER_TYPE_IP_ADDRESS_AVAILABILITY, NULL, L"IP address" }, + { SERVICE_TRIGGER_TYPE_IP_ADDRESS_AVAILABILITY, &NetworkManagerFirstIpAddressArrivalGuid, L"IP address: First arrival" }, + { SERVICE_TRIGGER_TYPE_IP_ADDRESS_AVAILABILITY, &NetworkManagerLastIpAddressRemovalGuid, L"IP address: Last removal" }, + { SERVICE_TRIGGER_TYPE_IP_ADDRESS_AVAILABILITY, &SubTypeUnknownGuid, L"IP address: Unknown" }, + { SERVICE_TRIGGER_TYPE_DOMAIN_JOIN, NULL, L"Domain" }, + { SERVICE_TRIGGER_TYPE_DOMAIN_JOIN, &DomainJoinGuid, L"Domain: Join" }, + { SERVICE_TRIGGER_TYPE_DOMAIN_JOIN, &DomainLeaveGuid, L"Domain: Leave" }, + { SERVICE_TRIGGER_TYPE_DOMAIN_JOIN, &SubTypeUnknownGuid, L"Domain: Unknown" }, + { SERVICE_TRIGGER_TYPE_FIREWALL_PORT_EVENT, NULL, L"Firewall port" }, + { SERVICE_TRIGGER_TYPE_FIREWALL_PORT_EVENT, &FirewallPortOpenGuid, L"Firewall port: Open" }, + { SERVICE_TRIGGER_TYPE_FIREWALL_PORT_EVENT, &FirewallPortCloseGuid, L"Firewall port: Close" }, + { SERVICE_TRIGGER_TYPE_FIREWALL_PORT_EVENT, &SubTypeUnknownGuid, L"Firewall port: Unknown" }, + { SERVICE_TRIGGER_TYPE_GROUP_POLICY, NULL, L"Group policy change" }, + { SERVICE_TRIGGER_TYPE_GROUP_POLICY, &MachinePolicyPresentGuid, L"Group policy change: Machine" }, + { SERVICE_TRIGGER_TYPE_GROUP_POLICY, &UserPolicyPresentGuid, L"Group policy change: User" }, + { SERVICE_TRIGGER_TYPE_GROUP_POLICY, &SubTypeUnknownGuid, L"Group policy change: Unknown" }, + { SERVICE_TRIGGER_TYPE_NETWORK_ENDPOINT, NULL, L"Network endpoint" }, + { SERVICE_TRIGGER_TYPE_NETWORK_ENDPOINT, &RpcInterfaceEventGuid, L"Network endpoint: RPC interface" }, + { SERVICE_TRIGGER_TYPE_NETWORK_ENDPOINT, &NamedPipeEventGuid, L"Network endpoint: Named pipe" }, + { SERVICE_TRIGGER_TYPE_NETWORK_ENDPOINT, &SubTypeUnknownGuid, L"Network endpoint: Unknown" } +}; + +static PH_STRINGREF PublishersKeyName = PH_STRINGREF_INIT(L"Software\\Microsoft\\Windows\\CurrentVersion\\WINEVT\\Publishers\\"); + +PES_TRIGGER_DATA EspCreateTriggerData( + _In_opt_ PSERVICE_TRIGGER_SPECIFIC_DATA_ITEM DataItem + ) +{ + PES_TRIGGER_DATA data; + + data = PhAllocate(sizeof(ES_TRIGGER_DATA)); + memset(data, 0, sizeof(ES_TRIGGER_DATA)); + + if (DataItem) + { + data->Type = DataItem->dwDataType; + + if (data->Type == SERVICE_TRIGGER_DATA_TYPE_STRING) + { + if (DataItem->pData && DataItem->cbData >= 2) + data->String = PhCreateStringEx((PWSTR)DataItem->pData, DataItem->cbData - 2); // exclude final null terminator + else + data->String = PhReferenceEmptyString(); + } + else if (data->Type == SERVICE_TRIGGER_DATA_TYPE_BINARY) + { + data->BinaryLength = DataItem->cbData; + data->Binary = PhAllocateCopy(DataItem->pData, DataItem->cbData); + } + else if (data->Type == SERVICE_TRIGGER_DATA_TYPE_LEVEL) + { + if (DataItem->cbData == sizeof(UCHAR)) + data->Byte = *(PUCHAR)DataItem->pData; + } + else if (data->Type == SERVICE_TRIGGER_DATA_TYPE_KEYWORD_ANY || data->Type == SERVICE_TRIGGER_DATA_TYPE_KEYWORD_ALL) + { + if (DataItem->cbData == sizeof(ULONG64)) + data->UInt64 = *(PULONG64)DataItem->pData; + } + } + + return data; +} + +PES_TRIGGER_DATA EspCloneTriggerData( + _In_ PES_TRIGGER_DATA Data + ) +{ + PES_TRIGGER_DATA newData; + + newData = PhAllocateCopy(Data, sizeof(ES_TRIGGER_DATA)); + + if (newData->Type == SERVICE_TRIGGER_DATA_TYPE_STRING) + { + if (newData->String) + newData->String = PhDuplicateString(newData->String); + } + else if (newData->Type == SERVICE_TRIGGER_DATA_TYPE_BINARY) + { + if (newData->Binary) + newData->Binary = PhAllocateCopy(newData->Binary, newData->BinaryLength); + } + + return newData; +} + +VOID EspDestroyTriggerData( + _In_ PES_TRIGGER_DATA Data + ) +{ + if (Data->Type == SERVICE_TRIGGER_DATA_TYPE_STRING) + { + if (Data->String) + PhDereferenceObject(Data->String); + } + else if (Data->Type == SERVICE_TRIGGER_DATA_TYPE_BINARY) + { + if (Data->Binary) + PhFree(Data->Binary); + } + + PhFree(Data); +} + +PES_TRIGGER_INFO EspCreateTriggerInfo( + _In_opt_ PSERVICE_TRIGGER Trigger + ) +{ + PES_TRIGGER_INFO info; + + info = PhAllocate(sizeof(ES_TRIGGER_INFO)); + memset(info, 0, sizeof(ES_TRIGGER_INFO)); + + if (Trigger) + { + info->Type = Trigger->dwTriggerType; + + if (Trigger->pTriggerSubtype) + { + info->SubtypeBuffer = *Trigger->pTriggerSubtype; + info->Subtype = &info->SubtypeBuffer; + } + + info->Action = Trigger->dwAction; + + if ( + info->Type == SERVICE_TRIGGER_TYPE_CUSTOM || + info->Type == SERVICE_TRIGGER_TYPE_DEVICE_INTERFACE_ARRIVAL || + info->Type == SERVICE_TRIGGER_TYPE_FIREWALL_PORT_EVENT || + info->Type == SERVICE_TRIGGER_TYPE_NETWORK_ENDPOINT + ) + { + ULONG i; + + info->DataList = PhCreateList(Trigger->cDataItems); + + for (i = 0; i < Trigger->cDataItems; i++) + { + PhAddItemList(info->DataList, EspCreateTriggerData(&Trigger->pDataItems[i])); + } + } + } + + return info; +} + +PES_TRIGGER_INFO EspCloneTriggerInfo( + _In_ PES_TRIGGER_INFO Info + ) +{ + PES_TRIGGER_INFO newInfo; + + newInfo = PhAllocateCopy(Info, sizeof(ES_TRIGGER_INFO)); + + if (newInfo->Subtype == &Info->SubtypeBuffer) + newInfo->Subtype = &newInfo->SubtypeBuffer; + + if (newInfo->DataList) + { + ULONG i; + + newInfo->DataList = PhCreateList(Info->DataList->AllocatedCount); + newInfo->DataList->Count = Info->DataList->Count; + + for (i = 0; i < Info->DataList->Count; i++) + newInfo->DataList->Items[i] = EspCloneTriggerData(Info->DataList->Items[i]); + } + + return newInfo; +} + +VOID EspDestroyTriggerInfo( + _In_ PES_TRIGGER_INFO Info + ) +{ + if (Info->DataList) + { + ULONG i; + + for (i = 0; i < Info->DataList->Count; i++) + { + EspDestroyTriggerData(Info->DataList->Items[i]); + } + + PhDereferenceObject(Info->DataList); + } + + PhFree(Info); +} + +VOID EspClearTriggerInfoList( + _In_ PPH_LIST List + ) +{ + ULONG i; + + for (i = 0; i < List->Count; i++) + { + EspDestroyTriggerInfo(List->Items[i]); + } + + PhClearList(List); +} + +struct _ES_TRIGGER_CONTEXT *EsCreateServiceTriggerContext( + _In_ PPH_SERVICE_ITEM ServiceItem, + _In_ HWND WindowHandle, + _In_ HWND TriggersLv + ) +{ + PES_TRIGGER_CONTEXT context; + + context = PhAllocate(sizeof(ES_TRIGGER_CONTEXT)); + memset(context, 0, sizeof(ES_TRIGGER_CONTEXT)); + context->ServiceItem = ServiceItem; + context->WindowHandle = WindowHandle; + context->TriggersLv = TriggersLv; + context->InfoList = PhCreateList(4); + + PhSetListViewStyle(TriggersLv, FALSE, TRUE); + PhSetControlTheme(TriggersLv, L"explorer"); + PhAddListViewColumn(TriggersLv, 0, 0, 0, LVCFMT_LEFT, 300, L"Trigger"); + PhAddListViewColumn(TriggersLv, 1, 1, 1, LVCFMT_LEFT, 60, L"Action"); + PhSetExtendedListView(TriggersLv); + + EnableWindow(GetDlgItem(WindowHandle, IDC_EDIT), FALSE); + EnableWindow(GetDlgItem(WindowHandle, IDC_DELETE), FALSE); + + return context; +} + +VOID EsDestroyServiceTriggerContext( + _In_ struct _ES_TRIGGER_CONTEXT *Context + ) +{ + ULONG i; + + for (i = 0; i < Context->InfoList->Count; i++) + { + EspDestroyTriggerInfo(Context->InfoList->Items[i]); + } + + PhDereferenceObject(Context->InfoList); + PhFree(Context); +} + +PPH_STRING EspLookupEtwPublisherName( + _In_ PGUID Guid + ) +{ + PPH_STRING guidString; + PPH_STRING keyName; + HANDLE keyHandle; + PPH_STRING publisherName = NULL; + + // Copied from ProcessHacker\hndlinfo.c. + + guidString = PhFormatGuid(Guid); + + keyName = PhConcatStringRef2(&PublishersKeyName, &guidString->sr); + + if (NT_SUCCESS(PhOpenKey( + &keyHandle, + KEY_READ, + PH_KEY_LOCAL_MACHINE, + &keyName->sr, + 0 + ))) + { + publisherName = PhQueryRegistryString(keyHandle, NULL); + + if (publisherName && publisherName->Length == 0) + { + PhDereferenceObject(publisherName); + publisherName = NULL; + } + + NtClose(keyHandle); + } + + PhDereferenceObject(keyName); + + if (publisherName) + { + PhDereferenceObject(guidString); + return publisherName; + } + else + { + return guidString; + } +} + +BOOLEAN EspEnumerateEtwPublishers( + _Out_ PETW_PUBLISHER_ENTRY *Entries, + _Out_ PULONG NumberOfEntries + ) +{ + NTSTATUS status; + HANDLE publishersKeyHandle; + ULONG index; + PKEY_BASIC_INFORMATION buffer; + ULONG bufferSize; + PETW_PUBLISHER_ENTRY entries; + ULONG numberOfEntries; + ULONG allocatedEntries; + + if (!NT_SUCCESS(PhOpenKey( + &publishersKeyHandle, + KEY_READ, + PH_KEY_LOCAL_MACHINE, + &PublishersKeyName, + 0 + ))) + { + return FALSE; + } + + numberOfEntries = 0; + allocatedEntries = 256; + entries = PhAllocate(allocatedEntries * sizeof(ETW_PUBLISHER_ENTRY)); + + index = 0; + bufferSize = 0x100; + buffer = PhAllocate(0x100); + + while (TRUE) + { + status = NtEnumerateKey( + publishersKeyHandle, + index, + KeyBasicInformation, + buffer, + bufferSize, + &bufferSize + ); + + if (NT_SUCCESS(status)) + { + UNICODE_STRING nameUs; + PH_STRINGREF name; + HANDLE keyHandle; + GUID guid; + PPH_STRING publisherName; + + nameUs.Buffer = buffer->Name; + nameUs.Length = (USHORT)buffer->NameLength; + name.Buffer = buffer->Name; + name.Length = buffer->NameLength; + + // Make sure this is a valid publisher key. + if (NT_SUCCESS(RtlGUIDFromString(&nameUs, &guid))) + { + if (NT_SUCCESS(PhOpenKey( + &keyHandle, + KEY_READ, + publishersKeyHandle, + &name, + 0 + ))) + { + publisherName = PhQueryRegistryString(keyHandle, NULL); + + if (publisherName) + { + if (publisherName->Length != 0) + { + PETW_PUBLISHER_ENTRY entry; + + if (numberOfEntries == allocatedEntries) + { + allocatedEntries *= 2; + entries = PhReAllocate(entries, allocatedEntries * sizeof(ETW_PUBLISHER_ENTRY)); + } + + entry = &entries[numberOfEntries++]; + entry->PublisherName = publisherName; + entry->Guid = guid; + } + else + { + PhDereferenceObject(publisherName); + } + } + + NtClose(keyHandle); + } + } + + index++; + } + else if (status == STATUS_NO_MORE_ENTRIES) + { + break; + } + else if (status == STATUS_BUFFER_OVERFLOW || status == STATUS_BUFFER_TOO_SMALL) + { + PhFree(buffer); + buffer = PhAllocate(bufferSize); + } + else + { + break; + } + } + + PhFree(buffer); + NtClose(publishersKeyHandle); + + *Entries = entries; + *NumberOfEntries = numberOfEntries; + + return TRUE; +} + +BOOLEAN EspLookupEtwPublisherGuid( + _In_ PPH_STRINGREF PublisherName, + _Out_ PGUID Guid + ) +{ + BOOLEAN result; + PETW_PUBLISHER_ENTRY entries; + ULONG numberOfEntries; + ULONG i; + + if (!EspEnumerateEtwPublishers(&entries, &numberOfEntries)) + return FALSE; + + result = FALSE; + + for (i = 0; i < numberOfEntries; i++) + { + if (!result && PhEqualStringRef(&entries[i].PublisherName->sr, PublisherName, TRUE)) + { + *Guid = entries[i].Guid; + result = TRUE; + } + + PhDereferenceObject(entries[i].PublisherName); + } + + PhFree(entries); + + return result; +} + +VOID EspFormatTriggerInfo( + _In_ PES_TRIGGER_INFO Info, + _Out_ PWSTR *TriggerString, + _Out_ PWSTR *ActionString, + _Out_ PPH_STRING *StringUsed + ) +{ + PPH_STRING stringUsed = NULL; + PWSTR triggerString = NULL; + PWSTR actionString; + ULONG i; + BOOLEAN typeFound; + BOOLEAN subTypeFound; + + switch (Info->Type) + { + case SERVICE_TRIGGER_TYPE_DEVICE_INTERFACE_ARRIVAL: + { + PPH_STRING guidString; + + if (!Info->Subtype) + { + triggerString = L"Device interface arrival"; + } + else + { + guidString = PhFormatGuid(Info->Subtype); + stringUsed = PhConcatStrings2(L"Device interface arrival: ", guidString->Buffer); + triggerString = stringUsed->Buffer; + } + } + break; + case SERVICE_TRIGGER_TYPE_CUSTOM_SYSTEM_STATE_CHANGE: + { + PPH_STRING guidString; + + if (!Info->Subtype) + { + triggerString = L"Custom system state change"; + } + else + { + guidString = PhFormatGuid(Info->Subtype); + stringUsed = PhConcatStrings2(L"Custom system state change: ", guidString->Buffer); + triggerString = stringUsed->Buffer; + } + } + break; + case SERVICE_TRIGGER_TYPE_CUSTOM: + { + if (Info->Subtype) + { + PPH_STRING publisherName; + + // Try to lookup the publisher name from the GUID. + publisherName = EspLookupEtwPublisherName(Info->Subtype); + stringUsed = PhConcatStrings2(L"Custom: ", publisherName->Buffer); + PhDereferenceObject(publisherName); + triggerString = stringUsed->Buffer; + } + else + { + triggerString = L"Custom"; + } + } + break; + default: + { + typeFound = FALSE; + subTypeFound = FALSE; + + for (i = 0; i < sizeof(SubTypeEntries) / sizeof(SUBTYPE_ENTRY); i++) + { + if (SubTypeEntries[i].Type == Info->Type) + { + typeFound = TRUE; + + if (!Info->Subtype && !SubTypeEntries[i].Guid) + { + subTypeFound = TRUE; + triggerString = SubTypeEntries[i].Name; + break; + } + else if (Info->Subtype && SubTypeEntries[i].Guid && memcmp(Info->Subtype, SubTypeEntries[i].Guid, sizeof(GUID)) == 0) + { + subTypeFound = TRUE; + triggerString = SubTypeEntries[i].Name; + break; + } + else if (!subTypeFound && SubTypeEntries[i].Guid == &SubTypeUnknownGuid) + { + triggerString = SubTypeEntries[i].Name; + break; + } + } + } + + if (!typeFound) + { + triggerString = L"Unknown"; + } + } + break; + } + + switch (Info->Action) + { + case SERVICE_TRIGGER_ACTION_SERVICE_START: + actionString = L"Start"; + break; + case SERVICE_TRIGGER_ACTION_SERVICE_STOP: + actionString = L"Stop"; + break; + default: + actionString = L"Unknown"; + break; + } + + *TriggerString = triggerString; + *ActionString = actionString; + *StringUsed = stringUsed; +} + +VOID EsLoadServiceTriggerInfo( + _In_ struct _ES_TRIGGER_CONTEXT *Context, + _In_ SC_HANDLE ServiceHandle + ) +{ + PSERVICE_TRIGGER_INFO triggerInfo; + ULONG i; + + EspClearTriggerInfoList(Context->InfoList); + + if (triggerInfo = PhQueryServiceVariableSize(ServiceHandle, SERVICE_CONFIG_TRIGGER_INFO)) + { + for (i = 0; i < triggerInfo->cTriggers; i++) + { + PSERVICE_TRIGGER trigger = &triggerInfo->pTriggers[i]; + PES_TRIGGER_INFO info; + PWSTR triggerString; + PWSTR actionString; + PPH_STRING stringUsed; + INT lvItemIndex; + + info = EspCreateTriggerInfo(trigger); + PhAddItemList(Context->InfoList, info); + + EspFormatTriggerInfo(info, &triggerString, &actionString, &stringUsed); + + lvItemIndex = PhAddListViewItem(Context->TriggersLv, MAXINT, triggerString, info); + PhSetListViewSubItem(Context->TriggersLv, lvItemIndex, 1, actionString); + + if (stringUsed) + PhDereferenceObject(stringUsed); + } + + Context->InitialNumberOfTriggers = triggerInfo->cTriggers; + + ExtendedListView_SortItems(Context->TriggersLv); + + PhFree(triggerInfo); + } +} + +BOOLEAN EsSaveServiceTriggerInfo( + _In_ struct _ES_TRIGGER_CONTEXT *Context, + _Out_ PULONG Win32Result + ) +{ + BOOLEAN result = TRUE; + PH_AUTO_POOL autoPool; + SC_HANDLE serviceHandle; + SERVICE_TRIGGER_INFO triggerInfo; + ULONG i; + ULONG j; + + if (!Context->Dirty) + return TRUE; + + // Do not try to change trigger information if we didn't have any triggers before and we don't + // have any now. ChangeServiceConfig2 returns an error in this situation. + if (Context->InitialNumberOfTriggers == 0 && Context->InfoList->Count == 0) + return TRUE; + + PhInitializeAutoPool(&autoPool); + + memset(&triggerInfo, 0, sizeof(SERVICE_TRIGGER_INFO)); + triggerInfo.cTriggers = Context->InfoList->Count; + + // pTriggers needs to be NULL when there are no triggers. + if (Context->InfoList->Count != 0) + { + triggerInfo.pTriggers = PH_AUTO(PhCreateAlloc(Context->InfoList->Count * sizeof(SERVICE_TRIGGER))); + memset(triggerInfo.pTriggers, 0, Context->InfoList->Count * sizeof(SERVICE_TRIGGER)); + + for (i = 0; i < Context->InfoList->Count; i++) + { + PSERVICE_TRIGGER trigger = &triggerInfo.pTriggers[i]; + PES_TRIGGER_INFO info = Context->InfoList->Items[i]; + + trigger->dwTriggerType = info->Type; + trigger->dwAction = info->Action; + trigger->pTriggerSubtype = info->Subtype; + + if (info->DataList && info->DataList->Count != 0) + { + trigger->cDataItems = info->DataList->Count; + trigger->pDataItems = PH_AUTO(PhCreateAlloc(info->DataList->Count * sizeof(SERVICE_TRIGGER_SPECIFIC_DATA_ITEM))); + + for (j = 0; j < info->DataList->Count; j++) + { + PSERVICE_TRIGGER_SPECIFIC_DATA_ITEM dataItem = &trigger->pDataItems[j]; + PES_TRIGGER_DATA data = info->DataList->Items[j]; + + dataItem->dwDataType = data->Type; + + if (data->Type == SERVICE_TRIGGER_DATA_TYPE_STRING) + { + dataItem->cbData = (ULONG)data->String->Length + 2; // include null terminator + dataItem->pData = (PBYTE)data->String->Buffer; + } + else if (data->Type == SERVICE_TRIGGER_DATA_TYPE_BINARY) + { + dataItem->cbData = data->BinaryLength; + dataItem->pData = data->Binary; + } + else if (data->Type == SERVICE_TRIGGER_DATA_TYPE_LEVEL) + { + dataItem->cbData = sizeof(UCHAR); + dataItem->pData = (PBYTE)&data->Byte; + } + else if (data->Type == SERVICE_TRIGGER_DATA_TYPE_KEYWORD_ANY || data->Type == SERVICE_TRIGGER_DATA_TYPE_KEYWORD_ALL) + { + dataItem->cbData = sizeof(ULONG64); + dataItem->pData = (PBYTE)&data->UInt64; + } + } + } + } + } + + if (serviceHandle = PhOpenService(Context->ServiceItem->Name->Buffer, SERVICE_CHANGE_CONFIG)) + { + if (!ChangeServiceConfig2(serviceHandle, SERVICE_CONFIG_TRIGGER_INFO, &triggerInfo)) + { + result = FALSE; + *Win32Result = GetLastError(); + } + + CloseServiceHandle(serviceHandle); + } + else + { + result = FALSE; + *Win32Result = GetLastError(); + + if (*Win32Result == ERROR_ACCESS_DENIED && !PhGetOwnTokenAttributes().Elevated) + { + // Elevate using phsvc. + if (PhUiConnectToPhSvc(Context->WindowHandle, FALSE)) + { + NTSTATUS status; + + result = TRUE; + + if (!NT_SUCCESS(status = PhSvcCallChangeServiceConfig2(Context->ServiceItem->Name->Buffer, + SERVICE_CONFIG_TRIGGER_INFO, &triggerInfo))) + { + result = FALSE; + *Win32Result = PhNtStatusToDosError(status); + } + + PhUiDisconnectFromPhSvc(); + } + else + { + // User cancelled elevation. + *Win32Result = ERROR_CANCELLED; + } + } + } + + PhDeleteAutoPool(&autoPool); + + return result; +} + +LOGICAL EspSetListViewItemParam( + _In_ HWND ListViewHandle, + _In_ INT Index, + _In_ PVOID Param + ) +{ + LVITEM item; + + item.mask = LVIF_PARAM; + item.iItem = Index; + item.iSubItem = 0; + item.lParam = (LPARAM)Param; + + return ListView_SetItem(ListViewHandle, &item); +} + +VOID EsHandleEventServiceTrigger( + _In_ struct _ES_TRIGGER_CONTEXT *Context, + _In_ ULONG Event + ) +{ + switch (Event) + { + case ES_TRIGGER_EVENT_NEW: + { + Context->EditingInfo = EspCreateTriggerInfo(NULL); + Context->EditingInfo->Type = SERVICE_TRIGGER_TYPE_IP_ADDRESS_AVAILABILITY; + Context->EditingInfo->SubtypeBuffer = NetworkManagerFirstIpAddressArrivalGuid; + Context->EditingInfo->Subtype = &Context->EditingInfo->SubtypeBuffer; + Context->EditingInfo->Action = SERVICE_TRIGGER_ACTION_SERVICE_START; + + if (DialogBoxParam( + PluginInstance->DllBase, + MAKEINTRESOURCE(IDD_SRVTRIGGER), + Context->WindowHandle, + EspServiceTriggerDlgProc, + (LPARAM)Context + ) == IDOK) + { + PWSTR triggerString; + PWSTR actionString; + PPH_STRING stringUsed; + INT lvItemIndex; + + Context->Dirty = TRUE; + PhAddItemList(Context->InfoList, Context->EditingInfo); + + EspFormatTriggerInfo(Context->EditingInfo, &triggerString, &actionString, &stringUsed); + + lvItemIndex = PhAddListViewItem(Context->TriggersLv, MAXINT, triggerString, Context->EditingInfo); + PhSetListViewSubItem(Context->TriggersLv, lvItemIndex, 1, actionString); + + if (stringUsed) + PhDereferenceObject(stringUsed); + } + else + { + EspDestroyTriggerInfo(Context->EditingInfo); + } + + Context->EditingInfo = NULL; + } + break; + case ES_TRIGGER_EVENT_EDIT: + { + INT lvItemIndex; + PES_TRIGGER_INFO info; + ULONG index; + + lvItemIndex = ListView_GetNextItem(Context->TriggersLv, -1, LVNI_SELECTED); + + if (lvItemIndex != -1 && PhGetListViewItemParam(Context->TriggersLv, lvItemIndex, (PVOID *)&info)) + { + index = PhFindItemList(Context->InfoList, info); + + if (index != -1) + { + Context->EditingInfo = EspCloneTriggerInfo(info); + + if (DialogBoxParam( + PluginInstance->DllBase, + MAKEINTRESOURCE(IDD_SRVTRIGGER), + Context->WindowHandle, + EspServiceTriggerDlgProc, + (LPARAM)Context + ) == IDOK) + { + PWSTR triggerString; + PWSTR actionString; + PPH_STRING stringUsed; + + Context->Dirty = TRUE; + EspDestroyTriggerInfo(Context->InfoList->Items[index]); + Context->InfoList->Items[index] = Context->EditingInfo; + + EspFormatTriggerInfo(Context->EditingInfo, &triggerString, &actionString, &stringUsed); + PhSetListViewSubItem(Context->TriggersLv, lvItemIndex, 0, triggerString); + PhSetListViewSubItem(Context->TriggersLv, lvItemIndex, 1, actionString); + + if (stringUsed) + PhDereferenceObject(stringUsed); + + EspSetListViewItemParam(Context->TriggersLv, lvItemIndex, Context->EditingInfo); + } + else + { + EspDestroyTriggerInfo(Context->EditingInfo); + } + + Context->EditingInfo = NULL; + } + } + } + break; + case ES_TRIGGER_EVENT_DELETE: + { + INT lvItemIndex; + PES_TRIGGER_INFO info; + ULONG index; + + lvItemIndex = ListView_GetNextItem(Context->TriggersLv, -1, LVNI_SELECTED); + + if (lvItemIndex != -1 && PhGetListViewItemParam(Context->TriggersLv, lvItemIndex, (PVOID *)&info)) + { + index = PhFindItemList(Context->InfoList, info); + + if (index != -1) + { + EspDestroyTriggerInfo(info); + PhRemoveItemList(Context->InfoList, index); + PhRemoveListViewItem(Context->TriggersLv, lvItemIndex); + } + } + + Context->Dirty = TRUE; + } + break; + case ES_TRIGGER_EVENT_SELECTIONCHANGED: + { + ULONG selectedCount; + + selectedCount = ListView_GetSelectedCount(Context->TriggersLv); + + EnableWindow(GetDlgItem(Context->WindowHandle, IDC_EDIT), selectedCount == 1); + EnableWindow(GetDlgItem(Context->WindowHandle, IDC_DELETE), selectedCount == 1); + } + break; + } +} + +ULONG EspTriggerTypeStringToInteger( + _In_ PWSTR String + ) +{ + ULONG i; + + for (i = 0; i < sizeof(TypeEntries) / sizeof(TYPE_ENTRY); i++) + { + if (PhEqualStringZ(TypeEntries[i].Name, String, FALSE)) + return TypeEntries[i].Type; + } + + return 0; +} + +static int __cdecl EtwPublisherByNameCompareFunction( + _In_ const void *elem1, + _In_ const void *elem2 + ) +{ + PETW_PUBLISHER_ENTRY entry1 = (PETW_PUBLISHER_ENTRY)elem1; + PETW_PUBLISHER_ENTRY entry2 = (PETW_PUBLISHER_ENTRY)elem2; + + return PhCompareString(entry1->PublisherName, entry2->PublisherName, TRUE); +} + +VOID EspFixServiceTriggerControls( + _In_ HWND hwndDlg, + _In_ PES_TRIGGER_CONTEXT Context + ) +{ + HWND typeComboBox; + HWND subTypeComboBox; + ULONG i; + PPH_STRING selectedTypeString; + ULONG type; + PPH_STRING selectedSubTypeString; + + typeComboBox = GetDlgItem(hwndDlg, IDC_TYPE); + subTypeComboBox = GetDlgItem(hwndDlg, IDC_SUBTYPE); + + selectedTypeString = PhGetWindowText(typeComboBox); + type = EspTriggerTypeStringToInteger(selectedTypeString->Buffer); + PhDereferenceObject(selectedTypeString); + + if (Context->LastSelectedType != type) + { + // Change the contents of the subtype combo box based on the type. + + ComboBox_ResetContent(subTypeComboBox); + + switch (type) + { + case SERVICE_TRIGGER_TYPE_DEVICE_INTERFACE_ARRIVAL: + { + ComboBox_AddString(subTypeComboBox, L"Custom"); + } + break; + case SERVICE_TRIGGER_TYPE_CUSTOM_SYSTEM_STATE_CHANGE: + { + ComboBox_AddString(subTypeComboBox, L"Custom"); + } + break; + case SERVICE_TRIGGER_TYPE_CUSTOM: + { + PETW_PUBLISHER_ENTRY entries; + ULONG numberOfEntries; + ULONG i; + + ComboBox_AddString(subTypeComboBox, L"Custom"); + + // Display a list of publishers. + if (EspEnumerateEtwPublishers(&entries, &numberOfEntries)) + { + // Sort the list by name. + qsort(entries, numberOfEntries, sizeof(ETW_PUBLISHER_ENTRY), EtwPublisherByNameCompareFunction); + + for (i = 0; i < numberOfEntries; i++) + { + ComboBox_AddString(subTypeComboBox, entries[i].PublisherName->Buffer); + PhDereferenceObject(entries[i].PublisherName); + } + + PhFree(entries); + } + } + break; + default: + for (i = 0; i < sizeof(SubTypeEntries) / sizeof(SUBTYPE_ENTRY); i++) + { + if (SubTypeEntries[i].Type == type && SubTypeEntries[i].Guid && SubTypeEntries[i].Guid != &SubTypeUnknownGuid) + { + ComboBox_AddString(subTypeComboBox, SubTypeEntries[i].Name); + } + } + break; + } + + ComboBox_SetCurSel(subTypeComboBox, 0); + + Context->LastSelectedType = type; + } + + selectedSubTypeString = PhGetWindowText(subTypeComboBox); + + if (PhEqualString2(selectedSubTypeString, L"Custom", FALSE)) + { + EnableWindow(GetDlgItem(hwndDlg, IDC_SUBTYPECUSTOM), TRUE); + SetDlgItemText(hwndDlg, IDC_SUBTYPECUSTOM, Context->LastCustomSubType->Buffer); + } + else + { + if (IsWindowEnabled(GetDlgItem(hwndDlg, IDC_SUBTYPECUSTOM))) + { + EnableWindow(GetDlgItem(hwndDlg, IDC_SUBTYPECUSTOM), FALSE); + PhMoveReference(&Context->LastCustomSubType, PhGetWindowText(GetDlgItem(hwndDlg, IDC_SUBTYPECUSTOM))); + SetDlgItemText(hwndDlg, IDC_SUBTYPECUSTOM, L""); + } + } + + PhDereferenceObject(selectedSubTypeString); +} + +PPH_STRING EspConvertNullsToNewLines( + _In_ PPH_STRING String + ) +{ + PH_STRING_BUILDER sb; + ULONG i; + + PhInitializeStringBuilder(&sb, String->Length); + + for (i = 0; i < (ULONG)String->Length / 2; i++) + { + if (String->Buffer[i] == 0) + { + PhAppendStringBuilderEx(&sb, L"\r\n", 4); + continue; + } + + PhAppendCharStringBuilder(&sb, String->Buffer[i]); + } + + return PhFinalStringBuilderString(&sb); +} + +PPH_STRING EspConvertNewLinesToNulls( + _In_ PPH_STRING String + ) +{ + PPH_STRING text; + SIZE_T count; + SIZE_T i; + + text = PhCreateStringEx(NULL, String->Length + 2); // plus one character for an extra null terminator (see below) + text->Length = 0; + count = 0; + + for (i = 0; i < String->Length / 2; i++) + { + // Lines are terminated by "\r\n". + if (String->Buffer[i] == '\r') + { + continue; + } + + if (String->Buffer[i] == '\n') + { + text->Buffer[count++] = 0; + continue; + } + + text->Buffer[count++] = String->Buffer[i]; + } + + if (count != 0) + { + // Make sure we have an extra null terminator at the end, as required of multistrings. + if (text->Buffer[count - 1] != 0) + text->Buffer[count++] = 0; + } + + text->Length = count * 2; + + return text; +} + +PPH_STRING EspConvertNullsToSpaces( + _In_ PPH_STRING String + ) +{ + PPH_STRING text; + SIZE_T j; + + text = PhDuplicateString(String); + + for (j = 0; j < text->Length / 2; j++) + { + if (text->Buffer[j] == 0) + text->Buffer[j] = ' '; + } + + return text; +} + +VOID EspFormatTriggerData( + _In_ PES_TRIGGER_DATA Data, + _Out_ PPH_STRING *Text + ) +{ + if (Data->Type == SERVICE_TRIGGER_DATA_TYPE_STRING) + { + // This check works for both normal strings and multistrings. + if (Data->String->Length != 0) + { + // Prepare the text for display by replacing null characters with spaces. + *Text = EspConvertNullsToSpaces(Data->String); + } + else + { + *Text = PhCreateString(L"(empty string)"); + } + } + else if (Data->Type == SERVICE_TRIGGER_DATA_TYPE_BINARY) + { + *Text = PhCreateString(L"(binary data)"); + } + else if (Data->Type == SERVICE_TRIGGER_DATA_TYPE_LEVEL) + { + *Text = PhFormatString(L"(level) %u", Data->Byte); + } + else if (Data->Type == SERVICE_TRIGGER_DATA_TYPE_KEYWORD_ANY) + { + *Text = PhFormatString(L"(keyword any) 0x%I64x", Data->UInt64); + } + else if (Data->Type == SERVICE_TRIGGER_DATA_TYPE_KEYWORD_ALL) + { + *Text = PhFormatString(L"(keyword all) 0x%I64x", Data->UInt64); + } + else + { + *Text = PhCreateString(L"(unknown type)"); + } +} + +INT_PTR CALLBACK EspServiceTriggerDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + PES_TRIGGER_CONTEXT context; + + if (uMsg == WM_INITDIALOG) + { + context = (PES_TRIGGER_CONTEXT)lParam; + SetProp(hwndDlg, L"Context", (HANDLE)context); + } + else + { + context = (PES_TRIGGER_CONTEXT)GetProp(hwndDlg, L"Context"); + + if (uMsg == WM_DESTROY) + RemoveProp(hwndDlg, L"Context"); + } + + if (!context) + return FALSE; + + switch (uMsg) + { + case WM_INITDIALOG: + { + HWND typeComboBox; + HWND actionComboBox; + HWND lvHandle; + ULONG i; + + context->LastSelectedType = 0; + + if (context->EditingInfo->Subtype) + context->LastCustomSubType = PhFormatGuid(context->EditingInfo->Subtype); + else + context->LastCustomSubType = PhReferenceEmptyString(); + + typeComboBox = GetDlgItem(hwndDlg, IDC_TYPE); + actionComboBox = GetDlgItem(hwndDlg, IDC_ACTION); + + for (i = 0; i < sizeof(TypeEntries) / sizeof(TYPE_ENTRY); i++) + { + ComboBox_AddString(typeComboBox, TypeEntries[i].Name); + + if (TypeEntries[i].Type == context->EditingInfo->Type) + { + PhSelectComboBoxString(typeComboBox, TypeEntries[i].Name, FALSE); + } + } + + ComboBox_AddString(actionComboBox, L"Start"); + ComboBox_AddString(actionComboBox, L"Stop"); + ComboBox_SetCurSel(actionComboBox, context->EditingInfo->Action == SERVICE_TRIGGER_ACTION_SERVICE_START ? 0 : 1); + + EspFixServiceTriggerControls(hwndDlg, context); + + if (context->EditingInfo->Type != SERVICE_TRIGGER_TYPE_CUSTOM) + { + for (i = 0; i < sizeof(SubTypeEntries) / sizeof(SUBTYPE_ENTRY); i++) + { + if ( + SubTypeEntries[i].Type == context->EditingInfo->Type && + SubTypeEntries[i].Guid && + context->EditingInfo->Subtype && + memcmp(SubTypeEntries[i].Guid, context->EditingInfo->Subtype, sizeof(GUID)) == 0 + ) + { + PhSelectComboBoxString(GetDlgItem(hwndDlg, IDC_SUBTYPE), SubTypeEntries[i].Name, FALSE); + break; + } + } + } + else + { + if (context->EditingInfo->Subtype) + { + PPH_STRING publisherName; + + // Try to select the publisher name in the subtype list. + publisherName = EspLookupEtwPublisherName(context->EditingInfo->Subtype); + PhSelectComboBoxString(GetDlgItem(hwndDlg, IDC_SUBTYPE), publisherName->Buffer, FALSE); + PhDereferenceObject(publisherName); + } + } + + // Call a second time since the state of the custom subtype text box may have changed. + EspFixServiceTriggerControls(hwndDlg, context); + + lvHandle = GetDlgItem(hwndDlg, IDC_LIST); + PhSetListViewStyle(lvHandle, FALSE, TRUE); + PhSetControlTheme(lvHandle, L"explorer"); + PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 280, L"Data"); + + if (context->EditingInfo->DataList) + { + for (i = 0; i < context->EditingInfo->DataList->Count; i++) + { + PES_TRIGGER_DATA data; + PPH_STRING text; + INT lvItemIndex; + + data = context->EditingInfo->DataList->Items[i]; + + EspFormatTriggerData(data, &text); + lvItemIndex = PhAddListViewItem(lvHandle, MAXINT, text->Buffer, data); + PhDereferenceObject(text); + } + } + + EnableWindow(GetDlgItem(hwndDlg, IDC_EDIT), FALSE); + EnableWindow(GetDlgItem(hwndDlg, IDC_DELETE), FALSE); + } + break; + case WM_DESTROY: + { + PhClearReference(&context->LastCustomSubType); + } + break; + case WM_COMMAND: + { + switch (LOWORD(wParam)) + { + case IDC_TYPE: + if (HIWORD(wParam) == CBN_SELCHANGE) + { + EspFixServiceTriggerControls(hwndDlg, context); + } + break; + case IDC_SUBTYPE: + if (HIWORD(wParam) == CBN_SELCHANGE) + { + EspFixServiceTriggerControls(hwndDlg, context); + } + break; + case IDC_NEW: + { + HWND lvHandle; + + lvHandle = GetDlgItem(hwndDlg, IDC_LIST); + context->EditingValue = PhReferenceEmptyString(); + + if (DialogBoxParam( + PluginInstance->DllBase, + MAKEINTRESOURCE(IDD_VALUE), + hwndDlg, + ValueDlgProc, + (LPARAM)context + ) == IDOK) + { + PES_TRIGGER_DATA data; + PPH_STRING text; + INT lvItemIndex; + + data = EspCreateTriggerData(NULL); + data->Type = SERVICE_TRIGGER_DATA_TYPE_STRING; + data->String = EspConvertNewLinesToNulls(context->EditingValue); + + if (!context->EditingInfo->DataList) + context->EditingInfo->DataList = PhCreateList(4); + + PhAddItemList(context->EditingInfo->DataList, data); + + EspFormatTriggerData(data, &text); + lvItemIndex = PhAddListViewItem(lvHandle, MAXINT, text->Buffer, data); + PhDereferenceObject(text); + } + + PhClearReference(&context->EditingValue); + } + break; + case IDC_EDIT: + { + HWND lvHandle; + INT lvItemIndex; + PES_TRIGGER_DATA data; + ULONG index; + + lvHandle = GetDlgItem(hwndDlg, IDC_LIST); + lvItemIndex = ListView_GetNextItem(lvHandle, -1, LVNI_SELECTED); + + if ( + lvItemIndex != -1 && PhGetListViewItemParam(lvHandle, lvItemIndex, (PVOID *)&data) && + data->Type == SERVICE_TRIGGER_DATA_TYPE_STRING // editing binary values is not supported + ) + { + index = PhFindItemList(context->EditingInfo->DataList, data); + + if (index != -1) + { + context->EditingValue = EspConvertNullsToNewLines(data->String); + + if (DialogBoxParam( + PluginInstance->DllBase, + MAKEINTRESOURCE(IDD_VALUE), + hwndDlg, + ValueDlgProc, + (LPARAM)context + ) == IDOK) + { + PPH_STRING text; + + PhMoveReference(&data->String, EspConvertNewLinesToNulls(context->EditingValue)); + + EspFormatTriggerData(data, &text); + PhSetListViewSubItem(lvHandle, lvItemIndex, 0, text->Buffer); + PhDereferenceObject(text); + } + + PhClearReference(&context->EditingValue); + } + } + } + break; + case IDC_DELETE: + { + HWND lvHandle; + INT lvItemIndex; + PES_TRIGGER_DATA data; + ULONG index; + + lvHandle = GetDlgItem(hwndDlg, IDC_LIST); + lvItemIndex = ListView_GetNextItem(lvHandle, -1, LVNI_SELECTED); + + if (lvItemIndex != -1 && PhGetListViewItemParam(lvHandle, lvItemIndex, (PVOID *)&data)) + { + index = PhFindItemList(context->EditingInfo->DataList, data); + + if (index != -1) + { + EspDestroyTriggerData(data); + PhRemoveItemList(context->EditingInfo->DataList, index); + PhRemoveListViewItem(lvHandle, lvItemIndex); + } + } + } + break; + case IDCANCEL: + EndDialog(hwndDlg, IDCANCEL); + break; + case IDOK: + { + PH_AUTO_POOL autoPool; + PPH_STRING typeString; + PPH_STRING subTypeString; + PPH_STRING customSubTypeString; + PPH_STRING actionString; + ULONG i; + + PhInitializeAutoPool(&autoPool); + + typeString = PhaGetDlgItemText(hwndDlg, IDC_TYPE); + subTypeString = PhaGetDlgItemText(hwndDlg, IDC_SUBTYPE); + customSubTypeString = PhaGetDlgItemText(hwndDlg, IDC_SUBTYPECUSTOM); + actionString = PhaGetDlgItemText(hwndDlg, IDC_ACTION); + + for (i = 0; i < sizeof(TypeEntries) / sizeof(TYPE_ENTRY); i++) + { + if (PhEqualStringZ(TypeEntries[i].Name, typeString->Buffer, FALSE)) + { + context->EditingInfo->Type = TypeEntries[i].Type; + break; + } + } + + if (!PhEqualString2(subTypeString, L"Custom", FALSE)) + { + if (context->EditingInfo->Type != SERVICE_TRIGGER_TYPE_CUSTOM) + { + for (i = 0; i < sizeof(SubTypeEntries) / sizeof(SUBTYPE_ENTRY); i++) + { + if ( + SubTypeEntries[i].Type == context->EditingInfo->Type && + PhEqualString2(subTypeString, SubTypeEntries[i].Name, FALSE) + ) + { + context->EditingInfo->SubtypeBuffer = *SubTypeEntries[i].Guid; + context->EditingInfo->Subtype = &context->EditingInfo->SubtypeBuffer; + break; + } + } + } + else + { + if (!EspLookupEtwPublisherGuid(&subTypeString->sr, &context->EditingInfo->SubtypeBuffer)) + { + PhShowError(hwndDlg, L"Unable to find the ETW publisher GUID."); + goto DoNotClose; + } + + context->EditingInfo->Subtype = &context->EditingInfo->SubtypeBuffer; + } + } + else + { + UNICODE_STRING guidString; + + PhStringRefToUnicodeString(&customSubTypeString->sr, &guidString); + + // Trim whitespace. + + while (guidString.Length != 0 && *guidString.Buffer == ' ') + { + guidString.Buffer++; + guidString.Length -= 2; + } + + while (guidString.Length != 0 && guidString.Buffer[guidString.Length / 2 - 1] == ' ') + { + guidString.Length -= 2; + } + + if (NT_SUCCESS(RtlGUIDFromString(&guidString, &context->EditingInfo->SubtypeBuffer))) + { + context->EditingInfo->Subtype = &context->EditingInfo->SubtypeBuffer; + } + else + { + PhShowError(hwndDlg, L"The custom subtype is invalid. Please ensure that the string is a valid GUID: \"{x-x-x-x-x}\"."); + goto DoNotClose; + } + } + + if (PhEqualString2(actionString, L"Start", FALSE)) + context->EditingInfo->Action = SERVICE_TRIGGER_ACTION_SERVICE_START; + else + context->EditingInfo->Action = SERVICE_TRIGGER_ACTION_SERVICE_STOP; + + if ( + context->EditingInfo->DataList && + context->EditingInfo->DataList->Count != 0 && + context->EditingInfo->Type != SERVICE_TRIGGER_TYPE_DEVICE_INTERFACE_ARRIVAL && + context->EditingInfo->Type != SERVICE_TRIGGER_TYPE_FIREWALL_PORT_EVENT && + context->EditingInfo->Type != SERVICE_TRIGGER_TYPE_NETWORK_ENDPOINT && + context->EditingInfo->Type != SERVICE_TRIGGER_TYPE_CUSTOM + ) + { + // This trigger has data items, but the trigger type doesn't allow them. + if (PhShowMessage( + hwndDlg, + MB_OKCANCEL | MB_ICONWARNING, + L"The trigger type \"%s\" does not allow data items to be configured. " + L"If you continue, they will be removed.", + typeString->Buffer + ) != IDOK) + { + goto DoNotClose; + } + + for (i = 0; i < context->EditingInfo->DataList->Count; i++) + { + EspDestroyTriggerData(context->EditingInfo->DataList->Items[i]); + } + + PhClearReference(&context->EditingInfo->DataList); + } + + EndDialog(hwndDlg, IDOK); + +DoNotClose: + PhDeleteAutoPool(&autoPool); + } + break; + } + } + break; + case WM_NOTIFY: + { + LPNMHDR header = (LPNMHDR)lParam; + HWND lvHandle; + + lvHandle = GetDlgItem(hwndDlg, IDC_LIST); + + switch (header->code) + { + case LVN_ITEMCHANGED: + { + if (header->hwndFrom == lvHandle) + { + if (ListView_GetSelectedCount(lvHandle) == 1) + { + PES_TRIGGER_DATA data = PhGetSelectedListViewItemParam(GetDlgItem(hwndDlg, IDC_LIST)); + + // Editing binary data is not supported. + EnableWindow(GetDlgItem(hwndDlg, IDC_EDIT), data && data->Type == SERVICE_TRIGGER_DATA_TYPE_STRING); + EnableWindow(GetDlgItem(hwndDlg, IDC_DELETE), TRUE); + } + else + { + EnableWindow(GetDlgItem(hwndDlg, IDC_EDIT), FALSE); + EnableWindow(GetDlgItem(hwndDlg, IDC_DELETE), FALSE); + } + } + } + break; + case NM_DBLCLK: + { + if (header->hwndFrom == lvHandle) + { + SendMessage(hwndDlg, WM_COMMAND, IDC_EDIT, 0); + } + } + break; + } + } + break; + } + + return FALSE; +} + +INT_PTR CALLBACK ValueDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + PES_TRIGGER_CONTEXT context; + + if (uMsg == WM_INITDIALOG) + { + context = (PES_TRIGGER_CONTEXT)lParam; + SetProp(hwndDlg, L"Context", (HANDLE)context); + } + else + { + context = (PES_TRIGGER_CONTEXT)GetProp(hwndDlg, L"Context"); + + if (uMsg == WM_DESTROY) + RemoveProp(hwndDlg, L"Context"); + } + + if (!context) + return FALSE; + + switch (uMsg) + { + case WM_INITDIALOG: + { + SetDlgItemText(hwndDlg, IDC_VALUES, context->EditingValue->Buffer); + SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hwndDlg, IDC_VALUES), TRUE); + Edit_SetSel(GetDlgItem(hwndDlg, IDC_VALUES), 0, -1); + } + break; + case WM_COMMAND: + { + switch (LOWORD(wParam)) + { + case IDCANCEL: + EndDialog(hwndDlg, IDCANCEL); + break; + case IDOK: + PhMoveReference(&context->EditingValue, PhGetWindowText(GetDlgItem(hwndDlg, IDC_VALUES))); + EndDialog(hwndDlg, IDOK); + break; + } + } + break; + } + + return FALSE; +} diff --git a/plugins/ExtendedServices/triggpg.c b/plugins/ExtendedServices/triggpg.c index d8861dd6e4e8..0188ddaead0f 100644 --- a/plugins/ExtendedServices/triggpg.c +++ b/plugins/ExtendedServices/triggpg.c @@ -1,182 +1,182 @@ -/* - * Process Hacker Extended Services - - * triggers page - * - * Copyright (C) 2015 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include "extsrv.h" - -typedef struct _SERVICE_TRIGGERS_CONTEXT -{ - PPH_SERVICE_ITEM ServiceItem; - HWND TriggersLv; - struct _ES_TRIGGER_CONTEXT *TriggerContext; -} SERVICE_TRIGGERS_CONTEXT, *PSERVICE_TRIGGERS_CONTEXT; - -NTSTATUS EspLoadTriggerInfo( - _In_ HWND hwndDlg, - _In_ PSERVICE_TRIGGERS_CONTEXT Context - ) -{ - NTSTATUS status = STATUS_SUCCESS; - SC_HANDLE serviceHandle; - - if (!(serviceHandle = PhOpenService(Context->ServiceItem->Name->Buffer, SERVICE_QUERY_CONFIG))) - return NTSTATUS_FROM_WIN32(GetLastError()); - - EsLoadServiceTriggerInfo(Context->TriggerContext, serviceHandle); - CloseServiceHandle(serviceHandle); - - return status; -} - -INT_PTR CALLBACK EspServiceTriggersDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - PSERVICE_TRIGGERS_CONTEXT context; - - if (uMsg == WM_INITDIALOG) - { - context = PhAllocate(sizeof(SERVICE_TRIGGERS_CONTEXT)); - memset(context, 0, sizeof(SERVICE_TRIGGERS_CONTEXT)); - - SetProp(hwndDlg, L"Context", (HANDLE)context); - } - else - { - context = (PSERVICE_TRIGGERS_CONTEXT)GetProp(hwndDlg, L"Context"); - - if (uMsg == WM_DESTROY) - RemoveProp(hwndDlg, L"Context"); - } - - if (!context) - return FALSE; - - switch (uMsg) - { - case WM_INITDIALOG: - { - NTSTATUS status; - LPPROPSHEETPAGE propSheetPage = (LPPROPSHEETPAGE)lParam; - PPH_SERVICE_ITEM serviceItem = (PPH_SERVICE_ITEM)propSheetPage->lParam; - HWND triggersLv; - - context->ServiceItem = serviceItem; - context->TriggersLv = triggersLv = GetDlgItem(hwndDlg, IDC_TRIGGERS); - context->TriggerContext = EsCreateServiceTriggerContext( - context->ServiceItem, - hwndDlg, - triggersLv - ); - - status = EspLoadTriggerInfo(hwndDlg, context); - - if (!NT_SUCCESS(status)) - { - PhShowWarning(hwndDlg, L"Unable to query service trigger information: %s", - ((PPH_STRING)PH_AUTO(PhGetNtMessage(status)))->Buffer); - } - } - break; - case WM_DESTROY: - { - EsDestroyServiceTriggerContext(context->TriggerContext); - PhFree(context); - } - break; - case WM_COMMAND: - { - switch (LOWORD(wParam)) - { - case IDC_NEW: - if (context->TriggerContext) - EsHandleEventServiceTrigger(context->TriggerContext, ES_TRIGGER_EVENT_NEW); - break; - case IDC_EDIT: - if (context->TriggerContext) - EsHandleEventServiceTrigger(context->TriggerContext, ES_TRIGGER_EVENT_EDIT); - break; - case IDC_DELETE: - if (context->TriggerContext) - EsHandleEventServiceTrigger(context->TriggerContext, ES_TRIGGER_EVENT_DELETE); - break; - } - } - break; - case WM_NOTIFY: - { - LPNMHDR header = (LPNMHDR)lParam; - - switch (header->code) - { - case PSN_KILLACTIVE: - { - SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, FALSE); - } - return TRUE; - case PSN_APPLY: - { - ULONG win32Result = 0; - - SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_NOERROR); - - if (!EsSaveServiceTriggerInfo(context->TriggerContext, &win32Result)) - { - if (win32Result == ERROR_CANCELLED || (PhShowMessage( - hwndDlg, - MB_ICONERROR | MB_RETRYCANCEL, - L"Unable to change service trigger information: %s", - ((PPH_STRING)PH_AUTO(PhGetWin32Message(win32Result)))->Buffer - ) == IDRETRY)) - { - SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_INVALID); - } - } - - return TRUE; - } - break; - case LVN_ITEMCHANGED: - { - if (header->hwndFrom == context->TriggersLv && context->TriggerContext) - { - EsHandleEventServiceTrigger(context->TriggerContext, ES_TRIGGER_EVENT_SELECTIONCHANGED); - } - } - break; - case NM_DBLCLK: - { - if (header->hwndFrom == context->TriggersLv && context->TriggerContext) - { - EsHandleEventServiceTrigger(context->TriggerContext, ES_TRIGGER_EVENT_EDIT); - } - } - break; - } - } - break; - } - - return FALSE; -} +/* + * Process Hacker Extended Services - + * triggers page + * + * Copyright (C) 2015 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include "extsrv.h" + +typedef struct _SERVICE_TRIGGERS_CONTEXT +{ + PPH_SERVICE_ITEM ServiceItem; + HWND TriggersLv; + struct _ES_TRIGGER_CONTEXT *TriggerContext; +} SERVICE_TRIGGERS_CONTEXT, *PSERVICE_TRIGGERS_CONTEXT; + +NTSTATUS EspLoadTriggerInfo( + _In_ HWND hwndDlg, + _In_ PSERVICE_TRIGGERS_CONTEXT Context + ) +{ + NTSTATUS status = STATUS_SUCCESS; + SC_HANDLE serviceHandle; + + if (!(serviceHandle = PhOpenService(Context->ServiceItem->Name->Buffer, SERVICE_QUERY_CONFIG))) + return NTSTATUS_FROM_WIN32(GetLastError()); + + EsLoadServiceTriggerInfo(Context->TriggerContext, serviceHandle); + CloseServiceHandle(serviceHandle); + + return status; +} + +INT_PTR CALLBACK EspServiceTriggersDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + PSERVICE_TRIGGERS_CONTEXT context; + + if (uMsg == WM_INITDIALOG) + { + context = PhAllocate(sizeof(SERVICE_TRIGGERS_CONTEXT)); + memset(context, 0, sizeof(SERVICE_TRIGGERS_CONTEXT)); + + SetProp(hwndDlg, L"Context", (HANDLE)context); + } + else + { + context = (PSERVICE_TRIGGERS_CONTEXT)GetProp(hwndDlg, L"Context"); + + if (uMsg == WM_DESTROY) + RemoveProp(hwndDlg, L"Context"); + } + + if (!context) + return FALSE; + + switch (uMsg) + { + case WM_INITDIALOG: + { + NTSTATUS status; + LPPROPSHEETPAGE propSheetPage = (LPPROPSHEETPAGE)lParam; + PPH_SERVICE_ITEM serviceItem = (PPH_SERVICE_ITEM)propSheetPage->lParam; + HWND triggersLv; + + context->ServiceItem = serviceItem; + context->TriggersLv = triggersLv = GetDlgItem(hwndDlg, IDC_TRIGGERS); + context->TriggerContext = EsCreateServiceTriggerContext( + context->ServiceItem, + hwndDlg, + triggersLv + ); + + status = EspLoadTriggerInfo(hwndDlg, context); + + if (!NT_SUCCESS(status)) + { + PhShowWarning(hwndDlg, L"Unable to query service trigger information: %s", + ((PPH_STRING)PH_AUTO(PhGetNtMessage(status)))->Buffer); + } + } + break; + case WM_DESTROY: + { + EsDestroyServiceTriggerContext(context->TriggerContext); + PhFree(context); + } + break; + case WM_COMMAND: + { + switch (LOWORD(wParam)) + { + case IDC_NEW: + if (context->TriggerContext) + EsHandleEventServiceTrigger(context->TriggerContext, ES_TRIGGER_EVENT_NEW); + break; + case IDC_EDIT: + if (context->TriggerContext) + EsHandleEventServiceTrigger(context->TriggerContext, ES_TRIGGER_EVENT_EDIT); + break; + case IDC_DELETE: + if (context->TriggerContext) + EsHandleEventServiceTrigger(context->TriggerContext, ES_TRIGGER_EVENT_DELETE); + break; + } + } + break; + case WM_NOTIFY: + { + LPNMHDR header = (LPNMHDR)lParam; + + switch (header->code) + { + case PSN_KILLACTIVE: + { + SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, FALSE); + } + return TRUE; + case PSN_APPLY: + { + ULONG win32Result = 0; + + SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_NOERROR); + + if (!EsSaveServiceTriggerInfo(context->TriggerContext, &win32Result)) + { + if (win32Result == ERROR_CANCELLED || (PhShowMessage( + hwndDlg, + MB_ICONERROR | MB_RETRYCANCEL, + L"Unable to change service trigger information: %s", + ((PPH_STRING)PH_AUTO(PhGetWin32Message(win32Result)))->Buffer + ) == IDRETRY)) + { + SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_INVALID); + } + } + + return TRUE; + } + break; + case LVN_ITEMCHANGED: + { + if (header->hwndFrom == context->TriggersLv && context->TriggerContext) + { + EsHandleEventServiceTrigger(context->TriggerContext, ES_TRIGGER_EVENT_SELECTIONCHANGED); + } + } + break; + case NM_DBLCLK: + { + if (header->hwndFrom == context->TriggersLv && context->TriggerContext) + { + EsHandleEventServiceTrigger(context->TriggerContext, ES_TRIGGER_EVENT_EDIT); + } + } + break; + } + } + break; + } + + return FALSE; +} diff --git a/plugins/ExtendedTools/CHANGELOG.txt b/plugins/ExtendedTools/CHANGELOG.txt index f654379850be..1ceff4a21f3f 100644 --- a/plugins/ExtendedTools/CHANGELOG.txt +++ b/plugins/ExtendedTools/CHANGELOG.txt @@ -1,68 +1,68 @@ -1.17 - * Removed legacy code - -1.16 - * Fixed "No process" disk event bug - -1.15 - * Added tray icon mini info window support - * Improved automatic GPU node selection - -1.14 - * Added Disk and Network graphs for all processes - -1.13 - * Added GPU graphs for all processes - * Can now use the search box in the Disk tab - * Improved kernel logger handling on Windows 8 - -1.12 - * Improved support for multiple GPUs (again) - * GPU column now respects "Include CPU usage of children" option - -1.11 - * Fixed network graph scaling - -1.10 - * Improved support for multiple GPUs - -1.9 - * Added GPU node selection - * Fixed incorrect GPU usage calculation - -1.8 - * Added support for new system information window - * Added Disk, Network and GPU tray icons - * Added support for custom fonts in the Disk tab - -1.7 - * Added GPU monitoring - * Added rate columns for disk and network I/O - -1.6 - * Updated disk monitoring for Windows 8 - * Updated memory list information for Windows 8 - -1.5 - * Added Disk tab - * Added Hard Faults, Hard Faults Delta and Peak Threads columns - to process tree list - * Added Firewall Status column to network list - -1.4 - * Added ETW columns for processes and network connections - -1.3 - * Fixed WS Watch refresh bug - -1.2 - * Added WS Watch - * Added display of standby repurposed pages - * Added Empty commands for memory lists - * Fixed Disk and Network page crash - -1.1 - * Fixed ETW crash - -1.0 +1.17 + * Removed legacy code + +1.16 + * Fixed "No process" disk event bug + +1.15 + * Added tray icon mini info window support + * Improved automatic GPU node selection + +1.14 + * Added Disk and Network graphs for all processes + +1.13 + * Added GPU graphs for all processes + * Can now use the search box in the Disk tab + * Improved kernel logger handling on Windows 8 + +1.12 + * Improved support for multiple GPUs (again) + * GPU column now respects "Include CPU usage of children" option + +1.11 + * Fixed network graph scaling + +1.10 + * Improved support for multiple GPUs + +1.9 + * Added GPU node selection + * Fixed incorrect GPU usage calculation + +1.8 + * Added support for new system information window + * Added Disk, Network and GPU tray icons + * Added support for custom fonts in the Disk tab + +1.7 + * Added GPU monitoring + * Added rate columns for disk and network I/O + +1.6 + * Updated disk monitoring for Windows 8 + * Updated memory list information for Windows 8 + +1.5 + * Added Disk tab + * Added Hard Faults, Hard Faults Delta and Peak Threads columns + to process tree list + * Added Firewall Status column to network list + +1.4 + * Added ETW columns for processes and network connections + +1.3 + * Fixed WS Watch refresh bug + +1.2 + * Added WS Watch + * Added display of standby repurposed pages + * Added Empty commands for memory lists + * Fixed Disk and Network page crash + +1.1 + * Fixed ETW crash + +1.0 * Initial release \ No newline at end of file diff --git a/plugins/ExtendedTools/ExtendedTools.rc b/plugins/ExtendedTools/ExtendedTools.rc index 3917a0c1aa93..6b90a093c160 100644 --- a/plugins/ExtendedTools/ExtendedTools.rc +++ b/plugins/ExtendedTools/ExtendedTools.rc @@ -1,543 +1,543 @@ -// Microsoft Visual C++ generated resource script. -// -#include "resource.h" - -#define APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// -#include "winres.h" -///////////////////////////////////////////////////////////////////////////// -#undef APSTUDIO_READONLY_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -// English (Australia) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENA) -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_AUS -#pragma code_page(1252) - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -1 TEXTINCLUDE -BEGIN - "resource.h\0" -END - -2 TEXTINCLUDE -BEGIN - "#include ""winres.h""\0" -END - -3 TEXTINCLUDE -BEGIN - "\r\n" - "\0" -END - -#endif // APSTUDIO_INVOKED - - -///////////////////////////////////////////////////////////////////////////// -// -// Version -// - -VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,17,0,0 - PRODUCTVERSION 1,17,0,0 - FILEFLAGSMASK 0x3fL -#ifdef _DEBUG - FILEFLAGS 0x1L -#else - FILEFLAGS 0x0L -#endif - FILEOS 0x40004L - FILETYPE 0x2L - FILESUBTYPE 0x0L -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "0c0904b0" - BEGIN - VALUE "CompanyName", "wj32" - VALUE "FileDescription", "Extended Tools plugin for Process Hacker" - VALUE "FileVersion", "1.17" - VALUE "InternalName", "ProcessHacker.ExtendedTools" - VALUE "LegalCopyright", "Licensed under the GNU GPL, v3." - VALUE "OriginalFilename", "ExtendedTools.dll" - VALUE "ProductName", "Extended Tools plugin for Process Hacker" - VALUE "ProductVersion", "1.17" - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0xc09, 1200 - END -END - - -///////////////////////////////////////////////////////////////////////////// -// -// Dialog -// - -IDD_UNLOADEDDLLS DIALOGEX 0, 0, 342, 265 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Unloaded Modules" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,7,328,233 - PUSHBUTTON "Refresh",IDC_REFRESH,7,244,50,14 - DEFPUSHBUTTON "Close",IDOK,285,244,50,14 -END - -IDD_OBJALPCPORT DIALOGEX 0, 0, 160, 101 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "ALPC Port" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "Sequence number: Unknown",IDC_SEQUENCENUMBER,7,7,146,8 - LTEXT "Port context: Unknown",IDC_PORTCONTEXT,7,19,146,8 -END - -IDD_OBJTPWORKERFACTORY DIALOGEX 0, 0, 186, 101 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Worker Factory" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "Worker thread start: Unknown",IDC_WORKERTHREADSTART,7,7,172,8,SS_ENDELLIPSIS - LTEXT "Worker thread context: Unknown",IDC_WORKERTHREADCONTEXT,7,18,172,8,SS_ENDELLIPSIS -END - -IDD_MODSERVICES DIALOGEX 0, 0, 276, 209 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Services" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "Static",IDC_MESSAGE,7,7,262,8 - LTEXT "Static",IDC_SERVICES_LAYOUT,7,22,262,162,NOT WS_VISIBLE - DEFPUSHBUTTON "Close",IDOK,219,188,50,14 -END - -IDD_PROCDISKNET DIALOGEX 0, 0, 265, 158 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Disk and Network" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - GROUPBOX "Disk",IDC_GROUPDISK,7,7,251,69 - GROUPBOX "Network",IDC_GROUPNETWORK,7,81,251,69 -END - -IDD_SYSINFO_DISKPANEL DIALOGEX 0, 0, 146, 58 -STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_SYSMENU -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - GROUPBOX "Disk I/O",IDC_STATIC,0,0,145,58 - LTEXT "Reads delta",IDC_STATIC,8,11,40,8 - LTEXT "Read bytes delta",IDC_STATIC,8,22,56,8 - LTEXT "Writes delta",IDC_STATIC,8,33,40,8 - LTEXT "Write bytes delta",IDC_STATIC,8,44,57,8 - RTEXT "Static",IDC_ZREADSDELTA_V,84,11,54,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZREADBYTESDELTA_V,78,22,60,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZWRITESDELTA_V,84,33,54,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZWRITEBYTESDELTA_V,82,44,56,8,SS_ENDELLIPSIS -END - -IDD_OPTIONS DIALOGEX 0, 0, 215, 77 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Options" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "Changes to settings will require a restart of Process Hacker.",IDC_STATIC,7,6,193,8 - CONTROL "Enable Disk and Network monitoring",IDC_ENABLEETWMONITOR, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,20,130,10 - CONTROL "Enable GPU monitoring",IDC_ENABLEGPUMONITOR,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,46,88,10 - PUSHBUTTON "Close",IDOK,158,56,50,14 - CONTROL "Enable Disk and Network graphs",IDC_ENABLESYSINFOGRAPHS, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,33,130,10 -END - -IDD_WSWATCH DIALOGEX 0, 0, 325, 266 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "WS Watch" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "Working set watch allows you to monitor page faults that occur in a process. You must enable WS watch for the process to start the monitoring. Once WS watch is enabled, it cannot be disabled.",IDC_STATIC,7,7,311,27 - PUSHBUTTON "Enable",IDC_ENABLE,7,37,50,14 - LTEXT "WS watch is enabled.",IDC_WSWATCHENABLED,63,40,119,8,NOT WS_VISIBLE - LTEXT "Page faults:",IDC_STATIC,7,54,40,8 - CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,65,311,175 - DEFPUSHBUTTON "Close",IDOK,268,245,50,14 -END - -IDD_SYSINFO_GPU DIALOGEX 0, 0, 315, 186 -STYLE DS_SETFONT | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME -CAPTION "GPU" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "GPU",IDC_TITLE,0,0,72,21 - RTEXT "GPU name",IDC_GPUNAME,83,4,232,16,SS_WORDELLIPSIS - LTEXT "Panel layout",IDC_PANEL_LAYOUT,0,130,315,55,NOT WS_VISIBLE - LTEXT "Graph layout",IDC_GRAPH_LAYOUT,0,22,315,102,NOT WS_VISIBLE - LTEXT "GPU:",IDC_GPU_L,73,0,17,8 - LTEXT "Dedicated memory:",IDC_DEDICATED_L,73,5,63,8 - LTEXT "Shared memory:",IDC_SHARED_L,74,11,54,8 -END - -IDD_SYSINFO_GPUPANEL DIALOGEX 0, 0, 246, 54 -STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_SYSMENU -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - GROUPBOX "Dedicated memory",IDC_STATIC,0,0,118,36 - LTEXT "Current",IDC_STATIC,8,11,26,8 - LTEXT "Limit",IDC_STATIC,8,22,15,8 - RTEXT "Static",IDC_ZDEDICATEDCURRENT_V,55,11,54,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZDEDICATEDLIMIT_V,55,22,54,8,SS_ENDELLIPSIS - GROUPBOX "Shared memory",IDC_STATIC,122,0,124,36 - LTEXT "Current",IDC_STATIC,130,11,26,8 - LTEXT "Limit",IDC_STATIC,130,23,15,8 - RTEXT "Static",IDC_ZSHAREDCURRENT_V,182,11,54,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZSHAREDLIMIT_V,182,23,54,8,SS_ENDELLIPSIS - PUSHBUTTON "Nodes",IDC_NODES,152,40,50,14 - LTEXT "Select nodes used for GPU usage calculations:",IDC_STATIC,0,43,148,8 -END - -IDD_PROCGPU DIALOGEX 0, 0, 369, 237 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "GPU" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - GROUPBOX "GPU",IDC_GROUPGPU,7,7,355,69 - GROUPBOX "Dedicated memory",IDC_GROUPMEM,7,81,355,69 - GROUPBOX "Shared memory",IDC_GROUPSHARED,7,160,355,69 -END - -IDD_SYSINFO_DISK DIALOGEX 0, 0, 315, 186 -STYLE DS_SETFONT | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME -CAPTION "Disk" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "Disk",IDC_TITLE,0,0,72,21 - LTEXT "Panel layout",IDC_PANEL_LAYOUT,0,124,315,61,NOT WS_VISIBLE - LTEXT "Graph layout",IDC_GRAPH_LAYOUT,0,22,315,99,NOT WS_VISIBLE -END - -IDD_SYSINFO_NETPANEL DIALOGEX 0, 0, 145, 58 -STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_SYSMENU -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - GROUPBOX "Network I/O",IDC_STATIC,0,0,145,58 - LTEXT "Receives delta",IDC_STATIC,8,11,48,8 - LTEXT "Receive bytes delta",IDC_STATIC,8,22,65,8 - LTEXT "Sends delta",IDC_STATIC,8,33,39,8 - LTEXT "Send bytes delta",IDC_STATIC,8,44,56,8 - RTEXT "Static",IDC_ZRECEIVESDELTA_V,84,11,54,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZRECEIVEBYTESDELTA_V,78,22,60,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZSENDSDELTA_V,84,33,54,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZSENDBYTESDELTA_V,82,44,56,8,SS_ENDELLIPSIS -END - -IDD_SYSINFO_NET DIALOGEX 0, 0, 315, 186 -STYLE DS_SETFONT | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME -CAPTION "Network" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "Network",IDC_TITLE,0,0,72,21 - LTEXT "Panel layout",IDC_PANEL_LAYOUT,0,124,315,61,NOT WS_VISIBLE - LTEXT "Graph layout",IDC_GRAPH_LAYOUT,0,22,315,99,NOT WS_VISIBLE -END - -IDD_GPUNODES DIALOGEX 0, 0, 317, 183 -STYLE DS_SETFONT | DS_FIXEDSYS | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME -CAPTION "GPU Nodes" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "Select the nodes that will be included in GPU usage calculations.",IDC_INSTRUCTION,7,7,204,8 - LTEXT "Graph layout",IDC_LAYOUT,7,21,303,137,NOT WS_VISIBLE - CONTROL "Example checkbox",IDC_EXAMPLE,"Button",BS_AUTOCHECKBOX | NOT WS_VISIBLE | WS_TABSTOP,7,166,75,10 - DEFPUSHBUTTON "OK",IDOK,260,162,50,14 -END - -IDD_PROCGPU_PANEL DIALOGEX 0, 0, 248, 46 -STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_SYSMENU -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - GROUPBOX "Memory",IDC_STATIC,2,0,118,46 - GROUPBOX "Nodes",IDC_STATIC,124,0,124,46 - LTEXT "Running time",IDC_STATIC,132,11,44,8 - LTEXT "Context switches",IDC_STATIC,132,22,57,8 - RTEXT "Static",IDC_ZRUNNINGTIME_V,184,11,54,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZCONTEXTSWITCHES_V,200,22,38,8,SS_ENDELLIPSIS - LTEXT "Total segments",IDC_STATIC,10,11,50,8 - RTEXT "Static",IDC_ZTOTALSEGMENTS_V,73,11,38,8,SS_ENDELLIPSIS - LTEXT "Total nodes",IDC_STATIC,132,33,39,8 - RTEXT "Static",IDC_ZTOTALNODES_V,200,33,38,8,SS_ENDELLIPSIS - PUSHBUTTON "More",IDC_GPUDETAILS,7,27,50,14 -END - -IDD_DISKTABERROR DIALOGEX 0, 0, 309, 176 -STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU -EXSTYLE WS_EX_TRANSPARENT -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "Disk monitoring requires Process Hacker to be restarted with administrative privileges.",IDC_ERROR,16,14,275,8 - PUSHBUTTON "Restart",IDC_RESTART,20,28,50,14 -END - -IDD_PROCDISKNET_PANEL DIALOGEX 0, 0, 248, 82 -STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - GROUPBOX "Disk I/O",IDC_STATIC,2,0,118,82 - LTEXT "Reads",IDC_STATIC,10,11,21,8 - LTEXT "Read bytes",IDC_STATIC,10,22,38,8 - LTEXT "Read bytes delta",IDC_STATIC,10,33,56,8 - LTEXT "Writes",IDC_STATIC,10,44,22,8 - LTEXT "Write bytes",IDC_STATIC,10,55,38,8 - LTEXT "Write bytes delta",IDC_STATIC,10,66,57,8 - RTEXT "Static",IDC_ZREADS_V,57,11,54,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZREADBYTES_V,73,22,38,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZREADBYTESDELTA_V,73,33,38,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZWRITES_V,57,44,54,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZWRITEBYTES_V,73,55,38,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZWRITEBYTESDELTA_V,73,66,38,8,SS_ENDELLIPSIS - GROUPBOX "Network I/O",IDC_STATIC,123,0,124,82 - LTEXT "Receives",IDC_STATIC,132,11,30,8 - LTEXT "Receive bytes",IDC_STATIC,132,23,46,8 - LTEXT "Receive bytes delta",IDC_STATIC,132,34,65,8 - LTEXT "Sends",IDC_STATIC,132,46,20,8 - LTEXT "Send bytes",IDC_STATIC,132,56,37,8 - LTEXT "Send bytes delta",IDC_STATIC,132,67,56,8 - RTEXT "Static",IDC_ZRECEIVES_V,184,11,54,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZRECEIVEBYTES_V,200,23,38,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZRECEIVEBYTESDELTA_V,200,34,38,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZSENDS_V,184,46,54,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZSENDBYTES_V,200,56,38,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZSENDBYTESDELTA_V,200,67,38,8,SS_ENDELLIPSIS -END - -IDD_PROCGPU_DETAILS DIALOGEX 0, 0, 181, 155 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "GPU Details" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - DEFPUSHBUTTON "Close",IDCANCEL,124,134,50,14 - GROUPBOX "System memory",IDC_STATIC,7,7,167,125 - LTEXT "Dedicated",IDC_STATIC,15,19,33,8 - LTEXT "Shared",IDC_STATIC,15,30,24,8 - RTEXT "Static",IDC_ZDEDICATEDCOMMITTED_V,111,19,54,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZSHAREDCOMMITTED_V,127,30,38,8,SS_ENDELLIPSIS - LTEXT "Total allocated",IDC_STATIC,15,41,48,8 - LTEXT "Total reserved",IDC_STATIC,15,51,50,8 - LTEXT "Write combined allocated",IDC_STATIC,15,62,83,8 - LTEXT "Write combined reserved",IDC_STATIC,15,73,84,8 - RTEXT "Static",IDC_ZTOTALALLOCATED_V,111,41,54,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZTOTALRESERVED_V,111,51,54,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZWRITECOMBINEDALLOCATED_V,111,62,54,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZWRITECOMBINEDRESERVED_V,111,73,54,8,SS_ENDELLIPSIS - LTEXT "Cached allocated",IDC_STATIC,15,84,56,8 - LTEXT "Cached reserved",IDC_STATIC,15,95,58,8 - LTEXT "Section allocated",IDC_STATIC,15,106,56,8 - LTEXT "Section reserved",IDC_STATIC,15,117,57,8 - RTEXT "Static",IDC_ZCACHEDALLOCATED_V,111,84,54,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZCACHEDRESERVED_V,111,95,54,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZSECTIONALLOCATED_V,111,106,54,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZSECTIONRESERVED_V,111,117,54,8,SS_ENDELLIPSIS -END - - -///////////////////////////////////////////////////////////////////////////// -// -// DESIGNINFO -// - -#ifdef APSTUDIO_INVOKED -GUIDELINES DESIGNINFO -BEGIN - IDD_UNLOADEDDLLS, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 335 - TOPMARGIN, 7 - BOTTOMMARGIN, 258 - END - - IDD_OBJALPCPORT, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 153 - TOPMARGIN, 7 - BOTTOMMARGIN, 94 - END - - IDD_OBJTPWORKERFACTORY, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 179 - TOPMARGIN, 7 - BOTTOMMARGIN, 94 - END - - IDD_MODSERVICES, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 269 - TOPMARGIN, 7 - BOTTOMMARGIN, 202 - END - - IDD_PROCDISKNET, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 258 - TOPMARGIN, 7 - BOTTOMMARGIN, 151 - END - - IDD_SYSINFO_DISKPANEL, DIALOG - BEGIN - END - - IDD_OPTIONS, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 208 - TOPMARGIN, 7 - BOTTOMMARGIN, 70 - END - - IDD_WSWATCH, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 318 - TOPMARGIN, 7 - BOTTOMMARGIN, 259 - END - - IDD_SYSINFO_GPU, DIALOG - BEGIN - END - - IDD_SYSINFO_GPUPANEL, DIALOG - BEGIN - END - - IDD_PROCGPU, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 362 - TOPMARGIN, 7 - BOTTOMMARGIN, 230 - END - - IDD_SYSINFO_DISK, DIALOG - BEGIN - END - - IDD_SYSINFO_NETPANEL, DIALOG - BEGIN - END - - IDD_SYSINFO_NET, DIALOG - BEGIN - END - - IDD_GPUNODES, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 310 - TOPMARGIN, 7 - BOTTOMMARGIN, 176 - END - - IDD_PROCGPU_PANEL, DIALOG - BEGIN - END - - IDD_DISKTABERROR, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 302 - TOPMARGIN, 7 - BOTTOMMARGIN, 169 - END - - IDD_PROCDISKNET_PANEL, DIALOG - BEGIN - END - - IDD_PROCGPU_DETAILS, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 174 - TOPMARGIN, 7 - BOTTOMMARGIN, 148 - END -END -#endif // APSTUDIO_INVOKED - - -///////////////////////////////////////////////////////////////////////////// -// -// Menu -// - -IDR_DISK MENU -BEGIN - POPUP "Disk" - BEGIN - MENUITEM "&Go to process", ID_DISK_GOTOPROCESS - MENUITEM SEPARATOR - MENUITEM "Open &file location\aEnter", ID_DISK_OPENFILELOCATION - MENUITEM "P&roperties", ID_DISK_PROPERTIES - MENUITEM "&Copy\aCtrl+C", ID_DISK_COPY - END -END - - -///////////////////////////////////////////////////////////////////////////// -// -// AFX_DIALOG_LAYOUT -// - -IDD_OBJTPWORKERFACTORY AFX_DIALOG_LAYOUT -BEGIN - 0 -END - -IDD_PROCGPU_DETAILS AFX_DIALOG_LAYOUT -BEGIN - 0 -END - -IDD_PROCGPU_PANEL AFX_DIALOG_LAYOUT -BEGIN - 0 -END - -IDD_OPTIONS AFX_DIALOG_LAYOUT -BEGIN - 0 -END - -#endif // English (Australia) resources -///////////////////////////////////////////////////////////////////////////// - - - -#ifndef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// - - -///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED - +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "winres.h" +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (Australia) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENA) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_AUS +#pragma code_page(1252) + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""winres.h""\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,17,0,0 + PRODUCTVERSION 1,17,0,0 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "0c0904b0" + BEGIN + VALUE "CompanyName", "wj32" + VALUE "FileDescription", "Extended Tools plugin for Process Hacker" + VALUE "FileVersion", "1.17" + VALUE "InternalName", "ProcessHacker.ExtendedTools" + VALUE "LegalCopyright", "Licensed under the GNU GPL, v3." + VALUE "OriginalFilename", "ExtendedTools.dll" + VALUE "ProductName", "Extended Tools plugin for Process Hacker" + VALUE "ProductVersion", "1.17" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0xc09, 1200 + END +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_UNLOADEDDLLS DIALOGEX 0, 0, 342, 265 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Unloaded Modules" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,7,328,233 + PUSHBUTTON "Refresh",IDC_REFRESH,7,244,50,14 + DEFPUSHBUTTON "Close",IDOK,285,244,50,14 +END + +IDD_OBJALPCPORT DIALOGEX 0, 0, 160, 101 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "ALPC Port" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "Sequence number: Unknown",IDC_SEQUENCENUMBER,7,7,146,8 + LTEXT "Port context: Unknown",IDC_PORTCONTEXT,7,19,146,8 +END + +IDD_OBJTPWORKERFACTORY DIALOGEX 0, 0, 186, 101 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Worker Factory" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "Worker thread start: Unknown",IDC_WORKERTHREADSTART,7,7,172,8,SS_ENDELLIPSIS + LTEXT "Worker thread context: Unknown",IDC_WORKERTHREADCONTEXT,7,18,172,8,SS_ENDELLIPSIS +END + +IDD_MODSERVICES DIALOGEX 0, 0, 276, 209 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Services" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "Static",IDC_MESSAGE,7,7,262,8 + LTEXT "Static",IDC_SERVICES_LAYOUT,7,22,262,162,NOT WS_VISIBLE + DEFPUSHBUTTON "Close",IDOK,219,188,50,14 +END + +IDD_PROCDISKNET DIALOGEX 0, 0, 265, 158 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Disk and Network" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + GROUPBOX "Disk",IDC_GROUPDISK,7,7,251,69 + GROUPBOX "Network",IDC_GROUPNETWORK,7,81,251,69 +END + +IDD_SYSINFO_DISKPANEL DIALOGEX 0, 0, 146, 58 +STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_SYSMENU +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + GROUPBOX "Disk I/O",IDC_STATIC,0,0,145,58 + LTEXT "Reads delta",IDC_STATIC,8,11,40,8 + LTEXT "Read bytes delta",IDC_STATIC,8,22,56,8 + LTEXT "Writes delta",IDC_STATIC,8,33,40,8 + LTEXT "Write bytes delta",IDC_STATIC,8,44,57,8 + RTEXT "Static",IDC_ZREADSDELTA_V,84,11,54,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZREADBYTESDELTA_V,78,22,60,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZWRITESDELTA_V,84,33,54,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZWRITEBYTESDELTA_V,82,44,56,8,SS_ENDELLIPSIS +END + +IDD_OPTIONS DIALOGEX 0, 0, 215, 77 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Options" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "Changes to settings will require a restart of Process Hacker.",IDC_STATIC,7,6,193,8 + CONTROL "Enable Disk and Network monitoring",IDC_ENABLEETWMONITOR, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,20,130,10 + CONTROL "Enable GPU monitoring",IDC_ENABLEGPUMONITOR,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,46,88,10 + PUSHBUTTON "Close",IDOK,158,56,50,14 + CONTROL "Enable Disk and Network graphs",IDC_ENABLESYSINFOGRAPHS, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,33,130,10 +END + +IDD_WSWATCH DIALOGEX 0, 0, 325, 266 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "WS Watch" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "Working set watch allows you to monitor page faults that occur in a process. You must enable WS watch for the process to start the monitoring. Once WS watch is enabled, it cannot be disabled.",IDC_STATIC,7,7,311,27 + PUSHBUTTON "Enable",IDC_ENABLE,7,37,50,14 + LTEXT "WS watch is enabled.",IDC_WSWATCHENABLED,63,40,119,8,NOT WS_VISIBLE + LTEXT "Page faults:",IDC_STATIC,7,54,40,8 + CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,65,311,175 + DEFPUSHBUTTON "Close",IDOK,268,245,50,14 +END + +IDD_SYSINFO_GPU DIALOGEX 0, 0, 315, 186 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME +CAPTION "GPU" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "GPU",IDC_TITLE,0,0,72,21 + RTEXT "GPU name",IDC_GPUNAME,83,4,232,16,SS_WORDELLIPSIS + LTEXT "Panel layout",IDC_PANEL_LAYOUT,0,130,315,55,NOT WS_VISIBLE + LTEXT "Graph layout",IDC_GRAPH_LAYOUT,0,22,315,102,NOT WS_VISIBLE + LTEXT "GPU:",IDC_GPU_L,73,0,17,8 + LTEXT "Dedicated memory:",IDC_DEDICATED_L,73,5,63,8 + LTEXT "Shared memory:",IDC_SHARED_L,74,11,54,8 +END + +IDD_SYSINFO_GPUPANEL DIALOGEX 0, 0, 246, 54 +STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_SYSMENU +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + GROUPBOX "Dedicated memory",IDC_STATIC,0,0,118,36 + LTEXT "Current",IDC_STATIC,8,11,26,8 + LTEXT "Limit",IDC_STATIC,8,22,15,8 + RTEXT "Static",IDC_ZDEDICATEDCURRENT_V,55,11,54,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZDEDICATEDLIMIT_V,55,22,54,8,SS_ENDELLIPSIS + GROUPBOX "Shared memory",IDC_STATIC,122,0,124,36 + LTEXT "Current",IDC_STATIC,130,11,26,8 + LTEXT "Limit",IDC_STATIC,130,23,15,8 + RTEXT "Static",IDC_ZSHAREDCURRENT_V,182,11,54,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZSHAREDLIMIT_V,182,23,54,8,SS_ENDELLIPSIS + PUSHBUTTON "Nodes",IDC_NODES,152,40,50,14 + LTEXT "Select nodes used for GPU usage calculations:",IDC_STATIC,0,43,148,8 +END + +IDD_PROCGPU DIALOGEX 0, 0, 369, 237 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "GPU" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + GROUPBOX "GPU",IDC_GROUPGPU,7,7,355,69 + GROUPBOX "Dedicated memory",IDC_GROUPMEM,7,81,355,69 + GROUPBOX "Shared memory",IDC_GROUPSHARED,7,160,355,69 +END + +IDD_SYSINFO_DISK DIALOGEX 0, 0, 315, 186 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME +CAPTION "Disk" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "Disk",IDC_TITLE,0,0,72,21 + LTEXT "Panel layout",IDC_PANEL_LAYOUT,0,124,315,61,NOT WS_VISIBLE + LTEXT "Graph layout",IDC_GRAPH_LAYOUT,0,22,315,99,NOT WS_VISIBLE +END + +IDD_SYSINFO_NETPANEL DIALOGEX 0, 0, 145, 58 +STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_SYSMENU +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + GROUPBOX "Network I/O",IDC_STATIC,0,0,145,58 + LTEXT "Receives delta",IDC_STATIC,8,11,48,8 + LTEXT "Receive bytes delta",IDC_STATIC,8,22,65,8 + LTEXT "Sends delta",IDC_STATIC,8,33,39,8 + LTEXT "Send bytes delta",IDC_STATIC,8,44,56,8 + RTEXT "Static",IDC_ZRECEIVESDELTA_V,84,11,54,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZRECEIVEBYTESDELTA_V,78,22,60,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZSENDSDELTA_V,84,33,54,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZSENDBYTESDELTA_V,82,44,56,8,SS_ENDELLIPSIS +END + +IDD_SYSINFO_NET DIALOGEX 0, 0, 315, 186 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME +CAPTION "Network" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "Network",IDC_TITLE,0,0,72,21 + LTEXT "Panel layout",IDC_PANEL_LAYOUT,0,124,315,61,NOT WS_VISIBLE + LTEXT "Graph layout",IDC_GRAPH_LAYOUT,0,22,315,99,NOT WS_VISIBLE +END + +IDD_GPUNODES DIALOGEX 0, 0, 317, 183 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME +CAPTION "GPU Nodes" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "Select the nodes that will be included in GPU usage calculations.",IDC_INSTRUCTION,7,7,204,8 + LTEXT "Graph layout",IDC_LAYOUT,7,21,303,137,NOT WS_VISIBLE + CONTROL "Example checkbox",IDC_EXAMPLE,"Button",BS_AUTOCHECKBOX | NOT WS_VISIBLE | WS_TABSTOP,7,166,75,10 + DEFPUSHBUTTON "OK",IDOK,260,162,50,14 +END + +IDD_PROCGPU_PANEL DIALOGEX 0, 0, 248, 46 +STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_SYSMENU +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + GROUPBOX "Memory",IDC_STATIC,2,0,118,46 + GROUPBOX "Nodes",IDC_STATIC,124,0,124,46 + LTEXT "Running time",IDC_STATIC,132,11,44,8 + LTEXT "Context switches",IDC_STATIC,132,22,57,8 + RTEXT "Static",IDC_ZRUNNINGTIME_V,184,11,54,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZCONTEXTSWITCHES_V,200,22,38,8,SS_ENDELLIPSIS + LTEXT "Total segments",IDC_STATIC,10,11,50,8 + RTEXT "Static",IDC_ZTOTALSEGMENTS_V,73,11,38,8,SS_ENDELLIPSIS + LTEXT "Total nodes",IDC_STATIC,132,33,39,8 + RTEXT "Static",IDC_ZTOTALNODES_V,200,33,38,8,SS_ENDELLIPSIS + PUSHBUTTON "More",IDC_GPUDETAILS,7,27,50,14 +END + +IDD_DISKTABERROR DIALOGEX 0, 0, 309, 176 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU +EXSTYLE WS_EX_TRANSPARENT +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "Disk monitoring requires Process Hacker to be restarted with administrative privileges.",IDC_ERROR,16,14,275,8 + PUSHBUTTON "Restart",IDC_RESTART,20,28,50,14 +END + +IDD_PROCDISKNET_PANEL DIALOGEX 0, 0, 248, 82 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + GROUPBOX "Disk I/O",IDC_STATIC,2,0,118,82 + LTEXT "Reads",IDC_STATIC,10,11,21,8 + LTEXT "Read bytes",IDC_STATIC,10,22,38,8 + LTEXT "Read bytes delta",IDC_STATIC,10,33,56,8 + LTEXT "Writes",IDC_STATIC,10,44,22,8 + LTEXT "Write bytes",IDC_STATIC,10,55,38,8 + LTEXT "Write bytes delta",IDC_STATIC,10,66,57,8 + RTEXT "Static",IDC_ZREADS_V,57,11,54,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZREADBYTES_V,73,22,38,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZREADBYTESDELTA_V,73,33,38,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZWRITES_V,57,44,54,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZWRITEBYTES_V,73,55,38,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZWRITEBYTESDELTA_V,73,66,38,8,SS_ENDELLIPSIS + GROUPBOX "Network I/O",IDC_STATIC,123,0,124,82 + LTEXT "Receives",IDC_STATIC,132,11,30,8 + LTEXT "Receive bytes",IDC_STATIC,132,23,46,8 + LTEXT "Receive bytes delta",IDC_STATIC,132,34,65,8 + LTEXT "Sends",IDC_STATIC,132,46,20,8 + LTEXT "Send bytes",IDC_STATIC,132,56,37,8 + LTEXT "Send bytes delta",IDC_STATIC,132,67,56,8 + RTEXT "Static",IDC_ZRECEIVES_V,184,11,54,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZRECEIVEBYTES_V,200,23,38,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZRECEIVEBYTESDELTA_V,200,34,38,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZSENDS_V,184,46,54,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZSENDBYTES_V,200,56,38,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZSENDBYTESDELTA_V,200,67,38,8,SS_ENDELLIPSIS +END + +IDD_PROCGPU_DETAILS DIALOGEX 0, 0, 181, 155 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "GPU Details" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + DEFPUSHBUTTON "Close",IDCANCEL,124,134,50,14 + GROUPBOX "System memory",IDC_STATIC,7,7,167,125 + LTEXT "Dedicated",IDC_STATIC,15,19,33,8 + LTEXT "Shared",IDC_STATIC,15,30,24,8 + RTEXT "Static",IDC_ZDEDICATEDCOMMITTED_V,111,19,54,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZSHAREDCOMMITTED_V,127,30,38,8,SS_ENDELLIPSIS + LTEXT "Total allocated",IDC_STATIC,15,41,48,8 + LTEXT "Total reserved",IDC_STATIC,15,51,50,8 + LTEXT "Write combined allocated",IDC_STATIC,15,62,83,8 + LTEXT "Write combined reserved",IDC_STATIC,15,73,84,8 + RTEXT "Static",IDC_ZTOTALALLOCATED_V,111,41,54,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZTOTALRESERVED_V,111,51,54,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZWRITECOMBINEDALLOCATED_V,111,62,54,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZWRITECOMBINEDRESERVED_V,111,73,54,8,SS_ENDELLIPSIS + LTEXT "Cached allocated",IDC_STATIC,15,84,56,8 + LTEXT "Cached reserved",IDC_STATIC,15,95,58,8 + LTEXT "Section allocated",IDC_STATIC,15,106,56,8 + LTEXT "Section reserved",IDC_STATIC,15,117,57,8 + RTEXT "Static",IDC_ZCACHEDALLOCATED_V,111,84,54,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZCACHEDRESERVED_V,111,95,54,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZSECTIONALLOCATED_V,111,106,54,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZSECTIONRESERVED_V,111,117,54,8,SS_ENDELLIPSIS +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_UNLOADEDDLLS, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 335 + TOPMARGIN, 7 + BOTTOMMARGIN, 258 + END + + IDD_OBJALPCPORT, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 153 + TOPMARGIN, 7 + BOTTOMMARGIN, 94 + END + + IDD_OBJTPWORKERFACTORY, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 179 + TOPMARGIN, 7 + BOTTOMMARGIN, 94 + END + + IDD_MODSERVICES, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 269 + TOPMARGIN, 7 + BOTTOMMARGIN, 202 + END + + IDD_PROCDISKNET, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 258 + TOPMARGIN, 7 + BOTTOMMARGIN, 151 + END + + IDD_SYSINFO_DISKPANEL, DIALOG + BEGIN + END + + IDD_OPTIONS, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 208 + TOPMARGIN, 7 + BOTTOMMARGIN, 70 + END + + IDD_WSWATCH, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 318 + TOPMARGIN, 7 + BOTTOMMARGIN, 259 + END + + IDD_SYSINFO_GPU, DIALOG + BEGIN + END + + IDD_SYSINFO_GPUPANEL, DIALOG + BEGIN + END + + IDD_PROCGPU, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 362 + TOPMARGIN, 7 + BOTTOMMARGIN, 230 + END + + IDD_SYSINFO_DISK, DIALOG + BEGIN + END + + IDD_SYSINFO_NETPANEL, DIALOG + BEGIN + END + + IDD_SYSINFO_NET, DIALOG + BEGIN + END + + IDD_GPUNODES, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 310 + TOPMARGIN, 7 + BOTTOMMARGIN, 176 + END + + IDD_PROCGPU_PANEL, DIALOG + BEGIN + END + + IDD_DISKTABERROR, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 302 + TOPMARGIN, 7 + BOTTOMMARGIN, 169 + END + + IDD_PROCDISKNET_PANEL, DIALOG + BEGIN + END + + IDD_PROCGPU_DETAILS, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 174 + TOPMARGIN, 7 + BOTTOMMARGIN, 148 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Menu +// + +IDR_DISK MENU +BEGIN + POPUP "Disk" + BEGIN + MENUITEM "&Go to process", ID_DISK_GOTOPROCESS + MENUITEM SEPARATOR + MENUITEM "Open &file location\aEnter", ID_DISK_OPENFILELOCATION + MENUITEM "P&roperties", ID_DISK_PROPERTIES + MENUITEM "&Copy\aCtrl+C", ID_DISK_COPY + END +END + + +///////////////////////////////////////////////////////////////////////////// +// +// AFX_DIALOG_LAYOUT +// + +IDD_OBJTPWORKERFACTORY AFX_DIALOG_LAYOUT +BEGIN + 0 +END + +IDD_PROCGPU_DETAILS AFX_DIALOG_LAYOUT +BEGIN + 0 +END + +IDD_PROCGPU_PANEL AFX_DIALOG_LAYOUT +BEGIN + 0 +END + +IDD_OPTIONS AFX_DIALOG_LAYOUT +BEGIN + 0 +END + +#endif // English (Australia) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/plugins/ExtendedTools/ExtendedTools.vcxproj b/plugins/ExtendedTools/ExtendedTools.vcxproj index 478dc51ff4c3..ea3f79282e4e 100644 --- a/plugins/ExtendedTools/ExtendedTools.vcxproj +++ b/plugins/ExtendedTools/ExtendedTools.vcxproj @@ -1,118 +1,118 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {3437FD16-A3BF-4938-883A-EB0DF1584A2A} - ExtendedTools - Win32Proj - ExtendedTools - 10.0.15063.0 - - - - DynamicLibrary - Unicode - v141 - - - DynamicLibrary - Unicode - v141 - - - DynamicLibrary - Unicode - v141 - - - DynamicLibrary - Unicode - v141 - - - - - - - - - cfgmgr32.lib;%(AdditionalDependencies) - - - - - cfgmgr32.lib;%(AdditionalDependencies) - - - - - cfgmgr32.lib;%(AdditionalDependencies) - - - - - cfgmgr32.lib;%(AdditionalDependencies) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {3437FD16-A3BF-4938-883A-EB0DF1584A2A} + ExtendedTools + Win32Proj + ExtendedTools + 10.0.15063.0 + + + + DynamicLibrary + Unicode + v141 + + + DynamicLibrary + Unicode + v141 + + + DynamicLibrary + Unicode + v141 + + + DynamicLibrary + Unicode + v141 + + + + + + + + + cfgmgr32.lib;%(AdditionalDependencies) + + + + + cfgmgr32.lib;%(AdditionalDependencies) + + + + + cfgmgr32.lib;%(AdditionalDependencies) + + + + + cfgmgr32.lib;%(AdditionalDependencies) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/plugins/ExtendedTools/d3dkmt.h b/plugins/ExtendedTools/d3dkmt.h index 863b3b9a3ee5..880cd9fd5f33 100644 --- a/plugins/ExtendedTools/d3dkmt.h +++ b/plugins/ExtendedTools/d3dkmt.h @@ -1,496 +1,496 @@ -#ifndef _D3DKMT_H -#define _D3DKMT_H - -// D3D definitions - -typedef ULONG D3DKMT_HANDLE; - -typedef struct _D3DKMT_OPENADAPTERFROMDEVICENAME -{ - _In_ PCWSTR pDeviceName; - _Out_ D3DKMT_HANDLE hAdapter; - _Out_ LUID AdapterLuid; -} D3DKMT_OPENADAPTERFROMDEVICENAME; - -typedef struct _D3DKMT_CLOSEADAPTER -{ - _In_ D3DKMT_HANDLE hAdapter; -} D3DKMT_CLOSEADAPTER; - -typedef enum _D3DKMT_QUERYRESULT_PREEMPTION_ATTEMPT_RESULT -{ - D3DKMT_PreemptionAttempt = 0, - D3DKMT_PreemptionAttemptSuccess = 1, - D3DKMT_PreemptionAttemptMissNoCommand = 2, - D3DKMT_PreemptionAttemptMissNotEnabled = 3, - D3DKMT_PreemptionAttemptMissNextFence = 4, - D3DKMT_PreemptionAttemptMissPagingCommand = 5, - D3DKMT_PreemptionAttemptMissSplittedCommand = 6, - D3DKMT_PreemptionAttemptMissFenceCommand= 7, - D3DKMT_PreemptionAttemptMissRenderPendingFlip = 8, - D3DKMT_PreemptionAttemptMissNotMakingProgress = 9, - D3DKMT_PreemptionAttemptMissLessPriority = 10, - D3DKMT_PreemptionAttemptMissRemainingQuantum = 11, - D3DKMT_PreemptionAttemptMissRemainingPreemptionQuantum = 12, - D3DKMT_PreemptionAttemptMissAlreadyPreempting = 13, - D3DKMT_PreemptionAttemptMissGlobalBlock = 14, - D3DKMT_PreemptionAttemptMissAlreadyRunning = 15, - D3DKMT_PreemptionAttemptStatisticsMax -} D3DKMT_QUERYRESULT_PREEMPTION_ATTEMPT_RESULT; - -typedef enum _D3DKMT_QUERYSTATISTICS_DMA_PACKET_TYPE -{ - D3DKMT_ClientRenderBuffer = 0, - D3DKMT_ClientPagingBuffer = 1, - D3DKMT_SystemPagingBuffer = 2, - D3DKMT_SystemPreemptionBuffer = 3, - D3DKMT_DmaPacketTypeMax -} D3DKMT_QUERYSTATISTICS_DMA_PACKET_TYPE; - -typedef enum _D3DKMT_QUERYSTATISTICS_QUEUE_PACKET_TYPE -{ - D3DKMT_RenderCommandBuffer = 0, - D3DKMT_DeferredCommandBuffer = 1, - D3DKMT_SystemCommandBuffer = 2, - D3DKMT_MmIoFlipCommandBuffer = 3, - D3DKMT_WaitCommandBuffer = 4, - D3DKMT_SignalCommandBuffer = 5, - D3DKMT_DeviceCommandBuffer = 6, - D3DKMT_SoftwareCommandBuffer = 7, - D3DKMT_QueuePacketTypeMax -} D3DKMT_QUERYSTATISTICS_QUEUE_PACKET_TYPE; - -typedef enum _D3DKMT_QUERYSTATISTICS_ALLOCATION_PRIORITY_CLASS -{ - D3DKMT_AllocationPriorityClassMinimum = 0, - D3DKMT_AllocationPriorityClassLow = 1, - D3DKMT_AllocationPriorityClassNormal = 2, - D3DKMT_AllocationPriorityClassHigh = 3, - D3DKMT_AllocationPriorityClassMaximum = 4, - D3DKMT_MaxAllocationPriorityClass -} D3DKMT_QUERYSTATISTICS_ALLOCATION_PRIORITY_CLASS; - -#define D3DKMT_QUERYSTATISTICS_SEGMENT_PREFERENCE_MAX 5 - -typedef struct _D3DKMT_QUERYSTATISTICS_COUNTER -{ - ULONG Count; - ULONGLONG Bytes; -} D3DKMT_QUERYSTATISTICS_COUNTER; - -typedef struct _D3DKMT_QUERYSTATISTICS_DMA_PACKET_TYPE_INFORMATION -{ - ULONG PacketSubmited; - ULONG PacketCompleted; - ULONG PacketPreempted; - ULONG PacketFaulted; -} D3DKMT_QUERYSTATISTICS_DMA_PACKET_TYPE_INFORMATION; - -typedef struct _D3DKMT_QUERYSTATISTICS_QUEUE_PACKET_TYPE_INFORMATION -{ - ULONG PacketSubmited; - ULONG PacketCompleted; -} D3DKMT_QUERYSTATISTICS_QUEUE_PACKET_TYPE_INFORMATION; - -typedef struct _D3DKMT_QUERYSTATISTICS_PACKET_INFORMATION -{ - D3DKMT_QUERYSTATISTICS_QUEUE_PACKET_TYPE_INFORMATION QueuePacket[D3DKMT_QueuePacketTypeMax]; - D3DKMT_QUERYSTATISTICS_DMA_PACKET_TYPE_INFORMATION DmaPacket[D3DKMT_DmaPacketTypeMax]; -} D3DKMT_QUERYSTATISTICS_PACKET_INFORMATION; - -typedef struct _D3DKMT_QUERYSTATISTICS_PREEMPTION_INFORMATION -{ - ULONG PreemptionCounter[D3DKMT_PreemptionAttemptStatisticsMax]; -} D3DKMT_QUERYSTATISTICS_PREEMPTION_INFORMATION; - -typedef struct _D3DKMT_QUERYSTATISTICS_PROCESS_NODE_INFORMATION -{ - LARGE_INTEGER RunningTime; // 100ns - ULONG ContextSwitch; - D3DKMT_QUERYSTATISTICS_PREEMPTION_INFORMATION PreemptionStatistics; - D3DKMT_QUERYSTATISTICS_PACKET_INFORMATION PacketStatistics; - ULONG64 Reserved[8]; -} D3DKMT_QUERYSTATISTICS_PROCESS_NODE_INFORMATION; - -typedef struct _D3DKMT_QUERYSTATISTICS_NODE_INFORMATION -{ - D3DKMT_QUERYSTATISTICS_PROCESS_NODE_INFORMATION GlobalInformation; // global - D3DKMT_QUERYSTATISTICS_PROCESS_NODE_INFORMATION SystemInformation; // system thread - ULONG64 Reserved[8]; -} D3DKMT_QUERYSTATISTICS_NODE_INFORMATION; - -typedef struct _D3DKMT_QUERYSTATISTICS_PROCESS_VIDPNSOURCE_INFORMATION -{ - ULONG Frame; - ULONG CancelledFrame; - ULONG QueuedPresent; - ULONG64 Reserved[8]; -} D3DKMT_QUERYSTATISTICS_PROCESS_VIDPNSOURCE_INFORMATION; - -typedef struct _D3DKMT_QUERYSTATISTICS_VIDPNSOURCE_INFORMATION -{ - D3DKMT_QUERYSTATISTICS_PROCESS_VIDPNSOURCE_INFORMATION GlobalInformation; // global - D3DKMT_QUERYSTATISTICS_PROCESS_VIDPNSOURCE_INFORMATION SystemInformation; // system thread - ULONG64 Reserved[8]; -} D3DKMT_QUERYSTATISTICS_VIDPNSOURCE_INFORMATION; - -typedef struct _D3DKMT_QUERYSTATSTICS_REFERENCE_DMA_BUFFER -{ - ULONG NbCall; - ULONG NbAllocationsReferenced; - ULONG MaxNbAllocationsReferenced; - ULONG NbNULLReference; - ULONG NbWriteReference; - ULONG NbRenamedAllocationsReferenced; - ULONG NbIterationSearchingRenamedAllocation; - ULONG NbLockedAllocationReferenced; - ULONG NbAllocationWithValidPrepatchingInfoReferenced; - ULONG NbAllocationWithInvalidPrepatchingInfoReferenced; - ULONG NbDMABufferSuccessfullyPrePatched; - ULONG NbPrimariesReferencesOverflow; - ULONG NbAllocationWithNonPreferredResources; - ULONG NbAllocationInsertedInMigrationTable; -} D3DKMT_QUERYSTATSTICS_REFERENCE_DMA_BUFFER; - -typedef struct _D3DKMT_QUERYSTATSTICS_RENAMING -{ - ULONG NbAllocationsRenamed; - ULONG NbAllocationsShrinked; - ULONG NbRenamedBuffer; - ULONG MaxRenamingListLength; - ULONG NbFailuresDueToRenamingLimit; - ULONG NbFailuresDueToCreateAllocation; - ULONG NbFailuresDueToOpenAllocation; - ULONG NbFailuresDueToLowResource; - ULONG NbFailuresDueToNonRetiredLimit; -} D3DKMT_QUERYSTATSTICS_RENAMING; - -typedef struct _D3DKMT_QUERYSTATSTICS_PREPRATION -{ - ULONG BroadcastStall; - ULONG NbDMAPrepared; - ULONG NbDMAPreparedLongPath; - ULONG ImmediateHighestPreparationPass; - D3DKMT_QUERYSTATISTICS_COUNTER AllocationsTrimmed; -} D3DKMT_QUERYSTATSTICS_PREPRATION; - -typedef struct _D3DKMT_QUERYSTATSTICS_PAGING_FAULT -{ - D3DKMT_QUERYSTATISTICS_COUNTER Faults; - D3DKMT_QUERYSTATISTICS_COUNTER FaultsFirstTimeAccess; - D3DKMT_QUERYSTATISTICS_COUNTER FaultsReclaimed; - D3DKMT_QUERYSTATISTICS_COUNTER FaultsMigration; - D3DKMT_QUERYSTATISTICS_COUNTER FaultsIncorrectResource; - D3DKMT_QUERYSTATISTICS_COUNTER FaultsLostContent; - D3DKMT_QUERYSTATISTICS_COUNTER FaultsEvicted; - D3DKMT_QUERYSTATISTICS_COUNTER AllocationsMEM_RESET; - D3DKMT_QUERYSTATISTICS_COUNTER AllocationsUnresetSuccess; - D3DKMT_QUERYSTATISTICS_COUNTER AllocationsUnresetFail; - ULONG AllocationsUnresetSuccessRead; - ULONG AllocationsUnresetFailRead; - - D3DKMT_QUERYSTATISTICS_COUNTER Evictions; - D3DKMT_QUERYSTATISTICS_COUNTER EvictionsDueToPreparation; - D3DKMT_QUERYSTATISTICS_COUNTER EvictionsDueToLock; - D3DKMT_QUERYSTATISTICS_COUNTER EvictionsDueToClose; - D3DKMT_QUERYSTATISTICS_COUNTER EvictionsDueToPurge; - D3DKMT_QUERYSTATISTICS_COUNTER EvictionsDueToSuspendCPUAccess; -} D3DKMT_QUERYSTATSTICS_PAGING_FAULT; - -typedef struct _D3DKMT_QUERYSTATSTICS_PAGING_TRANSFER -{ - ULONGLONG BytesFilled; - ULONGLONG BytesDiscarded; - ULONGLONG BytesMappedIntoAperture; - ULONGLONG BytesUnmappedFromAperture; - ULONGLONG BytesTransferredFromMdlToMemory; - ULONGLONG BytesTransferredFromMemoryToMdl; - ULONGLONG BytesTransferredFromApertureToMemory; - ULONGLONG BytesTransferredFromMemoryToAperture; -} D3DKMT_QUERYSTATSTICS_PAGING_TRANSFER; - -typedef struct _D3DKMT_QUERYSTATSTICS_SWIZZLING_RANGE -{ - ULONG NbRangesAcquired; - ULONG NbRangesReleased; -} D3DKMT_QUERYSTATSTICS_SWIZZLING_RANGE; - -typedef struct _D3DKMT_QUERYSTATSTICS_LOCKS -{ - ULONG NbLocks; - ULONG NbLocksWaitFlag; - ULONG NbLocksDiscardFlag; - ULONG NbLocksNoOverwrite; - ULONG NbLocksNoReadSync; - ULONG NbLocksLinearization; - ULONG NbComplexLocks; -} D3DKMT_QUERYSTATSTICS_LOCKS; - -typedef struct _D3DKMT_QUERYSTATSTICS_ALLOCATIONS -{ - D3DKMT_QUERYSTATISTICS_COUNTER Created; - D3DKMT_QUERYSTATISTICS_COUNTER Destroyed; - D3DKMT_QUERYSTATISTICS_COUNTER Opened; - D3DKMT_QUERYSTATISTICS_COUNTER Closed; - D3DKMT_QUERYSTATISTICS_COUNTER MigratedSuccess; - D3DKMT_QUERYSTATISTICS_COUNTER MigratedFail; - D3DKMT_QUERYSTATISTICS_COUNTER MigratedAbandoned; -} D3DKMT_QUERYSTATSTICS_ALLOCATIONS; - -typedef struct _D3DKMT_QUERYSTATSTICS_TERMINATIONS -{ - D3DKMT_QUERYSTATISTICS_COUNTER TerminatedShared; - D3DKMT_QUERYSTATISTICS_COUNTER TerminatedNonShared; - D3DKMT_QUERYSTATISTICS_COUNTER DestroyedShared; - D3DKMT_QUERYSTATISTICS_COUNTER DestroyedNonShared; -} D3DKMT_QUERYSTATSTICS_TERMINATIONS; - -typedef struct _D3DKMT_QUERYSTATISTICS_ADAPTER_INFORMATION -{ - ULONG NbSegments; - ULONG NodeCount; - ULONG VidPnSourceCount; - - ULONG VSyncEnabled; - ULONG TdrDetectedCount; - - LONGLONG ZeroLengthDmaBuffers; - ULONGLONG RestartedPeriod; - - D3DKMT_QUERYSTATSTICS_REFERENCE_DMA_BUFFER ReferenceDmaBuffer; - D3DKMT_QUERYSTATSTICS_RENAMING Renaming; - D3DKMT_QUERYSTATSTICS_PREPRATION Preparation; - D3DKMT_QUERYSTATSTICS_PAGING_FAULT PagingFault; - D3DKMT_QUERYSTATSTICS_PAGING_TRANSFER PagingTransfer; - D3DKMT_QUERYSTATSTICS_SWIZZLING_RANGE SwizzlingRange; - D3DKMT_QUERYSTATSTICS_LOCKS Locks; - D3DKMT_QUERYSTATSTICS_ALLOCATIONS Allocations; - D3DKMT_QUERYSTATSTICS_TERMINATIONS Terminations; - - ULONG64 Reserved[8]; -} D3DKMT_QUERYSTATISTICS_ADAPTER_INFORMATION; - -typedef struct _D3DKMT_QUERYSTATISTICS_SYSTEM_MEMORY -{ - ULONGLONG BytesAllocated; - ULONGLONG BytesReserved; - ULONG SmallAllocationBlocks; - ULONG LargeAllocationBlocks; - ULONGLONG WriteCombinedBytesAllocated; - ULONGLONG WriteCombinedBytesReserved; - ULONGLONG CachedBytesAllocated; - ULONGLONG CachedBytesReserved; - ULONGLONG SectionBytesAllocated; - ULONGLONG SectionBytesReserved; -} D3DKMT_QUERYSTATISTICS_SYSTEM_MEMORY; - -typedef struct _D3DKMT_QUERYSTATISTICS_PROCESS_INFORMATION -{ - ULONG NodeCount; - ULONG VidPnSourceCount; - - D3DKMT_QUERYSTATISTICS_SYSTEM_MEMORY SystemMemory; - - ULONG64 Reserved[8]; -} D3DKMT_QUERYSTATISTICS_PROCESS_INFORMATION; - -typedef struct _D3DKMT_QUERYSTATISTICS_DMA_BUFFER -{ - D3DKMT_QUERYSTATISTICS_COUNTER Size; - ULONG AllocationListBytes; - ULONG PatchLocationListBytes; -} D3DKMT_QUERYSTATISTICS_DMA_BUFFER; - -typedef struct _D3DKMT_QUERYSTATISTICS_COMMITMENT_DATA -{ - ULONG64 TotalBytesEvictedFromProcess; - ULONG64 BytesBySegmentPreference[D3DKMT_QUERYSTATISTICS_SEGMENT_PREFERENCE_MAX]; -} D3DKMT_QUERYSTATISTICS_COMMITMENT_DATA; - -typedef struct _D3DKMT_QUERYSTATISTICS_POLICY -{ - ULONGLONG PreferApertureForRead[D3DKMT_MaxAllocationPriorityClass]; - ULONGLONG PreferAperture[D3DKMT_MaxAllocationPriorityClass]; - ULONGLONG MemResetOnPaging; - ULONGLONG RemovePagesFromWorkingSetOnPaging; - ULONGLONG MigrationEnabled; -} D3DKMT_QUERYSTATISTICS_POLICY; - -typedef struct _D3DKMT_QUERYSTATISTICS_PROCESS_ADAPTER_INFORMATION -{ - ULONG NbSegments; - ULONG NodeCount; - ULONG VidPnSourceCount; - - ULONG VirtualMemoryUsage; - - D3DKMT_QUERYSTATISTICS_DMA_BUFFER DmaBuffer; - D3DKMT_QUERYSTATISTICS_COMMITMENT_DATA CommitmentData; - D3DKMT_QUERYSTATISTICS_POLICY _Policy; - - ULONG64 Reserved[8]; -} D3DKMT_QUERYSTATISTICS_PROCESS_ADAPTER_INFORMATION; - -typedef struct _D3DKMT_QUERYSTATISTICS_MEMORY -{ - ULONGLONG TotalBytesEvicted; - ULONG AllocsCommitted; - ULONG AllocsResident; -} D3DKMT_QUERYSTATISTICS_MEMORY; - -typedef struct _D3DKMT_QUERYSTATISTICS_SEGMENT_INFORMATION_V1 -{ - ULONG CommitLimit; - ULONG BytesCommitted; - ULONG BytesResident; - - D3DKMT_QUERYSTATISTICS_MEMORY Memory; - - ULONG Aperture; // boolean - - ULONGLONG TotalBytesEvictedByPriority[D3DKMT_MaxAllocationPriorityClass]; - - ULONG64 SystemMemoryEndAddress; - struct - { - ULONG64 PreservedDuringStandby : 1; - ULONG64 PreservedDuringHibernate : 1; - ULONG64 PartiallyPreservedDuringHibernate : 1; - ULONG64 Reserved : 61; - } PowerFlags; - - ULONG64 Reserved[7]; -} D3DKMT_QUERYSTATISTICS_SEGMENT_INFORMATION_V1; - -typedef struct _D3DKMT_QUERYSTATISTICS_SEGMENT_INFORMATION -{ - ULONGLONG CommitLimit; - ULONGLONG BytesCommitted; - ULONGLONG BytesResident; - - D3DKMT_QUERYSTATISTICS_MEMORY Memory; - - ULONG Aperture; // boolean - - ULONGLONG TotalBytesEvictedByPriority[D3DKMT_MaxAllocationPriorityClass]; - - ULONG64 SystemMemoryEndAddress; - struct - { - ULONG64 PreservedDuringStandby : 1; - ULONG64 PreservedDuringHibernate : 1; - ULONG64 PartiallyPreservedDuringHibernate : 1; - ULONG64 Reserved : 61; - } PowerFlags; - - ULONG64 Reserved[6]; -} D3DKMT_QUERYSTATISTICS_SEGMENT_INFORMATION; - -typedef struct _D3DKMT_QUERYSTATISTICS_VIDEO_MEMORY -{ - ULONG AllocsCommitted; - D3DKMT_QUERYSTATISTICS_COUNTER AllocsResidentInP[D3DKMT_QUERYSTATISTICS_SEGMENT_PREFERENCE_MAX]; - D3DKMT_QUERYSTATISTICS_COUNTER AllocsResidentInNonPreferred; - ULONGLONG TotalBytesEvictedDueToPreparation; -} D3DKMT_QUERYSTATISTICS_VIDEO_MEMORY; - -typedef struct _D3DKMT_QUERYSTATISTICS_PROCESS_SEGMENT_POLICY -{ - ULONGLONG UseMRU; -} D3DKMT_QUERYSTATISTICS_PROCESS_SEGMENT_POLICY; - -typedef struct _D3DKMT_QUERYSTATISTICS_PROCESS_SEGMENT_INFORMATION -{ - ULONGLONG BytesCommitted; - ULONGLONG MaximumWorkingSet; - ULONGLONG MinimumWorkingSet; - - ULONG NbReferencedAllocationEvictedInPeriod; - - D3DKMT_QUERYSTATISTICS_VIDEO_MEMORY VideoMemory; - D3DKMT_QUERYSTATISTICS_PROCESS_SEGMENT_POLICY _Policy; - - ULONG64 Reserved[8]; -} D3DKMT_QUERYSTATISTICS_PROCESS_SEGMENT_INFORMATION; - -typedef enum _D3DKMT_QUERYSTATISTICS_TYPE -{ - D3DKMT_QUERYSTATISTICS_ADAPTER = 0, - D3DKMT_QUERYSTATISTICS_PROCESS = 1, - D3DKMT_QUERYSTATISTICS_PROCESS_ADAPTER = 2, - D3DKMT_QUERYSTATISTICS_SEGMENT = 3, - D3DKMT_QUERYSTATISTICS_PROCESS_SEGMENT = 4, - D3DKMT_QUERYSTATISTICS_NODE = 5, - D3DKMT_QUERYSTATISTICS_PROCESS_NODE = 6, - D3DKMT_QUERYSTATISTICS_VIDPNSOURCE = 7, - D3DKMT_QUERYSTATISTICS_PROCESS_VIDPNSOURCE = 8 -} D3DKMT_QUERYSTATISTICS_TYPE; - -typedef struct _D3DKMT_QUERYSTATISTICS_QUERY_SEGMENT -{ - ULONG SegmentId; -} D3DKMT_QUERYSTATISTICS_QUERY_SEGMENT; - -typedef struct _D3DKMT_QUERYSTATISTICS_QUERY_NODE -{ - ULONG NodeId; -} D3DKMT_QUERYSTATISTICS_QUERY_NODE; - -typedef struct _D3DKMT_QUERYSTATISTICS_QUERY_VIDPNSOURCE -{ - ULONG VidPnSourceId; -} D3DKMT_QUERYSTATISTICS_QUERY_VIDPNSOURCE; - -typedef union _D3DKMT_QUERYSTATISTICS_RESULT -{ - D3DKMT_QUERYSTATISTICS_ADAPTER_INFORMATION AdapterInformation; - D3DKMT_QUERYSTATISTICS_SEGMENT_INFORMATION_V1 SegmentInformationV1; // WIN7 - D3DKMT_QUERYSTATISTICS_SEGMENT_INFORMATION SegmentInformation; // WIN8 - D3DKMT_QUERYSTATISTICS_NODE_INFORMATION NodeInformation; - D3DKMT_QUERYSTATISTICS_VIDPNSOURCE_INFORMATION VidPnSourceInformation; - D3DKMT_QUERYSTATISTICS_PROCESS_INFORMATION ProcessInformation; - D3DKMT_QUERYSTATISTICS_PROCESS_ADAPTER_INFORMATION ProcessAdapterInformation; - D3DKMT_QUERYSTATISTICS_PROCESS_SEGMENT_INFORMATION ProcessSegmentInformation; - D3DKMT_QUERYSTATISTICS_PROCESS_NODE_INFORMATION ProcessNodeInformation; - D3DKMT_QUERYSTATISTICS_PROCESS_VIDPNSOURCE_INFORMATION ProcessVidPnSourceInformation; -} D3DKMT_QUERYSTATISTICS_RESULT; - -typedef struct _D3DKMT_QUERYSTATISTICS -{ - _In_ D3DKMT_QUERYSTATISTICS_TYPE Type; - _In_ LUID AdapterLuid; - _In_opt_ HANDLE hProcess; - _Out_ D3DKMT_QUERYSTATISTICS_RESULT QueryResult; - - union - { - _In_ D3DKMT_QUERYSTATISTICS_QUERY_SEGMENT QuerySegment; - _In_ D3DKMT_QUERYSTATISTICS_QUERY_SEGMENT QueryProcessSegment; - _In_ D3DKMT_QUERYSTATISTICS_QUERY_NODE QueryNode; - _In_ D3DKMT_QUERYSTATISTICS_QUERY_NODE QueryProcessNode; - _In_ D3DKMT_QUERYSTATISTICS_QUERY_VIDPNSOURCE QueryVidPnSource; - _In_ D3DKMT_QUERYSTATISTICS_QUERY_VIDPNSOURCE QueryProcessVidPnSource; - }; -} D3DKMT_QUERYSTATISTICS; - -// Function pointers - -// https://msdn.microsoft.com/en-us/library/ff547033.aspx -_Check_return_ -NTSTATUS D3DKMTOpenAdapterFromDeviceName( - _Inout_ D3DKMT_OPENADAPTERFROMDEVICENAME *pData - ); - -// https://msdn.microsoft.com/en-us/library/ff546787.aspx -_Check_return_ -NTSTATUS D3DKMTCloseAdapter( - _In_ const D3DKMT_CLOSEADAPTER *pData - ); - -// rev -_Check_return_ -NTSTATUS D3DKMTQueryStatistics( - _Inout_ const D3DKMT_QUERYSTATISTICS *pData - ); - -#endif +#ifndef _D3DKMT_H +#define _D3DKMT_H + +// D3D definitions + +typedef ULONG D3DKMT_HANDLE; + +typedef struct _D3DKMT_OPENADAPTERFROMDEVICENAME +{ + _In_ PCWSTR pDeviceName; + _Out_ D3DKMT_HANDLE hAdapter; + _Out_ LUID AdapterLuid; +} D3DKMT_OPENADAPTERFROMDEVICENAME; + +typedef struct _D3DKMT_CLOSEADAPTER +{ + _In_ D3DKMT_HANDLE hAdapter; +} D3DKMT_CLOSEADAPTER; + +typedef enum _D3DKMT_QUERYRESULT_PREEMPTION_ATTEMPT_RESULT +{ + D3DKMT_PreemptionAttempt = 0, + D3DKMT_PreemptionAttemptSuccess = 1, + D3DKMT_PreemptionAttemptMissNoCommand = 2, + D3DKMT_PreemptionAttemptMissNotEnabled = 3, + D3DKMT_PreemptionAttemptMissNextFence = 4, + D3DKMT_PreemptionAttemptMissPagingCommand = 5, + D3DKMT_PreemptionAttemptMissSplittedCommand = 6, + D3DKMT_PreemptionAttemptMissFenceCommand= 7, + D3DKMT_PreemptionAttemptMissRenderPendingFlip = 8, + D3DKMT_PreemptionAttemptMissNotMakingProgress = 9, + D3DKMT_PreemptionAttemptMissLessPriority = 10, + D3DKMT_PreemptionAttemptMissRemainingQuantum = 11, + D3DKMT_PreemptionAttemptMissRemainingPreemptionQuantum = 12, + D3DKMT_PreemptionAttemptMissAlreadyPreempting = 13, + D3DKMT_PreemptionAttemptMissGlobalBlock = 14, + D3DKMT_PreemptionAttemptMissAlreadyRunning = 15, + D3DKMT_PreemptionAttemptStatisticsMax +} D3DKMT_QUERYRESULT_PREEMPTION_ATTEMPT_RESULT; + +typedef enum _D3DKMT_QUERYSTATISTICS_DMA_PACKET_TYPE +{ + D3DKMT_ClientRenderBuffer = 0, + D3DKMT_ClientPagingBuffer = 1, + D3DKMT_SystemPagingBuffer = 2, + D3DKMT_SystemPreemptionBuffer = 3, + D3DKMT_DmaPacketTypeMax +} D3DKMT_QUERYSTATISTICS_DMA_PACKET_TYPE; + +typedef enum _D3DKMT_QUERYSTATISTICS_QUEUE_PACKET_TYPE +{ + D3DKMT_RenderCommandBuffer = 0, + D3DKMT_DeferredCommandBuffer = 1, + D3DKMT_SystemCommandBuffer = 2, + D3DKMT_MmIoFlipCommandBuffer = 3, + D3DKMT_WaitCommandBuffer = 4, + D3DKMT_SignalCommandBuffer = 5, + D3DKMT_DeviceCommandBuffer = 6, + D3DKMT_SoftwareCommandBuffer = 7, + D3DKMT_QueuePacketTypeMax +} D3DKMT_QUERYSTATISTICS_QUEUE_PACKET_TYPE; + +typedef enum _D3DKMT_QUERYSTATISTICS_ALLOCATION_PRIORITY_CLASS +{ + D3DKMT_AllocationPriorityClassMinimum = 0, + D3DKMT_AllocationPriorityClassLow = 1, + D3DKMT_AllocationPriorityClassNormal = 2, + D3DKMT_AllocationPriorityClassHigh = 3, + D3DKMT_AllocationPriorityClassMaximum = 4, + D3DKMT_MaxAllocationPriorityClass +} D3DKMT_QUERYSTATISTICS_ALLOCATION_PRIORITY_CLASS; + +#define D3DKMT_QUERYSTATISTICS_SEGMENT_PREFERENCE_MAX 5 + +typedef struct _D3DKMT_QUERYSTATISTICS_COUNTER +{ + ULONG Count; + ULONGLONG Bytes; +} D3DKMT_QUERYSTATISTICS_COUNTER; + +typedef struct _D3DKMT_QUERYSTATISTICS_DMA_PACKET_TYPE_INFORMATION +{ + ULONG PacketSubmited; + ULONG PacketCompleted; + ULONG PacketPreempted; + ULONG PacketFaulted; +} D3DKMT_QUERYSTATISTICS_DMA_PACKET_TYPE_INFORMATION; + +typedef struct _D3DKMT_QUERYSTATISTICS_QUEUE_PACKET_TYPE_INFORMATION +{ + ULONG PacketSubmited; + ULONG PacketCompleted; +} D3DKMT_QUERYSTATISTICS_QUEUE_PACKET_TYPE_INFORMATION; + +typedef struct _D3DKMT_QUERYSTATISTICS_PACKET_INFORMATION +{ + D3DKMT_QUERYSTATISTICS_QUEUE_PACKET_TYPE_INFORMATION QueuePacket[D3DKMT_QueuePacketTypeMax]; + D3DKMT_QUERYSTATISTICS_DMA_PACKET_TYPE_INFORMATION DmaPacket[D3DKMT_DmaPacketTypeMax]; +} D3DKMT_QUERYSTATISTICS_PACKET_INFORMATION; + +typedef struct _D3DKMT_QUERYSTATISTICS_PREEMPTION_INFORMATION +{ + ULONG PreemptionCounter[D3DKMT_PreemptionAttemptStatisticsMax]; +} D3DKMT_QUERYSTATISTICS_PREEMPTION_INFORMATION; + +typedef struct _D3DKMT_QUERYSTATISTICS_PROCESS_NODE_INFORMATION +{ + LARGE_INTEGER RunningTime; // 100ns + ULONG ContextSwitch; + D3DKMT_QUERYSTATISTICS_PREEMPTION_INFORMATION PreemptionStatistics; + D3DKMT_QUERYSTATISTICS_PACKET_INFORMATION PacketStatistics; + ULONG64 Reserved[8]; +} D3DKMT_QUERYSTATISTICS_PROCESS_NODE_INFORMATION; + +typedef struct _D3DKMT_QUERYSTATISTICS_NODE_INFORMATION +{ + D3DKMT_QUERYSTATISTICS_PROCESS_NODE_INFORMATION GlobalInformation; // global + D3DKMT_QUERYSTATISTICS_PROCESS_NODE_INFORMATION SystemInformation; // system thread + ULONG64 Reserved[8]; +} D3DKMT_QUERYSTATISTICS_NODE_INFORMATION; + +typedef struct _D3DKMT_QUERYSTATISTICS_PROCESS_VIDPNSOURCE_INFORMATION +{ + ULONG Frame; + ULONG CancelledFrame; + ULONG QueuedPresent; + ULONG64 Reserved[8]; +} D3DKMT_QUERYSTATISTICS_PROCESS_VIDPNSOURCE_INFORMATION; + +typedef struct _D3DKMT_QUERYSTATISTICS_VIDPNSOURCE_INFORMATION +{ + D3DKMT_QUERYSTATISTICS_PROCESS_VIDPNSOURCE_INFORMATION GlobalInformation; // global + D3DKMT_QUERYSTATISTICS_PROCESS_VIDPNSOURCE_INFORMATION SystemInformation; // system thread + ULONG64 Reserved[8]; +} D3DKMT_QUERYSTATISTICS_VIDPNSOURCE_INFORMATION; + +typedef struct _D3DKMT_QUERYSTATSTICS_REFERENCE_DMA_BUFFER +{ + ULONG NbCall; + ULONG NbAllocationsReferenced; + ULONG MaxNbAllocationsReferenced; + ULONG NbNULLReference; + ULONG NbWriteReference; + ULONG NbRenamedAllocationsReferenced; + ULONG NbIterationSearchingRenamedAllocation; + ULONG NbLockedAllocationReferenced; + ULONG NbAllocationWithValidPrepatchingInfoReferenced; + ULONG NbAllocationWithInvalidPrepatchingInfoReferenced; + ULONG NbDMABufferSuccessfullyPrePatched; + ULONG NbPrimariesReferencesOverflow; + ULONG NbAllocationWithNonPreferredResources; + ULONG NbAllocationInsertedInMigrationTable; +} D3DKMT_QUERYSTATSTICS_REFERENCE_DMA_BUFFER; + +typedef struct _D3DKMT_QUERYSTATSTICS_RENAMING +{ + ULONG NbAllocationsRenamed; + ULONG NbAllocationsShrinked; + ULONG NbRenamedBuffer; + ULONG MaxRenamingListLength; + ULONG NbFailuresDueToRenamingLimit; + ULONG NbFailuresDueToCreateAllocation; + ULONG NbFailuresDueToOpenAllocation; + ULONG NbFailuresDueToLowResource; + ULONG NbFailuresDueToNonRetiredLimit; +} D3DKMT_QUERYSTATSTICS_RENAMING; + +typedef struct _D3DKMT_QUERYSTATSTICS_PREPRATION +{ + ULONG BroadcastStall; + ULONG NbDMAPrepared; + ULONG NbDMAPreparedLongPath; + ULONG ImmediateHighestPreparationPass; + D3DKMT_QUERYSTATISTICS_COUNTER AllocationsTrimmed; +} D3DKMT_QUERYSTATSTICS_PREPRATION; + +typedef struct _D3DKMT_QUERYSTATSTICS_PAGING_FAULT +{ + D3DKMT_QUERYSTATISTICS_COUNTER Faults; + D3DKMT_QUERYSTATISTICS_COUNTER FaultsFirstTimeAccess; + D3DKMT_QUERYSTATISTICS_COUNTER FaultsReclaimed; + D3DKMT_QUERYSTATISTICS_COUNTER FaultsMigration; + D3DKMT_QUERYSTATISTICS_COUNTER FaultsIncorrectResource; + D3DKMT_QUERYSTATISTICS_COUNTER FaultsLostContent; + D3DKMT_QUERYSTATISTICS_COUNTER FaultsEvicted; + D3DKMT_QUERYSTATISTICS_COUNTER AllocationsMEM_RESET; + D3DKMT_QUERYSTATISTICS_COUNTER AllocationsUnresetSuccess; + D3DKMT_QUERYSTATISTICS_COUNTER AllocationsUnresetFail; + ULONG AllocationsUnresetSuccessRead; + ULONG AllocationsUnresetFailRead; + + D3DKMT_QUERYSTATISTICS_COUNTER Evictions; + D3DKMT_QUERYSTATISTICS_COUNTER EvictionsDueToPreparation; + D3DKMT_QUERYSTATISTICS_COUNTER EvictionsDueToLock; + D3DKMT_QUERYSTATISTICS_COUNTER EvictionsDueToClose; + D3DKMT_QUERYSTATISTICS_COUNTER EvictionsDueToPurge; + D3DKMT_QUERYSTATISTICS_COUNTER EvictionsDueToSuspendCPUAccess; +} D3DKMT_QUERYSTATSTICS_PAGING_FAULT; + +typedef struct _D3DKMT_QUERYSTATSTICS_PAGING_TRANSFER +{ + ULONGLONG BytesFilled; + ULONGLONG BytesDiscarded; + ULONGLONG BytesMappedIntoAperture; + ULONGLONG BytesUnmappedFromAperture; + ULONGLONG BytesTransferredFromMdlToMemory; + ULONGLONG BytesTransferredFromMemoryToMdl; + ULONGLONG BytesTransferredFromApertureToMemory; + ULONGLONG BytesTransferredFromMemoryToAperture; +} D3DKMT_QUERYSTATSTICS_PAGING_TRANSFER; + +typedef struct _D3DKMT_QUERYSTATSTICS_SWIZZLING_RANGE +{ + ULONG NbRangesAcquired; + ULONG NbRangesReleased; +} D3DKMT_QUERYSTATSTICS_SWIZZLING_RANGE; + +typedef struct _D3DKMT_QUERYSTATSTICS_LOCKS +{ + ULONG NbLocks; + ULONG NbLocksWaitFlag; + ULONG NbLocksDiscardFlag; + ULONG NbLocksNoOverwrite; + ULONG NbLocksNoReadSync; + ULONG NbLocksLinearization; + ULONG NbComplexLocks; +} D3DKMT_QUERYSTATSTICS_LOCKS; + +typedef struct _D3DKMT_QUERYSTATSTICS_ALLOCATIONS +{ + D3DKMT_QUERYSTATISTICS_COUNTER Created; + D3DKMT_QUERYSTATISTICS_COUNTER Destroyed; + D3DKMT_QUERYSTATISTICS_COUNTER Opened; + D3DKMT_QUERYSTATISTICS_COUNTER Closed; + D3DKMT_QUERYSTATISTICS_COUNTER MigratedSuccess; + D3DKMT_QUERYSTATISTICS_COUNTER MigratedFail; + D3DKMT_QUERYSTATISTICS_COUNTER MigratedAbandoned; +} D3DKMT_QUERYSTATSTICS_ALLOCATIONS; + +typedef struct _D3DKMT_QUERYSTATSTICS_TERMINATIONS +{ + D3DKMT_QUERYSTATISTICS_COUNTER TerminatedShared; + D3DKMT_QUERYSTATISTICS_COUNTER TerminatedNonShared; + D3DKMT_QUERYSTATISTICS_COUNTER DestroyedShared; + D3DKMT_QUERYSTATISTICS_COUNTER DestroyedNonShared; +} D3DKMT_QUERYSTATSTICS_TERMINATIONS; + +typedef struct _D3DKMT_QUERYSTATISTICS_ADAPTER_INFORMATION +{ + ULONG NbSegments; + ULONG NodeCount; + ULONG VidPnSourceCount; + + ULONG VSyncEnabled; + ULONG TdrDetectedCount; + + LONGLONG ZeroLengthDmaBuffers; + ULONGLONG RestartedPeriod; + + D3DKMT_QUERYSTATSTICS_REFERENCE_DMA_BUFFER ReferenceDmaBuffer; + D3DKMT_QUERYSTATSTICS_RENAMING Renaming; + D3DKMT_QUERYSTATSTICS_PREPRATION Preparation; + D3DKMT_QUERYSTATSTICS_PAGING_FAULT PagingFault; + D3DKMT_QUERYSTATSTICS_PAGING_TRANSFER PagingTransfer; + D3DKMT_QUERYSTATSTICS_SWIZZLING_RANGE SwizzlingRange; + D3DKMT_QUERYSTATSTICS_LOCKS Locks; + D3DKMT_QUERYSTATSTICS_ALLOCATIONS Allocations; + D3DKMT_QUERYSTATSTICS_TERMINATIONS Terminations; + + ULONG64 Reserved[8]; +} D3DKMT_QUERYSTATISTICS_ADAPTER_INFORMATION; + +typedef struct _D3DKMT_QUERYSTATISTICS_SYSTEM_MEMORY +{ + ULONGLONG BytesAllocated; + ULONGLONG BytesReserved; + ULONG SmallAllocationBlocks; + ULONG LargeAllocationBlocks; + ULONGLONG WriteCombinedBytesAllocated; + ULONGLONG WriteCombinedBytesReserved; + ULONGLONG CachedBytesAllocated; + ULONGLONG CachedBytesReserved; + ULONGLONG SectionBytesAllocated; + ULONGLONG SectionBytesReserved; +} D3DKMT_QUERYSTATISTICS_SYSTEM_MEMORY; + +typedef struct _D3DKMT_QUERYSTATISTICS_PROCESS_INFORMATION +{ + ULONG NodeCount; + ULONG VidPnSourceCount; + + D3DKMT_QUERYSTATISTICS_SYSTEM_MEMORY SystemMemory; + + ULONG64 Reserved[8]; +} D3DKMT_QUERYSTATISTICS_PROCESS_INFORMATION; + +typedef struct _D3DKMT_QUERYSTATISTICS_DMA_BUFFER +{ + D3DKMT_QUERYSTATISTICS_COUNTER Size; + ULONG AllocationListBytes; + ULONG PatchLocationListBytes; +} D3DKMT_QUERYSTATISTICS_DMA_BUFFER; + +typedef struct _D3DKMT_QUERYSTATISTICS_COMMITMENT_DATA +{ + ULONG64 TotalBytesEvictedFromProcess; + ULONG64 BytesBySegmentPreference[D3DKMT_QUERYSTATISTICS_SEGMENT_PREFERENCE_MAX]; +} D3DKMT_QUERYSTATISTICS_COMMITMENT_DATA; + +typedef struct _D3DKMT_QUERYSTATISTICS_POLICY +{ + ULONGLONG PreferApertureForRead[D3DKMT_MaxAllocationPriorityClass]; + ULONGLONG PreferAperture[D3DKMT_MaxAllocationPriorityClass]; + ULONGLONG MemResetOnPaging; + ULONGLONG RemovePagesFromWorkingSetOnPaging; + ULONGLONG MigrationEnabled; +} D3DKMT_QUERYSTATISTICS_POLICY; + +typedef struct _D3DKMT_QUERYSTATISTICS_PROCESS_ADAPTER_INFORMATION +{ + ULONG NbSegments; + ULONG NodeCount; + ULONG VidPnSourceCount; + + ULONG VirtualMemoryUsage; + + D3DKMT_QUERYSTATISTICS_DMA_BUFFER DmaBuffer; + D3DKMT_QUERYSTATISTICS_COMMITMENT_DATA CommitmentData; + D3DKMT_QUERYSTATISTICS_POLICY _Policy; + + ULONG64 Reserved[8]; +} D3DKMT_QUERYSTATISTICS_PROCESS_ADAPTER_INFORMATION; + +typedef struct _D3DKMT_QUERYSTATISTICS_MEMORY +{ + ULONGLONG TotalBytesEvicted; + ULONG AllocsCommitted; + ULONG AllocsResident; +} D3DKMT_QUERYSTATISTICS_MEMORY; + +typedef struct _D3DKMT_QUERYSTATISTICS_SEGMENT_INFORMATION_V1 +{ + ULONG CommitLimit; + ULONG BytesCommitted; + ULONG BytesResident; + + D3DKMT_QUERYSTATISTICS_MEMORY Memory; + + ULONG Aperture; // boolean + + ULONGLONG TotalBytesEvictedByPriority[D3DKMT_MaxAllocationPriorityClass]; + + ULONG64 SystemMemoryEndAddress; + struct + { + ULONG64 PreservedDuringStandby : 1; + ULONG64 PreservedDuringHibernate : 1; + ULONG64 PartiallyPreservedDuringHibernate : 1; + ULONG64 Reserved : 61; + } PowerFlags; + + ULONG64 Reserved[7]; +} D3DKMT_QUERYSTATISTICS_SEGMENT_INFORMATION_V1; + +typedef struct _D3DKMT_QUERYSTATISTICS_SEGMENT_INFORMATION +{ + ULONGLONG CommitLimit; + ULONGLONG BytesCommitted; + ULONGLONG BytesResident; + + D3DKMT_QUERYSTATISTICS_MEMORY Memory; + + ULONG Aperture; // boolean + + ULONGLONG TotalBytesEvictedByPriority[D3DKMT_MaxAllocationPriorityClass]; + + ULONG64 SystemMemoryEndAddress; + struct + { + ULONG64 PreservedDuringStandby : 1; + ULONG64 PreservedDuringHibernate : 1; + ULONG64 PartiallyPreservedDuringHibernate : 1; + ULONG64 Reserved : 61; + } PowerFlags; + + ULONG64 Reserved[6]; +} D3DKMT_QUERYSTATISTICS_SEGMENT_INFORMATION; + +typedef struct _D3DKMT_QUERYSTATISTICS_VIDEO_MEMORY +{ + ULONG AllocsCommitted; + D3DKMT_QUERYSTATISTICS_COUNTER AllocsResidentInP[D3DKMT_QUERYSTATISTICS_SEGMENT_PREFERENCE_MAX]; + D3DKMT_QUERYSTATISTICS_COUNTER AllocsResidentInNonPreferred; + ULONGLONG TotalBytesEvictedDueToPreparation; +} D3DKMT_QUERYSTATISTICS_VIDEO_MEMORY; + +typedef struct _D3DKMT_QUERYSTATISTICS_PROCESS_SEGMENT_POLICY +{ + ULONGLONG UseMRU; +} D3DKMT_QUERYSTATISTICS_PROCESS_SEGMENT_POLICY; + +typedef struct _D3DKMT_QUERYSTATISTICS_PROCESS_SEGMENT_INFORMATION +{ + ULONGLONG BytesCommitted; + ULONGLONG MaximumWorkingSet; + ULONGLONG MinimumWorkingSet; + + ULONG NbReferencedAllocationEvictedInPeriod; + + D3DKMT_QUERYSTATISTICS_VIDEO_MEMORY VideoMemory; + D3DKMT_QUERYSTATISTICS_PROCESS_SEGMENT_POLICY _Policy; + + ULONG64 Reserved[8]; +} D3DKMT_QUERYSTATISTICS_PROCESS_SEGMENT_INFORMATION; + +typedef enum _D3DKMT_QUERYSTATISTICS_TYPE +{ + D3DKMT_QUERYSTATISTICS_ADAPTER = 0, + D3DKMT_QUERYSTATISTICS_PROCESS = 1, + D3DKMT_QUERYSTATISTICS_PROCESS_ADAPTER = 2, + D3DKMT_QUERYSTATISTICS_SEGMENT = 3, + D3DKMT_QUERYSTATISTICS_PROCESS_SEGMENT = 4, + D3DKMT_QUERYSTATISTICS_NODE = 5, + D3DKMT_QUERYSTATISTICS_PROCESS_NODE = 6, + D3DKMT_QUERYSTATISTICS_VIDPNSOURCE = 7, + D3DKMT_QUERYSTATISTICS_PROCESS_VIDPNSOURCE = 8 +} D3DKMT_QUERYSTATISTICS_TYPE; + +typedef struct _D3DKMT_QUERYSTATISTICS_QUERY_SEGMENT +{ + ULONG SegmentId; +} D3DKMT_QUERYSTATISTICS_QUERY_SEGMENT; + +typedef struct _D3DKMT_QUERYSTATISTICS_QUERY_NODE +{ + ULONG NodeId; +} D3DKMT_QUERYSTATISTICS_QUERY_NODE; + +typedef struct _D3DKMT_QUERYSTATISTICS_QUERY_VIDPNSOURCE +{ + ULONG VidPnSourceId; +} D3DKMT_QUERYSTATISTICS_QUERY_VIDPNSOURCE; + +typedef union _D3DKMT_QUERYSTATISTICS_RESULT +{ + D3DKMT_QUERYSTATISTICS_ADAPTER_INFORMATION AdapterInformation; + D3DKMT_QUERYSTATISTICS_SEGMENT_INFORMATION_V1 SegmentInformationV1; // WIN7 + D3DKMT_QUERYSTATISTICS_SEGMENT_INFORMATION SegmentInformation; // WIN8 + D3DKMT_QUERYSTATISTICS_NODE_INFORMATION NodeInformation; + D3DKMT_QUERYSTATISTICS_VIDPNSOURCE_INFORMATION VidPnSourceInformation; + D3DKMT_QUERYSTATISTICS_PROCESS_INFORMATION ProcessInformation; + D3DKMT_QUERYSTATISTICS_PROCESS_ADAPTER_INFORMATION ProcessAdapterInformation; + D3DKMT_QUERYSTATISTICS_PROCESS_SEGMENT_INFORMATION ProcessSegmentInformation; + D3DKMT_QUERYSTATISTICS_PROCESS_NODE_INFORMATION ProcessNodeInformation; + D3DKMT_QUERYSTATISTICS_PROCESS_VIDPNSOURCE_INFORMATION ProcessVidPnSourceInformation; +} D3DKMT_QUERYSTATISTICS_RESULT; + +typedef struct _D3DKMT_QUERYSTATISTICS +{ + _In_ D3DKMT_QUERYSTATISTICS_TYPE Type; + _In_ LUID AdapterLuid; + _In_opt_ HANDLE hProcess; + _Out_ D3DKMT_QUERYSTATISTICS_RESULT QueryResult; + + union + { + _In_ D3DKMT_QUERYSTATISTICS_QUERY_SEGMENT QuerySegment; + _In_ D3DKMT_QUERYSTATISTICS_QUERY_SEGMENT QueryProcessSegment; + _In_ D3DKMT_QUERYSTATISTICS_QUERY_NODE QueryNode; + _In_ D3DKMT_QUERYSTATISTICS_QUERY_NODE QueryProcessNode; + _In_ D3DKMT_QUERYSTATISTICS_QUERY_VIDPNSOURCE QueryVidPnSource; + _In_ D3DKMT_QUERYSTATISTICS_QUERY_VIDPNSOURCE QueryProcessVidPnSource; + }; +} D3DKMT_QUERYSTATISTICS; + +// Function pointers + +// https://msdn.microsoft.com/en-us/library/ff547033.aspx +_Check_return_ +NTSTATUS D3DKMTOpenAdapterFromDeviceName( + _Inout_ D3DKMT_OPENADAPTERFROMDEVICENAME *pData + ); + +// https://msdn.microsoft.com/en-us/library/ff546787.aspx +_Check_return_ +NTSTATUS D3DKMTCloseAdapter( + _In_ const D3DKMT_CLOSEADAPTER *pData + ); + +// rev +_Check_return_ +NTSTATUS D3DKMTQueryStatistics( + _Inout_ const D3DKMT_QUERYSTATISTICS *pData + ); + +#endif diff --git a/plugins/ExtendedTools/disktab.c b/plugins/ExtendedTools/disktab.c index 232acf3dd7ca..b8b1ae72e953 100644 --- a/plugins/ExtendedTools/disktab.c +++ b/plugins/ExtendedTools/disktab.c @@ -1,1172 +1,1172 @@ -/* - * Process Hacker Extended Tools - - * ETW disk monitoring - * - * Copyright (C) 2011-2015 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include "exttools.h" -#include "etwmon.h" -#include -#include "disktabp.h" - -static PPH_MAIN_TAB_PAGE DiskPage; -static BOOLEAN DiskTreeNewCreated = FALSE; -static HWND DiskTreeNewHandle; -static ULONG DiskTreeNewSortColumn; -static PH_SORT_ORDER DiskTreeNewSortOrder; - -static PPH_HASHTABLE DiskNodeHashtable; // hashtable of all nodes -static PPH_LIST DiskNodeList; // list of all nodes - -static PH_CALLBACK_REGISTRATION DiskItemAddedRegistration; -static PH_CALLBACK_REGISTRATION DiskItemModifiedRegistration; -static PH_CALLBACK_REGISTRATION DiskItemRemovedRegistration; -static PH_CALLBACK_REGISTRATION DiskItemsUpdatedRegistration; -static BOOLEAN DiskNeedsRedraw = FALSE; - -static PH_TN_FILTER_SUPPORT FilterSupport; -static PTOOLSTATUS_INTERFACE ToolStatusInterface; -static PH_CALLBACK_REGISTRATION SearchChangedRegistration; - -VOID EtInitializeDiskTab( - VOID - ) -{ - PH_MAIN_TAB_PAGE page; - PPH_PLUGIN toolStatusPlugin; - - if (toolStatusPlugin = PhFindPlugin(TOOLSTATUS_PLUGIN_NAME)) - { - ToolStatusInterface = PhGetPluginInformation(toolStatusPlugin)->Interface; - - if (ToolStatusInterface->Version < TOOLSTATUS_INTERFACE_VERSION) - ToolStatusInterface = NULL; - } - - memset(&page, 0, sizeof(PH_MAIN_TAB_PAGE)); - PhInitializeStringRef(&page.Name, L"Disk"); - page.Callback = EtpDiskPageCallback; - DiskPage = ProcessHacker_CreateTabPage(PhMainWndHandle, &page); - - if (ToolStatusInterface) - { - PTOOLSTATUS_TAB_INFO tabInfo; - - tabInfo = ToolStatusInterface->RegisterTabInfo(DiskPage->Index); - tabInfo->BannerText = L"Search Disk"; - tabInfo->ActivateContent = EtpToolStatusActivateContent; - tabInfo->GetTreeNewHandle = EtpToolStatusGetTreeNewHandle; - } -} - -BOOLEAN EtpDiskPageCallback( - _In_ struct _PH_MAIN_TAB_PAGE *Page, - _In_ PH_MAIN_TAB_PAGE_MESSAGE Message, - _In_opt_ PVOID Parameter1, - _In_opt_ PVOID Parameter2 - ) -{ - switch (Message) - { - case MainTabPageCreateWindow: - { - HWND hwnd; - - if (EtEtwEnabled) - { - ULONG thinRows; - - thinRows = PhGetIntegerSetting(L"ThinRows") ? TN_STYLE_THIN_ROWS : 0; - hwnd = CreateWindow( - PH_TREENEW_CLASSNAME, - NULL, - WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_BORDER | TN_STYLE_ICONS | TN_STYLE_DOUBLE_BUFFERED | thinRows, - 0, - 0, - 3, - 3, - PhMainWndHandle, - NULL, - NULL, - NULL - ); - - if (!hwnd) - return FALSE; - } - else - { - *(HWND *)Parameter1 = CreateDialog( - PluginInstance->DllBase, - MAKEINTRESOURCE(IDD_DISKTABERROR), - PhMainWndHandle, - EtpDiskTabErrorDialogProc - ); - return TRUE; - } - - DiskTreeNewCreated = TRUE; - - DiskNodeHashtable = PhCreateHashtable( - sizeof(PET_DISK_NODE), - EtpDiskNodeHashtableEqualFunction, - EtpDiskNodeHashtableHashFunction, - 100 - ); - DiskNodeList = PhCreateList(100); - - EtInitializeDiskTreeList(hwnd); - - PhRegisterCallback( - &EtDiskItemAddedEvent, - EtpDiskItemAddedHandler, - NULL, - &DiskItemAddedRegistration - ); - PhRegisterCallback( - &EtDiskItemModifiedEvent, - EtpDiskItemModifiedHandler, - NULL, - &DiskItemModifiedRegistration - ); - PhRegisterCallback( - &EtDiskItemRemovedEvent, - EtpDiskItemRemovedHandler, - NULL, - &DiskItemRemovedRegistration - ); - PhRegisterCallback( - &EtDiskItemsUpdatedEvent, - EtpDiskItemsUpdatedHandler, - NULL, - &DiskItemsUpdatedRegistration - ); - - SetCursor(LoadCursor(NULL, IDC_WAIT)); - EtInitializeDiskInformation(); - SetCursor(LoadCursor(NULL, IDC_ARROW)); - - *(HWND *)Parameter1 = hwnd; - } - return TRUE; - case MainTabPageLoadSettings: - { - // Nothing - } - return TRUE; - case MainTabPageSaveSettings: - { - // Nothing - } - return TRUE; - case MainTabPageExportContent: - { - PPH_MAIN_TAB_PAGE_EXPORT_CONTENT exportContent = Parameter1; - - if (!EtEtwEnabled) - return FALSE; - - EtWriteDiskList(exportContent->FileStream, exportContent->Mode); - } - return TRUE; - case MainTabPageFontChanged: - { - HFONT font = (HFONT)Parameter1; - - if (DiskTreeNewHandle) - SendMessage(DiskTreeNewHandle, WM_SETFONT, (WPARAM)Parameter1, TRUE); - } - break; - } - - return FALSE; -} - -BOOLEAN EtpDiskNodeHashtableEqualFunction( - _In_ PVOID Entry1, - _In_ PVOID Entry2 - ) -{ - PET_DISK_NODE diskNode1 = *(PET_DISK_NODE *)Entry1; - PET_DISK_NODE diskNode2 = *(PET_DISK_NODE *)Entry2; - - return diskNode1->DiskItem == diskNode2->DiskItem; -} - -ULONG EtpDiskNodeHashtableHashFunction( - _In_ PVOID Entry - ) -{ - return PhHashIntPtr((ULONG_PTR)(*(PET_DISK_NODE *)Entry)->DiskItem); -} - -VOID EtInitializeDiskTreeList( - _In_ HWND hwnd - ) -{ - DiskTreeNewHandle = hwnd; - PhSetControlTheme(DiskTreeNewHandle, L"explorer"); - SendMessage(TreeNew_GetTooltips(DiskTreeNewHandle), TTM_SETDELAYTIME, TTDT_AUTOPOP, 0x7fff); - - TreeNew_SetCallback(hwnd, EtpDiskTreeNewCallback, NULL); - - TreeNew_SetRedraw(hwnd, FALSE); - - // Default columns - PhAddTreeNewColumn(hwnd, ETDSTNC_NAME, TRUE, L"Name", 100, PH_ALIGN_LEFT, 0, 0); - PhAddTreeNewColumn(hwnd, ETDSTNC_FILE, TRUE, L"File", 400, PH_ALIGN_LEFT, 1, DT_PATH_ELLIPSIS); - PhAddTreeNewColumnEx(hwnd, ETDSTNC_READRATEAVERAGE, TRUE, L"Read rate average", 70, PH_ALIGN_RIGHT, 2, DT_RIGHT, TRUE); - PhAddTreeNewColumnEx(hwnd, ETDSTNC_WRITERATEAVERAGE, TRUE, L"Write rate average", 70, PH_ALIGN_RIGHT, 3, DT_RIGHT, TRUE); - PhAddTreeNewColumnEx(hwnd, ETDSTNC_TOTALRATEAVERAGE, TRUE, L"Total rate average", 70, PH_ALIGN_RIGHT, 4, DT_RIGHT, TRUE); - PhAddTreeNewColumnEx(hwnd, ETDSTNC_IOPRIORITY, TRUE, L"I/O priority", 70, PH_ALIGN_LEFT, 5, 0, TRUE); - PhAddTreeNewColumnEx(hwnd, ETDSTNC_RESPONSETIME, TRUE, L"Response time (ms)", 70, PH_ALIGN_RIGHT, 6, 0, TRUE); - - TreeNew_SetRedraw(hwnd, TRUE); - - TreeNew_SetSort(hwnd, ETDSTNC_TOTALRATEAVERAGE, DescendingSortOrder); - - EtLoadSettingsDiskTreeList(); - - PhInitializeTreeNewFilterSupport(&FilterSupport, hwnd, DiskNodeList); - - if (ToolStatusInterface) - { - PhRegisterCallback(ToolStatusInterface->SearchChangedEvent, EtpSearchChangedHandler, NULL, &SearchChangedRegistration); - PhAddTreeNewFilter(&FilterSupport, EtpSearchDiskListFilterCallback, NULL); - } -} - -VOID EtLoadSettingsDiskTreeList( - VOID - ) -{ - PH_INTEGER_PAIR sortSettings; - - PhCmLoadSettings(DiskTreeNewHandle, &PhaGetStringSetting(SETTING_NAME_DISK_TREE_LIST_COLUMNS)->sr); - - sortSettings = PhGetIntegerPairSetting(SETTING_NAME_DISK_TREE_LIST_SORT); - TreeNew_SetSort(DiskTreeNewHandle, (ULONG)sortSettings.X, (PH_SORT_ORDER)sortSettings.Y); -} - -VOID EtSaveSettingsDiskTreeList( - VOID - ) -{ - PPH_STRING settings; - PH_INTEGER_PAIR sortSettings; - ULONG sortColumn; - PH_SORT_ORDER sortOrder; - - if (!DiskTreeNewCreated) - return; - - settings = PH_AUTO(PhCmSaveSettings(DiskTreeNewHandle)); - PhSetStringSetting2(SETTING_NAME_DISK_TREE_LIST_COLUMNS, &settings->sr); - - TreeNew_GetSort(DiskTreeNewHandle, &sortColumn, &sortOrder); - sortSettings.X = sortColumn; - sortSettings.Y = sortOrder; - PhSetIntegerPairSetting(SETTING_NAME_DISK_TREE_LIST_SORT, sortSettings); -} - -PET_DISK_NODE EtAddDiskNode( - _In_ PET_DISK_ITEM DiskItem - ) -{ - PET_DISK_NODE diskNode; - - diskNode = PhAllocate(sizeof(ET_DISK_NODE)); - memset(diskNode, 0, sizeof(ET_DISK_NODE)); - PhInitializeTreeNewNode(&diskNode->Node); - - PhSetReference(&diskNode->DiskItem, DiskItem); - - memset(diskNode->TextCache, 0, sizeof(PH_STRINGREF) * ETDSTNC_MAXIMUM); - diskNode->Node.TextCache = diskNode->TextCache; - diskNode->Node.TextCacheSize = ETDSTNC_MAXIMUM; - - diskNode->ProcessNameText = EtpGetDiskItemProcessName(DiskItem); - - PhAddEntryHashtable(DiskNodeHashtable, &diskNode); - PhAddItemList(DiskNodeList, diskNode); - - if (FilterSupport.NodeList) - diskNode->Node.Visible = PhApplyTreeNewFiltersToNode(&FilterSupport, &diskNode->Node); - - TreeNew_NodesStructured(DiskTreeNewHandle); - - return diskNode; -} - -PET_DISK_NODE EtFindDiskNode( - _In_ PET_DISK_ITEM DiskItem - ) -{ - ET_DISK_NODE lookupDiskNode; - PET_DISK_NODE lookupDiskNodePtr = &lookupDiskNode; - PET_DISK_NODE *diskNode; - - lookupDiskNode.DiskItem = DiskItem; - - diskNode = (PET_DISK_NODE *)PhFindEntryHashtable( - DiskNodeHashtable, - &lookupDiskNodePtr - ); - - if (diskNode) - return *diskNode; - else - return NULL; -} - -VOID EtRemoveDiskNode( - _In_ PET_DISK_NODE DiskNode - ) -{ - ULONG index; - - // Remove from the hashtable/list and cleanup. - - PhRemoveEntryHashtable(DiskNodeHashtable, &DiskNode); - - if ((index = PhFindItemList(DiskNodeList, DiskNode)) != -1) - PhRemoveItemList(DiskNodeList, index); - - if (DiskNode->ProcessNameText) PhDereferenceObject(DiskNode->ProcessNameText); - if (DiskNode->ReadRateAverageText) PhDereferenceObject(DiskNode->ReadRateAverageText); - if (DiskNode->WriteRateAverageText) PhDereferenceObject(DiskNode->WriteRateAverageText); - if (DiskNode->TotalRateAverageText) PhDereferenceObject(DiskNode->TotalRateAverageText); - if (DiskNode->ResponseTimeText) PhDereferenceObject(DiskNode->ResponseTimeText); - if (DiskNode->TooltipText) PhDereferenceObject(DiskNode->TooltipText); - - PhDereferenceObject(DiskNode->DiskItem); - - PhFree(DiskNode); - - TreeNew_NodesStructured(DiskTreeNewHandle); -} - -VOID EtUpdateDiskNode( - _In_ PET_DISK_NODE DiskNode - ) -{ - memset(DiskNode->TextCache, 0, sizeof(PH_STRINGREF) * ETDSTNC_MAXIMUM); - - PhInvalidateTreeNewNode(&DiskNode->Node, TN_CACHE_ICON); - TreeNew_NodesStructured(DiskTreeNewHandle); -} - -#define SORT_FUNCTION(Column) EtpDiskTreeNewCompare##Column - -#define BEGIN_SORT_FUNCTION(Column) static int __cdecl EtpDiskTreeNewCompare##Column( \ - _In_ const void *_elem1, \ - _In_ const void *_elem2 \ - ) \ -{ \ - PET_DISK_NODE node1 = *(PET_DISK_NODE *)_elem1; \ - PET_DISK_NODE node2 = *(PET_DISK_NODE *)_elem2; \ - PET_DISK_ITEM diskItem1 = node1->DiskItem; \ - PET_DISK_ITEM diskItem2 = node2->DiskItem; \ - int sortResult = 0; - -#define END_SORT_FUNCTION \ - if (sortResult == 0) \ - sortResult = PhCompareString(diskItem1->FileNameWin32, diskItem2->FileNameWin32, TRUE); \ - \ - return PhModifySort(sortResult, DiskTreeNewSortOrder); \ -} - -BEGIN_SORT_FUNCTION(Process) -{ - sortResult = PhCompareString(node1->ProcessNameText, node2->ProcessNameText, TRUE); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(File) -{ - sortResult = PhCompareString(diskItem1->FileNameWin32, diskItem2->FileNameWin32, TRUE); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(ReadRateAverage) -{ - sortResult = uint64cmp(diskItem1->ReadAverage, diskItem2->ReadAverage); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(WriteRateAverage) -{ - sortResult = uint64cmp(diskItem1->WriteAverage, diskItem2->WriteAverage); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(TotalRateAverage) -{ - sortResult = uint64cmp(diskItem1->ReadAverage + diskItem1->WriteAverage, diskItem2->ReadAverage + diskItem2->WriteAverage); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(IoPriority) -{ - sortResult = uintcmp(diskItem1->IoPriority, diskItem2->IoPriority); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(ResponseTime) -{ - sortResult = singlecmp(diskItem1->ResponseTimeAverage, diskItem2->ResponseTimeAverage); -} -END_SORT_FUNCTION - -BOOLEAN NTAPI EtpDiskTreeNewCallback( - _In_ HWND hwnd, - _In_ PH_TREENEW_MESSAGE Message, - _In_opt_ PVOID Parameter1, - _In_opt_ PVOID Parameter2, - _In_opt_ PVOID Context - ) -{ - PET_DISK_NODE node; - - switch (Message) - { - case TreeNewGetChildren: - { - PPH_TREENEW_GET_CHILDREN getChildren = Parameter1; - - if (!getChildren->Node) - { - static PVOID sortFunctions[] = - { - SORT_FUNCTION(Process), - SORT_FUNCTION(File), - SORT_FUNCTION(ReadRateAverage), - SORT_FUNCTION(WriteRateAverage), - SORT_FUNCTION(TotalRateAverage), - SORT_FUNCTION(IoPriority), - SORT_FUNCTION(ResponseTime) - }; - int (__cdecl *sortFunction)(const void *, const void *); - - if (DiskTreeNewSortColumn < ETDSTNC_MAXIMUM) - sortFunction = sortFunctions[DiskTreeNewSortColumn]; - else - sortFunction = NULL; - - if (sortFunction) - { - qsort(DiskNodeList->Items, DiskNodeList->Count, sizeof(PVOID), sortFunction); - } - - getChildren->Children = (PPH_TREENEW_NODE *)DiskNodeList->Items; - getChildren->NumberOfChildren = DiskNodeList->Count; - } - } - return TRUE; - case TreeNewIsLeaf: - { - PPH_TREENEW_IS_LEAF isLeaf = Parameter1; - - isLeaf->IsLeaf = TRUE; - } - return TRUE; - case TreeNewGetCellText: - { - PPH_TREENEW_GET_CELL_TEXT getCellText = Parameter1; - PET_DISK_ITEM diskItem; - - node = (PET_DISK_NODE)getCellText->Node; - diskItem = node->DiskItem; - - switch (getCellText->Id) - { - case ETDSTNC_NAME: - getCellText->Text = node->ProcessNameText->sr; - break; - case ETDSTNC_FILE: - getCellText->Text = diskItem->FileNameWin32->sr; - break; - case ETDSTNC_READRATEAVERAGE: - EtFormatRate(diskItem->ReadAverage, &node->ReadRateAverageText, &getCellText->Text); - break; - case ETDSTNC_WRITERATEAVERAGE: - EtFormatRate(diskItem->WriteAverage, &node->WriteRateAverageText, &getCellText->Text); - break; - case ETDSTNC_TOTALRATEAVERAGE: - EtFormatRate(diskItem->ReadAverage + diskItem->WriteAverage, &node->TotalRateAverageText, &getCellText->Text); - break; - case ETDSTNC_IOPRIORITY: - switch (diskItem->IoPriority) - { - case IoPriorityVeryLow: - PhInitializeStringRef(&getCellText->Text, L"Very Low"); - break; - case IoPriorityLow: - PhInitializeStringRef(&getCellText->Text, L"Low"); - break; - case IoPriorityNormal: - PhInitializeStringRef(&getCellText->Text, L"Normal"); - break; - case IoPriorityHigh: - PhInitializeStringRef(&getCellText->Text, L"High"); - break; - case IoPriorityCritical: - PhInitializeStringRef(&getCellText->Text, L"Critical"); - break; - default: - PhInitializeStringRef(&getCellText->Text, L"Unknown"); - break; - } - break; - case ETDSTNC_RESPONSETIME: - { - PH_FORMAT format; - - PhInitFormatF(&format, diskItem->ResponseTimeAverage, 0); - PhMoveReference(&node->ResponseTimeText, PhFormat(&format, 1, 0)); - getCellText->Text = node->ResponseTimeText->sr; - } - break; - default: - return FALSE; - } - - getCellText->Flags = TN_CACHE; - } - return TRUE; - case TreeNewGetNodeIcon: - { - PPH_TREENEW_GET_NODE_ICON getNodeIcon = Parameter1; - - node = (PET_DISK_NODE)getNodeIcon->Node; - - if (node->DiskItem->ProcessIcon) - { - getNodeIcon->Icon = node->DiskItem->ProcessIcon->Icon; - } - else - { - PhGetStockApplicationIcon(&getNodeIcon->Icon, NULL); - } - - getNodeIcon->Flags = TN_CACHE; - } - return TRUE; - case TreeNewGetCellTooltip: - { - PPH_TREENEW_GET_CELL_TOOLTIP getCellTooltip = Parameter1; - PPH_PROCESS_NODE processNode; - - node = (PET_DISK_NODE)getCellTooltip->Node; - - if (getCellTooltip->Column->Id != 0) - return FALSE; - - if (!node->TooltipText) - { - if (processNode = PhFindProcessNode(node->DiskItem->ProcessId)) - { - PPH_TREENEW_CALLBACK callback; - PVOID callbackContext; - PPH_TREENEW_COLUMN fixedColumn; - PH_TREENEW_GET_CELL_TOOLTIP fakeGetCellTooltip; - - // HACK: Get the tooltip text by using the treenew callback of the process tree. - if (TreeNew_GetCallback(ProcessTreeNewHandle, &callback, &callbackContext) && - (fixedColumn = TreeNew_GetFixedColumn(ProcessTreeNewHandle))) - { - fakeGetCellTooltip.Flags = 0; - fakeGetCellTooltip.Node = &processNode->Node; - fakeGetCellTooltip.Column = fixedColumn; - fakeGetCellTooltip.Unfolding = FALSE; - PhInitializeEmptyStringRef(&fakeGetCellTooltip.Text); - fakeGetCellTooltip.Font = getCellTooltip->Font; - fakeGetCellTooltip.MaximumWidth = getCellTooltip->MaximumWidth; - - if (callback(ProcessTreeNewHandle, TreeNewGetCellTooltip, &fakeGetCellTooltip, NULL, callbackContext)) - { - node->TooltipText = PhCreateString2(&fakeGetCellTooltip.Text); - } - } - } - } - - if (!PhIsNullOrEmptyString(node->TooltipText)) - { - getCellTooltip->Text = node->TooltipText->sr; - getCellTooltip->Unfolding = FALSE; - getCellTooltip->MaximumWidth = -1; - } - else - { - return FALSE; - } - } - return TRUE; - case TreeNewSortChanged: - { - TreeNew_GetSort(hwnd, &DiskTreeNewSortColumn, &DiskTreeNewSortOrder); - // Force a rebuild to sort the items. - TreeNew_NodesStructured(hwnd); - } - return TRUE; - case TreeNewKeyDown: - { - PPH_TREENEW_KEY_EVENT keyEvent = Parameter1; - - switch (keyEvent->VirtualKey) - { - case 'C': - if (GetKeyState(VK_CONTROL) < 0) - EtHandleDiskCommand(ID_DISK_COPY); - break; - case 'A': - if (GetKeyState(VK_CONTROL) < 0) - TreeNew_SelectRange(DiskTreeNewHandle, 0, -1); - break; - case VK_RETURN: - EtHandleDiskCommand(ID_DISK_OPENFILELOCATION); - break; - } - } - return TRUE; - case TreeNewHeaderRightClick: - { - PH_TN_COLUMN_MENU_DATA data; - - data.TreeNewHandle = hwnd; - data.MouseEvent = Parameter1; - data.DefaultSortColumn = 0; - data.DefaultSortOrder = AscendingSortOrder; - PhInitializeTreeNewColumnMenu(&data); - - data.Selection = PhShowEMenu(data.Menu, hwnd, PH_EMENU_SHOW_LEFTRIGHT, - PH_ALIGN_LEFT | PH_ALIGN_TOP, data.MouseEvent->ScreenLocation.x, data.MouseEvent->ScreenLocation.y); - PhHandleTreeNewColumnMenu(&data); - PhDeleteTreeNewColumnMenu(&data); - } - return TRUE; - case TreeNewLeftDoubleClick: - { - EtHandleDiskCommand(ID_DISK_OPENFILELOCATION); - } - return TRUE; - case TreeNewContextMenu: - { - PPH_TREENEW_MOUSE_EVENT mouseEvent = Parameter1; - - EtShowDiskContextMenu(mouseEvent->Location); - } - return TRUE; - case TreeNewDestroying: - { - EtSaveSettingsDiskTreeList(); - } - return TRUE; - } - - return FALSE; -} - -PPH_STRING EtpGetDiskItemProcessName( - _In_ PET_DISK_ITEM DiskItem - ) -{ - PH_FORMAT format[4]; - - if (!DiskItem->ProcessId) - return PhCreateString(L"No process"); - - PhInitFormatS(&format[1], L" ("); - PhInitFormatU(&format[2], HandleToUlong(DiskItem->ProcessId)); - PhInitFormatC(&format[3], ')'); - - if (DiskItem->ProcessName) - PhInitFormatSR(&format[0], DiskItem->ProcessName->sr); - else - PhInitFormatS(&format[0], L"Unknown process"); - - return PhFormat(format, 4, 96); -} - -PET_DISK_ITEM EtGetSelectedDiskItem( - VOID - ) -{ - PET_DISK_ITEM diskItem = NULL; - ULONG i; - - for (i = 0; i < DiskNodeList->Count; i++) - { - PET_DISK_NODE node = DiskNodeList->Items[i]; - - if (node->Node.Selected) - { - diskItem = node->DiskItem; - break; - } - } - - return diskItem; -} - -VOID EtGetSelectedDiskItems( - _Out_ PET_DISK_ITEM **DiskItems, - _Out_ PULONG NumberOfDiskItems - ) -{ - PPH_LIST list; - ULONG i; - - list = PhCreateList(2); - - for (i = 0; i < DiskNodeList->Count; i++) - { - PET_DISK_NODE node = DiskNodeList->Items[i]; - - if (node->Node.Selected) - { - PhAddItemList(list, node->DiskItem); - } - } - - *DiskItems = PhAllocateCopy(list->Items, sizeof(PVOID) * list->Count); - *NumberOfDiskItems = list->Count; - - PhDereferenceObject(list); -} - -VOID EtDeselectAllDiskNodes( - VOID - ) -{ - TreeNew_DeselectRange(DiskTreeNewHandle, 0, -1); -} - -VOID EtSelectAndEnsureVisibleDiskNode( - _In_ PET_DISK_NODE DiskNode - ) -{ - EtDeselectAllDiskNodes(); - - if (!DiskNode->Node.Visible) - return; - - TreeNew_SetFocusNode(DiskTreeNewHandle, &DiskNode->Node); - TreeNew_SetMarkNode(DiskTreeNewHandle, &DiskNode->Node); - TreeNew_SelectRange(DiskTreeNewHandle, DiskNode->Node.Index, DiskNode->Node.Index); - TreeNew_EnsureVisible(DiskTreeNewHandle, &DiskNode->Node); -} - -VOID EtCopyDiskList( - VOID - ) -{ - PPH_STRING text; - - text = PhGetTreeNewText(DiskTreeNewHandle, 0); - PhSetClipboardString(DiskTreeNewHandle, &text->sr); - PhDereferenceObject(text); -} - -VOID EtWriteDiskList( - _Inout_ PPH_FILE_STREAM FileStream, - _In_ ULONG Mode - ) -{ - PPH_LIST lines; - ULONG i; - - lines = PhGetGenericTreeNewLines(DiskTreeNewHandle, Mode); - - for (i = 0; i < lines->Count; i++) - { - PPH_STRING line; - - line = lines->Items[i]; - PhWriteStringAsUtf8FileStream(FileStream, &line->sr); - PhDereferenceObject(line); - PhWriteStringAsUtf8FileStream2(FileStream, L"\r\n"); - } - - PhDereferenceObject(lines); -} - -VOID EtHandleDiskCommand( - _In_ ULONG Id - ) -{ - switch (Id) - { - case ID_DISK_GOTOPROCESS: - { - PET_DISK_ITEM diskItem = EtGetSelectedDiskItem(); - PPH_PROCESS_NODE processNode; - - if (diskItem) - { - PhReferenceObject(diskItem); - - if (diskItem->ProcessRecord) - { - // Check if this is really the process that we want, or if it's just a case of PID re-use. - if ((processNode = PhFindProcessNode(diskItem->ProcessId)) && - processNode->ProcessItem->CreateTime.QuadPart == diskItem->ProcessRecord->CreateTime.QuadPart) - { - ProcessHacker_SelectTabPage(PhMainWndHandle, 0); - PhSelectAndEnsureVisibleProcessNode(processNode); - } - else - { - PhShowProcessRecordDialog(PhMainWndHandle, diskItem->ProcessRecord); - } - } - else - { - PhShowError(PhMainWndHandle, L"The process does not exist."); - } - - PhDereferenceObject(diskItem); - } - } - break; - case ID_DISK_OPENFILELOCATION: - { - PET_DISK_ITEM diskItem = EtGetSelectedDiskItem(); - - if (diskItem) - { - PhShellExploreFile(PhMainWndHandle, diskItem->FileNameWin32->Buffer); - } - } - break; - case ID_DISK_COPY: - { - EtCopyDiskList(); - } - break; - case ID_DISK_PROPERTIES: - { - PET_DISK_ITEM diskItem = EtGetSelectedDiskItem(); - - if (diskItem) - { - PhShellProperties(PhMainWndHandle, diskItem->FileNameWin32->Buffer); - } - } - break; - } -} - -VOID EtpInitializeDiskMenu( - _In_ PPH_EMENU Menu, - _In_ PET_DISK_ITEM *DiskItems, - _In_ ULONG NumberOfDiskItems - ) -{ - PPH_EMENU_ITEM item; - - if (NumberOfDiskItems == 0) - { - PhSetFlagsAllEMenuItems(Menu, PH_EMENU_DISABLED, PH_EMENU_DISABLED); - } - else if (NumberOfDiskItems == 1) - { - PPH_PROCESS_ITEM processItem; - - // If we have a process record and the process has terminated, we can only show - // process properties. - if (DiskItems[0]->ProcessRecord) - { - if (processItem = PhReferenceProcessItemForRecord(DiskItems[0]->ProcessRecord)) - { - PhDereferenceObject(processItem); - } - else - { - if (item = PhFindEMenuItem(Menu, 0, NULL, ID_DISK_GOTOPROCESS)) - { - item->Text = L"Process Properties"; - item->Flags &= ~PH_EMENU_TEXT_OWNED; - } - } - } - } - else - { - PhSetFlagsAllEMenuItems(Menu, PH_EMENU_DISABLED, PH_EMENU_DISABLED); - PhEnableEMenuItem(Menu, ID_DISK_COPY, TRUE); - } -} - -VOID EtShowDiskContextMenu( - _In_ POINT Location - ) -{ - PET_DISK_ITEM *diskItems; - ULONG numberOfDiskItems; - - EtGetSelectedDiskItems(&diskItems, &numberOfDiskItems); - - if (numberOfDiskItems != 0) - { - PPH_EMENU menu; - PPH_EMENU_ITEM item; - - menu = PhCreateEMenu(); - PhLoadResourceEMenuItem(menu, PluginInstance->DllBase, MAKEINTRESOURCE(IDR_DISK), 0); - PhSetFlagsEMenuItem(menu, ID_DISK_OPENFILELOCATION, PH_EMENU_DEFAULT, PH_EMENU_DEFAULT); - - EtpInitializeDiskMenu(menu, diskItems, numberOfDiskItems); - - item = PhShowEMenu( - menu, - PhMainWndHandle, - PH_EMENU_SHOW_LEFTRIGHT, - PH_ALIGN_LEFT | PH_ALIGN_TOP, - Location.x, - Location.y - ); - - if (item) - { - EtHandleDiskCommand(item->Id); - } - - PhDestroyEMenu(menu); - } - - PhFree(diskItems); -} - -VOID NTAPI EtpDiskItemAddedHandler( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - PET_DISK_ITEM diskItem = (PET_DISK_ITEM)Parameter; - - PhReferenceObject(diskItem); - ProcessHacker_Invoke(PhMainWndHandle, EtpOnDiskItemAdded, diskItem); -} - -VOID NTAPI EtpDiskItemModifiedHandler( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - ProcessHacker_Invoke(PhMainWndHandle, EtpOnDiskItemModified, (PET_DISK_ITEM)Parameter); -} - -VOID NTAPI EtpDiskItemRemovedHandler( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - ProcessHacker_Invoke(PhMainWndHandle, EtpOnDiskItemRemoved, (PET_DISK_ITEM)Parameter); -} - -VOID NTAPI EtpDiskItemsUpdatedHandler( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - ProcessHacker_Invoke(PhMainWndHandle, EtpOnDiskItemsUpdated, NULL); -} - -VOID NTAPI EtpOnDiskItemAdded( - _In_ PVOID Parameter - ) -{ - PET_DISK_ITEM diskItem = Parameter; - PET_DISK_NODE diskNode; - - if (!DiskNeedsRedraw) - { - TreeNew_SetRedraw(DiskTreeNewHandle, FALSE); - DiskNeedsRedraw = TRUE; - } - - diskNode = EtAddDiskNode(diskItem); - PhDereferenceObject(diskItem); -} - -VOID NTAPI EtpOnDiskItemModified( - _In_ PVOID Parameter - ) -{ - PET_DISK_ITEM diskItem = Parameter; - - EtUpdateDiskNode(EtFindDiskNode(diskItem)); -} - -VOID NTAPI EtpOnDiskItemRemoved( - _In_ PVOID Parameter - ) -{ - PET_DISK_ITEM diskItem = Parameter; - - if (!DiskNeedsRedraw) - { - TreeNew_SetRedraw(DiskTreeNewHandle, FALSE); - DiskNeedsRedraw = TRUE; - } - - EtRemoveDiskNode(EtFindDiskNode(diskItem)); -} - -VOID NTAPI EtpOnDiskItemsUpdated( - _In_ PVOID Parameter - ) -{ - ULONG i; - - if (DiskNeedsRedraw) - { - TreeNew_SetRedraw(DiskTreeNewHandle, TRUE); - DiskNeedsRedraw = FALSE; - } - - // Text invalidation - - for (i = 0; i < DiskNodeList->Count; i++) - { - PET_DISK_NODE node = DiskNodeList->Items[i]; - - // The name and file name never change, so we don't invalidate that. - memset(&node->TextCache[2], 0, sizeof(PH_STRINGREF) * (ETDSTNC_MAXIMUM - 2)); - // Always get the newest tooltip text from the process tree. - PhClearReference(&node->TooltipText); - } - - InvalidateRect(DiskTreeNewHandle, NULL, FALSE); -} - -VOID NTAPI EtpSearchChangedHandler( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - if (!EtEtwEnabled) - return; - - PhApplyTreeNewFilters(&FilterSupport); -} - -BOOLEAN NTAPI EtpSearchDiskListFilterCallback( - _In_ PPH_TREENEW_NODE Node, - _In_opt_ PVOID Context - ) -{ - PET_DISK_NODE diskNode = (PET_DISK_NODE)Node; - PTOOLSTATUS_WORD_MATCH wordMatch = ToolStatusInterface->WordMatch; - - if (PhIsNullOrEmptyString(ToolStatusInterface->GetSearchboxText())) - return TRUE; - - if (wordMatch(&diskNode->ProcessNameText->sr)) - return TRUE; - - if (wordMatch(&diskNode->DiskItem->FileNameWin32->sr)) - return TRUE; - - return FALSE; -} - -VOID NTAPI EtpToolStatusActivateContent( - _In_ BOOLEAN Select - ) -{ - SetFocus(DiskTreeNewHandle); - - if (Select) - { - if (TreeNew_GetFlatNodeCount(DiskTreeNewHandle) > 0) - EtSelectAndEnsureVisibleDiskNode((PET_DISK_NODE)TreeNew_GetFlatNode(DiskTreeNewHandle, 0)); - } -} - -HWND NTAPI EtpToolStatusGetTreeNewHandle( - VOID - ) -{ - return DiskTreeNewHandle; -} - -INT_PTR CALLBACK EtpDiskTabErrorDialogProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - switch (uMsg) - { - case WM_INITDIALOG: - { - if (!PhGetOwnTokenAttributes().Elevated) - { - SendMessage(GetDlgItem(hwndDlg, IDC_RESTART), BCM_SETSHIELD, 0, TRUE); - } - else - { - SetDlgItemText(hwndDlg, IDC_ERROR, L"Unable to start the kernel event tracing session."); - ShowWindow(GetDlgItem(hwndDlg, IDC_RESTART), SW_HIDE); - } - } - break; - case WM_COMMAND: - { - switch (LOWORD(wParam)) - { - case IDC_RESTART: - ProcessHacker_PrepareForEarlyShutdown(PhMainWndHandle); - - if (PhShellProcessHacker( - PhMainWndHandle, - L"-v -selecttab Disk", - SW_SHOW, - PH_SHELL_EXECUTE_ADMIN, - PH_SHELL_APP_PROPAGATE_PARAMETERS | PH_SHELL_APP_PROPAGATE_PARAMETERS_IGNORE_VISIBILITY, - 0, - NULL - )) - { - ProcessHacker_Destroy(PhMainWndHandle); - } - else - { - ProcessHacker_CancelEarlyShutdown(PhMainWndHandle); - } - - break; - } - } - break; - case WM_CTLCOLORBTN: - case WM_CTLCOLORSTATIC: - { - SetBkMode((HDC)wParam, TRANSPARENT); - return (INT_PTR)GetSysColorBrush(COLOR_WINDOW); - } - break; - } - - return FALSE; -} +/* + * Process Hacker Extended Tools - + * ETW disk monitoring + * + * Copyright (C) 2011-2015 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include "exttools.h" +#include "etwmon.h" +#include +#include "disktabp.h" + +static PPH_MAIN_TAB_PAGE DiskPage; +static BOOLEAN DiskTreeNewCreated = FALSE; +static HWND DiskTreeNewHandle; +static ULONG DiskTreeNewSortColumn; +static PH_SORT_ORDER DiskTreeNewSortOrder; + +static PPH_HASHTABLE DiskNodeHashtable; // hashtable of all nodes +static PPH_LIST DiskNodeList; // list of all nodes + +static PH_CALLBACK_REGISTRATION DiskItemAddedRegistration; +static PH_CALLBACK_REGISTRATION DiskItemModifiedRegistration; +static PH_CALLBACK_REGISTRATION DiskItemRemovedRegistration; +static PH_CALLBACK_REGISTRATION DiskItemsUpdatedRegistration; +static BOOLEAN DiskNeedsRedraw = FALSE; + +static PH_TN_FILTER_SUPPORT FilterSupport; +static PTOOLSTATUS_INTERFACE ToolStatusInterface; +static PH_CALLBACK_REGISTRATION SearchChangedRegistration; + +VOID EtInitializeDiskTab( + VOID + ) +{ + PH_MAIN_TAB_PAGE page; + PPH_PLUGIN toolStatusPlugin; + + if (toolStatusPlugin = PhFindPlugin(TOOLSTATUS_PLUGIN_NAME)) + { + ToolStatusInterface = PhGetPluginInformation(toolStatusPlugin)->Interface; + + if (ToolStatusInterface->Version < TOOLSTATUS_INTERFACE_VERSION) + ToolStatusInterface = NULL; + } + + memset(&page, 0, sizeof(PH_MAIN_TAB_PAGE)); + PhInitializeStringRef(&page.Name, L"Disk"); + page.Callback = EtpDiskPageCallback; + DiskPage = ProcessHacker_CreateTabPage(PhMainWndHandle, &page); + + if (ToolStatusInterface) + { + PTOOLSTATUS_TAB_INFO tabInfo; + + tabInfo = ToolStatusInterface->RegisterTabInfo(DiskPage->Index); + tabInfo->BannerText = L"Search Disk"; + tabInfo->ActivateContent = EtpToolStatusActivateContent; + tabInfo->GetTreeNewHandle = EtpToolStatusGetTreeNewHandle; + } +} + +BOOLEAN EtpDiskPageCallback( + _In_ struct _PH_MAIN_TAB_PAGE *Page, + _In_ PH_MAIN_TAB_PAGE_MESSAGE Message, + _In_opt_ PVOID Parameter1, + _In_opt_ PVOID Parameter2 + ) +{ + switch (Message) + { + case MainTabPageCreateWindow: + { + HWND hwnd; + + if (EtEtwEnabled) + { + ULONG thinRows; + + thinRows = PhGetIntegerSetting(L"ThinRows") ? TN_STYLE_THIN_ROWS : 0; + hwnd = CreateWindow( + PH_TREENEW_CLASSNAME, + NULL, + WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_BORDER | TN_STYLE_ICONS | TN_STYLE_DOUBLE_BUFFERED | thinRows, + 0, + 0, + 3, + 3, + PhMainWndHandle, + NULL, + NULL, + NULL + ); + + if (!hwnd) + return FALSE; + } + else + { + *(HWND *)Parameter1 = CreateDialog( + PluginInstance->DllBase, + MAKEINTRESOURCE(IDD_DISKTABERROR), + PhMainWndHandle, + EtpDiskTabErrorDialogProc + ); + return TRUE; + } + + DiskTreeNewCreated = TRUE; + + DiskNodeHashtable = PhCreateHashtable( + sizeof(PET_DISK_NODE), + EtpDiskNodeHashtableEqualFunction, + EtpDiskNodeHashtableHashFunction, + 100 + ); + DiskNodeList = PhCreateList(100); + + EtInitializeDiskTreeList(hwnd); + + PhRegisterCallback( + &EtDiskItemAddedEvent, + EtpDiskItemAddedHandler, + NULL, + &DiskItemAddedRegistration + ); + PhRegisterCallback( + &EtDiskItemModifiedEvent, + EtpDiskItemModifiedHandler, + NULL, + &DiskItemModifiedRegistration + ); + PhRegisterCallback( + &EtDiskItemRemovedEvent, + EtpDiskItemRemovedHandler, + NULL, + &DiskItemRemovedRegistration + ); + PhRegisterCallback( + &EtDiskItemsUpdatedEvent, + EtpDiskItemsUpdatedHandler, + NULL, + &DiskItemsUpdatedRegistration + ); + + SetCursor(LoadCursor(NULL, IDC_WAIT)); + EtInitializeDiskInformation(); + SetCursor(LoadCursor(NULL, IDC_ARROW)); + + *(HWND *)Parameter1 = hwnd; + } + return TRUE; + case MainTabPageLoadSettings: + { + // Nothing + } + return TRUE; + case MainTabPageSaveSettings: + { + // Nothing + } + return TRUE; + case MainTabPageExportContent: + { + PPH_MAIN_TAB_PAGE_EXPORT_CONTENT exportContent = Parameter1; + + if (!EtEtwEnabled) + return FALSE; + + EtWriteDiskList(exportContent->FileStream, exportContent->Mode); + } + return TRUE; + case MainTabPageFontChanged: + { + HFONT font = (HFONT)Parameter1; + + if (DiskTreeNewHandle) + SendMessage(DiskTreeNewHandle, WM_SETFONT, (WPARAM)Parameter1, TRUE); + } + break; + } + + return FALSE; +} + +BOOLEAN EtpDiskNodeHashtableEqualFunction( + _In_ PVOID Entry1, + _In_ PVOID Entry2 + ) +{ + PET_DISK_NODE diskNode1 = *(PET_DISK_NODE *)Entry1; + PET_DISK_NODE diskNode2 = *(PET_DISK_NODE *)Entry2; + + return diskNode1->DiskItem == diskNode2->DiskItem; +} + +ULONG EtpDiskNodeHashtableHashFunction( + _In_ PVOID Entry + ) +{ + return PhHashIntPtr((ULONG_PTR)(*(PET_DISK_NODE *)Entry)->DiskItem); +} + +VOID EtInitializeDiskTreeList( + _In_ HWND hwnd + ) +{ + DiskTreeNewHandle = hwnd; + PhSetControlTheme(DiskTreeNewHandle, L"explorer"); + SendMessage(TreeNew_GetTooltips(DiskTreeNewHandle), TTM_SETDELAYTIME, TTDT_AUTOPOP, 0x7fff); + + TreeNew_SetCallback(hwnd, EtpDiskTreeNewCallback, NULL); + + TreeNew_SetRedraw(hwnd, FALSE); + + // Default columns + PhAddTreeNewColumn(hwnd, ETDSTNC_NAME, TRUE, L"Name", 100, PH_ALIGN_LEFT, 0, 0); + PhAddTreeNewColumn(hwnd, ETDSTNC_FILE, TRUE, L"File", 400, PH_ALIGN_LEFT, 1, DT_PATH_ELLIPSIS); + PhAddTreeNewColumnEx(hwnd, ETDSTNC_READRATEAVERAGE, TRUE, L"Read rate average", 70, PH_ALIGN_RIGHT, 2, DT_RIGHT, TRUE); + PhAddTreeNewColumnEx(hwnd, ETDSTNC_WRITERATEAVERAGE, TRUE, L"Write rate average", 70, PH_ALIGN_RIGHT, 3, DT_RIGHT, TRUE); + PhAddTreeNewColumnEx(hwnd, ETDSTNC_TOTALRATEAVERAGE, TRUE, L"Total rate average", 70, PH_ALIGN_RIGHT, 4, DT_RIGHT, TRUE); + PhAddTreeNewColumnEx(hwnd, ETDSTNC_IOPRIORITY, TRUE, L"I/O priority", 70, PH_ALIGN_LEFT, 5, 0, TRUE); + PhAddTreeNewColumnEx(hwnd, ETDSTNC_RESPONSETIME, TRUE, L"Response time (ms)", 70, PH_ALIGN_RIGHT, 6, 0, TRUE); + + TreeNew_SetRedraw(hwnd, TRUE); + + TreeNew_SetSort(hwnd, ETDSTNC_TOTALRATEAVERAGE, DescendingSortOrder); + + EtLoadSettingsDiskTreeList(); + + PhInitializeTreeNewFilterSupport(&FilterSupport, hwnd, DiskNodeList); + + if (ToolStatusInterface) + { + PhRegisterCallback(ToolStatusInterface->SearchChangedEvent, EtpSearchChangedHandler, NULL, &SearchChangedRegistration); + PhAddTreeNewFilter(&FilterSupport, EtpSearchDiskListFilterCallback, NULL); + } +} + +VOID EtLoadSettingsDiskTreeList( + VOID + ) +{ + PH_INTEGER_PAIR sortSettings; + + PhCmLoadSettings(DiskTreeNewHandle, &PhaGetStringSetting(SETTING_NAME_DISK_TREE_LIST_COLUMNS)->sr); + + sortSettings = PhGetIntegerPairSetting(SETTING_NAME_DISK_TREE_LIST_SORT); + TreeNew_SetSort(DiskTreeNewHandle, (ULONG)sortSettings.X, (PH_SORT_ORDER)sortSettings.Y); +} + +VOID EtSaveSettingsDiskTreeList( + VOID + ) +{ + PPH_STRING settings; + PH_INTEGER_PAIR sortSettings; + ULONG sortColumn; + PH_SORT_ORDER sortOrder; + + if (!DiskTreeNewCreated) + return; + + settings = PH_AUTO(PhCmSaveSettings(DiskTreeNewHandle)); + PhSetStringSetting2(SETTING_NAME_DISK_TREE_LIST_COLUMNS, &settings->sr); + + TreeNew_GetSort(DiskTreeNewHandle, &sortColumn, &sortOrder); + sortSettings.X = sortColumn; + sortSettings.Y = sortOrder; + PhSetIntegerPairSetting(SETTING_NAME_DISK_TREE_LIST_SORT, sortSettings); +} + +PET_DISK_NODE EtAddDiskNode( + _In_ PET_DISK_ITEM DiskItem + ) +{ + PET_DISK_NODE diskNode; + + diskNode = PhAllocate(sizeof(ET_DISK_NODE)); + memset(diskNode, 0, sizeof(ET_DISK_NODE)); + PhInitializeTreeNewNode(&diskNode->Node); + + PhSetReference(&diskNode->DiskItem, DiskItem); + + memset(diskNode->TextCache, 0, sizeof(PH_STRINGREF) * ETDSTNC_MAXIMUM); + diskNode->Node.TextCache = diskNode->TextCache; + diskNode->Node.TextCacheSize = ETDSTNC_MAXIMUM; + + diskNode->ProcessNameText = EtpGetDiskItemProcessName(DiskItem); + + PhAddEntryHashtable(DiskNodeHashtable, &diskNode); + PhAddItemList(DiskNodeList, diskNode); + + if (FilterSupport.NodeList) + diskNode->Node.Visible = PhApplyTreeNewFiltersToNode(&FilterSupport, &diskNode->Node); + + TreeNew_NodesStructured(DiskTreeNewHandle); + + return diskNode; +} + +PET_DISK_NODE EtFindDiskNode( + _In_ PET_DISK_ITEM DiskItem + ) +{ + ET_DISK_NODE lookupDiskNode; + PET_DISK_NODE lookupDiskNodePtr = &lookupDiskNode; + PET_DISK_NODE *diskNode; + + lookupDiskNode.DiskItem = DiskItem; + + diskNode = (PET_DISK_NODE *)PhFindEntryHashtable( + DiskNodeHashtable, + &lookupDiskNodePtr + ); + + if (diskNode) + return *diskNode; + else + return NULL; +} + +VOID EtRemoveDiskNode( + _In_ PET_DISK_NODE DiskNode + ) +{ + ULONG index; + + // Remove from the hashtable/list and cleanup. + + PhRemoveEntryHashtable(DiskNodeHashtable, &DiskNode); + + if ((index = PhFindItemList(DiskNodeList, DiskNode)) != -1) + PhRemoveItemList(DiskNodeList, index); + + if (DiskNode->ProcessNameText) PhDereferenceObject(DiskNode->ProcessNameText); + if (DiskNode->ReadRateAverageText) PhDereferenceObject(DiskNode->ReadRateAverageText); + if (DiskNode->WriteRateAverageText) PhDereferenceObject(DiskNode->WriteRateAverageText); + if (DiskNode->TotalRateAverageText) PhDereferenceObject(DiskNode->TotalRateAverageText); + if (DiskNode->ResponseTimeText) PhDereferenceObject(DiskNode->ResponseTimeText); + if (DiskNode->TooltipText) PhDereferenceObject(DiskNode->TooltipText); + + PhDereferenceObject(DiskNode->DiskItem); + + PhFree(DiskNode); + + TreeNew_NodesStructured(DiskTreeNewHandle); +} + +VOID EtUpdateDiskNode( + _In_ PET_DISK_NODE DiskNode + ) +{ + memset(DiskNode->TextCache, 0, sizeof(PH_STRINGREF) * ETDSTNC_MAXIMUM); + + PhInvalidateTreeNewNode(&DiskNode->Node, TN_CACHE_ICON); + TreeNew_NodesStructured(DiskTreeNewHandle); +} + +#define SORT_FUNCTION(Column) EtpDiskTreeNewCompare##Column + +#define BEGIN_SORT_FUNCTION(Column) static int __cdecl EtpDiskTreeNewCompare##Column( \ + _In_ const void *_elem1, \ + _In_ const void *_elem2 \ + ) \ +{ \ + PET_DISK_NODE node1 = *(PET_DISK_NODE *)_elem1; \ + PET_DISK_NODE node2 = *(PET_DISK_NODE *)_elem2; \ + PET_DISK_ITEM diskItem1 = node1->DiskItem; \ + PET_DISK_ITEM diskItem2 = node2->DiskItem; \ + int sortResult = 0; + +#define END_SORT_FUNCTION \ + if (sortResult == 0) \ + sortResult = PhCompareString(diskItem1->FileNameWin32, diskItem2->FileNameWin32, TRUE); \ + \ + return PhModifySort(sortResult, DiskTreeNewSortOrder); \ +} + +BEGIN_SORT_FUNCTION(Process) +{ + sortResult = PhCompareString(node1->ProcessNameText, node2->ProcessNameText, TRUE); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(File) +{ + sortResult = PhCompareString(diskItem1->FileNameWin32, diskItem2->FileNameWin32, TRUE); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(ReadRateAverage) +{ + sortResult = uint64cmp(diskItem1->ReadAverage, diskItem2->ReadAverage); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(WriteRateAverage) +{ + sortResult = uint64cmp(diskItem1->WriteAverage, diskItem2->WriteAverage); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(TotalRateAverage) +{ + sortResult = uint64cmp(diskItem1->ReadAverage + diskItem1->WriteAverage, diskItem2->ReadAverage + diskItem2->WriteAverage); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(IoPriority) +{ + sortResult = uintcmp(diskItem1->IoPriority, diskItem2->IoPriority); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(ResponseTime) +{ + sortResult = singlecmp(diskItem1->ResponseTimeAverage, diskItem2->ResponseTimeAverage); +} +END_SORT_FUNCTION + +BOOLEAN NTAPI EtpDiskTreeNewCallback( + _In_ HWND hwnd, + _In_ PH_TREENEW_MESSAGE Message, + _In_opt_ PVOID Parameter1, + _In_opt_ PVOID Parameter2, + _In_opt_ PVOID Context + ) +{ + PET_DISK_NODE node; + + switch (Message) + { + case TreeNewGetChildren: + { + PPH_TREENEW_GET_CHILDREN getChildren = Parameter1; + + if (!getChildren->Node) + { + static PVOID sortFunctions[] = + { + SORT_FUNCTION(Process), + SORT_FUNCTION(File), + SORT_FUNCTION(ReadRateAverage), + SORT_FUNCTION(WriteRateAverage), + SORT_FUNCTION(TotalRateAverage), + SORT_FUNCTION(IoPriority), + SORT_FUNCTION(ResponseTime) + }; + int (__cdecl *sortFunction)(const void *, const void *); + + if (DiskTreeNewSortColumn < ETDSTNC_MAXIMUM) + sortFunction = sortFunctions[DiskTreeNewSortColumn]; + else + sortFunction = NULL; + + if (sortFunction) + { + qsort(DiskNodeList->Items, DiskNodeList->Count, sizeof(PVOID), sortFunction); + } + + getChildren->Children = (PPH_TREENEW_NODE *)DiskNodeList->Items; + getChildren->NumberOfChildren = DiskNodeList->Count; + } + } + return TRUE; + case TreeNewIsLeaf: + { + PPH_TREENEW_IS_LEAF isLeaf = Parameter1; + + isLeaf->IsLeaf = TRUE; + } + return TRUE; + case TreeNewGetCellText: + { + PPH_TREENEW_GET_CELL_TEXT getCellText = Parameter1; + PET_DISK_ITEM diskItem; + + node = (PET_DISK_NODE)getCellText->Node; + diskItem = node->DiskItem; + + switch (getCellText->Id) + { + case ETDSTNC_NAME: + getCellText->Text = node->ProcessNameText->sr; + break; + case ETDSTNC_FILE: + getCellText->Text = diskItem->FileNameWin32->sr; + break; + case ETDSTNC_READRATEAVERAGE: + EtFormatRate(diskItem->ReadAverage, &node->ReadRateAverageText, &getCellText->Text); + break; + case ETDSTNC_WRITERATEAVERAGE: + EtFormatRate(diskItem->WriteAverage, &node->WriteRateAverageText, &getCellText->Text); + break; + case ETDSTNC_TOTALRATEAVERAGE: + EtFormatRate(diskItem->ReadAverage + diskItem->WriteAverage, &node->TotalRateAverageText, &getCellText->Text); + break; + case ETDSTNC_IOPRIORITY: + switch (diskItem->IoPriority) + { + case IoPriorityVeryLow: + PhInitializeStringRef(&getCellText->Text, L"Very Low"); + break; + case IoPriorityLow: + PhInitializeStringRef(&getCellText->Text, L"Low"); + break; + case IoPriorityNormal: + PhInitializeStringRef(&getCellText->Text, L"Normal"); + break; + case IoPriorityHigh: + PhInitializeStringRef(&getCellText->Text, L"High"); + break; + case IoPriorityCritical: + PhInitializeStringRef(&getCellText->Text, L"Critical"); + break; + default: + PhInitializeStringRef(&getCellText->Text, L"Unknown"); + break; + } + break; + case ETDSTNC_RESPONSETIME: + { + PH_FORMAT format; + + PhInitFormatF(&format, diskItem->ResponseTimeAverage, 0); + PhMoveReference(&node->ResponseTimeText, PhFormat(&format, 1, 0)); + getCellText->Text = node->ResponseTimeText->sr; + } + break; + default: + return FALSE; + } + + getCellText->Flags = TN_CACHE; + } + return TRUE; + case TreeNewGetNodeIcon: + { + PPH_TREENEW_GET_NODE_ICON getNodeIcon = Parameter1; + + node = (PET_DISK_NODE)getNodeIcon->Node; + + if (node->DiskItem->ProcessIcon) + { + getNodeIcon->Icon = node->DiskItem->ProcessIcon->Icon; + } + else + { + PhGetStockApplicationIcon(&getNodeIcon->Icon, NULL); + } + + getNodeIcon->Flags = TN_CACHE; + } + return TRUE; + case TreeNewGetCellTooltip: + { + PPH_TREENEW_GET_CELL_TOOLTIP getCellTooltip = Parameter1; + PPH_PROCESS_NODE processNode; + + node = (PET_DISK_NODE)getCellTooltip->Node; + + if (getCellTooltip->Column->Id != 0) + return FALSE; + + if (!node->TooltipText) + { + if (processNode = PhFindProcessNode(node->DiskItem->ProcessId)) + { + PPH_TREENEW_CALLBACK callback; + PVOID callbackContext; + PPH_TREENEW_COLUMN fixedColumn; + PH_TREENEW_GET_CELL_TOOLTIP fakeGetCellTooltip; + + // HACK: Get the tooltip text by using the treenew callback of the process tree. + if (TreeNew_GetCallback(ProcessTreeNewHandle, &callback, &callbackContext) && + (fixedColumn = TreeNew_GetFixedColumn(ProcessTreeNewHandle))) + { + fakeGetCellTooltip.Flags = 0; + fakeGetCellTooltip.Node = &processNode->Node; + fakeGetCellTooltip.Column = fixedColumn; + fakeGetCellTooltip.Unfolding = FALSE; + PhInitializeEmptyStringRef(&fakeGetCellTooltip.Text); + fakeGetCellTooltip.Font = getCellTooltip->Font; + fakeGetCellTooltip.MaximumWidth = getCellTooltip->MaximumWidth; + + if (callback(ProcessTreeNewHandle, TreeNewGetCellTooltip, &fakeGetCellTooltip, NULL, callbackContext)) + { + node->TooltipText = PhCreateString2(&fakeGetCellTooltip.Text); + } + } + } + } + + if (!PhIsNullOrEmptyString(node->TooltipText)) + { + getCellTooltip->Text = node->TooltipText->sr; + getCellTooltip->Unfolding = FALSE; + getCellTooltip->MaximumWidth = -1; + } + else + { + return FALSE; + } + } + return TRUE; + case TreeNewSortChanged: + { + TreeNew_GetSort(hwnd, &DiskTreeNewSortColumn, &DiskTreeNewSortOrder); + // Force a rebuild to sort the items. + TreeNew_NodesStructured(hwnd); + } + return TRUE; + case TreeNewKeyDown: + { + PPH_TREENEW_KEY_EVENT keyEvent = Parameter1; + + switch (keyEvent->VirtualKey) + { + case 'C': + if (GetKeyState(VK_CONTROL) < 0) + EtHandleDiskCommand(ID_DISK_COPY); + break; + case 'A': + if (GetKeyState(VK_CONTROL) < 0) + TreeNew_SelectRange(DiskTreeNewHandle, 0, -1); + break; + case VK_RETURN: + EtHandleDiskCommand(ID_DISK_OPENFILELOCATION); + break; + } + } + return TRUE; + case TreeNewHeaderRightClick: + { + PH_TN_COLUMN_MENU_DATA data; + + data.TreeNewHandle = hwnd; + data.MouseEvent = Parameter1; + data.DefaultSortColumn = 0; + data.DefaultSortOrder = AscendingSortOrder; + PhInitializeTreeNewColumnMenu(&data); + + data.Selection = PhShowEMenu(data.Menu, hwnd, PH_EMENU_SHOW_LEFTRIGHT, + PH_ALIGN_LEFT | PH_ALIGN_TOP, data.MouseEvent->ScreenLocation.x, data.MouseEvent->ScreenLocation.y); + PhHandleTreeNewColumnMenu(&data); + PhDeleteTreeNewColumnMenu(&data); + } + return TRUE; + case TreeNewLeftDoubleClick: + { + EtHandleDiskCommand(ID_DISK_OPENFILELOCATION); + } + return TRUE; + case TreeNewContextMenu: + { + PPH_TREENEW_MOUSE_EVENT mouseEvent = Parameter1; + + EtShowDiskContextMenu(mouseEvent->Location); + } + return TRUE; + case TreeNewDestroying: + { + EtSaveSettingsDiskTreeList(); + } + return TRUE; + } + + return FALSE; +} + +PPH_STRING EtpGetDiskItemProcessName( + _In_ PET_DISK_ITEM DiskItem + ) +{ + PH_FORMAT format[4]; + + if (!DiskItem->ProcessId) + return PhCreateString(L"No process"); + + PhInitFormatS(&format[1], L" ("); + PhInitFormatU(&format[2], HandleToUlong(DiskItem->ProcessId)); + PhInitFormatC(&format[3], ')'); + + if (DiskItem->ProcessName) + PhInitFormatSR(&format[0], DiskItem->ProcessName->sr); + else + PhInitFormatS(&format[0], L"Unknown process"); + + return PhFormat(format, 4, 96); +} + +PET_DISK_ITEM EtGetSelectedDiskItem( + VOID + ) +{ + PET_DISK_ITEM diskItem = NULL; + ULONG i; + + for (i = 0; i < DiskNodeList->Count; i++) + { + PET_DISK_NODE node = DiskNodeList->Items[i]; + + if (node->Node.Selected) + { + diskItem = node->DiskItem; + break; + } + } + + return diskItem; +} + +VOID EtGetSelectedDiskItems( + _Out_ PET_DISK_ITEM **DiskItems, + _Out_ PULONG NumberOfDiskItems + ) +{ + PPH_LIST list; + ULONG i; + + list = PhCreateList(2); + + for (i = 0; i < DiskNodeList->Count; i++) + { + PET_DISK_NODE node = DiskNodeList->Items[i]; + + if (node->Node.Selected) + { + PhAddItemList(list, node->DiskItem); + } + } + + *DiskItems = PhAllocateCopy(list->Items, sizeof(PVOID) * list->Count); + *NumberOfDiskItems = list->Count; + + PhDereferenceObject(list); +} + +VOID EtDeselectAllDiskNodes( + VOID + ) +{ + TreeNew_DeselectRange(DiskTreeNewHandle, 0, -1); +} + +VOID EtSelectAndEnsureVisibleDiskNode( + _In_ PET_DISK_NODE DiskNode + ) +{ + EtDeselectAllDiskNodes(); + + if (!DiskNode->Node.Visible) + return; + + TreeNew_SetFocusNode(DiskTreeNewHandle, &DiskNode->Node); + TreeNew_SetMarkNode(DiskTreeNewHandle, &DiskNode->Node); + TreeNew_SelectRange(DiskTreeNewHandle, DiskNode->Node.Index, DiskNode->Node.Index); + TreeNew_EnsureVisible(DiskTreeNewHandle, &DiskNode->Node); +} + +VOID EtCopyDiskList( + VOID + ) +{ + PPH_STRING text; + + text = PhGetTreeNewText(DiskTreeNewHandle, 0); + PhSetClipboardString(DiskTreeNewHandle, &text->sr); + PhDereferenceObject(text); +} + +VOID EtWriteDiskList( + _Inout_ PPH_FILE_STREAM FileStream, + _In_ ULONG Mode + ) +{ + PPH_LIST lines; + ULONG i; + + lines = PhGetGenericTreeNewLines(DiskTreeNewHandle, Mode); + + for (i = 0; i < lines->Count; i++) + { + PPH_STRING line; + + line = lines->Items[i]; + PhWriteStringAsUtf8FileStream(FileStream, &line->sr); + PhDereferenceObject(line); + PhWriteStringAsUtf8FileStream2(FileStream, L"\r\n"); + } + + PhDereferenceObject(lines); +} + +VOID EtHandleDiskCommand( + _In_ ULONG Id + ) +{ + switch (Id) + { + case ID_DISK_GOTOPROCESS: + { + PET_DISK_ITEM diskItem = EtGetSelectedDiskItem(); + PPH_PROCESS_NODE processNode; + + if (diskItem) + { + PhReferenceObject(diskItem); + + if (diskItem->ProcessRecord) + { + // Check if this is really the process that we want, or if it's just a case of PID re-use. + if ((processNode = PhFindProcessNode(diskItem->ProcessId)) && + processNode->ProcessItem->CreateTime.QuadPart == diskItem->ProcessRecord->CreateTime.QuadPart) + { + ProcessHacker_SelectTabPage(PhMainWndHandle, 0); + PhSelectAndEnsureVisibleProcessNode(processNode); + } + else + { + PhShowProcessRecordDialog(PhMainWndHandle, diskItem->ProcessRecord); + } + } + else + { + PhShowError(PhMainWndHandle, L"The process does not exist."); + } + + PhDereferenceObject(diskItem); + } + } + break; + case ID_DISK_OPENFILELOCATION: + { + PET_DISK_ITEM diskItem = EtGetSelectedDiskItem(); + + if (diskItem) + { + PhShellExploreFile(PhMainWndHandle, diskItem->FileNameWin32->Buffer); + } + } + break; + case ID_DISK_COPY: + { + EtCopyDiskList(); + } + break; + case ID_DISK_PROPERTIES: + { + PET_DISK_ITEM diskItem = EtGetSelectedDiskItem(); + + if (diskItem) + { + PhShellProperties(PhMainWndHandle, diskItem->FileNameWin32->Buffer); + } + } + break; + } +} + +VOID EtpInitializeDiskMenu( + _In_ PPH_EMENU Menu, + _In_ PET_DISK_ITEM *DiskItems, + _In_ ULONG NumberOfDiskItems + ) +{ + PPH_EMENU_ITEM item; + + if (NumberOfDiskItems == 0) + { + PhSetFlagsAllEMenuItems(Menu, PH_EMENU_DISABLED, PH_EMENU_DISABLED); + } + else if (NumberOfDiskItems == 1) + { + PPH_PROCESS_ITEM processItem; + + // If we have a process record and the process has terminated, we can only show + // process properties. + if (DiskItems[0]->ProcessRecord) + { + if (processItem = PhReferenceProcessItemForRecord(DiskItems[0]->ProcessRecord)) + { + PhDereferenceObject(processItem); + } + else + { + if (item = PhFindEMenuItem(Menu, 0, NULL, ID_DISK_GOTOPROCESS)) + { + item->Text = L"Process Properties"; + item->Flags &= ~PH_EMENU_TEXT_OWNED; + } + } + } + } + else + { + PhSetFlagsAllEMenuItems(Menu, PH_EMENU_DISABLED, PH_EMENU_DISABLED); + PhEnableEMenuItem(Menu, ID_DISK_COPY, TRUE); + } +} + +VOID EtShowDiskContextMenu( + _In_ POINT Location + ) +{ + PET_DISK_ITEM *diskItems; + ULONG numberOfDiskItems; + + EtGetSelectedDiskItems(&diskItems, &numberOfDiskItems); + + if (numberOfDiskItems != 0) + { + PPH_EMENU menu; + PPH_EMENU_ITEM item; + + menu = PhCreateEMenu(); + PhLoadResourceEMenuItem(menu, PluginInstance->DllBase, MAKEINTRESOURCE(IDR_DISK), 0); + PhSetFlagsEMenuItem(menu, ID_DISK_OPENFILELOCATION, PH_EMENU_DEFAULT, PH_EMENU_DEFAULT); + + EtpInitializeDiskMenu(menu, diskItems, numberOfDiskItems); + + item = PhShowEMenu( + menu, + PhMainWndHandle, + PH_EMENU_SHOW_LEFTRIGHT, + PH_ALIGN_LEFT | PH_ALIGN_TOP, + Location.x, + Location.y + ); + + if (item) + { + EtHandleDiskCommand(item->Id); + } + + PhDestroyEMenu(menu); + } + + PhFree(diskItems); +} + +VOID NTAPI EtpDiskItemAddedHandler( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + PET_DISK_ITEM diskItem = (PET_DISK_ITEM)Parameter; + + PhReferenceObject(diskItem); + ProcessHacker_Invoke(PhMainWndHandle, EtpOnDiskItemAdded, diskItem); +} + +VOID NTAPI EtpDiskItemModifiedHandler( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + ProcessHacker_Invoke(PhMainWndHandle, EtpOnDiskItemModified, (PET_DISK_ITEM)Parameter); +} + +VOID NTAPI EtpDiskItemRemovedHandler( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + ProcessHacker_Invoke(PhMainWndHandle, EtpOnDiskItemRemoved, (PET_DISK_ITEM)Parameter); +} + +VOID NTAPI EtpDiskItemsUpdatedHandler( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + ProcessHacker_Invoke(PhMainWndHandle, EtpOnDiskItemsUpdated, NULL); +} + +VOID NTAPI EtpOnDiskItemAdded( + _In_ PVOID Parameter + ) +{ + PET_DISK_ITEM diskItem = Parameter; + PET_DISK_NODE diskNode; + + if (!DiskNeedsRedraw) + { + TreeNew_SetRedraw(DiskTreeNewHandle, FALSE); + DiskNeedsRedraw = TRUE; + } + + diskNode = EtAddDiskNode(diskItem); + PhDereferenceObject(diskItem); +} + +VOID NTAPI EtpOnDiskItemModified( + _In_ PVOID Parameter + ) +{ + PET_DISK_ITEM diskItem = Parameter; + + EtUpdateDiskNode(EtFindDiskNode(diskItem)); +} + +VOID NTAPI EtpOnDiskItemRemoved( + _In_ PVOID Parameter + ) +{ + PET_DISK_ITEM diskItem = Parameter; + + if (!DiskNeedsRedraw) + { + TreeNew_SetRedraw(DiskTreeNewHandle, FALSE); + DiskNeedsRedraw = TRUE; + } + + EtRemoveDiskNode(EtFindDiskNode(diskItem)); +} + +VOID NTAPI EtpOnDiskItemsUpdated( + _In_ PVOID Parameter + ) +{ + ULONG i; + + if (DiskNeedsRedraw) + { + TreeNew_SetRedraw(DiskTreeNewHandle, TRUE); + DiskNeedsRedraw = FALSE; + } + + // Text invalidation + + for (i = 0; i < DiskNodeList->Count; i++) + { + PET_DISK_NODE node = DiskNodeList->Items[i]; + + // The name and file name never change, so we don't invalidate that. + memset(&node->TextCache[2], 0, sizeof(PH_STRINGREF) * (ETDSTNC_MAXIMUM - 2)); + // Always get the newest tooltip text from the process tree. + PhClearReference(&node->TooltipText); + } + + InvalidateRect(DiskTreeNewHandle, NULL, FALSE); +} + +VOID NTAPI EtpSearchChangedHandler( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + if (!EtEtwEnabled) + return; + + PhApplyTreeNewFilters(&FilterSupport); +} + +BOOLEAN NTAPI EtpSearchDiskListFilterCallback( + _In_ PPH_TREENEW_NODE Node, + _In_opt_ PVOID Context + ) +{ + PET_DISK_NODE diskNode = (PET_DISK_NODE)Node; + PTOOLSTATUS_WORD_MATCH wordMatch = ToolStatusInterface->WordMatch; + + if (PhIsNullOrEmptyString(ToolStatusInterface->GetSearchboxText())) + return TRUE; + + if (wordMatch(&diskNode->ProcessNameText->sr)) + return TRUE; + + if (wordMatch(&diskNode->DiskItem->FileNameWin32->sr)) + return TRUE; + + return FALSE; +} + +VOID NTAPI EtpToolStatusActivateContent( + _In_ BOOLEAN Select + ) +{ + SetFocus(DiskTreeNewHandle); + + if (Select) + { + if (TreeNew_GetFlatNodeCount(DiskTreeNewHandle) > 0) + EtSelectAndEnsureVisibleDiskNode((PET_DISK_NODE)TreeNew_GetFlatNode(DiskTreeNewHandle, 0)); + } +} + +HWND NTAPI EtpToolStatusGetTreeNewHandle( + VOID + ) +{ + return DiskTreeNewHandle; +} + +INT_PTR CALLBACK EtpDiskTabErrorDialogProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + switch (uMsg) + { + case WM_INITDIALOG: + { + if (!PhGetOwnTokenAttributes().Elevated) + { + SendMessage(GetDlgItem(hwndDlg, IDC_RESTART), BCM_SETSHIELD, 0, TRUE); + } + else + { + SetDlgItemText(hwndDlg, IDC_ERROR, L"Unable to start the kernel event tracing session."); + ShowWindow(GetDlgItem(hwndDlg, IDC_RESTART), SW_HIDE); + } + } + break; + case WM_COMMAND: + { + switch (LOWORD(wParam)) + { + case IDC_RESTART: + ProcessHacker_PrepareForEarlyShutdown(PhMainWndHandle); + + if (PhShellProcessHacker( + PhMainWndHandle, + L"-v -selecttab Disk", + SW_SHOW, + PH_SHELL_EXECUTE_ADMIN, + PH_SHELL_APP_PROPAGATE_PARAMETERS | PH_SHELL_APP_PROPAGATE_PARAMETERS_IGNORE_VISIBILITY, + 0, + NULL + )) + { + ProcessHacker_Destroy(PhMainWndHandle); + } + else + { + ProcessHacker_CancelEarlyShutdown(PhMainWndHandle); + } + + break; + } + } + break; + case WM_CTLCOLORBTN: + case WM_CTLCOLORSTATIC: + { + SetBkMode((HDC)wParam, TRANSPARENT); + return (INT_PTR)GetSysColorBrush(COLOR_WINDOW); + } + break; + } + + return FALSE; +} diff --git a/plugins/ExtendedTools/disktabp.h b/plugins/ExtendedTools/disktabp.h index 23f259290799..794572c90e7c 100644 --- a/plugins/ExtendedTools/disktabp.h +++ b/plugins/ExtendedTools/disktabp.h @@ -1,174 +1,174 @@ -#ifndef DISKTABP_H -#define DISKTABP_H - -BOOLEAN EtpDiskPageCallback( - _In_ struct _PH_MAIN_TAB_PAGE *Page, - _In_ PH_MAIN_TAB_PAGE_MESSAGE Message, - _In_opt_ PVOID Parameter1, - _In_opt_ PVOID Parameter2 - ); - -VOID NTAPI EtpDiskTabSelectionChangedCallback( - _In_ PVOID Parameter1, - _In_ PVOID Parameter2, - _In_ PVOID Parameter3, - _In_ PVOID Context - ); - -VOID NTAPI EtpDiskTabSaveContentCallback( - _In_ PVOID Parameter1, - _In_ PVOID Parameter2, - _In_ PVOID Parameter3, - _In_ PVOID Context - ); - -VOID NTAPI EtpDiskTabFontChangedCallback( - _In_ PVOID Parameter1, - _In_ PVOID Parameter2, - _In_ PVOID Parameter3, - _In_ PVOID Context - ); - -BOOLEAN EtpDiskNodeHashtableEqualFunction( - _In_ PVOID Entry1, - _In_ PVOID Entry2 - ); - -ULONG EtpDiskNodeHashtableHashFunction( - _In_ PVOID Entry - ); - -VOID EtInitializeDiskTreeList( - _In_ HWND hwnd - ); - -PET_DISK_NODE EtAddDiskNode( - _In_ PET_DISK_ITEM DiskItem - ); - -PET_DISK_NODE EtFindDiskNode( - _In_ PET_DISK_ITEM DiskItem - ); - -VOID EtRemoveDiskNode( - _In_ PET_DISK_NODE DiskNode - ); - -VOID EtUpdateDiskNode( - _In_ PET_DISK_NODE DiskNode - ); - -BOOLEAN NTAPI EtpDiskTreeNewCallback( - _In_ HWND hwnd, - _In_ PH_TREENEW_MESSAGE Message, - _In_opt_ PVOID Parameter1, - _In_opt_ PVOID Parameter2, - _In_opt_ PVOID Context - ); - -PPH_STRING EtpGetDiskItemProcessName( - _In_ PET_DISK_ITEM DiskItem - ); - -PET_DISK_ITEM EtGetSelectedDiskItem( - VOID - ); - -VOID EtGetSelectedDiskItems( - _Out_ PET_DISK_ITEM **DiskItems, - _Out_ PULONG NumberOfDiskItems - ); - -VOID EtDeselectAllDiskNodes( - VOID - ); - -VOID EtSelectAndEnsureVisibleDiskNode( - _In_ PET_DISK_NODE DiskNode - ); - -VOID EtCopyDiskList( - VOID - ); - -VOID EtWriteDiskList( - _Inout_ PPH_FILE_STREAM FileStream, - _In_ ULONG Mode - ); - -VOID EtHandleDiskCommand( - _In_ ULONG Id - ); - -VOID EtpInitializeDiskMenu( - _In_ PPH_EMENU Menu, - _In_ PET_DISK_ITEM *DiskItems, - _In_ ULONG NumberOfDiskItems - ); - -VOID EtShowDiskContextMenu( - _In_ POINT Location - ); - -VOID NTAPI EtpDiskItemAddedHandler( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ); - -VOID NTAPI EtpDiskItemModifiedHandler( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ); - -VOID NTAPI EtpDiskItemRemovedHandler( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ); - -VOID NTAPI EtpDiskItemsUpdatedHandler( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ); - -VOID NTAPI EtpOnDiskItemAdded( - _In_ PVOID Parameter - ); - -VOID NTAPI EtpOnDiskItemModified( - _In_ PVOID Parameter - ); - -VOID NTAPI EtpOnDiskItemRemoved( - _In_ PVOID Parameter - ); - -VOID NTAPI EtpOnDiskItemsUpdated( - _In_ PVOID Parameter - ); - -VOID NTAPI EtpSearchChangedHandler( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ); - -BOOLEAN NTAPI EtpSearchDiskListFilterCallback( - _In_ PPH_TREENEW_NODE Node, - _In_opt_ PVOID Context - ); - -VOID NTAPI EtpToolStatusActivateContent( - _In_ BOOLEAN Select - ); - -HWND NTAPI EtpToolStatusGetTreeNewHandle( - VOID - ); - -INT_PTR CALLBACK EtpDiskTabErrorDialogProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -#endif +#ifndef DISKTABP_H +#define DISKTABP_H + +BOOLEAN EtpDiskPageCallback( + _In_ struct _PH_MAIN_TAB_PAGE *Page, + _In_ PH_MAIN_TAB_PAGE_MESSAGE Message, + _In_opt_ PVOID Parameter1, + _In_opt_ PVOID Parameter2 + ); + +VOID NTAPI EtpDiskTabSelectionChangedCallback( + _In_ PVOID Parameter1, + _In_ PVOID Parameter2, + _In_ PVOID Parameter3, + _In_ PVOID Context + ); + +VOID NTAPI EtpDiskTabSaveContentCallback( + _In_ PVOID Parameter1, + _In_ PVOID Parameter2, + _In_ PVOID Parameter3, + _In_ PVOID Context + ); + +VOID NTAPI EtpDiskTabFontChangedCallback( + _In_ PVOID Parameter1, + _In_ PVOID Parameter2, + _In_ PVOID Parameter3, + _In_ PVOID Context + ); + +BOOLEAN EtpDiskNodeHashtableEqualFunction( + _In_ PVOID Entry1, + _In_ PVOID Entry2 + ); + +ULONG EtpDiskNodeHashtableHashFunction( + _In_ PVOID Entry + ); + +VOID EtInitializeDiskTreeList( + _In_ HWND hwnd + ); + +PET_DISK_NODE EtAddDiskNode( + _In_ PET_DISK_ITEM DiskItem + ); + +PET_DISK_NODE EtFindDiskNode( + _In_ PET_DISK_ITEM DiskItem + ); + +VOID EtRemoveDiskNode( + _In_ PET_DISK_NODE DiskNode + ); + +VOID EtUpdateDiskNode( + _In_ PET_DISK_NODE DiskNode + ); + +BOOLEAN NTAPI EtpDiskTreeNewCallback( + _In_ HWND hwnd, + _In_ PH_TREENEW_MESSAGE Message, + _In_opt_ PVOID Parameter1, + _In_opt_ PVOID Parameter2, + _In_opt_ PVOID Context + ); + +PPH_STRING EtpGetDiskItemProcessName( + _In_ PET_DISK_ITEM DiskItem + ); + +PET_DISK_ITEM EtGetSelectedDiskItem( + VOID + ); + +VOID EtGetSelectedDiskItems( + _Out_ PET_DISK_ITEM **DiskItems, + _Out_ PULONG NumberOfDiskItems + ); + +VOID EtDeselectAllDiskNodes( + VOID + ); + +VOID EtSelectAndEnsureVisibleDiskNode( + _In_ PET_DISK_NODE DiskNode + ); + +VOID EtCopyDiskList( + VOID + ); + +VOID EtWriteDiskList( + _Inout_ PPH_FILE_STREAM FileStream, + _In_ ULONG Mode + ); + +VOID EtHandleDiskCommand( + _In_ ULONG Id + ); + +VOID EtpInitializeDiskMenu( + _In_ PPH_EMENU Menu, + _In_ PET_DISK_ITEM *DiskItems, + _In_ ULONG NumberOfDiskItems + ); + +VOID EtShowDiskContextMenu( + _In_ POINT Location + ); + +VOID NTAPI EtpDiskItemAddedHandler( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ); + +VOID NTAPI EtpDiskItemModifiedHandler( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ); + +VOID NTAPI EtpDiskItemRemovedHandler( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ); + +VOID NTAPI EtpDiskItemsUpdatedHandler( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ); + +VOID NTAPI EtpOnDiskItemAdded( + _In_ PVOID Parameter + ); + +VOID NTAPI EtpOnDiskItemModified( + _In_ PVOID Parameter + ); + +VOID NTAPI EtpOnDiskItemRemoved( + _In_ PVOID Parameter + ); + +VOID NTAPI EtpOnDiskItemsUpdated( + _In_ PVOID Parameter + ); + +VOID NTAPI EtpSearchChangedHandler( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ); + +BOOLEAN NTAPI EtpSearchDiskListFilterCallback( + _In_ PPH_TREENEW_NODE Node, + _In_opt_ PVOID Context + ); + +VOID NTAPI EtpToolStatusActivateContent( + _In_ BOOLEAN Select + ); + +HWND NTAPI EtpToolStatusGetTreeNewHandle( + VOID + ); + +INT_PTR CALLBACK EtpDiskTabErrorDialogProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +#endif diff --git a/plugins/ExtendedTools/etwdisk.c b/plugins/ExtendedTools/etwdisk.c index 7980ce675e79..c8512f20a01d 100644 --- a/plugins/ExtendedTools/etwdisk.c +++ b/plugins/ExtendedTools/etwdisk.c @@ -1,536 +1,536 @@ -/* - * Process Hacker Extended Tools - - * ETW disk monitoring - * - * Copyright (C) 2011 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include "exttools.h" -#include "etwmon.h" - -typedef struct _ETP_DISK_PACKET -{ - SLIST_ENTRY ListEntry; - ET_ETW_DISK_EVENT Event; - PPH_STRING FileName; -} ETP_DISK_PACKET, *PETP_DISK_PACKET; - -VOID NTAPI EtpDiskItemDeleteProcedure( - _In_ PVOID Object, - _In_ ULONG Flags - ); - -BOOLEAN NTAPI EtpDiskHashtableEqualFunction( - _In_ PVOID Entry1, - _In_ PVOID Entry2 - ); - -ULONG NTAPI EtpDiskHashtableHashFunction( - _In_ PVOID Entry - ); - -VOID NTAPI EtpDiskProcessesUpdatedCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ); - -BOOLEAN EtDiskEnabled = FALSE; - -PPH_OBJECT_TYPE EtDiskItemType; -PPH_HASHTABLE EtDiskHashtable; -PH_QUEUED_LOCK EtDiskHashtableLock = PH_QUEUED_LOCK_INIT; -LIST_ENTRY EtDiskAgeListHead; -PH_CALLBACK_DECLARE(EtDiskItemAddedEvent); -PH_CALLBACK_DECLARE(EtDiskItemModifiedEvent); -PH_CALLBACK_DECLARE(EtDiskItemRemovedEvent); -PH_CALLBACK_DECLARE(EtDiskItemsUpdatedEvent); - -PH_FREE_LIST EtDiskPacketFreeList; -SLIST_HEADER EtDiskPacketListHead; -PPH_HASHTABLE EtFileNameHashtable; -PH_QUEUED_LOCK EtFileNameHashtableLock = PH_QUEUED_LOCK_INIT; - -static LARGE_INTEGER EtpPerformanceFrequency; -static PH_CALLBACK_REGISTRATION ProcessesUpdatedCallbackRegistration; - -VOID EtInitializeDiskInformation( - VOID - ) -{ - LARGE_INTEGER performanceCounter; - - EtDiskItemType = PhCreateObjectType(L"DiskItem", 0, EtpDiskItemDeleteProcedure); - EtDiskHashtable = PhCreateHashtable( - sizeof(PET_DISK_ITEM), - EtpDiskHashtableEqualFunction, - EtpDiskHashtableHashFunction, - 128 - ); - InitializeListHead(&EtDiskAgeListHead); - - PhInitializeFreeList(&EtDiskPacketFreeList, sizeof(ETP_DISK_PACKET), 64); - RtlInitializeSListHead(&EtDiskPacketListHead); - EtFileNameHashtable = PhCreateSimpleHashtable(128); - - NtQueryPerformanceCounter(&performanceCounter, &EtpPerformanceFrequency); - - EtDiskEnabled = TRUE; - - // Collect all existing file names. - EtStartEtwRundown(); - - PhRegisterCallback( - &PhProcessesUpdatedEvent, - EtpDiskProcessesUpdatedCallback, - NULL, - &ProcessesUpdatedCallbackRegistration - ); -} - -PET_DISK_ITEM EtCreateDiskItem( - VOID - ) -{ - PET_DISK_ITEM diskItem; - - diskItem = PhCreateObject(sizeof(ET_DISK_ITEM), EtDiskItemType); - memset(diskItem, 0, sizeof(ET_DISK_ITEM)); - - return diskItem; -} - -VOID NTAPI EtpDiskItemDeleteProcedure( - _In_ PVOID Object, - _In_ ULONG Flags - ) -{ - PET_DISK_ITEM diskItem = Object; - - if (diskItem->FileName) PhDereferenceObject(diskItem->FileName); - if (diskItem->FileNameWin32) PhDereferenceObject(diskItem->FileNameWin32); - if (diskItem->ProcessName) PhDereferenceObject(diskItem->ProcessName); - if (diskItem->ProcessIcon) EtProcIconDereferenceProcessIcon(diskItem->ProcessIcon); - if (diskItem->ProcessRecord) PhDereferenceProcessRecord(diskItem->ProcessRecord); -} - -BOOLEAN NTAPI EtpDiskHashtableEqualFunction( - _In_ PVOID Entry1, - _In_ PVOID Entry2 - ) -{ - PET_DISK_ITEM diskItem1 = *(PET_DISK_ITEM *)Entry1; - PET_DISK_ITEM diskItem2 = *(PET_DISK_ITEM *)Entry2; - - return diskItem1->ProcessId == diskItem2->ProcessId && PhEqualString(diskItem1->FileName, diskItem2->FileName, TRUE); -} - -ULONG NTAPI EtpDiskHashtableHashFunction( - _In_ PVOID Entry - ) -{ - PET_DISK_ITEM diskItem = *(PET_DISK_ITEM *)Entry; - - return (HandleToUlong(diskItem->ProcessId) / 4) ^ PhHashStringRef(&diskItem->FileName->sr, TRUE); -} - -PET_DISK_ITEM EtReferenceDiskItem( - _In_ HANDLE ProcessId, - _In_ PPH_STRING FileName - ) -{ - ET_DISK_ITEM lookupDiskItem; - PET_DISK_ITEM lookupDiskItemPtr = &lookupDiskItem; - PET_DISK_ITEM *diskItemPtr; - PET_DISK_ITEM diskItem; - - lookupDiskItem.ProcessId = ProcessId; - lookupDiskItem.FileName = FileName; - - PhAcquireQueuedLockShared(&EtDiskHashtableLock); - - diskItemPtr = (PET_DISK_ITEM *)PhFindEntryHashtable( - EtDiskHashtable, - &lookupDiskItemPtr - ); - - if (diskItemPtr) - PhSetReference(&diskItem, *diskItemPtr); - else - diskItem = NULL; - - PhReleaseQueuedLockShared(&EtDiskHashtableLock); - - return diskItem; -} - -VOID EtpRemoveDiskItem( - _In_ PET_DISK_ITEM DiskItem - ) -{ - RemoveEntryList(&DiskItem->AgeListEntry); - PhRemoveEntryHashtable(EtDiskHashtable, &DiskItem); - PhDereferenceObject(DiskItem); -} - -VOID EtDiskProcessDiskEvent( - _In_ PET_ETW_DISK_EVENT Event - ) -{ - PETP_DISK_PACKET packet; - - if (!EtDiskEnabled) - return; - - packet = PhAllocateFromFreeList(&EtDiskPacketFreeList); - memcpy(&packet->Event, Event, sizeof(ET_ETW_DISK_EVENT)); - packet->FileName = EtFileObjectToFileName(Event->FileObject); - RtlInterlockedPushEntrySList(&EtDiskPacketListHead, &packet->ListEntry); -} - -VOID EtDiskProcessFileEvent( - _In_ PET_ETW_FILE_EVENT Event - ) -{ - PH_KEY_VALUE_PAIR pair; - PPH_KEY_VALUE_PAIR realPair; - - if (!EtDiskEnabled) - return; - - if (Event->Type == EtEtwFileCreateType || Event->Type == EtEtwFileRundownType) - { - pair.Key = Event->FileObject; - pair.Value = NULL; - - PhAcquireQueuedLockExclusive(&EtFileNameHashtableLock); - - realPair = PhAddEntryHashtableEx(EtFileNameHashtable, &pair, NULL); - PhMoveReference(&realPair->Value, PhCreateString2(&Event->FileName)); - - PhReleaseQueuedLockExclusive(&EtFileNameHashtableLock); - } - else if (Event->Type == EtEtwFileDeleteType) - { - pair.Key = Event->FileObject; - - PhAcquireQueuedLockExclusive(&EtFileNameHashtableLock); - - realPair = PhFindEntryHashtable(EtFileNameHashtable, &pair); - - if (realPair) - { - PhDereferenceObject(realPair->Value); - PhRemoveEntryHashtable(EtFileNameHashtable, &pair); - } - - PhReleaseQueuedLockExclusive(&EtFileNameHashtableLock); - } -} - -PPH_STRING EtFileObjectToFileName( - _In_ PVOID FileObject - ) -{ - PH_KEY_VALUE_PAIR pair; - PPH_KEY_VALUE_PAIR realPair; - PPH_STRING fileName; - - pair.Key = FileObject; - fileName = NULL; - - PhAcquireQueuedLockShared(&EtFileNameHashtableLock); - - realPair = PhFindEntryHashtable(EtFileNameHashtable, &pair); - - if (realPair) - PhSetReference(&fileName, realPair->Value); - - PhReleaseQueuedLockShared(&EtFileNameHashtableLock); - - return fileName; -} - -VOID EtpProcessDiskPacket( - _In_ PETP_DISK_PACKET Packet, - _In_ ULONG RunId - ) -{ - PET_ETW_DISK_EVENT diskEvent; - PET_DISK_ITEM diskItem; - BOOLEAN added = FALSE; - - diskEvent = &Packet->Event; - - // We only process non-zero read/write events. - if (diskEvent->Type != EtEtwDiskReadType && diskEvent->Type != EtEtwDiskWriteType) - return; - if (diskEvent->TransferSize == 0) - return; - - // Ignore packets with no file name - this is useless to the user. - if (!Packet->FileName) - return; - - diskItem = EtReferenceDiskItem(diskEvent->ClientId.UniqueProcess, Packet->FileName); - - if (!diskItem) - { - PPH_PROCESS_ITEM processItem; - - // Disk item not found (or the address was re-used), create it. - - diskItem = EtCreateDiskItem(); - - diskItem->ProcessId = diskEvent->ClientId.UniqueProcess; - PhSetReference(&diskItem->FileName, Packet->FileName); - diskItem->FileNameWin32 = PhGetFileName(diskItem->FileName); - - if (processItem = PhReferenceProcessItem(diskItem->ProcessId)) - { - PhSetReference(&diskItem->ProcessName, processItem->ProcessName); - diskItem->ProcessIcon = EtProcIconReferenceSmallProcessIcon(EtGetProcessBlock(processItem)); - diskItem->ProcessRecord = processItem->Record; - PhReferenceProcessRecord(diskItem->ProcessRecord); - - PhDereferenceObject(processItem); - } - - // Add the disk item to the age list. - diskItem->AddTime = RunId; - diskItem->FreshTime = RunId; - InsertHeadList(&EtDiskAgeListHead, &diskItem->AgeListEntry); - - // Add the disk item to the hashtable. - PhAcquireQueuedLockExclusive(&EtDiskHashtableLock); - PhAddEntryHashtable(EtDiskHashtable, &diskItem); - PhReleaseQueuedLockExclusive(&EtDiskHashtableLock); - - // Raise the disk item added event. - PhInvokeCallback(&EtDiskItemAddedEvent, diskItem); - added = TRUE; - } - - // The I/O priority number needs to be decoded. - - diskItem->IoPriority = (diskEvent->IrpFlags >> 17) & 7; - - if (diskItem->IoPriority == 0) - diskItem->IoPriority = IoPriorityNormal; - else - diskItem->IoPriority--; - - // Accumulate statistics for this update period. - - if (diskEvent->Type == EtEtwDiskReadType) - diskItem->ReadDelta += diskEvent->TransferSize; - else - diskItem->WriteDelta += diskEvent->TransferSize; - - if (EtpPerformanceFrequency.QuadPart != 0) - { - // Convert the response time to milliseconds. - diskItem->ResponseTimeTotal += (FLOAT)diskEvent->HighResResponseTime * 1000 / EtpPerformanceFrequency.QuadPart; - diskItem->ResponseTimeCount++; - } - - if (!added) - { - if (diskItem->FreshTime != RunId) - { - diskItem->FreshTime = RunId; - RemoveEntryList(&diskItem->AgeListEntry); - InsertHeadList(&EtDiskAgeListHead, &diskItem->AgeListEntry); - } - - PhDereferenceObject(diskItem); - } -} - -ULONG64 EtpCalculateAverage( - _In_ PULONG64 Buffer, - _In_ ULONG BufferSize, - _In_ ULONG BufferPosition, - _In_ ULONG BufferCount, - _In_ ULONG NumberToConsider - ) -{ - ULONG64 sum; - ULONG i; - ULONG count; - - sum = 0; - i = BufferPosition; - - if (NumberToConsider > BufferCount) - NumberToConsider = BufferCount; - - if (NumberToConsider == 0) - return 0; - - count = NumberToConsider; - - do - { - sum += Buffer[i]; - i++; - - if (i == BufferSize) - i = 0; - } while (--count != 0); - - return sum / NumberToConsider; -} - -VOID NTAPI EtpDiskProcessesUpdatedCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - static ULONG runCount = 0; - - PSLIST_ENTRY listEntry; - PLIST_ENTRY ageListEntry; - - // Process incoming disk event packets. - - listEntry = RtlInterlockedFlushSList(&EtDiskPacketListHead); - - while (listEntry) - { - PETP_DISK_PACKET packet; - - packet = CONTAINING_RECORD(listEntry, ETP_DISK_PACKET, ListEntry); - listEntry = listEntry->Next; - - EtpProcessDiskPacket(packet, runCount); - - if (packet->FileName) - PhDereferenceObject(packet->FileName); - - PhFreeToFreeList(&EtDiskPacketFreeList, packet); - } - - // Remove old entries. - - ageListEntry = EtDiskAgeListHead.Blink; - - while (ageListEntry != &EtDiskAgeListHead) - { - PET_DISK_ITEM diskItem; - - diskItem = CONTAINING_RECORD(ageListEntry, ET_DISK_ITEM, AgeListEntry); - ageListEntry = ageListEntry->Blink; - - if (runCount - diskItem->FreshTime < HISTORY_SIZE) // must compare like this to avoid overflow/underflow problems - break; - - PhInvokeCallback(&EtDiskItemRemovedEvent, diskItem); - - PhAcquireQueuedLockExclusive(&EtDiskHashtableLock); - EtpRemoveDiskItem(diskItem); - PhReleaseQueuedLockExclusive(&EtDiskHashtableLock); - } - - // Update existing items. - - ageListEntry = EtDiskAgeListHead.Flink; - - while (ageListEntry != &EtDiskAgeListHead) - { - PET_DISK_ITEM diskItem; - - diskItem = CONTAINING_RECORD(ageListEntry, ET_DISK_ITEM, AgeListEntry); - - // Update statistics. - - if (diskItem->HistoryPosition != 0) - diskItem->HistoryPosition--; - else - diskItem->HistoryPosition = HISTORY_SIZE - 1; - - diskItem->ReadHistory[diskItem->HistoryPosition] = diskItem->ReadDelta; - diskItem->WriteHistory[diskItem->HistoryPosition] = diskItem->WriteDelta; - - if (diskItem->HistoryCount < HISTORY_SIZE) - diskItem->HistoryCount++; - - if (diskItem->ResponseTimeCount != 0) - { - diskItem->ResponseTimeAverage = (FLOAT)diskItem->ResponseTimeTotal / diskItem->ResponseTimeCount; - - // Reset the total once in a while to avoid the number getting too large (and thus losing precision). - if (diskItem->ResponseTimeCount >= 1000) - { - diskItem->ResponseTimeTotal = diskItem->ResponseTimeAverage; - diskItem->ResponseTimeCount = 1; - } - } - - diskItem->ReadTotal += diskItem->ReadDelta; - diskItem->WriteTotal += diskItem->WriteDelta; - diskItem->ReadDelta = 0; - diskItem->WriteDelta = 0; - diskItem->ReadAverage = EtpCalculateAverage(diskItem->ReadHistory, HISTORY_SIZE, diskItem->HistoryPosition, diskItem->HistoryCount, HISTORY_SIZE); - diskItem->WriteAverage = EtpCalculateAverage(diskItem->WriteHistory, HISTORY_SIZE, diskItem->HistoryPosition, diskItem->HistoryCount, HISTORY_SIZE); - - if (diskItem->AddTime != runCount) - { - BOOLEAN modified = FALSE; - PPH_PROCESS_ITEM processItem; - - if (!diskItem->ProcessName || !diskItem->ProcessIcon || !diskItem->ProcessRecord) - { - if (processItem = PhReferenceProcessItem(diskItem->ProcessId)) - { - if (!diskItem->ProcessName) - { - PhSetReference(&diskItem->ProcessName, processItem->ProcessName); - modified = TRUE; - } - - if (!diskItem->ProcessIcon) - { - diskItem->ProcessIcon = EtProcIconReferenceSmallProcessIcon(EtGetProcessBlock(processItem)); - - if (diskItem->ProcessIcon) - modified = TRUE; - } - - if (!diskItem->ProcessRecord) - { - diskItem->ProcessRecord = processItem->Record; - PhReferenceProcessRecord(diskItem->ProcessRecord); - } - - PhDereferenceObject(processItem); - } - } - - if (modified) - { - // Raise the disk item modified event. - PhInvokeCallback(&EtDiskItemModifiedEvent, diskItem); - } - } - - ageListEntry = ageListEntry->Flink; - } - - PhInvokeCallback(&EtDiskItemsUpdatedEvent, NULL); - runCount++; -} +/* + * Process Hacker Extended Tools - + * ETW disk monitoring + * + * Copyright (C) 2011 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include "exttools.h" +#include "etwmon.h" + +typedef struct _ETP_DISK_PACKET +{ + SLIST_ENTRY ListEntry; + ET_ETW_DISK_EVENT Event; + PPH_STRING FileName; +} ETP_DISK_PACKET, *PETP_DISK_PACKET; + +VOID NTAPI EtpDiskItemDeleteProcedure( + _In_ PVOID Object, + _In_ ULONG Flags + ); + +BOOLEAN NTAPI EtpDiskHashtableEqualFunction( + _In_ PVOID Entry1, + _In_ PVOID Entry2 + ); + +ULONG NTAPI EtpDiskHashtableHashFunction( + _In_ PVOID Entry + ); + +VOID NTAPI EtpDiskProcessesUpdatedCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ); + +BOOLEAN EtDiskEnabled = FALSE; + +PPH_OBJECT_TYPE EtDiskItemType; +PPH_HASHTABLE EtDiskHashtable; +PH_QUEUED_LOCK EtDiskHashtableLock = PH_QUEUED_LOCK_INIT; +LIST_ENTRY EtDiskAgeListHead; +PH_CALLBACK_DECLARE(EtDiskItemAddedEvent); +PH_CALLBACK_DECLARE(EtDiskItemModifiedEvent); +PH_CALLBACK_DECLARE(EtDiskItemRemovedEvent); +PH_CALLBACK_DECLARE(EtDiskItemsUpdatedEvent); + +PH_FREE_LIST EtDiskPacketFreeList; +SLIST_HEADER EtDiskPacketListHead; +PPH_HASHTABLE EtFileNameHashtable; +PH_QUEUED_LOCK EtFileNameHashtableLock = PH_QUEUED_LOCK_INIT; + +static LARGE_INTEGER EtpPerformanceFrequency; +static PH_CALLBACK_REGISTRATION ProcessesUpdatedCallbackRegistration; + +VOID EtInitializeDiskInformation( + VOID + ) +{ + LARGE_INTEGER performanceCounter; + + EtDiskItemType = PhCreateObjectType(L"DiskItem", 0, EtpDiskItemDeleteProcedure); + EtDiskHashtable = PhCreateHashtable( + sizeof(PET_DISK_ITEM), + EtpDiskHashtableEqualFunction, + EtpDiskHashtableHashFunction, + 128 + ); + InitializeListHead(&EtDiskAgeListHead); + + PhInitializeFreeList(&EtDiskPacketFreeList, sizeof(ETP_DISK_PACKET), 64); + RtlInitializeSListHead(&EtDiskPacketListHead); + EtFileNameHashtable = PhCreateSimpleHashtable(128); + + NtQueryPerformanceCounter(&performanceCounter, &EtpPerformanceFrequency); + + EtDiskEnabled = TRUE; + + // Collect all existing file names. + EtStartEtwRundown(); + + PhRegisterCallback( + &PhProcessesUpdatedEvent, + EtpDiskProcessesUpdatedCallback, + NULL, + &ProcessesUpdatedCallbackRegistration + ); +} + +PET_DISK_ITEM EtCreateDiskItem( + VOID + ) +{ + PET_DISK_ITEM diskItem; + + diskItem = PhCreateObject(sizeof(ET_DISK_ITEM), EtDiskItemType); + memset(diskItem, 0, sizeof(ET_DISK_ITEM)); + + return diskItem; +} + +VOID NTAPI EtpDiskItemDeleteProcedure( + _In_ PVOID Object, + _In_ ULONG Flags + ) +{ + PET_DISK_ITEM diskItem = Object; + + if (diskItem->FileName) PhDereferenceObject(diskItem->FileName); + if (diskItem->FileNameWin32) PhDereferenceObject(diskItem->FileNameWin32); + if (diskItem->ProcessName) PhDereferenceObject(diskItem->ProcessName); + if (diskItem->ProcessIcon) EtProcIconDereferenceProcessIcon(diskItem->ProcessIcon); + if (diskItem->ProcessRecord) PhDereferenceProcessRecord(diskItem->ProcessRecord); +} + +BOOLEAN NTAPI EtpDiskHashtableEqualFunction( + _In_ PVOID Entry1, + _In_ PVOID Entry2 + ) +{ + PET_DISK_ITEM diskItem1 = *(PET_DISK_ITEM *)Entry1; + PET_DISK_ITEM diskItem2 = *(PET_DISK_ITEM *)Entry2; + + return diskItem1->ProcessId == diskItem2->ProcessId && PhEqualString(diskItem1->FileName, diskItem2->FileName, TRUE); +} + +ULONG NTAPI EtpDiskHashtableHashFunction( + _In_ PVOID Entry + ) +{ + PET_DISK_ITEM diskItem = *(PET_DISK_ITEM *)Entry; + + return (HandleToUlong(diskItem->ProcessId) / 4) ^ PhHashStringRef(&diskItem->FileName->sr, TRUE); +} + +PET_DISK_ITEM EtReferenceDiskItem( + _In_ HANDLE ProcessId, + _In_ PPH_STRING FileName + ) +{ + ET_DISK_ITEM lookupDiskItem; + PET_DISK_ITEM lookupDiskItemPtr = &lookupDiskItem; + PET_DISK_ITEM *diskItemPtr; + PET_DISK_ITEM diskItem; + + lookupDiskItem.ProcessId = ProcessId; + lookupDiskItem.FileName = FileName; + + PhAcquireQueuedLockShared(&EtDiskHashtableLock); + + diskItemPtr = (PET_DISK_ITEM *)PhFindEntryHashtable( + EtDiskHashtable, + &lookupDiskItemPtr + ); + + if (diskItemPtr) + PhSetReference(&diskItem, *diskItemPtr); + else + diskItem = NULL; + + PhReleaseQueuedLockShared(&EtDiskHashtableLock); + + return diskItem; +} + +VOID EtpRemoveDiskItem( + _In_ PET_DISK_ITEM DiskItem + ) +{ + RemoveEntryList(&DiskItem->AgeListEntry); + PhRemoveEntryHashtable(EtDiskHashtable, &DiskItem); + PhDereferenceObject(DiskItem); +} + +VOID EtDiskProcessDiskEvent( + _In_ PET_ETW_DISK_EVENT Event + ) +{ + PETP_DISK_PACKET packet; + + if (!EtDiskEnabled) + return; + + packet = PhAllocateFromFreeList(&EtDiskPacketFreeList); + memcpy(&packet->Event, Event, sizeof(ET_ETW_DISK_EVENT)); + packet->FileName = EtFileObjectToFileName(Event->FileObject); + RtlInterlockedPushEntrySList(&EtDiskPacketListHead, &packet->ListEntry); +} + +VOID EtDiskProcessFileEvent( + _In_ PET_ETW_FILE_EVENT Event + ) +{ + PH_KEY_VALUE_PAIR pair; + PPH_KEY_VALUE_PAIR realPair; + + if (!EtDiskEnabled) + return; + + if (Event->Type == EtEtwFileCreateType || Event->Type == EtEtwFileRundownType) + { + pair.Key = Event->FileObject; + pair.Value = NULL; + + PhAcquireQueuedLockExclusive(&EtFileNameHashtableLock); + + realPair = PhAddEntryHashtableEx(EtFileNameHashtable, &pair, NULL); + PhMoveReference(&realPair->Value, PhCreateString2(&Event->FileName)); + + PhReleaseQueuedLockExclusive(&EtFileNameHashtableLock); + } + else if (Event->Type == EtEtwFileDeleteType) + { + pair.Key = Event->FileObject; + + PhAcquireQueuedLockExclusive(&EtFileNameHashtableLock); + + realPair = PhFindEntryHashtable(EtFileNameHashtable, &pair); + + if (realPair) + { + PhDereferenceObject(realPair->Value); + PhRemoveEntryHashtable(EtFileNameHashtable, &pair); + } + + PhReleaseQueuedLockExclusive(&EtFileNameHashtableLock); + } +} + +PPH_STRING EtFileObjectToFileName( + _In_ PVOID FileObject + ) +{ + PH_KEY_VALUE_PAIR pair; + PPH_KEY_VALUE_PAIR realPair; + PPH_STRING fileName; + + pair.Key = FileObject; + fileName = NULL; + + PhAcquireQueuedLockShared(&EtFileNameHashtableLock); + + realPair = PhFindEntryHashtable(EtFileNameHashtable, &pair); + + if (realPair) + PhSetReference(&fileName, realPair->Value); + + PhReleaseQueuedLockShared(&EtFileNameHashtableLock); + + return fileName; +} + +VOID EtpProcessDiskPacket( + _In_ PETP_DISK_PACKET Packet, + _In_ ULONG RunId + ) +{ + PET_ETW_DISK_EVENT diskEvent; + PET_DISK_ITEM diskItem; + BOOLEAN added = FALSE; + + diskEvent = &Packet->Event; + + // We only process non-zero read/write events. + if (diskEvent->Type != EtEtwDiskReadType && diskEvent->Type != EtEtwDiskWriteType) + return; + if (diskEvent->TransferSize == 0) + return; + + // Ignore packets with no file name - this is useless to the user. + if (!Packet->FileName) + return; + + diskItem = EtReferenceDiskItem(diskEvent->ClientId.UniqueProcess, Packet->FileName); + + if (!diskItem) + { + PPH_PROCESS_ITEM processItem; + + // Disk item not found (or the address was re-used), create it. + + diskItem = EtCreateDiskItem(); + + diskItem->ProcessId = diskEvent->ClientId.UniqueProcess; + PhSetReference(&diskItem->FileName, Packet->FileName); + diskItem->FileNameWin32 = PhGetFileName(diskItem->FileName); + + if (processItem = PhReferenceProcessItem(diskItem->ProcessId)) + { + PhSetReference(&diskItem->ProcessName, processItem->ProcessName); + diskItem->ProcessIcon = EtProcIconReferenceSmallProcessIcon(EtGetProcessBlock(processItem)); + diskItem->ProcessRecord = processItem->Record; + PhReferenceProcessRecord(diskItem->ProcessRecord); + + PhDereferenceObject(processItem); + } + + // Add the disk item to the age list. + diskItem->AddTime = RunId; + diskItem->FreshTime = RunId; + InsertHeadList(&EtDiskAgeListHead, &diskItem->AgeListEntry); + + // Add the disk item to the hashtable. + PhAcquireQueuedLockExclusive(&EtDiskHashtableLock); + PhAddEntryHashtable(EtDiskHashtable, &diskItem); + PhReleaseQueuedLockExclusive(&EtDiskHashtableLock); + + // Raise the disk item added event. + PhInvokeCallback(&EtDiskItemAddedEvent, diskItem); + added = TRUE; + } + + // The I/O priority number needs to be decoded. + + diskItem->IoPriority = (diskEvent->IrpFlags >> 17) & 7; + + if (diskItem->IoPriority == 0) + diskItem->IoPriority = IoPriorityNormal; + else + diskItem->IoPriority--; + + // Accumulate statistics for this update period. + + if (diskEvent->Type == EtEtwDiskReadType) + diskItem->ReadDelta += diskEvent->TransferSize; + else + diskItem->WriteDelta += diskEvent->TransferSize; + + if (EtpPerformanceFrequency.QuadPart != 0) + { + // Convert the response time to milliseconds. + diskItem->ResponseTimeTotal += (FLOAT)diskEvent->HighResResponseTime * 1000 / EtpPerformanceFrequency.QuadPart; + diskItem->ResponseTimeCount++; + } + + if (!added) + { + if (diskItem->FreshTime != RunId) + { + diskItem->FreshTime = RunId; + RemoveEntryList(&diskItem->AgeListEntry); + InsertHeadList(&EtDiskAgeListHead, &diskItem->AgeListEntry); + } + + PhDereferenceObject(diskItem); + } +} + +ULONG64 EtpCalculateAverage( + _In_ PULONG64 Buffer, + _In_ ULONG BufferSize, + _In_ ULONG BufferPosition, + _In_ ULONG BufferCount, + _In_ ULONG NumberToConsider + ) +{ + ULONG64 sum; + ULONG i; + ULONG count; + + sum = 0; + i = BufferPosition; + + if (NumberToConsider > BufferCount) + NumberToConsider = BufferCount; + + if (NumberToConsider == 0) + return 0; + + count = NumberToConsider; + + do + { + sum += Buffer[i]; + i++; + + if (i == BufferSize) + i = 0; + } while (--count != 0); + + return sum / NumberToConsider; +} + +VOID NTAPI EtpDiskProcessesUpdatedCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + static ULONG runCount = 0; + + PSLIST_ENTRY listEntry; + PLIST_ENTRY ageListEntry; + + // Process incoming disk event packets. + + listEntry = RtlInterlockedFlushSList(&EtDiskPacketListHead); + + while (listEntry) + { + PETP_DISK_PACKET packet; + + packet = CONTAINING_RECORD(listEntry, ETP_DISK_PACKET, ListEntry); + listEntry = listEntry->Next; + + EtpProcessDiskPacket(packet, runCount); + + if (packet->FileName) + PhDereferenceObject(packet->FileName); + + PhFreeToFreeList(&EtDiskPacketFreeList, packet); + } + + // Remove old entries. + + ageListEntry = EtDiskAgeListHead.Blink; + + while (ageListEntry != &EtDiskAgeListHead) + { + PET_DISK_ITEM diskItem; + + diskItem = CONTAINING_RECORD(ageListEntry, ET_DISK_ITEM, AgeListEntry); + ageListEntry = ageListEntry->Blink; + + if (runCount - diskItem->FreshTime < HISTORY_SIZE) // must compare like this to avoid overflow/underflow problems + break; + + PhInvokeCallback(&EtDiskItemRemovedEvent, diskItem); + + PhAcquireQueuedLockExclusive(&EtDiskHashtableLock); + EtpRemoveDiskItem(diskItem); + PhReleaseQueuedLockExclusive(&EtDiskHashtableLock); + } + + // Update existing items. + + ageListEntry = EtDiskAgeListHead.Flink; + + while (ageListEntry != &EtDiskAgeListHead) + { + PET_DISK_ITEM diskItem; + + diskItem = CONTAINING_RECORD(ageListEntry, ET_DISK_ITEM, AgeListEntry); + + // Update statistics. + + if (diskItem->HistoryPosition != 0) + diskItem->HistoryPosition--; + else + diskItem->HistoryPosition = HISTORY_SIZE - 1; + + diskItem->ReadHistory[diskItem->HistoryPosition] = diskItem->ReadDelta; + diskItem->WriteHistory[diskItem->HistoryPosition] = diskItem->WriteDelta; + + if (diskItem->HistoryCount < HISTORY_SIZE) + diskItem->HistoryCount++; + + if (diskItem->ResponseTimeCount != 0) + { + diskItem->ResponseTimeAverage = (FLOAT)diskItem->ResponseTimeTotal / diskItem->ResponseTimeCount; + + // Reset the total once in a while to avoid the number getting too large (and thus losing precision). + if (diskItem->ResponseTimeCount >= 1000) + { + diskItem->ResponseTimeTotal = diskItem->ResponseTimeAverage; + diskItem->ResponseTimeCount = 1; + } + } + + diskItem->ReadTotal += diskItem->ReadDelta; + diskItem->WriteTotal += diskItem->WriteDelta; + diskItem->ReadDelta = 0; + diskItem->WriteDelta = 0; + diskItem->ReadAverage = EtpCalculateAverage(diskItem->ReadHistory, HISTORY_SIZE, diskItem->HistoryPosition, diskItem->HistoryCount, HISTORY_SIZE); + diskItem->WriteAverage = EtpCalculateAverage(diskItem->WriteHistory, HISTORY_SIZE, diskItem->HistoryPosition, diskItem->HistoryCount, HISTORY_SIZE); + + if (diskItem->AddTime != runCount) + { + BOOLEAN modified = FALSE; + PPH_PROCESS_ITEM processItem; + + if (!diskItem->ProcessName || !diskItem->ProcessIcon || !diskItem->ProcessRecord) + { + if (processItem = PhReferenceProcessItem(diskItem->ProcessId)) + { + if (!diskItem->ProcessName) + { + PhSetReference(&diskItem->ProcessName, processItem->ProcessName); + modified = TRUE; + } + + if (!diskItem->ProcessIcon) + { + diskItem->ProcessIcon = EtProcIconReferenceSmallProcessIcon(EtGetProcessBlock(processItem)); + + if (diskItem->ProcessIcon) + modified = TRUE; + } + + if (!diskItem->ProcessRecord) + { + diskItem->ProcessRecord = processItem->Record; + PhReferenceProcessRecord(diskItem->ProcessRecord); + } + + PhDereferenceObject(processItem); + } + } + + if (modified) + { + // Raise the disk item modified event. + PhInvokeCallback(&EtDiskItemModifiedEvent, diskItem); + } + } + + ageListEntry = ageListEntry->Flink; + } + + PhInvokeCallback(&EtDiskItemsUpdatedEvent, NULL); + runCount++; +} diff --git a/plugins/ExtendedTools/etwmini.c b/plugins/ExtendedTools/etwmini.c index 03c1c7013307..367c8dc61033 100644 --- a/plugins/ExtendedTools/etwmini.c +++ b/plugins/ExtendedTools/etwmini.c @@ -1,264 +1,264 @@ -/* - * Process Hacker Extended Tools - - * ETW mini information section - * - * Copyright (C) 2015 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include "exttools.h" -#include "etwmini.h" - -VOID EtEtwMiniInformationInitializing( - _In_ PPH_PLUGIN_MINIINFO_POINTERS Pointers - ) -{ - PH_MINIINFO_LIST_SECTION section; - - memset(§ion, 0, sizeof(PH_MINIINFO_LIST_SECTION)); - section.Callback = EtpDiskListSectionCallback; - Pointers->CreateListSection(L"Disk", 0, §ion); - - memset(§ion, 0, sizeof(PH_MINIINFO_LIST_SECTION)); - section.Callback = EtpNetworkListSectionCallback; - - Pointers->CreateListSection(L"Network", 0, §ion); -} - -BOOLEAN EtpDiskListSectionCallback( - _In_ struct _PH_MINIINFO_LIST_SECTION *ListSection, - _In_ PH_MINIINFO_LIST_SECTION_MESSAGE Message, - _In_opt_ PVOID Parameter1, - _In_opt_ PVOID Parameter2 - ) -{ - switch (Message) - { - case MiListSectionTick: - { - PH_FORMAT format[4]; - - PhInitFormatS(&format[0], L"Disk R: "); - PhInitFormatSize(&format[1], EtDiskReadDelta.Delta); - format[1].Type |= FormatUsePrecision; - format[1].Precision = 0; - PhInitFormatS(&format[2], L" W: "); - PhInitFormatSize(&format[3], EtDiskWriteDelta.Delta); - format[3].Type |= FormatUsePrecision; - format[3].Precision = 0; - ListSection->Section->Parameters->SetSectionText(ListSection->Section, - PH_AUTO(PhFormat(format, 4, 50))); - } - break; - case MiListSectionSortProcessList: - { - PPH_MINIINFO_LIST_SECTION_SORT_LIST sortList = Parameter1; - - qsort(sortList->List->Items, sortList->List->Count, - sizeof(PPH_PROCESS_NODE), EtpDiskListSectionProcessCompareFunction); - } - return TRUE; - case MiListSectionAssignSortData: - { - PPH_MINIINFO_LIST_SECTION_ASSIGN_SORT_DATA assignSortData = Parameter1; - PPH_LIST processes = assignSortData->ProcessGroup->Processes; - ULONG64 diskReadDelta = 0; - ULONG64 diskWriteDelta = 0; - ULONG i; - - for (i = 0; i < processes->Count; i++) - { - PPH_PROCESS_ITEM processItem = processes->Items[i]; - PET_PROCESS_BLOCK block = EtGetProcessBlock(processItem); - diskReadDelta += block->DiskReadRawDelta.Delta; - diskWriteDelta += block->DiskWriteRawDelta.Delta; - } - - assignSortData->SortData->UserData[0] = diskReadDelta; - assignSortData->SortData->UserData[1] = diskWriteDelta; - } - return TRUE; - case MiListSectionSortGroupList: - { - PPH_MINIINFO_LIST_SECTION_SORT_LIST sortList = Parameter1; - - qsort(sortList->List->Items, sortList->List->Count, - sizeof(PPH_MINIINFO_LIST_SECTION_SORT_DATA), EtpDiskListSectionNodeCompareFunction); - } - return TRUE; - case MiListSectionGetUsageText: - { - PPH_MINIINFO_LIST_SECTION_GET_USAGE_TEXT getUsageText = Parameter1; - PPH_LIST processes = getUsageText->ProcessGroup->Processes; - ULONG64 diskReadDelta = getUsageText->SortData->UserData[0]; - ULONG64 diskWriteDelta = getUsageText->SortData->UserData[1]; - PH_FORMAT format[1]; - - PhInitFormatSize(&format[0], diskReadDelta + diskWriteDelta); - PhMoveReference(&getUsageText->Line1, PhFormat(format, 1, 16)); - } - return TRUE; - } - - return FALSE; -} - -int __cdecl EtpDiskListSectionProcessCompareFunction( - _In_ const void *elem1, - _In_ const void *elem2 - ) -{ - int result; - PPH_PROCESS_NODE node1 = *(PPH_PROCESS_NODE *)elem1; - PPH_PROCESS_NODE node2 = *(PPH_PROCESS_NODE *)elem2; - PET_PROCESS_BLOCK block1 = EtGetProcessBlock(node1->ProcessItem); - PET_PROCESS_BLOCK block2 = EtGetProcessBlock(node2->ProcessItem); - ULONG64 total1 = block1->DiskReadRawDelta.Delta + block1->DiskWriteRawDelta.Delta; - ULONG64 total2 = block2->DiskReadRawDelta.Delta + block2->DiskWriteRawDelta.Delta; - - result = uint64cmp(total2, total1); - - if (result == 0) - result = uint64cmp(block2->DiskReadRaw + block2->DiskWriteRaw, block1->DiskReadRaw + block1->DiskWriteRaw); - if (result == 0) - result = singlecmp(node2->ProcessItem->CpuUsage, node1->ProcessItem->CpuUsage); - - return result; -} - -int __cdecl EtpDiskListSectionNodeCompareFunction( - _In_ const void *elem1, - _In_ const void *elem2 - ) -{ - PPH_MINIINFO_LIST_SECTION_SORT_DATA data1 = *(PPH_MINIINFO_LIST_SECTION_SORT_DATA *)elem1; - PPH_MINIINFO_LIST_SECTION_SORT_DATA data2 = *(PPH_MINIINFO_LIST_SECTION_SORT_DATA *)elem2; - - return uint64cmp(data2->UserData[0] + data2->UserData[1], data1->UserData[0] + data1->UserData[1]); -} - -BOOLEAN EtpNetworkListSectionCallback( - _In_ struct _PH_MINIINFO_LIST_SECTION *ListSection, - _In_ PH_MINIINFO_LIST_SECTION_MESSAGE Message, - _In_opt_ PVOID Parameter1, - _In_opt_ PVOID Parameter2 - ) -{ - switch (Message) - { - case MiListSectionTick: - { - PH_FORMAT format[4]; - - PhInitFormatS(&format[0], L"Network R: "); - PhInitFormatSize(&format[1], EtNetworkReceiveDelta.Delta); - format[1].Type |= FormatUsePrecision; - format[1].Precision = 0; - PhInitFormatS(&format[2], L" S: "); - PhInitFormatSize(&format[3], EtNetworkSendDelta.Delta); - format[3].Type |= FormatUsePrecision; - format[3].Precision = 0; - ListSection->Section->Parameters->SetSectionText(ListSection->Section, - PH_AUTO(PhFormat(format, 4, 50))); - } - break; - case MiListSectionSortProcessList: - { - PPH_MINIINFO_LIST_SECTION_SORT_LIST sortList = Parameter1; - - qsort(sortList->List->Items, sortList->List->Count, - sizeof(PPH_PROCESS_NODE), EtpNetworkListSectionProcessCompareFunction); - } - return TRUE; - case MiListSectionAssignSortData: - { - PPH_MINIINFO_LIST_SECTION_ASSIGN_SORT_DATA assignSortData = Parameter1; - PPH_LIST processes = assignSortData->ProcessGroup->Processes; - ULONG64 networkReceiveDelta = 0; - ULONG64 networkSendDelta = 0; - ULONG i; - - for (i = 0; i < processes->Count; i++) - { - PPH_PROCESS_ITEM processItem = processes->Items[i]; - PET_PROCESS_BLOCK block = EtGetProcessBlock(processItem); - networkReceiveDelta += block->NetworkReceiveRawDelta.Delta; - networkSendDelta += block->NetworkSendRawDelta.Delta; - } - - assignSortData->SortData->UserData[0] = networkReceiveDelta; - assignSortData->SortData->UserData[1] = networkSendDelta; - } - return TRUE; - case MiListSectionSortGroupList: - { - PPH_MINIINFO_LIST_SECTION_SORT_LIST sortList = Parameter1; - - qsort(sortList->List->Items, sortList->List->Count, - sizeof(PPH_MINIINFO_LIST_SECTION_SORT_DATA), EtpNetworkListSectionNodeCompareFunction); - } - return TRUE; - case MiListSectionGetUsageText: - { - PPH_MINIINFO_LIST_SECTION_GET_USAGE_TEXT getUsageText = Parameter1; - PPH_LIST processes = getUsageText->ProcessGroup->Processes; - ULONG64 networkReceiveDelta = getUsageText->SortData->UserData[0]; - ULONG64 networkSendDelta = getUsageText->SortData->UserData[1]; - PH_FORMAT format[1]; - - PhInitFormatSize(&format[0], networkReceiveDelta + networkSendDelta); - PhMoveReference(&getUsageText->Line1, PhFormat(format, 1, 16)); - } - return TRUE; - } - - return FALSE; -} - -int __cdecl EtpNetworkListSectionProcessCompareFunction( - _In_ const void *elem1, - _In_ const void *elem2 - ) -{ - int result; - PPH_PROCESS_NODE node1 = *(PPH_PROCESS_NODE *)elem1; - PPH_PROCESS_NODE node2 = *(PPH_PROCESS_NODE *)elem2; - PET_PROCESS_BLOCK block1 = EtGetProcessBlock(node1->ProcessItem); - PET_PROCESS_BLOCK block2 = EtGetProcessBlock(node2->ProcessItem); - ULONG64 total1 = block1->NetworkReceiveRawDelta.Delta + block1->NetworkSendRawDelta.Delta; - ULONG64 total2 = block2->NetworkReceiveRawDelta.Delta + block2->NetworkSendRawDelta.Delta; - - result = uint64cmp(total2, total1); - - if (result == 0) - result = uint64cmp(block2->NetworkReceiveRaw + block2->NetworkSendRaw, block1->NetworkReceiveRaw + block1->NetworkSendRaw); - if (result == 0) - result = singlecmp(node2->ProcessItem->CpuUsage, node1->ProcessItem->CpuUsage); - - return result; -} - -int __cdecl EtpNetworkListSectionNodeCompareFunction( - _In_ const void *elem1, - _In_ const void *elem2 - ) -{ - PPH_MINIINFO_LIST_SECTION_SORT_DATA data1 = *(PPH_MINIINFO_LIST_SECTION_SORT_DATA *)elem1; - PPH_MINIINFO_LIST_SECTION_SORT_DATA data2 = *(PPH_MINIINFO_LIST_SECTION_SORT_DATA *)elem2; - - return uint64cmp(data2->UserData[0] + data2->UserData[1], data1->UserData[0] + data1->UserData[1]); -} +/* + * Process Hacker Extended Tools - + * ETW mini information section + * + * Copyright (C) 2015 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include "exttools.h" +#include "etwmini.h" + +VOID EtEtwMiniInformationInitializing( + _In_ PPH_PLUGIN_MINIINFO_POINTERS Pointers + ) +{ + PH_MINIINFO_LIST_SECTION section; + + memset(§ion, 0, sizeof(PH_MINIINFO_LIST_SECTION)); + section.Callback = EtpDiskListSectionCallback; + Pointers->CreateListSection(L"Disk", 0, §ion); + + memset(§ion, 0, sizeof(PH_MINIINFO_LIST_SECTION)); + section.Callback = EtpNetworkListSectionCallback; + + Pointers->CreateListSection(L"Network", 0, §ion); +} + +BOOLEAN EtpDiskListSectionCallback( + _In_ struct _PH_MINIINFO_LIST_SECTION *ListSection, + _In_ PH_MINIINFO_LIST_SECTION_MESSAGE Message, + _In_opt_ PVOID Parameter1, + _In_opt_ PVOID Parameter2 + ) +{ + switch (Message) + { + case MiListSectionTick: + { + PH_FORMAT format[4]; + + PhInitFormatS(&format[0], L"Disk R: "); + PhInitFormatSize(&format[1], EtDiskReadDelta.Delta); + format[1].Type |= FormatUsePrecision; + format[1].Precision = 0; + PhInitFormatS(&format[2], L" W: "); + PhInitFormatSize(&format[3], EtDiskWriteDelta.Delta); + format[3].Type |= FormatUsePrecision; + format[3].Precision = 0; + ListSection->Section->Parameters->SetSectionText(ListSection->Section, + PH_AUTO(PhFormat(format, 4, 50))); + } + break; + case MiListSectionSortProcessList: + { + PPH_MINIINFO_LIST_SECTION_SORT_LIST sortList = Parameter1; + + qsort(sortList->List->Items, sortList->List->Count, + sizeof(PPH_PROCESS_NODE), EtpDiskListSectionProcessCompareFunction); + } + return TRUE; + case MiListSectionAssignSortData: + { + PPH_MINIINFO_LIST_SECTION_ASSIGN_SORT_DATA assignSortData = Parameter1; + PPH_LIST processes = assignSortData->ProcessGroup->Processes; + ULONG64 diskReadDelta = 0; + ULONG64 diskWriteDelta = 0; + ULONG i; + + for (i = 0; i < processes->Count; i++) + { + PPH_PROCESS_ITEM processItem = processes->Items[i]; + PET_PROCESS_BLOCK block = EtGetProcessBlock(processItem); + diskReadDelta += block->DiskReadRawDelta.Delta; + diskWriteDelta += block->DiskWriteRawDelta.Delta; + } + + assignSortData->SortData->UserData[0] = diskReadDelta; + assignSortData->SortData->UserData[1] = diskWriteDelta; + } + return TRUE; + case MiListSectionSortGroupList: + { + PPH_MINIINFO_LIST_SECTION_SORT_LIST sortList = Parameter1; + + qsort(sortList->List->Items, sortList->List->Count, + sizeof(PPH_MINIINFO_LIST_SECTION_SORT_DATA), EtpDiskListSectionNodeCompareFunction); + } + return TRUE; + case MiListSectionGetUsageText: + { + PPH_MINIINFO_LIST_SECTION_GET_USAGE_TEXT getUsageText = Parameter1; + PPH_LIST processes = getUsageText->ProcessGroup->Processes; + ULONG64 diskReadDelta = getUsageText->SortData->UserData[0]; + ULONG64 diskWriteDelta = getUsageText->SortData->UserData[1]; + PH_FORMAT format[1]; + + PhInitFormatSize(&format[0], diskReadDelta + diskWriteDelta); + PhMoveReference(&getUsageText->Line1, PhFormat(format, 1, 16)); + } + return TRUE; + } + + return FALSE; +} + +int __cdecl EtpDiskListSectionProcessCompareFunction( + _In_ const void *elem1, + _In_ const void *elem2 + ) +{ + int result; + PPH_PROCESS_NODE node1 = *(PPH_PROCESS_NODE *)elem1; + PPH_PROCESS_NODE node2 = *(PPH_PROCESS_NODE *)elem2; + PET_PROCESS_BLOCK block1 = EtGetProcessBlock(node1->ProcessItem); + PET_PROCESS_BLOCK block2 = EtGetProcessBlock(node2->ProcessItem); + ULONG64 total1 = block1->DiskReadRawDelta.Delta + block1->DiskWriteRawDelta.Delta; + ULONG64 total2 = block2->DiskReadRawDelta.Delta + block2->DiskWriteRawDelta.Delta; + + result = uint64cmp(total2, total1); + + if (result == 0) + result = uint64cmp(block2->DiskReadRaw + block2->DiskWriteRaw, block1->DiskReadRaw + block1->DiskWriteRaw); + if (result == 0) + result = singlecmp(node2->ProcessItem->CpuUsage, node1->ProcessItem->CpuUsage); + + return result; +} + +int __cdecl EtpDiskListSectionNodeCompareFunction( + _In_ const void *elem1, + _In_ const void *elem2 + ) +{ + PPH_MINIINFO_LIST_SECTION_SORT_DATA data1 = *(PPH_MINIINFO_LIST_SECTION_SORT_DATA *)elem1; + PPH_MINIINFO_LIST_SECTION_SORT_DATA data2 = *(PPH_MINIINFO_LIST_SECTION_SORT_DATA *)elem2; + + return uint64cmp(data2->UserData[0] + data2->UserData[1], data1->UserData[0] + data1->UserData[1]); +} + +BOOLEAN EtpNetworkListSectionCallback( + _In_ struct _PH_MINIINFO_LIST_SECTION *ListSection, + _In_ PH_MINIINFO_LIST_SECTION_MESSAGE Message, + _In_opt_ PVOID Parameter1, + _In_opt_ PVOID Parameter2 + ) +{ + switch (Message) + { + case MiListSectionTick: + { + PH_FORMAT format[4]; + + PhInitFormatS(&format[0], L"Network R: "); + PhInitFormatSize(&format[1], EtNetworkReceiveDelta.Delta); + format[1].Type |= FormatUsePrecision; + format[1].Precision = 0; + PhInitFormatS(&format[2], L" S: "); + PhInitFormatSize(&format[3], EtNetworkSendDelta.Delta); + format[3].Type |= FormatUsePrecision; + format[3].Precision = 0; + ListSection->Section->Parameters->SetSectionText(ListSection->Section, + PH_AUTO(PhFormat(format, 4, 50))); + } + break; + case MiListSectionSortProcessList: + { + PPH_MINIINFO_LIST_SECTION_SORT_LIST sortList = Parameter1; + + qsort(sortList->List->Items, sortList->List->Count, + sizeof(PPH_PROCESS_NODE), EtpNetworkListSectionProcessCompareFunction); + } + return TRUE; + case MiListSectionAssignSortData: + { + PPH_MINIINFO_LIST_SECTION_ASSIGN_SORT_DATA assignSortData = Parameter1; + PPH_LIST processes = assignSortData->ProcessGroup->Processes; + ULONG64 networkReceiveDelta = 0; + ULONG64 networkSendDelta = 0; + ULONG i; + + for (i = 0; i < processes->Count; i++) + { + PPH_PROCESS_ITEM processItem = processes->Items[i]; + PET_PROCESS_BLOCK block = EtGetProcessBlock(processItem); + networkReceiveDelta += block->NetworkReceiveRawDelta.Delta; + networkSendDelta += block->NetworkSendRawDelta.Delta; + } + + assignSortData->SortData->UserData[0] = networkReceiveDelta; + assignSortData->SortData->UserData[1] = networkSendDelta; + } + return TRUE; + case MiListSectionSortGroupList: + { + PPH_MINIINFO_LIST_SECTION_SORT_LIST sortList = Parameter1; + + qsort(sortList->List->Items, sortList->List->Count, + sizeof(PPH_MINIINFO_LIST_SECTION_SORT_DATA), EtpNetworkListSectionNodeCompareFunction); + } + return TRUE; + case MiListSectionGetUsageText: + { + PPH_MINIINFO_LIST_SECTION_GET_USAGE_TEXT getUsageText = Parameter1; + PPH_LIST processes = getUsageText->ProcessGroup->Processes; + ULONG64 networkReceiveDelta = getUsageText->SortData->UserData[0]; + ULONG64 networkSendDelta = getUsageText->SortData->UserData[1]; + PH_FORMAT format[1]; + + PhInitFormatSize(&format[0], networkReceiveDelta + networkSendDelta); + PhMoveReference(&getUsageText->Line1, PhFormat(format, 1, 16)); + } + return TRUE; + } + + return FALSE; +} + +int __cdecl EtpNetworkListSectionProcessCompareFunction( + _In_ const void *elem1, + _In_ const void *elem2 + ) +{ + int result; + PPH_PROCESS_NODE node1 = *(PPH_PROCESS_NODE *)elem1; + PPH_PROCESS_NODE node2 = *(PPH_PROCESS_NODE *)elem2; + PET_PROCESS_BLOCK block1 = EtGetProcessBlock(node1->ProcessItem); + PET_PROCESS_BLOCK block2 = EtGetProcessBlock(node2->ProcessItem); + ULONG64 total1 = block1->NetworkReceiveRawDelta.Delta + block1->NetworkSendRawDelta.Delta; + ULONG64 total2 = block2->NetworkReceiveRawDelta.Delta + block2->NetworkSendRawDelta.Delta; + + result = uint64cmp(total2, total1); + + if (result == 0) + result = uint64cmp(block2->NetworkReceiveRaw + block2->NetworkSendRaw, block1->NetworkReceiveRaw + block1->NetworkSendRaw); + if (result == 0) + result = singlecmp(node2->ProcessItem->CpuUsage, node1->ProcessItem->CpuUsage); + + return result; +} + +int __cdecl EtpNetworkListSectionNodeCompareFunction( + _In_ const void *elem1, + _In_ const void *elem2 + ) +{ + PPH_MINIINFO_LIST_SECTION_SORT_DATA data1 = *(PPH_MINIINFO_LIST_SECTION_SORT_DATA *)elem1; + PPH_MINIINFO_LIST_SECTION_SORT_DATA data2 = *(PPH_MINIINFO_LIST_SECTION_SORT_DATA *)elem2; + + return uint64cmp(data2->UserData[0] + data2->UserData[1], data1->UserData[0] + data1->UserData[1]); +} diff --git a/plugins/ExtendedTools/etwmini.h b/plugins/ExtendedTools/etwmini.h index 6237b81e68b9..0c394a4f64a3 100644 --- a/plugins/ExtendedTools/etwmini.h +++ b/plugins/ExtendedTools/etwmini.h @@ -1,38 +1,38 @@ -#ifndef ETWMINI_H -#define ETWMINI_H - -BOOLEAN EtpDiskListSectionCallback( - _In_ struct _PH_MINIINFO_LIST_SECTION *ListSection, - _In_ PH_MINIINFO_LIST_SECTION_MESSAGE Message, - _In_opt_ PVOID Parameter1, - _In_opt_ PVOID Parameter2 - ); - -int __cdecl EtpDiskListSectionProcessCompareFunction( - _In_ const void *elem1, - _In_ const void *elem2 - ); - -int __cdecl EtpDiskListSectionNodeCompareFunction( - _In_ const void *elem1, - _In_ const void *elem2 - ); - -BOOLEAN EtpNetworkListSectionCallback( - _In_ struct _PH_MINIINFO_LIST_SECTION *ListSection, - _In_ PH_MINIINFO_LIST_SECTION_MESSAGE Message, - _In_opt_ PVOID Parameter1, - _In_opt_ PVOID Parameter2 - ); - -int __cdecl EtpNetworkListSectionProcessCompareFunction( - _In_ const void *elem1, - _In_ const void *elem2 - ); - -int __cdecl EtpNetworkListSectionNodeCompareFunction( - _In_ const void *elem1, - _In_ const void *elem2 - ); - +#ifndef ETWMINI_H +#define ETWMINI_H + +BOOLEAN EtpDiskListSectionCallback( + _In_ struct _PH_MINIINFO_LIST_SECTION *ListSection, + _In_ PH_MINIINFO_LIST_SECTION_MESSAGE Message, + _In_opt_ PVOID Parameter1, + _In_opt_ PVOID Parameter2 + ); + +int __cdecl EtpDiskListSectionProcessCompareFunction( + _In_ const void *elem1, + _In_ const void *elem2 + ); + +int __cdecl EtpDiskListSectionNodeCompareFunction( + _In_ const void *elem1, + _In_ const void *elem2 + ); + +BOOLEAN EtpNetworkListSectionCallback( + _In_ struct _PH_MINIINFO_LIST_SECTION *ListSection, + _In_ PH_MINIINFO_LIST_SECTION_MESSAGE Message, + _In_opt_ PVOID Parameter1, + _In_opt_ PVOID Parameter2 + ); + +int __cdecl EtpNetworkListSectionProcessCompareFunction( + _In_ const void *elem1, + _In_ const void *elem2 + ); + +int __cdecl EtpNetworkListSectionNodeCompareFunction( + _In_ const void *elem1, + _In_ const void *elem2 + ); + #endif \ No newline at end of file diff --git a/plugins/ExtendedTools/etwmon.c b/plugins/ExtendedTools/etwmon.c index e106bb123f85..7c4823ae21ba 100644 --- a/plugins/ExtendedTools/etwmon.c +++ b/plugins/ExtendedTools/etwmon.c @@ -1,562 +1,562 @@ -/* - * Process Hacker Extended Tools - - * ETW monitoring - * - * Copyright (C) 2010-2015 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include "exttools.h" -#include "etwmon.h" - -ULONG NTAPI EtpEtwBufferCallback( - _In_ PEVENT_TRACE_LOGFILE Buffer - ); - -VOID NTAPI EtpEtwEventCallback( - _In_ PEVENT_RECORD EventRecord - ); - -NTSTATUS EtpEtwMonitorThreadStart( - _In_ PVOID Parameter - ); - -ULONG EtpStopEtwRundownSession( - VOID - ); - -ULONG NTAPI EtpRundownEtwBufferCallback( - _In_ PEVENT_TRACE_LOGFILE Buffer - ); - -VOID NTAPI EtpRundownEtwEventCallback( - _In_ PEVENT_RECORD EventRecord - ); - -NTSTATUS EtpRundownEtwMonitorThreadStart( - _In_ PVOID Parameter - ); - -static GUID ProcessHackerGuid = { 0x1288c53b, 0xaf35, 0x481b, { 0xb6, 0xb5, 0xa0, 0x5c, 0x39, 0x87, 0x2e, 0xd } }; -static GUID SystemTraceControlGuid_I = { 0x9e814aad, 0x3204, 0x11d2, { 0x9a, 0x82, 0x00, 0x60, 0x08, 0xa8, 0x69, 0x39 } }; -static GUID KernelRundownGuid_I = { 0x3b9c9951, 0x3480, 0x4220, { 0x93, 0x77, 0x9c, 0x8e, 0x51, 0x84, 0xf5, 0xcd } }; -static GUID DiskIoGuid_I = { 0x3d6fa8d4, 0xfe05, 0x11d0, { 0x9d, 0xda, 0x00, 0xc0, 0x4f, 0xd7, 0xba, 0x7c } }; -static GUID FileIoGuid_I = { 0x90cbdc39, 0x4a3e, 0x11d1, { 0x84, 0xf4, 0x00, 0x00, 0xf8, 0x04, 0x64, 0xe3 } }; -static GUID TcpIpGuid_I = { 0x9a280ac0, 0xc8e0, 0x11d1, { 0x84, 0xe2, 0x00, 0xc0, 0x4f, 0xb9, 0x98, 0xa2 } }; -static GUID UdpIpGuid_I = { 0xbf3a50c5, 0xa9c9, 0x4988, { 0xa0, 0x05, 0x2d, 0xf0, 0xb7, 0xc8, 0x0f, 0x80 } }; - -// ETW tracing layer - -BOOLEAN EtEtwEnabled; -static UNICODE_STRING EtpSharedKernelLoggerName = RTL_CONSTANT_STRING(KERNEL_LOGGER_NAME); -static UNICODE_STRING EtpPrivateKernelLoggerName = RTL_CONSTANT_STRING(L"PhEtKernelLogger"); -static TRACEHANDLE EtpSessionHandle; -static PUNICODE_STRING EtpActualKernelLoggerName; -static PGUID EtpActualSessionGuid; -static PEVENT_TRACE_PROPERTIES EtpTraceProperties; -static BOOLEAN EtpEtwActive; -static BOOLEAN EtpStartedSession; -static BOOLEAN EtpEtwExiting; -static HANDLE EtpEtwMonitorThreadHandle; - -// ETW rundown layer - -static UNICODE_STRING EtpRundownLoggerName = RTL_CONSTANT_STRING(L"PhEtRundownLogger"); -static TRACEHANDLE EtpRundownSessionHandle; -static PEVENT_TRACE_PROPERTIES EtpRundownTraceProperties; -static BOOLEAN EtpRundownActive; -static HANDLE EtpRundownEtwMonitorThreadHandle; - -VOID EtEtwMonitorInitialization( - VOID - ) -{ - if (PhGetOwnTokenAttributes().Elevated && PhGetIntegerSetting(SETTING_NAME_ENABLE_ETW_MONITOR)) - { - EtStartEtwSession(); - - if (EtEtwEnabled) - EtpEtwMonitorThreadHandle = PhCreateThread(0, EtpEtwMonitorThreadStart, NULL); - } -} - -VOID EtEtwMonitorUninitialization( - VOID - ) -{ - if (EtEtwEnabled) - { - EtpEtwExiting = TRUE; - EtStopEtwSession(); - } - - if (EtpRundownActive) - { - EtpStopEtwRundownSession(); - } -} - -VOID EtStartEtwSession( - VOID - ) -{ - ULONG result; - ULONG bufferSize; - - if (WindowsVersion >= WINDOWS_8) - { - EtpActualKernelLoggerName = &EtpPrivateKernelLoggerName; - EtpActualSessionGuid = &ProcessHackerGuid; - } - else - { - EtpActualKernelLoggerName = &EtpSharedKernelLoggerName; - EtpActualSessionGuid = &SystemTraceControlGuid_I; - } - - bufferSize = sizeof(EVENT_TRACE_PROPERTIES) + EtpActualKernelLoggerName->Length + sizeof(WCHAR); - - if (!EtpTraceProperties) - EtpTraceProperties = PhAllocate(bufferSize); - - memset(EtpTraceProperties, 0, sizeof(EVENT_TRACE_PROPERTIES)); - - EtpTraceProperties->Wnode.BufferSize = bufferSize; - EtpTraceProperties->Wnode.Guid = *EtpActualSessionGuid; - EtpTraceProperties->Wnode.ClientContext = 1; - EtpTraceProperties->Wnode.Flags = WNODE_FLAG_TRACED_GUID; - EtpTraceProperties->MinimumBuffers = 1; - EtpTraceProperties->LogFileMode = EVENT_TRACE_REAL_TIME_MODE; - EtpTraceProperties->FlushTimer = 1; - EtpTraceProperties->EnableFlags = EVENT_TRACE_FLAG_DISK_IO | EVENT_TRACE_FLAG_DISK_FILE_IO | EVENT_TRACE_FLAG_NETWORK_TCPIP; - EtpTraceProperties->LogFileNameOffset = 0; - EtpTraceProperties->LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES); - - if (WindowsVersion >= WINDOWS_8) - EtpTraceProperties->LogFileMode |= EVENT_TRACE_SYSTEM_LOGGER_MODE; - - result = StartTrace(&EtpSessionHandle, EtpActualKernelLoggerName->Buffer, EtpTraceProperties); - - if (result == ERROR_SUCCESS) - { - EtEtwEnabled = TRUE; - EtpEtwActive = TRUE; - EtpStartedSession = TRUE; - } - else if (result == ERROR_ALREADY_EXISTS) - { - EtEtwEnabled = TRUE; - EtpEtwActive = TRUE; - EtpStartedSession = FALSE; - // The session already exists. - //result = ControlTrace(0, EtpActualKernelLoggerName->Buffer, EtpTraceProperties, EVENT_TRACE_CONTROL_UPDATE); - } - else - { - EtpEtwActive = FALSE; - EtpStartedSession = FALSE; - } -} - -ULONG EtpControlEtwSession( - _In_ ULONG ControlCode - ) -{ - // If we have a session handle, we use that instead of the logger name. - - EtpTraceProperties->LogFileNameOffset = 0; // make sure it is 0, otherwise ControlTrace crashes - - return ControlTrace( - EtpStartedSession ? EtpSessionHandle : 0, - EtpStartedSession ? NULL : EtpActualKernelLoggerName->Buffer, - EtpTraceProperties, - ControlCode - ); -} - -VOID EtStopEtwSession( - VOID - ) -{ - if (EtEtwEnabled) - EtpControlEtwSession(EVENT_TRACE_CONTROL_STOP); -} - -VOID EtFlushEtwSession( - VOID - ) -{ - if (EtEtwEnabled) - EtpControlEtwSession(EVENT_TRACE_CONTROL_FLUSH); -} - -ULONG NTAPI EtpEtwBufferCallback( - _In_ PEVENT_TRACE_LOGFILE Buffer - ) -{ - return !EtpEtwExiting; -} - -VOID NTAPI EtpEtwEventCallback( - _In_ PEVENT_RECORD EventRecord - ) -{ - if (memcmp(&EventRecord->EventHeader.ProviderId, &DiskIoGuid_I, sizeof(GUID)) == 0) - { - // DiskIo - - ET_ETW_DISK_EVENT diskEvent; - - memset(&diskEvent, 0, sizeof(ET_ETW_DISK_EVENT)); - diskEvent.Type = -1; - - switch (EventRecord->EventHeader.EventDescriptor.Opcode) - { - case EVENT_TRACE_TYPE_IO_READ: - diskEvent.Type = EtEtwDiskReadType; - break; - case EVENT_TRACE_TYPE_IO_WRITE: - diskEvent.Type = EtEtwDiskWriteType; - break; - default: - break; - } - - if (diskEvent.Type != -1) - { - DiskIo_TypeGroup1 *data = EventRecord->UserData; - - if (WindowsVersion >= WINDOWS_8) - { - diskEvent.ClientId.UniqueThread = UlongToHandle(data->IssuingThreadId); - diskEvent.ClientId.UniqueProcess = EtThreadIdToProcessId(diskEvent.ClientId.UniqueThread); - } - else - { - if (EventRecord->EventHeader.ProcessId != -1) - { - diskEvent.ClientId.UniqueProcess = UlongToHandle(EventRecord->EventHeader.ProcessId); - diskEvent.ClientId.UniqueThread = UlongToHandle(EventRecord->EventHeader.ThreadId); - } - } - - diskEvent.IrpFlags = data->IrpFlags; - diskEvent.TransferSize = data->TransferSize; - diskEvent.FileObject = (PVOID)data->FileObject; - diskEvent.HighResResponseTime = data->HighResResponseTime; - - EtProcessDiskEvent(&diskEvent); - EtDiskProcessDiskEvent(&diskEvent); - } - } - else if (memcmp(&EventRecord->EventHeader.ProviderId, &FileIoGuid_I, sizeof(GUID)) == 0) - { - // FileIo - - ET_ETW_FILE_EVENT fileEvent; - - memset(&fileEvent, 0, sizeof(ET_ETW_FILE_EVENT)); - fileEvent.Type = -1; - - switch (EventRecord->EventHeader.EventDescriptor.Opcode) - { - case 0: // Name - fileEvent.Type = EtEtwFileNameType; - break; - case 32: // FileCreate - fileEvent.Type = EtEtwFileCreateType; - break; - case 35: // FileDelete - fileEvent.Type = EtEtwFileDeleteType; - break; - default: - break; - } - - if (fileEvent.Type != -1) - { - FileIo_Name *data = EventRecord->UserData; - - fileEvent.FileObject = (PVOID)data->FileObject; - PhInitializeStringRef(&fileEvent.FileName, data->FileName); - - EtDiskProcessFileEvent(&fileEvent); - } - } - else if ( - memcmp(&EventRecord->EventHeader.ProviderId, &TcpIpGuid_I, sizeof(GUID)) == 0 || - memcmp(&EventRecord->EventHeader.ProviderId, &UdpIpGuid_I, sizeof(GUID)) == 0 - ) - { - // TcpIp/UdpIp - - ET_ETW_NETWORK_EVENT networkEvent; - - memset(&networkEvent, 0, sizeof(ET_ETW_NETWORK_EVENT)); - networkEvent.Type = -1; - - switch (EventRecord->EventHeader.EventDescriptor.Opcode) - { - case EVENT_TRACE_TYPE_SEND: // send - networkEvent.Type = EtEtwNetworkSendType; - networkEvent.ProtocolType = PH_IPV4_NETWORK_TYPE; - break; - case EVENT_TRACE_TYPE_RECEIVE: // receive - networkEvent.Type = EtEtwNetworkReceiveType; - networkEvent.ProtocolType = PH_IPV4_NETWORK_TYPE; - break; - case EVENT_TRACE_TYPE_SEND + 16: // send ipv6 - networkEvent.Type = EtEtwNetworkSendType; - networkEvent.ProtocolType = PH_IPV6_NETWORK_TYPE; - break; - case EVENT_TRACE_TYPE_RECEIVE + 16: // receive ipv6 - networkEvent.Type = EtEtwNetworkReceiveType; - networkEvent.ProtocolType = PH_IPV6_NETWORK_TYPE; - break; - } - - if (memcmp(&EventRecord->EventHeader.ProviderId, &TcpIpGuid_I, sizeof(GUID)) == 0) - networkEvent.ProtocolType |= PH_TCP_PROTOCOL_TYPE; - else - networkEvent.ProtocolType |= PH_UDP_PROTOCOL_TYPE; - - if (networkEvent.Type != -1) - { - PH_IP_ENDPOINT source; - PH_IP_ENDPOINT destination; - - if (networkEvent.ProtocolType & PH_IPV4_NETWORK_TYPE) - { - TcpIpOrUdpIp_IPV4_Header *data = EventRecord->UserData; - - networkEvent.ClientId.UniqueProcess = UlongToHandle(data->PID); - networkEvent.TransferSize = data->size; - - source.Address.Type = PH_IPV4_NETWORK_TYPE; - source.Address.Ipv4 = data->saddr; - source.Port = _byteswap_ushort(data->sport); - destination.Address.Type = PH_IPV4_NETWORK_TYPE; - destination.Address.Ipv4 = data->daddr; - destination.Port = _byteswap_ushort(data->dport); - } - else if (networkEvent.ProtocolType & PH_IPV6_NETWORK_TYPE) - { - TcpIpOrUdpIp_IPV6_Header *data = EventRecord->UserData; - - networkEvent.ClientId.UniqueProcess = UlongToHandle(data->PID); - networkEvent.TransferSize = data->size; - - source.Address.Type = PH_IPV6_NETWORK_TYPE; - source.Address.In6Addr = data->saddr; - source.Port = _byteswap_ushort(data->sport); - destination.Address.Type = PH_IPV6_NETWORK_TYPE; - destination.Address.In6Addr = data->daddr; - destination.Port = _byteswap_ushort(data->dport); - } - - networkEvent.LocalEndpoint = source; - - if (networkEvent.ProtocolType & PH_TCP_PROTOCOL_TYPE) - networkEvent.RemoteEndpoint = destination; - - EtProcessNetworkEvent(&networkEvent); - } - } -} - -NTSTATUS EtpEtwMonitorThreadStart( - _In_ PVOID Parameter - ) -{ - ULONG result; - EVENT_TRACE_LOGFILE logFile; - TRACEHANDLE traceHandle; - - // See comment in EtEtwProcessesUpdatedCallback. - if (WindowsVersion >= WINDOWS_8) - EtUpdateProcessInformation(); - - memset(&logFile, 0, sizeof(EVENT_TRACE_LOGFILE)); - logFile.LoggerName = EtpActualKernelLoggerName->Buffer; - logFile.ProcessTraceMode = PROCESS_TRACE_MODE_REAL_TIME | PROCESS_TRACE_MODE_EVENT_RECORD; - logFile.BufferCallback = EtpEtwBufferCallback; - logFile.EventRecordCallback = EtpEtwEventCallback; - - while (TRUE) - { - result = ERROR_SUCCESS; - traceHandle = OpenTrace(&logFile); - - if (traceHandle != INVALID_PROCESSTRACE_HANDLE) - { - while (!EtpEtwExiting && (result = ProcessTrace(&traceHandle, 1, NULL, NULL)) == ERROR_SUCCESS) - NOTHING; - - CloseTrace(traceHandle); - } - - if (EtpEtwExiting) - break; - - if (result == ERROR_WMI_INSTANCE_NOT_FOUND) - { - // The session was stopped by another program. Try to start it again. - EtStartEtwSession(); - } - - // Some error occurred, so sleep for a while before trying again. - // Don't sleep if we just successfully started a session, though. - if (!EtpEtwActive) - Sleep(250); - } - - return STATUS_SUCCESS; -} - -ULONG EtStartEtwRundown( - VOID - ) -{ - ULONG result; - ULONG bufferSize; - - bufferSize = sizeof(EVENT_TRACE_PROPERTIES) + EtpRundownLoggerName.Length + sizeof(WCHAR); - - if (!EtpRundownTraceProperties) - EtpRundownTraceProperties = PhAllocate(bufferSize); - - memset(EtpRundownTraceProperties, 0, sizeof(EVENT_TRACE_PROPERTIES)); - - EtpRundownTraceProperties->Wnode.BufferSize = bufferSize; - EtpRundownTraceProperties->Wnode.ClientContext = 1; - EtpRundownTraceProperties->Wnode.Flags = WNODE_FLAG_TRACED_GUID; - EtpRundownTraceProperties->MinimumBuffers = 1; - EtpRundownTraceProperties->LogFileMode = EVENT_TRACE_REAL_TIME_MODE; - EtpRundownTraceProperties->FlushTimer = 1; - EtpRundownTraceProperties->LogFileNameOffset = 0; - EtpRundownTraceProperties->LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES); - - result = StartTrace(&EtpRundownSessionHandle, EtpRundownLoggerName.Buffer, EtpRundownTraceProperties); - - if (result == ERROR_ALREADY_EXISTS) - { - EtpStopEtwRundownSession(); - // ControlTrace (called from EtpStopEtwRundownSession) screws up the structure. - EtpRundownTraceProperties->Wnode.BufferSize = bufferSize; - EtpRundownTraceProperties->LogFileNameOffset = 0; - EtpRundownTraceProperties->LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES); - result = StartTrace(&EtpRundownSessionHandle, EtpRundownLoggerName.Buffer, EtpRundownTraceProperties); - } - - if (result != ERROR_SUCCESS) - return result; - - result = EnableTraceEx(&KernelRundownGuid_I, NULL, EtpRundownSessionHandle, 1, 0, 0x10, 0, 0, NULL); - - if (result != ERROR_SUCCESS) - { - EtpStopEtwRundownSession(); - return result; - } - - EtpRundownActive = TRUE; - EtpRundownEtwMonitorThreadHandle = PhCreateThread(0, EtpRundownEtwMonitorThreadStart, NULL); - - return result; -} - -ULONG EtpStopEtwRundownSession( - VOID - ) -{ - EtpRundownTraceProperties->LogFileNameOffset = 0; - return ControlTrace(0, EtpRundownLoggerName.Buffer, EtpRundownTraceProperties, EVENT_TRACE_CONTROL_STOP); -} - -ULONG NTAPI EtpRundownEtwBufferCallback( - _In_ PEVENT_TRACE_LOGFILE Buffer - ) -{ - return !EtpEtwExiting; -} - -VOID NTAPI EtpRundownEtwEventCallback( - _In_ PEVENT_RECORD EventRecord - ) -{ - // TODO: Find a way to call CloseTrace when the enumeration finishes so we can - // stop the trace cleanly. - - if (memcmp(&EventRecord->EventHeader.ProviderId, &FileIoGuid_I, sizeof(GUID)) == 0) - { - // FileIo - - ET_ETW_FILE_EVENT fileEvent; - - memset(&fileEvent, 0, sizeof(ET_ETW_FILE_EVENT)); - fileEvent.Type = -1; - - switch (EventRecord->EventHeader.EventDescriptor.Opcode) - { - case 36: // FileRundown - fileEvent.Type = EtEtwFileRundownType; - break; - default: - break; - } - - if (fileEvent.Type != -1) - { - FileIo_Name *data = EventRecord->UserData; - - fileEvent.FileObject = (PVOID)data->FileObject; - PhInitializeStringRef(&fileEvent.FileName, data->FileName); - - EtDiskProcessFileEvent(&fileEvent); - } - } -} - -NTSTATUS EtpRundownEtwMonitorThreadStart( - _In_ PVOID Parameter - ) -{ - EVENT_TRACE_LOGFILE logFile; - TRACEHANDLE traceHandle; - - memset(&logFile, 0, sizeof(EVENT_TRACE_LOGFILE)); - logFile.LoggerName = EtpRundownLoggerName.Buffer; - logFile.ProcessTraceMode = PROCESS_TRACE_MODE_REAL_TIME | PROCESS_TRACE_MODE_EVENT_RECORD; - logFile.BufferCallback = EtpRundownEtwBufferCallback; - logFile.EventRecordCallback = EtpRundownEtwEventCallback; - logFile.Context = &traceHandle; - - traceHandle = OpenTrace(&logFile); - - if (traceHandle != INVALID_PROCESSTRACE_HANDLE) - { - ProcessTrace(&traceHandle, 1, NULL, NULL); - - if (traceHandle != 0) - CloseTrace(traceHandle); - } - - NtClose(EtpRundownEtwMonitorThreadHandle); - EtpRundownEtwMonitorThreadHandle = NULL; - - return STATUS_SUCCESS; -} +/* + * Process Hacker Extended Tools - + * ETW monitoring + * + * Copyright (C) 2010-2015 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include "exttools.h" +#include "etwmon.h" + +ULONG NTAPI EtpEtwBufferCallback( + _In_ PEVENT_TRACE_LOGFILE Buffer + ); + +VOID NTAPI EtpEtwEventCallback( + _In_ PEVENT_RECORD EventRecord + ); + +NTSTATUS EtpEtwMonitorThreadStart( + _In_ PVOID Parameter + ); + +ULONG EtpStopEtwRundownSession( + VOID + ); + +ULONG NTAPI EtpRundownEtwBufferCallback( + _In_ PEVENT_TRACE_LOGFILE Buffer + ); + +VOID NTAPI EtpRundownEtwEventCallback( + _In_ PEVENT_RECORD EventRecord + ); + +NTSTATUS EtpRundownEtwMonitorThreadStart( + _In_ PVOID Parameter + ); + +static GUID ProcessHackerGuid = { 0x1288c53b, 0xaf35, 0x481b, { 0xb6, 0xb5, 0xa0, 0x5c, 0x39, 0x87, 0x2e, 0xd } }; +static GUID SystemTraceControlGuid_I = { 0x9e814aad, 0x3204, 0x11d2, { 0x9a, 0x82, 0x00, 0x60, 0x08, 0xa8, 0x69, 0x39 } }; +static GUID KernelRundownGuid_I = { 0x3b9c9951, 0x3480, 0x4220, { 0x93, 0x77, 0x9c, 0x8e, 0x51, 0x84, 0xf5, 0xcd } }; +static GUID DiskIoGuid_I = { 0x3d6fa8d4, 0xfe05, 0x11d0, { 0x9d, 0xda, 0x00, 0xc0, 0x4f, 0xd7, 0xba, 0x7c } }; +static GUID FileIoGuid_I = { 0x90cbdc39, 0x4a3e, 0x11d1, { 0x84, 0xf4, 0x00, 0x00, 0xf8, 0x04, 0x64, 0xe3 } }; +static GUID TcpIpGuid_I = { 0x9a280ac0, 0xc8e0, 0x11d1, { 0x84, 0xe2, 0x00, 0xc0, 0x4f, 0xb9, 0x98, 0xa2 } }; +static GUID UdpIpGuid_I = { 0xbf3a50c5, 0xa9c9, 0x4988, { 0xa0, 0x05, 0x2d, 0xf0, 0xb7, 0xc8, 0x0f, 0x80 } }; + +// ETW tracing layer + +BOOLEAN EtEtwEnabled; +static UNICODE_STRING EtpSharedKernelLoggerName = RTL_CONSTANT_STRING(KERNEL_LOGGER_NAME); +static UNICODE_STRING EtpPrivateKernelLoggerName = RTL_CONSTANT_STRING(L"PhEtKernelLogger"); +static TRACEHANDLE EtpSessionHandle; +static PUNICODE_STRING EtpActualKernelLoggerName; +static PGUID EtpActualSessionGuid; +static PEVENT_TRACE_PROPERTIES EtpTraceProperties; +static BOOLEAN EtpEtwActive; +static BOOLEAN EtpStartedSession; +static BOOLEAN EtpEtwExiting; +static HANDLE EtpEtwMonitorThreadHandle; + +// ETW rundown layer + +static UNICODE_STRING EtpRundownLoggerName = RTL_CONSTANT_STRING(L"PhEtRundownLogger"); +static TRACEHANDLE EtpRundownSessionHandle; +static PEVENT_TRACE_PROPERTIES EtpRundownTraceProperties; +static BOOLEAN EtpRundownActive; +static HANDLE EtpRundownEtwMonitorThreadHandle; + +VOID EtEtwMonitorInitialization( + VOID + ) +{ + if (PhGetOwnTokenAttributes().Elevated && PhGetIntegerSetting(SETTING_NAME_ENABLE_ETW_MONITOR)) + { + EtStartEtwSession(); + + if (EtEtwEnabled) + EtpEtwMonitorThreadHandle = PhCreateThread(0, EtpEtwMonitorThreadStart, NULL); + } +} + +VOID EtEtwMonitorUninitialization( + VOID + ) +{ + if (EtEtwEnabled) + { + EtpEtwExiting = TRUE; + EtStopEtwSession(); + } + + if (EtpRundownActive) + { + EtpStopEtwRundownSession(); + } +} + +VOID EtStartEtwSession( + VOID + ) +{ + ULONG result; + ULONG bufferSize; + + if (WindowsVersion >= WINDOWS_8) + { + EtpActualKernelLoggerName = &EtpPrivateKernelLoggerName; + EtpActualSessionGuid = &ProcessHackerGuid; + } + else + { + EtpActualKernelLoggerName = &EtpSharedKernelLoggerName; + EtpActualSessionGuid = &SystemTraceControlGuid_I; + } + + bufferSize = sizeof(EVENT_TRACE_PROPERTIES) + EtpActualKernelLoggerName->Length + sizeof(WCHAR); + + if (!EtpTraceProperties) + EtpTraceProperties = PhAllocate(bufferSize); + + memset(EtpTraceProperties, 0, sizeof(EVENT_TRACE_PROPERTIES)); + + EtpTraceProperties->Wnode.BufferSize = bufferSize; + EtpTraceProperties->Wnode.Guid = *EtpActualSessionGuid; + EtpTraceProperties->Wnode.ClientContext = 1; + EtpTraceProperties->Wnode.Flags = WNODE_FLAG_TRACED_GUID; + EtpTraceProperties->MinimumBuffers = 1; + EtpTraceProperties->LogFileMode = EVENT_TRACE_REAL_TIME_MODE; + EtpTraceProperties->FlushTimer = 1; + EtpTraceProperties->EnableFlags = EVENT_TRACE_FLAG_DISK_IO | EVENT_TRACE_FLAG_DISK_FILE_IO | EVENT_TRACE_FLAG_NETWORK_TCPIP; + EtpTraceProperties->LogFileNameOffset = 0; + EtpTraceProperties->LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES); + + if (WindowsVersion >= WINDOWS_8) + EtpTraceProperties->LogFileMode |= EVENT_TRACE_SYSTEM_LOGGER_MODE; + + result = StartTrace(&EtpSessionHandle, EtpActualKernelLoggerName->Buffer, EtpTraceProperties); + + if (result == ERROR_SUCCESS) + { + EtEtwEnabled = TRUE; + EtpEtwActive = TRUE; + EtpStartedSession = TRUE; + } + else if (result == ERROR_ALREADY_EXISTS) + { + EtEtwEnabled = TRUE; + EtpEtwActive = TRUE; + EtpStartedSession = FALSE; + // The session already exists. + //result = ControlTrace(0, EtpActualKernelLoggerName->Buffer, EtpTraceProperties, EVENT_TRACE_CONTROL_UPDATE); + } + else + { + EtpEtwActive = FALSE; + EtpStartedSession = FALSE; + } +} + +ULONG EtpControlEtwSession( + _In_ ULONG ControlCode + ) +{ + // If we have a session handle, we use that instead of the logger name. + + EtpTraceProperties->LogFileNameOffset = 0; // make sure it is 0, otherwise ControlTrace crashes + + return ControlTrace( + EtpStartedSession ? EtpSessionHandle : 0, + EtpStartedSession ? NULL : EtpActualKernelLoggerName->Buffer, + EtpTraceProperties, + ControlCode + ); +} + +VOID EtStopEtwSession( + VOID + ) +{ + if (EtEtwEnabled) + EtpControlEtwSession(EVENT_TRACE_CONTROL_STOP); +} + +VOID EtFlushEtwSession( + VOID + ) +{ + if (EtEtwEnabled) + EtpControlEtwSession(EVENT_TRACE_CONTROL_FLUSH); +} + +ULONG NTAPI EtpEtwBufferCallback( + _In_ PEVENT_TRACE_LOGFILE Buffer + ) +{ + return !EtpEtwExiting; +} + +VOID NTAPI EtpEtwEventCallback( + _In_ PEVENT_RECORD EventRecord + ) +{ + if (memcmp(&EventRecord->EventHeader.ProviderId, &DiskIoGuid_I, sizeof(GUID)) == 0) + { + // DiskIo + + ET_ETW_DISK_EVENT diskEvent; + + memset(&diskEvent, 0, sizeof(ET_ETW_DISK_EVENT)); + diskEvent.Type = -1; + + switch (EventRecord->EventHeader.EventDescriptor.Opcode) + { + case EVENT_TRACE_TYPE_IO_READ: + diskEvent.Type = EtEtwDiskReadType; + break; + case EVENT_TRACE_TYPE_IO_WRITE: + diskEvent.Type = EtEtwDiskWriteType; + break; + default: + break; + } + + if (diskEvent.Type != -1) + { + DiskIo_TypeGroup1 *data = EventRecord->UserData; + + if (WindowsVersion >= WINDOWS_8) + { + diskEvent.ClientId.UniqueThread = UlongToHandle(data->IssuingThreadId); + diskEvent.ClientId.UniqueProcess = EtThreadIdToProcessId(diskEvent.ClientId.UniqueThread); + } + else + { + if (EventRecord->EventHeader.ProcessId != -1) + { + diskEvent.ClientId.UniqueProcess = UlongToHandle(EventRecord->EventHeader.ProcessId); + diskEvent.ClientId.UniqueThread = UlongToHandle(EventRecord->EventHeader.ThreadId); + } + } + + diskEvent.IrpFlags = data->IrpFlags; + diskEvent.TransferSize = data->TransferSize; + diskEvent.FileObject = (PVOID)data->FileObject; + diskEvent.HighResResponseTime = data->HighResResponseTime; + + EtProcessDiskEvent(&diskEvent); + EtDiskProcessDiskEvent(&diskEvent); + } + } + else if (memcmp(&EventRecord->EventHeader.ProviderId, &FileIoGuid_I, sizeof(GUID)) == 0) + { + // FileIo + + ET_ETW_FILE_EVENT fileEvent; + + memset(&fileEvent, 0, sizeof(ET_ETW_FILE_EVENT)); + fileEvent.Type = -1; + + switch (EventRecord->EventHeader.EventDescriptor.Opcode) + { + case 0: // Name + fileEvent.Type = EtEtwFileNameType; + break; + case 32: // FileCreate + fileEvent.Type = EtEtwFileCreateType; + break; + case 35: // FileDelete + fileEvent.Type = EtEtwFileDeleteType; + break; + default: + break; + } + + if (fileEvent.Type != -1) + { + FileIo_Name *data = EventRecord->UserData; + + fileEvent.FileObject = (PVOID)data->FileObject; + PhInitializeStringRef(&fileEvent.FileName, data->FileName); + + EtDiskProcessFileEvent(&fileEvent); + } + } + else if ( + memcmp(&EventRecord->EventHeader.ProviderId, &TcpIpGuid_I, sizeof(GUID)) == 0 || + memcmp(&EventRecord->EventHeader.ProviderId, &UdpIpGuid_I, sizeof(GUID)) == 0 + ) + { + // TcpIp/UdpIp + + ET_ETW_NETWORK_EVENT networkEvent; + + memset(&networkEvent, 0, sizeof(ET_ETW_NETWORK_EVENT)); + networkEvent.Type = -1; + + switch (EventRecord->EventHeader.EventDescriptor.Opcode) + { + case EVENT_TRACE_TYPE_SEND: // send + networkEvent.Type = EtEtwNetworkSendType; + networkEvent.ProtocolType = PH_IPV4_NETWORK_TYPE; + break; + case EVENT_TRACE_TYPE_RECEIVE: // receive + networkEvent.Type = EtEtwNetworkReceiveType; + networkEvent.ProtocolType = PH_IPV4_NETWORK_TYPE; + break; + case EVENT_TRACE_TYPE_SEND + 16: // send ipv6 + networkEvent.Type = EtEtwNetworkSendType; + networkEvent.ProtocolType = PH_IPV6_NETWORK_TYPE; + break; + case EVENT_TRACE_TYPE_RECEIVE + 16: // receive ipv6 + networkEvent.Type = EtEtwNetworkReceiveType; + networkEvent.ProtocolType = PH_IPV6_NETWORK_TYPE; + break; + } + + if (memcmp(&EventRecord->EventHeader.ProviderId, &TcpIpGuid_I, sizeof(GUID)) == 0) + networkEvent.ProtocolType |= PH_TCP_PROTOCOL_TYPE; + else + networkEvent.ProtocolType |= PH_UDP_PROTOCOL_TYPE; + + if (networkEvent.Type != -1) + { + PH_IP_ENDPOINT source; + PH_IP_ENDPOINT destination; + + if (networkEvent.ProtocolType & PH_IPV4_NETWORK_TYPE) + { + TcpIpOrUdpIp_IPV4_Header *data = EventRecord->UserData; + + networkEvent.ClientId.UniqueProcess = UlongToHandle(data->PID); + networkEvent.TransferSize = data->size; + + source.Address.Type = PH_IPV4_NETWORK_TYPE; + source.Address.Ipv4 = data->saddr; + source.Port = _byteswap_ushort(data->sport); + destination.Address.Type = PH_IPV4_NETWORK_TYPE; + destination.Address.Ipv4 = data->daddr; + destination.Port = _byteswap_ushort(data->dport); + } + else if (networkEvent.ProtocolType & PH_IPV6_NETWORK_TYPE) + { + TcpIpOrUdpIp_IPV6_Header *data = EventRecord->UserData; + + networkEvent.ClientId.UniqueProcess = UlongToHandle(data->PID); + networkEvent.TransferSize = data->size; + + source.Address.Type = PH_IPV6_NETWORK_TYPE; + source.Address.In6Addr = data->saddr; + source.Port = _byteswap_ushort(data->sport); + destination.Address.Type = PH_IPV6_NETWORK_TYPE; + destination.Address.In6Addr = data->daddr; + destination.Port = _byteswap_ushort(data->dport); + } + + networkEvent.LocalEndpoint = source; + + if (networkEvent.ProtocolType & PH_TCP_PROTOCOL_TYPE) + networkEvent.RemoteEndpoint = destination; + + EtProcessNetworkEvent(&networkEvent); + } + } +} + +NTSTATUS EtpEtwMonitorThreadStart( + _In_ PVOID Parameter + ) +{ + ULONG result; + EVENT_TRACE_LOGFILE logFile; + TRACEHANDLE traceHandle; + + // See comment in EtEtwProcessesUpdatedCallback. + if (WindowsVersion >= WINDOWS_8) + EtUpdateProcessInformation(); + + memset(&logFile, 0, sizeof(EVENT_TRACE_LOGFILE)); + logFile.LoggerName = EtpActualKernelLoggerName->Buffer; + logFile.ProcessTraceMode = PROCESS_TRACE_MODE_REAL_TIME | PROCESS_TRACE_MODE_EVENT_RECORD; + logFile.BufferCallback = EtpEtwBufferCallback; + logFile.EventRecordCallback = EtpEtwEventCallback; + + while (TRUE) + { + result = ERROR_SUCCESS; + traceHandle = OpenTrace(&logFile); + + if (traceHandle != INVALID_PROCESSTRACE_HANDLE) + { + while (!EtpEtwExiting && (result = ProcessTrace(&traceHandle, 1, NULL, NULL)) == ERROR_SUCCESS) + NOTHING; + + CloseTrace(traceHandle); + } + + if (EtpEtwExiting) + break; + + if (result == ERROR_WMI_INSTANCE_NOT_FOUND) + { + // The session was stopped by another program. Try to start it again. + EtStartEtwSession(); + } + + // Some error occurred, so sleep for a while before trying again. + // Don't sleep if we just successfully started a session, though. + if (!EtpEtwActive) + Sleep(250); + } + + return STATUS_SUCCESS; +} + +ULONG EtStartEtwRundown( + VOID + ) +{ + ULONG result; + ULONG bufferSize; + + bufferSize = sizeof(EVENT_TRACE_PROPERTIES) + EtpRundownLoggerName.Length + sizeof(WCHAR); + + if (!EtpRundownTraceProperties) + EtpRundownTraceProperties = PhAllocate(bufferSize); + + memset(EtpRundownTraceProperties, 0, sizeof(EVENT_TRACE_PROPERTIES)); + + EtpRundownTraceProperties->Wnode.BufferSize = bufferSize; + EtpRundownTraceProperties->Wnode.ClientContext = 1; + EtpRundownTraceProperties->Wnode.Flags = WNODE_FLAG_TRACED_GUID; + EtpRundownTraceProperties->MinimumBuffers = 1; + EtpRundownTraceProperties->LogFileMode = EVENT_TRACE_REAL_TIME_MODE; + EtpRundownTraceProperties->FlushTimer = 1; + EtpRundownTraceProperties->LogFileNameOffset = 0; + EtpRundownTraceProperties->LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES); + + result = StartTrace(&EtpRundownSessionHandle, EtpRundownLoggerName.Buffer, EtpRundownTraceProperties); + + if (result == ERROR_ALREADY_EXISTS) + { + EtpStopEtwRundownSession(); + // ControlTrace (called from EtpStopEtwRundownSession) screws up the structure. + EtpRundownTraceProperties->Wnode.BufferSize = bufferSize; + EtpRundownTraceProperties->LogFileNameOffset = 0; + EtpRundownTraceProperties->LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES); + result = StartTrace(&EtpRundownSessionHandle, EtpRundownLoggerName.Buffer, EtpRundownTraceProperties); + } + + if (result != ERROR_SUCCESS) + return result; + + result = EnableTraceEx(&KernelRundownGuid_I, NULL, EtpRundownSessionHandle, 1, 0, 0x10, 0, 0, NULL); + + if (result != ERROR_SUCCESS) + { + EtpStopEtwRundownSession(); + return result; + } + + EtpRundownActive = TRUE; + EtpRundownEtwMonitorThreadHandle = PhCreateThread(0, EtpRundownEtwMonitorThreadStart, NULL); + + return result; +} + +ULONG EtpStopEtwRundownSession( + VOID + ) +{ + EtpRundownTraceProperties->LogFileNameOffset = 0; + return ControlTrace(0, EtpRundownLoggerName.Buffer, EtpRundownTraceProperties, EVENT_TRACE_CONTROL_STOP); +} + +ULONG NTAPI EtpRundownEtwBufferCallback( + _In_ PEVENT_TRACE_LOGFILE Buffer + ) +{ + return !EtpEtwExiting; +} + +VOID NTAPI EtpRundownEtwEventCallback( + _In_ PEVENT_RECORD EventRecord + ) +{ + // TODO: Find a way to call CloseTrace when the enumeration finishes so we can + // stop the trace cleanly. + + if (memcmp(&EventRecord->EventHeader.ProviderId, &FileIoGuid_I, sizeof(GUID)) == 0) + { + // FileIo + + ET_ETW_FILE_EVENT fileEvent; + + memset(&fileEvent, 0, sizeof(ET_ETW_FILE_EVENT)); + fileEvent.Type = -1; + + switch (EventRecord->EventHeader.EventDescriptor.Opcode) + { + case 36: // FileRundown + fileEvent.Type = EtEtwFileRundownType; + break; + default: + break; + } + + if (fileEvent.Type != -1) + { + FileIo_Name *data = EventRecord->UserData; + + fileEvent.FileObject = (PVOID)data->FileObject; + PhInitializeStringRef(&fileEvent.FileName, data->FileName); + + EtDiskProcessFileEvent(&fileEvent); + } + } +} + +NTSTATUS EtpRundownEtwMonitorThreadStart( + _In_ PVOID Parameter + ) +{ + EVENT_TRACE_LOGFILE logFile; + TRACEHANDLE traceHandle; + + memset(&logFile, 0, sizeof(EVENT_TRACE_LOGFILE)); + logFile.LoggerName = EtpRundownLoggerName.Buffer; + logFile.ProcessTraceMode = PROCESS_TRACE_MODE_REAL_TIME | PROCESS_TRACE_MODE_EVENT_RECORD; + logFile.BufferCallback = EtpRundownEtwBufferCallback; + logFile.EventRecordCallback = EtpRundownEtwEventCallback; + logFile.Context = &traceHandle; + + traceHandle = OpenTrace(&logFile); + + if (traceHandle != INVALID_PROCESSTRACE_HANDLE) + { + ProcessTrace(&traceHandle, 1, NULL, NULL); + + if (traceHandle != 0) + CloseTrace(traceHandle); + } + + NtClose(EtpRundownEtwMonitorThreadHandle); + EtpRundownEtwMonitorThreadHandle = NULL; + + return STATUS_SUCCESS; +} diff --git a/plugins/ExtendedTools/etwmon.h b/plugins/ExtendedTools/etwmon.h index cb9bca0aee9d..85f3e399bb98 100644 --- a/plugins/ExtendedTools/etwmon.h +++ b/plugins/ExtendedTools/etwmon.h @@ -1,140 +1,140 @@ -#ifndef ETWMON_H -#define ETWMON_H - -#include - -typedef struct -{ - ULONG DiskNumber; - ULONG IrpFlags; - ULONG TransferSize; - ULONG ResponseTime; - ULONG64 ByteOffset; - ULONG_PTR FileObject; - ULONG_PTR Irp; - ULONG64 HighResResponseTime; - ULONG IssuingThreadId; // since WIN8 (ETW_DISKIO_READWRITE_V3) -} DiskIo_TypeGroup1; - -typedef struct -{ - ULONG_PTR FileObject; - WCHAR FileName[1]; -} FileIo_Name; - -typedef struct -{ - ULONG PID; - ULONG size; - ULONG daddr; - ULONG saddr; - USHORT dport; - USHORT sport; -} TcpIpOrUdpIp_IPV4_Header; - -typedef struct -{ - ULONG PID; - ULONG size; - IN6_ADDR daddr; - IN6_ADDR saddr; - USHORT dport; - USHORT sport; -} TcpIpOrUdpIp_IPV6_Header; - -// etwmon - -VOID EtEtwMonitorInitialization( - VOID - ); - -VOID EtEtwMonitorUninitialization( - VOID - ); - -VOID EtStartEtwSession( - VOID - ); - -VOID EtStopEtwSession( - VOID - ); - -VOID EtFlushEtwSession( - VOID - ); - -ULONG EtStartEtwRundown( - VOID - ); - -// etwstat - -typedef enum _ET_ETW_EVENT_TYPE -{ - EtEtwDiskReadType = 1, - EtEtwDiskWriteType, - EtEtwFileNameType, - EtEtwFileCreateType, - EtEtwFileDeleteType, - EtEtwFileRundownType, - EtEtwNetworkReceiveType, - EtEtwNetworkSendType -} ET_ETW_EVENT_TYPE; - -typedef struct _ET_ETW_DISK_EVENT -{ - ET_ETW_EVENT_TYPE Type; - CLIENT_ID ClientId; - ULONG IrpFlags; - ULONG TransferSize; - PVOID FileObject; - ULONG64 HighResResponseTime; -} ET_ETW_DISK_EVENT, *PET_ETW_DISK_EVENT; - -typedef struct _ET_ETW_FILE_EVENT -{ - ET_ETW_EVENT_TYPE Type; - PVOID FileObject; - PH_STRINGREF FileName; -} ET_ETW_FILE_EVENT, *PET_ETW_FILE_EVENT; - -typedef struct _ET_ETW_NETWORK_EVENT -{ - ET_ETW_EVENT_TYPE Type; - CLIENT_ID ClientId; - ULONG ProtocolType; - ULONG TransferSize; - PH_IP_ENDPOINT LocalEndpoint; - PH_IP_ENDPOINT RemoteEndpoint; -} ET_ETW_NETWORK_EVENT, *PET_ETW_NETWORK_EVENT; - -// etwstat - -VOID EtProcessDiskEvent( - _In_ PET_ETW_DISK_EVENT Event - ); - -VOID EtProcessNetworkEvent( - _In_ PET_ETW_NETWORK_EVENT Event - ); - -VOID EtUpdateProcessInformation( - VOID - ); - -HANDLE EtThreadIdToProcessId( - _In_ HANDLE ThreadId - ); - -// etwdisk - -VOID EtDiskProcessDiskEvent( - _In_ PET_ETW_DISK_EVENT Event - ); - -VOID EtDiskProcessFileEvent( - _In_ PET_ETW_FILE_EVENT Event - ); - -#endif +#ifndef ETWMON_H +#define ETWMON_H + +#include + +typedef struct +{ + ULONG DiskNumber; + ULONG IrpFlags; + ULONG TransferSize; + ULONG ResponseTime; + ULONG64 ByteOffset; + ULONG_PTR FileObject; + ULONG_PTR Irp; + ULONG64 HighResResponseTime; + ULONG IssuingThreadId; // since WIN8 (ETW_DISKIO_READWRITE_V3) +} DiskIo_TypeGroup1; + +typedef struct +{ + ULONG_PTR FileObject; + WCHAR FileName[1]; +} FileIo_Name; + +typedef struct +{ + ULONG PID; + ULONG size; + ULONG daddr; + ULONG saddr; + USHORT dport; + USHORT sport; +} TcpIpOrUdpIp_IPV4_Header; + +typedef struct +{ + ULONG PID; + ULONG size; + IN6_ADDR daddr; + IN6_ADDR saddr; + USHORT dport; + USHORT sport; +} TcpIpOrUdpIp_IPV6_Header; + +// etwmon + +VOID EtEtwMonitorInitialization( + VOID + ); + +VOID EtEtwMonitorUninitialization( + VOID + ); + +VOID EtStartEtwSession( + VOID + ); + +VOID EtStopEtwSession( + VOID + ); + +VOID EtFlushEtwSession( + VOID + ); + +ULONG EtStartEtwRundown( + VOID + ); + +// etwstat + +typedef enum _ET_ETW_EVENT_TYPE +{ + EtEtwDiskReadType = 1, + EtEtwDiskWriteType, + EtEtwFileNameType, + EtEtwFileCreateType, + EtEtwFileDeleteType, + EtEtwFileRundownType, + EtEtwNetworkReceiveType, + EtEtwNetworkSendType +} ET_ETW_EVENT_TYPE; + +typedef struct _ET_ETW_DISK_EVENT +{ + ET_ETW_EVENT_TYPE Type; + CLIENT_ID ClientId; + ULONG IrpFlags; + ULONG TransferSize; + PVOID FileObject; + ULONG64 HighResResponseTime; +} ET_ETW_DISK_EVENT, *PET_ETW_DISK_EVENT; + +typedef struct _ET_ETW_FILE_EVENT +{ + ET_ETW_EVENT_TYPE Type; + PVOID FileObject; + PH_STRINGREF FileName; +} ET_ETW_FILE_EVENT, *PET_ETW_FILE_EVENT; + +typedef struct _ET_ETW_NETWORK_EVENT +{ + ET_ETW_EVENT_TYPE Type; + CLIENT_ID ClientId; + ULONG ProtocolType; + ULONG TransferSize; + PH_IP_ENDPOINT LocalEndpoint; + PH_IP_ENDPOINT RemoteEndpoint; +} ET_ETW_NETWORK_EVENT, *PET_ETW_NETWORK_EVENT; + +// etwstat + +VOID EtProcessDiskEvent( + _In_ PET_ETW_DISK_EVENT Event + ); + +VOID EtProcessNetworkEvent( + _In_ PET_ETW_NETWORK_EVENT Event + ); + +VOID EtUpdateProcessInformation( + VOID + ); + +HANDLE EtThreadIdToProcessId( + _In_ HANDLE ThreadId + ); + +// etwdisk + +VOID EtDiskProcessDiskEvent( + _In_ PET_ETW_DISK_EVENT Event + ); + +VOID EtDiskProcessFileEvent( + _In_ PET_ETW_FILE_EVENT Event + ); + +#endif diff --git a/plugins/ExtendedTools/etwprprp.c b/plugins/ExtendedTools/etwprprp.c index 5d2ca9a1843b..1e87ffbd4672 100644 --- a/plugins/ExtendedTools/etwprprp.c +++ b/plugins/ExtendedTools/etwprprp.c @@ -1,615 +1,615 @@ -/* - * Process Hacker Extended Tools - - * ETW process properties page - * - * Copyright (C) 2010-2011 wj32 - * Copyright (C) 2015 dmex - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include "exttools.h" - -static RECT NormalGraphTextMargin = { 5, 5, 5, 5 }; -static RECT NormalGraphTextPadding = { 3, 3, 3, 3 }; - -typedef struct _ET_DISKNET_CONTEXT -{ - HWND WindowHandle; - PET_PROCESS_BLOCK Block; - PH_CALLBACK_REGISTRATION ProcessesUpdatedRegistration; - BOOLEAN Enabled; - - PH_LAYOUT_MANAGER LayoutManager; - - HWND DiskGroupBox; - HWND NetworkGroupBox; - - HWND DiskGraphHandle; - HWND NetworkGraphHandle; - HWND PanelHandle; - - ULONG64 CurrentDiskRead; - ULONG64 CurrentDiskWrite; - ULONG64 CurrentNetworkSend; - ULONG64 CurrentNetworkReceive; - - PH_GRAPH_STATE DiskGraphState; - PH_GRAPH_STATE NetworkGraphState; - - PH_CIRCULAR_BUFFER_ULONG64 DiskReadHistory; - PH_CIRCULAR_BUFFER_ULONG64 DiskWriteHistory; - PH_CIRCULAR_BUFFER_ULONG64 NetworkSendHistory; - PH_CIRCULAR_BUFFER_ULONG64 NetworkReceiveHistory; -} ET_DISKNET_CONTEXT, *PET_DISKNET_CONTEXT; - -INT_PTR CALLBACK EtwDiskNetworkPanelDialogProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - return FALSE; -} - -VOID EtwDiskNetworkCreateGraphs( - _In_ PET_DISKNET_CONTEXT Context - ) -{ - Context->DiskGraphHandle = CreateWindow( - PH_GRAPH_CLASSNAME, - NULL, - WS_VISIBLE | WS_CHILD | WS_BORDER, - 0, - 0, - 3, - 3, - Context->WindowHandle, - NULL, - NULL, - NULL - ); - Graph_SetTooltip(Context->DiskGraphHandle, TRUE); - - Context->NetworkGraphHandle = CreateWindow( - PH_GRAPH_CLASSNAME, - NULL, - WS_VISIBLE | WS_CHILD | WS_BORDER, - 0, - 0, - 3, - 3, - Context->WindowHandle, - NULL, - NULL, - NULL - ); - Graph_SetTooltip(Context->NetworkGraphHandle, TRUE); -} - -VOID EtwDiskNetworkCreatePanel( - _In_ PET_DISKNET_CONTEXT Context - ) -{ - RECT margin; - - Context->PanelHandle = CreateDialogParam( - PluginInstance->DllBase, - MAKEINTRESOURCE(IDD_PROCDISKNET_PANEL), - Context->WindowHandle, - EtwDiskNetworkPanelDialogProc, - (LPARAM)Context - ); - - SetWindowPos( - Context->PanelHandle, - NULL, - 10, 0, 0, 0, - SWP_NOACTIVATE | SWP_NOREDRAW | SWP_NOSIZE | SWP_NOZORDER - ); - - ShowWindow(Context->PanelHandle, SW_SHOW); - - margin.left = 0; - margin.top = 0; - margin.right = 0; - margin.bottom = 10; - MapDialogRect(Context->WindowHandle, &margin); - - PhAddLayoutItemEx( - &Context->LayoutManager, - Context->PanelHandle, - NULL, - PH_ANCHOR_BOTTOM | PH_ANCHOR_LEFT, - margin - ); - - SendMessage(Context->WindowHandle, WM_SIZE, 0, 0); -} - -VOID EtwDiskNetworkLayoutGraphs( - _In_ PET_DISKNET_CONTEXT Context - ) -{ - HDWP deferHandle; - RECT clientRect; - RECT panelRect; - RECT margin = { ET_SCALE_DPI(13), ET_SCALE_DPI(13), ET_SCALE_DPI(13), ET_SCALE_DPI(13) }; - RECT innerMargin = { ET_SCALE_DPI(10), ET_SCALE_DPI(20), ET_SCALE_DPI(10), ET_SCALE_DPI(10) }; - LONG between = ET_SCALE_DPI(3); - ULONG graphWidth; - ULONG graphHeight; - - PhLayoutManagerLayout(&Context->LayoutManager); - - Context->DiskGraphState.Valid = FALSE; - Context->NetworkGraphState.Valid = FALSE; - - GetClientRect(Context->WindowHandle, &clientRect); - - // Limit the rectangle bottom to the top of the panel. - GetWindowRect(Context->PanelHandle, &panelRect); - MapWindowPoints(NULL, Context->WindowHandle, (PPOINT)&panelRect, 2); - clientRect.bottom = panelRect.top + 10; // +10 removing extra spacing - - graphWidth = clientRect.right - margin.left - margin.right; - graphHeight = (clientRect.bottom - margin.top - margin.bottom - between * 2) / 2; - - deferHandle = BeginDeferWindowPos(4); - - deferHandle = DeferWindowPos(deferHandle, Context->DiskGroupBox, NULL, margin.left, margin.top, graphWidth, graphHeight, SWP_NOACTIVATE | SWP_NOZORDER); - deferHandle = DeferWindowPos( - deferHandle, - Context->DiskGraphHandle, - NULL, - margin.left + innerMargin.left, - margin.top + innerMargin.top, - graphWidth - innerMargin.left - innerMargin.right, - graphHeight - innerMargin.top - innerMargin.bottom, - SWP_NOACTIVATE | SWP_NOZORDER - ); - - deferHandle = DeferWindowPos(deferHandle, Context->NetworkGroupBox, NULL, margin.left, margin.top + graphHeight + between, graphWidth, graphHeight, SWP_NOACTIVATE | SWP_NOZORDER); - deferHandle = DeferWindowPos( - deferHandle, - Context->NetworkGraphHandle, - NULL, - margin.left + innerMargin.left, - margin.top + graphHeight + between + innerMargin.top, - graphWidth - innerMargin.left - innerMargin.right, - graphHeight - innerMargin.top - innerMargin.bottom, - SWP_NOACTIVATE | SWP_NOZORDER - ); - - EndDeferWindowPos(deferHandle); -} - -VOID EtwDiskNetworkUpdateGraphs( - _In_ PET_DISKNET_CONTEXT Context - ) -{ - Context->DiskGraphState.Valid = FALSE; - Context->DiskGraphState.TooltipIndex = -1; - Graph_MoveGrid(Context->DiskGraphHandle, 1); - Graph_Draw(Context->DiskGraphHandle); - Graph_UpdateTooltip(Context->DiskGraphHandle); - InvalidateRect(Context->DiskGraphHandle, NULL, FALSE); - - Context->NetworkGraphState.Valid = FALSE; - Context->NetworkGraphState.TooltipIndex = -1; - Graph_MoveGrid(Context->NetworkGraphHandle, 1); - Graph_Draw(Context->NetworkGraphHandle); - Graph_UpdateTooltip(Context->NetworkGraphHandle); - InvalidateRect(Context->NetworkGraphHandle, NULL, FALSE); -} - -VOID EtwDiskNetworkUpdatePanel( - _Inout_ PET_DISKNET_CONTEXT Context - ) -{ - PET_PROCESS_BLOCK block = Context->Block; - - SetDlgItemText(Context->PanelHandle, IDC_ZREADS_V, PhaFormatUInt64(block->DiskReadCount, TRUE)->Buffer); - SetDlgItemText(Context->PanelHandle, IDC_ZREADBYTES_V, PhaFormatSize(block->DiskReadRawDelta.Value, -1)->Buffer); - SetDlgItemText(Context->PanelHandle, IDC_ZREADBYTESDELTA_V, PhaFormatSize(block->DiskReadRawDelta.Delta, -1)->Buffer); - SetDlgItemText(Context->PanelHandle, IDC_ZWRITES_V, PhaFormatUInt64(block->DiskWriteCount, TRUE)->Buffer); - SetDlgItemText(Context->PanelHandle, IDC_ZWRITEBYTES_V, PhaFormatSize(block->DiskWriteRawDelta.Value, -1)->Buffer); - SetDlgItemText(Context->PanelHandle, IDC_ZWRITEBYTESDELTA_V, PhaFormatSize(block->DiskWriteRawDelta.Delta, -1)->Buffer); - - SetDlgItemText(Context->PanelHandle, IDC_ZRECEIVES_V, PhaFormatUInt64(block->NetworkReceiveCount, TRUE)->Buffer); - SetDlgItemText(Context->PanelHandle, IDC_ZRECEIVEBYTES_V, PhaFormatSize(block->NetworkReceiveRawDelta.Value, -1)->Buffer); - SetDlgItemText(Context->PanelHandle, IDC_ZRECEIVEBYTESDELTA_V, PhaFormatSize(block->NetworkReceiveRawDelta.Delta, -1)->Buffer); - SetDlgItemText(Context->PanelHandle, IDC_ZSENDS_V, PhaFormatUInt64(block->NetworkSendCount, TRUE)->Buffer); - SetDlgItemText(Context->PanelHandle, IDC_ZSENDBYTES_V, PhaFormatSize(block->NetworkSendRawDelta.Value, -1)->Buffer); - SetDlgItemText(Context->PanelHandle, IDC_ZSENDBYTESDELTA_V, PhaFormatSize(block->NetworkSendRawDelta.Delta, -1)->Buffer); -} - -VOID EtwDiskNetworkUpdateInfo( - _In_ PET_DISKNET_CONTEXT Context - ) -{ - PET_PROCESS_BLOCK block = Context->Block; - - Context->CurrentDiskRead = block->DiskReadRawDelta.Delta; - Context->CurrentDiskWrite = block->DiskWriteRawDelta.Delta; - Context->CurrentNetworkSend = block->NetworkSendRawDelta.Delta; - Context->CurrentNetworkReceive = block->NetworkReceiveRawDelta.Delta; - - PhAddItemCircularBuffer_ULONG64(&Context->DiskReadHistory, Context->CurrentDiskRead); - PhAddItemCircularBuffer_ULONG64(&Context->DiskWriteHistory, Context->CurrentDiskWrite); - PhAddItemCircularBuffer_ULONG64(&Context->NetworkSendHistory, Context->CurrentNetworkSend); - PhAddItemCircularBuffer_ULONG64(&Context->NetworkReceiveHistory, Context->CurrentNetworkReceive); -} - -VOID NTAPI EtwDiskNetworkUpdateHandler( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - PET_DISKNET_CONTEXT context = Context; - - if (!context->Enabled) - return; - - if (context->WindowHandle) - { - PostMessage(context->WindowHandle, UPDATE_MSG, 0, 0); - } -} - -INT_PTR CALLBACK EtwDiskNetworkPageDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - LPPROPSHEETPAGE propSheetPage; - PPH_PROCESS_PROPPAGECONTEXT propPageContext; - PPH_PROCESS_ITEM processItem; - PET_DISKNET_CONTEXT context; - - if (PhPropPageDlgProcHeader(hwndDlg, uMsg, lParam, &propSheetPage, &propPageContext, &processItem)) - { - context = propPageContext->Context; - } - else - { - return FALSE; - } - - switch (uMsg) - { - case WM_INITDIALOG: - { - ULONG sampleCount; - - sampleCount = PhGetIntegerSetting(L"SampleCount"); - - context = PhAllocate(sizeof(ET_DISKNET_CONTEXT)); - memset(context, 0, sizeof(ET_DISKNET_CONTEXT)); - - context->WindowHandle = hwndDlg; - context->Block = EtGetProcessBlock(processItem); - context->Enabled = TRUE; - context->DiskGroupBox = GetDlgItem(hwndDlg, IDC_GROUPDISK); - context->NetworkGroupBox = GetDlgItem(hwndDlg, IDC_GROUPNETWORK); - propPageContext->Context = context; - - PhInitializeLayoutManager(&context->LayoutManager, hwndDlg); - - PhInitializeGraphState(&context->DiskGraphState); - PhInitializeGraphState(&context->NetworkGraphState); - - PhInitializeCircularBuffer_ULONG64(&context->DiskReadHistory, sampleCount); - PhInitializeCircularBuffer_ULONG64(&context->DiskWriteHistory, sampleCount); - PhInitializeCircularBuffer_ULONG64(&context->NetworkSendHistory, sampleCount); - PhInitializeCircularBuffer_ULONG64(&context->NetworkReceiveHistory, sampleCount); - - EtwDiskNetworkCreateGraphs(context); - EtwDiskNetworkCreatePanel(context); - EtwDiskNetworkUpdateInfo(context); - EtwDiskNetworkUpdatePanel(context); - - PhRegisterCallback( - &PhProcessesUpdatedEvent, - EtwDiskNetworkUpdateHandler, - context, - &context->ProcessesUpdatedRegistration - ); - } - break; - case WM_DESTROY: - { - PhDeleteLayoutManager(&context->LayoutManager); - - PhDeleteGraphState(&context->DiskGraphState); - PhDeleteGraphState(&context->NetworkGraphState); - - PhDeleteCircularBuffer_ULONG64(&context->DiskReadHistory); - PhDeleteCircularBuffer_ULONG64(&context->DiskWriteHistory); - PhDeleteCircularBuffer_ULONG64(&context->NetworkSendHistory); - PhDeleteCircularBuffer_ULONG64(&context->NetworkReceiveHistory); - - if (context->DiskGraphHandle) - DestroyWindow(context->DiskGraphHandle); - if (context->NetworkGraphHandle) - DestroyWindow(context->NetworkGraphHandle); - if (context->PanelHandle) - DestroyWindow(context->PanelHandle); - - PhUnregisterCallback(&PhProcessesUpdatedEvent, &context->ProcessesUpdatedRegistration); - PhFree(context); - - PhPropPageDlgProcDestroy(hwndDlg); - } - break; - case WM_SHOWWINDOW: - { - if (PhBeginPropPageLayout(hwndDlg, propPageContext)) - PhEndPropPageLayout(hwndDlg, propPageContext); - } - break; - case WM_NOTIFY: - { - LPNMHDR header = (LPNMHDR)lParam; - - switch (header->code) - { - case PSN_SETACTIVE: - context->Enabled = TRUE; - break; - case PSN_KILLACTIVE: - context->Enabled = FALSE; - break; - case GCN_GETDRAWINFO: - { - PPH_GRAPH_GETDRAWINFO getDrawInfo = (PPH_GRAPH_GETDRAWINFO)header; - PPH_GRAPH_DRAW_INFO drawInfo = getDrawInfo->DrawInfo; - - if (header->hwndFrom == context->DiskGraphHandle) - { - if (PhGetIntegerSetting(L"GraphShowText")) - { - HDC hdc; - - PhMoveReference(&context->DiskGraphState.Text, PhFormatString( - L"R: %s, W: %s", - PhaFormatSize(context->CurrentDiskRead, -1)->Buffer, - PhaFormatSize(context->CurrentDiskWrite, -1)->Buffer - )); - - hdc = Graph_GetBufferedContext(context->DiskGraphHandle); - SelectObject(hdc, PhApplicationFont); - PhSetGraphText(hdc, drawInfo, &context->DiskGraphState.Text->sr, - &NormalGraphTextMargin, &NormalGraphTextPadding, PH_ALIGN_TOP | PH_ALIGN_LEFT); - } - else - { - drawInfo->Text.Buffer = NULL; - } - - drawInfo->Flags = PH_GRAPH_USE_GRID_X | PH_GRAPH_USE_GRID_Y | PH_GRAPH_LABEL_MAX_Y | PH_GRAPH_USE_LINE_2; - PhSiSetColorsGraphDrawInfo(drawInfo, PhGetIntegerSetting(L"ColorIoReadOther"), PhGetIntegerSetting(L"ColorIoWrite")); - PhGraphStateGetDrawInfo(&context->DiskGraphState, getDrawInfo, context->DiskReadHistory.Count); - - if (!context->DiskGraphState.Valid) - { - FLOAT max = 0; - - for (ULONG i = 0; i < drawInfo->LineDataCount; i++) - { - FLOAT data1; - FLOAT data2; - - context->DiskGraphState.Data1[i] = data1 = (FLOAT)PhGetItemCircularBuffer_ULONG64(&context->DiskReadHistory, i); - context->DiskGraphState.Data2[i] = data2 = (FLOAT)PhGetItemCircularBuffer_ULONG64(&context->DiskWriteHistory, i); - - if (max < data1 + data2) - max = data1 + data2; - } - - // Minimum scaling of 1 MB. - //if (max < 1024 * 1024) - // max = 1024 * 1024; - - if (max != 0) - { - // Scale the data. - - PhDivideSinglesBySingle( - context->DiskGraphState.Data1, - max, - drawInfo->LineDataCount - ); - PhDivideSinglesBySingle( - context->DiskGraphState.Data2, - max, - drawInfo->LineDataCount - ); - } - - drawInfo->LabelYFunction = PhSiSizeLabelYFunction; - drawInfo->LabelYFunctionParameter = max; - - context->DiskGraphState.Valid = TRUE; - } - } - else if (header->hwndFrom == context->NetworkGraphHandle) - { - if (PhGetIntegerSetting(L"GraphShowText")) - { - HDC hdc; - - PhMoveReference(&context->NetworkGraphState.Text, PhFormatString( - L"R: %s, S: %s", - PhaFormatSize(context->CurrentNetworkReceive, -1)->Buffer, - PhaFormatSize(context->CurrentNetworkSend, -1)->Buffer - )); - - hdc = Graph_GetBufferedContext(context->NetworkGraphHandle); - SelectObject(hdc, PhApplicationFont); - PhSetGraphText(hdc, drawInfo, &context->NetworkGraphState.Text->sr, - &NormalGraphTextMargin, &NormalGraphTextPadding, PH_ALIGN_TOP | PH_ALIGN_LEFT); - } - else - { - drawInfo->Text.Buffer = NULL; - } - - drawInfo->Flags = PH_GRAPH_USE_GRID_X | PH_GRAPH_USE_GRID_Y | PH_GRAPH_LABEL_MAX_Y | PH_GRAPH_USE_LINE_2; - PhSiSetColorsGraphDrawInfo(drawInfo, PhGetIntegerSetting(L"ColorIoReadOther"), PhGetIntegerSetting(L"ColorIoWrite")); - PhGraphStateGetDrawInfo(&context->NetworkGraphState, getDrawInfo, context->NetworkSendHistory.Count); - - if (!context->NetworkGraphState.Valid) - { - FLOAT max = 0; - - for (ULONG i = 0; i < drawInfo->LineDataCount; i++) - { - FLOAT data1; - FLOAT data2; - - context->NetworkGraphState.Data1[i] = data1 = (FLOAT)PhGetItemCircularBuffer_ULONG64(&context->NetworkReceiveHistory, i); - context->NetworkGraphState.Data2[i] = data2 = (FLOAT)PhGetItemCircularBuffer_ULONG64(&context->NetworkSendHistory, i); - - if (max < data1 + data2) - max = data1 + data2; - } - - // Minimum scaling of 1 MB. - //if (max < 1024 * 1024) - // max = 1024 * 1024; - - if (max != 0) - { - // Scale the data. - - PhDivideSinglesBySingle( - context->NetworkGraphState.Data1, - max, - drawInfo->LineDataCount - ); - PhDivideSinglesBySingle( - context->NetworkGraphState.Data2, - max, - drawInfo->LineDataCount - ); - } - - drawInfo->LabelYFunction = PhSiSizeLabelYFunction; - drawInfo->LabelYFunctionParameter = max; - - context->NetworkGraphState.Valid = TRUE; - } - } - } - break; - case GCN_GETTOOLTIPTEXT: - { - PPH_GRAPH_GETTOOLTIPTEXT getTooltipText = (PPH_GRAPH_GETTOOLTIPTEXT)lParam; - - if (getTooltipText->Index < getTooltipText->TotalCount) - { - if (header->hwndFrom == context->DiskGraphHandle) - { - if (context->DiskGraphState.TooltipIndex != getTooltipText->Index) - { - ULONG64 diskRead = PhGetItemCircularBuffer_ULONG64( - &context->DiskReadHistory, - getTooltipText->Index - ); - - ULONG64 diskWrite = PhGetItemCircularBuffer_ULONG64( - &context->DiskWriteHistory, - getTooltipText->Index - ); - - PhMoveReference(&context->DiskGraphState.TooltipText, PhFormatString( - L"R: %s\nW: %s\n%s", - PhaFormatSize(diskRead, -1)->Buffer, - PhaFormatSize(diskWrite, -1)->Buffer, - ((PPH_STRING)PH_AUTO(PhGetStatisticsTimeString(NULL, getTooltipText->Index)))->Buffer - )); - } - - getTooltipText->Text = context->DiskGraphState.TooltipText->sr; - } - else if (header->hwndFrom == context->NetworkGraphHandle) - { - if (context->NetworkGraphState.TooltipIndex != getTooltipText->Index) - { - ULONG64 networkSend = PhGetItemCircularBuffer_ULONG64( - &context->NetworkSendHistory, - getTooltipText->Index - ); - - ULONG64 networkReceive = PhGetItemCircularBuffer_ULONG64( - &context->NetworkReceiveHistory, - getTooltipText->Index - ); - - PhMoveReference(&context->NetworkGraphState.TooltipText, PhFormatString( - L"S: %s\nR: %s\n%s", - PhaFormatSize(networkSend, -1)->Buffer, - PhaFormatSize(networkReceive, -1)->Buffer, - ((PPH_STRING)PH_AUTO(PhGetStatisticsTimeString(NULL, getTooltipText->Index)))->Buffer - )); - } - - getTooltipText->Text = context->NetworkGraphState.TooltipText->sr; - } - } - } - break; - } - } - break; - case UPDATE_MSG: - { - if (context->Enabled) - { - EtwDiskNetworkUpdateInfo(context); - EtwDiskNetworkUpdateGraphs(context); - EtwDiskNetworkUpdatePanel(context); - } - } - break; - case WM_SIZE: - { - EtwDiskNetworkLayoutGraphs(context); - } - break; - } - - return FALSE; -} - -VOID EtProcessEtwPropertiesInitializing( - _In_ PVOID Parameter - ) -{ - PPH_PLUGIN_PROCESS_PROPCONTEXT propContext = Parameter; - - if (EtEtwEnabled) - { - PhAddProcessPropPage( - propContext->PropContext, - PhCreateProcessPropPageContextEx(PluginInstance->DllBase, MAKEINTRESOURCE(IDD_PROCDISKNET), EtwDiskNetworkPageDlgProc, NULL) - ); - } +/* + * Process Hacker Extended Tools - + * ETW process properties page + * + * Copyright (C) 2010-2011 wj32 + * Copyright (C) 2015 dmex + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include "exttools.h" + +static RECT NormalGraphTextMargin = { 5, 5, 5, 5 }; +static RECT NormalGraphTextPadding = { 3, 3, 3, 3 }; + +typedef struct _ET_DISKNET_CONTEXT +{ + HWND WindowHandle; + PET_PROCESS_BLOCK Block; + PH_CALLBACK_REGISTRATION ProcessesUpdatedRegistration; + BOOLEAN Enabled; + + PH_LAYOUT_MANAGER LayoutManager; + + HWND DiskGroupBox; + HWND NetworkGroupBox; + + HWND DiskGraphHandle; + HWND NetworkGraphHandle; + HWND PanelHandle; + + ULONG64 CurrentDiskRead; + ULONG64 CurrentDiskWrite; + ULONG64 CurrentNetworkSend; + ULONG64 CurrentNetworkReceive; + + PH_GRAPH_STATE DiskGraphState; + PH_GRAPH_STATE NetworkGraphState; + + PH_CIRCULAR_BUFFER_ULONG64 DiskReadHistory; + PH_CIRCULAR_BUFFER_ULONG64 DiskWriteHistory; + PH_CIRCULAR_BUFFER_ULONG64 NetworkSendHistory; + PH_CIRCULAR_BUFFER_ULONG64 NetworkReceiveHistory; +} ET_DISKNET_CONTEXT, *PET_DISKNET_CONTEXT; + +INT_PTR CALLBACK EtwDiskNetworkPanelDialogProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + return FALSE; +} + +VOID EtwDiskNetworkCreateGraphs( + _In_ PET_DISKNET_CONTEXT Context + ) +{ + Context->DiskGraphHandle = CreateWindow( + PH_GRAPH_CLASSNAME, + NULL, + WS_VISIBLE | WS_CHILD | WS_BORDER, + 0, + 0, + 3, + 3, + Context->WindowHandle, + NULL, + NULL, + NULL + ); + Graph_SetTooltip(Context->DiskGraphHandle, TRUE); + + Context->NetworkGraphHandle = CreateWindow( + PH_GRAPH_CLASSNAME, + NULL, + WS_VISIBLE | WS_CHILD | WS_BORDER, + 0, + 0, + 3, + 3, + Context->WindowHandle, + NULL, + NULL, + NULL + ); + Graph_SetTooltip(Context->NetworkGraphHandle, TRUE); +} + +VOID EtwDiskNetworkCreatePanel( + _In_ PET_DISKNET_CONTEXT Context + ) +{ + RECT margin; + + Context->PanelHandle = CreateDialogParam( + PluginInstance->DllBase, + MAKEINTRESOURCE(IDD_PROCDISKNET_PANEL), + Context->WindowHandle, + EtwDiskNetworkPanelDialogProc, + (LPARAM)Context + ); + + SetWindowPos( + Context->PanelHandle, + NULL, + 10, 0, 0, 0, + SWP_NOACTIVATE | SWP_NOREDRAW | SWP_NOSIZE | SWP_NOZORDER + ); + + ShowWindow(Context->PanelHandle, SW_SHOW); + + margin.left = 0; + margin.top = 0; + margin.right = 0; + margin.bottom = 10; + MapDialogRect(Context->WindowHandle, &margin); + + PhAddLayoutItemEx( + &Context->LayoutManager, + Context->PanelHandle, + NULL, + PH_ANCHOR_BOTTOM | PH_ANCHOR_LEFT, + margin + ); + + SendMessage(Context->WindowHandle, WM_SIZE, 0, 0); +} + +VOID EtwDiskNetworkLayoutGraphs( + _In_ PET_DISKNET_CONTEXT Context + ) +{ + HDWP deferHandle; + RECT clientRect; + RECT panelRect; + RECT margin = { ET_SCALE_DPI(13), ET_SCALE_DPI(13), ET_SCALE_DPI(13), ET_SCALE_DPI(13) }; + RECT innerMargin = { ET_SCALE_DPI(10), ET_SCALE_DPI(20), ET_SCALE_DPI(10), ET_SCALE_DPI(10) }; + LONG between = ET_SCALE_DPI(3); + ULONG graphWidth; + ULONG graphHeight; + + PhLayoutManagerLayout(&Context->LayoutManager); + + Context->DiskGraphState.Valid = FALSE; + Context->NetworkGraphState.Valid = FALSE; + + GetClientRect(Context->WindowHandle, &clientRect); + + // Limit the rectangle bottom to the top of the panel. + GetWindowRect(Context->PanelHandle, &panelRect); + MapWindowPoints(NULL, Context->WindowHandle, (PPOINT)&panelRect, 2); + clientRect.bottom = panelRect.top + 10; // +10 removing extra spacing + + graphWidth = clientRect.right - margin.left - margin.right; + graphHeight = (clientRect.bottom - margin.top - margin.bottom - between * 2) / 2; + + deferHandle = BeginDeferWindowPos(4); + + deferHandle = DeferWindowPos(deferHandle, Context->DiskGroupBox, NULL, margin.left, margin.top, graphWidth, graphHeight, SWP_NOACTIVATE | SWP_NOZORDER); + deferHandle = DeferWindowPos( + deferHandle, + Context->DiskGraphHandle, + NULL, + margin.left + innerMargin.left, + margin.top + innerMargin.top, + graphWidth - innerMargin.left - innerMargin.right, + graphHeight - innerMargin.top - innerMargin.bottom, + SWP_NOACTIVATE | SWP_NOZORDER + ); + + deferHandle = DeferWindowPos(deferHandle, Context->NetworkGroupBox, NULL, margin.left, margin.top + graphHeight + between, graphWidth, graphHeight, SWP_NOACTIVATE | SWP_NOZORDER); + deferHandle = DeferWindowPos( + deferHandle, + Context->NetworkGraphHandle, + NULL, + margin.left + innerMargin.left, + margin.top + graphHeight + between + innerMargin.top, + graphWidth - innerMargin.left - innerMargin.right, + graphHeight - innerMargin.top - innerMargin.bottom, + SWP_NOACTIVATE | SWP_NOZORDER + ); + + EndDeferWindowPos(deferHandle); +} + +VOID EtwDiskNetworkUpdateGraphs( + _In_ PET_DISKNET_CONTEXT Context + ) +{ + Context->DiskGraphState.Valid = FALSE; + Context->DiskGraphState.TooltipIndex = -1; + Graph_MoveGrid(Context->DiskGraphHandle, 1); + Graph_Draw(Context->DiskGraphHandle); + Graph_UpdateTooltip(Context->DiskGraphHandle); + InvalidateRect(Context->DiskGraphHandle, NULL, FALSE); + + Context->NetworkGraphState.Valid = FALSE; + Context->NetworkGraphState.TooltipIndex = -1; + Graph_MoveGrid(Context->NetworkGraphHandle, 1); + Graph_Draw(Context->NetworkGraphHandle); + Graph_UpdateTooltip(Context->NetworkGraphHandle); + InvalidateRect(Context->NetworkGraphHandle, NULL, FALSE); +} + +VOID EtwDiskNetworkUpdatePanel( + _Inout_ PET_DISKNET_CONTEXT Context + ) +{ + PET_PROCESS_BLOCK block = Context->Block; + + SetDlgItemText(Context->PanelHandle, IDC_ZREADS_V, PhaFormatUInt64(block->DiskReadCount, TRUE)->Buffer); + SetDlgItemText(Context->PanelHandle, IDC_ZREADBYTES_V, PhaFormatSize(block->DiskReadRawDelta.Value, -1)->Buffer); + SetDlgItemText(Context->PanelHandle, IDC_ZREADBYTESDELTA_V, PhaFormatSize(block->DiskReadRawDelta.Delta, -1)->Buffer); + SetDlgItemText(Context->PanelHandle, IDC_ZWRITES_V, PhaFormatUInt64(block->DiskWriteCount, TRUE)->Buffer); + SetDlgItemText(Context->PanelHandle, IDC_ZWRITEBYTES_V, PhaFormatSize(block->DiskWriteRawDelta.Value, -1)->Buffer); + SetDlgItemText(Context->PanelHandle, IDC_ZWRITEBYTESDELTA_V, PhaFormatSize(block->DiskWriteRawDelta.Delta, -1)->Buffer); + + SetDlgItemText(Context->PanelHandle, IDC_ZRECEIVES_V, PhaFormatUInt64(block->NetworkReceiveCount, TRUE)->Buffer); + SetDlgItemText(Context->PanelHandle, IDC_ZRECEIVEBYTES_V, PhaFormatSize(block->NetworkReceiveRawDelta.Value, -1)->Buffer); + SetDlgItemText(Context->PanelHandle, IDC_ZRECEIVEBYTESDELTA_V, PhaFormatSize(block->NetworkReceiveRawDelta.Delta, -1)->Buffer); + SetDlgItemText(Context->PanelHandle, IDC_ZSENDS_V, PhaFormatUInt64(block->NetworkSendCount, TRUE)->Buffer); + SetDlgItemText(Context->PanelHandle, IDC_ZSENDBYTES_V, PhaFormatSize(block->NetworkSendRawDelta.Value, -1)->Buffer); + SetDlgItemText(Context->PanelHandle, IDC_ZSENDBYTESDELTA_V, PhaFormatSize(block->NetworkSendRawDelta.Delta, -1)->Buffer); +} + +VOID EtwDiskNetworkUpdateInfo( + _In_ PET_DISKNET_CONTEXT Context + ) +{ + PET_PROCESS_BLOCK block = Context->Block; + + Context->CurrentDiskRead = block->DiskReadRawDelta.Delta; + Context->CurrentDiskWrite = block->DiskWriteRawDelta.Delta; + Context->CurrentNetworkSend = block->NetworkSendRawDelta.Delta; + Context->CurrentNetworkReceive = block->NetworkReceiveRawDelta.Delta; + + PhAddItemCircularBuffer_ULONG64(&Context->DiskReadHistory, Context->CurrentDiskRead); + PhAddItemCircularBuffer_ULONG64(&Context->DiskWriteHistory, Context->CurrentDiskWrite); + PhAddItemCircularBuffer_ULONG64(&Context->NetworkSendHistory, Context->CurrentNetworkSend); + PhAddItemCircularBuffer_ULONG64(&Context->NetworkReceiveHistory, Context->CurrentNetworkReceive); +} + +VOID NTAPI EtwDiskNetworkUpdateHandler( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + PET_DISKNET_CONTEXT context = Context; + + if (!context->Enabled) + return; + + if (context->WindowHandle) + { + PostMessage(context->WindowHandle, UPDATE_MSG, 0, 0); + } +} + +INT_PTR CALLBACK EtwDiskNetworkPageDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + LPPROPSHEETPAGE propSheetPage; + PPH_PROCESS_PROPPAGECONTEXT propPageContext; + PPH_PROCESS_ITEM processItem; + PET_DISKNET_CONTEXT context; + + if (PhPropPageDlgProcHeader(hwndDlg, uMsg, lParam, &propSheetPage, &propPageContext, &processItem)) + { + context = propPageContext->Context; + } + else + { + return FALSE; + } + + switch (uMsg) + { + case WM_INITDIALOG: + { + ULONG sampleCount; + + sampleCount = PhGetIntegerSetting(L"SampleCount"); + + context = PhAllocate(sizeof(ET_DISKNET_CONTEXT)); + memset(context, 0, sizeof(ET_DISKNET_CONTEXT)); + + context->WindowHandle = hwndDlg; + context->Block = EtGetProcessBlock(processItem); + context->Enabled = TRUE; + context->DiskGroupBox = GetDlgItem(hwndDlg, IDC_GROUPDISK); + context->NetworkGroupBox = GetDlgItem(hwndDlg, IDC_GROUPNETWORK); + propPageContext->Context = context; + + PhInitializeLayoutManager(&context->LayoutManager, hwndDlg); + + PhInitializeGraphState(&context->DiskGraphState); + PhInitializeGraphState(&context->NetworkGraphState); + + PhInitializeCircularBuffer_ULONG64(&context->DiskReadHistory, sampleCount); + PhInitializeCircularBuffer_ULONG64(&context->DiskWriteHistory, sampleCount); + PhInitializeCircularBuffer_ULONG64(&context->NetworkSendHistory, sampleCount); + PhInitializeCircularBuffer_ULONG64(&context->NetworkReceiveHistory, sampleCount); + + EtwDiskNetworkCreateGraphs(context); + EtwDiskNetworkCreatePanel(context); + EtwDiskNetworkUpdateInfo(context); + EtwDiskNetworkUpdatePanel(context); + + PhRegisterCallback( + &PhProcessesUpdatedEvent, + EtwDiskNetworkUpdateHandler, + context, + &context->ProcessesUpdatedRegistration + ); + } + break; + case WM_DESTROY: + { + PhDeleteLayoutManager(&context->LayoutManager); + + PhDeleteGraphState(&context->DiskGraphState); + PhDeleteGraphState(&context->NetworkGraphState); + + PhDeleteCircularBuffer_ULONG64(&context->DiskReadHistory); + PhDeleteCircularBuffer_ULONG64(&context->DiskWriteHistory); + PhDeleteCircularBuffer_ULONG64(&context->NetworkSendHistory); + PhDeleteCircularBuffer_ULONG64(&context->NetworkReceiveHistory); + + if (context->DiskGraphHandle) + DestroyWindow(context->DiskGraphHandle); + if (context->NetworkGraphHandle) + DestroyWindow(context->NetworkGraphHandle); + if (context->PanelHandle) + DestroyWindow(context->PanelHandle); + + PhUnregisterCallback(&PhProcessesUpdatedEvent, &context->ProcessesUpdatedRegistration); + PhFree(context); + + PhPropPageDlgProcDestroy(hwndDlg); + } + break; + case WM_SHOWWINDOW: + { + if (PhBeginPropPageLayout(hwndDlg, propPageContext)) + PhEndPropPageLayout(hwndDlg, propPageContext); + } + break; + case WM_NOTIFY: + { + LPNMHDR header = (LPNMHDR)lParam; + + switch (header->code) + { + case PSN_SETACTIVE: + context->Enabled = TRUE; + break; + case PSN_KILLACTIVE: + context->Enabled = FALSE; + break; + case GCN_GETDRAWINFO: + { + PPH_GRAPH_GETDRAWINFO getDrawInfo = (PPH_GRAPH_GETDRAWINFO)header; + PPH_GRAPH_DRAW_INFO drawInfo = getDrawInfo->DrawInfo; + + if (header->hwndFrom == context->DiskGraphHandle) + { + if (PhGetIntegerSetting(L"GraphShowText")) + { + HDC hdc; + + PhMoveReference(&context->DiskGraphState.Text, PhFormatString( + L"R: %s, W: %s", + PhaFormatSize(context->CurrentDiskRead, -1)->Buffer, + PhaFormatSize(context->CurrentDiskWrite, -1)->Buffer + )); + + hdc = Graph_GetBufferedContext(context->DiskGraphHandle); + SelectObject(hdc, PhApplicationFont); + PhSetGraphText(hdc, drawInfo, &context->DiskGraphState.Text->sr, + &NormalGraphTextMargin, &NormalGraphTextPadding, PH_ALIGN_TOP | PH_ALIGN_LEFT); + } + else + { + drawInfo->Text.Buffer = NULL; + } + + drawInfo->Flags = PH_GRAPH_USE_GRID_X | PH_GRAPH_USE_GRID_Y | PH_GRAPH_LABEL_MAX_Y | PH_GRAPH_USE_LINE_2; + PhSiSetColorsGraphDrawInfo(drawInfo, PhGetIntegerSetting(L"ColorIoReadOther"), PhGetIntegerSetting(L"ColorIoWrite")); + PhGraphStateGetDrawInfo(&context->DiskGraphState, getDrawInfo, context->DiskReadHistory.Count); + + if (!context->DiskGraphState.Valid) + { + FLOAT max = 0; + + for (ULONG i = 0; i < drawInfo->LineDataCount; i++) + { + FLOAT data1; + FLOAT data2; + + context->DiskGraphState.Data1[i] = data1 = (FLOAT)PhGetItemCircularBuffer_ULONG64(&context->DiskReadHistory, i); + context->DiskGraphState.Data2[i] = data2 = (FLOAT)PhGetItemCircularBuffer_ULONG64(&context->DiskWriteHistory, i); + + if (max < data1 + data2) + max = data1 + data2; + } + + // Minimum scaling of 1 MB. + //if (max < 1024 * 1024) + // max = 1024 * 1024; + + if (max != 0) + { + // Scale the data. + + PhDivideSinglesBySingle( + context->DiskGraphState.Data1, + max, + drawInfo->LineDataCount + ); + PhDivideSinglesBySingle( + context->DiskGraphState.Data2, + max, + drawInfo->LineDataCount + ); + } + + drawInfo->LabelYFunction = PhSiSizeLabelYFunction; + drawInfo->LabelYFunctionParameter = max; + + context->DiskGraphState.Valid = TRUE; + } + } + else if (header->hwndFrom == context->NetworkGraphHandle) + { + if (PhGetIntegerSetting(L"GraphShowText")) + { + HDC hdc; + + PhMoveReference(&context->NetworkGraphState.Text, PhFormatString( + L"R: %s, S: %s", + PhaFormatSize(context->CurrentNetworkReceive, -1)->Buffer, + PhaFormatSize(context->CurrentNetworkSend, -1)->Buffer + )); + + hdc = Graph_GetBufferedContext(context->NetworkGraphHandle); + SelectObject(hdc, PhApplicationFont); + PhSetGraphText(hdc, drawInfo, &context->NetworkGraphState.Text->sr, + &NormalGraphTextMargin, &NormalGraphTextPadding, PH_ALIGN_TOP | PH_ALIGN_LEFT); + } + else + { + drawInfo->Text.Buffer = NULL; + } + + drawInfo->Flags = PH_GRAPH_USE_GRID_X | PH_GRAPH_USE_GRID_Y | PH_GRAPH_LABEL_MAX_Y | PH_GRAPH_USE_LINE_2; + PhSiSetColorsGraphDrawInfo(drawInfo, PhGetIntegerSetting(L"ColorIoReadOther"), PhGetIntegerSetting(L"ColorIoWrite")); + PhGraphStateGetDrawInfo(&context->NetworkGraphState, getDrawInfo, context->NetworkSendHistory.Count); + + if (!context->NetworkGraphState.Valid) + { + FLOAT max = 0; + + for (ULONG i = 0; i < drawInfo->LineDataCount; i++) + { + FLOAT data1; + FLOAT data2; + + context->NetworkGraphState.Data1[i] = data1 = (FLOAT)PhGetItemCircularBuffer_ULONG64(&context->NetworkReceiveHistory, i); + context->NetworkGraphState.Data2[i] = data2 = (FLOAT)PhGetItemCircularBuffer_ULONG64(&context->NetworkSendHistory, i); + + if (max < data1 + data2) + max = data1 + data2; + } + + // Minimum scaling of 1 MB. + //if (max < 1024 * 1024) + // max = 1024 * 1024; + + if (max != 0) + { + // Scale the data. + + PhDivideSinglesBySingle( + context->NetworkGraphState.Data1, + max, + drawInfo->LineDataCount + ); + PhDivideSinglesBySingle( + context->NetworkGraphState.Data2, + max, + drawInfo->LineDataCount + ); + } + + drawInfo->LabelYFunction = PhSiSizeLabelYFunction; + drawInfo->LabelYFunctionParameter = max; + + context->NetworkGraphState.Valid = TRUE; + } + } + } + break; + case GCN_GETTOOLTIPTEXT: + { + PPH_GRAPH_GETTOOLTIPTEXT getTooltipText = (PPH_GRAPH_GETTOOLTIPTEXT)lParam; + + if (getTooltipText->Index < getTooltipText->TotalCount) + { + if (header->hwndFrom == context->DiskGraphHandle) + { + if (context->DiskGraphState.TooltipIndex != getTooltipText->Index) + { + ULONG64 diskRead = PhGetItemCircularBuffer_ULONG64( + &context->DiskReadHistory, + getTooltipText->Index + ); + + ULONG64 diskWrite = PhGetItemCircularBuffer_ULONG64( + &context->DiskWriteHistory, + getTooltipText->Index + ); + + PhMoveReference(&context->DiskGraphState.TooltipText, PhFormatString( + L"R: %s\nW: %s\n%s", + PhaFormatSize(diskRead, -1)->Buffer, + PhaFormatSize(diskWrite, -1)->Buffer, + ((PPH_STRING)PH_AUTO(PhGetStatisticsTimeString(NULL, getTooltipText->Index)))->Buffer + )); + } + + getTooltipText->Text = context->DiskGraphState.TooltipText->sr; + } + else if (header->hwndFrom == context->NetworkGraphHandle) + { + if (context->NetworkGraphState.TooltipIndex != getTooltipText->Index) + { + ULONG64 networkSend = PhGetItemCircularBuffer_ULONG64( + &context->NetworkSendHistory, + getTooltipText->Index + ); + + ULONG64 networkReceive = PhGetItemCircularBuffer_ULONG64( + &context->NetworkReceiveHistory, + getTooltipText->Index + ); + + PhMoveReference(&context->NetworkGraphState.TooltipText, PhFormatString( + L"S: %s\nR: %s\n%s", + PhaFormatSize(networkSend, -1)->Buffer, + PhaFormatSize(networkReceive, -1)->Buffer, + ((PPH_STRING)PH_AUTO(PhGetStatisticsTimeString(NULL, getTooltipText->Index)))->Buffer + )); + } + + getTooltipText->Text = context->NetworkGraphState.TooltipText->sr; + } + } + } + break; + } + } + break; + case UPDATE_MSG: + { + if (context->Enabled) + { + EtwDiskNetworkUpdateInfo(context); + EtwDiskNetworkUpdateGraphs(context); + EtwDiskNetworkUpdatePanel(context); + } + } + break; + case WM_SIZE: + { + EtwDiskNetworkLayoutGraphs(context); + } + break; + } + + return FALSE; +} + +VOID EtProcessEtwPropertiesInitializing( + _In_ PVOID Parameter + ) +{ + PPH_PLUGIN_PROCESS_PROPCONTEXT propContext = Parameter; + + if (EtEtwEnabled) + { + PhAddProcessPropPage( + propContext->PropContext, + PhCreateProcessPropPageContextEx(PluginInstance->DllBase, MAKEINTRESOURCE(IDD_PROCDISKNET), EtwDiskNetworkPageDlgProc, NULL) + ); + } } \ No newline at end of file diff --git a/plugins/ExtendedTools/etwstat.c b/plugins/ExtendedTools/etwstat.c index 8238528249a8..33ee65dd33ee 100644 --- a/plugins/ExtendedTools/etwstat.c +++ b/plugins/ExtendedTools/etwstat.c @@ -1,419 +1,419 @@ -/* - * Process Hacker Extended Tools - - * ETW statistics collection - * - * Copyright (C) 2010-2011 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include "exttools.h" -#include "etwmon.h" - -VOID NTAPI EtEtwProcessesUpdatedCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ); - -VOID NTAPI EtEtwNetworkItemsUpdatedCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ); - -static PH_CALLBACK_REGISTRATION EtpProcessesUpdatedCallbackRegistration; -static PH_CALLBACK_REGISTRATION EtpNetworkItemsUpdatedCallbackRegistration; - -ULONG EtpDiskReadRaw; -ULONG EtpDiskWriteRaw; -ULONG EtpNetworkReceiveRaw; -ULONG EtpNetworkSendRaw; - -ULONG EtDiskReadCount; -ULONG EtDiskWriteCount; -ULONG EtNetworkReceiveCount; -ULONG EtNetworkSendCount; - -PH_UINT32_DELTA EtDiskReadDelta; -PH_UINT32_DELTA EtDiskWriteDelta; -PH_UINT32_DELTA EtNetworkReceiveDelta; -PH_UINT32_DELTA EtNetworkSendDelta; - -PH_UINT32_DELTA EtDiskReadCountDelta; -PH_UINT32_DELTA EtDiskWriteCountDelta; -PH_UINT32_DELTA EtNetworkReceiveCountDelta; -PH_UINT32_DELTA EtNetworkSendCountDelta; - -PH_CIRCULAR_BUFFER_ULONG EtDiskReadHistory; -PH_CIRCULAR_BUFFER_ULONG EtDiskWriteHistory; -PH_CIRCULAR_BUFFER_ULONG EtNetworkReceiveHistory; -PH_CIRCULAR_BUFFER_ULONG EtNetworkSendHistory; -PH_CIRCULAR_BUFFER_ULONG EtMaxDiskHistory; // ID of max. disk usage process -PH_CIRCULAR_BUFFER_ULONG EtMaxNetworkHistory; // ID of max. network usage process - -PVOID EtpProcessInformation; -PH_QUEUED_LOCK EtpProcessInformationLock = PH_QUEUED_LOCK_INIT; - -VOID EtEtwStatisticsInitialization( - VOID - ) -{ - EtEtwMonitorInitialization(); - - if (EtEtwEnabled) - { - ULONG sampleCount; - - sampleCount = PhGetIntegerSetting(L"SampleCount"); - PhInitializeCircularBuffer_ULONG(&EtDiskReadHistory, sampleCount); - PhInitializeCircularBuffer_ULONG(&EtDiskWriteHistory, sampleCount); - PhInitializeCircularBuffer_ULONG(&EtNetworkReceiveHistory, sampleCount); - PhInitializeCircularBuffer_ULONG(&EtNetworkSendHistory, sampleCount); - PhInitializeCircularBuffer_ULONG(&EtMaxDiskHistory, sampleCount); - PhInitializeCircularBuffer_ULONG(&EtMaxNetworkHistory, sampleCount); - - PhRegisterCallback( - &PhProcessesUpdatedEvent, - EtEtwProcessesUpdatedCallback, - NULL, - &EtpProcessesUpdatedCallbackRegistration - ); - PhRegisterCallback( - &PhNetworkItemsUpdatedEvent, - EtEtwNetworkItemsUpdatedCallback, - NULL, - &EtpNetworkItemsUpdatedCallbackRegistration - ); - } -} - -VOID EtEtwStatisticsUninitialization( - VOID - ) -{ - EtEtwMonitorUninitialization(); -} - -VOID EtProcessDiskEvent( - _In_ PET_ETW_DISK_EVENT Event - ) -{ - PPH_PROCESS_ITEM processItem; - PET_PROCESS_BLOCK block; - - if (Event->Type == EtEtwDiskReadType) - { - EtpDiskReadRaw += Event->TransferSize; - EtDiskReadCount++; - } - else - { - EtpDiskWriteRaw += Event->TransferSize; - EtDiskWriteCount++; - } - - if (processItem = PhReferenceProcessItem(Event->ClientId.UniqueProcess)) - { - block = EtGetProcessBlock(processItem); - - if (Event->Type == EtEtwDiskReadType) - { - block->DiskReadRaw += Event->TransferSize; - block->DiskReadCount++; - } - else - { - block->DiskWriteRaw += Event->TransferSize; - block->DiskWriteCount++; - } - - PhDereferenceObject(processItem); - } -} - -VOID EtProcessNetworkEvent( - _In_ PET_ETW_NETWORK_EVENT Event - ) -{ - PPH_PROCESS_ITEM processItem; - PET_PROCESS_BLOCK block; - PPH_NETWORK_ITEM networkItem; - PET_NETWORK_BLOCK networkBlock; - - if (Event->Type == EtEtwNetworkReceiveType) - { - EtpNetworkReceiveRaw += Event->TransferSize; - EtNetworkReceiveCount++; - } - else - { - EtpNetworkSendRaw += Event->TransferSize; - EtNetworkSendCount++; - } - - // Note: there is always the possibility of us receiving the event too early, - // before the process item or network item is created. So events may be lost. - - if (processItem = PhReferenceProcessItem(Event->ClientId.UniqueProcess)) - { - block = EtGetProcessBlock(processItem); - - if (Event->Type == EtEtwNetworkReceiveType) - { - block->NetworkReceiveRaw += Event->TransferSize; - block->NetworkReceiveCount++; - } - else - { - block->NetworkSendRaw += Event->TransferSize; - block->NetworkSendCount++; - } - - PhDereferenceObject(processItem); - } - - if (networkItem = PhReferenceNetworkItem( - Event->ProtocolType, - &Event->LocalEndpoint, - &Event->RemoteEndpoint, - Event->ClientId.UniqueProcess - )) - { - networkBlock = EtGetNetworkBlock(networkItem); - - if (Event->Type == EtEtwNetworkReceiveType) - { - networkBlock->ReceiveRaw += Event->TransferSize; - networkBlock->ReceiveCount++; - } - else - { - networkBlock->SendRaw += Event->TransferSize; - networkBlock->SendCount++; - } - - PhDereferenceObject(networkItem); - } -} - -VOID NTAPI EtEtwProcessesUpdatedCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - static ULONG runCount = 0; // MUST keep in sync with runCount in process provider - - PLIST_ENTRY listEntry; - ULONG64 maxDiskValue = 0; - PET_PROCESS_BLOCK maxDiskBlock = NULL; - ULONG64 maxNetworkValue = 0; - PET_PROCESS_BLOCK maxNetworkBlock = NULL; - - // Since Windows 8, we no longer get the correct process/thread IDs in the - // event headers for disk events. We need to update our process information since - // etwmon uses our EtThreadIdToProcessId function. - if (WindowsVersion >= WINDOWS_8) - EtUpdateProcessInformation(); - - // ETW is extremely lazy when it comes to flushing buffers, so we must do it - // manually. - EtFlushEtwSession(); - - // Update global statistics. - - PhUpdateDelta(&EtDiskReadDelta, EtpDiskReadRaw); - PhUpdateDelta(&EtDiskWriteDelta, EtpDiskWriteRaw); - PhUpdateDelta(&EtNetworkReceiveDelta, EtpNetworkReceiveRaw); - PhUpdateDelta(&EtNetworkSendDelta, EtpNetworkSendRaw); - - PhUpdateDelta(&EtDiskReadCountDelta, EtDiskReadCount); - PhUpdateDelta(&EtDiskWriteCountDelta, EtDiskWriteCount); - PhUpdateDelta(&EtNetworkReceiveCountDelta, EtNetworkReceiveCount); - PhUpdateDelta(&EtNetworkSendCountDelta, EtNetworkSendCount); - - // Update per-process statistics. - // Note: no lock is needed because we only ever modify the list on this same thread. - - listEntry = EtProcessBlockListHead.Flink; - - while (listEntry != &EtProcessBlockListHead) - { - PET_PROCESS_BLOCK block; - - block = CONTAINING_RECORD(listEntry, ET_PROCESS_BLOCK, ListEntry); - - PhUpdateDelta(&block->DiskReadDelta, block->DiskReadCount); - PhUpdateDelta(&block->DiskReadRawDelta, block->DiskReadRaw); - PhUpdateDelta(&block->DiskWriteDelta, block->DiskWriteCount); - PhUpdateDelta(&block->DiskWriteRawDelta, block->DiskWriteRaw); - PhUpdateDelta(&block->NetworkReceiveDelta, block->NetworkReceiveCount); - PhUpdateDelta(&block->NetworkReceiveRawDelta, block->NetworkReceiveRaw); - PhUpdateDelta(&block->NetworkSendDelta, block->NetworkSendCount); - PhUpdateDelta(&block->NetworkSendRawDelta, block->NetworkSendRaw); - - if (maxDiskValue < block->DiskReadRawDelta.Delta + block->DiskWriteRawDelta.Delta) - { - maxDiskValue = block->DiskReadRawDelta.Delta + block->DiskWriteRawDelta.Delta; - maxDiskBlock = block; - } - - if (maxNetworkValue < block->NetworkReceiveRawDelta.Delta + block->NetworkSendRawDelta.Delta) - { - maxNetworkValue = block->NetworkReceiveRawDelta.Delta + block->NetworkSendRawDelta.Delta; - maxNetworkBlock = block; - } - - listEntry = listEntry->Flink; - } - - // Update history buffers. - - if (runCount != 0) - { - PhAddItemCircularBuffer_ULONG(&EtDiskReadHistory, EtDiskReadDelta.Delta); - PhAddItemCircularBuffer_ULONG(&EtDiskWriteHistory, EtDiskWriteDelta.Delta); - PhAddItemCircularBuffer_ULONG(&EtNetworkReceiveHistory, EtNetworkReceiveDelta.Delta); - PhAddItemCircularBuffer_ULONG(&EtNetworkSendHistory, EtNetworkSendDelta.Delta); - - if (maxDiskBlock) - { - PhAddItemCircularBuffer_ULONG(&EtMaxDiskHistory, HandleToUlong(maxDiskBlock->ProcessItem->ProcessId)); - PhReferenceProcessRecordForStatistics(maxDiskBlock->ProcessItem->Record); - } - else - { - PhAddItemCircularBuffer_ULONG(&EtMaxDiskHistory, 0); - } - - if (maxNetworkBlock) - { - PhAddItemCircularBuffer_ULONG(&EtMaxNetworkHistory, HandleToUlong(maxNetworkBlock->ProcessItem->ProcessId)); - PhReferenceProcessRecordForStatistics(maxNetworkBlock->ProcessItem->Record); - } - else - { - PhAddItemCircularBuffer_ULONG(&EtMaxNetworkHistory, 0); - } - } - - runCount++; -} - -static VOID NTAPI EtpInvalidateNetworkNode( - _In_ PVOID Parameter - ) -{ - PPH_NETWORK_ITEM networkItem = Parameter; - PPH_NETWORK_NODE networkNode; - - if (networkNode = PhFindNetworkNode(networkItem)) - TreeNew_InvalidateNode(NetworkTreeNewHandle, &networkNode->Node); - - PhDereferenceObject(networkItem); -} - -VOID NTAPI EtEtwNetworkItemsUpdatedCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - PLIST_ENTRY listEntry; - - // ETW is flushed in the processes-updated callback above. This may cause us the network - // blocks to all fall one update interval behind, however. - - // Update per-connection statistics. - // Note: no lock is needed because we only ever modify the list on this same thread. - - listEntry = EtNetworkBlockListHead.Flink; - - while (listEntry != &EtNetworkBlockListHead) - { - PET_NETWORK_BLOCK block; - PH_UINT64_DELTA oldDeltas[4]; - - block = CONTAINING_RECORD(listEntry, ET_NETWORK_BLOCK, ListEntry); - - memcpy(oldDeltas, block->Deltas, sizeof(block->Deltas)); - - PhUpdateDelta(&block->ReceiveDelta, block->ReceiveCount); - PhUpdateDelta(&block->ReceiveRawDelta, block->ReceiveRaw); - PhUpdateDelta(&block->SendDelta, block->SendCount); - PhUpdateDelta(&block->SendRawDelta, block->SendRaw); - - if (memcmp(oldDeltas, block->Deltas, sizeof(block->Deltas))) - { - // Values have changed. Invalidate the network node. - PhReferenceObject(block->NetworkItem); - ProcessHacker_Invoke(PhMainWndHandle, EtpInvalidateNetworkNode, block->NetworkItem); - } - - listEntry = listEntry->Flink; - } -} - -VOID EtUpdateProcessInformation( - VOID - ) -{ - PhAcquireQueuedLockExclusive(&EtpProcessInformationLock); - - if (EtpProcessInformation) - { - PhFree(EtpProcessInformation); - EtpProcessInformation = NULL; - } - - PhEnumProcesses(&EtpProcessInformation); - - PhReleaseQueuedLockExclusive(&EtpProcessInformationLock); -} - -HANDLE EtThreadIdToProcessId( - _In_ HANDLE ThreadId - ) -{ - PSYSTEM_PROCESS_INFORMATION process; - ULONG i; - HANDLE processId; - - PhAcquireQueuedLockShared(&EtpProcessInformationLock); - - if (!EtpProcessInformation) - { - PhReleaseQueuedLockShared(&EtpProcessInformationLock); - return SYSTEM_PROCESS_ID; - } - - process = PH_FIRST_PROCESS(EtpProcessInformation); - - do - { - for (i = 0; i < process->NumberOfThreads; i++) - { - if (process->Threads[i].ClientId.UniqueThread == ThreadId) - { - processId = process->UniqueProcessId; - PhReleaseQueuedLockShared(&EtpProcessInformationLock); - - return processId; - } - } - } while (process = PH_NEXT_PROCESS(process)); - - PhReleaseQueuedLockShared(&EtpProcessInformationLock); - - return SYSTEM_PROCESS_ID; -} +/* + * Process Hacker Extended Tools - + * ETW statistics collection + * + * Copyright (C) 2010-2011 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include "exttools.h" +#include "etwmon.h" + +VOID NTAPI EtEtwProcessesUpdatedCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ); + +VOID NTAPI EtEtwNetworkItemsUpdatedCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ); + +static PH_CALLBACK_REGISTRATION EtpProcessesUpdatedCallbackRegistration; +static PH_CALLBACK_REGISTRATION EtpNetworkItemsUpdatedCallbackRegistration; + +ULONG EtpDiskReadRaw; +ULONG EtpDiskWriteRaw; +ULONG EtpNetworkReceiveRaw; +ULONG EtpNetworkSendRaw; + +ULONG EtDiskReadCount; +ULONG EtDiskWriteCount; +ULONG EtNetworkReceiveCount; +ULONG EtNetworkSendCount; + +PH_UINT32_DELTA EtDiskReadDelta; +PH_UINT32_DELTA EtDiskWriteDelta; +PH_UINT32_DELTA EtNetworkReceiveDelta; +PH_UINT32_DELTA EtNetworkSendDelta; + +PH_UINT32_DELTA EtDiskReadCountDelta; +PH_UINT32_DELTA EtDiskWriteCountDelta; +PH_UINT32_DELTA EtNetworkReceiveCountDelta; +PH_UINT32_DELTA EtNetworkSendCountDelta; + +PH_CIRCULAR_BUFFER_ULONG EtDiskReadHistory; +PH_CIRCULAR_BUFFER_ULONG EtDiskWriteHistory; +PH_CIRCULAR_BUFFER_ULONG EtNetworkReceiveHistory; +PH_CIRCULAR_BUFFER_ULONG EtNetworkSendHistory; +PH_CIRCULAR_BUFFER_ULONG EtMaxDiskHistory; // ID of max. disk usage process +PH_CIRCULAR_BUFFER_ULONG EtMaxNetworkHistory; // ID of max. network usage process + +PVOID EtpProcessInformation; +PH_QUEUED_LOCK EtpProcessInformationLock = PH_QUEUED_LOCK_INIT; + +VOID EtEtwStatisticsInitialization( + VOID + ) +{ + EtEtwMonitorInitialization(); + + if (EtEtwEnabled) + { + ULONG sampleCount; + + sampleCount = PhGetIntegerSetting(L"SampleCount"); + PhInitializeCircularBuffer_ULONG(&EtDiskReadHistory, sampleCount); + PhInitializeCircularBuffer_ULONG(&EtDiskWriteHistory, sampleCount); + PhInitializeCircularBuffer_ULONG(&EtNetworkReceiveHistory, sampleCount); + PhInitializeCircularBuffer_ULONG(&EtNetworkSendHistory, sampleCount); + PhInitializeCircularBuffer_ULONG(&EtMaxDiskHistory, sampleCount); + PhInitializeCircularBuffer_ULONG(&EtMaxNetworkHistory, sampleCount); + + PhRegisterCallback( + &PhProcessesUpdatedEvent, + EtEtwProcessesUpdatedCallback, + NULL, + &EtpProcessesUpdatedCallbackRegistration + ); + PhRegisterCallback( + &PhNetworkItemsUpdatedEvent, + EtEtwNetworkItemsUpdatedCallback, + NULL, + &EtpNetworkItemsUpdatedCallbackRegistration + ); + } +} + +VOID EtEtwStatisticsUninitialization( + VOID + ) +{ + EtEtwMonitorUninitialization(); +} + +VOID EtProcessDiskEvent( + _In_ PET_ETW_DISK_EVENT Event + ) +{ + PPH_PROCESS_ITEM processItem; + PET_PROCESS_BLOCK block; + + if (Event->Type == EtEtwDiskReadType) + { + EtpDiskReadRaw += Event->TransferSize; + EtDiskReadCount++; + } + else + { + EtpDiskWriteRaw += Event->TransferSize; + EtDiskWriteCount++; + } + + if (processItem = PhReferenceProcessItem(Event->ClientId.UniqueProcess)) + { + block = EtGetProcessBlock(processItem); + + if (Event->Type == EtEtwDiskReadType) + { + block->DiskReadRaw += Event->TransferSize; + block->DiskReadCount++; + } + else + { + block->DiskWriteRaw += Event->TransferSize; + block->DiskWriteCount++; + } + + PhDereferenceObject(processItem); + } +} + +VOID EtProcessNetworkEvent( + _In_ PET_ETW_NETWORK_EVENT Event + ) +{ + PPH_PROCESS_ITEM processItem; + PET_PROCESS_BLOCK block; + PPH_NETWORK_ITEM networkItem; + PET_NETWORK_BLOCK networkBlock; + + if (Event->Type == EtEtwNetworkReceiveType) + { + EtpNetworkReceiveRaw += Event->TransferSize; + EtNetworkReceiveCount++; + } + else + { + EtpNetworkSendRaw += Event->TransferSize; + EtNetworkSendCount++; + } + + // Note: there is always the possibility of us receiving the event too early, + // before the process item or network item is created. So events may be lost. + + if (processItem = PhReferenceProcessItem(Event->ClientId.UniqueProcess)) + { + block = EtGetProcessBlock(processItem); + + if (Event->Type == EtEtwNetworkReceiveType) + { + block->NetworkReceiveRaw += Event->TransferSize; + block->NetworkReceiveCount++; + } + else + { + block->NetworkSendRaw += Event->TransferSize; + block->NetworkSendCount++; + } + + PhDereferenceObject(processItem); + } + + if (networkItem = PhReferenceNetworkItem( + Event->ProtocolType, + &Event->LocalEndpoint, + &Event->RemoteEndpoint, + Event->ClientId.UniqueProcess + )) + { + networkBlock = EtGetNetworkBlock(networkItem); + + if (Event->Type == EtEtwNetworkReceiveType) + { + networkBlock->ReceiveRaw += Event->TransferSize; + networkBlock->ReceiveCount++; + } + else + { + networkBlock->SendRaw += Event->TransferSize; + networkBlock->SendCount++; + } + + PhDereferenceObject(networkItem); + } +} + +VOID NTAPI EtEtwProcessesUpdatedCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + static ULONG runCount = 0; // MUST keep in sync with runCount in process provider + + PLIST_ENTRY listEntry; + ULONG64 maxDiskValue = 0; + PET_PROCESS_BLOCK maxDiskBlock = NULL; + ULONG64 maxNetworkValue = 0; + PET_PROCESS_BLOCK maxNetworkBlock = NULL; + + // Since Windows 8, we no longer get the correct process/thread IDs in the + // event headers for disk events. We need to update our process information since + // etwmon uses our EtThreadIdToProcessId function. + if (WindowsVersion >= WINDOWS_8) + EtUpdateProcessInformation(); + + // ETW is extremely lazy when it comes to flushing buffers, so we must do it + // manually. + EtFlushEtwSession(); + + // Update global statistics. + + PhUpdateDelta(&EtDiskReadDelta, EtpDiskReadRaw); + PhUpdateDelta(&EtDiskWriteDelta, EtpDiskWriteRaw); + PhUpdateDelta(&EtNetworkReceiveDelta, EtpNetworkReceiveRaw); + PhUpdateDelta(&EtNetworkSendDelta, EtpNetworkSendRaw); + + PhUpdateDelta(&EtDiskReadCountDelta, EtDiskReadCount); + PhUpdateDelta(&EtDiskWriteCountDelta, EtDiskWriteCount); + PhUpdateDelta(&EtNetworkReceiveCountDelta, EtNetworkReceiveCount); + PhUpdateDelta(&EtNetworkSendCountDelta, EtNetworkSendCount); + + // Update per-process statistics. + // Note: no lock is needed because we only ever modify the list on this same thread. + + listEntry = EtProcessBlockListHead.Flink; + + while (listEntry != &EtProcessBlockListHead) + { + PET_PROCESS_BLOCK block; + + block = CONTAINING_RECORD(listEntry, ET_PROCESS_BLOCK, ListEntry); + + PhUpdateDelta(&block->DiskReadDelta, block->DiskReadCount); + PhUpdateDelta(&block->DiskReadRawDelta, block->DiskReadRaw); + PhUpdateDelta(&block->DiskWriteDelta, block->DiskWriteCount); + PhUpdateDelta(&block->DiskWriteRawDelta, block->DiskWriteRaw); + PhUpdateDelta(&block->NetworkReceiveDelta, block->NetworkReceiveCount); + PhUpdateDelta(&block->NetworkReceiveRawDelta, block->NetworkReceiveRaw); + PhUpdateDelta(&block->NetworkSendDelta, block->NetworkSendCount); + PhUpdateDelta(&block->NetworkSendRawDelta, block->NetworkSendRaw); + + if (maxDiskValue < block->DiskReadRawDelta.Delta + block->DiskWriteRawDelta.Delta) + { + maxDiskValue = block->DiskReadRawDelta.Delta + block->DiskWriteRawDelta.Delta; + maxDiskBlock = block; + } + + if (maxNetworkValue < block->NetworkReceiveRawDelta.Delta + block->NetworkSendRawDelta.Delta) + { + maxNetworkValue = block->NetworkReceiveRawDelta.Delta + block->NetworkSendRawDelta.Delta; + maxNetworkBlock = block; + } + + listEntry = listEntry->Flink; + } + + // Update history buffers. + + if (runCount != 0) + { + PhAddItemCircularBuffer_ULONG(&EtDiskReadHistory, EtDiskReadDelta.Delta); + PhAddItemCircularBuffer_ULONG(&EtDiskWriteHistory, EtDiskWriteDelta.Delta); + PhAddItemCircularBuffer_ULONG(&EtNetworkReceiveHistory, EtNetworkReceiveDelta.Delta); + PhAddItemCircularBuffer_ULONG(&EtNetworkSendHistory, EtNetworkSendDelta.Delta); + + if (maxDiskBlock) + { + PhAddItemCircularBuffer_ULONG(&EtMaxDiskHistory, HandleToUlong(maxDiskBlock->ProcessItem->ProcessId)); + PhReferenceProcessRecordForStatistics(maxDiskBlock->ProcessItem->Record); + } + else + { + PhAddItemCircularBuffer_ULONG(&EtMaxDiskHistory, 0); + } + + if (maxNetworkBlock) + { + PhAddItemCircularBuffer_ULONG(&EtMaxNetworkHistory, HandleToUlong(maxNetworkBlock->ProcessItem->ProcessId)); + PhReferenceProcessRecordForStatistics(maxNetworkBlock->ProcessItem->Record); + } + else + { + PhAddItemCircularBuffer_ULONG(&EtMaxNetworkHistory, 0); + } + } + + runCount++; +} + +static VOID NTAPI EtpInvalidateNetworkNode( + _In_ PVOID Parameter + ) +{ + PPH_NETWORK_ITEM networkItem = Parameter; + PPH_NETWORK_NODE networkNode; + + if (networkNode = PhFindNetworkNode(networkItem)) + TreeNew_InvalidateNode(NetworkTreeNewHandle, &networkNode->Node); + + PhDereferenceObject(networkItem); +} + +VOID NTAPI EtEtwNetworkItemsUpdatedCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + PLIST_ENTRY listEntry; + + // ETW is flushed in the processes-updated callback above. This may cause us the network + // blocks to all fall one update interval behind, however. + + // Update per-connection statistics. + // Note: no lock is needed because we only ever modify the list on this same thread. + + listEntry = EtNetworkBlockListHead.Flink; + + while (listEntry != &EtNetworkBlockListHead) + { + PET_NETWORK_BLOCK block; + PH_UINT64_DELTA oldDeltas[4]; + + block = CONTAINING_RECORD(listEntry, ET_NETWORK_BLOCK, ListEntry); + + memcpy(oldDeltas, block->Deltas, sizeof(block->Deltas)); + + PhUpdateDelta(&block->ReceiveDelta, block->ReceiveCount); + PhUpdateDelta(&block->ReceiveRawDelta, block->ReceiveRaw); + PhUpdateDelta(&block->SendDelta, block->SendCount); + PhUpdateDelta(&block->SendRawDelta, block->SendRaw); + + if (memcmp(oldDeltas, block->Deltas, sizeof(block->Deltas))) + { + // Values have changed. Invalidate the network node. + PhReferenceObject(block->NetworkItem); + ProcessHacker_Invoke(PhMainWndHandle, EtpInvalidateNetworkNode, block->NetworkItem); + } + + listEntry = listEntry->Flink; + } +} + +VOID EtUpdateProcessInformation( + VOID + ) +{ + PhAcquireQueuedLockExclusive(&EtpProcessInformationLock); + + if (EtpProcessInformation) + { + PhFree(EtpProcessInformation); + EtpProcessInformation = NULL; + } + + PhEnumProcesses(&EtpProcessInformation); + + PhReleaseQueuedLockExclusive(&EtpProcessInformationLock); +} + +HANDLE EtThreadIdToProcessId( + _In_ HANDLE ThreadId + ) +{ + PSYSTEM_PROCESS_INFORMATION process; + ULONG i; + HANDLE processId; + + PhAcquireQueuedLockShared(&EtpProcessInformationLock); + + if (!EtpProcessInformation) + { + PhReleaseQueuedLockShared(&EtpProcessInformationLock); + return SYSTEM_PROCESS_ID; + } + + process = PH_FIRST_PROCESS(EtpProcessInformation); + + do + { + for (i = 0; i < process->NumberOfThreads; i++) + { + if (process->Threads[i].ClientId.UniqueThread == ThreadId) + { + processId = process->UniqueProcessId; + PhReleaseQueuedLockShared(&EtpProcessInformationLock); + + return processId; + } + } + } while (process = PH_NEXT_PROCESS(process)); + + PhReleaseQueuedLockShared(&EtpProcessInformationLock); + + return SYSTEM_PROCESS_ID; +} diff --git a/plugins/ExtendedTools/etwsys.c b/plugins/ExtendedTools/etwsys.c index 2cc5b4b14515..dd813a88c088 100644 --- a/plugins/ExtendedTools/etwsys.c +++ b/plugins/ExtendedTools/etwsys.c @@ -1,811 +1,811 @@ -/* - * Process Hacker Extended Tools - - * ETW system information section - * - * Copyright (C) 2010-2011 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include "exttools.h" -#include "etwsys.h" - -static PPH_SYSINFO_SECTION DiskSection; -static HWND DiskDialog; -static PH_LAYOUT_MANAGER DiskLayoutManager; -static HWND DiskGraphHandle; -static PH_GRAPH_STATE DiskGraphState; -static HWND DiskPanel; - -static PPH_SYSINFO_SECTION NetworkSection; -static HWND NetworkDialog; -static PH_LAYOUT_MANAGER NetworkLayoutManager; -static HWND NetworkGraphHandle; -static PH_GRAPH_STATE NetworkGraphState; -static HWND NetworkPanel; - -VOID EtEtwSystemInformationInitializing( - _In_ PPH_PLUGIN_SYSINFO_POINTERS Pointers - ) -{ - PH_SYSINFO_SECTION section; - - memset(§ion, 0, sizeof(PH_SYSINFO_SECTION)); - PhInitializeStringRef(§ion.Name, L"Disk"); - section.Flags = 0; - section.Callback = EtpDiskSysInfoSectionCallback; - - DiskSection = Pointers->CreateSection(§ion); - - memset(§ion, 0, sizeof(PH_SYSINFO_SECTION)); - PhInitializeStringRef(§ion.Name, L"Network"); - section.Flags = 0; - section.Callback = EtpNetworkSysInfoSectionCallback; - - NetworkSection = Pointers->CreateSection(§ion); -} - -BOOLEAN EtpDiskSysInfoSectionCallback( - _In_ PPH_SYSINFO_SECTION Section, - _In_ PH_SYSINFO_SECTION_MESSAGE Message, - _In_opt_ PVOID Parameter1, - _In_opt_ PVOID Parameter2 - ) -{ - switch (Message) - { - case SysInfoDestroy: - { - if (DiskDialog) - { - PhDeleteGraphState(&DiskGraphState); - DiskDialog = NULL; - } - } - return TRUE; - case SysInfoTick: - { - if (DiskDialog) - { - EtpUpdateDiskGraph(); - EtpUpdateDiskPanel(); - } - } - return TRUE; - case SysInfoCreateDialog: - { - PPH_SYSINFO_CREATE_DIALOG createDialog = Parameter1; - - createDialog->Instance = PluginInstance->DllBase; - createDialog->Template = MAKEINTRESOURCE(IDD_SYSINFO_DISK); - createDialog->DialogProc = EtpDiskDialogProc; - } - return TRUE; - case SysInfoGraphGetDrawInfo: - { - PPH_GRAPH_DRAW_INFO drawInfo = Parameter1; - - drawInfo->Flags = PH_GRAPH_USE_GRID_X | PH_GRAPH_USE_GRID_Y | PH_GRAPH_LABEL_MAX_Y | PH_GRAPH_USE_LINE_2; - Section->Parameters->ColorSetupFunction(drawInfo, PhGetIntegerSetting(L"ColorIoReadOther"), PhGetIntegerSetting(L"ColorIoWrite")); - PhGetDrawInfoGraphBuffers(&Section->GraphState.Buffers, drawInfo, EtDiskReadHistory.Count); - - if (!Section->GraphState.Valid) - { - ULONG i; - FLOAT max = 1024 * 1024; // Minimum scaling of 1 MB - - for (i = 0; i < drawInfo->LineDataCount; i++) - { - FLOAT data1; - FLOAT data2; - - Section->GraphState.Data1[i] = data1 = - (FLOAT)PhGetItemCircularBuffer_ULONG(&EtDiskReadHistory, i); - Section->GraphState.Data2[i] = data2 = - (FLOAT)PhGetItemCircularBuffer_ULONG(&EtDiskWriteHistory, i); - - if (max < data1 + data2) - max = data1 + data2; - } - - if (max != 0) - { - // Scale the data. - - PhDivideSinglesBySingle( - Section->GraphState.Data1, - max, - drawInfo->LineDataCount - ); - PhDivideSinglesBySingle( - Section->GraphState.Data2, - max, - drawInfo->LineDataCount - ); - } - - drawInfo->LabelYFunction = PhSiSizeLabelYFunction; - drawInfo->LabelYFunctionParameter = max; - - Section->GraphState.Valid = TRUE; - } - } - return TRUE; - case SysInfoGraphGetTooltipText: - { - PPH_SYSINFO_GRAPH_GET_TOOLTIP_TEXT getTooltipText = Parameter1; - ULONG64 diskRead; - ULONG64 diskWrite; - - diskRead = PhGetItemCircularBuffer_ULONG(&EtDiskReadHistory, getTooltipText->Index); - diskWrite = PhGetItemCircularBuffer_ULONG(&EtDiskWriteHistory, getTooltipText->Index); - - PhMoveReference(&Section->GraphState.TooltipText, PhFormatString( - L"R: %s\nW: %s%s\n%s", - PhaFormatSize(diskRead, -1)->Buffer, - PhaFormatSize(diskWrite, -1)->Buffer, - PhGetStringOrEmpty(EtpGetMaxDiskString(getTooltipText->Index)), - ((PPH_STRING)PH_AUTO(PhGetStatisticsTimeString(NULL, getTooltipText->Index)))->Buffer - )); - getTooltipText->Text = Section->GraphState.TooltipText->sr; - } - return TRUE; - case SysInfoGraphDrawPanel: - { - PPH_SYSINFO_DRAW_PANEL drawPanel = Parameter1; - - drawPanel->Title = PhCreateString(L"Disk"); - drawPanel->SubTitle = PhFormatString( - L"R: %s\nW: %s", - PhaFormatSize(EtDiskReadDelta.Delta, -1)->Buffer, - PhaFormatSize(EtDiskWriteDelta.Delta, -1)->Buffer - ); - } - return TRUE; - } - - return FALSE; -} - -INT_PTR CALLBACK EtpDiskDialogProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - switch (uMsg) - { - case WM_INITDIALOG: - { - PPH_LAYOUT_ITEM graphItem; - PPH_LAYOUT_ITEM panelItem; - - PhInitializeGraphState(&DiskGraphState); - - DiskDialog = hwndDlg; - PhInitializeLayoutManager(&DiskLayoutManager, hwndDlg); - graphItem = PhAddLayoutItem(&DiskLayoutManager, GetDlgItem(hwndDlg, IDC_GRAPH_LAYOUT), NULL, PH_ANCHOR_ALL); - panelItem = PhAddLayoutItem(&DiskLayoutManager, GetDlgItem(hwndDlg, IDC_PANEL_LAYOUT), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); - - SendMessage(GetDlgItem(hwndDlg, IDC_TITLE), WM_SETFONT, (WPARAM)DiskSection->Parameters->LargeFont, FALSE); - - DiskPanel = CreateDialog(PluginInstance->DllBase, MAKEINTRESOURCE(IDD_SYSINFO_DISKPANEL), hwndDlg, EtpDiskPanelDialogProc); - ShowWindow(DiskPanel, SW_SHOW); - PhAddLayoutItemEx(&DiskLayoutManager, DiskPanel, NULL, PH_ANCHOR_LEFT | PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM, panelItem->Margin); - - DiskGraphHandle = CreateWindow( - PH_GRAPH_CLASSNAME, - NULL, - WS_VISIBLE | WS_CHILD | WS_BORDER, - 0, - 0, - 3, - 3, - hwndDlg, - NULL, - NULL, - NULL - ); - Graph_SetTooltip(DiskGraphHandle, TRUE); - - PhAddLayoutItemEx(&DiskLayoutManager, DiskGraphHandle, NULL, PH_ANCHOR_ALL, graphItem->Margin); - - EtpUpdateDiskGraph(); - EtpUpdateDiskPanel(); - } - break; - case WM_DESTROY: - { - PhDeleteLayoutManager(&DiskLayoutManager); - } - break; - case WM_SIZE: - { - PhLayoutManagerLayout(&DiskLayoutManager); - } - break; - case WM_NOTIFY: - { - NMHDR *header = (NMHDR *)lParam; - - if (header->hwndFrom == DiskGraphHandle) - { - EtpNotifyDiskGraph(header); - } - } - break; - } - - return FALSE; -} - -INT_PTR CALLBACK EtpDiskPanelDialogProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - return FALSE; -} - -VOID EtpNotifyDiskGraph( - _In_ NMHDR *Header - ) -{ - switch (Header->code) - { - case GCN_GETDRAWINFO: - { - PPH_GRAPH_GETDRAWINFO getDrawInfo = (PPH_GRAPH_GETDRAWINFO)Header; - PPH_GRAPH_DRAW_INFO drawInfo = getDrawInfo->DrawInfo; - - drawInfo->Flags = PH_GRAPH_USE_GRID_X | PH_GRAPH_USE_GRID_Y | PH_GRAPH_LABEL_MAX_Y | PH_GRAPH_USE_LINE_2; - DiskSection->Parameters->ColorSetupFunction(drawInfo, PhGetIntegerSetting(L"ColorIoReadOther"), PhGetIntegerSetting(L"ColorIoWrite")); - - PhGraphStateGetDrawInfo( - &DiskGraphState, - getDrawInfo, - EtDiskReadHistory.Count - ); - - if (!DiskGraphState.Valid) - { - ULONG i; - FLOAT max = 1024 * 1024; // Minimum scaling of 1 MB - - for (i = 0; i < drawInfo->LineDataCount; i++) - { - FLOAT data1; - FLOAT data2; - - DiskGraphState.Data1[i] = data1 = - (FLOAT)PhGetItemCircularBuffer_ULONG(&EtDiskReadHistory, i); - DiskGraphState.Data2[i] = data2 = - (FLOAT)PhGetItemCircularBuffer_ULONG(&EtDiskWriteHistory, i); - - if (max < data1 + data2) - max = data1 + data2; - } - - if (max != 0) - { - // Scale the data. - - PhDivideSinglesBySingle( - DiskGraphState.Data1, - max, - drawInfo->LineDataCount - ); - PhDivideSinglesBySingle( - DiskGraphState.Data2, - max, - drawInfo->LineDataCount - ); - } - - drawInfo->LabelYFunction = PhSiSizeLabelYFunction; - drawInfo->LabelYFunctionParameter = max; - - DiskGraphState.Valid = TRUE; - } - } - break; - case GCN_GETTOOLTIPTEXT: - { - PPH_GRAPH_GETTOOLTIPTEXT getTooltipText = (PPH_GRAPH_GETTOOLTIPTEXT)Header; - - if (getTooltipText->Index < getTooltipText->TotalCount) - { - if (DiskGraphState.TooltipIndex != getTooltipText->Index) - { - ULONG64 diskRead; - ULONG64 diskWrite; - - diskRead = PhGetItemCircularBuffer_ULONG(&EtDiskReadHistory, getTooltipText->Index); - diskWrite = PhGetItemCircularBuffer_ULONG(&EtDiskWriteHistory, getTooltipText->Index); - - PhMoveReference(&DiskGraphState.TooltipText, PhFormatString( - L"R: %s\nW: %s%s\n%s", - PhaFormatSize(diskRead, -1)->Buffer, - PhaFormatSize(diskWrite, -1)->Buffer, - PhGetStringOrEmpty(EtpGetMaxDiskString(getTooltipText->Index)), - ((PPH_STRING)PH_AUTO(PhGetStatisticsTimeString(NULL, getTooltipText->Index)))->Buffer - )); - } - - getTooltipText->Text = DiskGraphState.TooltipText->sr; - } - } - break; - case GCN_MOUSEEVENT: - { - PPH_GRAPH_MOUSEEVENT mouseEvent = (PPH_GRAPH_MOUSEEVENT)Header; - PPH_PROCESS_RECORD record; - - record = NULL; - - if (mouseEvent->Message == WM_LBUTTONDBLCLK && mouseEvent->Index < mouseEvent->TotalCount) - { - record = EtpReferenceMaxDiskRecord(mouseEvent->Index); - } - - if (record) - { - PhShowProcessRecordDialog(DiskDialog, record); - PhDereferenceProcessRecord(record); - } - } - break; - } -} - -VOID EtpUpdateDiskGraph( - VOID - ) -{ - DiskGraphState.Valid = FALSE; - DiskGraphState.TooltipIndex = -1; - Graph_MoveGrid(DiskGraphHandle, 1); - Graph_Draw(DiskGraphHandle); - Graph_UpdateTooltip(DiskGraphHandle); - InvalidateRect(DiskGraphHandle, NULL, FALSE); -} - -VOID EtpUpdateDiskPanel( - VOID - ) -{ - SetDlgItemText(DiskPanel, IDC_ZREADSDELTA_V, PhaFormatUInt64(EtDiskReadCountDelta.Delta, TRUE)->Buffer); - SetDlgItemText(DiskPanel, IDC_ZREADBYTESDELTA_V, PhaFormatSize(EtDiskReadDelta.Delta, -1)->Buffer); - SetDlgItemText(DiskPanel, IDC_ZWRITESDELTA_V, PhaFormatUInt64(EtDiskWriteCountDelta.Delta, TRUE)->Buffer); - SetDlgItemText(DiskPanel, IDC_ZWRITEBYTESDELTA_V, PhaFormatSize(EtDiskWriteDelta.Delta, -1)->Buffer); -} - -PPH_PROCESS_RECORD EtpReferenceMaxDiskRecord( - _In_ LONG Index - ) -{ - LARGE_INTEGER time; - ULONG maxProcessId; - - maxProcessId = PhGetItemCircularBuffer_ULONG(&EtMaxDiskHistory, Index); - - if (!maxProcessId) - return NULL; - - PhGetStatisticsTime(NULL, Index, &time); - time.QuadPart += PH_TICKS_PER_SEC - 1; - - return PhFindProcessRecord(UlongToHandle(maxProcessId), &time); -} - -PPH_STRING EtpGetMaxDiskString( - _In_ LONG Index - ) -{ - PPH_PROCESS_RECORD maxProcessRecord; - PPH_STRING maxUsageString = NULL; - - if (maxProcessRecord = EtpReferenceMaxDiskRecord(Index)) - { - maxUsageString = PhaFormatString( - L"\n%s (%lu)", - maxProcessRecord->ProcessName->Buffer, - HandleToUlong(maxProcessRecord->ProcessId) - ); - PhDereferenceProcessRecord(maxProcessRecord); - } - - return maxUsageString; -} - -BOOLEAN EtpNetworkSysInfoSectionCallback( - _In_ PPH_SYSINFO_SECTION Section, - _In_ PH_SYSINFO_SECTION_MESSAGE Message, - _In_opt_ PVOID Parameter1, - _In_opt_ PVOID Parameter2 - ) -{ - switch (Message) - { - case SysInfoDestroy: - { - if (NetworkDialog) - { - PhDeleteGraphState(&NetworkGraphState); - NetworkDialog = NULL; - } - } - return TRUE; - case SysInfoTick: - { - if (NetworkDialog) - { - EtpUpdateNetworkGraph(); - EtpUpdateNetworkPanel(); - } - } - return TRUE; - case SysInfoCreateDialog: - { - PPH_SYSINFO_CREATE_DIALOG createDialog = Parameter1; - - createDialog->Instance = PluginInstance->DllBase; - createDialog->Template = MAKEINTRESOURCE(IDD_SYSINFO_NET); - createDialog->DialogProc = EtpNetworkDialogProc; - } - return TRUE; - case SysInfoGraphGetDrawInfo: - { - PPH_GRAPH_DRAW_INFO drawInfo = Parameter1; - - drawInfo->Flags = PH_GRAPH_USE_GRID_X | PH_GRAPH_USE_GRID_Y | PH_GRAPH_LABEL_MAX_Y | PH_GRAPH_USE_LINE_2; - Section->Parameters->ColorSetupFunction(drawInfo, PhGetIntegerSetting(L"ColorIoReadOther"), PhGetIntegerSetting(L"ColorIoWrite")); - PhGetDrawInfoGraphBuffers(&Section->GraphState.Buffers, drawInfo, EtNetworkReceiveHistory.Count); - - if (!Section->GraphState.Valid) - { - ULONG i; - FLOAT max = 1024 * 1024; // Minimum scaling of 1 MB - - for (i = 0; i < drawInfo->LineDataCount; i++) - { - FLOAT data1; - FLOAT data2; - - Section->GraphState.Data1[i] = data1 = - (FLOAT)PhGetItemCircularBuffer_ULONG(&EtNetworkReceiveHistory, i); - Section->GraphState.Data2[i] = data2 = - (FLOAT)PhGetItemCircularBuffer_ULONG(&EtNetworkSendHistory, i); - - if (max < data1 + data2) - max = data1 + data2; - } - - if (max != 0) - { - // Scale the data. - - PhDivideSinglesBySingle( - Section->GraphState.Data1, - max, - drawInfo->LineDataCount - ); - PhDivideSinglesBySingle( - Section->GraphState.Data2, - max, - drawInfo->LineDataCount - ); - } - - drawInfo->LabelYFunction = PhSiSizeLabelYFunction; - drawInfo->LabelYFunctionParameter = max; - - Section->GraphState.Valid = TRUE; - } - } - return TRUE; - case SysInfoGraphGetTooltipText: - { - PPH_SYSINFO_GRAPH_GET_TOOLTIP_TEXT getTooltipText = Parameter1; - ULONG64 networkReceive; - ULONG64 networkSend; - - networkReceive = PhGetItemCircularBuffer_ULONG(&EtNetworkReceiveHistory, getTooltipText->Index); - networkSend = PhGetItemCircularBuffer_ULONG(&EtNetworkSendHistory, getTooltipText->Index); - - PhMoveReference(&Section->GraphState.TooltipText, PhFormatString( - L"R: %s\nS: %s%s\n%s", - PhaFormatSize(networkReceive, -1)->Buffer, - PhaFormatSize(networkSend, -1)->Buffer, - PhGetStringOrEmpty(EtpGetMaxNetworkString(getTooltipText->Index)), - ((PPH_STRING)PH_AUTO(PhGetStatisticsTimeString(NULL, getTooltipText->Index)))->Buffer - )); - getTooltipText->Text = Section->GraphState.TooltipText->sr; - } - return TRUE; - case SysInfoGraphDrawPanel: - { - PPH_SYSINFO_DRAW_PANEL drawPanel = Parameter1; - - drawPanel->Title = PhCreateString(L"Network"); - drawPanel->SubTitle = PhFormatString( - L"R: %s\nS: %s", - PhaFormatSize(EtNetworkReceiveDelta.Delta, -1)->Buffer, - PhaFormatSize(EtNetworkSendDelta.Delta, -1)->Buffer - ); - } - return TRUE; - } - - return FALSE; -} - -INT_PTR CALLBACK EtpNetworkDialogProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - switch (uMsg) - { - case WM_INITDIALOG: - { - PPH_LAYOUT_ITEM graphItem; - PPH_LAYOUT_ITEM panelItem; - - PhInitializeGraphState(&NetworkGraphState); - - NetworkDialog = hwndDlg; - PhInitializeLayoutManager(&NetworkLayoutManager, hwndDlg); - graphItem = PhAddLayoutItem(&NetworkLayoutManager, GetDlgItem(hwndDlg, IDC_GRAPH_LAYOUT), NULL, PH_ANCHOR_ALL); - panelItem = PhAddLayoutItem(&NetworkLayoutManager, GetDlgItem(hwndDlg, IDC_PANEL_LAYOUT), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); - - SendMessage(GetDlgItem(hwndDlg, IDC_TITLE), WM_SETFONT, (WPARAM)NetworkSection->Parameters->LargeFont, FALSE); - - NetworkPanel = CreateDialog(PluginInstance->DllBase, MAKEINTRESOURCE(IDD_SYSINFO_NETPANEL), hwndDlg, EtpNetworkPanelDialogProc); - ShowWindow(NetworkPanel, SW_SHOW); - PhAddLayoutItemEx(&NetworkLayoutManager, NetworkPanel, NULL, PH_ANCHOR_LEFT | PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM, panelItem->Margin); - - NetworkGraphHandle = CreateWindow( - PH_GRAPH_CLASSNAME, - NULL, - WS_VISIBLE | WS_CHILD | WS_BORDER, - 0, - 0, - 3, - 3, - hwndDlg, - NULL, - NULL, - NULL - ); - Graph_SetTooltip(NetworkGraphHandle, TRUE); - - PhAddLayoutItemEx(&NetworkLayoutManager, NetworkGraphHandle, NULL, PH_ANCHOR_ALL, graphItem->Margin); - - EtpUpdateNetworkGraph(); - EtpUpdateNetworkPanel(); - } - break; - case WM_DESTROY: - { - PhDeleteLayoutManager(&NetworkLayoutManager); - } - break; - case WM_SIZE: - { - PhLayoutManagerLayout(&NetworkLayoutManager); - } - break; - case WM_NOTIFY: - { - NMHDR *header = (NMHDR *)lParam; - - if (header->hwndFrom == NetworkGraphHandle) - { - EtpNotifyNetworkGraph(header); - } - } - break; - } - - return FALSE; -} - -INT_PTR CALLBACK EtpNetworkPanelDialogProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - return FALSE; -} - -VOID EtpNotifyNetworkGraph( - _In_ NMHDR *Header - ) -{ - switch (Header->code) - { - case GCN_GETDRAWINFO: - { - PPH_GRAPH_GETDRAWINFO getDrawInfo = (PPH_GRAPH_GETDRAWINFO)Header; - PPH_GRAPH_DRAW_INFO drawInfo = getDrawInfo->DrawInfo; - - drawInfo->Flags = PH_GRAPH_USE_GRID_X | PH_GRAPH_USE_GRID_Y | PH_GRAPH_LABEL_MAX_Y | PH_GRAPH_USE_LINE_2; - NetworkSection->Parameters->ColorSetupFunction(drawInfo, PhGetIntegerSetting(L"ColorIoReadOther"), PhGetIntegerSetting(L"ColorIoWrite")); - - PhGraphStateGetDrawInfo( - &NetworkGraphState, - getDrawInfo, - EtNetworkReceiveHistory.Count - ); - - if (!NetworkGraphState.Valid) - { - ULONG i; - FLOAT max = 1024 * 1024; // Minimum scaling of 1 MB - - for (i = 0; i < drawInfo->LineDataCount; i++) - { - FLOAT data1; - FLOAT data2; - - NetworkGraphState.Data1[i] = data1 = - (FLOAT)PhGetItemCircularBuffer_ULONG(&EtNetworkReceiveHistory, i); - NetworkGraphState.Data2[i] = data2 = - (FLOAT)PhGetItemCircularBuffer_ULONG(&EtNetworkSendHistory, i); - - if (max < data1 + data2) - max = data1 + data2; - } - - if (max != 0) - { - // Scale the data. - - PhDivideSinglesBySingle( - NetworkGraphState.Data1, - max, - drawInfo->LineDataCount - ); - PhDivideSinglesBySingle( - NetworkGraphState.Data2, - max, - drawInfo->LineDataCount - ); - } - - drawInfo->LabelYFunction = PhSiSizeLabelYFunction; - drawInfo->LabelYFunctionParameter = max; - - NetworkGraphState.Valid = TRUE; - } - } - break; - case GCN_GETTOOLTIPTEXT: - { - PPH_GRAPH_GETTOOLTIPTEXT getTooltipText = (PPH_GRAPH_GETTOOLTIPTEXT)Header; - - if (getTooltipText->Index < getTooltipText->TotalCount) - { - if (NetworkGraphState.TooltipIndex != getTooltipText->Index) - { - ULONG64 networkReceive; - ULONG64 networkSend; - - networkReceive = PhGetItemCircularBuffer_ULONG(&EtNetworkReceiveHistory, getTooltipText->Index); - networkSend = PhGetItemCircularBuffer_ULONG(&EtNetworkSendHistory, getTooltipText->Index); - - PhMoveReference(&NetworkGraphState.TooltipText, PhFormatString( - L"R: %s\nS: %s%s\n%s", - PhaFormatSize(networkReceive, -1)->Buffer, - PhaFormatSize(networkSend, -1)->Buffer, - PhGetStringOrEmpty(EtpGetMaxNetworkString(getTooltipText->Index)), - ((PPH_STRING)PH_AUTO(PhGetStatisticsTimeString(NULL, getTooltipText->Index)))->Buffer - )); - } - - getTooltipText->Text = NetworkGraphState.TooltipText->sr; - } - } - break; - case GCN_MOUSEEVENT: - { - PPH_GRAPH_MOUSEEVENT mouseEvent = (PPH_GRAPH_MOUSEEVENT)Header; - PPH_PROCESS_RECORD record; - - record = NULL; - - if (mouseEvent->Message == WM_LBUTTONDBLCLK && mouseEvent->Index < mouseEvent->TotalCount) - { - record = EtpReferenceMaxNetworkRecord(mouseEvent->Index); - } - - if (record) - { - PhShowProcessRecordDialog(NetworkDialog, record); - PhDereferenceProcessRecord(record); - } - } - break; - } -} - -VOID EtpUpdateNetworkGraph( - VOID - ) -{ - NetworkGraphState.Valid = FALSE; - NetworkGraphState.TooltipIndex = -1; - Graph_MoveGrid(NetworkGraphHandle, 1); - Graph_Draw(NetworkGraphHandle); - Graph_UpdateTooltip(NetworkGraphHandle); - InvalidateRect(NetworkGraphHandle, NULL, FALSE); -} - -VOID EtpUpdateNetworkPanel( - VOID - ) -{ - SetDlgItemText(NetworkPanel, IDC_ZRECEIVESDELTA_V, PhaFormatUInt64(EtNetworkReceiveCountDelta.Delta, TRUE)->Buffer); - SetDlgItemText(NetworkPanel, IDC_ZRECEIVEBYTESDELTA_V, PhaFormatSize(EtNetworkReceiveDelta.Delta, -1)->Buffer); - SetDlgItemText(NetworkPanel, IDC_ZSENDSDELTA_V, PhaFormatUInt64(EtNetworkSendCountDelta.Delta, TRUE)->Buffer); - SetDlgItemText(NetworkPanel, IDC_ZSENDBYTESDELTA_V, PhaFormatSize(EtNetworkSendDelta.Delta, -1)->Buffer); -} - -PPH_PROCESS_RECORD EtpReferenceMaxNetworkRecord( - _In_ LONG Index - ) -{ - LARGE_INTEGER time; - ULONG maxProcessId; - - maxProcessId = PhGetItemCircularBuffer_ULONG(&EtMaxNetworkHistory, Index); - - if (!maxProcessId) - return NULL; - - PhGetStatisticsTime(NULL, Index, &time); - time.QuadPart += PH_TICKS_PER_SEC - 1; - - return PhFindProcessRecord(UlongToHandle(maxProcessId), &time); -} - -PPH_STRING EtpGetMaxNetworkString( - _In_ LONG Index - ) -{ - PPH_PROCESS_RECORD maxProcessRecord; - PPH_STRING maxUsageString = NULL; - - if (maxProcessRecord = EtpReferenceMaxNetworkRecord(Index)) - { - maxUsageString = PhaFormatString( - L"\n%s (%lu)", - maxProcessRecord->ProcessName->Buffer, - HandleToUlong(maxProcessRecord->ProcessId) - ); - PhDereferenceProcessRecord(maxProcessRecord); - } - - return maxUsageString; -} +/* + * Process Hacker Extended Tools - + * ETW system information section + * + * Copyright (C) 2010-2011 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include "exttools.h" +#include "etwsys.h" + +static PPH_SYSINFO_SECTION DiskSection; +static HWND DiskDialog; +static PH_LAYOUT_MANAGER DiskLayoutManager; +static HWND DiskGraphHandle; +static PH_GRAPH_STATE DiskGraphState; +static HWND DiskPanel; + +static PPH_SYSINFO_SECTION NetworkSection; +static HWND NetworkDialog; +static PH_LAYOUT_MANAGER NetworkLayoutManager; +static HWND NetworkGraphHandle; +static PH_GRAPH_STATE NetworkGraphState; +static HWND NetworkPanel; + +VOID EtEtwSystemInformationInitializing( + _In_ PPH_PLUGIN_SYSINFO_POINTERS Pointers + ) +{ + PH_SYSINFO_SECTION section; + + memset(§ion, 0, sizeof(PH_SYSINFO_SECTION)); + PhInitializeStringRef(§ion.Name, L"Disk"); + section.Flags = 0; + section.Callback = EtpDiskSysInfoSectionCallback; + + DiskSection = Pointers->CreateSection(§ion); + + memset(§ion, 0, sizeof(PH_SYSINFO_SECTION)); + PhInitializeStringRef(§ion.Name, L"Network"); + section.Flags = 0; + section.Callback = EtpNetworkSysInfoSectionCallback; + + NetworkSection = Pointers->CreateSection(§ion); +} + +BOOLEAN EtpDiskSysInfoSectionCallback( + _In_ PPH_SYSINFO_SECTION Section, + _In_ PH_SYSINFO_SECTION_MESSAGE Message, + _In_opt_ PVOID Parameter1, + _In_opt_ PVOID Parameter2 + ) +{ + switch (Message) + { + case SysInfoDestroy: + { + if (DiskDialog) + { + PhDeleteGraphState(&DiskGraphState); + DiskDialog = NULL; + } + } + return TRUE; + case SysInfoTick: + { + if (DiskDialog) + { + EtpUpdateDiskGraph(); + EtpUpdateDiskPanel(); + } + } + return TRUE; + case SysInfoCreateDialog: + { + PPH_SYSINFO_CREATE_DIALOG createDialog = Parameter1; + + createDialog->Instance = PluginInstance->DllBase; + createDialog->Template = MAKEINTRESOURCE(IDD_SYSINFO_DISK); + createDialog->DialogProc = EtpDiskDialogProc; + } + return TRUE; + case SysInfoGraphGetDrawInfo: + { + PPH_GRAPH_DRAW_INFO drawInfo = Parameter1; + + drawInfo->Flags = PH_GRAPH_USE_GRID_X | PH_GRAPH_USE_GRID_Y | PH_GRAPH_LABEL_MAX_Y | PH_GRAPH_USE_LINE_2; + Section->Parameters->ColorSetupFunction(drawInfo, PhGetIntegerSetting(L"ColorIoReadOther"), PhGetIntegerSetting(L"ColorIoWrite")); + PhGetDrawInfoGraphBuffers(&Section->GraphState.Buffers, drawInfo, EtDiskReadHistory.Count); + + if (!Section->GraphState.Valid) + { + ULONG i; + FLOAT max = 1024 * 1024; // Minimum scaling of 1 MB + + for (i = 0; i < drawInfo->LineDataCount; i++) + { + FLOAT data1; + FLOAT data2; + + Section->GraphState.Data1[i] = data1 = + (FLOAT)PhGetItemCircularBuffer_ULONG(&EtDiskReadHistory, i); + Section->GraphState.Data2[i] = data2 = + (FLOAT)PhGetItemCircularBuffer_ULONG(&EtDiskWriteHistory, i); + + if (max < data1 + data2) + max = data1 + data2; + } + + if (max != 0) + { + // Scale the data. + + PhDivideSinglesBySingle( + Section->GraphState.Data1, + max, + drawInfo->LineDataCount + ); + PhDivideSinglesBySingle( + Section->GraphState.Data2, + max, + drawInfo->LineDataCount + ); + } + + drawInfo->LabelYFunction = PhSiSizeLabelYFunction; + drawInfo->LabelYFunctionParameter = max; + + Section->GraphState.Valid = TRUE; + } + } + return TRUE; + case SysInfoGraphGetTooltipText: + { + PPH_SYSINFO_GRAPH_GET_TOOLTIP_TEXT getTooltipText = Parameter1; + ULONG64 diskRead; + ULONG64 diskWrite; + + diskRead = PhGetItemCircularBuffer_ULONG(&EtDiskReadHistory, getTooltipText->Index); + diskWrite = PhGetItemCircularBuffer_ULONG(&EtDiskWriteHistory, getTooltipText->Index); + + PhMoveReference(&Section->GraphState.TooltipText, PhFormatString( + L"R: %s\nW: %s%s\n%s", + PhaFormatSize(diskRead, -1)->Buffer, + PhaFormatSize(diskWrite, -1)->Buffer, + PhGetStringOrEmpty(EtpGetMaxDiskString(getTooltipText->Index)), + ((PPH_STRING)PH_AUTO(PhGetStatisticsTimeString(NULL, getTooltipText->Index)))->Buffer + )); + getTooltipText->Text = Section->GraphState.TooltipText->sr; + } + return TRUE; + case SysInfoGraphDrawPanel: + { + PPH_SYSINFO_DRAW_PANEL drawPanel = Parameter1; + + drawPanel->Title = PhCreateString(L"Disk"); + drawPanel->SubTitle = PhFormatString( + L"R: %s\nW: %s", + PhaFormatSize(EtDiskReadDelta.Delta, -1)->Buffer, + PhaFormatSize(EtDiskWriteDelta.Delta, -1)->Buffer + ); + } + return TRUE; + } + + return FALSE; +} + +INT_PTR CALLBACK EtpDiskDialogProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + switch (uMsg) + { + case WM_INITDIALOG: + { + PPH_LAYOUT_ITEM graphItem; + PPH_LAYOUT_ITEM panelItem; + + PhInitializeGraphState(&DiskGraphState); + + DiskDialog = hwndDlg; + PhInitializeLayoutManager(&DiskLayoutManager, hwndDlg); + graphItem = PhAddLayoutItem(&DiskLayoutManager, GetDlgItem(hwndDlg, IDC_GRAPH_LAYOUT), NULL, PH_ANCHOR_ALL); + panelItem = PhAddLayoutItem(&DiskLayoutManager, GetDlgItem(hwndDlg, IDC_PANEL_LAYOUT), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); + + SendMessage(GetDlgItem(hwndDlg, IDC_TITLE), WM_SETFONT, (WPARAM)DiskSection->Parameters->LargeFont, FALSE); + + DiskPanel = CreateDialog(PluginInstance->DllBase, MAKEINTRESOURCE(IDD_SYSINFO_DISKPANEL), hwndDlg, EtpDiskPanelDialogProc); + ShowWindow(DiskPanel, SW_SHOW); + PhAddLayoutItemEx(&DiskLayoutManager, DiskPanel, NULL, PH_ANCHOR_LEFT | PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM, panelItem->Margin); + + DiskGraphHandle = CreateWindow( + PH_GRAPH_CLASSNAME, + NULL, + WS_VISIBLE | WS_CHILD | WS_BORDER, + 0, + 0, + 3, + 3, + hwndDlg, + NULL, + NULL, + NULL + ); + Graph_SetTooltip(DiskGraphHandle, TRUE); + + PhAddLayoutItemEx(&DiskLayoutManager, DiskGraphHandle, NULL, PH_ANCHOR_ALL, graphItem->Margin); + + EtpUpdateDiskGraph(); + EtpUpdateDiskPanel(); + } + break; + case WM_DESTROY: + { + PhDeleteLayoutManager(&DiskLayoutManager); + } + break; + case WM_SIZE: + { + PhLayoutManagerLayout(&DiskLayoutManager); + } + break; + case WM_NOTIFY: + { + NMHDR *header = (NMHDR *)lParam; + + if (header->hwndFrom == DiskGraphHandle) + { + EtpNotifyDiskGraph(header); + } + } + break; + } + + return FALSE; +} + +INT_PTR CALLBACK EtpDiskPanelDialogProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + return FALSE; +} + +VOID EtpNotifyDiskGraph( + _In_ NMHDR *Header + ) +{ + switch (Header->code) + { + case GCN_GETDRAWINFO: + { + PPH_GRAPH_GETDRAWINFO getDrawInfo = (PPH_GRAPH_GETDRAWINFO)Header; + PPH_GRAPH_DRAW_INFO drawInfo = getDrawInfo->DrawInfo; + + drawInfo->Flags = PH_GRAPH_USE_GRID_X | PH_GRAPH_USE_GRID_Y | PH_GRAPH_LABEL_MAX_Y | PH_GRAPH_USE_LINE_2; + DiskSection->Parameters->ColorSetupFunction(drawInfo, PhGetIntegerSetting(L"ColorIoReadOther"), PhGetIntegerSetting(L"ColorIoWrite")); + + PhGraphStateGetDrawInfo( + &DiskGraphState, + getDrawInfo, + EtDiskReadHistory.Count + ); + + if (!DiskGraphState.Valid) + { + ULONG i; + FLOAT max = 1024 * 1024; // Minimum scaling of 1 MB + + for (i = 0; i < drawInfo->LineDataCount; i++) + { + FLOAT data1; + FLOAT data2; + + DiskGraphState.Data1[i] = data1 = + (FLOAT)PhGetItemCircularBuffer_ULONG(&EtDiskReadHistory, i); + DiskGraphState.Data2[i] = data2 = + (FLOAT)PhGetItemCircularBuffer_ULONG(&EtDiskWriteHistory, i); + + if (max < data1 + data2) + max = data1 + data2; + } + + if (max != 0) + { + // Scale the data. + + PhDivideSinglesBySingle( + DiskGraphState.Data1, + max, + drawInfo->LineDataCount + ); + PhDivideSinglesBySingle( + DiskGraphState.Data2, + max, + drawInfo->LineDataCount + ); + } + + drawInfo->LabelYFunction = PhSiSizeLabelYFunction; + drawInfo->LabelYFunctionParameter = max; + + DiskGraphState.Valid = TRUE; + } + } + break; + case GCN_GETTOOLTIPTEXT: + { + PPH_GRAPH_GETTOOLTIPTEXT getTooltipText = (PPH_GRAPH_GETTOOLTIPTEXT)Header; + + if (getTooltipText->Index < getTooltipText->TotalCount) + { + if (DiskGraphState.TooltipIndex != getTooltipText->Index) + { + ULONG64 diskRead; + ULONG64 diskWrite; + + diskRead = PhGetItemCircularBuffer_ULONG(&EtDiskReadHistory, getTooltipText->Index); + diskWrite = PhGetItemCircularBuffer_ULONG(&EtDiskWriteHistory, getTooltipText->Index); + + PhMoveReference(&DiskGraphState.TooltipText, PhFormatString( + L"R: %s\nW: %s%s\n%s", + PhaFormatSize(diskRead, -1)->Buffer, + PhaFormatSize(diskWrite, -1)->Buffer, + PhGetStringOrEmpty(EtpGetMaxDiskString(getTooltipText->Index)), + ((PPH_STRING)PH_AUTO(PhGetStatisticsTimeString(NULL, getTooltipText->Index)))->Buffer + )); + } + + getTooltipText->Text = DiskGraphState.TooltipText->sr; + } + } + break; + case GCN_MOUSEEVENT: + { + PPH_GRAPH_MOUSEEVENT mouseEvent = (PPH_GRAPH_MOUSEEVENT)Header; + PPH_PROCESS_RECORD record; + + record = NULL; + + if (mouseEvent->Message == WM_LBUTTONDBLCLK && mouseEvent->Index < mouseEvent->TotalCount) + { + record = EtpReferenceMaxDiskRecord(mouseEvent->Index); + } + + if (record) + { + PhShowProcessRecordDialog(DiskDialog, record); + PhDereferenceProcessRecord(record); + } + } + break; + } +} + +VOID EtpUpdateDiskGraph( + VOID + ) +{ + DiskGraphState.Valid = FALSE; + DiskGraphState.TooltipIndex = -1; + Graph_MoveGrid(DiskGraphHandle, 1); + Graph_Draw(DiskGraphHandle); + Graph_UpdateTooltip(DiskGraphHandle); + InvalidateRect(DiskGraphHandle, NULL, FALSE); +} + +VOID EtpUpdateDiskPanel( + VOID + ) +{ + SetDlgItemText(DiskPanel, IDC_ZREADSDELTA_V, PhaFormatUInt64(EtDiskReadCountDelta.Delta, TRUE)->Buffer); + SetDlgItemText(DiskPanel, IDC_ZREADBYTESDELTA_V, PhaFormatSize(EtDiskReadDelta.Delta, -1)->Buffer); + SetDlgItemText(DiskPanel, IDC_ZWRITESDELTA_V, PhaFormatUInt64(EtDiskWriteCountDelta.Delta, TRUE)->Buffer); + SetDlgItemText(DiskPanel, IDC_ZWRITEBYTESDELTA_V, PhaFormatSize(EtDiskWriteDelta.Delta, -1)->Buffer); +} + +PPH_PROCESS_RECORD EtpReferenceMaxDiskRecord( + _In_ LONG Index + ) +{ + LARGE_INTEGER time; + ULONG maxProcessId; + + maxProcessId = PhGetItemCircularBuffer_ULONG(&EtMaxDiskHistory, Index); + + if (!maxProcessId) + return NULL; + + PhGetStatisticsTime(NULL, Index, &time); + time.QuadPart += PH_TICKS_PER_SEC - 1; + + return PhFindProcessRecord(UlongToHandle(maxProcessId), &time); +} + +PPH_STRING EtpGetMaxDiskString( + _In_ LONG Index + ) +{ + PPH_PROCESS_RECORD maxProcessRecord; + PPH_STRING maxUsageString = NULL; + + if (maxProcessRecord = EtpReferenceMaxDiskRecord(Index)) + { + maxUsageString = PhaFormatString( + L"\n%s (%lu)", + maxProcessRecord->ProcessName->Buffer, + HandleToUlong(maxProcessRecord->ProcessId) + ); + PhDereferenceProcessRecord(maxProcessRecord); + } + + return maxUsageString; +} + +BOOLEAN EtpNetworkSysInfoSectionCallback( + _In_ PPH_SYSINFO_SECTION Section, + _In_ PH_SYSINFO_SECTION_MESSAGE Message, + _In_opt_ PVOID Parameter1, + _In_opt_ PVOID Parameter2 + ) +{ + switch (Message) + { + case SysInfoDestroy: + { + if (NetworkDialog) + { + PhDeleteGraphState(&NetworkGraphState); + NetworkDialog = NULL; + } + } + return TRUE; + case SysInfoTick: + { + if (NetworkDialog) + { + EtpUpdateNetworkGraph(); + EtpUpdateNetworkPanel(); + } + } + return TRUE; + case SysInfoCreateDialog: + { + PPH_SYSINFO_CREATE_DIALOG createDialog = Parameter1; + + createDialog->Instance = PluginInstance->DllBase; + createDialog->Template = MAKEINTRESOURCE(IDD_SYSINFO_NET); + createDialog->DialogProc = EtpNetworkDialogProc; + } + return TRUE; + case SysInfoGraphGetDrawInfo: + { + PPH_GRAPH_DRAW_INFO drawInfo = Parameter1; + + drawInfo->Flags = PH_GRAPH_USE_GRID_X | PH_GRAPH_USE_GRID_Y | PH_GRAPH_LABEL_MAX_Y | PH_GRAPH_USE_LINE_2; + Section->Parameters->ColorSetupFunction(drawInfo, PhGetIntegerSetting(L"ColorIoReadOther"), PhGetIntegerSetting(L"ColorIoWrite")); + PhGetDrawInfoGraphBuffers(&Section->GraphState.Buffers, drawInfo, EtNetworkReceiveHistory.Count); + + if (!Section->GraphState.Valid) + { + ULONG i; + FLOAT max = 1024 * 1024; // Minimum scaling of 1 MB + + for (i = 0; i < drawInfo->LineDataCount; i++) + { + FLOAT data1; + FLOAT data2; + + Section->GraphState.Data1[i] = data1 = + (FLOAT)PhGetItemCircularBuffer_ULONG(&EtNetworkReceiveHistory, i); + Section->GraphState.Data2[i] = data2 = + (FLOAT)PhGetItemCircularBuffer_ULONG(&EtNetworkSendHistory, i); + + if (max < data1 + data2) + max = data1 + data2; + } + + if (max != 0) + { + // Scale the data. + + PhDivideSinglesBySingle( + Section->GraphState.Data1, + max, + drawInfo->LineDataCount + ); + PhDivideSinglesBySingle( + Section->GraphState.Data2, + max, + drawInfo->LineDataCount + ); + } + + drawInfo->LabelYFunction = PhSiSizeLabelYFunction; + drawInfo->LabelYFunctionParameter = max; + + Section->GraphState.Valid = TRUE; + } + } + return TRUE; + case SysInfoGraphGetTooltipText: + { + PPH_SYSINFO_GRAPH_GET_TOOLTIP_TEXT getTooltipText = Parameter1; + ULONG64 networkReceive; + ULONG64 networkSend; + + networkReceive = PhGetItemCircularBuffer_ULONG(&EtNetworkReceiveHistory, getTooltipText->Index); + networkSend = PhGetItemCircularBuffer_ULONG(&EtNetworkSendHistory, getTooltipText->Index); + + PhMoveReference(&Section->GraphState.TooltipText, PhFormatString( + L"R: %s\nS: %s%s\n%s", + PhaFormatSize(networkReceive, -1)->Buffer, + PhaFormatSize(networkSend, -1)->Buffer, + PhGetStringOrEmpty(EtpGetMaxNetworkString(getTooltipText->Index)), + ((PPH_STRING)PH_AUTO(PhGetStatisticsTimeString(NULL, getTooltipText->Index)))->Buffer + )); + getTooltipText->Text = Section->GraphState.TooltipText->sr; + } + return TRUE; + case SysInfoGraphDrawPanel: + { + PPH_SYSINFO_DRAW_PANEL drawPanel = Parameter1; + + drawPanel->Title = PhCreateString(L"Network"); + drawPanel->SubTitle = PhFormatString( + L"R: %s\nS: %s", + PhaFormatSize(EtNetworkReceiveDelta.Delta, -1)->Buffer, + PhaFormatSize(EtNetworkSendDelta.Delta, -1)->Buffer + ); + } + return TRUE; + } + + return FALSE; +} + +INT_PTR CALLBACK EtpNetworkDialogProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + switch (uMsg) + { + case WM_INITDIALOG: + { + PPH_LAYOUT_ITEM graphItem; + PPH_LAYOUT_ITEM panelItem; + + PhInitializeGraphState(&NetworkGraphState); + + NetworkDialog = hwndDlg; + PhInitializeLayoutManager(&NetworkLayoutManager, hwndDlg); + graphItem = PhAddLayoutItem(&NetworkLayoutManager, GetDlgItem(hwndDlg, IDC_GRAPH_LAYOUT), NULL, PH_ANCHOR_ALL); + panelItem = PhAddLayoutItem(&NetworkLayoutManager, GetDlgItem(hwndDlg, IDC_PANEL_LAYOUT), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); + + SendMessage(GetDlgItem(hwndDlg, IDC_TITLE), WM_SETFONT, (WPARAM)NetworkSection->Parameters->LargeFont, FALSE); + + NetworkPanel = CreateDialog(PluginInstance->DllBase, MAKEINTRESOURCE(IDD_SYSINFO_NETPANEL), hwndDlg, EtpNetworkPanelDialogProc); + ShowWindow(NetworkPanel, SW_SHOW); + PhAddLayoutItemEx(&NetworkLayoutManager, NetworkPanel, NULL, PH_ANCHOR_LEFT | PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM, panelItem->Margin); + + NetworkGraphHandle = CreateWindow( + PH_GRAPH_CLASSNAME, + NULL, + WS_VISIBLE | WS_CHILD | WS_BORDER, + 0, + 0, + 3, + 3, + hwndDlg, + NULL, + NULL, + NULL + ); + Graph_SetTooltip(NetworkGraphHandle, TRUE); + + PhAddLayoutItemEx(&NetworkLayoutManager, NetworkGraphHandle, NULL, PH_ANCHOR_ALL, graphItem->Margin); + + EtpUpdateNetworkGraph(); + EtpUpdateNetworkPanel(); + } + break; + case WM_DESTROY: + { + PhDeleteLayoutManager(&NetworkLayoutManager); + } + break; + case WM_SIZE: + { + PhLayoutManagerLayout(&NetworkLayoutManager); + } + break; + case WM_NOTIFY: + { + NMHDR *header = (NMHDR *)lParam; + + if (header->hwndFrom == NetworkGraphHandle) + { + EtpNotifyNetworkGraph(header); + } + } + break; + } + + return FALSE; +} + +INT_PTR CALLBACK EtpNetworkPanelDialogProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + return FALSE; +} + +VOID EtpNotifyNetworkGraph( + _In_ NMHDR *Header + ) +{ + switch (Header->code) + { + case GCN_GETDRAWINFO: + { + PPH_GRAPH_GETDRAWINFO getDrawInfo = (PPH_GRAPH_GETDRAWINFO)Header; + PPH_GRAPH_DRAW_INFO drawInfo = getDrawInfo->DrawInfo; + + drawInfo->Flags = PH_GRAPH_USE_GRID_X | PH_GRAPH_USE_GRID_Y | PH_GRAPH_LABEL_MAX_Y | PH_GRAPH_USE_LINE_2; + NetworkSection->Parameters->ColorSetupFunction(drawInfo, PhGetIntegerSetting(L"ColorIoReadOther"), PhGetIntegerSetting(L"ColorIoWrite")); + + PhGraphStateGetDrawInfo( + &NetworkGraphState, + getDrawInfo, + EtNetworkReceiveHistory.Count + ); + + if (!NetworkGraphState.Valid) + { + ULONG i; + FLOAT max = 1024 * 1024; // Minimum scaling of 1 MB + + for (i = 0; i < drawInfo->LineDataCount; i++) + { + FLOAT data1; + FLOAT data2; + + NetworkGraphState.Data1[i] = data1 = + (FLOAT)PhGetItemCircularBuffer_ULONG(&EtNetworkReceiveHistory, i); + NetworkGraphState.Data2[i] = data2 = + (FLOAT)PhGetItemCircularBuffer_ULONG(&EtNetworkSendHistory, i); + + if (max < data1 + data2) + max = data1 + data2; + } + + if (max != 0) + { + // Scale the data. + + PhDivideSinglesBySingle( + NetworkGraphState.Data1, + max, + drawInfo->LineDataCount + ); + PhDivideSinglesBySingle( + NetworkGraphState.Data2, + max, + drawInfo->LineDataCount + ); + } + + drawInfo->LabelYFunction = PhSiSizeLabelYFunction; + drawInfo->LabelYFunctionParameter = max; + + NetworkGraphState.Valid = TRUE; + } + } + break; + case GCN_GETTOOLTIPTEXT: + { + PPH_GRAPH_GETTOOLTIPTEXT getTooltipText = (PPH_GRAPH_GETTOOLTIPTEXT)Header; + + if (getTooltipText->Index < getTooltipText->TotalCount) + { + if (NetworkGraphState.TooltipIndex != getTooltipText->Index) + { + ULONG64 networkReceive; + ULONG64 networkSend; + + networkReceive = PhGetItemCircularBuffer_ULONG(&EtNetworkReceiveHistory, getTooltipText->Index); + networkSend = PhGetItemCircularBuffer_ULONG(&EtNetworkSendHistory, getTooltipText->Index); + + PhMoveReference(&NetworkGraphState.TooltipText, PhFormatString( + L"R: %s\nS: %s%s\n%s", + PhaFormatSize(networkReceive, -1)->Buffer, + PhaFormatSize(networkSend, -1)->Buffer, + PhGetStringOrEmpty(EtpGetMaxNetworkString(getTooltipText->Index)), + ((PPH_STRING)PH_AUTO(PhGetStatisticsTimeString(NULL, getTooltipText->Index)))->Buffer + )); + } + + getTooltipText->Text = NetworkGraphState.TooltipText->sr; + } + } + break; + case GCN_MOUSEEVENT: + { + PPH_GRAPH_MOUSEEVENT mouseEvent = (PPH_GRAPH_MOUSEEVENT)Header; + PPH_PROCESS_RECORD record; + + record = NULL; + + if (mouseEvent->Message == WM_LBUTTONDBLCLK && mouseEvent->Index < mouseEvent->TotalCount) + { + record = EtpReferenceMaxNetworkRecord(mouseEvent->Index); + } + + if (record) + { + PhShowProcessRecordDialog(NetworkDialog, record); + PhDereferenceProcessRecord(record); + } + } + break; + } +} + +VOID EtpUpdateNetworkGraph( + VOID + ) +{ + NetworkGraphState.Valid = FALSE; + NetworkGraphState.TooltipIndex = -1; + Graph_MoveGrid(NetworkGraphHandle, 1); + Graph_Draw(NetworkGraphHandle); + Graph_UpdateTooltip(NetworkGraphHandle); + InvalidateRect(NetworkGraphHandle, NULL, FALSE); +} + +VOID EtpUpdateNetworkPanel( + VOID + ) +{ + SetDlgItemText(NetworkPanel, IDC_ZRECEIVESDELTA_V, PhaFormatUInt64(EtNetworkReceiveCountDelta.Delta, TRUE)->Buffer); + SetDlgItemText(NetworkPanel, IDC_ZRECEIVEBYTESDELTA_V, PhaFormatSize(EtNetworkReceiveDelta.Delta, -1)->Buffer); + SetDlgItemText(NetworkPanel, IDC_ZSENDSDELTA_V, PhaFormatUInt64(EtNetworkSendCountDelta.Delta, TRUE)->Buffer); + SetDlgItemText(NetworkPanel, IDC_ZSENDBYTESDELTA_V, PhaFormatSize(EtNetworkSendDelta.Delta, -1)->Buffer); +} + +PPH_PROCESS_RECORD EtpReferenceMaxNetworkRecord( + _In_ LONG Index + ) +{ + LARGE_INTEGER time; + ULONG maxProcessId; + + maxProcessId = PhGetItemCircularBuffer_ULONG(&EtMaxNetworkHistory, Index); + + if (!maxProcessId) + return NULL; + + PhGetStatisticsTime(NULL, Index, &time); + time.QuadPart += PH_TICKS_PER_SEC - 1; + + return PhFindProcessRecord(UlongToHandle(maxProcessId), &time); +} + +PPH_STRING EtpGetMaxNetworkString( + _In_ LONG Index + ) +{ + PPH_PROCESS_RECORD maxProcessRecord; + PPH_STRING maxUsageString = NULL; + + if (maxProcessRecord = EtpReferenceMaxNetworkRecord(Index)) + { + maxUsageString = PhaFormatString( + L"\n%s (%lu)", + maxProcessRecord->ProcessName->Buffer, + HandleToUlong(maxProcessRecord->ProcessId) + ); + PhDereferenceProcessRecord(maxProcessRecord); + } + + return maxUsageString; +} diff --git a/plugins/ExtendedTools/etwsys.h b/plugins/ExtendedTools/etwsys.h index f8d53024baa0..b33ac171d018 100644 --- a/plugins/ExtendedTools/etwsys.h +++ b/plugins/ExtendedTools/etwsys.h @@ -1,90 +1,90 @@ -#ifndef ETWSYS_H -#define ETWSYS_H - -// Disk section - -BOOLEAN EtpDiskSysInfoSectionCallback( - _In_ PPH_SYSINFO_SECTION Section, - _In_ PH_SYSINFO_SECTION_MESSAGE Message, - _In_opt_ PVOID Parameter1, - _In_opt_ PVOID Parameter2 - ); - -INT_PTR CALLBACK EtpDiskDialogProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -INT_PTR CALLBACK EtpDiskPanelDialogProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -VOID EtpNotifyDiskGraph( - _In_ NMHDR *Header - ); - -VOID EtpUpdateDiskGraph( - VOID - ); - -VOID EtpUpdateDiskPanel( - VOID - ); - -PPH_PROCESS_RECORD EtpReferenceMaxDiskRecord( - _In_ LONG Index - ); - -PPH_STRING EtpGetMaxDiskString( - _In_ LONG Index - ); - -// Network section - -BOOLEAN EtpNetworkSysInfoSectionCallback( - _In_ PPH_SYSINFO_SECTION Section, - _In_ PH_SYSINFO_SECTION_MESSAGE Message, - _In_opt_ PVOID Parameter1, - _In_opt_ PVOID Parameter2 - ); - -INT_PTR CALLBACK EtpNetworkDialogProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -INT_PTR CALLBACK EtpNetworkPanelDialogProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -VOID EtpNotifyNetworkGraph( - _In_ NMHDR *Header - ); - -VOID EtpUpdateNetworkGraph( - VOID - ); - -VOID EtpUpdateNetworkPanel( - VOID - ); - -PPH_PROCESS_RECORD EtpReferenceMaxNetworkRecord( - _In_ LONG Index - ); - -PPH_STRING EtpGetMaxNetworkString( - _In_ LONG Index - ); - -#endif +#ifndef ETWSYS_H +#define ETWSYS_H + +// Disk section + +BOOLEAN EtpDiskSysInfoSectionCallback( + _In_ PPH_SYSINFO_SECTION Section, + _In_ PH_SYSINFO_SECTION_MESSAGE Message, + _In_opt_ PVOID Parameter1, + _In_opt_ PVOID Parameter2 + ); + +INT_PTR CALLBACK EtpDiskDialogProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +INT_PTR CALLBACK EtpDiskPanelDialogProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +VOID EtpNotifyDiskGraph( + _In_ NMHDR *Header + ); + +VOID EtpUpdateDiskGraph( + VOID + ); + +VOID EtpUpdateDiskPanel( + VOID + ); + +PPH_PROCESS_RECORD EtpReferenceMaxDiskRecord( + _In_ LONG Index + ); + +PPH_STRING EtpGetMaxDiskString( + _In_ LONG Index + ); + +// Network section + +BOOLEAN EtpNetworkSysInfoSectionCallback( + _In_ PPH_SYSINFO_SECTION Section, + _In_ PH_SYSINFO_SECTION_MESSAGE Message, + _In_opt_ PVOID Parameter1, + _In_opt_ PVOID Parameter2 + ); + +INT_PTR CALLBACK EtpNetworkDialogProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +INT_PTR CALLBACK EtpNetworkPanelDialogProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +VOID EtpNotifyNetworkGraph( + _In_ NMHDR *Header + ); + +VOID EtpUpdateNetworkGraph( + VOID + ); + +VOID EtpUpdateNetworkPanel( + VOID + ); + +PPH_PROCESS_RECORD EtpReferenceMaxNetworkRecord( + _In_ LONG Index + ); + +PPH_STRING EtpGetMaxNetworkString( + _In_ LONG Index + ); + +#endif diff --git a/plugins/ExtendedTools/exttools.h b/plugins/ExtendedTools/exttools.h index ceacc3710c80..e76d42f99688 100644 --- a/plugins/ExtendedTools/exttools.h +++ b/plugins/ExtendedTools/exttools.h @@ -1,549 +1,549 @@ -#ifndef EXTTOOLS_H -#define EXTTOOLS_H - -#include -#include -#include - -#include "resource.h" - -extern PPH_PLUGIN PluginInstance; -extern LIST_ENTRY EtProcessBlockListHead; -extern LIST_ENTRY EtNetworkBlockListHead; -extern HWND ProcessTreeNewHandle; -extern HWND NetworkTreeNewHandle; - -#define PLUGIN_NAME L"ProcessHacker.ExtendedTools" -#define SETTING_NAME_DISK_TREE_LIST_COLUMNS (PLUGIN_NAME L".DiskTreeListColumns") -#define SETTING_NAME_DISK_TREE_LIST_SORT (PLUGIN_NAME L".DiskTreeListSort") -#define SETTING_NAME_ENABLE_ETW_MONITOR (PLUGIN_NAME L".EnableEtwMonitor") -#define SETTING_NAME_ENABLE_GPU_MONITOR (PLUGIN_NAME L".EnableGpuMonitor") -#define SETTING_NAME_ENABLE_SYSINFO_GRAPHS (PLUGIN_NAME L".EnableSysInfoGraphs") -#define SETTING_NAME_GPU_NODE_BITMAP (PLUGIN_NAME L".GpuNodeBitmap") -#define SETTING_NAME_GPU_LAST_NODE_COUNT (PLUGIN_NAME L".GpuLastNodeCount") - -#define ET_SCALE_DPI(Value) PhMultiplyDivide(Value, PhGlobalDpi, 96) - -// Graph update message - -#define UPDATE_MSG (WM_APP + 1) - -// Process icon - -typedef struct _ET_PROCESS_ICON -{ - LONG RefCount; - HICON Icon; -} ET_PROCESS_ICON, *PET_PROCESS_ICON; - -// Disk item - -#define HISTORY_SIZE 60 - -typedef struct _ET_DISK_ITEM -{ - LIST_ENTRY AgeListEntry; - ULONG AddTime; - ULONG FreshTime; - - HANDLE ProcessId; - PPH_STRING FileName; - PPH_STRING FileNameWin32; - - PPH_STRING ProcessName; - PET_PROCESS_ICON ProcessIcon; - PPH_PROCESS_RECORD ProcessRecord; - - ULONG IoPriority; - ULONG ResponseTimeCount; - FLOAT ResponseTimeTotal; // in milliseconds - FLOAT ResponseTimeAverage; - - ULONG64 ReadTotal; - ULONG64 WriteTotal; - ULONG64 ReadDelta; - ULONG64 WriteDelta; - ULONG64 ReadAverage; - ULONG64 WriteAverage; - - ULONG64 ReadHistory[HISTORY_SIZE]; - ULONG64 WriteHistory[HISTORY_SIZE]; - ULONG HistoryCount; - ULONG HistoryPosition; -} ET_DISK_ITEM, *PET_DISK_ITEM; - -// Disk node - -#define ETDSTNC_NAME 0 -#define ETDSTNC_FILE 1 -#define ETDSTNC_READRATEAVERAGE 2 -#define ETDSTNC_WRITERATEAVERAGE 3 -#define ETDSTNC_TOTALRATEAVERAGE 4 -#define ETDSTNC_IOPRIORITY 5 -#define ETDSTNC_RESPONSETIME 6 -#define ETDSTNC_MAXIMUM 7 - -typedef struct _ET_DISK_NODE -{ - PH_TREENEW_NODE Node; - - PET_DISK_ITEM DiskItem; - - PH_STRINGREF TextCache[ETDSTNC_MAXIMUM]; - - PPH_STRING ProcessNameText; - PPH_STRING ReadRateAverageText; - PPH_STRING WriteRateAverageText; - PPH_STRING TotalRateAverageText; - PPH_STRING ResponseTimeText; - - PPH_STRING TooltipText; -} ET_DISK_NODE, *PET_DISK_NODE; - -// Process tree columns - -#define ETPRTNC_DISKREADS 1 -#define ETPRTNC_DISKWRITES 2 -#define ETPRTNC_DISKREADBYTES 3 -#define ETPRTNC_DISKWRITEBYTES 4 -#define ETPRTNC_DISKTOTALBYTES 5 -#define ETPRTNC_DISKREADSDELTA 6 -#define ETPRTNC_DISKWRITESDELTA 7 -#define ETPRTNC_DISKREADBYTESDELTA 8 -#define ETPRTNC_DISKWRITEBYTESDELTA 9 -#define ETPRTNC_DISKTOTALBYTESDELTA 10 -#define ETPRTNC_NETWORKRECEIVES 11 -#define ETPRTNC_NETWORKSENDS 12 -#define ETPRTNC_NETWORKRECEIVEBYTES 13 -#define ETPRTNC_NETWORKSENDBYTES 14 -#define ETPRTNC_NETWORKTOTALBYTES 15 -#define ETPRTNC_NETWORKRECEIVESDELTA 16 -#define ETPRTNC_NETWORKSENDSDELTA 17 -#define ETPRTNC_NETWORKRECEIVEBYTESDELTA 18 -#define ETPRTNC_NETWORKSENDBYTESDELTA 19 -#define ETPRTNC_NETWORKTOTALBYTESDELTA 20 -#define ETPRTNC_HARDFAULTS 21 -#define ETPRTNC_HARDFAULTSDELTA 22 -#define ETPRTNC_PEAKTHREADS 23 -#define ETPRTNC_GPU 24 -#define ETPRTNC_GPUDEDICATEDBYTES 25 -#define ETPRTNC_GPUSHAREDBYTES 26 -#define ETPRTNC_DISKREADRATE 27 -#define ETPRTNC_DISKWRITERATE 28 -#define ETPRTNC_DISKTOTALRATE 29 -#define ETPRTNC_NETWORKRECEIVERATE 30 -#define ETPRTNC_NETWORKSENDRATE 31 -#define ETPRTNC_NETWORKTOTALRATE 32 -#define ETPRTNC_MAXIMUM 32 - -// Network list columns - -#define ETNETNC_RECEIVES 1 -#define ETNETNC_SENDS 2 -#define ETNETNC_RECEIVEBYTES 3 -#define ETNETNC_SENDBYTES 4 -#define ETNETNC_TOTALBYTES 5 -#define ETNETNC_RECEIVESDELTA 6 -#define ETNETNC_SENDSDELTA 7 -#define ETNETNC_RECEIVEBYTESDELTA 8 -#define ETNETNC_SENDBYTESDELTA 9 -#define ETNETNC_TOTALBYTESDELTA 10 -#define ETNETNC_FIREWALLSTATUS 11 -#define ETNETNC_RECEIVERATE 12 -#define ETNETNC_SENDRATE 13 -#define ETNETNC_TOTALRATE 14 -#define ETNETNC_MAXIMUM 14 - -// Firewall status - -typedef enum _ET_FIREWALL_STATUS -{ - FirewallUnknownStatus, - FirewallAllowedNotRestricted, - FirewallAllowedRestricted, - FirewallNotAllowedNotRestricted, - FirewallNotAllowedRestricted, - FirewallMaximumStatus -} ET_FIREWALL_STATUS; - -// Object extensions - -typedef struct _ET_PROCESS_BLOCK -{ - LIST_ENTRY ListEntry; - PPH_PROCESS_ITEM ProcessItem; - - ULONG64 DiskReadCount; - ULONG64 DiskWriteCount; - ULONG64 NetworkReceiveCount; - ULONG64 NetworkSendCount; - - ULONG64 DiskReadRaw; - ULONG64 DiskWriteRaw; - ULONG64 NetworkReceiveRaw; - ULONG64 NetworkSendRaw; - - PH_UINT64_DELTA DiskReadDelta; - PH_UINT64_DELTA DiskReadRawDelta; - PH_UINT64_DELTA DiskWriteDelta; - PH_UINT64_DELTA DiskWriteRawDelta; - PH_UINT64_DELTA NetworkReceiveDelta; - PH_UINT64_DELTA NetworkReceiveRawDelta; - PH_UINT64_DELTA NetworkSendDelta; - PH_UINT64_DELTA NetworkSendRawDelta; - - PH_UINT64_DELTA GpuRunningTimeDelta; - FLOAT GpuNodeUsage; - ULONG64 GpuDedicatedUsage; - ULONG64 GpuSharedUsage; - - PH_UINT32_DELTA HardFaultsDelta; - - PH_QUEUED_LOCK TextCacheLock; - PPH_STRING TextCache[ETPRTNC_MAXIMUM + 1]; - BOOLEAN TextCacheValid[ETPRTNC_MAXIMUM + 1]; - - PET_PROCESS_ICON SmallProcessIcon; -} ET_PROCESS_BLOCK, *PET_PROCESS_BLOCK; - -typedef struct _ET_NETWORK_BLOCK -{ - LIST_ENTRY ListEntry; - PPH_NETWORK_ITEM NetworkItem; - - ULONG64 ReceiveCount; - ULONG64 SendCount; - ULONG64 ReceiveRaw; - ULONG64 SendRaw; - - union - { - struct - { - PH_UINT64_DELTA ReceiveDelta; - PH_UINT64_DELTA ReceiveRawDelta; - PH_UINT64_DELTA SendDelta; - PH_UINT64_DELTA SendRawDelta; - }; - PH_UINT64_DELTA Deltas[4]; - }; - - ET_FIREWALL_STATUS FirewallStatus; - BOOLEAN FirewallStatusValid; - - PH_QUEUED_LOCK TextCacheLock; - PPH_STRING TextCache[ETNETNC_MAXIMUM + 1]; - BOOLEAN TextCacheValid[ETNETNC_MAXIMUM + 1]; -} ET_NETWORK_BLOCK, *PET_NETWORK_BLOCK; - -// main - -PET_PROCESS_BLOCK EtGetProcessBlock( - _In_ PPH_PROCESS_ITEM ProcessItem - ); - -PET_NETWORK_BLOCK EtGetNetworkBlock( - _In_ PPH_NETWORK_ITEM NetworkItem - ); - -// utils - -VOID EtFormatRate( - _In_ ULONG64 ValuePerPeriod, - _Inout_ PPH_STRING *Buffer, - _Out_opt_ PPH_STRINGREF String - ); - -// etwmon - -extern BOOLEAN EtEtwEnabled; - -// etwstat - -extern ULONG EtDiskReadCount; -extern ULONG EtDiskWriteCount; -extern ULONG EtNetworkReceiveCount; -extern ULONG EtNetworkSendCount; - -extern PH_UINT32_DELTA EtDiskReadDelta; -extern PH_UINT32_DELTA EtDiskWriteDelta; -extern PH_UINT32_DELTA EtNetworkReceiveDelta; -extern PH_UINT32_DELTA EtNetworkSendDelta; - -extern PH_UINT32_DELTA EtDiskReadCountDelta; -extern PH_UINT32_DELTA EtDiskWriteCountDelta; -extern PH_UINT32_DELTA EtNetworkReceiveCountDelta; -extern PH_UINT32_DELTA EtNetworkSendCountDelta; - -extern PH_CIRCULAR_BUFFER_ULONG EtDiskReadHistory; -extern PH_CIRCULAR_BUFFER_ULONG EtDiskWriteHistory; -extern PH_CIRCULAR_BUFFER_ULONG EtNetworkReceiveHistory; -extern PH_CIRCULAR_BUFFER_ULONG EtNetworkSendHistory; -extern PH_CIRCULAR_BUFFER_ULONG EtMaxDiskHistory; -extern PH_CIRCULAR_BUFFER_ULONG EtMaxNetworkHistory; - -VOID EtEtwStatisticsInitialization( - VOID - ); - -VOID EtEtwStatisticsUninitialization( - VOID - ); - -// etwdisk - -extern BOOLEAN EtDiskEnabled; - -extern PPH_OBJECT_TYPE EtDiskItemType; -extern PH_CALLBACK EtDiskItemAddedEvent; -extern PH_CALLBACK EtDiskItemModifiedEvent; -extern PH_CALLBACK EtDiskItemRemovedEvent; -extern PH_CALLBACK EtDiskItemsUpdatedEvent; - -VOID EtInitializeDiskInformation( - VOID - ); - -PET_DISK_ITEM EtCreateDiskItem( - VOID - ); - -PET_DISK_ITEM EtReferenceDiskItem( - _In_ HANDLE ProcessId, - _In_ PPH_STRING FileName - ); - -PPH_STRING EtFileObjectToFileName( - _In_ PVOID FileObject - ); - -// procicon - -PET_PROCESS_ICON EtProcIconCreateProcessIcon( - _In_ HICON Icon - ); - -VOID EtProcIconReferenceProcessIcon( - _Inout_ PET_PROCESS_ICON ProcessIcon - ); - -VOID EtProcIconDereferenceProcessIcon( - _Inout_ PET_PROCESS_ICON ProcessIcon - ); - -PET_PROCESS_ICON EtProcIconReferenceSmallProcessIcon( - _Inout_ PET_PROCESS_BLOCK Block - ); - -VOID EtProcIconNotifyProcessDelete( - _Inout_ PET_PROCESS_BLOCK Block - ); - -// etwprprp - -VOID EtProcessEtwPropertiesInitializing( - _In_ PVOID Parameter - ); - -// disktab - -VOID EtInitializeDiskTab( - VOID - ); - -VOID EtLoadSettingsDiskTreeList( - VOID - ); - -VOID EtSaveSettingsDiskTreeList( - VOID - ); - -// gpumon - -extern BOOLEAN EtGpuEnabled; - -extern ULONG EtGpuTotalNodeCount; -extern ULONG EtGpuTotalSegmentCount; -extern ULONG64 EtGpuDedicatedLimit; -extern ULONG64 EtGpuSharedLimit; -extern RTL_BITMAP EtGpuNodeBitMap; - -extern PH_UINT64_DELTA EtClockTotalRunningTimeDelta; -extern LARGE_INTEGER EtClockTotalRunningTimeFrequency; -extern PH_UINT64_DELTA EtGpuTotalRunningTimeDelta; -extern PH_UINT64_DELTA EtGpuSystemRunningTimeDelta; -extern FLOAT EtGpuNodeUsage; -extern PH_CIRCULAR_BUFFER_FLOAT EtGpuNodeHistory; -extern PH_CIRCULAR_BUFFER_ULONG EtMaxGpuNodeHistory; // ID of max. GPU usage process -extern PH_CIRCULAR_BUFFER_FLOAT EtMaxGpuNodeUsageHistory; - -extern PPH_UINT64_DELTA EtGpuNodesTotalRunningTimeDelta; -extern PPH_CIRCULAR_BUFFER_FLOAT EtGpuNodesHistory; - -extern ULONG64 EtGpuDedicatedUsage; -extern ULONG64 EtGpuSharedUsage; -extern PH_CIRCULAR_BUFFER_ULONG EtGpuDedicatedHistory; -extern PH_CIRCULAR_BUFFER_ULONG EtGpuSharedHistory; - -VOID EtGpuMonitorInitialization( - VOID - ); - -typedef struct _ET_PROCESS_GPU_STATISTICS -{ - ULONG SegmentCount; - ULONG NodeCount; - - ULONG64 DedicatedCommitted; - ULONG64 SharedCommitted; - - ULONG64 BytesAllocated; - ULONG64 BytesReserved; - ULONG64 WriteCombinedBytesAllocated; - ULONG64 WriteCombinedBytesReserved; - ULONG64 CachedBytesAllocated; - ULONG64 CachedBytesReserved; - ULONG64 SectionBytesAllocated; - ULONG64 SectionBytesReserved; - - ULONG64 RunningTime; - ULONG64 ContextSwitches; -} ET_PROCESS_GPU_STATISTICS, *PET_PROCESS_GPU_STATISTICS; - -VOID EtSaveGpuMonitorSettings( - VOID - ); - -ULONG EtGetGpuAdapterCount( - VOID - ); - -ULONG EtGetGpuAdapterIndexFromNodeIndex( - _In_ ULONG NodeIndex - ); - -PPH_STRING EtGetGpuAdapterDescription( - _In_ ULONG Index - ); - -VOID EtAllocateGpuNodeBitMap( - _Out_ PRTL_BITMAP BitMap - ); - -VOID EtUpdateGpuNodeBitMap( - _In_ PRTL_BITMAP NewBitMap - ); - -VOID EtQueryProcessGpuStatistics( - _In_ HANDLE ProcessHandle, - _Out_ PET_PROCESS_GPU_STATISTICS Statistics - ); - -// gpuprprp - -VOID EtProcessGpuPropertiesInitializing( - _In_ PVOID Parameter - ); - -// treeext - -VOID EtProcessTreeNewInitializing( - _In_ PVOID Parameter - ); - -VOID EtProcessTreeNewMessage( - _In_ PVOID Parameter - ); - -VOID EtNetworkTreeNewInitializing( - _In_ PVOID Parameter - ); - -VOID EtNetworkTreeNewMessage( - _In_ PVOID Parameter - ); - -ET_FIREWALL_STATUS EtQueryFirewallStatus( - _In_ PPH_NETWORK_ITEM NetworkItem - ); - -// etwsys - -VOID EtEtwSystemInformationInitializing( - _In_ PPH_PLUGIN_SYSINFO_POINTERS Pointers - ); - -// etwmini - -VOID EtEtwMiniInformationInitializing( - _In_ PPH_PLUGIN_MINIINFO_POINTERS Pointers - ); - -// gpunodes - -VOID EtShowGpuNodesDialog( - _In_ HWND ParentWindowHandle, - _In_ PPH_SYSINFO_PARAMETERS Parameters - ); - -// gpusys - -VOID EtGpuSystemInformationInitializing( - _In_ PPH_PLUGIN_SYSINFO_POINTERS Pointers - ); - -// gpumini - -VOID EtGpuMiniInformationInitializing( - _In_ PPH_PLUGIN_MINIINFO_POINTERS Pointers - ); - -// iconext - -VOID EtRegisterNotifyIcons( - VOID - ); - -// modsrv - -VOID EtShowModuleServicesDialog( - _In_ HWND ParentWindowHandle, - _In_ HANDLE ProcessId, - _In_ PWSTR ModuleName - ); - -// objprp - -VOID EtHandlePropertiesInitializing( - _In_ PVOID Parameter - ); - -// options - -VOID EtShowOptionsDialog( - _In_ HWND ParentWindowHandle - ); - -// thrdact - -BOOLEAN EtUiCancelIoThread( - _In_ HWND hWnd, - _In_ PPH_THREAD_ITEM Thread - ); - -// unldll - -VOID EtShowUnloadedDllsDialog( - _In_ HWND ParentWindowHandle, - _In_ PPH_PROCESS_ITEM ProcessItem - ); - -// wswatch - -VOID EtShowWsWatchDialog( - _In_ HWND ParentWindowHandle, - _In_ PPH_PROCESS_ITEM ProcessItem - ); - -#endif +#ifndef EXTTOOLS_H +#define EXTTOOLS_H + +#include +#include +#include + +#include "resource.h" + +extern PPH_PLUGIN PluginInstance; +extern LIST_ENTRY EtProcessBlockListHead; +extern LIST_ENTRY EtNetworkBlockListHead; +extern HWND ProcessTreeNewHandle; +extern HWND NetworkTreeNewHandle; + +#define PLUGIN_NAME L"ProcessHacker.ExtendedTools" +#define SETTING_NAME_DISK_TREE_LIST_COLUMNS (PLUGIN_NAME L".DiskTreeListColumns") +#define SETTING_NAME_DISK_TREE_LIST_SORT (PLUGIN_NAME L".DiskTreeListSort") +#define SETTING_NAME_ENABLE_ETW_MONITOR (PLUGIN_NAME L".EnableEtwMonitor") +#define SETTING_NAME_ENABLE_GPU_MONITOR (PLUGIN_NAME L".EnableGpuMonitor") +#define SETTING_NAME_ENABLE_SYSINFO_GRAPHS (PLUGIN_NAME L".EnableSysInfoGraphs") +#define SETTING_NAME_GPU_NODE_BITMAP (PLUGIN_NAME L".GpuNodeBitmap") +#define SETTING_NAME_GPU_LAST_NODE_COUNT (PLUGIN_NAME L".GpuLastNodeCount") + +#define ET_SCALE_DPI(Value) PhMultiplyDivide(Value, PhGlobalDpi, 96) + +// Graph update message + +#define UPDATE_MSG (WM_APP + 1) + +// Process icon + +typedef struct _ET_PROCESS_ICON +{ + LONG RefCount; + HICON Icon; +} ET_PROCESS_ICON, *PET_PROCESS_ICON; + +// Disk item + +#define HISTORY_SIZE 60 + +typedef struct _ET_DISK_ITEM +{ + LIST_ENTRY AgeListEntry; + ULONG AddTime; + ULONG FreshTime; + + HANDLE ProcessId; + PPH_STRING FileName; + PPH_STRING FileNameWin32; + + PPH_STRING ProcessName; + PET_PROCESS_ICON ProcessIcon; + PPH_PROCESS_RECORD ProcessRecord; + + ULONG IoPriority; + ULONG ResponseTimeCount; + FLOAT ResponseTimeTotal; // in milliseconds + FLOAT ResponseTimeAverage; + + ULONG64 ReadTotal; + ULONG64 WriteTotal; + ULONG64 ReadDelta; + ULONG64 WriteDelta; + ULONG64 ReadAverage; + ULONG64 WriteAverage; + + ULONG64 ReadHistory[HISTORY_SIZE]; + ULONG64 WriteHistory[HISTORY_SIZE]; + ULONG HistoryCount; + ULONG HistoryPosition; +} ET_DISK_ITEM, *PET_DISK_ITEM; + +// Disk node + +#define ETDSTNC_NAME 0 +#define ETDSTNC_FILE 1 +#define ETDSTNC_READRATEAVERAGE 2 +#define ETDSTNC_WRITERATEAVERAGE 3 +#define ETDSTNC_TOTALRATEAVERAGE 4 +#define ETDSTNC_IOPRIORITY 5 +#define ETDSTNC_RESPONSETIME 6 +#define ETDSTNC_MAXIMUM 7 + +typedef struct _ET_DISK_NODE +{ + PH_TREENEW_NODE Node; + + PET_DISK_ITEM DiskItem; + + PH_STRINGREF TextCache[ETDSTNC_MAXIMUM]; + + PPH_STRING ProcessNameText; + PPH_STRING ReadRateAverageText; + PPH_STRING WriteRateAverageText; + PPH_STRING TotalRateAverageText; + PPH_STRING ResponseTimeText; + + PPH_STRING TooltipText; +} ET_DISK_NODE, *PET_DISK_NODE; + +// Process tree columns + +#define ETPRTNC_DISKREADS 1 +#define ETPRTNC_DISKWRITES 2 +#define ETPRTNC_DISKREADBYTES 3 +#define ETPRTNC_DISKWRITEBYTES 4 +#define ETPRTNC_DISKTOTALBYTES 5 +#define ETPRTNC_DISKREADSDELTA 6 +#define ETPRTNC_DISKWRITESDELTA 7 +#define ETPRTNC_DISKREADBYTESDELTA 8 +#define ETPRTNC_DISKWRITEBYTESDELTA 9 +#define ETPRTNC_DISKTOTALBYTESDELTA 10 +#define ETPRTNC_NETWORKRECEIVES 11 +#define ETPRTNC_NETWORKSENDS 12 +#define ETPRTNC_NETWORKRECEIVEBYTES 13 +#define ETPRTNC_NETWORKSENDBYTES 14 +#define ETPRTNC_NETWORKTOTALBYTES 15 +#define ETPRTNC_NETWORKRECEIVESDELTA 16 +#define ETPRTNC_NETWORKSENDSDELTA 17 +#define ETPRTNC_NETWORKRECEIVEBYTESDELTA 18 +#define ETPRTNC_NETWORKSENDBYTESDELTA 19 +#define ETPRTNC_NETWORKTOTALBYTESDELTA 20 +#define ETPRTNC_HARDFAULTS 21 +#define ETPRTNC_HARDFAULTSDELTA 22 +#define ETPRTNC_PEAKTHREADS 23 +#define ETPRTNC_GPU 24 +#define ETPRTNC_GPUDEDICATEDBYTES 25 +#define ETPRTNC_GPUSHAREDBYTES 26 +#define ETPRTNC_DISKREADRATE 27 +#define ETPRTNC_DISKWRITERATE 28 +#define ETPRTNC_DISKTOTALRATE 29 +#define ETPRTNC_NETWORKRECEIVERATE 30 +#define ETPRTNC_NETWORKSENDRATE 31 +#define ETPRTNC_NETWORKTOTALRATE 32 +#define ETPRTNC_MAXIMUM 32 + +// Network list columns + +#define ETNETNC_RECEIVES 1 +#define ETNETNC_SENDS 2 +#define ETNETNC_RECEIVEBYTES 3 +#define ETNETNC_SENDBYTES 4 +#define ETNETNC_TOTALBYTES 5 +#define ETNETNC_RECEIVESDELTA 6 +#define ETNETNC_SENDSDELTA 7 +#define ETNETNC_RECEIVEBYTESDELTA 8 +#define ETNETNC_SENDBYTESDELTA 9 +#define ETNETNC_TOTALBYTESDELTA 10 +#define ETNETNC_FIREWALLSTATUS 11 +#define ETNETNC_RECEIVERATE 12 +#define ETNETNC_SENDRATE 13 +#define ETNETNC_TOTALRATE 14 +#define ETNETNC_MAXIMUM 14 + +// Firewall status + +typedef enum _ET_FIREWALL_STATUS +{ + FirewallUnknownStatus, + FirewallAllowedNotRestricted, + FirewallAllowedRestricted, + FirewallNotAllowedNotRestricted, + FirewallNotAllowedRestricted, + FirewallMaximumStatus +} ET_FIREWALL_STATUS; + +// Object extensions + +typedef struct _ET_PROCESS_BLOCK +{ + LIST_ENTRY ListEntry; + PPH_PROCESS_ITEM ProcessItem; + + ULONG64 DiskReadCount; + ULONG64 DiskWriteCount; + ULONG64 NetworkReceiveCount; + ULONG64 NetworkSendCount; + + ULONG64 DiskReadRaw; + ULONG64 DiskWriteRaw; + ULONG64 NetworkReceiveRaw; + ULONG64 NetworkSendRaw; + + PH_UINT64_DELTA DiskReadDelta; + PH_UINT64_DELTA DiskReadRawDelta; + PH_UINT64_DELTA DiskWriteDelta; + PH_UINT64_DELTA DiskWriteRawDelta; + PH_UINT64_DELTA NetworkReceiveDelta; + PH_UINT64_DELTA NetworkReceiveRawDelta; + PH_UINT64_DELTA NetworkSendDelta; + PH_UINT64_DELTA NetworkSendRawDelta; + + PH_UINT64_DELTA GpuRunningTimeDelta; + FLOAT GpuNodeUsage; + ULONG64 GpuDedicatedUsage; + ULONG64 GpuSharedUsage; + + PH_UINT32_DELTA HardFaultsDelta; + + PH_QUEUED_LOCK TextCacheLock; + PPH_STRING TextCache[ETPRTNC_MAXIMUM + 1]; + BOOLEAN TextCacheValid[ETPRTNC_MAXIMUM + 1]; + + PET_PROCESS_ICON SmallProcessIcon; +} ET_PROCESS_BLOCK, *PET_PROCESS_BLOCK; + +typedef struct _ET_NETWORK_BLOCK +{ + LIST_ENTRY ListEntry; + PPH_NETWORK_ITEM NetworkItem; + + ULONG64 ReceiveCount; + ULONG64 SendCount; + ULONG64 ReceiveRaw; + ULONG64 SendRaw; + + union + { + struct + { + PH_UINT64_DELTA ReceiveDelta; + PH_UINT64_DELTA ReceiveRawDelta; + PH_UINT64_DELTA SendDelta; + PH_UINT64_DELTA SendRawDelta; + }; + PH_UINT64_DELTA Deltas[4]; + }; + + ET_FIREWALL_STATUS FirewallStatus; + BOOLEAN FirewallStatusValid; + + PH_QUEUED_LOCK TextCacheLock; + PPH_STRING TextCache[ETNETNC_MAXIMUM + 1]; + BOOLEAN TextCacheValid[ETNETNC_MAXIMUM + 1]; +} ET_NETWORK_BLOCK, *PET_NETWORK_BLOCK; + +// main + +PET_PROCESS_BLOCK EtGetProcessBlock( + _In_ PPH_PROCESS_ITEM ProcessItem + ); + +PET_NETWORK_BLOCK EtGetNetworkBlock( + _In_ PPH_NETWORK_ITEM NetworkItem + ); + +// utils + +VOID EtFormatRate( + _In_ ULONG64 ValuePerPeriod, + _Inout_ PPH_STRING *Buffer, + _Out_opt_ PPH_STRINGREF String + ); + +// etwmon + +extern BOOLEAN EtEtwEnabled; + +// etwstat + +extern ULONG EtDiskReadCount; +extern ULONG EtDiskWriteCount; +extern ULONG EtNetworkReceiveCount; +extern ULONG EtNetworkSendCount; + +extern PH_UINT32_DELTA EtDiskReadDelta; +extern PH_UINT32_DELTA EtDiskWriteDelta; +extern PH_UINT32_DELTA EtNetworkReceiveDelta; +extern PH_UINT32_DELTA EtNetworkSendDelta; + +extern PH_UINT32_DELTA EtDiskReadCountDelta; +extern PH_UINT32_DELTA EtDiskWriteCountDelta; +extern PH_UINT32_DELTA EtNetworkReceiveCountDelta; +extern PH_UINT32_DELTA EtNetworkSendCountDelta; + +extern PH_CIRCULAR_BUFFER_ULONG EtDiskReadHistory; +extern PH_CIRCULAR_BUFFER_ULONG EtDiskWriteHistory; +extern PH_CIRCULAR_BUFFER_ULONG EtNetworkReceiveHistory; +extern PH_CIRCULAR_BUFFER_ULONG EtNetworkSendHistory; +extern PH_CIRCULAR_BUFFER_ULONG EtMaxDiskHistory; +extern PH_CIRCULAR_BUFFER_ULONG EtMaxNetworkHistory; + +VOID EtEtwStatisticsInitialization( + VOID + ); + +VOID EtEtwStatisticsUninitialization( + VOID + ); + +// etwdisk + +extern BOOLEAN EtDiskEnabled; + +extern PPH_OBJECT_TYPE EtDiskItemType; +extern PH_CALLBACK EtDiskItemAddedEvent; +extern PH_CALLBACK EtDiskItemModifiedEvent; +extern PH_CALLBACK EtDiskItemRemovedEvent; +extern PH_CALLBACK EtDiskItemsUpdatedEvent; + +VOID EtInitializeDiskInformation( + VOID + ); + +PET_DISK_ITEM EtCreateDiskItem( + VOID + ); + +PET_DISK_ITEM EtReferenceDiskItem( + _In_ HANDLE ProcessId, + _In_ PPH_STRING FileName + ); + +PPH_STRING EtFileObjectToFileName( + _In_ PVOID FileObject + ); + +// procicon + +PET_PROCESS_ICON EtProcIconCreateProcessIcon( + _In_ HICON Icon + ); + +VOID EtProcIconReferenceProcessIcon( + _Inout_ PET_PROCESS_ICON ProcessIcon + ); + +VOID EtProcIconDereferenceProcessIcon( + _Inout_ PET_PROCESS_ICON ProcessIcon + ); + +PET_PROCESS_ICON EtProcIconReferenceSmallProcessIcon( + _Inout_ PET_PROCESS_BLOCK Block + ); + +VOID EtProcIconNotifyProcessDelete( + _Inout_ PET_PROCESS_BLOCK Block + ); + +// etwprprp + +VOID EtProcessEtwPropertiesInitializing( + _In_ PVOID Parameter + ); + +// disktab + +VOID EtInitializeDiskTab( + VOID + ); + +VOID EtLoadSettingsDiskTreeList( + VOID + ); + +VOID EtSaveSettingsDiskTreeList( + VOID + ); + +// gpumon + +extern BOOLEAN EtGpuEnabled; + +extern ULONG EtGpuTotalNodeCount; +extern ULONG EtGpuTotalSegmentCount; +extern ULONG64 EtGpuDedicatedLimit; +extern ULONG64 EtGpuSharedLimit; +extern RTL_BITMAP EtGpuNodeBitMap; + +extern PH_UINT64_DELTA EtClockTotalRunningTimeDelta; +extern LARGE_INTEGER EtClockTotalRunningTimeFrequency; +extern PH_UINT64_DELTA EtGpuTotalRunningTimeDelta; +extern PH_UINT64_DELTA EtGpuSystemRunningTimeDelta; +extern FLOAT EtGpuNodeUsage; +extern PH_CIRCULAR_BUFFER_FLOAT EtGpuNodeHistory; +extern PH_CIRCULAR_BUFFER_ULONG EtMaxGpuNodeHistory; // ID of max. GPU usage process +extern PH_CIRCULAR_BUFFER_FLOAT EtMaxGpuNodeUsageHistory; + +extern PPH_UINT64_DELTA EtGpuNodesTotalRunningTimeDelta; +extern PPH_CIRCULAR_BUFFER_FLOAT EtGpuNodesHistory; + +extern ULONG64 EtGpuDedicatedUsage; +extern ULONG64 EtGpuSharedUsage; +extern PH_CIRCULAR_BUFFER_ULONG EtGpuDedicatedHistory; +extern PH_CIRCULAR_BUFFER_ULONG EtGpuSharedHistory; + +VOID EtGpuMonitorInitialization( + VOID + ); + +typedef struct _ET_PROCESS_GPU_STATISTICS +{ + ULONG SegmentCount; + ULONG NodeCount; + + ULONG64 DedicatedCommitted; + ULONG64 SharedCommitted; + + ULONG64 BytesAllocated; + ULONG64 BytesReserved; + ULONG64 WriteCombinedBytesAllocated; + ULONG64 WriteCombinedBytesReserved; + ULONG64 CachedBytesAllocated; + ULONG64 CachedBytesReserved; + ULONG64 SectionBytesAllocated; + ULONG64 SectionBytesReserved; + + ULONG64 RunningTime; + ULONG64 ContextSwitches; +} ET_PROCESS_GPU_STATISTICS, *PET_PROCESS_GPU_STATISTICS; + +VOID EtSaveGpuMonitorSettings( + VOID + ); + +ULONG EtGetGpuAdapterCount( + VOID + ); + +ULONG EtGetGpuAdapterIndexFromNodeIndex( + _In_ ULONG NodeIndex + ); + +PPH_STRING EtGetGpuAdapterDescription( + _In_ ULONG Index + ); + +VOID EtAllocateGpuNodeBitMap( + _Out_ PRTL_BITMAP BitMap + ); + +VOID EtUpdateGpuNodeBitMap( + _In_ PRTL_BITMAP NewBitMap + ); + +VOID EtQueryProcessGpuStatistics( + _In_ HANDLE ProcessHandle, + _Out_ PET_PROCESS_GPU_STATISTICS Statistics + ); + +// gpuprprp + +VOID EtProcessGpuPropertiesInitializing( + _In_ PVOID Parameter + ); + +// treeext + +VOID EtProcessTreeNewInitializing( + _In_ PVOID Parameter + ); + +VOID EtProcessTreeNewMessage( + _In_ PVOID Parameter + ); + +VOID EtNetworkTreeNewInitializing( + _In_ PVOID Parameter + ); + +VOID EtNetworkTreeNewMessage( + _In_ PVOID Parameter + ); + +ET_FIREWALL_STATUS EtQueryFirewallStatus( + _In_ PPH_NETWORK_ITEM NetworkItem + ); + +// etwsys + +VOID EtEtwSystemInformationInitializing( + _In_ PPH_PLUGIN_SYSINFO_POINTERS Pointers + ); + +// etwmini + +VOID EtEtwMiniInformationInitializing( + _In_ PPH_PLUGIN_MINIINFO_POINTERS Pointers + ); + +// gpunodes + +VOID EtShowGpuNodesDialog( + _In_ HWND ParentWindowHandle, + _In_ PPH_SYSINFO_PARAMETERS Parameters + ); + +// gpusys + +VOID EtGpuSystemInformationInitializing( + _In_ PPH_PLUGIN_SYSINFO_POINTERS Pointers + ); + +// gpumini + +VOID EtGpuMiniInformationInitializing( + _In_ PPH_PLUGIN_MINIINFO_POINTERS Pointers + ); + +// iconext + +VOID EtRegisterNotifyIcons( + VOID + ); + +// modsrv + +VOID EtShowModuleServicesDialog( + _In_ HWND ParentWindowHandle, + _In_ HANDLE ProcessId, + _In_ PWSTR ModuleName + ); + +// objprp + +VOID EtHandlePropertiesInitializing( + _In_ PVOID Parameter + ); + +// options + +VOID EtShowOptionsDialog( + _In_ HWND ParentWindowHandle + ); + +// thrdact + +BOOLEAN EtUiCancelIoThread( + _In_ HWND hWnd, + _In_ PPH_THREAD_ITEM Thread + ); + +// unldll + +VOID EtShowUnloadedDllsDialog( + _In_ HWND ParentWindowHandle, + _In_ PPH_PROCESS_ITEM ProcessItem + ); + +// wswatch + +VOID EtShowWsWatchDialog( + _In_ HWND ParentWindowHandle, + _In_ PPH_PROCESS_ITEM ProcessItem + ); + +#endif diff --git a/plugins/ExtendedTools/gpumini.c b/plugins/ExtendedTools/gpumini.c index ae20f1a6a744..db599455a68c 100644 --- a/plugins/ExtendedTools/gpumini.c +++ b/plugins/ExtendedTools/gpumini.c @@ -1,129 +1,129 @@ -/* - * Process Hacker Extended Tools - - * GPU mini information section - * - * Copyright (C) 2015 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include "exttools.h" -#include "gpumini.h" - -VOID EtGpuMiniInformationInitializing( - _In_ PPH_PLUGIN_MINIINFO_POINTERS Pointers - ) -{ - PH_MINIINFO_LIST_SECTION section; - - memset(§ion, 0, sizeof(PH_MINIINFO_LIST_SECTION)); - section.Callback = EtpGpuListSectionCallback; - Pointers->CreateListSection(L"GPU", 0, §ion); -} - -BOOLEAN EtpGpuListSectionCallback( - _In_ struct _PH_MINIINFO_LIST_SECTION *ListSection, - _In_ PH_MINIINFO_LIST_SECTION_MESSAGE Message, - _In_opt_ PVOID Parameter1, - _In_opt_ PVOID Parameter2 - ) -{ - switch (Message) - { - case MiListSectionTick: - { - ListSection->Section->Parameters->SetSectionText(ListSection->Section, - PhaFormatString(L"GPU %.2f%%", EtGpuNodeUsage * 100)); - } - break; - case MiListSectionSortProcessList: - { - PPH_MINIINFO_LIST_SECTION_SORT_LIST sortList = Parameter1; - - qsort(sortList->List->Items, sortList->List->Count, - sizeof(PPH_PROCESS_NODE), EtpGpuListSectionProcessCompareFunction); - } - return TRUE; - case MiListSectionAssignSortData: - { - PPH_MINIINFO_LIST_SECTION_ASSIGN_SORT_DATA assignSortData = Parameter1; - PPH_LIST processes = assignSortData->ProcessGroup->Processes; - FLOAT gpuUsage = 0; - ULONG i; - - for (i = 0; i < processes->Count; i++) - { - PPH_PROCESS_ITEM processItem = processes->Items[i]; - PET_PROCESS_BLOCK block = EtGetProcessBlock(processItem); - gpuUsage += block->GpuNodeUsage; - } - - *(PFLOAT)assignSortData->SortData->UserData = gpuUsage; - } - return TRUE; - case MiListSectionSortGroupList: - { - PPH_MINIINFO_LIST_SECTION_SORT_LIST sortList = Parameter1; - - qsort(sortList->List->Items, sortList->List->Count, - sizeof(PPH_MINIINFO_LIST_SECTION_SORT_DATA), EtpGpuListSectionNodeCompareFunction); - } - return TRUE; - case MiListSectionGetUsageText: - { - PPH_MINIINFO_LIST_SECTION_GET_USAGE_TEXT getUsageText = Parameter1; - PPH_LIST processes = getUsageText->ProcessGroup->Processes; - FLOAT gpuUsage = *(PFLOAT)getUsageText->SortData->UserData; - - PhMoveReference(&getUsageText->Line1, PhFormatString(L"%.2f%%", gpuUsage * 100)); - } - return TRUE; - } - - return FALSE; -} - -int __cdecl EtpGpuListSectionProcessCompareFunction( - _In_ const void *elem1, - _In_ const void *elem2 - ) -{ - int result; - PPH_PROCESS_NODE node1 = *(PPH_PROCESS_NODE *)elem1; - PPH_PROCESS_NODE node2 = *(PPH_PROCESS_NODE *)elem2; - PET_PROCESS_BLOCK block1 = EtGetProcessBlock(node1->ProcessItem); - PET_PROCESS_BLOCK block2 = EtGetProcessBlock(node2->ProcessItem); - - result = singlecmp(block2->GpuNodeUsage, block1->GpuNodeUsage); - - if (result == 0) - result = uint64cmp(block2->GpuRunningTimeDelta.Value, block1->GpuRunningTimeDelta.Value); - if (result == 0) - result = singlecmp(node2->ProcessItem->CpuUsage, node1->ProcessItem->CpuUsage); - - return result; -} - -int __cdecl EtpGpuListSectionNodeCompareFunction( - _In_ const void *elem1, - _In_ const void *elem2 - ) -{ - PPH_MINIINFO_LIST_SECTION_SORT_DATA data1 = *(PPH_MINIINFO_LIST_SECTION_SORT_DATA *)elem1; - PPH_MINIINFO_LIST_SECTION_SORT_DATA data2 = *(PPH_MINIINFO_LIST_SECTION_SORT_DATA *)elem2; - - return singlecmp(*(PFLOAT)data2->UserData, *(PFLOAT)data1->UserData); -} +/* + * Process Hacker Extended Tools - + * GPU mini information section + * + * Copyright (C) 2015 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include "exttools.h" +#include "gpumini.h" + +VOID EtGpuMiniInformationInitializing( + _In_ PPH_PLUGIN_MINIINFO_POINTERS Pointers + ) +{ + PH_MINIINFO_LIST_SECTION section; + + memset(§ion, 0, sizeof(PH_MINIINFO_LIST_SECTION)); + section.Callback = EtpGpuListSectionCallback; + Pointers->CreateListSection(L"GPU", 0, §ion); +} + +BOOLEAN EtpGpuListSectionCallback( + _In_ struct _PH_MINIINFO_LIST_SECTION *ListSection, + _In_ PH_MINIINFO_LIST_SECTION_MESSAGE Message, + _In_opt_ PVOID Parameter1, + _In_opt_ PVOID Parameter2 + ) +{ + switch (Message) + { + case MiListSectionTick: + { + ListSection->Section->Parameters->SetSectionText(ListSection->Section, + PhaFormatString(L"GPU %.2f%%", EtGpuNodeUsage * 100)); + } + break; + case MiListSectionSortProcessList: + { + PPH_MINIINFO_LIST_SECTION_SORT_LIST sortList = Parameter1; + + qsort(sortList->List->Items, sortList->List->Count, + sizeof(PPH_PROCESS_NODE), EtpGpuListSectionProcessCompareFunction); + } + return TRUE; + case MiListSectionAssignSortData: + { + PPH_MINIINFO_LIST_SECTION_ASSIGN_SORT_DATA assignSortData = Parameter1; + PPH_LIST processes = assignSortData->ProcessGroup->Processes; + FLOAT gpuUsage = 0; + ULONG i; + + for (i = 0; i < processes->Count; i++) + { + PPH_PROCESS_ITEM processItem = processes->Items[i]; + PET_PROCESS_BLOCK block = EtGetProcessBlock(processItem); + gpuUsage += block->GpuNodeUsage; + } + + *(PFLOAT)assignSortData->SortData->UserData = gpuUsage; + } + return TRUE; + case MiListSectionSortGroupList: + { + PPH_MINIINFO_LIST_SECTION_SORT_LIST sortList = Parameter1; + + qsort(sortList->List->Items, sortList->List->Count, + sizeof(PPH_MINIINFO_LIST_SECTION_SORT_DATA), EtpGpuListSectionNodeCompareFunction); + } + return TRUE; + case MiListSectionGetUsageText: + { + PPH_MINIINFO_LIST_SECTION_GET_USAGE_TEXT getUsageText = Parameter1; + PPH_LIST processes = getUsageText->ProcessGroup->Processes; + FLOAT gpuUsage = *(PFLOAT)getUsageText->SortData->UserData; + + PhMoveReference(&getUsageText->Line1, PhFormatString(L"%.2f%%", gpuUsage * 100)); + } + return TRUE; + } + + return FALSE; +} + +int __cdecl EtpGpuListSectionProcessCompareFunction( + _In_ const void *elem1, + _In_ const void *elem2 + ) +{ + int result; + PPH_PROCESS_NODE node1 = *(PPH_PROCESS_NODE *)elem1; + PPH_PROCESS_NODE node2 = *(PPH_PROCESS_NODE *)elem2; + PET_PROCESS_BLOCK block1 = EtGetProcessBlock(node1->ProcessItem); + PET_PROCESS_BLOCK block2 = EtGetProcessBlock(node2->ProcessItem); + + result = singlecmp(block2->GpuNodeUsage, block1->GpuNodeUsage); + + if (result == 0) + result = uint64cmp(block2->GpuRunningTimeDelta.Value, block1->GpuRunningTimeDelta.Value); + if (result == 0) + result = singlecmp(node2->ProcessItem->CpuUsage, node1->ProcessItem->CpuUsage); + + return result; +} + +int __cdecl EtpGpuListSectionNodeCompareFunction( + _In_ const void *elem1, + _In_ const void *elem2 + ) +{ + PPH_MINIINFO_LIST_SECTION_SORT_DATA data1 = *(PPH_MINIINFO_LIST_SECTION_SORT_DATA *)elem1; + PPH_MINIINFO_LIST_SECTION_SORT_DATA data2 = *(PPH_MINIINFO_LIST_SECTION_SORT_DATA *)elem2; + + return singlecmp(*(PFLOAT)data2->UserData, *(PFLOAT)data1->UserData); +} diff --git a/plugins/ExtendedTools/gpumini.h b/plugins/ExtendedTools/gpumini.h index 2375e83f1807..d3cb6828f640 100644 --- a/plugins/ExtendedTools/gpumini.h +++ b/plugins/ExtendedTools/gpumini.h @@ -1,21 +1,21 @@ -#ifndef GPUMINI_H -#define GPUMINI_H - -BOOLEAN EtpGpuListSectionCallback( - _In_ struct _PH_MINIINFO_LIST_SECTION *ListSection, - _In_ PH_MINIINFO_LIST_SECTION_MESSAGE Message, - _In_opt_ PVOID Parameter1, - _In_opt_ PVOID Parameter2 - ); - -int __cdecl EtpGpuListSectionProcessCompareFunction( - _In_ const void *elem1, - _In_ const void *elem2 - ); - -int __cdecl EtpGpuListSectionNodeCompareFunction( - _In_ const void *elem1, - _In_ const void *elem2 - ); - +#ifndef GPUMINI_H +#define GPUMINI_H + +BOOLEAN EtpGpuListSectionCallback( + _In_ struct _PH_MINIINFO_LIST_SECTION *ListSection, + _In_ PH_MINIINFO_LIST_SECTION_MESSAGE Message, + _In_opt_ PVOID Parameter1, + _In_opt_ PVOID Parameter2 + ); + +int __cdecl EtpGpuListSectionProcessCompareFunction( + _In_ const void *elem1, + _In_ const void *elem2 + ); + +int __cdecl EtpGpuListSectionNodeCompareFunction( + _In_ const void *elem1, + _In_ const void *elem2 + ); + #endif \ No newline at end of file diff --git a/plugins/ExtendedTools/gpumon.c b/plugins/ExtendedTools/gpumon.c index 1615f380d6a6..7f941d54a4be 100644 --- a/plugins/ExtendedTools/gpumon.c +++ b/plugins/ExtendedTools/gpumon.c @@ -1,825 +1,825 @@ -/* - * Process Hacker Extended Tools - - * GPU monitoring - * - * Copyright (C) 2011-2015 wj32 - * Copyright (C) 2016 dmex - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#define INITGUID -#include "exttools.h" -#include -#include -#include -#include "d3dkmt.h" -#include "gpumon.h" - -BOOLEAN EtGpuEnabled; -static PPH_LIST EtpGpuAdapterList; -static PH_CALLBACK_REGISTRATION ProcessesUpdatedCallbackRegistration; - -ULONG EtGpuTotalNodeCount; -ULONG EtGpuTotalSegmentCount; -ULONG64 EtGpuDedicatedLimit; -ULONG64 EtGpuSharedLimit; -ULONG EtGpuNextNodeIndex = 0; -RTL_BITMAP EtGpuNodeBitMap; -PULONG EtGpuNodeBitMapBuffer; -ULONG EtGpuNodeBitMapBitsSet; -PULONG EtGpuNewNodeBitMapBuffer; - -PH_UINT64_DELTA EtClockTotalRunningTimeDelta; -LARGE_INTEGER EtClockTotalRunningTimeFrequency; -PH_UINT64_DELTA EtGpuTotalRunningTimeDelta; -PH_UINT64_DELTA EtGpuSystemRunningTimeDelta; -FLOAT EtGpuNodeUsage; -PH_CIRCULAR_BUFFER_FLOAT EtGpuNodeHistory; -PH_CIRCULAR_BUFFER_ULONG EtMaxGpuNodeHistory; // ID of max. GPU usage process -PH_CIRCULAR_BUFFER_FLOAT EtMaxGpuNodeUsageHistory; - -PPH_UINT64_DELTA EtGpuNodesTotalRunningTimeDelta; -PPH_CIRCULAR_BUFFER_FLOAT EtGpuNodesHistory; - -ULONG64 EtGpuDedicatedUsage; -ULONG64 EtGpuSharedUsage; -PH_CIRCULAR_BUFFER_ULONG EtGpuDedicatedHistory; -PH_CIRCULAR_BUFFER_ULONG EtGpuSharedHistory; - -VOID EtGpuMonitorInitialization( - VOID - ) -{ - if (PhGetIntegerSetting(SETTING_NAME_ENABLE_GPU_MONITOR)) - { - EtpGpuAdapterList = PhCreateList(4); - - if (EtpInitializeD3DStatistics()) - EtGpuEnabled = TRUE; - } - - if (EtGpuEnabled) - { - ULONG sampleCount; - ULONG i; - ULONG j; - PPH_STRING bitmapString; - D3DKMT_QUERYSTATISTICS queryStatistics; - - sampleCount = PhGetIntegerSetting(L"SampleCount"); - PhInitializeCircularBuffer_FLOAT(&EtGpuNodeHistory, sampleCount); - PhInitializeCircularBuffer_ULONG(&EtMaxGpuNodeHistory, sampleCount); - PhInitializeCircularBuffer_FLOAT(&EtMaxGpuNodeUsageHistory, sampleCount); - PhInitializeCircularBuffer_ULONG(&EtGpuDedicatedHistory, sampleCount); - PhInitializeCircularBuffer_ULONG(&EtGpuSharedHistory, sampleCount); - - EtGpuNodesTotalRunningTimeDelta = PhAllocate(sizeof(PH_UINT64_DELTA) * EtGpuTotalNodeCount); - memset(EtGpuNodesTotalRunningTimeDelta, 0, sizeof(PH_UINT64_DELTA) * EtGpuTotalNodeCount); - EtGpuNodesHistory = PhAllocate(sizeof(PH_CIRCULAR_BUFFER_FLOAT) * EtGpuTotalNodeCount); - - for (i = 0; i < EtGpuTotalNodeCount; i++) - { - PhInitializeCircularBuffer_FLOAT(&EtGpuNodesHistory[i], sampleCount); - } - - PhRegisterCallback( - &PhProcessesUpdatedEvent, - EtGpuProcessesUpdatedCallback, - NULL, - &ProcessesUpdatedCallbackRegistration - ); - - // Load the node bitmap. - - bitmapString = PhGetStringSetting(SETTING_NAME_GPU_NODE_BITMAP); - - if (!(bitmapString->Length & 3) && bitmapString->Length / 4 <= BYTES_NEEDED_FOR_BITS(EtGpuTotalNodeCount)) - { - PhHexStringToBuffer(&bitmapString->sr, (PUCHAR)EtGpuNodeBitMapBuffer); - EtGpuNodeBitMapBitsSet = RtlNumberOfSetBits(&EtGpuNodeBitMap); - } - - PhDereferenceObject(bitmapString); - - // Fix up the node bitmap if the current node count differs from what we've seen. - if (EtGpuTotalNodeCount != PhGetIntegerSetting(SETTING_NAME_GPU_LAST_NODE_COUNT)) - { - ULONG maxContextSwitch = 0; - ULONG maxContextSwitchNodeIndex = 0; - - RtlClearAllBits(&EtGpuNodeBitMap); - EtGpuNodeBitMapBitsSet = 0; - - for (i = 0; i < EtpGpuAdapterList->Count; i++) - { - PETP_GPU_ADAPTER gpuAdapter = EtpGpuAdapterList->Items[i]; - - for (j = 0; j < gpuAdapter->NodeCount; j++) - { - memset(&queryStatistics, 0, sizeof(D3DKMT_QUERYSTATISTICS)); - queryStatistics.Type = D3DKMT_QUERYSTATISTICS_NODE; - queryStatistics.AdapterLuid = gpuAdapter->AdapterLuid; - queryStatistics.QueryNode.NodeId = j; - - if (NT_SUCCESS(D3DKMTQueryStatistics(&queryStatistics))) - { - // The numbers below are quite arbitrary. - if (queryStatistics.QueryResult.NodeInformation.GlobalInformation.RunningTime.QuadPart != 0 && - queryStatistics.QueryResult.NodeInformation.GlobalInformation.ContextSwitch > 10000) - { - RtlSetBits(&EtGpuNodeBitMap, gpuAdapter->FirstNodeIndex + j, 1); - EtGpuNodeBitMapBitsSet++; - } - - if (maxContextSwitch < queryStatistics.QueryResult.NodeInformation.GlobalInformation.ContextSwitch) - { - maxContextSwitch = queryStatistics.QueryResult.NodeInformation.GlobalInformation.ContextSwitch; - maxContextSwitchNodeIndex = gpuAdapter->FirstNodeIndex + j; - } - } - } - } - - // Just in case - if (EtGpuNodeBitMapBitsSet == 0) - { - RtlSetBits(&EtGpuNodeBitMap, maxContextSwitchNodeIndex, 1); - EtGpuNodeBitMapBitsSet = 1; - } - - PhSetIntegerSetting(SETTING_NAME_GPU_LAST_NODE_COUNT, EtGpuTotalNodeCount); - } - } -} - -BOOLEAN EtpInitializeD3DStatistics( - VOID - ) -{ - PWSTR deviceInterfaceList; - ULONG deviceInterfaceListLength = 0; - PWSTR deviceInterface; - D3DKMT_OPENADAPTERFROMDEVICENAME openAdapterFromDeviceName; - D3DKMT_QUERYSTATISTICS queryStatistics; - D3DKMT_CLOSEADAPTER closeAdapter; - - if (CM_Get_Device_Interface_List_Size( - &deviceInterfaceListLength, - (PGUID)&GUID_DISPLAY_DEVICE_ARRIVAL, - NULL, - CM_GET_DEVICE_INTERFACE_LIST_PRESENT - ) != CR_SUCCESS) - { - return FALSE; - } - - deviceInterfaceList = PhAllocate(deviceInterfaceListLength * sizeof(WCHAR)); - memset(deviceInterfaceList, 0, deviceInterfaceListLength * sizeof(WCHAR)); - - if (CM_Get_Device_Interface_List( - (PGUID)&GUID_DISPLAY_DEVICE_ARRIVAL, - NULL, - deviceInterfaceList, - deviceInterfaceListLength, - CM_GET_DEVICE_INTERFACE_LIST_PRESENT - ) != CR_SUCCESS) - { - PhFree(deviceInterfaceList); - return FALSE; - } - - for (deviceInterface = deviceInterfaceList; *deviceInterface; deviceInterface += PhCountStringZ(deviceInterface) + 1) - { - memset(&openAdapterFromDeviceName, 0, sizeof(D3DKMT_OPENADAPTERFROMDEVICENAME)); - openAdapterFromDeviceName.pDeviceName = deviceInterface; - - if (NT_SUCCESS(D3DKMTOpenAdapterFromDeviceName(&openAdapterFromDeviceName))) - { - memset(&queryStatistics, 0, sizeof(D3DKMT_QUERYSTATISTICS)); - queryStatistics.Type = D3DKMT_QUERYSTATISTICS_ADAPTER; - queryStatistics.AdapterLuid = openAdapterFromDeviceName.AdapterLuid; - - if (NT_SUCCESS(D3DKMTQueryStatistics(&queryStatistics))) - { - PETP_GPU_ADAPTER gpuAdapter; - ULONG i; - - gpuAdapter = EtpAllocateGpuAdapter(queryStatistics.QueryResult.AdapterInformation.NbSegments); - gpuAdapter->AdapterLuid = openAdapterFromDeviceName.AdapterLuid; - gpuAdapter->Description = EtpQueryDeviceDescription(deviceInterface); - gpuAdapter->NodeCount = queryStatistics.QueryResult.AdapterInformation.NodeCount; - gpuAdapter->SegmentCount = queryStatistics.QueryResult.AdapterInformation.NbSegments; - RtlInitializeBitMap(&gpuAdapter->ApertureBitMap, gpuAdapter->ApertureBitMapBuffer, queryStatistics.QueryResult.AdapterInformation.NbSegments); - - PhAddItemList(EtpGpuAdapterList, gpuAdapter); - EtGpuTotalNodeCount += gpuAdapter->NodeCount; - EtGpuTotalSegmentCount += gpuAdapter->SegmentCount; - - gpuAdapter->FirstNodeIndex = EtGpuNextNodeIndex; - EtGpuNextNodeIndex += gpuAdapter->NodeCount; - - for (i = 0; i < gpuAdapter->SegmentCount; i++) - { - memset(&queryStatistics, 0, sizeof(D3DKMT_QUERYSTATISTICS)); - queryStatistics.Type = D3DKMT_QUERYSTATISTICS_SEGMENT; - queryStatistics.AdapterLuid = gpuAdapter->AdapterLuid; - queryStatistics.QuerySegment.SegmentId = i; - - if (NT_SUCCESS(D3DKMTQueryStatistics(&queryStatistics))) - { - ULONG64 commitLimit; - ULONG aperture; - - if (WindowsVersion >= WINDOWS_8) - { - commitLimit = queryStatistics.QueryResult.SegmentInformation.CommitLimit; - aperture = queryStatistics.QueryResult.SegmentInformation.Aperture; - } - else - { - commitLimit = queryStatistics.QueryResult.SegmentInformationV1.CommitLimit; - aperture = queryStatistics.QueryResult.SegmentInformationV1.Aperture; - } - - if (aperture) - EtGpuSharedLimit += commitLimit; - else - EtGpuDedicatedLimit += commitLimit; - - if (aperture) - RtlSetBits(&gpuAdapter->ApertureBitMap, i, 1); - } - } - } - - memset(&closeAdapter, 0, sizeof(D3DKMT_CLOSEADAPTER)); - closeAdapter.hAdapter = openAdapterFromDeviceName.hAdapter; - D3DKMTCloseAdapter(&closeAdapter); - } - } - - PhFree(deviceInterfaceList); - - EtGpuNodeBitMapBuffer = PhAllocate(BYTES_NEEDED_FOR_BITS(EtGpuTotalNodeCount)); - RtlInitializeBitMap(&EtGpuNodeBitMap, EtGpuNodeBitMapBuffer, EtGpuTotalNodeCount); - RtlSetBits(&EtGpuNodeBitMap, 0, 1); - EtGpuNodeBitMapBitsSet = 1; - - return TRUE; -} - -PETP_GPU_ADAPTER EtpAllocateGpuAdapter( - _In_ ULONG NumberOfSegments - ) -{ - PETP_GPU_ADAPTER adapter; - SIZE_T sizeNeeded; - - sizeNeeded = FIELD_OFFSET(ETP_GPU_ADAPTER, ApertureBitMapBuffer); - sizeNeeded += BYTES_NEEDED_FOR_BITS(NumberOfSegments); - - adapter = PhAllocate(sizeNeeded); - memset(adapter, 0, sizeNeeded); - - return adapter; -} - -PPH_STRING EtpQueryDeviceDescription( - _In_ PWSTR DeviceInterface - ) -{ - CONFIGRET result; - PPH_STRING string; - ULONG bufferSize; - DEVPROPTYPE devicePropertyType; - DEVINST deviceInstanceHandle; - ULONG deviceInstanceIdLength = MAX_DEVICE_ID_LEN; - WCHAR deviceInstanceId[MAX_DEVICE_ID_LEN]; - - if (CM_Get_Device_Interface_Property( - DeviceInterface, - &DEVPKEY_Device_InstanceId, - &devicePropertyType, - (PBYTE)deviceInstanceId, - &deviceInstanceIdLength, - 0 - ) != CR_SUCCESS) - { - return NULL; - } - - if (CM_Locate_DevNode( - &deviceInstanceHandle, - deviceInstanceId, - CM_LOCATE_DEVNODE_NORMAL - ) != CR_SUCCESS) - { - return NULL; - } - - bufferSize = 0x40; - string = PhCreateStringEx(NULL, bufferSize); - - if ((result = CM_Get_DevNode_Property( // CM_Get_DevNode_Registry_Property with CM_DRP_DEVICEDESC?? - deviceInstanceHandle, - &DEVPKEY_Device_DeviceDesc, - &devicePropertyType, - (PBYTE)string->Buffer, - &bufferSize, - 0 - )) != CR_SUCCESS) - { - PhDereferenceObject(string); - string = PhCreateStringEx(NULL, bufferSize); - - result = CM_Get_DevNode_Property( - deviceInstanceHandle, - &DEVPKEY_Device_DeviceDesc, - &devicePropertyType, - (PBYTE)string->Buffer, - &bufferSize, - 0 - ); - } - - if (result != CR_SUCCESS) - { - PhDereferenceObject(string); - return NULL; - } - - PhTrimToNullTerminatorString(string); - - return string; -} - -VOID EtpUpdateSegmentInformation( - _In_opt_ PET_PROCESS_BLOCK Block - ) -{ - ULONG i; - ULONG j; - PETP_GPU_ADAPTER gpuAdapter; - D3DKMT_QUERYSTATISTICS queryStatistics; - ULONG64 dedicatedUsage; - ULONG64 sharedUsage; - - if (Block && !Block->ProcessItem->QueryHandle) - return; - - dedicatedUsage = 0; - sharedUsage = 0; - - for (i = 0; i < EtpGpuAdapterList->Count; i++) - { - gpuAdapter = EtpGpuAdapterList->Items[i]; - - for (j = 0; j < gpuAdapter->SegmentCount; j++) - { - memset(&queryStatistics, 0, sizeof(D3DKMT_QUERYSTATISTICS)); - - if (Block) - queryStatistics.Type = D3DKMT_QUERYSTATISTICS_PROCESS_SEGMENT; - else - queryStatistics.Type = D3DKMT_QUERYSTATISTICS_SEGMENT; - - queryStatistics.AdapterLuid = gpuAdapter->AdapterLuid; - - if (Block) - { - queryStatistics.hProcess = Block->ProcessItem->QueryHandle; - queryStatistics.QueryProcessSegment.SegmentId = j; - } - else - { - queryStatistics.QuerySegment.SegmentId = j; - } - - if (NT_SUCCESS(D3DKMTQueryStatistics(&queryStatistics))) - { - if (Block) - { - ULONG64 bytesCommitted; - - if (WindowsVersion >= WINDOWS_8) - { - bytesCommitted = queryStatistics.QueryResult.ProcessSegmentInformation.BytesCommitted; - } - else - { - bytesCommitted = (ULONG)queryStatistics.QueryResult.ProcessSegmentInformation.BytesCommitted; - } - - if (RtlCheckBit(&gpuAdapter->ApertureBitMap, j)) - sharedUsage += bytesCommitted; - else - dedicatedUsage += bytesCommitted; - } - else - { - ULONG64 bytesCommitted; - - if (WindowsVersion >= WINDOWS_8) - { - bytesCommitted = queryStatistics.QueryResult.SegmentInformation.BytesResident; - } - else - { - bytesCommitted = queryStatistics.QueryResult.SegmentInformationV1.BytesResident; - } - - if (RtlCheckBit(&gpuAdapter->ApertureBitMap, j)) - sharedUsage += bytesCommitted; - else - dedicatedUsage += bytesCommitted; - } - } - } - } - - if (Block) - { - Block->GpuDedicatedUsage = dedicatedUsage; - Block->GpuSharedUsage = sharedUsage; - } - else - { - EtGpuDedicatedUsage = dedicatedUsage; - EtGpuSharedUsage = sharedUsage; - } -} - -VOID EtpUpdateNodeInformation( - _In_opt_ PET_PROCESS_BLOCK Block - ) -{ - ULONG i; - ULONG j; - PETP_GPU_ADAPTER gpuAdapter; - D3DKMT_QUERYSTATISTICS queryStatistics; - ULONG64 totalRunningTime; - ULONG64 systemRunningTime; - - if (Block && !Block->ProcessItem->QueryHandle) - return; - - totalRunningTime = 0; - systemRunningTime = 0; - - for (i = 0; i < EtpGpuAdapterList->Count; i++) - { - gpuAdapter = EtpGpuAdapterList->Items[i]; - - for (j = 0; j < gpuAdapter->NodeCount; j++) - { - if (Block && !RtlCheckBit(&EtGpuNodeBitMap, gpuAdapter->FirstNodeIndex + j)) - continue; - - memset(&queryStatistics, 0, sizeof(D3DKMT_QUERYSTATISTICS)); - - if (Block) - queryStatistics.Type = D3DKMT_QUERYSTATISTICS_PROCESS_NODE; - else - queryStatistics.Type = D3DKMT_QUERYSTATISTICS_NODE; - - queryStatistics.AdapterLuid = gpuAdapter->AdapterLuid; - - if (Block) - { - queryStatistics.hProcess = Block->ProcessItem->QueryHandle; - queryStatistics.QueryProcessNode.NodeId = j; - } - else - { - queryStatistics.QueryNode.NodeId = j; - } - - if (NT_SUCCESS(D3DKMTQueryStatistics(&queryStatistics))) - { - if (Block) - { - totalRunningTime += queryStatistics.QueryResult.ProcessNodeInformation.RunningTime.QuadPart; - } - else - { - ULONG nodeIndex; - - nodeIndex = gpuAdapter->FirstNodeIndex + j; - - PhUpdateDelta(&EtGpuNodesTotalRunningTimeDelta[nodeIndex], queryStatistics.QueryResult.NodeInformation.GlobalInformation.RunningTime.QuadPart); - - if (RtlCheckBit(&EtGpuNodeBitMap, gpuAdapter->FirstNodeIndex + j)) - { - totalRunningTime += queryStatistics.QueryResult.NodeInformation.GlobalInformation.RunningTime.QuadPart; - systemRunningTime += queryStatistics.QueryResult.NodeInformation.SystemInformation.RunningTime.QuadPart; - } - } - } - } - } - - if (Block) - { - PhUpdateDelta(&Block->GpuRunningTimeDelta, totalRunningTime); - } - else - { - LARGE_INTEGER performanceCounter; - - NtQueryPerformanceCounter(&performanceCounter, &EtClockTotalRunningTimeFrequency); - PhUpdateDelta(&EtClockTotalRunningTimeDelta, performanceCounter.QuadPart); - PhUpdateDelta(&EtGpuTotalRunningTimeDelta, totalRunningTime); - PhUpdateDelta(&EtGpuSystemRunningTimeDelta, systemRunningTime); - } -} - -VOID NTAPI EtGpuProcessesUpdatedCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - static ULONG runCount = 0; // MUST keep in sync with runCount in process provider - - DOUBLE elapsedTime; // total GPU node elapsed time in micro-seconds - ULONG i; - PLIST_ENTRY listEntry; - FLOAT maxNodeValue = 0; - PET_PROCESS_BLOCK maxNodeBlock = NULL; - - // Update global statistics. - - EtpUpdateSegmentInformation(NULL); - EtpUpdateNodeInformation(NULL); - - elapsedTime = (DOUBLE)EtClockTotalRunningTimeDelta.Delta * 10000000 / EtClockTotalRunningTimeFrequency.QuadPart; - - if (elapsedTime != 0) - EtGpuNodeUsage = (FLOAT)(EtGpuTotalRunningTimeDelta.Delta / (elapsedTime * EtGpuNodeBitMapBitsSet)); - else - EtGpuNodeUsage = 0; - - if (EtGpuNodeUsage > 1) - EtGpuNodeUsage = 1; - - // Do the update of the node bitmap if needed. - if (EtGpuNewNodeBitMapBuffer) - { - PULONG newBuffer; - - newBuffer = _InterlockedExchangePointer(&EtGpuNewNodeBitMapBuffer, NULL); - - if (newBuffer) - { - PhFree(EtGpuNodeBitMap.Buffer); - EtGpuNodeBitMap.Buffer = newBuffer; - EtGpuNodeBitMapBuffer = newBuffer; - EtGpuNodeBitMapBitsSet = RtlNumberOfSetBits(&EtGpuNodeBitMap); - EtSaveGpuMonitorSettings(); - } - } - - // Update per-process statistics. - // Note: no lock is needed because we only ever modify the list on this same thread. - - listEntry = EtProcessBlockListHead.Flink; - - while (listEntry != &EtProcessBlockListHead) - { - PET_PROCESS_BLOCK block; - - block = CONTAINING_RECORD(listEntry, ET_PROCESS_BLOCK, ListEntry); - - EtpUpdateSegmentInformation(block); - EtpUpdateNodeInformation(block); - - if (elapsedTime != 0) - { - block->GpuNodeUsage = (FLOAT)(block->GpuRunningTimeDelta.Delta / (elapsedTime * EtGpuNodeBitMapBitsSet)); - - if (block->GpuNodeUsage > 1) - block->GpuNodeUsage = 1; - } - - if (maxNodeValue < block->GpuNodeUsage) - { - maxNodeValue = block->GpuNodeUsage; - maxNodeBlock = block; - } - - listEntry = listEntry->Flink; - } - - // Update history buffers. - - if (runCount != 0) - { - PhAddItemCircularBuffer_FLOAT(&EtGpuNodeHistory, EtGpuNodeUsage); - PhAddItemCircularBuffer_ULONG(&EtGpuDedicatedHistory, (ULONG)(EtGpuDedicatedUsage / PAGE_SIZE)); - PhAddItemCircularBuffer_ULONG(&EtGpuSharedHistory, (ULONG)(EtGpuSharedUsage / PAGE_SIZE)); - - for (i = 0; i < EtGpuTotalNodeCount; i++) - { - FLOAT usage; - - usage = (FLOAT)(EtGpuNodesTotalRunningTimeDelta[i].Delta / elapsedTime); - - if (usage > 1) - usage = 1; - - PhAddItemCircularBuffer_FLOAT(&EtGpuNodesHistory[i], usage); - } - - if (maxNodeBlock) - { - PhAddItemCircularBuffer_ULONG(&EtMaxGpuNodeHistory, HandleToUlong(maxNodeBlock->ProcessItem->ProcessId)); - PhAddItemCircularBuffer_FLOAT(&EtMaxGpuNodeUsageHistory, maxNodeBlock->GpuNodeUsage); - PhReferenceProcessRecordForStatistics(maxNodeBlock->ProcessItem->Record); - } - else - { - PhAddItemCircularBuffer_ULONG(&EtMaxGpuNodeHistory, 0); - PhAddItemCircularBuffer_FLOAT(&EtMaxGpuNodeUsageHistory, 0); - } - } - - runCount++; -} - -VOID EtSaveGpuMonitorSettings( - VOID - ) -{ - PPH_STRING string; - - string = PhBufferToHexString((PUCHAR)EtGpuNodeBitMapBuffer, BYTES_NEEDED_FOR_BITS(EtGpuTotalNodeCount)); - PhSetStringSetting2(SETTING_NAME_GPU_NODE_BITMAP, &string->sr); - PhDereferenceObject(string); -} - -ULONG EtGetGpuAdapterCount( - VOID - ) -{ - return EtpGpuAdapterList->Count; -} - -ULONG EtGetGpuAdapterIndexFromNodeIndex( - _In_ ULONG NodeIndex - ) -{ - ULONG i; - PETP_GPU_ADAPTER gpuAdapter; - - for (i = 0; i < EtpGpuAdapterList->Count; i++) - { - gpuAdapter = EtpGpuAdapterList->Items[i]; - - if (NodeIndex >= gpuAdapter->FirstNodeIndex && NodeIndex < gpuAdapter->FirstNodeIndex + gpuAdapter->NodeCount) - return i; - } - - return -1; -} - -PPH_STRING EtGetGpuAdapterDescription( - _In_ ULONG Index - ) -{ - PPH_STRING description; - - if (Index >= EtpGpuAdapterList->Count) - return NULL; - - description = ((PETP_GPU_ADAPTER)EtpGpuAdapterList->Items[Index])->Description; - - if (description) - { - PhReferenceObject(description); - return description; - } - else - { - return NULL; - } -} - -VOID EtAllocateGpuNodeBitMap( - _Out_ PRTL_BITMAP BitMap - ) -{ - SIZE_T numberOfBytes; - - numberOfBytes = BYTES_NEEDED_FOR_BITS(EtGpuTotalNodeCount); - - BitMap->Buffer = PhAllocate(numberOfBytes); - BitMap->SizeOfBitMap = EtGpuTotalNodeCount; - memset(BitMap->Buffer, 0, numberOfBytes); -} - -VOID EtUpdateGpuNodeBitMap( - _In_ PRTL_BITMAP NewBitMap - ) -{ - PULONG buffer; - - buffer = _InterlockedExchangePointer(&EtGpuNewNodeBitMapBuffer, NewBitMap->Buffer); - - if (buffer) - PhFree(buffer); -} - -VOID EtQueryProcessGpuStatistics( - _In_ HANDLE ProcessHandle, - _Out_ PET_PROCESS_GPU_STATISTICS Statistics - ) -{ - NTSTATUS status; - ULONG i; - ULONG j; - PETP_GPU_ADAPTER gpuAdapter; - D3DKMT_QUERYSTATISTICS queryStatistics; - - memset(Statistics, 0, sizeof(ET_PROCESS_GPU_STATISTICS)); - - for (i = 0; i < EtpGpuAdapterList->Count; i++) - { - gpuAdapter = EtpGpuAdapterList->Items[i]; - - Statistics->SegmentCount += gpuAdapter->SegmentCount; - Statistics->NodeCount += gpuAdapter->NodeCount; - - for (j = 0; j < gpuAdapter->SegmentCount; j++) - { - memset(&queryStatistics, 0, sizeof(D3DKMT_QUERYSTATISTICS)); - queryStatistics.Type = D3DKMT_QUERYSTATISTICS_PROCESS_SEGMENT; - queryStatistics.AdapterLuid = gpuAdapter->AdapterLuid; - queryStatistics.hProcess = ProcessHandle; - queryStatistics.QueryProcessSegment.SegmentId = j; - - if (NT_SUCCESS(status = D3DKMTQueryStatistics(&queryStatistics))) - { - ULONG64 bytesCommitted; - - if (WindowsVersion >= WINDOWS_8) - { - bytesCommitted = queryStatistics.QueryResult.ProcessSegmentInformation.BytesCommitted; - } - else - { - bytesCommitted = (ULONG)queryStatistics.QueryResult.ProcessSegmentInformation.BytesCommitted; - } - - if (RtlCheckBit(&gpuAdapter->ApertureBitMap, j)) - Statistics->SharedCommitted += bytesCommitted; - else - Statistics->DedicatedCommitted += bytesCommitted; - } - } - - for (j = 0; j < gpuAdapter->NodeCount; j++) - { - memset(&queryStatistics, 0, sizeof(D3DKMT_QUERYSTATISTICS)); - queryStatistics.Type = D3DKMT_QUERYSTATISTICS_PROCESS_NODE; - queryStatistics.AdapterLuid = gpuAdapter->AdapterLuid; - queryStatistics.hProcess = ProcessHandle; - queryStatistics.QueryProcessNode.NodeId = j; - - if (NT_SUCCESS(D3DKMTQueryStatistics(&queryStatistics))) - { - Statistics->RunningTime += queryStatistics.QueryResult.ProcessNodeInformation.RunningTime.QuadPart; - Statistics->ContextSwitches += queryStatistics.QueryResult.ProcessNodeInformation.ContextSwitch; - } - } - - memset(&queryStatistics, 0, sizeof(D3DKMT_QUERYSTATISTICS)); - queryStatistics.Type = D3DKMT_QUERYSTATISTICS_PROCESS; - queryStatistics.AdapterLuid = gpuAdapter->AdapterLuid; - queryStatistics.hProcess = ProcessHandle; - - if (NT_SUCCESS(D3DKMTQueryStatistics(&queryStatistics))) - { - Statistics->BytesAllocated += queryStatistics.QueryResult.ProcessInformation.SystemMemory.BytesAllocated; - Statistics->BytesReserved += queryStatistics.QueryResult.ProcessInformation.SystemMemory.BytesReserved; - Statistics->WriteCombinedBytesAllocated += queryStatistics.QueryResult.ProcessInformation.SystemMemory.WriteCombinedBytesAllocated; - Statistics->WriteCombinedBytesReserved += queryStatistics.QueryResult.ProcessInformation.SystemMemory.WriteCombinedBytesReserved; - Statistics->CachedBytesAllocated += queryStatistics.QueryResult.ProcessInformation.SystemMemory.CachedBytesAllocated; - Statistics->CachedBytesReserved += queryStatistics.QueryResult.ProcessInformation.SystemMemory.CachedBytesReserved; - Statistics->SectionBytesAllocated += queryStatistics.QueryResult.ProcessInformation.SystemMemory.SectionBytesAllocated; - Statistics->SectionBytesReserved += queryStatistics.QueryResult.ProcessInformation.SystemMemory.SectionBytesReserved; - } - } -} +/* + * Process Hacker Extended Tools - + * GPU monitoring + * + * Copyright (C) 2011-2015 wj32 + * Copyright (C) 2016 dmex + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#define INITGUID +#include "exttools.h" +#include +#include +#include +#include "d3dkmt.h" +#include "gpumon.h" + +BOOLEAN EtGpuEnabled; +static PPH_LIST EtpGpuAdapterList; +static PH_CALLBACK_REGISTRATION ProcessesUpdatedCallbackRegistration; + +ULONG EtGpuTotalNodeCount; +ULONG EtGpuTotalSegmentCount; +ULONG64 EtGpuDedicatedLimit; +ULONG64 EtGpuSharedLimit; +ULONG EtGpuNextNodeIndex = 0; +RTL_BITMAP EtGpuNodeBitMap; +PULONG EtGpuNodeBitMapBuffer; +ULONG EtGpuNodeBitMapBitsSet; +PULONG EtGpuNewNodeBitMapBuffer; + +PH_UINT64_DELTA EtClockTotalRunningTimeDelta; +LARGE_INTEGER EtClockTotalRunningTimeFrequency; +PH_UINT64_DELTA EtGpuTotalRunningTimeDelta; +PH_UINT64_DELTA EtGpuSystemRunningTimeDelta; +FLOAT EtGpuNodeUsage; +PH_CIRCULAR_BUFFER_FLOAT EtGpuNodeHistory; +PH_CIRCULAR_BUFFER_ULONG EtMaxGpuNodeHistory; // ID of max. GPU usage process +PH_CIRCULAR_BUFFER_FLOAT EtMaxGpuNodeUsageHistory; + +PPH_UINT64_DELTA EtGpuNodesTotalRunningTimeDelta; +PPH_CIRCULAR_BUFFER_FLOAT EtGpuNodesHistory; + +ULONG64 EtGpuDedicatedUsage; +ULONG64 EtGpuSharedUsage; +PH_CIRCULAR_BUFFER_ULONG EtGpuDedicatedHistory; +PH_CIRCULAR_BUFFER_ULONG EtGpuSharedHistory; + +VOID EtGpuMonitorInitialization( + VOID + ) +{ + if (PhGetIntegerSetting(SETTING_NAME_ENABLE_GPU_MONITOR)) + { + EtpGpuAdapterList = PhCreateList(4); + + if (EtpInitializeD3DStatistics()) + EtGpuEnabled = TRUE; + } + + if (EtGpuEnabled) + { + ULONG sampleCount; + ULONG i; + ULONG j; + PPH_STRING bitmapString; + D3DKMT_QUERYSTATISTICS queryStatistics; + + sampleCount = PhGetIntegerSetting(L"SampleCount"); + PhInitializeCircularBuffer_FLOAT(&EtGpuNodeHistory, sampleCount); + PhInitializeCircularBuffer_ULONG(&EtMaxGpuNodeHistory, sampleCount); + PhInitializeCircularBuffer_FLOAT(&EtMaxGpuNodeUsageHistory, sampleCount); + PhInitializeCircularBuffer_ULONG(&EtGpuDedicatedHistory, sampleCount); + PhInitializeCircularBuffer_ULONG(&EtGpuSharedHistory, sampleCount); + + EtGpuNodesTotalRunningTimeDelta = PhAllocate(sizeof(PH_UINT64_DELTA) * EtGpuTotalNodeCount); + memset(EtGpuNodesTotalRunningTimeDelta, 0, sizeof(PH_UINT64_DELTA) * EtGpuTotalNodeCount); + EtGpuNodesHistory = PhAllocate(sizeof(PH_CIRCULAR_BUFFER_FLOAT) * EtGpuTotalNodeCount); + + for (i = 0; i < EtGpuTotalNodeCount; i++) + { + PhInitializeCircularBuffer_FLOAT(&EtGpuNodesHistory[i], sampleCount); + } + + PhRegisterCallback( + &PhProcessesUpdatedEvent, + EtGpuProcessesUpdatedCallback, + NULL, + &ProcessesUpdatedCallbackRegistration + ); + + // Load the node bitmap. + + bitmapString = PhGetStringSetting(SETTING_NAME_GPU_NODE_BITMAP); + + if (!(bitmapString->Length & 3) && bitmapString->Length / 4 <= BYTES_NEEDED_FOR_BITS(EtGpuTotalNodeCount)) + { + PhHexStringToBuffer(&bitmapString->sr, (PUCHAR)EtGpuNodeBitMapBuffer); + EtGpuNodeBitMapBitsSet = RtlNumberOfSetBits(&EtGpuNodeBitMap); + } + + PhDereferenceObject(bitmapString); + + // Fix up the node bitmap if the current node count differs from what we've seen. + if (EtGpuTotalNodeCount != PhGetIntegerSetting(SETTING_NAME_GPU_LAST_NODE_COUNT)) + { + ULONG maxContextSwitch = 0; + ULONG maxContextSwitchNodeIndex = 0; + + RtlClearAllBits(&EtGpuNodeBitMap); + EtGpuNodeBitMapBitsSet = 0; + + for (i = 0; i < EtpGpuAdapterList->Count; i++) + { + PETP_GPU_ADAPTER gpuAdapter = EtpGpuAdapterList->Items[i]; + + for (j = 0; j < gpuAdapter->NodeCount; j++) + { + memset(&queryStatistics, 0, sizeof(D3DKMT_QUERYSTATISTICS)); + queryStatistics.Type = D3DKMT_QUERYSTATISTICS_NODE; + queryStatistics.AdapterLuid = gpuAdapter->AdapterLuid; + queryStatistics.QueryNode.NodeId = j; + + if (NT_SUCCESS(D3DKMTQueryStatistics(&queryStatistics))) + { + // The numbers below are quite arbitrary. + if (queryStatistics.QueryResult.NodeInformation.GlobalInformation.RunningTime.QuadPart != 0 && + queryStatistics.QueryResult.NodeInformation.GlobalInformation.ContextSwitch > 10000) + { + RtlSetBits(&EtGpuNodeBitMap, gpuAdapter->FirstNodeIndex + j, 1); + EtGpuNodeBitMapBitsSet++; + } + + if (maxContextSwitch < queryStatistics.QueryResult.NodeInformation.GlobalInformation.ContextSwitch) + { + maxContextSwitch = queryStatistics.QueryResult.NodeInformation.GlobalInformation.ContextSwitch; + maxContextSwitchNodeIndex = gpuAdapter->FirstNodeIndex + j; + } + } + } + } + + // Just in case + if (EtGpuNodeBitMapBitsSet == 0) + { + RtlSetBits(&EtGpuNodeBitMap, maxContextSwitchNodeIndex, 1); + EtGpuNodeBitMapBitsSet = 1; + } + + PhSetIntegerSetting(SETTING_NAME_GPU_LAST_NODE_COUNT, EtGpuTotalNodeCount); + } + } +} + +BOOLEAN EtpInitializeD3DStatistics( + VOID + ) +{ + PWSTR deviceInterfaceList; + ULONG deviceInterfaceListLength = 0; + PWSTR deviceInterface; + D3DKMT_OPENADAPTERFROMDEVICENAME openAdapterFromDeviceName; + D3DKMT_QUERYSTATISTICS queryStatistics; + D3DKMT_CLOSEADAPTER closeAdapter; + + if (CM_Get_Device_Interface_List_Size( + &deviceInterfaceListLength, + (PGUID)&GUID_DISPLAY_DEVICE_ARRIVAL, + NULL, + CM_GET_DEVICE_INTERFACE_LIST_PRESENT + ) != CR_SUCCESS) + { + return FALSE; + } + + deviceInterfaceList = PhAllocate(deviceInterfaceListLength * sizeof(WCHAR)); + memset(deviceInterfaceList, 0, deviceInterfaceListLength * sizeof(WCHAR)); + + if (CM_Get_Device_Interface_List( + (PGUID)&GUID_DISPLAY_DEVICE_ARRIVAL, + NULL, + deviceInterfaceList, + deviceInterfaceListLength, + CM_GET_DEVICE_INTERFACE_LIST_PRESENT + ) != CR_SUCCESS) + { + PhFree(deviceInterfaceList); + return FALSE; + } + + for (deviceInterface = deviceInterfaceList; *deviceInterface; deviceInterface += PhCountStringZ(deviceInterface) + 1) + { + memset(&openAdapterFromDeviceName, 0, sizeof(D3DKMT_OPENADAPTERFROMDEVICENAME)); + openAdapterFromDeviceName.pDeviceName = deviceInterface; + + if (NT_SUCCESS(D3DKMTOpenAdapterFromDeviceName(&openAdapterFromDeviceName))) + { + memset(&queryStatistics, 0, sizeof(D3DKMT_QUERYSTATISTICS)); + queryStatistics.Type = D3DKMT_QUERYSTATISTICS_ADAPTER; + queryStatistics.AdapterLuid = openAdapterFromDeviceName.AdapterLuid; + + if (NT_SUCCESS(D3DKMTQueryStatistics(&queryStatistics))) + { + PETP_GPU_ADAPTER gpuAdapter; + ULONG i; + + gpuAdapter = EtpAllocateGpuAdapter(queryStatistics.QueryResult.AdapterInformation.NbSegments); + gpuAdapter->AdapterLuid = openAdapterFromDeviceName.AdapterLuid; + gpuAdapter->Description = EtpQueryDeviceDescription(deviceInterface); + gpuAdapter->NodeCount = queryStatistics.QueryResult.AdapterInformation.NodeCount; + gpuAdapter->SegmentCount = queryStatistics.QueryResult.AdapterInformation.NbSegments; + RtlInitializeBitMap(&gpuAdapter->ApertureBitMap, gpuAdapter->ApertureBitMapBuffer, queryStatistics.QueryResult.AdapterInformation.NbSegments); + + PhAddItemList(EtpGpuAdapterList, gpuAdapter); + EtGpuTotalNodeCount += gpuAdapter->NodeCount; + EtGpuTotalSegmentCount += gpuAdapter->SegmentCount; + + gpuAdapter->FirstNodeIndex = EtGpuNextNodeIndex; + EtGpuNextNodeIndex += gpuAdapter->NodeCount; + + for (i = 0; i < gpuAdapter->SegmentCount; i++) + { + memset(&queryStatistics, 0, sizeof(D3DKMT_QUERYSTATISTICS)); + queryStatistics.Type = D3DKMT_QUERYSTATISTICS_SEGMENT; + queryStatistics.AdapterLuid = gpuAdapter->AdapterLuid; + queryStatistics.QuerySegment.SegmentId = i; + + if (NT_SUCCESS(D3DKMTQueryStatistics(&queryStatistics))) + { + ULONG64 commitLimit; + ULONG aperture; + + if (WindowsVersion >= WINDOWS_8) + { + commitLimit = queryStatistics.QueryResult.SegmentInformation.CommitLimit; + aperture = queryStatistics.QueryResult.SegmentInformation.Aperture; + } + else + { + commitLimit = queryStatistics.QueryResult.SegmentInformationV1.CommitLimit; + aperture = queryStatistics.QueryResult.SegmentInformationV1.Aperture; + } + + if (aperture) + EtGpuSharedLimit += commitLimit; + else + EtGpuDedicatedLimit += commitLimit; + + if (aperture) + RtlSetBits(&gpuAdapter->ApertureBitMap, i, 1); + } + } + } + + memset(&closeAdapter, 0, sizeof(D3DKMT_CLOSEADAPTER)); + closeAdapter.hAdapter = openAdapterFromDeviceName.hAdapter; + D3DKMTCloseAdapter(&closeAdapter); + } + } + + PhFree(deviceInterfaceList); + + EtGpuNodeBitMapBuffer = PhAllocate(BYTES_NEEDED_FOR_BITS(EtGpuTotalNodeCount)); + RtlInitializeBitMap(&EtGpuNodeBitMap, EtGpuNodeBitMapBuffer, EtGpuTotalNodeCount); + RtlSetBits(&EtGpuNodeBitMap, 0, 1); + EtGpuNodeBitMapBitsSet = 1; + + return TRUE; +} + +PETP_GPU_ADAPTER EtpAllocateGpuAdapter( + _In_ ULONG NumberOfSegments + ) +{ + PETP_GPU_ADAPTER adapter; + SIZE_T sizeNeeded; + + sizeNeeded = FIELD_OFFSET(ETP_GPU_ADAPTER, ApertureBitMapBuffer); + sizeNeeded += BYTES_NEEDED_FOR_BITS(NumberOfSegments); + + adapter = PhAllocate(sizeNeeded); + memset(adapter, 0, sizeNeeded); + + return adapter; +} + +PPH_STRING EtpQueryDeviceDescription( + _In_ PWSTR DeviceInterface + ) +{ + CONFIGRET result; + PPH_STRING string; + ULONG bufferSize; + DEVPROPTYPE devicePropertyType; + DEVINST deviceInstanceHandle; + ULONG deviceInstanceIdLength = MAX_DEVICE_ID_LEN; + WCHAR deviceInstanceId[MAX_DEVICE_ID_LEN]; + + if (CM_Get_Device_Interface_Property( + DeviceInterface, + &DEVPKEY_Device_InstanceId, + &devicePropertyType, + (PBYTE)deviceInstanceId, + &deviceInstanceIdLength, + 0 + ) != CR_SUCCESS) + { + return NULL; + } + + if (CM_Locate_DevNode( + &deviceInstanceHandle, + deviceInstanceId, + CM_LOCATE_DEVNODE_NORMAL + ) != CR_SUCCESS) + { + return NULL; + } + + bufferSize = 0x40; + string = PhCreateStringEx(NULL, bufferSize); + + if ((result = CM_Get_DevNode_Property( // CM_Get_DevNode_Registry_Property with CM_DRP_DEVICEDESC?? + deviceInstanceHandle, + &DEVPKEY_Device_DeviceDesc, + &devicePropertyType, + (PBYTE)string->Buffer, + &bufferSize, + 0 + )) != CR_SUCCESS) + { + PhDereferenceObject(string); + string = PhCreateStringEx(NULL, bufferSize); + + result = CM_Get_DevNode_Property( + deviceInstanceHandle, + &DEVPKEY_Device_DeviceDesc, + &devicePropertyType, + (PBYTE)string->Buffer, + &bufferSize, + 0 + ); + } + + if (result != CR_SUCCESS) + { + PhDereferenceObject(string); + return NULL; + } + + PhTrimToNullTerminatorString(string); + + return string; +} + +VOID EtpUpdateSegmentInformation( + _In_opt_ PET_PROCESS_BLOCK Block + ) +{ + ULONG i; + ULONG j; + PETP_GPU_ADAPTER gpuAdapter; + D3DKMT_QUERYSTATISTICS queryStatistics; + ULONG64 dedicatedUsage; + ULONG64 sharedUsage; + + if (Block && !Block->ProcessItem->QueryHandle) + return; + + dedicatedUsage = 0; + sharedUsage = 0; + + for (i = 0; i < EtpGpuAdapterList->Count; i++) + { + gpuAdapter = EtpGpuAdapterList->Items[i]; + + for (j = 0; j < gpuAdapter->SegmentCount; j++) + { + memset(&queryStatistics, 0, sizeof(D3DKMT_QUERYSTATISTICS)); + + if (Block) + queryStatistics.Type = D3DKMT_QUERYSTATISTICS_PROCESS_SEGMENT; + else + queryStatistics.Type = D3DKMT_QUERYSTATISTICS_SEGMENT; + + queryStatistics.AdapterLuid = gpuAdapter->AdapterLuid; + + if (Block) + { + queryStatistics.hProcess = Block->ProcessItem->QueryHandle; + queryStatistics.QueryProcessSegment.SegmentId = j; + } + else + { + queryStatistics.QuerySegment.SegmentId = j; + } + + if (NT_SUCCESS(D3DKMTQueryStatistics(&queryStatistics))) + { + if (Block) + { + ULONG64 bytesCommitted; + + if (WindowsVersion >= WINDOWS_8) + { + bytesCommitted = queryStatistics.QueryResult.ProcessSegmentInformation.BytesCommitted; + } + else + { + bytesCommitted = (ULONG)queryStatistics.QueryResult.ProcessSegmentInformation.BytesCommitted; + } + + if (RtlCheckBit(&gpuAdapter->ApertureBitMap, j)) + sharedUsage += bytesCommitted; + else + dedicatedUsage += bytesCommitted; + } + else + { + ULONG64 bytesCommitted; + + if (WindowsVersion >= WINDOWS_8) + { + bytesCommitted = queryStatistics.QueryResult.SegmentInformation.BytesResident; + } + else + { + bytesCommitted = queryStatistics.QueryResult.SegmentInformationV1.BytesResident; + } + + if (RtlCheckBit(&gpuAdapter->ApertureBitMap, j)) + sharedUsage += bytesCommitted; + else + dedicatedUsage += bytesCommitted; + } + } + } + } + + if (Block) + { + Block->GpuDedicatedUsage = dedicatedUsage; + Block->GpuSharedUsage = sharedUsage; + } + else + { + EtGpuDedicatedUsage = dedicatedUsage; + EtGpuSharedUsage = sharedUsage; + } +} + +VOID EtpUpdateNodeInformation( + _In_opt_ PET_PROCESS_BLOCK Block + ) +{ + ULONG i; + ULONG j; + PETP_GPU_ADAPTER gpuAdapter; + D3DKMT_QUERYSTATISTICS queryStatistics; + ULONG64 totalRunningTime; + ULONG64 systemRunningTime; + + if (Block && !Block->ProcessItem->QueryHandle) + return; + + totalRunningTime = 0; + systemRunningTime = 0; + + for (i = 0; i < EtpGpuAdapterList->Count; i++) + { + gpuAdapter = EtpGpuAdapterList->Items[i]; + + for (j = 0; j < gpuAdapter->NodeCount; j++) + { + if (Block && !RtlCheckBit(&EtGpuNodeBitMap, gpuAdapter->FirstNodeIndex + j)) + continue; + + memset(&queryStatistics, 0, sizeof(D3DKMT_QUERYSTATISTICS)); + + if (Block) + queryStatistics.Type = D3DKMT_QUERYSTATISTICS_PROCESS_NODE; + else + queryStatistics.Type = D3DKMT_QUERYSTATISTICS_NODE; + + queryStatistics.AdapterLuid = gpuAdapter->AdapterLuid; + + if (Block) + { + queryStatistics.hProcess = Block->ProcessItem->QueryHandle; + queryStatistics.QueryProcessNode.NodeId = j; + } + else + { + queryStatistics.QueryNode.NodeId = j; + } + + if (NT_SUCCESS(D3DKMTQueryStatistics(&queryStatistics))) + { + if (Block) + { + totalRunningTime += queryStatistics.QueryResult.ProcessNodeInformation.RunningTime.QuadPart; + } + else + { + ULONG nodeIndex; + + nodeIndex = gpuAdapter->FirstNodeIndex + j; + + PhUpdateDelta(&EtGpuNodesTotalRunningTimeDelta[nodeIndex], queryStatistics.QueryResult.NodeInformation.GlobalInformation.RunningTime.QuadPart); + + if (RtlCheckBit(&EtGpuNodeBitMap, gpuAdapter->FirstNodeIndex + j)) + { + totalRunningTime += queryStatistics.QueryResult.NodeInformation.GlobalInformation.RunningTime.QuadPart; + systemRunningTime += queryStatistics.QueryResult.NodeInformation.SystemInformation.RunningTime.QuadPart; + } + } + } + } + } + + if (Block) + { + PhUpdateDelta(&Block->GpuRunningTimeDelta, totalRunningTime); + } + else + { + LARGE_INTEGER performanceCounter; + + NtQueryPerformanceCounter(&performanceCounter, &EtClockTotalRunningTimeFrequency); + PhUpdateDelta(&EtClockTotalRunningTimeDelta, performanceCounter.QuadPart); + PhUpdateDelta(&EtGpuTotalRunningTimeDelta, totalRunningTime); + PhUpdateDelta(&EtGpuSystemRunningTimeDelta, systemRunningTime); + } +} + +VOID NTAPI EtGpuProcessesUpdatedCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + static ULONG runCount = 0; // MUST keep in sync with runCount in process provider + + DOUBLE elapsedTime; // total GPU node elapsed time in micro-seconds + ULONG i; + PLIST_ENTRY listEntry; + FLOAT maxNodeValue = 0; + PET_PROCESS_BLOCK maxNodeBlock = NULL; + + // Update global statistics. + + EtpUpdateSegmentInformation(NULL); + EtpUpdateNodeInformation(NULL); + + elapsedTime = (DOUBLE)EtClockTotalRunningTimeDelta.Delta * 10000000 / EtClockTotalRunningTimeFrequency.QuadPart; + + if (elapsedTime != 0) + EtGpuNodeUsage = (FLOAT)(EtGpuTotalRunningTimeDelta.Delta / (elapsedTime * EtGpuNodeBitMapBitsSet)); + else + EtGpuNodeUsage = 0; + + if (EtGpuNodeUsage > 1) + EtGpuNodeUsage = 1; + + // Do the update of the node bitmap if needed. + if (EtGpuNewNodeBitMapBuffer) + { + PULONG newBuffer; + + newBuffer = _InterlockedExchangePointer(&EtGpuNewNodeBitMapBuffer, NULL); + + if (newBuffer) + { + PhFree(EtGpuNodeBitMap.Buffer); + EtGpuNodeBitMap.Buffer = newBuffer; + EtGpuNodeBitMapBuffer = newBuffer; + EtGpuNodeBitMapBitsSet = RtlNumberOfSetBits(&EtGpuNodeBitMap); + EtSaveGpuMonitorSettings(); + } + } + + // Update per-process statistics. + // Note: no lock is needed because we only ever modify the list on this same thread. + + listEntry = EtProcessBlockListHead.Flink; + + while (listEntry != &EtProcessBlockListHead) + { + PET_PROCESS_BLOCK block; + + block = CONTAINING_RECORD(listEntry, ET_PROCESS_BLOCK, ListEntry); + + EtpUpdateSegmentInformation(block); + EtpUpdateNodeInformation(block); + + if (elapsedTime != 0) + { + block->GpuNodeUsage = (FLOAT)(block->GpuRunningTimeDelta.Delta / (elapsedTime * EtGpuNodeBitMapBitsSet)); + + if (block->GpuNodeUsage > 1) + block->GpuNodeUsage = 1; + } + + if (maxNodeValue < block->GpuNodeUsage) + { + maxNodeValue = block->GpuNodeUsage; + maxNodeBlock = block; + } + + listEntry = listEntry->Flink; + } + + // Update history buffers. + + if (runCount != 0) + { + PhAddItemCircularBuffer_FLOAT(&EtGpuNodeHistory, EtGpuNodeUsage); + PhAddItemCircularBuffer_ULONG(&EtGpuDedicatedHistory, (ULONG)(EtGpuDedicatedUsage / PAGE_SIZE)); + PhAddItemCircularBuffer_ULONG(&EtGpuSharedHistory, (ULONG)(EtGpuSharedUsage / PAGE_SIZE)); + + for (i = 0; i < EtGpuTotalNodeCount; i++) + { + FLOAT usage; + + usage = (FLOAT)(EtGpuNodesTotalRunningTimeDelta[i].Delta / elapsedTime); + + if (usage > 1) + usage = 1; + + PhAddItemCircularBuffer_FLOAT(&EtGpuNodesHistory[i], usage); + } + + if (maxNodeBlock) + { + PhAddItemCircularBuffer_ULONG(&EtMaxGpuNodeHistory, HandleToUlong(maxNodeBlock->ProcessItem->ProcessId)); + PhAddItemCircularBuffer_FLOAT(&EtMaxGpuNodeUsageHistory, maxNodeBlock->GpuNodeUsage); + PhReferenceProcessRecordForStatistics(maxNodeBlock->ProcessItem->Record); + } + else + { + PhAddItemCircularBuffer_ULONG(&EtMaxGpuNodeHistory, 0); + PhAddItemCircularBuffer_FLOAT(&EtMaxGpuNodeUsageHistory, 0); + } + } + + runCount++; +} + +VOID EtSaveGpuMonitorSettings( + VOID + ) +{ + PPH_STRING string; + + string = PhBufferToHexString((PUCHAR)EtGpuNodeBitMapBuffer, BYTES_NEEDED_FOR_BITS(EtGpuTotalNodeCount)); + PhSetStringSetting2(SETTING_NAME_GPU_NODE_BITMAP, &string->sr); + PhDereferenceObject(string); +} + +ULONG EtGetGpuAdapterCount( + VOID + ) +{ + return EtpGpuAdapterList->Count; +} + +ULONG EtGetGpuAdapterIndexFromNodeIndex( + _In_ ULONG NodeIndex + ) +{ + ULONG i; + PETP_GPU_ADAPTER gpuAdapter; + + for (i = 0; i < EtpGpuAdapterList->Count; i++) + { + gpuAdapter = EtpGpuAdapterList->Items[i]; + + if (NodeIndex >= gpuAdapter->FirstNodeIndex && NodeIndex < gpuAdapter->FirstNodeIndex + gpuAdapter->NodeCount) + return i; + } + + return -1; +} + +PPH_STRING EtGetGpuAdapterDescription( + _In_ ULONG Index + ) +{ + PPH_STRING description; + + if (Index >= EtpGpuAdapterList->Count) + return NULL; + + description = ((PETP_GPU_ADAPTER)EtpGpuAdapterList->Items[Index])->Description; + + if (description) + { + PhReferenceObject(description); + return description; + } + else + { + return NULL; + } +} + +VOID EtAllocateGpuNodeBitMap( + _Out_ PRTL_BITMAP BitMap + ) +{ + SIZE_T numberOfBytes; + + numberOfBytes = BYTES_NEEDED_FOR_BITS(EtGpuTotalNodeCount); + + BitMap->Buffer = PhAllocate(numberOfBytes); + BitMap->SizeOfBitMap = EtGpuTotalNodeCount; + memset(BitMap->Buffer, 0, numberOfBytes); +} + +VOID EtUpdateGpuNodeBitMap( + _In_ PRTL_BITMAP NewBitMap + ) +{ + PULONG buffer; + + buffer = _InterlockedExchangePointer(&EtGpuNewNodeBitMapBuffer, NewBitMap->Buffer); + + if (buffer) + PhFree(buffer); +} + +VOID EtQueryProcessGpuStatistics( + _In_ HANDLE ProcessHandle, + _Out_ PET_PROCESS_GPU_STATISTICS Statistics + ) +{ + NTSTATUS status; + ULONG i; + ULONG j; + PETP_GPU_ADAPTER gpuAdapter; + D3DKMT_QUERYSTATISTICS queryStatistics; + + memset(Statistics, 0, sizeof(ET_PROCESS_GPU_STATISTICS)); + + for (i = 0; i < EtpGpuAdapterList->Count; i++) + { + gpuAdapter = EtpGpuAdapterList->Items[i]; + + Statistics->SegmentCount += gpuAdapter->SegmentCount; + Statistics->NodeCount += gpuAdapter->NodeCount; + + for (j = 0; j < gpuAdapter->SegmentCount; j++) + { + memset(&queryStatistics, 0, sizeof(D3DKMT_QUERYSTATISTICS)); + queryStatistics.Type = D3DKMT_QUERYSTATISTICS_PROCESS_SEGMENT; + queryStatistics.AdapterLuid = gpuAdapter->AdapterLuid; + queryStatistics.hProcess = ProcessHandle; + queryStatistics.QueryProcessSegment.SegmentId = j; + + if (NT_SUCCESS(status = D3DKMTQueryStatistics(&queryStatistics))) + { + ULONG64 bytesCommitted; + + if (WindowsVersion >= WINDOWS_8) + { + bytesCommitted = queryStatistics.QueryResult.ProcessSegmentInformation.BytesCommitted; + } + else + { + bytesCommitted = (ULONG)queryStatistics.QueryResult.ProcessSegmentInformation.BytesCommitted; + } + + if (RtlCheckBit(&gpuAdapter->ApertureBitMap, j)) + Statistics->SharedCommitted += bytesCommitted; + else + Statistics->DedicatedCommitted += bytesCommitted; + } + } + + for (j = 0; j < gpuAdapter->NodeCount; j++) + { + memset(&queryStatistics, 0, sizeof(D3DKMT_QUERYSTATISTICS)); + queryStatistics.Type = D3DKMT_QUERYSTATISTICS_PROCESS_NODE; + queryStatistics.AdapterLuid = gpuAdapter->AdapterLuid; + queryStatistics.hProcess = ProcessHandle; + queryStatistics.QueryProcessNode.NodeId = j; + + if (NT_SUCCESS(D3DKMTQueryStatistics(&queryStatistics))) + { + Statistics->RunningTime += queryStatistics.QueryResult.ProcessNodeInformation.RunningTime.QuadPart; + Statistics->ContextSwitches += queryStatistics.QueryResult.ProcessNodeInformation.ContextSwitch; + } + } + + memset(&queryStatistics, 0, sizeof(D3DKMT_QUERYSTATISTICS)); + queryStatistics.Type = D3DKMT_QUERYSTATISTICS_PROCESS; + queryStatistics.AdapterLuid = gpuAdapter->AdapterLuid; + queryStatistics.hProcess = ProcessHandle; + + if (NT_SUCCESS(D3DKMTQueryStatistics(&queryStatistics))) + { + Statistics->BytesAllocated += queryStatistics.QueryResult.ProcessInformation.SystemMemory.BytesAllocated; + Statistics->BytesReserved += queryStatistics.QueryResult.ProcessInformation.SystemMemory.BytesReserved; + Statistics->WriteCombinedBytesAllocated += queryStatistics.QueryResult.ProcessInformation.SystemMemory.WriteCombinedBytesAllocated; + Statistics->WriteCombinedBytesReserved += queryStatistics.QueryResult.ProcessInformation.SystemMemory.WriteCombinedBytesReserved; + Statistics->CachedBytesAllocated += queryStatistics.QueryResult.ProcessInformation.SystemMemory.CachedBytesAllocated; + Statistics->CachedBytesReserved += queryStatistics.QueryResult.ProcessInformation.SystemMemory.CachedBytesReserved; + Statistics->SectionBytesAllocated += queryStatistics.QueryResult.ProcessInformation.SystemMemory.SectionBytesAllocated; + Statistics->SectionBytesReserved += queryStatistics.QueryResult.ProcessInformation.SystemMemory.SectionBytesReserved; + } + } +} diff --git a/plugins/ExtendedTools/gpumon.h b/plugins/ExtendedTools/gpumon.h index 3643a0bf7a62..0ec6f15f23c0 100644 --- a/plugins/ExtendedTools/gpumon.h +++ b/plugins/ExtendedTools/gpumon.h @@ -1,43 +1,43 @@ -#ifndef GPUMON_H -#define GPUMON_H - -// Macros - -#define BYTES_NEEDED_FOR_BITS(Bits) ((((Bits) + sizeof(ULONG) * 8 - 1) / 8) & ~(SIZE_T)(sizeof(ULONG) - 1)) // divide round up - -// Structures - -typedef struct _ETP_GPU_ADAPTER -{ - LUID AdapterLuid; - PPH_STRING Description; - ULONG SegmentCount; - ULONG NodeCount; - ULONG FirstNodeIndex; - - BOOLEAN HasActivity; - - RTL_BITMAP ApertureBitMap; - ULONG ApertureBitMapBuffer[1]; -} ETP_GPU_ADAPTER, *PETP_GPU_ADAPTER; - -// Functions - -BOOLEAN EtpInitializeD3DStatistics( - VOID - ); - -PETP_GPU_ADAPTER EtpAllocateGpuAdapter( - _In_ ULONG NumberOfSegments - ); - -PPH_STRING EtpQueryDeviceDescription( - _In_ PWSTR DeviceInterface - ); - -VOID NTAPI EtGpuProcessesUpdatedCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ); - -#endif +#ifndef GPUMON_H +#define GPUMON_H + +// Macros + +#define BYTES_NEEDED_FOR_BITS(Bits) ((((Bits) + sizeof(ULONG) * 8 - 1) / 8) & ~(SIZE_T)(sizeof(ULONG) - 1)) // divide round up + +// Structures + +typedef struct _ETP_GPU_ADAPTER +{ + LUID AdapterLuid; + PPH_STRING Description; + ULONG SegmentCount; + ULONG NodeCount; + ULONG FirstNodeIndex; + + BOOLEAN HasActivity; + + RTL_BITMAP ApertureBitMap; + ULONG ApertureBitMapBuffer[1]; +} ETP_GPU_ADAPTER, *PETP_GPU_ADAPTER; + +// Functions + +BOOLEAN EtpInitializeD3DStatistics( + VOID + ); + +PETP_GPU_ADAPTER EtpAllocateGpuAdapter( + _In_ ULONG NumberOfSegments + ); + +PPH_STRING EtpQueryDeviceDescription( + _In_ PWSTR DeviceInterface + ); + +VOID NTAPI EtGpuProcessesUpdatedCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ); + +#endif diff --git a/plugins/ExtendedTools/gpunodes.c b/plugins/ExtendedTools/gpunodes.c index 65fb6e141816..bc863cb45bc2 100644 --- a/plugins/ExtendedTools/gpunodes.c +++ b/plugins/ExtendedTools/gpunodes.c @@ -1,430 +1,430 @@ -/* - * Process Hacker Extended Tools - - * GPU nodes window - * - * Copyright (C) 2011-2015 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include "exttools.h" - -#define GRAPH_PADDING 5 -#define CHECKBOX_PADDING 3 - -INT_PTR CALLBACK EtpGpuNodesDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -static HWND WindowHandle; -static RECT MinimumSize; -static PH_LAYOUT_MANAGER LayoutManager; -static RECT LayoutMargin; -static HWND *GraphHandle; -static HWND *CheckBoxHandle; -static PPH_GRAPH_STATE GraphState; -static PPH_SYSINFO_PARAMETERS SysInfoParameters; -static PH_CALLBACK_REGISTRATION ProcessesUpdatedCallbackRegistration; - -VOID EtShowGpuNodesDialog( - _In_ HWND ParentWindowHandle, - _In_ PPH_SYSINFO_PARAMETERS Parameters - ) -{ - SysInfoParameters = Parameters; - DialogBox( - PluginInstance->DllBase, - MAKEINTRESOURCE(IDD_GPUNODES), - ParentWindowHandle, - EtpGpuNodesDlgProc - ); -} - -static VOID ProcessesUpdatedCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - PostMessage(WindowHandle, UPDATE_MSG, 0, 0); -} - -VOID EtpLoadNodeBitMap( - VOID - ) -{ - ULONG i; - - for (i = 0; i < EtGpuTotalNodeCount; i++) - { - Button_SetCheck( - CheckBoxHandle[i], - RtlCheckBit(&EtGpuNodeBitMap, i) ? BST_CHECKED : BST_UNCHECKED - ); - } -} - -VOID EtpSaveNodeBitMap( - VOID - ) -{ - RTL_BITMAP newBitMap; - ULONG i; - - EtAllocateGpuNodeBitMap(&newBitMap); - - for (i = 0; i < EtGpuTotalNodeCount; i++) - { - if (Button_GetCheck(CheckBoxHandle[i]) == BST_CHECKED) - RtlSetBits(&newBitMap, i, 1); - } - - if (RtlNumberOfSetBits(&newBitMap) == 0) - RtlSetBits(&newBitMap, 0, 1); - - EtUpdateGpuNodeBitMap(&newBitMap); -} - -INT_PTR CALLBACK EtpGpuNodesDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - switch (uMsg) - { - case WM_INITDIALOG: - { - ULONG i; - HFONT font; - PPH_STRING nodeString; - RECT labelRect; - RECT tempRect; - ULONG numberOfRows; - ULONG numberOfColumns; - - WindowHandle = hwndDlg; - - PhInitializeLayoutManager(&LayoutManager, hwndDlg); - PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDOK), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); - LayoutMargin = PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDC_LAYOUT), NULL, PH_ANCHOR_ALL)->Margin; - - PhRegisterCallback(&PhProcessesUpdatedEvent, ProcessesUpdatedCallback, NULL, &ProcessesUpdatedCallbackRegistration); - - GraphHandle = PhAllocate(sizeof(HWND) * EtGpuTotalNodeCount); - CheckBoxHandle = PhAllocate(sizeof(HWND) * EtGpuTotalNodeCount); - GraphState = PhAllocate(sizeof(PH_GRAPH_STATE) * EtGpuTotalNodeCount); - - font = (HFONT)SendMessage(hwndDlg, WM_GETFONT, 0, 0); - - for (i = 0; i < EtGpuTotalNodeCount; i++) - { - nodeString = PhFormatString(L"Node %lu", i); - - GraphHandle[i] = CreateWindow( - PH_GRAPH_CLASSNAME, - NULL, - WS_VISIBLE | WS_CHILD | WS_BORDER, - 0, - 0, - 3, - 3, - hwndDlg, - NULL, - NULL, - NULL - ); - Graph_SetTooltip(GraphHandle[i], TRUE); - CheckBoxHandle[i] = CreateWindow( - WC_BUTTON, - nodeString->Buffer, - WS_VISIBLE | WS_CHILD | BS_AUTOCHECKBOX, - 0, - 0, - 3, - 3, - hwndDlg, - NULL, - NULL, - NULL - ); - SendMessage(CheckBoxHandle[i], WM_SETFONT, (WPARAM)font, FALSE); - PhInitializeGraphState(&GraphState[i]); - - PhDereferenceObject(nodeString); - } - - // Calculate the minimum size. - - numberOfRows = (ULONG)sqrt(EtGpuTotalNodeCount); - numberOfColumns = (EtGpuTotalNodeCount + numberOfRows - 1) / numberOfRows; - - MinimumSize.left = 0; - MinimumSize.top = 0; - MinimumSize.right = 55; - MinimumSize.bottom = 60; - MapDialogRect(hwndDlg, &MinimumSize); - MinimumSize.right += (MinimumSize.right + GRAPH_PADDING) * numberOfColumns; - MinimumSize.bottom += (MinimumSize.bottom + GRAPH_PADDING) * numberOfRows; - - GetWindowRect(GetDlgItem(hwndDlg, IDC_INSTRUCTION), &labelRect); - MapWindowPoints(NULL, hwndDlg, (POINT *)&labelRect, 2); - labelRect.right += GetSystemMetrics(SM_CXFRAME) * 2; - - tempRect.left = 0; - tempRect.top = 0; - tempRect.right = 7; - tempRect.bottom = 0; - MapDialogRect(hwndDlg, &tempRect); - labelRect.right += tempRect.right; - - if (MinimumSize.right < labelRect.right) - MinimumSize.right = labelRect.right; - - SetWindowPos(hwndDlg, NULL, 0, 0, MinimumSize.right, MinimumSize.bottom, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER); - - // Note: This dialog must be centered after all other graphs and controls have been added. - PhCenterWindow(hwndDlg, GetParent(hwndDlg)); - - EtpLoadNodeBitMap(); - } - break; - case WM_DESTROY: - { - ULONG i; - - EtpSaveNodeBitMap(); - - PhUnregisterCallback(&PhProcessesUpdatedEvent, &ProcessesUpdatedCallbackRegistration); - - for (i = 0; i < EtGpuTotalNodeCount; i++) - { - PhDeleteGraphState(&GraphState[i]); - } - - PhFree(GraphHandle); - PhFree(CheckBoxHandle); - PhFree(GraphState); - - PhDeleteLayoutManager(&LayoutManager); - } - break; - case WM_SIZE: - { - HDWP deferHandle; - RECT clientRect; - RECT checkBoxRect; - ULONG numberOfRows = (ULONG)sqrt(EtGpuTotalNodeCount); - ULONG numberOfColumns = (EtGpuTotalNodeCount + numberOfRows - 1) / numberOfRows; - ULONG numberOfYPaddings = numberOfRows - 1; - ULONG numberOfXPaddings = numberOfColumns - 1; - ULONG cellHeight; - ULONG y; - ULONG cellWidth; - ULONG x; - ULONG i; - - PhLayoutManagerLayout(&LayoutManager); - - deferHandle = BeginDeferWindowPos(EtGpuTotalNodeCount * 2); - - GetClientRect(hwndDlg, &clientRect); - GetClientRect(GetDlgItem(hwndDlg, IDC_EXAMPLE), &checkBoxRect); - cellHeight = (clientRect.bottom - LayoutMargin.top - LayoutMargin.bottom - GRAPH_PADDING * numberOfYPaddings) / numberOfRows; - y = LayoutMargin.top; - i = 0; - - for (ULONG row = 0; row < numberOfRows; ++row) - { - // Give the last row the remaining space; the height we calculated might be off by a few - // pixels due to integer division. - if (row == numberOfRows - 1) - cellHeight = clientRect.bottom - LayoutMargin.bottom - y; - - cellWidth = (clientRect.right - LayoutMargin.left - LayoutMargin.right - GRAPH_PADDING * numberOfXPaddings) / numberOfColumns; - x = LayoutMargin.left; - - for (ULONG column = 0; column < numberOfColumns; column++) - { - // Give the last cell the remaining space; the width we calculated might be off by a few - // pixels due to integer division. - if (column == numberOfColumns - 1) - cellWidth = clientRect.right - LayoutMargin.right - x; - - if (i < EtGpuTotalNodeCount) - { - deferHandle = DeferWindowPos( - deferHandle, - GraphHandle[i], - NULL, - x, - y, - cellWidth, - cellHeight - checkBoxRect.bottom - CHECKBOX_PADDING, - SWP_NOACTIVATE | SWP_NOZORDER - ); - deferHandle = DeferWindowPos( - deferHandle, - CheckBoxHandle[i], - NULL, - x, - y + cellHeight - checkBoxRect.bottom, - cellWidth, - checkBoxRect.bottom, - SWP_NOACTIVATE | SWP_NOZORDER - ); - i++; - } - x += cellWidth + GRAPH_PADDING; - } - - y += cellHeight + GRAPH_PADDING; - } - - EndDeferWindowPos(deferHandle); - } - break; - case WM_SIZING: - { - PhResizingMinimumSize((PRECT)lParam, wParam, MinimumSize.right, MinimumSize.bottom); - } - break; - case WM_COMMAND: - { - switch (LOWORD(wParam)) - { - case IDCANCEL: - case IDOK: - { - EndDialog(hwndDlg, IDOK); - } - break; - } - } - break; - case WM_NOTIFY: - { - NMHDR *header = (NMHDR *)lParam; - ULONG i; - - switch (header->code) - { - case GCN_GETDRAWINFO: - { - PPH_GRAPH_GETDRAWINFO getDrawInfo = (PPH_GRAPH_GETDRAWINFO)header; - PPH_GRAPH_DRAW_INFO drawInfo = getDrawInfo->DrawInfo; - - drawInfo->Flags = PH_GRAPH_USE_GRID_X | PH_GRAPH_USE_GRID_Y; - SysInfoParameters->ColorSetupFunction(drawInfo, PhGetIntegerSetting(L"ColorCpuKernel"), 0); - - for (i = 0; i < EtGpuTotalNodeCount; i++) - { - if (header->hwndFrom == GraphHandle[i]) - { - PhGraphStateGetDrawInfo( - &GraphState[i], - getDrawInfo, - EtGpuNodesHistory[i].Count - ); - - if (!GraphState[i].Valid) - { - PhCopyCircularBuffer_FLOAT(&EtGpuNodesHistory[i], GraphState[i].Data1, drawInfo->LineDataCount); - GraphState[i].Valid = TRUE; - } - - break; - } - } - } - break; - case GCN_GETTOOLTIPTEXT: - { - PPH_GRAPH_GETTOOLTIPTEXT getTooltipText = (PPH_GRAPH_GETTOOLTIPTEXT)header; - - if (getTooltipText->Index < getTooltipText->TotalCount) - { - for (i = 0; i < EtGpuTotalNodeCount; i++) - { - if (header->hwndFrom == GraphHandle[i]) - { - if (GraphState[i].TooltipIndex != getTooltipText->Index) - { - FLOAT gpu; - ULONG adapterIndex; - PPH_STRING adapterDescription; - - gpu = PhGetItemCircularBuffer_FLOAT(&EtGpuNodesHistory[i], getTooltipText->Index); - adapterIndex = EtGetGpuAdapterIndexFromNodeIndex(i); - - if (adapterIndex != -1) - { - adapterDescription = EtGetGpuAdapterDescription(adapterIndex); - - if (adapterDescription && adapterDescription->Length == 0) - PhClearReference(&adapterDescription); - - if (!adapterDescription) - adapterDescription = PhFormatString(L"Adapter %lu", adapterIndex); - } - else - { - adapterDescription = PhCreateString(L"Unknown Adapter"); - } - - PhMoveReference(&GraphState[i].TooltipText, PhFormatString( - L"Node %lu on %s\n%.2f%%\n%s", - i, - adapterDescription->Buffer, - gpu * 100, - ((PPH_STRING)PH_AUTO(PhGetStatisticsTimeString(NULL, getTooltipText->Index)))->Buffer - )); - PhDereferenceObject(adapterDescription); - } - - getTooltipText->Text = GraphState[i].TooltipText->sr; - - break; - } - } - } - } - break; - } - } - break; - case UPDATE_MSG: - { - ULONG i; - - for (i = 0; i < EtGpuTotalNodeCount; i++) - { - GraphState[i].Valid = FALSE; - GraphState[i].TooltipIndex = -1; - Graph_MoveGrid(GraphHandle[i], 1); - Graph_Draw(GraphHandle[i]); - Graph_UpdateTooltip(GraphHandle[i]); - InvalidateRect(GraphHandle[i], NULL, FALSE); - } - } - break; - } - - return FALSE; -} +/* + * Process Hacker Extended Tools - + * GPU nodes window + * + * Copyright (C) 2011-2015 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include "exttools.h" + +#define GRAPH_PADDING 5 +#define CHECKBOX_PADDING 3 + +INT_PTR CALLBACK EtpGpuNodesDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +static HWND WindowHandle; +static RECT MinimumSize; +static PH_LAYOUT_MANAGER LayoutManager; +static RECT LayoutMargin; +static HWND *GraphHandle; +static HWND *CheckBoxHandle; +static PPH_GRAPH_STATE GraphState; +static PPH_SYSINFO_PARAMETERS SysInfoParameters; +static PH_CALLBACK_REGISTRATION ProcessesUpdatedCallbackRegistration; + +VOID EtShowGpuNodesDialog( + _In_ HWND ParentWindowHandle, + _In_ PPH_SYSINFO_PARAMETERS Parameters + ) +{ + SysInfoParameters = Parameters; + DialogBox( + PluginInstance->DllBase, + MAKEINTRESOURCE(IDD_GPUNODES), + ParentWindowHandle, + EtpGpuNodesDlgProc + ); +} + +static VOID ProcessesUpdatedCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + PostMessage(WindowHandle, UPDATE_MSG, 0, 0); +} + +VOID EtpLoadNodeBitMap( + VOID + ) +{ + ULONG i; + + for (i = 0; i < EtGpuTotalNodeCount; i++) + { + Button_SetCheck( + CheckBoxHandle[i], + RtlCheckBit(&EtGpuNodeBitMap, i) ? BST_CHECKED : BST_UNCHECKED + ); + } +} + +VOID EtpSaveNodeBitMap( + VOID + ) +{ + RTL_BITMAP newBitMap; + ULONG i; + + EtAllocateGpuNodeBitMap(&newBitMap); + + for (i = 0; i < EtGpuTotalNodeCount; i++) + { + if (Button_GetCheck(CheckBoxHandle[i]) == BST_CHECKED) + RtlSetBits(&newBitMap, i, 1); + } + + if (RtlNumberOfSetBits(&newBitMap) == 0) + RtlSetBits(&newBitMap, 0, 1); + + EtUpdateGpuNodeBitMap(&newBitMap); +} + +INT_PTR CALLBACK EtpGpuNodesDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + switch (uMsg) + { + case WM_INITDIALOG: + { + ULONG i; + HFONT font; + PPH_STRING nodeString; + RECT labelRect; + RECT tempRect; + ULONG numberOfRows; + ULONG numberOfColumns; + + WindowHandle = hwndDlg; + + PhInitializeLayoutManager(&LayoutManager, hwndDlg); + PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDOK), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); + LayoutMargin = PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDC_LAYOUT), NULL, PH_ANCHOR_ALL)->Margin; + + PhRegisterCallback(&PhProcessesUpdatedEvent, ProcessesUpdatedCallback, NULL, &ProcessesUpdatedCallbackRegistration); + + GraphHandle = PhAllocate(sizeof(HWND) * EtGpuTotalNodeCount); + CheckBoxHandle = PhAllocate(sizeof(HWND) * EtGpuTotalNodeCount); + GraphState = PhAllocate(sizeof(PH_GRAPH_STATE) * EtGpuTotalNodeCount); + + font = (HFONT)SendMessage(hwndDlg, WM_GETFONT, 0, 0); + + for (i = 0; i < EtGpuTotalNodeCount; i++) + { + nodeString = PhFormatString(L"Node %lu", i); + + GraphHandle[i] = CreateWindow( + PH_GRAPH_CLASSNAME, + NULL, + WS_VISIBLE | WS_CHILD | WS_BORDER, + 0, + 0, + 3, + 3, + hwndDlg, + NULL, + NULL, + NULL + ); + Graph_SetTooltip(GraphHandle[i], TRUE); + CheckBoxHandle[i] = CreateWindow( + WC_BUTTON, + nodeString->Buffer, + WS_VISIBLE | WS_CHILD | BS_AUTOCHECKBOX, + 0, + 0, + 3, + 3, + hwndDlg, + NULL, + NULL, + NULL + ); + SendMessage(CheckBoxHandle[i], WM_SETFONT, (WPARAM)font, FALSE); + PhInitializeGraphState(&GraphState[i]); + + PhDereferenceObject(nodeString); + } + + // Calculate the minimum size. + + numberOfRows = (ULONG)sqrt(EtGpuTotalNodeCount); + numberOfColumns = (EtGpuTotalNodeCount + numberOfRows - 1) / numberOfRows; + + MinimumSize.left = 0; + MinimumSize.top = 0; + MinimumSize.right = 55; + MinimumSize.bottom = 60; + MapDialogRect(hwndDlg, &MinimumSize); + MinimumSize.right += (MinimumSize.right + GRAPH_PADDING) * numberOfColumns; + MinimumSize.bottom += (MinimumSize.bottom + GRAPH_PADDING) * numberOfRows; + + GetWindowRect(GetDlgItem(hwndDlg, IDC_INSTRUCTION), &labelRect); + MapWindowPoints(NULL, hwndDlg, (POINT *)&labelRect, 2); + labelRect.right += GetSystemMetrics(SM_CXFRAME) * 2; + + tempRect.left = 0; + tempRect.top = 0; + tempRect.right = 7; + tempRect.bottom = 0; + MapDialogRect(hwndDlg, &tempRect); + labelRect.right += tempRect.right; + + if (MinimumSize.right < labelRect.right) + MinimumSize.right = labelRect.right; + + SetWindowPos(hwndDlg, NULL, 0, 0, MinimumSize.right, MinimumSize.bottom, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER); + + // Note: This dialog must be centered after all other graphs and controls have been added. + PhCenterWindow(hwndDlg, GetParent(hwndDlg)); + + EtpLoadNodeBitMap(); + } + break; + case WM_DESTROY: + { + ULONG i; + + EtpSaveNodeBitMap(); + + PhUnregisterCallback(&PhProcessesUpdatedEvent, &ProcessesUpdatedCallbackRegistration); + + for (i = 0; i < EtGpuTotalNodeCount; i++) + { + PhDeleteGraphState(&GraphState[i]); + } + + PhFree(GraphHandle); + PhFree(CheckBoxHandle); + PhFree(GraphState); + + PhDeleteLayoutManager(&LayoutManager); + } + break; + case WM_SIZE: + { + HDWP deferHandle; + RECT clientRect; + RECT checkBoxRect; + ULONG numberOfRows = (ULONG)sqrt(EtGpuTotalNodeCount); + ULONG numberOfColumns = (EtGpuTotalNodeCount + numberOfRows - 1) / numberOfRows; + ULONG numberOfYPaddings = numberOfRows - 1; + ULONG numberOfXPaddings = numberOfColumns - 1; + ULONG cellHeight; + ULONG y; + ULONG cellWidth; + ULONG x; + ULONG i; + + PhLayoutManagerLayout(&LayoutManager); + + deferHandle = BeginDeferWindowPos(EtGpuTotalNodeCount * 2); + + GetClientRect(hwndDlg, &clientRect); + GetClientRect(GetDlgItem(hwndDlg, IDC_EXAMPLE), &checkBoxRect); + cellHeight = (clientRect.bottom - LayoutMargin.top - LayoutMargin.bottom - GRAPH_PADDING * numberOfYPaddings) / numberOfRows; + y = LayoutMargin.top; + i = 0; + + for (ULONG row = 0; row < numberOfRows; ++row) + { + // Give the last row the remaining space; the height we calculated might be off by a few + // pixels due to integer division. + if (row == numberOfRows - 1) + cellHeight = clientRect.bottom - LayoutMargin.bottom - y; + + cellWidth = (clientRect.right - LayoutMargin.left - LayoutMargin.right - GRAPH_PADDING * numberOfXPaddings) / numberOfColumns; + x = LayoutMargin.left; + + for (ULONG column = 0; column < numberOfColumns; column++) + { + // Give the last cell the remaining space; the width we calculated might be off by a few + // pixels due to integer division. + if (column == numberOfColumns - 1) + cellWidth = clientRect.right - LayoutMargin.right - x; + + if (i < EtGpuTotalNodeCount) + { + deferHandle = DeferWindowPos( + deferHandle, + GraphHandle[i], + NULL, + x, + y, + cellWidth, + cellHeight - checkBoxRect.bottom - CHECKBOX_PADDING, + SWP_NOACTIVATE | SWP_NOZORDER + ); + deferHandle = DeferWindowPos( + deferHandle, + CheckBoxHandle[i], + NULL, + x, + y + cellHeight - checkBoxRect.bottom, + cellWidth, + checkBoxRect.bottom, + SWP_NOACTIVATE | SWP_NOZORDER + ); + i++; + } + x += cellWidth + GRAPH_PADDING; + } + + y += cellHeight + GRAPH_PADDING; + } + + EndDeferWindowPos(deferHandle); + } + break; + case WM_SIZING: + { + PhResizingMinimumSize((PRECT)lParam, wParam, MinimumSize.right, MinimumSize.bottom); + } + break; + case WM_COMMAND: + { + switch (LOWORD(wParam)) + { + case IDCANCEL: + case IDOK: + { + EndDialog(hwndDlg, IDOK); + } + break; + } + } + break; + case WM_NOTIFY: + { + NMHDR *header = (NMHDR *)lParam; + ULONG i; + + switch (header->code) + { + case GCN_GETDRAWINFO: + { + PPH_GRAPH_GETDRAWINFO getDrawInfo = (PPH_GRAPH_GETDRAWINFO)header; + PPH_GRAPH_DRAW_INFO drawInfo = getDrawInfo->DrawInfo; + + drawInfo->Flags = PH_GRAPH_USE_GRID_X | PH_GRAPH_USE_GRID_Y; + SysInfoParameters->ColorSetupFunction(drawInfo, PhGetIntegerSetting(L"ColorCpuKernel"), 0); + + for (i = 0; i < EtGpuTotalNodeCount; i++) + { + if (header->hwndFrom == GraphHandle[i]) + { + PhGraphStateGetDrawInfo( + &GraphState[i], + getDrawInfo, + EtGpuNodesHistory[i].Count + ); + + if (!GraphState[i].Valid) + { + PhCopyCircularBuffer_FLOAT(&EtGpuNodesHistory[i], GraphState[i].Data1, drawInfo->LineDataCount); + GraphState[i].Valid = TRUE; + } + + break; + } + } + } + break; + case GCN_GETTOOLTIPTEXT: + { + PPH_GRAPH_GETTOOLTIPTEXT getTooltipText = (PPH_GRAPH_GETTOOLTIPTEXT)header; + + if (getTooltipText->Index < getTooltipText->TotalCount) + { + for (i = 0; i < EtGpuTotalNodeCount; i++) + { + if (header->hwndFrom == GraphHandle[i]) + { + if (GraphState[i].TooltipIndex != getTooltipText->Index) + { + FLOAT gpu; + ULONG adapterIndex; + PPH_STRING adapterDescription; + + gpu = PhGetItemCircularBuffer_FLOAT(&EtGpuNodesHistory[i], getTooltipText->Index); + adapterIndex = EtGetGpuAdapterIndexFromNodeIndex(i); + + if (adapterIndex != -1) + { + adapterDescription = EtGetGpuAdapterDescription(adapterIndex); + + if (adapterDescription && adapterDescription->Length == 0) + PhClearReference(&adapterDescription); + + if (!adapterDescription) + adapterDescription = PhFormatString(L"Adapter %lu", adapterIndex); + } + else + { + adapterDescription = PhCreateString(L"Unknown Adapter"); + } + + PhMoveReference(&GraphState[i].TooltipText, PhFormatString( + L"Node %lu on %s\n%.2f%%\n%s", + i, + adapterDescription->Buffer, + gpu * 100, + ((PPH_STRING)PH_AUTO(PhGetStatisticsTimeString(NULL, getTooltipText->Index)))->Buffer + )); + PhDereferenceObject(adapterDescription); + } + + getTooltipText->Text = GraphState[i].TooltipText->sr; + + break; + } + } + } + } + break; + } + } + break; + case UPDATE_MSG: + { + ULONG i; + + for (i = 0; i < EtGpuTotalNodeCount; i++) + { + GraphState[i].Valid = FALSE; + GraphState[i].TooltipIndex = -1; + Graph_MoveGrid(GraphHandle[i], 1); + Graph_Draw(GraphHandle[i]); + Graph_UpdateTooltip(GraphHandle[i]); + InvalidateRect(GraphHandle[i], NULL, FALSE); + } + } + break; + } + + return FALSE; +} diff --git a/plugins/ExtendedTools/gpuprprp.c b/plugins/ExtendedTools/gpuprprp.c index 0cc87551e9de..882b3c453d75 100644 --- a/plugins/ExtendedTools/gpuprprp.c +++ b/plugins/ExtendedTools/gpuprprp.c @@ -1,767 +1,767 @@ -/* - * Process Hacker Extended Tools - - * GPU process properties page - * - * Copyright (C) 2011 wj32 - * Copyright (C) 2015-2016 dmex - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include "exttools.h" - -typedef struct _ET_GPU_CONTEXT -{ - HWND WindowHandle; - HWND PanelHandle; - HWND DetailsHandle; - PET_PROCESS_BLOCK Block; - PH_CALLBACK_REGISTRATION ProcessesUpdatedRegistration; - BOOLEAN Enabled; - PH_LAYOUT_MANAGER LayoutManager; - - HWND GpuGroupBox; - HWND MemGroupBox; - HWND SharedGroupBox; - - HWND GpuGraphHandle; - HWND MemGraphHandle; - HWND SharedGraphHandle; - - FLOAT CurrentGpuUsage; - ULONG CurrentMemUsage; - ULONG CurrentMemSharedUsage; - - PH_GRAPH_STATE GpuGraphState; - PH_GRAPH_STATE MemoryGraphState; - PH_GRAPH_STATE MemorySharedGraphState; - - PH_CIRCULAR_BUFFER_FLOAT GpuHistory; - PH_CIRCULAR_BUFFER_ULONG MemoryHistory; - PH_CIRCULAR_BUFFER_ULONG MemorySharedHistory; -} ET_GPU_CONTEXT, *PET_GPU_CONTEXT; - -static RECT NormalGraphTextMargin = { 5, 5, 5, 5 }; -static RECT NormalGraphTextPadding = { 3, 3, 3, 3 }; - -VOID GpuPropUpdatePanel( - _Inout_ PET_GPU_CONTEXT Context - ); - -INT_PTR CALLBACK GpuDetailsDialogProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - PET_GPU_CONTEXT context = NULL; - - if (uMsg == WM_INITDIALOG) - { - context = (PET_GPU_CONTEXT)lParam; - SetProp(hwndDlg, L"Context", (HANDLE)context); - } - else - { - context = (PET_GPU_CONTEXT)GetProp(hwndDlg, L"Context"); - - if (uMsg == WM_DESTROY) - { - context->DetailsHandle = NULL; - RemoveProp(hwndDlg, L"Context"); - } - } - - if (context == NULL) - return FALSE; - - switch (uMsg) - { - case WM_INITDIALOG: - { - context->DetailsHandle = hwndDlg; - PhCenterWindow(hwndDlg, GetParent(hwndDlg)); - - GpuPropUpdatePanel(context); - } - break; - case WM_COMMAND: - { - switch (GET_WM_COMMAND_ID(wParam, lparam)) - { - case IDCANCEL: - EndDialog(hwndDlg, IDCANCEL); - break; - } - } - break; - } - - return FALSE; -} - -INT_PTR CALLBACK GpuPanelDialogProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - PET_GPU_CONTEXT context = NULL; - - if (uMsg == WM_INITDIALOG) - { - context = (PET_GPU_CONTEXT)lParam; - SetProp(hwndDlg, L"Context", (HANDLE)context); - } - else - { - context = (PET_GPU_CONTEXT)GetProp(hwndDlg, L"Context"); - - if (uMsg == WM_DESTROY) - { - RemoveProp(hwndDlg, L"Context"); - } - } - - if (context == NULL) - return FALSE; - - switch (uMsg) - { - case WM_COMMAND: - { - switch (GET_WM_COMMAND_ID(wParam, lparam)) - { - case IDC_GPUDETAILS: - { - DialogBoxParam( - PluginInstance->DllBase, - MAKEINTRESOURCE(IDD_PROCGPU_DETAILS), - hwndDlg, - GpuDetailsDialogProc, - (LPARAM)context - ); - } - break; - } - } - break; - } - - return FALSE; -} - -VOID GpuPropCreateGraphs( - _In_ PET_GPU_CONTEXT Context - ) -{ - Context->GpuGraphHandle = CreateWindow( - PH_GRAPH_CLASSNAME, - NULL, - WS_VISIBLE | WS_CHILD | WS_BORDER, - 0, - 0, - 3, - 3, - Context->WindowHandle, - NULL, - NULL, - NULL - ); - Graph_SetTooltip(Context->GpuGraphHandle, TRUE); - - Context->MemGraphHandle = CreateWindow( - PH_GRAPH_CLASSNAME, - NULL, - WS_VISIBLE | WS_CHILD | WS_BORDER, - 0, - 0, - 3, - 3, - Context->WindowHandle, - NULL, - NULL, - NULL - ); - Graph_SetTooltip(Context->MemGraphHandle, TRUE); - - Context->SharedGraphHandle = CreateWindow( - PH_GRAPH_CLASSNAME, - NULL, - WS_VISIBLE | WS_CHILD | WS_BORDER, - 0, - 0, - 3, - 3, - Context->WindowHandle, - NULL, - NULL, - NULL - ); - Graph_SetTooltip(Context->SharedGraphHandle, TRUE); -} - -VOID GpuPropCreatePanel( - _In_ PET_GPU_CONTEXT Context - ) -{ - RECT margin; - - Context->PanelHandle = CreateDialogParam( - PluginInstance->DllBase, - MAKEINTRESOURCE(IDD_PROCGPU_PANEL), - Context->WindowHandle, - GpuPanelDialogProc, - (LPARAM)Context - ); - - SetWindowPos( - Context->PanelHandle, - NULL, - 10, 0, 0, 0, - SWP_NOACTIVATE | SWP_NOREDRAW | SWP_NOSIZE | SWP_NOZORDER - ); - - ShowWindow(Context->PanelHandle, SW_SHOW); - - margin.left = 0; - margin.top = 0; - margin.right = 0; - margin.bottom = 10; - MapDialogRect(Context->WindowHandle, &margin); - - PhAddLayoutItemEx( - &Context->LayoutManager, - Context->PanelHandle, - NULL, - PH_ANCHOR_BOTTOM | PH_ANCHOR_LEFT, - margin - ); - - SendMessage(Context->WindowHandle, WM_SIZE, 0, 0); -} - -VOID GpuPropLayoutGraphs( - _In_ PET_GPU_CONTEXT Context - ) -{ - HDWP deferHandle; - RECT clientRect; - RECT panelRect; - RECT margin = { ET_SCALE_DPI(13), ET_SCALE_DPI(13), ET_SCALE_DPI(13), ET_SCALE_DPI(13) }; - RECT innerMargin = { ET_SCALE_DPI(10), ET_SCALE_DPI(20), ET_SCALE_DPI(10), ET_SCALE_DPI(10) }; - LONG between = ET_SCALE_DPI(3); - ULONG graphWidth; - ULONG graphHeight; - - PhLayoutManagerLayout(&Context->LayoutManager); - - Context->GpuGraphState.Valid = FALSE; - Context->MemoryGraphState.Valid = FALSE; - Context->MemorySharedGraphState.Valid = FALSE; - - GetClientRect(Context->WindowHandle, &clientRect); - - // Limit the rectangle bottom to the top of the panel. - GetWindowRect(Context->PanelHandle, &panelRect); - MapWindowPoints(NULL, Context->WindowHandle, (PPOINT)&panelRect, 2); - clientRect.bottom = panelRect.top + 10; // +10 removing extra spacing - - graphWidth = clientRect.right - margin.left - margin.right; - graphHeight = (clientRect.bottom - margin.top - margin.bottom - between * 2) / 3; - - deferHandle = BeginDeferWindowPos(6); - - deferHandle = DeferWindowPos(deferHandle, Context->GpuGroupBox, NULL, margin.left, margin.top, graphWidth, graphHeight, SWP_NOACTIVATE | SWP_NOZORDER); - deferHandle = DeferWindowPos( - deferHandle, - Context->GpuGraphHandle, - NULL, - margin.left + innerMargin.left, - margin.top + innerMargin.top, - graphWidth - innerMargin.left - innerMargin.right, - graphHeight - innerMargin.top - innerMargin.bottom, - SWP_NOACTIVATE | SWP_NOZORDER - ); - - deferHandle = DeferWindowPos(deferHandle, Context->MemGroupBox, NULL, margin.left, margin.top + graphHeight + between, graphWidth, graphHeight, SWP_NOACTIVATE | SWP_NOZORDER); - deferHandle = DeferWindowPos( - deferHandle, - Context->MemGraphHandle, - NULL, - margin.left + innerMargin.left, - margin.top + graphHeight + between + innerMargin.top, - graphWidth - innerMargin.left - innerMargin.right, - graphHeight - innerMargin.top - innerMargin.bottom, - SWP_NOACTIVATE | SWP_NOZORDER - ); - - deferHandle = DeferWindowPos(deferHandle, Context->SharedGroupBox, NULL, margin.left, margin.top + (graphHeight + between) * 2, graphWidth, graphHeight, SWP_NOACTIVATE | SWP_NOZORDER); - deferHandle = DeferWindowPos( - deferHandle, - Context->SharedGraphHandle, - NULL, - margin.left + innerMargin.left, - margin.top + (graphHeight + between) * 2 + innerMargin.top, - graphWidth - innerMargin.left - innerMargin.right, - graphHeight - innerMargin.top - innerMargin.bottom, - SWP_NOACTIVATE | SWP_NOZORDER - ); - - EndDeferWindowPos(deferHandle); -} - -VOID GpuPropUpdateGraphs( - _In_ PET_GPU_CONTEXT Context - ) -{ - Context->GpuGraphState.Valid = FALSE; - Context->GpuGraphState.TooltipIndex = -1; - Graph_MoveGrid(Context->GpuGraphHandle, 1); - Graph_Draw(Context->GpuGraphHandle); - Graph_UpdateTooltip(Context->GpuGraphHandle); - InvalidateRect(Context->GpuGraphHandle, NULL, FALSE); - - Context->MemoryGraphState.Valid = FALSE; - Context->MemoryGraphState.TooltipIndex = -1; - Graph_MoveGrid(Context->MemGraphHandle, 1); - Graph_Draw(Context->MemGraphHandle); - Graph_UpdateTooltip(Context->MemGraphHandle); - InvalidateRect(Context->MemGraphHandle, NULL, FALSE); - - Context->MemorySharedGraphState.Valid = FALSE; - Context->MemorySharedGraphState.TooltipIndex = -1; - Graph_MoveGrid(Context->SharedGraphHandle, 1); - Graph_Draw(Context->SharedGraphHandle); - Graph_UpdateTooltip(Context->SharedGraphHandle); - InvalidateRect(Context->SharedGraphHandle, NULL, FALSE); -} - -VOID GpuPropUpdatePanel( - _Inout_ PET_GPU_CONTEXT Context - ) -{ - ET_PROCESS_GPU_STATISTICS statistics; - WCHAR runningTimeString[PH_TIMESPAN_STR_LEN_1] = L"N/A"; - - if (Context->Block->ProcessItem->QueryHandle) - EtQueryProcessGpuStatistics(Context->Block->ProcessItem->QueryHandle, &statistics); - else - memset(&statistics, 0, sizeof(ET_PROCESS_GPU_STATISTICS)); - - PhPrintTimeSpan(runningTimeString, statistics.RunningTime * 10, PH_TIMESPAN_HMSM); - - SetDlgItemText(Context->PanelHandle, IDC_ZRUNNINGTIME_V, runningTimeString); - SetDlgItemText(Context->PanelHandle, IDC_ZCONTEXTSWITCHES_V, PhaFormatUInt64(statistics.ContextSwitches, TRUE)->Buffer); - SetDlgItemText(Context->PanelHandle, IDC_ZTOTALNODES_V, PhaFormatUInt64(statistics.NodeCount, TRUE)->Buffer); - SetDlgItemText(Context->PanelHandle, IDC_ZTOTALSEGMENTS_V, PhaFormatUInt64(statistics.SegmentCount, TRUE)->Buffer); - - if (Context->DetailsHandle) - { - // Note: no lock is needed because we only ever update the 'details' dialog text on this same thread. - SetDlgItemText(Context->DetailsHandle, IDC_ZDEDICATEDCOMMITTED_V, PhaFormatSize(statistics.DedicatedCommitted, -1)->Buffer); - SetDlgItemText(Context->DetailsHandle, IDC_ZSHAREDCOMMITTED_V, PhaFormatSize(statistics.SharedCommitted, -1)->Buffer); - SetDlgItemText(Context->DetailsHandle, IDC_ZTOTALALLOCATED_V, PhaFormatSize(statistics.BytesAllocated, -1)->Buffer); - SetDlgItemText(Context->DetailsHandle, IDC_ZTOTALRESERVED_V, PhaFormatSize(statistics.BytesReserved, -1)->Buffer); - SetDlgItemText(Context->DetailsHandle, IDC_ZWRITECOMBINEDALLOCATED_V, PhaFormatSize(statistics.WriteCombinedBytesAllocated, -1)->Buffer); - SetDlgItemText(Context->DetailsHandle, IDC_ZWRITECOMBINEDRESERVED_V, PhaFormatSize(statistics.WriteCombinedBytesReserved, -1)->Buffer); - SetDlgItemText(Context->DetailsHandle, IDC_ZCACHEDALLOCATED_V, PhaFormatSize(statistics.CachedBytesAllocated, -1)->Buffer); - SetDlgItemText(Context->DetailsHandle, IDC_ZCACHEDRESERVED_V, PhaFormatSize(statistics.CachedBytesReserved, -1)->Buffer); - SetDlgItemText(Context->DetailsHandle, IDC_ZSECTIONALLOCATED_V, PhaFormatSize(statistics.SectionBytesAllocated, -1)->Buffer); - SetDlgItemText(Context->DetailsHandle, IDC_ZSECTIONRESERVED_V, PhaFormatSize(statistics.SectionBytesReserved, -1)->Buffer); - } -} - -VOID GpuPropUpdateInfo( - _In_ PET_GPU_CONTEXT Context - ) -{ - PET_PROCESS_BLOCK block = Context->Block; - - Context->CurrentGpuUsage = block->GpuNodeUsage; - Context->CurrentMemUsage = (ULONG)(block->GpuDedicatedUsage / PAGE_SIZE); - Context->CurrentMemSharedUsage = (ULONG)(block->GpuSharedUsage / PAGE_SIZE); - - PhAddItemCircularBuffer_FLOAT(&Context->GpuHistory, Context->CurrentGpuUsage); - PhAddItemCircularBuffer_ULONG(&Context->MemoryHistory, Context->CurrentMemUsage); - PhAddItemCircularBuffer_ULONG(&Context->MemorySharedHistory, Context->CurrentMemSharedUsage); -} - -VOID NTAPI ProcessesUpdatedHandler( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - PET_GPU_CONTEXT context = Context; - - if (!context->Enabled) - return; - - if (context->WindowHandle) - { - PostMessage(context->WindowHandle, UPDATE_MSG, 0, 0); - } -} - -INT_PTR CALLBACK EtpGpuPageDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - LPPROPSHEETPAGE propSheetPage; - PPH_PROCESS_PROPPAGECONTEXT propPageContext; - PPH_PROCESS_ITEM processItem; - PET_GPU_CONTEXT context; - - if (PhPropPageDlgProcHeader(hwndDlg, uMsg, lParam, &propSheetPage, &propPageContext, &processItem)) - { - context = propPageContext->Context; - } - else - { - return FALSE; - } - - switch (uMsg) - { - case WM_INITDIALOG: - { - ULONG sampleCount; - - sampleCount = PhGetIntegerSetting(L"SampleCount"); - - context = PhAllocate(sizeof(ET_GPU_CONTEXT)); - memset(context, 0, sizeof(ET_GPU_CONTEXT)); - - context->WindowHandle = hwndDlg; - context->Block = EtGetProcessBlock(processItem); - context->Enabled = TRUE; - context->GpuGroupBox = GetDlgItem(hwndDlg, IDC_GROUPGPU); - context->MemGroupBox = GetDlgItem(hwndDlg, IDC_GROUPMEM); - context->SharedGroupBox = GetDlgItem(hwndDlg, IDC_GROUPSHARED); - propPageContext->Context = context; - - PhInitializeLayoutManager(&context->LayoutManager, hwndDlg); - - PhInitializeGraphState(&context->GpuGraphState); - PhInitializeGraphState(&context->MemoryGraphState); - PhInitializeGraphState(&context->MemorySharedGraphState); - - PhInitializeCircularBuffer_FLOAT(&context->GpuHistory, sampleCount); - PhInitializeCircularBuffer_ULONG(&context->MemoryHistory, sampleCount); - PhInitializeCircularBuffer_ULONG(&context->MemorySharedHistory, sampleCount); - - GpuPropCreateGraphs(context); - GpuPropCreatePanel(context); - GpuPropUpdateInfo(context); - GpuPropUpdatePanel(context); - - PhRegisterCallback( - &PhProcessesUpdatedEvent, - ProcessesUpdatedHandler, - context, - &context->ProcessesUpdatedRegistration - ); - } - break; - case WM_DESTROY: - { - PhDeleteLayoutManager(&context->LayoutManager); - - PhDeleteGraphState(&context->GpuGraphState); - PhDeleteGraphState(&context->MemoryGraphState); - PhDeleteGraphState(&context->MemorySharedGraphState); - - PhDeleteCircularBuffer_FLOAT(&context->GpuHistory); - PhDeleteCircularBuffer_ULONG(&context->MemoryHistory); - PhDeleteCircularBuffer_ULONG(&context->MemorySharedHistory); - - if (context->GpuGraphHandle) - DestroyWindow(context->GpuGraphHandle); - if (context->MemGraphHandle) - DestroyWindow(context->MemGraphHandle); - if (context->SharedGraphHandle) - DestroyWindow(context->SharedGraphHandle); - if (context->PanelHandle) - DestroyWindow(context->PanelHandle); - - PhUnregisterCallback(&PhProcessesUpdatedEvent, &context->ProcessesUpdatedRegistration); - PhFree(context); - - PhPropPageDlgProcDestroy(hwndDlg); - } - break; - case WM_SHOWWINDOW: - { - if (PhBeginPropPageLayout(hwndDlg, propPageContext)) - PhEndPropPageLayout(hwndDlg, propPageContext); - } - break; - case WM_NOTIFY: - { - LPNMHDR header = (LPNMHDR)lParam; - - switch (header->code) - { - case PSN_SETACTIVE: - context->Enabled = TRUE; - break; - case PSN_KILLACTIVE: - context->Enabled = FALSE; - break; - case GCN_GETDRAWINFO: - { - PPH_GRAPH_GETDRAWINFO getDrawInfo = (PPH_GRAPH_GETDRAWINFO)header; - PPH_GRAPH_DRAW_INFO drawInfo = getDrawInfo->DrawInfo; - - if (header->hwndFrom == context->GpuGraphHandle) - { - if (PhGetIntegerSetting(L"GraphShowText")) - { - HDC hdc; - - PhMoveReference(&context->GpuGraphState.Text, PhFormatString( - L"%.2f%%", - context->CurrentGpuUsage * 100 - )); - - hdc = Graph_GetBufferedContext(context->GpuGraphHandle); - SelectObject(hdc, PhApplicationFont); - PhSetGraphText(hdc, drawInfo, &context->GpuGraphState.Text->sr, - &NormalGraphTextMargin, &NormalGraphTextPadding, PH_ALIGN_TOP | PH_ALIGN_LEFT); - } - else - { - drawInfo->Text.Buffer = NULL; - } - - drawInfo->Flags = PH_GRAPH_USE_GRID_X | PH_GRAPH_USE_GRID_Y; - PhSiSetColorsGraphDrawInfo(drawInfo, PhGetIntegerSetting(L"ColorCpuKernel"), 0); - PhGraphStateGetDrawInfo(&context->GpuGraphState, getDrawInfo, context->GpuHistory.Count); - - if (!context->GpuGraphState.Valid) - { - PhCopyCircularBuffer_FLOAT(&context->GpuHistory, context->GpuGraphState.Data1, drawInfo->LineDataCount); - context->GpuGraphState.Valid = TRUE; - } - } - else if (header->hwndFrom == context->MemGraphHandle) - { - if (PhGetIntegerSetting(L"GraphShowText")) - { - HDC hdc; - - PhMoveReference(&context->MemoryGraphState.Text, PhFormatString( - L"%s", - PhaFormatSize(UInt32x32To64(context->CurrentMemUsage, PAGE_SIZE), -1)->Buffer - )); - - hdc = Graph_GetBufferedContext(context->MemGraphHandle); - SelectObject(hdc, PhApplicationFont); - PhSetGraphText( - hdc, - drawInfo, - &context->MemoryGraphState.Text->sr, - &NormalGraphTextMargin, - &NormalGraphTextPadding, - PH_ALIGN_TOP | PH_ALIGN_LEFT - ); - } - else - { - drawInfo->Text.Buffer = NULL; - } - - drawInfo->Flags = PH_GRAPH_USE_GRID_X | PH_GRAPH_USE_GRID_Y; - PhSiSetColorsGraphDrawInfo(drawInfo, PhGetIntegerSetting(L"ColorPhysical"), 0); - PhGraphStateGetDrawInfo( - &context->MemoryGraphState, - getDrawInfo, - context->MemoryHistory.Count - ); - - if (!context->MemoryGraphState.Valid) - { - ULONG i = 0; - - for (i = 0; i < drawInfo->LineDataCount; i++) - { - context->MemoryGraphState.Data1[i] = (FLOAT)PhGetItemCircularBuffer_ULONG(&context->MemoryHistory, i); - } - - if (EtGpuDedicatedLimit != 0) - { - PhDivideSinglesBySingle( - context->MemoryGraphState.Data1, - (FLOAT)EtGpuDedicatedLimit / PAGE_SIZE, - drawInfo->LineDataCount - ); - } - - context->MemoryGraphState.Valid = TRUE; - } - } - else if (header->hwndFrom == context->SharedGraphHandle) - { - if (PhGetIntegerSetting(L"GraphShowText")) - { - HDC hdc; - - PhMoveReference(&context->MemorySharedGraphState.Text, PhFormatString( - L"%s", - PhaFormatSize(UInt32x32To64(context->CurrentMemSharedUsage, PAGE_SIZE), -1)->Buffer - )); - - hdc = Graph_GetBufferedContext(context->SharedGraphHandle); - SelectObject(hdc, PhApplicationFont); - PhSetGraphText(hdc, drawInfo, &context->MemorySharedGraphState.Text->sr, - &NormalGraphTextMargin, &NormalGraphTextPadding, PH_ALIGN_TOP | PH_ALIGN_LEFT); - } - else - { - drawInfo->Text.Buffer = NULL; - } - - drawInfo->Flags = PH_GRAPH_USE_GRID_X | PH_GRAPH_USE_GRID_Y; - PhSiSetColorsGraphDrawInfo(drawInfo, PhGetIntegerSetting(L"ColorPrivate"), 0); - PhGraphStateGetDrawInfo( - &context->MemorySharedGraphState, - getDrawInfo, - context->MemorySharedHistory.Count - ); - - if (!context->MemorySharedGraphState.Valid) - { - ULONG i = 0; - - for (i = 0; i < drawInfo->LineDataCount; i++) - { - context->MemorySharedGraphState.Data1[i] = (FLOAT)PhGetItemCircularBuffer_ULONG(&context->MemorySharedHistory, i); - } - - if (EtGpuSharedLimit != 0) - { - PhDivideSinglesBySingle( - context->MemorySharedGraphState.Data1, - (FLOAT)EtGpuSharedLimit / PAGE_SIZE, - drawInfo->LineDataCount - ); - } - - context->MemorySharedGraphState.Valid = TRUE; - } - } - } - break; - case GCN_GETTOOLTIPTEXT: - { - PPH_GRAPH_GETTOOLTIPTEXT getTooltipText = (PPH_GRAPH_GETTOOLTIPTEXT)lParam; - - if (getTooltipText->Index < getTooltipText->TotalCount) - { - if (header->hwndFrom == context->GpuGraphHandle) - { - if (context->GpuGraphState.TooltipIndex != getTooltipText->Index) - { - FLOAT gpuUsage = PhGetItemCircularBuffer_FLOAT( - &context->GpuHistory, - getTooltipText->Index - ); - - PhMoveReference(&context->GpuGraphState.TooltipText, PhFormatString( - L"%.2f%%", - gpuUsage * 100 - )); - } - - getTooltipText->Text = context->GpuGraphState.TooltipText->sr; - } - else if (header->hwndFrom == context->MemGraphHandle) - { - if (context->MemoryGraphState.TooltipIndex != getTooltipText->Index) - { - ULONG gpuMemory = PhGetItemCircularBuffer_ULONG( - &context->MemoryHistory, - getTooltipText->Index - ); - - PhMoveReference(&context->MemoryGraphState.TooltipText, - PhFormatSize(UInt32x32To64(gpuMemory, PAGE_SIZE), -1) - ); - } - - getTooltipText->Text = context->MemoryGraphState.TooltipText->sr; - } - else if (header->hwndFrom == context->SharedGraphHandle) - { - if (context->MemorySharedGraphState.TooltipIndex != getTooltipText->Index) - { - ULONG gpuSharedMemory = PhGetItemCircularBuffer_ULONG( - &context->MemorySharedHistory, - getTooltipText->Index - ); - - PhMoveReference(&context->MemorySharedGraphState.TooltipText, - PhFormatSize(UInt32x32To64(gpuSharedMemory, PAGE_SIZE), -1) - ); - } - - getTooltipText->Text = context->MemorySharedGraphState.TooltipText->sr; - } - } - } - break; - } - } - break; - case UPDATE_MSG: - { - if (context->Enabled) - { - GpuPropUpdateInfo(context); - GpuPropUpdateGraphs(context); - GpuPropUpdatePanel(context); - } - } - break; - case WM_SIZE: - { - GpuPropLayoutGraphs(context); - } - break; - } - - return FALSE; -} - -VOID EtProcessGpuPropertiesInitializing( - _In_ PVOID Parameter - ) -{ - PPH_PLUGIN_PROCESS_PROPCONTEXT propContext = Parameter; - - if (EtGpuEnabled) - { - PhAddProcessPropPage( - propContext->PropContext, - PhCreateProcessPropPageContextEx(PluginInstance->DllBase, MAKEINTRESOURCE(IDD_PROCGPU), EtpGpuPageDlgProc, NULL) - ); - } +/* + * Process Hacker Extended Tools - + * GPU process properties page + * + * Copyright (C) 2011 wj32 + * Copyright (C) 2015-2016 dmex + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include "exttools.h" + +typedef struct _ET_GPU_CONTEXT +{ + HWND WindowHandle; + HWND PanelHandle; + HWND DetailsHandle; + PET_PROCESS_BLOCK Block; + PH_CALLBACK_REGISTRATION ProcessesUpdatedRegistration; + BOOLEAN Enabled; + PH_LAYOUT_MANAGER LayoutManager; + + HWND GpuGroupBox; + HWND MemGroupBox; + HWND SharedGroupBox; + + HWND GpuGraphHandle; + HWND MemGraphHandle; + HWND SharedGraphHandle; + + FLOAT CurrentGpuUsage; + ULONG CurrentMemUsage; + ULONG CurrentMemSharedUsage; + + PH_GRAPH_STATE GpuGraphState; + PH_GRAPH_STATE MemoryGraphState; + PH_GRAPH_STATE MemorySharedGraphState; + + PH_CIRCULAR_BUFFER_FLOAT GpuHistory; + PH_CIRCULAR_BUFFER_ULONG MemoryHistory; + PH_CIRCULAR_BUFFER_ULONG MemorySharedHistory; +} ET_GPU_CONTEXT, *PET_GPU_CONTEXT; + +static RECT NormalGraphTextMargin = { 5, 5, 5, 5 }; +static RECT NormalGraphTextPadding = { 3, 3, 3, 3 }; + +VOID GpuPropUpdatePanel( + _Inout_ PET_GPU_CONTEXT Context + ); + +INT_PTR CALLBACK GpuDetailsDialogProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + PET_GPU_CONTEXT context = NULL; + + if (uMsg == WM_INITDIALOG) + { + context = (PET_GPU_CONTEXT)lParam; + SetProp(hwndDlg, L"Context", (HANDLE)context); + } + else + { + context = (PET_GPU_CONTEXT)GetProp(hwndDlg, L"Context"); + + if (uMsg == WM_DESTROY) + { + context->DetailsHandle = NULL; + RemoveProp(hwndDlg, L"Context"); + } + } + + if (context == NULL) + return FALSE; + + switch (uMsg) + { + case WM_INITDIALOG: + { + context->DetailsHandle = hwndDlg; + PhCenterWindow(hwndDlg, GetParent(hwndDlg)); + + GpuPropUpdatePanel(context); + } + break; + case WM_COMMAND: + { + switch (GET_WM_COMMAND_ID(wParam, lparam)) + { + case IDCANCEL: + EndDialog(hwndDlg, IDCANCEL); + break; + } + } + break; + } + + return FALSE; +} + +INT_PTR CALLBACK GpuPanelDialogProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + PET_GPU_CONTEXT context = NULL; + + if (uMsg == WM_INITDIALOG) + { + context = (PET_GPU_CONTEXT)lParam; + SetProp(hwndDlg, L"Context", (HANDLE)context); + } + else + { + context = (PET_GPU_CONTEXT)GetProp(hwndDlg, L"Context"); + + if (uMsg == WM_DESTROY) + { + RemoveProp(hwndDlg, L"Context"); + } + } + + if (context == NULL) + return FALSE; + + switch (uMsg) + { + case WM_COMMAND: + { + switch (GET_WM_COMMAND_ID(wParam, lparam)) + { + case IDC_GPUDETAILS: + { + DialogBoxParam( + PluginInstance->DllBase, + MAKEINTRESOURCE(IDD_PROCGPU_DETAILS), + hwndDlg, + GpuDetailsDialogProc, + (LPARAM)context + ); + } + break; + } + } + break; + } + + return FALSE; +} + +VOID GpuPropCreateGraphs( + _In_ PET_GPU_CONTEXT Context + ) +{ + Context->GpuGraphHandle = CreateWindow( + PH_GRAPH_CLASSNAME, + NULL, + WS_VISIBLE | WS_CHILD | WS_BORDER, + 0, + 0, + 3, + 3, + Context->WindowHandle, + NULL, + NULL, + NULL + ); + Graph_SetTooltip(Context->GpuGraphHandle, TRUE); + + Context->MemGraphHandle = CreateWindow( + PH_GRAPH_CLASSNAME, + NULL, + WS_VISIBLE | WS_CHILD | WS_BORDER, + 0, + 0, + 3, + 3, + Context->WindowHandle, + NULL, + NULL, + NULL + ); + Graph_SetTooltip(Context->MemGraphHandle, TRUE); + + Context->SharedGraphHandle = CreateWindow( + PH_GRAPH_CLASSNAME, + NULL, + WS_VISIBLE | WS_CHILD | WS_BORDER, + 0, + 0, + 3, + 3, + Context->WindowHandle, + NULL, + NULL, + NULL + ); + Graph_SetTooltip(Context->SharedGraphHandle, TRUE); +} + +VOID GpuPropCreatePanel( + _In_ PET_GPU_CONTEXT Context + ) +{ + RECT margin; + + Context->PanelHandle = CreateDialogParam( + PluginInstance->DllBase, + MAKEINTRESOURCE(IDD_PROCGPU_PANEL), + Context->WindowHandle, + GpuPanelDialogProc, + (LPARAM)Context + ); + + SetWindowPos( + Context->PanelHandle, + NULL, + 10, 0, 0, 0, + SWP_NOACTIVATE | SWP_NOREDRAW | SWP_NOSIZE | SWP_NOZORDER + ); + + ShowWindow(Context->PanelHandle, SW_SHOW); + + margin.left = 0; + margin.top = 0; + margin.right = 0; + margin.bottom = 10; + MapDialogRect(Context->WindowHandle, &margin); + + PhAddLayoutItemEx( + &Context->LayoutManager, + Context->PanelHandle, + NULL, + PH_ANCHOR_BOTTOM | PH_ANCHOR_LEFT, + margin + ); + + SendMessage(Context->WindowHandle, WM_SIZE, 0, 0); +} + +VOID GpuPropLayoutGraphs( + _In_ PET_GPU_CONTEXT Context + ) +{ + HDWP deferHandle; + RECT clientRect; + RECT panelRect; + RECT margin = { ET_SCALE_DPI(13), ET_SCALE_DPI(13), ET_SCALE_DPI(13), ET_SCALE_DPI(13) }; + RECT innerMargin = { ET_SCALE_DPI(10), ET_SCALE_DPI(20), ET_SCALE_DPI(10), ET_SCALE_DPI(10) }; + LONG between = ET_SCALE_DPI(3); + ULONG graphWidth; + ULONG graphHeight; + + PhLayoutManagerLayout(&Context->LayoutManager); + + Context->GpuGraphState.Valid = FALSE; + Context->MemoryGraphState.Valid = FALSE; + Context->MemorySharedGraphState.Valid = FALSE; + + GetClientRect(Context->WindowHandle, &clientRect); + + // Limit the rectangle bottom to the top of the panel. + GetWindowRect(Context->PanelHandle, &panelRect); + MapWindowPoints(NULL, Context->WindowHandle, (PPOINT)&panelRect, 2); + clientRect.bottom = panelRect.top + 10; // +10 removing extra spacing + + graphWidth = clientRect.right - margin.left - margin.right; + graphHeight = (clientRect.bottom - margin.top - margin.bottom - between * 2) / 3; + + deferHandle = BeginDeferWindowPos(6); + + deferHandle = DeferWindowPos(deferHandle, Context->GpuGroupBox, NULL, margin.left, margin.top, graphWidth, graphHeight, SWP_NOACTIVATE | SWP_NOZORDER); + deferHandle = DeferWindowPos( + deferHandle, + Context->GpuGraphHandle, + NULL, + margin.left + innerMargin.left, + margin.top + innerMargin.top, + graphWidth - innerMargin.left - innerMargin.right, + graphHeight - innerMargin.top - innerMargin.bottom, + SWP_NOACTIVATE | SWP_NOZORDER + ); + + deferHandle = DeferWindowPos(deferHandle, Context->MemGroupBox, NULL, margin.left, margin.top + graphHeight + between, graphWidth, graphHeight, SWP_NOACTIVATE | SWP_NOZORDER); + deferHandle = DeferWindowPos( + deferHandle, + Context->MemGraphHandle, + NULL, + margin.left + innerMargin.left, + margin.top + graphHeight + between + innerMargin.top, + graphWidth - innerMargin.left - innerMargin.right, + graphHeight - innerMargin.top - innerMargin.bottom, + SWP_NOACTIVATE | SWP_NOZORDER + ); + + deferHandle = DeferWindowPos(deferHandle, Context->SharedGroupBox, NULL, margin.left, margin.top + (graphHeight + between) * 2, graphWidth, graphHeight, SWP_NOACTIVATE | SWP_NOZORDER); + deferHandle = DeferWindowPos( + deferHandle, + Context->SharedGraphHandle, + NULL, + margin.left + innerMargin.left, + margin.top + (graphHeight + between) * 2 + innerMargin.top, + graphWidth - innerMargin.left - innerMargin.right, + graphHeight - innerMargin.top - innerMargin.bottom, + SWP_NOACTIVATE | SWP_NOZORDER + ); + + EndDeferWindowPos(deferHandle); +} + +VOID GpuPropUpdateGraphs( + _In_ PET_GPU_CONTEXT Context + ) +{ + Context->GpuGraphState.Valid = FALSE; + Context->GpuGraphState.TooltipIndex = -1; + Graph_MoveGrid(Context->GpuGraphHandle, 1); + Graph_Draw(Context->GpuGraphHandle); + Graph_UpdateTooltip(Context->GpuGraphHandle); + InvalidateRect(Context->GpuGraphHandle, NULL, FALSE); + + Context->MemoryGraphState.Valid = FALSE; + Context->MemoryGraphState.TooltipIndex = -1; + Graph_MoveGrid(Context->MemGraphHandle, 1); + Graph_Draw(Context->MemGraphHandle); + Graph_UpdateTooltip(Context->MemGraphHandle); + InvalidateRect(Context->MemGraphHandle, NULL, FALSE); + + Context->MemorySharedGraphState.Valid = FALSE; + Context->MemorySharedGraphState.TooltipIndex = -1; + Graph_MoveGrid(Context->SharedGraphHandle, 1); + Graph_Draw(Context->SharedGraphHandle); + Graph_UpdateTooltip(Context->SharedGraphHandle); + InvalidateRect(Context->SharedGraphHandle, NULL, FALSE); +} + +VOID GpuPropUpdatePanel( + _Inout_ PET_GPU_CONTEXT Context + ) +{ + ET_PROCESS_GPU_STATISTICS statistics; + WCHAR runningTimeString[PH_TIMESPAN_STR_LEN_1] = L"N/A"; + + if (Context->Block->ProcessItem->QueryHandle) + EtQueryProcessGpuStatistics(Context->Block->ProcessItem->QueryHandle, &statistics); + else + memset(&statistics, 0, sizeof(ET_PROCESS_GPU_STATISTICS)); + + PhPrintTimeSpan(runningTimeString, statistics.RunningTime * 10, PH_TIMESPAN_HMSM); + + SetDlgItemText(Context->PanelHandle, IDC_ZRUNNINGTIME_V, runningTimeString); + SetDlgItemText(Context->PanelHandle, IDC_ZCONTEXTSWITCHES_V, PhaFormatUInt64(statistics.ContextSwitches, TRUE)->Buffer); + SetDlgItemText(Context->PanelHandle, IDC_ZTOTALNODES_V, PhaFormatUInt64(statistics.NodeCount, TRUE)->Buffer); + SetDlgItemText(Context->PanelHandle, IDC_ZTOTALSEGMENTS_V, PhaFormatUInt64(statistics.SegmentCount, TRUE)->Buffer); + + if (Context->DetailsHandle) + { + // Note: no lock is needed because we only ever update the 'details' dialog text on this same thread. + SetDlgItemText(Context->DetailsHandle, IDC_ZDEDICATEDCOMMITTED_V, PhaFormatSize(statistics.DedicatedCommitted, -1)->Buffer); + SetDlgItemText(Context->DetailsHandle, IDC_ZSHAREDCOMMITTED_V, PhaFormatSize(statistics.SharedCommitted, -1)->Buffer); + SetDlgItemText(Context->DetailsHandle, IDC_ZTOTALALLOCATED_V, PhaFormatSize(statistics.BytesAllocated, -1)->Buffer); + SetDlgItemText(Context->DetailsHandle, IDC_ZTOTALRESERVED_V, PhaFormatSize(statistics.BytesReserved, -1)->Buffer); + SetDlgItemText(Context->DetailsHandle, IDC_ZWRITECOMBINEDALLOCATED_V, PhaFormatSize(statistics.WriteCombinedBytesAllocated, -1)->Buffer); + SetDlgItemText(Context->DetailsHandle, IDC_ZWRITECOMBINEDRESERVED_V, PhaFormatSize(statistics.WriteCombinedBytesReserved, -1)->Buffer); + SetDlgItemText(Context->DetailsHandle, IDC_ZCACHEDALLOCATED_V, PhaFormatSize(statistics.CachedBytesAllocated, -1)->Buffer); + SetDlgItemText(Context->DetailsHandle, IDC_ZCACHEDRESERVED_V, PhaFormatSize(statistics.CachedBytesReserved, -1)->Buffer); + SetDlgItemText(Context->DetailsHandle, IDC_ZSECTIONALLOCATED_V, PhaFormatSize(statistics.SectionBytesAllocated, -1)->Buffer); + SetDlgItemText(Context->DetailsHandle, IDC_ZSECTIONRESERVED_V, PhaFormatSize(statistics.SectionBytesReserved, -1)->Buffer); + } +} + +VOID GpuPropUpdateInfo( + _In_ PET_GPU_CONTEXT Context + ) +{ + PET_PROCESS_BLOCK block = Context->Block; + + Context->CurrentGpuUsage = block->GpuNodeUsage; + Context->CurrentMemUsage = (ULONG)(block->GpuDedicatedUsage / PAGE_SIZE); + Context->CurrentMemSharedUsage = (ULONG)(block->GpuSharedUsage / PAGE_SIZE); + + PhAddItemCircularBuffer_FLOAT(&Context->GpuHistory, Context->CurrentGpuUsage); + PhAddItemCircularBuffer_ULONG(&Context->MemoryHistory, Context->CurrentMemUsage); + PhAddItemCircularBuffer_ULONG(&Context->MemorySharedHistory, Context->CurrentMemSharedUsage); +} + +VOID NTAPI ProcessesUpdatedHandler( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + PET_GPU_CONTEXT context = Context; + + if (!context->Enabled) + return; + + if (context->WindowHandle) + { + PostMessage(context->WindowHandle, UPDATE_MSG, 0, 0); + } +} + +INT_PTR CALLBACK EtpGpuPageDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + LPPROPSHEETPAGE propSheetPage; + PPH_PROCESS_PROPPAGECONTEXT propPageContext; + PPH_PROCESS_ITEM processItem; + PET_GPU_CONTEXT context; + + if (PhPropPageDlgProcHeader(hwndDlg, uMsg, lParam, &propSheetPage, &propPageContext, &processItem)) + { + context = propPageContext->Context; + } + else + { + return FALSE; + } + + switch (uMsg) + { + case WM_INITDIALOG: + { + ULONG sampleCount; + + sampleCount = PhGetIntegerSetting(L"SampleCount"); + + context = PhAllocate(sizeof(ET_GPU_CONTEXT)); + memset(context, 0, sizeof(ET_GPU_CONTEXT)); + + context->WindowHandle = hwndDlg; + context->Block = EtGetProcessBlock(processItem); + context->Enabled = TRUE; + context->GpuGroupBox = GetDlgItem(hwndDlg, IDC_GROUPGPU); + context->MemGroupBox = GetDlgItem(hwndDlg, IDC_GROUPMEM); + context->SharedGroupBox = GetDlgItem(hwndDlg, IDC_GROUPSHARED); + propPageContext->Context = context; + + PhInitializeLayoutManager(&context->LayoutManager, hwndDlg); + + PhInitializeGraphState(&context->GpuGraphState); + PhInitializeGraphState(&context->MemoryGraphState); + PhInitializeGraphState(&context->MemorySharedGraphState); + + PhInitializeCircularBuffer_FLOAT(&context->GpuHistory, sampleCount); + PhInitializeCircularBuffer_ULONG(&context->MemoryHistory, sampleCount); + PhInitializeCircularBuffer_ULONG(&context->MemorySharedHistory, sampleCount); + + GpuPropCreateGraphs(context); + GpuPropCreatePanel(context); + GpuPropUpdateInfo(context); + GpuPropUpdatePanel(context); + + PhRegisterCallback( + &PhProcessesUpdatedEvent, + ProcessesUpdatedHandler, + context, + &context->ProcessesUpdatedRegistration + ); + } + break; + case WM_DESTROY: + { + PhDeleteLayoutManager(&context->LayoutManager); + + PhDeleteGraphState(&context->GpuGraphState); + PhDeleteGraphState(&context->MemoryGraphState); + PhDeleteGraphState(&context->MemorySharedGraphState); + + PhDeleteCircularBuffer_FLOAT(&context->GpuHistory); + PhDeleteCircularBuffer_ULONG(&context->MemoryHistory); + PhDeleteCircularBuffer_ULONG(&context->MemorySharedHistory); + + if (context->GpuGraphHandle) + DestroyWindow(context->GpuGraphHandle); + if (context->MemGraphHandle) + DestroyWindow(context->MemGraphHandle); + if (context->SharedGraphHandle) + DestroyWindow(context->SharedGraphHandle); + if (context->PanelHandle) + DestroyWindow(context->PanelHandle); + + PhUnregisterCallback(&PhProcessesUpdatedEvent, &context->ProcessesUpdatedRegistration); + PhFree(context); + + PhPropPageDlgProcDestroy(hwndDlg); + } + break; + case WM_SHOWWINDOW: + { + if (PhBeginPropPageLayout(hwndDlg, propPageContext)) + PhEndPropPageLayout(hwndDlg, propPageContext); + } + break; + case WM_NOTIFY: + { + LPNMHDR header = (LPNMHDR)lParam; + + switch (header->code) + { + case PSN_SETACTIVE: + context->Enabled = TRUE; + break; + case PSN_KILLACTIVE: + context->Enabled = FALSE; + break; + case GCN_GETDRAWINFO: + { + PPH_GRAPH_GETDRAWINFO getDrawInfo = (PPH_GRAPH_GETDRAWINFO)header; + PPH_GRAPH_DRAW_INFO drawInfo = getDrawInfo->DrawInfo; + + if (header->hwndFrom == context->GpuGraphHandle) + { + if (PhGetIntegerSetting(L"GraphShowText")) + { + HDC hdc; + + PhMoveReference(&context->GpuGraphState.Text, PhFormatString( + L"%.2f%%", + context->CurrentGpuUsage * 100 + )); + + hdc = Graph_GetBufferedContext(context->GpuGraphHandle); + SelectObject(hdc, PhApplicationFont); + PhSetGraphText(hdc, drawInfo, &context->GpuGraphState.Text->sr, + &NormalGraphTextMargin, &NormalGraphTextPadding, PH_ALIGN_TOP | PH_ALIGN_LEFT); + } + else + { + drawInfo->Text.Buffer = NULL; + } + + drawInfo->Flags = PH_GRAPH_USE_GRID_X | PH_GRAPH_USE_GRID_Y; + PhSiSetColorsGraphDrawInfo(drawInfo, PhGetIntegerSetting(L"ColorCpuKernel"), 0); + PhGraphStateGetDrawInfo(&context->GpuGraphState, getDrawInfo, context->GpuHistory.Count); + + if (!context->GpuGraphState.Valid) + { + PhCopyCircularBuffer_FLOAT(&context->GpuHistory, context->GpuGraphState.Data1, drawInfo->LineDataCount); + context->GpuGraphState.Valid = TRUE; + } + } + else if (header->hwndFrom == context->MemGraphHandle) + { + if (PhGetIntegerSetting(L"GraphShowText")) + { + HDC hdc; + + PhMoveReference(&context->MemoryGraphState.Text, PhFormatString( + L"%s", + PhaFormatSize(UInt32x32To64(context->CurrentMemUsage, PAGE_SIZE), -1)->Buffer + )); + + hdc = Graph_GetBufferedContext(context->MemGraphHandle); + SelectObject(hdc, PhApplicationFont); + PhSetGraphText( + hdc, + drawInfo, + &context->MemoryGraphState.Text->sr, + &NormalGraphTextMargin, + &NormalGraphTextPadding, + PH_ALIGN_TOP | PH_ALIGN_LEFT + ); + } + else + { + drawInfo->Text.Buffer = NULL; + } + + drawInfo->Flags = PH_GRAPH_USE_GRID_X | PH_GRAPH_USE_GRID_Y; + PhSiSetColorsGraphDrawInfo(drawInfo, PhGetIntegerSetting(L"ColorPhysical"), 0); + PhGraphStateGetDrawInfo( + &context->MemoryGraphState, + getDrawInfo, + context->MemoryHistory.Count + ); + + if (!context->MemoryGraphState.Valid) + { + ULONG i = 0; + + for (i = 0; i < drawInfo->LineDataCount; i++) + { + context->MemoryGraphState.Data1[i] = (FLOAT)PhGetItemCircularBuffer_ULONG(&context->MemoryHistory, i); + } + + if (EtGpuDedicatedLimit != 0) + { + PhDivideSinglesBySingle( + context->MemoryGraphState.Data1, + (FLOAT)EtGpuDedicatedLimit / PAGE_SIZE, + drawInfo->LineDataCount + ); + } + + context->MemoryGraphState.Valid = TRUE; + } + } + else if (header->hwndFrom == context->SharedGraphHandle) + { + if (PhGetIntegerSetting(L"GraphShowText")) + { + HDC hdc; + + PhMoveReference(&context->MemorySharedGraphState.Text, PhFormatString( + L"%s", + PhaFormatSize(UInt32x32To64(context->CurrentMemSharedUsage, PAGE_SIZE), -1)->Buffer + )); + + hdc = Graph_GetBufferedContext(context->SharedGraphHandle); + SelectObject(hdc, PhApplicationFont); + PhSetGraphText(hdc, drawInfo, &context->MemorySharedGraphState.Text->sr, + &NormalGraphTextMargin, &NormalGraphTextPadding, PH_ALIGN_TOP | PH_ALIGN_LEFT); + } + else + { + drawInfo->Text.Buffer = NULL; + } + + drawInfo->Flags = PH_GRAPH_USE_GRID_X | PH_GRAPH_USE_GRID_Y; + PhSiSetColorsGraphDrawInfo(drawInfo, PhGetIntegerSetting(L"ColorPrivate"), 0); + PhGraphStateGetDrawInfo( + &context->MemorySharedGraphState, + getDrawInfo, + context->MemorySharedHistory.Count + ); + + if (!context->MemorySharedGraphState.Valid) + { + ULONG i = 0; + + for (i = 0; i < drawInfo->LineDataCount; i++) + { + context->MemorySharedGraphState.Data1[i] = (FLOAT)PhGetItemCircularBuffer_ULONG(&context->MemorySharedHistory, i); + } + + if (EtGpuSharedLimit != 0) + { + PhDivideSinglesBySingle( + context->MemorySharedGraphState.Data1, + (FLOAT)EtGpuSharedLimit / PAGE_SIZE, + drawInfo->LineDataCount + ); + } + + context->MemorySharedGraphState.Valid = TRUE; + } + } + } + break; + case GCN_GETTOOLTIPTEXT: + { + PPH_GRAPH_GETTOOLTIPTEXT getTooltipText = (PPH_GRAPH_GETTOOLTIPTEXT)lParam; + + if (getTooltipText->Index < getTooltipText->TotalCount) + { + if (header->hwndFrom == context->GpuGraphHandle) + { + if (context->GpuGraphState.TooltipIndex != getTooltipText->Index) + { + FLOAT gpuUsage = PhGetItemCircularBuffer_FLOAT( + &context->GpuHistory, + getTooltipText->Index + ); + + PhMoveReference(&context->GpuGraphState.TooltipText, PhFormatString( + L"%.2f%%", + gpuUsage * 100 + )); + } + + getTooltipText->Text = context->GpuGraphState.TooltipText->sr; + } + else if (header->hwndFrom == context->MemGraphHandle) + { + if (context->MemoryGraphState.TooltipIndex != getTooltipText->Index) + { + ULONG gpuMemory = PhGetItemCircularBuffer_ULONG( + &context->MemoryHistory, + getTooltipText->Index + ); + + PhMoveReference(&context->MemoryGraphState.TooltipText, + PhFormatSize(UInt32x32To64(gpuMemory, PAGE_SIZE), -1) + ); + } + + getTooltipText->Text = context->MemoryGraphState.TooltipText->sr; + } + else if (header->hwndFrom == context->SharedGraphHandle) + { + if (context->MemorySharedGraphState.TooltipIndex != getTooltipText->Index) + { + ULONG gpuSharedMemory = PhGetItemCircularBuffer_ULONG( + &context->MemorySharedHistory, + getTooltipText->Index + ); + + PhMoveReference(&context->MemorySharedGraphState.TooltipText, + PhFormatSize(UInt32x32To64(gpuSharedMemory, PAGE_SIZE), -1) + ); + } + + getTooltipText->Text = context->MemorySharedGraphState.TooltipText->sr; + } + } + } + break; + } + } + break; + case UPDATE_MSG: + { + if (context->Enabled) + { + GpuPropUpdateInfo(context); + GpuPropUpdateGraphs(context); + GpuPropUpdatePanel(context); + } + } + break; + case WM_SIZE: + { + GpuPropLayoutGraphs(context); + } + break; + } + + return FALSE; +} + +VOID EtProcessGpuPropertiesInitializing( + _In_ PVOID Parameter + ) +{ + PPH_PLUGIN_PROCESS_PROPCONTEXT propContext = Parameter; + + if (EtGpuEnabled) + { + PhAddProcessPropPage( + propContext->PropContext, + PhCreateProcessPropPageContextEx(PluginInstance->DllBase, MAKEINTRESOURCE(IDD_PROCGPU), EtpGpuPageDlgProc, NULL) + ); + } } \ No newline at end of file diff --git a/plugins/ExtendedTools/gpusys.c b/plugins/ExtendedTools/gpusys.c index b57e88e2ad71..57c9dcb68aae 100644 --- a/plugins/ExtendedTools/gpusys.c +++ b/plugins/ExtendedTools/gpusys.c @@ -1,722 +1,722 @@ -/* - * Process Hacker Extended Tools - - * GPU system information section - * - * Copyright (C) 2011 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include "exttools.h" -#include "gpusys.h" - -static PPH_SYSINFO_SECTION GpuSection; -static HWND GpuDialog; -static PH_LAYOUT_MANAGER GpuLayoutManager; -static RECT GpuGraphMargin; -static HWND GpuGraphHandle; -static PH_GRAPH_STATE GpuGraphState; -static HWND DedicatedGraphHandle; -static PH_GRAPH_STATE DedicatedGraphState; -static HWND SharedGraphHandle; -static PH_GRAPH_STATE SharedGraphState; -static HWND GpuPanel; - -VOID EtGpuSystemInformationInitializing( - _In_ PPH_PLUGIN_SYSINFO_POINTERS Pointers - ) -{ - PH_SYSINFO_SECTION section; - - memset(§ion, 0, sizeof(PH_SYSINFO_SECTION)); - PhInitializeStringRef(§ion.Name, L"GPU"); - section.Flags = 0; - section.Callback = EtpGpuSysInfoSectionCallback; - - GpuSection = Pointers->CreateSection(§ion); -} - -BOOLEAN EtpGpuSysInfoSectionCallback( - _In_ PPH_SYSINFO_SECTION Section, - _In_ PH_SYSINFO_SECTION_MESSAGE Message, - _In_opt_ PVOID Parameter1, - _In_opt_ PVOID Parameter2 - ) -{ - switch (Message) - { - case SysInfoDestroy: - { - if (GpuDialog) - { - EtpUninitializeGpuDialog(); - GpuDialog = NULL; - } - } - return TRUE; - case SysInfoTick: - { - if (GpuDialog) - { - EtpTickGpuDialog(); - } - } - return TRUE; - case SysInfoCreateDialog: - { - PPH_SYSINFO_CREATE_DIALOG createDialog = Parameter1; - - createDialog->Instance = PluginInstance->DllBase; - createDialog->Template = MAKEINTRESOURCE(IDD_SYSINFO_GPU); - createDialog->DialogProc = EtpGpuDialogProc; - } - return TRUE; - case SysInfoGraphGetDrawInfo: - { - PPH_GRAPH_DRAW_INFO drawInfo = Parameter1; - - drawInfo->Flags = PH_GRAPH_USE_GRID_X | PH_GRAPH_USE_GRID_Y; - Section->Parameters->ColorSetupFunction(drawInfo, PhGetIntegerSetting(L"ColorCpuKernel"), 0); - PhGetDrawInfoGraphBuffers(&Section->GraphState.Buffers, drawInfo, EtGpuNodeHistory.Count); - - if (!Section->GraphState.Valid) - { - PhCopyCircularBuffer_FLOAT(&EtGpuNodeHistory, Section->GraphState.Data1, drawInfo->LineDataCount); - Section->GraphState.Valid = TRUE; - } - } - return TRUE; - case SysInfoGraphGetTooltipText: - { - PPH_SYSINFO_GRAPH_GET_TOOLTIP_TEXT getTooltipText = Parameter1; - FLOAT gpu; - - gpu = PhGetItemCircularBuffer_FLOAT(&EtGpuNodeHistory, getTooltipText->Index); - - PhMoveReference(&Section->GraphState.TooltipText, PhFormatString( - L"%.2f%%%s\n%s", - gpu * 100, - PhGetStringOrEmpty(EtpGetMaxNodeString(getTooltipText->Index)), - ((PPH_STRING)PH_AUTO(PhGetStatisticsTimeString(NULL, getTooltipText->Index)))->Buffer - )); - getTooltipText->Text = Section->GraphState.TooltipText->sr; - } - return TRUE; - case SysInfoGraphDrawPanel: - { - PPH_SYSINFO_DRAW_PANEL drawPanel = Parameter1; - - drawPanel->Title = PhCreateString(L"GPU"); - drawPanel->SubTitle = PhFormatString(L"%.2f%%", EtGpuNodeUsage * 100); - } - return TRUE; - } - - return FALSE; -} - -VOID EtpInitializeGpuDialog( - VOID - ) -{ - PhInitializeGraphState(&GpuGraphState); - PhInitializeGraphState(&DedicatedGraphState); - PhInitializeGraphState(&SharedGraphState); -} - -VOID EtpUninitializeGpuDialog( - VOID - ) -{ - PhDeleteGraphState(&GpuGraphState); - PhDeleteGraphState(&DedicatedGraphState); - PhDeleteGraphState(&SharedGraphState); -} - -VOID EtpTickGpuDialog( - VOID - ) -{ - EtpUpdateGpuGraphs(); - EtpUpdateGpuPanel(); -} - -INT_PTR CALLBACK EtpGpuDialogProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - switch (uMsg) - { - case WM_INITDIALOG: - { - PPH_LAYOUT_ITEM graphItem; - PPH_LAYOUT_ITEM panelItem; - - EtpInitializeGpuDialog(); - - GpuDialog = hwndDlg; - PhInitializeLayoutManager(&GpuLayoutManager, hwndDlg); - PhAddLayoutItem(&GpuLayoutManager, GetDlgItem(hwndDlg, IDC_GPUNAME), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT | PH_LAYOUT_FORCE_INVALIDATE); - graphItem = PhAddLayoutItem(&GpuLayoutManager, GetDlgItem(hwndDlg, IDC_GRAPH_LAYOUT), NULL, PH_ANCHOR_ALL); - GpuGraphMargin = graphItem->Margin; - panelItem = PhAddLayoutItem(&GpuLayoutManager, GetDlgItem(hwndDlg, IDC_PANEL_LAYOUT), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); - - SendMessage(GetDlgItem(hwndDlg, IDC_TITLE), WM_SETFONT, (WPARAM)GpuSection->Parameters->LargeFont, FALSE); - SendMessage(GetDlgItem(hwndDlg, IDC_GPUNAME), WM_SETFONT, (WPARAM)GpuSection->Parameters->MediumFont, FALSE); - - SetDlgItemText(hwndDlg, IDC_GPUNAME, ((PPH_STRING)PH_AUTO(EtpGetGpuNameString()))->Buffer); - - GpuPanel = CreateDialog(PluginInstance->DllBase, MAKEINTRESOURCE(IDD_SYSINFO_GPUPANEL), hwndDlg, EtpGpuPanelDialogProc); - ShowWindow(GpuPanel, SW_SHOW); - PhAddLayoutItemEx(&GpuLayoutManager, GpuPanel, NULL, PH_ANCHOR_LEFT | PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM, panelItem->Margin); - - EtpCreateGpuGraphs(); - EtpUpdateGpuGraphs(); - EtpUpdateGpuPanel(); - } - break; - case WM_DESTROY: - { - PhDeleteLayoutManager(&GpuLayoutManager); - } - break; - case WM_SIZE: - { - PhLayoutManagerLayout(&GpuLayoutManager); - EtpLayoutGpuGraphs(); - } - break; - case WM_NOTIFY: - { - NMHDR *header = (NMHDR *)lParam; - - if (header->hwndFrom == GpuGraphHandle) - { - EtpNotifyGpuGraph(header); - } - else if (header->hwndFrom == DedicatedGraphHandle) - { - EtpNotifyDedicatedGraph(header); - } - else if (header->hwndFrom == SharedGraphHandle) - { - EtpNotifySharedGraph(header); - } - } - break; - } - - return FALSE; -} - -INT_PTR CALLBACK EtpGpuPanelDialogProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - switch (uMsg) - { - case WM_COMMAND: - { - switch (LOWORD(wParam)) - { - case IDC_NODES: - EtShowGpuNodesDialog(GpuDialog, GpuSection->Parameters); - break; - } - } - break; - } - - return FALSE; -} - -VOID EtpCreateGpuGraphs( - VOID - ) -{ - GpuGraphHandle = CreateWindow( - PH_GRAPH_CLASSNAME, - NULL, - WS_VISIBLE | WS_CHILD | WS_BORDER, - 0, - 0, - 3, - 3, - GpuDialog, - NULL, - NULL, - NULL - ); - Graph_SetTooltip(GpuGraphHandle, TRUE); - - DedicatedGraphHandle = CreateWindow( - PH_GRAPH_CLASSNAME, - NULL, - WS_VISIBLE | WS_CHILD | WS_BORDER, - 0, - 0, - 3, - 3, - GpuDialog, - NULL, - NULL, - NULL - ); - Graph_SetTooltip(DedicatedGraphHandle, TRUE); - - SharedGraphHandle = CreateWindow( - PH_GRAPH_CLASSNAME, - NULL, - WS_VISIBLE | WS_CHILD | WS_BORDER, - 0, - 0, - 3, - 3, - GpuDialog, - NULL, - NULL, - NULL - ); - Graph_SetTooltip(SharedGraphHandle, TRUE); -} - -VOID EtpLayoutGpuGraphs( - VOID - ) -{ - RECT clientRect; - RECT labelRect; - ULONG graphWidth; - ULONG graphHeight; - HDWP deferHandle; - ULONG y; - - GetClientRect(GpuDialog, &clientRect); - GetClientRect(GetDlgItem(GpuDialog, IDC_GPU_L), &labelRect); - graphWidth = clientRect.right - GpuGraphMargin.left - GpuGraphMargin.right; - graphHeight = (clientRect.bottom - GpuGraphMargin.top - GpuGraphMargin.bottom - labelRect.bottom * 3 - ET_GPU_PADDING * 5) / 3; - - deferHandle = BeginDeferWindowPos(6); - y = GpuGraphMargin.top; - - deferHandle = DeferWindowPos( - deferHandle, - GetDlgItem(GpuDialog, IDC_GPU_L), - NULL, - GpuGraphMargin.left, - y, - 0, - 0, - SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER - ); - y += labelRect.bottom + ET_GPU_PADDING; - - deferHandle = DeferWindowPos( - deferHandle, - GpuGraphHandle, - NULL, - GpuGraphMargin.left, - y, - graphWidth, - graphHeight, - SWP_NOACTIVATE | SWP_NOZORDER - ); - y += graphHeight + ET_GPU_PADDING; - - deferHandle = DeferWindowPos( - deferHandle, - GetDlgItem(GpuDialog, IDC_DEDICATED_L), - NULL, - GpuGraphMargin.left, - y, - 0, - 0, - SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER - ); - y += labelRect.bottom + ET_GPU_PADDING; - - deferHandle = DeferWindowPos( - deferHandle, - DedicatedGraphHandle, - NULL, - GpuGraphMargin.left, - y, - graphWidth, - graphHeight, - SWP_NOACTIVATE | SWP_NOZORDER - ); - y += graphHeight + ET_GPU_PADDING; - - deferHandle = DeferWindowPos( - deferHandle, - GetDlgItem(GpuDialog, IDC_SHARED_L), - NULL, - GpuGraphMargin.left, - y, - 0, - 0, - SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER - ); - y += labelRect.bottom + ET_GPU_PADDING; - - deferHandle = DeferWindowPos( - deferHandle, - SharedGraphHandle, - NULL, - GpuGraphMargin.left, - y, - graphWidth, - clientRect.bottom - GpuGraphMargin.bottom - y, - SWP_NOACTIVATE | SWP_NOZORDER - ); - - EndDeferWindowPos(deferHandle); -} - -VOID EtpNotifyGpuGraph( - _In_ NMHDR *Header - ) -{ - switch (Header->code) - { - case GCN_GETDRAWINFO: - { - PPH_GRAPH_GETDRAWINFO getDrawInfo = (PPH_GRAPH_GETDRAWINFO)Header; - PPH_GRAPH_DRAW_INFO drawInfo = getDrawInfo->DrawInfo; - - drawInfo->Flags = PH_GRAPH_USE_GRID_X | PH_GRAPH_USE_GRID_Y; - GpuSection->Parameters->ColorSetupFunction(drawInfo, PhGetIntegerSetting(L"ColorCpuKernel"), 0); - - PhGraphStateGetDrawInfo( - &GpuGraphState, - getDrawInfo, - EtGpuNodeHistory.Count - ); - - if (!GpuGraphState.Valid) - { - PhCopyCircularBuffer_FLOAT(&EtGpuNodeHistory, GpuGraphState.Data1, drawInfo->LineDataCount); - GpuGraphState.Valid = TRUE; - } - } - break; - case GCN_GETTOOLTIPTEXT: - { - PPH_GRAPH_GETTOOLTIPTEXT getTooltipText = (PPH_GRAPH_GETTOOLTIPTEXT)Header; - - if (getTooltipText->Index < getTooltipText->TotalCount) - { - if (GpuGraphState.TooltipIndex != getTooltipText->Index) - { - FLOAT gpu; - - gpu = PhGetItemCircularBuffer_FLOAT(&EtGpuNodeHistory, getTooltipText->Index); - - PhMoveReference(&GpuGraphState.TooltipText, PhFormatString( - L"%.2f%%%s\n%s", - gpu * 100, - PhGetStringOrEmpty(EtpGetMaxNodeString(getTooltipText->Index)), - ((PPH_STRING)PH_AUTO(PhGetStatisticsTimeString(NULL, getTooltipText->Index)))->Buffer - )); - } - - getTooltipText->Text = GpuGraphState.TooltipText->sr; - } - } - break; - case GCN_MOUSEEVENT: - { - PPH_GRAPH_MOUSEEVENT mouseEvent = (PPH_GRAPH_MOUSEEVENT)Header; - PPH_PROCESS_RECORD record; - - record = NULL; - - if (mouseEvent->Message == WM_LBUTTONDBLCLK && mouseEvent->Index < mouseEvent->TotalCount) - { - record = EtpReferenceMaxNodeRecord(mouseEvent->Index); - } - - if (record) - { - PhShowProcessRecordDialog(GpuDialog, record); - PhDereferenceProcessRecord(record); - } - } - break; - } -} - -VOID EtpNotifyDedicatedGraph( - _In_ NMHDR *Header - ) -{ - switch (Header->code) - { - case GCN_GETDRAWINFO: - { - PPH_GRAPH_GETDRAWINFO getDrawInfo = (PPH_GRAPH_GETDRAWINFO)Header; - PPH_GRAPH_DRAW_INFO drawInfo = getDrawInfo->DrawInfo; - ULONG i; - - drawInfo->Flags = PH_GRAPH_USE_GRID_X | PH_GRAPH_USE_GRID_Y; - GpuSection->Parameters->ColorSetupFunction(drawInfo, PhGetIntegerSetting(L"ColorPrivate"), 0); - - PhGraphStateGetDrawInfo( - &DedicatedGraphState, - getDrawInfo, - EtGpuDedicatedHistory.Count - ); - - if (!DedicatedGraphState.Valid) - { - for (i = 0; i < drawInfo->LineDataCount; i++) - { - DedicatedGraphState.Data1[i] = - (FLOAT)PhGetItemCircularBuffer_ULONG(&EtGpuDedicatedHistory, i); - } - - if (EtGpuDedicatedLimit != 0) - { - // Scale the data. - PhDivideSinglesBySingle( - DedicatedGraphState.Data1, - (FLOAT)EtGpuDedicatedLimit / PAGE_SIZE, - drawInfo->LineDataCount - ); - } - - DedicatedGraphState.Valid = TRUE; - } - } - break; - case GCN_GETTOOLTIPTEXT: - { - PPH_GRAPH_GETTOOLTIPTEXT getTooltipText = (PPH_GRAPH_GETTOOLTIPTEXT)Header; - - if (getTooltipText->Index < getTooltipText->TotalCount) - { - if (DedicatedGraphState.TooltipIndex != getTooltipText->Index) - { - ULONG usedPages; - - usedPages = PhGetItemCircularBuffer_ULONG(&EtGpuDedicatedHistory, getTooltipText->Index); - - PhMoveReference(&DedicatedGraphState.TooltipText, PhFormatString( - L"Dedicated Memory: %s\n%s", - PhaFormatSize(UInt32x32To64(usedPages, PAGE_SIZE), -1)->Buffer, - ((PPH_STRING)PH_AUTO(PhGetStatisticsTimeString(NULL, getTooltipText->Index)))->Buffer - )); - } - - getTooltipText->Text = DedicatedGraphState.TooltipText->sr; - } - } - break; - } -} - -VOID EtpNotifySharedGraph( - _In_ NMHDR *Header - ) -{ - switch (Header->code) - { - case GCN_GETDRAWINFO: - { - PPH_GRAPH_GETDRAWINFO getDrawInfo = (PPH_GRAPH_GETDRAWINFO)Header; - PPH_GRAPH_DRAW_INFO drawInfo = getDrawInfo->DrawInfo; - ULONG i; - - drawInfo->Flags = PH_GRAPH_USE_GRID_X | PH_GRAPH_USE_GRID_Y; - GpuSection->Parameters->ColorSetupFunction(drawInfo, PhGetIntegerSetting(L"ColorPhysical"), 0); - - PhGraphStateGetDrawInfo( - &SharedGraphState, - getDrawInfo, - EtGpuSharedHistory.Count - ); - - if (!SharedGraphState.Valid) - { - for (i = 0; i < drawInfo->LineDataCount; i++) - { - SharedGraphState.Data1[i] = - (FLOAT)PhGetItemCircularBuffer_ULONG(&EtGpuSharedHistory, i); - } - - if (EtGpuSharedLimit != 0) - { - // Scale the data. - PhDivideSinglesBySingle( - SharedGraphState.Data1, - (FLOAT)EtGpuSharedLimit / PAGE_SIZE, - drawInfo->LineDataCount - ); - } - - SharedGraphState.Valid = TRUE; - } - } - break; - case GCN_GETTOOLTIPTEXT: - { - PPH_GRAPH_GETTOOLTIPTEXT getTooltipText = (PPH_GRAPH_GETTOOLTIPTEXT)Header; - - if (getTooltipText->Index < getTooltipText->TotalCount) - { - if (SharedGraphState.TooltipIndex != getTooltipText->Index) - { - ULONG usedPages; - - usedPages = PhGetItemCircularBuffer_ULONG(&EtGpuSharedHistory, getTooltipText->Index); - - PhMoveReference(&SharedGraphState.TooltipText, PhFormatString( - L"Shared Memory: %s\n%s", - PhaFormatSize(UInt32x32To64(usedPages, PAGE_SIZE), -1)->Buffer, - ((PPH_STRING)PH_AUTO(PhGetStatisticsTimeString(NULL, getTooltipText->Index)))->Buffer - )); - } - - getTooltipText->Text = SharedGraphState.TooltipText->sr; - } - } - break; - } -} - -VOID EtpUpdateGpuGraphs( - VOID - ) -{ - GpuGraphState.Valid = FALSE; - GpuGraphState.TooltipIndex = -1; - Graph_MoveGrid(GpuGraphHandle, 1); - Graph_Draw(GpuGraphHandle); - Graph_UpdateTooltip(GpuGraphHandle); - InvalidateRect(GpuGraphHandle, NULL, FALSE); - - DedicatedGraphState.Valid = FALSE; - DedicatedGraphState.TooltipIndex = -1; - Graph_MoveGrid(DedicatedGraphHandle, 1); - Graph_Draw(DedicatedGraphHandle); - Graph_UpdateTooltip(DedicatedGraphHandle); - InvalidateRect(DedicatedGraphHandle, NULL, FALSE); - - SharedGraphState.Valid = FALSE; - SharedGraphState.TooltipIndex = -1; - Graph_MoveGrid(SharedGraphHandle, 1); - Graph_Draw(SharedGraphHandle); - Graph_UpdateTooltip(SharedGraphHandle); - InvalidateRect(SharedGraphHandle, NULL, FALSE); -} - -VOID EtpUpdateGpuPanel( - VOID - ) -{ - SetDlgItemText(GpuPanel, IDC_ZDEDICATEDCURRENT_V, PhaFormatSize(EtGpuDedicatedUsage, -1)->Buffer); - SetDlgItemText(GpuPanel, IDC_ZDEDICATEDLIMIT_V, PhaFormatSize(EtGpuDedicatedLimit, -1)->Buffer); - - SetDlgItemText(GpuPanel, IDC_ZSHAREDCURRENT_V, PhaFormatSize(EtGpuSharedUsage, -1)->Buffer); - SetDlgItemText(GpuPanel, IDC_ZSHAREDLIMIT_V, PhaFormatSize(EtGpuSharedLimit, -1)->Buffer); -} - -PPH_PROCESS_RECORD EtpReferenceMaxNodeRecord( - _In_ LONG Index - ) -{ - LARGE_INTEGER time; - ULONG maxProcessId; - - maxProcessId = PhGetItemCircularBuffer_ULONG(&EtMaxGpuNodeHistory, Index); - - if (!maxProcessId) - return NULL; - - PhGetStatisticsTime(NULL, Index, &time); - time.QuadPart += PH_TICKS_PER_SEC - 1; - - return PhFindProcessRecord(UlongToHandle(maxProcessId), &time); -} - -PPH_STRING EtpGetMaxNodeString( - _In_ LONG Index - ) -{ - PPH_PROCESS_RECORD maxProcessRecord; - FLOAT maxGpuUsage; - PPH_STRING maxUsageString = NULL; - - if (maxProcessRecord = EtpReferenceMaxNodeRecord(Index)) - { - maxGpuUsage = PhGetItemCircularBuffer_FLOAT(&EtMaxGpuNodeUsageHistory, Index); - - maxUsageString = PhaFormatString( - L"\n%s (%lu): %.2f%%", - maxProcessRecord->ProcessName->Buffer, - HandleToUlong(maxProcessRecord->ProcessId), - maxGpuUsage * 100 - ); - - PhDereferenceProcessRecord(maxProcessRecord); - } - - return maxUsageString; -} - -PPH_STRING EtpGetGpuNameString( - VOID - ) -{ - ULONG i; - ULONG count; - PH_STRING_BUILDER sb; - - count = EtGetGpuAdapterCount(); - PhInitializeStringBuilder(&sb, 100); - - for (i = 0; i < count; i++) - { - PPH_STRING description; - - description = EtGetGpuAdapterDescription(i); - - if (!PhIsNullOrEmptyString(description)) - { - // Ignore "Microsoft Basic Render Driver" unless we don't have any other adapters. - // This does not take into account localization. - if (count == 1 || !PhEqualString2(description, L"Microsoft Basic Render Driver", TRUE)) - { - PhAppendStringBuilder(&sb, &description->sr); - PhAppendStringBuilder2(&sb, L", "); - } - } - - if (description) - PhDereferenceObject(description); - } - - if (sb.String->Length != 0) - PhRemoveEndStringBuilder(&sb, 2); - - return PhFinalStringBuilderString(&sb); -} +/* + * Process Hacker Extended Tools - + * GPU system information section + * + * Copyright (C) 2011 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include "exttools.h" +#include "gpusys.h" + +static PPH_SYSINFO_SECTION GpuSection; +static HWND GpuDialog; +static PH_LAYOUT_MANAGER GpuLayoutManager; +static RECT GpuGraphMargin; +static HWND GpuGraphHandle; +static PH_GRAPH_STATE GpuGraphState; +static HWND DedicatedGraphHandle; +static PH_GRAPH_STATE DedicatedGraphState; +static HWND SharedGraphHandle; +static PH_GRAPH_STATE SharedGraphState; +static HWND GpuPanel; + +VOID EtGpuSystemInformationInitializing( + _In_ PPH_PLUGIN_SYSINFO_POINTERS Pointers + ) +{ + PH_SYSINFO_SECTION section; + + memset(§ion, 0, sizeof(PH_SYSINFO_SECTION)); + PhInitializeStringRef(§ion.Name, L"GPU"); + section.Flags = 0; + section.Callback = EtpGpuSysInfoSectionCallback; + + GpuSection = Pointers->CreateSection(§ion); +} + +BOOLEAN EtpGpuSysInfoSectionCallback( + _In_ PPH_SYSINFO_SECTION Section, + _In_ PH_SYSINFO_SECTION_MESSAGE Message, + _In_opt_ PVOID Parameter1, + _In_opt_ PVOID Parameter2 + ) +{ + switch (Message) + { + case SysInfoDestroy: + { + if (GpuDialog) + { + EtpUninitializeGpuDialog(); + GpuDialog = NULL; + } + } + return TRUE; + case SysInfoTick: + { + if (GpuDialog) + { + EtpTickGpuDialog(); + } + } + return TRUE; + case SysInfoCreateDialog: + { + PPH_SYSINFO_CREATE_DIALOG createDialog = Parameter1; + + createDialog->Instance = PluginInstance->DllBase; + createDialog->Template = MAKEINTRESOURCE(IDD_SYSINFO_GPU); + createDialog->DialogProc = EtpGpuDialogProc; + } + return TRUE; + case SysInfoGraphGetDrawInfo: + { + PPH_GRAPH_DRAW_INFO drawInfo = Parameter1; + + drawInfo->Flags = PH_GRAPH_USE_GRID_X | PH_GRAPH_USE_GRID_Y; + Section->Parameters->ColorSetupFunction(drawInfo, PhGetIntegerSetting(L"ColorCpuKernel"), 0); + PhGetDrawInfoGraphBuffers(&Section->GraphState.Buffers, drawInfo, EtGpuNodeHistory.Count); + + if (!Section->GraphState.Valid) + { + PhCopyCircularBuffer_FLOAT(&EtGpuNodeHistory, Section->GraphState.Data1, drawInfo->LineDataCount); + Section->GraphState.Valid = TRUE; + } + } + return TRUE; + case SysInfoGraphGetTooltipText: + { + PPH_SYSINFO_GRAPH_GET_TOOLTIP_TEXT getTooltipText = Parameter1; + FLOAT gpu; + + gpu = PhGetItemCircularBuffer_FLOAT(&EtGpuNodeHistory, getTooltipText->Index); + + PhMoveReference(&Section->GraphState.TooltipText, PhFormatString( + L"%.2f%%%s\n%s", + gpu * 100, + PhGetStringOrEmpty(EtpGetMaxNodeString(getTooltipText->Index)), + ((PPH_STRING)PH_AUTO(PhGetStatisticsTimeString(NULL, getTooltipText->Index)))->Buffer + )); + getTooltipText->Text = Section->GraphState.TooltipText->sr; + } + return TRUE; + case SysInfoGraphDrawPanel: + { + PPH_SYSINFO_DRAW_PANEL drawPanel = Parameter1; + + drawPanel->Title = PhCreateString(L"GPU"); + drawPanel->SubTitle = PhFormatString(L"%.2f%%", EtGpuNodeUsage * 100); + } + return TRUE; + } + + return FALSE; +} + +VOID EtpInitializeGpuDialog( + VOID + ) +{ + PhInitializeGraphState(&GpuGraphState); + PhInitializeGraphState(&DedicatedGraphState); + PhInitializeGraphState(&SharedGraphState); +} + +VOID EtpUninitializeGpuDialog( + VOID + ) +{ + PhDeleteGraphState(&GpuGraphState); + PhDeleteGraphState(&DedicatedGraphState); + PhDeleteGraphState(&SharedGraphState); +} + +VOID EtpTickGpuDialog( + VOID + ) +{ + EtpUpdateGpuGraphs(); + EtpUpdateGpuPanel(); +} + +INT_PTR CALLBACK EtpGpuDialogProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + switch (uMsg) + { + case WM_INITDIALOG: + { + PPH_LAYOUT_ITEM graphItem; + PPH_LAYOUT_ITEM panelItem; + + EtpInitializeGpuDialog(); + + GpuDialog = hwndDlg; + PhInitializeLayoutManager(&GpuLayoutManager, hwndDlg); + PhAddLayoutItem(&GpuLayoutManager, GetDlgItem(hwndDlg, IDC_GPUNAME), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT | PH_LAYOUT_FORCE_INVALIDATE); + graphItem = PhAddLayoutItem(&GpuLayoutManager, GetDlgItem(hwndDlg, IDC_GRAPH_LAYOUT), NULL, PH_ANCHOR_ALL); + GpuGraphMargin = graphItem->Margin; + panelItem = PhAddLayoutItem(&GpuLayoutManager, GetDlgItem(hwndDlg, IDC_PANEL_LAYOUT), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); + + SendMessage(GetDlgItem(hwndDlg, IDC_TITLE), WM_SETFONT, (WPARAM)GpuSection->Parameters->LargeFont, FALSE); + SendMessage(GetDlgItem(hwndDlg, IDC_GPUNAME), WM_SETFONT, (WPARAM)GpuSection->Parameters->MediumFont, FALSE); + + SetDlgItemText(hwndDlg, IDC_GPUNAME, ((PPH_STRING)PH_AUTO(EtpGetGpuNameString()))->Buffer); + + GpuPanel = CreateDialog(PluginInstance->DllBase, MAKEINTRESOURCE(IDD_SYSINFO_GPUPANEL), hwndDlg, EtpGpuPanelDialogProc); + ShowWindow(GpuPanel, SW_SHOW); + PhAddLayoutItemEx(&GpuLayoutManager, GpuPanel, NULL, PH_ANCHOR_LEFT | PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM, panelItem->Margin); + + EtpCreateGpuGraphs(); + EtpUpdateGpuGraphs(); + EtpUpdateGpuPanel(); + } + break; + case WM_DESTROY: + { + PhDeleteLayoutManager(&GpuLayoutManager); + } + break; + case WM_SIZE: + { + PhLayoutManagerLayout(&GpuLayoutManager); + EtpLayoutGpuGraphs(); + } + break; + case WM_NOTIFY: + { + NMHDR *header = (NMHDR *)lParam; + + if (header->hwndFrom == GpuGraphHandle) + { + EtpNotifyGpuGraph(header); + } + else if (header->hwndFrom == DedicatedGraphHandle) + { + EtpNotifyDedicatedGraph(header); + } + else if (header->hwndFrom == SharedGraphHandle) + { + EtpNotifySharedGraph(header); + } + } + break; + } + + return FALSE; +} + +INT_PTR CALLBACK EtpGpuPanelDialogProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + switch (uMsg) + { + case WM_COMMAND: + { + switch (LOWORD(wParam)) + { + case IDC_NODES: + EtShowGpuNodesDialog(GpuDialog, GpuSection->Parameters); + break; + } + } + break; + } + + return FALSE; +} + +VOID EtpCreateGpuGraphs( + VOID + ) +{ + GpuGraphHandle = CreateWindow( + PH_GRAPH_CLASSNAME, + NULL, + WS_VISIBLE | WS_CHILD | WS_BORDER, + 0, + 0, + 3, + 3, + GpuDialog, + NULL, + NULL, + NULL + ); + Graph_SetTooltip(GpuGraphHandle, TRUE); + + DedicatedGraphHandle = CreateWindow( + PH_GRAPH_CLASSNAME, + NULL, + WS_VISIBLE | WS_CHILD | WS_BORDER, + 0, + 0, + 3, + 3, + GpuDialog, + NULL, + NULL, + NULL + ); + Graph_SetTooltip(DedicatedGraphHandle, TRUE); + + SharedGraphHandle = CreateWindow( + PH_GRAPH_CLASSNAME, + NULL, + WS_VISIBLE | WS_CHILD | WS_BORDER, + 0, + 0, + 3, + 3, + GpuDialog, + NULL, + NULL, + NULL + ); + Graph_SetTooltip(SharedGraphHandle, TRUE); +} + +VOID EtpLayoutGpuGraphs( + VOID + ) +{ + RECT clientRect; + RECT labelRect; + ULONG graphWidth; + ULONG graphHeight; + HDWP deferHandle; + ULONG y; + + GetClientRect(GpuDialog, &clientRect); + GetClientRect(GetDlgItem(GpuDialog, IDC_GPU_L), &labelRect); + graphWidth = clientRect.right - GpuGraphMargin.left - GpuGraphMargin.right; + graphHeight = (clientRect.bottom - GpuGraphMargin.top - GpuGraphMargin.bottom - labelRect.bottom * 3 - ET_GPU_PADDING * 5) / 3; + + deferHandle = BeginDeferWindowPos(6); + y = GpuGraphMargin.top; + + deferHandle = DeferWindowPos( + deferHandle, + GetDlgItem(GpuDialog, IDC_GPU_L), + NULL, + GpuGraphMargin.left, + y, + 0, + 0, + SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER + ); + y += labelRect.bottom + ET_GPU_PADDING; + + deferHandle = DeferWindowPos( + deferHandle, + GpuGraphHandle, + NULL, + GpuGraphMargin.left, + y, + graphWidth, + graphHeight, + SWP_NOACTIVATE | SWP_NOZORDER + ); + y += graphHeight + ET_GPU_PADDING; + + deferHandle = DeferWindowPos( + deferHandle, + GetDlgItem(GpuDialog, IDC_DEDICATED_L), + NULL, + GpuGraphMargin.left, + y, + 0, + 0, + SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER + ); + y += labelRect.bottom + ET_GPU_PADDING; + + deferHandle = DeferWindowPos( + deferHandle, + DedicatedGraphHandle, + NULL, + GpuGraphMargin.left, + y, + graphWidth, + graphHeight, + SWP_NOACTIVATE | SWP_NOZORDER + ); + y += graphHeight + ET_GPU_PADDING; + + deferHandle = DeferWindowPos( + deferHandle, + GetDlgItem(GpuDialog, IDC_SHARED_L), + NULL, + GpuGraphMargin.left, + y, + 0, + 0, + SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER + ); + y += labelRect.bottom + ET_GPU_PADDING; + + deferHandle = DeferWindowPos( + deferHandle, + SharedGraphHandle, + NULL, + GpuGraphMargin.left, + y, + graphWidth, + clientRect.bottom - GpuGraphMargin.bottom - y, + SWP_NOACTIVATE | SWP_NOZORDER + ); + + EndDeferWindowPos(deferHandle); +} + +VOID EtpNotifyGpuGraph( + _In_ NMHDR *Header + ) +{ + switch (Header->code) + { + case GCN_GETDRAWINFO: + { + PPH_GRAPH_GETDRAWINFO getDrawInfo = (PPH_GRAPH_GETDRAWINFO)Header; + PPH_GRAPH_DRAW_INFO drawInfo = getDrawInfo->DrawInfo; + + drawInfo->Flags = PH_GRAPH_USE_GRID_X | PH_GRAPH_USE_GRID_Y; + GpuSection->Parameters->ColorSetupFunction(drawInfo, PhGetIntegerSetting(L"ColorCpuKernel"), 0); + + PhGraphStateGetDrawInfo( + &GpuGraphState, + getDrawInfo, + EtGpuNodeHistory.Count + ); + + if (!GpuGraphState.Valid) + { + PhCopyCircularBuffer_FLOAT(&EtGpuNodeHistory, GpuGraphState.Data1, drawInfo->LineDataCount); + GpuGraphState.Valid = TRUE; + } + } + break; + case GCN_GETTOOLTIPTEXT: + { + PPH_GRAPH_GETTOOLTIPTEXT getTooltipText = (PPH_GRAPH_GETTOOLTIPTEXT)Header; + + if (getTooltipText->Index < getTooltipText->TotalCount) + { + if (GpuGraphState.TooltipIndex != getTooltipText->Index) + { + FLOAT gpu; + + gpu = PhGetItemCircularBuffer_FLOAT(&EtGpuNodeHistory, getTooltipText->Index); + + PhMoveReference(&GpuGraphState.TooltipText, PhFormatString( + L"%.2f%%%s\n%s", + gpu * 100, + PhGetStringOrEmpty(EtpGetMaxNodeString(getTooltipText->Index)), + ((PPH_STRING)PH_AUTO(PhGetStatisticsTimeString(NULL, getTooltipText->Index)))->Buffer + )); + } + + getTooltipText->Text = GpuGraphState.TooltipText->sr; + } + } + break; + case GCN_MOUSEEVENT: + { + PPH_GRAPH_MOUSEEVENT mouseEvent = (PPH_GRAPH_MOUSEEVENT)Header; + PPH_PROCESS_RECORD record; + + record = NULL; + + if (mouseEvent->Message == WM_LBUTTONDBLCLK && mouseEvent->Index < mouseEvent->TotalCount) + { + record = EtpReferenceMaxNodeRecord(mouseEvent->Index); + } + + if (record) + { + PhShowProcessRecordDialog(GpuDialog, record); + PhDereferenceProcessRecord(record); + } + } + break; + } +} + +VOID EtpNotifyDedicatedGraph( + _In_ NMHDR *Header + ) +{ + switch (Header->code) + { + case GCN_GETDRAWINFO: + { + PPH_GRAPH_GETDRAWINFO getDrawInfo = (PPH_GRAPH_GETDRAWINFO)Header; + PPH_GRAPH_DRAW_INFO drawInfo = getDrawInfo->DrawInfo; + ULONG i; + + drawInfo->Flags = PH_GRAPH_USE_GRID_X | PH_GRAPH_USE_GRID_Y; + GpuSection->Parameters->ColorSetupFunction(drawInfo, PhGetIntegerSetting(L"ColorPrivate"), 0); + + PhGraphStateGetDrawInfo( + &DedicatedGraphState, + getDrawInfo, + EtGpuDedicatedHistory.Count + ); + + if (!DedicatedGraphState.Valid) + { + for (i = 0; i < drawInfo->LineDataCount; i++) + { + DedicatedGraphState.Data1[i] = + (FLOAT)PhGetItemCircularBuffer_ULONG(&EtGpuDedicatedHistory, i); + } + + if (EtGpuDedicatedLimit != 0) + { + // Scale the data. + PhDivideSinglesBySingle( + DedicatedGraphState.Data1, + (FLOAT)EtGpuDedicatedLimit / PAGE_SIZE, + drawInfo->LineDataCount + ); + } + + DedicatedGraphState.Valid = TRUE; + } + } + break; + case GCN_GETTOOLTIPTEXT: + { + PPH_GRAPH_GETTOOLTIPTEXT getTooltipText = (PPH_GRAPH_GETTOOLTIPTEXT)Header; + + if (getTooltipText->Index < getTooltipText->TotalCount) + { + if (DedicatedGraphState.TooltipIndex != getTooltipText->Index) + { + ULONG usedPages; + + usedPages = PhGetItemCircularBuffer_ULONG(&EtGpuDedicatedHistory, getTooltipText->Index); + + PhMoveReference(&DedicatedGraphState.TooltipText, PhFormatString( + L"Dedicated Memory: %s\n%s", + PhaFormatSize(UInt32x32To64(usedPages, PAGE_SIZE), -1)->Buffer, + ((PPH_STRING)PH_AUTO(PhGetStatisticsTimeString(NULL, getTooltipText->Index)))->Buffer + )); + } + + getTooltipText->Text = DedicatedGraphState.TooltipText->sr; + } + } + break; + } +} + +VOID EtpNotifySharedGraph( + _In_ NMHDR *Header + ) +{ + switch (Header->code) + { + case GCN_GETDRAWINFO: + { + PPH_GRAPH_GETDRAWINFO getDrawInfo = (PPH_GRAPH_GETDRAWINFO)Header; + PPH_GRAPH_DRAW_INFO drawInfo = getDrawInfo->DrawInfo; + ULONG i; + + drawInfo->Flags = PH_GRAPH_USE_GRID_X | PH_GRAPH_USE_GRID_Y; + GpuSection->Parameters->ColorSetupFunction(drawInfo, PhGetIntegerSetting(L"ColorPhysical"), 0); + + PhGraphStateGetDrawInfo( + &SharedGraphState, + getDrawInfo, + EtGpuSharedHistory.Count + ); + + if (!SharedGraphState.Valid) + { + for (i = 0; i < drawInfo->LineDataCount; i++) + { + SharedGraphState.Data1[i] = + (FLOAT)PhGetItemCircularBuffer_ULONG(&EtGpuSharedHistory, i); + } + + if (EtGpuSharedLimit != 0) + { + // Scale the data. + PhDivideSinglesBySingle( + SharedGraphState.Data1, + (FLOAT)EtGpuSharedLimit / PAGE_SIZE, + drawInfo->LineDataCount + ); + } + + SharedGraphState.Valid = TRUE; + } + } + break; + case GCN_GETTOOLTIPTEXT: + { + PPH_GRAPH_GETTOOLTIPTEXT getTooltipText = (PPH_GRAPH_GETTOOLTIPTEXT)Header; + + if (getTooltipText->Index < getTooltipText->TotalCount) + { + if (SharedGraphState.TooltipIndex != getTooltipText->Index) + { + ULONG usedPages; + + usedPages = PhGetItemCircularBuffer_ULONG(&EtGpuSharedHistory, getTooltipText->Index); + + PhMoveReference(&SharedGraphState.TooltipText, PhFormatString( + L"Shared Memory: %s\n%s", + PhaFormatSize(UInt32x32To64(usedPages, PAGE_SIZE), -1)->Buffer, + ((PPH_STRING)PH_AUTO(PhGetStatisticsTimeString(NULL, getTooltipText->Index)))->Buffer + )); + } + + getTooltipText->Text = SharedGraphState.TooltipText->sr; + } + } + break; + } +} + +VOID EtpUpdateGpuGraphs( + VOID + ) +{ + GpuGraphState.Valid = FALSE; + GpuGraphState.TooltipIndex = -1; + Graph_MoveGrid(GpuGraphHandle, 1); + Graph_Draw(GpuGraphHandle); + Graph_UpdateTooltip(GpuGraphHandle); + InvalidateRect(GpuGraphHandle, NULL, FALSE); + + DedicatedGraphState.Valid = FALSE; + DedicatedGraphState.TooltipIndex = -1; + Graph_MoveGrid(DedicatedGraphHandle, 1); + Graph_Draw(DedicatedGraphHandle); + Graph_UpdateTooltip(DedicatedGraphHandle); + InvalidateRect(DedicatedGraphHandle, NULL, FALSE); + + SharedGraphState.Valid = FALSE; + SharedGraphState.TooltipIndex = -1; + Graph_MoveGrid(SharedGraphHandle, 1); + Graph_Draw(SharedGraphHandle); + Graph_UpdateTooltip(SharedGraphHandle); + InvalidateRect(SharedGraphHandle, NULL, FALSE); +} + +VOID EtpUpdateGpuPanel( + VOID + ) +{ + SetDlgItemText(GpuPanel, IDC_ZDEDICATEDCURRENT_V, PhaFormatSize(EtGpuDedicatedUsage, -1)->Buffer); + SetDlgItemText(GpuPanel, IDC_ZDEDICATEDLIMIT_V, PhaFormatSize(EtGpuDedicatedLimit, -1)->Buffer); + + SetDlgItemText(GpuPanel, IDC_ZSHAREDCURRENT_V, PhaFormatSize(EtGpuSharedUsage, -1)->Buffer); + SetDlgItemText(GpuPanel, IDC_ZSHAREDLIMIT_V, PhaFormatSize(EtGpuSharedLimit, -1)->Buffer); +} + +PPH_PROCESS_RECORD EtpReferenceMaxNodeRecord( + _In_ LONG Index + ) +{ + LARGE_INTEGER time; + ULONG maxProcessId; + + maxProcessId = PhGetItemCircularBuffer_ULONG(&EtMaxGpuNodeHistory, Index); + + if (!maxProcessId) + return NULL; + + PhGetStatisticsTime(NULL, Index, &time); + time.QuadPart += PH_TICKS_PER_SEC - 1; + + return PhFindProcessRecord(UlongToHandle(maxProcessId), &time); +} + +PPH_STRING EtpGetMaxNodeString( + _In_ LONG Index + ) +{ + PPH_PROCESS_RECORD maxProcessRecord; + FLOAT maxGpuUsage; + PPH_STRING maxUsageString = NULL; + + if (maxProcessRecord = EtpReferenceMaxNodeRecord(Index)) + { + maxGpuUsage = PhGetItemCircularBuffer_FLOAT(&EtMaxGpuNodeUsageHistory, Index); + + maxUsageString = PhaFormatString( + L"\n%s (%lu): %.2f%%", + maxProcessRecord->ProcessName->Buffer, + HandleToUlong(maxProcessRecord->ProcessId), + maxGpuUsage * 100 + ); + + PhDereferenceProcessRecord(maxProcessRecord); + } + + return maxUsageString; +} + +PPH_STRING EtpGetGpuNameString( + VOID + ) +{ + ULONG i; + ULONG count; + PH_STRING_BUILDER sb; + + count = EtGetGpuAdapterCount(); + PhInitializeStringBuilder(&sb, 100); + + for (i = 0; i < count; i++) + { + PPH_STRING description; + + description = EtGetGpuAdapterDescription(i); + + if (!PhIsNullOrEmptyString(description)) + { + // Ignore "Microsoft Basic Render Driver" unless we don't have any other adapters. + // This does not take into account localization. + if (count == 1 || !PhEqualString2(description, L"Microsoft Basic Render Driver", TRUE)) + { + PhAppendStringBuilder(&sb, &description->sr); + PhAppendStringBuilder2(&sb, L", "); + } + } + + if (description) + PhDereferenceObject(description); + } + + if (sb.String->Length != 0) + PhRemoveEndStringBuilder(&sb, 2); + + return PhFinalStringBuilderString(&sb); +} diff --git a/plugins/ExtendedTools/gpusys.h b/plugins/ExtendedTools/gpusys.h index 6162fd142079..9cc138a506e1 100644 --- a/plugins/ExtendedTools/gpusys.h +++ b/plugins/ExtendedTools/gpusys.h @@ -1,79 +1,79 @@ -#ifndef GPUSYS_H -#define GPUSYS_H - -#define ET_GPU_PADDING 3 - -BOOLEAN EtpGpuSysInfoSectionCallback( - _In_ PPH_SYSINFO_SECTION Section, - _In_ PH_SYSINFO_SECTION_MESSAGE Message, - _In_opt_ PVOID Parameter1, - _In_opt_ PVOID Parameter2 - ); - -VOID EtpInitializeGpuDialog( - VOID - ); - -VOID EtpUninitializeGpuDialog( - VOID - ); - -VOID EtpTickGpuDialog( - VOID - ); - -INT_PTR CALLBACK EtpGpuDialogProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -INT_PTR CALLBACK EtpGpuPanelDialogProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -VOID EtpCreateGpuGraphs( - VOID - ); - -VOID EtpLayoutGpuGraphs( - VOID - ); - -VOID EtpNotifyGpuGraph( - _In_ NMHDR *Header - ); - -VOID EtpNotifyDedicatedGraph( - _In_ NMHDR *Header - ); - -VOID EtpNotifySharedGraph( - _In_ NMHDR *Header - ); - -VOID EtpUpdateGpuGraphs( - VOID - ); - -VOID EtpUpdateGpuPanel( - VOID - ); - -PPH_PROCESS_RECORD EtpReferenceMaxNodeRecord( - _In_ LONG Index - ); - -PPH_STRING EtpGetMaxNodeString( - _In_ LONG Index - ); - -PPH_STRING EtpGetGpuNameString( - VOID - ); - -#endif +#ifndef GPUSYS_H +#define GPUSYS_H + +#define ET_GPU_PADDING 3 + +BOOLEAN EtpGpuSysInfoSectionCallback( + _In_ PPH_SYSINFO_SECTION Section, + _In_ PH_SYSINFO_SECTION_MESSAGE Message, + _In_opt_ PVOID Parameter1, + _In_opt_ PVOID Parameter2 + ); + +VOID EtpInitializeGpuDialog( + VOID + ); + +VOID EtpUninitializeGpuDialog( + VOID + ); + +VOID EtpTickGpuDialog( + VOID + ); + +INT_PTR CALLBACK EtpGpuDialogProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +INT_PTR CALLBACK EtpGpuPanelDialogProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +VOID EtpCreateGpuGraphs( + VOID + ); + +VOID EtpLayoutGpuGraphs( + VOID + ); + +VOID EtpNotifyGpuGraph( + _In_ NMHDR *Header + ); + +VOID EtpNotifyDedicatedGraph( + _In_ NMHDR *Header + ); + +VOID EtpNotifySharedGraph( + _In_ NMHDR *Header + ); + +VOID EtpUpdateGpuGraphs( + VOID + ); + +VOID EtpUpdateGpuPanel( + VOID + ); + +PPH_PROCESS_RECORD EtpReferenceMaxNodeRecord( + _In_ LONG Index + ); + +PPH_STRING EtpGetMaxNodeString( + _In_ LONG Index + ); + +PPH_STRING EtpGetGpuNameString( + VOID + ); + +#endif diff --git a/plugins/ExtendedTools/iconext.c b/plugins/ExtendedTools/iconext.c index ce4d0c5ec807..e125bf364e64 100644 --- a/plugins/ExtendedTools/iconext.c +++ b/plugins/ExtendedTools/iconext.c @@ -1,466 +1,466 @@ -/* - * Process Hacker Extended Tools - - * notification icon extensions - * - * Copyright (C) 2011 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include "exttools.h" - -#define GPU_ICON_ID 1 -#define DISK_ICON_ID 2 -#define NETWORK_ICON_ID 3 - -VOID EtpGpuIconUpdateCallback( - _In_ struct _PH_NF_ICON *Icon, - _Out_ PVOID *NewIconOrBitmap, - _Out_ PULONG Flags, - _Out_ PPH_STRING *NewText, - _In_opt_ PVOID Context - ); - -BOOLEAN EtpGpuIconMessageCallback( - _In_ struct _PH_NF_ICON *Icon, - _In_ ULONG_PTR WParam, - _In_ ULONG_PTR LParam, - _In_opt_ PVOID Context - ); - -VOID EtpDiskIconUpdateCallback( - _In_ struct _PH_NF_ICON *Icon, - _Out_ PVOID *NewIconOrBitmap, - _Out_ PULONG Flags, - _Out_ PPH_STRING *NewText, - _In_opt_ PVOID Context - ); - -BOOLEAN EtpDiskIconMessageCallback( - _In_ struct _PH_NF_ICON *Icon, - _In_ ULONG_PTR WParam, - _In_ ULONG_PTR LParam, - _In_opt_ PVOID Context - ); - -VOID EtpNetworkIconUpdateCallback( - _In_ struct _PH_NF_ICON *Icon, - _Out_ PVOID *NewIconOrBitmap, - _Out_ PULONG Flags, - _Out_ PPH_STRING *NewText, - _In_opt_ PVOID Context - ); - -BOOLEAN EtpNetworkIconMessageCallback( - _In_ struct _PH_NF_ICON *Icon, - _In_ ULONG_PTR WParam, - _In_ ULONG_PTR LParam, - _In_opt_ PVOID Context - ); - -VOID EtRegisterNotifyIcons( - VOID - ) -{ - PH_NF_ICON_REGISTRATION_DATA data; - - data.MessageCallback = NULL; - - data.UpdateCallback = EtpGpuIconUpdateCallback; - data.MessageCallback = EtpGpuIconMessageCallback; - PhPluginRegisterIcon( - PluginInstance, - GPU_ICON_ID, - NULL, - L"GPU history", - PH_NF_ICON_SHOW_MINIINFO | (EtGpuEnabled ? 0 : PH_NF_ICON_UNAVAILABLE), - &data - ); - - data.UpdateCallback = EtpDiskIconUpdateCallback; - data.MessageCallback = EtpDiskIconMessageCallback; - PhPluginRegisterIcon( - PluginInstance, - DISK_ICON_ID, - NULL, - L"Disk history", - PH_NF_ICON_SHOW_MINIINFO | (EtEtwEnabled ? 0 : PH_NF_ICON_UNAVAILABLE), - &data - ); - - data.UpdateCallback = EtpNetworkIconUpdateCallback; - data.MessageCallback = EtpNetworkIconMessageCallback; - PhPluginRegisterIcon( - PluginInstance, - NETWORK_ICON_ID, - NULL, - L"Network history", - PH_NF_ICON_SHOW_MINIINFO | (EtEtwEnabled ? 0 : PH_NF_ICON_UNAVAILABLE), - &data - ); -} - -VOID EtpGpuIconUpdateCallback( - _In_ struct _PH_NF_ICON *Icon, - _Out_ PVOID *NewIconOrBitmap, - _Out_ PULONG Flags, - _Out_ PPH_STRING *NewText, - _In_opt_ PVOID Context - ) -{ - static PH_GRAPH_DRAW_INFO drawInfo = - { - 16, - 16, - 0, - 2, - RGB(0x00, 0x00, 0x00), - - 16, - NULL, - NULL, - 0, - 0, - 0, - 0 - }; - ULONG maxDataCount; - ULONG lineDataCount; - PFLOAT lineData1; - HBITMAP bitmap; - PVOID bits; - HDC hdc; - HBITMAP oldBitmap; - HANDLE maxGpuProcessId; - PPH_PROCESS_ITEM maxGpuProcessItem; - PH_FORMAT format[8]; - - // Icon - - Icon->Pointers->BeginBitmap(&drawInfo.Width, &drawInfo.Height, &bitmap, &bits, &hdc, &oldBitmap); - maxDataCount = drawInfo.Width / 2 + 1; - lineData1 = _alloca(maxDataCount * sizeof(FLOAT)); - - lineDataCount = min(maxDataCount, EtGpuNodeHistory.Count); - PhCopyCircularBuffer_FLOAT(&EtGpuNodeHistory, lineData1, lineDataCount); - - drawInfo.LineDataCount = lineDataCount; - drawInfo.LineData1 = lineData1; - drawInfo.LineColor1 = PhGetIntegerSetting(L"ColorCpuKernel"); - drawInfo.LineBackColor1 = PhHalveColorBrightness(drawInfo.LineColor1); - - if (bits) - PhDrawGraphDirect(hdc, bits, &drawInfo); - - SelectObject(hdc, oldBitmap); - *NewIconOrBitmap = bitmap; - *Flags = PH_NF_UPDATE_IS_BITMAP; - - // Text - - if (EtMaxGpuNodeHistory.Count != 0) - maxGpuProcessId = UlongToHandle(PhGetItemCircularBuffer_ULONG(&EtMaxGpuNodeHistory, 0)); - else - maxGpuProcessId = NULL; - - if (maxGpuProcessId) - maxGpuProcessItem = PhReferenceProcessItem(maxGpuProcessId); - else - maxGpuProcessItem = NULL; - - PhInitFormatS(&format[0], L"GPU Usage: "); - PhInitFormatF(&format[1], EtGpuNodeUsage * 100, 2); - PhInitFormatC(&format[2], '%'); - - if (maxGpuProcessItem) - { - PhInitFormatC(&format[3], '\n'); - PhInitFormatSR(&format[4], maxGpuProcessItem->ProcessName->sr); - PhInitFormatS(&format[5], L": "); - PhInitFormatF(&format[6], EtGetProcessBlock(maxGpuProcessItem)->GpuNodeUsage * 100, 2); - PhInitFormatC(&format[7], '%'); - } - - *NewText = PhFormat(format, maxGpuProcessItem ? 8 : 3, 128); - if (maxGpuProcessItem) PhDereferenceObject(maxGpuProcessItem); -} - -BOOLEAN EtpGpuIconMessageCallback( - _In_ struct _PH_NF_ICON *Icon, - _In_ ULONG_PTR WParam, - _In_ ULONG_PTR LParam, - _In_opt_ PVOID Context - ) -{ - switch (LOWORD(LParam)) - { - case PH_NF_MSG_SHOWMINIINFOSECTION: - { - PPH_NF_MSG_SHOWMINIINFOSECTION_DATA data = (PVOID)WParam; - - data->SectionName = L"GPU"; - } - return TRUE; - } - - return FALSE; -} - -VOID EtpDiskIconUpdateCallback( - _In_ struct _PH_NF_ICON *Icon, - _Out_ PVOID *NewIconOrBitmap, - _Out_ PULONG Flags, - _Out_ PPH_STRING *NewText, - _In_opt_ PVOID Context - ) -{ - static PH_GRAPH_DRAW_INFO drawInfo = - { - 16, - 16, - PH_GRAPH_USE_LINE_2, - 2, - RGB(0x00, 0x00, 0x00), - - 16, - NULL, - NULL, - 0, - 0, - 0, - 0 - }; - ULONG maxDataCount; - ULONG lineDataCount; - PFLOAT lineData1; - PFLOAT lineData2; - FLOAT max; - ULONG i; - HBITMAP bitmap; - PVOID bits; - HDC hdc; - HBITMAP oldBitmap; - HANDLE maxDiskProcessId; - PPH_PROCESS_ITEM maxDiskProcessItem; - PH_FORMAT format[6]; - - // Icon - - Icon->Pointers->BeginBitmap(&drawInfo.Width, &drawInfo.Height, &bitmap, &bits, &hdc, &oldBitmap); - maxDataCount = drawInfo.Width / 2 + 1; - lineData1 = _alloca(maxDataCount * sizeof(FLOAT)); - lineData2 = _alloca(maxDataCount * sizeof(FLOAT)); - - lineDataCount = min(maxDataCount, EtDiskReadHistory.Count); - max = 1024 * 1024; // minimum scaling of 1 MB. - - for (i = 0; i < lineDataCount; i++) - { - lineData1[i] = (FLOAT)PhGetItemCircularBuffer_ULONG(&EtDiskReadHistory, i); - lineData2[i] = (FLOAT)PhGetItemCircularBuffer_ULONG(&EtDiskWriteHistory, i); - - if (max < lineData1[i] + lineData2[i]) - max = lineData1[i] + lineData2[i]; - } - - PhDivideSinglesBySingle(lineData1, max, lineDataCount); - PhDivideSinglesBySingle(lineData2, max, lineDataCount); - - drawInfo.LineDataCount = lineDataCount; - drawInfo.LineData1 = lineData1; - drawInfo.LineData2 = lineData2; - drawInfo.LineColor1 = PhGetIntegerSetting(L"ColorIoReadOther"); - drawInfo.LineColor2 = PhGetIntegerSetting(L"ColorIoWrite"); - drawInfo.LineBackColor1 = PhHalveColorBrightness(drawInfo.LineColor1); - drawInfo.LineBackColor2 = PhHalveColorBrightness(drawInfo.LineColor2); - - if (bits) - PhDrawGraphDirect(hdc, bits, &drawInfo); - - SelectObject(hdc, oldBitmap); - *NewIconOrBitmap = bitmap; - *Flags = PH_NF_UPDATE_IS_BITMAP; - - // Text - - if (EtMaxDiskHistory.Count != 0) - maxDiskProcessId = UlongToHandle(PhGetItemCircularBuffer_ULONG(&EtMaxDiskHistory, 0)); - else - maxDiskProcessId = NULL; - - if (maxDiskProcessId) - maxDiskProcessItem = PhReferenceProcessItem(maxDiskProcessId); - else - maxDiskProcessItem = NULL; - - PhInitFormatS(&format[0], L"Disk\nR: "); - PhInitFormatSize(&format[1], EtDiskReadDelta.Delta); - PhInitFormatS(&format[2], L"\nW: "); - PhInitFormatSize(&format[3], EtDiskWriteDelta.Delta); - - if (maxDiskProcessItem) - { - PhInitFormatC(&format[4], '\n'); - PhInitFormatSR(&format[5], maxDiskProcessItem->ProcessName->sr); - } - - *NewText = PhFormat(format, maxDiskProcessItem ? 6 : 4, 128); - if (maxDiskProcessItem) PhDereferenceObject(maxDiskProcessItem); -} - -BOOLEAN EtpDiskIconMessageCallback( - _In_ struct _PH_NF_ICON *Icon, - _In_ ULONG_PTR WParam, - _In_ ULONG_PTR LParam, - _In_opt_ PVOID Context - ) -{ - switch (LOWORD(LParam)) - { - case PH_NF_MSG_SHOWMINIINFOSECTION: - { - PPH_NF_MSG_SHOWMINIINFOSECTION_DATA data = (PVOID)WParam; - - data->SectionName = L"Disk"; - } - return TRUE; - } - - return FALSE; -} - -VOID EtpNetworkIconUpdateCallback( - _In_ struct _PH_NF_ICON *Icon, - _Out_ PVOID *NewIconOrBitmap, - _Out_ PULONG Flags, - _Out_ PPH_STRING *NewText, - _In_opt_ PVOID Context - ) -{ - static PH_GRAPH_DRAW_INFO drawInfo = - { - 16, - 16, - PH_GRAPH_USE_LINE_2, - 2, - RGB(0x00, 0x00, 0x00), - - 16, - NULL, - NULL, - 0, - 0, - 0, - 0 - }; - ULONG maxDataCount; - ULONG lineDataCount; - PFLOAT lineData1; - PFLOAT lineData2; - FLOAT max; - ULONG i; - HBITMAP bitmap; - PVOID bits; - HDC hdc; - HBITMAP oldBitmap; - HANDLE maxNetworkProcessId; - PPH_PROCESS_ITEM maxNetworkProcessItem; - PH_FORMAT format[6]; - - // Icon - - Icon->Pointers->BeginBitmap(&drawInfo.Width, &drawInfo.Height, &bitmap, &bits, &hdc, &oldBitmap); - maxDataCount = drawInfo.Width / 2 + 1; - lineData1 = _alloca(maxDataCount * sizeof(FLOAT)); - lineData2 = _alloca(maxDataCount * sizeof(FLOAT)); - - lineDataCount = min(maxDataCount, EtNetworkReceiveHistory.Count); - max = 1024 * 1024; // minimum scaling of 1 MB. - - for (i = 0; i < lineDataCount; i++) - { - lineData1[i] = (FLOAT)PhGetItemCircularBuffer_ULONG(&EtNetworkReceiveHistory, i); - lineData2[i] = (FLOAT)PhGetItemCircularBuffer_ULONG(&EtNetworkSendHistory, i); - - if (max < lineData1[i] + lineData2[i]) - max = lineData1[i] + lineData2[i]; - } - - PhDivideSinglesBySingle(lineData1, max, lineDataCount); - PhDivideSinglesBySingle(lineData2, max, lineDataCount); - - drawInfo.LineDataCount = lineDataCount; - drawInfo.LineData1 = lineData1; - drawInfo.LineData2 = lineData2; - drawInfo.LineColor1 = PhGetIntegerSetting(L"ColorIoReadOther"); - drawInfo.LineColor2 = PhGetIntegerSetting(L"ColorIoWrite"); - drawInfo.LineBackColor1 = PhHalveColorBrightness(drawInfo.LineColor1); - drawInfo.LineBackColor2 = PhHalveColorBrightness(drawInfo.LineColor2); - - if (bits) - PhDrawGraphDirect(hdc, bits, &drawInfo); - - SelectObject(hdc, oldBitmap); - *NewIconOrBitmap = bitmap; - *Flags = PH_NF_UPDATE_IS_BITMAP; - - // Text - - if (EtMaxNetworkHistory.Count != 0) - maxNetworkProcessId = UlongToHandle(PhGetItemCircularBuffer_ULONG(&EtMaxNetworkHistory, 0)); - else - maxNetworkProcessId = NULL; - - if (maxNetworkProcessId) - maxNetworkProcessItem = PhReferenceProcessItem(maxNetworkProcessId); - else - maxNetworkProcessItem = NULL; - - PhInitFormatS(&format[0], L"Network\nR: "); - PhInitFormatSize(&format[1], EtNetworkReceiveDelta.Delta); - PhInitFormatS(&format[2], L"\nS: "); - PhInitFormatSize(&format[3], EtNetworkSendDelta.Delta); - - if (maxNetworkProcessItem) - { - PhInitFormatC(&format[4], '\n'); - PhInitFormatSR(&format[5], maxNetworkProcessItem->ProcessName->sr); - } - - *NewText = PhFormat(format, maxNetworkProcessItem ? 6 : 4, 128); - if (maxNetworkProcessItem) PhDereferenceObject(maxNetworkProcessItem); -} - -BOOLEAN EtpNetworkIconMessageCallback( - _In_ struct _PH_NF_ICON *Icon, - _In_ ULONG_PTR WParam, - _In_ ULONG_PTR LParam, - _In_opt_ PVOID Context - ) -{ - switch (LOWORD(LParam)) - { - case PH_NF_MSG_SHOWMINIINFOSECTION: - { - PPH_NF_MSG_SHOWMINIINFOSECTION_DATA data = (PVOID)WParam; - - data->SectionName = L"Network"; - } - return TRUE; - } - - return FALSE; -} +/* + * Process Hacker Extended Tools - + * notification icon extensions + * + * Copyright (C) 2011 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include "exttools.h" + +#define GPU_ICON_ID 1 +#define DISK_ICON_ID 2 +#define NETWORK_ICON_ID 3 + +VOID EtpGpuIconUpdateCallback( + _In_ struct _PH_NF_ICON *Icon, + _Out_ PVOID *NewIconOrBitmap, + _Out_ PULONG Flags, + _Out_ PPH_STRING *NewText, + _In_opt_ PVOID Context + ); + +BOOLEAN EtpGpuIconMessageCallback( + _In_ struct _PH_NF_ICON *Icon, + _In_ ULONG_PTR WParam, + _In_ ULONG_PTR LParam, + _In_opt_ PVOID Context + ); + +VOID EtpDiskIconUpdateCallback( + _In_ struct _PH_NF_ICON *Icon, + _Out_ PVOID *NewIconOrBitmap, + _Out_ PULONG Flags, + _Out_ PPH_STRING *NewText, + _In_opt_ PVOID Context + ); + +BOOLEAN EtpDiskIconMessageCallback( + _In_ struct _PH_NF_ICON *Icon, + _In_ ULONG_PTR WParam, + _In_ ULONG_PTR LParam, + _In_opt_ PVOID Context + ); + +VOID EtpNetworkIconUpdateCallback( + _In_ struct _PH_NF_ICON *Icon, + _Out_ PVOID *NewIconOrBitmap, + _Out_ PULONG Flags, + _Out_ PPH_STRING *NewText, + _In_opt_ PVOID Context + ); + +BOOLEAN EtpNetworkIconMessageCallback( + _In_ struct _PH_NF_ICON *Icon, + _In_ ULONG_PTR WParam, + _In_ ULONG_PTR LParam, + _In_opt_ PVOID Context + ); + +VOID EtRegisterNotifyIcons( + VOID + ) +{ + PH_NF_ICON_REGISTRATION_DATA data; + + data.MessageCallback = NULL; + + data.UpdateCallback = EtpGpuIconUpdateCallback; + data.MessageCallback = EtpGpuIconMessageCallback; + PhPluginRegisterIcon( + PluginInstance, + GPU_ICON_ID, + NULL, + L"GPU history", + PH_NF_ICON_SHOW_MINIINFO | (EtGpuEnabled ? 0 : PH_NF_ICON_UNAVAILABLE), + &data + ); + + data.UpdateCallback = EtpDiskIconUpdateCallback; + data.MessageCallback = EtpDiskIconMessageCallback; + PhPluginRegisterIcon( + PluginInstance, + DISK_ICON_ID, + NULL, + L"Disk history", + PH_NF_ICON_SHOW_MINIINFO | (EtEtwEnabled ? 0 : PH_NF_ICON_UNAVAILABLE), + &data + ); + + data.UpdateCallback = EtpNetworkIconUpdateCallback; + data.MessageCallback = EtpNetworkIconMessageCallback; + PhPluginRegisterIcon( + PluginInstance, + NETWORK_ICON_ID, + NULL, + L"Network history", + PH_NF_ICON_SHOW_MINIINFO | (EtEtwEnabled ? 0 : PH_NF_ICON_UNAVAILABLE), + &data + ); +} + +VOID EtpGpuIconUpdateCallback( + _In_ struct _PH_NF_ICON *Icon, + _Out_ PVOID *NewIconOrBitmap, + _Out_ PULONG Flags, + _Out_ PPH_STRING *NewText, + _In_opt_ PVOID Context + ) +{ + static PH_GRAPH_DRAW_INFO drawInfo = + { + 16, + 16, + 0, + 2, + RGB(0x00, 0x00, 0x00), + + 16, + NULL, + NULL, + 0, + 0, + 0, + 0 + }; + ULONG maxDataCount; + ULONG lineDataCount; + PFLOAT lineData1; + HBITMAP bitmap; + PVOID bits; + HDC hdc; + HBITMAP oldBitmap; + HANDLE maxGpuProcessId; + PPH_PROCESS_ITEM maxGpuProcessItem; + PH_FORMAT format[8]; + + // Icon + + Icon->Pointers->BeginBitmap(&drawInfo.Width, &drawInfo.Height, &bitmap, &bits, &hdc, &oldBitmap); + maxDataCount = drawInfo.Width / 2 + 1; + lineData1 = _alloca(maxDataCount * sizeof(FLOAT)); + + lineDataCount = min(maxDataCount, EtGpuNodeHistory.Count); + PhCopyCircularBuffer_FLOAT(&EtGpuNodeHistory, lineData1, lineDataCount); + + drawInfo.LineDataCount = lineDataCount; + drawInfo.LineData1 = lineData1; + drawInfo.LineColor1 = PhGetIntegerSetting(L"ColorCpuKernel"); + drawInfo.LineBackColor1 = PhHalveColorBrightness(drawInfo.LineColor1); + + if (bits) + PhDrawGraphDirect(hdc, bits, &drawInfo); + + SelectObject(hdc, oldBitmap); + *NewIconOrBitmap = bitmap; + *Flags = PH_NF_UPDATE_IS_BITMAP; + + // Text + + if (EtMaxGpuNodeHistory.Count != 0) + maxGpuProcessId = UlongToHandle(PhGetItemCircularBuffer_ULONG(&EtMaxGpuNodeHistory, 0)); + else + maxGpuProcessId = NULL; + + if (maxGpuProcessId) + maxGpuProcessItem = PhReferenceProcessItem(maxGpuProcessId); + else + maxGpuProcessItem = NULL; + + PhInitFormatS(&format[0], L"GPU Usage: "); + PhInitFormatF(&format[1], EtGpuNodeUsage * 100, 2); + PhInitFormatC(&format[2], '%'); + + if (maxGpuProcessItem) + { + PhInitFormatC(&format[3], '\n'); + PhInitFormatSR(&format[4], maxGpuProcessItem->ProcessName->sr); + PhInitFormatS(&format[5], L": "); + PhInitFormatF(&format[6], EtGetProcessBlock(maxGpuProcessItem)->GpuNodeUsage * 100, 2); + PhInitFormatC(&format[7], '%'); + } + + *NewText = PhFormat(format, maxGpuProcessItem ? 8 : 3, 128); + if (maxGpuProcessItem) PhDereferenceObject(maxGpuProcessItem); +} + +BOOLEAN EtpGpuIconMessageCallback( + _In_ struct _PH_NF_ICON *Icon, + _In_ ULONG_PTR WParam, + _In_ ULONG_PTR LParam, + _In_opt_ PVOID Context + ) +{ + switch (LOWORD(LParam)) + { + case PH_NF_MSG_SHOWMINIINFOSECTION: + { + PPH_NF_MSG_SHOWMINIINFOSECTION_DATA data = (PVOID)WParam; + + data->SectionName = L"GPU"; + } + return TRUE; + } + + return FALSE; +} + +VOID EtpDiskIconUpdateCallback( + _In_ struct _PH_NF_ICON *Icon, + _Out_ PVOID *NewIconOrBitmap, + _Out_ PULONG Flags, + _Out_ PPH_STRING *NewText, + _In_opt_ PVOID Context + ) +{ + static PH_GRAPH_DRAW_INFO drawInfo = + { + 16, + 16, + PH_GRAPH_USE_LINE_2, + 2, + RGB(0x00, 0x00, 0x00), + + 16, + NULL, + NULL, + 0, + 0, + 0, + 0 + }; + ULONG maxDataCount; + ULONG lineDataCount; + PFLOAT lineData1; + PFLOAT lineData2; + FLOAT max; + ULONG i; + HBITMAP bitmap; + PVOID bits; + HDC hdc; + HBITMAP oldBitmap; + HANDLE maxDiskProcessId; + PPH_PROCESS_ITEM maxDiskProcessItem; + PH_FORMAT format[6]; + + // Icon + + Icon->Pointers->BeginBitmap(&drawInfo.Width, &drawInfo.Height, &bitmap, &bits, &hdc, &oldBitmap); + maxDataCount = drawInfo.Width / 2 + 1; + lineData1 = _alloca(maxDataCount * sizeof(FLOAT)); + lineData2 = _alloca(maxDataCount * sizeof(FLOAT)); + + lineDataCount = min(maxDataCount, EtDiskReadHistory.Count); + max = 1024 * 1024; // minimum scaling of 1 MB. + + for (i = 0; i < lineDataCount; i++) + { + lineData1[i] = (FLOAT)PhGetItemCircularBuffer_ULONG(&EtDiskReadHistory, i); + lineData2[i] = (FLOAT)PhGetItemCircularBuffer_ULONG(&EtDiskWriteHistory, i); + + if (max < lineData1[i] + lineData2[i]) + max = lineData1[i] + lineData2[i]; + } + + PhDivideSinglesBySingle(lineData1, max, lineDataCount); + PhDivideSinglesBySingle(lineData2, max, lineDataCount); + + drawInfo.LineDataCount = lineDataCount; + drawInfo.LineData1 = lineData1; + drawInfo.LineData2 = lineData2; + drawInfo.LineColor1 = PhGetIntegerSetting(L"ColorIoReadOther"); + drawInfo.LineColor2 = PhGetIntegerSetting(L"ColorIoWrite"); + drawInfo.LineBackColor1 = PhHalveColorBrightness(drawInfo.LineColor1); + drawInfo.LineBackColor2 = PhHalveColorBrightness(drawInfo.LineColor2); + + if (bits) + PhDrawGraphDirect(hdc, bits, &drawInfo); + + SelectObject(hdc, oldBitmap); + *NewIconOrBitmap = bitmap; + *Flags = PH_NF_UPDATE_IS_BITMAP; + + // Text + + if (EtMaxDiskHistory.Count != 0) + maxDiskProcessId = UlongToHandle(PhGetItemCircularBuffer_ULONG(&EtMaxDiskHistory, 0)); + else + maxDiskProcessId = NULL; + + if (maxDiskProcessId) + maxDiskProcessItem = PhReferenceProcessItem(maxDiskProcessId); + else + maxDiskProcessItem = NULL; + + PhInitFormatS(&format[0], L"Disk\nR: "); + PhInitFormatSize(&format[1], EtDiskReadDelta.Delta); + PhInitFormatS(&format[2], L"\nW: "); + PhInitFormatSize(&format[3], EtDiskWriteDelta.Delta); + + if (maxDiskProcessItem) + { + PhInitFormatC(&format[4], '\n'); + PhInitFormatSR(&format[5], maxDiskProcessItem->ProcessName->sr); + } + + *NewText = PhFormat(format, maxDiskProcessItem ? 6 : 4, 128); + if (maxDiskProcessItem) PhDereferenceObject(maxDiskProcessItem); +} + +BOOLEAN EtpDiskIconMessageCallback( + _In_ struct _PH_NF_ICON *Icon, + _In_ ULONG_PTR WParam, + _In_ ULONG_PTR LParam, + _In_opt_ PVOID Context + ) +{ + switch (LOWORD(LParam)) + { + case PH_NF_MSG_SHOWMINIINFOSECTION: + { + PPH_NF_MSG_SHOWMINIINFOSECTION_DATA data = (PVOID)WParam; + + data->SectionName = L"Disk"; + } + return TRUE; + } + + return FALSE; +} + +VOID EtpNetworkIconUpdateCallback( + _In_ struct _PH_NF_ICON *Icon, + _Out_ PVOID *NewIconOrBitmap, + _Out_ PULONG Flags, + _Out_ PPH_STRING *NewText, + _In_opt_ PVOID Context + ) +{ + static PH_GRAPH_DRAW_INFO drawInfo = + { + 16, + 16, + PH_GRAPH_USE_LINE_2, + 2, + RGB(0x00, 0x00, 0x00), + + 16, + NULL, + NULL, + 0, + 0, + 0, + 0 + }; + ULONG maxDataCount; + ULONG lineDataCount; + PFLOAT lineData1; + PFLOAT lineData2; + FLOAT max; + ULONG i; + HBITMAP bitmap; + PVOID bits; + HDC hdc; + HBITMAP oldBitmap; + HANDLE maxNetworkProcessId; + PPH_PROCESS_ITEM maxNetworkProcessItem; + PH_FORMAT format[6]; + + // Icon + + Icon->Pointers->BeginBitmap(&drawInfo.Width, &drawInfo.Height, &bitmap, &bits, &hdc, &oldBitmap); + maxDataCount = drawInfo.Width / 2 + 1; + lineData1 = _alloca(maxDataCount * sizeof(FLOAT)); + lineData2 = _alloca(maxDataCount * sizeof(FLOAT)); + + lineDataCount = min(maxDataCount, EtNetworkReceiveHistory.Count); + max = 1024 * 1024; // minimum scaling of 1 MB. + + for (i = 0; i < lineDataCount; i++) + { + lineData1[i] = (FLOAT)PhGetItemCircularBuffer_ULONG(&EtNetworkReceiveHistory, i); + lineData2[i] = (FLOAT)PhGetItemCircularBuffer_ULONG(&EtNetworkSendHistory, i); + + if (max < lineData1[i] + lineData2[i]) + max = lineData1[i] + lineData2[i]; + } + + PhDivideSinglesBySingle(lineData1, max, lineDataCount); + PhDivideSinglesBySingle(lineData2, max, lineDataCount); + + drawInfo.LineDataCount = lineDataCount; + drawInfo.LineData1 = lineData1; + drawInfo.LineData2 = lineData2; + drawInfo.LineColor1 = PhGetIntegerSetting(L"ColorIoReadOther"); + drawInfo.LineColor2 = PhGetIntegerSetting(L"ColorIoWrite"); + drawInfo.LineBackColor1 = PhHalveColorBrightness(drawInfo.LineColor1); + drawInfo.LineBackColor2 = PhHalveColorBrightness(drawInfo.LineColor2); + + if (bits) + PhDrawGraphDirect(hdc, bits, &drawInfo); + + SelectObject(hdc, oldBitmap); + *NewIconOrBitmap = bitmap; + *Flags = PH_NF_UPDATE_IS_BITMAP; + + // Text + + if (EtMaxNetworkHistory.Count != 0) + maxNetworkProcessId = UlongToHandle(PhGetItemCircularBuffer_ULONG(&EtMaxNetworkHistory, 0)); + else + maxNetworkProcessId = NULL; + + if (maxNetworkProcessId) + maxNetworkProcessItem = PhReferenceProcessItem(maxNetworkProcessId); + else + maxNetworkProcessItem = NULL; + + PhInitFormatS(&format[0], L"Network\nR: "); + PhInitFormatSize(&format[1], EtNetworkReceiveDelta.Delta); + PhInitFormatS(&format[2], L"\nS: "); + PhInitFormatSize(&format[3], EtNetworkSendDelta.Delta); + + if (maxNetworkProcessItem) + { + PhInitFormatC(&format[4], '\n'); + PhInitFormatSR(&format[5], maxNetworkProcessItem->ProcessName->sr); + } + + *NewText = PhFormat(format, maxNetworkProcessItem ? 6 : 4, 128); + if (maxNetworkProcessItem) PhDereferenceObject(maxNetworkProcessItem); +} + +BOOLEAN EtpNetworkIconMessageCallback( + _In_ struct _PH_NF_ICON *Icon, + _In_ ULONG_PTR WParam, + _In_ ULONG_PTR LParam, + _In_opt_ PVOID Context + ) +{ + switch (LOWORD(LParam)) + { + case PH_NF_MSG_SHOWMINIINFOSECTION: + { + PPH_NF_MSG_SHOWMINIINFOSECTION_DATA data = (PVOID)WParam; + + data->SectionName = L"Network"; + } + return TRUE; + } + + return FALSE; +} diff --git a/plugins/ExtendedTools/main.c b/plugins/ExtendedTools/main.c index 4bf9c82f8661..108a747d714e 100644 --- a/plugins/ExtendedTools/main.c +++ b/plugins/ExtendedTools/main.c @@ -1,617 +1,617 @@ -/* - * Process Hacker Extended Tools - - * main program - * - * Copyright (C) 2010-2015 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include "exttools.h" - -PPH_PLUGIN PluginInstance; -LIST_ENTRY EtProcessBlockListHead; -LIST_ENTRY EtNetworkBlockListHead; -HWND ProcessTreeNewHandle; -HWND NetworkTreeNewHandle; -PH_CALLBACK_REGISTRATION PluginLoadCallbackRegistration; -PH_CALLBACK_REGISTRATION PluginUnloadCallbackRegistration; -PH_CALLBACK_REGISTRATION PluginShowOptionsCallbackRegistration; -PH_CALLBACK_REGISTRATION PluginMenuItemCallbackRegistration; -PH_CALLBACK_REGISTRATION PluginTreeNewMessageCallbackRegistration; -PH_CALLBACK_REGISTRATION MainWindowShowingCallbackRegistration; -PH_CALLBACK_REGISTRATION ProcessPropertiesInitializingCallbackRegistration; -PH_CALLBACK_REGISTRATION HandlePropertiesInitializingCallbackRegistration; -PH_CALLBACK_REGISTRATION ProcessMenuInitializingCallbackRegistration; -PH_CALLBACK_REGISTRATION ThreadMenuInitializingCallbackRegistration; -PH_CALLBACK_REGISTRATION ModuleMenuInitializingCallbackRegistration; -PH_CALLBACK_REGISTRATION ProcessTreeNewInitializingCallbackRegistration; -PH_CALLBACK_REGISTRATION NetworkTreeNewInitializingCallbackRegistration; -PH_CALLBACK_REGISTRATION SystemInformationInitializingCallbackRegistration; -PH_CALLBACK_REGISTRATION MiniInformationInitializingCallbackRegistration; -PH_CALLBACK_REGISTRATION ProcessesUpdatedCallbackRegistration; -PH_CALLBACK_REGISTRATION NetworkItemsUpdatedCallbackRegistration; - -static HANDLE ModuleProcessId; - -VOID NTAPI LoadCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - EtEtwStatisticsInitialization(); - EtGpuMonitorInitialization(); - - EtRegisterNotifyIcons(); -} - -VOID NTAPI UnloadCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - EtSaveSettingsDiskTreeList(); - EtEtwStatisticsUninitialization(); -} - -VOID NTAPI ShowOptionsCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - EtShowOptionsDialog((HWND)Parameter); -} - -VOID NTAPI MenuItemCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - PPH_PLUGIN_MENU_ITEM menuItem = Parameter; - - switch (menuItem->Id) - { - case ID_PROCESS_UNLOADEDMODULES: - { - EtShowUnloadedDllsDialog(PhMainWndHandle, menuItem->Context); - } - break; - case ID_PROCESS_WSWATCH: - { - EtShowWsWatchDialog(PhMainWndHandle, menuItem->Context); - } - break; - case ID_THREAD_CANCELIO: - { - EtUiCancelIoThread(menuItem->OwnerWindow, menuItem->Context); - } - break; - case ID_MODULE_SERVICES: - { - EtShowModuleServicesDialog( - menuItem->OwnerWindow, - ModuleProcessId, - ((PPH_MODULE_ITEM)menuItem->Context)->Name->Buffer - ); - } - break; - } -} - -VOID NTAPI TreeNewMessageCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - PPH_PLUGIN_TREENEW_MESSAGE message = Parameter; - - if (message->TreeNewHandle == ProcessTreeNewHandle) - EtProcessTreeNewMessage(Parameter); - else if (message->TreeNewHandle == NetworkTreeNewHandle) - EtNetworkTreeNewMessage(Parameter); -} - -VOID NTAPI MainWindowShowingCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - EtInitializeDiskTab(); -} - -VOID NTAPI ProcessPropertiesInitializingCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - EtProcessGpuPropertiesInitializing(Parameter); - EtProcessEtwPropertiesInitializing(Parameter); -} - -VOID NTAPI HandlePropertiesInitializingCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - EtHandlePropertiesInitializing(Parameter); -} - -VOID NTAPI ProcessMenuInitializingCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - PPH_PLUGIN_MENU_INFORMATION menuInfo = Parameter; - PPH_PROCESS_ITEM processItem; - ULONG flags; - PPH_EMENU_ITEM miscMenu; - - if (menuInfo->u.Process.NumberOfProcesses == 1) - processItem = menuInfo->u.Process.Processes[0]; - else - processItem = NULL; - - flags = 0; - - if (!processItem) - flags = PH_EMENU_DISABLED; - - miscMenu = PhFindEMenuItem(menuInfo->Menu, 0, L"Miscellaneous", 0); - - if (miscMenu) - { - PhInsertEMenuItem(miscMenu, PhPluginCreateEMenuItem(PluginInstance, flags, ID_PROCESS_UNLOADEDMODULES, L"Unloaded modules", processItem), -1); - PhInsertEMenuItem(miscMenu, PhPluginCreateEMenuItem(PluginInstance, flags, ID_PROCESS_WSWATCH, L"WS watch", processItem), -1); - } -} - -VOID NTAPI ThreadMenuInitializingCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - PPH_PLUGIN_MENU_INFORMATION menuInfo = Parameter; - PPH_THREAD_ITEM threadItem; - ULONG insertIndex; - PPH_EMENU_ITEM menuItem; - - if (menuInfo->u.Thread.NumberOfThreads == 1) - threadItem = menuInfo->u.Thread.Threads[0]; - else - threadItem = NULL; - - if (menuItem = PhFindEMenuItem(menuInfo->Menu, 0, L"Resume", 0)) - insertIndex = PhIndexOfEMenuItem(menuInfo->Menu, menuItem) + 1; - else - insertIndex = 0; - - PhInsertEMenuItem(menuInfo->Menu, menuItem = PhPluginCreateEMenuItem(PluginInstance, 0, ID_THREAD_CANCELIO, - L"Cancel I/O", threadItem), insertIndex); - - if (!threadItem) menuItem->Flags |= PH_EMENU_DISABLED; -} - -VOID NTAPI ModuleMenuInitializingCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - PPH_PLUGIN_MENU_INFORMATION menuInfo = Parameter; - PPH_PROCESS_ITEM processItem; - BOOLEAN addMenuItem; - PPH_MODULE_ITEM moduleItem; - ULONG insertIndex; - PPH_EMENU_ITEM menuItem; - - addMenuItem = FALSE; - - if (processItem = PhReferenceProcessItem(menuInfo->u.Module.ProcessId)) - { - if (processItem->ServiceList && processItem->ServiceList->Count != 0) - addMenuItem = TRUE; - - PhDereferenceObject(processItem); - } - - if (!addMenuItem) - return; - - if (menuInfo->u.Module.NumberOfModules == 1) - moduleItem = menuInfo->u.Module.Modules[0]; - else - moduleItem = NULL; - - if (menuItem = PhFindEMenuItem(menuInfo->Menu, PH_EMENU_FIND_STARTSWITH, L"Inspect", 0)) - insertIndex = PhIndexOfEMenuItem(menuInfo->Menu, menuItem) + 1; - else - insertIndex = 0; - - ModuleProcessId = menuInfo->u.Module.ProcessId; - - PhInsertEMenuItem(menuInfo->Menu, menuItem = PhPluginCreateEMenuItem(PluginInstance, 0, ID_MODULE_SERVICES, - L"Services", moduleItem), insertIndex); - - if (!moduleItem) menuItem->Flags |= PH_EMENU_DISABLED; -} - -VOID NTAPI ProcessTreeNewInitializingCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - PPH_PLUGIN_TREENEW_INFORMATION treeNewInfo = Parameter; - - ProcessTreeNewHandle = treeNewInfo->TreeNewHandle; - EtProcessTreeNewInitializing(Parameter); -} - -VOID NTAPI NetworkTreeNewInitializingCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - PPH_PLUGIN_TREENEW_INFORMATION treeNewInfo = Parameter; - - NetworkTreeNewHandle = treeNewInfo->TreeNewHandle; - EtNetworkTreeNewInitializing(Parameter); -} - -VOID NTAPI SystemInformationInitializingCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - if (EtGpuEnabled) - EtGpuSystemInformationInitializing(Parameter); - if (EtEtwEnabled && !!PhGetIntegerSetting(SETTING_NAME_ENABLE_SYSINFO_GRAPHS)) - EtEtwSystemInformationInitializing(Parameter); -} - -VOID NTAPI MiniInformationInitializingCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - if (EtGpuEnabled) - EtGpuMiniInformationInitializing(Parameter); - if (EtEtwEnabled) - EtEtwMiniInformationInitializing(Parameter); -} - -VOID NTAPI ProcessesUpdatedCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - PLIST_ENTRY listEntry; - - // Note: no lock is needed because we only ever modify the list on this same thread. - - listEntry = EtProcessBlockListHead.Flink; - - while (listEntry != &EtProcessBlockListHead) - { - PET_PROCESS_BLOCK block; - - block = CONTAINING_RECORD(listEntry, ET_PROCESS_BLOCK, ListEntry); - - PhUpdateDelta(&block->HardFaultsDelta, block->ProcessItem->HardFaultCount); - - // Invalidate all text. - - PhAcquireQueuedLockExclusive(&block->TextCacheLock); - memset(block->TextCacheValid, 0, sizeof(block->TextCacheValid)); - PhReleaseQueuedLockExclusive(&block->TextCacheLock); - - listEntry = listEntry->Flink; - } -} - -VOID NTAPI NetworkItemsUpdatedCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - PLIST_ENTRY listEntry; - - // Note: no lock is needed because we only ever modify the list on this same thread. - - listEntry = EtNetworkBlockListHead.Flink; - - while (listEntry != &EtNetworkBlockListHead) - { - PET_NETWORK_BLOCK block; - - block = CONTAINING_RECORD(listEntry, ET_NETWORK_BLOCK, ListEntry); - - // Invalidate all text. - - PhAcquireQueuedLockExclusive(&block->TextCacheLock); - memset(block->TextCacheValid, 0, sizeof(block->TextCacheValid)); - PhReleaseQueuedLockExclusive(&block->TextCacheLock); - - listEntry = listEntry->Flink; - } -} - -PET_PROCESS_BLOCK EtGetProcessBlock( - _In_ PPH_PROCESS_ITEM ProcessItem - ) -{ - return PhPluginGetObjectExtension(PluginInstance, ProcessItem, EmProcessItemType); -} - -PET_NETWORK_BLOCK EtGetNetworkBlock( - _In_ PPH_NETWORK_ITEM NetworkItem - ) -{ - return PhPluginGetObjectExtension(PluginInstance, NetworkItem, EmNetworkItemType); -} - -VOID EtInitializeProcessBlock( - _Out_ PET_PROCESS_BLOCK Block, - _In_ PPH_PROCESS_ITEM ProcessItem - ) -{ - memset(Block, 0, sizeof(ET_PROCESS_BLOCK)); - Block->ProcessItem = ProcessItem; - PhInitializeQueuedLock(&Block->TextCacheLock); - InsertTailList(&EtProcessBlockListHead, &Block->ListEntry); -} - -VOID EtDeleteProcessBlock( - _In_ PET_PROCESS_BLOCK Block - ) -{ - ULONG i; - - EtProcIconNotifyProcessDelete(Block); - - for (i = 1; i <= ETPRTNC_MAXIMUM; i++) - { - PhClearReference(&Block->TextCache[i]); - } - - RemoveEntryList(&Block->ListEntry); -} - -VOID EtInitializeNetworkBlock( - _Out_ PET_NETWORK_BLOCK Block, - _In_ PPH_NETWORK_ITEM NetworkItem - ) -{ - memset(Block, 0, sizeof(ET_NETWORK_BLOCK)); - Block->NetworkItem = NetworkItem; - PhInitializeQueuedLock(&Block->TextCacheLock); - InsertTailList(&EtNetworkBlockListHead, &Block->ListEntry); -} - -VOID EtDeleteNetworkBlock( - _In_ PET_NETWORK_BLOCK Block - ) -{ - ULONG i; - - for (i = 1; i <= ETNETNC_MAXIMUM; i++) - { - PhClearReference(&Block->TextCache[i]); - } - - RemoveEntryList(&Block->ListEntry); -} - -VOID NTAPI ProcessItemCreateCallback( - _In_ PVOID Object, - _In_ PH_EM_OBJECT_TYPE ObjectType, - _In_ PVOID Extension - ) -{ - EtInitializeProcessBlock(Extension, Object); -} - -VOID NTAPI ProcessItemDeleteCallback( - _In_ PVOID Object, - _In_ PH_EM_OBJECT_TYPE ObjectType, - _In_ PVOID Extension - ) -{ - EtDeleteProcessBlock(Extension); -} - -VOID NTAPI NetworkItemCreateCallback( - _In_ PVOID Object, - _In_ PH_EM_OBJECT_TYPE ObjectType, - _In_ PVOID Extension - ) -{ - EtInitializeNetworkBlock(Extension, Object); -} - -VOID NTAPI NetworkItemDeleteCallback( - _In_ PVOID Object, - _In_ PH_EM_OBJECT_TYPE ObjectType, - _In_ PVOID Extension - ) -{ - EtDeleteNetworkBlock(Extension); -} - -LOGICAL DllMain( - _In_ HINSTANCE Instance, - _In_ ULONG Reason, - _Reserved_ PVOID Reserved - ) -{ - switch (Reason) - { - case DLL_PROCESS_ATTACH: - { - PPH_PLUGIN_INFORMATION info; - - PluginInstance = PhRegisterPlugin(PLUGIN_NAME, Instance, &info); - - if (!PluginInstance) - return FALSE; - - info->DisplayName = L"Extended Tools"; - info->Author = L"wj32"; - info->Description = L"Extended functionality for Windows 7 and above, including ETW monitoring, GPU monitoring and a Disk tab."; - info->Url = L"https://wj32.org/processhacker/forums/viewtopic.php?t=1114"; - info->HasOptions = TRUE; - - PhRegisterCallback( - PhGetPluginCallback(PluginInstance, PluginCallbackLoad), - LoadCallback, - NULL, - &PluginLoadCallbackRegistration - ); - PhRegisterCallback( - PhGetPluginCallback(PluginInstance, PluginCallbackUnload), - UnloadCallback, - NULL, - &PluginUnloadCallbackRegistration - ); - PhRegisterCallback( - PhGetPluginCallback(PluginInstance, PluginCallbackShowOptions), - ShowOptionsCallback, - NULL, - &PluginShowOptionsCallbackRegistration - ); - PhRegisterCallback( - PhGetPluginCallback(PluginInstance, PluginCallbackMenuItem), - MenuItemCallback, - NULL, - &PluginMenuItemCallbackRegistration - ); - PhRegisterCallback( - PhGetPluginCallback(PluginInstance, PluginCallbackTreeNewMessage), - TreeNewMessageCallback, - NULL, - &PluginTreeNewMessageCallbackRegistration - ); - - PhRegisterCallback( - PhGetGeneralCallback(GeneralCallbackMainWindowShowing), - MainWindowShowingCallback, - NULL, - &MainWindowShowingCallbackRegistration - ); - PhRegisterCallback( - PhGetGeneralCallback(GeneralCallbackProcessPropertiesInitializing), - ProcessPropertiesInitializingCallback, - NULL, - &ProcessPropertiesInitializingCallbackRegistration - ); - PhRegisterCallback( - PhGetGeneralCallback(GeneralCallbackHandlePropertiesInitializing), - HandlePropertiesInitializingCallback, - NULL, - &HandlePropertiesInitializingCallbackRegistration - ); - PhRegisterCallback( - PhGetGeneralCallback(GeneralCallbackProcessMenuInitializing), - ProcessMenuInitializingCallback, - NULL, - &ProcessMenuInitializingCallbackRegistration - ); - PhRegisterCallback( - PhGetGeneralCallback(GeneralCallbackThreadMenuInitializing), - ThreadMenuInitializingCallback, - NULL, - &ThreadMenuInitializingCallbackRegistration - ); - PhRegisterCallback( - PhGetGeneralCallback(GeneralCallbackModuleMenuInitializing), - ModuleMenuInitializingCallback, - NULL, - &ModuleMenuInitializingCallbackRegistration - ); - PhRegisterCallback( - PhGetGeneralCallback(GeneralCallbackProcessTreeNewInitializing), - ProcessTreeNewInitializingCallback, - NULL, - &ProcessTreeNewInitializingCallbackRegistration - ); - PhRegisterCallback( - PhGetGeneralCallback(GeneralCallbackNetworkTreeNewInitializing), - NetworkTreeNewInitializingCallback, - NULL, - &NetworkTreeNewInitializingCallbackRegistration - ); - PhRegisterCallback( - PhGetGeneralCallback(GeneralCallbackSystemInformationInitializing), - SystemInformationInitializingCallback, - NULL, - &SystemInformationInitializingCallbackRegistration - ); - PhRegisterCallback( - PhGetGeneralCallback(GeneralCallbackMiniInformationInitializing), - MiniInformationInitializingCallback, - NULL, - &MiniInformationInitializingCallbackRegistration - ); - - PhRegisterCallback( - &PhProcessesUpdatedEvent, - ProcessesUpdatedCallback, - NULL, - &ProcessesUpdatedCallbackRegistration - ); - PhRegisterCallback( - &PhNetworkItemsUpdatedEvent, - NetworkItemsUpdatedCallback, - NULL, - &NetworkItemsUpdatedCallbackRegistration - ); - - InitializeListHead(&EtProcessBlockListHead); - InitializeListHead(&EtNetworkBlockListHead); - - PhPluginSetObjectExtension( - PluginInstance, - EmProcessItemType, - sizeof(ET_PROCESS_BLOCK), - ProcessItemCreateCallback, - ProcessItemDeleteCallback - ); - PhPluginSetObjectExtension( - PluginInstance, - EmNetworkItemType, - sizeof(ET_NETWORK_BLOCK), - NetworkItemCreateCallback, - NetworkItemDeleteCallback - ); - - { - static PH_SETTING_CREATE settings[] = - { - { StringSettingType, SETTING_NAME_DISK_TREE_LIST_COLUMNS, L"" }, - { IntegerPairSettingType, SETTING_NAME_DISK_TREE_LIST_SORT, L"4,2" }, // 4, DescendingSortOrder - { IntegerSettingType, SETTING_NAME_ENABLE_ETW_MONITOR, L"1" }, - { IntegerSettingType, SETTING_NAME_ENABLE_GPU_MONITOR, L"1" }, - { IntegerSettingType, SETTING_NAME_ENABLE_SYSINFO_GRAPHS, L"1" }, - { StringSettingType, SETTING_NAME_GPU_NODE_BITMAP, L"01000000" }, - { IntegerSettingType, SETTING_NAME_GPU_LAST_NODE_COUNT, L"0" } - }; - - PhAddSettings(settings, sizeof(settings) / sizeof(PH_SETTING_CREATE)); - } - } - break; - } - - return TRUE; +/* + * Process Hacker Extended Tools - + * main program + * + * Copyright (C) 2010-2015 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include "exttools.h" + +PPH_PLUGIN PluginInstance; +LIST_ENTRY EtProcessBlockListHead; +LIST_ENTRY EtNetworkBlockListHead; +HWND ProcessTreeNewHandle; +HWND NetworkTreeNewHandle; +PH_CALLBACK_REGISTRATION PluginLoadCallbackRegistration; +PH_CALLBACK_REGISTRATION PluginUnloadCallbackRegistration; +PH_CALLBACK_REGISTRATION PluginShowOptionsCallbackRegistration; +PH_CALLBACK_REGISTRATION PluginMenuItemCallbackRegistration; +PH_CALLBACK_REGISTRATION PluginTreeNewMessageCallbackRegistration; +PH_CALLBACK_REGISTRATION MainWindowShowingCallbackRegistration; +PH_CALLBACK_REGISTRATION ProcessPropertiesInitializingCallbackRegistration; +PH_CALLBACK_REGISTRATION HandlePropertiesInitializingCallbackRegistration; +PH_CALLBACK_REGISTRATION ProcessMenuInitializingCallbackRegistration; +PH_CALLBACK_REGISTRATION ThreadMenuInitializingCallbackRegistration; +PH_CALLBACK_REGISTRATION ModuleMenuInitializingCallbackRegistration; +PH_CALLBACK_REGISTRATION ProcessTreeNewInitializingCallbackRegistration; +PH_CALLBACK_REGISTRATION NetworkTreeNewInitializingCallbackRegistration; +PH_CALLBACK_REGISTRATION SystemInformationInitializingCallbackRegistration; +PH_CALLBACK_REGISTRATION MiniInformationInitializingCallbackRegistration; +PH_CALLBACK_REGISTRATION ProcessesUpdatedCallbackRegistration; +PH_CALLBACK_REGISTRATION NetworkItemsUpdatedCallbackRegistration; + +static HANDLE ModuleProcessId; + +VOID NTAPI LoadCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + EtEtwStatisticsInitialization(); + EtGpuMonitorInitialization(); + + EtRegisterNotifyIcons(); +} + +VOID NTAPI UnloadCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + EtSaveSettingsDiskTreeList(); + EtEtwStatisticsUninitialization(); +} + +VOID NTAPI ShowOptionsCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + EtShowOptionsDialog((HWND)Parameter); +} + +VOID NTAPI MenuItemCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + PPH_PLUGIN_MENU_ITEM menuItem = Parameter; + + switch (menuItem->Id) + { + case ID_PROCESS_UNLOADEDMODULES: + { + EtShowUnloadedDllsDialog(PhMainWndHandle, menuItem->Context); + } + break; + case ID_PROCESS_WSWATCH: + { + EtShowWsWatchDialog(PhMainWndHandle, menuItem->Context); + } + break; + case ID_THREAD_CANCELIO: + { + EtUiCancelIoThread(menuItem->OwnerWindow, menuItem->Context); + } + break; + case ID_MODULE_SERVICES: + { + EtShowModuleServicesDialog( + menuItem->OwnerWindow, + ModuleProcessId, + ((PPH_MODULE_ITEM)menuItem->Context)->Name->Buffer + ); + } + break; + } +} + +VOID NTAPI TreeNewMessageCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + PPH_PLUGIN_TREENEW_MESSAGE message = Parameter; + + if (message->TreeNewHandle == ProcessTreeNewHandle) + EtProcessTreeNewMessage(Parameter); + else if (message->TreeNewHandle == NetworkTreeNewHandle) + EtNetworkTreeNewMessage(Parameter); +} + +VOID NTAPI MainWindowShowingCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + EtInitializeDiskTab(); +} + +VOID NTAPI ProcessPropertiesInitializingCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + EtProcessGpuPropertiesInitializing(Parameter); + EtProcessEtwPropertiesInitializing(Parameter); +} + +VOID NTAPI HandlePropertiesInitializingCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + EtHandlePropertiesInitializing(Parameter); +} + +VOID NTAPI ProcessMenuInitializingCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + PPH_PLUGIN_MENU_INFORMATION menuInfo = Parameter; + PPH_PROCESS_ITEM processItem; + ULONG flags; + PPH_EMENU_ITEM miscMenu; + + if (menuInfo->u.Process.NumberOfProcesses == 1) + processItem = menuInfo->u.Process.Processes[0]; + else + processItem = NULL; + + flags = 0; + + if (!processItem) + flags = PH_EMENU_DISABLED; + + miscMenu = PhFindEMenuItem(menuInfo->Menu, 0, L"Miscellaneous", 0); + + if (miscMenu) + { + PhInsertEMenuItem(miscMenu, PhPluginCreateEMenuItem(PluginInstance, flags, ID_PROCESS_UNLOADEDMODULES, L"Unloaded modules", processItem), -1); + PhInsertEMenuItem(miscMenu, PhPluginCreateEMenuItem(PluginInstance, flags, ID_PROCESS_WSWATCH, L"WS watch", processItem), -1); + } +} + +VOID NTAPI ThreadMenuInitializingCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + PPH_PLUGIN_MENU_INFORMATION menuInfo = Parameter; + PPH_THREAD_ITEM threadItem; + ULONG insertIndex; + PPH_EMENU_ITEM menuItem; + + if (menuInfo->u.Thread.NumberOfThreads == 1) + threadItem = menuInfo->u.Thread.Threads[0]; + else + threadItem = NULL; + + if (menuItem = PhFindEMenuItem(menuInfo->Menu, 0, L"Resume", 0)) + insertIndex = PhIndexOfEMenuItem(menuInfo->Menu, menuItem) + 1; + else + insertIndex = 0; + + PhInsertEMenuItem(menuInfo->Menu, menuItem = PhPluginCreateEMenuItem(PluginInstance, 0, ID_THREAD_CANCELIO, + L"Cancel I/O", threadItem), insertIndex); + + if (!threadItem) menuItem->Flags |= PH_EMENU_DISABLED; +} + +VOID NTAPI ModuleMenuInitializingCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + PPH_PLUGIN_MENU_INFORMATION menuInfo = Parameter; + PPH_PROCESS_ITEM processItem; + BOOLEAN addMenuItem; + PPH_MODULE_ITEM moduleItem; + ULONG insertIndex; + PPH_EMENU_ITEM menuItem; + + addMenuItem = FALSE; + + if (processItem = PhReferenceProcessItem(menuInfo->u.Module.ProcessId)) + { + if (processItem->ServiceList && processItem->ServiceList->Count != 0) + addMenuItem = TRUE; + + PhDereferenceObject(processItem); + } + + if (!addMenuItem) + return; + + if (menuInfo->u.Module.NumberOfModules == 1) + moduleItem = menuInfo->u.Module.Modules[0]; + else + moduleItem = NULL; + + if (menuItem = PhFindEMenuItem(menuInfo->Menu, PH_EMENU_FIND_STARTSWITH, L"Inspect", 0)) + insertIndex = PhIndexOfEMenuItem(menuInfo->Menu, menuItem) + 1; + else + insertIndex = 0; + + ModuleProcessId = menuInfo->u.Module.ProcessId; + + PhInsertEMenuItem(menuInfo->Menu, menuItem = PhPluginCreateEMenuItem(PluginInstance, 0, ID_MODULE_SERVICES, + L"Services", moduleItem), insertIndex); + + if (!moduleItem) menuItem->Flags |= PH_EMENU_DISABLED; +} + +VOID NTAPI ProcessTreeNewInitializingCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + PPH_PLUGIN_TREENEW_INFORMATION treeNewInfo = Parameter; + + ProcessTreeNewHandle = treeNewInfo->TreeNewHandle; + EtProcessTreeNewInitializing(Parameter); +} + +VOID NTAPI NetworkTreeNewInitializingCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + PPH_PLUGIN_TREENEW_INFORMATION treeNewInfo = Parameter; + + NetworkTreeNewHandle = treeNewInfo->TreeNewHandle; + EtNetworkTreeNewInitializing(Parameter); +} + +VOID NTAPI SystemInformationInitializingCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + if (EtGpuEnabled) + EtGpuSystemInformationInitializing(Parameter); + if (EtEtwEnabled && !!PhGetIntegerSetting(SETTING_NAME_ENABLE_SYSINFO_GRAPHS)) + EtEtwSystemInformationInitializing(Parameter); +} + +VOID NTAPI MiniInformationInitializingCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + if (EtGpuEnabled) + EtGpuMiniInformationInitializing(Parameter); + if (EtEtwEnabled) + EtEtwMiniInformationInitializing(Parameter); +} + +VOID NTAPI ProcessesUpdatedCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + PLIST_ENTRY listEntry; + + // Note: no lock is needed because we only ever modify the list on this same thread. + + listEntry = EtProcessBlockListHead.Flink; + + while (listEntry != &EtProcessBlockListHead) + { + PET_PROCESS_BLOCK block; + + block = CONTAINING_RECORD(listEntry, ET_PROCESS_BLOCK, ListEntry); + + PhUpdateDelta(&block->HardFaultsDelta, block->ProcessItem->HardFaultCount); + + // Invalidate all text. + + PhAcquireQueuedLockExclusive(&block->TextCacheLock); + memset(block->TextCacheValid, 0, sizeof(block->TextCacheValid)); + PhReleaseQueuedLockExclusive(&block->TextCacheLock); + + listEntry = listEntry->Flink; + } +} + +VOID NTAPI NetworkItemsUpdatedCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + PLIST_ENTRY listEntry; + + // Note: no lock is needed because we only ever modify the list on this same thread. + + listEntry = EtNetworkBlockListHead.Flink; + + while (listEntry != &EtNetworkBlockListHead) + { + PET_NETWORK_BLOCK block; + + block = CONTAINING_RECORD(listEntry, ET_NETWORK_BLOCK, ListEntry); + + // Invalidate all text. + + PhAcquireQueuedLockExclusive(&block->TextCacheLock); + memset(block->TextCacheValid, 0, sizeof(block->TextCacheValid)); + PhReleaseQueuedLockExclusive(&block->TextCacheLock); + + listEntry = listEntry->Flink; + } +} + +PET_PROCESS_BLOCK EtGetProcessBlock( + _In_ PPH_PROCESS_ITEM ProcessItem + ) +{ + return PhPluginGetObjectExtension(PluginInstance, ProcessItem, EmProcessItemType); +} + +PET_NETWORK_BLOCK EtGetNetworkBlock( + _In_ PPH_NETWORK_ITEM NetworkItem + ) +{ + return PhPluginGetObjectExtension(PluginInstance, NetworkItem, EmNetworkItemType); +} + +VOID EtInitializeProcessBlock( + _Out_ PET_PROCESS_BLOCK Block, + _In_ PPH_PROCESS_ITEM ProcessItem + ) +{ + memset(Block, 0, sizeof(ET_PROCESS_BLOCK)); + Block->ProcessItem = ProcessItem; + PhInitializeQueuedLock(&Block->TextCacheLock); + InsertTailList(&EtProcessBlockListHead, &Block->ListEntry); +} + +VOID EtDeleteProcessBlock( + _In_ PET_PROCESS_BLOCK Block + ) +{ + ULONG i; + + EtProcIconNotifyProcessDelete(Block); + + for (i = 1; i <= ETPRTNC_MAXIMUM; i++) + { + PhClearReference(&Block->TextCache[i]); + } + + RemoveEntryList(&Block->ListEntry); +} + +VOID EtInitializeNetworkBlock( + _Out_ PET_NETWORK_BLOCK Block, + _In_ PPH_NETWORK_ITEM NetworkItem + ) +{ + memset(Block, 0, sizeof(ET_NETWORK_BLOCK)); + Block->NetworkItem = NetworkItem; + PhInitializeQueuedLock(&Block->TextCacheLock); + InsertTailList(&EtNetworkBlockListHead, &Block->ListEntry); +} + +VOID EtDeleteNetworkBlock( + _In_ PET_NETWORK_BLOCK Block + ) +{ + ULONG i; + + for (i = 1; i <= ETNETNC_MAXIMUM; i++) + { + PhClearReference(&Block->TextCache[i]); + } + + RemoveEntryList(&Block->ListEntry); +} + +VOID NTAPI ProcessItemCreateCallback( + _In_ PVOID Object, + _In_ PH_EM_OBJECT_TYPE ObjectType, + _In_ PVOID Extension + ) +{ + EtInitializeProcessBlock(Extension, Object); +} + +VOID NTAPI ProcessItemDeleteCallback( + _In_ PVOID Object, + _In_ PH_EM_OBJECT_TYPE ObjectType, + _In_ PVOID Extension + ) +{ + EtDeleteProcessBlock(Extension); +} + +VOID NTAPI NetworkItemCreateCallback( + _In_ PVOID Object, + _In_ PH_EM_OBJECT_TYPE ObjectType, + _In_ PVOID Extension + ) +{ + EtInitializeNetworkBlock(Extension, Object); +} + +VOID NTAPI NetworkItemDeleteCallback( + _In_ PVOID Object, + _In_ PH_EM_OBJECT_TYPE ObjectType, + _In_ PVOID Extension + ) +{ + EtDeleteNetworkBlock(Extension); +} + +LOGICAL DllMain( + _In_ HINSTANCE Instance, + _In_ ULONG Reason, + _Reserved_ PVOID Reserved + ) +{ + switch (Reason) + { + case DLL_PROCESS_ATTACH: + { + PPH_PLUGIN_INFORMATION info; + + PluginInstance = PhRegisterPlugin(PLUGIN_NAME, Instance, &info); + + if (!PluginInstance) + return FALSE; + + info->DisplayName = L"Extended Tools"; + info->Author = L"wj32"; + info->Description = L"Extended functionality for Windows 7 and above, including ETW monitoring, GPU monitoring and a Disk tab."; + info->Url = L"https://wj32.org/processhacker/forums/viewtopic.php?t=1114"; + info->HasOptions = TRUE; + + PhRegisterCallback( + PhGetPluginCallback(PluginInstance, PluginCallbackLoad), + LoadCallback, + NULL, + &PluginLoadCallbackRegistration + ); + PhRegisterCallback( + PhGetPluginCallback(PluginInstance, PluginCallbackUnload), + UnloadCallback, + NULL, + &PluginUnloadCallbackRegistration + ); + PhRegisterCallback( + PhGetPluginCallback(PluginInstance, PluginCallbackShowOptions), + ShowOptionsCallback, + NULL, + &PluginShowOptionsCallbackRegistration + ); + PhRegisterCallback( + PhGetPluginCallback(PluginInstance, PluginCallbackMenuItem), + MenuItemCallback, + NULL, + &PluginMenuItemCallbackRegistration + ); + PhRegisterCallback( + PhGetPluginCallback(PluginInstance, PluginCallbackTreeNewMessage), + TreeNewMessageCallback, + NULL, + &PluginTreeNewMessageCallbackRegistration + ); + + PhRegisterCallback( + PhGetGeneralCallback(GeneralCallbackMainWindowShowing), + MainWindowShowingCallback, + NULL, + &MainWindowShowingCallbackRegistration + ); + PhRegisterCallback( + PhGetGeneralCallback(GeneralCallbackProcessPropertiesInitializing), + ProcessPropertiesInitializingCallback, + NULL, + &ProcessPropertiesInitializingCallbackRegistration + ); + PhRegisterCallback( + PhGetGeneralCallback(GeneralCallbackHandlePropertiesInitializing), + HandlePropertiesInitializingCallback, + NULL, + &HandlePropertiesInitializingCallbackRegistration + ); + PhRegisterCallback( + PhGetGeneralCallback(GeneralCallbackProcessMenuInitializing), + ProcessMenuInitializingCallback, + NULL, + &ProcessMenuInitializingCallbackRegistration + ); + PhRegisterCallback( + PhGetGeneralCallback(GeneralCallbackThreadMenuInitializing), + ThreadMenuInitializingCallback, + NULL, + &ThreadMenuInitializingCallbackRegistration + ); + PhRegisterCallback( + PhGetGeneralCallback(GeneralCallbackModuleMenuInitializing), + ModuleMenuInitializingCallback, + NULL, + &ModuleMenuInitializingCallbackRegistration + ); + PhRegisterCallback( + PhGetGeneralCallback(GeneralCallbackProcessTreeNewInitializing), + ProcessTreeNewInitializingCallback, + NULL, + &ProcessTreeNewInitializingCallbackRegistration + ); + PhRegisterCallback( + PhGetGeneralCallback(GeneralCallbackNetworkTreeNewInitializing), + NetworkTreeNewInitializingCallback, + NULL, + &NetworkTreeNewInitializingCallbackRegistration + ); + PhRegisterCallback( + PhGetGeneralCallback(GeneralCallbackSystemInformationInitializing), + SystemInformationInitializingCallback, + NULL, + &SystemInformationInitializingCallbackRegistration + ); + PhRegisterCallback( + PhGetGeneralCallback(GeneralCallbackMiniInformationInitializing), + MiniInformationInitializingCallback, + NULL, + &MiniInformationInitializingCallbackRegistration + ); + + PhRegisterCallback( + &PhProcessesUpdatedEvent, + ProcessesUpdatedCallback, + NULL, + &ProcessesUpdatedCallbackRegistration + ); + PhRegisterCallback( + &PhNetworkItemsUpdatedEvent, + NetworkItemsUpdatedCallback, + NULL, + &NetworkItemsUpdatedCallbackRegistration + ); + + InitializeListHead(&EtProcessBlockListHead); + InitializeListHead(&EtNetworkBlockListHead); + + PhPluginSetObjectExtension( + PluginInstance, + EmProcessItemType, + sizeof(ET_PROCESS_BLOCK), + ProcessItemCreateCallback, + ProcessItemDeleteCallback + ); + PhPluginSetObjectExtension( + PluginInstance, + EmNetworkItemType, + sizeof(ET_NETWORK_BLOCK), + NetworkItemCreateCallback, + NetworkItemDeleteCallback + ); + + { + static PH_SETTING_CREATE settings[] = + { + { StringSettingType, SETTING_NAME_DISK_TREE_LIST_COLUMNS, L"" }, + { IntegerPairSettingType, SETTING_NAME_DISK_TREE_LIST_SORT, L"4,2" }, // 4, DescendingSortOrder + { IntegerSettingType, SETTING_NAME_ENABLE_ETW_MONITOR, L"1" }, + { IntegerSettingType, SETTING_NAME_ENABLE_GPU_MONITOR, L"1" }, + { IntegerSettingType, SETTING_NAME_ENABLE_SYSINFO_GRAPHS, L"1" }, + { StringSettingType, SETTING_NAME_GPU_NODE_BITMAP, L"01000000" }, + { IntegerSettingType, SETTING_NAME_GPU_LAST_NODE_COUNT, L"0" } + }; + + PhAddSettings(settings, sizeof(settings) / sizeof(PH_SETTING_CREATE)); + } + } + break; + } + + return TRUE; } \ No newline at end of file diff --git a/plugins/ExtendedTools/modsrv.c b/plugins/ExtendedTools/modsrv.c index 1a73346f4624..16b110ae4628 100644 --- a/plugins/ExtendedTools/modsrv.c +++ b/plugins/ExtendedTools/modsrv.c @@ -1,173 +1,173 @@ -/* - * Process Hacker Extended Tools - - * services referencing module - * - * Copyright (C) 2010-2011 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include "exttools.h" -#include - -typedef struct _MODULE_SERVICES_CONTEXT -{ - HANDLE ProcessId; - PWSTR ModuleName; -} MODULE_SERVICES_CONTEXT, *PMODULE_SERVICES_CONTEXT; - -INT_PTR CALLBACK EtpModuleServicesDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -VOID EtShowModuleServicesDialog( - _In_ HWND ParentWindowHandle, - _In_ HANDLE ProcessId, - _In_ PWSTR ModuleName - ) -{ - MODULE_SERVICES_CONTEXT context; - - context.ProcessId = ProcessId; - context.ModuleName = ModuleName; - - DialogBoxParam( - PluginInstance->DllBase, - MAKEINTRESOURCE(IDD_MODSERVICES), - ParentWindowHandle, - EtpModuleServicesDlgProc, - (LPARAM)&context - ); -} - -INT_PTR CALLBACK EtpModuleServicesDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - switch (uMsg) - { - case WM_INITDIALOG: - { - PMODULE_SERVICES_CONTEXT context = (PMODULE_SERVICES_CONTEXT)lParam; - ULONG win32Result; - PQUERY_TAG_INFORMATION I_QueryTagInformation; - TAG_INFO_NAMES_REFERENCING_MODULE namesReferencingModule; - PPH_LIST serviceList; - PPH_SERVICE_ITEM *serviceItems; - HWND serviceListHandle; - RECT rect; - PPH_PROCESS_ITEM processItem; - PPH_STRING message; - - PhCenterWindow(hwndDlg, GetParent(hwndDlg)); - - I_QueryTagInformation = PhGetModuleProcAddress(L"advapi32.dll", "I_QueryTagInformation"); - - if (!I_QueryTagInformation) - { - PhShowError(hwndDlg, L"Unable to query services because the feature is not supported by the operating system."); - EndDialog(hwndDlg, IDCANCEL); - return FALSE; - } - - memset(&namesReferencingModule, 0, sizeof(TAG_INFO_NAMES_REFERENCING_MODULE)); - namesReferencingModule.InParams.dwPid = HandleToUlong(context->ProcessId); - namesReferencingModule.InParams.pszModule = context->ModuleName; - - win32Result = I_QueryTagInformation(NULL, eTagInfoLevelNamesReferencingModule, &namesReferencingModule); - - if (win32Result == ERROR_NO_MORE_ITEMS) - win32Result = 0; - - if (win32Result != 0) - { - PhShowStatus(hwndDlg, L"Unable to query services", 0, win32Result); - EndDialog(hwndDlg, IDCANCEL); - return FALSE; - } - - serviceList = PhCreateList(16); - - if (namesReferencingModule.OutParams.pmszNames) - { - PPH_SERVICE_ITEM serviceItem; - PWSTR serviceName; - ULONG nameLength; - - serviceName = namesReferencingModule.OutParams.pmszNames; - - while (TRUE) - { - nameLength = (ULONG)PhCountStringZ(serviceName); - - if (nameLength == 0) - break; - - if (serviceItem = PhReferenceServiceItem(serviceName)) - PhAddItemList(serviceList, serviceItem); - - serviceName += nameLength + 1; - } - - LocalFree(namesReferencingModule.OutParams.pmszNames); - } - - serviceItems = PhAllocateCopy(serviceList->Items, serviceList->Count * sizeof(PPH_SERVICE_ITEM)); - PhDereferenceObject(serviceList); - serviceListHandle = PhCreateServiceListControl(hwndDlg, serviceItems, serviceList->Count); - - // Position the control. - GetWindowRect(GetDlgItem(hwndDlg, IDC_SERVICES_LAYOUT), &rect); - MapWindowPoints(NULL, hwndDlg, (POINT *)&rect, 2); - MoveWindow(serviceListHandle, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, FALSE); - - ShowWindow(serviceListHandle, SW_SHOW); - - if (processItem = PhReferenceProcessItem(context->ProcessId)) - { - message = PhFormatString(L"Services referencing %s in %s:", context->ModuleName, processItem->ProcessName->Buffer); - PhDereferenceObject(processItem); - } - else - { - message = PhFormatString(L"Services referencing %s:", context->ModuleName); - } - - SetDlgItemText(hwndDlg, IDC_MESSAGE, message->Buffer); - PhDereferenceObject(message); - } - break; - case WM_COMMAND: - { - switch (LOWORD(wParam)) - { - case IDCANCEL: - case IDOK: - EndDialog(hwndDlg, IDOK); - break; - } - } - break; - } - - return FALSE; -} +/* + * Process Hacker Extended Tools - + * services referencing module + * + * Copyright (C) 2010-2011 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include "exttools.h" +#include + +typedef struct _MODULE_SERVICES_CONTEXT +{ + HANDLE ProcessId; + PWSTR ModuleName; +} MODULE_SERVICES_CONTEXT, *PMODULE_SERVICES_CONTEXT; + +INT_PTR CALLBACK EtpModuleServicesDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +VOID EtShowModuleServicesDialog( + _In_ HWND ParentWindowHandle, + _In_ HANDLE ProcessId, + _In_ PWSTR ModuleName + ) +{ + MODULE_SERVICES_CONTEXT context; + + context.ProcessId = ProcessId; + context.ModuleName = ModuleName; + + DialogBoxParam( + PluginInstance->DllBase, + MAKEINTRESOURCE(IDD_MODSERVICES), + ParentWindowHandle, + EtpModuleServicesDlgProc, + (LPARAM)&context + ); +} + +INT_PTR CALLBACK EtpModuleServicesDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + switch (uMsg) + { + case WM_INITDIALOG: + { + PMODULE_SERVICES_CONTEXT context = (PMODULE_SERVICES_CONTEXT)lParam; + ULONG win32Result; + PQUERY_TAG_INFORMATION I_QueryTagInformation; + TAG_INFO_NAMES_REFERENCING_MODULE namesReferencingModule; + PPH_LIST serviceList; + PPH_SERVICE_ITEM *serviceItems; + HWND serviceListHandle; + RECT rect; + PPH_PROCESS_ITEM processItem; + PPH_STRING message; + + PhCenterWindow(hwndDlg, GetParent(hwndDlg)); + + I_QueryTagInformation = PhGetModuleProcAddress(L"advapi32.dll", "I_QueryTagInformation"); + + if (!I_QueryTagInformation) + { + PhShowError(hwndDlg, L"Unable to query services because the feature is not supported by the operating system."); + EndDialog(hwndDlg, IDCANCEL); + return FALSE; + } + + memset(&namesReferencingModule, 0, sizeof(TAG_INFO_NAMES_REFERENCING_MODULE)); + namesReferencingModule.InParams.dwPid = HandleToUlong(context->ProcessId); + namesReferencingModule.InParams.pszModule = context->ModuleName; + + win32Result = I_QueryTagInformation(NULL, eTagInfoLevelNamesReferencingModule, &namesReferencingModule); + + if (win32Result == ERROR_NO_MORE_ITEMS) + win32Result = 0; + + if (win32Result != 0) + { + PhShowStatus(hwndDlg, L"Unable to query services", 0, win32Result); + EndDialog(hwndDlg, IDCANCEL); + return FALSE; + } + + serviceList = PhCreateList(16); + + if (namesReferencingModule.OutParams.pmszNames) + { + PPH_SERVICE_ITEM serviceItem; + PWSTR serviceName; + ULONG nameLength; + + serviceName = namesReferencingModule.OutParams.pmszNames; + + while (TRUE) + { + nameLength = (ULONG)PhCountStringZ(serviceName); + + if (nameLength == 0) + break; + + if (serviceItem = PhReferenceServiceItem(serviceName)) + PhAddItemList(serviceList, serviceItem); + + serviceName += nameLength + 1; + } + + LocalFree(namesReferencingModule.OutParams.pmszNames); + } + + serviceItems = PhAllocateCopy(serviceList->Items, serviceList->Count * sizeof(PPH_SERVICE_ITEM)); + PhDereferenceObject(serviceList); + serviceListHandle = PhCreateServiceListControl(hwndDlg, serviceItems, serviceList->Count); + + // Position the control. + GetWindowRect(GetDlgItem(hwndDlg, IDC_SERVICES_LAYOUT), &rect); + MapWindowPoints(NULL, hwndDlg, (POINT *)&rect, 2); + MoveWindow(serviceListHandle, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, FALSE); + + ShowWindow(serviceListHandle, SW_SHOW); + + if (processItem = PhReferenceProcessItem(context->ProcessId)) + { + message = PhFormatString(L"Services referencing %s in %s:", context->ModuleName, processItem->ProcessName->Buffer); + PhDereferenceObject(processItem); + } + else + { + message = PhFormatString(L"Services referencing %s:", context->ModuleName); + } + + SetDlgItemText(hwndDlg, IDC_MESSAGE, message->Buffer); + PhDereferenceObject(message); + } + break; + case WM_COMMAND: + { + switch (LOWORD(wParam)) + { + case IDCANCEL: + case IDOK: + EndDialog(hwndDlg, IDOK); + break; + } + } + break; + } + + return FALSE; +} diff --git a/plugins/ExtendedTools/objprp.c b/plugins/ExtendedTools/objprp.c index 8cf21194bdc6..6716448708b6 100644 --- a/plugins/ExtendedTools/objprp.c +++ b/plugins/ExtendedTools/objprp.c @@ -1,312 +1,312 @@ -/* - * Process Hacker Extended Tools - - * handle properties extensions - * - * Copyright (C) 2010-2011 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include "exttools.h" -#include - -typedef struct _COMMON_PAGE_CONTEXT -{ - PPH_HANDLE_ITEM HandleItem; - HANDLE ProcessId; -} COMMON_PAGE_CONTEXT, *PCOMMON_PAGE_CONTEXT; - -HPROPSHEETPAGE EtpCommonCreatePage( - _In_ PPH_PLUGIN_HANDLE_PROPERTIES_CONTEXT Context, - _In_ PWSTR Template, - _In_ DLGPROC DlgProc - ); - -INT CALLBACK EtpCommonPropPageProc( - _In_ HWND hwnd, - _In_ UINT uMsg, - _In_ LPPROPSHEETPAGE ppsp - ); - -INT_PTR CALLBACK EtpAlpcPortPageDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -INT_PTR CALLBACK EtpTpWorkerFactoryPageDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -VOID EtHandlePropertiesInitializing( - _In_ PVOID Parameter - ) -{ - PPH_PLUGIN_OBJECT_PROPERTIES objectProperties = Parameter; - PPH_PLUGIN_HANDLE_PROPERTIES_CONTEXT context = objectProperties->Parameter; - - if (objectProperties->NumberOfPages < objectProperties->MaximumNumberOfPages) - { - HPROPSHEETPAGE page = NULL; - - if (PhEqualString2(context->HandleItem->TypeName, L"ALPC Port", TRUE)) - { - page = EtpCommonCreatePage( - context, - MAKEINTRESOURCE(IDD_OBJALPCPORT), - EtpAlpcPortPageDlgProc - ); - } - else if (PhEqualString2(context->HandleItem->TypeName, L"TpWorkerFactory", TRUE)) - { - page = EtpCommonCreatePage( - context, - MAKEINTRESOURCE(IDD_OBJTPWORKERFACTORY), - EtpTpWorkerFactoryPageDlgProc - ); - } - - // Insert our page into the second slot. - - if (page) - { - if (objectProperties->NumberOfPages > 1) - { - memmove(&objectProperties->Pages[2], &objectProperties->Pages[1], - (objectProperties->NumberOfPages - 1) * sizeof(HPROPSHEETPAGE)); - } - - objectProperties->Pages[1] = page; - objectProperties->NumberOfPages++; - } - } -} - -static HPROPSHEETPAGE EtpCommonCreatePage( - _In_ PPH_PLUGIN_HANDLE_PROPERTIES_CONTEXT Context, - _In_ PWSTR Template, - _In_ DLGPROC DlgProc - ) -{ - HPROPSHEETPAGE propSheetPageHandle; - PROPSHEETPAGE propSheetPage; - PCOMMON_PAGE_CONTEXT pageContext; - - pageContext = PhCreateAlloc(sizeof(COMMON_PAGE_CONTEXT)); - memset(pageContext, 0, sizeof(COMMON_PAGE_CONTEXT)); - pageContext->HandleItem = Context->HandleItem; - pageContext->ProcessId = Context->ProcessId; - - memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); - propSheetPage.dwSize = sizeof(PROPSHEETPAGE); - propSheetPage.dwFlags = PSP_USECALLBACK; - propSheetPage.hInstance = PluginInstance->DllBase; - propSheetPage.pszTemplate = Template; - propSheetPage.pfnDlgProc = DlgProc; - propSheetPage.lParam = (LPARAM)pageContext; - propSheetPage.pfnCallback = EtpCommonPropPageProc; - - propSheetPageHandle = CreatePropertySheetPage(&propSheetPage); - PhDereferenceObject(pageContext); // already got a ref from above call - - return propSheetPageHandle; -} - -INT CALLBACK EtpCommonPropPageProc( - _In_ HWND hwnd, - _In_ UINT uMsg, - _In_ LPPROPSHEETPAGE ppsp - ) -{ - PCOMMON_PAGE_CONTEXT pageContext; - - pageContext = (PCOMMON_PAGE_CONTEXT)ppsp->lParam; - - if (uMsg == PSPCB_ADDREF) - PhReferenceObject(pageContext); - else if (uMsg == PSPCB_RELEASE) - PhDereferenceObject(pageContext); - - return 1; -} - -static NTSTATUS EtpDuplicateHandleFromProcess( - _Out_ PHANDLE Handle, - _In_ ACCESS_MASK DesiredAccess, - _In_ PCOMMON_PAGE_CONTEXT Context - ) -{ - NTSTATUS status; - HANDLE processHandle; - - if (!NT_SUCCESS(status = PhOpenProcess( - &processHandle, - PROCESS_DUP_HANDLE, - Context->ProcessId - ))) - return status; - - status = NtDuplicateObject( - processHandle, - Context->HandleItem->Handle, - NtCurrentProcess(), - Handle, - DesiredAccess, - 0, - 0 - ); - NtClose(processHandle); - - return status; -} - -INT_PTR CALLBACK EtpAlpcPortPageDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - switch (uMsg) - { - case WM_INITDIALOG: - { - LPPROPSHEETPAGE propSheetPage = (LPPROPSHEETPAGE)lParam; - PCOMMON_PAGE_CONTEXT context = (PCOMMON_PAGE_CONTEXT)propSheetPage->lParam; - HANDLE portHandle; - - if (NT_SUCCESS(EtpDuplicateHandleFromProcess(&portHandle, READ_CONTROL, context))) - { - ALPC_BASIC_INFORMATION basicInfo; - - if (NT_SUCCESS(NtAlpcQueryInformation( - portHandle, - AlpcBasicInformation, - &basicInfo, - sizeof(ALPC_BASIC_INFORMATION), - NULL - ))) - { - PH_FORMAT format[2]; - PPH_STRING string; - - PhInitFormatS(&format[0], L"Sequence Number: "); - PhInitFormatD(&format[1], basicInfo.SequenceNo); - format[1].Type |= FormatGroupDigits; - - string = PhFormat(format, 2, 128); - SetDlgItemText(hwndDlg, IDC_SEQUENCENUMBER, string->Buffer); - PhDereferenceObject(string); - - SetDlgItemText(hwndDlg, IDC_PORTCONTEXT, - PhaFormatString(L"Port Context: 0x%Ix", basicInfo.PortContext)->Buffer); - } - - NtClose(portHandle); - } - } - break; - } - - return FALSE; -} - -static BOOLEAN NTAPI EnumGenericModulesCallback( - _In_ PPH_MODULE_INFO Module, - _In_opt_ PVOID Context - ) -{ - if (Module->Type == PH_MODULE_TYPE_MODULE || Module->Type == PH_MODULE_TYPE_WOW64_MODULE) - { - PhLoadModuleSymbolProvider(Context, Module->FileName->Buffer, - (ULONG64)Module->BaseAddress, Module->Size); - } - - return TRUE; -} - -INT_PTR CALLBACK EtpTpWorkerFactoryPageDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - switch (uMsg) - { - case WM_INITDIALOG: - { - LPPROPSHEETPAGE propSheetPage = (LPPROPSHEETPAGE)lParam; - PCOMMON_PAGE_CONTEXT context = (PCOMMON_PAGE_CONTEXT)propSheetPage->lParam; - HANDLE workerFactoryHandle; - - if (NT_SUCCESS(EtpDuplicateHandleFromProcess(&workerFactoryHandle, WORKER_FACTORY_QUERY_INFORMATION, context))) - { - WORKER_FACTORY_BASIC_INFORMATION basicInfo; - - if (NT_SUCCESS(NtQueryInformationWorkerFactory( - workerFactoryHandle, - WorkerFactoryBasicInformation, - &basicInfo, - sizeof(WORKER_FACTORY_BASIC_INFORMATION), - NULL - ))) - { - PPH_SYMBOL_PROVIDER symbolProvider; - PPH_STRING symbol = NULL; - - symbolProvider = PhCreateSymbolProvider(basicInfo.ProcessId); - PhLoadSymbolProviderOptions(symbolProvider); - - if (symbolProvider->IsRealHandle) - { - PhEnumGenericModules(basicInfo.ProcessId, symbolProvider->ProcessHandle, - 0, EnumGenericModulesCallback, symbolProvider); - - symbol = PhGetSymbolFromAddress(symbolProvider, (ULONG64)basicInfo.StartRoutine, - NULL, NULL, NULL, NULL); - } - - PhDereferenceObject(symbolProvider); - - if (symbol) - { - SetDlgItemText(hwndDlg, IDC_WORKERTHREADSTART, - PhaFormatString(L"Worker Thread Start: %s", symbol->Buffer)->Buffer); - PhDereferenceObject(symbol); - } - else - { - SetDlgItemText(hwndDlg, IDC_WORKERTHREADSTART, - PhaFormatString(L"Worker Thread Start: 0x%Ix", basicInfo.StartRoutine)->Buffer); - } - - SetDlgItemText(hwndDlg, IDC_WORKERTHREADCONTEXT, - PhaFormatString(L"Worker Thread Context: 0x%Ix", basicInfo.StartParameter)->Buffer); - } - - NtClose(workerFactoryHandle); - } - } - break; - } - - return FALSE; -} +/* + * Process Hacker Extended Tools - + * handle properties extensions + * + * Copyright (C) 2010-2011 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include "exttools.h" +#include + +typedef struct _COMMON_PAGE_CONTEXT +{ + PPH_HANDLE_ITEM HandleItem; + HANDLE ProcessId; +} COMMON_PAGE_CONTEXT, *PCOMMON_PAGE_CONTEXT; + +HPROPSHEETPAGE EtpCommonCreatePage( + _In_ PPH_PLUGIN_HANDLE_PROPERTIES_CONTEXT Context, + _In_ PWSTR Template, + _In_ DLGPROC DlgProc + ); + +INT CALLBACK EtpCommonPropPageProc( + _In_ HWND hwnd, + _In_ UINT uMsg, + _In_ LPPROPSHEETPAGE ppsp + ); + +INT_PTR CALLBACK EtpAlpcPortPageDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +INT_PTR CALLBACK EtpTpWorkerFactoryPageDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +VOID EtHandlePropertiesInitializing( + _In_ PVOID Parameter + ) +{ + PPH_PLUGIN_OBJECT_PROPERTIES objectProperties = Parameter; + PPH_PLUGIN_HANDLE_PROPERTIES_CONTEXT context = objectProperties->Parameter; + + if (objectProperties->NumberOfPages < objectProperties->MaximumNumberOfPages) + { + HPROPSHEETPAGE page = NULL; + + if (PhEqualString2(context->HandleItem->TypeName, L"ALPC Port", TRUE)) + { + page = EtpCommonCreatePage( + context, + MAKEINTRESOURCE(IDD_OBJALPCPORT), + EtpAlpcPortPageDlgProc + ); + } + else if (PhEqualString2(context->HandleItem->TypeName, L"TpWorkerFactory", TRUE)) + { + page = EtpCommonCreatePage( + context, + MAKEINTRESOURCE(IDD_OBJTPWORKERFACTORY), + EtpTpWorkerFactoryPageDlgProc + ); + } + + // Insert our page into the second slot. + + if (page) + { + if (objectProperties->NumberOfPages > 1) + { + memmove(&objectProperties->Pages[2], &objectProperties->Pages[1], + (objectProperties->NumberOfPages - 1) * sizeof(HPROPSHEETPAGE)); + } + + objectProperties->Pages[1] = page; + objectProperties->NumberOfPages++; + } + } +} + +static HPROPSHEETPAGE EtpCommonCreatePage( + _In_ PPH_PLUGIN_HANDLE_PROPERTIES_CONTEXT Context, + _In_ PWSTR Template, + _In_ DLGPROC DlgProc + ) +{ + HPROPSHEETPAGE propSheetPageHandle; + PROPSHEETPAGE propSheetPage; + PCOMMON_PAGE_CONTEXT pageContext; + + pageContext = PhCreateAlloc(sizeof(COMMON_PAGE_CONTEXT)); + memset(pageContext, 0, sizeof(COMMON_PAGE_CONTEXT)); + pageContext->HandleItem = Context->HandleItem; + pageContext->ProcessId = Context->ProcessId; + + memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); + propSheetPage.dwSize = sizeof(PROPSHEETPAGE); + propSheetPage.dwFlags = PSP_USECALLBACK; + propSheetPage.hInstance = PluginInstance->DllBase; + propSheetPage.pszTemplate = Template; + propSheetPage.pfnDlgProc = DlgProc; + propSheetPage.lParam = (LPARAM)pageContext; + propSheetPage.pfnCallback = EtpCommonPropPageProc; + + propSheetPageHandle = CreatePropertySheetPage(&propSheetPage); + PhDereferenceObject(pageContext); // already got a ref from above call + + return propSheetPageHandle; +} + +INT CALLBACK EtpCommonPropPageProc( + _In_ HWND hwnd, + _In_ UINT uMsg, + _In_ LPPROPSHEETPAGE ppsp + ) +{ + PCOMMON_PAGE_CONTEXT pageContext; + + pageContext = (PCOMMON_PAGE_CONTEXT)ppsp->lParam; + + if (uMsg == PSPCB_ADDREF) + PhReferenceObject(pageContext); + else if (uMsg == PSPCB_RELEASE) + PhDereferenceObject(pageContext); + + return 1; +} + +static NTSTATUS EtpDuplicateHandleFromProcess( + _Out_ PHANDLE Handle, + _In_ ACCESS_MASK DesiredAccess, + _In_ PCOMMON_PAGE_CONTEXT Context + ) +{ + NTSTATUS status; + HANDLE processHandle; + + if (!NT_SUCCESS(status = PhOpenProcess( + &processHandle, + PROCESS_DUP_HANDLE, + Context->ProcessId + ))) + return status; + + status = NtDuplicateObject( + processHandle, + Context->HandleItem->Handle, + NtCurrentProcess(), + Handle, + DesiredAccess, + 0, + 0 + ); + NtClose(processHandle); + + return status; +} + +INT_PTR CALLBACK EtpAlpcPortPageDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + switch (uMsg) + { + case WM_INITDIALOG: + { + LPPROPSHEETPAGE propSheetPage = (LPPROPSHEETPAGE)lParam; + PCOMMON_PAGE_CONTEXT context = (PCOMMON_PAGE_CONTEXT)propSheetPage->lParam; + HANDLE portHandle; + + if (NT_SUCCESS(EtpDuplicateHandleFromProcess(&portHandle, READ_CONTROL, context))) + { + ALPC_BASIC_INFORMATION basicInfo; + + if (NT_SUCCESS(NtAlpcQueryInformation( + portHandle, + AlpcBasicInformation, + &basicInfo, + sizeof(ALPC_BASIC_INFORMATION), + NULL + ))) + { + PH_FORMAT format[2]; + PPH_STRING string; + + PhInitFormatS(&format[0], L"Sequence Number: "); + PhInitFormatD(&format[1], basicInfo.SequenceNo); + format[1].Type |= FormatGroupDigits; + + string = PhFormat(format, 2, 128); + SetDlgItemText(hwndDlg, IDC_SEQUENCENUMBER, string->Buffer); + PhDereferenceObject(string); + + SetDlgItemText(hwndDlg, IDC_PORTCONTEXT, + PhaFormatString(L"Port Context: 0x%Ix", basicInfo.PortContext)->Buffer); + } + + NtClose(portHandle); + } + } + break; + } + + return FALSE; +} + +static BOOLEAN NTAPI EnumGenericModulesCallback( + _In_ PPH_MODULE_INFO Module, + _In_opt_ PVOID Context + ) +{ + if (Module->Type == PH_MODULE_TYPE_MODULE || Module->Type == PH_MODULE_TYPE_WOW64_MODULE) + { + PhLoadModuleSymbolProvider(Context, Module->FileName->Buffer, + (ULONG64)Module->BaseAddress, Module->Size); + } + + return TRUE; +} + +INT_PTR CALLBACK EtpTpWorkerFactoryPageDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + switch (uMsg) + { + case WM_INITDIALOG: + { + LPPROPSHEETPAGE propSheetPage = (LPPROPSHEETPAGE)lParam; + PCOMMON_PAGE_CONTEXT context = (PCOMMON_PAGE_CONTEXT)propSheetPage->lParam; + HANDLE workerFactoryHandle; + + if (NT_SUCCESS(EtpDuplicateHandleFromProcess(&workerFactoryHandle, WORKER_FACTORY_QUERY_INFORMATION, context))) + { + WORKER_FACTORY_BASIC_INFORMATION basicInfo; + + if (NT_SUCCESS(NtQueryInformationWorkerFactory( + workerFactoryHandle, + WorkerFactoryBasicInformation, + &basicInfo, + sizeof(WORKER_FACTORY_BASIC_INFORMATION), + NULL + ))) + { + PPH_SYMBOL_PROVIDER symbolProvider; + PPH_STRING symbol = NULL; + + symbolProvider = PhCreateSymbolProvider(basicInfo.ProcessId); + PhLoadSymbolProviderOptions(symbolProvider); + + if (symbolProvider->IsRealHandle) + { + PhEnumGenericModules(basicInfo.ProcessId, symbolProvider->ProcessHandle, + 0, EnumGenericModulesCallback, symbolProvider); + + symbol = PhGetSymbolFromAddress(symbolProvider, (ULONG64)basicInfo.StartRoutine, + NULL, NULL, NULL, NULL); + } + + PhDereferenceObject(symbolProvider); + + if (symbol) + { + SetDlgItemText(hwndDlg, IDC_WORKERTHREADSTART, + PhaFormatString(L"Worker Thread Start: %s", symbol->Buffer)->Buffer); + PhDereferenceObject(symbol); + } + else + { + SetDlgItemText(hwndDlg, IDC_WORKERTHREADSTART, + PhaFormatString(L"Worker Thread Start: 0x%Ix", basicInfo.StartRoutine)->Buffer); + } + + SetDlgItemText(hwndDlg, IDC_WORKERTHREADCONTEXT, + PhaFormatString(L"Worker Thread Context: 0x%Ix", basicInfo.StartParameter)->Buffer); + } + + NtClose(workerFactoryHandle); + } + } + break; + } + + return FALSE; +} diff --git a/plugins/ExtendedTools/options.c b/plugins/ExtendedTools/options.c index 20e0c3323788..a33671d5f1e5 100644 --- a/plugins/ExtendedTools/options.c +++ b/plugins/ExtendedTools/options.c @@ -1,87 +1,87 @@ -/* - * Process Hacker Extended Tools - - * options dialog - * - * Copyright (C) 2010 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include "exttools.h" - -INT_PTR CALLBACK OptionsDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -VOID EtShowOptionsDialog( - _In_ HWND ParentWindowHandle - ) -{ - DialogBox( - PluginInstance->DllBase, - MAKEINTRESOURCE(IDD_OPTIONS), - ParentWindowHandle, - OptionsDlgProc - ); -} - -INT_PTR CALLBACK OptionsDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - switch (uMsg) - { - case WM_INITDIALOG: - { - PhCenterWindow(hwndDlg, GetParent(hwndDlg)); - - Button_SetCheck(GetDlgItem(hwndDlg, IDC_ENABLEETWMONITOR), PhGetIntegerSetting(SETTING_NAME_ENABLE_ETW_MONITOR) ? BST_CHECKED : BST_UNCHECKED); - Button_SetCheck(GetDlgItem(hwndDlg, IDC_ENABLEGPUMONITOR), PhGetIntegerSetting(SETTING_NAME_ENABLE_GPU_MONITOR) ? BST_CHECKED : BST_UNCHECKED); - Button_SetCheck(GetDlgItem(hwndDlg, IDC_ENABLESYSINFOGRAPHS), PhGetIntegerSetting(SETTING_NAME_ENABLE_SYSINFO_GRAPHS) ? BST_CHECKED : BST_UNCHECKED); - } - break; - case WM_COMMAND: - { - switch (LOWORD(wParam)) - { - case IDCANCEL: - EndDialog(hwndDlg, IDCANCEL); - break; - case IDOK: - { - PhSetIntegerSetting(SETTING_NAME_ENABLE_ETW_MONITOR, - Button_GetCheck(GetDlgItem(hwndDlg, IDC_ENABLEETWMONITOR)) == BST_CHECKED); - PhSetIntegerSetting(SETTING_NAME_ENABLE_GPU_MONITOR, - Button_GetCheck(GetDlgItem(hwndDlg, IDC_ENABLEGPUMONITOR)) == BST_CHECKED); - PhSetIntegerSetting(SETTING_NAME_ENABLE_SYSINFO_GRAPHS, - Button_GetCheck(GetDlgItem(hwndDlg, IDC_ENABLESYSINFOGRAPHS)) == BST_CHECKED); - - EndDialog(hwndDlg, IDOK); - } - break; - } - } - break; - } - - return FALSE; -} +/* + * Process Hacker Extended Tools - + * options dialog + * + * Copyright (C) 2010 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include "exttools.h" + +INT_PTR CALLBACK OptionsDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +VOID EtShowOptionsDialog( + _In_ HWND ParentWindowHandle + ) +{ + DialogBox( + PluginInstance->DllBase, + MAKEINTRESOURCE(IDD_OPTIONS), + ParentWindowHandle, + OptionsDlgProc + ); +} + +INT_PTR CALLBACK OptionsDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + switch (uMsg) + { + case WM_INITDIALOG: + { + PhCenterWindow(hwndDlg, GetParent(hwndDlg)); + + Button_SetCheck(GetDlgItem(hwndDlg, IDC_ENABLEETWMONITOR), PhGetIntegerSetting(SETTING_NAME_ENABLE_ETW_MONITOR) ? BST_CHECKED : BST_UNCHECKED); + Button_SetCheck(GetDlgItem(hwndDlg, IDC_ENABLEGPUMONITOR), PhGetIntegerSetting(SETTING_NAME_ENABLE_GPU_MONITOR) ? BST_CHECKED : BST_UNCHECKED); + Button_SetCheck(GetDlgItem(hwndDlg, IDC_ENABLESYSINFOGRAPHS), PhGetIntegerSetting(SETTING_NAME_ENABLE_SYSINFO_GRAPHS) ? BST_CHECKED : BST_UNCHECKED); + } + break; + case WM_COMMAND: + { + switch (LOWORD(wParam)) + { + case IDCANCEL: + EndDialog(hwndDlg, IDCANCEL); + break; + case IDOK: + { + PhSetIntegerSetting(SETTING_NAME_ENABLE_ETW_MONITOR, + Button_GetCheck(GetDlgItem(hwndDlg, IDC_ENABLEETWMONITOR)) == BST_CHECKED); + PhSetIntegerSetting(SETTING_NAME_ENABLE_GPU_MONITOR, + Button_GetCheck(GetDlgItem(hwndDlg, IDC_ENABLEGPUMONITOR)) == BST_CHECKED); + PhSetIntegerSetting(SETTING_NAME_ENABLE_SYSINFO_GRAPHS, + Button_GetCheck(GetDlgItem(hwndDlg, IDC_ENABLESYSINFOGRAPHS)) == BST_CHECKED); + + EndDialog(hwndDlg, IDOK); + } + break; + } + } + break; + } + + return FALSE; +} diff --git a/plugins/ExtendedTools/procicon.c b/plugins/ExtendedTools/procicon.c index 9724a62da3f0..bfb202f570df 100644 --- a/plugins/ExtendedTools/procicon.c +++ b/plugins/ExtendedTools/procicon.c @@ -1,95 +1,95 @@ -/* - * Process Hacker Extended Tools - - * process icon duplication - * - * Copyright (C) 2011 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include "exttools.h" - -PET_PROCESS_ICON EtProcIconCreateProcessIcon( - _In_ HICON Icon - ) -{ - PET_PROCESS_ICON processIcon; - - processIcon = PhAllocate(sizeof(ET_PROCESS_ICON)); - processIcon->RefCount = 1; - processIcon->Icon = CopyIcon(Icon); - - return processIcon; -} - -VOID EtProcIconReferenceProcessIcon( - _Inout_ PET_PROCESS_ICON ProcessIcon - ) -{ - _InterlockedIncrement(&ProcessIcon->RefCount); -} - -VOID EtProcIconDereferenceProcessIcon( - _Inout_ PET_PROCESS_ICON ProcessIcon - ) -{ - if (_InterlockedDecrement(&ProcessIcon->RefCount) == 0) - { - DestroyIcon(ProcessIcon->Icon); - PhFree(ProcessIcon); - } -} - -PET_PROCESS_ICON EtProcIconReferenceSmallProcessIcon( - _Inout_ PET_PROCESS_BLOCK Block - ) -{ - PET_PROCESS_ICON smallProcessIcon; - - smallProcessIcon = Block->SmallProcessIcon; - - if (!smallProcessIcon && PhTestEvent(&Block->ProcessItem->Stage1Event)) - { - smallProcessIcon = EtProcIconCreateProcessIcon(Block->ProcessItem->SmallIcon); - - if (_InterlockedCompareExchangePointer( - &Block->SmallProcessIcon, - smallProcessIcon, - NULL - ) != NULL) - { - EtProcIconDereferenceProcessIcon(smallProcessIcon); - smallProcessIcon = Block->SmallProcessIcon; - } - } - - if (smallProcessIcon) - { - EtProcIconReferenceProcessIcon(smallProcessIcon); - } - - return smallProcessIcon; -} - -VOID EtProcIconNotifyProcessDelete( - _Inout_ PET_PROCESS_BLOCK Block - ) -{ - if (Block->SmallProcessIcon) - { - EtProcIconDereferenceProcessIcon(Block->SmallProcessIcon); - } -} +/* + * Process Hacker Extended Tools - + * process icon duplication + * + * Copyright (C) 2011 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include "exttools.h" + +PET_PROCESS_ICON EtProcIconCreateProcessIcon( + _In_ HICON Icon + ) +{ + PET_PROCESS_ICON processIcon; + + processIcon = PhAllocate(sizeof(ET_PROCESS_ICON)); + processIcon->RefCount = 1; + processIcon->Icon = CopyIcon(Icon); + + return processIcon; +} + +VOID EtProcIconReferenceProcessIcon( + _Inout_ PET_PROCESS_ICON ProcessIcon + ) +{ + _InterlockedIncrement(&ProcessIcon->RefCount); +} + +VOID EtProcIconDereferenceProcessIcon( + _Inout_ PET_PROCESS_ICON ProcessIcon + ) +{ + if (_InterlockedDecrement(&ProcessIcon->RefCount) == 0) + { + DestroyIcon(ProcessIcon->Icon); + PhFree(ProcessIcon); + } +} + +PET_PROCESS_ICON EtProcIconReferenceSmallProcessIcon( + _Inout_ PET_PROCESS_BLOCK Block + ) +{ + PET_PROCESS_ICON smallProcessIcon; + + smallProcessIcon = Block->SmallProcessIcon; + + if (!smallProcessIcon && PhTestEvent(&Block->ProcessItem->Stage1Event)) + { + smallProcessIcon = EtProcIconCreateProcessIcon(Block->ProcessItem->SmallIcon); + + if (_InterlockedCompareExchangePointer( + &Block->SmallProcessIcon, + smallProcessIcon, + NULL + ) != NULL) + { + EtProcIconDereferenceProcessIcon(smallProcessIcon); + smallProcessIcon = Block->SmallProcessIcon; + } + } + + if (smallProcessIcon) + { + EtProcIconReferenceProcessIcon(smallProcessIcon); + } + + return smallProcessIcon; +} + +VOID EtProcIconNotifyProcessDelete( + _Inout_ PET_PROCESS_BLOCK Block + ) +{ + if (Block->SmallProcessIcon) + { + EtProcIconDereferenceProcessIcon(Block->SmallProcessIcon); + } +} diff --git a/plugins/ExtendedTools/resource.h b/plugins/ExtendedTools/resource.h index 4e73128faf6f..27a55506b591 100644 --- a/plugins/ExtendedTools/resource.h +++ b/plugins/ExtendedTools/resource.h @@ -1,114 +1,114 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by ExtendedTools.rc -// -#define ID_PROCESS_UNLOADEDMODULES 101 -#define IDD_UNLOADEDDLLS 102 -#define IDD_OBJALPCPORT 103 -#define ID_THREAD_CANCELIO 104 -#define IDD_OBJTPWORKERFACTORY 105 -#define ID_MODULE_SERVICES 106 -#define IDD_MODSERVICES 107 -#define ID_VIEW_MEMORYLISTS 108 -#define IDD_PROCDISKNET 110 -#define ID_VIEW_DISKANDNETWORK 111 -#define ID_PROCESS_WSWATCH 112 -#define IDD_SYSINFO_DISKPANEL 113 -#define IDD_OPTIONS 114 -#define IDD_WSWATCH 115 -#define IDD_SYSINFO_GPU 117 -#define IDR_DISK 118 -#define ID_VIEW_GPUINFORMATION 119 -#define IDD_SYSINFO_GPUPANEL 120 -#define IDD_PROCGPU 121 -#define IDD_SYSINFO_DISK 122 -#define IDD_GPUNODES 123 -#define IDD_SYSINFO_NETPANEL 124 -#define IDD_SYSINFO_NET 125 -#define IDD_PROCGPU_PANEL 126 -#define IDD_DISKTABRESTART 127 -#define IDD_DISKTABERROR 128 -#define IDD_PROCDISKNET_PANEL 129 -#define IDD_PROCGPU_DETAILS 131 -#define IDC_LIST 1001 -#define IDC_REFRESH 1002 -#define IDC_SEQUENCENUMBER 1003 -#define IDC_PORTCONTEXT 1004 -#define IDC_WORKERTHREADSTART 1005 -#define IDC_WORKERTHREADCONTEXT 1006 -#define IDC_SERVICES_LAYOUT 1007 -#define IDC_MESSAGE 1008 -#define IDC_ZREADS_V 1023 -#define IDC_ZREADBYTES_V 1024 -#define IDC_ZREADBYTESDELTA_V 1025 -#define IDC_ZWRITES_V 1026 -#define IDC_ZWRITEBYTES_V 1027 -#define IDC_ZWRITEBYTESDELTA_V 1028 -#define IDC_ZRECEIVES_V 1029 -#define IDC_ZRECEIVEBYTES_V 1030 -#define IDC_ZRECEIVEBYTESDELTA_V 1031 -#define IDC_ZSENDS_V 1032 -#define IDC_ZSENDBYTES_V 1033 -#define IDC_ZSENDBYTESDELTA_V 1034 -#define IDC_ENABLEETWMONITOR 1035 -#define IDC_ENABLE 1036 -#define IDC_WSWATCHENABLED 1037 -#define IDC_NODES 1048 -#define IDC_ENABLEGPUMONITOR 1049 -#define IDC_EXAMPLE 1050 -#define IDC_ENABLESYSINFOGRAPHS 1050 -#define IDC_GROUPGPU 1051 -#define IDC_GROUPMEM 1052 -#define IDC_GROUPSHARED 1053 -#define IDC_GROUPDEDICATED 1054 -#define IDC_ZDEDICATEDCURRENT_V 1055 -#define IDC_ZDEDICATEDLIMIT_V 1056 -#define IDC_ZSHAREDCURRENT_V 1057 -#define IDC_ZSHAREDLIMIT_V 1058 -#define IDC_ZDEDICATEDCOMMITTED_V 1059 -#define IDC_ZRUNNINGTIME_V 1060 -#define IDC_ZCONTEXTSWITCHES_V 1061 -#define IDC_ZTOTALNODES_V 1062 -#define IDC_ZCACHEDALLOCATED_V 1063 -#define IDC_ZCACHEDRESERVED_V 1064 -#define IDC_ZSHAREDCOMMITTED_V 1065 -#define IDC_ZTOTALALLOCATED_V 1066 -#define IDC_ZTOTALRESERVED_V 1067 -#define IDC_ZWRITECOMBINEDALLOCATED_V 1068 -#define IDC_ZWRITECOMBINEDRESERVED_V 1069 -#define IDC_ZSECTIONALLOCATED_V 1070 -#define IDC_ZSECTIONRESERVED_V 1071 -#define IDC_ZTOTALSEGMENTS_V 1072 -#define IDC_TITLE 1073 -#define IDC_GRAPH_LAYOUT 1074 -#define IDC_LAYOUT 1075 -#define IDC_GPUNAME 1076 -#define IDC_GPU_L 1077 -#define IDC_DEDICATED_L 1078 -#define IDC_SHARED_L 1079 -#define IDC_ZRECEIVESDELTA_V 1080 -#define IDC_ZSENDSDELTA_V 1081 -#define IDC_ZWRITESDELTA_V 1082 -#define IDC_ZREADSDELTA_V 1083 -#define IDC_INSTRUCTION 1084 -#define IDC_PANEL_LAYOUT 1085 -#define IDC_RESTART 1086 -#define IDC_ERROR 1087 -#define IDC_GROUPDISK 1088 -#define IDC_GROUPNETWORK 1089 -#define IDC_GPUDETAILS 1090 -#define ID_DISK_GOTOPROCESS 40005 -#define ID_DISK_COPY 40006 -#define ID_DISK_PROPERTIES 40007 -#define ID_DISK_OPENFILELOCATION 40008 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 135 -#define _APS_NEXT_COMMAND_VALUE 40009 -#define _APS_NEXT_CONTROL_VALUE 1091 -#define _APS_NEXT_SYMED_VALUE 130 -#endif -#endif +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by ExtendedTools.rc +// +#define ID_PROCESS_UNLOADEDMODULES 101 +#define IDD_UNLOADEDDLLS 102 +#define IDD_OBJALPCPORT 103 +#define ID_THREAD_CANCELIO 104 +#define IDD_OBJTPWORKERFACTORY 105 +#define ID_MODULE_SERVICES 106 +#define IDD_MODSERVICES 107 +#define ID_VIEW_MEMORYLISTS 108 +#define IDD_PROCDISKNET 110 +#define ID_VIEW_DISKANDNETWORK 111 +#define ID_PROCESS_WSWATCH 112 +#define IDD_SYSINFO_DISKPANEL 113 +#define IDD_OPTIONS 114 +#define IDD_WSWATCH 115 +#define IDD_SYSINFO_GPU 117 +#define IDR_DISK 118 +#define ID_VIEW_GPUINFORMATION 119 +#define IDD_SYSINFO_GPUPANEL 120 +#define IDD_PROCGPU 121 +#define IDD_SYSINFO_DISK 122 +#define IDD_GPUNODES 123 +#define IDD_SYSINFO_NETPANEL 124 +#define IDD_SYSINFO_NET 125 +#define IDD_PROCGPU_PANEL 126 +#define IDD_DISKTABRESTART 127 +#define IDD_DISKTABERROR 128 +#define IDD_PROCDISKNET_PANEL 129 +#define IDD_PROCGPU_DETAILS 131 +#define IDC_LIST 1001 +#define IDC_REFRESH 1002 +#define IDC_SEQUENCENUMBER 1003 +#define IDC_PORTCONTEXT 1004 +#define IDC_WORKERTHREADSTART 1005 +#define IDC_WORKERTHREADCONTEXT 1006 +#define IDC_SERVICES_LAYOUT 1007 +#define IDC_MESSAGE 1008 +#define IDC_ZREADS_V 1023 +#define IDC_ZREADBYTES_V 1024 +#define IDC_ZREADBYTESDELTA_V 1025 +#define IDC_ZWRITES_V 1026 +#define IDC_ZWRITEBYTES_V 1027 +#define IDC_ZWRITEBYTESDELTA_V 1028 +#define IDC_ZRECEIVES_V 1029 +#define IDC_ZRECEIVEBYTES_V 1030 +#define IDC_ZRECEIVEBYTESDELTA_V 1031 +#define IDC_ZSENDS_V 1032 +#define IDC_ZSENDBYTES_V 1033 +#define IDC_ZSENDBYTESDELTA_V 1034 +#define IDC_ENABLEETWMONITOR 1035 +#define IDC_ENABLE 1036 +#define IDC_WSWATCHENABLED 1037 +#define IDC_NODES 1048 +#define IDC_ENABLEGPUMONITOR 1049 +#define IDC_EXAMPLE 1050 +#define IDC_ENABLESYSINFOGRAPHS 1050 +#define IDC_GROUPGPU 1051 +#define IDC_GROUPMEM 1052 +#define IDC_GROUPSHARED 1053 +#define IDC_GROUPDEDICATED 1054 +#define IDC_ZDEDICATEDCURRENT_V 1055 +#define IDC_ZDEDICATEDLIMIT_V 1056 +#define IDC_ZSHAREDCURRENT_V 1057 +#define IDC_ZSHAREDLIMIT_V 1058 +#define IDC_ZDEDICATEDCOMMITTED_V 1059 +#define IDC_ZRUNNINGTIME_V 1060 +#define IDC_ZCONTEXTSWITCHES_V 1061 +#define IDC_ZTOTALNODES_V 1062 +#define IDC_ZCACHEDALLOCATED_V 1063 +#define IDC_ZCACHEDRESERVED_V 1064 +#define IDC_ZSHAREDCOMMITTED_V 1065 +#define IDC_ZTOTALALLOCATED_V 1066 +#define IDC_ZTOTALRESERVED_V 1067 +#define IDC_ZWRITECOMBINEDALLOCATED_V 1068 +#define IDC_ZWRITECOMBINEDRESERVED_V 1069 +#define IDC_ZSECTIONALLOCATED_V 1070 +#define IDC_ZSECTIONRESERVED_V 1071 +#define IDC_ZTOTALSEGMENTS_V 1072 +#define IDC_TITLE 1073 +#define IDC_GRAPH_LAYOUT 1074 +#define IDC_LAYOUT 1075 +#define IDC_GPUNAME 1076 +#define IDC_GPU_L 1077 +#define IDC_DEDICATED_L 1078 +#define IDC_SHARED_L 1079 +#define IDC_ZRECEIVESDELTA_V 1080 +#define IDC_ZSENDSDELTA_V 1081 +#define IDC_ZWRITESDELTA_V 1082 +#define IDC_ZREADSDELTA_V 1083 +#define IDC_INSTRUCTION 1084 +#define IDC_PANEL_LAYOUT 1085 +#define IDC_RESTART 1086 +#define IDC_ERROR 1087 +#define IDC_GROUPDISK 1088 +#define IDC_GROUPNETWORK 1089 +#define IDC_GPUDETAILS 1090 +#define ID_DISK_GOTOPROCESS 40005 +#define ID_DISK_COPY 40006 +#define ID_DISK_PROPERTIES 40007 +#define ID_DISK_OPENFILELOCATION 40008 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 135 +#define _APS_NEXT_COMMAND_VALUE 40009 +#define _APS_NEXT_CONTROL_VALUE 1091 +#define _APS_NEXT_SYMED_VALUE 130 +#endif +#endif diff --git a/plugins/ExtendedTools/thrdact.c b/plugins/ExtendedTools/thrdact.c index bcbaef9d4e98..f30be0defb88 100644 --- a/plugins/ExtendedTools/thrdact.c +++ b/plugins/ExtendedTools/thrdact.c @@ -1,64 +1,64 @@ -/* - * Process Hacker Extended Tools - - * thread actions extensions - * - * Copyright (C) 2010 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include "exttools.h" - -BOOLEAN EtUiCancelIoThread( - _In_ HWND hWnd, - _In_ PPH_THREAD_ITEM Thread - ) -{ - NTSTATUS status; - BOOLEAN cont = FALSE; - HANDLE threadHandle; - IO_STATUS_BLOCK isb; - - if (!PhGetIntegerSetting(L"EnableWarnings") || PhShowConfirmMessage( - hWnd, - L"end", - L"I/O for the selected thread", - NULL, - FALSE - )) - cont = TRUE; - - if (!cont) - return FALSE; - - if (NT_SUCCESS(status = PhOpenThread(&threadHandle, THREAD_TERMINATE, Thread->ThreadId))) - { - status = NtCancelSynchronousIoFile(threadHandle, NULL, &isb); - } - - if (status == STATUS_NOT_FOUND) - { - PhShowInformation(hWnd, L"There is no synchronous I/O to cancel."); - return FALSE; - } - else if (!NT_SUCCESS(status)) - { - PhShowStatus(hWnd, L"Unable to cancel synchronous I/O", status, 0); - return FALSE; - } - - return TRUE; -} +/* + * Process Hacker Extended Tools - + * thread actions extensions + * + * Copyright (C) 2010 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include "exttools.h" + +BOOLEAN EtUiCancelIoThread( + _In_ HWND hWnd, + _In_ PPH_THREAD_ITEM Thread + ) +{ + NTSTATUS status; + BOOLEAN cont = FALSE; + HANDLE threadHandle; + IO_STATUS_BLOCK isb; + + if (!PhGetIntegerSetting(L"EnableWarnings") || PhShowConfirmMessage( + hWnd, + L"end", + L"I/O for the selected thread", + NULL, + FALSE + )) + cont = TRUE; + + if (!cont) + return FALSE; + + if (NT_SUCCESS(status = PhOpenThread(&threadHandle, THREAD_TERMINATE, Thread->ThreadId))) + { + status = NtCancelSynchronousIoFile(threadHandle, NULL, &isb); + } + + if (status == STATUS_NOT_FOUND) + { + PhShowInformation(hWnd, L"There is no synchronous I/O to cancel."); + return FALSE; + } + else if (!NT_SUCCESS(status)) + { + PhShowStatus(hWnd, L"Unable to cancel synchronous I/O", status, 0); + return FALSE; + } + + return TRUE; +} diff --git a/plugins/ExtendedTools/treeext.c b/plugins/ExtendedTools/treeext.c index 20a4cc0847c2..ac9a2e133b44 100644 --- a/plugins/ExtendedTools/treeext.c +++ b/plugins/ExtendedTools/treeext.c @@ -1,783 +1,783 @@ -/* - * Process Hacker Extended Tools - - * process and network tree support - * - * Copyright (C) 2011 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include "exttools.h" -#define CINTERFACE -#define COBJMACROS -#include - -LONG EtpProcessTreeNewSortFunction( - _In_ PVOID Node1, - _In_ PVOID Node2, - _In_ ULONG SubId, - _In_ PVOID Context - ); - -LONG EtpNetworkTreeNewSortFunction( - _In_ PVOID Node1, - _In_ PVOID Node2, - _In_ ULONG SubId, - _In_ PVOID Context - ); - -typedef struct _COLUMN_INFO -{ - ULONG SubId; - PWSTR Text; - ULONG Width; - ULONG Alignment; - ULONG TextFlags; - BOOLEAN SortDescending; -} COLUMN_INFO, *PCOLUMN_INFO; - -static ULONG ProcessTreeListSortColumn; -static PH_SORT_ORDER ProcessTreeListSortOrder; - -static GUID IID_INetFwMgr_I = { 0xf7898af5, 0xcac4, 0x4632, { 0xa2, 0xec, 0xda, 0x06, 0xe5, 0x11, 0x1a, 0xf2 } }; -static GUID CLSID_NetFwMgr_I = { 0x304ce942, 0x6e39, 0x40d8, { 0x94, 0x3a, 0xb9, 0x13, 0xc4, 0x0c, 0x9c, 0xd4 } }; - -VOID EtpAddTreeNewColumn( - _In_ PPH_PLUGIN_TREENEW_INFORMATION TreeNewInfo, - _In_ ULONG SubId, - _In_ PWSTR Text, - _In_ ULONG Width, - _In_ ULONG Alignment, - _In_ ULONG TextFlags, - _In_ BOOLEAN SortDescending, - _In_ PPH_PLUGIN_TREENEW_SORT_FUNCTION SortFunction - ) -{ - PH_TREENEW_COLUMN column; - - memset(&column, 0, sizeof(PH_TREENEW_COLUMN)); - column.SortDescending = SortDescending; - column.Text = Text; - column.Width = Width; - column.Alignment = Alignment; - column.TextFlags = TextFlags; - - PhPluginAddTreeNewColumn( - PluginInstance, - TreeNewInfo->CmData, - &column, - SubId, - NULL, - SortFunction - ); -} - -VOID EtProcessTreeNewInitializing( - _In_ PVOID Parameter - ) -{ - static COLUMN_INFO columns[] = - { - { ETPRTNC_DISKREADS, L"Disk reads", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE }, - { ETPRTNC_DISKWRITES, L"Disk writes", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE }, - { ETPRTNC_DISKREADBYTES, L"Disk read bytes", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE }, - { ETPRTNC_DISKWRITEBYTES, L"Disk write bytes", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE }, - { ETPRTNC_DISKTOTALBYTES, L"Disk total bytes", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE }, - { ETPRTNC_DISKREADSDELTA, L"Disk reads delta", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE }, - { ETPRTNC_DISKWRITESDELTA, L"Disk writes delta", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE }, - { ETPRTNC_DISKREADBYTESDELTA, L"Disk read bytes delta", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE }, - { ETPRTNC_DISKWRITEBYTESDELTA, L"Disk write bytes delta", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE }, - { ETPRTNC_DISKTOTALBYTESDELTA, L"Disk total bytes delta", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE }, - { ETPRTNC_NETWORKRECEIVES, L"Network receives", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE }, - { ETPRTNC_NETWORKSENDS, L"Network sends", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE }, - { ETPRTNC_NETWORKRECEIVEBYTES, L"Network receive bytes", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE }, - { ETPRTNC_NETWORKSENDBYTES, L"Network send bytes", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE }, - { ETPRTNC_NETWORKTOTALBYTES, L"Network total bytes", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE }, - { ETPRTNC_NETWORKRECEIVESDELTA, L"Network receives delta", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE }, - { ETPRTNC_NETWORKSENDSDELTA, L"Network sends delta", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE }, - { ETPRTNC_NETWORKRECEIVEBYTESDELTA, L"Network receive bytes delta", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE }, - { ETPRTNC_NETWORKSENDBYTESDELTA, L"Network send bytes delta", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE }, - { ETPRTNC_NETWORKTOTALBYTESDELTA, L"Network total bytes delta", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE }, - { ETPRTNC_HARDFAULTS, L"Hard faults", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE }, - { ETPRTNC_HARDFAULTSDELTA, L"Hard faults delta", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE }, - { ETPRTNC_PEAKTHREADS, L"Peak threads", 45, PH_ALIGN_RIGHT, DT_RIGHT, TRUE }, - { ETPRTNC_GPU, L"GPU", 45, PH_ALIGN_RIGHT, DT_RIGHT, TRUE }, - { ETPRTNC_GPUDEDICATEDBYTES, L"GPU dedicated bytes", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE }, - { ETPRTNC_GPUSHAREDBYTES, L"GPU shared bytes", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE }, - { ETPRTNC_DISKREADRATE, L"Disk read rate", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE }, - { ETPRTNC_DISKWRITERATE, L"Disk write rate", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE }, - { ETPRTNC_DISKTOTALRATE, L"Disk total rate", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE }, - { ETPRTNC_NETWORKRECEIVERATE, L"Network receive rate", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE }, - { ETPRTNC_NETWORKSENDRATE, L"Network send rate", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE }, - { ETPRTNC_NETWORKTOTALRATE, L"Network total rate", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE } - }; - - PPH_PLUGIN_TREENEW_INFORMATION treeNewInfo = Parameter; - ULONG i; - - for (i = 0; i < sizeof(columns) / sizeof(COLUMN_INFO); i++) - { - EtpAddTreeNewColumn(treeNewInfo, columns[i].SubId, columns[i].Text, columns[i].Width, columns[i].Alignment, - columns[i].TextFlags, columns[i].SortDescending, EtpProcessTreeNewSortFunction); - } - - PhPluginEnableTreeNewNotify(PluginInstance, treeNewInfo->CmData); -} - -FLOAT EtpCalculateInclusiveGpuUsage( - _In_ PPH_PROCESS_NODE ProcessNode - ) -{ - FLOAT gpuUsage; - ULONG i; - - gpuUsage = EtGetProcessBlock(ProcessNode->ProcessItem)->GpuNodeUsage; - - for (i = 0; i < ProcessNode->Children->Count; i++) - { - gpuUsage += EtpCalculateInclusiveGpuUsage(ProcessNode->Children->Items[i]); - } - - return gpuUsage; -} - -VOID EtProcessTreeNewMessage( - _In_ PVOID Parameter - ) -{ - PPH_PLUGIN_TREENEW_MESSAGE message = Parameter; - PPH_PROCESS_NODE processNode; - PET_PROCESS_BLOCK block; - - if (message->Message == TreeNewGetCellText) - { - PPH_TREENEW_GET_CELL_TEXT getCellText = message->Parameter1; - PPH_STRING text; - - processNode = (PPH_PROCESS_NODE)getCellText->Node; - block = EtGetProcessBlock(processNode->ProcessItem); - - PhAcquireQueuedLockExclusive(&block->TextCacheLock); - - if (block->TextCacheValid[message->SubId]) - { - if (block->TextCache[message->SubId]) - getCellText->Text = block->TextCache[message->SubId]->sr; - } - else - { - text = NULL; - - switch (message->SubId) - { - case ETPRTNC_DISKREADS: - if (block->DiskReadCount != 0) - text = PhFormatUInt64(block->DiskReadCount, TRUE); - break; - case ETPRTNC_DISKWRITES: - if (block->DiskWriteCount != 0) - text = PhFormatUInt64(block->DiskWriteCount, TRUE); - break; - case ETPRTNC_DISKREADBYTES: - if (block->DiskReadRaw != 0) - text = PhFormatSize(block->DiskReadRaw, -1); - break; - case ETPRTNC_DISKWRITEBYTES: - if (block->DiskWriteRaw != 0) - text = PhFormatSize(block->DiskWriteRaw, -1); - break; - case ETPRTNC_DISKTOTALBYTES: - if (block->DiskReadRaw + block->DiskWriteRaw != 0) - text = PhFormatSize(block->DiskReadRaw + block->DiskWriteRaw, -1); - break; - case ETPRTNC_DISKREADSDELTA: - if (block->DiskReadDelta.Delta != 0) - text = PhFormatUInt64(block->DiskReadDelta.Delta, TRUE); - break; - case ETPRTNC_DISKWRITESDELTA: - if (block->DiskWriteDelta.Delta != 0) - text = PhFormatUInt64(block->DiskWriteDelta.Delta, TRUE); - break; - case ETPRTNC_DISKREADBYTESDELTA: - if (block->DiskReadRawDelta.Delta != 0) - text = PhFormatSize(block->DiskReadRawDelta.Delta, -1); - break; - case ETPRTNC_DISKWRITEBYTESDELTA: - if (block->DiskWriteRawDelta.Delta != 0) - text = PhFormatSize(block->DiskWriteRawDelta.Delta, -1); - break; - case ETPRTNC_DISKTOTALBYTESDELTA: - if (block->DiskReadRawDelta.Delta + block->DiskWriteRawDelta.Delta != 0) - text = PhFormatSize(block->DiskReadRawDelta.Delta + block->DiskWriteRawDelta.Delta, -1); - break; - case ETPRTNC_NETWORKRECEIVES: - if (block->NetworkReceiveCount != 0) - text = PhFormatUInt64(block->NetworkReceiveCount, TRUE); - break; - case ETPRTNC_NETWORKSENDS: - if (block->NetworkSendCount != 0) - text = PhFormatUInt64(block->NetworkSendCount, TRUE); - break; - case ETPRTNC_NETWORKRECEIVEBYTES: - if (block->NetworkReceiveRaw != 0) - text = PhFormatSize(block->NetworkReceiveRaw, -1); - break; - case ETPRTNC_NETWORKSENDBYTES: - if (block->NetworkSendRaw != 0) - text = PhFormatSize(block->NetworkSendRaw, -1); - break; - case ETPRTNC_NETWORKTOTALBYTES: - if (block->NetworkReceiveRaw + block->NetworkSendRaw != 0) - text = PhFormatSize(block->NetworkReceiveRaw + block->NetworkSendRaw, -1); - break; - case ETPRTNC_NETWORKRECEIVESDELTA: - if (block->NetworkReceiveDelta.Delta != 0) - text = PhFormatUInt64(block->NetworkReceiveDelta.Delta, TRUE); - break; - case ETPRTNC_NETWORKSENDSDELTA: - if (block->NetworkSendDelta.Delta != 0) - text = PhFormatUInt64(block->NetworkSendDelta.Delta, TRUE); - break; - case ETPRTNC_NETWORKRECEIVEBYTESDELTA: - if (block->NetworkReceiveRawDelta.Delta != 0) - text = PhFormatSize(block->NetworkReceiveRawDelta.Delta, -1); - break; - case ETPRTNC_NETWORKSENDBYTESDELTA: - if (block->NetworkSendRawDelta.Delta != 0) - text = PhFormatSize(block->NetworkSendRawDelta.Delta, -1); - break; - case ETPRTNC_NETWORKTOTALBYTESDELTA: - if (block->NetworkReceiveRawDelta.Delta + block->NetworkSendRawDelta.Delta != 0) - text = PhFormatSize(block->NetworkReceiveRawDelta.Delta + block->NetworkSendRawDelta.Delta, -1); - break; - case ETPRTNC_HARDFAULTS: - text = PhFormatUInt64(block->HardFaultsDelta.Value, TRUE); - break; - case ETPRTNC_HARDFAULTSDELTA: - if (block->HardFaultsDelta.Delta != 0) - text = PhFormatUInt64(block->HardFaultsDelta.Delta, TRUE); - break; - case ETPRTNC_PEAKTHREADS: - text = PhFormatUInt64(block->ProcessItem->PeakNumberOfThreads, TRUE); - break; - case ETPRTNC_GPU: - { - FLOAT gpuUsage; - - if (!PhGetIntegerSetting(L"PropagateCpuUsage") || processNode->Node.Expanded || ProcessTreeListSortOrder != NoSortOrder) - { - gpuUsage = block->GpuNodeUsage * 100; - } - else - { - gpuUsage = EtpCalculateInclusiveGpuUsage(processNode) * 100; - } - - if (gpuUsage >= 0.01) - { - PH_FORMAT format; - - PhInitFormatF(&format, gpuUsage, 2); - text = PhFormat(&format, 1, 0); - } - } - break; - case ETPRTNC_GPUDEDICATEDBYTES: - if (block->GpuDedicatedUsage != 0) - text = PhFormatSize(block->GpuDedicatedUsage, -1); - break; - case ETPRTNC_GPUSHAREDBYTES: - if (block->GpuSharedUsage != 0) - text = PhFormatSize(block->GpuSharedUsage, -1); - break; - case ETPRTNC_DISKREADRATE: - if (block->DiskReadRawDelta.Delta != 0) - EtFormatRate(block->DiskReadRawDelta.Delta, &text, NULL); - break; - case ETPRTNC_DISKWRITERATE: - if (block->DiskWriteRawDelta.Delta != 0) - EtFormatRate(block->DiskWriteRawDelta.Delta, &text, NULL); - break; - case ETPRTNC_DISKTOTALRATE: - if (block->DiskReadRawDelta.Delta + block->DiskWriteRawDelta.Delta != 0) - EtFormatRate(block->DiskReadRawDelta.Delta + block->DiskWriteRawDelta.Delta, &text, NULL); - break; - case ETPRTNC_NETWORKRECEIVERATE: - if (block->NetworkReceiveRawDelta.Delta != 0) - EtFormatRate(block->NetworkReceiveRawDelta.Delta, &text, NULL); - break; - case ETPRTNC_NETWORKSENDRATE: - if (block->NetworkSendRawDelta.Delta != 0) - EtFormatRate(block->NetworkSendRawDelta.Delta, &text, NULL); - break; - case ETPRTNC_NETWORKTOTALRATE: - if (block->NetworkReceiveRawDelta.Delta + block->NetworkSendRawDelta.Delta != 0) - EtFormatRate(block->NetworkReceiveRawDelta.Delta + block->NetworkSendRawDelta.Delta, &text, NULL); - break; - } - - if (text) - { - getCellText->Text = text->sr; - } - - PhMoveReference(&block->TextCache[message->SubId], text); - block->TextCacheValid[message->SubId] = TRUE; - } - - PhReleaseQueuedLockExclusive(&block->TextCacheLock); - } - else if (message->Message == TreeNewSortChanged) - { - TreeNew_GetSort(message->TreeNewHandle, &ProcessTreeListSortColumn, &ProcessTreeListSortOrder); - } - else if (message->Message == TreeNewNodeExpanding) - { - processNode = message->Parameter1; - block = EtGetProcessBlock(processNode->ProcessItem); - - if (PhGetIntegerSetting(L"PropagateCpuUsage")) - block->TextCacheValid[ETPRTNC_GPU] = FALSE; - } -} - -LONG EtpProcessTreeNewSortFunction( - _In_ PVOID Node1, - _In_ PVOID Node2, - _In_ ULONG SubId, - _In_ PVOID Context - ) -{ - LONG result; - PPH_PROCESS_NODE node1 = Node1; - PPH_PROCESS_NODE node2 = Node2; - PET_PROCESS_BLOCK block1; - PET_PROCESS_BLOCK block2; - - block1 = EtGetProcessBlock(node1->ProcessItem); - block2 = EtGetProcessBlock(node2->ProcessItem); - - result = 0; - - switch (SubId) - { - case ETPRTNC_DISKREADS: - result = uint64cmp(block1->DiskReadCount, block2->DiskReadCount); - break; - case ETPRTNC_DISKWRITES: - result = uint64cmp(block1->DiskWriteCount, block2->DiskWriteCount); - break; - case ETPRTNC_DISKREADBYTES: - result = uint64cmp(block1->DiskReadRaw, block2->DiskReadRaw); - break; - case ETPRTNC_DISKWRITEBYTES: - result = uint64cmp(block1->DiskWriteRaw, block2->DiskWriteRaw); - break; - case ETPRTNC_DISKTOTALBYTES: - result = uint64cmp(block1->DiskReadRaw + block1->DiskWriteRaw, block2->DiskReadRaw + block2->DiskWriteRaw); - break; - case ETPRTNC_DISKREADSDELTA: - result = uint64cmp(block1->DiskReadDelta.Delta, block2->DiskReadDelta.Delta); - break; - case ETPRTNC_DISKWRITESDELTA: - result = uint64cmp(block1->DiskWriteDelta.Delta, block2->DiskWriteDelta.Delta); - break; - case ETPRTNC_DISKREADBYTESDELTA: - result = uint64cmp(block1->DiskReadRawDelta.Delta, block2->DiskReadRawDelta.Delta); - break; - case ETPRTNC_DISKWRITEBYTESDELTA: - result = uint64cmp(block1->DiskWriteRawDelta.Delta, block2->DiskWriteRawDelta.Delta); - break; - case ETPRTNC_DISKTOTALBYTESDELTA: - result = uint64cmp(block1->DiskReadRawDelta.Delta + block1->DiskWriteRawDelta.Delta, block2->DiskReadRawDelta.Delta + block2->DiskWriteRawDelta.Delta); - break; - case ETPRTNC_NETWORKRECEIVES: - result = uint64cmp(block1->NetworkReceiveCount, block2->NetworkReceiveCount); - break; - case ETPRTNC_NETWORKSENDS: - result = uint64cmp(block1->NetworkSendCount, block2->NetworkSendCount); - break; - case ETPRTNC_NETWORKRECEIVEBYTES: - result = uint64cmp(block1->NetworkReceiveRaw, block2->NetworkReceiveRaw); - break; - case ETPRTNC_NETWORKSENDBYTES: - result = uint64cmp(block1->NetworkSendRaw, block2->NetworkSendRaw); - break; - case ETPRTNC_NETWORKTOTALBYTES: - result = uint64cmp(block1->NetworkReceiveRaw + block1->NetworkSendRaw, block2->NetworkReceiveRaw + block2->NetworkSendRaw); - break; - case ETPRTNC_NETWORKRECEIVESDELTA: - result = uint64cmp(block1->NetworkReceiveDelta.Delta, block2->NetworkReceiveDelta.Delta); - break; - case ETPRTNC_NETWORKSENDSDELTA: - result = uint64cmp(block1->NetworkSendDelta.Delta, block2->NetworkSendDelta.Delta); - break; - case ETPRTNC_NETWORKRECEIVEBYTESDELTA: - result = uint64cmp(block1->NetworkReceiveRawDelta.Delta, block2->NetworkReceiveRawDelta.Delta); - break; - case ETPRTNC_NETWORKSENDBYTESDELTA: - result = uint64cmp(block1->NetworkSendRawDelta.Delta, block2->NetworkSendRawDelta.Delta); - break; - case ETPRTNC_NETWORKTOTALBYTESDELTA: - result = uint64cmp(block1->NetworkReceiveRawDelta.Delta + block1->NetworkSendRawDelta.Delta, block2->NetworkReceiveRawDelta.Delta + block2->NetworkSendRawDelta.Delta); - break; - case ETPRTNC_HARDFAULTS: - result = uintcmp(block1->HardFaultsDelta.Value, block2->HardFaultsDelta.Value); - break; - case ETPRTNC_HARDFAULTSDELTA: - result = uintcmp(block1->HardFaultsDelta.Delta, block2->HardFaultsDelta.Delta); - break; - case ETPRTNC_PEAKTHREADS: - result = uintcmp(block1->ProcessItem->PeakNumberOfThreads, block2->ProcessItem->PeakNumberOfThreads); - break; - case ETPRTNC_GPU: - result = singlecmp(block1->GpuNodeUsage, block2->GpuNodeUsage); - break; - case ETPRTNC_GPUDEDICATEDBYTES: - result = uint64cmp(block1->GpuDedicatedUsage, block2->GpuDedicatedUsage); - break; - case ETPRTNC_GPUSHAREDBYTES: - result = uint64cmp(block1->GpuSharedUsage, block2->GpuSharedUsage); - break; - case ETPRTNC_DISKREADRATE: - result = uint64cmp(block1->DiskReadRawDelta.Delta, block2->DiskReadRawDelta.Delta); - break; - case ETPRTNC_DISKWRITERATE: - result = uint64cmp(block1->DiskWriteRawDelta.Delta, block2->DiskWriteRawDelta.Delta); - break; - case ETPRTNC_DISKTOTALRATE: - result = uint64cmp(block1->DiskReadRawDelta.Delta + block1->DiskWriteRawDelta.Delta, block2->DiskReadRawDelta.Delta + block2->DiskWriteRawDelta.Delta); - break; - case ETPRTNC_NETWORKRECEIVERATE: - result = uint64cmp(block1->NetworkReceiveRawDelta.Delta, block2->NetworkReceiveRawDelta.Delta); - break; - case ETPRTNC_NETWORKSENDRATE: - result = uint64cmp(block1->NetworkSendRawDelta.Delta, block2->NetworkSendRawDelta.Delta); - break; - case ETPRTNC_NETWORKTOTALRATE: - result = uint64cmp(block1->NetworkReceiveRawDelta.Delta + block1->NetworkSendRawDelta.Delta, block2->NetworkReceiveRawDelta.Delta + block2->NetworkSendRawDelta.Delta); - break; - } - - return result; -} - -VOID EtNetworkTreeNewInitializing( - _In_ PVOID Parameter - ) -{ - static COLUMN_INFO columns[] = - { - { ETNETNC_RECEIVES, L"Receives", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE }, - { ETNETNC_SENDS, L"Sends", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE }, - { ETNETNC_RECEIVEBYTES, L"Receive bytes", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE }, - { ETNETNC_SENDBYTES, L"Send bytes", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE }, - { ETNETNC_TOTALBYTES, L"Total bytes", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE }, - { ETNETNC_RECEIVESDELTA, L"Receives delta", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE }, - { ETNETNC_SENDSDELTA, L"Sends delta", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE }, - { ETNETNC_RECEIVEBYTESDELTA, L"Receive bytes delta", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE }, - { ETNETNC_SENDBYTESDELTA, L"Send bytes delta", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE }, - { ETNETNC_TOTALBYTESDELTA, L"Total bytes delta", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE }, - { ETNETNC_FIREWALLSTATUS, L"Firewall status", 170, PH_ALIGN_LEFT, 0, FALSE }, - { ETNETNC_RECEIVERATE, L"Receive rate", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE }, - { ETNETNC_SENDRATE, L"Send rate", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE }, - { ETNETNC_TOTALRATE, L"Total rate", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE } - }; - - PPH_PLUGIN_TREENEW_INFORMATION treeNewInfo = Parameter; - ULONG i; - - for (i = 0; i < sizeof(columns) / sizeof(COLUMN_INFO); i++) - { - EtpAddTreeNewColumn(treeNewInfo, columns[i].SubId, columns[i].Text, columns[i].Width, columns[i].Alignment, - columns[i].TextFlags, columns[i].SortDescending, EtpNetworkTreeNewSortFunction); - } -} - -VOID EtpUpdateFirewallStatus( - _Inout_ PET_NETWORK_BLOCK Block - ) -{ - if (!Block->FirewallStatusValid) - { - Block->FirewallStatus = EtQueryFirewallStatus(Block->NetworkItem); - Block->FirewallStatusValid = TRUE; - } -} - -VOID EtNetworkTreeNewMessage( - _In_ PVOID Parameter - ) -{ - PPH_PLUGIN_TREENEW_MESSAGE message = Parameter; - - if (message->Message == TreeNewGetCellText) - { - PPH_TREENEW_GET_CELL_TEXT getCellText = message->Parameter1; - PPH_NETWORK_NODE networkNode = (PPH_NETWORK_NODE)getCellText->Node; - PET_NETWORK_BLOCK block; - PPH_STRING text; - - block = EtGetNetworkBlock(networkNode->NetworkItem); - - PhAcquireQueuedLockExclusive(&block->TextCacheLock); - - if (block->TextCacheValid[message->SubId]) - { - if (block->TextCache[message->SubId]) - getCellText->Text = block->TextCache[message->SubId]->sr; - } - else - { - text = NULL; - - switch (message->SubId) - { - case ETNETNC_RECEIVES: - if (block->ReceiveCount != 0) - text = PhFormatUInt64(block->ReceiveCount, TRUE); - break; - case ETNETNC_SENDS: - if (block->SendCount != 0) - text = PhFormatUInt64(block->SendCount, TRUE); - break; - case ETNETNC_RECEIVEBYTES: - if (block->ReceiveRaw != 0) - text = PhFormatSize(block->ReceiveRaw, -1); - break; - case ETNETNC_SENDBYTES: - if (block->SendRaw != 0) - text = PhFormatSize(block->SendRaw, -1); - break; - case ETNETNC_TOTALBYTES: - if (block->ReceiveRaw + block->SendRaw != 0) - text = PhFormatSize(block->ReceiveRaw + block->SendRaw, -1); - break; - case ETNETNC_RECEIVESDELTA: - if (block->ReceiveDelta.Delta != 0) - text = PhFormatUInt64(block->ReceiveDelta.Delta, TRUE); - break; - case ETNETNC_SENDSDELTA: - if (block->SendDelta.Delta != 0) - text = PhFormatUInt64(block->SendDelta.Delta, TRUE); - break; - case ETNETNC_RECEIVEBYTESDELTA: - if (block->ReceiveRawDelta.Delta != 0) - text = PhFormatSize(block->ReceiveRawDelta.Delta, -1); - break; - case ETNETNC_SENDBYTESDELTA: - if (block->SendRawDelta.Delta != 0) - text = PhFormatSize(block->SendRawDelta.Delta, -1); - break; - case ETNETNC_TOTALBYTESDELTA: - if (block->ReceiveRawDelta.Delta + block->SendRawDelta.Delta != 0) - text = PhFormatSize(block->ReceiveRawDelta.Delta + block->SendRawDelta.Delta, -1); - break; - case ETNETNC_FIREWALLSTATUS: - { - static PPH_STRING strings[FirewallMaximumStatus]; - static PH_INITONCE initOnce = PH_INITONCE_INIT; - - if (PhBeginInitOnce(&initOnce)) - { - strings[FirewallUnknownStatus] = NULL; - strings[FirewallAllowedNotRestricted] = PhCreateString(L"Allowed, not restricted"); - strings[FirewallAllowedRestricted] = PhCreateString(L"Allowed, restricted"); - strings[FirewallNotAllowedNotRestricted] = PhCreateString(L"Not allowed, not restricted"); - strings[FirewallNotAllowedRestricted] = PhCreateString(L"Not allowed, restricted"); - PhEndInitOnce(&initOnce); - } - - EtpUpdateFirewallStatus(block); - - if (block->FirewallStatus < FirewallMaximumStatus) - PhSetReference(&text, strings[block->FirewallStatus]); - } - break; - case ETNETNC_RECEIVERATE: - if (block->ReceiveRawDelta.Delta != 0) - EtFormatRate(block->ReceiveRawDelta.Delta, &text, NULL); - break; - case ETNETNC_SENDRATE: - if (block->SendRawDelta.Delta != 0) - EtFormatRate(block->SendRawDelta.Delta, &text, NULL); - break; - case ETNETNC_TOTALRATE: - if (block->ReceiveRawDelta.Delta + block->SendRawDelta.Delta != 0) - EtFormatRate(block->ReceiveRawDelta.Delta + block->SendRawDelta.Delta, &text, NULL); - break; - } - - if (text) - { - getCellText->Text = text->sr; - } - - PhMoveReference(&block->TextCache[message->SubId], text); - block->TextCacheValid[message->SubId] = TRUE; - } - - PhReleaseQueuedLockExclusive(&block->TextCacheLock); - } -} - -LONG EtpNetworkTreeNewSortFunction( - _In_ PVOID Node1, - _In_ PVOID Node2, - _In_ ULONG SubId, - _In_ PVOID Context - ) -{ - LONG result; - PPH_NETWORK_NODE node1 = Node1; - PPH_NETWORK_NODE node2 = Node2; - PET_NETWORK_BLOCK block1; - PET_NETWORK_BLOCK block2; - - block1 = EtGetNetworkBlock(node1->NetworkItem); - block2 = EtGetNetworkBlock(node2->NetworkItem); - - result = 0; - - switch (SubId) - { - case ETNETNC_RECEIVES: - result = uint64cmp(block1->ReceiveCount, block2->ReceiveCount); - break; - case ETNETNC_SENDS: - result = uint64cmp(block1->SendCount, block2->SendCount); - break; - case ETNETNC_RECEIVEBYTES: - result = uint64cmp(block1->ReceiveRaw, block2->ReceiveRaw); - break; - case ETNETNC_SENDBYTES: - result = uint64cmp(block1->SendRaw, block2->SendRaw); - break; - case ETNETNC_TOTALBYTES: - result = uint64cmp(block1->ReceiveRaw + block1->SendRaw, block2->ReceiveRaw + block2->SendRaw); - break; - case ETNETNC_RECEIVESDELTA: - result = uint64cmp(block1->ReceiveDelta.Delta, block2->ReceiveDelta.Delta); - break; - case ETNETNC_SENDSDELTA: - result = uint64cmp(block1->SendDelta.Delta, block2->SendDelta.Delta); - break; - case ETNETNC_RECEIVEBYTESDELTA: - result = uint64cmp(block1->ReceiveRawDelta.Delta, block2->ReceiveRawDelta.Delta); - break; - case ETNETNC_SENDBYTESDELTA: - result = uint64cmp(block1->SendRawDelta.Delta, block2->SendRawDelta.Delta); - break; - case ETNETNC_TOTALBYTESDELTA: - result = uint64cmp(block1->ReceiveRawDelta.Delta + block1->SendRawDelta.Delta, block2->ReceiveRawDelta.Delta + block2->SendRawDelta.Delta); - break; - case ETNETNC_FIREWALLSTATUS: - EtpUpdateFirewallStatus(block1); - EtpUpdateFirewallStatus(block2); - result = intcmp(block1->FirewallStatus, block2->FirewallStatus); - break; - case ETNETNC_RECEIVERATE: - result = uint64cmp(block1->ReceiveRawDelta.Delta, block2->ReceiveRawDelta.Delta); - break; - case ETNETNC_SENDRATE: - result = uint64cmp(block1->SendRawDelta.Delta, block2->SendRawDelta.Delta); - break; - case ETNETNC_TOTALRATE: - result = uint64cmp(block1->ReceiveRawDelta.Delta + block1->SendRawDelta.Delta, block2->ReceiveRawDelta.Delta + block2->SendRawDelta.Delta); - break; - } - - return result; -} - -ET_FIREWALL_STATUS EtQueryFirewallStatus( - _In_ PPH_NETWORK_ITEM NetworkItem - ) -{ - static INetFwMgr* manager = NULL; - ET_FIREWALL_STATUS result; - PPH_PROCESS_ITEM processItem; - BSTR imageFileNameBStr; - BSTR localAddressBStr; - VARIANT allowed; - VARIANT restricted; - - if (!manager) - { - if (!SUCCEEDED(CoCreateInstance(&CLSID_NetFwMgr_I, NULL, CLSCTX_INPROC_SERVER, &IID_INetFwMgr_I, &manager))) - return FirewallUnknownStatus; - - if (!manager) - return FirewallUnknownStatus; - } - - processItem = PhReferenceProcessItem(NetworkItem->ProcessId); - - if (!processItem) - return FirewallUnknownStatus; - - if (!processItem->FileName) - { - PhDereferenceObject(processItem); - return FirewallUnknownStatus; - } - - result = FirewallUnknownStatus; - - if (imageFileNameBStr = SysAllocStringLen(processItem->FileName->Buffer, (ULONG)processItem->FileName->Length / sizeof(WCHAR))) - { - localAddressBStr = NULL; - - if (!PhIsNullIpAddress(&NetworkItem->LocalEndpoint.Address)) - localAddressBStr = SysAllocString(NetworkItem->LocalAddressString); - - if (SUCCEEDED(INetFwMgr_IsPortAllowed( - manager, - imageFileNameBStr, - (NetworkItem->ProtocolType & PH_IPV6_NETWORK_TYPE) ? NET_FW_IP_VERSION_V6 : NET_FW_IP_VERSION_V4, - NetworkItem->LocalEndpoint.Port, - localAddressBStr, - (NetworkItem->ProtocolType & PH_UDP_PROTOCOL_TYPE) ? NET_FW_IP_PROTOCOL_UDP : NET_FW_IP_PROTOCOL_TCP, - &allowed, - &restricted - ))) - { - if (allowed.boolVal) - { - if (restricted.boolVal) - result = FirewallAllowedRestricted; - else - result = FirewallAllowedNotRestricted; - } - else - { - if (restricted.boolVal) - result = FirewallNotAllowedRestricted; - else - result = FirewallNotAllowedNotRestricted; - } - } - - if (localAddressBStr) - SysFreeString(localAddressBStr); - - SysFreeString(imageFileNameBStr); - } - - PhDereferenceObject(processItem); - - return result; -} +/* + * Process Hacker Extended Tools - + * process and network tree support + * + * Copyright (C) 2011 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include "exttools.h" +#define CINTERFACE +#define COBJMACROS +#include + +LONG EtpProcessTreeNewSortFunction( + _In_ PVOID Node1, + _In_ PVOID Node2, + _In_ ULONG SubId, + _In_ PVOID Context + ); + +LONG EtpNetworkTreeNewSortFunction( + _In_ PVOID Node1, + _In_ PVOID Node2, + _In_ ULONG SubId, + _In_ PVOID Context + ); + +typedef struct _COLUMN_INFO +{ + ULONG SubId; + PWSTR Text; + ULONG Width; + ULONG Alignment; + ULONG TextFlags; + BOOLEAN SortDescending; +} COLUMN_INFO, *PCOLUMN_INFO; + +static ULONG ProcessTreeListSortColumn; +static PH_SORT_ORDER ProcessTreeListSortOrder; + +static GUID IID_INetFwMgr_I = { 0xf7898af5, 0xcac4, 0x4632, { 0xa2, 0xec, 0xda, 0x06, 0xe5, 0x11, 0x1a, 0xf2 } }; +static GUID CLSID_NetFwMgr_I = { 0x304ce942, 0x6e39, 0x40d8, { 0x94, 0x3a, 0xb9, 0x13, 0xc4, 0x0c, 0x9c, 0xd4 } }; + +VOID EtpAddTreeNewColumn( + _In_ PPH_PLUGIN_TREENEW_INFORMATION TreeNewInfo, + _In_ ULONG SubId, + _In_ PWSTR Text, + _In_ ULONG Width, + _In_ ULONG Alignment, + _In_ ULONG TextFlags, + _In_ BOOLEAN SortDescending, + _In_ PPH_PLUGIN_TREENEW_SORT_FUNCTION SortFunction + ) +{ + PH_TREENEW_COLUMN column; + + memset(&column, 0, sizeof(PH_TREENEW_COLUMN)); + column.SortDescending = SortDescending; + column.Text = Text; + column.Width = Width; + column.Alignment = Alignment; + column.TextFlags = TextFlags; + + PhPluginAddTreeNewColumn( + PluginInstance, + TreeNewInfo->CmData, + &column, + SubId, + NULL, + SortFunction + ); +} + +VOID EtProcessTreeNewInitializing( + _In_ PVOID Parameter + ) +{ + static COLUMN_INFO columns[] = + { + { ETPRTNC_DISKREADS, L"Disk reads", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE }, + { ETPRTNC_DISKWRITES, L"Disk writes", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE }, + { ETPRTNC_DISKREADBYTES, L"Disk read bytes", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE }, + { ETPRTNC_DISKWRITEBYTES, L"Disk write bytes", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE }, + { ETPRTNC_DISKTOTALBYTES, L"Disk total bytes", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE }, + { ETPRTNC_DISKREADSDELTA, L"Disk reads delta", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE }, + { ETPRTNC_DISKWRITESDELTA, L"Disk writes delta", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE }, + { ETPRTNC_DISKREADBYTESDELTA, L"Disk read bytes delta", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE }, + { ETPRTNC_DISKWRITEBYTESDELTA, L"Disk write bytes delta", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE }, + { ETPRTNC_DISKTOTALBYTESDELTA, L"Disk total bytes delta", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE }, + { ETPRTNC_NETWORKRECEIVES, L"Network receives", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE }, + { ETPRTNC_NETWORKSENDS, L"Network sends", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE }, + { ETPRTNC_NETWORKRECEIVEBYTES, L"Network receive bytes", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE }, + { ETPRTNC_NETWORKSENDBYTES, L"Network send bytes", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE }, + { ETPRTNC_NETWORKTOTALBYTES, L"Network total bytes", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE }, + { ETPRTNC_NETWORKRECEIVESDELTA, L"Network receives delta", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE }, + { ETPRTNC_NETWORKSENDSDELTA, L"Network sends delta", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE }, + { ETPRTNC_NETWORKRECEIVEBYTESDELTA, L"Network receive bytes delta", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE }, + { ETPRTNC_NETWORKSENDBYTESDELTA, L"Network send bytes delta", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE }, + { ETPRTNC_NETWORKTOTALBYTESDELTA, L"Network total bytes delta", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE }, + { ETPRTNC_HARDFAULTS, L"Hard faults", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE }, + { ETPRTNC_HARDFAULTSDELTA, L"Hard faults delta", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE }, + { ETPRTNC_PEAKTHREADS, L"Peak threads", 45, PH_ALIGN_RIGHT, DT_RIGHT, TRUE }, + { ETPRTNC_GPU, L"GPU", 45, PH_ALIGN_RIGHT, DT_RIGHT, TRUE }, + { ETPRTNC_GPUDEDICATEDBYTES, L"GPU dedicated bytes", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE }, + { ETPRTNC_GPUSHAREDBYTES, L"GPU shared bytes", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE }, + { ETPRTNC_DISKREADRATE, L"Disk read rate", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE }, + { ETPRTNC_DISKWRITERATE, L"Disk write rate", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE }, + { ETPRTNC_DISKTOTALRATE, L"Disk total rate", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE }, + { ETPRTNC_NETWORKRECEIVERATE, L"Network receive rate", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE }, + { ETPRTNC_NETWORKSENDRATE, L"Network send rate", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE }, + { ETPRTNC_NETWORKTOTALRATE, L"Network total rate", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE } + }; + + PPH_PLUGIN_TREENEW_INFORMATION treeNewInfo = Parameter; + ULONG i; + + for (i = 0; i < sizeof(columns) / sizeof(COLUMN_INFO); i++) + { + EtpAddTreeNewColumn(treeNewInfo, columns[i].SubId, columns[i].Text, columns[i].Width, columns[i].Alignment, + columns[i].TextFlags, columns[i].SortDescending, EtpProcessTreeNewSortFunction); + } + + PhPluginEnableTreeNewNotify(PluginInstance, treeNewInfo->CmData); +} + +FLOAT EtpCalculateInclusiveGpuUsage( + _In_ PPH_PROCESS_NODE ProcessNode + ) +{ + FLOAT gpuUsage; + ULONG i; + + gpuUsage = EtGetProcessBlock(ProcessNode->ProcessItem)->GpuNodeUsage; + + for (i = 0; i < ProcessNode->Children->Count; i++) + { + gpuUsage += EtpCalculateInclusiveGpuUsage(ProcessNode->Children->Items[i]); + } + + return gpuUsage; +} + +VOID EtProcessTreeNewMessage( + _In_ PVOID Parameter + ) +{ + PPH_PLUGIN_TREENEW_MESSAGE message = Parameter; + PPH_PROCESS_NODE processNode; + PET_PROCESS_BLOCK block; + + if (message->Message == TreeNewGetCellText) + { + PPH_TREENEW_GET_CELL_TEXT getCellText = message->Parameter1; + PPH_STRING text; + + processNode = (PPH_PROCESS_NODE)getCellText->Node; + block = EtGetProcessBlock(processNode->ProcessItem); + + PhAcquireQueuedLockExclusive(&block->TextCacheLock); + + if (block->TextCacheValid[message->SubId]) + { + if (block->TextCache[message->SubId]) + getCellText->Text = block->TextCache[message->SubId]->sr; + } + else + { + text = NULL; + + switch (message->SubId) + { + case ETPRTNC_DISKREADS: + if (block->DiskReadCount != 0) + text = PhFormatUInt64(block->DiskReadCount, TRUE); + break; + case ETPRTNC_DISKWRITES: + if (block->DiskWriteCount != 0) + text = PhFormatUInt64(block->DiskWriteCount, TRUE); + break; + case ETPRTNC_DISKREADBYTES: + if (block->DiskReadRaw != 0) + text = PhFormatSize(block->DiskReadRaw, -1); + break; + case ETPRTNC_DISKWRITEBYTES: + if (block->DiskWriteRaw != 0) + text = PhFormatSize(block->DiskWriteRaw, -1); + break; + case ETPRTNC_DISKTOTALBYTES: + if (block->DiskReadRaw + block->DiskWriteRaw != 0) + text = PhFormatSize(block->DiskReadRaw + block->DiskWriteRaw, -1); + break; + case ETPRTNC_DISKREADSDELTA: + if (block->DiskReadDelta.Delta != 0) + text = PhFormatUInt64(block->DiskReadDelta.Delta, TRUE); + break; + case ETPRTNC_DISKWRITESDELTA: + if (block->DiskWriteDelta.Delta != 0) + text = PhFormatUInt64(block->DiskWriteDelta.Delta, TRUE); + break; + case ETPRTNC_DISKREADBYTESDELTA: + if (block->DiskReadRawDelta.Delta != 0) + text = PhFormatSize(block->DiskReadRawDelta.Delta, -1); + break; + case ETPRTNC_DISKWRITEBYTESDELTA: + if (block->DiskWriteRawDelta.Delta != 0) + text = PhFormatSize(block->DiskWriteRawDelta.Delta, -1); + break; + case ETPRTNC_DISKTOTALBYTESDELTA: + if (block->DiskReadRawDelta.Delta + block->DiskWriteRawDelta.Delta != 0) + text = PhFormatSize(block->DiskReadRawDelta.Delta + block->DiskWriteRawDelta.Delta, -1); + break; + case ETPRTNC_NETWORKRECEIVES: + if (block->NetworkReceiveCount != 0) + text = PhFormatUInt64(block->NetworkReceiveCount, TRUE); + break; + case ETPRTNC_NETWORKSENDS: + if (block->NetworkSendCount != 0) + text = PhFormatUInt64(block->NetworkSendCount, TRUE); + break; + case ETPRTNC_NETWORKRECEIVEBYTES: + if (block->NetworkReceiveRaw != 0) + text = PhFormatSize(block->NetworkReceiveRaw, -1); + break; + case ETPRTNC_NETWORKSENDBYTES: + if (block->NetworkSendRaw != 0) + text = PhFormatSize(block->NetworkSendRaw, -1); + break; + case ETPRTNC_NETWORKTOTALBYTES: + if (block->NetworkReceiveRaw + block->NetworkSendRaw != 0) + text = PhFormatSize(block->NetworkReceiveRaw + block->NetworkSendRaw, -1); + break; + case ETPRTNC_NETWORKRECEIVESDELTA: + if (block->NetworkReceiveDelta.Delta != 0) + text = PhFormatUInt64(block->NetworkReceiveDelta.Delta, TRUE); + break; + case ETPRTNC_NETWORKSENDSDELTA: + if (block->NetworkSendDelta.Delta != 0) + text = PhFormatUInt64(block->NetworkSendDelta.Delta, TRUE); + break; + case ETPRTNC_NETWORKRECEIVEBYTESDELTA: + if (block->NetworkReceiveRawDelta.Delta != 0) + text = PhFormatSize(block->NetworkReceiveRawDelta.Delta, -1); + break; + case ETPRTNC_NETWORKSENDBYTESDELTA: + if (block->NetworkSendRawDelta.Delta != 0) + text = PhFormatSize(block->NetworkSendRawDelta.Delta, -1); + break; + case ETPRTNC_NETWORKTOTALBYTESDELTA: + if (block->NetworkReceiveRawDelta.Delta + block->NetworkSendRawDelta.Delta != 0) + text = PhFormatSize(block->NetworkReceiveRawDelta.Delta + block->NetworkSendRawDelta.Delta, -1); + break; + case ETPRTNC_HARDFAULTS: + text = PhFormatUInt64(block->HardFaultsDelta.Value, TRUE); + break; + case ETPRTNC_HARDFAULTSDELTA: + if (block->HardFaultsDelta.Delta != 0) + text = PhFormatUInt64(block->HardFaultsDelta.Delta, TRUE); + break; + case ETPRTNC_PEAKTHREADS: + text = PhFormatUInt64(block->ProcessItem->PeakNumberOfThreads, TRUE); + break; + case ETPRTNC_GPU: + { + FLOAT gpuUsage; + + if (!PhGetIntegerSetting(L"PropagateCpuUsage") || processNode->Node.Expanded || ProcessTreeListSortOrder != NoSortOrder) + { + gpuUsage = block->GpuNodeUsage * 100; + } + else + { + gpuUsage = EtpCalculateInclusiveGpuUsage(processNode) * 100; + } + + if (gpuUsage >= 0.01) + { + PH_FORMAT format; + + PhInitFormatF(&format, gpuUsage, 2); + text = PhFormat(&format, 1, 0); + } + } + break; + case ETPRTNC_GPUDEDICATEDBYTES: + if (block->GpuDedicatedUsage != 0) + text = PhFormatSize(block->GpuDedicatedUsage, -1); + break; + case ETPRTNC_GPUSHAREDBYTES: + if (block->GpuSharedUsage != 0) + text = PhFormatSize(block->GpuSharedUsage, -1); + break; + case ETPRTNC_DISKREADRATE: + if (block->DiskReadRawDelta.Delta != 0) + EtFormatRate(block->DiskReadRawDelta.Delta, &text, NULL); + break; + case ETPRTNC_DISKWRITERATE: + if (block->DiskWriteRawDelta.Delta != 0) + EtFormatRate(block->DiskWriteRawDelta.Delta, &text, NULL); + break; + case ETPRTNC_DISKTOTALRATE: + if (block->DiskReadRawDelta.Delta + block->DiskWriteRawDelta.Delta != 0) + EtFormatRate(block->DiskReadRawDelta.Delta + block->DiskWriteRawDelta.Delta, &text, NULL); + break; + case ETPRTNC_NETWORKRECEIVERATE: + if (block->NetworkReceiveRawDelta.Delta != 0) + EtFormatRate(block->NetworkReceiveRawDelta.Delta, &text, NULL); + break; + case ETPRTNC_NETWORKSENDRATE: + if (block->NetworkSendRawDelta.Delta != 0) + EtFormatRate(block->NetworkSendRawDelta.Delta, &text, NULL); + break; + case ETPRTNC_NETWORKTOTALRATE: + if (block->NetworkReceiveRawDelta.Delta + block->NetworkSendRawDelta.Delta != 0) + EtFormatRate(block->NetworkReceiveRawDelta.Delta + block->NetworkSendRawDelta.Delta, &text, NULL); + break; + } + + if (text) + { + getCellText->Text = text->sr; + } + + PhMoveReference(&block->TextCache[message->SubId], text); + block->TextCacheValid[message->SubId] = TRUE; + } + + PhReleaseQueuedLockExclusive(&block->TextCacheLock); + } + else if (message->Message == TreeNewSortChanged) + { + TreeNew_GetSort(message->TreeNewHandle, &ProcessTreeListSortColumn, &ProcessTreeListSortOrder); + } + else if (message->Message == TreeNewNodeExpanding) + { + processNode = message->Parameter1; + block = EtGetProcessBlock(processNode->ProcessItem); + + if (PhGetIntegerSetting(L"PropagateCpuUsage")) + block->TextCacheValid[ETPRTNC_GPU] = FALSE; + } +} + +LONG EtpProcessTreeNewSortFunction( + _In_ PVOID Node1, + _In_ PVOID Node2, + _In_ ULONG SubId, + _In_ PVOID Context + ) +{ + LONG result; + PPH_PROCESS_NODE node1 = Node1; + PPH_PROCESS_NODE node2 = Node2; + PET_PROCESS_BLOCK block1; + PET_PROCESS_BLOCK block2; + + block1 = EtGetProcessBlock(node1->ProcessItem); + block2 = EtGetProcessBlock(node2->ProcessItem); + + result = 0; + + switch (SubId) + { + case ETPRTNC_DISKREADS: + result = uint64cmp(block1->DiskReadCount, block2->DiskReadCount); + break; + case ETPRTNC_DISKWRITES: + result = uint64cmp(block1->DiskWriteCount, block2->DiskWriteCount); + break; + case ETPRTNC_DISKREADBYTES: + result = uint64cmp(block1->DiskReadRaw, block2->DiskReadRaw); + break; + case ETPRTNC_DISKWRITEBYTES: + result = uint64cmp(block1->DiskWriteRaw, block2->DiskWriteRaw); + break; + case ETPRTNC_DISKTOTALBYTES: + result = uint64cmp(block1->DiskReadRaw + block1->DiskWriteRaw, block2->DiskReadRaw + block2->DiskWriteRaw); + break; + case ETPRTNC_DISKREADSDELTA: + result = uint64cmp(block1->DiskReadDelta.Delta, block2->DiskReadDelta.Delta); + break; + case ETPRTNC_DISKWRITESDELTA: + result = uint64cmp(block1->DiskWriteDelta.Delta, block2->DiskWriteDelta.Delta); + break; + case ETPRTNC_DISKREADBYTESDELTA: + result = uint64cmp(block1->DiskReadRawDelta.Delta, block2->DiskReadRawDelta.Delta); + break; + case ETPRTNC_DISKWRITEBYTESDELTA: + result = uint64cmp(block1->DiskWriteRawDelta.Delta, block2->DiskWriteRawDelta.Delta); + break; + case ETPRTNC_DISKTOTALBYTESDELTA: + result = uint64cmp(block1->DiskReadRawDelta.Delta + block1->DiskWriteRawDelta.Delta, block2->DiskReadRawDelta.Delta + block2->DiskWriteRawDelta.Delta); + break; + case ETPRTNC_NETWORKRECEIVES: + result = uint64cmp(block1->NetworkReceiveCount, block2->NetworkReceiveCount); + break; + case ETPRTNC_NETWORKSENDS: + result = uint64cmp(block1->NetworkSendCount, block2->NetworkSendCount); + break; + case ETPRTNC_NETWORKRECEIVEBYTES: + result = uint64cmp(block1->NetworkReceiveRaw, block2->NetworkReceiveRaw); + break; + case ETPRTNC_NETWORKSENDBYTES: + result = uint64cmp(block1->NetworkSendRaw, block2->NetworkSendRaw); + break; + case ETPRTNC_NETWORKTOTALBYTES: + result = uint64cmp(block1->NetworkReceiveRaw + block1->NetworkSendRaw, block2->NetworkReceiveRaw + block2->NetworkSendRaw); + break; + case ETPRTNC_NETWORKRECEIVESDELTA: + result = uint64cmp(block1->NetworkReceiveDelta.Delta, block2->NetworkReceiveDelta.Delta); + break; + case ETPRTNC_NETWORKSENDSDELTA: + result = uint64cmp(block1->NetworkSendDelta.Delta, block2->NetworkSendDelta.Delta); + break; + case ETPRTNC_NETWORKRECEIVEBYTESDELTA: + result = uint64cmp(block1->NetworkReceiveRawDelta.Delta, block2->NetworkReceiveRawDelta.Delta); + break; + case ETPRTNC_NETWORKSENDBYTESDELTA: + result = uint64cmp(block1->NetworkSendRawDelta.Delta, block2->NetworkSendRawDelta.Delta); + break; + case ETPRTNC_NETWORKTOTALBYTESDELTA: + result = uint64cmp(block1->NetworkReceiveRawDelta.Delta + block1->NetworkSendRawDelta.Delta, block2->NetworkReceiveRawDelta.Delta + block2->NetworkSendRawDelta.Delta); + break; + case ETPRTNC_HARDFAULTS: + result = uintcmp(block1->HardFaultsDelta.Value, block2->HardFaultsDelta.Value); + break; + case ETPRTNC_HARDFAULTSDELTA: + result = uintcmp(block1->HardFaultsDelta.Delta, block2->HardFaultsDelta.Delta); + break; + case ETPRTNC_PEAKTHREADS: + result = uintcmp(block1->ProcessItem->PeakNumberOfThreads, block2->ProcessItem->PeakNumberOfThreads); + break; + case ETPRTNC_GPU: + result = singlecmp(block1->GpuNodeUsage, block2->GpuNodeUsage); + break; + case ETPRTNC_GPUDEDICATEDBYTES: + result = uint64cmp(block1->GpuDedicatedUsage, block2->GpuDedicatedUsage); + break; + case ETPRTNC_GPUSHAREDBYTES: + result = uint64cmp(block1->GpuSharedUsage, block2->GpuSharedUsage); + break; + case ETPRTNC_DISKREADRATE: + result = uint64cmp(block1->DiskReadRawDelta.Delta, block2->DiskReadRawDelta.Delta); + break; + case ETPRTNC_DISKWRITERATE: + result = uint64cmp(block1->DiskWriteRawDelta.Delta, block2->DiskWriteRawDelta.Delta); + break; + case ETPRTNC_DISKTOTALRATE: + result = uint64cmp(block1->DiskReadRawDelta.Delta + block1->DiskWriteRawDelta.Delta, block2->DiskReadRawDelta.Delta + block2->DiskWriteRawDelta.Delta); + break; + case ETPRTNC_NETWORKRECEIVERATE: + result = uint64cmp(block1->NetworkReceiveRawDelta.Delta, block2->NetworkReceiveRawDelta.Delta); + break; + case ETPRTNC_NETWORKSENDRATE: + result = uint64cmp(block1->NetworkSendRawDelta.Delta, block2->NetworkSendRawDelta.Delta); + break; + case ETPRTNC_NETWORKTOTALRATE: + result = uint64cmp(block1->NetworkReceiveRawDelta.Delta + block1->NetworkSendRawDelta.Delta, block2->NetworkReceiveRawDelta.Delta + block2->NetworkSendRawDelta.Delta); + break; + } + + return result; +} + +VOID EtNetworkTreeNewInitializing( + _In_ PVOID Parameter + ) +{ + static COLUMN_INFO columns[] = + { + { ETNETNC_RECEIVES, L"Receives", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE }, + { ETNETNC_SENDS, L"Sends", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE }, + { ETNETNC_RECEIVEBYTES, L"Receive bytes", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE }, + { ETNETNC_SENDBYTES, L"Send bytes", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE }, + { ETNETNC_TOTALBYTES, L"Total bytes", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE }, + { ETNETNC_RECEIVESDELTA, L"Receives delta", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE }, + { ETNETNC_SENDSDELTA, L"Sends delta", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE }, + { ETNETNC_RECEIVEBYTESDELTA, L"Receive bytes delta", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE }, + { ETNETNC_SENDBYTESDELTA, L"Send bytes delta", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE }, + { ETNETNC_TOTALBYTESDELTA, L"Total bytes delta", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE }, + { ETNETNC_FIREWALLSTATUS, L"Firewall status", 170, PH_ALIGN_LEFT, 0, FALSE }, + { ETNETNC_RECEIVERATE, L"Receive rate", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE }, + { ETNETNC_SENDRATE, L"Send rate", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE }, + { ETNETNC_TOTALRATE, L"Total rate", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE } + }; + + PPH_PLUGIN_TREENEW_INFORMATION treeNewInfo = Parameter; + ULONG i; + + for (i = 0; i < sizeof(columns) / sizeof(COLUMN_INFO); i++) + { + EtpAddTreeNewColumn(treeNewInfo, columns[i].SubId, columns[i].Text, columns[i].Width, columns[i].Alignment, + columns[i].TextFlags, columns[i].SortDescending, EtpNetworkTreeNewSortFunction); + } +} + +VOID EtpUpdateFirewallStatus( + _Inout_ PET_NETWORK_BLOCK Block + ) +{ + if (!Block->FirewallStatusValid) + { + Block->FirewallStatus = EtQueryFirewallStatus(Block->NetworkItem); + Block->FirewallStatusValid = TRUE; + } +} + +VOID EtNetworkTreeNewMessage( + _In_ PVOID Parameter + ) +{ + PPH_PLUGIN_TREENEW_MESSAGE message = Parameter; + + if (message->Message == TreeNewGetCellText) + { + PPH_TREENEW_GET_CELL_TEXT getCellText = message->Parameter1; + PPH_NETWORK_NODE networkNode = (PPH_NETWORK_NODE)getCellText->Node; + PET_NETWORK_BLOCK block; + PPH_STRING text; + + block = EtGetNetworkBlock(networkNode->NetworkItem); + + PhAcquireQueuedLockExclusive(&block->TextCacheLock); + + if (block->TextCacheValid[message->SubId]) + { + if (block->TextCache[message->SubId]) + getCellText->Text = block->TextCache[message->SubId]->sr; + } + else + { + text = NULL; + + switch (message->SubId) + { + case ETNETNC_RECEIVES: + if (block->ReceiveCount != 0) + text = PhFormatUInt64(block->ReceiveCount, TRUE); + break; + case ETNETNC_SENDS: + if (block->SendCount != 0) + text = PhFormatUInt64(block->SendCount, TRUE); + break; + case ETNETNC_RECEIVEBYTES: + if (block->ReceiveRaw != 0) + text = PhFormatSize(block->ReceiveRaw, -1); + break; + case ETNETNC_SENDBYTES: + if (block->SendRaw != 0) + text = PhFormatSize(block->SendRaw, -1); + break; + case ETNETNC_TOTALBYTES: + if (block->ReceiveRaw + block->SendRaw != 0) + text = PhFormatSize(block->ReceiveRaw + block->SendRaw, -1); + break; + case ETNETNC_RECEIVESDELTA: + if (block->ReceiveDelta.Delta != 0) + text = PhFormatUInt64(block->ReceiveDelta.Delta, TRUE); + break; + case ETNETNC_SENDSDELTA: + if (block->SendDelta.Delta != 0) + text = PhFormatUInt64(block->SendDelta.Delta, TRUE); + break; + case ETNETNC_RECEIVEBYTESDELTA: + if (block->ReceiveRawDelta.Delta != 0) + text = PhFormatSize(block->ReceiveRawDelta.Delta, -1); + break; + case ETNETNC_SENDBYTESDELTA: + if (block->SendRawDelta.Delta != 0) + text = PhFormatSize(block->SendRawDelta.Delta, -1); + break; + case ETNETNC_TOTALBYTESDELTA: + if (block->ReceiveRawDelta.Delta + block->SendRawDelta.Delta != 0) + text = PhFormatSize(block->ReceiveRawDelta.Delta + block->SendRawDelta.Delta, -1); + break; + case ETNETNC_FIREWALLSTATUS: + { + static PPH_STRING strings[FirewallMaximumStatus]; + static PH_INITONCE initOnce = PH_INITONCE_INIT; + + if (PhBeginInitOnce(&initOnce)) + { + strings[FirewallUnknownStatus] = NULL; + strings[FirewallAllowedNotRestricted] = PhCreateString(L"Allowed, not restricted"); + strings[FirewallAllowedRestricted] = PhCreateString(L"Allowed, restricted"); + strings[FirewallNotAllowedNotRestricted] = PhCreateString(L"Not allowed, not restricted"); + strings[FirewallNotAllowedRestricted] = PhCreateString(L"Not allowed, restricted"); + PhEndInitOnce(&initOnce); + } + + EtpUpdateFirewallStatus(block); + + if (block->FirewallStatus < FirewallMaximumStatus) + PhSetReference(&text, strings[block->FirewallStatus]); + } + break; + case ETNETNC_RECEIVERATE: + if (block->ReceiveRawDelta.Delta != 0) + EtFormatRate(block->ReceiveRawDelta.Delta, &text, NULL); + break; + case ETNETNC_SENDRATE: + if (block->SendRawDelta.Delta != 0) + EtFormatRate(block->SendRawDelta.Delta, &text, NULL); + break; + case ETNETNC_TOTALRATE: + if (block->ReceiveRawDelta.Delta + block->SendRawDelta.Delta != 0) + EtFormatRate(block->ReceiveRawDelta.Delta + block->SendRawDelta.Delta, &text, NULL); + break; + } + + if (text) + { + getCellText->Text = text->sr; + } + + PhMoveReference(&block->TextCache[message->SubId], text); + block->TextCacheValid[message->SubId] = TRUE; + } + + PhReleaseQueuedLockExclusive(&block->TextCacheLock); + } +} + +LONG EtpNetworkTreeNewSortFunction( + _In_ PVOID Node1, + _In_ PVOID Node2, + _In_ ULONG SubId, + _In_ PVOID Context + ) +{ + LONG result; + PPH_NETWORK_NODE node1 = Node1; + PPH_NETWORK_NODE node2 = Node2; + PET_NETWORK_BLOCK block1; + PET_NETWORK_BLOCK block2; + + block1 = EtGetNetworkBlock(node1->NetworkItem); + block2 = EtGetNetworkBlock(node2->NetworkItem); + + result = 0; + + switch (SubId) + { + case ETNETNC_RECEIVES: + result = uint64cmp(block1->ReceiveCount, block2->ReceiveCount); + break; + case ETNETNC_SENDS: + result = uint64cmp(block1->SendCount, block2->SendCount); + break; + case ETNETNC_RECEIVEBYTES: + result = uint64cmp(block1->ReceiveRaw, block2->ReceiveRaw); + break; + case ETNETNC_SENDBYTES: + result = uint64cmp(block1->SendRaw, block2->SendRaw); + break; + case ETNETNC_TOTALBYTES: + result = uint64cmp(block1->ReceiveRaw + block1->SendRaw, block2->ReceiveRaw + block2->SendRaw); + break; + case ETNETNC_RECEIVESDELTA: + result = uint64cmp(block1->ReceiveDelta.Delta, block2->ReceiveDelta.Delta); + break; + case ETNETNC_SENDSDELTA: + result = uint64cmp(block1->SendDelta.Delta, block2->SendDelta.Delta); + break; + case ETNETNC_RECEIVEBYTESDELTA: + result = uint64cmp(block1->ReceiveRawDelta.Delta, block2->ReceiveRawDelta.Delta); + break; + case ETNETNC_SENDBYTESDELTA: + result = uint64cmp(block1->SendRawDelta.Delta, block2->SendRawDelta.Delta); + break; + case ETNETNC_TOTALBYTESDELTA: + result = uint64cmp(block1->ReceiveRawDelta.Delta + block1->SendRawDelta.Delta, block2->ReceiveRawDelta.Delta + block2->SendRawDelta.Delta); + break; + case ETNETNC_FIREWALLSTATUS: + EtpUpdateFirewallStatus(block1); + EtpUpdateFirewallStatus(block2); + result = intcmp(block1->FirewallStatus, block2->FirewallStatus); + break; + case ETNETNC_RECEIVERATE: + result = uint64cmp(block1->ReceiveRawDelta.Delta, block2->ReceiveRawDelta.Delta); + break; + case ETNETNC_SENDRATE: + result = uint64cmp(block1->SendRawDelta.Delta, block2->SendRawDelta.Delta); + break; + case ETNETNC_TOTALRATE: + result = uint64cmp(block1->ReceiveRawDelta.Delta + block1->SendRawDelta.Delta, block2->ReceiveRawDelta.Delta + block2->SendRawDelta.Delta); + break; + } + + return result; +} + +ET_FIREWALL_STATUS EtQueryFirewallStatus( + _In_ PPH_NETWORK_ITEM NetworkItem + ) +{ + static INetFwMgr* manager = NULL; + ET_FIREWALL_STATUS result; + PPH_PROCESS_ITEM processItem; + BSTR imageFileNameBStr; + BSTR localAddressBStr; + VARIANT allowed; + VARIANT restricted; + + if (!manager) + { + if (!SUCCEEDED(CoCreateInstance(&CLSID_NetFwMgr_I, NULL, CLSCTX_INPROC_SERVER, &IID_INetFwMgr_I, &manager))) + return FirewallUnknownStatus; + + if (!manager) + return FirewallUnknownStatus; + } + + processItem = PhReferenceProcessItem(NetworkItem->ProcessId); + + if (!processItem) + return FirewallUnknownStatus; + + if (!processItem->FileName) + { + PhDereferenceObject(processItem); + return FirewallUnknownStatus; + } + + result = FirewallUnknownStatus; + + if (imageFileNameBStr = SysAllocStringLen(processItem->FileName->Buffer, (ULONG)processItem->FileName->Length / sizeof(WCHAR))) + { + localAddressBStr = NULL; + + if (!PhIsNullIpAddress(&NetworkItem->LocalEndpoint.Address)) + localAddressBStr = SysAllocString(NetworkItem->LocalAddressString); + + if (SUCCEEDED(INetFwMgr_IsPortAllowed( + manager, + imageFileNameBStr, + (NetworkItem->ProtocolType & PH_IPV6_NETWORK_TYPE) ? NET_FW_IP_VERSION_V6 : NET_FW_IP_VERSION_V4, + NetworkItem->LocalEndpoint.Port, + localAddressBStr, + (NetworkItem->ProtocolType & PH_UDP_PROTOCOL_TYPE) ? NET_FW_IP_PROTOCOL_UDP : NET_FW_IP_PROTOCOL_TCP, + &allowed, + &restricted + ))) + { + if (allowed.boolVal) + { + if (restricted.boolVal) + result = FirewallAllowedRestricted; + else + result = FirewallAllowedNotRestricted; + } + else + { + if (restricted.boolVal) + result = FirewallNotAllowedRestricted; + else + result = FirewallNotAllowedNotRestricted; + } + } + + if (localAddressBStr) + SysFreeString(localAddressBStr); + + SysFreeString(imageFileNameBStr); + } + + PhDereferenceObject(processItem); + + return result; +} diff --git a/plugins/ExtendedTools/unldll.c b/plugins/ExtendedTools/unldll.c index e58672399a45..5145c62348e4 100644 --- a/plugins/ExtendedTools/unldll.c +++ b/plugins/ExtendedTools/unldll.c @@ -1,357 +1,357 @@ -/* - * Process Hacker Extended Tools - - * unloaded DLLs display - * - * Copyright (C) 2010-2011 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include "exttools.h" - -typedef struct _UNLOADED_DLLS_CONTEXT -{ - PPH_PROCESS_ITEM ProcessItem; - HWND ListViewHandle; - PVOID CapturedEventTrace; -} UNLOADED_DLLS_CONTEXT, *PUNLOADED_DLLS_CONTEXT; - -INT_PTR CALLBACK EtpUnloadedDllsDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -VOID EtShowUnloadedDllsDialog( - _In_ HWND ParentWindowHandle, - _In_ PPH_PROCESS_ITEM ProcessItem - ) -{ - UNLOADED_DLLS_CONTEXT context; - - context.ProcessItem = ProcessItem; - context.CapturedEventTrace = NULL; - - DialogBoxParam( - PluginInstance->DllBase, - MAKEINTRESOURCE(IDD_UNLOADEDDLLS), - ParentWindowHandle, - EtpUnloadedDllsDlgProc, - (LPARAM)&context - ); - - if (context.CapturedEventTrace) - PhFree(context.CapturedEventTrace); -} - -BOOLEAN EtpRefreshUnloadedDlls( - _In_ HWND hwndDlg, - _In_ PUNLOADED_DLLS_CONTEXT Context - ) -{ - NTSTATUS status; - PULONG elementSize; - PULONG elementCount; - PVOID eventTrace; - HANDLE processHandle = NULL; - ULONG eventTraceSize; - ULONG capturedElementSize; - ULONG capturedElementCount; - PVOID capturedEventTracePointer; - PVOID capturedEventTrace = NULL; - ULONG i; - PVOID currentEvent; - HWND lvHandle; - - lvHandle = GetDlgItem(hwndDlg, IDC_LIST); - ListView_DeleteAllItems(lvHandle); - - RtlGetUnloadEventTraceEx(&elementSize, &elementCount, &eventTrace); - - if (!NT_SUCCESS(status = PhOpenProcess(&processHandle, PROCESS_VM_READ, Context->ProcessItem->ProcessId))) - goto CleanupExit; - - // We have the pointers for the unload event trace information. - // Since ntdll is loaded at the same base address across all processes, - // we can read the information in. - - if (!NT_SUCCESS(status = NtReadVirtualMemory( - processHandle, - elementSize, - &capturedElementSize, - sizeof(ULONG), - NULL - ))) - goto CleanupExit; - - if (!NT_SUCCESS(status = NtReadVirtualMemory( - processHandle, - elementCount, - &capturedElementCount, - sizeof(ULONG), - NULL - ))) - goto CleanupExit; - - if (!NT_SUCCESS(status = NtReadVirtualMemory( - processHandle, - eventTrace, - &capturedEventTracePointer, - sizeof(PVOID), - NULL - ))) - goto CleanupExit; - - if (!capturedEventTracePointer) - goto CleanupExit; // no events - - if (capturedElementCount > 0x4000) - capturedElementCount = 0x4000; - - eventTraceSize = capturedElementSize * capturedElementCount; - - capturedEventTrace = PhAllocateSafe(eventTraceSize); - - if (!capturedEventTrace) - { - status = STATUS_NO_MEMORY; - goto CleanupExit; - } - - if (!NT_SUCCESS(status = NtReadVirtualMemory( - processHandle, - capturedEventTracePointer, - capturedEventTrace, - eventTraceSize, - NULL - ))) - goto CleanupExit; - - currentEvent = capturedEventTrace; - - ExtendedListView_SetRedraw(lvHandle, FALSE); - - for (i = 0; i < capturedElementCount; i++) - { - PRTL_UNLOAD_EVENT_TRACE rtlEvent = currentEvent; - INT lvItemIndex; - WCHAR buffer[128]; - PPH_STRING string; - LARGE_INTEGER time; - SYSTEMTIME systemTime; - - if (!rtlEvent->BaseAddress) - break; - - PhPrintUInt32(buffer, rtlEvent->Sequence); - lvItemIndex = PhAddListViewItem(lvHandle, MAXINT, buffer, rtlEvent); - - // Name - if (PhCopyStringZ(rtlEvent->ImageName, sizeof(rtlEvent->ImageName) / sizeof(WCHAR), - buffer, sizeof(buffer) / sizeof(WCHAR), NULL)) - { - PhSetListViewSubItem(lvHandle, lvItemIndex, 1, buffer); - } - - // Base Address - PhPrintPointer(buffer, rtlEvent->BaseAddress); - PhSetListViewSubItem(lvHandle, lvItemIndex, 2, buffer); - - // Size - string = PhFormatSize(rtlEvent->SizeOfImage, -1); - PhSetListViewSubItem(lvHandle, lvItemIndex, 3, string->Buffer); - PhDereferenceObject(string); - - // Time Stamp - RtlSecondsSince1970ToTime(rtlEvent->TimeDateStamp, &time); - PhLargeIntegerToLocalSystemTime(&systemTime, &time); - string = PhFormatDateTime(&systemTime); - PhSetListViewSubItem(lvHandle, lvItemIndex, 4, string->Buffer); - PhDereferenceObject(string); - - // Checksum - PhPrintPointer(buffer, UlongToPtr(rtlEvent->CheckSum)); - PhSetListViewSubItem(lvHandle, lvItemIndex, 5, buffer); - - currentEvent = PTR_ADD_OFFSET(currentEvent, capturedElementSize); - } - - ExtendedListView_SortItems(lvHandle); - ExtendedListView_SetRedraw(lvHandle, TRUE); - - if (Context->CapturedEventTrace) - PhFree(Context->CapturedEventTrace); - - Context->CapturedEventTrace = capturedEventTrace; - -CleanupExit: - - if (processHandle) - NtClose(processHandle); - - if (NT_SUCCESS(status)) - { - return TRUE; - } - else - { - PhShowStatus(hwndDlg, L"Unable to retrieve unload event trace information", status, 0); - return FALSE; - } -} - -static INT NTAPI EtpNumberCompareFunction( - _In_ PVOID Item1, - _In_ PVOID Item2, - _In_opt_ PVOID Context - ) -{ - PRTL_UNLOAD_EVENT_TRACE item1 = Item1; - PRTL_UNLOAD_EVENT_TRACE item2 = Item2; - - return uintcmp(item1->Sequence, item2->Sequence); -} - -static INT NTAPI EtpBaseAddressCompareFunction( - _In_ PVOID Item1, - _In_ PVOID Item2, - _In_opt_ PVOID Context - ) -{ - PRTL_UNLOAD_EVENT_TRACE item1 = Item1; - PRTL_UNLOAD_EVENT_TRACE item2 = Item2; - - return uintptrcmp((ULONG_PTR)item1->BaseAddress, (ULONG_PTR)item2->BaseAddress); -} - -static INT NTAPI EtpSizeCompareFunction( - _In_ PVOID Item1, - _In_ PVOID Item2, - _In_opt_ PVOID Context - ) -{ - PRTL_UNLOAD_EVENT_TRACE item1 = Item1; - PRTL_UNLOAD_EVENT_TRACE item2 = Item2; - - return uintptrcmp(item1->SizeOfImage, item2->SizeOfImage); -} - -static INT NTAPI EtpTimeStampCompareFunction( - _In_ PVOID Item1, - _In_ PVOID Item2, - _In_opt_ PVOID Context - ) -{ - PRTL_UNLOAD_EVENT_TRACE item1 = Item1; - PRTL_UNLOAD_EVENT_TRACE item2 = Item2; - - return uintcmp(item1->TimeDateStamp, item2->TimeDateStamp); -} - -static INT NTAPI EtpCheckSumCompareFunction( - _In_ PVOID Item1, - _In_ PVOID Item2, - _In_opt_ PVOID Context - ) -{ - PRTL_UNLOAD_EVENT_TRACE item1 = Item1; - PRTL_UNLOAD_EVENT_TRACE item2 = Item2; - - return uintcmp(item1->CheckSum, item2->CheckSum); -} - -INT_PTR CALLBACK EtpUnloadedDllsDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - PUNLOADED_DLLS_CONTEXT context; - - if (uMsg == WM_INITDIALOG) - { - context = (PUNLOADED_DLLS_CONTEXT)lParam; - SetProp(hwndDlg, L"Context", (HANDLE)context); - } - else - { - context = (PUNLOADED_DLLS_CONTEXT)GetProp(hwndDlg, L"Context"); - - if (uMsg == WM_DESTROY) - RemoveProp(hwndDlg, L"Context"); - } - - if (!context) - return FALSE; - - switch (uMsg) - { - case WM_INITDIALOG: - { - HWND lvHandle; - - PhCenterWindow(hwndDlg, GetParent(hwndDlg)); - - context->ListViewHandle = lvHandle = GetDlgItem(hwndDlg, IDC_LIST); - - PhSetListViewStyle(lvHandle, FALSE, TRUE); - PhSetControlTheme(lvHandle, L"explorer"); - PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 40, L"No."); - PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 120, L"Name"); - PhAddListViewColumn(lvHandle, 2, 2, 2, LVCFMT_LEFT, 80, L"Base Address"); - PhAddListViewColumn(lvHandle, 3, 3, 3, LVCFMT_LEFT, 60, L"Size"); - PhAddListViewColumn(lvHandle, 4, 4, 4, LVCFMT_LEFT, 100, L"Time Stamp"); - PhAddListViewColumn(lvHandle, 5, 5, 5, LVCFMT_LEFT, 60, L"Checksum"); - - PhSetExtendedListView(lvHandle); - ExtendedListView_SetCompareFunction(lvHandle, 0, EtpNumberCompareFunction); - ExtendedListView_SetCompareFunction(lvHandle, 2, EtpBaseAddressCompareFunction); - ExtendedListView_SetCompareFunction(lvHandle, 3, EtpSizeCompareFunction); - ExtendedListView_SetCompareFunction(lvHandle, 4, EtpTimeStampCompareFunction); - ExtendedListView_SetCompareFunction(lvHandle, 5, EtpCheckSumCompareFunction); - - if (!EtpRefreshUnloadedDlls(hwndDlg, context)) - { - EndDialog(hwndDlg, IDCANCEL); - return FALSE; - } - } - break; - case WM_COMMAND: - { - switch (LOWORD(wParam)) - { - case IDCANCEL: - case IDOK: - EndDialog(hwndDlg, IDOK); - break; - case IDC_REFRESH: - EtpRefreshUnloadedDlls(hwndDlg, context); - break; - } - } - break; - case WM_NOTIFY: - { - PhHandleListViewNotifyForCopy(lParam, context->ListViewHandle); - } - break; - } - - return FALSE; -} +/* + * Process Hacker Extended Tools - + * unloaded DLLs display + * + * Copyright (C) 2010-2011 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include "exttools.h" + +typedef struct _UNLOADED_DLLS_CONTEXT +{ + PPH_PROCESS_ITEM ProcessItem; + HWND ListViewHandle; + PVOID CapturedEventTrace; +} UNLOADED_DLLS_CONTEXT, *PUNLOADED_DLLS_CONTEXT; + +INT_PTR CALLBACK EtpUnloadedDllsDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +VOID EtShowUnloadedDllsDialog( + _In_ HWND ParentWindowHandle, + _In_ PPH_PROCESS_ITEM ProcessItem + ) +{ + UNLOADED_DLLS_CONTEXT context; + + context.ProcessItem = ProcessItem; + context.CapturedEventTrace = NULL; + + DialogBoxParam( + PluginInstance->DllBase, + MAKEINTRESOURCE(IDD_UNLOADEDDLLS), + ParentWindowHandle, + EtpUnloadedDllsDlgProc, + (LPARAM)&context + ); + + if (context.CapturedEventTrace) + PhFree(context.CapturedEventTrace); +} + +BOOLEAN EtpRefreshUnloadedDlls( + _In_ HWND hwndDlg, + _In_ PUNLOADED_DLLS_CONTEXT Context + ) +{ + NTSTATUS status; + PULONG elementSize; + PULONG elementCount; + PVOID eventTrace; + HANDLE processHandle = NULL; + ULONG eventTraceSize; + ULONG capturedElementSize; + ULONG capturedElementCount; + PVOID capturedEventTracePointer; + PVOID capturedEventTrace = NULL; + ULONG i; + PVOID currentEvent; + HWND lvHandle; + + lvHandle = GetDlgItem(hwndDlg, IDC_LIST); + ListView_DeleteAllItems(lvHandle); + + RtlGetUnloadEventTraceEx(&elementSize, &elementCount, &eventTrace); + + if (!NT_SUCCESS(status = PhOpenProcess(&processHandle, PROCESS_VM_READ, Context->ProcessItem->ProcessId))) + goto CleanupExit; + + // We have the pointers for the unload event trace information. + // Since ntdll is loaded at the same base address across all processes, + // we can read the information in. + + if (!NT_SUCCESS(status = NtReadVirtualMemory( + processHandle, + elementSize, + &capturedElementSize, + sizeof(ULONG), + NULL + ))) + goto CleanupExit; + + if (!NT_SUCCESS(status = NtReadVirtualMemory( + processHandle, + elementCount, + &capturedElementCount, + sizeof(ULONG), + NULL + ))) + goto CleanupExit; + + if (!NT_SUCCESS(status = NtReadVirtualMemory( + processHandle, + eventTrace, + &capturedEventTracePointer, + sizeof(PVOID), + NULL + ))) + goto CleanupExit; + + if (!capturedEventTracePointer) + goto CleanupExit; // no events + + if (capturedElementCount > 0x4000) + capturedElementCount = 0x4000; + + eventTraceSize = capturedElementSize * capturedElementCount; + + capturedEventTrace = PhAllocateSafe(eventTraceSize); + + if (!capturedEventTrace) + { + status = STATUS_NO_MEMORY; + goto CleanupExit; + } + + if (!NT_SUCCESS(status = NtReadVirtualMemory( + processHandle, + capturedEventTracePointer, + capturedEventTrace, + eventTraceSize, + NULL + ))) + goto CleanupExit; + + currentEvent = capturedEventTrace; + + ExtendedListView_SetRedraw(lvHandle, FALSE); + + for (i = 0; i < capturedElementCount; i++) + { + PRTL_UNLOAD_EVENT_TRACE rtlEvent = currentEvent; + INT lvItemIndex; + WCHAR buffer[128]; + PPH_STRING string; + LARGE_INTEGER time; + SYSTEMTIME systemTime; + + if (!rtlEvent->BaseAddress) + break; + + PhPrintUInt32(buffer, rtlEvent->Sequence); + lvItemIndex = PhAddListViewItem(lvHandle, MAXINT, buffer, rtlEvent); + + // Name + if (PhCopyStringZ(rtlEvent->ImageName, sizeof(rtlEvent->ImageName) / sizeof(WCHAR), + buffer, sizeof(buffer) / sizeof(WCHAR), NULL)) + { + PhSetListViewSubItem(lvHandle, lvItemIndex, 1, buffer); + } + + // Base Address + PhPrintPointer(buffer, rtlEvent->BaseAddress); + PhSetListViewSubItem(lvHandle, lvItemIndex, 2, buffer); + + // Size + string = PhFormatSize(rtlEvent->SizeOfImage, -1); + PhSetListViewSubItem(lvHandle, lvItemIndex, 3, string->Buffer); + PhDereferenceObject(string); + + // Time Stamp + RtlSecondsSince1970ToTime(rtlEvent->TimeDateStamp, &time); + PhLargeIntegerToLocalSystemTime(&systemTime, &time); + string = PhFormatDateTime(&systemTime); + PhSetListViewSubItem(lvHandle, lvItemIndex, 4, string->Buffer); + PhDereferenceObject(string); + + // Checksum + PhPrintPointer(buffer, UlongToPtr(rtlEvent->CheckSum)); + PhSetListViewSubItem(lvHandle, lvItemIndex, 5, buffer); + + currentEvent = PTR_ADD_OFFSET(currentEvent, capturedElementSize); + } + + ExtendedListView_SortItems(lvHandle); + ExtendedListView_SetRedraw(lvHandle, TRUE); + + if (Context->CapturedEventTrace) + PhFree(Context->CapturedEventTrace); + + Context->CapturedEventTrace = capturedEventTrace; + +CleanupExit: + + if (processHandle) + NtClose(processHandle); + + if (NT_SUCCESS(status)) + { + return TRUE; + } + else + { + PhShowStatus(hwndDlg, L"Unable to retrieve unload event trace information", status, 0); + return FALSE; + } +} + +static INT NTAPI EtpNumberCompareFunction( + _In_ PVOID Item1, + _In_ PVOID Item2, + _In_opt_ PVOID Context + ) +{ + PRTL_UNLOAD_EVENT_TRACE item1 = Item1; + PRTL_UNLOAD_EVENT_TRACE item2 = Item2; + + return uintcmp(item1->Sequence, item2->Sequence); +} + +static INT NTAPI EtpBaseAddressCompareFunction( + _In_ PVOID Item1, + _In_ PVOID Item2, + _In_opt_ PVOID Context + ) +{ + PRTL_UNLOAD_EVENT_TRACE item1 = Item1; + PRTL_UNLOAD_EVENT_TRACE item2 = Item2; + + return uintptrcmp((ULONG_PTR)item1->BaseAddress, (ULONG_PTR)item2->BaseAddress); +} + +static INT NTAPI EtpSizeCompareFunction( + _In_ PVOID Item1, + _In_ PVOID Item2, + _In_opt_ PVOID Context + ) +{ + PRTL_UNLOAD_EVENT_TRACE item1 = Item1; + PRTL_UNLOAD_EVENT_TRACE item2 = Item2; + + return uintptrcmp(item1->SizeOfImage, item2->SizeOfImage); +} + +static INT NTAPI EtpTimeStampCompareFunction( + _In_ PVOID Item1, + _In_ PVOID Item2, + _In_opt_ PVOID Context + ) +{ + PRTL_UNLOAD_EVENT_TRACE item1 = Item1; + PRTL_UNLOAD_EVENT_TRACE item2 = Item2; + + return uintcmp(item1->TimeDateStamp, item2->TimeDateStamp); +} + +static INT NTAPI EtpCheckSumCompareFunction( + _In_ PVOID Item1, + _In_ PVOID Item2, + _In_opt_ PVOID Context + ) +{ + PRTL_UNLOAD_EVENT_TRACE item1 = Item1; + PRTL_UNLOAD_EVENT_TRACE item2 = Item2; + + return uintcmp(item1->CheckSum, item2->CheckSum); +} + +INT_PTR CALLBACK EtpUnloadedDllsDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + PUNLOADED_DLLS_CONTEXT context; + + if (uMsg == WM_INITDIALOG) + { + context = (PUNLOADED_DLLS_CONTEXT)lParam; + SetProp(hwndDlg, L"Context", (HANDLE)context); + } + else + { + context = (PUNLOADED_DLLS_CONTEXT)GetProp(hwndDlg, L"Context"); + + if (uMsg == WM_DESTROY) + RemoveProp(hwndDlg, L"Context"); + } + + if (!context) + return FALSE; + + switch (uMsg) + { + case WM_INITDIALOG: + { + HWND lvHandle; + + PhCenterWindow(hwndDlg, GetParent(hwndDlg)); + + context->ListViewHandle = lvHandle = GetDlgItem(hwndDlg, IDC_LIST); + + PhSetListViewStyle(lvHandle, FALSE, TRUE); + PhSetControlTheme(lvHandle, L"explorer"); + PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 40, L"No."); + PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 120, L"Name"); + PhAddListViewColumn(lvHandle, 2, 2, 2, LVCFMT_LEFT, 80, L"Base Address"); + PhAddListViewColumn(lvHandle, 3, 3, 3, LVCFMT_LEFT, 60, L"Size"); + PhAddListViewColumn(lvHandle, 4, 4, 4, LVCFMT_LEFT, 100, L"Time Stamp"); + PhAddListViewColumn(lvHandle, 5, 5, 5, LVCFMT_LEFT, 60, L"Checksum"); + + PhSetExtendedListView(lvHandle); + ExtendedListView_SetCompareFunction(lvHandle, 0, EtpNumberCompareFunction); + ExtendedListView_SetCompareFunction(lvHandle, 2, EtpBaseAddressCompareFunction); + ExtendedListView_SetCompareFunction(lvHandle, 3, EtpSizeCompareFunction); + ExtendedListView_SetCompareFunction(lvHandle, 4, EtpTimeStampCompareFunction); + ExtendedListView_SetCompareFunction(lvHandle, 5, EtpCheckSumCompareFunction); + + if (!EtpRefreshUnloadedDlls(hwndDlg, context)) + { + EndDialog(hwndDlg, IDCANCEL); + return FALSE; + } + } + break; + case WM_COMMAND: + { + switch (LOWORD(wParam)) + { + case IDCANCEL: + case IDOK: + EndDialog(hwndDlg, IDOK); + break; + case IDC_REFRESH: + EtpRefreshUnloadedDlls(hwndDlg, context); + break; + } + } + break; + case WM_NOTIFY: + { + PhHandleListViewNotifyForCopy(lParam, context->ListViewHandle); + } + break; + } + + return FALSE; +} diff --git a/plugins/ExtendedTools/utils.c b/plugins/ExtendedTools/utils.c index d0e1c4da868d..2d5f23af7c81 100644 --- a/plugins/ExtendedTools/utils.c +++ b/plugins/ExtendedTools/utils.c @@ -1,48 +1,48 @@ -/* - * Process Hacker Extended Tools - - * utility functions - * - * Copyright (C) 2011 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include "exttools.h" - -VOID EtFormatRate( - _In_ ULONG64 ValuePerPeriod, - _Inout_ PPH_STRING *Buffer, - _Out_opt_ PPH_STRINGREF String - ) -{ - ULONG64 number; - - number = ValuePerPeriod; - number *= 1000; - number /= PhGetIntegerSetting(L"UpdateInterval"); - - if (number != 0) - { - PH_FORMAT format[2]; - - PhInitFormatSize(&format[0], number); - PhInitFormatS(&format[1], L"/s"); - PhMoveReference(Buffer, PhFormat(format, 2, 0)); - - if (String) - *String = (*Buffer)->sr; - } -} +/* + * Process Hacker Extended Tools - + * utility functions + * + * Copyright (C) 2011 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include "exttools.h" + +VOID EtFormatRate( + _In_ ULONG64 ValuePerPeriod, + _Inout_ PPH_STRING *Buffer, + _Out_opt_ PPH_STRINGREF String + ) +{ + ULONG64 number; + + number = ValuePerPeriod; + number *= 1000; + number /= PhGetIntegerSetting(L"UpdateInterval"); + + if (number != 0) + { + PH_FORMAT format[2]; + + PhInitFormatSize(&format[0], number); + PhInitFormatS(&format[1], L"/s"); + PhMoveReference(Buffer, PhFormat(format, 2, 0)); + + if (String) + *String = (*Buffer)->sr; + } +} diff --git a/plugins/ExtendedTools/wswatch.c b/plugins/ExtendedTools/wswatch.c index 2047c505d813..470092cb3b0d 100644 --- a/plugins/ExtendedTools/wswatch.c +++ b/plugins/ExtendedTools/wswatch.c @@ -1,571 +1,571 @@ -/* - * Process Hacker Extended Tools - - * working set watch - * - * Copyright (C) 2011 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include "exttools.h" -#include -#include - -typedef struct _WS_WATCH_CONTEXT -{ - LONG RefCount; - - PPH_PROCESS_ITEM ProcessItem; - HWND WindowHandle; - HWND ListViewHandle; - BOOLEAN Enabled; - BOOLEAN Destroying; - PPH_HASHTABLE Hashtable; - HANDLE ProcessHandle; - PVOID Buffer; - ULONG BufferSize; - - PPH_SYMBOL_PROVIDER SymbolProvider; - HANDLE LoadingSymbolsForProcessId; - SINGLE_LIST_ENTRY ResultListHead; - PH_QUEUED_LOCK ResultListLock; -} WS_WATCH_CONTEXT, *PWS_WATCH_CONTEXT; - -typedef struct _SYMBOL_LOOKUP_RESULT -{ - SINGLE_LIST_ENTRY ListEntry; - PWS_WATCH_CONTEXT Context; - PVOID Address; - PPH_STRING Symbol; -} SYMBOL_LOOKUP_RESULT, *PSYMBOL_LOOKUP_RESULT; - -VOID EtpReferenceWsWatchContext( - _Inout_ PWS_WATCH_CONTEXT Context - ); - -VOID EtpDereferenceWsWatchContext( - _Inout_ PWS_WATCH_CONTEXT Context - ); - -INT_PTR CALLBACK EtpWsWatchDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -VOID EtShowWsWatchDialog( - _In_ HWND ParentWindowHandle, - _In_ PPH_PROCESS_ITEM ProcessItem - ) -{ - PWS_WATCH_CONTEXT context; - - context = PhAllocate(sizeof(WS_WATCH_CONTEXT)); - memset(context, 0, sizeof(WS_WATCH_CONTEXT)); - context->RefCount = 1; - context->ProcessItem = ProcessItem; - - DialogBoxParam( - PluginInstance->DllBase, - MAKEINTRESOURCE(IDD_WSWATCH), - ParentWindowHandle, - EtpWsWatchDlgProc, - (LPARAM)context - ); - EtpDereferenceWsWatchContext(context); -} - -static VOID EtpReferenceWsWatchContext( - _Inout_ PWS_WATCH_CONTEXT Context - ) -{ - _InterlockedIncrement(&Context->RefCount); -} - -static VOID EtpDereferenceWsWatchContext( - _Inout_ PWS_WATCH_CONTEXT Context - ) -{ - if (_InterlockedDecrement(&Context->RefCount) == 0) - { - PSINGLE_LIST_ENTRY listEntry; - - if (Context->SymbolProvider) - PhDereferenceObject(Context->SymbolProvider); - - // Free all unused results. - - PhAcquireQueuedLockExclusive(&Context->ResultListLock); - - listEntry = Context->ResultListHead.Next; - - while (listEntry) - { - PSYMBOL_LOOKUP_RESULT result; - - result = CONTAINING_RECORD(listEntry, SYMBOL_LOOKUP_RESULT, ListEntry); - listEntry = listEntry->Next; - PhDereferenceObject(result->Symbol); - PhFree(result); - } - - PhReleaseQueuedLockExclusive(&Context->ResultListLock); - - PhFree(Context); - } -} - -static NTSTATUS EtpSymbolLookupFunction( - _In_ PVOID Parameter - ) -{ - PSYMBOL_LOOKUP_RESULT result; - - result = Parameter; - - // Don't bother looking up the symbol if the window has already closed. - if (result->Context->Destroying) - { - EtpDereferenceWsWatchContext(result->Context); - PhFree(result); - return STATUS_SUCCESS; - } - - result->Symbol = PhGetSymbolFromAddress( - result->Context->SymbolProvider, - (ULONG64)result->Address, - NULL, - NULL, - NULL, - NULL - ); - - // Fail if we don't have a symbol. - if (!result->Symbol) - { - EtpDereferenceWsWatchContext(result->Context); - PhFree(result); - return STATUS_SUCCESS; - } - - PhAcquireQueuedLockExclusive(&result->Context->ResultListLock); - PushEntryList(&result->Context->ResultListHead, &result->ListEntry); - PhReleaseQueuedLockExclusive(&result->Context->ResultListLock); - EtpDereferenceWsWatchContext(result->Context); - - return STATUS_SUCCESS; -} - -static VOID EtpQueueSymbolLookup( - _In_ PWS_WATCH_CONTEXT Context, - _In_ PVOID Address - ) -{ - PSYMBOL_LOOKUP_RESULT result; - - result = PhAllocate(sizeof(SYMBOL_LOOKUP_RESULT)); - result->Context = Context; - result->Address = Address; - EtpReferenceWsWatchContext(Context); - - PhQueueItemWorkQueue(PhGetGlobalWorkQueue(), EtpSymbolLookupFunction, result); -} - -static PPH_STRING EtpGetBasicSymbol( - _In_ PPH_SYMBOL_PROVIDER SymbolProvider, - _In_ ULONG64 Address - ) -{ - ULONG64 modBase; - PPH_STRING fileName = NULL; - PPH_STRING baseName = NULL; - PPH_STRING symbol; - - modBase = PhGetModuleFromAddress(SymbolProvider, Address, &fileName); - - if (!fileName) - { - symbol = PhCreateStringEx(NULL, PH_PTR_STR_LEN * 2); - PhPrintPointer(symbol->Buffer, (PVOID)Address); - PhTrimToNullTerminatorString(symbol); - } - else - { - PH_FORMAT format[3]; - - baseName = PhGetBaseName(fileName); - - PhInitFormatSR(&format[0], baseName->sr); - PhInitFormatS(&format[1], L"+0x"); - PhInitFormatIX(&format[2], (ULONG_PTR)(Address - modBase)); - - symbol = PhFormat(format, 3, baseName->Length + 6 + 32); - } - - if (fileName) - PhDereferenceObject(fileName); - if (baseName) - PhDereferenceObject(baseName); - - return symbol; -} - -static VOID EtpProcessSymbolLookupResults( - _In_ HWND hwndDlg, - _In_ PWS_WATCH_CONTEXT Context - ) -{ - PSINGLE_LIST_ENTRY listEntry; - - // Remove all results. - PhAcquireQueuedLockExclusive(&Context->ResultListLock); - listEntry = Context->ResultListHead.Next; - Context->ResultListHead.Next = NULL; - PhReleaseQueuedLockExclusive(&Context->ResultListLock); - - // Update the list view with the results. - while (listEntry) - { - PSYMBOL_LOOKUP_RESULT result; - - result = CONTAINING_RECORD(listEntry, SYMBOL_LOOKUP_RESULT, ListEntry); - listEntry = listEntry->Next; - - PhSetListViewSubItem( - Context->ListViewHandle, - PhFindListViewItemByParam(Context->ListViewHandle, -1, result->Address), - 0, - result->Symbol->Buffer - ); - - PhDereferenceObject(result->Symbol); - PhFree(result); - } -} - -static BOOLEAN EtpUpdateWsWatch( - _In_ HWND hwndDlg, - _In_ PWS_WATCH_CONTEXT Context - ) -{ - NTSTATUS status; - BOOLEAN result; - ULONG returnLength; - PPROCESS_WS_WATCH_INFORMATION_EX wsWatchInfo; - - // Query WS watch information. - - if (!Context->Buffer) - return FALSE; - - status = NtQueryInformationProcess( - Context->ProcessHandle, - ProcessWorkingSetWatchEx, - Context->Buffer, - Context->BufferSize, - &returnLength - ); - - if (status == STATUS_UNSUCCESSFUL) - { - // WS Watch is not enabled. - return FALSE; - } - - if (status == STATUS_NO_MORE_ENTRIES) - { - // There were no new faults, but we still need to process symbol lookup results. - result = TRUE; - goto SkipBuffer; - } - - if (status == STATUS_BUFFER_TOO_SMALL || status == STATUS_INFO_LENGTH_MISMATCH) - { - PhFree(Context->Buffer); - Context->Buffer = PhAllocate(returnLength); - Context->BufferSize = returnLength; - - status = NtQueryInformationProcess( - Context->ProcessHandle, - ProcessWorkingSetWatchEx, - Context->Buffer, - Context->BufferSize, - &returnLength - ); - } - - if (!NT_SUCCESS(status)) - { - // Error related to the buffer size. Try again later. - result = FALSE; - goto SkipBuffer; - } - - // Update the hashtable and list view. - - ExtendedListView_SetRedraw(Context->ListViewHandle, FALSE); - - wsWatchInfo = Context->Buffer; - - while (wsWatchInfo->BasicInfo.FaultingPc) - { - PVOID *entry; - WCHAR buffer[PH_INT32_STR_LEN_1]; - INT lvItemIndex; - ULONG newCount; - - // Update the count in the entry for this instruction pointer, or add a new entry if it doesn't exist. - - entry = PhFindItemSimpleHashtable(Context->Hashtable, wsWatchInfo->BasicInfo.FaultingPc); - - if (entry) - { - newCount = PtrToUlong(*entry) + 1; - *entry = UlongToPtr(newCount); - lvItemIndex = PhFindListViewItemByParam(Context->ListViewHandle, -1, wsWatchInfo->BasicInfo.FaultingPc); - } - else - { - PPH_STRING basicSymbol; - - newCount = 1; - PhAddItemSimpleHashtable(Context->Hashtable, wsWatchInfo->BasicInfo.FaultingPc, UlongToPtr(1)); - - // Get a basic symbol name (module+offset). - basicSymbol = EtpGetBasicSymbol(Context->SymbolProvider, (ULONG64)wsWatchInfo->BasicInfo.FaultingPc); - - lvItemIndex = PhAddListViewItem(Context->ListViewHandle, MAXINT, basicSymbol->Buffer, wsWatchInfo->BasicInfo.FaultingPc); - PhDereferenceObject(basicSymbol); - - // Queue a full symbol lookup. - EtpQueueSymbolLookup(Context, wsWatchInfo->BasicInfo.FaultingPc); - } - - // Update the count in the list view item. - PhPrintUInt32(buffer, newCount); - PhSetListViewSubItem( - Context->ListViewHandle, - lvItemIndex, - 1, - buffer - ); - - wsWatchInfo++; - } - - ExtendedListView_SetRedraw(Context->ListViewHandle, TRUE); - result = TRUE; - -SkipBuffer: - EtpProcessSymbolLookupResults(hwndDlg, Context); - ExtendedListView_SortItems(Context->ListViewHandle); - - return result; -} - -static BOOLEAN NTAPI EnumGenericModulesCallback( - _In_ PPH_MODULE_INFO Module, - _In_opt_ PVOID Context - ) -{ - PWS_WATCH_CONTEXT context = Context; - - // If we're loading kernel module symbols for a process other than - // System, ignore modules which are in user space. This may happen - // in Windows 7. - if ( - context->LoadingSymbolsForProcessId == SYSTEM_PROCESS_ID && - (ULONG_PTR)Module->BaseAddress <= PhSystemBasicInformation.MaximumUserModeAddress - ) - return TRUE; - - PhLoadModuleSymbolProvider(context->SymbolProvider, Module->FileName->Buffer, - (ULONG64)Module->BaseAddress, Module->Size); - - return TRUE; -} - -INT_PTR CALLBACK EtpWsWatchDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - PWS_WATCH_CONTEXT context; - - if (uMsg == WM_INITDIALOG) - { - context = (PWS_WATCH_CONTEXT)lParam; - SetProp(hwndDlg, L"Context", (HANDLE)context); - } - else - { - context = (PWS_WATCH_CONTEXT)GetProp(hwndDlg, L"Context"); - - if (uMsg == WM_DESTROY) - RemoveProp(hwndDlg, L"Context"); - } - - if (!context) - return FALSE; - - switch (uMsg) - { - case WM_INITDIALOG: - { - HWND lvHandle; - - PhCenterWindow(hwndDlg, GetParent(hwndDlg)); - - context->WindowHandle = hwndDlg; - context->ListViewHandle = lvHandle = GetDlgItem(hwndDlg, IDC_LIST); - - PhSetListViewStyle(lvHandle, FALSE, TRUE); - PhSetControlTheme(lvHandle, L"explorer"); - PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 340, L"Instruction"); - PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 80, L"Count"); - PhSetExtendedListView(lvHandle); - ExtendedListView_SetSort(lvHandle, 1, DescendingSortOrder); - - context->Hashtable = PhCreateSimpleHashtable(64); - context->BufferSize = 0x2000; - context->Buffer = PhAllocate(context->BufferSize); - - PhInitializeQueuedLock(&context->ResultListLock); - context->SymbolProvider = PhCreateSymbolProvider(context->ProcessItem->ProcessId); - PhLoadSymbolProviderOptions(context->SymbolProvider); - - if (!context->SymbolProvider || !context->SymbolProvider->IsRealHandle) - { - PhShowError(hwndDlg, L"Unable to open the process."); - EndDialog(hwndDlg, IDCANCEL); - break; - } - - context->ProcessHandle = context->SymbolProvider->ProcessHandle; - - // Load symbols for both process and kernel modules. - context->LoadingSymbolsForProcessId = context->ProcessItem->ProcessId; - PhEnumGenericModules( - NULL, - context->ProcessHandle, - 0, - EnumGenericModulesCallback, - context - ); - context->LoadingSymbolsForProcessId = SYSTEM_PROCESS_ID; - PhEnumGenericModules( - SYSTEM_PROCESS_ID, - NULL, - 0, - EnumGenericModulesCallback, - context - ); - - context->Enabled = EtpUpdateWsWatch(hwndDlg, context); - - if (context->Enabled) - { - // WS Watch is already enabled for the process. Enable updating. - EnableWindow(GetDlgItem(hwndDlg, IDC_ENABLE), FALSE); - ShowWindow(GetDlgItem(hwndDlg, IDC_WSWATCHENABLED), SW_SHOW); - SetTimer(hwndDlg, 1, 1000, NULL); - } - else - { - // WS Watch has not yet been enabled for the process. - } - } - break; - case WM_DESTROY: - { - context->Destroying = TRUE; - - PhDereferenceObject(context->Hashtable); - - if (context->Buffer) - { - PhFree(context->Buffer); - context->Buffer = NULL; - } - } - break; - case WM_COMMAND: - { - switch (LOWORD(wParam)) - { - case IDCANCEL: - case IDOK: - EndDialog(hwndDlg, IDOK); - break; - case IDC_ENABLE: - { - NTSTATUS status; - HANDLE processHandle; - - if (NT_SUCCESS(status = PhOpenProcess( - &processHandle, - PROCESS_SET_INFORMATION, - context->ProcessItem->ProcessId - ))) - { - status = NtSetInformationProcess( - processHandle, - ProcessWorkingSetWatchEx, - NULL, - 0 - ); - NtClose(processHandle); - } - - if (NT_SUCCESS(status)) - { - EnableWindow(GetDlgItem(hwndDlg, IDC_ENABLE), FALSE); - ShowWindow(GetDlgItem(hwndDlg, IDC_WSWATCHENABLED), SW_SHOW); - SetTimer(hwndDlg, 1, 1000, NULL); - } - else - { - PhShowStatus(hwndDlg, L"Unable to enable WS watch", status, 0); - } - } - break; - } - } - break; - case WM_NOTIFY: - { - PhHandleListViewNotifyForCopy(lParam, context->ListViewHandle); - } - break; - case WM_TIMER: - { - switch (wParam) - { - case 1: - { - EtpUpdateWsWatch(hwndDlg, context); - } - break; - } - } - break; - } - - return FALSE; -} +/* + * Process Hacker Extended Tools - + * working set watch + * + * Copyright (C) 2011 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include "exttools.h" +#include +#include + +typedef struct _WS_WATCH_CONTEXT +{ + LONG RefCount; + + PPH_PROCESS_ITEM ProcessItem; + HWND WindowHandle; + HWND ListViewHandle; + BOOLEAN Enabled; + BOOLEAN Destroying; + PPH_HASHTABLE Hashtable; + HANDLE ProcessHandle; + PVOID Buffer; + ULONG BufferSize; + + PPH_SYMBOL_PROVIDER SymbolProvider; + HANDLE LoadingSymbolsForProcessId; + SINGLE_LIST_ENTRY ResultListHead; + PH_QUEUED_LOCK ResultListLock; +} WS_WATCH_CONTEXT, *PWS_WATCH_CONTEXT; + +typedef struct _SYMBOL_LOOKUP_RESULT +{ + SINGLE_LIST_ENTRY ListEntry; + PWS_WATCH_CONTEXT Context; + PVOID Address; + PPH_STRING Symbol; +} SYMBOL_LOOKUP_RESULT, *PSYMBOL_LOOKUP_RESULT; + +VOID EtpReferenceWsWatchContext( + _Inout_ PWS_WATCH_CONTEXT Context + ); + +VOID EtpDereferenceWsWatchContext( + _Inout_ PWS_WATCH_CONTEXT Context + ); + +INT_PTR CALLBACK EtpWsWatchDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +VOID EtShowWsWatchDialog( + _In_ HWND ParentWindowHandle, + _In_ PPH_PROCESS_ITEM ProcessItem + ) +{ + PWS_WATCH_CONTEXT context; + + context = PhAllocate(sizeof(WS_WATCH_CONTEXT)); + memset(context, 0, sizeof(WS_WATCH_CONTEXT)); + context->RefCount = 1; + context->ProcessItem = ProcessItem; + + DialogBoxParam( + PluginInstance->DllBase, + MAKEINTRESOURCE(IDD_WSWATCH), + ParentWindowHandle, + EtpWsWatchDlgProc, + (LPARAM)context + ); + EtpDereferenceWsWatchContext(context); +} + +static VOID EtpReferenceWsWatchContext( + _Inout_ PWS_WATCH_CONTEXT Context + ) +{ + _InterlockedIncrement(&Context->RefCount); +} + +static VOID EtpDereferenceWsWatchContext( + _Inout_ PWS_WATCH_CONTEXT Context + ) +{ + if (_InterlockedDecrement(&Context->RefCount) == 0) + { + PSINGLE_LIST_ENTRY listEntry; + + if (Context->SymbolProvider) + PhDereferenceObject(Context->SymbolProvider); + + // Free all unused results. + + PhAcquireQueuedLockExclusive(&Context->ResultListLock); + + listEntry = Context->ResultListHead.Next; + + while (listEntry) + { + PSYMBOL_LOOKUP_RESULT result; + + result = CONTAINING_RECORD(listEntry, SYMBOL_LOOKUP_RESULT, ListEntry); + listEntry = listEntry->Next; + PhDereferenceObject(result->Symbol); + PhFree(result); + } + + PhReleaseQueuedLockExclusive(&Context->ResultListLock); + + PhFree(Context); + } +} + +static NTSTATUS EtpSymbolLookupFunction( + _In_ PVOID Parameter + ) +{ + PSYMBOL_LOOKUP_RESULT result; + + result = Parameter; + + // Don't bother looking up the symbol if the window has already closed. + if (result->Context->Destroying) + { + EtpDereferenceWsWatchContext(result->Context); + PhFree(result); + return STATUS_SUCCESS; + } + + result->Symbol = PhGetSymbolFromAddress( + result->Context->SymbolProvider, + (ULONG64)result->Address, + NULL, + NULL, + NULL, + NULL + ); + + // Fail if we don't have a symbol. + if (!result->Symbol) + { + EtpDereferenceWsWatchContext(result->Context); + PhFree(result); + return STATUS_SUCCESS; + } + + PhAcquireQueuedLockExclusive(&result->Context->ResultListLock); + PushEntryList(&result->Context->ResultListHead, &result->ListEntry); + PhReleaseQueuedLockExclusive(&result->Context->ResultListLock); + EtpDereferenceWsWatchContext(result->Context); + + return STATUS_SUCCESS; +} + +static VOID EtpQueueSymbolLookup( + _In_ PWS_WATCH_CONTEXT Context, + _In_ PVOID Address + ) +{ + PSYMBOL_LOOKUP_RESULT result; + + result = PhAllocate(sizeof(SYMBOL_LOOKUP_RESULT)); + result->Context = Context; + result->Address = Address; + EtpReferenceWsWatchContext(Context); + + PhQueueItemWorkQueue(PhGetGlobalWorkQueue(), EtpSymbolLookupFunction, result); +} + +static PPH_STRING EtpGetBasicSymbol( + _In_ PPH_SYMBOL_PROVIDER SymbolProvider, + _In_ ULONG64 Address + ) +{ + ULONG64 modBase; + PPH_STRING fileName = NULL; + PPH_STRING baseName = NULL; + PPH_STRING symbol; + + modBase = PhGetModuleFromAddress(SymbolProvider, Address, &fileName); + + if (!fileName) + { + symbol = PhCreateStringEx(NULL, PH_PTR_STR_LEN * 2); + PhPrintPointer(symbol->Buffer, (PVOID)Address); + PhTrimToNullTerminatorString(symbol); + } + else + { + PH_FORMAT format[3]; + + baseName = PhGetBaseName(fileName); + + PhInitFormatSR(&format[0], baseName->sr); + PhInitFormatS(&format[1], L"+0x"); + PhInitFormatIX(&format[2], (ULONG_PTR)(Address - modBase)); + + symbol = PhFormat(format, 3, baseName->Length + 6 + 32); + } + + if (fileName) + PhDereferenceObject(fileName); + if (baseName) + PhDereferenceObject(baseName); + + return symbol; +} + +static VOID EtpProcessSymbolLookupResults( + _In_ HWND hwndDlg, + _In_ PWS_WATCH_CONTEXT Context + ) +{ + PSINGLE_LIST_ENTRY listEntry; + + // Remove all results. + PhAcquireQueuedLockExclusive(&Context->ResultListLock); + listEntry = Context->ResultListHead.Next; + Context->ResultListHead.Next = NULL; + PhReleaseQueuedLockExclusive(&Context->ResultListLock); + + // Update the list view with the results. + while (listEntry) + { + PSYMBOL_LOOKUP_RESULT result; + + result = CONTAINING_RECORD(listEntry, SYMBOL_LOOKUP_RESULT, ListEntry); + listEntry = listEntry->Next; + + PhSetListViewSubItem( + Context->ListViewHandle, + PhFindListViewItemByParam(Context->ListViewHandle, -1, result->Address), + 0, + result->Symbol->Buffer + ); + + PhDereferenceObject(result->Symbol); + PhFree(result); + } +} + +static BOOLEAN EtpUpdateWsWatch( + _In_ HWND hwndDlg, + _In_ PWS_WATCH_CONTEXT Context + ) +{ + NTSTATUS status; + BOOLEAN result; + ULONG returnLength; + PPROCESS_WS_WATCH_INFORMATION_EX wsWatchInfo; + + // Query WS watch information. + + if (!Context->Buffer) + return FALSE; + + status = NtQueryInformationProcess( + Context->ProcessHandle, + ProcessWorkingSetWatchEx, + Context->Buffer, + Context->BufferSize, + &returnLength + ); + + if (status == STATUS_UNSUCCESSFUL) + { + // WS Watch is not enabled. + return FALSE; + } + + if (status == STATUS_NO_MORE_ENTRIES) + { + // There were no new faults, but we still need to process symbol lookup results. + result = TRUE; + goto SkipBuffer; + } + + if (status == STATUS_BUFFER_TOO_SMALL || status == STATUS_INFO_LENGTH_MISMATCH) + { + PhFree(Context->Buffer); + Context->Buffer = PhAllocate(returnLength); + Context->BufferSize = returnLength; + + status = NtQueryInformationProcess( + Context->ProcessHandle, + ProcessWorkingSetWatchEx, + Context->Buffer, + Context->BufferSize, + &returnLength + ); + } + + if (!NT_SUCCESS(status)) + { + // Error related to the buffer size. Try again later. + result = FALSE; + goto SkipBuffer; + } + + // Update the hashtable and list view. + + ExtendedListView_SetRedraw(Context->ListViewHandle, FALSE); + + wsWatchInfo = Context->Buffer; + + while (wsWatchInfo->BasicInfo.FaultingPc) + { + PVOID *entry; + WCHAR buffer[PH_INT32_STR_LEN_1]; + INT lvItemIndex; + ULONG newCount; + + // Update the count in the entry for this instruction pointer, or add a new entry if it doesn't exist. + + entry = PhFindItemSimpleHashtable(Context->Hashtable, wsWatchInfo->BasicInfo.FaultingPc); + + if (entry) + { + newCount = PtrToUlong(*entry) + 1; + *entry = UlongToPtr(newCount); + lvItemIndex = PhFindListViewItemByParam(Context->ListViewHandle, -1, wsWatchInfo->BasicInfo.FaultingPc); + } + else + { + PPH_STRING basicSymbol; + + newCount = 1; + PhAddItemSimpleHashtable(Context->Hashtable, wsWatchInfo->BasicInfo.FaultingPc, UlongToPtr(1)); + + // Get a basic symbol name (module+offset). + basicSymbol = EtpGetBasicSymbol(Context->SymbolProvider, (ULONG64)wsWatchInfo->BasicInfo.FaultingPc); + + lvItemIndex = PhAddListViewItem(Context->ListViewHandle, MAXINT, basicSymbol->Buffer, wsWatchInfo->BasicInfo.FaultingPc); + PhDereferenceObject(basicSymbol); + + // Queue a full symbol lookup. + EtpQueueSymbolLookup(Context, wsWatchInfo->BasicInfo.FaultingPc); + } + + // Update the count in the list view item. + PhPrintUInt32(buffer, newCount); + PhSetListViewSubItem( + Context->ListViewHandle, + lvItemIndex, + 1, + buffer + ); + + wsWatchInfo++; + } + + ExtendedListView_SetRedraw(Context->ListViewHandle, TRUE); + result = TRUE; + +SkipBuffer: + EtpProcessSymbolLookupResults(hwndDlg, Context); + ExtendedListView_SortItems(Context->ListViewHandle); + + return result; +} + +static BOOLEAN NTAPI EnumGenericModulesCallback( + _In_ PPH_MODULE_INFO Module, + _In_opt_ PVOID Context + ) +{ + PWS_WATCH_CONTEXT context = Context; + + // If we're loading kernel module symbols for a process other than + // System, ignore modules which are in user space. This may happen + // in Windows 7. + if ( + context->LoadingSymbolsForProcessId == SYSTEM_PROCESS_ID && + (ULONG_PTR)Module->BaseAddress <= PhSystemBasicInformation.MaximumUserModeAddress + ) + return TRUE; + + PhLoadModuleSymbolProvider(context->SymbolProvider, Module->FileName->Buffer, + (ULONG64)Module->BaseAddress, Module->Size); + + return TRUE; +} + +INT_PTR CALLBACK EtpWsWatchDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + PWS_WATCH_CONTEXT context; + + if (uMsg == WM_INITDIALOG) + { + context = (PWS_WATCH_CONTEXT)lParam; + SetProp(hwndDlg, L"Context", (HANDLE)context); + } + else + { + context = (PWS_WATCH_CONTEXT)GetProp(hwndDlg, L"Context"); + + if (uMsg == WM_DESTROY) + RemoveProp(hwndDlg, L"Context"); + } + + if (!context) + return FALSE; + + switch (uMsg) + { + case WM_INITDIALOG: + { + HWND lvHandle; + + PhCenterWindow(hwndDlg, GetParent(hwndDlg)); + + context->WindowHandle = hwndDlg; + context->ListViewHandle = lvHandle = GetDlgItem(hwndDlg, IDC_LIST); + + PhSetListViewStyle(lvHandle, FALSE, TRUE); + PhSetControlTheme(lvHandle, L"explorer"); + PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 340, L"Instruction"); + PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 80, L"Count"); + PhSetExtendedListView(lvHandle); + ExtendedListView_SetSort(lvHandle, 1, DescendingSortOrder); + + context->Hashtable = PhCreateSimpleHashtable(64); + context->BufferSize = 0x2000; + context->Buffer = PhAllocate(context->BufferSize); + + PhInitializeQueuedLock(&context->ResultListLock); + context->SymbolProvider = PhCreateSymbolProvider(context->ProcessItem->ProcessId); + PhLoadSymbolProviderOptions(context->SymbolProvider); + + if (!context->SymbolProvider || !context->SymbolProvider->IsRealHandle) + { + PhShowError(hwndDlg, L"Unable to open the process."); + EndDialog(hwndDlg, IDCANCEL); + break; + } + + context->ProcessHandle = context->SymbolProvider->ProcessHandle; + + // Load symbols for both process and kernel modules. + context->LoadingSymbolsForProcessId = context->ProcessItem->ProcessId; + PhEnumGenericModules( + NULL, + context->ProcessHandle, + 0, + EnumGenericModulesCallback, + context + ); + context->LoadingSymbolsForProcessId = SYSTEM_PROCESS_ID; + PhEnumGenericModules( + SYSTEM_PROCESS_ID, + NULL, + 0, + EnumGenericModulesCallback, + context + ); + + context->Enabled = EtpUpdateWsWatch(hwndDlg, context); + + if (context->Enabled) + { + // WS Watch is already enabled for the process. Enable updating. + EnableWindow(GetDlgItem(hwndDlg, IDC_ENABLE), FALSE); + ShowWindow(GetDlgItem(hwndDlg, IDC_WSWATCHENABLED), SW_SHOW); + SetTimer(hwndDlg, 1, 1000, NULL); + } + else + { + // WS Watch has not yet been enabled for the process. + } + } + break; + case WM_DESTROY: + { + context->Destroying = TRUE; + + PhDereferenceObject(context->Hashtable); + + if (context->Buffer) + { + PhFree(context->Buffer); + context->Buffer = NULL; + } + } + break; + case WM_COMMAND: + { + switch (LOWORD(wParam)) + { + case IDCANCEL: + case IDOK: + EndDialog(hwndDlg, IDOK); + break; + case IDC_ENABLE: + { + NTSTATUS status; + HANDLE processHandle; + + if (NT_SUCCESS(status = PhOpenProcess( + &processHandle, + PROCESS_SET_INFORMATION, + context->ProcessItem->ProcessId + ))) + { + status = NtSetInformationProcess( + processHandle, + ProcessWorkingSetWatchEx, + NULL, + 0 + ); + NtClose(processHandle); + } + + if (NT_SUCCESS(status)) + { + EnableWindow(GetDlgItem(hwndDlg, IDC_ENABLE), FALSE); + ShowWindow(GetDlgItem(hwndDlg, IDC_WSWATCHENABLED), SW_SHOW); + SetTimer(hwndDlg, 1, 1000, NULL); + } + else + { + PhShowStatus(hwndDlg, L"Unable to enable WS watch", status, 0); + } + } + break; + } + } + break; + case WM_NOTIFY: + { + PhHandleListViewNotifyForCopy(lParam, context->ListViewHandle); + } + break; + case WM_TIMER: + { + switch (wParam) + { + case 1: + { + EtpUpdateWsWatch(hwndDlg, context); + } + break; + } + } + break; + } + + return FALSE; +} diff --git a/plugins/NetworkTools/CHANGELOG.txt b/plugins/NetworkTools/CHANGELOG.txt index 2cc9983b5553..17bdec0b9e13 100644 --- a/plugins/NetworkTools/CHANGELOG.txt +++ b/plugins/NetworkTools/CHANGELOG.txt @@ -1,32 +1,32 @@ -1.8 - * Added custom tracert and whois support - * Added geoip lookup for country name and image - -1.7 - * Added option to specify ping buffer length - * Removed legacy code - -1.6 - * Added PathPing support - -1.5 - * Improved ping graph scaling - -1.4 - * Fixed whois scrolling issue - * Fixed ping threading issues - * Fixed various memory leaks - -1.3 - * Added plugin options for ping/tracert/whois - * Added native ping/tracert/whois support - * Updated UI - -1.2 - * Fixed encoding bug - -1.1 - * Fixed handle leak - -1.0 - * Initial release +1.8 + * Added custom tracert and whois support + * Added geoip lookup for country name and image + +1.7 + * Added option to specify ping buffer length + * Removed legacy code + +1.6 + * Added PathPing support + +1.5 + * Improved ping graph scaling + +1.4 + * Fixed whois scrolling issue + * Fixed ping threading issues + * Fixed various memory leaks + +1.3 + * Added plugin options for ping/tracert/whois + * Added native ping/tracert/whois support + * Updated UI + +1.2 + * Fixed encoding bug + +1.1 + * Fixed handle leak + +1.0 + * Initial release diff --git a/plugins/NetworkTools/NetworkTools.rc b/plugins/NetworkTools/NetworkTools.rc index 5916e23269f9..928883c44c71 100644 --- a/plugins/NetworkTools/NetworkTools.rc +++ b/plugins/NetworkTools/NetworkTools.rc @@ -1,723 +1,723 @@ -// Microsoft Visual C++ generated resource script. -// -#include "resource.h" - -#define APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// -#include "winres.h" -///////////////////////////////////////////////////////////////////////////// -#undef APSTUDIO_READONLY_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -// English (Australia) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENA) -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_AUS -#pragma code_page(1252) - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -1 TEXTINCLUDE -BEGIN - "resource.h\0" -END - -2 TEXTINCLUDE -BEGIN - "#include ""winres.h""\0" -END - -3 TEXTINCLUDE -BEGIN - "\r\n" - "\0" -END - -#endif // APSTUDIO_INVOKED - - -///////////////////////////////////////////////////////////////////////////// -// -// Version -// - -VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,8,0,0 - PRODUCTVERSION 1,8,0,0 - FILEFLAGSMASK 0x3fL -#ifdef _DEBUG - FILEFLAGS 0x1L -#else - FILEFLAGS 0x0L -#endif - FILEOS 0x40004L - FILETYPE 0x2L - FILESUBTYPE 0x0L -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "0c0904b0" - BEGIN - VALUE "CompanyName", "dmex" - VALUE "FileDescription", "Network Tools plugin for Process Hacker" - VALUE "FileVersion", "1.8" - VALUE "InternalName", "ProcessHacker.NetworkTools" - VALUE "LegalCopyright", "Licensed under the GNU GPL, v3." - VALUE "OriginalFilename", "NetworkTools.dll" - VALUE "ProductName", "Network Tools plugin for Process Hacker" - VALUE "ProductVersion", "1.8" - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0xc09, 1200 - END -END - - -///////////////////////////////////////////////////////////////////////////// -// -// Dialog -// - -IDD_WHOIS DIALOGEX 0, 0, 389, 214 -STYLE DS_SETFONT | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME -EXSTYLE WS_EX_APPWINDOW -CAPTION "Network Tools" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - CONTROL "",IDC_NETOUTPUTEDIT,"RICHEDIT50W",WS_VSCROLL | WS_TABSTOP | 0x4,2,2,385,210 -END - -IDD_OPTIONS DIALOGEX 0, 0, 201, 57 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Options" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "Ping packet length:",IDC_STATIC,9,7,62,8 - EDITTEXT IDC_PINGPACKETLENGTH,7,17,89,14,ES_AUTOHSCROLL | ES_NUMBER - PUSHBUTTON "Close",IDCANCEL,135,36,60,14 - EDITTEXT IDC_MAXHOPS,105,17,89,14,ES_AUTOHSCROLL | ES_NUMBER - LTEXT "Max Tracert Hops:",IDC_STATIC,105,7,60,8 - PUSHBUTTON "Manage GeoIP Database",IDC_GEOIP,6,36,90,14 -END - -IDD_PING DIALOGEX 0, 0, 329, 151 -STYLE DS_SETFONT | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME -EXSTYLE WS_EX_APPWINDOW -CAPTION "Dialog" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "Pinging X with X bytes of data:",IDC_MAINTEXT,7,7,315,16 - LTEXT "PingGraphLayout",IDC_PING_LAYOUT,7,26,315,64,NOT WS_VISIBLE | WS_BORDER - GROUPBOX "Ping statistics",IDC_ICMP_PANEL,7,92,315,52,0,WS_EX_TRANSPARENT - LTEXT "Average: 0ms",IDC_ICMP_AVG,13,104,73,8 - LTEXT "Pings sent: 0",IDC_PINGS_SENT,91,104,88,8 - LTEXT "Bad replies: 0",IDC_BAD_HASH,187,104,90,8 - LTEXT "Minimum: 0ms",IDC_ICMP_MIN,13,116,73,8 - LTEXT "Pings lost: 0 (0%)",IDC_PINGS_LOST,91,116,88,8 - LTEXT "Anon replies: 0",IDC_ANON_ADDR,188,116,87,8 - LTEXT "Maximum: 0ms",IDC_ICMP_MAX,13,129,73,8 -END - -IDD_TRACERT DIALOGEX 0, 0, 389, 212 -STYLE DS_SETFONT | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME -CAPTION "Dialog" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "Tracing route to xyz...",IDC_STATUS,7,5,375,12 - DEFPUSHBUTTON "Close",IDCANCEL,333,191,50,14 - CONTROL "",IDC_LIST_TRACERT,"PhTreeNew",WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP | 0xa,7,22,375,166,WS_EX_CLIENTEDGE -END - - -///////////////////////////////////////////////////////////////////////////// -// -// PNG -// - -AD_PNG PNG "resources\\ad.png" - -AE_PNG PNG "resources\\ae.png" - -AF_PNG PNG "resources\\af.png" - -AG_PNG PNG "resources\\ag.png" - -AI_PNG PNG "resources\\ai.png" - -AL_PNG PNG "resources\\al.png" - -AM_PNG PNG "resources\\am.png" - -AN_PNG PNG "resources\\an.png" - -AO_PNG PNG "resources\\ao.png" - -AR_PNG PNG "resources\\ar.png" - -AS_PNG PNG "resources\\as.png" - -AT_PNG PNG "resources\\at.png" - -AU_PNG PNG "resources\\au.png" - -AW_PNG PNG "resources\\aw.png" - -AX_PNG PNG "resources\\ax.png" - -AZ_PNG PNG "resources\\az.png" - -BA_PNG PNG "resources\\ba.png" - -BB_PNG PNG "resources\\bb.png" - -BD_PNG PNG "resources\\bd.png" - -BE_PNG PNG "resources\\be.png" - -BF_PNG PNG "resources\\bf.png" - -BG_PNG PNG "resources\\bg.png" - -BH_PNG PNG "resources\\bh.png" - -BI__PNG PNG "resources\\bi.png" - -BJ_PNG PNG "resources\\bj.png" - -BM_PNG PNG "resources\\bm.png" - -BN_PNG PNG "resources\\bn.png" - -BO_PNG PNG "resources\\bo.png" - -BR_PNG PNG "resources\\br.png" - -BS_PNG PNG "resources\\bs.png" - -BT_PNG PNG "resources\\bt.png" - -BV_PNG PNG "resources\\bv.png" - -BW_PNG PNG "resources\\bw.png" - -BY_PNG PNG "resources\\by.png" - -BZ_PNG PNG "resources\\bz.png" - -CA_PNG PNG "resources\\ca.png" - -AAC_PNG PNG "resources\\catalonia.png" - -CC_PNG PNG "resources\\cc.png" - -CD_PNG PNG "resources\\cd.png" - -CF_PNG PNG "resources\\cf.png" - -CG_PNG PNG "resources\\cg.png" - -CH_PNG PNG "resources\\ch.png" - -CI_PNG PNG "resources\\ci.png" - -CK_PNG PNG "resources\\ck.png" - -CL_PNG PNG "resources\\cl.png" - -CM_PNG PNG "resources\\cm.png" - -CN_PNG PNG "resources\\cn.png" - -CO_PNG PNG "resources\\co.png" - -CR_PNG PNG "resources\\cr.png" - -CS_PNG PNG "resources\\cs.png" - -CU_PNG PNG "resources\\cu.png" - -CV_PNG PNG "resources\\cv.png" - -CX_PNG PNG "resources\\cx.png" - -CY_PNG PNG "resources\\cy.png" - -CZ_PNG PNG "resources\\cz.png" - -DE_PNG PNG "resources\\de.png" - -DJ_PNG PNG "resources\\dj.png" - -DK_PNG PNG "resources\\dk.png" - -DM_PNG PNG "resources\\dm.png" - -DO_PNG PNG "resources\\do.png" - -DZ_PNG PNG "resources\\dz.png" - -EC_PNG PNG "resources\\ec.png" - -EE_PNG PNG "resources\\ee.png" - -EG_PNG PNG "resources\\eg.png" - -EH_PNG PNG "resources\\eh.png" - -AAD_PNG PNG "resources\\england.png" - -ER_PNG PNG "resources\\er.png" - -ES_PNG PNG "resources\\es.png" - -ET_PNG PNG "resources\\et.png" - -AAE_PNG PNG "resources\\europeanunion.png" - -AAF_PNG PNG "resources\\fam.png" - -FI_PNG PNG "resources\\fi.png" - -FJ_PNG PNG "resources\\fj.png" - -FK_PNG PNG "resources\\fk.png" - -FM_PNG PNG "resources\\fm.png" - -FO_PNG PNG "resources\\fo.png" - -FR_PNG PNG "resources\\fr.png" - -GA_PNG PNG "resources\\ga.png" - -GB_PNG PNG "resources\\gb.png" - -GD_PNG PNG "resources\\gd.png" - -GE_PNG PNG "resources\\ge.png" - -GF_PNG PNG "resources\\gf.png" - -GH_PNG PNG "resources\\gh.png" - -GI_PNG PNG "resources\\gi.png" - -GL_PNG PNG "resources\\gl.png" - -GM_PNG PNG "resources\\gm.png" - -GN_PNG PNG "resources\\gn.png" - -GP_PNG PNG "resources\\gp.png" - -GQ_PNG PNG "resources\\gq.png" - -GR_PNG PNG "resources\\gr.png" - -GS_PNG PNG "resources\\gs.png" - -GT_PNG PNG "resources\\gt.png" - -GU_PNG PNG "resources\\gu.png" - -GW_PNG PNG "resources\\gw.png" - -GY_PNG PNG "resources\\gy.png" - -HK_PNG PNG "resources\\hk.png" - -HM_PNG PNG "resources\\hm.png" - -HN_PNG PNG "resources\\hn.png" - -HR_PNG PNG "resources\\hr.png" - -HT_PNG PNG "resources\\ht.png" - -HU_PNG PNG "resources\\hu.png" - -ID_PNG PNG "resources\\id.png" - -IE_PNG PNG "resources\\ie.png" - -IL_PNG PNG "resources\\il.png" - -IN_PNG PNG "resources\\in.png" - -IO_PNG PNG "resources\\io.png" - -IQ_PNG PNG "resources\\iq.png" - -IR_PNG PNG "resources\\ir.png" - -IS_PNG PNG "resources\\is.png" - -IT_PNG PNG "resources\\it.png" - -JM_PNG PNG "resources\\jm.png" - -JO_PNG PNG "resources\\jo.png" - -JP_PNG PNG "resources\\jp.png" - -KE_PNG PNG "resources\\ke.png" - -KG_PNG PNG "resources\\kg.png" - -KH_PNG PNG "resources\\kh.png" - -KI_PNG PNG "resources\\ki.png" - -KM_PNG PNG "resources\\km.png" - -KN_PNG PNG "resources\\kn.png" - -KP_PNG PNG "resources\\kp.png" - -KR_PNG PNG "resources\\kr.png" - -KW_PNG PNG "resources\\kw.png" - -KY_PNG PNG "resources\\ky.png" - -KZ_PNG PNG "resources\\kz.png" - -LA_PNG PNG "resources\\la.png" - -LB_PNG PNG "resources\\lb.png" - -LC_PNG PNG "resources\\lc.png" - -LI_PNG PNG "resources\\li.png" - -LK_PNG PNG "resources\\lk.png" - -LR_PNG PNG "resources\\lr.png" - -LS_PNG PNG "resources\\ls.png" - -LT_PNG PNG "resources\\lt.png" - -LU_PNG PNG "resources\\lu.png" - -LV_PNG PNG "resources\\lv.png" - -LY_PNG PNG "resources\\ly.png" - -MA_PNG PNG "resources\\ma.png" - -MC_PNG PNG "resources\\mc.png" - -MD_PNG PNG "resources\\md.png" - -ME_PNG PNG "resources\\me.png" - -MG_PNG PNG "resources\\mg.png" - -MH_PNG PNG "resources\\mh.png" - -MK_PNG PNG "resources\\mk.png" - -ML_PNG PNG "resources\\ml.png" - -MM_PNG PNG "resources\\mm.png" - -MN_PNG PNG "resources\\mn.png" - -MO_PNG PNG "resources\\mo.png" - -MP_PNG PNG "resources\\mp.png" - -MQ_PNG PNG "resources\\mq.png" - -MR_PNG PNG "resources\\mr.png" - -MS_PNG PNG "resources\\ms.png" - -MT_PNG PNG "resources\\mt.png" - -MU_PNG PNG "resources\\mu.png" - -MV_PNG PNG "resources\\mv.png" - -MW_PNG PNG "resources\\mw.png" - -MX_PNG PNG "resources\\mx.png" - -MY_PNG PNG "resources\\my.png" - -MZ_PNG PNG "resources\\mz.png" - -NA_PNG PNG "resources\\na.png" - -NC_PNG PNG "resources\\nc.png" - -NE_PNG PNG "resources\\ne.png" - -NF_PNG PNG "resources\\nf.png" - -NG_PNG PNG "resources\\ng.png" - -NI_PNG PNG "resources\\ni.png" - -NL_PNG PNG "resources\\nl.png" - -NO_PNG PNG "resources\\no.png" - -NP_PNG PNG "resources\\np.png" - -NR_PNG PNG "resources\\nr.png" - -NU_PNG PNG "resources\\nu.png" - -NZ_PNG PNG "resources\\nz.png" - -OM_PNG PNG "resources\\om.png" - -PA_PNG PNG "resources\\pa.png" - -PE_PNG PNG "resources\\pe.png" - -PF_PNG PNG "resources\\pf.png" - -PG_PNG PNG "resources\\pg.png" - -PH_PNG PNG "resources\\ph.png" - -PK_PNG PNG "resources\\pk.png" - -PL_PNG PNG "resources\\pl.png" - -PM_PNG PNG "resources\\pm.png" - -PN_PNG PNG "resources\\pn.png" - -PR_PNG PNG "resources\\pr.png" - -PS_PNG PNG "resources\\ps.png" - -PT_PNG PNG "resources\\pt.png" - -PW_PNG PNG "resources\\pw.png" - -PY_PNG PNG "resources\\py.png" - -QA_PNG PNG "resources\\qa.png" - -RE_PNG PNG "resources\\re.png" - -RO_PNG PNG "resources\\ro.png" - -RS_PNG PNG "resources\\rs.png" - -RU_PNG PNG "resources\\ru.png" - -RW_PNG PNG "resources\\rw.png" - -SA_PNG PNG "resources\\sa.png" - -SB_PNG PNG "resources\\sb.png" - -SC_PNG PNG "resources\\sc.png" - -AAA_PNG PNG "resources\\scotland.png" - -SD_PNG PNG "resources\\sd.png" - -SE_PNG PNG "resources\\se.png" - -SG_PNG PNG "resources\\sg.png" - -SH_PNG PNG "resources\\sh.png" - -SI_PNG PNG "resources\\si.png" - -SJ_PNG PNG "resources\\sj.png" - -SK_PNG PNG "resources\\sk.png" - -SL_PNG PNG "resources\\sl.png" - -SM_PNG PNG "resources\\sm.png" - -SN_PNG PNG "resources\\sn.png" - -SO_PNG PNG "resources\\so.png" - -SR_PNG PNG "resources\\sr.png" - -ST_PNG PNG "resources\\st.png" - -SV_PNG PNG "resources\\sv.png" - -SY_PNG PNG "resources\\sy.png" - -SZ_PNG PNG "resources\\sz.png" - -TC_PNG PNG "resources\\tc.png" - -TD_PNG PNG "resources\\td.png" - -TF_PNG PNG "resources\\tf.png" - -TG_PNG PNG "resources\\tg.png" - -TH_PNG PNG "resources\\th.png" - -TJ_PNG PNG "resources\\tj.png" - -TK_PNG PNG "resources\\tk.png" - -TL_PNG PNG "resources\\tl.png" - -TM_PNG PNG "resources\\tm.png" - -TN_PNG PNG "resources\\tn.png" - -TO_PNG PNG "resources\\to.png" - -TR_PNG PNG "resources\\tr.png" - -TT_PNG PNG "resources\\tt.png" - -TV_PNG PNG "resources\\tv.png" - -TW_PNG PNG "resources\\tw.png" - -TZ_PNG PNG "resources\\tz.png" - -UA_PNG PNG "resources\\ua.png" - -UG_PNG PNG "resources\\ug.png" - -UM_PNG PNG "resources\\um.png" - -US_PNG PNG "resources\\us.png" - -UY_PNG PNG "resources\\uy.png" - -UZ_PNG PNG "resources\\uz.png" - -VA_PNG PNG "resources\\va.png" - -VC_PNG PNG "resources\\vc.png" - -VE_PNG PNG "resources\\ve.png" - -VG_PNG PNG "resources\\vg.png" - -VI_PNG PNG "resources\\vi.png" - -VN_PNG PNG "resources\\vn.png" - -VU_PNG PNG "resources\\vu.png" - -AAB_PNG PNG "resources\\wales.png" - -WF_PNG PNG "resources\\wf.png" - -WS_PNG PNG "resources\\ws.png" - -YE_PNG PNG "resources\\ye.png" - -YT_PNG PNG "resources\\yt.png" - -ZA_PNG PNG "resources\\za.png" - -ZM_PNG PNG "resources\\zm.png" - -ZW_PNG PNG "resources\\zw.png" - - -///////////////////////////////////////////////////////////////////////////// -// -// DESIGNINFO -// - -#ifdef APSTUDIO_INVOKED -GUIDELINES DESIGNINFO -BEGIN - IDD_WHOIS, DIALOG - BEGIN - LEFTMARGIN, 2 - RIGHTMARGIN, 387 - TOPMARGIN, 2 - BOTTOMMARGIN, 212 - END - - IDD_OPTIONS, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 194 - TOPMARGIN, 7 - BOTTOMMARGIN, 50 - END - - IDD_PING, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 322 - TOPMARGIN, 7 - BOTTOMMARGIN, 144 - END - - IDD_TRACERT, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 382 - TOPMARGIN, 7 - BOTTOMMARGIN, 205 - END -END -#endif // APSTUDIO_INVOKED - - -///////////////////////////////////////////////////////////////////////////// -// -// AFX_DIALOG_LAYOUT -// - -IDD_WHOIS AFX_DIALOG_LAYOUT -BEGIN - 0 -END - -IDD_OPTIONS AFX_DIALOG_LAYOUT -BEGIN - 0 -END - -IDD_TRACERT AFX_DIALOG_LAYOUT -BEGIN - 0 -END - -IDD_PING AFX_DIALOG_LAYOUT -BEGIN - 0 -END - -#endif // English (Australia) resources -///////////////////////////////////////////////////////////////////////////// - - - -#ifndef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// - - -///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED - +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "winres.h" +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (Australia) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENA) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_AUS +#pragma code_page(1252) + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""winres.h""\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,8,0,0 + PRODUCTVERSION 1,8,0,0 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "0c0904b0" + BEGIN + VALUE "CompanyName", "dmex" + VALUE "FileDescription", "Network Tools plugin for Process Hacker" + VALUE "FileVersion", "1.8" + VALUE "InternalName", "ProcessHacker.NetworkTools" + VALUE "LegalCopyright", "Licensed under the GNU GPL, v3." + VALUE "OriginalFilename", "NetworkTools.dll" + VALUE "ProductName", "Network Tools plugin for Process Hacker" + VALUE "ProductVersion", "1.8" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0xc09, 1200 + END +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_WHOIS DIALOGEX 0, 0, 389, 214 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME +EXSTYLE WS_EX_APPWINDOW +CAPTION "Network Tools" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + CONTROL "",IDC_NETOUTPUTEDIT,"RICHEDIT50W",WS_VSCROLL | WS_TABSTOP | 0x4,2,2,385,210 +END + +IDD_OPTIONS DIALOGEX 0, 0, 201, 57 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Options" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "Ping packet length:",IDC_STATIC,9,7,62,8 + EDITTEXT IDC_PINGPACKETLENGTH,7,17,89,14,ES_AUTOHSCROLL | ES_NUMBER + PUSHBUTTON "Close",IDCANCEL,135,36,60,14 + EDITTEXT IDC_MAXHOPS,105,17,89,14,ES_AUTOHSCROLL | ES_NUMBER + LTEXT "Max Tracert Hops:",IDC_STATIC,105,7,60,8 + PUSHBUTTON "Manage GeoIP Database",IDC_GEOIP,6,36,90,14 +END + +IDD_PING DIALOGEX 0, 0, 329, 151 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME +EXSTYLE WS_EX_APPWINDOW +CAPTION "Dialog" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "Pinging X with X bytes of data:",IDC_MAINTEXT,7,7,315,16 + LTEXT "PingGraphLayout",IDC_PING_LAYOUT,7,26,315,64,NOT WS_VISIBLE | WS_BORDER + GROUPBOX "Ping statistics",IDC_ICMP_PANEL,7,92,315,52,0,WS_EX_TRANSPARENT + LTEXT "Average: 0ms",IDC_ICMP_AVG,13,104,73,8 + LTEXT "Pings sent: 0",IDC_PINGS_SENT,91,104,88,8 + LTEXT "Bad replies: 0",IDC_BAD_HASH,187,104,90,8 + LTEXT "Minimum: 0ms",IDC_ICMP_MIN,13,116,73,8 + LTEXT "Pings lost: 0 (0%)",IDC_PINGS_LOST,91,116,88,8 + LTEXT "Anon replies: 0",IDC_ANON_ADDR,188,116,87,8 + LTEXT "Maximum: 0ms",IDC_ICMP_MAX,13,129,73,8 +END + +IDD_TRACERT DIALOGEX 0, 0, 389, 212 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME +CAPTION "Dialog" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "Tracing route to xyz...",IDC_STATUS,7,5,375,12 + DEFPUSHBUTTON "Close",IDCANCEL,333,191,50,14 + CONTROL "",IDC_LIST_TRACERT,"PhTreeNew",WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP | 0xa,7,22,375,166,WS_EX_CLIENTEDGE +END + + +///////////////////////////////////////////////////////////////////////////// +// +// PNG +// + +AD_PNG PNG "resources\\ad.png" + +AE_PNG PNG "resources\\ae.png" + +AF_PNG PNG "resources\\af.png" + +AG_PNG PNG "resources\\ag.png" + +AI_PNG PNG "resources\\ai.png" + +AL_PNG PNG "resources\\al.png" + +AM_PNG PNG "resources\\am.png" + +AN_PNG PNG "resources\\an.png" + +AO_PNG PNG "resources\\ao.png" + +AR_PNG PNG "resources\\ar.png" + +AS_PNG PNG "resources\\as.png" + +AT_PNG PNG "resources\\at.png" + +AU_PNG PNG "resources\\au.png" + +AW_PNG PNG "resources\\aw.png" + +AX_PNG PNG "resources\\ax.png" + +AZ_PNG PNG "resources\\az.png" + +BA_PNG PNG "resources\\ba.png" + +BB_PNG PNG "resources\\bb.png" + +BD_PNG PNG "resources\\bd.png" + +BE_PNG PNG "resources\\be.png" + +BF_PNG PNG "resources\\bf.png" + +BG_PNG PNG "resources\\bg.png" + +BH_PNG PNG "resources\\bh.png" + +BI__PNG PNG "resources\\bi.png" + +BJ_PNG PNG "resources\\bj.png" + +BM_PNG PNG "resources\\bm.png" + +BN_PNG PNG "resources\\bn.png" + +BO_PNG PNG "resources\\bo.png" + +BR_PNG PNG "resources\\br.png" + +BS_PNG PNG "resources\\bs.png" + +BT_PNG PNG "resources\\bt.png" + +BV_PNG PNG "resources\\bv.png" + +BW_PNG PNG "resources\\bw.png" + +BY_PNG PNG "resources\\by.png" + +BZ_PNG PNG "resources\\bz.png" + +CA_PNG PNG "resources\\ca.png" + +AAC_PNG PNG "resources\\catalonia.png" + +CC_PNG PNG "resources\\cc.png" + +CD_PNG PNG "resources\\cd.png" + +CF_PNG PNG "resources\\cf.png" + +CG_PNG PNG "resources\\cg.png" + +CH_PNG PNG "resources\\ch.png" + +CI_PNG PNG "resources\\ci.png" + +CK_PNG PNG "resources\\ck.png" + +CL_PNG PNG "resources\\cl.png" + +CM_PNG PNG "resources\\cm.png" + +CN_PNG PNG "resources\\cn.png" + +CO_PNG PNG "resources\\co.png" + +CR_PNG PNG "resources\\cr.png" + +CS_PNG PNG "resources\\cs.png" + +CU_PNG PNG "resources\\cu.png" + +CV_PNG PNG "resources\\cv.png" + +CX_PNG PNG "resources\\cx.png" + +CY_PNG PNG "resources\\cy.png" + +CZ_PNG PNG "resources\\cz.png" + +DE_PNG PNG "resources\\de.png" + +DJ_PNG PNG "resources\\dj.png" + +DK_PNG PNG "resources\\dk.png" + +DM_PNG PNG "resources\\dm.png" + +DO_PNG PNG "resources\\do.png" + +DZ_PNG PNG "resources\\dz.png" + +EC_PNG PNG "resources\\ec.png" + +EE_PNG PNG "resources\\ee.png" + +EG_PNG PNG "resources\\eg.png" + +EH_PNG PNG "resources\\eh.png" + +AAD_PNG PNG "resources\\england.png" + +ER_PNG PNG "resources\\er.png" + +ES_PNG PNG "resources\\es.png" + +ET_PNG PNG "resources\\et.png" + +AAE_PNG PNG "resources\\europeanunion.png" + +AAF_PNG PNG "resources\\fam.png" + +FI_PNG PNG "resources\\fi.png" + +FJ_PNG PNG "resources\\fj.png" + +FK_PNG PNG "resources\\fk.png" + +FM_PNG PNG "resources\\fm.png" + +FO_PNG PNG "resources\\fo.png" + +FR_PNG PNG "resources\\fr.png" + +GA_PNG PNG "resources\\ga.png" + +GB_PNG PNG "resources\\gb.png" + +GD_PNG PNG "resources\\gd.png" + +GE_PNG PNG "resources\\ge.png" + +GF_PNG PNG "resources\\gf.png" + +GH_PNG PNG "resources\\gh.png" + +GI_PNG PNG "resources\\gi.png" + +GL_PNG PNG "resources\\gl.png" + +GM_PNG PNG "resources\\gm.png" + +GN_PNG PNG "resources\\gn.png" + +GP_PNG PNG "resources\\gp.png" + +GQ_PNG PNG "resources\\gq.png" + +GR_PNG PNG "resources\\gr.png" + +GS_PNG PNG "resources\\gs.png" + +GT_PNG PNG "resources\\gt.png" + +GU_PNG PNG "resources\\gu.png" + +GW_PNG PNG "resources\\gw.png" + +GY_PNG PNG "resources\\gy.png" + +HK_PNG PNG "resources\\hk.png" + +HM_PNG PNG "resources\\hm.png" + +HN_PNG PNG "resources\\hn.png" + +HR_PNG PNG "resources\\hr.png" + +HT_PNG PNG "resources\\ht.png" + +HU_PNG PNG "resources\\hu.png" + +ID_PNG PNG "resources\\id.png" + +IE_PNG PNG "resources\\ie.png" + +IL_PNG PNG "resources\\il.png" + +IN_PNG PNG "resources\\in.png" + +IO_PNG PNG "resources\\io.png" + +IQ_PNG PNG "resources\\iq.png" + +IR_PNG PNG "resources\\ir.png" + +IS_PNG PNG "resources\\is.png" + +IT_PNG PNG "resources\\it.png" + +JM_PNG PNG "resources\\jm.png" + +JO_PNG PNG "resources\\jo.png" + +JP_PNG PNG "resources\\jp.png" + +KE_PNG PNG "resources\\ke.png" + +KG_PNG PNG "resources\\kg.png" + +KH_PNG PNG "resources\\kh.png" + +KI_PNG PNG "resources\\ki.png" + +KM_PNG PNG "resources\\km.png" + +KN_PNG PNG "resources\\kn.png" + +KP_PNG PNG "resources\\kp.png" + +KR_PNG PNG "resources\\kr.png" + +KW_PNG PNG "resources\\kw.png" + +KY_PNG PNG "resources\\ky.png" + +KZ_PNG PNG "resources\\kz.png" + +LA_PNG PNG "resources\\la.png" + +LB_PNG PNG "resources\\lb.png" + +LC_PNG PNG "resources\\lc.png" + +LI_PNG PNG "resources\\li.png" + +LK_PNG PNG "resources\\lk.png" + +LR_PNG PNG "resources\\lr.png" + +LS_PNG PNG "resources\\ls.png" + +LT_PNG PNG "resources\\lt.png" + +LU_PNG PNG "resources\\lu.png" + +LV_PNG PNG "resources\\lv.png" + +LY_PNG PNG "resources\\ly.png" + +MA_PNG PNG "resources\\ma.png" + +MC_PNG PNG "resources\\mc.png" + +MD_PNG PNG "resources\\md.png" + +ME_PNG PNG "resources\\me.png" + +MG_PNG PNG "resources\\mg.png" + +MH_PNG PNG "resources\\mh.png" + +MK_PNG PNG "resources\\mk.png" + +ML_PNG PNG "resources\\ml.png" + +MM_PNG PNG "resources\\mm.png" + +MN_PNG PNG "resources\\mn.png" + +MO_PNG PNG "resources\\mo.png" + +MP_PNG PNG "resources\\mp.png" + +MQ_PNG PNG "resources\\mq.png" + +MR_PNG PNG "resources\\mr.png" + +MS_PNG PNG "resources\\ms.png" + +MT_PNG PNG "resources\\mt.png" + +MU_PNG PNG "resources\\mu.png" + +MV_PNG PNG "resources\\mv.png" + +MW_PNG PNG "resources\\mw.png" + +MX_PNG PNG "resources\\mx.png" + +MY_PNG PNG "resources\\my.png" + +MZ_PNG PNG "resources\\mz.png" + +NA_PNG PNG "resources\\na.png" + +NC_PNG PNG "resources\\nc.png" + +NE_PNG PNG "resources\\ne.png" + +NF_PNG PNG "resources\\nf.png" + +NG_PNG PNG "resources\\ng.png" + +NI_PNG PNG "resources\\ni.png" + +NL_PNG PNG "resources\\nl.png" + +NO_PNG PNG "resources\\no.png" + +NP_PNG PNG "resources\\np.png" + +NR_PNG PNG "resources\\nr.png" + +NU_PNG PNG "resources\\nu.png" + +NZ_PNG PNG "resources\\nz.png" + +OM_PNG PNG "resources\\om.png" + +PA_PNG PNG "resources\\pa.png" + +PE_PNG PNG "resources\\pe.png" + +PF_PNG PNG "resources\\pf.png" + +PG_PNG PNG "resources\\pg.png" + +PH_PNG PNG "resources\\ph.png" + +PK_PNG PNG "resources\\pk.png" + +PL_PNG PNG "resources\\pl.png" + +PM_PNG PNG "resources\\pm.png" + +PN_PNG PNG "resources\\pn.png" + +PR_PNG PNG "resources\\pr.png" + +PS_PNG PNG "resources\\ps.png" + +PT_PNG PNG "resources\\pt.png" + +PW_PNG PNG "resources\\pw.png" + +PY_PNG PNG "resources\\py.png" + +QA_PNG PNG "resources\\qa.png" + +RE_PNG PNG "resources\\re.png" + +RO_PNG PNG "resources\\ro.png" + +RS_PNG PNG "resources\\rs.png" + +RU_PNG PNG "resources\\ru.png" + +RW_PNG PNG "resources\\rw.png" + +SA_PNG PNG "resources\\sa.png" + +SB_PNG PNG "resources\\sb.png" + +SC_PNG PNG "resources\\sc.png" + +AAA_PNG PNG "resources\\scotland.png" + +SD_PNG PNG "resources\\sd.png" + +SE_PNG PNG "resources\\se.png" + +SG_PNG PNG "resources\\sg.png" + +SH_PNG PNG "resources\\sh.png" + +SI_PNG PNG "resources\\si.png" + +SJ_PNG PNG "resources\\sj.png" + +SK_PNG PNG "resources\\sk.png" + +SL_PNG PNG "resources\\sl.png" + +SM_PNG PNG "resources\\sm.png" + +SN_PNG PNG "resources\\sn.png" + +SO_PNG PNG "resources\\so.png" + +SR_PNG PNG "resources\\sr.png" + +ST_PNG PNG "resources\\st.png" + +SV_PNG PNG "resources\\sv.png" + +SY_PNG PNG "resources\\sy.png" + +SZ_PNG PNG "resources\\sz.png" + +TC_PNG PNG "resources\\tc.png" + +TD_PNG PNG "resources\\td.png" + +TF_PNG PNG "resources\\tf.png" + +TG_PNG PNG "resources\\tg.png" + +TH_PNG PNG "resources\\th.png" + +TJ_PNG PNG "resources\\tj.png" + +TK_PNG PNG "resources\\tk.png" + +TL_PNG PNG "resources\\tl.png" + +TM_PNG PNG "resources\\tm.png" + +TN_PNG PNG "resources\\tn.png" + +TO_PNG PNG "resources\\to.png" + +TR_PNG PNG "resources\\tr.png" + +TT_PNG PNG "resources\\tt.png" + +TV_PNG PNG "resources\\tv.png" + +TW_PNG PNG "resources\\tw.png" + +TZ_PNG PNG "resources\\tz.png" + +UA_PNG PNG "resources\\ua.png" + +UG_PNG PNG "resources\\ug.png" + +UM_PNG PNG "resources\\um.png" + +US_PNG PNG "resources\\us.png" + +UY_PNG PNG "resources\\uy.png" + +UZ_PNG PNG "resources\\uz.png" + +VA_PNG PNG "resources\\va.png" + +VC_PNG PNG "resources\\vc.png" + +VE_PNG PNG "resources\\ve.png" + +VG_PNG PNG "resources\\vg.png" + +VI_PNG PNG "resources\\vi.png" + +VN_PNG PNG "resources\\vn.png" + +VU_PNG PNG "resources\\vu.png" + +AAB_PNG PNG "resources\\wales.png" + +WF_PNG PNG "resources\\wf.png" + +WS_PNG PNG "resources\\ws.png" + +YE_PNG PNG "resources\\ye.png" + +YT_PNG PNG "resources\\yt.png" + +ZA_PNG PNG "resources\\za.png" + +ZM_PNG PNG "resources\\zm.png" + +ZW_PNG PNG "resources\\zw.png" + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_WHOIS, DIALOG + BEGIN + LEFTMARGIN, 2 + RIGHTMARGIN, 387 + TOPMARGIN, 2 + BOTTOMMARGIN, 212 + END + + IDD_OPTIONS, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 194 + TOPMARGIN, 7 + BOTTOMMARGIN, 50 + END + + IDD_PING, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 322 + TOPMARGIN, 7 + BOTTOMMARGIN, 144 + END + + IDD_TRACERT, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 382 + TOPMARGIN, 7 + BOTTOMMARGIN, 205 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// AFX_DIALOG_LAYOUT +// + +IDD_WHOIS AFX_DIALOG_LAYOUT +BEGIN + 0 +END + +IDD_OPTIONS AFX_DIALOG_LAYOUT +BEGIN + 0 +END + +IDD_TRACERT AFX_DIALOG_LAYOUT +BEGIN + 0 +END + +IDD_PING AFX_DIALOG_LAYOUT +BEGIN + 0 +END + +#endif // English (Australia) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/plugins/NetworkTools/NetworkTools.vcxproj b/plugins/NetworkTools/NetworkTools.vcxproj index 5a770136f286..307ef4de731f 100644 --- a/plugins/NetworkTools/NetworkTools.vcxproj +++ b/plugins/NetworkTools/NetworkTools.vcxproj @@ -1,398 +1,398 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {B5E0DA09-EA01-4D5A-A9D6-5B22DB0C306E} - NetworkTools - Win32Proj - NetworkTools - 10.0.15063.0 - - - - DynamicLibrary - Unicode - v141 - - - DynamicLibrary - Unicode - v141 - - - DynamicLibrary - Unicode - v141 - - - DynamicLibrary - Unicode - v141 - - - - - - - - - iphlpapi.lib;winhttp.lib;ws2_32.lib;uxtheme.lib;%(AdditionalDependencies) - iphlpapi.dll;winhttp.dll;ws2_32.dll;%(DelayLoadDLLs) - - - - - - iphlpapi.lib;winhttp.lib;ws2_32.lib;uxtheme.lib;%(AdditionalDependencies) - iphlpapi.dll;winhttp.dll;ws2_32.dll;%(DelayLoadDLLs) - - - - - iphlpapi.lib;winhttp.lib;ws2_32.lib;uxtheme.lib;%(AdditionalDependencies) - iphlpapi.dll;winhttp.dll;ws2_32.dll;%(DelayLoadDLLs) - - - - - iphlpapi.lib;winhttp.lib;ws2_32.lib;uxtheme.lib;%(AdditionalDependencies) - iphlpapi.dll;winhttp.dll;ws2_32.dll;%(DelayLoadDLLs) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {B5E0DA09-EA01-4D5A-A9D6-5B22DB0C306E} + NetworkTools + Win32Proj + NetworkTools + 10.0.15063.0 + + + + DynamicLibrary + Unicode + v141 + + + DynamicLibrary + Unicode + v141 + + + DynamicLibrary + Unicode + v141 + + + DynamicLibrary + Unicode + v141 + + + + + + + + + iphlpapi.lib;winhttp.lib;ws2_32.lib;uxtheme.lib;%(AdditionalDependencies) + iphlpapi.dll;winhttp.dll;ws2_32.dll;%(DelayLoadDLLs) + + + + + + iphlpapi.lib;winhttp.lib;ws2_32.lib;uxtheme.lib;%(AdditionalDependencies) + iphlpapi.dll;winhttp.dll;ws2_32.dll;%(DelayLoadDLLs) + + + + + iphlpapi.lib;winhttp.lib;ws2_32.lib;uxtheme.lib;%(AdditionalDependencies) + iphlpapi.dll;winhttp.dll;ws2_32.dll;%(DelayLoadDLLs) + + + + + iphlpapi.lib;winhttp.lib;ws2_32.lib;uxtheme.lib;%(AdditionalDependencies) + iphlpapi.dll;winhttp.dll;ws2_32.dll;%(DelayLoadDLLs) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/plugins/NetworkTools/main.c b/plugins/NetworkTools/main.c index 9dfaf8fc6fc9..129ffafa72c9 100644 --- a/plugins/NetworkTools/main.c +++ b/plugins/NetworkTools/main.c @@ -1,732 +1,732 @@ -/* - * Process Hacker Network Tools - - * Main program - * - * Copyright (C) 2010-2011 wj32 - * Copyright (C) 2013-2017 dmex - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include "nettools.h" -#include "tracert.h" -#include - -PPH_PLUGIN PluginInstance; -PH_CALLBACK_REGISTRATION PluginLoadCallbackRegistration; -PH_CALLBACK_REGISTRATION PluginShowOptionsCallbackRegistration; -PH_CALLBACK_REGISTRATION PluginMenuItemCallbackRegistration; -PH_CALLBACK_REGISTRATION MainMenuInitializingCallbackRegistration; -PH_CALLBACK_REGISTRATION NetworkMenuInitializingCallbackRegistration; -PH_CALLBACK_REGISTRATION NetworkTreeNewInitializingCallbackRegistration; -PH_CALLBACK_REGISTRATION TreeNewMessageCallbackRegistration; -HWND NetworkTreeNewHandle = NULL; - -VOID NTAPI LoadCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - LoadGeoLiteDb(); -} - -VOID NTAPI ShowOptionsCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - ShowOptionsDialog((HWND)Parameter); -} - -HRESULT CALLBACK ElevateActionCallbackProc( - _In_ HWND hwnd, - _In_ UINT uNotification, - _In_ WPARAM wParam, - _In_ LPARAM lParam, - _In_ LONG_PTR dwRefData - ) -{ - switch (uNotification) - { - case TDN_CREATED: - SendMessage(hwnd, TDM_SET_BUTTON_ELEVATION_REQUIRED_STATE, IDYES, TRUE); - break; - } - - return S_OK; -} - -VOID NTAPI MenuItemCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - PPH_PLUGIN_MENU_ITEM menuItem = (PPH_PLUGIN_MENU_ITEM)Parameter; - PPH_NETWORK_ITEM networkItem = (PPH_NETWORK_ITEM)menuItem->Context; - - switch (menuItem->Id) - { - case NETWORK_ACTION_PING: - ShowPingWindow(networkItem); - break; - case NETWORK_ACTION_TRACEROUTE: - ShowTracertWindow(networkItem); - break; - case NETWORK_ACTION_WHOIS: - ShowWhoisWindow(networkItem); - break; - case MAINMENU_ACTION_PING: - { - PH_IP_ENDPOINT RemoteEndpoint; - PPH_STRING selectedChoice = NULL; - - while (PhaChoiceDialog( - menuItem->OwnerWindow, - L"Ping", - L"IP address:", - NULL, - 0, - NULL, - PH_CHOICE_DIALOG_USER_CHOICE, - &selectedChoice, - NULL, - SETTING_NAME_TRACERT_HISTORY - )) - { - PWSTR terminator = NULL; - - if (NT_SUCCESS(RtlIpv4StringToAddress( - selectedChoice->Buffer, - TRUE, - &terminator, - &RemoteEndpoint.Address.InAddr - ))) - { - RemoteEndpoint.Address.Type = PH_IPV4_NETWORK_TYPE; - ShowPingWindowFromAddress(RemoteEndpoint); - break; - } - - if (NT_SUCCESS(RtlIpv6StringToAddress( - selectedChoice->Buffer, - &terminator, - &RemoteEndpoint.Address.In6Addr - ))) - { - RemoteEndpoint.Address.Type = PH_IPV6_NETWORK_TYPE; - ShowPingWindowFromAddress(RemoteEndpoint); - break; - } - } - } - break; - case MAINMENU_ACTION_TRACERT: - { - PH_IP_ENDPOINT RemoteEndpoint; - PPH_STRING selectedChoice = NULL; - - while (PhaChoiceDialog( - menuItem->OwnerWindow, - L"Tracert", - L"IP address:", - NULL, - 0, - NULL, - PH_CHOICE_DIALOG_USER_CHOICE, - &selectedChoice, - NULL, - SETTING_NAME_TRACERT_HISTORY - )) - { - PWSTR terminator = NULL; - - if (NT_SUCCESS(RtlIpv4StringToAddress( - selectedChoice->Buffer, - TRUE, - &terminator, - &RemoteEndpoint.Address.InAddr - ))) - { - RemoteEndpoint.Address.Type = PH_IPV4_NETWORK_TYPE; - ShowTracertWindowFromAddress(RemoteEndpoint); - break; - } - - if (NT_SUCCESS(RtlIpv6StringToAddress( - selectedChoice->Buffer, - &terminator, - &RemoteEndpoint.Address.In6Addr - ))) - { - RemoteEndpoint.Address.Type = PH_IPV6_NETWORK_TYPE; - ShowTracertWindowFromAddress(RemoteEndpoint); - break; - } - } - } - break; - case MAINMENU_ACTION_WHOIS: - { - PH_IP_ENDPOINT RemoteEndpoint; - PPH_STRING selectedChoice = NULL; - - while (PhaChoiceDialog( - menuItem->OwnerWindow, - L"Whois", - L"IP address for Whois:", - NULL, - 0, - NULL, - PH_CHOICE_DIALOG_USER_CHOICE, - &selectedChoice, - NULL, - SETTING_NAME_TRACERT_HISTORY - )) - { - PWSTR terminator = NULL; - - if (NT_SUCCESS(RtlIpv4StringToAddress( - selectedChoice->Buffer, - TRUE, - &terminator, - &RemoteEndpoint.Address.InAddr - ))) - { - RemoteEndpoint.Address.Type = PH_IPV4_NETWORK_TYPE; - ShowWhoisWindowFromAddress(RemoteEndpoint); - break; - } - - if (NT_SUCCESS(RtlIpv6StringToAddress( - selectedChoice->Buffer, - &terminator, - &RemoteEndpoint.Address.In6Addr - ))) - { - RemoteEndpoint.Address.Type = PH_IPV6_NETWORK_TYPE; - ShowWhoisWindowFromAddress(RemoteEndpoint); - break; - } - } - } - break; - case MAINMENU_ACTION_GEOIP_UPDATE: - { - if (PhGetOwnTokenAttributes().Elevated) - { - ShowGeoIPUpdateDialog(NULL); - } - else - { - TASKDIALOGCONFIG config = { sizeof(config) }; - TASKDIALOG_BUTTON buttons[1]; - INT button; - - config.dwFlags = TDF_CAN_BE_MINIMIZED; - config.pszWindowTitle = L"Process Hacker"; - config.pszMainIcon = TD_ERROR_ICON; - config.pszMainInstruction = L"Unable to update the GeoIP database."; - config.pszContent = L"You will need to provide administrator permission. " - L"Click Continue to complete this operation."; - config.dwCommonButtons = TDCBF_CANCEL_BUTTON; - - buttons[0].nButtonID = IDYES; - buttons[0].pszButtonText = L"Continue"; - - config.cButtons = 1; - config.pButtons = buttons; - config.nDefaultButton = IDYES; - - config.pfCallback = ElevateActionCallbackProc; - - if (TaskDialogIndirect( - &config, - &button, - NULL, - NULL - ) == S_OK && button == IDYES) - { - ProcessHacker_PrepareForEarlyShutdown(PhMainWndHandle); - - if (PhShellProcessHacker( - PhMainWndHandle, - NULL, - SW_SHOW, - PH_SHELL_EXECUTE_ADMIN, - PH_SHELL_APP_PROPAGATE_PARAMETERS | PH_SHELL_APP_PROPAGATE_PARAMETERS_IGNORE_VISIBILITY, - 0, - NULL - )) - { - ProcessHacker_Destroy(PhMainWndHandle); - } - else - { - ProcessHacker_CancelEarlyShutdown(PhMainWndHandle); - } - } - } - } - break; - } -} - -VOID NTAPI MainMenuInitializingCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - PPH_PLUGIN_MENU_INFORMATION menuInfo = Parameter; - PPH_EMENU_ITEM networkToolsMenu; - - if (menuInfo->u.MainMenu.SubMenuIndex != PH_MENU_ITEM_LOCATION_TOOLS) - return; - - networkToolsMenu = PhPluginCreateEMenuItem(PluginInstance, 0, 0, L"Network Tools", NULL); - PhInsertEMenuItem(networkToolsMenu, PhPluginCreateEMenuItem(PluginInstance, 0, MAINMENU_ACTION_GEOIP_UPDATE, L"GeoIP database update...", NULL), -1); - PhInsertEMenuItem(networkToolsMenu, PhPluginCreateEMenuItem(PluginInstance, PH_EMENU_SEPARATOR, 0, NULL, NULL), -1); - PhInsertEMenuItem(networkToolsMenu, PhPluginCreateEMenuItem(PluginInstance, 0, MAINMENU_ACTION_PING, L"Ping address...", NULL), -1); - PhInsertEMenuItem(networkToolsMenu, PhPluginCreateEMenuItem(PluginInstance, 0, MAINMENU_ACTION_TRACERT, L"Traceroute address...", NULL), -1); - PhInsertEMenuItem(networkToolsMenu, PhPluginCreateEMenuItem(PluginInstance, 0, MAINMENU_ACTION_WHOIS, L"Whois address...", NULL), -1); - PhInsertEMenuItem(menuInfo->Menu, networkToolsMenu, -1); -} - -VOID NTAPI NetworkMenuInitializingCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - PPH_PLUGIN_MENU_INFORMATION menuInfo = (PPH_PLUGIN_MENU_INFORMATION)Parameter; - PPH_NETWORK_ITEM networkItem; - PPH_EMENU_ITEM whoisMenu; - PPH_EMENU_ITEM traceMenu; - PPH_EMENU_ITEM pingMenu; - - if (menuInfo->u.Network.NumberOfNetworkItems == 1) - networkItem = menuInfo->u.Network.NetworkItems[0]; - else - networkItem = NULL; - - PhInsertEMenuItem(menuInfo->Menu, PhPluginCreateEMenuItem(PluginInstance, PH_EMENU_SEPARATOR, 0, NULL, NULL), 0); - PhInsertEMenuItem(menuInfo->Menu, whoisMenu = PhPluginCreateEMenuItem(PluginInstance, 0, NETWORK_ACTION_WHOIS, L"Whois", networkItem), 0); - PhInsertEMenuItem(menuInfo->Menu, traceMenu = PhPluginCreateEMenuItem(PluginInstance, 0, NETWORK_ACTION_TRACEROUTE, L"Traceroute", networkItem), 0); - PhInsertEMenuItem(menuInfo->Menu, pingMenu = PhPluginCreateEMenuItem(PluginInstance, 0, NETWORK_ACTION_PING, L"Ping", networkItem), 0); - - if (networkItem) - { - if (PhIsNullIpAddress(&networkItem->RemoteEndpoint.Address)) - { - whoisMenu->Flags |= PH_EMENU_DISABLED; - traceMenu->Flags |= PH_EMENU_DISABLED; - pingMenu->Flags |= PH_EMENU_DISABLED; - } - else if (networkItem->RemoteEndpoint.Address.Type == PH_IPV4_NETWORK_TYPE) - { - if (IN4_IS_ADDR_LOOPBACK(&networkItem->RemoteEndpoint.Address.InAddr)) - { - whoisMenu->Flags |= PH_EMENU_DISABLED; - traceMenu->Flags |= PH_EMENU_DISABLED; - pingMenu->Flags |= PH_EMENU_DISABLED; - } - } - else - { - if (IN6_IS_ADDR_LOOPBACK(&networkItem->RemoteEndpoint.Address.In6Addr)) - { - whoisMenu->Flags |= PH_EMENU_DISABLED; - traceMenu->Flags |= PH_EMENU_DISABLED; - pingMenu->Flags |= PH_EMENU_DISABLED; - } - } - } - else - { - whoisMenu->Flags |= PH_EMENU_DISABLED; - traceMenu->Flags |= PH_EMENU_DISABLED; - pingMenu->Flags |= PH_EMENU_DISABLED; - } -} - -LONG NTAPI NetworkServiceSortFunction( - _In_ PVOID Node1, - _In_ PVOID Node2, - _In_ ULONG SubId, - _In_ PVOID Context - ) -{ - PPH_NETWORK_NODE node1 = Node1; - PPH_NETWORK_NODE node2 = Node2; - PNETWORK_EXTENSION extension1 = PhPluginGetObjectExtension(PluginInstance, node1->NetworkItem, EmNetworkItemType); - PNETWORK_EXTENSION extension2 = PhPluginGetObjectExtension(PluginInstance, node2->NetworkItem, EmNetworkItemType); - - switch (SubId) - { - case NETWORK_COLUMN_ID_REMOTE_COUNTRY: - return PhCompareStringWithNull(extension1->RemoteCountryCode, extension2->RemoteCountryCode, TRUE); - } - - return 0; -} - -VOID NTAPI NetworkTreeNewInitializingCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - PPH_PLUGIN_TREENEW_INFORMATION info = Parameter; - PH_TREENEW_COLUMN column; - - *(HWND*)Context = info->TreeNewHandle; - - memset(&column, 0, sizeof(PH_TREENEW_COLUMN)); - column.Text = L"Country"; - column.Width = 140; - column.Alignment = PH_ALIGN_LEFT; - column.CustomDraw = TRUE; // Owner-draw this column to show country flags - PhPluginAddTreeNewColumn(PluginInstance, info->CmData, &column, NETWORK_COLUMN_ID_REMOTE_COUNTRY, NULL, NetworkServiceSortFunction); - - memset(&column, 0, sizeof(PH_TREENEW_COLUMN)); - column.Text = L"Local service"; - column.Width = 140; - column.Alignment = PH_ALIGN_LEFT; - PhPluginAddTreeNewColumn(PluginInstance, info->CmData, &column, NETWORK_COLUMN_ID_LOCAL_SERVICE, NULL, NetworkServiceSortFunction); - - memset(&column, 0, sizeof(PH_TREENEW_COLUMN)); - column.Text = L"Remote service"; - column.Width = 140; - column.Alignment = PH_ALIGN_LEFT; - PhPluginAddTreeNewColumn(PluginInstance, info->CmData, &column, NETWORK_COLUMN_ID_REMOTE_SERVICE, NULL, NetworkServiceSortFunction); -} - -VOID NTAPI NetworkItemCreateCallback( - _In_ PVOID Object, - _In_ PH_EM_OBJECT_TYPE ObjectType, - _In_ PVOID Extension - ) -{ - //PPH_NETWORK_ITEM networkItem = Object; - PNETWORK_EXTENSION extension = Extension; - - memset(extension, 0, sizeof(NETWORK_EXTENSION)); -} - -VOID NTAPI NetworkItemDeleteCallback( - _In_ PVOID Object, - _In_ PH_EM_OBJECT_TYPE ObjectType, - _In_ PVOID Extension - ) -{ - //PPH_NETWORK_ITEM networkItem = Object; - PNETWORK_EXTENSION extension = Extension; - - PhClearReference(&extension->RemoteCountryCode); - PhClearReference(&extension->RemoteCountryName); - - if (extension->CountryIcon) - DestroyIcon(extension->CountryIcon); -} - -VOID NTAPI NetworkNodeCreateCallback( - _In_ PVOID Object, - _In_ PH_EM_OBJECT_TYPE ObjectType, - _In_ PVOID Extension - ) -{ - PPH_NETWORK_NODE networkNode = Object; - PNETWORK_EXTENSION extension = PhPluginGetObjectExtension(PluginInstance, networkNode->NetworkItem, EmNetworkItemType); - - if (!extension->CountryValid) - { - PPH_STRING remoteCountryCode; - PPH_STRING remoteCountryName; - - if (LookupCountryCode( - networkNode->NetworkItem->RemoteEndpoint.Address, - &remoteCountryCode, - &remoteCountryName - )) - { - PhMoveReference(&extension->RemoteCountryCode, remoteCountryCode); - PhMoveReference(&extension->RemoteCountryName, remoteCountryName); - } - - extension->CountryValid = TRUE; - } -} - -VOID UpdateNetworkNode( - _In_ NETWORK_COLUMN_ID ColumnID, - _In_ PPH_NETWORK_NODE Node, - _In_ PNETWORK_EXTENSION Extension - ) -{ - switch (ColumnID) - { - case NETWORK_COLUMN_ID_LOCAL_SERVICE: - { - if (!Extension->LocalValid) - { - for (ULONG x = 0; x < ARRAYSIZE(ResolvedPortsTable); x++) - { - if (Node->NetworkItem->LocalEndpoint.Port == ResolvedPortsTable[x].Port) - { - //PhAppendFormatStringBuilder(&stringBuilder, L"%s,", ResolvedPortsTable[x].Name); - PhMoveReference(&Extension->LocalServiceName, PhCreateString(ResolvedPortsTable[x].Name)); - break; - } - } - - Extension->LocalValid = TRUE; - } - } - break; - case NETWORK_COLUMN_ID_REMOTE_SERVICE: - { - if (!Extension->RemoteValid) - { - for (ULONG x = 0; x < ARRAYSIZE(ResolvedPortsTable); x++) - { - if (Node->NetworkItem->RemoteEndpoint.Port == ResolvedPortsTable[x].Port) - { - //PhAppendFormatStringBuilder(&stringBuilder, L"%s,", ResolvedPortsTable[x].Name); - PhMoveReference(&Extension->RemoteServiceName, PhCreateString(ResolvedPortsTable[x].Name)); - break; - } - } - - Extension->RemoteValid = TRUE; - } - } - break; - } -} - -VOID NTAPI TreeNewMessageCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - PPH_PLUGIN_TREENEW_MESSAGE message = Parameter; - - switch (message->Message) - { - case TreeNewGetCellText: - { - if (message->TreeNewHandle == NetworkTreeNewHandle) - { - PPH_TREENEW_GET_CELL_TEXT getCellText = message->Parameter1; - PPH_NETWORK_NODE networkNode = (PPH_NETWORK_NODE)getCellText->Node; - PNETWORK_EXTENSION extension = PhPluginGetObjectExtension(PluginInstance, networkNode->NetworkItem, EmNetworkItemType); - - UpdateNetworkNode(message->SubId, networkNode, extension); - - switch (message->SubId) - { - case NETWORK_COLUMN_ID_REMOTE_COUNTRY: - getCellText->Text = PhGetStringRef(extension->RemoteCountryName); - break; - case NETWORK_COLUMN_ID_LOCAL_SERVICE: - getCellText->Text = PhGetStringRef(extension->LocalServiceName); - break; - case NETWORK_COLUMN_ID_REMOTE_SERVICE: - getCellText->Text = PhGetStringRef(extension->RemoteServiceName); - break; - } - } - } - break; - case TreeNewCustomDraw: - { - PPH_TREENEW_CUSTOM_DRAW customDraw = message->Parameter1; - PPH_NETWORK_NODE networkNode = (PPH_NETWORK_NODE)customDraw->Node; - PNETWORK_EXTENSION extension = PhPluginGetObjectExtension(PluginInstance, networkNode->NetworkItem, EmNetworkItemType); - HDC hdc = customDraw->Dc; - RECT rect = customDraw->CellRect; - - // Check if this is the country column - if (message->SubId != NETWORK_COLUMN_ID_REMOTE_COUNTRY) - break; - - // Check if there's something to draw - if (rect.right - rect.left <= 1) - { - // nothing to draw - break; - } - - // Padding - rect.left += 5; - - // Draw the column data - if (GeoDbLoaded && extension->RemoteCountryCode && extension->RemoteCountryName) - { - if (!extension->CountryIcon) - { - INT resourceCode; - HBITMAP countryBitmap; - - if ((resourceCode = LookupResourceCode(extension->RemoteCountryCode)) != 0) - { - if (countryBitmap = PhLoadPngImageFromResource(PluginInstance->DllBase, 16, 11, MAKEINTRESOURCE(resourceCode), TRUE)) - { - extension->CountryIcon = CommonBitmapToIcon(countryBitmap, 16, 11); - } - } - } - - if (extension->CountryIcon) - { - DrawIconEx( - hdc, - rect.left, - rect.top + ((rect.bottom - rect.top) - 11) / 2, - extension->CountryIcon, - 16, - 11, - 0, - NULL, - DI_NORMAL - ); - - rect.left += 16 + 2; - } - - DrawText( - hdc, - extension->RemoteCountryName->Buffer, - (INT)extension->RemoteCountryName->Length / 2, - &rect, - DT_LEFT | DT_VCENTER | DT_SINGLELINE - ); - } - - if (GeoDbExpired && !extension->CountryIcon) - { - DrawText(hdc, L"Geoip database expired.", -1, &rect, DT_LEFT | DT_VCENTER | DT_SINGLELINE); - } - - if (!GeoDbLoaded) - { - DrawText(hdc, L"Geoip database not found.", -1, &rect, DT_LEFT | DT_VCENTER | DT_SINGLELINE); - } - } - break; - } -} - -LOGICAL DllMain( - _In_ HINSTANCE Instance, - _In_ ULONG Reason, - _Reserved_ PVOID Reserved - ) -{ - switch (Reason) - { - case DLL_PROCESS_ATTACH: - { - PPH_PLUGIN_INFORMATION info; - PH_SETTING_CREATE settings[] = - { - { IntegerPairSettingType, SETTING_NAME_PING_WINDOW_POSITION, L"0,0" }, - { ScalableIntegerPairSettingType, SETTING_NAME_PING_WINDOW_SIZE, L"@96|420,250" }, - { IntegerSettingType, SETTING_NAME_PING_MINIMUM_SCALING, L"1F4" }, // 500ms minimum scaling - { IntegerSettingType, SETTING_NAME_PING_SIZE, L"20" }, // 32 byte packet - { IntegerPairSettingType, SETTING_NAME_TRACERT_WINDOW_POSITION, L"0,0" }, - { ScalableIntegerPairSettingType, SETTING_NAME_TRACERT_WINDOW_SIZE, L"@96|850,490" }, - { StringSettingType, SETTING_NAME_TRACERT_LIST_COLUMNS, L"" }, - { StringSettingType, SETTING_NAME_TRACERT_HISTORY, L"" }, - { IntegerSettingType, SETTING_NAME_TRACERT_MAX_HOPS, L"30" }, - { IntegerPairSettingType, SETTING_NAME_WHOIS_WINDOW_POSITION, L"0,0" }, - { ScalableIntegerPairSettingType, SETTING_NAME_WHOIS_WINDOW_SIZE, L"@96|600,365" }, - }; - - PluginInstance = PhRegisterPlugin(PLUGIN_NAME, Instance, &info); - - if (!PluginInstance) - return FALSE; - - info->DisplayName = L"Network Tools"; - info->Author = L"dmex, wj32"; - info->Description = L"Provides ping, traceroute and whois for network connections."; - info->Url = L"https://wj32.org/processhacker/forums/viewtopic.php?t=1117"; - info->HasOptions = TRUE; - - PhRegisterCallback( - PhGetPluginCallback(PluginInstance, PluginCallbackLoad), - LoadCallback, - NULL, - &PluginLoadCallbackRegistration - ); - PhRegisterCallback( - PhGetPluginCallback(PluginInstance, PluginCallbackShowOptions), - ShowOptionsCallback, - NULL, - &PluginShowOptionsCallbackRegistration - ); - PhRegisterCallback( - PhGetPluginCallback(PluginInstance, PluginCallbackMenuItem), - MenuItemCallback, - NULL, - &PluginMenuItemCallbackRegistration - ); - PhRegisterCallback( - PhGetGeneralCallback(GeneralCallbackMainMenuInitializing), - MainMenuInitializingCallback, - NULL, - &MainMenuInitializingCallbackRegistration - ); - PhRegisterCallback( - PhGetGeneralCallback(GeneralCallbackNetworkMenuInitializing), - NetworkMenuInitializingCallback, - NULL, - &NetworkMenuInitializingCallbackRegistration - ); - - PhRegisterCallback( - PhGetGeneralCallback(GeneralCallbackNetworkTreeNewInitializing), - NetworkTreeNewInitializingCallback, - &NetworkTreeNewHandle, - &NetworkTreeNewInitializingCallbackRegistration - ); - PhRegisterCallback( - PhGetPluginCallback(PluginInstance, PluginCallbackTreeNewMessage), - TreeNewMessageCallback, - NULL, - &TreeNewMessageCallbackRegistration - ); - - PhPluginSetObjectExtension( - PluginInstance, - EmNetworkItemType, - sizeof(NETWORK_EXTENSION), - NetworkItemCreateCallback, - NetworkItemDeleteCallback - ); - PhPluginSetObjectExtension( - PluginInstance, - EmNetworkNodeType, - sizeof(NETWORK_EXTENSION), - NetworkNodeCreateCallback, - NULL - ); - - PhAddSettings(settings, ARRAYSIZE(settings)); - } - break; - } - - return TRUE; +/* + * Process Hacker Network Tools - + * Main program + * + * Copyright (C) 2010-2011 wj32 + * Copyright (C) 2013-2017 dmex + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include "nettools.h" +#include "tracert.h" +#include + +PPH_PLUGIN PluginInstance; +PH_CALLBACK_REGISTRATION PluginLoadCallbackRegistration; +PH_CALLBACK_REGISTRATION PluginShowOptionsCallbackRegistration; +PH_CALLBACK_REGISTRATION PluginMenuItemCallbackRegistration; +PH_CALLBACK_REGISTRATION MainMenuInitializingCallbackRegistration; +PH_CALLBACK_REGISTRATION NetworkMenuInitializingCallbackRegistration; +PH_CALLBACK_REGISTRATION NetworkTreeNewInitializingCallbackRegistration; +PH_CALLBACK_REGISTRATION TreeNewMessageCallbackRegistration; +HWND NetworkTreeNewHandle = NULL; + +VOID NTAPI LoadCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + LoadGeoLiteDb(); +} + +VOID NTAPI ShowOptionsCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + ShowOptionsDialog((HWND)Parameter); +} + +HRESULT CALLBACK ElevateActionCallbackProc( + _In_ HWND hwnd, + _In_ UINT uNotification, + _In_ WPARAM wParam, + _In_ LPARAM lParam, + _In_ LONG_PTR dwRefData + ) +{ + switch (uNotification) + { + case TDN_CREATED: + SendMessage(hwnd, TDM_SET_BUTTON_ELEVATION_REQUIRED_STATE, IDYES, TRUE); + break; + } + + return S_OK; +} + +VOID NTAPI MenuItemCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + PPH_PLUGIN_MENU_ITEM menuItem = (PPH_PLUGIN_MENU_ITEM)Parameter; + PPH_NETWORK_ITEM networkItem = (PPH_NETWORK_ITEM)menuItem->Context; + + switch (menuItem->Id) + { + case NETWORK_ACTION_PING: + ShowPingWindow(networkItem); + break; + case NETWORK_ACTION_TRACEROUTE: + ShowTracertWindow(networkItem); + break; + case NETWORK_ACTION_WHOIS: + ShowWhoisWindow(networkItem); + break; + case MAINMENU_ACTION_PING: + { + PH_IP_ENDPOINT RemoteEndpoint; + PPH_STRING selectedChoice = NULL; + + while (PhaChoiceDialog( + menuItem->OwnerWindow, + L"Ping", + L"IP address:", + NULL, + 0, + NULL, + PH_CHOICE_DIALOG_USER_CHOICE, + &selectedChoice, + NULL, + SETTING_NAME_TRACERT_HISTORY + )) + { + PWSTR terminator = NULL; + + if (NT_SUCCESS(RtlIpv4StringToAddress( + selectedChoice->Buffer, + TRUE, + &terminator, + &RemoteEndpoint.Address.InAddr + ))) + { + RemoteEndpoint.Address.Type = PH_IPV4_NETWORK_TYPE; + ShowPingWindowFromAddress(RemoteEndpoint); + break; + } + + if (NT_SUCCESS(RtlIpv6StringToAddress( + selectedChoice->Buffer, + &terminator, + &RemoteEndpoint.Address.In6Addr + ))) + { + RemoteEndpoint.Address.Type = PH_IPV6_NETWORK_TYPE; + ShowPingWindowFromAddress(RemoteEndpoint); + break; + } + } + } + break; + case MAINMENU_ACTION_TRACERT: + { + PH_IP_ENDPOINT RemoteEndpoint; + PPH_STRING selectedChoice = NULL; + + while (PhaChoiceDialog( + menuItem->OwnerWindow, + L"Tracert", + L"IP address:", + NULL, + 0, + NULL, + PH_CHOICE_DIALOG_USER_CHOICE, + &selectedChoice, + NULL, + SETTING_NAME_TRACERT_HISTORY + )) + { + PWSTR terminator = NULL; + + if (NT_SUCCESS(RtlIpv4StringToAddress( + selectedChoice->Buffer, + TRUE, + &terminator, + &RemoteEndpoint.Address.InAddr + ))) + { + RemoteEndpoint.Address.Type = PH_IPV4_NETWORK_TYPE; + ShowTracertWindowFromAddress(RemoteEndpoint); + break; + } + + if (NT_SUCCESS(RtlIpv6StringToAddress( + selectedChoice->Buffer, + &terminator, + &RemoteEndpoint.Address.In6Addr + ))) + { + RemoteEndpoint.Address.Type = PH_IPV6_NETWORK_TYPE; + ShowTracertWindowFromAddress(RemoteEndpoint); + break; + } + } + } + break; + case MAINMENU_ACTION_WHOIS: + { + PH_IP_ENDPOINT RemoteEndpoint; + PPH_STRING selectedChoice = NULL; + + while (PhaChoiceDialog( + menuItem->OwnerWindow, + L"Whois", + L"IP address for Whois:", + NULL, + 0, + NULL, + PH_CHOICE_DIALOG_USER_CHOICE, + &selectedChoice, + NULL, + SETTING_NAME_TRACERT_HISTORY + )) + { + PWSTR terminator = NULL; + + if (NT_SUCCESS(RtlIpv4StringToAddress( + selectedChoice->Buffer, + TRUE, + &terminator, + &RemoteEndpoint.Address.InAddr + ))) + { + RemoteEndpoint.Address.Type = PH_IPV4_NETWORK_TYPE; + ShowWhoisWindowFromAddress(RemoteEndpoint); + break; + } + + if (NT_SUCCESS(RtlIpv6StringToAddress( + selectedChoice->Buffer, + &terminator, + &RemoteEndpoint.Address.In6Addr + ))) + { + RemoteEndpoint.Address.Type = PH_IPV6_NETWORK_TYPE; + ShowWhoisWindowFromAddress(RemoteEndpoint); + break; + } + } + } + break; + case MAINMENU_ACTION_GEOIP_UPDATE: + { + if (PhGetOwnTokenAttributes().Elevated) + { + ShowGeoIPUpdateDialog(NULL); + } + else + { + TASKDIALOGCONFIG config = { sizeof(config) }; + TASKDIALOG_BUTTON buttons[1]; + INT button; + + config.dwFlags = TDF_CAN_BE_MINIMIZED; + config.pszWindowTitle = L"Process Hacker"; + config.pszMainIcon = TD_ERROR_ICON; + config.pszMainInstruction = L"Unable to update the GeoIP database."; + config.pszContent = L"You will need to provide administrator permission. " + L"Click Continue to complete this operation."; + config.dwCommonButtons = TDCBF_CANCEL_BUTTON; + + buttons[0].nButtonID = IDYES; + buttons[0].pszButtonText = L"Continue"; + + config.cButtons = 1; + config.pButtons = buttons; + config.nDefaultButton = IDYES; + + config.pfCallback = ElevateActionCallbackProc; + + if (TaskDialogIndirect( + &config, + &button, + NULL, + NULL + ) == S_OK && button == IDYES) + { + ProcessHacker_PrepareForEarlyShutdown(PhMainWndHandle); + + if (PhShellProcessHacker( + PhMainWndHandle, + NULL, + SW_SHOW, + PH_SHELL_EXECUTE_ADMIN, + PH_SHELL_APP_PROPAGATE_PARAMETERS | PH_SHELL_APP_PROPAGATE_PARAMETERS_IGNORE_VISIBILITY, + 0, + NULL + )) + { + ProcessHacker_Destroy(PhMainWndHandle); + } + else + { + ProcessHacker_CancelEarlyShutdown(PhMainWndHandle); + } + } + } + } + break; + } +} + +VOID NTAPI MainMenuInitializingCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + PPH_PLUGIN_MENU_INFORMATION menuInfo = Parameter; + PPH_EMENU_ITEM networkToolsMenu; + + if (menuInfo->u.MainMenu.SubMenuIndex != PH_MENU_ITEM_LOCATION_TOOLS) + return; + + networkToolsMenu = PhPluginCreateEMenuItem(PluginInstance, 0, 0, L"Network Tools", NULL); + PhInsertEMenuItem(networkToolsMenu, PhPluginCreateEMenuItem(PluginInstance, 0, MAINMENU_ACTION_GEOIP_UPDATE, L"GeoIP database update...", NULL), -1); + PhInsertEMenuItem(networkToolsMenu, PhPluginCreateEMenuItem(PluginInstance, PH_EMENU_SEPARATOR, 0, NULL, NULL), -1); + PhInsertEMenuItem(networkToolsMenu, PhPluginCreateEMenuItem(PluginInstance, 0, MAINMENU_ACTION_PING, L"Ping address...", NULL), -1); + PhInsertEMenuItem(networkToolsMenu, PhPluginCreateEMenuItem(PluginInstance, 0, MAINMENU_ACTION_TRACERT, L"Traceroute address...", NULL), -1); + PhInsertEMenuItem(networkToolsMenu, PhPluginCreateEMenuItem(PluginInstance, 0, MAINMENU_ACTION_WHOIS, L"Whois address...", NULL), -1); + PhInsertEMenuItem(menuInfo->Menu, networkToolsMenu, -1); +} + +VOID NTAPI NetworkMenuInitializingCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + PPH_PLUGIN_MENU_INFORMATION menuInfo = (PPH_PLUGIN_MENU_INFORMATION)Parameter; + PPH_NETWORK_ITEM networkItem; + PPH_EMENU_ITEM whoisMenu; + PPH_EMENU_ITEM traceMenu; + PPH_EMENU_ITEM pingMenu; + + if (menuInfo->u.Network.NumberOfNetworkItems == 1) + networkItem = menuInfo->u.Network.NetworkItems[0]; + else + networkItem = NULL; + + PhInsertEMenuItem(menuInfo->Menu, PhPluginCreateEMenuItem(PluginInstance, PH_EMENU_SEPARATOR, 0, NULL, NULL), 0); + PhInsertEMenuItem(menuInfo->Menu, whoisMenu = PhPluginCreateEMenuItem(PluginInstance, 0, NETWORK_ACTION_WHOIS, L"Whois", networkItem), 0); + PhInsertEMenuItem(menuInfo->Menu, traceMenu = PhPluginCreateEMenuItem(PluginInstance, 0, NETWORK_ACTION_TRACEROUTE, L"Traceroute", networkItem), 0); + PhInsertEMenuItem(menuInfo->Menu, pingMenu = PhPluginCreateEMenuItem(PluginInstance, 0, NETWORK_ACTION_PING, L"Ping", networkItem), 0); + + if (networkItem) + { + if (PhIsNullIpAddress(&networkItem->RemoteEndpoint.Address)) + { + whoisMenu->Flags |= PH_EMENU_DISABLED; + traceMenu->Flags |= PH_EMENU_DISABLED; + pingMenu->Flags |= PH_EMENU_DISABLED; + } + else if (networkItem->RemoteEndpoint.Address.Type == PH_IPV4_NETWORK_TYPE) + { + if (IN4_IS_ADDR_LOOPBACK(&networkItem->RemoteEndpoint.Address.InAddr)) + { + whoisMenu->Flags |= PH_EMENU_DISABLED; + traceMenu->Flags |= PH_EMENU_DISABLED; + pingMenu->Flags |= PH_EMENU_DISABLED; + } + } + else + { + if (IN6_IS_ADDR_LOOPBACK(&networkItem->RemoteEndpoint.Address.In6Addr)) + { + whoisMenu->Flags |= PH_EMENU_DISABLED; + traceMenu->Flags |= PH_EMENU_DISABLED; + pingMenu->Flags |= PH_EMENU_DISABLED; + } + } + } + else + { + whoisMenu->Flags |= PH_EMENU_DISABLED; + traceMenu->Flags |= PH_EMENU_DISABLED; + pingMenu->Flags |= PH_EMENU_DISABLED; + } +} + +LONG NTAPI NetworkServiceSortFunction( + _In_ PVOID Node1, + _In_ PVOID Node2, + _In_ ULONG SubId, + _In_ PVOID Context + ) +{ + PPH_NETWORK_NODE node1 = Node1; + PPH_NETWORK_NODE node2 = Node2; + PNETWORK_EXTENSION extension1 = PhPluginGetObjectExtension(PluginInstance, node1->NetworkItem, EmNetworkItemType); + PNETWORK_EXTENSION extension2 = PhPluginGetObjectExtension(PluginInstance, node2->NetworkItem, EmNetworkItemType); + + switch (SubId) + { + case NETWORK_COLUMN_ID_REMOTE_COUNTRY: + return PhCompareStringWithNull(extension1->RemoteCountryCode, extension2->RemoteCountryCode, TRUE); + } + + return 0; +} + +VOID NTAPI NetworkTreeNewInitializingCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + PPH_PLUGIN_TREENEW_INFORMATION info = Parameter; + PH_TREENEW_COLUMN column; + + *(HWND*)Context = info->TreeNewHandle; + + memset(&column, 0, sizeof(PH_TREENEW_COLUMN)); + column.Text = L"Country"; + column.Width = 140; + column.Alignment = PH_ALIGN_LEFT; + column.CustomDraw = TRUE; // Owner-draw this column to show country flags + PhPluginAddTreeNewColumn(PluginInstance, info->CmData, &column, NETWORK_COLUMN_ID_REMOTE_COUNTRY, NULL, NetworkServiceSortFunction); + + memset(&column, 0, sizeof(PH_TREENEW_COLUMN)); + column.Text = L"Local service"; + column.Width = 140; + column.Alignment = PH_ALIGN_LEFT; + PhPluginAddTreeNewColumn(PluginInstance, info->CmData, &column, NETWORK_COLUMN_ID_LOCAL_SERVICE, NULL, NetworkServiceSortFunction); + + memset(&column, 0, sizeof(PH_TREENEW_COLUMN)); + column.Text = L"Remote service"; + column.Width = 140; + column.Alignment = PH_ALIGN_LEFT; + PhPluginAddTreeNewColumn(PluginInstance, info->CmData, &column, NETWORK_COLUMN_ID_REMOTE_SERVICE, NULL, NetworkServiceSortFunction); +} + +VOID NTAPI NetworkItemCreateCallback( + _In_ PVOID Object, + _In_ PH_EM_OBJECT_TYPE ObjectType, + _In_ PVOID Extension + ) +{ + //PPH_NETWORK_ITEM networkItem = Object; + PNETWORK_EXTENSION extension = Extension; + + memset(extension, 0, sizeof(NETWORK_EXTENSION)); +} + +VOID NTAPI NetworkItemDeleteCallback( + _In_ PVOID Object, + _In_ PH_EM_OBJECT_TYPE ObjectType, + _In_ PVOID Extension + ) +{ + //PPH_NETWORK_ITEM networkItem = Object; + PNETWORK_EXTENSION extension = Extension; + + PhClearReference(&extension->RemoteCountryCode); + PhClearReference(&extension->RemoteCountryName); + + if (extension->CountryIcon) + DestroyIcon(extension->CountryIcon); +} + +VOID NTAPI NetworkNodeCreateCallback( + _In_ PVOID Object, + _In_ PH_EM_OBJECT_TYPE ObjectType, + _In_ PVOID Extension + ) +{ + PPH_NETWORK_NODE networkNode = Object; + PNETWORK_EXTENSION extension = PhPluginGetObjectExtension(PluginInstance, networkNode->NetworkItem, EmNetworkItemType); + + if (!extension->CountryValid) + { + PPH_STRING remoteCountryCode; + PPH_STRING remoteCountryName; + + if (LookupCountryCode( + networkNode->NetworkItem->RemoteEndpoint.Address, + &remoteCountryCode, + &remoteCountryName + )) + { + PhMoveReference(&extension->RemoteCountryCode, remoteCountryCode); + PhMoveReference(&extension->RemoteCountryName, remoteCountryName); + } + + extension->CountryValid = TRUE; + } +} + +VOID UpdateNetworkNode( + _In_ NETWORK_COLUMN_ID ColumnID, + _In_ PPH_NETWORK_NODE Node, + _In_ PNETWORK_EXTENSION Extension + ) +{ + switch (ColumnID) + { + case NETWORK_COLUMN_ID_LOCAL_SERVICE: + { + if (!Extension->LocalValid) + { + for (ULONG x = 0; x < ARRAYSIZE(ResolvedPortsTable); x++) + { + if (Node->NetworkItem->LocalEndpoint.Port == ResolvedPortsTable[x].Port) + { + //PhAppendFormatStringBuilder(&stringBuilder, L"%s,", ResolvedPortsTable[x].Name); + PhMoveReference(&Extension->LocalServiceName, PhCreateString(ResolvedPortsTable[x].Name)); + break; + } + } + + Extension->LocalValid = TRUE; + } + } + break; + case NETWORK_COLUMN_ID_REMOTE_SERVICE: + { + if (!Extension->RemoteValid) + { + for (ULONG x = 0; x < ARRAYSIZE(ResolvedPortsTable); x++) + { + if (Node->NetworkItem->RemoteEndpoint.Port == ResolvedPortsTable[x].Port) + { + //PhAppendFormatStringBuilder(&stringBuilder, L"%s,", ResolvedPortsTable[x].Name); + PhMoveReference(&Extension->RemoteServiceName, PhCreateString(ResolvedPortsTable[x].Name)); + break; + } + } + + Extension->RemoteValid = TRUE; + } + } + break; + } +} + +VOID NTAPI TreeNewMessageCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + PPH_PLUGIN_TREENEW_MESSAGE message = Parameter; + + switch (message->Message) + { + case TreeNewGetCellText: + { + if (message->TreeNewHandle == NetworkTreeNewHandle) + { + PPH_TREENEW_GET_CELL_TEXT getCellText = message->Parameter1; + PPH_NETWORK_NODE networkNode = (PPH_NETWORK_NODE)getCellText->Node; + PNETWORK_EXTENSION extension = PhPluginGetObjectExtension(PluginInstance, networkNode->NetworkItem, EmNetworkItemType); + + UpdateNetworkNode(message->SubId, networkNode, extension); + + switch (message->SubId) + { + case NETWORK_COLUMN_ID_REMOTE_COUNTRY: + getCellText->Text = PhGetStringRef(extension->RemoteCountryName); + break; + case NETWORK_COLUMN_ID_LOCAL_SERVICE: + getCellText->Text = PhGetStringRef(extension->LocalServiceName); + break; + case NETWORK_COLUMN_ID_REMOTE_SERVICE: + getCellText->Text = PhGetStringRef(extension->RemoteServiceName); + break; + } + } + } + break; + case TreeNewCustomDraw: + { + PPH_TREENEW_CUSTOM_DRAW customDraw = message->Parameter1; + PPH_NETWORK_NODE networkNode = (PPH_NETWORK_NODE)customDraw->Node; + PNETWORK_EXTENSION extension = PhPluginGetObjectExtension(PluginInstance, networkNode->NetworkItem, EmNetworkItemType); + HDC hdc = customDraw->Dc; + RECT rect = customDraw->CellRect; + + // Check if this is the country column + if (message->SubId != NETWORK_COLUMN_ID_REMOTE_COUNTRY) + break; + + // Check if there's something to draw + if (rect.right - rect.left <= 1) + { + // nothing to draw + break; + } + + // Padding + rect.left += 5; + + // Draw the column data + if (GeoDbLoaded && extension->RemoteCountryCode && extension->RemoteCountryName) + { + if (!extension->CountryIcon) + { + INT resourceCode; + HBITMAP countryBitmap; + + if ((resourceCode = LookupResourceCode(extension->RemoteCountryCode)) != 0) + { + if (countryBitmap = PhLoadPngImageFromResource(PluginInstance->DllBase, 16, 11, MAKEINTRESOURCE(resourceCode), TRUE)) + { + extension->CountryIcon = CommonBitmapToIcon(countryBitmap, 16, 11); + } + } + } + + if (extension->CountryIcon) + { + DrawIconEx( + hdc, + rect.left, + rect.top + ((rect.bottom - rect.top) - 11) / 2, + extension->CountryIcon, + 16, + 11, + 0, + NULL, + DI_NORMAL + ); + + rect.left += 16 + 2; + } + + DrawText( + hdc, + extension->RemoteCountryName->Buffer, + (INT)extension->RemoteCountryName->Length / 2, + &rect, + DT_LEFT | DT_VCENTER | DT_SINGLELINE + ); + } + + if (GeoDbExpired && !extension->CountryIcon) + { + DrawText(hdc, L"Geoip database expired.", -1, &rect, DT_LEFT | DT_VCENTER | DT_SINGLELINE); + } + + if (!GeoDbLoaded) + { + DrawText(hdc, L"Geoip database not found.", -1, &rect, DT_LEFT | DT_VCENTER | DT_SINGLELINE); + } + } + break; + } +} + +LOGICAL DllMain( + _In_ HINSTANCE Instance, + _In_ ULONG Reason, + _Reserved_ PVOID Reserved + ) +{ + switch (Reason) + { + case DLL_PROCESS_ATTACH: + { + PPH_PLUGIN_INFORMATION info; + PH_SETTING_CREATE settings[] = + { + { IntegerPairSettingType, SETTING_NAME_PING_WINDOW_POSITION, L"0,0" }, + { ScalableIntegerPairSettingType, SETTING_NAME_PING_WINDOW_SIZE, L"@96|420,250" }, + { IntegerSettingType, SETTING_NAME_PING_MINIMUM_SCALING, L"1F4" }, // 500ms minimum scaling + { IntegerSettingType, SETTING_NAME_PING_SIZE, L"20" }, // 32 byte packet + { IntegerPairSettingType, SETTING_NAME_TRACERT_WINDOW_POSITION, L"0,0" }, + { ScalableIntegerPairSettingType, SETTING_NAME_TRACERT_WINDOW_SIZE, L"@96|850,490" }, + { StringSettingType, SETTING_NAME_TRACERT_LIST_COLUMNS, L"" }, + { StringSettingType, SETTING_NAME_TRACERT_HISTORY, L"" }, + { IntegerSettingType, SETTING_NAME_TRACERT_MAX_HOPS, L"30" }, + { IntegerPairSettingType, SETTING_NAME_WHOIS_WINDOW_POSITION, L"0,0" }, + { ScalableIntegerPairSettingType, SETTING_NAME_WHOIS_WINDOW_SIZE, L"@96|600,365" }, + }; + + PluginInstance = PhRegisterPlugin(PLUGIN_NAME, Instance, &info); + + if (!PluginInstance) + return FALSE; + + info->DisplayName = L"Network Tools"; + info->Author = L"dmex, wj32"; + info->Description = L"Provides ping, traceroute and whois for network connections."; + info->Url = L"https://wj32.org/processhacker/forums/viewtopic.php?t=1117"; + info->HasOptions = TRUE; + + PhRegisterCallback( + PhGetPluginCallback(PluginInstance, PluginCallbackLoad), + LoadCallback, + NULL, + &PluginLoadCallbackRegistration + ); + PhRegisterCallback( + PhGetPluginCallback(PluginInstance, PluginCallbackShowOptions), + ShowOptionsCallback, + NULL, + &PluginShowOptionsCallbackRegistration + ); + PhRegisterCallback( + PhGetPluginCallback(PluginInstance, PluginCallbackMenuItem), + MenuItemCallback, + NULL, + &PluginMenuItemCallbackRegistration + ); + PhRegisterCallback( + PhGetGeneralCallback(GeneralCallbackMainMenuInitializing), + MainMenuInitializingCallback, + NULL, + &MainMenuInitializingCallbackRegistration + ); + PhRegisterCallback( + PhGetGeneralCallback(GeneralCallbackNetworkMenuInitializing), + NetworkMenuInitializingCallback, + NULL, + &NetworkMenuInitializingCallbackRegistration + ); + + PhRegisterCallback( + PhGetGeneralCallback(GeneralCallbackNetworkTreeNewInitializing), + NetworkTreeNewInitializingCallback, + &NetworkTreeNewHandle, + &NetworkTreeNewInitializingCallbackRegistration + ); + PhRegisterCallback( + PhGetPluginCallback(PluginInstance, PluginCallbackTreeNewMessage), + TreeNewMessageCallback, + NULL, + &TreeNewMessageCallbackRegistration + ); + + PhPluginSetObjectExtension( + PluginInstance, + EmNetworkItemType, + sizeof(NETWORK_EXTENSION), + NetworkItemCreateCallback, + NetworkItemDeleteCallback + ); + PhPluginSetObjectExtension( + PluginInstance, + EmNetworkNodeType, + sizeof(NETWORK_EXTENSION), + NetworkNodeCreateCallback, + NULL + ); + + PhAddSettings(settings, ARRAYSIZE(settings)); + } + break; + } + + return TRUE; } \ No newline at end of file diff --git a/plugins/NetworkTools/nettools.h b/plugins/NetworkTools/nettools.h index f79de0beb6d7..47b8722f86a8 100644 --- a/plugins/NetworkTools/nettools.h +++ b/plugins/NetworkTools/nettools.h @@ -1,331 +1,331 @@ -/* - * Process Hacker Network Tools - - * Main header - * - * Copyright (C) 2010-2013 wj32 - * Copyright (C) 2012-2017 dmex - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#ifndef _NET_TOOLS_H_ -#define _NET_TOOLS_H_ - -#define CINTERFACE -#define COBJMACROS -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "resource.h" - -#define PLUGIN_NAME L"ProcessHacker.NetworkTools" -#define SETTING_NAME_DB_TYPE (PLUGIN_NAME L".GeoIpType") -#define SETTING_NAME_PING_WINDOW_POSITION (PLUGIN_NAME L".PingWindowPosition") -#define SETTING_NAME_PING_WINDOW_SIZE (PLUGIN_NAME L".PingWindowSize") -#define SETTING_NAME_PING_MINIMUM_SCALING (PLUGIN_NAME L".PingMinScaling") -#define SETTING_NAME_PING_SIZE (PLUGIN_NAME L".PingSize") -#define SETTING_NAME_TRACERT_WINDOW_POSITION (PLUGIN_NAME L".TracertWindowPosition") -#define SETTING_NAME_TRACERT_WINDOW_SIZE (PLUGIN_NAME L".TracertWindowSize") -#define SETTING_NAME_TRACERT_LIST_COLUMNS (PLUGIN_NAME L".TracertListColumns") -#define SETTING_NAME_TRACERT_HISTORY (PLUGIN_NAME L".TracertAddresses") -#define SETTING_NAME_TRACERT_MAX_HOPS (PLUGIN_NAME L".TracertMaxHops") -#define SETTING_NAME_WHOIS_WINDOW_POSITION (PLUGIN_NAME L".WhoisWindowPosition") -#define SETTING_NAME_WHOIS_WINDOW_SIZE (PLUGIN_NAME L".WhoisWindowSize") - -extern PPH_PLUGIN PluginInstance; -extern BOOLEAN GeoDbLoaded; -extern BOOLEAN GeoDbExpired; -extern PPH_STRING SearchboxText; - -// ICMP Packet Length: (msdn: IcmpSendEcho2/Icmp6SendEcho2) -// The buffer must be large enough to hold at least one ICMP_ECHO_REPLY or ICMPV6_ECHO_REPLY structure -// + the number of bytes of data specified in the RequestSize parameter. -// This buffer should also be large enough to also hold 8 more bytes of data (the size of an ICMP error message) -// + space for an IO_STATUS_BLOCK structure. -#define ICMP_BUFFER_SIZE(EchoReplyLength, Buffer) \ - (ULONG)(((EchoReplyLength) + (Buffer)->Length) + 8 + sizeof(IO_STATUS_BLOCK) + MAX_OPT_SIZE) - -#define BITS_IN_ONE_BYTE 8 -#define NDIS_UNIT_OF_MEASUREMENT 100 - -// The ICMPV6_ECHO_REPLY struct doesn't have a field to access the reply data, -// so copy the struct and add an additional Data field. -typedef struct _ICMPV6_ECHO_REPLY2 -{ - IPV6_ADDRESS_EX Address; - ULONG Status; - unsigned int RoundTripTime; - BYTE Data[ANYSIZE_ARRAY]; // custom -} ICMPV6_ECHO_REPLY2, *PICMPV6_ECHO_REPLY2; - -typedef enum _PH_NETWORK_ACTION -{ - NETWORK_ACTION_PING = 1, - NETWORK_ACTION_TRACEROUTE, - NETWORK_ACTION_WHOIS, - NETWORK_ACTION_FINISH, - NETWORK_ACTION_PATHPING, - MAINMENU_ACTION_PING, - MAINMENU_ACTION_TRACERT, - MAINMENU_ACTION_WHOIS, - MAINMENU_ACTION_GEOIP_UPDATE, -} PH_NETWORK_ACTION; - -#define NTM_RECEIVEDTRACE (WM_APP + NETWORK_ACTION_TRACEROUTE) -#define NTM_RECEIVEDWHOIS (WM_APP + NETWORK_ACTION_WHOIS) -#define NTM_RECEIVEDFINISH (WM_APP + NETWORK_ACTION_FINISH) -#define WM_TRACERT_UPDATE (WM_APP + NETWORK_ACTION_TRACEROUTE + 1002) -#define WM_TRACERT_COUNTRY (WM_APP + NETWORK_ACTION_TRACEROUTE) - -#define UPDATE_MENUITEM 1005 -#define PH_UPDATEISERRORED (WM_APP + 501) -#define PH_UPDATEISCURRENT (WM_APP + 503) -#define PH_UPDATENEWER (WM_APP + 504) -#define PH_UPDATESUCCESS (WM_APP + 505) -#define PH_UPDATEFAILURE (WM_APP + 506) -#define WM_SHOWDIALOG (WM_APP + 550) - -typedef struct _NETWORK_PING_CONTEXT -{ - HWND WindowHandle; - HWND StatusHandle; - HWND PingGraphHandle; - HFONT FontHandle; - - ULONG CurrentPingMs; - ULONG MaxPingTimeout; - ULONG HashFailCount; - ULONG UnknownAddrCount; - ULONG PingMinMs; - ULONG PingMaxMs; - ULONG PingSentCount; - ULONG PingRecvCount; - ULONG PingLossCount; - - PH_NETWORK_ACTION Action; - PH_LAYOUT_MANAGER LayoutManager; - PH_WORK_QUEUE PingWorkQueue; - PH_GRAPH_STATE PingGraphState; - PH_CIRCULAR_BUFFER_ULONG PingHistory; - PH_CALLBACK_REGISTRATION ProcessesUpdatedRegistration; - - PH_IP_ENDPOINT RemoteEndpoint; - WCHAR IpAddressString[INET6_ADDRSTRLEN + 1]; -} NETWORK_PING_CONTEXT, *PNETWORK_PING_CONTEXT; - -// ping.c - -VOID ShowPingWindow( - _In_ PPH_NETWORK_ITEM NetworkItem - ); - -VOID ShowPingWindowFromAddress( - _In_ PH_IP_ENDPOINT RemoteEndpoint - ); - -// whois.c - -typedef struct _NETWORK_WHOIS_CONTEXT -{ - HWND WindowHandle; - HWND RichEditHandle; - HFONT FontHandle; - - PH_NETWORK_ACTION Action; - PH_LAYOUT_MANAGER LayoutManager; - - PH_IP_ENDPOINT RemoteEndpoint; - WCHAR IpAddressString[INET6_ADDRSTRLEN + 1]; -} NETWORK_WHOIS_CONTEXT, *PNETWORK_WHOIS_CONTEXT; - -VOID ShowWhoisWindow( - _In_ PPH_NETWORK_ITEM NetworkItem - ); - -VOID ShowWhoisWindowFromAddress( - _In_ PH_IP_ENDPOINT RemoteEndpoint - ); - -// tracert.c - -typedef struct _NETWORK_TRACERT_CONTEXT -{ - HWND WindowHandle; - HWND SearchboxHandle; - HWND TreeNewHandle; - HFONT FontHandle; - - BOOLEAN Cancel; - ULONG TreeNewSortColumn; - PH_SORT_ORDER TreeNewSortOrder; - PH_LAYOUT_MANAGER LayoutManager; - PH_WORK_QUEUE WorkQueue; - PPH_HASHTABLE NodeHashtable; - PPH_LIST NodeList; - PPH_LIST NodeRootList; - - PH_IP_ENDPOINT RemoteEndpoint; - WCHAR IpAddressString[INET6_ADDRSTRLEN + 1]; -} NETWORK_TRACERT_CONTEXT, *PNETWORK_TRACERT_CONTEXT; - -VOID ShowTracertWindow( - _In_ PPH_NETWORK_ITEM NetworkItem - ); - -VOID ShowTracertWindowFromAddress( - _In_ PH_IP_ENDPOINT RemoteEndpoint - ); - -// options.c - -VOID ShowOptionsDialog( - _In_opt_ HWND Parent - ); - -// country.c -typedef struct _NETWORK_EXTENSION -{ - union - { - BOOLEAN Flags; - struct - { - BOOLEAN CountryValid : 1; - BOOLEAN LocalValid : 1; - BOOLEAN RemoteValid : 1; - BOOLEAN Spare : 5; - }; - }; - - HICON CountryIcon; - PPH_STRING LocalServiceName; - PPH_STRING RemoteServiceName; - PPH_STRING RemoteCountryCode; - PPH_STRING RemoteCountryName; -} NETWORK_EXTENSION, *PNETWORK_EXTENSION; - -typedef enum _NETWORK_COLUMN_ID -{ - NETWORK_COLUMN_ID_REMOTE_COUNTRY = 1, - NETWORK_COLUMN_ID_LOCAL_SERVICE = 2, - NETWORK_COLUMN_ID_REMOTE_SERVICE = 3, -} NETWORK_COLUMN_ID; - -// country.c -VOID LoadGeoLiteDb(VOID); -VOID FreeGeoLiteDb(VOID); - -BOOLEAN LookupCountryCode( - _In_ PH_IP_ADDRESS RemoteAddress, - _Out_ PPH_STRING *CountryCode, - _Out_ PPH_STRING *CountryName - ); - -BOOLEAN LookupSockInAddr4CountryCode( - _In_ IN_ADDR RemoteAddress, - _Out_ PPH_STRING *CountryCode, - _Out_ PPH_STRING *CountryName - ); - -BOOLEAN LookupSockInAddr6CountryCode( - _In_ IN6_ADDR RemoteAddress, - _Out_ PPH_STRING *CountryCode, - _Out_ PPH_STRING *CountryName - ); - -INT LookupResourceCode( - _In_ PPH_STRING Name - ); - -typedef struct _PH_UPDATER_CONTEXT -{ - BOOLEAN FixedWindowStyles; - HWND DialogHandle; - HICON IconSmallHandle; - HICON IconLargeHandle; - - PPH_STRING FileDownloadUrl; - PPH_STRING RevVersion; - PPH_STRING Size; - PPH_STRING SetupFilePath; -} PH_UPDATER_CONTEXT, *PPH_UPDATER_CONTEXT; - -VOID TaskDialogLinkClicked( - _In_ PPH_UPDATER_CONTEXT Context - ); - -NTSTATUS GeoIPUpdateThread( - _In_ PVOID Parameter - ); - -VOID ShowGeoIPUpdateDialog( - _In_opt_ HWND Parent - ); - -// page1.c -VOID ShowCheckForUpdatesDialog( - _In_ PPH_UPDATER_CONTEXT Context - ); - -// page2.c -VOID ShowCheckingForUpdatesDialog( - _In_ PPH_UPDATER_CONTEXT Context - ); - -// page5.c -VOID ShowInstallRestartDialog( - _In_ PPH_UPDATER_CONTEXT Context - ); - -// Copied from mstcpip.h due to PH sdk conflicts -#define INADDR_ANY (ULONG)0x00000000 -#define INADDR_LOOPBACK 0x7f000001 - -FORCEINLINE -BOOLEAN -IN4_IS_ADDR_UNSPECIFIED(_In_ CONST IN_ADDR *a) -{ - return (BOOLEAN)(a->s_addr == INADDR_ANY); -} - -FORCEINLINE -BOOLEAN -IN4_IS_ADDR_LOOPBACK(_In_ CONST IN_ADDR *a) -{ - return (BOOLEAN)(*((PUCHAR)a) == 0x7f); // 127/8 -} - -// ports.c -typedef struct _RESOLVED_PORT -{ - PWSTR Name; - USHORT Port; -} RESOLVED_PORT; - -RESOLVED_PORT ResolvedPortsTable[6265]; - +/* + * Process Hacker Network Tools - + * Main header + * + * Copyright (C) 2010-2013 wj32 + * Copyright (C) 2012-2017 dmex + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#ifndef _NET_TOOLS_H_ +#define _NET_TOOLS_H_ + +#define CINTERFACE +#define COBJMACROS +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "resource.h" + +#define PLUGIN_NAME L"ProcessHacker.NetworkTools" +#define SETTING_NAME_DB_TYPE (PLUGIN_NAME L".GeoIpType") +#define SETTING_NAME_PING_WINDOW_POSITION (PLUGIN_NAME L".PingWindowPosition") +#define SETTING_NAME_PING_WINDOW_SIZE (PLUGIN_NAME L".PingWindowSize") +#define SETTING_NAME_PING_MINIMUM_SCALING (PLUGIN_NAME L".PingMinScaling") +#define SETTING_NAME_PING_SIZE (PLUGIN_NAME L".PingSize") +#define SETTING_NAME_TRACERT_WINDOW_POSITION (PLUGIN_NAME L".TracertWindowPosition") +#define SETTING_NAME_TRACERT_WINDOW_SIZE (PLUGIN_NAME L".TracertWindowSize") +#define SETTING_NAME_TRACERT_LIST_COLUMNS (PLUGIN_NAME L".TracertListColumns") +#define SETTING_NAME_TRACERT_HISTORY (PLUGIN_NAME L".TracertAddresses") +#define SETTING_NAME_TRACERT_MAX_HOPS (PLUGIN_NAME L".TracertMaxHops") +#define SETTING_NAME_WHOIS_WINDOW_POSITION (PLUGIN_NAME L".WhoisWindowPosition") +#define SETTING_NAME_WHOIS_WINDOW_SIZE (PLUGIN_NAME L".WhoisWindowSize") + +extern PPH_PLUGIN PluginInstance; +extern BOOLEAN GeoDbLoaded; +extern BOOLEAN GeoDbExpired; +extern PPH_STRING SearchboxText; + +// ICMP Packet Length: (msdn: IcmpSendEcho2/Icmp6SendEcho2) +// The buffer must be large enough to hold at least one ICMP_ECHO_REPLY or ICMPV6_ECHO_REPLY structure +// + the number of bytes of data specified in the RequestSize parameter. +// This buffer should also be large enough to also hold 8 more bytes of data (the size of an ICMP error message) +// + space for an IO_STATUS_BLOCK structure. +#define ICMP_BUFFER_SIZE(EchoReplyLength, Buffer) \ + (ULONG)(((EchoReplyLength) + (Buffer)->Length) + 8 + sizeof(IO_STATUS_BLOCK) + MAX_OPT_SIZE) + +#define BITS_IN_ONE_BYTE 8 +#define NDIS_UNIT_OF_MEASUREMENT 100 + +// The ICMPV6_ECHO_REPLY struct doesn't have a field to access the reply data, +// so copy the struct and add an additional Data field. +typedef struct _ICMPV6_ECHO_REPLY2 +{ + IPV6_ADDRESS_EX Address; + ULONG Status; + unsigned int RoundTripTime; + BYTE Data[ANYSIZE_ARRAY]; // custom +} ICMPV6_ECHO_REPLY2, *PICMPV6_ECHO_REPLY2; + +typedef enum _PH_NETWORK_ACTION +{ + NETWORK_ACTION_PING = 1, + NETWORK_ACTION_TRACEROUTE, + NETWORK_ACTION_WHOIS, + NETWORK_ACTION_FINISH, + NETWORK_ACTION_PATHPING, + MAINMENU_ACTION_PING, + MAINMENU_ACTION_TRACERT, + MAINMENU_ACTION_WHOIS, + MAINMENU_ACTION_GEOIP_UPDATE, +} PH_NETWORK_ACTION; + +#define NTM_RECEIVEDTRACE (WM_APP + NETWORK_ACTION_TRACEROUTE) +#define NTM_RECEIVEDWHOIS (WM_APP + NETWORK_ACTION_WHOIS) +#define NTM_RECEIVEDFINISH (WM_APP + NETWORK_ACTION_FINISH) +#define WM_TRACERT_UPDATE (WM_APP + NETWORK_ACTION_TRACEROUTE + 1002) +#define WM_TRACERT_COUNTRY (WM_APP + NETWORK_ACTION_TRACEROUTE) + +#define UPDATE_MENUITEM 1005 +#define PH_UPDATEISERRORED (WM_APP + 501) +#define PH_UPDATEISCURRENT (WM_APP + 503) +#define PH_UPDATENEWER (WM_APP + 504) +#define PH_UPDATESUCCESS (WM_APP + 505) +#define PH_UPDATEFAILURE (WM_APP + 506) +#define WM_SHOWDIALOG (WM_APP + 550) + +typedef struct _NETWORK_PING_CONTEXT +{ + HWND WindowHandle; + HWND StatusHandle; + HWND PingGraphHandle; + HFONT FontHandle; + + ULONG CurrentPingMs; + ULONG MaxPingTimeout; + ULONG HashFailCount; + ULONG UnknownAddrCount; + ULONG PingMinMs; + ULONG PingMaxMs; + ULONG PingSentCount; + ULONG PingRecvCount; + ULONG PingLossCount; + + PH_NETWORK_ACTION Action; + PH_LAYOUT_MANAGER LayoutManager; + PH_WORK_QUEUE PingWorkQueue; + PH_GRAPH_STATE PingGraphState; + PH_CIRCULAR_BUFFER_ULONG PingHistory; + PH_CALLBACK_REGISTRATION ProcessesUpdatedRegistration; + + PH_IP_ENDPOINT RemoteEndpoint; + WCHAR IpAddressString[INET6_ADDRSTRLEN + 1]; +} NETWORK_PING_CONTEXT, *PNETWORK_PING_CONTEXT; + +// ping.c + +VOID ShowPingWindow( + _In_ PPH_NETWORK_ITEM NetworkItem + ); + +VOID ShowPingWindowFromAddress( + _In_ PH_IP_ENDPOINT RemoteEndpoint + ); + +// whois.c + +typedef struct _NETWORK_WHOIS_CONTEXT +{ + HWND WindowHandle; + HWND RichEditHandle; + HFONT FontHandle; + + PH_NETWORK_ACTION Action; + PH_LAYOUT_MANAGER LayoutManager; + + PH_IP_ENDPOINT RemoteEndpoint; + WCHAR IpAddressString[INET6_ADDRSTRLEN + 1]; +} NETWORK_WHOIS_CONTEXT, *PNETWORK_WHOIS_CONTEXT; + +VOID ShowWhoisWindow( + _In_ PPH_NETWORK_ITEM NetworkItem + ); + +VOID ShowWhoisWindowFromAddress( + _In_ PH_IP_ENDPOINT RemoteEndpoint + ); + +// tracert.c + +typedef struct _NETWORK_TRACERT_CONTEXT +{ + HWND WindowHandle; + HWND SearchboxHandle; + HWND TreeNewHandle; + HFONT FontHandle; + + BOOLEAN Cancel; + ULONG TreeNewSortColumn; + PH_SORT_ORDER TreeNewSortOrder; + PH_LAYOUT_MANAGER LayoutManager; + PH_WORK_QUEUE WorkQueue; + PPH_HASHTABLE NodeHashtable; + PPH_LIST NodeList; + PPH_LIST NodeRootList; + + PH_IP_ENDPOINT RemoteEndpoint; + WCHAR IpAddressString[INET6_ADDRSTRLEN + 1]; +} NETWORK_TRACERT_CONTEXT, *PNETWORK_TRACERT_CONTEXT; + +VOID ShowTracertWindow( + _In_ PPH_NETWORK_ITEM NetworkItem + ); + +VOID ShowTracertWindowFromAddress( + _In_ PH_IP_ENDPOINT RemoteEndpoint + ); + +// options.c + +VOID ShowOptionsDialog( + _In_opt_ HWND Parent + ); + +// country.c +typedef struct _NETWORK_EXTENSION +{ + union + { + BOOLEAN Flags; + struct + { + BOOLEAN CountryValid : 1; + BOOLEAN LocalValid : 1; + BOOLEAN RemoteValid : 1; + BOOLEAN Spare : 5; + }; + }; + + HICON CountryIcon; + PPH_STRING LocalServiceName; + PPH_STRING RemoteServiceName; + PPH_STRING RemoteCountryCode; + PPH_STRING RemoteCountryName; +} NETWORK_EXTENSION, *PNETWORK_EXTENSION; + +typedef enum _NETWORK_COLUMN_ID +{ + NETWORK_COLUMN_ID_REMOTE_COUNTRY = 1, + NETWORK_COLUMN_ID_LOCAL_SERVICE = 2, + NETWORK_COLUMN_ID_REMOTE_SERVICE = 3, +} NETWORK_COLUMN_ID; + +// country.c +VOID LoadGeoLiteDb(VOID); +VOID FreeGeoLiteDb(VOID); + +BOOLEAN LookupCountryCode( + _In_ PH_IP_ADDRESS RemoteAddress, + _Out_ PPH_STRING *CountryCode, + _Out_ PPH_STRING *CountryName + ); + +BOOLEAN LookupSockInAddr4CountryCode( + _In_ IN_ADDR RemoteAddress, + _Out_ PPH_STRING *CountryCode, + _Out_ PPH_STRING *CountryName + ); + +BOOLEAN LookupSockInAddr6CountryCode( + _In_ IN6_ADDR RemoteAddress, + _Out_ PPH_STRING *CountryCode, + _Out_ PPH_STRING *CountryName + ); + +INT LookupResourceCode( + _In_ PPH_STRING Name + ); + +typedef struct _PH_UPDATER_CONTEXT +{ + BOOLEAN FixedWindowStyles; + HWND DialogHandle; + HICON IconSmallHandle; + HICON IconLargeHandle; + + PPH_STRING FileDownloadUrl; + PPH_STRING RevVersion; + PPH_STRING Size; + PPH_STRING SetupFilePath; +} PH_UPDATER_CONTEXT, *PPH_UPDATER_CONTEXT; + +VOID TaskDialogLinkClicked( + _In_ PPH_UPDATER_CONTEXT Context + ); + +NTSTATUS GeoIPUpdateThread( + _In_ PVOID Parameter + ); + +VOID ShowGeoIPUpdateDialog( + _In_opt_ HWND Parent + ); + +// page1.c +VOID ShowCheckForUpdatesDialog( + _In_ PPH_UPDATER_CONTEXT Context + ); + +// page2.c +VOID ShowCheckingForUpdatesDialog( + _In_ PPH_UPDATER_CONTEXT Context + ); + +// page5.c +VOID ShowInstallRestartDialog( + _In_ PPH_UPDATER_CONTEXT Context + ); + +// Copied from mstcpip.h due to PH sdk conflicts +#define INADDR_ANY (ULONG)0x00000000 +#define INADDR_LOOPBACK 0x7f000001 + +FORCEINLINE +BOOLEAN +IN4_IS_ADDR_UNSPECIFIED(_In_ CONST IN_ADDR *a) +{ + return (BOOLEAN)(a->s_addr == INADDR_ANY); +} + +FORCEINLINE +BOOLEAN +IN4_IS_ADDR_LOOPBACK(_In_ CONST IN_ADDR *a) +{ + return (BOOLEAN)(*((PUCHAR)a) == 0x7f); // 127/8 +} + +// ports.c +typedef struct _RESOLVED_PORT +{ + PWSTR Name; + USHORT Port; +} RESOLVED_PORT; + +RESOLVED_PORT ResolvedPortsTable[6265]; + #endif \ No newline at end of file diff --git a/plugins/NetworkTools/options.c b/plugins/NetworkTools/options.c index 69cbeda2cebd..e0483f80af03 100644 --- a/plugins/NetworkTools/options.c +++ b/plugins/NetworkTools/options.c @@ -1,81 +1,81 @@ -/* - * Process Hacker Network Tools - - * options dialog - * - * Copyright (C) 2010-2013 wj32 - * Copyright (C) 2012-2013 dmex - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include "nettools.h" - -INT_PTR CALLBACK OptionsDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - switch (uMsg) - { - case WM_INITDIALOG: - { - PhCenterWindow(hwndDlg, GetParent(hwndDlg)); - - SetDlgItemInt(hwndDlg, IDC_PINGPACKETLENGTH, PhGetIntegerSetting(SETTING_NAME_PING_SIZE), FALSE); - SetDlgItemInt(hwndDlg, IDC_MAXHOPS, PhGetIntegerSetting(SETTING_NAME_TRACERT_MAX_HOPS), FALSE); - } - break; - case WM_COMMAND: - { - switch (LOWORD(wParam)) - { - case IDCANCEL: - { - PhSetIntegerSetting(SETTING_NAME_PING_SIZE, GetDlgItemInt(hwndDlg, IDC_PINGPACKETLENGTH, NULL, FALSE)); - PhSetIntegerSetting(SETTING_NAME_TRACERT_MAX_HOPS, GetDlgItemInt(hwndDlg, IDC_MAXHOPS, NULL, FALSE)); - - EndDialog(hwndDlg, IDCANCEL); - } - break; - case IDC_GEOIP: - { - if (PhGetOwnTokenAttributes().Elevated) - { - ShowGeoIPUpdateDialog(NULL); - } - } - break; - } - } - break; - } - - return FALSE; -} - -VOID ShowOptionsDialog( - _In_opt_ HWND Parent - ) -{ - DialogBox( - PluginInstance->DllBase, - MAKEINTRESOURCE(IDD_OPTIONS), - (HWND)Parent, - OptionsDlgProc - ); +/* + * Process Hacker Network Tools - + * options dialog + * + * Copyright (C) 2010-2013 wj32 + * Copyright (C) 2012-2013 dmex + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include "nettools.h" + +INT_PTR CALLBACK OptionsDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + switch (uMsg) + { + case WM_INITDIALOG: + { + PhCenterWindow(hwndDlg, GetParent(hwndDlg)); + + SetDlgItemInt(hwndDlg, IDC_PINGPACKETLENGTH, PhGetIntegerSetting(SETTING_NAME_PING_SIZE), FALSE); + SetDlgItemInt(hwndDlg, IDC_MAXHOPS, PhGetIntegerSetting(SETTING_NAME_TRACERT_MAX_HOPS), FALSE); + } + break; + case WM_COMMAND: + { + switch (LOWORD(wParam)) + { + case IDCANCEL: + { + PhSetIntegerSetting(SETTING_NAME_PING_SIZE, GetDlgItemInt(hwndDlg, IDC_PINGPACKETLENGTH, NULL, FALSE)); + PhSetIntegerSetting(SETTING_NAME_TRACERT_MAX_HOPS, GetDlgItemInt(hwndDlg, IDC_MAXHOPS, NULL, FALSE)); + + EndDialog(hwndDlg, IDCANCEL); + } + break; + case IDC_GEOIP: + { + if (PhGetOwnTokenAttributes().Elevated) + { + ShowGeoIPUpdateDialog(NULL); + } + } + break; + } + } + break; + } + + return FALSE; +} + +VOID ShowOptionsDialog( + _In_opt_ HWND Parent + ) +{ + DialogBox( + PluginInstance->DllBase, + MAKEINTRESOURCE(IDD_OPTIONS), + (HWND)Parent, + OptionsDlgProc + ); } \ No newline at end of file diff --git a/plugins/NetworkTools/ping.c b/plugins/NetworkTools/ping.c index eb9224c79872..56f39a697b02 100644 --- a/plugins/NetworkTools/ping.c +++ b/plugins/NetworkTools/ping.c @@ -1,610 +1,610 @@ -/* - * Process Hacker Network Tools - - * Ping dialog - * - * Copyright (C) 2015 dmex - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include "nettools.h" -#include - -#define WM_PING_UPDATE (WM_APP + 151) - -static RECT NormalGraphTextMargin = { 5, 5, 5, 5 }; -static RECT NormalGraphTextPadding = { 3, 3, 3, 3 }; - -NTSTATUS NetworkPingThreadStart( - _In_ PVOID Parameter - ) -{ - PNETWORK_PING_CONTEXT context = (PNETWORK_PING_CONTEXT)Parameter; - HANDLE icmpHandle = INVALID_HANDLE_VALUE; - ULONG icmpCurrentPingMs = 0; - ULONG icmpReplyCount = 0; - ULONG icmpReplyLength = 0; - PVOID icmpReplyBuffer = NULL; - PPH_BYTES icmpEchoBuffer = NULL; - PPH_STRING icmpRandString = NULL; - IP_OPTION_INFORMATION pingOptions = - { - 255, // Time To Live - 0, // Type Of Service - IP_FLAG_DF, // IP header flags - 0 // Size of options data - }; - //pingOptions.Flags |= IP_FLAG_REVERSE; - - if (icmpRandString = PhCreateStringEx(NULL, PhGetIntegerSetting(SETTING_NAME_PING_SIZE) * 2 + 2)) - { - PhGenerateRandomAlphaString(icmpRandString->Buffer, (ULONG)icmpRandString->Length / sizeof(WCHAR)); - - icmpEchoBuffer = PhConvertUtf16ToMultiByte(icmpRandString->Buffer); - PhDereferenceObject(icmpRandString); - } - - if (context->RemoteEndpoint.Address.Type == PH_IPV6_NETWORK_TYPE) - { - SOCKADDR_IN6 icmp6LocalAddr = { 0 }; - SOCKADDR_IN6 icmp6RemoteAddr = { 0 }; - PICMPV6_ECHO_REPLY2 icmp6ReplyStruct = NULL; - - // TODO: Cache handle. - if ((icmpHandle = Icmp6CreateFile()) == INVALID_HANDLE_VALUE) - goto CleanupExit; - - // Set Local IPv6-ANY address. - icmp6LocalAddr.sin6_addr = in6addr_any; - icmp6LocalAddr.sin6_family = AF_INET6; - - // Set Remote IPv6 address. - icmp6RemoteAddr.sin6_addr = context->RemoteEndpoint.Address.In6Addr; - //icmp6RemoteAddr.sin6_port = _byteswap_ushort((USHORT)context->NetworkItem->RemoteEndpoint.Port); - - // Allocate ICMPv6 message. - icmpReplyLength = ICMP_BUFFER_SIZE(sizeof(ICMPV6_ECHO_REPLY), icmpEchoBuffer); - icmpReplyBuffer = PhAllocate(icmpReplyLength); - memset(icmpReplyBuffer, 0, icmpReplyLength); - - InterlockedIncrement(&context->PingSentCount); - - // Send ICMPv6 ping... - icmpReplyCount = Icmp6SendEcho2( - icmpHandle, - NULL, - NULL, - NULL, - &icmp6LocalAddr, - &icmp6RemoteAddr, - icmpEchoBuffer->Buffer, - (USHORT)icmpEchoBuffer->Length, - &pingOptions, - icmpReplyBuffer, - icmpReplyLength, - context->MaxPingTimeout - ); - - icmp6ReplyStruct = (PICMPV6_ECHO_REPLY2)icmpReplyBuffer; - - if (icmp6ReplyStruct->Status == IP_SUCCESS) - { - BOOLEAN icmpPacketSignature = FALSE; - - if (!RtlEqualMemory( - icmp6ReplyStruct->Address.sin6_addr, - context->RemoteEndpoint.Address.In6Addr.u.Word, - sizeof(icmp6ReplyStruct->Address.sin6_addr) - )) - { - InterlockedIncrement(&context->UnknownAddrCount); - } - - icmpPacketSignature = RtlEqualMemory( - icmpEchoBuffer->Buffer, - icmp6ReplyStruct->Data, - icmpEchoBuffer->Length - ); - - if (!icmpPacketSignature) - { - InterlockedIncrement(&context->HashFailCount); - } - } - else - { - InterlockedIncrement(&context->PingLossCount); - } - - icmpCurrentPingMs = icmp6ReplyStruct->RoundTripTime; - } - else - { - IPAddr icmpLocalAddr = 0; - IPAddr icmpRemoteAddr = 0; - BOOLEAN icmpPacketSignature = FALSE; - PICMP_ECHO_REPLY icmpReplyStruct = NULL; - - // TODO: Cache handle. - if ((icmpHandle = IcmpCreateFile()) == INVALID_HANDLE_VALUE) - goto CleanupExit; - - // Set Local IPv4-ANY address. - icmpLocalAddr = in4addr_any.s_addr; - - // Set Remote IPv4 address. - icmpRemoteAddr = context->RemoteEndpoint.Address.InAddr.s_addr; - - // Allocate ICMPv4 message. - icmpReplyLength = ICMP_BUFFER_SIZE(sizeof(ICMP_ECHO_REPLY), icmpEchoBuffer); - icmpReplyBuffer = PhAllocate(icmpReplyLength); - memset(icmpReplyBuffer, 0, icmpReplyLength); - - InterlockedIncrement(&context->PingSentCount); - - // Send ICMPv4 ping... - icmpReplyCount = IcmpSendEcho2Ex( - icmpHandle, - NULL, - NULL, - NULL, - icmpLocalAddr, - icmpRemoteAddr, - NULL, - 0, - &pingOptions, - icmpReplyBuffer, - icmpReplyLength, - context->MaxPingTimeout - ); - - icmpReplyStruct = (PICMP_ECHO_REPLY)icmpReplyBuffer; - - if (icmpReplyStruct->Status == IP_SUCCESS) - { - if (icmpReplyStruct->Address != context->RemoteEndpoint.Address.InAddr.s_addr) - { - InterlockedIncrement(&context->UnknownAddrCount); - } - - if (icmpReplyStruct->DataSize == icmpEchoBuffer->Length) - { - icmpPacketSignature = RtlEqualMemory( - icmpEchoBuffer->Buffer, - icmpReplyStruct->Data, - icmpReplyStruct->DataSize); - } - - if (!icmpPacketSignature) - { - InterlockedIncrement(&context->HashFailCount); - } - } - else - { - InterlockedIncrement(&context->PingLossCount); - } - - icmpCurrentPingMs = icmpReplyStruct->RoundTripTime; - } - - if (context->PingMinMs == 0 || icmpCurrentPingMs < context->PingMinMs) - context->PingMinMs = icmpCurrentPingMs; - if (icmpCurrentPingMs > context->PingMaxMs) - context->PingMaxMs = icmpCurrentPingMs; - - context->CurrentPingMs = icmpCurrentPingMs; - - InterlockedIncrement(&context->PingRecvCount); - - PhAddItemCircularBuffer_ULONG(&context->PingHistory, icmpCurrentPingMs); - -CleanupExit: - - if (icmpEchoBuffer) - { - PhDereferenceObject(icmpEchoBuffer); - } - - if (icmpHandle != INVALID_HANDLE_VALUE) - { - IcmpCloseHandle(icmpHandle); - } - - if (icmpReplyBuffer) - { - PhFree(icmpReplyBuffer); - } - - PostMessage(context->WindowHandle, WM_PING_UPDATE, 0, 0); - - return STATUS_SUCCESS; -} - -VOID NTAPI NetworkPingUpdateHandler( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - PNETWORK_PING_CONTEXT context = (PNETWORK_PING_CONTEXT)Context; - - // Queue up the next ping request - PhQueueItemWorkQueue(&context->PingWorkQueue, NetworkPingThreadStart, (PVOID)context); -} - -VOID NetworkPingUpdateGraph( - _In_ PNETWORK_PING_CONTEXT Context - ) -{ - Context->PingGraphState.Valid = FALSE; - Context->PingGraphState.TooltipIndex = -1; - Graph_MoveGrid(Context->PingGraphHandle, 1); - Graph_Draw(Context->PingGraphHandle); - Graph_UpdateTooltip(Context->PingGraphHandle); - InvalidateRect(Context->PingGraphHandle, NULL, FALSE); -} - -INT_PTR CALLBACK NetworkPingWndProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - PNETWORK_PING_CONTEXT context = NULL; - - if (uMsg == WM_INITDIALOG) - { - context = (PNETWORK_PING_CONTEXT)lParam; - SetProp(hwndDlg, L"Context", (HANDLE)context); - } - else - { - context = (PNETWORK_PING_CONTEXT)GetProp(hwndDlg, L"Context"); - } - - if (context == NULL) - return FALSE; - - switch (uMsg) - { - case WM_INITDIALOG: - { - PPH_LAYOUT_ITEM panelItem; - - // We have already set the group boxes to have WS_EX_TRANSPARENT to fix - // the drawing issue that arises when using WS_CLIPCHILDREN. However - // in removing the flicker from the graphs the group boxes will now flicker. - // It's a good tradeoff since no one stares at the group boxes. - PhSetWindowStyle(hwndDlg, WS_CLIPCHILDREN, WS_CLIPCHILDREN); - - context->WindowHandle = hwndDlg; - context->StatusHandle = GetDlgItem(hwndDlg, IDC_MAINTEXT); - context->MaxPingTimeout = PhGetIntegerSetting(SETTING_NAME_PING_MINIMUM_SCALING); - context->FontHandle = PhCreateCommonFont(-15, FW_MEDIUM, context->StatusHandle); - context->PingGraphHandle = CreateWindow( - PH_GRAPH_CLASSNAME, - NULL, - WS_VISIBLE | WS_CHILD | WS_BORDER, - 0, - 0, - 3, - 3, - hwndDlg, - NULL, - NULL, - NULL - ); - Graph_SetTooltip(context->PingGraphHandle, TRUE); - - PhInitializeWorkQueue(&context->PingWorkQueue, 0, 20, 5000); - PhInitializeGraphState(&context->PingGraphState); - PhInitializeLayoutManager(&context->LayoutManager, hwndDlg); - PhInitializeCircularBuffer_ULONG(&context->PingHistory, PhGetIntegerSetting(L"SampleCount")); - - PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_ICMP_PANEL), NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_LEFT | PH_ANCHOR_RIGHT| PH_LAYOUT_FORCE_INVALIDATE); - PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_ICMP_AVG), NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_LEFT); - PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_ICMP_MIN), NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_LEFT); - PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_ICMP_MAX), NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_LEFT); - PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_PINGS_SENT), NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_LEFT); - PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_PINGS_LOST), NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_LEFT); - PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_BAD_HASH), NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_LEFT); - PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_ANON_ADDR), NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_LEFT); - panelItem = PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_PING_LAYOUT), NULL, PH_ANCHOR_ALL); - PhAddLayoutItemEx(&context->LayoutManager, context->PingGraphHandle, NULL, PH_ANCHOR_ALL, panelItem->Margin); - - if (PhGetIntegerPairSetting(SETTING_NAME_PING_WINDOW_POSITION).X != 0) - PhLoadWindowPlacementFromSetting(SETTING_NAME_PING_WINDOW_POSITION, SETTING_NAME_PING_WINDOW_SIZE, hwndDlg); - else - PhCenterWindow(hwndDlg, PhMainWndHandle); - - SetWindowText(hwndDlg, PhaFormatString(L"Ping %s", context->IpAddressString)->Buffer); - SetWindowText(context->StatusHandle, PhaFormatString(L"Pinging %s with %lu bytes of data...", - context->IpAddressString, - PhGetIntegerSetting(SETTING_NAME_PING_SIZE))->Buffer - ); - - PhRegisterCallback( - &PhProcessesUpdatedEvent, - NetworkPingUpdateHandler, - context, - &context->ProcessesUpdatedRegistration - ); - - EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); - } - return TRUE; - case WM_COMMAND: - { - switch (LOWORD(wParam)) - { - case IDCANCEL: - case IDOK: - DestroyWindow(hwndDlg); - break; - } - } - break; - case WM_DESTROY: - { - PhUnregisterCallback( - &PhProcessesUpdatedEvent, - &context->ProcessesUpdatedRegistration - ); - - PhSaveWindowPlacementToSetting( - SETTING_NAME_PING_WINDOW_POSITION, - SETTING_NAME_PING_WINDOW_SIZE, - hwndDlg - ); - - if (context->PingGraphHandle) - DestroyWindow(context->PingGraphHandle); - - if (context->FontHandle) - DeleteObject(context->FontHandle); - - PhDeleteWorkQueue(&context->PingWorkQueue); - PhDeleteGraphState(&context->PingGraphState); - PhDeleteLayoutManager(&context->LayoutManager); - - RemoveProp(hwndDlg, L"Context"); - PhFree(context); - - PostQuitMessage(0); - } - break; - case WM_SIZE: - PhLayoutManagerLayout(&context->LayoutManager); - break; - case WM_SIZING: - //PhResizingMinimumSize((PRECT)lParam, wParam, 420, 250); - break; - case WM_PING_UPDATE: - { - ULONG maxGraphHeight = 0; - ULONG pingAvgValue = 0; - - NetworkPingUpdateGraph(context); - - for (ULONG i = 0; i < context->PingHistory.Count; i++) - { - maxGraphHeight = maxGraphHeight + PhGetItemCircularBuffer_ULONG(&context->PingHistory, i); - pingAvgValue = maxGraphHeight / context->PingHistory.Count; - } - - SetDlgItemText(hwndDlg, IDC_ICMP_AVG, PhaFormatString( - L"Average: %lums", pingAvgValue)->Buffer); - SetDlgItemText(hwndDlg, IDC_ICMP_MIN, PhaFormatString( - L"Minimum: %lums", context->PingMinMs)->Buffer); - SetDlgItemText(hwndDlg, IDC_ICMP_MAX, PhaFormatString( - L"Maximum: %lums", context->PingMaxMs)->Buffer); - - SetDlgItemText(hwndDlg, IDC_PINGS_SENT, PhaFormatString( - L"Pings sent: %lu", context->PingSentCount)->Buffer); - SetDlgItemText(hwndDlg, IDC_PINGS_LOST, PhaFormatString( - L"Pings lost: %lu (%.0f%%)", context->PingLossCount, - ((FLOAT)context->PingLossCount / context->PingSentCount * 100))->Buffer); - - //SetDlgItemText(hwndDlg, IDC_BAD_HASH, PhaFormatString( - // L"Bad hashes: %lu", context->HashFailCount)->Buffer); - SetDlgItemText(hwndDlg, IDC_ANON_ADDR, PhaFormatString( - L"Anon replies: %lu", context->UnknownAddrCount)->Buffer); - } - break; - case WM_NOTIFY: - { - LPNMHDR header = (LPNMHDR)lParam; - - switch (header->code) - { - case GCN_GETDRAWINFO: - { - PPH_GRAPH_GETDRAWINFO getDrawInfo = (PPH_GRAPH_GETDRAWINFO)header; - PPH_GRAPH_DRAW_INFO drawInfo = getDrawInfo->DrawInfo; - - if (header->hwndFrom == context->PingGraphHandle) - { - if (PhGetIntegerSetting(L"GraphShowText")) - { - HDC hdc = Graph_GetBufferedContext(context->PingGraphHandle); - - PhMoveReference(&context->PingGraphState.Text, - PhFormatString(L"%lu ms", context->CurrentPingMs) - ); - - SelectObject(hdc, PhApplicationFont); - PhSetGraphText(hdc, drawInfo, &context->PingGraphState.Text->sr, - &NormalGraphTextMargin, &NormalGraphTextPadding, PH_ALIGN_TOP | PH_ALIGN_LEFT); - } - else - { - drawInfo->Text.Buffer = NULL; - } - - drawInfo->Flags = PH_GRAPH_USE_GRID_X | PH_GRAPH_USE_GRID_Y; - PhSiSetColorsGraphDrawInfo(drawInfo, PhGetIntegerSetting(L"ColorCpuKernel"), 0); - PhGraphStateGetDrawInfo(&context->PingGraphState, getDrawInfo, context->PingHistory.Count); - - if (!context->PingGraphState.Valid) - { - ULONG i; - FLOAT max = (FLOAT)context->MaxPingTimeout; // minimum scaling - - for (i = 0; i < drawInfo->LineDataCount; i++) - { - FLOAT data1; - - context->PingGraphState.Data1[i] = data1 = (FLOAT)PhGetItemCircularBuffer_ULONG(&context->PingHistory, i); - - if (max < data1) - max = data1; - } - - // Scale the data. - PhDivideSinglesBySingle( - context->PingGraphState.Data1, - max, - drawInfo->LineDataCount - ); - - context->PingGraphState.Valid = TRUE; - } - } - } - break; - case GCN_GETTOOLTIPTEXT: - { - PPH_GRAPH_GETTOOLTIPTEXT getTooltipText = (PPH_GRAPH_GETTOOLTIPTEXT)lParam; - - if (getTooltipText->Index < getTooltipText->TotalCount) - { - if (header->hwndFrom == context->PingGraphHandle) - { - if (context->PingGraphState.TooltipIndex != getTooltipText->Index) - { - ULONG pingMs = PhGetItemCircularBuffer_ULONG(&context->PingHistory, getTooltipText->Index); - - PhMoveReference(&context->PingGraphState.TooltipText, PhFormatString( - L"%lu ms\n%s", - pingMs, - PH_AUTO_T(PH_STRING, PhGetStatisticsTimeString(NULL, getTooltipText->Index))->Buffer) - ); - } - - getTooltipText->Text = context->PingGraphState.TooltipText->sr; - } - } - } - break; - } - } - break; - } - - return FALSE; -} - -NTSTATUS NetworkPingDialogThreadStart( - _In_ PVOID Parameter - ) -{ - BOOL result; - MSG message; - HWND windowHandle; - PH_AUTO_POOL autoPool; - - PhInitializeAutoPool(&autoPool); - - windowHandle = CreateDialogParam( - PluginInstance->DllBase, - MAKEINTRESOURCE(IDD_PING), - NULL, - NetworkPingWndProc, - (LPARAM)Parameter - ); - - ShowWindow(windowHandle, SW_SHOW); - SetForegroundWindow(windowHandle); - - while (result = GetMessage(&message, NULL, 0, 0)) - { - if (result == -1) - break; - - if (!IsDialogMessage(windowHandle, &message)) - { - TranslateMessage(&message); - DispatchMessage(&message); - } - - PhDrainAutoPool(&autoPool); - } - - PhDeleteAutoPool(&autoPool); - - return STATUS_SUCCESS; -} - -VOID ShowPingWindow( - _In_ PPH_NETWORK_ITEM NetworkItem - ) -{ - HANDLE dialogThread; - PNETWORK_PING_CONTEXT context; - - context = (PNETWORK_PING_CONTEXT)PhAllocate(sizeof(NETWORK_PING_CONTEXT)); - memset(context, 0, sizeof(NETWORK_PING_CONTEXT)); - - if (NetworkItem->RemoteEndpoint.Address.Type == PH_IPV4_NETWORK_TYPE) - RtlIpv4AddressToString(&NetworkItem->RemoteEndpoint.Address.InAddr, context->IpAddressString); - else - RtlIpv6AddressToString(&NetworkItem->RemoteEndpoint.Address.In6Addr, context->IpAddressString); - - context->RemoteEndpoint = NetworkItem->RemoteEndpoint; - - if (dialogThread = PhCreateThread(0, NetworkPingDialogThreadStart, (PVOID)context)) - { - NtClose(dialogThread); - } -} - -VOID ShowPingWindowFromAddress( - _In_ PH_IP_ENDPOINT RemoteEndpoint - ) -{ - HANDLE dialogThread; - PNETWORK_PING_CONTEXT context; - - context = (PNETWORK_PING_CONTEXT)PhAllocate(sizeof(NETWORK_PING_CONTEXT)); - memset(context, 0, sizeof(NETWORK_PING_CONTEXT)); - - if (RemoteEndpoint.Address.Type == PH_IPV4_NETWORK_TYPE) - { - RtlIpv4AddressToString(&RemoteEndpoint.Address.InAddr, context->IpAddressString); - } - else - { - RtlIpv6AddressToString(&RemoteEndpoint.Address.In6Addr, context->IpAddressString); - } - - context->RemoteEndpoint = RemoteEndpoint; - - if (dialogThread = PhCreateThread(0, NetworkPingDialogThreadStart, (PVOID)context)) - { - NtClose(dialogThread); - } +/* + * Process Hacker Network Tools - + * Ping dialog + * + * Copyright (C) 2015 dmex + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include "nettools.h" +#include + +#define WM_PING_UPDATE (WM_APP + 151) + +static RECT NormalGraphTextMargin = { 5, 5, 5, 5 }; +static RECT NormalGraphTextPadding = { 3, 3, 3, 3 }; + +NTSTATUS NetworkPingThreadStart( + _In_ PVOID Parameter + ) +{ + PNETWORK_PING_CONTEXT context = (PNETWORK_PING_CONTEXT)Parameter; + HANDLE icmpHandle = INVALID_HANDLE_VALUE; + ULONG icmpCurrentPingMs = 0; + ULONG icmpReplyCount = 0; + ULONG icmpReplyLength = 0; + PVOID icmpReplyBuffer = NULL; + PPH_BYTES icmpEchoBuffer = NULL; + PPH_STRING icmpRandString = NULL; + IP_OPTION_INFORMATION pingOptions = + { + 255, // Time To Live + 0, // Type Of Service + IP_FLAG_DF, // IP header flags + 0 // Size of options data + }; + //pingOptions.Flags |= IP_FLAG_REVERSE; + + if (icmpRandString = PhCreateStringEx(NULL, PhGetIntegerSetting(SETTING_NAME_PING_SIZE) * 2 + 2)) + { + PhGenerateRandomAlphaString(icmpRandString->Buffer, (ULONG)icmpRandString->Length / sizeof(WCHAR)); + + icmpEchoBuffer = PhConvertUtf16ToMultiByte(icmpRandString->Buffer); + PhDereferenceObject(icmpRandString); + } + + if (context->RemoteEndpoint.Address.Type == PH_IPV6_NETWORK_TYPE) + { + SOCKADDR_IN6 icmp6LocalAddr = { 0 }; + SOCKADDR_IN6 icmp6RemoteAddr = { 0 }; + PICMPV6_ECHO_REPLY2 icmp6ReplyStruct = NULL; + + // TODO: Cache handle. + if ((icmpHandle = Icmp6CreateFile()) == INVALID_HANDLE_VALUE) + goto CleanupExit; + + // Set Local IPv6-ANY address. + icmp6LocalAddr.sin6_addr = in6addr_any; + icmp6LocalAddr.sin6_family = AF_INET6; + + // Set Remote IPv6 address. + icmp6RemoteAddr.sin6_addr = context->RemoteEndpoint.Address.In6Addr; + //icmp6RemoteAddr.sin6_port = _byteswap_ushort((USHORT)context->NetworkItem->RemoteEndpoint.Port); + + // Allocate ICMPv6 message. + icmpReplyLength = ICMP_BUFFER_SIZE(sizeof(ICMPV6_ECHO_REPLY), icmpEchoBuffer); + icmpReplyBuffer = PhAllocate(icmpReplyLength); + memset(icmpReplyBuffer, 0, icmpReplyLength); + + InterlockedIncrement(&context->PingSentCount); + + // Send ICMPv6 ping... + icmpReplyCount = Icmp6SendEcho2( + icmpHandle, + NULL, + NULL, + NULL, + &icmp6LocalAddr, + &icmp6RemoteAddr, + icmpEchoBuffer->Buffer, + (USHORT)icmpEchoBuffer->Length, + &pingOptions, + icmpReplyBuffer, + icmpReplyLength, + context->MaxPingTimeout + ); + + icmp6ReplyStruct = (PICMPV6_ECHO_REPLY2)icmpReplyBuffer; + + if (icmp6ReplyStruct->Status == IP_SUCCESS) + { + BOOLEAN icmpPacketSignature = FALSE; + + if (!RtlEqualMemory( + icmp6ReplyStruct->Address.sin6_addr, + context->RemoteEndpoint.Address.In6Addr.u.Word, + sizeof(icmp6ReplyStruct->Address.sin6_addr) + )) + { + InterlockedIncrement(&context->UnknownAddrCount); + } + + icmpPacketSignature = RtlEqualMemory( + icmpEchoBuffer->Buffer, + icmp6ReplyStruct->Data, + icmpEchoBuffer->Length + ); + + if (!icmpPacketSignature) + { + InterlockedIncrement(&context->HashFailCount); + } + } + else + { + InterlockedIncrement(&context->PingLossCount); + } + + icmpCurrentPingMs = icmp6ReplyStruct->RoundTripTime; + } + else + { + IPAddr icmpLocalAddr = 0; + IPAddr icmpRemoteAddr = 0; + BOOLEAN icmpPacketSignature = FALSE; + PICMP_ECHO_REPLY icmpReplyStruct = NULL; + + // TODO: Cache handle. + if ((icmpHandle = IcmpCreateFile()) == INVALID_HANDLE_VALUE) + goto CleanupExit; + + // Set Local IPv4-ANY address. + icmpLocalAddr = in4addr_any.s_addr; + + // Set Remote IPv4 address. + icmpRemoteAddr = context->RemoteEndpoint.Address.InAddr.s_addr; + + // Allocate ICMPv4 message. + icmpReplyLength = ICMP_BUFFER_SIZE(sizeof(ICMP_ECHO_REPLY), icmpEchoBuffer); + icmpReplyBuffer = PhAllocate(icmpReplyLength); + memset(icmpReplyBuffer, 0, icmpReplyLength); + + InterlockedIncrement(&context->PingSentCount); + + // Send ICMPv4 ping... + icmpReplyCount = IcmpSendEcho2Ex( + icmpHandle, + NULL, + NULL, + NULL, + icmpLocalAddr, + icmpRemoteAddr, + NULL, + 0, + &pingOptions, + icmpReplyBuffer, + icmpReplyLength, + context->MaxPingTimeout + ); + + icmpReplyStruct = (PICMP_ECHO_REPLY)icmpReplyBuffer; + + if (icmpReplyStruct->Status == IP_SUCCESS) + { + if (icmpReplyStruct->Address != context->RemoteEndpoint.Address.InAddr.s_addr) + { + InterlockedIncrement(&context->UnknownAddrCount); + } + + if (icmpReplyStruct->DataSize == icmpEchoBuffer->Length) + { + icmpPacketSignature = RtlEqualMemory( + icmpEchoBuffer->Buffer, + icmpReplyStruct->Data, + icmpReplyStruct->DataSize); + } + + if (!icmpPacketSignature) + { + InterlockedIncrement(&context->HashFailCount); + } + } + else + { + InterlockedIncrement(&context->PingLossCount); + } + + icmpCurrentPingMs = icmpReplyStruct->RoundTripTime; + } + + if (context->PingMinMs == 0 || icmpCurrentPingMs < context->PingMinMs) + context->PingMinMs = icmpCurrentPingMs; + if (icmpCurrentPingMs > context->PingMaxMs) + context->PingMaxMs = icmpCurrentPingMs; + + context->CurrentPingMs = icmpCurrentPingMs; + + InterlockedIncrement(&context->PingRecvCount); + + PhAddItemCircularBuffer_ULONG(&context->PingHistory, icmpCurrentPingMs); + +CleanupExit: + + if (icmpEchoBuffer) + { + PhDereferenceObject(icmpEchoBuffer); + } + + if (icmpHandle != INVALID_HANDLE_VALUE) + { + IcmpCloseHandle(icmpHandle); + } + + if (icmpReplyBuffer) + { + PhFree(icmpReplyBuffer); + } + + PostMessage(context->WindowHandle, WM_PING_UPDATE, 0, 0); + + return STATUS_SUCCESS; +} + +VOID NTAPI NetworkPingUpdateHandler( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + PNETWORK_PING_CONTEXT context = (PNETWORK_PING_CONTEXT)Context; + + // Queue up the next ping request + PhQueueItemWorkQueue(&context->PingWorkQueue, NetworkPingThreadStart, (PVOID)context); +} + +VOID NetworkPingUpdateGraph( + _In_ PNETWORK_PING_CONTEXT Context + ) +{ + Context->PingGraphState.Valid = FALSE; + Context->PingGraphState.TooltipIndex = -1; + Graph_MoveGrid(Context->PingGraphHandle, 1); + Graph_Draw(Context->PingGraphHandle); + Graph_UpdateTooltip(Context->PingGraphHandle); + InvalidateRect(Context->PingGraphHandle, NULL, FALSE); +} + +INT_PTR CALLBACK NetworkPingWndProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + PNETWORK_PING_CONTEXT context = NULL; + + if (uMsg == WM_INITDIALOG) + { + context = (PNETWORK_PING_CONTEXT)lParam; + SetProp(hwndDlg, L"Context", (HANDLE)context); + } + else + { + context = (PNETWORK_PING_CONTEXT)GetProp(hwndDlg, L"Context"); + } + + if (context == NULL) + return FALSE; + + switch (uMsg) + { + case WM_INITDIALOG: + { + PPH_LAYOUT_ITEM panelItem; + + // We have already set the group boxes to have WS_EX_TRANSPARENT to fix + // the drawing issue that arises when using WS_CLIPCHILDREN. However + // in removing the flicker from the graphs the group boxes will now flicker. + // It's a good tradeoff since no one stares at the group boxes. + PhSetWindowStyle(hwndDlg, WS_CLIPCHILDREN, WS_CLIPCHILDREN); + + context->WindowHandle = hwndDlg; + context->StatusHandle = GetDlgItem(hwndDlg, IDC_MAINTEXT); + context->MaxPingTimeout = PhGetIntegerSetting(SETTING_NAME_PING_MINIMUM_SCALING); + context->FontHandle = PhCreateCommonFont(-15, FW_MEDIUM, context->StatusHandle); + context->PingGraphHandle = CreateWindow( + PH_GRAPH_CLASSNAME, + NULL, + WS_VISIBLE | WS_CHILD | WS_BORDER, + 0, + 0, + 3, + 3, + hwndDlg, + NULL, + NULL, + NULL + ); + Graph_SetTooltip(context->PingGraphHandle, TRUE); + + PhInitializeWorkQueue(&context->PingWorkQueue, 0, 20, 5000); + PhInitializeGraphState(&context->PingGraphState); + PhInitializeLayoutManager(&context->LayoutManager, hwndDlg); + PhInitializeCircularBuffer_ULONG(&context->PingHistory, PhGetIntegerSetting(L"SampleCount")); + + PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_ICMP_PANEL), NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_LEFT | PH_ANCHOR_RIGHT| PH_LAYOUT_FORCE_INVALIDATE); + PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_ICMP_AVG), NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_LEFT); + PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_ICMP_MIN), NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_LEFT); + PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_ICMP_MAX), NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_LEFT); + PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_PINGS_SENT), NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_LEFT); + PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_PINGS_LOST), NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_LEFT); + PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_BAD_HASH), NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_LEFT); + PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_ANON_ADDR), NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_LEFT); + panelItem = PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_PING_LAYOUT), NULL, PH_ANCHOR_ALL); + PhAddLayoutItemEx(&context->LayoutManager, context->PingGraphHandle, NULL, PH_ANCHOR_ALL, panelItem->Margin); + + if (PhGetIntegerPairSetting(SETTING_NAME_PING_WINDOW_POSITION).X != 0) + PhLoadWindowPlacementFromSetting(SETTING_NAME_PING_WINDOW_POSITION, SETTING_NAME_PING_WINDOW_SIZE, hwndDlg); + else + PhCenterWindow(hwndDlg, PhMainWndHandle); + + SetWindowText(hwndDlg, PhaFormatString(L"Ping %s", context->IpAddressString)->Buffer); + SetWindowText(context->StatusHandle, PhaFormatString(L"Pinging %s with %lu bytes of data...", + context->IpAddressString, + PhGetIntegerSetting(SETTING_NAME_PING_SIZE))->Buffer + ); + + PhRegisterCallback( + &PhProcessesUpdatedEvent, + NetworkPingUpdateHandler, + context, + &context->ProcessesUpdatedRegistration + ); + + EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); + } + return TRUE; + case WM_COMMAND: + { + switch (LOWORD(wParam)) + { + case IDCANCEL: + case IDOK: + DestroyWindow(hwndDlg); + break; + } + } + break; + case WM_DESTROY: + { + PhUnregisterCallback( + &PhProcessesUpdatedEvent, + &context->ProcessesUpdatedRegistration + ); + + PhSaveWindowPlacementToSetting( + SETTING_NAME_PING_WINDOW_POSITION, + SETTING_NAME_PING_WINDOW_SIZE, + hwndDlg + ); + + if (context->PingGraphHandle) + DestroyWindow(context->PingGraphHandle); + + if (context->FontHandle) + DeleteObject(context->FontHandle); + + PhDeleteWorkQueue(&context->PingWorkQueue); + PhDeleteGraphState(&context->PingGraphState); + PhDeleteLayoutManager(&context->LayoutManager); + + RemoveProp(hwndDlg, L"Context"); + PhFree(context); + + PostQuitMessage(0); + } + break; + case WM_SIZE: + PhLayoutManagerLayout(&context->LayoutManager); + break; + case WM_SIZING: + //PhResizingMinimumSize((PRECT)lParam, wParam, 420, 250); + break; + case WM_PING_UPDATE: + { + ULONG maxGraphHeight = 0; + ULONG pingAvgValue = 0; + + NetworkPingUpdateGraph(context); + + for (ULONG i = 0; i < context->PingHistory.Count; i++) + { + maxGraphHeight = maxGraphHeight + PhGetItemCircularBuffer_ULONG(&context->PingHistory, i); + pingAvgValue = maxGraphHeight / context->PingHistory.Count; + } + + SetDlgItemText(hwndDlg, IDC_ICMP_AVG, PhaFormatString( + L"Average: %lums", pingAvgValue)->Buffer); + SetDlgItemText(hwndDlg, IDC_ICMP_MIN, PhaFormatString( + L"Minimum: %lums", context->PingMinMs)->Buffer); + SetDlgItemText(hwndDlg, IDC_ICMP_MAX, PhaFormatString( + L"Maximum: %lums", context->PingMaxMs)->Buffer); + + SetDlgItemText(hwndDlg, IDC_PINGS_SENT, PhaFormatString( + L"Pings sent: %lu", context->PingSentCount)->Buffer); + SetDlgItemText(hwndDlg, IDC_PINGS_LOST, PhaFormatString( + L"Pings lost: %lu (%.0f%%)", context->PingLossCount, + ((FLOAT)context->PingLossCount / context->PingSentCount * 100))->Buffer); + + //SetDlgItemText(hwndDlg, IDC_BAD_HASH, PhaFormatString( + // L"Bad hashes: %lu", context->HashFailCount)->Buffer); + SetDlgItemText(hwndDlg, IDC_ANON_ADDR, PhaFormatString( + L"Anon replies: %lu", context->UnknownAddrCount)->Buffer); + } + break; + case WM_NOTIFY: + { + LPNMHDR header = (LPNMHDR)lParam; + + switch (header->code) + { + case GCN_GETDRAWINFO: + { + PPH_GRAPH_GETDRAWINFO getDrawInfo = (PPH_GRAPH_GETDRAWINFO)header; + PPH_GRAPH_DRAW_INFO drawInfo = getDrawInfo->DrawInfo; + + if (header->hwndFrom == context->PingGraphHandle) + { + if (PhGetIntegerSetting(L"GraphShowText")) + { + HDC hdc = Graph_GetBufferedContext(context->PingGraphHandle); + + PhMoveReference(&context->PingGraphState.Text, + PhFormatString(L"%lu ms", context->CurrentPingMs) + ); + + SelectObject(hdc, PhApplicationFont); + PhSetGraphText(hdc, drawInfo, &context->PingGraphState.Text->sr, + &NormalGraphTextMargin, &NormalGraphTextPadding, PH_ALIGN_TOP | PH_ALIGN_LEFT); + } + else + { + drawInfo->Text.Buffer = NULL; + } + + drawInfo->Flags = PH_GRAPH_USE_GRID_X | PH_GRAPH_USE_GRID_Y; + PhSiSetColorsGraphDrawInfo(drawInfo, PhGetIntegerSetting(L"ColorCpuKernel"), 0); + PhGraphStateGetDrawInfo(&context->PingGraphState, getDrawInfo, context->PingHistory.Count); + + if (!context->PingGraphState.Valid) + { + ULONG i; + FLOAT max = (FLOAT)context->MaxPingTimeout; // minimum scaling + + for (i = 0; i < drawInfo->LineDataCount; i++) + { + FLOAT data1; + + context->PingGraphState.Data1[i] = data1 = (FLOAT)PhGetItemCircularBuffer_ULONG(&context->PingHistory, i); + + if (max < data1) + max = data1; + } + + // Scale the data. + PhDivideSinglesBySingle( + context->PingGraphState.Data1, + max, + drawInfo->LineDataCount + ); + + context->PingGraphState.Valid = TRUE; + } + } + } + break; + case GCN_GETTOOLTIPTEXT: + { + PPH_GRAPH_GETTOOLTIPTEXT getTooltipText = (PPH_GRAPH_GETTOOLTIPTEXT)lParam; + + if (getTooltipText->Index < getTooltipText->TotalCount) + { + if (header->hwndFrom == context->PingGraphHandle) + { + if (context->PingGraphState.TooltipIndex != getTooltipText->Index) + { + ULONG pingMs = PhGetItemCircularBuffer_ULONG(&context->PingHistory, getTooltipText->Index); + + PhMoveReference(&context->PingGraphState.TooltipText, PhFormatString( + L"%lu ms\n%s", + pingMs, + PH_AUTO_T(PH_STRING, PhGetStatisticsTimeString(NULL, getTooltipText->Index))->Buffer) + ); + } + + getTooltipText->Text = context->PingGraphState.TooltipText->sr; + } + } + } + break; + } + } + break; + } + + return FALSE; +} + +NTSTATUS NetworkPingDialogThreadStart( + _In_ PVOID Parameter + ) +{ + BOOL result; + MSG message; + HWND windowHandle; + PH_AUTO_POOL autoPool; + + PhInitializeAutoPool(&autoPool); + + windowHandle = CreateDialogParam( + PluginInstance->DllBase, + MAKEINTRESOURCE(IDD_PING), + NULL, + NetworkPingWndProc, + (LPARAM)Parameter + ); + + ShowWindow(windowHandle, SW_SHOW); + SetForegroundWindow(windowHandle); + + while (result = GetMessage(&message, NULL, 0, 0)) + { + if (result == -1) + break; + + if (!IsDialogMessage(windowHandle, &message)) + { + TranslateMessage(&message); + DispatchMessage(&message); + } + + PhDrainAutoPool(&autoPool); + } + + PhDeleteAutoPool(&autoPool); + + return STATUS_SUCCESS; +} + +VOID ShowPingWindow( + _In_ PPH_NETWORK_ITEM NetworkItem + ) +{ + HANDLE dialogThread; + PNETWORK_PING_CONTEXT context; + + context = (PNETWORK_PING_CONTEXT)PhAllocate(sizeof(NETWORK_PING_CONTEXT)); + memset(context, 0, sizeof(NETWORK_PING_CONTEXT)); + + if (NetworkItem->RemoteEndpoint.Address.Type == PH_IPV4_NETWORK_TYPE) + RtlIpv4AddressToString(&NetworkItem->RemoteEndpoint.Address.InAddr, context->IpAddressString); + else + RtlIpv6AddressToString(&NetworkItem->RemoteEndpoint.Address.In6Addr, context->IpAddressString); + + context->RemoteEndpoint = NetworkItem->RemoteEndpoint; + + if (dialogThread = PhCreateThread(0, NetworkPingDialogThreadStart, (PVOID)context)) + { + NtClose(dialogThread); + } +} + +VOID ShowPingWindowFromAddress( + _In_ PH_IP_ENDPOINT RemoteEndpoint + ) +{ + HANDLE dialogThread; + PNETWORK_PING_CONTEXT context; + + context = (PNETWORK_PING_CONTEXT)PhAllocate(sizeof(NETWORK_PING_CONTEXT)); + memset(context, 0, sizeof(NETWORK_PING_CONTEXT)); + + if (RemoteEndpoint.Address.Type == PH_IPV4_NETWORK_TYPE) + { + RtlIpv4AddressToString(&RemoteEndpoint.Address.InAddr, context->IpAddressString); + } + else + { + RtlIpv6AddressToString(&RemoteEndpoint.Address.In6Addr, context->IpAddressString); + } + + context->RemoteEndpoint = RemoteEndpoint; + + if (dialogThread = PhCreateThread(0, NetworkPingDialogThreadStart, (PVOID)context)) + { + NtClose(dialogThread); + } } \ No newline at end of file diff --git a/plugins/NetworkTools/resource.h b/plugins/NetworkTools/resource.h index 1747f72aae6f..84bd7f5c868c 100644 --- a/plugins/NetworkTools/resource.h +++ b/plugins/NetworkTools/resource.h @@ -1,282 +1,282 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by NetworkTools.rc -// -#define AD_PNG 101 -#define AE_PNG 102 -#define AF_PNG 103 -#define AG_PNG 104 -#define AI_PNG 105 -#define AL_PNG 106 -#define AM_PNG 107 -#define AN_PNG 108 -#define AO_PNG 109 -#define AR_PNG 110 -#define AS_PNG 111 -#define AT_PNG 112 -#define AU_PNG 113 -#define AW_PNG 114 -#define AX_PNG 115 -#define AZ_PNG 116 -#define BA_PNG 117 -#define BB_PNG 118 -#define BD_PNG 119 -#define BE_PNG 120 -#define BF_PNG 121 -#define BG_PNG 122 -#define BH_PNG 123 -#define BI__PNG 124 -#define BJ_PNG 125 -#define BM_PNG 126 -#define BN_PNG 127 -#define BO_PNG 128 -#define BR_PNG 129 -#define BS_PNG 130 -#define BT_PNG 131 -#define BV_PNG 132 -#define BW_PNG 133 -#define BY_PNG 134 -#define BZ_PNG 135 -#define CA_PNG 136 -#define AAC_PNG 137 -#define CC_PNG 138 -#define CD_PNG 139 -#define CF_PNG 140 -#define CG_PNG 141 -#define CH_PNG 142 -#define CI_PNG 143 -#define CK_PNG 144 -#define CL_PNG 145 -#define CM_PNG 146 -#define CN_PNG 147 -#define CO_PNG 148 -#define CR_PNG 149 -#define IDD_WHOIS 149 -#define CS_PNG 150 -#define IDD_PING 150 -#define CU_PNG 151 -#define IDD_OPTIONS 151 -#define CV_PNG 152 -#define IDD_TRACERT 152 -#define CX_PNG 153 -#define CY_PNG 154 -#define CZ_PNG 155 -#define DE_PNG 156 -#define DJ_PNG 157 -#define DK_PNG 158 -#define DM_PNG 159 -#define DO_PNG 160 -#define DZ_PNG 161 -#define EC_PNG 162 -#define EE_PNG 163 -#define EG_PNG 164 -#define EH_PNG 165 -#define AAD_PNG 166 -#define ER_PNG 167 -#define ES_PNG 168 -#define ET_PNG 169 -#define AAE_PNG 170 -#define AAF_PNG 171 -#define FI_PNG 172 -#define FJ_PNG 173 -#define FK_PNG 174 -#define FM_PNG 175 -#define FO_PNG 176 -#define FR_PNG 177 -#define GA_PNG 178 -#define GB_PNG 179 -#define GD_PNG 180 -#define GE_PNG 181 -#define GF_PNG 182 -#define GH_PNG 183 -#define GI_PNG 184 -#define GL_PNG 185 -#define GM_PNG 186 -#define GN_PNG 187 -#define GP_PNG 188 -#define GQ_PNG 189 -#define GR_PNG 190 -#define GS_PNG 191 -#define GT_PNG 192 -#define GU_PNG 193 -#define GW_PNG 194 -#define GY_PNG 195 -#define HK_PNG 196 -#define HM_PNG 197 -#define HN_PNG 198 -#define HR_PNG 199 -#define HT_PNG 200 -#define ID_PNG 202 -#define IE_PNG 203 -#define IL_PNG 204 -#define IN_PNG 205 -#define IO_PNG 206 -#define IQ_PNG 207 -#define IR_PNG 208 -#define IS_PNG 209 -#define IT_PNG 210 -#define JM_PNG 211 -#define JO_PNG 212 -#define JP_PNG 213 -#define KE_PNG 214 -#define KG_PNG 215 -#define KH_PNG 216 -#define KI_PNG 217 -#define KM_PNG 218 -#define KN_PNG 219 -#define KP_PNG 220 -#define KR_PNG 221 -#define KW_PNG 222 -#define KY_PNG 223 -#define KZ_PNG 224 -#define LA_PNG 225 -#define LB_PNG 226 -#define LC_PNG 227 -#define LI_PNG 228 -#define LK_PNG 229 -#define LR_PNG 230 -#define LS_PNG 231 -#define LT_PNG 232 -#define LU_PNG 233 -#define LV_PNG 234 -#define LY_PNG 235 -#define MA_PNG 236 -#define MC_PNG 237 -#define MD_PNG 238 -#define ME_PNG 239 -#define MG_PNG 240 -#define MH_PNG 241 -#define MK_PNG 242 -#define ML_PNG 243 -#define MM_PNG 244 -#define MN_PNG 245 -#define MO_PNG 246 -#define MP_PNG 247 -#define MQ_PNG 248 -#define MR_PNG 249 -#define MS_PNG 250 -#define MT_PNG 251 -#define MU_PNG 252 -#define MV_PNG 253 -#define MW_PNG 254 -#define MX_PNG 255 -#define MY_PNG 256 -#define MZ_PNG 257 -#define NA_PNG 258 -#define NC_PNG 259 -#define NE_PNG 260 -#define NF_PNG 261 -#define NG_PNG 262 -#define NI_PNG 263 -#define NL_PNG 264 -#define NO_PNG 265 -#define NP_PNG 266 -#define NR_PNG 267 -#define NU_PNG 268 -#define NZ_PNG 269 -#define OM_PNG 270 -#define PA_PNG 271 -#define PE_PNG 272 -#define PF_PNG 273 -#define PG_PNG 274 -#define PH_PNG 275 -#define PK_PNG 276 -#define PL_PNG 277 -#define PM_PNG 278 -#define PN_PNG 279 -#define PR_PNG 280 -#define PS_PNG 281 -#define PT_PNG 282 -#define PW_PNG 283 -#define PY_PNG 284 -#define QA_PNG 285 -#define RE_PNG 286 -#define RO_PNG 287 -#define RS_PNG 288 -#define RU_PNG 289 -#define RW_PNG 290 -#define SA_PNG 291 -#define SB_PNG 292 -#define SC_PNG 293 -#define AAA_PNG 294 -#define SD_PNG 295 -#define SE_PNG 296 -#define SG_PNG 297 -#define SH_PNG 298 -#define SI_PNG 299 -#define SJ_PNG 300 -#define SK_PNG 301 -#define SL_PNG 302 -#define SM_PNG 303 -#define SN_PNG 304 -#define SO_PNG 305 -#define SR_PNG 306 -#define ST_PNG 307 -#define SV_PNG 308 -#define SY_PNG 309 -#define SZ_PNG 310 -#define TC_PNG 311 -#define TD_PNG 312 -#define TF_PNG 313 -#define TG_PNG 314 -#define TH_PNG 315 -#define TJ_PNG 316 -#define TK_PNG 317 -#define TL_PNG 318 -#define TM_PNG 319 -#define TN_PNG 320 -#define TO_PNG 321 -#define TR_PNG 322 -#define TT_PNG 323 -#define TV_PNG 324 -#define TW_PNG 325 -#define TZ_PNG 326 -#define UA_PNG 327 -#define UG_PNG 328 -#define UM_PNG 329 -#define US_PNG 330 -#define UY_PNG 331 -#define UZ_PNG 332 -#define VA_PNG 333 -#define VC_PNG 334 -#define VE_PNG 335 -#define VG_PNG 336 -#define VI_PNG 337 -#define VN_PNG 338 -#define VU_PNG 339 -#define AAB_PNG 340 -#define WF_PNG 341 -#define WS_PNG 342 -#define YE_PNG 343 -#define YT_PNG 344 -#define ZA_PNG 345 -#define ZM_PNG 346 -#define ZW_PNG 347 -#define HU_PNG 348 -#define IDC_PINGPACKETLENGTH 1008 -#define IDC_NETOUTPUTEDIT 1009 -#define IDC_MAXHOPS 1009 -#define IDC_ICMP_PANEL 1011 -#define IDC_PINGS_LOST 1012 -#define IDC_ICMP_MIN 1013 -#define IDC_ICMP_MAX 1014 -#define IDC_ICMP_AVG 1015 -#define IDC_MAINTEXT 1016 -#define IDC_ANON_ADDR 1017 -#define IDC_PINGS_SENT 1020 -#define IDC_PING_LAYOUT 1021 -#define IDC_BAD_HASH 1022 -#define IDC_STATUS 1023 -#define IDC_GEOIP 1028 -#define IDC_LIST_TRACERT 1030 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 107 -#define _APS_NEXT_COMMAND_VALUE 40006 -#define _APS_NEXT_CONTROL_VALUE 1031 -#define _APS_NEXT_SYMED_VALUE 104 -#endif -#endif +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by NetworkTools.rc +// +#define AD_PNG 101 +#define AE_PNG 102 +#define AF_PNG 103 +#define AG_PNG 104 +#define AI_PNG 105 +#define AL_PNG 106 +#define AM_PNG 107 +#define AN_PNG 108 +#define AO_PNG 109 +#define AR_PNG 110 +#define AS_PNG 111 +#define AT_PNG 112 +#define AU_PNG 113 +#define AW_PNG 114 +#define AX_PNG 115 +#define AZ_PNG 116 +#define BA_PNG 117 +#define BB_PNG 118 +#define BD_PNG 119 +#define BE_PNG 120 +#define BF_PNG 121 +#define BG_PNG 122 +#define BH_PNG 123 +#define BI__PNG 124 +#define BJ_PNG 125 +#define BM_PNG 126 +#define BN_PNG 127 +#define BO_PNG 128 +#define BR_PNG 129 +#define BS_PNG 130 +#define BT_PNG 131 +#define BV_PNG 132 +#define BW_PNG 133 +#define BY_PNG 134 +#define BZ_PNG 135 +#define CA_PNG 136 +#define AAC_PNG 137 +#define CC_PNG 138 +#define CD_PNG 139 +#define CF_PNG 140 +#define CG_PNG 141 +#define CH_PNG 142 +#define CI_PNG 143 +#define CK_PNG 144 +#define CL_PNG 145 +#define CM_PNG 146 +#define CN_PNG 147 +#define CO_PNG 148 +#define CR_PNG 149 +#define IDD_WHOIS 149 +#define CS_PNG 150 +#define IDD_PING 150 +#define CU_PNG 151 +#define IDD_OPTIONS 151 +#define CV_PNG 152 +#define IDD_TRACERT 152 +#define CX_PNG 153 +#define CY_PNG 154 +#define CZ_PNG 155 +#define DE_PNG 156 +#define DJ_PNG 157 +#define DK_PNG 158 +#define DM_PNG 159 +#define DO_PNG 160 +#define DZ_PNG 161 +#define EC_PNG 162 +#define EE_PNG 163 +#define EG_PNG 164 +#define EH_PNG 165 +#define AAD_PNG 166 +#define ER_PNG 167 +#define ES_PNG 168 +#define ET_PNG 169 +#define AAE_PNG 170 +#define AAF_PNG 171 +#define FI_PNG 172 +#define FJ_PNG 173 +#define FK_PNG 174 +#define FM_PNG 175 +#define FO_PNG 176 +#define FR_PNG 177 +#define GA_PNG 178 +#define GB_PNG 179 +#define GD_PNG 180 +#define GE_PNG 181 +#define GF_PNG 182 +#define GH_PNG 183 +#define GI_PNG 184 +#define GL_PNG 185 +#define GM_PNG 186 +#define GN_PNG 187 +#define GP_PNG 188 +#define GQ_PNG 189 +#define GR_PNG 190 +#define GS_PNG 191 +#define GT_PNG 192 +#define GU_PNG 193 +#define GW_PNG 194 +#define GY_PNG 195 +#define HK_PNG 196 +#define HM_PNG 197 +#define HN_PNG 198 +#define HR_PNG 199 +#define HT_PNG 200 +#define ID_PNG 202 +#define IE_PNG 203 +#define IL_PNG 204 +#define IN_PNG 205 +#define IO_PNG 206 +#define IQ_PNG 207 +#define IR_PNG 208 +#define IS_PNG 209 +#define IT_PNG 210 +#define JM_PNG 211 +#define JO_PNG 212 +#define JP_PNG 213 +#define KE_PNG 214 +#define KG_PNG 215 +#define KH_PNG 216 +#define KI_PNG 217 +#define KM_PNG 218 +#define KN_PNG 219 +#define KP_PNG 220 +#define KR_PNG 221 +#define KW_PNG 222 +#define KY_PNG 223 +#define KZ_PNG 224 +#define LA_PNG 225 +#define LB_PNG 226 +#define LC_PNG 227 +#define LI_PNG 228 +#define LK_PNG 229 +#define LR_PNG 230 +#define LS_PNG 231 +#define LT_PNG 232 +#define LU_PNG 233 +#define LV_PNG 234 +#define LY_PNG 235 +#define MA_PNG 236 +#define MC_PNG 237 +#define MD_PNG 238 +#define ME_PNG 239 +#define MG_PNG 240 +#define MH_PNG 241 +#define MK_PNG 242 +#define ML_PNG 243 +#define MM_PNG 244 +#define MN_PNG 245 +#define MO_PNG 246 +#define MP_PNG 247 +#define MQ_PNG 248 +#define MR_PNG 249 +#define MS_PNG 250 +#define MT_PNG 251 +#define MU_PNG 252 +#define MV_PNG 253 +#define MW_PNG 254 +#define MX_PNG 255 +#define MY_PNG 256 +#define MZ_PNG 257 +#define NA_PNG 258 +#define NC_PNG 259 +#define NE_PNG 260 +#define NF_PNG 261 +#define NG_PNG 262 +#define NI_PNG 263 +#define NL_PNG 264 +#define NO_PNG 265 +#define NP_PNG 266 +#define NR_PNG 267 +#define NU_PNG 268 +#define NZ_PNG 269 +#define OM_PNG 270 +#define PA_PNG 271 +#define PE_PNG 272 +#define PF_PNG 273 +#define PG_PNG 274 +#define PH_PNG 275 +#define PK_PNG 276 +#define PL_PNG 277 +#define PM_PNG 278 +#define PN_PNG 279 +#define PR_PNG 280 +#define PS_PNG 281 +#define PT_PNG 282 +#define PW_PNG 283 +#define PY_PNG 284 +#define QA_PNG 285 +#define RE_PNG 286 +#define RO_PNG 287 +#define RS_PNG 288 +#define RU_PNG 289 +#define RW_PNG 290 +#define SA_PNG 291 +#define SB_PNG 292 +#define SC_PNG 293 +#define AAA_PNG 294 +#define SD_PNG 295 +#define SE_PNG 296 +#define SG_PNG 297 +#define SH_PNG 298 +#define SI_PNG 299 +#define SJ_PNG 300 +#define SK_PNG 301 +#define SL_PNG 302 +#define SM_PNG 303 +#define SN_PNG 304 +#define SO_PNG 305 +#define SR_PNG 306 +#define ST_PNG 307 +#define SV_PNG 308 +#define SY_PNG 309 +#define SZ_PNG 310 +#define TC_PNG 311 +#define TD_PNG 312 +#define TF_PNG 313 +#define TG_PNG 314 +#define TH_PNG 315 +#define TJ_PNG 316 +#define TK_PNG 317 +#define TL_PNG 318 +#define TM_PNG 319 +#define TN_PNG 320 +#define TO_PNG 321 +#define TR_PNG 322 +#define TT_PNG 323 +#define TV_PNG 324 +#define TW_PNG 325 +#define TZ_PNG 326 +#define UA_PNG 327 +#define UG_PNG 328 +#define UM_PNG 329 +#define US_PNG 330 +#define UY_PNG 331 +#define UZ_PNG 332 +#define VA_PNG 333 +#define VC_PNG 334 +#define VE_PNG 335 +#define VG_PNG 336 +#define VI_PNG 337 +#define VN_PNG 338 +#define VU_PNG 339 +#define AAB_PNG 340 +#define WF_PNG 341 +#define WS_PNG 342 +#define YE_PNG 343 +#define YT_PNG 344 +#define ZA_PNG 345 +#define ZM_PNG 346 +#define ZW_PNG 347 +#define HU_PNG 348 +#define IDC_PINGPACKETLENGTH 1008 +#define IDC_NETOUTPUTEDIT 1009 +#define IDC_MAXHOPS 1009 +#define IDC_ICMP_PANEL 1011 +#define IDC_PINGS_LOST 1012 +#define IDC_ICMP_MIN 1013 +#define IDC_ICMP_MAX 1014 +#define IDC_ICMP_AVG 1015 +#define IDC_MAINTEXT 1016 +#define IDC_ANON_ADDR 1017 +#define IDC_PINGS_SENT 1020 +#define IDC_PING_LAYOUT 1021 +#define IDC_BAD_HASH 1022 +#define IDC_STATUS 1023 +#define IDC_GEOIP 1028 +#define IDC_LIST_TRACERT 1030 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 107 +#define _APS_NEXT_COMMAND_VALUE 40006 +#define _APS_NEXT_CONTROL_VALUE 1031 +#define _APS_NEXT_SYMED_VALUE 104 +#endif +#endif diff --git a/plugins/NetworkTools/tracert.c b/plugins/NetworkTools/tracert.c index 0484e9bc1055..41550a1f123b 100644 --- a/plugins/NetworkTools/tracert.c +++ b/plugins/NetworkTools/tracert.c @@ -1,772 +1,772 @@ -/* - * Process Hacker Network Tools - - * Tracert dialog - * - * Copyright (C) 2015-2017 dmex - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include "nettools.h" -#include "tracert.h" -#include -#include - -PPH_STRING TracertGetErrorMessage( - _In_ IP_STATUS Result - ) -{ - PPH_STRING message; - ULONG messageLength; - - messageLength = 128; - message = PhCreateStringEx(NULL, 128 * sizeof(WCHAR)); - - if (GetIpErrorString(Result, message->Buffer, &messageLength) == ERROR_INSUFFICIENT_BUFFER) - { - PhDereferenceObject(message); - message = PhCreateStringEx(NULL, messageLength * sizeof(WCHAR)); - - if (GetIpErrorString(Result, message->Buffer, &messageLength) != ERROR_SUCCESS) - { - PhDereferenceObject(message); - message = PhGetWin32Message(Result); - } - } - else - { - message = PhGetWin32Message(Result); - } - - return message; -} - -NTSTATUS TracertHostnameLookupCallback( - _In_ PVOID Parameter - ) -{ - PTRACERT_RESOLVE_WORKITEM resolve = Parameter; - - if (resolve->Type == PH_IPV4_NETWORK_TYPE) - { - if (!GetNameInfo( - (PSOCKADDR)&resolve->SocketAddress, - sizeof(SOCKADDR_IN), - resolve->SocketAddressHostname, - sizeof(resolve->SocketAddressHostname), - NULL, - 0, - NI_NAMEREQD - )) - { - PhMoveReference(&resolve->Node->HostnameString, PhCreateString(resolve->SocketAddressHostname)); - } - else - { - ULONG errorCode = WSAGetLastError(); - - if (errorCode != WSAHOST_NOT_FOUND && errorCode != WSATRY_AGAIN) - { - //PPH_STRING errorMessage = PhGetWin32Message(errorCode); - //PhSetListViewSubItem(work->LvHandle, work->LvItemIndex, HOSTNAME_COLUMN, errorMessage->Buffer); - //PhDereferenceObject(errorMessage); - } - - PhDereferenceObject(resolve); - } - } - else if (resolve->Type == PH_IPV6_NETWORK_TYPE) - { - if (!GetNameInfo( - (PSOCKADDR)&resolve->SocketAddress, - sizeof(SOCKADDR_IN6), - resolve->SocketAddressHostname, - sizeof(resolve->SocketAddressHostname), - NULL, - 0, - NI_NAMEREQD - )) - { - PhMoveReference(&resolve->Node->HostnameString, PhCreateString(resolve->SocketAddressHostname)); - } - else - { - ULONG errorCode = WSAGetLastError(); - - if (errorCode != WSAHOST_NOT_FOUND && errorCode != WSATRY_AGAIN) - { - //PPH_STRING errorMessage = PhGetWin32Message(errorCode); - //PhSetListViewSubItem(work->LvHandle, work->LvItemIndex, HOSTNAME_COLUMN, errorMessage->Buffer); - //PhDereferenceObject(errorMessage); - } - - PhDereferenceObject(resolve); - } - } - - return STATUS_SUCCESS; -} - -VOID TracertQueueHostLookup( - _In_ PNETWORK_TRACERT_CONTEXT Context, - _In_ PTRACERT_ROOT_NODE Node, - _In_ PVOID SocketAddress - ) -{ - PPH_STRING remoteCountryCode; - PPH_STRING remoteCountryName; - ULONG addressStringLength = INET_ADDRSTRLEN; - WCHAR addressString[INET_ADDRSTRLEN] = L""; - - if (Context->RemoteEndpoint.Address.Type == PH_IPV4_NETWORK_TYPE) - { - IN_ADDR sockAddrIn; - PTRACERT_RESOLVE_WORKITEM resolve; - - memset(&sockAddrIn, 0, sizeof(IN_ADDR)); - memcpy(&sockAddrIn, SocketAddress, sizeof(IN_ADDR)); - - if (NT_SUCCESS(RtlIpv4AddressToStringEx(&sockAddrIn, 0, addressString, &addressStringLength))) - { - Node->IpAddressString = PhCreateString(addressString); - } - - resolve = PhCreateAlloc(sizeof(TRACERT_RESOLVE_WORKITEM)); - memset(resolve, 0, sizeof(TRACERT_RESOLVE_WORKITEM)); - - resolve->Type = PH_IPV4_NETWORK_TYPE; - resolve->WindowHandle = Context->WindowHandle; - resolve->Node = Node; - - ((PSOCKADDR_IN)&resolve->SocketAddress)->sin_family = AF_INET; - ((PSOCKADDR_IN)&resolve->SocketAddress)->sin_addr = sockAddrIn; - - PhQueueItemWorkQueue(&Context->WorkQueue, TracertHostnameLookupCallback, resolve); - - if (LookupSockInAddr4CountryCode( - sockAddrIn, - &remoteCountryCode, - &remoteCountryName - )) - { - PhMoveReference(&Node->RemoteCountryCode, remoteCountryCode); - PhMoveReference(&Node->RemoteCountryName, remoteCountryName); - } - } - else if (Context->RemoteEndpoint.Address.Type == PH_IPV6_NETWORK_TYPE) - { - IN6_ADDR sockAddrIn6; - PTRACERT_RESOLVE_WORKITEM resolve; - - memset(&sockAddrIn6, 0, sizeof(IN6_ADDR)); - memcpy(&sockAddrIn6, SocketAddress, sizeof(IN6_ADDR)); - - if (NT_SUCCESS(RtlIpv6AddressToStringEx(&sockAddrIn6, 0, 0, addressString, &addressStringLength))) - { - Node->IpAddressString = PhCreateString(addressString); - } - - resolve = PhCreateAlloc(sizeof(TRACERT_RESOLVE_WORKITEM)); - memset(resolve, 0, sizeof(TRACERT_RESOLVE_WORKITEM)); - - resolve->Type = PH_IPV6_NETWORK_TYPE; - resolve->WindowHandle = Context->WindowHandle; - resolve->Node = Node; - - ((PSOCKADDR_IN6)&resolve->SocketAddress)->sin6_family = AF_INET6; - ((PSOCKADDR_IN6)&resolve->SocketAddress)->sin6_addr = sockAddrIn6; - - PhQueueItemWorkQueue(&Context->WorkQueue, TracertHostnameLookupCallback, resolve); - - if (LookupSockInAddr6CountryCode( - sockAddrIn6, - &remoteCountryCode, - &remoteCountryName - )) - { - PhMoveReference(&Node->RemoteCountryCode, remoteCountryCode); - PhMoveReference(&Node->RemoteCountryName, remoteCountryName); - } - } -} - -NTSTATUS NetworkTracertThreadStart( - _In_ PVOID Parameter - ) -{ - PNETWORK_TRACERT_CONTEXT context = (PNETWORK_TRACERT_CONTEXT)Parameter; - HANDLE icmpHandle = INVALID_HANDLE_VALUE; - SOCKADDR_STORAGE sourceAddress = { 0 }; - SOCKADDR_STORAGE destinationAddress = { 0 }; - ULONG icmpReplyLength = 0; - PVOID icmpReplyBuffer = NULL; - PPH_BYTES icmpEchoBuffer = NULL; - PPH_STRING icmpRandString = NULL; - IP_OPTION_INFORMATION pingOptions = - { - 1, - 0, - IP_FLAG_DF, - 0 - }; - - if (icmpRandString = PhCreateStringEx(NULL, PhGetIntegerSetting(SETTING_NAME_PING_SIZE) * 2 + 2)) - { - PhGenerateRandomAlphaString(icmpRandString->Buffer, (ULONG)icmpRandString->Length / sizeof(WCHAR)); - - icmpEchoBuffer = PhConvertUtf16ToMultiByte(icmpRandString->Buffer); - PhDereferenceObject(icmpRandString); - } - - switch (context->RemoteEndpoint.Address.Type) - { - case PH_IPV4_NETWORK_TYPE: - icmpHandle = IcmpCreateFile(); - break; - case PH_IPV6_NETWORK_TYPE: - icmpHandle = Icmp6CreateFile(); - break; - } - - if (icmpHandle == INVALID_HANDLE_VALUE) - goto CleanupExit; - - if (context->RemoteEndpoint.Address.Type == PH_IPV4_NETWORK_TYPE) - { - ((PSOCKADDR_IN)&destinationAddress)->sin_family = AF_INET; - ((PSOCKADDR_IN)&destinationAddress)->sin_addr = context->RemoteEndpoint.Address.InAddr; - //((PSOCKADDR_IN)&destinationAddress)->sin_port = (USHORT)context->RemoteEndpoint.Port; - } - else if (context->RemoteEndpoint.Address.Type == PH_IPV6_NETWORK_TYPE) - { - ((PSOCKADDR_IN6)&destinationAddress)->sin6_family = AF_INET6; - ((PSOCKADDR_IN6)&destinationAddress)->sin6_addr = context->RemoteEndpoint.Address.In6Addr; - //((PSOCKADDR_IN6)&destinationAddress)->sin6_port = (USHORT)context->RemoteEndpoint.Port; - } - - for (ULONG i = 0; i < DEFAULT_MAXIMUM_HOPS; i++) - { - IN_ADDR last4ReplyAddress = in4addr_any; - IN6_ADDR last6ReplyAddress = in6addr_any; - - if (context->Cancel) - break; - - PTRACERT_ROOT_NODE node = AddTracertNode(context, pingOptions.Ttl); - - for (ULONG ii = 0; ii < DEFAULT_MAXIMUM_PINGS; ii++) - { - if (context->Cancel) - break; - - if (context->RemoteEndpoint.Address.Type == PH_IPV4_NETWORK_TYPE) - { - icmpReplyLength = ICMP_BUFFER_SIZE(sizeof(ICMP_ECHO_REPLY), icmpEchoBuffer); - icmpReplyBuffer = PhAllocate(icmpReplyLength); - memset(icmpReplyBuffer, 0, icmpReplyLength); - - if (IcmpSendEcho2Ex( - icmpHandle, - 0, - NULL, - NULL, - ((PSOCKADDR_IN)&sourceAddress)->sin_addr.s_addr, - ((PSOCKADDR_IN)&destinationAddress)->sin_addr.s_addr, - icmpEchoBuffer->Buffer, - (USHORT)icmpEchoBuffer->Length, - &pingOptions, - icmpReplyBuffer, - icmpReplyLength, - DEFAULT_TIMEOUT - )) - { - PICMP_ECHO_REPLY reply4 = (PICMP_ECHO_REPLY)icmpReplyBuffer; - - memcpy(&last4ReplyAddress, &reply4->Address, sizeof(IN_ADDR)); - - TracertQueueHostLookup( - context, - node, - &reply4->Address - ); - - node->PingStatus[ii] = reply4->Status; - node->PingList[ii] = reply4->RoundTripTime; - UpdateTracertNode(context, node); - - if (reply4->Status == IP_HOP_LIMIT_EXCEEDED && reply4->RoundTripTime < MIN_INTERVAL) - { - //LARGE_INTEGER interval; - //NtDelayExecution(FALSE, PhTimeoutFromMilliseconds(&interval, MIN_INTERVAL - reply4->RoundTripTime)); - } - - //if (reply4->Status != IP_REQ_TIMED_OUT) - //{ - // PPH_STRING errorMessage; - // - // if (errorMessage = TracertGetErrorMessage(reply4->Status)) - // { - // node->IpAddressString = errorMessage; - // } - //} - } - else - { - node->PingStatus[ii] = IP_REQ_TIMED_OUT; - UpdateTracertNode(context, node); - } - - PhFree(icmpReplyBuffer); - } - else - { - icmpReplyLength = ICMP_BUFFER_SIZE(sizeof(ICMPV6_ECHO_REPLY), icmpEchoBuffer); - icmpReplyBuffer = PhAllocate(icmpReplyLength); - memset(icmpReplyBuffer, 0, icmpReplyLength); - - if (Icmp6SendEcho2( - icmpHandle, - 0, - NULL, - NULL, - ((PSOCKADDR_IN6)&sourceAddress), - ((PSOCKADDR_IN6)&destinationAddress), - icmpEchoBuffer->Buffer, - (USHORT)icmpEchoBuffer->Length, - &pingOptions, - icmpReplyBuffer, - icmpReplyLength, - DEFAULT_TIMEOUT - )) - { - PICMPV6_ECHO_REPLY reply6 = (PICMPV6_ECHO_REPLY)icmpReplyBuffer; - - memcpy(&last6ReplyAddress, &reply6->Address.sin6_addr, sizeof(IN6_ADDR)); - - TracertQueueHostLookup( - context, - node, - &reply6->Address.sin6_addr - ); - - node->PingStatus[ii] = reply6->Status; - node->PingList[ii] = reply6->RoundTripTime; - UpdateTracertNode(context, node); - - if (reply6->Status == IP_HOP_LIMIT_EXCEEDED) - { - if (reply6->RoundTripTime < MIN_INTERVAL) - { - //LARGE_INTEGER interval; - //NtDelayExecution(FALSE, PhTimeoutFromMilliseconds(&interval, MIN_INTERVAL - reply6->RoundTripTime)); - } - } - } - else - { - node->PingStatus[ii] = IP_REQ_TIMED_OUT; - UpdateTracertNode(context, node); - } - - PhFree(icmpReplyBuffer); - } - } - - if (context->RemoteEndpoint.Address.Type == PH_IPV4_NETWORK_TYPE) - { - if (!memcmp(&last4ReplyAddress, &((PSOCKADDR_IN)&destinationAddress)->sin_addr, sizeof(IN_ADDR))) - break; - } - else if (context->RemoteEndpoint.Address.Type == PH_IPV6_NETWORK_TYPE) - { - if (!memcmp(&last6ReplyAddress, &((PSOCKADDR_IN6)&destinationAddress)->sin6_addr, sizeof(IN6_ADDR))) - break; - } - - pingOptions.Ttl++; - } - -CleanupExit: - - if (icmpHandle != INVALID_HANDLE_VALUE) - { - IcmpCloseHandle(icmpHandle); - } - - PhDereferenceObject(context); - - PostMessage(context->WindowHandle, NTM_RECEIVEDFINISH, 0, 0); - return STATUS_SUCCESS; -} - -VOID ShowMenu( - _In_ PNETWORK_TRACERT_CONTEXT Context, - _In_ ULONG Id - ) -{ - switch (Id) - { - case MAINMENU_ACTION_PING: - { - PH_IP_ENDPOINT RemoteEndpoint; - PWSTR terminator = NULL; - PTRACERT_ROOT_NODE node; - - if (node = GetSelectedTracertNode(Context)) - { - if (NT_SUCCESS(RtlIpv4StringToAddress( - node->IpAddressString->Buffer, - TRUE, - &terminator, - &RemoteEndpoint.Address.InAddr - ))) - { - RemoteEndpoint.Address.Type = PH_IPV4_NETWORK_TYPE; - ShowPingWindowFromAddress(RemoteEndpoint); - break; - } - - if (NT_SUCCESS(RtlIpv6StringToAddress( - node->IpAddressString->Buffer, - &terminator, - &RemoteEndpoint.Address.In6Addr - ))) - { - RemoteEndpoint.Address.Type = PH_IPV6_NETWORK_TYPE; - ShowPingWindowFromAddress(RemoteEndpoint); - break; - } - } - } - break; - case NETWORK_ACTION_TRACEROUTE: - { - PH_IP_ENDPOINT RemoteEndpoint; - PWSTR terminator = NULL; - PTRACERT_ROOT_NODE node; - - if (node = GetSelectedTracertNode(Context)) - { - if (NT_SUCCESS(RtlIpv4StringToAddress( - node->IpAddressString->Buffer, - TRUE, - &terminator, - &RemoteEndpoint.Address.InAddr - ))) - { - RemoteEndpoint.Address.Type = PH_IPV4_NETWORK_TYPE; - ShowTracertWindowFromAddress(RemoteEndpoint); - break; - } - - if (NT_SUCCESS(RtlIpv6StringToAddress( - node->IpAddressString->Buffer, - &terminator, - &RemoteEndpoint.Address.In6Addr - ))) - { - RemoteEndpoint.Address.Type = PH_IPV6_NETWORK_TYPE; - ShowTracertWindowFromAddress(RemoteEndpoint); - break; - } - } - } - break; - case NETWORK_ACTION_WHOIS: - { - PH_IP_ENDPOINT RemoteEndpoint; - PWSTR terminator = NULL; - PTRACERT_ROOT_NODE node; - - if (node = GetSelectedTracertNode(Context)) - { - if (NT_SUCCESS(RtlIpv4StringToAddress( - node->IpAddressString->Buffer, - TRUE, - &terminator, - &RemoteEndpoint.Address.InAddr - ))) - { - RemoteEndpoint.Address.Type = PH_IPV4_NETWORK_TYPE; - ShowWhoisWindowFromAddress(RemoteEndpoint); - break; - } - - if (NT_SUCCESS(RtlIpv6StringToAddress( - node->IpAddressString->Buffer, - &terminator, - &RemoteEndpoint.Address.In6Addr - ))) - { - RemoteEndpoint.Address.Type = PH_IPV6_NETWORK_TYPE; - ShowWhoisWindowFromAddress(RemoteEndpoint); - break; - } - } - } - break; - } -} - -INT_PTR CALLBACK TracertDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - PNETWORK_TRACERT_CONTEXT context; - - if (uMsg == WM_INITDIALOG) - { - context = (PNETWORK_TRACERT_CONTEXT)lParam; - SetProp(hwndDlg, L"Context", (HANDLE)context); - } - else - { - context = (PNETWORK_TRACERT_CONTEXT)GetProp(hwndDlg, L"Context"); - - if (uMsg == WM_DESTROY) - { - context->Cancel = TRUE; - - PhSaveWindowPlacementToSetting(SETTING_NAME_TRACERT_WINDOW_POSITION, SETTING_NAME_TRACERT_WINDOW_SIZE, hwndDlg); - - if (context->FontHandle) - DeleteObject(context->FontHandle); - - DeleteTracertTree(context); - - PhDeleteWorkQueue(&context->WorkQueue); - PhDeleteLayoutManager(&context->LayoutManager); - RemoveProp(hwndDlg, L"Context"); - PhDereferenceObject(context); - - PostQuitMessage(0); - } - } - - if (!context) - return FALSE; - - switch (uMsg) - { - case WM_INITDIALOG: - { - HANDLE tracertThread; - - PhCenterWindow(hwndDlg, PhMainWndHandle); - - Static_SetText(hwndDlg, - PhaFormatString(L"Tracing %s...", context->IpAddressString)->Buffer - ); - Static_SetText(GetDlgItem(hwndDlg, IDC_STATUS), - PhaFormatString(L"Tracing route to %s with %lu bytes of data...", context->IpAddressString, PhGetIntegerSetting(SETTING_NAME_PING_SIZE))->Buffer - ); - - context->WindowHandle = hwndDlg; - context->TreeNewHandle = GetDlgItem(hwndDlg, IDC_LIST_TRACERT); - context->FontHandle = PhCreateCommonFont(-15, FW_MEDIUM, GetDlgItem(hwndDlg, IDC_STATUS)); - - InitializeTracertTree(context); - - PhInitializeWorkQueue(&context->WorkQueue, 0, 40, 5000); - PhInitializeLayoutManager(&context->LayoutManager, hwndDlg); - PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_STATUS), NULL, PH_ANCHOR_TOP | PH_ANCHOR_LEFT | PH_ANCHOR_RIGHT | PH_LAYOUT_FORCE_INVALIDATE); - PhAddLayoutItem(&context->LayoutManager, context->TreeNewHandle, NULL, PH_ANCHOR_ALL); - PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDCANCEL), NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_RIGHT); - - if (PhGetIntegerPairSetting(SETTING_NAME_TRACERT_WINDOW_POSITION).X != 0) - PhLoadWindowPlacementFromSetting(SETTING_NAME_TRACERT_WINDOW_POSITION, SETTING_NAME_TRACERT_WINDOW_SIZE, hwndDlg); - else - PhCenterWindow(hwndDlg, PhMainWndHandle); - - PhReferenceObject(context); - - if (tracertThread = PhCreateThread(0, NetworkTracertThreadStart, (PVOID)context)) - NtClose(tracertThread); - - EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); - } - break; - case WM_COMMAND: - { - switch (GET_WM_COMMAND_ID(wParam, lParam)) - { - case IDCANCEL: - DestroyWindow(hwndDlg); - break; - case TRACERT_SHOWCONTEXTMENU: - { - PPH_EMENU menu; - PTRACERT_ROOT_NODE selectedNode; - PPH_EMENU_ITEM selectedItem; - PPH_TREENEW_MOUSE_EVENT mouseEvent = (PPH_TREENEW_MOUSE_EVENT)lParam; - - if (selectedNode = GetSelectedTracertNode(context)) - { - menu = PhCreateEMenu(); - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, MAINMENU_ACTION_PING, L"Ping", NULL, NULL), -1); - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, NETWORK_ACTION_TRACEROUTE, L"Traceroute", NULL, NULL), -1); - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, NETWORK_ACTION_WHOIS, L"Whois", NULL, NULL), -1); - - selectedItem = PhShowEMenu( - menu, - hwndDlg, - PH_EMENU_SHOW_LEFTRIGHT, - PH_ALIGN_LEFT | PH_ALIGN_TOP, - mouseEvent->Location.x, - mouseEvent->Location.y - ); - - if (selectedItem && selectedItem->Id != -1) - { - ShowMenu(context, selectedItem->Id); - } - - PhDestroyEMenu(menu); - } - } - break; - } - } - break; - case WM_SIZE: - PhLayoutManagerLayout(&context->LayoutManager); - break; - case NTM_RECEIVEDFINISH: - { - PPH_STRING windowText; - - if (windowText = PH_AUTO(PhGetWindowText(context->WindowHandle))) - { - Static_SetText( - context->WindowHandle, - PhaFormatString(L"%s complete", windowText->Buffer)->Buffer - ); - } - - if (windowText = PH_AUTO(PhGetWindowText(GetDlgItem(hwndDlg, IDC_STATUS)))) - { - Static_SetText( - GetDlgItem(hwndDlg, IDC_STATUS), - PhaFormatString(L"%s complete", windowText->Buffer)->Buffer - ); - } - - TreeNew_NodesStructured(context->TreeNewHandle); - } - break; - } - - return FALSE; -} - -NTSTATUS TracertDialogThreadStart( - _In_ PVOID Parameter - ) -{ - BOOL result; - MSG message; - HWND windowHandle; - PH_AUTO_POOL autoPool; - PNETWORK_TRACERT_CONTEXT context = (PNETWORK_TRACERT_CONTEXT)Parameter; - - PhInitializeAutoPool(&autoPool); - - windowHandle = CreateDialogParam( - (HINSTANCE)PluginInstance->DllBase, - MAKEINTRESOURCE(IDD_TRACERT), - NULL, - TracertDlgProc, - (LPARAM)Parameter - ); - - ShowWindow(windowHandle, SW_SHOW); - SetForegroundWindow(windowHandle); - - while (result = GetMessage(&message, NULL, 0, 0)) - { - if (result == -1) - break; - - if (!IsDialogMessage(context->WindowHandle, &message)) - { - TranslateMessage(&message); - DispatchMessage(&message); - } - - PhDrainAutoPool(&autoPool); - } - - PhDeleteAutoPool(&autoPool); - - return STATUS_SUCCESS; -} - -VOID ShowTracertWindow( - _In_ PPH_NETWORK_ITEM NetworkItem - ) -{ - HANDLE dialogThread; - PNETWORK_TRACERT_CONTEXT context; - - context = (PNETWORK_TRACERT_CONTEXT)PhCreateAlloc(sizeof(NETWORK_TRACERT_CONTEXT)); - memset(context, 0, sizeof(NETWORK_TRACERT_CONTEXT)); - - context->RemoteEndpoint = NetworkItem->RemoteEndpoint; - - if (NetworkItem->RemoteEndpoint.Address.Type == PH_IPV4_NETWORK_TYPE) - { - RtlIpv4AddressToString(&NetworkItem->RemoteEndpoint.Address.InAddr, context->IpAddressString); - } - else if (NetworkItem->RemoteEndpoint.Address.Type == PH_IPV6_NETWORK_TYPE) - { - RtlIpv6AddressToString(&NetworkItem->RemoteEndpoint.Address.In6Addr, context->IpAddressString); - } - - if (dialogThread = PhCreateThread(0, TracertDialogThreadStart, (PVOID)context)) - { - NtClose(dialogThread); - } -} - -VOID ShowTracertWindowFromAddress( - _In_ PH_IP_ENDPOINT RemoteEndpoint - ) -{ - HANDLE dialogThread; - PNETWORK_TRACERT_CONTEXT context; - - context = (PNETWORK_TRACERT_CONTEXT)PhCreateAlloc(sizeof(NETWORK_TRACERT_CONTEXT)); - memset(context, 0, sizeof(NETWORK_TRACERT_CONTEXT)); - - context->RemoteEndpoint = RemoteEndpoint; - - if (RemoteEndpoint.Address.Type == PH_IPV4_NETWORK_TYPE) - { - RtlIpv4AddressToString(&RemoteEndpoint.Address.InAddr, context->IpAddressString); - } - else if (RemoteEndpoint.Address.Type == PH_IPV6_NETWORK_TYPE) - { - RtlIpv6AddressToString(&RemoteEndpoint.Address.In6Addr, context->IpAddressString); - } - - if (dialogThread = PhCreateThread(0, TracertDialogThreadStart, (PVOID)context)) - { - NtClose(dialogThread); - } +/* + * Process Hacker Network Tools - + * Tracert dialog + * + * Copyright (C) 2015-2017 dmex + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include "nettools.h" +#include "tracert.h" +#include +#include + +PPH_STRING TracertGetErrorMessage( + _In_ IP_STATUS Result + ) +{ + PPH_STRING message; + ULONG messageLength; + + messageLength = 128; + message = PhCreateStringEx(NULL, 128 * sizeof(WCHAR)); + + if (GetIpErrorString(Result, message->Buffer, &messageLength) == ERROR_INSUFFICIENT_BUFFER) + { + PhDereferenceObject(message); + message = PhCreateStringEx(NULL, messageLength * sizeof(WCHAR)); + + if (GetIpErrorString(Result, message->Buffer, &messageLength) != ERROR_SUCCESS) + { + PhDereferenceObject(message); + message = PhGetWin32Message(Result); + } + } + else + { + message = PhGetWin32Message(Result); + } + + return message; +} + +NTSTATUS TracertHostnameLookupCallback( + _In_ PVOID Parameter + ) +{ + PTRACERT_RESOLVE_WORKITEM resolve = Parameter; + + if (resolve->Type == PH_IPV4_NETWORK_TYPE) + { + if (!GetNameInfo( + (PSOCKADDR)&resolve->SocketAddress, + sizeof(SOCKADDR_IN), + resolve->SocketAddressHostname, + sizeof(resolve->SocketAddressHostname), + NULL, + 0, + NI_NAMEREQD + )) + { + PhMoveReference(&resolve->Node->HostnameString, PhCreateString(resolve->SocketAddressHostname)); + } + else + { + ULONG errorCode = WSAGetLastError(); + + if (errorCode != WSAHOST_NOT_FOUND && errorCode != WSATRY_AGAIN) + { + //PPH_STRING errorMessage = PhGetWin32Message(errorCode); + //PhSetListViewSubItem(work->LvHandle, work->LvItemIndex, HOSTNAME_COLUMN, errorMessage->Buffer); + //PhDereferenceObject(errorMessage); + } + + PhDereferenceObject(resolve); + } + } + else if (resolve->Type == PH_IPV6_NETWORK_TYPE) + { + if (!GetNameInfo( + (PSOCKADDR)&resolve->SocketAddress, + sizeof(SOCKADDR_IN6), + resolve->SocketAddressHostname, + sizeof(resolve->SocketAddressHostname), + NULL, + 0, + NI_NAMEREQD + )) + { + PhMoveReference(&resolve->Node->HostnameString, PhCreateString(resolve->SocketAddressHostname)); + } + else + { + ULONG errorCode = WSAGetLastError(); + + if (errorCode != WSAHOST_NOT_FOUND && errorCode != WSATRY_AGAIN) + { + //PPH_STRING errorMessage = PhGetWin32Message(errorCode); + //PhSetListViewSubItem(work->LvHandle, work->LvItemIndex, HOSTNAME_COLUMN, errorMessage->Buffer); + //PhDereferenceObject(errorMessage); + } + + PhDereferenceObject(resolve); + } + } + + return STATUS_SUCCESS; +} + +VOID TracertQueueHostLookup( + _In_ PNETWORK_TRACERT_CONTEXT Context, + _In_ PTRACERT_ROOT_NODE Node, + _In_ PVOID SocketAddress + ) +{ + PPH_STRING remoteCountryCode; + PPH_STRING remoteCountryName; + ULONG addressStringLength = INET_ADDRSTRLEN; + WCHAR addressString[INET_ADDRSTRLEN] = L""; + + if (Context->RemoteEndpoint.Address.Type == PH_IPV4_NETWORK_TYPE) + { + IN_ADDR sockAddrIn; + PTRACERT_RESOLVE_WORKITEM resolve; + + memset(&sockAddrIn, 0, sizeof(IN_ADDR)); + memcpy(&sockAddrIn, SocketAddress, sizeof(IN_ADDR)); + + if (NT_SUCCESS(RtlIpv4AddressToStringEx(&sockAddrIn, 0, addressString, &addressStringLength))) + { + Node->IpAddressString = PhCreateString(addressString); + } + + resolve = PhCreateAlloc(sizeof(TRACERT_RESOLVE_WORKITEM)); + memset(resolve, 0, sizeof(TRACERT_RESOLVE_WORKITEM)); + + resolve->Type = PH_IPV4_NETWORK_TYPE; + resolve->WindowHandle = Context->WindowHandle; + resolve->Node = Node; + + ((PSOCKADDR_IN)&resolve->SocketAddress)->sin_family = AF_INET; + ((PSOCKADDR_IN)&resolve->SocketAddress)->sin_addr = sockAddrIn; + + PhQueueItemWorkQueue(&Context->WorkQueue, TracertHostnameLookupCallback, resolve); + + if (LookupSockInAddr4CountryCode( + sockAddrIn, + &remoteCountryCode, + &remoteCountryName + )) + { + PhMoveReference(&Node->RemoteCountryCode, remoteCountryCode); + PhMoveReference(&Node->RemoteCountryName, remoteCountryName); + } + } + else if (Context->RemoteEndpoint.Address.Type == PH_IPV6_NETWORK_TYPE) + { + IN6_ADDR sockAddrIn6; + PTRACERT_RESOLVE_WORKITEM resolve; + + memset(&sockAddrIn6, 0, sizeof(IN6_ADDR)); + memcpy(&sockAddrIn6, SocketAddress, sizeof(IN6_ADDR)); + + if (NT_SUCCESS(RtlIpv6AddressToStringEx(&sockAddrIn6, 0, 0, addressString, &addressStringLength))) + { + Node->IpAddressString = PhCreateString(addressString); + } + + resolve = PhCreateAlloc(sizeof(TRACERT_RESOLVE_WORKITEM)); + memset(resolve, 0, sizeof(TRACERT_RESOLVE_WORKITEM)); + + resolve->Type = PH_IPV6_NETWORK_TYPE; + resolve->WindowHandle = Context->WindowHandle; + resolve->Node = Node; + + ((PSOCKADDR_IN6)&resolve->SocketAddress)->sin6_family = AF_INET6; + ((PSOCKADDR_IN6)&resolve->SocketAddress)->sin6_addr = sockAddrIn6; + + PhQueueItemWorkQueue(&Context->WorkQueue, TracertHostnameLookupCallback, resolve); + + if (LookupSockInAddr6CountryCode( + sockAddrIn6, + &remoteCountryCode, + &remoteCountryName + )) + { + PhMoveReference(&Node->RemoteCountryCode, remoteCountryCode); + PhMoveReference(&Node->RemoteCountryName, remoteCountryName); + } + } +} + +NTSTATUS NetworkTracertThreadStart( + _In_ PVOID Parameter + ) +{ + PNETWORK_TRACERT_CONTEXT context = (PNETWORK_TRACERT_CONTEXT)Parameter; + HANDLE icmpHandle = INVALID_HANDLE_VALUE; + SOCKADDR_STORAGE sourceAddress = { 0 }; + SOCKADDR_STORAGE destinationAddress = { 0 }; + ULONG icmpReplyLength = 0; + PVOID icmpReplyBuffer = NULL; + PPH_BYTES icmpEchoBuffer = NULL; + PPH_STRING icmpRandString = NULL; + IP_OPTION_INFORMATION pingOptions = + { + 1, + 0, + IP_FLAG_DF, + 0 + }; + + if (icmpRandString = PhCreateStringEx(NULL, PhGetIntegerSetting(SETTING_NAME_PING_SIZE) * 2 + 2)) + { + PhGenerateRandomAlphaString(icmpRandString->Buffer, (ULONG)icmpRandString->Length / sizeof(WCHAR)); + + icmpEchoBuffer = PhConvertUtf16ToMultiByte(icmpRandString->Buffer); + PhDereferenceObject(icmpRandString); + } + + switch (context->RemoteEndpoint.Address.Type) + { + case PH_IPV4_NETWORK_TYPE: + icmpHandle = IcmpCreateFile(); + break; + case PH_IPV6_NETWORK_TYPE: + icmpHandle = Icmp6CreateFile(); + break; + } + + if (icmpHandle == INVALID_HANDLE_VALUE) + goto CleanupExit; + + if (context->RemoteEndpoint.Address.Type == PH_IPV4_NETWORK_TYPE) + { + ((PSOCKADDR_IN)&destinationAddress)->sin_family = AF_INET; + ((PSOCKADDR_IN)&destinationAddress)->sin_addr = context->RemoteEndpoint.Address.InAddr; + //((PSOCKADDR_IN)&destinationAddress)->sin_port = (USHORT)context->RemoteEndpoint.Port; + } + else if (context->RemoteEndpoint.Address.Type == PH_IPV6_NETWORK_TYPE) + { + ((PSOCKADDR_IN6)&destinationAddress)->sin6_family = AF_INET6; + ((PSOCKADDR_IN6)&destinationAddress)->sin6_addr = context->RemoteEndpoint.Address.In6Addr; + //((PSOCKADDR_IN6)&destinationAddress)->sin6_port = (USHORT)context->RemoteEndpoint.Port; + } + + for (ULONG i = 0; i < DEFAULT_MAXIMUM_HOPS; i++) + { + IN_ADDR last4ReplyAddress = in4addr_any; + IN6_ADDR last6ReplyAddress = in6addr_any; + + if (context->Cancel) + break; + + PTRACERT_ROOT_NODE node = AddTracertNode(context, pingOptions.Ttl); + + for (ULONG ii = 0; ii < DEFAULT_MAXIMUM_PINGS; ii++) + { + if (context->Cancel) + break; + + if (context->RemoteEndpoint.Address.Type == PH_IPV4_NETWORK_TYPE) + { + icmpReplyLength = ICMP_BUFFER_SIZE(sizeof(ICMP_ECHO_REPLY), icmpEchoBuffer); + icmpReplyBuffer = PhAllocate(icmpReplyLength); + memset(icmpReplyBuffer, 0, icmpReplyLength); + + if (IcmpSendEcho2Ex( + icmpHandle, + 0, + NULL, + NULL, + ((PSOCKADDR_IN)&sourceAddress)->sin_addr.s_addr, + ((PSOCKADDR_IN)&destinationAddress)->sin_addr.s_addr, + icmpEchoBuffer->Buffer, + (USHORT)icmpEchoBuffer->Length, + &pingOptions, + icmpReplyBuffer, + icmpReplyLength, + DEFAULT_TIMEOUT + )) + { + PICMP_ECHO_REPLY reply4 = (PICMP_ECHO_REPLY)icmpReplyBuffer; + + memcpy(&last4ReplyAddress, &reply4->Address, sizeof(IN_ADDR)); + + TracertQueueHostLookup( + context, + node, + &reply4->Address + ); + + node->PingStatus[ii] = reply4->Status; + node->PingList[ii] = reply4->RoundTripTime; + UpdateTracertNode(context, node); + + if (reply4->Status == IP_HOP_LIMIT_EXCEEDED && reply4->RoundTripTime < MIN_INTERVAL) + { + //LARGE_INTEGER interval; + //NtDelayExecution(FALSE, PhTimeoutFromMilliseconds(&interval, MIN_INTERVAL - reply4->RoundTripTime)); + } + + //if (reply4->Status != IP_REQ_TIMED_OUT) + //{ + // PPH_STRING errorMessage; + // + // if (errorMessage = TracertGetErrorMessage(reply4->Status)) + // { + // node->IpAddressString = errorMessage; + // } + //} + } + else + { + node->PingStatus[ii] = IP_REQ_TIMED_OUT; + UpdateTracertNode(context, node); + } + + PhFree(icmpReplyBuffer); + } + else + { + icmpReplyLength = ICMP_BUFFER_SIZE(sizeof(ICMPV6_ECHO_REPLY), icmpEchoBuffer); + icmpReplyBuffer = PhAllocate(icmpReplyLength); + memset(icmpReplyBuffer, 0, icmpReplyLength); + + if (Icmp6SendEcho2( + icmpHandle, + 0, + NULL, + NULL, + ((PSOCKADDR_IN6)&sourceAddress), + ((PSOCKADDR_IN6)&destinationAddress), + icmpEchoBuffer->Buffer, + (USHORT)icmpEchoBuffer->Length, + &pingOptions, + icmpReplyBuffer, + icmpReplyLength, + DEFAULT_TIMEOUT + )) + { + PICMPV6_ECHO_REPLY reply6 = (PICMPV6_ECHO_REPLY)icmpReplyBuffer; + + memcpy(&last6ReplyAddress, &reply6->Address.sin6_addr, sizeof(IN6_ADDR)); + + TracertQueueHostLookup( + context, + node, + &reply6->Address.sin6_addr + ); + + node->PingStatus[ii] = reply6->Status; + node->PingList[ii] = reply6->RoundTripTime; + UpdateTracertNode(context, node); + + if (reply6->Status == IP_HOP_LIMIT_EXCEEDED) + { + if (reply6->RoundTripTime < MIN_INTERVAL) + { + //LARGE_INTEGER interval; + //NtDelayExecution(FALSE, PhTimeoutFromMilliseconds(&interval, MIN_INTERVAL - reply6->RoundTripTime)); + } + } + } + else + { + node->PingStatus[ii] = IP_REQ_TIMED_OUT; + UpdateTracertNode(context, node); + } + + PhFree(icmpReplyBuffer); + } + } + + if (context->RemoteEndpoint.Address.Type == PH_IPV4_NETWORK_TYPE) + { + if (!memcmp(&last4ReplyAddress, &((PSOCKADDR_IN)&destinationAddress)->sin_addr, sizeof(IN_ADDR))) + break; + } + else if (context->RemoteEndpoint.Address.Type == PH_IPV6_NETWORK_TYPE) + { + if (!memcmp(&last6ReplyAddress, &((PSOCKADDR_IN6)&destinationAddress)->sin6_addr, sizeof(IN6_ADDR))) + break; + } + + pingOptions.Ttl++; + } + +CleanupExit: + + if (icmpHandle != INVALID_HANDLE_VALUE) + { + IcmpCloseHandle(icmpHandle); + } + + PhDereferenceObject(context); + + PostMessage(context->WindowHandle, NTM_RECEIVEDFINISH, 0, 0); + return STATUS_SUCCESS; +} + +VOID ShowMenu( + _In_ PNETWORK_TRACERT_CONTEXT Context, + _In_ ULONG Id + ) +{ + switch (Id) + { + case MAINMENU_ACTION_PING: + { + PH_IP_ENDPOINT RemoteEndpoint; + PWSTR terminator = NULL; + PTRACERT_ROOT_NODE node; + + if (node = GetSelectedTracertNode(Context)) + { + if (NT_SUCCESS(RtlIpv4StringToAddress( + node->IpAddressString->Buffer, + TRUE, + &terminator, + &RemoteEndpoint.Address.InAddr + ))) + { + RemoteEndpoint.Address.Type = PH_IPV4_NETWORK_TYPE; + ShowPingWindowFromAddress(RemoteEndpoint); + break; + } + + if (NT_SUCCESS(RtlIpv6StringToAddress( + node->IpAddressString->Buffer, + &terminator, + &RemoteEndpoint.Address.In6Addr + ))) + { + RemoteEndpoint.Address.Type = PH_IPV6_NETWORK_TYPE; + ShowPingWindowFromAddress(RemoteEndpoint); + break; + } + } + } + break; + case NETWORK_ACTION_TRACEROUTE: + { + PH_IP_ENDPOINT RemoteEndpoint; + PWSTR terminator = NULL; + PTRACERT_ROOT_NODE node; + + if (node = GetSelectedTracertNode(Context)) + { + if (NT_SUCCESS(RtlIpv4StringToAddress( + node->IpAddressString->Buffer, + TRUE, + &terminator, + &RemoteEndpoint.Address.InAddr + ))) + { + RemoteEndpoint.Address.Type = PH_IPV4_NETWORK_TYPE; + ShowTracertWindowFromAddress(RemoteEndpoint); + break; + } + + if (NT_SUCCESS(RtlIpv6StringToAddress( + node->IpAddressString->Buffer, + &terminator, + &RemoteEndpoint.Address.In6Addr + ))) + { + RemoteEndpoint.Address.Type = PH_IPV6_NETWORK_TYPE; + ShowTracertWindowFromAddress(RemoteEndpoint); + break; + } + } + } + break; + case NETWORK_ACTION_WHOIS: + { + PH_IP_ENDPOINT RemoteEndpoint; + PWSTR terminator = NULL; + PTRACERT_ROOT_NODE node; + + if (node = GetSelectedTracertNode(Context)) + { + if (NT_SUCCESS(RtlIpv4StringToAddress( + node->IpAddressString->Buffer, + TRUE, + &terminator, + &RemoteEndpoint.Address.InAddr + ))) + { + RemoteEndpoint.Address.Type = PH_IPV4_NETWORK_TYPE; + ShowWhoisWindowFromAddress(RemoteEndpoint); + break; + } + + if (NT_SUCCESS(RtlIpv6StringToAddress( + node->IpAddressString->Buffer, + &terminator, + &RemoteEndpoint.Address.In6Addr + ))) + { + RemoteEndpoint.Address.Type = PH_IPV6_NETWORK_TYPE; + ShowWhoisWindowFromAddress(RemoteEndpoint); + break; + } + } + } + break; + } +} + +INT_PTR CALLBACK TracertDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + PNETWORK_TRACERT_CONTEXT context; + + if (uMsg == WM_INITDIALOG) + { + context = (PNETWORK_TRACERT_CONTEXT)lParam; + SetProp(hwndDlg, L"Context", (HANDLE)context); + } + else + { + context = (PNETWORK_TRACERT_CONTEXT)GetProp(hwndDlg, L"Context"); + + if (uMsg == WM_DESTROY) + { + context->Cancel = TRUE; + + PhSaveWindowPlacementToSetting(SETTING_NAME_TRACERT_WINDOW_POSITION, SETTING_NAME_TRACERT_WINDOW_SIZE, hwndDlg); + + if (context->FontHandle) + DeleteObject(context->FontHandle); + + DeleteTracertTree(context); + + PhDeleteWorkQueue(&context->WorkQueue); + PhDeleteLayoutManager(&context->LayoutManager); + RemoveProp(hwndDlg, L"Context"); + PhDereferenceObject(context); + + PostQuitMessage(0); + } + } + + if (!context) + return FALSE; + + switch (uMsg) + { + case WM_INITDIALOG: + { + HANDLE tracertThread; + + PhCenterWindow(hwndDlg, PhMainWndHandle); + + Static_SetText(hwndDlg, + PhaFormatString(L"Tracing %s...", context->IpAddressString)->Buffer + ); + Static_SetText(GetDlgItem(hwndDlg, IDC_STATUS), + PhaFormatString(L"Tracing route to %s with %lu bytes of data...", context->IpAddressString, PhGetIntegerSetting(SETTING_NAME_PING_SIZE))->Buffer + ); + + context->WindowHandle = hwndDlg; + context->TreeNewHandle = GetDlgItem(hwndDlg, IDC_LIST_TRACERT); + context->FontHandle = PhCreateCommonFont(-15, FW_MEDIUM, GetDlgItem(hwndDlg, IDC_STATUS)); + + InitializeTracertTree(context); + + PhInitializeWorkQueue(&context->WorkQueue, 0, 40, 5000); + PhInitializeLayoutManager(&context->LayoutManager, hwndDlg); + PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_STATUS), NULL, PH_ANCHOR_TOP | PH_ANCHOR_LEFT | PH_ANCHOR_RIGHT | PH_LAYOUT_FORCE_INVALIDATE); + PhAddLayoutItem(&context->LayoutManager, context->TreeNewHandle, NULL, PH_ANCHOR_ALL); + PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDCANCEL), NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_RIGHT); + + if (PhGetIntegerPairSetting(SETTING_NAME_TRACERT_WINDOW_POSITION).X != 0) + PhLoadWindowPlacementFromSetting(SETTING_NAME_TRACERT_WINDOW_POSITION, SETTING_NAME_TRACERT_WINDOW_SIZE, hwndDlg); + else + PhCenterWindow(hwndDlg, PhMainWndHandle); + + PhReferenceObject(context); + + if (tracertThread = PhCreateThread(0, NetworkTracertThreadStart, (PVOID)context)) + NtClose(tracertThread); + + EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); + } + break; + case WM_COMMAND: + { + switch (GET_WM_COMMAND_ID(wParam, lParam)) + { + case IDCANCEL: + DestroyWindow(hwndDlg); + break; + case TRACERT_SHOWCONTEXTMENU: + { + PPH_EMENU menu; + PTRACERT_ROOT_NODE selectedNode; + PPH_EMENU_ITEM selectedItem; + PPH_TREENEW_MOUSE_EVENT mouseEvent = (PPH_TREENEW_MOUSE_EVENT)lParam; + + if (selectedNode = GetSelectedTracertNode(context)) + { + menu = PhCreateEMenu(); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, MAINMENU_ACTION_PING, L"Ping", NULL, NULL), -1); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, NETWORK_ACTION_TRACEROUTE, L"Traceroute", NULL, NULL), -1); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, NETWORK_ACTION_WHOIS, L"Whois", NULL, NULL), -1); + + selectedItem = PhShowEMenu( + menu, + hwndDlg, + PH_EMENU_SHOW_LEFTRIGHT, + PH_ALIGN_LEFT | PH_ALIGN_TOP, + mouseEvent->Location.x, + mouseEvent->Location.y + ); + + if (selectedItem && selectedItem->Id != -1) + { + ShowMenu(context, selectedItem->Id); + } + + PhDestroyEMenu(menu); + } + } + break; + } + } + break; + case WM_SIZE: + PhLayoutManagerLayout(&context->LayoutManager); + break; + case NTM_RECEIVEDFINISH: + { + PPH_STRING windowText; + + if (windowText = PH_AUTO(PhGetWindowText(context->WindowHandle))) + { + Static_SetText( + context->WindowHandle, + PhaFormatString(L"%s complete", windowText->Buffer)->Buffer + ); + } + + if (windowText = PH_AUTO(PhGetWindowText(GetDlgItem(hwndDlg, IDC_STATUS)))) + { + Static_SetText( + GetDlgItem(hwndDlg, IDC_STATUS), + PhaFormatString(L"%s complete", windowText->Buffer)->Buffer + ); + } + + TreeNew_NodesStructured(context->TreeNewHandle); + } + break; + } + + return FALSE; +} + +NTSTATUS TracertDialogThreadStart( + _In_ PVOID Parameter + ) +{ + BOOL result; + MSG message; + HWND windowHandle; + PH_AUTO_POOL autoPool; + PNETWORK_TRACERT_CONTEXT context = (PNETWORK_TRACERT_CONTEXT)Parameter; + + PhInitializeAutoPool(&autoPool); + + windowHandle = CreateDialogParam( + (HINSTANCE)PluginInstance->DllBase, + MAKEINTRESOURCE(IDD_TRACERT), + NULL, + TracertDlgProc, + (LPARAM)Parameter + ); + + ShowWindow(windowHandle, SW_SHOW); + SetForegroundWindow(windowHandle); + + while (result = GetMessage(&message, NULL, 0, 0)) + { + if (result == -1) + break; + + if (!IsDialogMessage(context->WindowHandle, &message)) + { + TranslateMessage(&message); + DispatchMessage(&message); + } + + PhDrainAutoPool(&autoPool); + } + + PhDeleteAutoPool(&autoPool); + + return STATUS_SUCCESS; +} + +VOID ShowTracertWindow( + _In_ PPH_NETWORK_ITEM NetworkItem + ) +{ + HANDLE dialogThread; + PNETWORK_TRACERT_CONTEXT context; + + context = (PNETWORK_TRACERT_CONTEXT)PhCreateAlloc(sizeof(NETWORK_TRACERT_CONTEXT)); + memset(context, 0, sizeof(NETWORK_TRACERT_CONTEXT)); + + context->RemoteEndpoint = NetworkItem->RemoteEndpoint; + + if (NetworkItem->RemoteEndpoint.Address.Type == PH_IPV4_NETWORK_TYPE) + { + RtlIpv4AddressToString(&NetworkItem->RemoteEndpoint.Address.InAddr, context->IpAddressString); + } + else if (NetworkItem->RemoteEndpoint.Address.Type == PH_IPV6_NETWORK_TYPE) + { + RtlIpv6AddressToString(&NetworkItem->RemoteEndpoint.Address.In6Addr, context->IpAddressString); + } + + if (dialogThread = PhCreateThread(0, TracertDialogThreadStart, (PVOID)context)) + { + NtClose(dialogThread); + } +} + +VOID ShowTracertWindowFromAddress( + _In_ PH_IP_ENDPOINT RemoteEndpoint + ) +{ + HANDLE dialogThread; + PNETWORK_TRACERT_CONTEXT context; + + context = (PNETWORK_TRACERT_CONTEXT)PhCreateAlloc(sizeof(NETWORK_TRACERT_CONTEXT)); + memset(context, 0, sizeof(NETWORK_TRACERT_CONTEXT)); + + context->RemoteEndpoint = RemoteEndpoint; + + if (RemoteEndpoint.Address.Type == PH_IPV4_NETWORK_TYPE) + { + RtlIpv4AddressToString(&RemoteEndpoint.Address.InAddr, context->IpAddressString); + } + else if (RemoteEndpoint.Address.Type == PH_IPV6_NETWORK_TYPE) + { + RtlIpv6AddressToString(&RemoteEndpoint.Address.In6Addr, context->IpAddressString); + } + + if (dialogThread = PhCreateThread(0, TracertDialogThreadStart, (PVOID)context)) + { + NtClose(dialogThread); + } } \ No newline at end of file diff --git a/plugins/NetworkTools/whois.c b/plugins/NetworkTools/whois.c index 4a2b968ffe26..bf6e602d0270 100644 --- a/plugins/NetworkTools/whois.c +++ b/plugins/NetworkTools/whois.c @@ -1,604 +1,604 @@ -/* - * Process Hacker Network Tools - - * Whois dialog - * - * Copyright (C) 2013-2017 dmex - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include "nettools.h" -#include -#include - -VOID RichEditSetText( - _In_ HWND RichEditHandle, - _In_ PWSTR Text - ) -{ - SendMessage(RichEditHandle, WM_SETREDRAW, FALSE, 0); - - // Update the Richedit text. - SendMessage(RichEditHandle, EM_REPLACESEL, FALSE, (LPARAM)Text); - // NOTE: EM_LINESCROLL and WM_VSCROLL won't update the scroll position - // if the Richedit control doesn't have keyboard focus (e.g. SetFocus). - SendMessage(RichEditHandle, WM_VSCROLL, SB_TOP, 0); - - // Redraw the Richedit with the new text. - SendMessage(RichEditHandle, WM_SETREDRAW, TRUE, 0); - InvalidateRect(RichEditHandle, NULL, FALSE); -} - -PPH_STRING TrimString( - _In_ PPH_STRING String - ) -{ - static PH_STRINGREF whitespace = PH_STRINGREF_INIT(L" "); - PH_STRINGREF sr = String->sr; - PhTrimStringRef(&sr, &whitespace, 0); - return PhCreateString2(&sr); -} - -PPH_STRING TrimString2( - _In_ PPH_STRING String - ) -{ - static PH_STRINGREF whitespace = PH_STRINGREF_INIT(L"\n\n"); - PH_STRINGREF sr = String->sr; - PhTrimStringRef(&sr, &whitespace, 0); - return PhCreateString2(&sr); -} - -BOOLEAN ReadSocketString( - _In_ SOCKET Handle, - _Out_ _Deref_post_z_cap_(*DataLength) PSTR *Data, - _Out_ ULONG *DataLength - ) -{ - PSTR data; - ULONG allocatedLength; - ULONG dataLength; - ULONG returnLength; - BYTE buffer[PAGE_SIZE]; - - allocatedLength = sizeof(buffer); - data = (PSTR)PhAllocate(allocatedLength); - dataLength = 0; - - // Zero the buffer - memset(buffer, 0, PAGE_SIZE); - - while ((returnLength = recv(Handle, buffer, PAGE_SIZE, 0)) != SOCKET_ERROR) - { - if (returnLength == 0) - break; - - if (allocatedLength < dataLength + returnLength) - { - allocatedLength *= 2; - data = (PSTR)PhReAllocate(data, allocatedLength); - } - - // Copy the returned buffer into our pointer - memcpy(data + dataLength, buffer, returnLength); - // Zero the returned buffer for the next loop - //memset(buffer, 0, returnLength); - - dataLength += returnLength; - } - - if (allocatedLength < dataLength + 1) - { - allocatedLength++; - data = (PSTR)PhReAllocate(data, allocatedLength); - } - - // Ensure that the buffer is null-terminated. - data[dataLength] = 0; - - *DataLength = dataLength; - *Data = data; - - return TRUE; -} - -BOOLEAN WhoisExtractServerUrl( - _In_ PPH_STRING WhoisResponce, - _Out_ PPH_STRING *WhoisServerAddress - ) -{ - ULONG_PTR whoisServerHostnameIndex; - ULONG_PTR whoisServerHostnameLength; - PPH_STRING whoisServerName; - - if ((whoisServerHostnameIndex = PhFindStringInString(WhoisResponce, 0, L"whois:")) == -1) - return FALSE; - if ((whoisServerHostnameLength = PhFindStringInString(WhoisResponce, whoisServerHostnameIndex, L"\n")) == -1) - return FALSE; - if ((whoisServerHostnameLength = whoisServerHostnameLength - whoisServerHostnameIndex) == 0) - return FALSE; - - whoisServerName = PhSubstring( - WhoisResponce, - whoisServerHostnameIndex + wcslen(L"whois:"), - (ULONG)whoisServerHostnameLength - wcslen(L"whois:") - ); - - *WhoisServerAddress = TrimString(whoisServerName); - - PhDereferenceObject(whoisServerName); - return TRUE; -} - -BOOLEAN WhoisExtractReferralServer( - _In_ PPH_STRING WhoisResponce, - _Out_ PPH_STRING *WhoisServerAddress, - _Out_ PPH_STRING *WhoisServerPort - ) -{ - ULONG_PTR whoisServerHostnameIndex; - ULONG_PTR whoisServerHostnameLength; - PPH_STRING whoisServerName; - PPH_STRING whoisServerHostname; - WCHAR urlProtocal[0x100] = L""; - WCHAR urlHost[0x100] = L""; - WCHAR urlPort[0x100] = L""; - WCHAR urlPath[0x100] = L""; - - if ((whoisServerHostnameIndex = PhFindStringInString(WhoisResponce, 0, L"ReferralServer:")) == -1) - return FALSE; - if ((whoisServerHostnameLength = PhFindStringInString(WhoisResponce, whoisServerHostnameIndex, L"\n")) == -1) - return FALSE; - if ((whoisServerHostnameLength = whoisServerHostnameLength - whoisServerHostnameIndex) == 0) - return FALSE; - - whoisServerName = PhSubstring( - WhoisResponce, - whoisServerHostnameIndex + wcslen(L"ReferralServer:"), - (ULONG)whoisServerHostnameLength - wcslen(L"ReferralServer:") - ); - - whoisServerHostname = TrimString(whoisServerName); - - if (swscanf_s( - whoisServerHostname->Buffer, - L"%[^:]://%[^:]:%[^/]/%s", - urlProtocal, - (UINT)ARRAYSIZE(urlProtocal), - urlHost, - (UINT)ARRAYSIZE(urlHost), - urlPort, - (UINT)ARRAYSIZE(urlPort), - urlPath, - (UINT)ARRAYSIZE(urlPath) - )) - { - *WhoisServerAddress = PhCreateString(urlHost); - - if (PhCountStringZ(urlPort) >= 2) - { - *WhoisServerPort = PhCreateString(urlPort); - } - - PhDereferenceObject(whoisServerName); - PhDereferenceObject(whoisServerHostname); - return TRUE; - } - - PhDereferenceObject(whoisServerName); - PhDereferenceObject(whoisServerHostname); - return FALSE; -} - -BOOLEAN WhoisQueryServer( - _In_ PWSTR WhoisServerAddress, - _In_ PWSTR WhoisServerPort, - _In_ PWSTR WhoisQueryAddress, - _In_ PPH_STRING* response - ) -{ - WSADATA winsockStartup; - PADDRINFOW result = NULL; - PADDRINFOW addrInfo = NULL; - ADDRINFOW hints; - ULONG whoisResponceLength = 0; - PSTR whoisResponce = NULL; - PPH_BYTES whoisQuery = NULL; - - if (!WhoisServerPort) - WhoisServerPort = L"43"; - - if (WSAStartup(WINSOCK_VERSION, &winsockStartup) != ERROR_SUCCESS) - return FALSE; - - memset(&hints, 0, sizeof(ADDRINFOW)); - hints.ai_family = AF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; - hints.ai_protocol = IPPROTO_TCP; - - if (GetAddrInfo(WhoisServerAddress, WhoisServerPort, &hints, &result)) - { - WSACleanup(); - return FALSE; - } - - if (PhEqualStringZ(WhoisServerAddress, L"whois.arin.net", TRUE)) - whoisQuery = FormatAnsiString("n %S\r\n", WhoisQueryAddress); - else - whoisQuery = FormatAnsiString("%S\r\n", WhoisQueryAddress); - - for (addrInfo = result; addrInfo; addrInfo = addrInfo->ai_next) - { - SOCKET socketHandle = socket( - addrInfo->ai_family, - addrInfo->ai_socktype, - addrInfo->ai_protocol - ); - - if (socketHandle == INVALID_SOCKET) - continue; - - if (connect(socketHandle, addrInfo->ai_addr, (INT)addrInfo->ai_addrlen) == SOCKET_ERROR) - { - closesocket(socketHandle); - continue; - } - - if (send(socketHandle, whoisQuery->Buffer, (INT)whoisQuery->Length, 0) == SOCKET_ERROR) - { - closesocket(socketHandle); - continue; - } - - if (ReadSocketString(socketHandle, &whoisResponce, &whoisResponceLength)) - { - closesocket(socketHandle); - break; - } - } - - FreeAddrInfo(result); - WSACleanup(); - PhDereferenceObject(whoisQuery); - - if (whoisResponce) - { - *response = PhConvertUtf8ToUtf16(whoisResponce); - return TRUE; - } - - return FALSE; -} - -NTSTATUS NetworkWhoisThreadStart( - _In_ PVOID Parameter - ) -{ - PNETWORK_WHOIS_CONTEXT context = (PNETWORK_WHOIS_CONTEXT)Parameter; - PH_STRING_BUILDER sb; - PPH_STRING whoisResponse = NULL; - PPH_STRING whoisReferralResponse = NULL; - PPH_STRING whoisServerName = NULL; - PPH_STRING whoisReferralServerName = NULL; - PPH_STRING whoisReferralServerPort = NULL; - - PhInitializeStringBuilder(&sb, 0x100); - - if (!WhoisQueryServer(L"whois.iana.org", L"43", context->IpAddressString, &whoisResponse)) - { - PhAppendFormatStringBuilder(&sb, L"Connection to whois.iana.org failed.\n"); - goto CleanupExit; - } - - if (!WhoisExtractServerUrl(whoisResponse, &whoisServerName)) - { - PhAppendFormatStringBuilder(&sb, L"Error parsing whois.iana.org response:\n%s\n", whoisResponse->Buffer); - goto CleanupExit; - } - - if (WhoisQueryServer( - PhGetString(whoisServerName), - L"43", - context->IpAddressString, - &whoisResponse - )) - { - if (WhoisExtractReferralServer( - whoisResponse, - &whoisReferralServerName, - &whoisReferralServerPort - )) - { - PhAppendFormatStringBuilder( - &sb, - L"%s referred the request to: %s\n", - PhGetString(whoisServerName), - PhGetString(whoisReferralServerName) - ); - - if (WhoisQueryServer( - PhGetString(whoisReferralServerName), - PhGetString(whoisReferralServerPort), - context->IpAddressString, - &whoisReferralResponse - )) - { - PhAppendFormatStringBuilder(&sb, L"\n%s\n", PhGetString(whoisReferralResponse)); - PhAppendFormatStringBuilder(&sb, L"\nOriginal request to %s:\n%s\n", PhGetString(whoisServerName), PhGetString(whoisResponse)); - PostMessage(context->WindowHandle, NTM_RECEIVEDWHOIS, 0, (LPARAM)PhFinalStringBuilderString(&sb)); - goto CleanupExit; - } - } - } - - PhAppendFormatStringBuilder(&sb, L"\n%s", PhGetString(whoisResponse)); - - PostMessage(context->WindowHandle, NTM_RECEIVEDWHOIS, 0, (LPARAM)PhFinalStringBuilderString(&sb)); - -CleanupExit: - PhClearReference(&whoisResponse); - PhClearReference(&whoisReferralResponse); - PhClearReference(&whoisServerName); - PhClearReference(&whoisReferralServerName); - PhClearReference(&whoisReferralServerPort); - - return STATUS_SUCCESS; -} - -INT_PTR CALLBACK NetworkOutputDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - PNETWORK_WHOIS_CONTEXT context; - - if (uMsg == WM_INITDIALOG) - { - context = (PNETWORK_WHOIS_CONTEXT)lParam; - SetProp(hwndDlg, L"Context", (HANDLE)context); - } - else - { - context = (PNETWORK_WHOIS_CONTEXT)GetProp(hwndDlg, L"Context"); - - if (uMsg == WM_DESTROY) - { - PhSaveWindowPlacementToSetting(SETTING_NAME_WHOIS_WINDOW_POSITION, SETTING_NAME_WHOIS_WINDOW_SIZE, hwndDlg); - PhDeleteLayoutManager(&context->LayoutManager); - RemoveProp(hwndDlg, L"Context"); - PhDereferenceObject(context); - - PostQuitMessage(0); - } - } - - if (!context) - return FALSE; - - switch (uMsg) - { - case WM_INITDIALOG: - { - HANDLE dialogThread; - - SetWindowText(hwndDlg, PhaFormatString(L"Whois %s...", context->IpAddressString)->Buffer); - - context->WindowHandle = hwndDlg; - context->RichEditHandle = GetDlgItem(hwndDlg, IDC_NETOUTPUTEDIT); - - // Reset the border style for richedit uxtheme borders - PhSetWindowStyle(context->RichEditHandle, WS_BORDER, WS_BORDER); - PhSetWindowExStyle(context->RichEditHandle, WS_EX_CLIENTEDGE, ~WS_EX_CLIENTEDGE); - //SendMessage(context->OutputHandle, EM_SETBKGNDCOLOR, RGB(0, 0, 0), 0); - SendMessage(context->RichEditHandle, EM_SETEVENTMASK, 0, SendMessage(context->RichEditHandle, EM_GETEVENTMASK, 0, 0) | ENM_LINK); - SendMessage(context->RichEditHandle, EM_AUTOURLDETECT, AURL_ENABLEURL, 0); - SendMessage(context->RichEditHandle, EM_SETWORDWRAPMODE, WBF_WORDWRAP, 0); - context->FontHandle = PhCreateCommonFont(-11, FW_MEDIUM, context->RichEditHandle); - - PhInitializeLayoutManager(&context->LayoutManager, hwndDlg); - PhAddLayoutItem(&context->LayoutManager, context->RichEditHandle, NULL, PH_ANCHOR_ALL); - - if (PhGetIntegerPairSetting(SETTING_NAME_WHOIS_WINDOW_POSITION).X != 0) - PhLoadWindowPlacementFromSetting(SETTING_NAME_WHOIS_WINDOW_POSITION, SETTING_NAME_WHOIS_WINDOW_SIZE, hwndDlg); - else - PhCenterWindow(hwndDlg, PhMainWndHandle); - - if (dialogThread = PhCreateThread(0, NetworkWhoisThreadStart, (PVOID)context)) - NtClose(dialogThread); - - EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); - } - break; - case WM_COMMAND: - { - switch (GET_WM_COMMAND_ID(wParam, lParam)) - { - case IDCANCEL: - case IDOK: - DestroyWindow(hwndDlg); - break; - } - } - break; - case WM_SIZE: - PhLayoutManagerLayout(&context->LayoutManager); - break; - case WM_NOTIFY: - { - LPNMHDR header = (LPNMHDR)lParam; - - switch (header->code) - { - case EN_LINK: - { - ENLINK* link = (ENLINK*)lParam; - - if (link->msg == WM_LBUTTONUP) - { - ULONG length; - PWSTR buffer; - TEXTRANGE textRange; - - length = (link->chrg.cpMax - link->chrg.cpMin) * sizeof(WCHAR); - buffer = PhAllocate(length + 1); - memset(buffer, 0, length + 1); - - textRange.chrg = link->chrg; - textRange.lpstrText = buffer; - - if (SendMessage(context->RichEditHandle, EM_GETTEXTRANGE, 0, (LPARAM)&textRange)) - { - if (PhCountStringZ(buffer) > 4) - { - PhShellExecute(context->WindowHandle, buffer, NULL); - } - } - - PhFree(buffer); - } - } - break; - } - } - break; - case NTM_RECEIVEDWHOIS: - { - PPH_STRING whoisString = PH_AUTO((PPH_STRING)lParam); - PPH_STRING trimString = PH_AUTO(TrimString2(whoisString)); - - RichEditSetText(context->RichEditHandle, trimString->Buffer); - } - break; - case WM_TRACERT_UPDATE: - { - PPH_STRING windowText = PH_AUTO(PhGetWindowText(context->WindowHandle)); - - if (windowText) - { - Static_SetText(context->WindowHandle, - PhaFormatString(L"%s Finished.", windowText->Buffer)->Buffer); - } - } - break; - } - - return FALSE; -} - -NTSTATUS NetworkWhoisDialogThreadStart( - _In_ PVOID Parameter - ) -{ - static PH_INITONCE initOnce = PH_INITONCE_INIT; - BOOL result; - MSG message; - HWND windowHandle; - PH_AUTO_POOL autoPool; - - if (PhBeginInitOnce(&initOnce)) - { - LoadLibrary(L"msftedit.dll"); - PhEndInitOnce(&initOnce); - } - - PhInitializeAutoPool(&autoPool); - - windowHandle = CreateDialogParam( - PluginInstance->DllBase, - MAKEINTRESOURCE(IDD_WHOIS), - NULL, - NetworkOutputDlgProc, - (LPARAM)Parameter - ); - - ShowWindow(windowHandle, SW_SHOW); - SetForegroundWindow(windowHandle); - - while (result = GetMessage(&message, NULL, 0, 0)) - { - if (result == -1) - break; - - if (!IsDialogMessage(windowHandle, &message)) - { - TranslateMessage(&message); - DispatchMessage(&message); - } - - PhDrainAutoPool(&autoPool); - } - - PhDeleteAutoPool(&autoPool); - - return STATUS_SUCCESS; -} - - -VOID ShowWhoisWindow( - _In_ PPH_NETWORK_ITEM NetworkItem - ) -{ - HANDLE dialogThread; - PNETWORK_WHOIS_CONTEXT context; - - context = (PNETWORK_WHOIS_CONTEXT)PhCreateAlloc(sizeof(NETWORK_WHOIS_CONTEXT)); - memset(context, 0, sizeof(NETWORK_WHOIS_CONTEXT)); - - context->RemoteEndpoint = NetworkItem->RemoteEndpoint; - - if (NetworkItem->RemoteEndpoint.Address.Type == PH_IPV4_NETWORK_TYPE) - { - RtlIpv4AddressToString(&NetworkItem->RemoteEndpoint.Address.InAddr, context->IpAddressString); - } - else if (NetworkItem->RemoteEndpoint.Address.Type == PH_IPV6_NETWORK_TYPE) - { - RtlIpv6AddressToString(&NetworkItem->RemoteEndpoint.Address.In6Addr, context->IpAddressString); - } - - if (dialogThread = PhCreateThread(0, NetworkWhoisDialogThreadStart, (PVOID)context)) - { - NtClose(dialogThread); - } -} - -VOID ShowWhoisWindowFromAddress( - _In_ PH_IP_ENDPOINT RemoteEndpoint - ) -{ - HANDLE dialogThread; - PNETWORK_WHOIS_CONTEXT context; - - context = (PNETWORK_WHOIS_CONTEXT)PhCreateAlloc(sizeof(NETWORK_WHOIS_CONTEXT)); - memset(context, 0, sizeof(NETWORK_WHOIS_CONTEXT)); - - context->RemoteEndpoint = RemoteEndpoint; - - if (RemoteEndpoint.Address.Type == PH_IPV4_NETWORK_TYPE) - { - RtlIpv4AddressToString(&RemoteEndpoint.Address.InAddr, context->IpAddressString); - } - else if (RemoteEndpoint.Address.Type == PH_IPV6_NETWORK_TYPE) - { - RtlIpv6AddressToString(&RemoteEndpoint.Address.In6Addr, context->IpAddressString); - } - - if (dialogThread = PhCreateThread(0, NetworkWhoisDialogThreadStart, (PVOID)context)) - { - NtClose(dialogThread); - } +/* + * Process Hacker Network Tools - + * Whois dialog + * + * Copyright (C) 2013-2017 dmex + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include "nettools.h" +#include +#include + +VOID RichEditSetText( + _In_ HWND RichEditHandle, + _In_ PWSTR Text + ) +{ + SendMessage(RichEditHandle, WM_SETREDRAW, FALSE, 0); + + // Update the Richedit text. + SendMessage(RichEditHandle, EM_REPLACESEL, FALSE, (LPARAM)Text); + // NOTE: EM_LINESCROLL and WM_VSCROLL won't update the scroll position + // if the Richedit control doesn't have keyboard focus (e.g. SetFocus). + SendMessage(RichEditHandle, WM_VSCROLL, SB_TOP, 0); + + // Redraw the Richedit with the new text. + SendMessage(RichEditHandle, WM_SETREDRAW, TRUE, 0); + InvalidateRect(RichEditHandle, NULL, FALSE); +} + +PPH_STRING TrimString( + _In_ PPH_STRING String + ) +{ + static PH_STRINGREF whitespace = PH_STRINGREF_INIT(L" "); + PH_STRINGREF sr = String->sr; + PhTrimStringRef(&sr, &whitespace, 0); + return PhCreateString2(&sr); +} + +PPH_STRING TrimString2( + _In_ PPH_STRING String + ) +{ + static PH_STRINGREF whitespace = PH_STRINGREF_INIT(L"\n\n"); + PH_STRINGREF sr = String->sr; + PhTrimStringRef(&sr, &whitespace, 0); + return PhCreateString2(&sr); +} + +BOOLEAN ReadSocketString( + _In_ SOCKET Handle, + _Out_ _Deref_post_z_cap_(*DataLength) PSTR *Data, + _Out_ ULONG *DataLength + ) +{ + PSTR data; + ULONG allocatedLength; + ULONG dataLength; + ULONG returnLength; + BYTE buffer[PAGE_SIZE]; + + allocatedLength = sizeof(buffer); + data = (PSTR)PhAllocate(allocatedLength); + dataLength = 0; + + // Zero the buffer + memset(buffer, 0, PAGE_SIZE); + + while ((returnLength = recv(Handle, buffer, PAGE_SIZE, 0)) != SOCKET_ERROR) + { + if (returnLength == 0) + break; + + if (allocatedLength < dataLength + returnLength) + { + allocatedLength *= 2; + data = (PSTR)PhReAllocate(data, allocatedLength); + } + + // Copy the returned buffer into our pointer + memcpy(data + dataLength, buffer, returnLength); + // Zero the returned buffer for the next loop + //memset(buffer, 0, returnLength); + + dataLength += returnLength; + } + + if (allocatedLength < dataLength + 1) + { + allocatedLength++; + data = (PSTR)PhReAllocate(data, allocatedLength); + } + + // Ensure that the buffer is null-terminated. + data[dataLength] = 0; + + *DataLength = dataLength; + *Data = data; + + return TRUE; +} + +BOOLEAN WhoisExtractServerUrl( + _In_ PPH_STRING WhoisResponce, + _Out_ PPH_STRING *WhoisServerAddress + ) +{ + ULONG_PTR whoisServerHostnameIndex; + ULONG_PTR whoisServerHostnameLength; + PPH_STRING whoisServerName; + + if ((whoisServerHostnameIndex = PhFindStringInString(WhoisResponce, 0, L"whois:")) == -1) + return FALSE; + if ((whoisServerHostnameLength = PhFindStringInString(WhoisResponce, whoisServerHostnameIndex, L"\n")) == -1) + return FALSE; + if ((whoisServerHostnameLength = whoisServerHostnameLength - whoisServerHostnameIndex) == 0) + return FALSE; + + whoisServerName = PhSubstring( + WhoisResponce, + whoisServerHostnameIndex + wcslen(L"whois:"), + (ULONG)whoisServerHostnameLength - wcslen(L"whois:") + ); + + *WhoisServerAddress = TrimString(whoisServerName); + + PhDereferenceObject(whoisServerName); + return TRUE; +} + +BOOLEAN WhoisExtractReferralServer( + _In_ PPH_STRING WhoisResponce, + _Out_ PPH_STRING *WhoisServerAddress, + _Out_ PPH_STRING *WhoisServerPort + ) +{ + ULONG_PTR whoisServerHostnameIndex; + ULONG_PTR whoisServerHostnameLength; + PPH_STRING whoisServerName; + PPH_STRING whoisServerHostname; + WCHAR urlProtocal[0x100] = L""; + WCHAR urlHost[0x100] = L""; + WCHAR urlPort[0x100] = L""; + WCHAR urlPath[0x100] = L""; + + if ((whoisServerHostnameIndex = PhFindStringInString(WhoisResponce, 0, L"ReferralServer:")) == -1) + return FALSE; + if ((whoisServerHostnameLength = PhFindStringInString(WhoisResponce, whoisServerHostnameIndex, L"\n")) == -1) + return FALSE; + if ((whoisServerHostnameLength = whoisServerHostnameLength - whoisServerHostnameIndex) == 0) + return FALSE; + + whoisServerName = PhSubstring( + WhoisResponce, + whoisServerHostnameIndex + wcslen(L"ReferralServer:"), + (ULONG)whoisServerHostnameLength - wcslen(L"ReferralServer:") + ); + + whoisServerHostname = TrimString(whoisServerName); + + if (swscanf_s( + whoisServerHostname->Buffer, + L"%[^:]://%[^:]:%[^/]/%s", + urlProtocal, + (UINT)ARRAYSIZE(urlProtocal), + urlHost, + (UINT)ARRAYSIZE(urlHost), + urlPort, + (UINT)ARRAYSIZE(urlPort), + urlPath, + (UINT)ARRAYSIZE(urlPath) + )) + { + *WhoisServerAddress = PhCreateString(urlHost); + + if (PhCountStringZ(urlPort) >= 2) + { + *WhoisServerPort = PhCreateString(urlPort); + } + + PhDereferenceObject(whoisServerName); + PhDereferenceObject(whoisServerHostname); + return TRUE; + } + + PhDereferenceObject(whoisServerName); + PhDereferenceObject(whoisServerHostname); + return FALSE; +} + +BOOLEAN WhoisQueryServer( + _In_ PWSTR WhoisServerAddress, + _In_ PWSTR WhoisServerPort, + _In_ PWSTR WhoisQueryAddress, + _In_ PPH_STRING* response + ) +{ + WSADATA winsockStartup; + PADDRINFOW result = NULL; + PADDRINFOW addrInfo = NULL; + ADDRINFOW hints; + ULONG whoisResponceLength = 0; + PSTR whoisResponce = NULL; + PPH_BYTES whoisQuery = NULL; + + if (!WhoisServerPort) + WhoisServerPort = L"43"; + + if (WSAStartup(WINSOCK_VERSION, &winsockStartup) != ERROR_SUCCESS) + return FALSE; + + memset(&hints, 0, sizeof(ADDRINFOW)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + + if (GetAddrInfo(WhoisServerAddress, WhoisServerPort, &hints, &result)) + { + WSACleanup(); + return FALSE; + } + + if (PhEqualStringZ(WhoisServerAddress, L"whois.arin.net", TRUE)) + whoisQuery = FormatAnsiString("n %S\r\n", WhoisQueryAddress); + else + whoisQuery = FormatAnsiString("%S\r\n", WhoisQueryAddress); + + for (addrInfo = result; addrInfo; addrInfo = addrInfo->ai_next) + { + SOCKET socketHandle = socket( + addrInfo->ai_family, + addrInfo->ai_socktype, + addrInfo->ai_protocol + ); + + if (socketHandle == INVALID_SOCKET) + continue; + + if (connect(socketHandle, addrInfo->ai_addr, (INT)addrInfo->ai_addrlen) == SOCKET_ERROR) + { + closesocket(socketHandle); + continue; + } + + if (send(socketHandle, whoisQuery->Buffer, (INT)whoisQuery->Length, 0) == SOCKET_ERROR) + { + closesocket(socketHandle); + continue; + } + + if (ReadSocketString(socketHandle, &whoisResponce, &whoisResponceLength)) + { + closesocket(socketHandle); + break; + } + } + + FreeAddrInfo(result); + WSACleanup(); + PhDereferenceObject(whoisQuery); + + if (whoisResponce) + { + *response = PhConvertUtf8ToUtf16(whoisResponce); + return TRUE; + } + + return FALSE; +} + +NTSTATUS NetworkWhoisThreadStart( + _In_ PVOID Parameter + ) +{ + PNETWORK_WHOIS_CONTEXT context = (PNETWORK_WHOIS_CONTEXT)Parameter; + PH_STRING_BUILDER sb; + PPH_STRING whoisResponse = NULL; + PPH_STRING whoisReferralResponse = NULL; + PPH_STRING whoisServerName = NULL; + PPH_STRING whoisReferralServerName = NULL; + PPH_STRING whoisReferralServerPort = NULL; + + PhInitializeStringBuilder(&sb, 0x100); + + if (!WhoisQueryServer(L"whois.iana.org", L"43", context->IpAddressString, &whoisResponse)) + { + PhAppendFormatStringBuilder(&sb, L"Connection to whois.iana.org failed.\n"); + goto CleanupExit; + } + + if (!WhoisExtractServerUrl(whoisResponse, &whoisServerName)) + { + PhAppendFormatStringBuilder(&sb, L"Error parsing whois.iana.org response:\n%s\n", whoisResponse->Buffer); + goto CleanupExit; + } + + if (WhoisQueryServer( + PhGetString(whoisServerName), + L"43", + context->IpAddressString, + &whoisResponse + )) + { + if (WhoisExtractReferralServer( + whoisResponse, + &whoisReferralServerName, + &whoisReferralServerPort + )) + { + PhAppendFormatStringBuilder( + &sb, + L"%s referred the request to: %s\n", + PhGetString(whoisServerName), + PhGetString(whoisReferralServerName) + ); + + if (WhoisQueryServer( + PhGetString(whoisReferralServerName), + PhGetString(whoisReferralServerPort), + context->IpAddressString, + &whoisReferralResponse + )) + { + PhAppendFormatStringBuilder(&sb, L"\n%s\n", PhGetString(whoisReferralResponse)); + PhAppendFormatStringBuilder(&sb, L"\nOriginal request to %s:\n%s\n", PhGetString(whoisServerName), PhGetString(whoisResponse)); + PostMessage(context->WindowHandle, NTM_RECEIVEDWHOIS, 0, (LPARAM)PhFinalStringBuilderString(&sb)); + goto CleanupExit; + } + } + } + + PhAppendFormatStringBuilder(&sb, L"\n%s", PhGetString(whoisResponse)); + + PostMessage(context->WindowHandle, NTM_RECEIVEDWHOIS, 0, (LPARAM)PhFinalStringBuilderString(&sb)); + +CleanupExit: + PhClearReference(&whoisResponse); + PhClearReference(&whoisReferralResponse); + PhClearReference(&whoisServerName); + PhClearReference(&whoisReferralServerName); + PhClearReference(&whoisReferralServerPort); + + return STATUS_SUCCESS; +} + +INT_PTR CALLBACK NetworkOutputDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + PNETWORK_WHOIS_CONTEXT context; + + if (uMsg == WM_INITDIALOG) + { + context = (PNETWORK_WHOIS_CONTEXT)lParam; + SetProp(hwndDlg, L"Context", (HANDLE)context); + } + else + { + context = (PNETWORK_WHOIS_CONTEXT)GetProp(hwndDlg, L"Context"); + + if (uMsg == WM_DESTROY) + { + PhSaveWindowPlacementToSetting(SETTING_NAME_WHOIS_WINDOW_POSITION, SETTING_NAME_WHOIS_WINDOW_SIZE, hwndDlg); + PhDeleteLayoutManager(&context->LayoutManager); + RemoveProp(hwndDlg, L"Context"); + PhDereferenceObject(context); + + PostQuitMessage(0); + } + } + + if (!context) + return FALSE; + + switch (uMsg) + { + case WM_INITDIALOG: + { + HANDLE dialogThread; + + SetWindowText(hwndDlg, PhaFormatString(L"Whois %s...", context->IpAddressString)->Buffer); + + context->WindowHandle = hwndDlg; + context->RichEditHandle = GetDlgItem(hwndDlg, IDC_NETOUTPUTEDIT); + + // Reset the border style for richedit uxtheme borders + PhSetWindowStyle(context->RichEditHandle, WS_BORDER, WS_BORDER); + PhSetWindowExStyle(context->RichEditHandle, WS_EX_CLIENTEDGE, ~WS_EX_CLIENTEDGE); + //SendMessage(context->OutputHandle, EM_SETBKGNDCOLOR, RGB(0, 0, 0), 0); + SendMessage(context->RichEditHandle, EM_SETEVENTMASK, 0, SendMessage(context->RichEditHandle, EM_GETEVENTMASK, 0, 0) | ENM_LINK); + SendMessage(context->RichEditHandle, EM_AUTOURLDETECT, AURL_ENABLEURL, 0); + SendMessage(context->RichEditHandle, EM_SETWORDWRAPMODE, WBF_WORDWRAP, 0); + context->FontHandle = PhCreateCommonFont(-11, FW_MEDIUM, context->RichEditHandle); + + PhInitializeLayoutManager(&context->LayoutManager, hwndDlg); + PhAddLayoutItem(&context->LayoutManager, context->RichEditHandle, NULL, PH_ANCHOR_ALL); + + if (PhGetIntegerPairSetting(SETTING_NAME_WHOIS_WINDOW_POSITION).X != 0) + PhLoadWindowPlacementFromSetting(SETTING_NAME_WHOIS_WINDOW_POSITION, SETTING_NAME_WHOIS_WINDOW_SIZE, hwndDlg); + else + PhCenterWindow(hwndDlg, PhMainWndHandle); + + if (dialogThread = PhCreateThread(0, NetworkWhoisThreadStart, (PVOID)context)) + NtClose(dialogThread); + + EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); + } + break; + case WM_COMMAND: + { + switch (GET_WM_COMMAND_ID(wParam, lParam)) + { + case IDCANCEL: + case IDOK: + DestroyWindow(hwndDlg); + break; + } + } + break; + case WM_SIZE: + PhLayoutManagerLayout(&context->LayoutManager); + break; + case WM_NOTIFY: + { + LPNMHDR header = (LPNMHDR)lParam; + + switch (header->code) + { + case EN_LINK: + { + ENLINK* link = (ENLINK*)lParam; + + if (link->msg == WM_LBUTTONUP) + { + ULONG length; + PWSTR buffer; + TEXTRANGE textRange; + + length = (link->chrg.cpMax - link->chrg.cpMin) * sizeof(WCHAR); + buffer = PhAllocate(length + 1); + memset(buffer, 0, length + 1); + + textRange.chrg = link->chrg; + textRange.lpstrText = buffer; + + if (SendMessage(context->RichEditHandle, EM_GETTEXTRANGE, 0, (LPARAM)&textRange)) + { + if (PhCountStringZ(buffer) > 4) + { + PhShellExecute(context->WindowHandle, buffer, NULL); + } + } + + PhFree(buffer); + } + } + break; + } + } + break; + case NTM_RECEIVEDWHOIS: + { + PPH_STRING whoisString = PH_AUTO((PPH_STRING)lParam); + PPH_STRING trimString = PH_AUTO(TrimString2(whoisString)); + + RichEditSetText(context->RichEditHandle, trimString->Buffer); + } + break; + case WM_TRACERT_UPDATE: + { + PPH_STRING windowText = PH_AUTO(PhGetWindowText(context->WindowHandle)); + + if (windowText) + { + Static_SetText(context->WindowHandle, + PhaFormatString(L"%s Finished.", windowText->Buffer)->Buffer); + } + } + break; + } + + return FALSE; +} + +NTSTATUS NetworkWhoisDialogThreadStart( + _In_ PVOID Parameter + ) +{ + static PH_INITONCE initOnce = PH_INITONCE_INIT; + BOOL result; + MSG message; + HWND windowHandle; + PH_AUTO_POOL autoPool; + + if (PhBeginInitOnce(&initOnce)) + { + LoadLibrary(L"msftedit.dll"); + PhEndInitOnce(&initOnce); + } + + PhInitializeAutoPool(&autoPool); + + windowHandle = CreateDialogParam( + PluginInstance->DllBase, + MAKEINTRESOURCE(IDD_WHOIS), + NULL, + NetworkOutputDlgProc, + (LPARAM)Parameter + ); + + ShowWindow(windowHandle, SW_SHOW); + SetForegroundWindow(windowHandle); + + while (result = GetMessage(&message, NULL, 0, 0)) + { + if (result == -1) + break; + + if (!IsDialogMessage(windowHandle, &message)) + { + TranslateMessage(&message); + DispatchMessage(&message); + } + + PhDrainAutoPool(&autoPool); + } + + PhDeleteAutoPool(&autoPool); + + return STATUS_SUCCESS; +} + + +VOID ShowWhoisWindow( + _In_ PPH_NETWORK_ITEM NetworkItem + ) +{ + HANDLE dialogThread; + PNETWORK_WHOIS_CONTEXT context; + + context = (PNETWORK_WHOIS_CONTEXT)PhCreateAlloc(sizeof(NETWORK_WHOIS_CONTEXT)); + memset(context, 0, sizeof(NETWORK_WHOIS_CONTEXT)); + + context->RemoteEndpoint = NetworkItem->RemoteEndpoint; + + if (NetworkItem->RemoteEndpoint.Address.Type == PH_IPV4_NETWORK_TYPE) + { + RtlIpv4AddressToString(&NetworkItem->RemoteEndpoint.Address.InAddr, context->IpAddressString); + } + else if (NetworkItem->RemoteEndpoint.Address.Type == PH_IPV6_NETWORK_TYPE) + { + RtlIpv6AddressToString(&NetworkItem->RemoteEndpoint.Address.In6Addr, context->IpAddressString); + } + + if (dialogThread = PhCreateThread(0, NetworkWhoisDialogThreadStart, (PVOID)context)) + { + NtClose(dialogThread); + } +} + +VOID ShowWhoisWindowFromAddress( + _In_ PH_IP_ENDPOINT RemoteEndpoint + ) +{ + HANDLE dialogThread; + PNETWORK_WHOIS_CONTEXT context; + + context = (PNETWORK_WHOIS_CONTEXT)PhCreateAlloc(sizeof(NETWORK_WHOIS_CONTEXT)); + memset(context, 0, sizeof(NETWORK_WHOIS_CONTEXT)); + + context->RemoteEndpoint = RemoteEndpoint; + + if (RemoteEndpoint.Address.Type == PH_IPV4_NETWORK_TYPE) + { + RtlIpv4AddressToString(&RemoteEndpoint.Address.InAddr, context->IpAddressString); + } + else if (RemoteEndpoint.Address.Type == PH_IPV6_NETWORK_TYPE) + { + RtlIpv6AddressToString(&RemoteEndpoint.Address.In6Addr, context->IpAddressString); + } + + if (dialogThread = PhCreateThread(0, NetworkWhoisDialogThreadStart, (PVOID)context)) + { + NtClose(dialogThread); + } } \ No newline at end of file diff --git a/plugins/OnlineChecks/CHANGELOG.txt b/plugins/OnlineChecks/CHANGELOG.txt index 2f8dfe8fe76d..0cd0f495f4f0 100644 --- a/plugins/OnlineChecks/CHANGELOG.txt +++ b/plugins/OnlineChecks/CHANGELOG.txt @@ -1,29 +1,29 @@ -1.8 - * Added VirusTotal process column - * Removed Comodo CAMAS uploader - -1.7 - * Fixed virusscan.jotti.org uploader - -1.6 - * Updated VirusTotal executable limit to 128 MB - -1.5 - * Added CIMA hash checking - * Added file analyzed prompt - -1.4 - * Added upload progress - * Updated UI - -1.3 - * Updated VirusTotal uploader and added hash checking - -1.2 - * Added Comodo Instant Malware Analysis - -1.1 - * Updated VirusTotal uploader - -1.0 - * Initial release +1.8 + * Added VirusTotal process column + * Removed Comodo CAMAS uploader + +1.7 + * Fixed virusscan.jotti.org uploader + +1.6 + * Updated VirusTotal executable limit to 128 MB + +1.5 + * Added CIMA hash checking + * Added file analyzed prompt + +1.4 + * Added upload progress + * Updated UI + +1.3 + * Updated VirusTotal uploader and added hash checking + +1.2 + * Added Comodo Instant Malware Analysis + +1.1 + * Updated VirusTotal uploader + +1.0 + * Initial release diff --git a/plugins/OnlineChecks/OnlineChecks.rc b/plugins/OnlineChecks/OnlineChecks.rc index b1a0e7c346e2..650d108605a9 100644 --- a/plugins/OnlineChecks/OnlineChecks.rc +++ b/plugins/OnlineChecks/OnlineChecks.rc @@ -1,151 +1,151 @@ -// Microsoft Visual C++ generated resource script. -// -#include "resource.h" - -#define APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// -#include "winres.h" -///////////////////////////////////////////////////////////////////////////// -#undef APSTUDIO_READONLY_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -// English (Australia) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENA) -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_AUS -#pragma code_page(1252) - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -1 TEXTINCLUDE -BEGIN - "resource.h\0" -END - -2 TEXTINCLUDE -BEGIN - "#include ""winres.h""\0" -END - -3 TEXTINCLUDE -BEGIN - "\r\n" - "\0" -END - -#endif // APSTUDIO_INVOKED - - -///////////////////////////////////////////////////////////////////////////// -// -// Version -// - -VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,8,0,0 - PRODUCTVERSION 1,8,0,0 - FILEFLAGSMASK 0x3fL -#ifdef _DEBUG - FILEFLAGS 0x1L -#else - FILEFLAGS 0x0L -#endif - FILEOS 0x40004L - FILETYPE 0x2L - FILESUBTYPE 0x0L -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "0c0904b0" - BEGIN - VALUE "CompanyName", "dmex" - VALUE "FileDescription", "Online Checks plugin for Process Hacker" - VALUE "FileVersion", "1.8" - VALUE "InternalName", "ProcessHacker.OnlineChecks" - VALUE "LegalCopyright", "Licensed under the GNU GPL, v3." - VALUE "OriginalFilename", "OnlineChecks.dll" - VALUE "ProductName", "Online Checks plugin for Process Hacker" - VALUE "ProductVersion", "1.8" - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0xc09, 1200 - END -END - - -///////////////////////////////////////////////////////////////////////////// -// -// Dialog -// - -IDD_OPTIONS DIALOGEX 0, 0, 185, 103 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Options" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - CONTROL "Enable VirusTotal scanning",IDC_ENABLE_VIRUSTOTAL, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,7,101,10 - CONTROL "Enable VirusTotal detection highlighting",IDC_ENABLE_IDC_ENABLE_VIRUSTOTAL_HIGHLIGHT, - "Button",BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,7,20,141,10 - PUSHBUTTON "Close",IDCANCEL,129,82,50,14 - CONTROL "Enable detection actions",IDC_CHECK1,"Button",BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,7,34,94,10 - EDITTEXT IDC_EDIT1,91,47,37,14,ES_AUTOHSCROLL | WS_DISABLED - LTEXT "Minimum detection ratio:",IDC_STATIC,8,50,79,8 - COMBOBOX IDC_COMBO1,91,65,88,14,CBS_DROPDOWN | CBS_SORT | WS_DISABLED | WS_VSCROLL | WS_TABSTOP - LTEXT "Minimum detection action:",IDC_STATIC,7,67,84,8 -END - - -///////////////////////////////////////////////////////////////////////////// -// -// DESIGNINFO -// - -#ifdef APSTUDIO_INVOKED -GUIDELINES DESIGNINFO -BEGIN - IDD_OPTIONS, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 179 - TOPMARGIN, 7 - BOTTOMMARGIN, 96 - END -END -#endif // APSTUDIO_INVOKED - - -///////////////////////////////////////////////////////////////////////////// -// -// AFX_DIALOG_LAYOUT -// - -IDD_OPTIONS AFX_DIALOG_LAYOUT -BEGIN - 0 -END - -#endif // English (Australia) resources -///////////////////////////////////////////////////////////////////////////// - - - -#ifndef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// - - -///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED - +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "winres.h" +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (Australia) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENA) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_AUS +#pragma code_page(1252) + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""winres.h""\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,8,0,0 + PRODUCTVERSION 1,8,0,0 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "0c0904b0" + BEGIN + VALUE "CompanyName", "dmex" + VALUE "FileDescription", "Online Checks plugin for Process Hacker" + VALUE "FileVersion", "1.8" + VALUE "InternalName", "ProcessHacker.OnlineChecks" + VALUE "LegalCopyright", "Licensed under the GNU GPL, v3." + VALUE "OriginalFilename", "OnlineChecks.dll" + VALUE "ProductName", "Online Checks plugin for Process Hacker" + VALUE "ProductVersion", "1.8" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0xc09, 1200 + END +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_OPTIONS DIALOGEX 0, 0, 185, 103 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Options" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + CONTROL "Enable VirusTotal scanning",IDC_ENABLE_VIRUSTOTAL, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,7,101,10 + CONTROL "Enable VirusTotal detection highlighting",IDC_ENABLE_IDC_ENABLE_VIRUSTOTAL_HIGHLIGHT, + "Button",BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,7,20,141,10 + PUSHBUTTON "Close",IDCANCEL,129,82,50,14 + CONTROL "Enable detection actions",IDC_CHECK1,"Button",BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,7,34,94,10 + EDITTEXT IDC_EDIT1,91,47,37,14,ES_AUTOHSCROLL | WS_DISABLED + LTEXT "Minimum detection ratio:",IDC_STATIC,8,50,79,8 + COMBOBOX IDC_COMBO1,91,65,88,14,CBS_DROPDOWN | CBS_SORT | WS_DISABLED | WS_VSCROLL | WS_TABSTOP + LTEXT "Minimum detection action:",IDC_STATIC,7,67,84,8 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_OPTIONS, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 179 + TOPMARGIN, 7 + BOTTOMMARGIN, 96 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// AFX_DIALOG_LAYOUT +// + +IDD_OPTIONS AFX_DIALOG_LAYOUT +BEGIN + 0 +END + +#endif // English (Australia) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/plugins/OnlineChecks/OnlineChecks.vcxproj b/plugins/OnlineChecks/OnlineChecks.vcxproj index f5190e231071..9683eec73393 100644 --- a/plugins/OnlineChecks/OnlineChecks.vcxproj +++ b/plugins/OnlineChecks/OnlineChecks.vcxproj @@ -1,101 +1,101 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {79D24223-1122-40A9-BC8F-46A2089FE089} - OnlineChecks - Win32Proj - OnlineChecks - 10.0.15063.0 - - - - DynamicLibrary - Unicode - v141 - - - DynamicLibrary - Unicode - v141 - - - DynamicLibrary - Unicode - v141 - - - DynamicLibrary - Unicode - v141 - - - - - - - - - winhttp.lib;%(AdditionalDependencies) - winhttp.dll;%(DelayLoadDLLs) - - - - - winhttp.lib;%(AdditionalDependencies) - winhttp.dll;%(DelayLoadDLLs) - - - - - winhttp.lib;%(AdditionalDependencies) - winhttp.dll;%(DelayLoadDLLs) - - - - - winhttp.lib;%(AdditionalDependencies) - winhttp.dll;%(DelayLoadDLLs) - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {79D24223-1122-40A9-BC8F-46A2089FE089} + OnlineChecks + Win32Proj + OnlineChecks + 10.0.15063.0 + + + + DynamicLibrary + Unicode + v141 + + + DynamicLibrary + Unicode + v141 + + + DynamicLibrary + Unicode + v141 + + + DynamicLibrary + Unicode + v141 + + + + + + + + + winhttp.lib;%(AdditionalDependencies) + winhttp.dll;%(DelayLoadDLLs) + + + + + winhttp.lib;%(AdditionalDependencies) + winhttp.dll;%(DelayLoadDLLs) + + + + + winhttp.lib;%(AdditionalDependencies) + winhttp.dll;%(DelayLoadDLLs) + + + + + winhttp.lib;%(AdditionalDependencies) + winhttp.dll;%(DelayLoadDLLs) + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/plugins/OnlineChecks/main.c b/plugins/OnlineChecks/main.c index eeb741df6887..9167e0a386db 100644 --- a/plugins/OnlineChecks/main.c +++ b/plugins/OnlineChecks/main.c @@ -1,853 +1,853 @@ -/* - * Process Hacker Online Checks - - * Main Program - * - * Copyright (C) 2010-2013 wj32 - * Copyright (C) 2012-2017 dmex - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include "onlnchk.h" -#include "db.h" - -PPH_PLUGIN PluginInstance; -PH_CALLBACK_REGISTRATION PluginLoadCallbackRegistration; -PH_CALLBACK_REGISTRATION PluginShowOptionsCallbackRegistration; -PH_CALLBACK_REGISTRATION PluginMenuItemCallbackRegistration; -PH_CALLBACK_REGISTRATION MainMenuInitializingCallbackRegistration; -PH_CALLBACK_REGISTRATION ProcessesUpdatedCallbackRegistration; -PH_CALLBACK_REGISTRATION ProcessHighlightingColorCallbackRegistration; -PH_CALLBACK_REGISTRATION ProcessMenuInitializingCallbackRegistration; -PH_CALLBACK_REGISTRATION ModuleMenuInitializingCallbackRegistration; -PH_CALLBACK_REGISTRATION ServiceMenuInitializingCallbackRegistration; -PH_CALLBACK_REGISTRATION TreeNewMessageCallbackRegistration; -PH_CALLBACK_REGISTRATION ProcessTreeNewInitializingCallbackRegistration; -PH_CALLBACK_REGISTRATION ModulesTreeNewInitializingCallbackRegistration; -PH_CALLBACK_REGISTRATION ServiceTreeNewInitializingCallbackRegistration; - -BOOLEAN VirusTotalScanningEnabled = FALSE; -ULONG ProcessesUpdatedCount = 0; -LIST_ENTRY ProcessListHead = { &ProcessListHead, &ProcessListHead }; -PH_QUEUED_LOCK ProcessesListLock = PH_QUEUED_LOCK_INIT; - -VOID ProcessesUpdatedCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ -#ifdef VIRUSTOTAL_API - static ULONG ProcessesUpdatedCount = 0; - PLIST_ENTRY listEntry; - - if (!VirusTotalScanningEnabled) - return; - - ProcessesUpdatedCount++; - - if (ProcessesUpdatedCount < 2) - return; - - listEntry = ProcessListHead.Flink; - - while (listEntry != &ProcessListHead) - { - PPROCESS_EXTENSION extension; - PPH_STRING filePath = NULL; - - extension = CONTAINING_RECORD(listEntry, PROCESS_EXTENSION, ListEntry); - - if (extension->ProcessItem) - { - filePath = extension->ProcessItem->FileName; - } - else if (extension->ModuleItem) - { - filePath = extension->ModuleItem->FileName; - } - else if (extension->ServiceItem) - { - if (extension->FilePath) - { - filePath = extension->FilePath; - } - else - { - PPH_STRING serviceFileName = NULL; - PPH_STRING serviceBinaryPath = NULL; - - if (NT_SUCCESS(QueryServiceFileName( - &extension->ServiceItem->Name->sr, - &serviceFileName, - &serviceBinaryPath - ))) - { - PhMoveReference(&extension->FilePath, serviceFileName); - if (serviceBinaryPath) PhDereferenceObject(serviceBinaryPath); - } - - filePath = extension->FilePath; - } - } - - if (!PhIsNullOrEmptyString(filePath)) - { - if (!extension->ResultValid) - { - PPROCESS_DB_OBJECT object; - - if (object = FindProcessDbObject(&filePath->sr)) - { - extension->Stage1 = TRUE; - extension->ResultValid = TRUE; - - extension->Positives = object->Positives; - PhSwapReference(&extension->VirusTotalResult, object->Result); - } - } - - if (!extension->Stage1) - { - if (!VirusTotalGetCachedResult(filePath)) - { - VirusTotalAddCacheResult(filePath, extension); - } - - extension->Stage1 = TRUE; - } - } - - listEntry = listEntry->Flink; - } -#endif -} - -VOID NTAPI LoadCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - if (VirusTotalScanningEnabled = !!PhGetIntegerSetting(SETTING_NAME_VIRUSTOTAL_SCAN_ENABLED)) - { - InitializeProcessDb(); - InitializeVirusTotalProcessMonitor(); - } -} - -VOID NTAPI ShowOptionsCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - ShowOptionsDialog((HWND)Parameter); -} - -VOID NTAPI MenuItemCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - PPH_PLUGIN_MENU_ITEM menuItem = Parameter; - - switch (menuItem->Id) - { - case ENABLE_SERVICE_VIRUSTOTAL: - { - ULONG scanningEnabled = !VirusTotalScanningEnabled; - - PhSetIntegerSetting(SETTING_NAME_VIRUSTOTAL_SCAN_ENABLED, scanningEnabled); - - if (VirusTotalScanningEnabled != scanningEnabled) - { - INT result = IDOK; - TASKDIALOGCONFIG config; - - memset(&config, 0, sizeof(TASKDIALOGCONFIG)); - config.cbSize = sizeof(TASKDIALOGCONFIG); - config.dwFlags = TDF_USE_HICON_MAIN | TDF_ALLOW_DIALOG_CANCELLATION; - config.dwCommonButtons = TDCBF_YES_BUTTON | TDCBF_NO_BUTTON; - config.hwndParent = menuItem->OwnerWindow; - config.hMainIcon = PhLoadIcon( - NtCurrentPeb()->ImageBaseAddress, - MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER), - PH_LOAD_ICON_SIZE_LARGE, - GetSystemMetrics(SM_CXICON), - GetSystemMetrics(SM_CYICON) - ); - config.cxWidth = 180; - config.pszWindowTitle = L"Process Hacker - VirusTotal"; - config.pszMainInstruction = L"VirusTotal scanning requires a restart of Process Hacker."; - config.pszContent = L"Do you want to restart Process Hacker now?"; - - if (SUCCEEDED(TaskDialogIndirect(&config, &result, NULL, NULL)) && result == IDYES) - { - ProcessHacker_PrepareForEarlyShutdown(PhMainWndHandle); - PhShellProcessHacker( - PhMainWndHandle, - L"-v", - SW_SHOW, - 0, - PH_SHELL_APP_PROPAGATE_PARAMETERS | PH_SHELL_APP_PROPAGATE_PARAMETERS_IGNORE_VISIBILITY, - 0, - NULL - ); - ProcessHacker_Destroy(PhMainWndHandle); - } - - DestroyIcon(config.hMainIcon); - } - } - break; - case MENUITEM_VIRUSTOTAL_UPLOAD: - UploadToOnlineService(menuItem->Context, MENUITEM_VIRUSTOTAL_UPLOAD); - break; - case MENUITEM_JOTTI_UPLOAD: - UploadToOnlineService(menuItem->Context, MENUITEM_JOTTI_UPLOAD); - break; - case MENUITEM_VIRUSTOTAL_UPLOAD_FILE: - { - static PH_FILETYPE_FILTER filters[] = - { - { L"All files (*.*)", L"*.*" } - }; - PVOID fileDialog; - PPH_STRING fileName; - - fileDialog = PhCreateOpenFileDialog(); - PhSetFileDialogFilter(fileDialog, filters, sizeof(filters) / sizeof(PH_FILETYPE_FILTER)); - - if (PhShowFileDialog(menuItem->Context, fileDialog)) - { - fileName = PH_AUTO(PhGetFileDialogFileName(fileDialog)); - - UploadToOnlineService(fileName, MENUITEM_VIRUSTOTAL_UPLOAD); - } - - PhFreeFileDialog(fileDialog); - } - break; - } -} - -VOID NTAPI MainMenuInitializingCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - PPH_EMENU_ITEM onlineMenuItem; - PPH_EMENU_ITEM enableMenuItem; - PPH_PLUGIN_MENU_INFORMATION menuInfo = Parameter; - - if (menuInfo->u.MainMenu.SubMenuIndex != PH_MENU_ITEM_LOCATION_TOOLS) - return; - - onlineMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, 0, L"Online Checks", NULL); - PhInsertEMenuItem(onlineMenuItem, enableMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, ENABLE_SERVICE_VIRUSTOTAL, L"Enable VirusTotal scanning", NULL), -1); - PhInsertEMenuItem(onlineMenuItem, PhPluginCreateEMenuItem(PluginInstance, PH_EMENU_SEPARATOR, 0, NULL, NULL), -1); - PhInsertEMenuItem(onlineMenuItem, PhPluginCreateEMenuItem(PluginInstance, 0, MENUITEM_VIRUSTOTAL_UPLOAD_FILE, L"Upload file to VirusTotal...", NULL), -1); - PhInsertEMenuItem(onlineMenuItem, PhPluginCreateEMenuItem(PluginInstance, 0, MENUITEM_VIRUSTOTAL_QUEUE, L"Upload unknown files to VirusTotal...", NULL), -1); - PhInsertEMenuItem(menuInfo->Menu, onlineMenuItem, -1); - - if (VirusTotalScanningEnabled) - enableMenuItem->Flags |= PH_EMENU_CHECKED; -} - -PPH_EMENU_ITEM CreateSendToMenu( - _In_ PPH_EMENU_ITEM Parent, - _In_ PPH_STRING FileName - ) -{ - PPH_EMENU_ITEM sendToMenu; - PPH_EMENU_ITEM menuItem; - ULONG insertIndex; - - sendToMenu = PhPluginCreateEMenuItem(PluginInstance, 0, 0, L"Send to", NULL); - PhInsertEMenuItem(sendToMenu, PhPluginCreateEMenuItem(PluginInstance, 0, MENUITEM_VIRUSTOTAL_UPLOAD, L"virustotal.com", FileName), -1); - PhInsertEMenuItem(sendToMenu, PhPluginCreateEMenuItem(PluginInstance, 0, MENUITEM_JOTTI_UPLOAD, L"virusscan.jotti.org", FileName), -1); - - if (menuItem = PhFindEMenuItem(Parent, PH_EMENU_FIND_STARTSWITH, L"Search online", 0)) - { - insertIndex = PhIndexOfEMenuItem(Parent, menuItem); - PhInsertEMenuItem(Parent, sendToMenu, insertIndex + 1); - PhInsertEMenuItem(Parent, PhPluginCreateEMenuItem(PluginInstance, PH_EMENU_SEPARATOR, 0, NULL, NULL), insertIndex + 2); - } - else - { - PhInsertEMenuItem(Parent, PhPluginCreateEMenuItem(PluginInstance, PH_EMENU_SEPARATOR, 0, NULL, NULL), -1); - PhInsertEMenuItem(Parent, sendToMenu, -1); - } - - return sendToMenu; -} - -VOID NTAPI ProcessMenuInitializingCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - PPH_PLUGIN_MENU_INFORMATION menuInfo = Parameter; - PPH_PROCESS_ITEM processItem; - PPH_EMENU_ITEM sendToMenu; - - if (menuInfo->u.Process.NumberOfProcesses == 1) - processItem = menuInfo->u.Process.Processes[0]; - else - processItem = NULL; - - sendToMenu = CreateSendToMenu(menuInfo->Menu, processItem ? processItem->FileName : NULL); - - // Only enable the Send To menu if there is exactly one process selected and it has a file name. - if (!processItem || !processItem->FileName) - { - sendToMenu->Flags |= PH_EMENU_DISABLED; - } -} - -VOID NTAPI ModuleMenuInitializingCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - PPH_PLUGIN_MENU_INFORMATION menuInfo = Parameter; - PPH_MODULE_ITEM moduleItem; - PPH_EMENU_ITEM sendToMenu; - - if (menuInfo->u.Module.NumberOfModules == 1) - moduleItem = menuInfo->u.Module.Modules[0]; - else - moduleItem = NULL; - - sendToMenu = CreateSendToMenu(menuInfo->Menu, moduleItem ? moduleItem->FileName : NULL); - - if (!moduleItem) - { - sendToMenu->Flags |= PH_EMENU_DISABLED; - } -} - -VOID NTAPI ServiceMenuInitializingCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - PPH_PLUGIN_MENU_INFORMATION menuInfo = Parameter; - PPH_SERVICE_ITEM serviceItem; - PPH_EMENU_ITEM sendToMenu; - PPH_STRING serviceFileName = NULL; - PPH_STRING serviceBinaryPath = NULL; - - if (menuInfo->u.Service.NumberOfServices == 1) - serviceItem = menuInfo->u.Service.Services[0]; - else - serviceItem = NULL; - - QueryServiceFileName( - &serviceItem->Name->sr, - &serviceFileName, - &serviceBinaryPath - ); - - if (serviceBinaryPath) PhDereferenceObject(serviceBinaryPath); - - // TODO: Possible serviceFileName string memory leak. - sendToMenu = CreateSendToMenu(menuInfo->Menu, serviceFileName ? serviceFileName : NULL); - - if (!serviceItem || !serviceFileName) - { - sendToMenu->Flags |= PH_EMENU_DISABLED; - } -} - -VOID ProcessHighlightingColorCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - PPH_PLUGIN_GET_HIGHLIGHTING_COLOR getHighlightingColor = Parameter; - PPH_PROCESS_ITEM processItem = (PPH_PROCESS_ITEM)getHighlightingColor->Parameter; - //PPROCESS_DB_OBJECT object; - - if (getHighlightingColor->Handled) - return; - - //if (!PhGetIntegerSetting(SETTING_NAME_VIRUSTOTAL_HIGHLIGHT_DETECTIONS)) - // return; - - //LockProcessDb(); - - //if (PhIsNullOrEmptyString(processItem->FileName)) - // return; - - //if ((object = FindProcessDbObject(&processItem->FileName->sr)) && object->Positives) - //{ - // getHighlightingColor->BackColor = RGB(255, 0, 0); - // getHighlightingColor->Cache = TRUE; - // getHighlightingColor->Handled = TRUE; - //} - - //UnlockProcessDb(); -} - -LONG NTAPI VirusTotalProcessNodeSortFunction( - _In_ PVOID Node1, - _In_ PVOID Node2, - _In_ ULONG SubId, - _In_ PVOID Context - ) -{ - PPH_PROCESS_NODE node1 = Node1; - PPH_PROCESS_NODE node2 = Node2; - PPROCESS_EXTENSION extension1 = PhPluginGetObjectExtension(PluginInstance, node1->ProcessItem, EmProcessItemType); - PPROCESS_EXTENSION extension2 = PhPluginGetObjectExtension(PluginInstance, node2->ProcessItem, EmProcessItemType); - - return PhCompareStringWithNull(extension1->VirusTotalResult, extension2->VirusTotalResult, TRUE); -} - -LONG NTAPI VirusTotalModuleNodeSortFunction( - _In_ PVOID Node1, - _In_ PVOID Node2, - _In_ ULONG SubId, - _In_ PVOID Context - ) -{ - PPH_MODULE_NODE node1 = Node1; - PPH_MODULE_NODE node2 = Node2; - PPROCESS_EXTENSION extension1 = PhPluginGetObjectExtension(PluginInstance, node1->ModuleItem, EmModuleItemType); - PPROCESS_EXTENSION extension2 = PhPluginGetObjectExtension(PluginInstance, node2->ModuleItem, EmModuleItemType); - - return PhCompareStringWithNull(extension1->VirusTotalResult, extension2->VirusTotalResult, TRUE); -} - -LONG NTAPI VirusTotalServiceNodeSortFunction( - _In_ PVOID Node1, - _In_ PVOID Node2, - _In_ ULONG SubId, - _In_ PVOID Context - ) -{ - PPH_SERVICE_NODE node1 = Node1; - PPH_SERVICE_NODE node2 = Node2; - PPROCESS_EXTENSION extension1 = PhPluginGetObjectExtension(PluginInstance, node1->ServiceItem, EmServiceItemType); - PPROCESS_EXTENSION extension2 = PhPluginGetObjectExtension(PluginInstance, node2->ServiceItem, EmServiceItemType); - - return PhCompareStringWithNull(extension1->VirusTotalResult, extension2->VirusTotalResult, TRUE); -} - -VOID NTAPI ProcessTreeNewInitializingCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - PPH_PLUGIN_TREENEW_INFORMATION info = Parameter; - PH_TREENEW_COLUMN column; - - memset(&column, 0, sizeof(PH_TREENEW_COLUMN)); - column.Text = L"VirusTotal"; - column.Width = 140; - column.Alignment = PH_ALIGN_CENTER; - column.CustomDraw = TRUE; - column.Context = info->TreeNewHandle; // Context - - PhPluginAddTreeNewColumn(PluginInstance, info->CmData, &column, COLUMN_ID_VIUSTOTAL_PROCESS, NULL, VirusTotalProcessNodeSortFunction); -} - -VOID NTAPI ModuleTreeNewInitializingCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - PPH_PLUGIN_TREENEW_INFORMATION info = Parameter; - PH_TREENEW_COLUMN column; - - memset(&column, 0, sizeof(PH_TREENEW_COLUMN)); - column.Text = L"VirusTotal"; - column.Width = 140; - column.Alignment = PH_ALIGN_CENTER; - column.CustomDraw = TRUE; - column.Context = info->TreeNewHandle; // Context - - PhPluginAddTreeNewColumn(PluginInstance, info->CmData, &column, COLUMN_ID_VIUSTOTAL_MODULE, NULL, VirusTotalModuleNodeSortFunction); -} - -VOID NTAPI ServiceTreeNewInitializingCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - PPH_PLUGIN_TREENEW_INFORMATION info = Parameter; - PH_TREENEW_COLUMN column; - - memset(&column, 0, sizeof(PH_TREENEW_COLUMN)); - column.Text = L"VirusTotal"; - column.Width = 140; - column.Alignment = PH_ALIGN_CENTER; - column.CustomDraw = TRUE; - column.Context = info->TreeNewHandle; // Context - - PhPluginAddTreeNewColumn(PluginInstance, info->CmData, &column, COLUMN_ID_VIUSTOTAL_SERVICE, NULL, VirusTotalServiceNodeSortFunction); -} - -VOID NTAPI TreeNewMessageCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - PPH_PLUGIN_TREENEW_MESSAGE message = Parameter; - - switch (message->Message) - { - case TreeNewGetCellText: - { - PPH_TREENEW_GET_CELL_TEXT getCellText = message->Parameter1; - - switch (message->SubId) - { - case COLUMN_ID_VIUSTOTAL_PROCESS: - { - PPH_PROCESS_NODE processNode = (PPH_PROCESS_NODE)getCellText->Node; - PPROCESS_EXTENSION extension = PhPluginGetObjectExtension(PluginInstance, processNode->ProcessItem, EmProcessItemType); - - getCellText->Text = PhGetStringRef(extension->VirusTotalResult); - } - break; - case COLUMN_ID_VIUSTOTAL_MODULE: - { - PPH_MODULE_NODE moduleNode = (PPH_MODULE_NODE)getCellText->Node; - PPROCESS_EXTENSION extension = PhPluginGetObjectExtension(PluginInstance, moduleNode->ModuleItem, EmModuleItemType); - - getCellText->Text = PhGetStringRef(extension->VirusTotalResult); - } - break; - case COLUMN_ID_VIUSTOTAL_SERVICE: - { - PPH_SERVICE_NODE serviceNode = (PPH_SERVICE_NODE)getCellText->Node; - PPROCESS_EXTENSION extension = PhPluginGetObjectExtension(PluginInstance, serviceNode->ServiceItem, EmServiceItemType); - - getCellText->Text = PhGetStringRef(extension->VirusTotalResult); - } - break; - } - } - break; - case TreeNewCustomDraw: - { - PPH_TREENEW_CUSTOM_DRAW customDraw = message->Parameter1; - PPROCESS_EXTENSION extension = NULL; - PH_STRINGREF text; - - if (!VirusTotalScanningEnabled) - { - static PH_STRINGREF disabledText = PH_STRINGREF_INIT(L"Scanning disabled"); - - DrawText( - customDraw->Dc, - disabledText.Buffer, - (ULONG)disabledText.Length / 2, - &customDraw->CellRect, - DT_CENTER | DT_VCENTER | DT_END_ELLIPSIS | DT_SINGLELINE - ); - - return; - } - - switch (message->SubId) - { - case COLUMN_ID_VIUSTOTAL_PROCESS: - { - PPH_PROCESS_NODE processNode = (PPH_PROCESS_NODE)customDraw->Node; - - extension = PhPluginGetObjectExtension(PluginInstance, processNode->ProcessItem, EmProcessItemType); - } - break; - case COLUMN_ID_VIUSTOTAL_MODULE: - { - PPH_MODULE_NODE moduleNode = (PPH_MODULE_NODE)customDraw->Node; - - extension = PhPluginGetObjectExtension(PluginInstance, moduleNode->ModuleItem, EmModuleItemType); - } - break; - case COLUMN_ID_VIUSTOTAL_SERVICE: - { - PPH_SERVICE_NODE serviceNode = (PPH_SERVICE_NODE)customDraw->Node; - - extension = PhPluginGetObjectExtension(PluginInstance, serviceNode->ServiceItem, EmServiceItemType); - } - break; - } - - if (!extension) - break; - - text = PhGetStringRef(extension->VirusTotalResult); - DrawText( - customDraw->Dc, - text.Buffer, - (ULONG)text.Length / 2, - &customDraw->CellRect, - DT_CENTER | DT_VCENTER | DT_END_ELLIPSIS | DT_SINGLELINE - ); - } - break; - } -} - -VOID NTAPI ProcessItemCreateCallback( - _In_ PVOID Object, - _In_ PH_EM_OBJECT_TYPE ObjectType, - _In_ PVOID Extension - ) -{ - PPH_PROCESS_ITEM processItem = Object; - PPROCESS_EXTENSION extension = Extension; - - memset(extension, 0, sizeof(PROCESS_EXTENSION)); - - extension->ProcessItem = processItem; - extension->VirusTotalResult = PhReferenceEmptyString(); - - PhAcquireQueuedLockExclusive(&ProcessesListLock); - InsertTailList(&ProcessListHead, &extension->ListEntry); - PhReleaseQueuedLockExclusive(&ProcessesListLock); -} - -VOID NTAPI ProcessItemDeleteCallback( - _In_ PVOID Object, - _In_ PH_EM_OBJECT_TYPE ObjectType, - _In_ PVOID Extension - ) -{ - PPH_PROCESS_ITEM processItem = Object; - PPROCESS_EXTENSION extension = Extension; - - PhClearReference(&extension->VirusTotalResult); - - PhAcquireQueuedLockExclusive(&ProcessesListLock); - RemoveEntryList(&extension->ListEntry); - PhReleaseQueuedLockExclusive(&ProcessesListLock); -} - -VOID NTAPI ModuleItemCreateCallback( - _In_ PVOID Object, - _In_ PH_EM_OBJECT_TYPE ObjectType, - _In_ PVOID Extension - ) -{ - PPH_MODULE_ITEM moduleItem = Object; - PPROCESS_EXTENSION extension = Extension; - - memset(extension, 0, sizeof(PROCESS_EXTENSION)); - - extension->ModuleItem = moduleItem; - extension->VirusTotalResult = PhReferenceEmptyString(); - - PhAcquireQueuedLockExclusive(&ProcessesListLock); - InsertTailList(&ProcessListHead, &extension->ListEntry); - PhReleaseQueuedLockExclusive(&ProcessesListLock); -} - -VOID NTAPI ModuleItemDeleteCallback( - _In_ PVOID Object, - _In_ PH_EM_OBJECT_TYPE ObjectType, - _In_ PVOID Extension - ) -{ - PPH_MODULE_ITEM processItem = Object; - PPROCESS_EXTENSION extension = Extension; - - PhClearReference(&extension->VirusTotalResult); - - PhAcquireQueuedLockExclusive(&ProcessesListLock); - RemoveEntryList(&extension->ListEntry); - PhReleaseQueuedLockExclusive(&ProcessesListLock); -} - -VOID NTAPI ServiceItemCreateCallback( - _In_ PVOID Object, - _In_ PH_EM_OBJECT_TYPE ObjectType, - _In_ PVOID Extension - ) -{ - PPH_SERVICE_ITEM serviceItem = Object; - PPROCESS_EXTENSION extension = Extension; - - memset(extension, 0, sizeof(PROCESS_EXTENSION)); - - extension->ServiceItem = serviceItem; - extension->VirusTotalResult = PhReferenceEmptyString(); - - PhAcquireQueuedLockExclusive(&ProcessesListLock); - InsertTailList(&ProcessListHead, &extension->ListEntry); - PhReleaseQueuedLockExclusive(&ProcessesListLock); -} - -VOID NTAPI ServiceItemDeleteCallback( - _In_ PVOID Object, - _In_ PH_EM_OBJECT_TYPE ObjectType, - _In_ PVOID Extension - ) -{ - PPH_SERVICE_ITEM serviceItem = Object; - PPROCESS_EXTENSION extension = Extension; - - PhClearReference(&extension->VirusTotalResult); - - PhAcquireQueuedLockExclusive(&ProcessesListLock); - RemoveEntryList(&extension->ListEntry); - PhReleaseQueuedLockExclusive(&ProcessesListLock); -} - -LOGICAL DllMain( - _In_ HINSTANCE Instance, - _In_ ULONG Reason, - _Reserved_ PVOID Reserved - ) -{ - switch (Reason) - { - case DLL_PROCESS_ATTACH: - { - PPH_PLUGIN_INFORMATION info; - PH_SETTING_CREATE settings[] = - { - { IntegerSettingType, SETTING_NAME_VIRUSTOTAL_SCAN_ENABLED, L"0" }, - { IntegerSettingType, SETTING_NAME_VIRUSTOTAL_HIGHLIGHT_DETECTIONS, L"0" } - }; - - PluginInstance = PhRegisterPlugin(PLUGIN_NAME, Instance, &info); - - if (!PluginInstance) - return FALSE; - - info->DisplayName = L"Online Checks"; - info->Author = L"dmex, wj32"; - info->Description = L"Allows files to be checked with online services."; - info->Url = L"https://wj32.org/processhacker/forums/viewtopic.php?t=1118"; - info->HasOptions = TRUE; - - PhRegisterCallback( - PhGetPluginCallback(PluginInstance, PluginCallbackLoad), - LoadCallback, - NULL, - &PluginLoadCallbackRegistration - ); - PhRegisterCallback( - PhGetPluginCallback(PluginInstance, PluginCallbackShowOptions), - ShowOptionsCallback, - NULL, - &PluginShowOptionsCallbackRegistration - ); - PhRegisterCallback( - PhGetPluginCallback(PluginInstance, PluginCallbackMenuItem), - MenuItemCallback, - NULL, - &PluginMenuItemCallbackRegistration - ); - PhRegisterCallback( - PhGetGeneralCallback(GeneralCallbackMainMenuInitializing), - MainMenuInitializingCallback, - NULL, - &MainMenuInitializingCallbackRegistration - ); - PhRegisterCallback( - PhGetGeneralCallback(GeneralCallbackProcessMenuInitializing), - ProcessMenuInitializingCallback, - NULL, - &ProcessMenuInitializingCallbackRegistration - ); - PhRegisterCallback( - PhGetGeneralCallback(GeneralCallbackModuleMenuInitializing), - ModuleMenuInitializingCallback, - NULL, - &ModuleMenuInitializingCallbackRegistration - ); - PhRegisterCallback( - PhGetGeneralCallback(GeneralCallbackServiceMenuInitializing), - ServiceMenuInitializingCallback, - NULL, - &ServiceMenuInitializingCallbackRegistration - ); - - PhRegisterCallback( - PhGetGeneralCallback(GeneralCallbackProcessesUpdated), - ProcessesUpdatedCallback, - NULL, - &ProcessesUpdatedCallbackRegistration - ); - - PhRegisterCallback( - PhGetGeneralCallback(GeneralCallbackGetProcessHighlightingColor), - ProcessHighlightingColorCallback, - NULL, - &ProcessHighlightingColorCallbackRegistration - ); - - PhRegisterCallback( - PhGetGeneralCallback(GeneralCallbackProcessTreeNewInitializing), - ProcessTreeNewInitializingCallback, - NULL, - &ProcessTreeNewInitializingCallbackRegistration - ); - PhRegisterCallback( - PhGetGeneralCallback(GeneralCallbackModuleTreeNewInitializing), - ModuleTreeNewInitializingCallback, - NULL, - &ModulesTreeNewInitializingCallbackRegistration - ); - PhRegisterCallback( - PhGetGeneralCallback(GeneralCallbackServiceTreeNewInitializing), - ServiceTreeNewInitializingCallback, - NULL, - &ServiceTreeNewInitializingCallbackRegistration - ); - - PhRegisterCallback( - PhGetPluginCallback(PluginInstance, PluginCallbackTreeNewMessage), - TreeNewMessageCallback, - NULL, - &TreeNewMessageCallbackRegistration - ); - - PhPluginSetObjectExtension( - PluginInstance, - EmProcessItemType, - sizeof(PROCESS_EXTENSION), - ProcessItemCreateCallback, - ProcessItemDeleteCallback - ); - - PhPluginSetObjectExtension( - PluginInstance, - EmModuleItemType, - sizeof(PROCESS_EXTENSION), - ModuleItemCreateCallback, - ModuleItemDeleteCallback - ); - - PhPluginSetObjectExtension( - PluginInstance, - EmServiceItemType, - sizeof(PROCESS_EXTENSION), - ServiceItemCreateCallback, - ServiceItemDeleteCallback - ); - - PhAddSettings(settings, ARRAYSIZE(settings)); - } - break; - } - - return TRUE; +/* + * Process Hacker Online Checks - + * Main Program + * + * Copyright (C) 2010-2013 wj32 + * Copyright (C) 2012-2017 dmex + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include "onlnchk.h" +#include "db.h" + +PPH_PLUGIN PluginInstance; +PH_CALLBACK_REGISTRATION PluginLoadCallbackRegistration; +PH_CALLBACK_REGISTRATION PluginShowOptionsCallbackRegistration; +PH_CALLBACK_REGISTRATION PluginMenuItemCallbackRegistration; +PH_CALLBACK_REGISTRATION MainMenuInitializingCallbackRegistration; +PH_CALLBACK_REGISTRATION ProcessesUpdatedCallbackRegistration; +PH_CALLBACK_REGISTRATION ProcessHighlightingColorCallbackRegistration; +PH_CALLBACK_REGISTRATION ProcessMenuInitializingCallbackRegistration; +PH_CALLBACK_REGISTRATION ModuleMenuInitializingCallbackRegistration; +PH_CALLBACK_REGISTRATION ServiceMenuInitializingCallbackRegistration; +PH_CALLBACK_REGISTRATION TreeNewMessageCallbackRegistration; +PH_CALLBACK_REGISTRATION ProcessTreeNewInitializingCallbackRegistration; +PH_CALLBACK_REGISTRATION ModulesTreeNewInitializingCallbackRegistration; +PH_CALLBACK_REGISTRATION ServiceTreeNewInitializingCallbackRegistration; + +BOOLEAN VirusTotalScanningEnabled = FALSE; +ULONG ProcessesUpdatedCount = 0; +LIST_ENTRY ProcessListHead = { &ProcessListHead, &ProcessListHead }; +PH_QUEUED_LOCK ProcessesListLock = PH_QUEUED_LOCK_INIT; + +VOID ProcessesUpdatedCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ +#ifdef VIRUSTOTAL_API + static ULONG ProcessesUpdatedCount = 0; + PLIST_ENTRY listEntry; + + if (!VirusTotalScanningEnabled) + return; + + ProcessesUpdatedCount++; + + if (ProcessesUpdatedCount < 2) + return; + + listEntry = ProcessListHead.Flink; + + while (listEntry != &ProcessListHead) + { + PPROCESS_EXTENSION extension; + PPH_STRING filePath = NULL; + + extension = CONTAINING_RECORD(listEntry, PROCESS_EXTENSION, ListEntry); + + if (extension->ProcessItem) + { + filePath = extension->ProcessItem->FileName; + } + else if (extension->ModuleItem) + { + filePath = extension->ModuleItem->FileName; + } + else if (extension->ServiceItem) + { + if (extension->FilePath) + { + filePath = extension->FilePath; + } + else + { + PPH_STRING serviceFileName = NULL; + PPH_STRING serviceBinaryPath = NULL; + + if (NT_SUCCESS(QueryServiceFileName( + &extension->ServiceItem->Name->sr, + &serviceFileName, + &serviceBinaryPath + ))) + { + PhMoveReference(&extension->FilePath, serviceFileName); + if (serviceBinaryPath) PhDereferenceObject(serviceBinaryPath); + } + + filePath = extension->FilePath; + } + } + + if (!PhIsNullOrEmptyString(filePath)) + { + if (!extension->ResultValid) + { + PPROCESS_DB_OBJECT object; + + if (object = FindProcessDbObject(&filePath->sr)) + { + extension->Stage1 = TRUE; + extension->ResultValid = TRUE; + + extension->Positives = object->Positives; + PhSwapReference(&extension->VirusTotalResult, object->Result); + } + } + + if (!extension->Stage1) + { + if (!VirusTotalGetCachedResult(filePath)) + { + VirusTotalAddCacheResult(filePath, extension); + } + + extension->Stage1 = TRUE; + } + } + + listEntry = listEntry->Flink; + } +#endif +} + +VOID NTAPI LoadCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + if (VirusTotalScanningEnabled = !!PhGetIntegerSetting(SETTING_NAME_VIRUSTOTAL_SCAN_ENABLED)) + { + InitializeProcessDb(); + InitializeVirusTotalProcessMonitor(); + } +} + +VOID NTAPI ShowOptionsCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + ShowOptionsDialog((HWND)Parameter); +} + +VOID NTAPI MenuItemCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + PPH_PLUGIN_MENU_ITEM menuItem = Parameter; + + switch (menuItem->Id) + { + case ENABLE_SERVICE_VIRUSTOTAL: + { + ULONG scanningEnabled = !VirusTotalScanningEnabled; + + PhSetIntegerSetting(SETTING_NAME_VIRUSTOTAL_SCAN_ENABLED, scanningEnabled); + + if (VirusTotalScanningEnabled != scanningEnabled) + { + INT result = IDOK; + TASKDIALOGCONFIG config; + + memset(&config, 0, sizeof(TASKDIALOGCONFIG)); + config.cbSize = sizeof(TASKDIALOGCONFIG); + config.dwFlags = TDF_USE_HICON_MAIN | TDF_ALLOW_DIALOG_CANCELLATION; + config.dwCommonButtons = TDCBF_YES_BUTTON | TDCBF_NO_BUTTON; + config.hwndParent = menuItem->OwnerWindow; + config.hMainIcon = PhLoadIcon( + NtCurrentPeb()->ImageBaseAddress, + MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER), + PH_LOAD_ICON_SIZE_LARGE, + GetSystemMetrics(SM_CXICON), + GetSystemMetrics(SM_CYICON) + ); + config.cxWidth = 180; + config.pszWindowTitle = L"Process Hacker - VirusTotal"; + config.pszMainInstruction = L"VirusTotal scanning requires a restart of Process Hacker."; + config.pszContent = L"Do you want to restart Process Hacker now?"; + + if (SUCCEEDED(TaskDialogIndirect(&config, &result, NULL, NULL)) && result == IDYES) + { + ProcessHacker_PrepareForEarlyShutdown(PhMainWndHandle); + PhShellProcessHacker( + PhMainWndHandle, + L"-v", + SW_SHOW, + 0, + PH_SHELL_APP_PROPAGATE_PARAMETERS | PH_SHELL_APP_PROPAGATE_PARAMETERS_IGNORE_VISIBILITY, + 0, + NULL + ); + ProcessHacker_Destroy(PhMainWndHandle); + } + + DestroyIcon(config.hMainIcon); + } + } + break; + case MENUITEM_VIRUSTOTAL_UPLOAD: + UploadToOnlineService(menuItem->Context, MENUITEM_VIRUSTOTAL_UPLOAD); + break; + case MENUITEM_JOTTI_UPLOAD: + UploadToOnlineService(menuItem->Context, MENUITEM_JOTTI_UPLOAD); + break; + case MENUITEM_VIRUSTOTAL_UPLOAD_FILE: + { + static PH_FILETYPE_FILTER filters[] = + { + { L"All files (*.*)", L"*.*" } + }; + PVOID fileDialog; + PPH_STRING fileName; + + fileDialog = PhCreateOpenFileDialog(); + PhSetFileDialogFilter(fileDialog, filters, sizeof(filters) / sizeof(PH_FILETYPE_FILTER)); + + if (PhShowFileDialog(menuItem->Context, fileDialog)) + { + fileName = PH_AUTO(PhGetFileDialogFileName(fileDialog)); + + UploadToOnlineService(fileName, MENUITEM_VIRUSTOTAL_UPLOAD); + } + + PhFreeFileDialog(fileDialog); + } + break; + } +} + +VOID NTAPI MainMenuInitializingCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + PPH_EMENU_ITEM onlineMenuItem; + PPH_EMENU_ITEM enableMenuItem; + PPH_PLUGIN_MENU_INFORMATION menuInfo = Parameter; + + if (menuInfo->u.MainMenu.SubMenuIndex != PH_MENU_ITEM_LOCATION_TOOLS) + return; + + onlineMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, 0, L"Online Checks", NULL); + PhInsertEMenuItem(onlineMenuItem, enableMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, ENABLE_SERVICE_VIRUSTOTAL, L"Enable VirusTotal scanning", NULL), -1); + PhInsertEMenuItem(onlineMenuItem, PhPluginCreateEMenuItem(PluginInstance, PH_EMENU_SEPARATOR, 0, NULL, NULL), -1); + PhInsertEMenuItem(onlineMenuItem, PhPluginCreateEMenuItem(PluginInstance, 0, MENUITEM_VIRUSTOTAL_UPLOAD_FILE, L"Upload file to VirusTotal...", NULL), -1); + PhInsertEMenuItem(onlineMenuItem, PhPluginCreateEMenuItem(PluginInstance, 0, MENUITEM_VIRUSTOTAL_QUEUE, L"Upload unknown files to VirusTotal...", NULL), -1); + PhInsertEMenuItem(menuInfo->Menu, onlineMenuItem, -1); + + if (VirusTotalScanningEnabled) + enableMenuItem->Flags |= PH_EMENU_CHECKED; +} + +PPH_EMENU_ITEM CreateSendToMenu( + _In_ PPH_EMENU_ITEM Parent, + _In_ PPH_STRING FileName + ) +{ + PPH_EMENU_ITEM sendToMenu; + PPH_EMENU_ITEM menuItem; + ULONG insertIndex; + + sendToMenu = PhPluginCreateEMenuItem(PluginInstance, 0, 0, L"Send to", NULL); + PhInsertEMenuItem(sendToMenu, PhPluginCreateEMenuItem(PluginInstance, 0, MENUITEM_VIRUSTOTAL_UPLOAD, L"virustotal.com", FileName), -1); + PhInsertEMenuItem(sendToMenu, PhPluginCreateEMenuItem(PluginInstance, 0, MENUITEM_JOTTI_UPLOAD, L"virusscan.jotti.org", FileName), -1); + + if (menuItem = PhFindEMenuItem(Parent, PH_EMENU_FIND_STARTSWITH, L"Search online", 0)) + { + insertIndex = PhIndexOfEMenuItem(Parent, menuItem); + PhInsertEMenuItem(Parent, sendToMenu, insertIndex + 1); + PhInsertEMenuItem(Parent, PhPluginCreateEMenuItem(PluginInstance, PH_EMENU_SEPARATOR, 0, NULL, NULL), insertIndex + 2); + } + else + { + PhInsertEMenuItem(Parent, PhPluginCreateEMenuItem(PluginInstance, PH_EMENU_SEPARATOR, 0, NULL, NULL), -1); + PhInsertEMenuItem(Parent, sendToMenu, -1); + } + + return sendToMenu; +} + +VOID NTAPI ProcessMenuInitializingCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + PPH_PLUGIN_MENU_INFORMATION menuInfo = Parameter; + PPH_PROCESS_ITEM processItem; + PPH_EMENU_ITEM sendToMenu; + + if (menuInfo->u.Process.NumberOfProcesses == 1) + processItem = menuInfo->u.Process.Processes[0]; + else + processItem = NULL; + + sendToMenu = CreateSendToMenu(menuInfo->Menu, processItem ? processItem->FileName : NULL); + + // Only enable the Send To menu if there is exactly one process selected and it has a file name. + if (!processItem || !processItem->FileName) + { + sendToMenu->Flags |= PH_EMENU_DISABLED; + } +} + +VOID NTAPI ModuleMenuInitializingCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + PPH_PLUGIN_MENU_INFORMATION menuInfo = Parameter; + PPH_MODULE_ITEM moduleItem; + PPH_EMENU_ITEM sendToMenu; + + if (menuInfo->u.Module.NumberOfModules == 1) + moduleItem = menuInfo->u.Module.Modules[0]; + else + moduleItem = NULL; + + sendToMenu = CreateSendToMenu(menuInfo->Menu, moduleItem ? moduleItem->FileName : NULL); + + if (!moduleItem) + { + sendToMenu->Flags |= PH_EMENU_DISABLED; + } +} + +VOID NTAPI ServiceMenuInitializingCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + PPH_PLUGIN_MENU_INFORMATION menuInfo = Parameter; + PPH_SERVICE_ITEM serviceItem; + PPH_EMENU_ITEM sendToMenu; + PPH_STRING serviceFileName = NULL; + PPH_STRING serviceBinaryPath = NULL; + + if (menuInfo->u.Service.NumberOfServices == 1) + serviceItem = menuInfo->u.Service.Services[0]; + else + serviceItem = NULL; + + QueryServiceFileName( + &serviceItem->Name->sr, + &serviceFileName, + &serviceBinaryPath + ); + + if (serviceBinaryPath) PhDereferenceObject(serviceBinaryPath); + + // TODO: Possible serviceFileName string memory leak. + sendToMenu = CreateSendToMenu(menuInfo->Menu, serviceFileName ? serviceFileName : NULL); + + if (!serviceItem || !serviceFileName) + { + sendToMenu->Flags |= PH_EMENU_DISABLED; + } +} + +VOID ProcessHighlightingColorCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + PPH_PLUGIN_GET_HIGHLIGHTING_COLOR getHighlightingColor = Parameter; + PPH_PROCESS_ITEM processItem = (PPH_PROCESS_ITEM)getHighlightingColor->Parameter; + //PPROCESS_DB_OBJECT object; + + if (getHighlightingColor->Handled) + return; + + //if (!PhGetIntegerSetting(SETTING_NAME_VIRUSTOTAL_HIGHLIGHT_DETECTIONS)) + // return; + + //LockProcessDb(); + + //if (PhIsNullOrEmptyString(processItem->FileName)) + // return; + + //if ((object = FindProcessDbObject(&processItem->FileName->sr)) && object->Positives) + //{ + // getHighlightingColor->BackColor = RGB(255, 0, 0); + // getHighlightingColor->Cache = TRUE; + // getHighlightingColor->Handled = TRUE; + //} + + //UnlockProcessDb(); +} + +LONG NTAPI VirusTotalProcessNodeSortFunction( + _In_ PVOID Node1, + _In_ PVOID Node2, + _In_ ULONG SubId, + _In_ PVOID Context + ) +{ + PPH_PROCESS_NODE node1 = Node1; + PPH_PROCESS_NODE node2 = Node2; + PPROCESS_EXTENSION extension1 = PhPluginGetObjectExtension(PluginInstance, node1->ProcessItem, EmProcessItemType); + PPROCESS_EXTENSION extension2 = PhPluginGetObjectExtension(PluginInstance, node2->ProcessItem, EmProcessItemType); + + return PhCompareStringWithNull(extension1->VirusTotalResult, extension2->VirusTotalResult, TRUE); +} + +LONG NTAPI VirusTotalModuleNodeSortFunction( + _In_ PVOID Node1, + _In_ PVOID Node2, + _In_ ULONG SubId, + _In_ PVOID Context + ) +{ + PPH_MODULE_NODE node1 = Node1; + PPH_MODULE_NODE node2 = Node2; + PPROCESS_EXTENSION extension1 = PhPluginGetObjectExtension(PluginInstance, node1->ModuleItem, EmModuleItemType); + PPROCESS_EXTENSION extension2 = PhPluginGetObjectExtension(PluginInstance, node2->ModuleItem, EmModuleItemType); + + return PhCompareStringWithNull(extension1->VirusTotalResult, extension2->VirusTotalResult, TRUE); +} + +LONG NTAPI VirusTotalServiceNodeSortFunction( + _In_ PVOID Node1, + _In_ PVOID Node2, + _In_ ULONG SubId, + _In_ PVOID Context + ) +{ + PPH_SERVICE_NODE node1 = Node1; + PPH_SERVICE_NODE node2 = Node2; + PPROCESS_EXTENSION extension1 = PhPluginGetObjectExtension(PluginInstance, node1->ServiceItem, EmServiceItemType); + PPROCESS_EXTENSION extension2 = PhPluginGetObjectExtension(PluginInstance, node2->ServiceItem, EmServiceItemType); + + return PhCompareStringWithNull(extension1->VirusTotalResult, extension2->VirusTotalResult, TRUE); +} + +VOID NTAPI ProcessTreeNewInitializingCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + PPH_PLUGIN_TREENEW_INFORMATION info = Parameter; + PH_TREENEW_COLUMN column; + + memset(&column, 0, sizeof(PH_TREENEW_COLUMN)); + column.Text = L"VirusTotal"; + column.Width = 140; + column.Alignment = PH_ALIGN_CENTER; + column.CustomDraw = TRUE; + column.Context = info->TreeNewHandle; // Context + + PhPluginAddTreeNewColumn(PluginInstance, info->CmData, &column, COLUMN_ID_VIUSTOTAL_PROCESS, NULL, VirusTotalProcessNodeSortFunction); +} + +VOID NTAPI ModuleTreeNewInitializingCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + PPH_PLUGIN_TREENEW_INFORMATION info = Parameter; + PH_TREENEW_COLUMN column; + + memset(&column, 0, sizeof(PH_TREENEW_COLUMN)); + column.Text = L"VirusTotal"; + column.Width = 140; + column.Alignment = PH_ALIGN_CENTER; + column.CustomDraw = TRUE; + column.Context = info->TreeNewHandle; // Context + + PhPluginAddTreeNewColumn(PluginInstance, info->CmData, &column, COLUMN_ID_VIUSTOTAL_MODULE, NULL, VirusTotalModuleNodeSortFunction); +} + +VOID NTAPI ServiceTreeNewInitializingCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + PPH_PLUGIN_TREENEW_INFORMATION info = Parameter; + PH_TREENEW_COLUMN column; + + memset(&column, 0, sizeof(PH_TREENEW_COLUMN)); + column.Text = L"VirusTotal"; + column.Width = 140; + column.Alignment = PH_ALIGN_CENTER; + column.CustomDraw = TRUE; + column.Context = info->TreeNewHandle; // Context + + PhPluginAddTreeNewColumn(PluginInstance, info->CmData, &column, COLUMN_ID_VIUSTOTAL_SERVICE, NULL, VirusTotalServiceNodeSortFunction); +} + +VOID NTAPI TreeNewMessageCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + PPH_PLUGIN_TREENEW_MESSAGE message = Parameter; + + switch (message->Message) + { + case TreeNewGetCellText: + { + PPH_TREENEW_GET_CELL_TEXT getCellText = message->Parameter1; + + switch (message->SubId) + { + case COLUMN_ID_VIUSTOTAL_PROCESS: + { + PPH_PROCESS_NODE processNode = (PPH_PROCESS_NODE)getCellText->Node; + PPROCESS_EXTENSION extension = PhPluginGetObjectExtension(PluginInstance, processNode->ProcessItem, EmProcessItemType); + + getCellText->Text = PhGetStringRef(extension->VirusTotalResult); + } + break; + case COLUMN_ID_VIUSTOTAL_MODULE: + { + PPH_MODULE_NODE moduleNode = (PPH_MODULE_NODE)getCellText->Node; + PPROCESS_EXTENSION extension = PhPluginGetObjectExtension(PluginInstance, moduleNode->ModuleItem, EmModuleItemType); + + getCellText->Text = PhGetStringRef(extension->VirusTotalResult); + } + break; + case COLUMN_ID_VIUSTOTAL_SERVICE: + { + PPH_SERVICE_NODE serviceNode = (PPH_SERVICE_NODE)getCellText->Node; + PPROCESS_EXTENSION extension = PhPluginGetObjectExtension(PluginInstance, serviceNode->ServiceItem, EmServiceItemType); + + getCellText->Text = PhGetStringRef(extension->VirusTotalResult); + } + break; + } + } + break; + case TreeNewCustomDraw: + { + PPH_TREENEW_CUSTOM_DRAW customDraw = message->Parameter1; + PPROCESS_EXTENSION extension = NULL; + PH_STRINGREF text; + + if (!VirusTotalScanningEnabled) + { + static PH_STRINGREF disabledText = PH_STRINGREF_INIT(L"Scanning disabled"); + + DrawText( + customDraw->Dc, + disabledText.Buffer, + (ULONG)disabledText.Length / 2, + &customDraw->CellRect, + DT_CENTER | DT_VCENTER | DT_END_ELLIPSIS | DT_SINGLELINE + ); + + return; + } + + switch (message->SubId) + { + case COLUMN_ID_VIUSTOTAL_PROCESS: + { + PPH_PROCESS_NODE processNode = (PPH_PROCESS_NODE)customDraw->Node; + + extension = PhPluginGetObjectExtension(PluginInstance, processNode->ProcessItem, EmProcessItemType); + } + break; + case COLUMN_ID_VIUSTOTAL_MODULE: + { + PPH_MODULE_NODE moduleNode = (PPH_MODULE_NODE)customDraw->Node; + + extension = PhPluginGetObjectExtension(PluginInstance, moduleNode->ModuleItem, EmModuleItemType); + } + break; + case COLUMN_ID_VIUSTOTAL_SERVICE: + { + PPH_SERVICE_NODE serviceNode = (PPH_SERVICE_NODE)customDraw->Node; + + extension = PhPluginGetObjectExtension(PluginInstance, serviceNode->ServiceItem, EmServiceItemType); + } + break; + } + + if (!extension) + break; + + text = PhGetStringRef(extension->VirusTotalResult); + DrawText( + customDraw->Dc, + text.Buffer, + (ULONG)text.Length / 2, + &customDraw->CellRect, + DT_CENTER | DT_VCENTER | DT_END_ELLIPSIS | DT_SINGLELINE + ); + } + break; + } +} + +VOID NTAPI ProcessItemCreateCallback( + _In_ PVOID Object, + _In_ PH_EM_OBJECT_TYPE ObjectType, + _In_ PVOID Extension + ) +{ + PPH_PROCESS_ITEM processItem = Object; + PPROCESS_EXTENSION extension = Extension; + + memset(extension, 0, sizeof(PROCESS_EXTENSION)); + + extension->ProcessItem = processItem; + extension->VirusTotalResult = PhReferenceEmptyString(); + + PhAcquireQueuedLockExclusive(&ProcessesListLock); + InsertTailList(&ProcessListHead, &extension->ListEntry); + PhReleaseQueuedLockExclusive(&ProcessesListLock); +} + +VOID NTAPI ProcessItemDeleteCallback( + _In_ PVOID Object, + _In_ PH_EM_OBJECT_TYPE ObjectType, + _In_ PVOID Extension + ) +{ + PPH_PROCESS_ITEM processItem = Object; + PPROCESS_EXTENSION extension = Extension; + + PhClearReference(&extension->VirusTotalResult); + + PhAcquireQueuedLockExclusive(&ProcessesListLock); + RemoveEntryList(&extension->ListEntry); + PhReleaseQueuedLockExclusive(&ProcessesListLock); +} + +VOID NTAPI ModuleItemCreateCallback( + _In_ PVOID Object, + _In_ PH_EM_OBJECT_TYPE ObjectType, + _In_ PVOID Extension + ) +{ + PPH_MODULE_ITEM moduleItem = Object; + PPROCESS_EXTENSION extension = Extension; + + memset(extension, 0, sizeof(PROCESS_EXTENSION)); + + extension->ModuleItem = moduleItem; + extension->VirusTotalResult = PhReferenceEmptyString(); + + PhAcquireQueuedLockExclusive(&ProcessesListLock); + InsertTailList(&ProcessListHead, &extension->ListEntry); + PhReleaseQueuedLockExclusive(&ProcessesListLock); +} + +VOID NTAPI ModuleItemDeleteCallback( + _In_ PVOID Object, + _In_ PH_EM_OBJECT_TYPE ObjectType, + _In_ PVOID Extension + ) +{ + PPH_MODULE_ITEM processItem = Object; + PPROCESS_EXTENSION extension = Extension; + + PhClearReference(&extension->VirusTotalResult); + + PhAcquireQueuedLockExclusive(&ProcessesListLock); + RemoveEntryList(&extension->ListEntry); + PhReleaseQueuedLockExclusive(&ProcessesListLock); +} + +VOID NTAPI ServiceItemCreateCallback( + _In_ PVOID Object, + _In_ PH_EM_OBJECT_TYPE ObjectType, + _In_ PVOID Extension + ) +{ + PPH_SERVICE_ITEM serviceItem = Object; + PPROCESS_EXTENSION extension = Extension; + + memset(extension, 0, sizeof(PROCESS_EXTENSION)); + + extension->ServiceItem = serviceItem; + extension->VirusTotalResult = PhReferenceEmptyString(); + + PhAcquireQueuedLockExclusive(&ProcessesListLock); + InsertTailList(&ProcessListHead, &extension->ListEntry); + PhReleaseQueuedLockExclusive(&ProcessesListLock); +} + +VOID NTAPI ServiceItemDeleteCallback( + _In_ PVOID Object, + _In_ PH_EM_OBJECT_TYPE ObjectType, + _In_ PVOID Extension + ) +{ + PPH_SERVICE_ITEM serviceItem = Object; + PPROCESS_EXTENSION extension = Extension; + + PhClearReference(&extension->VirusTotalResult); + + PhAcquireQueuedLockExclusive(&ProcessesListLock); + RemoveEntryList(&extension->ListEntry); + PhReleaseQueuedLockExclusive(&ProcessesListLock); +} + +LOGICAL DllMain( + _In_ HINSTANCE Instance, + _In_ ULONG Reason, + _Reserved_ PVOID Reserved + ) +{ + switch (Reason) + { + case DLL_PROCESS_ATTACH: + { + PPH_PLUGIN_INFORMATION info; + PH_SETTING_CREATE settings[] = + { + { IntegerSettingType, SETTING_NAME_VIRUSTOTAL_SCAN_ENABLED, L"0" }, + { IntegerSettingType, SETTING_NAME_VIRUSTOTAL_HIGHLIGHT_DETECTIONS, L"0" } + }; + + PluginInstance = PhRegisterPlugin(PLUGIN_NAME, Instance, &info); + + if (!PluginInstance) + return FALSE; + + info->DisplayName = L"Online Checks"; + info->Author = L"dmex, wj32"; + info->Description = L"Allows files to be checked with online services."; + info->Url = L"https://wj32.org/processhacker/forums/viewtopic.php?t=1118"; + info->HasOptions = TRUE; + + PhRegisterCallback( + PhGetPluginCallback(PluginInstance, PluginCallbackLoad), + LoadCallback, + NULL, + &PluginLoadCallbackRegistration + ); + PhRegisterCallback( + PhGetPluginCallback(PluginInstance, PluginCallbackShowOptions), + ShowOptionsCallback, + NULL, + &PluginShowOptionsCallbackRegistration + ); + PhRegisterCallback( + PhGetPluginCallback(PluginInstance, PluginCallbackMenuItem), + MenuItemCallback, + NULL, + &PluginMenuItemCallbackRegistration + ); + PhRegisterCallback( + PhGetGeneralCallback(GeneralCallbackMainMenuInitializing), + MainMenuInitializingCallback, + NULL, + &MainMenuInitializingCallbackRegistration + ); + PhRegisterCallback( + PhGetGeneralCallback(GeneralCallbackProcessMenuInitializing), + ProcessMenuInitializingCallback, + NULL, + &ProcessMenuInitializingCallbackRegistration + ); + PhRegisterCallback( + PhGetGeneralCallback(GeneralCallbackModuleMenuInitializing), + ModuleMenuInitializingCallback, + NULL, + &ModuleMenuInitializingCallbackRegistration + ); + PhRegisterCallback( + PhGetGeneralCallback(GeneralCallbackServiceMenuInitializing), + ServiceMenuInitializingCallback, + NULL, + &ServiceMenuInitializingCallbackRegistration + ); + + PhRegisterCallback( + PhGetGeneralCallback(GeneralCallbackProcessesUpdated), + ProcessesUpdatedCallback, + NULL, + &ProcessesUpdatedCallbackRegistration + ); + + PhRegisterCallback( + PhGetGeneralCallback(GeneralCallbackGetProcessHighlightingColor), + ProcessHighlightingColorCallback, + NULL, + &ProcessHighlightingColorCallbackRegistration + ); + + PhRegisterCallback( + PhGetGeneralCallback(GeneralCallbackProcessTreeNewInitializing), + ProcessTreeNewInitializingCallback, + NULL, + &ProcessTreeNewInitializingCallbackRegistration + ); + PhRegisterCallback( + PhGetGeneralCallback(GeneralCallbackModuleTreeNewInitializing), + ModuleTreeNewInitializingCallback, + NULL, + &ModulesTreeNewInitializingCallbackRegistration + ); + PhRegisterCallback( + PhGetGeneralCallback(GeneralCallbackServiceTreeNewInitializing), + ServiceTreeNewInitializingCallback, + NULL, + &ServiceTreeNewInitializingCallbackRegistration + ); + + PhRegisterCallback( + PhGetPluginCallback(PluginInstance, PluginCallbackTreeNewMessage), + TreeNewMessageCallback, + NULL, + &TreeNewMessageCallbackRegistration + ); + + PhPluginSetObjectExtension( + PluginInstance, + EmProcessItemType, + sizeof(PROCESS_EXTENSION), + ProcessItemCreateCallback, + ProcessItemDeleteCallback + ); + + PhPluginSetObjectExtension( + PluginInstance, + EmModuleItemType, + sizeof(PROCESS_EXTENSION), + ModuleItemCreateCallback, + ModuleItemDeleteCallback + ); + + PhPluginSetObjectExtension( + PluginInstance, + EmServiceItemType, + sizeof(PROCESS_EXTENSION), + ServiceItemCreateCallback, + ServiceItemDeleteCallback + ); + + PhAddSettings(settings, ARRAYSIZE(settings)); + } + break; + } + + return TRUE; } \ No newline at end of file diff --git a/plugins/OnlineChecks/onlnchk.h b/plugins/OnlineChecks/onlnchk.h index ef064d48df00..498933978ecd 100644 --- a/plugins/OnlineChecks/onlnchk.h +++ b/plugins/OnlineChecks/onlnchk.h @@ -1,269 +1,269 @@ -/* - * Process Hacker Online Checks - - * Main Headers - * - * Copyright (C) 2010-2013 wj32 - * Copyright (C) 2012-2016 dmex - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#ifndef ONLNCHK_H -#define ONLNCHK_H - -#define CINTERFACE -#define COBJMACROS -#include -#include -#include -#include -#include -#include -#include -#include -#include "resource.h" -#include "db.h" - -#define PLUGIN_NAME L"ProcessHacker.OnlineChecks" -#define SETTING_NAME_VIRUSTOTAL_SCAN_ENABLED (PLUGIN_NAME L".EnableVirusTotalScanning") -#define SETTING_NAME_VIRUSTOTAL_HIGHLIGHT_DETECTIONS (PLUGIN_NAME L".VirusTotalHighlightDetection") - -#ifdef VIRUSTOTAL_API -#include "virustotal.h" -#else -#define VIRUSTOTAL_URLPATH L"" -#define VIRUSTOTAL_APIKEY L"" -#endif - -#define UM_UPLOAD (WM_APP + 1) -#define UM_EXISTS (WM_APP + 2) -#define UM_LAUNCH (WM_APP + 3) -#define UM_ERROR (WM_APP + 4) -#define UM_SHOWDIALOG (WM_APP + 5) - -extern PPH_PLUGIN PluginInstance; - -typedef struct _SERVICE_INFO -{ - ULONG Id; - PWSTR HostName; - INTERNET_PORT HostPort; - ULONG HostFlags; - PWSTR UploadObjectName; - PWSTR FileNameFieldName; -} SERVICE_INFO, *PSERVICE_INFO; - -typedef struct _PROCESS_EXTENSION -{ - LIST_ENTRY ListEntry; - - union - { - BOOLEAN Flags; - struct - { - BOOLEAN Stage1 : 1; - BOOLEAN ResultValid : 1; - BOOLEAN Spare : 6; - }; - }; - - INT64 Retries; - INT64 Positives; - PPH_STRING VirusTotalResult; - PPH_STRING FilePath; - - PPH_PROCESS_ITEM ProcessItem; - PPH_MODULE_ITEM ModuleItem; - PPH_SERVICE_ITEM ServiceItem; -} PROCESS_EXTENSION, *PPROCESS_EXTENSION; - -typedef struct _VIRUSTOTAL_FILE_HASH_ENTRY -{ - union - { - BOOLEAN Flags; - struct - { - BOOLEAN Stage1 : 1; - BOOLEAN Processing : 1; - BOOLEAN Processed : 1; - BOOLEAN Found : 1; - BOOLEAN Spare : 5; - }; - }; - - PPROCESS_EXTENSION Extension; - - INT64 Positives; - PPH_STRING FileName; - PPH_STRING FileHash; - PPH_BYTES FileNameAnsi; - PPH_BYTES FileHashAnsi; - PPH_BYTES CreationTime; - PPH_STRING FileResult; -} VIRUSTOTAL_FILE_HASH_ENTRY, *PVIRUSTOTAL_FILE_HASH_ENTRY; - -typedef struct _UPLOAD_CONTEXT -{ - BOOLEAN VtApiUpload; - BOOLEAN FileExists; - ULONG Service; - ULONG ErrorCode; - ULONG TotalFileLength; - - HWND DialogHandle; - HANDLE UploadThreadHandle; - HICON IconLargeHandle; - HICON IconSmallHandle; - HINTERNET HttpHandle; - ITaskbarList3* TaskbarListClass; - - PPH_STRING FileSize; - PPH_STRING ErrorString; - PPH_STRING KeyString; - - PPH_STRING FileName; - PPH_STRING BaseFileName; - PPH_STRING WindowFileName; - PPH_STRING LaunchCommand; - PPH_STRING Detected; - PPH_STRING MaxDetected; - PPH_STRING UploadUrl; - PPH_STRING ReAnalyseUrl; - PPH_STRING FirstAnalysisDate; - PPH_STRING LastAnalysisDate; - PPH_STRING LastAnalysisUrl; - PPH_STRING LastAnalysisAgo; -} UPLOAD_CONTEXT, *PUPLOAD_CONTEXT; - -VOID ShowOptionsDialog( - _In_opt_ HWND Parent - ); - -NTSTATUS UploadFileThreadStart( - _In_ PVOID Parameter - ); - -NTSTATUS UploadCheckThreadStart( - _In_ PVOID Parameter - ); - -VOID ShowVirusTotalUploadDialog( - _In_ PUPLOAD_CONTEXT Context - ); - -VOID ShowFileFoundDialog( - _In_ PUPLOAD_CONTEXT Context - ); - -VOID ShowVirusTotalProgressDialog( - _In_ PUPLOAD_CONTEXT Context - ); - -VOID VirusTotalShowErrorDialog( - _In_ PUPLOAD_CONTEXT Context - ); - -typedef struct _VIRUSTOTAL_FILE_REPORT_RESULT -{ - PPH_STRING FileName; - PPH_STRING BaseFileName; - - PPH_STRING Total; - PPH_STRING Positives; - PPH_STRING Resource; - PPH_STRING ScanId; - PPH_STRING Md5; - PPH_STRING Sha1; - PPH_STRING Sha256; - PPH_STRING ScanDate; - PPH_STRING Permalink; - PPH_STRING StatusMessage; - PPH_LIST ScanResults; -} VIRUSTOTAL_FILE_REPORT_RESULT, *PVIRUSTOTAL_FILE_REPORT_RESULT; - -PPH_STRING VirusTotalStringToTime( - _In_ PPH_STRING Time - ); - -PVIRUSTOTAL_FILE_REPORT_RESULT VirusTotalSendHttpFileReportRequest( - _In_ PPH_STRING FileHash - ); - -// upload -#define ENABLE_SERVICE_VIRUSTOTAL 100 -#define MENUITEM_VIRUSTOTAL_QUEUE 101 -#define MENUITEM_VIRUSTOTAL_UPLOAD 102 -#define MENUITEM_VIRUSTOTAL_UPLOAD_FILE 103 -#define MENUITEM_JOTTI_UPLOAD 104 - -VOID UploadToOnlineService( - _In_ PPH_STRING FileName, - _In_ ULONG Service - ); - -typedef enum _NETWORK_COLUMN_ID -{ - COLUMN_ID_VIUSTOTAL_PROCESS = 1, - COLUMN_ID_VIUSTOTAL_MODULE = 2, - COLUMN_ID_VIUSTOTAL_SERVICE = 3 -} NETWORK_COLUMN_ID; - -NTSTATUS HashFileAndResetPosition( - _In_ HANDLE FileHandle, - _In_ PLARGE_INTEGER FileSize, - _In_ PH_HASH_ALGORITHM Algorithm, - _Out_ PPH_STRING *HashString - ); - -typedef struct _VIRUSTOTAL_API_RESULT -{ - BOOLEAN Found; - INT64 Positives; - INT64 Total; - PPH_STRING Permalink; - PPH_STRING FileHash; - PPH_STRING DetectionRatio; -} VIRUSTOTAL_API_RESULT, *PVIRUSTOTAL_API_RESULT; - -extern PPH_LIST VirusTotalList; -extern BOOLEAN VirusTotalScanningEnabled; - -PVIRUSTOTAL_FILE_HASH_ENTRY VirusTotalAddCacheResult( - _In_ PPH_STRING FileName, - _In_ PPROCESS_EXTENSION Extension - ); - -PVIRUSTOTAL_FILE_HASH_ENTRY VirusTotalGetCachedResult( - _In_ PPH_STRING FileName - ); - -VOID InitializeVirusTotalProcessMonitor( - VOID - ); - -VOID CleanupVirusTotalProcessMonitor( - VOID - ); - -NTSTATUS QueryServiceFileName( - _In_ PPH_STRINGREF ServiceName, - _Out_ PPH_STRING *ServiceFileName, - _Out_ PPH_STRING *ServiceBinaryPath - ); - -#endif +/* + * Process Hacker Online Checks - + * Main Headers + * + * Copyright (C) 2010-2013 wj32 + * Copyright (C) 2012-2016 dmex + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#ifndef ONLNCHK_H +#define ONLNCHK_H + +#define CINTERFACE +#define COBJMACROS +#include +#include +#include +#include +#include +#include +#include +#include +#include "resource.h" +#include "db.h" + +#define PLUGIN_NAME L"ProcessHacker.OnlineChecks" +#define SETTING_NAME_VIRUSTOTAL_SCAN_ENABLED (PLUGIN_NAME L".EnableVirusTotalScanning") +#define SETTING_NAME_VIRUSTOTAL_HIGHLIGHT_DETECTIONS (PLUGIN_NAME L".VirusTotalHighlightDetection") + +#ifdef VIRUSTOTAL_API +#include "virustotal.h" +#else +#define VIRUSTOTAL_URLPATH L"" +#define VIRUSTOTAL_APIKEY L"" +#endif + +#define UM_UPLOAD (WM_APP + 1) +#define UM_EXISTS (WM_APP + 2) +#define UM_LAUNCH (WM_APP + 3) +#define UM_ERROR (WM_APP + 4) +#define UM_SHOWDIALOG (WM_APP + 5) + +extern PPH_PLUGIN PluginInstance; + +typedef struct _SERVICE_INFO +{ + ULONG Id; + PWSTR HostName; + INTERNET_PORT HostPort; + ULONG HostFlags; + PWSTR UploadObjectName; + PWSTR FileNameFieldName; +} SERVICE_INFO, *PSERVICE_INFO; + +typedef struct _PROCESS_EXTENSION +{ + LIST_ENTRY ListEntry; + + union + { + BOOLEAN Flags; + struct + { + BOOLEAN Stage1 : 1; + BOOLEAN ResultValid : 1; + BOOLEAN Spare : 6; + }; + }; + + INT64 Retries; + INT64 Positives; + PPH_STRING VirusTotalResult; + PPH_STRING FilePath; + + PPH_PROCESS_ITEM ProcessItem; + PPH_MODULE_ITEM ModuleItem; + PPH_SERVICE_ITEM ServiceItem; +} PROCESS_EXTENSION, *PPROCESS_EXTENSION; + +typedef struct _VIRUSTOTAL_FILE_HASH_ENTRY +{ + union + { + BOOLEAN Flags; + struct + { + BOOLEAN Stage1 : 1; + BOOLEAN Processing : 1; + BOOLEAN Processed : 1; + BOOLEAN Found : 1; + BOOLEAN Spare : 5; + }; + }; + + PPROCESS_EXTENSION Extension; + + INT64 Positives; + PPH_STRING FileName; + PPH_STRING FileHash; + PPH_BYTES FileNameAnsi; + PPH_BYTES FileHashAnsi; + PPH_BYTES CreationTime; + PPH_STRING FileResult; +} VIRUSTOTAL_FILE_HASH_ENTRY, *PVIRUSTOTAL_FILE_HASH_ENTRY; + +typedef struct _UPLOAD_CONTEXT +{ + BOOLEAN VtApiUpload; + BOOLEAN FileExists; + ULONG Service; + ULONG ErrorCode; + ULONG TotalFileLength; + + HWND DialogHandle; + HANDLE UploadThreadHandle; + HICON IconLargeHandle; + HICON IconSmallHandle; + HINTERNET HttpHandle; + ITaskbarList3* TaskbarListClass; + + PPH_STRING FileSize; + PPH_STRING ErrorString; + PPH_STRING KeyString; + + PPH_STRING FileName; + PPH_STRING BaseFileName; + PPH_STRING WindowFileName; + PPH_STRING LaunchCommand; + PPH_STRING Detected; + PPH_STRING MaxDetected; + PPH_STRING UploadUrl; + PPH_STRING ReAnalyseUrl; + PPH_STRING FirstAnalysisDate; + PPH_STRING LastAnalysisDate; + PPH_STRING LastAnalysisUrl; + PPH_STRING LastAnalysisAgo; +} UPLOAD_CONTEXT, *PUPLOAD_CONTEXT; + +VOID ShowOptionsDialog( + _In_opt_ HWND Parent + ); + +NTSTATUS UploadFileThreadStart( + _In_ PVOID Parameter + ); + +NTSTATUS UploadCheckThreadStart( + _In_ PVOID Parameter + ); + +VOID ShowVirusTotalUploadDialog( + _In_ PUPLOAD_CONTEXT Context + ); + +VOID ShowFileFoundDialog( + _In_ PUPLOAD_CONTEXT Context + ); + +VOID ShowVirusTotalProgressDialog( + _In_ PUPLOAD_CONTEXT Context + ); + +VOID VirusTotalShowErrorDialog( + _In_ PUPLOAD_CONTEXT Context + ); + +typedef struct _VIRUSTOTAL_FILE_REPORT_RESULT +{ + PPH_STRING FileName; + PPH_STRING BaseFileName; + + PPH_STRING Total; + PPH_STRING Positives; + PPH_STRING Resource; + PPH_STRING ScanId; + PPH_STRING Md5; + PPH_STRING Sha1; + PPH_STRING Sha256; + PPH_STRING ScanDate; + PPH_STRING Permalink; + PPH_STRING StatusMessage; + PPH_LIST ScanResults; +} VIRUSTOTAL_FILE_REPORT_RESULT, *PVIRUSTOTAL_FILE_REPORT_RESULT; + +PPH_STRING VirusTotalStringToTime( + _In_ PPH_STRING Time + ); + +PVIRUSTOTAL_FILE_REPORT_RESULT VirusTotalSendHttpFileReportRequest( + _In_ PPH_STRING FileHash + ); + +// upload +#define ENABLE_SERVICE_VIRUSTOTAL 100 +#define MENUITEM_VIRUSTOTAL_QUEUE 101 +#define MENUITEM_VIRUSTOTAL_UPLOAD 102 +#define MENUITEM_VIRUSTOTAL_UPLOAD_FILE 103 +#define MENUITEM_JOTTI_UPLOAD 104 + +VOID UploadToOnlineService( + _In_ PPH_STRING FileName, + _In_ ULONG Service + ); + +typedef enum _NETWORK_COLUMN_ID +{ + COLUMN_ID_VIUSTOTAL_PROCESS = 1, + COLUMN_ID_VIUSTOTAL_MODULE = 2, + COLUMN_ID_VIUSTOTAL_SERVICE = 3 +} NETWORK_COLUMN_ID; + +NTSTATUS HashFileAndResetPosition( + _In_ HANDLE FileHandle, + _In_ PLARGE_INTEGER FileSize, + _In_ PH_HASH_ALGORITHM Algorithm, + _Out_ PPH_STRING *HashString + ); + +typedef struct _VIRUSTOTAL_API_RESULT +{ + BOOLEAN Found; + INT64 Positives; + INT64 Total; + PPH_STRING Permalink; + PPH_STRING FileHash; + PPH_STRING DetectionRatio; +} VIRUSTOTAL_API_RESULT, *PVIRUSTOTAL_API_RESULT; + +extern PPH_LIST VirusTotalList; +extern BOOLEAN VirusTotalScanningEnabled; + +PVIRUSTOTAL_FILE_HASH_ENTRY VirusTotalAddCacheResult( + _In_ PPH_STRING FileName, + _In_ PPROCESS_EXTENSION Extension + ); + +PVIRUSTOTAL_FILE_HASH_ENTRY VirusTotalGetCachedResult( + _In_ PPH_STRING FileName + ); + +VOID InitializeVirusTotalProcessMonitor( + VOID + ); + +VOID CleanupVirusTotalProcessMonitor( + VOID + ); + +NTSTATUS QueryServiceFileName( + _In_ PPH_STRINGREF ServiceName, + _Out_ PPH_STRING *ServiceFileName, + _Out_ PPH_STRING *ServiceBinaryPath + ); + +#endif diff --git a/plugins/OnlineChecks/resource.h b/plugins/OnlineChecks/resource.h index e0adf0b1da02..6b43b8c86cbf 100644 --- a/plugins/OnlineChecks/resource.h +++ b/plugins/OnlineChecks/resource.h @@ -1,21 +1,21 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by OnlineChecks.rc -// -#define IDD_OPTIONS 102 -#define IDC_ENABLE_VIRUSTOTAL 1001 -#define IDC_ENABLE_IDC_ENABLE_VIRUSTOTAL_HIGHLIGHT 1002 -#define IDC_CHECK1 1010 -#define IDC_EDIT1 1011 -#define IDC_COMBO1 1012 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 103 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1013 -#define _APS_NEXT_SYMED_VALUE 103 -#endif -#endif +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by OnlineChecks.rc +// +#define IDD_OPTIONS 102 +#define IDC_ENABLE_VIRUSTOTAL 1001 +#define IDC_ENABLE_IDC_ENABLE_VIRUSTOTAL_HIGHLIGHT 1002 +#define IDC_CHECK1 1010 +#define IDC_EDIT1 1011 +#define IDC_COMBO1 1012 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 103 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1013 +#define _APS_NEXT_SYMED_VALUE 103 +#endif +#endif diff --git a/plugins/OnlineChecks/upload.c b/plugins/OnlineChecks/upload.c index e0d15a71f12b..3c8ff16e74c7 100644 --- a/plugins/OnlineChecks/upload.c +++ b/plugins/OnlineChecks/upload.c @@ -1,1337 +1,1337 @@ -/* - * Process Hacker Plugins - - * Online Checks Plugin - * - * Copyright (C) 2016 dmex - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include "onlnchk.h" -#include -#include - -PPH_OBJECT_TYPE UploadContextType = NULL; -SERVICE_INFO UploadServiceInfo[] = -{ - { MENUITEM_VIRUSTOTAL_UPLOAD, L"www.virustotal.com", INTERNET_DEFAULT_HTTPS_PORT, WINHTTP_FLAG_SECURE, L"???", L"file" }, - { MENUITEM_JOTTI_UPLOAD, L"virusscan.jotti.org", INTERNET_DEFAULT_HTTPS_PORT, WINHTTP_FLAG_SECURE, L"/en-US/submit-file?isAjax=true", L"sample-file[]" }, -}; - -BOOL ReadRequestString( - _In_ HINTERNET Handle, - _Out_ _Deref_post_z_cap_(*DataLength) PSTR *Data, - _Out_ ULONG *DataLength - ) -{ - BYTE buffer[PAGE_SIZE]; - PSTR data; - ULONG allocatedLength; - ULONG dataLength; - ULONG returnLength; - - allocatedLength = sizeof(buffer); - data = (PSTR)PhAllocate(allocatedLength); - dataLength = 0; - - // Zero the buffer - memset(buffer, 0, PAGE_SIZE); - - while (WinHttpReadData(Handle, buffer, PAGE_SIZE, &returnLength)) - { - if (returnLength == 0) - break; - - if (allocatedLength < dataLength + returnLength) - { - allocatedLength *= 2; - data = (PSTR)PhReAllocate(data, allocatedLength); - } - - // Copy the returned buffer into our pointer - memcpy(data + dataLength, buffer, returnLength); - // Zero the returned buffer for the next loop - //memset(buffer, 0, returnLength); - - dataLength += returnLength; - } - - if (allocatedLength < dataLength + 1) - { - allocatedLength++; - data = (PSTR)PhReAllocate(data, allocatedLength); - } - - // Ensure that the buffer is null-terminated. - data[dataLength] = 0; - - *DataLength = dataLength; - *Data = data; - - return TRUE; -} - -VOID RaiseUploadError( - _In_ PUPLOAD_CONTEXT Context, - _In_ PWSTR Error, - _In_ ULONG ErrorCode - ) -{ - PWSTR errorMessage = NULL; - PPH_STRING message; - - if (!Context->DialogHandle) - return; - - if (message = PhGetMessage(GetModuleHandle(L"winhttp.dll"), 0xb, GetUserDefaultLangID(), ErrorCode)) - { - PhTrimToNullTerminatorString(message); - } - - // Remove any trailing newline - if (message && message->Length >= 2 * sizeof(WCHAR) && - message->Buffer[message->Length / sizeof(WCHAR) - 2] == '\r' && - message->Buffer[message->Length / sizeof(WCHAR) - 1] == '\n') - { - PhMoveReference(&message, PhCreateStringEx(message->Buffer, message->Length - 2 * sizeof(WCHAR))); - } - - if (message) - { - PhMoveReference(&Context->ErrorString, PhFormatString( - L"[%lu] %s", - ErrorCode, - PhGetString(message) - )); - - PhDereferenceObject(message); - } - else - { - PhMoveReference(&Context->ErrorString, PhFormatString( - L"[%lu] %s", - ErrorCode, - Error - )); - } - - PostMessage(Context->DialogHandle, UM_ERROR, 0, 0); - -} - -PSERVICE_INFO GetUploadServiceInfo( - _In_ ULONG Id - ) -{ - ULONG i; - - for (i = 0; i < ARRAYSIZE(UploadServiceInfo); i++) - { - if (UploadServiceInfo[i].Id == Id) - return &UploadServiceInfo[i]; - } - - return NULL; -} - -VOID UploadContextDeleteProcedure( - _In_ PVOID Object, - _In_ ULONG Flags - ) -{ - PUPLOAD_CONTEXT context = Object; - - if (context->TaskbarListClass) - { - ITaskbarList3_Release(context->TaskbarListClass); - context->TaskbarListClass = NULL; - } - - if (context->UploadThreadHandle) - { - NtClose(context->UploadThreadHandle); - context->UploadThreadHandle = NULL; - } - - if (context->HttpHandle) - { - WinHttpCloseHandle(context->HttpHandle); - context->HttpHandle = NULL; - } - - if (context->IconLargeHandle) - { - DestroyIcon(context->IconLargeHandle); - context->IconLargeHandle = NULL; - } - - if (context->IconSmallHandle) - { - DestroyIcon(context->IconSmallHandle); - context->IconSmallHandle = NULL; - } - - PhClearReference(&context->ErrorString); - PhClearReference(&context->KeyString); - PhClearReference(&context->FileName); - PhClearReference(&context->BaseFileName); - PhClearReference(&context->WindowFileName); - PhClearReference(&context->LaunchCommand); - PhClearReference(&context->Detected); - PhClearReference(&context->MaxDetected); - PhClearReference(&context->UploadUrl); - PhClearReference(&context->ReAnalyseUrl); - PhClearReference(&context->FirstAnalysisDate); - PhClearReference(&context->LastAnalysisDate); - PhClearReference(&context->LastAnalysisUrl); - PhClearReference(&context->LastAnalysisAgo); -} - -VOID TaskDialogFreeContext( - _In_ PUPLOAD_CONTEXT Context - ) -{ - // Reset Taskbar progress state(s) - if (Context->TaskbarListClass) - ITaskbarList3_SetProgressState(Context->TaskbarListClass, PhMainWndHandle, TBPF_NOPROGRESS); - - if (Context->TaskbarListClass) - ITaskbarList3_SetProgressState(Context->TaskbarListClass, Context->DialogHandle, TBPF_NOPROGRESS); - - PhDereferenceObject(Context); -} - -VOID TaskDialogCreateIcons( - _In_ PUPLOAD_CONTEXT Context - ) -{ - Context->IconLargeHandle = PhLoadIcon( - NtCurrentPeb()->ImageBaseAddress, - MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER), - PH_LOAD_ICON_SIZE_LARGE, - GetSystemMetrics(SM_CXICON), - GetSystemMetrics(SM_CYICON) - ); - Context->IconSmallHandle = PhLoadIcon( - NtCurrentPeb()->ImageBaseAddress, - MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER), - PH_LOAD_ICON_SIZE_LARGE, - GetSystemMetrics(SM_CXICON), - GetSystemMetrics(SM_CYICON) - ); - - SendMessage(Context->DialogHandle, WM_SETICON, ICON_SMALL, (LPARAM)Context->IconSmallHandle); - SendMessage(Context->DialogHandle, WM_SETICON, ICON_BIG, (LPARAM)Context->IconLargeHandle); -} - -PPH_STRING UpdateVersionString( - VOID - ) -{ - ULONG majorVersion; - ULONG minorVersion; - ULONG revisionVersion; - PPH_STRING currentVersion; - PPH_STRING versionHeader = NULL; - - PhGetPhVersionNumbers(&majorVersion, &minorVersion, NULL, &revisionVersion); - - if (currentVersion = PhFormatString(L"%lu.%lu.%lu", majorVersion, minorVersion, revisionVersion)) - { - versionHeader = PhConcatStrings2(L"ProcessHacker-Build: ", currentVersion->Buffer); - PhDereferenceObject(currentVersion); - } - - return versionHeader; -} - -NTSTATUS HashFileAndResetPosition( - _In_ HANDLE FileHandle, - _In_ PLARGE_INTEGER FileSize, - _In_ PH_HASH_ALGORITHM Algorithm, - _Out_ PPH_STRING *HashString - ) -{ - NTSTATUS status; - IO_STATUS_BLOCK iosb; - PH_HASH_CONTEXT hashContext; - PPH_STRING hashString = NULL; - ULONG64 bytesRemaining; - FILE_POSITION_INFORMATION positionInfo; - LONG priority; - LONG newpriority; - IO_PRIORITY_HINT ioPriority; - IO_PRIORITY_HINT newioPriority; - UCHAR buffer[PAGE_SIZE]; - - bytesRemaining = FileSize->QuadPart; - - newpriority = THREAD_PRIORITY_LOWEST; - newioPriority = IoPriorityVeryLow; - NtQueryInformationThread(NtCurrentThread(), ThreadBasePriority, &priority, sizeof(LONG), NULL); - NtQueryInformationThread(NtCurrentThread(), ThreadIoPriority, &ioPriority, sizeof(IO_PRIORITY_HINT), NULL); - NtSetInformationThread(NtCurrentThread(), ThreadBasePriority, &newpriority, sizeof(LONG)); - NtSetInformationThread(NtCurrentThread(), ThreadIoPriority, &newioPriority, sizeof(IO_PRIORITY_HINT)); - - PhInitializeHash(&hashContext, Algorithm); - - while (bytesRemaining) - { - status = NtReadFile( - FileHandle, - NULL, - NULL, - NULL, - &iosb, - buffer, - sizeof(buffer), - NULL, - NULL - ); - - if (!NT_SUCCESS(status)) - break; - - PhUpdateHash(&hashContext, buffer, (ULONG)iosb.Information); - bytesRemaining -= (ULONG)iosb.Information; - } - - if (status == STATUS_END_OF_FILE) - status = STATUS_SUCCESS; - - if (NT_SUCCESS(status)) - { - UCHAR hash[32]; - - switch (Algorithm) - { - case Md5HashAlgorithm: - PhFinalHash(&hashContext, hash, 16, NULL); - *HashString = PhBufferToHexString(hash, 16); - break; - case Sha1HashAlgorithm: - PhFinalHash(&hashContext, hash, 20, NULL); - *HashString = PhBufferToHexString(hash, 20); - break; - case Sha256HashAlgorithm: - PhFinalHash(&hashContext, hash, 32, NULL); - *HashString = PhBufferToHexString(hash, 32); - break; - } - - positionInfo.CurrentByteOffset.QuadPart = 0; - status = NtSetInformationFile( - FileHandle, - &iosb, - &positionInfo, - sizeof(FILE_POSITION_INFORMATION), - FilePositionInformation - ); - } - - NtSetInformationThread(NtCurrentThread(), ThreadBasePriority, &priority, sizeof(LONG)); - NtSetInformationThread(NtCurrentThread(), ThreadIoPriority, &ioPriority, sizeof(IO_PRIORITY_HINT)); - - return status; -} - -PPH_BYTES PerformSubRequest( - _In_ PUPLOAD_CONTEXT Context, - _In_ PWSTR HostName, - _In_ INTERNET_PORT HostPort, - _In_ ULONG HostFlags, - _In_ PWSTR ObjectName - ) -{ - PPH_BYTES result = NULL; - HINTERNET connectHandle = NULL; - HINTERNET requestHandle = NULL; - - if (!(connectHandle = WinHttpConnect( - Context->HttpHandle, - HostName, - HostPort, - 0 - ))) - { - RaiseUploadError(Context, L"Unable to connect to the service", GetLastError()); - goto CleanupExit; - } - - if (!(requestHandle = WinHttpOpenRequest( - connectHandle, - NULL, - ObjectName, - NULL, - WINHTTP_NO_REFERER, - WINHTTP_DEFAULT_ACCEPT_TYPES, - WINHTTP_FLAG_REFRESH | HostFlags - ))) - { - RaiseUploadError(Context, L"Unable to create the request", GetLastError()); - goto CleanupExit; - } - - if (!WinHttpSendRequest( - requestHandle, - WINHTTP_NO_ADDITIONAL_HEADERS, - 0, - WINHTTP_NO_REQUEST_DATA, - 0, - WINHTTP_IGNORE_REQUEST_TOTAL_LENGTH, - 0 - )) - { - RaiseUploadError(Context, L"Unable to send the request", GetLastError()); - goto CleanupExit; - } - - if (WinHttpReceiveResponse(requestHandle, NULL)) - { - PSTR data; - ULONG allocatedLength; - ULONG dataLength; - ULONG returnLength; - BYTE buffer[PAGE_SIZE]; - - allocatedLength = sizeof(buffer); - data = PhAllocate(allocatedLength); - dataLength = 0; - - while (WinHttpReadData(requestHandle, buffer, PAGE_SIZE, &returnLength)) - { - if (returnLength == 0) - break; - - if (allocatedLength < dataLength + returnLength) - { - allocatedLength *= 2; - data = PhReAllocate(data, allocatedLength); - } - - memcpy(data + dataLength, buffer, returnLength); - dataLength += returnLength; - } - - if (allocatedLength < dataLength + 1) - { - allocatedLength++; - data = PhReAllocate(data, allocatedLength); - } - - data[dataLength] = 0; - - result = PhCreateBytesEx(data, dataLength); - } - else - { - RaiseUploadError(Context, L"Unable to receive the response", GetLastError()); - goto CleanupExit; - } - -CleanupExit: - - if (requestHandle) - WinHttpCloseHandle(requestHandle); - - if (connectHandle) - WinHttpCloseHandle(connectHandle); - - return result; -} - -NTSTATUS UploadFileThreadStart( - _In_ PVOID Parameter - ) -{ - NTSTATUS status = STATUS_SUCCESS; - ULONG httpStatus = 0; - ULONG httpStatusLength = sizeof(ULONG); - ULONG httpPostSeed = 0; - ULONG totalUploadLength = 0; - ULONG totalUploadedLength = 0; - ULONG totalPostHeaderWritten = 0; - ULONG totalPostFooterWritten = 0; - ULONG totalWriteLength = 0; - LARGE_INTEGER timeNow; - LARGE_INTEGER timeStart; - ULONG64 timeTicks = 0; - ULONG64 timeBitsPerSecond = 0; - HANDLE fileHandle = NULL; - HINTERNET connectHandle = NULL; - HINTERNET requestHandle = NULL; - IO_STATUS_BLOCK isb; - URL_COMPONENTS httpComponents = { sizeof(URL_COMPONENTS) }; - PPH_STRING httpHostName = NULL; - PPH_STRING httpHostPath = NULL; - PSERVICE_INFO serviceInfo = NULL; - PPH_STRING postBoundary = NULL; - PPH_BYTES asciiPostData = NULL; - PPH_BYTES asciiFooterData = NULL; - PH_STRING_BUILDER httpRequestHeaders = { 0 }; - PH_STRING_BUILDER httpPostHeader = { 0 }; - PH_STRING_BUILDER httpPostFooter = { 0 }; - PUPLOAD_CONTEXT context = (PUPLOAD_CONTEXT)Parameter; - - serviceInfo = GetUploadServiceInfo(context->Service); - - // Set lengths to non-zero enabling these params to be cracked. - httpComponents.dwSchemeLength = (ULONG)-1; - httpComponents.dwHostNameLength = (ULONG)-1; - httpComponents.dwUrlPathLength = (ULONG)-1; - - if (!WinHttpCrackUrl( - PhGetStringOrEmpty(context->UploadUrl), - 0, - 0, - &httpComponents - )) - { - goto CleanupExit; - } - - // Create the Host string. - if (PhIsNullOrEmptyString(httpHostName = PhCreateStringEx( - httpComponents.lpszHostName, - httpComponents.dwHostNameLength * sizeof(WCHAR) - ))) - { - goto CleanupExit; - } - - // Create the Path string. - if (PhIsNullOrEmptyString(httpHostPath = PhCreateStringEx( - httpComponents.lpszUrlPath, - httpComponents.dwUrlPathLength * sizeof(WCHAR) - ))) - { - goto CleanupExit; - } - - if (!NT_SUCCESS(status = PhCreateFileWin32( - &fileHandle, - PhGetStringOrEmpty(context->FileName), - FILE_GENERIC_READ, - 0, - FILE_SHARE_READ | FILE_SHARE_DELETE, - FILE_OPEN, - FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT - ))) - { - RaiseUploadError(context, L"Unable to open the file", RtlNtStatusToDosError(status)); - goto CleanupExit; - } - - if (!(connectHandle = WinHttpConnect( - context->HttpHandle, - serviceInfo->HostName, - serviceInfo->HostPort, - 0 - ))) - { - RaiseUploadError(context, L"Unable to connect to the service", GetLastError()); - goto CleanupExit; - } - - if (!(requestHandle = WinHttpOpenRequest( - connectHandle, - L"POST", - PhGetStringOrEmpty(httpHostPath), - NULL, - WINHTTP_NO_REFERER, - WINHTTP_DEFAULT_ACCEPT_TYPES, - WINHTTP_FLAG_REFRESH | serviceInfo->HostFlags - ))) - { - RaiseUploadError(context, L"Unable to create the request", GetLastError()); - goto CleanupExit; - } - - PhInitializeStringBuilder(&httpRequestHeaders, DOS_MAX_PATH_LENGTH); - PhInitializeStringBuilder(&httpPostHeader, DOS_MAX_PATH_LENGTH); - PhInitializeStringBuilder(&httpPostFooter, DOS_MAX_PATH_LENGTH); - - // build request boundary string - postBoundary = PhFormatString( - L"------------------------%I64u", - (ULONG64)RtlRandomEx(&httpPostSeed) | ((ULONG64)RtlRandomEx(&httpPostSeed) << 31) - ); - - // build request header string - PhAppendFormatStringBuilder( - &httpRequestHeaders, - L"Content-Type: multipart/form-data; boundary=%s\r\n", - postBoundary->Buffer - ); - - if (context->Service == MENUITEM_JOTTI_UPLOAD) - { - // POST boundary header - PhAppendFormatStringBuilder( - &httpPostHeader, - L"\r\n--%s\r\n", - postBoundary->Buffer - ); - PhAppendFormatStringBuilder( - &httpPostHeader, - L"Content-Disposition: form-data; name=\"MAX_FILE_SIZE\"\r\n\r\n268435456\r\n" - ); - PhAppendFormatStringBuilder( - &httpPostHeader, - L"--%s\r\n", - postBoundary->Buffer - ); - PhAppendFormatStringBuilder( - &httpPostHeader, - L"Content-Disposition: form-data; name=\"%s\"; filename=\"%s\"\r\n", - serviceInfo->FileNameFieldName, - PhGetStringOrEmpty(context->BaseFileName) - ); - PhAppendFormatStringBuilder( - &httpPostHeader, - L"Content-Type: application/x-msdownload\r\n\r\n" - ); - - // POST boundary footer - PhAppendFormatStringBuilder( - &httpPostFooter, - L"\r\n--%s--\r\n", - postBoundary->Buffer - ); - } - else - { - // POST boundary header - PhAppendFormatStringBuilder( - &httpPostHeader, - L"--%s\r\n", - postBoundary->Buffer - ); - PhAppendFormatStringBuilder( - &httpPostHeader, - L"Content-Disposition: form-data; name=\"%s\"; filename=\"%s\"\r\n", - serviceInfo->FileNameFieldName, - PhGetStringOrEmpty(context->BaseFileName) - ); - PhAppendFormatStringBuilder( - &httpPostHeader, - L"Content-Type: application/octet-stream\r\n\r\n" - ); - - // POST boundary footer - PhAppendFormatStringBuilder( - &httpPostFooter, - L"\r\n--%s--\r\n\r\n", - postBoundary->Buffer - ); - } - - // add headers - if (!WinHttpAddRequestHeaders( - requestHandle, - httpRequestHeaders.String->Buffer, - -1L, - WINHTTP_ADDREQ_FLAG_REPLACE | WINHTTP_ADDREQ_FLAG_ADD - )) - { - RaiseUploadError(context, L"Unable to add request headers", GetLastError()); - goto CleanupExit; - } - - if (context->Service == MENUITEM_JOTTI_UPLOAD) - { - PPH_STRING ajaxHeader = PhCreateString(L"X-Requested-With: XMLHttpRequest"); - - WinHttpAddRequestHeaders( - requestHandle, - ajaxHeader->Buffer, - (ULONG)ajaxHeader->Length / sizeof(WCHAR), - WINHTTP_ADDREQ_FLAG_ADD - ); - - PhDereferenceObject(ajaxHeader); - } - - // Calculate the total request length. - totalUploadLength = (ULONG)httpPostHeader.String->Length / sizeof(WCHAR) + context->TotalFileLength + (ULONG)httpPostFooter.String->Length / sizeof(WCHAR); - - // Send the request. - if (!WinHttpSendRequest( - requestHandle, - WINHTTP_NO_ADDITIONAL_HEADERS, - 0, - WINHTTP_NO_REQUEST_DATA, - 0, - totalUploadLength, - 0 - )) - { - RaiseUploadError(context, L"Unable to send the request", GetLastError()); - goto CleanupExit; - } - - // Convert to ASCII - asciiPostData = PhConvertUtf16ToAscii(httpPostHeader.String->Buffer, '-'); - asciiFooterData = PhConvertUtf16ToAscii(httpPostFooter.String->Buffer, '-'); - - // Start the clock. - PhQuerySystemTime(&timeStart); - - // Write the header - if (!WinHttpWriteData( - requestHandle, - asciiPostData->Buffer, - (ULONG)asciiPostData->Length, - &totalPostHeaderWritten - )) - { - RaiseUploadError(context, L"Unable to write the post header", GetLastError()); - goto CleanupExit; - } - - PPH_STRING msg = PhFormatString(L"Uploading %s...", PhGetStringOrEmpty(context->BaseFileName)); - SendMessage(context->DialogHandle, TDM_SET_MARQUEE_PROGRESS_BAR, FALSE, 0); - SendMessage(context->DialogHandle, TDM_UPDATE_ELEMENT_TEXT, TDE_MAIN_INSTRUCTION, (LPARAM)PhGetString(msg)); - PhDereferenceObject(msg); - - if (context->TaskbarListClass) - { - ITaskbarList3_SetProgressState( - context->TaskbarListClass, - PhMainWndHandle, - TBPF_NORMAL - ); - } - - while (TRUE) - { - BYTE buffer[PAGE_SIZE]; - - if (!context->UploadThreadHandle) - goto CleanupExit; - - if (!NT_SUCCESS(status = NtReadFile( - fileHandle, - NULL, - NULL, - NULL, - &isb, - buffer, - PAGE_SIZE, - NULL, - NULL - ))) - { - break; - } - - if (!WinHttpWriteData(requestHandle, buffer, (ULONG)isb.Information, &totalWriteLength)) - { - RaiseUploadError(context, L"Unable to upload the file data", GetLastError()); - goto CleanupExit; - } - - PhQuerySystemTime(&timeNow); - - totalUploadedLength += totalWriteLength; - timeTicks = (timeNow.QuadPart - timeStart.QuadPart) / PH_TICKS_PER_SEC; - timeBitsPerSecond = totalUploadedLength / __max(timeTicks, 1); - - { - FLOAT percent = ((FLOAT)totalUploadedLength / context->TotalFileLength * 100); - PPH_STRING totalLength = PhFormatSize(context->TotalFileLength, -1); - PPH_STRING totalUploaded = PhFormatSize(totalUploadedLength, -1); - PPH_STRING totalSpeed = PhFormatSize(timeBitsPerSecond, -1); - PPH_STRING statusMessage = PhFormatString( - L"Uploaded: %s of %s (%.0f%%)\r\nSpeed: %s/s", - PhGetStringOrEmpty(totalUploaded), - PhGetStringOrEmpty(totalLength), - percent, - PhGetStringOrEmpty(totalSpeed) - ); - - SendMessage(context->DialogHandle, TDM_UPDATE_ELEMENT_TEXT, TDE_CONTENT, (LPARAM)statusMessage->Buffer); - SendMessage(context->DialogHandle, TDM_SET_PROGRESS_BAR_POS, (WPARAM)percent, 0); - - if (context->TaskbarListClass) - { - ITaskbarList3_SetProgressValue( - context->TaskbarListClass, - context->DialogHandle, - totalUploadedLength, - context->TotalFileLength - ); - } - - PhDereferenceObject(statusMessage); - PhDereferenceObject(totalSpeed); - PhDereferenceObject(totalUploaded); - PhDereferenceObject(totalLength); - } - } - - // Write the footer bytes - if (!WinHttpWriteData( - requestHandle, - asciiFooterData->Buffer, - (ULONG)asciiFooterData->Length, - &totalPostFooterWritten - )) - { - RaiseUploadError(context, L"Unable to write the post footer", GetLastError()); - goto CleanupExit; - } - - if (!WinHttpReceiveResponse(requestHandle, NULL)) - { - RaiseUploadError(context, L"Unable to receive the response", GetLastError()); - goto CleanupExit; - } - - if (!WinHttpQueryHeaders( - requestHandle, - WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, - NULL, - &httpStatus, - &httpStatusLength, - NULL - )) - { - RaiseUploadError(context, L"Unable to query http headers", GetLastError()); - goto CleanupExit; - } - - if (httpStatus == HTTP_STATUS_OK || httpStatus == HTTP_STATUS_REDIRECT_METHOD || httpStatus == HTTP_STATUS_REDIRECT) - { - switch (context->Service) - { - case MENUITEM_VIRUSTOTAL_UPLOAD: - { - PSTR buffer = NULL; - PSTR redirectUrl; - ULONG bufferLength; - PVOID jsonRootObject; - - if (!ReadRequestString(requestHandle, &buffer, &bufferLength)) - { - RaiseUploadError(context, L"Unable to complete the request", GetLastError()); - goto CleanupExit; - } - - if (jsonRootObject = CreateJsonParser(buffer)) - { - if (!GetJsonValueAsUlong(jsonRootObject, "response_code")) - goto CleanupExit; - - // PhZeroExtendToUtf16(GetJsonValueAsString(jsonRootObject, "resource")); - // PhZeroExtendToUtf16(GetJsonValueAsString(jsonRootObject, "scan_id")); - // PhZeroExtendToUtf16(GetJsonValueAsString(jsonRootObject, "sha256")); - // PhZeroExtendToUtf16(GetJsonValueAsString(jsonRootObject, "verbose_msg")); - - if (redirectUrl = GetJsonValueAsString(jsonRootObject, "permalink")) - { - PhMoveReference(&context->LaunchCommand, PhZeroExtendToUtf16(redirectUrl)); - } - - CleanupJsonParser(jsonRootObject); - } - else - { - ULONG httpUrlLength = 0; - - if (!WinHttpQueryOption(requestHandle, WINHTTP_OPTION_URL, NULL, &httpUrlLength)) - { - PPH_STRING httpUrlString = PhCreateStringEx(NULL, httpUrlLength); - - if (WinHttpQueryOption(requestHandle, WINHTTP_OPTION_URL, httpUrlString->Buffer, &httpUrlLength)) - { - PhSwapReference(&context->LaunchCommand, httpUrlString); - } - - PhDereferenceObject(httpUrlString); - } - } - } - break; - case MENUITEM_JOTTI_UPLOAD: - { - PSTR buffer = NULL; - PSTR redirectUrl; - ULONG bufferLength; - PVOID rootJsonObject; - - if (!ReadRequestString(requestHandle, &buffer, &bufferLength)) - { - RaiseUploadError(context, L"Unable to complete the request", GetLastError()); - goto CleanupExit; - } - - if (rootJsonObject = CreateJsonParser(buffer)) - { - if (redirectUrl = GetJsonValueAsString(rootJsonObject, "redirecturl")) - { - PhMoveReference(&context->LaunchCommand, PhFormatString(L"http://virusscan.jotti.org%hs", redirectUrl)); - } - - CleanupJsonParser(rootJsonObject); - } - } - break; - } - } - else - { - RaiseUploadError(context, L"Unable to complete the request", STATUS_FVE_PARTIAL_METADATA); - goto CleanupExit; - } - - if (!context->UploadThreadHandle) - goto CleanupExit; - - if (!PhIsNullOrEmptyString(context->LaunchCommand)) - { - PostMessage(context->DialogHandle, UM_LAUNCH, 0, 0); - } - else - { - RaiseUploadError(context, L"Unable to complete the Launch request (please try again after a few minutes)", ERROR_INVALID_DATA); - } - -CleanupExit: - - // Reset Taskbar progress state(s) - if (context->TaskbarListClass) - { - ITaskbarList3_SetProgressState(context->TaskbarListClass, PhMainWndHandle, TBPF_NOPROGRESS); - ITaskbarList3_SetProgressState(context->TaskbarListClass, context->DialogHandle, TBPF_NOPROGRESS); - } - - if (postBoundary) - PhDereferenceObject(postBoundary); - - if (asciiFooterData) - PhDereferenceObject(asciiFooterData); - - if (asciiPostData) - PhDereferenceObject(asciiPostData); - - if (httpPostFooter.String) - PhDeleteStringBuilder(&httpPostFooter); - - if (httpPostHeader.String) - PhDeleteStringBuilder(&httpPostHeader); - - if (httpRequestHeaders.String) - PhDeleteStringBuilder(&httpRequestHeaders); - - if (fileHandle) - NtClose(fileHandle); - - PhDereferenceObject(context); - - return status; -} - -NTSTATUS UploadCheckThreadStart( - _In_ PVOID Parameter - ) -{ - NTSTATUS status = STATUS_SUCCESS; - BOOLEAN fileExists = FALSE; - BOOLEAN success = FALSE; - LARGE_INTEGER fileSize64; - PPH_BYTES subRequestBuffer = NULL; - HINTERNET connectHandle = NULL; - HINTERNET requestHandle = NULL; - PSERVICE_INFO serviceInfo = NULL; - PPH_STRING hashString = NULL; - PPH_STRING subObjectName = NULL; - HANDLE fileHandle = NULL; - PPH_STRING phVersion = NULL; - PPH_STRING userAgent = NULL; - WINHTTP_CURRENT_USER_IE_PROXY_CONFIG proxyConfig = { 0 }; - PUPLOAD_CONTEXT context = (PUPLOAD_CONTEXT)Parameter; - - //context->Extension = VirusTotalGetCachedResult(context->FileName); - serviceInfo = GetUploadServiceInfo(context->Service); - - if (!NT_SUCCESS(status = PhCreateFileWin32( - &fileHandle, - context->FileName->Buffer, - FILE_GENERIC_READ, - 0, - FILE_SHARE_READ | FILE_SHARE_DELETE, - FILE_OPEN, - FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT - ))) - { - RaiseUploadError(context, L"Unable to open the file", RtlNtStatusToDosError(status)); - goto CleanupExit; - } - - if (NT_SUCCESS(status = PhGetFileSize(fileHandle, &fileSize64))) - { - if (context->Service == MENUITEM_VIRUSTOTAL_UPLOAD) - { - if (fileSize64.QuadPart < 32 * 1024 * 1024) - { - context->VtApiUpload = TRUE; - } - - if (fileSize64.QuadPart > 128 * 1024 * 1024) // 128 MB - { - RaiseUploadError(context, L"The file is too large (over 128 MB)", ERROR_FILE_TOO_LARGE); - goto CleanupExit; - } - } - else - { - if (fileSize64.QuadPart > 20 * 1024 * 1024) // 20 MB - { - RaiseUploadError(context, L"The file is too large (over 20 MB)", ERROR_FILE_TOO_LARGE); - goto CleanupExit; - } - } - - context->FileSize = PhFormatSize(fileSize64.QuadPart, -1); - context->TotalFileLength = fileSize64.LowPart; - } - - // Create a user agent string. - phVersion = PhGetPhVersion(); - userAgent = PhConcatStrings2(L"ProcessHacker_", phVersion->Buffer); - - WinHttpGetIEProxyConfigForCurrentUser(&proxyConfig); - - if (!(context->HttpHandle = WinHttpOpen( - userAgent->Buffer, - proxyConfig.lpszProxy ? WINHTTP_ACCESS_TYPE_NAMED_PROXY : WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, - proxyConfig.lpszProxy, - proxyConfig.lpszProxyBypass, - 0 - ))) - { - goto CleanupExit; - } - - if (WindowsVersion >= WINDOWS_8_1) - { - ULONG gzipFlags = WINHTTP_DECOMPRESSION_FLAG_ALL; - - WinHttpSetOption(context->HttpHandle, WINHTTP_OPTION_DECOMPRESSION, &gzipFlags, sizeof(ULONG)); - } - - switch (context->Service) - { - case MENUITEM_VIRUSTOTAL_UPLOAD: - { - PSTR uploadUrl = NULL; - PSTR quote = NULL; - PVOID rootJsonObject; - - if (!NT_SUCCESS(status = HashFileAndResetPosition(fileHandle, &fileSize64, Sha256HashAlgorithm, &hashString))) - { - RaiseUploadError(context, L"Unable to hash the file", RtlNtStatusToDosError(status)); - goto CleanupExit; - } - - subObjectName = PhConcatStrings2(L"/file/upload/?sha256=", hashString->Buffer); - - //if (PhIsNullOrEmptyString(context->KeyString)) - // Create the default launch URL - PhMoveReference(&context->LaunchCommand, PhFormatString( - L"https://www.virustotal.com/file/%s/analysis/", - PhGetString(hashString) - )); - - if (!(subRequestBuffer = PerformSubRequest( - context, - serviceInfo->HostName, - serviceInfo->HostPort, - serviceInfo->HostFlags, - subObjectName->Buffer - ))) - { - goto CleanupExit; - } - - if (rootJsonObject = CreateJsonParser(subRequestBuffer->Buffer)) - { - if (context->FileExists = GetJsonValueAsBool(rootJsonObject, "file_exists")) - { - INT64 detected = 0; - INT64 detectedMax = 0; - PVOID detectionRatio; - - if (detectionRatio = JsonGetObject(rootJsonObject, "detection_ratio")) - { - detected = GetJsonArrayUlong(detectionRatio, 0); - detectedMax = GetJsonArrayUlong(detectionRatio, 1); - } - - context->Detected = PhFormatString(L"%I64d", detected); - context->MaxDetected = PhFormatString(L"%I64d", detectedMax); - context->UploadUrl = PhZeroExtendToUtf16(GetJsonValueAsString(rootJsonObject, "upload_url")); - context->ReAnalyseUrl = PhZeroExtendToUtf16(GetJsonValueAsString(rootJsonObject, "reanalyse_url")); - context->LastAnalysisUrl = PhZeroExtendToUtf16(GetJsonValueAsString(rootJsonObject, "last_analysis_url")); - context->FirstAnalysisDate = PhZeroExtendToUtf16(GetJsonValueAsString(rootJsonObject, "first_analysis_date")); - context->LastAnalysisDate = PhZeroExtendToUtf16(GetJsonValueAsString(rootJsonObject, "last_analysis_date")); - context->LastAnalysisAgo = PhZeroExtendToUtf16(GetJsonValueAsString(rootJsonObject, "last_analysis_ago")); - - PhMoveReference(&context->FirstAnalysisDate, VirusTotalStringToTime(context->FirstAnalysisDate)); - PhMoveReference(&context->LastAnalysisDate, VirusTotalStringToTime(context->LastAnalysisDate)); - - if (!PhIsNullOrEmptyString(context->ReAnalyseUrl)) - { - PhMoveReference(&context->ReAnalyseUrl, PhFormatString( - L"%s%s", - L"https://www.virustotal.com/", - PhGetString(context->ReAnalyseUrl) - )); - } - - if (context->VtApiUpload && !PhIsNullOrEmptyString(context->KeyString)) - { - PhMoveReference(&context->UploadUrl, PhFormatString( - L"%s%s?apikey=%s&resource=%s", - L"https://www.virustotal.com/", - L"/vtapi/v2/file/scan", - PhGetString(context->KeyString), - PhGetString(hashString) - )); - } - - if (!PhIsNullOrEmptyString(context->UploadUrl)) - { - success = TRUE; - PostMessage(context->DialogHandle, UM_EXISTS, 0, 0); - } - } - else - { - context->UploadUrl = PhZeroExtendToUtf16(GetJsonValueAsString(rootJsonObject, "upload_url")); - - // No file found... Start the upload. - if (!PhIsNullOrEmptyString(context->UploadUrl)) - { - success = TRUE; - PostMessage(context->DialogHandle, UM_UPLOAD, 0, 0); - } - } - - CleanupJsonParser(rootJsonObject); - } - } - break; - case MENUITEM_JOTTI_UPLOAD: - { - // Create the default upload URL - context->UploadUrl = PhFormatString(L"https://virusscan.jotti.org%s", serviceInfo->UploadObjectName); - - // No file found... Start the upload. - if (!PhIsNullOrEmptyString(context->UploadUrl)) - { - success = TRUE; - PostMessage(context->DialogHandle, UM_UPLOAD, 0, 0); - } - } - break; - } - -CleanupExit: - - if (context->DialogHandle && !success) - { - PostMessage(context->DialogHandle, UM_ERROR, 0, 0); - } - - PhClearReference(&phVersion); - PhClearReference(&userAgent); - PhClearReference(&hashString); - PhClearReference(&subObjectName); - PhClearReference(&subRequestBuffer); - - if (requestHandle) - WinHttpCloseHandle(requestHandle); - - if (connectHandle) - WinHttpCloseHandle(connectHandle); - - if (fileHandle) - NtClose(fileHandle); - - PhDereferenceObject(context); - - return status; -} - -LRESULT CALLBACK TaskDialogSubclassProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam, - _In_ UINT_PTR uIdSubclass, - _In_ ULONG_PTR dwRefData - ) -{ - PUPLOAD_CONTEXT context = (PUPLOAD_CONTEXT)dwRefData; - - switch (uMsg) - { - case WM_NCDESTROY: - { - TaskDialogFreeContext(context); - - RemoveWindowSubclass(hwndDlg, TaskDialogSubclassProc, uIdSubclass); - } - break; - case UM_SHOWDIALOG: - { - if (IsMinimized(hwndDlg)) - ShowWindow(hwndDlg, SW_RESTORE); - else - ShowWindow(hwndDlg, SW_SHOW); - - SetForegroundWindow(hwndDlg); - } - break; - case UM_UPLOAD: - { - ShowVirusTotalProgressDialog(context); - } - break; - case UM_EXISTS: - { - ShowFileFoundDialog(context); - } - break; - case UM_LAUNCH: - { - if (!PhIsNullOrEmptyString(context->LaunchCommand)) - { - PhShellExecute(hwndDlg, context->LaunchCommand->Buffer, NULL); - } - - PostQuitMessage(0); - } - break; - case UM_ERROR: - { - VirusTotalShowErrorDialog(context); - } - break; - } - - return DefSubclassProc(hwndDlg, uMsg, wParam, lParam); -} - -HRESULT CALLBACK TaskDialogBootstrapCallback( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam, - _In_ LONG_PTR dwRefData - ) -{ - PUPLOAD_CONTEXT context = (PUPLOAD_CONTEXT)dwRefData; - - switch (uMsg) - { - case TDN_CREATED: - { - context->DialogHandle = hwndDlg; - - // Center the update window on PH if it's visible else we center on the desktop. - PhCenterWindow(hwndDlg, (IsWindowVisible(PhMainWndHandle) && !IsMinimized(PhMainWndHandle)) ? PhMainWndHandle : NULL); - - // Create the Taskdialog icons - TaskDialogCreateIcons(context); - - if (SUCCEEDED(CoCreateInstance(&CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, &IID_ITaskbarList3, &context->TaskbarListClass))) - { - if (!SUCCEEDED(ITaskbarList3_HrInit(context->TaskbarListClass))) - { - ITaskbarList3_Release(context->TaskbarListClass); - context->TaskbarListClass = NULL; - } - } - - // Subclass the Taskdialog - SetWindowSubclass(hwndDlg, TaskDialogSubclassProc, 0, (ULONG_PTR)context); - - ShowVirusTotalUploadDialog(context); - } - break; - } - - return S_OK; -} - -NTSTATUS ShowUpdateDialogThread( - _In_ PVOID Parameter - ) -{ - PH_AUTO_POOL autoPool; - TASKDIALOGCONFIG config = { sizeof(TASKDIALOGCONFIG) }; - PUPLOAD_CONTEXT context = (PUPLOAD_CONTEXT)Parameter; - BOOL checked = FALSE; - - PhInitializeAutoPool(&autoPool); - - config.dwFlags = TDF_ALLOW_DIALOG_CANCELLATION | TDF_CAN_BE_MINIMIZED; - config.pszContent = L"Initializing..."; - config.lpCallbackData = (LONG_PTR)context; - config.pfCallback = TaskDialogBootstrapCallback; - - // Start TaskDialog bootstrap - TaskDialogIndirect(&config, NULL, NULL, &checked); - - PhDeleteAutoPool(&autoPool); - - return STATUS_SUCCESS; -} - -VOID UploadToOnlineService( - _In_ PPH_STRING FileName, - _In_ ULONG Service - ) -{ - static PH_INITONCE initOnce = PH_INITONCE_INIT; - - HANDLE dialogThread; - PUPLOAD_CONTEXT context; - - if (PhBeginInitOnce(&initOnce)) - { - UploadContextType = PhCreateObjectType(L"OnlineChecksObjectType", 0, UploadContextDeleteProcedure); - PhEndInitOnce(&initOnce); - } - - context = (PUPLOAD_CONTEXT)PhCreateObject(sizeof(UPLOAD_CONTEXT), UploadContextType); - memset(context, 0, sizeof(UPLOAD_CONTEXT)); - - PhReferenceObject(FileName); - context->Service = Service; - context->FileName = FileName; - context->BaseFileName = PhGetBaseName(context->FileName); - context->KeyString = PhCreateString(VIRUSTOTAL_APIKEY); - - if (dialogThread = PhCreateThread(0, ShowUpdateDialogThread, (PVOID)context)) - { - PostMessage(dialogThread, UM_SHOWDIALOG, 0, 0); - NtClose(dialogThread); - } -} +/* + * Process Hacker Plugins - + * Online Checks Plugin + * + * Copyright (C) 2016 dmex + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include "onlnchk.h" +#include +#include + +PPH_OBJECT_TYPE UploadContextType = NULL; +SERVICE_INFO UploadServiceInfo[] = +{ + { MENUITEM_VIRUSTOTAL_UPLOAD, L"www.virustotal.com", INTERNET_DEFAULT_HTTPS_PORT, WINHTTP_FLAG_SECURE, L"???", L"file" }, + { MENUITEM_JOTTI_UPLOAD, L"virusscan.jotti.org", INTERNET_DEFAULT_HTTPS_PORT, WINHTTP_FLAG_SECURE, L"/en-US/submit-file?isAjax=true", L"sample-file[]" }, +}; + +BOOL ReadRequestString( + _In_ HINTERNET Handle, + _Out_ _Deref_post_z_cap_(*DataLength) PSTR *Data, + _Out_ ULONG *DataLength + ) +{ + BYTE buffer[PAGE_SIZE]; + PSTR data; + ULONG allocatedLength; + ULONG dataLength; + ULONG returnLength; + + allocatedLength = sizeof(buffer); + data = (PSTR)PhAllocate(allocatedLength); + dataLength = 0; + + // Zero the buffer + memset(buffer, 0, PAGE_SIZE); + + while (WinHttpReadData(Handle, buffer, PAGE_SIZE, &returnLength)) + { + if (returnLength == 0) + break; + + if (allocatedLength < dataLength + returnLength) + { + allocatedLength *= 2; + data = (PSTR)PhReAllocate(data, allocatedLength); + } + + // Copy the returned buffer into our pointer + memcpy(data + dataLength, buffer, returnLength); + // Zero the returned buffer for the next loop + //memset(buffer, 0, returnLength); + + dataLength += returnLength; + } + + if (allocatedLength < dataLength + 1) + { + allocatedLength++; + data = (PSTR)PhReAllocate(data, allocatedLength); + } + + // Ensure that the buffer is null-terminated. + data[dataLength] = 0; + + *DataLength = dataLength; + *Data = data; + + return TRUE; +} + +VOID RaiseUploadError( + _In_ PUPLOAD_CONTEXT Context, + _In_ PWSTR Error, + _In_ ULONG ErrorCode + ) +{ + PWSTR errorMessage = NULL; + PPH_STRING message; + + if (!Context->DialogHandle) + return; + + if (message = PhGetMessage(GetModuleHandle(L"winhttp.dll"), 0xb, GetUserDefaultLangID(), ErrorCode)) + { + PhTrimToNullTerminatorString(message); + } + + // Remove any trailing newline + if (message && message->Length >= 2 * sizeof(WCHAR) && + message->Buffer[message->Length / sizeof(WCHAR) - 2] == '\r' && + message->Buffer[message->Length / sizeof(WCHAR) - 1] == '\n') + { + PhMoveReference(&message, PhCreateStringEx(message->Buffer, message->Length - 2 * sizeof(WCHAR))); + } + + if (message) + { + PhMoveReference(&Context->ErrorString, PhFormatString( + L"[%lu] %s", + ErrorCode, + PhGetString(message) + )); + + PhDereferenceObject(message); + } + else + { + PhMoveReference(&Context->ErrorString, PhFormatString( + L"[%lu] %s", + ErrorCode, + Error + )); + } + + PostMessage(Context->DialogHandle, UM_ERROR, 0, 0); + +} + +PSERVICE_INFO GetUploadServiceInfo( + _In_ ULONG Id + ) +{ + ULONG i; + + for (i = 0; i < ARRAYSIZE(UploadServiceInfo); i++) + { + if (UploadServiceInfo[i].Id == Id) + return &UploadServiceInfo[i]; + } + + return NULL; +} + +VOID UploadContextDeleteProcedure( + _In_ PVOID Object, + _In_ ULONG Flags + ) +{ + PUPLOAD_CONTEXT context = Object; + + if (context->TaskbarListClass) + { + ITaskbarList3_Release(context->TaskbarListClass); + context->TaskbarListClass = NULL; + } + + if (context->UploadThreadHandle) + { + NtClose(context->UploadThreadHandle); + context->UploadThreadHandle = NULL; + } + + if (context->HttpHandle) + { + WinHttpCloseHandle(context->HttpHandle); + context->HttpHandle = NULL; + } + + if (context->IconLargeHandle) + { + DestroyIcon(context->IconLargeHandle); + context->IconLargeHandle = NULL; + } + + if (context->IconSmallHandle) + { + DestroyIcon(context->IconSmallHandle); + context->IconSmallHandle = NULL; + } + + PhClearReference(&context->ErrorString); + PhClearReference(&context->KeyString); + PhClearReference(&context->FileName); + PhClearReference(&context->BaseFileName); + PhClearReference(&context->WindowFileName); + PhClearReference(&context->LaunchCommand); + PhClearReference(&context->Detected); + PhClearReference(&context->MaxDetected); + PhClearReference(&context->UploadUrl); + PhClearReference(&context->ReAnalyseUrl); + PhClearReference(&context->FirstAnalysisDate); + PhClearReference(&context->LastAnalysisDate); + PhClearReference(&context->LastAnalysisUrl); + PhClearReference(&context->LastAnalysisAgo); +} + +VOID TaskDialogFreeContext( + _In_ PUPLOAD_CONTEXT Context + ) +{ + // Reset Taskbar progress state(s) + if (Context->TaskbarListClass) + ITaskbarList3_SetProgressState(Context->TaskbarListClass, PhMainWndHandle, TBPF_NOPROGRESS); + + if (Context->TaskbarListClass) + ITaskbarList3_SetProgressState(Context->TaskbarListClass, Context->DialogHandle, TBPF_NOPROGRESS); + + PhDereferenceObject(Context); +} + +VOID TaskDialogCreateIcons( + _In_ PUPLOAD_CONTEXT Context + ) +{ + Context->IconLargeHandle = PhLoadIcon( + NtCurrentPeb()->ImageBaseAddress, + MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER), + PH_LOAD_ICON_SIZE_LARGE, + GetSystemMetrics(SM_CXICON), + GetSystemMetrics(SM_CYICON) + ); + Context->IconSmallHandle = PhLoadIcon( + NtCurrentPeb()->ImageBaseAddress, + MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER), + PH_LOAD_ICON_SIZE_LARGE, + GetSystemMetrics(SM_CXICON), + GetSystemMetrics(SM_CYICON) + ); + + SendMessage(Context->DialogHandle, WM_SETICON, ICON_SMALL, (LPARAM)Context->IconSmallHandle); + SendMessage(Context->DialogHandle, WM_SETICON, ICON_BIG, (LPARAM)Context->IconLargeHandle); +} + +PPH_STRING UpdateVersionString( + VOID + ) +{ + ULONG majorVersion; + ULONG minorVersion; + ULONG revisionVersion; + PPH_STRING currentVersion; + PPH_STRING versionHeader = NULL; + + PhGetPhVersionNumbers(&majorVersion, &minorVersion, NULL, &revisionVersion); + + if (currentVersion = PhFormatString(L"%lu.%lu.%lu", majorVersion, minorVersion, revisionVersion)) + { + versionHeader = PhConcatStrings2(L"ProcessHacker-Build: ", currentVersion->Buffer); + PhDereferenceObject(currentVersion); + } + + return versionHeader; +} + +NTSTATUS HashFileAndResetPosition( + _In_ HANDLE FileHandle, + _In_ PLARGE_INTEGER FileSize, + _In_ PH_HASH_ALGORITHM Algorithm, + _Out_ PPH_STRING *HashString + ) +{ + NTSTATUS status; + IO_STATUS_BLOCK iosb; + PH_HASH_CONTEXT hashContext; + PPH_STRING hashString = NULL; + ULONG64 bytesRemaining; + FILE_POSITION_INFORMATION positionInfo; + LONG priority; + LONG newpriority; + IO_PRIORITY_HINT ioPriority; + IO_PRIORITY_HINT newioPriority; + UCHAR buffer[PAGE_SIZE]; + + bytesRemaining = FileSize->QuadPart; + + newpriority = THREAD_PRIORITY_LOWEST; + newioPriority = IoPriorityVeryLow; + NtQueryInformationThread(NtCurrentThread(), ThreadBasePriority, &priority, sizeof(LONG), NULL); + NtQueryInformationThread(NtCurrentThread(), ThreadIoPriority, &ioPriority, sizeof(IO_PRIORITY_HINT), NULL); + NtSetInformationThread(NtCurrentThread(), ThreadBasePriority, &newpriority, sizeof(LONG)); + NtSetInformationThread(NtCurrentThread(), ThreadIoPriority, &newioPriority, sizeof(IO_PRIORITY_HINT)); + + PhInitializeHash(&hashContext, Algorithm); + + while (bytesRemaining) + { + status = NtReadFile( + FileHandle, + NULL, + NULL, + NULL, + &iosb, + buffer, + sizeof(buffer), + NULL, + NULL + ); + + if (!NT_SUCCESS(status)) + break; + + PhUpdateHash(&hashContext, buffer, (ULONG)iosb.Information); + bytesRemaining -= (ULONG)iosb.Information; + } + + if (status == STATUS_END_OF_FILE) + status = STATUS_SUCCESS; + + if (NT_SUCCESS(status)) + { + UCHAR hash[32]; + + switch (Algorithm) + { + case Md5HashAlgorithm: + PhFinalHash(&hashContext, hash, 16, NULL); + *HashString = PhBufferToHexString(hash, 16); + break; + case Sha1HashAlgorithm: + PhFinalHash(&hashContext, hash, 20, NULL); + *HashString = PhBufferToHexString(hash, 20); + break; + case Sha256HashAlgorithm: + PhFinalHash(&hashContext, hash, 32, NULL); + *HashString = PhBufferToHexString(hash, 32); + break; + } + + positionInfo.CurrentByteOffset.QuadPart = 0; + status = NtSetInformationFile( + FileHandle, + &iosb, + &positionInfo, + sizeof(FILE_POSITION_INFORMATION), + FilePositionInformation + ); + } + + NtSetInformationThread(NtCurrentThread(), ThreadBasePriority, &priority, sizeof(LONG)); + NtSetInformationThread(NtCurrentThread(), ThreadIoPriority, &ioPriority, sizeof(IO_PRIORITY_HINT)); + + return status; +} + +PPH_BYTES PerformSubRequest( + _In_ PUPLOAD_CONTEXT Context, + _In_ PWSTR HostName, + _In_ INTERNET_PORT HostPort, + _In_ ULONG HostFlags, + _In_ PWSTR ObjectName + ) +{ + PPH_BYTES result = NULL; + HINTERNET connectHandle = NULL; + HINTERNET requestHandle = NULL; + + if (!(connectHandle = WinHttpConnect( + Context->HttpHandle, + HostName, + HostPort, + 0 + ))) + { + RaiseUploadError(Context, L"Unable to connect to the service", GetLastError()); + goto CleanupExit; + } + + if (!(requestHandle = WinHttpOpenRequest( + connectHandle, + NULL, + ObjectName, + NULL, + WINHTTP_NO_REFERER, + WINHTTP_DEFAULT_ACCEPT_TYPES, + WINHTTP_FLAG_REFRESH | HostFlags + ))) + { + RaiseUploadError(Context, L"Unable to create the request", GetLastError()); + goto CleanupExit; + } + + if (!WinHttpSendRequest( + requestHandle, + WINHTTP_NO_ADDITIONAL_HEADERS, + 0, + WINHTTP_NO_REQUEST_DATA, + 0, + WINHTTP_IGNORE_REQUEST_TOTAL_LENGTH, + 0 + )) + { + RaiseUploadError(Context, L"Unable to send the request", GetLastError()); + goto CleanupExit; + } + + if (WinHttpReceiveResponse(requestHandle, NULL)) + { + PSTR data; + ULONG allocatedLength; + ULONG dataLength; + ULONG returnLength; + BYTE buffer[PAGE_SIZE]; + + allocatedLength = sizeof(buffer); + data = PhAllocate(allocatedLength); + dataLength = 0; + + while (WinHttpReadData(requestHandle, buffer, PAGE_SIZE, &returnLength)) + { + if (returnLength == 0) + break; + + if (allocatedLength < dataLength + returnLength) + { + allocatedLength *= 2; + data = PhReAllocate(data, allocatedLength); + } + + memcpy(data + dataLength, buffer, returnLength); + dataLength += returnLength; + } + + if (allocatedLength < dataLength + 1) + { + allocatedLength++; + data = PhReAllocate(data, allocatedLength); + } + + data[dataLength] = 0; + + result = PhCreateBytesEx(data, dataLength); + } + else + { + RaiseUploadError(Context, L"Unable to receive the response", GetLastError()); + goto CleanupExit; + } + +CleanupExit: + + if (requestHandle) + WinHttpCloseHandle(requestHandle); + + if (connectHandle) + WinHttpCloseHandle(connectHandle); + + return result; +} + +NTSTATUS UploadFileThreadStart( + _In_ PVOID Parameter + ) +{ + NTSTATUS status = STATUS_SUCCESS; + ULONG httpStatus = 0; + ULONG httpStatusLength = sizeof(ULONG); + ULONG httpPostSeed = 0; + ULONG totalUploadLength = 0; + ULONG totalUploadedLength = 0; + ULONG totalPostHeaderWritten = 0; + ULONG totalPostFooterWritten = 0; + ULONG totalWriteLength = 0; + LARGE_INTEGER timeNow; + LARGE_INTEGER timeStart; + ULONG64 timeTicks = 0; + ULONG64 timeBitsPerSecond = 0; + HANDLE fileHandle = NULL; + HINTERNET connectHandle = NULL; + HINTERNET requestHandle = NULL; + IO_STATUS_BLOCK isb; + URL_COMPONENTS httpComponents = { sizeof(URL_COMPONENTS) }; + PPH_STRING httpHostName = NULL; + PPH_STRING httpHostPath = NULL; + PSERVICE_INFO serviceInfo = NULL; + PPH_STRING postBoundary = NULL; + PPH_BYTES asciiPostData = NULL; + PPH_BYTES asciiFooterData = NULL; + PH_STRING_BUILDER httpRequestHeaders = { 0 }; + PH_STRING_BUILDER httpPostHeader = { 0 }; + PH_STRING_BUILDER httpPostFooter = { 0 }; + PUPLOAD_CONTEXT context = (PUPLOAD_CONTEXT)Parameter; + + serviceInfo = GetUploadServiceInfo(context->Service); + + // Set lengths to non-zero enabling these params to be cracked. + httpComponents.dwSchemeLength = (ULONG)-1; + httpComponents.dwHostNameLength = (ULONG)-1; + httpComponents.dwUrlPathLength = (ULONG)-1; + + if (!WinHttpCrackUrl( + PhGetStringOrEmpty(context->UploadUrl), + 0, + 0, + &httpComponents + )) + { + goto CleanupExit; + } + + // Create the Host string. + if (PhIsNullOrEmptyString(httpHostName = PhCreateStringEx( + httpComponents.lpszHostName, + httpComponents.dwHostNameLength * sizeof(WCHAR) + ))) + { + goto CleanupExit; + } + + // Create the Path string. + if (PhIsNullOrEmptyString(httpHostPath = PhCreateStringEx( + httpComponents.lpszUrlPath, + httpComponents.dwUrlPathLength * sizeof(WCHAR) + ))) + { + goto CleanupExit; + } + + if (!NT_SUCCESS(status = PhCreateFileWin32( + &fileHandle, + PhGetStringOrEmpty(context->FileName), + FILE_GENERIC_READ, + 0, + FILE_SHARE_READ | FILE_SHARE_DELETE, + FILE_OPEN, + FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT + ))) + { + RaiseUploadError(context, L"Unable to open the file", RtlNtStatusToDosError(status)); + goto CleanupExit; + } + + if (!(connectHandle = WinHttpConnect( + context->HttpHandle, + serviceInfo->HostName, + serviceInfo->HostPort, + 0 + ))) + { + RaiseUploadError(context, L"Unable to connect to the service", GetLastError()); + goto CleanupExit; + } + + if (!(requestHandle = WinHttpOpenRequest( + connectHandle, + L"POST", + PhGetStringOrEmpty(httpHostPath), + NULL, + WINHTTP_NO_REFERER, + WINHTTP_DEFAULT_ACCEPT_TYPES, + WINHTTP_FLAG_REFRESH | serviceInfo->HostFlags + ))) + { + RaiseUploadError(context, L"Unable to create the request", GetLastError()); + goto CleanupExit; + } + + PhInitializeStringBuilder(&httpRequestHeaders, DOS_MAX_PATH_LENGTH); + PhInitializeStringBuilder(&httpPostHeader, DOS_MAX_PATH_LENGTH); + PhInitializeStringBuilder(&httpPostFooter, DOS_MAX_PATH_LENGTH); + + // build request boundary string + postBoundary = PhFormatString( + L"------------------------%I64u", + (ULONG64)RtlRandomEx(&httpPostSeed) | ((ULONG64)RtlRandomEx(&httpPostSeed) << 31) + ); + + // build request header string + PhAppendFormatStringBuilder( + &httpRequestHeaders, + L"Content-Type: multipart/form-data; boundary=%s\r\n", + postBoundary->Buffer + ); + + if (context->Service == MENUITEM_JOTTI_UPLOAD) + { + // POST boundary header + PhAppendFormatStringBuilder( + &httpPostHeader, + L"\r\n--%s\r\n", + postBoundary->Buffer + ); + PhAppendFormatStringBuilder( + &httpPostHeader, + L"Content-Disposition: form-data; name=\"MAX_FILE_SIZE\"\r\n\r\n268435456\r\n" + ); + PhAppendFormatStringBuilder( + &httpPostHeader, + L"--%s\r\n", + postBoundary->Buffer + ); + PhAppendFormatStringBuilder( + &httpPostHeader, + L"Content-Disposition: form-data; name=\"%s\"; filename=\"%s\"\r\n", + serviceInfo->FileNameFieldName, + PhGetStringOrEmpty(context->BaseFileName) + ); + PhAppendFormatStringBuilder( + &httpPostHeader, + L"Content-Type: application/x-msdownload\r\n\r\n" + ); + + // POST boundary footer + PhAppendFormatStringBuilder( + &httpPostFooter, + L"\r\n--%s--\r\n", + postBoundary->Buffer + ); + } + else + { + // POST boundary header + PhAppendFormatStringBuilder( + &httpPostHeader, + L"--%s\r\n", + postBoundary->Buffer + ); + PhAppendFormatStringBuilder( + &httpPostHeader, + L"Content-Disposition: form-data; name=\"%s\"; filename=\"%s\"\r\n", + serviceInfo->FileNameFieldName, + PhGetStringOrEmpty(context->BaseFileName) + ); + PhAppendFormatStringBuilder( + &httpPostHeader, + L"Content-Type: application/octet-stream\r\n\r\n" + ); + + // POST boundary footer + PhAppendFormatStringBuilder( + &httpPostFooter, + L"\r\n--%s--\r\n\r\n", + postBoundary->Buffer + ); + } + + // add headers + if (!WinHttpAddRequestHeaders( + requestHandle, + httpRequestHeaders.String->Buffer, + -1L, + WINHTTP_ADDREQ_FLAG_REPLACE | WINHTTP_ADDREQ_FLAG_ADD + )) + { + RaiseUploadError(context, L"Unable to add request headers", GetLastError()); + goto CleanupExit; + } + + if (context->Service == MENUITEM_JOTTI_UPLOAD) + { + PPH_STRING ajaxHeader = PhCreateString(L"X-Requested-With: XMLHttpRequest"); + + WinHttpAddRequestHeaders( + requestHandle, + ajaxHeader->Buffer, + (ULONG)ajaxHeader->Length / sizeof(WCHAR), + WINHTTP_ADDREQ_FLAG_ADD + ); + + PhDereferenceObject(ajaxHeader); + } + + // Calculate the total request length. + totalUploadLength = (ULONG)httpPostHeader.String->Length / sizeof(WCHAR) + context->TotalFileLength + (ULONG)httpPostFooter.String->Length / sizeof(WCHAR); + + // Send the request. + if (!WinHttpSendRequest( + requestHandle, + WINHTTP_NO_ADDITIONAL_HEADERS, + 0, + WINHTTP_NO_REQUEST_DATA, + 0, + totalUploadLength, + 0 + )) + { + RaiseUploadError(context, L"Unable to send the request", GetLastError()); + goto CleanupExit; + } + + // Convert to ASCII + asciiPostData = PhConvertUtf16ToAscii(httpPostHeader.String->Buffer, '-'); + asciiFooterData = PhConvertUtf16ToAscii(httpPostFooter.String->Buffer, '-'); + + // Start the clock. + PhQuerySystemTime(&timeStart); + + // Write the header + if (!WinHttpWriteData( + requestHandle, + asciiPostData->Buffer, + (ULONG)asciiPostData->Length, + &totalPostHeaderWritten + )) + { + RaiseUploadError(context, L"Unable to write the post header", GetLastError()); + goto CleanupExit; + } + + PPH_STRING msg = PhFormatString(L"Uploading %s...", PhGetStringOrEmpty(context->BaseFileName)); + SendMessage(context->DialogHandle, TDM_SET_MARQUEE_PROGRESS_BAR, FALSE, 0); + SendMessage(context->DialogHandle, TDM_UPDATE_ELEMENT_TEXT, TDE_MAIN_INSTRUCTION, (LPARAM)PhGetString(msg)); + PhDereferenceObject(msg); + + if (context->TaskbarListClass) + { + ITaskbarList3_SetProgressState( + context->TaskbarListClass, + PhMainWndHandle, + TBPF_NORMAL + ); + } + + while (TRUE) + { + BYTE buffer[PAGE_SIZE]; + + if (!context->UploadThreadHandle) + goto CleanupExit; + + if (!NT_SUCCESS(status = NtReadFile( + fileHandle, + NULL, + NULL, + NULL, + &isb, + buffer, + PAGE_SIZE, + NULL, + NULL + ))) + { + break; + } + + if (!WinHttpWriteData(requestHandle, buffer, (ULONG)isb.Information, &totalWriteLength)) + { + RaiseUploadError(context, L"Unable to upload the file data", GetLastError()); + goto CleanupExit; + } + + PhQuerySystemTime(&timeNow); + + totalUploadedLength += totalWriteLength; + timeTicks = (timeNow.QuadPart - timeStart.QuadPart) / PH_TICKS_PER_SEC; + timeBitsPerSecond = totalUploadedLength / __max(timeTicks, 1); + + { + FLOAT percent = ((FLOAT)totalUploadedLength / context->TotalFileLength * 100); + PPH_STRING totalLength = PhFormatSize(context->TotalFileLength, -1); + PPH_STRING totalUploaded = PhFormatSize(totalUploadedLength, -1); + PPH_STRING totalSpeed = PhFormatSize(timeBitsPerSecond, -1); + PPH_STRING statusMessage = PhFormatString( + L"Uploaded: %s of %s (%.0f%%)\r\nSpeed: %s/s", + PhGetStringOrEmpty(totalUploaded), + PhGetStringOrEmpty(totalLength), + percent, + PhGetStringOrEmpty(totalSpeed) + ); + + SendMessage(context->DialogHandle, TDM_UPDATE_ELEMENT_TEXT, TDE_CONTENT, (LPARAM)statusMessage->Buffer); + SendMessage(context->DialogHandle, TDM_SET_PROGRESS_BAR_POS, (WPARAM)percent, 0); + + if (context->TaskbarListClass) + { + ITaskbarList3_SetProgressValue( + context->TaskbarListClass, + context->DialogHandle, + totalUploadedLength, + context->TotalFileLength + ); + } + + PhDereferenceObject(statusMessage); + PhDereferenceObject(totalSpeed); + PhDereferenceObject(totalUploaded); + PhDereferenceObject(totalLength); + } + } + + // Write the footer bytes + if (!WinHttpWriteData( + requestHandle, + asciiFooterData->Buffer, + (ULONG)asciiFooterData->Length, + &totalPostFooterWritten + )) + { + RaiseUploadError(context, L"Unable to write the post footer", GetLastError()); + goto CleanupExit; + } + + if (!WinHttpReceiveResponse(requestHandle, NULL)) + { + RaiseUploadError(context, L"Unable to receive the response", GetLastError()); + goto CleanupExit; + } + + if (!WinHttpQueryHeaders( + requestHandle, + WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, + NULL, + &httpStatus, + &httpStatusLength, + NULL + )) + { + RaiseUploadError(context, L"Unable to query http headers", GetLastError()); + goto CleanupExit; + } + + if (httpStatus == HTTP_STATUS_OK || httpStatus == HTTP_STATUS_REDIRECT_METHOD || httpStatus == HTTP_STATUS_REDIRECT) + { + switch (context->Service) + { + case MENUITEM_VIRUSTOTAL_UPLOAD: + { + PSTR buffer = NULL; + PSTR redirectUrl; + ULONG bufferLength; + PVOID jsonRootObject; + + if (!ReadRequestString(requestHandle, &buffer, &bufferLength)) + { + RaiseUploadError(context, L"Unable to complete the request", GetLastError()); + goto CleanupExit; + } + + if (jsonRootObject = CreateJsonParser(buffer)) + { + if (!GetJsonValueAsUlong(jsonRootObject, "response_code")) + goto CleanupExit; + + // PhZeroExtendToUtf16(GetJsonValueAsString(jsonRootObject, "resource")); + // PhZeroExtendToUtf16(GetJsonValueAsString(jsonRootObject, "scan_id")); + // PhZeroExtendToUtf16(GetJsonValueAsString(jsonRootObject, "sha256")); + // PhZeroExtendToUtf16(GetJsonValueAsString(jsonRootObject, "verbose_msg")); + + if (redirectUrl = GetJsonValueAsString(jsonRootObject, "permalink")) + { + PhMoveReference(&context->LaunchCommand, PhZeroExtendToUtf16(redirectUrl)); + } + + CleanupJsonParser(jsonRootObject); + } + else + { + ULONG httpUrlLength = 0; + + if (!WinHttpQueryOption(requestHandle, WINHTTP_OPTION_URL, NULL, &httpUrlLength)) + { + PPH_STRING httpUrlString = PhCreateStringEx(NULL, httpUrlLength); + + if (WinHttpQueryOption(requestHandle, WINHTTP_OPTION_URL, httpUrlString->Buffer, &httpUrlLength)) + { + PhSwapReference(&context->LaunchCommand, httpUrlString); + } + + PhDereferenceObject(httpUrlString); + } + } + } + break; + case MENUITEM_JOTTI_UPLOAD: + { + PSTR buffer = NULL; + PSTR redirectUrl; + ULONG bufferLength; + PVOID rootJsonObject; + + if (!ReadRequestString(requestHandle, &buffer, &bufferLength)) + { + RaiseUploadError(context, L"Unable to complete the request", GetLastError()); + goto CleanupExit; + } + + if (rootJsonObject = CreateJsonParser(buffer)) + { + if (redirectUrl = GetJsonValueAsString(rootJsonObject, "redirecturl")) + { + PhMoveReference(&context->LaunchCommand, PhFormatString(L"http://virusscan.jotti.org%hs", redirectUrl)); + } + + CleanupJsonParser(rootJsonObject); + } + } + break; + } + } + else + { + RaiseUploadError(context, L"Unable to complete the request", STATUS_FVE_PARTIAL_METADATA); + goto CleanupExit; + } + + if (!context->UploadThreadHandle) + goto CleanupExit; + + if (!PhIsNullOrEmptyString(context->LaunchCommand)) + { + PostMessage(context->DialogHandle, UM_LAUNCH, 0, 0); + } + else + { + RaiseUploadError(context, L"Unable to complete the Launch request (please try again after a few minutes)", ERROR_INVALID_DATA); + } + +CleanupExit: + + // Reset Taskbar progress state(s) + if (context->TaskbarListClass) + { + ITaskbarList3_SetProgressState(context->TaskbarListClass, PhMainWndHandle, TBPF_NOPROGRESS); + ITaskbarList3_SetProgressState(context->TaskbarListClass, context->DialogHandle, TBPF_NOPROGRESS); + } + + if (postBoundary) + PhDereferenceObject(postBoundary); + + if (asciiFooterData) + PhDereferenceObject(asciiFooterData); + + if (asciiPostData) + PhDereferenceObject(asciiPostData); + + if (httpPostFooter.String) + PhDeleteStringBuilder(&httpPostFooter); + + if (httpPostHeader.String) + PhDeleteStringBuilder(&httpPostHeader); + + if (httpRequestHeaders.String) + PhDeleteStringBuilder(&httpRequestHeaders); + + if (fileHandle) + NtClose(fileHandle); + + PhDereferenceObject(context); + + return status; +} + +NTSTATUS UploadCheckThreadStart( + _In_ PVOID Parameter + ) +{ + NTSTATUS status = STATUS_SUCCESS; + BOOLEAN fileExists = FALSE; + BOOLEAN success = FALSE; + LARGE_INTEGER fileSize64; + PPH_BYTES subRequestBuffer = NULL; + HINTERNET connectHandle = NULL; + HINTERNET requestHandle = NULL; + PSERVICE_INFO serviceInfo = NULL; + PPH_STRING hashString = NULL; + PPH_STRING subObjectName = NULL; + HANDLE fileHandle = NULL; + PPH_STRING phVersion = NULL; + PPH_STRING userAgent = NULL; + WINHTTP_CURRENT_USER_IE_PROXY_CONFIG proxyConfig = { 0 }; + PUPLOAD_CONTEXT context = (PUPLOAD_CONTEXT)Parameter; + + //context->Extension = VirusTotalGetCachedResult(context->FileName); + serviceInfo = GetUploadServiceInfo(context->Service); + + if (!NT_SUCCESS(status = PhCreateFileWin32( + &fileHandle, + context->FileName->Buffer, + FILE_GENERIC_READ, + 0, + FILE_SHARE_READ | FILE_SHARE_DELETE, + FILE_OPEN, + FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT + ))) + { + RaiseUploadError(context, L"Unable to open the file", RtlNtStatusToDosError(status)); + goto CleanupExit; + } + + if (NT_SUCCESS(status = PhGetFileSize(fileHandle, &fileSize64))) + { + if (context->Service == MENUITEM_VIRUSTOTAL_UPLOAD) + { + if (fileSize64.QuadPart < 32 * 1024 * 1024) + { + context->VtApiUpload = TRUE; + } + + if (fileSize64.QuadPart > 128 * 1024 * 1024) // 128 MB + { + RaiseUploadError(context, L"The file is too large (over 128 MB)", ERROR_FILE_TOO_LARGE); + goto CleanupExit; + } + } + else + { + if (fileSize64.QuadPart > 20 * 1024 * 1024) // 20 MB + { + RaiseUploadError(context, L"The file is too large (over 20 MB)", ERROR_FILE_TOO_LARGE); + goto CleanupExit; + } + } + + context->FileSize = PhFormatSize(fileSize64.QuadPart, -1); + context->TotalFileLength = fileSize64.LowPart; + } + + // Create a user agent string. + phVersion = PhGetPhVersion(); + userAgent = PhConcatStrings2(L"ProcessHacker_", phVersion->Buffer); + + WinHttpGetIEProxyConfigForCurrentUser(&proxyConfig); + + if (!(context->HttpHandle = WinHttpOpen( + userAgent->Buffer, + proxyConfig.lpszProxy ? WINHTTP_ACCESS_TYPE_NAMED_PROXY : WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, + proxyConfig.lpszProxy, + proxyConfig.lpszProxyBypass, + 0 + ))) + { + goto CleanupExit; + } + + if (WindowsVersion >= WINDOWS_8_1) + { + ULONG gzipFlags = WINHTTP_DECOMPRESSION_FLAG_ALL; + + WinHttpSetOption(context->HttpHandle, WINHTTP_OPTION_DECOMPRESSION, &gzipFlags, sizeof(ULONG)); + } + + switch (context->Service) + { + case MENUITEM_VIRUSTOTAL_UPLOAD: + { + PSTR uploadUrl = NULL; + PSTR quote = NULL; + PVOID rootJsonObject; + + if (!NT_SUCCESS(status = HashFileAndResetPosition(fileHandle, &fileSize64, Sha256HashAlgorithm, &hashString))) + { + RaiseUploadError(context, L"Unable to hash the file", RtlNtStatusToDosError(status)); + goto CleanupExit; + } + + subObjectName = PhConcatStrings2(L"/file/upload/?sha256=", hashString->Buffer); + + //if (PhIsNullOrEmptyString(context->KeyString)) + // Create the default launch URL + PhMoveReference(&context->LaunchCommand, PhFormatString( + L"https://www.virustotal.com/file/%s/analysis/", + PhGetString(hashString) + )); + + if (!(subRequestBuffer = PerformSubRequest( + context, + serviceInfo->HostName, + serviceInfo->HostPort, + serviceInfo->HostFlags, + subObjectName->Buffer + ))) + { + goto CleanupExit; + } + + if (rootJsonObject = CreateJsonParser(subRequestBuffer->Buffer)) + { + if (context->FileExists = GetJsonValueAsBool(rootJsonObject, "file_exists")) + { + INT64 detected = 0; + INT64 detectedMax = 0; + PVOID detectionRatio; + + if (detectionRatio = JsonGetObject(rootJsonObject, "detection_ratio")) + { + detected = GetJsonArrayUlong(detectionRatio, 0); + detectedMax = GetJsonArrayUlong(detectionRatio, 1); + } + + context->Detected = PhFormatString(L"%I64d", detected); + context->MaxDetected = PhFormatString(L"%I64d", detectedMax); + context->UploadUrl = PhZeroExtendToUtf16(GetJsonValueAsString(rootJsonObject, "upload_url")); + context->ReAnalyseUrl = PhZeroExtendToUtf16(GetJsonValueAsString(rootJsonObject, "reanalyse_url")); + context->LastAnalysisUrl = PhZeroExtendToUtf16(GetJsonValueAsString(rootJsonObject, "last_analysis_url")); + context->FirstAnalysisDate = PhZeroExtendToUtf16(GetJsonValueAsString(rootJsonObject, "first_analysis_date")); + context->LastAnalysisDate = PhZeroExtendToUtf16(GetJsonValueAsString(rootJsonObject, "last_analysis_date")); + context->LastAnalysisAgo = PhZeroExtendToUtf16(GetJsonValueAsString(rootJsonObject, "last_analysis_ago")); + + PhMoveReference(&context->FirstAnalysisDate, VirusTotalStringToTime(context->FirstAnalysisDate)); + PhMoveReference(&context->LastAnalysisDate, VirusTotalStringToTime(context->LastAnalysisDate)); + + if (!PhIsNullOrEmptyString(context->ReAnalyseUrl)) + { + PhMoveReference(&context->ReAnalyseUrl, PhFormatString( + L"%s%s", + L"https://www.virustotal.com/", + PhGetString(context->ReAnalyseUrl) + )); + } + + if (context->VtApiUpload && !PhIsNullOrEmptyString(context->KeyString)) + { + PhMoveReference(&context->UploadUrl, PhFormatString( + L"%s%s?apikey=%s&resource=%s", + L"https://www.virustotal.com/", + L"/vtapi/v2/file/scan", + PhGetString(context->KeyString), + PhGetString(hashString) + )); + } + + if (!PhIsNullOrEmptyString(context->UploadUrl)) + { + success = TRUE; + PostMessage(context->DialogHandle, UM_EXISTS, 0, 0); + } + } + else + { + context->UploadUrl = PhZeroExtendToUtf16(GetJsonValueAsString(rootJsonObject, "upload_url")); + + // No file found... Start the upload. + if (!PhIsNullOrEmptyString(context->UploadUrl)) + { + success = TRUE; + PostMessage(context->DialogHandle, UM_UPLOAD, 0, 0); + } + } + + CleanupJsonParser(rootJsonObject); + } + } + break; + case MENUITEM_JOTTI_UPLOAD: + { + // Create the default upload URL + context->UploadUrl = PhFormatString(L"https://virusscan.jotti.org%s", serviceInfo->UploadObjectName); + + // No file found... Start the upload. + if (!PhIsNullOrEmptyString(context->UploadUrl)) + { + success = TRUE; + PostMessage(context->DialogHandle, UM_UPLOAD, 0, 0); + } + } + break; + } + +CleanupExit: + + if (context->DialogHandle && !success) + { + PostMessage(context->DialogHandle, UM_ERROR, 0, 0); + } + + PhClearReference(&phVersion); + PhClearReference(&userAgent); + PhClearReference(&hashString); + PhClearReference(&subObjectName); + PhClearReference(&subRequestBuffer); + + if (requestHandle) + WinHttpCloseHandle(requestHandle); + + if (connectHandle) + WinHttpCloseHandle(connectHandle); + + if (fileHandle) + NtClose(fileHandle); + + PhDereferenceObject(context); + + return status; +} + +LRESULT CALLBACK TaskDialogSubclassProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam, + _In_ UINT_PTR uIdSubclass, + _In_ ULONG_PTR dwRefData + ) +{ + PUPLOAD_CONTEXT context = (PUPLOAD_CONTEXT)dwRefData; + + switch (uMsg) + { + case WM_NCDESTROY: + { + TaskDialogFreeContext(context); + + RemoveWindowSubclass(hwndDlg, TaskDialogSubclassProc, uIdSubclass); + } + break; + case UM_SHOWDIALOG: + { + if (IsMinimized(hwndDlg)) + ShowWindow(hwndDlg, SW_RESTORE); + else + ShowWindow(hwndDlg, SW_SHOW); + + SetForegroundWindow(hwndDlg); + } + break; + case UM_UPLOAD: + { + ShowVirusTotalProgressDialog(context); + } + break; + case UM_EXISTS: + { + ShowFileFoundDialog(context); + } + break; + case UM_LAUNCH: + { + if (!PhIsNullOrEmptyString(context->LaunchCommand)) + { + PhShellExecute(hwndDlg, context->LaunchCommand->Buffer, NULL); + } + + PostQuitMessage(0); + } + break; + case UM_ERROR: + { + VirusTotalShowErrorDialog(context); + } + break; + } + + return DefSubclassProc(hwndDlg, uMsg, wParam, lParam); +} + +HRESULT CALLBACK TaskDialogBootstrapCallback( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam, + _In_ LONG_PTR dwRefData + ) +{ + PUPLOAD_CONTEXT context = (PUPLOAD_CONTEXT)dwRefData; + + switch (uMsg) + { + case TDN_CREATED: + { + context->DialogHandle = hwndDlg; + + // Center the update window on PH if it's visible else we center on the desktop. + PhCenterWindow(hwndDlg, (IsWindowVisible(PhMainWndHandle) && !IsMinimized(PhMainWndHandle)) ? PhMainWndHandle : NULL); + + // Create the Taskdialog icons + TaskDialogCreateIcons(context); + + if (SUCCEEDED(CoCreateInstance(&CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, &IID_ITaskbarList3, &context->TaskbarListClass))) + { + if (!SUCCEEDED(ITaskbarList3_HrInit(context->TaskbarListClass))) + { + ITaskbarList3_Release(context->TaskbarListClass); + context->TaskbarListClass = NULL; + } + } + + // Subclass the Taskdialog + SetWindowSubclass(hwndDlg, TaskDialogSubclassProc, 0, (ULONG_PTR)context); + + ShowVirusTotalUploadDialog(context); + } + break; + } + + return S_OK; +} + +NTSTATUS ShowUpdateDialogThread( + _In_ PVOID Parameter + ) +{ + PH_AUTO_POOL autoPool; + TASKDIALOGCONFIG config = { sizeof(TASKDIALOGCONFIG) }; + PUPLOAD_CONTEXT context = (PUPLOAD_CONTEXT)Parameter; + BOOL checked = FALSE; + + PhInitializeAutoPool(&autoPool); + + config.dwFlags = TDF_ALLOW_DIALOG_CANCELLATION | TDF_CAN_BE_MINIMIZED; + config.pszContent = L"Initializing..."; + config.lpCallbackData = (LONG_PTR)context; + config.pfCallback = TaskDialogBootstrapCallback; + + // Start TaskDialog bootstrap + TaskDialogIndirect(&config, NULL, NULL, &checked); + + PhDeleteAutoPool(&autoPool); + + return STATUS_SUCCESS; +} + +VOID UploadToOnlineService( + _In_ PPH_STRING FileName, + _In_ ULONG Service + ) +{ + static PH_INITONCE initOnce = PH_INITONCE_INIT; + + HANDLE dialogThread; + PUPLOAD_CONTEXT context; + + if (PhBeginInitOnce(&initOnce)) + { + UploadContextType = PhCreateObjectType(L"OnlineChecksObjectType", 0, UploadContextDeleteProcedure); + PhEndInitOnce(&initOnce); + } + + context = (PUPLOAD_CONTEXT)PhCreateObject(sizeof(UPLOAD_CONTEXT), UploadContextType); + memset(context, 0, sizeof(UPLOAD_CONTEXT)); + + PhReferenceObject(FileName); + context->Service = Service; + context->FileName = FileName; + context->BaseFileName = PhGetBaseName(context->FileName); + context->KeyString = PhCreateString(VIRUSTOTAL_APIKEY); + + if (dialogThread = PhCreateThread(0, ShowUpdateDialogThread, (PVOID)context)) + { + PostMessage(dialogThread, UM_SHOWDIALOG, 0, 0); + NtClose(dialogThread); + } +} diff --git a/plugins/Plugins.sln b/plugins/Plugins.sln index 4e75dea003a4..ae4f9f9a95bd 100644 --- a/plugins/Plugins.sln +++ b/plugins/Plugins.sln @@ -1,165 +1,165 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.26228.4 -MinimumVisualStudioVersion = 15.0.26228.4 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{53C3AE07-D96F-4F5C-B407-4195084472CF}" - ProjectSection(SolutionItems) = preProject - include\commonutil.h = include\commonutil.h - Plugins.props = Plugins.props - include\toolstatusintf.h = include\toolstatusintf.h - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SbieSupport", "SbieSupport\SbieSupport.vcxproj", "{EEF1E81D-D286-422A-89E6-C6C8F3BE648A}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ExtendedNotifications", "ExtendedNotifications\ExtendedNotifications.vcxproj", "{80E791B8-AC98-407E-8FF9-5154AF50E887}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ToolStatus", "ToolStatus\ToolStatus.vcxproj", "{60B43533-C75E-4741-9E19-C4D581BEF51C}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ExtendedServices", "ExtendedServices\ExtendedServices.vcxproj", "{AC547368-D861-4B88-B5D4-E3B1F1AEEEDD}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "NetworkTools", "NetworkTools\NetworkTools.vcxproj", "{B5E0DA09-EA01-4D5A-A9D6-5B22DB0C306E}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "OnlineChecks", "OnlineChecks\OnlineChecks.vcxproj", "{79D24223-1122-40A9-BC8F-46A2089FE089}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ExtendedTools", "ExtendedTools\ExtendedTools.vcxproj", "{3437FD16-A3BF-4938-883A-EB0DF1584A2A}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WindowExplorer", "WindowExplorer\WindowExplorer.vcxproj", "{37488DC1-E45F-4626-A87C-3A854A153D1A}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DotNetTools", "DotNetTools\DotNetTools.vcxproj", "{2B3235B0-31E1-44DA-81A1-183F40517E47}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Updater", "Updater\Updater.vcxproj", "{A0C1595C-FA3E-4B7A-936C-306BC6294C5E}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UserNotes", "UserNotes\UserNotes.vcxproj", "{7C38D0AA-572C-4D75-8E4E-D68AF3C051AF}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "HardwareDevices", "HardwareDevices\HardwareDevices.vcxproj", "{5F0D72C4-8319-4B61-9E13-6084B680EB90}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CommonUtil", "CommonUtil\CommonUtil.vcxproj", "{C74D269B-3FCC-4C3E-93C7-1B4A94E7BBEE}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ExtraPlugins", "ExtraPlugins\ExtraPlugins.vcxproj", "{96549A3E-D1BD-470E-A5B3-A64803C4DEF5}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Win32 = Debug|Win32 - Debug|x64 = Debug|x64 - Release|Win32 = Release|Win32 - Release|x64 = Release|x64 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {EEF1E81D-D286-422A-89E6-C6C8F3BE648A}.Debug|Win32.ActiveCfg = Debug|Win32 - {EEF1E81D-D286-422A-89E6-C6C8F3BE648A}.Debug|Win32.Build.0 = Debug|Win32 - {EEF1E81D-D286-422A-89E6-C6C8F3BE648A}.Debug|x64.ActiveCfg = Debug|x64 - {EEF1E81D-D286-422A-89E6-C6C8F3BE648A}.Debug|x64.Build.0 = Debug|x64 - {EEF1E81D-D286-422A-89E6-C6C8F3BE648A}.Release|Win32.ActiveCfg = Release|Win32 - {EEF1E81D-D286-422A-89E6-C6C8F3BE648A}.Release|Win32.Build.0 = Release|Win32 - {EEF1E81D-D286-422A-89E6-C6C8F3BE648A}.Release|x64.ActiveCfg = Release|x64 - {EEF1E81D-D286-422A-89E6-C6C8F3BE648A}.Release|x64.Build.0 = Release|x64 - {80E791B8-AC98-407E-8FF9-5154AF50E887}.Debug|Win32.ActiveCfg = Debug|Win32 - {80E791B8-AC98-407E-8FF9-5154AF50E887}.Debug|Win32.Build.0 = Debug|Win32 - {80E791B8-AC98-407E-8FF9-5154AF50E887}.Debug|x64.ActiveCfg = Debug|x64 - {80E791B8-AC98-407E-8FF9-5154AF50E887}.Debug|x64.Build.0 = Debug|x64 - {80E791B8-AC98-407E-8FF9-5154AF50E887}.Release|Win32.ActiveCfg = Release|Win32 - {80E791B8-AC98-407E-8FF9-5154AF50E887}.Release|Win32.Build.0 = Release|Win32 - {80E791B8-AC98-407E-8FF9-5154AF50E887}.Release|x64.ActiveCfg = Release|x64 - {80E791B8-AC98-407E-8FF9-5154AF50E887}.Release|x64.Build.0 = Release|x64 - {60B43533-C75E-4741-9E19-C4D581BEF51C}.Debug|Win32.ActiveCfg = Debug|Win32 - {60B43533-C75E-4741-9E19-C4D581BEF51C}.Debug|Win32.Build.0 = Debug|Win32 - {60B43533-C75E-4741-9E19-C4D581BEF51C}.Debug|x64.ActiveCfg = Debug|x64 - {60B43533-C75E-4741-9E19-C4D581BEF51C}.Debug|x64.Build.0 = Debug|x64 - {60B43533-C75E-4741-9E19-C4D581BEF51C}.Release|Win32.ActiveCfg = Release|Win32 - {60B43533-C75E-4741-9E19-C4D581BEF51C}.Release|Win32.Build.0 = Release|Win32 - {60B43533-C75E-4741-9E19-C4D581BEF51C}.Release|x64.ActiveCfg = Release|x64 - {60B43533-C75E-4741-9E19-C4D581BEF51C}.Release|x64.Build.0 = Release|x64 - {AC547368-D861-4B88-B5D4-E3B1F1AEEEDD}.Debug|Win32.ActiveCfg = Debug|Win32 - {AC547368-D861-4B88-B5D4-E3B1F1AEEEDD}.Debug|Win32.Build.0 = Debug|Win32 - {AC547368-D861-4B88-B5D4-E3B1F1AEEEDD}.Debug|x64.ActiveCfg = Debug|x64 - {AC547368-D861-4B88-B5D4-E3B1F1AEEEDD}.Debug|x64.Build.0 = Debug|x64 - {AC547368-D861-4B88-B5D4-E3B1F1AEEEDD}.Release|Win32.ActiveCfg = Release|Win32 - {AC547368-D861-4B88-B5D4-E3B1F1AEEEDD}.Release|Win32.Build.0 = Release|Win32 - {AC547368-D861-4B88-B5D4-E3B1F1AEEEDD}.Release|x64.ActiveCfg = Release|x64 - {AC547368-D861-4B88-B5D4-E3B1F1AEEEDD}.Release|x64.Build.0 = Release|x64 - {B5E0DA09-EA01-4D5A-A9D6-5B22DB0C306E}.Debug|Win32.ActiveCfg = Debug|Win32 - {B5E0DA09-EA01-4D5A-A9D6-5B22DB0C306E}.Debug|Win32.Build.0 = Debug|Win32 - {B5E0DA09-EA01-4D5A-A9D6-5B22DB0C306E}.Debug|x64.ActiveCfg = Debug|x64 - {B5E0DA09-EA01-4D5A-A9D6-5B22DB0C306E}.Debug|x64.Build.0 = Debug|x64 - {B5E0DA09-EA01-4D5A-A9D6-5B22DB0C306E}.Release|Win32.ActiveCfg = Release|Win32 - {B5E0DA09-EA01-4D5A-A9D6-5B22DB0C306E}.Release|Win32.Build.0 = Release|Win32 - {B5E0DA09-EA01-4D5A-A9D6-5B22DB0C306E}.Release|x64.ActiveCfg = Release|x64 - {B5E0DA09-EA01-4D5A-A9D6-5B22DB0C306E}.Release|x64.Build.0 = Release|x64 - {79D24223-1122-40A9-BC8F-46A2089FE089}.Debug|Win32.ActiveCfg = Debug|Win32 - {79D24223-1122-40A9-BC8F-46A2089FE089}.Debug|Win32.Build.0 = Debug|Win32 - {79D24223-1122-40A9-BC8F-46A2089FE089}.Debug|x64.ActiveCfg = Debug|x64 - {79D24223-1122-40A9-BC8F-46A2089FE089}.Debug|x64.Build.0 = Debug|x64 - {79D24223-1122-40A9-BC8F-46A2089FE089}.Release|Win32.ActiveCfg = Release|Win32 - {79D24223-1122-40A9-BC8F-46A2089FE089}.Release|Win32.Build.0 = Release|Win32 - {79D24223-1122-40A9-BC8F-46A2089FE089}.Release|x64.ActiveCfg = Release|x64 - {79D24223-1122-40A9-BC8F-46A2089FE089}.Release|x64.Build.0 = Release|x64 - {3437FD16-A3BF-4938-883A-EB0DF1584A2A}.Debug|Win32.ActiveCfg = Debug|Win32 - {3437FD16-A3BF-4938-883A-EB0DF1584A2A}.Debug|Win32.Build.0 = Debug|Win32 - {3437FD16-A3BF-4938-883A-EB0DF1584A2A}.Debug|x64.ActiveCfg = Debug|x64 - {3437FD16-A3BF-4938-883A-EB0DF1584A2A}.Debug|x64.Build.0 = Debug|x64 - {3437FD16-A3BF-4938-883A-EB0DF1584A2A}.Release|Win32.ActiveCfg = Release|Win32 - {3437FD16-A3BF-4938-883A-EB0DF1584A2A}.Release|Win32.Build.0 = Release|Win32 - {3437FD16-A3BF-4938-883A-EB0DF1584A2A}.Release|x64.ActiveCfg = Release|x64 - {3437FD16-A3BF-4938-883A-EB0DF1584A2A}.Release|x64.Build.0 = Release|x64 - {37488DC1-E45F-4626-A87C-3A854A153D1A}.Debug|Win32.ActiveCfg = Debug|Win32 - {37488DC1-E45F-4626-A87C-3A854A153D1A}.Debug|Win32.Build.0 = Debug|Win32 - {37488DC1-E45F-4626-A87C-3A854A153D1A}.Debug|x64.ActiveCfg = Debug|x64 - {37488DC1-E45F-4626-A87C-3A854A153D1A}.Debug|x64.Build.0 = Debug|x64 - {37488DC1-E45F-4626-A87C-3A854A153D1A}.Release|Win32.ActiveCfg = Release|Win32 - {37488DC1-E45F-4626-A87C-3A854A153D1A}.Release|Win32.Build.0 = Release|Win32 - {37488DC1-E45F-4626-A87C-3A854A153D1A}.Release|x64.ActiveCfg = Release|x64 - {37488DC1-E45F-4626-A87C-3A854A153D1A}.Release|x64.Build.0 = Release|x64 - {2B3235B0-31E1-44DA-81A1-183F40517E47}.Debug|Win32.ActiveCfg = Debug|Win32 - {2B3235B0-31E1-44DA-81A1-183F40517E47}.Debug|Win32.Build.0 = Debug|Win32 - {2B3235B0-31E1-44DA-81A1-183F40517E47}.Debug|x64.ActiveCfg = Debug|x64 - {2B3235B0-31E1-44DA-81A1-183F40517E47}.Debug|x64.Build.0 = Debug|x64 - {2B3235B0-31E1-44DA-81A1-183F40517E47}.Release|Win32.ActiveCfg = Release|Win32 - {2B3235B0-31E1-44DA-81A1-183F40517E47}.Release|Win32.Build.0 = Release|Win32 - {2B3235B0-31E1-44DA-81A1-183F40517E47}.Release|x64.ActiveCfg = Release|x64 - {2B3235B0-31E1-44DA-81A1-183F40517E47}.Release|x64.Build.0 = Release|x64 - {A0C1595C-FA3E-4B7A-936C-306BC6294C5E}.Debug|Win32.ActiveCfg = Debug|Win32 - {A0C1595C-FA3E-4B7A-936C-306BC6294C5E}.Debug|Win32.Build.0 = Debug|Win32 - {A0C1595C-FA3E-4B7A-936C-306BC6294C5E}.Debug|x64.ActiveCfg = Debug|x64 - {A0C1595C-FA3E-4B7A-936C-306BC6294C5E}.Debug|x64.Build.0 = Debug|x64 - {A0C1595C-FA3E-4B7A-936C-306BC6294C5E}.Release|Win32.ActiveCfg = Release|Win32 - {A0C1595C-FA3E-4B7A-936C-306BC6294C5E}.Release|Win32.Build.0 = Release|Win32 - {A0C1595C-FA3E-4B7A-936C-306BC6294C5E}.Release|x64.ActiveCfg = Release|x64 - {A0C1595C-FA3E-4B7A-936C-306BC6294C5E}.Release|x64.Build.0 = Release|x64 - {7C38D0AA-572C-4D75-8E4E-D68AF3C051AF}.Debug|Win32.ActiveCfg = Debug|Win32 - {7C38D0AA-572C-4D75-8E4E-D68AF3C051AF}.Debug|Win32.Build.0 = Debug|Win32 - {7C38D0AA-572C-4D75-8E4E-D68AF3C051AF}.Debug|x64.ActiveCfg = Debug|x64 - {7C38D0AA-572C-4D75-8E4E-D68AF3C051AF}.Debug|x64.Build.0 = Debug|x64 - {7C38D0AA-572C-4D75-8E4E-D68AF3C051AF}.Release|Win32.ActiveCfg = Release|Win32 - {7C38D0AA-572C-4D75-8E4E-D68AF3C051AF}.Release|Win32.Build.0 = Release|Win32 - {7C38D0AA-572C-4D75-8E4E-D68AF3C051AF}.Release|x64.ActiveCfg = Release|x64 - {7C38D0AA-572C-4D75-8E4E-D68AF3C051AF}.Release|x64.Build.0 = Release|x64 - {5F0D72C4-8319-4B61-9E13-6084B680EB90}.Debug|Win32.ActiveCfg = Debug|Win32 - {5F0D72C4-8319-4B61-9E13-6084B680EB90}.Debug|Win32.Build.0 = Debug|Win32 - {5F0D72C4-8319-4B61-9E13-6084B680EB90}.Debug|x64.ActiveCfg = Debug|x64 - {5F0D72C4-8319-4B61-9E13-6084B680EB90}.Debug|x64.Build.0 = Debug|x64 - {5F0D72C4-8319-4B61-9E13-6084B680EB90}.Release|Win32.ActiveCfg = Release|Win32 - {5F0D72C4-8319-4B61-9E13-6084B680EB90}.Release|Win32.Build.0 = Release|Win32 - {5F0D72C4-8319-4B61-9E13-6084B680EB90}.Release|x64.ActiveCfg = Release|x64 - {5F0D72C4-8319-4B61-9E13-6084B680EB90}.Release|x64.Build.0 = Release|x64 - {C74D269B-3FCC-4C3E-93C7-1B4A94E7BBEE}.Debug|Win32.ActiveCfg = Debug|Win32 - {C74D269B-3FCC-4C3E-93C7-1B4A94E7BBEE}.Debug|Win32.Build.0 = Debug|Win32 - {C74D269B-3FCC-4C3E-93C7-1B4A94E7BBEE}.Debug|x64.ActiveCfg = Debug|x64 - {C74D269B-3FCC-4C3E-93C7-1B4A94E7BBEE}.Debug|x64.Build.0 = Debug|x64 - {C74D269B-3FCC-4C3E-93C7-1B4A94E7BBEE}.Release|Win32.ActiveCfg = Release|Win32 - {C74D269B-3FCC-4C3E-93C7-1B4A94E7BBEE}.Release|Win32.Build.0 = Release|Win32 - {C74D269B-3FCC-4C3E-93C7-1B4A94E7BBEE}.Release|x64.ActiveCfg = Release|x64 - {C74D269B-3FCC-4C3E-93C7-1B4A94E7BBEE}.Release|x64.Build.0 = Release|x64 - {96549A3E-D1BD-470E-A5B3-A64803C4DEF5}.Debug|Win32.ActiveCfg = Debug|Win32 - {96549A3E-D1BD-470E-A5B3-A64803C4DEF5}.Debug|Win32.Build.0 = Debug|Win32 - {96549A3E-D1BD-470E-A5B3-A64803C4DEF5}.Debug|x64.ActiveCfg = Debug|x64 - {96549A3E-D1BD-470E-A5B3-A64803C4DEF5}.Debug|x64.Build.0 = Debug|x64 - {96549A3E-D1BD-470E-A5B3-A64803C4DEF5}.Release|Win32.ActiveCfg = Release|Win32 - {96549A3E-D1BD-470E-A5B3-A64803C4DEF5}.Release|Win32.Build.0 = Release|Win32 - {96549A3E-D1BD-470E-A5B3-A64803C4DEF5}.Release|x64.ActiveCfg = Release|x64 - {96549A3E-D1BD-470E-A5B3-A64803C4DEF5}.Release|x64.Build.0 = Release|x64 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.26228.4 +MinimumVisualStudioVersion = 15.0.26228.4 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{53C3AE07-D96F-4F5C-B407-4195084472CF}" + ProjectSection(SolutionItems) = preProject + include\commonutil.h = include\commonutil.h + Plugins.props = Plugins.props + include\toolstatusintf.h = include\toolstatusintf.h + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SbieSupport", "SbieSupport\SbieSupport.vcxproj", "{EEF1E81D-D286-422A-89E6-C6C8F3BE648A}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ExtendedNotifications", "ExtendedNotifications\ExtendedNotifications.vcxproj", "{80E791B8-AC98-407E-8FF9-5154AF50E887}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ToolStatus", "ToolStatus\ToolStatus.vcxproj", "{60B43533-C75E-4741-9E19-C4D581BEF51C}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ExtendedServices", "ExtendedServices\ExtendedServices.vcxproj", "{AC547368-D861-4B88-B5D4-E3B1F1AEEEDD}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "NetworkTools", "NetworkTools\NetworkTools.vcxproj", "{B5E0DA09-EA01-4D5A-A9D6-5B22DB0C306E}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "OnlineChecks", "OnlineChecks\OnlineChecks.vcxproj", "{79D24223-1122-40A9-BC8F-46A2089FE089}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ExtendedTools", "ExtendedTools\ExtendedTools.vcxproj", "{3437FD16-A3BF-4938-883A-EB0DF1584A2A}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WindowExplorer", "WindowExplorer\WindowExplorer.vcxproj", "{37488DC1-E45F-4626-A87C-3A854A153D1A}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DotNetTools", "DotNetTools\DotNetTools.vcxproj", "{2B3235B0-31E1-44DA-81A1-183F40517E47}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Updater", "Updater\Updater.vcxproj", "{A0C1595C-FA3E-4B7A-936C-306BC6294C5E}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UserNotes", "UserNotes\UserNotes.vcxproj", "{7C38D0AA-572C-4D75-8E4E-D68AF3C051AF}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "HardwareDevices", "HardwareDevices\HardwareDevices.vcxproj", "{5F0D72C4-8319-4B61-9E13-6084B680EB90}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CommonUtil", "CommonUtil\CommonUtil.vcxproj", "{C74D269B-3FCC-4C3E-93C7-1B4A94E7BBEE}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ExtraPlugins", "ExtraPlugins\ExtraPlugins.vcxproj", "{96549A3E-D1BD-470E-A5B3-A64803C4DEF5}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {EEF1E81D-D286-422A-89E6-C6C8F3BE648A}.Debug|Win32.ActiveCfg = Debug|Win32 + {EEF1E81D-D286-422A-89E6-C6C8F3BE648A}.Debug|Win32.Build.0 = Debug|Win32 + {EEF1E81D-D286-422A-89E6-C6C8F3BE648A}.Debug|x64.ActiveCfg = Debug|x64 + {EEF1E81D-D286-422A-89E6-C6C8F3BE648A}.Debug|x64.Build.0 = Debug|x64 + {EEF1E81D-D286-422A-89E6-C6C8F3BE648A}.Release|Win32.ActiveCfg = Release|Win32 + {EEF1E81D-D286-422A-89E6-C6C8F3BE648A}.Release|Win32.Build.0 = Release|Win32 + {EEF1E81D-D286-422A-89E6-C6C8F3BE648A}.Release|x64.ActiveCfg = Release|x64 + {EEF1E81D-D286-422A-89E6-C6C8F3BE648A}.Release|x64.Build.0 = Release|x64 + {80E791B8-AC98-407E-8FF9-5154AF50E887}.Debug|Win32.ActiveCfg = Debug|Win32 + {80E791B8-AC98-407E-8FF9-5154AF50E887}.Debug|Win32.Build.0 = Debug|Win32 + {80E791B8-AC98-407E-8FF9-5154AF50E887}.Debug|x64.ActiveCfg = Debug|x64 + {80E791B8-AC98-407E-8FF9-5154AF50E887}.Debug|x64.Build.0 = Debug|x64 + {80E791B8-AC98-407E-8FF9-5154AF50E887}.Release|Win32.ActiveCfg = Release|Win32 + {80E791B8-AC98-407E-8FF9-5154AF50E887}.Release|Win32.Build.0 = Release|Win32 + {80E791B8-AC98-407E-8FF9-5154AF50E887}.Release|x64.ActiveCfg = Release|x64 + {80E791B8-AC98-407E-8FF9-5154AF50E887}.Release|x64.Build.0 = Release|x64 + {60B43533-C75E-4741-9E19-C4D581BEF51C}.Debug|Win32.ActiveCfg = Debug|Win32 + {60B43533-C75E-4741-9E19-C4D581BEF51C}.Debug|Win32.Build.0 = Debug|Win32 + {60B43533-C75E-4741-9E19-C4D581BEF51C}.Debug|x64.ActiveCfg = Debug|x64 + {60B43533-C75E-4741-9E19-C4D581BEF51C}.Debug|x64.Build.0 = Debug|x64 + {60B43533-C75E-4741-9E19-C4D581BEF51C}.Release|Win32.ActiveCfg = Release|Win32 + {60B43533-C75E-4741-9E19-C4D581BEF51C}.Release|Win32.Build.0 = Release|Win32 + {60B43533-C75E-4741-9E19-C4D581BEF51C}.Release|x64.ActiveCfg = Release|x64 + {60B43533-C75E-4741-9E19-C4D581BEF51C}.Release|x64.Build.0 = Release|x64 + {AC547368-D861-4B88-B5D4-E3B1F1AEEEDD}.Debug|Win32.ActiveCfg = Debug|Win32 + {AC547368-D861-4B88-B5D4-E3B1F1AEEEDD}.Debug|Win32.Build.0 = Debug|Win32 + {AC547368-D861-4B88-B5D4-E3B1F1AEEEDD}.Debug|x64.ActiveCfg = Debug|x64 + {AC547368-D861-4B88-B5D4-E3B1F1AEEEDD}.Debug|x64.Build.0 = Debug|x64 + {AC547368-D861-4B88-B5D4-E3B1F1AEEEDD}.Release|Win32.ActiveCfg = Release|Win32 + {AC547368-D861-4B88-B5D4-E3B1F1AEEEDD}.Release|Win32.Build.0 = Release|Win32 + {AC547368-D861-4B88-B5D4-E3B1F1AEEEDD}.Release|x64.ActiveCfg = Release|x64 + {AC547368-D861-4B88-B5D4-E3B1F1AEEEDD}.Release|x64.Build.0 = Release|x64 + {B5E0DA09-EA01-4D5A-A9D6-5B22DB0C306E}.Debug|Win32.ActiveCfg = Debug|Win32 + {B5E0DA09-EA01-4D5A-A9D6-5B22DB0C306E}.Debug|Win32.Build.0 = Debug|Win32 + {B5E0DA09-EA01-4D5A-A9D6-5B22DB0C306E}.Debug|x64.ActiveCfg = Debug|x64 + {B5E0DA09-EA01-4D5A-A9D6-5B22DB0C306E}.Debug|x64.Build.0 = Debug|x64 + {B5E0DA09-EA01-4D5A-A9D6-5B22DB0C306E}.Release|Win32.ActiveCfg = Release|Win32 + {B5E0DA09-EA01-4D5A-A9D6-5B22DB0C306E}.Release|Win32.Build.0 = Release|Win32 + {B5E0DA09-EA01-4D5A-A9D6-5B22DB0C306E}.Release|x64.ActiveCfg = Release|x64 + {B5E0DA09-EA01-4D5A-A9D6-5B22DB0C306E}.Release|x64.Build.0 = Release|x64 + {79D24223-1122-40A9-BC8F-46A2089FE089}.Debug|Win32.ActiveCfg = Debug|Win32 + {79D24223-1122-40A9-BC8F-46A2089FE089}.Debug|Win32.Build.0 = Debug|Win32 + {79D24223-1122-40A9-BC8F-46A2089FE089}.Debug|x64.ActiveCfg = Debug|x64 + {79D24223-1122-40A9-BC8F-46A2089FE089}.Debug|x64.Build.0 = Debug|x64 + {79D24223-1122-40A9-BC8F-46A2089FE089}.Release|Win32.ActiveCfg = Release|Win32 + {79D24223-1122-40A9-BC8F-46A2089FE089}.Release|Win32.Build.0 = Release|Win32 + {79D24223-1122-40A9-BC8F-46A2089FE089}.Release|x64.ActiveCfg = Release|x64 + {79D24223-1122-40A9-BC8F-46A2089FE089}.Release|x64.Build.0 = Release|x64 + {3437FD16-A3BF-4938-883A-EB0DF1584A2A}.Debug|Win32.ActiveCfg = Debug|Win32 + {3437FD16-A3BF-4938-883A-EB0DF1584A2A}.Debug|Win32.Build.0 = Debug|Win32 + {3437FD16-A3BF-4938-883A-EB0DF1584A2A}.Debug|x64.ActiveCfg = Debug|x64 + {3437FD16-A3BF-4938-883A-EB0DF1584A2A}.Debug|x64.Build.0 = Debug|x64 + {3437FD16-A3BF-4938-883A-EB0DF1584A2A}.Release|Win32.ActiveCfg = Release|Win32 + {3437FD16-A3BF-4938-883A-EB0DF1584A2A}.Release|Win32.Build.0 = Release|Win32 + {3437FD16-A3BF-4938-883A-EB0DF1584A2A}.Release|x64.ActiveCfg = Release|x64 + {3437FD16-A3BF-4938-883A-EB0DF1584A2A}.Release|x64.Build.0 = Release|x64 + {37488DC1-E45F-4626-A87C-3A854A153D1A}.Debug|Win32.ActiveCfg = Debug|Win32 + {37488DC1-E45F-4626-A87C-3A854A153D1A}.Debug|Win32.Build.0 = Debug|Win32 + {37488DC1-E45F-4626-A87C-3A854A153D1A}.Debug|x64.ActiveCfg = Debug|x64 + {37488DC1-E45F-4626-A87C-3A854A153D1A}.Debug|x64.Build.0 = Debug|x64 + {37488DC1-E45F-4626-A87C-3A854A153D1A}.Release|Win32.ActiveCfg = Release|Win32 + {37488DC1-E45F-4626-A87C-3A854A153D1A}.Release|Win32.Build.0 = Release|Win32 + {37488DC1-E45F-4626-A87C-3A854A153D1A}.Release|x64.ActiveCfg = Release|x64 + {37488DC1-E45F-4626-A87C-3A854A153D1A}.Release|x64.Build.0 = Release|x64 + {2B3235B0-31E1-44DA-81A1-183F40517E47}.Debug|Win32.ActiveCfg = Debug|Win32 + {2B3235B0-31E1-44DA-81A1-183F40517E47}.Debug|Win32.Build.0 = Debug|Win32 + {2B3235B0-31E1-44DA-81A1-183F40517E47}.Debug|x64.ActiveCfg = Debug|x64 + {2B3235B0-31E1-44DA-81A1-183F40517E47}.Debug|x64.Build.0 = Debug|x64 + {2B3235B0-31E1-44DA-81A1-183F40517E47}.Release|Win32.ActiveCfg = Release|Win32 + {2B3235B0-31E1-44DA-81A1-183F40517E47}.Release|Win32.Build.0 = Release|Win32 + {2B3235B0-31E1-44DA-81A1-183F40517E47}.Release|x64.ActiveCfg = Release|x64 + {2B3235B0-31E1-44DA-81A1-183F40517E47}.Release|x64.Build.0 = Release|x64 + {A0C1595C-FA3E-4B7A-936C-306BC6294C5E}.Debug|Win32.ActiveCfg = Debug|Win32 + {A0C1595C-FA3E-4B7A-936C-306BC6294C5E}.Debug|Win32.Build.0 = Debug|Win32 + {A0C1595C-FA3E-4B7A-936C-306BC6294C5E}.Debug|x64.ActiveCfg = Debug|x64 + {A0C1595C-FA3E-4B7A-936C-306BC6294C5E}.Debug|x64.Build.0 = Debug|x64 + {A0C1595C-FA3E-4B7A-936C-306BC6294C5E}.Release|Win32.ActiveCfg = Release|Win32 + {A0C1595C-FA3E-4B7A-936C-306BC6294C5E}.Release|Win32.Build.0 = Release|Win32 + {A0C1595C-FA3E-4B7A-936C-306BC6294C5E}.Release|x64.ActiveCfg = Release|x64 + {A0C1595C-FA3E-4B7A-936C-306BC6294C5E}.Release|x64.Build.0 = Release|x64 + {7C38D0AA-572C-4D75-8E4E-D68AF3C051AF}.Debug|Win32.ActiveCfg = Debug|Win32 + {7C38D0AA-572C-4D75-8E4E-D68AF3C051AF}.Debug|Win32.Build.0 = Debug|Win32 + {7C38D0AA-572C-4D75-8E4E-D68AF3C051AF}.Debug|x64.ActiveCfg = Debug|x64 + {7C38D0AA-572C-4D75-8E4E-D68AF3C051AF}.Debug|x64.Build.0 = Debug|x64 + {7C38D0AA-572C-4D75-8E4E-D68AF3C051AF}.Release|Win32.ActiveCfg = Release|Win32 + {7C38D0AA-572C-4D75-8E4E-D68AF3C051AF}.Release|Win32.Build.0 = Release|Win32 + {7C38D0AA-572C-4D75-8E4E-D68AF3C051AF}.Release|x64.ActiveCfg = Release|x64 + {7C38D0AA-572C-4D75-8E4E-D68AF3C051AF}.Release|x64.Build.0 = Release|x64 + {5F0D72C4-8319-4B61-9E13-6084B680EB90}.Debug|Win32.ActiveCfg = Debug|Win32 + {5F0D72C4-8319-4B61-9E13-6084B680EB90}.Debug|Win32.Build.0 = Debug|Win32 + {5F0D72C4-8319-4B61-9E13-6084B680EB90}.Debug|x64.ActiveCfg = Debug|x64 + {5F0D72C4-8319-4B61-9E13-6084B680EB90}.Debug|x64.Build.0 = Debug|x64 + {5F0D72C4-8319-4B61-9E13-6084B680EB90}.Release|Win32.ActiveCfg = Release|Win32 + {5F0D72C4-8319-4B61-9E13-6084B680EB90}.Release|Win32.Build.0 = Release|Win32 + {5F0D72C4-8319-4B61-9E13-6084B680EB90}.Release|x64.ActiveCfg = Release|x64 + {5F0D72C4-8319-4B61-9E13-6084B680EB90}.Release|x64.Build.0 = Release|x64 + {C74D269B-3FCC-4C3E-93C7-1B4A94E7BBEE}.Debug|Win32.ActiveCfg = Debug|Win32 + {C74D269B-3FCC-4C3E-93C7-1B4A94E7BBEE}.Debug|Win32.Build.0 = Debug|Win32 + {C74D269B-3FCC-4C3E-93C7-1B4A94E7BBEE}.Debug|x64.ActiveCfg = Debug|x64 + {C74D269B-3FCC-4C3E-93C7-1B4A94E7BBEE}.Debug|x64.Build.0 = Debug|x64 + {C74D269B-3FCC-4C3E-93C7-1B4A94E7BBEE}.Release|Win32.ActiveCfg = Release|Win32 + {C74D269B-3FCC-4C3E-93C7-1B4A94E7BBEE}.Release|Win32.Build.0 = Release|Win32 + {C74D269B-3FCC-4C3E-93C7-1B4A94E7BBEE}.Release|x64.ActiveCfg = Release|x64 + {C74D269B-3FCC-4C3E-93C7-1B4A94E7BBEE}.Release|x64.Build.0 = Release|x64 + {96549A3E-D1BD-470E-A5B3-A64803C4DEF5}.Debug|Win32.ActiveCfg = Debug|Win32 + {96549A3E-D1BD-470E-A5B3-A64803C4DEF5}.Debug|Win32.Build.0 = Debug|Win32 + {96549A3E-D1BD-470E-A5B3-A64803C4DEF5}.Debug|x64.ActiveCfg = Debug|x64 + {96549A3E-D1BD-470E-A5B3-A64803C4DEF5}.Debug|x64.Build.0 = Debug|x64 + {96549A3E-D1BD-470E-A5B3-A64803C4DEF5}.Release|Win32.ActiveCfg = Release|Win32 + {96549A3E-D1BD-470E-A5B3-A64803C4DEF5}.Release|Win32.Build.0 = Release|Win32 + {96549A3E-D1BD-470E-A5B3-A64803C4DEF5}.Release|x64.ActiveCfg = Release|x64 + {96549A3E-D1BD-470E-A5B3-A64803C4DEF5}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/plugins/SamplePlugin/SamplePlugin.sln b/plugins/SamplePlugin/SamplePlugin.sln index 6b056c7dab6b..947d0cd473bf 100644 --- a/plugins/SamplePlugin/SamplePlugin.sln +++ b/plugins/SamplePlugin/SamplePlugin.sln @@ -1,26 +1,26 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2013 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SamplePlugin", "SamplePlugin.vcxproj", "{C74D269B-3FCC-4C3E-93C7-1B4A94E7BBEE}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Win32 = Debug|Win32 - Debug|x64 = Debug|x64 - Release|Win32 = Release|Win32 - Release|x64 = Release|x64 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {C74D269B-3FCC-4C3E-93C7-1B4A94E7BBEE}.Debug|Win32.ActiveCfg = Debug|Win32 - {C74D269B-3FCC-4C3E-93C7-1B4A94E7BBEE}.Debug|Win32.Build.0 = Debug|Win32 - {C74D269B-3FCC-4C3E-93C7-1B4A94E7BBEE}.Debug|x64.ActiveCfg = Debug|x64 - {C74D269B-3FCC-4C3E-93C7-1B4A94E7BBEE}.Debug|x64.Build.0 = Debug|x64 - {C74D269B-3FCC-4C3E-93C7-1B4A94E7BBEE}.Release|Win32.ActiveCfg = Release|Win32 - {C74D269B-3FCC-4C3E-93C7-1B4A94E7BBEE}.Release|Win32.Build.0 = Release|Win32 - {C74D269B-3FCC-4C3E-93C7-1B4A94E7BBEE}.Release|x64.ActiveCfg = Release|x64 - {C74D269B-3FCC-4C3E-93C7-1B4A94E7BBEE}.Release|x64.Build.0 = Release|x64 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SamplePlugin", "SamplePlugin.vcxproj", "{C74D269B-3FCC-4C3E-93C7-1B4A94E7BBEE}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {C74D269B-3FCC-4C3E-93C7-1B4A94E7BBEE}.Debug|Win32.ActiveCfg = Debug|Win32 + {C74D269B-3FCC-4C3E-93C7-1B4A94E7BBEE}.Debug|Win32.Build.0 = Debug|Win32 + {C74D269B-3FCC-4C3E-93C7-1B4A94E7BBEE}.Debug|x64.ActiveCfg = Debug|x64 + {C74D269B-3FCC-4C3E-93C7-1B4A94E7BBEE}.Debug|x64.Build.0 = Debug|x64 + {C74D269B-3FCC-4C3E-93C7-1B4A94E7BBEE}.Release|Win32.ActiveCfg = Release|Win32 + {C74D269B-3FCC-4C3E-93C7-1B4A94E7BBEE}.Release|Win32.Build.0 = Release|Win32 + {C74D269B-3FCC-4C3E-93C7-1B4A94E7BBEE}.Release|x64.ActiveCfg = Release|x64 + {C74D269B-3FCC-4C3E-93C7-1B4A94E7BBEE}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/plugins/SamplePlugin/SamplePlugin.vcxproj b/plugins/SamplePlugin/SamplePlugin.vcxproj index b03001956d10..876d3bafa7d9 100644 --- a/plugins/SamplePlugin/SamplePlugin.vcxproj +++ b/plugins/SamplePlugin/SamplePlugin.vcxproj @@ -1,172 +1,172 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {C74D269B-3FCC-4C3E-93C7-1B4A94E7BBEE} - SamplePlugin - Win32Proj - 10.0.10586.0 - - - - DynamicLibrary - Unicode - true - v140 - - - DynamicLibrary - Unicode - v140 - - - DynamicLibrary - Unicode - true - v140 - - - DynamicLibrary - Unicode - v140 - - - - - - - - - - - - - - - - - - - $(ProjectDir)\bin\$(Configuration)32\ - $(ProjectDir)obj\$(Configuration)$(PlatformArchitecture)\ - true - $(ProjectDir)\bin\$(Configuration)64\ - $(ProjectDir)obj\$(Configuration)$(PlatformArchitecture)\ - true - $(ProjectDir)\bin\$(Configuration)32\ - $(ProjectDir)obj\$(Configuration)$(PlatformArchitecture)\ - false - $(ProjectDir)\bin\$(Configuration)64\ - $(ProjectDir)obj\$(Configuration)$(PlatformArchitecture)\ - false - - - - Disabled - ../../sdk/include;%(AdditionalIncludeDirectories) - WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - true - EnableFastChecks - MultiThreadedDebug - Level3 - EditAndContinue - StdCall - - - ProcessHacker.lib;ntdll.lib;%(AdditionalDependencies) - ../../sdk/lib/i386;%(AdditionalLibraryDirectories) - true - Windows - MachineX86 - - - - - Disabled - ../../sdk/include;%(AdditionalIncludeDirectories) - WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - true - EnableFastChecks - MultiThreadedDebug - Level3 - ProgramDatabase - StdCall - - - ProcessHacker.lib;ntdll.lib;%(AdditionalDependencies) - ../../sdk/lib/amd64;%(AdditionalLibraryDirectories) - true - Windows - MachineX64 - - - - - MaxSpeed - true - ../../sdk/include;%(AdditionalIncludeDirectories) - WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - MultiThreaded - true - Level3 - ProgramDatabase - StdCall - - - ProcessHacker.lib;ntdll.lib;%(AdditionalDependencies) - ../../sdk/lib/i386;%(AdditionalLibraryDirectories) - true - Windows - true - true - MachineX86 - true - - - - - MaxSpeed - true - ../../sdk/include;%(AdditionalIncludeDirectories) - WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - MultiThreaded - true - Level3 - ProgramDatabase - StdCall - - - ProcessHacker.lib;ntdll.lib;%(AdditionalDependencies) - ../../sdk/lib/amd64;%(AdditionalLibraryDirectories) - true - Windows - true - true - MachineX64 - true - - - - - - - - + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {C74D269B-3FCC-4C3E-93C7-1B4A94E7BBEE} + SamplePlugin + Win32Proj + 10.0.10586.0 + + + + DynamicLibrary + Unicode + true + v140 + + + DynamicLibrary + Unicode + v140 + + + DynamicLibrary + Unicode + true + v140 + + + DynamicLibrary + Unicode + v140 + + + + + + + + + + + + + + + + + + + $(ProjectDir)\bin\$(Configuration)32\ + $(ProjectDir)obj\$(Configuration)$(PlatformArchitecture)\ + true + $(ProjectDir)\bin\$(Configuration)64\ + $(ProjectDir)obj\$(Configuration)$(PlatformArchitecture)\ + true + $(ProjectDir)\bin\$(Configuration)32\ + $(ProjectDir)obj\$(Configuration)$(PlatformArchitecture)\ + false + $(ProjectDir)\bin\$(Configuration)64\ + $(ProjectDir)obj\$(Configuration)$(PlatformArchitecture)\ + false + + + + Disabled + ../../sdk/include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + Level3 + EditAndContinue + StdCall + + + ProcessHacker.lib;ntdll.lib;%(AdditionalDependencies) + ../../sdk/lib/i386;%(AdditionalLibraryDirectories) + true + Windows + MachineX86 + + + + + Disabled + ../../sdk/include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + Level3 + ProgramDatabase + StdCall + + + ProcessHacker.lib;ntdll.lib;%(AdditionalDependencies) + ../../sdk/lib/amd64;%(AdditionalLibraryDirectories) + true + Windows + MachineX64 + + + + + MaxSpeed + true + ../../sdk/include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + MultiThreaded + true + Level3 + ProgramDatabase + StdCall + + + ProcessHacker.lib;ntdll.lib;%(AdditionalDependencies) + ../../sdk/lib/i386;%(AdditionalLibraryDirectories) + true + Windows + true + true + MachineX86 + true + + + + + MaxSpeed + true + ../../sdk/include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + MultiThreaded + true + Level3 + ProgramDatabase + StdCall + + + ProcessHacker.lib;ntdll.lib;%(AdditionalDependencies) + ../../sdk/lib/amd64;%(AdditionalLibraryDirectories) + true + Windows + true + true + MachineX64 + true + + + + + + + + \ No newline at end of file diff --git a/plugins/SamplePlugin/main.c b/plugins/SamplePlugin/main.c index 5c18eaae5561..45a9349513df 100644 --- a/plugins/SamplePlugin/main.c +++ b/plugins/SamplePlugin/main.c @@ -1,261 +1,261 @@ -#include - -#define ID_SAMPLE_MENU_ITEM 1 -#define ID_SHOW_ME_SOME_OBJECTS 2 - -VOID LoadCallback( - __in_opt PVOID Parameter, - __in_opt PVOID Context - ); - -VOID ShowOptionsCallback( - __in_opt PVOID Parameter, - __in_opt PVOID Context - ); - -VOID MenuItemCallback( - __in_opt PVOID Parameter, - __in_opt PVOID Context - ); - -VOID MainWindowShowingCallback( - __in_opt PVOID Parameter, - __in_opt PVOID Context - ); - -VOID GetProcessHighlightingColorCallback( - __in_opt PVOID Parameter, - __in_opt PVOID Context - ); - -VOID GetProcessTooltipTextCallback( - __in_opt PVOID Parameter, - __in_opt PVOID Context - ); - -PPH_PLUGIN PluginInstance; -PH_CALLBACK_REGISTRATION PluginLoadCallbackRegistration; -PH_CALLBACK_REGISTRATION PluginShowOptionsCallbackRegistration; -PH_CALLBACK_REGISTRATION PluginMenuItemCallbackRegistration; -PH_CALLBACK_REGISTRATION MainWindowShowingCallbackRegistration; -PH_CALLBACK_REGISTRATION GetProcessHighlightingColorCallbackRegistration; -PH_CALLBACK_REGISTRATION GetProcessTooltipTextCallbackRegistration; - -LOGICAL DllMain( - __in HINSTANCE Instance, - __in ULONG Reason, - __reserved PVOID Reserved - ) -{ - switch (Reason) - { - case DLL_PROCESS_ATTACH: - { - PPH_PLUGIN_INFORMATION info; - - // Register your plugin with a unique name, otherwise it will fail. - PluginInstance = PhRegisterPlugin(L"YourName.SamplePlugin", Instance, &info); - - if (!PluginInstance) - return FALSE; - - info->DisplayName = L"Sample Plugin"; - info->Author = L"Someone"; - info->Description = L"Description goes here"; - info->HasOptions = TRUE; - - PhRegisterCallback( - PhGetPluginCallback(PluginInstance, PluginCallbackLoad), - LoadCallback, - NULL, - &PluginLoadCallbackRegistration - ); - PhRegisterCallback( - PhGetPluginCallback(PluginInstance, PluginCallbackShowOptions), - ShowOptionsCallback, - NULL, - &PluginShowOptionsCallbackRegistration - ); - PhRegisterCallback( - PhGetPluginCallback(PluginInstance, PluginCallbackMenuItem), - MenuItemCallback, - NULL, - &PluginMenuItemCallbackRegistration - ); - - PhRegisterCallback( - PhGetGeneralCallback(GeneralCallbackMainWindowShowing), - MainWindowShowingCallback, - NULL, - &MainWindowShowingCallbackRegistration - ); - PhRegisterCallback( - PhGetGeneralCallback(GeneralCallbackGetProcessHighlightingColor), - GetProcessHighlightingColorCallback, - NULL, - &GetProcessHighlightingColorCallbackRegistration - ); - PhRegisterCallback( - PhGetGeneralCallback(GeneralCallbackGetProcessTooltipText), - GetProcessTooltipTextCallback, - NULL, - &GetProcessTooltipTextCallbackRegistration - ); - - // Add some settings. Note that we cannot access these settings - // in DllMain. Settings must be added in DllMain. - { - static PH_SETTING_CREATE settings[] = - { - // You must prepend your plugin name to the setting names. - { IntegerSettingType, L"ProcessHacker.SamplePlugin.SomeInteger", L"1234" }, - { StringSettingType, L"ProcessHacker.SamplePlugin.SomeString", L"my string" } - }; - - PhAddSettings(settings, sizeof(settings) / sizeof(PH_SETTING_CREATE)); - } - } - break; - } - - return TRUE; -} - -VOID LoadCallback( - __in_opt PVOID Parameter, - __in_opt PVOID Context - ) -{ - ULONG myInteger; - PPH_STRING myString; - - myInteger = PhGetIntegerSetting(L"ProcessHacker.SamplePlugin.SomeInteger"); - // Do stuff to the integer. Possibly modify the setting. - PhSetIntegerSetting(L"ProcessHacker.SamplePlugin.SomeInteger", myInteger + 100); - - myString = PhGetStringSetting(L"ProcessHacker.SamplePlugin.SomeString"); - // Do stuff to the string. - // Dereference the string when you're done, or memory will be leaked. - PhDereferenceObject(myString); -} - -VOID ShowOptionsCallback( - __in_opt PVOID Parameter, - __in_opt PVOID Context - ) -{ - PhShowError((HWND)Parameter, L"Show some options here."); -} - -BOOLEAN NTAPI EnumDirectoryObjectsCallback( - __in PPH_STRINGREF Name, - __in PPH_STRINGREF TypeName, - __in_opt PVOID Context - ) -{ - INT result; - PPH_STRING name; - PPH_STRING typeName; - - name = PhCreateString2(Name); - typeName = PhCreateString2(TypeName); - result = PhShowMessage( - PhMainWndHandle, - MB_ICONINFORMATION | MB_OKCANCEL, - L"%s: %s", - name->Buffer, - typeName->Buffer - ); - PhDereferenceObject(name); - PhDereferenceObject(typeName); - - return result == IDOK; -} - -VOID MenuItemCallback( - __in_opt PVOID Parameter, - __in_opt PVOID Context - ) -{ - PPH_PLUGIN_MENU_ITEM menuItem = Parameter; - - switch (menuItem->Id) - { - case ID_SAMPLE_MENU_ITEM: - { - PhShowInformation(PhMainWndHandle, L"You clicked the sample menu item!"); - } - break; - case ID_SHOW_ME_SOME_OBJECTS: - { - NTSTATUS status; - HANDLE directoryHandle; - OBJECT_ATTRIBUTES oa; - UNICODE_STRING name; - - // Use the Native API seamlessly alongside Win32. - RtlInitUnicodeString(&name, L"\\"); - InitializeObjectAttributes(&oa, &name, 0, NULL, NULL); - - if (NT_SUCCESS(status = NtOpenDirectoryObject(&directoryHandle, DIRECTORY_QUERY, &oa))) - { - PhEnumDirectoryObjects(directoryHandle, EnumDirectoryObjectsCallback, NULL); - NtClose(directoryHandle); - } - } - break; - } -} - -VOID MainWindowShowingCallback( - __in_opt PVOID Parameter, - __in_opt PVOID Context - ) -{ - // $ won't match anything, so the menu item will get added to the end. - PhPluginAddMenuItem(PluginInstance, PH_MENU_ITEM_LOCATION_TOOLS, L"$", - ID_SAMPLE_MENU_ITEM, L"Sample menu item", NULL); - PhPluginAddMenuItem(PluginInstance, PH_MENU_ITEM_LOCATION_TOOLS, L"$", - ID_SHOW_ME_SOME_OBJECTS, L"Show me some objects", NULL); -} - -VOID GetProcessHighlightingColorCallback( - __in_opt PVOID Parameter, - __in_opt PVOID Context - ) -{ - PPH_PLUGIN_GET_HIGHLIGHTING_COLOR getHighlightingColor = Parameter; - PPH_PROCESS_ITEM processItem; - - processItem = getHighlightingColor->Parameter; - - // Optional: if another plugin handled the highlighting, don't override it. - if (getHighlightingColor->Handled) - return; - - // Set the background color of svchost.exe processes to black. - if (PhEqualString2(processItem->ProcessName, L"svchost.exe", TRUE)) - { - getHighlightingColor->BackColor = RGB(0x00, 0x00, 0x00); - getHighlightingColor->Cache = TRUE; - getHighlightingColor->Handled = TRUE; - } -} - -VOID GetProcessTooltipTextCallback( - __in_opt PVOID Parameter, - __in_opt PVOID Context - ) -{ - PPH_PLUGIN_GET_TOOLTIP_TEXT getTooltipText = Parameter; - PPH_PROCESS_ITEM processItem; - - processItem = getTooltipText->Parameter; - - // Put some text into the tooltip. This will go in just before the Notes section. - PhAppendFormatStringBuilder( - getTooltipText->StringBuilder, - L"Sample plugin:\n The process name is: %s\n", - processItem->ProcessName->Buffer - ); -} +#include + +#define ID_SAMPLE_MENU_ITEM 1 +#define ID_SHOW_ME_SOME_OBJECTS 2 + +VOID LoadCallback( + __in_opt PVOID Parameter, + __in_opt PVOID Context + ); + +VOID ShowOptionsCallback( + __in_opt PVOID Parameter, + __in_opt PVOID Context + ); + +VOID MenuItemCallback( + __in_opt PVOID Parameter, + __in_opt PVOID Context + ); + +VOID MainWindowShowingCallback( + __in_opt PVOID Parameter, + __in_opt PVOID Context + ); + +VOID GetProcessHighlightingColorCallback( + __in_opt PVOID Parameter, + __in_opt PVOID Context + ); + +VOID GetProcessTooltipTextCallback( + __in_opt PVOID Parameter, + __in_opt PVOID Context + ); + +PPH_PLUGIN PluginInstance; +PH_CALLBACK_REGISTRATION PluginLoadCallbackRegistration; +PH_CALLBACK_REGISTRATION PluginShowOptionsCallbackRegistration; +PH_CALLBACK_REGISTRATION PluginMenuItemCallbackRegistration; +PH_CALLBACK_REGISTRATION MainWindowShowingCallbackRegistration; +PH_CALLBACK_REGISTRATION GetProcessHighlightingColorCallbackRegistration; +PH_CALLBACK_REGISTRATION GetProcessTooltipTextCallbackRegistration; + +LOGICAL DllMain( + __in HINSTANCE Instance, + __in ULONG Reason, + __reserved PVOID Reserved + ) +{ + switch (Reason) + { + case DLL_PROCESS_ATTACH: + { + PPH_PLUGIN_INFORMATION info; + + // Register your plugin with a unique name, otherwise it will fail. + PluginInstance = PhRegisterPlugin(L"YourName.SamplePlugin", Instance, &info); + + if (!PluginInstance) + return FALSE; + + info->DisplayName = L"Sample Plugin"; + info->Author = L"Someone"; + info->Description = L"Description goes here"; + info->HasOptions = TRUE; + + PhRegisterCallback( + PhGetPluginCallback(PluginInstance, PluginCallbackLoad), + LoadCallback, + NULL, + &PluginLoadCallbackRegistration + ); + PhRegisterCallback( + PhGetPluginCallback(PluginInstance, PluginCallbackShowOptions), + ShowOptionsCallback, + NULL, + &PluginShowOptionsCallbackRegistration + ); + PhRegisterCallback( + PhGetPluginCallback(PluginInstance, PluginCallbackMenuItem), + MenuItemCallback, + NULL, + &PluginMenuItemCallbackRegistration + ); + + PhRegisterCallback( + PhGetGeneralCallback(GeneralCallbackMainWindowShowing), + MainWindowShowingCallback, + NULL, + &MainWindowShowingCallbackRegistration + ); + PhRegisterCallback( + PhGetGeneralCallback(GeneralCallbackGetProcessHighlightingColor), + GetProcessHighlightingColorCallback, + NULL, + &GetProcessHighlightingColorCallbackRegistration + ); + PhRegisterCallback( + PhGetGeneralCallback(GeneralCallbackGetProcessTooltipText), + GetProcessTooltipTextCallback, + NULL, + &GetProcessTooltipTextCallbackRegistration + ); + + // Add some settings. Note that we cannot access these settings + // in DllMain. Settings must be added in DllMain. + { + static PH_SETTING_CREATE settings[] = + { + // You must prepend your plugin name to the setting names. + { IntegerSettingType, L"ProcessHacker.SamplePlugin.SomeInteger", L"1234" }, + { StringSettingType, L"ProcessHacker.SamplePlugin.SomeString", L"my string" } + }; + + PhAddSettings(settings, sizeof(settings) / sizeof(PH_SETTING_CREATE)); + } + } + break; + } + + return TRUE; +} + +VOID LoadCallback( + __in_opt PVOID Parameter, + __in_opt PVOID Context + ) +{ + ULONG myInteger; + PPH_STRING myString; + + myInteger = PhGetIntegerSetting(L"ProcessHacker.SamplePlugin.SomeInteger"); + // Do stuff to the integer. Possibly modify the setting. + PhSetIntegerSetting(L"ProcessHacker.SamplePlugin.SomeInteger", myInteger + 100); + + myString = PhGetStringSetting(L"ProcessHacker.SamplePlugin.SomeString"); + // Do stuff to the string. + // Dereference the string when you're done, or memory will be leaked. + PhDereferenceObject(myString); +} + +VOID ShowOptionsCallback( + __in_opt PVOID Parameter, + __in_opt PVOID Context + ) +{ + PhShowError((HWND)Parameter, L"Show some options here."); +} + +BOOLEAN NTAPI EnumDirectoryObjectsCallback( + __in PPH_STRINGREF Name, + __in PPH_STRINGREF TypeName, + __in_opt PVOID Context + ) +{ + INT result; + PPH_STRING name; + PPH_STRING typeName; + + name = PhCreateString2(Name); + typeName = PhCreateString2(TypeName); + result = PhShowMessage( + PhMainWndHandle, + MB_ICONINFORMATION | MB_OKCANCEL, + L"%s: %s", + name->Buffer, + typeName->Buffer + ); + PhDereferenceObject(name); + PhDereferenceObject(typeName); + + return result == IDOK; +} + +VOID MenuItemCallback( + __in_opt PVOID Parameter, + __in_opt PVOID Context + ) +{ + PPH_PLUGIN_MENU_ITEM menuItem = Parameter; + + switch (menuItem->Id) + { + case ID_SAMPLE_MENU_ITEM: + { + PhShowInformation(PhMainWndHandle, L"You clicked the sample menu item!"); + } + break; + case ID_SHOW_ME_SOME_OBJECTS: + { + NTSTATUS status; + HANDLE directoryHandle; + OBJECT_ATTRIBUTES oa; + UNICODE_STRING name; + + // Use the Native API seamlessly alongside Win32. + RtlInitUnicodeString(&name, L"\\"); + InitializeObjectAttributes(&oa, &name, 0, NULL, NULL); + + if (NT_SUCCESS(status = NtOpenDirectoryObject(&directoryHandle, DIRECTORY_QUERY, &oa))) + { + PhEnumDirectoryObjects(directoryHandle, EnumDirectoryObjectsCallback, NULL); + NtClose(directoryHandle); + } + } + break; + } +} + +VOID MainWindowShowingCallback( + __in_opt PVOID Parameter, + __in_opt PVOID Context + ) +{ + // $ won't match anything, so the menu item will get added to the end. + PhPluginAddMenuItem(PluginInstance, PH_MENU_ITEM_LOCATION_TOOLS, L"$", + ID_SAMPLE_MENU_ITEM, L"Sample menu item", NULL); + PhPluginAddMenuItem(PluginInstance, PH_MENU_ITEM_LOCATION_TOOLS, L"$", + ID_SHOW_ME_SOME_OBJECTS, L"Show me some objects", NULL); +} + +VOID GetProcessHighlightingColorCallback( + __in_opt PVOID Parameter, + __in_opt PVOID Context + ) +{ + PPH_PLUGIN_GET_HIGHLIGHTING_COLOR getHighlightingColor = Parameter; + PPH_PROCESS_ITEM processItem; + + processItem = getHighlightingColor->Parameter; + + // Optional: if another plugin handled the highlighting, don't override it. + if (getHighlightingColor->Handled) + return; + + // Set the background color of svchost.exe processes to black. + if (PhEqualString2(processItem->ProcessName, L"svchost.exe", TRUE)) + { + getHighlightingColor->BackColor = RGB(0x00, 0x00, 0x00); + getHighlightingColor->Cache = TRUE; + getHighlightingColor->Handled = TRUE; + } +} + +VOID GetProcessTooltipTextCallback( + __in_opt PVOID Parameter, + __in_opt PVOID Context + ) +{ + PPH_PLUGIN_GET_TOOLTIP_TEXT getTooltipText = Parameter; + PPH_PROCESS_ITEM processItem; + + processItem = getTooltipText->Parameter; + + // Put some text into the tooltip. This will go in just before the Notes section. + PhAppendFormatStringBuilder( + getTooltipText->StringBuilder, + L"Sample plugin:\n The process name is: %s\n", + processItem->ProcessName->Buffer + ); +} diff --git a/plugins/SbieSupport/SbieSupport.rc b/plugins/SbieSupport/SbieSupport.rc index e2d61f7fcf25..82c4ae0686ab 100644 --- a/plugins/SbieSupport/SbieSupport.rc +++ b/plugins/SbieSupport/SbieSupport.rc @@ -1,146 +1,146 @@ -// Microsoft Visual C++ generated resource script. -// -#include "resource.h" - -#define APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// -#include "winres.h" -///////////////////////////////////////////////////////////////////////////// -#undef APSTUDIO_READONLY_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -// English (Australia) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENA) -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_AUS -#pragma code_page(1252) - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -1 TEXTINCLUDE -BEGIN - "resource.h\0" -END - -2 TEXTINCLUDE -BEGIN - "#include ""winres.h""\0" -END - -3 TEXTINCLUDE -BEGIN - "\r\n" - "\0" -END - -#endif // APSTUDIO_INVOKED - - -///////////////////////////////////////////////////////////////////////////// -// -// Version -// - -VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,0,0,0 - PRODUCTVERSION 1,0,0,0 - FILEFLAGSMASK 0x3fL -#ifdef _DEBUG - FILEFLAGS 0x1L -#else - FILEFLAGS 0x0L -#endif - FILEOS 0x40004L - FILETYPE 0x2L - FILESUBTYPE 0x0L -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "0c0904b0" - BEGIN - VALUE "CompanyName", "wj32" - VALUE "FileDescription", "Sandboxie Support for Process Hacker" - VALUE "FileVersion", "1.0" - VALUE "InternalName", "ProcessHacker.SbieSupport" - VALUE "LegalCopyright", "Licensed under the GNU GPL, v3." - VALUE "OriginalFilename", "SbieSupport.dll" - VALUE "ProductName", "Sandboxie Support for Process Hacker" - VALUE "ProductVersion", "1.0" - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0xc09, 1200 - END -END - - -///////////////////////////////////////////////////////////////////////////// -// -// Dialog -// - -IDD_OPTIONS DIALOGEX 0, 0, 268, 50 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Options" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "SbieDll.dll path:",IDC_STATIC,7,9,50,8 - EDITTEXT IDC_SBIEDLLPATH,63,8,143,12,ES_AUTOHSCROLL - PUSHBUTTON "Browse...",IDC_BROWSE,211,7,50,14 - PUSHBUTTON "OK",IDOK,158,29,50,14 - PUSHBUTTON "Cancel",IDCANCEL,211,29,50,14 -END - - -///////////////////////////////////////////////////////////////////////////// -// -// DESIGNINFO -// - -#ifdef APSTUDIO_INVOKED -GUIDELINES DESIGNINFO -BEGIN - IDD_OPTIONS, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 261 - TOPMARGIN, 7 - BOTTOMMARGIN, 43 - END -END -#endif // APSTUDIO_INVOKED - - -///////////////////////////////////////////////////////////////////////////// -// -// AFX_DIALOG_LAYOUT -// - -IDD_OPTIONS AFX_DIALOG_LAYOUT -BEGIN - 0 -END - -#endif // English (Australia) resources -///////////////////////////////////////////////////////////////////////////// - - - -#ifndef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// - - -///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED - +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "winres.h" +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (Australia) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENA) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_AUS +#pragma code_page(1252) + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""winres.h""\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,0,0 + PRODUCTVERSION 1,0,0,0 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "0c0904b0" + BEGIN + VALUE "CompanyName", "wj32" + VALUE "FileDescription", "Sandboxie Support for Process Hacker" + VALUE "FileVersion", "1.0" + VALUE "InternalName", "ProcessHacker.SbieSupport" + VALUE "LegalCopyright", "Licensed under the GNU GPL, v3." + VALUE "OriginalFilename", "SbieSupport.dll" + VALUE "ProductName", "Sandboxie Support for Process Hacker" + VALUE "ProductVersion", "1.0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0xc09, 1200 + END +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_OPTIONS DIALOGEX 0, 0, 268, 50 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Options" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "SbieDll.dll path:",IDC_STATIC,7,9,50,8 + EDITTEXT IDC_SBIEDLLPATH,63,8,143,12,ES_AUTOHSCROLL + PUSHBUTTON "Browse...",IDC_BROWSE,211,7,50,14 + PUSHBUTTON "OK",IDOK,158,29,50,14 + PUSHBUTTON "Cancel",IDCANCEL,211,29,50,14 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_OPTIONS, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 261 + TOPMARGIN, 7 + BOTTOMMARGIN, 43 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// AFX_DIALOG_LAYOUT +// + +IDD_OPTIONS AFX_DIALOG_LAYOUT +BEGIN + 0 +END + +#endif // English (Australia) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/plugins/SbieSupport/SbieSupport.vcxproj b/plugins/SbieSupport/SbieSupport.vcxproj index 413788b0c8cd..08a3a4d34cab 100644 --- a/plugins/SbieSupport/SbieSupport.vcxproj +++ b/plugins/SbieSupport/SbieSupport.vcxproj @@ -1,65 +1,65 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {EEF1E81D-D286-422A-89E6-C6C8F3BE648A} - SbieSupport - Win32Proj - SbieSupport - 10.0.15063.0 - - - - DynamicLibrary - Unicode - v141 - - - DynamicLibrary - Unicode - v141 - - - DynamicLibrary - Unicode - v141 - - - DynamicLibrary - Unicode - v141 - - - - - - - - - - - - - - - - - + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {EEF1E81D-D286-422A-89E6-C6C8F3BE648A} + SbieSupport + Win32Proj + SbieSupport + 10.0.15063.0 + + + + DynamicLibrary + Unicode + v141 + + + DynamicLibrary + Unicode + v141 + + + DynamicLibrary + Unicode + v141 + + + DynamicLibrary + Unicode + v141 + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/plugins/SbieSupport/main.c b/plugins/SbieSupport/main.c index bbd753b09245..a355a0acfd99 100644 --- a/plugins/SbieSupport/main.c +++ b/plugins/SbieSupport/main.c @@ -1,555 +1,555 @@ -/* - * Process Hacker Sandboxie Support - - * main program - * - * Copyright (C) 2010-2011 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include -#include "resource.h" -#include "sbiedll.h" - -typedef struct _BOX_INFO -{ - WCHAR BoxName[34]; - PH_STRINGREF IpcRoot; - WCHAR IpcRootBuffer[256]; -} BOX_INFO, *PBOX_INFO; - -typedef struct _BOXED_PROCESS -{ - HANDLE ProcessId; - WCHAR BoxName[34]; -} BOXED_PROCESS, *PBOXED_PROCESS; - -VOID NTAPI LoadCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ); - -VOID NTAPI ShowOptionsCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ); - -VOID NTAPI MenuItemCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ); - -VOID NTAPI MainMenuInitializingCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ); - -VOID NTAPI ProcessesUpdatedCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ); - -VOID NTAPI GetProcessHighlightingColorCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ); - -VOID NTAPI GetProcessTooltipTextCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ); - -VOID NTAPI GetIsDotNetDirectoryNamesCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ); - -VOID NTAPI RefreshSandboxieInfo( - _In_opt_ PVOID Context, - _In_ BOOLEAN TimerOrWaitFired - ); - -INT_PTR CALLBACK OptionsDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -PPH_PLUGIN PluginInstance; -PH_CALLBACK_REGISTRATION PluginLoadCallbackRegistration; -PH_CALLBACK_REGISTRATION PluginShowOptionsCallbackRegistration; -PH_CALLBACK_REGISTRATION PluginMenuItemCallbackRegistration; -PH_CALLBACK_REGISTRATION MainMenuInitializingCallbackRegistration; -PH_CALLBACK_REGISTRATION ProcessesUpdatedCallbackRegistration; -PH_CALLBACK_REGISTRATION GetProcessHighlightingColorCallbackRegistration; -PH_CALLBACK_REGISTRATION GetProcessTooltipTextCallbackRegistration; - -P_SbieApi_QueryBoxPath SbieApi_QueryBoxPath; -P_SbieApi_EnumBoxes SbieApi_EnumBoxes; -P_SbieApi_EnumProcessEx SbieApi_EnumProcessEx; -P_SbieDll_KillAll SbieDll_KillAll; - -PPH_HASHTABLE BoxedProcessesHashtable; -PH_QUEUED_LOCK BoxedProcessesLock = PH_QUEUED_LOCK_INIT; -BOOLEAN BoxedProcessesUpdated = FALSE; - -BOX_INFO BoxInfo[16]; -ULONG BoxInfoCount; - -LOGICAL DllMain( - _In_ HINSTANCE Instance, - _In_ ULONG Reason, - _Reserved_ PVOID Reserved - ) -{ - switch (Reason) - { - case DLL_PROCESS_ATTACH: - { - PPH_PLUGIN_INFORMATION info; - - PluginInstance = PhRegisterPlugin(PLUGIN_NAME, Instance, &info); - - if (!PluginInstance) - return FALSE; - - info->DisplayName = L"Sandboxie Support"; - info->Author = L"wj32"; - info->Description = L"Provides functionality for sandboxed processes."; - info->Url = L"https://wj32.org/processhacker/forums/viewtopic.php?t=1115"; - info->HasOptions = TRUE; - - PhRegisterCallback( - PhGetPluginCallback(PluginInstance, PluginCallbackLoad), - LoadCallback, - NULL, - &PluginLoadCallbackRegistration - ); - PhRegisterCallback( - PhGetPluginCallback(PluginInstance, PluginCallbackShowOptions), - ShowOptionsCallback, - NULL, - &PluginShowOptionsCallbackRegistration - ); - PhRegisterCallback( - PhGetPluginCallback(PluginInstance, PluginCallbackMenuItem), - MenuItemCallback, - NULL, - &PluginMenuItemCallbackRegistration - ); - - PhRegisterCallback( - PhGetGeneralCallback(GeneralCallbackMainMenuInitializing), - MainMenuInitializingCallback, - NULL, - &MainMenuInitializingCallbackRegistration - ); - PhRegisterCallback( - PhGetGeneralCallback(GeneralCallbackProcessesUpdated), - ProcessesUpdatedCallback, - NULL, - &ProcessesUpdatedCallbackRegistration - ); - PhRegisterCallback( - PhGetGeneralCallback(GeneralCallbackGetProcessHighlightingColor), - GetProcessHighlightingColorCallback, - NULL, - &GetProcessHighlightingColorCallbackRegistration - ); - PhRegisterCallback( - PhGetGeneralCallback(GeneralCallbackGetProcessTooltipText), - GetProcessTooltipTextCallback, - NULL, - &GetProcessTooltipTextCallbackRegistration - ); - - { - static PH_SETTING_CREATE settings[] = - { - { StringSettingType, SETTING_NAME_SBIE_DLL_PATH, L"C:\\Program Files\\Sandboxie\\SbieDll.dll" } - }; - - PhAddSettings(settings, sizeof(settings) / sizeof(PH_SETTING_CREATE)); - } - } - break; - } - - return TRUE; -} - -BOOLEAN NTAPI BoxedProcessesEqualFunction( - _In_ PVOID Entry1, - _In_ PVOID Entry2 - ) -{ - return ((PBOXED_PROCESS)Entry1)->ProcessId == ((PBOXED_PROCESS)Entry2)->ProcessId; -} - -ULONG NTAPI BoxedProcessesHashFunction( - _In_ PVOID Entry - ) -{ - return HandleToUlong(((PBOXED_PROCESS)Entry)->ProcessId) / 4; -} - -VOID NTAPI LoadCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - PPH_STRING sbieDllPath; - HMODULE module; - HANDLE timerQueueHandle; - HANDLE timerHandle; - - BoxedProcessesHashtable = PhCreateHashtable( - sizeof(BOXED_PROCESS), - BoxedProcessesEqualFunction, - BoxedProcessesHashFunction, - 32 - ); - - sbieDllPath = PhaGetStringSetting(SETTING_NAME_SBIE_DLL_PATH); - module = LoadLibrary(sbieDllPath->Buffer); - - SbieApi_QueryBoxPath = PhGetProcedureAddress(module, SbieApi_QueryBoxPath_Name, 0); - SbieApi_EnumBoxes = PhGetProcedureAddress(module, SbieApi_EnumBoxes_Name, 0); - SbieApi_EnumProcessEx = PhGetProcedureAddress(module, SbieApi_EnumProcessEx_Name, 0); - SbieDll_KillAll = PhGetProcedureAddress(module, SbieDll_KillAll_Name, 0); - - if (NT_SUCCESS(RtlCreateTimerQueue(&timerQueueHandle))) - { - RtlCreateTimer(timerQueueHandle, &timerHandle, RefreshSandboxieInfo, NULL, 0, 4000, 0); - } -} - -VOID NTAPI ShowOptionsCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - DialogBox( - PluginInstance->DllBase, - MAKEINTRESOURCE(IDD_OPTIONS), - (HWND)Parameter, - OptionsDlgProc - ); -} - -VOID NTAPI MenuItemCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - PPH_PLUGIN_MENU_ITEM menuItem = Parameter; - - switch (menuItem->Id) - { - case 1: - { - if (PhShowConfirmMessage( - PhMainWndHandle, - L"terminate", - L"all sandboxed processes", - NULL, - FALSE - )) - { - PBOXED_PROCESS boxedProcess; - ULONG enumerationKey = 0; - - // Make sure we have an update-to-date list. - RefreshSandboxieInfo(NULL, FALSE); - - PhAcquireQueuedLockShared(&BoxedProcessesLock); - - while (PhEnumHashtable(BoxedProcessesHashtable, &boxedProcess, &enumerationKey)) - { - HANDLE processHandle; - - if (NT_SUCCESS(PhOpenProcess(&processHandle, PROCESS_TERMINATE, boxedProcess->ProcessId))) - { - PhTerminateProcess(processHandle, STATUS_SUCCESS); - NtClose(processHandle); - } - } - - PhReleaseQueuedLockShared(&BoxedProcessesLock); - } - } - break; - } -} - -VOID NTAPI MainMenuInitializingCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - PPH_PLUGIN_MENU_INFORMATION menuInfo = Parameter; - - if (!SbieDll_KillAll) - return; - if (menuInfo->u.MainMenu.SubMenuIndex != PH_MENU_ITEM_LOCATION_TOOLS) - return; - - PhInsertEMenuItem(menuInfo->Menu, PhPluginCreateEMenuItem(PluginInstance, PH_EMENU_SEPARATOR, 0, NULL, NULL), -1); - PhInsertEMenuItem(menuInfo->Menu, PhPluginCreateEMenuItem(PluginInstance, 0, 1, L"Terminate sandboxed processes", NULL), -1); -} - -VOID NTAPI ProcessesUpdatedCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - PBOXED_PROCESS boxedProcess; - ULONG enumerationKey = 0; - - if (BoxedProcessesUpdated) - { - // Invalidate the nodes of boxed processes (so they use the correct highlighting color). - - PhAcquireQueuedLockShared(&BoxedProcessesLock); - - if (BoxedProcessesUpdated) - { - while (PhEnumHashtable(BoxedProcessesHashtable, &boxedProcess, &enumerationKey)) - { - PPH_PROCESS_NODE processNode; - - if (processNode = PhFindProcessNode(boxedProcess->ProcessId)) - PhUpdateProcessNode(processNode); - } - - BoxedProcessesUpdated = FALSE; - } - - PhReleaseQueuedLockShared(&BoxedProcessesLock); - } -} - -VOID NTAPI GetProcessHighlightingColorCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - PPH_PLUGIN_GET_HIGHLIGHTING_COLOR getHighlightingColor = Parameter; - BOXED_PROCESS lookupBoxedProcess; - PBOXED_PROCESS boxedProcess; - - PhAcquireQueuedLockShared(&BoxedProcessesLock); - - lookupBoxedProcess.ProcessId = ((PPH_PROCESS_ITEM)getHighlightingColor->Parameter)->ProcessId; - - if (boxedProcess = PhFindEntryHashtable(BoxedProcessesHashtable, &lookupBoxedProcess)) - { - getHighlightingColor->BackColor = RGB(0x33, 0x33, 0x00); - getHighlightingColor->Cache = TRUE; - getHighlightingColor->Handled = TRUE; - } - - PhReleaseQueuedLockShared(&BoxedProcessesLock); -} - -VOID NTAPI GetProcessTooltipTextCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - PPH_PLUGIN_GET_TOOLTIP_TEXT getTooltipText = Parameter; - BOXED_PROCESS lookupBoxedProcess; - PBOXED_PROCESS boxedProcess; - - PhAcquireQueuedLockShared(&BoxedProcessesLock); - - lookupBoxedProcess.ProcessId = ((PPH_PROCESS_ITEM)getTooltipText->Parameter)->ProcessId; - - if (boxedProcess = PhFindEntryHashtable(BoxedProcessesHashtable, &lookupBoxedProcess)) - { - PhAppendFormatStringBuilder(getTooltipText->StringBuilder, L"Sandboxie:\n Box name: %s\n", boxedProcess->BoxName); - } - - PhReleaseQueuedLockShared(&BoxedProcessesLock); -} - -VOID NTAPI RefreshSandboxieInfo( - _In_opt_ PVOID Context, - _In_ BOOLEAN TimerOrWaitFired - ) -{ - LONG index; - WCHAR boxName[34]; - ULONG pids[512]; - PBOX_INFO boxInfo; - - if (!SbieApi_QueryBoxPath || !SbieApi_EnumBoxes || !SbieApi_EnumProcessEx) - return; - - PhAcquireQueuedLockExclusive(&BoxedProcessesLock); - - PhClearHashtable(BoxedProcessesHashtable); - - BoxInfoCount = 0; - - index = -1; - - while ((index = SbieApi_EnumBoxes(index, boxName)) != -1) - { - if (SbieApi_EnumProcessEx(boxName, TRUE, 0, pids) == 0) - { - ULONG count; - PULONG pid; - - count = pids[0]; - pid = &pids[1]; - - while (count != 0) - { - BOXED_PROCESS boxedProcess; - - boxedProcess.ProcessId = UlongToHandle(*pid); - memcpy(boxedProcess.BoxName, boxName, sizeof(boxName)); - - PhAddEntryHashtable(BoxedProcessesHashtable, &boxedProcess); - - count--; - pid++; - } - } - - if (BoxInfoCount < 16) - { - ULONG filePathLength = 0; - ULONG keyPathLength = 0; - ULONG ipcPathLength = 0; - - boxInfo = &BoxInfo[BoxInfoCount++]; - memcpy(boxInfo->BoxName, boxName, sizeof(boxName)); - - SbieApi_QueryBoxPath( - boxName, - NULL, - NULL, - NULL, - &filePathLength, - &keyPathLength, - &ipcPathLength - ); - - if (ipcPathLength < sizeof(boxInfo->IpcRootBuffer)) - { - boxInfo->IpcRootBuffer[0] = 0; - SbieApi_QueryBoxPath( - boxName, - NULL, - NULL, - boxInfo->IpcRootBuffer, - NULL, - NULL, - &ipcPathLength - ); - - if (boxInfo->IpcRootBuffer[0] != 0) - { - PhInitializeStringRef(&boxInfo->IpcRoot, boxInfo->IpcRootBuffer); - } - else - { - BoxInfoCount--; - } - } - else - { - BoxInfoCount--; - } - } - } - - BoxedProcessesUpdated = TRUE; - - PhReleaseQueuedLockExclusive(&BoxedProcessesLock); -} - -INT_PTR CALLBACK OptionsDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - switch (uMsg) - { - case WM_INITDIALOG: - { - PPH_STRING sbieDllPath; - - PhCenterWindow(hwndDlg, GetParent(hwndDlg)); - - sbieDllPath = PhaGetStringSetting(SETTING_NAME_SBIE_DLL_PATH); - SetDlgItemText(hwndDlg, IDC_SBIEDLLPATH, sbieDllPath->Buffer); - - SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hwndDlg, IDCANCEL), TRUE); - } - break; - case WM_COMMAND: - { - switch (LOWORD(wParam)) - { - case IDCANCEL: - EndDialog(hwndDlg, IDCANCEL); - break; - case IDOK: - { - PhSetStringSetting2(SETTING_NAME_SBIE_DLL_PATH, - &PhaGetDlgItemText(hwndDlg, IDC_SBIEDLLPATH)->sr); - - EndDialog(hwndDlg, IDOK); - } - break; - case IDC_BROWSE: - { - static PH_FILETYPE_FILTER filters[] = - { - { L"SbieDll.dll", L"SbieDll.dll" }, - { L"All files (*.*)", L"*.*" } - }; - PVOID fileDialog; - PPH_STRING fileName; - - fileDialog = PhCreateOpenFileDialog(); - PhSetFileDialogFilter(fileDialog, filters, sizeof(filters) / sizeof(PH_FILETYPE_FILTER)); - - fileName = PH_AUTO(PhGetFileName(PhaGetDlgItemText(hwndDlg, IDC_SBIEDLLPATH))); - PhSetFileDialogFileName(fileDialog, fileName->Buffer); - - if (PhShowFileDialog(hwndDlg, fileDialog)) - { - fileName = PH_AUTO(PhGetFileDialogFileName(fileDialog)); - SetDlgItemText(hwndDlg, IDC_SBIEDLLPATH, fileName->Buffer); - } - - PhFreeFileDialog(fileDialog); - } - break; - } - } - break; - } - - return FALSE; -} +/* + * Process Hacker Sandboxie Support - + * main program + * + * Copyright (C) 2010-2011 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include +#include "resource.h" +#include "sbiedll.h" + +typedef struct _BOX_INFO +{ + WCHAR BoxName[34]; + PH_STRINGREF IpcRoot; + WCHAR IpcRootBuffer[256]; +} BOX_INFO, *PBOX_INFO; + +typedef struct _BOXED_PROCESS +{ + HANDLE ProcessId; + WCHAR BoxName[34]; +} BOXED_PROCESS, *PBOXED_PROCESS; + +VOID NTAPI LoadCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ); + +VOID NTAPI ShowOptionsCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ); + +VOID NTAPI MenuItemCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ); + +VOID NTAPI MainMenuInitializingCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ); + +VOID NTAPI ProcessesUpdatedCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ); + +VOID NTAPI GetProcessHighlightingColorCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ); + +VOID NTAPI GetProcessTooltipTextCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ); + +VOID NTAPI GetIsDotNetDirectoryNamesCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ); + +VOID NTAPI RefreshSandboxieInfo( + _In_opt_ PVOID Context, + _In_ BOOLEAN TimerOrWaitFired + ); + +INT_PTR CALLBACK OptionsDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +PPH_PLUGIN PluginInstance; +PH_CALLBACK_REGISTRATION PluginLoadCallbackRegistration; +PH_CALLBACK_REGISTRATION PluginShowOptionsCallbackRegistration; +PH_CALLBACK_REGISTRATION PluginMenuItemCallbackRegistration; +PH_CALLBACK_REGISTRATION MainMenuInitializingCallbackRegistration; +PH_CALLBACK_REGISTRATION ProcessesUpdatedCallbackRegistration; +PH_CALLBACK_REGISTRATION GetProcessHighlightingColorCallbackRegistration; +PH_CALLBACK_REGISTRATION GetProcessTooltipTextCallbackRegistration; + +P_SbieApi_QueryBoxPath SbieApi_QueryBoxPath; +P_SbieApi_EnumBoxes SbieApi_EnumBoxes; +P_SbieApi_EnumProcessEx SbieApi_EnumProcessEx; +P_SbieDll_KillAll SbieDll_KillAll; + +PPH_HASHTABLE BoxedProcessesHashtable; +PH_QUEUED_LOCK BoxedProcessesLock = PH_QUEUED_LOCK_INIT; +BOOLEAN BoxedProcessesUpdated = FALSE; + +BOX_INFO BoxInfo[16]; +ULONG BoxInfoCount; + +LOGICAL DllMain( + _In_ HINSTANCE Instance, + _In_ ULONG Reason, + _Reserved_ PVOID Reserved + ) +{ + switch (Reason) + { + case DLL_PROCESS_ATTACH: + { + PPH_PLUGIN_INFORMATION info; + + PluginInstance = PhRegisterPlugin(PLUGIN_NAME, Instance, &info); + + if (!PluginInstance) + return FALSE; + + info->DisplayName = L"Sandboxie Support"; + info->Author = L"wj32"; + info->Description = L"Provides functionality for sandboxed processes."; + info->Url = L"https://wj32.org/processhacker/forums/viewtopic.php?t=1115"; + info->HasOptions = TRUE; + + PhRegisterCallback( + PhGetPluginCallback(PluginInstance, PluginCallbackLoad), + LoadCallback, + NULL, + &PluginLoadCallbackRegistration + ); + PhRegisterCallback( + PhGetPluginCallback(PluginInstance, PluginCallbackShowOptions), + ShowOptionsCallback, + NULL, + &PluginShowOptionsCallbackRegistration + ); + PhRegisterCallback( + PhGetPluginCallback(PluginInstance, PluginCallbackMenuItem), + MenuItemCallback, + NULL, + &PluginMenuItemCallbackRegistration + ); + + PhRegisterCallback( + PhGetGeneralCallback(GeneralCallbackMainMenuInitializing), + MainMenuInitializingCallback, + NULL, + &MainMenuInitializingCallbackRegistration + ); + PhRegisterCallback( + PhGetGeneralCallback(GeneralCallbackProcessesUpdated), + ProcessesUpdatedCallback, + NULL, + &ProcessesUpdatedCallbackRegistration + ); + PhRegisterCallback( + PhGetGeneralCallback(GeneralCallbackGetProcessHighlightingColor), + GetProcessHighlightingColorCallback, + NULL, + &GetProcessHighlightingColorCallbackRegistration + ); + PhRegisterCallback( + PhGetGeneralCallback(GeneralCallbackGetProcessTooltipText), + GetProcessTooltipTextCallback, + NULL, + &GetProcessTooltipTextCallbackRegistration + ); + + { + static PH_SETTING_CREATE settings[] = + { + { StringSettingType, SETTING_NAME_SBIE_DLL_PATH, L"C:\\Program Files\\Sandboxie\\SbieDll.dll" } + }; + + PhAddSettings(settings, sizeof(settings) / sizeof(PH_SETTING_CREATE)); + } + } + break; + } + + return TRUE; +} + +BOOLEAN NTAPI BoxedProcessesEqualFunction( + _In_ PVOID Entry1, + _In_ PVOID Entry2 + ) +{ + return ((PBOXED_PROCESS)Entry1)->ProcessId == ((PBOXED_PROCESS)Entry2)->ProcessId; +} + +ULONG NTAPI BoxedProcessesHashFunction( + _In_ PVOID Entry + ) +{ + return HandleToUlong(((PBOXED_PROCESS)Entry)->ProcessId) / 4; +} + +VOID NTAPI LoadCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + PPH_STRING sbieDllPath; + HMODULE module; + HANDLE timerQueueHandle; + HANDLE timerHandle; + + BoxedProcessesHashtable = PhCreateHashtable( + sizeof(BOXED_PROCESS), + BoxedProcessesEqualFunction, + BoxedProcessesHashFunction, + 32 + ); + + sbieDllPath = PhaGetStringSetting(SETTING_NAME_SBIE_DLL_PATH); + module = LoadLibrary(sbieDllPath->Buffer); + + SbieApi_QueryBoxPath = PhGetProcedureAddress(module, SbieApi_QueryBoxPath_Name, 0); + SbieApi_EnumBoxes = PhGetProcedureAddress(module, SbieApi_EnumBoxes_Name, 0); + SbieApi_EnumProcessEx = PhGetProcedureAddress(module, SbieApi_EnumProcessEx_Name, 0); + SbieDll_KillAll = PhGetProcedureAddress(module, SbieDll_KillAll_Name, 0); + + if (NT_SUCCESS(RtlCreateTimerQueue(&timerQueueHandle))) + { + RtlCreateTimer(timerQueueHandle, &timerHandle, RefreshSandboxieInfo, NULL, 0, 4000, 0); + } +} + +VOID NTAPI ShowOptionsCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + DialogBox( + PluginInstance->DllBase, + MAKEINTRESOURCE(IDD_OPTIONS), + (HWND)Parameter, + OptionsDlgProc + ); +} + +VOID NTAPI MenuItemCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + PPH_PLUGIN_MENU_ITEM menuItem = Parameter; + + switch (menuItem->Id) + { + case 1: + { + if (PhShowConfirmMessage( + PhMainWndHandle, + L"terminate", + L"all sandboxed processes", + NULL, + FALSE + )) + { + PBOXED_PROCESS boxedProcess; + ULONG enumerationKey = 0; + + // Make sure we have an update-to-date list. + RefreshSandboxieInfo(NULL, FALSE); + + PhAcquireQueuedLockShared(&BoxedProcessesLock); + + while (PhEnumHashtable(BoxedProcessesHashtable, &boxedProcess, &enumerationKey)) + { + HANDLE processHandle; + + if (NT_SUCCESS(PhOpenProcess(&processHandle, PROCESS_TERMINATE, boxedProcess->ProcessId))) + { + PhTerminateProcess(processHandle, STATUS_SUCCESS); + NtClose(processHandle); + } + } + + PhReleaseQueuedLockShared(&BoxedProcessesLock); + } + } + break; + } +} + +VOID NTAPI MainMenuInitializingCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + PPH_PLUGIN_MENU_INFORMATION menuInfo = Parameter; + + if (!SbieDll_KillAll) + return; + if (menuInfo->u.MainMenu.SubMenuIndex != PH_MENU_ITEM_LOCATION_TOOLS) + return; + + PhInsertEMenuItem(menuInfo->Menu, PhPluginCreateEMenuItem(PluginInstance, PH_EMENU_SEPARATOR, 0, NULL, NULL), -1); + PhInsertEMenuItem(menuInfo->Menu, PhPluginCreateEMenuItem(PluginInstance, 0, 1, L"Terminate sandboxed processes", NULL), -1); +} + +VOID NTAPI ProcessesUpdatedCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + PBOXED_PROCESS boxedProcess; + ULONG enumerationKey = 0; + + if (BoxedProcessesUpdated) + { + // Invalidate the nodes of boxed processes (so they use the correct highlighting color). + + PhAcquireQueuedLockShared(&BoxedProcessesLock); + + if (BoxedProcessesUpdated) + { + while (PhEnumHashtable(BoxedProcessesHashtable, &boxedProcess, &enumerationKey)) + { + PPH_PROCESS_NODE processNode; + + if (processNode = PhFindProcessNode(boxedProcess->ProcessId)) + PhUpdateProcessNode(processNode); + } + + BoxedProcessesUpdated = FALSE; + } + + PhReleaseQueuedLockShared(&BoxedProcessesLock); + } +} + +VOID NTAPI GetProcessHighlightingColorCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + PPH_PLUGIN_GET_HIGHLIGHTING_COLOR getHighlightingColor = Parameter; + BOXED_PROCESS lookupBoxedProcess; + PBOXED_PROCESS boxedProcess; + + PhAcquireQueuedLockShared(&BoxedProcessesLock); + + lookupBoxedProcess.ProcessId = ((PPH_PROCESS_ITEM)getHighlightingColor->Parameter)->ProcessId; + + if (boxedProcess = PhFindEntryHashtable(BoxedProcessesHashtable, &lookupBoxedProcess)) + { + getHighlightingColor->BackColor = RGB(0x33, 0x33, 0x00); + getHighlightingColor->Cache = TRUE; + getHighlightingColor->Handled = TRUE; + } + + PhReleaseQueuedLockShared(&BoxedProcessesLock); +} + +VOID NTAPI GetProcessTooltipTextCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + PPH_PLUGIN_GET_TOOLTIP_TEXT getTooltipText = Parameter; + BOXED_PROCESS lookupBoxedProcess; + PBOXED_PROCESS boxedProcess; + + PhAcquireQueuedLockShared(&BoxedProcessesLock); + + lookupBoxedProcess.ProcessId = ((PPH_PROCESS_ITEM)getTooltipText->Parameter)->ProcessId; + + if (boxedProcess = PhFindEntryHashtable(BoxedProcessesHashtable, &lookupBoxedProcess)) + { + PhAppendFormatStringBuilder(getTooltipText->StringBuilder, L"Sandboxie:\n Box name: %s\n", boxedProcess->BoxName); + } + + PhReleaseQueuedLockShared(&BoxedProcessesLock); +} + +VOID NTAPI RefreshSandboxieInfo( + _In_opt_ PVOID Context, + _In_ BOOLEAN TimerOrWaitFired + ) +{ + LONG index; + WCHAR boxName[34]; + ULONG pids[512]; + PBOX_INFO boxInfo; + + if (!SbieApi_QueryBoxPath || !SbieApi_EnumBoxes || !SbieApi_EnumProcessEx) + return; + + PhAcquireQueuedLockExclusive(&BoxedProcessesLock); + + PhClearHashtable(BoxedProcessesHashtable); + + BoxInfoCount = 0; + + index = -1; + + while ((index = SbieApi_EnumBoxes(index, boxName)) != -1) + { + if (SbieApi_EnumProcessEx(boxName, TRUE, 0, pids) == 0) + { + ULONG count; + PULONG pid; + + count = pids[0]; + pid = &pids[1]; + + while (count != 0) + { + BOXED_PROCESS boxedProcess; + + boxedProcess.ProcessId = UlongToHandle(*pid); + memcpy(boxedProcess.BoxName, boxName, sizeof(boxName)); + + PhAddEntryHashtable(BoxedProcessesHashtable, &boxedProcess); + + count--; + pid++; + } + } + + if (BoxInfoCount < 16) + { + ULONG filePathLength = 0; + ULONG keyPathLength = 0; + ULONG ipcPathLength = 0; + + boxInfo = &BoxInfo[BoxInfoCount++]; + memcpy(boxInfo->BoxName, boxName, sizeof(boxName)); + + SbieApi_QueryBoxPath( + boxName, + NULL, + NULL, + NULL, + &filePathLength, + &keyPathLength, + &ipcPathLength + ); + + if (ipcPathLength < sizeof(boxInfo->IpcRootBuffer)) + { + boxInfo->IpcRootBuffer[0] = 0; + SbieApi_QueryBoxPath( + boxName, + NULL, + NULL, + boxInfo->IpcRootBuffer, + NULL, + NULL, + &ipcPathLength + ); + + if (boxInfo->IpcRootBuffer[0] != 0) + { + PhInitializeStringRef(&boxInfo->IpcRoot, boxInfo->IpcRootBuffer); + } + else + { + BoxInfoCount--; + } + } + else + { + BoxInfoCount--; + } + } + } + + BoxedProcessesUpdated = TRUE; + + PhReleaseQueuedLockExclusive(&BoxedProcessesLock); +} + +INT_PTR CALLBACK OptionsDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + switch (uMsg) + { + case WM_INITDIALOG: + { + PPH_STRING sbieDllPath; + + PhCenterWindow(hwndDlg, GetParent(hwndDlg)); + + sbieDllPath = PhaGetStringSetting(SETTING_NAME_SBIE_DLL_PATH); + SetDlgItemText(hwndDlg, IDC_SBIEDLLPATH, sbieDllPath->Buffer); + + SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hwndDlg, IDCANCEL), TRUE); + } + break; + case WM_COMMAND: + { + switch (LOWORD(wParam)) + { + case IDCANCEL: + EndDialog(hwndDlg, IDCANCEL); + break; + case IDOK: + { + PhSetStringSetting2(SETTING_NAME_SBIE_DLL_PATH, + &PhaGetDlgItemText(hwndDlg, IDC_SBIEDLLPATH)->sr); + + EndDialog(hwndDlg, IDOK); + } + break; + case IDC_BROWSE: + { + static PH_FILETYPE_FILTER filters[] = + { + { L"SbieDll.dll", L"SbieDll.dll" }, + { L"All files (*.*)", L"*.*" } + }; + PVOID fileDialog; + PPH_STRING fileName; + + fileDialog = PhCreateOpenFileDialog(); + PhSetFileDialogFilter(fileDialog, filters, sizeof(filters) / sizeof(PH_FILETYPE_FILTER)); + + fileName = PH_AUTO(PhGetFileName(PhaGetDlgItemText(hwndDlg, IDC_SBIEDLLPATH))); + PhSetFileDialogFileName(fileDialog, fileName->Buffer); + + if (PhShowFileDialog(hwndDlg, fileDialog)) + { + fileName = PH_AUTO(PhGetFileDialogFileName(fileDialog)); + SetDlgItemText(hwndDlg, IDC_SBIEDLLPATH, fileName->Buffer); + } + + PhFreeFileDialog(fileDialog); + } + break; + } + } + break; + } + + return FALSE; +} diff --git a/plugins/SbieSupport/resource.h b/plugins/SbieSupport/resource.h index 343b05f2006b..b338721498ca 100644 --- a/plugins/SbieSupport/resource.h +++ b/plugins/SbieSupport/resource.h @@ -1,18 +1,18 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by SbieSupport.rc -// -#define IDD_OPTIONS 101 -#define IDC_SBIEDLLPATH 1001 -#define IDC_BROWSE 1002 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 102 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1003 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by SbieSupport.rc +// +#define IDD_OPTIONS 101 +#define IDC_SBIEDLLPATH 1001 +#define IDC_BROWSE 1002 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 102 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1003 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/plugins/SbieSupport/sbiedll.h b/plugins/SbieSupport/sbiedll.h index 073349f2e7b8..fab2af6674ac 100644 --- a/plugins/SbieSupport/sbiedll.h +++ b/plugins/SbieSupport/sbiedll.h @@ -1,42 +1,42 @@ -#ifndef SBIEDLL_H -#define SBIEDLL_H - -#define PLUGIN_NAME L"ProcessHacker.SbieSupport" -#define SETTING_NAME_SBIE_DLL_PATH (PLUGIN_NAME L".SbieDllPath") - -typedef LONG (__stdcall *P_SbieApi_QueryBoxPath)( - const WCHAR *box_name, // pointer to WCHAR [34] - WCHAR *file_path, - WCHAR *key_path, - WCHAR *ipc_path, - ULONG *file_path_len, - ULONG *key_path_len, - ULONG *ipc_path_len); - -typedef LONG (__stdcall *P_SbieApi_EnumBoxes)( - LONG index, // initialize to -1 - WCHAR *box_name); // pointer to WCHAR [34] - -typedef LONG (__stdcall *P_SbieApi_EnumProcessEx)( - const WCHAR *box_name, // pointer to WCHAR [34] - BOOLEAN all_sessions, - ULONG which_session, - ULONG *boxed_pids); // pointer to ULONG [512] - -typedef BOOLEAN (__stdcall *P_SbieDll_KillAll)( - ULONG session_id, - const WCHAR *box_name); - -#ifdef _WIN64 -#define SbieApi_QueryBoxPath_Name "SbieApi_QueryBoxPath" -#define SbieApi_EnumBoxes_Name "SbieApi_EnumBoxes" -#define SbieApi_EnumProcessEx_Name "SbieApi_EnumProcessEx" -#define SbieDll_KillAll_Name "SbieDll_KillAll" -#else -#define SbieApi_QueryBoxPath_Name "_SbieApi_QueryBoxPath@28" -#define SbieApi_EnumBoxes_Name "_SbieApi_EnumBoxes@8" -#define SbieApi_EnumProcessEx_Name "_SbieApi_EnumProcessEx@16" -#define SbieDll_KillAll_Name "_SbieDll_KillAll@8" -#endif - -#endif +#ifndef SBIEDLL_H +#define SBIEDLL_H + +#define PLUGIN_NAME L"ProcessHacker.SbieSupport" +#define SETTING_NAME_SBIE_DLL_PATH (PLUGIN_NAME L".SbieDllPath") + +typedef LONG (__stdcall *P_SbieApi_QueryBoxPath)( + const WCHAR *box_name, // pointer to WCHAR [34] + WCHAR *file_path, + WCHAR *key_path, + WCHAR *ipc_path, + ULONG *file_path_len, + ULONG *key_path_len, + ULONG *ipc_path_len); + +typedef LONG (__stdcall *P_SbieApi_EnumBoxes)( + LONG index, // initialize to -1 + WCHAR *box_name); // pointer to WCHAR [34] + +typedef LONG (__stdcall *P_SbieApi_EnumProcessEx)( + const WCHAR *box_name, // pointer to WCHAR [34] + BOOLEAN all_sessions, + ULONG which_session, + ULONG *boxed_pids); // pointer to ULONG [512] + +typedef BOOLEAN (__stdcall *P_SbieDll_KillAll)( + ULONG session_id, + const WCHAR *box_name); + +#ifdef _WIN64 +#define SbieApi_QueryBoxPath_Name "SbieApi_QueryBoxPath" +#define SbieApi_EnumBoxes_Name "SbieApi_EnumBoxes" +#define SbieApi_EnumProcessEx_Name "SbieApi_EnumProcessEx" +#define SbieDll_KillAll_Name "SbieDll_KillAll" +#else +#define SbieApi_QueryBoxPath_Name "_SbieApi_QueryBoxPath@28" +#define SbieApi_EnumBoxes_Name "_SbieApi_EnumBoxes@8" +#define SbieApi_EnumProcessEx_Name "_SbieApi_EnumProcessEx@16" +#define SbieDll_KillAll_Name "_SbieDll_KillAll@8" +#endif + +#endif diff --git a/plugins/ToolStatus/CHANGELOG.txt b/plugins/ToolStatus/CHANGELOG.txt index 2e1ec94f0175..87015dfac5d5 100644 --- a/plugins/ToolStatus/CHANGELOG.txt +++ b/plugins/ToolStatus/CHANGELOG.txt @@ -1,64 +1,64 @@ -2.4 - * Added 32x32 icons for high DPI displays - * Fixed status bar crash - -2.3 - * Added Auto-hide main menu - * Added CPU, Memory and IO graphs to main window - * Added Right-click menu on the Toolbar - * Added Toolbar customize dialog - * Added Statusbar customize dialog - -2.2 - * Added Modern Toolbar theme - * Added portable Toolbar customization - * Added Toolbar power menu (ported from PH1.x) - * Fixed Toolbar DPI scaling issues - -2.1 - * Fixed Auto-hide Searchbox (Ctrl+K to show) - -2.0 - * Added Toolbar customization - * Added Rebar Chevron support - * Added Auto-hide Searchbox - * Fixed searching multiple processes - -1.9 - * Added PNG images - * Fixed search box fonts - * Fixed plugin settings state (disable/enable) - * Updated Searchbox UI - * Updated Searchbox commands - * Updated plugin settings - -1.8 - * Added search box - -1.7 - * Added option to configure Toolbar display style. - -1.6 - * Fixed Always on Top being reset when using Find Window - * Fixed Esc key when using Find Window - -1.5 - * Added Find Window and Kill - -1.4 - * Added option to resolve ghost windows to the hung windows - they represent - -1.3 - * Fixed layout problems - -1.2 - * Added options - * Status bar panel widths are more stable - -1.1 - * Fixed hanging when using Find Window on hung programs - * Fixed status bar with no selected parts - -1.0 +2.4 + * Added 32x32 icons for high DPI displays + * Fixed status bar crash + +2.3 + * Added Auto-hide main menu + * Added CPU, Memory and IO graphs to main window + * Added Right-click menu on the Toolbar + * Added Toolbar customize dialog + * Added Statusbar customize dialog + +2.2 + * Added Modern Toolbar theme + * Added portable Toolbar customization + * Added Toolbar power menu (ported from PH1.x) + * Fixed Toolbar DPI scaling issues + +2.1 + * Fixed Auto-hide Searchbox (Ctrl+K to show) + +2.0 + * Added Toolbar customization + * Added Rebar Chevron support + * Added Auto-hide Searchbox + * Fixed searching multiple processes + +1.9 + * Added PNG images + * Fixed search box fonts + * Fixed plugin settings state (disable/enable) + * Updated Searchbox UI + * Updated Searchbox commands + * Updated plugin settings + +1.8 + * Added search box + +1.7 + * Added option to configure Toolbar display style. + +1.6 + * Fixed Always on Top being reset when using Find Window + * Fixed Esc key when using Find Window + +1.5 + * Added Find Window and Kill + +1.4 + * Added option to resolve ghost windows to the hung windows + they represent + +1.3 + * Fixed layout problems + +1.2 + * Added options + * Status bar panel widths are more stable + +1.1 + * Fixed hanging when using Find Window on hung programs + * Fixed status bar with no selected parts + +1.0 * Initial release \ No newline at end of file diff --git a/plugins/ToolStatus/ToolStatus.rc b/plugins/ToolStatus/ToolStatus.rc index 9b9ae88f59cb..b0862532cf6f 100644 --- a/plugins/ToolStatus/ToolStatus.rc +++ b/plugins/ToolStatus/ToolStatus.rc @@ -1,277 +1,277 @@ -// Microsoft Visual C++ generated resource script. -// -#include "resource.h" - -#define APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// -#include "winres.h" -///////////////////////////////////////////////////////////////////////////// -#undef APSTUDIO_READONLY_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -// English (Australia) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENA) -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_AUS -#pragma code_page(1252) - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -1 TEXTINCLUDE -BEGIN - "resource.h\0" -END - -2 TEXTINCLUDE -BEGIN - "#include ""winres.h""\0" -END - -3 TEXTINCLUDE -BEGIN - "\r\n" - "\0" -END - -#endif // APSTUDIO_INVOKED - - -///////////////////////////////////////////////////////////////////////////// -// -// Version -// - -VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,4,0,0 - PRODUCTVERSION 2,4,0,0 - FILEFLAGSMASK 0x3fL -#ifdef _DEBUG - FILEFLAGS 0x1L -#else - FILEFLAGS 0x0L -#endif - FILEOS 0x40004L - FILETYPE 0x2L - FILESUBTYPE 0x0L -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "0c0904b0" - BEGIN - VALUE "CompanyName", "dmex" - VALUE "FileDescription", "ToolStatus plugin for Process Hacker" - VALUE "FileVersion", "2.4" - VALUE "InternalName", "ProcessHacker.ToolStatus" - VALUE "LegalCopyright", "Licensed under the GNU GPL, v3." - VALUE "OriginalFilename", "ToolStatus.dll" - VALUE "ProductName", "ToolStatus plugin for Process Hacker" - VALUE "ProductVersion", "2.4" - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0xc09, 1200 - END -END - - -///////////////////////////////////////////////////////////////////////////// -// -// Dialog -// - -IDD_OPTIONS DIALOGEX 0, 0, 191, 103 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Options" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - CONTROL "Enable toolbar",IDC_ENABLE_TOOLBAR,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,7,62,10 - CONTROL "Enable status bar",IDC_ENABLE_STATUSBAR,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,19,72,10 - CONTROL "Resolve ghost windows to hung windows",IDC_RESOLVEGHOSTWINDOWS, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,32,152,10 - CONTROL "Auto-hide main menu (Alt or F10 key toggle)",IDC_ENABLE_AUTOHIDE_MENU, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,44,157,10 - DEFPUSHBUTTON "Close",IDOK,134,82,50,14 - LTEXT "Note: Right-click the toolbar on the main window to customize the icons and graphs.",IDC_STATIC,7,59,157,18 -END - -IDD_CUSTOMIZE_TB DIALOGEX 0, 0, 369, 188 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Customize Toolbar" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "Available toolbar buttons:",IDC_STATIC,7,7,85,8 - LISTBOX IDC_AVAILABLE,7,18,122,117,LBS_OWNERDRAWFIXED | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP - PUSHBUTTON "Add >",IDC_ADD,133,50,50,14 - PUSHBUTTON "< Remove",IDC_REMOVE,133,68,50,14 - LTEXT "Current toolbar buttons:",IDC_STATIC,188,7,81,8 - LISTBOX IDC_CURRENT,187,18,122,117,LBS_OWNERDRAWFIXED | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP - PUSHBUTTON "Move up",IDC_MOVEUP,312,18,50,14 - PUSHBUTTON "Move down",IDC_MOVEDOWN,312,36,50,14 - LTEXT "Text options:",IDC_STATIC,7,142,44,8 - COMBOBOX IDC_TEXTOPTIONS,56,139,113,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LTEXT "Search box:",IDC_STATIC,7,158,45,8 - COMBOBOX IDC_SEARCHOPTIONS,56,155,113,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - CONTROL "Enable modern icons",IDC_ENABLE_MODERN,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,188,139,83,10 - CONTROL "Auto-hide main menu (Alt or F10 key toggle)",IDC_ENABLE_AUTOHIDE_MENU, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,188,152,157,10 - PUSHBUTTON "Reset",IDC_RESET,258,167,50,14 - DEFPUSHBUTTON "Close",IDCANCEL,312,167,50,14 -END - -IDD_CUSTOMIZE_SB DIALOGEX 0, 0, 373, 142 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Customize Status Bar" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "Available status bar entries:",-1,7,7,91,8 - LISTBOX IDC_AVAILABLE,7,18,122,117,LBS_OWNERDRAWFIXED | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP - PUSHBUTTON "Add >",IDC_ADD,133,50,50,14 - PUSHBUTTON "< Remove",IDC_REMOVE,133,68,50,14 - LTEXT "Current status bar entries:",-1,188,7,87,8 - LISTBOX IDC_CURRENT,187,18,122,117,LBS_OWNERDRAWFIXED | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP - PUSHBUTTON "Move up",IDC_MOVEUP,316,18,50,14 - PUSHBUTTON "Move down",IDC_MOVEDOWN,316,36,50,14 - PUSHBUTTON "Reset",IDC_RESET,316,103,50,14 - DEFPUSHBUTTON "Close",IDCANCEL,316,121,50,14 -END - - -///////////////////////////////////////////////////////////////////////////// -// -// DESIGNINFO -// - -#ifdef APSTUDIO_INVOKED -GUIDELINES DESIGNINFO -BEGIN - IDD_OPTIONS, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 184 - TOPMARGIN, 7 - BOTTOMMARGIN, 96 - END - - IDD_CUSTOMIZE_TB, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 362 - TOPMARGIN, 7 - BOTTOMMARGIN, 181 - END - - IDD_CUSTOMIZE_SB, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 366 - TOPMARGIN, 7 - BOTTOMMARGIN, 135 - END -END -#endif // APSTUDIO_INVOKED - - -///////////////////////////////////////////////////////////////////////////// -// -// Accelerator -// - -IDR_MAINWND_ACCEL ACCELERATORS -BEGIN - "K", ID_SEARCH, VIRTKEY, CONTROL, NOINVERT -END - - -///////////////////////////////////////////////////////////////////////////// -// -// PNG -// - -IDB_APPLICATION_GET_MODERN PNG "resources\\application_get_modern.png" - -IDB_APPLICATION_GO_MODERN PNG "resources\\application_go_modern.png" - -IDB_APPLICATION_MODERN PNG "resources\\application_modern.png" - -IDB_ARROW_REFRESH_MODERN PNG "resources\\arrow_refresh_modern.png" - -IDB_CHART_LINE_MODERN PNG "resources\\chart_line_modern.png" - -IDB_COG_EDIT_MODERN PNG "resources\\cog_edit_modern.png" - -IDB_CROSS_MODERN PNG "resources\\cross_modern.png" - -IDB_FIND_MODERN PNG "resources\\find_modern.png" - -IDB_POWER_MODERN PNG "resources\\lightbulb_off_modern.png" - - -///////////////////////////////////////////////////////////////////////////// -// -// AFX_DIALOG_LAYOUT -// - -IDD_OPTIONS AFX_DIALOG_LAYOUT -BEGIN - 0 -END - -IDD_CUSTOMIZE_TB AFX_DIALOG_LAYOUT -BEGIN - 0 -END - -IDD_CUSTOMIZE_SB AFX_DIALOG_LAYOUT -BEGIN - 0 -END - - -///////////////////////////////////////////////////////////////////////////// -// -// Icon -// - -// Icon with lowest ID value placed first to ensure application icon -// remains consistent on all systems. -IDI_ARROW_REFRESH ICON "resources\\arrow_refresh.ico" - -IDI_COG_EDIT ICON "resources\\cog_edit.ico" - -IDI_FIND ICON "resources\\find.ico" - -IDI_CHART_LINE ICON "resources\\chart_line.ico" - -IDI_TBAPPLICATION ICON "resources\\application.ico" - -IDI_APPLICATION_GO ICON "resources\\application_go.ico" - -IDI_CROSS ICON "resources\\cross.ico" - -IDI_APPLICATION_GET ICON "resources\\application_get.ico" - -IDI_LIGHTBULB_OFF ICON "resources\\lightbulb_off.ico" - -#endif // English (Australia) resources -///////////////////////////////////////////////////////////////////////////// - - - -#ifndef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// - - -///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED - +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "winres.h" +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (Australia) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENA) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_AUS +#pragma code_page(1252) + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""winres.h""\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 2,4,0,0 + PRODUCTVERSION 2,4,0,0 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "0c0904b0" + BEGIN + VALUE "CompanyName", "dmex" + VALUE "FileDescription", "ToolStatus plugin for Process Hacker" + VALUE "FileVersion", "2.4" + VALUE "InternalName", "ProcessHacker.ToolStatus" + VALUE "LegalCopyright", "Licensed under the GNU GPL, v3." + VALUE "OriginalFilename", "ToolStatus.dll" + VALUE "ProductName", "ToolStatus plugin for Process Hacker" + VALUE "ProductVersion", "2.4" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0xc09, 1200 + END +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_OPTIONS DIALOGEX 0, 0, 191, 103 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Options" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + CONTROL "Enable toolbar",IDC_ENABLE_TOOLBAR,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,7,62,10 + CONTROL "Enable status bar",IDC_ENABLE_STATUSBAR,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,19,72,10 + CONTROL "Resolve ghost windows to hung windows",IDC_RESOLVEGHOSTWINDOWS, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,32,152,10 + CONTROL "Auto-hide main menu (Alt or F10 key toggle)",IDC_ENABLE_AUTOHIDE_MENU, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,44,157,10 + DEFPUSHBUTTON "Close",IDOK,134,82,50,14 + LTEXT "Note: Right-click the toolbar on the main window to customize the icons and graphs.",IDC_STATIC,7,59,157,18 +END + +IDD_CUSTOMIZE_TB DIALOGEX 0, 0, 369, 188 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Customize Toolbar" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "Available toolbar buttons:",IDC_STATIC,7,7,85,8 + LISTBOX IDC_AVAILABLE,7,18,122,117,LBS_OWNERDRAWFIXED | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Add >",IDC_ADD,133,50,50,14 + PUSHBUTTON "< Remove",IDC_REMOVE,133,68,50,14 + LTEXT "Current toolbar buttons:",IDC_STATIC,188,7,81,8 + LISTBOX IDC_CURRENT,187,18,122,117,LBS_OWNERDRAWFIXED | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Move up",IDC_MOVEUP,312,18,50,14 + PUSHBUTTON "Move down",IDC_MOVEDOWN,312,36,50,14 + LTEXT "Text options:",IDC_STATIC,7,142,44,8 + COMBOBOX IDC_TEXTOPTIONS,56,139,113,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + LTEXT "Search box:",IDC_STATIC,7,158,45,8 + COMBOBOX IDC_SEARCHOPTIONS,56,155,113,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + CONTROL "Enable modern icons",IDC_ENABLE_MODERN,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,188,139,83,10 + CONTROL "Auto-hide main menu (Alt or F10 key toggle)",IDC_ENABLE_AUTOHIDE_MENU, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,188,152,157,10 + PUSHBUTTON "Reset",IDC_RESET,258,167,50,14 + DEFPUSHBUTTON "Close",IDCANCEL,312,167,50,14 +END + +IDD_CUSTOMIZE_SB DIALOGEX 0, 0, 373, 142 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Customize Status Bar" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "Available status bar entries:",-1,7,7,91,8 + LISTBOX IDC_AVAILABLE,7,18,122,117,LBS_OWNERDRAWFIXED | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Add >",IDC_ADD,133,50,50,14 + PUSHBUTTON "< Remove",IDC_REMOVE,133,68,50,14 + LTEXT "Current status bar entries:",-1,188,7,87,8 + LISTBOX IDC_CURRENT,187,18,122,117,LBS_OWNERDRAWFIXED | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Move up",IDC_MOVEUP,316,18,50,14 + PUSHBUTTON "Move down",IDC_MOVEDOWN,316,36,50,14 + PUSHBUTTON "Reset",IDC_RESET,316,103,50,14 + DEFPUSHBUTTON "Close",IDCANCEL,316,121,50,14 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_OPTIONS, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 184 + TOPMARGIN, 7 + BOTTOMMARGIN, 96 + END + + IDD_CUSTOMIZE_TB, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 362 + TOPMARGIN, 7 + BOTTOMMARGIN, 181 + END + + IDD_CUSTOMIZE_SB, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 366 + TOPMARGIN, 7 + BOTTOMMARGIN, 135 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Accelerator +// + +IDR_MAINWND_ACCEL ACCELERATORS +BEGIN + "K", ID_SEARCH, VIRTKEY, CONTROL, NOINVERT +END + + +///////////////////////////////////////////////////////////////////////////// +// +// PNG +// + +IDB_APPLICATION_GET_MODERN PNG "resources\\application_get_modern.png" + +IDB_APPLICATION_GO_MODERN PNG "resources\\application_go_modern.png" + +IDB_APPLICATION_MODERN PNG "resources\\application_modern.png" + +IDB_ARROW_REFRESH_MODERN PNG "resources\\arrow_refresh_modern.png" + +IDB_CHART_LINE_MODERN PNG "resources\\chart_line_modern.png" + +IDB_COG_EDIT_MODERN PNG "resources\\cog_edit_modern.png" + +IDB_CROSS_MODERN PNG "resources\\cross_modern.png" + +IDB_FIND_MODERN PNG "resources\\find_modern.png" + +IDB_POWER_MODERN PNG "resources\\lightbulb_off_modern.png" + + +///////////////////////////////////////////////////////////////////////////// +// +// AFX_DIALOG_LAYOUT +// + +IDD_OPTIONS AFX_DIALOG_LAYOUT +BEGIN + 0 +END + +IDD_CUSTOMIZE_TB AFX_DIALOG_LAYOUT +BEGIN + 0 +END + +IDD_CUSTOMIZE_SB AFX_DIALOG_LAYOUT +BEGIN + 0 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_ARROW_REFRESH ICON "resources\\arrow_refresh.ico" + +IDI_COG_EDIT ICON "resources\\cog_edit.ico" + +IDI_FIND ICON "resources\\find.ico" + +IDI_CHART_LINE ICON "resources\\chart_line.ico" + +IDI_TBAPPLICATION ICON "resources\\application.ico" + +IDI_APPLICATION_GO ICON "resources\\application_go.ico" + +IDI_CROSS ICON "resources\\cross.ico" + +IDI_APPLICATION_GET ICON "resources\\application_get.ico" + +IDI_LIGHTBULB_OFF ICON "resources\\lightbulb_off.ico" + +#endif // English (Australia) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/plugins/ToolStatus/ToolStatus.vcxproj b/plugins/ToolStatus/ToolStatus.vcxproj index 08a9206043e7..b92b848af210 100644 --- a/plugins/ToolStatus/ToolStatus.vcxproj +++ b/plugins/ToolStatus/ToolStatus.vcxproj @@ -1,116 +1,116 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {60B43533-C75E-4741-9E19-C4D581BEF51C} - ToolStatus - Win32Proj - ToolStatus - 10.0.15063.0 - - - - DynamicLibrary - Unicode - v141 - - - DynamicLibrary - Unicode - v141 - - - DynamicLibrary - Unicode - v141 - - - DynamicLibrary - Unicode - v141 - - - - - - - - - uxtheme.lib;%(AdditionalDependencies) - - - - - uxtheme.lib;%(AdditionalDependencies) - - - - - uxtheme.lib;%(AdditionalDependencies) - - - - - uxtheme.lib;%(AdditionalDependencies) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {60B43533-C75E-4741-9E19-C4D581BEF51C} + ToolStatus + Win32Proj + ToolStatus + 10.0.15063.0 + + + + DynamicLibrary + Unicode + v141 + + + DynamicLibrary + Unicode + v141 + + + DynamicLibrary + Unicode + v141 + + + DynamicLibrary + Unicode + v141 + + + + + + + + + uxtheme.lib;%(AdditionalDependencies) + + + + + uxtheme.lib;%(AdditionalDependencies) + + + + + uxtheme.lib;%(AdditionalDependencies) + + + + + uxtheme.lib;%(AdditionalDependencies) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/plugins/ToolStatus/customizesb.c b/plugins/ToolStatus/customizesb.c index fc78e31d370b..6b7d51ef4cdf 100644 --- a/plugins/ToolStatus/customizesb.c +++ b/plugins/ToolStatus/customizesb.c @@ -1,633 +1,633 @@ -/* - * Process Hacker ToolStatus - - * Statusbar Customize Dialog - * - * Copyright (C) 2015-2016 dmex - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include "toolstatus.h" -#include "commonutil.h" - -BOOLEAN CustomizeStatusBarItemExists( - _In_ PCUSTOMIZE_CONTEXT Context, - _In_ INT IdCommand - ) -{ - INT index = 0; - INT count = 0; - PBUTTON_CONTEXT button; - - if ((count = ListBox_GetCount(Context->CurrentListHandle)) == LB_ERR) - return FALSE; - - for (index = 0; index < count; index++) - { - if (!(button = (PBUTTON_CONTEXT)ListBox_GetItemData(Context->CurrentListHandle, index))) - continue; - - if (button->IdCommand == IdCommand) - return TRUE; - } - - return FALSE; -} - -VOID CustomizeInsertStatusBarItem( - _In_ INT Index, - _In_ PBUTTON_CONTEXT Button - ) -{ - PSTATUSBAR_ITEM item; - - item = PhAllocate(sizeof(STATUSBAR_ITEM)); - memset(item, 0, sizeof(STATUSBAR_ITEM)); - - item->Id = Button->IdCommand; - - PhInsertItemList(StatusBarItemList, Index, item); - - StatusBarUpdate(TRUE); -} - -VOID CustomizeAddStatusBarItem( - _In_ PCUSTOMIZE_CONTEXT Context, - _In_ INT IndexAvail, - _In_ INT IndexTo - ) -{ - INT count; - PBUTTON_CONTEXT button; - - if ((count = ListBox_GetCount(Context->AvailableListHandle)) == LB_ERR) - return; - - if (!(button = (PBUTTON_CONTEXT)ListBox_GetItemData(Context->AvailableListHandle, IndexAvail))) - return; - - if (!button->IsVirtual) - { - // remove from 'available' list - ListBox_DeleteString(Context->AvailableListHandle, IndexAvail); - - if (IndexAvail == count - 1) - { - ListBox_SetCurSel(Context->AvailableListHandle, IndexAvail - 1); - } - else - { - ListBox_SetCurSel(Context->AvailableListHandle, IndexAvail); - } - - // insert into 'current' list - ListBox_InsertItemData(Context->CurrentListHandle, IndexTo, button); - - CustomizeInsertStatusBarItem(IndexTo, button); - } - - SendMessage(Context->DialogHandle, WM_COMMAND, MAKEWPARAM(IDC_AVAILABLE, LBN_SELCHANGE), 0); -} - -VOID CustomizeRemoveStatusBarItem( - _In_ PCUSTOMIZE_CONTEXT Context, - _In_ INT IndexFrom - ) -{ - PBUTTON_CONTEXT button; - - if (!(button = (PBUTTON_CONTEXT)ListBox_GetItemData(Context->CurrentListHandle, IndexFrom))) - return; - - ListBox_DeleteString(Context->CurrentListHandle, IndexFrom); - ListBox_SetCurSel(Context->CurrentListHandle, IndexFrom); - - PhRemoveItemList(StatusBarItemList, IndexFrom); - - if (!button->IsVirtual) - { - INT count = ListBox_GetCount(Context->AvailableListHandle); - - if (count == LB_ERR) - count = 1; - - // insert into 'available' list - ListBox_InsertItemData(Context->AvailableListHandle, count - 1, button); - } - - SendMessage(Context->DialogHandle, WM_COMMAND, MAKEWPARAM(IDC_CURRENT, LBN_SELCHANGE), 0); - - StatusBarUpdate(TRUE); -} - -VOID CustomizeMoveStatusBarItem( - _In_ PCUSTOMIZE_CONTEXT Context, - _In_ INT IndexFrom, - _In_ INT IndexTo - ) -{ - INT count; - PBUTTON_CONTEXT button; - - if (IndexFrom == IndexTo) - return; - - if ((count = ListBox_GetCount(Context->CurrentListHandle)) == LB_ERR) - return; - - if (!(button = (PBUTTON_CONTEXT)ListBox_GetItemData(Context->CurrentListHandle, IndexFrom))) - return; - - ListBox_DeleteString(Context->CurrentListHandle, IndexFrom); - ListBox_InsertItemData(Context->CurrentListHandle, IndexTo, button); - ListBox_SetCurSel(Context->CurrentListHandle, IndexTo); - - if (IndexTo <= 0) - { - Button_Enable(Context->MoveUpButtonHandle, FALSE); - } - else - { - Button_Enable(Context->MoveUpButtonHandle, TRUE); - } - - // last item is always separator - if (IndexTo >= (count - 2)) - { - Button_Enable(Context->MoveDownButtonHandle, FALSE); - } - else - { - Button_Enable(Context->MoveDownButtonHandle, TRUE); - } - - PhRemoveItemList(StatusBarItemList, IndexFrom); - - CustomizeInsertStatusBarItem(IndexTo, button); -} - -VOID CustomizeFreeStatusBarItems( - _In_ PCUSTOMIZE_CONTEXT Context - ) -{ - INT index = 0; - INT count = 0; - PBUTTON_CONTEXT button; - - if ((count = ListBox_GetCount(Context->CurrentListHandle)) != LB_ERR) - { - for (index = 0; index < count; index++) - { - if (button = (PBUTTON_CONTEXT)ListBox_GetItemData(Context->CurrentListHandle, index)) - { - PhFree(button); - } - } - } - - if ((count = ListBox_GetCount(Context->AvailableListHandle)) != LB_ERR) - { - for (index = 0; index < count; index++) - { - if (button = (PBUTTON_CONTEXT)ListBox_GetItemData(Context->AvailableListHandle, index)) - { - PhFree(button); - } - } - } -} - -VOID CustomizeLoadStatusBarItems( - _In_ PCUSTOMIZE_CONTEXT Context - ) -{ - ULONG index; - PBUTTON_CONTEXT button; - - CustomizeFreeStatusBarItems(Context); - - ListBox_ResetContent(Context->AvailableListHandle); - ListBox_ResetContent(Context->CurrentListHandle); - - for (index = 0; index < StatusBarItemList->Count; index++) - { - PSTATUSBAR_ITEM item; - - item = StatusBarItemList->Items[index]; - - button = PhAllocate(sizeof(BUTTON_CONTEXT)); - memset(button, 0, sizeof(BUTTON_CONTEXT)); - - button->IdCommand = item->Id; - - ListBox_AddItemData(Context->CurrentListHandle, button); - } - - for (index = 0; index < MAX_STATUSBAR_ITEMS; index++) - { - ULONG buttonId = StatusBarItems[index]; - - if (CustomizeStatusBarItemExists(Context, buttonId)) - continue; - - button = PhAllocate(sizeof(BUTTON_CONTEXT)); - memset(button, 0, sizeof(BUTTON_CONTEXT)); - - button->IdCommand = buttonId; - - ListBox_AddItemData(Context->AvailableListHandle, button); - } - - // Append separator to the last 'current list' position - button = PhAllocate(sizeof(BUTTON_CONTEXT)); - memset(button, 0, sizeof(BUTTON_CONTEXT)); - button->IsVirtual = TRUE; - - index = ListBox_AddItemData(Context->CurrentListHandle, button); - ListBox_SetCurSel(Context->CurrentListHandle, index); - ListBox_SetTopIndex(Context->CurrentListHandle, index); - - // Append separator to the last 'available list' position - button = PhAllocate(sizeof(BUTTON_CONTEXT)); - memset(button, 0, sizeof(BUTTON_CONTEXT)); - button->IsVirtual = TRUE; - - index = ListBox_AddItemData(Context->AvailableListHandle, button); - ListBox_SetCurSel(Context->AvailableListHandle, index); - ListBox_SetTopIndex(Context->AvailableListHandle, 0); // NOTE: This is intentional. - - // Disable buttons - Button_Enable(Context->MoveUpButtonHandle, FALSE); - Button_Enable(Context->MoveDownButtonHandle, FALSE); - Button_Enable(Context->AddButtonHandle, FALSE); - Button_Enable(Context->RemoveButtonHandle, FALSE); -} - -INT_PTR CALLBACK CustomizeStatusBarDialogProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - PCUSTOMIZE_CONTEXT context = NULL; - - if (uMsg == WM_INITDIALOG) - { - context = (PCUSTOMIZE_CONTEXT)PhAllocate(sizeof(CUSTOMIZE_CONTEXT)); - memset(context, 0, sizeof(CUSTOMIZE_CONTEXT)); - - SetProp(hwndDlg, L"Context", (HANDLE)context); - } - else - { - context = (PCUSTOMIZE_CONTEXT)GetProp(hwndDlg, L"Context"); - - if (uMsg == WM_NCDESTROY) - { - RemoveProp(hwndDlg, L"Context"); - PhFree(context); - } - } - - if (context == NULL) - return FALSE; - - switch (uMsg) - { - case WM_INITDIALOG: - { - PhCenterWindow(hwndDlg, PhMainWndHandle); - - context->DialogHandle = hwndDlg; - context->AvailableListHandle = GetDlgItem(hwndDlg, IDC_AVAILABLE); - context->CurrentListHandle = GetDlgItem(hwndDlg, IDC_CURRENT); - context->MoveUpButtonHandle = GetDlgItem(hwndDlg, IDC_MOVEUP); - context->MoveDownButtonHandle = GetDlgItem(hwndDlg, IDC_MOVEDOWN); - context->AddButtonHandle = GetDlgItem(hwndDlg, IDC_ADD); - context->RemoveButtonHandle = GetDlgItem(hwndDlg, IDC_REMOVE); - context->FontHandle = CommonDuplicateFont((HFONT)SendMessage(StatusBarHandle, WM_GETFONT, 0, 0)); - - ListBox_SetItemHeight(context->AvailableListHandle, 0, PhMultiplyDivide(22, PhGlobalDpi, 96)); // BitmapHeight - ListBox_SetItemHeight(context->CurrentListHandle, 0, PhMultiplyDivide(22, PhGlobalDpi, 96)); // BitmapHeight - - CustomizeLoadStatusBarItems(context); - - SendMessage(context->DialogHandle, WM_NEXTDLGCTL, (WPARAM)context->CurrentListHandle, TRUE); - } - return TRUE; - case WM_DESTROY: - { - StatusBarSaveSettings(); - - CustomizeFreeStatusBarItems(context); - - if (context->FontHandle) - { - DeleteObject(context->FontHandle); - } - } - break; - case WM_COMMAND: - { - switch (GET_WM_COMMAND_ID(wParam, lParam)) - { - case IDC_AVAILABLE: - { - switch (GET_WM_COMMAND_CMD(wParam, lParam)) - { - case LBN_SELCHANGE: - { - INT count; - INT index; - - if ((count = ListBox_GetCount(context->AvailableListHandle)) == LB_ERR) - break; - - if ((index = ListBox_GetCurSel(context->AvailableListHandle)) == LB_ERR) - break; - - if (index == (count - 1)) - { - Button_Enable(context->AddButtonHandle, FALSE); - } - else - { - Button_Enable(context->AddButtonHandle, TRUE); - } - } - break; - case LBN_DBLCLK: - { - INT count; - INT index; - INT indexto; - - if ((count = ListBox_GetCount(context->AvailableListHandle)) == LB_ERR) - break; - - if ((index = ListBox_GetCurSel(context->AvailableListHandle)) == LB_ERR) - break; - - if ((indexto = ListBox_GetCurSel(context->CurrentListHandle)) == LB_ERR) - break; - - if (index == (count - 1)) - { - // virtual separator - break; - } - - CustomizeAddStatusBarItem(context, index, indexto); - } - break; - } - } - break; - case IDC_CURRENT: - { - switch (GET_WM_COMMAND_CMD(wParam, lParam)) - { - case LBN_SELCHANGE: - { - INT count; - INT index; - PBUTTON_CONTEXT button; - - if ((count = ListBox_GetCount(context->CurrentListHandle)) == LB_ERR) - break; - - if ((index = ListBox_GetCurSel(context->CurrentListHandle)) == LB_ERR) - break; - - button = (PBUTTON_CONTEXT)ListBox_GetItemData(context->CurrentListHandle, index); - if (button == NULL) - break; - - if (index == 0 && count == 2) - { - // first and last item - Button_Enable(context->MoveUpButtonHandle, FALSE); - Button_Enable(context->MoveDownButtonHandle, FALSE); - } - else if (index == (count - 1)) - { - // last item (virtual separator) - Button_Enable(context->MoveUpButtonHandle, FALSE); - Button_Enable(context->MoveDownButtonHandle, FALSE); - } - else if (index == (count - 2)) - { - // second last item (last non-virtual item) - Button_Enable(context->MoveUpButtonHandle, TRUE); - Button_Enable(context->MoveDownButtonHandle, FALSE); - } - else if (index == 0) - { - // first item - Button_Enable(context->MoveUpButtonHandle, FALSE); - Button_Enable(context->MoveDownButtonHandle, TRUE); - } - else - { - Button_Enable(context->MoveUpButtonHandle, TRUE); - Button_Enable(context->MoveDownButtonHandle, TRUE); - } - - Button_Enable(context->RemoveButtonHandle, !button->IsVirtual); - } - break; - case LBN_DBLCLK: - { - INT count; - INT index; - - if ((count = ListBox_GetCount(context->CurrentListHandle)) == LB_ERR) - break; - - if ((index = ListBox_GetCurSel(context->CurrentListHandle)) == LB_ERR) - break; - - if (index == (count - 1)) - { - // virtual separator - break; - } - - CustomizeRemoveStatusBarItem(context, index); - } - break; - } - } - break; - case IDC_ADD: - { - INT index; - INT indexto; - - if ((index = ListBox_GetCurSel(context->AvailableListHandle)) == LB_ERR) - break; - - if ((indexto = ListBox_GetCurSel(context->CurrentListHandle)) == LB_ERR) - break; - - CustomizeAddStatusBarItem(context, index, indexto); - } - break; - case IDC_REMOVE: - { - INT index; - - if ((index = ListBox_GetCurSel(context->CurrentListHandle)) == LB_ERR) - break; - - CustomizeRemoveStatusBarItem(context, index); - } - break; - case IDC_MOVEUP: - { - INT index; - - if ((index = ListBox_GetCurSel(context->CurrentListHandle)) == LB_ERR) - break; - - CustomizeMoveStatusBarItem(context, index, index - 1); - } - break; - case IDC_MOVEDOWN: - { - INT index; - - if ((index = ListBox_GetCurSel(context->CurrentListHandle)) == LB_ERR) - break; - - CustomizeMoveStatusBarItem(context, index, index + 1); - } - break; - case IDC_RESET: - { - // Reset to default settings. - StatusBarResetSettings(); - - // Save as the new defaults. - StatusBarSaveSettings(); - - StatusBarUpdate(TRUE); - - CustomizeLoadStatusBarItems(context); - } - break; - case IDCANCEL: - { - EndDialog(hwndDlg, FALSE); - } - break; - } - } - break; - case WM_DRAWITEM: - { - LPDRAWITEMSTRUCT drawInfo = (LPDRAWITEMSTRUCT)lParam; - - if (drawInfo->CtlID == IDC_AVAILABLE || drawInfo->CtlID == IDC_CURRENT) - { - HDC bufferDc; - HBITMAP bufferBitmap; - HBITMAP oldBufferBitmap; - PBUTTON_CONTEXT button; - RECT bufferRect = - { - 0, 0, - drawInfo->rcItem.right - drawInfo->rcItem.left, - drawInfo->rcItem.bottom - drawInfo->rcItem.top - }; - BOOLEAN isSelected = (drawInfo->itemState & ODS_SELECTED) == ODS_SELECTED; - BOOLEAN isFocused = (drawInfo->itemState & ODS_FOCUS) == ODS_FOCUS; - - if (drawInfo->itemID == LB_ERR) - break; - - if (!(button = (PBUTTON_CONTEXT)ListBox_GetItemData(drawInfo->hwndItem, drawInfo->itemID))) - break; - - bufferDc = CreateCompatibleDC(drawInfo->hDC); - bufferBitmap = CreateCompatibleBitmap(drawInfo->hDC, bufferRect.right, bufferRect.bottom); - - oldBufferBitmap = SelectBitmap(bufferDc, bufferBitmap); - SelectFont(bufferDc, context->FontHandle); - SetBkMode(bufferDc, TRANSPARENT); - - if (isSelected) - { - FillRect(bufferDc, &bufferRect, GetSysColorBrush(isFocused ? COLOR_HIGHLIGHT : COLOR_WINDOW)); - SetTextColor(bufferDc, GetSysColor(isFocused ? COLOR_HIGHLIGHTTEXT : COLOR_WINDOWTEXT)); - //FrameRect(bufferDc, &bufferRect, isFocused ? GetStockBrush(BLACK_BRUSH) : GetSysColorBrush(COLOR_HIGHLIGHT)); - } - else - { - FillRect(bufferDc, &bufferRect, GetSysColorBrush(isFocused ? COLOR_HIGHLIGHT : COLOR_WINDOW)); - SetTextColor(bufferDc, GetSysColor(isFocused ? COLOR_HIGHLIGHTTEXT : COLOR_WINDOWTEXT)); - //FrameRect(bufferDc, &bufferRect, isFocused ? GetStockBrush(BLACK_BRUSH) : GetSysColorBrush(COLOR_HIGHLIGHTTEXT)); - } - - if (!button->IsVirtual) - { - bufferRect.left += 5; - DrawText( - bufferDc, - StatusBarGetText(button->IdCommand), - -1, - &bufferRect, - DT_LEFT | DT_VCENTER | DT_SINGLELINE - ); - } - - BitBlt( - drawInfo->hDC, - drawInfo->rcItem.left, - drawInfo->rcItem.top, - drawInfo->rcItem.right, - drawInfo->rcItem.bottom, - bufferDc, - 0, - 0, - SRCCOPY - ); - - SelectBitmap(bufferDc, oldBufferBitmap); - DeleteBitmap(bufferBitmap); - DeleteDC(bufferDc); - - return TRUE; - } - } - break; - } - - return FALSE; -} - -VOID StatusBarShowCustomizeDialog( - VOID - ) -{ - DialogBox( - PluginInstance->DllBase, - MAKEINTRESOURCE(IDD_CUSTOMIZE_SB), - PhMainWndHandle, - CustomizeStatusBarDialogProc - ); +/* + * Process Hacker ToolStatus - + * Statusbar Customize Dialog + * + * Copyright (C) 2015-2016 dmex + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include "toolstatus.h" +#include "commonutil.h" + +BOOLEAN CustomizeStatusBarItemExists( + _In_ PCUSTOMIZE_CONTEXT Context, + _In_ INT IdCommand + ) +{ + INT index = 0; + INT count = 0; + PBUTTON_CONTEXT button; + + if ((count = ListBox_GetCount(Context->CurrentListHandle)) == LB_ERR) + return FALSE; + + for (index = 0; index < count; index++) + { + if (!(button = (PBUTTON_CONTEXT)ListBox_GetItemData(Context->CurrentListHandle, index))) + continue; + + if (button->IdCommand == IdCommand) + return TRUE; + } + + return FALSE; +} + +VOID CustomizeInsertStatusBarItem( + _In_ INT Index, + _In_ PBUTTON_CONTEXT Button + ) +{ + PSTATUSBAR_ITEM item; + + item = PhAllocate(sizeof(STATUSBAR_ITEM)); + memset(item, 0, sizeof(STATUSBAR_ITEM)); + + item->Id = Button->IdCommand; + + PhInsertItemList(StatusBarItemList, Index, item); + + StatusBarUpdate(TRUE); +} + +VOID CustomizeAddStatusBarItem( + _In_ PCUSTOMIZE_CONTEXT Context, + _In_ INT IndexAvail, + _In_ INT IndexTo + ) +{ + INT count; + PBUTTON_CONTEXT button; + + if ((count = ListBox_GetCount(Context->AvailableListHandle)) == LB_ERR) + return; + + if (!(button = (PBUTTON_CONTEXT)ListBox_GetItemData(Context->AvailableListHandle, IndexAvail))) + return; + + if (!button->IsVirtual) + { + // remove from 'available' list + ListBox_DeleteString(Context->AvailableListHandle, IndexAvail); + + if (IndexAvail == count - 1) + { + ListBox_SetCurSel(Context->AvailableListHandle, IndexAvail - 1); + } + else + { + ListBox_SetCurSel(Context->AvailableListHandle, IndexAvail); + } + + // insert into 'current' list + ListBox_InsertItemData(Context->CurrentListHandle, IndexTo, button); + + CustomizeInsertStatusBarItem(IndexTo, button); + } + + SendMessage(Context->DialogHandle, WM_COMMAND, MAKEWPARAM(IDC_AVAILABLE, LBN_SELCHANGE), 0); +} + +VOID CustomizeRemoveStatusBarItem( + _In_ PCUSTOMIZE_CONTEXT Context, + _In_ INT IndexFrom + ) +{ + PBUTTON_CONTEXT button; + + if (!(button = (PBUTTON_CONTEXT)ListBox_GetItemData(Context->CurrentListHandle, IndexFrom))) + return; + + ListBox_DeleteString(Context->CurrentListHandle, IndexFrom); + ListBox_SetCurSel(Context->CurrentListHandle, IndexFrom); + + PhRemoveItemList(StatusBarItemList, IndexFrom); + + if (!button->IsVirtual) + { + INT count = ListBox_GetCount(Context->AvailableListHandle); + + if (count == LB_ERR) + count = 1; + + // insert into 'available' list + ListBox_InsertItemData(Context->AvailableListHandle, count - 1, button); + } + + SendMessage(Context->DialogHandle, WM_COMMAND, MAKEWPARAM(IDC_CURRENT, LBN_SELCHANGE), 0); + + StatusBarUpdate(TRUE); +} + +VOID CustomizeMoveStatusBarItem( + _In_ PCUSTOMIZE_CONTEXT Context, + _In_ INT IndexFrom, + _In_ INT IndexTo + ) +{ + INT count; + PBUTTON_CONTEXT button; + + if (IndexFrom == IndexTo) + return; + + if ((count = ListBox_GetCount(Context->CurrentListHandle)) == LB_ERR) + return; + + if (!(button = (PBUTTON_CONTEXT)ListBox_GetItemData(Context->CurrentListHandle, IndexFrom))) + return; + + ListBox_DeleteString(Context->CurrentListHandle, IndexFrom); + ListBox_InsertItemData(Context->CurrentListHandle, IndexTo, button); + ListBox_SetCurSel(Context->CurrentListHandle, IndexTo); + + if (IndexTo <= 0) + { + Button_Enable(Context->MoveUpButtonHandle, FALSE); + } + else + { + Button_Enable(Context->MoveUpButtonHandle, TRUE); + } + + // last item is always separator + if (IndexTo >= (count - 2)) + { + Button_Enable(Context->MoveDownButtonHandle, FALSE); + } + else + { + Button_Enable(Context->MoveDownButtonHandle, TRUE); + } + + PhRemoveItemList(StatusBarItemList, IndexFrom); + + CustomizeInsertStatusBarItem(IndexTo, button); +} + +VOID CustomizeFreeStatusBarItems( + _In_ PCUSTOMIZE_CONTEXT Context + ) +{ + INT index = 0; + INT count = 0; + PBUTTON_CONTEXT button; + + if ((count = ListBox_GetCount(Context->CurrentListHandle)) != LB_ERR) + { + for (index = 0; index < count; index++) + { + if (button = (PBUTTON_CONTEXT)ListBox_GetItemData(Context->CurrentListHandle, index)) + { + PhFree(button); + } + } + } + + if ((count = ListBox_GetCount(Context->AvailableListHandle)) != LB_ERR) + { + for (index = 0; index < count; index++) + { + if (button = (PBUTTON_CONTEXT)ListBox_GetItemData(Context->AvailableListHandle, index)) + { + PhFree(button); + } + } + } +} + +VOID CustomizeLoadStatusBarItems( + _In_ PCUSTOMIZE_CONTEXT Context + ) +{ + ULONG index; + PBUTTON_CONTEXT button; + + CustomizeFreeStatusBarItems(Context); + + ListBox_ResetContent(Context->AvailableListHandle); + ListBox_ResetContent(Context->CurrentListHandle); + + for (index = 0; index < StatusBarItemList->Count; index++) + { + PSTATUSBAR_ITEM item; + + item = StatusBarItemList->Items[index]; + + button = PhAllocate(sizeof(BUTTON_CONTEXT)); + memset(button, 0, sizeof(BUTTON_CONTEXT)); + + button->IdCommand = item->Id; + + ListBox_AddItemData(Context->CurrentListHandle, button); + } + + for (index = 0; index < MAX_STATUSBAR_ITEMS; index++) + { + ULONG buttonId = StatusBarItems[index]; + + if (CustomizeStatusBarItemExists(Context, buttonId)) + continue; + + button = PhAllocate(sizeof(BUTTON_CONTEXT)); + memset(button, 0, sizeof(BUTTON_CONTEXT)); + + button->IdCommand = buttonId; + + ListBox_AddItemData(Context->AvailableListHandle, button); + } + + // Append separator to the last 'current list' position + button = PhAllocate(sizeof(BUTTON_CONTEXT)); + memset(button, 0, sizeof(BUTTON_CONTEXT)); + button->IsVirtual = TRUE; + + index = ListBox_AddItemData(Context->CurrentListHandle, button); + ListBox_SetCurSel(Context->CurrentListHandle, index); + ListBox_SetTopIndex(Context->CurrentListHandle, index); + + // Append separator to the last 'available list' position + button = PhAllocate(sizeof(BUTTON_CONTEXT)); + memset(button, 0, sizeof(BUTTON_CONTEXT)); + button->IsVirtual = TRUE; + + index = ListBox_AddItemData(Context->AvailableListHandle, button); + ListBox_SetCurSel(Context->AvailableListHandle, index); + ListBox_SetTopIndex(Context->AvailableListHandle, 0); // NOTE: This is intentional. + + // Disable buttons + Button_Enable(Context->MoveUpButtonHandle, FALSE); + Button_Enable(Context->MoveDownButtonHandle, FALSE); + Button_Enable(Context->AddButtonHandle, FALSE); + Button_Enable(Context->RemoveButtonHandle, FALSE); +} + +INT_PTR CALLBACK CustomizeStatusBarDialogProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + PCUSTOMIZE_CONTEXT context = NULL; + + if (uMsg == WM_INITDIALOG) + { + context = (PCUSTOMIZE_CONTEXT)PhAllocate(sizeof(CUSTOMIZE_CONTEXT)); + memset(context, 0, sizeof(CUSTOMIZE_CONTEXT)); + + SetProp(hwndDlg, L"Context", (HANDLE)context); + } + else + { + context = (PCUSTOMIZE_CONTEXT)GetProp(hwndDlg, L"Context"); + + if (uMsg == WM_NCDESTROY) + { + RemoveProp(hwndDlg, L"Context"); + PhFree(context); + } + } + + if (context == NULL) + return FALSE; + + switch (uMsg) + { + case WM_INITDIALOG: + { + PhCenterWindow(hwndDlg, PhMainWndHandle); + + context->DialogHandle = hwndDlg; + context->AvailableListHandle = GetDlgItem(hwndDlg, IDC_AVAILABLE); + context->CurrentListHandle = GetDlgItem(hwndDlg, IDC_CURRENT); + context->MoveUpButtonHandle = GetDlgItem(hwndDlg, IDC_MOVEUP); + context->MoveDownButtonHandle = GetDlgItem(hwndDlg, IDC_MOVEDOWN); + context->AddButtonHandle = GetDlgItem(hwndDlg, IDC_ADD); + context->RemoveButtonHandle = GetDlgItem(hwndDlg, IDC_REMOVE); + context->FontHandle = CommonDuplicateFont((HFONT)SendMessage(StatusBarHandle, WM_GETFONT, 0, 0)); + + ListBox_SetItemHeight(context->AvailableListHandle, 0, PhMultiplyDivide(22, PhGlobalDpi, 96)); // BitmapHeight + ListBox_SetItemHeight(context->CurrentListHandle, 0, PhMultiplyDivide(22, PhGlobalDpi, 96)); // BitmapHeight + + CustomizeLoadStatusBarItems(context); + + SendMessage(context->DialogHandle, WM_NEXTDLGCTL, (WPARAM)context->CurrentListHandle, TRUE); + } + return TRUE; + case WM_DESTROY: + { + StatusBarSaveSettings(); + + CustomizeFreeStatusBarItems(context); + + if (context->FontHandle) + { + DeleteObject(context->FontHandle); + } + } + break; + case WM_COMMAND: + { + switch (GET_WM_COMMAND_ID(wParam, lParam)) + { + case IDC_AVAILABLE: + { + switch (GET_WM_COMMAND_CMD(wParam, lParam)) + { + case LBN_SELCHANGE: + { + INT count; + INT index; + + if ((count = ListBox_GetCount(context->AvailableListHandle)) == LB_ERR) + break; + + if ((index = ListBox_GetCurSel(context->AvailableListHandle)) == LB_ERR) + break; + + if (index == (count - 1)) + { + Button_Enable(context->AddButtonHandle, FALSE); + } + else + { + Button_Enable(context->AddButtonHandle, TRUE); + } + } + break; + case LBN_DBLCLK: + { + INT count; + INT index; + INT indexto; + + if ((count = ListBox_GetCount(context->AvailableListHandle)) == LB_ERR) + break; + + if ((index = ListBox_GetCurSel(context->AvailableListHandle)) == LB_ERR) + break; + + if ((indexto = ListBox_GetCurSel(context->CurrentListHandle)) == LB_ERR) + break; + + if (index == (count - 1)) + { + // virtual separator + break; + } + + CustomizeAddStatusBarItem(context, index, indexto); + } + break; + } + } + break; + case IDC_CURRENT: + { + switch (GET_WM_COMMAND_CMD(wParam, lParam)) + { + case LBN_SELCHANGE: + { + INT count; + INT index; + PBUTTON_CONTEXT button; + + if ((count = ListBox_GetCount(context->CurrentListHandle)) == LB_ERR) + break; + + if ((index = ListBox_GetCurSel(context->CurrentListHandle)) == LB_ERR) + break; + + button = (PBUTTON_CONTEXT)ListBox_GetItemData(context->CurrentListHandle, index); + if (button == NULL) + break; + + if (index == 0 && count == 2) + { + // first and last item + Button_Enable(context->MoveUpButtonHandle, FALSE); + Button_Enable(context->MoveDownButtonHandle, FALSE); + } + else if (index == (count - 1)) + { + // last item (virtual separator) + Button_Enable(context->MoveUpButtonHandle, FALSE); + Button_Enable(context->MoveDownButtonHandle, FALSE); + } + else if (index == (count - 2)) + { + // second last item (last non-virtual item) + Button_Enable(context->MoveUpButtonHandle, TRUE); + Button_Enable(context->MoveDownButtonHandle, FALSE); + } + else if (index == 0) + { + // first item + Button_Enable(context->MoveUpButtonHandle, FALSE); + Button_Enable(context->MoveDownButtonHandle, TRUE); + } + else + { + Button_Enable(context->MoveUpButtonHandle, TRUE); + Button_Enable(context->MoveDownButtonHandle, TRUE); + } + + Button_Enable(context->RemoveButtonHandle, !button->IsVirtual); + } + break; + case LBN_DBLCLK: + { + INT count; + INT index; + + if ((count = ListBox_GetCount(context->CurrentListHandle)) == LB_ERR) + break; + + if ((index = ListBox_GetCurSel(context->CurrentListHandle)) == LB_ERR) + break; + + if (index == (count - 1)) + { + // virtual separator + break; + } + + CustomizeRemoveStatusBarItem(context, index); + } + break; + } + } + break; + case IDC_ADD: + { + INT index; + INT indexto; + + if ((index = ListBox_GetCurSel(context->AvailableListHandle)) == LB_ERR) + break; + + if ((indexto = ListBox_GetCurSel(context->CurrentListHandle)) == LB_ERR) + break; + + CustomizeAddStatusBarItem(context, index, indexto); + } + break; + case IDC_REMOVE: + { + INT index; + + if ((index = ListBox_GetCurSel(context->CurrentListHandle)) == LB_ERR) + break; + + CustomizeRemoveStatusBarItem(context, index); + } + break; + case IDC_MOVEUP: + { + INT index; + + if ((index = ListBox_GetCurSel(context->CurrentListHandle)) == LB_ERR) + break; + + CustomizeMoveStatusBarItem(context, index, index - 1); + } + break; + case IDC_MOVEDOWN: + { + INT index; + + if ((index = ListBox_GetCurSel(context->CurrentListHandle)) == LB_ERR) + break; + + CustomizeMoveStatusBarItem(context, index, index + 1); + } + break; + case IDC_RESET: + { + // Reset to default settings. + StatusBarResetSettings(); + + // Save as the new defaults. + StatusBarSaveSettings(); + + StatusBarUpdate(TRUE); + + CustomizeLoadStatusBarItems(context); + } + break; + case IDCANCEL: + { + EndDialog(hwndDlg, FALSE); + } + break; + } + } + break; + case WM_DRAWITEM: + { + LPDRAWITEMSTRUCT drawInfo = (LPDRAWITEMSTRUCT)lParam; + + if (drawInfo->CtlID == IDC_AVAILABLE || drawInfo->CtlID == IDC_CURRENT) + { + HDC bufferDc; + HBITMAP bufferBitmap; + HBITMAP oldBufferBitmap; + PBUTTON_CONTEXT button; + RECT bufferRect = + { + 0, 0, + drawInfo->rcItem.right - drawInfo->rcItem.left, + drawInfo->rcItem.bottom - drawInfo->rcItem.top + }; + BOOLEAN isSelected = (drawInfo->itemState & ODS_SELECTED) == ODS_SELECTED; + BOOLEAN isFocused = (drawInfo->itemState & ODS_FOCUS) == ODS_FOCUS; + + if (drawInfo->itemID == LB_ERR) + break; + + if (!(button = (PBUTTON_CONTEXT)ListBox_GetItemData(drawInfo->hwndItem, drawInfo->itemID))) + break; + + bufferDc = CreateCompatibleDC(drawInfo->hDC); + bufferBitmap = CreateCompatibleBitmap(drawInfo->hDC, bufferRect.right, bufferRect.bottom); + + oldBufferBitmap = SelectBitmap(bufferDc, bufferBitmap); + SelectFont(bufferDc, context->FontHandle); + SetBkMode(bufferDc, TRANSPARENT); + + if (isSelected) + { + FillRect(bufferDc, &bufferRect, GetSysColorBrush(isFocused ? COLOR_HIGHLIGHT : COLOR_WINDOW)); + SetTextColor(bufferDc, GetSysColor(isFocused ? COLOR_HIGHLIGHTTEXT : COLOR_WINDOWTEXT)); + //FrameRect(bufferDc, &bufferRect, isFocused ? GetStockBrush(BLACK_BRUSH) : GetSysColorBrush(COLOR_HIGHLIGHT)); + } + else + { + FillRect(bufferDc, &bufferRect, GetSysColorBrush(isFocused ? COLOR_HIGHLIGHT : COLOR_WINDOW)); + SetTextColor(bufferDc, GetSysColor(isFocused ? COLOR_HIGHLIGHTTEXT : COLOR_WINDOWTEXT)); + //FrameRect(bufferDc, &bufferRect, isFocused ? GetStockBrush(BLACK_BRUSH) : GetSysColorBrush(COLOR_HIGHLIGHTTEXT)); + } + + if (!button->IsVirtual) + { + bufferRect.left += 5; + DrawText( + bufferDc, + StatusBarGetText(button->IdCommand), + -1, + &bufferRect, + DT_LEFT | DT_VCENTER | DT_SINGLELINE + ); + } + + BitBlt( + drawInfo->hDC, + drawInfo->rcItem.left, + drawInfo->rcItem.top, + drawInfo->rcItem.right, + drawInfo->rcItem.bottom, + bufferDc, + 0, + 0, + SRCCOPY + ); + + SelectBitmap(bufferDc, oldBufferBitmap); + DeleteBitmap(bufferBitmap); + DeleteDC(bufferDc); + + return TRUE; + } + } + break; + } + + return FALSE; +} + +VOID StatusBarShowCustomizeDialog( + VOID + ) +{ + DialogBox( + PluginInstance->DllBase, + MAKEINTRESOURCE(IDD_CUSTOMIZE_SB), + PhMainWndHandle, + CustomizeStatusBarDialogProc + ); } \ No newline at end of file diff --git a/plugins/ToolStatus/customizetb.c b/plugins/ToolStatus/customizetb.c index 73f7be904bd5..f1b906bd17c5 100644 --- a/plugins/ToolStatus/customizetb.c +++ b/plugins/ToolStatus/customizetb.c @@ -1,943 +1,943 @@ -/* - * Process Hacker ToolStatus - - * Toolbar Customize Dialog - * - * Copyright (C) 2015-2016 dmex - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include "toolstatus.h" -#include "commonutil.h" - -static PWSTR CustomizeTextOptionsStrings[] = -{ - L"No text labels", - L"Selective text", - L"Show text labels" -}; - -static PWSTR CustomizeSearchDisplayStrings[] = -{ - L"Always show", - L"Hide when inactive (Ctrl+K)", - // L"Auto-hide" -}; - -static PWSTR CustomizeThemeOptionsStrings[] = -{ - L"None", - L"Black", - L"Blue" -}; - -BOOLEAN CustomizeToolbarItemExists( - _In_ PCUSTOMIZE_CONTEXT Context, - _In_ INT IdCommand - ) -{ - INT index = 0; - INT count = 0; - PBUTTON_CONTEXT button; - - if ((count = ListBox_GetCount(Context->CurrentListHandle)) == LB_ERR) - return FALSE; - - for (index = 0; index < count; index++) - { - if (!(button = (PBUTTON_CONTEXT)ListBox_GetItemData(Context->CurrentListHandle, index))) - continue; - - if (button->IdCommand == IdCommand) - return TRUE; - } - - return FALSE; -} - -VOID CustomizeInsertToolbarButton( - _In_ INT Index, - _In_ PBUTTON_CONTEXT ItemContext - ) -{ - TBBUTTON button; - - memset(&button, 0, sizeof(TBBUTTON)); - - button.idCommand = ItemContext->IdCommand; - button.iBitmap = I_IMAGECALLBACK; - button.fsState = TBSTATE_ENABLED; - button.iString = (INT_PTR)ToolbarGetText(ItemContext->IdCommand); - - if (ItemContext->IsSeparator) - { - button.fsStyle = BTNS_SEP; - } - else - { - switch (DisplayStyle) - { - case TOOLBAR_DISPLAY_STYLE_IMAGEONLY: - button.fsStyle = BTNS_BUTTON | BTNS_AUTOSIZE; - break; - case TOOLBAR_DISPLAY_STYLE_SELECTIVETEXT: - { - switch (button.idCommand) - { - case PHAPP_ID_VIEW_REFRESH: - case PHAPP_ID_HACKER_OPTIONS: - case PHAPP_ID_HACKER_FINDHANDLESORDLLS: - case PHAPP_ID_VIEW_SYSTEMINFORMATION: - button.fsStyle = BTNS_BUTTON | BTNS_AUTOSIZE | BTNS_SHOWTEXT; - break; - default: - button.fsStyle = BTNS_BUTTON | BTNS_AUTOSIZE; - break; - } - } - break; - case TOOLBAR_DISPLAY_STYLE_ALLTEXT: - button.fsStyle = BTNS_BUTTON | BTNS_AUTOSIZE | BTNS_SHOWTEXT; - break; - } - } - - SendMessage(ToolBarHandle, TB_INSERTBUTTON, Index, (LPARAM)&button); -} - -VOID CustomizeAddToolbarItem( - _In_ PCUSTOMIZE_CONTEXT Context, - _In_ INT IndexAvail, - _In_ INT IndexTo - ) -{ - INT count; - PBUTTON_CONTEXT button; - - if ((count = ListBox_GetCount(Context->AvailableListHandle)) == LB_ERR) - return; - - if (!(button = (PBUTTON_CONTEXT)ListBox_GetItemData(Context->AvailableListHandle, IndexAvail))) - return; - - if (IndexAvail != 0) // index 0 is separator - { - // remove from 'available' list - ListBox_DeleteString(Context->AvailableListHandle, IndexAvail); - - if (IndexAvail == count - 1) - { - ListBox_SetCurSel(Context->AvailableListHandle, IndexAvail - 1); - } - else - { - ListBox_SetCurSel(Context->AvailableListHandle, IndexAvail); - } - } - else - { - button = PhAllocate(sizeof(BUTTON_CONTEXT)); - memset(button, 0, sizeof(BUTTON_CONTEXT)); - - button->IsSeparator = TRUE; - button->IsRemovable = TRUE; - } - - // insert into 'current' list - ListBox_InsertItemData(Context->CurrentListHandle, IndexTo, button); - - CustomizeInsertToolbarButton(IndexTo, button); -} - -VOID CustomizeRemoveToolbarItem( - _In_ PCUSTOMIZE_CONTEXT Context, - _In_ INT IndexFrom - ) -{ - PBUTTON_CONTEXT button; - - if (!(button = (PBUTTON_CONTEXT)ListBox_GetItemData(Context->CurrentListHandle, IndexFrom))) - return; - - ListBox_DeleteString(Context->CurrentListHandle, IndexFrom); - ListBox_SetCurSel(Context->CurrentListHandle, IndexFrom); - - SendMessage(ToolBarHandle, TB_DELETEBUTTON, IndexFrom, 0); - - if (button->IsSeparator) - { - PhFree(button); - } - else - { - // insert into 'available' list - ListBox_AddItemData(Context->AvailableListHandle, button); - } - - SendMessage(Context->DialogHandle, WM_COMMAND, MAKEWPARAM(IDC_CURRENT, LBN_SELCHANGE), 0); -} - -VOID CustomizeMoveToolbarItem( - _In_ PCUSTOMIZE_CONTEXT Context, - _In_ INT IndexFrom, - _In_ INT IndexTo - ) -{ - INT count; - PBUTTON_CONTEXT button; - - if (IndexFrom == IndexTo) - return; - - if ((count = ListBox_GetCount(Context->CurrentListHandle)) == LB_ERR) - return; - - if (!(button = (PBUTTON_CONTEXT)ListBox_GetItemData(Context->CurrentListHandle, IndexFrom))) - return; - - ListBox_DeleteString(Context->CurrentListHandle, IndexFrom); - ListBox_InsertItemData(Context->CurrentListHandle, IndexTo, button); - ListBox_SetCurSel(Context->CurrentListHandle, IndexTo); - - if (IndexTo <= 0) - { - Button_Enable(Context->MoveUpButtonHandle, FALSE); - } - else - { - Button_Enable(Context->MoveUpButtonHandle, TRUE); - } - - // last item is always separator - if (IndexTo >= (count - 2)) - { - Button_Enable(Context->MoveDownButtonHandle, FALSE); - } - else - { - Button_Enable(Context->MoveDownButtonHandle, TRUE); - } - - SendMessage(ToolBarHandle, TB_DELETEBUTTON, IndexFrom, 0); - - CustomizeInsertToolbarButton(IndexTo, button); -} - -VOID CustomizeFreeToolbarItems( - _In_ PCUSTOMIZE_CONTEXT Context - ) -{ - INT i = 0; - INT count = 0; - PBUTTON_CONTEXT button; - - if ((count = ListBox_GetCount(Context->CurrentListHandle)) != LB_ERR) - { - for (i = 0; i < count; i++) - { - if (button = (PBUTTON_CONTEXT)ListBox_GetItemData(Context->CurrentListHandle, i)) - { - if (button->IconHandle) - { - DeleteObject(button->IconHandle); - } - - PhFree(button); - } - } - } - - if ((count = ListBox_GetCount(Context->AvailableListHandle)) != LB_ERR) - { - for (i = 0; i < count; i++) - { - if (button = (PBUTTON_CONTEXT)ListBox_GetItemData(Context->AvailableListHandle, i)) - { - if (button->IconHandle) - { - DeleteObject(button->IconHandle); - } - - PhFree(button); - } - } - } -} - -VOID CustomizeLoadToolbarItems( - _In_ PCUSTOMIZE_CONTEXT Context - ) -{ - INT index = 0; - INT count = 0; - PBUTTON_CONTEXT context; - - CustomizeFreeToolbarItems(Context); - - ListBox_ResetContent(Context->AvailableListHandle); - ListBox_ResetContent(Context->CurrentListHandle); - - count = (INT)SendMessage(ToolBarHandle, TB_BUTTONCOUNT, 0, 0); - - for (index = 0; index < count; index++) - { - TBBUTTON button; - - memset(&button, 0, sizeof(TBBUTTON)); - - if (SendMessage(ToolBarHandle, TB_GETBUTTON, index, (LPARAM)&button)) - { - context = PhAllocate(sizeof(BUTTON_CONTEXT)); - memset(context, 0, sizeof(BUTTON_CONTEXT)); - - context->IsVirtual = FALSE; - context->IsRemovable = TRUE; - context->IdCommand = button.idCommand; - - if (button.fsStyle & BTNS_SEP) - { - context->IsSeparator = TRUE; - } - else - { - context->IconHandle = CustomizeGetToolbarIcon(Context, button.idCommand); - } - - ListBox_AddItemData(Context->CurrentListHandle, context); - } - } - - for (index = 0; index < MAX_TOOLBAR_ITEMS; index++) - { - TBBUTTON button = ToolbarButtons[index]; - - if (button.idCommand == 0) - continue; - - if (CustomizeToolbarItemExists(Context, button.idCommand)) - continue; - - context = PhAllocate(sizeof(BUTTON_CONTEXT)); - memset(context, 0, sizeof(BUTTON_CONTEXT)); - - context->IsRemovable = TRUE; - context->IdCommand = button.idCommand; - context->IconHandle = CustomizeGetToolbarIcon(Context, button.idCommand); - - ListBox_AddItemData(Context->AvailableListHandle, context); - } - - // Append separator to the last 'current list' position - context = PhAllocate(sizeof(BUTTON_CONTEXT)); - memset(context, 0, sizeof(BUTTON_CONTEXT)); - context->IsSeparator = TRUE; - context->IsVirtual = TRUE; - context->IsRemovable = FALSE; - - index = ListBox_AddItemData(Context->CurrentListHandle, context); - ListBox_SetCurSel(Context->CurrentListHandle, index); - ListBox_SetTopIndex(Context->CurrentListHandle, index); - - // Insert separator into first 'available list' position - context = PhAllocate(sizeof(BUTTON_CONTEXT)); - memset(context, 0, sizeof(BUTTON_CONTEXT)); - context->IsSeparator = TRUE; - context->IsVirtual = FALSE; - context->IsRemovable = FALSE; - - index = ListBox_InsertItemData(Context->AvailableListHandle, 0, context); - ListBox_SetCurSel(Context->AvailableListHandle, index); - ListBox_SetTopIndex(Context->AvailableListHandle, index); - - // Disable buttons - Button_Enable(Context->MoveUpButtonHandle, FALSE); - Button_Enable(Context->MoveDownButtonHandle, FALSE); - Button_Enable(Context->RemoveButtonHandle, FALSE); -} - -VOID CustomizeLoadToolbarSettings( - _In_ PCUSTOMIZE_CONTEXT Context - ) -{ - HWND toolbarCombo = GetDlgItem(Context->DialogHandle, IDC_TEXTOPTIONS); - HWND searchboxCombo = GetDlgItem(Context->DialogHandle, IDC_SEARCHOPTIONS); - - PhAddComboBoxStrings( - toolbarCombo, - CustomizeTextOptionsStrings, - ARRAYSIZE(CustomizeTextOptionsStrings) - ); - PhAddComboBoxStrings( - searchboxCombo, - CustomizeSearchDisplayStrings, - ARRAYSIZE(CustomizeSearchDisplayStrings) - ); - ComboBox_SetCurSel(toolbarCombo, PhGetIntegerSetting(SETTING_NAME_TOOLBARDISPLAYSTYLE)); - ComboBox_SetCurSel(searchboxCombo, PhGetIntegerSetting(SETTING_NAME_SEARCHBOXDISPLAYMODE)); - - Button_SetCheck(GetDlgItem(Context->DialogHandle, IDC_ENABLE_MODERN), - ToolStatusConfig.ModernIcons ? BST_CHECKED : BST_UNCHECKED); - Button_SetCheck(GetDlgItem(Context->DialogHandle, IDC_ENABLE_AUTOHIDE_MENU), - ToolStatusConfig.AutoHideMenu ? BST_CHECKED : BST_UNCHECKED); - - if (!ToolStatusConfig.SearchBoxEnabled) - { - ComboBox_Enable(searchboxCombo, FALSE); - } -} - -VOID CustomizeResetImages( - _In_ PCUSTOMIZE_CONTEXT Context - ) -{ - INT index = 0; - INT count = 0; - PBUTTON_CONTEXT button; - - if ((count = ListBox_GetCount(Context->CurrentListHandle)) != LB_ERR) - { - for (index = 0; index < count; index++) - { - if (button = (PBUTTON_CONTEXT)ListBox_GetItemData(Context->CurrentListHandle, index)) - { - button->IconHandle = CustomizeGetToolbarIcon(Context, button->IdCommand); - } - } - } - - if ((count = ListBox_GetCount(Context->AvailableListHandle)) != LB_ERR) - { - for (index = 0; index < count; index++) - { - if (button = (PBUTTON_CONTEXT)ListBox_GetItemData(Context->AvailableListHandle, index)) - { - button->IconHandle = CustomizeGetToolbarIcon(Context, button->IdCommand); - } - } - } - - InvalidateRect(Context->AvailableListHandle, NULL, TRUE); - InvalidateRect(Context->CurrentListHandle, NULL, TRUE); -} - -HICON CustomizeGetToolbarIcon( - _In_ PCUSTOMIZE_CONTEXT Context, - _In_ INT CommandID - ) -{ - HBITMAP bitmapHandle; - HICON iconHandle; - - bitmapHandle = ToolbarGetImage(CommandID); - iconHandle = CommonBitmapToIcon(bitmapHandle, Context->CXWidth, Context->CXWidth); - - DeleteObject(bitmapHandle); - return iconHandle; -} - -VOID CustomizeResetToolbarImages( - VOID - ) -{ - // Reset the image cache with the new icons. - // TODO: Move function to Toolbar.c - for (INT index = 0; index < ARRAYSIZE(ToolbarButtons); index++) - { - if (ToolbarButtons[index].iBitmap != I_IMAGECALLBACK) - { - HBITMAP bitmap; - - if (bitmap = ToolbarGetImage(ToolbarButtons[index].idCommand)) - { - ImageList_Replace( - ToolBarImageList, - ToolbarButtons[index].iBitmap, - bitmap, - NULL - ); - - DeleteObject(bitmap); - } - } - } -} - -INT_PTR CALLBACK CustomizeToolbarDialogProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - PCUSTOMIZE_CONTEXT context = NULL; - - if (uMsg == WM_INITDIALOG) - { - context = (PCUSTOMIZE_CONTEXT)PhAllocate(sizeof(CUSTOMIZE_CONTEXT)); - memset(context, 0, sizeof(CUSTOMIZE_CONTEXT)); - - SetProp(hwndDlg, L"Context", (HANDLE)context); - } - else - { - context = (PCUSTOMIZE_CONTEXT)GetProp(hwndDlg, L"Context"); - - if (uMsg == WM_NCDESTROY) - { - RemoveProp(hwndDlg, L"Context"); - PhFree(context); - } - } - - if (context == NULL) - return FALSE; - - switch (uMsg) - { - case WM_INITDIALOG: - { - PhCenterWindow(hwndDlg, PhMainWndHandle); - - context->DialogHandle = hwndDlg; - context->AvailableListHandle = GetDlgItem(hwndDlg, IDC_AVAILABLE); - context->CurrentListHandle = GetDlgItem(hwndDlg, IDC_CURRENT); - context->MoveUpButtonHandle = GetDlgItem(hwndDlg, IDC_MOVEUP); - context->MoveDownButtonHandle = GetDlgItem(hwndDlg, IDC_MOVEDOWN); - context->AddButtonHandle = GetDlgItem(hwndDlg, IDC_ADD); - context->RemoveButtonHandle = GetDlgItem(hwndDlg, IDC_REMOVE); - - context->CXWidth = 16; - context->BrushNormal = GetSysColorBrush(COLOR_WINDOW); - context->BrushHot = CreateSolidBrush(RGB(145, 201, 247)); - context->BrushPushed = CreateSolidBrush(RGB(153, 209, 255)); - context->FontHandle = CommonDuplicateFont((HFONT)SendMessage(ToolBarHandle, WM_GETFONT, 0, 0)); - - ListBox_SetItemHeight(context->AvailableListHandle, 0, context->CXWidth + 6); // BitmapHeight - ListBox_SetItemHeight(context->CurrentListHandle, 0, context->CXWidth + 6); // BitmapHeight - - CustomizeLoadToolbarItems(context); - CustomizeLoadToolbarSettings(context); - - SendMessage(context->DialogHandle, WM_NEXTDLGCTL, (WPARAM)context->CurrentListHandle, TRUE); - } - return TRUE; - case WM_DESTROY: - { - ToolbarSaveButtonSettings(); - ToolbarLoadSettings(); - CustomizeFreeToolbarItems(context); - - if (context->BrushHot) - DeleteObject(context->BrushHot); - - if (context->BrushPushed) - DeleteObject(context->BrushPushed); - - if (context->FontHandle) - DeleteObject(context->FontHandle); - } - break; - case WM_COMMAND: - { - switch (GET_WM_COMMAND_ID(wParam, lParam)) - { - case IDC_AVAILABLE: - { - switch (GET_WM_COMMAND_CMD(wParam, lParam)) - { - case LBN_DBLCLK: - { - INT index; - INT indexto; - - index = ListBox_GetCurSel(context->AvailableListHandle); - indexto = ListBox_GetCurSel(context->CurrentListHandle); - - if (index == LB_ERR) - break; - - if (indexto == LB_ERR) - break; - - CustomizeAddToolbarItem(context, index, indexto); - } - break; - } - } - break; - case IDC_CURRENT: - { - switch (GET_WM_COMMAND_CMD(wParam, lParam)) - { - case LBN_SELCHANGE: - { - INT count; - INT index; - PBUTTON_CONTEXT itemContext; - - if ((count = ListBox_GetCount(context->CurrentListHandle)) == LB_ERR) - break; - - if ((index = ListBox_GetCurSel(context->CurrentListHandle)) == LB_ERR) - break; - - if (!(itemContext = (PBUTTON_CONTEXT)ListBox_GetItemData(context->CurrentListHandle, index))) - break; - - if (index == 0 && count == 2) - { - // first and last item - Button_Enable(context->MoveUpButtonHandle, FALSE); - Button_Enable(context->MoveDownButtonHandle, FALSE); - } - else if (index == (count - 1)) - { - // last item (virtual separator) - Button_Enable(context->MoveUpButtonHandle, FALSE); - Button_Enable(context->MoveDownButtonHandle, FALSE); - } - else if (index == (count - 2)) - { - // second last item (last non-virtual item) - Button_Enable(context->MoveUpButtonHandle, TRUE); - Button_Enable(context->MoveDownButtonHandle, FALSE); - } - else if (index == 0) - { - // first item - Button_Enable(context->MoveUpButtonHandle, FALSE); - Button_Enable(context->MoveDownButtonHandle, TRUE); - } - else - { - Button_Enable(context->MoveUpButtonHandle, TRUE); - Button_Enable(context->MoveDownButtonHandle, TRUE); - } - - Button_Enable(context->RemoveButtonHandle, itemContext->IsRemovable); - } - break; - case LBN_DBLCLK: - { - INT count; - INT index; - - if ((count = ListBox_GetCount(context->CurrentListHandle)) == LB_ERR) - break; - - if ((index = ListBox_GetCurSel(context->CurrentListHandle)) == LB_ERR) - break; - - if (index == (count - 1)) - { - // virtual separator - break; - } - - CustomizeRemoveToolbarItem(context, index); - } - break; - } - } - break; - case IDC_ADD: - { - INT index; - INT indexto; - - if ((index = ListBox_GetCurSel(context->AvailableListHandle)) == LB_ERR) - break; - - if ((indexto = ListBox_GetCurSel(context->CurrentListHandle)) == LB_ERR) - break; - - CustomizeAddToolbarItem(context, index, indexto); - } - break; - case IDC_REMOVE: - { - INT index; - - if ((index = ListBox_GetCurSel(context->CurrentListHandle)) == LB_ERR) - break; - - CustomizeRemoveToolbarItem(context, index); - } - break; - case IDC_MOVEUP: - { - INT index; - - if ((index = ListBox_GetCurSel(context->CurrentListHandle)) == LB_ERR) - break; - - CustomizeMoveToolbarItem(context, index, index - 1); - } - break; - case IDC_MOVEDOWN: - { - INT index; - - if ((index = ListBox_GetCurSel(context->CurrentListHandle)) == LB_ERR) - break; - - CustomizeMoveToolbarItem(context, index, index + 1); - } - break; - case IDC_RESET: - { - // Reset the Toolbar buttons to default settings. - ToolbarResetSettings(); - // Re-load the settings. - ToolbarLoadSettings(); - // Save as the new defaults. - ToolbarSaveButtonSettings(); - - CustomizeLoadToolbarItems(context); - } - break; - case IDC_TEXTOPTIONS: - { - if (GET_WM_COMMAND_CMD(wParam, lParam) == CBN_SELCHANGE) - { - PhSetIntegerSetting(SETTING_NAME_TOOLBARDISPLAYSTYLE, - (DisplayStyle = (TOOLBAR_DISPLAY_STYLE)ComboBox_GetCurSel(GET_WM_COMMAND_HWND(wParam, lParam)))); - - ToolbarLoadSettings(); - } - } - break; - case IDC_SEARCHOPTIONS: - { - if (GET_WM_COMMAND_CMD(wParam, lParam) == CBN_SELCHANGE) - { - PhSetIntegerSetting(SETTING_NAME_SEARCHBOXDISPLAYMODE, - (SearchBoxDisplayMode = (SEARCHBOX_DISPLAY_MODE)ComboBox_GetCurSel(GET_WM_COMMAND_HWND(wParam, lParam)))); - - ToolbarLoadSettings(); - } - } - break; - //case IDC_THEMEOPTIONS: - // { - // if (GET_WM_COMMAND_CMD(wParam, lParam) == CBN_SELCHANGE) - // { - // PhSetIntegerSetting(SETTING_NAME_TOOLBAR_THEME, - // (ToolBarTheme = (TOOLBAR_THEME)ComboBox_GetCurSel(GET_WM_COMMAND_HWND(wParam, lParam)))); - // - // switch (ToolBarTheme) - // { - // case TOOLBAR_THEME_NONE: - // { - // SendMessage(RebarHandle, RB_SETWINDOWTHEME, 0, (LPARAM)L""); - // SendMessage(ToolBarHandle, TB_SETWINDOWTHEME, 0, (LPARAM)L""); - // } - // break; - // case TOOLBAR_THEME_BLACK: - // { - // SendMessage(RebarHandle, RB_SETWINDOWTHEME, 0, (LPARAM)L"Media"); - // SendMessage(ToolBarHandle, TB_SETWINDOWTHEME, 0, (LPARAM)L"Media"); - // } - // break; - // case TOOLBAR_THEME_BLUE: - // { - // SendMessage(RebarHandle, RB_SETWINDOWTHEME, 0, (LPARAM)L"Communications"); - // SendMessage(ToolBarHandle, TB_SETWINDOWTHEME, 0, (LPARAM)L"Communications"); - // } - // break; - // } - // } - // } - // break; - case IDC_ENABLE_MODERN: - { - if (GET_WM_COMMAND_CMD(wParam, lParam) == BN_CLICKED) - { - ToolStatusConfig.ModernIcons = Button_GetCheck(GET_WM_COMMAND_HWND(wParam, lParam)) == BST_CHECKED; - - PhSetIntegerSetting(SETTING_NAME_TOOLSTATUS_CONFIG, ToolStatusConfig.Flags); - - ToolbarLoadSettings(); - - CustomizeResetImages(context); - CustomizeResetToolbarImages(); - //CustomizeLoadItems(context); - } - } - break; - case IDC_ENABLE_AUTOHIDE_MENU: - { - if (GET_WM_COMMAND_CMD(wParam, lParam) == BN_CLICKED) - { - ToolStatusConfig.AutoHideMenu = !ToolStatusConfig.AutoHideMenu; - - PhSetIntegerSetting(SETTING_NAME_TOOLSTATUS_CONFIG, ToolStatusConfig.Flags); - - if (ToolStatusConfig.AutoHideMenu) - { - SetMenu(PhMainWndHandle, NULL); - } - else - { - SetMenu(PhMainWndHandle, MainMenu); - DrawMenuBar(PhMainWndHandle); - } - } - } - break; - case IDCANCEL: - { - EndDialog(hwndDlg, FALSE); - } - break; - } - } - break; - case WM_DRAWITEM: - { - LPDRAWITEMSTRUCT drawInfo = (LPDRAWITEMSTRUCT)lParam; - - if (drawInfo->CtlID == IDC_AVAILABLE || drawInfo->CtlID == IDC_CURRENT) - { - HDC bufferDc; - HBITMAP bufferBitmap; - HBITMAP oldBufferBitmap; - PBUTTON_CONTEXT itemContext; - RECT bufferRect = - { - 0, 0, - drawInfo->rcItem.right - drawInfo->rcItem.left, - drawInfo->rcItem.bottom - drawInfo->rcItem.top - }; - BOOLEAN isSelected = (drawInfo->itemState & ODS_SELECTED) == ODS_SELECTED; - BOOLEAN isFocused = (drawInfo->itemState & ODS_FOCUS) == ODS_FOCUS; - - if (drawInfo->itemID == LB_ERR) - break; - - if (!(itemContext = (PBUTTON_CONTEXT)ListBox_GetItemData(drawInfo->hwndItem, drawInfo->itemID))) - break; - - bufferDc = CreateCompatibleDC(drawInfo->hDC); - bufferBitmap = CreateCompatibleBitmap(drawInfo->hDC, bufferRect.right, bufferRect.bottom); - - oldBufferBitmap = SelectBitmap(bufferDc, bufferBitmap); - SelectFont(bufferDc, context->FontHandle); - SetBkMode(bufferDc, TRANSPARENT); - - if (isFocused) - { - FillRect(bufferDc, &bufferRect, context->BrushHot); // leak - //FrameRect(bufferDc, &bufferRect, GetStockBrush(BLACK_BRUSH)); - - if (!itemContext->IsVirtual) - { - SetTextColor(bufferDc, GetSysColor(COLOR_WINDOWTEXT)); - } - else - { - SetTextColor(bufferDc, GetSysColor(COLOR_GRAYTEXT)); - } - } - else - { - FillRect(bufferDc, &bufferRect, context->BrushNormal); - //FrameRect(bufferDc, &bufferRect, GetSysColorBrush(COLOR_HIGHLIGHTTEXT)); - - if (!itemContext->IsVirtual) - { - SetTextColor(bufferDc, GetSysColor(COLOR_WINDOWTEXT)); - } - else - { - SetTextColor(bufferDc, GetSysColor(COLOR_GRAYTEXT)); - } - } - - if (itemContext->IconHandle && !itemContext->IsSeparator) - { - DrawIconEx( - bufferDc, - bufferRect.left + 2, - bufferRect.top + ((bufferRect.bottom - bufferRect.top) - context->CXWidth) / 2, - itemContext->IconHandle, - context->CXWidth, - context->CXWidth, - 0, - NULL, - DI_NORMAL - ); - } - - bufferRect.left += context->CXWidth + 4; - - if (itemContext->IdCommand != 0) - { - DrawText( - bufferDc, - ToolbarGetText(itemContext->IdCommand), - -1, - &bufferRect, - DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS | DT_NOCLIP - ); - } - else - { - DrawText( - bufferDc, - L"Separator", - -1, - &bufferRect, - DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS | DT_NOCLIP - ); - } - - BitBlt( - drawInfo->hDC, - drawInfo->rcItem.left, - drawInfo->rcItem.top, - drawInfo->rcItem.right, - drawInfo->rcItem.bottom, - bufferDc, - 0, - 0, - SRCCOPY - ); - - SelectBitmap(bufferDc, oldBufferBitmap); - DeleteBitmap(bufferBitmap); - DeleteDC(bufferDc); - - return TRUE; - } - } - break; - } - - return FALSE; -} - -VOID ToolBarShowCustomizeDialog( - VOID - ) -{ - DialogBox( - PluginInstance->DllBase, - MAKEINTRESOURCE(IDD_CUSTOMIZE_TB), - PhMainWndHandle, - CustomizeToolbarDialogProc - ); +/* + * Process Hacker ToolStatus - + * Toolbar Customize Dialog + * + * Copyright (C) 2015-2016 dmex + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include "toolstatus.h" +#include "commonutil.h" + +static PWSTR CustomizeTextOptionsStrings[] = +{ + L"No text labels", + L"Selective text", + L"Show text labels" +}; + +static PWSTR CustomizeSearchDisplayStrings[] = +{ + L"Always show", + L"Hide when inactive (Ctrl+K)", + // L"Auto-hide" +}; + +static PWSTR CustomizeThemeOptionsStrings[] = +{ + L"None", + L"Black", + L"Blue" +}; + +BOOLEAN CustomizeToolbarItemExists( + _In_ PCUSTOMIZE_CONTEXT Context, + _In_ INT IdCommand + ) +{ + INT index = 0; + INT count = 0; + PBUTTON_CONTEXT button; + + if ((count = ListBox_GetCount(Context->CurrentListHandle)) == LB_ERR) + return FALSE; + + for (index = 0; index < count; index++) + { + if (!(button = (PBUTTON_CONTEXT)ListBox_GetItemData(Context->CurrentListHandle, index))) + continue; + + if (button->IdCommand == IdCommand) + return TRUE; + } + + return FALSE; +} + +VOID CustomizeInsertToolbarButton( + _In_ INT Index, + _In_ PBUTTON_CONTEXT ItemContext + ) +{ + TBBUTTON button; + + memset(&button, 0, sizeof(TBBUTTON)); + + button.idCommand = ItemContext->IdCommand; + button.iBitmap = I_IMAGECALLBACK; + button.fsState = TBSTATE_ENABLED; + button.iString = (INT_PTR)ToolbarGetText(ItemContext->IdCommand); + + if (ItemContext->IsSeparator) + { + button.fsStyle = BTNS_SEP; + } + else + { + switch (DisplayStyle) + { + case TOOLBAR_DISPLAY_STYLE_IMAGEONLY: + button.fsStyle = BTNS_BUTTON | BTNS_AUTOSIZE; + break; + case TOOLBAR_DISPLAY_STYLE_SELECTIVETEXT: + { + switch (button.idCommand) + { + case PHAPP_ID_VIEW_REFRESH: + case PHAPP_ID_HACKER_OPTIONS: + case PHAPP_ID_HACKER_FINDHANDLESORDLLS: + case PHAPP_ID_VIEW_SYSTEMINFORMATION: + button.fsStyle = BTNS_BUTTON | BTNS_AUTOSIZE | BTNS_SHOWTEXT; + break; + default: + button.fsStyle = BTNS_BUTTON | BTNS_AUTOSIZE; + break; + } + } + break; + case TOOLBAR_DISPLAY_STYLE_ALLTEXT: + button.fsStyle = BTNS_BUTTON | BTNS_AUTOSIZE | BTNS_SHOWTEXT; + break; + } + } + + SendMessage(ToolBarHandle, TB_INSERTBUTTON, Index, (LPARAM)&button); +} + +VOID CustomizeAddToolbarItem( + _In_ PCUSTOMIZE_CONTEXT Context, + _In_ INT IndexAvail, + _In_ INT IndexTo + ) +{ + INT count; + PBUTTON_CONTEXT button; + + if ((count = ListBox_GetCount(Context->AvailableListHandle)) == LB_ERR) + return; + + if (!(button = (PBUTTON_CONTEXT)ListBox_GetItemData(Context->AvailableListHandle, IndexAvail))) + return; + + if (IndexAvail != 0) // index 0 is separator + { + // remove from 'available' list + ListBox_DeleteString(Context->AvailableListHandle, IndexAvail); + + if (IndexAvail == count - 1) + { + ListBox_SetCurSel(Context->AvailableListHandle, IndexAvail - 1); + } + else + { + ListBox_SetCurSel(Context->AvailableListHandle, IndexAvail); + } + } + else + { + button = PhAllocate(sizeof(BUTTON_CONTEXT)); + memset(button, 0, sizeof(BUTTON_CONTEXT)); + + button->IsSeparator = TRUE; + button->IsRemovable = TRUE; + } + + // insert into 'current' list + ListBox_InsertItemData(Context->CurrentListHandle, IndexTo, button); + + CustomizeInsertToolbarButton(IndexTo, button); +} + +VOID CustomizeRemoveToolbarItem( + _In_ PCUSTOMIZE_CONTEXT Context, + _In_ INT IndexFrom + ) +{ + PBUTTON_CONTEXT button; + + if (!(button = (PBUTTON_CONTEXT)ListBox_GetItemData(Context->CurrentListHandle, IndexFrom))) + return; + + ListBox_DeleteString(Context->CurrentListHandle, IndexFrom); + ListBox_SetCurSel(Context->CurrentListHandle, IndexFrom); + + SendMessage(ToolBarHandle, TB_DELETEBUTTON, IndexFrom, 0); + + if (button->IsSeparator) + { + PhFree(button); + } + else + { + // insert into 'available' list + ListBox_AddItemData(Context->AvailableListHandle, button); + } + + SendMessage(Context->DialogHandle, WM_COMMAND, MAKEWPARAM(IDC_CURRENT, LBN_SELCHANGE), 0); +} + +VOID CustomizeMoveToolbarItem( + _In_ PCUSTOMIZE_CONTEXT Context, + _In_ INT IndexFrom, + _In_ INT IndexTo + ) +{ + INT count; + PBUTTON_CONTEXT button; + + if (IndexFrom == IndexTo) + return; + + if ((count = ListBox_GetCount(Context->CurrentListHandle)) == LB_ERR) + return; + + if (!(button = (PBUTTON_CONTEXT)ListBox_GetItemData(Context->CurrentListHandle, IndexFrom))) + return; + + ListBox_DeleteString(Context->CurrentListHandle, IndexFrom); + ListBox_InsertItemData(Context->CurrentListHandle, IndexTo, button); + ListBox_SetCurSel(Context->CurrentListHandle, IndexTo); + + if (IndexTo <= 0) + { + Button_Enable(Context->MoveUpButtonHandle, FALSE); + } + else + { + Button_Enable(Context->MoveUpButtonHandle, TRUE); + } + + // last item is always separator + if (IndexTo >= (count - 2)) + { + Button_Enable(Context->MoveDownButtonHandle, FALSE); + } + else + { + Button_Enable(Context->MoveDownButtonHandle, TRUE); + } + + SendMessage(ToolBarHandle, TB_DELETEBUTTON, IndexFrom, 0); + + CustomizeInsertToolbarButton(IndexTo, button); +} + +VOID CustomizeFreeToolbarItems( + _In_ PCUSTOMIZE_CONTEXT Context + ) +{ + INT i = 0; + INT count = 0; + PBUTTON_CONTEXT button; + + if ((count = ListBox_GetCount(Context->CurrentListHandle)) != LB_ERR) + { + for (i = 0; i < count; i++) + { + if (button = (PBUTTON_CONTEXT)ListBox_GetItemData(Context->CurrentListHandle, i)) + { + if (button->IconHandle) + { + DeleteObject(button->IconHandle); + } + + PhFree(button); + } + } + } + + if ((count = ListBox_GetCount(Context->AvailableListHandle)) != LB_ERR) + { + for (i = 0; i < count; i++) + { + if (button = (PBUTTON_CONTEXT)ListBox_GetItemData(Context->AvailableListHandle, i)) + { + if (button->IconHandle) + { + DeleteObject(button->IconHandle); + } + + PhFree(button); + } + } + } +} + +VOID CustomizeLoadToolbarItems( + _In_ PCUSTOMIZE_CONTEXT Context + ) +{ + INT index = 0; + INT count = 0; + PBUTTON_CONTEXT context; + + CustomizeFreeToolbarItems(Context); + + ListBox_ResetContent(Context->AvailableListHandle); + ListBox_ResetContent(Context->CurrentListHandle); + + count = (INT)SendMessage(ToolBarHandle, TB_BUTTONCOUNT, 0, 0); + + for (index = 0; index < count; index++) + { + TBBUTTON button; + + memset(&button, 0, sizeof(TBBUTTON)); + + if (SendMessage(ToolBarHandle, TB_GETBUTTON, index, (LPARAM)&button)) + { + context = PhAllocate(sizeof(BUTTON_CONTEXT)); + memset(context, 0, sizeof(BUTTON_CONTEXT)); + + context->IsVirtual = FALSE; + context->IsRemovable = TRUE; + context->IdCommand = button.idCommand; + + if (button.fsStyle & BTNS_SEP) + { + context->IsSeparator = TRUE; + } + else + { + context->IconHandle = CustomizeGetToolbarIcon(Context, button.idCommand); + } + + ListBox_AddItemData(Context->CurrentListHandle, context); + } + } + + for (index = 0; index < MAX_TOOLBAR_ITEMS; index++) + { + TBBUTTON button = ToolbarButtons[index]; + + if (button.idCommand == 0) + continue; + + if (CustomizeToolbarItemExists(Context, button.idCommand)) + continue; + + context = PhAllocate(sizeof(BUTTON_CONTEXT)); + memset(context, 0, sizeof(BUTTON_CONTEXT)); + + context->IsRemovable = TRUE; + context->IdCommand = button.idCommand; + context->IconHandle = CustomizeGetToolbarIcon(Context, button.idCommand); + + ListBox_AddItemData(Context->AvailableListHandle, context); + } + + // Append separator to the last 'current list' position + context = PhAllocate(sizeof(BUTTON_CONTEXT)); + memset(context, 0, sizeof(BUTTON_CONTEXT)); + context->IsSeparator = TRUE; + context->IsVirtual = TRUE; + context->IsRemovable = FALSE; + + index = ListBox_AddItemData(Context->CurrentListHandle, context); + ListBox_SetCurSel(Context->CurrentListHandle, index); + ListBox_SetTopIndex(Context->CurrentListHandle, index); + + // Insert separator into first 'available list' position + context = PhAllocate(sizeof(BUTTON_CONTEXT)); + memset(context, 0, sizeof(BUTTON_CONTEXT)); + context->IsSeparator = TRUE; + context->IsVirtual = FALSE; + context->IsRemovable = FALSE; + + index = ListBox_InsertItemData(Context->AvailableListHandle, 0, context); + ListBox_SetCurSel(Context->AvailableListHandle, index); + ListBox_SetTopIndex(Context->AvailableListHandle, index); + + // Disable buttons + Button_Enable(Context->MoveUpButtonHandle, FALSE); + Button_Enable(Context->MoveDownButtonHandle, FALSE); + Button_Enable(Context->RemoveButtonHandle, FALSE); +} + +VOID CustomizeLoadToolbarSettings( + _In_ PCUSTOMIZE_CONTEXT Context + ) +{ + HWND toolbarCombo = GetDlgItem(Context->DialogHandle, IDC_TEXTOPTIONS); + HWND searchboxCombo = GetDlgItem(Context->DialogHandle, IDC_SEARCHOPTIONS); + + PhAddComboBoxStrings( + toolbarCombo, + CustomizeTextOptionsStrings, + ARRAYSIZE(CustomizeTextOptionsStrings) + ); + PhAddComboBoxStrings( + searchboxCombo, + CustomizeSearchDisplayStrings, + ARRAYSIZE(CustomizeSearchDisplayStrings) + ); + ComboBox_SetCurSel(toolbarCombo, PhGetIntegerSetting(SETTING_NAME_TOOLBARDISPLAYSTYLE)); + ComboBox_SetCurSel(searchboxCombo, PhGetIntegerSetting(SETTING_NAME_SEARCHBOXDISPLAYMODE)); + + Button_SetCheck(GetDlgItem(Context->DialogHandle, IDC_ENABLE_MODERN), + ToolStatusConfig.ModernIcons ? BST_CHECKED : BST_UNCHECKED); + Button_SetCheck(GetDlgItem(Context->DialogHandle, IDC_ENABLE_AUTOHIDE_MENU), + ToolStatusConfig.AutoHideMenu ? BST_CHECKED : BST_UNCHECKED); + + if (!ToolStatusConfig.SearchBoxEnabled) + { + ComboBox_Enable(searchboxCombo, FALSE); + } +} + +VOID CustomizeResetImages( + _In_ PCUSTOMIZE_CONTEXT Context + ) +{ + INT index = 0; + INT count = 0; + PBUTTON_CONTEXT button; + + if ((count = ListBox_GetCount(Context->CurrentListHandle)) != LB_ERR) + { + for (index = 0; index < count; index++) + { + if (button = (PBUTTON_CONTEXT)ListBox_GetItemData(Context->CurrentListHandle, index)) + { + button->IconHandle = CustomizeGetToolbarIcon(Context, button->IdCommand); + } + } + } + + if ((count = ListBox_GetCount(Context->AvailableListHandle)) != LB_ERR) + { + for (index = 0; index < count; index++) + { + if (button = (PBUTTON_CONTEXT)ListBox_GetItemData(Context->AvailableListHandle, index)) + { + button->IconHandle = CustomizeGetToolbarIcon(Context, button->IdCommand); + } + } + } + + InvalidateRect(Context->AvailableListHandle, NULL, TRUE); + InvalidateRect(Context->CurrentListHandle, NULL, TRUE); +} + +HICON CustomizeGetToolbarIcon( + _In_ PCUSTOMIZE_CONTEXT Context, + _In_ INT CommandID + ) +{ + HBITMAP bitmapHandle; + HICON iconHandle; + + bitmapHandle = ToolbarGetImage(CommandID); + iconHandle = CommonBitmapToIcon(bitmapHandle, Context->CXWidth, Context->CXWidth); + + DeleteObject(bitmapHandle); + return iconHandle; +} + +VOID CustomizeResetToolbarImages( + VOID + ) +{ + // Reset the image cache with the new icons. + // TODO: Move function to Toolbar.c + for (INT index = 0; index < ARRAYSIZE(ToolbarButtons); index++) + { + if (ToolbarButtons[index].iBitmap != I_IMAGECALLBACK) + { + HBITMAP bitmap; + + if (bitmap = ToolbarGetImage(ToolbarButtons[index].idCommand)) + { + ImageList_Replace( + ToolBarImageList, + ToolbarButtons[index].iBitmap, + bitmap, + NULL + ); + + DeleteObject(bitmap); + } + } + } +} + +INT_PTR CALLBACK CustomizeToolbarDialogProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + PCUSTOMIZE_CONTEXT context = NULL; + + if (uMsg == WM_INITDIALOG) + { + context = (PCUSTOMIZE_CONTEXT)PhAllocate(sizeof(CUSTOMIZE_CONTEXT)); + memset(context, 0, sizeof(CUSTOMIZE_CONTEXT)); + + SetProp(hwndDlg, L"Context", (HANDLE)context); + } + else + { + context = (PCUSTOMIZE_CONTEXT)GetProp(hwndDlg, L"Context"); + + if (uMsg == WM_NCDESTROY) + { + RemoveProp(hwndDlg, L"Context"); + PhFree(context); + } + } + + if (context == NULL) + return FALSE; + + switch (uMsg) + { + case WM_INITDIALOG: + { + PhCenterWindow(hwndDlg, PhMainWndHandle); + + context->DialogHandle = hwndDlg; + context->AvailableListHandle = GetDlgItem(hwndDlg, IDC_AVAILABLE); + context->CurrentListHandle = GetDlgItem(hwndDlg, IDC_CURRENT); + context->MoveUpButtonHandle = GetDlgItem(hwndDlg, IDC_MOVEUP); + context->MoveDownButtonHandle = GetDlgItem(hwndDlg, IDC_MOVEDOWN); + context->AddButtonHandle = GetDlgItem(hwndDlg, IDC_ADD); + context->RemoveButtonHandle = GetDlgItem(hwndDlg, IDC_REMOVE); + + context->CXWidth = 16; + context->BrushNormal = GetSysColorBrush(COLOR_WINDOW); + context->BrushHot = CreateSolidBrush(RGB(145, 201, 247)); + context->BrushPushed = CreateSolidBrush(RGB(153, 209, 255)); + context->FontHandle = CommonDuplicateFont((HFONT)SendMessage(ToolBarHandle, WM_GETFONT, 0, 0)); + + ListBox_SetItemHeight(context->AvailableListHandle, 0, context->CXWidth + 6); // BitmapHeight + ListBox_SetItemHeight(context->CurrentListHandle, 0, context->CXWidth + 6); // BitmapHeight + + CustomizeLoadToolbarItems(context); + CustomizeLoadToolbarSettings(context); + + SendMessage(context->DialogHandle, WM_NEXTDLGCTL, (WPARAM)context->CurrentListHandle, TRUE); + } + return TRUE; + case WM_DESTROY: + { + ToolbarSaveButtonSettings(); + ToolbarLoadSettings(); + CustomizeFreeToolbarItems(context); + + if (context->BrushHot) + DeleteObject(context->BrushHot); + + if (context->BrushPushed) + DeleteObject(context->BrushPushed); + + if (context->FontHandle) + DeleteObject(context->FontHandle); + } + break; + case WM_COMMAND: + { + switch (GET_WM_COMMAND_ID(wParam, lParam)) + { + case IDC_AVAILABLE: + { + switch (GET_WM_COMMAND_CMD(wParam, lParam)) + { + case LBN_DBLCLK: + { + INT index; + INT indexto; + + index = ListBox_GetCurSel(context->AvailableListHandle); + indexto = ListBox_GetCurSel(context->CurrentListHandle); + + if (index == LB_ERR) + break; + + if (indexto == LB_ERR) + break; + + CustomizeAddToolbarItem(context, index, indexto); + } + break; + } + } + break; + case IDC_CURRENT: + { + switch (GET_WM_COMMAND_CMD(wParam, lParam)) + { + case LBN_SELCHANGE: + { + INT count; + INT index; + PBUTTON_CONTEXT itemContext; + + if ((count = ListBox_GetCount(context->CurrentListHandle)) == LB_ERR) + break; + + if ((index = ListBox_GetCurSel(context->CurrentListHandle)) == LB_ERR) + break; + + if (!(itemContext = (PBUTTON_CONTEXT)ListBox_GetItemData(context->CurrentListHandle, index))) + break; + + if (index == 0 && count == 2) + { + // first and last item + Button_Enable(context->MoveUpButtonHandle, FALSE); + Button_Enable(context->MoveDownButtonHandle, FALSE); + } + else if (index == (count - 1)) + { + // last item (virtual separator) + Button_Enable(context->MoveUpButtonHandle, FALSE); + Button_Enable(context->MoveDownButtonHandle, FALSE); + } + else if (index == (count - 2)) + { + // second last item (last non-virtual item) + Button_Enable(context->MoveUpButtonHandle, TRUE); + Button_Enable(context->MoveDownButtonHandle, FALSE); + } + else if (index == 0) + { + // first item + Button_Enable(context->MoveUpButtonHandle, FALSE); + Button_Enable(context->MoveDownButtonHandle, TRUE); + } + else + { + Button_Enable(context->MoveUpButtonHandle, TRUE); + Button_Enable(context->MoveDownButtonHandle, TRUE); + } + + Button_Enable(context->RemoveButtonHandle, itemContext->IsRemovable); + } + break; + case LBN_DBLCLK: + { + INT count; + INT index; + + if ((count = ListBox_GetCount(context->CurrentListHandle)) == LB_ERR) + break; + + if ((index = ListBox_GetCurSel(context->CurrentListHandle)) == LB_ERR) + break; + + if (index == (count - 1)) + { + // virtual separator + break; + } + + CustomizeRemoveToolbarItem(context, index); + } + break; + } + } + break; + case IDC_ADD: + { + INT index; + INT indexto; + + if ((index = ListBox_GetCurSel(context->AvailableListHandle)) == LB_ERR) + break; + + if ((indexto = ListBox_GetCurSel(context->CurrentListHandle)) == LB_ERR) + break; + + CustomizeAddToolbarItem(context, index, indexto); + } + break; + case IDC_REMOVE: + { + INT index; + + if ((index = ListBox_GetCurSel(context->CurrentListHandle)) == LB_ERR) + break; + + CustomizeRemoveToolbarItem(context, index); + } + break; + case IDC_MOVEUP: + { + INT index; + + if ((index = ListBox_GetCurSel(context->CurrentListHandle)) == LB_ERR) + break; + + CustomizeMoveToolbarItem(context, index, index - 1); + } + break; + case IDC_MOVEDOWN: + { + INT index; + + if ((index = ListBox_GetCurSel(context->CurrentListHandle)) == LB_ERR) + break; + + CustomizeMoveToolbarItem(context, index, index + 1); + } + break; + case IDC_RESET: + { + // Reset the Toolbar buttons to default settings. + ToolbarResetSettings(); + // Re-load the settings. + ToolbarLoadSettings(); + // Save as the new defaults. + ToolbarSaveButtonSettings(); + + CustomizeLoadToolbarItems(context); + } + break; + case IDC_TEXTOPTIONS: + { + if (GET_WM_COMMAND_CMD(wParam, lParam) == CBN_SELCHANGE) + { + PhSetIntegerSetting(SETTING_NAME_TOOLBARDISPLAYSTYLE, + (DisplayStyle = (TOOLBAR_DISPLAY_STYLE)ComboBox_GetCurSel(GET_WM_COMMAND_HWND(wParam, lParam)))); + + ToolbarLoadSettings(); + } + } + break; + case IDC_SEARCHOPTIONS: + { + if (GET_WM_COMMAND_CMD(wParam, lParam) == CBN_SELCHANGE) + { + PhSetIntegerSetting(SETTING_NAME_SEARCHBOXDISPLAYMODE, + (SearchBoxDisplayMode = (SEARCHBOX_DISPLAY_MODE)ComboBox_GetCurSel(GET_WM_COMMAND_HWND(wParam, lParam)))); + + ToolbarLoadSettings(); + } + } + break; + //case IDC_THEMEOPTIONS: + // { + // if (GET_WM_COMMAND_CMD(wParam, lParam) == CBN_SELCHANGE) + // { + // PhSetIntegerSetting(SETTING_NAME_TOOLBAR_THEME, + // (ToolBarTheme = (TOOLBAR_THEME)ComboBox_GetCurSel(GET_WM_COMMAND_HWND(wParam, lParam)))); + // + // switch (ToolBarTheme) + // { + // case TOOLBAR_THEME_NONE: + // { + // SendMessage(RebarHandle, RB_SETWINDOWTHEME, 0, (LPARAM)L""); + // SendMessage(ToolBarHandle, TB_SETWINDOWTHEME, 0, (LPARAM)L""); + // } + // break; + // case TOOLBAR_THEME_BLACK: + // { + // SendMessage(RebarHandle, RB_SETWINDOWTHEME, 0, (LPARAM)L"Media"); + // SendMessage(ToolBarHandle, TB_SETWINDOWTHEME, 0, (LPARAM)L"Media"); + // } + // break; + // case TOOLBAR_THEME_BLUE: + // { + // SendMessage(RebarHandle, RB_SETWINDOWTHEME, 0, (LPARAM)L"Communications"); + // SendMessage(ToolBarHandle, TB_SETWINDOWTHEME, 0, (LPARAM)L"Communications"); + // } + // break; + // } + // } + // } + // break; + case IDC_ENABLE_MODERN: + { + if (GET_WM_COMMAND_CMD(wParam, lParam) == BN_CLICKED) + { + ToolStatusConfig.ModernIcons = Button_GetCheck(GET_WM_COMMAND_HWND(wParam, lParam)) == BST_CHECKED; + + PhSetIntegerSetting(SETTING_NAME_TOOLSTATUS_CONFIG, ToolStatusConfig.Flags); + + ToolbarLoadSettings(); + + CustomizeResetImages(context); + CustomizeResetToolbarImages(); + //CustomizeLoadItems(context); + } + } + break; + case IDC_ENABLE_AUTOHIDE_MENU: + { + if (GET_WM_COMMAND_CMD(wParam, lParam) == BN_CLICKED) + { + ToolStatusConfig.AutoHideMenu = !ToolStatusConfig.AutoHideMenu; + + PhSetIntegerSetting(SETTING_NAME_TOOLSTATUS_CONFIG, ToolStatusConfig.Flags); + + if (ToolStatusConfig.AutoHideMenu) + { + SetMenu(PhMainWndHandle, NULL); + } + else + { + SetMenu(PhMainWndHandle, MainMenu); + DrawMenuBar(PhMainWndHandle); + } + } + } + break; + case IDCANCEL: + { + EndDialog(hwndDlg, FALSE); + } + break; + } + } + break; + case WM_DRAWITEM: + { + LPDRAWITEMSTRUCT drawInfo = (LPDRAWITEMSTRUCT)lParam; + + if (drawInfo->CtlID == IDC_AVAILABLE || drawInfo->CtlID == IDC_CURRENT) + { + HDC bufferDc; + HBITMAP bufferBitmap; + HBITMAP oldBufferBitmap; + PBUTTON_CONTEXT itemContext; + RECT bufferRect = + { + 0, 0, + drawInfo->rcItem.right - drawInfo->rcItem.left, + drawInfo->rcItem.bottom - drawInfo->rcItem.top + }; + BOOLEAN isSelected = (drawInfo->itemState & ODS_SELECTED) == ODS_SELECTED; + BOOLEAN isFocused = (drawInfo->itemState & ODS_FOCUS) == ODS_FOCUS; + + if (drawInfo->itemID == LB_ERR) + break; + + if (!(itemContext = (PBUTTON_CONTEXT)ListBox_GetItemData(drawInfo->hwndItem, drawInfo->itemID))) + break; + + bufferDc = CreateCompatibleDC(drawInfo->hDC); + bufferBitmap = CreateCompatibleBitmap(drawInfo->hDC, bufferRect.right, bufferRect.bottom); + + oldBufferBitmap = SelectBitmap(bufferDc, bufferBitmap); + SelectFont(bufferDc, context->FontHandle); + SetBkMode(bufferDc, TRANSPARENT); + + if (isFocused) + { + FillRect(bufferDc, &bufferRect, context->BrushHot); // leak + //FrameRect(bufferDc, &bufferRect, GetStockBrush(BLACK_BRUSH)); + + if (!itemContext->IsVirtual) + { + SetTextColor(bufferDc, GetSysColor(COLOR_WINDOWTEXT)); + } + else + { + SetTextColor(bufferDc, GetSysColor(COLOR_GRAYTEXT)); + } + } + else + { + FillRect(bufferDc, &bufferRect, context->BrushNormal); + //FrameRect(bufferDc, &bufferRect, GetSysColorBrush(COLOR_HIGHLIGHTTEXT)); + + if (!itemContext->IsVirtual) + { + SetTextColor(bufferDc, GetSysColor(COLOR_WINDOWTEXT)); + } + else + { + SetTextColor(bufferDc, GetSysColor(COLOR_GRAYTEXT)); + } + } + + if (itemContext->IconHandle && !itemContext->IsSeparator) + { + DrawIconEx( + bufferDc, + bufferRect.left + 2, + bufferRect.top + ((bufferRect.bottom - bufferRect.top) - context->CXWidth) / 2, + itemContext->IconHandle, + context->CXWidth, + context->CXWidth, + 0, + NULL, + DI_NORMAL + ); + } + + bufferRect.left += context->CXWidth + 4; + + if (itemContext->IdCommand != 0) + { + DrawText( + bufferDc, + ToolbarGetText(itemContext->IdCommand), + -1, + &bufferRect, + DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS | DT_NOCLIP + ); + } + else + { + DrawText( + bufferDc, + L"Separator", + -1, + &bufferRect, + DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS | DT_NOCLIP + ); + } + + BitBlt( + drawInfo->hDC, + drawInfo->rcItem.left, + drawInfo->rcItem.top, + drawInfo->rcItem.right, + drawInfo->rcItem.bottom, + bufferDc, + 0, + 0, + SRCCOPY + ); + + SelectBitmap(bufferDc, oldBufferBitmap); + DeleteBitmap(bufferBitmap); + DeleteDC(bufferDc); + + return TRUE; + } + } + break; + } + + return FALSE; +} + +VOID ToolBarShowCustomizeDialog( + VOID + ) +{ + DialogBox( + PluginInstance->DllBase, + MAKEINTRESOURCE(IDD_CUSTOMIZE_TB), + PhMainWndHandle, + CustomizeToolbarDialogProc + ); } \ No newline at end of file diff --git a/plugins/ToolStatus/filter.c b/plugins/ToolStatus/filter.c index 70dc09f3febb..3e89fa21b0d3 100644 --- a/plugins/ToolStatus/filter.c +++ b/plugins/ToolStatus/filter.c @@ -1,670 +1,670 @@ -/* - * Process Hacker ToolStatus - - * search filter callbacks - * - * Copyright (C) 2011-2016 dmex - * Copyright (C) 2010-2013 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include "toolstatus.h" -#include - -BOOLEAN WordMatchStringRef( - _In_ PPH_STRINGREF Text - ) -{ - PH_STRINGREF part; - PH_STRINGREF remainingPart; - - remainingPart = SearchboxText->sr; - - while (remainingPart.Length) - { - PhSplitStringRefAtChar(&remainingPart, '|', &part, &remainingPart); - - if (part.Length) - { - if (PhFindStringInStringRef(Text, &part, TRUE) != -1) - return TRUE; - } - } - - return FALSE; -} - -BOOLEAN WordMatchStringZ( - _In_ PWSTR Text - ) -{ - PH_STRINGREF text; - - PhInitializeStringRef(&text, Text); - return WordMatchStringRef(&text); -} - -BOOLEAN ProcessTreeFilterCallback( - _In_ PPH_TREENEW_NODE Node, - _In_opt_ PVOID Context - ) -{ - PPH_PROCESS_NODE processNode = (PPH_PROCESS_NODE)Node; - - if (PhIsNullOrEmptyString(SearchboxText)) - return TRUE; - - if (!PhIsNullOrEmptyString(processNode->ProcessItem->ProcessName)) - { - if (WordMatchStringRef(&processNode->ProcessItem->ProcessName->sr)) - return TRUE; - } - - if (!PhIsNullOrEmptyString(processNode->ProcessItem->FileName)) - { - if (WordMatchStringRef(&processNode->ProcessItem->FileName->sr)) - return TRUE; - } - - if (!PhIsNullOrEmptyString(processNode->ProcessItem->CommandLine)) - { - if (WordMatchStringRef(&processNode->ProcessItem->CommandLine->sr)) - return TRUE; - } - - if (!PhIsNullOrEmptyString(processNode->ProcessItem->VersionInfo.CompanyName)) - { - if (WordMatchStringRef(&processNode->ProcessItem->VersionInfo.CompanyName->sr)) - return TRUE; - } - - if (!PhIsNullOrEmptyString(processNode->ProcessItem->VersionInfo.FileDescription)) - { - if (WordMatchStringRef(&processNode->ProcessItem->VersionInfo.FileDescription->sr)) - return TRUE; - } - - if (!PhIsNullOrEmptyString(processNode->ProcessItem->VersionInfo.FileVersion)) - { - if (WordMatchStringRef(&processNode->ProcessItem->VersionInfo.FileVersion->sr)) - return TRUE; - } - - if (!PhIsNullOrEmptyString(processNode->ProcessItem->VersionInfo.ProductName)) - { - if (WordMatchStringRef(&processNode->ProcessItem->VersionInfo.ProductName->sr)) - return TRUE; - } - - if (!PhIsNullOrEmptyString(processNode->ProcessItem->UserName)) - { - if (WordMatchStringRef(&processNode->ProcessItem->UserName->sr)) - return TRUE; - } - - if (processNode->ProcessItem->IntegrityString) - { - if (WordMatchStringZ(processNode->ProcessItem->IntegrityString)) - return TRUE; - } - - if (!PhIsNullOrEmptyString(processNode->ProcessItem->JobName)) - { - if (WordMatchStringRef(&processNode->ProcessItem->JobName->sr)) - return TRUE; - } - - if (!PhIsNullOrEmptyString(processNode->ProcessItem->VerifySignerName)) - { - if (WordMatchStringRef(&processNode->ProcessItem->VerifySignerName->sr)) - return TRUE; - } - - if (processNode->ProcessItem->ProcessIdString[0]) - { - if (WordMatchStringZ(processNode->ProcessItem->ProcessIdString)) - return TRUE; - } - - if (processNode->ProcessItem->ParentProcessIdString[0]) - { - if (WordMatchStringZ(processNode->ProcessItem->ParentProcessIdString)) - return TRUE; - } - - if (processNode->ProcessItem->SessionIdString[0]) - { - if (WordMatchStringZ(processNode->ProcessItem->SessionIdString)) - return TRUE; - } - - if (!PhIsNullOrEmptyString(processNode->ProcessItem->PackageFullName)) - { - if (WordMatchStringRef(&processNode->ProcessItem->PackageFullName->sr)) - return TRUE; - } - - if (WordMatchStringZ(PhGetProcessPriorityClassString(processNode->ProcessItem->PriorityClass))) - { - return TRUE; - } - - if (processNode->ProcessItem->VerifyResult != VrUnknown) - { - switch (processNode->ProcessItem->VerifyResult) - { - case VrNoSignature: - if (WordMatchStringZ(L"NoSignature")) - return TRUE; - break; - case VrTrusted: - if (WordMatchStringZ(L"Trusted")) - return TRUE; - break; - case VrExpired: - if (WordMatchStringZ(L"Expired")) - return TRUE; - break; - case VrRevoked: - if (WordMatchStringZ(L"Revoked")) - return TRUE; - break; - case VrDistrust: - if (WordMatchStringZ(L"Distrust")) - return TRUE; - break; - case VrSecuritySettings: - if (WordMatchStringZ(L"SecuritySettings")) - return TRUE; - break; - case VrBadSignature: - if (WordMatchStringZ(L"BadSignature")) - return TRUE; - break; - default: - if (WordMatchStringZ(L"Unknown")) - return TRUE; - break; - } - } - - if (WINDOWS_HAS_UAC && processNode->ProcessItem->ElevationType != TokenElevationTypeDefault) - { - switch (processNode->ProcessItem->ElevationType) - { - case TokenElevationTypeLimited: - if (WordMatchStringZ(L"Limited")) - return TRUE; - break; - case TokenElevationTypeFull: - if (WordMatchStringZ(L"Full")) - return TRUE; - break; - default: - if (WordMatchStringZ(L"Unknown")) - return TRUE; - break; - } - } - - if (WordMatchStringZ(L"IsBeingDebugged") && processNode->ProcessItem->IsBeingDebugged) - { - return TRUE; - } - - if (WordMatchStringZ(L"IsDotNet") && processNode->ProcessItem->IsDotNet) - { - return TRUE; - } - - if (WordMatchStringZ(L"IsElevated") && processNode->ProcessItem->IsElevated) - { - return TRUE; - } - - if (WordMatchStringZ(L"IsInJob") && processNode->ProcessItem->IsInJob) - { - return TRUE; - } - - if (WordMatchStringZ(L"IsInSignificantJob") && processNode->ProcessItem->IsInSignificantJob) - { - return TRUE; - } - - if (WordMatchStringZ(L"IsPacked") && processNode->ProcessItem->IsPacked) - { - return TRUE; - } - - if (WordMatchStringZ(L"IsSuspended") && processNode->ProcessItem->IsSuspended) - { - return TRUE; - } - - if (WordMatchStringZ(L"IsWow64") && processNode->ProcessItem->IsWow64) - { - return TRUE; - } - - if (WordMatchStringZ(L"IsImmersive") && processNode->ProcessItem->IsImmersive) - { - return TRUE; - } - - if (WordMatchStringZ(L"IsProtectedProcess") && processNode->ProcessItem->IsProtectedProcess) - { - return TRUE; - } - - if (WordMatchStringZ(L"IsSecureProcess") && processNode->ProcessItem->IsSecureProcess) - { - return TRUE; - } - - if (WordMatchStringZ(L"IsPicoProcess") && processNode->ProcessItem->IsSubsystemProcess) - { - return TRUE; - } - - if (processNode->ProcessItem->ServiceList && processNode->ProcessItem->ServiceList->Count) - { - ULONG enumerationKey = 0; - PPH_SERVICE_ITEM serviceItem; - PPH_LIST serviceList; - ULONG i; - BOOLEAN matched = FALSE; - - // Copy the service list so we can search it. - serviceList = PhCreateList(processNode->ProcessItem->ServiceList->Count); - - PhAcquireQueuedLockShared(&processNode->ProcessItem->ServiceListLock); - - while (PhEnumPointerList( - processNode->ProcessItem->ServiceList, - &enumerationKey, - &serviceItem - )) - { - PhReferenceObject(serviceItem); - PhAddItemList(serviceList, serviceItem); - } - - PhReleaseQueuedLockShared(&processNode->ProcessItem->ServiceListLock); - - for (i = 0; i < serviceList->Count; i++) - { - PPH_STRING serviceFileName = NULL; - PPH_STRING serviceBinaryPath = NULL; - - serviceItem = serviceList->Items[i]; - - if (!PhIsNullOrEmptyString(serviceItem->Name)) - { - if (WordMatchStringRef(&serviceItem->Name->sr)) - { - matched = TRUE; - break; - } - } - - if (!PhIsNullOrEmptyString(serviceItem->DisplayName)) - { - if (WordMatchStringRef(&serviceItem->DisplayName->sr)) - { - matched = TRUE; - break; - } - } - - if (serviceItem->ProcessId) - { - WCHAR processIdString[PH_INT32_STR_LEN_1]; - - PhPrintUInt32(processIdString, HandleToUlong(serviceItem->ProcessId)); - - if (WordMatchStringZ(processIdString)) - { - matched = TRUE; - break; - } - } - - if (NT_SUCCESS(QueryServiceFileName( - &serviceItem->Name->sr, - &serviceFileName, - &serviceBinaryPath - ))) - { - if (serviceFileName) - { - if (WordMatchStringRef(&serviceFileName->sr)) - { - matched = TRUE; - } - - PhDereferenceObject(serviceFileName); - } - - if (serviceBinaryPath) - { - if (WordMatchStringRef(&serviceBinaryPath->sr)) - { - matched = TRUE; - } - - PhDereferenceObject(serviceBinaryPath); - } - - if (matched) - break; - } - } - - PhDereferenceObjects(serviceList->Items, serviceList->Count); - PhDereferenceObject(serviceList); - - if (matched) - return TRUE; - } - - return FALSE; -} - -BOOLEAN ServiceTreeFilterCallback( - _In_ PPH_TREENEW_NODE Node, - _In_opt_ PVOID Context - ) -{ - PPH_SERVICE_NODE serviceNode = (PPH_SERVICE_NODE)Node; - PPH_STRING serviceFileName = NULL; - PPH_STRING serviceBinaryPath = NULL; - - if (PhIsNullOrEmptyString(SearchboxText)) - return TRUE; - - if (WordMatchStringZ(PhGetServiceTypeString(serviceNode->ServiceItem->Type))) - return TRUE; - - if (WordMatchStringZ(PhGetServiceStateString(serviceNode->ServiceItem->State))) - return TRUE; - - if (WordMatchStringZ(PhGetServiceStartTypeString(serviceNode->ServiceItem->StartType))) - return TRUE; - - if (WordMatchStringZ(PhGetServiceErrorControlString(serviceNode->ServiceItem->ErrorControl))) - return TRUE; - - if (!PhIsNullOrEmptyString(serviceNode->ServiceItem->Name)) - { - if (WordMatchStringRef(&serviceNode->ServiceItem->Name->sr)) - return TRUE; - } - - if (!PhIsNullOrEmptyString(serviceNode->ServiceItem->DisplayName)) - { - if (WordMatchStringRef(&serviceNode->ServiceItem->DisplayName->sr)) - return TRUE; - } - - if (serviceNode->ServiceItem->ProcessId) - { - PPH_PROCESS_NODE processNode; - WCHAR processIdString[PH_INT32_STR_LEN_1]; - - PhPrintUInt32(processIdString, HandleToUlong(serviceNode->ServiceItem->ProcessId)); - - if (WordMatchStringZ(processIdString)) - return TRUE; - - // Search the process node - if (processNode = PhFindProcessNode(serviceNode->ServiceItem->ProcessId)) - { - if (ProcessTreeFilterCallback(&processNode->Node, NULL)) - return TRUE; - } - } - - if (NT_SUCCESS(QueryServiceFileName( - &serviceNode->ServiceItem->Name->sr, - &serviceFileName, - &serviceBinaryPath - ))) - { - BOOLEAN matched = FALSE; - - if (serviceFileName) - { - if (WordMatchStringRef(&serviceFileName->sr)) - { - matched = TRUE; - } - - PhDereferenceObject(serviceFileName); - } - - if (serviceBinaryPath) - { - if (WordMatchStringRef(&serviceBinaryPath->sr)) - { - matched = TRUE; - } - - PhDereferenceObject(serviceBinaryPath); - } - - if (matched) - return TRUE; - } - - return FALSE; -} - -BOOLEAN NetworkTreeFilterCallback( - _In_ PPH_TREENEW_NODE Node, - _In_opt_ PVOID Context - ) -{ - PPH_NETWORK_NODE networkNode = (PPH_NETWORK_NODE)Node; - - if (PhIsNullOrEmptyString(SearchboxText)) - return TRUE; - - if (!PhIsNullOrEmptyString(networkNode->NetworkItem->ProcessName)) - { - if (WordMatchStringRef(&networkNode->NetworkItem->ProcessName->sr)) - return TRUE; - } - - if (!PhIsNullOrEmptyString(networkNode->NetworkItem->OwnerName)) - { - if (WordMatchStringRef(&networkNode->NetworkItem->OwnerName->sr)) - return TRUE; - } - - if (networkNode->NetworkItem->LocalAddressString[0]) - { - if (WordMatchStringZ(networkNode->NetworkItem->LocalAddressString)) - return TRUE; - } - - if (networkNode->NetworkItem->LocalPortString[0]) - { - if (WordMatchStringZ(networkNode->NetworkItem->LocalPortString)) - return TRUE; - } - - if (!PhIsNullOrEmptyString(networkNode->NetworkItem->LocalHostString)) - { - if (WordMatchStringRef(&networkNode->NetworkItem->LocalHostString->sr)) - return TRUE; - } - - if (networkNode->NetworkItem->RemoteAddressString[0]) - { - if (WordMatchStringZ(networkNode->NetworkItem->RemoteAddressString)) - return TRUE; - } - - if (networkNode->NetworkItem->RemotePortString[0]) - { - if (WordMatchStringZ(networkNode->NetworkItem->RemotePortString)) - return TRUE; - } - - if (!PhIsNullOrEmptyString(networkNode->NetworkItem->RemoteHostString)) - { - if (WordMatchStringRef(&networkNode->NetworkItem->RemoteHostString->sr)) - return TRUE; - } - - if (WordMatchStringZ(PhGetProtocolTypeName(networkNode->NetworkItem->ProtocolType))) - return TRUE; - - if ((networkNode->NetworkItem->ProtocolType & PH_TCP_PROTOCOL_TYPE) && - WordMatchStringZ(PhGetTcpStateName(networkNode->NetworkItem->State))) - return TRUE; - - if (networkNode->NetworkItem->ProcessId) - { - PPH_PROCESS_NODE processNode; - WCHAR processIdString[PH_INT32_STR_LEN_1]; - - PhPrintUInt32(processIdString, HandleToUlong(networkNode->NetworkItem->ProcessId)); - - if (WordMatchStringZ(processIdString)) - return TRUE; - - // Search the process node - if (processNode = PhFindProcessNode(networkNode->NetworkItem->ProcessId)) - { - if (ProcessTreeFilterCallback(&processNode->Node, NULL)) - return TRUE; - } - } - - return FALSE; -} - -// NOTE: This function does not use the SCM due to major performance issues. -// For now just query this information from the registry but it might be out-of-sync -// with any recent services changes until the SCM flushes its cache. -NTSTATUS QueryServiceFileName( - _In_ PPH_STRINGREF ServiceName, - _Out_ PPH_STRING *ServiceFileName, - _Out_ PPH_STRING *ServiceBinaryPath - ) -{ - static PH_STRINGREF servicesKeyName = PH_STRINGREF_INIT(L"System\\CurrentControlSet\\Services\\"); - static PH_STRINGREF typeKeyName = PH_STRINGREF_INIT(L"Type"); - - NTSTATUS status; - HANDLE keyHandle; - ULONG serviceType = 0; - PPH_STRING keyName; - PPH_STRING binaryPath; - PPH_STRING fileName; - - keyName = PhConcatStringRef2(&servicesKeyName, ServiceName); - binaryPath = NULL; - fileName = NULL; - - if (NT_SUCCESS(status = PhOpenKey( - &keyHandle, - KEY_READ, - PH_KEY_LOCAL_MACHINE, - &keyName->sr, - 0 - ))) - { - PPH_STRING serviceImagePath; - PKEY_VALUE_PARTIAL_INFORMATION buffer; - - if (NT_SUCCESS(status = PhQueryValueKey( - keyHandle, - &typeKeyName, - KeyValuePartialInformation, - &buffer - ))) - { - if ( - buffer->Type == REG_DWORD && - buffer->DataLength == sizeof(ULONG) - ) - { - serviceType = *(PULONG)buffer->Data; - } - - PhFree(buffer); - } - - if (serviceImagePath = PhQueryRegistryString(keyHandle, L"ImagePath")) - { - PPH_STRING expandedString; - - if (expandedString = PhExpandEnvironmentStrings(&serviceImagePath->sr)) - { - binaryPath = expandedString; - PhDereferenceObject(serviceImagePath); - } - else - { - binaryPath = serviceImagePath; - } - } - else - { - status = STATUS_NOT_FOUND; - } - - NtClose(keyHandle); - } - - if (NT_SUCCESS(status)) - { - PhGetServiceDllParameter(ServiceName, &fileName); - - if (!fileName) - { - if (serviceType & SERVICE_WIN32) - { - PH_STRINGREF dummyFileName; - PH_STRINGREF dummyArguments; - - PhParseCommandLineFuzzy(&binaryPath->sr, &dummyFileName, &dummyArguments, &fileName); - - if (!fileName) - PhSwapReference(&fileName, binaryPath); - } - else - { - fileName = PhGetFileName(binaryPath); - } - } - - *ServiceFileName = fileName; - *ServiceBinaryPath = binaryPath; - } - else - { - if (binaryPath) - PhDereferenceObject(binaryPath); - } - - PhDereferenceObject(keyName); - - return status; -} +/* + * Process Hacker ToolStatus - + * search filter callbacks + * + * Copyright (C) 2011-2016 dmex + * Copyright (C) 2010-2013 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include "toolstatus.h" +#include + +BOOLEAN WordMatchStringRef( + _In_ PPH_STRINGREF Text + ) +{ + PH_STRINGREF part; + PH_STRINGREF remainingPart; + + remainingPart = SearchboxText->sr; + + while (remainingPart.Length) + { + PhSplitStringRefAtChar(&remainingPart, '|', &part, &remainingPart); + + if (part.Length) + { + if (PhFindStringInStringRef(Text, &part, TRUE) != -1) + return TRUE; + } + } + + return FALSE; +} + +BOOLEAN WordMatchStringZ( + _In_ PWSTR Text + ) +{ + PH_STRINGREF text; + + PhInitializeStringRef(&text, Text); + return WordMatchStringRef(&text); +} + +BOOLEAN ProcessTreeFilterCallback( + _In_ PPH_TREENEW_NODE Node, + _In_opt_ PVOID Context + ) +{ + PPH_PROCESS_NODE processNode = (PPH_PROCESS_NODE)Node; + + if (PhIsNullOrEmptyString(SearchboxText)) + return TRUE; + + if (!PhIsNullOrEmptyString(processNode->ProcessItem->ProcessName)) + { + if (WordMatchStringRef(&processNode->ProcessItem->ProcessName->sr)) + return TRUE; + } + + if (!PhIsNullOrEmptyString(processNode->ProcessItem->FileName)) + { + if (WordMatchStringRef(&processNode->ProcessItem->FileName->sr)) + return TRUE; + } + + if (!PhIsNullOrEmptyString(processNode->ProcessItem->CommandLine)) + { + if (WordMatchStringRef(&processNode->ProcessItem->CommandLine->sr)) + return TRUE; + } + + if (!PhIsNullOrEmptyString(processNode->ProcessItem->VersionInfo.CompanyName)) + { + if (WordMatchStringRef(&processNode->ProcessItem->VersionInfo.CompanyName->sr)) + return TRUE; + } + + if (!PhIsNullOrEmptyString(processNode->ProcessItem->VersionInfo.FileDescription)) + { + if (WordMatchStringRef(&processNode->ProcessItem->VersionInfo.FileDescription->sr)) + return TRUE; + } + + if (!PhIsNullOrEmptyString(processNode->ProcessItem->VersionInfo.FileVersion)) + { + if (WordMatchStringRef(&processNode->ProcessItem->VersionInfo.FileVersion->sr)) + return TRUE; + } + + if (!PhIsNullOrEmptyString(processNode->ProcessItem->VersionInfo.ProductName)) + { + if (WordMatchStringRef(&processNode->ProcessItem->VersionInfo.ProductName->sr)) + return TRUE; + } + + if (!PhIsNullOrEmptyString(processNode->ProcessItem->UserName)) + { + if (WordMatchStringRef(&processNode->ProcessItem->UserName->sr)) + return TRUE; + } + + if (processNode->ProcessItem->IntegrityString) + { + if (WordMatchStringZ(processNode->ProcessItem->IntegrityString)) + return TRUE; + } + + if (!PhIsNullOrEmptyString(processNode->ProcessItem->JobName)) + { + if (WordMatchStringRef(&processNode->ProcessItem->JobName->sr)) + return TRUE; + } + + if (!PhIsNullOrEmptyString(processNode->ProcessItem->VerifySignerName)) + { + if (WordMatchStringRef(&processNode->ProcessItem->VerifySignerName->sr)) + return TRUE; + } + + if (processNode->ProcessItem->ProcessIdString[0]) + { + if (WordMatchStringZ(processNode->ProcessItem->ProcessIdString)) + return TRUE; + } + + if (processNode->ProcessItem->ParentProcessIdString[0]) + { + if (WordMatchStringZ(processNode->ProcessItem->ParentProcessIdString)) + return TRUE; + } + + if (processNode->ProcessItem->SessionIdString[0]) + { + if (WordMatchStringZ(processNode->ProcessItem->SessionIdString)) + return TRUE; + } + + if (!PhIsNullOrEmptyString(processNode->ProcessItem->PackageFullName)) + { + if (WordMatchStringRef(&processNode->ProcessItem->PackageFullName->sr)) + return TRUE; + } + + if (WordMatchStringZ(PhGetProcessPriorityClassString(processNode->ProcessItem->PriorityClass))) + { + return TRUE; + } + + if (processNode->ProcessItem->VerifyResult != VrUnknown) + { + switch (processNode->ProcessItem->VerifyResult) + { + case VrNoSignature: + if (WordMatchStringZ(L"NoSignature")) + return TRUE; + break; + case VrTrusted: + if (WordMatchStringZ(L"Trusted")) + return TRUE; + break; + case VrExpired: + if (WordMatchStringZ(L"Expired")) + return TRUE; + break; + case VrRevoked: + if (WordMatchStringZ(L"Revoked")) + return TRUE; + break; + case VrDistrust: + if (WordMatchStringZ(L"Distrust")) + return TRUE; + break; + case VrSecuritySettings: + if (WordMatchStringZ(L"SecuritySettings")) + return TRUE; + break; + case VrBadSignature: + if (WordMatchStringZ(L"BadSignature")) + return TRUE; + break; + default: + if (WordMatchStringZ(L"Unknown")) + return TRUE; + break; + } + } + + if (WINDOWS_HAS_UAC && processNode->ProcessItem->ElevationType != TokenElevationTypeDefault) + { + switch (processNode->ProcessItem->ElevationType) + { + case TokenElevationTypeLimited: + if (WordMatchStringZ(L"Limited")) + return TRUE; + break; + case TokenElevationTypeFull: + if (WordMatchStringZ(L"Full")) + return TRUE; + break; + default: + if (WordMatchStringZ(L"Unknown")) + return TRUE; + break; + } + } + + if (WordMatchStringZ(L"IsBeingDebugged") && processNode->ProcessItem->IsBeingDebugged) + { + return TRUE; + } + + if (WordMatchStringZ(L"IsDotNet") && processNode->ProcessItem->IsDotNet) + { + return TRUE; + } + + if (WordMatchStringZ(L"IsElevated") && processNode->ProcessItem->IsElevated) + { + return TRUE; + } + + if (WordMatchStringZ(L"IsInJob") && processNode->ProcessItem->IsInJob) + { + return TRUE; + } + + if (WordMatchStringZ(L"IsInSignificantJob") && processNode->ProcessItem->IsInSignificantJob) + { + return TRUE; + } + + if (WordMatchStringZ(L"IsPacked") && processNode->ProcessItem->IsPacked) + { + return TRUE; + } + + if (WordMatchStringZ(L"IsSuspended") && processNode->ProcessItem->IsSuspended) + { + return TRUE; + } + + if (WordMatchStringZ(L"IsWow64") && processNode->ProcessItem->IsWow64) + { + return TRUE; + } + + if (WordMatchStringZ(L"IsImmersive") && processNode->ProcessItem->IsImmersive) + { + return TRUE; + } + + if (WordMatchStringZ(L"IsProtectedProcess") && processNode->ProcessItem->IsProtectedProcess) + { + return TRUE; + } + + if (WordMatchStringZ(L"IsSecureProcess") && processNode->ProcessItem->IsSecureProcess) + { + return TRUE; + } + + if (WordMatchStringZ(L"IsPicoProcess") && processNode->ProcessItem->IsSubsystemProcess) + { + return TRUE; + } + + if (processNode->ProcessItem->ServiceList && processNode->ProcessItem->ServiceList->Count) + { + ULONG enumerationKey = 0; + PPH_SERVICE_ITEM serviceItem; + PPH_LIST serviceList; + ULONG i; + BOOLEAN matched = FALSE; + + // Copy the service list so we can search it. + serviceList = PhCreateList(processNode->ProcessItem->ServiceList->Count); + + PhAcquireQueuedLockShared(&processNode->ProcessItem->ServiceListLock); + + while (PhEnumPointerList( + processNode->ProcessItem->ServiceList, + &enumerationKey, + &serviceItem + )) + { + PhReferenceObject(serviceItem); + PhAddItemList(serviceList, serviceItem); + } + + PhReleaseQueuedLockShared(&processNode->ProcessItem->ServiceListLock); + + for (i = 0; i < serviceList->Count; i++) + { + PPH_STRING serviceFileName = NULL; + PPH_STRING serviceBinaryPath = NULL; + + serviceItem = serviceList->Items[i]; + + if (!PhIsNullOrEmptyString(serviceItem->Name)) + { + if (WordMatchStringRef(&serviceItem->Name->sr)) + { + matched = TRUE; + break; + } + } + + if (!PhIsNullOrEmptyString(serviceItem->DisplayName)) + { + if (WordMatchStringRef(&serviceItem->DisplayName->sr)) + { + matched = TRUE; + break; + } + } + + if (serviceItem->ProcessId) + { + WCHAR processIdString[PH_INT32_STR_LEN_1]; + + PhPrintUInt32(processIdString, HandleToUlong(serviceItem->ProcessId)); + + if (WordMatchStringZ(processIdString)) + { + matched = TRUE; + break; + } + } + + if (NT_SUCCESS(QueryServiceFileName( + &serviceItem->Name->sr, + &serviceFileName, + &serviceBinaryPath + ))) + { + if (serviceFileName) + { + if (WordMatchStringRef(&serviceFileName->sr)) + { + matched = TRUE; + } + + PhDereferenceObject(serviceFileName); + } + + if (serviceBinaryPath) + { + if (WordMatchStringRef(&serviceBinaryPath->sr)) + { + matched = TRUE; + } + + PhDereferenceObject(serviceBinaryPath); + } + + if (matched) + break; + } + } + + PhDereferenceObjects(serviceList->Items, serviceList->Count); + PhDereferenceObject(serviceList); + + if (matched) + return TRUE; + } + + return FALSE; +} + +BOOLEAN ServiceTreeFilterCallback( + _In_ PPH_TREENEW_NODE Node, + _In_opt_ PVOID Context + ) +{ + PPH_SERVICE_NODE serviceNode = (PPH_SERVICE_NODE)Node; + PPH_STRING serviceFileName = NULL; + PPH_STRING serviceBinaryPath = NULL; + + if (PhIsNullOrEmptyString(SearchboxText)) + return TRUE; + + if (WordMatchStringZ(PhGetServiceTypeString(serviceNode->ServiceItem->Type))) + return TRUE; + + if (WordMatchStringZ(PhGetServiceStateString(serviceNode->ServiceItem->State))) + return TRUE; + + if (WordMatchStringZ(PhGetServiceStartTypeString(serviceNode->ServiceItem->StartType))) + return TRUE; + + if (WordMatchStringZ(PhGetServiceErrorControlString(serviceNode->ServiceItem->ErrorControl))) + return TRUE; + + if (!PhIsNullOrEmptyString(serviceNode->ServiceItem->Name)) + { + if (WordMatchStringRef(&serviceNode->ServiceItem->Name->sr)) + return TRUE; + } + + if (!PhIsNullOrEmptyString(serviceNode->ServiceItem->DisplayName)) + { + if (WordMatchStringRef(&serviceNode->ServiceItem->DisplayName->sr)) + return TRUE; + } + + if (serviceNode->ServiceItem->ProcessId) + { + PPH_PROCESS_NODE processNode; + WCHAR processIdString[PH_INT32_STR_LEN_1]; + + PhPrintUInt32(processIdString, HandleToUlong(serviceNode->ServiceItem->ProcessId)); + + if (WordMatchStringZ(processIdString)) + return TRUE; + + // Search the process node + if (processNode = PhFindProcessNode(serviceNode->ServiceItem->ProcessId)) + { + if (ProcessTreeFilterCallback(&processNode->Node, NULL)) + return TRUE; + } + } + + if (NT_SUCCESS(QueryServiceFileName( + &serviceNode->ServiceItem->Name->sr, + &serviceFileName, + &serviceBinaryPath + ))) + { + BOOLEAN matched = FALSE; + + if (serviceFileName) + { + if (WordMatchStringRef(&serviceFileName->sr)) + { + matched = TRUE; + } + + PhDereferenceObject(serviceFileName); + } + + if (serviceBinaryPath) + { + if (WordMatchStringRef(&serviceBinaryPath->sr)) + { + matched = TRUE; + } + + PhDereferenceObject(serviceBinaryPath); + } + + if (matched) + return TRUE; + } + + return FALSE; +} + +BOOLEAN NetworkTreeFilterCallback( + _In_ PPH_TREENEW_NODE Node, + _In_opt_ PVOID Context + ) +{ + PPH_NETWORK_NODE networkNode = (PPH_NETWORK_NODE)Node; + + if (PhIsNullOrEmptyString(SearchboxText)) + return TRUE; + + if (!PhIsNullOrEmptyString(networkNode->NetworkItem->ProcessName)) + { + if (WordMatchStringRef(&networkNode->NetworkItem->ProcessName->sr)) + return TRUE; + } + + if (!PhIsNullOrEmptyString(networkNode->NetworkItem->OwnerName)) + { + if (WordMatchStringRef(&networkNode->NetworkItem->OwnerName->sr)) + return TRUE; + } + + if (networkNode->NetworkItem->LocalAddressString[0]) + { + if (WordMatchStringZ(networkNode->NetworkItem->LocalAddressString)) + return TRUE; + } + + if (networkNode->NetworkItem->LocalPortString[0]) + { + if (WordMatchStringZ(networkNode->NetworkItem->LocalPortString)) + return TRUE; + } + + if (!PhIsNullOrEmptyString(networkNode->NetworkItem->LocalHostString)) + { + if (WordMatchStringRef(&networkNode->NetworkItem->LocalHostString->sr)) + return TRUE; + } + + if (networkNode->NetworkItem->RemoteAddressString[0]) + { + if (WordMatchStringZ(networkNode->NetworkItem->RemoteAddressString)) + return TRUE; + } + + if (networkNode->NetworkItem->RemotePortString[0]) + { + if (WordMatchStringZ(networkNode->NetworkItem->RemotePortString)) + return TRUE; + } + + if (!PhIsNullOrEmptyString(networkNode->NetworkItem->RemoteHostString)) + { + if (WordMatchStringRef(&networkNode->NetworkItem->RemoteHostString->sr)) + return TRUE; + } + + if (WordMatchStringZ(PhGetProtocolTypeName(networkNode->NetworkItem->ProtocolType))) + return TRUE; + + if ((networkNode->NetworkItem->ProtocolType & PH_TCP_PROTOCOL_TYPE) && + WordMatchStringZ(PhGetTcpStateName(networkNode->NetworkItem->State))) + return TRUE; + + if (networkNode->NetworkItem->ProcessId) + { + PPH_PROCESS_NODE processNode; + WCHAR processIdString[PH_INT32_STR_LEN_1]; + + PhPrintUInt32(processIdString, HandleToUlong(networkNode->NetworkItem->ProcessId)); + + if (WordMatchStringZ(processIdString)) + return TRUE; + + // Search the process node + if (processNode = PhFindProcessNode(networkNode->NetworkItem->ProcessId)) + { + if (ProcessTreeFilterCallback(&processNode->Node, NULL)) + return TRUE; + } + } + + return FALSE; +} + +// NOTE: This function does not use the SCM due to major performance issues. +// For now just query this information from the registry but it might be out-of-sync +// with any recent services changes until the SCM flushes its cache. +NTSTATUS QueryServiceFileName( + _In_ PPH_STRINGREF ServiceName, + _Out_ PPH_STRING *ServiceFileName, + _Out_ PPH_STRING *ServiceBinaryPath + ) +{ + static PH_STRINGREF servicesKeyName = PH_STRINGREF_INIT(L"System\\CurrentControlSet\\Services\\"); + static PH_STRINGREF typeKeyName = PH_STRINGREF_INIT(L"Type"); + + NTSTATUS status; + HANDLE keyHandle; + ULONG serviceType = 0; + PPH_STRING keyName; + PPH_STRING binaryPath; + PPH_STRING fileName; + + keyName = PhConcatStringRef2(&servicesKeyName, ServiceName); + binaryPath = NULL; + fileName = NULL; + + if (NT_SUCCESS(status = PhOpenKey( + &keyHandle, + KEY_READ, + PH_KEY_LOCAL_MACHINE, + &keyName->sr, + 0 + ))) + { + PPH_STRING serviceImagePath; + PKEY_VALUE_PARTIAL_INFORMATION buffer; + + if (NT_SUCCESS(status = PhQueryValueKey( + keyHandle, + &typeKeyName, + KeyValuePartialInformation, + &buffer + ))) + { + if ( + buffer->Type == REG_DWORD && + buffer->DataLength == sizeof(ULONG) + ) + { + serviceType = *(PULONG)buffer->Data; + } + + PhFree(buffer); + } + + if (serviceImagePath = PhQueryRegistryString(keyHandle, L"ImagePath")) + { + PPH_STRING expandedString; + + if (expandedString = PhExpandEnvironmentStrings(&serviceImagePath->sr)) + { + binaryPath = expandedString; + PhDereferenceObject(serviceImagePath); + } + else + { + binaryPath = serviceImagePath; + } + } + else + { + status = STATUS_NOT_FOUND; + } + + NtClose(keyHandle); + } + + if (NT_SUCCESS(status)) + { + PhGetServiceDllParameter(ServiceName, &fileName); + + if (!fileName) + { + if (serviceType & SERVICE_WIN32) + { + PH_STRINGREF dummyFileName; + PH_STRINGREF dummyArguments; + + PhParseCommandLineFuzzy(&binaryPath->sr, &dummyFileName, &dummyArguments, &fileName); + + if (!fileName) + PhSwapReference(&fileName, binaryPath); + } + else + { + fileName = PhGetFileName(binaryPath); + } + } + + *ServiceFileName = fileName; + *ServiceBinaryPath = binaryPath; + } + else + { + if (binaryPath) + PhDereferenceObject(binaryPath); + } + + PhDereferenceObject(keyName); + + return status; +} diff --git a/plugins/ToolStatus/graph.c b/plugins/ToolStatus/graph.c index 856838fb1eb2..c8effcd4396e 100644 --- a/plugins/ToolStatus/graph.c +++ b/plugins/ToolStatus/graph.c @@ -1,662 +1,662 @@ -/* - * Process Hacker ToolStatus - - * Toolbar Graph Bands - * - * Copyright (C) 2015-2016 dmex - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include "toolstatus.h" - -HWND CpuGraphHandle = NULL; -HWND MemGraphHandle = NULL; -HWND CommitGraphHandle = NULL; -HWND IoGraphHandle = NULL; -static PH_GRAPH_STATE CpuGraphState; -static PH_GRAPH_STATE MemGraphState; -static PH_GRAPH_STATE CommitGraphState; -static PH_GRAPH_STATE IoGraphState; - -VOID ToolbarCreateGraphs(VOID) -{ - UINT height = (UINT)SendMessage(RebarHandle, RB_GETROWHEIGHT, 0, 0); - - if (ToolStatusConfig.CpuGraphEnabled && !CpuGraphHandle) - { - CpuGraphHandle = CreateWindow( - PH_GRAPH_CLASSNAME, - NULL, - WS_VISIBLE | WS_CHILD | WS_BORDER, - 0, - 0, - 0, - 0, - PhMainWndHandle, - NULL, - NULL, - NULL - ); - Graph_SetTooltip(CpuGraphHandle, TRUE); - - PhInitializeGraphState(&CpuGraphState); - } - - if (ToolStatusConfig.MemGraphEnabled && !MemGraphHandle) - { - MemGraphHandle = CreateWindow( - PH_GRAPH_CLASSNAME, - NULL, - WS_VISIBLE | WS_CHILD | WS_BORDER, - 0, - 0, - 0, - 0, - PhMainWndHandle, - NULL, - NULL, - NULL - ); - Graph_SetTooltip(MemGraphHandle, TRUE); - - PhInitializeGraphState(&MemGraphState); - } - - if (ToolStatusConfig.CommitGraphEnabled && !CommitGraphHandle) - { - CommitGraphHandle = CreateWindow( - PH_GRAPH_CLASSNAME, - NULL, - WS_VISIBLE | WS_CHILD | WS_BORDER, - 0, - 0, - 0, - 0, - PhMainWndHandle, - NULL, - NULL, - NULL - ); - Graph_SetTooltip(CommitGraphHandle, TRUE); - - PhInitializeGraphState(&CommitGraphState); - } - - if (ToolStatusConfig.IoGraphEnabled && !IoGraphHandle) - { - IoGraphHandle = CreateWindow( - PH_GRAPH_CLASSNAME, - NULL, - WS_VISIBLE | WS_CHILD | WS_BORDER, - 0, - 0, - 0, - 0, - PhMainWndHandle, - NULL, - NULL, - NULL - ); - Graph_SetTooltip(IoGraphHandle, TRUE); - - PhInitializeGraphState(&IoGraphState); - } - - if (ToolStatusConfig.CpuGraphEnabled) - { - if (!RebarBandExists(REBAR_BAND_ID_CPUGRAPH)) - RebarBandInsert(REBAR_BAND_ID_CPUGRAPH, CpuGraphHandle, 145, height); // 85 - - if (CpuGraphHandle && !IsWindowVisible(CpuGraphHandle)) - ShowWindow(CpuGraphHandle, SW_SHOW); - } - else - { - if (RebarBandExists(REBAR_BAND_ID_CPUGRAPH)) - RebarBandRemove(REBAR_BAND_ID_CPUGRAPH); - - if (CpuGraphHandle) - { - PhDeleteGraphState(&CpuGraphState); - - DestroyWindow(CpuGraphHandle); - CpuGraphHandle = NULL; - } - } - - if (ToolStatusConfig.MemGraphEnabled) - { - if (!RebarBandExists(REBAR_BAND_ID_MEMGRAPH)) - RebarBandInsert(REBAR_BAND_ID_MEMGRAPH, MemGraphHandle, 145, height); // 85 - - if (MemGraphHandle && !IsWindowVisible(MemGraphHandle)) - { - ShowWindow(MemGraphHandle, SW_SHOW); - } - } - else - { - if (RebarBandExists(REBAR_BAND_ID_MEMGRAPH)) - RebarBandRemove(REBAR_BAND_ID_MEMGRAPH); - - if (MemGraphHandle) - { - PhDeleteGraphState(&MemGraphState); - - DestroyWindow(MemGraphHandle); - MemGraphHandle = NULL; - } - } - - if (ToolStatusConfig.CommitGraphEnabled) - { - if (!RebarBandExists(REBAR_BAND_ID_COMMITGRAPH)) - RebarBandInsert(REBAR_BAND_ID_COMMITGRAPH, CommitGraphHandle, 145, height); // 85 - - if (CommitGraphHandle && !IsWindowVisible(CommitGraphHandle)) - { - ShowWindow(CommitGraphHandle, SW_SHOW); - } - } - else - { - if (RebarBandExists(REBAR_BAND_ID_COMMITGRAPH)) - RebarBandRemove(REBAR_BAND_ID_COMMITGRAPH); - - if (CommitGraphHandle) - { - PhDeleteGraphState(&CommitGraphState); - - DestroyWindow(CommitGraphHandle); - CommitGraphHandle = NULL; - } - } - - if (ToolStatusConfig.IoGraphEnabled) - { - if (!RebarBandExists(REBAR_BAND_ID_IOGRAPH)) - RebarBandInsert(REBAR_BAND_ID_IOGRAPH, IoGraphHandle, 145, height); // 85 - - if (IoGraphHandle && !IsWindowVisible(IoGraphHandle)) - { - ShowWindow(IoGraphHandle, SW_SHOW); - } - } - else - { - if (RebarBandExists(REBAR_BAND_ID_IOGRAPH)) - RebarBandRemove(REBAR_BAND_ID_IOGRAPH); - - if (IoGraphHandle) - { - PhDeleteGraphState(&IoGraphState); - - DestroyWindow(IoGraphHandle); - IoGraphHandle = NULL; - } - } -} - -VOID ToolbarUpdateGraphs(VOID) -{ - if (ToolStatusConfig.CpuGraphEnabled && CpuGraphHandle) - { - CpuGraphState.Valid = FALSE; - CpuGraphState.TooltipIndex = -1; - Graph_MoveGrid(CpuGraphHandle, 1); - Graph_Draw(CpuGraphHandle); - Graph_UpdateTooltip(CpuGraphHandle); - InvalidateRect(CpuGraphHandle, NULL, FALSE); - } - - if (ToolStatusConfig.MemGraphEnabled && MemGraphHandle) - { - MemGraphState.Valid = FALSE; - MemGraphState.TooltipIndex = -1; - Graph_MoveGrid(MemGraphHandle, 1); - Graph_Draw(MemGraphHandle); - Graph_UpdateTooltip(MemGraphHandle); - InvalidateRect(MemGraphHandle, NULL, FALSE); - } - - if (ToolStatusConfig.CommitGraphEnabled && CommitGraphHandle) - { - CommitGraphState.Valid = FALSE; - CommitGraphState.TooltipIndex = -1; - Graph_MoveGrid(CommitGraphHandle, 1); - Graph_Draw(CommitGraphHandle); - Graph_UpdateTooltip(CommitGraphHandle); - InvalidateRect(CommitGraphHandle, NULL, FALSE); - } - - if (ToolStatusConfig.IoGraphEnabled && IoGraphHandle) - { - IoGraphState.Valid = FALSE; - IoGraphState.TooltipIndex = -1; - Graph_MoveGrid(IoGraphHandle, 1); - Graph_Draw(IoGraphHandle); - Graph_UpdateTooltip(IoGraphHandle); - InvalidateRect(IoGraphHandle, NULL, FALSE); - } -} - -// -// BEGIN copied from ProcessHacker/sysinfo.c -// - -static PPH_PROCESS_RECORD PhSipReferenceMaxCpuRecord( - _In_ LONG Index - ) -{ - LARGE_INTEGER time; - LONG maxProcessIdLong; - HANDLE maxProcessId; - - // Find the process record for the max. CPU process for the particular time. - - maxProcessIdLong = PhGetItemCircularBuffer_ULONG(SystemStatistics.MaxCpuHistory, Index); - - if (!maxProcessIdLong) - return NULL; - - // This must be treated as a signed integer to handle Interrupts correctly. - maxProcessId = LongToHandle(maxProcessIdLong); - - // Note that the time we get has its components beyond seconds cleared. - // For example: - // * At 2.5 seconds a process is started. - // * At 2.75 seconds our process provider is fired, and the process is determined - // to have 75% CPU usage, which happens to be the maximum CPU usage. - // * However the 2.75 seconds is recorded as 2 seconds due to - // RtlTimeToSecondsSince1980. - // * If we call PhFindProcessRecord, it cannot find the process because it was - // started at 2.5 seconds, not 2 seconds or older. - // - // This mean we must add one second minus one tick (100ns) to the time, giving us - // 2.9999999 seconds. This will then make sure we find the process. - PhGetStatisticsTime(NULL, Index, &time); - time.QuadPart += PH_TICKS_PER_SEC - 1; - - return PhFindProcessRecord(maxProcessId, &time); -} - -static PPH_STRING PhSipGetMaxCpuString( - _In_ LONG Index - ) -{ - PPH_PROCESS_RECORD maxProcessRecord; - FLOAT maxCpuUsage; - PPH_STRING maxUsageString = NULL; - - if (maxProcessRecord = PhSipReferenceMaxCpuRecord(Index)) - { - // We found the process record, so now we construct the max. usage string. - maxCpuUsage = PhGetItemCircularBuffer_FLOAT(SystemStatistics.MaxCpuUsageHistory, Index); - - // Make sure we don't try to display the PID of DPCs or Interrupts. - if (!PH_IS_FAKE_PROCESS_ID(maxProcessRecord->ProcessId)) - { - maxUsageString = PhaFormatString( - L"\n%s (%u): %.2f%%", - maxProcessRecord->ProcessName->Buffer, - HandleToUlong(maxProcessRecord->ProcessId), - maxCpuUsage * 100 - ); - } - else - { - maxUsageString = PhaFormatString( - L"\n%s: %.2f%%", - maxProcessRecord->ProcessName->Buffer, - maxCpuUsage * 100 - ); - } - - PhDereferenceProcessRecord(maxProcessRecord); - } - - return maxUsageString; -} - -static PPH_PROCESS_RECORD PhSipReferenceMaxIoRecord( - _In_ LONG Index - ) -{ - LARGE_INTEGER time; - ULONG maxProcessId; - - // Find the process record for the max. I/O process for the particular time. - - maxProcessId = PhGetItemCircularBuffer_ULONG(SystemStatistics.MaxIoHistory, Index); - - if (!maxProcessId) - return NULL; - - // See above for the explanation. - PhGetStatisticsTime(NULL, Index, &time); - time.QuadPart += PH_TICKS_PER_SEC - 1; - - return PhFindProcessRecord(UlongToHandle(maxProcessId), &time); -} - -static PPH_STRING PhSipGetMaxIoString( - _In_ LONG Index - ) -{ - PPH_PROCESS_RECORD maxProcessRecord; - ULONG64 maxIoReadOther; - ULONG64 maxIoWrite; - - PPH_STRING maxUsageString = NULL; - - if (maxProcessRecord = PhSipReferenceMaxIoRecord(Index)) - { - // We found the process record, so now we construct the max. usage string. - maxIoReadOther = PhGetItemCircularBuffer_ULONG64(SystemStatistics.MaxIoReadOtherHistory, Index); - maxIoWrite = PhGetItemCircularBuffer_ULONG64(SystemStatistics.MaxIoWriteHistory, Index); - - if (!PH_IS_FAKE_PROCESS_ID(maxProcessRecord->ProcessId)) - { - maxUsageString = PhaFormatString( - L"\n%s (%u): R+O: %s, W: %s", - maxProcessRecord->ProcessName->Buffer, - HandleToUlong(maxProcessRecord->ProcessId), - PhaFormatSize(maxIoReadOther, -1)->Buffer, - PhaFormatSize(maxIoWrite, -1)->Buffer - ); - } - else - { - maxUsageString = PhaFormatString( - L"\n%s: R+O: %s, W: %s", - maxProcessRecord->ProcessName->Buffer, - PhaFormatSize(maxIoReadOther, -1)->Buffer, - PhaFormatSize(maxIoWrite, -1)->Buffer - ); - } - - PhDereferenceProcessRecord(maxProcessRecord); - } - - return maxUsageString; -} - -// -// END copied from ProcessHacker/sysinfo.c -// - -VOID ToolbarUpdateGraphsInfo(LPNMHDR Header) -{ - switch (Header->code) - { - case GCN_GETDRAWINFO: - { - if (ToolStatusConfig.CpuGraphEnabled && Header->hwndFrom == CpuGraphHandle) - { - PPH_GRAPH_GETDRAWINFO getDrawInfo = (PPH_GRAPH_GETDRAWINFO)Header; - PPH_GRAPH_DRAW_INFO drawInfo = getDrawInfo->DrawInfo; - - drawInfo->Flags = PH_GRAPH_USE_GRID_X | PH_GRAPH_USE_LINE_2; - PhSiSetColorsGraphDrawInfo(drawInfo, PhGetIntegerSetting(L"ColorCpuKernel"), PhGetIntegerSetting(L"ColorCpuUser")); - - if (ProcessesUpdatedCount < 2) - return; - - PhGraphStateGetDrawInfo(&CpuGraphState, getDrawInfo, SystemStatistics.CpuUserHistory->Count); - - if (!CpuGraphState.Valid) - { - PhCopyCircularBuffer_FLOAT(SystemStatistics.CpuKernelHistory, - CpuGraphState.Data1, drawInfo->LineDataCount); - PhCopyCircularBuffer_FLOAT(SystemStatistics.CpuUserHistory, - CpuGraphState.Data2, drawInfo->LineDataCount); - - CpuGraphState.Valid = TRUE; - } - } - else if (ToolStatusConfig.MemGraphEnabled && Header->hwndFrom == MemGraphHandle) - { - PPH_GRAPH_GETDRAWINFO getDrawInfo = (PPH_GRAPH_GETDRAWINFO)Header; - PPH_GRAPH_DRAW_INFO drawInfo = getDrawInfo->DrawInfo; - - drawInfo->Flags = PH_GRAPH_USE_GRID_X; - PhSiSetColorsGraphDrawInfo(drawInfo, PhGetIntegerSetting(L"ColorPhysical"), 0); - - if (ProcessesUpdatedCount < 2) - return; - - PhGraphStateGetDrawInfo(&MemGraphState, getDrawInfo, SystemStatistics.PhysicalHistory->Count); - - if (!MemGraphState.Valid) - { - for (ULONG i = 0; i < drawInfo->LineDataCount; i++) - { - MemGraphState.Data1[i] = (FLOAT)PhGetItemCircularBuffer_ULONG(SystemStatistics.PhysicalHistory, i); - } - - PhDivideSinglesBySingle( - MemGraphState.Data1, - (FLOAT)PhSystemBasicInformation.NumberOfPhysicalPages, - drawInfo->LineDataCount - ); - - MemGraphState.Valid = TRUE; - } - } - else if (ToolStatusConfig.CommitGraphEnabled && Header->hwndFrom == CommitGraphHandle) - { - PPH_GRAPH_GETDRAWINFO getDrawInfo = (PPH_GRAPH_GETDRAWINFO)Header; - PPH_GRAPH_DRAW_INFO drawInfo = getDrawInfo->DrawInfo; - - drawInfo->Flags = PH_GRAPH_USE_GRID_X; - PhSiSetColorsGraphDrawInfo(drawInfo, PhGetIntegerSetting(L"ColorPrivate"), 0); - - if (ProcessesUpdatedCount < 2) - return; - - PhGraphStateGetDrawInfo(&CommitGraphState, getDrawInfo, SystemStatistics.CommitHistory->Count); - - if (!CommitGraphState.Valid) - { - for (ULONG i = 0; i < drawInfo->LineDataCount; i++) - { - CommitGraphState.Data1[i] = (FLOAT)PhGetItemCircularBuffer_ULONG(SystemStatistics.CommitHistory, i); - } - - PhDivideSinglesBySingle( - CommitGraphState.Data1, - (FLOAT)SystemStatistics.Performance->CommitLimit, - drawInfo->LineDataCount - ); - - CommitGraphState.Valid = TRUE; - } - } - else if (ToolStatusConfig.IoGraphEnabled && Header->hwndFrom == IoGraphHandle) - { - PPH_GRAPH_GETDRAWINFO getDrawInfo = (PPH_GRAPH_GETDRAWINFO)Header; - PPH_GRAPH_DRAW_INFO drawInfo = getDrawInfo->DrawInfo; - - drawInfo->Flags = PH_GRAPH_USE_GRID_X | PH_GRAPH_USE_LINE_2; - PhSiSetColorsGraphDrawInfo(drawInfo, PhGetIntegerSetting(L"ColorIoReadOther"), PhGetIntegerSetting(L"ColorIoWrite")); - - if (ProcessesUpdatedCount < 2) - return; - - PhGraphStateGetDrawInfo(&IoGraphState, getDrawInfo, SystemStatistics.IoReadHistory->Count); - - if (!IoGraphState.Valid) - { - FLOAT max = 1024 * 1024; // minimum scaling of 1 MB. - - for (ULONG i = 0; i < drawInfo->LineDataCount; i++) - { - IoGraphState.Data1[i] = - (FLOAT)PhGetItemCircularBuffer_ULONG64(SystemStatistics.IoReadHistory, i) + - (FLOAT)PhGetItemCircularBuffer_ULONG64(SystemStatistics.IoOtherHistory, i); - IoGraphState.Data2[i] = - (FLOAT)PhGetItemCircularBuffer_ULONG64(SystemStatistics.IoWriteHistory, i); - - if (max < IoGraphState.Data1[i] + IoGraphState.Data2[i]) - max = IoGraphState.Data1[i] + IoGraphState.Data2[i]; - } - - PhDivideSinglesBySingle(IoGraphState.Data1, max, drawInfo->LineDataCount); - PhDivideSinglesBySingle(IoGraphState.Data2, max, drawInfo->LineDataCount); - - IoGraphState.Valid = TRUE; - } - } - } - break; - case GCN_GETTOOLTIPTEXT: - { - PPH_GRAPH_GETTOOLTIPTEXT getTooltipText = (PPH_GRAPH_GETTOOLTIPTEXT)Header; - - if (getTooltipText->Index < getTooltipText->TotalCount) - { - if (ToolStatusConfig.CpuGraphEnabled && Header->hwndFrom == CpuGraphHandle) - { - if (CpuGraphState.TooltipIndex != getTooltipText->Index) - { - FLOAT cpuKernel; - FLOAT cpuUser; - - cpuKernel = PhGetItemCircularBuffer_FLOAT(SystemStatistics.CpuKernelHistory, getTooltipText->Index); - cpuUser = PhGetItemCircularBuffer_FLOAT(SystemStatistics.CpuUserHistory, getTooltipText->Index); - - PhMoveReference(&CpuGraphState.TooltipText, PhFormatString( - L"%.2f%%%s\n%s", - (cpuKernel + cpuUser) * 100, - PhGetStringOrEmpty(PhSipGetMaxCpuString(getTooltipText->Index)), - PH_AUTO_T(PH_STRING, PhGetStatisticsTimeString(NULL, getTooltipText->Index))->Buffer - )); - } - - getTooltipText->Text = CpuGraphState.TooltipText->sr; - } - else if (ToolStatusConfig.MemGraphEnabled && Header->hwndFrom == MemGraphHandle) - { - ULONG physicalUsage; - - physicalUsage = PhGetItemCircularBuffer_ULONG(SystemStatistics.PhysicalHistory, getTooltipText->Index); - - PhMoveReference(&MemGraphState.TooltipText, PhFormatString( - L"Physical memory: %s\n%s", - PhaFormatSize(UInt32x32To64(physicalUsage, PAGE_SIZE), -1)->Buffer, - PH_AUTO_T(PH_STRING, PhGetStatisticsTimeString(NULL, getTooltipText->Index))->Buffer - )); - getTooltipText->Text = MemGraphState.TooltipText->sr; - } - else if (ToolStatusConfig.CommitGraphEnabled && Header->hwndFrom == CommitGraphHandle) - { - ULONG commitUsage; - - commitUsage = PhGetItemCircularBuffer_ULONG(SystemStatistics.CommitHistory, getTooltipText->Index); - - PhMoveReference(&CommitGraphState.TooltipText, PhFormatString( - L"Commit charge: %s\n%s", - PhaFormatSize(UInt32x32To64(commitUsage, PAGE_SIZE), -1)->Buffer, - PH_AUTO_T(PH_STRING, PhGetStatisticsTimeString(NULL, getTooltipText->Index))->Buffer - )); - getTooltipText->Text = CommitGraphState.TooltipText->sr; - } - else if (ToolStatusConfig.IoGraphEnabled && Header->hwndFrom == IoGraphHandle) - { - ULONG64 ioRead; - ULONG64 ioWrite; - ULONG64 ioOther; - - ioRead = PhGetItemCircularBuffer_ULONG64(SystemStatistics.IoReadHistory, getTooltipText->Index); - ioWrite = PhGetItemCircularBuffer_ULONG64(SystemStatistics.IoWriteHistory, getTooltipText->Index); - ioOther = PhGetItemCircularBuffer_ULONG64(SystemStatistics.IoOtherHistory, getTooltipText->Index); - - PhMoveReference(&IoGraphState.TooltipText, PhFormatString( - L"R: %s\nW: %s\nO: %s%s\n%s", - PhaFormatSize(ioRead, -1)->Buffer, - PhaFormatSize(ioWrite, -1)->Buffer, - PhaFormatSize(ioOther, -1)->Buffer, - PhGetStringOrEmpty(PhSipGetMaxIoString(getTooltipText->Index)), - PH_AUTO_T(PH_STRING, PhGetStatisticsTimeString(NULL, getTooltipText->Index))->Buffer - )); - getTooltipText->Text = IoGraphState.TooltipText->sr; - } - } - } - break; - case GCN_MOUSEEVENT: - { - PPH_GRAPH_MOUSEEVENT mouseEvent = (PPH_GRAPH_MOUSEEVENT)Header; - PPH_PROCESS_RECORD record = NULL; - - if (ToolStatusConfig.CpuGraphEnabled && Header->hwndFrom == CpuGraphHandle) - { - if (mouseEvent->Message == WM_RBUTTONUP) - { - ShowCustomizeMenu(); - } - else - { - if (mouseEvent->Message == WM_LBUTTONDBLCLK && mouseEvent->Index < mouseEvent->TotalCount) - { - record = PhSipReferenceMaxCpuRecord(mouseEvent->Index); - } - - if (record) - { - PhShowProcessRecordDialog(PhMainWndHandle, record); - PhDereferenceProcessRecord(record); - } - } - } - else if (ToolStatusConfig.MemGraphEnabled && Header->hwndFrom == MemGraphHandle) - { - if (mouseEvent->Message == WM_RBUTTONUP) - { - ShowCustomizeMenu(); - } - } - else if (ToolStatusConfig.CommitGraphEnabled && Header->hwndFrom == CommitGraphHandle) - { - if (mouseEvent->Message == WM_RBUTTONUP) - { - ShowCustomizeMenu(); - } - } - else if (ToolStatusConfig.IoGraphEnabled && Header->hwndFrom == IoGraphHandle) - { - if (mouseEvent->Message == WM_RBUTTONUP) - { - ShowCustomizeMenu(); - } - else - { - if (mouseEvent->Message == WM_LBUTTONDBLCLK && mouseEvent->Index < mouseEvent->TotalCount) - { - record = PhSipReferenceMaxIoRecord(mouseEvent->Index); - } - - if (record) - { - PhShowProcessRecordDialog(PhMainWndHandle, record); - PhDereferenceProcessRecord(record); - } - } - } - } - break; - } +/* + * Process Hacker ToolStatus - + * Toolbar Graph Bands + * + * Copyright (C) 2015-2016 dmex + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include "toolstatus.h" + +HWND CpuGraphHandle = NULL; +HWND MemGraphHandle = NULL; +HWND CommitGraphHandle = NULL; +HWND IoGraphHandle = NULL; +static PH_GRAPH_STATE CpuGraphState; +static PH_GRAPH_STATE MemGraphState; +static PH_GRAPH_STATE CommitGraphState; +static PH_GRAPH_STATE IoGraphState; + +VOID ToolbarCreateGraphs(VOID) +{ + UINT height = (UINT)SendMessage(RebarHandle, RB_GETROWHEIGHT, 0, 0); + + if (ToolStatusConfig.CpuGraphEnabled && !CpuGraphHandle) + { + CpuGraphHandle = CreateWindow( + PH_GRAPH_CLASSNAME, + NULL, + WS_VISIBLE | WS_CHILD | WS_BORDER, + 0, + 0, + 0, + 0, + PhMainWndHandle, + NULL, + NULL, + NULL + ); + Graph_SetTooltip(CpuGraphHandle, TRUE); + + PhInitializeGraphState(&CpuGraphState); + } + + if (ToolStatusConfig.MemGraphEnabled && !MemGraphHandle) + { + MemGraphHandle = CreateWindow( + PH_GRAPH_CLASSNAME, + NULL, + WS_VISIBLE | WS_CHILD | WS_BORDER, + 0, + 0, + 0, + 0, + PhMainWndHandle, + NULL, + NULL, + NULL + ); + Graph_SetTooltip(MemGraphHandle, TRUE); + + PhInitializeGraphState(&MemGraphState); + } + + if (ToolStatusConfig.CommitGraphEnabled && !CommitGraphHandle) + { + CommitGraphHandle = CreateWindow( + PH_GRAPH_CLASSNAME, + NULL, + WS_VISIBLE | WS_CHILD | WS_BORDER, + 0, + 0, + 0, + 0, + PhMainWndHandle, + NULL, + NULL, + NULL + ); + Graph_SetTooltip(CommitGraphHandle, TRUE); + + PhInitializeGraphState(&CommitGraphState); + } + + if (ToolStatusConfig.IoGraphEnabled && !IoGraphHandle) + { + IoGraphHandle = CreateWindow( + PH_GRAPH_CLASSNAME, + NULL, + WS_VISIBLE | WS_CHILD | WS_BORDER, + 0, + 0, + 0, + 0, + PhMainWndHandle, + NULL, + NULL, + NULL + ); + Graph_SetTooltip(IoGraphHandle, TRUE); + + PhInitializeGraphState(&IoGraphState); + } + + if (ToolStatusConfig.CpuGraphEnabled) + { + if (!RebarBandExists(REBAR_BAND_ID_CPUGRAPH)) + RebarBandInsert(REBAR_BAND_ID_CPUGRAPH, CpuGraphHandle, 145, height); // 85 + + if (CpuGraphHandle && !IsWindowVisible(CpuGraphHandle)) + ShowWindow(CpuGraphHandle, SW_SHOW); + } + else + { + if (RebarBandExists(REBAR_BAND_ID_CPUGRAPH)) + RebarBandRemove(REBAR_BAND_ID_CPUGRAPH); + + if (CpuGraphHandle) + { + PhDeleteGraphState(&CpuGraphState); + + DestroyWindow(CpuGraphHandle); + CpuGraphHandle = NULL; + } + } + + if (ToolStatusConfig.MemGraphEnabled) + { + if (!RebarBandExists(REBAR_BAND_ID_MEMGRAPH)) + RebarBandInsert(REBAR_BAND_ID_MEMGRAPH, MemGraphHandle, 145, height); // 85 + + if (MemGraphHandle && !IsWindowVisible(MemGraphHandle)) + { + ShowWindow(MemGraphHandle, SW_SHOW); + } + } + else + { + if (RebarBandExists(REBAR_BAND_ID_MEMGRAPH)) + RebarBandRemove(REBAR_BAND_ID_MEMGRAPH); + + if (MemGraphHandle) + { + PhDeleteGraphState(&MemGraphState); + + DestroyWindow(MemGraphHandle); + MemGraphHandle = NULL; + } + } + + if (ToolStatusConfig.CommitGraphEnabled) + { + if (!RebarBandExists(REBAR_BAND_ID_COMMITGRAPH)) + RebarBandInsert(REBAR_BAND_ID_COMMITGRAPH, CommitGraphHandle, 145, height); // 85 + + if (CommitGraphHandle && !IsWindowVisible(CommitGraphHandle)) + { + ShowWindow(CommitGraphHandle, SW_SHOW); + } + } + else + { + if (RebarBandExists(REBAR_BAND_ID_COMMITGRAPH)) + RebarBandRemove(REBAR_BAND_ID_COMMITGRAPH); + + if (CommitGraphHandle) + { + PhDeleteGraphState(&CommitGraphState); + + DestroyWindow(CommitGraphHandle); + CommitGraphHandle = NULL; + } + } + + if (ToolStatusConfig.IoGraphEnabled) + { + if (!RebarBandExists(REBAR_BAND_ID_IOGRAPH)) + RebarBandInsert(REBAR_BAND_ID_IOGRAPH, IoGraphHandle, 145, height); // 85 + + if (IoGraphHandle && !IsWindowVisible(IoGraphHandle)) + { + ShowWindow(IoGraphHandle, SW_SHOW); + } + } + else + { + if (RebarBandExists(REBAR_BAND_ID_IOGRAPH)) + RebarBandRemove(REBAR_BAND_ID_IOGRAPH); + + if (IoGraphHandle) + { + PhDeleteGraphState(&IoGraphState); + + DestroyWindow(IoGraphHandle); + IoGraphHandle = NULL; + } + } +} + +VOID ToolbarUpdateGraphs(VOID) +{ + if (ToolStatusConfig.CpuGraphEnabled && CpuGraphHandle) + { + CpuGraphState.Valid = FALSE; + CpuGraphState.TooltipIndex = -1; + Graph_MoveGrid(CpuGraphHandle, 1); + Graph_Draw(CpuGraphHandle); + Graph_UpdateTooltip(CpuGraphHandle); + InvalidateRect(CpuGraphHandle, NULL, FALSE); + } + + if (ToolStatusConfig.MemGraphEnabled && MemGraphHandle) + { + MemGraphState.Valid = FALSE; + MemGraphState.TooltipIndex = -1; + Graph_MoveGrid(MemGraphHandle, 1); + Graph_Draw(MemGraphHandle); + Graph_UpdateTooltip(MemGraphHandle); + InvalidateRect(MemGraphHandle, NULL, FALSE); + } + + if (ToolStatusConfig.CommitGraphEnabled && CommitGraphHandle) + { + CommitGraphState.Valid = FALSE; + CommitGraphState.TooltipIndex = -1; + Graph_MoveGrid(CommitGraphHandle, 1); + Graph_Draw(CommitGraphHandle); + Graph_UpdateTooltip(CommitGraphHandle); + InvalidateRect(CommitGraphHandle, NULL, FALSE); + } + + if (ToolStatusConfig.IoGraphEnabled && IoGraphHandle) + { + IoGraphState.Valid = FALSE; + IoGraphState.TooltipIndex = -1; + Graph_MoveGrid(IoGraphHandle, 1); + Graph_Draw(IoGraphHandle); + Graph_UpdateTooltip(IoGraphHandle); + InvalidateRect(IoGraphHandle, NULL, FALSE); + } +} + +// +// BEGIN copied from ProcessHacker/sysinfo.c +// + +static PPH_PROCESS_RECORD PhSipReferenceMaxCpuRecord( + _In_ LONG Index + ) +{ + LARGE_INTEGER time; + LONG maxProcessIdLong; + HANDLE maxProcessId; + + // Find the process record for the max. CPU process for the particular time. + + maxProcessIdLong = PhGetItemCircularBuffer_ULONG(SystemStatistics.MaxCpuHistory, Index); + + if (!maxProcessIdLong) + return NULL; + + // This must be treated as a signed integer to handle Interrupts correctly. + maxProcessId = LongToHandle(maxProcessIdLong); + + // Note that the time we get has its components beyond seconds cleared. + // For example: + // * At 2.5 seconds a process is started. + // * At 2.75 seconds our process provider is fired, and the process is determined + // to have 75% CPU usage, which happens to be the maximum CPU usage. + // * However the 2.75 seconds is recorded as 2 seconds due to + // RtlTimeToSecondsSince1980. + // * If we call PhFindProcessRecord, it cannot find the process because it was + // started at 2.5 seconds, not 2 seconds or older. + // + // This mean we must add one second minus one tick (100ns) to the time, giving us + // 2.9999999 seconds. This will then make sure we find the process. + PhGetStatisticsTime(NULL, Index, &time); + time.QuadPart += PH_TICKS_PER_SEC - 1; + + return PhFindProcessRecord(maxProcessId, &time); +} + +static PPH_STRING PhSipGetMaxCpuString( + _In_ LONG Index + ) +{ + PPH_PROCESS_RECORD maxProcessRecord; + FLOAT maxCpuUsage; + PPH_STRING maxUsageString = NULL; + + if (maxProcessRecord = PhSipReferenceMaxCpuRecord(Index)) + { + // We found the process record, so now we construct the max. usage string. + maxCpuUsage = PhGetItemCircularBuffer_FLOAT(SystemStatistics.MaxCpuUsageHistory, Index); + + // Make sure we don't try to display the PID of DPCs or Interrupts. + if (!PH_IS_FAKE_PROCESS_ID(maxProcessRecord->ProcessId)) + { + maxUsageString = PhaFormatString( + L"\n%s (%u): %.2f%%", + maxProcessRecord->ProcessName->Buffer, + HandleToUlong(maxProcessRecord->ProcessId), + maxCpuUsage * 100 + ); + } + else + { + maxUsageString = PhaFormatString( + L"\n%s: %.2f%%", + maxProcessRecord->ProcessName->Buffer, + maxCpuUsage * 100 + ); + } + + PhDereferenceProcessRecord(maxProcessRecord); + } + + return maxUsageString; +} + +static PPH_PROCESS_RECORD PhSipReferenceMaxIoRecord( + _In_ LONG Index + ) +{ + LARGE_INTEGER time; + ULONG maxProcessId; + + // Find the process record for the max. I/O process for the particular time. + + maxProcessId = PhGetItemCircularBuffer_ULONG(SystemStatistics.MaxIoHistory, Index); + + if (!maxProcessId) + return NULL; + + // See above for the explanation. + PhGetStatisticsTime(NULL, Index, &time); + time.QuadPart += PH_TICKS_PER_SEC - 1; + + return PhFindProcessRecord(UlongToHandle(maxProcessId), &time); +} + +static PPH_STRING PhSipGetMaxIoString( + _In_ LONG Index + ) +{ + PPH_PROCESS_RECORD maxProcessRecord; + ULONG64 maxIoReadOther; + ULONG64 maxIoWrite; + + PPH_STRING maxUsageString = NULL; + + if (maxProcessRecord = PhSipReferenceMaxIoRecord(Index)) + { + // We found the process record, so now we construct the max. usage string. + maxIoReadOther = PhGetItemCircularBuffer_ULONG64(SystemStatistics.MaxIoReadOtherHistory, Index); + maxIoWrite = PhGetItemCircularBuffer_ULONG64(SystemStatistics.MaxIoWriteHistory, Index); + + if (!PH_IS_FAKE_PROCESS_ID(maxProcessRecord->ProcessId)) + { + maxUsageString = PhaFormatString( + L"\n%s (%u): R+O: %s, W: %s", + maxProcessRecord->ProcessName->Buffer, + HandleToUlong(maxProcessRecord->ProcessId), + PhaFormatSize(maxIoReadOther, -1)->Buffer, + PhaFormatSize(maxIoWrite, -1)->Buffer + ); + } + else + { + maxUsageString = PhaFormatString( + L"\n%s: R+O: %s, W: %s", + maxProcessRecord->ProcessName->Buffer, + PhaFormatSize(maxIoReadOther, -1)->Buffer, + PhaFormatSize(maxIoWrite, -1)->Buffer + ); + } + + PhDereferenceProcessRecord(maxProcessRecord); + } + + return maxUsageString; +} + +// +// END copied from ProcessHacker/sysinfo.c +// + +VOID ToolbarUpdateGraphsInfo(LPNMHDR Header) +{ + switch (Header->code) + { + case GCN_GETDRAWINFO: + { + if (ToolStatusConfig.CpuGraphEnabled && Header->hwndFrom == CpuGraphHandle) + { + PPH_GRAPH_GETDRAWINFO getDrawInfo = (PPH_GRAPH_GETDRAWINFO)Header; + PPH_GRAPH_DRAW_INFO drawInfo = getDrawInfo->DrawInfo; + + drawInfo->Flags = PH_GRAPH_USE_GRID_X | PH_GRAPH_USE_LINE_2; + PhSiSetColorsGraphDrawInfo(drawInfo, PhGetIntegerSetting(L"ColorCpuKernel"), PhGetIntegerSetting(L"ColorCpuUser")); + + if (ProcessesUpdatedCount < 2) + return; + + PhGraphStateGetDrawInfo(&CpuGraphState, getDrawInfo, SystemStatistics.CpuUserHistory->Count); + + if (!CpuGraphState.Valid) + { + PhCopyCircularBuffer_FLOAT(SystemStatistics.CpuKernelHistory, + CpuGraphState.Data1, drawInfo->LineDataCount); + PhCopyCircularBuffer_FLOAT(SystemStatistics.CpuUserHistory, + CpuGraphState.Data2, drawInfo->LineDataCount); + + CpuGraphState.Valid = TRUE; + } + } + else if (ToolStatusConfig.MemGraphEnabled && Header->hwndFrom == MemGraphHandle) + { + PPH_GRAPH_GETDRAWINFO getDrawInfo = (PPH_GRAPH_GETDRAWINFO)Header; + PPH_GRAPH_DRAW_INFO drawInfo = getDrawInfo->DrawInfo; + + drawInfo->Flags = PH_GRAPH_USE_GRID_X; + PhSiSetColorsGraphDrawInfo(drawInfo, PhGetIntegerSetting(L"ColorPhysical"), 0); + + if (ProcessesUpdatedCount < 2) + return; + + PhGraphStateGetDrawInfo(&MemGraphState, getDrawInfo, SystemStatistics.PhysicalHistory->Count); + + if (!MemGraphState.Valid) + { + for (ULONG i = 0; i < drawInfo->LineDataCount; i++) + { + MemGraphState.Data1[i] = (FLOAT)PhGetItemCircularBuffer_ULONG(SystemStatistics.PhysicalHistory, i); + } + + PhDivideSinglesBySingle( + MemGraphState.Data1, + (FLOAT)PhSystemBasicInformation.NumberOfPhysicalPages, + drawInfo->LineDataCount + ); + + MemGraphState.Valid = TRUE; + } + } + else if (ToolStatusConfig.CommitGraphEnabled && Header->hwndFrom == CommitGraphHandle) + { + PPH_GRAPH_GETDRAWINFO getDrawInfo = (PPH_GRAPH_GETDRAWINFO)Header; + PPH_GRAPH_DRAW_INFO drawInfo = getDrawInfo->DrawInfo; + + drawInfo->Flags = PH_GRAPH_USE_GRID_X; + PhSiSetColorsGraphDrawInfo(drawInfo, PhGetIntegerSetting(L"ColorPrivate"), 0); + + if (ProcessesUpdatedCount < 2) + return; + + PhGraphStateGetDrawInfo(&CommitGraphState, getDrawInfo, SystemStatistics.CommitHistory->Count); + + if (!CommitGraphState.Valid) + { + for (ULONG i = 0; i < drawInfo->LineDataCount; i++) + { + CommitGraphState.Data1[i] = (FLOAT)PhGetItemCircularBuffer_ULONG(SystemStatistics.CommitHistory, i); + } + + PhDivideSinglesBySingle( + CommitGraphState.Data1, + (FLOAT)SystemStatistics.Performance->CommitLimit, + drawInfo->LineDataCount + ); + + CommitGraphState.Valid = TRUE; + } + } + else if (ToolStatusConfig.IoGraphEnabled && Header->hwndFrom == IoGraphHandle) + { + PPH_GRAPH_GETDRAWINFO getDrawInfo = (PPH_GRAPH_GETDRAWINFO)Header; + PPH_GRAPH_DRAW_INFO drawInfo = getDrawInfo->DrawInfo; + + drawInfo->Flags = PH_GRAPH_USE_GRID_X | PH_GRAPH_USE_LINE_2; + PhSiSetColorsGraphDrawInfo(drawInfo, PhGetIntegerSetting(L"ColorIoReadOther"), PhGetIntegerSetting(L"ColorIoWrite")); + + if (ProcessesUpdatedCount < 2) + return; + + PhGraphStateGetDrawInfo(&IoGraphState, getDrawInfo, SystemStatistics.IoReadHistory->Count); + + if (!IoGraphState.Valid) + { + FLOAT max = 1024 * 1024; // minimum scaling of 1 MB. + + for (ULONG i = 0; i < drawInfo->LineDataCount; i++) + { + IoGraphState.Data1[i] = + (FLOAT)PhGetItemCircularBuffer_ULONG64(SystemStatistics.IoReadHistory, i) + + (FLOAT)PhGetItemCircularBuffer_ULONG64(SystemStatistics.IoOtherHistory, i); + IoGraphState.Data2[i] = + (FLOAT)PhGetItemCircularBuffer_ULONG64(SystemStatistics.IoWriteHistory, i); + + if (max < IoGraphState.Data1[i] + IoGraphState.Data2[i]) + max = IoGraphState.Data1[i] + IoGraphState.Data2[i]; + } + + PhDivideSinglesBySingle(IoGraphState.Data1, max, drawInfo->LineDataCount); + PhDivideSinglesBySingle(IoGraphState.Data2, max, drawInfo->LineDataCount); + + IoGraphState.Valid = TRUE; + } + } + } + break; + case GCN_GETTOOLTIPTEXT: + { + PPH_GRAPH_GETTOOLTIPTEXT getTooltipText = (PPH_GRAPH_GETTOOLTIPTEXT)Header; + + if (getTooltipText->Index < getTooltipText->TotalCount) + { + if (ToolStatusConfig.CpuGraphEnabled && Header->hwndFrom == CpuGraphHandle) + { + if (CpuGraphState.TooltipIndex != getTooltipText->Index) + { + FLOAT cpuKernel; + FLOAT cpuUser; + + cpuKernel = PhGetItemCircularBuffer_FLOAT(SystemStatistics.CpuKernelHistory, getTooltipText->Index); + cpuUser = PhGetItemCircularBuffer_FLOAT(SystemStatistics.CpuUserHistory, getTooltipText->Index); + + PhMoveReference(&CpuGraphState.TooltipText, PhFormatString( + L"%.2f%%%s\n%s", + (cpuKernel + cpuUser) * 100, + PhGetStringOrEmpty(PhSipGetMaxCpuString(getTooltipText->Index)), + PH_AUTO_T(PH_STRING, PhGetStatisticsTimeString(NULL, getTooltipText->Index))->Buffer + )); + } + + getTooltipText->Text = CpuGraphState.TooltipText->sr; + } + else if (ToolStatusConfig.MemGraphEnabled && Header->hwndFrom == MemGraphHandle) + { + ULONG physicalUsage; + + physicalUsage = PhGetItemCircularBuffer_ULONG(SystemStatistics.PhysicalHistory, getTooltipText->Index); + + PhMoveReference(&MemGraphState.TooltipText, PhFormatString( + L"Physical memory: %s\n%s", + PhaFormatSize(UInt32x32To64(physicalUsage, PAGE_SIZE), -1)->Buffer, + PH_AUTO_T(PH_STRING, PhGetStatisticsTimeString(NULL, getTooltipText->Index))->Buffer + )); + getTooltipText->Text = MemGraphState.TooltipText->sr; + } + else if (ToolStatusConfig.CommitGraphEnabled && Header->hwndFrom == CommitGraphHandle) + { + ULONG commitUsage; + + commitUsage = PhGetItemCircularBuffer_ULONG(SystemStatistics.CommitHistory, getTooltipText->Index); + + PhMoveReference(&CommitGraphState.TooltipText, PhFormatString( + L"Commit charge: %s\n%s", + PhaFormatSize(UInt32x32To64(commitUsage, PAGE_SIZE), -1)->Buffer, + PH_AUTO_T(PH_STRING, PhGetStatisticsTimeString(NULL, getTooltipText->Index))->Buffer + )); + getTooltipText->Text = CommitGraphState.TooltipText->sr; + } + else if (ToolStatusConfig.IoGraphEnabled && Header->hwndFrom == IoGraphHandle) + { + ULONG64 ioRead; + ULONG64 ioWrite; + ULONG64 ioOther; + + ioRead = PhGetItemCircularBuffer_ULONG64(SystemStatistics.IoReadHistory, getTooltipText->Index); + ioWrite = PhGetItemCircularBuffer_ULONG64(SystemStatistics.IoWriteHistory, getTooltipText->Index); + ioOther = PhGetItemCircularBuffer_ULONG64(SystemStatistics.IoOtherHistory, getTooltipText->Index); + + PhMoveReference(&IoGraphState.TooltipText, PhFormatString( + L"R: %s\nW: %s\nO: %s%s\n%s", + PhaFormatSize(ioRead, -1)->Buffer, + PhaFormatSize(ioWrite, -1)->Buffer, + PhaFormatSize(ioOther, -1)->Buffer, + PhGetStringOrEmpty(PhSipGetMaxIoString(getTooltipText->Index)), + PH_AUTO_T(PH_STRING, PhGetStatisticsTimeString(NULL, getTooltipText->Index))->Buffer + )); + getTooltipText->Text = IoGraphState.TooltipText->sr; + } + } + } + break; + case GCN_MOUSEEVENT: + { + PPH_GRAPH_MOUSEEVENT mouseEvent = (PPH_GRAPH_MOUSEEVENT)Header; + PPH_PROCESS_RECORD record = NULL; + + if (ToolStatusConfig.CpuGraphEnabled && Header->hwndFrom == CpuGraphHandle) + { + if (mouseEvent->Message == WM_RBUTTONUP) + { + ShowCustomizeMenu(); + } + else + { + if (mouseEvent->Message == WM_LBUTTONDBLCLK && mouseEvent->Index < mouseEvent->TotalCount) + { + record = PhSipReferenceMaxCpuRecord(mouseEvent->Index); + } + + if (record) + { + PhShowProcessRecordDialog(PhMainWndHandle, record); + PhDereferenceProcessRecord(record); + } + } + } + else if (ToolStatusConfig.MemGraphEnabled && Header->hwndFrom == MemGraphHandle) + { + if (mouseEvent->Message == WM_RBUTTONUP) + { + ShowCustomizeMenu(); + } + } + else if (ToolStatusConfig.CommitGraphEnabled && Header->hwndFrom == CommitGraphHandle) + { + if (mouseEvent->Message == WM_RBUTTONUP) + { + ShowCustomizeMenu(); + } + } + else if (ToolStatusConfig.IoGraphEnabled && Header->hwndFrom == IoGraphHandle) + { + if (mouseEvent->Message == WM_RBUTTONUP) + { + ShowCustomizeMenu(); + } + else + { + if (mouseEvent->Message == WM_LBUTTONDBLCLK && mouseEvent->Index < mouseEvent->TotalCount) + { + record = PhSipReferenceMaxIoRecord(mouseEvent->Index); + } + + if (record) + { + PhShowProcessRecordDialog(PhMainWndHandle, record); + PhDereferenceProcessRecord(record); + } + } + } + } + break; + } } \ No newline at end of file diff --git a/plugins/ToolStatus/main.c b/plugins/ToolStatus/main.c index 6f3c1f8c530d..8bd024e7203a 100644 --- a/plugins/ToolStatus/main.c +++ b/plugins/ToolStatus/main.c @@ -1,1445 +1,1445 @@ -/* - * Process Hacker ToolStatus - - * main program - * - * Copyright (C) 2011-2016 dmex - * Copyright (C) 2010-2016 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include "toolstatus.h" - -PPH_STRING GetSearchboxText( - VOID - ); - -VOID RegisterTabSearch( - _In_ INT TabIndex, - _In_ PWSTR BannerText - ); - -PTOOLSTATUS_TAB_INFO RegisterTabInfo( - _In_ INT TabIndex - ); - -TOOLSTATUS_CONFIG ToolStatusConfig = { 0 }; -HWND ProcessTreeNewHandle = NULL; -HWND ServiceTreeNewHandle = NULL; -HWND NetworkTreeNewHandle = NULL; -INT SelectedTabIndex; -BOOLEAN UpdateAutomatically = TRUE; -BOOLEAN UpdateGraphs = TRUE; -TOOLBAR_DISPLAY_STYLE DisplayStyle = TOOLBAR_DISPLAY_STYLE_SELECTIVETEXT; -SEARCHBOX_DISPLAY_MODE SearchBoxDisplayMode = SEARCHBOX_DISPLAY_MODE_ALWAYSSHOW; -REBAR_DISPLAY_LOCATION RebarDisplayLocation = REBAR_DISPLAY_LOCATION_TOP; -HWND RebarHandle = NULL; -HWND ToolBarHandle = NULL; -HWND SearchboxHandle = NULL; -HMENU MainMenu = NULL; -HACCEL AcceleratorTable = NULL; -PPH_STRING SearchboxText = NULL; -PH_PLUGIN_SYSTEM_STATISTICS SystemStatistics = { 0 }; -PH_CALLBACK_DECLARE(SearchChangedEvent); -PPH_HASHTABLE TabInfoHashtable; -PPH_TN_FILTER_ENTRY ProcessTreeFilterEntry = NULL; -PPH_TN_FILTER_ENTRY ServiceTreeFilterEntry = NULL; -PPH_TN_FILTER_ENTRY NetworkTreeFilterEntry = NULL; -PPH_PLUGIN PluginInstance = NULL; -TOOLSTATUS_INTERFACE PluginInterface = -{ - TOOLSTATUS_INTERFACE_VERSION, - GetSearchboxText, - WordMatchStringRef, - RegisterTabSearch, - &SearchChangedEvent, - RegisterTabInfo -}; - -static ULONG TargetingMode = 0; -static BOOLEAN TargetingWindow = FALSE; -static BOOLEAN TargetingCurrentWindowDraw = FALSE; -static BOOLEAN TargetingCompleted = FALSE; -static HWND TargetingCurrentWindow = NULL; -static PH_CALLBACK_REGISTRATION PluginLoadCallbackRegistration; -static PH_CALLBACK_REGISTRATION PluginShowOptionsCallbackRegistration; -static PH_CALLBACK_REGISTRATION MainWindowShowingCallbackRegistration; -static PH_CALLBACK_REGISTRATION ProcessesUpdatedCallbackRegistration; -static PH_CALLBACK_REGISTRATION LayoutPaddingCallbackRegistration; -static PH_CALLBACK_REGISTRATION TabPageCallbackRegistration; -static PH_CALLBACK_REGISTRATION ProcessTreeNewInitializingCallbackRegistration; -static PH_CALLBACK_REGISTRATION ServiceTreeNewInitializingCallbackRegistration; -static PH_CALLBACK_REGISTRATION NetworkTreeNewInitializingCallbackRegistration; - -PPH_STRING GetSearchboxText( - VOID - ) -{ - return SearchboxText; -} - -VOID NTAPI ProcessesUpdatedCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - ProcessesUpdatedCount++; - - if (ProcessesUpdatedCount < 2) - return; - - PhPluginGetSystemStatistics(&SystemStatistics); - - if (UpdateGraphs) - ToolbarUpdateGraphs(); - - if (ToolStatusConfig.StatusBarEnabled) - StatusBarUpdate(FALSE); -} - -VOID NTAPI TreeNewInitializingCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - *(HWND *)Context = ((PPH_PLUGIN_TREENEW_INFORMATION)Parameter)->TreeNewHandle; -} - -VOID RegisterTabSearch( - _In_ INT TabIndex, - _In_ PWSTR BannerText - ) -{ - PTOOLSTATUS_TAB_INFO tabInfo; - - tabInfo = RegisterTabInfo(TabIndex); - tabInfo->BannerText = BannerText; -} - -PTOOLSTATUS_TAB_INFO RegisterTabInfo( - _In_ INT TabIndex - ) -{ - PTOOLSTATUS_TAB_INFO tabInfoCopy; - PVOID *entry; - - tabInfoCopy = PhCreateAlloc(sizeof(TOOLSTATUS_TAB_INFO)); - memset(tabInfoCopy, 0, sizeof(TOOLSTATUS_TAB_INFO)); - - if (!PhAddItemSimpleHashtable(TabInfoHashtable, IntToPtr(TabIndex), tabInfoCopy)) - { - PhClearReference(&tabInfoCopy); - - if (entry = PhFindItemSimpleHashtable(TabInfoHashtable, IntToPtr(TabIndex))) - tabInfoCopy = *entry; - } - - return tabInfoCopy; -} - -PTOOLSTATUS_TAB_INFO FindTabInfo( - _In_ INT TabIndex - ) -{ - PVOID *entry; - - if (entry = PhFindItemSimpleHashtable(TabInfoHashtable, IntToPtr(TabIndex))) - return *entry; - - return NULL; -} - -HWND GetCurrentTreeNewHandle( - VOID - ) -{ - HWND treeNewHandle = NULL; - - switch (SelectedTabIndex) - { - case 0: - treeNewHandle = ProcessTreeNewHandle; - break; - case 1: - treeNewHandle = ServiceTreeNewHandle; - break; - case 2: - treeNewHandle = NetworkTreeNewHandle; - break; - default: - { - PTOOLSTATUS_TAB_INFO tabInfo; - - if ((tabInfo = FindTabInfo(SelectedTabIndex)) && tabInfo->GetTreeNewHandle) - { - treeNewHandle = tabInfo->GetTreeNewHandle(); - } - } - break; - } - - return treeNewHandle; -} - -VOID ShowCustomizeMenu( - VOID - ) -{ - POINT cursorPos; - PPH_EMENU menu; - PPH_EMENU_ITEM selectedItem; - - GetCursorPos(&cursorPos); - - menu = PhCreateEMenu(); - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, COMMAND_ID_ENABLE_MENU, L"Main menu (auto-hide)", NULL, NULL), -1); - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, COMMAND_ID_ENABLE_SEARCHBOX, L"Search box", NULL, NULL), -1); - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, COMMAND_ID_ENABLE_CPU_GRAPH, L"CPU history", NULL, NULL), -1); - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, COMMAND_ID_ENABLE_IO_GRAPH, L"I/O history", NULL, NULL), -1); - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, COMMAND_ID_ENABLE_MEMORY_GRAPH, L"Physical memory history", NULL, NULL), -1); - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, COMMAND_ID_ENABLE_COMMIT_GRAPH, L"Commit charge history", NULL, NULL), -1); - PhInsertEMenuItem(menu, PhCreateEMenuItem(PH_EMENU_SEPARATOR, 0, NULL, NULL, NULL), -1); - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, COMMAND_ID_TOOLBAR_LOCKUNLOCK, L"Lock the toolbar", NULL, NULL), -1); - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, COMMAND_ID_TOOLBAR_CUSTOMIZE, L"Customize...", NULL, NULL), -1); - - if (ToolStatusConfig.AutoHideMenu) - { - PhSetFlagsEMenuItem(menu, COMMAND_ID_ENABLE_MENU, PH_EMENU_CHECKED, PH_EMENU_CHECKED); - } - - if (ToolStatusConfig.SearchBoxEnabled) - { - PhSetFlagsEMenuItem(menu, COMMAND_ID_ENABLE_SEARCHBOX, PH_EMENU_CHECKED, PH_EMENU_CHECKED); - } - - if (ToolStatusConfig.CpuGraphEnabled) - { - PhSetFlagsEMenuItem(menu, COMMAND_ID_ENABLE_CPU_GRAPH, PH_EMENU_CHECKED, PH_EMENU_CHECKED); - } - - if (ToolStatusConfig.MemGraphEnabled) - { - PhSetFlagsEMenuItem(menu, COMMAND_ID_ENABLE_MEMORY_GRAPH, PH_EMENU_CHECKED, PH_EMENU_CHECKED); - } - - if (ToolStatusConfig.CommitGraphEnabled) - { - PhSetFlagsEMenuItem(menu, COMMAND_ID_ENABLE_COMMIT_GRAPH, PH_EMENU_CHECKED, PH_EMENU_CHECKED); - } - - if (ToolStatusConfig.IoGraphEnabled) - { - PhSetFlagsEMenuItem(menu, COMMAND_ID_ENABLE_IO_GRAPH, PH_EMENU_CHECKED, PH_EMENU_CHECKED); - } - - if (ToolStatusConfig.ToolBarLocked) - { - PhSetFlagsEMenuItem(menu, COMMAND_ID_TOOLBAR_LOCKUNLOCK, PH_EMENU_CHECKED, PH_EMENU_CHECKED); - } - - selectedItem = PhShowEMenu( - menu, - PhMainWndHandle, - PH_EMENU_SHOW_LEFTRIGHT, - PH_ALIGN_LEFT | PH_ALIGN_TOP, - cursorPos.x, - cursorPos.y - ); - - if (selectedItem && selectedItem->Id != -1) - { - switch (selectedItem->Id) - { - case COMMAND_ID_ENABLE_MENU: - { - ToolStatusConfig.AutoHideMenu = !ToolStatusConfig.AutoHideMenu; - - PhSetIntegerSetting(SETTING_NAME_TOOLSTATUS_CONFIG, ToolStatusConfig.Flags); - - if (ToolStatusConfig.AutoHideMenu) - { - SetMenu(PhMainWndHandle, NULL); - } - else - { - SetMenu(PhMainWndHandle, MainMenu); - DrawMenuBar(PhMainWndHandle); - } - } - break; - case COMMAND_ID_ENABLE_SEARCHBOX: - { - ToolStatusConfig.SearchBoxEnabled = !ToolStatusConfig.SearchBoxEnabled; - - PhSetIntegerSetting(SETTING_NAME_TOOLSTATUS_CONFIG, ToolStatusConfig.Flags); - - ToolbarLoadSettings(); - ReBarSaveLayoutSettings(); - - if (ToolStatusConfig.SearchBoxEnabled) - { - // Adding the Searchbox makes it focused, - // reset the focus back to the main window. - SetFocus(PhMainWndHandle); - } - } - break; - case COMMAND_ID_ENABLE_CPU_GRAPH: - { - ToolStatusConfig.CpuGraphEnabled = !ToolStatusConfig.CpuGraphEnabled; - - PhSetIntegerSetting(SETTING_NAME_TOOLSTATUS_CONFIG, ToolStatusConfig.Flags); - - ToolbarLoadSettings(); - ReBarSaveLayoutSettings(); - } - break; - case COMMAND_ID_ENABLE_MEMORY_GRAPH: - { - ToolStatusConfig.MemGraphEnabled = !ToolStatusConfig.MemGraphEnabled; - - PhSetIntegerSetting(SETTING_NAME_TOOLSTATUS_CONFIG, ToolStatusConfig.Flags); - - ToolbarLoadSettings(); - ReBarSaveLayoutSettings(); - } - break; - case COMMAND_ID_ENABLE_COMMIT_GRAPH: - { - ToolStatusConfig.CommitGraphEnabled = !ToolStatusConfig.CommitGraphEnabled; - - PhSetIntegerSetting(SETTING_NAME_TOOLSTATUS_CONFIG, ToolStatusConfig.Flags); - - ToolbarLoadSettings(); - ReBarSaveLayoutSettings(); - } - break; - case COMMAND_ID_ENABLE_IO_GRAPH: - { - ToolStatusConfig.IoGraphEnabled = !ToolStatusConfig.IoGraphEnabled; - - PhSetIntegerSetting(SETTING_NAME_TOOLSTATUS_CONFIG, ToolStatusConfig.Flags); - - ToolbarLoadSettings(); - ReBarSaveLayoutSettings(); - } - break; - case COMMAND_ID_TOOLBAR_LOCKUNLOCK: - { - UINT bandCount; - UINT bandIndex; - - bandCount = (UINT)SendMessage(RebarHandle, RB_GETBANDCOUNT, 0, 0); - - for (bandIndex = 0; bandIndex < bandCount; bandIndex++) - { - REBARBANDINFO rebarBandInfo = - { - sizeof(REBARBANDINFO), - RBBIM_STYLE - }; - - SendMessage(RebarHandle, RB_GETBANDINFO, bandIndex, (LPARAM)&rebarBandInfo); - - if (!(rebarBandInfo.fStyle & RBBS_GRIPPERALWAYS)) - { - // Removing the RBBS_NOGRIPPER style doesn't remove the gripper padding, - // So we toggle the RBBS_GRIPPERALWAYS style to make the Toolbar remove the padding. - - rebarBandInfo.fStyle |= RBBS_GRIPPERALWAYS; - - SendMessage(RebarHandle, RB_SETBANDINFO, bandIndex, (LPARAM)&rebarBandInfo); - - rebarBandInfo.fStyle &= ~RBBS_GRIPPERALWAYS; - } - - if (rebarBandInfo.fStyle & RBBS_NOGRIPPER) - { - rebarBandInfo.fStyle &= ~RBBS_NOGRIPPER; - } - else - { - rebarBandInfo.fStyle |= RBBS_NOGRIPPER; - } - - SendMessage(RebarHandle, RB_SETBANDINFO, bandIndex, (LPARAM)&rebarBandInfo); - } - - ToolStatusConfig.ToolBarLocked = !ToolStatusConfig.ToolBarLocked; - - PhSetIntegerSetting(SETTING_NAME_TOOLSTATUS_CONFIG, ToolStatusConfig.Flags); - - ToolbarLoadSettings(); - } - break; - case COMMAND_ID_TOOLBAR_CUSTOMIZE: - { - ToolBarShowCustomizeDialog(); - } - break; - } - } - - PhDestroyEMenu(menu); -} - -VOID NTAPI TabPageUpdatedCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - INT tabIndex = PtrToInt(Parameter); - - SelectedTabIndex = tabIndex; - - if (!SearchboxHandle) - return; - - switch (tabIndex) - { - case 0: - Edit_SetCueBannerText(SearchboxHandle, L"Search Processes (Ctrl+K)"); - break; - case 1: - Edit_SetCueBannerText(SearchboxHandle, L"Search Services (Ctrl+K)"); - break; - case 2: - Edit_SetCueBannerText(SearchboxHandle, L"Search Network (Ctrl+K)"); - break; - default: - { - PTOOLSTATUS_TAB_INFO tabInfo; - - if ((tabInfo = FindTabInfo(tabIndex)) && tabInfo->BannerText) - { - Edit_SetCueBannerText(SearchboxHandle, PhaConcatStrings2(tabInfo->BannerText, L" (Ctrl+K)")->Buffer); - } - else - { - // Disable the textbox if we're on an unsupported tab. - Edit_SetCueBannerText(SearchboxHandle, L"Search disabled"); - } - } - break; - } -} - -VOID NTAPI LayoutPaddingCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - PPH_LAYOUT_PADDING_DATA layoutPadding = Parameter; - - if (RebarHandle && ToolStatusConfig.ToolBarEnabled) - { - RECT rebarRect; - //RECT clientRect; - //INT x, y, cx, cy; - - SendMessage(RebarHandle, WM_SIZE, 0, 0); - - // TODO: GetClientRect with PhMainWndHandle causes crash. - //GetClientRect(PhMainWndHandle, &clientRect); - GetClientRect(RebarHandle, &rebarRect); - - // Adjust the PH client area and exclude the rebar width. - layoutPadding->Padding.top += rebarRect.bottom; - - // TODO: Replace CCS_TOP with CCS_NOPARENTALIGN and use below code - //switch (RebarDisplayLocation) - //{ - //case RebarLocationLeft: - // { - // //x = 0; - // //y = 0; - // //cx = rebarRect.right - rebarRect.left; - // //cy = clientRect.bottom - clientRect.top; - // } - // break; - //case RebarLocationTop: - // { - // //x = 0; - // //y = 0; - // //cx = clientRect.right - clientRect.left; - // //cy = clientRect.bottom - clientRect.top; - // - // // Adjust the PH client area and exclude the rebar height. - // //layoutPadding->Padding.top += rebarRect.bottom; - // } - // break; - //case RebarLocationRight: - // { - // //x = clientRect.right - (rebarRect.right - rebarRect.left); - // //y = 0; - // //cx = rebarRect.right - rebarRect.left; - // //cy = clientRect.bottom - clientRect.top; - // } - // break; - //case RebarLocationBottom: - // { - // //x = 0; - // //y = clientRect.bottom - (rebarRect.bottom - rebarRect.top) - (StatusBarEnabled ? rebarRect.bottom + 1 : 0); - // //cx = clientRect.right - clientRect.left; - // //cy = rebarRect.bottom - rebarRect.top; - // - // // Adjust the PH client area and exclude the rebar width. - // //layoutPadding->Padding.bottom += rebarRect.bottom; - // } - // break; - //} - //MoveWindow(RebarHandle, x, y, cx, cy, TRUE); - - //if (SearchBoxDisplayStyle == SearchBoxDisplayAutoHide) - //{ - // static BOOLEAN isSearchboxVisible = FALSE; - // SIZE idealWidth; - // - // // Query the Toolbar ideal width - // SendMessage(ToolBarHandle, TB_GETIDEALSIZE, FALSE, (LPARAM)&idealWidth); - // - // // Hide the Searcbox band if the window size is too small... - // if (rebarRect.right > idealWidth.cx) - // { - // if (isSearchboxVisible) - // { - // if (!RebarBandExists(REBAR_BAND_ID_SEARCHBOX)) - // RebarBandInsert(REBAR_BAND_ID_SEARCHBOX, SearchboxHandle, 180, 20); - // - // isSearchboxVisible = FALSE; - // } - // } - // else - // { - // if (!isSearchboxVisible) - // { - // if (RebarBandExists(REBAR_BAND_ID_SEARCHBOX)) - // RebarBandRemove(REBAR_BAND_ID_SEARCHBOX); - // - // isSearchboxVisible = TRUE; - // } - // } - //} - } - - if (StatusBarHandle && ToolStatusConfig.StatusBarEnabled) - { - RECT statusBarRect; - - SendMessage(StatusBarHandle, WM_SIZE, 0, 0); - - GetClientRect(StatusBarHandle, &statusBarRect); - - // Adjust the PH client area and exclude the StatusBar width. - layoutPadding->Padding.bottom += statusBarRect.bottom; - - //InvalidateRect(StatusBarHandle, NULL, TRUE); - } -} - -BOOLEAN NTAPI MessageLoopFilter( - _In_ PMSG Message, - _In_ PVOID Context - ) -{ - if ( - Message->hwnd == PhMainWndHandle || - IsChild(PhMainWndHandle, Message->hwnd) - ) - { - if (TranslateAccelerator(PhMainWndHandle, AcceleratorTable, Message)) - return TRUE; - - if (Message->message == WM_SYSCHAR && ToolStatusConfig.AutoHideMenu && !GetMenu(PhMainWndHandle)) - { - ULONG key = (ULONG)Message->wParam; - - if (key == 'h' || key == 'v' || key == 't' || key == 'u' || key == 'e') - { - SetMenu(PhMainWndHandle, MainMenu); - DrawMenuBar(PhMainWndHandle); - SendMessage(PhMainWndHandle, WM_SYSCHAR, Message->wParam, Message->lParam); - return TRUE; - } - } - } - - return FALSE; -} - -VOID DrawWindowBorderForTargeting( - _In_ HWND hWnd - ) -{ - RECT rect; - HDC hdc; - - GetWindowRect(hWnd, &rect); - hdc = GetWindowDC(hWnd); - - if (hdc) - { - INT penWidth; - INT oldDc; - HPEN pen; - HBRUSH brush; - - penWidth = GetSystemMetrics(SM_CXBORDER) * 3; - oldDc = SaveDC(hdc); - - // Get an inversion effect. - SetROP2(hdc, R2_NOT); - - pen = CreatePen(PS_INSIDEFRAME, penWidth, RGB(0x00, 0x00, 0x00)); - SelectPen(hdc, pen); - - brush = GetStockBrush(NULL_BRUSH); - SelectBrush(hdc, brush); - - // Draw the rectangle. - Rectangle(hdc, 0, 0, rect.right - rect.left, rect.bottom - rect.top); - - // Cleanup. - DeleteObject(pen); - - RestoreDC(hdc, oldDc); - ReleaseDC(hWnd, hdc); - } -} - -LRESULT CALLBACK MainWndSubclassProc( - _In_ HWND hWnd, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam, - _In_ UINT_PTR uIdSubclass, - _In_ ULONG_PTR dwRefData - ) -{ - switch (uMsg) - { - case WM_COMMAND: - { - switch (GET_WM_COMMAND_CMD(wParam, lParam)) - { - case EN_CHANGE: - { - PPH_STRING newSearchboxText; - - if (!SearchboxHandle) - break; - - if (GET_WM_COMMAND_HWND(wParam, lParam) != SearchboxHandle) - break; - - newSearchboxText = PH_AUTO(PhGetWindowText(SearchboxHandle)); - - if (!PhEqualString(SearchboxText, newSearchboxText, FALSE)) - { - // Cache the current search text for our callback. - PhSwapReference(&SearchboxText, newSearchboxText); - - if (!PhIsNullOrEmptyString(SearchboxText)) - { - // Expand the nodes to ensure that they will be visible to the user. - PhExpandAllProcessNodes(TRUE); - PhDeselectAllProcessNodes(); - PhDeselectAllServiceNodes(); - } - - PhApplyTreeNewFilters(PhGetFilterSupportProcessTreeList()); - PhApplyTreeNewFilters(PhGetFilterSupportServiceTreeList()); - PhApplyTreeNewFilters(PhGetFilterSupportNetworkTreeList()); - - PhInvokeCallback(&SearchChangedEvent, SearchboxText); - } - - goto DefaultWndProc; - } - break; - case EN_KILLFOCUS: - { - if (GET_WM_COMMAND_HWND(wParam, lParam) != SearchboxHandle) - break; - - if (SearchBoxDisplayMode != SEARCHBOX_DISPLAY_MODE_HIDEINACTIVE) - break; - - if (SearchboxText->Length == 0) - { - if (RebarBandExists(REBAR_BAND_ID_SEARCHBOX)) - RebarBandRemove(REBAR_BAND_ID_SEARCHBOX); - } - - goto DefaultWndProc; - } - break; - } - - switch (GET_WM_COMMAND_ID(wParam, lParam)) - { - case PHAPP_ID_ESC_EXIT: - { - // If we're targeting and the user presses the Esc key, cancel the targeting. - // We also make sure the window doesn't get closed, by filtering out the message. - if (TargetingWindow) - { - TargetingWindow = FALSE; - ReleaseCapture(); - - goto DefaultWndProc; - } - } - break; - case ID_SEARCH: - { - // handle keybind Ctrl + K - if (SearchboxHandle && ToolStatusConfig.SearchBoxEnabled) - { - if (SearchBoxDisplayMode == SEARCHBOX_DISPLAY_MODE_HIDEINACTIVE) - { - if (!RebarBandExists(REBAR_BAND_ID_SEARCHBOX)) - RebarBandInsert(REBAR_BAND_ID_SEARCHBOX, SearchboxHandle, PhMultiplyDivide(180, PhGlobalDpi, 96), 22); - - if (!IsWindowVisible(SearchboxHandle)) - ShowWindow(SearchboxHandle, SW_SHOW); - } - - SetFocus(SearchboxHandle); - Edit_SetSel(SearchboxHandle, 0, -1); - } - - goto DefaultWndProc; - } - break; - case PHAPP_ID_VIEW_ALWAYSONTOP: - { - // Let Process Hacker perform the default processing. - DefSubclassProc(hWnd, uMsg, wParam, lParam); - - // Query the settings. - BOOLEAN isAlwaysOnTopEnabled = (BOOLEAN)PhGetIntegerSetting(L"MainWindowAlwaysOnTop"); - - // Set the pressed button state. - SendMessage(ToolBarHandle, TB_PRESSBUTTON, (WPARAM)PHAPP_ID_VIEW_ALWAYSONTOP, (LPARAM)(MAKELONG(isAlwaysOnTopEnabled, 0))); - - goto DefaultWndProc; - } - break; - case PHAPP_ID_UPDATEINTERVAL_FAST: - case PHAPP_ID_UPDATEINTERVAL_NORMAL: - case PHAPP_ID_UPDATEINTERVAL_BELOWNORMAL: - case PHAPP_ID_UPDATEINTERVAL_SLOW: - case PHAPP_ID_UPDATEINTERVAL_VERYSLOW: - { - // Let Process Hacker perform the default processing. - DefSubclassProc(hWnd, uMsg, wParam, lParam); - - StatusBarUpdate(TRUE); - - goto DefaultWndProc; - } - break; - case PHAPP_ID_VIEW_UPDATEAUTOMATICALLY: - { - UpdateAutomatically = !UpdateAutomatically; - - StatusBarUpdate(TRUE); - } - break; - } - } - break; - case WM_NOTIFY: - { - LPNMHDR hdr = (LPNMHDR)lParam; - - if (RebarHandle && hdr->hwndFrom == RebarHandle) - { - switch (hdr->code) - { - case RBN_HEIGHTCHANGE: - { - // Invoke the LayoutPaddingCallback. - SendMessage(PhMainWndHandle, WM_SIZE, 0, 0); - } - break; - case RBN_CHEVRONPUSHED: - { - LPNMREBARCHEVRON rebar; - ULONG index = 0; - ULONG buttonCount = 0; - RECT toolbarRect; - PPH_EMENU menu; - PPH_EMENU_ITEM selectedItem; - - rebar = (LPNMREBARCHEVRON)lParam; - menu = PhCreateEMenu(); - - GetClientRect(ToolBarHandle, &toolbarRect); - - buttonCount = (ULONG)SendMessage(ToolBarHandle, TB_BUTTONCOUNT, 0, 0); - - for (index = 0; index < buttonCount; index++) - { - RECT buttonRect; - TBBUTTONINFO buttonInfo = - { - sizeof(TBBUTTONINFO), - TBIF_BYINDEX | TBIF_STYLE | TBIF_COMMAND | TBIF_IMAGE - }; - - // Get the client coordinates of the button. - if (SendMessage(ToolBarHandle, TB_GETITEMRECT, index, (LPARAM)&buttonRect) == -1) - break; - - if (buttonRect.right <= toolbarRect.right) - continue; - - // Get extended button information. - if (SendMessage(ToolBarHandle, TB_GETBUTTONINFO, index, (LPARAM)&buttonInfo) == -1) - break; - - if (buttonInfo.fsStyle == BTNS_SEP) - { - // Add separators to menu. - PhInsertEMenuItem(menu, PhCreateEMenuItem(PH_EMENU_SEPARATOR, 0, NULL, NULL, NULL), -1); - } - else - { - PPH_EMENU_ITEM menuItem; - - if (PhGetOwnTokenAttributes().Elevated && buttonInfo.idCommand == PHAPP_ID_HACKER_SHOWDETAILSFORALLPROCESSES) - { - // Don't show the 'Show Details for All Processes' button in the - // dropdown menu when we're elevated. - continue; - } - - // Add buttons to menu. - menuItem = PhCreateEMenuItem(0, buttonInfo.idCommand, ToolbarGetText(buttonInfo.idCommand), NULL, NULL); - - menuItem->Flags |= PH_EMENU_BITMAP_OWNED; - menuItem->Bitmap = ToolbarGetImage(buttonInfo.idCommand); - - switch (buttonInfo.idCommand) - { - case PHAPP_ID_VIEW_ALWAYSONTOP: - { - // Set the pressed state. - if (PhGetIntegerSetting(L"MainWindowAlwaysOnTop")) - menuItem->Flags |= PH_EMENU_CHECKED; - } - break; - case TIDC_FINDWINDOW: - case TIDC_FINDWINDOWTHREAD: - case TIDC_FINDWINDOWKILL: - { - // Note: These buttons are incompatible with menus. - menuItem->Flags |= PH_EMENU_DISABLED; - } - break; - case TIDC_POWERMENUDROPDOWN: - { - // Create the sub-menu... - PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, PHAPP_ID_COMPUTER_LOCK, L"&Lock", NULL, NULL), -1); - PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, PHAPP_ID_COMPUTER_LOGOFF, L"Log o&ff", NULL, NULL), -1); - PhInsertEMenuItem(menuItem, PhCreateEMenuItem(PH_EMENU_SEPARATOR, 0, NULL, NULL, NULL), -1); - PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, PHAPP_ID_COMPUTER_SLEEP, L"&Sleep", NULL, NULL), -1); - PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, PHAPP_ID_COMPUTER_HIBERNATE, L"&Hibernate", NULL, NULL), -1); - PhInsertEMenuItem(menuItem, PhCreateEMenuItem(PH_EMENU_SEPARATOR, 0, NULL, NULL, NULL), -1); - PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, PHAPP_ID_COMPUTER_RESTART, L"R&estart", NULL, NULL), -1); - PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, PHAPP_ID_COMPUTER_RESTARTBOOTOPTIONS, L"Restart to boot &options", NULL, NULL), -1); - PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, PHAPP_ID_COMPUTER_SHUTDOWN, L"Shu&t down", NULL, NULL), -1); - PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, PHAPP_ID_COMPUTER_SHUTDOWNHYBRID, L"H&ybrid shut down", NULL, NULL), -1); - } - break; - } - - PhInsertEMenuItem(menu, menuItem, -1); - } - } - - MapWindowPoints(RebarHandle, NULL, (LPPOINT)&rebar->rc, 2); - - selectedItem = PhShowEMenu( - menu, - hWnd, - PH_EMENU_SHOW_LEFTRIGHT, - PH_ALIGN_LEFT | PH_ALIGN_TOP, - rebar->rc.left, - rebar->rc.bottom - ); - - if (selectedItem && selectedItem->Id != -1) - { - SendMessage(PhMainWndHandle, WM_COMMAND, MAKEWPARAM(selectedItem->Id, BN_CLICKED), 0); - } - - PhDestroyEMenu(menu); - } - break; - case RBN_LAYOUTCHANGED: - { - ReBarSaveLayoutSettings(); - } - break; - } - - goto DefaultWndProc; - } - else if (ToolBarHandle && hdr->hwndFrom == ToolBarHandle) - { - switch (hdr->code) - { - case TBN_GETDISPINFO: - { - LPNMTBDISPINFO toolbarDisplayInfo = (LPNMTBDISPINFO)lParam; - - if (toolbarDisplayInfo->dwMask & TBNF_IMAGE) - { - BOOLEAN found = FALSE; - - // Try to find the cached bitmap index. - // NOTE: The TBNF_DI_SETITEM flag below will cache the index so we only get called once. - // However, when adding buttons from the customize dialog we get called a second time, - // so we cache the index in our ToolbarButtons array to prevent ToolBarImageList from growing. - for (INT i = 0; i < ARRAYSIZE(ToolbarButtons); i++) - { - if (ToolbarButtons[i].idCommand == toolbarDisplayInfo->idCommand) - { - if (ToolbarButtons[i].iBitmap != I_IMAGECALLBACK) - { - found = TRUE; - - // Cache the bitmap index. - toolbarDisplayInfo->dwMask |= TBNF_DI_SETITEM; - // Set the bitmap index. - toolbarDisplayInfo->iImage = ToolbarButtons[i].iBitmap; - } - break; - } - } - - if (!found) - { - // We didn't find a cached bitmap index... - // Load the button bitmap and cache the index. - for (INT i = 0; i < ARRAYSIZE(ToolbarButtons); i++) - { - if (ToolbarButtons[i].idCommand == toolbarDisplayInfo->idCommand) - { - HBITMAP buttonImage; - - buttonImage = ToolbarGetImage(toolbarDisplayInfo->idCommand); - - // Cache the bitmap index. - toolbarDisplayInfo->dwMask |= TBNF_DI_SETITEM; - // Add the image, cache the value in the ToolbarButtons array, set the bitmap index. - toolbarDisplayInfo->iImage = ToolbarButtons[i].iBitmap = ImageList_Add( - ToolBarImageList, - buttonImage, - NULL - ); - - DeleteObject(buttonImage); - break; - } - } - } - } - } - break; - case TBN_DROPDOWN: - { - LPNMTOOLBAR toolbar = (LPNMTOOLBAR)hdr; - PPH_EMENU menu; - PPH_EMENU_ITEM selectedItem; - - if (toolbar->iItem != TIDC_POWERMENUDROPDOWN) - break; - - menu = PhCreateEMenu(); - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, PHAPP_ID_COMPUTER_LOCK, L"&Lock", NULL, NULL), -1); - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, PHAPP_ID_COMPUTER_LOGOFF, L"Log o&ff", NULL, NULL), -1); - PhInsertEMenuItem(menu, PhCreateEMenuItem(PH_EMENU_SEPARATOR, 0, NULL, NULL, NULL), -1); - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, PHAPP_ID_COMPUTER_SLEEP, L"&Sleep", NULL, NULL), -1); - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, PHAPP_ID_COMPUTER_HIBERNATE, L"&Hibernate", NULL, NULL), -1); - PhInsertEMenuItem(menu, PhCreateEMenuItem(PH_EMENU_SEPARATOR, 0, NULL, NULL, NULL), -1); - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, PHAPP_ID_COMPUTER_RESTART, L"R&estart", NULL, NULL), -1); - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, PHAPP_ID_COMPUTER_RESTARTBOOTOPTIONS, L"Restart to boot &options", NULL, NULL), -1); - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, PHAPP_ID_COMPUTER_SHUTDOWN, L"Shu&t down", NULL, NULL), -1); - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, PHAPP_ID_COMPUTER_SHUTDOWNHYBRID, L"H&ybrid shut down", NULL, NULL), -1); - - MapWindowPoints(ToolBarHandle, NULL, (LPPOINT)&toolbar->rcButton, 2); - - selectedItem = PhShowEMenu( - menu, - hWnd, - PH_EMENU_SHOW_LEFTRIGHT, - PH_ALIGN_LEFT | PH_ALIGN_TOP, - toolbar->rcButton.left, - toolbar->rcButton.bottom - ); - - if (selectedItem && selectedItem->Id != -1) - { - SendMessage(PhMainWndHandle, WM_COMMAND, MAKEWPARAM(selectedItem->Id, BN_CLICKED), 0); - } - - PhDestroyEMenu(menu); - } - return TBDDRET_DEFAULT; - case NM_LDOWN: - { - LPNMCLICK toolbar = (LPNMCLICK)hdr; - ULONG id = (ULONG)toolbar->dwItemSpec; - - if (id == -1) - break; - - if (id == TIDC_FINDWINDOW || id == TIDC_FINDWINDOWTHREAD || id == TIDC_FINDWINDOWKILL) - { - // Direct all mouse events to this window. - SetCapture(hWnd); - - // Set the cursor. - SetCursor(LoadCursor(NULL, IDC_CROSS)); - - // Send the window to the bottom. - SetWindowPos(hWnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE); - - TargetingWindow = TRUE; - TargetingCurrentWindow = NULL; - TargetingCurrentWindowDraw = FALSE; - TargetingCompleted = FALSE; - TargetingMode = id; - - SendMessage(hWnd, WM_MOUSEMOVE, 0, 0); - } - } - break; - case NM_RCLICK: - { - ShowCustomizeMenu(); - } - break; - } - - goto DefaultWndProc; - } - else if (StatusBarHandle && hdr->hwndFrom == StatusBarHandle) - { - switch (hdr->code) - { - case NM_RCLICK: - { - StatusBarShowMenu(); - } - break; - } - - goto DefaultWndProc; - } - else if ( - CpuGraphHandle && hdr->hwndFrom == CpuGraphHandle || - MemGraphHandle && hdr->hwndFrom == MemGraphHandle || - CommitGraphHandle && hdr->hwndFrom == CommitGraphHandle || - IoGraphHandle && hdr->hwndFrom == IoGraphHandle - ) - { - ToolbarUpdateGraphsInfo(hdr); - - goto DefaultWndProc; - } - } - break; - case WM_MOUSEMOVE: - { - if (TargetingWindow) - { - POINT cursorPos; - HWND windowOverMouse; - ULONG processId; - ULONG threadId; - - GetCursorPos(&cursorPos); - windowOverMouse = WindowFromPoint(cursorPos); - - if (TargetingCurrentWindow != windowOverMouse) - { - if (TargetingCurrentWindow && TargetingCurrentWindowDraw) - { - // Invert the old border (to remove it). - DrawWindowBorderForTargeting(TargetingCurrentWindow); - } - - if (windowOverMouse) - { - threadId = GetWindowThreadProcessId(windowOverMouse, &processId); - - // Draw a rectangle over the current window (but not if it's one of our own). - if (UlongToHandle(processId) != NtCurrentProcessId()) - { - DrawWindowBorderForTargeting(windowOverMouse); - TargetingCurrentWindowDraw = TRUE; - } - else - { - TargetingCurrentWindowDraw = FALSE; - } - } - - TargetingCurrentWindow = windowOverMouse; - } - - goto DefaultWndProc; - } - } - break; - case WM_LBUTTONUP: - { - if (TargetingWindow) - { - ULONG processId; - ULONG threadId; - - TargetingCompleted = TRUE; - - // Reset the original cursor. - SetCursor(LoadCursor(NULL, IDC_ARROW)); - - // Bring the window back to the top, and preserve the Always on Top setting. - SetWindowPos(PhMainWndHandle, PhGetIntegerSetting(L"MainWindowAlwaysOnTop") ? HWND_TOPMOST : HWND_TOP, - 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE); - - TargetingWindow = FALSE; - ReleaseCapture(); - - if (TargetingCurrentWindow) - { - if (TargetingCurrentWindowDraw) - { - // Remove the border on the window we found. - DrawWindowBorderForTargeting(TargetingCurrentWindow); - } - - if (ToolStatusConfig.ResolveGhostWindows) - { - // This is an undocumented function exported by user32.dll that - // retrieves the hung window represented by a ghost window. - static HWND (WINAPI *HungWindowFromGhostWindow_I)( - _In_ HWND hWnd - ); - - if (!HungWindowFromGhostWindow_I) - HungWindowFromGhostWindow_I = PhGetModuleProcAddress(L"user32.dll", "HungWindowFromGhostWindow"); - - if (HungWindowFromGhostWindow_I) - { - HWND hungWindow = HungWindowFromGhostWindow_I(TargetingCurrentWindow); - - // The call will have failed if the window wasn't actually a ghost - // window. - if (hungWindow) - TargetingCurrentWindow = hungWindow; - } - } - - threadId = GetWindowThreadProcessId(TargetingCurrentWindow, &processId); - - if (threadId && processId && UlongToHandle(processId) != NtCurrentProcessId()) - { - PPH_PROCESS_NODE processNode; - - processNode = PhFindProcessNode(UlongToHandle(processId)); - - if (processNode) - { - ProcessHacker_SelectTabPage(hWnd, 0); - ProcessHacker_SelectProcessNode(hWnd, processNode); - } - - switch (TargetingMode) - { - case TIDC_FINDWINDOWTHREAD: - { - PPH_PROCESS_PROPCONTEXT propContext; - PPH_PROCESS_ITEM processItem; - - if (processItem = PhReferenceProcessItem(UlongToHandle(processId))) - { - if (propContext = PhCreateProcessPropContext(hWnd, processItem)) - { - PhSetSelectThreadIdProcessPropContext(propContext, UlongToHandle(threadId)); - PhShowProcessProperties(propContext); - PhDereferenceObject(propContext); - } - - PhDereferenceObject(processItem); - } - else - { - PhShowError(hWnd, L"The process (PID %lu) does not exist.", processId); - } - } - break; - case TIDC_FINDWINDOWKILL: - { - PPH_PROCESS_ITEM processItem; - - if (processItem = PhReferenceProcessItem(UlongToHandle(processId))) - { - PhUiTerminateProcesses(hWnd, &processItem, 1); - PhDereferenceObject(processItem); - } - else - { - PhShowError(hWnd, L"The process (PID %lu) does not exist.", processId); - } - } - break; - } - } - } - - goto DefaultWndProc; - } - } - break; - case WM_CAPTURECHANGED: - { - if (!TargetingCompleted) - { - // The user cancelled the targeting, probably by pressing the Esc key. - - // Remove the border on the currently selected window. - if (TargetingCurrentWindow) - { - if (TargetingCurrentWindowDraw) - { - // Remove the border on the window we found. - DrawWindowBorderForTargeting(TargetingCurrentWindow); - } - } - - SetWindowPos(PhMainWndHandle, PhGetIntegerSetting(L"MainWindowAlwaysOnTop") ? HWND_TOPMOST : HWND_TOP, - 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE); - - TargetingCompleted = TRUE; - } - } - break; - case WM_SIZE: - // Resize PH main window client-area. - ProcessHacker_InvalidateLayoutPadding(hWnd); - break; - case WM_SETTINGCHANGE: - // Forward to the Searchbox so we can reinitialize the settings... - SendMessage(SearchboxHandle, WM_SETTINGCHANGE, 0, 0); - break; - case WM_SHOWWINDOW: - { - UpdateGraphs = (BOOLEAN)wParam; - } - break; - case WM_SYSCOMMAND: - { - if ((wParam & 0xFFF0) == SC_KEYMENU && lParam == 0) - { - if (!ToolStatusConfig.AutoHideMenu) - break; - - if (GetMenu(PhMainWndHandle)) - { - SetMenu(PhMainWndHandle, NULL); - } - else - { - SetMenu(PhMainWndHandle, MainMenu); - DrawMenuBar(PhMainWndHandle); - } - } - else if ((wParam & 0xFFF0) == SC_MINIMIZE) - { - UpdateGraphs = FALSE; - } - else if ((wParam & 0xFFF0) == SC_RESTORE) - { - UpdateGraphs = TRUE; - } - } - break; - case WM_EXITMENULOOP: - { - if (!ToolStatusConfig.AutoHideMenu) - break; - - if (GetMenu(PhMainWndHandle)) - { - SetMenu(PhMainWndHandle, NULL); - } - } - break; - } - - return DefSubclassProc(hWnd, uMsg, wParam, lParam); - -DefaultWndProc: - return DefWindowProc(hWnd, uMsg, wParam, lParam); -} - -VOID NTAPI MainWindowShowingCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - PhRegisterMessageLoopFilter(MessageLoopFilter, NULL); - PhRegisterCallback( - ProcessHacker_GetCallbackLayoutPadding(PhMainWndHandle), - LayoutPaddingCallback, - NULL, - &LayoutPaddingCallbackRegistration - ); - SetWindowSubclass(PhMainWndHandle, MainWndSubclassProc, 0, 0); - - ToolbarLoadSettings(); - ReBarLoadLayoutSettings(); - StatusBarLoadSettings(); - - MainMenu = GetMenu(PhMainWndHandle); - if (ToolStatusConfig.AutoHideMenu) - { - SetMenu(PhMainWndHandle, NULL); - } -} - -VOID NTAPI LoadCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - ToolStatusConfig.Flags = PhGetIntegerSetting(SETTING_NAME_TOOLSTATUS_CONFIG); - DisplayStyle = (TOOLBAR_DISPLAY_STYLE)PhGetIntegerSetting(SETTING_NAME_TOOLBARDISPLAYSTYLE); - SearchBoxDisplayMode = (SEARCHBOX_DISPLAY_MODE)PhGetIntegerSetting(SETTING_NAME_SEARCHBOXDISPLAYMODE); - UpdateGraphs = !PhGetIntegerSetting(L"StartHidden"); -} - -VOID NTAPI ShowOptionsCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - ShowOptionsDialog(Parameter); -} - -LOGICAL DllMain( - _In_ HINSTANCE Instance, - _In_ ULONG Reason, - _Reserved_ PVOID Reserved - ) -{ - switch (Reason) - { - case DLL_PROCESS_ATTACH: - { - PPH_PLUGIN_INFORMATION info; - PH_SETTING_CREATE settings[] = - { - { IntegerSettingType, SETTING_NAME_TOOLSTATUS_CONFIG, L"1F" }, - { IntegerSettingType, SETTING_NAME_TOOLBAR_THEME, L"0" }, - { IntegerSettingType, SETTING_NAME_TOOLBARDISPLAYSTYLE, L"1" }, - { IntegerSettingType, SETTING_NAME_SEARCHBOXDISPLAYMODE, L"0" }, - { StringSettingType, SETTING_NAME_REBAR_CONFIG, L"" }, - { StringSettingType, SETTING_NAME_TOOLBAR_CONFIG, L"" }, - { StringSettingType, SETTING_NAME_STATUSBAR_CONFIG, L"" } - }; - - PluginInstance = PhRegisterPlugin(PLUGIN_NAME, Instance, &info); - - if (!PluginInstance) - return FALSE; - - info->DisplayName = L"Toolbar and Status Bar"; - info->Author = L"dmex, wj32"; - info->Description = L"Adds a Toolbar, Status Bar and Search box.\r\n\r\nModern Toolbar icons by http://www.icons8.com"; - info->Url = L"https://wj32.org/processhacker/forums/viewtopic.php?t=1119"; - info->HasOptions = TRUE; - info->Interface = &PluginInterface; - - PhRegisterCallback( - PhGetPluginCallback(PluginInstance, PluginCallbackLoad), - LoadCallback, - NULL, - &PluginLoadCallbackRegistration - ); - PhRegisterCallback( - PhGetPluginCallback(PluginInstance, PluginCallbackShowOptions), - ShowOptionsCallback, - NULL, - &PluginShowOptionsCallbackRegistration - ); - PhRegisterCallback( - PhGetGeneralCallback(GeneralCallbackMainWindowShowing), - MainWindowShowingCallback, - NULL, - &MainWindowShowingCallbackRegistration - ); - PhRegisterCallback( - PhGetGeneralCallback(GeneralCallbackProcessesUpdated), - ProcessesUpdatedCallback, - NULL, - &ProcessesUpdatedCallbackRegistration - ); - PhRegisterCallback( - PhGetGeneralCallback(GeneralCallbackMainWindowTabChanged), - TabPageUpdatedCallback, - NULL, - &TabPageCallbackRegistration - ); - PhRegisterCallback( - PhGetGeneralCallback(GeneralCallbackProcessTreeNewInitializing), - TreeNewInitializingCallback, - &ProcessTreeNewHandle, - &ProcessTreeNewInitializingCallbackRegistration - ); - PhRegisterCallback( - PhGetGeneralCallback(GeneralCallbackServiceTreeNewInitializing), - TreeNewInitializingCallback, - &ServiceTreeNewHandle, - &ServiceTreeNewInitializingCallbackRegistration - ); - PhRegisterCallback( - PhGetGeneralCallback(GeneralCallbackNetworkTreeNewInitializing), - TreeNewInitializingCallback, - &NetworkTreeNewHandle, - &NetworkTreeNewInitializingCallbackRegistration - ); - - PhAddSettings(settings, ARRAYSIZE(settings)); - - AcceleratorTable = LoadAccelerators( - Instance, - MAKEINTRESOURCE(IDR_MAINWND_ACCEL) - ); - - TabInfoHashtable = PhCreateSimpleHashtable(3); - } - break; - } - - return TRUE; +/* + * Process Hacker ToolStatus - + * main program + * + * Copyright (C) 2011-2016 dmex + * Copyright (C) 2010-2016 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include "toolstatus.h" + +PPH_STRING GetSearchboxText( + VOID + ); + +VOID RegisterTabSearch( + _In_ INT TabIndex, + _In_ PWSTR BannerText + ); + +PTOOLSTATUS_TAB_INFO RegisterTabInfo( + _In_ INT TabIndex + ); + +TOOLSTATUS_CONFIG ToolStatusConfig = { 0 }; +HWND ProcessTreeNewHandle = NULL; +HWND ServiceTreeNewHandle = NULL; +HWND NetworkTreeNewHandle = NULL; +INT SelectedTabIndex; +BOOLEAN UpdateAutomatically = TRUE; +BOOLEAN UpdateGraphs = TRUE; +TOOLBAR_DISPLAY_STYLE DisplayStyle = TOOLBAR_DISPLAY_STYLE_SELECTIVETEXT; +SEARCHBOX_DISPLAY_MODE SearchBoxDisplayMode = SEARCHBOX_DISPLAY_MODE_ALWAYSSHOW; +REBAR_DISPLAY_LOCATION RebarDisplayLocation = REBAR_DISPLAY_LOCATION_TOP; +HWND RebarHandle = NULL; +HWND ToolBarHandle = NULL; +HWND SearchboxHandle = NULL; +HMENU MainMenu = NULL; +HACCEL AcceleratorTable = NULL; +PPH_STRING SearchboxText = NULL; +PH_PLUGIN_SYSTEM_STATISTICS SystemStatistics = { 0 }; +PH_CALLBACK_DECLARE(SearchChangedEvent); +PPH_HASHTABLE TabInfoHashtable; +PPH_TN_FILTER_ENTRY ProcessTreeFilterEntry = NULL; +PPH_TN_FILTER_ENTRY ServiceTreeFilterEntry = NULL; +PPH_TN_FILTER_ENTRY NetworkTreeFilterEntry = NULL; +PPH_PLUGIN PluginInstance = NULL; +TOOLSTATUS_INTERFACE PluginInterface = +{ + TOOLSTATUS_INTERFACE_VERSION, + GetSearchboxText, + WordMatchStringRef, + RegisterTabSearch, + &SearchChangedEvent, + RegisterTabInfo +}; + +static ULONG TargetingMode = 0; +static BOOLEAN TargetingWindow = FALSE; +static BOOLEAN TargetingCurrentWindowDraw = FALSE; +static BOOLEAN TargetingCompleted = FALSE; +static HWND TargetingCurrentWindow = NULL; +static PH_CALLBACK_REGISTRATION PluginLoadCallbackRegistration; +static PH_CALLBACK_REGISTRATION PluginShowOptionsCallbackRegistration; +static PH_CALLBACK_REGISTRATION MainWindowShowingCallbackRegistration; +static PH_CALLBACK_REGISTRATION ProcessesUpdatedCallbackRegistration; +static PH_CALLBACK_REGISTRATION LayoutPaddingCallbackRegistration; +static PH_CALLBACK_REGISTRATION TabPageCallbackRegistration; +static PH_CALLBACK_REGISTRATION ProcessTreeNewInitializingCallbackRegistration; +static PH_CALLBACK_REGISTRATION ServiceTreeNewInitializingCallbackRegistration; +static PH_CALLBACK_REGISTRATION NetworkTreeNewInitializingCallbackRegistration; + +PPH_STRING GetSearchboxText( + VOID + ) +{ + return SearchboxText; +} + +VOID NTAPI ProcessesUpdatedCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + ProcessesUpdatedCount++; + + if (ProcessesUpdatedCount < 2) + return; + + PhPluginGetSystemStatistics(&SystemStatistics); + + if (UpdateGraphs) + ToolbarUpdateGraphs(); + + if (ToolStatusConfig.StatusBarEnabled) + StatusBarUpdate(FALSE); +} + +VOID NTAPI TreeNewInitializingCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + *(HWND *)Context = ((PPH_PLUGIN_TREENEW_INFORMATION)Parameter)->TreeNewHandle; +} + +VOID RegisterTabSearch( + _In_ INT TabIndex, + _In_ PWSTR BannerText + ) +{ + PTOOLSTATUS_TAB_INFO tabInfo; + + tabInfo = RegisterTabInfo(TabIndex); + tabInfo->BannerText = BannerText; +} + +PTOOLSTATUS_TAB_INFO RegisterTabInfo( + _In_ INT TabIndex + ) +{ + PTOOLSTATUS_TAB_INFO tabInfoCopy; + PVOID *entry; + + tabInfoCopy = PhCreateAlloc(sizeof(TOOLSTATUS_TAB_INFO)); + memset(tabInfoCopy, 0, sizeof(TOOLSTATUS_TAB_INFO)); + + if (!PhAddItemSimpleHashtable(TabInfoHashtable, IntToPtr(TabIndex), tabInfoCopy)) + { + PhClearReference(&tabInfoCopy); + + if (entry = PhFindItemSimpleHashtable(TabInfoHashtable, IntToPtr(TabIndex))) + tabInfoCopy = *entry; + } + + return tabInfoCopy; +} + +PTOOLSTATUS_TAB_INFO FindTabInfo( + _In_ INT TabIndex + ) +{ + PVOID *entry; + + if (entry = PhFindItemSimpleHashtable(TabInfoHashtable, IntToPtr(TabIndex))) + return *entry; + + return NULL; +} + +HWND GetCurrentTreeNewHandle( + VOID + ) +{ + HWND treeNewHandle = NULL; + + switch (SelectedTabIndex) + { + case 0: + treeNewHandle = ProcessTreeNewHandle; + break; + case 1: + treeNewHandle = ServiceTreeNewHandle; + break; + case 2: + treeNewHandle = NetworkTreeNewHandle; + break; + default: + { + PTOOLSTATUS_TAB_INFO tabInfo; + + if ((tabInfo = FindTabInfo(SelectedTabIndex)) && tabInfo->GetTreeNewHandle) + { + treeNewHandle = tabInfo->GetTreeNewHandle(); + } + } + break; + } + + return treeNewHandle; +} + +VOID ShowCustomizeMenu( + VOID + ) +{ + POINT cursorPos; + PPH_EMENU menu; + PPH_EMENU_ITEM selectedItem; + + GetCursorPos(&cursorPos); + + menu = PhCreateEMenu(); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, COMMAND_ID_ENABLE_MENU, L"Main menu (auto-hide)", NULL, NULL), -1); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, COMMAND_ID_ENABLE_SEARCHBOX, L"Search box", NULL, NULL), -1); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, COMMAND_ID_ENABLE_CPU_GRAPH, L"CPU history", NULL, NULL), -1); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, COMMAND_ID_ENABLE_IO_GRAPH, L"I/O history", NULL, NULL), -1); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, COMMAND_ID_ENABLE_MEMORY_GRAPH, L"Physical memory history", NULL, NULL), -1); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, COMMAND_ID_ENABLE_COMMIT_GRAPH, L"Commit charge history", NULL, NULL), -1); + PhInsertEMenuItem(menu, PhCreateEMenuItem(PH_EMENU_SEPARATOR, 0, NULL, NULL, NULL), -1); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, COMMAND_ID_TOOLBAR_LOCKUNLOCK, L"Lock the toolbar", NULL, NULL), -1); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, COMMAND_ID_TOOLBAR_CUSTOMIZE, L"Customize...", NULL, NULL), -1); + + if (ToolStatusConfig.AutoHideMenu) + { + PhSetFlagsEMenuItem(menu, COMMAND_ID_ENABLE_MENU, PH_EMENU_CHECKED, PH_EMENU_CHECKED); + } + + if (ToolStatusConfig.SearchBoxEnabled) + { + PhSetFlagsEMenuItem(menu, COMMAND_ID_ENABLE_SEARCHBOX, PH_EMENU_CHECKED, PH_EMENU_CHECKED); + } + + if (ToolStatusConfig.CpuGraphEnabled) + { + PhSetFlagsEMenuItem(menu, COMMAND_ID_ENABLE_CPU_GRAPH, PH_EMENU_CHECKED, PH_EMENU_CHECKED); + } + + if (ToolStatusConfig.MemGraphEnabled) + { + PhSetFlagsEMenuItem(menu, COMMAND_ID_ENABLE_MEMORY_GRAPH, PH_EMENU_CHECKED, PH_EMENU_CHECKED); + } + + if (ToolStatusConfig.CommitGraphEnabled) + { + PhSetFlagsEMenuItem(menu, COMMAND_ID_ENABLE_COMMIT_GRAPH, PH_EMENU_CHECKED, PH_EMENU_CHECKED); + } + + if (ToolStatusConfig.IoGraphEnabled) + { + PhSetFlagsEMenuItem(menu, COMMAND_ID_ENABLE_IO_GRAPH, PH_EMENU_CHECKED, PH_EMENU_CHECKED); + } + + if (ToolStatusConfig.ToolBarLocked) + { + PhSetFlagsEMenuItem(menu, COMMAND_ID_TOOLBAR_LOCKUNLOCK, PH_EMENU_CHECKED, PH_EMENU_CHECKED); + } + + selectedItem = PhShowEMenu( + menu, + PhMainWndHandle, + PH_EMENU_SHOW_LEFTRIGHT, + PH_ALIGN_LEFT | PH_ALIGN_TOP, + cursorPos.x, + cursorPos.y + ); + + if (selectedItem && selectedItem->Id != -1) + { + switch (selectedItem->Id) + { + case COMMAND_ID_ENABLE_MENU: + { + ToolStatusConfig.AutoHideMenu = !ToolStatusConfig.AutoHideMenu; + + PhSetIntegerSetting(SETTING_NAME_TOOLSTATUS_CONFIG, ToolStatusConfig.Flags); + + if (ToolStatusConfig.AutoHideMenu) + { + SetMenu(PhMainWndHandle, NULL); + } + else + { + SetMenu(PhMainWndHandle, MainMenu); + DrawMenuBar(PhMainWndHandle); + } + } + break; + case COMMAND_ID_ENABLE_SEARCHBOX: + { + ToolStatusConfig.SearchBoxEnabled = !ToolStatusConfig.SearchBoxEnabled; + + PhSetIntegerSetting(SETTING_NAME_TOOLSTATUS_CONFIG, ToolStatusConfig.Flags); + + ToolbarLoadSettings(); + ReBarSaveLayoutSettings(); + + if (ToolStatusConfig.SearchBoxEnabled) + { + // Adding the Searchbox makes it focused, + // reset the focus back to the main window. + SetFocus(PhMainWndHandle); + } + } + break; + case COMMAND_ID_ENABLE_CPU_GRAPH: + { + ToolStatusConfig.CpuGraphEnabled = !ToolStatusConfig.CpuGraphEnabled; + + PhSetIntegerSetting(SETTING_NAME_TOOLSTATUS_CONFIG, ToolStatusConfig.Flags); + + ToolbarLoadSettings(); + ReBarSaveLayoutSettings(); + } + break; + case COMMAND_ID_ENABLE_MEMORY_GRAPH: + { + ToolStatusConfig.MemGraphEnabled = !ToolStatusConfig.MemGraphEnabled; + + PhSetIntegerSetting(SETTING_NAME_TOOLSTATUS_CONFIG, ToolStatusConfig.Flags); + + ToolbarLoadSettings(); + ReBarSaveLayoutSettings(); + } + break; + case COMMAND_ID_ENABLE_COMMIT_GRAPH: + { + ToolStatusConfig.CommitGraphEnabled = !ToolStatusConfig.CommitGraphEnabled; + + PhSetIntegerSetting(SETTING_NAME_TOOLSTATUS_CONFIG, ToolStatusConfig.Flags); + + ToolbarLoadSettings(); + ReBarSaveLayoutSettings(); + } + break; + case COMMAND_ID_ENABLE_IO_GRAPH: + { + ToolStatusConfig.IoGraphEnabled = !ToolStatusConfig.IoGraphEnabled; + + PhSetIntegerSetting(SETTING_NAME_TOOLSTATUS_CONFIG, ToolStatusConfig.Flags); + + ToolbarLoadSettings(); + ReBarSaveLayoutSettings(); + } + break; + case COMMAND_ID_TOOLBAR_LOCKUNLOCK: + { + UINT bandCount; + UINT bandIndex; + + bandCount = (UINT)SendMessage(RebarHandle, RB_GETBANDCOUNT, 0, 0); + + for (bandIndex = 0; bandIndex < bandCount; bandIndex++) + { + REBARBANDINFO rebarBandInfo = + { + sizeof(REBARBANDINFO), + RBBIM_STYLE + }; + + SendMessage(RebarHandle, RB_GETBANDINFO, bandIndex, (LPARAM)&rebarBandInfo); + + if (!(rebarBandInfo.fStyle & RBBS_GRIPPERALWAYS)) + { + // Removing the RBBS_NOGRIPPER style doesn't remove the gripper padding, + // So we toggle the RBBS_GRIPPERALWAYS style to make the Toolbar remove the padding. + + rebarBandInfo.fStyle |= RBBS_GRIPPERALWAYS; + + SendMessage(RebarHandle, RB_SETBANDINFO, bandIndex, (LPARAM)&rebarBandInfo); + + rebarBandInfo.fStyle &= ~RBBS_GRIPPERALWAYS; + } + + if (rebarBandInfo.fStyle & RBBS_NOGRIPPER) + { + rebarBandInfo.fStyle &= ~RBBS_NOGRIPPER; + } + else + { + rebarBandInfo.fStyle |= RBBS_NOGRIPPER; + } + + SendMessage(RebarHandle, RB_SETBANDINFO, bandIndex, (LPARAM)&rebarBandInfo); + } + + ToolStatusConfig.ToolBarLocked = !ToolStatusConfig.ToolBarLocked; + + PhSetIntegerSetting(SETTING_NAME_TOOLSTATUS_CONFIG, ToolStatusConfig.Flags); + + ToolbarLoadSettings(); + } + break; + case COMMAND_ID_TOOLBAR_CUSTOMIZE: + { + ToolBarShowCustomizeDialog(); + } + break; + } + } + + PhDestroyEMenu(menu); +} + +VOID NTAPI TabPageUpdatedCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + INT tabIndex = PtrToInt(Parameter); + + SelectedTabIndex = tabIndex; + + if (!SearchboxHandle) + return; + + switch (tabIndex) + { + case 0: + Edit_SetCueBannerText(SearchboxHandle, L"Search Processes (Ctrl+K)"); + break; + case 1: + Edit_SetCueBannerText(SearchboxHandle, L"Search Services (Ctrl+K)"); + break; + case 2: + Edit_SetCueBannerText(SearchboxHandle, L"Search Network (Ctrl+K)"); + break; + default: + { + PTOOLSTATUS_TAB_INFO tabInfo; + + if ((tabInfo = FindTabInfo(tabIndex)) && tabInfo->BannerText) + { + Edit_SetCueBannerText(SearchboxHandle, PhaConcatStrings2(tabInfo->BannerText, L" (Ctrl+K)")->Buffer); + } + else + { + // Disable the textbox if we're on an unsupported tab. + Edit_SetCueBannerText(SearchboxHandle, L"Search disabled"); + } + } + break; + } +} + +VOID NTAPI LayoutPaddingCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + PPH_LAYOUT_PADDING_DATA layoutPadding = Parameter; + + if (RebarHandle && ToolStatusConfig.ToolBarEnabled) + { + RECT rebarRect; + //RECT clientRect; + //INT x, y, cx, cy; + + SendMessage(RebarHandle, WM_SIZE, 0, 0); + + // TODO: GetClientRect with PhMainWndHandle causes crash. + //GetClientRect(PhMainWndHandle, &clientRect); + GetClientRect(RebarHandle, &rebarRect); + + // Adjust the PH client area and exclude the rebar width. + layoutPadding->Padding.top += rebarRect.bottom; + + // TODO: Replace CCS_TOP with CCS_NOPARENTALIGN and use below code + //switch (RebarDisplayLocation) + //{ + //case RebarLocationLeft: + // { + // //x = 0; + // //y = 0; + // //cx = rebarRect.right - rebarRect.left; + // //cy = clientRect.bottom - clientRect.top; + // } + // break; + //case RebarLocationTop: + // { + // //x = 0; + // //y = 0; + // //cx = clientRect.right - clientRect.left; + // //cy = clientRect.bottom - clientRect.top; + // + // // Adjust the PH client area and exclude the rebar height. + // //layoutPadding->Padding.top += rebarRect.bottom; + // } + // break; + //case RebarLocationRight: + // { + // //x = clientRect.right - (rebarRect.right - rebarRect.left); + // //y = 0; + // //cx = rebarRect.right - rebarRect.left; + // //cy = clientRect.bottom - clientRect.top; + // } + // break; + //case RebarLocationBottom: + // { + // //x = 0; + // //y = clientRect.bottom - (rebarRect.bottom - rebarRect.top) - (StatusBarEnabled ? rebarRect.bottom + 1 : 0); + // //cx = clientRect.right - clientRect.left; + // //cy = rebarRect.bottom - rebarRect.top; + // + // // Adjust the PH client area and exclude the rebar width. + // //layoutPadding->Padding.bottom += rebarRect.bottom; + // } + // break; + //} + //MoveWindow(RebarHandle, x, y, cx, cy, TRUE); + + //if (SearchBoxDisplayStyle == SearchBoxDisplayAutoHide) + //{ + // static BOOLEAN isSearchboxVisible = FALSE; + // SIZE idealWidth; + // + // // Query the Toolbar ideal width + // SendMessage(ToolBarHandle, TB_GETIDEALSIZE, FALSE, (LPARAM)&idealWidth); + // + // // Hide the Searcbox band if the window size is too small... + // if (rebarRect.right > idealWidth.cx) + // { + // if (isSearchboxVisible) + // { + // if (!RebarBandExists(REBAR_BAND_ID_SEARCHBOX)) + // RebarBandInsert(REBAR_BAND_ID_SEARCHBOX, SearchboxHandle, 180, 20); + // + // isSearchboxVisible = FALSE; + // } + // } + // else + // { + // if (!isSearchboxVisible) + // { + // if (RebarBandExists(REBAR_BAND_ID_SEARCHBOX)) + // RebarBandRemove(REBAR_BAND_ID_SEARCHBOX); + // + // isSearchboxVisible = TRUE; + // } + // } + //} + } + + if (StatusBarHandle && ToolStatusConfig.StatusBarEnabled) + { + RECT statusBarRect; + + SendMessage(StatusBarHandle, WM_SIZE, 0, 0); + + GetClientRect(StatusBarHandle, &statusBarRect); + + // Adjust the PH client area and exclude the StatusBar width. + layoutPadding->Padding.bottom += statusBarRect.bottom; + + //InvalidateRect(StatusBarHandle, NULL, TRUE); + } +} + +BOOLEAN NTAPI MessageLoopFilter( + _In_ PMSG Message, + _In_ PVOID Context + ) +{ + if ( + Message->hwnd == PhMainWndHandle || + IsChild(PhMainWndHandle, Message->hwnd) + ) + { + if (TranslateAccelerator(PhMainWndHandle, AcceleratorTable, Message)) + return TRUE; + + if (Message->message == WM_SYSCHAR && ToolStatusConfig.AutoHideMenu && !GetMenu(PhMainWndHandle)) + { + ULONG key = (ULONG)Message->wParam; + + if (key == 'h' || key == 'v' || key == 't' || key == 'u' || key == 'e') + { + SetMenu(PhMainWndHandle, MainMenu); + DrawMenuBar(PhMainWndHandle); + SendMessage(PhMainWndHandle, WM_SYSCHAR, Message->wParam, Message->lParam); + return TRUE; + } + } + } + + return FALSE; +} + +VOID DrawWindowBorderForTargeting( + _In_ HWND hWnd + ) +{ + RECT rect; + HDC hdc; + + GetWindowRect(hWnd, &rect); + hdc = GetWindowDC(hWnd); + + if (hdc) + { + INT penWidth; + INT oldDc; + HPEN pen; + HBRUSH brush; + + penWidth = GetSystemMetrics(SM_CXBORDER) * 3; + oldDc = SaveDC(hdc); + + // Get an inversion effect. + SetROP2(hdc, R2_NOT); + + pen = CreatePen(PS_INSIDEFRAME, penWidth, RGB(0x00, 0x00, 0x00)); + SelectPen(hdc, pen); + + brush = GetStockBrush(NULL_BRUSH); + SelectBrush(hdc, brush); + + // Draw the rectangle. + Rectangle(hdc, 0, 0, rect.right - rect.left, rect.bottom - rect.top); + + // Cleanup. + DeleteObject(pen); + + RestoreDC(hdc, oldDc); + ReleaseDC(hWnd, hdc); + } +} + +LRESULT CALLBACK MainWndSubclassProc( + _In_ HWND hWnd, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam, + _In_ UINT_PTR uIdSubclass, + _In_ ULONG_PTR dwRefData + ) +{ + switch (uMsg) + { + case WM_COMMAND: + { + switch (GET_WM_COMMAND_CMD(wParam, lParam)) + { + case EN_CHANGE: + { + PPH_STRING newSearchboxText; + + if (!SearchboxHandle) + break; + + if (GET_WM_COMMAND_HWND(wParam, lParam) != SearchboxHandle) + break; + + newSearchboxText = PH_AUTO(PhGetWindowText(SearchboxHandle)); + + if (!PhEqualString(SearchboxText, newSearchboxText, FALSE)) + { + // Cache the current search text for our callback. + PhSwapReference(&SearchboxText, newSearchboxText); + + if (!PhIsNullOrEmptyString(SearchboxText)) + { + // Expand the nodes to ensure that they will be visible to the user. + PhExpandAllProcessNodes(TRUE); + PhDeselectAllProcessNodes(); + PhDeselectAllServiceNodes(); + } + + PhApplyTreeNewFilters(PhGetFilterSupportProcessTreeList()); + PhApplyTreeNewFilters(PhGetFilterSupportServiceTreeList()); + PhApplyTreeNewFilters(PhGetFilterSupportNetworkTreeList()); + + PhInvokeCallback(&SearchChangedEvent, SearchboxText); + } + + goto DefaultWndProc; + } + break; + case EN_KILLFOCUS: + { + if (GET_WM_COMMAND_HWND(wParam, lParam) != SearchboxHandle) + break; + + if (SearchBoxDisplayMode != SEARCHBOX_DISPLAY_MODE_HIDEINACTIVE) + break; + + if (SearchboxText->Length == 0) + { + if (RebarBandExists(REBAR_BAND_ID_SEARCHBOX)) + RebarBandRemove(REBAR_BAND_ID_SEARCHBOX); + } + + goto DefaultWndProc; + } + break; + } + + switch (GET_WM_COMMAND_ID(wParam, lParam)) + { + case PHAPP_ID_ESC_EXIT: + { + // If we're targeting and the user presses the Esc key, cancel the targeting. + // We also make sure the window doesn't get closed, by filtering out the message. + if (TargetingWindow) + { + TargetingWindow = FALSE; + ReleaseCapture(); + + goto DefaultWndProc; + } + } + break; + case ID_SEARCH: + { + // handle keybind Ctrl + K + if (SearchboxHandle && ToolStatusConfig.SearchBoxEnabled) + { + if (SearchBoxDisplayMode == SEARCHBOX_DISPLAY_MODE_HIDEINACTIVE) + { + if (!RebarBandExists(REBAR_BAND_ID_SEARCHBOX)) + RebarBandInsert(REBAR_BAND_ID_SEARCHBOX, SearchboxHandle, PhMultiplyDivide(180, PhGlobalDpi, 96), 22); + + if (!IsWindowVisible(SearchboxHandle)) + ShowWindow(SearchboxHandle, SW_SHOW); + } + + SetFocus(SearchboxHandle); + Edit_SetSel(SearchboxHandle, 0, -1); + } + + goto DefaultWndProc; + } + break; + case PHAPP_ID_VIEW_ALWAYSONTOP: + { + // Let Process Hacker perform the default processing. + DefSubclassProc(hWnd, uMsg, wParam, lParam); + + // Query the settings. + BOOLEAN isAlwaysOnTopEnabled = (BOOLEAN)PhGetIntegerSetting(L"MainWindowAlwaysOnTop"); + + // Set the pressed button state. + SendMessage(ToolBarHandle, TB_PRESSBUTTON, (WPARAM)PHAPP_ID_VIEW_ALWAYSONTOP, (LPARAM)(MAKELONG(isAlwaysOnTopEnabled, 0))); + + goto DefaultWndProc; + } + break; + case PHAPP_ID_UPDATEINTERVAL_FAST: + case PHAPP_ID_UPDATEINTERVAL_NORMAL: + case PHAPP_ID_UPDATEINTERVAL_BELOWNORMAL: + case PHAPP_ID_UPDATEINTERVAL_SLOW: + case PHAPP_ID_UPDATEINTERVAL_VERYSLOW: + { + // Let Process Hacker perform the default processing. + DefSubclassProc(hWnd, uMsg, wParam, lParam); + + StatusBarUpdate(TRUE); + + goto DefaultWndProc; + } + break; + case PHAPP_ID_VIEW_UPDATEAUTOMATICALLY: + { + UpdateAutomatically = !UpdateAutomatically; + + StatusBarUpdate(TRUE); + } + break; + } + } + break; + case WM_NOTIFY: + { + LPNMHDR hdr = (LPNMHDR)lParam; + + if (RebarHandle && hdr->hwndFrom == RebarHandle) + { + switch (hdr->code) + { + case RBN_HEIGHTCHANGE: + { + // Invoke the LayoutPaddingCallback. + SendMessage(PhMainWndHandle, WM_SIZE, 0, 0); + } + break; + case RBN_CHEVRONPUSHED: + { + LPNMREBARCHEVRON rebar; + ULONG index = 0; + ULONG buttonCount = 0; + RECT toolbarRect; + PPH_EMENU menu; + PPH_EMENU_ITEM selectedItem; + + rebar = (LPNMREBARCHEVRON)lParam; + menu = PhCreateEMenu(); + + GetClientRect(ToolBarHandle, &toolbarRect); + + buttonCount = (ULONG)SendMessage(ToolBarHandle, TB_BUTTONCOUNT, 0, 0); + + for (index = 0; index < buttonCount; index++) + { + RECT buttonRect; + TBBUTTONINFO buttonInfo = + { + sizeof(TBBUTTONINFO), + TBIF_BYINDEX | TBIF_STYLE | TBIF_COMMAND | TBIF_IMAGE + }; + + // Get the client coordinates of the button. + if (SendMessage(ToolBarHandle, TB_GETITEMRECT, index, (LPARAM)&buttonRect) == -1) + break; + + if (buttonRect.right <= toolbarRect.right) + continue; + + // Get extended button information. + if (SendMessage(ToolBarHandle, TB_GETBUTTONINFO, index, (LPARAM)&buttonInfo) == -1) + break; + + if (buttonInfo.fsStyle == BTNS_SEP) + { + // Add separators to menu. + PhInsertEMenuItem(menu, PhCreateEMenuItem(PH_EMENU_SEPARATOR, 0, NULL, NULL, NULL), -1); + } + else + { + PPH_EMENU_ITEM menuItem; + + if (PhGetOwnTokenAttributes().Elevated && buttonInfo.idCommand == PHAPP_ID_HACKER_SHOWDETAILSFORALLPROCESSES) + { + // Don't show the 'Show Details for All Processes' button in the + // dropdown menu when we're elevated. + continue; + } + + // Add buttons to menu. + menuItem = PhCreateEMenuItem(0, buttonInfo.idCommand, ToolbarGetText(buttonInfo.idCommand), NULL, NULL); + + menuItem->Flags |= PH_EMENU_BITMAP_OWNED; + menuItem->Bitmap = ToolbarGetImage(buttonInfo.idCommand); + + switch (buttonInfo.idCommand) + { + case PHAPP_ID_VIEW_ALWAYSONTOP: + { + // Set the pressed state. + if (PhGetIntegerSetting(L"MainWindowAlwaysOnTop")) + menuItem->Flags |= PH_EMENU_CHECKED; + } + break; + case TIDC_FINDWINDOW: + case TIDC_FINDWINDOWTHREAD: + case TIDC_FINDWINDOWKILL: + { + // Note: These buttons are incompatible with menus. + menuItem->Flags |= PH_EMENU_DISABLED; + } + break; + case TIDC_POWERMENUDROPDOWN: + { + // Create the sub-menu... + PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, PHAPP_ID_COMPUTER_LOCK, L"&Lock", NULL, NULL), -1); + PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, PHAPP_ID_COMPUTER_LOGOFF, L"Log o&ff", NULL, NULL), -1); + PhInsertEMenuItem(menuItem, PhCreateEMenuItem(PH_EMENU_SEPARATOR, 0, NULL, NULL, NULL), -1); + PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, PHAPP_ID_COMPUTER_SLEEP, L"&Sleep", NULL, NULL), -1); + PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, PHAPP_ID_COMPUTER_HIBERNATE, L"&Hibernate", NULL, NULL), -1); + PhInsertEMenuItem(menuItem, PhCreateEMenuItem(PH_EMENU_SEPARATOR, 0, NULL, NULL, NULL), -1); + PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, PHAPP_ID_COMPUTER_RESTART, L"R&estart", NULL, NULL), -1); + PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, PHAPP_ID_COMPUTER_RESTARTBOOTOPTIONS, L"Restart to boot &options", NULL, NULL), -1); + PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, PHAPP_ID_COMPUTER_SHUTDOWN, L"Shu&t down", NULL, NULL), -1); + PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, PHAPP_ID_COMPUTER_SHUTDOWNHYBRID, L"H&ybrid shut down", NULL, NULL), -1); + } + break; + } + + PhInsertEMenuItem(menu, menuItem, -1); + } + } + + MapWindowPoints(RebarHandle, NULL, (LPPOINT)&rebar->rc, 2); + + selectedItem = PhShowEMenu( + menu, + hWnd, + PH_EMENU_SHOW_LEFTRIGHT, + PH_ALIGN_LEFT | PH_ALIGN_TOP, + rebar->rc.left, + rebar->rc.bottom + ); + + if (selectedItem && selectedItem->Id != -1) + { + SendMessage(PhMainWndHandle, WM_COMMAND, MAKEWPARAM(selectedItem->Id, BN_CLICKED), 0); + } + + PhDestroyEMenu(menu); + } + break; + case RBN_LAYOUTCHANGED: + { + ReBarSaveLayoutSettings(); + } + break; + } + + goto DefaultWndProc; + } + else if (ToolBarHandle && hdr->hwndFrom == ToolBarHandle) + { + switch (hdr->code) + { + case TBN_GETDISPINFO: + { + LPNMTBDISPINFO toolbarDisplayInfo = (LPNMTBDISPINFO)lParam; + + if (toolbarDisplayInfo->dwMask & TBNF_IMAGE) + { + BOOLEAN found = FALSE; + + // Try to find the cached bitmap index. + // NOTE: The TBNF_DI_SETITEM flag below will cache the index so we only get called once. + // However, when adding buttons from the customize dialog we get called a second time, + // so we cache the index in our ToolbarButtons array to prevent ToolBarImageList from growing. + for (INT i = 0; i < ARRAYSIZE(ToolbarButtons); i++) + { + if (ToolbarButtons[i].idCommand == toolbarDisplayInfo->idCommand) + { + if (ToolbarButtons[i].iBitmap != I_IMAGECALLBACK) + { + found = TRUE; + + // Cache the bitmap index. + toolbarDisplayInfo->dwMask |= TBNF_DI_SETITEM; + // Set the bitmap index. + toolbarDisplayInfo->iImage = ToolbarButtons[i].iBitmap; + } + break; + } + } + + if (!found) + { + // We didn't find a cached bitmap index... + // Load the button bitmap and cache the index. + for (INT i = 0; i < ARRAYSIZE(ToolbarButtons); i++) + { + if (ToolbarButtons[i].idCommand == toolbarDisplayInfo->idCommand) + { + HBITMAP buttonImage; + + buttonImage = ToolbarGetImage(toolbarDisplayInfo->idCommand); + + // Cache the bitmap index. + toolbarDisplayInfo->dwMask |= TBNF_DI_SETITEM; + // Add the image, cache the value in the ToolbarButtons array, set the bitmap index. + toolbarDisplayInfo->iImage = ToolbarButtons[i].iBitmap = ImageList_Add( + ToolBarImageList, + buttonImage, + NULL + ); + + DeleteObject(buttonImage); + break; + } + } + } + } + } + break; + case TBN_DROPDOWN: + { + LPNMTOOLBAR toolbar = (LPNMTOOLBAR)hdr; + PPH_EMENU menu; + PPH_EMENU_ITEM selectedItem; + + if (toolbar->iItem != TIDC_POWERMENUDROPDOWN) + break; + + menu = PhCreateEMenu(); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, PHAPP_ID_COMPUTER_LOCK, L"&Lock", NULL, NULL), -1); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, PHAPP_ID_COMPUTER_LOGOFF, L"Log o&ff", NULL, NULL), -1); + PhInsertEMenuItem(menu, PhCreateEMenuItem(PH_EMENU_SEPARATOR, 0, NULL, NULL, NULL), -1); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, PHAPP_ID_COMPUTER_SLEEP, L"&Sleep", NULL, NULL), -1); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, PHAPP_ID_COMPUTER_HIBERNATE, L"&Hibernate", NULL, NULL), -1); + PhInsertEMenuItem(menu, PhCreateEMenuItem(PH_EMENU_SEPARATOR, 0, NULL, NULL, NULL), -1); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, PHAPP_ID_COMPUTER_RESTART, L"R&estart", NULL, NULL), -1); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, PHAPP_ID_COMPUTER_RESTARTBOOTOPTIONS, L"Restart to boot &options", NULL, NULL), -1); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, PHAPP_ID_COMPUTER_SHUTDOWN, L"Shu&t down", NULL, NULL), -1); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, PHAPP_ID_COMPUTER_SHUTDOWNHYBRID, L"H&ybrid shut down", NULL, NULL), -1); + + MapWindowPoints(ToolBarHandle, NULL, (LPPOINT)&toolbar->rcButton, 2); + + selectedItem = PhShowEMenu( + menu, + hWnd, + PH_EMENU_SHOW_LEFTRIGHT, + PH_ALIGN_LEFT | PH_ALIGN_TOP, + toolbar->rcButton.left, + toolbar->rcButton.bottom + ); + + if (selectedItem && selectedItem->Id != -1) + { + SendMessage(PhMainWndHandle, WM_COMMAND, MAKEWPARAM(selectedItem->Id, BN_CLICKED), 0); + } + + PhDestroyEMenu(menu); + } + return TBDDRET_DEFAULT; + case NM_LDOWN: + { + LPNMCLICK toolbar = (LPNMCLICK)hdr; + ULONG id = (ULONG)toolbar->dwItemSpec; + + if (id == -1) + break; + + if (id == TIDC_FINDWINDOW || id == TIDC_FINDWINDOWTHREAD || id == TIDC_FINDWINDOWKILL) + { + // Direct all mouse events to this window. + SetCapture(hWnd); + + // Set the cursor. + SetCursor(LoadCursor(NULL, IDC_CROSS)); + + // Send the window to the bottom. + SetWindowPos(hWnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE); + + TargetingWindow = TRUE; + TargetingCurrentWindow = NULL; + TargetingCurrentWindowDraw = FALSE; + TargetingCompleted = FALSE; + TargetingMode = id; + + SendMessage(hWnd, WM_MOUSEMOVE, 0, 0); + } + } + break; + case NM_RCLICK: + { + ShowCustomizeMenu(); + } + break; + } + + goto DefaultWndProc; + } + else if (StatusBarHandle && hdr->hwndFrom == StatusBarHandle) + { + switch (hdr->code) + { + case NM_RCLICK: + { + StatusBarShowMenu(); + } + break; + } + + goto DefaultWndProc; + } + else if ( + CpuGraphHandle && hdr->hwndFrom == CpuGraphHandle || + MemGraphHandle && hdr->hwndFrom == MemGraphHandle || + CommitGraphHandle && hdr->hwndFrom == CommitGraphHandle || + IoGraphHandle && hdr->hwndFrom == IoGraphHandle + ) + { + ToolbarUpdateGraphsInfo(hdr); + + goto DefaultWndProc; + } + } + break; + case WM_MOUSEMOVE: + { + if (TargetingWindow) + { + POINT cursorPos; + HWND windowOverMouse; + ULONG processId; + ULONG threadId; + + GetCursorPos(&cursorPos); + windowOverMouse = WindowFromPoint(cursorPos); + + if (TargetingCurrentWindow != windowOverMouse) + { + if (TargetingCurrentWindow && TargetingCurrentWindowDraw) + { + // Invert the old border (to remove it). + DrawWindowBorderForTargeting(TargetingCurrentWindow); + } + + if (windowOverMouse) + { + threadId = GetWindowThreadProcessId(windowOverMouse, &processId); + + // Draw a rectangle over the current window (but not if it's one of our own). + if (UlongToHandle(processId) != NtCurrentProcessId()) + { + DrawWindowBorderForTargeting(windowOverMouse); + TargetingCurrentWindowDraw = TRUE; + } + else + { + TargetingCurrentWindowDraw = FALSE; + } + } + + TargetingCurrentWindow = windowOverMouse; + } + + goto DefaultWndProc; + } + } + break; + case WM_LBUTTONUP: + { + if (TargetingWindow) + { + ULONG processId; + ULONG threadId; + + TargetingCompleted = TRUE; + + // Reset the original cursor. + SetCursor(LoadCursor(NULL, IDC_ARROW)); + + // Bring the window back to the top, and preserve the Always on Top setting. + SetWindowPos(PhMainWndHandle, PhGetIntegerSetting(L"MainWindowAlwaysOnTop") ? HWND_TOPMOST : HWND_TOP, + 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE); + + TargetingWindow = FALSE; + ReleaseCapture(); + + if (TargetingCurrentWindow) + { + if (TargetingCurrentWindowDraw) + { + // Remove the border on the window we found. + DrawWindowBorderForTargeting(TargetingCurrentWindow); + } + + if (ToolStatusConfig.ResolveGhostWindows) + { + // This is an undocumented function exported by user32.dll that + // retrieves the hung window represented by a ghost window. + static HWND (WINAPI *HungWindowFromGhostWindow_I)( + _In_ HWND hWnd + ); + + if (!HungWindowFromGhostWindow_I) + HungWindowFromGhostWindow_I = PhGetModuleProcAddress(L"user32.dll", "HungWindowFromGhostWindow"); + + if (HungWindowFromGhostWindow_I) + { + HWND hungWindow = HungWindowFromGhostWindow_I(TargetingCurrentWindow); + + // The call will have failed if the window wasn't actually a ghost + // window. + if (hungWindow) + TargetingCurrentWindow = hungWindow; + } + } + + threadId = GetWindowThreadProcessId(TargetingCurrentWindow, &processId); + + if (threadId && processId && UlongToHandle(processId) != NtCurrentProcessId()) + { + PPH_PROCESS_NODE processNode; + + processNode = PhFindProcessNode(UlongToHandle(processId)); + + if (processNode) + { + ProcessHacker_SelectTabPage(hWnd, 0); + ProcessHacker_SelectProcessNode(hWnd, processNode); + } + + switch (TargetingMode) + { + case TIDC_FINDWINDOWTHREAD: + { + PPH_PROCESS_PROPCONTEXT propContext; + PPH_PROCESS_ITEM processItem; + + if (processItem = PhReferenceProcessItem(UlongToHandle(processId))) + { + if (propContext = PhCreateProcessPropContext(hWnd, processItem)) + { + PhSetSelectThreadIdProcessPropContext(propContext, UlongToHandle(threadId)); + PhShowProcessProperties(propContext); + PhDereferenceObject(propContext); + } + + PhDereferenceObject(processItem); + } + else + { + PhShowError(hWnd, L"The process (PID %lu) does not exist.", processId); + } + } + break; + case TIDC_FINDWINDOWKILL: + { + PPH_PROCESS_ITEM processItem; + + if (processItem = PhReferenceProcessItem(UlongToHandle(processId))) + { + PhUiTerminateProcesses(hWnd, &processItem, 1); + PhDereferenceObject(processItem); + } + else + { + PhShowError(hWnd, L"The process (PID %lu) does not exist.", processId); + } + } + break; + } + } + } + + goto DefaultWndProc; + } + } + break; + case WM_CAPTURECHANGED: + { + if (!TargetingCompleted) + { + // The user cancelled the targeting, probably by pressing the Esc key. + + // Remove the border on the currently selected window. + if (TargetingCurrentWindow) + { + if (TargetingCurrentWindowDraw) + { + // Remove the border on the window we found. + DrawWindowBorderForTargeting(TargetingCurrentWindow); + } + } + + SetWindowPos(PhMainWndHandle, PhGetIntegerSetting(L"MainWindowAlwaysOnTop") ? HWND_TOPMOST : HWND_TOP, + 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE); + + TargetingCompleted = TRUE; + } + } + break; + case WM_SIZE: + // Resize PH main window client-area. + ProcessHacker_InvalidateLayoutPadding(hWnd); + break; + case WM_SETTINGCHANGE: + // Forward to the Searchbox so we can reinitialize the settings... + SendMessage(SearchboxHandle, WM_SETTINGCHANGE, 0, 0); + break; + case WM_SHOWWINDOW: + { + UpdateGraphs = (BOOLEAN)wParam; + } + break; + case WM_SYSCOMMAND: + { + if ((wParam & 0xFFF0) == SC_KEYMENU && lParam == 0) + { + if (!ToolStatusConfig.AutoHideMenu) + break; + + if (GetMenu(PhMainWndHandle)) + { + SetMenu(PhMainWndHandle, NULL); + } + else + { + SetMenu(PhMainWndHandle, MainMenu); + DrawMenuBar(PhMainWndHandle); + } + } + else if ((wParam & 0xFFF0) == SC_MINIMIZE) + { + UpdateGraphs = FALSE; + } + else if ((wParam & 0xFFF0) == SC_RESTORE) + { + UpdateGraphs = TRUE; + } + } + break; + case WM_EXITMENULOOP: + { + if (!ToolStatusConfig.AutoHideMenu) + break; + + if (GetMenu(PhMainWndHandle)) + { + SetMenu(PhMainWndHandle, NULL); + } + } + break; + } + + return DefSubclassProc(hWnd, uMsg, wParam, lParam); + +DefaultWndProc: + return DefWindowProc(hWnd, uMsg, wParam, lParam); +} + +VOID NTAPI MainWindowShowingCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + PhRegisterMessageLoopFilter(MessageLoopFilter, NULL); + PhRegisterCallback( + ProcessHacker_GetCallbackLayoutPadding(PhMainWndHandle), + LayoutPaddingCallback, + NULL, + &LayoutPaddingCallbackRegistration + ); + SetWindowSubclass(PhMainWndHandle, MainWndSubclassProc, 0, 0); + + ToolbarLoadSettings(); + ReBarLoadLayoutSettings(); + StatusBarLoadSettings(); + + MainMenu = GetMenu(PhMainWndHandle); + if (ToolStatusConfig.AutoHideMenu) + { + SetMenu(PhMainWndHandle, NULL); + } +} + +VOID NTAPI LoadCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + ToolStatusConfig.Flags = PhGetIntegerSetting(SETTING_NAME_TOOLSTATUS_CONFIG); + DisplayStyle = (TOOLBAR_DISPLAY_STYLE)PhGetIntegerSetting(SETTING_NAME_TOOLBARDISPLAYSTYLE); + SearchBoxDisplayMode = (SEARCHBOX_DISPLAY_MODE)PhGetIntegerSetting(SETTING_NAME_SEARCHBOXDISPLAYMODE); + UpdateGraphs = !PhGetIntegerSetting(L"StartHidden"); +} + +VOID NTAPI ShowOptionsCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + ShowOptionsDialog(Parameter); +} + +LOGICAL DllMain( + _In_ HINSTANCE Instance, + _In_ ULONG Reason, + _Reserved_ PVOID Reserved + ) +{ + switch (Reason) + { + case DLL_PROCESS_ATTACH: + { + PPH_PLUGIN_INFORMATION info; + PH_SETTING_CREATE settings[] = + { + { IntegerSettingType, SETTING_NAME_TOOLSTATUS_CONFIG, L"1F" }, + { IntegerSettingType, SETTING_NAME_TOOLBAR_THEME, L"0" }, + { IntegerSettingType, SETTING_NAME_TOOLBARDISPLAYSTYLE, L"1" }, + { IntegerSettingType, SETTING_NAME_SEARCHBOXDISPLAYMODE, L"0" }, + { StringSettingType, SETTING_NAME_REBAR_CONFIG, L"" }, + { StringSettingType, SETTING_NAME_TOOLBAR_CONFIG, L"" }, + { StringSettingType, SETTING_NAME_STATUSBAR_CONFIG, L"" } + }; + + PluginInstance = PhRegisterPlugin(PLUGIN_NAME, Instance, &info); + + if (!PluginInstance) + return FALSE; + + info->DisplayName = L"Toolbar and Status Bar"; + info->Author = L"dmex, wj32"; + info->Description = L"Adds a Toolbar, Status Bar and Search box.\r\n\r\nModern Toolbar icons by http://www.icons8.com"; + info->Url = L"https://wj32.org/processhacker/forums/viewtopic.php?t=1119"; + info->HasOptions = TRUE; + info->Interface = &PluginInterface; + + PhRegisterCallback( + PhGetPluginCallback(PluginInstance, PluginCallbackLoad), + LoadCallback, + NULL, + &PluginLoadCallbackRegistration + ); + PhRegisterCallback( + PhGetPluginCallback(PluginInstance, PluginCallbackShowOptions), + ShowOptionsCallback, + NULL, + &PluginShowOptionsCallbackRegistration + ); + PhRegisterCallback( + PhGetGeneralCallback(GeneralCallbackMainWindowShowing), + MainWindowShowingCallback, + NULL, + &MainWindowShowingCallbackRegistration + ); + PhRegisterCallback( + PhGetGeneralCallback(GeneralCallbackProcessesUpdated), + ProcessesUpdatedCallback, + NULL, + &ProcessesUpdatedCallbackRegistration + ); + PhRegisterCallback( + PhGetGeneralCallback(GeneralCallbackMainWindowTabChanged), + TabPageUpdatedCallback, + NULL, + &TabPageCallbackRegistration + ); + PhRegisterCallback( + PhGetGeneralCallback(GeneralCallbackProcessTreeNewInitializing), + TreeNewInitializingCallback, + &ProcessTreeNewHandle, + &ProcessTreeNewInitializingCallbackRegistration + ); + PhRegisterCallback( + PhGetGeneralCallback(GeneralCallbackServiceTreeNewInitializing), + TreeNewInitializingCallback, + &ServiceTreeNewHandle, + &ServiceTreeNewInitializingCallbackRegistration + ); + PhRegisterCallback( + PhGetGeneralCallback(GeneralCallbackNetworkTreeNewInitializing), + TreeNewInitializingCallback, + &NetworkTreeNewHandle, + &NetworkTreeNewInitializingCallbackRegistration + ); + + PhAddSettings(settings, ARRAYSIZE(settings)); + + AcceleratorTable = LoadAccelerators( + Instance, + MAKEINTRESOURCE(IDR_MAINWND_ACCEL) + ); + + TabInfoHashtable = PhCreateSimpleHashtable(3); + } + break; + } + + return TRUE; } \ No newline at end of file diff --git a/plugins/ToolStatus/options.c b/plugins/ToolStatus/options.c index 4245130e9ef9..f46e5b5564ac 100644 --- a/plugins/ToolStatus/options.c +++ b/plugins/ToolStatus/options.c @@ -1,98 +1,98 @@ -/* - * Process Hacker ToolStatus - - * Plugin Options - * - * Copyright (C) 2011-2016 dmex - * Copyright (C) 2010-2013 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include "toolstatus.h" - -INT_PTR CALLBACK OptionsDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - switch (uMsg) - { - case WM_INITDIALOG: - { - PhCenterWindow(hwndDlg, GetParent(hwndDlg)); - - Button_SetCheck(GetDlgItem(hwndDlg, IDC_ENABLE_TOOLBAR), - ToolStatusConfig.ToolBarEnabled ? BST_CHECKED : BST_UNCHECKED); - Button_SetCheck(GetDlgItem(hwndDlg, IDC_ENABLE_STATUSBAR), - ToolStatusConfig.StatusBarEnabled ? BST_CHECKED : BST_UNCHECKED); - Button_SetCheck(GetDlgItem(hwndDlg, IDC_RESOLVEGHOSTWINDOWS), - ToolStatusConfig.ResolveGhostWindows ? BST_CHECKED : BST_UNCHECKED); - Button_SetCheck(GetDlgItem(hwndDlg, IDC_ENABLE_AUTOHIDE_MENU), - ToolStatusConfig.AutoHideMenu ? BST_CHECKED : BST_UNCHECKED); - } - break; - case WM_COMMAND: - { - switch (GET_WM_COMMAND_ID(wParam, lParam)) - { - case IDCANCEL: - EndDialog(hwndDlg, IDCANCEL); - break; - case IDOK: - { - ToolStatusConfig.ToolBarEnabled = Button_GetCheck(GetDlgItem(hwndDlg, IDC_ENABLE_TOOLBAR)) == BST_CHECKED; - ToolStatusConfig.StatusBarEnabled = Button_GetCheck(GetDlgItem(hwndDlg, IDC_ENABLE_STATUSBAR)) == BST_CHECKED; - ToolStatusConfig.ResolveGhostWindows = Button_GetCheck(GetDlgItem(hwndDlg, IDC_RESOLVEGHOSTWINDOWS)) == BST_CHECKED; - ToolStatusConfig.AutoHideMenu = Button_GetCheck(GetDlgItem(hwndDlg, IDC_ENABLE_AUTOHIDE_MENU)) == BST_CHECKED; - - PhSetIntegerSetting(SETTING_NAME_TOOLSTATUS_CONFIG, ToolStatusConfig.Flags); - - ToolbarLoadSettings(); - - if (ToolStatusConfig.AutoHideMenu) - { - SetMenu(PhMainWndHandle, NULL); - } - else - { - SetMenu(PhMainWndHandle, MainMenu); - DrawMenuBar(PhMainWndHandle); - } - - EndDialog(hwndDlg, IDOK); - } - break; - } - } - break; - } - - return FALSE; -} - -VOID ShowOptionsDialog( - _In_opt_ HWND Parent - ) -{ - DialogBox( - PluginInstance->DllBase, - MAKEINTRESOURCE(IDD_OPTIONS), - Parent, - OptionsDlgProc - ); +/* + * Process Hacker ToolStatus - + * Plugin Options + * + * Copyright (C) 2011-2016 dmex + * Copyright (C) 2010-2013 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include "toolstatus.h" + +INT_PTR CALLBACK OptionsDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + switch (uMsg) + { + case WM_INITDIALOG: + { + PhCenterWindow(hwndDlg, GetParent(hwndDlg)); + + Button_SetCheck(GetDlgItem(hwndDlg, IDC_ENABLE_TOOLBAR), + ToolStatusConfig.ToolBarEnabled ? BST_CHECKED : BST_UNCHECKED); + Button_SetCheck(GetDlgItem(hwndDlg, IDC_ENABLE_STATUSBAR), + ToolStatusConfig.StatusBarEnabled ? BST_CHECKED : BST_UNCHECKED); + Button_SetCheck(GetDlgItem(hwndDlg, IDC_RESOLVEGHOSTWINDOWS), + ToolStatusConfig.ResolveGhostWindows ? BST_CHECKED : BST_UNCHECKED); + Button_SetCheck(GetDlgItem(hwndDlg, IDC_ENABLE_AUTOHIDE_MENU), + ToolStatusConfig.AutoHideMenu ? BST_CHECKED : BST_UNCHECKED); + } + break; + case WM_COMMAND: + { + switch (GET_WM_COMMAND_ID(wParam, lParam)) + { + case IDCANCEL: + EndDialog(hwndDlg, IDCANCEL); + break; + case IDOK: + { + ToolStatusConfig.ToolBarEnabled = Button_GetCheck(GetDlgItem(hwndDlg, IDC_ENABLE_TOOLBAR)) == BST_CHECKED; + ToolStatusConfig.StatusBarEnabled = Button_GetCheck(GetDlgItem(hwndDlg, IDC_ENABLE_STATUSBAR)) == BST_CHECKED; + ToolStatusConfig.ResolveGhostWindows = Button_GetCheck(GetDlgItem(hwndDlg, IDC_RESOLVEGHOSTWINDOWS)) == BST_CHECKED; + ToolStatusConfig.AutoHideMenu = Button_GetCheck(GetDlgItem(hwndDlg, IDC_ENABLE_AUTOHIDE_MENU)) == BST_CHECKED; + + PhSetIntegerSetting(SETTING_NAME_TOOLSTATUS_CONFIG, ToolStatusConfig.Flags); + + ToolbarLoadSettings(); + + if (ToolStatusConfig.AutoHideMenu) + { + SetMenu(PhMainWndHandle, NULL); + } + else + { + SetMenu(PhMainWndHandle, MainMenu); + DrawMenuBar(PhMainWndHandle); + } + + EndDialog(hwndDlg, IDOK); + } + break; + } + } + break; + } + + return FALSE; +} + +VOID ShowOptionsDialog( + _In_opt_ HWND Parent + ) +{ + DialogBox( + PluginInstance->DllBase, + MAKEINTRESOURCE(IDD_OPTIONS), + Parent, + OptionsDlgProc + ); } \ No newline at end of file diff --git a/plugins/ToolStatus/resource.h b/plugins/ToolStatus/resource.h index 63439645b349..1868d400abcf 100644 --- a/plugins/ToolStatus/resource.h +++ b/plugins/ToolStatus/resource.h @@ -1,57 +1,57 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by ToolStatus.rc -// -#define IDD_OPTIONS 102 -#define IDR_MAINWND_ACCEL 103 -#define IDB_SEARCH_ACTIVE 104 -#define IDB_SEARCH_ACTIVE_BMP 119 -#define IDB_SEARCH_INACTIVE 120 -#define IDB_SEARCH_INACTIVE_BMP 121 -#define IDB_APPLICATION_GET_MODERN 126 -#define IDB_APPLICATION_GO_MODERN 127 -#define IDB_APPLICATION_MODERN 128 -#define IDB_ARROW_REFRESH_MODERN 129 -#define IDB_CHART_LINE_MODERN 130 -#define IDB_COG_EDIT_MODERN 131 -#define IDB_CROSS_MODERN 132 -#define IDB_FIND_MODERN 133 -#define IDB_POWER_MODERN 134 -#define IDD_CUSTOMIZE_TB 135 -#define IDD_CUSTOMIZE_SB 136 -#define IDI_ARROW_REFRESH 137 -#define IDI_COG_EDIT 138 -#define IDI_FIND 139 -#define IDI_CHART_LINE 140 -#define IDI_TBAPPLICATION 141 -#define IDI_APPLICATION_GO 142 -#define IDI_CROSS 143 -#define IDI_APPLICATION_GET 144 -#define IDI_LIGHTBULB_OFF 145 -#define IDC_ENABLE_TOOLBAR 1001 -#define IDC_ENABLE_MODERN 1002 -#define IDC_ENABLE_STATUSBAR 1003 -#define IDC_RESOLVEGHOSTWINDOWS 1004 -#define IDC_AVAILABLE 1005 -#define IDC_ADD 1006 -#define IDC_REMOVE 1007 -#define IDC_CURRENT 1008 -#define IDC_SEARCHOPTIONS 1009 -#define IDC_TEXTOPTIONS 1010 -#define IDC_MOVEUP 1011 -#define IDC_MOVEDOWN 1012 -#define IDC_RESET 1014 -#define IDC_ENABLE_AUTOHIDE_MENU 1015 -#define IDC_ENABLE_AUTOCOMPLETE 1016 -#define ID_SEARCH 40011 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 146 -#define _APS_NEXT_COMMAND_VALUE 40012 -#define _APS_NEXT_CONTROL_VALUE 1017 -#define _APS_NEXT_SYMED_VALUE 11010 -#endif -#endif +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by ToolStatus.rc +// +#define IDD_OPTIONS 102 +#define IDR_MAINWND_ACCEL 103 +#define IDB_SEARCH_ACTIVE 104 +#define IDB_SEARCH_ACTIVE_BMP 119 +#define IDB_SEARCH_INACTIVE 120 +#define IDB_SEARCH_INACTIVE_BMP 121 +#define IDB_APPLICATION_GET_MODERN 126 +#define IDB_APPLICATION_GO_MODERN 127 +#define IDB_APPLICATION_MODERN 128 +#define IDB_ARROW_REFRESH_MODERN 129 +#define IDB_CHART_LINE_MODERN 130 +#define IDB_COG_EDIT_MODERN 131 +#define IDB_CROSS_MODERN 132 +#define IDB_FIND_MODERN 133 +#define IDB_POWER_MODERN 134 +#define IDD_CUSTOMIZE_TB 135 +#define IDD_CUSTOMIZE_SB 136 +#define IDI_ARROW_REFRESH 137 +#define IDI_COG_EDIT 138 +#define IDI_FIND 139 +#define IDI_CHART_LINE 140 +#define IDI_TBAPPLICATION 141 +#define IDI_APPLICATION_GO 142 +#define IDI_CROSS 143 +#define IDI_APPLICATION_GET 144 +#define IDI_LIGHTBULB_OFF 145 +#define IDC_ENABLE_TOOLBAR 1001 +#define IDC_ENABLE_MODERN 1002 +#define IDC_ENABLE_STATUSBAR 1003 +#define IDC_RESOLVEGHOSTWINDOWS 1004 +#define IDC_AVAILABLE 1005 +#define IDC_ADD 1006 +#define IDC_REMOVE 1007 +#define IDC_CURRENT 1008 +#define IDC_SEARCHOPTIONS 1009 +#define IDC_TEXTOPTIONS 1010 +#define IDC_MOVEUP 1011 +#define IDC_MOVEDOWN 1012 +#define IDC_RESET 1014 +#define IDC_ENABLE_AUTOHIDE_MENU 1015 +#define IDC_ENABLE_AUTOCOMPLETE 1016 +#define ID_SEARCH 40011 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 146 +#define _APS_NEXT_COMMAND_VALUE 40012 +#define _APS_NEXT_CONTROL_VALUE 1017 +#define _APS_NEXT_SYMED_VALUE 11010 +#endif +#endif diff --git a/plugins/ToolStatus/searchbox.c b/plugins/ToolStatus/searchbox.c index 4cd68dadd33b..1c62529daddf 100644 --- a/plugins/ToolStatus/searchbox.c +++ b/plugins/ToolStatus/searchbox.c @@ -1,48 +1,48 @@ -/* - * Process Hacker - - * Search control stub - * - * Copyright (C) 2016 dmex - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - * - */ - -#include "toolstatus.h" -#include "commonutil.h" - -BOOLEAN CreateSearchboxControl( - VOID - ) -{ - if (SearchboxHandle = CreateWindowEx( - WS_EX_CLIENTEDGE, - WC_EDIT, - NULL, - WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | ES_LEFT | ES_AUTOHSCROLL | WS_VISIBLE, - CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, - RebarHandle, - NULL, - NULL, - NULL - )) - { - PhCreateSearchControl(RebarHandle, SearchboxHandle, L"Search Processes (Ctrl+K)"); - return TRUE; - } - - return FALSE; +/* + * Process Hacker - + * Search control stub + * + * Copyright (C) 2016 dmex + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + * + */ + +#include "toolstatus.h" +#include "commonutil.h" + +BOOLEAN CreateSearchboxControl( + VOID + ) +{ + if (SearchboxHandle = CreateWindowEx( + WS_EX_CLIENTEDGE, + WC_EDIT, + NULL, + WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | ES_LEFT | ES_AUTOHSCROLL | WS_VISIBLE, + CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, + RebarHandle, + NULL, + NULL, + NULL + )) + { + PhCreateSearchControl(RebarHandle, SearchboxHandle, L"Search Processes (Ctrl+K)"); + return TRUE; + } + + return FALSE; } \ No newline at end of file diff --git a/plugins/ToolStatus/statusbar.c b/plugins/ToolStatus/statusbar.c index 7bd302f877ed..92a8515eb812 100644 --- a/plugins/ToolStatus/statusbar.c +++ b/plugins/ToolStatus/statusbar.c @@ -1,581 +1,581 @@ -/* - * Process Hacker ToolStatus - - * statusbar main - * - * Copyright (C) 2011-2016 dmex - * Copyright (C) 2010-2013 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include "toolstatus.h" - -HWND StatusBarHandle = NULL; -ULONG ProcessesUpdatedCount = 0; -ULONG StatusBarMaxWidths[MAX_STATUSBAR_ITEMS]; -// Note: no lock is needed because we only ever modify the list on this same thread. -PPH_LIST StatusBarItemList = NULL; -ULONG StatusBarItems[MAX_STATUSBAR_ITEMS] = -{ - // Default items (displayed) - { ID_STATUS_CPUUSAGE }, - { ID_STATUS_PHYSICALMEMORY }, - { ID_STATUS_FREEMEMORY }, - // Available items (hidden) - { ID_STATUS_COMMITCHARGE }, - { ID_STATUS_NUMBEROFPROCESSES }, - { ID_STATUS_NUMBEROFTHREADS }, - { ID_STATUS_NUMBEROFHANDLES }, - { ID_STATUS_NUMBEROFVISIBLEITEMS, }, - { ID_STATUS_NUMBEROFSELECTEDITEMS, }, - { ID_STATUS_INTERVALSTATUS }, - { ID_STATUS_IO_RO }, - { ID_STATUS_IO_W }, - { ID_STATUS_MAX_CPU_PROCESS }, - { ID_STATUS_MAX_IO_PROCESS }, -}; - -VOID StatusBarLoadDefault( - VOID - ) -{ - if (!StatusBarItemList) - StatusBarItemList = PhCreateList(MAX_DEFAULT_STATUSBAR_ITEMS); - - for (ULONG i = 0; i < MAX_DEFAULT_STATUSBAR_ITEMS; i++) - { - PSTATUSBAR_ITEM item; - - item = PhAllocate(sizeof(STATUSBAR_ITEM)); - memset(item, 0, sizeof(STATUSBAR_ITEM)); - - item->Id = StatusBarItems[i]; - - PhAddItemList(StatusBarItemList, item); - } -} - -VOID StatusBarLoadSettings( - VOID - ) -{ - ULONG64 buttonCount = 0; - PPH_STRING settingsString; - PH_STRINGREF remaining; - PH_STRINGREF part; - - settingsString = PhaGetStringSetting(SETTING_NAME_STATUSBAR_CONFIG); - remaining = settingsString->sr; - - if (remaining.Length == 0) - { - // Load default settings - StatusBarLoadDefault(); - return; - } - - // Query the number of buttons to insert - if (!PhSplitStringRefAtChar(&remaining, '|', &part, &remaining)) - { - // Load default settings - StatusBarLoadDefault(); - return; - } - - if (!PhStringToInteger64(&part, 10, &buttonCount)) - { - // Load default settings - StatusBarLoadDefault(); - return; - } - - StatusBarItemList = PhCreateList((ULONG)buttonCount); - - for (ULONG i = 0; i < (ULONG)buttonCount; i++) - { - PH_STRINGREF idPart; - ULONG64 idInteger; - - if (remaining.Length == 0) - break; - - PhSplitStringRefAtChar(&remaining, '|', &idPart, &remaining); - - if (PhStringToInteger64(&idPart, 10, &idInteger)) - { - PSTATUSBAR_ITEM item; - - item = PhAllocate(sizeof(STATUSBAR_ITEM)); - memset(item, 0, sizeof(STATUSBAR_ITEM)); - - item->Id = (ULONG)idInteger; - - PhInsertItemList(StatusBarItemList, i, item); - } - } -} - -VOID StatusBarSaveSettings( - VOID - ) -{ - PPH_STRING settingsString; - PH_STRING_BUILDER stringBuilder; - - PhInitializeStringBuilder(&stringBuilder, 100); - - PhAppendFormatStringBuilder( - &stringBuilder, - L"%lu|", - StatusBarItemList->Count - ); - - for (ULONG i = 0; i < StatusBarItemList->Count; i++) - { - PSTATUSBAR_ITEM item = StatusBarItemList->Items[i]; - - PhAppendFormatStringBuilder( - &stringBuilder, - L"%lu|", - item->Id - ); - } - - if (stringBuilder.String->Length != 0) - PhRemoveEndStringBuilder(&stringBuilder, 1); - - settingsString = PH_AUTO(PhFinalStringBuilderString(&stringBuilder)); - PhSetStringSetting2(SETTING_NAME_STATUSBAR_CONFIG, &settingsString->sr); -} - -VOID StatusBarResetSettings( - VOID - ) -{ - for (ULONG i = 0; i < StatusBarItemList->Count; i++) - { - PhFree(StatusBarItemList->Items[i]); - } - - PhClearList(StatusBarItemList); - - StatusBarLoadDefault(); -} - -PWSTR StatusBarGetText( - _In_ ULONG CommandID - ) -{ - switch (CommandID) - { - case ID_STATUS_CPUUSAGE: - return L"CPU usage"; - case ID_STATUS_PHYSICALMEMORY: - return L"Physical memory"; - case ID_STATUS_NUMBEROFPROCESSES: - return L"Number of processes"; - case ID_STATUS_COMMITCHARGE: - return L"Commit charge"; - case ID_STATUS_FREEMEMORY: - return L"Free physical memory"; - case ID_STATUS_NUMBEROFTHREADS: - return L"Number of threads"; - case ID_STATUS_NUMBEROFHANDLES: - return L"Number of handles"; - case ID_STATUS_NUMBEROFVISIBLEITEMS: - return L"Number of visible items"; - case ID_STATUS_NUMBEROFSELECTEDITEMS: - return L"Number of selected items"; - case ID_STATUS_INTERVALSTATUS: - return L"Interval status"; - case ID_STATUS_IO_RO: - return L"I/O read+other"; - case ID_STATUS_IO_W: - return L"I/O write"; - case ID_STATUS_MAX_CPU_PROCESS: - return L"Max. CPU process"; - case ID_STATUS_MAX_IO_PROCESS: - return L"Max. I/O process"; - } - - return L"ERROR"; -} - -VOID StatusBarShowMenu( - VOID - ) -{ - PPH_EMENU menu; - PPH_EMENU_ITEM selectedItem; - POINT cursorPos; - - GetCursorPos(&cursorPos); - - menu = PhCreateEMenu(); - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, COMMAND_ID_ENABLE_SEARCHBOX, L"Customize...", NULL, NULL), -1); - - selectedItem = PhShowEMenu( - menu, - PhMainWndHandle, - PH_EMENU_SHOW_LEFTRIGHT, - PH_ALIGN_LEFT | PH_ALIGN_BOTTOM, - cursorPos.x, - cursorPos.y - ); - - if (selectedItem && selectedItem->Id != -1) - { - StatusBarShowCustomizeDialog(); - - StatusBarUpdate(TRUE); - } - - PhDestroyEMenu(menu); -} - -VOID StatusBarUpdate( - _In_ BOOLEAN ResetMaxWidths - ) -{ - static ULONG64 lastTickCount = 0; - - ULONG count; - ULONG i; - HDC hdc; - BOOLEAN resetMaxWidths = FALSE; - PPH_STRING text[MAX_STATUSBAR_ITEMS]; - ULONG widths[MAX_STATUSBAR_ITEMS]; - - if (ProcessesUpdatedCount < 2) - return; - - if (ResetMaxWidths) - resetMaxWidths = TRUE; - - if (!StatusBarItemList || StatusBarItemList->Count == 0) - { - // The status bar doesn't cope well with 0 parts. - widths[0] = -1; - SendMessage(StatusBarHandle, SB_SETPARTS, 1, (LPARAM)widths); - SendMessage(StatusBarHandle, SB_SETTEXT, 0, (LPARAM)L""); - return; - } - - hdc = GetDC(StatusBarHandle); - SelectObject(hdc, (HFONT)SendMessage(StatusBarHandle, WM_GETFONT, 0, 0)); - - // Reset max. widths for Max. CPU Process and Max. I/O Process parts once in a while. - { - LARGE_INTEGER tickCount; - - PhQuerySystemTime(&tickCount); - - if (tickCount.QuadPart - lastTickCount >= 10 * PH_TICKS_PER_SEC) - { - resetMaxWidths = TRUE; - lastTickCount = tickCount.QuadPart; - } - } - - count = 0; - - for (i = 0; i < StatusBarItemList->Count; i++) - { - SIZE size; - ULONG width; - PSTATUSBAR_ITEM item; - - item = StatusBarItemList->Items[i]; - - switch (item->Id) - { - case ID_STATUS_CPUUSAGE: - { - text[count] = PhFormatString( - L"CPU Usage: %.2f%%", - (SystemStatistics.CpuKernelUsage + SystemStatistics.CpuUserUsage) * 100 - ); - } - break; - case ID_STATUS_COMMITCHARGE: - { - ULONG commitUsage = SystemStatistics.Performance->CommittedPages; - FLOAT commitFraction = (FLOAT)commitUsage / SystemStatistics.Performance->CommitLimit * 100; - - text[count] = PhFormatString( - L"Commit charge: %s (%.2f%%)", - PhaFormatSize(UInt32x32To64(commitUsage, PAGE_SIZE), -1)->Buffer, - commitFraction - ); - } - break; - case ID_STATUS_PHYSICALMEMORY: - { - ULONG physicalUsage = PhSystemBasicInformation.NumberOfPhysicalPages - SystemStatistics.Performance->AvailablePages; - FLOAT physicalFraction = (FLOAT)physicalUsage / PhSystemBasicInformation.NumberOfPhysicalPages * 100; - - text[count] = PhFormatString( - L"Physical memory: %s (%.2f%%)", - PhaFormatSize(UInt32x32To64(physicalUsage, PAGE_SIZE), -1)->Buffer, - physicalFraction - ); - } - break; - case ID_STATUS_FREEMEMORY: - { - ULONG physicalFree = SystemStatistics.Performance->AvailablePages; - FLOAT physicalFreeFraction = (FLOAT)physicalFree / PhSystemBasicInformation.NumberOfPhysicalPages * 100; - - text[count] = PhFormatString( - L"Free memory: %s (%.2f%%)", - PhaFormatSize(UInt32x32To64(physicalFree, PAGE_SIZE), -1)->Buffer, - physicalFreeFraction - ); - } - break; - case ID_STATUS_NUMBEROFPROCESSES: - { - text[count] = PhConcatStrings2( - L"Processes: ", - PhaFormatUInt64(SystemStatistics.NumberOfProcesses, TRUE)->Buffer - ); - } - break; - case ID_STATUS_NUMBEROFTHREADS: - { - text[count] = PhConcatStrings2( - L"Threads: ", - PhaFormatUInt64(SystemStatistics.NumberOfThreads, TRUE)->Buffer - ); - } - break; - case ID_STATUS_NUMBEROFHANDLES: - { - text[count] = PhConcatStrings2( - L"Handles: ", - PhaFormatUInt64(SystemStatistics.NumberOfHandles, TRUE)->Buffer - ); - } - break; - case ID_STATUS_IO_RO: - { - text[count] = PhConcatStrings2( - L"I/O R+O: ", - PhaFormatSize(SystemStatistics.IoReadDelta.Delta + SystemStatistics.IoOtherDelta.Delta, -1)->Buffer - ); - } - break; - case ID_STATUS_IO_W: - { - text[count] = PhConcatStrings2( - L"I/O W: ", - PhaFormatSize(SystemStatistics.IoWriteDelta.Delta, -1)->Buffer - ); - } - break; - case ID_STATUS_MAX_CPU_PROCESS: - { - PPH_PROCESS_ITEM processItem; - - if (SystemStatistics.MaxCpuProcessId && (processItem = PhReferenceProcessItem(SystemStatistics.MaxCpuProcessId))) - { - if (!PH_IS_FAKE_PROCESS_ID(processItem->ProcessId)) - { - text[count] = PhFormatString( - L"%s (%lu): %.2f%%", - processItem->ProcessName->Buffer, - HandleToUlong(processItem->ProcessId), - processItem->CpuUsage * 100 - ); - } - else - { - text[count] = PhFormatString( - L"%s: %.2f%%", - processItem->ProcessName->Buffer, - processItem->CpuUsage * 100 - ); - } - - PhDereferenceObject(processItem); - } - else - { - text[count] = PhCreateString(L"-"); - } - } - break; - case ID_STATUS_MAX_IO_PROCESS: - { - PPH_PROCESS_ITEM processItem; - - if (SystemStatistics.MaxIoProcessId && (processItem = PhReferenceProcessItem(SystemStatistics.MaxIoProcessId))) - { - if (!PH_IS_FAKE_PROCESS_ID(processItem->ProcessId)) - { - text[count] = PhFormatString( - L"%s (%lu): %s", - processItem->ProcessName->Buffer, - HandleToUlong(processItem->ProcessId), - PhaFormatSize(processItem->IoReadDelta.Delta + processItem->IoWriteDelta.Delta + processItem->IoOtherDelta.Delta, -1)->Buffer - ); - } - else - { - text[count] = PhFormatString( - L"%s: %s", - processItem->ProcessName->Buffer, - PhaFormatSize(processItem->IoReadDelta.Delta + processItem->IoWriteDelta.Delta + processItem->IoOtherDelta.Delta, -1)->Buffer - ); - } - - PhDereferenceObject(processItem); - } - else - { - text[count] = PhCreateString(L"-"); - } - } - break; - case ID_STATUS_NUMBEROFVISIBLEITEMS: - { - HWND tnHandle = NULL; - - tnHandle = GetCurrentTreeNewHandle(); - - if (tnHandle) - { - ULONG visibleCount = 0; - - visibleCount = TreeNew_GetFlatNodeCount(tnHandle); - - text[count] = PhFormatString( - L"Visible: %lu", - visibleCount - ); - } - else - { - text[count] = PhCreateString( - L"Visible: N/A" - ); - } - } - break; - case ID_STATUS_NUMBEROFSELECTEDITEMS: - { - HWND tnHandle = NULL; - - tnHandle = GetCurrentTreeNewHandle(); - - if (tnHandle) - { - ULONG visibleCount = 0; - ULONG selectedCount = 0; - - visibleCount = TreeNew_GetFlatNodeCount(tnHandle); - - for (ULONG i = 0; i < visibleCount; i++) - { - if (TreeNew_GetFlatNode(tnHandle, i)->Selected) - selectedCount++; - } - - text[count] = PhFormatString( - L"Selected: %lu", - selectedCount - ); - } - else - { - text[count] = PhCreateString( - L"Selected: N/A" - ); - } - } - break; - case ID_STATUS_INTERVALSTATUS: - { - ULONG interval; - - interval = PhGetIntegerSetting(L"UpdateInterval"); - - if (UpdateAutomatically) - { - switch (interval) - { - case 500: - text[count] = PhCreateString(L"Interval: Fast"); - break; - case 1000: - text[count] = PhCreateString(L"Interval: Normal"); - break; - case 2000: - text[count] = PhCreateString(L"Interval: Below normal"); - break; - case 5000: - text[count] = PhCreateString(L"Interval: Slow"); - break; - case 10000: - text[count] = PhCreateString(L"Interval: Very slow"); - break; - } - } - else - { - text[count] = PhCreateString(L"Interval: Paused"); - } - } - break; - } - - if (resetMaxWidths) - StatusBarMaxWidths[count] = 0; - - if (!GetTextExtentPoint32(hdc, text[count]->Buffer, (ULONG)text[count]->Length / sizeof(WCHAR), &size)) - size.cx = 200; - - if (count != 0) - widths[count] = widths[count - 1]; - else - widths[count] = 0; - - width = size.cx + 10; - - if (width <= StatusBarMaxWidths[count]) - { - width = StatusBarMaxWidths[count]; - } - else - { - StatusBarMaxWidths[count] = width; - } - - widths[count] += width; - - count++; - } - - ReleaseDC(StatusBarHandle, hdc); - - SendMessage(StatusBarHandle, SB_SETPARTS, count, (LPARAM)widths); - - for (i = 0; i < count; i++) - { - SendMessage(StatusBarHandle, SB_SETTEXT, i, (LPARAM)text[i]->Buffer); - PhDereferenceObject(text[i]); - } +/* + * Process Hacker ToolStatus - + * statusbar main + * + * Copyright (C) 2011-2016 dmex + * Copyright (C) 2010-2013 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include "toolstatus.h" + +HWND StatusBarHandle = NULL; +ULONG ProcessesUpdatedCount = 0; +ULONG StatusBarMaxWidths[MAX_STATUSBAR_ITEMS]; +// Note: no lock is needed because we only ever modify the list on this same thread. +PPH_LIST StatusBarItemList = NULL; +ULONG StatusBarItems[MAX_STATUSBAR_ITEMS] = +{ + // Default items (displayed) + { ID_STATUS_CPUUSAGE }, + { ID_STATUS_PHYSICALMEMORY }, + { ID_STATUS_FREEMEMORY }, + // Available items (hidden) + { ID_STATUS_COMMITCHARGE }, + { ID_STATUS_NUMBEROFPROCESSES }, + { ID_STATUS_NUMBEROFTHREADS }, + { ID_STATUS_NUMBEROFHANDLES }, + { ID_STATUS_NUMBEROFVISIBLEITEMS, }, + { ID_STATUS_NUMBEROFSELECTEDITEMS, }, + { ID_STATUS_INTERVALSTATUS }, + { ID_STATUS_IO_RO }, + { ID_STATUS_IO_W }, + { ID_STATUS_MAX_CPU_PROCESS }, + { ID_STATUS_MAX_IO_PROCESS }, +}; + +VOID StatusBarLoadDefault( + VOID + ) +{ + if (!StatusBarItemList) + StatusBarItemList = PhCreateList(MAX_DEFAULT_STATUSBAR_ITEMS); + + for (ULONG i = 0; i < MAX_DEFAULT_STATUSBAR_ITEMS; i++) + { + PSTATUSBAR_ITEM item; + + item = PhAllocate(sizeof(STATUSBAR_ITEM)); + memset(item, 0, sizeof(STATUSBAR_ITEM)); + + item->Id = StatusBarItems[i]; + + PhAddItemList(StatusBarItemList, item); + } +} + +VOID StatusBarLoadSettings( + VOID + ) +{ + ULONG64 buttonCount = 0; + PPH_STRING settingsString; + PH_STRINGREF remaining; + PH_STRINGREF part; + + settingsString = PhaGetStringSetting(SETTING_NAME_STATUSBAR_CONFIG); + remaining = settingsString->sr; + + if (remaining.Length == 0) + { + // Load default settings + StatusBarLoadDefault(); + return; + } + + // Query the number of buttons to insert + if (!PhSplitStringRefAtChar(&remaining, '|', &part, &remaining)) + { + // Load default settings + StatusBarLoadDefault(); + return; + } + + if (!PhStringToInteger64(&part, 10, &buttonCount)) + { + // Load default settings + StatusBarLoadDefault(); + return; + } + + StatusBarItemList = PhCreateList((ULONG)buttonCount); + + for (ULONG i = 0; i < (ULONG)buttonCount; i++) + { + PH_STRINGREF idPart; + ULONG64 idInteger; + + if (remaining.Length == 0) + break; + + PhSplitStringRefAtChar(&remaining, '|', &idPart, &remaining); + + if (PhStringToInteger64(&idPart, 10, &idInteger)) + { + PSTATUSBAR_ITEM item; + + item = PhAllocate(sizeof(STATUSBAR_ITEM)); + memset(item, 0, sizeof(STATUSBAR_ITEM)); + + item->Id = (ULONG)idInteger; + + PhInsertItemList(StatusBarItemList, i, item); + } + } +} + +VOID StatusBarSaveSettings( + VOID + ) +{ + PPH_STRING settingsString; + PH_STRING_BUILDER stringBuilder; + + PhInitializeStringBuilder(&stringBuilder, 100); + + PhAppendFormatStringBuilder( + &stringBuilder, + L"%lu|", + StatusBarItemList->Count + ); + + for (ULONG i = 0; i < StatusBarItemList->Count; i++) + { + PSTATUSBAR_ITEM item = StatusBarItemList->Items[i]; + + PhAppendFormatStringBuilder( + &stringBuilder, + L"%lu|", + item->Id + ); + } + + if (stringBuilder.String->Length != 0) + PhRemoveEndStringBuilder(&stringBuilder, 1); + + settingsString = PH_AUTO(PhFinalStringBuilderString(&stringBuilder)); + PhSetStringSetting2(SETTING_NAME_STATUSBAR_CONFIG, &settingsString->sr); +} + +VOID StatusBarResetSettings( + VOID + ) +{ + for (ULONG i = 0; i < StatusBarItemList->Count; i++) + { + PhFree(StatusBarItemList->Items[i]); + } + + PhClearList(StatusBarItemList); + + StatusBarLoadDefault(); +} + +PWSTR StatusBarGetText( + _In_ ULONG CommandID + ) +{ + switch (CommandID) + { + case ID_STATUS_CPUUSAGE: + return L"CPU usage"; + case ID_STATUS_PHYSICALMEMORY: + return L"Physical memory"; + case ID_STATUS_NUMBEROFPROCESSES: + return L"Number of processes"; + case ID_STATUS_COMMITCHARGE: + return L"Commit charge"; + case ID_STATUS_FREEMEMORY: + return L"Free physical memory"; + case ID_STATUS_NUMBEROFTHREADS: + return L"Number of threads"; + case ID_STATUS_NUMBEROFHANDLES: + return L"Number of handles"; + case ID_STATUS_NUMBEROFVISIBLEITEMS: + return L"Number of visible items"; + case ID_STATUS_NUMBEROFSELECTEDITEMS: + return L"Number of selected items"; + case ID_STATUS_INTERVALSTATUS: + return L"Interval status"; + case ID_STATUS_IO_RO: + return L"I/O read+other"; + case ID_STATUS_IO_W: + return L"I/O write"; + case ID_STATUS_MAX_CPU_PROCESS: + return L"Max. CPU process"; + case ID_STATUS_MAX_IO_PROCESS: + return L"Max. I/O process"; + } + + return L"ERROR"; +} + +VOID StatusBarShowMenu( + VOID + ) +{ + PPH_EMENU menu; + PPH_EMENU_ITEM selectedItem; + POINT cursorPos; + + GetCursorPos(&cursorPos); + + menu = PhCreateEMenu(); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, COMMAND_ID_ENABLE_SEARCHBOX, L"Customize...", NULL, NULL), -1); + + selectedItem = PhShowEMenu( + menu, + PhMainWndHandle, + PH_EMENU_SHOW_LEFTRIGHT, + PH_ALIGN_LEFT | PH_ALIGN_BOTTOM, + cursorPos.x, + cursorPos.y + ); + + if (selectedItem && selectedItem->Id != -1) + { + StatusBarShowCustomizeDialog(); + + StatusBarUpdate(TRUE); + } + + PhDestroyEMenu(menu); +} + +VOID StatusBarUpdate( + _In_ BOOLEAN ResetMaxWidths + ) +{ + static ULONG64 lastTickCount = 0; + + ULONG count; + ULONG i; + HDC hdc; + BOOLEAN resetMaxWidths = FALSE; + PPH_STRING text[MAX_STATUSBAR_ITEMS]; + ULONG widths[MAX_STATUSBAR_ITEMS]; + + if (ProcessesUpdatedCount < 2) + return; + + if (ResetMaxWidths) + resetMaxWidths = TRUE; + + if (!StatusBarItemList || StatusBarItemList->Count == 0) + { + // The status bar doesn't cope well with 0 parts. + widths[0] = -1; + SendMessage(StatusBarHandle, SB_SETPARTS, 1, (LPARAM)widths); + SendMessage(StatusBarHandle, SB_SETTEXT, 0, (LPARAM)L""); + return; + } + + hdc = GetDC(StatusBarHandle); + SelectObject(hdc, (HFONT)SendMessage(StatusBarHandle, WM_GETFONT, 0, 0)); + + // Reset max. widths for Max. CPU Process and Max. I/O Process parts once in a while. + { + LARGE_INTEGER tickCount; + + PhQuerySystemTime(&tickCount); + + if (tickCount.QuadPart - lastTickCount >= 10 * PH_TICKS_PER_SEC) + { + resetMaxWidths = TRUE; + lastTickCount = tickCount.QuadPart; + } + } + + count = 0; + + for (i = 0; i < StatusBarItemList->Count; i++) + { + SIZE size; + ULONG width; + PSTATUSBAR_ITEM item; + + item = StatusBarItemList->Items[i]; + + switch (item->Id) + { + case ID_STATUS_CPUUSAGE: + { + text[count] = PhFormatString( + L"CPU Usage: %.2f%%", + (SystemStatistics.CpuKernelUsage + SystemStatistics.CpuUserUsage) * 100 + ); + } + break; + case ID_STATUS_COMMITCHARGE: + { + ULONG commitUsage = SystemStatistics.Performance->CommittedPages; + FLOAT commitFraction = (FLOAT)commitUsage / SystemStatistics.Performance->CommitLimit * 100; + + text[count] = PhFormatString( + L"Commit charge: %s (%.2f%%)", + PhaFormatSize(UInt32x32To64(commitUsage, PAGE_SIZE), -1)->Buffer, + commitFraction + ); + } + break; + case ID_STATUS_PHYSICALMEMORY: + { + ULONG physicalUsage = PhSystemBasicInformation.NumberOfPhysicalPages - SystemStatistics.Performance->AvailablePages; + FLOAT physicalFraction = (FLOAT)physicalUsage / PhSystemBasicInformation.NumberOfPhysicalPages * 100; + + text[count] = PhFormatString( + L"Physical memory: %s (%.2f%%)", + PhaFormatSize(UInt32x32To64(physicalUsage, PAGE_SIZE), -1)->Buffer, + physicalFraction + ); + } + break; + case ID_STATUS_FREEMEMORY: + { + ULONG physicalFree = SystemStatistics.Performance->AvailablePages; + FLOAT physicalFreeFraction = (FLOAT)physicalFree / PhSystemBasicInformation.NumberOfPhysicalPages * 100; + + text[count] = PhFormatString( + L"Free memory: %s (%.2f%%)", + PhaFormatSize(UInt32x32To64(physicalFree, PAGE_SIZE), -1)->Buffer, + physicalFreeFraction + ); + } + break; + case ID_STATUS_NUMBEROFPROCESSES: + { + text[count] = PhConcatStrings2( + L"Processes: ", + PhaFormatUInt64(SystemStatistics.NumberOfProcesses, TRUE)->Buffer + ); + } + break; + case ID_STATUS_NUMBEROFTHREADS: + { + text[count] = PhConcatStrings2( + L"Threads: ", + PhaFormatUInt64(SystemStatistics.NumberOfThreads, TRUE)->Buffer + ); + } + break; + case ID_STATUS_NUMBEROFHANDLES: + { + text[count] = PhConcatStrings2( + L"Handles: ", + PhaFormatUInt64(SystemStatistics.NumberOfHandles, TRUE)->Buffer + ); + } + break; + case ID_STATUS_IO_RO: + { + text[count] = PhConcatStrings2( + L"I/O R+O: ", + PhaFormatSize(SystemStatistics.IoReadDelta.Delta + SystemStatistics.IoOtherDelta.Delta, -1)->Buffer + ); + } + break; + case ID_STATUS_IO_W: + { + text[count] = PhConcatStrings2( + L"I/O W: ", + PhaFormatSize(SystemStatistics.IoWriteDelta.Delta, -1)->Buffer + ); + } + break; + case ID_STATUS_MAX_CPU_PROCESS: + { + PPH_PROCESS_ITEM processItem; + + if (SystemStatistics.MaxCpuProcessId && (processItem = PhReferenceProcessItem(SystemStatistics.MaxCpuProcessId))) + { + if (!PH_IS_FAKE_PROCESS_ID(processItem->ProcessId)) + { + text[count] = PhFormatString( + L"%s (%lu): %.2f%%", + processItem->ProcessName->Buffer, + HandleToUlong(processItem->ProcessId), + processItem->CpuUsage * 100 + ); + } + else + { + text[count] = PhFormatString( + L"%s: %.2f%%", + processItem->ProcessName->Buffer, + processItem->CpuUsage * 100 + ); + } + + PhDereferenceObject(processItem); + } + else + { + text[count] = PhCreateString(L"-"); + } + } + break; + case ID_STATUS_MAX_IO_PROCESS: + { + PPH_PROCESS_ITEM processItem; + + if (SystemStatistics.MaxIoProcessId && (processItem = PhReferenceProcessItem(SystemStatistics.MaxIoProcessId))) + { + if (!PH_IS_FAKE_PROCESS_ID(processItem->ProcessId)) + { + text[count] = PhFormatString( + L"%s (%lu): %s", + processItem->ProcessName->Buffer, + HandleToUlong(processItem->ProcessId), + PhaFormatSize(processItem->IoReadDelta.Delta + processItem->IoWriteDelta.Delta + processItem->IoOtherDelta.Delta, -1)->Buffer + ); + } + else + { + text[count] = PhFormatString( + L"%s: %s", + processItem->ProcessName->Buffer, + PhaFormatSize(processItem->IoReadDelta.Delta + processItem->IoWriteDelta.Delta + processItem->IoOtherDelta.Delta, -1)->Buffer + ); + } + + PhDereferenceObject(processItem); + } + else + { + text[count] = PhCreateString(L"-"); + } + } + break; + case ID_STATUS_NUMBEROFVISIBLEITEMS: + { + HWND tnHandle = NULL; + + tnHandle = GetCurrentTreeNewHandle(); + + if (tnHandle) + { + ULONG visibleCount = 0; + + visibleCount = TreeNew_GetFlatNodeCount(tnHandle); + + text[count] = PhFormatString( + L"Visible: %lu", + visibleCount + ); + } + else + { + text[count] = PhCreateString( + L"Visible: N/A" + ); + } + } + break; + case ID_STATUS_NUMBEROFSELECTEDITEMS: + { + HWND tnHandle = NULL; + + tnHandle = GetCurrentTreeNewHandle(); + + if (tnHandle) + { + ULONG visibleCount = 0; + ULONG selectedCount = 0; + + visibleCount = TreeNew_GetFlatNodeCount(tnHandle); + + for (ULONG i = 0; i < visibleCount; i++) + { + if (TreeNew_GetFlatNode(tnHandle, i)->Selected) + selectedCount++; + } + + text[count] = PhFormatString( + L"Selected: %lu", + selectedCount + ); + } + else + { + text[count] = PhCreateString( + L"Selected: N/A" + ); + } + } + break; + case ID_STATUS_INTERVALSTATUS: + { + ULONG interval; + + interval = PhGetIntegerSetting(L"UpdateInterval"); + + if (UpdateAutomatically) + { + switch (interval) + { + case 500: + text[count] = PhCreateString(L"Interval: Fast"); + break; + case 1000: + text[count] = PhCreateString(L"Interval: Normal"); + break; + case 2000: + text[count] = PhCreateString(L"Interval: Below normal"); + break; + case 5000: + text[count] = PhCreateString(L"Interval: Slow"); + break; + case 10000: + text[count] = PhCreateString(L"Interval: Very slow"); + break; + } + } + else + { + text[count] = PhCreateString(L"Interval: Paused"); + } + } + break; + } + + if (resetMaxWidths) + StatusBarMaxWidths[count] = 0; + + if (!GetTextExtentPoint32(hdc, text[count]->Buffer, (ULONG)text[count]->Length / sizeof(WCHAR), &size)) + size.cx = 200; + + if (count != 0) + widths[count] = widths[count - 1]; + else + widths[count] = 0; + + width = size.cx + 10; + + if (width <= StatusBarMaxWidths[count]) + { + width = StatusBarMaxWidths[count]; + } + else + { + StatusBarMaxWidths[count] = width; + } + + widths[count] += width; + + count++; + } + + ReleaseDC(StatusBarHandle, hdc); + + SendMessage(StatusBarHandle, SB_SETPARTS, count, (LPARAM)widths); + + for (i = 0; i < count; i++) + { + SendMessage(StatusBarHandle, SB_SETTEXT, i, (LPARAM)text[i]->Buffer); + PhDereferenceObject(text[i]); + } } \ No newline at end of file diff --git a/plugins/ToolStatus/toolbar.c b/plugins/ToolStatus/toolbar.c index d5609cda8848..67fb6176bab4 100644 --- a/plugins/ToolStatus/toolbar.c +++ b/plugins/ToolStatus/toolbar.c @@ -1,852 +1,852 @@ -/* - * Process Hacker ToolStatus - - * main toolbar - * - * Copyright (C) 2011-2016 dmex - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include "toolstatus.h" -#include "commonutil.h" - -SIZE ToolBarImageSize = { 16, 16 }; -HIMAGELIST ToolBarImageList = NULL; - -TBBUTTON ToolbarButtons[MAX_TOOLBAR_ITEMS] = -{ - // Default toolbar buttons (displayed) - { I_IMAGECALLBACK, PHAPP_ID_VIEW_REFRESH, TBSTATE_ENABLED, BTNS_BUTTON | BTNS_AUTOSIZE | BTNS_SHOWTEXT, { 0 }, 0, 0 }, - { I_IMAGECALLBACK, PHAPP_ID_HACKER_OPTIONS, TBSTATE_ENABLED, BTNS_BUTTON | BTNS_AUTOSIZE | BTNS_SHOWTEXT, { 0 }, 0, 0 }, - { 0, 0, 0, BTNS_SEP, { 0 }, 0, 0 }, - { I_IMAGECALLBACK, PHAPP_ID_HACKER_FINDHANDLESORDLLS, TBSTATE_ENABLED, BTNS_BUTTON | BTNS_AUTOSIZE | BTNS_SHOWTEXT, { 0 }, 0, 0 }, - { I_IMAGECALLBACK, PHAPP_ID_VIEW_SYSTEMINFORMATION, TBSTATE_ENABLED, BTNS_BUTTON | BTNS_AUTOSIZE | BTNS_SHOWTEXT, { 0 }, 0, 0 }, - { 0, 0, 0, BTNS_SEP, { 0 }, 0, 0 }, - { I_IMAGECALLBACK, TIDC_FINDWINDOW, TBSTATE_ENABLED, BTNS_BUTTON | BTNS_AUTOSIZE | BTNS_SHOWTEXT, { 0 }, 0, 0 }, - { I_IMAGECALLBACK, TIDC_FINDWINDOWTHREAD, TBSTATE_ENABLED, BTNS_BUTTON | BTNS_AUTOSIZE | BTNS_SHOWTEXT, { 0 }, 0, 0 }, - { I_IMAGECALLBACK, TIDC_FINDWINDOWKILL, TBSTATE_ENABLED, BTNS_BUTTON | BTNS_AUTOSIZE | BTNS_SHOWTEXT, { 0 }, 0, 0 }, - // Available toolbar buttons (hidden) - { I_IMAGECALLBACK, PHAPP_ID_VIEW_ALWAYSONTOP, TBSTATE_ENABLED, BTNS_BUTTON | BTNS_AUTOSIZE | BTNS_SHOWTEXT, { 0 }, 0, 0 }, - { I_IMAGECALLBACK, TIDC_POWERMENUDROPDOWN, TBSTATE_ENABLED, BTNS_WHOLEDROPDOWN | BTNS_BUTTON | BTNS_AUTOSIZE | BTNS_SHOWTEXT,{ 0 }, 0, 0 }, - { I_IMAGECALLBACK, PHAPP_ID_HACKER_SHOWDETAILSFORALLPROCESSES, TBSTATE_ENABLED, BTNS_BUTTON | BTNS_AUTOSIZE | BTNS_SHOWTEXT,{ 0 }, 0, 0 }, -}; - -VOID RebarBandInsert( - _In_ UINT BandID, - _In_ HWND HwndChild, - _In_ UINT cxMinChild, - _In_ UINT cyMinChild - ) -{ - UINT index; - REBARBANDINFO rebarBandInfo = - { - sizeof(REBARBANDINFO), - RBBIM_STYLE | RBBIM_ID | RBBIM_CHILD | RBBIM_CHILDSIZE, - RBBS_USECHEVRON // RBBS_NOGRIPPER | RBBS_HIDETITLE | RBBS_TOPALIGN - }; - - rebarBandInfo.wID = BandID; - rebarBandInfo.hwndChild = HwndChild; - rebarBandInfo.cxMinChild = cxMinChild; - rebarBandInfo.cyMinChild = cyMinChild; - - if (ToolStatusConfig.ToolBarLocked) - { - rebarBandInfo.fStyle |= RBBS_NOGRIPPER; - } - - if ((index = (UINT)SendMessage(RebarHandle, RB_IDTOINDEX, REBAR_BAND_ID_SEARCHBOX, 0)) != -1) - { - SendMessage(RebarHandle, RB_INSERTBAND, (WPARAM)index, (LPARAM)&rebarBandInfo); - } - else - { - SendMessage(RebarHandle, RB_INSERTBAND, (WPARAM)-1, (LPARAM)&rebarBandInfo); - } -} - -VOID RebarBandRemove( - _In_ UINT BandID - ) -{ - UINT index = (UINT)SendMessage(RebarHandle, RB_IDTOINDEX, (WPARAM)BandID, 0); - - if (index == -1) - return; - - SendMessage(RebarHandle, RB_DELETEBAND, (WPARAM)index, 0); -} - -BOOLEAN RebarBandExists( - _In_ UINT BandID - ) -{ - UINT index = (UINT)SendMessage(RebarHandle, RB_IDTOINDEX, (WPARAM)BandID, 0); - - if (index != -1) - return TRUE; - - return FALSE; -} - -VOID RebarLoadSettings( - VOID - ) -{ - if (ToolStatusConfig.ToolBarEnabled && !ToolBarImageList) - { - ToolBarImageList = ImageList_Create(ToolBarImageSize.cx, ToolBarImageSize.cy, ILC_COLOR32, 0, 0); - } - - if (ToolStatusConfig.ToolBarEnabled && !RebarHandle) - { - REBARINFO rebarInfo = { sizeof(REBARINFO) }; - ULONG toolbarButtonSize; - - RebarHandle = CreateWindowEx( - WS_EX_TOOLWINDOW, - REBARCLASSNAME, - NULL, - WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | CCS_NODIVIDER | CCS_TOP | RBS_VARHEIGHT | RBS_AUTOSIZE, // CCS_NOPARENTALIGN | RBS_FIXEDORDER - CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, - PhMainWndHandle, - NULL, - NULL, - NULL - ); - - ToolBarHandle = CreateWindowEx( - 0, - TOOLBARCLASSNAME, - NULL, - WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | CCS_NORESIZE | CCS_NOPARENTALIGN | CCS_NODIVIDER | TBSTYLE_FLAT | TBSTYLE_LIST | TBSTYLE_TRANSPARENT | TBSTYLE_TOOLTIPS | TBSTYLE_AUTOSIZE, // TBSTYLE_CUSTOMERASE TBSTYLE_ALTDRAG - CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, - RebarHandle, - NULL, - NULL, - NULL - ); - - // Set the toolbar info with no imagelist. - SendMessage(RebarHandle, RB_SETBARINFO, 0, (LPARAM)&rebarInfo); - // Set the toolbar struct size. - SendMessage(ToolBarHandle, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0); - // Set the toolbar extended toolbar styles. - SendMessage(ToolBarHandle, TB_SETEXTENDEDSTYLE, 0, TBSTYLE_EX_DOUBLEBUFFER | TBSTYLE_EX_MIXEDBUTTONS | TBSTYLE_EX_HIDECLIPPEDBUTTONS); - // Configure the toolbar imagelist. - SendMessage(ToolBarHandle, TB_SETIMAGELIST, 0, (LPARAM)ToolBarImageList); - // Add the buttons to the toolbar. - ToolbarLoadButtonSettings(); - // Resize the toolbar. - SendMessage(ToolBarHandle, TB_AUTOSIZE, 0, 0); - // Query the toolbar width and height. - //SendMessage(ToolBarHandle, TB_GETMAXSIZE, 0, (LPARAM)&toolbarSize); - toolbarButtonSize = (ULONG)SendMessage(ToolBarHandle, TB_GETBUTTONSIZE, 0, 0); - - // Enable theming - // SendMessage(RebarHandle, RB_SETWINDOWTHEME, 0, (LPARAM)L"Media"); //Media/Communications/BrowserTabBar/Help - // SendMessage(ToolBarHandle, TB_SETWINDOWTHEME, 0, (LPARAM)L"Media"); //Media/Communications/BrowserTabBar/Help - - // Inset the toolbar into the rebar control. - RebarBandInsert(REBAR_BAND_ID_TOOLBAR, ToolBarHandle, LOWORD(toolbarButtonSize), HIWORD(toolbarButtonSize)); - } - - if (ToolStatusConfig.SearchBoxEnabled && !SearchboxHandle) - { - SearchboxText = PhReferenceEmptyString(); - ProcessTreeFilterEntry = PhAddTreeNewFilter(PhGetFilterSupportProcessTreeList(), (PPH_TN_FILTER_FUNCTION)ProcessTreeFilterCallback, NULL); - ServiceTreeFilterEntry = PhAddTreeNewFilter(PhGetFilterSupportServiceTreeList(), (PPH_TN_FILTER_FUNCTION)ServiceTreeFilterCallback, NULL); - NetworkTreeFilterEntry = PhAddTreeNewFilter(PhGetFilterSupportNetworkTreeList(), (PPH_TN_FILTER_FUNCTION)NetworkTreeFilterCallback, NULL); - - CreateSearchboxControl(); - } - - if (ToolStatusConfig.StatusBarEnabled && !StatusBarHandle) - { - // Create the StatusBar window. - StatusBarHandle = CreateWindowEx( - 0, - STATUSCLASSNAME, - NULL, - WS_CHILD | WS_VISIBLE | CCS_BOTTOM | SBARS_SIZEGRIP, - CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, - PhMainWndHandle, - NULL, - NULL, - NULL - ); - } - - // Hide or show controls (Note: don't unload or remove at runtime). - if (ToolStatusConfig.ToolBarEnabled) - { - if (RebarHandle && !IsWindowVisible(RebarHandle)) - ShowWindow(RebarHandle, SW_SHOW); - } - else - { - if (RebarHandle && IsWindowVisible(RebarHandle)) - ShowWindow(RebarHandle, SW_HIDE); - } - - if (ToolStatusConfig.SearchBoxEnabled && RebarHandle && SearchboxHandle) - { - UINT height = (UINT)SendMessage(RebarHandle, RB_GETROWHEIGHT, 0, 0); - - // Add the Searchbox band into the rebar control. - if (!RebarBandExists(REBAR_BAND_ID_SEARCHBOX)) - RebarBandInsert(REBAR_BAND_ID_SEARCHBOX, SearchboxHandle, PhMultiplyDivide(180, PhGlobalDpi, 96), height); - - if (!IsWindowVisible(SearchboxHandle)) - ShowWindow(SearchboxHandle, SW_SHOW); - - if (SearchBoxDisplayMode == SEARCHBOX_DISPLAY_MODE_HIDEINACTIVE) - { - if (RebarBandExists(REBAR_BAND_ID_SEARCHBOX)) - RebarBandRemove(REBAR_BAND_ID_SEARCHBOX); - } - } - else - { - // Remove the Searchbox band from the rebar control. - if (RebarBandExists(REBAR_BAND_ID_SEARCHBOX)) - RebarBandRemove(REBAR_BAND_ID_SEARCHBOX); - - if (SearchboxHandle) - { - // Clear search text and reset search filters. - SetFocus(SearchboxHandle); - Static_SetText(SearchboxHandle, L""); - - if (IsWindowVisible(SearchboxHandle)) - ShowWindow(SearchboxHandle, SW_HIDE); - } - } - - if (ToolStatusConfig.StatusBarEnabled) - { - if (StatusBarHandle && !IsWindowVisible(StatusBarHandle)) - ShowWindow(StatusBarHandle, SW_SHOW); - } - else - { - if (StatusBarHandle && IsWindowVisible(StatusBarHandle)) - ShowWindow(StatusBarHandle, SW_HIDE); - } - - ToolbarCreateGraphs(); -} - -VOID ToolbarLoadSettings( - VOID - ) -{ - RebarLoadSettings(); - - if (ToolStatusConfig.ToolBarEnabled && ToolBarHandle) - { - INT index = 0; - INT buttonCount = 0; - - buttonCount = (INT)SendMessage(ToolBarHandle, TB_BUTTONCOUNT, 0, 0); - - for (index = 0; index < buttonCount; index++) - { - TBBUTTONINFO buttonInfo = - { - sizeof(TBBUTTONINFO), - TBIF_BYINDEX | TBIF_STYLE | TBIF_COMMAND | TBIF_STATE - }; - - // Get settings for first button - if (SendMessage(ToolBarHandle, TB_GETBUTTONINFO, index, (LPARAM)&buttonInfo) == -1) - break; - - // Skip separator buttons - if (buttonInfo.fsStyle == BTNS_SEP) - continue; - - // Add the button text - buttonInfo.dwMask |= TBIF_TEXT; - buttonInfo.pszText = ToolbarGetText(buttonInfo.idCommand); - - switch (DisplayStyle) - { - case TOOLBAR_DISPLAY_STYLE_IMAGEONLY: - buttonInfo.fsStyle = BTNS_BUTTON | BTNS_AUTOSIZE; - break; - case TOOLBAR_DISPLAY_STYLE_SELECTIVETEXT: - { - switch (buttonInfo.idCommand) - { - case PHAPP_ID_VIEW_REFRESH: - case PHAPP_ID_HACKER_OPTIONS: - case PHAPP_ID_HACKER_FINDHANDLESORDLLS: - case PHAPP_ID_VIEW_SYSTEMINFORMATION: - buttonInfo.fsStyle = BTNS_BUTTON | BTNS_AUTOSIZE | BTNS_SHOWTEXT; - break; - default: - buttonInfo.fsStyle = BTNS_BUTTON | BTNS_AUTOSIZE; - break; - } - } - break; - case TOOLBAR_DISPLAY_STYLE_ALLTEXT: - buttonInfo.fsStyle = BTNS_BUTTON | BTNS_AUTOSIZE | BTNS_SHOWTEXT; - break; - } - - switch (buttonInfo.idCommand) - { - case PHAPP_ID_HACKER_SHOWDETAILSFORALLPROCESSES: - { - if (WINDOWS_HAS_UAC && PhGetOwnTokenAttributes().Elevated) - { - buttonInfo.fsState |= TBSTATE_HIDDEN; - } - } - break; - case PHAPP_ID_VIEW_ALWAYSONTOP: - { - // Set the pressed state - if (PhGetIntegerSetting(L"MainWindowAlwaysOnTop")) - { - buttonInfo.fsState |= TBSTATE_PRESSED; - } - } - break; - case TIDC_POWERMENUDROPDOWN: - { - buttonInfo.fsStyle |= BTNS_WHOLEDROPDOWN; - } - break; - } - - // Set updated button info - SendMessage(ToolBarHandle, TB_SETBUTTONINFO, index, (LPARAM)&buttonInfo); - } - - // Resize the toolbar - SendMessage(ToolBarHandle, TB_AUTOSIZE, 0, 0); - } - - if (ToolStatusConfig.ToolBarEnabled && RebarHandle && ToolBarHandle) - { - UINT index; - REBARBANDINFO rebarBandInfo = - { - sizeof(REBARBANDINFO), - RBBIM_IDEALSIZE - }; - - index = (UINT)SendMessage(RebarHandle, RB_IDTOINDEX, REBAR_BAND_ID_TOOLBAR, 0); - - // Get settings for Rebar band. - if (SendMessage(RebarHandle, RB_GETBANDINFO, index, (LPARAM)&rebarBandInfo) != -1) - { - SIZE idealWidth; - - // Reset the cxIdeal for the Chevron - SendMessage(ToolBarHandle, TB_GETIDEALSIZE, FALSE, (LPARAM)&idealWidth); - - rebarBandInfo.cxIdeal = idealWidth.cx; - - SendMessage(RebarHandle, RB_SETBANDINFO, index, (LPARAM)&rebarBandInfo); - } - } - - // Invoke the LayoutPaddingCallback. - SendMessage(PhMainWndHandle, WM_SIZE, 0, 0); -} - -VOID ToolbarResetSettings( - VOID - ) -{ - // Remove all buttons. - INT buttonCount = (INT)SendMessage(ToolBarHandle, TB_BUTTONCOUNT, 0, 0); - - while (buttonCount--) - SendMessage(ToolBarHandle, TB_DELETEBUTTON, (WPARAM)buttonCount, 0); - - // Add the default buttons. - SendMessage(ToolBarHandle, TB_ADDBUTTONS, MAX_DEFAULT_TOOLBAR_ITEMS, (LPARAM)ToolbarButtons); -} - -PWSTR ToolbarGetText( - _In_ INT CommandID - ) -{ - switch (CommandID) - { - case PHAPP_ID_VIEW_REFRESH: - return L"Refresh"; - case PHAPP_ID_HACKER_OPTIONS: - return L"Options"; - case PHAPP_ID_HACKER_FINDHANDLESORDLLS: - return L"Find handles or DLLs"; - case PHAPP_ID_VIEW_SYSTEMINFORMATION: - return L"System information"; - case TIDC_FINDWINDOW: - return L"Find window"; - case TIDC_FINDWINDOWTHREAD: - return L"Find window and thread"; - case TIDC_FINDWINDOWKILL: - return L"Find window and kill"; - case PHAPP_ID_VIEW_ALWAYSONTOP: - return L"Always on top"; - case TIDC_POWERMENUDROPDOWN: - return L"Computer"; - case PHAPP_ID_HACKER_SHOWDETAILSFORALLPROCESSES: - return L"Show details for all processes"; - } - - return L"ERROR"; -} - -HBITMAP ToolbarLoadImageFromIcon( - _In_ ULONG Width, - _In_ ULONG Height, - _In_ PWSTR Name - ) -{ - HICON icon = PhLoadIcon(PluginInstance->DllBase, Name, 0, Width, Height); - HBITMAP bitmap = PhIconToBitmap(icon, Width, Height); - DestroyIcon(icon); - return bitmap; -} - -HBITMAP ToolbarGetImage( - _In_ INT CommandID - ) -{ - switch (CommandID) - { - case PHAPP_ID_VIEW_REFRESH: - { - HBITMAP toolbarBitmap = NULL; - - if (ToolStatusConfig.ModernIcons) - { - toolbarBitmap = PhLoadPngImageFromResource(PluginInstance->DllBase, ToolBarImageSize.cx, ToolBarImageSize.cy, MAKEINTRESOURCE(IDB_ARROW_REFRESH_MODERN), FALSE); - } - else - { - toolbarBitmap = ToolbarLoadImageFromIcon(ToolBarImageSize.cx, ToolBarImageSize.cy, MAKEINTRESOURCE(IDI_ARROW_REFRESH)); - } - - return toolbarBitmap; - } - break; - case PHAPP_ID_HACKER_OPTIONS: - { - HBITMAP toolbarBitmap = NULL; - - if (ToolStatusConfig.ModernIcons) - { - toolbarBitmap = PhLoadPngImageFromResource(PluginInstance->DllBase, ToolBarImageSize.cx, ToolBarImageSize.cy, MAKEINTRESOURCE(IDB_COG_EDIT_MODERN), FALSE); - } - else - { - toolbarBitmap = ToolbarLoadImageFromIcon(ToolBarImageSize.cx, ToolBarImageSize.cy, MAKEINTRESOURCE(IDI_COG_EDIT)); - } - - return toolbarBitmap; - } - break; - case PHAPP_ID_HACKER_FINDHANDLESORDLLS: - { - HBITMAP toolbarBitmap = NULL; - - if (ToolStatusConfig.ModernIcons) - { - toolbarBitmap = PhLoadPngImageFromResource(PluginInstance->DllBase, ToolBarImageSize.cx, ToolBarImageSize.cy, MAKEINTRESOURCE(IDB_FIND_MODERN), FALSE); - } - else - { - toolbarBitmap = ToolbarLoadImageFromIcon(ToolBarImageSize.cx, ToolBarImageSize.cy, MAKEINTRESOURCE(IDI_FIND)); - } - - return toolbarBitmap; - } - break; - case PHAPP_ID_VIEW_SYSTEMINFORMATION: - { - HBITMAP toolbarBitmap = NULL; - - if (ToolStatusConfig.ModernIcons) - { - toolbarBitmap = PhLoadPngImageFromResource(PluginInstance->DllBase, ToolBarImageSize.cx, ToolBarImageSize.cy, MAKEINTRESOURCE(IDB_CHART_LINE_MODERN), FALSE); - } - else - { - toolbarBitmap = ToolbarLoadImageFromIcon(ToolBarImageSize.cx, ToolBarImageSize.cy, MAKEINTRESOURCE(IDI_CHART_LINE)); - } - - return toolbarBitmap; - } - break; - case TIDC_FINDWINDOW: - { - HBITMAP toolbarBitmap = NULL; - - if (ToolStatusConfig.ModernIcons) - { - toolbarBitmap = PhLoadPngImageFromResource(PluginInstance->DllBase, ToolBarImageSize.cx, ToolBarImageSize.cy, MAKEINTRESOURCE(IDB_APPLICATION_MODERN), FALSE); - } - else - { - toolbarBitmap = ToolbarLoadImageFromIcon(ToolBarImageSize.cx, ToolBarImageSize.cy, MAKEINTRESOURCE(IDI_TBAPPLICATION)); - } - - return toolbarBitmap; - } - break; - case TIDC_FINDWINDOWTHREAD: - { - HBITMAP toolbarBitmap = NULL; - - if (ToolStatusConfig.ModernIcons) - { - toolbarBitmap = PhLoadPngImageFromResource(PluginInstance->DllBase, ToolBarImageSize.cx, ToolBarImageSize.cy, MAKEINTRESOURCE(IDB_APPLICATION_GO_MODERN), FALSE); - } - else - { - toolbarBitmap = ToolbarLoadImageFromIcon(ToolBarImageSize.cx, ToolBarImageSize.cy, MAKEINTRESOURCE(IDI_APPLICATION_GO)); - } - - return toolbarBitmap; - } - break; - case TIDC_FINDWINDOWKILL: - { - HBITMAP toolbarBitmap = NULL; - - if (ToolStatusConfig.ModernIcons) - { - toolbarBitmap = PhLoadPngImageFromResource(PluginInstance->DllBase, ToolBarImageSize.cx, ToolBarImageSize.cy, MAKEINTRESOURCE(IDB_CROSS_MODERN), FALSE); - } - else - { - toolbarBitmap = ToolbarLoadImageFromIcon(ToolBarImageSize.cx, ToolBarImageSize.cy, MAKEINTRESOURCE(IDI_CROSS)); - } - - return toolbarBitmap; - } - break; - case PHAPP_ID_VIEW_ALWAYSONTOP: - { - HBITMAP toolbarBitmap = NULL; - - if (ToolStatusConfig.ModernIcons) - { - toolbarBitmap = PhLoadPngImageFromResource(PluginInstance->DllBase, ToolBarImageSize.cx, ToolBarImageSize.cy, MAKEINTRESOURCE(IDB_APPLICATION_GET_MODERN), FALSE); - } - else - { - toolbarBitmap = ToolbarLoadImageFromIcon(ToolBarImageSize.cx, ToolBarImageSize.cy, MAKEINTRESOURCE(IDI_APPLICATION_GET)); - } - - return toolbarBitmap; - } - break; - case TIDC_POWERMENUDROPDOWN: - { - HBITMAP toolbarBitmap = NULL; - - if (ToolStatusConfig.ModernIcons) - { - toolbarBitmap = PhLoadPngImageFromResource(PluginInstance->DllBase, ToolBarImageSize.cx, ToolBarImageSize.cy, MAKEINTRESOURCE(IDB_POWER_MODERN), FALSE); - } - else - { - toolbarBitmap = ToolbarLoadImageFromIcon(ToolBarImageSize.cx, ToolBarImageSize.cy, MAKEINTRESOURCE(IDI_LIGHTBULB_OFF)); - } - - return toolbarBitmap; - } - break; - case PHAPP_ID_HACKER_SHOWDETAILSFORALLPROCESSES: - { - HICON shieldIcon; - HBITMAP toolbarBitmap = NULL; - - if (shieldIcon = PhLoadIcon(NULL, IDI_SHIELD, PH_LOAD_ICON_SIZE_SMALL, 0, 0)) - { - toolbarBitmap = PhIconToBitmap(shieldIcon, ToolBarImageSize.cx, ToolBarImageSize.cy); - DestroyIcon(shieldIcon); - } - - return toolbarBitmap; - } - break; - } - - return NULL; -} - -VOID ToolbarLoadButtonSettings( - VOID - ) -{ - INT count; - ULONG64 countInteger; - PPH_STRING settingsString; - PTBBUTTON buttonArray; - PH_STRINGREF remaining; - PH_STRINGREF part; - - settingsString = PhaGetStringSetting(SETTING_NAME_TOOLBAR_CONFIG); - remaining = settingsString->sr; - - if (remaining.Length == 0) - { - // Load default settings - SendMessage(ToolBarHandle, TB_ADDBUTTONS, MAX_DEFAULT_TOOLBAR_ITEMS, (LPARAM)ToolbarButtons); - return; - } - - // Query the number of buttons to insert - if (!PhSplitStringRefAtChar(&remaining, '|', &part, &remaining)) - { - // Load default settings - SendMessage(ToolBarHandle, TB_ADDBUTTONS, MAX_DEFAULT_TOOLBAR_ITEMS, (LPARAM)ToolbarButtons); - return; - } - - if (!PhStringToInteger64(&part, 10, &countInteger)) - { - // Load default settings - SendMessage(ToolBarHandle, TB_ADDBUTTONS, MAX_DEFAULT_TOOLBAR_ITEMS, (LPARAM)ToolbarButtons); - return; - } - - count = (INT)countInteger; - - // Allocate the button array - buttonArray = PhAllocate(count * sizeof(TBBUTTON)); - memset(buttonArray, 0, count * sizeof(TBBUTTON)); - - for (INT index = 0; index < count; index++) - { - ULONG64 commandInteger; - PH_STRINGREF commandIdPart; - - if (remaining.Length == 0) - break; - - PhSplitStringRefAtChar(&remaining, '|', &commandIdPart, &remaining); - PhStringToInteger64(&commandIdPart, 10, &commandInteger); - - buttonArray[index].idCommand = (INT)commandInteger; - //buttonArray[index].iBitmap = I_IMAGECALLBACK; - buttonArray[index].fsState = TBSTATE_ENABLED; - - if (commandInteger) - { - buttonArray[index].fsStyle = BTNS_BUTTON | BTNS_AUTOSIZE; - } - else - { - buttonArray[index].fsStyle = BTNS_SEP; - } - - // Pre-cache the image in the Toolbar array on startup. - for (INT i = 0; i < ARRAYSIZE(ToolbarButtons); i++) - { - if (ToolbarButtons[i].idCommand == buttonArray[index].idCommand) - { - HBITMAP bitmap; - - bitmap = ToolbarGetImage(ToolbarButtons[i].idCommand); - - // Add the image, cache the value in the ToolbarButtons array, set the bitmap index. - buttonArray[index].iBitmap = ToolbarButtons[i].iBitmap = ImageList_Add( - ToolBarImageList, - bitmap, - NULL - ); - - DeleteObject(bitmap); - break; - } - } - } - - SendMessage(ToolBarHandle, TB_ADDBUTTONS, count, (LPARAM)buttonArray); - - PhFree(buttonArray); -} - -VOID ToolbarSaveButtonSettings( - VOID - ) -{ - INT index = 0; - INT count = 0; - PPH_STRING settingsString; - PH_STRING_BUILDER stringBuilder; - - PhInitializeStringBuilder(&stringBuilder, 100); - - count = (INT)SendMessage(ToolBarHandle, TB_BUTTONCOUNT, 0, 0); - - PhAppendFormatStringBuilder( - &stringBuilder, - L"%d|", - count - ); - - for (index = 0; index < count; index++) - { - TBBUTTONINFO buttonInfo = - { - sizeof(TBBUTTONINFO), - TBIF_BYINDEX | TBIF_IMAGE | TBIF_STYLE | TBIF_COMMAND - }; - - if (SendMessage(ToolBarHandle, TB_GETBUTTONINFO, index, (LPARAM)&buttonInfo) == -1) - break; - - PhAppendFormatStringBuilder( - &stringBuilder, - L"%d|", - buttonInfo.idCommand - ); - } - - if (stringBuilder.String->Length != 0) - PhRemoveEndStringBuilder(&stringBuilder, 1); - - settingsString = PH_AUTO(PhFinalStringBuilderString(&stringBuilder)); - PhSetStringSetting2(SETTING_NAME_TOOLBAR_CONFIG, &settingsString->sr); -} - -VOID ReBarLoadLayoutSettings( - VOID - ) -{ - UINT index = 0; - UINT count = 0; - PPH_STRING settingsString; - PH_STRINGREF remaining; - - settingsString = PhGetStringSetting(SETTING_NAME_REBAR_CONFIG); - remaining = settingsString->sr; - - if (remaining.Length == 0) - return; - - count = (UINT)SendMessage(RebarHandle, RB_GETBANDCOUNT, 0, 0); - - for (index = 0; index < count; index++) - { - PH_STRINGREF idPart; - PH_STRINGREF cxPart; - PH_STRINGREF stylePart; - ULONG64 idInteger; - ULONG64 cxInteger; - ULONG64 styleInteger; - UINT oldBandIndex; - REBARBANDINFO rebarBandInfo = - { - sizeof(REBARBANDINFO), - RBBIM_STYLE | RBBIM_SIZE - }; - - if (remaining.Length == 0) - break; - - PhSplitStringRefAtChar(&remaining, '|', &idPart, &remaining); - PhSplitStringRefAtChar(&remaining, '|', &cxPart, &remaining); - PhSplitStringRefAtChar(&remaining, '|', &stylePart, &remaining); - - PhStringToInteger64(&idPart, 10, &idInteger); - PhStringToInteger64(&cxPart, 10, &cxInteger); - PhStringToInteger64(&stylePart, 10, &styleInteger); - - if ((oldBandIndex = (UINT)SendMessage(RebarHandle, RB_IDTOINDEX, (UINT)idInteger, 0)) == -1) - break; - - if (oldBandIndex != index) - { - SendMessage(RebarHandle, RB_MOVEBAND, oldBandIndex, index); - } - - if (SendMessage(RebarHandle, RB_GETBANDINFO, index, (LPARAM)&rebarBandInfo)) - { - rebarBandInfo.cx = (UINT)cxInteger; - rebarBandInfo.fStyle |= (UINT)styleInteger; - - SendMessage(RebarHandle, RB_SETBANDINFO, index, (LPARAM)&rebarBandInfo); - } - } -} - -VOID ReBarSaveLayoutSettings( - VOID - ) -{ - UINT index = 0; - UINT count = 0; - PPH_STRING settingsString; - PH_STRING_BUILDER stringBuilder; - - PhInitializeStringBuilder(&stringBuilder, 100); - - count = (UINT)SendMessage(RebarHandle, RB_GETBANDCOUNT, 0, 0); - - for (index = 0; index < count; index++) - { - REBARBANDINFO rebarBandInfo = - { - sizeof(REBARBANDINFO), - RBBIM_STYLE | RBBIM_SIZE | RBBIM_ID - }; - - SendMessage(RebarHandle, RB_GETBANDINFO, index, (LPARAM)&rebarBandInfo); - - if (rebarBandInfo.fStyle & RBBS_GRIPPERALWAYS) - { - rebarBandInfo.fStyle &= ~RBBS_GRIPPERALWAYS; - } - - if (rebarBandInfo.fStyle & RBBS_NOGRIPPER) - { - rebarBandInfo.fStyle &= ~RBBS_NOGRIPPER; - } - - if (rebarBandInfo.fStyle & RBBS_FIXEDSIZE) - { - rebarBandInfo.fStyle &= ~RBBS_FIXEDSIZE; - } - - PhAppendFormatStringBuilder( - &stringBuilder, - L"%u|%u|%u|", - rebarBandInfo.wID, - rebarBandInfo.cx, - rebarBandInfo.fStyle - ); - } - - if (stringBuilder.String->Length != 0) - PhRemoveEndStringBuilder(&stringBuilder, 1); - - settingsString = PH_AUTO(PhFinalStringBuilderString(&stringBuilder)); - PhSetStringSetting2(SETTING_NAME_REBAR_CONFIG, &settingsString->sr); +/* + * Process Hacker ToolStatus - + * main toolbar + * + * Copyright (C) 2011-2016 dmex + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include "toolstatus.h" +#include "commonutil.h" + +SIZE ToolBarImageSize = { 16, 16 }; +HIMAGELIST ToolBarImageList = NULL; + +TBBUTTON ToolbarButtons[MAX_TOOLBAR_ITEMS] = +{ + // Default toolbar buttons (displayed) + { I_IMAGECALLBACK, PHAPP_ID_VIEW_REFRESH, TBSTATE_ENABLED, BTNS_BUTTON | BTNS_AUTOSIZE | BTNS_SHOWTEXT, { 0 }, 0, 0 }, + { I_IMAGECALLBACK, PHAPP_ID_HACKER_OPTIONS, TBSTATE_ENABLED, BTNS_BUTTON | BTNS_AUTOSIZE | BTNS_SHOWTEXT, { 0 }, 0, 0 }, + { 0, 0, 0, BTNS_SEP, { 0 }, 0, 0 }, + { I_IMAGECALLBACK, PHAPP_ID_HACKER_FINDHANDLESORDLLS, TBSTATE_ENABLED, BTNS_BUTTON | BTNS_AUTOSIZE | BTNS_SHOWTEXT, { 0 }, 0, 0 }, + { I_IMAGECALLBACK, PHAPP_ID_VIEW_SYSTEMINFORMATION, TBSTATE_ENABLED, BTNS_BUTTON | BTNS_AUTOSIZE | BTNS_SHOWTEXT, { 0 }, 0, 0 }, + { 0, 0, 0, BTNS_SEP, { 0 }, 0, 0 }, + { I_IMAGECALLBACK, TIDC_FINDWINDOW, TBSTATE_ENABLED, BTNS_BUTTON | BTNS_AUTOSIZE | BTNS_SHOWTEXT, { 0 }, 0, 0 }, + { I_IMAGECALLBACK, TIDC_FINDWINDOWTHREAD, TBSTATE_ENABLED, BTNS_BUTTON | BTNS_AUTOSIZE | BTNS_SHOWTEXT, { 0 }, 0, 0 }, + { I_IMAGECALLBACK, TIDC_FINDWINDOWKILL, TBSTATE_ENABLED, BTNS_BUTTON | BTNS_AUTOSIZE | BTNS_SHOWTEXT, { 0 }, 0, 0 }, + // Available toolbar buttons (hidden) + { I_IMAGECALLBACK, PHAPP_ID_VIEW_ALWAYSONTOP, TBSTATE_ENABLED, BTNS_BUTTON | BTNS_AUTOSIZE | BTNS_SHOWTEXT, { 0 }, 0, 0 }, + { I_IMAGECALLBACK, TIDC_POWERMENUDROPDOWN, TBSTATE_ENABLED, BTNS_WHOLEDROPDOWN | BTNS_BUTTON | BTNS_AUTOSIZE | BTNS_SHOWTEXT,{ 0 }, 0, 0 }, + { I_IMAGECALLBACK, PHAPP_ID_HACKER_SHOWDETAILSFORALLPROCESSES, TBSTATE_ENABLED, BTNS_BUTTON | BTNS_AUTOSIZE | BTNS_SHOWTEXT,{ 0 }, 0, 0 }, +}; + +VOID RebarBandInsert( + _In_ UINT BandID, + _In_ HWND HwndChild, + _In_ UINT cxMinChild, + _In_ UINT cyMinChild + ) +{ + UINT index; + REBARBANDINFO rebarBandInfo = + { + sizeof(REBARBANDINFO), + RBBIM_STYLE | RBBIM_ID | RBBIM_CHILD | RBBIM_CHILDSIZE, + RBBS_USECHEVRON // RBBS_NOGRIPPER | RBBS_HIDETITLE | RBBS_TOPALIGN + }; + + rebarBandInfo.wID = BandID; + rebarBandInfo.hwndChild = HwndChild; + rebarBandInfo.cxMinChild = cxMinChild; + rebarBandInfo.cyMinChild = cyMinChild; + + if (ToolStatusConfig.ToolBarLocked) + { + rebarBandInfo.fStyle |= RBBS_NOGRIPPER; + } + + if ((index = (UINT)SendMessage(RebarHandle, RB_IDTOINDEX, REBAR_BAND_ID_SEARCHBOX, 0)) != -1) + { + SendMessage(RebarHandle, RB_INSERTBAND, (WPARAM)index, (LPARAM)&rebarBandInfo); + } + else + { + SendMessage(RebarHandle, RB_INSERTBAND, (WPARAM)-1, (LPARAM)&rebarBandInfo); + } +} + +VOID RebarBandRemove( + _In_ UINT BandID + ) +{ + UINT index = (UINT)SendMessage(RebarHandle, RB_IDTOINDEX, (WPARAM)BandID, 0); + + if (index == -1) + return; + + SendMessage(RebarHandle, RB_DELETEBAND, (WPARAM)index, 0); +} + +BOOLEAN RebarBandExists( + _In_ UINT BandID + ) +{ + UINT index = (UINT)SendMessage(RebarHandle, RB_IDTOINDEX, (WPARAM)BandID, 0); + + if (index != -1) + return TRUE; + + return FALSE; +} + +VOID RebarLoadSettings( + VOID + ) +{ + if (ToolStatusConfig.ToolBarEnabled && !ToolBarImageList) + { + ToolBarImageList = ImageList_Create(ToolBarImageSize.cx, ToolBarImageSize.cy, ILC_COLOR32, 0, 0); + } + + if (ToolStatusConfig.ToolBarEnabled && !RebarHandle) + { + REBARINFO rebarInfo = { sizeof(REBARINFO) }; + ULONG toolbarButtonSize; + + RebarHandle = CreateWindowEx( + WS_EX_TOOLWINDOW, + REBARCLASSNAME, + NULL, + WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | CCS_NODIVIDER | CCS_TOP | RBS_VARHEIGHT | RBS_AUTOSIZE, // CCS_NOPARENTALIGN | RBS_FIXEDORDER + CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, + PhMainWndHandle, + NULL, + NULL, + NULL + ); + + ToolBarHandle = CreateWindowEx( + 0, + TOOLBARCLASSNAME, + NULL, + WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | CCS_NORESIZE | CCS_NOPARENTALIGN | CCS_NODIVIDER | TBSTYLE_FLAT | TBSTYLE_LIST | TBSTYLE_TRANSPARENT | TBSTYLE_TOOLTIPS | TBSTYLE_AUTOSIZE, // TBSTYLE_CUSTOMERASE TBSTYLE_ALTDRAG + CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, + RebarHandle, + NULL, + NULL, + NULL + ); + + // Set the toolbar info with no imagelist. + SendMessage(RebarHandle, RB_SETBARINFO, 0, (LPARAM)&rebarInfo); + // Set the toolbar struct size. + SendMessage(ToolBarHandle, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0); + // Set the toolbar extended toolbar styles. + SendMessage(ToolBarHandle, TB_SETEXTENDEDSTYLE, 0, TBSTYLE_EX_DOUBLEBUFFER | TBSTYLE_EX_MIXEDBUTTONS | TBSTYLE_EX_HIDECLIPPEDBUTTONS); + // Configure the toolbar imagelist. + SendMessage(ToolBarHandle, TB_SETIMAGELIST, 0, (LPARAM)ToolBarImageList); + // Add the buttons to the toolbar. + ToolbarLoadButtonSettings(); + // Resize the toolbar. + SendMessage(ToolBarHandle, TB_AUTOSIZE, 0, 0); + // Query the toolbar width and height. + //SendMessage(ToolBarHandle, TB_GETMAXSIZE, 0, (LPARAM)&toolbarSize); + toolbarButtonSize = (ULONG)SendMessage(ToolBarHandle, TB_GETBUTTONSIZE, 0, 0); + + // Enable theming + // SendMessage(RebarHandle, RB_SETWINDOWTHEME, 0, (LPARAM)L"Media"); //Media/Communications/BrowserTabBar/Help + // SendMessage(ToolBarHandle, TB_SETWINDOWTHEME, 0, (LPARAM)L"Media"); //Media/Communications/BrowserTabBar/Help + + // Inset the toolbar into the rebar control. + RebarBandInsert(REBAR_BAND_ID_TOOLBAR, ToolBarHandle, LOWORD(toolbarButtonSize), HIWORD(toolbarButtonSize)); + } + + if (ToolStatusConfig.SearchBoxEnabled && !SearchboxHandle) + { + SearchboxText = PhReferenceEmptyString(); + ProcessTreeFilterEntry = PhAddTreeNewFilter(PhGetFilterSupportProcessTreeList(), (PPH_TN_FILTER_FUNCTION)ProcessTreeFilterCallback, NULL); + ServiceTreeFilterEntry = PhAddTreeNewFilter(PhGetFilterSupportServiceTreeList(), (PPH_TN_FILTER_FUNCTION)ServiceTreeFilterCallback, NULL); + NetworkTreeFilterEntry = PhAddTreeNewFilter(PhGetFilterSupportNetworkTreeList(), (PPH_TN_FILTER_FUNCTION)NetworkTreeFilterCallback, NULL); + + CreateSearchboxControl(); + } + + if (ToolStatusConfig.StatusBarEnabled && !StatusBarHandle) + { + // Create the StatusBar window. + StatusBarHandle = CreateWindowEx( + 0, + STATUSCLASSNAME, + NULL, + WS_CHILD | WS_VISIBLE | CCS_BOTTOM | SBARS_SIZEGRIP, + CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, + PhMainWndHandle, + NULL, + NULL, + NULL + ); + } + + // Hide or show controls (Note: don't unload or remove at runtime). + if (ToolStatusConfig.ToolBarEnabled) + { + if (RebarHandle && !IsWindowVisible(RebarHandle)) + ShowWindow(RebarHandle, SW_SHOW); + } + else + { + if (RebarHandle && IsWindowVisible(RebarHandle)) + ShowWindow(RebarHandle, SW_HIDE); + } + + if (ToolStatusConfig.SearchBoxEnabled && RebarHandle && SearchboxHandle) + { + UINT height = (UINT)SendMessage(RebarHandle, RB_GETROWHEIGHT, 0, 0); + + // Add the Searchbox band into the rebar control. + if (!RebarBandExists(REBAR_BAND_ID_SEARCHBOX)) + RebarBandInsert(REBAR_BAND_ID_SEARCHBOX, SearchboxHandle, PhMultiplyDivide(180, PhGlobalDpi, 96), height); + + if (!IsWindowVisible(SearchboxHandle)) + ShowWindow(SearchboxHandle, SW_SHOW); + + if (SearchBoxDisplayMode == SEARCHBOX_DISPLAY_MODE_HIDEINACTIVE) + { + if (RebarBandExists(REBAR_BAND_ID_SEARCHBOX)) + RebarBandRemove(REBAR_BAND_ID_SEARCHBOX); + } + } + else + { + // Remove the Searchbox band from the rebar control. + if (RebarBandExists(REBAR_BAND_ID_SEARCHBOX)) + RebarBandRemove(REBAR_BAND_ID_SEARCHBOX); + + if (SearchboxHandle) + { + // Clear search text and reset search filters. + SetFocus(SearchboxHandle); + Static_SetText(SearchboxHandle, L""); + + if (IsWindowVisible(SearchboxHandle)) + ShowWindow(SearchboxHandle, SW_HIDE); + } + } + + if (ToolStatusConfig.StatusBarEnabled) + { + if (StatusBarHandle && !IsWindowVisible(StatusBarHandle)) + ShowWindow(StatusBarHandle, SW_SHOW); + } + else + { + if (StatusBarHandle && IsWindowVisible(StatusBarHandle)) + ShowWindow(StatusBarHandle, SW_HIDE); + } + + ToolbarCreateGraphs(); +} + +VOID ToolbarLoadSettings( + VOID + ) +{ + RebarLoadSettings(); + + if (ToolStatusConfig.ToolBarEnabled && ToolBarHandle) + { + INT index = 0; + INT buttonCount = 0; + + buttonCount = (INT)SendMessage(ToolBarHandle, TB_BUTTONCOUNT, 0, 0); + + for (index = 0; index < buttonCount; index++) + { + TBBUTTONINFO buttonInfo = + { + sizeof(TBBUTTONINFO), + TBIF_BYINDEX | TBIF_STYLE | TBIF_COMMAND | TBIF_STATE + }; + + // Get settings for first button + if (SendMessage(ToolBarHandle, TB_GETBUTTONINFO, index, (LPARAM)&buttonInfo) == -1) + break; + + // Skip separator buttons + if (buttonInfo.fsStyle == BTNS_SEP) + continue; + + // Add the button text + buttonInfo.dwMask |= TBIF_TEXT; + buttonInfo.pszText = ToolbarGetText(buttonInfo.idCommand); + + switch (DisplayStyle) + { + case TOOLBAR_DISPLAY_STYLE_IMAGEONLY: + buttonInfo.fsStyle = BTNS_BUTTON | BTNS_AUTOSIZE; + break; + case TOOLBAR_DISPLAY_STYLE_SELECTIVETEXT: + { + switch (buttonInfo.idCommand) + { + case PHAPP_ID_VIEW_REFRESH: + case PHAPP_ID_HACKER_OPTIONS: + case PHAPP_ID_HACKER_FINDHANDLESORDLLS: + case PHAPP_ID_VIEW_SYSTEMINFORMATION: + buttonInfo.fsStyle = BTNS_BUTTON | BTNS_AUTOSIZE | BTNS_SHOWTEXT; + break; + default: + buttonInfo.fsStyle = BTNS_BUTTON | BTNS_AUTOSIZE; + break; + } + } + break; + case TOOLBAR_DISPLAY_STYLE_ALLTEXT: + buttonInfo.fsStyle = BTNS_BUTTON | BTNS_AUTOSIZE | BTNS_SHOWTEXT; + break; + } + + switch (buttonInfo.idCommand) + { + case PHAPP_ID_HACKER_SHOWDETAILSFORALLPROCESSES: + { + if (WINDOWS_HAS_UAC && PhGetOwnTokenAttributes().Elevated) + { + buttonInfo.fsState |= TBSTATE_HIDDEN; + } + } + break; + case PHAPP_ID_VIEW_ALWAYSONTOP: + { + // Set the pressed state + if (PhGetIntegerSetting(L"MainWindowAlwaysOnTop")) + { + buttonInfo.fsState |= TBSTATE_PRESSED; + } + } + break; + case TIDC_POWERMENUDROPDOWN: + { + buttonInfo.fsStyle |= BTNS_WHOLEDROPDOWN; + } + break; + } + + // Set updated button info + SendMessage(ToolBarHandle, TB_SETBUTTONINFO, index, (LPARAM)&buttonInfo); + } + + // Resize the toolbar + SendMessage(ToolBarHandle, TB_AUTOSIZE, 0, 0); + } + + if (ToolStatusConfig.ToolBarEnabled && RebarHandle && ToolBarHandle) + { + UINT index; + REBARBANDINFO rebarBandInfo = + { + sizeof(REBARBANDINFO), + RBBIM_IDEALSIZE + }; + + index = (UINT)SendMessage(RebarHandle, RB_IDTOINDEX, REBAR_BAND_ID_TOOLBAR, 0); + + // Get settings for Rebar band. + if (SendMessage(RebarHandle, RB_GETBANDINFO, index, (LPARAM)&rebarBandInfo) != -1) + { + SIZE idealWidth; + + // Reset the cxIdeal for the Chevron + SendMessage(ToolBarHandle, TB_GETIDEALSIZE, FALSE, (LPARAM)&idealWidth); + + rebarBandInfo.cxIdeal = idealWidth.cx; + + SendMessage(RebarHandle, RB_SETBANDINFO, index, (LPARAM)&rebarBandInfo); + } + } + + // Invoke the LayoutPaddingCallback. + SendMessage(PhMainWndHandle, WM_SIZE, 0, 0); +} + +VOID ToolbarResetSettings( + VOID + ) +{ + // Remove all buttons. + INT buttonCount = (INT)SendMessage(ToolBarHandle, TB_BUTTONCOUNT, 0, 0); + + while (buttonCount--) + SendMessage(ToolBarHandle, TB_DELETEBUTTON, (WPARAM)buttonCount, 0); + + // Add the default buttons. + SendMessage(ToolBarHandle, TB_ADDBUTTONS, MAX_DEFAULT_TOOLBAR_ITEMS, (LPARAM)ToolbarButtons); +} + +PWSTR ToolbarGetText( + _In_ INT CommandID + ) +{ + switch (CommandID) + { + case PHAPP_ID_VIEW_REFRESH: + return L"Refresh"; + case PHAPP_ID_HACKER_OPTIONS: + return L"Options"; + case PHAPP_ID_HACKER_FINDHANDLESORDLLS: + return L"Find handles or DLLs"; + case PHAPP_ID_VIEW_SYSTEMINFORMATION: + return L"System information"; + case TIDC_FINDWINDOW: + return L"Find window"; + case TIDC_FINDWINDOWTHREAD: + return L"Find window and thread"; + case TIDC_FINDWINDOWKILL: + return L"Find window and kill"; + case PHAPP_ID_VIEW_ALWAYSONTOP: + return L"Always on top"; + case TIDC_POWERMENUDROPDOWN: + return L"Computer"; + case PHAPP_ID_HACKER_SHOWDETAILSFORALLPROCESSES: + return L"Show details for all processes"; + } + + return L"ERROR"; +} + +HBITMAP ToolbarLoadImageFromIcon( + _In_ ULONG Width, + _In_ ULONG Height, + _In_ PWSTR Name + ) +{ + HICON icon = PhLoadIcon(PluginInstance->DllBase, Name, 0, Width, Height); + HBITMAP bitmap = PhIconToBitmap(icon, Width, Height); + DestroyIcon(icon); + return bitmap; +} + +HBITMAP ToolbarGetImage( + _In_ INT CommandID + ) +{ + switch (CommandID) + { + case PHAPP_ID_VIEW_REFRESH: + { + HBITMAP toolbarBitmap = NULL; + + if (ToolStatusConfig.ModernIcons) + { + toolbarBitmap = PhLoadPngImageFromResource(PluginInstance->DllBase, ToolBarImageSize.cx, ToolBarImageSize.cy, MAKEINTRESOURCE(IDB_ARROW_REFRESH_MODERN), FALSE); + } + else + { + toolbarBitmap = ToolbarLoadImageFromIcon(ToolBarImageSize.cx, ToolBarImageSize.cy, MAKEINTRESOURCE(IDI_ARROW_REFRESH)); + } + + return toolbarBitmap; + } + break; + case PHAPP_ID_HACKER_OPTIONS: + { + HBITMAP toolbarBitmap = NULL; + + if (ToolStatusConfig.ModernIcons) + { + toolbarBitmap = PhLoadPngImageFromResource(PluginInstance->DllBase, ToolBarImageSize.cx, ToolBarImageSize.cy, MAKEINTRESOURCE(IDB_COG_EDIT_MODERN), FALSE); + } + else + { + toolbarBitmap = ToolbarLoadImageFromIcon(ToolBarImageSize.cx, ToolBarImageSize.cy, MAKEINTRESOURCE(IDI_COG_EDIT)); + } + + return toolbarBitmap; + } + break; + case PHAPP_ID_HACKER_FINDHANDLESORDLLS: + { + HBITMAP toolbarBitmap = NULL; + + if (ToolStatusConfig.ModernIcons) + { + toolbarBitmap = PhLoadPngImageFromResource(PluginInstance->DllBase, ToolBarImageSize.cx, ToolBarImageSize.cy, MAKEINTRESOURCE(IDB_FIND_MODERN), FALSE); + } + else + { + toolbarBitmap = ToolbarLoadImageFromIcon(ToolBarImageSize.cx, ToolBarImageSize.cy, MAKEINTRESOURCE(IDI_FIND)); + } + + return toolbarBitmap; + } + break; + case PHAPP_ID_VIEW_SYSTEMINFORMATION: + { + HBITMAP toolbarBitmap = NULL; + + if (ToolStatusConfig.ModernIcons) + { + toolbarBitmap = PhLoadPngImageFromResource(PluginInstance->DllBase, ToolBarImageSize.cx, ToolBarImageSize.cy, MAKEINTRESOURCE(IDB_CHART_LINE_MODERN), FALSE); + } + else + { + toolbarBitmap = ToolbarLoadImageFromIcon(ToolBarImageSize.cx, ToolBarImageSize.cy, MAKEINTRESOURCE(IDI_CHART_LINE)); + } + + return toolbarBitmap; + } + break; + case TIDC_FINDWINDOW: + { + HBITMAP toolbarBitmap = NULL; + + if (ToolStatusConfig.ModernIcons) + { + toolbarBitmap = PhLoadPngImageFromResource(PluginInstance->DllBase, ToolBarImageSize.cx, ToolBarImageSize.cy, MAKEINTRESOURCE(IDB_APPLICATION_MODERN), FALSE); + } + else + { + toolbarBitmap = ToolbarLoadImageFromIcon(ToolBarImageSize.cx, ToolBarImageSize.cy, MAKEINTRESOURCE(IDI_TBAPPLICATION)); + } + + return toolbarBitmap; + } + break; + case TIDC_FINDWINDOWTHREAD: + { + HBITMAP toolbarBitmap = NULL; + + if (ToolStatusConfig.ModernIcons) + { + toolbarBitmap = PhLoadPngImageFromResource(PluginInstance->DllBase, ToolBarImageSize.cx, ToolBarImageSize.cy, MAKEINTRESOURCE(IDB_APPLICATION_GO_MODERN), FALSE); + } + else + { + toolbarBitmap = ToolbarLoadImageFromIcon(ToolBarImageSize.cx, ToolBarImageSize.cy, MAKEINTRESOURCE(IDI_APPLICATION_GO)); + } + + return toolbarBitmap; + } + break; + case TIDC_FINDWINDOWKILL: + { + HBITMAP toolbarBitmap = NULL; + + if (ToolStatusConfig.ModernIcons) + { + toolbarBitmap = PhLoadPngImageFromResource(PluginInstance->DllBase, ToolBarImageSize.cx, ToolBarImageSize.cy, MAKEINTRESOURCE(IDB_CROSS_MODERN), FALSE); + } + else + { + toolbarBitmap = ToolbarLoadImageFromIcon(ToolBarImageSize.cx, ToolBarImageSize.cy, MAKEINTRESOURCE(IDI_CROSS)); + } + + return toolbarBitmap; + } + break; + case PHAPP_ID_VIEW_ALWAYSONTOP: + { + HBITMAP toolbarBitmap = NULL; + + if (ToolStatusConfig.ModernIcons) + { + toolbarBitmap = PhLoadPngImageFromResource(PluginInstance->DllBase, ToolBarImageSize.cx, ToolBarImageSize.cy, MAKEINTRESOURCE(IDB_APPLICATION_GET_MODERN), FALSE); + } + else + { + toolbarBitmap = ToolbarLoadImageFromIcon(ToolBarImageSize.cx, ToolBarImageSize.cy, MAKEINTRESOURCE(IDI_APPLICATION_GET)); + } + + return toolbarBitmap; + } + break; + case TIDC_POWERMENUDROPDOWN: + { + HBITMAP toolbarBitmap = NULL; + + if (ToolStatusConfig.ModernIcons) + { + toolbarBitmap = PhLoadPngImageFromResource(PluginInstance->DllBase, ToolBarImageSize.cx, ToolBarImageSize.cy, MAKEINTRESOURCE(IDB_POWER_MODERN), FALSE); + } + else + { + toolbarBitmap = ToolbarLoadImageFromIcon(ToolBarImageSize.cx, ToolBarImageSize.cy, MAKEINTRESOURCE(IDI_LIGHTBULB_OFF)); + } + + return toolbarBitmap; + } + break; + case PHAPP_ID_HACKER_SHOWDETAILSFORALLPROCESSES: + { + HICON shieldIcon; + HBITMAP toolbarBitmap = NULL; + + if (shieldIcon = PhLoadIcon(NULL, IDI_SHIELD, PH_LOAD_ICON_SIZE_SMALL, 0, 0)) + { + toolbarBitmap = PhIconToBitmap(shieldIcon, ToolBarImageSize.cx, ToolBarImageSize.cy); + DestroyIcon(shieldIcon); + } + + return toolbarBitmap; + } + break; + } + + return NULL; +} + +VOID ToolbarLoadButtonSettings( + VOID + ) +{ + INT count; + ULONG64 countInteger; + PPH_STRING settingsString; + PTBBUTTON buttonArray; + PH_STRINGREF remaining; + PH_STRINGREF part; + + settingsString = PhaGetStringSetting(SETTING_NAME_TOOLBAR_CONFIG); + remaining = settingsString->sr; + + if (remaining.Length == 0) + { + // Load default settings + SendMessage(ToolBarHandle, TB_ADDBUTTONS, MAX_DEFAULT_TOOLBAR_ITEMS, (LPARAM)ToolbarButtons); + return; + } + + // Query the number of buttons to insert + if (!PhSplitStringRefAtChar(&remaining, '|', &part, &remaining)) + { + // Load default settings + SendMessage(ToolBarHandle, TB_ADDBUTTONS, MAX_DEFAULT_TOOLBAR_ITEMS, (LPARAM)ToolbarButtons); + return; + } + + if (!PhStringToInteger64(&part, 10, &countInteger)) + { + // Load default settings + SendMessage(ToolBarHandle, TB_ADDBUTTONS, MAX_DEFAULT_TOOLBAR_ITEMS, (LPARAM)ToolbarButtons); + return; + } + + count = (INT)countInteger; + + // Allocate the button array + buttonArray = PhAllocate(count * sizeof(TBBUTTON)); + memset(buttonArray, 0, count * sizeof(TBBUTTON)); + + for (INT index = 0; index < count; index++) + { + ULONG64 commandInteger; + PH_STRINGREF commandIdPart; + + if (remaining.Length == 0) + break; + + PhSplitStringRefAtChar(&remaining, '|', &commandIdPart, &remaining); + PhStringToInteger64(&commandIdPart, 10, &commandInteger); + + buttonArray[index].idCommand = (INT)commandInteger; + //buttonArray[index].iBitmap = I_IMAGECALLBACK; + buttonArray[index].fsState = TBSTATE_ENABLED; + + if (commandInteger) + { + buttonArray[index].fsStyle = BTNS_BUTTON | BTNS_AUTOSIZE; + } + else + { + buttonArray[index].fsStyle = BTNS_SEP; + } + + // Pre-cache the image in the Toolbar array on startup. + for (INT i = 0; i < ARRAYSIZE(ToolbarButtons); i++) + { + if (ToolbarButtons[i].idCommand == buttonArray[index].idCommand) + { + HBITMAP bitmap; + + bitmap = ToolbarGetImage(ToolbarButtons[i].idCommand); + + // Add the image, cache the value in the ToolbarButtons array, set the bitmap index. + buttonArray[index].iBitmap = ToolbarButtons[i].iBitmap = ImageList_Add( + ToolBarImageList, + bitmap, + NULL + ); + + DeleteObject(bitmap); + break; + } + } + } + + SendMessage(ToolBarHandle, TB_ADDBUTTONS, count, (LPARAM)buttonArray); + + PhFree(buttonArray); +} + +VOID ToolbarSaveButtonSettings( + VOID + ) +{ + INT index = 0; + INT count = 0; + PPH_STRING settingsString; + PH_STRING_BUILDER stringBuilder; + + PhInitializeStringBuilder(&stringBuilder, 100); + + count = (INT)SendMessage(ToolBarHandle, TB_BUTTONCOUNT, 0, 0); + + PhAppendFormatStringBuilder( + &stringBuilder, + L"%d|", + count + ); + + for (index = 0; index < count; index++) + { + TBBUTTONINFO buttonInfo = + { + sizeof(TBBUTTONINFO), + TBIF_BYINDEX | TBIF_IMAGE | TBIF_STYLE | TBIF_COMMAND + }; + + if (SendMessage(ToolBarHandle, TB_GETBUTTONINFO, index, (LPARAM)&buttonInfo) == -1) + break; + + PhAppendFormatStringBuilder( + &stringBuilder, + L"%d|", + buttonInfo.idCommand + ); + } + + if (stringBuilder.String->Length != 0) + PhRemoveEndStringBuilder(&stringBuilder, 1); + + settingsString = PH_AUTO(PhFinalStringBuilderString(&stringBuilder)); + PhSetStringSetting2(SETTING_NAME_TOOLBAR_CONFIG, &settingsString->sr); +} + +VOID ReBarLoadLayoutSettings( + VOID + ) +{ + UINT index = 0; + UINT count = 0; + PPH_STRING settingsString; + PH_STRINGREF remaining; + + settingsString = PhGetStringSetting(SETTING_NAME_REBAR_CONFIG); + remaining = settingsString->sr; + + if (remaining.Length == 0) + return; + + count = (UINT)SendMessage(RebarHandle, RB_GETBANDCOUNT, 0, 0); + + for (index = 0; index < count; index++) + { + PH_STRINGREF idPart; + PH_STRINGREF cxPart; + PH_STRINGREF stylePart; + ULONG64 idInteger; + ULONG64 cxInteger; + ULONG64 styleInteger; + UINT oldBandIndex; + REBARBANDINFO rebarBandInfo = + { + sizeof(REBARBANDINFO), + RBBIM_STYLE | RBBIM_SIZE + }; + + if (remaining.Length == 0) + break; + + PhSplitStringRefAtChar(&remaining, '|', &idPart, &remaining); + PhSplitStringRefAtChar(&remaining, '|', &cxPart, &remaining); + PhSplitStringRefAtChar(&remaining, '|', &stylePart, &remaining); + + PhStringToInteger64(&idPart, 10, &idInteger); + PhStringToInteger64(&cxPart, 10, &cxInteger); + PhStringToInteger64(&stylePart, 10, &styleInteger); + + if ((oldBandIndex = (UINT)SendMessage(RebarHandle, RB_IDTOINDEX, (UINT)idInteger, 0)) == -1) + break; + + if (oldBandIndex != index) + { + SendMessage(RebarHandle, RB_MOVEBAND, oldBandIndex, index); + } + + if (SendMessage(RebarHandle, RB_GETBANDINFO, index, (LPARAM)&rebarBandInfo)) + { + rebarBandInfo.cx = (UINT)cxInteger; + rebarBandInfo.fStyle |= (UINT)styleInteger; + + SendMessage(RebarHandle, RB_SETBANDINFO, index, (LPARAM)&rebarBandInfo); + } + } +} + +VOID ReBarSaveLayoutSettings( + VOID + ) +{ + UINT index = 0; + UINT count = 0; + PPH_STRING settingsString; + PH_STRING_BUILDER stringBuilder; + + PhInitializeStringBuilder(&stringBuilder, 100); + + count = (UINT)SendMessage(RebarHandle, RB_GETBANDCOUNT, 0, 0); + + for (index = 0; index < count; index++) + { + REBARBANDINFO rebarBandInfo = + { + sizeof(REBARBANDINFO), + RBBIM_STYLE | RBBIM_SIZE | RBBIM_ID + }; + + SendMessage(RebarHandle, RB_GETBANDINFO, index, (LPARAM)&rebarBandInfo); + + if (rebarBandInfo.fStyle & RBBS_GRIPPERALWAYS) + { + rebarBandInfo.fStyle &= ~RBBS_GRIPPERALWAYS; + } + + if (rebarBandInfo.fStyle & RBBS_NOGRIPPER) + { + rebarBandInfo.fStyle &= ~RBBS_NOGRIPPER; + } + + if (rebarBandInfo.fStyle & RBBS_FIXEDSIZE) + { + rebarBandInfo.fStyle &= ~RBBS_FIXEDSIZE; + } + + PhAppendFormatStringBuilder( + &stringBuilder, + L"%u|%u|%u|", + rebarBandInfo.wID, + rebarBandInfo.cx, + rebarBandInfo.fStyle + ); + } + + if (stringBuilder.String->Length != 0) + PhRemoveEndStringBuilder(&stringBuilder, 1); + + settingsString = PH_AUTO(PhFinalStringBuilderString(&stringBuilder)); + PhSetStringSetting2(SETTING_NAME_REBAR_CONFIG, &settingsString->sr); } \ No newline at end of file diff --git a/plugins/ToolStatus/toolstatus.h b/plugins/ToolStatus/toolstatus.h index 45b08fd9f807..0bc63b8f4fd1 100644 --- a/plugins/ToolStatus/toolstatus.h +++ b/plugins/ToolStatus/toolstatus.h @@ -1,382 +1,382 @@ -/* - * Process Hacker ToolStatus - - * toolstatus header - * - * Copyright (C) 2011-2016 dmex - * Copyright (C) 2010-2013 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#ifndef _TOOLSTATUS_H -#define _TOOLSTATUS_H - -#define CINTERFACE -#define COBJMACROS -#define INITGUID -#include -#include -#include -#include -#include -#include - -#include "resource.h" -#include - -#define PLUGIN_NAME TOOLSTATUS_PLUGIN_NAME -#define SETTING_NAME_TOOLSTATUS_CONFIG (PLUGIN_NAME L".Config") -#define SETTING_NAME_REBAR_CONFIG (PLUGIN_NAME L".RebarConfig") -#define SETTING_NAME_TOOLBAR_CONFIG (PLUGIN_NAME L".ToolbarConfig") -#define SETTING_NAME_STATUSBAR_CONFIG (PLUGIN_NAME L".StatusbarConfig") -#define SETTING_NAME_TOOLBAR_THEME (PLUGIN_NAME L".ToolbarTheme") -#define SETTING_NAME_TOOLBARDISPLAYSTYLE (PLUGIN_NAME L".ToolbarDisplayStyle") -#define SETTING_NAME_SEARCHBOXDISPLAYMODE (PLUGIN_NAME L".SearchBoxDisplayMode") - -#define MAX_DEFAULT_TOOLBAR_ITEMS 9 -#define MAX_DEFAULT_STATUSBAR_ITEMS 3 -#define MAX_TOOLBAR_ITEMS 12 -#define MAX_STATUSBAR_ITEMS 14 - -#define TIDC_FINDWINDOW (WM_APP + 1) -#define TIDC_FINDWINDOWTHREAD (WM_APP + 2) -#define TIDC_FINDWINDOWKILL (WM_APP + 3) -#define TIDC_POWERMENUDROPDOWN (WM_APP + 4) - -typedef enum _TOOLBAR_DISPLAY_STYLE -{ - TOOLBAR_DISPLAY_STYLE_IMAGEONLY, - TOOLBAR_DISPLAY_STYLE_SELECTIVETEXT, - TOOLBAR_DISPLAY_STYLE_ALLTEXT -} TOOLBAR_DISPLAY_STYLE; - -typedef enum _TOOLBAR_COMMAND_ID -{ - COMMAND_ID_ENABLE_MENU = 1, - COMMAND_ID_ENABLE_SEARCHBOX, - COMMAND_ID_ENABLE_CPU_GRAPH, - COMMAND_ID_ENABLE_MEMORY_GRAPH, - COMMAND_ID_ENABLE_COMMIT_GRAPH, - COMMAND_ID_ENABLE_IO_GRAPH, - COMMAND_ID_TOOLBAR_LOCKUNLOCK, - COMMAND_ID_TOOLBAR_CUSTOMIZE, -} TOOLBAR_COMMAND_ID; - -//typedef enum _TOOLBAR_THEME -//{ -// TOOLBAR_THEME_NONE, -// TOOLBAR_THEME_BLACK, -// TOOLBAR_THEME_BLUE -//} TOOLBAR_THEME; - -typedef enum _SEARCHBOX_DISPLAY_MODE -{ - SEARCHBOX_DISPLAY_MODE_ALWAYSSHOW, - SEARCHBOX_DISPLAY_MODE_HIDEINACTIVE, - //SEARCHBOX_DISPLAY_MODE_AUTOHIDE -} SEARCHBOX_DISPLAY_MODE; - -typedef enum _REBAR_BAND_ID -{ - REBAR_BAND_ID_TOOLBAR, - REBAR_BAND_ID_SEARCHBOX, - REBAR_BAND_ID_CPUGRAPH, - REBAR_BAND_ID_MEMGRAPH, - REBAR_BAND_ID_COMMITGRAPH, - REBAR_BAND_ID_IOGRAPH -} REBAR_BAND; - -typedef enum _REBAR_DISPLAY_LOCATION -{ - REBAR_DISPLAY_LOCATION_TOP, - REBAR_DISPLAY_LOCATION_LEFT, - REBAR_DISPLAY_LOCATION_BOTTOM, - REBAR_DISPLAY_LOCATION_RIGHT, -} REBAR_DISPLAY_LOCATION; - -typedef union _TOOLSTATUS_CONFIG -{ - ULONG Flags; - struct - { - ULONG ToolBarEnabled : 1; - ULONG SearchBoxEnabled : 1; - ULONG StatusBarEnabled : 1; - ULONG ToolBarLocked : 1; - ULONG ResolveGhostWindows : 1; - - ULONG ModernIcons : 1; - ULONG AutoHideMenu : 1; - ULONG CpuGraphEnabled : 1; - ULONG MemGraphEnabled : 1; - ULONG CommitGraphEnabled : 1; - ULONG IoGraphEnabled : 1; - - ULONG Spare : 21; - }; -} TOOLSTATUS_CONFIG; - -extern TOOLSTATUS_CONFIG ToolStatusConfig; -extern HWND ProcessTreeNewHandle; -extern HWND ServiceTreeNewHandle; -extern HWND NetworkTreeNewHandle; -extern INT SelectedTabIndex; -extern BOOLEAN UpdateAutomatically; -extern BOOLEAN UpdateGraphs; -extern TOOLBAR_DISPLAY_STYLE DisplayStyle; -extern SEARCHBOX_DISPLAY_MODE SearchBoxDisplayMode; -extern REBAR_DISPLAY_LOCATION RebarDisplayLocation; - -extern HWND RebarHandle; -extern HWND ToolBarHandle; -extern HWND SearchboxHandle; - -extern HMENU MainMenu; -extern HACCEL AcceleratorTable; -extern PPH_STRING SearchboxText; -extern PH_PLUGIN_SYSTEM_STATISTICS SystemStatistics; - -extern HIMAGELIST ToolBarImageList; -extern TBBUTTON ToolbarButtons[MAX_TOOLBAR_ITEMS]; - -extern PPH_PLUGIN PluginInstance; -extern PPH_TN_FILTER_ENTRY ProcessTreeFilterEntry; -extern PPH_TN_FILTER_ENTRY ServiceTreeFilterEntry; -extern PPH_TN_FILTER_ENTRY NetworkTreeFilterEntry; - -PTOOLSTATUS_TAB_INFO FindTabInfo( - _In_ INT TabIndex - ); - -// toolbar.c - -VOID RebarBandInsert( - _In_ UINT BandID, - _In_ HWND HwndChild, - _In_ UINT cyMinChild, - _In_ UINT cxMinChild - ); - -VOID RebarBandRemove( - _In_ UINT BandID - ); - -BOOLEAN RebarBandExists( - _In_ UINT BandID - ); - -VOID ToolbarLoadSettings( - VOID - ); - -VOID ToolbarResetSettings( - VOID - ); - -PWSTR ToolbarGetText( - _In_ INT CommandID - ); - -HBITMAP ToolbarGetImage( - _In_ INT CommandID - ); - -VOID ToolbarLoadButtonSettings( - VOID - ); - -VOID ToolbarSaveButtonSettings( - VOID - ); - -VOID ReBarLoadLayoutSettings( - VOID - ); - -VOID ReBarSaveLayoutSettings( - VOID - ); - -// main.c - -HWND GetCurrentTreeNewHandle( - VOID - ); - -VOID ShowCustomizeMenu( - VOID - ); - -// options.c - -VOID ShowOptionsDialog( - _In_opt_ HWND Parent - ); - -// filter.c - -BOOLEAN WordMatchStringRef( - _In_ PPH_STRINGREF Text - ); - -BOOLEAN ProcessTreeFilterCallback( - _In_ PPH_TREENEW_NODE Node, - _In_opt_ PVOID Context - ); -BOOLEAN ServiceTreeFilterCallback( - _In_ PPH_TREENEW_NODE Node, - _In_opt_ PVOID Context - ); -BOOLEAN NetworkTreeFilterCallback( - _In_ PPH_TREENEW_NODE Node, - _In_opt_ PVOID Context - ); - -NTSTATUS QueryServiceFileName( - _In_ PPH_STRINGREF ServiceName, - _Out_ PPH_STRING *ServiceFileName, - _Out_ PPH_STRING *ServiceBinaryPath - ); - -// graph.c - -extern HWND CpuGraphHandle; -extern HWND MemGraphHandle; -extern HWND CommitGraphHandle; -extern HWND IoGraphHandle; - -VOID ToolbarCreateGraphs(VOID); -VOID ToolbarUpdateGraphs(VOID); -VOID ToolbarUpdateGraphsInfo(LPNMHDR Header); - -// statusbar.c - -typedef struct _STATUSBAR_ITEM -{ - ULONG Id; -} STATUSBAR_ITEM, *PSTATUSBAR_ITEM; - -extern ULONG ProcessesUpdatedCount; -extern HWND StatusBarHandle; -extern PPH_LIST StatusBarItemList; -extern ULONG StatusBarItems[MAX_STATUSBAR_ITEMS]; - -VOID StatusBarLoadSettings( - VOID - ); - -VOID StatusBarSaveSettings( - VOID - ); - -VOID StatusBarResetSettings( - VOID - ); - -PWSTR StatusBarGetText( - _In_ ULONG CommandID - ); - -VOID StatusBarUpdate( - _In_ BOOLEAN ResetMaxWidths - ); - -VOID StatusBarShowMenu( - VOID - ); - -// customizetb.c - -VOID ToolBarShowCustomizeDialog( - VOID - ); - -// customizesb.c - -typedef enum _ID_STATUS -{ - ID_STATUS_NONE, - ID_STATUS_CPUUSAGE, - ID_STATUS_COMMITCHARGE, - ID_STATUS_PHYSICALMEMORY, - ID_STATUS_NUMBEROFPROCESSES, - ID_STATUS_NUMBEROFTHREADS, - ID_STATUS_NUMBEROFHANDLES, - ID_STATUS_IO_RO, - ID_STATUS_IO_W, - ID_STATUS_MAX_CPU_PROCESS, - ID_STATUS_MAX_IO_PROCESS, - ID_STATUS_NUMBEROFVISIBLEITEMS, - ID_STATUS_NUMBEROFSELECTEDITEMS, - ID_STATUS_INTERVALSTATUS, - ID_STATUS_FREEMEMORY -} ID_STATUS; - -VOID StatusBarShowCustomizeDialog( - VOID - ); - -// Shared by customizetb.c and customizesb.c - -typedef struct _BUTTON_CONTEXT -{ - INT IdCommand; - HICON IconHandle; - - union - { - ULONG Flags; - struct - { - ULONG IsVirtual : 1; - ULONG IsRemovable : 1; - ULONG IsSeparator : 1; - ULONG Spare : 29; - }; - }; -} BUTTON_CONTEXT, *PBUTTON_CONTEXT; - -typedef struct _CUSTOMIZE_CONTEXT -{ - HFONT FontHandle; - HBRUSH BrushNormal; - HBRUSH BrushPushed; - HBRUSH BrushHot; - INT CXWidth; - INT ImageWidth; - INT ImageHeight; - - HWND DialogHandle; - HWND AvailableListHandle; - HWND CurrentListHandle; - HWND MoveUpButtonHandle; - HWND MoveDownButtonHandle; - HWND AddButtonHandle; - HWND RemoveButtonHandle; -} CUSTOMIZE_CONTEXT, *PCUSTOMIZE_CONTEXT; - -HICON CustomizeGetToolbarIcon( - _In_ PCUSTOMIZE_CONTEXT Context, - _In_ INT CommandID - ); - -// searchbox.c - -BOOLEAN CreateSearchboxControl( - VOID - ); - +/* + * Process Hacker ToolStatus - + * toolstatus header + * + * Copyright (C) 2011-2016 dmex + * Copyright (C) 2010-2013 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#ifndef _TOOLSTATUS_H +#define _TOOLSTATUS_H + +#define CINTERFACE +#define COBJMACROS +#define INITGUID +#include +#include +#include +#include +#include +#include + +#include "resource.h" +#include + +#define PLUGIN_NAME TOOLSTATUS_PLUGIN_NAME +#define SETTING_NAME_TOOLSTATUS_CONFIG (PLUGIN_NAME L".Config") +#define SETTING_NAME_REBAR_CONFIG (PLUGIN_NAME L".RebarConfig") +#define SETTING_NAME_TOOLBAR_CONFIG (PLUGIN_NAME L".ToolbarConfig") +#define SETTING_NAME_STATUSBAR_CONFIG (PLUGIN_NAME L".StatusbarConfig") +#define SETTING_NAME_TOOLBAR_THEME (PLUGIN_NAME L".ToolbarTheme") +#define SETTING_NAME_TOOLBARDISPLAYSTYLE (PLUGIN_NAME L".ToolbarDisplayStyle") +#define SETTING_NAME_SEARCHBOXDISPLAYMODE (PLUGIN_NAME L".SearchBoxDisplayMode") + +#define MAX_DEFAULT_TOOLBAR_ITEMS 9 +#define MAX_DEFAULT_STATUSBAR_ITEMS 3 +#define MAX_TOOLBAR_ITEMS 12 +#define MAX_STATUSBAR_ITEMS 14 + +#define TIDC_FINDWINDOW (WM_APP + 1) +#define TIDC_FINDWINDOWTHREAD (WM_APP + 2) +#define TIDC_FINDWINDOWKILL (WM_APP + 3) +#define TIDC_POWERMENUDROPDOWN (WM_APP + 4) + +typedef enum _TOOLBAR_DISPLAY_STYLE +{ + TOOLBAR_DISPLAY_STYLE_IMAGEONLY, + TOOLBAR_DISPLAY_STYLE_SELECTIVETEXT, + TOOLBAR_DISPLAY_STYLE_ALLTEXT +} TOOLBAR_DISPLAY_STYLE; + +typedef enum _TOOLBAR_COMMAND_ID +{ + COMMAND_ID_ENABLE_MENU = 1, + COMMAND_ID_ENABLE_SEARCHBOX, + COMMAND_ID_ENABLE_CPU_GRAPH, + COMMAND_ID_ENABLE_MEMORY_GRAPH, + COMMAND_ID_ENABLE_COMMIT_GRAPH, + COMMAND_ID_ENABLE_IO_GRAPH, + COMMAND_ID_TOOLBAR_LOCKUNLOCK, + COMMAND_ID_TOOLBAR_CUSTOMIZE, +} TOOLBAR_COMMAND_ID; + +//typedef enum _TOOLBAR_THEME +//{ +// TOOLBAR_THEME_NONE, +// TOOLBAR_THEME_BLACK, +// TOOLBAR_THEME_BLUE +//} TOOLBAR_THEME; + +typedef enum _SEARCHBOX_DISPLAY_MODE +{ + SEARCHBOX_DISPLAY_MODE_ALWAYSSHOW, + SEARCHBOX_DISPLAY_MODE_HIDEINACTIVE, + //SEARCHBOX_DISPLAY_MODE_AUTOHIDE +} SEARCHBOX_DISPLAY_MODE; + +typedef enum _REBAR_BAND_ID +{ + REBAR_BAND_ID_TOOLBAR, + REBAR_BAND_ID_SEARCHBOX, + REBAR_BAND_ID_CPUGRAPH, + REBAR_BAND_ID_MEMGRAPH, + REBAR_BAND_ID_COMMITGRAPH, + REBAR_BAND_ID_IOGRAPH +} REBAR_BAND; + +typedef enum _REBAR_DISPLAY_LOCATION +{ + REBAR_DISPLAY_LOCATION_TOP, + REBAR_DISPLAY_LOCATION_LEFT, + REBAR_DISPLAY_LOCATION_BOTTOM, + REBAR_DISPLAY_LOCATION_RIGHT, +} REBAR_DISPLAY_LOCATION; + +typedef union _TOOLSTATUS_CONFIG +{ + ULONG Flags; + struct + { + ULONG ToolBarEnabled : 1; + ULONG SearchBoxEnabled : 1; + ULONG StatusBarEnabled : 1; + ULONG ToolBarLocked : 1; + ULONG ResolveGhostWindows : 1; + + ULONG ModernIcons : 1; + ULONG AutoHideMenu : 1; + ULONG CpuGraphEnabled : 1; + ULONG MemGraphEnabled : 1; + ULONG CommitGraphEnabled : 1; + ULONG IoGraphEnabled : 1; + + ULONG Spare : 21; + }; +} TOOLSTATUS_CONFIG; + +extern TOOLSTATUS_CONFIG ToolStatusConfig; +extern HWND ProcessTreeNewHandle; +extern HWND ServiceTreeNewHandle; +extern HWND NetworkTreeNewHandle; +extern INT SelectedTabIndex; +extern BOOLEAN UpdateAutomatically; +extern BOOLEAN UpdateGraphs; +extern TOOLBAR_DISPLAY_STYLE DisplayStyle; +extern SEARCHBOX_DISPLAY_MODE SearchBoxDisplayMode; +extern REBAR_DISPLAY_LOCATION RebarDisplayLocation; + +extern HWND RebarHandle; +extern HWND ToolBarHandle; +extern HWND SearchboxHandle; + +extern HMENU MainMenu; +extern HACCEL AcceleratorTable; +extern PPH_STRING SearchboxText; +extern PH_PLUGIN_SYSTEM_STATISTICS SystemStatistics; + +extern HIMAGELIST ToolBarImageList; +extern TBBUTTON ToolbarButtons[MAX_TOOLBAR_ITEMS]; + +extern PPH_PLUGIN PluginInstance; +extern PPH_TN_FILTER_ENTRY ProcessTreeFilterEntry; +extern PPH_TN_FILTER_ENTRY ServiceTreeFilterEntry; +extern PPH_TN_FILTER_ENTRY NetworkTreeFilterEntry; + +PTOOLSTATUS_TAB_INFO FindTabInfo( + _In_ INT TabIndex + ); + +// toolbar.c + +VOID RebarBandInsert( + _In_ UINT BandID, + _In_ HWND HwndChild, + _In_ UINT cyMinChild, + _In_ UINT cxMinChild + ); + +VOID RebarBandRemove( + _In_ UINT BandID + ); + +BOOLEAN RebarBandExists( + _In_ UINT BandID + ); + +VOID ToolbarLoadSettings( + VOID + ); + +VOID ToolbarResetSettings( + VOID + ); + +PWSTR ToolbarGetText( + _In_ INT CommandID + ); + +HBITMAP ToolbarGetImage( + _In_ INT CommandID + ); + +VOID ToolbarLoadButtonSettings( + VOID + ); + +VOID ToolbarSaveButtonSettings( + VOID + ); + +VOID ReBarLoadLayoutSettings( + VOID + ); + +VOID ReBarSaveLayoutSettings( + VOID + ); + +// main.c + +HWND GetCurrentTreeNewHandle( + VOID + ); + +VOID ShowCustomizeMenu( + VOID + ); + +// options.c + +VOID ShowOptionsDialog( + _In_opt_ HWND Parent + ); + +// filter.c + +BOOLEAN WordMatchStringRef( + _In_ PPH_STRINGREF Text + ); + +BOOLEAN ProcessTreeFilterCallback( + _In_ PPH_TREENEW_NODE Node, + _In_opt_ PVOID Context + ); +BOOLEAN ServiceTreeFilterCallback( + _In_ PPH_TREENEW_NODE Node, + _In_opt_ PVOID Context + ); +BOOLEAN NetworkTreeFilterCallback( + _In_ PPH_TREENEW_NODE Node, + _In_opt_ PVOID Context + ); + +NTSTATUS QueryServiceFileName( + _In_ PPH_STRINGREF ServiceName, + _Out_ PPH_STRING *ServiceFileName, + _Out_ PPH_STRING *ServiceBinaryPath + ); + +// graph.c + +extern HWND CpuGraphHandle; +extern HWND MemGraphHandle; +extern HWND CommitGraphHandle; +extern HWND IoGraphHandle; + +VOID ToolbarCreateGraphs(VOID); +VOID ToolbarUpdateGraphs(VOID); +VOID ToolbarUpdateGraphsInfo(LPNMHDR Header); + +// statusbar.c + +typedef struct _STATUSBAR_ITEM +{ + ULONG Id; +} STATUSBAR_ITEM, *PSTATUSBAR_ITEM; + +extern ULONG ProcessesUpdatedCount; +extern HWND StatusBarHandle; +extern PPH_LIST StatusBarItemList; +extern ULONG StatusBarItems[MAX_STATUSBAR_ITEMS]; + +VOID StatusBarLoadSettings( + VOID + ); + +VOID StatusBarSaveSettings( + VOID + ); + +VOID StatusBarResetSettings( + VOID + ); + +PWSTR StatusBarGetText( + _In_ ULONG CommandID + ); + +VOID StatusBarUpdate( + _In_ BOOLEAN ResetMaxWidths + ); + +VOID StatusBarShowMenu( + VOID + ); + +// customizetb.c + +VOID ToolBarShowCustomizeDialog( + VOID + ); + +// customizesb.c + +typedef enum _ID_STATUS +{ + ID_STATUS_NONE, + ID_STATUS_CPUUSAGE, + ID_STATUS_COMMITCHARGE, + ID_STATUS_PHYSICALMEMORY, + ID_STATUS_NUMBEROFPROCESSES, + ID_STATUS_NUMBEROFTHREADS, + ID_STATUS_NUMBEROFHANDLES, + ID_STATUS_IO_RO, + ID_STATUS_IO_W, + ID_STATUS_MAX_CPU_PROCESS, + ID_STATUS_MAX_IO_PROCESS, + ID_STATUS_NUMBEROFVISIBLEITEMS, + ID_STATUS_NUMBEROFSELECTEDITEMS, + ID_STATUS_INTERVALSTATUS, + ID_STATUS_FREEMEMORY +} ID_STATUS; + +VOID StatusBarShowCustomizeDialog( + VOID + ); + +// Shared by customizetb.c and customizesb.c + +typedef struct _BUTTON_CONTEXT +{ + INT IdCommand; + HICON IconHandle; + + union + { + ULONG Flags; + struct + { + ULONG IsVirtual : 1; + ULONG IsRemovable : 1; + ULONG IsSeparator : 1; + ULONG Spare : 29; + }; + }; +} BUTTON_CONTEXT, *PBUTTON_CONTEXT; + +typedef struct _CUSTOMIZE_CONTEXT +{ + HFONT FontHandle; + HBRUSH BrushNormal; + HBRUSH BrushPushed; + HBRUSH BrushHot; + INT CXWidth; + INT ImageWidth; + INT ImageHeight; + + HWND DialogHandle; + HWND AvailableListHandle; + HWND CurrentListHandle; + HWND MoveUpButtonHandle; + HWND MoveDownButtonHandle; + HWND AddButtonHandle; + HWND RemoveButtonHandle; +} CUSTOMIZE_CONTEXT, *PCUSTOMIZE_CONTEXT; + +HICON CustomizeGetToolbarIcon( + _In_ PCUSTOMIZE_CONTEXT Context, + _In_ INT CommandID + ); + +// searchbox.c + +BOOLEAN CreateSearchboxControl( + VOID + ); + #endif \ No newline at end of file diff --git a/plugins/Updater/CHANGELOG.txt b/plugins/Updater/CHANGELOG.txt index 9cf6f9e3b1df..f1ebcf0295f8 100644 --- a/plugins/Updater/CHANGELOG.txt +++ b/plugins/Updater/CHANGELOG.txt @@ -1,45 +1,45 @@ -2.0 - * Added support for Process Hacker nightly builds - * Improved UI with native TaskDialog - -1.8 - * Removed legacy code - -1.7 - * Ignore v2.40 and above on XP and Vista. - -1.6 - * Fixed background update check interval - -1.5 - * Added dynamic URL support - * Added digital signature verification - -1.4 - * Added PNG images - * Fixed offline crash - * Improved background update check - * Removed BMP images - -1.3 - * Added revision checking - * Fixed invalid xml crash - * Fixed GDI handle leak - * Fixed caching - -1.2 - * Improved UI - * Improved internet connectivity check for Vista and above (INetworkListManager) - * Improved download speed calculation - * Improved time remaining calculation - * Fixed auto-update prompt location if PH minimized - * Fixed install failures if hash check failed - -1.1 - * Added download speed - * Added remaining time - * Fixed buffer zeroing - * Fixed threading memory leak - -1.0 - * Initial release +2.0 + * Added support for Process Hacker nightly builds + * Improved UI with native TaskDialog + +1.8 + * Removed legacy code + +1.7 + * Ignore v2.40 and above on XP and Vista. + +1.6 + * Fixed background update check interval + +1.5 + * Added dynamic URL support + * Added digital signature verification + +1.4 + * Added PNG images + * Fixed offline crash + * Improved background update check + * Removed BMP images + +1.3 + * Added revision checking + * Fixed invalid xml crash + * Fixed GDI handle leak + * Fixed caching + +1.2 + * Improved UI + * Improved internet connectivity check for Vista and above (INetworkListManager) + * Improved download speed calculation + * Improved time remaining calculation + * Fixed auto-update prompt location if PH minimized + * Fixed install failures if hash check failed + +1.1 + * Added download speed + * Added remaining time + * Fixed buffer zeroing + * Fixed threading memory leak + +1.0 + * Initial release diff --git a/plugins/Updater/Updater.vcxproj b/plugins/Updater/Updater.vcxproj index 2e06be53bac9..0cacd9bc1f76 100644 --- a/plugins/Updater/Updater.vcxproj +++ b/plugins/Updater/Updater.vcxproj @@ -1,100 +1,100 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {A0C1595C-FA3E-4B7A-936C-306BC6294C5E} - Updater - Win32Proj - Updater - 10.0.15063.0 - - - - DynamicLibrary - Unicode - v141 - - - DynamicLibrary - Unicode - v141 - - - DynamicLibrary - Unicode - v141 - - - DynamicLibrary - Unicode - v141 - - - - - - - - - bcrypt.lib;winhttp.lib;%(AdditionalDependencies) - bcrypt.dll;winhttp.dll;%(DelayLoadDLLs) - - - - - bcrypt.lib;winhttp.lib;%(AdditionalDependencies) - bcrypt.dll;winhttp.dll;%(DelayLoadDLLs) - - - - - bcrypt.lib;winhttp.lib;%(AdditionalDependencies) - bcrypt.dll;winhttp.dll;%(DelayLoadDLLs) - - - - - bcrypt.lib;winhttp.lib;%(AdditionalDependencies) - bcrypt.dll;winhttp.dll;%(DelayLoadDLLs) - - - - - - - - - - - - - - - - - - - - - - - - + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {A0C1595C-FA3E-4B7A-936C-306BC6294C5E} + Updater + Win32Proj + Updater + 10.0.15063.0 + + + + DynamicLibrary + Unicode + v141 + + + DynamicLibrary + Unicode + v141 + + + DynamicLibrary + Unicode + v141 + + + DynamicLibrary + Unicode + v141 + + + + + + + + + bcrypt.lib;winhttp.lib;%(AdditionalDependencies) + bcrypt.dll;winhttp.dll;%(DelayLoadDLLs) + + + + + bcrypt.lib;winhttp.lib;%(AdditionalDependencies) + bcrypt.dll;winhttp.dll;%(DelayLoadDLLs) + + + + + bcrypt.lib;winhttp.lib;%(AdditionalDependencies) + bcrypt.dll;winhttp.dll;%(DelayLoadDLLs) + + + + + bcrypt.lib;winhttp.lib;%(AdditionalDependencies) + bcrypt.dll;winhttp.dll;%(DelayLoadDLLs) + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/plugins/UserNotes/CHANGELOG.txt b/plugins/UserNotes/CHANGELOG.txt index 2a7350cbfe01..95197b0d1630 100644 --- a/plugins/UserNotes/CHANGELOG.txt +++ b/plugins/UserNotes/CHANGELOG.txt @@ -1,24 +1,24 @@ -1.7 - * Added ability to save process affinity - -1.6 - * Added "Collapse by Default" option for processes - -1.5 - * Added individual process highlighting support - -1.4 - * Added tray icon mini info window support - -1.3 - * Added ability to save I/O priority - -1.2 - * Fixed bug where process priorities were not actually saved - -1.1 - * Added ability to save process priority - * Added "Only for processes with the same command line" option for process comments - -1.0 - * Initial release +1.7 + * Added ability to save process affinity + +1.6 + * Added "Collapse by Default" option for processes + +1.5 + * Added individual process highlighting support + +1.4 + * Added tray icon mini info window support + +1.3 + * Added ability to save I/O priority + +1.2 + * Fixed bug where process priorities were not actually saved + +1.1 + * Added ability to save process priority + * Added "Only for processes with the same command line" option for process comments + +1.0 + * Initial release diff --git a/plugins/UserNotes/UserNotes.rc b/plugins/UserNotes/UserNotes.rc index 58e1a1357383..5510b557d445 100644 --- a/plugins/UserNotes/UserNotes.rc +++ b/plugins/UserNotes/UserNotes.rc @@ -1,182 +1,182 @@ -// Microsoft Visual C++ generated resource script. -// -#include "resource.h" - -#define APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// -#include "winres.h" -///////////////////////////////////////////////////////////////////////////// -#undef APSTUDIO_READONLY_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -// English (Australia) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENA) -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_AUS -#pragma code_page(1252) - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -1 TEXTINCLUDE -BEGIN - "resource.h\0" -END - -2 TEXTINCLUDE -BEGIN - "#include ""winres.h""\0" -END - -3 TEXTINCLUDE -BEGIN - "\r\n" - "\0" -END - -#endif // APSTUDIO_INVOKED - - -///////////////////////////////////////////////////////////////////////////// -// -// Dialog -// - -IDD_OPTIONS DIALOGEX 0, 0, 316, 71 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Options" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "Database location:",IDC_STATIC,7,9,61,8 - EDITTEXT IDC_DATABASE,72,8,183,12,ES_AUTOHSCROLL - PUSHBUTTON "Browse...",IDC_BROWSE,259,7,50,14 - LTEXT "If a relative path is specified, it is relative to Process Hacker's directory. Environment variables can be used. Changes will take place after Process Hacker is restarted.",IDC_STATIC,7,26,302,19 - DEFPUSHBUTTON "OK",IDOK,205,50,50,14 - PUSHBUTTON "Cancel",IDCANCEL,259,50,50,14 -END - -IDD_PROCCOMMENT DIALOGEX 0, 0, 260, 260 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Comment" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - EDITTEXT IDC_COMMENT,7,7,246,229,ES_MULTILINE | ES_AUTOHSCROLL | ES_WANTRETURN | WS_VSCROLL - PUSHBUTTON "Revert",IDC_REVERT,7,239,50,14,WS_DISABLED - CONTROL "Only for processes with the same command line",IDC_MATCHCOMMANDLINE, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,86,241,167,10 -END - -IDD_SRVCOMMENT DIALOGEX 0, 0, 252, 179 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Comment" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - EDITTEXT IDC_COMMENT,7,7,238,165,ES_MULTILINE | ES_AUTOHSCROLL | ES_WANTRETURN | WS_VSCROLL -END - - -///////////////////////////////////////////////////////////////////////////// -// -// DESIGNINFO -// - -#ifdef APSTUDIO_INVOKED -GUIDELINES DESIGNINFO -BEGIN - IDD_OPTIONS, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 309 - TOPMARGIN, 7 - BOTTOMMARGIN, 64 - END - - IDD_PROCCOMMENT, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 253 - TOPMARGIN, 7 - BOTTOMMARGIN, 253 - END - - IDD_SRVCOMMENT, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 245 - TOPMARGIN, 7 - BOTTOMMARGIN, 172 - END -END -#endif // APSTUDIO_INVOKED - - -///////////////////////////////////////////////////////////////////////////// -// -// Version -// - -VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,7,0,0 - PRODUCTVERSION 1,7,0,0 - FILEFLAGSMASK 0x3fL -#ifdef _DEBUG - FILEFLAGS 0x1L -#else - FILEFLAGS 0x0L -#endif - FILEOS 0x40004L - FILETYPE 0x2L - FILESUBTYPE 0x0L -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "0c0904b0" - BEGIN - VALUE "CompanyName", "dmex" - VALUE "FileDescription", "User Notes plugin for Process Hacker" - VALUE "FileVersion", "1.7" - VALUE "InternalName", "ProcessHacker.UserNotes" - VALUE "LegalCopyright", "Licensed under the GNU GPL, v3." - VALUE "OriginalFilename", "UserNotes.dll" - VALUE "ProductName", "User Notes plugin for Process Hacker" - VALUE "ProductVersion", "1.7" - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0xc09, 1200 - END -END - - -///////////////////////////////////////////////////////////////////////////// -// -// AFX_DIALOG_LAYOUT -// - -IDD_OPTIONS AFX_DIALOG_LAYOUT -BEGIN - 0 -END - -#endif // English (Australia) resources -///////////////////////////////////////////////////////////////////////////// - - - -#ifndef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// - - -///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED - +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "winres.h" +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (Australia) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENA) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_AUS +#pragma code_page(1252) + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""winres.h""\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_OPTIONS DIALOGEX 0, 0, 316, 71 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Options" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "Database location:",IDC_STATIC,7,9,61,8 + EDITTEXT IDC_DATABASE,72,8,183,12,ES_AUTOHSCROLL + PUSHBUTTON "Browse...",IDC_BROWSE,259,7,50,14 + LTEXT "If a relative path is specified, it is relative to Process Hacker's directory. Environment variables can be used. Changes will take place after Process Hacker is restarted.",IDC_STATIC,7,26,302,19 + DEFPUSHBUTTON "OK",IDOK,205,50,50,14 + PUSHBUTTON "Cancel",IDCANCEL,259,50,50,14 +END + +IDD_PROCCOMMENT DIALOGEX 0, 0, 260, 260 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Comment" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + EDITTEXT IDC_COMMENT,7,7,246,229,ES_MULTILINE | ES_AUTOHSCROLL | ES_WANTRETURN | WS_VSCROLL + PUSHBUTTON "Revert",IDC_REVERT,7,239,50,14,WS_DISABLED + CONTROL "Only for processes with the same command line",IDC_MATCHCOMMANDLINE, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,86,241,167,10 +END + +IDD_SRVCOMMENT DIALOGEX 0, 0, 252, 179 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Comment" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + EDITTEXT IDC_COMMENT,7,7,238,165,ES_MULTILINE | ES_AUTOHSCROLL | ES_WANTRETURN | WS_VSCROLL +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_OPTIONS, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 309 + TOPMARGIN, 7 + BOTTOMMARGIN, 64 + END + + IDD_PROCCOMMENT, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 253 + TOPMARGIN, 7 + BOTTOMMARGIN, 253 + END + + IDD_SRVCOMMENT, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 245 + TOPMARGIN, 7 + BOTTOMMARGIN, 172 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,7,0,0 + PRODUCTVERSION 1,7,0,0 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "0c0904b0" + BEGIN + VALUE "CompanyName", "dmex" + VALUE "FileDescription", "User Notes plugin for Process Hacker" + VALUE "FileVersion", "1.7" + VALUE "InternalName", "ProcessHacker.UserNotes" + VALUE "LegalCopyright", "Licensed under the GNU GPL, v3." + VALUE "OriginalFilename", "UserNotes.dll" + VALUE "ProductName", "User Notes plugin for Process Hacker" + VALUE "ProductVersion", "1.7" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0xc09, 1200 + END +END + + +///////////////////////////////////////////////////////////////////////////// +// +// AFX_DIALOG_LAYOUT +// + +IDD_OPTIONS AFX_DIALOG_LAYOUT +BEGIN + 0 +END + +#endif // English (Australia) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/plugins/UserNotes/UserNotes.vcxproj b/plugins/UserNotes/UserNotes.vcxproj index 2e4924d7bd4e..45cec0ecac59 100644 --- a/plugins/UserNotes/UserNotes.vcxproj +++ b/plugins/UserNotes/UserNotes.vcxproj @@ -1,90 +1,90 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {7C38D0AA-572C-4D75-8E4E-D68AF3C051AF} - UserNotes - Win32Proj - UserNotes - 10.0.15063.0 - - - - DynamicLibrary - Unicode - v141 - - - DynamicLibrary - Unicode - v141 - - - DynamicLibrary - Unicode - v141 - - - DynamicLibrary - Unicode - v141 - - - - - - - - - uxtheme.lib;%(AdditionalDependencies) - - - - - uxtheme.lib;%(AdditionalDependencies) - - - - - uxtheme.lib;%(AdditionalDependencies) - - - - - uxtheme.lib;%(AdditionalDependencies) - - - - - - - - - - - - - - - - - - + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {7C38D0AA-572C-4D75-8E4E-D68AF3C051AF} + UserNotes + Win32Proj + UserNotes + 10.0.15063.0 + + + + DynamicLibrary + Unicode + v141 + + + DynamicLibrary + Unicode + v141 + + + DynamicLibrary + Unicode + v141 + + + DynamicLibrary + Unicode + v141 + + + + + + + + + uxtheme.lib;%(AdditionalDependencies) + + + + + uxtheme.lib;%(AdditionalDependencies) + + + + + uxtheme.lib;%(AdditionalDependencies) + + + + + uxtheme.lib;%(AdditionalDependencies) + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/plugins/UserNotes/db.c b/plugins/UserNotes/db.c index 1412d51cfcbb..3e96290eb91e 100644 --- a/plugins/UserNotes/db.c +++ b/plugins/UserNotes/db.c @@ -1,447 +1,447 @@ -/* - * Process Hacker User Notes - - * database functions - * - * Copyright (C) 2011-2015 wj32 - * Copyright (C) 2016 dmex - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include "usernotes.h" -#include - -BOOLEAN NTAPI ObjectDbEqualFunction( - _In_ PVOID Entry1, - _In_ PVOID Entry2 - ); - -ULONG NTAPI ObjectDbHashFunction( - _In_ PVOID Entry - ); - -PPH_HASHTABLE ObjectDb; -PH_QUEUED_LOCK ObjectDbLock = PH_QUEUED_LOCK_INIT; -PPH_STRING ObjectDbPath; - -VOID InitializeDb( - VOID - ) -{ - ObjectDb = PhCreateHashtable( - sizeof(PDB_OBJECT), - ObjectDbEqualFunction, - ObjectDbHashFunction, - 64 - ); -} - -BOOLEAN NTAPI ObjectDbEqualFunction( - _In_ PVOID Entry1, - _In_ PVOID Entry2 - ) -{ - PDB_OBJECT object1 = *(PDB_OBJECT *)Entry1; - PDB_OBJECT object2 = *(PDB_OBJECT *)Entry2; - - return object1->Tag == object2->Tag && PhEqualStringRef(&object1->Key, &object2->Key, TRUE); -} - -ULONG NTAPI ObjectDbHashFunction( - _In_ PVOID Entry - ) -{ - PDB_OBJECT object = *(PDB_OBJECT *)Entry; - - return object->Tag + PhHashStringRef(&object->Key, TRUE); -} - -ULONG GetNumberOfDbObjects( - VOID - ) -{ - return ObjectDb->Count; -} - -VOID LockDb( - VOID - ) -{ - PhAcquireQueuedLockExclusive(&ObjectDbLock); -} - -VOID UnlockDb( - VOID - ) -{ - PhReleaseQueuedLockExclusive(&ObjectDbLock); -} - -PDB_OBJECT FindDbObject( - _In_ ULONG Tag, - _In_ PPH_STRINGREF Name - ) -{ - DB_OBJECT lookupObject; - PDB_OBJECT lookupObjectPtr; - PDB_OBJECT *objectPtr; - - lookupObject.Tag = Tag; - lookupObject.Key = *Name; - lookupObjectPtr = &lookupObject; - - objectPtr = PhFindEntryHashtable(ObjectDb, &lookupObjectPtr); - - if (objectPtr) - return *objectPtr; - else - return NULL; -} - -PDB_OBJECT CreateDbObject( - _In_ ULONG Tag, - _In_ PPH_STRINGREF Name, - _In_opt_ PPH_STRING Comment - ) -{ - PDB_OBJECT object; - BOOLEAN added; - PDB_OBJECT *realObject; - - object = PhAllocate(sizeof(DB_OBJECT)); - memset(object, 0, sizeof(DB_OBJECT)); - object->Tag = Tag; - object->Key = *Name; - object->BackColor = ULONG_MAX; - - realObject = PhAddEntryHashtableEx(ObjectDb, &object, &added); - - if (added) - { - object->Name = PhCreateStringEx(Name->Buffer, Name->Length); - object->Key = object->Name->sr; - - if (Comment) - PhSetReference(&object->Comment, Comment); - else - object->Comment = PhReferenceEmptyString(); - } - else - { - PhFree(object); - object = *realObject; - - if (Comment) - PhSwapReference(&object->Comment, Comment); - } - - return object; -} - -VOID DeleteDbObject( - _In_ PDB_OBJECT Object - ) -{ - PhRemoveEntryHashtable(ObjectDb, &Object); - - PhDereferenceObject(Object->Name); - PhDereferenceObject(Object->Comment); - PhFree(Object); -} - -VOID SetDbPath( - _In_ PPH_STRING Path - ) -{ - PhSwapReference(&ObjectDbPath, Path); -} - -PPH_STRING GetOpaqueXmlNodeText( - _In_ mxml_node_t *node - ) -{ - if (node->child && node->child->type == MXML_OPAQUE && node->child->value.opaque) - { - return PhConvertUtf8ToUtf16(node->child->value.opaque); - } - else - { - return PhReferenceEmptyString(); - } -} - -NTSTATUS LoadDb( - VOID - ) -{ - NTSTATUS status; - HANDLE fileHandle; - LARGE_INTEGER fileSize; - mxml_node_t *topNode; - mxml_node_t *currentNode; - - status = PhCreateFileWin32( - &fileHandle, - ObjectDbPath->Buffer, - FILE_GENERIC_READ, - 0, - FILE_SHARE_READ | FILE_SHARE_DELETE, - FILE_OPEN, - FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT - ); - - if (!NT_SUCCESS(status)) - return status; - - if (NT_SUCCESS(PhGetFileSize(fileHandle, &fileSize)) && fileSize.QuadPart == 0) - { - // A blank file is OK. There are no objects to load. - NtClose(fileHandle); - return status; - } - - topNode = mxmlLoadFd(NULL, fileHandle, MXML_OPAQUE_CALLBACK); - NtClose(fileHandle); - - if (!topNode) - return STATUS_FILE_CORRUPT_ERROR; - - if (topNode->type != MXML_ELEMENT) - { - mxmlDelete(topNode); - return STATUS_FILE_CORRUPT_ERROR; - } - - LockDb(); - - for (currentNode = topNode->child; currentNode; currentNode = currentNode->next) - { - PDB_OBJECT object = NULL; - PPH_STRING tag = NULL; - PPH_STRING name = NULL; - PPH_STRING priorityClass = NULL; - PPH_STRING ioPriorityPlusOne = NULL; - PPH_STRING comment = NULL; - PPH_STRING backColor = NULL; - PPH_STRING collapse = NULL; - PPH_STRING affinityMask = NULL; - - if (currentNode->type == MXML_ELEMENT && - currentNode->value.element.num_attrs >= 2) - { - for (INT i = 0; i < currentNode->value.element.num_attrs; i++) - { - if (_stricmp(currentNode->value.element.attrs[i].name, "tag") == 0) - PhMoveReference(&tag, PhConvertUtf8ToUtf16(currentNode->value.element.attrs[i].value)); - else if (_stricmp(currentNode->value.element.attrs[i].name, "name") == 0) - PhMoveReference(&name, PhConvertUtf8ToUtf16(currentNode->value.element.attrs[i].value)); - else if (_stricmp(currentNode->value.element.attrs[i].name, "priorityclass") == 0) - PhMoveReference(&priorityClass, PhConvertUtf8ToUtf16(currentNode->value.element.attrs[i].value)); - else if (_stricmp(currentNode->value.element.attrs[i].name, "iopriorityplusone") == 0) - PhMoveReference(&ioPriorityPlusOne, PhConvertUtf8ToUtf16(currentNode->value.element.attrs[i].value)); - else if (_stricmp(currentNode->value.element.attrs[i].name, "backcolor") == 0) - PhMoveReference(&backColor, PhConvertUtf8ToUtf16(currentNode->value.element.attrs[i].value)); - else if (_stricmp(currentNode->value.element.attrs[i].name, "collapse") == 0) - PhMoveReference(&collapse, PhConvertUtf8ToUtf16(currentNode->value.element.attrs[i].value)); - else if (_stricmp(currentNode->value.element.attrs[i].name, "affinity") == 0) - PhMoveReference(&affinityMask, PhConvertUtf8ToUtf16(currentNode->value.element.attrs[i].value)); - } - } - - comment = GetOpaqueXmlNodeText(currentNode); - - if (tag && name && comment) - { - ULONG64 tagInteger; - ULONG64 priorityClassInteger = 0; - ULONG64 ioPriorityPlusOneInteger = 0; - - PhStringToInteger64(&tag->sr, 10, &tagInteger); - - if (priorityClass) - PhStringToInteger64(&priorityClass->sr, 10, &priorityClassInteger); - if (ioPriorityPlusOne) - PhStringToInteger64(&ioPriorityPlusOne->sr, 10, &ioPriorityPlusOneInteger); - - object = CreateDbObject((ULONG)tagInteger, &name->sr, comment); - object->PriorityClass = (ULONG)priorityClassInteger; - object->IoPriorityPlusOne = (ULONG)ioPriorityPlusOneInteger; - } - - // NOTE: These items are handled separately to maintain compatibility with previous versions of the database. - - if (object && backColor) - { - ULONG64 backColorInteger = ULONG_MAX; - - PhStringToInteger64(&backColor->sr, 10, &backColorInteger); - - object->BackColor = (COLORREF)backColorInteger; - } - - if (object && collapse) - { - ULONG64 collapseInteger = 0; - - PhStringToInteger64(&collapse->sr, 10, &collapseInteger); - - object->Collapse = !!collapseInteger; - } - - if (object && affinityMask) - { - ULONG64 affinityInteger = 0; - - PhStringToInteger64(&affinityMask->sr, 10, &affinityInteger); - - object->AffinityMask = (ULONG)affinityInteger; - } - - PhClearReference(&tag); - PhClearReference(&name); - PhClearReference(&priorityClass); - PhClearReference(&ioPriorityPlusOne); - PhClearReference(&comment); - PhClearReference(&backColor); - PhClearReference(&collapse); - PhClearReference(&affinityMask); - } - - UnlockDb(); - - mxmlDelete(topNode); - - return STATUS_SUCCESS; -} - -PPH_BYTES StringRefToUtf8( - _In_ PPH_STRINGREF String - ) -{ - return PH_AUTO(PhConvertUtf16ToUtf8Ex(String->Buffer, String->Length)); -} - -mxml_node_t *CreateObjectElement( - _Inout_ mxml_node_t *ParentNode, - _In_ PPH_STRINGREF Tag, - _In_ PPH_STRINGREF Name, - _In_ PPH_STRINGREF PriorityClass, - _In_ PPH_STRINGREF IoPriorityPlusOne, - _In_ PPH_STRINGREF Comment, - _In_ PPH_STRINGREF BackColor, - _In_ PPH_STRINGREF Collapse, - _In_ PPH_STRINGREF AffinityMask - ) -{ - mxml_node_t *objectNode; - mxml_node_t *textNode; - - // Create the setting element. - objectNode = mxmlNewElement(ParentNode, "object"); - - // Set the attributes. - mxmlElementSetAttr(objectNode, "tag", StringRefToUtf8(Tag)->Buffer); - mxmlElementSetAttr(objectNode, "name", StringRefToUtf8(Name)->Buffer); - mxmlElementSetAttr(objectNode, "priorityclass", StringRefToUtf8(PriorityClass)->Buffer); - mxmlElementSetAttr(objectNode, "iopriorityplusone", StringRefToUtf8(IoPriorityPlusOne)->Buffer); - mxmlElementSetAttr(objectNode, "backcolor", StringRefToUtf8(BackColor)->Buffer); - mxmlElementSetAttr(objectNode, "collapse", StringRefToUtf8(Collapse)->Buffer); - mxmlElementSetAttr(objectNode, "affinity", StringRefToUtf8(AffinityMask)->Buffer); - - // Set the value. - textNode = mxmlNewOpaque(objectNode, StringRefToUtf8(Comment)->Buffer); - - return objectNode; -} - -PPH_STRING UInt64ToBase10String( - _In_ ULONG64 Integer - ) -{ - return PH_AUTO(PhIntegerToString64(Integer, 10, FALSE)); -} - -NTSTATUS SaveDb( - VOID - ) -{ - PH_AUTO_POOL autoPool; - NTSTATUS status; - HANDLE fileHandle; - mxml_node_t *topNode; - ULONG enumerationKey = 0; - PDB_OBJECT *object; - - PhInitializeAutoPool(&autoPool); - - topNode = mxmlNewElement(MXML_NO_PARENT, "objects"); - - LockDb(); - - while (PhEnumHashtable(ObjectDb, (PVOID*)&object, &enumerationKey)) - { - CreateObjectElement( - topNode, - &UInt64ToBase10String((*object)->Tag)->sr, - &(*object)->Name->sr, - &UInt64ToBase10String((*object)->PriorityClass)->sr, - &UInt64ToBase10String((*object)->IoPriorityPlusOne)->sr, - &(*object)->Comment->sr, - &UInt64ToBase10String((*object)->BackColor)->sr, - &UInt64ToBase10String((*object)->Collapse)->sr, - &UInt64ToBase10String((*object)->AffinityMask)->sr - ); - PhDrainAutoPool(&autoPool); - } - - UnlockDb(); - - // Create the directory if it does not exist. - { - PPH_STRING fullPath; - ULONG indexOfFileName; - - if (fullPath = PH_AUTO(PhGetFullPath(ObjectDbPath->Buffer, &indexOfFileName))) - { - if (indexOfFileName != -1) - SHCreateDirectoryEx(NULL, PhaSubstring(fullPath, 0, indexOfFileName)->Buffer, NULL); - } - } - - PhDeleteAutoPool(&autoPool); - - status = PhCreateFileWin32( - &fileHandle, - ObjectDbPath->Buffer, - FILE_GENERIC_WRITE, - 0, - FILE_SHARE_READ, - FILE_OVERWRITE_IF, - FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT - ); - - if (!NT_SUCCESS(status)) - { - mxmlDelete(topNode); - return status; - } - - mxmlSaveFd(topNode, fileHandle, MXML_NO_CALLBACK); - mxmlDelete(topNode); - NtClose(fileHandle); - - return STATUS_SUCCESS; -} +/* + * Process Hacker User Notes - + * database functions + * + * Copyright (C) 2011-2015 wj32 + * Copyright (C) 2016 dmex + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include "usernotes.h" +#include + +BOOLEAN NTAPI ObjectDbEqualFunction( + _In_ PVOID Entry1, + _In_ PVOID Entry2 + ); + +ULONG NTAPI ObjectDbHashFunction( + _In_ PVOID Entry + ); + +PPH_HASHTABLE ObjectDb; +PH_QUEUED_LOCK ObjectDbLock = PH_QUEUED_LOCK_INIT; +PPH_STRING ObjectDbPath; + +VOID InitializeDb( + VOID + ) +{ + ObjectDb = PhCreateHashtable( + sizeof(PDB_OBJECT), + ObjectDbEqualFunction, + ObjectDbHashFunction, + 64 + ); +} + +BOOLEAN NTAPI ObjectDbEqualFunction( + _In_ PVOID Entry1, + _In_ PVOID Entry2 + ) +{ + PDB_OBJECT object1 = *(PDB_OBJECT *)Entry1; + PDB_OBJECT object2 = *(PDB_OBJECT *)Entry2; + + return object1->Tag == object2->Tag && PhEqualStringRef(&object1->Key, &object2->Key, TRUE); +} + +ULONG NTAPI ObjectDbHashFunction( + _In_ PVOID Entry + ) +{ + PDB_OBJECT object = *(PDB_OBJECT *)Entry; + + return object->Tag + PhHashStringRef(&object->Key, TRUE); +} + +ULONG GetNumberOfDbObjects( + VOID + ) +{ + return ObjectDb->Count; +} + +VOID LockDb( + VOID + ) +{ + PhAcquireQueuedLockExclusive(&ObjectDbLock); +} + +VOID UnlockDb( + VOID + ) +{ + PhReleaseQueuedLockExclusive(&ObjectDbLock); +} + +PDB_OBJECT FindDbObject( + _In_ ULONG Tag, + _In_ PPH_STRINGREF Name + ) +{ + DB_OBJECT lookupObject; + PDB_OBJECT lookupObjectPtr; + PDB_OBJECT *objectPtr; + + lookupObject.Tag = Tag; + lookupObject.Key = *Name; + lookupObjectPtr = &lookupObject; + + objectPtr = PhFindEntryHashtable(ObjectDb, &lookupObjectPtr); + + if (objectPtr) + return *objectPtr; + else + return NULL; +} + +PDB_OBJECT CreateDbObject( + _In_ ULONG Tag, + _In_ PPH_STRINGREF Name, + _In_opt_ PPH_STRING Comment + ) +{ + PDB_OBJECT object; + BOOLEAN added; + PDB_OBJECT *realObject; + + object = PhAllocate(sizeof(DB_OBJECT)); + memset(object, 0, sizeof(DB_OBJECT)); + object->Tag = Tag; + object->Key = *Name; + object->BackColor = ULONG_MAX; + + realObject = PhAddEntryHashtableEx(ObjectDb, &object, &added); + + if (added) + { + object->Name = PhCreateStringEx(Name->Buffer, Name->Length); + object->Key = object->Name->sr; + + if (Comment) + PhSetReference(&object->Comment, Comment); + else + object->Comment = PhReferenceEmptyString(); + } + else + { + PhFree(object); + object = *realObject; + + if (Comment) + PhSwapReference(&object->Comment, Comment); + } + + return object; +} + +VOID DeleteDbObject( + _In_ PDB_OBJECT Object + ) +{ + PhRemoveEntryHashtable(ObjectDb, &Object); + + PhDereferenceObject(Object->Name); + PhDereferenceObject(Object->Comment); + PhFree(Object); +} + +VOID SetDbPath( + _In_ PPH_STRING Path + ) +{ + PhSwapReference(&ObjectDbPath, Path); +} + +PPH_STRING GetOpaqueXmlNodeText( + _In_ mxml_node_t *node + ) +{ + if (node->child && node->child->type == MXML_OPAQUE && node->child->value.opaque) + { + return PhConvertUtf8ToUtf16(node->child->value.opaque); + } + else + { + return PhReferenceEmptyString(); + } +} + +NTSTATUS LoadDb( + VOID + ) +{ + NTSTATUS status; + HANDLE fileHandle; + LARGE_INTEGER fileSize; + mxml_node_t *topNode; + mxml_node_t *currentNode; + + status = PhCreateFileWin32( + &fileHandle, + ObjectDbPath->Buffer, + FILE_GENERIC_READ, + 0, + FILE_SHARE_READ | FILE_SHARE_DELETE, + FILE_OPEN, + FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT + ); + + if (!NT_SUCCESS(status)) + return status; + + if (NT_SUCCESS(PhGetFileSize(fileHandle, &fileSize)) && fileSize.QuadPart == 0) + { + // A blank file is OK. There are no objects to load. + NtClose(fileHandle); + return status; + } + + topNode = mxmlLoadFd(NULL, fileHandle, MXML_OPAQUE_CALLBACK); + NtClose(fileHandle); + + if (!topNode) + return STATUS_FILE_CORRUPT_ERROR; + + if (topNode->type != MXML_ELEMENT) + { + mxmlDelete(topNode); + return STATUS_FILE_CORRUPT_ERROR; + } + + LockDb(); + + for (currentNode = topNode->child; currentNode; currentNode = currentNode->next) + { + PDB_OBJECT object = NULL; + PPH_STRING tag = NULL; + PPH_STRING name = NULL; + PPH_STRING priorityClass = NULL; + PPH_STRING ioPriorityPlusOne = NULL; + PPH_STRING comment = NULL; + PPH_STRING backColor = NULL; + PPH_STRING collapse = NULL; + PPH_STRING affinityMask = NULL; + + if (currentNode->type == MXML_ELEMENT && + currentNode->value.element.num_attrs >= 2) + { + for (INT i = 0; i < currentNode->value.element.num_attrs; i++) + { + if (_stricmp(currentNode->value.element.attrs[i].name, "tag") == 0) + PhMoveReference(&tag, PhConvertUtf8ToUtf16(currentNode->value.element.attrs[i].value)); + else if (_stricmp(currentNode->value.element.attrs[i].name, "name") == 0) + PhMoveReference(&name, PhConvertUtf8ToUtf16(currentNode->value.element.attrs[i].value)); + else if (_stricmp(currentNode->value.element.attrs[i].name, "priorityclass") == 0) + PhMoveReference(&priorityClass, PhConvertUtf8ToUtf16(currentNode->value.element.attrs[i].value)); + else if (_stricmp(currentNode->value.element.attrs[i].name, "iopriorityplusone") == 0) + PhMoveReference(&ioPriorityPlusOne, PhConvertUtf8ToUtf16(currentNode->value.element.attrs[i].value)); + else if (_stricmp(currentNode->value.element.attrs[i].name, "backcolor") == 0) + PhMoveReference(&backColor, PhConvertUtf8ToUtf16(currentNode->value.element.attrs[i].value)); + else if (_stricmp(currentNode->value.element.attrs[i].name, "collapse") == 0) + PhMoveReference(&collapse, PhConvertUtf8ToUtf16(currentNode->value.element.attrs[i].value)); + else if (_stricmp(currentNode->value.element.attrs[i].name, "affinity") == 0) + PhMoveReference(&affinityMask, PhConvertUtf8ToUtf16(currentNode->value.element.attrs[i].value)); + } + } + + comment = GetOpaqueXmlNodeText(currentNode); + + if (tag && name && comment) + { + ULONG64 tagInteger; + ULONG64 priorityClassInteger = 0; + ULONG64 ioPriorityPlusOneInteger = 0; + + PhStringToInteger64(&tag->sr, 10, &tagInteger); + + if (priorityClass) + PhStringToInteger64(&priorityClass->sr, 10, &priorityClassInteger); + if (ioPriorityPlusOne) + PhStringToInteger64(&ioPriorityPlusOne->sr, 10, &ioPriorityPlusOneInteger); + + object = CreateDbObject((ULONG)tagInteger, &name->sr, comment); + object->PriorityClass = (ULONG)priorityClassInteger; + object->IoPriorityPlusOne = (ULONG)ioPriorityPlusOneInteger; + } + + // NOTE: These items are handled separately to maintain compatibility with previous versions of the database. + + if (object && backColor) + { + ULONG64 backColorInteger = ULONG_MAX; + + PhStringToInteger64(&backColor->sr, 10, &backColorInteger); + + object->BackColor = (COLORREF)backColorInteger; + } + + if (object && collapse) + { + ULONG64 collapseInteger = 0; + + PhStringToInteger64(&collapse->sr, 10, &collapseInteger); + + object->Collapse = !!collapseInteger; + } + + if (object && affinityMask) + { + ULONG64 affinityInteger = 0; + + PhStringToInteger64(&affinityMask->sr, 10, &affinityInteger); + + object->AffinityMask = (ULONG)affinityInteger; + } + + PhClearReference(&tag); + PhClearReference(&name); + PhClearReference(&priorityClass); + PhClearReference(&ioPriorityPlusOne); + PhClearReference(&comment); + PhClearReference(&backColor); + PhClearReference(&collapse); + PhClearReference(&affinityMask); + } + + UnlockDb(); + + mxmlDelete(topNode); + + return STATUS_SUCCESS; +} + +PPH_BYTES StringRefToUtf8( + _In_ PPH_STRINGREF String + ) +{ + return PH_AUTO(PhConvertUtf16ToUtf8Ex(String->Buffer, String->Length)); +} + +mxml_node_t *CreateObjectElement( + _Inout_ mxml_node_t *ParentNode, + _In_ PPH_STRINGREF Tag, + _In_ PPH_STRINGREF Name, + _In_ PPH_STRINGREF PriorityClass, + _In_ PPH_STRINGREF IoPriorityPlusOne, + _In_ PPH_STRINGREF Comment, + _In_ PPH_STRINGREF BackColor, + _In_ PPH_STRINGREF Collapse, + _In_ PPH_STRINGREF AffinityMask + ) +{ + mxml_node_t *objectNode; + mxml_node_t *textNode; + + // Create the setting element. + objectNode = mxmlNewElement(ParentNode, "object"); + + // Set the attributes. + mxmlElementSetAttr(objectNode, "tag", StringRefToUtf8(Tag)->Buffer); + mxmlElementSetAttr(objectNode, "name", StringRefToUtf8(Name)->Buffer); + mxmlElementSetAttr(objectNode, "priorityclass", StringRefToUtf8(PriorityClass)->Buffer); + mxmlElementSetAttr(objectNode, "iopriorityplusone", StringRefToUtf8(IoPriorityPlusOne)->Buffer); + mxmlElementSetAttr(objectNode, "backcolor", StringRefToUtf8(BackColor)->Buffer); + mxmlElementSetAttr(objectNode, "collapse", StringRefToUtf8(Collapse)->Buffer); + mxmlElementSetAttr(objectNode, "affinity", StringRefToUtf8(AffinityMask)->Buffer); + + // Set the value. + textNode = mxmlNewOpaque(objectNode, StringRefToUtf8(Comment)->Buffer); + + return objectNode; +} + +PPH_STRING UInt64ToBase10String( + _In_ ULONG64 Integer + ) +{ + return PH_AUTO(PhIntegerToString64(Integer, 10, FALSE)); +} + +NTSTATUS SaveDb( + VOID + ) +{ + PH_AUTO_POOL autoPool; + NTSTATUS status; + HANDLE fileHandle; + mxml_node_t *topNode; + ULONG enumerationKey = 0; + PDB_OBJECT *object; + + PhInitializeAutoPool(&autoPool); + + topNode = mxmlNewElement(MXML_NO_PARENT, "objects"); + + LockDb(); + + while (PhEnumHashtable(ObjectDb, (PVOID*)&object, &enumerationKey)) + { + CreateObjectElement( + topNode, + &UInt64ToBase10String((*object)->Tag)->sr, + &(*object)->Name->sr, + &UInt64ToBase10String((*object)->PriorityClass)->sr, + &UInt64ToBase10String((*object)->IoPriorityPlusOne)->sr, + &(*object)->Comment->sr, + &UInt64ToBase10String((*object)->BackColor)->sr, + &UInt64ToBase10String((*object)->Collapse)->sr, + &UInt64ToBase10String((*object)->AffinityMask)->sr + ); + PhDrainAutoPool(&autoPool); + } + + UnlockDb(); + + // Create the directory if it does not exist. + { + PPH_STRING fullPath; + ULONG indexOfFileName; + + if (fullPath = PH_AUTO(PhGetFullPath(ObjectDbPath->Buffer, &indexOfFileName))) + { + if (indexOfFileName != -1) + SHCreateDirectoryEx(NULL, PhaSubstring(fullPath, 0, indexOfFileName)->Buffer, NULL); + } + } + + PhDeleteAutoPool(&autoPool); + + status = PhCreateFileWin32( + &fileHandle, + ObjectDbPath->Buffer, + FILE_GENERIC_WRITE, + 0, + FILE_SHARE_READ, + FILE_OVERWRITE_IF, + FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT + ); + + if (!NT_SUCCESS(status)) + { + mxmlDelete(topNode); + return status; + } + + mxmlSaveFd(topNode, fileHandle, MXML_NO_CALLBACK); + mxmlDelete(topNode); + NtClose(fileHandle); + + return STATUS_SUCCESS; +} diff --git a/plugins/UserNotes/db.h b/plugins/UserNotes/db.h index bfae0318271e..bf8018c4b9f2 100644 --- a/plugins/UserNotes/db.h +++ b/plugins/UserNotes/db.h @@ -1,92 +1,92 @@ -/* - * Process Hacker User Notes - - * database functions - * - * Copyright (C) 2011-2015 wj32 - * Copyright (C) 2016 dmex - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#ifndef DB_H -#define DB_H - -#define PLUGIN_NAME L"ProcessHacker.UserNotes" -#define SETTING_NAME_DATABASE_PATH (PLUGIN_NAME L".DatabasePath") -#define SETTING_NAME_CUSTOM_COLOR_LIST (PLUGIN_NAME L".ColorCustomList") - -#define FILE_TAG 1 -#define SERVICE_TAG 2 -#define COMMAND_LINE_TAG 3 - -typedef struct _DB_OBJECT -{ - ULONG Tag; - PH_STRINGREF Key; - - PPH_STRING Name; - PPH_STRING Comment; - ULONG PriorityClass; - ULONG IoPriorityPlusOne; - COLORREF BackColor; - BOOLEAN Collapse; - ULONG AffinityMask; -} DB_OBJECT, *PDB_OBJECT; - -VOID InitializeDb( - VOID - ); - -ULONG GetNumberOfDbObjects( - VOID - ); - -VOID LockDb( - VOID - ); - -VOID UnlockDb( - VOID - ); - -PDB_OBJECT FindDbObject( - _In_ ULONG Tag, - _In_ PPH_STRINGREF Name - ); - -PDB_OBJECT CreateDbObject( - _In_ ULONG Tag, - _In_ PPH_STRINGREF Name, - _In_opt_ PPH_STRING Comment - ); - -VOID DeleteDbObject( - _In_ PDB_OBJECT Object - ); - -VOID SetDbPath( - _In_ PPH_STRING Path - ); - -NTSTATUS LoadDb( - VOID - ); - -NTSTATUS SaveDb( - VOID - ); - -#endif +/* + * Process Hacker User Notes - + * database functions + * + * Copyright (C) 2011-2015 wj32 + * Copyright (C) 2016 dmex + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#ifndef DB_H +#define DB_H + +#define PLUGIN_NAME L"ProcessHacker.UserNotes" +#define SETTING_NAME_DATABASE_PATH (PLUGIN_NAME L".DatabasePath") +#define SETTING_NAME_CUSTOM_COLOR_LIST (PLUGIN_NAME L".ColorCustomList") + +#define FILE_TAG 1 +#define SERVICE_TAG 2 +#define COMMAND_LINE_TAG 3 + +typedef struct _DB_OBJECT +{ + ULONG Tag; + PH_STRINGREF Key; + + PPH_STRING Name; + PPH_STRING Comment; + ULONG PriorityClass; + ULONG IoPriorityPlusOne; + COLORREF BackColor; + BOOLEAN Collapse; + ULONG AffinityMask; +} DB_OBJECT, *PDB_OBJECT; + +VOID InitializeDb( + VOID + ); + +ULONG GetNumberOfDbObjects( + VOID + ); + +VOID LockDb( + VOID + ); + +VOID UnlockDb( + VOID + ); + +PDB_OBJECT FindDbObject( + _In_ ULONG Tag, + _In_ PPH_STRINGREF Name + ); + +PDB_OBJECT CreateDbObject( + _In_ ULONG Tag, + _In_ PPH_STRINGREF Name, + _In_opt_ PPH_STRING Comment + ); + +VOID DeleteDbObject( + _In_ PDB_OBJECT Object + ); + +VOID SetDbPath( + _In_ PPH_STRING Path + ); + +NTSTATUS LoadDb( + VOID + ); + +NTSTATUS SaveDb( + VOID + ); + +#endif diff --git a/plugins/UserNotes/main.c b/plugins/UserNotes/main.c index e6471f4e8600..e0f3f0278e08 100644 --- a/plugins/UserNotes/main.c +++ b/plugins/UserNotes/main.c @@ -1,1892 +1,1892 @@ -/* - * Process Hacker User Notes - - * main program - * - * Copyright (C) 2011-2016 wj32 - * Copyright (C) 2016 dmex - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include "usernotes.h" -#include -#include - -VOID SearchChangedHandler( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ); - -static PPH_PLUGIN PluginInstance; -static PH_CALLBACK_REGISTRATION PluginLoadCallbackRegistration; -static PH_CALLBACK_REGISTRATION PluginUnloadCallbackRegistration; -static PH_CALLBACK_REGISTRATION PluginShowOptionsCallbackRegistration; -static PH_CALLBACK_REGISTRATION PluginMenuItemCallbackRegistration; -static PH_CALLBACK_REGISTRATION PluginMenuHookCallbackRegistration; -static PH_CALLBACK_REGISTRATION TreeNewMessageCallbackRegistration; -static PH_CALLBACK_REGISTRATION MainWindowShowingCallbackRegistration; -static PH_CALLBACK_REGISTRATION ProcessPropertiesInitializingCallbackRegistration; -static PH_CALLBACK_REGISTRATION ServicePropertiesInitializingCallbackRegistration; -static PH_CALLBACK_REGISTRATION ProcessMenuInitializingCallbackRegistration; -static PH_CALLBACK_REGISTRATION ProcessTreeNewInitializingCallbackRegistration; -static PH_CALLBACK_REGISTRATION GetProcessHighlightingColorCallbackRegistration; -static PH_CALLBACK_REGISTRATION ServiceTreeNewInitializingCallbackRegistration; -static PH_CALLBACK_REGISTRATION MiListSectionMenuInitializingCallbackRegistration; -static PH_CALLBACK_REGISTRATION ProcessModifiedCallbackRegistration; -static PH_CALLBACK_REGISTRATION ProcessesUpdatedCallbackRegistration; -static PH_CALLBACK_REGISTRATION SearchChangedRegistration; - -static PTOOLSTATUS_INTERFACE ToolStatusInterface = NULL; - -HWND ProcessTreeNewHandle; -LIST_ENTRY ProcessListHead = { &ProcessListHead, &ProcessListHead }; -PH_QUEUED_LOCK ProcessListLock = PH_QUEUED_LOCK_INIT; - -HWND ServiceTreeNewHandle; -LIST_ENTRY ServiceListHead = { &ServiceListHead, &ServiceListHead }; -PH_QUEUED_LOCK ServiceListLock = PH_QUEUED_LOCK_INIT; - -static COLORREF ProcessCustomColors[16] = { 0 }; - -BOOLEAN MatchDbObjectIntent( - _In_ PDB_OBJECT Object, - _In_ ULONG Intent - ) -{ - return (!(Intent & INTENT_PROCESS_COMMENT) || Object->Comment->Length != 0) && - (!(Intent & INTENT_PROCESS_PRIORITY_CLASS) || Object->PriorityClass != 0) && - (!(Intent & INTENT_PROCESS_IO_PRIORITY) || Object->IoPriorityPlusOne != 0) && - (!(Intent & INTENT_PROCESS_HIGHLIGHT) || Object->BackColor != ULONG_MAX) && - (!(Intent & INTENT_PROCESS_COLLAPSE) || Object->Collapse == TRUE) && - (!(Intent & INTENT_PROCESS_AFFINITY) || Object->AffinityMask != 0); -} - -PDB_OBJECT FindDbObjectForProcess( - _In_ PPH_PROCESS_ITEM ProcessItem, - _In_ ULONG Intent - ) -{ - PDB_OBJECT object; - - if ( - ProcessItem->CommandLine && - (object = FindDbObject(COMMAND_LINE_TAG, &ProcessItem->CommandLine->sr)) && - MatchDbObjectIntent(object, Intent) - ) - { - return object; - } - - if ( - (object = FindDbObject(FILE_TAG, &ProcessItem->ProcessName->sr)) && - MatchDbObjectIntent(object, Intent) - ) - { - return object; - } - - return NULL; -} - -VOID DeleteDbObjectForProcessIfUnused( - _In_ PDB_OBJECT Object - ) -{ - if ( - Object->Comment->Length == 0 && - Object->PriorityClass == 0 && - Object->IoPriorityPlusOne == 0 && - Object->BackColor == ULONG_MAX && - Object->Collapse == FALSE && - Object->AffinityMask == 0 - ) - { - DeleteDbObject(Object); - } -} - -VOID LoadCustomColors( - VOID - ) -{ - PPH_STRING settingsString; - PH_STRINGREF remaining; - PH_STRINGREF part; - - settingsString = PhaGetStringSetting(SETTING_NAME_CUSTOM_COLOR_LIST); - remaining = settingsString->sr; - - if (remaining.Length == 0) - return; - - for (ULONG i = 0; i < ARRAYSIZE(ProcessCustomColors); i++) - { - ULONG64 integer = 0; - - if (remaining.Length == 0) - break; - - PhSplitStringRefAtChar(&remaining, ',', &part, &remaining); - - if (PhStringToInteger64(&part, 10, &integer)) - { - ProcessCustomColors[i] = (COLORREF)integer; - } - } -} - -PPH_STRING SaveCustomColors( - VOID - ) -{ - PH_STRING_BUILDER stringBuilder; - - PhInitializeStringBuilder(&stringBuilder, 100); - - for (ULONG i = 0; i < ARRAYSIZE(ProcessCustomColors); i++) - { - PhAppendFormatStringBuilder( - &stringBuilder, - L"%lu,", - ProcessCustomColors[i] - ); - } - - if (stringBuilder.String->Length != 0) - PhRemoveEndStringBuilder(&stringBuilder, 1); - - return PhFinalStringBuilderString(&stringBuilder); -} - -ULONG GetProcessAffinity( - _In_ HANDLE ProcessId - ) -{ - HANDLE processHandle; - ULONG affinityMask = 0; - PROCESS_BASIC_INFORMATION basicInfo; - - if (NT_SUCCESS(PhOpenProcess( - &processHandle, - ProcessQueryAccess, - ProcessId - ))) - { - if (NT_SUCCESS(PhGetProcessBasicInformation( - processHandle, - &basicInfo - ))) - { - affinityMask = (ULONG)basicInfo.AffinityMask; - } - - NtClose(processHandle); - } - - return affinityMask; -} - -IO_PRIORITY_HINT GetProcessIoPriority( - _In_ HANDLE ProcessId - ) -{ - HANDLE processHandle; - IO_PRIORITY_HINT ioPriority = -1; - - if (NT_SUCCESS(PhOpenProcess( - &processHandle, - ProcessQueryAccess, - ProcessId - ))) - { - if (!NT_SUCCESS(PhGetProcessIoPriority( - processHandle, - &ioPriority - ))) - { - ioPriority = -1; - } - - NtClose(processHandle); - } - - return ioPriority; -} - -ULONG GetPriorityClassFromId( - _In_ ULONG Id - ) -{ - switch (Id) - { - case PHAPP_ID_PRIORITY_REALTIME: - return PROCESS_PRIORITY_CLASS_REALTIME; - case PHAPP_ID_PRIORITY_HIGH: - return PROCESS_PRIORITY_CLASS_HIGH; - case PHAPP_ID_PRIORITY_ABOVENORMAL: - return PROCESS_PRIORITY_CLASS_ABOVE_NORMAL; - case PHAPP_ID_PRIORITY_NORMAL: - return PROCESS_PRIORITY_CLASS_NORMAL; - case PHAPP_ID_PRIORITY_BELOWNORMAL: - return PROCESS_PRIORITY_CLASS_BELOW_NORMAL; - case PHAPP_ID_PRIORITY_IDLE: - return PROCESS_PRIORITY_CLASS_IDLE; - } - - return 0; -} - -ULONG GetIoPriorityFromId( - _In_ ULONG Id - ) -{ - switch (Id) - { - case PHAPP_ID_IOPRIORITY_VERYLOW: - return 0; - case PHAPP_ID_IOPRIORITY_LOW: - return 1; - case PHAPP_ID_IOPRIORITY_NORMAL: - return 2; - case PHAPP_ID_IOPRIORITY_HIGH: - return 3; - } - - return -1; -} - -VOID NTAPI LoadCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - PPH_PLUGIN toolStatusPlugin; - PPH_STRING path; - - if (toolStatusPlugin = PhFindPlugin(TOOLSTATUS_PLUGIN_NAME)) - { - ToolStatusInterface = PhGetPluginInformation(toolStatusPlugin)->Interface; - - if (ToolStatusInterface->Version < TOOLSTATUS_INTERFACE_VERSION) - ToolStatusInterface = NULL; - } - - path = PhaGetStringSetting(SETTING_NAME_DATABASE_PATH); - path = PH_AUTO(PhExpandEnvironmentStrings(&path->sr)); - - LoadCustomColors(); - - if (RtlDetermineDosPathNameType_U(path->Buffer) == RtlPathTypeRelative) - { - PPH_STRING directory; - - directory = PH_AUTO(PhGetApplicationDirectory()); - path = PH_AUTO(PhConcatStringRef2(&directory->sr, &path->sr)); - } - - SetDbPath(path); - LoadDb(); -} - -VOID NTAPI UnloadCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - SaveDb(); -} - -VOID NTAPI ShowOptionsCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - DialogBox( - PluginInstance->DllBase, - MAKEINTRESOURCE(IDD_OPTIONS), - (HWND)Parameter, - OptionsDlgProc - ); -} - -VOID NTAPI MenuItemCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - PPH_PLUGIN_MENU_ITEM menuItem = Parameter; - PPH_PROCESS_ITEM processItem = PhGetSelectedProcessItem(); - PDB_OBJECT object; - - if (!processItem) - return; - - switch (menuItem->Id) - { - case PROCESS_PRIORITY_SAVE_ID: - { - LockDb(); - - if ((object = FindDbObject(FILE_TAG, &processItem->ProcessName->sr)) && object->PriorityClass != 0) - { - object->PriorityClass = 0; - DeleteDbObjectForProcessIfUnused(object); - } - else - { - object = CreateDbObject(FILE_TAG, &processItem->ProcessName->sr, NULL); - object->PriorityClass = processItem->PriorityClass; - } - - UnlockDb(); - SaveDb(); - } - break; - case PROCESS_PRIORITY_SAVE_FOR_THIS_COMMAND_LINE_ID: - { - if (processItem->CommandLine) - { - LockDb(); - - if ((object = FindDbObject(COMMAND_LINE_TAG, &processItem->CommandLine->sr)) && object->PriorityClass != 0) - { - object->PriorityClass = 0; - DeleteDbObjectForProcessIfUnused(object); - } - else - { - object = CreateDbObject(COMMAND_LINE_TAG, &processItem->CommandLine->sr, NULL); - object->PriorityClass = processItem->PriorityClass; - } - - UnlockDb(); - SaveDb(); - } - } - break; - case PROCESS_IO_PRIORITY_SAVE_ID: - { - LockDb(); - - if ((object = FindDbObject(FILE_TAG, &processItem->ProcessName->sr)) && object->IoPriorityPlusOne != 0) - { - object->IoPriorityPlusOne = 0; - DeleteDbObjectForProcessIfUnused(object); - } - else - { - object = CreateDbObject(FILE_TAG, &processItem->ProcessName->sr, NULL); - object->IoPriorityPlusOne = GetProcessIoPriority(processItem->ProcessId) + 1; - } - - UnlockDb(); - SaveDb(); - } - break; - case PROCESS_IO_PRIORITY_SAVE_FOR_THIS_COMMAND_LINE_ID: - { - if (processItem->CommandLine) - { - LockDb(); - - if ((object = FindDbObject(COMMAND_LINE_TAG, &processItem->CommandLine->sr)) && object->IoPriorityPlusOne != 0) - { - object->IoPriorityPlusOne = 0; - DeleteDbObjectForProcessIfUnused(object); - } - else - { - object = CreateDbObject(COMMAND_LINE_TAG, &processItem->CommandLine->sr, NULL); - object->IoPriorityPlusOne = GetProcessIoPriority(processItem->ProcessId) + 1; - } - - UnlockDb(); - SaveDb(); - } - } - break; - case PROCESS_HIGHLIGHT_ID: - { - BOOLEAN highlightPresent = (BOOLEAN)menuItem->Context; - - if (!highlightPresent) - { - CHOOSECOLOR chooseColor = { sizeof(CHOOSECOLOR) }; - chooseColor.hwndOwner = PhMainWndHandle; - chooseColor.lpCustColors = ProcessCustomColors; - chooseColor.lpfnHook = ColorDlgHookProc; - chooseColor.Flags = CC_ANYCOLOR | CC_FULLOPEN | CC_SOLIDCOLOR | CC_ENABLEHOOK; - - if (ChooseColor(&chooseColor)) - { - PhSetStringSetting2(SETTING_NAME_CUSTOM_COLOR_LIST, &PH_AUTO_T(PH_STRING, SaveCustomColors())->sr); - - LockDb(); - - object = CreateDbObject(FILE_TAG, &processItem->ProcessName->sr, NULL); - object->BackColor = chooseColor.rgbResult; - - UnlockDb(); - SaveDb(); - } - } - else - { - LockDb(); - - if ((object = FindDbObject(FILE_TAG, &processItem->ProcessName->sr)) && object->BackColor != ULONG_MAX) - { - object->BackColor = ULONG_MAX; - DeleteDbObjectForProcessIfUnused(object); - } - - UnlockDb(); - SaveDb(); - } - - PhInvalidateAllProcessNodes(); - } - break; - case PROCESS_COLLAPSE_ID: - { - LockDb(); - - if ((object = FindDbObject(FILE_TAG, &processItem->ProcessName->sr)) && object->Collapse) - { - object->Collapse = FALSE; - DeleteDbObjectForProcessIfUnused(object); - } - else - { - object = CreateDbObject(FILE_TAG, &processItem->ProcessName->sr, NULL); - object->Collapse = TRUE; - } - - UnlockDb(); - SaveDb(); - } - break; - case PROCESS_AFFINITY_SAVE_ID: - { - LockDb(); - - if ((object = FindDbObject(FILE_TAG, &processItem->ProcessName->sr)) && object->AffinityMask != 0) - { - object->AffinityMask = 0; - DeleteDbObjectForProcessIfUnused(object); - } - else - { - object = CreateDbObject(FILE_TAG, &processItem->ProcessName->sr, NULL); - object->AffinityMask = GetProcessAffinity(processItem->ProcessId); - } - - UnlockDb(); - SaveDb(); - } - break; - case PROCESS_AFFINITY_SAVE_FOR_THIS_COMMAND_LINE_ID: - { - if (processItem->CommandLine) - { - LockDb(); - - if ((object = FindDbObject(COMMAND_LINE_TAG, &processItem->CommandLine->sr)) && object->AffinityMask != 0) - { - object->AffinityMask = 0; - DeleteDbObjectForProcessIfUnused(object); - } - else - { - object = CreateDbObject(COMMAND_LINE_TAG, &processItem->CommandLine->sr, NULL); - object->AffinityMask = GetProcessAffinity(processItem->ProcessId); - } - - UnlockDb(); - SaveDb(); - } - } - break; - } -} - -VOID NTAPI MenuHookCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - PPH_PLUGIN_MENU_HOOK_INFORMATION menuHookInfo = Parameter; - ULONG id = menuHookInfo->SelectedItem->Id; - - switch (id) - { - case PHAPP_ID_PRIORITY_REALTIME: - case PHAPP_ID_PRIORITY_HIGH: - case PHAPP_ID_PRIORITY_ABOVENORMAL: - case PHAPP_ID_PRIORITY_NORMAL: - case PHAPP_ID_PRIORITY_BELOWNORMAL: - case PHAPP_ID_PRIORITY_IDLE: - { - BOOLEAN changed = FALSE; - PPH_PROCESS_ITEM *processes; - ULONG numberOfProcesses; - ULONG i; - - PhGetSelectedProcessItems(&processes, &numberOfProcesses); - LockDb(); - - for (i = 0; i < numberOfProcesses; i++) - { - PDB_OBJECT object; - - if (object = FindDbObjectForProcess(processes[i], INTENT_PROCESS_PRIORITY_CLASS)) - { - ULONG newPriorityClass = GetPriorityClassFromId(id); - - if (object->PriorityClass != newPriorityClass) - { - object->PriorityClass = newPriorityClass; - changed = TRUE; - } - } - } - - UnlockDb(); - PhFree(processes); - - if (changed) - SaveDb(); - } - break; - case PHAPP_ID_IOPRIORITY_VERYLOW: - case PHAPP_ID_IOPRIORITY_LOW: - case PHAPP_ID_IOPRIORITY_NORMAL: - case PHAPP_ID_IOPRIORITY_HIGH: - { - BOOLEAN changed = FALSE; - PPH_PROCESS_ITEM *processes; - ULONG numberOfProcesses; - ULONG i; - - PhGetSelectedProcessItems(&processes, &numberOfProcesses); - LockDb(); - - for (i = 0; i < numberOfProcesses; i++) - { - PDB_OBJECT object; - - if (object = FindDbObjectForProcess(processes[i], INTENT_PROCESS_IO_PRIORITY)) - { - ULONG newIoPriorityPlusOne = GetIoPriorityFromId(id) + 1; - - if (object->IoPriorityPlusOne != newIoPriorityPlusOne) - { - object->IoPriorityPlusOne = newIoPriorityPlusOne; - changed = TRUE; - } - } - } - - UnlockDb(); - PhFree(processes); - - if (changed) - SaveDb(); - } - break; - case PHAPP_ID_PROCESS_AFFINITY: - { - BOOLEAN changed = FALSE; - ULONG_PTR affinityMask; - ULONG_PTR newAffinityMask; - PPH_PROCESS_ITEM processItem = PhGetSelectedProcessItem(); - - if (!processItem) - break; - - // Don't show the default Process Hacker affinity dialog. - menuHookInfo->Handled = TRUE; - - // Query the current process affinity. - affinityMask = GetProcessAffinity(processItem->ProcessId); - - // Show the affinity dialog (with our values). - if (PhShowProcessAffinityDialog2(PhMainWndHandle, affinityMask, &newAffinityMask)) - { - PDB_OBJECT object; - - LockDb(); - - if (object = FindDbObjectForProcess(processItem, INTENT_PROCESS_AFFINITY)) - { - // Update the process affinity in our database (if the database values are different). - if (object->AffinityMask != (ULONG)newAffinityMask) - { - object->AffinityMask = (ULONG)newAffinityMask; - changed = TRUE; - } - } - - UnlockDb(); - - if (changed) - { - SaveDb(); - } - - // Update the process affinity in Windows (if the system values are different). - if (affinityMask != newAffinityMask) - { - HANDLE processHandle; - - if (NT_SUCCESS(PhOpenProcess( - &processHandle, - PROCESS_SET_INFORMATION, - processItem->ProcessId - ))) - { - PhSetProcessAffinityMask(processHandle, newAffinityMask); - NtClose(processHandle); - } - } - } - } - break; - } -} - -VOID InvalidateProcessComments( - VOID - ) -{ - PLIST_ENTRY listEntry; - - PhAcquireQueuedLockExclusive(&ProcessListLock); - - listEntry = ProcessListHead.Flink; - - while (listEntry != &ProcessListHead) - { - PPROCESS_EXTENSION extension; - - extension = CONTAINING_RECORD(listEntry, PROCESS_EXTENSION, ListEntry); - - extension->Valid = FALSE; - - listEntry = listEntry->Flink; - } - - PhReleaseQueuedLockExclusive(&ProcessListLock); -} - -VOID UpdateProcessComment( - _In_ PPH_PROCESS_NODE Node, - _In_ PPROCESS_EXTENSION Extension - ) -{ - if (!Extension->Valid) - { - PDB_OBJECT object; - - LockDb(); - - if (object = FindDbObjectForProcess(Node->ProcessItem, INTENT_PROCESS_COMMENT)) - { - PhSwapReference(&Extension->Comment, object->Comment); - } - else - { - PhClearReference(&Extension->Comment); - } - - UnlockDb(); - - Extension->Valid = TRUE; - } -} - -VOID InvalidateServiceComments( - VOID - ) -{ - PLIST_ENTRY listEntry; - - PhAcquireQueuedLockExclusive(&ServiceListLock); - - listEntry = ServiceListHead.Flink; - - while (listEntry != &ServiceListHead) - { - PSERVICE_EXTENSION extension; - - extension = CONTAINING_RECORD(listEntry, SERVICE_EXTENSION, ListEntry); - - extension->Valid = FALSE; - - listEntry = listEntry->Flink; - } - - PhReleaseQueuedLockExclusive(&ServiceListLock); -} - -VOID UpdateServiceComment( - _In_ PPH_SERVICE_NODE Node, - _In_ PSERVICE_EXTENSION Extension - ) -{ - if (!Extension->Valid) - { - PDB_OBJECT object; - - LockDb(); - - if (object = FindDbObject(SERVICE_TAG, &Node->ServiceItem->Name->sr)) - { - PhSwapReference(&Extension->Comment, object->Comment); - } - else - { - PhClearReference(&Extension->Comment); - } - - UnlockDb(); - - Extension->Valid = TRUE; - } -} - -VOID TreeNewMessageCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - PPH_PLUGIN_TREENEW_MESSAGE message = Parameter; - - switch (message->Message) - { - case TreeNewGetCellText: - { - PPH_TREENEW_GET_CELL_TEXT getCellText = message->Parameter1; - - if (message->TreeNewHandle == ProcessTreeNewHandle) - { - PPH_PROCESS_NODE node; - - node = (PPH_PROCESS_NODE)getCellText->Node; - - switch (message->SubId) - { - case COMMENT_COLUMN_ID: - { - PPROCESS_EXTENSION extension; - - extension = PhPluginGetObjectExtension(PluginInstance, node->ProcessItem, EmProcessItemType); - UpdateProcessComment(node, extension); - getCellText->Text = PhGetStringRef(extension->Comment); - } - break; - } - } - else if (message->TreeNewHandle == ServiceTreeNewHandle) - { - PPH_SERVICE_NODE node; - - node = (PPH_SERVICE_NODE)getCellText->Node; - - switch (message->SubId) - { - case COMMENT_COLUMN_ID: - { - PSERVICE_EXTENSION extension; - - extension = PhPluginGetObjectExtension(PluginInstance, node->ServiceItem, EmServiceItemType); - UpdateServiceComment(node, extension); - getCellText->Text = PhGetStringRef(extension->Comment); - } - break; - } - } - } - break; - } -} - -VOID MainWindowShowingCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - if (ToolStatusInterface) - { - PhRegisterCallback(ToolStatusInterface->SearchChangedEvent, SearchChangedHandler, NULL, &SearchChangedRegistration); - } -} - -VOID ProcessPropertiesInitializingCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - PPH_PLUGIN_PROCESS_PROPCONTEXT propContext = Parameter; - - PhAddProcessPropPage( - propContext->PropContext, - PhCreateProcessPropPageContextEx(PluginInstance->DllBase, MAKEINTRESOURCE(IDD_PROCCOMMENT), ProcessCommentPageDlgProc, NULL) - ); -} - -VOID AddSavePriorityMenuItemsAndHook( - _In_ PPH_PLUGIN_MENU_INFORMATION MenuInfo, - _In_ PPH_PROCESS_ITEM ProcessItem, - _In_ BOOLEAN UseSelectionForHook - ) -{ - PPH_EMENU_ITEM affinityMenuItem; - PPH_EMENU_ITEM priorityMenuItem; - PPH_EMENU_ITEM ioPriorityMenuItem; - PPH_EMENU_ITEM saveMenuItem; - PPH_EMENU_ITEM saveForCommandLineMenuItem; - PDB_OBJECT object; - - if (affinityMenuItem = PhFindEMenuItem(MenuInfo->Menu, 0, L"Affinity", PHAPP_ID_PROCESS_AFFINITY)) - { - // HACK: Change default Affinity menu-item into a drop-down list - PhInsertEMenuItem(affinityMenuItem, PhCreateEMenuItem(0, affinityMenuItem->Id, L"Set &affinity", NULL, NULL), -1); - //PhInsertEMenuItem(affinityMenuItem, PhPluginCreateEMenuItem(PluginInstance, 0, PHAPP_ID_PROCESS_AFFINITY, L"Set &affinity", NULL), PhIndexOfEMenuItem(MenuInfo->Menu, affinityMenuItem) + 1); - //PhRemoveEMenuItem(affinityMenuItem, affinityMenuItem, 0); - - // Insert standard menu-items - PhInsertEMenuItem(affinityMenuItem, PhPluginCreateEMenuItem(PluginInstance, PH_EMENU_SEPARATOR, 0, NULL, NULL), -1); - PhInsertEMenuItem(affinityMenuItem, saveMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, PROCESS_AFFINITY_SAVE_ID, PhaFormatString(L"Save for %s", ProcessItem->ProcessName->Buffer)->Buffer, NULL), -1); - PhInsertEMenuItem(affinityMenuItem, saveForCommandLineMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, PROCESS_AFFINITY_SAVE_FOR_THIS_COMMAND_LINE_ID, L"Save for this command line", NULL), -1); - - if (!ProcessItem->CommandLine) - saveForCommandLineMenuItem->Flags |= PH_EMENU_DISABLED; - - LockDb(); - - if ((object = FindDbObject(FILE_TAG, &ProcessItem->ProcessName->sr)) && object->AffinityMask != 0) - saveMenuItem->Flags |= PH_EMENU_CHECKED; - if (ProcessItem->CommandLine && (object = FindDbObject(COMMAND_LINE_TAG, &ProcessItem->CommandLine->sr)) && object->AffinityMask != 0) - saveForCommandLineMenuItem->Flags |= PH_EMENU_CHECKED; - - UnlockDb(); - } - - // Priority - if (priorityMenuItem = PhFindEMenuItem(MenuInfo->Menu, 0, L"Priority", 0)) - { - PhInsertEMenuItem(priorityMenuItem, PhPluginCreateEMenuItem(PluginInstance, PH_EMENU_SEPARATOR, 0, NULL, NULL), -1); - PhInsertEMenuItem(priorityMenuItem, saveMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, PROCESS_PRIORITY_SAVE_ID, PhaFormatString(L"Save for %s", ProcessItem->ProcessName->Buffer)->Buffer, NULL), -1); - PhInsertEMenuItem(priorityMenuItem, saveForCommandLineMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, PROCESS_PRIORITY_SAVE_FOR_THIS_COMMAND_LINE_ID, L"Save for this command line", NULL), -1); - - if (!ProcessItem->CommandLine) - saveForCommandLineMenuItem->Flags |= PH_EMENU_DISABLED; - - LockDb(); - - if ((object = FindDbObject(FILE_TAG, &ProcessItem->ProcessName->sr)) && object->PriorityClass != 0) - saveMenuItem->Flags |= PH_EMENU_CHECKED; - if (ProcessItem->CommandLine && (object = FindDbObject(COMMAND_LINE_TAG, &ProcessItem->CommandLine->sr)) && object->PriorityClass != 0) - saveForCommandLineMenuItem->Flags |= PH_EMENU_CHECKED; - - UnlockDb(); - } - - // I/O Priority - if (ioPriorityMenuItem = PhFindEMenuItem(MenuInfo->Menu, 0, L"I/O Priority", 0)) - { - PhInsertEMenuItem(ioPriorityMenuItem, PhPluginCreateEMenuItem(PluginInstance, PH_EMENU_SEPARATOR, 0, NULL, NULL), -1); - PhInsertEMenuItem(ioPriorityMenuItem, saveMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, PROCESS_IO_PRIORITY_SAVE_ID, PhaFormatString(L"Save for %s", ProcessItem->ProcessName->Buffer)->Buffer, NULL), -1); - PhInsertEMenuItem(ioPriorityMenuItem, saveForCommandLineMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, PROCESS_IO_PRIORITY_SAVE_FOR_THIS_COMMAND_LINE_ID, L"Save for this command line", NULL), -1); - - if (!ProcessItem->CommandLine) - saveForCommandLineMenuItem->Flags |= PH_EMENU_DISABLED; - - LockDb(); - - if ((object = FindDbObject(FILE_TAG, &ProcessItem->ProcessName->sr)) && object->IoPriorityPlusOne != 0) - saveMenuItem->Flags |= PH_EMENU_CHECKED; - if (ProcessItem->CommandLine && (object = FindDbObject(COMMAND_LINE_TAG, &ProcessItem->CommandLine->sr)) && object->IoPriorityPlusOne != 0) - saveForCommandLineMenuItem->Flags |= PH_EMENU_CHECKED; - - UnlockDb(); - } - - PhPluginAddMenuHook(MenuInfo, PluginInstance, UseSelectionForHook ? NULL : ProcessItem->ProcessId); -} - -VOID ProcessMenuInitializingCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - BOOLEAN highlightPresent = FALSE; - PPH_PLUGIN_MENU_INFORMATION menuInfo = Parameter; - PPH_PROCESS_ITEM processItem; - PPH_EMENU_ITEM miscMenuItem; - PPH_EMENU_ITEM collapseMenuItem; - PPH_EMENU_ITEM highlightMenuItem; - PDB_OBJECT object; - - if (menuInfo->u.Process.NumberOfProcesses != 1) - return; - - processItem = menuInfo->u.Process.Processes[0]; - - if (!PH_IS_FAKE_PROCESS_ID(processItem->ProcessId) && processItem->ProcessId != SYSTEM_IDLE_PROCESS_ID && processItem->ProcessId != SYSTEM_PROCESS_ID) - AddSavePriorityMenuItemsAndHook(menuInfo, processItem, TRUE); - - if (!(miscMenuItem = PhFindEMenuItem(menuInfo->Menu, 0, L"Miscellaneous", 0))) - return; - - LockDb(); - if ((object = FindDbObject(FILE_TAG, &processItem->ProcessName->sr)) && object->BackColor != ULONG_MAX) - highlightPresent = TRUE; - UnlockDb(); - - PhInsertEMenuItem(miscMenuItem, collapseMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, PROCESS_COLLAPSE_ID, L"Collapse by default", NULL), 0); - PhInsertEMenuItem(miscMenuItem, highlightMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, PROCESS_HIGHLIGHT_ID, L"Highlight", UlongToPtr(highlightPresent)), 1); - PhInsertEMenuItem(miscMenuItem, PhPluginCreateEMenuItem(PluginInstance, PH_EMENU_SEPARATOR, 0, NULL, NULL), 2); - - LockDb(); - - if ((object = FindDbObject(FILE_TAG, &menuInfo->u.Process.Processes[0]->ProcessName->sr)) && object->Collapse) - collapseMenuItem->Flags |= PH_EMENU_CHECKED; - if (highlightPresent) - highlightMenuItem->Flags |= PH_EMENU_CHECKED; - - UnlockDb(); -} - -static LONG NTAPI ProcessCommentSortFunction( - _In_ PVOID Node1, - _In_ PVOID Node2, - _In_ ULONG SubId, - _In_ PVOID Context - ) -{ - PPH_PROCESS_NODE node1 = Node1; - PPH_PROCESS_NODE node2 = Node2; - PPROCESS_EXTENSION extension1 = PhPluginGetObjectExtension(PluginInstance, node1->ProcessItem, EmProcessItemType); - PPROCESS_EXTENSION extension2 = PhPluginGetObjectExtension(PluginInstance, node2->ProcessItem, EmProcessItemType); - - UpdateProcessComment(node1, extension1); - UpdateProcessComment(node2, extension2); - - return PhCompareStringWithNull(extension1->Comment, extension2->Comment, TRUE); -} - -VOID ProcessTreeNewInitializingCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - PPH_PLUGIN_TREENEW_INFORMATION info = Parameter; - PH_TREENEW_COLUMN column; - - ProcessTreeNewHandle = info->TreeNewHandle; - - memset(&column, 0, sizeof(PH_TREENEW_COLUMN)); - column.Text = L"Comment"; - column.Width = 120; - column.Alignment = PH_ALIGN_LEFT; - - PhPluginAddTreeNewColumn(PluginInstance, info->CmData, &column, COMMENT_COLUMN_ID, NULL, ProcessCommentSortFunction); -} - -VOID GetProcessHighlightingColorCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - PPH_PLUGIN_GET_HIGHLIGHTING_COLOR getHighlightingColor = Parameter; - PPH_PROCESS_ITEM processItem = (PPH_PROCESS_ITEM)getHighlightingColor->Parameter; - PDB_OBJECT object; - - if (getHighlightingColor->Handled) - return; - - LockDb(); - - if ((object = FindDbObject(FILE_TAG, &processItem->ProcessName->sr)) && object->BackColor != ULONG_MAX) - { - getHighlightingColor->BackColor = object->BackColor; - getHighlightingColor->Cache = TRUE; - getHighlightingColor->Handled = TRUE; - } - - UnlockDb(); -} - -VOID ServicePropertiesInitializingCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - PPH_PLUGIN_OBJECT_PROPERTIES objectProperties = Parameter; - PROPSHEETPAGE propSheetPage; - - if (objectProperties->NumberOfPages < objectProperties->MaximumNumberOfPages) - { - memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); - propSheetPage.dwSize = sizeof(PROPSHEETPAGE); - propSheetPage.dwFlags = PSP_USETITLE; - propSheetPage.hInstance = PluginInstance->DllBase; - propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_SRVCOMMENT); - propSheetPage.pszTitle = L"Comment"; - propSheetPage.pfnDlgProc = ServiceCommentPageDlgProc; - propSheetPage.lParam = (LPARAM)objectProperties->Parameter; - objectProperties->Pages[objectProperties->NumberOfPages++] = CreatePropertySheetPage(&propSheetPage); - } -} - -LONG NTAPI ServiceCommentSortFunction( - _In_ PVOID Node1, - _In_ PVOID Node2, - _In_ ULONG SubId, - _In_ PVOID Context - ) -{ - PPH_SERVICE_NODE node1 = Node1; - PPH_SERVICE_NODE node2 = Node2; - PSERVICE_EXTENSION extension1 = PhPluginGetObjectExtension(PluginInstance, node1->ServiceItem, EmServiceItemType); - PSERVICE_EXTENSION extension2 = PhPluginGetObjectExtension(PluginInstance, node2->ServiceItem, EmServiceItemType); - - UpdateServiceComment(node1, extension1); - UpdateServiceComment(node2, extension2); - - return PhCompareStringWithNull(extension1->Comment, extension2->Comment, TRUE); -} - -VOID ServiceTreeNewInitializingCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - PPH_PLUGIN_TREENEW_INFORMATION info = Parameter; - PH_TREENEW_COLUMN column; - - ServiceTreeNewHandle = info->TreeNewHandle; - - memset(&column, 0, sizeof(PH_TREENEW_COLUMN)); - column.Text = L"Comment"; - column.Width = 120; - column.Alignment = PH_ALIGN_LEFT; - - PhPluginAddTreeNewColumn(PluginInstance, info->CmData, &column, COMMENT_COLUMN_ID, NULL, ServiceCommentSortFunction); -} - -VOID MiListSectionMenuInitializingCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - PPH_PLUGIN_MENU_INFORMATION menuInfo = Parameter; - PPH_PROCESS_ITEM processItem = menuInfo->u.MiListSection.ProcessGroup->Representative; - - if (PH_IS_FAKE_PROCESS_ID(processItem->ProcessId) || processItem->ProcessId == SYSTEM_IDLE_PROCESS_ID || processItem->ProcessId == SYSTEM_PROCESS_ID) - return; - - AddSavePriorityMenuItemsAndHook(menuInfo, processItem, FALSE); -} - -VOID ProcessModifiedCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - PPH_PROCESS_ITEM processItem = Parameter; - PPROCESS_EXTENSION extension = PhPluginGetObjectExtension(PluginInstance, processItem, EmProcessItemType); - - extension->Valid = FALSE; -} - -VOID ProcessesUpdatedCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - PLIST_ENTRY listEntry; - - if (GetNumberOfDbObjects() == 0) - return; - - PhAcquireQueuedLockExclusive(&ProcessListLock); - LockDb(); - - listEntry = ProcessListHead.Flink; - - while (listEntry != &ProcessListHead) - { - PPROCESS_EXTENSION extension; - PPH_PROCESS_ITEM processItem; - PDB_OBJECT object; - - extension = CONTAINING_RECORD(listEntry, PROCESS_EXTENSION, ListEntry); - processItem = extension->ProcessItem; - - if (object = FindDbObjectForProcess(processItem, INTENT_PROCESS_PRIORITY_CLASS)) - { - if (processItem->PriorityClass != object->PriorityClass) - { - HANDLE processHandle; - PROCESS_PRIORITY_CLASS priorityClass; - - if (NT_SUCCESS(PhOpenProcess( - &processHandle, - PROCESS_SET_INFORMATION, - processItem->ProcessId - ))) - { - priorityClass.Foreground = FALSE; - priorityClass.PriorityClass = (UCHAR)object->PriorityClass; - NtSetInformationProcess(processHandle, ProcessPriorityClass, &priorityClass, sizeof(PROCESS_PRIORITY_CLASS)); - - NtClose(processHandle); - } - } - } - - if (object = FindDbObjectForProcess(processItem, INTENT_PROCESS_IO_PRIORITY)) - { - if (object->IoPriorityPlusOne != 0) - { - HANDLE processHandle; - - if (NT_SUCCESS(PhOpenProcess( - &processHandle, - PROCESS_SET_INFORMATION, - processItem->ProcessId - ))) - { - PhSetProcessIoPriority(processHandle, object->IoPriorityPlusOne - 1); - NtClose(processHandle); - } - } - } - - if (object = FindDbObjectForProcess(processItem, INTENT_PROCESS_AFFINITY)) - { - if (object->AffinityMask != 0) - { - HANDLE processHandle; - - if (NT_SUCCESS(PhOpenProcess( - &processHandle, - PROCESS_SET_INFORMATION, - processItem->ProcessId - ))) - { - PhSetProcessAffinityMask(processHandle, object->AffinityMask); - NtClose(processHandle); - } - } - } - - listEntry = listEntry->Flink; - } - - UnlockDb(); - PhReleaseQueuedLockExclusive(&ProcessListLock); -} - -VOID SearchChangedHandler( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - PPH_STRING searchText = Parameter; - - if (PhIsNullOrEmptyString(searchText)) - { - // ToolStatus expanded all nodes for searching, but the search text just became empty. We - // should re-collapse processes. - - PPH_LIST nodes = PH_AUTO(PhDuplicateProcessNodeList()); - ULONG i; - BOOLEAN changed = FALSE; - - LockDb(); - - for (i = 0; i < nodes->Count; i++) - { - PPH_PROCESS_NODE node = nodes->Items[i]; - PDB_OBJECT object; - - if ((object = FindDbObjectForProcess(node->ProcessItem, INTENT_PROCESS_COLLAPSE)) && object->Collapse) - { - node->Node.Expanded = FALSE; - changed = TRUE; - } - } - - UnlockDb(); - - if (changed) - TreeNew_NodesStructured(ProcessTreeNewHandle); - } -} - -VOID ProcessItemCreateCallback( - _In_ PVOID Object, - _In_ PH_EM_OBJECT_TYPE ObjectType, - _In_ PVOID Extension - ) -{ - PPH_PROCESS_ITEM processItem = Object; - PPROCESS_EXTENSION extension = Extension; - - memset(extension, 0, sizeof(PROCESS_EXTENSION)); - extension->ProcessItem = processItem; - - PhAcquireQueuedLockExclusive(&ProcessListLock); - InsertTailList(&ProcessListHead, &extension->ListEntry); - PhReleaseQueuedLockExclusive(&ProcessListLock); -} - -VOID ProcessItemDeleteCallback( - _In_ PVOID Object, - _In_ PH_EM_OBJECT_TYPE ObjectType, - _In_ PVOID Extension - ) -{ - PPH_PROCESS_ITEM processItem = Object; - PPROCESS_EXTENSION extension = Extension; - - PhClearReference(&extension->Comment); - PhAcquireQueuedLockExclusive(&ProcessListLock); - RemoveEntryList(&extension->ListEntry); - PhReleaseQueuedLockExclusive(&ProcessListLock); -} - -VOID ProcessNodeCreateCallback( - _In_ PVOID Object, - _In_ PH_EM_OBJECT_TYPE ObjectType, - _In_ PVOID Extension - ) -{ - PPH_PROCESS_NODE processNode = Object; - PDB_OBJECT object; - - LockDb(); - - if ((object = FindDbObjectForProcess(processNode->ProcessItem, INTENT_PROCESS_COLLAPSE)) && object->Collapse) - processNode->Node.Expanded = FALSE; - - UnlockDb(); -} - -VOID ServiceItemCreateCallback( - _In_ PVOID Object, - _In_ PH_EM_OBJECT_TYPE ObjectType, - _In_ PVOID Extension - ) -{ - PPH_SERVICE_ITEM processItem = Object; - PSERVICE_EXTENSION extension = Extension; - - memset(extension, 0, sizeof(SERVICE_EXTENSION)); - PhAcquireQueuedLockExclusive(&ServiceListLock); - InsertTailList(&ServiceListHead, &extension->ListEntry); - PhReleaseQueuedLockExclusive(&ServiceListLock); -} - -VOID ServiceItemDeleteCallback( - _In_ PVOID Object, - _In_ PH_EM_OBJECT_TYPE ObjectType, - _In_ PVOID Extension - ) -{ - PPH_SERVICE_ITEM processItem = Object; - PSERVICE_EXTENSION extension = Extension; - - PhClearReference(&extension->Comment); - PhAcquireQueuedLockExclusive(&ServiceListLock); - RemoveEntryList(&extension->ListEntry); - PhReleaseQueuedLockExclusive(&ServiceListLock); -} - -LOGICAL DllMain( - _In_ HINSTANCE Instance, - _In_ ULONG Reason, - _Reserved_ PVOID Reserved - ) -{ - if (Reason == DLL_PROCESS_ATTACH) - { - PPH_PLUGIN_INFORMATION info; - PH_SETTING_CREATE settings[] = - { - { StringSettingType, SETTING_NAME_DATABASE_PATH, L"%APPDATA%\\Process Hacker 2\\usernotesdb.xml" }, - { StringSettingType, SETTING_NAME_CUSTOM_COLOR_LIST, L"" } - }; - - PluginInstance = PhRegisterPlugin(PLUGIN_NAME, Instance, &info); - - if (!PluginInstance) - return FALSE; - - info->DisplayName = L"User Notes"; - info->Author = L"dmex, wj32"; - info->Description = L"Allows the user to add comments for processes and services, save process priority and affinity, highlight individual processes and show processes collapsed by default."; - info->Url = L"https://wj32.org/processhacker/forums/viewtopic.php?t=1120"; - info->HasOptions = TRUE; - - InitializeDb(); - - PhRegisterCallback( - PhGetPluginCallback(PluginInstance, PluginCallbackLoad), - LoadCallback, - NULL, - &PluginLoadCallbackRegistration - ); - PhRegisterCallback( - PhGetPluginCallback(PluginInstance, PluginCallbackUnload), - UnloadCallback, - NULL, - &PluginUnloadCallbackRegistration - ); - PhRegisterCallback( - PhGetPluginCallback(PluginInstance, PluginCallbackShowOptions), - ShowOptionsCallback, - NULL, - &PluginShowOptionsCallbackRegistration - ); - PhRegisterCallback( - PhGetPluginCallback(PluginInstance, PluginCallbackMenuItem), - MenuItemCallback, - NULL, - &PluginMenuItemCallbackRegistration - ); - PhRegisterCallback( - PhGetPluginCallback(PluginInstance, PluginCallbackMenuHook), - MenuHookCallback, - NULL, - &PluginMenuHookCallbackRegistration - ); - PhRegisterCallback( - PhGetPluginCallback(PluginInstance, PluginCallbackTreeNewMessage), - TreeNewMessageCallback, - NULL, - &TreeNewMessageCallbackRegistration - ); - PhRegisterCallback( - PhGetGeneralCallback(GeneralCallbackMainWindowShowing), - MainWindowShowingCallback, - NULL, - &MainWindowShowingCallbackRegistration - ); - PhRegisterCallback( - PhGetGeneralCallback(GeneralCallbackProcessPropertiesInitializing), - ProcessPropertiesInitializingCallback, - NULL, - &ProcessPropertiesInitializingCallbackRegistration - ); - PhRegisterCallback( - PhGetGeneralCallback(GeneralCallbackServicePropertiesInitializing), - ServicePropertiesInitializingCallback, - NULL, - &ServicePropertiesInitializingCallbackRegistration - ); - PhRegisterCallback( - PhGetGeneralCallback(GeneralCallbackProcessMenuInitializing), - ProcessMenuInitializingCallback, - NULL, - &ProcessMenuInitializingCallbackRegistration - ); - PhRegisterCallback( - PhGetGeneralCallback(GeneralCallbackProcessTreeNewInitializing), - ProcessTreeNewInitializingCallback, - NULL, - &ProcessTreeNewInitializingCallbackRegistration - ); - PhRegisterCallback( - PhGetGeneralCallback(GeneralCallbackGetProcessHighlightingColor), - GetProcessHighlightingColorCallback, - NULL, - &GetProcessHighlightingColorCallbackRegistration - ); - PhRegisterCallback( - PhGetGeneralCallback(GeneralCallbackServiceTreeNewInitializing), - ServiceTreeNewInitializingCallback, - NULL, - &ServiceTreeNewInitializingCallbackRegistration - ); - PhRegisterCallback( - PhGetGeneralCallback(GeneralCallbackMiListSectionMenuInitializing), - MiListSectionMenuInitializingCallback, - NULL, - &MiListSectionMenuInitializingCallbackRegistration - ); - PhRegisterCallback(&PhProcessModifiedEvent, - ProcessModifiedCallback, - NULL, - &ProcessModifiedCallbackRegistration - ); - PhRegisterCallback( - &PhProcessesUpdatedEvent, - ProcessesUpdatedCallback, - NULL, - &ProcessesUpdatedCallbackRegistration - ); - - PhPluginSetObjectExtension( - PluginInstance, - EmProcessItemType, - sizeof(PROCESS_EXTENSION), - ProcessItemCreateCallback, - ProcessItemDeleteCallback - ); - PhPluginSetObjectExtension( - PluginInstance, - EmProcessNodeType, - sizeof(PROCESS_EXTENSION), - ProcessNodeCreateCallback, - NULL - ); - PhPluginSetObjectExtension( - PluginInstance, - EmServiceItemType, - sizeof(SERVICE_EXTENSION), - ServiceItemCreateCallback, - ServiceItemDeleteCallback - ); - - PhAddSettings(settings, ARRAYSIZE(settings)); - } - - return TRUE; -} - -INT_PTR CALLBACK OptionsDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - switch (uMsg) - { - case WM_INITDIALOG: - { - PhCenterWindow(hwndDlg, GetParent(hwndDlg)); - - SetDlgItemText(hwndDlg, IDC_DATABASE, PhaGetStringSetting(SETTING_NAME_DATABASE_PATH)->Buffer); - - SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hwndDlg, IDCANCEL), TRUE); - } - break; - case WM_COMMAND: - { - switch (LOWORD(wParam)) - { - case IDCANCEL: - EndDialog(hwndDlg, IDCANCEL); - break; - case IDOK: - { - PhSetStringSetting2(SETTING_NAME_DATABASE_PATH, - &PhaGetDlgItemText(hwndDlg, IDC_DATABASE)->sr); - - EndDialog(hwndDlg, IDOK); - } - break; - case IDC_BROWSE: - { - static PH_FILETYPE_FILTER filters[] = - { - { L"XML files (*.xml)", L"*.xml" }, - { L"All files (*.*)", L"*.*" } - }; - PVOID fileDialog; - PPH_STRING fileName; - - fileDialog = PhCreateOpenFileDialog(); - PhSetFileDialogFilter(fileDialog, filters, sizeof(filters) / sizeof(PH_FILETYPE_FILTER)); - - fileName = PH_AUTO(PhGetFileName(PhaGetDlgItemText(hwndDlg, IDC_DATABASE))); - PhSetFileDialogFileName(fileDialog, fileName->Buffer); - - if (PhShowFileDialog(hwndDlg, fileDialog)) - { - fileName = PH_AUTO(PhGetFileDialogFileName(fileDialog)); - SetDlgItemText(hwndDlg, IDC_DATABASE, fileName->Buffer); - } - - PhFreeFileDialog(fileDialog); - } - break; - } - } - break; - } - - return FALSE; -} - -INT_PTR CALLBACK ProcessCommentPageDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - LPPROPSHEETPAGE propSheetPage; - PPH_PROCESS_PROPPAGECONTEXT propPageContext; - PPH_PROCESS_ITEM processItem; - PPROCESS_COMMENT_PAGE_CONTEXT context; - - if (PhPropPageDlgProcHeader(hwndDlg, uMsg, lParam, &propSheetPage, &propPageContext, &processItem)) - { - context = propPageContext->Context; - } - else - { - return FALSE; - } - - switch (uMsg) - { - case WM_INITDIALOG: - { - PDB_OBJECT object; - PPH_STRING comment; - - context = PhAllocate(sizeof(PROCESS_COMMENT_PAGE_CONTEXT)); - context->CommentHandle = GetDlgItem(hwndDlg, IDC_COMMENT); - context->RevertHandle = GetDlgItem(hwndDlg, IDC_REVERT); - context->MatchCommandlineHandle = GetDlgItem(hwndDlg, IDC_MATCHCOMMANDLINE); - propPageContext->Context = context; - - // Load the comment. - Edit_LimitText(context->CommentHandle, UNICODE_STRING_MAX_CHARS); - - LockDb(); - - if (object = FindDbObjectForProcess(processItem, INTENT_PROCESS_COMMENT)) - { - PhSetReference(&comment, object->Comment); - - if (processItem->CommandLine && (object = FindDbObject(COMMAND_LINE_TAG, &processItem->CommandLine->sr)) && object->Comment->Length != 0) - { - Button_SetCheck(context->MatchCommandlineHandle, BST_CHECKED); - } - } - else - { - comment = PhReferenceEmptyString(); - } - - UnlockDb(); - - Edit_SetText(context->CommentHandle, comment->Buffer); - context->OriginalComment = comment; - - if (!processItem->CommandLine) - EnableWindow(context->MatchCommandlineHandle, FALSE); - } - break; - case WM_DESTROY: - { - PDB_OBJECT object; - PPH_STRING comment; - BOOLEAN matchCommandLine; - BOOLEAN done = FALSE; - - comment = PH_AUTO(PhGetWindowText(context->CommentHandle)); - matchCommandLine = Button_GetCheck(context->MatchCommandlineHandle) == BST_CHECKED; - - if (!processItem->CommandLine) - matchCommandLine = FALSE; - - LockDb(); - - if (processItem->CommandLine && !matchCommandLine) - { - PDB_OBJECT objectForProcessName; - PPH_STRING message = NULL; - - object = FindDbObject(COMMAND_LINE_TAG, &processItem->CommandLine->sr); - objectForProcessName = FindDbObject(FILE_TAG, &processItem->ProcessName->sr); - - if (object && objectForProcessName && object->Comment->Length != 0 && objectForProcessName->Comment->Length != 0 && - !PhEqualString(comment, objectForProcessName->Comment, FALSE)) - { - message = PhaFormatString( - L"Do you want to replace the comment for %s which is currently\n \"%s\"\n" - L"with\n \"%s\"?", - processItem->ProcessName->Buffer, - objectForProcessName->Comment->Buffer, - comment->Buffer - ); - } - - if (object) - { - PhMoveReference(&object->Comment, PhReferenceEmptyString()); - DeleteDbObjectForProcessIfUnused(object); - } - - if (message) - { - // Prevent deadlocks. - UnlockDb(); - - if (MessageBox(hwndDlg, message->Buffer, L"Comment", MB_ICONQUESTION | MB_YESNO) == IDNO) - { - done = TRUE; - } - - LockDb(); - } - } - - if (!done) - { - if (comment->Length != 0) - { - if (matchCommandLine) - CreateDbObject(COMMAND_LINE_TAG, &processItem->CommandLine->sr, comment); - else - CreateDbObject(FILE_TAG, &processItem->ProcessName->sr, comment); - } - else - { - if ( - (!matchCommandLine && (object = FindDbObject(FILE_TAG, &processItem->ProcessName->sr))) || - (matchCommandLine && (object = FindDbObject(COMMAND_LINE_TAG, &processItem->CommandLine->sr))) - ) - { - PhMoveReference(&object->Comment, PhReferenceEmptyString()); - DeleteDbObjectForProcessIfUnused(object); - } - } - } - - UnlockDb(); - - PhDereferenceObject(context->OriginalComment); - PhFree(context); - - PhPropPageDlgProcDestroy(hwndDlg); - - SaveDb(); - InvalidateProcessComments(); - } - break; - case WM_SHOWWINDOW: - { - PPH_LAYOUT_ITEM dialogItem; - - if (dialogItem = PhBeginPropPageLayout(hwndDlg, propPageContext)) - { - PhAddPropPageLayoutItem(hwndDlg, context->CommentHandle, dialogItem, PH_ANCHOR_ALL); - PhAddPropPageLayoutItem(hwndDlg, context->RevertHandle, dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_BOTTOM); - PhAddPropPageLayoutItem(hwndDlg, context->MatchCommandlineHandle, dialogItem, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); - PhEndPropPageLayout(hwndDlg, propPageContext); - } - } - break; - case WM_COMMAND: - { - switch (LOWORD(wParam)) - { - case IDC_COMMENT: - { - if (HIWORD(wParam) == EN_CHANGE) - EnableWindow(context->RevertHandle, TRUE); - } - break; - case IDC_REVERT: - { - Edit_SetText(context->CommentHandle, context->OriginalComment->Buffer); - SendMessage(context->CommentHandle, EM_SETSEL, 0, -1); - SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)context->CommentHandle, TRUE); - EnableWindow(context->RevertHandle, FALSE); - } - break; - } - } - break; - case WM_NOTIFY: - { - LPNMHDR header = (LPNMHDR)lParam; - - switch (header->code) - { - case PSN_QUERYINITIALFOCUS: - { - SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, (LONG_PTR)context->MatchCommandlineHandle); - } - return TRUE; - } - } - break; - } - - return FALSE; -} - -INT_PTR CALLBACK ServiceCommentPageDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - PSERVICE_COMMENT_PAGE_CONTEXT context; - - if (uMsg == WM_INITDIALOG) - { - context = PhAllocate(sizeof(SERVICE_COMMENT_PAGE_CONTEXT)); - memset(context, 0, sizeof(SERVICE_COMMENT_PAGE_CONTEXT)); - - SetProp(hwndDlg, L"Context", (HANDLE)context); - } - else - { - context = (PSERVICE_COMMENT_PAGE_CONTEXT)GetProp(hwndDlg, L"Context"); - - if (uMsg == WM_DESTROY) - RemoveProp(hwndDlg, L"Context"); - } - - if (!context) - return FALSE; - - switch (uMsg) - { - case WM_INITDIALOG: - { - LPPROPSHEETPAGE propSheetPage = (LPPROPSHEETPAGE)lParam; - PPH_SERVICE_ITEM serviceItem = (PPH_SERVICE_ITEM)propSheetPage->lParam; - PDB_OBJECT object; - PPH_STRING comment; - - context->ServiceItem = serviceItem; - - PhInitializeLayoutManager(&context->LayoutManager, hwndDlg); - PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_COMMENT), NULL, PH_ANCHOR_ALL); - - // Load the comment. - - SendMessage(GetDlgItem(hwndDlg, IDC_COMMENT), EM_SETLIMITTEXT, UNICODE_STRING_MAX_CHARS, 0); - - LockDb(); - - if (object = FindDbObject(SERVICE_TAG, &serviceItem->Name->sr)) - comment = object->Comment; - else - comment = PH_AUTO(PhReferenceEmptyString()); - - UnlockDb(); - - SetDlgItemText(hwndDlg, IDC_COMMENT, comment->Buffer); - - EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); - } - break; - case WM_DESTROY: - { - PhDeleteLayoutManager(&context->LayoutManager); - PhFree(context); - } - break; - case WM_SIZE: - { - PhLayoutManagerLayout(&context->LayoutManager); - } - break; - case WM_COMMAND: - { - switch (LOWORD(wParam)) - { - case IDC_COMMENT: - { - if (HIWORD(wParam) == EN_CHANGE) - EnableWindow(GetDlgItem(hwndDlg, IDC_REVERT), TRUE); - } - break; - } - } - break; - case WM_NOTIFY: - { - LPNMHDR header = (LPNMHDR)lParam; - - switch (header->code) - { - case PSN_KILLACTIVE: - { - SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, FALSE); - } - return TRUE; - case PSN_APPLY: - { - PDB_OBJECT object; - PPH_STRING comment; - - comment = PH_AUTO(PhGetWindowText(GetDlgItem(hwndDlg, IDC_COMMENT))); - - LockDb(); - - if (comment->Length != 0) - { - CreateDbObject(SERVICE_TAG, &context->ServiceItem->Name->sr, comment); - } - else - { - if (object = FindDbObject(SERVICE_TAG, &context->ServiceItem->Name->sr)) - DeleteDbObject(object); - } - - UnlockDb(); - - SaveDb(); - InvalidateServiceComments(); - - SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_NOERROR); - } - return TRUE; - } - } - break; - } - - return FALSE; -} - -UINT_PTR CALLBACK ColorDlgHookProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - switch (uMsg) - { - case WM_INITDIALOG: - { - PhCenterWindow(hwndDlg, PhMainWndHandle); - - EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); - } - break; - } - - return FALSE; +/* + * Process Hacker User Notes - + * main program + * + * Copyright (C) 2011-2016 wj32 + * Copyright (C) 2016 dmex + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include "usernotes.h" +#include +#include + +VOID SearchChangedHandler( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ); + +static PPH_PLUGIN PluginInstance; +static PH_CALLBACK_REGISTRATION PluginLoadCallbackRegistration; +static PH_CALLBACK_REGISTRATION PluginUnloadCallbackRegistration; +static PH_CALLBACK_REGISTRATION PluginShowOptionsCallbackRegistration; +static PH_CALLBACK_REGISTRATION PluginMenuItemCallbackRegistration; +static PH_CALLBACK_REGISTRATION PluginMenuHookCallbackRegistration; +static PH_CALLBACK_REGISTRATION TreeNewMessageCallbackRegistration; +static PH_CALLBACK_REGISTRATION MainWindowShowingCallbackRegistration; +static PH_CALLBACK_REGISTRATION ProcessPropertiesInitializingCallbackRegistration; +static PH_CALLBACK_REGISTRATION ServicePropertiesInitializingCallbackRegistration; +static PH_CALLBACK_REGISTRATION ProcessMenuInitializingCallbackRegistration; +static PH_CALLBACK_REGISTRATION ProcessTreeNewInitializingCallbackRegistration; +static PH_CALLBACK_REGISTRATION GetProcessHighlightingColorCallbackRegistration; +static PH_CALLBACK_REGISTRATION ServiceTreeNewInitializingCallbackRegistration; +static PH_CALLBACK_REGISTRATION MiListSectionMenuInitializingCallbackRegistration; +static PH_CALLBACK_REGISTRATION ProcessModifiedCallbackRegistration; +static PH_CALLBACK_REGISTRATION ProcessesUpdatedCallbackRegistration; +static PH_CALLBACK_REGISTRATION SearchChangedRegistration; + +static PTOOLSTATUS_INTERFACE ToolStatusInterface = NULL; + +HWND ProcessTreeNewHandle; +LIST_ENTRY ProcessListHead = { &ProcessListHead, &ProcessListHead }; +PH_QUEUED_LOCK ProcessListLock = PH_QUEUED_LOCK_INIT; + +HWND ServiceTreeNewHandle; +LIST_ENTRY ServiceListHead = { &ServiceListHead, &ServiceListHead }; +PH_QUEUED_LOCK ServiceListLock = PH_QUEUED_LOCK_INIT; + +static COLORREF ProcessCustomColors[16] = { 0 }; + +BOOLEAN MatchDbObjectIntent( + _In_ PDB_OBJECT Object, + _In_ ULONG Intent + ) +{ + return (!(Intent & INTENT_PROCESS_COMMENT) || Object->Comment->Length != 0) && + (!(Intent & INTENT_PROCESS_PRIORITY_CLASS) || Object->PriorityClass != 0) && + (!(Intent & INTENT_PROCESS_IO_PRIORITY) || Object->IoPriorityPlusOne != 0) && + (!(Intent & INTENT_PROCESS_HIGHLIGHT) || Object->BackColor != ULONG_MAX) && + (!(Intent & INTENT_PROCESS_COLLAPSE) || Object->Collapse == TRUE) && + (!(Intent & INTENT_PROCESS_AFFINITY) || Object->AffinityMask != 0); +} + +PDB_OBJECT FindDbObjectForProcess( + _In_ PPH_PROCESS_ITEM ProcessItem, + _In_ ULONG Intent + ) +{ + PDB_OBJECT object; + + if ( + ProcessItem->CommandLine && + (object = FindDbObject(COMMAND_LINE_TAG, &ProcessItem->CommandLine->sr)) && + MatchDbObjectIntent(object, Intent) + ) + { + return object; + } + + if ( + (object = FindDbObject(FILE_TAG, &ProcessItem->ProcessName->sr)) && + MatchDbObjectIntent(object, Intent) + ) + { + return object; + } + + return NULL; +} + +VOID DeleteDbObjectForProcessIfUnused( + _In_ PDB_OBJECT Object + ) +{ + if ( + Object->Comment->Length == 0 && + Object->PriorityClass == 0 && + Object->IoPriorityPlusOne == 0 && + Object->BackColor == ULONG_MAX && + Object->Collapse == FALSE && + Object->AffinityMask == 0 + ) + { + DeleteDbObject(Object); + } +} + +VOID LoadCustomColors( + VOID + ) +{ + PPH_STRING settingsString; + PH_STRINGREF remaining; + PH_STRINGREF part; + + settingsString = PhaGetStringSetting(SETTING_NAME_CUSTOM_COLOR_LIST); + remaining = settingsString->sr; + + if (remaining.Length == 0) + return; + + for (ULONG i = 0; i < ARRAYSIZE(ProcessCustomColors); i++) + { + ULONG64 integer = 0; + + if (remaining.Length == 0) + break; + + PhSplitStringRefAtChar(&remaining, ',', &part, &remaining); + + if (PhStringToInteger64(&part, 10, &integer)) + { + ProcessCustomColors[i] = (COLORREF)integer; + } + } +} + +PPH_STRING SaveCustomColors( + VOID + ) +{ + PH_STRING_BUILDER stringBuilder; + + PhInitializeStringBuilder(&stringBuilder, 100); + + for (ULONG i = 0; i < ARRAYSIZE(ProcessCustomColors); i++) + { + PhAppendFormatStringBuilder( + &stringBuilder, + L"%lu,", + ProcessCustomColors[i] + ); + } + + if (stringBuilder.String->Length != 0) + PhRemoveEndStringBuilder(&stringBuilder, 1); + + return PhFinalStringBuilderString(&stringBuilder); +} + +ULONG GetProcessAffinity( + _In_ HANDLE ProcessId + ) +{ + HANDLE processHandle; + ULONG affinityMask = 0; + PROCESS_BASIC_INFORMATION basicInfo; + + if (NT_SUCCESS(PhOpenProcess( + &processHandle, + ProcessQueryAccess, + ProcessId + ))) + { + if (NT_SUCCESS(PhGetProcessBasicInformation( + processHandle, + &basicInfo + ))) + { + affinityMask = (ULONG)basicInfo.AffinityMask; + } + + NtClose(processHandle); + } + + return affinityMask; +} + +IO_PRIORITY_HINT GetProcessIoPriority( + _In_ HANDLE ProcessId + ) +{ + HANDLE processHandle; + IO_PRIORITY_HINT ioPriority = -1; + + if (NT_SUCCESS(PhOpenProcess( + &processHandle, + ProcessQueryAccess, + ProcessId + ))) + { + if (!NT_SUCCESS(PhGetProcessIoPriority( + processHandle, + &ioPriority + ))) + { + ioPriority = -1; + } + + NtClose(processHandle); + } + + return ioPriority; +} + +ULONG GetPriorityClassFromId( + _In_ ULONG Id + ) +{ + switch (Id) + { + case PHAPP_ID_PRIORITY_REALTIME: + return PROCESS_PRIORITY_CLASS_REALTIME; + case PHAPP_ID_PRIORITY_HIGH: + return PROCESS_PRIORITY_CLASS_HIGH; + case PHAPP_ID_PRIORITY_ABOVENORMAL: + return PROCESS_PRIORITY_CLASS_ABOVE_NORMAL; + case PHAPP_ID_PRIORITY_NORMAL: + return PROCESS_PRIORITY_CLASS_NORMAL; + case PHAPP_ID_PRIORITY_BELOWNORMAL: + return PROCESS_PRIORITY_CLASS_BELOW_NORMAL; + case PHAPP_ID_PRIORITY_IDLE: + return PROCESS_PRIORITY_CLASS_IDLE; + } + + return 0; +} + +ULONG GetIoPriorityFromId( + _In_ ULONG Id + ) +{ + switch (Id) + { + case PHAPP_ID_IOPRIORITY_VERYLOW: + return 0; + case PHAPP_ID_IOPRIORITY_LOW: + return 1; + case PHAPP_ID_IOPRIORITY_NORMAL: + return 2; + case PHAPP_ID_IOPRIORITY_HIGH: + return 3; + } + + return -1; +} + +VOID NTAPI LoadCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + PPH_PLUGIN toolStatusPlugin; + PPH_STRING path; + + if (toolStatusPlugin = PhFindPlugin(TOOLSTATUS_PLUGIN_NAME)) + { + ToolStatusInterface = PhGetPluginInformation(toolStatusPlugin)->Interface; + + if (ToolStatusInterface->Version < TOOLSTATUS_INTERFACE_VERSION) + ToolStatusInterface = NULL; + } + + path = PhaGetStringSetting(SETTING_NAME_DATABASE_PATH); + path = PH_AUTO(PhExpandEnvironmentStrings(&path->sr)); + + LoadCustomColors(); + + if (RtlDetermineDosPathNameType_U(path->Buffer) == RtlPathTypeRelative) + { + PPH_STRING directory; + + directory = PH_AUTO(PhGetApplicationDirectory()); + path = PH_AUTO(PhConcatStringRef2(&directory->sr, &path->sr)); + } + + SetDbPath(path); + LoadDb(); +} + +VOID NTAPI UnloadCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + SaveDb(); +} + +VOID NTAPI ShowOptionsCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + DialogBox( + PluginInstance->DllBase, + MAKEINTRESOURCE(IDD_OPTIONS), + (HWND)Parameter, + OptionsDlgProc + ); +} + +VOID NTAPI MenuItemCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + PPH_PLUGIN_MENU_ITEM menuItem = Parameter; + PPH_PROCESS_ITEM processItem = PhGetSelectedProcessItem(); + PDB_OBJECT object; + + if (!processItem) + return; + + switch (menuItem->Id) + { + case PROCESS_PRIORITY_SAVE_ID: + { + LockDb(); + + if ((object = FindDbObject(FILE_TAG, &processItem->ProcessName->sr)) && object->PriorityClass != 0) + { + object->PriorityClass = 0; + DeleteDbObjectForProcessIfUnused(object); + } + else + { + object = CreateDbObject(FILE_TAG, &processItem->ProcessName->sr, NULL); + object->PriorityClass = processItem->PriorityClass; + } + + UnlockDb(); + SaveDb(); + } + break; + case PROCESS_PRIORITY_SAVE_FOR_THIS_COMMAND_LINE_ID: + { + if (processItem->CommandLine) + { + LockDb(); + + if ((object = FindDbObject(COMMAND_LINE_TAG, &processItem->CommandLine->sr)) && object->PriorityClass != 0) + { + object->PriorityClass = 0; + DeleteDbObjectForProcessIfUnused(object); + } + else + { + object = CreateDbObject(COMMAND_LINE_TAG, &processItem->CommandLine->sr, NULL); + object->PriorityClass = processItem->PriorityClass; + } + + UnlockDb(); + SaveDb(); + } + } + break; + case PROCESS_IO_PRIORITY_SAVE_ID: + { + LockDb(); + + if ((object = FindDbObject(FILE_TAG, &processItem->ProcessName->sr)) && object->IoPriorityPlusOne != 0) + { + object->IoPriorityPlusOne = 0; + DeleteDbObjectForProcessIfUnused(object); + } + else + { + object = CreateDbObject(FILE_TAG, &processItem->ProcessName->sr, NULL); + object->IoPriorityPlusOne = GetProcessIoPriority(processItem->ProcessId) + 1; + } + + UnlockDb(); + SaveDb(); + } + break; + case PROCESS_IO_PRIORITY_SAVE_FOR_THIS_COMMAND_LINE_ID: + { + if (processItem->CommandLine) + { + LockDb(); + + if ((object = FindDbObject(COMMAND_LINE_TAG, &processItem->CommandLine->sr)) && object->IoPriorityPlusOne != 0) + { + object->IoPriorityPlusOne = 0; + DeleteDbObjectForProcessIfUnused(object); + } + else + { + object = CreateDbObject(COMMAND_LINE_TAG, &processItem->CommandLine->sr, NULL); + object->IoPriorityPlusOne = GetProcessIoPriority(processItem->ProcessId) + 1; + } + + UnlockDb(); + SaveDb(); + } + } + break; + case PROCESS_HIGHLIGHT_ID: + { + BOOLEAN highlightPresent = (BOOLEAN)menuItem->Context; + + if (!highlightPresent) + { + CHOOSECOLOR chooseColor = { sizeof(CHOOSECOLOR) }; + chooseColor.hwndOwner = PhMainWndHandle; + chooseColor.lpCustColors = ProcessCustomColors; + chooseColor.lpfnHook = ColorDlgHookProc; + chooseColor.Flags = CC_ANYCOLOR | CC_FULLOPEN | CC_SOLIDCOLOR | CC_ENABLEHOOK; + + if (ChooseColor(&chooseColor)) + { + PhSetStringSetting2(SETTING_NAME_CUSTOM_COLOR_LIST, &PH_AUTO_T(PH_STRING, SaveCustomColors())->sr); + + LockDb(); + + object = CreateDbObject(FILE_TAG, &processItem->ProcessName->sr, NULL); + object->BackColor = chooseColor.rgbResult; + + UnlockDb(); + SaveDb(); + } + } + else + { + LockDb(); + + if ((object = FindDbObject(FILE_TAG, &processItem->ProcessName->sr)) && object->BackColor != ULONG_MAX) + { + object->BackColor = ULONG_MAX; + DeleteDbObjectForProcessIfUnused(object); + } + + UnlockDb(); + SaveDb(); + } + + PhInvalidateAllProcessNodes(); + } + break; + case PROCESS_COLLAPSE_ID: + { + LockDb(); + + if ((object = FindDbObject(FILE_TAG, &processItem->ProcessName->sr)) && object->Collapse) + { + object->Collapse = FALSE; + DeleteDbObjectForProcessIfUnused(object); + } + else + { + object = CreateDbObject(FILE_TAG, &processItem->ProcessName->sr, NULL); + object->Collapse = TRUE; + } + + UnlockDb(); + SaveDb(); + } + break; + case PROCESS_AFFINITY_SAVE_ID: + { + LockDb(); + + if ((object = FindDbObject(FILE_TAG, &processItem->ProcessName->sr)) && object->AffinityMask != 0) + { + object->AffinityMask = 0; + DeleteDbObjectForProcessIfUnused(object); + } + else + { + object = CreateDbObject(FILE_TAG, &processItem->ProcessName->sr, NULL); + object->AffinityMask = GetProcessAffinity(processItem->ProcessId); + } + + UnlockDb(); + SaveDb(); + } + break; + case PROCESS_AFFINITY_SAVE_FOR_THIS_COMMAND_LINE_ID: + { + if (processItem->CommandLine) + { + LockDb(); + + if ((object = FindDbObject(COMMAND_LINE_TAG, &processItem->CommandLine->sr)) && object->AffinityMask != 0) + { + object->AffinityMask = 0; + DeleteDbObjectForProcessIfUnused(object); + } + else + { + object = CreateDbObject(COMMAND_LINE_TAG, &processItem->CommandLine->sr, NULL); + object->AffinityMask = GetProcessAffinity(processItem->ProcessId); + } + + UnlockDb(); + SaveDb(); + } + } + break; + } +} + +VOID NTAPI MenuHookCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + PPH_PLUGIN_MENU_HOOK_INFORMATION menuHookInfo = Parameter; + ULONG id = menuHookInfo->SelectedItem->Id; + + switch (id) + { + case PHAPP_ID_PRIORITY_REALTIME: + case PHAPP_ID_PRIORITY_HIGH: + case PHAPP_ID_PRIORITY_ABOVENORMAL: + case PHAPP_ID_PRIORITY_NORMAL: + case PHAPP_ID_PRIORITY_BELOWNORMAL: + case PHAPP_ID_PRIORITY_IDLE: + { + BOOLEAN changed = FALSE; + PPH_PROCESS_ITEM *processes; + ULONG numberOfProcesses; + ULONG i; + + PhGetSelectedProcessItems(&processes, &numberOfProcesses); + LockDb(); + + for (i = 0; i < numberOfProcesses; i++) + { + PDB_OBJECT object; + + if (object = FindDbObjectForProcess(processes[i], INTENT_PROCESS_PRIORITY_CLASS)) + { + ULONG newPriorityClass = GetPriorityClassFromId(id); + + if (object->PriorityClass != newPriorityClass) + { + object->PriorityClass = newPriorityClass; + changed = TRUE; + } + } + } + + UnlockDb(); + PhFree(processes); + + if (changed) + SaveDb(); + } + break; + case PHAPP_ID_IOPRIORITY_VERYLOW: + case PHAPP_ID_IOPRIORITY_LOW: + case PHAPP_ID_IOPRIORITY_NORMAL: + case PHAPP_ID_IOPRIORITY_HIGH: + { + BOOLEAN changed = FALSE; + PPH_PROCESS_ITEM *processes; + ULONG numberOfProcesses; + ULONG i; + + PhGetSelectedProcessItems(&processes, &numberOfProcesses); + LockDb(); + + for (i = 0; i < numberOfProcesses; i++) + { + PDB_OBJECT object; + + if (object = FindDbObjectForProcess(processes[i], INTENT_PROCESS_IO_PRIORITY)) + { + ULONG newIoPriorityPlusOne = GetIoPriorityFromId(id) + 1; + + if (object->IoPriorityPlusOne != newIoPriorityPlusOne) + { + object->IoPriorityPlusOne = newIoPriorityPlusOne; + changed = TRUE; + } + } + } + + UnlockDb(); + PhFree(processes); + + if (changed) + SaveDb(); + } + break; + case PHAPP_ID_PROCESS_AFFINITY: + { + BOOLEAN changed = FALSE; + ULONG_PTR affinityMask; + ULONG_PTR newAffinityMask; + PPH_PROCESS_ITEM processItem = PhGetSelectedProcessItem(); + + if (!processItem) + break; + + // Don't show the default Process Hacker affinity dialog. + menuHookInfo->Handled = TRUE; + + // Query the current process affinity. + affinityMask = GetProcessAffinity(processItem->ProcessId); + + // Show the affinity dialog (with our values). + if (PhShowProcessAffinityDialog2(PhMainWndHandle, affinityMask, &newAffinityMask)) + { + PDB_OBJECT object; + + LockDb(); + + if (object = FindDbObjectForProcess(processItem, INTENT_PROCESS_AFFINITY)) + { + // Update the process affinity in our database (if the database values are different). + if (object->AffinityMask != (ULONG)newAffinityMask) + { + object->AffinityMask = (ULONG)newAffinityMask; + changed = TRUE; + } + } + + UnlockDb(); + + if (changed) + { + SaveDb(); + } + + // Update the process affinity in Windows (if the system values are different). + if (affinityMask != newAffinityMask) + { + HANDLE processHandle; + + if (NT_SUCCESS(PhOpenProcess( + &processHandle, + PROCESS_SET_INFORMATION, + processItem->ProcessId + ))) + { + PhSetProcessAffinityMask(processHandle, newAffinityMask); + NtClose(processHandle); + } + } + } + } + break; + } +} + +VOID InvalidateProcessComments( + VOID + ) +{ + PLIST_ENTRY listEntry; + + PhAcquireQueuedLockExclusive(&ProcessListLock); + + listEntry = ProcessListHead.Flink; + + while (listEntry != &ProcessListHead) + { + PPROCESS_EXTENSION extension; + + extension = CONTAINING_RECORD(listEntry, PROCESS_EXTENSION, ListEntry); + + extension->Valid = FALSE; + + listEntry = listEntry->Flink; + } + + PhReleaseQueuedLockExclusive(&ProcessListLock); +} + +VOID UpdateProcessComment( + _In_ PPH_PROCESS_NODE Node, + _In_ PPROCESS_EXTENSION Extension + ) +{ + if (!Extension->Valid) + { + PDB_OBJECT object; + + LockDb(); + + if (object = FindDbObjectForProcess(Node->ProcessItem, INTENT_PROCESS_COMMENT)) + { + PhSwapReference(&Extension->Comment, object->Comment); + } + else + { + PhClearReference(&Extension->Comment); + } + + UnlockDb(); + + Extension->Valid = TRUE; + } +} + +VOID InvalidateServiceComments( + VOID + ) +{ + PLIST_ENTRY listEntry; + + PhAcquireQueuedLockExclusive(&ServiceListLock); + + listEntry = ServiceListHead.Flink; + + while (listEntry != &ServiceListHead) + { + PSERVICE_EXTENSION extension; + + extension = CONTAINING_RECORD(listEntry, SERVICE_EXTENSION, ListEntry); + + extension->Valid = FALSE; + + listEntry = listEntry->Flink; + } + + PhReleaseQueuedLockExclusive(&ServiceListLock); +} + +VOID UpdateServiceComment( + _In_ PPH_SERVICE_NODE Node, + _In_ PSERVICE_EXTENSION Extension + ) +{ + if (!Extension->Valid) + { + PDB_OBJECT object; + + LockDb(); + + if (object = FindDbObject(SERVICE_TAG, &Node->ServiceItem->Name->sr)) + { + PhSwapReference(&Extension->Comment, object->Comment); + } + else + { + PhClearReference(&Extension->Comment); + } + + UnlockDb(); + + Extension->Valid = TRUE; + } +} + +VOID TreeNewMessageCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + PPH_PLUGIN_TREENEW_MESSAGE message = Parameter; + + switch (message->Message) + { + case TreeNewGetCellText: + { + PPH_TREENEW_GET_CELL_TEXT getCellText = message->Parameter1; + + if (message->TreeNewHandle == ProcessTreeNewHandle) + { + PPH_PROCESS_NODE node; + + node = (PPH_PROCESS_NODE)getCellText->Node; + + switch (message->SubId) + { + case COMMENT_COLUMN_ID: + { + PPROCESS_EXTENSION extension; + + extension = PhPluginGetObjectExtension(PluginInstance, node->ProcessItem, EmProcessItemType); + UpdateProcessComment(node, extension); + getCellText->Text = PhGetStringRef(extension->Comment); + } + break; + } + } + else if (message->TreeNewHandle == ServiceTreeNewHandle) + { + PPH_SERVICE_NODE node; + + node = (PPH_SERVICE_NODE)getCellText->Node; + + switch (message->SubId) + { + case COMMENT_COLUMN_ID: + { + PSERVICE_EXTENSION extension; + + extension = PhPluginGetObjectExtension(PluginInstance, node->ServiceItem, EmServiceItemType); + UpdateServiceComment(node, extension); + getCellText->Text = PhGetStringRef(extension->Comment); + } + break; + } + } + } + break; + } +} + +VOID MainWindowShowingCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + if (ToolStatusInterface) + { + PhRegisterCallback(ToolStatusInterface->SearchChangedEvent, SearchChangedHandler, NULL, &SearchChangedRegistration); + } +} + +VOID ProcessPropertiesInitializingCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + PPH_PLUGIN_PROCESS_PROPCONTEXT propContext = Parameter; + + PhAddProcessPropPage( + propContext->PropContext, + PhCreateProcessPropPageContextEx(PluginInstance->DllBase, MAKEINTRESOURCE(IDD_PROCCOMMENT), ProcessCommentPageDlgProc, NULL) + ); +} + +VOID AddSavePriorityMenuItemsAndHook( + _In_ PPH_PLUGIN_MENU_INFORMATION MenuInfo, + _In_ PPH_PROCESS_ITEM ProcessItem, + _In_ BOOLEAN UseSelectionForHook + ) +{ + PPH_EMENU_ITEM affinityMenuItem; + PPH_EMENU_ITEM priorityMenuItem; + PPH_EMENU_ITEM ioPriorityMenuItem; + PPH_EMENU_ITEM saveMenuItem; + PPH_EMENU_ITEM saveForCommandLineMenuItem; + PDB_OBJECT object; + + if (affinityMenuItem = PhFindEMenuItem(MenuInfo->Menu, 0, L"Affinity", PHAPP_ID_PROCESS_AFFINITY)) + { + // HACK: Change default Affinity menu-item into a drop-down list + PhInsertEMenuItem(affinityMenuItem, PhCreateEMenuItem(0, affinityMenuItem->Id, L"Set &affinity", NULL, NULL), -1); + //PhInsertEMenuItem(affinityMenuItem, PhPluginCreateEMenuItem(PluginInstance, 0, PHAPP_ID_PROCESS_AFFINITY, L"Set &affinity", NULL), PhIndexOfEMenuItem(MenuInfo->Menu, affinityMenuItem) + 1); + //PhRemoveEMenuItem(affinityMenuItem, affinityMenuItem, 0); + + // Insert standard menu-items + PhInsertEMenuItem(affinityMenuItem, PhPluginCreateEMenuItem(PluginInstance, PH_EMENU_SEPARATOR, 0, NULL, NULL), -1); + PhInsertEMenuItem(affinityMenuItem, saveMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, PROCESS_AFFINITY_SAVE_ID, PhaFormatString(L"Save for %s", ProcessItem->ProcessName->Buffer)->Buffer, NULL), -1); + PhInsertEMenuItem(affinityMenuItem, saveForCommandLineMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, PROCESS_AFFINITY_SAVE_FOR_THIS_COMMAND_LINE_ID, L"Save for this command line", NULL), -1); + + if (!ProcessItem->CommandLine) + saveForCommandLineMenuItem->Flags |= PH_EMENU_DISABLED; + + LockDb(); + + if ((object = FindDbObject(FILE_TAG, &ProcessItem->ProcessName->sr)) && object->AffinityMask != 0) + saveMenuItem->Flags |= PH_EMENU_CHECKED; + if (ProcessItem->CommandLine && (object = FindDbObject(COMMAND_LINE_TAG, &ProcessItem->CommandLine->sr)) && object->AffinityMask != 0) + saveForCommandLineMenuItem->Flags |= PH_EMENU_CHECKED; + + UnlockDb(); + } + + // Priority + if (priorityMenuItem = PhFindEMenuItem(MenuInfo->Menu, 0, L"Priority", 0)) + { + PhInsertEMenuItem(priorityMenuItem, PhPluginCreateEMenuItem(PluginInstance, PH_EMENU_SEPARATOR, 0, NULL, NULL), -1); + PhInsertEMenuItem(priorityMenuItem, saveMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, PROCESS_PRIORITY_SAVE_ID, PhaFormatString(L"Save for %s", ProcessItem->ProcessName->Buffer)->Buffer, NULL), -1); + PhInsertEMenuItem(priorityMenuItem, saveForCommandLineMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, PROCESS_PRIORITY_SAVE_FOR_THIS_COMMAND_LINE_ID, L"Save for this command line", NULL), -1); + + if (!ProcessItem->CommandLine) + saveForCommandLineMenuItem->Flags |= PH_EMENU_DISABLED; + + LockDb(); + + if ((object = FindDbObject(FILE_TAG, &ProcessItem->ProcessName->sr)) && object->PriorityClass != 0) + saveMenuItem->Flags |= PH_EMENU_CHECKED; + if (ProcessItem->CommandLine && (object = FindDbObject(COMMAND_LINE_TAG, &ProcessItem->CommandLine->sr)) && object->PriorityClass != 0) + saveForCommandLineMenuItem->Flags |= PH_EMENU_CHECKED; + + UnlockDb(); + } + + // I/O Priority + if (ioPriorityMenuItem = PhFindEMenuItem(MenuInfo->Menu, 0, L"I/O Priority", 0)) + { + PhInsertEMenuItem(ioPriorityMenuItem, PhPluginCreateEMenuItem(PluginInstance, PH_EMENU_SEPARATOR, 0, NULL, NULL), -1); + PhInsertEMenuItem(ioPriorityMenuItem, saveMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, PROCESS_IO_PRIORITY_SAVE_ID, PhaFormatString(L"Save for %s", ProcessItem->ProcessName->Buffer)->Buffer, NULL), -1); + PhInsertEMenuItem(ioPriorityMenuItem, saveForCommandLineMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, PROCESS_IO_PRIORITY_SAVE_FOR_THIS_COMMAND_LINE_ID, L"Save for this command line", NULL), -1); + + if (!ProcessItem->CommandLine) + saveForCommandLineMenuItem->Flags |= PH_EMENU_DISABLED; + + LockDb(); + + if ((object = FindDbObject(FILE_TAG, &ProcessItem->ProcessName->sr)) && object->IoPriorityPlusOne != 0) + saveMenuItem->Flags |= PH_EMENU_CHECKED; + if (ProcessItem->CommandLine && (object = FindDbObject(COMMAND_LINE_TAG, &ProcessItem->CommandLine->sr)) && object->IoPriorityPlusOne != 0) + saveForCommandLineMenuItem->Flags |= PH_EMENU_CHECKED; + + UnlockDb(); + } + + PhPluginAddMenuHook(MenuInfo, PluginInstance, UseSelectionForHook ? NULL : ProcessItem->ProcessId); +} + +VOID ProcessMenuInitializingCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + BOOLEAN highlightPresent = FALSE; + PPH_PLUGIN_MENU_INFORMATION menuInfo = Parameter; + PPH_PROCESS_ITEM processItem; + PPH_EMENU_ITEM miscMenuItem; + PPH_EMENU_ITEM collapseMenuItem; + PPH_EMENU_ITEM highlightMenuItem; + PDB_OBJECT object; + + if (menuInfo->u.Process.NumberOfProcesses != 1) + return; + + processItem = menuInfo->u.Process.Processes[0]; + + if (!PH_IS_FAKE_PROCESS_ID(processItem->ProcessId) && processItem->ProcessId != SYSTEM_IDLE_PROCESS_ID && processItem->ProcessId != SYSTEM_PROCESS_ID) + AddSavePriorityMenuItemsAndHook(menuInfo, processItem, TRUE); + + if (!(miscMenuItem = PhFindEMenuItem(menuInfo->Menu, 0, L"Miscellaneous", 0))) + return; + + LockDb(); + if ((object = FindDbObject(FILE_TAG, &processItem->ProcessName->sr)) && object->BackColor != ULONG_MAX) + highlightPresent = TRUE; + UnlockDb(); + + PhInsertEMenuItem(miscMenuItem, collapseMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, PROCESS_COLLAPSE_ID, L"Collapse by default", NULL), 0); + PhInsertEMenuItem(miscMenuItem, highlightMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, PROCESS_HIGHLIGHT_ID, L"Highlight", UlongToPtr(highlightPresent)), 1); + PhInsertEMenuItem(miscMenuItem, PhPluginCreateEMenuItem(PluginInstance, PH_EMENU_SEPARATOR, 0, NULL, NULL), 2); + + LockDb(); + + if ((object = FindDbObject(FILE_TAG, &menuInfo->u.Process.Processes[0]->ProcessName->sr)) && object->Collapse) + collapseMenuItem->Flags |= PH_EMENU_CHECKED; + if (highlightPresent) + highlightMenuItem->Flags |= PH_EMENU_CHECKED; + + UnlockDb(); +} + +static LONG NTAPI ProcessCommentSortFunction( + _In_ PVOID Node1, + _In_ PVOID Node2, + _In_ ULONG SubId, + _In_ PVOID Context + ) +{ + PPH_PROCESS_NODE node1 = Node1; + PPH_PROCESS_NODE node2 = Node2; + PPROCESS_EXTENSION extension1 = PhPluginGetObjectExtension(PluginInstance, node1->ProcessItem, EmProcessItemType); + PPROCESS_EXTENSION extension2 = PhPluginGetObjectExtension(PluginInstance, node2->ProcessItem, EmProcessItemType); + + UpdateProcessComment(node1, extension1); + UpdateProcessComment(node2, extension2); + + return PhCompareStringWithNull(extension1->Comment, extension2->Comment, TRUE); +} + +VOID ProcessTreeNewInitializingCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + PPH_PLUGIN_TREENEW_INFORMATION info = Parameter; + PH_TREENEW_COLUMN column; + + ProcessTreeNewHandle = info->TreeNewHandle; + + memset(&column, 0, sizeof(PH_TREENEW_COLUMN)); + column.Text = L"Comment"; + column.Width = 120; + column.Alignment = PH_ALIGN_LEFT; + + PhPluginAddTreeNewColumn(PluginInstance, info->CmData, &column, COMMENT_COLUMN_ID, NULL, ProcessCommentSortFunction); +} + +VOID GetProcessHighlightingColorCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + PPH_PLUGIN_GET_HIGHLIGHTING_COLOR getHighlightingColor = Parameter; + PPH_PROCESS_ITEM processItem = (PPH_PROCESS_ITEM)getHighlightingColor->Parameter; + PDB_OBJECT object; + + if (getHighlightingColor->Handled) + return; + + LockDb(); + + if ((object = FindDbObject(FILE_TAG, &processItem->ProcessName->sr)) && object->BackColor != ULONG_MAX) + { + getHighlightingColor->BackColor = object->BackColor; + getHighlightingColor->Cache = TRUE; + getHighlightingColor->Handled = TRUE; + } + + UnlockDb(); +} + +VOID ServicePropertiesInitializingCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + PPH_PLUGIN_OBJECT_PROPERTIES objectProperties = Parameter; + PROPSHEETPAGE propSheetPage; + + if (objectProperties->NumberOfPages < objectProperties->MaximumNumberOfPages) + { + memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); + propSheetPage.dwSize = sizeof(PROPSHEETPAGE); + propSheetPage.dwFlags = PSP_USETITLE; + propSheetPage.hInstance = PluginInstance->DllBase; + propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_SRVCOMMENT); + propSheetPage.pszTitle = L"Comment"; + propSheetPage.pfnDlgProc = ServiceCommentPageDlgProc; + propSheetPage.lParam = (LPARAM)objectProperties->Parameter; + objectProperties->Pages[objectProperties->NumberOfPages++] = CreatePropertySheetPage(&propSheetPage); + } +} + +LONG NTAPI ServiceCommentSortFunction( + _In_ PVOID Node1, + _In_ PVOID Node2, + _In_ ULONG SubId, + _In_ PVOID Context + ) +{ + PPH_SERVICE_NODE node1 = Node1; + PPH_SERVICE_NODE node2 = Node2; + PSERVICE_EXTENSION extension1 = PhPluginGetObjectExtension(PluginInstance, node1->ServiceItem, EmServiceItemType); + PSERVICE_EXTENSION extension2 = PhPluginGetObjectExtension(PluginInstance, node2->ServiceItem, EmServiceItemType); + + UpdateServiceComment(node1, extension1); + UpdateServiceComment(node2, extension2); + + return PhCompareStringWithNull(extension1->Comment, extension2->Comment, TRUE); +} + +VOID ServiceTreeNewInitializingCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + PPH_PLUGIN_TREENEW_INFORMATION info = Parameter; + PH_TREENEW_COLUMN column; + + ServiceTreeNewHandle = info->TreeNewHandle; + + memset(&column, 0, sizeof(PH_TREENEW_COLUMN)); + column.Text = L"Comment"; + column.Width = 120; + column.Alignment = PH_ALIGN_LEFT; + + PhPluginAddTreeNewColumn(PluginInstance, info->CmData, &column, COMMENT_COLUMN_ID, NULL, ServiceCommentSortFunction); +} + +VOID MiListSectionMenuInitializingCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + PPH_PLUGIN_MENU_INFORMATION menuInfo = Parameter; + PPH_PROCESS_ITEM processItem = menuInfo->u.MiListSection.ProcessGroup->Representative; + + if (PH_IS_FAKE_PROCESS_ID(processItem->ProcessId) || processItem->ProcessId == SYSTEM_IDLE_PROCESS_ID || processItem->ProcessId == SYSTEM_PROCESS_ID) + return; + + AddSavePriorityMenuItemsAndHook(menuInfo, processItem, FALSE); +} + +VOID ProcessModifiedCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + PPH_PROCESS_ITEM processItem = Parameter; + PPROCESS_EXTENSION extension = PhPluginGetObjectExtension(PluginInstance, processItem, EmProcessItemType); + + extension->Valid = FALSE; +} + +VOID ProcessesUpdatedCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + PLIST_ENTRY listEntry; + + if (GetNumberOfDbObjects() == 0) + return; + + PhAcquireQueuedLockExclusive(&ProcessListLock); + LockDb(); + + listEntry = ProcessListHead.Flink; + + while (listEntry != &ProcessListHead) + { + PPROCESS_EXTENSION extension; + PPH_PROCESS_ITEM processItem; + PDB_OBJECT object; + + extension = CONTAINING_RECORD(listEntry, PROCESS_EXTENSION, ListEntry); + processItem = extension->ProcessItem; + + if (object = FindDbObjectForProcess(processItem, INTENT_PROCESS_PRIORITY_CLASS)) + { + if (processItem->PriorityClass != object->PriorityClass) + { + HANDLE processHandle; + PROCESS_PRIORITY_CLASS priorityClass; + + if (NT_SUCCESS(PhOpenProcess( + &processHandle, + PROCESS_SET_INFORMATION, + processItem->ProcessId + ))) + { + priorityClass.Foreground = FALSE; + priorityClass.PriorityClass = (UCHAR)object->PriorityClass; + NtSetInformationProcess(processHandle, ProcessPriorityClass, &priorityClass, sizeof(PROCESS_PRIORITY_CLASS)); + + NtClose(processHandle); + } + } + } + + if (object = FindDbObjectForProcess(processItem, INTENT_PROCESS_IO_PRIORITY)) + { + if (object->IoPriorityPlusOne != 0) + { + HANDLE processHandle; + + if (NT_SUCCESS(PhOpenProcess( + &processHandle, + PROCESS_SET_INFORMATION, + processItem->ProcessId + ))) + { + PhSetProcessIoPriority(processHandle, object->IoPriorityPlusOne - 1); + NtClose(processHandle); + } + } + } + + if (object = FindDbObjectForProcess(processItem, INTENT_PROCESS_AFFINITY)) + { + if (object->AffinityMask != 0) + { + HANDLE processHandle; + + if (NT_SUCCESS(PhOpenProcess( + &processHandle, + PROCESS_SET_INFORMATION, + processItem->ProcessId + ))) + { + PhSetProcessAffinityMask(processHandle, object->AffinityMask); + NtClose(processHandle); + } + } + } + + listEntry = listEntry->Flink; + } + + UnlockDb(); + PhReleaseQueuedLockExclusive(&ProcessListLock); +} + +VOID SearchChangedHandler( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + PPH_STRING searchText = Parameter; + + if (PhIsNullOrEmptyString(searchText)) + { + // ToolStatus expanded all nodes for searching, but the search text just became empty. We + // should re-collapse processes. + + PPH_LIST nodes = PH_AUTO(PhDuplicateProcessNodeList()); + ULONG i; + BOOLEAN changed = FALSE; + + LockDb(); + + for (i = 0; i < nodes->Count; i++) + { + PPH_PROCESS_NODE node = nodes->Items[i]; + PDB_OBJECT object; + + if ((object = FindDbObjectForProcess(node->ProcessItem, INTENT_PROCESS_COLLAPSE)) && object->Collapse) + { + node->Node.Expanded = FALSE; + changed = TRUE; + } + } + + UnlockDb(); + + if (changed) + TreeNew_NodesStructured(ProcessTreeNewHandle); + } +} + +VOID ProcessItemCreateCallback( + _In_ PVOID Object, + _In_ PH_EM_OBJECT_TYPE ObjectType, + _In_ PVOID Extension + ) +{ + PPH_PROCESS_ITEM processItem = Object; + PPROCESS_EXTENSION extension = Extension; + + memset(extension, 0, sizeof(PROCESS_EXTENSION)); + extension->ProcessItem = processItem; + + PhAcquireQueuedLockExclusive(&ProcessListLock); + InsertTailList(&ProcessListHead, &extension->ListEntry); + PhReleaseQueuedLockExclusive(&ProcessListLock); +} + +VOID ProcessItemDeleteCallback( + _In_ PVOID Object, + _In_ PH_EM_OBJECT_TYPE ObjectType, + _In_ PVOID Extension + ) +{ + PPH_PROCESS_ITEM processItem = Object; + PPROCESS_EXTENSION extension = Extension; + + PhClearReference(&extension->Comment); + PhAcquireQueuedLockExclusive(&ProcessListLock); + RemoveEntryList(&extension->ListEntry); + PhReleaseQueuedLockExclusive(&ProcessListLock); +} + +VOID ProcessNodeCreateCallback( + _In_ PVOID Object, + _In_ PH_EM_OBJECT_TYPE ObjectType, + _In_ PVOID Extension + ) +{ + PPH_PROCESS_NODE processNode = Object; + PDB_OBJECT object; + + LockDb(); + + if ((object = FindDbObjectForProcess(processNode->ProcessItem, INTENT_PROCESS_COLLAPSE)) && object->Collapse) + processNode->Node.Expanded = FALSE; + + UnlockDb(); +} + +VOID ServiceItemCreateCallback( + _In_ PVOID Object, + _In_ PH_EM_OBJECT_TYPE ObjectType, + _In_ PVOID Extension + ) +{ + PPH_SERVICE_ITEM processItem = Object; + PSERVICE_EXTENSION extension = Extension; + + memset(extension, 0, sizeof(SERVICE_EXTENSION)); + PhAcquireQueuedLockExclusive(&ServiceListLock); + InsertTailList(&ServiceListHead, &extension->ListEntry); + PhReleaseQueuedLockExclusive(&ServiceListLock); +} + +VOID ServiceItemDeleteCallback( + _In_ PVOID Object, + _In_ PH_EM_OBJECT_TYPE ObjectType, + _In_ PVOID Extension + ) +{ + PPH_SERVICE_ITEM processItem = Object; + PSERVICE_EXTENSION extension = Extension; + + PhClearReference(&extension->Comment); + PhAcquireQueuedLockExclusive(&ServiceListLock); + RemoveEntryList(&extension->ListEntry); + PhReleaseQueuedLockExclusive(&ServiceListLock); +} + +LOGICAL DllMain( + _In_ HINSTANCE Instance, + _In_ ULONG Reason, + _Reserved_ PVOID Reserved + ) +{ + if (Reason == DLL_PROCESS_ATTACH) + { + PPH_PLUGIN_INFORMATION info; + PH_SETTING_CREATE settings[] = + { + { StringSettingType, SETTING_NAME_DATABASE_PATH, L"%APPDATA%\\Process Hacker 2\\usernotesdb.xml" }, + { StringSettingType, SETTING_NAME_CUSTOM_COLOR_LIST, L"" } + }; + + PluginInstance = PhRegisterPlugin(PLUGIN_NAME, Instance, &info); + + if (!PluginInstance) + return FALSE; + + info->DisplayName = L"User Notes"; + info->Author = L"dmex, wj32"; + info->Description = L"Allows the user to add comments for processes and services, save process priority and affinity, highlight individual processes and show processes collapsed by default."; + info->Url = L"https://wj32.org/processhacker/forums/viewtopic.php?t=1120"; + info->HasOptions = TRUE; + + InitializeDb(); + + PhRegisterCallback( + PhGetPluginCallback(PluginInstance, PluginCallbackLoad), + LoadCallback, + NULL, + &PluginLoadCallbackRegistration + ); + PhRegisterCallback( + PhGetPluginCallback(PluginInstance, PluginCallbackUnload), + UnloadCallback, + NULL, + &PluginUnloadCallbackRegistration + ); + PhRegisterCallback( + PhGetPluginCallback(PluginInstance, PluginCallbackShowOptions), + ShowOptionsCallback, + NULL, + &PluginShowOptionsCallbackRegistration + ); + PhRegisterCallback( + PhGetPluginCallback(PluginInstance, PluginCallbackMenuItem), + MenuItemCallback, + NULL, + &PluginMenuItemCallbackRegistration + ); + PhRegisterCallback( + PhGetPluginCallback(PluginInstance, PluginCallbackMenuHook), + MenuHookCallback, + NULL, + &PluginMenuHookCallbackRegistration + ); + PhRegisterCallback( + PhGetPluginCallback(PluginInstance, PluginCallbackTreeNewMessage), + TreeNewMessageCallback, + NULL, + &TreeNewMessageCallbackRegistration + ); + PhRegisterCallback( + PhGetGeneralCallback(GeneralCallbackMainWindowShowing), + MainWindowShowingCallback, + NULL, + &MainWindowShowingCallbackRegistration + ); + PhRegisterCallback( + PhGetGeneralCallback(GeneralCallbackProcessPropertiesInitializing), + ProcessPropertiesInitializingCallback, + NULL, + &ProcessPropertiesInitializingCallbackRegistration + ); + PhRegisterCallback( + PhGetGeneralCallback(GeneralCallbackServicePropertiesInitializing), + ServicePropertiesInitializingCallback, + NULL, + &ServicePropertiesInitializingCallbackRegistration + ); + PhRegisterCallback( + PhGetGeneralCallback(GeneralCallbackProcessMenuInitializing), + ProcessMenuInitializingCallback, + NULL, + &ProcessMenuInitializingCallbackRegistration + ); + PhRegisterCallback( + PhGetGeneralCallback(GeneralCallbackProcessTreeNewInitializing), + ProcessTreeNewInitializingCallback, + NULL, + &ProcessTreeNewInitializingCallbackRegistration + ); + PhRegisterCallback( + PhGetGeneralCallback(GeneralCallbackGetProcessHighlightingColor), + GetProcessHighlightingColorCallback, + NULL, + &GetProcessHighlightingColorCallbackRegistration + ); + PhRegisterCallback( + PhGetGeneralCallback(GeneralCallbackServiceTreeNewInitializing), + ServiceTreeNewInitializingCallback, + NULL, + &ServiceTreeNewInitializingCallbackRegistration + ); + PhRegisterCallback( + PhGetGeneralCallback(GeneralCallbackMiListSectionMenuInitializing), + MiListSectionMenuInitializingCallback, + NULL, + &MiListSectionMenuInitializingCallbackRegistration + ); + PhRegisterCallback(&PhProcessModifiedEvent, + ProcessModifiedCallback, + NULL, + &ProcessModifiedCallbackRegistration + ); + PhRegisterCallback( + &PhProcessesUpdatedEvent, + ProcessesUpdatedCallback, + NULL, + &ProcessesUpdatedCallbackRegistration + ); + + PhPluginSetObjectExtension( + PluginInstance, + EmProcessItemType, + sizeof(PROCESS_EXTENSION), + ProcessItemCreateCallback, + ProcessItemDeleteCallback + ); + PhPluginSetObjectExtension( + PluginInstance, + EmProcessNodeType, + sizeof(PROCESS_EXTENSION), + ProcessNodeCreateCallback, + NULL + ); + PhPluginSetObjectExtension( + PluginInstance, + EmServiceItemType, + sizeof(SERVICE_EXTENSION), + ServiceItemCreateCallback, + ServiceItemDeleteCallback + ); + + PhAddSettings(settings, ARRAYSIZE(settings)); + } + + return TRUE; +} + +INT_PTR CALLBACK OptionsDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + switch (uMsg) + { + case WM_INITDIALOG: + { + PhCenterWindow(hwndDlg, GetParent(hwndDlg)); + + SetDlgItemText(hwndDlg, IDC_DATABASE, PhaGetStringSetting(SETTING_NAME_DATABASE_PATH)->Buffer); + + SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hwndDlg, IDCANCEL), TRUE); + } + break; + case WM_COMMAND: + { + switch (LOWORD(wParam)) + { + case IDCANCEL: + EndDialog(hwndDlg, IDCANCEL); + break; + case IDOK: + { + PhSetStringSetting2(SETTING_NAME_DATABASE_PATH, + &PhaGetDlgItemText(hwndDlg, IDC_DATABASE)->sr); + + EndDialog(hwndDlg, IDOK); + } + break; + case IDC_BROWSE: + { + static PH_FILETYPE_FILTER filters[] = + { + { L"XML files (*.xml)", L"*.xml" }, + { L"All files (*.*)", L"*.*" } + }; + PVOID fileDialog; + PPH_STRING fileName; + + fileDialog = PhCreateOpenFileDialog(); + PhSetFileDialogFilter(fileDialog, filters, sizeof(filters) / sizeof(PH_FILETYPE_FILTER)); + + fileName = PH_AUTO(PhGetFileName(PhaGetDlgItemText(hwndDlg, IDC_DATABASE))); + PhSetFileDialogFileName(fileDialog, fileName->Buffer); + + if (PhShowFileDialog(hwndDlg, fileDialog)) + { + fileName = PH_AUTO(PhGetFileDialogFileName(fileDialog)); + SetDlgItemText(hwndDlg, IDC_DATABASE, fileName->Buffer); + } + + PhFreeFileDialog(fileDialog); + } + break; + } + } + break; + } + + return FALSE; +} + +INT_PTR CALLBACK ProcessCommentPageDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + LPPROPSHEETPAGE propSheetPage; + PPH_PROCESS_PROPPAGECONTEXT propPageContext; + PPH_PROCESS_ITEM processItem; + PPROCESS_COMMENT_PAGE_CONTEXT context; + + if (PhPropPageDlgProcHeader(hwndDlg, uMsg, lParam, &propSheetPage, &propPageContext, &processItem)) + { + context = propPageContext->Context; + } + else + { + return FALSE; + } + + switch (uMsg) + { + case WM_INITDIALOG: + { + PDB_OBJECT object; + PPH_STRING comment; + + context = PhAllocate(sizeof(PROCESS_COMMENT_PAGE_CONTEXT)); + context->CommentHandle = GetDlgItem(hwndDlg, IDC_COMMENT); + context->RevertHandle = GetDlgItem(hwndDlg, IDC_REVERT); + context->MatchCommandlineHandle = GetDlgItem(hwndDlg, IDC_MATCHCOMMANDLINE); + propPageContext->Context = context; + + // Load the comment. + Edit_LimitText(context->CommentHandle, UNICODE_STRING_MAX_CHARS); + + LockDb(); + + if (object = FindDbObjectForProcess(processItem, INTENT_PROCESS_COMMENT)) + { + PhSetReference(&comment, object->Comment); + + if (processItem->CommandLine && (object = FindDbObject(COMMAND_LINE_TAG, &processItem->CommandLine->sr)) && object->Comment->Length != 0) + { + Button_SetCheck(context->MatchCommandlineHandle, BST_CHECKED); + } + } + else + { + comment = PhReferenceEmptyString(); + } + + UnlockDb(); + + Edit_SetText(context->CommentHandle, comment->Buffer); + context->OriginalComment = comment; + + if (!processItem->CommandLine) + EnableWindow(context->MatchCommandlineHandle, FALSE); + } + break; + case WM_DESTROY: + { + PDB_OBJECT object; + PPH_STRING comment; + BOOLEAN matchCommandLine; + BOOLEAN done = FALSE; + + comment = PH_AUTO(PhGetWindowText(context->CommentHandle)); + matchCommandLine = Button_GetCheck(context->MatchCommandlineHandle) == BST_CHECKED; + + if (!processItem->CommandLine) + matchCommandLine = FALSE; + + LockDb(); + + if (processItem->CommandLine && !matchCommandLine) + { + PDB_OBJECT objectForProcessName; + PPH_STRING message = NULL; + + object = FindDbObject(COMMAND_LINE_TAG, &processItem->CommandLine->sr); + objectForProcessName = FindDbObject(FILE_TAG, &processItem->ProcessName->sr); + + if (object && objectForProcessName && object->Comment->Length != 0 && objectForProcessName->Comment->Length != 0 && + !PhEqualString(comment, objectForProcessName->Comment, FALSE)) + { + message = PhaFormatString( + L"Do you want to replace the comment for %s which is currently\n \"%s\"\n" + L"with\n \"%s\"?", + processItem->ProcessName->Buffer, + objectForProcessName->Comment->Buffer, + comment->Buffer + ); + } + + if (object) + { + PhMoveReference(&object->Comment, PhReferenceEmptyString()); + DeleteDbObjectForProcessIfUnused(object); + } + + if (message) + { + // Prevent deadlocks. + UnlockDb(); + + if (MessageBox(hwndDlg, message->Buffer, L"Comment", MB_ICONQUESTION | MB_YESNO) == IDNO) + { + done = TRUE; + } + + LockDb(); + } + } + + if (!done) + { + if (comment->Length != 0) + { + if (matchCommandLine) + CreateDbObject(COMMAND_LINE_TAG, &processItem->CommandLine->sr, comment); + else + CreateDbObject(FILE_TAG, &processItem->ProcessName->sr, comment); + } + else + { + if ( + (!matchCommandLine && (object = FindDbObject(FILE_TAG, &processItem->ProcessName->sr))) || + (matchCommandLine && (object = FindDbObject(COMMAND_LINE_TAG, &processItem->CommandLine->sr))) + ) + { + PhMoveReference(&object->Comment, PhReferenceEmptyString()); + DeleteDbObjectForProcessIfUnused(object); + } + } + } + + UnlockDb(); + + PhDereferenceObject(context->OriginalComment); + PhFree(context); + + PhPropPageDlgProcDestroy(hwndDlg); + + SaveDb(); + InvalidateProcessComments(); + } + break; + case WM_SHOWWINDOW: + { + PPH_LAYOUT_ITEM dialogItem; + + if (dialogItem = PhBeginPropPageLayout(hwndDlg, propPageContext)) + { + PhAddPropPageLayoutItem(hwndDlg, context->CommentHandle, dialogItem, PH_ANCHOR_ALL); + PhAddPropPageLayoutItem(hwndDlg, context->RevertHandle, dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_BOTTOM); + PhAddPropPageLayoutItem(hwndDlg, context->MatchCommandlineHandle, dialogItem, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); + PhEndPropPageLayout(hwndDlg, propPageContext); + } + } + break; + case WM_COMMAND: + { + switch (LOWORD(wParam)) + { + case IDC_COMMENT: + { + if (HIWORD(wParam) == EN_CHANGE) + EnableWindow(context->RevertHandle, TRUE); + } + break; + case IDC_REVERT: + { + Edit_SetText(context->CommentHandle, context->OriginalComment->Buffer); + SendMessage(context->CommentHandle, EM_SETSEL, 0, -1); + SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)context->CommentHandle, TRUE); + EnableWindow(context->RevertHandle, FALSE); + } + break; + } + } + break; + case WM_NOTIFY: + { + LPNMHDR header = (LPNMHDR)lParam; + + switch (header->code) + { + case PSN_QUERYINITIALFOCUS: + { + SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, (LONG_PTR)context->MatchCommandlineHandle); + } + return TRUE; + } + } + break; + } + + return FALSE; +} + +INT_PTR CALLBACK ServiceCommentPageDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + PSERVICE_COMMENT_PAGE_CONTEXT context; + + if (uMsg == WM_INITDIALOG) + { + context = PhAllocate(sizeof(SERVICE_COMMENT_PAGE_CONTEXT)); + memset(context, 0, sizeof(SERVICE_COMMENT_PAGE_CONTEXT)); + + SetProp(hwndDlg, L"Context", (HANDLE)context); + } + else + { + context = (PSERVICE_COMMENT_PAGE_CONTEXT)GetProp(hwndDlg, L"Context"); + + if (uMsg == WM_DESTROY) + RemoveProp(hwndDlg, L"Context"); + } + + if (!context) + return FALSE; + + switch (uMsg) + { + case WM_INITDIALOG: + { + LPPROPSHEETPAGE propSheetPage = (LPPROPSHEETPAGE)lParam; + PPH_SERVICE_ITEM serviceItem = (PPH_SERVICE_ITEM)propSheetPage->lParam; + PDB_OBJECT object; + PPH_STRING comment; + + context->ServiceItem = serviceItem; + + PhInitializeLayoutManager(&context->LayoutManager, hwndDlg); + PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_COMMENT), NULL, PH_ANCHOR_ALL); + + // Load the comment. + + SendMessage(GetDlgItem(hwndDlg, IDC_COMMENT), EM_SETLIMITTEXT, UNICODE_STRING_MAX_CHARS, 0); + + LockDb(); + + if (object = FindDbObject(SERVICE_TAG, &serviceItem->Name->sr)) + comment = object->Comment; + else + comment = PH_AUTO(PhReferenceEmptyString()); + + UnlockDb(); + + SetDlgItemText(hwndDlg, IDC_COMMENT, comment->Buffer); + + EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); + } + break; + case WM_DESTROY: + { + PhDeleteLayoutManager(&context->LayoutManager); + PhFree(context); + } + break; + case WM_SIZE: + { + PhLayoutManagerLayout(&context->LayoutManager); + } + break; + case WM_COMMAND: + { + switch (LOWORD(wParam)) + { + case IDC_COMMENT: + { + if (HIWORD(wParam) == EN_CHANGE) + EnableWindow(GetDlgItem(hwndDlg, IDC_REVERT), TRUE); + } + break; + } + } + break; + case WM_NOTIFY: + { + LPNMHDR header = (LPNMHDR)lParam; + + switch (header->code) + { + case PSN_KILLACTIVE: + { + SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, FALSE); + } + return TRUE; + case PSN_APPLY: + { + PDB_OBJECT object; + PPH_STRING comment; + + comment = PH_AUTO(PhGetWindowText(GetDlgItem(hwndDlg, IDC_COMMENT))); + + LockDb(); + + if (comment->Length != 0) + { + CreateDbObject(SERVICE_TAG, &context->ServiceItem->Name->sr, comment); + } + else + { + if (object = FindDbObject(SERVICE_TAG, &context->ServiceItem->Name->sr)) + DeleteDbObject(object); + } + + UnlockDb(); + + SaveDb(); + InvalidateServiceComments(); + + SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_NOERROR); + } + return TRUE; + } + } + break; + } + + return FALSE; +} + +UINT_PTR CALLBACK ColorDlgHookProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + switch (uMsg) + { + case WM_INITDIALOG: + { + PhCenterWindow(hwndDlg, PhMainWndHandle); + + EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); + } + break; + } + + return FALSE; } \ No newline at end of file diff --git a/plugins/UserNotes/resource.h b/plugins/UserNotes/resource.h index 16b90406a0f6..7d5001f06322 100644 --- a/plugins/UserNotes/resource.h +++ b/plugins/UserNotes/resource.h @@ -1,25 +1,25 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by UserNotes.rc -// -#define IDD_OPTIONS 101 -#define IDD_COMMENT 102 -#define IDD_PROCCOMMENT 102 -#define IDD_SRVCOMMENT 103 -#define IDC_DATABASE 1001 -#define IDC_BROWSE 1002 -#define IDC_COMMENT 1003 -#define IDC_REVERT 1004 -#define IDC_CHECK1 1005 -#define IDC_MATCHCOMMANDLINE 1005 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 104 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1006 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by UserNotes.rc +// +#define IDD_OPTIONS 101 +#define IDD_COMMENT 102 +#define IDD_PROCCOMMENT 102 +#define IDD_SRVCOMMENT 103 +#define IDC_DATABASE 1001 +#define IDC_BROWSE 1002 +#define IDC_COMMENT 1003 +#define IDC_REVERT 1004 +#define IDC_CHECK1 1005 +#define IDC_MATCHCOMMANDLINE 1005 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 104 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1006 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/plugins/WindowExplorer/CHANGELOG.txt b/plugins/WindowExplorer/CHANGELOG.txt index 6266123ef575..5473e5bb68ef 100644 --- a/plugins/WindowExplorer/CHANGELOG.txt +++ b/plugins/WindowExplorer/CHANGELOG.txt @@ -1,22 +1,22 @@ -1.6 - * Added Searchbox - * Added Window tab to process properties - -1.5 - * Fixed window list not displaying Modern UI windows - -1.4 - * Fixed hook support for low integrity processes - -1.3 - * Fixed hook bugs - -1.2 - * Added more window properties - -1.1 - * Added Always on Top and Opacity - * Renamed Show/Hide and Enable/Disable to Visible and Enabled - -1.0 +1.6 + * Added Searchbox + * Added Window tab to process properties + +1.5 + * Fixed window list not displaying Modern UI windows + +1.4 + * Fixed hook support for low integrity processes + +1.3 + * Fixed hook bugs + +1.2 + * Added more window properties + +1.1 + * Added Always on Top and Opacity + * Renamed Show/Hide and Enable/Disable to Visible and Enabled + +1.0 * Initial release \ No newline at end of file diff --git a/plugins/WindowExplorer/WindowExplorer.rc b/plugins/WindowExplorer/WindowExplorer.rc index 88315ad57173..0511d3ff6a8f 100644 --- a/plugins/WindowExplorer/WindowExplorer.rc +++ b/plugins/WindowExplorer/WindowExplorer.rc @@ -1,308 +1,308 @@ -// Microsoft Visual C++ generated resource script. -// -#include "resource.h" - -#define APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// -#include "winres.h" -///////////////////////////////////////////////////////////////////////////// -#undef APSTUDIO_READONLY_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -// English (Australia) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENA) -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_AUS -#pragma code_page(1252) - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -1 TEXTINCLUDE -BEGIN - "resource.h\0" -END - -2 TEXTINCLUDE -BEGIN - "#include ""winres.h""\0" -END - -3 TEXTINCLUDE -BEGIN - "\r\n" - "\0" -END - -#endif // APSTUDIO_INVOKED - - -///////////////////////////////////////////////////////////////////////////// -// -// Version -// - -VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,6,0,0 - PRODUCTVERSION 1,6,0,0 - FILEFLAGSMASK 0x3fL -#ifdef _DEBUG - FILEFLAGS 0x1L -#else - FILEFLAGS 0x0L -#endif - FILEOS 0x40004L - FILETYPE 0x2L - FILESUBTYPE 0x0L -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "0c0904b0" - BEGIN - VALUE "CompanyName", "wj32" - VALUE "FileDescription", "Window Explorer plugin for Process Hacker" - VALUE "FileVersion", "1.6" - VALUE "InternalName", "ProcessHacker.WindowExplorer" - VALUE "LegalCopyright", "Licensed under the GNU GPL, v3." - VALUE "OriginalFilename", "WindowExplorer.dll" - VALUE "ProductName", "Window Explorer plugin for Process Hacker" - VALUE "ProductVersion", "1.6" - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0xc09, 1200 - END -END - - -///////////////////////////////////////////////////////////////////////////// -// -// Dialog -// - -IDD_WNDLIST DIALOGEX 0, 0, 447, 309 -STYLE DS_SETFONT | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME -EXSTYLE WS_EX_APPWINDOW -CAPTION "Windows" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - PUSHBUTTON "Refresh",IDC_REFRESH,2,3,50,14 - CONTROL "Windows",IDC_LIST,"PhTreeNew",WS_CLIPSIBLINGS | WS_CLIPCHILDREN | 0x2,2,19,443,288,WS_EX_CLIENTEDGE - EDITTEXT IDC_SEARCHEDIT,302,3,143,14,ES_AUTOHSCROLL -END - -IDD_WNDPROPS DIALOGEX 0, 0, 233, 152 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Properties" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "Property list for the window:",IDC_STATIC,7,7,92,8 - CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,20,219,125 -END - -IDD_WNDGENERAL DIALOGEX 0, 0, 233, 147 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "General" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "Text:",IDC_STATIC,7,8,18,8 - EDITTEXT IDC_TEXT,33,7,193,12,ES_AUTOHSCROLL | ES_READONLY - LTEXT "Thread:",IDC_STATIC,7,22,26,8 - LTEXT "Static",IDC_THREAD,77,22,149,8,SS_ENDELLIPSIS - LTEXT "Rectangle:",IDC_STATIC,7,33,36,8 - LTEXT "Static",IDC_RECTANGLE,77,33,149,8,SS_ENDELLIPSIS - LTEXT "Normal rectangle:",IDC_STATIC,7,44,60,8 - LTEXT "Static",IDC_NORMALRECTANGLE,77,44,149,8,SS_ENDELLIPSIS - LTEXT "Client rectangle:",IDC_STATIC,7,55,56,8 - LTEXT "Static",IDC_CLIENTRECTANGLE,77,55,149,8,SS_ENDELLIPSIS - LTEXT "Instance handle:",IDC_STATIC,7,66,56,8 - LTEXT "Static",IDC_INSTANCEHANDLE,77,66,149,8,SS_ENDELLIPSIS - LTEXT "Menu handle:",IDC_STATIC,7,77,45,8 - LTEXT "Static",IDC_MENUHANDLE,77,77,149,8,SS_ENDELLIPSIS - LTEXT "User data:",IDC_STATIC,7,88,36,8 - LTEXT "Static",IDC_USERDATA,77,88,149,8,SS_ENDELLIPSIS - LTEXT "Unicode:",IDC_STATIC,7,99,29,8 - LTEXT "Static",IDC_UNICODE,77,99,149,8 - LTEXT "Window proc:",IDC_STATIC,7,110,45,8 - EDITTEXT IDC_WINDOWPROC,75,110,151,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER - LTEXT "Dialog proc:",IDC_STATIC,7,121,39,8 - EDITTEXT IDC_DIALOGPROC,75,121,151,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER - LTEXT "Dialog control ID:",IDC_STATIC,7,132,61,8 - LTEXT "Static",IDC_CTRLID,77,132,149,8 -END - -IDD_WNDSTYLES DIALOGEX 0, 0, 233, 140 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Styles" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "Styles:",IDC_STATIC,7,7,23,8 - LTEXT "Static",IDC_STYLES,67,7,159,8 - LISTBOX IDC_STYLESLIST,7,19,219,46,LBS_SORT | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP - LTEXT "Extended styles:",IDC_STATIC,7,69,56,8 - LTEXT "Static",IDC_EXTENDEDSTYLES,67,69,159,8 - LISTBOX IDC_EXTENDEDSTYLESLIST,7,81,219,46,LBS_SORT | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP -END - -IDD_WNDCLASS DIALOGEX 0, 0, 233, 132 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Class" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "Name:",IDC_STATIC,7,8,22,8 - EDITTEXT IDC_NAME,33,7,193,12,ES_AUTOHSCROLL | ES_READONLY - LTEXT "Atom:",IDC_STATIC,7,22,20,8 - LTEXT "Static",IDC_ATOM,77,22,149,8,SS_ENDELLIPSIS - LTEXT "Styles:",IDC_STATIC,7,33,23,8 - EDITTEXT IDC_STYLES,75,33,150,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER - LTEXT "Instance handle:",IDC_STATIC,7,44,56,8 - LTEXT "Static",IDC_INSTANCEHANDLE,77,44,149,8,SS_ENDELLIPSIS - LTEXT "Icon handle:",IDC_STATIC,7,55,42,8 - LTEXT "Static",IDC_ICONHANDLE,77,55,149,8,SS_ENDELLIPSIS - LTEXT "Small icon handle:",IDC_STATIC,7,66,60,8 - LTEXT "Static",IDC_SMALLICONHANDLE,77,66,149,8,SS_ENDELLIPSIS - LTEXT "Cursor handle:",IDC_STATIC,7,77,49,8 - LTEXT "Static",IDC_CURSORHANDLE,77,77,149,8,SS_ENDELLIPSIS - LTEXT "Background brush:",IDC_STATIC,7,88,61,8 - LTEXT "Static",IDC_BACKGROUNDBRUSH,77,88,149,8,SS_ENDELLIPSIS - LTEXT "Menu name:",IDC_STATIC,7,99,41,8 - LTEXT "Static",IDC_MENUNAME,77,99,149,8,SS_ENDELLIPSIS - LTEXT "Window proc:",IDC_STATIC,7,110,45,8 - EDITTEXT IDC_WINDOWPROC,75,110,151,14,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER -END - - -///////////////////////////////////////////////////////////////////////////// -// -// DESIGNINFO -// - -#ifdef APSTUDIO_INVOKED -GUIDELINES DESIGNINFO -BEGIN - IDD_WNDLIST, DIALOG - BEGIN - LEFTMARGIN, 2 - RIGHTMARGIN, 445 - TOPMARGIN, 3 - BOTTOMMARGIN, 307 - END - - IDD_WNDPROPS, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 226 - TOPMARGIN, 7 - BOTTOMMARGIN, 145 - END - - IDD_WNDGENERAL, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 226 - TOPMARGIN, 7 - BOTTOMMARGIN, 140 - END - - IDD_WNDSTYLES, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 226 - TOPMARGIN, 7 - BOTTOMMARGIN, 133 - END - - IDD_WNDCLASS, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 226 - TOPMARGIN, 7 - BOTTOMMARGIN, 125 - END -END -#endif // APSTUDIO_INVOKED - - -///////////////////////////////////////////////////////////////////////////// -// -// Menu -// - -IDR_WINDOW MENU -BEGIN - POPUP "Window" - BEGIN - MENUITEM "Bring to front", ID_WINDOW_BRINGTOFRONT - MENUITEM "Restore", ID_WINDOW_RESTORE - MENUITEM "Minimize", ID_WINDOW_MINIMIZE - MENUITEM "Maximize", ID_WINDOW_MAXIMIZE - MENUITEM "Close", ID_WINDOW_CLOSE - MENUITEM SEPARATOR - MENUITEM "Visible", ID_WINDOW_VISIBLE - MENUITEM "Enabled", ID_WINDOW_ENABLED - MENUITEM "Always on top", ID_WINDOW_ALWAYSONTOP - POPUP "Opacity" - BEGIN - MENUITEM "10%", ID_OPACITY_10 - MENUITEM "20%", ID_OPACITY_20 - MENUITEM "30%", ID_OPACITY_30 - MENUITEM "40%", ID_OPACITY_40 - MENUITEM "50%", ID_OPACITY_50 - MENUITEM "60%", ID_OPACITY_60 - MENUITEM "70%", ID_OPACITY_70 - MENUITEM "80%", ID_OPACITY_80 - MENUITEM "90%", ID_OPACITY_90 - MENUITEM "Opaque", ID_OPACITY_OPAQUE - END - MENUITEM SEPARATOR - MENUITEM "Highlight", ID_WINDOW_HIGHLIGHT - MENUITEM "Go to thread", ID_WINDOW_GOTOTHREAD - MENUITEM "Properties", ID_WINDOW_PROPERTIES - MENUITEM SEPARATOR - MENUITEM "Copy\aCtrl+C", ID_WINDOW_COPY - END -END - - -///////////////////////////////////////////////////////////////////////////// -// -// AFX_DIALOG_LAYOUT -// - -IDD_WNDGENERAL AFX_DIALOG_LAYOUT -BEGIN - 0 -END - -IDD_WNDLIST AFX_DIALOG_LAYOUT -BEGIN - 0 -END - -IDD_WNDCLASS AFX_DIALOG_LAYOUT -BEGIN - 0 -END - -#endif // English (Australia) resources -///////////////////////////////////////////////////////////////////////////// - - - -#ifndef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// - - -///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED - +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "winres.h" +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (Australia) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENA) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_AUS +#pragma code_page(1252) + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""winres.h""\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,6,0,0 + PRODUCTVERSION 1,6,0,0 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "0c0904b0" + BEGIN + VALUE "CompanyName", "wj32" + VALUE "FileDescription", "Window Explorer plugin for Process Hacker" + VALUE "FileVersion", "1.6" + VALUE "InternalName", "ProcessHacker.WindowExplorer" + VALUE "LegalCopyright", "Licensed under the GNU GPL, v3." + VALUE "OriginalFilename", "WindowExplorer.dll" + VALUE "ProductName", "Window Explorer plugin for Process Hacker" + VALUE "ProductVersion", "1.6" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0xc09, 1200 + END +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_WNDLIST DIALOGEX 0, 0, 447, 309 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME +EXSTYLE WS_EX_APPWINDOW +CAPTION "Windows" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + PUSHBUTTON "Refresh",IDC_REFRESH,2,3,50,14 + CONTROL "Windows",IDC_LIST,"PhTreeNew",WS_CLIPSIBLINGS | WS_CLIPCHILDREN | 0x2,2,19,443,288,WS_EX_CLIENTEDGE + EDITTEXT IDC_SEARCHEDIT,302,3,143,14,ES_AUTOHSCROLL +END + +IDD_WNDPROPS DIALOGEX 0, 0, 233, 152 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Properties" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "Property list for the window:",IDC_STATIC,7,7,92,8 + CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,20,219,125 +END + +IDD_WNDGENERAL DIALOGEX 0, 0, 233, 147 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "General" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "Text:",IDC_STATIC,7,8,18,8 + EDITTEXT IDC_TEXT,33,7,193,12,ES_AUTOHSCROLL | ES_READONLY + LTEXT "Thread:",IDC_STATIC,7,22,26,8 + LTEXT "Static",IDC_THREAD,77,22,149,8,SS_ENDELLIPSIS + LTEXT "Rectangle:",IDC_STATIC,7,33,36,8 + LTEXT "Static",IDC_RECTANGLE,77,33,149,8,SS_ENDELLIPSIS + LTEXT "Normal rectangle:",IDC_STATIC,7,44,60,8 + LTEXT "Static",IDC_NORMALRECTANGLE,77,44,149,8,SS_ENDELLIPSIS + LTEXT "Client rectangle:",IDC_STATIC,7,55,56,8 + LTEXT "Static",IDC_CLIENTRECTANGLE,77,55,149,8,SS_ENDELLIPSIS + LTEXT "Instance handle:",IDC_STATIC,7,66,56,8 + LTEXT "Static",IDC_INSTANCEHANDLE,77,66,149,8,SS_ENDELLIPSIS + LTEXT "Menu handle:",IDC_STATIC,7,77,45,8 + LTEXT "Static",IDC_MENUHANDLE,77,77,149,8,SS_ENDELLIPSIS + LTEXT "User data:",IDC_STATIC,7,88,36,8 + LTEXT "Static",IDC_USERDATA,77,88,149,8,SS_ENDELLIPSIS + LTEXT "Unicode:",IDC_STATIC,7,99,29,8 + LTEXT "Static",IDC_UNICODE,77,99,149,8 + LTEXT "Window proc:",IDC_STATIC,7,110,45,8 + EDITTEXT IDC_WINDOWPROC,75,110,151,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + LTEXT "Dialog proc:",IDC_STATIC,7,121,39,8 + EDITTEXT IDC_DIALOGPROC,75,121,151,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + LTEXT "Dialog control ID:",IDC_STATIC,7,132,61,8 + LTEXT "Static",IDC_CTRLID,77,132,149,8 +END + +IDD_WNDSTYLES DIALOGEX 0, 0, 233, 140 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Styles" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "Styles:",IDC_STATIC,7,7,23,8 + LTEXT "Static",IDC_STYLES,67,7,159,8 + LISTBOX IDC_STYLESLIST,7,19,219,46,LBS_SORT | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP + LTEXT "Extended styles:",IDC_STATIC,7,69,56,8 + LTEXT "Static",IDC_EXTENDEDSTYLES,67,69,159,8 + LISTBOX IDC_EXTENDEDSTYLESLIST,7,81,219,46,LBS_SORT | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP +END + +IDD_WNDCLASS DIALOGEX 0, 0, 233, 132 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Class" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "Name:",IDC_STATIC,7,8,22,8 + EDITTEXT IDC_NAME,33,7,193,12,ES_AUTOHSCROLL | ES_READONLY + LTEXT "Atom:",IDC_STATIC,7,22,20,8 + LTEXT "Static",IDC_ATOM,77,22,149,8,SS_ENDELLIPSIS + LTEXT "Styles:",IDC_STATIC,7,33,23,8 + EDITTEXT IDC_STYLES,75,33,150,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + LTEXT "Instance handle:",IDC_STATIC,7,44,56,8 + LTEXT "Static",IDC_INSTANCEHANDLE,77,44,149,8,SS_ENDELLIPSIS + LTEXT "Icon handle:",IDC_STATIC,7,55,42,8 + LTEXT "Static",IDC_ICONHANDLE,77,55,149,8,SS_ENDELLIPSIS + LTEXT "Small icon handle:",IDC_STATIC,7,66,60,8 + LTEXT "Static",IDC_SMALLICONHANDLE,77,66,149,8,SS_ENDELLIPSIS + LTEXT "Cursor handle:",IDC_STATIC,7,77,49,8 + LTEXT "Static",IDC_CURSORHANDLE,77,77,149,8,SS_ENDELLIPSIS + LTEXT "Background brush:",IDC_STATIC,7,88,61,8 + LTEXT "Static",IDC_BACKGROUNDBRUSH,77,88,149,8,SS_ENDELLIPSIS + LTEXT "Menu name:",IDC_STATIC,7,99,41,8 + LTEXT "Static",IDC_MENUNAME,77,99,149,8,SS_ENDELLIPSIS + LTEXT "Window proc:",IDC_STATIC,7,110,45,8 + EDITTEXT IDC_WINDOWPROC,75,110,151,14,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_WNDLIST, DIALOG + BEGIN + LEFTMARGIN, 2 + RIGHTMARGIN, 445 + TOPMARGIN, 3 + BOTTOMMARGIN, 307 + END + + IDD_WNDPROPS, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 226 + TOPMARGIN, 7 + BOTTOMMARGIN, 145 + END + + IDD_WNDGENERAL, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 226 + TOPMARGIN, 7 + BOTTOMMARGIN, 140 + END + + IDD_WNDSTYLES, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 226 + TOPMARGIN, 7 + BOTTOMMARGIN, 133 + END + + IDD_WNDCLASS, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 226 + TOPMARGIN, 7 + BOTTOMMARGIN, 125 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Menu +// + +IDR_WINDOW MENU +BEGIN + POPUP "Window" + BEGIN + MENUITEM "Bring to front", ID_WINDOW_BRINGTOFRONT + MENUITEM "Restore", ID_WINDOW_RESTORE + MENUITEM "Minimize", ID_WINDOW_MINIMIZE + MENUITEM "Maximize", ID_WINDOW_MAXIMIZE + MENUITEM "Close", ID_WINDOW_CLOSE + MENUITEM SEPARATOR + MENUITEM "Visible", ID_WINDOW_VISIBLE + MENUITEM "Enabled", ID_WINDOW_ENABLED + MENUITEM "Always on top", ID_WINDOW_ALWAYSONTOP + POPUP "Opacity" + BEGIN + MENUITEM "10%", ID_OPACITY_10 + MENUITEM "20%", ID_OPACITY_20 + MENUITEM "30%", ID_OPACITY_30 + MENUITEM "40%", ID_OPACITY_40 + MENUITEM "50%", ID_OPACITY_50 + MENUITEM "60%", ID_OPACITY_60 + MENUITEM "70%", ID_OPACITY_70 + MENUITEM "80%", ID_OPACITY_80 + MENUITEM "90%", ID_OPACITY_90 + MENUITEM "Opaque", ID_OPACITY_OPAQUE + END + MENUITEM SEPARATOR + MENUITEM "Highlight", ID_WINDOW_HIGHLIGHT + MENUITEM "Go to thread", ID_WINDOW_GOTOTHREAD + MENUITEM "Properties", ID_WINDOW_PROPERTIES + MENUITEM SEPARATOR + MENUITEM "Copy\aCtrl+C", ID_WINDOW_COPY + END +END + + +///////////////////////////////////////////////////////////////////////////// +// +// AFX_DIALOG_LAYOUT +// + +IDD_WNDGENERAL AFX_DIALOG_LAYOUT +BEGIN + 0 +END + +IDD_WNDLIST AFX_DIALOG_LAYOUT +BEGIN + 0 +END + +IDD_WNDCLASS AFX_DIALOG_LAYOUT +BEGIN + 0 +END + +#endif // English (Australia) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/plugins/WindowExplorer/WindowExplorer.vcxproj b/plugins/WindowExplorer/WindowExplorer.vcxproj index bf5b3e58f4a0..f61d6d998529 100644 --- a/plugins/WindowExplorer/WindowExplorer.vcxproj +++ b/plugins/WindowExplorer/WindowExplorer.vcxproj @@ -1,94 +1,94 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {37488DC1-E45F-4626-A87C-3A854A153D1A} - WindowExplorer - Win32Proj - WindowExplorer - 10.0.15063.0 - - - - DynamicLibrary - Unicode - v141 - - - DynamicLibrary - Unicode - v141 - - - DynamicLibrary - Unicode - v141 - - - DynamicLibrary - Unicode - v141 - - - - - - - - - ProcessHacker.exe;comctl32.dll;%(DelayLoadDLLs) - - - - - ProcessHacker.exe;comctl32.dll;%(DelayLoadDLLs) - - - - - ProcessHacker.exe;comctl32.dll;%(DelayLoadDLLs) - - - - - ProcessHacker.exe;comctl32.dll;%(DelayLoadDLLs) - - - - - - - - - - - - - - - - - - - - - - + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {37488DC1-E45F-4626-A87C-3A854A153D1A} + WindowExplorer + Win32Proj + WindowExplorer + 10.0.15063.0 + + + + DynamicLibrary + Unicode + v141 + + + DynamicLibrary + Unicode + v141 + + + DynamicLibrary + Unicode + v141 + + + DynamicLibrary + Unicode + v141 + + + + + + + + + ProcessHacker.exe;comctl32.dll;%(DelayLoadDLLs) + + + + + ProcessHacker.exe;comctl32.dll;%(DelayLoadDLLs) + + + + + ProcessHacker.exe;comctl32.dll;%(DelayLoadDLLs) + + + + + ProcessHacker.exe;comctl32.dll;%(DelayLoadDLLs) + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/plugins/WindowExplorer/hook.c b/plugins/WindowExplorer/hook.c index 75d6861b84aa..abecae533993 100644 --- a/plugins/WindowExplorer/hook.c +++ b/plugins/WindowExplorer/hook.c @@ -1,509 +1,509 @@ -/* - * Process Hacker Window Explorer - - * hook procedure - * - * Copyright (C) 2011 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -/* - * Window Explorer uses a hook procedure in order to get window procedure - * and other information that can't be retrieved using GetWindowLongPtr. - * Because WindowExplorer.dll needs to be loaded into processes other - * than Process Hacker, both ProcessHacker.exe and comctl32.dll are set as - * delay-loaded DLLs. The other DLLs that we depend on (gdi32.dll, - * kernel32.dll, ntdll.dll, user32.dll) are all guaranteed to be already - * loaded whenever WindowExplorer.dll needs to be loaded. - */ - -#include "wndexp.h" - -BOOLEAN WepCreateServerObjects( - VOID - ); - -BOOLEAN WepOpenServerObjects( - VOID - ); - -VOID WepCloseServerObjects( - VOID - ); - -VOID WepWriteClientData( - _In_ HWND hwnd - ); - -LRESULT CALLBACK WepCallWndProc( - _In_ int nCode, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -// Shared -ULONG WeServerMessage; -HANDLE WeServerSharedSection; -PWE_HOOK_SHARED_DATA WeServerSharedData; -HANDLE WeServerSharedSectionLock; -HANDLE WeServerSharedSectionEvent; -// Server -HHOOK WeHookHandle = NULL; -// The current message ID is used to detect out-of-sync clients. -ULONG WeCurrentMessageId = 0; - -// Server - -VOID WeHookServerInitialization( - VOID - ) -{ - if (WeHookHandle) - return; - - WeServerMessage = RegisterWindowMessage(WE_SERVER_MESSAGE_NAME); - - if (!WepCreateServerObjects()) - return; - - WeHookHandle = SetWindowsHookEx(WH_CALLWNDPROC, WepCallWndProc, PluginInstance->DllBase, 0); -} - -VOID WeHookServerUninitialization( - VOID - ) -{ - if (WeHookHandle) - { - UnhookWindowsHookEx(WeHookHandle); - WeHookHandle = NULL; - } -} - -BOOLEAN WepCreateServerObjects( - VOID - ) -{ - OBJECT_ATTRIBUTES objectAttributes; - WCHAR buffer[256]; - UNICODE_STRING objectName; - SECURITY_DESCRIPTOR securityDescriptor; - UCHAR saclBuffer[sizeof(ACL) + FIELD_OFFSET(SYSTEM_MANDATORY_LABEL_ACE, SidStart) + FIELD_OFFSET(SID, SubAuthority) + sizeof(ULONG)]; - PACL sacl; - UCHAR mandatoryLabelAceBuffer[FIELD_OFFSET(SYSTEM_MANDATORY_LABEL_ACE, SidStart) + FIELD_OFFSET(SID, SubAuthority) + sizeof(ULONG)]; - PSYSTEM_MANDATORY_LABEL_ACE mandatoryLabelAce; - PSID sid; - - if (!WeServerSharedSection) - { - LARGE_INTEGER maximumSize; - - WeFormatLocalObjectName(WE_SERVER_SHARED_SECTION_NAME, buffer, &objectName); - InitializeObjectAttributes(&objectAttributes, &objectName, OBJ_CASE_INSENSITIVE, NULL, NULL); - maximumSize.QuadPart = sizeof(WE_HOOK_SHARED_DATA); - - if (!NT_SUCCESS(NtCreateSection( - &WeServerSharedSection, - SECTION_ALL_ACCESS, - &objectAttributes, - &maximumSize, - PAGE_READWRITE, - SEC_COMMIT, - NULL - ))) - { - return FALSE; - } - } - - if (!WeServerSharedData) - { - PVOID viewBase; - SIZE_T viewSize; - - viewBase = NULL; - viewSize = sizeof(WE_HOOK_SHARED_DATA); - - if (!NT_SUCCESS(NtMapViewOfSection( - WeServerSharedSection, - NtCurrentProcess(), - &viewBase, - 0, - 0, - NULL, - &viewSize, - ViewShare, - 0, - PAGE_READWRITE - ))) - { - WepCloseServerObjects(); - return FALSE; - } - - WeServerSharedData = viewBase; - } - - if (!WeServerSharedSectionLock) - { - WeFormatLocalObjectName(WE_SERVER_SHARED_SECTION_LOCK_NAME, buffer, &objectName); - InitializeObjectAttributes(&objectAttributes, &objectName, OBJ_CASE_INSENSITIVE, NULL, NULL); - - if (!NT_SUCCESS(NtCreateMutant( - &WeServerSharedSectionLock, - MUTANT_ALL_ACCESS, - &objectAttributes, - FALSE - ))) - { - WepCloseServerObjects(); - return FALSE; - } - } - - if (!WeServerSharedSectionEvent) - { - WeFormatLocalObjectName(WE_SERVER_SHARED_SECTION_EVENT_NAME, buffer, &objectName); - InitializeObjectAttributes(&objectAttributes, &objectName, OBJ_CASE_INSENSITIVE, NULL, NULL); - - if (!NT_SUCCESS(NtCreateEvent( - &WeServerSharedSectionEvent, - EVENT_ALL_ACCESS, - &objectAttributes, - NotificationEvent, - FALSE - ))) - { - WepCloseServerObjects(); - return FALSE; - } - } - - // If mandatory labels are supported, set it to the lowest possible level. - if (WE_WindowsVersion >= WINDOWS_VISTA) - { - static SID_IDENTIFIER_AUTHORITY mandatoryLabelAuthority = SECURITY_MANDATORY_LABEL_AUTHORITY; - - RtlCreateSecurityDescriptor(&securityDescriptor, SECURITY_DESCRIPTOR_REVISION); - - sacl = (PACL)saclBuffer; - RtlCreateAcl(sacl, sizeof(saclBuffer), ACL_REVISION); - - mandatoryLabelAce = (PSYSTEM_MANDATORY_LABEL_ACE)mandatoryLabelAceBuffer; - mandatoryLabelAce->Header.AceType = SYSTEM_MANDATORY_LABEL_ACE_TYPE; - mandatoryLabelAce->Header.AceFlags = 0; - mandatoryLabelAce->Header.AceSize = sizeof(mandatoryLabelAceBuffer); - mandatoryLabelAce->Mask = SYSTEM_MANDATORY_LABEL_NO_WRITE_UP; - - sid = (PSID)&mandatoryLabelAce->SidStart; - RtlInitializeSid(sid, &mandatoryLabelAuthority, 1); - *RtlSubAuthoritySid(sid, 0) = SECURITY_MANDATORY_LOW_RID; - - if (NT_SUCCESS(RtlAddAce(sacl, ACL_REVISION, MAXULONG32, mandatoryLabelAce, sizeof(mandatoryLabelAceBuffer)))) - { - if (NT_SUCCESS(RtlSetSaclSecurityDescriptor(&securityDescriptor, TRUE, sacl, FALSE))) - { - NtSetSecurityObject(WeServerSharedSection, LABEL_SECURITY_INFORMATION, &securityDescriptor); - NtSetSecurityObject(WeServerSharedSectionLock, LABEL_SECURITY_INFORMATION, &securityDescriptor); - NtSetSecurityObject(WeServerSharedSectionEvent, LABEL_SECURITY_INFORMATION, &securityDescriptor); - } - } - } - - return TRUE; -} - -BOOLEAN WepOpenServerObjects( - VOID - ) -{ - OBJECT_ATTRIBUTES objectAttributes; - WCHAR buffer[256]; - UNICODE_STRING objectName; - - if (!WeServerSharedSection) - { - WeFormatLocalObjectName(WE_SERVER_SHARED_SECTION_NAME, buffer, &objectName); - InitializeObjectAttributes(&objectAttributes, &objectName, OBJ_CASE_INSENSITIVE, NULL, NULL); - - if (!NT_SUCCESS(NtOpenSection( - &WeServerSharedSection, - SECTION_ALL_ACCESS, - &objectAttributes - ))) - { - return FALSE; - } - } - - if (!WeServerSharedData) - { - PVOID viewBase; - SIZE_T viewSize; - - viewBase = NULL; - viewSize = sizeof(WE_HOOK_SHARED_DATA); - - if (!NT_SUCCESS(NtMapViewOfSection( - WeServerSharedSection, - NtCurrentProcess(), - &viewBase, - 0, - 0, - NULL, - &viewSize, - ViewShare, - 0, - PAGE_READWRITE - ))) - { - WepCloseServerObjects(); - return FALSE; - } - - WeServerSharedData = viewBase; - } - - if (!WeServerSharedSectionLock) - { - WeFormatLocalObjectName(WE_SERVER_SHARED_SECTION_LOCK_NAME, buffer, &objectName); - InitializeObjectAttributes(&objectAttributes, &objectName, OBJ_CASE_INSENSITIVE, NULL, NULL); - - if (!NT_SUCCESS(NtOpenMutant( - &WeServerSharedSectionLock, - MUTANT_ALL_ACCESS, - &objectAttributes - ))) - { - WepCloseServerObjects(); - return FALSE; - } - } - - if (!WeServerSharedSectionEvent) - { - WeFormatLocalObjectName(WE_SERVER_SHARED_SECTION_EVENT_NAME, buffer, &objectName); - InitializeObjectAttributes(&objectAttributes, &objectName, OBJ_CASE_INSENSITIVE, NULL, NULL); - - if (!NT_SUCCESS(NtOpenEvent( - &WeServerSharedSectionEvent, - EVENT_ALL_ACCESS, - &objectAttributes - ))) - { - WepCloseServerObjects(); - return FALSE; - } - } - - return TRUE; -} - -VOID WepCloseServerObjects( - VOID - ) -{ - if (WeServerSharedSection) - { - NtClose(WeServerSharedSection); - WeServerSharedSection = NULL; - } - - if (WeServerSharedData) - { - NtUnmapViewOfSection(NtCurrentProcess(), WeServerSharedData); - WeServerSharedData = NULL; - } - - if (WeServerSharedSectionLock) - { - NtClose(WeServerSharedSectionLock); - WeServerSharedSectionLock = NULL; - } - - if (WeServerSharedSectionEvent) - { - NtClose(WeServerSharedSectionEvent); - WeServerSharedSectionEvent = NULL; - } -} - -BOOLEAN WeIsServerActive( - VOID - ) -{ - if (WepOpenServerObjects()) - { - WepCloseServerObjects(); - - return TRUE; - } - else - { - return FALSE; - } -} - -BOOLEAN WeLockServerSharedData( - _Out_ PWE_HOOK_SHARED_DATA *Data - ) -{ - LARGE_INTEGER timeout; - - if (!WeServerSharedSectionLock) - return FALSE; - - timeout.QuadPart = -WE_CLIENT_MESSAGE_TIMEOUT * PH_TIMEOUT_MS; - - if (NtWaitForSingleObject(WeServerSharedSectionLock, FALSE, &timeout) != WAIT_OBJECT_0) - return FALSE; - - *Data = WeServerSharedData; - - return TRUE; -} - -VOID WeUnlockServerSharedData( - VOID - ) -{ - NtReleaseMutant(WeServerSharedSectionLock, NULL); -} - -BOOLEAN WeSendServerRequest( - _In_ HWND hWnd - ) -{ - ULONG threadId; - ULONG processId; - LARGE_INTEGER timeout; - - if (!WeServerSharedData || !WeServerSharedSectionEvent) - return FALSE; - - threadId = GetWindowThreadProcessId(hWnd, &processId); - - if (UlongToHandle(processId) == NtCurrentProcessId()) - { - // We are trying to get information about the server. Call the procedure directly. - WepWriteClientData(hWnd); - return TRUE; - } - - // Call the client and wait for the client to finish. - - WeCurrentMessageId++; - WeServerSharedData->MessageId = WeCurrentMessageId; - NtResetEvent(WeServerSharedSectionEvent, NULL); - - if (!SendNotifyMessage(hWnd, WeServerMessage, (WPARAM)NtCurrentProcessId(), WeCurrentMessageId)) - return FALSE; - - timeout.QuadPart = -WE_CLIENT_MESSAGE_TIMEOUT * PH_TIMEOUT_MS; - - if (NtWaitForSingleObject(WeServerSharedSectionEvent, FALSE, &timeout) != STATUS_WAIT_0) - return FALSE; - - return TRUE; -} - -// Client - -VOID WeHookClientInitialization( - VOID - ) -{ - WeServerMessage = RegisterWindowMessage(WE_SERVER_MESSAGE_NAME); -} - -VOID WeHookClientUninitialization( - VOID - ) -{ - NOTHING; -} - -VOID WepWriteClientData( - _In_ HWND hwnd - ) -{ - WCHAR className[256]; - LOGICAL isUnicode; - - memset(&WeServerSharedData->c, 0, sizeof(WeServerSharedData->c)); - isUnicode = IsWindowUnicode(hwnd); - - if (isUnicode) - { - WeServerSharedData->c.WndProc = GetWindowLongPtrW(hwnd, GWLP_WNDPROC); - WeServerSharedData->c.DlgProc = GetWindowLongPtrW(hwnd, DWLP_DLGPROC); - } - else - { - WeServerSharedData->c.WndProc = GetWindowLongPtrA(hwnd, GWLP_WNDPROC); - WeServerSharedData->c.DlgProc = GetWindowLongPtrA(hwnd, DWLP_DLGPROC); - } - - if (!GetClassName(hwnd, className, sizeof(className) / sizeof(WCHAR))) - className[0] = 0; - - WeServerSharedData->c.ClassInfo.cbSize = sizeof(WNDCLASSEX); - GetClassInfoEx(NULL, className, &WeServerSharedData->c.ClassInfo); - - if (isUnicode) - WeServerSharedData->c.ClassInfo.lpfnWndProc = (PVOID)GetClassLongPtrW(hwnd, GCLP_WNDPROC); - else - WeServerSharedData->c.ClassInfo.lpfnWndProc = (PVOID)GetClassLongPtrA(hwnd, GCLP_WNDPROC); -} - -LRESULT CALLBACK WepCallWndProc( - _In_ int nCode, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - LRESULT result; - PCWPSTRUCT info; - - result = CallNextHookEx(NULL, nCode, wParam, lParam); - - info = (PCWPSTRUCT)lParam; - - if (info->message == WeServerMessage) - { - HANDLE serverProcessId; - ULONG messageId; - - serverProcessId = (HANDLE)info->wParam; - messageId = (ULONG)info->lParam; - - if (serverProcessId != NtCurrentProcessId()) - { - if (WepOpenServerObjects()) - { - if (WeServerSharedData->MessageId == messageId) - { - WepWriteClientData(info->hwnd); - NtSetEvent(WeServerSharedSectionEvent, NULL); - } - - WepCloseServerObjects(); - } - } - } - - return result; -} +/* + * Process Hacker Window Explorer - + * hook procedure + * + * Copyright (C) 2011 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +/* + * Window Explorer uses a hook procedure in order to get window procedure + * and other information that can't be retrieved using GetWindowLongPtr. + * Because WindowExplorer.dll needs to be loaded into processes other + * than Process Hacker, both ProcessHacker.exe and comctl32.dll are set as + * delay-loaded DLLs. The other DLLs that we depend on (gdi32.dll, + * kernel32.dll, ntdll.dll, user32.dll) are all guaranteed to be already + * loaded whenever WindowExplorer.dll needs to be loaded. + */ + +#include "wndexp.h" + +BOOLEAN WepCreateServerObjects( + VOID + ); + +BOOLEAN WepOpenServerObjects( + VOID + ); + +VOID WepCloseServerObjects( + VOID + ); + +VOID WepWriteClientData( + _In_ HWND hwnd + ); + +LRESULT CALLBACK WepCallWndProc( + _In_ int nCode, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +// Shared +ULONG WeServerMessage; +HANDLE WeServerSharedSection; +PWE_HOOK_SHARED_DATA WeServerSharedData; +HANDLE WeServerSharedSectionLock; +HANDLE WeServerSharedSectionEvent; +// Server +HHOOK WeHookHandle = NULL; +// The current message ID is used to detect out-of-sync clients. +ULONG WeCurrentMessageId = 0; + +// Server + +VOID WeHookServerInitialization( + VOID + ) +{ + if (WeHookHandle) + return; + + WeServerMessage = RegisterWindowMessage(WE_SERVER_MESSAGE_NAME); + + if (!WepCreateServerObjects()) + return; + + WeHookHandle = SetWindowsHookEx(WH_CALLWNDPROC, WepCallWndProc, PluginInstance->DllBase, 0); +} + +VOID WeHookServerUninitialization( + VOID + ) +{ + if (WeHookHandle) + { + UnhookWindowsHookEx(WeHookHandle); + WeHookHandle = NULL; + } +} + +BOOLEAN WepCreateServerObjects( + VOID + ) +{ + OBJECT_ATTRIBUTES objectAttributes; + WCHAR buffer[256]; + UNICODE_STRING objectName; + SECURITY_DESCRIPTOR securityDescriptor; + UCHAR saclBuffer[sizeof(ACL) + FIELD_OFFSET(SYSTEM_MANDATORY_LABEL_ACE, SidStart) + FIELD_OFFSET(SID, SubAuthority) + sizeof(ULONG)]; + PACL sacl; + UCHAR mandatoryLabelAceBuffer[FIELD_OFFSET(SYSTEM_MANDATORY_LABEL_ACE, SidStart) + FIELD_OFFSET(SID, SubAuthority) + sizeof(ULONG)]; + PSYSTEM_MANDATORY_LABEL_ACE mandatoryLabelAce; + PSID sid; + + if (!WeServerSharedSection) + { + LARGE_INTEGER maximumSize; + + WeFormatLocalObjectName(WE_SERVER_SHARED_SECTION_NAME, buffer, &objectName); + InitializeObjectAttributes(&objectAttributes, &objectName, OBJ_CASE_INSENSITIVE, NULL, NULL); + maximumSize.QuadPart = sizeof(WE_HOOK_SHARED_DATA); + + if (!NT_SUCCESS(NtCreateSection( + &WeServerSharedSection, + SECTION_ALL_ACCESS, + &objectAttributes, + &maximumSize, + PAGE_READWRITE, + SEC_COMMIT, + NULL + ))) + { + return FALSE; + } + } + + if (!WeServerSharedData) + { + PVOID viewBase; + SIZE_T viewSize; + + viewBase = NULL; + viewSize = sizeof(WE_HOOK_SHARED_DATA); + + if (!NT_SUCCESS(NtMapViewOfSection( + WeServerSharedSection, + NtCurrentProcess(), + &viewBase, + 0, + 0, + NULL, + &viewSize, + ViewShare, + 0, + PAGE_READWRITE + ))) + { + WepCloseServerObjects(); + return FALSE; + } + + WeServerSharedData = viewBase; + } + + if (!WeServerSharedSectionLock) + { + WeFormatLocalObjectName(WE_SERVER_SHARED_SECTION_LOCK_NAME, buffer, &objectName); + InitializeObjectAttributes(&objectAttributes, &objectName, OBJ_CASE_INSENSITIVE, NULL, NULL); + + if (!NT_SUCCESS(NtCreateMutant( + &WeServerSharedSectionLock, + MUTANT_ALL_ACCESS, + &objectAttributes, + FALSE + ))) + { + WepCloseServerObjects(); + return FALSE; + } + } + + if (!WeServerSharedSectionEvent) + { + WeFormatLocalObjectName(WE_SERVER_SHARED_SECTION_EVENT_NAME, buffer, &objectName); + InitializeObjectAttributes(&objectAttributes, &objectName, OBJ_CASE_INSENSITIVE, NULL, NULL); + + if (!NT_SUCCESS(NtCreateEvent( + &WeServerSharedSectionEvent, + EVENT_ALL_ACCESS, + &objectAttributes, + NotificationEvent, + FALSE + ))) + { + WepCloseServerObjects(); + return FALSE; + } + } + + // If mandatory labels are supported, set it to the lowest possible level. + if (WE_WindowsVersion >= WINDOWS_VISTA) + { + static SID_IDENTIFIER_AUTHORITY mandatoryLabelAuthority = SECURITY_MANDATORY_LABEL_AUTHORITY; + + RtlCreateSecurityDescriptor(&securityDescriptor, SECURITY_DESCRIPTOR_REVISION); + + sacl = (PACL)saclBuffer; + RtlCreateAcl(sacl, sizeof(saclBuffer), ACL_REVISION); + + mandatoryLabelAce = (PSYSTEM_MANDATORY_LABEL_ACE)mandatoryLabelAceBuffer; + mandatoryLabelAce->Header.AceType = SYSTEM_MANDATORY_LABEL_ACE_TYPE; + mandatoryLabelAce->Header.AceFlags = 0; + mandatoryLabelAce->Header.AceSize = sizeof(mandatoryLabelAceBuffer); + mandatoryLabelAce->Mask = SYSTEM_MANDATORY_LABEL_NO_WRITE_UP; + + sid = (PSID)&mandatoryLabelAce->SidStart; + RtlInitializeSid(sid, &mandatoryLabelAuthority, 1); + *RtlSubAuthoritySid(sid, 0) = SECURITY_MANDATORY_LOW_RID; + + if (NT_SUCCESS(RtlAddAce(sacl, ACL_REVISION, MAXULONG32, mandatoryLabelAce, sizeof(mandatoryLabelAceBuffer)))) + { + if (NT_SUCCESS(RtlSetSaclSecurityDescriptor(&securityDescriptor, TRUE, sacl, FALSE))) + { + NtSetSecurityObject(WeServerSharedSection, LABEL_SECURITY_INFORMATION, &securityDescriptor); + NtSetSecurityObject(WeServerSharedSectionLock, LABEL_SECURITY_INFORMATION, &securityDescriptor); + NtSetSecurityObject(WeServerSharedSectionEvent, LABEL_SECURITY_INFORMATION, &securityDescriptor); + } + } + } + + return TRUE; +} + +BOOLEAN WepOpenServerObjects( + VOID + ) +{ + OBJECT_ATTRIBUTES objectAttributes; + WCHAR buffer[256]; + UNICODE_STRING objectName; + + if (!WeServerSharedSection) + { + WeFormatLocalObjectName(WE_SERVER_SHARED_SECTION_NAME, buffer, &objectName); + InitializeObjectAttributes(&objectAttributes, &objectName, OBJ_CASE_INSENSITIVE, NULL, NULL); + + if (!NT_SUCCESS(NtOpenSection( + &WeServerSharedSection, + SECTION_ALL_ACCESS, + &objectAttributes + ))) + { + return FALSE; + } + } + + if (!WeServerSharedData) + { + PVOID viewBase; + SIZE_T viewSize; + + viewBase = NULL; + viewSize = sizeof(WE_HOOK_SHARED_DATA); + + if (!NT_SUCCESS(NtMapViewOfSection( + WeServerSharedSection, + NtCurrentProcess(), + &viewBase, + 0, + 0, + NULL, + &viewSize, + ViewShare, + 0, + PAGE_READWRITE + ))) + { + WepCloseServerObjects(); + return FALSE; + } + + WeServerSharedData = viewBase; + } + + if (!WeServerSharedSectionLock) + { + WeFormatLocalObjectName(WE_SERVER_SHARED_SECTION_LOCK_NAME, buffer, &objectName); + InitializeObjectAttributes(&objectAttributes, &objectName, OBJ_CASE_INSENSITIVE, NULL, NULL); + + if (!NT_SUCCESS(NtOpenMutant( + &WeServerSharedSectionLock, + MUTANT_ALL_ACCESS, + &objectAttributes + ))) + { + WepCloseServerObjects(); + return FALSE; + } + } + + if (!WeServerSharedSectionEvent) + { + WeFormatLocalObjectName(WE_SERVER_SHARED_SECTION_EVENT_NAME, buffer, &objectName); + InitializeObjectAttributes(&objectAttributes, &objectName, OBJ_CASE_INSENSITIVE, NULL, NULL); + + if (!NT_SUCCESS(NtOpenEvent( + &WeServerSharedSectionEvent, + EVENT_ALL_ACCESS, + &objectAttributes + ))) + { + WepCloseServerObjects(); + return FALSE; + } + } + + return TRUE; +} + +VOID WepCloseServerObjects( + VOID + ) +{ + if (WeServerSharedSection) + { + NtClose(WeServerSharedSection); + WeServerSharedSection = NULL; + } + + if (WeServerSharedData) + { + NtUnmapViewOfSection(NtCurrentProcess(), WeServerSharedData); + WeServerSharedData = NULL; + } + + if (WeServerSharedSectionLock) + { + NtClose(WeServerSharedSectionLock); + WeServerSharedSectionLock = NULL; + } + + if (WeServerSharedSectionEvent) + { + NtClose(WeServerSharedSectionEvent); + WeServerSharedSectionEvent = NULL; + } +} + +BOOLEAN WeIsServerActive( + VOID + ) +{ + if (WepOpenServerObjects()) + { + WepCloseServerObjects(); + + return TRUE; + } + else + { + return FALSE; + } +} + +BOOLEAN WeLockServerSharedData( + _Out_ PWE_HOOK_SHARED_DATA *Data + ) +{ + LARGE_INTEGER timeout; + + if (!WeServerSharedSectionLock) + return FALSE; + + timeout.QuadPart = -WE_CLIENT_MESSAGE_TIMEOUT * PH_TIMEOUT_MS; + + if (NtWaitForSingleObject(WeServerSharedSectionLock, FALSE, &timeout) != WAIT_OBJECT_0) + return FALSE; + + *Data = WeServerSharedData; + + return TRUE; +} + +VOID WeUnlockServerSharedData( + VOID + ) +{ + NtReleaseMutant(WeServerSharedSectionLock, NULL); +} + +BOOLEAN WeSendServerRequest( + _In_ HWND hWnd + ) +{ + ULONG threadId; + ULONG processId; + LARGE_INTEGER timeout; + + if (!WeServerSharedData || !WeServerSharedSectionEvent) + return FALSE; + + threadId = GetWindowThreadProcessId(hWnd, &processId); + + if (UlongToHandle(processId) == NtCurrentProcessId()) + { + // We are trying to get information about the server. Call the procedure directly. + WepWriteClientData(hWnd); + return TRUE; + } + + // Call the client and wait for the client to finish. + + WeCurrentMessageId++; + WeServerSharedData->MessageId = WeCurrentMessageId; + NtResetEvent(WeServerSharedSectionEvent, NULL); + + if (!SendNotifyMessage(hWnd, WeServerMessage, (WPARAM)NtCurrentProcessId(), WeCurrentMessageId)) + return FALSE; + + timeout.QuadPart = -WE_CLIENT_MESSAGE_TIMEOUT * PH_TIMEOUT_MS; + + if (NtWaitForSingleObject(WeServerSharedSectionEvent, FALSE, &timeout) != STATUS_WAIT_0) + return FALSE; + + return TRUE; +} + +// Client + +VOID WeHookClientInitialization( + VOID + ) +{ + WeServerMessage = RegisterWindowMessage(WE_SERVER_MESSAGE_NAME); +} + +VOID WeHookClientUninitialization( + VOID + ) +{ + NOTHING; +} + +VOID WepWriteClientData( + _In_ HWND hwnd + ) +{ + WCHAR className[256]; + LOGICAL isUnicode; + + memset(&WeServerSharedData->c, 0, sizeof(WeServerSharedData->c)); + isUnicode = IsWindowUnicode(hwnd); + + if (isUnicode) + { + WeServerSharedData->c.WndProc = GetWindowLongPtrW(hwnd, GWLP_WNDPROC); + WeServerSharedData->c.DlgProc = GetWindowLongPtrW(hwnd, DWLP_DLGPROC); + } + else + { + WeServerSharedData->c.WndProc = GetWindowLongPtrA(hwnd, GWLP_WNDPROC); + WeServerSharedData->c.DlgProc = GetWindowLongPtrA(hwnd, DWLP_DLGPROC); + } + + if (!GetClassName(hwnd, className, sizeof(className) / sizeof(WCHAR))) + className[0] = 0; + + WeServerSharedData->c.ClassInfo.cbSize = sizeof(WNDCLASSEX); + GetClassInfoEx(NULL, className, &WeServerSharedData->c.ClassInfo); + + if (isUnicode) + WeServerSharedData->c.ClassInfo.lpfnWndProc = (PVOID)GetClassLongPtrW(hwnd, GCLP_WNDPROC); + else + WeServerSharedData->c.ClassInfo.lpfnWndProc = (PVOID)GetClassLongPtrA(hwnd, GCLP_WNDPROC); +} + +LRESULT CALLBACK WepCallWndProc( + _In_ int nCode, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + LRESULT result; + PCWPSTRUCT info; + + result = CallNextHookEx(NULL, nCode, wParam, lParam); + + info = (PCWPSTRUCT)lParam; + + if (info->message == WeServerMessage) + { + HANDLE serverProcessId; + ULONG messageId; + + serverProcessId = (HANDLE)info->wParam; + messageId = (ULONG)info->lParam; + + if (serverProcessId != NtCurrentProcessId()) + { + if (WepOpenServerObjects()) + { + if (WeServerSharedData->MessageId == messageId) + { + WepWriteClientData(info->hwnd); + NtSetEvent(WeServerSharedSectionEvent, NULL); + } + + WepCloseServerObjects(); + } + } + } + + return result; +} diff --git a/plugins/WindowExplorer/main.c b/plugins/WindowExplorer/main.c index db51c855bcb5..c3cc7af784de 100644 --- a/plugins/WindowExplorer/main.c +++ b/plugins/WindowExplorer/main.c @@ -1,325 +1,325 @@ -/* - * Process Hacker Window Explorer - - * main program - * - * Copyright (C) 2011 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include "wndexp.h" -#include "resource.h" - -BOOLEAN IsHookClient; -PPH_PLUGIN PluginInstance; -PH_CALLBACK_REGISTRATION PluginLoadCallbackRegistration; -PH_CALLBACK_REGISTRATION PluginUnloadCallbackRegistration; -PH_CALLBACK_REGISTRATION PluginShowOptionsCallbackRegistration; -PH_CALLBACK_REGISTRATION PluginMenuItemCallbackRegistration; -PH_CALLBACK_REGISTRATION MainMenuInitializingCallbackRegistration; -PH_CALLBACK_REGISTRATION ProcessPropertiesInitializingCallbackRegistration; -PH_CALLBACK_REGISTRATION ThreadMenuInitializingCallbackRegistration; - - -VOID NTAPI LoadCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - NOTHING; -} - -VOID NTAPI UnloadCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - WeHookServerUninitialization(); -} - -VOID NTAPI ShowOptionsCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - NOTHING; -} - -BOOL CALLBACK WepEnumDesktopProc( - _In_ LPTSTR lpszDesktop, - _In_ LPARAM lParam - ) -{ - PhAddItemList((PPH_LIST)lParam, PhaCreateString(lpszDesktop)->Buffer); - - return TRUE; -} - -VOID NTAPI MenuItemCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - PPH_PLUGIN_MENU_ITEM menuItem = Parameter; - - switch (menuItem->Id) - { - case ID_VIEW_WINDOWS: - { - WE_WINDOW_SELECTOR selector; - - selector.Type = WeWindowSelectorAll; - WeShowWindowsDialog(WE_PhMainWndHandle, &selector); - } - break; - case ID_VIEW_DESKTOPWINDOWS: - { - PPH_LIST desktopNames; - PPH_STRING selectedChoice = NULL; - - desktopNames = PH_AUTO(PhCreateList(4)); - EnumDesktops(GetProcessWindowStation(), WepEnumDesktopProc, (LPARAM)desktopNames); - - if (PhaChoiceDialog( - WE_PhMainWndHandle, - L"Desktop Windows", - L"Display windows for the following desktop:", - (PWSTR *)desktopNames->Items, - desktopNames->Count, - NULL, - PH_CHOICE_DIALOG_CHOICE, - &selectedChoice, - NULL, - NULL - )) - { - WE_WINDOW_SELECTOR selector; - - selector.Type = WeWindowSelectorDesktop; - PhSetReference(&selector.Desktop.DesktopName, selectedChoice); - WeShowWindowsDialog(WE_PhMainWndHandle, &selector); - } - } - break; - case ID_PROCESS_WINDOWS: - { - WE_WINDOW_SELECTOR selector; - - selector.Type = WeWindowSelectorProcess; - selector.Process.ProcessId = ((PPH_PROCESS_ITEM)menuItem->Context)->ProcessId; - WeShowWindowsDialog(WE_PhMainWndHandle, &selector); - } - break; - case ID_THREAD_WINDOWS: - { - WE_WINDOW_SELECTOR selector; - - selector.Type = WeWindowSelectorThread; - selector.Thread.ThreadId = ((PPH_THREAD_ITEM)menuItem->Context)->ThreadId; - WeShowWindowsDialog(WE_PhMainWndHandle, &selector); - } - break; - } -} - -VOID NTAPI MainMenuInitializingCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - ULONG insertIndex; - PPH_EMENU_ITEM menuItem; - PPH_PLUGIN_MENU_INFORMATION menuInfo = Parameter; - - if (menuInfo->u.MainMenu.SubMenuIndex != PH_MENU_ITEM_LOCATION_VIEW) - return; - - if (menuItem = PhFindEMenuItem(menuInfo->Menu, PH_EMENU_FIND_STARTSWITH, L"System Information", 0)) - insertIndex = PhIndexOfEMenuItem(menuInfo->Menu, menuItem) + 1; - else - insertIndex = 0; - - PhInsertEMenuItem(menuInfo->Menu, menuItem = PhPluginCreateEMenuItem(PluginInstance, 0, ID_VIEW_WINDOWS, L"Windows", NULL), insertIndex); - - if (PhGetIntegerSetting(SETTING_NAME_SHOW_DESKTOP_WINDOWS)) - { - insertIndex = PhIndexOfEMenuItem(menuInfo->Menu, menuItem) + 1; - - PhInsertEMenuItem(menuInfo->Menu, PhPluginCreateEMenuItem(PluginInstance, 0, ID_VIEW_DESKTOPWINDOWS, L"Desktop Windows...", NULL), insertIndex); - } -} - -VOID NTAPI ProcessPropertiesInitializingCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - PPH_PLUGIN_PROCESS_PROPCONTEXT propContext = Parameter; - BOOLEAN isGuiProcess = TRUE; - - // enum threads, IsGuiThread, isGuiProcess=TRUE - - if (isGuiProcess) - { - WE_WINDOW_SELECTOR selector; - - selector.Type = WeWindowSelectorProcess; - selector.Process.ProcessId = propContext->ProcessItem->ProcessId; - WeShowWindowsPropPage(propContext, &selector); - } -} - -VOID NTAPI ThreadMenuInitializingCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - PPH_PLUGIN_MENU_INFORMATION menuInfo = Parameter; - PPH_THREAD_ITEM threadItem; - ULONG insertIndex; - PPH_EMENU_ITEM menuItem; - - if (menuInfo->u.Thread.NumberOfThreads == 1) - threadItem = menuInfo->u.Thread.Threads[0]; - else - threadItem = NULL; - - if (menuItem = PhFindEMenuItem(menuInfo->Menu, 0, L"Token", 0)) - insertIndex = PhIndexOfEMenuItem(menuInfo->Menu, menuItem) + 1; - else - insertIndex = 0; - - PhInsertEMenuItem(menuInfo->Menu, menuItem = PhPluginCreateEMenuItem(PluginInstance, 0, ID_THREAD_WINDOWS, - L"Windows", threadItem), insertIndex); - - if (!threadItem) menuItem->Flags |= PH_EMENU_DISABLED; -} - -LOGICAL DllMain( - _In_ HINSTANCE Instance, - _In_ ULONG Reason, - _Reserved_ PVOID Reserved - ) -{ - switch (Reason) - { - case DLL_PROCESS_ATTACH: - { - BOOLEAN isClient; - PPH_PLUGIN_INFORMATION info; - PH_SETTING_CREATE settings[] = - { - { IntegerSettingType, SETTING_NAME_SHOW_DESKTOP_WINDOWS, L"1" }, - { StringSettingType, SETTING_NAME_WINDOW_TREE_LIST_COLUMNS, L"" }, - { IntegerPairSettingType, SETTING_NAME_WINDOWS_WINDOW_POSITION, L"100,100" }, - { ScalableIntegerPairSettingType, SETTING_NAME_WINDOWS_WINDOW_SIZE, L"@96|690,540" } - }; - - isClient = FALSE; - - if (!GetModuleHandle(L"ProcessHacker.exe") || !WeGetProcedureAddress("PhLibImageBase")) - { - isClient = TRUE; - } - else - { - // WindowExplorer appears to be loading within Process Hacker. However, if there is - // already a server instance, the the hook will be active, and our DllMain routine - // will most likely be called before the plugin system is even initialized. Attempting - // to register a plugin would result in an access violation, so load as a client for now. - if (WeIsServerActive()) - isClient = TRUE; - } - - if (isClient) - { - // This DLL is being loaded not as a Process Hacker plugin, but as a hook. - IsHookClient = TRUE; - WeHookClientInitialization(); - - break; - } - - PluginInstance = PhRegisterPlugin(PLUGIN_NAME, Instance, &info); - - if (!PluginInstance) - return FALSE; - - info->DisplayName = L"Window Explorer"; - info->Author = L"wj32"; - info->Description = L"View and manipulate windows."; - info->Url = L"https://wj32.org/processhacker/forums/viewtopic.php?t=1116"; - info->HasOptions = FALSE; - - PhRegisterCallback( - PhGetPluginCallback(PluginInstance, PluginCallbackLoad), - LoadCallback, - NULL, - &PluginLoadCallbackRegistration - ); - PhRegisterCallback( - PhGetPluginCallback(PluginInstance, PluginCallbackUnload), - UnloadCallback, - NULL, - &PluginUnloadCallbackRegistration - ); - //PhRegisterCallback( - // PhGetPluginCallback(PluginInstance, PluginCallbackShowOptions), - // ShowOptionsCallback, - // NULL, - // &PluginShowOptionsCallbackRegistration - // ); - PhRegisterCallback( - PhGetPluginCallback(PluginInstance, PluginCallbackMenuItem), - MenuItemCallback, - NULL, - &PluginMenuItemCallbackRegistration - ); - - PhRegisterCallback( - PhGetGeneralCallback(GeneralCallbackMainMenuInitializing), - MainMenuInitializingCallback, - NULL, - &MainMenuInitializingCallbackRegistration - ); - PhRegisterCallback( - PhGetGeneralCallback(GeneralCallbackProcessPropertiesInitializing), - ProcessPropertiesInitializingCallback, - NULL, - &ProcessPropertiesInitializingCallbackRegistration - ); - PhRegisterCallback( - PhGetGeneralCallback(GeneralCallbackThreadMenuInitializing), - ThreadMenuInitializingCallback, - NULL, - &ThreadMenuInitializingCallbackRegistration - ); - - PhAddSettings(settings, ARRAYSIZE(settings)); - } - break; - case DLL_PROCESS_DETACH: - { - if (IsHookClient) - { - WeHookClientUninitialization(); - } - } - break; - } - - return TRUE; -} +/* + * Process Hacker Window Explorer - + * main program + * + * Copyright (C) 2011 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include "wndexp.h" +#include "resource.h" + +BOOLEAN IsHookClient; +PPH_PLUGIN PluginInstance; +PH_CALLBACK_REGISTRATION PluginLoadCallbackRegistration; +PH_CALLBACK_REGISTRATION PluginUnloadCallbackRegistration; +PH_CALLBACK_REGISTRATION PluginShowOptionsCallbackRegistration; +PH_CALLBACK_REGISTRATION PluginMenuItemCallbackRegistration; +PH_CALLBACK_REGISTRATION MainMenuInitializingCallbackRegistration; +PH_CALLBACK_REGISTRATION ProcessPropertiesInitializingCallbackRegistration; +PH_CALLBACK_REGISTRATION ThreadMenuInitializingCallbackRegistration; + + +VOID NTAPI LoadCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + NOTHING; +} + +VOID NTAPI UnloadCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + WeHookServerUninitialization(); +} + +VOID NTAPI ShowOptionsCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + NOTHING; +} + +BOOL CALLBACK WepEnumDesktopProc( + _In_ LPTSTR lpszDesktop, + _In_ LPARAM lParam + ) +{ + PhAddItemList((PPH_LIST)lParam, PhaCreateString(lpszDesktop)->Buffer); + + return TRUE; +} + +VOID NTAPI MenuItemCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + PPH_PLUGIN_MENU_ITEM menuItem = Parameter; + + switch (menuItem->Id) + { + case ID_VIEW_WINDOWS: + { + WE_WINDOW_SELECTOR selector; + + selector.Type = WeWindowSelectorAll; + WeShowWindowsDialog(WE_PhMainWndHandle, &selector); + } + break; + case ID_VIEW_DESKTOPWINDOWS: + { + PPH_LIST desktopNames; + PPH_STRING selectedChoice = NULL; + + desktopNames = PH_AUTO(PhCreateList(4)); + EnumDesktops(GetProcessWindowStation(), WepEnumDesktopProc, (LPARAM)desktopNames); + + if (PhaChoiceDialog( + WE_PhMainWndHandle, + L"Desktop Windows", + L"Display windows for the following desktop:", + (PWSTR *)desktopNames->Items, + desktopNames->Count, + NULL, + PH_CHOICE_DIALOG_CHOICE, + &selectedChoice, + NULL, + NULL + )) + { + WE_WINDOW_SELECTOR selector; + + selector.Type = WeWindowSelectorDesktop; + PhSetReference(&selector.Desktop.DesktopName, selectedChoice); + WeShowWindowsDialog(WE_PhMainWndHandle, &selector); + } + } + break; + case ID_PROCESS_WINDOWS: + { + WE_WINDOW_SELECTOR selector; + + selector.Type = WeWindowSelectorProcess; + selector.Process.ProcessId = ((PPH_PROCESS_ITEM)menuItem->Context)->ProcessId; + WeShowWindowsDialog(WE_PhMainWndHandle, &selector); + } + break; + case ID_THREAD_WINDOWS: + { + WE_WINDOW_SELECTOR selector; + + selector.Type = WeWindowSelectorThread; + selector.Thread.ThreadId = ((PPH_THREAD_ITEM)menuItem->Context)->ThreadId; + WeShowWindowsDialog(WE_PhMainWndHandle, &selector); + } + break; + } +} + +VOID NTAPI MainMenuInitializingCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + ULONG insertIndex; + PPH_EMENU_ITEM menuItem; + PPH_PLUGIN_MENU_INFORMATION menuInfo = Parameter; + + if (menuInfo->u.MainMenu.SubMenuIndex != PH_MENU_ITEM_LOCATION_VIEW) + return; + + if (menuItem = PhFindEMenuItem(menuInfo->Menu, PH_EMENU_FIND_STARTSWITH, L"System Information", 0)) + insertIndex = PhIndexOfEMenuItem(menuInfo->Menu, menuItem) + 1; + else + insertIndex = 0; + + PhInsertEMenuItem(menuInfo->Menu, menuItem = PhPluginCreateEMenuItem(PluginInstance, 0, ID_VIEW_WINDOWS, L"Windows", NULL), insertIndex); + + if (PhGetIntegerSetting(SETTING_NAME_SHOW_DESKTOP_WINDOWS)) + { + insertIndex = PhIndexOfEMenuItem(menuInfo->Menu, menuItem) + 1; + + PhInsertEMenuItem(menuInfo->Menu, PhPluginCreateEMenuItem(PluginInstance, 0, ID_VIEW_DESKTOPWINDOWS, L"Desktop Windows...", NULL), insertIndex); + } +} + +VOID NTAPI ProcessPropertiesInitializingCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + PPH_PLUGIN_PROCESS_PROPCONTEXT propContext = Parameter; + BOOLEAN isGuiProcess = TRUE; + + // enum threads, IsGuiThread, isGuiProcess=TRUE + + if (isGuiProcess) + { + WE_WINDOW_SELECTOR selector; + + selector.Type = WeWindowSelectorProcess; + selector.Process.ProcessId = propContext->ProcessItem->ProcessId; + WeShowWindowsPropPage(propContext, &selector); + } +} + +VOID NTAPI ThreadMenuInitializingCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + PPH_PLUGIN_MENU_INFORMATION menuInfo = Parameter; + PPH_THREAD_ITEM threadItem; + ULONG insertIndex; + PPH_EMENU_ITEM menuItem; + + if (menuInfo->u.Thread.NumberOfThreads == 1) + threadItem = menuInfo->u.Thread.Threads[0]; + else + threadItem = NULL; + + if (menuItem = PhFindEMenuItem(menuInfo->Menu, 0, L"Token", 0)) + insertIndex = PhIndexOfEMenuItem(menuInfo->Menu, menuItem) + 1; + else + insertIndex = 0; + + PhInsertEMenuItem(menuInfo->Menu, menuItem = PhPluginCreateEMenuItem(PluginInstance, 0, ID_THREAD_WINDOWS, + L"Windows", threadItem), insertIndex); + + if (!threadItem) menuItem->Flags |= PH_EMENU_DISABLED; +} + +LOGICAL DllMain( + _In_ HINSTANCE Instance, + _In_ ULONG Reason, + _Reserved_ PVOID Reserved + ) +{ + switch (Reason) + { + case DLL_PROCESS_ATTACH: + { + BOOLEAN isClient; + PPH_PLUGIN_INFORMATION info; + PH_SETTING_CREATE settings[] = + { + { IntegerSettingType, SETTING_NAME_SHOW_DESKTOP_WINDOWS, L"1" }, + { StringSettingType, SETTING_NAME_WINDOW_TREE_LIST_COLUMNS, L"" }, + { IntegerPairSettingType, SETTING_NAME_WINDOWS_WINDOW_POSITION, L"100,100" }, + { ScalableIntegerPairSettingType, SETTING_NAME_WINDOWS_WINDOW_SIZE, L"@96|690,540" } + }; + + isClient = FALSE; + + if (!GetModuleHandle(L"ProcessHacker.exe") || !WeGetProcedureAddress("PhLibImageBase")) + { + isClient = TRUE; + } + else + { + // WindowExplorer appears to be loading within Process Hacker. However, if there is + // already a server instance, the the hook will be active, and our DllMain routine + // will most likely be called before the plugin system is even initialized. Attempting + // to register a plugin would result in an access violation, so load as a client for now. + if (WeIsServerActive()) + isClient = TRUE; + } + + if (isClient) + { + // This DLL is being loaded not as a Process Hacker plugin, but as a hook. + IsHookClient = TRUE; + WeHookClientInitialization(); + + break; + } + + PluginInstance = PhRegisterPlugin(PLUGIN_NAME, Instance, &info); + + if (!PluginInstance) + return FALSE; + + info->DisplayName = L"Window Explorer"; + info->Author = L"wj32"; + info->Description = L"View and manipulate windows."; + info->Url = L"https://wj32.org/processhacker/forums/viewtopic.php?t=1116"; + info->HasOptions = FALSE; + + PhRegisterCallback( + PhGetPluginCallback(PluginInstance, PluginCallbackLoad), + LoadCallback, + NULL, + &PluginLoadCallbackRegistration + ); + PhRegisterCallback( + PhGetPluginCallback(PluginInstance, PluginCallbackUnload), + UnloadCallback, + NULL, + &PluginUnloadCallbackRegistration + ); + //PhRegisterCallback( + // PhGetPluginCallback(PluginInstance, PluginCallbackShowOptions), + // ShowOptionsCallback, + // NULL, + // &PluginShowOptionsCallbackRegistration + // ); + PhRegisterCallback( + PhGetPluginCallback(PluginInstance, PluginCallbackMenuItem), + MenuItemCallback, + NULL, + &PluginMenuItemCallbackRegistration + ); + + PhRegisterCallback( + PhGetGeneralCallback(GeneralCallbackMainMenuInitializing), + MainMenuInitializingCallback, + NULL, + &MainMenuInitializingCallbackRegistration + ); + PhRegisterCallback( + PhGetGeneralCallback(GeneralCallbackProcessPropertiesInitializing), + ProcessPropertiesInitializingCallback, + NULL, + &ProcessPropertiesInitializingCallbackRegistration + ); + PhRegisterCallback( + PhGetGeneralCallback(GeneralCallbackThreadMenuInitializing), + ThreadMenuInitializingCallback, + NULL, + &ThreadMenuInitializingCallbackRegistration + ); + + PhAddSettings(settings, ARRAYSIZE(settings)); + } + break; + case DLL_PROCESS_DETACH: + { + if (IsHookClient) + { + WeHookClientUninitialization(); + } + } + break; + } + + return TRUE; +} diff --git a/plugins/WindowExplorer/resource.h b/plugins/WindowExplorer/resource.h index 055357f62d44..29511b8b8ae5 100644 --- a/plugins/WindowExplorer/resource.h +++ b/plugins/WindowExplorer/resource.h @@ -1,82 +1,82 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by WindowExplorer.rc -// -#define IDD_WNDPROPS 9 -#define IDD_WNDLIST 101 -#define ID_VIEW_WINDOWS 101 -#define ID_THREAD_WINDOWS 102 -#define ID_PROCESS_WINDOWS 103 -#define IDR_WINDOW 103 -#define ID_SHOWCONTEXTMENU 104 -#define IDD_WNDGENERAL 104 -#define ID_VIEW_DESKTOPWINDOWS 105 -#define IDD_WNDSTYLES 105 -#define IDD_WNDCLASS 106 -#define IDD_WNDGENERAL1 106 -#define IDC_LIST 1001 -#define IDC_REFRESH 1002 -#define IDC_TEXT 1009 -#define IDC_RECTANGLE 1010 -#define IDC_NORMALRECTANGLE 1011 -#define IDC_CLIENTRECTANGLE 1012 -#define IDC_THREAD 1016 -#define IDC_STYLESLIST 1017 -#define IDC_STYLES 1018 -#define IDC_EXTENDEDSTYLES 1019 -#define IDC_EXTENDEDSTYLESLIST 1020 -#define IDC_INSTANCEHANDLE 1021 -#define IDC_MENUHANDLE 1022 -#define IDC_WINDOWPROC 1023 -#define IDC_WINDOWPROC2 1024 -#define IDC_DIALOGPROC 1024 -#define IDC_USERDATA 1025 -#define IDC_NAME 1026 -#define IDC_ATOM 1028 -#define IDC_CURSORHANDLE 1029 -#define IDC_ICONHANDLE 1030 -#define IDC_ICONHANDLE2 1031 -#define IDC_SMALLICONHANDLE 1031 -#define IDC_BACKGROUNDBRUSH 1032 -#define IDC_MENUNAME 1033 -#define IDC_UNICODE 1034 -#define IDC_CTRLID 1035 -#define IDC_SEARCHEDIT 1035 -#define ID_WINDOW_GOTOTHREAD 40001 -#define ID_WINDOW_COPY 40002 -#define ID_WINDOW_PROPERTIES 40003 -#define ID_WINDOW_BRINGTOFRONT 40004 -#define ID_WINDOW_RESTORE 40005 -#define ID_WINDOW_MINIMIZE 40006 -#define ID_WINDOW_MAXIMIZE 40007 -#define ID_WINDOW_CLOSE 40008 -#define ID_WINDOW_SHOW 40009 -#define ID_WINDOW_HIGHLIGHT 40010 -#define ID_WINDOW_SHOWHIDE 40011 -#define ID_WINDOW_ENABLE 40012 -#define ID_WINDOW_ENABLEDISABLE 40013 -#define ID_WINDOW_ALWAYSONTOP 40014 -#define ID_WINDOW_OPACITY 40015 -#define ID_OPACITY_10 40016 -#define ID_OPACITY_20 40017 -#define ID_OPACITY_30 40018 -#define ID_OPACITY_40 40019 -#define ID_OPACITY_50 40020 -#define ID_OPACITY_60 40021 -#define ID_OPACITY_70 40022 -#define ID_OPACITY_80 40023 -#define ID_OPACITY_90 40024 -#define ID_OPACITY_OPAQUE 40025 -#define ID_WINDOW_VISIBLE 40026 -#define ID_WINDOW_ENABLED 40027 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 108 -#define _APS_NEXT_COMMAND_VALUE 40028 -#define _APS_NEXT_CONTROL_VALUE 1036 -#define _APS_NEXT_SYMED_VALUE 106 -#endif -#endif +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by WindowExplorer.rc +// +#define IDD_WNDPROPS 9 +#define IDD_WNDLIST 101 +#define ID_VIEW_WINDOWS 101 +#define ID_THREAD_WINDOWS 102 +#define ID_PROCESS_WINDOWS 103 +#define IDR_WINDOW 103 +#define ID_SHOWCONTEXTMENU 104 +#define IDD_WNDGENERAL 104 +#define ID_VIEW_DESKTOPWINDOWS 105 +#define IDD_WNDSTYLES 105 +#define IDD_WNDCLASS 106 +#define IDD_WNDGENERAL1 106 +#define IDC_LIST 1001 +#define IDC_REFRESH 1002 +#define IDC_TEXT 1009 +#define IDC_RECTANGLE 1010 +#define IDC_NORMALRECTANGLE 1011 +#define IDC_CLIENTRECTANGLE 1012 +#define IDC_THREAD 1016 +#define IDC_STYLESLIST 1017 +#define IDC_STYLES 1018 +#define IDC_EXTENDEDSTYLES 1019 +#define IDC_EXTENDEDSTYLESLIST 1020 +#define IDC_INSTANCEHANDLE 1021 +#define IDC_MENUHANDLE 1022 +#define IDC_WINDOWPROC 1023 +#define IDC_WINDOWPROC2 1024 +#define IDC_DIALOGPROC 1024 +#define IDC_USERDATA 1025 +#define IDC_NAME 1026 +#define IDC_ATOM 1028 +#define IDC_CURSORHANDLE 1029 +#define IDC_ICONHANDLE 1030 +#define IDC_ICONHANDLE2 1031 +#define IDC_SMALLICONHANDLE 1031 +#define IDC_BACKGROUNDBRUSH 1032 +#define IDC_MENUNAME 1033 +#define IDC_UNICODE 1034 +#define IDC_CTRLID 1035 +#define IDC_SEARCHEDIT 1035 +#define ID_WINDOW_GOTOTHREAD 40001 +#define ID_WINDOW_COPY 40002 +#define ID_WINDOW_PROPERTIES 40003 +#define ID_WINDOW_BRINGTOFRONT 40004 +#define ID_WINDOW_RESTORE 40005 +#define ID_WINDOW_MINIMIZE 40006 +#define ID_WINDOW_MAXIMIZE 40007 +#define ID_WINDOW_CLOSE 40008 +#define ID_WINDOW_SHOW 40009 +#define ID_WINDOW_HIGHLIGHT 40010 +#define ID_WINDOW_SHOWHIDE 40011 +#define ID_WINDOW_ENABLE 40012 +#define ID_WINDOW_ENABLEDISABLE 40013 +#define ID_WINDOW_ALWAYSONTOP 40014 +#define ID_WINDOW_OPACITY 40015 +#define ID_OPACITY_10 40016 +#define ID_OPACITY_20 40017 +#define ID_OPACITY_30 40018 +#define ID_OPACITY_40 40019 +#define ID_OPACITY_50 40020 +#define ID_OPACITY_60 40021 +#define ID_OPACITY_70 40022 +#define ID_OPACITY_80 40023 +#define ID_OPACITY_90 40024 +#define ID_OPACITY_OPAQUE 40025 +#define ID_WINDOW_VISIBLE 40026 +#define ID_WINDOW_ENABLED 40027 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 108 +#define _APS_NEXT_COMMAND_VALUE 40028 +#define _APS_NEXT_CONTROL_VALUE 1036 +#define _APS_NEXT_SYMED_VALUE 106 +#endif +#endif diff --git a/plugins/WindowExplorer/utils.c b/plugins/WindowExplorer/utils.c index d9b6cfb5dfdb..55baeb6161c1 100644 --- a/plugins/WindowExplorer/utils.c +++ b/plugins/WindowExplorer/utils.c @@ -1,104 +1,104 @@ -/* - * Process Hacker Window Explorer - - * utility functions - * - * Copyright (C) 2011 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include "wndexp.h" - -// WARNING: No functions from ProcessHacker.exe should be used in this file! - -PVOID WeGetProcedureAddress( - _In_ PSTR Name - ) -{ - static PVOID imageBase = NULL; - - if (!imageBase) - imageBase = GetModuleHandle(L"ProcessHacker.exe"); - - return (PVOID)GetProcAddress(imageBase, Name); -} - -VOID WeFormatLocalObjectName( - _In_ PWSTR OriginalName, - _Inout_updates_(256) PWCHAR Buffer, - _Out_ PUNICODE_STRING ObjectName - ) -{ - SIZE_T length; - SIZE_T originalNameLength; - - // Sessions other than session 0 require SeCreateGlobalPrivilege. - if (NtCurrentPeb()->SessionId != 0) - { - memcpy(Buffer, L"\\Sessions\\", 10 * sizeof(WCHAR)); - _ultow(NtCurrentPeb()->SessionId, Buffer + 10, 10); - length = wcslen(Buffer); - originalNameLength = wcslen(OriginalName); - memcpy(Buffer + length, OriginalName, (originalNameLength + 1) * sizeof(WCHAR)); - length += originalNameLength; - - ObjectName->Buffer = Buffer; - ObjectName->MaximumLength = (ObjectName->Length = (USHORT)(length * sizeof(WCHAR))) + sizeof(WCHAR); - } - else - { - RtlInitUnicodeString(ObjectName, OriginalName); - } -} - -VOID WeInvertWindowBorder( - _In_ HWND hWnd - ) -{ - RECT rect; - HDC hdc; - - GetWindowRect(hWnd, &rect); - hdc = GetWindowDC(hWnd); - - if (hdc) - { - ULONG penWidth = GetSystemMetrics(SM_CXBORDER) * 3; - INT oldDc; - HPEN pen; - HBRUSH brush; - - oldDc = SaveDC(hdc); - - // Get an inversion effect. - SetROP2(hdc, R2_NOT); - - pen = CreatePen(PS_INSIDEFRAME, penWidth, RGB(0x00, 0x00, 0x00)); - SelectObject(hdc, pen); - - brush = GetStockObject(NULL_BRUSH); - SelectObject(hdc, brush); - - // Draw the rectangle. - Rectangle(hdc, 0, 0, rect.right - rect.left, rect.bottom - rect.top); - - // Cleanup. - DeleteObject(pen); - - RestoreDC(hdc, oldDc); - ReleaseDC(hWnd, hdc); - } -} +/* + * Process Hacker Window Explorer - + * utility functions + * + * Copyright (C) 2011 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include "wndexp.h" + +// WARNING: No functions from ProcessHacker.exe should be used in this file! + +PVOID WeGetProcedureAddress( + _In_ PSTR Name + ) +{ + static PVOID imageBase = NULL; + + if (!imageBase) + imageBase = GetModuleHandle(L"ProcessHacker.exe"); + + return (PVOID)GetProcAddress(imageBase, Name); +} + +VOID WeFormatLocalObjectName( + _In_ PWSTR OriginalName, + _Inout_updates_(256) PWCHAR Buffer, + _Out_ PUNICODE_STRING ObjectName + ) +{ + SIZE_T length; + SIZE_T originalNameLength; + + // Sessions other than session 0 require SeCreateGlobalPrivilege. + if (NtCurrentPeb()->SessionId != 0) + { + memcpy(Buffer, L"\\Sessions\\", 10 * sizeof(WCHAR)); + _ultow(NtCurrentPeb()->SessionId, Buffer + 10, 10); + length = wcslen(Buffer); + originalNameLength = wcslen(OriginalName); + memcpy(Buffer + length, OriginalName, (originalNameLength + 1) * sizeof(WCHAR)); + length += originalNameLength; + + ObjectName->Buffer = Buffer; + ObjectName->MaximumLength = (ObjectName->Length = (USHORT)(length * sizeof(WCHAR))) + sizeof(WCHAR); + } + else + { + RtlInitUnicodeString(ObjectName, OriginalName); + } +} + +VOID WeInvertWindowBorder( + _In_ HWND hWnd + ) +{ + RECT rect; + HDC hdc; + + GetWindowRect(hWnd, &rect); + hdc = GetWindowDC(hWnd); + + if (hdc) + { + ULONG penWidth = GetSystemMetrics(SM_CXBORDER) * 3; + INT oldDc; + HPEN pen; + HBRUSH brush; + + oldDc = SaveDC(hdc); + + // Get an inversion effect. + SetROP2(hdc, R2_NOT); + + pen = CreatePen(PS_INSIDEFRAME, penWidth, RGB(0x00, 0x00, 0x00)); + SelectObject(hdc, pen); + + brush = GetStockObject(NULL_BRUSH); + SelectObject(hdc, brush); + + // Draw the rectangle. + Rectangle(hdc, 0, 0, rect.right - rect.left, rect.bottom - rect.top); + + // Cleanup. + DeleteObject(pen); + + RestoreDC(hdc, oldDc); + ReleaseDC(hWnd, hdc); + } +} diff --git a/plugins/WindowExplorer/wnddlg.c b/plugins/WindowExplorer/wnddlg.c index 189d52ea3ea9..baa2117ac900 100644 --- a/plugins/WindowExplorer/wnddlg.c +++ b/plugins/WindowExplorer/wnddlg.c @@ -1,1193 +1,1193 @@ -/* - * Process Hacker Window Explorer - - * window tree dialog - * - * Copyright (C) 2016 dmex - * Copyright (C) 2011 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include "wndexp.h" -#include "resource.h" -#include -#include - -typedef struct _WINDOWS_CONTEXT -{ - HWND TreeNewHandle; - HWND SearchBoxHandle; - WE_WINDOW_TREE_CONTEXT TreeContext; - WE_WINDOW_SELECTOR Selector; - - PH_LAYOUT_MANAGER LayoutManager; - - HWND HighlightingWindow; - ULONG HighlightingWindowCount; -} WINDOWS_CONTEXT, *PWINDOWS_CONTEXT; - -VOID WepShowWindowsDialogCallback( - _In_ PVOID Parameter - ); - -INT_PTR CALLBACK WepWindowsDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -INT_PTR CALLBACK WepWindowsPageProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -VOID WeShowWindowsDialog( - _In_ HWND ParentWindowHandle, - _In_ PWE_WINDOW_SELECTOR Selector - ) -{ - PWINDOWS_CONTEXT context; - - context = PhAllocate(sizeof(WINDOWS_CONTEXT)); - memset(context, 0, sizeof(WINDOWS_CONTEXT)); - memcpy(&context->Selector, Selector, sizeof(WE_WINDOW_SELECTOR)); - - ProcessHacker_Invoke(WE_PhMainWndHandle, WepShowWindowsDialogCallback, context); -} - -VOID WeShowWindowsPropPage( - _In_ PPH_PLUGIN_PROCESS_PROPCONTEXT Context, - _In_ PWE_WINDOW_SELECTOR Selector - ) -{ - PWINDOWS_CONTEXT context; - - context = PhAllocate(sizeof(WINDOWS_CONTEXT)); - memset(context, 0, sizeof(WINDOWS_CONTEXT)); - memcpy(&context->Selector, Selector, sizeof(WE_WINDOW_SELECTOR)); - - PhAddProcessPropPage( - Context->PropContext, - PhCreateProcessPropPageContextEx(PluginInstance->DllBase, MAKEINTRESOURCE(IDD_WNDLIST), WepWindowsPageProc, context) - ); -} - -VOID WepShowWindowsDialogCallback( - _In_ PVOID Parameter - ) -{ - HWND hwnd; - PWINDOWS_CONTEXT context = Parameter; - - hwnd = CreateDialogParam( - PluginInstance->DllBase, - MAKEINTRESOURCE(IDD_WNDLIST), - NULL, - WepWindowsDlgProc, - (LPARAM)context - ); - ShowWindow(hwnd, SW_SHOW); -} - -VOID WepDeleteWindowSelector( - _In_ PWE_WINDOW_SELECTOR Selector - ) -{ - switch (Selector->Type) - { - case WeWindowSelectorDesktop: - PhDereferenceObject(Selector->Desktop.DesktopName); - break; - } -} - -VOID WepFillWindowInfo( - _In_ PWE_WINDOW_NODE Node - ) -{ - HWND hwnd; - ULONG threadId; - ULONG processId; - - hwnd = Node->WindowHandle; - - GetClassName(hwnd, Node->WindowClass, sizeof(Node->WindowClass) / sizeof(WCHAR)); - Node->WindowText = PhGetWindowText(hwnd); - - if (!Node->WindowText) - Node->WindowText = PhReferenceEmptyString(); - - threadId = GetWindowThreadProcessId(hwnd, &processId); - Node->ClientId.UniqueProcess = UlongToHandle(processId); - Node->ClientId.UniqueThread = UlongToHandle(threadId); - - Node->WindowVisible = !!IsWindowVisible(hwnd); - Node->HasChildren = !!FindWindowEx(hwnd, NULL, NULL, NULL); -} - -PWE_WINDOW_NODE WepAddChildWindowNode( - _In_ PWE_WINDOW_TREE_CONTEXT Context, - _In_opt_ PWE_WINDOW_NODE ParentNode, - _In_ HWND hwnd - ) -{ - PWE_WINDOW_NODE childNode; - - childNode = WeAddWindowNode(Context); - childNode->WindowHandle = hwnd; - - WepFillWindowInfo(childNode); - - if (ParentNode) - { - // This is a child node. - childNode->Node.Expanded = TRUE; - childNode->Parent = ParentNode; - - PhAddItemList(ParentNode->Children, childNode); - } - else - { - // This is a root node. - childNode->Node.Expanded = TRUE; - - PhAddItemList(Context->NodeRootList, childNode); - } - - return childNode; -} - -VOID WepAddChildWindows( - _In_ PWINDOWS_CONTEXT Context, - _In_opt_ PWE_WINDOW_NODE ParentNode, - _In_ HWND hwnd, - _In_opt_ HANDLE FilterProcessId, - _In_opt_ HANDLE FilterThreadId - ) -{ - HWND childWindow = NULL; - ULONG i = 0; - - // We use FindWindowEx because EnumWindows doesn't return Metro app windows. - // Set a reasonable limit to prevent infinite loops. - while (i < 0x800 && (childWindow = FindWindowEx(hwnd, childWindow, NULL, NULL))) - { - ULONG processId; - ULONG threadId; - - threadId = GetWindowThreadProcessId(childWindow, &processId); - - if ( - (!FilterProcessId || UlongToHandle(processId) == FilterProcessId) && - (!FilterThreadId || UlongToHandle(threadId) == FilterThreadId) - ) - { - PWE_WINDOW_NODE childNode = WepAddChildWindowNode(&Context->TreeContext, ParentNode, childWindow); - - if (childNode->HasChildren) - { - WepAddChildWindows(Context, childNode, childWindow, NULL, NULL); - } - } - - i++; - } -} - -BOOL CALLBACK WepEnumDesktopWindowsProc( - _In_ HWND hwnd, - _In_ LPARAM lParam - ) -{ - PWINDOWS_CONTEXT context = (PWINDOWS_CONTEXT)lParam; - - WepAddChildWindowNode(&context->TreeContext, NULL, hwnd); - - return TRUE; -} - -VOID WepAddDesktopWindows( - _In_ PWINDOWS_CONTEXT Context, - _In_ PWSTR DesktopName - ) -{ - HDESK desktopHandle; - - if (desktopHandle = OpenDesktop(DesktopName, 0, FALSE, DESKTOP_ENUMERATE)) - { - EnumDesktopWindows(desktopHandle, WepEnumDesktopWindowsProc, (LPARAM)Context); - CloseDesktop(desktopHandle); - } -} - -VOID WepRefreshWindows( - _In_ PWINDOWS_CONTEXT Context - ) -{ - TreeNew_SetRedraw(Context->TreeNewHandle, FALSE); - WeClearWindowTree(&Context->TreeContext); - - switch (Context->Selector.Type) - { - case WeWindowSelectorAll: - { - PWE_WINDOW_NODE desktopNode; - - desktopNode = WeAddWindowNode(&Context->TreeContext); - desktopNode->WindowHandle = GetDesktopWindow(); - WepFillWindowInfo(desktopNode); - - PhAddItemList(Context->TreeContext.NodeRootList, desktopNode); - - WepAddChildWindows(Context, desktopNode, desktopNode->WindowHandle, NULL, NULL); - - desktopNode->HasChildren = TRUE; - } - break; - case WeWindowSelectorThread: - { - WepAddChildWindows(Context, NULL, GetDesktopWindow(), NULL, Context->Selector.Thread.ThreadId); - } - break; - case WeWindowSelectorProcess: - { - WepAddChildWindows(Context, NULL, GetDesktopWindow(), Context->Selector.Process.ProcessId, NULL); - } - break; - case WeWindowSelectorDesktop: - { - WepAddDesktopWindows(Context, Context->Selector.Desktop.DesktopName->Buffer); - } - break; - } - - TreeNew_NodesStructured(Context->TreeNewHandle); - TreeNew_SetRedraw(Context->TreeNewHandle, TRUE); -} - -PPH_STRING WepGetWindowTitleForSelector( - _In_ PWE_WINDOW_SELECTOR Selector - ) -{ - switch (Selector->Type) - { - case WeWindowSelectorAll: - { - return PhCreateString(L"Windows - All"); - } - break; - case WeWindowSelectorThread: - { - return PhFormatString(L"Windows - Thread %lu", HandleToUlong(Selector->Thread.ThreadId)); - } - break; - case WeWindowSelectorProcess: - { - CLIENT_ID clientId; - - clientId.UniqueProcess = Selector->Process.ProcessId; - clientId.UniqueThread = NULL; - - return PhConcatStrings2(L"Windows - ", PH_AUTO_T(PH_STRING, PhGetClientIdName(&clientId))->Buffer); - } - break; - case WeWindowSelectorDesktop: - { - return PhFormatString(L"Windows - Desktop \"%s\"", Selector->Desktop.DesktopName->Buffer); - } - break; - default: - return PhCreateString(L"Windows"); - } -} - -INT_PTR CALLBACK WepWindowsDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - PWINDOWS_CONTEXT context; - - if (uMsg == WM_INITDIALOG) - { - context = (PWINDOWS_CONTEXT)lParam; - SetProp(hwndDlg, L"Context", (HANDLE)context); - } - else - { - context = (PWINDOWS_CONTEXT)GetProp(hwndDlg, L"Context"); - - if (uMsg == WM_DESTROY) - RemoveProp(hwndDlg, L"Context"); - } - - if (!context) - return FALSE; - - switch (uMsg) - { - case WM_INITDIALOG: - { - PH_RECTANGLE windowRectangle; - - context->TreeNewHandle = GetDlgItem(hwndDlg, IDC_LIST); - context->SearchBoxHandle = GetDlgItem(hwndDlg, IDC_SEARCHEDIT); - - SetWindowText(hwndDlg, PH_AUTO_T(PH_STRING, WepGetWindowTitleForSelector(&context->Selector))->Buffer); - - PhCreateSearchControl(hwndDlg, context->SearchBoxHandle, L"Search Windows (Ctrl+K)"); - - WeInitializeWindowTree(hwndDlg, context->TreeNewHandle, &context->TreeContext); - - PhRegisterDialog(hwndDlg); - - PhInitializeLayoutManager(&context->LayoutManager, hwndDlg); - PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_SEARCHEDIT), NULL, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); - PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_LIST), NULL, PH_ANCHOR_ALL); - - // Set up the window position and size. - windowRectangle.Position = PhGetIntegerPairSetting(SETTING_NAME_WINDOWS_WINDOW_POSITION); - windowRectangle.Size = PhGetScalableIntegerPairSetting(SETTING_NAME_WINDOWS_WINDOW_SIZE, TRUE).Pair; - PhAdjustRectangleToWorkingArea(NULL, &windowRectangle); - - MoveWindow(hwndDlg, windowRectangle.Left, windowRectangle.Top, windowRectangle.Width, windowRectangle.Height, FALSE); - - // Implement cascading by saving an offsetted rectangle. - windowRectangle.Left += 20; - windowRectangle.Top += 20; - PhSetIntegerPairSetting(SETTING_NAME_WINDOWS_WINDOW_POSITION, windowRectangle.Position); - - WepRefreshWindows(context); - - SendMessage(GetParent(hwndDlg), WM_NEXTDLGCTL, (WPARAM)GetDlgItem(GetParent(hwndDlg), IDCANCEL), TRUE); - } - break; - case WM_DESTROY: - { - PhSaveWindowPlacementToSetting(SETTING_NAME_WINDOWS_WINDOW_POSITION, SETTING_NAME_WINDOWS_WINDOW_SIZE, hwndDlg); - - PhDeleteLayoutManager(&context->LayoutManager); - - PhUnregisterDialog(hwndDlg); - - WeDeleteWindowTree(&context->TreeContext); - WepDeleteWindowSelector(&context->Selector); - PhFree(context); - } - break; - case WM_COMMAND: - { - switch (GET_WM_COMMAND_CMD(wParam, lParam)) - { - case EN_CHANGE: - { - PPH_STRING newSearchboxText; - - if (GET_WM_COMMAND_HWND(wParam, lParam) != context->SearchBoxHandle) - break; - - newSearchboxText = PH_AUTO(PhGetWindowText(context->SearchBoxHandle)); - - if (!PhEqualString(context->TreeContext.SearchboxText, newSearchboxText, FALSE)) - { - PhSwapReference(&context->TreeContext.SearchboxText, newSearchboxText); - - if (!PhIsNullOrEmptyString(context->TreeContext.SearchboxText)) - WeExpandAllWindowNodes(&context->TreeContext, TRUE); - - PhApplyTreeNewFilters(&context->TreeContext.FilterSupport); - - TreeNew_NodesStructured(context->TreeNewHandle); - // PhInvokeCallback(&SearchChangedEvent, SearchboxText); - } - } - break; - } - - switch (LOWORD(wParam)) - { - case IDCANCEL: - DestroyWindow(hwndDlg); - break; - case IDC_REFRESH: - WepRefreshWindows(context); - break; - case ID_SHOWCONTEXTMENU: - { - POINT point; - PWE_WINDOW_NODE *windows; - ULONG numberOfWindows; - PPH_EMENU menu; - - point.x = (SHORT)LOWORD(lParam); - point.y = (SHORT)HIWORD(lParam); - - WeGetSelectedWindowNodes( - &context->TreeContext, - &windows, - &numberOfWindows - ); - - if (numberOfWindows != 0) - { - menu = PhCreateEMenu(); - PhLoadResourceEMenuItem(menu, PluginInstance->DllBase, MAKEINTRESOURCE(IDR_WINDOW), 0); - PhSetFlagsEMenuItem(menu, ID_WINDOW_PROPERTIES, PH_EMENU_DEFAULT, PH_EMENU_DEFAULT); - - if (numberOfWindows == 1) - { - WINDOWPLACEMENT placement = { sizeof(placement) }; - BYTE alpha; - ULONG flags; - ULONG i; - ULONG id; - - // State - - GetWindowPlacement(windows[0]->WindowHandle, &placement); - - if (placement.showCmd == SW_MINIMIZE) - PhSetFlagsEMenuItem(menu, ID_WINDOW_MINIMIZE, PH_EMENU_DISABLED, PH_EMENU_DISABLED); - else if (placement.showCmd == SW_MAXIMIZE) - PhSetFlagsEMenuItem(menu, ID_WINDOW_MAXIMIZE, PH_EMENU_DISABLED, PH_EMENU_DISABLED); - else if (placement.showCmd == SW_NORMAL) - PhSetFlagsEMenuItem(menu, ID_WINDOW_RESTORE, PH_EMENU_DISABLED, PH_EMENU_DISABLED); - - // Visible - - PhSetFlagsEMenuItem(menu, ID_WINDOW_VISIBLE, PH_EMENU_CHECKED, - (GetWindowLong(windows[0]->WindowHandle, GWL_STYLE) & WS_VISIBLE) ? PH_EMENU_CHECKED : 0); - - // Enabled - - PhSetFlagsEMenuItem(menu, ID_WINDOW_ENABLED, PH_EMENU_CHECKED, - !(GetWindowLong(windows[0]->WindowHandle, GWL_STYLE) & WS_DISABLED) ? PH_EMENU_CHECKED : 0); - - // Always on Top - - PhSetFlagsEMenuItem(menu, ID_WINDOW_ALWAYSONTOP, PH_EMENU_CHECKED, - (GetWindowLong(windows[0]->WindowHandle, GWL_EXSTYLE) & WS_EX_TOPMOST) ? PH_EMENU_CHECKED : 0); - - // Opacity - - if (GetLayeredWindowAttributes(windows[0]->WindowHandle, NULL, &alpha, &flags)) - { - if (!(flags & LWA_ALPHA)) - alpha = 255; - } - else - { - alpha = 255; - } - - if (alpha == 255) - { - id = ID_OPACITY_OPAQUE; - } - else - { - id = 0; - - // Due to integer division, we cannot use simple arithmetic to calculate which menu item to check. - for (i = 0; i < 10; i++) - { - if (alpha == (BYTE)(255 * (i + 1) / 10)) - { - id = ID_OPACITY_10 + i; - break; - } - } - } - - if (id != 0) - { - PhSetFlagsEMenuItem(menu, id, PH_EMENU_CHECKED | PH_EMENU_RADIOCHECK, - PH_EMENU_CHECKED | PH_EMENU_RADIOCHECK); - } - } - else - { - PhSetFlagsAllEMenuItems(menu, PH_EMENU_DISABLED, PH_EMENU_DISABLED); - PhSetFlagsEMenuItem(menu, ID_WINDOW_COPY, PH_EMENU_DISABLED, 0); - } - - PhShowEMenu(menu, hwndDlg, PH_EMENU_SHOW_SEND_COMMAND | PH_EMENU_SHOW_LEFTRIGHT, PH_ALIGN_LEFT | PH_ALIGN_TOP, point.x, point.y); - PhDestroyEMenu(menu); - } - } - break; - case ID_WINDOW_BRINGTOFRONT: - { - PWE_WINDOW_NODE selectedNode; - - if (selectedNode = WeGetSelectedWindowNode(&context->TreeContext)) - { - WINDOWPLACEMENT placement = { sizeof(placement) }; - - GetWindowPlacement(selectedNode->WindowHandle, &placement); - - if (placement.showCmd == SW_MINIMIZE) - ShowWindowAsync(selectedNode->WindowHandle, SW_RESTORE); - else - SetForegroundWindow(selectedNode->WindowHandle); - } - } - break; - case ID_WINDOW_RESTORE: - { - PWE_WINDOW_NODE selectedNode; - - if (selectedNode = WeGetSelectedWindowNode(&context->TreeContext)) - { - ShowWindowAsync(selectedNode->WindowHandle, SW_RESTORE); - } - } - break; - case ID_WINDOW_MINIMIZE: - { - PWE_WINDOW_NODE selectedNode; - - if (selectedNode = WeGetSelectedWindowNode(&context->TreeContext)) - { - ShowWindowAsync(selectedNode->WindowHandle, SW_MINIMIZE); - } - } - break; - case ID_WINDOW_MAXIMIZE: - { - PWE_WINDOW_NODE selectedNode; - - if (selectedNode = WeGetSelectedWindowNode(&context->TreeContext)) - { - ShowWindowAsync(selectedNode->WindowHandle, SW_MAXIMIZE); - } - } - break; - case ID_WINDOW_CLOSE: - { - PWE_WINDOW_NODE selectedNode; - - if (selectedNode = WeGetSelectedWindowNode(&context->TreeContext)) - { - PostMessage(selectedNode->WindowHandle, WM_CLOSE, 0, 0); - } - } - break; - case ID_WINDOW_VISIBLE: - { - PWE_WINDOW_NODE selectedNode; - - if (selectedNode = WeGetSelectedWindowNode(&context->TreeContext)) - { - if (IsWindowVisible(selectedNode->WindowHandle)) - { - selectedNode->WindowVisible = FALSE; - ShowWindowAsync(selectedNode->WindowHandle, SW_HIDE); - } - else - { - selectedNode->WindowVisible = TRUE; - ShowWindowAsync(selectedNode->WindowHandle, SW_SHOW); - } - - PhInvalidateTreeNewNode(&selectedNode->Node, TN_CACHE_COLOR); - TreeNew_InvalidateNode(context->TreeNewHandle, &selectedNode->Node); - } - } - break; - case ID_WINDOW_ENABLED: - { - PWE_WINDOW_NODE selectedNode; - - if (selectedNode = WeGetSelectedWindowNode(&context->TreeContext)) - { - EnableWindow(selectedNode->WindowHandle, !IsWindowEnabled(selectedNode->WindowHandle)); - } - } - break; - case ID_WINDOW_ALWAYSONTOP: - { - PWE_WINDOW_NODE selectedNode; - - if (selectedNode = WeGetSelectedWindowNode(&context->TreeContext)) - { - LOGICAL topMost; - - topMost = GetWindowLong(selectedNode->WindowHandle, GWL_EXSTYLE) & WS_EX_TOPMOST; - SetWindowPos(selectedNode->WindowHandle, topMost ? HWND_NOTOPMOST : HWND_TOPMOST, - 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE); - } - } - break; - case ID_OPACITY_10: - case ID_OPACITY_20: - case ID_OPACITY_30: - case ID_OPACITY_40: - case ID_OPACITY_50: - case ID_OPACITY_60: - case ID_OPACITY_70: - case ID_OPACITY_80: - case ID_OPACITY_90: - case ID_OPACITY_OPAQUE: - { - PWE_WINDOW_NODE selectedNode; - - if (selectedNode = WeGetSelectedWindowNode(&context->TreeContext)) - { - ULONG opacity; - - opacity = ((ULONG)LOWORD(wParam) - ID_OPACITY_10) + 1; - - if (opacity == 10) - { - // Remove the WS_EX_LAYERED bit since it is not needed. - PhSetWindowExStyle(selectedNode->WindowHandle, WS_EX_LAYERED, 0); - RedrawWindow(selectedNode->WindowHandle, NULL, NULL, RDW_ERASE | RDW_INVALIDATE | RDW_FRAME | RDW_ALLCHILDREN); - } - else - { - // Add the WS_EX_LAYERED bit so opacity will work. - PhSetWindowExStyle(selectedNode->WindowHandle, WS_EX_LAYERED, WS_EX_LAYERED); - SetLayeredWindowAttributes(selectedNode->WindowHandle, 0, (BYTE)(255 * opacity / 10), LWA_ALPHA); - } - } - } - break; - case ID_WINDOW_HIGHLIGHT: - { - PWE_WINDOW_NODE selectedNode; - - if (selectedNode = WeGetSelectedWindowNode(&context->TreeContext)) - { - if (context->HighlightingWindow) - { - if (context->HighlightingWindowCount & 1) - WeInvertWindowBorder(context->HighlightingWindow); - } - - context->HighlightingWindow = selectedNode->WindowHandle; - context->HighlightingWindowCount = 10; - SetTimer(hwndDlg, 9, 100, NULL); - } - } - break; - case ID_WINDOW_GOTOTHREAD: - { - PWE_WINDOW_NODE selectedNode; - PPH_PROCESS_ITEM processItem; - PPH_PROCESS_PROPCONTEXT propContext; - - if (selectedNode = WeGetSelectedWindowNode(&context->TreeContext)) - { - if (processItem = PhReferenceProcessItem(selectedNode->ClientId.UniqueProcess)) - { - if (propContext = PhCreateProcessPropContext(WE_PhMainWndHandle, processItem)) - { - PhSetSelectThreadIdProcessPropContext(propContext, selectedNode->ClientId.UniqueThread); - PhShowProcessProperties(propContext); - PhDereferenceObject(propContext); - } - - PhDereferenceObject(processItem); - } - else - { - PhShowError(hwndDlg, L"The process does not exist."); - } - } - } - break; - case ID_WINDOW_PROPERTIES: - { - PWE_WINDOW_NODE selectedNode; - - if (selectedNode = WeGetSelectedWindowNode(&context->TreeContext)) - WeShowWindowProperties(hwndDlg, selectedNode->WindowHandle); - } - break; - case ID_WINDOW_COPY: - { - PPH_STRING text; - - text = PhGetTreeNewText(context->TreeNewHandle, 0); - PhSetClipboardString(hwndDlg, &text->sr); - PhDereferenceObject(text); - } - break; - } - } - break; - case WM_TIMER: - { - switch (wParam) - { - case 9: - { - WeInvertWindowBorder(context->HighlightingWindow); - - if (--context->HighlightingWindowCount == 0) - KillTimer(hwndDlg, 9); - } - break; - } - } - break; - case WM_SIZE: - { - PhLayoutManagerLayout(&context->LayoutManager); - } - break; - } - - return FALSE; -} - -INT_PTR CALLBACK WepWindowsPageProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - PWINDOWS_CONTEXT context; - LPPROPSHEETPAGE propSheetPage; - PPH_PROCESS_PROPPAGECONTEXT propPageContext; - PPH_PROCESS_ITEM processItem; - - if (PhPropPageDlgProcHeader(hwndDlg, uMsg, lParam, &propSheetPage, &propPageContext, &processItem)) - { - context = propPageContext->Context; - } - else - { - return FALSE; - } - - switch (uMsg) - { - case WM_INITDIALOG: - { - context->TreeNewHandle = GetDlgItem(hwndDlg, IDC_LIST); - context->SearchBoxHandle = GetDlgItem(hwndDlg, IDC_SEARCHEDIT); - - PhCreateSearchControl(hwndDlg, context->SearchBoxHandle, L"Search Windows (Ctrl+K)"); - - WeInitializeWindowTree(hwndDlg, context->TreeNewHandle, &context->TreeContext); - - PhRegisterDialog(hwndDlg); - - PhInitializeLayoutManager(&context->LayoutManager, hwndDlg); - PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_SEARCHEDIT), NULL, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); - PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_LIST), NULL, PH_ANCHOR_ALL); - - WepRefreshWindows(context); - } - break; - case WM_SHOWWINDOW: - { - if (PhBeginPropPageLayout(hwndDlg, propPageContext)) - PhEndPropPageLayout(hwndDlg, propPageContext); - } - break; - case WM_DESTROY: - { - PhDeleteLayoutManager(&context->LayoutManager); - - PhUnregisterDialog(hwndDlg); - - WeDeleteWindowTree(&context->TreeContext); - WepDeleteWindowSelector(&context->Selector); - PhFree(context); - } - break; - case WM_COMMAND: - { - switch (GET_WM_COMMAND_CMD(wParam, lParam)) - { - case EN_CHANGE: - { - PPH_STRING newSearchboxText; - - if (GET_WM_COMMAND_HWND(wParam, lParam) != context->SearchBoxHandle) - break; - - newSearchboxText = PH_AUTO(PhGetWindowText(context->SearchBoxHandle)); - - if (!PhEqualString(context->TreeContext.SearchboxText, newSearchboxText, FALSE)) - { - PhSwapReference(&context->TreeContext.SearchboxText, newSearchboxText); - - if (!PhIsNullOrEmptyString(context->TreeContext.SearchboxText)) - WeExpandAllWindowNodes(&context->TreeContext, TRUE); - - PhApplyTreeNewFilters(&context->TreeContext.FilterSupport); - - TreeNew_NodesStructured(context->TreeNewHandle); - // PhInvokeCallback(&SearchChangedEvent, SearchboxText); - } - } - break; - } - - switch (LOWORD(wParam)) - { - case IDC_REFRESH: - WepRefreshWindows(context); - break; - case ID_SHOWCONTEXTMENU: - { - POINT point; - PWE_WINDOW_NODE *windows; - ULONG numberOfWindows; - PPH_EMENU menu; - - point.x = (SHORT)LOWORD(lParam); - point.y = (SHORT)HIWORD(lParam); - - WeGetSelectedWindowNodes( - &context->TreeContext, - &windows, - &numberOfWindows - ); - - if (numberOfWindows != 0) - { - menu = PhCreateEMenu(); - PhLoadResourceEMenuItem(menu, PluginInstance->DllBase, MAKEINTRESOURCE(IDR_WINDOW), 0); - PhSetFlagsEMenuItem(menu, ID_WINDOW_PROPERTIES, PH_EMENU_DEFAULT, PH_EMENU_DEFAULT); - - if (numberOfWindows == 1) - { - WINDOWPLACEMENT placement = { sizeof(placement) }; - BYTE alpha; - ULONG flags; - ULONG i; - ULONG id; - - // State - - GetWindowPlacement(windows[0]->WindowHandle, &placement); - - if (placement.showCmd == SW_MINIMIZE) - PhSetFlagsEMenuItem(menu, ID_WINDOW_MINIMIZE, PH_EMENU_DISABLED, PH_EMENU_DISABLED); - else if (placement.showCmd == SW_MAXIMIZE) - PhSetFlagsEMenuItem(menu, ID_WINDOW_MAXIMIZE, PH_EMENU_DISABLED, PH_EMENU_DISABLED); - else if (placement.showCmd == SW_NORMAL) - PhSetFlagsEMenuItem(menu, ID_WINDOW_RESTORE, PH_EMENU_DISABLED, PH_EMENU_DISABLED); - - // Visible - - PhSetFlagsEMenuItem(menu, ID_WINDOW_VISIBLE, PH_EMENU_CHECKED, - (GetWindowLong(windows[0]->WindowHandle, GWL_STYLE) & WS_VISIBLE) ? PH_EMENU_CHECKED : 0); - - // Enabled - - PhSetFlagsEMenuItem(menu, ID_WINDOW_ENABLED, PH_EMENU_CHECKED, - !(GetWindowLong(windows[0]->WindowHandle, GWL_STYLE) & WS_DISABLED) ? PH_EMENU_CHECKED : 0); - - // Always on Top - - PhSetFlagsEMenuItem(menu, ID_WINDOW_ALWAYSONTOP, PH_EMENU_CHECKED, - (GetWindowLong(windows[0]->WindowHandle, GWL_EXSTYLE) & WS_EX_TOPMOST) ? PH_EMENU_CHECKED : 0); - - // Opacity - - if (GetLayeredWindowAttributes(windows[0]->WindowHandle, NULL, &alpha, &flags)) - { - if (!(flags & LWA_ALPHA)) - alpha = 255; - } - else - { - alpha = 255; - } - - if (alpha == 255) - { - id = ID_OPACITY_OPAQUE; - } - else - { - id = 0; - - // Due to integer division, we cannot use simple arithmetic to calculate which menu item to check. - for (i = 0; i < 10; i++) - { - if (alpha == (BYTE)(255 * (i + 1) / 10)) - { - id = ID_OPACITY_10 + i; - break; - } - } - } - - if (id != 0) - { - PhSetFlagsEMenuItem(menu, id, PH_EMENU_CHECKED | PH_EMENU_RADIOCHECK, - PH_EMENU_CHECKED | PH_EMENU_RADIOCHECK); - } - } - else - { - PhSetFlagsAllEMenuItems(menu, PH_EMENU_DISABLED, PH_EMENU_DISABLED); - PhSetFlagsEMenuItem(menu, ID_WINDOW_COPY, PH_EMENU_DISABLED, 0); - } - - PhShowEMenu(menu, hwndDlg, PH_EMENU_SHOW_SEND_COMMAND | PH_EMENU_SHOW_LEFTRIGHT, PH_ALIGN_LEFT | PH_ALIGN_TOP, point.x, point.y); - PhDestroyEMenu(menu); - } - } - break; - case ID_WINDOW_BRINGTOFRONT: - { - PWE_WINDOW_NODE selectedNode; - - if (selectedNode = WeGetSelectedWindowNode(&context->TreeContext)) - { - WINDOWPLACEMENT placement = { sizeof(placement) }; - - GetWindowPlacement(selectedNode->WindowHandle, &placement); - - if (placement.showCmd == SW_MINIMIZE) - ShowWindowAsync(selectedNode->WindowHandle, SW_RESTORE); - else - SetForegroundWindow(selectedNode->WindowHandle); - } - } - break; - case ID_WINDOW_RESTORE: - { - PWE_WINDOW_NODE selectedNode; - - if (selectedNode = WeGetSelectedWindowNode(&context->TreeContext)) - { - ShowWindowAsync(selectedNode->WindowHandle, SW_RESTORE); - } - } - break; - case ID_WINDOW_MINIMIZE: - { - PWE_WINDOW_NODE selectedNode; - - if (selectedNode = WeGetSelectedWindowNode(&context->TreeContext)) - { - ShowWindowAsync(selectedNode->WindowHandle, SW_MINIMIZE); - } - } - break; - case ID_WINDOW_MAXIMIZE: - { - PWE_WINDOW_NODE selectedNode; - - if (selectedNode = WeGetSelectedWindowNode(&context->TreeContext)) - { - ShowWindowAsync(selectedNode->WindowHandle, SW_MAXIMIZE); - } - } - break; - case ID_WINDOW_CLOSE: - { - PWE_WINDOW_NODE selectedNode; - - if (selectedNode = WeGetSelectedWindowNode(&context->TreeContext)) - { - PostMessage(selectedNode->WindowHandle, WM_CLOSE, 0, 0); - } - } - break; - case ID_WINDOW_VISIBLE: - { - PWE_WINDOW_NODE selectedNode; - - if (selectedNode = WeGetSelectedWindowNode(&context->TreeContext)) - { - if (IsWindowVisible(selectedNode->WindowHandle)) - { - selectedNode->WindowVisible = FALSE; - ShowWindowAsync(selectedNode->WindowHandle, SW_HIDE); - } - else - { - selectedNode->WindowVisible = TRUE; - ShowWindowAsync(selectedNode->WindowHandle, SW_SHOW); - } - - PhInvalidateTreeNewNode(&selectedNode->Node, TN_CACHE_COLOR); - TreeNew_InvalidateNode(context->TreeNewHandle, &selectedNode->Node); - } - } - break; - case ID_WINDOW_ENABLED: - { - PWE_WINDOW_NODE selectedNode; - - if (selectedNode = WeGetSelectedWindowNode(&context->TreeContext)) - { - EnableWindow(selectedNode->WindowHandle, !IsWindowEnabled(selectedNode->WindowHandle)); - } - } - break; - case ID_WINDOW_ALWAYSONTOP: - { - PWE_WINDOW_NODE selectedNode; - - if (selectedNode = WeGetSelectedWindowNode(&context->TreeContext)) - { - LOGICAL topMost; - - topMost = GetWindowLong(selectedNode->WindowHandle, GWL_EXSTYLE) & WS_EX_TOPMOST; - SetWindowPos(selectedNode->WindowHandle, topMost ? HWND_NOTOPMOST : HWND_TOPMOST, - 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE); - } - } - break; - case ID_OPACITY_10: - case ID_OPACITY_20: - case ID_OPACITY_30: - case ID_OPACITY_40: - case ID_OPACITY_50: - case ID_OPACITY_60: - case ID_OPACITY_70: - case ID_OPACITY_80: - case ID_OPACITY_90: - case ID_OPACITY_OPAQUE: - { - PWE_WINDOW_NODE selectedNode; - - if (selectedNode = WeGetSelectedWindowNode(&context->TreeContext)) - { - ULONG opacity; - - opacity = ((ULONG)LOWORD(wParam) - ID_OPACITY_10) + 1; - - if (opacity == 10) - { - // Remove the WS_EX_LAYERED bit since it is not needed. - PhSetWindowExStyle(selectedNode->WindowHandle, WS_EX_LAYERED, 0); - RedrawWindow(selectedNode->WindowHandle, NULL, NULL, RDW_ERASE | RDW_INVALIDATE | RDW_FRAME | RDW_ALLCHILDREN); - } - else - { - // Add the WS_EX_LAYERED bit so opacity will work. - PhSetWindowExStyle(selectedNode->WindowHandle, WS_EX_LAYERED, WS_EX_LAYERED); - SetLayeredWindowAttributes(selectedNode->WindowHandle, 0, (BYTE)(255 * opacity / 10), LWA_ALPHA); - } - } - } - break; - case ID_WINDOW_HIGHLIGHT: - { - PWE_WINDOW_NODE selectedNode; - - if (selectedNode = WeGetSelectedWindowNode(&context->TreeContext)) - { - if (context->HighlightingWindow) - { - if (context->HighlightingWindowCount & 1) - WeInvertWindowBorder(context->HighlightingWindow); - } - - context->HighlightingWindow = selectedNode->WindowHandle; - context->HighlightingWindowCount = 10; - SetTimer(hwndDlg, 9, 100, NULL); - } - } - break; - case ID_WINDOW_GOTOTHREAD: - { - PWE_WINDOW_NODE selectedNode; - PPH_PROCESS_ITEM processItem; - PPH_PROCESS_PROPCONTEXT propContext; - - if (selectedNode = WeGetSelectedWindowNode(&context->TreeContext)) - { - if (processItem = PhReferenceProcessItem(selectedNode->ClientId.UniqueProcess)) - { - if (propContext = PhCreateProcessPropContext(WE_PhMainWndHandle, processItem)) - { - PhSetSelectThreadIdProcessPropContext(propContext, selectedNode->ClientId.UniqueThread); - PhShowProcessProperties(propContext); - PhDereferenceObject(propContext); - } - - PhDereferenceObject(processItem); - } - else - { - PhShowError(hwndDlg, L"The process does not exist."); - } - } - } - break; - case ID_WINDOW_PROPERTIES: - { - PWE_WINDOW_NODE selectedNode; - - if (selectedNode = WeGetSelectedWindowNode(&context->TreeContext)) - WeShowWindowProperties(hwndDlg, selectedNode->WindowHandle); - } - break; - case ID_WINDOW_COPY: - { - PPH_STRING text; - - text = PhGetTreeNewText(context->TreeNewHandle, 0); - PhSetClipboardString(hwndDlg, &text->sr); - PhDereferenceObject(text); - } - break; - } - } - break; - case WM_TIMER: - { - switch (wParam) - { - case 9: - { - WeInvertWindowBorder(context->HighlightingWindow); - - if (--context->HighlightingWindowCount == 0) - KillTimer(hwndDlg, 9); - } - break; - } - } - break; - case WM_SIZE: - PhLayoutManagerLayout(&context->LayoutManager); - break; - case WM_NOTIFY: - { - LPNMHDR header = (LPNMHDR)lParam; - - switch (header->code) - { - case PSN_QUERYINITIALFOCUS: - SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, (LPARAM)GetDlgItem(hwndDlg, IDC_REFRESH)); - return TRUE; - } - } - break; - } - - return FALSE; +/* + * Process Hacker Window Explorer - + * window tree dialog + * + * Copyright (C) 2016 dmex + * Copyright (C) 2011 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include "wndexp.h" +#include "resource.h" +#include +#include + +typedef struct _WINDOWS_CONTEXT +{ + HWND TreeNewHandle; + HWND SearchBoxHandle; + WE_WINDOW_TREE_CONTEXT TreeContext; + WE_WINDOW_SELECTOR Selector; + + PH_LAYOUT_MANAGER LayoutManager; + + HWND HighlightingWindow; + ULONG HighlightingWindowCount; +} WINDOWS_CONTEXT, *PWINDOWS_CONTEXT; + +VOID WepShowWindowsDialogCallback( + _In_ PVOID Parameter + ); + +INT_PTR CALLBACK WepWindowsDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +INT_PTR CALLBACK WepWindowsPageProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +VOID WeShowWindowsDialog( + _In_ HWND ParentWindowHandle, + _In_ PWE_WINDOW_SELECTOR Selector + ) +{ + PWINDOWS_CONTEXT context; + + context = PhAllocate(sizeof(WINDOWS_CONTEXT)); + memset(context, 0, sizeof(WINDOWS_CONTEXT)); + memcpy(&context->Selector, Selector, sizeof(WE_WINDOW_SELECTOR)); + + ProcessHacker_Invoke(WE_PhMainWndHandle, WepShowWindowsDialogCallback, context); +} + +VOID WeShowWindowsPropPage( + _In_ PPH_PLUGIN_PROCESS_PROPCONTEXT Context, + _In_ PWE_WINDOW_SELECTOR Selector + ) +{ + PWINDOWS_CONTEXT context; + + context = PhAllocate(sizeof(WINDOWS_CONTEXT)); + memset(context, 0, sizeof(WINDOWS_CONTEXT)); + memcpy(&context->Selector, Selector, sizeof(WE_WINDOW_SELECTOR)); + + PhAddProcessPropPage( + Context->PropContext, + PhCreateProcessPropPageContextEx(PluginInstance->DllBase, MAKEINTRESOURCE(IDD_WNDLIST), WepWindowsPageProc, context) + ); +} + +VOID WepShowWindowsDialogCallback( + _In_ PVOID Parameter + ) +{ + HWND hwnd; + PWINDOWS_CONTEXT context = Parameter; + + hwnd = CreateDialogParam( + PluginInstance->DllBase, + MAKEINTRESOURCE(IDD_WNDLIST), + NULL, + WepWindowsDlgProc, + (LPARAM)context + ); + ShowWindow(hwnd, SW_SHOW); +} + +VOID WepDeleteWindowSelector( + _In_ PWE_WINDOW_SELECTOR Selector + ) +{ + switch (Selector->Type) + { + case WeWindowSelectorDesktop: + PhDereferenceObject(Selector->Desktop.DesktopName); + break; + } +} + +VOID WepFillWindowInfo( + _In_ PWE_WINDOW_NODE Node + ) +{ + HWND hwnd; + ULONG threadId; + ULONG processId; + + hwnd = Node->WindowHandle; + + GetClassName(hwnd, Node->WindowClass, sizeof(Node->WindowClass) / sizeof(WCHAR)); + Node->WindowText = PhGetWindowText(hwnd); + + if (!Node->WindowText) + Node->WindowText = PhReferenceEmptyString(); + + threadId = GetWindowThreadProcessId(hwnd, &processId); + Node->ClientId.UniqueProcess = UlongToHandle(processId); + Node->ClientId.UniqueThread = UlongToHandle(threadId); + + Node->WindowVisible = !!IsWindowVisible(hwnd); + Node->HasChildren = !!FindWindowEx(hwnd, NULL, NULL, NULL); +} + +PWE_WINDOW_NODE WepAddChildWindowNode( + _In_ PWE_WINDOW_TREE_CONTEXT Context, + _In_opt_ PWE_WINDOW_NODE ParentNode, + _In_ HWND hwnd + ) +{ + PWE_WINDOW_NODE childNode; + + childNode = WeAddWindowNode(Context); + childNode->WindowHandle = hwnd; + + WepFillWindowInfo(childNode); + + if (ParentNode) + { + // This is a child node. + childNode->Node.Expanded = TRUE; + childNode->Parent = ParentNode; + + PhAddItemList(ParentNode->Children, childNode); + } + else + { + // This is a root node. + childNode->Node.Expanded = TRUE; + + PhAddItemList(Context->NodeRootList, childNode); + } + + return childNode; +} + +VOID WepAddChildWindows( + _In_ PWINDOWS_CONTEXT Context, + _In_opt_ PWE_WINDOW_NODE ParentNode, + _In_ HWND hwnd, + _In_opt_ HANDLE FilterProcessId, + _In_opt_ HANDLE FilterThreadId + ) +{ + HWND childWindow = NULL; + ULONG i = 0; + + // We use FindWindowEx because EnumWindows doesn't return Metro app windows. + // Set a reasonable limit to prevent infinite loops. + while (i < 0x800 && (childWindow = FindWindowEx(hwnd, childWindow, NULL, NULL))) + { + ULONG processId; + ULONG threadId; + + threadId = GetWindowThreadProcessId(childWindow, &processId); + + if ( + (!FilterProcessId || UlongToHandle(processId) == FilterProcessId) && + (!FilterThreadId || UlongToHandle(threadId) == FilterThreadId) + ) + { + PWE_WINDOW_NODE childNode = WepAddChildWindowNode(&Context->TreeContext, ParentNode, childWindow); + + if (childNode->HasChildren) + { + WepAddChildWindows(Context, childNode, childWindow, NULL, NULL); + } + } + + i++; + } +} + +BOOL CALLBACK WepEnumDesktopWindowsProc( + _In_ HWND hwnd, + _In_ LPARAM lParam + ) +{ + PWINDOWS_CONTEXT context = (PWINDOWS_CONTEXT)lParam; + + WepAddChildWindowNode(&context->TreeContext, NULL, hwnd); + + return TRUE; +} + +VOID WepAddDesktopWindows( + _In_ PWINDOWS_CONTEXT Context, + _In_ PWSTR DesktopName + ) +{ + HDESK desktopHandle; + + if (desktopHandle = OpenDesktop(DesktopName, 0, FALSE, DESKTOP_ENUMERATE)) + { + EnumDesktopWindows(desktopHandle, WepEnumDesktopWindowsProc, (LPARAM)Context); + CloseDesktop(desktopHandle); + } +} + +VOID WepRefreshWindows( + _In_ PWINDOWS_CONTEXT Context + ) +{ + TreeNew_SetRedraw(Context->TreeNewHandle, FALSE); + WeClearWindowTree(&Context->TreeContext); + + switch (Context->Selector.Type) + { + case WeWindowSelectorAll: + { + PWE_WINDOW_NODE desktopNode; + + desktopNode = WeAddWindowNode(&Context->TreeContext); + desktopNode->WindowHandle = GetDesktopWindow(); + WepFillWindowInfo(desktopNode); + + PhAddItemList(Context->TreeContext.NodeRootList, desktopNode); + + WepAddChildWindows(Context, desktopNode, desktopNode->WindowHandle, NULL, NULL); + + desktopNode->HasChildren = TRUE; + } + break; + case WeWindowSelectorThread: + { + WepAddChildWindows(Context, NULL, GetDesktopWindow(), NULL, Context->Selector.Thread.ThreadId); + } + break; + case WeWindowSelectorProcess: + { + WepAddChildWindows(Context, NULL, GetDesktopWindow(), Context->Selector.Process.ProcessId, NULL); + } + break; + case WeWindowSelectorDesktop: + { + WepAddDesktopWindows(Context, Context->Selector.Desktop.DesktopName->Buffer); + } + break; + } + + TreeNew_NodesStructured(Context->TreeNewHandle); + TreeNew_SetRedraw(Context->TreeNewHandle, TRUE); +} + +PPH_STRING WepGetWindowTitleForSelector( + _In_ PWE_WINDOW_SELECTOR Selector + ) +{ + switch (Selector->Type) + { + case WeWindowSelectorAll: + { + return PhCreateString(L"Windows - All"); + } + break; + case WeWindowSelectorThread: + { + return PhFormatString(L"Windows - Thread %lu", HandleToUlong(Selector->Thread.ThreadId)); + } + break; + case WeWindowSelectorProcess: + { + CLIENT_ID clientId; + + clientId.UniqueProcess = Selector->Process.ProcessId; + clientId.UniqueThread = NULL; + + return PhConcatStrings2(L"Windows - ", PH_AUTO_T(PH_STRING, PhGetClientIdName(&clientId))->Buffer); + } + break; + case WeWindowSelectorDesktop: + { + return PhFormatString(L"Windows - Desktop \"%s\"", Selector->Desktop.DesktopName->Buffer); + } + break; + default: + return PhCreateString(L"Windows"); + } +} + +INT_PTR CALLBACK WepWindowsDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + PWINDOWS_CONTEXT context; + + if (uMsg == WM_INITDIALOG) + { + context = (PWINDOWS_CONTEXT)lParam; + SetProp(hwndDlg, L"Context", (HANDLE)context); + } + else + { + context = (PWINDOWS_CONTEXT)GetProp(hwndDlg, L"Context"); + + if (uMsg == WM_DESTROY) + RemoveProp(hwndDlg, L"Context"); + } + + if (!context) + return FALSE; + + switch (uMsg) + { + case WM_INITDIALOG: + { + PH_RECTANGLE windowRectangle; + + context->TreeNewHandle = GetDlgItem(hwndDlg, IDC_LIST); + context->SearchBoxHandle = GetDlgItem(hwndDlg, IDC_SEARCHEDIT); + + SetWindowText(hwndDlg, PH_AUTO_T(PH_STRING, WepGetWindowTitleForSelector(&context->Selector))->Buffer); + + PhCreateSearchControl(hwndDlg, context->SearchBoxHandle, L"Search Windows (Ctrl+K)"); + + WeInitializeWindowTree(hwndDlg, context->TreeNewHandle, &context->TreeContext); + + PhRegisterDialog(hwndDlg); + + PhInitializeLayoutManager(&context->LayoutManager, hwndDlg); + PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_SEARCHEDIT), NULL, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); + PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_LIST), NULL, PH_ANCHOR_ALL); + + // Set up the window position and size. + windowRectangle.Position = PhGetIntegerPairSetting(SETTING_NAME_WINDOWS_WINDOW_POSITION); + windowRectangle.Size = PhGetScalableIntegerPairSetting(SETTING_NAME_WINDOWS_WINDOW_SIZE, TRUE).Pair; + PhAdjustRectangleToWorkingArea(NULL, &windowRectangle); + + MoveWindow(hwndDlg, windowRectangle.Left, windowRectangle.Top, windowRectangle.Width, windowRectangle.Height, FALSE); + + // Implement cascading by saving an offsetted rectangle. + windowRectangle.Left += 20; + windowRectangle.Top += 20; + PhSetIntegerPairSetting(SETTING_NAME_WINDOWS_WINDOW_POSITION, windowRectangle.Position); + + WepRefreshWindows(context); + + SendMessage(GetParent(hwndDlg), WM_NEXTDLGCTL, (WPARAM)GetDlgItem(GetParent(hwndDlg), IDCANCEL), TRUE); + } + break; + case WM_DESTROY: + { + PhSaveWindowPlacementToSetting(SETTING_NAME_WINDOWS_WINDOW_POSITION, SETTING_NAME_WINDOWS_WINDOW_SIZE, hwndDlg); + + PhDeleteLayoutManager(&context->LayoutManager); + + PhUnregisterDialog(hwndDlg); + + WeDeleteWindowTree(&context->TreeContext); + WepDeleteWindowSelector(&context->Selector); + PhFree(context); + } + break; + case WM_COMMAND: + { + switch (GET_WM_COMMAND_CMD(wParam, lParam)) + { + case EN_CHANGE: + { + PPH_STRING newSearchboxText; + + if (GET_WM_COMMAND_HWND(wParam, lParam) != context->SearchBoxHandle) + break; + + newSearchboxText = PH_AUTO(PhGetWindowText(context->SearchBoxHandle)); + + if (!PhEqualString(context->TreeContext.SearchboxText, newSearchboxText, FALSE)) + { + PhSwapReference(&context->TreeContext.SearchboxText, newSearchboxText); + + if (!PhIsNullOrEmptyString(context->TreeContext.SearchboxText)) + WeExpandAllWindowNodes(&context->TreeContext, TRUE); + + PhApplyTreeNewFilters(&context->TreeContext.FilterSupport); + + TreeNew_NodesStructured(context->TreeNewHandle); + // PhInvokeCallback(&SearchChangedEvent, SearchboxText); + } + } + break; + } + + switch (LOWORD(wParam)) + { + case IDCANCEL: + DestroyWindow(hwndDlg); + break; + case IDC_REFRESH: + WepRefreshWindows(context); + break; + case ID_SHOWCONTEXTMENU: + { + POINT point; + PWE_WINDOW_NODE *windows; + ULONG numberOfWindows; + PPH_EMENU menu; + + point.x = (SHORT)LOWORD(lParam); + point.y = (SHORT)HIWORD(lParam); + + WeGetSelectedWindowNodes( + &context->TreeContext, + &windows, + &numberOfWindows + ); + + if (numberOfWindows != 0) + { + menu = PhCreateEMenu(); + PhLoadResourceEMenuItem(menu, PluginInstance->DllBase, MAKEINTRESOURCE(IDR_WINDOW), 0); + PhSetFlagsEMenuItem(menu, ID_WINDOW_PROPERTIES, PH_EMENU_DEFAULT, PH_EMENU_DEFAULT); + + if (numberOfWindows == 1) + { + WINDOWPLACEMENT placement = { sizeof(placement) }; + BYTE alpha; + ULONG flags; + ULONG i; + ULONG id; + + // State + + GetWindowPlacement(windows[0]->WindowHandle, &placement); + + if (placement.showCmd == SW_MINIMIZE) + PhSetFlagsEMenuItem(menu, ID_WINDOW_MINIMIZE, PH_EMENU_DISABLED, PH_EMENU_DISABLED); + else if (placement.showCmd == SW_MAXIMIZE) + PhSetFlagsEMenuItem(menu, ID_WINDOW_MAXIMIZE, PH_EMENU_DISABLED, PH_EMENU_DISABLED); + else if (placement.showCmd == SW_NORMAL) + PhSetFlagsEMenuItem(menu, ID_WINDOW_RESTORE, PH_EMENU_DISABLED, PH_EMENU_DISABLED); + + // Visible + + PhSetFlagsEMenuItem(menu, ID_WINDOW_VISIBLE, PH_EMENU_CHECKED, + (GetWindowLong(windows[0]->WindowHandle, GWL_STYLE) & WS_VISIBLE) ? PH_EMENU_CHECKED : 0); + + // Enabled + + PhSetFlagsEMenuItem(menu, ID_WINDOW_ENABLED, PH_EMENU_CHECKED, + !(GetWindowLong(windows[0]->WindowHandle, GWL_STYLE) & WS_DISABLED) ? PH_EMENU_CHECKED : 0); + + // Always on Top + + PhSetFlagsEMenuItem(menu, ID_WINDOW_ALWAYSONTOP, PH_EMENU_CHECKED, + (GetWindowLong(windows[0]->WindowHandle, GWL_EXSTYLE) & WS_EX_TOPMOST) ? PH_EMENU_CHECKED : 0); + + // Opacity + + if (GetLayeredWindowAttributes(windows[0]->WindowHandle, NULL, &alpha, &flags)) + { + if (!(flags & LWA_ALPHA)) + alpha = 255; + } + else + { + alpha = 255; + } + + if (alpha == 255) + { + id = ID_OPACITY_OPAQUE; + } + else + { + id = 0; + + // Due to integer division, we cannot use simple arithmetic to calculate which menu item to check. + for (i = 0; i < 10; i++) + { + if (alpha == (BYTE)(255 * (i + 1) / 10)) + { + id = ID_OPACITY_10 + i; + break; + } + } + } + + if (id != 0) + { + PhSetFlagsEMenuItem(menu, id, PH_EMENU_CHECKED | PH_EMENU_RADIOCHECK, + PH_EMENU_CHECKED | PH_EMENU_RADIOCHECK); + } + } + else + { + PhSetFlagsAllEMenuItems(menu, PH_EMENU_DISABLED, PH_EMENU_DISABLED); + PhSetFlagsEMenuItem(menu, ID_WINDOW_COPY, PH_EMENU_DISABLED, 0); + } + + PhShowEMenu(menu, hwndDlg, PH_EMENU_SHOW_SEND_COMMAND | PH_EMENU_SHOW_LEFTRIGHT, PH_ALIGN_LEFT | PH_ALIGN_TOP, point.x, point.y); + PhDestroyEMenu(menu); + } + } + break; + case ID_WINDOW_BRINGTOFRONT: + { + PWE_WINDOW_NODE selectedNode; + + if (selectedNode = WeGetSelectedWindowNode(&context->TreeContext)) + { + WINDOWPLACEMENT placement = { sizeof(placement) }; + + GetWindowPlacement(selectedNode->WindowHandle, &placement); + + if (placement.showCmd == SW_MINIMIZE) + ShowWindowAsync(selectedNode->WindowHandle, SW_RESTORE); + else + SetForegroundWindow(selectedNode->WindowHandle); + } + } + break; + case ID_WINDOW_RESTORE: + { + PWE_WINDOW_NODE selectedNode; + + if (selectedNode = WeGetSelectedWindowNode(&context->TreeContext)) + { + ShowWindowAsync(selectedNode->WindowHandle, SW_RESTORE); + } + } + break; + case ID_WINDOW_MINIMIZE: + { + PWE_WINDOW_NODE selectedNode; + + if (selectedNode = WeGetSelectedWindowNode(&context->TreeContext)) + { + ShowWindowAsync(selectedNode->WindowHandle, SW_MINIMIZE); + } + } + break; + case ID_WINDOW_MAXIMIZE: + { + PWE_WINDOW_NODE selectedNode; + + if (selectedNode = WeGetSelectedWindowNode(&context->TreeContext)) + { + ShowWindowAsync(selectedNode->WindowHandle, SW_MAXIMIZE); + } + } + break; + case ID_WINDOW_CLOSE: + { + PWE_WINDOW_NODE selectedNode; + + if (selectedNode = WeGetSelectedWindowNode(&context->TreeContext)) + { + PostMessage(selectedNode->WindowHandle, WM_CLOSE, 0, 0); + } + } + break; + case ID_WINDOW_VISIBLE: + { + PWE_WINDOW_NODE selectedNode; + + if (selectedNode = WeGetSelectedWindowNode(&context->TreeContext)) + { + if (IsWindowVisible(selectedNode->WindowHandle)) + { + selectedNode->WindowVisible = FALSE; + ShowWindowAsync(selectedNode->WindowHandle, SW_HIDE); + } + else + { + selectedNode->WindowVisible = TRUE; + ShowWindowAsync(selectedNode->WindowHandle, SW_SHOW); + } + + PhInvalidateTreeNewNode(&selectedNode->Node, TN_CACHE_COLOR); + TreeNew_InvalidateNode(context->TreeNewHandle, &selectedNode->Node); + } + } + break; + case ID_WINDOW_ENABLED: + { + PWE_WINDOW_NODE selectedNode; + + if (selectedNode = WeGetSelectedWindowNode(&context->TreeContext)) + { + EnableWindow(selectedNode->WindowHandle, !IsWindowEnabled(selectedNode->WindowHandle)); + } + } + break; + case ID_WINDOW_ALWAYSONTOP: + { + PWE_WINDOW_NODE selectedNode; + + if (selectedNode = WeGetSelectedWindowNode(&context->TreeContext)) + { + LOGICAL topMost; + + topMost = GetWindowLong(selectedNode->WindowHandle, GWL_EXSTYLE) & WS_EX_TOPMOST; + SetWindowPos(selectedNode->WindowHandle, topMost ? HWND_NOTOPMOST : HWND_TOPMOST, + 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE); + } + } + break; + case ID_OPACITY_10: + case ID_OPACITY_20: + case ID_OPACITY_30: + case ID_OPACITY_40: + case ID_OPACITY_50: + case ID_OPACITY_60: + case ID_OPACITY_70: + case ID_OPACITY_80: + case ID_OPACITY_90: + case ID_OPACITY_OPAQUE: + { + PWE_WINDOW_NODE selectedNode; + + if (selectedNode = WeGetSelectedWindowNode(&context->TreeContext)) + { + ULONG opacity; + + opacity = ((ULONG)LOWORD(wParam) - ID_OPACITY_10) + 1; + + if (opacity == 10) + { + // Remove the WS_EX_LAYERED bit since it is not needed. + PhSetWindowExStyle(selectedNode->WindowHandle, WS_EX_LAYERED, 0); + RedrawWindow(selectedNode->WindowHandle, NULL, NULL, RDW_ERASE | RDW_INVALIDATE | RDW_FRAME | RDW_ALLCHILDREN); + } + else + { + // Add the WS_EX_LAYERED bit so opacity will work. + PhSetWindowExStyle(selectedNode->WindowHandle, WS_EX_LAYERED, WS_EX_LAYERED); + SetLayeredWindowAttributes(selectedNode->WindowHandle, 0, (BYTE)(255 * opacity / 10), LWA_ALPHA); + } + } + } + break; + case ID_WINDOW_HIGHLIGHT: + { + PWE_WINDOW_NODE selectedNode; + + if (selectedNode = WeGetSelectedWindowNode(&context->TreeContext)) + { + if (context->HighlightingWindow) + { + if (context->HighlightingWindowCount & 1) + WeInvertWindowBorder(context->HighlightingWindow); + } + + context->HighlightingWindow = selectedNode->WindowHandle; + context->HighlightingWindowCount = 10; + SetTimer(hwndDlg, 9, 100, NULL); + } + } + break; + case ID_WINDOW_GOTOTHREAD: + { + PWE_WINDOW_NODE selectedNode; + PPH_PROCESS_ITEM processItem; + PPH_PROCESS_PROPCONTEXT propContext; + + if (selectedNode = WeGetSelectedWindowNode(&context->TreeContext)) + { + if (processItem = PhReferenceProcessItem(selectedNode->ClientId.UniqueProcess)) + { + if (propContext = PhCreateProcessPropContext(WE_PhMainWndHandle, processItem)) + { + PhSetSelectThreadIdProcessPropContext(propContext, selectedNode->ClientId.UniqueThread); + PhShowProcessProperties(propContext); + PhDereferenceObject(propContext); + } + + PhDereferenceObject(processItem); + } + else + { + PhShowError(hwndDlg, L"The process does not exist."); + } + } + } + break; + case ID_WINDOW_PROPERTIES: + { + PWE_WINDOW_NODE selectedNode; + + if (selectedNode = WeGetSelectedWindowNode(&context->TreeContext)) + WeShowWindowProperties(hwndDlg, selectedNode->WindowHandle); + } + break; + case ID_WINDOW_COPY: + { + PPH_STRING text; + + text = PhGetTreeNewText(context->TreeNewHandle, 0); + PhSetClipboardString(hwndDlg, &text->sr); + PhDereferenceObject(text); + } + break; + } + } + break; + case WM_TIMER: + { + switch (wParam) + { + case 9: + { + WeInvertWindowBorder(context->HighlightingWindow); + + if (--context->HighlightingWindowCount == 0) + KillTimer(hwndDlg, 9); + } + break; + } + } + break; + case WM_SIZE: + { + PhLayoutManagerLayout(&context->LayoutManager); + } + break; + } + + return FALSE; +} + +INT_PTR CALLBACK WepWindowsPageProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + PWINDOWS_CONTEXT context; + LPPROPSHEETPAGE propSheetPage; + PPH_PROCESS_PROPPAGECONTEXT propPageContext; + PPH_PROCESS_ITEM processItem; + + if (PhPropPageDlgProcHeader(hwndDlg, uMsg, lParam, &propSheetPage, &propPageContext, &processItem)) + { + context = propPageContext->Context; + } + else + { + return FALSE; + } + + switch (uMsg) + { + case WM_INITDIALOG: + { + context->TreeNewHandle = GetDlgItem(hwndDlg, IDC_LIST); + context->SearchBoxHandle = GetDlgItem(hwndDlg, IDC_SEARCHEDIT); + + PhCreateSearchControl(hwndDlg, context->SearchBoxHandle, L"Search Windows (Ctrl+K)"); + + WeInitializeWindowTree(hwndDlg, context->TreeNewHandle, &context->TreeContext); + + PhRegisterDialog(hwndDlg); + + PhInitializeLayoutManager(&context->LayoutManager, hwndDlg); + PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_SEARCHEDIT), NULL, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); + PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_LIST), NULL, PH_ANCHOR_ALL); + + WepRefreshWindows(context); + } + break; + case WM_SHOWWINDOW: + { + if (PhBeginPropPageLayout(hwndDlg, propPageContext)) + PhEndPropPageLayout(hwndDlg, propPageContext); + } + break; + case WM_DESTROY: + { + PhDeleteLayoutManager(&context->LayoutManager); + + PhUnregisterDialog(hwndDlg); + + WeDeleteWindowTree(&context->TreeContext); + WepDeleteWindowSelector(&context->Selector); + PhFree(context); + } + break; + case WM_COMMAND: + { + switch (GET_WM_COMMAND_CMD(wParam, lParam)) + { + case EN_CHANGE: + { + PPH_STRING newSearchboxText; + + if (GET_WM_COMMAND_HWND(wParam, lParam) != context->SearchBoxHandle) + break; + + newSearchboxText = PH_AUTO(PhGetWindowText(context->SearchBoxHandle)); + + if (!PhEqualString(context->TreeContext.SearchboxText, newSearchboxText, FALSE)) + { + PhSwapReference(&context->TreeContext.SearchboxText, newSearchboxText); + + if (!PhIsNullOrEmptyString(context->TreeContext.SearchboxText)) + WeExpandAllWindowNodes(&context->TreeContext, TRUE); + + PhApplyTreeNewFilters(&context->TreeContext.FilterSupport); + + TreeNew_NodesStructured(context->TreeNewHandle); + // PhInvokeCallback(&SearchChangedEvent, SearchboxText); + } + } + break; + } + + switch (LOWORD(wParam)) + { + case IDC_REFRESH: + WepRefreshWindows(context); + break; + case ID_SHOWCONTEXTMENU: + { + POINT point; + PWE_WINDOW_NODE *windows; + ULONG numberOfWindows; + PPH_EMENU menu; + + point.x = (SHORT)LOWORD(lParam); + point.y = (SHORT)HIWORD(lParam); + + WeGetSelectedWindowNodes( + &context->TreeContext, + &windows, + &numberOfWindows + ); + + if (numberOfWindows != 0) + { + menu = PhCreateEMenu(); + PhLoadResourceEMenuItem(menu, PluginInstance->DllBase, MAKEINTRESOURCE(IDR_WINDOW), 0); + PhSetFlagsEMenuItem(menu, ID_WINDOW_PROPERTIES, PH_EMENU_DEFAULT, PH_EMENU_DEFAULT); + + if (numberOfWindows == 1) + { + WINDOWPLACEMENT placement = { sizeof(placement) }; + BYTE alpha; + ULONG flags; + ULONG i; + ULONG id; + + // State + + GetWindowPlacement(windows[0]->WindowHandle, &placement); + + if (placement.showCmd == SW_MINIMIZE) + PhSetFlagsEMenuItem(menu, ID_WINDOW_MINIMIZE, PH_EMENU_DISABLED, PH_EMENU_DISABLED); + else if (placement.showCmd == SW_MAXIMIZE) + PhSetFlagsEMenuItem(menu, ID_WINDOW_MAXIMIZE, PH_EMENU_DISABLED, PH_EMENU_DISABLED); + else if (placement.showCmd == SW_NORMAL) + PhSetFlagsEMenuItem(menu, ID_WINDOW_RESTORE, PH_EMENU_DISABLED, PH_EMENU_DISABLED); + + // Visible + + PhSetFlagsEMenuItem(menu, ID_WINDOW_VISIBLE, PH_EMENU_CHECKED, + (GetWindowLong(windows[0]->WindowHandle, GWL_STYLE) & WS_VISIBLE) ? PH_EMENU_CHECKED : 0); + + // Enabled + + PhSetFlagsEMenuItem(menu, ID_WINDOW_ENABLED, PH_EMENU_CHECKED, + !(GetWindowLong(windows[0]->WindowHandle, GWL_STYLE) & WS_DISABLED) ? PH_EMENU_CHECKED : 0); + + // Always on Top + + PhSetFlagsEMenuItem(menu, ID_WINDOW_ALWAYSONTOP, PH_EMENU_CHECKED, + (GetWindowLong(windows[0]->WindowHandle, GWL_EXSTYLE) & WS_EX_TOPMOST) ? PH_EMENU_CHECKED : 0); + + // Opacity + + if (GetLayeredWindowAttributes(windows[0]->WindowHandle, NULL, &alpha, &flags)) + { + if (!(flags & LWA_ALPHA)) + alpha = 255; + } + else + { + alpha = 255; + } + + if (alpha == 255) + { + id = ID_OPACITY_OPAQUE; + } + else + { + id = 0; + + // Due to integer division, we cannot use simple arithmetic to calculate which menu item to check. + for (i = 0; i < 10; i++) + { + if (alpha == (BYTE)(255 * (i + 1) / 10)) + { + id = ID_OPACITY_10 + i; + break; + } + } + } + + if (id != 0) + { + PhSetFlagsEMenuItem(menu, id, PH_EMENU_CHECKED | PH_EMENU_RADIOCHECK, + PH_EMENU_CHECKED | PH_EMENU_RADIOCHECK); + } + } + else + { + PhSetFlagsAllEMenuItems(menu, PH_EMENU_DISABLED, PH_EMENU_DISABLED); + PhSetFlagsEMenuItem(menu, ID_WINDOW_COPY, PH_EMENU_DISABLED, 0); + } + + PhShowEMenu(menu, hwndDlg, PH_EMENU_SHOW_SEND_COMMAND | PH_EMENU_SHOW_LEFTRIGHT, PH_ALIGN_LEFT | PH_ALIGN_TOP, point.x, point.y); + PhDestroyEMenu(menu); + } + } + break; + case ID_WINDOW_BRINGTOFRONT: + { + PWE_WINDOW_NODE selectedNode; + + if (selectedNode = WeGetSelectedWindowNode(&context->TreeContext)) + { + WINDOWPLACEMENT placement = { sizeof(placement) }; + + GetWindowPlacement(selectedNode->WindowHandle, &placement); + + if (placement.showCmd == SW_MINIMIZE) + ShowWindowAsync(selectedNode->WindowHandle, SW_RESTORE); + else + SetForegroundWindow(selectedNode->WindowHandle); + } + } + break; + case ID_WINDOW_RESTORE: + { + PWE_WINDOW_NODE selectedNode; + + if (selectedNode = WeGetSelectedWindowNode(&context->TreeContext)) + { + ShowWindowAsync(selectedNode->WindowHandle, SW_RESTORE); + } + } + break; + case ID_WINDOW_MINIMIZE: + { + PWE_WINDOW_NODE selectedNode; + + if (selectedNode = WeGetSelectedWindowNode(&context->TreeContext)) + { + ShowWindowAsync(selectedNode->WindowHandle, SW_MINIMIZE); + } + } + break; + case ID_WINDOW_MAXIMIZE: + { + PWE_WINDOW_NODE selectedNode; + + if (selectedNode = WeGetSelectedWindowNode(&context->TreeContext)) + { + ShowWindowAsync(selectedNode->WindowHandle, SW_MAXIMIZE); + } + } + break; + case ID_WINDOW_CLOSE: + { + PWE_WINDOW_NODE selectedNode; + + if (selectedNode = WeGetSelectedWindowNode(&context->TreeContext)) + { + PostMessage(selectedNode->WindowHandle, WM_CLOSE, 0, 0); + } + } + break; + case ID_WINDOW_VISIBLE: + { + PWE_WINDOW_NODE selectedNode; + + if (selectedNode = WeGetSelectedWindowNode(&context->TreeContext)) + { + if (IsWindowVisible(selectedNode->WindowHandle)) + { + selectedNode->WindowVisible = FALSE; + ShowWindowAsync(selectedNode->WindowHandle, SW_HIDE); + } + else + { + selectedNode->WindowVisible = TRUE; + ShowWindowAsync(selectedNode->WindowHandle, SW_SHOW); + } + + PhInvalidateTreeNewNode(&selectedNode->Node, TN_CACHE_COLOR); + TreeNew_InvalidateNode(context->TreeNewHandle, &selectedNode->Node); + } + } + break; + case ID_WINDOW_ENABLED: + { + PWE_WINDOW_NODE selectedNode; + + if (selectedNode = WeGetSelectedWindowNode(&context->TreeContext)) + { + EnableWindow(selectedNode->WindowHandle, !IsWindowEnabled(selectedNode->WindowHandle)); + } + } + break; + case ID_WINDOW_ALWAYSONTOP: + { + PWE_WINDOW_NODE selectedNode; + + if (selectedNode = WeGetSelectedWindowNode(&context->TreeContext)) + { + LOGICAL topMost; + + topMost = GetWindowLong(selectedNode->WindowHandle, GWL_EXSTYLE) & WS_EX_TOPMOST; + SetWindowPos(selectedNode->WindowHandle, topMost ? HWND_NOTOPMOST : HWND_TOPMOST, + 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE); + } + } + break; + case ID_OPACITY_10: + case ID_OPACITY_20: + case ID_OPACITY_30: + case ID_OPACITY_40: + case ID_OPACITY_50: + case ID_OPACITY_60: + case ID_OPACITY_70: + case ID_OPACITY_80: + case ID_OPACITY_90: + case ID_OPACITY_OPAQUE: + { + PWE_WINDOW_NODE selectedNode; + + if (selectedNode = WeGetSelectedWindowNode(&context->TreeContext)) + { + ULONG opacity; + + opacity = ((ULONG)LOWORD(wParam) - ID_OPACITY_10) + 1; + + if (opacity == 10) + { + // Remove the WS_EX_LAYERED bit since it is not needed. + PhSetWindowExStyle(selectedNode->WindowHandle, WS_EX_LAYERED, 0); + RedrawWindow(selectedNode->WindowHandle, NULL, NULL, RDW_ERASE | RDW_INVALIDATE | RDW_FRAME | RDW_ALLCHILDREN); + } + else + { + // Add the WS_EX_LAYERED bit so opacity will work. + PhSetWindowExStyle(selectedNode->WindowHandle, WS_EX_LAYERED, WS_EX_LAYERED); + SetLayeredWindowAttributes(selectedNode->WindowHandle, 0, (BYTE)(255 * opacity / 10), LWA_ALPHA); + } + } + } + break; + case ID_WINDOW_HIGHLIGHT: + { + PWE_WINDOW_NODE selectedNode; + + if (selectedNode = WeGetSelectedWindowNode(&context->TreeContext)) + { + if (context->HighlightingWindow) + { + if (context->HighlightingWindowCount & 1) + WeInvertWindowBorder(context->HighlightingWindow); + } + + context->HighlightingWindow = selectedNode->WindowHandle; + context->HighlightingWindowCount = 10; + SetTimer(hwndDlg, 9, 100, NULL); + } + } + break; + case ID_WINDOW_GOTOTHREAD: + { + PWE_WINDOW_NODE selectedNode; + PPH_PROCESS_ITEM processItem; + PPH_PROCESS_PROPCONTEXT propContext; + + if (selectedNode = WeGetSelectedWindowNode(&context->TreeContext)) + { + if (processItem = PhReferenceProcessItem(selectedNode->ClientId.UniqueProcess)) + { + if (propContext = PhCreateProcessPropContext(WE_PhMainWndHandle, processItem)) + { + PhSetSelectThreadIdProcessPropContext(propContext, selectedNode->ClientId.UniqueThread); + PhShowProcessProperties(propContext); + PhDereferenceObject(propContext); + } + + PhDereferenceObject(processItem); + } + else + { + PhShowError(hwndDlg, L"The process does not exist."); + } + } + } + break; + case ID_WINDOW_PROPERTIES: + { + PWE_WINDOW_NODE selectedNode; + + if (selectedNode = WeGetSelectedWindowNode(&context->TreeContext)) + WeShowWindowProperties(hwndDlg, selectedNode->WindowHandle); + } + break; + case ID_WINDOW_COPY: + { + PPH_STRING text; + + text = PhGetTreeNewText(context->TreeNewHandle, 0); + PhSetClipboardString(hwndDlg, &text->sr); + PhDereferenceObject(text); + } + break; + } + } + break; + case WM_TIMER: + { + switch (wParam) + { + case 9: + { + WeInvertWindowBorder(context->HighlightingWindow); + + if (--context->HighlightingWindowCount == 0) + KillTimer(hwndDlg, 9); + } + break; + } + } + break; + case WM_SIZE: + PhLayoutManagerLayout(&context->LayoutManager); + break; + case WM_NOTIFY: + { + LPNMHDR header = (LPNMHDR)lParam; + + switch (header->code) + { + case PSN_QUERYINITIALFOCUS: + SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, (LPARAM)GetDlgItem(hwndDlg, IDC_REFRESH)); + return TRUE; + } + } + break; + } + + return FALSE; } \ No newline at end of file diff --git a/plugins/WindowExplorer/wndexp.h b/plugins/WindowExplorer/wndexp.h index 05c330d571b8..6be77e09186f 100644 --- a/plugins/WindowExplorer/wndexp.h +++ b/plugins/WindowExplorer/wndexp.h @@ -1,135 +1,135 @@ -#ifndef WNDEXP_H -#define WNDEXP_H - -#include -#include -#include "wndtree.h" - -extern BOOLEAN IsHookClient; -extern PPH_PLUGIN PluginInstance; - -#define PLUGIN_NAME L"ProcessHacker.WindowExplorer" -#define SETTING_NAME_SHOW_DESKTOP_WINDOWS (PLUGIN_NAME L".ShowDesktopWindows") -#define SETTING_NAME_WINDOW_TREE_LIST_COLUMNS (PLUGIN_NAME L".WindowTreeListColumns") -#define SETTING_NAME_WINDOWS_WINDOW_POSITION (PLUGIN_NAME L".WindowsWindowPosition") -#define SETTING_NAME_WINDOWS_WINDOW_SIZE (PLUGIN_NAME L".WindowsWindowSize") - -// hook - -#define WE_SERVER_MESSAGE_NAME L"WE_ServerMessage" -#define WE_SERVER_SHARED_SECTION_NAME L"\\BaseNamedObjects\\WeSharedSection" -#define WE_SERVER_SHARED_SECTION_LOCK_NAME L"\\BaseNamedObjects\\WeSharedSectionLock" -#define WE_SERVER_SHARED_SECTION_EVENT_NAME L"\\BaseNamedObjects\\WeSharedSectionEvent" -#define WE_CLIENT_MESSAGE_TIMEOUT 2000 - -typedef struct _WE_HOOK_SHARED_DATA -{ - ULONG MessageId; - - struct - { - ULONG_PTR WndProc; - ULONG_PTR DlgProc; - WNDCLASSEX ClassInfo; - } c; -} WE_HOOK_SHARED_DATA, *PWE_HOOK_SHARED_DATA; - -VOID WeHookServerInitialization( - VOID - ); - -VOID WeHookServerUninitialization( - VOID - ); - -BOOLEAN WeIsServerActive( - VOID - ); - -BOOLEAN WeLockServerSharedData( - _Out_ PWE_HOOK_SHARED_DATA *Data - ); - -VOID WeUnlockServerSharedData( - VOID - ); - -BOOLEAN WeSendServerRequest( - _In_ HWND hWnd - ); - -VOID WeHookClientInitialization( - VOID - ); - -VOID WeHookClientUninitialization( - VOID - ); - -// wnddlg - -typedef enum _WE_WINDOW_SELECTOR_TYPE -{ - WeWindowSelectorAll, - WeWindowSelectorProcess, - WeWindowSelectorThread, - WeWindowSelectorDesktop -} WE_WINDOW_SELECTOR_TYPE; - -typedef struct _WE_WINDOW_SELECTOR -{ - WE_WINDOW_SELECTOR_TYPE Type; - union - { - struct - { - HANDLE ProcessId; - } Process; - struct - { - HANDLE ThreadId; - } Thread; - struct - { - PPH_STRING DesktopName; - } Desktop; - }; -} WE_WINDOW_SELECTOR, *PWE_WINDOW_SELECTOR; - -VOID WeShowWindowsDialog( - _In_ HWND ParentWindowHandle, - _In_ PWE_WINDOW_SELECTOR Selector - ); - -VOID WeShowWindowsPropPage( - _In_ PPH_PLUGIN_PROCESS_PROPCONTEXT Context, - _In_ PWE_WINDOW_SELECTOR Selector - ); - -// wndprp - -VOID WeShowWindowProperties( - _In_ HWND ParentWindowHandle, - _In_ HWND WindowHandle - ); - -// utils - -#define WE_PhMainWndHandle (*(HWND *)WeGetProcedureAddress("PhMainWndHandle")) -#define WE_WindowsVersion (*(ULONG *)WeGetProcedureAddress("WindowsVersion")) - -PVOID WeGetProcedureAddress( - _In_ PSTR Name - ); - -VOID WeFormatLocalObjectName( - _In_ PWSTR OriginalName, - _Inout_updates_(256) PWCHAR Buffer, - _Out_ PUNICODE_STRING ObjectName - ); - -VOID WeInvertWindowBorder( - _In_ HWND hWnd - ); - -#endif +#ifndef WNDEXP_H +#define WNDEXP_H + +#include +#include +#include "wndtree.h" + +extern BOOLEAN IsHookClient; +extern PPH_PLUGIN PluginInstance; + +#define PLUGIN_NAME L"ProcessHacker.WindowExplorer" +#define SETTING_NAME_SHOW_DESKTOP_WINDOWS (PLUGIN_NAME L".ShowDesktopWindows") +#define SETTING_NAME_WINDOW_TREE_LIST_COLUMNS (PLUGIN_NAME L".WindowTreeListColumns") +#define SETTING_NAME_WINDOWS_WINDOW_POSITION (PLUGIN_NAME L".WindowsWindowPosition") +#define SETTING_NAME_WINDOWS_WINDOW_SIZE (PLUGIN_NAME L".WindowsWindowSize") + +// hook + +#define WE_SERVER_MESSAGE_NAME L"WE_ServerMessage" +#define WE_SERVER_SHARED_SECTION_NAME L"\\BaseNamedObjects\\WeSharedSection" +#define WE_SERVER_SHARED_SECTION_LOCK_NAME L"\\BaseNamedObjects\\WeSharedSectionLock" +#define WE_SERVER_SHARED_SECTION_EVENT_NAME L"\\BaseNamedObjects\\WeSharedSectionEvent" +#define WE_CLIENT_MESSAGE_TIMEOUT 2000 + +typedef struct _WE_HOOK_SHARED_DATA +{ + ULONG MessageId; + + struct + { + ULONG_PTR WndProc; + ULONG_PTR DlgProc; + WNDCLASSEX ClassInfo; + } c; +} WE_HOOK_SHARED_DATA, *PWE_HOOK_SHARED_DATA; + +VOID WeHookServerInitialization( + VOID + ); + +VOID WeHookServerUninitialization( + VOID + ); + +BOOLEAN WeIsServerActive( + VOID + ); + +BOOLEAN WeLockServerSharedData( + _Out_ PWE_HOOK_SHARED_DATA *Data + ); + +VOID WeUnlockServerSharedData( + VOID + ); + +BOOLEAN WeSendServerRequest( + _In_ HWND hWnd + ); + +VOID WeHookClientInitialization( + VOID + ); + +VOID WeHookClientUninitialization( + VOID + ); + +// wnddlg + +typedef enum _WE_WINDOW_SELECTOR_TYPE +{ + WeWindowSelectorAll, + WeWindowSelectorProcess, + WeWindowSelectorThread, + WeWindowSelectorDesktop +} WE_WINDOW_SELECTOR_TYPE; + +typedef struct _WE_WINDOW_SELECTOR +{ + WE_WINDOW_SELECTOR_TYPE Type; + union + { + struct + { + HANDLE ProcessId; + } Process; + struct + { + HANDLE ThreadId; + } Thread; + struct + { + PPH_STRING DesktopName; + } Desktop; + }; +} WE_WINDOW_SELECTOR, *PWE_WINDOW_SELECTOR; + +VOID WeShowWindowsDialog( + _In_ HWND ParentWindowHandle, + _In_ PWE_WINDOW_SELECTOR Selector + ); + +VOID WeShowWindowsPropPage( + _In_ PPH_PLUGIN_PROCESS_PROPCONTEXT Context, + _In_ PWE_WINDOW_SELECTOR Selector + ); + +// wndprp + +VOID WeShowWindowProperties( + _In_ HWND ParentWindowHandle, + _In_ HWND WindowHandle + ); + +// utils + +#define WE_PhMainWndHandle (*(HWND *)WeGetProcedureAddress("PhMainWndHandle")) +#define WE_WindowsVersion (*(ULONG *)WeGetProcedureAddress("WindowsVersion")) + +PVOID WeGetProcedureAddress( + _In_ PSTR Name + ); + +VOID WeFormatLocalObjectName( + _In_ PWSTR OriginalName, + _Inout_updates_(256) PWCHAR Buffer, + _Out_ PUNICODE_STRING ObjectName + ); + +VOID WeInvertWindowBorder( + _In_ HWND hWnd + ); + +#endif diff --git a/plugins/WindowExplorer/wndprp.c b/plugins/WindowExplorer/wndprp.c index aa71849b3bc5..515b17ee9c40 100644 --- a/plugins/WindowExplorer/wndprp.c +++ b/plugins/WindowExplorer/wndprp.c @@ -1,1210 +1,1210 @@ -/* - * Process Hacker Window Explorer - - * window properties - * - * Copyright (C) 2011 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -// Since the main message loop doesn't support property sheets, we need a separate thread to run -// property sheets on. - -#include "wndexp.h" -#include "resource.h" -#include -#include -#include - -#define NUMBER_OF_PAGES 4 -#define WEM_RESOLVE_DONE (WM_APP + 1234) - -typedef struct _WINDOW_PROPERTIES_CONTEXT -{ - LONG RefCount; - - HWND ParentWindowHandle; - - HWND WindowHandle; - CLIENT_ID ClientId; - PH_INITONCE SymbolProviderInitOnce; - PPH_SYMBOL_PROVIDER SymbolProvider; - LIST_ENTRY ResolveListHead; - PH_QUEUED_LOCK ResolveListLock; - - PPH_STRING WndProcSymbol; - ULONG WndProcResolving; - PPH_STRING DlgProcSymbol; - ULONG DlgProcResolving; - PPH_STRING ClassWndProcSymbol; - ULONG ClassWndProcResolving; - - BOOLEAN HookDataValid; - BOOLEAN HookDataSuccess; - ULONG_PTR WndProc; - ULONG_PTR DlgProc; - WNDCLASSEX ClassInfo; -} WINDOW_PROPERTIES_CONTEXT, *PWINDOW_PROPERTIES_CONTEXT; - -typedef struct _SYMBOL_RESOLVE_CONTEXT -{ - LIST_ENTRY ListEntry; - ULONG64 Address; - PPH_STRING Symbol; - PH_SYMBOL_RESOLVE_LEVEL ResolveLevel; - HWND NotifyWindow; - PWINDOW_PROPERTIES_CONTEXT Context; - ULONG Id; -} SYMBOL_RESOLVE_CONTEXT, *PSYMBOL_RESOLVE_CONTEXT; - -typedef struct _STRING_INTEGER_PAIR -{ - PWSTR String; - ULONG Integer; -} STRING_INTEGER_PAIR, *PSTRING_INTEGER_PAIR; - -VOID WepReferenceWindowPropertiesContext( - _Inout_ PWINDOW_PROPERTIES_CONTEXT Context - ); - -VOID WepDereferenceWindowPropertiesContext( - _Inout_ PWINDOW_PROPERTIES_CONTEXT Context - ); - -HWND WepCreateWindowProperties( - _In_ PWINDOW_PROPERTIES_CONTEXT Context - ); - -INT CALLBACK WepPropSheetProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ LPARAM lParam - ); - -LRESULT CALLBACK WepPropSheetWndProc( - _In_ HWND hwnd, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -HPROPSHEETPAGE WepCommonCreatePage( - _In_ PWINDOW_PROPERTIES_CONTEXT Context, - _In_ PWSTR Template, - _In_ DLGPROC DlgProc - ); - -INT CALLBACK WepCommonPropPageProc( - _In_ HWND hwnd, - _In_ UINT uMsg, - _In_ LPPROPSHEETPAGE ppsp - ); - -NTSTATUS WepPropertiesThreadStart( - _In_ PVOID Parameter - ); - -INT_PTR CALLBACK WepWindowGeneralDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -INT_PTR CALLBACK WepWindowStylesDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -INT_PTR CALLBACK WepWindowClassDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -INT_PTR CALLBACK WepWindowPropertiesDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -#define DEFINE_PAIR(Symbol) { L#Symbol, Symbol } - -static STRING_INTEGER_PAIR WepStylePairs[] = -{ - DEFINE_PAIR(WS_POPUP), - DEFINE_PAIR(WS_CHILD), - DEFINE_PAIR(WS_MINIMIZE), - DEFINE_PAIR(WS_VISIBLE), - DEFINE_PAIR(WS_DISABLED), - DEFINE_PAIR(WS_CLIPSIBLINGS), - DEFINE_PAIR(WS_CLIPCHILDREN), - DEFINE_PAIR(WS_MAXIMIZE), - DEFINE_PAIR(WS_BORDER), - DEFINE_PAIR(WS_DLGFRAME), - DEFINE_PAIR(WS_VSCROLL), - DEFINE_PAIR(WS_HSCROLL), - DEFINE_PAIR(WS_SYSMENU), - DEFINE_PAIR(WS_THICKFRAME), - DEFINE_PAIR(WS_GROUP), - DEFINE_PAIR(WS_TABSTOP), - DEFINE_PAIR(WS_MINIMIZEBOX), - DEFINE_PAIR(WS_MAXIMIZEBOX) -}; - -static STRING_INTEGER_PAIR WepExtendedStylePairs[] = -{ - DEFINE_PAIR(WS_EX_DLGMODALFRAME), - DEFINE_PAIR(WS_EX_NOPARENTNOTIFY), - DEFINE_PAIR(WS_EX_TOPMOST), - DEFINE_PAIR(WS_EX_ACCEPTFILES), - DEFINE_PAIR(WS_EX_TRANSPARENT), - DEFINE_PAIR(WS_EX_MDICHILD), - DEFINE_PAIR(WS_EX_TOOLWINDOW), - DEFINE_PAIR(WS_EX_WINDOWEDGE), - DEFINE_PAIR(WS_EX_CLIENTEDGE), - DEFINE_PAIR(WS_EX_CONTEXTHELP), - DEFINE_PAIR(WS_EX_RIGHT), - DEFINE_PAIR(WS_EX_RTLREADING), - DEFINE_PAIR(WS_EX_LEFTSCROLLBAR), - DEFINE_PAIR(WS_EX_CONTROLPARENT), - DEFINE_PAIR(WS_EX_STATICEDGE), - DEFINE_PAIR(WS_EX_APPWINDOW), - DEFINE_PAIR(WS_EX_LAYERED), - DEFINE_PAIR(WS_EX_NOINHERITLAYOUT), - DEFINE_PAIR(WS_EX_LAYOUTRTL), - DEFINE_PAIR(WS_EX_COMPOSITED), - DEFINE_PAIR(WS_EX_NOACTIVATE) -}; - -static STRING_INTEGER_PAIR WepClassStylePairs[] = -{ - DEFINE_PAIR(CS_VREDRAW), - DEFINE_PAIR(CS_HREDRAW), - DEFINE_PAIR(CS_DBLCLKS), - DEFINE_PAIR(CS_OWNDC), - DEFINE_PAIR(CS_CLASSDC), - DEFINE_PAIR(CS_PARENTDC), - DEFINE_PAIR(CS_NOCLOSE), - DEFINE_PAIR(CS_SAVEBITS), - DEFINE_PAIR(CS_BYTEALIGNCLIENT), - DEFINE_PAIR(CS_BYTEALIGNWINDOW), - DEFINE_PAIR(CS_GLOBALCLASS), - DEFINE_PAIR(CS_IME), - DEFINE_PAIR(CS_DROPSHADOW) -}; - -HANDLE WePropertiesThreadHandle = NULL; -CLIENT_ID WePropertiesThreadClientId; -PH_EVENT WePropertiesThreadReadyEvent = PH_EVENT_INIT; -PPH_LIST WePropertiesCreateList; -PPH_LIST WePropertiesWindowList; -PH_QUEUED_LOCK WePropertiesCreateLock = PH_QUEUED_LOCK_INIT; - -VOID WeShowWindowProperties( - _In_ HWND ParentWindowHandle, - _In_ HWND WindowHandle - ) -{ - PWINDOW_PROPERTIES_CONTEXT context; - ULONG threadId; - ULONG processId; - - if (!WePropertiesCreateList) - WePropertiesCreateList = PhCreateList(4); - if (!WePropertiesWindowList) - WePropertiesWindowList = PhCreateList(4); - - if (!WePropertiesThreadHandle) - { - WePropertiesThreadHandle = PhCreateThread(0, WepPropertiesThreadStart, NULL); - PhWaitForEvent(&WePropertiesThreadReadyEvent, NULL); - } - - context = PhAllocate(sizeof(WINDOW_PROPERTIES_CONTEXT)); - memset(context, 0, sizeof(WINDOW_PROPERTIES_CONTEXT)); - context->RefCount = 1; - context->ParentWindowHandle = ParentWindowHandle; - context->WindowHandle = WindowHandle; - - processId = 0; - threadId = GetWindowThreadProcessId(WindowHandle, &processId); - context->ClientId.UniqueProcess = UlongToHandle(processId); - context->ClientId.UniqueThread = UlongToHandle(threadId); - PhInitializeInitOnce(&context->SymbolProviderInitOnce); - InitializeListHead(&context->ResolveListHead); - PhInitializeQueuedLock(&context->ResolveListLock); - - // Queue the window for creation and wake up the host thread. - PhAcquireQueuedLockExclusive(&WePropertiesCreateLock); - PhAddItemList(WePropertiesCreateList, context); - PhReleaseQueuedLockExclusive(&WePropertiesCreateLock); - PostThreadMessage(HandleToUlong(WePropertiesThreadClientId.UniqueThread), WM_NULL, 0, 0); -} - -VOID WepReferenceWindowPropertiesContext( - _Inout_ PWINDOW_PROPERTIES_CONTEXT Context - ) -{ - _InterlockedIncrement(&Context->RefCount); -} - -VOID WepDereferenceWindowPropertiesContext( - _Inout_ PWINDOW_PROPERTIES_CONTEXT Context - ) -{ - if (_InterlockedDecrement(&Context->RefCount) == 0) - { - PLIST_ENTRY listEntry; - - PhClearReference(&Context->SymbolProvider); - - // Destroy results that have not been processed by any property pages. - - listEntry = Context->ResolveListHead.Flink; - - while (listEntry != &Context->ResolveListHead) - { - PSYMBOL_RESOLVE_CONTEXT resolveContext; - - resolveContext = CONTAINING_RECORD(listEntry, SYMBOL_RESOLVE_CONTEXT, ListEntry); - listEntry = listEntry->Flink; - - PhClearReference(&resolveContext->Symbol); - PhFree(resolveContext); - } - - PhClearReference(&Context->WndProcSymbol); - PhClearReference(&Context->DlgProcSymbol); - PhClearReference(&Context->ClassWndProcSymbol); - - PhFree(Context); - } -} - -static HWND WepCreateWindowProperties( - _In_ PWINDOW_PROPERTIES_CONTEXT Context - ) -{ - PROPSHEETHEADER propSheetHeader = { sizeof(propSheetHeader) }; - HPROPSHEETPAGE pages[NUMBER_OF_PAGES]; - - propSheetHeader.dwFlags = - PSH_MODELESS | - PSH_NOAPPLYNOW | - PSH_NOCONTEXTHELP | - PSH_PROPTITLE | - PSH_USECALLBACK; - propSheetHeader.hwndParent = Context->ParentWindowHandle; - propSheetHeader.pszCaption = PhaFormatString(L"Window %Ix", Context->WindowHandle)->Buffer; - propSheetHeader.nPages = 0; - propSheetHeader.nStartPage = 0; - propSheetHeader.phpage = pages; - propSheetHeader.pfnCallback = WepPropSheetProc; - - // General - pages[propSheetHeader.nPages++] = WepCommonCreatePage( - Context, - MAKEINTRESOURCE(IDD_WNDGENERAL), - WepWindowGeneralDlgProc - ); - // Styles - pages[propSheetHeader.nPages++] = WepCommonCreatePage( - Context, - MAKEINTRESOURCE(IDD_WNDSTYLES), - WepWindowStylesDlgProc - ); - // Class - pages[propSheetHeader.nPages++] = WepCommonCreatePage( - Context, - MAKEINTRESOURCE(IDD_WNDCLASS), - WepWindowClassDlgProc - ); - // Properties - pages[propSheetHeader.nPages++] = WepCommonCreatePage( - Context, - MAKEINTRESOURCE(IDD_WNDPROPS), - WepWindowPropertiesDlgProc - ); - - return (HWND)PropertySheet(&propSheetHeader); -} - -static INT CALLBACK WepPropSheetProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ LPARAM lParam - ) -{ - switch (uMsg) - { - case PSCB_INITIALIZED: - { - WNDPROC oldWndProc; - HWND refreshButtonHandle; - - oldWndProc = (WNDPROC)GetWindowLongPtr(hwndDlg, GWLP_WNDPROC); - SetWindowLongPtr(hwndDlg, GWLP_WNDPROC, (LONG_PTR)WepPropSheetWndProc); - SetProp(hwndDlg, L"OldWndProc", (HANDLE)oldWndProc); - - // Hide the Cancel button. - ShowWindow(GetDlgItem(hwndDlg, IDCANCEL), SW_HIDE); - // Set the OK button's text to "Close". - SetDlgItemText(hwndDlg, IDOK, L"Close"); - // Add the Refresh button. - refreshButtonHandle = CreateWindow(L"BUTTON", L"Refresh", WS_CHILD | WS_TABSTOP | WS_VISIBLE, 0, 0, 3, 3, hwndDlg, (HMENU)IDC_REFRESH, - PluginInstance->DllBase, NULL); - SendMessage(refreshButtonHandle, WM_SETFONT, (WPARAM)SendMessage(GetDlgItem(hwndDlg, IDOK), WM_GETFONT, 0, 0), FALSE); - } - break; - } - - return 0; -} - -LRESULT CALLBACK WepPropSheetWndProc( - _In_ HWND hwnd, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - WNDPROC oldWndProc = (WNDPROC)GetProp(hwnd, L"OldWndProc"); - - switch (uMsg) - { - case WM_DESTROY: - { - SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)oldWndProc); - RemoveProp(hwnd, L"OldWndProc"); - RemoveProp(hwnd, L"Moved"); - } - break; - case WM_SHOWWINDOW: - { - if (!GetProp(hwnd, L"Moved")) - { - // Move the Refresh button to where the OK button is, and move the OK button to - // where the Cancel button is. - // This must be done here because in the prop sheet callback the buttons are not - // in the right places. - PhCopyControlRectangle(hwnd, GetDlgItem(hwnd, IDOK), GetDlgItem(hwnd, IDC_REFRESH)); - PhCopyControlRectangle(hwnd, GetDlgItem(hwnd, IDCANCEL), GetDlgItem(hwnd, IDOK)); - SetProp(hwnd, L"Moved", (HANDLE)1); - } - } - break; - case WM_COMMAND: - { - switch (LOWORD(wParam)) - { - case IDC_REFRESH: - { - ULONG i; - HWND pageHandle; - - // Broadcast the message to all property pages. - for (i = 0; i < NUMBER_OF_PAGES; i++) - { - if (pageHandle = PropSheet_IndexToHwnd(hwnd, i)) - SendMessage(pageHandle, WM_COMMAND, IDC_REFRESH, 0); - } - } - break; - } - } - break; - } - - return CallWindowProc(oldWndProc, hwnd, uMsg, wParam, lParam); -} - -static HPROPSHEETPAGE WepCommonCreatePage( - _In_ PWINDOW_PROPERTIES_CONTEXT Context, - _In_ PWSTR Template, - _In_ DLGPROC DlgProc - ) -{ - HPROPSHEETPAGE propSheetPageHandle; - PROPSHEETPAGE propSheetPage; - - memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); - propSheetPage.dwSize = sizeof(PROPSHEETPAGE); - propSheetPage.dwFlags = PSP_USECALLBACK; - propSheetPage.hInstance = PluginInstance->DllBase; - propSheetPage.pszTemplate = Template; - propSheetPage.pfnDlgProc = DlgProc; - propSheetPage.lParam = (LPARAM)Context; - propSheetPage.pfnCallback = WepCommonPropPageProc; - - propSheetPageHandle = CreatePropertySheetPage(&propSheetPage); - - return propSheetPageHandle; -} - -static INT CALLBACK WepCommonPropPageProc( - _In_ HWND hwnd, - _In_ UINT uMsg, - _In_ LPPROPSHEETPAGE ppsp - ) -{ - PWINDOW_PROPERTIES_CONTEXT context; - - context = (PWINDOW_PROPERTIES_CONTEXT)ppsp->lParam; - - if (uMsg == PSPCB_ADDREF) - WepReferenceWindowPropertiesContext(context); - else if (uMsg == PSPCB_RELEASE) - WepDereferenceWindowPropertiesContext(context); - - return 1; -} - -NTSTATUS WepPropertiesThreadStart( - _In_ PVOID Parameter - ) -{ - PH_AUTO_POOL autoPool; - BOOL result; - MSG message; - BOOLEAN processed; - ULONG i; - - PhInitializeAutoPool(&autoPool); - - WePropertiesThreadClientId = NtCurrentTeb()->ClientId; - - // Force the creation of the message queue so PostThreadMessage works. - PeekMessage(&message, NULL, WM_USER, WM_USER, PM_NOREMOVE); - PhSetEvent(&WePropertiesThreadReadyEvent); - - while (result = GetMessage(&message, NULL, 0, 0)) - { - if (result == -1) - break; - - if (WePropertiesCreateList->Count != 0) - { - PhAcquireQueuedLockExclusive(&WePropertiesCreateLock); - - for (i = 0; i < WePropertiesCreateList->Count; i++) - { - PWINDOW_PROPERTIES_CONTEXT context; - HWND hwnd; - - context = WePropertiesCreateList->Items[i]; - hwnd = WepCreateWindowProperties(context); - WepDereferenceWindowPropertiesContext(context); - PhAddItemList(WePropertiesWindowList, hwnd); - } - - PhClearList(WePropertiesCreateList); - PhReleaseQueuedLockExclusive(&WePropertiesCreateLock); - } - - processed = FALSE; - - for (i = 0; i < WePropertiesWindowList->Count; i++) - { - if (PropSheet_IsDialogMessage(WePropertiesWindowList->Items[i], &message)) - { - processed = TRUE; - break; - } - } - - if (!processed) - { - TranslateMessage(&message); - DispatchMessage(&message); - } - - // Destroy properties windows when necessary. - for (i = 0; i < WePropertiesWindowList->Count; i++) - { - if (!PropSheet_GetCurrentPageHwnd(WePropertiesWindowList->Items[i])) - { - DestroyWindow(WePropertiesWindowList->Items[i]); - PhRemoveItemList(WePropertiesWindowList, i); - i--; - } - } - - PhDrainAutoPool(&autoPool); - } - - PhDeleteAutoPool(&autoPool); - - return STATUS_SUCCESS; -} - -FORCEINLINE BOOLEAN WepPropPageDlgProcHeader( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ LPARAM lParam, - _Out_opt_ LPPROPSHEETPAGE *PropSheetPage, - _Out_opt_ PWINDOW_PROPERTIES_CONTEXT *Context - ) -{ - LPPROPSHEETPAGE propSheetPage; - - if (uMsg == WM_INITDIALOG) - { - propSheetPage = (LPPROPSHEETPAGE)lParam; - // Save the context. - SetProp(hwndDlg, L"PropSheetPage", (HANDLE)lParam); - } - else - { - propSheetPage = (LPPROPSHEETPAGE)GetProp(hwndDlg, L"PropSheetPage"); - - if (uMsg == WM_DESTROY) - RemoveProp(hwndDlg, L"PropSheetPage"); - } - - if (!propSheetPage) - return FALSE; - - if (PropSheetPage) - *PropSheetPage = propSheetPage; - if (Context) - *Context = (PWINDOW_PROPERTIES_CONTEXT)propSheetPage->lParam; - - return TRUE; -} - -static VOID WepEnsureHookDataValid( - _In_ PWINDOW_PROPERTIES_CONTEXT Context - ) -{ - if (!Context->HookDataValid) - { - PWE_HOOK_SHARED_DATA data; -#ifdef _WIN64 - HANDLE processHandle; - BOOLEAN isWow64 = FALSE; -#endif - - // The desktop window is owned by CSR. The hook will never work on the desktop window. - if (Context->WindowHandle == GetDesktopWindow()) - { - Context->HookDataValid = TRUE; - return; - } - -#ifdef _WIN64 - // We can't use the hook on WOW64 processes. - if (NT_SUCCESS(PhOpenProcess(&processHandle, *(PULONG)WeGetProcedureAddress("ProcessQueryAccess"), Context->ClientId.UniqueProcess))) - { - PhGetProcessIsWow64(processHandle, &isWow64); - NtClose(processHandle); - } - - if (isWow64) - return; -#endif - - WeHookServerInitialization(); - - Context->HookDataSuccess = FALSE; - - if (WeLockServerSharedData(&data)) - { - if (WeSendServerRequest(Context->WindowHandle)) - { - Context->WndProc = data->c.WndProc; - Context->DlgProc = data->c.DlgProc; - memcpy(&Context->ClassInfo, &data->c.ClassInfo, sizeof(WNDCLASSEX)); - Context->HookDataSuccess = TRUE; - } - - WeUnlockServerSharedData(); - } - - Context->HookDataValid = TRUE; - } -} - -static BOOLEAN NTAPI EnumGenericModulesCallback( - _In_ PPH_MODULE_INFO Module, - _In_opt_ PVOID Context - ) -{ - PWINDOW_PROPERTIES_CONTEXT context = Context; - - PhLoadModuleSymbolProvider(context->SymbolProvider, Module->FileName->Buffer, - (ULONG64)Module->BaseAddress, Module->Size); - - return TRUE; -} - -static NTSTATUS WepResolveSymbolFunction( - _In_ PVOID Parameter - ) -{ - PSYMBOL_RESOLVE_CONTEXT context = Parameter; - - if (PhBeginInitOnce(&context->Context->SymbolProviderInitOnce)) - { - PhEnumGenericModules(context->Context->ClientId.UniqueProcess, NULL, 0, EnumGenericModulesCallback, context->Context); - PhEndInitOnce(&context->Context->SymbolProviderInitOnce); - } - - context->Symbol = PhGetSymbolFromAddress( - context->Context->SymbolProvider, - (ULONG64)context->Address, - &context->ResolveLevel, - NULL, - NULL, - NULL - ); - - // Fail if we don't have a symbol. - if (!context->Symbol) - { - WepDereferenceWindowPropertiesContext(context->Context); - PhFree(context); - return STATUS_SUCCESS; - } - - PhAcquireQueuedLockExclusive(&context->Context->ResolveListLock); - InsertHeadList(&context->Context->ResolveListHead, &context->ListEntry); - PhReleaseQueuedLockExclusive(&context->Context->ResolveListLock); - - PostMessage(context->NotifyWindow, WEM_RESOLVE_DONE, 0, (LPARAM)context); - - WepDereferenceWindowPropertiesContext(context->Context); - - return STATUS_SUCCESS; -} - -static VOID WepQueueResolveSymbol( - _In_ PWINDOW_PROPERTIES_CONTEXT Context, - _In_ HWND NotifyWindow, - _In_ ULONG64 Address, - _In_ ULONG Id - ) -{ - PSYMBOL_RESOLVE_CONTEXT resolveContext; - - if (!Context->SymbolProvider) - { - Context->SymbolProvider = PhCreateSymbolProvider(Context->ClientId.UniqueProcess); - PhLoadSymbolProviderOptions(Context->SymbolProvider); - } - - resolveContext = PhAllocate(sizeof(SYMBOL_RESOLVE_CONTEXT)); - resolveContext->Address = Address; - resolveContext->Symbol = NULL; - resolveContext->ResolveLevel = PhsrlInvalid; - resolveContext->NotifyWindow = NotifyWindow; - resolveContext->Context = Context; - WepReferenceWindowPropertiesContext(Context); - resolveContext->Id = Id; - - PhQueueItemWorkQueue(PhGetGlobalWorkQueue(), WepResolveSymbolFunction, resolveContext); -} - -static PPH_STRING WepFormatRect( - _In_ PRECT Rect - ) -{ - return PhaFormatString(L"(%d, %d) - (%d, %d) [%dx%d]", - Rect->left, Rect->top, Rect->right, Rect->bottom, - Rect->right - Rect->left, Rect->bottom - Rect->top); -} - -static VOID WepRefreshWindowGeneralInfoSymbols( - _In_ HWND hwndDlg, - _In_ PWINDOW_PROPERTIES_CONTEXT Context - ) -{ - if (Context->WndProcResolving != 0) - SetDlgItemText(hwndDlg, IDC_WINDOWPROC, PhaFormatString(L"0x%Ix (resolving...)", Context->WndProc)->Buffer); - else if (Context->WndProcSymbol) - SetDlgItemText(hwndDlg, IDC_WINDOWPROC, PhaFormatString(L"0x%Ix (%s)", Context->WndProc, Context->WndProcSymbol->Buffer)->Buffer); - else if (Context->WndProc != 0) - SetDlgItemText(hwndDlg, IDC_WINDOWPROC, PhaFormatString(L"0x%Ix", Context->WndProc)->Buffer); - else - SetDlgItemText(hwndDlg, IDC_WINDOWPROC, L"Unknown"); - - if (Context->DlgProcResolving != 0) - SetDlgItemText(hwndDlg, IDC_DIALOGPROC, PhaFormatString(L"0x%Ix (resolving...)", Context->DlgProc)->Buffer); - else if (Context->DlgProcSymbol) - SetDlgItemText(hwndDlg, IDC_DIALOGPROC, PhaFormatString(L"0x%Ix (%s)", Context->DlgProc, Context->DlgProcSymbol->Buffer)->Buffer); - else if (Context->DlgProc != 0) - SetDlgItemText(hwndDlg, IDC_DIALOGPROC, PhaFormatString(L"0x%Ix", Context->DlgProc)->Buffer); - else if (Context->WndProc != 0) - SetDlgItemText(hwndDlg, IDC_DIALOGPROC, L"N/A"); - else - SetDlgItemText(hwndDlg, IDC_DIALOGPROC, L"Unknown"); -} - -static VOID WepRefreshWindowGeneralInfo( - _In_ HWND hwndDlg, - _In_ PWINDOW_PROPERTIES_CONTEXT Context - ) -{ - WINDOWINFO windowInfo = { sizeof(WINDOWINFO) }; - WINDOWPLACEMENT windowPlacement = { sizeof(WINDOWPLACEMENT) }; - MONITORINFO monitorInfo = { sizeof(MONITORINFO) }; - - SetDlgItemText(hwndDlg, IDC_THREAD, PH_AUTO_T(PH_STRING, PhGetClientIdName(&Context->ClientId))->Buffer); - SetDlgItemText(hwndDlg, IDC_TEXT, PhGetStringOrEmpty(PH_AUTO(PhGetWindowText(Context->WindowHandle)))); - - if (GetWindowInfo(Context->WindowHandle, &windowInfo)) - { - SetDlgItemText(hwndDlg, IDC_RECTANGLE, WepFormatRect(&windowInfo.rcWindow)->Buffer); - SetDlgItemText(hwndDlg, IDC_CLIENTRECTANGLE, WepFormatRect(&windowInfo.rcClient)->Buffer); - } - else - { - SetDlgItemText(hwndDlg, IDC_RECTANGLE, L"N/A"); - SetDlgItemText(hwndDlg, IDC_CLIENTRECTANGLE, L"N/A"); - } - - if (GetWindowPlacement(Context->WindowHandle, &windowPlacement)) - { - // The rectangle is in workspace coordinates. Convert the values back to screen coordinates. - if (GetMonitorInfo(MonitorFromRect(&windowPlacement.rcNormalPosition, MONITOR_DEFAULTTOPRIMARY), &monitorInfo)) - { - windowPlacement.rcNormalPosition.left += monitorInfo.rcWork.left; - windowPlacement.rcNormalPosition.top += monitorInfo.rcWork.top; - windowPlacement.rcNormalPosition.right += monitorInfo.rcWork.left; - windowPlacement.rcNormalPosition.bottom += monitorInfo.rcWork.top; - } - - SetDlgItemText(hwndDlg, IDC_NORMALRECTANGLE, WepFormatRect(&windowPlacement.rcNormalPosition)->Buffer); - } - else - { - SetDlgItemText(hwndDlg, IDC_NORMALRECTANGLE, L"N/A"); - } - - SetDlgItemText(hwndDlg, IDC_INSTANCEHANDLE, PhaFormatString(L"0x%Ix", GetWindowLongPtr(Context->WindowHandle, GWLP_HINSTANCE))->Buffer); - SetDlgItemText(hwndDlg, IDC_MENUHANDLE, PhaFormatString(L"0x%Ix", GetMenu(Context->WindowHandle))->Buffer); - SetDlgItemText(hwndDlg, IDC_USERDATA, PhaFormatString(L"0x%Ix", GetWindowLongPtr(Context->WindowHandle, GWLP_USERDATA))->Buffer); - SetDlgItemText(hwndDlg, IDC_UNICODE, IsWindowUnicode(Context->WindowHandle) ? L"Yes" : L"No"); - SetDlgItemText(hwndDlg, IDC_CTRLID, PhaFormatString(L"%lu", GetWindowLongPtr(Context->WindowHandle, GWLP_ID))->Buffer); - - WepEnsureHookDataValid(Context); - - if (Context->WndProc != 0) - { - Context->WndProcResolving++; - WepQueueResolveSymbol(Context, hwndDlg, Context->WndProc, 1); - } - - if (Context->DlgProc != 0) - { - Context->DlgProcResolving++; - WepQueueResolveSymbol(Context, hwndDlg, Context->DlgProc, 2); - } - - WepRefreshWindowGeneralInfoSymbols(hwndDlg, Context); -} - -INT_PTR CALLBACK WepWindowGeneralDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - PWINDOW_PROPERTIES_CONTEXT context; - - if (!WepPropPageDlgProcHeader(hwndDlg, uMsg, lParam, NULL, &context)) - return FALSE; - - switch (uMsg) - { - case WM_INITDIALOG: - { - // HACK - PhCenterWindow(GetParent(hwndDlg), GetParent(GetParent(hwndDlg))); - - WepRefreshWindowGeneralInfo(hwndDlg, context); - } - break; - case WM_COMMAND: - { - switch (LOWORD(wParam)) - { - case IDC_REFRESH: - context->HookDataValid = FALSE; - PhClearReference(&context->WndProcSymbol); - WepRefreshWindowGeneralInfo(hwndDlg, context); - break; - } - } - break; - case WEM_RESOLVE_DONE: - { - PSYMBOL_RESOLVE_CONTEXT resolveContext = (PSYMBOL_RESOLVE_CONTEXT)lParam; - - if (resolveContext->Id == 1) - { - PhAcquireQueuedLockExclusive(&context->ResolveListLock); - RemoveEntryList(&resolveContext->ListEntry); - PhReleaseQueuedLockExclusive(&context->ResolveListLock); - - if (resolveContext->ResolveLevel != PhsrlModule && resolveContext->ResolveLevel != PhsrlFunction) - PhClearReference(&resolveContext->Symbol); - - PhMoveReference(&context->WndProcSymbol, resolveContext->Symbol); - PhFree(resolveContext); - - context->WndProcResolving--; - } - else if (resolveContext->Id == 2) - { - PhAcquireQueuedLockExclusive(&context->ResolveListLock); - RemoveEntryList(&resolveContext->ListEntry); - PhReleaseQueuedLockExclusive(&context->ResolveListLock); - - if (resolveContext->ResolveLevel != PhsrlModule && resolveContext->ResolveLevel != PhsrlFunction) - PhClearReference(&resolveContext->Symbol); - - PhMoveReference(&context->DlgProcSymbol, resolveContext->Symbol); - PhFree(resolveContext); - - context->DlgProcResolving--; - } - - WepRefreshWindowGeneralInfoSymbols(hwndDlg, context); - } - break; - } - - return FALSE; -} - -static VOID WepRefreshWindowStyles( - _In_ HWND hwndDlg, - _In_ PWINDOW_PROPERTIES_CONTEXT Context - ) -{ - WINDOWINFO windowInfo = { sizeof(WINDOWINFO) }; - HWND stylesListBox; - HWND extendedStylesListBox; - ULONG i; - - stylesListBox = GetDlgItem(hwndDlg, IDC_STYLESLIST); - extendedStylesListBox = GetDlgItem(hwndDlg, IDC_EXTENDEDSTYLESLIST); - - ListBox_ResetContent(stylesListBox); - ListBox_ResetContent(extendedStylesListBox); - - if (GetWindowInfo(Context->WindowHandle, &windowInfo)) - { - SetDlgItemText(hwndDlg, IDC_STYLES, PhaFormatString(L"0x%x", windowInfo.dwStyle)->Buffer); - SetDlgItemText(hwndDlg, IDC_EXTENDEDSTYLES, PhaFormatString(L"0x%x", windowInfo.dwExStyle)->Buffer); - - for (i = 0; i < sizeof(WepStylePairs) / sizeof(STRING_INTEGER_PAIR); i++) - { - if (windowInfo.dwStyle & WepStylePairs[i].Integer) - { - // Skip irrelevant styles. - - if (WepStylePairs[i].Integer == WS_MAXIMIZEBOX || - WepStylePairs[i].Integer == WS_MINIMIZEBOX) - { - if (windowInfo.dwStyle & WS_CHILD) - continue; - } - - if (WepStylePairs[i].Integer == WS_TABSTOP || - WepStylePairs[i].Integer == WS_GROUP) - { - if (!(windowInfo.dwStyle & WS_CHILD)) - continue; - } - - ListBox_AddString(stylesListBox, WepStylePairs[i].String); - } - } - - for (i = 0; i < sizeof(WepExtendedStylePairs) / sizeof(STRING_INTEGER_PAIR); i++) - { - if (windowInfo.dwExStyle & WepExtendedStylePairs[i].Integer) - { - ListBox_AddString(extendedStylesListBox, WepExtendedStylePairs[i].String); - } - } - } - else - { - SetDlgItemText(hwndDlg, IDC_STYLES, L"N/A"); - SetDlgItemText(hwndDlg, IDC_EXTENDEDSTYLES, L"N/A"); - } -} - -INT_PTR CALLBACK WepWindowStylesDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - PWINDOW_PROPERTIES_CONTEXT context; - - if (!WepPropPageDlgProcHeader(hwndDlg, uMsg, lParam, NULL, &context)) - return FALSE; - - switch (uMsg) - { - case WM_INITDIALOG: - { - WepRefreshWindowStyles(hwndDlg, context); - } - break; - case WM_COMMAND: - { - switch (LOWORD(wParam)) - { - case IDC_REFRESH: - WepRefreshWindowStyles(hwndDlg, context); - break; - } - } - break; - } - - return FALSE; -} - -static VOID WepRefreshWindowClassInfoSymbols( - _In_ HWND hwndDlg, - _In_ PWINDOW_PROPERTIES_CONTEXT Context - ) -{ - if (Context->ClassWndProcResolving != 0) - SetDlgItemText(hwndDlg, IDC_WINDOWPROC, PhaFormatString(L"0x%Ix (resolving...)", Context->ClassInfo.lpfnWndProc)->Buffer); - else if (Context->ClassWndProcSymbol) - SetDlgItemText(hwndDlg, IDC_WINDOWPROC, PhaFormatString(L"0x%Ix (%s)", Context->ClassInfo.lpfnWndProc, Context->ClassWndProcSymbol->Buffer)->Buffer); - else if (Context->ClassInfo.lpfnWndProc) - SetDlgItemText(hwndDlg, IDC_WINDOWPROC, PhaFormatString(L"0x%Ix", Context->ClassInfo.lpfnWndProc)->Buffer); - else - SetDlgItemText(hwndDlg, IDC_WINDOWPROC, L"Unknown"); -} - -static VOID WepRefreshWindowClassInfo( - _In_ HWND hwndDlg, - _In_ PWINDOW_PROPERTIES_CONTEXT Context - ) -{ - WCHAR className[256]; - PH_STRING_BUILDER stringBuilder; - ULONG i; - - if (!GetClassName(Context->WindowHandle, className, sizeof(className) / sizeof(WCHAR))) - className[0] = 0; - - WepEnsureHookDataValid(Context); - - if (!Context->HookDataSuccess) - { - Context->ClassInfo.cbSize = sizeof(WNDCLASSEX); - GetClassInfoEx(NULL, className, &Context->ClassInfo); - } - - SetDlgItemText(hwndDlg, IDC_NAME, className); - SetDlgItemText(hwndDlg, IDC_ATOM, PhaFormatString(L"0x%x", GetClassWord(Context->WindowHandle, GCW_ATOM))->Buffer); - SetDlgItemText(hwndDlg, IDC_INSTANCEHANDLE, PhaFormatString(L"0x%Ix", GetClassLongPtr(Context->WindowHandle, GCLP_HMODULE))->Buffer); - SetDlgItemText(hwndDlg, IDC_ICONHANDLE, PhaFormatString(L"0x%Ix", Context->ClassInfo.hIcon)->Buffer); - SetDlgItemText(hwndDlg, IDC_SMALLICONHANDLE, PhaFormatString(L"0x%Ix", Context->ClassInfo.hIconSm)->Buffer); - SetDlgItemText(hwndDlg, IDC_MENUNAME, PhaFormatString(L"0x%Ix", Context->ClassInfo.lpszMenuName)->Buffer); - - PhInitializeStringBuilder(&stringBuilder, 100); - PhAppendFormatStringBuilder(&stringBuilder, L"0x%x (", Context->ClassInfo.style); - - for (i = 0; i < sizeof(WepClassStylePairs) / sizeof(STRING_INTEGER_PAIR); i++) - { - if (Context->ClassInfo.style & WepClassStylePairs[i].Integer) - { - PhAppendStringBuilder2(&stringBuilder, WepClassStylePairs[i].String); - PhAppendStringBuilder2(&stringBuilder, L" | "); - } - } - - if (PhEndsWithString2(stringBuilder.String, L" | ", FALSE)) - { - PhRemoveEndStringBuilder(&stringBuilder, 3); - PhAppendCharStringBuilder(&stringBuilder, ')'); - } - else - { - // No styles. Remove the brackets. - PhRemoveEndStringBuilder(&stringBuilder, 1); - } - - SetDlgItemText(hwndDlg, IDC_STYLES, stringBuilder.String->Buffer); - PhDeleteStringBuilder(&stringBuilder); - - // TODO: Add symbols for these values. - SetDlgItemText(hwndDlg, IDC_CURSORHANDLE, PhaFormatString(L"0x%Ix", Context->ClassInfo.hCursor)->Buffer); - SetDlgItemText(hwndDlg, IDC_BACKGROUNDBRUSH, PhaFormatString(L"0x%Ix", Context->ClassInfo.hbrBackground)->Buffer); - - if (Context->ClassInfo.lpfnWndProc) - { - Context->ClassWndProcResolving++; - WepQueueResolveSymbol(Context, hwndDlg, (ULONG_PTR)Context->ClassInfo.lpfnWndProc, 0); - } - - WepRefreshWindowClassInfoSymbols(hwndDlg, Context); -} - -INT_PTR CALLBACK WepWindowClassDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - PWINDOW_PROPERTIES_CONTEXT context; - - if (!WepPropPageDlgProcHeader(hwndDlg, uMsg, lParam, NULL, &context)) - return FALSE; - - switch (uMsg) - { - case WM_INITDIALOG: - { - WepRefreshWindowClassInfo(hwndDlg, context); - } - break; - case WM_COMMAND: - { - switch (LOWORD(wParam)) - { - case IDC_REFRESH: - context->HookDataValid = FALSE; - PhClearReference(&context->ClassWndProcSymbol); - WepRefreshWindowClassInfo(hwndDlg, context); - break; - } - } - break; - case WEM_RESOLVE_DONE: - { - PSYMBOL_RESOLVE_CONTEXT resolveContext = (PSYMBOL_RESOLVE_CONTEXT)lParam; - - PhAcquireQueuedLockExclusive(&context->ResolveListLock); - RemoveEntryList(&resolveContext->ListEntry); - PhReleaseQueuedLockExclusive(&context->ResolveListLock); - - if (resolveContext->ResolveLevel != PhsrlModule && resolveContext->ResolveLevel != PhsrlFunction) - PhClearReference(&resolveContext->Symbol); - - PhMoveReference(&context->ClassWndProcSymbol, resolveContext->Symbol); - PhFree(resolveContext); - - context->ClassWndProcResolving--; - WepRefreshWindowClassInfoSymbols(hwndDlg, context); - } - break; - } - - return FALSE; -} - -static BOOL CALLBACK EnumPropsExCallback( - _In_ HWND hwnd, - _In_ LPTSTR lpszString, - _In_ HANDLE hData, - _In_ ULONG_PTR dwData - ) -{ - INT lvItemIndex; - PWSTR propName; - WCHAR value[PH_PTR_STR_LEN_1]; - - propName = lpszString; - - if ((ULONG_PTR)lpszString < USHRT_MAX) - { - // This is an integer atom. - propName = PhaFormatString(L"#%lu", (ULONG_PTR)lpszString)->Buffer; - } - - lvItemIndex = PhAddListViewItem((HWND)dwData, MAXINT, propName, NULL); - - PhPrintPointer(value, (PVOID)hData); - PhSetListViewSubItem((HWND)dwData, lvItemIndex, 1, value); - - return TRUE; -} - -static VOID WepRefreshWindowProps( - _In_ HWND hwndDlg, - _In_ HWND ListViewHandle, - _In_ PWINDOW_PROPERTIES_CONTEXT Context - ) -{ - ExtendedListView_SetRedraw(ListViewHandle, FALSE); - ListView_DeleteAllItems(ListViewHandle); - EnumPropsEx(Context->WindowHandle, EnumPropsExCallback, (LPARAM)ListViewHandle); - ExtendedListView_SortItems(ListViewHandle); - ExtendedListView_SetRedraw(ListViewHandle, TRUE); -} - -INT_PTR CALLBACK WepWindowPropertiesDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - PWINDOW_PROPERTIES_CONTEXT context; - - if (!WepPropPageDlgProcHeader(hwndDlg, uMsg, lParam, NULL, &context)) - return FALSE; - - switch (uMsg) - { - case WM_INITDIALOG: - { - HWND lvHandle; - - lvHandle = GetDlgItem(hwndDlg, IDC_LIST); - PhSetListViewStyle(lvHandle, FALSE, TRUE); - PhSetControlTheme(lvHandle, L"explorer"); - - PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 160, L"Name"); - PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 100, L"Value"); - PhSetExtendedListView(lvHandle); - - WepRefreshWindowProps(hwndDlg, lvHandle, context); - } - break; - case WM_COMMAND: - { - switch (LOWORD(wParam)) - { - case IDC_REFRESH: - WepRefreshWindowProps(hwndDlg, GetDlgItem(hwndDlg, IDC_LIST), context); - break; - } - } - break; - } - - return FALSE; -} +/* + * Process Hacker Window Explorer - + * window properties + * + * Copyright (C) 2011 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +// Since the main message loop doesn't support property sheets, we need a separate thread to run +// property sheets on. + +#include "wndexp.h" +#include "resource.h" +#include +#include +#include + +#define NUMBER_OF_PAGES 4 +#define WEM_RESOLVE_DONE (WM_APP + 1234) + +typedef struct _WINDOW_PROPERTIES_CONTEXT +{ + LONG RefCount; + + HWND ParentWindowHandle; + + HWND WindowHandle; + CLIENT_ID ClientId; + PH_INITONCE SymbolProviderInitOnce; + PPH_SYMBOL_PROVIDER SymbolProvider; + LIST_ENTRY ResolveListHead; + PH_QUEUED_LOCK ResolveListLock; + + PPH_STRING WndProcSymbol; + ULONG WndProcResolving; + PPH_STRING DlgProcSymbol; + ULONG DlgProcResolving; + PPH_STRING ClassWndProcSymbol; + ULONG ClassWndProcResolving; + + BOOLEAN HookDataValid; + BOOLEAN HookDataSuccess; + ULONG_PTR WndProc; + ULONG_PTR DlgProc; + WNDCLASSEX ClassInfo; +} WINDOW_PROPERTIES_CONTEXT, *PWINDOW_PROPERTIES_CONTEXT; + +typedef struct _SYMBOL_RESOLVE_CONTEXT +{ + LIST_ENTRY ListEntry; + ULONG64 Address; + PPH_STRING Symbol; + PH_SYMBOL_RESOLVE_LEVEL ResolveLevel; + HWND NotifyWindow; + PWINDOW_PROPERTIES_CONTEXT Context; + ULONG Id; +} SYMBOL_RESOLVE_CONTEXT, *PSYMBOL_RESOLVE_CONTEXT; + +typedef struct _STRING_INTEGER_PAIR +{ + PWSTR String; + ULONG Integer; +} STRING_INTEGER_PAIR, *PSTRING_INTEGER_PAIR; + +VOID WepReferenceWindowPropertiesContext( + _Inout_ PWINDOW_PROPERTIES_CONTEXT Context + ); + +VOID WepDereferenceWindowPropertiesContext( + _Inout_ PWINDOW_PROPERTIES_CONTEXT Context + ); + +HWND WepCreateWindowProperties( + _In_ PWINDOW_PROPERTIES_CONTEXT Context + ); + +INT CALLBACK WepPropSheetProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ LPARAM lParam + ); + +LRESULT CALLBACK WepPropSheetWndProc( + _In_ HWND hwnd, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +HPROPSHEETPAGE WepCommonCreatePage( + _In_ PWINDOW_PROPERTIES_CONTEXT Context, + _In_ PWSTR Template, + _In_ DLGPROC DlgProc + ); + +INT CALLBACK WepCommonPropPageProc( + _In_ HWND hwnd, + _In_ UINT uMsg, + _In_ LPPROPSHEETPAGE ppsp + ); + +NTSTATUS WepPropertiesThreadStart( + _In_ PVOID Parameter + ); + +INT_PTR CALLBACK WepWindowGeneralDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +INT_PTR CALLBACK WepWindowStylesDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +INT_PTR CALLBACK WepWindowClassDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +INT_PTR CALLBACK WepWindowPropertiesDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +#define DEFINE_PAIR(Symbol) { L#Symbol, Symbol } + +static STRING_INTEGER_PAIR WepStylePairs[] = +{ + DEFINE_PAIR(WS_POPUP), + DEFINE_PAIR(WS_CHILD), + DEFINE_PAIR(WS_MINIMIZE), + DEFINE_PAIR(WS_VISIBLE), + DEFINE_PAIR(WS_DISABLED), + DEFINE_PAIR(WS_CLIPSIBLINGS), + DEFINE_PAIR(WS_CLIPCHILDREN), + DEFINE_PAIR(WS_MAXIMIZE), + DEFINE_PAIR(WS_BORDER), + DEFINE_PAIR(WS_DLGFRAME), + DEFINE_PAIR(WS_VSCROLL), + DEFINE_PAIR(WS_HSCROLL), + DEFINE_PAIR(WS_SYSMENU), + DEFINE_PAIR(WS_THICKFRAME), + DEFINE_PAIR(WS_GROUP), + DEFINE_PAIR(WS_TABSTOP), + DEFINE_PAIR(WS_MINIMIZEBOX), + DEFINE_PAIR(WS_MAXIMIZEBOX) +}; + +static STRING_INTEGER_PAIR WepExtendedStylePairs[] = +{ + DEFINE_PAIR(WS_EX_DLGMODALFRAME), + DEFINE_PAIR(WS_EX_NOPARENTNOTIFY), + DEFINE_PAIR(WS_EX_TOPMOST), + DEFINE_PAIR(WS_EX_ACCEPTFILES), + DEFINE_PAIR(WS_EX_TRANSPARENT), + DEFINE_PAIR(WS_EX_MDICHILD), + DEFINE_PAIR(WS_EX_TOOLWINDOW), + DEFINE_PAIR(WS_EX_WINDOWEDGE), + DEFINE_PAIR(WS_EX_CLIENTEDGE), + DEFINE_PAIR(WS_EX_CONTEXTHELP), + DEFINE_PAIR(WS_EX_RIGHT), + DEFINE_PAIR(WS_EX_RTLREADING), + DEFINE_PAIR(WS_EX_LEFTSCROLLBAR), + DEFINE_PAIR(WS_EX_CONTROLPARENT), + DEFINE_PAIR(WS_EX_STATICEDGE), + DEFINE_PAIR(WS_EX_APPWINDOW), + DEFINE_PAIR(WS_EX_LAYERED), + DEFINE_PAIR(WS_EX_NOINHERITLAYOUT), + DEFINE_PAIR(WS_EX_LAYOUTRTL), + DEFINE_PAIR(WS_EX_COMPOSITED), + DEFINE_PAIR(WS_EX_NOACTIVATE) +}; + +static STRING_INTEGER_PAIR WepClassStylePairs[] = +{ + DEFINE_PAIR(CS_VREDRAW), + DEFINE_PAIR(CS_HREDRAW), + DEFINE_PAIR(CS_DBLCLKS), + DEFINE_PAIR(CS_OWNDC), + DEFINE_PAIR(CS_CLASSDC), + DEFINE_PAIR(CS_PARENTDC), + DEFINE_PAIR(CS_NOCLOSE), + DEFINE_PAIR(CS_SAVEBITS), + DEFINE_PAIR(CS_BYTEALIGNCLIENT), + DEFINE_PAIR(CS_BYTEALIGNWINDOW), + DEFINE_PAIR(CS_GLOBALCLASS), + DEFINE_PAIR(CS_IME), + DEFINE_PAIR(CS_DROPSHADOW) +}; + +HANDLE WePropertiesThreadHandle = NULL; +CLIENT_ID WePropertiesThreadClientId; +PH_EVENT WePropertiesThreadReadyEvent = PH_EVENT_INIT; +PPH_LIST WePropertiesCreateList; +PPH_LIST WePropertiesWindowList; +PH_QUEUED_LOCK WePropertiesCreateLock = PH_QUEUED_LOCK_INIT; + +VOID WeShowWindowProperties( + _In_ HWND ParentWindowHandle, + _In_ HWND WindowHandle + ) +{ + PWINDOW_PROPERTIES_CONTEXT context; + ULONG threadId; + ULONG processId; + + if (!WePropertiesCreateList) + WePropertiesCreateList = PhCreateList(4); + if (!WePropertiesWindowList) + WePropertiesWindowList = PhCreateList(4); + + if (!WePropertiesThreadHandle) + { + WePropertiesThreadHandle = PhCreateThread(0, WepPropertiesThreadStart, NULL); + PhWaitForEvent(&WePropertiesThreadReadyEvent, NULL); + } + + context = PhAllocate(sizeof(WINDOW_PROPERTIES_CONTEXT)); + memset(context, 0, sizeof(WINDOW_PROPERTIES_CONTEXT)); + context->RefCount = 1; + context->ParentWindowHandle = ParentWindowHandle; + context->WindowHandle = WindowHandle; + + processId = 0; + threadId = GetWindowThreadProcessId(WindowHandle, &processId); + context->ClientId.UniqueProcess = UlongToHandle(processId); + context->ClientId.UniqueThread = UlongToHandle(threadId); + PhInitializeInitOnce(&context->SymbolProviderInitOnce); + InitializeListHead(&context->ResolveListHead); + PhInitializeQueuedLock(&context->ResolveListLock); + + // Queue the window for creation and wake up the host thread. + PhAcquireQueuedLockExclusive(&WePropertiesCreateLock); + PhAddItemList(WePropertiesCreateList, context); + PhReleaseQueuedLockExclusive(&WePropertiesCreateLock); + PostThreadMessage(HandleToUlong(WePropertiesThreadClientId.UniqueThread), WM_NULL, 0, 0); +} + +VOID WepReferenceWindowPropertiesContext( + _Inout_ PWINDOW_PROPERTIES_CONTEXT Context + ) +{ + _InterlockedIncrement(&Context->RefCount); +} + +VOID WepDereferenceWindowPropertiesContext( + _Inout_ PWINDOW_PROPERTIES_CONTEXT Context + ) +{ + if (_InterlockedDecrement(&Context->RefCount) == 0) + { + PLIST_ENTRY listEntry; + + PhClearReference(&Context->SymbolProvider); + + // Destroy results that have not been processed by any property pages. + + listEntry = Context->ResolveListHead.Flink; + + while (listEntry != &Context->ResolveListHead) + { + PSYMBOL_RESOLVE_CONTEXT resolveContext; + + resolveContext = CONTAINING_RECORD(listEntry, SYMBOL_RESOLVE_CONTEXT, ListEntry); + listEntry = listEntry->Flink; + + PhClearReference(&resolveContext->Symbol); + PhFree(resolveContext); + } + + PhClearReference(&Context->WndProcSymbol); + PhClearReference(&Context->DlgProcSymbol); + PhClearReference(&Context->ClassWndProcSymbol); + + PhFree(Context); + } +} + +static HWND WepCreateWindowProperties( + _In_ PWINDOW_PROPERTIES_CONTEXT Context + ) +{ + PROPSHEETHEADER propSheetHeader = { sizeof(propSheetHeader) }; + HPROPSHEETPAGE pages[NUMBER_OF_PAGES]; + + propSheetHeader.dwFlags = + PSH_MODELESS | + PSH_NOAPPLYNOW | + PSH_NOCONTEXTHELP | + PSH_PROPTITLE | + PSH_USECALLBACK; + propSheetHeader.hwndParent = Context->ParentWindowHandle; + propSheetHeader.pszCaption = PhaFormatString(L"Window %Ix", Context->WindowHandle)->Buffer; + propSheetHeader.nPages = 0; + propSheetHeader.nStartPage = 0; + propSheetHeader.phpage = pages; + propSheetHeader.pfnCallback = WepPropSheetProc; + + // General + pages[propSheetHeader.nPages++] = WepCommonCreatePage( + Context, + MAKEINTRESOURCE(IDD_WNDGENERAL), + WepWindowGeneralDlgProc + ); + // Styles + pages[propSheetHeader.nPages++] = WepCommonCreatePage( + Context, + MAKEINTRESOURCE(IDD_WNDSTYLES), + WepWindowStylesDlgProc + ); + // Class + pages[propSheetHeader.nPages++] = WepCommonCreatePage( + Context, + MAKEINTRESOURCE(IDD_WNDCLASS), + WepWindowClassDlgProc + ); + // Properties + pages[propSheetHeader.nPages++] = WepCommonCreatePage( + Context, + MAKEINTRESOURCE(IDD_WNDPROPS), + WepWindowPropertiesDlgProc + ); + + return (HWND)PropertySheet(&propSheetHeader); +} + +static INT CALLBACK WepPropSheetProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ LPARAM lParam + ) +{ + switch (uMsg) + { + case PSCB_INITIALIZED: + { + WNDPROC oldWndProc; + HWND refreshButtonHandle; + + oldWndProc = (WNDPROC)GetWindowLongPtr(hwndDlg, GWLP_WNDPROC); + SetWindowLongPtr(hwndDlg, GWLP_WNDPROC, (LONG_PTR)WepPropSheetWndProc); + SetProp(hwndDlg, L"OldWndProc", (HANDLE)oldWndProc); + + // Hide the Cancel button. + ShowWindow(GetDlgItem(hwndDlg, IDCANCEL), SW_HIDE); + // Set the OK button's text to "Close". + SetDlgItemText(hwndDlg, IDOK, L"Close"); + // Add the Refresh button. + refreshButtonHandle = CreateWindow(L"BUTTON", L"Refresh", WS_CHILD | WS_TABSTOP | WS_VISIBLE, 0, 0, 3, 3, hwndDlg, (HMENU)IDC_REFRESH, + PluginInstance->DllBase, NULL); + SendMessage(refreshButtonHandle, WM_SETFONT, (WPARAM)SendMessage(GetDlgItem(hwndDlg, IDOK), WM_GETFONT, 0, 0), FALSE); + } + break; + } + + return 0; +} + +LRESULT CALLBACK WepPropSheetWndProc( + _In_ HWND hwnd, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + WNDPROC oldWndProc = (WNDPROC)GetProp(hwnd, L"OldWndProc"); + + switch (uMsg) + { + case WM_DESTROY: + { + SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)oldWndProc); + RemoveProp(hwnd, L"OldWndProc"); + RemoveProp(hwnd, L"Moved"); + } + break; + case WM_SHOWWINDOW: + { + if (!GetProp(hwnd, L"Moved")) + { + // Move the Refresh button to where the OK button is, and move the OK button to + // where the Cancel button is. + // This must be done here because in the prop sheet callback the buttons are not + // in the right places. + PhCopyControlRectangle(hwnd, GetDlgItem(hwnd, IDOK), GetDlgItem(hwnd, IDC_REFRESH)); + PhCopyControlRectangle(hwnd, GetDlgItem(hwnd, IDCANCEL), GetDlgItem(hwnd, IDOK)); + SetProp(hwnd, L"Moved", (HANDLE)1); + } + } + break; + case WM_COMMAND: + { + switch (LOWORD(wParam)) + { + case IDC_REFRESH: + { + ULONG i; + HWND pageHandle; + + // Broadcast the message to all property pages. + for (i = 0; i < NUMBER_OF_PAGES; i++) + { + if (pageHandle = PropSheet_IndexToHwnd(hwnd, i)) + SendMessage(pageHandle, WM_COMMAND, IDC_REFRESH, 0); + } + } + break; + } + } + break; + } + + return CallWindowProc(oldWndProc, hwnd, uMsg, wParam, lParam); +} + +static HPROPSHEETPAGE WepCommonCreatePage( + _In_ PWINDOW_PROPERTIES_CONTEXT Context, + _In_ PWSTR Template, + _In_ DLGPROC DlgProc + ) +{ + HPROPSHEETPAGE propSheetPageHandle; + PROPSHEETPAGE propSheetPage; + + memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); + propSheetPage.dwSize = sizeof(PROPSHEETPAGE); + propSheetPage.dwFlags = PSP_USECALLBACK; + propSheetPage.hInstance = PluginInstance->DllBase; + propSheetPage.pszTemplate = Template; + propSheetPage.pfnDlgProc = DlgProc; + propSheetPage.lParam = (LPARAM)Context; + propSheetPage.pfnCallback = WepCommonPropPageProc; + + propSheetPageHandle = CreatePropertySheetPage(&propSheetPage); + + return propSheetPageHandle; +} + +static INT CALLBACK WepCommonPropPageProc( + _In_ HWND hwnd, + _In_ UINT uMsg, + _In_ LPPROPSHEETPAGE ppsp + ) +{ + PWINDOW_PROPERTIES_CONTEXT context; + + context = (PWINDOW_PROPERTIES_CONTEXT)ppsp->lParam; + + if (uMsg == PSPCB_ADDREF) + WepReferenceWindowPropertiesContext(context); + else if (uMsg == PSPCB_RELEASE) + WepDereferenceWindowPropertiesContext(context); + + return 1; +} + +NTSTATUS WepPropertiesThreadStart( + _In_ PVOID Parameter + ) +{ + PH_AUTO_POOL autoPool; + BOOL result; + MSG message; + BOOLEAN processed; + ULONG i; + + PhInitializeAutoPool(&autoPool); + + WePropertiesThreadClientId = NtCurrentTeb()->ClientId; + + // Force the creation of the message queue so PostThreadMessage works. + PeekMessage(&message, NULL, WM_USER, WM_USER, PM_NOREMOVE); + PhSetEvent(&WePropertiesThreadReadyEvent); + + while (result = GetMessage(&message, NULL, 0, 0)) + { + if (result == -1) + break; + + if (WePropertiesCreateList->Count != 0) + { + PhAcquireQueuedLockExclusive(&WePropertiesCreateLock); + + for (i = 0; i < WePropertiesCreateList->Count; i++) + { + PWINDOW_PROPERTIES_CONTEXT context; + HWND hwnd; + + context = WePropertiesCreateList->Items[i]; + hwnd = WepCreateWindowProperties(context); + WepDereferenceWindowPropertiesContext(context); + PhAddItemList(WePropertiesWindowList, hwnd); + } + + PhClearList(WePropertiesCreateList); + PhReleaseQueuedLockExclusive(&WePropertiesCreateLock); + } + + processed = FALSE; + + for (i = 0; i < WePropertiesWindowList->Count; i++) + { + if (PropSheet_IsDialogMessage(WePropertiesWindowList->Items[i], &message)) + { + processed = TRUE; + break; + } + } + + if (!processed) + { + TranslateMessage(&message); + DispatchMessage(&message); + } + + // Destroy properties windows when necessary. + for (i = 0; i < WePropertiesWindowList->Count; i++) + { + if (!PropSheet_GetCurrentPageHwnd(WePropertiesWindowList->Items[i])) + { + DestroyWindow(WePropertiesWindowList->Items[i]); + PhRemoveItemList(WePropertiesWindowList, i); + i--; + } + } + + PhDrainAutoPool(&autoPool); + } + + PhDeleteAutoPool(&autoPool); + + return STATUS_SUCCESS; +} + +FORCEINLINE BOOLEAN WepPropPageDlgProcHeader( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ LPARAM lParam, + _Out_opt_ LPPROPSHEETPAGE *PropSheetPage, + _Out_opt_ PWINDOW_PROPERTIES_CONTEXT *Context + ) +{ + LPPROPSHEETPAGE propSheetPage; + + if (uMsg == WM_INITDIALOG) + { + propSheetPage = (LPPROPSHEETPAGE)lParam; + // Save the context. + SetProp(hwndDlg, L"PropSheetPage", (HANDLE)lParam); + } + else + { + propSheetPage = (LPPROPSHEETPAGE)GetProp(hwndDlg, L"PropSheetPage"); + + if (uMsg == WM_DESTROY) + RemoveProp(hwndDlg, L"PropSheetPage"); + } + + if (!propSheetPage) + return FALSE; + + if (PropSheetPage) + *PropSheetPage = propSheetPage; + if (Context) + *Context = (PWINDOW_PROPERTIES_CONTEXT)propSheetPage->lParam; + + return TRUE; +} + +static VOID WepEnsureHookDataValid( + _In_ PWINDOW_PROPERTIES_CONTEXT Context + ) +{ + if (!Context->HookDataValid) + { + PWE_HOOK_SHARED_DATA data; +#ifdef _WIN64 + HANDLE processHandle; + BOOLEAN isWow64 = FALSE; +#endif + + // The desktop window is owned by CSR. The hook will never work on the desktop window. + if (Context->WindowHandle == GetDesktopWindow()) + { + Context->HookDataValid = TRUE; + return; + } + +#ifdef _WIN64 + // We can't use the hook on WOW64 processes. + if (NT_SUCCESS(PhOpenProcess(&processHandle, *(PULONG)WeGetProcedureAddress("ProcessQueryAccess"), Context->ClientId.UniqueProcess))) + { + PhGetProcessIsWow64(processHandle, &isWow64); + NtClose(processHandle); + } + + if (isWow64) + return; +#endif + + WeHookServerInitialization(); + + Context->HookDataSuccess = FALSE; + + if (WeLockServerSharedData(&data)) + { + if (WeSendServerRequest(Context->WindowHandle)) + { + Context->WndProc = data->c.WndProc; + Context->DlgProc = data->c.DlgProc; + memcpy(&Context->ClassInfo, &data->c.ClassInfo, sizeof(WNDCLASSEX)); + Context->HookDataSuccess = TRUE; + } + + WeUnlockServerSharedData(); + } + + Context->HookDataValid = TRUE; + } +} + +static BOOLEAN NTAPI EnumGenericModulesCallback( + _In_ PPH_MODULE_INFO Module, + _In_opt_ PVOID Context + ) +{ + PWINDOW_PROPERTIES_CONTEXT context = Context; + + PhLoadModuleSymbolProvider(context->SymbolProvider, Module->FileName->Buffer, + (ULONG64)Module->BaseAddress, Module->Size); + + return TRUE; +} + +static NTSTATUS WepResolveSymbolFunction( + _In_ PVOID Parameter + ) +{ + PSYMBOL_RESOLVE_CONTEXT context = Parameter; + + if (PhBeginInitOnce(&context->Context->SymbolProviderInitOnce)) + { + PhEnumGenericModules(context->Context->ClientId.UniqueProcess, NULL, 0, EnumGenericModulesCallback, context->Context); + PhEndInitOnce(&context->Context->SymbolProviderInitOnce); + } + + context->Symbol = PhGetSymbolFromAddress( + context->Context->SymbolProvider, + (ULONG64)context->Address, + &context->ResolveLevel, + NULL, + NULL, + NULL + ); + + // Fail if we don't have a symbol. + if (!context->Symbol) + { + WepDereferenceWindowPropertiesContext(context->Context); + PhFree(context); + return STATUS_SUCCESS; + } + + PhAcquireQueuedLockExclusive(&context->Context->ResolveListLock); + InsertHeadList(&context->Context->ResolveListHead, &context->ListEntry); + PhReleaseQueuedLockExclusive(&context->Context->ResolveListLock); + + PostMessage(context->NotifyWindow, WEM_RESOLVE_DONE, 0, (LPARAM)context); + + WepDereferenceWindowPropertiesContext(context->Context); + + return STATUS_SUCCESS; +} + +static VOID WepQueueResolveSymbol( + _In_ PWINDOW_PROPERTIES_CONTEXT Context, + _In_ HWND NotifyWindow, + _In_ ULONG64 Address, + _In_ ULONG Id + ) +{ + PSYMBOL_RESOLVE_CONTEXT resolveContext; + + if (!Context->SymbolProvider) + { + Context->SymbolProvider = PhCreateSymbolProvider(Context->ClientId.UniqueProcess); + PhLoadSymbolProviderOptions(Context->SymbolProvider); + } + + resolveContext = PhAllocate(sizeof(SYMBOL_RESOLVE_CONTEXT)); + resolveContext->Address = Address; + resolveContext->Symbol = NULL; + resolveContext->ResolveLevel = PhsrlInvalid; + resolveContext->NotifyWindow = NotifyWindow; + resolveContext->Context = Context; + WepReferenceWindowPropertiesContext(Context); + resolveContext->Id = Id; + + PhQueueItemWorkQueue(PhGetGlobalWorkQueue(), WepResolveSymbolFunction, resolveContext); +} + +static PPH_STRING WepFormatRect( + _In_ PRECT Rect + ) +{ + return PhaFormatString(L"(%d, %d) - (%d, %d) [%dx%d]", + Rect->left, Rect->top, Rect->right, Rect->bottom, + Rect->right - Rect->left, Rect->bottom - Rect->top); +} + +static VOID WepRefreshWindowGeneralInfoSymbols( + _In_ HWND hwndDlg, + _In_ PWINDOW_PROPERTIES_CONTEXT Context + ) +{ + if (Context->WndProcResolving != 0) + SetDlgItemText(hwndDlg, IDC_WINDOWPROC, PhaFormatString(L"0x%Ix (resolving...)", Context->WndProc)->Buffer); + else if (Context->WndProcSymbol) + SetDlgItemText(hwndDlg, IDC_WINDOWPROC, PhaFormatString(L"0x%Ix (%s)", Context->WndProc, Context->WndProcSymbol->Buffer)->Buffer); + else if (Context->WndProc != 0) + SetDlgItemText(hwndDlg, IDC_WINDOWPROC, PhaFormatString(L"0x%Ix", Context->WndProc)->Buffer); + else + SetDlgItemText(hwndDlg, IDC_WINDOWPROC, L"Unknown"); + + if (Context->DlgProcResolving != 0) + SetDlgItemText(hwndDlg, IDC_DIALOGPROC, PhaFormatString(L"0x%Ix (resolving...)", Context->DlgProc)->Buffer); + else if (Context->DlgProcSymbol) + SetDlgItemText(hwndDlg, IDC_DIALOGPROC, PhaFormatString(L"0x%Ix (%s)", Context->DlgProc, Context->DlgProcSymbol->Buffer)->Buffer); + else if (Context->DlgProc != 0) + SetDlgItemText(hwndDlg, IDC_DIALOGPROC, PhaFormatString(L"0x%Ix", Context->DlgProc)->Buffer); + else if (Context->WndProc != 0) + SetDlgItemText(hwndDlg, IDC_DIALOGPROC, L"N/A"); + else + SetDlgItemText(hwndDlg, IDC_DIALOGPROC, L"Unknown"); +} + +static VOID WepRefreshWindowGeneralInfo( + _In_ HWND hwndDlg, + _In_ PWINDOW_PROPERTIES_CONTEXT Context + ) +{ + WINDOWINFO windowInfo = { sizeof(WINDOWINFO) }; + WINDOWPLACEMENT windowPlacement = { sizeof(WINDOWPLACEMENT) }; + MONITORINFO monitorInfo = { sizeof(MONITORINFO) }; + + SetDlgItemText(hwndDlg, IDC_THREAD, PH_AUTO_T(PH_STRING, PhGetClientIdName(&Context->ClientId))->Buffer); + SetDlgItemText(hwndDlg, IDC_TEXT, PhGetStringOrEmpty(PH_AUTO(PhGetWindowText(Context->WindowHandle)))); + + if (GetWindowInfo(Context->WindowHandle, &windowInfo)) + { + SetDlgItemText(hwndDlg, IDC_RECTANGLE, WepFormatRect(&windowInfo.rcWindow)->Buffer); + SetDlgItemText(hwndDlg, IDC_CLIENTRECTANGLE, WepFormatRect(&windowInfo.rcClient)->Buffer); + } + else + { + SetDlgItemText(hwndDlg, IDC_RECTANGLE, L"N/A"); + SetDlgItemText(hwndDlg, IDC_CLIENTRECTANGLE, L"N/A"); + } + + if (GetWindowPlacement(Context->WindowHandle, &windowPlacement)) + { + // The rectangle is in workspace coordinates. Convert the values back to screen coordinates. + if (GetMonitorInfo(MonitorFromRect(&windowPlacement.rcNormalPosition, MONITOR_DEFAULTTOPRIMARY), &monitorInfo)) + { + windowPlacement.rcNormalPosition.left += monitorInfo.rcWork.left; + windowPlacement.rcNormalPosition.top += monitorInfo.rcWork.top; + windowPlacement.rcNormalPosition.right += monitorInfo.rcWork.left; + windowPlacement.rcNormalPosition.bottom += monitorInfo.rcWork.top; + } + + SetDlgItemText(hwndDlg, IDC_NORMALRECTANGLE, WepFormatRect(&windowPlacement.rcNormalPosition)->Buffer); + } + else + { + SetDlgItemText(hwndDlg, IDC_NORMALRECTANGLE, L"N/A"); + } + + SetDlgItemText(hwndDlg, IDC_INSTANCEHANDLE, PhaFormatString(L"0x%Ix", GetWindowLongPtr(Context->WindowHandle, GWLP_HINSTANCE))->Buffer); + SetDlgItemText(hwndDlg, IDC_MENUHANDLE, PhaFormatString(L"0x%Ix", GetMenu(Context->WindowHandle))->Buffer); + SetDlgItemText(hwndDlg, IDC_USERDATA, PhaFormatString(L"0x%Ix", GetWindowLongPtr(Context->WindowHandle, GWLP_USERDATA))->Buffer); + SetDlgItemText(hwndDlg, IDC_UNICODE, IsWindowUnicode(Context->WindowHandle) ? L"Yes" : L"No"); + SetDlgItemText(hwndDlg, IDC_CTRLID, PhaFormatString(L"%lu", GetWindowLongPtr(Context->WindowHandle, GWLP_ID))->Buffer); + + WepEnsureHookDataValid(Context); + + if (Context->WndProc != 0) + { + Context->WndProcResolving++; + WepQueueResolveSymbol(Context, hwndDlg, Context->WndProc, 1); + } + + if (Context->DlgProc != 0) + { + Context->DlgProcResolving++; + WepQueueResolveSymbol(Context, hwndDlg, Context->DlgProc, 2); + } + + WepRefreshWindowGeneralInfoSymbols(hwndDlg, Context); +} + +INT_PTR CALLBACK WepWindowGeneralDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + PWINDOW_PROPERTIES_CONTEXT context; + + if (!WepPropPageDlgProcHeader(hwndDlg, uMsg, lParam, NULL, &context)) + return FALSE; + + switch (uMsg) + { + case WM_INITDIALOG: + { + // HACK + PhCenterWindow(GetParent(hwndDlg), GetParent(GetParent(hwndDlg))); + + WepRefreshWindowGeneralInfo(hwndDlg, context); + } + break; + case WM_COMMAND: + { + switch (LOWORD(wParam)) + { + case IDC_REFRESH: + context->HookDataValid = FALSE; + PhClearReference(&context->WndProcSymbol); + WepRefreshWindowGeneralInfo(hwndDlg, context); + break; + } + } + break; + case WEM_RESOLVE_DONE: + { + PSYMBOL_RESOLVE_CONTEXT resolveContext = (PSYMBOL_RESOLVE_CONTEXT)lParam; + + if (resolveContext->Id == 1) + { + PhAcquireQueuedLockExclusive(&context->ResolveListLock); + RemoveEntryList(&resolveContext->ListEntry); + PhReleaseQueuedLockExclusive(&context->ResolveListLock); + + if (resolveContext->ResolveLevel != PhsrlModule && resolveContext->ResolveLevel != PhsrlFunction) + PhClearReference(&resolveContext->Symbol); + + PhMoveReference(&context->WndProcSymbol, resolveContext->Symbol); + PhFree(resolveContext); + + context->WndProcResolving--; + } + else if (resolveContext->Id == 2) + { + PhAcquireQueuedLockExclusive(&context->ResolveListLock); + RemoveEntryList(&resolveContext->ListEntry); + PhReleaseQueuedLockExclusive(&context->ResolveListLock); + + if (resolveContext->ResolveLevel != PhsrlModule && resolveContext->ResolveLevel != PhsrlFunction) + PhClearReference(&resolveContext->Symbol); + + PhMoveReference(&context->DlgProcSymbol, resolveContext->Symbol); + PhFree(resolveContext); + + context->DlgProcResolving--; + } + + WepRefreshWindowGeneralInfoSymbols(hwndDlg, context); + } + break; + } + + return FALSE; +} + +static VOID WepRefreshWindowStyles( + _In_ HWND hwndDlg, + _In_ PWINDOW_PROPERTIES_CONTEXT Context + ) +{ + WINDOWINFO windowInfo = { sizeof(WINDOWINFO) }; + HWND stylesListBox; + HWND extendedStylesListBox; + ULONG i; + + stylesListBox = GetDlgItem(hwndDlg, IDC_STYLESLIST); + extendedStylesListBox = GetDlgItem(hwndDlg, IDC_EXTENDEDSTYLESLIST); + + ListBox_ResetContent(stylesListBox); + ListBox_ResetContent(extendedStylesListBox); + + if (GetWindowInfo(Context->WindowHandle, &windowInfo)) + { + SetDlgItemText(hwndDlg, IDC_STYLES, PhaFormatString(L"0x%x", windowInfo.dwStyle)->Buffer); + SetDlgItemText(hwndDlg, IDC_EXTENDEDSTYLES, PhaFormatString(L"0x%x", windowInfo.dwExStyle)->Buffer); + + for (i = 0; i < sizeof(WepStylePairs) / sizeof(STRING_INTEGER_PAIR); i++) + { + if (windowInfo.dwStyle & WepStylePairs[i].Integer) + { + // Skip irrelevant styles. + + if (WepStylePairs[i].Integer == WS_MAXIMIZEBOX || + WepStylePairs[i].Integer == WS_MINIMIZEBOX) + { + if (windowInfo.dwStyle & WS_CHILD) + continue; + } + + if (WepStylePairs[i].Integer == WS_TABSTOP || + WepStylePairs[i].Integer == WS_GROUP) + { + if (!(windowInfo.dwStyle & WS_CHILD)) + continue; + } + + ListBox_AddString(stylesListBox, WepStylePairs[i].String); + } + } + + for (i = 0; i < sizeof(WepExtendedStylePairs) / sizeof(STRING_INTEGER_PAIR); i++) + { + if (windowInfo.dwExStyle & WepExtendedStylePairs[i].Integer) + { + ListBox_AddString(extendedStylesListBox, WepExtendedStylePairs[i].String); + } + } + } + else + { + SetDlgItemText(hwndDlg, IDC_STYLES, L"N/A"); + SetDlgItemText(hwndDlg, IDC_EXTENDEDSTYLES, L"N/A"); + } +} + +INT_PTR CALLBACK WepWindowStylesDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + PWINDOW_PROPERTIES_CONTEXT context; + + if (!WepPropPageDlgProcHeader(hwndDlg, uMsg, lParam, NULL, &context)) + return FALSE; + + switch (uMsg) + { + case WM_INITDIALOG: + { + WepRefreshWindowStyles(hwndDlg, context); + } + break; + case WM_COMMAND: + { + switch (LOWORD(wParam)) + { + case IDC_REFRESH: + WepRefreshWindowStyles(hwndDlg, context); + break; + } + } + break; + } + + return FALSE; +} + +static VOID WepRefreshWindowClassInfoSymbols( + _In_ HWND hwndDlg, + _In_ PWINDOW_PROPERTIES_CONTEXT Context + ) +{ + if (Context->ClassWndProcResolving != 0) + SetDlgItemText(hwndDlg, IDC_WINDOWPROC, PhaFormatString(L"0x%Ix (resolving...)", Context->ClassInfo.lpfnWndProc)->Buffer); + else if (Context->ClassWndProcSymbol) + SetDlgItemText(hwndDlg, IDC_WINDOWPROC, PhaFormatString(L"0x%Ix (%s)", Context->ClassInfo.lpfnWndProc, Context->ClassWndProcSymbol->Buffer)->Buffer); + else if (Context->ClassInfo.lpfnWndProc) + SetDlgItemText(hwndDlg, IDC_WINDOWPROC, PhaFormatString(L"0x%Ix", Context->ClassInfo.lpfnWndProc)->Buffer); + else + SetDlgItemText(hwndDlg, IDC_WINDOWPROC, L"Unknown"); +} + +static VOID WepRefreshWindowClassInfo( + _In_ HWND hwndDlg, + _In_ PWINDOW_PROPERTIES_CONTEXT Context + ) +{ + WCHAR className[256]; + PH_STRING_BUILDER stringBuilder; + ULONG i; + + if (!GetClassName(Context->WindowHandle, className, sizeof(className) / sizeof(WCHAR))) + className[0] = 0; + + WepEnsureHookDataValid(Context); + + if (!Context->HookDataSuccess) + { + Context->ClassInfo.cbSize = sizeof(WNDCLASSEX); + GetClassInfoEx(NULL, className, &Context->ClassInfo); + } + + SetDlgItemText(hwndDlg, IDC_NAME, className); + SetDlgItemText(hwndDlg, IDC_ATOM, PhaFormatString(L"0x%x", GetClassWord(Context->WindowHandle, GCW_ATOM))->Buffer); + SetDlgItemText(hwndDlg, IDC_INSTANCEHANDLE, PhaFormatString(L"0x%Ix", GetClassLongPtr(Context->WindowHandle, GCLP_HMODULE))->Buffer); + SetDlgItemText(hwndDlg, IDC_ICONHANDLE, PhaFormatString(L"0x%Ix", Context->ClassInfo.hIcon)->Buffer); + SetDlgItemText(hwndDlg, IDC_SMALLICONHANDLE, PhaFormatString(L"0x%Ix", Context->ClassInfo.hIconSm)->Buffer); + SetDlgItemText(hwndDlg, IDC_MENUNAME, PhaFormatString(L"0x%Ix", Context->ClassInfo.lpszMenuName)->Buffer); + + PhInitializeStringBuilder(&stringBuilder, 100); + PhAppendFormatStringBuilder(&stringBuilder, L"0x%x (", Context->ClassInfo.style); + + for (i = 0; i < sizeof(WepClassStylePairs) / sizeof(STRING_INTEGER_PAIR); i++) + { + if (Context->ClassInfo.style & WepClassStylePairs[i].Integer) + { + PhAppendStringBuilder2(&stringBuilder, WepClassStylePairs[i].String); + PhAppendStringBuilder2(&stringBuilder, L" | "); + } + } + + if (PhEndsWithString2(stringBuilder.String, L" | ", FALSE)) + { + PhRemoveEndStringBuilder(&stringBuilder, 3); + PhAppendCharStringBuilder(&stringBuilder, ')'); + } + else + { + // No styles. Remove the brackets. + PhRemoveEndStringBuilder(&stringBuilder, 1); + } + + SetDlgItemText(hwndDlg, IDC_STYLES, stringBuilder.String->Buffer); + PhDeleteStringBuilder(&stringBuilder); + + // TODO: Add symbols for these values. + SetDlgItemText(hwndDlg, IDC_CURSORHANDLE, PhaFormatString(L"0x%Ix", Context->ClassInfo.hCursor)->Buffer); + SetDlgItemText(hwndDlg, IDC_BACKGROUNDBRUSH, PhaFormatString(L"0x%Ix", Context->ClassInfo.hbrBackground)->Buffer); + + if (Context->ClassInfo.lpfnWndProc) + { + Context->ClassWndProcResolving++; + WepQueueResolveSymbol(Context, hwndDlg, (ULONG_PTR)Context->ClassInfo.lpfnWndProc, 0); + } + + WepRefreshWindowClassInfoSymbols(hwndDlg, Context); +} + +INT_PTR CALLBACK WepWindowClassDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + PWINDOW_PROPERTIES_CONTEXT context; + + if (!WepPropPageDlgProcHeader(hwndDlg, uMsg, lParam, NULL, &context)) + return FALSE; + + switch (uMsg) + { + case WM_INITDIALOG: + { + WepRefreshWindowClassInfo(hwndDlg, context); + } + break; + case WM_COMMAND: + { + switch (LOWORD(wParam)) + { + case IDC_REFRESH: + context->HookDataValid = FALSE; + PhClearReference(&context->ClassWndProcSymbol); + WepRefreshWindowClassInfo(hwndDlg, context); + break; + } + } + break; + case WEM_RESOLVE_DONE: + { + PSYMBOL_RESOLVE_CONTEXT resolveContext = (PSYMBOL_RESOLVE_CONTEXT)lParam; + + PhAcquireQueuedLockExclusive(&context->ResolveListLock); + RemoveEntryList(&resolveContext->ListEntry); + PhReleaseQueuedLockExclusive(&context->ResolveListLock); + + if (resolveContext->ResolveLevel != PhsrlModule && resolveContext->ResolveLevel != PhsrlFunction) + PhClearReference(&resolveContext->Symbol); + + PhMoveReference(&context->ClassWndProcSymbol, resolveContext->Symbol); + PhFree(resolveContext); + + context->ClassWndProcResolving--; + WepRefreshWindowClassInfoSymbols(hwndDlg, context); + } + break; + } + + return FALSE; +} + +static BOOL CALLBACK EnumPropsExCallback( + _In_ HWND hwnd, + _In_ LPTSTR lpszString, + _In_ HANDLE hData, + _In_ ULONG_PTR dwData + ) +{ + INT lvItemIndex; + PWSTR propName; + WCHAR value[PH_PTR_STR_LEN_1]; + + propName = lpszString; + + if ((ULONG_PTR)lpszString < USHRT_MAX) + { + // This is an integer atom. + propName = PhaFormatString(L"#%lu", (ULONG_PTR)lpszString)->Buffer; + } + + lvItemIndex = PhAddListViewItem((HWND)dwData, MAXINT, propName, NULL); + + PhPrintPointer(value, (PVOID)hData); + PhSetListViewSubItem((HWND)dwData, lvItemIndex, 1, value); + + return TRUE; +} + +static VOID WepRefreshWindowProps( + _In_ HWND hwndDlg, + _In_ HWND ListViewHandle, + _In_ PWINDOW_PROPERTIES_CONTEXT Context + ) +{ + ExtendedListView_SetRedraw(ListViewHandle, FALSE); + ListView_DeleteAllItems(ListViewHandle); + EnumPropsEx(Context->WindowHandle, EnumPropsExCallback, (LPARAM)ListViewHandle); + ExtendedListView_SortItems(ListViewHandle); + ExtendedListView_SetRedraw(ListViewHandle, TRUE); +} + +INT_PTR CALLBACK WepWindowPropertiesDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + PWINDOW_PROPERTIES_CONTEXT context; + + if (!WepPropPageDlgProcHeader(hwndDlg, uMsg, lParam, NULL, &context)) + return FALSE; + + switch (uMsg) + { + case WM_INITDIALOG: + { + HWND lvHandle; + + lvHandle = GetDlgItem(hwndDlg, IDC_LIST); + PhSetListViewStyle(lvHandle, FALSE, TRUE); + PhSetControlTheme(lvHandle, L"explorer"); + + PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 160, L"Name"); + PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 100, L"Value"); + PhSetExtendedListView(lvHandle); + + WepRefreshWindowProps(hwndDlg, lvHandle, context); + } + break; + case WM_COMMAND: + { + switch (LOWORD(wParam)) + { + case IDC_REFRESH: + WepRefreshWindowProps(hwndDlg, GetDlgItem(hwndDlg, IDC_LIST), context); + break; + } + } + break; + } + + return FALSE; +} diff --git a/plugins/WindowExplorer/wndtree.c b/plugins/WindowExplorer/wndtree.c index db75a7180a75..a18b545b90e5 100644 --- a/plugins/WindowExplorer/wndtree.c +++ b/plugins/WindowExplorer/wndtree.c @@ -1,572 +1,572 @@ -/* - * Process Hacker Window Explorer - - * window treelist - * - * Copyright (C) 2011 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include "wndexp.h" -#include "resource.h" - -BOOLEAN WepWindowNodeHashtableEqualFunction( - _In_ PVOID Entry1, - _In_ PVOID Entry2 - ); - -ULONG WepWindowNodeHashtableHashFunction( - _In_ PVOID Entry - ); - -VOID WepDestroyWindowNode( - _In_ PWE_WINDOW_NODE WindowNode - ); - -BOOLEAN NTAPI WepWindowTreeNewCallback( - _In_ HWND hwnd, - _In_ PH_TREENEW_MESSAGE Message, - _In_opt_ PVOID Parameter1, - _In_opt_ PVOID Parameter2, - _In_opt_ PVOID Context - ); - -BOOLEAN WordMatchStringRef( - _Inout_ PWE_WINDOW_TREE_CONTEXT Context, - _In_ PPH_STRINGREF Text - ) -{ - PH_STRINGREF part; - PH_STRINGREF remainingPart; - - remainingPart = Context->SearchboxText->sr; - - while (remainingPart.Length != 0) - { - PhSplitStringRefAtChar(&remainingPart, '|', &part, &remainingPart); - - if (part.Length != 0) - { - if (PhFindStringInStringRef(Text, &part, TRUE) != -1) - return TRUE; - } - } - - return FALSE; -} - -BOOLEAN WordMatchStringZ( - _Inout_ PWE_WINDOW_TREE_CONTEXT Context, - _In_ PWSTR Text - ) -{ - PH_STRINGREF text; - - PhInitializeStringRef(&text, Text); - - return WordMatchStringRef(Context, &text); -} - -BOOLEAN WeWindowTreeFilterCallback( - _In_ PPH_TREENEW_NODE Node, - _In_opt_ PVOID Context - ) -{ - PWE_WINDOW_TREE_CONTEXT context = Context; - PWE_WINDOW_NODE windowNode = (PWE_WINDOW_NODE)Node; - - if (PhIsNullOrEmptyString(context->SearchboxText)) - return TRUE; - - if (windowNode->WindowClass[0]) - { - if (WordMatchStringZ(context, windowNode->WindowClass)) - return TRUE; - } - - if (windowNode->WindowHandleString[0]) - { - if (WordMatchStringZ(context, windowNode->WindowHandleString)) - return TRUE; - } - - if (!PhIsNullOrEmptyString(windowNode->WindowText)) - { - if (WordMatchStringRef(context, &windowNode->WindowText->sr)) - return TRUE; - } - - if (!PhIsNullOrEmptyString(windowNode->ThreadString)) - { - if (WordMatchStringRef(context, &windowNode->ThreadString->sr)) - return TRUE; - } - - return FALSE; -} - -VOID WeInitializeWindowTree( - _In_ HWND ParentWindowHandle, - _In_ HWND TreeNewHandle, - _Out_ PWE_WINDOW_TREE_CONTEXT Context - ) -{ - HWND hwnd; - PPH_STRING settings; - - memset(Context, 0, sizeof(WE_WINDOW_TREE_CONTEXT)); - - Context->NodeHashtable = PhCreateHashtable( - sizeof(PWE_WINDOW_NODE), - WepWindowNodeHashtableEqualFunction, - WepWindowNodeHashtableHashFunction, - 100 - ); - Context->NodeList = PhCreateList(100); - Context->NodeRootList = PhCreateList(30); - - Context->ParentWindowHandle = ParentWindowHandle; - Context->TreeNewHandle = TreeNewHandle; - hwnd = TreeNewHandle; - PhSetControlTheme(hwnd, L"explorer"); - - TreeNew_SetCallback(hwnd, WepWindowTreeNewCallback, Context); - - PhAddTreeNewColumn(hwnd, WEWNTLC_CLASS, TRUE, L"Class", 180, PH_ALIGN_LEFT, 0, 0); - PhAddTreeNewColumn(hwnd, WEWNTLC_HANDLE, TRUE, L"Handle", 70, PH_ALIGN_LEFT, 1, 0); - PhAddTreeNewColumn(hwnd, WEWNTLC_TEXT, TRUE, L"Text", 220, PH_ALIGN_LEFT, 2, 0); - PhAddTreeNewColumn(hwnd, WEWNTLC_THREAD, TRUE, L"Thread", 150, PH_ALIGN_LEFT, 3, 0); - - TreeNew_SetTriState(hwnd, TRUE); - TreeNew_SetSort(hwnd, WEWNTLC_CLASS, NoSortOrder); - - settings = PhGetStringSetting(SETTING_NAME_WINDOW_TREE_LIST_COLUMNS); - PhCmLoadSettings(hwnd, &settings->sr); - PhDereferenceObject(settings); - - Context->SearchboxText = PhReferenceEmptyString(); - - PhInitializeTreeNewFilterSupport( - &Context->FilterSupport, - Context->TreeNewHandle, - Context->NodeList - ); - - Context->TreeFilterEntry = PhAddTreeNewFilter( - &Context->FilterSupport, - WeWindowTreeFilterCallback, - Context - ); -} - -VOID WeDeleteWindowTree( - _In_ PWE_WINDOW_TREE_CONTEXT Context - ) -{ - PPH_STRING settings; - ULONG i; - - PhDeleteTreeNewFilterSupport(&Context->FilterSupport); - - settings = PhCmSaveSettings(Context->TreeNewHandle); - PhSetStringSetting2(SETTING_NAME_WINDOW_TREE_LIST_COLUMNS, &settings->sr); - PhDereferenceObject(settings); - - for (i = 0; i < Context->NodeList->Count; i++) - WepDestroyWindowNode(Context->NodeList->Items[i]); - - PhDereferenceObject(Context->NodeHashtable); - PhDereferenceObject(Context->NodeList); - PhDereferenceObject(Context->NodeRootList); -} - -BOOLEAN WepWindowNodeHashtableEqualFunction( - _In_ PVOID Entry1, - _In_ PVOID Entry2 - ) -{ - PWE_WINDOW_NODE windowNode1 = *(PWE_WINDOW_NODE *)Entry1; - PWE_WINDOW_NODE windowNode2 = *(PWE_WINDOW_NODE *)Entry2; - - return windowNode1->WindowHandle == windowNode2->WindowHandle; -} - -ULONG WepWindowNodeHashtableHashFunction( - _In_ PVOID Entry - ) -{ - return PhHashIntPtr((ULONG_PTR)(*(PWE_WINDOW_NODE *)Entry)->WindowHandle); -} - -PWE_WINDOW_NODE WeAddWindowNode( - _Inout_ PWE_WINDOW_TREE_CONTEXT Context - ) -{ - PWE_WINDOW_NODE windowNode; - - windowNode = PhAllocate(sizeof(WE_WINDOW_NODE)); - memset(windowNode, 0, sizeof(WE_WINDOW_NODE)); - PhInitializeTreeNewNode(&windowNode->Node); - - memset(windowNode->TextCache, 0, sizeof(PH_STRINGREF) * WEWNTLC_MAXIMUM); - windowNode->Node.TextCache = windowNode->TextCache; - windowNode->Node.TextCacheSize = WEWNTLC_MAXIMUM; - - windowNode->Children = PhCreateList(1); - - PhAddEntryHashtable(Context->NodeHashtable, &windowNode); - PhAddItemList(Context->NodeList, windowNode); - - if (Context->FilterSupport.FilterList) - windowNode->Node.Visible = PhApplyTreeNewFiltersToNode(&Context->FilterSupport, &windowNode->Node); - - //TreeNew_NodesStructured(Context->TreeNewHandle); - - return windowNode; -} - -PWE_WINDOW_NODE WeFindWindowNode( - _In_ PWE_WINDOW_TREE_CONTEXT Context, - _In_ HWND WindowHandle - ) -{ - WE_WINDOW_NODE lookupWindowNode; - PWE_WINDOW_NODE lookupWindowNodePtr = &lookupWindowNode; - PWE_WINDOW_NODE *windowNode; - - lookupWindowNode.WindowHandle = WindowHandle; - - windowNode = (PWE_WINDOW_NODE *)PhFindEntryHashtable( - Context->NodeHashtable, - &lookupWindowNodePtr - ); - - if (windowNode) - return *windowNode; - else - return NULL; -} - -VOID WeRemoveWindowNode( - _In_ PWE_WINDOW_TREE_CONTEXT Context, - _In_ PWE_WINDOW_NODE WindowNode - ) -{ - ULONG index; - - // Remove from hashtable/list and cleanup. - - PhRemoveEntryHashtable(Context->NodeHashtable, &WindowNode); - - if ((index = PhFindItemList(Context->NodeList, WindowNode)) != -1) - PhRemoveItemList(Context->NodeList, index); - - WepDestroyWindowNode(WindowNode); - - TreeNew_NodesStructured(Context->TreeNewHandle); -} - -VOID WepDestroyWindowNode( - _In_ PWE_WINDOW_NODE WindowNode - ) -{ - PhDereferenceObject(WindowNode->Children); - - if (WindowNode->WindowText) PhDereferenceObject(WindowNode->WindowText); - - if (WindowNode->ThreadString) PhDereferenceObject(WindowNode->ThreadString); - - PhFree(WindowNode); -} - -#define SORT_FUNCTION(Column) WepWindowTreeNewCompare##Column - -#define BEGIN_SORT_FUNCTION(Column) static int __cdecl WepWindowTreeNewCompare##Column( \ - _In_ void *_context, \ - _In_ const void *_elem1, \ - _In_ const void *_elem2 \ - ) \ -{ \ - PWE_WINDOW_NODE node1 = *(PWE_WINDOW_NODE *)_elem1; \ - PWE_WINDOW_NODE node2 = *(PWE_WINDOW_NODE *)_elem2; \ - int sortResult = 0; - -#define END_SORT_FUNCTION \ - return PhModifySort(sortResult, ((PWE_WINDOW_TREE_CONTEXT)_context)->TreeNewSortOrder); \ -} - -BEGIN_SORT_FUNCTION(Class) -{ - sortResult = _wcsicmp(node1->WindowClass, node2->WindowClass); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(Handle) -{ - sortResult = uintptrcmp((ULONG_PTR)node1->WindowHandle, (ULONG_PTR)node2->WindowHandle); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(Text) -{ - sortResult = PhCompareString(node1->WindowText, node2->WindowText, TRUE); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(Thread) -{ - sortResult = uintptrcmp((ULONG_PTR)node1->ClientId.UniqueProcess, (ULONG_PTR)node2->ClientId.UniqueProcess); - - if (sortResult == 0) - sortResult = uintptrcmp((ULONG_PTR)node1->ClientId.UniqueThread, (ULONG_PTR)node2->ClientId.UniqueThread); -} -END_SORT_FUNCTION - -BOOLEAN NTAPI WepWindowTreeNewCallback( - _In_ HWND hwnd, - _In_ PH_TREENEW_MESSAGE Message, - _In_opt_ PVOID Parameter1, - _In_opt_ PVOID Parameter2, - _In_opt_ PVOID Context - ) -{ - PWE_WINDOW_TREE_CONTEXT context; - PWE_WINDOW_NODE node; - - context = Context; - - switch (Message) - { - case TreeNewGetChildren: - { - PPH_TREENEW_GET_CHILDREN getChildren = Parameter1; - - node = (PWE_WINDOW_NODE)getChildren->Node; - - if (context->TreeNewSortOrder == NoSortOrder) - { - if (!node) - { - getChildren->Children = (PPH_TREENEW_NODE *)context->NodeRootList->Items; - getChildren->NumberOfChildren = context->NodeRootList->Count; - } - else - { - getChildren->Children = (PPH_TREENEW_NODE *)node->Children->Items; - getChildren->NumberOfChildren = node->Children->Count; - } - } - else - { - if (!node) - { - static PVOID sortFunctions[] = - { - SORT_FUNCTION(Class), - SORT_FUNCTION(Handle), - SORT_FUNCTION(Text), - SORT_FUNCTION(Thread) - }; - int (__cdecl *sortFunction)(void *, const void *, const void *); - - if (context->TreeNewSortColumn < WEWNTLC_MAXIMUM) - sortFunction = sortFunctions[context->TreeNewSortColumn]; - else - sortFunction = NULL; - - if (sortFunction) - { - qsort_s(context->NodeList->Items, context->NodeList->Count, sizeof(PVOID), sortFunction, context); - } - - getChildren->Children = (PPH_TREENEW_NODE *)context->NodeList->Items; - getChildren->NumberOfChildren = context->NodeList->Count; - } - } - } - return TRUE; - case TreeNewIsLeaf: - { - PPH_TREENEW_IS_LEAF isLeaf = Parameter1; - - node = (PWE_WINDOW_NODE)isLeaf->Node; - - if (context->TreeNewSortOrder == NoSortOrder) - isLeaf->IsLeaf = !node->HasChildren; - else - isLeaf->IsLeaf = TRUE; - } - return TRUE; - case TreeNewGetCellText: - { - PPH_TREENEW_GET_CELL_TEXT getCellText = Parameter1; - - node = (PWE_WINDOW_NODE)getCellText->Node; - - switch (getCellText->Id) - { - case WEWNTLC_CLASS: - PhInitializeStringRef(&getCellText->Text, node->WindowClass); - break; - case WEWNTLC_HANDLE: - PhPrintPointer(node->WindowHandleString, node->WindowHandle); - PhInitializeStringRef(&getCellText->Text, node->WindowHandleString); - break; - case WEWNTLC_TEXT: - getCellText->Text = PhGetStringRef(node->WindowText); - break; - case WEWNTLC_THREAD: - if (!node->ThreadString) - node->ThreadString = PhGetClientIdName(&node->ClientId); - getCellText->Text = PhGetStringRef(node->ThreadString); - break; - default: - return FALSE; - } - - getCellText->Flags = TN_CACHE; - } - return TRUE; - case TreeNewGetNodeColor: - { - PPH_TREENEW_GET_NODE_COLOR getNodeColor = Parameter1; - - node = (PWE_WINDOW_NODE)getNodeColor->Node; - - if (!node->WindowVisible) - getNodeColor->ForeColor = RGB(0x55, 0x55, 0x55); - - getNodeColor->Flags = TN_CACHE; - } - return TRUE; - case TreeNewSortChanged: - { - TreeNew_GetSort(hwnd, &context->TreeNewSortColumn, &context->TreeNewSortOrder); - // Force a rebuild to sort the items. - TreeNew_NodesStructured(hwnd); - } - return TRUE; - case TreeNewKeyDown: - { - PPH_TREENEW_KEY_EVENT keyEvent = Parameter1; - - switch (keyEvent->VirtualKey) - { - case 'C': - if (GetKeyState(VK_CONTROL) < 0) - SendMessage(context->ParentWindowHandle, WM_COMMAND, ID_WINDOW_COPY, 0); - break; - } - } - return TRUE; - case TreeNewLeftDoubleClick: - { - SendMessage(context->ParentWindowHandle, WM_COMMAND, ID_WINDOW_PROPERTIES, 0); - } - return TRUE; - case TreeNewContextMenu: - { - PPH_TREENEW_MOUSE_EVENT mouseEvent = Parameter1; - - SendMessage(context->ParentWindowHandle, WM_COMMAND, ID_SHOWCONTEXTMENU, MAKELONG(mouseEvent->Location.x, mouseEvent->Location.y)); - } - return TRUE; - } - - return FALSE; -} - -VOID WeClearWindowTree( - _In_ PWE_WINDOW_TREE_CONTEXT Context - ) -{ - ULONG i; - - for (i = 0; i < Context->NodeList->Count; i++) - WepDestroyWindowNode(Context->NodeList->Items[i]); - - PhClearHashtable(Context->NodeHashtable); - PhClearList(Context->NodeList); - PhClearList(Context->NodeRootList); -} - -PWE_WINDOW_NODE WeGetSelectedWindowNode( - _In_ PWE_WINDOW_TREE_CONTEXT Context - ) -{ - PWE_WINDOW_NODE windowNode = NULL; - ULONG i; - - for (i = 0; i < Context->NodeList->Count; i++) - { - windowNode = Context->NodeList->Items[i]; - - if (windowNode->Node.Selected) - return windowNode; - } - - return NULL; -} - -VOID WeGetSelectedWindowNodes( - _In_ PWE_WINDOW_TREE_CONTEXT Context, - _Out_ PWE_WINDOW_NODE **Windows, - _Out_ PULONG NumberOfWindows - ) -{ - PPH_LIST list; - ULONG i; - - list = PhCreateList(2); - - for (i = 0; i < Context->NodeList->Count; i++) - { - PWE_WINDOW_NODE node = Context->NodeList->Items[i]; - - if (node->Node.Selected) - { - PhAddItemList(list, node); - } - } - - *Windows = PhAllocateCopy(list->Items, sizeof(PVOID) * list->Count); - *NumberOfWindows = list->Count; - - PhDereferenceObject(list); -} - -VOID WeExpandAllWindowNodes( - _In_ PWE_WINDOW_TREE_CONTEXT Context, - _In_ BOOLEAN Expand - ) -{ - ULONG i; - BOOLEAN needsRestructure = FALSE; - - for (i = 0; i < Context->NodeList->Count; i++) - { - PWE_WINDOW_NODE node = Context->NodeList->Items[i]; - - if (node->Children->Count != 0 && node->Node.Expanded != Expand) - { - node->Node.Expanded = Expand; - needsRestructure = TRUE; - } - } - - if (needsRestructure) - TreeNew_NodesStructured(Context->TreeNewHandle); +/* + * Process Hacker Window Explorer - + * window treelist + * + * Copyright (C) 2011 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include "wndexp.h" +#include "resource.h" + +BOOLEAN WepWindowNodeHashtableEqualFunction( + _In_ PVOID Entry1, + _In_ PVOID Entry2 + ); + +ULONG WepWindowNodeHashtableHashFunction( + _In_ PVOID Entry + ); + +VOID WepDestroyWindowNode( + _In_ PWE_WINDOW_NODE WindowNode + ); + +BOOLEAN NTAPI WepWindowTreeNewCallback( + _In_ HWND hwnd, + _In_ PH_TREENEW_MESSAGE Message, + _In_opt_ PVOID Parameter1, + _In_opt_ PVOID Parameter2, + _In_opt_ PVOID Context + ); + +BOOLEAN WordMatchStringRef( + _Inout_ PWE_WINDOW_TREE_CONTEXT Context, + _In_ PPH_STRINGREF Text + ) +{ + PH_STRINGREF part; + PH_STRINGREF remainingPart; + + remainingPart = Context->SearchboxText->sr; + + while (remainingPart.Length != 0) + { + PhSplitStringRefAtChar(&remainingPart, '|', &part, &remainingPart); + + if (part.Length != 0) + { + if (PhFindStringInStringRef(Text, &part, TRUE) != -1) + return TRUE; + } + } + + return FALSE; +} + +BOOLEAN WordMatchStringZ( + _Inout_ PWE_WINDOW_TREE_CONTEXT Context, + _In_ PWSTR Text + ) +{ + PH_STRINGREF text; + + PhInitializeStringRef(&text, Text); + + return WordMatchStringRef(Context, &text); +} + +BOOLEAN WeWindowTreeFilterCallback( + _In_ PPH_TREENEW_NODE Node, + _In_opt_ PVOID Context + ) +{ + PWE_WINDOW_TREE_CONTEXT context = Context; + PWE_WINDOW_NODE windowNode = (PWE_WINDOW_NODE)Node; + + if (PhIsNullOrEmptyString(context->SearchboxText)) + return TRUE; + + if (windowNode->WindowClass[0]) + { + if (WordMatchStringZ(context, windowNode->WindowClass)) + return TRUE; + } + + if (windowNode->WindowHandleString[0]) + { + if (WordMatchStringZ(context, windowNode->WindowHandleString)) + return TRUE; + } + + if (!PhIsNullOrEmptyString(windowNode->WindowText)) + { + if (WordMatchStringRef(context, &windowNode->WindowText->sr)) + return TRUE; + } + + if (!PhIsNullOrEmptyString(windowNode->ThreadString)) + { + if (WordMatchStringRef(context, &windowNode->ThreadString->sr)) + return TRUE; + } + + return FALSE; +} + +VOID WeInitializeWindowTree( + _In_ HWND ParentWindowHandle, + _In_ HWND TreeNewHandle, + _Out_ PWE_WINDOW_TREE_CONTEXT Context + ) +{ + HWND hwnd; + PPH_STRING settings; + + memset(Context, 0, sizeof(WE_WINDOW_TREE_CONTEXT)); + + Context->NodeHashtable = PhCreateHashtable( + sizeof(PWE_WINDOW_NODE), + WepWindowNodeHashtableEqualFunction, + WepWindowNodeHashtableHashFunction, + 100 + ); + Context->NodeList = PhCreateList(100); + Context->NodeRootList = PhCreateList(30); + + Context->ParentWindowHandle = ParentWindowHandle; + Context->TreeNewHandle = TreeNewHandle; + hwnd = TreeNewHandle; + PhSetControlTheme(hwnd, L"explorer"); + + TreeNew_SetCallback(hwnd, WepWindowTreeNewCallback, Context); + + PhAddTreeNewColumn(hwnd, WEWNTLC_CLASS, TRUE, L"Class", 180, PH_ALIGN_LEFT, 0, 0); + PhAddTreeNewColumn(hwnd, WEWNTLC_HANDLE, TRUE, L"Handle", 70, PH_ALIGN_LEFT, 1, 0); + PhAddTreeNewColumn(hwnd, WEWNTLC_TEXT, TRUE, L"Text", 220, PH_ALIGN_LEFT, 2, 0); + PhAddTreeNewColumn(hwnd, WEWNTLC_THREAD, TRUE, L"Thread", 150, PH_ALIGN_LEFT, 3, 0); + + TreeNew_SetTriState(hwnd, TRUE); + TreeNew_SetSort(hwnd, WEWNTLC_CLASS, NoSortOrder); + + settings = PhGetStringSetting(SETTING_NAME_WINDOW_TREE_LIST_COLUMNS); + PhCmLoadSettings(hwnd, &settings->sr); + PhDereferenceObject(settings); + + Context->SearchboxText = PhReferenceEmptyString(); + + PhInitializeTreeNewFilterSupport( + &Context->FilterSupport, + Context->TreeNewHandle, + Context->NodeList + ); + + Context->TreeFilterEntry = PhAddTreeNewFilter( + &Context->FilterSupport, + WeWindowTreeFilterCallback, + Context + ); +} + +VOID WeDeleteWindowTree( + _In_ PWE_WINDOW_TREE_CONTEXT Context + ) +{ + PPH_STRING settings; + ULONG i; + + PhDeleteTreeNewFilterSupport(&Context->FilterSupport); + + settings = PhCmSaveSettings(Context->TreeNewHandle); + PhSetStringSetting2(SETTING_NAME_WINDOW_TREE_LIST_COLUMNS, &settings->sr); + PhDereferenceObject(settings); + + for (i = 0; i < Context->NodeList->Count; i++) + WepDestroyWindowNode(Context->NodeList->Items[i]); + + PhDereferenceObject(Context->NodeHashtable); + PhDereferenceObject(Context->NodeList); + PhDereferenceObject(Context->NodeRootList); +} + +BOOLEAN WepWindowNodeHashtableEqualFunction( + _In_ PVOID Entry1, + _In_ PVOID Entry2 + ) +{ + PWE_WINDOW_NODE windowNode1 = *(PWE_WINDOW_NODE *)Entry1; + PWE_WINDOW_NODE windowNode2 = *(PWE_WINDOW_NODE *)Entry2; + + return windowNode1->WindowHandle == windowNode2->WindowHandle; +} + +ULONG WepWindowNodeHashtableHashFunction( + _In_ PVOID Entry + ) +{ + return PhHashIntPtr((ULONG_PTR)(*(PWE_WINDOW_NODE *)Entry)->WindowHandle); +} + +PWE_WINDOW_NODE WeAddWindowNode( + _Inout_ PWE_WINDOW_TREE_CONTEXT Context + ) +{ + PWE_WINDOW_NODE windowNode; + + windowNode = PhAllocate(sizeof(WE_WINDOW_NODE)); + memset(windowNode, 0, sizeof(WE_WINDOW_NODE)); + PhInitializeTreeNewNode(&windowNode->Node); + + memset(windowNode->TextCache, 0, sizeof(PH_STRINGREF) * WEWNTLC_MAXIMUM); + windowNode->Node.TextCache = windowNode->TextCache; + windowNode->Node.TextCacheSize = WEWNTLC_MAXIMUM; + + windowNode->Children = PhCreateList(1); + + PhAddEntryHashtable(Context->NodeHashtable, &windowNode); + PhAddItemList(Context->NodeList, windowNode); + + if (Context->FilterSupport.FilterList) + windowNode->Node.Visible = PhApplyTreeNewFiltersToNode(&Context->FilterSupport, &windowNode->Node); + + //TreeNew_NodesStructured(Context->TreeNewHandle); + + return windowNode; +} + +PWE_WINDOW_NODE WeFindWindowNode( + _In_ PWE_WINDOW_TREE_CONTEXT Context, + _In_ HWND WindowHandle + ) +{ + WE_WINDOW_NODE lookupWindowNode; + PWE_WINDOW_NODE lookupWindowNodePtr = &lookupWindowNode; + PWE_WINDOW_NODE *windowNode; + + lookupWindowNode.WindowHandle = WindowHandle; + + windowNode = (PWE_WINDOW_NODE *)PhFindEntryHashtable( + Context->NodeHashtable, + &lookupWindowNodePtr + ); + + if (windowNode) + return *windowNode; + else + return NULL; +} + +VOID WeRemoveWindowNode( + _In_ PWE_WINDOW_TREE_CONTEXT Context, + _In_ PWE_WINDOW_NODE WindowNode + ) +{ + ULONG index; + + // Remove from hashtable/list and cleanup. + + PhRemoveEntryHashtable(Context->NodeHashtable, &WindowNode); + + if ((index = PhFindItemList(Context->NodeList, WindowNode)) != -1) + PhRemoveItemList(Context->NodeList, index); + + WepDestroyWindowNode(WindowNode); + + TreeNew_NodesStructured(Context->TreeNewHandle); +} + +VOID WepDestroyWindowNode( + _In_ PWE_WINDOW_NODE WindowNode + ) +{ + PhDereferenceObject(WindowNode->Children); + + if (WindowNode->WindowText) PhDereferenceObject(WindowNode->WindowText); + + if (WindowNode->ThreadString) PhDereferenceObject(WindowNode->ThreadString); + + PhFree(WindowNode); +} + +#define SORT_FUNCTION(Column) WepWindowTreeNewCompare##Column + +#define BEGIN_SORT_FUNCTION(Column) static int __cdecl WepWindowTreeNewCompare##Column( \ + _In_ void *_context, \ + _In_ const void *_elem1, \ + _In_ const void *_elem2 \ + ) \ +{ \ + PWE_WINDOW_NODE node1 = *(PWE_WINDOW_NODE *)_elem1; \ + PWE_WINDOW_NODE node2 = *(PWE_WINDOW_NODE *)_elem2; \ + int sortResult = 0; + +#define END_SORT_FUNCTION \ + return PhModifySort(sortResult, ((PWE_WINDOW_TREE_CONTEXT)_context)->TreeNewSortOrder); \ +} + +BEGIN_SORT_FUNCTION(Class) +{ + sortResult = _wcsicmp(node1->WindowClass, node2->WindowClass); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(Handle) +{ + sortResult = uintptrcmp((ULONG_PTR)node1->WindowHandle, (ULONG_PTR)node2->WindowHandle); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(Text) +{ + sortResult = PhCompareString(node1->WindowText, node2->WindowText, TRUE); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(Thread) +{ + sortResult = uintptrcmp((ULONG_PTR)node1->ClientId.UniqueProcess, (ULONG_PTR)node2->ClientId.UniqueProcess); + + if (sortResult == 0) + sortResult = uintptrcmp((ULONG_PTR)node1->ClientId.UniqueThread, (ULONG_PTR)node2->ClientId.UniqueThread); +} +END_SORT_FUNCTION + +BOOLEAN NTAPI WepWindowTreeNewCallback( + _In_ HWND hwnd, + _In_ PH_TREENEW_MESSAGE Message, + _In_opt_ PVOID Parameter1, + _In_opt_ PVOID Parameter2, + _In_opt_ PVOID Context + ) +{ + PWE_WINDOW_TREE_CONTEXT context; + PWE_WINDOW_NODE node; + + context = Context; + + switch (Message) + { + case TreeNewGetChildren: + { + PPH_TREENEW_GET_CHILDREN getChildren = Parameter1; + + node = (PWE_WINDOW_NODE)getChildren->Node; + + if (context->TreeNewSortOrder == NoSortOrder) + { + if (!node) + { + getChildren->Children = (PPH_TREENEW_NODE *)context->NodeRootList->Items; + getChildren->NumberOfChildren = context->NodeRootList->Count; + } + else + { + getChildren->Children = (PPH_TREENEW_NODE *)node->Children->Items; + getChildren->NumberOfChildren = node->Children->Count; + } + } + else + { + if (!node) + { + static PVOID sortFunctions[] = + { + SORT_FUNCTION(Class), + SORT_FUNCTION(Handle), + SORT_FUNCTION(Text), + SORT_FUNCTION(Thread) + }; + int (__cdecl *sortFunction)(void *, const void *, const void *); + + if (context->TreeNewSortColumn < WEWNTLC_MAXIMUM) + sortFunction = sortFunctions[context->TreeNewSortColumn]; + else + sortFunction = NULL; + + if (sortFunction) + { + qsort_s(context->NodeList->Items, context->NodeList->Count, sizeof(PVOID), sortFunction, context); + } + + getChildren->Children = (PPH_TREENEW_NODE *)context->NodeList->Items; + getChildren->NumberOfChildren = context->NodeList->Count; + } + } + } + return TRUE; + case TreeNewIsLeaf: + { + PPH_TREENEW_IS_LEAF isLeaf = Parameter1; + + node = (PWE_WINDOW_NODE)isLeaf->Node; + + if (context->TreeNewSortOrder == NoSortOrder) + isLeaf->IsLeaf = !node->HasChildren; + else + isLeaf->IsLeaf = TRUE; + } + return TRUE; + case TreeNewGetCellText: + { + PPH_TREENEW_GET_CELL_TEXT getCellText = Parameter1; + + node = (PWE_WINDOW_NODE)getCellText->Node; + + switch (getCellText->Id) + { + case WEWNTLC_CLASS: + PhInitializeStringRef(&getCellText->Text, node->WindowClass); + break; + case WEWNTLC_HANDLE: + PhPrintPointer(node->WindowHandleString, node->WindowHandle); + PhInitializeStringRef(&getCellText->Text, node->WindowHandleString); + break; + case WEWNTLC_TEXT: + getCellText->Text = PhGetStringRef(node->WindowText); + break; + case WEWNTLC_THREAD: + if (!node->ThreadString) + node->ThreadString = PhGetClientIdName(&node->ClientId); + getCellText->Text = PhGetStringRef(node->ThreadString); + break; + default: + return FALSE; + } + + getCellText->Flags = TN_CACHE; + } + return TRUE; + case TreeNewGetNodeColor: + { + PPH_TREENEW_GET_NODE_COLOR getNodeColor = Parameter1; + + node = (PWE_WINDOW_NODE)getNodeColor->Node; + + if (!node->WindowVisible) + getNodeColor->ForeColor = RGB(0x55, 0x55, 0x55); + + getNodeColor->Flags = TN_CACHE; + } + return TRUE; + case TreeNewSortChanged: + { + TreeNew_GetSort(hwnd, &context->TreeNewSortColumn, &context->TreeNewSortOrder); + // Force a rebuild to sort the items. + TreeNew_NodesStructured(hwnd); + } + return TRUE; + case TreeNewKeyDown: + { + PPH_TREENEW_KEY_EVENT keyEvent = Parameter1; + + switch (keyEvent->VirtualKey) + { + case 'C': + if (GetKeyState(VK_CONTROL) < 0) + SendMessage(context->ParentWindowHandle, WM_COMMAND, ID_WINDOW_COPY, 0); + break; + } + } + return TRUE; + case TreeNewLeftDoubleClick: + { + SendMessage(context->ParentWindowHandle, WM_COMMAND, ID_WINDOW_PROPERTIES, 0); + } + return TRUE; + case TreeNewContextMenu: + { + PPH_TREENEW_MOUSE_EVENT mouseEvent = Parameter1; + + SendMessage(context->ParentWindowHandle, WM_COMMAND, ID_SHOWCONTEXTMENU, MAKELONG(mouseEvent->Location.x, mouseEvent->Location.y)); + } + return TRUE; + } + + return FALSE; +} + +VOID WeClearWindowTree( + _In_ PWE_WINDOW_TREE_CONTEXT Context + ) +{ + ULONG i; + + for (i = 0; i < Context->NodeList->Count; i++) + WepDestroyWindowNode(Context->NodeList->Items[i]); + + PhClearHashtable(Context->NodeHashtable); + PhClearList(Context->NodeList); + PhClearList(Context->NodeRootList); +} + +PWE_WINDOW_NODE WeGetSelectedWindowNode( + _In_ PWE_WINDOW_TREE_CONTEXT Context + ) +{ + PWE_WINDOW_NODE windowNode = NULL; + ULONG i; + + for (i = 0; i < Context->NodeList->Count; i++) + { + windowNode = Context->NodeList->Items[i]; + + if (windowNode->Node.Selected) + return windowNode; + } + + return NULL; +} + +VOID WeGetSelectedWindowNodes( + _In_ PWE_WINDOW_TREE_CONTEXT Context, + _Out_ PWE_WINDOW_NODE **Windows, + _Out_ PULONG NumberOfWindows + ) +{ + PPH_LIST list; + ULONG i; + + list = PhCreateList(2); + + for (i = 0; i < Context->NodeList->Count; i++) + { + PWE_WINDOW_NODE node = Context->NodeList->Items[i]; + + if (node->Node.Selected) + { + PhAddItemList(list, node); + } + } + + *Windows = PhAllocateCopy(list->Items, sizeof(PVOID) * list->Count); + *NumberOfWindows = list->Count; + + PhDereferenceObject(list); +} + +VOID WeExpandAllWindowNodes( + _In_ PWE_WINDOW_TREE_CONTEXT Context, + _In_ BOOLEAN Expand + ) +{ + ULONG i; + BOOLEAN needsRestructure = FALSE; + + for (i = 0; i < Context->NodeList->Count; i++) + { + PWE_WINDOW_NODE node = Context->NodeList->Items[i]; + + if (node->Children->Count != 0 && node->Node.Expanded != Expand) + { + node->Node.Expanded = Expand; + needsRestructure = TRUE; + } + } + + if (needsRestructure) + TreeNew_NodesStructured(Context->TreeNewHandle); } \ No newline at end of file diff --git a/plugins/WindowExplorer/wndtree.h b/plugins/WindowExplorer/wndtree.h index 3157c4d2bd73..e1d3882174f6 100644 --- a/plugins/WindowExplorer/wndtree.h +++ b/plugins/WindowExplorer/wndtree.h @@ -1,98 +1,98 @@ -#ifndef WNDTREE_H -#define WNDTREE_H - -#define WEWNTLC_CLASS 0 -#define WEWNTLC_HANDLE 1 -#define WEWNTLC_TEXT 2 -#define WEWNTLC_THREAD 3 -#define WEWNTLC_MAXIMUM 4 - -typedef struct _WE_WINDOW_NODE -{ - PH_TREENEW_NODE Node; - - struct _WE_WINDOW_NODE *Parent; - PPH_LIST Children; - - union - { - ULONG Flags; - struct - { - ULONG HasChildren : 1; - ULONG WindowVisible : 1; - ULONG Spare : 30; - }; - }; - - PH_STRINGREF TextCache[WEWNTLC_MAXIMUM]; - - HWND WindowHandle; - WCHAR WindowClass[64]; - PPH_STRING WindowText; - CLIENT_ID ClientId; - - WCHAR WindowHandleString[PH_PTR_STR_LEN_1]; - PPH_STRING ThreadString; -} WE_WINDOW_NODE, *PWE_WINDOW_NODE; - -typedef struct _WE_WINDOW_TREE_CONTEXT -{ - HWND ParentWindowHandle; - HWND TreeNewHandle; - ULONG TreeNewSortColumn; - PH_SORT_ORDER TreeNewSortOrder; - - PPH_STRING SearchboxText; - PH_TN_FILTER_SUPPORT FilterSupport; - PPH_TN_FILTER_ENTRY TreeFilterEntry; - - PPH_HASHTABLE NodeHashtable; - PPH_LIST NodeList; - PPH_LIST NodeRootList; -} WE_WINDOW_TREE_CONTEXT, *PWE_WINDOW_TREE_CONTEXT; - -VOID WeInitializeWindowTree( - _In_ HWND ParentWindowHandle, - _In_ HWND TreeNewHandle, - _Out_ PWE_WINDOW_TREE_CONTEXT Context - ); - -VOID WeDeleteWindowTree( - _In_ PWE_WINDOW_TREE_CONTEXT Context - ); - -PWE_WINDOW_NODE WeAddWindowNode( - _Inout_ PWE_WINDOW_TREE_CONTEXT Context - ); - -PWE_WINDOW_NODE WeFindWindowNode( - _In_ PWE_WINDOW_TREE_CONTEXT Context, - _In_ HWND WindowHandle - ); - -VOID WeRemoveWindowNode( - _In_ PWE_WINDOW_TREE_CONTEXT Context, - _In_ PWE_WINDOW_NODE WindowNode - ); - -VOID WeClearWindowTree( - _In_ PWE_WINDOW_TREE_CONTEXT Context - ); - -PWE_WINDOW_NODE WeGetSelectedWindowNode( - _In_ PWE_WINDOW_TREE_CONTEXT Context - ); - -VOID WeGetSelectedWindowNodes( - _In_ PWE_WINDOW_TREE_CONTEXT Context, - _Out_ PWE_WINDOW_NODE **Windows, - _Out_ PULONG NumberOfWindows - ); - -VOID WeExpandAllWindowNodes( - _In_ PWE_WINDOW_TREE_CONTEXT Context, - _In_ BOOLEAN Expand - ); - -#endif +#ifndef WNDTREE_H +#define WNDTREE_H + +#define WEWNTLC_CLASS 0 +#define WEWNTLC_HANDLE 1 +#define WEWNTLC_TEXT 2 +#define WEWNTLC_THREAD 3 +#define WEWNTLC_MAXIMUM 4 + +typedef struct _WE_WINDOW_NODE +{ + PH_TREENEW_NODE Node; + + struct _WE_WINDOW_NODE *Parent; + PPH_LIST Children; + + union + { + ULONG Flags; + struct + { + ULONG HasChildren : 1; + ULONG WindowVisible : 1; + ULONG Spare : 30; + }; + }; + + PH_STRINGREF TextCache[WEWNTLC_MAXIMUM]; + + HWND WindowHandle; + WCHAR WindowClass[64]; + PPH_STRING WindowText; + CLIENT_ID ClientId; + + WCHAR WindowHandleString[PH_PTR_STR_LEN_1]; + PPH_STRING ThreadString; +} WE_WINDOW_NODE, *PWE_WINDOW_NODE; + +typedef struct _WE_WINDOW_TREE_CONTEXT +{ + HWND ParentWindowHandle; + HWND TreeNewHandle; + ULONG TreeNewSortColumn; + PH_SORT_ORDER TreeNewSortOrder; + + PPH_STRING SearchboxText; + PH_TN_FILTER_SUPPORT FilterSupport; + PPH_TN_FILTER_ENTRY TreeFilterEntry; + + PPH_HASHTABLE NodeHashtable; + PPH_LIST NodeList; + PPH_LIST NodeRootList; +} WE_WINDOW_TREE_CONTEXT, *PWE_WINDOW_TREE_CONTEXT; + +VOID WeInitializeWindowTree( + _In_ HWND ParentWindowHandle, + _In_ HWND TreeNewHandle, + _Out_ PWE_WINDOW_TREE_CONTEXT Context + ); + +VOID WeDeleteWindowTree( + _In_ PWE_WINDOW_TREE_CONTEXT Context + ); + +PWE_WINDOW_NODE WeAddWindowNode( + _Inout_ PWE_WINDOW_TREE_CONTEXT Context + ); + +PWE_WINDOW_NODE WeFindWindowNode( + _In_ PWE_WINDOW_TREE_CONTEXT Context, + _In_ HWND WindowHandle + ); + +VOID WeRemoveWindowNode( + _In_ PWE_WINDOW_TREE_CONTEXT Context, + _In_ PWE_WINDOW_NODE WindowNode + ); + +VOID WeClearWindowTree( + _In_ PWE_WINDOW_TREE_CONTEXT Context + ); + +PWE_WINDOW_NODE WeGetSelectedWindowNode( + _In_ PWE_WINDOW_TREE_CONTEXT Context + ); + +VOID WeGetSelectedWindowNodes( + _In_ PWE_WINDOW_TREE_CONTEXT Context, + _Out_ PWE_WINDOW_NODE **Windows, + _Out_ PULONG NumberOfWindows + ); + +VOID WeExpandAllWindowNodes( + _In_ PWE_WINDOW_TREE_CONTEXT Context, + _In_ BOOLEAN Expand + ); + +#endif diff --git a/plugins/include/toolstatusintf.h b/plugins/include/toolstatusintf.h index c185b16df030..9f366f928e30 100644 --- a/plugins/include/toolstatusintf.h +++ b/plugins/include/toolstatusintf.h @@ -1,49 +1,49 @@ -#ifndef _TOOLSTATUSINTF_H -#define _TOOLSTATUSINTF_H - -#define TOOLSTATUS_PLUGIN_NAME L"ProcessHacker.ToolStatus" -#define TOOLSTATUS_INTERFACE_VERSION 1 - -typedef PPH_STRING (NTAPI *PTOOLSTATUS_GET_SEARCHBOX_TEXT)( - VOID - ); - -typedef BOOLEAN (NTAPI *PTOOLSTATUS_WORD_MATCH)( - _In_ PPH_STRINGREF Text - ); - -typedef VOID (NTAPI *PTOOLSTATUS_REGISTER_TAB_SEARCH)( - _In_ INT TabIndex, - _In_ PWSTR BannerText - ); - -typedef VOID (NTAPI *PTOOLSTATUS_TAB_ACTIVATE_CONTENT)( - _In_ BOOLEAN Select - ); - -typedef HWND (NTAPI *PTOOLSTATUS_GET_TREENEW_HANDLE)( - VOID - ); - -typedef struct _TOOLSTATUS_TAB_INFO -{ - PWSTR BannerText; - PTOOLSTATUS_TAB_ACTIVATE_CONTENT ActivateContent; - PTOOLSTATUS_GET_TREENEW_HANDLE GetTreeNewHandle; -} TOOLSTATUS_TAB_INFO, *PTOOLSTATUS_TAB_INFO; - -typedef PTOOLSTATUS_TAB_INFO (NTAPI *PTOOLSTATUS_REGISTER_TAB_INFO)( - _In_ INT TabIndex - ); - -typedef struct _TOOLSTATUS_INTERFACE -{ - ULONG Version; - PTOOLSTATUS_GET_SEARCHBOX_TEXT GetSearchboxText; - PTOOLSTATUS_WORD_MATCH WordMatch; - PTOOLSTATUS_REGISTER_TAB_SEARCH RegisterTabSearchDeprecated; - PPH_CALLBACK SearchChangedEvent; - PTOOLSTATUS_REGISTER_TAB_INFO RegisterTabInfo; -} TOOLSTATUS_INTERFACE, *PTOOLSTATUS_INTERFACE; - -#endif +#ifndef _TOOLSTATUSINTF_H +#define _TOOLSTATUSINTF_H + +#define TOOLSTATUS_PLUGIN_NAME L"ProcessHacker.ToolStatus" +#define TOOLSTATUS_INTERFACE_VERSION 1 + +typedef PPH_STRING (NTAPI *PTOOLSTATUS_GET_SEARCHBOX_TEXT)( + VOID + ); + +typedef BOOLEAN (NTAPI *PTOOLSTATUS_WORD_MATCH)( + _In_ PPH_STRINGREF Text + ); + +typedef VOID (NTAPI *PTOOLSTATUS_REGISTER_TAB_SEARCH)( + _In_ INT TabIndex, + _In_ PWSTR BannerText + ); + +typedef VOID (NTAPI *PTOOLSTATUS_TAB_ACTIVATE_CONTENT)( + _In_ BOOLEAN Select + ); + +typedef HWND (NTAPI *PTOOLSTATUS_GET_TREENEW_HANDLE)( + VOID + ); + +typedef struct _TOOLSTATUS_TAB_INFO +{ + PWSTR BannerText; + PTOOLSTATUS_TAB_ACTIVATE_CONTENT ActivateContent; + PTOOLSTATUS_GET_TREENEW_HANDLE GetTreeNewHandle; +} TOOLSTATUS_TAB_INFO, *PTOOLSTATUS_TAB_INFO; + +typedef PTOOLSTATUS_TAB_INFO (NTAPI *PTOOLSTATUS_REGISTER_TAB_INFO)( + _In_ INT TabIndex + ); + +typedef struct _TOOLSTATUS_INTERFACE +{ + ULONG Version; + PTOOLSTATUS_GET_SEARCHBOX_TEXT GetSearchboxText; + PTOOLSTATUS_WORD_MATCH WordMatch; + PTOOLSTATUS_REGISTER_TAB_SEARCH RegisterTabSearchDeprecated; + PPH_CALLBACK SearchChangedEvent; + PTOOLSTATUS_REGISTER_TAB_INFO RegisterTabInfo; +} TOOLSTATUS_INTERFACE, *PTOOLSTATUS_INTERFACE; + +#endif diff --git a/plugins/readme.txt b/plugins/readme.txt index 8a949b95e044..7e0a28756a3e 100644 --- a/plugins/readme.txt +++ b/plugins/readme.txt @@ -1,3 +1,3 @@ -Before compiling these plugins you must have generated the -Process Hacker SDK. You can do this by running makesdk.cmd in +Before compiling these plugins you must have generated the +Process Hacker SDK. You can do this by running makesdk.cmd in build/sdk. \ No newline at end of file diff --git a/tests/phlib-test/main.c b/tests/phlib-test/main.c index 867a5b376909..c6799fbfafeb 100644 --- a/tests/phlib-test/main.c +++ b/tests/phlib-test/main.c @@ -1,16 +1,16 @@ -#include "tests.h" - -int __cdecl wmain(int argc, wchar_t *argv[]) -{ - NTSTATUS status; - - status = PhInitializePhLib(); - assert(NT_SUCCESS(status)); - - Test_basesup(); - Test_avltree(); - Test_format(); - Test_util(); - - return 0; -} +#include "tests.h" + +int __cdecl wmain(int argc, wchar_t *argv[]) +{ + NTSTATUS status; + + status = PhInitializePhLib(); + assert(NT_SUCCESS(status)); + + Test_basesup(); + Test_avltree(); + Test_format(); + Test_util(); + + return 0; +} diff --git a/tests/phlib-test/phlib-test.vcxproj b/tests/phlib-test/phlib-test.vcxproj index 50fa90fcf171..aa1ab1641568 100644 --- a/tests/phlib-test/phlib-test.vcxproj +++ b/tests/phlib-test/phlib-test.vcxproj @@ -1,116 +1,116 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - - {0C21014E-BC90-4AE5-AA32-398445C13B28} - phlib-test - Win32Proj - 10.0.15063.0 - - - - Application - Unicode - true - v141 - - - Application - Unicode - v141 - - - - - - - - - - - - - $(ProjectDir)bin\$(Configuration)\ - $(ProjectDir)obj\$(Configuration)\ - false - $(ProjectDir)bin\$(Configuration)\ - $(ProjectDir)obj\$(Configuration)\ - false - - - - Disabled - ..\..\phnt\include;..\..\phlib\include;%(AdditionalIncludeDirectories) - _PHLIB_;_CONSOLE;WIN32;DEBUG;%(PreprocessorDefinitions) - EnableFastChecks - MultiThreadedDebug - Level3 - ProgramDatabase - StdCall - true - true - - - phlib.lib;ntdll.lib;%(AdditionalDependencies) - ..\..\phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) - true - Console - MachineX86 - 5.01 - - - - - MaxSpeed - true - ..\..\phnt\include;..\..\phlib\include;%(AdditionalIncludeDirectories) - _PHLIB_;_CONSOLE;WIN32;NDEBUG;%(PreprocessorDefinitions) - MultiThreaded - true - Level3 - ProgramDatabase - StdCall - true - true - - - phlib.lib;ntdll.lib;%(AdditionalDependencies) - ..\..\phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) - true - Console - true - true - MachineX86 - true - 5.01 - - - - - - - - - - - - {477d0215-f252-41a1-874b-f27e3ea1ed17} - false - - - - - - - - + + + + + Debug + Win32 + + + Release + Win32 + + + + {0C21014E-BC90-4AE5-AA32-398445C13B28} + phlib-test + Win32Proj + 10.0.15063.0 + + + + Application + Unicode + true + v141 + + + Application + Unicode + v141 + + + + + + + + + + + + + $(ProjectDir)bin\$(Configuration)\ + $(ProjectDir)obj\$(Configuration)\ + false + $(ProjectDir)bin\$(Configuration)\ + $(ProjectDir)obj\$(Configuration)\ + false + + + + Disabled + ..\..\phnt\include;..\..\phlib\include;%(AdditionalIncludeDirectories) + _PHLIB_;_CONSOLE;WIN32;DEBUG;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + Level3 + ProgramDatabase + StdCall + true + true + + + phlib.lib;ntdll.lib;%(AdditionalDependencies) + ..\..\phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) + true + Console + MachineX86 + 5.01 + + + + + MaxSpeed + true + ..\..\phnt\include;..\..\phlib\include;%(AdditionalIncludeDirectories) + _PHLIB_;_CONSOLE;WIN32;NDEBUG;%(PreprocessorDefinitions) + MultiThreaded + true + Level3 + ProgramDatabase + StdCall + true + true + + + phlib.lib;ntdll.lib;%(AdditionalDependencies) + ..\..\phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) + true + Console + true + true + MachineX86 + true + 5.01 + + + + + + + + + + + + {477d0215-f252-41a1-874b-f27e3ea1ed17} + false + + + + + + + + \ No newline at end of file diff --git a/tests/phlib-test/t_basesup.c b/tests/phlib-test/t_basesup.c index 2bd2fe06c060..f32d49d9ecd4 100644 --- a/tests/phlib-test/t_basesup.c +++ b/tests/phlib-test/t_basesup.c @@ -1,352 +1,352 @@ -#include "tests.h" - -static VOID Test_time( - VOID - ) -{ - LARGE_INTEGER time; - FILETIME fileTime; - LARGE_INTEGER localTime; - FILETIME localFileTime; - LARGE_INTEGER systemTime; - FILETIME systemFileTime; - - PhQuerySystemTime(&time); - fileTime.dwLowDateTime = time.LowPart; - fileTime.dwHighDateTime = time.HighPart; - - PhSystemTimeToLocalTime(&time, &localTime); - FileTimeToLocalFileTime(&fileTime, &localFileTime); - - assert(localTime.LowPart == localFileTime.dwLowDateTime); - assert(localTime.HighPart == localFileTime.dwHighDateTime); - - PhLocalTimeToSystemTime(&localTime, &systemTime); - LocalFileTimeToFileTime(&localFileTime, &systemFileTime); - - assert(systemTime.LowPart == systemFileTime.dwLowDateTime); - assert(systemTime.HighPart == systemFileTime.dwHighDateTime); -} - -static VOID Test_stringz( - VOID - ) -{ - BOOLEAN result; - CHAR inputA[16] = "test"; - CHAR outputA[16]; - WCHAR inputW[16] = L"test"; - WCHAR outputW[16]; - ULONG returnCount; - PWSTR zero = L"\0\0\0\0\0\0\0\0"; - PWSTR asdf = L"asdfasdfasdfasdf"; - ULONG i; - - for (i = 0; i < 8; i++) - assert(PhCountStringZ(zero + i) == 0); - for (i = 0; i < 16; i++) - assert(PhCountStringZ(asdf + i) == 16 - i); - - result = PhCopyBytesZ(inputA, 4, outputA, 4, &returnCount); - assert(!result && returnCount == 5); - result = PhCopyBytesZ(inputA, 100, outputA, 4, &returnCount); - assert(!result && returnCount == 5); - result = PhCopyBytesZ(inputA, 3, outputA, 4, &returnCount); - assert(result && returnCount == 4); - result = PhCopyBytesZ(inputA, 4, outputA, 5, &returnCount); - assert(result && returnCount == 5); - result = PhCopyBytesZ(inputA, 100, outputA, 5, &returnCount); - assert(result && returnCount == 5); - - result = PhCopyStringZ(inputW, 100, outputW, 4, &returnCount); - assert(!result && returnCount == 5); - result = PhCopyStringZ(inputW, 4, outputW, 5, &returnCount); - assert(result && returnCount == 5); - result = PhCopyStringZ(inputW, 100, outputW, 5, &returnCount); - assert(result && returnCount == 5); - - result = PhCopyStringZFromMultiByte(inputA, 4, outputW, 4, &returnCount); - assert(!result && returnCount == 5); - result = PhCopyStringZFromMultiByte(inputA, 100, outputW, 4, &returnCount); - assert(!result && returnCount == 5); - result = PhCopyStringZFromMultiByte(inputA, 3, outputW, 4, &returnCount); - assert(result && returnCount == 4); - result = PhCopyStringZFromMultiByte(inputA, 4, outputW, 5, &returnCount); - assert(result && returnCount == 5); - result = PhCopyStringZFromMultiByte(inputA, 100, outputW, 5, &returnCount); - assert(result && returnCount == 5); - - assert(PhCompareStringZNatural(L"abc", L"abc", FALSE) == 0); - assert(PhCompareStringZNatural(L"abc", L"abc", TRUE) == 0); - assert(PhCompareStringZNatural(L"abc", L"ABC", FALSE) != 0); - assert(PhCompareStringZNatural(L"abc", L"ABC", TRUE) == 0); - assert(PhCompareStringZNatural(L"abc", L"abd", FALSE) < 0); - assert(PhCompareStringZNatural(L"abe", L"abd", FALSE) > 0); - assert(PhCompareStringZNatural(L"1", L"2", FALSE) < 0); - assert(PhCompareStringZNatural(L"12", L"9", FALSE) > 0); - assert(PhCompareStringZNatural(L"file-1", L"file-9", FALSE) < 0); - assert(PhCompareStringZNatural(L"file-12", L"file-9", FALSE) > 0); - assert(PhCompareStringZNatural(L"file-12", L"file-90", FALSE) < 0); -} - -VOID Test_stringref( - VOID - ) -{ - ULONG i; - ULONG j; - PH_STRINGREF s1; - PH_STRINGREF s2; - PH_STRINGREF s3; - WCHAR buffer[26 * 2]; - - // PhEqualStringRef, PhFindCharInStringRef, PhFindLastCharInStringRef - - // Alignment tests - - s1.Buffer = buffer; - s1.Length = sizeof(buffer); - - for (i = 0; i < 26; i++) - s1.Buffer[i] = (WCHAR)i; - - for (i = 0; i < 26; i++) - assert(PhFindCharInStringRef(&s1, (WCHAR)i, FALSE) == i); - - memset(buffer, 0, sizeof(buffer)); - s1.Length = 0; - - for (i = 0; i < 26; i++) - assert(PhFindCharInStringRef(&s1, 0, FALSE) == -1); - - buffer[26] = 1; - - for (i = 0; i < 26; i++) - { - s1.Buffer = buffer + 26 - i; - s1.Length = i * sizeof(WCHAR); - assert(PhFindCharInStringRef(&s1, 1, FALSE) == -1); - } - - for (i = 1; i < 26; i++) - { - s1.Buffer = buffer; - s1.Length = i * 2 * sizeof(WCHAR); - - for (j = 0; j < i; j++) - { - buffer[j] = (WCHAR)('a' + j); - buffer[i + j] = (WCHAR)('A' + j); - } - - s2.Buffer = buffer; - s2.Length = i * sizeof(WCHAR); - s3.Buffer = buffer + i; - s3.Length = i * sizeof(WCHAR); - assert(!PhEqualStringRef(&s2, &s3, FALSE)); - assert(PhEqualStringRef(&s2, &s3, TRUE)); - - for (j = 0; j < i; j++) - { - buffer[j] = 'z'; - assert(!PhEqualStringRef(&s2, &s3, FALSE)); - assert(!PhEqualStringRef(&s2, &s3, TRUE)); - buffer[j] = (WCHAR)('a' + j); - } - - s3 = s2; - assert(PhEqualStringRef(&s2, &s3, FALSE)); - assert(PhEqualStringRef(&s2, &s3, TRUE)); - - for (j = 0; j < i; j++) - { - assert(PhFindCharInStringRef(&s1, s1.Buffer[j], FALSE) == j); - assert(PhFindLastCharInStringRef(&s1, s1.Buffer[j], FALSE) == j); - assert(PhFindCharInStringRef(&s1, s1.Buffer[j], TRUE) == j % i); - assert(PhFindLastCharInStringRef(&s1, s1.Buffer[j], TRUE) == i + j % i); - } - - s1.Length = i * sizeof(WCHAR); - - for (j = 0; j < i; j++) - { - assert(PhFindCharInStringRef(&s1, s1.Buffer[j] - ('a' - 'A'), FALSE) == -1); - assert(PhFindLastCharInStringRef(&s1, s1.Buffer[j] - ('a' - 'A'), FALSE) == -1); - assert(PhFindCharInStringRef(&s1, s1.Buffer[j] - ('a' - 'A'), TRUE) == j); - assert(PhFindLastCharInStringRef(&s1, s1.Buffer[j] - ('a' - 'A'), TRUE) == j); - } - - s1.Buffer += i; - - for (j = 0; j < i; j++) - { - assert(PhFindCharInStringRef(&s1, s1.Buffer[j] + ('a' - 'A'), FALSE) == -1); - assert(PhFindLastCharInStringRef(&s1, s1.Buffer[j] + ('a' - 'A'), FALSE) == -1); - assert(PhFindCharInStringRef(&s1, s1.Buffer[j] + ('a' - 'A'), TRUE) == j); - assert(PhFindLastCharInStringRef(&s1, s1.Buffer[j] + ('a' - 'A'), TRUE) == j); - } - } - - // PhFindStringInStringRef - -#define DO_STRSTR_TEST(func, s1, s2, expected, ...) \ - do { \ - PH_STRINGREF ___t1; \ - PH_STRINGREF ___t2; \ - PhInitializeStringRef(&___t1, s1); \ - PhInitializeStringRef(&___t2, s2); \ - assert(func(&___t1, &___t2, __VA_ARGS__) == expected); \ - } while (0) - - DO_STRSTR_TEST(PhFindStringInStringRef, L"asdfasdf", L"f", 3, FALSE); - DO_STRSTR_TEST(PhFindStringInStringRef, L"asdfasdf", L"g", -1, FALSE); - DO_STRSTR_TEST(PhFindStringInStringRef, L"asdfasdg", L"g", 7, FALSE); - DO_STRSTR_TEST(PhFindStringInStringRef, L"asdfasdg", L"asdg", 4, FALSE); - DO_STRSTR_TEST(PhFindStringInStringRef, L"asdfasdg", L"asdgh", -1, FALSE); - DO_STRSTR_TEST(PhFindStringInStringRef, L"asdfasdg", L"asdfasdg", 0, FALSE); - DO_STRSTR_TEST(PhFindStringInStringRef, L"asdfasdg", L"sdfasdg", 1, FALSE); - DO_STRSTR_TEST(PhFindStringInStringRef, L"asdfasdg", L"asdfasdgg", -1, FALSE); - DO_STRSTR_TEST(PhFindStringInStringRef, L"asdfasdg", L"asdfasdgggggg", -1, FALSE); - DO_STRSTR_TEST(PhFindStringInStringRef, L"", L"asdfasdgggggg", -1, FALSE); - DO_STRSTR_TEST(PhFindStringInStringRef, L"asdfasdg", L"", 0, FALSE); - DO_STRSTR_TEST(PhFindStringInStringRef, L"", L"", 0, FALSE); - // Test roll-over - DO_STRSTR_TEST(PhFindStringInStringRef, L"0sdfasdf1sdfasdf2sdfasdf3sdfasdg4sdfg", L"0sdfasdf1sdfasdf2sdfasdf3sdfasdg4sdfg", 0, FALSE); - DO_STRSTR_TEST(PhFindStringInStringRef, L"0sdfasdf1sdfasdf2sdfasdf3sdfasdg4sdfg", L"asdg4sdfg", 28, FALSE); - DO_STRSTR_TEST(PhFindStringInStringRef, L"0sdfasdf1sdfasdf2sdfasdf3sdfasdg4sdfg", L"asdg4Gdfg", -1, FALSE); -} - -VOID Test_hexstring( - VOID - ) -{ - BOOLEAN result; - PH_STRINGREF sr; - PPH_STRING string; - UCHAR buffer[16]; - - PhInitializeStringRef(&sr, L"0011223344"); - result = PhHexStringToBuffer(&sr, buffer); - assert(result && buffer[0] == 0 && buffer[1] == 0x11 && buffer[2] == 0x22 && buffer[3] == 0x33 && buffer[4] == 0x44); - - PhInitializeStringRef(&sr, L"00111"); - result = PhHexStringToBuffer(&sr, buffer); - assert(!result); - - buffer[0] = 0; - buffer[1] = 0x99; - buffer[2] = 0xff; - - string = PhBufferToHexString(buffer, 3); - assert(wcscmp(string->Buffer, L"0099ff") == 0); -} - -VOID Test_strint( - VOID - ) -{ - PH_STRINGREF sr; - LONG64 integer; - PPH_STRING string; - - PhInitializeStringRef(&sr, L"123"); - PhStringToInteger64(&sr, 0, &integer); - assert(integer == 123); - PhStringToInteger64(&sr, 10, &integer); - assert(integer == 123); - PhStringToInteger64(&sr, 8, &integer); - assert(integer == 0123); - PhStringToInteger64(&sr, 16, &integer); - assert(integer == 0x123); - - PhInitializeStringRef(&sr, L"0o123"); - PhStringToInteger64(&sr, 0, &integer); - assert(integer == 0123); - PhInitializeStringRef(&sr, L"0x123"); - PhStringToInteger64(&sr, 0, &integer); - assert(integer == 0x123); - - string = PhIntegerToString64(123, 0, FALSE); - assert(wcscmp(string->Buffer, L"123") == 0); - string = PhIntegerToString64(123, 10, FALSE); - assert(wcscmp(string->Buffer, L"123") == 0); - string = PhIntegerToString64(123, 8, FALSE); - assert(wcscmp(string->Buffer, L"173") == 0); - string = PhIntegerToString64(123, 16, FALSE); - assert(wcscmp(string->Buffer, L"7b") == 0); - - string = PhIntegerToString64(-123, 0, TRUE); - assert(wcscmp(string->Buffer, L"-123") == 0); - string = PhIntegerToString64(-123, 10, TRUE); - assert(wcscmp(string->Buffer, L"-123") == 0); - string = PhIntegerToString64(-123, 8, TRUE); - assert(wcscmp(string->Buffer, L"-173") == 0); - string = PhIntegerToString64(-123, 16, TRUE); - assert(wcscmp(string->Buffer, L"-7b") == 0); - - string = PhIntegerToString64(-123, 0, FALSE); - assert(wcscmp(string->Buffer, L"18446744073709551493") == 0); -} - -VOID Test_unicode( - VOID - ) -{ - BOOLEAN result; - ULONG codePoints[6]; - SIZE_T i; - WCHAR utf16[sizeof(codePoints) / sizeof(WCHAR)]; - CHAR utf8[sizeof(codePoints) / sizeof(CHAR)]; - ULONG numberOfCodePoints; - SIZE_T utf16Position = 0; - SIZE_T utf8Position = 0; - PPH_STRING utf16_1, utf16_2, utf16_3; - PPH_BYTES utf8_1, utf8_2, utf8_3; - - codePoints[0] = 0; - codePoints[1] = 0x50; - codePoints[2] = 0x312; - codePoints[3] = 0x3121; - codePoints[4] = 0x31212; - codePoints[5] = PH_UNICODE_MAX_CODE_POINT; - - for (i = 0; i < sizeof(codePoints) / sizeof(ULONG); i++) - { - result = PhEncodeUnicode(PH_UNICODE_UTF16, codePoints[i], utf16 + utf16Position, &numberOfCodePoints); - assert(result); - utf16Position += numberOfCodePoints; - - result = PhEncodeUnicode(PH_UNICODE_UTF8, codePoints[i], utf8 + utf8Position, &numberOfCodePoints); - assert(result); - utf8Position += numberOfCodePoints; - } - - utf16_1 = PhCreateStringEx(utf16, utf16Position * sizeof(WCHAR)); - utf8_1 = PhCreateBytesEx(utf8, utf8Position); - utf16_2 = PhConvertUtf8ToUtf16Ex(utf8_1->Buffer, utf8_1->Length); - utf8_2 = PhConvertUtf16ToUtf8Ex(utf16_1->Buffer, utf16_1->Length); - utf16_3 = PhConvertUtf8ToUtf16Ex(utf8_2->Buffer, utf8_2->Length); - utf8_3 = PhConvertUtf16ToUtf8Ex(utf16_2->Buffer, utf16_2->Length); - - assert(utf16_1->Length == utf16_2->Length); - assert(memcmp(utf16_1->Buffer, utf16_2->Buffer, utf16_1->Length) == 0); - assert(utf16_2->Length == utf16_3->Length); - assert(memcmp(utf16_2->Buffer, utf16_3->Buffer, utf16_2->Length) == 0); - - assert(utf8_1->Length == utf8_2->Length); - assert(memcmp(utf8_1->Buffer, utf8_2->Buffer, utf8_1->Length) == 0); - assert(utf8_2->Length == utf8_3->Length); - assert(memcmp(utf8_2->Buffer, utf8_3->Buffer, utf8_2->Length) == 0); -} - -VOID Test_basesup( - VOID - ) -{ - Test_time(); - Test_stringz(); - Test_stringref(); - Test_hexstring(); - Test_strint(); - Test_unicode(); -} +#include "tests.h" + +static VOID Test_time( + VOID + ) +{ + LARGE_INTEGER time; + FILETIME fileTime; + LARGE_INTEGER localTime; + FILETIME localFileTime; + LARGE_INTEGER systemTime; + FILETIME systemFileTime; + + PhQuerySystemTime(&time); + fileTime.dwLowDateTime = time.LowPart; + fileTime.dwHighDateTime = time.HighPart; + + PhSystemTimeToLocalTime(&time, &localTime); + FileTimeToLocalFileTime(&fileTime, &localFileTime); + + assert(localTime.LowPart == localFileTime.dwLowDateTime); + assert(localTime.HighPart == localFileTime.dwHighDateTime); + + PhLocalTimeToSystemTime(&localTime, &systemTime); + LocalFileTimeToFileTime(&localFileTime, &systemFileTime); + + assert(systemTime.LowPart == systemFileTime.dwLowDateTime); + assert(systemTime.HighPart == systemFileTime.dwHighDateTime); +} + +static VOID Test_stringz( + VOID + ) +{ + BOOLEAN result; + CHAR inputA[16] = "test"; + CHAR outputA[16]; + WCHAR inputW[16] = L"test"; + WCHAR outputW[16]; + ULONG returnCount; + PWSTR zero = L"\0\0\0\0\0\0\0\0"; + PWSTR asdf = L"asdfasdfasdfasdf"; + ULONG i; + + for (i = 0; i < 8; i++) + assert(PhCountStringZ(zero + i) == 0); + for (i = 0; i < 16; i++) + assert(PhCountStringZ(asdf + i) == 16 - i); + + result = PhCopyBytesZ(inputA, 4, outputA, 4, &returnCount); + assert(!result && returnCount == 5); + result = PhCopyBytesZ(inputA, 100, outputA, 4, &returnCount); + assert(!result && returnCount == 5); + result = PhCopyBytesZ(inputA, 3, outputA, 4, &returnCount); + assert(result && returnCount == 4); + result = PhCopyBytesZ(inputA, 4, outputA, 5, &returnCount); + assert(result && returnCount == 5); + result = PhCopyBytesZ(inputA, 100, outputA, 5, &returnCount); + assert(result && returnCount == 5); + + result = PhCopyStringZ(inputW, 100, outputW, 4, &returnCount); + assert(!result && returnCount == 5); + result = PhCopyStringZ(inputW, 4, outputW, 5, &returnCount); + assert(result && returnCount == 5); + result = PhCopyStringZ(inputW, 100, outputW, 5, &returnCount); + assert(result && returnCount == 5); + + result = PhCopyStringZFromMultiByte(inputA, 4, outputW, 4, &returnCount); + assert(!result && returnCount == 5); + result = PhCopyStringZFromMultiByte(inputA, 100, outputW, 4, &returnCount); + assert(!result && returnCount == 5); + result = PhCopyStringZFromMultiByte(inputA, 3, outputW, 4, &returnCount); + assert(result && returnCount == 4); + result = PhCopyStringZFromMultiByte(inputA, 4, outputW, 5, &returnCount); + assert(result && returnCount == 5); + result = PhCopyStringZFromMultiByte(inputA, 100, outputW, 5, &returnCount); + assert(result && returnCount == 5); + + assert(PhCompareStringZNatural(L"abc", L"abc", FALSE) == 0); + assert(PhCompareStringZNatural(L"abc", L"abc", TRUE) == 0); + assert(PhCompareStringZNatural(L"abc", L"ABC", FALSE) != 0); + assert(PhCompareStringZNatural(L"abc", L"ABC", TRUE) == 0); + assert(PhCompareStringZNatural(L"abc", L"abd", FALSE) < 0); + assert(PhCompareStringZNatural(L"abe", L"abd", FALSE) > 0); + assert(PhCompareStringZNatural(L"1", L"2", FALSE) < 0); + assert(PhCompareStringZNatural(L"12", L"9", FALSE) > 0); + assert(PhCompareStringZNatural(L"file-1", L"file-9", FALSE) < 0); + assert(PhCompareStringZNatural(L"file-12", L"file-9", FALSE) > 0); + assert(PhCompareStringZNatural(L"file-12", L"file-90", FALSE) < 0); +} + +VOID Test_stringref( + VOID + ) +{ + ULONG i; + ULONG j; + PH_STRINGREF s1; + PH_STRINGREF s2; + PH_STRINGREF s3; + WCHAR buffer[26 * 2]; + + // PhEqualStringRef, PhFindCharInStringRef, PhFindLastCharInStringRef + + // Alignment tests + + s1.Buffer = buffer; + s1.Length = sizeof(buffer); + + for (i = 0; i < 26; i++) + s1.Buffer[i] = (WCHAR)i; + + for (i = 0; i < 26; i++) + assert(PhFindCharInStringRef(&s1, (WCHAR)i, FALSE) == i); + + memset(buffer, 0, sizeof(buffer)); + s1.Length = 0; + + for (i = 0; i < 26; i++) + assert(PhFindCharInStringRef(&s1, 0, FALSE) == -1); + + buffer[26] = 1; + + for (i = 0; i < 26; i++) + { + s1.Buffer = buffer + 26 - i; + s1.Length = i * sizeof(WCHAR); + assert(PhFindCharInStringRef(&s1, 1, FALSE) == -1); + } + + for (i = 1; i < 26; i++) + { + s1.Buffer = buffer; + s1.Length = i * 2 * sizeof(WCHAR); + + for (j = 0; j < i; j++) + { + buffer[j] = (WCHAR)('a' + j); + buffer[i + j] = (WCHAR)('A' + j); + } + + s2.Buffer = buffer; + s2.Length = i * sizeof(WCHAR); + s3.Buffer = buffer + i; + s3.Length = i * sizeof(WCHAR); + assert(!PhEqualStringRef(&s2, &s3, FALSE)); + assert(PhEqualStringRef(&s2, &s3, TRUE)); + + for (j = 0; j < i; j++) + { + buffer[j] = 'z'; + assert(!PhEqualStringRef(&s2, &s3, FALSE)); + assert(!PhEqualStringRef(&s2, &s3, TRUE)); + buffer[j] = (WCHAR)('a' + j); + } + + s3 = s2; + assert(PhEqualStringRef(&s2, &s3, FALSE)); + assert(PhEqualStringRef(&s2, &s3, TRUE)); + + for (j = 0; j < i; j++) + { + assert(PhFindCharInStringRef(&s1, s1.Buffer[j], FALSE) == j); + assert(PhFindLastCharInStringRef(&s1, s1.Buffer[j], FALSE) == j); + assert(PhFindCharInStringRef(&s1, s1.Buffer[j], TRUE) == j % i); + assert(PhFindLastCharInStringRef(&s1, s1.Buffer[j], TRUE) == i + j % i); + } + + s1.Length = i * sizeof(WCHAR); + + for (j = 0; j < i; j++) + { + assert(PhFindCharInStringRef(&s1, s1.Buffer[j] - ('a' - 'A'), FALSE) == -1); + assert(PhFindLastCharInStringRef(&s1, s1.Buffer[j] - ('a' - 'A'), FALSE) == -1); + assert(PhFindCharInStringRef(&s1, s1.Buffer[j] - ('a' - 'A'), TRUE) == j); + assert(PhFindLastCharInStringRef(&s1, s1.Buffer[j] - ('a' - 'A'), TRUE) == j); + } + + s1.Buffer += i; + + for (j = 0; j < i; j++) + { + assert(PhFindCharInStringRef(&s1, s1.Buffer[j] + ('a' - 'A'), FALSE) == -1); + assert(PhFindLastCharInStringRef(&s1, s1.Buffer[j] + ('a' - 'A'), FALSE) == -1); + assert(PhFindCharInStringRef(&s1, s1.Buffer[j] + ('a' - 'A'), TRUE) == j); + assert(PhFindLastCharInStringRef(&s1, s1.Buffer[j] + ('a' - 'A'), TRUE) == j); + } + } + + // PhFindStringInStringRef + +#define DO_STRSTR_TEST(func, s1, s2, expected, ...) \ + do { \ + PH_STRINGREF ___t1; \ + PH_STRINGREF ___t2; \ + PhInitializeStringRef(&___t1, s1); \ + PhInitializeStringRef(&___t2, s2); \ + assert(func(&___t1, &___t2, __VA_ARGS__) == expected); \ + } while (0) + + DO_STRSTR_TEST(PhFindStringInStringRef, L"asdfasdf", L"f", 3, FALSE); + DO_STRSTR_TEST(PhFindStringInStringRef, L"asdfasdf", L"g", -1, FALSE); + DO_STRSTR_TEST(PhFindStringInStringRef, L"asdfasdg", L"g", 7, FALSE); + DO_STRSTR_TEST(PhFindStringInStringRef, L"asdfasdg", L"asdg", 4, FALSE); + DO_STRSTR_TEST(PhFindStringInStringRef, L"asdfasdg", L"asdgh", -1, FALSE); + DO_STRSTR_TEST(PhFindStringInStringRef, L"asdfasdg", L"asdfasdg", 0, FALSE); + DO_STRSTR_TEST(PhFindStringInStringRef, L"asdfasdg", L"sdfasdg", 1, FALSE); + DO_STRSTR_TEST(PhFindStringInStringRef, L"asdfasdg", L"asdfasdgg", -1, FALSE); + DO_STRSTR_TEST(PhFindStringInStringRef, L"asdfasdg", L"asdfasdgggggg", -1, FALSE); + DO_STRSTR_TEST(PhFindStringInStringRef, L"", L"asdfasdgggggg", -1, FALSE); + DO_STRSTR_TEST(PhFindStringInStringRef, L"asdfasdg", L"", 0, FALSE); + DO_STRSTR_TEST(PhFindStringInStringRef, L"", L"", 0, FALSE); + // Test roll-over + DO_STRSTR_TEST(PhFindStringInStringRef, L"0sdfasdf1sdfasdf2sdfasdf3sdfasdg4sdfg", L"0sdfasdf1sdfasdf2sdfasdf3sdfasdg4sdfg", 0, FALSE); + DO_STRSTR_TEST(PhFindStringInStringRef, L"0sdfasdf1sdfasdf2sdfasdf3sdfasdg4sdfg", L"asdg4sdfg", 28, FALSE); + DO_STRSTR_TEST(PhFindStringInStringRef, L"0sdfasdf1sdfasdf2sdfasdf3sdfasdg4sdfg", L"asdg4Gdfg", -1, FALSE); +} + +VOID Test_hexstring( + VOID + ) +{ + BOOLEAN result; + PH_STRINGREF sr; + PPH_STRING string; + UCHAR buffer[16]; + + PhInitializeStringRef(&sr, L"0011223344"); + result = PhHexStringToBuffer(&sr, buffer); + assert(result && buffer[0] == 0 && buffer[1] == 0x11 && buffer[2] == 0x22 && buffer[3] == 0x33 && buffer[4] == 0x44); + + PhInitializeStringRef(&sr, L"00111"); + result = PhHexStringToBuffer(&sr, buffer); + assert(!result); + + buffer[0] = 0; + buffer[1] = 0x99; + buffer[2] = 0xff; + + string = PhBufferToHexString(buffer, 3); + assert(wcscmp(string->Buffer, L"0099ff") == 0); +} + +VOID Test_strint( + VOID + ) +{ + PH_STRINGREF sr; + LONG64 integer; + PPH_STRING string; + + PhInitializeStringRef(&sr, L"123"); + PhStringToInteger64(&sr, 0, &integer); + assert(integer == 123); + PhStringToInteger64(&sr, 10, &integer); + assert(integer == 123); + PhStringToInteger64(&sr, 8, &integer); + assert(integer == 0123); + PhStringToInteger64(&sr, 16, &integer); + assert(integer == 0x123); + + PhInitializeStringRef(&sr, L"0o123"); + PhStringToInteger64(&sr, 0, &integer); + assert(integer == 0123); + PhInitializeStringRef(&sr, L"0x123"); + PhStringToInteger64(&sr, 0, &integer); + assert(integer == 0x123); + + string = PhIntegerToString64(123, 0, FALSE); + assert(wcscmp(string->Buffer, L"123") == 0); + string = PhIntegerToString64(123, 10, FALSE); + assert(wcscmp(string->Buffer, L"123") == 0); + string = PhIntegerToString64(123, 8, FALSE); + assert(wcscmp(string->Buffer, L"173") == 0); + string = PhIntegerToString64(123, 16, FALSE); + assert(wcscmp(string->Buffer, L"7b") == 0); + + string = PhIntegerToString64(-123, 0, TRUE); + assert(wcscmp(string->Buffer, L"-123") == 0); + string = PhIntegerToString64(-123, 10, TRUE); + assert(wcscmp(string->Buffer, L"-123") == 0); + string = PhIntegerToString64(-123, 8, TRUE); + assert(wcscmp(string->Buffer, L"-173") == 0); + string = PhIntegerToString64(-123, 16, TRUE); + assert(wcscmp(string->Buffer, L"-7b") == 0); + + string = PhIntegerToString64(-123, 0, FALSE); + assert(wcscmp(string->Buffer, L"18446744073709551493") == 0); +} + +VOID Test_unicode( + VOID + ) +{ + BOOLEAN result; + ULONG codePoints[6]; + SIZE_T i; + WCHAR utf16[sizeof(codePoints) / sizeof(WCHAR)]; + CHAR utf8[sizeof(codePoints) / sizeof(CHAR)]; + ULONG numberOfCodePoints; + SIZE_T utf16Position = 0; + SIZE_T utf8Position = 0; + PPH_STRING utf16_1, utf16_2, utf16_3; + PPH_BYTES utf8_1, utf8_2, utf8_3; + + codePoints[0] = 0; + codePoints[1] = 0x50; + codePoints[2] = 0x312; + codePoints[3] = 0x3121; + codePoints[4] = 0x31212; + codePoints[5] = PH_UNICODE_MAX_CODE_POINT; + + for (i = 0; i < sizeof(codePoints) / sizeof(ULONG); i++) + { + result = PhEncodeUnicode(PH_UNICODE_UTF16, codePoints[i], utf16 + utf16Position, &numberOfCodePoints); + assert(result); + utf16Position += numberOfCodePoints; + + result = PhEncodeUnicode(PH_UNICODE_UTF8, codePoints[i], utf8 + utf8Position, &numberOfCodePoints); + assert(result); + utf8Position += numberOfCodePoints; + } + + utf16_1 = PhCreateStringEx(utf16, utf16Position * sizeof(WCHAR)); + utf8_1 = PhCreateBytesEx(utf8, utf8Position); + utf16_2 = PhConvertUtf8ToUtf16Ex(utf8_1->Buffer, utf8_1->Length); + utf8_2 = PhConvertUtf16ToUtf8Ex(utf16_1->Buffer, utf16_1->Length); + utf16_3 = PhConvertUtf8ToUtf16Ex(utf8_2->Buffer, utf8_2->Length); + utf8_3 = PhConvertUtf16ToUtf8Ex(utf16_2->Buffer, utf16_2->Length); + + assert(utf16_1->Length == utf16_2->Length); + assert(memcmp(utf16_1->Buffer, utf16_2->Buffer, utf16_1->Length) == 0); + assert(utf16_2->Length == utf16_3->Length); + assert(memcmp(utf16_2->Buffer, utf16_3->Buffer, utf16_2->Length) == 0); + + assert(utf8_1->Length == utf8_2->Length); + assert(memcmp(utf8_1->Buffer, utf8_2->Buffer, utf8_1->Length) == 0); + assert(utf8_2->Length == utf8_3->Length); + assert(memcmp(utf8_2->Buffer, utf8_3->Buffer, utf8_2->Length) == 0); +} + +VOID Test_basesup( + VOID + ) +{ + Test_time(); + Test_stringz(); + Test_stringref(); + Test_hexstring(); + Test_strint(); + Test_unicode(); +} diff --git a/tests/phlib-test/t_format.c b/tests/phlib-test/t_format.c index 1e9302e2a46e..825f7f609b8e 100644 --- a/tests/phlib-test/t_format.c +++ b/tests/phlib-test/t_format.c @@ -1,511 +1,511 @@ -#include "tests.h" - -static VOID Test_buffer( - VOID - ) -{ -#define OUTPUT_COUNT 10 - - BOOLEAN result; - PH_FORMAT format[1]; - WCHAR buffer[16]; - SIZE_T returnLength; - - format[0].Type = Int32FormatType; - format[0].u.Int32 = 1234567890; - - result = PhFormatToBuffer(format, 1, buffer, (OUTPUT_COUNT + 1) * sizeof(WCHAR), &returnLength); - assert(result && wcscmp(buffer, L"1234567890") == 0 && returnLength == (OUTPUT_COUNT + 1) * sizeof(WCHAR)); - result = PhFormatToBuffer(format, 1, buffer, 16 * sizeof(WCHAR), &returnLength); - assert(result && wcscmp(buffer, L"1234567890") == 0 && returnLength == (OUTPUT_COUNT + 1) * sizeof(WCHAR)); - result = PhFormatToBuffer(format, 1, buffer, OUTPUT_COUNT * sizeof(WCHAR), &returnLength); - assert(!result && buffer[0] == 0 && returnLength == (OUTPUT_COUNT + 1) * sizeof(WCHAR)); - result = PhFormatToBuffer(format, 1, buffer, 0, &returnLength); - assert(!result && returnLength == (OUTPUT_COUNT + 1) * sizeof(WCHAR)); - result = PhFormatToBuffer(format, 1, NULL, 9999, &returnLength); - assert(!result && returnLength == (OUTPUT_COUNT + 1) * sizeof(WCHAR)); -} - -static VOID Test_char( - VOID - ) -{ - BOOLEAN result; - PH_FORMAT format[2]; - WCHAR buffer[1024]; - - format[0].Type = CharFormatType; - format[0].u.Char = 'H'; - format[1].Type = CharFormatType; - format[1].u.Char = 'i'; - result = PhFormatToBuffer(format, 2, buffer, sizeof(buffer), NULL); - assert(result && wcscmp(buffer, L"Hi") == 0); -} - -static VOID Test_string( - VOID - ) -{ - BOOLEAN result; - PH_FORMAT format[4]; - WCHAR buffer[1024]; - - format[0].Type = StringFormatType; - PhInitializeStringRef(&format[0].u.String, L"This "); - format[1].Type = StringZFormatType; - format[1].u.StringZ = L"is "; - format[2].Type = MultiByteStringFormatType; - PhInitializeBytesRef(&format[2].u.MultiByteString, "a "); - format[3].Type = MultiByteStringZFormatType; - format[3].u.MultiByteStringZ = "string."; - result = PhFormatToBuffer(format, 4, buffer, sizeof(buffer), NULL); - assert(result && wcscmp(buffer, L"This is a string.") == 0); -} - -static BOOLEAN IsThousandSepComma( - VOID - ) -{ - WCHAR thousandSep[4]; - - if (!GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, thousandSep, 4)) - return FALSE; - if (thousandSep[0] != ',' || thousandSep[1] != 0) - return FALSE; - - return TRUE; -} - -static VOID Test_integer( - VOID - ) -{ - BOOLEAN result; - PH_FORMAT format[1]; - WCHAR buffer[1024]; - - // Basic - - format[0].Type = Int32FormatType; - format[0].u.Int32 = 0; - result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); - assert(result && wcscmp(buffer, L"0") == 0); - - format[0].Type = Int32FormatType; - format[0].u.Int32 = 123; - result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); - assert(result && wcscmp(buffer, L"123") == 0); - - format[0].Type = Int32FormatType; - format[0].u.Int32 = -123; - result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); - assert(result && wcscmp(buffer, L"-123") == 0); - - format[0].Type = UInt32FormatType; - format[0].u.UInt32 = -123; - result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); - assert(result && wcscmp(buffer, L"4294967173") == 0); - - format[0].Type = Int64FormatType; - format[0].u.Int64 = -1234567890; - result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); - assert(result && wcscmp(buffer, L"-1234567890") == 0); - - format[0].Type = UInt64FormatType; - format[0].u.UInt64 = 12345678901234567890; - result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); - assert(result && wcscmp(buffer, L"12345678901234567890") == 0); - - // Bases - - format[0].Type = UInt64FormatType | FormatUseRadix; - format[0].u.UInt64 = 12345678901234567890; - format[0].Radix = 16; - result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); - assert(result && wcscmp(buffer, L"ab54a98ceb1f0ad2") == 0); - - format[0].Type = UInt64FormatType | FormatUseRadix | FormatUpperCase; - format[0].u.UInt64 = 12345678901234567890; - format[0].Radix = 16; - result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); - assert(result && wcscmp(buffer, L"AB54A98CEB1F0AD2") == 0); - - format[0].Type = Int32FormatType | FormatUseRadix; - format[0].u.Int32 = -1234; - format[0].Radix = 8; - result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); - assert(result && wcscmp(buffer, L"-2322") == 0); - - // Prefix sign - - format[0].Type = Int32FormatType | FormatPrefixSign; - format[0].u.Int32 = 1234; - result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); - assert(result && wcscmp(buffer, L"+1234") == 0); - - format[0].Type = Int32FormatType | FormatPrefixSign; - format[0].u.Int32 = -1234; - result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); - assert(result && wcscmp(buffer, L"-1234") == 0); - - // Zero pad - - format[0].Type = Int32FormatType | FormatPadZeros; - format[0].Width = 6; - - format[0].u.Int32 = 0; - result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); - assert(result && wcscmp(buffer, L"000000") == 0); - format[0].u.Int32 = 1; - result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); - assert(result && wcscmp(buffer, L"000001") == 0); - format[0].u.Int32 = 12345; - result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); - assert(result && wcscmp(buffer, L"012345") == 0); - format[0].u.Int32 = 123456; - result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); - assert(result && wcscmp(buffer, L"123456") == 0); - format[0].u.Int32 = 1234567890; - result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); - assert(result && wcscmp(buffer, L"1234567890") == 0); - format[0].u.Int32 = -1; - result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); - assert(result && wcscmp(buffer, L"-00001") == 0); - format[0].u.Int32 = -1234; - result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); - assert(result && wcscmp(buffer, L"-01234") == 0); - format[0].u.Int32 = -12345; - result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); - assert(result && wcscmp(buffer, L"-12345") == 0); - format[0].u.Int32 = -1234567890; - result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); - assert(result && wcscmp(buffer, L"-1234567890") == 0); - - // Digit grouping - - if (!IsThousandSepComma()) - return; - - format[0].Type = Int32FormatType | FormatGroupDigits; - - format[0].u.Int32 = 0; - result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); - assert(result && wcscmp(buffer, L"0") == 0); - format[0].u.Int32 = 1; - result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); - assert(result && wcscmp(buffer, L"1") == 0); - format[0].u.Int32 = 12; - result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); - assert(result && wcscmp(buffer, L"12") == 0); - format[0].u.Int32 = 123; - result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); - assert(result && wcscmp(buffer, L"123") == 0); - format[0].u.Int32 = 1234; - result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); - assert(result && wcscmp(buffer, L"1,234") == 0); - format[0].u.Int32 = 12345; - result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); - assert(result && wcscmp(buffer, L"12,345") == 0); - format[0].u.Int32 = 123456; - result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); - assert(result && wcscmp(buffer, L"123,456") == 0); - format[0].u.Int32 = -123; - result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); - assert(result && wcscmp(buffer, L"-123") == 0); - format[0].u.Int32 = -1234; - result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); - assert(result && wcscmp(buffer, L"-1,234") == 0); - format[0].u.Int32 = -12345; - result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); - assert(result && wcscmp(buffer, L"-12,345") == 0); -} - -static VOID Test_float( - VOID - ) -{ - BOOLEAN result; - PH_FORMAT format[1]; - WCHAR buffer[1024]; - - // TODO: Standard and hexadecimal form - - // Basic - - format[0].Type = DoubleFormatType; - format[0].u.Double = 0; - result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); - assert(result && wcscmp(buffer, L"0.000000") == 0); - - format[0].Type = DoubleFormatType; - format[0].u.Double = 1; - result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); - assert(result && wcscmp(buffer, L"1.000000") == 0); - - format[0].Type = DoubleFormatType; - format[0].u.Double = 123456789; - result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); - assert(result && wcscmp(buffer, L"123456789.000000") == 0); - - format[0].Type = DoubleFormatType; - format[0].u.Double = 3.14159265358979; - result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); - assert(result && wcscmp(buffer, L"3.141593") == 0); - - // Precision - - format[0].Type = DoubleFormatType | FormatUsePrecision; - format[0].u.Double = 0; - format[0].Precision = 0; - result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); - assert(result && wcscmp(buffer, L"0") == 0); - - format[0].Type = DoubleFormatType | FormatUsePrecision; - format[0].u.Double = 3.14159265358979; - format[0].Precision = 0; - result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); - assert(result && wcscmp(buffer, L"3") == 0); - - format[0].Type = DoubleFormatType | FormatUsePrecision; - format[0].u.Double = 3.14159265358979; - format[0].Precision = 1; - result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); - assert(result && wcscmp(buffer, L"3.1") == 0); - - format[0].Type = DoubleFormatType | FormatUsePrecision; - format[0].u.Double = 3.14159265358979; - format[0].Precision = 4; - result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); - assert(result && wcscmp(buffer, L"3.1416") == 0); - - // Crop zeros - - format[0].Type = DoubleFormatType | FormatUsePrecision | FormatCropZeros; - format[0].u.Double = 0; - format[0].Precision = 3; - result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); - assert(result && wcscmp(buffer, L"0") == 0); - - format[0].Type = DoubleFormatType | FormatUsePrecision | FormatCropZeros; - format[0].u.Double = 1.2; - format[0].Precision = 3; - result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); - assert(result && wcscmp(buffer, L"1.2") == 0); - - format[0].Type = DoubleFormatType | FormatUsePrecision | FormatCropZeros; - format[0].u.Double = 1.21; - format[0].Precision = 3; - result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); - assert(result && wcscmp(buffer, L"1.21") == 0); - - format[0].Type = DoubleFormatType | FormatUsePrecision | FormatCropZeros; - format[0].u.Double = 1.216; - format[0].Precision = 3; - result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); - assert(result && wcscmp(buffer, L"1.216") == 0); - - format[0].Type = DoubleFormatType | FormatUsePrecision | FormatCropZeros; - format[0].u.Double = 1.2159; - format[0].Precision = 3; - result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); - assert(result && wcscmp(buffer, L"1.216") == 0); - - // Prefix sign - - format[0].Type = DoubleFormatType | FormatPrefixSign; - format[0].u.Double = 1234; - result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); - assert(result && wcscmp(buffer, L"+1234.000000") == 0); - - format[0].Type = DoubleFormatType | FormatUsePrecision | FormatPrefixSign; - format[0].u.Double = 1234; - format[0].Precision = 0; - result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); - assert(result && wcscmp(buffer, L"+1234") == 0); - - format[0].Type = DoubleFormatType | FormatPrefixSign; - format[0].u.Double = -1234; - result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); - assert(result && wcscmp(buffer, L"-1234.000000") == 0); - - format[0].Type = DoubleFormatType | FormatPrefixSign; - format[0].u.Double = -1234.12; - result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); - assert(result && wcscmp(buffer, L"-1234.120000") == 0); - - // Zero pad - - format[0].Type = DoubleFormatType | FormatUsePrecision | FormatPadZeros; - format[0].Width = 6; - - format[0].u.Double = 0; - format[0].Precision = 3; - result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); - assert(result && wcscmp(buffer, L"00.000") == 0); - format[0].u.Double = 1.23; - format[0].Precision = 3; - result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); - assert(result && wcscmp(buffer, L"01.230") == 0); - format[0].u.Double = 123456; - format[0].Precision = 3; - result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); - assert(result && wcscmp(buffer, L"123456.000") == 0); - format[0].u.Double = -1.23; - format[0].Precision = 2; - result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); - assert(result && wcscmp(buffer, L"-01.23") == 0); - format[0].u.Double = -1.23; - format[0].Precision = 3; - result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); - assert(result && wcscmp(buffer, L"-1.230") == 0); - - // Digit grouping - - if (!IsThousandSepComma()) - return; - - format[0].Type = DoubleFormatType | FormatUsePrecision | FormatGroupDigits; - - format[0].u.Double = 0; - format[0].Precision = 0; - result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); - assert(result && wcscmp(buffer, L"0") == 0); - format[0].u.Double = 1; - format[0].Precision = 0; - result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); - assert(result && wcscmp(buffer, L"1") == 0); - format[0].u.Double = 12; - format[0].Precision = 0; - result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); - assert(result && wcscmp(buffer, L"12") == 0); - format[0].u.Double = 123; - format[0].Precision = 0; - result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); - assert(result && wcscmp(buffer, L"123") == 0); - format[0].u.Double = 1234; - format[0].Precision = 0; - result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); - assert(result && wcscmp(buffer, L"1,234") == 0); - format[0].u.Double = 12345; - format[0].Precision = 0; - result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); - assert(result && wcscmp(buffer, L"12,345") == 0); - format[0].u.Double = 123456; - format[0].Precision = 0; - result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); - assert(result && wcscmp(buffer, L"123,456") == 0); - format[0].u.Double = -123; - format[0].Precision = 0; - result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); - assert(result && wcscmp(buffer, L"-123") == 0); - format[0].u.Double = -1234; - format[0].Precision = 0; - result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); - assert(result && wcscmp(buffer, L"-1,234") == 0); - format[0].u.Double = -12345; - format[0].Precision = 0; - result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); - assert(result && wcscmp(buffer, L"-12,345") == 0); - format[0].u.Double = -12345; - format[0].Precision = 2; - result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); - assert(result && wcscmp(buffer, L"-12,345.00") == 0); - format[0].u.Double = -9876543.21; - format[0].Precision = 5; - result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); - assert(result && wcscmp(buffer, L"-9,876,543.21000") == 0); -} - -static VOID Test_width( - VOID - ) -{ - BOOLEAN result; - PH_FORMAT format[2]; - WCHAR buffer[1024]; - - PhInitializeStringRef(&format[0].u.String, L"asdf"); - - format[0].Type = StringFormatType; - result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); - assert(result && wcscmp(buffer, L"asdf") == 0); - - // Left align - - format[0].Type = StringFormatType | FormatLeftAlign; - format[0].Width = 4; - result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); - assert(result && wcscmp(buffer, L"asdf") == 0); - - format[0].Type = StringFormatType | FormatLeftAlign; - format[0].Width = 2; - result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); - assert(result && wcscmp(buffer, L"asdf") == 0); - - format[0].Type = StringFormatType | FormatLeftAlign; - format[0].Width = 5; - result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); - assert(result && wcscmp(buffer, L"asdf ") == 0); - - format[0].Type = StringFormatType | FormatLeftAlign; - format[0].Width = 10; - result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); - assert(result && wcscmp(buffer, L"asdf ") == 0); - - format[0].Type = StringFormatType | FormatLeftAlign | FormatUsePad; - format[0].Width = 6; - format[0].Pad = '!'; - result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); - assert(result && wcscmp(buffer, L"asdf!!") == 0); - - // Right align - - format[0].Type = StringFormatType | FormatRightAlign; - format[0].Width = 4; - result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); - assert(result && wcscmp(buffer, L"asdf") == 0); - - format[0].Type = StringFormatType | FormatRightAlign; - format[0].Width = 2; - result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); - assert(result && wcscmp(buffer, L"asdf") == 0); - - format[0].Type = StringFormatType | FormatRightAlign; - format[0].Width = 5; - result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); - assert(result && wcscmp(buffer, L" asdf") == 0); - - format[0].Type = StringFormatType | FormatRightAlign; - format[0].Width = 10; - result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); - assert(result && wcscmp(buffer, L" asdf") == 0); - - format[0].Type = StringFormatType | FormatRightAlign | FormatUsePad; - format[0].Width = 6; - format[0].Pad = '!'; - result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); - assert(result && wcscmp(buffer, L"!!asdf") == 0); - - // Multiple - - format[0].Type = Int32FormatType | FormatRightAlign; - format[0].u.Int32 = 1234; - format[0].Width = 7; - format[1].Type = StringZFormatType | FormatLeftAlign; - format[1].u.StringZ = L"asdf"; - format[1].Width = 10; - result = PhFormatToBuffer(format, 2, buffer, sizeof(buffer), NULL); - assert(result && wcscmp(buffer, L" 1234asdf ") == 0); -} - -VOID Test_format( - VOID - ) -{ - Test_buffer(); - Test_char(); - Test_string(); - Test_integer(); - Test_float(); - Test_width(); -} +#include "tests.h" + +static VOID Test_buffer( + VOID + ) +{ +#define OUTPUT_COUNT 10 + + BOOLEAN result; + PH_FORMAT format[1]; + WCHAR buffer[16]; + SIZE_T returnLength; + + format[0].Type = Int32FormatType; + format[0].u.Int32 = 1234567890; + + result = PhFormatToBuffer(format, 1, buffer, (OUTPUT_COUNT + 1) * sizeof(WCHAR), &returnLength); + assert(result && wcscmp(buffer, L"1234567890") == 0 && returnLength == (OUTPUT_COUNT + 1) * sizeof(WCHAR)); + result = PhFormatToBuffer(format, 1, buffer, 16 * sizeof(WCHAR), &returnLength); + assert(result && wcscmp(buffer, L"1234567890") == 0 && returnLength == (OUTPUT_COUNT + 1) * sizeof(WCHAR)); + result = PhFormatToBuffer(format, 1, buffer, OUTPUT_COUNT * sizeof(WCHAR), &returnLength); + assert(!result && buffer[0] == 0 && returnLength == (OUTPUT_COUNT + 1) * sizeof(WCHAR)); + result = PhFormatToBuffer(format, 1, buffer, 0, &returnLength); + assert(!result && returnLength == (OUTPUT_COUNT + 1) * sizeof(WCHAR)); + result = PhFormatToBuffer(format, 1, NULL, 9999, &returnLength); + assert(!result && returnLength == (OUTPUT_COUNT + 1) * sizeof(WCHAR)); +} + +static VOID Test_char( + VOID + ) +{ + BOOLEAN result; + PH_FORMAT format[2]; + WCHAR buffer[1024]; + + format[0].Type = CharFormatType; + format[0].u.Char = 'H'; + format[1].Type = CharFormatType; + format[1].u.Char = 'i'; + result = PhFormatToBuffer(format, 2, buffer, sizeof(buffer), NULL); + assert(result && wcscmp(buffer, L"Hi") == 0); +} + +static VOID Test_string( + VOID + ) +{ + BOOLEAN result; + PH_FORMAT format[4]; + WCHAR buffer[1024]; + + format[0].Type = StringFormatType; + PhInitializeStringRef(&format[0].u.String, L"This "); + format[1].Type = StringZFormatType; + format[1].u.StringZ = L"is "; + format[2].Type = MultiByteStringFormatType; + PhInitializeBytesRef(&format[2].u.MultiByteString, "a "); + format[3].Type = MultiByteStringZFormatType; + format[3].u.MultiByteStringZ = "string."; + result = PhFormatToBuffer(format, 4, buffer, sizeof(buffer), NULL); + assert(result && wcscmp(buffer, L"This is a string.") == 0); +} + +static BOOLEAN IsThousandSepComma( + VOID + ) +{ + WCHAR thousandSep[4]; + + if (!GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, thousandSep, 4)) + return FALSE; + if (thousandSep[0] != ',' || thousandSep[1] != 0) + return FALSE; + + return TRUE; +} + +static VOID Test_integer( + VOID + ) +{ + BOOLEAN result; + PH_FORMAT format[1]; + WCHAR buffer[1024]; + + // Basic + + format[0].Type = Int32FormatType; + format[0].u.Int32 = 0; + result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); + assert(result && wcscmp(buffer, L"0") == 0); + + format[0].Type = Int32FormatType; + format[0].u.Int32 = 123; + result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); + assert(result && wcscmp(buffer, L"123") == 0); + + format[0].Type = Int32FormatType; + format[0].u.Int32 = -123; + result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); + assert(result && wcscmp(buffer, L"-123") == 0); + + format[0].Type = UInt32FormatType; + format[0].u.UInt32 = -123; + result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); + assert(result && wcscmp(buffer, L"4294967173") == 0); + + format[0].Type = Int64FormatType; + format[0].u.Int64 = -1234567890; + result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); + assert(result && wcscmp(buffer, L"-1234567890") == 0); + + format[0].Type = UInt64FormatType; + format[0].u.UInt64 = 12345678901234567890; + result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); + assert(result && wcscmp(buffer, L"12345678901234567890") == 0); + + // Bases + + format[0].Type = UInt64FormatType | FormatUseRadix; + format[0].u.UInt64 = 12345678901234567890; + format[0].Radix = 16; + result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); + assert(result && wcscmp(buffer, L"ab54a98ceb1f0ad2") == 0); + + format[0].Type = UInt64FormatType | FormatUseRadix | FormatUpperCase; + format[0].u.UInt64 = 12345678901234567890; + format[0].Radix = 16; + result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); + assert(result && wcscmp(buffer, L"AB54A98CEB1F0AD2") == 0); + + format[0].Type = Int32FormatType | FormatUseRadix; + format[0].u.Int32 = -1234; + format[0].Radix = 8; + result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); + assert(result && wcscmp(buffer, L"-2322") == 0); + + // Prefix sign + + format[0].Type = Int32FormatType | FormatPrefixSign; + format[0].u.Int32 = 1234; + result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); + assert(result && wcscmp(buffer, L"+1234") == 0); + + format[0].Type = Int32FormatType | FormatPrefixSign; + format[0].u.Int32 = -1234; + result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); + assert(result && wcscmp(buffer, L"-1234") == 0); + + // Zero pad + + format[0].Type = Int32FormatType | FormatPadZeros; + format[0].Width = 6; + + format[0].u.Int32 = 0; + result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); + assert(result && wcscmp(buffer, L"000000") == 0); + format[0].u.Int32 = 1; + result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); + assert(result && wcscmp(buffer, L"000001") == 0); + format[0].u.Int32 = 12345; + result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); + assert(result && wcscmp(buffer, L"012345") == 0); + format[0].u.Int32 = 123456; + result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); + assert(result && wcscmp(buffer, L"123456") == 0); + format[0].u.Int32 = 1234567890; + result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); + assert(result && wcscmp(buffer, L"1234567890") == 0); + format[0].u.Int32 = -1; + result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); + assert(result && wcscmp(buffer, L"-00001") == 0); + format[0].u.Int32 = -1234; + result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); + assert(result && wcscmp(buffer, L"-01234") == 0); + format[0].u.Int32 = -12345; + result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); + assert(result && wcscmp(buffer, L"-12345") == 0); + format[0].u.Int32 = -1234567890; + result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); + assert(result && wcscmp(buffer, L"-1234567890") == 0); + + // Digit grouping + + if (!IsThousandSepComma()) + return; + + format[0].Type = Int32FormatType | FormatGroupDigits; + + format[0].u.Int32 = 0; + result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); + assert(result && wcscmp(buffer, L"0") == 0); + format[0].u.Int32 = 1; + result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); + assert(result && wcscmp(buffer, L"1") == 0); + format[0].u.Int32 = 12; + result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); + assert(result && wcscmp(buffer, L"12") == 0); + format[0].u.Int32 = 123; + result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); + assert(result && wcscmp(buffer, L"123") == 0); + format[0].u.Int32 = 1234; + result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); + assert(result && wcscmp(buffer, L"1,234") == 0); + format[0].u.Int32 = 12345; + result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); + assert(result && wcscmp(buffer, L"12,345") == 0); + format[0].u.Int32 = 123456; + result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); + assert(result && wcscmp(buffer, L"123,456") == 0); + format[0].u.Int32 = -123; + result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); + assert(result && wcscmp(buffer, L"-123") == 0); + format[0].u.Int32 = -1234; + result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); + assert(result && wcscmp(buffer, L"-1,234") == 0); + format[0].u.Int32 = -12345; + result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); + assert(result && wcscmp(buffer, L"-12,345") == 0); +} + +static VOID Test_float( + VOID + ) +{ + BOOLEAN result; + PH_FORMAT format[1]; + WCHAR buffer[1024]; + + // TODO: Standard and hexadecimal form + + // Basic + + format[0].Type = DoubleFormatType; + format[0].u.Double = 0; + result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); + assert(result && wcscmp(buffer, L"0.000000") == 0); + + format[0].Type = DoubleFormatType; + format[0].u.Double = 1; + result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); + assert(result && wcscmp(buffer, L"1.000000") == 0); + + format[0].Type = DoubleFormatType; + format[0].u.Double = 123456789; + result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); + assert(result && wcscmp(buffer, L"123456789.000000") == 0); + + format[0].Type = DoubleFormatType; + format[0].u.Double = 3.14159265358979; + result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); + assert(result && wcscmp(buffer, L"3.141593") == 0); + + // Precision + + format[0].Type = DoubleFormatType | FormatUsePrecision; + format[0].u.Double = 0; + format[0].Precision = 0; + result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); + assert(result && wcscmp(buffer, L"0") == 0); + + format[0].Type = DoubleFormatType | FormatUsePrecision; + format[0].u.Double = 3.14159265358979; + format[0].Precision = 0; + result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); + assert(result && wcscmp(buffer, L"3") == 0); + + format[0].Type = DoubleFormatType | FormatUsePrecision; + format[0].u.Double = 3.14159265358979; + format[0].Precision = 1; + result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); + assert(result && wcscmp(buffer, L"3.1") == 0); + + format[0].Type = DoubleFormatType | FormatUsePrecision; + format[0].u.Double = 3.14159265358979; + format[0].Precision = 4; + result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); + assert(result && wcscmp(buffer, L"3.1416") == 0); + + // Crop zeros + + format[0].Type = DoubleFormatType | FormatUsePrecision | FormatCropZeros; + format[0].u.Double = 0; + format[0].Precision = 3; + result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); + assert(result && wcscmp(buffer, L"0") == 0); + + format[0].Type = DoubleFormatType | FormatUsePrecision | FormatCropZeros; + format[0].u.Double = 1.2; + format[0].Precision = 3; + result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); + assert(result && wcscmp(buffer, L"1.2") == 0); + + format[0].Type = DoubleFormatType | FormatUsePrecision | FormatCropZeros; + format[0].u.Double = 1.21; + format[0].Precision = 3; + result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); + assert(result && wcscmp(buffer, L"1.21") == 0); + + format[0].Type = DoubleFormatType | FormatUsePrecision | FormatCropZeros; + format[0].u.Double = 1.216; + format[0].Precision = 3; + result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); + assert(result && wcscmp(buffer, L"1.216") == 0); + + format[0].Type = DoubleFormatType | FormatUsePrecision | FormatCropZeros; + format[0].u.Double = 1.2159; + format[0].Precision = 3; + result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); + assert(result && wcscmp(buffer, L"1.216") == 0); + + // Prefix sign + + format[0].Type = DoubleFormatType | FormatPrefixSign; + format[0].u.Double = 1234; + result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); + assert(result && wcscmp(buffer, L"+1234.000000") == 0); + + format[0].Type = DoubleFormatType | FormatUsePrecision | FormatPrefixSign; + format[0].u.Double = 1234; + format[0].Precision = 0; + result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); + assert(result && wcscmp(buffer, L"+1234") == 0); + + format[0].Type = DoubleFormatType | FormatPrefixSign; + format[0].u.Double = -1234; + result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); + assert(result && wcscmp(buffer, L"-1234.000000") == 0); + + format[0].Type = DoubleFormatType | FormatPrefixSign; + format[0].u.Double = -1234.12; + result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); + assert(result && wcscmp(buffer, L"-1234.120000") == 0); + + // Zero pad + + format[0].Type = DoubleFormatType | FormatUsePrecision | FormatPadZeros; + format[0].Width = 6; + + format[0].u.Double = 0; + format[0].Precision = 3; + result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); + assert(result && wcscmp(buffer, L"00.000") == 0); + format[0].u.Double = 1.23; + format[0].Precision = 3; + result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); + assert(result && wcscmp(buffer, L"01.230") == 0); + format[0].u.Double = 123456; + format[0].Precision = 3; + result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); + assert(result && wcscmp(buffer, L"123456.000") == 0); + format[0].u.Double = -1.23; + format[0].Precision = 2; + result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); + assert(result && wcscmp(buffer, L"-01.23") == 0); + format[0].u.Double = -1.23; + format[0].Precision = 3; + result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); + assert(result && wcscmp(buffer, L"-1.230") == 0); + + // Digit grouping + + if (!IsThousandSepComma()) + return; + + format[0].Type = DoubleFormatType | FormatUsePrecision | FormatGroupDigits; + + format[0].u.Double = 0; + format[0].Precision = 0; + result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); + assert(result && wcscmp(buffer, L"0") == 0); + format[0].u.Double = 1; + format[0].Precision = 0; + result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); + assert(result && wcscmp(buffer, L"1") == 0); + format[0].u.Double = 12; + format[0].Precision = 0; + result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); + assert(result && wcscmp(buffer, L"12") == 0); + format[0].u.Double = 123; + format[0].Precision = 0; + result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); + assert(result && wcscmp(buffer, L"123") == 0); + format[0].u.Double = 1234; + format[0].Precision = 0; + result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); + assert(result && wcscmp(buffer, L"1,234") == 0); + format[0].u.Double = 12345; + format[0].Precision = 0; + result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); + assert(result && wcscmp(buffer, L"12,345") == 0); + format[0].u.Double = 123456; + format[0].Precision = 0; + result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); + assert(result && wcscmp(buffer, L"123,456") == 0); + format[0].u.Double = -123; + format[0].Precision = 0; + result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); + assert(result && wcscmp(buffer, L"-123") == 0); + format[0].u.Double = -1234; + format[0].Precision = 0; + result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); + assert(result && wcscmp(buffer, L"-1,234") == 0); + format[0].u.Double = -12345; + format[0].Precision = 0; + result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); + assert(result && wcscmp(buffer, L"-12,345") == 0); + format[0].u.Double = -12345; + format[0].Precision = 2; + result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); + assert(result && wcscmp(buffer, L"-12,345.00") == 0); + format[0].u.Double = -9876543.21; + format[0].Precision = 5; + result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); + assert(result && wcscmp(buffer, L"-9,876,543.21000") == 0); +} + +static VOID Test_width( + VOID + ) +{ + BOOLEAN result; + PH_FORMAT format[2]; + WCHAR buffer[1024]; + + PhInitializeStringRef(&format[0].u.String, L"asdf"); + + format[0].Type = StringFormatType; + result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); + assert(result && wcscmp(buffer, L"asdf") == 0); + + // Left align + + format[0].Type = StringFormatType | FormatLeftAlign; + format[0].Width = 4; + result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); + assert(result && wcscmp(buffer, L"asdf") == 0); + + format[0].Type = StringFormatType | FormatLeftAlign; + format[0].Width = 2; + result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); + assert(result && wcscmp(buffer, L"asdf") == 0); + + format[0].Type = StringFormatType | FormatLeftAlign; + format[0].Width = 5; + result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); + assert(result && wcscmp(buffer, L"asdf ") == 0); + + format[0].Type = StringFormatType | FormatLeftAlign; + format[0].Width = 10; + result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); + assert(result && wcscmp(buffer, L"asdf ") == 0); + + format[0].Type = StringFormatType | FormatLeftAlign | FormatUsePad; + format[0].Width = 6; + format[0].Pad = '!'; + result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); + assert(result && wcscmp(buffer, L"asdf!!") == 0); + + // Right align + + format[0].Type = StringFormatType | FormatRightAlign; + format[0].Width = 4; + result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); + assert(result && wcscmp(buffer, L"asdf") == 0); + + format[0].Type = StringFormatType | FormatRightAlign; + format[0].Width = 2; + result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); + assert(result && wcscmp(buffer, L"asdf") == 0); + + format[0].Type = StringFormatType | FormatRightAlign; + format[0].Width = 5; + result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); + assert(result && wcscmp(buffer, L" asdf") == 0); + + format[0].Type = StringFormatType | FormatRightAlign; + format[0].Width = 10; + result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); + assert(result && wcscmp(buffer, L" asdf") == 0); + + format[0].Type = StringFormatType | FormatRightAlign | FormatUsePad; + format[0].Width = 6; + format[0].Pad = '!'; + result = PhFormatToBuffer(format, 1, buffer, sizeof(buffer), NULL); + assert(result && wcscmp(buffer, L"!!asdf") == 0); + + // Multiple + + format[0].Type = Int32FormatType | FormatRightAlign; + format[0].u.Int32 = 1234; + format[0].Width = 7; + format[1].Type = StringZFormatType | FormatLeftAlign; + format[1].u.StringZ = L"asdf"; + format[1].Width = 10; + result = PhFormatToBuffer(format, 2, buffer, sizeof(buffer), NULL); + assert(result && wcscmp(buffer, L" 1234asdf ") == 0); +} + +VOID Test_format( + VOID + ) +{ + Test_buffer(); + Test_char(); + Test_string(); + Test_integer(); + Test_float(); + Test_width(); +} diff --git a/tests/phlib-test/tests.h b/tests/phlib-test/tests.h index 8d1fd9b5b872..9e65f73be328 100644 --- a/tests/phlib-test/tests.h +++ b/tests/phlib-test/tests.h @@ -1,22 +1,22 @@ -#ifndef TESTS_H -#define TESTS_H - -#include - -VOID Test_basesup( - VOID - ); - -VOID Test_avltree( - VOID - ); - -VOID Test_format( - VOID - ); - -VOID Test_util( - VOID - ); - -#endif +#ifndef TESTS_H +#define TESTS_H + +#include + +VOID Test_basesup( + VOID + ); + +VOID Test_avltree( + VOID + ); + +VOID Test_format( + VOID + ); + +VOID Test_util( + VOID + ); + +#endif diff --git a/tools/GenerateZw/GenerateZw.sln b/tools/GenerateZw/GenerateZw.sln index e41ba905db6c..95020ef1863e 100644 --- a/tools/GenerateZw/GenerateZw.sln +++ b/tools/GenerateZw/GenerateZw.sln @@ -1,22 +1,22 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.26228.4 -MinimumVisualStudioVersion = 15.0.26228.4 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GenerateZw", "GenerateZw\GenerateZw.csproj", "{10589240-84D9-4935-9868-7FFADB6545F9}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|x86 = Debug|x86 - Release|x86 = Release|x86 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {10589240-84D9-4935-9868-7FFADB6545F9}.Debug|x86.ActiveCfg = Debug|x86 - {10589240-84D9-4935-9868-7FFADB6545F9}.Debug|x86.Build.0 = Debug|x86 - {10589240-84D9-4935-9868-7FFADB6545F9}.Release|x86.ActiveCfg = Release|x86 - {10589240-84D9-4935-9868-7FFADB6545F9}.Release|x86.Build.0 = Release|x86 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.26228.4 +MinimumVisualStudioVersion = 15.0.26228.4 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GenerateZw", "GenerateZw\GenerateZw.csproj", "{10589240-84D9-4935-9868-7FFADB6545F9}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x86 = Debug|x86 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {10589240-84D9-4935-9868-7FFADB6545F9}.Debug|x86.ActiveCfg = Debug|x86 + {10589240-84D9-4935-9868-7FFADB6545F9}.Debug|x86.Build.0 = Debug|x86 + {10589240-84D9-4935-9868-7FFADB6545F9}.Release|x86.ActiveCfg = Release|x86 + {10589240-84D9-4935-9868-7FFADB6545F9}.Release|x86.Build.0 = Release|x86 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/tools/GenerateZw/GenerateZw/GenerateZw.csproj b/tools/GenerateZw/GenerateZw/GenerateZw.csproj index 43a71f805235..ee20581f9977 100644 --- a/tools/GenerateZw/GenerateZw/GenerateZw.csproj +++ b/tools/GenerateZw/GenerateZw/GenerateZw.csproj @@ -1,61 +1,61 @@ - - - - Debug - x86 - 8.0.30703 - 2.0 - {10589240-84D9-4935-9868-7FFADB6545F9} - Exe - Properties - GenerateZw - GenerateZw - v4.6.1 - 512 - - - x86 - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - false - - - x86 - pdbonly - true - bin\Release\ - prompt - 4 - false - - - - - - - - - - - - - - - - - - - - + + + + Debug + x86 + 8.0.30703 + 2.0 + {10589240-84D9-4935-9868-7FFADB6545F9} + Exe + Properties + GenerateZw + GenerateZw + v4.6.1 + 512 + + + x86 + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + false + + + x86 + pdbonly + true + bin\Release\ + prompt + 4 + false + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tools/fixlib/fixlib.c b/tools/fixlib/fixlib.c index 3109b12dac49..abb2688f9513 100644 --- a/tools/fixlib/fixlib.c +++ b/tools/fixlib/fixlib.c @@ -1,113 +1,113 @@ -#include -#include - -#define ARG_OUTFILE 1 - -PPH_STRING inFile = NULL; -PPH_STRING outFile = NULL; - -BOOLEAN NTAPI CommandLineCallback( - _In_opt_ PPH_COMMAND_LINE_OPTION Option, - _In_opt_ PPH_STRING Value, - _In_opt_ PVOID Context - ) -{ - if (Option) - { - switch (Option->Id) - { - case ARG_OUTFILE: - { - PhSwapReference(&outFile, Value); - } - break; - } - } - else - { - PhSwapReference(&inFile, Value); - } - - return TRUE; -} - -int __cdecl main(int argc, char *argv[]) -{ - static PH_COMMAND_LINE_OPTION options[] = - { - { ARG_OUTFILE, L"o", MandatoryArgumentType } - }; - NTSTATUS status; - PH_STRINGREF commandLine; - PH_MAPPED_ARCHIVE mappedArchive; - PH_MAPPED_ARCHIVE_MEMBER member; - PH_MAPPED_ARCHIVE_IMPORT_ENTRY entry; - - if (!NT_SUCCESS(PhInitializePhLib())) - return 1; - - PhUnicodeStringToStringRef(&NtCurrentPeb()->ProcessParameters->CommandLine, &commandLine); - - if (!PhParseCommandLine( - &commandLine, - options, - sizeof(options) / sizeof(PH_COMMAND_LINE_OPTION), - PH_COMMAND_LINE_IGNORE_FIRST_PART, - CommandLineCallback, - NULL - ) || !inFile) - { - wprintf(L"Usage: fixlib [-o outfile] infile\n"); - return 1; - } - - if (!outFile) - outFile = inFile; - - CopyFile(inFile->Buffer, outFile->Buffer, FALSE); - - status = PhLoadMappedArchive(outFile->Buffer, NULL, FALSE, &mappedArchive); - - if (!NT_SUCCESS(status)) - { - wprintf(L"Error: %s\n", PhGetStringOrDefault(PhGetNtMessage(status), L"unknown")); - return status; - } - - member = *(mappedArchive.LastStandardMember); - - while (NT_SUCCESS(PhGetNextMappedArchiveMember(&member, &member))) - { - if (NT_SUCCESS(PhGetMappedArchiveImportEntry(&member, &entry))) - { - IMPORT_OBJECT_HEADER *header; - PWSTR type = L"unknown"; - - switch (entry.NameType) - { - case IMPORT_OBJECT_ORDINAL: - type = L"ordinal"; - break; - case IMPORT_OBJECT_NAME: - type = L"name"; - break; - case IMPORT_OBJECT_NAME_NO_PREFIX: - type = L"name-noprefix"; - break; - case IMPORT_OBJECT_NAME_UNDECORATE: - type = L"name-undecorate"; - break; - } - - wprintf(L"%S: %S (%s)\n", entry.DllName, entry.Name, type); - - header = (IMPORT_OBJECT_HEADER *)member.Data; - - // Changes - - header->NameType = IMPORT_OBJECT_NAME_UNDECORATE; - } - } - - PhUnloadMappedArchive(&mappedArchive); -} +#include +#include + +#define ARG_OUTFILE 1 + +PPH_STRING inFile = NULL; +PPH_STRING outFile = NULL; + +BOOLEAN NTAPI CommandLineCallback( + _In_opt_ PPH_COMMAND_LINE_OPTION Option, + _In_opt_ PPH_STRING Value, + _In_opt_ PVOID Context + ) +{ + if (Option) + { + switch (Option->Id) + { + case ARG_OUTFILE: + { + PhSwapReference(&outFile, Value); + } + break; + } + } + else + { + PhSwapReference(&inFile, Value); + } + + return TRUE; +} + +int __cdecl main(int argc, char *argv[]) +{ + static PH_COMMAND_LINE_OPTION options[] = + { + { ARG_OUTFILE, L"o", MandatoryArgumentType } + }; + NTSTATUS status; + PH_STRINGREF commandLine; + PH_MAPPED_ARCHIVE mappedArchive; + PH_MAPPED_ARCHIVE_MEMBER member; + PH_MAPPED_ARCHIVE_IMPORT_ENTRY entry; + + if (!NT_SUCCESS(PhInitializePhLib())) + return 1; + + PhUnicodeStringToStringRef(&NtCurrentPeb()->ProcessParameters->CommandLine, &commandLine); + + if (!PhParseCommandLine( + &commandLine, + options, + sizeof(options) / sizeof(PH_COMMAND_LINE_OPTION), + PH_COMMAND_LINE_IGNORE_FIRST_PART, + CommandLineCallback, + NULL + ) || !inFile) + { + wprintf(L"Usage: fixlib [-o outfile] infile\n"); + return 1; + } + + if (!outFile) + outFile = inFile; + + CopyFile(inFile->Buffer, outFile->Buffer, FALSE); + + status = PhLoadMappedArchive(outFile->Buffer, NULL, FALSE, &mappedArchive); + + if (!NT_SUCCESS(status)) + { + wprintf(L"Error: %s\n", PhGetStringOrDefault(PhGetNtMessage(status), L"unknown")); + return status; + } + + member = *(mappedArchive.LastStandardMember); + + while (NT_SUCCESS(PhGetNextMappedArchiveMember(&member, &member))) + { + if (NT_SUCCESS(PhGetMappedArchiveImportEntry(&member, &entry))) + { + IMPORT_OBJECT_HEADER *header; + PWSTR type = L"unknown"; + + switch (entry.NameType) + { + case IMPORT_OBJECT_ORDINAL: + type = L"ordinal"; + break; + case IMPORT_OBJECT_NAME: + type = L"name"; + break; + case IMPORT_OBJECT_NAME_NO_PREFIX: + type = L"name-noprefix"; + break; + case IMPORT_OBJECT_NAME_UNDECORATE: + type = L"name-undecorate"; + break; + } + + wprintf(L"%S: %S (%s)\n", entry.DllName, entry.Name, type); + + header = (IMPORT_OBJECT_HEADER *)member.Data; + + // Changes + + header->NameType = IMPORT_OBJECT_NAME_UNDECORATE; + } + } + + PhUnloadMappedArchive(&mappedArchive); +} diff --git a/tools/fixlib/fixlib.vcxproj b/tools/fixlib/fixlib.vcxproj index 39611dda7afb..1d3d7d12e3c7 100644 --- a/tools/fixlib/fixlib.vcxproj +++ b/tools/fixlib/fixlib.vcxproj @@ -1,109 +1,109 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - - {31F4AA06-7ED5-4A6D-B901-19AD4BD16175} - fixlib - Win32Proj - 10.0.15063.0 - - - - Application - Unicode - true - v141 - - - Application - Unicode - v141 - - - - - - - - - - - - - $(ProjectDir)bin\$(Configuration)\ - $(ProjectDir)obj\$(Configuration)\ - false - $(ProjectDir)bin\$(Configuration)\ - $(ProjectDir)obj\$(Configuration)\ - false - - - - Disabled - ..\..\phnt\include;..\..\phlib\include;%(AdditionalIncludeDirectories) - _PHLIB_;_CONSOLE;WIN32;DEBUG;%(PreprocessorDefinitions) - EnableFastChecks - MultiThreadedDebug - Level3 - ProgramDatabase - StdCall - true - true - - - noenv.obj;phlib.lib;ntdll.lib;%(AdditionalDependencies) - ..\..\phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) - true - Console - MachineX86 - 5.01 - - - - - MaxSpeed - true - ..\..\phnt\include;..\..\phlib\include;%(AdditionalIncludeDirectories) - _PHLIB_;_CONSOLE;WIN32;NDEBUG;%(PreprocessorDefinitions) - MultiThreaded - true - Level3 - ProgramDatabase - StdCall - true - true - - - noenv.obj;phlib.lib;ntdll.lib;%(AdditionalDependencies) - ..\..\phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) - true - Console - true - true - MachineX86 - true - 5.01 - - - - - - - - {477d0215-f252-41a1-874b-f27e3ea1ed17} - false - - - - - + + + + + Debug + Win32 + + + Release + Win32 + + + + {31F4AA06-7ED5-4A6D-B901-19AD4BD16175} + fixlib + Win32Proj + 10.0.15063.0 + + + + Application + Unicode + true + v141 + + + Application + Unicode + v141 + + + + + + + + + + + + + $(ProjectDir)bin\$(Configuration)\ + $(ProjectDir)obj\$(Configuration)\ + false + $(ProjectDir)bin\$(Configuration)\ + $(ProjectDir)obj\$(Configuration)\ + false + + + + Disabled + ..\..\phnt\include;..\..\phlib\include;%(AdditionalIncludeDirectories) + _PHLIB_;_CONSOLE;WIN32;DEBUG;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + Level3 + ProgramDatabase + StdCall + true + true + + + noenv.obj;phlib.lib;ntdll.lib;%(AdditionalDependencies) + ..\..\phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) + true + Console + MachineX86 + 5.01 + + + + + MaxSpeed + true + ..\..\phnt\include;..\..\phlib\include;%(AdditionalIncludeDirectories) + _PHLIB_;_CONSOLE;WIN32;NDEBUG;%(PreprocessorDefinitions) + MultiThreaded + true + Level3 + ProgramDatabase + StdCall + true + true + + + noenv.obj;phlib.lib;ntdll.lib;%(AdditionalDependencies) + ..\..\phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) + true + Console + true + true + MachineX86 + true + 5.01 + + + + + + + + {477d0215-f252-41a1-874b-f27e3ea1ed17} + false + + + + + \ No newline at end of file diff --git a/tools/peview/include/peview.h b/tools/peview/include/peview.h index 2ac8644b65e4..bcb62f34d4ce 100644 --- a/tools/peview/include/peview.h +++ b/tools/peview/include/peview.h @@ -1,39 +1,39 @@ -#ifndef PEVIEW_H -#define PEVIEW_H - -#include -#include -#include -#include -#include "resource.h" - -extern PPH_STRING PvFileName; - -// peprp - -VOID PvPeProperties( - VOID - ); - -// libprp - -VOID PvLibProperties( - VOID - ); - -// misc - -PPH_STRING PvResolveShortcutTarget( - _In_ PPH_STRING ShortcutFileName - ); - -VOID PvCopyListView( - _In_ HWND ListViewHandle - ); - -VOID PvHandleListViewNotifyForCopy( - _In_ LPARAM lParam, - _In_ HWND ListViewHandle - ); - -#endif +#ifndef PEVIEW_H +#define PEVIEW_H + +#include +#include +#include +#include +#include "resource.h" + +extern PPH_STRING PvFileName; + +// peprp + +VOID PvPeProperties( + VOID + ); + +// libprp + +VOID PvLibProperties( + VOID + ); + +// misc + +PPH_STRING PvResolveShortcutTarget( + _In_ PPH_STRING ShortcutFileName + ); + +VOID PvCopyListView( + _In_ HWND ListViewHandle + ); + +VOID PvHandleListViewNotifyForCopy( + _In_ LPARAM lParam, + _In_ HWND ListViewHandle + ); + +#endif diff --git a/tools/peview/libprp.c b/tools/peview/libprp.c index 89d473b9103e..b7ee42316c31 100644 --- a/tools/peview/libprp.c +++ b/tools/peview/libprp.c @@ -1,181 +1,181 @@ -/* - * Process Hacker - - * PE viewer - * - * Copyright (C) 2010 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include -#include -#include - -INT_PTR CALLBACK PvpLibExportsDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -PH_MAPPED_ARCHIVE PvMappedArchive; - -VOID PvLibProperties( - VOID - ) -{ - NTSTATUS status; - PROPSHEETHEADER propSheetHeader = { sizeof(propSheetHeader) }; - PROPSHEETPAGE propSheetPage; - HPROPSHEETPAGE pages[1]; - - status = PhLoadMappedArchive(PvFileName->Buffer, NULL, TRUE, &PvMappedArchive); - - if (!NT_SUCCESS(status)) - { - PhShowStatus(NULL, L"Unable to load the archive file", status, 0); - return; - } - - propSheetHeader.dwFlags = - PSH_NOAPPLYNOW | - PSH_NOCONTEXTHELP | - PSH_PROPTITLE; - propSheetHeader.hwndParent = NULL; - propSheetHeader.pszCaption = PvFileName->Buffer; - propSheetHeader.nPages = 0; - propSheetHeader.nStartPage = 0; - propSheetHeader.phpage = pages; - - // Exports page - memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); - propSheetPage.dwSize = sizeof(PROPSHEETPAGE); - propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_LIBEXPORTS); - propSheetPage.pfnDlgProc = PvpLibExportsDlgProc; - pages[propSheetHeader.nPages++] = CreatePropertySheetPage(&propSheetPage); - - PhModalPropertySheet(&propSheetHeader); - - PhUnloadMappedArchive(&PvMappedArchive); -} - -INT_PTR CALLBACK PvpLibExportsDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - switch (uMsg) - { - case WM_INITDIALOG: - { - ULONG fallbackColumns[] = { 0, 1, 2, 3 }; - HWND lvHandle; - PH_MAPPED_ARCHIVE_MEMBER member; - PH_MAPPED_ARCHIVE_IMPORT_ENTRY importEntry; - - PhCenterWindow(GetParent(hwndDlg), NULL); - - lvHandle = GetDlgItem(hwndDlg, IDC_LIST); - PhSetListViewStyle(lvHandle, FALSE, TRUE); - PhSetControlTheme(lvHandle, L"explorer"); - PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 60, L"DLL"); - PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 200, L"Name"); - PhAddListViewColumn(lvHandle, 2, 2, 2, LVCFMT_LEFT, 40, L"Ordinal/Hint"); - PhAddListViewColumn(lvHandle, 3, 3, 3, LVCFMT_LEFT, 40, L"Type"); - PhAddListViewColumn(lvHandle, 4, 4, 4, LVCFMT_LEFT, 60, L"Name type"); - PhSetExtendedListView(lvHandle); - ExtendedListView_AddFallbackColumns(lvHandle, 4, fallbackColumns); - - member = *PvMappedArchive.LastStandardMember; - - while (NT_SUCCESS(PhGetNextMappedArchiveMember(&member, &member))) - { - if (NT_SUCCESS(PhGetMappedArchiveImportEntry(&member, &importEntry))) - { - INT lvItemIndex; - PPH_STRING name; - WCHAR number[PH_INT32_STR_LEN_1]; - PWSTR type; - - name = PhZeroExtendToUtf16(importEntry.DllName); - lvItemIndex = PhAddListViewItem(lvHandle, MAXINT, name->Buffer, NULL); - PhDereferenceObject(name); - - name = PhZeroExtendToUtf16(importEntry.Name); - PhSetListViewSubItem(lvHandle, lvItemIndex, 1, name->Buffer); - PhDereferenceObject(name); - - // Ordinal is unioned with NameHint, so this works both ways. - PhPrintUInt32(number, importEntry.Ordinal); - PhSetListViewSubItem(lvHandle, lvItemIndex, 2, number); - - switch (importEntry.Type) - { - case IMPORT_OBJECT_CODE: - type = L"Code"; - break; - case IMPORT_OBJECT_DATA: - type = L"Data"; - break; - case IMPORT_OBJECT_CONST: - type = L"Const"; - break; - default: - type = L"Unknown"; - break; - } - - PhSetListViewSubItem(lvHandle, lvItemIndex, 3, type); - - switch (importEntry.NameType) - { - case IMPORT_OBJECT_ORDINAL: - type = L"Ordinal"; - break; - case IMPORT_OBJECT_NAME: - type = L"Name"; - break; - case IMPORT_OBJECT_NAME_NO_PREFIX: - type = L"Name, no prefix"; - break; - case IMPORT_OBJECT_NAME_UNDECORATE: - type = L"Name, undecorate"; - break; - default: - type = L"Unknown"; - break; - } - - PhSetListViewSubItem(lvHandle, lvItemIndex, 4, type); - } - } - - ExtendedListView_SortItems(lvHandle); - - EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); - } - break; - case WM_NOTIFY: - { - PvHandleListViewNotifyForCopy(lParam, GetDlgItem(hwndDlg, IDC_LIST)); - } - break; - } - - return FALSE; -} +/* + * Process Hacker - + * PE viewer + * + * Copyright (C) 2010 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include +#include +#include + +INT_PTR CALLBACK PvpLibExportsDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +PH_MAPPED_ARCHIVE PvMappedArchive; + +VOID PvLibProperties( + VOID + ) +{ + NTSTATUS status; + PROPSHEETHEADER propSheetHeader = { sizeof(propSheetHeader) }; + PROPSHEETPAGE propSheetPage; + HPROPSHEETPAGE pages[1]; + + status = PhLoadMappedArchive(PvFileName->Buffer, NULL, TRUE, &PvMappedArchive); + + if (!NT_SUCCESS(status)) + { + PhShowStatus(NULL, L"Unable to load the archive file", status, 0); + return; + } + + propSheetHeader.dwFlags = + PSH_NOAPPLYNOW | + PSH_NOCONTEXTHELP | + PSH_PROPTITLE; + propSheetHeader.hwndParent = NULL; + propSheetHeader.pszCaption = PvFileName->Buffer; + propSheetHeader.nPages = 0; + propSheetHeader.nStartPage = 0; + propSheetHeader.phpage = pages; + + // Exports page + memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); + propSheetPage.dwSize = sizeof(PROPSHEETPAGE); + propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_LIBEXPORTS); + propSheetPage.pfnDlgProc = PvpLibExportsDlgProc; + pages[propSheetHeader.nPages++] = CreatePropertySheetPage(&propSheetPage); + + PhModalPropertySheet(&propSheetHeader); + + PhUnloadMappedArchive(&PvMappedArchive); +} + +INT_PTR CALLBACK PvpLibExportsDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + switch (uMsg) + { + case WM_INITDIALOG: + { + ULONG fallbackColumns[] = { 0, 1, 2, 3 }; + HWND lvHandle; + PH_MAPPED_ARCHIVE_MEMBER member; + PH_MAPPED_ARCHIVE_IMPORT_ENTRY importEntry; + + PhCenterWindow(GetParent(hwndDlg), NULL); + + lvHandle = GetDlgItem(hwndDlg, IDC_LIST); + PhSetListViewStyle(lvHandle, FALSE, TRUE); + PhSetControlTheme(lvHandle, L"explorer"); + PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 60, L"DLL"); + PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 200, L"Name"); + PhAddListViewColumn(lvHandle, 2, 2, 2, LVCFMT_LEFT, 40, L"Ordinal/Hint"); + PhAddListViewColumn(lvHandle, 3, 3, 3, LVCFMT_LEFT, 40, L"Type"); + PhAddListViewColumn(lvHandle, 4, 4, 4, LVCFMT_LEFT, 60, L"Name type"); + PhSetExtendedListView(lvHandle); + ExtendedListView_AddFallbackColumns(lvHandle, 4, fallbackColumns); + + member = *PvMappedArchive.LastStandardMember; + + while (NT_SUCCESS(PhGetNextMappedArchiveMember(&member, &member))) + { + if (NT_SUCCESS(PhGetMappedArchiveImportEntry(&member, &importEntry))) + { + INT lvItemIndex; + PPH_STRING name; + WCHAR number[PH_INT32_STR_LEN_1]; + PWSTR type; + + name = PhZeroExtendToUtf16(importEntry.DllName); + lvItemIndex = PhAddListViewItem(lvHandle, MAXINT, name->Buffer, NULL); + PhDereferenceObject(name); + + name = PhZeroExtendToUtf16(importEntry.Name); + PhSetListViewSubItem(lvHandle, lvItemIndex, 1, name->Buffer); + PhDereferenceObject(name); + + // Ordinal is unioned with NameHint, so this works both ways. + PhPrintUInt32(number, importEntry.Ordinal); + PhSetListViewSubItem(lvHandle, lvItemIndex, 2, number); + + switch (importEntry.Type) + { + case IMPORT_OBJECT_CODE: + type = L"Code"; + break; + case IMPORT_OBJECT_DATA: + type = L"Data"; + break; + case IMPORT_OBJECT_CONST: + type = L"Const"; + break; + default: + type = L"Unknown"; + break; + } + + PhSetListViewSubItem(lvHandle, lvItemIndex, 3, type); + + switch (importEntry.NameType) + { + case IMPORT_OBJECT_ORDINAL: + type = L"Ordinal"; + break; + case IMPORT_OBJECT_NAME: + type = L"Name"; + break; + case IMPORT_OBJECT_NAME_NO_PREFIX: + type = L"Name, no prefix"; + break; + case IMPORT_OBJECT_NAME_UNDECORATE: + type = L"Name, undecorate"; + break; + default: + type = L"Unknown"; + break; + } + + PhSetListViewSubItem(lvHandle, lvItemIndex, 4, type); + } + } + + ExtendedListView_SortItems(lvHandle); + + EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); + } + break; + case WM_NOTIFY: + { + PvHandleListViewNotifyForCopy(lParam, GetDlgItem(hwndDlg, IDC_LIST)); + } + break; + } + + return FALSE; +} diff --git a/tools/peview/main.c b/tools/peview/main.c index 811f604359e2..d3e580a7ec82 100644 --- a/tools/peview/main.c +++ b/tools/peview/main.c @@ -1,128 +1,128 @@ -/* - * Process Hacker - - * PE viewer - * - * Copyright (C) 2010 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include -#include - -PPH_STRING PvFileName = NULL; - -static BOOLEAN NTAPI PvCommandLineCallback( - _In_opt_ PPH_COMMAND_LINE_OPTION Option, - _In_opt_ PPH_STRING Value, - _In_opt_ PVOID Context - ) -{ - if (!Option) - PhSwapReference(&PvFileName, Value); - - return TRUE; -} - -static VOID PvpInitializeDpi( - VOID - ) -{ - HDC hdc; - - if (hdc = CreateIC(L"DISPLAY", NULL, NULL, NULL)) - { - PhGlobalDpi = GetDeviceCaps(hdc, LOGPIXELSY); - ReleaseDC(NULL, hdc); - } -} - -INT WINAPI wWinMain( - _In_ HINSTANCE hInstance, - _In_opt_ HINSTANCE hPrevInstance, - _In_ PWSTR lpCmdLine, - _In_ INT nCmdShow - ) -{ - static PH_COMMAND_LINE_OPTION options[] = - { - { 0, L"h", NoArgumentType } - }; - PH_STRINGREF commandLine; - - if (!NT_SUCCESS(PhInitializePhLibEx(0, 0, 0))) - return 1; - - PhGuiSupportInitialization(); - PvpInitializeDpi(); - PvPropInitialization(); - - PhApplicationName = L"PE Viewer"; - - PhUnicodeStringToStringRef(&NtCurrentPeb()->ProcessParameters->CommandLine, &commandLine); - - PhParseCommandLine( - &commandLine, - options, - sizeof(options) / sizeof(PH_COMMAND_LINE_OPTION), - PH_COMMAND_LINE_IGNORE_FIRST_PART, - PvCommandLineCallback, - NULL - ); - - if (!PvFileName) - { - static PH_FILETYPE_FILTER filters[] = - { - { L"Supported files (*.exe;*.dll;*.ocx;*.sys;*.scr;*.cpl;*.ax;*.acm;*.lib;*.winmd;*.efi)", L"*.exe;*.dll;*.ocx;*.sys;*.scr;*.cpl;*.ax;*.acm;*.lib;*.winmd;*.efi" }, - { L"All files (*.*)", L"*.*" } - }; - PVOID fileDialog; - - CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE); - - fileDialog = PhCreateOpenFileDialog(); - PhSetFileDialogFilter(fileDialog, filters, sizeof(filters) / sizeof(PH_FILETYPE_FILTER)); - - if (PhShowFileDialog(NULL, fileDialog)) - { - PvFileName = PhGetFileDialogFileName(fileDialog); - } - - PhFreeFileDialog(fileDialog); - } - - if (!PvFileName) - return 1; - - if (PhEndsWithString2(PvFileName, L".lnk", TRUE)) - { - PPH_STRING targetFileName; - - CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE); - targetFileName = PvResolveShortcutTarget(PvFileName); - - if (targetFileName) - PhMoveReference(&PvFileName, targetFileName); - } - - if (!PhEndsWithString2(PvFileName, L".lib", TRUE)) - PvPeProperties(); - else - PvLibProperties(); - - return 0; -} +/* + * Process Hacker - + * PE viewer + * + * Copyright (C) 2010 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include +#include + +PPH_STRING PvFileName = NULL; + +static BOOLEAN NTAPI PvCommandLineCallback( + _In_opt_ PPH_COMMAND_LINE_OPTION Option, + _In_opt_ PPH_STRING Value, + _In_opt_ PVOID Context + ) +{ + if (!Option) + PhSwapReference(&PvFileName, Value); + + return TRUE; +} + +static VOID PvpInitializeDpi( + VOID + ) +{ + HDC hdc; + + if (hdc = CreateIC(L"DISPLAY", NULL, NULL, NULL)) + { + PhGlobalDpi = GetDeviceCaps(hdc, LOGPIXELSY); + ReleaseDC(NULL, hdc); + } +} + +INT WINAPI wWinMain( + _In_ HINSTANCE hInstance, + _In_opt_ HINSTANCE hPrevInstance, + _In_ PWSTR lpCmdLine, + _In_ INT nCmdShow + ) +{ + static PH_COMMAND_LINE_OPTION options[] = + { + { 0, L"h", NoArgumentType } + }; + PH_STRINGREF commandLine; + + if (!NT_SUCCESS(PhInitializePhLibEx(0, 0, 0))) + return 1; + + PhGuiSupportInitialization(); + PvpInitializeDpi(); + PvPropInitialization(); + + PhApplicationName = L"PE Viewer"; + + PhUnicodeStringToStringRef(&NtCurrentPeb()->ProcessParameters->CommandLine, &commandLine); + + PhParseCommandLine( + &commandLine, + options, + sizeof(options) / sizeof(PH_COMMAND_LINE_OPTION), + PH_COMMAND_LINE_IGNORE_FIRST_PART, + PvCommandLineCallback, + NULL + ); + + if (!PvFileName) + { + static PH_FILETYPE_FILTER filters[] = + { + { L"Supported files (*.exe;*.dll;*.ocx;*.sys;*.scr;*.cpl;*.ax;*.acm;*.lib;*.winmd;*.efi)", L"*.exe;*.dll;*.ocx;*.sys;*.scr;*.cpl;*.ax;*.acm;*.lib;*.winmd;*.efi" }, + { L"All files (*.*)", L"*.*" } + }; + PVOID fileDialog; + + CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE); + + fileDialog = PhCreateOpenFileDialog(); + PhSetFileDialogFilter(fileDialog, filters, sizeof(filters) / sizeof(PH_FILETYPE_FILTER)); + + if (PhShowFileDialog(NULL, fileDialog)) + { + PvFileName = PhGetFileDialogFileName(fileDialog); + } + + PhFreeFileDialog(fileDialog); + } + + if (!PvFileName) + return 1; + + if (PhEndsWithString2(PvFileName, L".lnk", TRUE)) + { + PPH_STRING targetFileName; + + CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE); + targetFileName = PvResolveShortcutTarget(PvFileName); + + if (targetFileName) + PhMoveReference(&PvFileName, targetFileName); + } + + if (!PhEndsWithString2(PvFileName, L".lib", TRUE)) + PvPeProperties(); + else + PvLibProperties(); + + return 0; +} diff --git a/tools/peview/misc.c b/tools/peview/misc.c index c1e3acb2fbea..fc036c831520 100644 --- a/tools/peview/misc.c +++ b/tools/peview/misc.c @@ -1,102 +1,102 @@ -/* - * Process Hacker - - * PE viewer - * - * Copyright (C) 2011 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#define CINTERFACE -#define COBJMACROS -#include -#include -#undef CINTERFACE -#undef COBJMACROS -#include - -static GUID CLSID_ShellLink_I = { 0x00021401, 0x0000, 0x0000, { 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46 } }; -static GUID IID_IShellLinkW_I = { 0x000214f9, 0x0000, 0x0000, { 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46 } }; -static GUID IID_IPersistFile_I = { 0x0000010b, 0x0000, 0x0000, { 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46 } }; - -PPH_STRING PvResolveShortcutTarget( - _In_ PPH_STRING ShortcutFileName - ) -{ - PPH_STRING targetFileName; - IShellLinkW *shellLink; - IPersistFile *persistFile; - WCHAR path[MAX_PATH]; - - targetFileName = NULL; - - if (SUCCEEDED(CoCreateInstance(&CLSID_ShellLink_I, NULL, CLSCTX_INPROC_SERVER, &IID_IShellLinkW_I, &shellLink))) - { - if (SUCCEEDED(IShellLinkW_QueryInterface(shellLink, &IID_IPersistFile_I, &persistFile))) - { - if (SUCCEEDED(IPersistFile_Load(persistFile, ShortcutFileName->Buffer, STGM_READ)) && - SUCCEEDED(IShellLinkW_Resolve(shellLink, NULL, SLR_NO_UI))) - { - if (SUCCEEDED(IShellLinkW_GetPath(shellLink, path, MAX_PATH, NULL, 0))) - { - targetFileName = PhCreateString(path); - } - } - - IPersistFile_Release(persistFile); - } - - IShellLinkW_Release(shellLink); - } - - return targetFileName; -} - -// Copied from appsup.c - -VOID PvCopyListView( - _In_ HWND ListViewHandle - ) -{ - PPH_STRING text; - - text = PhGetListViewText(ListViewHandle); - PhSetClipboardString(ListViewHandle, &text->sr); - PhDereferenceObject(text); -} - -VOID PvHandleListViewNotifyForCopy( - _In_ LPARAM lParam, - _In_ HWND ListViewHandle - ) -{ - if (((LPNMHDR)lParam)->hwndFrom == ListViewHandle && ((LPNMHDR)lParam)->code == LVN_KEYDOWN) - { - LPNMLVKEYDOWN keyDown = (LPNMLVKEYDOWN)lParam; - - switch (keyDown->wVKey) - { - case 'C': - if (GetKeyState(VK_CONTROL) < 0) - PvCopyListView(ListViewHandle); - break; - case 'A': - if (GetKeyState(VK_CONTROL) < 0) - PhSetStateAllListViewItems(ListViewHandle, LVIS_SELECTED, LVIS_SELECTED); - break; - } - } -} +/* + * Process Hacker - + * PE viewer + * + * Copyright (C) 2011 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#define CINTERFACE +#define COBJMACROS +#include +#include +#undef CINTERFACE +#undef COBJMACROS +#include + +static GUID CLSID_ShellLink_I = { 0x00021401, 0x0000, 0x0000, { 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46 } }; +static GUID IID_IShellLinkW_I = { 0x000214f9, 0x0000, 0x0000, { 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46 } }; +static GUID IID_IPersistFile_I = { 0x0000010b, 0x0000, 0x0000, { 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46 } }; + +PPH_STRING PvResolveShortcutTarget( + _In_ PPH_STRING ShortcutFileName + ) +{ + PPH_STRING targetFileName; + IShellLinkW *shellLink; + IPersistFile *persistFile; + WCHAR path[MAX_PATH]; + + targetFileName = NULL; + + if (SUCCEEDED(CoCreateInstance(&CLSID_ShellLink_I, NULL, CLSCTX_INPROC_SERVER, &IID_IShellLinkW_I, &shellLink))) + { + if (SUCCEEDED(IShellLinkW_QueryInterface(shellLink, &IID_IPersistFile_I, &persistFile))) + { + if (SUCCEEDED(IPersistFile_Load(persistFile, ShortcutFileName->Buffer, STGM_READ)) && + SUCCEEDED(IShellLinkW_Resolve(shellLink, NULL, SLR_NO_UI))) + { + if (SUCCEEDED(IShellLinkW_GetPath(shellLink, path, MAX_PATH, NULL, 0))) + { + targetFileName = PhCreateString(path); + } + } + + IPersistFile_Release(persistFile); + } + + IShellLinkW_Release(shellLink); + } + + return targetFileName; +} + +// Copied from appsup.c + +VOID PvCopyListView( + _In_ HWND ListViewHandle + ) +{ + PPH_STRING text; + + text = PhGetListViewText(ListViewHandle); + PhSetClipboardString(ListViewHandle, &text->sr); + PhDereferenceObject(text); +} + +VOID PvHandleListViewNotifyForCopy( + _In_ LPARAM lParam, + _In_ HWND ListViewHandle + ) +{ + if (((LPNMHDR)lParam)->hwndFrom == ListViewHandle && ((LPNMHDR)lParam)->code == LVN_KEYDOWN) + { + LPNMLVKEYDOWN keyDown = (LPNMLVKEYDOWN)lParam; + + switch (keyDown->wVKey) + { + case 'C': + if (GetKeyState(VK_CONTROL) < 0) + PvCopyListView(ListViewHandle); + break; + case 'A': + if (GetKeyState(VK_CONTROL) < 0) + PhSetStateAllListViewItems(ListViewHandle, LVIS_SELECTED, LVIS_SELECTED); + break; + } + } +} diff --git a/tools/peview/peprp.c b/tools/peview/peprp.c index 22512aeac285..1908df441a52 100644 --- a/tools/peview/peprp.c +++ b/tools/peview/peprp.c @@ -1,1408 +1,1408 @@ -/* - * Process Hacker - - * PE viewer - * - * Copyright (C) 2010-2011 wj32 - * Copyright (C) 2017 dmex - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define PVM_CHECKSUM_DONE (WM_APP + 1) -#define PVM_VERIFY_DONE (WM_APP + 2) - -INT_PTR CALLBACK PvpPeGeneralDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -INT_PTR CALLBACK PvpPeImportsDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -INT_PTR CALLBACK PvpPeExportsDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -INT_PTR CALLBACK PvpPeLoadConfigDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -INT_PTR CALLBACK PvpPeClrDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -INT_PTR CALLBACK PvpPeCgfDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -PH_MAPPED_IMAGE PvMappedImage; -PIMAGE_COR20_HEADER PvImageCor20Header; - -HICON PvImageLargeIcon; -PH_IMAGE_VERSION_INFO PvImageVersionInfo; -VERIFY_RESULT PvImageVerifyResult; -PPH_STRING PvImageSignerName; - -VOID PvPeProperties( - VOID - ) -{ - NTSTATUS status; - PPV_PROPCONTEXT propContext; - PH_MAPPED_IMAGE_IMPORTS imports; - PH_MAPPED_IMAGE_EXPORTS exports; - PIMAGE_DATA_DIRECTORY entry; - - if (!NT_SUCCESS(status = PhLoadMappedImage( - PvFileName->Buffer, - NULL, - TRUE, - &PvMappedImage - ))) - { - PhShowStatus(NULL, L"Unable to load the PE file", status, 0); - return; - } - - if (propContext = PvCreatePropContext(PvFileName)) - { - PPV_PROPPAGECONTEXT newPage; - - // General page - newPage = PvCreatePropPageContext( - MAKEINTRESOURCE(IDD_PEGENERAL), - PvpPeGeneralDlgProc, - NULL - ); - PvAddPropPage(propContext, newPage); - - // Imports page - if ((NT_SUCCESS(PhGetMappedImageImports(&imports, &PvMappedImage)) && imports.NumberOfDlls != 0) || - (NT_SUCCESS(PhGetMappedImageDelayImports(&imports, &PvMappedImage)) && imports.NumberOfDlls != 0)) - { - newPage = PvCreatePropPageContext( - MAKEINTRESOURCE(IDD_PEIMPORTS), - PvpPeImportsDlgProc, - NULL - ); - PvAddPropPage(propContext, newPage); - } - - // Exports page - if (NT_SUCCESS(PhGetMappedImageExports(&exports, &PvMappedImage)) && exports.NumberOfEntries != 0) - { - newPage = PvCreatePropPageContext( - MAKEINTRESOURCE(IDD_PEEXPORTS), - PvpPeExportsDlgProc, - NULL - ); - PvAddPropPage(propContext, newPage); - } - - // Load Config page - if (NT_SUCCESS(PhGetMappedImageDataEntry(&PvMappedImage, IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG, &entry)) && entry->VirtualAddress) - { - newPage = PvCreatePropPageContext( - MAKEINTRESOURCE(IDD_PELOADCONFIG), - PvpPeLoadConfigDlgProc, - NULL - ); - PvAddPropPage(propContext, newPage); - } - - // CLR page - if (NT_SUCCESS(PhGetMappedImageDataEntry(&PvMappedImage, IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR, &entry)) && - entry->VirtualAddress && - (PvImageCor20Header = PhMappedImageRvaToVa(&PvMappedImage, entry->VirtualAddress, NULL))) - { - status = STATUS_SUCCESS; - - __try - { - PhProbeAddress( - PvImageCor20Header, - sizeof(IMAGE_COR20_HEADER), - PvMappedImage.ViewBase, - PvMappedImage.Size, - 4 - ); - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - status = GetExceptionCode(); - } - - if (NT_SUCCESS(status)) - { - newPage = PvCreatePropPageContext( - MAKEINTRESOURCE(IDD_PECLR), - PvpPeClrDlgProc, - NULL - ); - PvAddPropPage(propContext, newPage); - } - } - - // CFG page - if ((PvMappedImage.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) && - (PvMappedImage.NtHeaders->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_GUARD_CF)) - { - newPage = PvCreatePropPageContext( - MAKEINTRESOURCE(IDD_PECFG), - PvpPeCgfDlgProc, - NULL - ); - PvAddPropPage(propContext, newPage); - } - - PhModalPropertySheet(&propContext->PropSheetHeader); - - PhDereferenceObject(propContext); - } - - PhUnloadMappedImage(&PvMappedImage); -} - -static NTSTATUS CheckSumImageThreadStart( - _In_ PVOID Parameter - ) -{ - HWND windowHandle; - ULONG checkSum; - - windowHandle = Parameter; - checkSum = PhCheckSumMappedImage(&PvMappedImage); - - PostMessage( - windowHandle, - PVM_CHECKSUM_DONE, - checkSum, - 0 - ); - - return STATUS_SUCCESS; -} - -VERIFY_RESULT PvpVerifyFileWithAdditionalCatalog( - _In_ PPH_STRING FileName, - _In_ ULONG Flags, - _In_opt_ HWND hWnd, - _Out_opt_ PPH_STRING *SignerName - ) -{ - static PH_STRINGREF codeIntegrityFileName = PH_STRINGREF_INIT(L"\\AppxMetadata\\CodeIntegrity.cat"); - - VERIFY_RESULT result; - PH_VERIFY_FILE_INFO info; - PPH_STRING windowsAppsPath; - PPH_STRING additionalCatalogFileName = NULL; - PCERT_CONTEXT *signatures; - ULONG numberOfSignatures; - - memset(&info, 0, sizeof(PH_VERIFY_FILE_INFO)); - info.FileName = FileName->Buffer; - info.Flags = Flags; - info.hWnd = hWnd; - - windowsAppsPath = PhGetKnownLocation(CSIDL_PROGRAM_FILES, L"\\WindowsApps\\"); - - if (windowsAppsPath) - { - if (PhStartsWithStringRef(&FileName->sr, &windowsAppsPath->sr, TRUE)) - { - PH_STRINGREF remainingFileName; - ULONG_PTR indexOfBackslash; - PH_STRINGREF baseFileName; - - remainingFileName = FileName->sr; - PhSkipStringRef(&remainingFileName, windowsAppsPath->Length); - indexOfBackslash = PhFindCharInStringRef(&remainingFileName, '\\', FALSE); - - if (indexOfBackslash != -1) - { - baseFileName.Buffer = FileName->Buffer; - baseFileName.Length = windowsAppsPath->Length + indexOfBackslash * sizeof(WCHAR); - additionalCatalogFileName = PhConcatStringRef2(&baseFileName, &codeIntegrityFileName); - } - } - - PhDereferenceObject(windowsAppsPath); - } - - if (additionalCatalogFileName) - { - info.NumberOfCatalogFileNames = 1; - info.CatalogFileNames = &additionalCatalogFileName->Buffer; - } - - if (!NT_SUCCESS(PhVerifyFileEx(&info, &result, &signatures, &numberOfSignatures))) - { - result = VrNoSignature; - signatures = NULL; - numberOfSignatures = 0; - } - - if (additionalCatalogFileName) - PhDereferenceObject(additionalCatalogFileName); - - if (SignerName) - { - if (numberOfSignatures != 0) - *SignerName = PhGetSignerNameFromCertificate(signatures[0]); - else - *SignerName = NULL; - } - - PhFreeVerifySignatures(signatures, numberOfSignatures); - - return result; -} - -static NTSTATUS VerifyImageThreadStart( - _In_ PVOID Parameter - ) -{ - HWND windowHandle; - - windowHandle = Parameter; - PvImageVerifyResult = PvpVerifyFileWithAdditionalCatalog(PvFileName, PH_VERIFY_PREVENT_NETWORK_ACCESS, NULL, &PvImageSignerName); - PostMessage(windowHandle, PVM_VERIFY_DONE, 0, 0); - - return STATUS_SUCCESS; -} - -FORCEINLINE PWSTR PvpGetStringOrNa( - _In_ PPH_STRING String - ) -{ - if (String) - return String->Buffer; - else - return L"N/A"; -} - -INT_PTR CALLBACK PvpPeGeneralDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - LPPROPSHEETPAGE propSheetPage; - PPV_PROPPAGECONTEXT propPageContext; - - if (!PvPropPageDlgProcHeader(hwndDlg, uMsg, lParam, &propSheetPage, &propPageContext)) - return FALSE; - - switch (uMsg) - { - case WM_INITDIALOG: - { - HWND lvHandle; - ULONG i; - PPH_STRING string; - PWSTR type; - PH_STRING_BUILDER stringBuilder; - - PhCenterWindow(GetParent(hwndDlg), NULL); - - // File version information - - { - PhInitializeImageVersionInfo(&PvImageVersionInfo, PvFileName->Buffer); - - if (ExtractIconEx( - PvFileName->Buffer, - 0, - &PvImageLargeIcon, - NULL, - 1 - ) == 0) - { - PvImageLargeIcon = PhGetFileShellIcon(PvFileName->Buffer, NULL, TRUE); - } - - SendMessage(GetDlgItem(hwndDlg, IDC_FILEICON), STM_SETICON, (WPARAM)PvImageLargeIcon, 0); - - SetDlgItemText(hwndDlg, IDC_NAME, PvpGetStringOrNa(PvImageVersionInfo.FileDescription)); - string = PhConcatStrings2(L"(Verifying...) ", PvpGetStringOrNa(PvImageVersionInfo.CompanyName)); - SetDlgItemText(hwndDlg, IDC_COMPANYNAME, string->Buffer); - PhDereferenceObject(string); - SetDlgItemText(hwndDlg, IDC_VERSION, PvpGetStringOrNa(PvImageVersionInfo.FileVersion)); - - PhQueueItemWorkQueue(PhGetGlobalWorkQueue(), VerifyImageThreadStart, hwndDlg); - } - - // PE properties - - switch (PvMappedImage.NtHeaders->FileHeader.Machine) - { - case IMAGE_FILE_MACHINE_I386: - type = L"i386"; - break; - case IMAGE_FILE_MACHINE_AMD64: - type = L"AMD64"; - break; - case IMAGE_FILE_MACHINE_IA64: - type = L"IA64"; - break; - case IMAGE_FILE_MACHINE_ARMNT: - type = L"ARM Thumb-2"; - break; - default: - type = L"Unknown"; - break; - } - - SetDlgItemText(hwndDlg, IDC_TARGETMACHINE, type); - - { - LARGE_INTEGER time; - SYSTEMTIME systemTime; - - RtlSecondsSince1970ToTime(PvMappedImage.NtHeaders->FileHeader.TimeDateStamp, &time); - PhLargeIntegerToLocalSystemTime(&systemTime, &time); - - string = PhFormatDateTime(&systemTime); - SetDlgItemText(hwndDlg, IDC_TIMESTAMP, string->Buffer); - PhDereferenceObject(string); - } - - if (PvMappedImage.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) - { - string = PhFormatString(L"0x%I32x", ((PIMAGE_OPTIONAL_HEADER32)&PvMappedImage.NtHeaders->OptionalHeader)->ImageBase); - } - else - { - string = PhFormatString(L"0x%I64x", ((PIMAGE_OPTIONAL_HEADER64)&PvMappedImage.NtHeaders->OptionalHeader)->ImageBase); - } - - SetDlgItemText(hwndDlg, IDC_IMAGEBASE, string->Buffer); - PhDereferenceObject(string); - - if (PvMappedImage.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) - { - string = PhFormatString(L"0x%I32x", ((PIMAGE_OPTIONAL_HEADER32)&PvMappedImage.NtHeaders->OptionalHeader)->AddressOfEntryPoint); - } - else - { - string = PhFormatString(L"0x%I64x", ((PIMAGE_OPTIONAL_HEADER64)&PvMappedImage.NtHeaders->OptionalHeader)->AddressOfEntryPoint); - } - - SetDlgItemText(hwndDlg, IDC_ENTRYPOINT, string->Buffer); - PhDereferenceObject(string); - - string = PhFormatString(L"0x%Ix (verifying...)", PvMappedImage.NtHeaders->OptionalHeader.CheckSum); // same for 32-bit and 64-bit images - SetDlgItemText(hwndDlg, IDC_CHECKSUM, string->Buffer); - PhDereferenceObject(string); - - PhQueueItemWorkQueue(PhGetGlobalWorkQueue(), CheckSumImageThreadStart, hwndDlg); - - switch (PvMappedImage.NtHeaders->OptionalHeader.Subsystem) - { - case IMAGE_SUBSYSTEM_NATIVE: - type = L"Native"; - break; - case IMAGE_SUBSYSTEM_WINDOWS_GUI: - type = L"Windows GUI"; - break; - case IMAGE_SUBSYSTEM_WINDOWS_CUI: - type = L"Windows CUI"; - break; - case IMAGE_SUBSYSTEM_OS2_CUI: - type = L"OS/2 CUI"; - break; - case IMAGE_SUBSYSTEM_POSIX_CUI: - type = L"POSIX CUI"; - break; - case IMAGE_SUBSYSTEM_WINDOWS_CE_GUI: - type = L"Windows CE CUI"; - break; - case IMAGE_SUBSYSTEM_EFI_APPLICATION: - type = L"EFI Application"; - break; - case IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER: - type = L"EFI Boot Service Driver"; - break; - case IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER: - type = L"EFI Runtime Driver"; - break; - case IMAGE_SUBSYSTEM_EFI_ROM: - type = L"EFI ROM"; - break; - case IMAGE_SUBSYSTEM_XBOX: - type = L"Xbox"; - break; - case IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION: - type = L"Windows Boot Application"; - break; - default: - type = L"Unknown"; - break; - } - - SetDlgItemText(hwndDlg, IDC_SUBSYSTEM, type); - SetDlgItemText(hwndDlg, IDC_SUBSYSTEMVERSION, PhaFormatString( - L"%u.%u", - PvMappedImage.NtHeaders->OptionalHeader.MajorSubsystemVersion, // same for 32-bit and 64-bit images - PvMappedImage.NtHeaders->OptionalHeader.MinorSubsystemVersion - )->Buffer); - - PhInitializeStringBuilder(&stringBuilder, 10); - - if (PvMappedImage.NtHeaders->FileHeader.Characteristics & IMAGE_FILE_EXECUTABLE_IMAGE) - PhAppendStringBuilder2(&stringBuilder, L"Executable, "); - if (PvMappedImage.NtHeaders->FileHeader.Characteristics & IMAGE_FILE_DLL) - PhAppendStringBuilder2(&stringBuilder, L"DLL, "); - if (PvMappedImage.NtHeaders->FileHeader.Characteristics & IMAGE_FILE_LARGE_ADDRESS_AWARE) - PhAppendStringBuilder2(&stringBuilder, L"Large address aware, "); - if (PvMappedImage.NtHeaders->FileHeader.Characteristics & IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP) - PhAppendStringBuilder2(&stringBuilder, L"Removable run from swap, "); - if (PvMappedImage.NtHeaders->FileHeader.Characteristics & IMAGE_FILE_NET_RUN_FROM_SWAP) - PhAppendStringBuilder2(&stringBuilder, L"Net run from swap, "); - if (PvMappedImage.NtHeaders->FileHeader.Characteristics & IMAGE_FILE_SYSTEM) - PhAppendStringBuilder2(&stringBuilder, L"System, "); - if (PvMappedImage.NtHeaders->FileHeader.Characteristics & IMAGE_FILE_UP_SYSTEM_ONLY) - PhAppendStringBuilder2(&stringBuilder, L"Uni-processor only, "); - - if (PvMappedImage.NtHeaders->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA) - PhAppendStringBuilder2(&stringBuilder, L"High entropy VA, "); - if (PvMappedImage.NtHeaders->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE) - PhAppendStringBuilder2(&stringBuilder, L"Dynamic base, "); - if (PvMappedImage.NtHeaders->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY) - PhAppendStringBuilder2(&stringBuilder, L"Force integrity check, "); - if (PvMappedImage.NtHeaders->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_NX_COMPAT) - PhAppendStringBuilder2(&stringBuilder, L"NX compatible, "); - if (PvMappedImage.NtHeaders->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_NO_ISOLATION) - PhAppendStringBuilder2(&stringBuilder, L"No isolation, "); - if (PvMappedImage.NtHeaders->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_NO_SEH) - PhAppendStringBuilder2(&stringBuilder, L"No SEH, "); - if (PvMappedImage.NtHeaders->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_NO_BIND) - PhAppendStringBuilder2(&stringBuilder, L"Do not bind, "); - if (PvMappedImage.NtHeaders->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_APPCONTAINER) - PhAppendStringBuilder2(&stringBuilder, L"AppContainer, "); - if (PvMappedImage.NtHeaders->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_WDM_DRIVER) - PhAppendStringBuilder2(&stringBuilder, L"WDM driver, "); - if (PvMappedImage.NtHeaders->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_GUARD_CF) - PhAppendStringBuilder2(&stringBuilder, L"Control Flow Guard, "); - if (PvMappedImage.NtHeaders->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE) - PhAppendStringBuilder2(&stringBuilder, L"Terminal server aware, "); - - if (PhEndsWithString2(stringBuilder.String, L", ", FALSE)) - PhRemoveEndStringBuilder(&stringBuilder, 2); - - SetDlgItemText(hwndDlg, IDC_CHARACTERISTICS, stringBuilder.String->Buffer); - PhDeleteStringBuilder(&stringBuilder); - - lvHandle = GetDlgItem(hwndDlg, IDC_LIST); - PhSetListViewStyle(lvHandle, FALSE, TRUE); - PhSetControlTheme(lvHandle, L"explorer"); - PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 80, L"Name"); - PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 80, L"VA"); - PhAddListViewColumn(lvHandle, 2, 2, 2, LVCFMT_LEFT, 80, L"Size"); - - for (i = 0; i < PvMappedImage.NumberOfSections; i++) - { - INT lvItemIndex; - WCHAR sectionName[9]; - WCHAR pointer[PH_PTR_STR_LEN_1]; - - if (PhCopyStringZFromBytes(PvMappedImage.Sections[i].Name, - IMAGE_SIZEOF_SHORT_NAME, sectionName, 9, NULL)) - { - lvItemIndex = PhAddListViewItem(lvHandle, MAXINT, sectionName, NULL); - - PhPrintPointer(pointer, UlongToPtr(PvMappedImage.Sections[i].VirtualAddress)); - PhSetListViewSubItem(lvHandle, lvItemIndex, 1, pointer); - - PhPrintPointer(pointer, UlongToPtr(PvMappedImage.Sections[i].SizeOfRawData)); - PhSetListViewSubItem(lvHandle, lvItemIndex, 2, pointer); - } - } - } - break; - case WM_SHOWWINDOW: - { - if (!propPageContext->LayoutInitialized) - { - PPH_LAYOUT_ITEM dialogItem; - - dialogItem = PvAddPropPageLayoutItem(hwndDlg, hwndDlg, - PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL); - PvAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_FILE), - dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); - PvAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_NAME), - dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); - PvAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_CHARACTERISTICS), - dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); - PvAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_LIST), - dialogItem, PH_ANCHOR_ALL); - - PvDoPropPageLayout(hwndDlg); - - propPageContext->LayoutInitialized = TRUE; - } - } - break; - case PVM_CHECKSUM_DONE: - { - PPH_STRING string; - ULONG headerCheckSum; - ULONG realCheckSum; - - headerCheckSum = PvMappedImage.NtHeaders->OptionalHeader.CheckSum; // same for 32-bit and 64-bit images - realCheckSum = (ULONG)wParam; - - if (headerCheckSum == 0) - { - // Some executables, like .NET ones, don't have a check sum. - string = PhFormatString(L"0x0 (real 0x%Ix)", realCheckSum); - SetDlgItemText(hwndDlg, IDC_CHECKSUM, string->Buffer); - PhDereferenceObject(string); - } - else if (headerCheckSum == realCheckSum) - { - string = PhFormatString(L"0x%Ix (correct)", headerCheckSum); - SetDlgItemText(hwndDlg, IDC_CHECKSUM, string->Buffer); - PhDereferenceObject(string); - } - else - { - string = PhFormatString(L"0x%Ix (incorrect, real 0x%Ix)", headerCheckSum, realCheckSum); - SetDlgItemText(hwndDlg, IDC_CHECKSUM, string->Buffer); - PhDereferenceObject(string); - } - } - break; - case PVM_VERIFY_DONE: - { - PPH_STRING string; - - if (PvImageVerifyResult == VrTrusted) - { - if (PvImageSignerName) - { - string = PhFormatString(L"(Verified) %s", PvImageSignerName->Buffer); - SetDlgItemText(hwndDlg, IDC_COMPANYNAME_LINK, string->Buffer); - PhDereferenceObject(string); - ShowWindow(GetDlgItem(hwndDlg, IDC_COMPANYNAME), SW_HIDE); - ShowWindow(GetDlgItem(hwndDlg, IDC_COMPANYNAME_LINK), SW_SHOW); - } - else - { - string = PhConcatStrings2(L"(Verified) ", PhGetStringOrEmpty(PvImageVersionInfo.CompanyName)); - SetDlgItemText(hwndDlg, IDC_COMPANYNAME, string->Buffer); - PhDereferenceObject(string); - } - } - else if (PvImageVerifyResult != VrUnknown) - { - string = PhConcatStrings2(L"(UNVERIFIED) ", PhGetStringOrEmpty(PvImageVersionInfo.CompanyName)); - SetDlgItemText(hwndDlg, IDC_COMPANYNAME, string->Buffer); - PhDereferenceObject(string); - } - else - { - SetDlgItemText(hwndDlg, IDC_COMPANYNAME, PvpGetStringOrNa(PvImageVersionInfo.CompanyName)); - } - } - break; - case WM_NOTIFY: - { - LPNMHDR header = (LPNMHDR)lParam; - - switch (header->code) - { - case NM_CLICK: - { - switch (header->idFrom) - { - case IDC_COMPANYNAME_LINK: - { - PvpVerifyFileWithAdditionalCatalog(PvFileName, PH_VERIFY_VIEW_PROPERTIES, hwndDlg, NULL); - } - break; - } - } - break; - } - - PvHandleListViewNotifyForCopy(lParam, GetDlgItem(hwndDlg, IDC_LIST)); - } - break; - } - - return FALSE; -} - -VOID PvpProcessImports( - _In_ HWND ListViewHandle, - _In_ PPH_MAPPED_IMAGE_IMPORTS Imports, - _In_ BOOLEAN DelayImports - ) -{ - PH_MAPPED_IMAGE_IMPORT_DLL importDll; - PH_MAPPED_IMAGE_IMPORT_ENTRY importEntry; - ULONG i; - ULONG j; - - for (i = 0; i < Imports->NumberOfDlls; i++) - { - if (NT_SUCCESS(PhGetMappedImageImportDll(Imports, i, &importDll))) - { - for (j = 0; j < importDll.NumberOfEntries; j++) - { - if (NT_SUCCESS(PhGetMappedImageImportEntry(&importDll, j, &importEntry))) - { - INT lvItemIndex; - PPH_STRING name; - WCHAR number[PH_INT32_STR_LEN_1]; - - if (!DelayImports) - name = PhZeroExtendToUtf16(importDll.Name); - else - name = PhFormatString(L"%S (Delay)", importDll.Name); - - lvItemIndex = PhAddListViewItem(ListViewHandle, MAXINT, name->Buffer, NULL); - PhDereferenceObject(name); - - if (importEntry.Name) - { - name = PhZeroExtendToUtf16(importEntry.Name); - PhSetListViewSubItem(ListViewHandle, lvItemIndex, 1, name->Buffer); - PhDereferenceObject(name); - - PhPrintUInt32(number, importEntry.NameHint); - PhSetListViewSubItem(ListViewHandle, lvItemIndex, 2, number); - } - else - { - name = PhFormatString(L"(Ordinal %u)", importEntry.Ordinal); - PhSetListViewSubItem(ListViewHandle, lvItemIndex, 1, name->Buffer); - PhDereferenceObject(name); - } - } - } - } - } -} - -INT_PTR CALLBACK PvpPeImportsDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - LPPROPSHEETPAGE propSheetPage; - PPV_PROPPAGECONTEXT propPageContext; - - if (!PvPropPageDlgProcHeader(hwndDlg, uMsg, lParam, &propSheetPage, &propPageContext)) - return FALSE; - - switch (uMsg) - { - case WM_INITDIALOG: - { - ULONG fallbackColumns[] = { 0, 1, 2 }; - HWND lvHandle; - PH_MAPPED_IMAGE_IMPORTS imports; - - lvHandle = GetDlgItem(hwndDlg, IDC_LIST); - PhSetListViewStyle(lvHandle, FALSE, TRUE); - PhSetControlTheme(lvHandle, L"explorer"); - PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 130, L"DLL"); - PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 210, L"Name"); - PhAddListViewColumn(lvHandle, 2, 2, 2, LVCFMT_LEFT, 50, L"Hint"); - PhSetExtendedListView(lvHandle); - ExtendedListView_AddFallbackColumns(lvHandle, 3, fallbackColumns); - - if (NT_SUCCESS(PhGetMappedImageImports(&imports, &PvMappedImage))) - { - PvpProcessImports(lvHandle, &imports, FALSE); - } - - if (NT_SUCCESS(PhGetMappedImageDelayImports(&imports, &PvMappedImage))) - { - PvpProcessImports(lvHandle, &imports, TRUE); - } - - ExtendedListView_SortItems(lvHandle); - - EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); - } - break; - case WM_SHOWWINDOW: - { - if (!propPageContext->LayoutInitialized) - { - PPH_LAYOUT_ITEM dialogItem; - - dialogItem = PvAddPropPageLayoutItem(hwndDlg, hwndDlg, - PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL); - PvAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_LIST), - dialogItem, PH_ANCHOR_ALL); - - PvDoPropPageLayout(hwndDlg); - - propPageContext->LayoutInitialized = TRUE; - } - } - break; - case WM_NOTIFY: - { - PvHandleListViewNotifyForCopy(lParam, GetDlgItem(hwndDlg, IDC_LIST)); - } - break; - } - - return FALSE; -} - -INT_PTR CALLBACK PvpPeExportsDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - LPPROPSHEETPAGE propSheetPage; - PPV_PROPPAGECONTEXT propPageContext; - - if (!PvPropPageDlgProcHeader(hwndDlg, uMsg, lParam, &propSheetPage, &propPageContext)) - return FALSE; - - switch (uMsg) - { - case WM_INITDIALOG: - { - HWND lvHandle; - PH_MAPPED_IMAGE_EXPORTS exports; - PH_MAPPED_IMAGE_EXPORT_ENTRY exportEntry; - PH_MAPPED_IMAGE_EXPORT_FUNCTION exportFunction; - ULONG i; - - lvHandle = GetDlgItem(hwndDlg, IDC_LIST); - PhSetListViewStyle(lvHandle, FALSE, TRUE); - PhSetControlTheme(lvHandle, L"explorer"); - PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 220, L"Name"); - PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 50, L"Ordinal"); - PhAddListViewColumn(lvHandle, 2, 2, 2, LVCFMT_LEFT, 120, L"VA"); - PhSetExtendedListView(lvHandle); - - if (NT_SUCCESS(PhGetMappedImageExports(&exports, &PvMappedImage))) - { - for (i = 0; i < exports.NumberOfEntries; i++) - { - if ( - NT_SUCCESS(PhGetMappedImageExportEntry(&exports, i, &exportEntry)) && - NT_SUCCESS(PhGetMappedImageExportFunction(&exports, NULL, exportEntry.Ordinal, &exportFunction)) - ) - { - INT lvItemIndex; - PPH_STRING name; - WCHAR number[PH_INT32_STR_LEN_1]; - WCHAR pointer[PH_PTR_STR_LEN_1]; - - if (exportEntry.Name) - { - name = PhZeroExtendToUtf16(exportEntry.Name); - lvItemIndex = PhAddListViewItem(lvHandle, MAXINT, name->Buffer, NULL); - PhDereferenceObject(name); - } - else - { - lvItemIndex = PhAddListViewItem(lvHandle, MAXINT, L"(unnamed)", NULL); - } - - PhPrintUInt32(number, exportEntry.Ordinal); - PhSetListViewSubItem(lvHandle, lvItemIndex, 1, number); - - if (!exportFunction.ForwardedName) - { - if ((ULONG_PTR)exportFunction.Function >= (ULONG_PTR)PvMappedImage.ViewBase) - PhPrintPointer(pointer, PTR_SUB_OFFSET(exportFunction.Function, PvMappedImage.ViewBase)); - else - PhPrintPointer(pointer, exportFunction.Function); - - PhSetListViewSubItem(lvHandle, lvItemIndex, 2, pointer); - } - else - { - name = PhZeroExtendToUtf16(exportFunction.ForwardedName); - PhSetListViewSubItem(lvHandle, lvItemIndex, 2, name->Buffer); - PhDereferenceObject(name); - } - } - } - } - - ExtendedListView_SortItems(lvHandle); - - EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); - } - break; - case WM_SHOWWINDOW: - { - if (!propPageContext->LayoutInitialized) - { - PPH_LAYOUT_ITEM dialogItem; - - dialogItem = PvAddPropPageLayoutItem(hwndDlg, hwndDlg, - PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL); - PvAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_LIST), - dialogItem, PH_ANCHOR_ALL); - - PvDoPropPageLayout(hwndDlg); - - propPageContext->LayoutInitialized = TRUE; - } - } - break; - case WM_NOTIFY: - { - PvHandleListViewNotifyForCopy(lParam, GetDlgItem(hwndDlg, IDC_LIST)); - } - break; - } - - return FALSE; -} - -INT_PTR CALLBACK PvpPeLoadConfigDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - LPPROPSHEETPAGE propSheetPage; - PPV_PROPPAGECONTEXT propPageContext; - - if (!PvPropPageDlgProcHeader(hwndDlg, uMsg, lParam, &propSheetPage, &propPageContext)) - return FALSE; - - switch (uMsg) - { - case WM_INITDIALOG: - { - HWND lvHandle; - PIMAGE_LOAD_CONFIG_DIRECTORY32 config32; - PIMAGE_LOAD_CONFIG_DIRECTORY64 config64; - - lvHandle = GetDlgItem(hwndDlg, IDC_LIST); - PhSetListViewStyle(lvHandle, FALSE, TRUE); - PhSetControlTheme(lvHandle, L"explorer"); - PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 220, L"Name"); - PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 170, L"Value"); - - #define ADD_VALUE(Name, Value) \ - { \ - INT lvItemIndex; \ - lvItemIndex = PhAddListViewItem(lvHandle, MAXINT, Name, NULL); \ - PhSetListViewSubItem(lvHandle, lvItemIndex, 1, Value); \ - } - - #define ADD_VALUES(Type, Config) \ - { \ - LARGE_INTEGER time; \ - SYSTEMTIME systemTime; \ - \ - RtlSecondsSince1970ToTime((Config)->TimeDateStamp, &time); \ - PhLargeIntegerToLocalSystemTime(&systemTime, &time); \ - \ - ADD_VALUE(L"Time stamp", PhaFormatDateTime(&systemTime)->Buffer); \ - ADD_VALUE(L"Version", PhaFormatString(L"%u.%u", (Config)->MajorVersion, (Config)->MinorVersion)->Buffer); \ - ADD_VALUE(L"Global flags to clear", PhaFormatString(L"0x%x", (Config)->GlobalFlagsClear)->Buffer); \ - ADD_VALUE(L"Global flags to set", PhaFormatString(L"0x%x", (Config)->GlobalFlagsSet)->Buffer); \ - ADD_VALUE(L"Critical section default timeout", PhaFormatUInt64((Config)->CriticalSectionDefaultTimeout, TRUE)->Buffer); \ - ADD_VALUE(L"De-commit free block threshold", PhaFormatUInt64((Config)->DeCommitFreeBlockThreshold, TRUE)->Buffer); \ - ADD_VALUE(L"De-commit total free threshold", PhaFormatUInt64((Config)->DeCommitTotalFreeThreshold, TRUE)->Buffer); \ - ADD_VALUE(L"LOCK prefix table", PhaFormatString(L"0x%Ix", (Config)->LockPrefixTable)->Buffer); \ - ADD_VALUE(L"Maximum allocation size", PhaFormatString(L"0x%Ix", (Config)->MaximumAllocationSize)->Buffer); \ - ADD_VALUE(L"Virtual memory threshold", PhaFormatString(L"0x%Ix", (Config)->VirtualMemoryThreshold)->Buffer); \ - ADD_VALUE(L"Process affinity mask", PhaFormatString(L"0x%Ix", (Config)->ProcessAffinityMask)->Buffer); \ - ADD_VALUE(L"Process heap flags", PhaFormatString(L"0x%Ix", (Config)->ProcessHeapFlags)->Buffer); \ - ADD_VALUE(L"CSD version", PhaFormatString(L"%u", (Config)->CSDVersion)->Buffer); \ - ADD_VALUE(L"Edit list", PhaFormatString(L"0x%Ix", (Config)->EditList)->Buffer); \ - ADD_VALUE(L"Security cookie", PhaFormatString(L"0x%Ix", (Config)->SecurityCookie)->Buffer); \ - ADD_VALUE(L"SEH handler table", PhaFormatString(L"0x%Ix", (Config)->SEHandlerTable)->Buffer); \ - ADD_VALUE(L"SEH handler count", PhaFormatUInt64((Config)->SEHandlerCount, TRUE)->Buffer); \ - \ - if ((Config)->Size >= (ULONG)FIELD_OFFSET(Type, GuardAddressTakenIatEntryTable)) \ - { \ - ADD_VALUE(L"CFG GuardFlags", PhaFormatString(L"0x%Ix", (Config)->GuardFlags)->Buffer); \ - ADD_VALUE(L"CFG Check Function pointer", PhaFormatString(L"0x%Ix", (Config)->GuardCFCheckFunctionPointer)->Buffer); \ - ADD_VALUE(L"CFG Check Dispatch pointer", PhaFormatString(L"0x%Ix", (Config)->GuardCFDispatchFunctionPointer)->Buffer); \ - ADD_VALUE(L"CFG Function table", PhaFormatString(L"0x%Ix", (Config)->GuardCFFunctionTable)->Buffer); \ - ADD_VALUE(L"CFG Function table entry count", PhaFormatUInt64((Config)->GuardCFFunctionCount, TRUE)->Buffer); \ - if ((Config)->Size >= (ULONG)FIELD_OFFSET(Type, GuardAddressTakenIatEntryTable) \ - + sizeof((Config)->GuardAddressTakenIatEntryTable) \ - + sizeof((Config)->GuardAddressTakenIatEntryCount)) \ - { \ - ADD_VALUE(L"CFG IatEntry table", PhaFormatString(L"0x%Ix", (Config)->GuardAddressTakenIatEntryTable)->Buffer); \ - ADD_VALUE(L"CFG IatEntry table entry count", PhaFormatUInt64((Config)->GuardAddressTakenIatEntryCount, TRUE)->Buffer); \ - } \ - if ((Config)->Size >= (ULONG)FIELD_OFFSET(Type, GuardLongJumpTargetTable) \ - + sizeof((Config)->GuardLongJumpTargetTable) \ - + sizeof((Config)->GuardLongJumpTargetCount))\ - { \ - ADD_VALUE(L"CFG LongJump table", PhaFormatString(L"0x%Ix", (Config)->GuardLongJumpTargetTable)->Buffer); \ - ADD_VALUE(L"CFG LongJump table entry count", PhaFormatUInt64((Config)->GuardLongJumpTargetCount, TRUE)->Buffer); \ - } \ - } \ - } - - if (PvMappedImage.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) - { - if (NT_SUCCESS(PhGetMappedImageLoadConfig32(&PvMappedImage, &config32))) - { - ADD_VALUES(IMAGE_LOAD_CONFIG_DIRECTORY32, config32); - } - } - else - { - if (NT_SUCCESS(PhGetMappedImageLoadConfig64(&PvMappedImage, &config64))) - { - ADD_VALUES(IMAGE_LOAD_CONFIG_DIRECTORY64, config64); - } - } - - EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); - } - break; - case WM_SHOWWINDOW: - { - if (!propPageContext->LayoutInitialized) - { - PPH_LAYOUT_ITEM dialogItem; - - dialogItem = PvAddPropPageLayoutItem(hwndDlg, hwndDlg, - PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL); - PvAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_LIST), - dialogItem, PH_ANCHOR_ALL); - - PvDoPropPageLayout(hwndDlg); - - propPageContext->LayoutInitialized = TRUE; - } - } - break; - case WM_NOTIFY: - { - PvHandleListViewNotifyForCopy(lParam, GetDlgItem(hwndDlg, IDC_LIST)); - } - break; - } - - return FALSE; -} - -VOID PvpLoadDbgHelpFromPath( - _In_ PWSTR DbgHelpPath - ) -{ - HMODULE dbghelpModule; - - if (dbghelpModule = LoadLibrary(DbgHelpPath)) - { - PPH_STRING fullDbghelpPath; - ULONG indexOfFileName; - PH_STRINGREF dbghelpFolder; - PPH_STRING symsrvPath; - - fullDbghelpPath = PhGetDllFileName(dbghelpModule, &indexOfFileName); - - if (fullDbghelpPath) - { - if (indexOfFileName != 0) - { - static PH_STRINGREF symsrvString = PH_STRINGREF_INIT(L"\\symsrv.dll"); - - dbghelpFolder.Buffer = fullDbghelpPath->Buffer; - dbghelpFolder.Length = indexOfFileName * sizeof(WCHAR); - - symsrvPath = PhConcatStringRef2(&dbghelpFolder, &symsrvString); - - LoadLibrary(symsrvPath->Buffer); - - PhDereferenceObject(symsrvPath); - } - - PhDereferenceObject(fullDbghelpPath); - } - } - else - { - dbghelpModule = LoadLibrary(L"dbghelp.dll"); - } - - PhSymbolProviderCompleteInitialization(dbghelpModule); -} - -BOOLEAN PvpLoadDbgHelp( - _Inout_ PPH_SYMBOL_PROVIDER *SymbolProvider - ) -{ - static UNICODE_STRING symbolPathVarName = RTL_CONSTANT_STRING(L"_NT_SYMBOL_PATH"); - PPH_STRING symbolSearchPath; - PPH_SYMBOL_PROVIDER symbolProvider; - WCHAR buffer[512] = L""; - UNICODE_STRING symbolPathUs = - { - .Buffer = buffer, - .MaximumLength = sizeof(buffer) - }; - - if (!PhSymbolProviderInitialization()) - return FALSE; - - PvpLoadDbgHelpFromPath(L"C:\\Program Files (x86)\\Windows Kits\\10\\Debuggers\\x64\\dbghelp.dll"); - symbolProvider = PhCreateSymbolProvider(NULL); - - // Load symbol path from _NT_SYMBOL_PATH if configured by the user. - if (NT_SUCCESS(RtlQueryEnvironmentVariable_U(NULL, &symbolPathVarName, &symbolPathUs))) - { - symbolSearchPath = PhFormatString(L"SRV*%s*http://msdl.microsoft.com/download/symbols", symbolPathUs.Buffer); - } - else - { - symbolSearchPath = PhCreateString(L"SRV**http://msdl.microsoft.com/download/symbols"); - } - - PhSetSearchPathSymbolProvider(symbolProvider, symbolSearchPath->Buffer); - PhDereferenceObject(symbolSearchPath); - - *SymbolProvider = symbolProvider; - return TRUE; -} - -INT_PTR CALLBACK PvpPeCgfDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - LPPROPSHEETPAGE propSheetPage; - PPV_PROPPAGECONTEXT propPageContext; - - if (!PvPropPageDlgProcHeader(hwndDlg, uMsg, lParam, &propSheetPage, &propPageContext)) - return FALSE; - - switch (uMsg) - { - case WM_INITDIALOG: - { - HWND lvHandle; - PPH_SYMBOL_PROVIDER symbolProvider = NULL; - PH_MAPPED_IMAGE_CFG cfgConfig = { 0 }; - - lvHandle = GetDlgItem(hwndDlg, IDC_LIST); - PhSetListViewStyle(lvHandle, FALSE, TRUE); - PhSetControlTheme(lvHandle, L"explorer"); - - PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT , 40, L"#"); - PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_RIGHT, 100, L"RVA"); - PhAddListViewColumn(lvHandle, 2, 2, 2, LVCFMT_LEFT , 250, L"Name"); - PhAddListViewColumn(lvHandle, 3, 3, 3, LVCFMT_LEFT , 100, L"Flags"); - PhSetExtendedListView(lvHandle); - - // Init symbol resolver - if (PvpLoadDbgHelp(&symbolProvider)) - { - // Load current PE's pdb - PhLoadModuleSymbolProvider( - symbolProvider, - PvFileName->Buffer, - (ULONG64)PvMappedImage.NtHeaders->OptionalHeader.ImageBase, - PvMappedImage.NtHeaders->OptionalHeader.SizeOfImage - ); - } - - // Retrieve Cfg Table entry and characteristics - if (NT_SUCCESS(PhGetMappedImageCfg(&cfgConfig, &PvMappedImage))) - { - for (ULONGLONG i = 0; i < cfgConfig.NumberOfGuardFunctionEntries; i++) - { - INT lvItemIndex; - ULONG64 displacement; - PPH_STRING symbol; - PPH_STRING symbolName = NULL; - PH_SYMBOL_RESOLVE_LEVEL symbolResolveLevel = PhsrlInvalid; - IMAGE_CFG_ENTRY cfgFunctionEntry = { 0 }; - - // Parse cfg entry : if it fails, just skip it ? - if (!NT_SUCCESS(PhGetMappedImageCfgEntry(&cfgConfig, i, ControlFlowGuardFunction, &cfgFunctionEntry))) - continue; - - lvItemIndex = PhAddListViewItem( - lvHandle, - MAXINT, - PhaFormatString(L"%I64u", i)->Buffer, - NULL - ); - PhSetListViewSubItem( - lvHandle, - lvItemIndex, - 1, - PhaFormatString(L"0x%08x", cfgFunctionEntry.Rva)->Buffer - ); - - // Resolve name based on public symbols - if (!(symbol = PhGetSymbolFromAddress( - symbolProvider, - (ULONG64)PTR_ADD_OFFSET(PvMappedImage.NtHeaders->OptionalHeader.ImageBase, cfgFunctionEntry.Rva), - &symbolResolveLevel, - NULL, - &symbolName, - &displacement - ))) - { - continue; - } - - switch (symbolResolveLevel) - { - case PhsrlFunction: - { - if (displacement) - { - PhSetListViewSubItem( - lvHandle, - lvItemIndex, - 2, - PhaFormatString(L"%s+0x%x", symbolName->Buffer, displacement)->Buffer - ); - } - else - { - PhSetListViewSubItem(lvHandle, lvItemIndex, 2, symbolName->Buffer); - } - } - break; - case PhsrlModule: - case PhsrlAddress: - { - PhSetListViewSubItem(lvHandle, lvItemIndex, 2, symbol->Buffer); - } - break; - default: - case PhsrlInvalid: - { - PhSetListViewSubItem(lvHandle, lvItemIndex, 2, L"(unnamed)"); - } - break; - } - - // Add additional flags - if (cfgFunctionEntry.SuppressedCall) - PhSetListViewSubItem(lvHandle, lvItemIndex, 3, L"SuppressedCall"); - else - PhSetListViewSubItem(lvHandle, lvItemIndex, 3, L""); - - if (symbolName) - PhDereferenceObject(symbolName); - PhDereferenceObject(symbol); - } - } - - ExtendedListView_SortItems(lvHandle); - EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); - } - break; - case WM_SHOWWINDOW: - { - if (!propPageContext->LayoutInitialized) - { - PPH_LAYOUT_ITEM dialogItem; - - dialogItem = PvAddPropPageLayoutItem(hwndDlg, hwndDlg, - PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL); - PvAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_LIST), - dialogItem, PH_ANCHOR_ALL); - - PvDoPropPageLayout(hwndDlg); - - propPageContext->LayoutInitialized = TRUE; - } - } - break; - case WM_NOTIFY: - { - PvHandleListViewNotifyForCopy(lParam, GetDlgItem(hwndDlg, IDC_LIST)); - } - break; - } - - return FALSE; -} - -INT_PTR CALLBACK PvpPeClrDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - LPPROPSHEETPAGE propSheetPage; - PPV_PROPPAGECONTEXT propPageContext; - - if (!PvPropPageDlgProcHeader(hwndDlg, uMsg, lParam, &propSheetPage, &propPageContext)) - return FALSE; - - switch (uMsg) - { - case WM_INITDIALOG: - { - PH_STRING_BUILDER stringBuilder; - PPH_STRING string; - PVOID metaData; - ULONG versionStringLength; - - string = PhaFormatString(L"%u.%u", PvImageCor20Header->MajorRuntimeVersion, - PvImageCor20Header->MinorRuntimeVersion); - SetDlgItemText(hwndDlg, IDC_RUNTIMEVERSION, string->Buffer); - - PhInitializeStringBuilder(&stringBuilder, 256); - - if (PvImageCor20Header->Flags & COMIMAGE_FLAGS_ILONLY) - PhAppendStringBuilder2(&stringBuilder, L"IL only, "); - if (PvImageCor20Header->Flags & COMIMAGE_FLAGS_32BITREQUIRED) - PhAppendStringBuilder2(&stringBuilder, L"32-bit only, "); - if (PvImageCor20Header->Flags & COMIMAGE_FLAGS_32BITPREFERRED) - PhAppendStringBuilder2(&stringBuilder, L"32-bit preferred, "); - if (PvImageCor20Header->Flags & COMIMAGE_FLAGS_IL_LIBRARY) - PhAppendStringBuilder2(&stringBuilder, L"IL library, "); - - if (PvImageCor20Header->StrongNameSignature.VirtualAddress != 0 && PvImageCor20Header->StrongNameSignature.Size != 0) - { - if (PvImageCor20Header->Flags & COMIMAGE_FLAGS_STRONGNAMESIGNED) - PhAppendStringBuilder2(&stringBuilder, L"Strong-name signed, "); - else - PhAppendStringBuilder2(&stringBuilder, L"Strong-name delay signed, "); - } - - if (PvImageCor20Header->Flags & COMIMAGE_FLAGS_NATIVE_ENTRYPOINT) - PhAppendStringBuilder2(&stringBuilder, L"Native entry-point, "); - if (PvImageCor20Header->Flags & COMIMAGE_FLAGS_TRACKDEBUGDATA) - PhAppendStringBuilder2(&stringBuilder, L"Track debug data, "); - - if (PhEndsWithString2(stringBuilder.String, L", ", FALSE)) - PhRemoveEndStringBuilder(&stringBuilder, 2); - - SetDlgItemText(hwndDlg, IDC_FLAGS, stringBuilder.String->Buffer); - PhDeleteStringBuilder(&stringBuilder); - - metaData = PhMappedImageRvaToVa(&PvMappedImage, PvImageCor20Header->MetaData.VirtualAddress, NULL); - - if (metaData) - { - __try - { - PhProbeAddress(metaData, PvImageCor20Header->MetaData.Size, PvMappedImage.ViewBase, PvMappedImage.Size, 4); - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - metaData = NULL; - } - } - - versionStringLength = 0; - - if (metaData) - { - // Skip 12 bytes. - // First 4 bytes contains the length of the version string. - // The version string follows. - versionStringLength = *(PULONG)((PCHAR)metaData + 12); - - // Make sure the length is valid. - if (versionStringLength >= 0x100) - versionStringLength = 0; - } - - if (versionStringLength != 0) - { - string = PhZeroExtendToUtf16Ex((PCHAR)metaData + 12 + 4, versionStringLength); - SetDlgItemText(hwndDlg, IDC_VERSIONSTRING, string->Buffer); - PhDereferenceObject(string); - } - else - { - SetDlgItemText(hwndDlg, IDC_VERSIONSTRING, L"N/A"); - } - } - break; - case WM_SHOWWINDOW: - { - if (!propPageContext->LayoutInitialized) - { - PvAddPropPageLayoutItem(hwndDlg, hwndDlg, - PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL); - - PvDoPropPageLayout(hwndDlg); - - propPageContext->LayoutInitialized = TRUE; - } - } - break; - case WM_NOTIFY: - { - LPNMHDR header = (LPNMHDR)lParam; - - switch (header->code) - { - case PSN_QUERYINITIALFOCUS: - { - SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, (LONG_PTR)GetDlgItem(hwndDlg, IDC_RUNTIMEVERSION)); - } - return TRUE; - } - } - break; - } - - return FALSE; -} +/* + * Process Hacker - + * PE viewer + * + * Copyright (C) 2010-2011 wj32 + * Copyright (C) 2017 dmex + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PVM_CHECKSUM_DONE (WM_APP + 1) +#define PVM_VERIFY_DONE (WM_APP + 2) + +INT_PTR CALLBACK PvpPeGeneralDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +INT_PTR CALLBACK PvpPeImportsDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +INT_PTR CALLBACK PvpPeExportsDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +INT_PTR CALLBACK PvpPeLoadConfigDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +INT_PTR CALLBACK PvpPeClrDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +INT_PTR CALLBACK PvpPeCgfDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +PH_MAPPED_IMAGE PvMappedImage; +PIMAGE_COR20_HEADER PvImageCor20Header; + +HICON PvImageLargeIcon; +PH_IMAGE_VERSION_INFO PvImageVersionInfo; +VERIFY_RESULT PvImageVerifyResult; +PPH_STRING PvImageSignerName; + +VOID PvPeProperties( + VOID + ) +{ + NTSTATUS status; + PPV_PROPCONTEXT propContext; + PH_MAPPED_IMAGE_IMPORTS imports; + PH_MAPPED_IMAGE_EXPORTS exports; + PIMAGE_DATA_DIRECTORY entry; + + if (!NT_SUCCESS(status = PhLoadMappedImage( + PvFileName->Buffer, + NULL, + TRUE, + &PvMappedImage + ))) + { + PhShowStatus(NULL, L"Unable to load the PE file", status, 0); + return; + } + + if (propContext = PvCreatePropContext(PvFileName)) + { + PPV_PROPPAGECONTEXT newPage; + + // General page + newPage = PvCreatePropPageContext( + MAKEINTRESOURCE(IDD_PEGENERAL), + PvpPeGeneralDlgProc, + NULL + ); + PvAddPropPage(propContext, newPage); + + // Imports page + if ((NT_SUCCESS(PhGetMappedImageImports(&imports, &PvMappedImage)) && imports.NumberOfDlls != 0) || + (NT_SUCCESS(PhGetMappedImageDelayImports(&imports, &PvMappedImage)) && imports.NumberOfDlls != 0)) + { + newPage = PvCreatePropPageContext( + MAKEINTRESOURCE(IDD_PEIMPORTS), + PvpPeImportsDlgProc, + NULL + ); + PvAddPropPage(propContext, newPage); + } + + // Exports page + if (NT_SUCCESS(PhGetMappedImageExports(&exports, &PvMappedImage)) && exports.NumberOfEntries != 0) + { + newPage = PvCreatePropPageContext( + MAKEINTRESOURCE(IDD_PEEXPORTS), + PvpPeExportsDlgProc, + NULL + ); + PvAddPropPage(propContext, newPage); + } + + // Load Config page + if (NT_SUCCESS(PhGetMappedImageDataEntry(&PvMappedImage, IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG, &entry)) && entry->VirtualAddress) + { + newPage = PvCreatePropPageContext( + MAKEINTRESOURCE(IDD_PELOADCONFIG), + PvpPeLoadConfigDlgProc, + NULL + ); + PvAddPropPage(propContext, newPage); + } + + // CLR page + if (NT_SUCCESS(PhGetMappedImageDataEntry(&PvMappedImage, IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR, &entry)) && + entry->VirtualAddress && + (PvImageCor20Header = PhMappedImageRvaToVa(&PvMappedImage, entry->VirtualAddress, NULL))) + { + status = STATUS_SUCCESS; + + __try + { + PhProbeAddress( + PvImageCor20Header, + sizeof(IMAGE_COR20_HEADER), + PvMappedImage.ViewBase, + PvMappedImage.Size, + 4 + ); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + status = GetExceptionCode(); + } + + if (NT_SUCCESS(status)) + { + newPage = PvCreatePropPageContext( + MAKEINTRESOURCE(IDD_PECLR), + PvpPeClrDlgProc, + NULL + ); + PvAddPropPage(propContext, newPage); + } + } + + // CFG page + if ((PvMappedImage.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) && + (PvMappedImage.NtHeaders->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_GUARD_CF)) + { + newPage = PvCreatePropPageContext( + MAKEINTRESOURCE(IDD_PECFG), + PvpPeCgfDlgProc, + NULL + ); + PvAddPropPage(propContext, newPage); + } + + PhModalPropertySheet(&propContext->PropSheetHeader); + + PhDereferenceObject(propContext); + } + + PhUnloadMappedImage(&PvMappedImage); +} + +static NTSTATUS CheckSumImageThreadStart( + _In_ PVOID Parameter + ) +{ + HWND windowHandle; + ULONG checkSum; + + windowHandle = Parameter; + checkSum = PhCheckSumMappedImage(&PvMappedImage); + + PostMessage( + windowHandle, + PVM_CHECKSUM_DONE, + checkSum, + 0 + ); + + return STATUS_SUCCESS; +} + +VERIFY_RESULT PvpVerifyFileWithAdditionalCatalog( + _In_ PPH_STRING FileName, + _In_ ULONG Flags, + _In_opt_ HWND hWnd, + _Out_opt_ PPH_STRING *SignerName + ) +{ + static PH_STRINGREF codeIntegrityFileName = PH_STRINGREF_INIT(L"\\AppxMetadata\\CodeIntegrity.cat"); + + VERIFY_RESULT result; + PH_VERIFY_FILE_INFO info; + PPH_STRING windowsAppsPath; + PPH_STRING additionalCatalogFileName = NULL; + PCERT_CONTEXT *signatures; + ULONG numberOfSignatures; + + memset(&info, 0, sizeof(PH_VERIFY_FILE_INFO)); + info.FileName = FileName->Buffer; + info.Flags = Flags; + info.hWnd = hWnd; + + windowsAppsPath = PhGetKnownLocation(CSIDL_PROGRAM_FILES, L"\\WindowsApps\\"); + + if (windowsAppsPath) + { + if (PhStartsWithStringRef(&FileName->sr, &windowsAppsPath->sr, TRUE)) + { + PH_STRINGREF remainingFileName; + ULONG_PTR indexOfBackslash; + PH_STRINGREF baseFileName; + + remainingFileName = FileName->sr; + PhSkipStringRef(&remainingFileName, windowsAppsPath->Length); + indexOfBackslash = PhFindCharInStringRef(&remainingFileName, '\\', FALSE); + + if (indexOfBackslash != -1) + { + baseFileName.Buffer = FileName->Buffer; + baseFileName.Length = windowsAppsPath->Length + indexOfBackslash * sizeof(WCHAR); + additionalCatalogFileName = PhConcatStringRef2(&baseFileName, &codeIntegrityFileName); + } + } + + PhDereferenceObject(windowsAppsPath); + } + + if (additionalCatalogFileName) + { + info.NumberOfCatalogFileNames = 1; + info.CatalogFileNames = &additionalCatalogFileName->Buffer; + } + + if (!NT_SUCCESS(PhVerifyFileEx(&info, &result, &signatures, &numberOfSignatures))) + { + result = VrNoSignature; + signatures = NULL; + numberOfSignatures = 0; + } + + if (additionalCatalogFileName) + PhDereferenceObject(additionalCatalogFileName); + + if (SignerName) + { + if (numberOfSignatures != 0) + *SignerName = PhGetSignerNameFromCertificate(signatures[0]); + else + *SignerName = NULL; + } + + PhFreeVerifySignatures(signatures, numberOfSignatures); + + return result; +} + +static NTSTATUS VerifyImageThreadStart( + _In_ PVOID Parameter + ) +{ + HWND windowHandle; + + windowHandle = Parameter; + PvImageVerifyResult = PvpVerifyFileWithAdditionalCatalog(PvFileName, PH_VERIFY_PREVENT_NETWORK_ACCESS, NULL, &PvImageSignerName); + PostMessage(windowHandle, PVM_VERIFY_DONE, 0, 0); + + return STATUS_SUCCESS; +} + +FORCEINLINE PWSTR PvpGetStringOrNa( + _In_ PPH_STRING String + ) +{ + if (String) + return String->Buffer; + else + return L"N/A"; +} + +INT_PTR CALLBACK PvpPeGeneralDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + LPPROPSHEETPAGE propSheetPage; + PPV_PROPPAGECONTEXT propPageContext; + + if (!PvPropPageDlgProcHeader(hwndDlg, uMsg, lParam, &propSheetPage, &propPageContext)) + return FALSE; + + switch (uMsg) + { + case WM_INITDIALOG: + { + HWND lvHandle; + ULONG i; + PPH_STRING string; + PWSTR type; + PH_STRING_BUILDER stringBuilder; + + PhCenterWindow(GetParent(hwndDlg), NULL); + + // File version information + + { + PhInitializeImageVersionInfo(&PvImageVersionInfo, PvFileName->Buffer); + + if (ExtractIconEx( + PvFileName->Buffer, + 0, + &PvImageLargeIcon, + NULL, + 1 + ) == 0) + { + PvImageLargeIcon = PhGetFileShellIcon(PvFileName->Buffer, NULL, TRUE); + } + + SendMessage(GetDlgItem(hwndDlg, IDC_FILEICON), STM_SETICON, (WPARAM)PvImageLargeIcon, 0); + + SetDlgItemText(hwndDlg, IDC_NAME, PvpGetStringOrNa(PvImageVersionInfo.FileDescription)); + string = PhConcatStrings2(L"(Verifying...) ", PvpGetStringOrNa(PvImageVersionInfo.CompanyName)); + SetDlgItemText(hwndDlg, IDC_COMPANYNAME, string->Buffer); + PhDereferenceObject(string); + SetDlgItemText(hwndDlg, IDC_VERSION, PvpGetStringOrNa(PvImageVersionInfo.FileVersion)); + + PhQueueItemWorkQueue(PhGetGlobalWorkQueue(), VerifyImageThreadStart, hwndDlg); + } + + // PE properties + + switch (PvMappedImage.NtHeaders->FileHeader.Machine) + { + case IMAGE_FILE_MACHINE_I386: + type = L"i386"; + break; + case IMAGE_FILE_MACHINE_AMD64: + type = L"AMD64"; + break; + case IMAGE_FILE_MACHINE_IA64: + type = L"IA64"; + break; + case IMAGE_FILE_MACHINE_ARMNT: + type = L"ARM Thumb-2"; + break; + default: + type = L"Unknown"; + break; + } + + SetDlgItemText(hwndDlg, IDC_TARGETMACHINE, type); + + { + LARGE_INTEGER time; + SYSTEMTIME systemTime; + + RtlSecondsSince1970ToTime(PvMappedImage.NtHeaders->FileHeader.TimeDateStamp, &time); + PhLargeIntegerToLocalSystemTime(&systemTime, &time); + + string = PhFormatDateTime(&systemTime); + SetDlgItemText(hwndDlg, IDC_TIMESTAMP, string->Buffer); + PhDereferenceObject(string); + } + + if (PvMappedImage.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) + { + string = PhFormatString(L"0x%I32x", ((PIMAGE_OPTIONAL_HEADER32)&PvMappedImage.NtHeaders->OptionalHeader)->ImageBase); + } + else + { + string = PhFormatString(L"0x%I64x", ((PIMAGE_OPTIONAL_HEADER64)&PvMappedImage.NtHeaders->OptionalHeader)->ImageBase); + } + + SetDlgItemText(hwndDlg, IDC_IMAGEBASE, string->Buffer); + PhDereferenceObject(string); + + if (PvMappedImage.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) + { + string = PhFormatString(L"0x%I32x", ((PIMAGE_OPTIONAL_HEADER32)&PvMappedImage.NtHeaders->OptionalHeader)->AddressOfEntryPoint); + } + else + { + string = PhFormatString(L"0x%I64x", ((PIMAGE_OPTIONAL_HEADER64)&PvMappedImage.NtHeaders->OptionalHeader)->AddressOfEntryPoint); + } + + SetDlgItemText(hwndDlg, IDC_ENTRYPOINT, string->Buffer); + PhDereferenceObject(string); + + string = PhFormatString(L"0x%Ix (verifying...)", PvMappedImage.NtHeaders->OptionalHeader.CheckSum); // same for 32-bit and 64-bit images + SetDlgItemText(hwndDlg, IDC_CHECKSUM, string->Buffer); + PhDereferenceObject(string); + + PhQueueItemWorkQueue(PhGetGlobalWorkQueue(), CheckSumImageThreadStart, hwndDlg); + + switch (PvMappedImage.NtHeaders->OptionalHeader.Subsystem) + { + case IMAGE_SUBSYSTEM_NATIVE: + type = L"Native"; + break; + case IMAGE_SUBSYSTEM_WINDOWS_GUI: + type = L"Windows GUI"; + break; + case IMAGE_SUBSYSTEM_WINDOWS_CUI: + type = L"Windows CUI"; + break; + case IMAGE_SUBSYSTEM_OS2_CUI: + type = L"OS/2 CUI"; + break; + case IMAGE_SUBSYSTEM_POSIX_CUI: + type = L"POSIX CUI"; + break; + case IMAGE_SUBSYSTEM_WINDOWS_CE_GUI: + type = L"Windows CE CUI"; + break; + case IMAGE_SUBSYSTEM_EFI_APPLICATION: + type = L"EFI Application"; + break; + case IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER: + type = L"EFI Boot Service Driver"; + break; + case IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER: + type = L"EFI Runtime Driver"; + break; + case IMAGE_SUBSYSTEM_EFI_ROM: + type = L"EFI ROM"; + break; + case IMAGE_SUBSYSTEM_XBOX: + type = L"Xbox"; + break; + case IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION: + type = L"Windows Boot Application"; + break; + default: + type = L"Unknown"; + break; + } + + SetDlgItemText(hwndDlg, IDC_SUBSYSTEM, type); + SetDlgItemText(hwndDlg, IDC_SUBSYSTEMVERSION, PhaFormatString( + L"%u.%u", + PvMappedImage.NtHeaders->OptionalHeader.MajorSubsystemVersion, // same for 32-bit and 64-bit images + PvMappedImage.NtHeaders->OptionalHeader.MinorSubsystemVersion + )->Buffer); + + PhInitializeStringBuilder(&stringBuilder, 10); + + if (PvMappedImage.NtHeaders->FileHeader.Characteristics & IMAGE_FILE_EXECUTABLE_IMAGE) + PhAppendStringBuilder2(&stringBuilder, L"Executable, "); + if (PvMappedImage.NtHeaders->FileHeader.Characteristics & IMAGE_FILE_DLL) + PhAppendStringBuilder2(&stringBuilder, L"DLL, "); + if (PvMappedImage.NtHeaders->FileHeader.Characteristics & IMAGE_FILE_LARGE_ADDRESS_AWARE) + PhAppendStringBuilder2(&stringBuilder, L"Large address aware, "); + if (PvMappedImage.NtHeaders->FileHeader.Characteristics & IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP) + PhAppendStringBuilder2(&stringBuilder, L"Removable run from swap, "); + if (PvMappedImage.NtHeaders->FileHeader.Characteristics & IMAGE_FILE_NET_RUN_FROM_SWAP) + PhAppendStringBuilder2(&stringBuilder, L"Net run from swap, "); + if (PvMappedImage.NtHeaders->FileHeader.Characteristics & IMAGE_FILE_SYSTEM) + PhAppendStringBuilder2(&stringBuilder, L"System, "); + if (PvMappedImage.NtHeaders->FileHeader.Characteristics & IMAGE_FILE_UP_SYSTEM_ONLY) + PhAppendStringBuilder2(&stringBuilder, L"Uni-processor only, "); + + if (PvMappedImage.NtHeaders->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA) + PhAppendStringBuilder2(&stringBuilder, L"High entropy VA, "); + if (PvMappedImage.NtHeaders->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE) + PhAppendStringBuilder2(&stringBuilder, L"Dynamic base, "); + if (PvMappedImage.NtHeaders->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY) + PhAppendStringBuilder2(&stringBuilder, L"Force integrity check, "); + if (PvMappedImage.NtHeaders->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_NX_COMPAT) + PhAppendStringBuilder2(&stringBuilder, L"NX compatible, "); + if (PvMappedImage.NtHeaders->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_NO_ISOLATION) + PhAppendStringBuilder2(&stringBuilder, L"No isolation, "); + if (PvMappedImage.NtHeaders->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_NO_SEH) + PhAppendStringBuilder2(&stringBuilder, L"No SEH, "); + if (PvMappedImage.NtHeaders->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_NO_BIND) + PhAppendStringBuilder2(&stringBuilder, L"Do not bind, "); + if (PvMappedImage.NtHeaders->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_APPCONTAINER) + PhAppendStringBuilder2(&stringBuilder, L"AppContainer, "); + if (PvMappedImage.NtHeaders->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_WDM_DRIVER) + PhAppendStringBuilder2(&stringBuilder, L"WDM driver, "); + if (PvMappedImage.NtHeaders->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_GUARD_CF) + PhAppendStringBuilder2(&stringBuilder, L"Control Flow Guard, "); + if (PvMappedImage.NtHeaders->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE) + PhAppendStringBuilder2(&stringBuilder, L"Terminal server aware, "); + + if (PhEndsWithString2(stringBuilder.String, L", ", FALSE)) + PhRemoveEndStringBuilder(&stringBuilder, 2); + + SetDlgItemText(hwndDlg, IDC_CHARACTERISTICS, stringBuilder.String->Buffer); + PhDeleteStringBuilder(&stringBuilder); + + lvHandle = GetDlgItem(hwndDlg, IDC_LIST); + PhSetListViewStyle(lvHandle, FALSE, TRUE); + PhSetControlTheme(lvHandle, L"explorer"); + PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 80, L"Name"); + PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 80, L"VA"); + PhAddListViewColumn(lvHandle, 2, 2, 2, LVCFMT_LEFT, 80, L"Size"); + + for (i = 0; i < PvMappedImage.NumberOfSections; i++) + { + INT lvItemIndex; + WCHAR sectionName[9]; + WCHAR pointer[PH_PTR_STR_LEN_1]; + + if (PhCopyStringZFromBytes(PvMappedImage.Sections[i].Name, + IMAGE_SIZEOF_SHORT_NAME, sectionName, 9, NULL)) + { + lvItemIndex = PhAddListViewItem(lvHandle, MAXINT, sectionName, NULL); + + PhPrintPointer(pointer, UlongToPtr(PvMappedImage.Sections[i].VirtualAddress)); + PhSetListViewSubItem(lvHandle, lvItemIndex, 1, pointer); + + PhPrintPointer(pointer, UlongToPtr(PvMappedImage.Sections[i].SizeOfRawData)); + PhSetListViewSubItem(lvHandle, lvItemIndex, 2, pointer); + } + } + } + break; + case WM_SHOWWINDOW: + { + if (!propPageContext->LayoutInitialized) + { + PPH_LAYOUT_ITEM dialogItem; + + dialogItem = PvAddPropPageLayoutItem(hwndDlg, hwndDlg, + PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL); + PvAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_FILE), + dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); + PvAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_NAME), + dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); + PvAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_CHARACTERISTICS), + dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); + PvAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_LIST), + dialogItem, PH_ANCHOR_ALL); + + PvDoPropPageLayout(hwndDlg); + + propPageContext->LayoutInitialized = TRUE; + } + } + break; + case PVM_CHECKSUM_DONE: + { + PPH_STRING string; + ULONG headerCheckSum; + ULONG realCheckSum; + + headerCheckSum = PvMappedImage.NtHeaders->OptionalHeader.CheckSum; // same for 32-bit and 64-bit images + realCheckSum = (ULONG)wParam; + + if (headerCheckSum == 0) + { + // Some executables, like .NET ones, don't have a check sum. + string = PhFormatString(L"0x0 (real 0x%Ix)", realCheckSum); + SetDlgItemText(hwndDlg, IDC_CHECKSUM, string->Buffer); + PhDereferenceObject(string); + } + else if (headerCheckSum == realCheckSum) + { + string = PhFormatString(L"0x%Ix (correct)", headerCheckSum); + SetDlgItemText(hwndDlg, IDC_CHECKSUM, string->Buffer); + PhDereferenceObject(string); + } + else + { + string = PhFormatString(L"0x%Ix (incorrect, real 0x%Ix)", headerCheckSum, realCheckSum); + SetDlgItemText(hwndDlg, IDC_CHECKSUM, string->Buffer); + PhDereferenceObject(string); + } + } + break; + case PVM_VERIFY_DONE: + { + PPH_STRING string; + + if (PvImageVerifyResult == VrTrusted) + { + if (PvImageSignerName) + { + string = PhFormatString(L"(Verified) %s", PvImageSignerName->Buffer); + SetDlgItemText(hwndDlg, IDC_COMPANYNAME_LINK, string->Buffer); + PhDereferenceObject(string); + ShowWindow(GetDlgItem(hwndDlg, IDC_COMPANYNAME), SW_HIDE); + ShowWindow(GetDlgItem(hwndDlg, IDC_COMPANYNAME_LINK), SW_SHOW); + } + else + { + string = PhConcatStrings2(L"(Verified) ", PhGetStringOrEmpty(PvImageVersionInfo.CompanyName)); + SetDlgItemText(hwndDlg, IDC_COMPANYNAME, string->Buffer); + PhDereferenceObject(string); + } + } + else if (PvImageVerifyResult != VrUnknown) + { + string = PhConcatStrings2(L"(UNVERIFIED) ", PhGetStringOrEmpty(PvImageVersionInfo.CompanyName)); + SetDlgItemText(hwndDlg, IDC_COMPANYNAME, string->Buffer); + PhDereferenceObject(string); + } + else + { + SetDlgItemText(hwndDlg, IDC_COMPANYNAME, PvpGetStringOrNa(PvImageVersionInfo.CompanyName)); + } + } + break; + case WM_NOTIFY: + { + LPNMHDR header = (LPNMHDR)lParam; + + switch (header->code) + { + case NM_CLICK: + { + switch (header->idFrom) + { + case IDC_COMPANYNAME_LINK: + { + PvpVerifyFileWithAdditionalCatalog(PvFileName, PH_VERIFY_VIEW_PROPERTIES, hwndDlg, NULL); + } + break; + } + } + break; + } + + PvHandleListViewNotifyForCopy(lParam, GetDlgItem(hwndDlg, IDC_LIST)); + } + break; + } + + return FALSE; +} + +VOID PvpProcessImports( + _In_ HWND ListViewHandle, + _In_ PPH_MAPPED_IMAGE_IMPORTS Imports, + _In_ BOOLEAN DelayImports + ) +{ + PH_MAPPED_IMAGE_IMPORT_DLL importDll; + PH_MAPPED_IMAGE_IMPORT_ENTRY importEntry; + ULONG i; + ULONG j; + + for (i = 0; i < Imports->NumberOfDlls; i++) + { + if (NT_SUCCESS(PhGetMappedImageImportDll(Imports, i, &importDll))) + { + for (j = 0; j < importDll.NumberOfEntries; j++) + { + if (NT_SUCCESS(PhGetMappedImageImportEntry(&importDll, j, &importEntry))) + { + INT lvItemIndex; + PPH_STRING name; + WCHAR number[PH_INT32_STR_LEN_1]; + + if (!DelayImports) + name = PhZeroExtendToUtf16(importDll.Name); + else + name = PhFormatString(L"%S (Delay)", importDll.Name); + + lvItemIndex = PhAddListViewItem(ListViewHandle, MAXINT, name->Buffer, NULL); + PhDereferenceObject(name); + + if (importEntry.Name) + { + name = PhZeroExtendToUtf16(importEntry.Name); + PhSetListViewSubItem(ListViewHandle, lvItemIndex, 1, name->Buffer); + PhDereferenceObject(name); + + PhPrintUInt32(number, importEntry.NameHint); + PhSetListViewSubItem(ListViewHandle, lvItemIndex, 2, number); + } + else + { + name = PhFormatString(L"(Ordinal %u)", importEntry.Ordinal); + PhSetListViewSubItem(ListViewHandle, lvItemIndex, 1, name->Buffer); + PhDereferenceObject(name); + } + } + } + } + } +} + +INT_PTR CALLBACK PvpPeImportsDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + LPPROPSHEETPAGE propSheetPage; + PPV_PROPPAGECONTEXT propPageContext; + + if (!PvPropPageDlgProcHeader(hwndDlg, uMsg, lParam, &propSheetPage, &propPageContext)) + return FALSE; + + switch (uMsg) + { + case WM_INITDIALOG: + { + ULONG fallbackColumns[] = { 0, 1, 2 }; + HWND lvHandle; + PH_MAPPED_IMAGE_IMPORTS imports; + + lvHandle = GetDlgItem(hwndDlg, IDC_LIST); + PhSetListViewStyle(lvHandle, FALSE, TRUE); + PhSetControlTheme(lvHandle, L"explorer"); + PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 130, L"DLL"); + PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 210, L"Name"); + PhAddListViewColumn(lvHandle, 2, 2, 2, LVCFMT_LEFT, 50, L"Hint"); + PhSetExtendedListView(lvHandle); + ExtendedListView_AddFallbackColumns(lvHandle, 3, fallbackColumns); + + if (NT_SUCCESS(PhGetMappedImageImports(&imports, &PvMappedImage))) + { + PvpProcessImports(lvHandle, &imports, FALSE); + } + + if (NT_SUCCESS(PhGetMappedImageDelayImports(&imports, &PvMappedImage))) + { + PvpProcessImports(lvHandle, &imports, TRUE); + } + + ExtendedListView_SortItems(lvHandle); + + EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); + } + break; + case WM_SHOWWINDOW: + { + if (!propPageContext->LayoutInitialized) + { + PPH_LAYOUT_ITEM dialogItem; + + dialogItem = PvAddPropPageLayoutItem(hwndDlg, hwndDlg, + PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL); + PvAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_LIST), + dialogItem, PH_ANCHOR_ALL); + + PvDoPropPageLayout(hwndDlg); + + propPageContext->LayoutInitialized = TRUE; + } + } + break; + case WM_NOTIFY: + { + PvHandleListViewNotifyForCopy(lParam, GetDlgItem(hwndDlg, IDC_LIST)); + } + break; + } + + return FALSE; +} + +INT_PTR CALLBACK PvpPeExportsDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + LPPROPSHEETPAGE propSheetPage; + PPV_PROPPAGECONTEXT propPageContext; + + if (!PvPropPageDlgProcHeader(hwndDlg, uMsg, lParam, &propSheetPage, &propPageContext)) + return FALSE; + + switch (uMsg) + { + case WM_INITDIALOG: + { + HWND lvHandle; + PH_MAPPED_IMAGE_EXPORTS exports; + PH_MAPPED_IMAGE_EXPORT_ENTRY exportEntry; + PH_MAPPED_IMAGE_EXPORT_FUNCTION exportFunction; + ULONG i; + + lvHandle = GetDlgItem(hwndDlg, IDC_LIST); + PhSetListViewStyle(lvHandle, FALSE, TRUE); + PhSetControlTheme(lvHandle, L"explorer"); + PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 220, L"Name"); + PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 50, L"Ordinal"); + PhAddListViewColumn(lvHandle, 2, 2, 2, LVCFMT_LEFT, 120, L"VA"); + PhSetExtendedListView(lvHandle); + + if (NT_SUCCESS(PhGetMappedImageExports(&exports, &PvMappedImage))) + { + for (i = 0; i < exports.NumberOfEntries; i++) + { + if ( + NT_SUCCESS(PhGetMappedImageExportEntry(&exports, i, &exportEntry)) && + NT_SUCCESS(PhGetMappedImageExportFunction(&exports, NULL, exportEntry.Ordinal, &exportFunction)) + ) + { + INT lvItemIndex; + PPH_STRING name; + WCHAR number[PH_INT32_STR_LEN_1]; + WCHAR pointer[PH_PTR_STR_LEN_1]; + + if (exportEntry.Name) + { + name = PhZeroExtendToUtf16(exportEntry.Name); + lvItemIndex = PhAddListViewItem(lvHandle, MAXINT, name->Buffer, NULL); + PhDereferenceObject(name); + } + else + { + lvItemIndex = PhAddListViewItem(lvHandle, MAXINT, L"(unnamed)", NULL); + } + + PhPrintUInt32(number, exportEntry.Ordinal); + PhSetListViewSubItem(lvHandle, lvItemIndex, 1, number); + + if (!exportFunction.ForwardedName) + { + if ((ULONG_PTR)exportFunction.Function >= (ULONG_PTR)PvMappedImage.ViewBase) + PhPrintPointer(pointer, PTR_SUB_OFFSET(exportFunction.Function, PvMappedImage.ViewBase)); + else + PhPrintPointer(pointer, exportFunction.Function); + + PhSetListViewSubItem(lvHandle, lvItemIndex, 2, pointer); + } + else + { + name = PhZeroExtendToUtf16(exportFunction.ForwardedName); + PhSetListViewSubItem(lvHandle, lvItemIndex, 2, name->Buffer); + PhDereferenceObject(name); + } + } + } + } + + ExtendedListView_SortItems(lvHandle); + + EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); + } + break; + case WM_SHOWWINDOW: + { + if (!propPageContext->LayoutInitialized) + { + PPH_LAYOUT_ITEM dialogItem; + + dialogItem = PvAddPropPageLayoutItem(hwndDlg, hwndDlg, + PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL); + PvAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_LIST), + dialogItem, PH_ANCHOR_ALL); + + PvDoPropPageLayout(hwndDlg); + + propPageContext->LayoutInitialized = TRUE; + } + } + break; + case WM_NOTIFY: + { + PvHandleListViewNotifyForCopy(lParam, GetDlgItem(hwndDlg, IDC_LIST)); + } + break; + } + + return FALSE; +} + +INT_PTR CALLBACK PvpPeLoadConfigDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + LPPROPSHEETPAGE propSheetPage; + PPV_PROPPAGECONTEXT propPageContext; + + if (!PvPropPageDlgProcHeader(hwndDlg, uMsg, lParam, &propSheetPage, &propPageContext)) + return FALSE; + + switch (uMsg) + { + case WM_INITDIALOG: + { + HWND lvHandle; + PIMAGE_LOAD_CONFIG_DIRECTORY32 config32; + PIMAGE_LOAD_CONFIG_DIRECTORY64 config64; + + lvHandle = GetDlgItem(hwndDlg, IDC_LIST); + PhSetListViewStyle(lvHandle, FALSE, TRUE); + PhSetControlTheme(lvHandle, L"explorer"); + PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 220, L"Name"); + PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 170, L"Value"); + + #define ADD_VALUE(Name, Value) \ + { \ + INT lvItemIndex; \ + lvItemIndex = PhAddListViewItem(lvHandle, MAXINT, Name, NULL); \ + PhSetListViewSubItem(lvHandle, lvItemIndex, 1, Value); \ + } + + #define ADD_VALUES(Type, Config) \ + { \ + LARGE_INTEGER time; \ + SYSTEMTIME systemTime; \ + \ + RtlSecondsSince1970ToTime((Config)->TimeDateStamp, &time); \ + PhLargeIntegerToLocalSystemTime(&systemTime, &time); \ + \ + ADD_VALUE(L"Time stamp", PhaFormatDateTime(&systemTime)->Buffer); \ + ADD_VALUE(L"Version", PhaFormatString(L"%u.%u", (Config)->MajorVersion, (Config)->MinorVersion)->Buffer); \ + ADD_VALUE(L"Global flags to clear", PhaFormatString(L"0x%x", (Config)->GlobalFlagsClear)->Buffer); \ + ADD_VALUE(L"Global flags to set", PhaFormatString(L"0x%x", (Config)->GlobalFlagsSet)->Buffer); \ + ADD_VALUE(L"Critical section default timeout", PhaFormatUInt64((Config)->CriticalSectionDefaultTimeout, TRUE)->Buffer); \ + ADD_VALUE(L"De-commit free block threshold", PhaFormatUInt64((Config)->DeCommitFreeBlockThreshold, TRUE)->Buffer); \ + ADD_VALUE(L"De-commit total free threshold", PhaFormatUInt64((Config)->DeCommitTotalFreeThreshold, TRUE)->Buffer); \ + ADD_VALUE(L"LOCK prefix table", PhaFormatString(L"0x%Ix", (Config)->LockPrefixTable)->Buffer); \ + ADD_VALUE(L"Maximum allocation size", PhaFormatString(L"0x%Ix", (Config)->MaximumAllocationSize)->Buffer); \ + ADD_VALUE(L"Virtual memory threshold", PhaFormatString(L"0x%Ix", (Config)->VirtualMemoryThreshold)->Buffer); \ + ADD_VALUE(L"Process affinity mask", PhaFormatString(L"0x%Ix", (Config)->ProcessAffinityMask)->Buffer); \ + ADD_VALUE(L"Process heap flags", PhaFormatString(L"0x%Ix", (Config)->ProcessHeapFlags)->Buffer); \ + ADD_VALUE(L"CSD version", PhaFormatString(L"%u", (Config)->CSDVersion)->Buffer); \ + ADD_VALUE(L"Edit list", PhaFormatString(L"0x%Ix", (Config)->EditList)->Buffer); \ + ADD_VALUE(L"Security cookie", PhaFormatString(L"0x%Ix", (Config)->SecurityCookie)->Buffer); \ + ADD_VALUE(L"SEH handler table", PhaFormatString(L"0x%Ix", (Config)->SEHandlerTable)->Buffer); \ + ADD_VALUE(L"SEH handler count", PhaFormatUInt64((Config)->SEHandlerCount, TRUE)->Buffer); \ + \ + if ((Config)->Size >= (ULONG)FIELD_OFFSET(Type, GuardAddressTakenIatEntryTable)) \ + { \ + ADD_VALUE(L"CFG GuardFlags", PhaFormatString(L"0x%Ix", (Config)->GuardFlags)->Buffer); \ + ADD_VALUE(L"CFG Check Function pointer", PhaFormatString(L"0x%Ix", (Config)->GuardCFCheckFunctionPointer)->Buffer); \ + ADD_VALUE(L"CFG Check Dispatch pointer", PhaFormatString(L"0x%Ix", (Config)->GuardCFDispatchFunctionPointer)->Buffer); \ + ADD_VALUE(L"CFG Function table", PhaFormatString(L"0x%Ix", (Config)->GuardCFFunctionTable)->Buffer); \ + ADD_VALUE(L"CFG Function table entry count", PhaFormatUInt64((Config)->GuardCFFunctionCount, TRUE)->Buffer); \ + if ((Config)->Size >= (ULONG)FIELD_OFFSET(Type, GuardAddressTakenIatEntryTable) \ + + sizeof((Config)->GuardAddressTakenIatEntryTable) \ + + sizeof((Config)->GuardAddressTakenIatEntryCount)) \ + { \ + ADD_VALUE(L"CFG IatEntry table", PhaFormatString(L"0x%Ix", (Config)->GuardAddressTakenIatEntryTable)->Buffer); \ + ADD_VALUE(L"CFG IatEntry table entry count", PhaFormatUInt64((Config)->GuardAddressTakenIatEntryCount, TRUE)->Buffer); \ + } \ + if ((Config)->Size >= (ULONG)FIELD_OFFSET(Type, GuardLongJumpTargetTable) \ + + sizeof((Config)->GuardLongJumpTargetTable) \ + + sizeof((Config)->GuardLongJumpTargetCount))\ + { \ + ADD_VALUE(L"CFG LongJump table", PhaFormatString(L"0x%Ix", (Config)->GuardLongJumpTargetTable)->Buffer); \ + ADD_VALUE(L"CFG LongJump table entry count", PhaFormatUInt64((Config)->GuardLongJumpTargetCount, TRUE)->Buffer); \ + } \ + } \ + } + + if (PvMappedImage.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) + { + if (NT_SUCCESS(PhGetMappedImageLoadConfig32(&PvMappedImage, &config32))) + { + ADD_VALUES(IMAGE_LOAD_CONFIG_DIRECTORY32, config32); + } + } + else + { + if (NT_SUCCESS(PhGetMappedImageLoadConfig64(&PvMappedImage, &config64))) + { + ADD_VALUES(IMAGE_LOAD_CONFIG_DIRECTORY64, config64); + } + } + + EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); + } + break; + case WM_SHOWWINDOW: + { + if (!propPageContext->LayoutInitialized) + { + PPH_LAYOUT_ITEM dialogItem; + + dialogItem = PvAddPropPageLayoutItem(hwndDlg, hwndDlg, + PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL); + PvAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_LIST), + dialogItem, PH_ANCHOR_ALL); + + PvDoPropPageLayout(hwndDlg); + + propPageContext->LayoutInitialized = TRUE; + } + } + break; + case WM_NOTIFY: + { + PvHandleListViewNotifyForCopy(lParam, GetDlgItem(hwndDlg, IDC_LIST)); + } + break; + } + + return FALSE; +} + +VOID PvpLoadDbgHelpFromPath( + _In_ PWSTR DbgHelpPath + ) +{ + HMODULE dbghelpModule; + + if (dbghelpModule = LoadLibrary(DbgHelpPath)) + { + PPH_STRING fullDbghelpPath; + ULONG indexOfFileName; + PH_STRINGREF dbghelpFolder; + PPH_STRING symsrvPath; + + fullDbghelpPath = PhGetDllFileName(dbghelpModule, &indexOfFileName); + + if (fullDbghelpPath) + { + if (indexOfFileName != 0) + { + static PH_STRINGREF symsrvString = PH_STRINGREF_INIT(L"\\symsrv.dll"); + + dbghelpFolder.Buffer = fullDbghelpPath->Buffer; + dbghelpFolder.Length = indexOfFileName * sizeof(WCHAR); + + symsrvPath = PhConcatStringRef2(&dbghelpFolder, &symsrvString); + + LoadLibrary(symsrvPath->Buffer); + + PhDereferenceObject(symsrvPath); + } + + PhDereferenceObject(fullDbghelpPath); + } + } + else + { + dbghelpModule = LoadLibrary(L"dbghelp.dll"); + } + + PhSymbolProviderCompleteInitialization(dbghelpModule); +} + +BOOLEAN PvpLoadDbgHelp( + _Inout_ PPH_SYMBOL_PROVIDER *SymbolProvider + ) +{ + static UNICODE_STRING symbolPathVarName = RTL_CONSTANT_STRING(L"_NT_SYMBOL_PATH"); + PPH_STRING symbolSearchPath; + PPH_SYMBOL_PROVIDER symbolProvider; + WCHAR buffer[512] = L""; + UNICODE_STRING symbolPathUs = + { + .Buffer = buffer, + .MaximumLength = sizeof(buffer) + }; + + if (!PhSymbolProviderInitialization()) + return FALSE; + + PvpLoadDbgHelpFromPath(L"C:\\Program Files (x86)\\Windows Kits\\10\\Debuggers\\x64\\dbghelp.dll"); + symbolProvider = PhCreateSymbolProvider(NULL); + + // Load symbol path from _NT_SYMBOL_PATH if configured by the user. + if (NT_SUCCESS(RtlQueryEnvironmentVariable_U(NULL, &symbolPathVarName, &symbolPathUs))) + { + symbolSearchPath = PhFormatString(L"SRV*%s*http://msdl.microsoft.com/download/symbols", symbolPathUs.Buffer); + } + else + { + symbolSearchPath = PhCreateString(L"SRV**http://msdl.microsoft.com/download/symbols"); + } + + PhSetSearchPathSymbolProvider(symbolProvider, symbolSearchPath->Buffer); + PhDereferenceObject(symbolSearchPath); + + *SymbolProvider = symbolProvider; + return TRUE; +} + +INT_PTR CALLBACK PvpPeCgfDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + LPPROPSHEETPAGE propSheetPage; + PPV_PROPPAGECONTEXT propPageContext; + + if (!PvPropPageDlgProcHeader(hwndDlg, uMsg, lParam, &propSheetPage, &propPageContext)) + return FALSE; + + switch (uMsg) + { + case WM_INITDIALOG: + { + HWND lvHandle; + PPH_SYMBOL_PROVIDER symbolProvider = NULL; + PH_MAPPED_IMAGE_CFG cfgConfig = { 0 }; + + lvHandle = GetDlgItem(hwndDlg, IDC_LIST); + PhSetListViewStyle(lvHandle, FALSE, TRUE); + PhSetControlTheme(lvHandle, L"explorer"); + + PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT , 40, L"#"); + PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_RIGHT, 100, L"RVA"); + PhAddListViewColumn(lvHandle, 2, 2, 2, LVCFMT_LEFT , 250, L"Name"); + PhAddListViewColumn(lvHandle, 3, 3, 3, LVCFMT_LEFT , 100, L"Flags"); + PhSetExtendedListView(lvHandle); + + // Init symbol resolver + if (PvpLoadDbgHelp(&symbolProvider)) + { + // Load current PE's pdb + PhLoadModuleSymbolProvider( + symbolProvider, + PvFileName->Buffer, + (ULONG64)PvMappedImage.NtHeaders->OptionalHeader.ImageBase, + PvMappedImage.NtHeaders->OptionalHeader.SizeOfImage + ); + } + + // Retrieve Cfg Table entry and characteristics + if (NT_SUCCESS(PhGetMappedImageCfg(&cfgConfig, &PvMappedImage))) + { + for (ULONGLONG i = 0; i < cfgConfig.NumberOfGuardFunctionEntries; i++) + { + INT lvItemIndex; + ULONG64 displacement; + PPH_STRING symbol; + PPH_STRING symbolName = NULL; + PH_SYMBOL_RESOLVE_LEVEL symbolResolveLevel = PhsrlInvalid; + IMAGE_CFG_ENTRY cfgFunctionEntry = { 0 }; + + // Parse cfg entry : if it fails, just skip it ? + if (!NT_SUCCESS(PhGetMappedImageCfgEntry(&cfgConfig, i, ControlFlowGuardFunction, &cfgFunctionEntry))) + continue; + + lvItemIndex = PhAddListViewItem( + lvHandle, + MAXINT, + PhaFormatString(L"%I64u", i)->Buffer, + NULL + ); + PhSetListViewSubItem( + lvHandle, + lvItemIndex, + 1, + PhaFormatString(L"0x%08x", cfgFunctionEntry.Rva)->Buffer + ); + + // Resolve name based on public symbols + if (!(symbol = PhGetSymbolFromAddress( + symbolProvider, + (ULONG64)PTR_ADD_OFFSET(PvMappedImage.NtHeaders->OptionalHeader.ImageBase, cfgFunctionEntry.Rva), + &symbolResolveLevel, + NULL, + &symbolName, + &displacement + ))) + { + continue; + } + + switch (symbolResolveLevel) + { + case PhsrlFunction: + { + if (displacement) + { + PhSetListViewSubItem( + lvHandle, + lvItemIndex, + 2, + PhaFormatString(L"%s+0x%x", symbolName->Buffer, displacement)->Buffer + ); + } + else + { + PhSetListViewSubItem(lvHandle, lvItemIndex, 2, symbolName->Buffer); + } + } + break; + case PhsrlModule: + case PhsrlAddress: + { + PhSetListViewSubItem(lvHandle, lvItemIndex, 2, symbol->Buffer); + } + break; + default: + case PhsrlInvalid: + { + PhSetListViewSubItem(lvHandle, lvItemIndex, 2, L"(unnamed)"); + } + break; + } + + // Add additional flags + if (cfgFunctionEntry.SuppressedCall) + PhSetListViewSubItem(lvHandle, lvItemIndex, 3, L"SuppressedCall"); + else + PhSetListViewSubItem(lvHandle, lvItemIndex, 3, L""); + + if (symbolName) + PhDereferenceObject(symbolName); + PhDereferenceObject(symbol); + } + } + + ExtendedListView_SortItems(lvHandle); + EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); + } + break; + case WM_SHOWWINDOW: + { + if (!propPageContext->LayoutInitialized) + { + PPH_LAYOUT_ITEM dialogItem; + + dialogItem = PvAddPropPageLayoutItem(hwndDlg, hwndDlg, + PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL); + PvAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_LIST), + dialogItem, PH_ANCHOR_ALL); + + PvDoPropPageLayout(hwndDlg); + + propPageContext->LayoutInitialized = TRUE; + } + } + break; + case WM_NOTIFY: + { + PvHandleListViewNotifyForCopy(lParam, GetDlgItem(hwndDlg, IDC_LIST)); + } + break; + } + + return FALSE; +} + +INT_PTR CALLBACK PvpPeClrDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + LPPROPSHEETPAGE propSheetPage; + PPV_PROPPAGECONTEXT propPageContext; + + if (!PvPropPageDlgProcHeader(hwndDlg, uMsg, lParam, &propSheetPage, &propPageContext)) + return FALSE; + + switch (uMsg) + { + case WM_INITDIALOG: + { + PH_STRING_BUILDER stringBuilder; + PPH_STRING string; + PVOID metaData; + ULONG versionStringLength; + + string = PhaFormatString(L"%u.%u", PvImageCor20Header->MajorRuntimeVersion, + PvImageCor20Header->MinorRuntimeVersion); + SetDlgItemText(hwndDlg, IDC_RUNTIMEVERSION, string->Buffer); + + PhInitializeStringBuilder(&stringBuilder, 256); + + if (PvImageCor20Header->Flags & COMIMAGE_FLAGS_ILONLY) + PhAppendStringBuilder2(&stringBuilder, L"IL only, "); + if (PvImageCor20Header->Flags & COMIMAGE_FLAGS_32BITREQUIRED) + PhAppendStringBuilder2(&stringBuilder, L"32-bit only, "); + if (PvImageCor20Header->Flags & COMIMAGE_FLAGS_32BITPREFERRED) + PhAppendStringBuilder2(&stringBuilder, L"32-bit preferred, "); + if (PvImageCor20Header->Flags & COMIMAGE_FLAGS_IL_LIBRARY) + PhAppendStringBuilder2(&stringBuilder, L"IL library, "); + + if (PvImageCor20Header->StrongNameSignature.VirtualAddress != 0 && PvImageCor20Header->StrongNameSignature.Size != 0) + { + if (PvImageCor20Header->Flags & COMIMAGE_FLAGS_STRONGNAMESIGNED) + PhAppendStringBuilder2(&stringBuilder, L"Strong-name signed, "); + else + PhAppendStringBuilder2(&stringBuilder, L"Strong-name delay signed, "); + } + + if (PvImageCor20Header->Flags & COMIMAGE_FLAGS_NATIVE_ENTRYPOINT) + PhAppendStringBuilder2(&stringBuilder, L"Native entry-point, "); + if (PvImageCor20Header->Flags & COMIMAGE_FLAGS_TRACKDEBUGDATA) + PhAppendStringBuilder2(&stringBuilder, L"Track debug data, "); + + if (PhEndsWithString2(stringBuilder.String, L", ", FALSE)) + PhRemoveEndStringBuilder(&stringBuilder, 2); + + SetDlgItemText(hwndDlg, IDC_FLAGS, stringBuilder.String->Buffer); + PhDeleteStringBuilder(&stringBuilder); + + metaData = PhMappedImageRvaToVa(&PvMappedImage, PvImageCor20Header->MetaData.VirtualAddress, NULL); + + if (metaData) + { + __try + { + PhProbeAddress(metaData, PvImageCor20Header->MetaData.Size, PvMappedImage.ViewBase, PvMappedImage.Size, 4); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + metaData = NULL; + } + } + + versionStringLength = 0; + + if (metaData) + { + // Skip 12 bytes. + // First 4 bytes contains the length of the version string. + // The version string follows. + versionStringLength = *(PULONG)((PCHAR)metaData + 12); + + // Make sure the length is valid. + if (versionStringLength >= 0x100) + versionStringLength = 0; + } + + if (versionStringLength != 0) + { + string = PhZeroExtendToUtf16Ex((PCHAR)metaData + 12 + 4, versionStringLength); + SetDlgItemText(hwndDlg, IDC_VERSIONSTRING, string->Buffer); + PhDereferenceObject(string); + } + else + { + SetDlgItemText(hwndDlg, IDC_VERSIONSTRING, L"N/A"); + } + } + break; + case WM_SHOWWINDOW: + { + if (!propPageContext->LayoutInitialized) + { + PvAddPropPageLayoutItem(hwndDlg, hwndDlg, + PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL); + + PvDoPropPageLayout(hwndDlg); + + propPageContext->LayoutInitialized = TRUE; + } + } + break; + case WM_NOTIFY: + { + LPNMHDR header = (LPNMHDR)lParam; + + switch (header->code) + { + case PSN_QUERYINITIALFOCUS: + { + SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, (LONG_PTR)GetDlgItem(hwndDlg, IDC_RUNTIMEVERSION)); + } + return TRUE; + } + } + break; + } + + return FALSE; +} diff --git a/tools/peview/peview.manifest b/tools/peview/peview.manifest index a40beb0cc0b2..ba407fa53b04 100644 --- a/tools/peview/peview.manifest +++ b/tools/peview/peview.manifest @@ -1,46 +1,46 @@ - - - - PE Viewer - - - - - - - - - - - - - - - - - - - - - - - - true - - - true - - + + + + PE Viewer + + + + + + + + + + + + + + + + + + + + + + + + true + + + true + + \ No newline at end of file diff --git a/tools/peview/peview.rc b/tools/peview/peview.rc index 28530525caa9..d8c1288b8a65 100644 --- a/tools/peview/peview.rc +++ b/tools/peview/peview.rc @@ -1,240 +1,240 @@ -// Microsoft Visual C++ generated resource script. -// -#include "resource.h" - -#define APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// -#include "winres.h" -#include "../../ProcessHacker/include/phappres.h" -///////////////////////////////////////////////////////////////////////////// -#undef APSTUDIO_READONLY_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -// English (Australia) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENA) -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_AUS -#pragma code_page(1252) - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -1 TEXTINCLUDE -BEGIN - "resource.h\0" -END - -2 TEXTINCLUDE -BEGIN - "#include ""winres.h""\r\n" - "#include ""../../ProcessHacker/include/phappres.h""\0" -END - -3 TEXTINCLUDE -BEGIN - "\r\n" - "\0" -END - -#endif // APSTUDIO_INVOKED - - -///////////////////////////////////////////////////////////////////////////// -// -// DESIGNINFO -// - -#ifdef APSTUDIO_INVOKED -GUIDELINES DESIGNINFO -BEGIN - IDD_PEGENERAL, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 293 - TOPMARGIN, 7 - BOTTOMMARGIN, 273 - END - - IDD_PEIMPORTS, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 293 - TOPMARGIN, 7 - BOTTOMMARGIN, 273 - END - - IDD_PEEXPORTS, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 293 - TOPMARGIN, 7 - BOTTOMMARGIN, 273 - END - - IDD_LIBEXPORTS, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 293 - TOPMARGIN, 7 - BOTTOMMARGIN, 273 - END - - IDD_PECLR, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 293 - TOPMARGIN, 7 - BOTTOMMARGIN, 273 - END - - IDD_PELOADCONFIG, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 293 - TOPMARGIN, 7 - BOTTOMMARGIN, 273 - END - - IDD_PECFG, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 292 - TOPMARGIN, 7 - BOTTOMMARGIN, 273 - END -END -#endif // APSTUDIO_INVOKED - - -///////////////////////////////////////////////////////////////////////////// -// -// Dialog -// - -IDD_PEGENERAL DIALOGEX 0, 0, 300, 280 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "General" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "Target machine:",IDC_STATIC,7,57,53,8 - LTEXT "Static",IDC_TARGETMACHINE,78,57,215,8 - LTEXT "Checksum:",IDC_STATIC,7,100,36,8 - LTEXT "Static",IDC_CHECKSUM,78,100,215,8 - LTEXT "Subsystem:",IDC_STATIC,7,111,38,8 - LTEXT "Subsystem version:",IDC_STATIC,7,122,64,8 - LTEXT "Characteristics:",IDC_STATIC,7,133,51,8 - LTEXT "Static",IDC_SUBSYSTEM,78,111,215,8 - LTEXT "Static",IDC_SUBSYSTEMVERSION,78,122,215,8 - CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,156,286,116 - LTEXT "Sections:",IDC_STATIC,7,146,30,8 - EDITTEXT IDC_CHARACTERISTICS,76,133,217,23,ES_MULTILINE | ES_READONLY | NOT WS_BORDER - LTEXT "Time stamp:",IDC_STATIC,7,68,40,8 - LTEXT "Static",IDC_TIMESTAMP,78,68,215,8 - LTEXT "Entry point:",IDC_STATIC,7,90,39,8 - LTEXT "Static",IDC_ENTRYPOINT,78,90,215,8 - LTEXT "Image base:",IDC_STATIC,7,79,41,8 - LTEXT "Static",IDC_IMAGEBASE,78,79,215,8 - ICON "",IDC_FILEICON,14,18,20,20 - GROUPBOX "File",IDC_FILE,7,7,286,48 - EDITTEXT IDC_NAME,44,17,242,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER - EDITTEXT IDC_COMPANYNAME,44,29,242,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER - LTEXT "Version:",IDC_STATIC,15,41,27,8 - EDITTEXT IDC_VERSION,44,41,242,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER - CONTROL "Company Name Link",IDC_COMPANYNAME_LINK,"SysLink",LWS_NOPREFIX | NOT WS_VISIBLE | WS_TABSTOP,46,29,240,9 -END - -IDD_PEIMPORTS DIALOGEX 0, 0, 300, 280 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Imports" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,7,286,266 -END - -IDD_PEEXPORTS DIALOGEX 0, 0, 300, 280 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Exports" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,7,286,266 -END - -IDD_LIBEXPORTS DIALOGEX 0, 0, 300, 280 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Exports" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,6,6,287,267 -END - -IDD_PECLR DIALOGEX 0, 0, 300, 280 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "CLR" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "Runtime Version:",IDC_STATIC,7,7,55,8 - LTEXT "Static",IDC_RUNTIMEVERSION,78,7,215,8 - LTEXT "Flags:",IDC_STATIC,7,19,20,8 - EDITTEXT IDC_FLAGS,76,19,217,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER - LTEXT "Version String:",IDC_STATIC,7,31,48,8 - LTEXT "Static",IDC_VERSIONSTRING,78,31,215,8 -END - -IDD_PELOADCONFIG DIALOGEX 0, 0, 300, 280 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Load config" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,7,286,266 -END - -IDD_PECFG DIALOGEX 0, 0, 299, 280 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "CFG" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,7,286,266 -END - - -///////////////////////////////////////////////////////////////////////////// -// -// AFX_DIALOG_LAYOUT -// - -IDD_PELOADCONFIG AFX_DIALOG_LAYOUT -BEGIN - 0 -END - -IDD_PEGENERAL AFX_DIALOG_LAYOUT -BEGIN - 0 -END - -IDD_PECFG AFX_DIALOG_LAYOUT -BEGIN - 0 -END - -#endif // English (Australia) resources -///////////////////////////////////////////////////////////////////////////// - - - -#ifndef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// - - -///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED - +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "winres.h" +#include "../../ProcessHacker/include/phappres.h" +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (Australia) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENA) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_AUS +#pragma code_page(1252) + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""winres.h""\r\n" + "#include ""../../ProcessHacker/include/phappres.h""\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_PEGENERAL, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 293 + TOPMARGIN, 7 + BOTTOMMARGIN, 273 + END + + IDD_PEIMPORTS, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 293 + TOPMARGIN, 7 + BOTTOMMARGIN, 273 + END + + IDD_PEEXPORTS, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 293 + TOPMARGIN, 7 + BOTTOMMARGIN, 273 + END + + IDD_LIBEXPORTS, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 293 + TOPMARGIN, 7 + BOTTOMMARGIN, 273 + END + + IDD_PECLR, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 293 + TOPMARGIN, 7 + BOTTOMMARGIN, 273 + END + + IDD_PELOADCONFIG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 293 + TOPMARGIN, 7 + BOTTOMMARGIN, 273 + END + + IDD_PECFG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 292 + TOPMARGIN, 7 + BOTTOMMARGIN, 273 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_PEGENERAL DIALOGEX 0, 0, 300, 280 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "General" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "Target machine:",IDC_STATIC,7,57,53,8 + LTEXT "Static",IDC_TARGETMACHINE,78,57,215,8 + LTEXT "Checksum:",IDC_STATIC,7,100,36,8 + LTEXT "Static",IDC_CHECKSUM,78,100,215,8 + LTEXT "Subsystem:",IDC_STATIC,7,111,38,8 + LTEXT "Subsystem version:",IDC_STATIC,7,122,64,8 + LTEXT "Characteristics:",IDC_STATIC,7,133,51,8 + LTEXT "Static",IDC_SUBSYSTEM,78,111,215,8 + LTEXT "Static",IDC_SUBSYSTEMVERSION,78,122,215,8 + CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,156,286,116 + LTEXT "Sections:",IDC_STATIC,7,146,30,8 + EDITTEXT IDC_CHARACTERISTICS,76,133,217,23,ES_MULTILINE | ES_READONLY | NOT WS_BORDER + LTEXT "Time stamp:",IDC_STATIC,7,68,40,8 + LTEXT "Static",IDC_TIMESTAMP,78,68,215,8 + LTEXT "Entry point:",IDC_STATIC,7,90,39,8 + LTEXT "Static",IDC_ENTRYPOINT,78,90,215,8 + LTEXT "Image base:",IDC_STATIC,7,79,41,8 + LTEXT "Static",IDC_IMAGEBASE,78,79,215,8 + ICON "",IDC_FILEICON,14,18,20,20 + GROUPBOX "File",IDC_FILE,7,7,286,48 + EDITTEXT IDC_NAME,44,17,242,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + EDITTEXT IDC_COMPANYNAME,44,29,242,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + LTEXT "Version:",IDC_STATIC,15,41,27,8 + EDITTEXT IDC_VERSION,44,41,242,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + CONTROL "Company Name Link",IDC_COMPANYNAME_LINK,"SysLink",LWS_NOPREFIX | NOT WS_VISIBLE | WS_TABSTOP,46,29,240,9 +END + +IDD_PEIMPORTS DIALOGEX 0, 0, 300, 280 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Imports" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,7,286,266 +END + +IDD_PEEXPORTS DIALOGEX 0, 0, 300, 280 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Exports" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,7,286,266 +END + +IDD_LIBEXPORTS DIALOGEX 0, 0, 300, 280 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Exports" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,6,6,287,267 +END + +IDD_PECLR DIALOGEX 0, 0, 300, 280 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "CLR" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "Runtime Version:",IDC_STATIC,7,7,55,8 + LTEXT "Static",IDC_RUNTIMEVERSION,78,7,215,8 + LTEXT "Flags:",IDC_STATIC,7,19,20,8 + EDITTEXT IDC_FLAGS,76,19,217,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + LTEXT "Version String:",IDC_STATIC,7,31,48,8 + LTEXT "Static",IDC_VERSIONSTRING,78,31,215,8 +END + +IDD_PELOADCONFIG DIALOGEX 0, 0, 300, 280 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Load config" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,7,286,266 +END + +IDD_PECFG DIALOGEX 0, 0, 299, 280 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "CFG" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,7,286,266 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// AFX_DIALOG_LAYOUT +// + +IDD_PELOADCONFIG AFX_DIALOG_LAYOUT +BEGIN + 0 +END + +IDD_PEGENERAL AFX_DIALOG_LAYOUT +BEGIN + 0 +END + +IDD_PECFG AFX_DIALOG_LAYOUT +BEGIN + 0 +END + +#endif // English (Australia) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/tools/peview/peview.vcxproj b/tools/peview/peview.vcxproj index d9119eb82275..29c125003e18 100644 --- a/tools/peview/peview.vcxproj +++ b/tools/peview/peview.vcxproj @@ -1,221 +1,221 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {72C124A2-3C80-41C6-ABA1-C4948B713204} - peview - Win32Proj - 10.0.15063.0 - - - - Application - Unicode - true - v141 - - - Application - Unicode - v141 - - - Application - Unicode - true - v141 - - - Application - Unicode - v141 - - - - - - - - - - - - - - - - - - - $(SolutionDir)bin\$(Configuration)$(PlatformArchitecture)\ - $(ProjectDir)obj\$(Configuration)$(PlatformArchitecture)\ - false - $(SolutionDir)bin\$(Configuration)$(PlatformArchitecture)\ - $(ProjectDir)obj\$(Configuration)$(PlatformArchitecture)\ - false - $(SolutionDir)bin\$(Configuration)$(PlatformArchitecture)\ - $(ProjectDir)obj\$(Configuration)$(PlatformArchitecture)\ - false - $(SolutionDir)bin\$(Configuration)$(PlatformArchitecture)\ - $(ProjectDir)obj\$(Configuration)$(PlatformArchitecture)\ - false - - - - - - - - Disabled - ..\..\phnt\include;..\..\phlib\include;include;%(AdditionalIncludeDirectories) - _PHLIB_;_WINDOWS;WIN32;DEBUG;%(PreprocessorDefinitions) - EnableFastChecks - MultiThreadedDebug - Level3 - ProgramDatabase - StdCall - true - true - true - - - noarg.obj;noenv.obj;phlib.lib;ntdll.lib;uxtheme.lib;%(AdditionalDependencies) - ..\..\phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) - - - true - Windows - MachineX86 - 6.01 - - - - - Disabled - ..\..\phnt\include;..\..\phlib\include;include;%(AdditionalIncludeDirectories) - _PHLIB_;_WINDOWS;WIN64;DEBUG;%(PreprocessorDefinitions) - EnableFastChecks - MultiThreadedDebug - Level3 - ProgramDatabase - StdCall - true - true - true - - - noarg.obj;noenv.obj;phlib.lib;ntdll.lib;uxtheme.lib;%(AdditionalDependencies) - ..\..\phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) - - - true - Windows - MachineX64 - 6.01 - - - - - MaxSpeed - true - ..\..\phnt\include;..\..\phlib\include;include;%(AdditionalIncludeDirectories) - _PHLIB_;_WINDOWS;WIN32;NDEBUG;%(PreprocessorDefinitions) - MultiThreaded - true - Level3 - ProgramDatabase - StdCall - true - StreamingSIMDExtensions - true - true - - - noarg.obj;noenv.obj;phlib.lib;ntdll.lib;uxtheme.lib;%(AdditionalDependencies) - ..\..\phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) - - - true - Windows - true - true - MachineX86 - true - 6.01 - - - - - MaxSpeed - true - ..\..\phnt\include;..\..\phlib\include;include;%(AdditionalIncludeDirectories) - _PHLIB_;_WINDOWS;WIN64;DEBUG;%(PreprocessorDefinitions) - MultiThreaded - true - Level3 - ProgramDatabase - StdCall - true - true - true - - - noarg.obj;noenv.obj;phlib.lib;ntdll.lib;uxtheme.lib;%(AdditionalDependencies) - ..\..\phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) - - - true - Windows - true - true - MachineX64 - true - 6.01 - - - - - - - - - - - - - - - - - - - - - {477d0215-f252-41a1-874b-f27e3ea1ed17} - false - - - - - - - - + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {72C124A2-3C80-41C6-ABA1-C4948B713204} + peview + Win32Proj + 10.0.15063.0 + + + + Application + Unicode + true + v141 + + + Application + Unicode + v141 + + + Application + Unicode + true + v141 + + + Application + Unicode + v141 + + + + + + + + + + + + + + + + + + + $(SolutionDir)bin\$(Configuration)$(PlatformArchitecture)\ + $(ProjectDir)obj\$(Configuration)$(PlatformArchitecture)\ + false + $(SolutionDir)bin\$(Configuration)$(PlatformArchitecture)\ + $(ProjectDir)obj\$(Configuration)$(PlatformArchitecture)\ + false + $(SolutionDir)bin\$(Configuration)$(PlatformArchitecture)\ + $(ProjectDir)obj\$(Configuration)$(PlatformArchitecture)\ + false + $(SolutionDir)bin\$(Configuration)$(PlatformArchitecture)\ + $(ProjectDir)obj\$(Configuration)$(PlatformArchitecture)\ + false + + + + + + + + Disabled + ..\..\phnt\include;..\..\phlib\include;include;%(AdditionalIncludeDirectories) + _PHLIB_;_WINDOWS;WIN32;DEBUG;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + Level3 + ProgramDatabase + StdCall + true + true + true + + + noarg.obj;noenv.obj;phlib.lib;ntdll.lib;uxtheme.lib;%(AdditionalDependencies) + ..\..\phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) + + + true + Windows + MachineX86 + 6.01 + + + + + Disabled + ..\..\phnt\include;..\..\phlib\include;include;%(AdditionalIncludeDirectories) + _PHLIB_;_WINDOWS;WIN64;DEBUG;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + Level3 + ProgramDatabase + StdCall + true + true + true + + + noarg.obj;noenv.obj;phlib.lib;ntdll.lib;uxtheme.lib;%(AdditionalDependencies) + ..\..\phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) + + + true + Windows + MachineX64 + 6.01 + + + + + MaxSpeed + true + ..\..\phnt\include;..\..\phlib\include;include;%(AdditionalIncludeDirectories) + _PHLIB_;_WINDOWS;WIN32;NDEBUG;%(PreprocessorDefinitions) + MultiThreaded + true + Level3 + ProgramDatabase + StdCall + true + StreamingSIMDExtensions + true + true + + + noarg.obj;noenv.obj;phlib.lib;ntdll.lib;uxtheme.lib;%(AdditionalDependencies) + ..\..\phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) + + + true + Windows + true + true + MachineX86 + true + 6.01 + + + + + MaxSpeed + true + ..\..\phnt\include;..\..\phlib\include;include;%(AdditionalIncludeDirectories) + _PHLIB_;_WINDOWS;WIN64;DEBUG;%(PreprocessorDefinitions) + MultiThreaded + true + Level3 + ProgramDatabase + StdCall + true + true + true + + + noarg.obj;noenv.obj;phlib.lib;ntdll.lib;uxtheme.lib;%(AdditionalDependencies) + ..\..\phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) + + + true + Windows + true + true + MachineX64 + true + 6.01 + + + + + + + + + + + + + + + + + + + + + {477d0215-f252-41a1-874b-f27e3ea1ed17} + false + + + + + + + + \ No newline at end of file diff --git a/tools/peview/resource.h b/tools/peview/resource.h index b300f449de11..aa0350eaa2d3 100644 --- a/tools/peview/resource.h +++ b/tools/peview/resource.h @@ -1,40 +1,40 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by peview.rc -// -#define IDD_PEGENERAL 102 -#define IDD_PEIMPORTS 103 -#define IDD_PEEXPORTS 104 -#define IDD_LIBEXPORTS 105 -#define IDD_PECLR 106 -#define IDD_PELOADCONFIG 107 -#define IDD_PECFG 108 -#define IDC_TARGETMACHINE 1003 -#define IDC_CHECKSUM 1004 -#define IDC_SUBSYSTEM 1005 -#define IDC_SUBSYSTEMVERSION 1006 -#define IDC_CHARACTERISTICS 1007 -#define IDC_LIST 1008 -#define IDC_FILEICON 1009 -#define IDC_TIMESTAMP 1010 -#define IDC_RUNTIMEVERSION 1011 -#define IDC_FILE 1011 -#define IDC_FLAGS 1012 -#define IDC_COMPANYNAME 1012 -#define IDC_VERSION 1013 -#define IDC_VERSIONSTRING 1014 -#define IDC_IMAGEBASE 1015 -#define IDC_ENTRYPOINT 1016 -#define IDC_NAME 1044 -#define IDC_COMPANYNAME_LINK 1279 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 110 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1017 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by peview.rc +// +#define IDD_PEGENERAL 102 +#define IDD_PEIMPORTS 103 +#define IDD_PEEXPORTS 104 +#define IDD_LIBEXPORTS 105 +#define IDD_PECLR 106 +#define IDD_PELOADCONFIG 107 +#define IDD_PECFG 108 +#define IDC_TARGETMACHINE 1003 +#define IDC_CHECKSUM 1004 +#define IDC_SUBSYSTEM 1005 +#define IDC_SUBSYSTEMVERSION 1006 +#define IDC_CHARACTERISTICS 1007 +#define IDC_LIST 1008 +#define IDC_FILEICON 1009 +#define IDC_TIMESTAMP 1010 +#define IDC_RUNTIMEVERSION 1011 +#define IDC_FILE 1011 +#define IDC_FLAGS 1012 +#define IDC_COMPANYNAME 1012 +#define IDC_VERSION 1013 +#define IDC_VERSIONSTRING 1014 +#define IDC_IMAGEBASE 1015 +#define IDC_ENTRYPOINT 1016 +#define IDC_NAME 1044 +#define IDC_COMPANYNAME_LINK 1279 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 110 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1017 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/tools/peview/version.rc b/tools/peview/version.rc index 3e12095c909a..1e412bb16d5e 100644 --- a/tools/peview/version.rc +++ b/tools/peview/version.rc @@ -1,35 +1,35 @@ -#include "winres.h" -#include "../../ProcessHacker/include/phappres.h" - -VS_VERSION_INFO VERSIONINFO - FILEVERSION PHAPP_VERSION_NUMBER - PRODUCTVERSION PHAPP_VERSION_NUMBER - FILEFLAGSMASK 0x17L -#ifdef _DEBUG - FILEFLAGS 0x1L -#else - FILEFLAGS 0x0L -#endif - FILEOS 0x4L - FILETYPE 0x1L - FILESUBTYPE 0x0L -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "0c0904b0" - BEGIN - VALUE "CompanyName", "wj32" - VALUE "FileDescription", "PE Viewer" - VALUE "FileVersion", PHAPP_VERSION_STRING - VALUE "InternalName", "peview" - VALUE "LegalCopyright", "Licensed under the GNU GPL, v3." - VALUE "OriginalFilename", "peview.exe" - VALUE "ProductName", "Process Hacker" - VALUE "ProductVersion", PHAPP_VERSION_STRING - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0xc09, 1200 - END -END +#include "winres.h" +#include "../../ProcessHacker/include/phappres.h" + +VS_VERSION_INFO VERSIONINFO + FILEVERSION PHAPP_VERSION_NUMBER + PRODUCTVERSION PHAPP_VERSION_NUMBER + FILEFLAGSMASK 0x17L +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "0c0904b0" + BEGIN + VALUE "CompanyName", "wj32" + VALUE "FileDescription", "PE Viewer" + VALUE "FileVersion", PHAPP_VERSION_STRING + VALUE "InternalName", "peview" + VALUE "LegalCopyright", "Licensed under the GNU GPL, v3." + VALUE "OriginalFilename", "peview.exe" + VALUE "ProductName", "Process Hacker" + VALUE "ProductVersion", PHAPP_VERSION_STRING + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0xc09, 1200 + END +END From 648b0ffe466513ea8d96a5c267e32ddb3af9f9e0 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 27 Apr 2017 19:30:01 +1000 Subject: [PATCH 0023/2058] Update git attributes --- .gitattributes | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitattributes b/.gitattributes index b895d0391026..961777c2611a 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,5 +1,5 @@ # Auto detect text files -* text=crlf +* text=auto # Custom for Visual Studio *.cs diff=csharp @@ -16,6 +16,7 @@ *.cmd eol=crlf *.csproj eol=crlf *.h eol=crlf +*.md eol=crlf *.manifest eol=crlf *.rc eol=crlf *.sln eol=crlf From 0c8667c4076b88ceca2ae8d62f30700c6a440a03 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 27 Apr 2017 22:43:02 +1000 Subject: [PATCH 0024/2058] CustomBuildTool: Add debug build support, Fix build_debug.cmd script --- build/build_binaries.cmd | 3 +- build/build_debug.cmd | 2 +- build/build_release.cmd | 16 +- build/build_sdk.cmd | 2 +- build/build_sdk_rebuild.cmd | 2 +- tools/CustomBuildTool/CustomBuildTool.csproj | 2 - tools/CustomBuildTool/Source Files/Build.cs | 187 ++++++++++++------ tools/CustomBuildTool/Source Files/Program.cs | 150 +++++++++----- .../bin/Release/CustomBuildTool.exe | Bin 143360 -> 145920 bytes .../bin/Release/CustomBuildTool.pdb | Bin 62976 -> 62976 bytes 10 files changed, 235 insertions(+), 129 deletions(-) diff --git a/build/build_binaries.cmd b/build/build_binaries.cmd index 8c42e4bbe1b1..2d17641e43e2 100644 --- a/build/build_binaries.cmd +++ b/build/build_binaries.cmd @@ -1,5 +1,6 @@ @echo off -..\tools\CustomBuildTool\bin\Release\CustomBuildTool.exe -bin +start /B /W "" "..\tools\CustomBuildTool\bin\Release\CustomBuildTool.exe" "-bin" +start /B /W "" "..\tools\CustomBuildTool\bin\Release\CustomBuildTool.exe" "-exe" pause diff --git a/build/build_debug.cmd b/build/build_debug.cmd index 7f3fbb6d6035..7a06cbedd774 100644 --- a/build/build_debug.cmd +++ b/build/build_debug.cmd @@ -1,5 +1,5 @@ @echo off -..\tools\CustomBuildTool\bin\Release\CustomBuildTool.exe -debug +start /B /W "" "..\tools\CustomBuildTool\bin\Release\CustomBuildTool.exe" "-debug" pause diff --git a/build/build_release.cmd b/build/build_release.cmd index 15e528690fb6..c0a55c13da5d 100644 --- a/build/build_release.cmd +++ b/build/build_release.cmd @@ -1,17 +1,5 @@ @echo off - set /p APPVEYOR_BUILD_KEY="APPVEYOR_BUILD_KEY: " - set /p APPVEYOR_BUILD_API="APPVEYOR_BUILD_API: " - set /p VIRUSTOTAL_BUILD_KEY="VIRUSTOTAL_BUILD_KEY: " - set /p KPH_BUILD_KEY="KPH_BUILD_KEY: " - set /p NIGHTLY_BUILD_KEY="NIGHTLY_BUILD_KEY: " - - set APPVEYOR_BUILD_KEY=%APPVEYOR_BUILD_KEY% - set APPVEYOR_BUILD_API=%APPVEYOR_BUILD_API% - set VIRUSTOTAL_BUILD_KEY=%VIRUSTOTAL_BUILD_KEY% - set KPH_BUILD_KEY=%KPH_BUILD_KEY% - set NIGHTLY_BUILD_KEY=%NIGHTLY_BUILD_KEY% +start /B /W "" "..\tools\CustomBuildTool\bin\Release\CustomBuildTool.exe" "-release" -..\tools\CustomBuildTool\bin\Release\CustomBuildTool.exe -release - -pause +pause \ No newline at end of file diff --git a/build/build_sdk.cmd b/build/build_sdk.cmd index 11e16deb7d05..0bed04835688 100644 --- a/build/build_sdk.cmd +++ b/build/build_sdk.cmd @@ -1,3 +1,3 @@ @echo off -..\tools\CustomBuildTool\bin\Release\CustomBuildTool.exe -sdk \ No newline at end of file +start /B /W "" "..\tools\CustomBuildTool\bin\Release\CustomBuildTool.exe" "-sdk" \ No newline at end of file diff --git a/build/build_sdk_rebuild.cmd b/build/build_sdk_rebuild.cmd index bc9493c504d5..57ead1eee13e 100644 --- a/build/build_sdk_rebuild.cmd +++ b/build/build_sdk_rebuild.cmd @@ -1,5 +1,5 @@ @echo off -..\tools\CustomBuildTool\bin\Release\CustomBuildTool.exe -cleansdk +start /B /W "" "..\tools\CustomBuildTool\bin\Release\CustomBuildTool.exe" "-cleansdk" pause diff --git a/tools/CustomBuildTool/CustomBuildTool.csproj b/tools/CustomBuildTool/CustomBuildTool.csproj index 08d1323194e2..b981e8ec1f99 100644 --- a/tools/CustomBuildTool/CustomBuildTool.csproj +++ b/tools/CustomBuildTool/CustomBuildTool.csproj @@ -89,11 +89,9 @@ - Designer - diff --git a/tools/CustomBuildTool/Source Files/Build.cs b/tools/CustomBuildTool/Source Files/Build.cs index 6819e256a7bf..00a9b2533dbb 100644 --- a/tools/CustomBuildTool/Source Files/Build.cs +++ b/tools/CustomBuildTool/Source Files/Build.cs @@ -273,12 +273,20 @@ public static bool CopyTextFiles() return true; } - public static bool CopyKProcessHacker() + public static bool CopyKProcessHacker(bool DebugBuild) { try { - File.Copy("KProcessHacker\\bin-signed\\i386\\kprocesshacker.sys", "bin\\Release32\\kprocesshacker.sys", true); - File.Copy("KProcessHacker\\bin-signed\\amd64\\kprocesshacker.sys", "bin\\Release64\\kprocesshacker.sys", true); + if (DebugBuild) + { + File.Copy("KProcessHacker\\bin-signed\\i386\\kprocesshacker.sys", "bin\\Debug32\\kprocesshacker.sys", true); + File.Copy("KProcessHacker\\bin-signed\\amd64\\kprocesshacker.sys", "bin\\Debug64\\kprocesshacker.sys", true); + } + else + { + File.Copy("KProcessHacker\\bin-signed\\i386\\kprocesshacker.sys", "bin\\Release32\\kprocesshacker.sys", true); + File.Copy("KProcessHacker\\bin-signed\\amd64\\kprocesshacker.sys", "bin\\Release64\\kprocesshacker.sys", true); + } } catch (Exception ex) { @@ -289,12 +297,20 @@ public static bool CopyKProcessHacker() return true; } - public static bool CopyLibFiles() + public static bool CopyLibFiles(bool DebugBuild) { try { - File.Copy("bin\\Release32\\ProcessHacker.lib", "sdk\\lib\\i386\\ProcessHacker.lib", true); - File.Copy("bin\\Release64\\ProcessHacker.lib", "sdk\\lib\\amd64\\ProcessHacker.lib", true); + if (DebugBuild) + { + File.Copy("bin\\Debug32\\ProcessHacker.lib", "sdk\\lib\\i386\\ProcessHacker.lib", true); + File.Copy("bin\\Debug64\\ProcessHacker.lib", "sdk\\lib\\amd64\\ProcessHacker.lib", true); + } + else + { + File.Copy("bin\\Release32\\ProcessHacker.lib", "sdk\\lib\\i386\\ProcessHacker.lib", true); + File.Copy("bin\\Release64\\ProcessHacker.lib", "sdk\\lib\\amd64\\ProcessHacker.lib", true); + } } catch (Exception ex) { @@ -305,20 +321,34 @@ public static bool CopyLibFiles() return true; } - public static bool CopyWow64Files() + public static bool CopyWow64Files(bool DebugBuild) { try { - if (!Directory.Exists("bin\\Release64\\x86")) - Directory.CreateDirectory("bin\\Release64\\x86"); - - if (!Directory.Exists("bin\\Release64\\x86\\plugins")) - Directory.CreateDirectory("bin\\Release64\\x86\\plugins"); - - File.Copy("bin\\Release32\\ProcessHacker.exe", "bin\\Release64\\x86\\ProcessHacker.exe", true); - File.Copy("bin\\Release32\\ProcessHacker.pdb", "bin\\Release64\\x86\\ProcessHacker.pdb", true); - File.Copy("bin\\Release32\\plugins\\DotNetTools.dll", "bin\\Release64\\x86\\plugins\\DotNetTools.dll", true); - File.Copy("bin\\Release32\\plugins\\DotNetTools.pdb", "bin\\Release64\\x86\\plugins\\DotNetTools.pdb", true); + if (DebugBuild) + { + if (!Directory.Exists("bin\\Debug64\\x86")) + Directory.CreateDirectory("bin\\Debug64\\x86"); + if (!Directory.Exists("bin\\Debug64\\x86\\plugins")) + Directory.CreateDirectory("bin\\Debug64\\x86\\plugins"); + + File.Copy("bin\\Debug32\\ProcessHacker.exe", "bin\\Debug64\\x86\\ProcessHacker.exe", true); + File.Copy("bin\\Debug32\\ProcessHacker.pdb", "bin\\Debug64\\x86\\ProcessHacker.pdb", true); + File.Copy("bin\\Debug32\\plugins\\DotNetTools.dll", "bin\\Debug64\\x86\\plugins\\DotNetTools.dll", true); + File.Copy("bin\\Debug32\\plugins\\DotNetTools.pdb", "bin\\Debug64\\x86\\plugins\\DotNetTools.pdb", true); + } + else + { + if (!Directory.Exists("bin\\Release64\\x86")) + Directory.CreateDirectory("bin\\Release64\\x86"); + if (!Directory.Exists("bin\\Release64\\x86\\plugins")) + Directory.CreateDirectory("bin\\Release64\\x86\\plugins"); + + File.Copy("bin\\Release32\\ProcessHacker.exe", "bin\\Release64\\x86\\ProcessHacker.exe", true); + File.Copy("bin\\Release32\\ProcessHacker.pdb", "bin\\Release64\\x86\\ProcessHacker.pdb", true); + File.Copy("bin\\Release32\\plugins\\DotNetTools.dll", "bin\\Release64\\x86\\plugins\\DotNetTools.dll", true); + File.Copy("bin\\Release32\\plugins\\DotNetTools.pdb", "bin\\Release64\\x86\\plugins\\DotNetTools.pdb", true); + } } catch (Exception ex) { @@ -412,7 +442,7 @@ public static bool FixupResourceHeader() return true; } - public static bool BuildKphSignatureFile() + public static bool BuildKphSignatureFile(bool DebugBuild) { string output; @@ -428,50 +458,73 @@ public static bool BuildKphSignatureFile() return true; } - if (!File.Exists("bin\\Release32\\ProcessHacker.exe")) + if (DebugBuild) { - Program.PrintColorMessage("[SKIPPED] Release32\\ProcessHacker.exe not found.", ConsoleColor.Yellow); - return true; - } + if (!File.Exists("bin\\Debug32\\ProcessHacker.exe")) + { + Program.PrintColorMessage("[SKIPPED] Debug32\\ProcessHacker.exe not found.", ConsoleColor.Yellow); + return true; + } - if (!File.Exists("bin\\Release64\\ProcessHacker.exe")) - { - Program.PrintColorMessage("[SKIPPED] Release64\\ProcessHacker.exe not found.", ConsoleColor.Yellow); - return true; - } + if (!File.Exists("bin\\Debug64\\ProcessHacker.exe")) + { + Program.PrintColorMessage("[SKIPPED] Debug64\\ProcessHacker.exe not found.", ConsoleColor.Yellow); + return true; + } - if (File.Exists("bin\\Debug32\\ProcessHacker.sig")) - File.Delete("bin\\Debug32\\ProcessHacker.sig"); - if (File.Exists("bin\\Debug64\\ProcessHacker.sig")) - File.Delete("bin\\Debug64\\ProcessHacker.sig"); - if (File.Exists("bin\\Release32\\ProcessHacker.sig")) - File.Delete("bin\\Release32\\ProcessHacker.sig"); - if (File.Exists("bin\\Release64\\ProcessHacker.sig")) - File.Delete("bin\\Release64\\ProcessHacker.sig"); + if (File.Exists("bin\\Debug32\\ProcessHacker.sig")) + File.Delete("bin\\Debug32\\ProcessHacker.sig"); + if (File.Exists("bin\\Debug64\\ProcessHacker.sig")) + File.Delete("bin\\Debug64\\ProcessHacker.sig"); - File.Create("bin\\Release32\\ProcessHacker.sig").Dispose(); - File.Create("bin\\Release64\\ProcessHacker.sig").Dispose(); + File.Create("bin\\Debug32\\ProcessHacker.sig").Dispose(); + File.Create("bin\\Debug64\\ProcessHacker.sig").Dispose(); - if (!string.IsNullOrEmpty(output = Win32.ExecCommand(CustomSignToolPath, "sign -k build\\kph.key bin\\Debug32\\ProcessHacker.exe -s bin\\Debug32\\ProcessHacker.sig"))) - { - //Program.PrintColorMessage("[WARN] (Debug32) " + output, ConsoleColor.Yellow); - } + if (!string.IsNullOrEmpty(output = Win32.ExecCommand(CustomSignToolPath, "sign -k build\\kph.key bin\\Debug32\\ProcessHacker.exe -s bin\\Debug32\\ProcessHacker.sig"))) + { + Program.PrintColorMessage("[WARN] (Debug32) " + output, ConsoleColor.Yellow); + return false; + } - if (!string.IsNullOrEmpty(output = Win32.ExecCommand(CustomSignToolPath, "sign -k build\\kph.key bin\\Debug64\\ProcessHacker.exe -s bin\\Debug64\\ProcessHacker.sig"))) - { - //Program.PrintColorMessage("[WARN] (Debug64) " + output, ConsoleColor.Yellow); + if (!string.IsNullOrEmpty(output = Win32.ExecCommand(CustomSignToolPath, "sign -k build\\kph.key bin\\Debug64\\ProcessHacker.exe -s bin\\Debug64\\ProcessHacker.sig"))) + { + Program.PrintColorMessage("[WARN] (Debug64) " + output, ConsoleColor.Yellow); + return false; + } } - - if (!string.IsNullOrEmpty(output = Win32.ExecCommand(CustomSignToolPath, "sign -k build\\kph.key bin\\Release32\\ProcessHacker.exe -s bin\\Release32\\ProcessHacker.sig"))) + else { - Program.PrintColorMessage("[ERROR] (Release32) " + output, ConsoleColor.Red); - return false; - } + if (!File.Exists("bin\\Release32\\ProcessHacker.exe")) + { + Program.PrintColorMessage("[SKIPPED] Release32\\ProcessHacker.exe not found.", ConsoleColor.Yellow); + return true; + } - if (!string.IsNullOrEmpty(output = Win32.ExecCommand(CustomSignToolPath, "sign -k build\\kph.key bin\\Release64\\ProcessHacker.exe -s bin\\Release64\\ProcessHacker.sig"))) - { - Program.PrintColorMessage("[ERROR] (Release64) " + output, ConsoleColor.Red); - return false; + if (!File.Exists("bin\\Release64\\ProcessHacker.exe")) + { + Program.PrintColorMessage("[SKIPPED] Release64\\ProcessHacker.exe not found.", ConsoleColor.Yellow); + return true; + } + + if (File.Exists("bin\\Release32\\ProcessHacker.sig")) + File.Delete("bin\\Release32\\ProcessHacker.sig"); + if (File.Exists("bin\\Release64\\ProcessHacker.sig")) + File.Delete("bin\\Release64\\ProcessHacker.sig"); + + File.Create("bin\\Release32\\ProcessHacker.sig").Dispose(); + File.Create("bin\\Release64\\ProcessHacker.sig").Dispose(); + + if (!string.IsNullOrEmpty(output = Win32.ExecCommand(CustomSignToolPath, "sign -k build\\kph.key bin\\Release32\\ProcessHacker.exe -s bin\\Release32\\ProcessHacker.sig"))) + { + Program.PrintColorMessage("[ERROR] (Release32) " + output, ConsoleColor.Red); + return false; + } + + if (!string.IsNullOrEmpty(output = Win32.ExecCommand(CustomSignToolPath, "sign -k build\\kph.key bin\\Release64\\ProcessHacker.exe -s bin\\Release64\\ProcessHacker.sig"))) + { + Program.PrintColorMessage("[ERROR] (Release64) " + output, ConsoleColor.Red); + return false; + } } return true; @@ -521,12 +574,12 @@ public static bool BuildSetupExe() { try { + if (!BuildSolution("tools\\CustomSetupTool\\CustomSetupTool.sln", false, false, false)) + return false; + if (File.Exists(BuildOutputFolder + "\\processhacker-build-setup.exe")) File.Delete(BuildOutputFolder + "\\processhacker-build-setup.exe"); - if (!BuildSolution("tools\\CustomSetupTool\\CustomSetupTool.sln", false, false)) - return false; - File.Move( "tools\\CustomSetupTool\\CustomSetupTool\\bin\\Release32\\CustomSetupTool.exe", BuildOutputFolder + "\\processhacker-build-setup.exe" @@ -775,7 +828,7 @@ public static void WebServiceUpdateConfig() } } - public static void AppveyorUploadBuildFiles() + public static bool AppveyorUploadBuildFiles() { string[] buildFileArray = { @@ -791,7 +844,7 @@ public static void AppveyorUploadBuildFiles() }; if (!BuildNightly) - return; + return false; for (int i = 0; i < releaseFileArray.Length; i++) { @@ -804,6 +857,7 @@ public static void AppveyorUploadBuildFiles() catch (Exception ex) { Program.PrintColorMessage("[WebServiceUploadBuild] " + ex, ConsoleColor.Red); + return false; } } } @@ -819,6 +873,7 @@ public static void AppveyorUploadBuildFiles() catch (Exception ex) { Program.PrintColorMessage("[WebServiceUploadBuild] " + ex, ConsoleColor.Red); + return false; } } } @@ -833,14 +888,16 @@ public static void AppveyorUploadBuildFiles() { Win32.ExecCommand("appveyor", "PushArtifact " + releaseFileArray[i]); } - catch (Exception) + catch (Exception ex) { - + Program.PrintColorMessage("[WebServicePushArtifact] " + ex, ConsoleColor.Red); + return false; } } } - } + return true; + } public static bool UpdateHeaderFileVersion() { @@ -884,7 +941,7 @@ public static bool BuildPublicHeaderFiles() return true; } - public static bool BuildSolution(string Solution, bool AllPlatforms, bool Verbose) + public static bool BuildSolution(string Solution, bool Build64bit, bool BuildDebug, bool Verbose) { if (Verbose) { @@ -895,7 +952,7 @@ public static bool BuildSolution(string Solution, bool AllPlatforms, bool Verbos string error32 = Win32.ExecCommand( MSBuildExePath, - "/m /nologo /verbosity:quiet /p:Configuration=Release /p:Platform=Win32 " + Solution + "/m /nologo /verbosity:quiet /p:Configuration=" + (BuildDebug ? "Debug" : "Release") + " /p:Platform=Win32 " + Solution ); if (!string.IsNullOrEmpty(error32)) @@ -904,7 +961,7 @@ public static bool BuildSolution(string Solution, bool AllPlatforms, bool Verbos return false; } - if (AllPlatforms) + if (Build64bit) { Program.PrintColorMessage("Building " + Path.GetFileNameWithoutExtension(Solution) + " (", ConsoleColor.Cyan, false); Program.PrintColorMessage("x64", ConsoleColor.Green, false); @@ -912,7 +969,7 @@ public static bool BuildSolution(string Solution, bool AllPlatforms, bool Verbos string error64 = Win32.ExecCommand( MSBuildExePath, - "/m /nologo /verbosity:quiet /p:Configuration=Release /p:Platform=x64 " + Solution + "/m /nologo /verbosity:quiet /p:Configuration=" + (BuildDebug ? "Debug" : "Release") + " /p:Platform=x64 " + Solution ); if (!string.IsNullOrEmpty(error64)) diff --git a/tools/CustomBuildTool/Source Files/Program.cs b/tools/CustomBuildTool/Source Files/Program.cs index 8774e49e97aa..49825dc49032 100644 --- a/tools/CustomBuildTool/Source Files/Program.cs +++ b/tools/CustomBuildTool/Source Files/Program.cs @@ -6,7 +6,6 @@ namespace CustomBuildTool public static class Program { public static Dictionary ProgramArgs; - public static bool BuildDebug = false; public static void PrintColorMessage(string Message, ConsoleColor Color, bool Newline = true) { @@ -23,7 +22,6 @@ public static void PrintColorMessage(string Message, ConsoleColor Color, bool Ne public static void Main(string[] args) { ProgramArgs = ParseArgs(args); - BuildDebug = ProgramArgs.ContainsKey("-debug"); if (ProgramArgs.ContainsKey("-cleanup")) { @@ -55,55 +53,57 @@ public static void Main(string[] args) } else if (ProgramArgs.ContainsKey("-sign")) { - Build.BuildKphSignatureFile(); + Build.BuildKphSignatureFile(false); return; } - else if (ProgramArgs.ContainsKey("-cleansdk")) + else if (ProgramArgs.ContainsKey("-sdk")) { + PrintColorMessage("Setting up build environment...", ConsoleColor.Cyan); if (!Build.InitializeBuildEnvironment(false)) return; - if (!Build.BuildSolution("ProcessHacker.sln", true, true)) - return; - - PrintColorMessage("Copying SDK headers...", ConsoleColor.Cyan); + PrintColorMessage("Copying Plugin SDK headers...", ConsoleColor.Cyan); if (!Build.CopyPluginSdkHeaders()) return; - PrintColorMessage("Copying version headers...", ConsoleColor.Cyan); + PrintColorMessage("Copying Plugin SDK version header...", ConsoleColor.Cyan); if (!Build.CopyVersionHeader()) return; - PrintColorMessage("Building sdk resource header...", ConsoleColor.Cyan); + PrintColorMessage("Building Plugin SDK resource header...", ConsoleColor.Cyan); if (!Build.FixupResourceHeader()) return; - PrintColorMessage("Copying plugin linker files...", ConsoleColor.Cyan); - if (!Build.CopyLibFiles()) + PrintColorMessage("Copying Plugin SDK linker files...", ConsoleColor.Cyan); + if (!Build.CopyLibFiles(false)) return; Build.ShowBuildStats(false); return; } - else if (ProgramArgs.ContainsKey("-sdk")) + else if (ProgramArgs.ContainsKey("-cleansdk")) { + PrintColorMessage("Setting up build environment...", ConsoleColor.Cyan); if (!Build.InitializeBuildEnvironment(false)) return; - PrintColorMessage("Copying SDK headers...", ConsoleColor.Cyan); + if (!Build.BuildSolution("ProcessHacker.sln", true, false, true)) + return; + + PrintColorMessage("Copying Plugin SDK headers...", ConsoleColor.Cyan); if (!Build.CopyPluginSdkHeaders()) return; - PrintColorMessage("Copying version headers...", ConsoleColor.Cyan); + PrintColorMessage("Copying Plugin SDK version header...", ConsoleColor.Cyan); if (!Build.CopyVersionHeader()) return; - PrintColorMessage("Building sdk resource header...", ConsoleColor.Cyan); + PrintColorMessage("Building Plugin SDK resource header...", ConsoleColor.Cyan); if (!Build.FixupResourceHeader()) return; - PrintColorMessage("Copying plugin linker files...", ConsoleColor.Cyan); - if (!Build.CopyLibFiles()) + PrintColorMessage("Copying Plugin SDK linker files...", ConsoleColor.Cyan); + if (!Build.CopyLibFiles(false)) return; Build.ShowBuildStats(false); @@ -111,31 +111,44 @@ public static void Main(string[] args) } else if (ProgramArgs.ContainsKey("-bin")) { + PrintColorMessage("Setting up build environment...", ConsoleColor.Cyan); if (!Build.InitializeBuildEnvironment(false)) return; Build.ShowBuildEnvironment(false); Build.BuildSecureFiles(); - if (!Build.BuildSolution("ProcessHacker.sln", true, true)) + if (!Build.BuildSolution("ProcessHacker.sln", true, false, true)) return; - if (!Build.BuildKphSignatureFile()) + + PrintColorMessage("Building KPH signature...", ConsoleColor.Cyan); + if (!Build.BuildKphSignatureFile(false)) return; + + PrintColorMessage("Copying text files...", ConsoleColor.Cyan); if (!Build.CopyTextFiles()) return; - if (!Build.CopyKProcessHacker()) + + PrintColorMessage("Copying KPH driver...", ConsoleColor.Cyan); + if (!Build.CopyKProcessHacker(false)) return; + + PrintColorMessage("Copying Plugin SDK headers...", ConsoleColor.Cyan); if (!Build.CopyPluginSdkHeaders()) return; + + PrintColorMessage("Copying Plugin SDK version header...", ConsoleColor.Cyan); if (!Build.CopyVersionHeader()) return; + + PrintColorMessage("Building Plugin SDK resource header...", ConsoleColor.Cyan); if (!Build.FixupResourceHeader()) return; - if (!Build.CopyLibFiles()) + if (!Build.CopyLibFiles(false)) return; - if (!Build.BuildSolution("plugins\\Plugins.sln", true, true)) + if (!Build.BuildSolution("plugins\\Plugins.sln", true, false, true)) return; - if (!Build.CopyWow64Files()) + if (!Build.CopyWow64Files(false)) return; PrintColorMessage("Building build-bin.zip...", ConsoleColor.Cyan); @@ -143,26 +156,78 @@ public static void Main(string[] args) return; Build.ShowBuildStats(false); - return; } else if (ProgramArgs.ContainsKey("-exe")) { + PrintColorMessage("Setting up build environment...", ConsoleColor.Cyan); if (!Build.InitializeBuildEnvironment(false)) return; + PrintColorMessage("Building build-bin.zip...", ConsoleColor.Cyan); if (!Build.BuildBinZip()) return; + PrintColorMessage("Building build-setup.exe...", ConsoleColor.Cyan); if (!Build.BuildSetupExe()) return; - Build.BuildSrcZip(); + PrintColorMessage("Building build-sdk.zip...", ConsoleColor.Cyan); Build.BuildSdkZip(); - return; + + PrintColorMessage("Building build-src.zip...", ConsoleColor.Cyan); + Build.BuildSrcZip(); } - else + else if (ProgramArgs.ContainsKey("-debug")) { + PrintColorMessage("Setting up build environment...", ConsoleColor.Cyan); + if (!Build.InitializeBuildEnvironment(true)) + return; + + Build.ShowBuildEnvironment(true); + Build.BuildSecureFiles(); + + if (!Build.BuildSolution("ProcessHacker.sln", true, true, true)) + return; + + PrintColorMessage("Building KPH signature...", ConsoleColor.Cyan); + if (!Build.BuildKphSignatureFile(true)) + return; + + PrintColorMessage("Copying text files...", ConsoleColor.Cyan); + if (!Build.CopyTextFiles()) + return; + + PrintColorMessage("Copying KPH driver...", ConsoleColor.Cyan); + if (!Build.CopyKProcessHacker(true)) + return; + + PrintColorMessage("Copying Plugin SDK headers...", ConsoleColor.Cyan); + if (!Build.CopyPluginSdkHeaders()) + return; + + PrintColorMessage("Copying Plugin SDK version header...", ConsoleColor.Cyan); + if (!Build.CopyVersionHeader()) + return; + + PrintColorMessage("Building Plugin SDK resource header...", ConsoleColor.Cyan); + if (!Build.FixupResourceHeader()) + return; + + PrintColorMessage("Copying Plugin SDK linker files...", ConsoleColor.Cyan); + if (!Build.CopyLibFiles(true)) + return; + + if (!Build.BuildSolution("plugins\\Plugins.sln", true, true, true)) + return; + PrintColorMessage("Copying Wow64 support files...", ConsoleColor.Cyan); + if (!Build.CopyWow64Files(true)) + return; + + Build.ShowBuildStats(true); + } + else // release + { if (!Build.InitializeBuildEnvironment(true)) return; @@ -170,11 +235,11 @@ public static void Main(string[] args) Build.ShowBuildEnvironment(true); Build.BuildSecureFiles(); - if (!Build.BuildSolution("ProcessHacker.sln", true, true)) + if (!Build.BuildSolution("ProcessHacker.sln", true, false, true)) return; PrintColorMessage("Building KPH signature...", ConsoleColor.Cyan); - if (!Build.BuildKphSignatureFile()) + if (!Build.BuildKphSignatureFile(false)) return; PrintColorMessage("Copying text files...", ConsoleColor.Cyan); @@ -182,40 +247,36 @@ public static void Main(string[] args) return; PrintColorMessage("Copying KPH driver...", ConsoleColor.Cyan); - if (!Build.CopyKProcessHacker()) + if (!Build.CopyKProcessHacker(false)) return; - PrintColorMessage("Copying SDK headers...", ConsoleColor.Cyan); + PrintColorMessage("Copying Plugin SDK headers...", ConsoleColor.Cyan); if (!Build.CopyPluginSdkHeaders()) return; - PrintColorMessage("Copying version headers...", ConsoleColor.Cyan); + PrintColorMessage("Copying Plugin SDK version header...", ConsoleColor.Cyan); if (!Build.CopyVersionHeader()) return; - PrintColorMessage("Building sdk resource header...", ConsoleColor.Cyan); + PrintColorMessage("Building Plugin SDK resource header...", ConsoleColor.Cyan); if (!Build.FixupResourceHeader()) return; - PrintColorMessage("Copying plugin linker files...", ConsoleColor.Cyan); - if (!Build.CopyLibFiles()) + PrintColorMessage("Copying Plugin SDK linker files...", ConsoleColor.Cyan); + if (!Build.CopyLibFiles(false)) return; - if (!Build.BuildSolution("plugins\\Plugins.sln", true, true)) + if (!Build.BuildSolution("plugins\\Plugins.sln", true, false, true)) return; PrintColorMessage("Copying Wow64 support files...", ConsoleColor.Cyan); - if (!Build.CopyWow64Files()) + if (!Build.CopyWow64Files(false)) return; PrintColorMessage("Building build-bin.zip...", ConsoleColor.Cyan); if (!Build.BuildBinZip()) return; - //Build.BuildSrcZip(); - //Build.BuildSdkZip(); - //Build.BuildPdbZip(); - PrintColorMessage("Building build-setup.exe...", ConsoleColor.Cyan); if (!Build.BuildSetupExe()) return; @@ -228,8 +289,9 @@ public static void Main(string[] args) if (!Build.BuildUpdateSignature()) return; - Build.AppveyorUploadBuildFiles(); - Build.WebServiceUpdateConfig(); + if (Build.AppveyorUploadBuildFiles()) + Build.WebServiceUpdateConfig(); + Build.ShowBuildStats(true); } } diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe b/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe index 29a6995bd64d0eb702065d554efad9fe67977c92..dd4aa7b45ed7243863358566d66f557b2cbd62bb 100644 GIT binary patch delta 14423 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 delta 13092 zcmbVz33yahw)H-@s%}lGN>x&+Aypa3M3I4clqrmnnHWJp?Pe5h!N3hF%20`nQB>j; z5KtbIv?vZ3Y(;rW6h&;?hXd`<7@>VWXIm6)wQc;@+4m+@@$-A%|Nmvzx@+yd&pzWl z_uL9yf8J4l#<6jI!PtghrjhwMLj~j(-HCR?utBi(k(Q6dh=lTUF}@1fsAxRM z5+a%UCL&d@KG0pCtdxlQ<{OodEO|pNJyAioG#Q}Y_zEh3&A>l(5 zJ_Q974j@;wyM@{dJ}3h}1DFNlPFc{Y?@~J_ezW8TWa26xKxDiVDywj7%nQIvv{zHi z%ndWSkhcY78x1LOwe?`pBK5houE3$VL1mmZDRx{>lKt!m@#qtwdv7=A>NR?vX6%ack?_ zJ?jJd{b_lLKf%y8N5N7%`a-VqbnWX7W=EU3Br7$Vv>DJmulD##x!N?T?*gcX{*%-{ z0UWGbBOYx?kQO=P`KU&ATOZ*mtg%oX`s9+!2ltp&n~e}27@qg?z^|=5M>`P|48|j< zw!#{8wf51@!_pS2KkX@Xx8KQ^U8aBK3174(^jmq8R?hnzf{ZLl$40%1qC0;#VajZ6({9mB5(P zWBphS$FFjk;YllpyAfVD7lOis7&e zzk%0VWd2Vj<0r$vC6h;tTytq@a=XSd(yr+wuVJl$uMzD&zGiDr@-?cx$=8_nC0}#2 zyaL46)uGYfd zkami%VeL!4Ml?|@>&n(L`5M)V`5M#u@HIyp$JbnK9$zse*Biv8tuu&Q+is9F?Vv$C z+6xBpYHt@)LXKp*_Nig=Y5y{aU$d2PFEg}|K{B;&1_@}R43ec?W{{w^&>$hL(I8=M zt3e{#euHFd&ln`Cy>5`0_Bn_g{~Ya~hACHbcjj92v>b!vYuyaeNgHaA0N7BsrMXIcGH$BUXD!+aShZCEKBZ~vq`bXdHc7dqO_pZrv!a78-VPnFLHUY{{Wk6X zb~PI6V7r9;o|8&X98btHbQ@g_*4_y7%1b-O-y`F( zy`vG*6USaz7Prfm1iC=Wf+3^el#T_r%7Qm@!72JPd4t8h`j2^dPjo>TW zgA0?vb#Z-qQBG)oyDul{doixxUKASguXdk3j<!Vm7F}E?MRy!cjM59MaL2 zXczr#QD$fiLfe~!qZYR_(M8`?oSF7qicfDT&I5i zj$Yp0GVTdRORg2!8o37eiWe=unyrlE)W{mkLtZsMk|sMCcbMh@rTQ}^d4m_WRasur z-u5`2Ih+EIPQGHpRZHUO5=%qv({^L2J}Vv@*WNrn(L2X28?qqLMDm1&NHKazGebo-98gV;t6+arr3_feb1BNvo#8uzX zrH|65TtC%ip)#OcA6YtDEZ1)<-2yBu`%mflds$7q0g*1XJg(NR0n_%BW6w;!>-gKv z`jzDq#U1*A^6cnz+%CKgO#`{0{s+p{J;68fbp333nSHHH^g+3vS$q}rsKrzX&jj1b;&#DjZT9S_9)>dzc5>9Fu7EV7tagrM+p@L6!P@B<^r$2GeP;yc6gp_hT6<%}tXyiZRb4`RB~7 z%+GVo5Y z+Y?afB&`d(=m)#xF7cWLH!<*9dMisd=y`h0qS7~veX?YtDe$hM=W*;=$1z?SCx)Z! z2q7~MV!YB_9n7FVWEEtp^r7#2B}flNGJ^?~Hl@j++1!Z5F4=>%+=F%8(qn1TGL!A^ zvwgMV4`o0H*=V9D}pbT1*wK^k6n=&)e z?>hprz;?#8piEK1eQo8z?-7-j@!aDwzwCE4;}dqthcKVQ@gHQ!$Tu=%wuJqAC7bry zXJq8kGl}qwjBHvOn}I4TeR6Qh&~LdQEjTgAmry|sB0$fovwfpj2`uZc98zUc6c+r9 z>X#}=F+}?4ZIUWRMO-c_3{^q`>wKGiw(nuer!rO%_iSI{Vd^fW&qpgGGPEDmF5Eba zGiC$(Q8}xP!Bn-#^mS+7a#SHBd$H<_q*C=})e99$)t6Ny%TPmDMWrtRXC=$oW}1sx zO*RWoXSKs+6r9EV9S}7dI*0rFwNI*Hw3O8a_Kl$B-1`?YrEdh)b2$|`rMiV9e`a4| z65UA_44d2qM&XYuO=RihqgO0aO(vavarRB6Z7IHKbRYStbF@kIQ$cJK@DXnVEN21| zKk-Z4!uYve@}JW0LCnXD?{nlyi3!SJF(q9Fjb@w)>_PtyZdZHI?;;W>16BIj*?_y> z7XAzkL8D>~Xm~Rs1sxAb3?W9)J~TqmgscXdTCXX0*rwLcVw?=@LANW9sH%F{ za!{RGp9oqG;gZYPhj9ku0>&!F!HSG2VI;P^$h@BUJ&e2A@*ZOvu&shB*Hb9l)hBU= zRpLCxYa^0RRNPPLr}_=ex*>c-4bmR(CbbitwMv|1+oTuvADC!DZ%;)Uu!MdQFCwOa zP5}Q%ZvdObY2f4H3*cYG&xqU`^4L}CEJAh}-`O6-U!KbBlk+iyw3+VC?qe79SSLe0 zn!TA6I%KNj*;PWJX@!QbIZ`F?Gfg2Ds4RFmbdlXk(~1nInkCgCQ;lMuuh{VQW%ZP) zl!%PHr^N6r4@gzs*-%%ry2n({IHb>q*B)8lwVWkZieJ8@Jn50n1CUaElF4bx40WDW zpxjWWS-oSbldJ~ektoYqowD4Su7-NtCDnp%hAQ*IPjh=1>XMLDj$Tj+6#ULFLzhbl zwVd1bmZ<`nL*P5oTl$*9A7yPOJ8kSI)!Og}St`^$tQzPtS07=gmkl4~dwuw`)tUY> zvVru_D7%v?@%%Q_rFIuR#wyW3KZLHbc>dsLt-C zLHO-cHuSt_m`JC4P4$iECcBT$o9Z=n3hp=gsi)2P%N+@OX1iK%Uv0-(*zhItx7ase z8Lb~G4Mq>cl9I(|^w3a5FWJ^ab$e1d0sSrg@JZsNwZ)gU}@qGr%OE!!9xIL+MI#Ydh>8YwXBatePIrrI;1#Ox8 zYz6IAT$J7iKLQ$`mu#{^zCYV5Oe$GnQppOFsu<&xRH!duOG;TG-`Jc~R>(IttN!l4 z*!fmw^#P_LschMAq^Ji`VbZrG@^*@Ef}>s}edFErB9WAy(CL)WP=_>fwv&-^wv$TE zc2ddNPAWOuNwpf2om6tN@ke>%^O8-@cGCG;=xj=3?)LnTJx-hW9$D+S0R_9zeWtp_ z>Vw*6s+0a|Dy2tEb=vQPdeT%U(4{hZ&Q$ND`=Ampn^N;t<1lj4R0$kd%IRHG?S`*{ z&YJ2`_$uf#Q*D5+D}7_CE%0@vf0?QTBh!s6m9mR#9lZlSs5DdEjD~inK*E%3(bDde zW2)g8wjNY$sDx?sQIBH)9Whl1Y7kwDS7GUU-7$oQ z(n(W&=Ut7{maj_snnp=Ft)vW79pcDrQ+WlfUq*7BkSoJj3HdYsz%7PVCNyDMg|Fw>9 zT@kc&yy3)SB^RnYUgKpi-VPNxhS5{3Hq((nD~;?h+@tB_SQ)vBuBH*nXzGTy{I-p} zszYQI4P@Ucx{WFvRa7li0tF9JPshbH-E?jj{T*XyuBncQk&dynz*KLG$&PUyl8&b( zrmw5G(lMUCG}R}f&OU)`_-Uc7F%vtKn@E24C00=tUE{zn4>-|%ju%ovv+$@AREUGM zpa{4^_v5K!q4!E(43iMlmYJ7$|fd zDzlJbF~*?Xf`61m(j@3RRpLh&Qia~c`M^S}*#0I^p(^Gt@i+;qjKpgM5dT2rS9mHS zEe8G>=bYa7_ZQvCgKs*GrwlA#Cw-75a6FOcr$hu77dFrjvg9TsaRB2m#xac5jMEus z0kh~D=8G9`Vr&4a)I&(DX1oTNO*a8MQ6n%;TiL#gv55{v2hgVp5e*HYb7Dt$1a0L+ zTj_N6coK?^JN=w^J2Hiw%E`#(1 z)?#~W0`?KZl(h+nG(Jj>QTBMM#9=OQnEFP>i|NWh>m_2A^1YZQu0hh@!TYIYzPL$= z>zMywj7(m*-wfX#}ona z15J!x&-zf5)5l0xP7Tp|QACf2F8~KxFCcWF)vEO70)rSwBEGjWp5xDnuy2HNPCT0~ z2lIsIVr3AQ8bl{N7sMdWb16zqRkkYKVpkxKC%O$wQs&&Hpss|t!gPNZc~O~b^8T?e zl?5~_9JVY$Wfhj?sBE}pHG4OhF*$+7mb>W(-vgF=P0RS`YnHtx|2gt6l#-qK5f&fq zS1xl)?1G7t=tCo9w-X1r9|t&ezw!~>jmm825LztuJIbvCc=ZnB6?<6uG}6a9OPP^9 zO$-z7MF)f5=^YN77Ot_%nCaHTN^9iz))q{bN-fF?PZsd1sKkq$KHzciF`_KG&^kt} z%e=wbl2D$H_}El0#)z8ea_j5LF|`_&5t!q5kqDcxvNh`#YXm)*3H~(RfsW8O(F@|N za@@7kdIbI3XO$Ci5PYEZFi`jpThA%idtb30Mzc;@4~h);JJui3&{nIk{5?7y__$@d z)u|+UT0bFS`8n%b>j{MZXziiQ$W(2@@&zof!xFQ-3sfm$Ip!_0b+WAWmfMb*gS^2t z)izzYymhv%ia&a@tw{*i9YCK%`qt6}Jc7HtQTZ4ndQO}P@31v0)qy?0iNJGWYr?zF z*2N-c$geyWI&5n}WiQyy0{;wmI{I`@JRTmQjIq4uI0efE&&Re`&FZUtS13(NMfMN2 zw@4GiEpL%uEW1>Yzn56u5*&0+&)^jOwJ- zG!bGA&`Im52E38^2AZa3(Cy4O(v`3`F~6H;gKuJf56wr+R_6E80%X`pi-CLT2H*p< z40r%Jo%9&8Iq4AcIO!>5aAF$gCvZ8&g zP0Jl!@$=joV3hU(3+Z8C8DlRx20oBp0ghnHIBEs2Vf*EbbLcx*uBAL@qAUK1Ub%Aw zEkpHVP{AGUYk<4mjlgF2e&7lB3+z1s{(<{LoL*|wPr<)+TZH6J(TqPf6bhYga2AR= zlyG)|B`>9y*4tR-s4)ayulijPB?@=B?LoF8B$vKu)z*UTU zEI9wvs4uXXX_fq}DpA-ac48dHIE%4?aTj9?<5@=Gknyt^8yI&nwlJP$6i&{`IE-CI=XWSq%Z&$yHEDB~GM@^U<5CF4xSdSIeP z-O1u8W2H}q&Sb1-+{t*9@eCvRIUQpq<4neS#+{5kXr0=N8r43y_QQ7!zT@znKpWIa zbO$!L4Qe-9OzZXI|4C~>8$GFX|Y98vyT zNw*YP23V>rvn^XK&6ZY+&)UV>Xq{mD!uD?)iAf1;1p?>2YFdw99!b>D7F@0M@(7sv zk-u-_)Y$&1P+Kfgq}uwb9{yP>)mEY2g_CW^xC(VO{t{%^dPyQb6>1Ux-qo@2jP^hy zO2)bL!4vcP*DCK*t8$i{miK9@XK1I~%->)63KfKo2e17d}*{tdtvYU_JQ6QB1JN3`*oZ-EM=HbCKk7i*Po=5uZ zjop;`+kV5-eAmV~cCV*`<|1r1T~G5#=-+K=Ey%2(IcA3IkYg@3bx|>bYVnx638(by zXudvRYreNnN7IU}dHUq7PQBN?nKmw@pV%6Y4ek(xccn$hEUQ8uJ!@M*z**5&1=ws( zFZ8q9uF~JXr&6D?ZG-;Z_93F5UcWtGb{|g|`JWgHLvHgW_xcpy=Es*6&Mq4``p&iQ zhNo4Ze64xOj@82JvD~4uzr>I Ukte;6h@Tpj$9gokoc>#&=0!fI;;gE!okOK)2@4lPGeOZ&4r7M0I@#_YEDN$L<++^D=aH;_Z?UIhZwE2IMA(P73jtCf0A`<;mP=SAB#Qzk)-*&)SSVXNAcA+GmJ`8J}54ZH`6k$K=kaazV%Zr_o z?JW*D+bPqv<))pku|v;rV>+@E$*%k&`}YpX?4mUdl>_;q&M&q6z!JfUT?_0jyMG%W z<7<(w*bw>$0a;SyKqR*DMa z?7@wF39l47?HP^bED3PEFvs5Cm{Y8=<0E887q=^(qt%!DT2roel)v0NBe-Oh(yy!2 z9u*-~T{B#xZp!H)*KyWzb|ra7*Btvdk#fFkjs3?+8QyJ%J)()c*)3DK(XGzj)Kuz< za_sF*WnWQ|9TO#A6;&pWy^ZR#tk%N^mN=TG9p!42Ts+*OnXiop&>ynMtvTC8$+kPn z9Ytg~6(!-_GaLy7KZ=sV?m5wS5e$#6KcVF45Sib-rK1J0>Cy6Dcb6RK9(!ARN}5bm z=}j3Mkug5;cr4eFRNdjJn^NgpCQ_#7#mms@EQ!hvl>v8z+U?_{s5mb4P#~kUI?|$@ zueuW`;-9SA7wc2CcfUZ~KUfoq|2jHwM})ds$Ft2+=*RazSJvT-k)$3e?kw8m8mlHd zW9rW>D7u=sS6Fp#veM(5Xw(%}JwSF0J-@PtuaB@9d{ZMgr|^M+l1z`;6Q_(Vn>JjH{;J4R;QS>+n5y^rO1VBpiRi;@R7laif< z+DhKMoXsB=el^z~Z!whh*bIz3*FKDkfkWw!}`DjJ+@g^*X0w zA56m$=*Cf)jun`J(Iz?8+-4TC)|qG%gNs-nmT7$weHHVMZU4SvSrniZ%R#MJE^5W{ zP%Bn|TCvWk6)QxoSQpfabwjOK5o*PXQ7hI10~NcU%1jMZY#QNeU&ScUO!f`BmZ=|E zwXxe1uS*{a(2Dg%?pSjV((JmrY#7xNDmVG5^)cf;jF+~hjrRgj-Hk=lR{*8Usvr^%GUez>fdg77%Gi!Gtim` zkXypcL%lCFy;UH+4K5%)D-fR(*zSxT;s*!fM+V}@;3DGh55!LkY|r7Mnny@@Dv+=) zkgypaC4MU|!ELw{_v7RE8(fZu@JZ=(&$L?qGtDxyiP42o-sl~q%hTlK`J=-i&1lRT z6gfn09UWdr#wl|cbvQnTdX6VB4^Lt~p2n{DJJg%*4E_YqqMrLX)XVk}vwuiTDP&Q_XecPBq^lH=4PDa~g2hm3QjtN4pxCue7foX)a zk_pA5*cdqp6Nyy9G(jq1VlcASXvX%;(8KSZ(qW? zzCwH@YsxL*yNH{|s^#1q?rjQhGrfuIO`_T_upVH$zMvn%k=*xR&;U9fGMidn;;N13 zBy^~AqIQGkSb{B3FFW1HciEG06x+!-1zRCcHxt>u3%lW6wppYD(miYs#eS%FbqVSz_D6cS8Hn1!%P`tZpk?*)48@^x z&w#Wr|3uO<6|!(>v*KaoiX-=M%s^gaJa^)KsCRKW_QuhuN2|d5a4c#AkCW2_I_i}3 z#sF9CWFob&DX4`_#eAHG#aNB^;&jwgn2F;(B>99gNb++nM9fY!k%~z%Po^(-X<`bh(BNjzKgT)J)DalU=5y^ z$U$Rj{}}0?^LaRgE;sk}56P*Q<|EWg^D*kB`4n}Ozl?f&{{{2$D)z%`sJ-xW9D)Df zp3p)38@3~VG_>W(-v*`Cj$j6$^Uk-Zl`hGw%L3t`Ab%Z#k*b;y)VerOhnPm_#!%Ec zg<&p+qt-1V$SivgU2K1dE$|X1;&+%7WNLj+gk&O^#F|!^j49X_Q&HPF4ZCAH_QrO| zRL*q3`>-RM~(>62Isc$WzEPgsH4kXqnJIEL-N;duNOC*Td7h+I=M8Dnt@>JwM@ z*LGIjI32ZpwY+vXlkI$*jV1ado=1SGsj0z<_#jTk`B;k!@L|+~^vSEP#6>9hFh-iD z#=o{?luhClL;JBIoX^v%kWn{|HJxx3tDBf^JbF8u7)c!3B8V92GBmZdrjP$ox<32D zOt|m)r-RO+XsH?MDqhMV^~QM|bu4%y$ULf@@oBd8Mp=yo_zd>PwOEGFp*|ni%ekQ) z!~Cz2mMQc-0=AImAZ;t^wDNh3$8D%L#CFsh;^(O2thb#LOhJx2uE=f9>ZOD9Dju; zgG|z*j|u#ah`-_))Gl%sb!dBAIt)*<5~OT+x;?m=cfs&FOI{n-Q-Vh(IC#)FR;G)4 zWT6cuQ&VJFRjfQSvL~C~^CNp$4yxd=-Qq4Ul;rYYJIpOr<@qw2V3b=nm*+UBnF=4>*@WZ0aE#>^t7*dN?Tkh*K^DT4joa-MvH-QMuAF5AA|Lflm; z)^#bJlPeEZyV2@~o9IZ&Iq`X_BtCmCciS6Y&`ltBLrst;9^$ zh+&gc9czgAzOB^xB2Ey&$mejR%NLV-$E+lHbK||+R{BoKuqjZ_ZpD(EyafNX>rQc>I~U9 zEy9j$ExV@W+p#1}&yc9<2)jjVNvfV?Jt&V=r#j}d?}*m2r#i(of-Bn4TC~(DuKgfd zi{z`-`F5oilpzDAN7xg!uzb6^z94Hxs)NU<k{NMI)r=hb<<_!pMxp(B zYk7M{O>?b%eIsb$r&9HxI+R!wo5@2nyKCJK&fIKs)Ppl!^3bd$VK4eBW|>ksGq9OA zd3LZBx*{=fflA+KCU?wMvWcuv2VZ6TB!SmtrKor&_{oJzYaReC>=qD*>V zpk0+J2Op^Hi2fl~J_-7+E^Ga$n={`I)JROm`dO9I>^*uFdRZm~G2jdVN zf}?OKj>h3Q4M$)#-iJC{DMx*Xj>1Q<0#{)r>TB#6?2Bk8dEab)HkmyN~Ar&cMIoO#BjO;a4~Zzr_cTcWGWw=?++fyc?T`xCWk< z1ZZ?m8|04g@Lp&<{Og1Zu`AYLH+&fT;v>jQm*L`gcqaAy?V64xhqjk>Sg;0~xhEzd!~nj~Ac8y+|+c z9KvUjmjV64>fvR;Y(OUa=BLPH-)zK-xEYyQn=SYi)@~*6HGypy9K@3!8{^NA>8{y< z&5>^AVODEiz*fk!*prFB#5~-M#Yi{w+=X;QPaoWiO#jS2WEN*$MkZB!N8pu}>9W~R zU@j5ALS|p)*T@vd9K_}L8a|7MkZFtgEpA2nw`VsV!B_AoGN~}fkx7F&fp6kTWR74? z;rns{+wd#giC^O`{04u8*YS1y7uFso@Ew6Ocmv7=_{J#KzbhBe5+u!E}tme2liZ|BDF35OD`GwfFSH+prAda1c7N0-5rA zCZG!^Vgk-VUSU1+F$ou7GCq#2a22MYU~625Y4}rYV?`Rz^8|QjU|Qc!`p++`&Esj| zWKy4x!&r-$%?uKv=(~#7+p<=3 zq_O(-=jhC~wnMju()`udzXfRfYTnL)@U7ME6o~&nUV~bmp#DM!1sqD@*@19-UzLBT zh*nBJk^cX+Vd@WUcyo`aZ%3_64((J>tCvIjTld6>;M&vj1`7GN>*fz@+oPXb*C^u}(;M8Nl_ zt5Up!?K13vqw!AU`RhB-bkqa!Ts3{XrJga?s=8zcW2wVR6L(#P4fStTOX}uEcu2`h z3rzo7ooXR%7Dd~6X;QdomtCGFmltK)RcYdScwKWXXc= z8+OD>axQKgD6@hx?^+UVFK#Qtmt0l)KK8bQhod8s*Sw`}8%mbu*qzd)Zs|ZK{^ypa zI(TL}YSQJ#(jGsW=a1&3$UgA#Dx1{(k5@T(YCDqJhwO)b|dQye3!%tclR7 zmaoaMTe34yJXJcJ|*(rIR6E5ndE3AE7v!Z>h-bqeQ~mQeU4obC;Qje*@NSyXag_1 z@iJ*ci9I=9_HU@M*JxytTVKxkD5KMBvnJkOmcHf=AdZhW3ta3EgKXU!=e@kOiKS<7 z{rRO@^~KvZb9isY_DYLmc$fd|6H7~&vm>8fy}NeIvFy3@;1}FV$qP01f&@AFLY;k; zt(|=}a^23=VOM#1(wD{v?IYfPyG~gtFNONs;2cv4i*rBW@cRVQQQZy+mL4ybG+!Sc zNG3|7=LdFME1O21@cq`id;|gYW(hqKp707zOo`DV|PhR zw?K4h;K*l!WYz8}*ZM~OTsm*n+}{N%njJ1Nd&--C7bxU;(lmJ(`bKu| zX_MYO5Z574locpyexRuIKm`xUH+u@K?Oav#gO;H`M2jTN$l<7|{CUM;W& zd5^qW<_JE+QMV+#7Gh11#3OB7`U4otWaVeEWEbc=Z<_XJlNBfBN8B#`MN30+XMLsi zC%2844M$u#`ty^9N10_Z$BdaZZHAT>$B%l{V5eL@Qf7^lqN4>?w#?!G z9NBfWqwGA|SUx?PX5~qfW4Tr*>2a*U%9omB1v2kgV>xiFgVk9sv-KHU?T>e`DrETa z0vUF^u{_7t7&&>ooi$dzI=-C}Hk>Gs^(Pw3g%cepqshqvt3Z15e`i^6GS{khn37Jv1{=^q+r z`9k{Vz6xJxJE1pxp&4}6=Y1jl^;aJa=^vS{pR2S#3ip=3?FbH^pz{Wn0Z#AK_qJIf z`qvzfZx{WW%3Hp}>0b|4`$C7f5JTkRIcIPTU+8?<^m}lyCi1~m4!-Z?VV=Zw@8~a< z3;DyMVI5C-W$-PxrVXY;6bG{3nxObw+)LnvVLHz|G0K* znoe}Fi5o)nOZ;(Jc`-gD zsSSTxl8YbS#{JC9@cf5P&QxcsI-}Nw`?6utR?@H6w@K-x_>ilF8fnPpD|N{wSIGDE z5h0HBKvJJbLOL1OrM~-USc|G5jl00N+?uwMG~WP9DtEV$PcJ3d{FvDB(T$-0@Pp+~ zvx4nq*-~;P&UQvh)s@U_?avReG7gz(tXi3=tW#L4S*Nq=h&_{a7VB*9kt?ID=yHOi hSSwj8SVv2zt1Uw&5t_Wac)Jxcm(V`o!VwS@5CIR0aFAo7qJV*t5w}O1@J}Ir+{Eldnuo zOD(OeOvMM8&#pE3$f%~e)0CQ~S!0g3nx-7H`~UVi$I`8bG06C8Q$ME&Na0v)pgj~V%M{+%T<q2}$hn@UM4S#3!_zTb#V@&BE<- zQYLQbRx+%rQAEqgxaI#y9^3S%l>FG&hc#Tb=PzfEy;iVnbEoI6Es5R3;<8@J>?R58 zKN$Y)p}G;fKYw!Ls>EZPJH28>^z!;k?B%Vp-aKz@X&UAV%Ng;@(bKy>u%yq4`b&B@ zmcophkYS@MMoV0a{vnHsv+k-I(_&YsRUpl?^7tK+m1O-%W@OzTTj0;j`K@h?>r^ed znB_@U^{HCMXx-yYt(a(+F?Vq%5)KWKnOP;WGCM40k@KAYCyb|4Wm|SysA^N?^XvqB zNr>!eGf;Zxq=da1;?GU2w-aP>PK-OK(CiyddguZVbd4~kH4hQ(&MmMLT#|W%)-+6Z<%T7W(S`@ENE((y+f^l--%f~idSoll zUsuN%O_?L1dDHD@Ys;*>48_L033h3ic-oDQofymo)+M7wVe(8nPqL~PQT1T|Zl#b* z+}gjV!sJ-HGW*vs8Q9+I{`IO<K`n9Up-^OqW$?^ir|%%NY4(5c48eF(ILZ~ zNGpRWeWZGadoT*3H+0Chr$)-L4rTTekutF31UoKDj&{scT<$o_9#~gq6=d7Rb!B@& zfql5H{8&(u(xw5`=NhM(2CjIz=1clVRr19iKLskO<0^P1P|5y*rzG`YQVXY&ZAp26TT=#Obxco1w~xCq`i0Sf zc@UOzL95M`?}zhCMO`lkGahmoY%`--Z-(I$C;kaX0*d)XPYs(We6?yG=?A1H4OIgPd%qWi3hY1ovnX z-5w+ByNs~fNL1GZdw+}+ZO*SM?pho&bSjbS97|!DpfO>{nlapZC0a%YjcEu|pc{H% z5=?`QVJ=LD+SF9o0eWDJDK|03CyRSFcFOTvq(3g_I?`)7&0z}6fLcxqsO7YRT23a^ zahqE1{WC9(%gcu5Je9dLzgx%-KgBn@HRLuaL1@mRjZj&*{aR)`~h;Z}QO>a{lj^eav~IVQtU=$S5#_pbi|3PYuL3gT?6E1oYW~ zu+F{`^mhdGcl-5&eM1q36EQXr@jxIv1>T4LiGY4ZK))7_LjOD*4c9{~sc$D73-?0o zgKs|^FP(ZmQ0_PSmYIx3FU+8M(UFXKkd!)wr@|OG4eGm@4z(!{!8|wv-VA5LJ7GB- z0DW*EoCUQ7v!TA5c~C9&e9K7dULAEQDedLH~>*-UD|)ozc~hNm_2+K+svd3(kVOVFla+m%+VI-_t(05$=cj zp5BBy;10kK;al(|{1f~c9)Zy`;(f^MG#^4{i}^F`2tR?hTUg`2AdE!uDP%C1&n+pt ztxrGKbSk2@YQld^BuL+Y4U7sT?#Do zEn&S9xmz+goa-dDawDCB+RtCYB6tSg4!?prn7)Sh!oNZK)trN+@I2IMZ~@MS{{!d3 z@8M(cA8-Zy5w3(f4_CoX|3dL9!X>yH{sP~Hm*IQxS6Blr+xSjF8=i%s@Ehoo@ILp4 z`@IayOqA3+>faYhTs(16Fay?uI;o?fTEke|%+^N56V^s0z`I~Wct3PQo!gC}&X8mn zWA4H@-9--%fgXs1hhf?`FhrdgcVBm>rX+U>V#|wb*#3A z+NW(~a^KeF#kg(ynhvAUD~9{O9m$wnQfdi#P)leJb74O01aE-7U?NK0-B#Wr!e7O8X!MHaKH^Bm z^dY5AXH0vKcNkmJ2l%Tt&yepk^_gX>(HXIwz8AgzWMLoH(oEQFO%7f6AV;1jSCJ_%oh zOW}U_6#N7(gBRcm_#=E8+Lq~IRw6W}uvM@*djeQBGZTHh+D)^{6JtFRsB!q;I>_y*LGybBJ3dzn}> z;Q^U@N1nRJd+u87JUj&6Fv#g zz*F!n`~`ju6KK)jU=w%_>TCKIVv)tt&f%G;-dA zUa!bnW^P9q3zxx$JgS4-4OhcPa4pnXq^ndiVO^y>a63$c)vzgi9eUvr*bE-k(?1UJGl$I7j}g@PH%=KP&3fwQTYJu0i#SkRx`buUb*&gCPY!Gy?%$$VCf~_(G;uEC?uTlo$G`+Q7U~Eug*w8=LA80~ zp_VlXwu6%;bx`Ya|IWm^vWdCc;7=oEEmBU0DexhvrfLSvheXcq4d)WR3(kkSf-Qh! z;iGUId<;GYE8q&a7`_0P)H2DlcOxuC@fKVLb$l#`I_Xx)w}aBHWT}65b2da(1$WP~ zDhH>y7@MvRUhxjjw?WZ3k1QG)C(8zRC0KQAaA!-3i$m;JJ>o6Scg-g8R*#G*&UNu# zTyJ<}ZE?11F5;UW`4n*;;z5r*v(zmuhct4{Cs^Z=q9OUN1&E(`qyq5~#A6;gintK* zv`6Ze|{rQ#Sw zS~YW6hE0o9a{vvkQSkyItx>Vj@MxRXWDd`;X^Cnkp*iOlS0hq))gD2-=#gWjv(l;} zM!0QzxLdpm-Zt%u~13283YCl^O}TPAqiuGFh~i=H~di|i?C1aAu21S$N6(c5P+a;;8Vp6_cnkpYp zDr=~<4-OyA{J|70R85F=e|>pqa-r6J&*Zf>rS9QvJ~U+k8CAI+Ot!-Q#UiY)Q~JDD zUv8WlWBp5R8JQzS-UBqyhq*q56~w`m^5=xKfJ7;>Iga+5zB%Q-pG zXVhkCRrHF&h-kPT#Pd{N&aq{&P;FTpRKKl(3@>X^9#jGIZe7C?mAV(bR8*q@|KsXfQ zEcu4Pd*FD8Yv_1q_d@pd>@kdQ9xQ=u#LZAx0qK)+-_rlH;e6N{ zV)=a?A!grK0I~T#wkhUOEub61V~|aT!I1mdOqj)x&4ghT_=dnr$mYR30Vl$xa5}_- z`5uCd5+5GFSpnz3mGDux3NC`rLcDgf8sd$cHE=mBUyp#7Z5UQQylnFl#BnwoAda$m z8R8flhMVso+z1cBO%Pw!Y=+0+7I++Ph4`#y8~h$_hq$Qh;yE2*mcI^hCCyG4UW*Ri zg%FQoH*5^|KpaA|58{`Z{Sg1nyb1B&^t{Yh2;YLZTjp)p9lir^hX)~UkU0c#gLEtB z!=*9rLR=d29>ftbHPBa!{(m3gVH6)iJPPw?_$2%Y;z$@AOW$+wGq?eM4qt}HVKqDf z_rfpWK6nbg3%`VahNt02@GJN!JPVJ*ui@#s2!BI}!WKlC4)UR|UwLbF4^6DO0qR*| zBY10oy^(VQa)0DD0eJv&c0kr`eT#tH3R&~Yg~7c3Lms%-B>qpC_`I|kzXy>M;C`Vk+joSw!8 zE2wg?lE3SbV50x4TZ6UMUTP)J&CV;&Mrz|^AN1NU88%%_{HqIw$GPhBdm$kIo!4H+ zALjKN^~iiNP&XZ#PQ!`t2iOe$2(#cnVFCOZc7hjSm#zrEAasMjLQJ}r?3^N6uphw? zSPVnqSf~Y!hg#5sFrsSJoT1i|-aRYlrMP@7tgobscV31Kfq_878LSWmFJPmc4Q?f zv(f{34k6E*7sXgv(q~?M8MEj!I}2Cqv5#F(ld3vhycJ#>6jfx~C-BuO`r^EORFUSw z=DE_na=D`OHNILgO(S{V#UpHDcP<{`!nnE)riu4)uMLVGUtwR@RK9t<%=I`CU7O12 zC7Cu@vE&Zh*Hpe+l5a0)Dw&np_Tx>Zq;g=aJ|Aq?K5{3Mqm^&-NYzrQz@<$R@6!B; zF-iXRaEzD9USL6SoNG7_PD)~HkZ(^BpX*`*kh;(pkC_7raT=TKHaH}Wx^akHs$FM>HT!1 zR(0^x8TLXR22@Xz*N}YqHOXt94yjxjsTHofGD9nz546Ih_N|N#-*HW9-^vi#L~`1& zhjg^z8$cU0d7D+y;U8U-yv?c*DP9$+%_?1$q0L$WXqF~FLGtgfNq%BgNLBPRakl+P zoOoAz6g^g-w5#JJbB!meI?n%s{2$Sltf?>K*2LNG#L2uh+4hk**|}zxy}yAJtj$o2 zURz{;+(34&Ewk--l*wM*U9IHq%Mh^R{dwuGt2a7!o)`m;G~%V~xw5eSfoK`>ahyay zA8q%K7tiyhc4@p+KA&w*iI=yZ&$oYw7kk|XyDULAuJb59SXX9$k|0IvGwl-zGIM=_ z{XdDaXMMJPcSHFOWmQA*yfDj-bj$h|O6=xtiFh$Xk^AC2ZR;LF)p1qdyja)L7F>L3 zVYt7Zmg%cU%d&dI0%}r~@p6epaa9$soUt^sDI0UirE25GDVBYT{n;k3qG(f@{k2;T zZJK2dU>t4kp~@ATmxd1r^m(KXm#Usyj#wEp!u;LwQHY<*U4A}>Ct%Snp#lBrNXg$? z6vLYBsBa29HbmBJZ4$nj6An#0L-udY%UBiR52a%pRT~vZ+cA)86+P~xt|Qsoirl|o zS~bWCuEX~O(F3BSa@z>^@Y;U$sDS#HK!tt|m)Pxt8@38Oy^bt2mxdT~IxuKyZIwC^Oyq;`( zjJS3-u_DB~vw+{>$hOSgnPP>>`knXc|C&@KzR}&X&Q%TB)yxWgfPWS@R zjO1qyy0i6@^_A%MdM4q2x+X#OnL~$8dSHU)7H^t6xz;4eHwXJ!Bc$L^o|P?A4&}+` zhw4c6p>(Qq>`-g#dZ~LjN2VRFBRvndvht+taGrckXcwXO@(rN@N9st+Bdx3w8F(bm z8Y-3i4wFMiT3Ey7$0IM0!!z&ZNz~Cga^hXhq3+QhL1UXG++702+F5<>L@*SC&NKL<^8B>l${ z<_0v`!+8K3h= z9OJsiDNfIG$2pRoG~VgN>iJ;4Bk8H$XHM4qAHkjziRH~6e1yT++Mh4)@;Y@OoXaxJ z9#qR3uJeKGw{iO!GM)TUzl&4rq}Eig-#(`%)Emrm_-_g9y;*a8* z6W782*l!ACcj}g%U$_V8AyhC)poBm%CiWC@Qv#3IGH3C~{1?@XRjWupJJ)aG%y8mr z%flxVbn%^e(j7YKiUPkt6|=7>SZ`HPc}0OofI@s8X)y{L&q|Ifb(Y+5BZ!4alH4`TsGmkN$96&zbCII>i5TnR$;RP`NMaylXO zAkuXC;!J|Nh{w((rrkP7Jy&(G^@=b92Kgl&!ki2c*FgGwl@PidskTZsM~+2bxkEPu z6``90QiC4ThgKu2cdl2YnLgAnX=c-hrhEPWL-hN&&>uPw=NM5UqfF=za`vl6Hvezv zI(xa+|MNeM=h}qWM_NnKg?Rf&gp9b5nKg+FCUawnoQm8J$8eA4F6DlJdmQ(8ZnfSM xtKPbBuN6~_crQ1HKYHL}O62 Date: Thu, 27 Apr 2017 23:39:21 +1000 Subject: [PATCH 0025/2058] CustomBuildTool: Add release builds, Fix build_release.cmd, Improve nightly builds --- appveyor.yml | 2 +- build/build_binaries.cmd | 6 - tools/CustomBuildTool/Source Files/Build.cs | 42 +++++- tools/CustomBuildTool/Source Files/Program.cs | 139 +++++++----------- .../bin/Release/CustomBuildTool.exe | Bin 145920 -> 146432 bytes .../bin/Release/CustomBuildTool.pdb | Bin 62976 -> 65024 bytes 6 files changed, 96 insertions(+), 93 deletions(-) delete mode 100644 build/build_binaries.cmd diff --git a/appveyor.yml b/appveyor.yml index 4ad9645b488a..1eb83fda0bb2 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -28,7 +28,7 @@ test: off # Run custom build script. build_script: -- cmd: tools\CustomBuildTool\bin\Release\CustomBuildTool.exe +- cmd: tools\CustomBuildTool\bin\Release\CustomBuildTool.exe -appveyor # Setup build notifications. notifications: diff --git a/build/build_binaries.cmd b/build/build_binaries.cmd deleted file mode 100644 index 2d17641e43e2..000000000000 --- a/build/build_binaries.cmd +++ /dev/null @@ -1,6 +0,0 @@ -@echo off - -start /B /W "" "..\tools\CustomBuildTool\bin\Release\CustomBuildTool.exe" "-bin" -start /B /W "" "..\tools\CustomBuildTool\bin\Release\CustomBuildTool.exe" "-exe" - -pause diff --git a/tools/CustomBuildTool/Source Files/Build.cs b/tools/CustomBuildTool/Source Files/Build.cs index 00a9b2533dbb..d88bfd38394f 100644 --- a/tools/CustomBuildTool/Source Files/Build.cs +++ b/tools/CustomBuildTool/Source Files/Build.cs @@ -181,6 +181,8 @@ public static bool InitializeBuildEnvironment(bool CheckDependencies) public static void CleanupBuildEnvironment() { + Program.PrintColorMessage("Cleaning up build environment...", ConsoleColor.Cyan); + try { @@ -193,6 +195,8 @@ public static void CleanupBuildEnvironment() public static void ShowBuildEnvironment(bool ShowBuildInfo) { + Program.PrintColorMessage("Setting up build environment...", ConsoleColor.Cyan); + string currentGitTag = Win32.ExecCommand(GitExePath, "describe --abbrev=0 --tags --always"); string latestGitRevision = Win32.ExecCommand(GitExePath, "rev-list --count \"" + currentGitTag + ".." + BuildBranch + "\""); @@ -257,6 +261,8 @@ public static void ShowBuildStats(bool block) public static bool CopyTextFiles() { + Program.PrintColorMessage("Copying text files...", ConsoleColor.Cyan); + try { File.Copy("README.md", "bin\\README.txt", true); @@ -275,6 +281,8 @@ public static bool CopyTextFiles() public static bool CopyKProcessHacker(bool DebugBuild) { + Program.PrintColorMessage("Copying KPH driver...", ConsoleColor.Cyan); + try { if (DebugBuild) @@ -299,6 +307,8 @@ public static bool CopyKProcessHacker(bool DebugBuild) public static bool CopyLibFiles(bool DebugBuild) { + Program.PrintColorMessage("Copying Plugin SDK linker files...", ConsoleColor.Cyan); + try { if (DebugBuild) @@ -323,6 +333,8 @@ public static bool CopyLibFiles(bool DebugBuild) public static bool CopyWow64Files(bool DebugBuild) { + Program.PrintColorMessage("Copying Wow64 support files...", ConsoleColor.Cyan); + try { if (DebugBuild) @@ -361,6 +373,8 @@ public static bool CopyWow64Files(bool DebugBuild) public static bool CopyPluginSdkHeaders() { + Program.PrintColorMessage("Copying Plugin SDK headers...", ConsoleColor.Cyan); + try { foreach (string folder in sdk_directories) @@ -400,6 +414,8 @@ public static bool CopyPluginSdkHeaders() public static bool CopyVersionHeader() { + Program.PrintColorMessage("Copying Plugin SDK version header...", ConsoleColor.Cyan); + try { HeaderGen gen = new HeaderGen(); @@ -422,6 +438,8 @@ public static bool CopyVersionHeader() public static bool FixupResourceHeader() { + Program.PrintColorMessage("Building Plugin SDK resource header...", ConsoleColor.Cyan); + try { string phappContent = File.ReadAllText("sdk\\include\\phappresource.h"); @@ -446,6 +464,8 @@ public static bool BuildKphSignatureFile(bool DebugBuild) { string output; + Program.PrintColorMessage("Building KPH signature...", ConsoleColor.Cyan); + if (!File.Exists(CustomSignToolPath)) { Program.PrintColorMessage("[SKIPPED] CustomSignTool not found.", ConsoleColor.Yellow); @@ -572,11 +592,13 @@ public static bool BuildSecureFiles() public static bool BuildSetupExe() { + Program.PrintColorMessage("Building build-setup.exe...", ConsoleColor.Cyan); + + if (!BuildSolution("tools\\CustomSetupTool\\CustomSetupTool.sln", false, false, false)) + return false; + try { - if (!BuildSolution("tools\\CustomSetupTool\\CustomSetupTool.sln", false, false, false)) - return false; - if (File.Exists(BuildOutputFolder + "\\processhacker-build-setup.exe")) File.Delete(BuildOutputFolder + "\\processhacker-build-setup.exe"); @@ -596,6 +618,8 @@ public static bool BuildSetupExe() public static bool BuildSdkZip() { + Program.PrintColorMessage("Building build-sdk.zip...", ConsoleColor.Cyan); + try { if (File.Exists(BuildOutputFolder + "\\processhacker-build-sdk.zip")) @@ -614,6 +638,8 @@ public static bool BuildSdkZip() public static bool BuildBinZip() { + Program.PrintColorMessage("Building build-bin.zip...", ConsoleColor.Cyan); + try { if (File.Exists(BuildOutputFolder + "\\processhacker-build-bin.zip")) @@ -643,6 +669,8 @@ public static bool BuildBinZip() public static bool BuildSrcZip() { + Program.PrintColorMessage("Building build-src.zip...", ConsoleColor.Cyan); + if (!File.Exists(GitExePath)) { Program.PrintColorMessage("[SKIPPED] Git not installed.", ConsoleColor.Yellow); @@ -702,6 +730,8 @@ public static bool BuildPdbZip() public static bool BuildChecksumsFile() { + Program.PrintColorMessage("Building build-checksums.txt...", ConsoleColor.Cyan); + try { if (File.Exists(BuildOutputFolder + "\\processhacker-build-checksums.txt")) @@ -735,6 +765,8 @@ public static bool BuildChecksumsFile() public static bool BuildUpdateSignature() { + Program.PrintColorMessage("Building release signature...", ConsoleColor.Cyan); + if (!File.Exists(CustomSignToolPath)) { Program.PrintColorMessage("[SKIPPED] CustomSignTool not found.", ConsoleColor.Yellow); @@ -901,6 +933,8 @@ public static bool AppveyorUploadBuildFiles() public static bool UpdateHeaderFileVersion() { + Program.PrintColorMessage("Updating Process Hacker build revision...", ConsoleColor.Cyan); + try { if (File.Exists("ProcessHacker\\include\\phapprev.h")) @@ -926,6 +960,8 @@ public static bool UpdateHeaderFileVersion() public static bool BuildPublicHeaderFiles() { + Program.PrintColorMessage("Building public SDK headers...", ConsoleColor.Cyan); + try { HeaderGen gen = new HeaderGen(); diff --git a/tools/CustomBuildTool/Source Files/Program.cs b/tools/CustomBuildTool/Source Files/Program.cs index 49825dc49032..18ec017a966b 100644 --- a/tools/CustomBuildTool/Source Files/Program.cs +++ b/tools/CustomBuildTool/Source Files/Program.cs @@ -28,7 +28,7 @@ public static void Main(string[] args) if (!Build.InitializeBuildEnvironment(false)) return; - PrintColorMessage("Cleanup build...", ConsoleColor.Cyan); + Build.CleanupBuildEnvironment(); return; } @@ -37,7 +37,6 @@ public static void Main(string[] args) if (!Build.InitializeBuildEnvironment(false)) return; - PrintColorMessage("Updating header version...", ConsoleColor.Cyan); Build.ShowBuildEnvironment(false); Build.UpdateHeaderFileVersion(); return; @@ -47,7 +46,6 @@ public static void Main(string[] args) if (!Build.InitializeBuildEnvironment(false)) return; - PrintColorMessage("Building public headers...", ConsoleColor.Cyan); Build.BuildPublicHeaderFiles(); return; } @@ -58,23 +56,18 @@ public static void Main(string[] args) } else if (ProgramArgs.ContainsKey("-sdk")) { - PrintColorMessage("Setting up build environment...", ConsoleColor.Cyan); if (!Build.InitializeBuildEnvironment(false)) return; - PrintColorMessage("Copying Plugin SDK headers...", ConsoleColor.Cyan); if (!Build.CopyPluginSdkHeaders()) return; - PrintColorMessage("Copying Plugin SDK version header...", ConsoleColor.Cyan); if (!Build.CopyVersionHeader()) return; - PrintColorMessage("Building Plugin SDK resource header...", ConsoleColor.Cyan); if (!Build.FixupResourceHeader()) return; - PrintColorMessage("Copying Plugin SDK linker files...", ConsoleColor.Cyan); if (!Build.CopyLibFiles(false)) return; @@ -83,26 +76,21 @@ public static void Main(string[] args) } else if (ProgramArgs.ContainsKey("-cleansdk")) { - PrintColorMessage("Setting up build environment...", ConsoleColor.Cyan); if (!Build.InitializeBuildEnvironment(false)) return; if (!Build.BuildSolution("ProcessHacker.sln", true, false, true)) return; - - PrintColorMessage("Copying Plugin SDK headers...", ConsoleColor.Cyan); + if (!Build.CopyPluginSdkHeaders()) return; - PrintColorMessage("Copying Plugin SDK version header...", ConsoleColor.Cyan); if (!Build.CopyVersionHeader()) return; - PrintColorMessage("Building Plugin SDK resource header...", ConsoleColor.Cyan); if (!Build.FixupResourceHeader()) return; - PrintColorMessage("Copying Plugin SDK linker files...", ConsoleColor.Cyan); if (!Build.CopyLibFiles(false)) return; @@ -111,7 +99,6 @@ public static void Main(string[] args) } else if (ProgramArgs.ContainsKey("-bin")) { - PrintColorMessage("Setting up build environment...", ConsoleColor.Cyan); if (!Build.InitializeBuildEnvironment(false)) return; @@ -120,66 +107,41 @@ public static void Main(string[] args) if (!Build.BuildSolution("ProcessHacker.sln", true, false, true)) return; - - PrintColorMessage("Building KPH signature...", ConsoleColor.Cyan); + if (!Build.BuildKphSignatureFile(false)) return; - PrintColorMessage("Copying text files...", ConsoleColor.Cyan); if (!Build.CopyTextFiles()) return; - PrintColorMessage("Copying KPH driver...", ConsoleColor.Cyan); if (!Build.CopyKProcessHacker(false)) return; - - PrintColorMessage("Copying Plugin SDK headers...", ConsoleColor.Cyan); + if (!Build.CopyPluginSdkHeaders()) return; - PrintColorMessage("Copying Plugin SDK version header...", ConsoleColor.Cyan); if (!Build.CopyVersionHeader()) return; - PrintColorMessage("Building Plugin SDK resource header...", ConsoleColor.Cyan); if (!Build.FixupResourceHeader()) return; + if (!Build.CopyLibFiles(false)) return; + if (!Build.BuildSolution("plugins\\Plugins.sln", true, false, true)) return; + if (!Build.CopyWow64Files(false)) return; - - PrintColorMessage("Building build-bin.zip...", ConsoleColor.Cyan); + if (!Build.BuildBinZip()) return; Build.ShowBuildStats(false); } - else if (ProgramArgs.ContainsKey("-exe")) - { - PrintColorMessage("Setting up build environment...", ConsoleColor.Cyan); - if (!Build.InitializeBuildEnvironment(false)) - return; - - PrintColorMessage("Building build-bin.zip...", ConsoleColor.Cyan); - if (!Build.BuildBinZip()) - return; - - PrintColorMessage("Building build-setup.exe...", ConsoleColor.Cyan); - if (!Build.BuildSetupExe()) - return; - - PrintColorMessage("Building build-sdk.zip...", ConsoleColor.Cyan); - Build.BuildSdkZip(); - - PrintColorMessage("Building build-src.zip...", ConsoleColor.Cyan); - Build.BuildSrcZip(); - } else if (ProgramArgs.ContainsKey("-debug")) { - PrintColorMessage("Setting up build environment...", ConsoleColor.Cyan); if (!Build.InitializeBuildEnvironment(true)) return; @@ -189,110 +151,121 @@ public static void Main(string[] args) if (!Build.BuildSolution("ProcessHacker.sln", true, true, true)) return; - PrintColorMessage("Building KPH signature...", ConsoleColor.Cyan); if (!Build.BuildKphSignatureFile(true)) return; - - PrintColorMessage("Copying text files...", ConsoleColor.Cyan); if (!Build.CopyTextFiles()) return; - - PrintColorMessage("Copying KPH driver...", ConsoleColor.Cyan); if (!Build.CopyKProcessHacker(true)) return; - PrintColorMessage("Copying Plugin SDK headers...", ConsoleColor.Cyan); if (!Build.CopyPluginSdkHeaders()) return; - - PrintColorMessage("Copying Plugin SDK version header...", ConsoleColor.Cyan); if (!Build.CopyVersionHeader()) return; - - PrintColorMessage("Building Plugin SDK resource header...", ConsoleColor.Cyan); if (!Build.FixupResourceHeader()) return; - - PrintColorMessage("Copying Plugin SDK linker files...", ConsoleColor.Cyan); if (!Build.CopyLibFiles(true)) return; if (!Build.BuildSolution("plugins\\Plugins.sln", true, true, true)) return; - PrintColorMessage("Copying Wow64 support files...", ConsoleColor.Cyan); if (!Build.CopyWow64Files(true)) return; Build.ShowBuildStats(true); } - else // release + else if (ProgramArgs.ContainsKey("-release")) { - if (!Build.InitializeBuildEnvironment(true)) + if (!Build.InitializeBuildEnvironment(false)) return; - PrintColorMessage("Setting up build environment...", ConsoleColor.Cyan); - Build.ShowBuildEnvironment(true); + Build.ShowBuildEnvironment(false); Build.BuildSecureFiles(); if (!Build.BuildSolution("ProcessHacker.sln", true, false, true)) return; - PrintColorMessage("Building KPH signature...", ConsoleColor.Cyan); if (!Build.BuildKphSignatureFile(false)) return; - - PrintColorMessage("Copying text files...", ConsoleColor.Cyan); if (!Build.CopyTextFiles()) return; - - PrintColorMessage("Copying KPH driver...", ConsoleColor.Cyan); if (!Build.CopyKProcessHacker(false)) return; - PrintColorMessage("Copying Plugin SDK headers...", ConsoleColor.Cyan); if (!Build.CopyPluginSdkHeaders()) return; - - PrintColorMessage("Copying Plugin SDK version header...", ConsoleColor.Cyan); if (!Build.CopyVersionHeader()) return; - - PrintColorMessage("Building Plugin SDK resource header...", ConsoleColor.Cyan); if (!Build.FixupResourceHeader()) return; - - PrintColorMessage("Copying Plugin SDK linker files...", ConsoleColor.Cyan); if (!Build.CopyLibFiles(false)) return; if (!Build.BuildSolution("plugins\\Plugins.sln", true, false, true)) return; - PrintColorMessage("Copying Wow64 support files...", ConsoleColor.Cyan); if (!Build.CopyWow64Files(false)) return; - PrintColorMessage("Building build-bin.zip...", ConsoleColor.Cyan); if (!Build.BuildBinZip()) return; + if (!Build.BuildSetupExe()) + return; + + Build.BuildSdkZip(); - PrintColorMessage("Building build-setup.exe...", ConsoleColor.Cyan); + Build.BuildSrcZip(); + } + else if (ProgramArgs.ContainsKey("-appveyor")) + { + if (!Build.InitializeBuildEnvironment(false)) + return; + + Build.ShowBuildEnvironment(false); + Build.BuildSecureFiles(); + + if (!Build.BuildSolution("ProcessHacker.sln", true, false, true)) + return; + + if (!Build.BuildKphSignatureFile(false)) + return; + if (!Build.CopyTextFiles()) + return; + if (!Build.CopyKProcessHacker(false)) + return; + + if (!Build.CopyPluginSdkHeaders()) + return; + if (!Build.CopyVersionHeader()) + return; + if (!Build.FixupResourceHeader()) + return; + if (!Build.CopyLibFiles(false)) + return; + + if (!Build.BuildSolution("plugins\\Plugins.sln", true, false, true)) + return; + + if (!Build.CopyWow64Files(false)) + return; + + if (!Build.BuildBinZip()) + return; if (!Build.BuildSetupExe()) return; - PrintColorMessage("Building build-checksums.txt...", ConsoleColor.Cyan); if (!Build.BuildChecksumsFile()) return; - - PrintColorMessage("Building release signature...", ConsoleColor.Cyan); if (!Build.BuildUpdateSignature()) return; if (Build.AppveyorUploadBuildFiles()) Build.WebServiceUpdateConfig(); - - Build.ShowBuildStats(true); + } + else + { + Console.WriteLine("Invalid arguments.\n"); } } diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe b/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe index dd4aa7b45ed7243863358566d66f557b2cbd62bb..88f5b94a10f31fb1fa25c3bcd41f229babb8d33b 100644 GIT binary patch delta 15584 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 delta 14797 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 diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb b/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb index f6216abb3bf3c1cdf615036245ef3bda716aa2b7..8020ab3344ec8af60c2fe10087ccab8d395c561e 100644 GIT binary patch delta 11474 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 delta 11269 zcmcKAd3Y4Xy1?P;P9`RhU?#!LkdOcgnLt=WLV&O(fPl!p?-IfuWEa`fh$5mQ@S!ZS zg;h}y7~GX3iaRcFjvi4#QAFGjJTAwT`}=w(8h!4)&$)lx=IME>tE;Q3yQ`|JJ2<~Y zIA2DrtQRxi7&F}FCun{DhIP=s(zgB`wCs!4!Klbcf6+N>h{ewGm2*42^?70U2aeVM zB+eVVELgKj!`SM(e0|H7mS6E@(1~AgaapVDbFZ2F%YmXD)h?Sv(LK1y8GJ5>s^-;6x& z&;4GiH|QTZtj(;n;N%8{wq?oQMmPHJ(aMCE2xFpJv8_>Z;8|aSNiq@M>YU30c4^91 zGPZGv^`^Ys_*VOCOZqms$$CTHYLdn8uT7?UM^@y79y0493!7%7YHSxW&}=osHIc@= z&+2FUHhH>fskeks#S+DFJEc`lR+`4{taMy|vfRk3$9)+gi*hFY>A)*EFj{`h$?)ib z(Nd?G&*~)$b4p}mvuN+-iu`pSDNE(yW*HuhEtONve0EQd9Bw*PdgsP_k5)<=L()ky zJ-2~JV<$;@uFsk!kLR|qHp->k7WPSxWas5u)ucGD)O$mv1FLXgV>y+Vm8!9gIjf4( z|2M@KlJ6jmmpaXJ?OUVd^$tU2fAjc+9+k4FN*3FrzU~DUXXB--#lcxbc#l z-_HI=lr(OwClD=9r;Sk5yqYO=XF-oFZ%(Fj&QRF*QP{cs>|xd9^|pvr+utE)7~RRg#Cq~@Yr@KG3A`A zRwP-93KL~xJHK~#I3~^1_R^C~tUTYYi8p}?hALd!OFtoYdfv6tyM1k|flP0o>unI; zpUzQQpE!BAeTEe$C)+pi9;9SBjG%f1t*IrVw__%mS!YQTBt10q8 zQCyTJIO3JVMM?G#Kp$?}A>Lb1aSYNTqx{mRLj#Y-`ektkpY2bO4IP@DDpe?VAw3&f)7*O%`{|@V;FsR?oDWJlt`rJup#v1`C3tIz48^)g`tiyDa@D*0{v7 zXN+-TOcnDDdnT|aG^$$e7)q3>$vRv!V_{&?)@7c@Zulbh#g|Zr&R1|E9>azB8m_`O za4jCkP55`*fo~a8<{TpMHW82DNhEXgE)r+n!*h5VzsC>o3M%svUWsQhfS+I!JddsM zbL@&=-~haUqw#B;jhFBi{1+$g+)aSY9U0tZ4o`>UT~cy>VpC7_7rY98#bNjxjztDz zXL{Hh(MW37jJTBqLQfCNjFba?6T3%Qp?s*bQ=7ff*c4;15UXGZtco2m4hLd29Ex5X zjtMA_b!`}T9~+?ujb%#Y%)rFqes*bFPew)slY$vo6Em?EHpkj{HKwEXh79bAnW(46 zWpu8?`dEzFD3h)EW<&#+?Ww&FoAoBVE*Hj<1jpcbOh%Jj=M&pIAe{-sYw|SzO8;MWC zxtJQ>Unjgj3l|Zu4NQ+~7T#`&4)NNsG@b@E)=gMK#1eK~AKo!FygeJ~9nP9?{DyG+ zHoTSi9k>j4;c|QeZ^ysk3Os^$p{(mZLAG8K855dQSmp+~)HQJo{ms#lmRXwP#kJ_e z^{D5t0bAg`sLf_04#G`11UI90j;*LwFGszbJ5cZDPL!2BTDtu)G!?N-54S%)z%J$y zW-n^XeF*E~0c?Un%)vvbm+ukOPV*>UgHPbK_#{eU&xU37Y@LyW?xW65bZN+1lXzW@ zkdSAyc@Fjd9>o-V5%pYO#yorl^YJxogKwbr&f_=$PoQ3dw@`1}KXDqPr+J6K3?kmc zMfg50!&9jD?=)`44{b05e6*3qV9tFjpW~$wcD|SQR-5 z6Ngm7R6{CZ5-?7_>-DHR2kf0(<|9G}0YB;`t${r;1@#hgOWaGChS#xO8z*BOoPrss zEk6^NU;uAHZn1MGW~26m2DlNmE9t|mDcfAx-X@2@(?m4G*Dx2~z&v~t^HB$h7I+>D zkO!4%jd5nVi8BuCYSvoDYf@!xpFU+;P-yCEnOTH&(FVNI4KZ|btd4*kP#bh7tdCb? zTkK++CED+=WqUAoN9{vBQBS@X(vD1D)MnHVy=H>B%A`|=!BW;YGwx>MJ2MFBoS|5( z2NQb@AypEwLopk9hjbrbBT&1`NbHQGP)jSu5jY0*(vL;28AvGuDP@AR@0Kb}heyWj z4wv$(6!lLmDPZ@vO((kTFY1sJ(m{YA?SHwU=uX zsfjDt*5TwX)a$YmwRf*V9aaQ~;~E@=Yi)C@UiGbP-(gIu*+yUs5!H4_W5K6b_i$ZX0q!V%a6b>f_Z3o#dYH=;flH=#@$R?p4apAhO71#Z^c*%d{S9jG(4o#?||sLgaYYBRkb zb$r`{TI61AiThBZhc_$>y{=j&lJn3-Gt)s;mxCmVz(ZIYA4VOP9>D^9Ji;s)gNNCk zjL%>h9>K+U6mP~CupD2+efSbSiLXSMv?ZSqc!P+q@HpxnJ%Nlc=50AXycciD!SoT& zTB}FZwN^>ysMh=zkD70-3Z5F(#j@>y1V*>BV*)a6bb%cokZq&$ZC^m%g|vWdUY9Hl zOKRJh0qI%N&Tbfx6_6W{*P$RF)y5P=7txU^%}CDciSlVloJ?>#A z2V*krfdPpcn^t3BINtrZ$wlHC869LlmbPP`)JiQHmn_xC#cRbhSV)k{X>c+@D!6D| zwpLJMjuJx!HF%LAmDFI(@$p*G#^bZKq8c-cn4(Z{D?zHLvBwDZ3dm{F4GaXUOh~rv zpHd_+DP8F{=@IKHu}ZVNRe0X%Stj#gLcK~_mCm%=)RcXtf%9&d#+SmG!e*ThGZ`vu~$b#WxPqiX6Uin-+HX#$;JAXPLD>=$Tu~ie8x-z8rmy zCrbNyUVCLKH>R1~Jg-w`ZM_#PyF4NFcP`JFz2Rd_kK&0_rqwh9k(c(^-#fcme#zpjo#t%!MSYCWfShhP5C`EPybcHBDCEjJQ;~^>GYv+i#KC8yOgsWS0OWU-oUs-NP}@U;2OLa z@5ViN4?civF^KE%5YnKWBX}<|>opsZS+CiQ%xcXRWL9go;u+jV`*WB)n(ah6txP18J}hGdlAi*1>()7$3qsJb*<=gLb+g4ch67hmiS@c?6l( zm`7=U4$}+w6>h2P^|`~mmjkN9LH*Z(I1&k^x69>rhrIR1w3;AK3C z7N1YfArltoD`aqSE}#d0#wfHsyfI(|#$Y^FK|fZ-8W@N5uo~7cBM?s@9~qsTc9?+e zk-4tZ9k0TEn1uRgO-3)L7?}e*6EGPkVojWlys9}1F%1`CZM+@p;A%`q!Mb?W1_GG` zwqO?S#QJjPrmLEFV~&`^>Ng3d4YuQBK~3z>n#)?TuYKixQfo;{*^o*xgWS}iBS#W$ z8qQ@D;b!6R@JjKG2y2P0v2s3r!)gD6{L0LKmtp>2GSpMZX06D$AK_NvLV6KySSg(U zpBK&v%C}3B255HK;lmp7L8%(&^w%m>PBWlVks6=L8ZvZjOSXqd%FQWd8r!l`ERTH+O~s$qbW#wSP+9K8iA|HpdQk%`jcENT3CpDdJ z`}HZz$5;1LKpy6>gGqwZ4qIRmw#1Iu8arcKWK!Y&v84~TXS*MEz){!{d6v5cO-C(= zXSC@WT)eczTD`2UZDmSeS+>%1M!MWFsk$s%wjeq$Gd$a@b0S5uZu8oCnNo1uK6_-Q ze12PFYn;?r{y>c7CbCSfSl1`Yhsz5|6->X~j)-2$RL-IpDdzAlE4t&GjmRyq7)+uSUCfE8zir2VDyuRiIYklzUyYJ!!rlthe74Y9nir2NaVq_D) z@p5uqYuleHN$U%$)JhG{fM-hDdR~my`|Ye$S+TyrZk#HwKz^!3Z78tYrb-96I#m{J z$hW(v$|KM}RW1-YELF1aEwD>cWgJXOm2EI1RZicVZ_lNejrsQCROz{~z+RRr%Qx~m z#kjW^ipFl_o0}q6 zZ;sXKRok3xwRPkAZ;p3sNJ3|Gyw%-}bT&uIeo|7|!=xPMMn-Ol*ZOLfO}E5blibLr zTOwuDmRPO&lr7oTTsQI%DXG1t{E(E(+{h2NLcM0s#mtUS0q)>~W=%gZ1SHgl!CynUuU&?oJ7WP1nt!iR+4 z6uBU~Qe@fASlPP6?=21QO=2&z1`{tY?Y-`Ps}sXF51mn)wZA8f@b)H-ZzJ?p zW<gT4JJD_b1A<`(nK}g!gFvJYU&!=Y37QOOr!+YWiq5 z_O<&myq7A)Rte`)%iA^OkF$w&V{`7GX_u$SuKP#Zhf}1=o^0>oaGHubR+p>yWJt@> zSZ;N+EZ9@1?cng9Y#KoD^F7rpy`w)puw3uX(g(NMpZS8>dq-Q=mBBmreQIgmv-jtd zcW~eS*_J(rj(RYl^gK9F>dlXp{RjQtMK%AZmR@Y1oIE(wzCfa2H%+@Ccu&j)H;u)A zFyTKt1iK$P=CzIoYrL?ws#RAG9QRpugD)Q+6fJd6#moMuqwQ9f^!zB{QvS5h zqx0vHZitUx{K;M8^snKekp7YSvKyy=%suLc^pBl4xFP-9V-Gi^e&%im@A@OT(8X?){{7=sH>7`U*y)D!%YIikq+j6|$gl6UqH?nTbTX}pzje9G zSsC%Zz7uJ*Jo0|0ieSkDGjH}q$?1OMjvh4d{T{t#2 z!Azi)>eAaUQ$B22k^0#WyH*4PXMWFh=^w#!XBvC-W4q&?!mw)0@%1|J)wjn-DV`%V z=Rxis{qR`ehV)xuq^8mTxN`WT<~QCA z``vIYH=N~$8@u6rH{8|@U+spwyW#$Bc$gb5al@0`@C-LR*9|Xr!^+sT=X`v~+Iud=6IIuk0dnA+&!b<=+z=nVtWRsSiCL@@huqL9nJfNs zzB=>Zh0$I9ypPu-zPx^#te-;_K7}fL237bBs_+R^(QmZCr%#1Xp9-Hn6+U??eC`B~ zeuRBVR(GPS7?~gg3rSNUB2fvp!?1`$c z*Pnf!I6~LU5mL>Qr`f+sPJY(F+7|SDemUZQ`LDJYnnv1psy2fg zSs7ByR92n5O<|qPI!*R|;|sp@%@`|gG@He&qgYF%)wdZ3I_ Date: Thu, 27 Apr 2017 23:43:05 +1000 Subject: [PATCH 0026/2058] Update build binaries --- .../bin/Release/CustomBuildTool.exe | Bin 146432 -> 145408 bytes .../bin/Release/CustomBuildTool.pdb | Bin 65024 -> 62976 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe b/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe index 88f5b94a10f31fb1fa25c3bcd41f229babb8d33b..8f33b1499a7fd4f9a9e0be7dcd40113f12acb90f 100644 GIT binary patch delta 8323 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 diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb b/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb index 8020ab3344ec8af60c2fe10087ccab8d395c561e..4af7deeb1bc7bfead1e9aaca9a28d36726076a59 100644 GIT binary patch delta 4078 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 delta 4376 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 Date: Fri, 28 Apr 2017 02:10:59 +1000 Subject: [PATCH 0027/2058] peview: Improve module import(s) enumeration --- phlib/include/mapimg.h | 2 +- phlib/mapimg.c | 42 +++++++++++++++++++++--------------------- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/phlib/include/mapimg.h b/phlib/include/mapimg.h index 306704dfb44c..608e652ce5a8 100644 --- a/phlib/include/mapimg.h +++ b/phlib/include/mapimg.h @@ -219,7 +219,7 @@ typedef struct _PH_MAPPED_IMAGE_IMPORT_DLL PIMAGE_IMPORT_DESCRIPTOR Descriptor; PIMAGE_DELAYLOAD_DESCRIPTOR DelayDescriptor; }; - PVOID *LookupTable; + PVOID LookupTable; } PH_MAPPED_IMAGE_IMPORT_DLL, *PPH_MAPPED_IMAGE_IMPORT_DLL; typedef struct _PH_MAPPED_IMAGE_IMPORT_ENTRY diff --git a/phlib/mapimg.c b/phlib/mapimg.c index 4366e633d1df..e093378073d2 100644 --- a/phlib/mapimg.c +++ b/phlib/mapimg.c @@ -949,11 +949,11 @@ NTSTATUS PhGetMappedImageImportDll( } else { - ImportDll->DelayDescriptor = &((PIMAGE_DELAYLOAD_DESCRIPTOR)Imports->DelayDescriptorTable)[Index]; + ImportDll->DelayDescriptor = &Imports->DelayDescriptorTable[Index]; ImportDll->Name = PhMappedImageRvaToVa( ImportDll->MappedImage, - ((PIMAGE_DELAYLOAD_DESCRIPTOR)ImportDll->DelayDescriptor)->DllNameRVA, + ImportDll->DelayDescriptor->DllNameRVA, NULL ); @@ -964,7 +964,7 @@ NTSTATUS PhGetMappedImageImportDll( ImportDll->LookupTable = PhMappedImageRvaToVa( ImportDll->MappedImage, - ((PIMAGE_DELAYLOAD_DESCRIPTOR)ImportDll->DelayDescriptor)->ImportNameTableRVA, + ImportDll->DelayDescriptor->ImportNameTableRVA, NULL ); } @@ -978,9 +978,9 @@ NTSTATUS PhGetMappedImageImportDll( if (ImportDll->MappedImage->Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) { - PULONG entry; + PIMAGE_THUNK_DATA32 entry; - entry = (PULONG)ImportDll->LookupTable; + entry = (PIMAGE_THUNK_DATA32)ImportDll->LookupTable; __try { @@ -989,10 +989,10 @@ NTSTATUS PhGetMappedImageImportDll( PhpMappedImageProbe( ImportDll->MappedImage, entry, - sizeof(ULONG) + sizeof(IMAGE_THUNK_DATA32) ); - if (*entry == 0) + if (entry->u1.AddressOfData == 0) break; entry++; @@ -1006,9 +1006,9 @@ NTSTATUS PhGetMappedImageImportDll( } else if (ImportDll->MappedImage->Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) { - PULONG64 entry; + PIMAGE_THUNK_DATA64 entry; - entry = (PULONG64)ImportDll->LookupTable; + entry = (PIMAGE_THUNK_DATA64)ImportDll->LookupTable; __try { @@ -1017,10 +1017,10 @@ NTSTATUS PhGetMappedImageImportDll( PhpMappedImageProbe( ImportDll->MappedImage, entry, - sizeof(ULONG64) + sizeof(IMAGE_THUNK_DATA64) ); - if (*entry == 0) + if (entry->u1.AddressOfData == 0) break; entry++; @@ -1055,15 +1055,15 @@ NTSTATUS PhGetMappedImageImportEntry( if (ImportDll->MappedImage->Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) { - ULONG entry; + IMAGE_THUNK_DATA32 entry; - entry = ((PULONG)ImportDll->LookupTable)[Index]; + entry = ((PIMAGE_THUNK_DATA32)ImportDll->LookupTable)[Index]; // Is this entry using an ordinal? - if (entry & IMAGE_ORDINAL_FLAG32) + if (IMAGE_SNAP_BY_ORDINAL32(entry.u1.Ordinal)) { Entry->Name = NULL; - Entry->Ordinal = (USHORT)IMAGE_ORDINAL32(entry); + Entry->Ordinal = (USHORT)IMAGE_ORDINAL32(entry.u1.Ordinal); return STATUS_SUCCESS; } @@ -1071,22 +1071,22 @@ NTSTATUS PhGetMappedImageImportEntry( { importByName = PhMappedImageRvaToVa( ImportDll->MappedImage, - entry, + entry.u1.AddressOfData, NULL ); } } else if (ImportDll->MappedImage->Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) { - ULONG64 entry; + IMAGE_THUNK_DATA64 entry; - entry = ((PULONG64)ImportDll->LookupTable)[Index]; + entry = ((PIMAGE_THUNK_DATA64)ImportDll->LookupTable)[Index]; // Is this entry using an ordinal? - if (entry & IMAGE_ORDINAL_FLAG64) + if (IMAGE_SNAP_BY_ORDINAL64(entry.u1.Ordinal)) { Entry->Name = NULL; - Entry->Ordinal = (USHORT)IMAGE_ORDINAL64(entry); + Entry->Ordinal = (USHORT)IMAGE_ORDINAL64(entry.u1.Ordinal); return STATUS_SUCCESS; } @@ -1094,7 +1094,7 @@ NTSTATUS PhGetMappedImageImportEntry( { importByName = PhMappedImageRvaToVa( ImportDll->MappedImage, - (ULONG)entry, + (ULONG)entry.u1.AddressOfData, NULL ); } From 35e5b6d69f8aea92898ece4a0c775f21b52a3d46 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 28 Apr 2017 02:58:44 +1000 Subject: [PATCH 0028/2058] Sync minor changes --- .gitignore | 40 +++++----------------------------------- ProcessHacker.sln | 13 +------------ phlib/mapimg.c | 18 +++--------------- phnt/include/ntrtl.h | 11 +++++++++++ 4 files changed, 20 insertions(+), 62 deletions(-) diff --git a/.gitignore b/.gitignore index d8d3deaf0cc8..7f672b4c792c 100644 --- a/.gitignore +++ b/.gitignore @@ -2,13 +2,9 @@ ## Visual Studio ################# -## Ignore Visual Studio temporary files, build results, and -## files generated by popular Visual Studio add-ons. - # User-specific files *.suo *.user -*.sln.docstates *.key # Build results @@ -28,11 +24,8 @@ *.tlh *.tmp *.vspscc -.builds -*.dotCover # Visual C++ cache files -ipch/ *.aps *.ncb *.opendb @@ -40,6 +33,9 @@ ipch/ *.sdf *.db *.dll + +# Visual C++ cache folders +ipch/ .vs/ # Visual Studio profiler @@ -49,60 +45,34 @@ ipch/ # ReSharper is a .NET coding add-in _ReSharper* -# Installshield output folder -[Ee]xpress - -# DocProject is a documentation generator add-in -DocProject/buildhelp/ -DocProject/Help/*.HxT -DocProject/Help/*.HxC -DocProject/Help/*.hhc -DocProject/Help/*.hhk -DocProject/Help/*.hhp -DocProject/Help/Html2 -DocProject/Help/html - # Click-Once directory publish # Others [Bb]in [Oo]bj -sql -TestResults *.Cache ClientBin -stylecop.* ~$* -*.dbmdl -Generated_Code #added for RIA/Silverlight projects -# Backup & report files from converting an old project file to a newer -# Visual Studio version. Backup files are not needed, because we have git ;-) +# Backup & report files _UpgradeReport_Files/ #Backup*/ UpgradeLog*.XML -############ -## Windows -############ - # Windows image file caches Thumbs.db # Folder config file Desktop.ini -# Mac crap -.DS_Store - ########################## ## Project specific rules ########################## build/installer/*.exe -ProcessHacker/sdk/phapppub.h ProcessHacker/include/phapprev.h +ProcessHacker/sdk/phapppub.h plugins-extra/ /sdk/ diff --git a/ProcessHacker.sln b/ProcessHacker.sln index f9d474cc33d6..490ed238ad0c 100644 --- a/ProcessHacker.sln +++ b/ProcessHacker.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 -VisualStudioVersion = 15.0.26228.4 +VisualStudioVersion = 15.0.26403.7 MinimumVisualStudioVersion = 15.0.26228.4 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tools", "Tools", "{2758DC86-368B-430C-9D29-F1EF20032A71}" EndProject @@ -16,10 +16,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fixlib", "tools\fixlib\fixl EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "peview", "tools\peview\peview.vcxproj", "{72C124A2-3C80-41C6-ABA1-C4948B713204}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{FD3C278D-BD40-4551-AE67-4DE196F8D7F6}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "phlib-test", "tests\phlib-test\phlib-test.vcxproj", "{0C21014E-BC90-4AE5-AA32-398445C13B28}" -EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CustomSignTool", "tools\CustomSignTool\CustomSignTool.vcxproj", "{E8CD0A41-1537-4EA6-98AC-E80CD59C478E}" EndProject Global @@ -58,12 +54,6 @@ Global {72C124A2-3C80-41C6-ABA1-C4948B713204}.Release|Win32.Build.0 = Release|Win32 {72C124A2-3C80-41C6-ABA1-C4948B713204}.Release|x64.ActiveCfg = Release|x64 {72C124A2-3C80-41C6-ABA1-C4948B713204}.Release|x64.Build.0 = Release|x64 - {0C21014E-BC90-4AE5-AA32-398445C13B28}.Debug|Win32.ActiveCfg = Debug|Win32 - {0C21014E-BC90-4AE5-AA32-398445C13B28}.Debug|Win32.Build.0 = Debug|Win32 - {0C21014E-BC90-4AE5-AA32-398445C13B28}.Debug|x64.ActiveCfg = Debug|Win32 - {0C21014E-BC90-4AE5-AA32-398445C13B28}.Release|Win32.ActiveCfg = Release|Win32 - {0C21014E-BC90-4AE5-AA32-398445C13B28}.Release|Win32.Build.0 = Release|Win32 - {0C21014E-BC90-4AE5-AA32-398445C13B28}.Release|x64.ActiveCfg = Release|Win32 {E8CD0A41-1537-4EA6-98AC-E80CD59C478E}.Debug|Win32.ActiveCfg = Debug|Win32 {E8CD0A41-1537-4EA6-98AC-E80CD59C478E}.Debug|x64.ActiveCfg = Debug|x64 {E8CD0A41-1537-4EA6-98AC-E80CD59C478E}.Release|Win32.ActiveCfg = Release|Win32 @@ -75,7 +65,6 @@ Global GlobalSection(NestedProjects) = preSolution {31F4AA06-7ED5-4A6D-B901-19AD4BD16175} = {2758DC86-368B-430C-9D29-F1EF20032A71} {72C124A2-3C80-41C6-ABA1-C4948B713204} = {2758DC86-368B-430C-9D29-F1EF20032A71} - {0C21014E-BC90-4AE5-AA32-398445C13B28} = {FD3C278D-BD40-4551-AE67-4DE196F8D7F6} {E8CD0A41-1537-4EA6-98AC-E80CD59C478E} = {2758DC86-368B-430C-9D29-F1EF20032A71} EndGlobalSection EndGlobal diff --git a/phlib/mapimg.c b/phlib/mapimg.c index e093378073d2..e8521af2f431 100644 --- a/phlib/mapimg.c +++ b/phlib/mapimg.c @@ -986,11 +986,7 @@ NTSTATUS PhGetMappedImageImportDll( { while (TRUE) { - PhpMappedImageProbe( - ImportDll->MappedImage, - entry, - sizeof(IMAGE_THUNK_DATA32) - ); + PhpMappedImageProbe(ImportDll->MappedImage, entry, sizeof(IMAGE_THUNK_DATA32)); if (entry->u1.AddressOfData == 0) break; @@ -1014,11 +1010,7 @@ NTSTATUS PhGetMappedImageImportDll( { while (TRUE) { - PhpMappedImageProbe( - ImportDll->MappedImage, - entry, - sizeof(IMAGE_THUNK_DATA64) - ); + PhpMappedImageProbe(ImportDll->MappedImage, entry, sizeof(IMAGE_THUNK_DATA64)); if (entry->u1.AddressOfData == 0) break; @@ -1109,11 +1101,7 @@ NTSTATUS PhGetMappedImageImportEntry( __try { - PhpMappedImageProbe( - ImportDll->MappedImage, - importByName, - sizeof(IMAGE_IMPORT_BY_NAME) - ); + PhpMappedImageProbe(ImportDll->MappedImage, importByName, sizeof(IMAGE_IMPORT_BY_NAME)); } __except (EXCEPTION_EXECUTE_HANDLER) { diff --git a/phnt/include/ntrtl.h b/phnt/include/ntrtl.h index 42f1c47971f1..1d904d2ead41 100644 --- a/phnt/include/ntrtl.h +++ b/phnt/include/ntrtl.h @@ -5123,6 +5123,17 @@ RtlSidHashLookup( ); #endif +#if (PHNT_VERSION >= PHNT_REDSTONE2) +NTSYSAPI +NTSTATUS +NTAPI +RtlDeriveCapabilitySidsFromName( + _Inout_ PUNICODE_STRING UnicodeString, + _Out_ PSID CapabilityGroupSid, + _Out_ PSID CapabilitySid, + ); +#endif + // Security Descriptors NTSYSAPI From 3e7a790823181c8c9fb27fccbae5c25ab475fbd2 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 28 Apr 2017 04:14:14 +1000 Subject: [PATCH 0029/2058] peview: Fix section sizes, update tab layout --- tools/peview/peprp.c | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/tools/peview/peprp.c b/tools/peview/peprp.c index 1908df441a52..dcf1ceb21bd6 100644 --- a/tools/peview/peprp.c +++ b/tools/peview/peprp.c @@ -117,6 +117,17 @@ VOID PvPeProperties( ); PvAddPropPage(propContext, newPage); + // Load Config page + if (NT_SUCCESS(PhGetMappedImageDataEntry(&PvMappedImage, IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG, &entry)) && entry->VirtualAddress) + { + newPage = PvCreatePropPageContext( + MAKEINTRESOURCE(IDD_PELOADCONFIG), + PvpPeLoadConfigDlgProc, + NULL + ); + PvAddPropPage(propContext, newPage); + } + // Imports page if ((NT_SUCCESS(PhGetMappedImageImports(&imports, &PvMappedImage)) && imports.NumberOfDlls != 0) || (NT_SUCCESS(PhGetMappedImageDelayImports(&imports, &PvMappedImage)) && imports.NumberOfDlls != 0)) @@ -140,17 +151,6 @@ VOID PvPeProperties( PvAddPropPage(propContext, newPage); } - // Load Config page - if (NT_SUCCESS(PhGetMappedImageDataEntry(&PvMappedImage, IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG, &entry)) && entry->VirtualAddress) - { - newPage = PvCreatePropPageContext( - MAKEINTRESOURCE(IDD_PELOADCONFIG), - PvpPeLoadConfigDlgProc, - NULL - ); - PvAddPropPage(propContext, newPage); - } - // CLR page if (NT_SUCCESS(PhGetMappedImageDataEntry(&PvMappedImage, IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR, &entry)) && entry->VirtualAddress && @@ -554,10 +554,9 @@ INT_PTR CALLBACK PvpPeGeneralDlgProc( lvItemIndex = PhAddListViewItem(lvHandle, MAXINT, sectionName, NULL); PhPrintPointer(pointer, UlongToPtr(PvMappedImage.Sections[i].VirtualAddress)); - PhSetListViewSubItem(lvHandle, lvItemIndex, 1, pointer); - PhPrintPointer(pointer, UlongToPtr(PvMappedImage.Sections[i].SizeOfRawData)); - PhSetListViewSubItem(lvHandle, lvItemIndex, 2, pointer); + PhSetListViewSubItem(lvHandle, lvItemIndex, 1, pointer); + PhSetListViewSubItem(lvHandle, lvItemIndex, 2, PhaFormatSize(PvMappedImage.Sections[i].SizeOfRawData, -1)->Buffer); } } } From b102521d2b7fd4ea48460013e5e4ad769919b0e0 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 28 Apr 2017 21:06:12 +1000 Subject: [PATCH 0030/2058] Fix pointer usage consistency --- ProcessHacker/phsvc/svcapi.c | 6 +++--- phlib/native.c | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/ProcessHacker/phsvc/svcapi.c b/ProcessHacker/phsvc/svcapi.c index a375f4a6dee4..20fef6efb6a2 100644 --- a/ProcessHacker/phsvc/svcapi.c +++ b/ProcessHacker/phsvc/svcapi.c @@ -863,7 +863,7 @@ NTSTATUS PhSvcpUnpackBuffer( if (offset & (Alignment - 1)) return STATUS_DATATYPE_MISALIGNMENT; - *OffsetInBuffer = (PVOID)((ULONG_PTR)CapturedBuffer + offset); + *OffsetInBuffer = PTR_ADD_OFFSET(CapturedBuffer, offset); return STATUS_SUCCESS; } @@ -897,8 +897,8 @@ NTSTATUS PhSvcpUnpackStringZ( if (offset & 1) return STATUS_DATATYPE_MISALIGNMENT; - start = (PWCHAR)((ULONG_PTR)CapturedBuffer + offset); - end = (PWCHAR)((ULONG_PTR)CapturedBuffer + (PackedData->Length & -2)); + start = (PWCHAR)PTR_ADD_OFFSET(CapturedBuffer, offset); + end = (PWCHAR)PTR_ADD_OFFSET(CapturedBuffer, (PackedData->Length & -2)); remainingPart.Buffer = start; remainingPart.Length = (end - start) * sizeof(WCHAR); diff --git a/phlib/native.c b/phlib/native.c index 169bcf5d01a1..6a70c8fe1400 100644 --- a/phlib/native.c +++ b/phlib/native.c @@ -5406,7 +5406,7 @@ VOID PhpEnumGenericMappedFilesAndImages( do { - baseAddress = (PVOID)((ULONG_PTR)baseAddress + basicInfo.RegionSize); + baseAddress = PTR_ADD_OFFSET(baseAddress, basicInfo.RegionSize); allocationSize += basicInfo.RegionSize; if (!NT_SUCCESS(NtQueryVirtualMemory( @@ -5464,7 +5464,7 @@ VOID PhpEnumGenericMappedFilesAndImages( } else { - baseAddress = (PVOID)((ULONG_PTR)baseAddress + basicInfo.RegionSize); + baseAddress = PTR_ADD_OFFSET(baseAddress, basicInfo.RegionSize); if (!NT_SUCCESS(NtQueryVirtualMemory( ProcessHandle, From f73aea5e353b40cc1048fe64d8b26a6fdc2adfd9 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 28 Apr 2017 22:15:57 +1000 Subject: [PATCH 0031/2058] peview: Fix incorrect export function addresses (reported by @lucasg) --- phlib/mapimg.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/phlib/mapimg.c b/phlib/mapimg.c index e8521af2f431..ab022d66fa5b 100644 --- a/phlib/mapimg.c +++ b/phlib/mapimg.c @@ -739,11 +739,7 @@ NTSTATUS PhGetMappedImageExportFunction( } else { - Function->Function = PhMappedImageRvaToVa( - Exports->MappedImage, - rva, - NULL - ); + Function->Function = UlongToPtr(rva); Function->ForwardedName = NULL; } From 8e019d308a067997353a48ebb82df627680e5931 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 29 Apr 2017 04:56:06 +1000 Subject: [PATCH 0032/2058] peview: Label unnamed exported variables vs exported functions --- tools/peview/peprp.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/tools/peview/peprp.c b/tools/peview/peprp.c index dcf1ceb21bd6..dbdef62cac5e 100644 --- a/tools/peview/peprp.c +++ b/tools/peview/peprp.c @@ -852,13 +852,22 @@ INT_PTR CALLBACK PvpPeExportsDlgProc( } else { - lvItemIndex = PhAddListViewItem(lvHandle, MAXINT, L"(unnamed)", NULL); + if (exportFunction.Function) + lvItemIndex = PhAddListViewItem(lvHandle, MAXINT, L"(unnamed)", NULL); + else + lvItemIndex = PhAddListViewItem(lvHandle, MAXINT, L"(unnamed variable)", NULL); } PhPrintUInt32(number, exportEntry.Ordinal); PhSetListViewSubItem(lvHandle, lvItemIndex, 1, number); - if (!exportFunction.ForwardedName) + if (exportFunction.ForwardedName) + { + name = PhZeroExtendToUtf16(exportFunction.ForwardedName); + PhSetListViewSubItem(lvHandle, lvItemIndex, 2, name->Buffer); + PhDereferenceObject(name); + } + else { if ((ULONG_PTR)exportFunction.Function >= (ULONG_PTR)PvMappedImage.ViewBase) PhPrintPointer(pointer, PTR_SUB_OFFSET(exportFunction.Function, PvMappedImage.ViewBase)); @@ -867,12 +876,6 @@ INT_PTR CALLBACK PvpPeExportsDlgProc( PhSetListViewSubItem(lvHandle, lvItemIndex, 2, pointer); } - else - { - name = PhZeroExtendToUtf16(exportFunction.ForwardedName); - PhSetListViewSubItem(lvHandle, lvItemIndex, 2, name->Buffer); - PhDereferenceObject(name); - } } } } From c5376cd6b4410b22f0c55447550f03f2f45805b5 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 29 Apr 2017 06:07:36 +1000 Subject: [PATCH 0033/2058] peview: Fix typo, Remove legacy hack fixed by commit f73aea5 --- tools/peview/peprp.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/tools/peview/peprp.c b/tools/peview/peprp.c index dbdef62cac5e..8ce3c08fe2ee 100644 --- a/tools/peview/peprp.c +++ b/tools/peview/peprp.c @@ -827,7 +827,7 @@ INT_PTR CALLBACK PvpPeExportsDlgProc( PhSetControlTheme(lvHandle, L"explorer"); PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 220, L"Name"); PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 50, L"Ordinal"); - PhAddListViewColumn(lvHandle, 2, 2, 2, LVCFMT_LEFT, 120, L"VA"); + PhAddListViewColumn(lvHandle, 2, 2, 2, LVCFMT_LEFT, 120, L"RVA"); PhSetExtendedListView(lvHandle); if (NT_SUCCESS(PhGetMappedImageExports(&exports, &PvMappedImage))) @@ -869,11 +869,7 @@ INT_PTR CALLBACK PvpPeExportsDlgProc( } else { - if ((ULONG_PTR)exportFunction.Function >= (ULONG_PTR)PvMappedImage.ViewBase) - PhPrintPointer(pointer, PTR_SUB_OFFSET(exportFunction.Function, PvMappedImage.ViewBase)); - else - PhPrintPointer(pointer, exportFunction.Function); - + PhPrintPointer(pointer, exportFunction.Function); PhSetListViewSubItem(lvHandle, lvItemIndex, 2, pointer); } } From bc346bfde1e2773ec4488357551023a1549f21fb Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 29 Apr 2017 06:18:14 +1000 Subject: [PATCH 0034/2058] peview: ignore entries with invalid RVA --- tools/peview/peprp.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/tools/peview/peprp.c b/tools/peview/peprp.c index 8ce3c08fe2ee..8e444a87255d 100644 --- a/tools/peview/peprp.c +++ b/tools/peview/peprp.c @@ -844,6 +844,12 @@ INT_PTR CALLBACK PvpPeExportsDlgProc( WCHAR number[PH_INT32_STR_LEN_1]; WCHAR pointer[PH_PTR_STR_LEN_1]; + // TODO: user32.dll and some other libraries have many (unnamed) exports with invalid RVA, + // they might be exported variables or caused by incorrect math, ignore these entries + // until more information is available. + if (!exportFunction.Function) + continue; + if (exportEntry.Name) { name = PhZeroExtendToUtf16(exportEntry.Name); @@ -852,10 +858,7 @@ INT_PTR CALLBACK PvpPeExportsDlgProc( } else { - if (exportFunction.Function) - lvItemIndex = PhAddListViewItem(lvHandle, MAXINT, L"(unnamed)", NULL); - else - lvItemIndex = PhAddListViewItem(lvHandle, MAXINT, L"(unnamed variable)", NULL); + lvItemIndex = PhAddListViewItem(lvHandle, MAXINT, L"(unnamed)", NULL); } PhPrintUInt32(number, exportEntry.Ordinal); From 733d3f3b52339f160948339d14641c5f33d5d0c3 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 29 Apr 2017 06:31:46 +1000 Subject: [PATCH 0035/2058] Fix typo --- tools/peview/peprp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/peview/peprp.c b/tools/peview/peprp.c index 8e444a87255d..6d26c7e76340 100644 --- a/tools/peview/peprp.c +++ b/tools/peview/peprp.c @@ -844,7 +844,7 @@ INT_PTR CALLBACK PvpPeExportsDlgProc( WCHAR number[PH_INT32_STR_LEN_1]; WCHAR pointer[PH_PTR_STR_LEN_1]; - // TODO: user32.dll and some other libraries have many (unnamed) exports with invalid RVA, + // TODO: user32.dll and some other dlls have many (unnamed) exports with (invalid) 0x0 RVA, // they might be exported variables or caused by incorrect math, ignore these entries // until more information is available. if (!exportFunction.Function) From 327d7e7fc66ce0094ca1b912790aef3d72a8c2bc Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 29 Apr 2017 21:07:18 +1000 Subject: [PATCH 0036/2058] Fix PhGetFileVersionInfoString returning invalid version strings --- phlib/util.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/phlib/util.c b/phlib/util.c index 5a923ee1daae..117339b56462 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -1627,6 +1627,10 @@ PPH_STRING PhGetFileVersionInfoString( { PPH_STRING string; + // Check if the string has a valid length. + if (length <= sizeof(WCHAR)) + return NULL; + string = PhCreateStringEx((PWCHAR)buffer, length * sizeof(WCHAR)); // length may include the null terminator. PhTrimToNullTerminatorString(string); From 6e7e769fb5a29dc44f25396f062778980ae75243 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 29 Apr 2017 21:07:59 +1000 Subject: [PATCH 0037/2058] peview: Fix null string check --- tools/peview/peprp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/peview/peprp.c b/tools/peview/peprp.c index 6d26c7e76340..dd63d9509a28 100644 --- a/tools/peview/peprp.c +++ b/tools/peview/peprp.c @@ -316,7 +316,7 @@ FORCEINLINE PWSTR PvpGetStringOrNa( _In_ PPH_STRING String ) { - if (String) + if (!PhIsNullOrEmptyString(String)) return String->Buffer; else return L"N/A"; From aca8f685692d74f74842297bebebbd623f4505f0 Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Sat, 29 Apr 2017 12:17:18 +0100 Subject: [PATCH 0038/2058] phlib: Fix a potential exception when calling NtQueryObject (#133) * Under some circumstances, NtQueryObject() will produce a NULL pointer exception if the last parameter is NULL. --- phlib/hndlinfo.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/phlib/hndlinfo.c b/phlib/hndlinfo.c index 749a6d91ccb9..ce0b3e27f28e 100644 --- a/phlib/hndlinfo.c +++ b/phlib/hndlinfo.c @@ -142,12 +142,13 @@ NTSTATUS PhpGetObjectBasicInformation( } else { + ULONG returnLength; status = NtQueryObject( Handle, ObjectBasicInformation, BasicInformation, sizeof(OBJECT_BASIC_INFORMATION), - NULL + &returnLength ); if (NT_SUCCESS(status)) @@ -1394,7 +1395,7 @@ NTSTATUS PhEnumObjectTypes( { NTSTATUS status; PVOID buffer; - ULONG bufferSize; + ULONG bufferSize, returnLength; bufferSize = 0x1000; buffer = PhAllocate(bufferSize); @@ -1404,7 +1405,7 @@ NTSTATUS PhEnumObjectTypes( ObjectTypesInformation, buffer, bufferSize, - NULL + &returnLength )) == STATUS_INFO_LENGTH_MISMATCH) { PhFree(buffer); From 19803e299771b9b18cfcd40d1e9a27ec9785cd99 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 29 Apr 2017 21:33:22 +1000 Subject: [PATCH 0039/2058] Fix up typos per project guidelines --- phlib/hndlinfo.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/phlib/hndlinfo.c b/phlib/hndlinfo.c index ce0b3e27f28e..77df87c8d7c1 100644 --- a/phlib/hndlinfo.c +++ b/phlib/hndlinfo.c @@ -143,6 +143,7 @@ NTSTATUS PhpGetObjectBasicInformation( else { ULONG returnLength; + status = NtQueryObject( Handle, ObjectBasicInformation, @@ -1395,7 +1396,8 @@ NTSTATUS PhEnumObjectTypes( { NTSTATUS status; PVOID buffer; - ULONG bufferSize, returnLength; + ULONG bufferSize; + ULONG returnLength; bufferSize = 0x1000; buffer = PhAllocate(bufferSize); From 2eb391aaf2365e6b71ca3d4f214ae6ff83512544 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 29 Apr 2017 22:46:05 +1000 Subject: [PATCH 0040/2058] peview: Fix CFG index and rva not being consistent with other tabs --- tools/peview/peprp.c | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/tools/peview/peprp.c b/tools/peview/peprp.c index dd63d9509a28..d9a237c942c1 100644 --- a/tools/peview/peprp.c +++ b/tools/peview/peprp.c @@ -1145,7 +1145,7 @@ INT_PTR CALLBACK PvpPeCgfDlgProc( PhSetControlTheme(lvHandle, L"explorer"); PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT , 40, L"#"); - PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_RIGHT, 100, L"RVA"); + PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_RIGHT, 80, L"RVA"); PhAddListViewColumn(lvHandle, 2, 2, 2, LVCFMT_LEFT , 250, L"Name"); PhAddListViewColumn(lvHandle, 3, 3, 3, LVCFMT_LEFT , 100, L"Flags"); PhSetExtendedListView(lvHandle); @@ -1173,23 +1173,18 @@ INT_PTR CALLBACK PvpPeCgfDlgProc( PPH_STRING symbolName = NULL; PH_SYMBOL_RESOLVE_LEVEL symbolResolveLevel = PhsrlInvalid; IMAGE_CFG_ENTRY cfgFunctionEntry = { 0 }; + WCHAR number[PH_INT64_STR_LEN_1]; + WCHAR pointer[PH_PTR_STR_LEN_1]; // Parse cfg entry : if it fails, just skip it ? if (!NT_SUCCESS(PhGetMappedImageCfgEntry(&cfgConfig, i, ControlFlowGuardFunction, &cfgFunctionEntry))) continue; - - lvItemIndex = PhAddListViewItem( - lvHandle, - MAXINT, - PhaFormatString(L"%I64u", i)->Buffer, - NULL - ); - PhSetListViewSubItem( - lvHandle, - lvItemIndex, - 1, - PhaFormatString(L"0x%08x", cfgFunctionEntry.Rva)->Buffer - ); + + PhPrintUInt64(number, i + 1); + lvItemIndex = PhAddListViewItem(lvHandle, MAXINT, number, NULL); + + PhPrintPointer(pointer, UlongToPtr(cfgFunctionEntry.Rva)); + PhSetListViewSubItem(lvHandle, lvItemIndex, 1, pointer); // Resolve name based on public symbols if (!(symbol = PhGetSymbolFromAddress( From 0da87cb201038afb166e7c2fb2fc9f777fe7bdf5 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 30 Apr 2017 00:38:36 +1000 Subject: [PATCH 0041/2058] UserNotes: Update default settings for 3.x builds --- plugins/UserNotes/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/UserNotes/main.c b/plugins/UserNotes/main.c index e0f3f0278e08..88a55cfa438b 100644 --- a/plugins/UserNotes/main.c +++ b/plugins/UserNotes/main.c @@ -1331,7 +1331,7 @@ LOGICAL DllMain( PPH_PLUGIN_INFORMATION info; PH_SETTING_CREATE settings[] = { - { StringSettingType, SETTING_NAME_DATABASE_PATH, L"%APPDATA%\\Process Hacker 2\\usernotesdb.xml" }, + { StringSettingType, SETTING_NAME_DATABASE_PATH, L"%APPDATA%\\Process Hacker\\usernotesdb.xml" }, { StringSettingType, SETTING_NAME_CUSTOM_COLOR_LIST, L"" } }; From 9c438e01cb44759a29615399b1e8641635ea5840 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 30 Apr 2017 09:09:27 +1000 Subject: [PATCH 0042/2058] Fix typo --- ProcessHacker/actions.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ProcessHacker/actions.c b/ProcessHacker/actions.c index fbec1593805a..f0f7526594fc 100644 --- a/ProcessHacker/actions.c +++ b/ProcessHacker/actions.c @@ -2807,7 +2807,7 @@ BOOLEAN PhUiUnloadModule( L"Unable to unload ", Module->Name->Buffer, L". Make sure Process Hacker is running with " - L"administrative privileges. Error" + L"administrative privileges." )->Buffer, status, 0 From 0bf49bdcb6fc04417bc3185bb974f6f66084302a Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Thu, 4 May 2017 03:44:50 +0100 Subject: [PATCH 0043/2058] Fix search box font size on high DPI displays (#135) --- ProcessHacker/searchbox.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ProcessHacker/searchbox.c b/ProcessHacker/searchbox.c index 4cc1c8e132af..53e2b47dbb25 100644 --- a/ProcessHacker/searchbox.c +++ b/ProcessHacker/searchbox.c @@ -83,7 +83,7 @@ VOID PhpSearchInitializeFont( if (Context->WindowFont) DeleteObject(Context->WindowFont); - Context->WindowFont = PhCreateCommonFont(PH_SCALE_DPI(10), FW_MEDIUM, Context->WindowHandle); + Context->WindowFont = PhCreateCommonFont(10, FW_MEDIUM, Context->WindowHandle); } VOID PhpSearchInitializeTheme( From e2245b4e574821e1904b9c98aa75d56854225caf Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 4 May 2017 16:17:31 +1000 Subject: [PATCH 0044/2058] Fix Toolbar and Plugin Manager High-DPI scaling issues --- ProcessHacker/include/phapp.h | 2 +- ProcessHacker/searchbox.c | 2 +- plugins/ExtraPlugins/wndtree.c | 32 +++++++++++++++++--------------- plugins/ToolStatus/customizesb.c | 6 +++--- plugins/ToolStatus/customizetb.c | 4 ++-- plugins/ToolStatus/main.c | 4 ++-- plugins/ToolStatus/toolbar.c | 10 +++++++--- 7 files changed, 33 insertions(+), 27 deletions(-) diff --git a/ProcessHacker/include/phapp.h b/ProcessHacker/include/phapp.h index f4ff73920fa5..5a9914f8a514 100644 --- a/ProcessHacker/include/phapp.h +++ b/ProcessHacker/include/phapp.h @@ -87,7 +87,7 @@ extern PH_STARTUP_PARAMETERS PhStartupParameters; extern PH_PROVIDER_THREAD PhPrimaryProviderThread; extern PH_PROVIDER_THREAD PhSecondaryProviderThread; -#define PH_SCALE_DPI(Value) PhMultiplyDivide(Value, PhGlobalDpi, 96) +#define PH_SCALE_DPI(Value) PhMultiplyDivide(Value, PhGlobalDpi, 96) // phapppub // begin_phapppub PHAPPAPI diff --git a/ProcessHacker/searchbox.c b/ProcessHacker/searchbox.c index 53e2b47dbb25..8581d2d15cfd 100644 --- a/ProcessHacker/searchbox.c +++ b/ProcessHacker/searchbox.c @@ -90,7 +90,7 @@ VOID PhpSearchInitializeTheme( _Inout_ PEDIT_CONTEXT Context ) { - Context->CXWidth = PhMultiplyDivide(20, PhGlobalDpi, 96); + Context->CXWidth = PH_SCALE_DPI(20); Context->BrushNormal = GetSysColorBrush(COLOR_WINDOW); Context->BrushHot = CreateSolidBrush(RGB(205, 232, 255)); Context->BrushPushed = CreateSolidBrush(RGB(153, 209, 255)); diff --git a/plugins/ExtraPlugins/wndtree.c b/plugins/ExtraPlugins/wndtree.c index 54be25aaa2a8..0bdeced96e21 100644 --- a/plugins/ExtraPlugins/wndtree.c +++ b/plugins/ExtraPlugins/wndtree.c @@ -2,7 +2,7 @@ * Process Hacker Extra Plugins - * Plugin Manager * - * Copyright (C) 2016 dmex + * Copyright (C) 2016-2017 dmex * * This file is part of Process Hacker. * @@ -307,16 +307,20 @@ BOOLEAN NTAPI PluginsTreeNewCallback( PH_STRINGREF text; SIZE nameSize; SIZE textSize; - + SIZE imageSize; + + imageSize.cx = PH_SCALE_DPI(17); + imageSize.cy = PH_SCALE_DPI(17); + if (node->PluginOptions) { if (!node->Icon) { HBITMAP bitmapActive; - if (bitmapActive = PhLoadPngImageFromResource(PluginInstance->DllBase, 17, 17, MAKEINTRESOURCE(IDB_SETTINGS_PNG), TRUE)) + if (bitmapActive = PhLoadPngImageFromResource(PluginInstance->DllBase, imageSize.cx, imageSize.cy, MAKEINTRESOURCE(IDB_SETTINGS_PNG), TRUE)) { - node->Icon = CommonBitmapToIcon(bitmapActive, 17, 17); + node->Icon = CommonBitmapToIcon(bitmapActive, imageSize.cx, imageSize.cy); DeleteObject(bitmapActive); } } @@ -325,11 +329,11 @@ BOOLEAN NTAPI PluginsTreeNewCallback( { DrawIconEx( customDraw->Dc, - rect.left + 5, - rect.top + ((rect.bottom - rect.top) - 17) / 2, + rect.left + PH_SCALE_DPI(5), + rect.top + ((rect.bottom - rect.top) - imageSize.cy) / 2, node->Icon, - 17, - 17, + imageSize.cx, + imageSize.cy, 0, NULL, DI_NORMAL @@ -337,12 +341,10 @@ BOOLEAN NTAPI PluginsTreeNewCallback( } } - rect.left += 19; - rect.left += 8; - - rect.top += 5; - rect.right -= 5; - rect.bottom -= 8; + rect.left += PH_SCALE_DPI(27); + rect.top += PH_SCALE_DPI(5); + rect.right -= PH_SCALE_DPI(5); + rect.bottom -= PH_SCALE_DPI(8); // top SetTextColor(customDraw->Dc, RGB(0x0, 0x0, 0x0)); @@ -443,7 +445,7 @@ VOID InitializePluginsTree( Context->TitleFontHandle = PhCreateCommonFont(-14, FW_BOLD, NULL); TreeNew_SetCallback(TreeNewHandle, PluginsTreeNewCallback, Context); - TreeNew_SetRowHeight(TreeNewHandle, 48); + TreeNew_SetRowHeight(TreeNewHandle, PH_SCALE_DPI(48)); PhAddTreeNewColumnEx2(TreeNewHandle, TREE_COLUMN_ITEM_NAME, TRUE, L"Plugin", 80, PH_ALIGN_LEFT, TREE_COLUMN_ITEM_NAME, 0, TN_COLUMN_FLAG_CUSTOMDRAW); PhAddTreeNewColumnEx2(TreeNewHandle, TREE_COLUMN_ITEM_AUTHOR, TRUE, L"Author", 80, PH_ALIGN_LEFT, TREE_COLUMN_ITEM_AUTHOR, 0, 0); diff --git a/plugins/ToolStatus/customizesb.c b/plugins/ToolStatus/customizesb.c index 6b7d51ef4cdf..cd4dbd29034d 100644 --- a/plugins/ToolStatus/customizesb.c +++ b/plugins/ToolStatus/customizesb.c @@ -2,7 +2,7 @@ * Process Hacker ToolStatus - * Statusbar Customize Dialog * - * Copyright (C) 2015-2016 dmex + * Copyright (C) 2015-2017 dmex * * This file is part of Process Hacker. * @@ -321,8 +321,8 @@ INT_PTR CALLBACK CustomizeStatusBarDialogProc( context->RemoveButtonHandle = GetDlgItem(hwndDlg, IDC_REMOVE); context->FontHandle = CommonDuplicateFont((HFONT)SendMessage(StatusBarHandle, WM_GETFONT, 0, 0)); - ListBox_SetItemHeight(context->AvailableListHandle, 0, PhMultiplyDivide(22, PhGlobalDpi, 96)); // BitmapHeight - ListBox_SetItemHeight(context->CurrentListHandle, 0, PhMultiplyDivide(22, PhGlobalDpi, 96)); // BitmapHeight + ListBox_SetItemHeight(context->AvailableListHandle, 0, PH_SCALE_DPI(22)); // BitmapHeight + ListBox_SetItemHeight(context->CurrentListHandle, 0, PH_SCALE_DPI(22)); // BitmapHeight CustomizeLoadStatusBarItems(context); diff --git a/plugins/ToolStatus/customizetb.c b/plugins/ToolStatus/customizetb.c index f1b906bd17c5..e376e26f749d 100644 --- a/plugins/ToolStatus/customizetb.c +++ b/plugins/ToolStatus/customizetb.c @@ -2,7 +2,7 @@ * Process Hacker ToolStatus - * Toolbar Customize Dialog * - * Copyright (C) 2015-2016 dmex + * Copyright (C) 2015-2017 dmex * * This file is part of Process Hacker. * @@ -519,7 +519,7 @@ INT_PTR CALLBACK CustomizeToolbarDialogProc( context->AddButtonHandle = GetDlgItem(hwndDlg, IDC_ADD); context->RemoveButtonHandle = GetDlgItem(hwndDlg, IDC_REMOVE); - context->CXWidth = 16; + context->CXWidth = PH_SCALE_DPI(16); context->BrushNormal = GetSysColorBrush(COLOR_WINDOW); context->BrushHot = CreateSolidBrush(RGB(145, 201, 247)); context->BrushPushed = CreateSolidBrush(RGB(153, 209, 255)); diff --git a/plugins/ToolStatus/main.c b/plugins/ToolStatus/main.c index 8bd024e7203a..2c81fa57babb 100644 --- a/plugins/ToolStatus/main.c +++ b/plugins/ToolStatus/main.c @@ -2,8 +2,8 @@ * Process Hacker ToolStatus - * main program * - * Copyright (C) 2011-2016 dmex * Copyright (C) 2010-2016 wj32 + * Copyright (C) 2011-2017 dmex * * This file is part of Process Hacker. * @@ -712,7 +712,7 @@ LRESULT CALLBACK MainWndSubclassProc( if (SearchBoxDisplayMode == SEARCHBOX_DISPLAY_MODE_HIDEINACTIVE) { if (!RebarBandExists(REBAR_BAND_ID_SEARCHBOX)) - RebarBandInsert(REBAR_BAND_ID_SEARCHBOX, SearchboxHandle, PhMultiplyDivide(180, PhGlobalDpi, 96), 22); + RebarBandInsert(REBAR_BAND_ID_SEARCHBOX, SearchboxHandle, PH_SCALE_DPI(180), 22); if (!IsWindowVisible(SearchboxHandle)) ShowWindow(SearchboxHandle, SW_SHOW); diff --git a/plugins/ToolStatus/toolbar.c b/plugins/ToolStatus/toolbar.c index 67fb6176bab4..c7b752460c7b 100644 --- a/plugins/ToolStatus/toolbar.c +++ b/plugins/ToolStatus/toolbar.c @@ -2,7 +2,7 @@ * Process Hacker ToolStatus - * main toolbar * - * Copyright (C) 2011-2016 dmex + * Copyright (C) 2011-2017 dmex * * This file is part of Process Hacker. * @@ -109,6 +109,10 @@ VOID RebarLoadSettings( { if (ToolStatusConfig.ToolBarEnabled && !ToolBarImageList) { + // Enable scaling the Toolbar and images on high-DPI machines. + ToolBarImageSize.cx = PH_SCALE_DPI(16); + ToolBarImageSize.cy = PH_SCALE_DPI(16); + ToolBarImageList = ImageList_Create(ToolBarImageSize.cx, ToolBarImageSize.cy, ILC_COLOR32, 0, 0); } @@ -141,7 +145,7 @@ VOID RebarLoadSettings( NULL ); - // Set the toolbar info with no imagelist. + // Set the rebar info with no imagelist. SendMessage(RebarHandle, RB_SETBARINFO, 0, (LPARAM)&rebarInfo); // Set the toolbar struct size. SendMessage(ToolBarHandle, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0); @@ -209,7 +213,7 @@ VOID RebarLoadSettings( // Add the Searchbox band into the rebar control. if (!RebarBandExists(REBAR_BAND_ID_SEARCHBOX)) - RebarBandInsert(REBAR_BAND_ID_SEARCHBOX, SearchboxHandle, PhMultiplyDivide(180, PhGlobalDpi, 96), height); + RebarBandInsert(REBAR_BAND_ID_SEARCHBOX, SearchboxHandle, PH_SCALE_DPI(180), height); if (!IsWindowVisible(SearchboxHandle)) ShowWindow(SearchboxHandle, SW_SHOW); From 1ca180bb60c16ceee0aa3a987c87081834c4d8fa Mon Sep 17 00:00:00 2001 From: lucasg Date: Thu, 4 May 2017 08:37:44 +0200 Subject: [PATCH 0045/2058] Add cfg support for wow64 process (#134) * Locate and tag CFG bitmap memory page (both x86 and x64) for wow64 processes * Add CFG entries parsing for 32-bit executables in peview * Add unnamed union in PH_MAPPED_IMAGE in order to selectively read a IMAGE_NT_HEADER as 32 bit (could also have used a C-style cast) * Rename CFG page "RVA" column to "VA" since we read Virtual Adresses --- ProcessHacker/include/memprv.h | 3 +- ProcessHacker/memlist.c | 4 +- ProcessHacker/memprv.c | 81 ++++++++++++++++--- phlib/include/mapimg.h | 6 +- phlib/mapimg.c | 143 ++++++++++++++++++++++++++++++++- tools/peview/peprp.c | 7 +- 6 files changed, 221 insertions(+), 23 deletions(-) diff --git a/ProcessHacker/include/memprv.h b/ProcessHacker/include/memprv.h index b3d7baf86f8f..dcd62a55fbea 100644 --- a/ProcessHacker/include/memprv.h +++ b/ProcessHacker/include/memprv.h @@ -21,7 +21,8 @@ typedef enum _PH_MEMORY_REGION_TYPE Heap32Region, HeapSegmentRegion, HeapSegment32Region, - CfgBitmapRegion + CfgBitmapRegion, + CfgBitmap32Region } PH_MEMORY_REGION_TYPE; typedef struct _PH_MEMORY_ITEM diff --git a/ProcessHacker/memlist.c b/ProcessHacker/memlist.c index 4e5d9373c741..90f4ec268941 100644 --- a/ProcessHacker/memlist.c +++ b/ProcessHacker/memlist.c @@ -425,7 +425,9 @@ PPH_STRING PhpGetMemoryRegionUseText( return PhFormatString(L"Heap segment%s (ID %u)", type == HeapSegment32Region ? L" 32-bit" : L"", (ULONG)MemoryItem->u.HeapSegment.HeapItem->u.Heap.Index + 1); case CfgBitmapRegion: - return PhFormatString(L"CFG Bitmap"); + case CfgBitmap32Region: + return PhFormatString(L"CFG Bitmap%s", + type == CfgBitmap32Region ? L" 32-bit" : L""); default: return PhReferenceEmptyString(); } diff --git a/ProcessHacker/memprv.c b/ProcessHacker/memprv.c index 14e9ca24bc42..ee97e34730b3 100644 --- a/ProcessHacker/memprv.c +++ b/ProcessHacker/memprv.c @@ -488,23 +488,81 @@ NTSTATUS PhpUpdateMemoryRegionTypes( } #ifdef _WIN64 - // CFG bitmaps for 64-bit processes - if (!isWow64) + + LDR_INIT_BLOCK ldrInitBlock = { 0 }; + PVOID ldrInitBlockBaseAddress = NULL; + PPH_MEMORY_ITEM cfgBitmapMemoryItem; + PPH_STRING ntdllFileName; + + ntdllFileName = PhConcatStrings2(USER_SHARED_DATA->NtSystemRoot, L"\\System32\\ntdll.dll"); + status = PhGetProcedureAddressRemote( + ProcessHandle, + ntdllFileName->Buffer, + "LdrSystemDllInitBlock", + 0, + &ldrInitBlockBaseAddress, + NULL + ); + + if (NT_SUCCESS(status) && ldrInitBlockBaseAddress) + { + status = NtReadVirtualMemory( + ProcessHandle, + ldrInitBlockBaseAddress, + &ldrInitBlock, + sizeof(LDR_INIT_BLOCK), + NULL + ); + } + + PhDereferenceObject(ntdllFileName); + + if (NT_SUCCESS(status)) + { + PVOID cfgBitmapAddress = NULL; + + // TODO: Remove this code once most users have updated their machines. + if (ldrInitBlock.Size == sizeof(LDR_INIT_BLOCK)) + cfgBitmapAddress = ldrInitBlock.CfgBitmapAddress; // 15063 + else if (ldrInitBlock.Size == 128) + cfgBitmapAddress = ldrInitBlock.Unknown1[11]; // 14393 + + if (cfgBitmapAddress && (cfgBitmapMemoryItem = PhLookupMemoryItemList(List, cfgBitmapAddress))) + { + PLIST_ENTRY listEntry = &cfgBitmapMemoryItem->ListEntry; + PPH_MEMORY_ITEM memoryItem = CONTAINING_RECORD(listEntry, PH_MEMORY_ITEM, ListEntry); + + // Tagging memory items + while (memoryItem->AllocationBaseItem == cfgBitmapMemoryItem) + { + // NB : we could do a finer tagging since each MEM_COMMIT memory + // map is the CFG bitmap of a loaded module. However that would + // imply to heavily rely on reverse-engineer results, and might be + // brittle to changes made by Windows dev teams. + memoryItem->RegionType = CfgBitmapRegion; + + listEntry = listEntry->Flink; + memoryItem = CONTAINING_RECORD(listEntry, PH_MEMORY_ITEM, ListEntry); + } + } + } + + if (isWow64) { LDR_INIT_BLOCK ldrInitBlock = { 0 }; PVOID ldrInitBlockBaseAddress = NULL; PPH_MEMORY_ITEM cfgBitmapMemoryItem; - PPH_STRING ntdllFileName; + PPH_STRING ntdllWow64FileName; - ntdllFileName = PhConcatStrings2(USER_SHARED_DATA->NtSystemRoot, L"\\System32\\ntdll.dll"); + ntdllWow64FileName = PhConcatStrings2(USER_SHARED_DATA->NtSystemRoot, L"\\SysWow64\\ntdll.dll"); status = PhGetProcedureAddressRemote( ProcessHandle, - ntdllFileName->Buffer, + ntdllWow64FileName->Buffer, "LdrSystemDllInitBlock", 0, &ldrInitBlockBaseAddress, NULL - ); + ); if (NT_SUCCESS(status) && ldrInitBlockBaseAddress) { @@ -514,10 +572,10 @@ NTSTATUS PhpUpdateMemoryRegionTypes( &ldrInitBlock, sizeof(LDR_INIT_BLOCK), NULL - ); + ); } - PhDereferenceObject(ntdllFileName); + PhDereferenceObject(ntdllWow64FileName); if (NT_SUCCESS(status)) { @@ -537,17 +595,14 @@ NTSTATUS PhpUpdateMemoryRegionTypes( // Tagging memory items while (memoryItem->AllocationBaseItem == cfgBitmapMemoryItem) { - // NB : we could do a finer tagging since each MEM_COMMIT memory - // map is the CFG bitmap of a loaded module. However that would - // imply to heavily rely on reverse-engineer results, and might be - // brittle to changes made by Windows dev teams. - memoryItem->RegionType = CfgBitmapRegion; + memoryItem->RegionType = CfgBitmap32Region; listEntry = listEntry->Flink; memoryItem = CONTAINING_RECORD(listEntry, PH_MEMORY_ITEM, ListEntry); } } } + } #endif diff --git a/phlib/include/mapimg.h b/phlib/include/mapimg.h index 608e652ce5a8..ba179e8ca83d 100644 --- a/phlib/include/mapimg.h +++ b/phlib/include/mapimg.h @@ -10,7 +10,11 @@ typedef struct _PH_MAPPED_IMAGE PVOID ViewBase; SIZE_T Size; - PIMAGE_NT_HEADERS NtHeaders; + union { + PIMAGE_NT_HEADERS32 NtHeaders32; + PIMAGE_NT_HEADERS NtHeaders; + }; + ULONG NumberOfSections; PIMAGE_SECTION_HEADER Sections; USHORT Magic; diff --git a/phlib/mapimg.c b/phlib/mapimg.c index ab022d66fa5b..d3d73cb55879 100644 --- a/phlib/mapimg.c +++ b/phlib/mapimg.c @@ -1213,16 +1213,17 @@ ULONG PhCheckSumMappedImage( return checkSum; } -NTSTATUS PhGetMappedImageCfg( +NTSTATUS PhGetMappedImageCfg64( _Out_ PPH_MAPPED_IMAGE_CFG CfgConfig, _In_ PPH_MAPPED_IMAGE MappedImage ) { NTSTATUS status; PIMAGE_LOAD_CONFIG_DIRECTORY64 config64; - + if (!NT_SUCCESS(status = PhGetMappedImageLoadConfig64(MappedImage, &config64))) return status; + // Not every load configuration defines CFG characteristics if (config64->Size < (ULONG)FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY64, GuardFlags)) @@ -1244,7 +1245,7 @@ NTSTATUS PhGetMappedImageCfg( CfgConfig->NumberOfGuardFunctionEntries = config64->GuardCFFunctionCount; CfgConfig->GuardFunctionTable = PhMappedImageRvaToVa( MappedImage, - (ULONG)(config64->GuardCFFunctionTable - MappedImage->NtHeaders->OptionalHeader.ImageBase), + (ULONG) (ULONG_PTR) PTR_SUB_OFFSET(config64->GuardCFFunctionTable , MappedImage->NtHeaders->OptionalHeader.ImageBase), NULL ); @@ -1333,6 +1334,142 @@ NTSTATUS PhGetMappedImageCfg( return STATUS_SUCCESS; } +NTSTATUS PhGetMappedImageCfg32( + _Out_ PPH_MAPPED_IMAGE_CFG CfgConfig, + _In_ PPH_MAPPED_IMAGE MappedImage +) +{ + NTSTATUS status; + PIMAGE_LOAD_CONFIG_DIRECTORY32 config32; + + if (!NT_SUCCESS(status = PhGetMappedImageLoadConfig32(MappedImage, &config32))) + return status; + + + // Not every load configuration defines CFG characteristics + if (config32->Size < (ULONG)FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY32, GuardFlags)) + return STATUS_INVALID_VIEW_SIZE; + + CfgConfig->MappedImage = MappedImage; + CfgConfig->EntrySize = sizeof(FIELD_OFFSET(IMAGE_CFG_ENTRY, Rva)) + + (ULONG)((config32->GuardFlags & IMAGE_GUARD_CF_FUNCTION_TABLE_SIZE_MASK) >> IMAGE_GUARD_CF_FUNCTION_TABLE_SIZE_SHIFT); + CfgConfig->CfgInstrumented = !!(config32->GuardFlags & IMAGE_GUARD_CF_INSTRUMENTED); + CfgConfig->WriteIntegrityChecks = !!(config32->GuardFlags & IMAGE_GUARD_CFW_INSTRUMENTED); + CfgConfig->CfgFunctionTablePresent = !!(config32->GuardFlags & IMAGE_GUARD_CF_FUNCTION_TABLE_PRESENT); + CfgConfig->SecurityCookieUnused = !!(config32->GuardFlags & IMAGE_GUARD_SECURITY_COOKIE_UNUSED); + CfgConfig->ProtectDelayLoadedIat = !!(config32->GuardFlags & IMAGE_GUARD_PROTECT_DELAYLOAD_IAT); + CfgConfig->DelayLoadInDidatSection = !!(config32->GuardFlags & IMAGE_GUARD_DELAYLOAD_IAT_IN_ITS_OWN_SECTION); + CfgConfig->EnableExportSuppression = !!(config32->GuardFlags & IMAGE_GUARD_CF_ENABLE_EXPORT_SUPPRESSION); + CfgConfig->HasExportSuppressionInfos = !!(config32->GuardFlags & IMAGE_GUARD_CF_EXPORT_SUPPRESSION_INFO_PRESENT); + CfgConfig->CfgLongJumpTablePresent = !!(config32->GuardFlags & IMAGE_GUARD_CF_LONGJUMP_TABLE_PRESENT); + + CfgConfig->NumberOfGuardFunctionEntries = config32->GuardCFFunctionCount; + CfgConfig->GuardFunctionTable = PhMappedImageRvaToVa( + MappedImage, + (ULONG)(ULONG_PTR)PTR_SUB_OFFSET(config32->GuardCFFunctionTable , MappedImage->NtHeaders32->OptionalHeader.ImageBase), + NULL + ); + + if (CfgConfig->GuardFunctionTable && CfgConfig->NumberOfGuardFunctionEntries) + { + __try + { + PhpMappedImageProbe( + MappedImage, + CfgConfig->GuardFunctionTable, + (SIZE_T)(CfgConfig->EntrySize * CfgConfig->NumberOfGuardFunctionEntries) + ); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + return GetExceptionCode(); + } + } + + CfgConfig->NumberOfGuardAdressIatEntries = 0; + CfgConfig->GuardAdressIatTable = 0; + + if ( + config32->Size >= (ULONG)FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY32, GuardAddressTakenIatEntryTable) + + sizeof(config32->GuardAddressTakenIatEntryTable) + + sizeof(config32->GuardAddressTakenIatEntryCount) + ) + { + CfgConfig->NumberOfGuardAdressIatEntries = config32->GuardAddressTakenIatEntryCount; + CfgConfig->GuardAdressIatTable = PhMappedImageRvaToVa( + MappedImage, + (ULONG)(config32->GuardAddressTakenIatEntryTable - MappedImage->NtHeaders->OptionalHeader.ImageBase), + NULL + ); + + if (CfgConfig->GuardAdressIatTable && CfgConfig->NumberOfGuardAdressIatEntries) + { + __try + { + PhpMappedImageProbe( + MappedImage, + CfgConfig->GuardAdressIatTable, + (SIZE_T)(CfgConfig->EntrySize * CfgConfig->NumberOfGuardAdressIatEntries) + ); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + return GetExceptionCode(); + } + } + } + + CfgConfig->NumberOfGuardLongJumpEntries = 0; + CfgConfig->GuardLongJumpTable = 0; + + if ( + config32->Size >= (ULONG)FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY32, GuardLongJumpTargetTable) + + sizeof(config32->GuardLongJumpTargetTable) + + sizeof(config32->GuardLongJumpTargetCount) + ) + { + CfgConfig->NumberOfGuardLongJumpEntries = config32->GuardLongJumpTargetCount; + CfgConfig->GuardLongJumpTable = PhMappedImageRvaToVa( + MappedImage, + (ULONG)(config32->GuardLongJumpTargetTable - MappedImage->NtHeaders->OptionalHeader.ImageBase), + NULL + ); + + if (CfgConfig->GuardLongJumpTable && CfgConfig->NumberOfGuardLongJumpEntries) + { + __try + { + PhpMappedImageProbe( + MappedImage, + CfgConfig->GuardLongJumpTable, + (SIZE_T)(CfgConfig->EntrySize * CfgConfig->NumberOfGuardLongJumpEntries) + ); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + return GetExceptionCode(); + } + } + } + + return STATUS_SUCCESS; +} + +NTSTATUS PhGetMappedImageCfg( + _Out_ PPH_MAPPED_IMAGE_CFG CfgConfig, + _In_ PPH_MAPPED_IMAGE MappedImage +) +{ + if (MappedImage->Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) + { + return PhGetMappedImageCfg32(CfgConfig, MappedImage); + } + else + { + return PhGetMappedImageCfg64(CfgConfig, MappedImage); + } +} + NTSTATUS PhGetMappedImageCfgEntry( _In_ PPH_MAPPED_IMAGE_CFG CfgConfig, _In_ ULONGLONG Index, diff --git a/tools/peview/peprp.c b/tools/peview/peprp.c index d9a237c942c1..778ada75b70c 100644 --- a/tools/peview/peprp.c +++ b/tools/peview/peprp.c @@ -185,8 +185,7 @@ VOID PvPeProperties( } // CFG page - if ((PvMappedImage.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) && - (PvMappedImage.NtHeaders->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_GUARD_CF)) + if (PvMappedImage.NtHeaders->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_GUARD_CF) { newPage = PvCreatePropPageContext( MAKEINTRESOURCE(IDD_PECFG), @@ -1144,8 +1143,8 @@ INT_PTR CALLBACK PvpPeCgfDlgProc( PhSetListViewStyle(lvHandle, FALSE, TRUE); PhSetControlTheme(lvHandle, L"explorer"); - PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT , 40, L"#"); - PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_RIGHT, 80, L"RVA"); + PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT , 40, L"#"); + PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_RIGHT, 80, L"VA"); PhAddListViewColumn(lvHandle, 2, 2, 2, LVCFMT_LEFT , 250, L"Name"); PhAddListViewColumn(lvHandle, 3, 3, 3, LVCFMT_LEFT , 100, L"Flags"); PhSetExtendedListView(lvHandle); From ead3508fc656a21a75c2bf0aae6552bbbe45df97 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 4 May 2017 17:05:10 +1000 Subject: [PATCH 0046/2058] Fix variable scope name re-use issues, Add extra LDR_INIT_BLOCK error checking, Fix tabspace --- ProcessHacker/memprv.c | 37 ++++++++++++++++++------------------- phlib/mapimg.c | 25 ++++++++++++------------- tools/peview/peprp.c | 8 ++++---- 3 files changed, 34 insertions(+), 36 deletions(-) diff --git a/ProcessHacker/memprv.c b/ProcessHacker/memprv.c index ee97e34730b3..cf5979bd1fc8 100644 --- a/ProcessHacker/memprv.c +++ b/ProcessHacker/memprv.c @@ -517,7 +517,7 @@ NTSTATUS PhpUpdateMemoryRegionTypes( PhDereferenceObject(ntdllFileName); - if (NT_SUCCESS(status)) + if (NT_SUCCESS(status) && ldrInitBlock.Size) { PVOID cfgBitmapAddress = NULL; @@ -549,9 +549,9 @@ NTSTATUS PhpUpdateMemoryRegionTypes( if (isWow64) { - LDR_INIT_BLOCK ldrInitBlock = { 0 }; - PVOID ldrInitBlockBaseAddress = NULL; - PPH_MEMORY_ITEM cfgBitmapMemoryItem; + LDR_INIT_BLOCK ldrInitBlock32 = { 0 }; + PVOID ldrInitBlockBaseAddress32 = NULL; + PPH_MEMORY_ITEM cfgBitmapMemoryItem32; PPH_STRING ntdllWow64FileName; ntdllWow64FileName = PhConcatStrings2(USER_SHARED_DATA->NtSystemRoot, L"\\SysWow64\\ntdll.dll"); @@ -560,40 +560,40 @@ NTSTATUS PhpUpdateMemoryRegionTypes( ntdllWow64FileName->Buffer, "LdrSystemDllInitBlock", 0, - &ldrInitBlockBaseAddress, + &ldrInitBlockBaseAddress32, NULL - ); + ); - if (NT_SUCCESS(status) && ldrInitBlockBaseAddress) + if (NT_SUCCESS(status) && ldrInitBlockBaseAddress32) { status = NtReadVirtualMemory( ProcessHandle, - ldrInitBlockBaseAddress, - &ldrInitBlock, + ldrInitBlockBaseAddress32, + &ldrInitBlock32, sizeof(LDR_INIT_BLOCK), NULL - ); + ); } PhDereferenceObject(ntdllWow64FileName); - if (NT_SUCCESS(status)) + if (NT_SUCCESS(status) && ldrInitBlock32.Size) { PVOID cfgBitmapAddress = NULL; // TODO: Remove this code once most users have updated their machines. - if (ldrInitBlock.Size == sizeof(LDR_INIT_BLOCK)) - cfgBitmapAddress = ldrInitBlock.CfgBitmapAddress; // 15063 - else if (ldrInitBlock.Size == 128) - cfgBitmapAddress = ldrInitBlock.Unknown1[11]; // 14393 + if (ldrInitBlock32.Size == sizeof(LDR_INIT_BLOCK)) + cfgBitmapAddress = ldrInitBlock32.CfgBitmapAddress; // 15063 + else if (ldrInitBlock32.Size == 128) + cfgBitmapAddress = ldrInitBlock32.Unknown1[11]; // 14393 - if (cfgBitmapAddress && (cfgBitmapMemoryItem = PhLookupMemoryItemList(List, cfgBitmapAddress))) + if (cfgBitmapAddress && (cfgBitmapMemoryItem32 = PhLookupMemoryItemList(List, cfgBitmapAddress))) { - PLIST_ENTRY listEntry = &cfgBitmapMemoryItem->ListEntry; + PLIST_ENTRY listEntry = &cfgBitmapMemoryItem32->ListEntry; PPH_MEMORY_ITEM memoryItem = CONTAINING_RECORD(listEntry, PH_MEMORY_ITEM, ListEntry); // Tagging memory items - while (memoryItem->AllocationBaseItem == cfgBitmapMemoryItem) + while (memoryItem->AllocationBaseItem == cfgBitmapMemoryItem32) { memoryItem->RegionType = CfgBitmap32Region; @@ -602,7 +602,6 @@ NTSTATUS PhpUpdateMemoryRegionTypes( } } } - } #endif diff --git a/phlib/mapimg.c b/phlib/mapimg.c index d3d73cb55879..b949e3aefc39 100644 --- a/phlib/mapimg.c +++ b/phlib/mapimg.c @@ -3,6 +3,7 @@ * mapped image * * Copyright (C) 2010 wj32 + * Copyright (C) 2017 dmex * * This file is part of Process Hacker. * @@ -1220,10 +1221,9 @@ NTSTATUS PhGetMappedImageCfg64( { NTSTATUS status; PIMAGE_LOAD_CONFIG_DIRECTORY64 config64; - + if (!NT_SUCCESS(status = PhGetMappedImageLoadConfig64(MappedImage, &config64))) return status; - // Not every load configuration defines CFG characteristics if (config64->Size < (ULONG)FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY64, GuardFlags)) @@ -1245,7 +1245,7 @@ NTSTATUS PhGetMappedImageCfg64( CfgConfig->NumberOfGuardFunctionEntries = config64->GuardCFFunctionCount; CfgConfig->GuardFunctionTable = PhMappedImageRvaToVa( MappedImage, - (ULONG) (ULONG_PTR) PTR_SUB_OFFSET(config64->GuardCFFunctionTable , MappedImage->NtHeaders->OptionalHeader.ImageBase), + (ULONG)(ULONG_PTR)PTR_SUB_OFFSET(config64->GuardCFFunctionTable, MappedImage->NtHeaders->OptionalHeader.ImageBase), NULL ); @@ -1289,7 +1289,7 @@ NTSTATUS PhGetMappedImageCfg64( MappedImage, CfgConfig->GuardAdressIatTable, (SIZE_T)(CfgConfig->EntrySize * CfgConfig->NumberOfGuardAdressIatEntries) - ); + ); } __except (EXCEPTION_EXECUTE_HANDLER) { @@ -1337,7 +1337,7 @@ NTSTATUS PhGetMappedImageCfg64( NTSTATUS PhGetMappedImageCfg32( _Out_ PPH_MAPPED_IMAGE_CFG CfgConfig, _In_ PPH_MAPPED_IMAGE MappedImage -) + ) { NTSTATUS status; PIMAGE_LOAD_CONFIG_DIRECTORY32 config32; @@ -1345,7 +1345,6 @@ NTSTATUS PhGetMappedImageCfg32( if (!NT_SUCCESS(status = PhGetMappedImageLoadConfig32(MappedImage, &config32))) return status; - // Not every load configuration defines CFG characteristics if (config32->Size < (ULONG)FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY32, GuardFlags)) return STATUS_INVALID_VIEW_SIZE; @@ -1368,7 +1367,7 @@ NTSTATUS PhGetMappedImageCfg32( MappedImage, (ULONG)(ULONG_PTR)PTR_SUB_OFFSET(config32->GuardCFFunctionTable , MappedImage->NtHeaders32->OptionalHeader.ImageBase), NULL - ); + ); if (CfgConfig->GuardFunctionTable && CfgConfig->NumberOfGuardFunctionEntries) { @@ -1378,7 +1377,7 @@ NTSTATUS PhGetMappedImageCfg32( MappedImage, CfgConfig->GuardFunctionTable, (SIZE_T)(CfgConfig->EntrySize * CfgConfig->NumberOfGuardFunctionEntries) - ); + ); } __except (EXCEPTION_EXECUTE_HANDLER) { @@ -1400,7 +1399,7 @@ NTSTATUS PhGetMappedImageCfg32( MappedImage, (ULONG)(config32->GuardAddressTakenIatEntryTable - MappedImage->NtHeaders->OptionalHeader.ImageBase), NULL - ); + ); if (CfgConfig->GuardAdressIatTable && CfgConfig->NumberOfGuardAdressIatEntries) { @@ -1410,7 +1409,7 @@ NTSTATUS PhGetMappedImageCfg32( MappedImage, CfgConfig->GuardAdressIatTable, (SIZE_T)(CfgConfig->EntrySize * CfgConfig->NumberOfGuardAdressIatEntries) - ); + ); } __except (EXCEPTION_EXECUTE_HANDLER) { @@ -1433,7 +1432,7 @@ NTSTATUS PhGetMappedImageCfg32( MappedImage, (ULONG)(config32->GuardLongJumpTargetTable - MappedImage->NtHeaders->OptionalHeader.ImageBase), NULL - ); + ); if (CfgConfig->GuardLongJumpTable && CfgConfig->NumberOfGuardLongJumpEntries) { @@ -1443,7 +1442,7 @@ NTSTATUS PhGetMappedImageCfg32( MappedImage, CfgConfig->GuardLongJumpTable, (SIZE_T)(CfgConfig->EntrySize * CfgConfig->NumberOfGuardLongJumpEntries) - ); + ); } __except (EXCEPTION_EXECUTE_HANDLER) { @@ -1458,7 +1457,7 @@ NTSTATUS PhGetMappedImageCfg32( NTSTATUS PhGetMappedImageCfg( _Out_ PPH_MAPPED_IMAGE_CFG CfgConfig, _In_ PPH_MAPPED_IMAGE MappedImage -) + ) { if (MappedImage->Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) { diff --git a/tools/peview/peprp.c b/tools/peview/peprp.c index 778ada75b70c..5d7b9fc84053 100644 --- a/tools/peview/peprp.c +++ b/tools/peview/peprp.c @@ -1143,10 +1143,10 @@ INT_PTR CALLBACK PvpPeCgfDlgProc( PhSetListViewStyle(lvHandle, FALSE, TRUE); PhSetControlTheme(lvHandle, L"explorer"); - PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT , 40, L"#"); - PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_RIGHT, 80, L"VA"); - PhAddListViewColumn(lvHandle, 2, 2, 2, LVCFMT_LEFT , 250, L"Name"); - PhAddListViewColumn(lvHandle, 3, 3, 3, LVCFMT_LEFT , 100, L"Flags"); + PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 40, L"#"); + PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_RIGHT, 80, L"VA"); + PhAddListViewColumn(lvHandle, 2, 2, 2, LVCFMT_LEFT, 250, L"Name"); + PhAddListViewColumn(lvHandle, 3, 3, 3, LVCFMT_LEFT, 100, L"Flags"); PhSetExtendedListView(lvHandle); // Init symbol resolver From 9509162bdcf91f494ea7e530cdd8039fd8b31a7f Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 4 May 2017 21:15:34 +1000 Subject: [PATCH 0047/2058] Save token properties splitter position, Add workaround for splitter resize bug --- ProcessHacker/include/splitter.h | 1 + ProcessHacker/settings.c | 1 + ProcessHacker/splitter.c | 17 +++++++++++++++-- 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/ProcessHacker/include/splitter.h b/ProcessHacker/include/splitter.h index 50b9c1fb7bf4..f872c7a7483a 100644 --- a/ProcessHacker/include/splitter.h +++ b/ProcessHacker/include/splitter.h @@ -18,6 +18,7 @@ typedef struct _PH_HSPLITTER_CONTEXT LONG SplitterOffset; LONG SplitterPosition; + ULONG SplitterLayoutCount; PH_LAYOUT_MANAGER LayoutManager; PPH_LAYOUT_ITEM Topitem; PPH_LAYOUT_ITEM Bottomitem; diff --git a/ProcessHacker/settings.c b/ProcessHacker/settings.c index addc547df23f..d57fafd97072 100644 --- a/ProcessHacker/settings.c +++ b/ProcessHacker/settings.c @@ -184,6 +184,7 @@ VOID PhSettingsInitialization( PhpAddStringSetting(L"ThreadTreeListSort", L"1,2"); // 1, DescendingSortOrder PhpAddStringSetting(L"ThreadStackListViewColumns", L""); PhpAddScalableIntegerPairSetting(L"ThreadStackWindowSize", L"@96|420,380"); + PhpAddIntegerSetting(L"TokenSplitterPosition", L"250"); PhpAddIntegerSetting(L"UpdateInterval", L"3e8"); // 1000ms // Colors are specified with R in the lowest byte, then G, then B. diff --git a/ProcessHacker/splitter.c b/ProcessHacker/splitter.c index 55c28b97785a..ddecd07f23aa 100644 --- a/ProcessHacker/splitter.c +++ b/ProcessHacker/splitter.c @@ -45,7 +45,7 @@ PPH_HSPLITTER_CONTEXT PhInitializeHSplitter( PhInitializeLayoutManager(&context->LayoutManager, Parent); context->SplitterOffset = -4; - context->SplitterPosition = 250; + context->SplitterPosition = PhGetIntegerSetting(L"TokenSplitterPosition"); context->Topitem = PhAddLayoutItem(&context->LayoutManager, TopChild, NULL, PH_ANCHOR_ALL); context->Bottomitem = PhAddLayoutItem(&context->LayoutManager, BottomChild, NULL, PH_ANCHOR_ALL); @@ -56,6 +56,8 @@ VOID PhDeleteHSplitter( _Inout_ PPH_HSPLITTER_CONTEXT Context ) { + PhSetIntegerSetting(L"TokenSplitterPosition", Context->SplitterPosition); + PhDeleteLayoutManager(&Context->LayoutManager); } @@ -66,7 +68,18 @@ VOID PhHSplitterHandleWmSize( ) { // HACK: Use the PH layout manager as the 'splitter' control by abusing layout margins. - // TODO: Check min_height and adjust second control if invisible. + + if (Context->SplitterLayoutCount >= 2) + { + // BUG: If the window is maximized and you move the splitter to the bottom, restoring the window causes + // the bottom control to get moved outside the visible area... Just move the splitter back up. + if ((Context->Bottomitem->Rect.bottom - Context->Bottomitem->Rect.top) <= 100) + Context->SplitterPosition = Context->Topitem->Rect.bottom - Context->Topitem->Rect.top - SPLITTER_PADDING; + } + else + { + Context->SplitterLayoutCount++; + } // Set the bottom margin of the top control. Context->Topitem->Margin.bottom = Height - Context->SplitterPosition - SPLITTER_PADDING; From f52b85838ba2ad91be77a8c26a8e0d0db317f925 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 4 May 2017 21:16:00 +1000 Subject: [PATCH 0048/2058] WindowExplorer: Hide window tab for system processes --- plugins/WindowExplorer/main.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/plugins/WindowExplorer/main.c b/plugins/WindowExplorer/main.c index c3cc7af784de..c31834ae619d 100644 --- a/plugins/WindowExplorer/main.c +++ b/plugins/WindowExplorer/main.c @@ -3,6 +3,7 @@ * main program * * Copyright (C) 2011 wj32 + * Copyright (C) 2017 dmex * * This file is part of Process Hacker. * @@ -168,11 +169,11 @@ VOID NTAPI ProcessPropertiesInitializingCallback( ) { PPH_PLUGIN_PROCESS_PROPCONTEXT propContext = Parameter; - BOOLEAN isGuiProcess = TRUE; - // enum threads, IsGuiThread, isGuiProcess=TRUE - - if (isGuiProcess) + if ( + propContext->ProcessItem->ProcessId != SYSTEM_IDLE_PROCESS_ID && + propContext->ProcessItem->ProcessId != SYSTEM_PROCESS_ID + ) { WE_WINDOW_SELECTOR selector; From e843852dcb35eb45ff54a034a2871319ef5d005e Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 4 May 2017 21:27:50 +1000 Subject: [PATCH 0049/2058] Updater: Fix memory leak --- plugins/Updater/page3.c | 6 ++---- plugins/Updater/page5.c | 13 +++++++------ plugins/Updater/updater.c | 1 + 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/plugins/Updater/page3.c b/plugins/Updater/page3.c index a34e8c6c07cf..740dae4589f1 100644 --- a/plugins/Updater/page3.c +++ b/plugins/Updater/page3.c @@ -77,7 +77,7 @@ VOID ShowAvailableDialog( memset(&config, 0, sizeof(TASKDIALOGCONFIG)); config.cbSize = sizeof(TASKDIALOGCONFIG); - config.dwFlags = TDF_USE_HICON_MAIN | TDF_ALLOW_DIALOG_CANCELLATION | TDF_CAN_BE_MINIMIZED | TDF_ENABLE_HYPERLINKS; + config.dwFlags = TDF_USE_HICON_MAIN | TDF_ALLOW_DIALOG_CANCELLATION | TDF_CAN_BE_MINIMIZED | TDF_ENABLE_HYPERLINKS | TDF_EXPAND_FOOTER_AREA; config.dwCommonButtons = TDCBF_CANCEL_BUTTON; config.hMainIcon = Context->IconLargeHandle; config.cxWidth = 200; @@ -94,9 +94,7 @@ VOID ShowAvailableDialog( Context->RevisionVersion, PhGetStringOrEmpty(Context->Size) )->Buffer; - - //if (!PhIsNullOrEmptyString(Context->BuildMessage)) - // config.pszExpandedInformation = PhGetStringOrEmpty(Context->BuildMessage); + config.pszExpandedInformation = PhGetString(Context->BuildMessage); SendMessage(Context->DialogHandle, TDM_NAVIGATE_PAGE, 0, (LPARAM)&config); } \ No newline at end of file diff --git a/plugins/Updater/page5.c b/plugins/Updater/page5.c index ca014212da1d..36b9860d61b0 100644 --- a/plugins/Updater/page5.c +++ b/plugins/Updater/page5.c @@ -136,7 +136,7 @@ VOID ShowLatestVersionDialog( memset(&config, 0, sizeof(TASKDIALOGCONFIG)); config.cbSize = sizeof(TASKDIALOGCONFIG); - config.dwFlags = TDF_USE_HICON_MAIN | TDF_ALLOW_DIALOG_CANCELLATION | TDF_CAN_BE_MINIMIZED | TDF_ENABLE_HYPERLINKS; + config.dwFlags = TDF_USE_HICON_MAIN | TDF_ALLOW_DIALOG_CANCELLATION | TDF_CAN_BE_MINIMIZED | TDF_ENABLE_HYPERLINKS | TDF_EXPAND_FOOTER_AREA; config.dwCommonButtons = TDCBF_CLOSE_BUTTON; config.hMainIcon = Context->IconLargeHandle; config.cxWidth = 200; @@ -158,6 +158,7 @@ VOID ShowLatestVersionDialog( Context->CurrentRevisionVersion, PhaFormatDateTime(&systemTime)->Buffer )->Buffer; + config.pszExpandedInformation = PhGetString(Context->BuildMessage); SendMessage(Context->DialogHandle, TDM_NAVIGATE_PAGE, 0, (LPARAM)&config); } @@ -170,9 +171,12 @@ VOID ShowNewerVersionDialog( memset(&config, 0, sizeof(TASKDIALOGCONFIG)); config.cbSize = sizeof(TASKDIALOGCONFIG); - config.dwFlags = TDF_USE_HICON_MAIN | TDF_ALLOW_DIALOG_CANCELLATION | TDF_CAN_BE_MINIMIZED; + config.dwFlags = TDF_USE_HICON_MAIN | TDF_ALLOW_DIALOG_CANCELLATION | TDF_CAN_BE_MINIMIZED | TDF_EXPAND_FOOTER_AREA; config.dwCommonButtons = TDCBF_CLOSE_BUTTON; config.hMainIcon = Context->IconLargeHandle; + config.cxWidth = 200; + config.pfCallback = FinalTaskDialogCallbackProc; + config.lpCallbackData = (LONG_PTR)Context; config.pszWindowTitle = L"Process Hacker - Updater"; config.pszMainInstruction = L"You're running a pre-release build."; @@ -182,10 +186,7 @@ VOID ShowNewerVersionDialog( Context->CurrentMinorVersion, Context->CurrentRevisionVersion )->Buffer; - - config.cxWidth = 200; - config.pfCallback = FinalTaskDialogCallbackProc; - config.lpCallbackData = (LONG_PTR)Context; + config.pszExpandedInformation = PhGetString(Context->BuildMessage); SendMessage(Context->DialogHandle, TDM_NAVIGATE_PAGE, 0, (LPARAM)&config); } diff --git a/plugins/Updater/updater.c b/plugins/Updater/updater.c index 51f75f11c329..de808e1da9bc 100644 --- a/plugins/Updater/updater.c +++ b/plugins/Updater/updater.c @@ -61,6 +61,7 @@ VOID FreeUpdateContext( PhClearReference(&Context->ReleaseNotesUrl); PhClearReference(&Context->SetupFilePath); PhClearReference(&Context->SetupFileDownloadUrl); + PhClearReference(&Context->BuildMessage); if (Context->IconLargeHandle) DestroyIcon(Context->IconLargeHandle); From e6a9472a4fb61d5078d1b0d741a93fc0eb23d591 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 4 May 2017 21:41:12 +1000 Subject: [PATCH 0050/2058] CustomSetupTool: Fix shutting down current instances --- .../CustomSetupTool/CustomSetupTool/appsup.c | 52 ++++++------------- 1 file changed, 16 insertions(+), 36 deletions(-) diff --git a/tools/CustomSetupTool/CustomSetupTool/appsup.c b/tools/CustomSetupTool/CustomSetupTool/appsup.c index fa09d200d337..5e5d174eb8b7 100644 --- a/tools/CustomSetupTool/CustomSetupTool/appsup.c +++ b/tools/CustomSetupTool/CustomSetupTool/appsup.c @@ -476,50 +476,30 @@ BOOLEAN ShutdownProcessHacker(VOID) HANDLE processHandle; ULONG processID = 0; - windowHandle = FindWindow(L"ProcessHacker", NULL); - if (!windowHandle) - return TRUE; - - GetWindowThreadProcessId(windowHandle, &processID); - - SendMessageTimeout( - windowHandle, - WM_QUIT, - 0, - 0, - SMTO_ABORTIFHUNG | SMTO_BLOCK, - 5000, - NULL - ); - - // Check the window handle again - windowHandle = FindWindow(L"ProcessHacker", NULL); - if (!windowHandle) - return TRUE; - - GetWindowThreadProcessId(windowHandle, &processID); - - if (NT_SUCCESS(PhOpenProcess( - &processHandle, - SYNCHRONIZE | PROCESS_TERMINATE, - ULongToHandle(processID) - ))) + while (windowHandle = FindWindow(L"ProcessHacker", NULL)) { - PostMessage(windowHandle, WM_QUIT, 0, 0); + GetWindowThreadProcessId(windowHandle, &processID); - if (WaitForSingleObject(processHandle, 10 * 1000) != WAIT_OBJECT_0) + if (NT_SUCCESS(PhOpenProcess( + &processHandle, + SYNCHRONIZE | PROCESS_TERMINATE, + ULongToHandle(processID) + ))) { - if (!NT_SUCCESS(NtTerminateProcess(processHandle, 1))) + PostMessage(windowHandle, WM_QUIT, 0, 0); + + // Wait for process exit. + if (WaitForSingleObject(processHandle, 10 * 1000) != WAIT_OBJECT_0) { - NtClose(processHandle); - return FALSE; + // Timed out, kill the process. + NtTerminateProcess(processHandle, 1); } - } - NtClose(processHandle); + NtClose(processHandle); + } } - return FALSE; + return TRUE; } BOOLEAN CreateDirectoryPath(_In_ PWSTR DirPath) From 7dbbac839a47236f423d18e87861f74131e3a637 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 5 May 2017 15:42:03 +1000 Subject: [PATCH 0051/2058] Update build tools --- ProcessHacker/ProcessHacker.vcxproj | 48 +----- ProcessHacker/include/phapprev.h | 2 +- build/phapppub_options.txt | 6 - tools/CustomBuildTool/Source Files/Build.cs | 2 - .../CustomBuildTool/Source Files/HeaderGen.cs | 159 +++++++++--------- tools/CustomBuildTool/Source Files/Program.cs | 23 ++- .../bin/Release/CustomBuildTool.exe | Bin 145408 -> 146432 bytes .../bin/Release/CustomBuildTool.pdb | Bin 62976 -> 62976 bytes 8 files changed, 103 insertions(+), 137 deletions(-) delete mode 100644 build/phapppub_options.txt diff --git a/ProcessHacker/ProcessHacker.vcxproj b/ProcessHacker/ProcessHacker.vcxproj index 8f2a2bbc1f1f..abad4684afab 100644 --- a/ProcessHacker/ProcessHacker.vcxproj +++ b/ProcessHacker/ProcessHacker.vcxproj @@ -104,16 +104,8 @@ ProcessHacker.def aclui.dll;iphlpapi.dll;ws2_32.dll;%(DelayLoadDLLs) - - ..\tools\CustomBuildTool\bin\Release\CustomBuildTool.exe -updaterev - Generating revision number... - - - - - - - + + @@ -138,16 +130,8 @@ ProcessHacker.def aclui.dll;iphlpapi.dll;ws2_32.dll;%(DelayLoadDLLs) - - ..\tools\CustomBuildTool\bin\Release\CustomBuildTool.exe -updaterev - Generating revision number... - - - - - - - + + @@ -179,16 +163,8 @@ ProcessHacker.def aclui.dll;iphlpapi.dll;ws2_32.dll;%(DelayLoadDLLs) - - ..\tools\CustomBuildTool\bin\Release\CustomBuildTool.exe -updaterev - Generating revision number... - - - - - - - + + @@ -219,16 +195,8 @@ ProcessHacker.def aclui.dll;iphlpapi.dll;ws2_32.dll;%(DelayLoadDLLs) - - ..\tools\CustomBuildTool\bin\Release\CustomBuildTool.exe -updaterev - Generating revision number... - - - - - - - + + diff --git a/ProcessHacker/include/phapprev.h b/ProcessHacker/include/phapprev.h index 7fb3bd0b5cb6..cbb6d2096029 100644 --- a/ProcessHacker/include/phapprev.h +++ b/ProcessHacker/include/phapprev.h @@ -1,6 +1,6 @@ #ifndef PHAPPREV_H #define PHAPPREV_H -#define PHAPP_VERSION_REVISION 0 +#define PHAPP_VERSION_REVISION 0x0D06F00D #endif // PHAPPREV_H diff --git a/build/phapppub_options.txt b/build/phapppub_options.txt deleted file mode 100644 index f668a06b10e3..000000000000 --- a/build/phapppub_options.txt +++ /dev/null @@ -1,6 +0,0 @@ -base=ProcessHacker\include -modes=phapppub -in=phapp.h;appsup.h;phfwddef.h;procprv.h;srvprv.h;netprv.h;modprv.h;thrdprv.h;hndlprv.h;memprv.h;phuisup.h;colmgr.h;proctree.h;srvlist.h;netlist.h;thrdlist.h;modlist.h;hndllist.h;memlist.h;extmgr.h;mainwnd.h;notifico.h;settings.h;phplug.h;actions.h;procprp.h;procprpp.h;phsvccl.h;sysinfo.h;procgrp.h;miniinfo.h -out=..\sdk\phapppub.h -header=#ifndef _PH_PHAPPPUB_H\r\n#define _PH_PHAPPPUB_H\r\n\r\n// This file was automatically generated. Do not edit.\r\n\r\n#ifdef __cplusplus\r\nextern "C" {\r\n#endif\r\n -footer=\r\n#ifdef __cplusplus\r\n}\r\n#endif\r\n\r\n#endif\r\n \ No newline at end of file diff --git a/tools/CustomBuildTool/Source Files/Build.cs b/tools/CustomBuildTool/Source Files/Build.cs index d88bfd38394f..835b79b8565e 100644 --- a/tools/CustomBuildTool/Source Files/Build.cs +++ b/tools/CustomBuildTool/Source Files/Build.cs @@ -419,7 +419,6 @@ public static bool CopyVersionHeader() try { HeaderGen gen = new HeaderGen(); - gen.LoadConfig("build\\phapppub_options.txt"); gen.Execute(); File.Copy("ProcessHacker\\sdk\\phapppub.h", "sdk\\include\\phapppub.h", true); @@ -965,7 +964,6 @@ public static bool BuildPublicHeaderFiles() try { HeaderGen gen = new HeaderGen(); - gen.LoadConfig("build\\phapppub_options.txt"); gen.Execute(); } catch (Exception ex) diff --git a/tools/CustomBuildTool/Source Files/HeaderGen.cs b/tools/CustomBuildTool/Source Files/HeaderGen.cs index 971675106e28..e4df545defbd 100644 --- a/tools/CustomBuildTool/Source Files/HeaderGen.cs +++ b/tools/CustomBuildTool/Source Files/HeaderGen.cs @@ -1,9 +1,7 @@ using System; -using System.Collections.Generic; using System.IO; using System.Linq; -using System.Text; -using System.Threading.Tasks; +using System.Collections.Generic; namespace CustomBuildTool { @@ -16,48 +14,54 @@ public class HeaderFile public class HeaderGen { - private string _baseDirectory; - private string[] _modes; - private string[] _files; - private string _outputFile; - private string _header = ""; - private string _footer = ""; - - private string UnEscape(string text) - { - return text.Replace("\\r", "\r").Replace("\\n", "\n").Replace("\\\\", "\\"); - } - - public void LoadConfig(string fileName) + private string BaseDirectory; + private string[] Modes; + private string[] Files; + private string OutputFile; + private string Header; + private string Footer; + + public HeaderGen() { - string[] lines = File.ReadAllLines(fileName); - - foreach (string line in lines) + this.OutputFile = "..\\sdk\\phapppub.h"; + this.BaseDirectory = "ProcessHacker\\include"; + this.Modes = new[] { "phapppub" }; + this.Files = new[] { - string[] split = line.Split(new char[] { '=' }, 2); - - switch (split[0]) - { - case "base": - _baseDirectory = split[1]; - break; - case "modes": - _modes = split[1].ToLowerInvariant().Split(';'); - break; - case "in": - _files = split[1].Split(';'); - break; - case "out": - _outputFile = split[1]; - break; - case "header": - _header = UnEscape(split[1]); - break; - case "footer": - _footer = UnEscape(split[1]); - break; - } - } + "phapp.h", + "appsup.h", + "phfwddef.h", + "procprv.h", + "srvprv.h", + "netprv.h", + "modprv.h", + "thrdprv.h", + "hndlprv.h", + "memprv.h", + "phuisup.h", + "colmgr.h", + "proctree.h", + "srvlist.h", + "netlist.h", + "thrdlist.h", + "modlist.h", + "hndllist.h", + "memlist.h", + "extmgr.h", + "mainwnd.h", + "notifico.h", + "settings.h", + "phplug.h", + "actions.h", + "procprp.h", + "procprpp.h", + "phsvccl.h", + "sysinfo.h", + "procgrp.h", + "miniinfo.h" + }; + this.Header = "#ifndef _PH_PHAPPPUB_H\r\n#define _PH_PHAPPPUB_H\r\n\r\n// This file was automatically generated. Do not edit.\r\n\r\n#ifdef __cplusplus\r\nextern \"C\" {\r\n#endif\r\n"; + this.Footer = "\r\n#ifdef __cplusplus\r\n}\r\n#endif\r\n\r\n#endif\r\n"; } private List OrderHeaderFiles(List headerFiles) @@ -104,15 +108,15 @@ private List ProcessHeaderLines(IEnumerable lines) } else { - bool blockMode = _modes.Any(modes.Contains); - bool lineMode = _modes.Any(mode => - { - int indexOfMarker = s.LastIndexOf("// " + mode); - if (indexOfMarker == -1) - return false; + bool blockMode = this.Modes.Any(modes.Contains); + bool lineMode = this.Modes.Any(mode => + { + int indexOfMarker = s.LastIndexOf("// " + mode); + if (indexOfMarker == -1) + return false; - return s.Substring(indexOfMarker).Trim().All(c => char.IsLetterOrDigit(c) || c == ' ' || c == '/'); - }); + return s.Substring(indexOfMarker).Trim().All(c => char.IsLetterOrDigit(c) || c == ' ' || c == '/'); + }); if (blockMode || lineMode) { @@ -136,34 +140,31 @@ public void Execute() { // Read in all header files. - var headerFiles = _files.Select(fileName => + var headerFiles = this.Files.Select(fileName => { - var fullFileName = _baseDirectory + "\\" + fileName; + var fullFileName = this.BaseDirectory + "\\" + fileName; var lines = File.ReadAllLines(fullFileName).ToList(); return new HeaderFile { Name = Path.GetFileName(fullFileName).ToLowerInvariant(), Lines = lines }; - }).ToDictionary(h => h.Name); + }) + .ToDictionary(h => h.Name); - foreach (var h in headerFiles.Values) + foreach (HeaderFile h in headerFiles.Values) { - var partitions = - h.Lines - .Select(s => - { - var trimmed = s.Trim().ToLowerInvariant(); - - if (trimmed.StartsWith("#include <", StringComparison.OrdinalIgnoreCase) && trimmed.EndsWith(">", StringComparison.OrdinalIgnoreCase)) - { - HeaderFile d; + var partitions = h.Lines.Select(s => + { + var trimmed = s.Trim().ToLowerInvariant(); - if (headerFiles.TryGetValue(trimmed.Remove(trimmed.Length - 1).Remove(0, "#include <".Length), out d)) - return Tuple.Create(s, d); - else - return Tuple.Create(s, null); - } - return Tuple.Create(s, null); - }) - .ToLookup(p => p.Item2 != null); + if (trimmed.StartsWith("#include <", StringComparison.OrdinalIgnoreCase) && trimmed.EndsWith(">", StringComparison.OrdinalIgnoreCase)) + { + if (headerFiles.TryGetValue(trimmed.Remove(trimmed.Length - 1).Remove(0, "#include <".Length), out HeaderFile d)) + return Tuple.Create(s, d); + else + return Tuple.Create(s, null); + } + return Tuple.Create(s, null); + }) + .ToLookup(p => p.Item2 != null); h.Lines = partitions[false].Select(p => p.Item1).ToList(); h.Dependencies = partitions[true].Select(p => p.Item2).Distinct().ToList(); @@ -174,20 +175,20 @@ public void Execute() // Generate the ordering. - var orderedHeaderFiles = OrderHeaderFiles(_files.Select(s => headerFiles[Path.GetFileName(s).ToLower()]).ToList()); + var orderedHeaderFiles = OrderHeaderFiles(this.Files.Select(s => headerFiles[Path.GetFileName(s).ToLower()]).ToList()); // Process each header file and remove irrelevant content. - foreach (var h in orderedHeaderFiles) + foreach (HeaderFile h in orderedHeaderFiles) h.Lines = ProcessHeaderLines(h.Lines); // Write out the result. - StreamWriter sw = new StreamWriter(_baseDirectory + "\\" + _outputFile); + StreamWriter sw = new StreamWriter(this.BaseDirectory + "\\" + this.OutputFile); // Header - sw.Write(_header); + sw.Write(this.Header); // Header files - foreach (var h in orderedHeaderFiles) + foreach (HeaderFile h in orderedHeaderFiles) { //Console.WriteLine("Header file: " + h.Name); sw.WriteLine(); @@ -196,13 +197,13 @@ public void Execute() sw.WriteLine("//"); sw.WriteLine(); - foreach (var line in h.Lines) + foreach (string line in h.Lines) sw.WriteLine(line); } // Footer - sw.Write(_footer); + sw.Write(this.Footer); sw.Close(); } diff --git a/tools/CustomBuildTool/Source Files/Program.cs b/tools/CustomBuildTool/Source Files/Program.cs index 18ec017a966b..43dd36a01569 100644 --- a/tools/CustomBuildTool/Source Files/Program.cs +++ b/tools/CustomBuildTool/Source Files/Program.cs @@ -32,15 +32,6 @@ public static void Main(string[] args) Build.CleanupBuildEnvironment(); return; } - else if (ProgramArgs.ContainsKey("-updaterev")) - { - if (!Build.InitializeBuildEnvironment(false)) - return; - - Build.ShowBuildEnvironment(false); - Build.UpdateHeaderFileVersion(); - return; - } else if (ProgramArgs.ContainsKey("-phapppub_gen")) { if (!Build.InitializeBuildEnvironment(false)) @@ -103,8 +94,11 @@ public static void Main(string[] args) return; Build.ShowBuildEnvironment(false); + Build.BuildSecureFiles(); + Build.UpdateHeaderFileVersion(); + if (!Build.BuildSolution("ProcessHacker.sln", true, false, true)) return; @@ -146,8 +140,11 @@ public static void Main(string[] args) return; Build.ShowBuildEnvironment(true); + Build.BuildSecureFiles(); + Build.UpdateHeaderFileVersion(); + if (!Build.BuildSolution("ProcessHacker.sln", true, true, true)) return; @@ -181,8 +178,11 @@ public static void Main(string[] args) return; Build.ShowBuildEnvironment(false); + Build.BuildSecureFiles(); + Build.UpdateHeaderFileVersion(); + if (!Build.BuildSolution("ProcessHacker.sln", true, false, true)) return; @@ -213,6 +213,8 @@ public static void Main(string[] args) if (!Build.BuildSetupExe()) return; + Build.BuildPdbZip(); + Build.BuildSdkZip(); Build.BuildSrcZip(); @@ -223,8 +225,11 @@ public static void Main(string[] args) return; Build.ShowBuildEnvironment(false); + Build.BuildSecureFiles(); + Build.UpdateHeaderFileVersion(); + if (!Build.BuildSolution("ProcessHacker.sln", true, false, true)) return; diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe b/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe index 8f33b1499a7fd4f9a9e0be7dcd40113f12acb90f..28649ca0c27566b3a0dfc7e3bdcec903df5a4071 100644 GIT binary patch delta 16187 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 D^X=}5 delta 15335 zcmbVz34B!L)%Usg&fJ-~lbOs+l9@>+Dy%XBLakqWpzWK&plfP1CQtI;&^&+oQL-ZgN8x_$WKDy<>8PzL}5=~+L5z%`c zwnfaH(56xb$uXZ_yGju&jt9Z z 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 Date: Fri, 5 May 2017 19:24:31 +1000 Subject: [PATCH 0052/2058] Tidy up some stuff --- plugins/ExtraPlugins/plugin.c | 18 +++++++++++------- .../HardwareDevices.vcxproj.filters | 8 ++++++-- plugins/HardwareDevices/prpsh.c | 19 +++++++++---------- plugins/ToolStatus/customizetb.c | 2 +- .../CustomSetupTool/uninstall.c | 8 +++----- tools/peview/prpsh.c | 2 +- 6 files changed, 31 insertions(+), 26 deletions(-) diff --git a/plugins/ExtraPlugins/plugin.c b/plugins/ExtraPlugins/plugin.c index 81bb2e63b9e9..2e9b5bbed56f 100644 --- a/plugins/ExtraPlugins/plugin.c +++ b/plugins/ExtraPlugins/plugin.c @@ -242,13 +242,17 @@ PPH_STRING PluginGetVersionInfo( if (info->dwSignature == 0xfeef04bd) { - version = PhFormatString( - L"%lu.%lu.%lu.%lu", - (info->dwFileVersionMS >> 16) & 0xffff, - (info->dwFileVersionMS >> 0) & 0xffff, - (info->dwFileVersionLS >> 16) & 0xffff, - (info->dwFileVersionLS >> 0) & 0xffff - ); + PH_FORMAT fileVersionFormat[7]; + + PhInitFormatU(&fileVersionFormat[0], info->dwFileVersionMS >> 16); + PhInitFormatC(&fileVersionFormat[1], '.'); + PhInitFormatU(&fileVersionFormat[2], info->dwFileVersionMS & 0xffff); + PhInitFormatC(&fileVersionFormat[3], '.'); + PhInitFormatU(&fileVersionFormat[4], info->dwFileVersionLS >> 16); + PhInitFormatC(&fileVersionFormat[5], '.'); + PhInitFormatU(&fileVersionFormat[6], info->dwFileVersionLS & 0xffff); + + version = PhFormat(fileVersionFormat, 7, 30); } } diff --git a/plugins/HardwareDevices/HardwareDevices.vcxproj.filters b/plugins/HardwareDevices/HardwareDevices.vcxproj.filters index 2a5f122356f7..7edc128bdafd 100644 --- a/plugins/HardwareDevices/HardwareDevices.vcxproj.filters +++ b/plugins/HardwareDevices/HardwareDevices.vcxproj.filters @@ -24,7 +24,9 @@ Header Files - + + Header Files + @@ -63,7 +65,9 @@ Source Files\Disk - + + Source Files + diff --git a/plugins/HardwareDevices/prpsh.c b/plugins/HardwareDevices/prpsh.c index 517f1aa9961c..2aa401d4d246 100644 --- a/plugins/HardwareDevices/prpsh.c +++ b/plugins/HardwareDevices/prpsh.c @@ -124,7 +124,7 @@ INT CALLBACK PvpPropSheetProc( { if (lParam) { - if (((DLGTEMPLATEEX *)lParam)->signature == 0xffff) + if (((DLGTEMPLATEEX *)lParam)->signature == USHRT_MAX) { ((DLGTEMPLATEEX *)lParam)->style |= PROPSHEET_ADD_STYLE; } @@ -227,26 +227,25 @@ LRESULT CALLBACK PvpPropSheetWndProc( } BOOLEAN PhpInitializePropSheetLayoutStage1( + _In_ PPV_PROPSHEETCONTEXT PropSheetContext, _In_ HWND hwnd ) { - PPV_PROPSHEETCONTEXT propSheetContext = PvpGetPropSheetContext(hwnd); - - if (!propSheetContext->LayoutInitialized) + if (!PropSheetContext->LayoutInitialized) { HWND tabControlHandle; PPH_LAYOUT_ITEM tabControlItem; PPH_LAYOUT_ITEM tabPageItem; tabControlHandle = PropSheet_GetTabControl(hwnd); - tabControlItem = PhAddLayoutItem(&propSheetContext->LayoutManager, tabControlHandle, + tabControlItem = PhAddLayoutItem(&PropSheetContext->LayoutManager, tabControlHandle, NULL, PH_ANCHOR_ALL | PH_LAYOUT_IMMEDIATE_RESIZE); - tabPageItem = PhAddLayoutItem(&propSheetContext->LayoutManager, tabControlHandle, + tabPageItem = PhAddLayoutItem(&PropSheetContext->LayoutManager, tabControlHandle, NULL, PH_LAYOUT_TAB_CONTROL); // dummy item to fix multiline tab control - propSheetContext->TabPageItem = tabPageItem; + PropSheetContext->TabPageItem = tabPageItem; - PhAddLayoutItem(&propSheetContext->LayoutManager, GetDlgItem(hwnd, IDCANCEL), + PhAddLayoutItem(&PropSheetContext->LayoutManager, GetDlgItem(hwnd, IDCANCEL), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); // Hide the OK button. @@ -256,7 +255,7 @@ BOOLEAN PhpInitializePropSheetLayoutStage1( PhLoadWindowPlacementFromSetting(SETTING_NAME_DISK_POSITION, SETTING_NAME_DISK_SIZE, hwnd); - propSheetContext->LayoutInitialized = TRUE; + PropSheetContext->LayoutInitialized = TRUE; return TRUE; } @@ -385,7 +384,7 @@ PPH_LAYOUT_ITEM PvAddPropPageLayoutItem( propSheetContext = PvpGetPropSheetContext(parent); layoutManager = &propSheetContext->LayoutManager; - PhpInitializePropSheetLayoutStage1(parent); + PhpInitializePropSheetLayoutStage1(propSheetContext, parent); if (ParentItem != PH_PROP_PAGE_TAB_CONTROL_PARENT) realParentItem = ParentItem; diff --git a/plugins/ToolStatus/customizetb.c b/plugins/ToolStatus/customizetb.c index e376e26f749d..cef8fdffbb33 100644 --- a/plugins/ToolStatus/customizetb.c +++ b/plugins/ToolStatus/customizetb.c @@ -840,7 +840,7 @@ INT_PTR CALLBACK CustomizeToolbarDialogProc( if (isFocused) { - FillRect(bufferDc, &bufferRect, context->BrushHot); // leak + FillRect(bufferDc, &bufferRect, context->BrushHot); //FrameRect(bufferDc, &bufferRect, GetStockBrush(BLACK_BRUSH)); if (!itemContext->IsVirtual) diff --git a/tools/CustomSetupTool/CustomSetupTool/uninstall.c b/tools/CustomSetupTool/CustomSetupTool/uninstall.c index da0493de2d9b..4de1817f7517 100644 --- a/tools/CustomSetupTool/CustomSetupTool/uninstall.c +++ b/tools/CustomSetupTool/CustomSetupTool/uninstall.c @@ -48,11 +48,9 @@ VOID ShowUninstallErrorDialog( ); NTSTATUS SetupUninstallBuild( - _In_ PVOID Context + _In_ PPH_SETUP_UNINSTALL_CONTEXT Context ) { - PPH_SETUP_UNINSTALL_CONTEXT context = Context; - SetupFindInstallDirectory(); // Stop Process Hacker. @@ -76,11 +74,11 @@ NTSTATUS SetupUninstallBuild( // Remove the ARP uninstall entry. SetupDeleteUninstallKey(); - ShowUninstallCompleteDialog(context); + ShowUninstallCompleteDialog(Context); return STATUS_SUCCESS; CleanupExit: - ShowUninstallErrorDialog(context); + ShowUninstallErrorDialog(Context); return STATUS_SUCCESS; } diff --git a/tools/peview/prpsh.c b/tools/peview/prpsh.c index ab84021aa15b..e6ac16b05e8e 100644 --- a/tools/peview/prpsh.c +++ b/tools/peview/prpsh.c @@ -127,7 +127,7 @@ INT CALLBACK PvpPropSheetProc( { if (lParam) { - if (((DLGTEMPLATEEX *)lParam)->signature == 0xffff) + if (((DLGTEMPLATEEX *)lParam)->signature == USHRT_MAX) { ((DLGTEMPLATEEX *)lParam)->style |= PROPSHEET_ADD_STYLE; } From 32a65912c32514ffaec78faffa47012b1fec2057 Mon Sep 17 00:00:00 2001 From: lucasg Date: Fri, 5 May 2017 22:22:07 +0200 Subject: [PATCH 0053/2058] [cfg] Fix typos when parsing CFG infos in PE load config (#136) There was some uninspired copy-pastes when adding support for CFG parsing for wow64 PE. --- phlib/mapimg.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/phlib/mapimg.c b/phlib/mapimg.c index b949e3aefc39..9210e2e351c9 100644 --- a/phlib/mapimg.c +++ b/phlib/mapimg.c @@ -1277,7 +1277,7 @@ NTSTATUS PhGetMappedImageCfg64( CfgConfig->NumberOfGuardAdressIatEntries = config64->GuardAddressTakenIatEntryCount; CfgConfig->GuardAdressIatTable = PhMappedImageRvaToVa( MappedImage, - (ULONG)(config64->GuardAddressTakenIatEntryTable - MappedImage->NtHeaders->OptionalHeader.ImageBase), + (ULONG)(ULONG_PTR)PTR_SUB_OFFSET(config64->GuardAddressTakenIatEntryTable, MappedImage->NtHeaders->OptionalHeader.ImageBase), NULL ); @@ -1310,7 +1310,7 @@ NTSTATUS PhGetMappedImageCfg64( CfgConfig->NumberOfGuardLongJumpEntries = config64->GuardLongJumpTargetCount; CfgConfig->GuardLongJumpTable = PhMappedImageRvaToVa( MappedImage, - (ULONG)(config64->GuardLongJumpTargetTable - MappedImage->NtHeaders->OptionalHeader.ImageBase), + (ULONG)(ULONG_PTR)PTR_SUB_OFFSET(config64->GuardLongJumpTargetTable, MappedImage->NtHeaders->OptionalHeader.ImageBase), NULL ); @@ -1397,7 +1397,7 @@ NTSTATUS PhGetMappedImageCfg32( CfgConfig->NumberOfGuardAdressIatEntries = config32->GuardAddressTakenIatEntryCount; CfgConfig->GuardAdressIatTable = PhMappedImageRvaToVa( MappedImage, - (ULONG)(config32->GuardAddressTakenIatEntryTable - MappedImage->NtHeaders->OptionalHeader.ImageBase), + (ULONG)(ULONG_PTR)PTR_SUB_OFFSET(config32->GuardAddressTakenIatEntryTable, MappedImage->NtHeaders32->OptionalHeader.ImageBase), NULL ); @@ -1430,7 +1430,7 @@ NTSTATUS PhGetMappedImageCfg32( CfgConfig->NumberOfGuardLongJumpEntries = config32->GuardLongJumpTargetCount; CfgConfig->GuardLongJumpTable = PhMappedImageRvaToVa( MappedImage, - (ULONG)(config32->GuardLongJumpTargetTable - MappedImage->NtHeaders->OptionalHeader.ImageBase), + (ULONG)(ULONG_PTR)PTR_SUB_OFFSET(config32->GuardLongJumpTargetTable, MappedImage->NtHeaders32->OptionalHeader.ImageBase), NULL ); From 233d227f0e9dfbfa721a664093ae5fcd6b295ca9 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 6 May 2017 06:39:30 +1000 Subject: [PATCH 0054/2058] NetworkTools: Update default geoip database directory --- plugins/NetworkTools/country.c | 4 +-- plugins/NetworkTools/main.c | 57 +--------------------------------- plugins/NetworkTools/options.c | 7 +---- plugins/NetworkTools/update.c | 21 ++----------- 4 files changed, 5 insertions(+), 84 deletions(-) diff --git a/plugins/NetworkTools/country.c b/plugins/NetworkTools/country.c index 147a7ac900ab..f4d0ff2e3078 100644 --- a/plugins/NetworkTools/country.c +++ b/plugins/NetworkTools/country.c @@ -32,10 +32,8 @@ VOID LoadGeoLiteDb( ) { PPH_STRING path; - PPH_STRING directory; - directory = PH_AUTO(PhGetApplicationDirectory()); - path = PhConcatStrings(2, PhGetString(directory), L"Plugins\\plugindata\\GeoLite2-Country.mmdb"); + path = PH_AUTO(PhGetKnownLocation(CSIDL_APPDATA, L"\\Process Hacker\\GeoLite2-Country.mmdb")); if (MMDB_open(PhGetString(path), MMDB_MODE_MMAP, &GeoDb) == MMDB_SUCCESS) { diff --git a/plugins/NetworkTools/main.c b/plugins/NetworkTools/main.c index 129ffafa72c9..9cd8d0992746 100644 --- a/plugins/NetworkTools/main.c +++ b/plugins/NetworkTools/main.c @@ -224,62 +224,7 @@ VOID NTAPI MenuItemCallback( } break; case MAINMENU_ACTION_GEOIP_UPDATE: - { - if (PhGetOwnTokenAttributes().Elevated) - { - ShowGeoIPUpdateDialog(NULL); - } - else - { - TASKDIALOGCONFIG config = { sizeof(config) }; - TASKDIALOG_BUTTON buttons[1]; - INT button; - - config.dwFlags = TDF_CAN_BE_MINIMIZED; - config.pszWindowTitle = L"Process Hacker"; - config.pszMainIcon = TD_ERROR_ICON; - config.pszMainInstruction = L"Unable to update the GeoIP database."; - config.pszContent = L"You will need to provide administrator permission. " - L"Click Continue to complete this operation."; - config.dwCommonButtons = TDCBF_CANCEL_BUTTON; - - buttons[0].nButtonID = IDYES; - buttons[0].pszButtonText = L"Continue"; - - config.cButtons = 1; - config.pButtons = buttons; - config.nDefaultButton = IDYES; - - config.pfCallback = ElevateActionCallbackProc; - - if (TaskDialogIndirect( - &config, - &button, - NULL, - NULL - ) == S_OK && button == IDYES) - { - ProcessHacker_PrepareForEarlyShutdown(PhMainWndHandle); - - if (PhShellProcessHacker( - PhMainWndHandle, - NULL, - SW_SHOW, - PH_SHELL_EXECUTE_ADMIN, - PH_SHELL_APP_PROPAGATE_PARAMETERS | PH_SHELL_APP_PROPAGATE_PARAMETERS_IGNORE_VISIBILITY, - 0, - NULL - )) - { - ProcessHacker_Destroy(PhMainWndHandle); - } - else - { - ProcessHacker_CancelEarlyShutdown(PhMainWndHandle); - } - } - } - } + ShowGeoIPUpdateDialog(NULL); break; } } diff --git a/plugins/NetworkTools/options.c b/plugins/NetworkTools/options.c index e0483f80af03..142402753dd7 100644 --- a/plugins/NetworkTools/options.c +++ b/plugins/NetworkTools/options.c @@ -53,12 +53,7 @@ INT_PTR CALLBACK OptionsDlgProc( } break; case IDC_GEOIP: - { - if (PhGetOwnTokenAttributes().Elevated) - { - ShowGeoIPUpdateDialog(NULL); - } - } + ShowGeoIPUpdateDialog(NULL); break; } } diff --git a/plugins/NetworkTools/update.c b/plugins/NetworkTools/update.c index b4604b58a20c..36a113ec6b45 100644 --- a/plugins/NetworkTools/update.c +++ b/plugins/NetworkTools/update.c @@ -580,13 +580,11 @@ NTSTATUS GeoIPUpdateThread( } PPH_STRING path; - PPH_STRING directory; PPH_STRING fullSetupPath; PPH_BYTES mmdbGzPath; gzFile file; - directory = PH_AUTO(PhGetApplicationDirectory()); - path = PhConcatStrings(2, PhGetString(directory), L"Plugins\\plugindata\\GeoLite2-Country.mmdb"); + path = PH_AUTO(PhGetKnownLocation(CSIDL_APPDATA, L"\\Process Hacker\\GeoLite2-Country.mmdb")); mmdbGzPath = PhConvertUtf16ToUtf8(PhGetString(context->SetupFilePath)); if (RtlDoesFileExists_U(PhGetString(path))) @@ -724,21 +722,6 @@ LRESULT CALLBACK TaskDialogSubclassProc( ShowInstallRestartDialog(context); } break; - case PH_UPDATEFAILURE: - { - // if ((BOOLEAN)wParam) - // ShowUpdateFailedDialog(context, TRUE, FALSE); - // else if ((BOOLEAN)lParam) - // ShowUpdateFailedDialog(context, FALSE, TRUE); - //else - //ShowUpdateFailedDialog(context, FALSE, FALSE); - } - break; - case PH_UPDATEISERRORED: - { - //ShowUpdateFailedDialog(context, FALSE, FALSE); - } - break; } return DefSubclassProc(hwndDlg, uMsg, wParam, lParam); @@ -852,7 +835,7 @@ VOID ShowGeoIPUpdateDialog( _In_opt_ HWND Parent ) { - HANDLE threadHandle = NULL; + HANDLE threadHandle; if (threadHandle = PhCreateThread(0, GeoIPUpdateDialogThread, Parent)) NtClose(threadHandle); From d498091d7f91fcf7382eac90fcc446f33fb43bdb Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 6 May 2017 07:59:01 +1000 Subject: [PATCH 0055/2058] Add token properties page listview settings --- ProcessHacker/settings.c | 2 ++ ProcessHacker/tokprp.c | 18 +++++------------- 2 files changed, 7 insertions(+), 13 deletions(-) diff --git a/ProcessHacker/settings.c b/ProcessHacker/settings.c index d57fafd97072..5412d4960e18 100644 --- a/ProcessHacker/settings.c +++ b/ProcessHacker/settings.c @@ -184,7 +184,9 @@ VOID PhSettingsInitialization( PhpAddStringSetting(L"ThreadTreeListSort", L"1,2"); // 1, DescendingSortOrder PhpAddStringSetting(L"ThreadStackListViewColumns", L""); PhpAddScalableIntegerPairSetting(L"ThreadStackWindowSize", L"@96|420,380"); + PhpAddStringSetting(L"TokenGroupsListViewColumns", L""); PhpAddIntegerSetting(L"TokenSplitterPosition", L"250"); + PhpAddStringSetting(L"TokenPrivilegesListViewColumns", L""); PhpAddIntegerSetting(L"UpdateInterval", L"3e8"); // 1000ms // Colors are specified with R in the lowest byte, then G, then B. diff --git a/ProcessHacker/tokprp.c b/ProcessHacker/tokprp.c index a80fc3f4aac8..897ba39e005e 100644 --- a/ProcessHacker/tokprp.c +++ b/ProcessHacker/tokprp.c @@ -442,6 +442,8 @@ INT_PTR CALLBACK PhpTokenPageProc( ExtendedListView_SetItemColorFunction(groupsLv, PhpTokenGroupColorFunction); PhSetExtendedListView(privilegesLv); ExtendedListView_SetItemColorFunction(privilegesLv, PhpTokenPrivilegeColorFunction); + PhLoadListViewColumnsFromSetting(L"TokenGroupsListViewColumns", groupsLv); + PhLoadListViewColumnsFromSetting(L"TokenPrivilegesListViewColumns", privilegesLv); SetDlgItemText(hwndDlg, IDC_USER, L"Unknown"); SetDlgItemText(hwndDlg, IDC_USERSID, L"Unknown"); @@ -589,6 +591,9 @@ INT_PTR CALLBACK PhpTokenPageProc( break; case WM_DESTROY: { + PhSaveListViewColumnsToSetting(L"TokenGroupsListViewColumns", tokenPageContext->GroupsListViewHandle); + PhSaveListViewColumnsToSetting(L"TokenPrivilegesListViewColumns", tokenPageContext->PrivilegesListViewHandle); + if (tokenPageContext->Groups) PhFree(tokenPageContext->Groups); if (tokenPageContext->Privileges) PhFree(tokenPageContext->Privileges); if (tokenPageContext->HSplitterContext) PhDeleteHSplitter(tokenPageContext->HSplitterContext); @@ -890,19 +895,6 @@ INT_PTR CALLBACK PhpTokenPageProc( { case PSN_QUERYINITIALFOCUS: { - if (ListView_GetItemCount(tokenPageContext->GroupsListViewHandle) != 0) - { - ListView_SetColumnWidth(tokenPageContext->GroupsListViewHandle, 0, LVSCW_AUTOSIZE); - ExtendedListView_SetColumnWidth(tokenPageContext->GroupsListViewHandle, 1, ELVSCW_AUTOSIZE_REMAININGSPACE); - } - - if (ListView_GetItemCount(tokenPageContext->PrivilegesListViewHandle) != 0) - { - ListView_SetColumnWidth(tokenPageContext->PrivilegesListViewHandle, 0, LVSCW_AUTOSIZE); - ListView_SetColumnWidth(tokenPageContext->PrivilegesListViewHandle, 1, LVSCW_AUTOSIZE); - ExtendedListView_SetColumnWidth(tokenPageContext->PrivilegesListViewHandle, 2, ELVSCW_AUTOSIZE_REMAININGSPACE); - } - SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, (LONG_PTR)GetDlgItem(hwndDlg, IDC_SESSIONID)); return TRUE; } From cefcd61fbcec1baaed3eda3ff71cd817526d9e62 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 7 May 2017 02:54:30 +1000 Subject: [PATCH 0056/2058] CustomBuildTool: Fix pdb releases, Add cleanup script, Add appx package build script --- .gitignore | 9 +- build/build_appx_package.cmd | 7 + build/build_clean.cmd | 5 + build/build_debug.cmd | 4 +- build/build_release.cmd | 6 +- build/build_sdk.cmd | 4 +- build/build_sdk_rebuild.cmd | 4 +- plugins/OnlineChecks/onlnchk.h | 2 +- tools/CustomBuildTool/CustomBuildTool.csproj | 13 + .../Properties/Resources.Designer.cs | 83 +++++ .../CustomBuildTool/Properties/Resources.resx | 164 +++++++++ tools/CustomBuildTool/Source Files/Build.cs | 312 +++++++++++++++--- tools/CustomBuildTool/Source Files/Program.cs | 176 ++++++---- tools/CustomBuildTool/Source Files/Zip.cs | 31 +- .../bin/Release/CustomBuildTool.exe | Bin 146432 -> 155648 bytes .../bin/Release/CustomBuildTool.pdb | Bin 62976 -> 71168 bytes .../resources/ProcessHacker.ico | Bin 97449 -> 0 bytes .../CustomSetupTool/resource.rc | 2 +- 18 files changed, 688 insertions(+), 134 deletions(-) create mode 100644 build/build_appx_package.cmd create mode 100644 build/build_clean.cmd create mode 100644 tools/CustomBuildTool/Properties/Resources.Designer.cs create mode 100644 tools/CustomBuildTool/Properties/Resources.resx delete mode 100644 tools/CustomBuildTool/resources/ProcessHacker.ico diff --git a/.gitignore b/.gitignore index 7f672b4c792c..c8bba02b98ab 100644 --- a/.gitignore +++ b/.gitignore @@ -8,8 +8,7 @@ *.key # Build results -*_i.c -*_p.c +*.appx *.ilk *.meta *.obj @@ -24,6 +23,8 @@ *.tlh *.tmp *.vspscc +*_i.c +*_p.c # Visual C++ cache files *.aps @@ -52,7 +53,6 @@ publish [Bb]in [Oo]bj *.Cache -ClientBin ~$* # Backup & report files @@ -70,7 +70,8 @@ Desktop.ini ## Project specific rules ########################## -build/installer/*.exe +build/*.exe +build/*.zip ProcessHacker/include/phapprev.h ProcessHacker/sdk/phapppub.h plugins-extra/ diff --git a/build/build_appx_package.cmd b/build/build_appx_package.cmd new file mode 100644 index 000000000000..54a1f86cb0c3 --- /dev/null +++ b/build/build_appx_package.cmd @@ -0,0 +1,7 @@ +@echo off +@setlocal enableextensions +@cd /d "%~dp0\..\" + +start /B /W "" "tools\CustomBuildTool\bin\Release\CustomBuildTool.exe" "-appxbuild" + +pause \ No newline at end of file diff --git a/build/build_clean.cmd b/build/build_clean.cmd new file mode 100644 index 000000000000..40de19df02f2 --- /dev/null +++ b/build/build_clean.cmd @@ -0,0 +1,5 @@ +@echo off +@setlocal enableextensions +@cd /d "%~dp0\..\" + +start /B /W "" "tools\CustomBuildTool\bin\Release\CustomBuildTool.exe" "-cleanup" diff --git a/build/build_debug.cmd b/build/build_debug.cmd index 7a06cbedd774..8a9027bb842f 100644 --- a/build/build_debug.cmd +++ b/build/build_debug.cmd @@ -1,5 +1,7 @@ @echo off +@setlocal enableextensions +@cd /d "%~dp0\..\" -start /B /W "" "..\tools\CustomBuildTool\bin\Release\CustomBuildTool.exe" "-debug" +start /B /W "" "tools\CustomBuildTool\bin\Release\CustomBuildTool.exe" "-debug" pause diff --git a/build/build_release.cmd b/build/build_release.cmd index c0a55c13da5d..000b928d35a4 100644 --- a/build/build_release.cmd +++ b/build/build_release.cmd @@ -1,5 +1,7 @@ @echo off +@setlocal enableextensions +@cd /d "%~dp0\..\" -start /B /W "" "..\tools\CustomBuildTool\bin\Release\CustomBuildTool.exe" "-release" +start /B /W "" "tools\CustomBuildTool\bin\Release\CustomBuildTool.exe" "-release" -pause \ No newline at end of file +pause diff --git a/build/build_sdk.cmd b/build/build_sdk.cmd index 0bed04835688..c3dc6044491f 100644 --- a/build/build_sdk.cmd +++ b/build/build_sdk.cmd @@ -1,3 +1,5 @@ @echo off +@setlocal enableextensions +@cd /d "%~dp0\..\" -start /B /W "" "..\tools\CustomBuildTool\bin\Release\CustomBuildTool.exe" "-sdk" \ No newline at end of file +start /B /W "" "tools\CustomBuildTool\bin\Release\CustomBuildTool.exe" "-sdk" diff --git a/build/build_sdk_rebuild.cmd b/build/build_sdk_rebuild.cmd index 57ead1eee13e..19ad008487ba 100644 --- a/build/build_sdk_rebuild.cmd +++ b/build/build_sdk_rebuild.cmd @@ -1,5 +1,7 @@ @echo off +@setlocal enableextensions +@cd /d "%~dp0\..\" -start /B /W "" "..\tools\CustomBuildTool\bin\Release\CustomBuildTool.exe" "-cleansdk" +start /B /W "" "tools\CustomBuildTool\bin\Release\CustomBuildTool.exe" "-cleansdk" pause diff --git a/plugins/OnlineChecks/onlnchk.h b/plugins/OnlineChecks/onlnchk.h index 498933978ecd..b53854ca4e17 100644 --- a/plugins/OnlineChecks/onlnchk.h +++ b/plugins/OnlineChecks/onlnchk.h @@ -41,7 +41,7 @@ #define SETTING_NAME_VIRUSTOTAL_SCAN_ENABLED (PLUGIN_NAME L".EnableVirusTotalScanning") #define SETTING_NAME_VIRUSTOTAL_HIGHLIGHT_DETECTIONS (PLUGIN_NAME L".VirusTotalHighlightDetection") -#ifdef VIRUSTOTAL_API +#ifdef PH_BUILD_API #include "virustotal.h" #else #define VIRUSTOTAL_URLPATH L"" diff --git a/tools/CustomBuildTool/CustomBuildTool.csproj b/tools/CustomBuildTool/CustomBuildTool.csproj index b981e8ec1f99..a5f7110ee6c5 100644 --- a/tools/CustomBuildTool/CustomBuildTool.csproj +++ b/tools/CustomBuildTool/CustomBuildTool.csproj @@ -40,6 +40,7 @@ 4 false false + true AnyCPU @@ -52,6 +53,7 @@ 4 false true + true CustomBuildTool.Program @@ -76,6 +78,11 @@ + + True + True + Resources.resx + @@ -108,6 +115,12 @@ + + + ResXFileCodeGenerator + Resources.Designer.cs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + <?xml version='1.0' encoding='utf-8' standalone='yes'?> +<Package + xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10" + xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10" + xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"> + <Identity + Name="ProcessHacker" + Version="PH_APPX_VERSION" + ProcessorArchitecture="x86" + Publisher="CN=ProcessHacker, O=ProcessHacker, C=AU" /> + <Properties> + <DisplayName>Process Hacker</DisplayName> + <PublisherDisplayName>Process Hacker</PublisherDisplayName> + <Description>ProcessHacker</Description> + <Logo>Assets\ProcessHacker-48.png</Logo> + </Properties> + <Resources> + <Resource Language="en-US" /> + </Resources> + <Dependencies> + <TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.14316.0" MaxVersionTested="10.0.15063.0" /> + </Dependencies> + <Capabilities> + <rescap:Capability Name="runFullTrust"/> + </Capabilities> + <Applications> + <Application Id="ProcessHacker" Executable="ProcessHacker.exe" EntryPoint="Windows.FullTrustApplication"> + <uap:VisualElements + BackgroundColor="transparent" + DisplayName="ProcessHacker" + Square150x150Logo="Assets\ProcessHacker-150.png" + Square44x44Logo="Assets\ProcessHacker-44.png" + Description="ProcessHacker"> + <uap:DefaultTile> + <uap:ShowNameOnTiles> + <uap:ShowOn Tile="square150x150Logo" /> + </uap:ShowNameOnTiles> + </uap:DefaultTile> + </uap:VisualElements> + </Application> + </Applications> +</Package> + + \ No newline at end of file diff --git a/tools/CustomBuildTool/Source Files/Build.cs b/tools/CustomBuildTool/Source Files/Build.cs index 835b79b8565e..3963a1f96c54 100644 --- a/tools/CustomBuildTool/Source Files/Build.cs +++ b/tools/CustomBuildTool/Source Files/Build.cs @@ -2,6 +2,7 @@ using System.IO; using System.Net.Http; using System.Security; +using System.Security.Cryptography.X509Certificates; using System.Text; namespace CustomBuildTool @@ -12,8 +13,9 @@ public static class Build private static DateTime TimeStart; private static bool BuildNightly = false; private static string BuildBranch = "master"; - private static string BuildOutputFolder = "ClientBin"; + private static string BuildOutputFolder = "build"; private static string BuildVersion; + private static string BuildLongVersion; private static string BuildRevision; private static string BuildMessage; private static long BuildSetupFileLength; @@ -23,7 +25,9 @@ public static class Build private static string BuildSetupSig; private static string GitExePath; private static string MSBuildExePath; - private static string CustomSignToolPath = "tools\\CustomSignTool\\bin\\Release32\\CustomSignTool.exe"; + private static string CertUtilExePath; + private static string MakeAppxExePath; + private static string CustomSignToolPath; #region Build Config private static readonly string[] sdk_directories = @@ -118,6 +122,9 @@ public static bool InitializeBuildEnvironment(bool CheckDependencies) TimeStart = DateTime.Now; GitExePath = Environment.ExpandEnvironmentVariables("%ProgramFiles%\\Git\\cmd\\git.exe"); MSBuildExePath = Environment.ExpandEnvironmentVariables(VisualStudio.GetMsbuildFilePath()); + CertUtilExePath = Environment.ExpandEnvironmentVariables("%SystemRoot%\\system32\\Certutil.exe"); + MakeAppxExePath = Environment.ExpandEnvironmentVariables("%ProgramFiles(x86)%\\Windows Kits\\10\\bin\\x64\\MakeAppx.exe"); + CustomSignToolPath = "tools\\CustomSignTool\\bin\\Release32\\CustomSignTool.exe"; BuildNightly = !string.Equals(Environment.ExpandEnvironmentVariables("%APPVEYOR_BUILD_API%"), "%APPVEYOR_BUILD_API%", StringComparison.OrdinalIgnoreCase); try @@ -181,11 +188,31 @@ public static bool InitializeBuildEnvironment(bool CheckDependencies) public static void CleanupBuildEnvironment() { - Program.PrintColorMessage("Cleaning up build environment...", ConsoleColor.Cyan); + string[] cleanupFileArray = + { + BuildOutputFolder + "\\processhacker-build-setup.exe", + BuildOutputFolder + "\\processhacker-build-bin.zip", + BuildOutputFolder + "\\processhacker-build-src.zip", + BuildOutputFolder + "\\processhacker-build-sdk.zip", + BuildOutputFolder + "\\processhacker-build-pdb.zip", + BuildOutputFolder + "\\processhacker-build-package.appx", + BuildOutputFolder + "\\processhacker-build-checksums.txt", + BuildOutputFolder + "\\processhacker-" + BuildVersion + "-setup.exe", + BuildOutputFolder + "\\processhacker-" + BuildVersion + "-bin.zip", + BuildOutputFolder + "\\processhacker-" + BuildVersion + "-src.zip", + BuildOutputFolder + "\\processhacker-" + BuildVersion + "-sdk.zip", + BuildOutputFolder + "\\processhacker-" + BuildVersion + "-pdb.zip", + BuildOutputFolder + "\\processhacker-" + BuildVersion + "-package.appx", + BuildOutputFolder + "\\processhacker-" + BuildVersion + "-checksums.txt" + }; try { - + for (int i = 0; i < cleanupFileArray.Length; i++) + { + if (File.Exists(cleanupFileArray[i])) + File.Delete(cleanupFileArray[i]); + } } catch (Exception ex) { @@ -205,7 +232,8 @@ public static void ShowBuildEnvironment(bool ShowBuildInfo) else BuildRevision = latestGitRevision.Trim(); - BuildVersion = "3.0." + BuildRevision; // TODO: Remove hard-coded major/minor version. + BuildVersion = "3.0." + BuildRevision; + BuildLongVersion = "3.0.0." + BuildRevision; BuildMessage = Win32.ExecCommand(GitExePath, "log -n 5 --date=format:%Y-%m-%d --pretty=format:\"[%cd] %an %s\" --abbrev-commit"); if (ShowBuildInfo) @@ -305,21 +333,27 @@ public static bool CopyKProcessHacker(bool DebugBuild) return true; } - public static bool CopyLibFiles(bool DebugBuild) + public static bool CopyLibFiles(BuildFlags Flags) { Program.PrintColorMessage("Copying Plugin SDK linker files...", ConsoleColor.Cyan); try { - if (DebugBuild) + if (Flags.HasFlag(BuildFlags.BuildDebug)) { - File.Copy("bin\\Debug32\\ProcessHacker.lib", "sdk\\lib\\i386\\ProcessHacker.lib", true); - File.Copy("bin\\Debug64\\ProcessHacker.lib", "sdk\\lib\\amd64\\ProcessHacker.lib", true); + if (Flags.HasFlag(BuildFlags.Build32bit)) + File.Copy("bin\\Debug32\\ProcessHacker.lib", "sdk\\lib\\i386\\ProcessHacker.lib", true); + + if (Flags.HasFlag(BuildFlags.Build64bit)) + File.Copy("bin\\Debug64\\ProcessHacker.lib", "sdk\\lib\\amd64\\ProcessHacker.lib", true); } else { - File.Copy("bin\\Release32\\ProcessHacker.lib", "sdk\\lib\\i386\\ProcessHacker.lib", true); - File.Copy("bin\\Release64\\ProcessHacker.lib", "sdk\\lib\\amd64\\ProcessHacker.lib", true); + if (Flags.HasFlag(BuildFlags.Build32bit)) + File.Copy("bin\\Release32\\ProcessHacker.lib", "sdk\\lib\\i386\\ProcessHacker.lib", true); + + if (Flags.HasFlag(BuildFlags.Build64bit)) + File.Copy("bin\\Release64\\ProcessHacker.lib", "sdk\\lib\\amd64\\ProcessHacker.lib", true); } } catch (Exception ex) @@ -331,13 +365,13 @@ public static bool CopyLibFiles(bool DebugBuild) return true; } - public static bool CopyWow64Files(bool DebugBuild) + public static bool CopyWow64Files(BuildFlags Flags) { Program.PrintColorMessage("Copying Wow64 support files...", ConsoleColor.Cyan); try { - if (DebugBuild) + if (Flags.HasFlag(BuildFlags.BuildDebug)) { if (!Directory.Exists("bin\\Debug64\\x86")) Directory.CreateDirectory("bin\\Debug64\\x86"); @@ -356,10 +390,14 @@ public static bool CopyWow64Files(bool DebugBuild) if (!Directory.Exists("bin\\Release64\\x86\\plugins")) Directory.CreateDirectory("bin\\Release64\\x86\\plugins"); - File.Copy("bin\\Release32\\ProcessHacker.exe", "bin\\Release64\\x86\\ProcessHacker.exe", true); - File.Copy("bin\\Release32\\ProcessHacker.pdb", "bin\\Release64\\x86\\ProcessHacker.pdb", true); - File.Copy("bin\\Release32\\plugins\\DotNetTools.dll", "bin\\Release64\\x86\\plugins\\DotNetTools.dll", true); - File.Copy("bin\\Release32\\plugins\\DotNetTools.pdb", "bin\\Release64\\x86\\plugins\\DotNetTools.pdb", true); + if (File.Exists("bin\\Release32\\ProcessHacker.exe")) + File.Copy("bin\\Release32\\ProcessHacker.exe", "bin\\Release64\\x86\\ProcessHacker.exe", true); + if (File.Exists("bin\\Release32\\ProcessHacker.pdb")) + File.Copy("bin\\Release32\\ProcessHacker.pdb", "bin\\Release64\\x86\\ProcessHacker.pdb", true); + if (File.Exists("bin\\Release32\\plugins\\DotNetTools.dll")) + File.Copy("bin\\Release32\\plugins\\DotNetTools.dll", "bin\\Release64\\x86\\plugins\\DotNetTools.dll", true); + if (File.Exists("bin\\Release32\\plugins\\DotNetTools.pdb")) + File.Copy("bin\\Release32\\plugins\\DotNetTools.pdb", "bin\\Release64\\x86\\plugins\\DotNetTools.pdb", true); } } catch (Exception ex) @@ -459,6 +497,177 @@ public static bool FixupResourceHeader() return true; } +#region Appx Package + public static void BuildAppxPackage() + { + Program.PrintColorMessage("Building processhacker-build-package.appx...", ConsoleColor.Cyan); + + try + { + StringBuilder sb = new StringBuilder(0x100); + int startIndex = "bin\\Release64\\".Length; + string[] filesToAdd; + + File.WriteAllText("build\\AppxManifest.xml", Properties.Resources.AppxManifest.Replace("PH_APPX_VERSION", BuildLongVersion)); + + sb.AppendLine("[Files]"); + sb.AppendLine("\"build\\AppxManifest.xml\" \"AppxManifest.xml\""); + sb.AppendLine("\"ProcessHacker\\resources\\ProcessHacker.png\" \"Assets\\ProcessHacker-44.png\""); + sb.AppendLine("\"ProcessHacker\\resources\\ProcessHacker.png\" \"Assets\\ProcessHacker-48.png\""); + sb.AppendLine("\"ProcessHacker\\resources\\ProcessHacker.png\" \"Assets\\ProcessHacker-150.png\""); + + filesToAdd = Directory.GetFiles("bin\\Release64", "*", SearchOption.AllDirectories); + + for (int i = 0; i < filesToAdd.Length; i++) + { + string filePath = filesToAdd[i]; + + // Ignore junk files + if (filePath.EndsWith(".pdb", StringComparison.OrdinalIgnoreCase) || + filePath.EndsWith(".iobj", StringComparison.OrdinalIgnoreCase) || + filePath.EndsWith(".ipdb", StringComparison.OrdinalIgnoreCase) || + filePath.EndsWith(".exp", StringComparison.OrdinalIgnoreCase) || + filePath.EndsWith(".lib", StringComparison.OrdinalIgnoreCase)) + { + continue; + } + + sb.AppendLine("\"" + filePath + "\" \"" + filePath.Substring(startIndex) + "\""); + } + + File.WriteAllText("build\\package.map", sb.ToString()); + + string error = Win32.ExecCommand( + MakeAppxExePath, + "pack /o /f build\\package.map /p " + BuildOutputFolder + "\\processhacker-build-package.appx" + ); + + if (File.Exists("build\\AppxManifest.xml")) + File.Delete("build\\AppxManifest.xml"); + if (File.Exists("build\\package.map")) + File.Delete("build\\package.map"); + + if (string.IsNullOrEmpty(error) || !error.EndsWith("Package creation succeeded.", StringComparison.OrdinalIgnoreCase)) + { + Program.PrintColorMessage("[ERROR] " + error, ConsoleColor.Red); + return; + } + + string signToolExePath = Environment.ExpandEnvironmentVariables("%ProgramFiles(x86)%\\Windows Kits\\10\\bin\\x64\\SignTool.exe"); + + error = Win32.ExecCommand( + signToolExePath, + "sign /v /fd SHA256 /a /f build\\appx.pfx /td SHA256 " + BuildOutputFolder + "\\processhacker-build-package.appx" + ); + + if (string.IsNullOrEmpty(error) || error.Contains("Successfully signed")) + { + Program.PrintColorMessage(Environment.NewLine + error, ConsoleColor.DarkGray); + return; + } + } + catch (Exception ex) + { + Program.PrintColorMessage("[ERROR] " + ex, ConsoleColor.Red); + } + } + + public static bool BuildAppxSignature() + { + Program.PrintColorMessage("Building Appx Signature...", ConsoleColor.Cyan); + + var makeCertExePath = Environment.ExpandEnvironmentVariables("%ProgramFiles(x86)%\\Windows Kits\\10\\bin\\x64\\MakeCert.exe"); + var pvk2PfxExePath = Environment.ExpandEnvironmentVariables("%ProgramFiles(x86)%\\Windows Kits\\10\\bin\\x64\\Pvk2Pfx.exe"); + + try + { + if (File.Exists("build\\processhacker-appx.pvk")) + File.Delete("build\\processhacker-appx.pvk"); + if (File.Exists("build\\processhacker-appx.cer")) + File.Delete("build\\processhacker-appx.cer"); + if (File.Exists("build\\processhacker-appx.pfx")) + File.Delete("build\\processhacker-appx.pfx"); + + string output = Win32.ExecCommand(makeCertExePath, + "/n " + + "\"CN=ProcessHacker, O=ProcessHacker, C=AU\" " + + "/r /h 0 " + + "/eku \"1.3.6.1.5.5.7.3.3,1.3.6.1.4.1.311.10.3.13\" " + + "/sv " + + "build\\processhacker-appx.pvk " + + "build\\processhacker-appx.cer " + ); + + if (string.IsNullOrEmpty(output) || !output.Equals("Succeeded", StringComparison.OrdinalIgnoreCase)) + { + Program.PrintColorMessage("[MakeCert] " + output, ConsoleColor.Red); + return false; + } + + output = Win32.ExecCommand(pvk2PfxExePath, + "/pvk build\\processhacker-appx.pvk " + + "/spc build\\processhacker-appx.cer " + + "/pfx build\\processhacker-appx.pfx " + ); + + if (!string.IsNullOrEmpty(output)) + { + Program.PrintColorMessage("[Pvk2Pfx] " + output, ConsoleColor.Red); + return false; + } + + output = Win32.ExecCommand(CertUtilExePath, + "-addStore TrustedPeople build\\processhacker-appx.cer" + ); + + if (string.IsNullOrEmpty(output) || !output.Contains("command completed successfully")) + { + Program.PrintColorMessage("[Certutil] " + output, ConsoleColor.Red); + return false; + } + } + catch (Exception ex) + { + Program.PrintColorMessage("[ERROR] " + ex, ConsoleColor.Red); + return false; + } + + return true; + } + + public static bool CleanupAppxSignature() + { + try + { + X509Store store = new X509Store(StoreName.TrustedPeople, StoreLocation.LocalMachine); + store.Open(OpenFlags.ReadWrite); + + foreach (X509Certificate2 c in store.Certificates) + { + if (c.Subject.Equals("CN=ProcessHacker, O=ProcessHacker, C=AU", StringComparison.OrdinalIgnoreCase)) + { + Console.WriteLine("Removing: {0}", c.Subject); + store.Remove(c); + } + } + + if (File.Exists("build\\processhacker-appx.pvk")) + File.Delete("build\\processhacker-appx.pvk"); + if (File.Exists("build\\processhacker-appx.cer")) + File.Delete("build\\processhacker-appx.cer"); + if (File.Exists("build\\processhacker-appx.pfx")) + File.Delete("build\\processhacker-appx.pfx"); + } + catch (Exception ex) + { + Program.PrintColorMessage("[ERROR] " + ex, ConsoleColor.Red); + return false; + } + + return true; + } +#endregion + public static bool BuildKphSignatureFile(bool DebugBuild) { string output; @@ -591,9 +800,9 @@ public static bool BuildSecureFiles() public static bool BuildSetupExe() { - Program.PrintColorMessage("Building build-setup.exe...", ConsoleColor.Cyan); + Program.PrintColorMessage("Building build-setup.exe...", ConsoleColor.Cyan, true, BuildFlags.BuildVerbose); - if (!BuildSolution("tools\\CustomSetupTool\\CustomSetupTool.sln", false, false, false)) + if (!BuildSolution("tools\\CustomSetupTool\\CustomSetupTool.sln", BuildFlags.Build32bit | BuildFlags.BuildVerbose)) return false; try @@ -712,11 +921,7 @@ public static bool BuildPdbZip() if (File.Exists(BuildOutputFolder + "\\processhacker-build-pdb.zip")) File.Delete(BuildOutputFolder + "\\processhacker-build-pdb.zip"); - // *.pdb # Include only PDB files - // Debug32 # Ignore junk directories - // Debug64 - // Obj - //Zip.CreateCompressedFolder("sdk", BuildOutputFolder + "\\processhacker-build-pdb.zip"); + Zip.CreateCompressedPdbFromFolder(".\\", BuildOutputFolder + "\\processhacker-build-pdb.zip"); } catch (Exception ex) { @@ -930,10 +1135,9 @@ public static bool AppveyorUploadBuildFiles() return true; } + public static bool UpdateHeaderFileVersion() { - Program.PrintColorMessage("Updating Process Hacker build revision...", ConsoleColor.Cyan); - try { if (File.Exists("ProcessHacker\\include\\phapprev.h")) @@ -950,7 +1154,7 @@ public static bool UpdateHeaderFileVersion() } catch (Exception ex) { - Program.PrintColorMessage("[ERROR] " + ex.ToString(), ConsoleColor.Yellow); + Program.PrintColorMessage("[phapprev] " + ex.ToString(), ConsoleColor.Yellow); return false; } @@ -975,45 +1179,59 @@ public static bool BuildPublicHeaderFiles() return true; } - public static bool BuildSolution(string Solution, bool Build64bit, bool BuildDebug, bool Verbose) + + public static bool BuildSolution(string Solution, BuildFlags Flags) { - if (Verbose) + if ((Flags & BuildFlags.Build32bit) == BuildFlags.Build32bit) { - Program.PrintColorMessage("Building " + Path.GetFileNameWithoutExtension(Solution) + " (", ConsoleColor.Cyan, false); - Program.PrintColorMessage("x32", ConsoleColor.Green, false); - Program.PrintColorMessage(")...", ConsoleColor.Cyan); - } + Program.PrintColorMessage("Building " + Path.GetFileNameWithoutExtension(Solution) + " (", ConsoleColor.Cyan, false, Flags); + Program.PrintColorMessage("x32", ConsoleColor.Green, false, Flags); + Program.PrintColorMessage(")...", ConsoleColor.Cyan, true, Flags); - string error32 = Win32.ExecCommand( - MSBuildExePath, - "/m /nologo /verbosity:quiet /p:Configuration=" + (BuildDebug ? "Debug" : "Release") + " /p:Platform=Win32 " + Solution - ); + string error32 = Win32.ExecCommand( + MSBuildExePath, + "/m /nologo /verbosity:quiet /p:Configuration=" + (Flags.HasFlag(BuildFlags.BuildDebug) ? "Debug" : "Release") + " /p:Platform=Win32 " + Solution + ); - if (!string.IsNullOrEmpty(error32)) - { - Program.PrintColorMessage("[ERROR] " + error32, ConsoleColor.Red); - return false; + if (!string.IsNullOrEmpty(error32)) + { + Program.PrintColorMessage("[ERROR] " + error32, ConsoleColor.Red, true, Flags); + return false; + } } - if (Build64bit) + if ((Flags & BuildFlags.Build64bit) == BuildFlags.Build64bit) { - Program.PrintColorMessage("Building " + Path.GetFileNameWithoutExtension(Solution) + " (", ConsoleColor.Cyan, false); - Program.PrintColorMessage("x64", ConsoleColor.Green, false); - Program.PrintColorMessage(")...", ConsoleColor.Cyan); + Program.PrintColorMessage("Building " + Path.GetFileNameWithoutExtension(Solution) + " (", ConsoleColor.Cyan, false, Flags); + Program.PrintColorMessage("x64", ConsoleColor.Green, false, Flags); + Program.PrintColorMessage(")...", ConsoleColor.Cyan, true, Flags); string error64 = Win32.ExecCommand( MSBuildExePath, - "/m /nologo /verbosity:quiet /p:Configuration=" + (BuildDebug ? "Debug" : "Release") + " /p:Platform=x64 " + Solution + "/m /nologo /verbosity:quiet /p:Configuration=" + (Flags.HasFlag(BuildFlags.BuildDebug) ? "Debug" : "Release") + " /p:Platform=x64 /p:ExternalCompilerOptions=PH_BUILD_API " + Solution ); if (!string.IsNullOrEmpty(error64)) { - Program.PrintColorMessage("[ERROR] " + error64, ConsoleColor.Red); + Program.PrintColorMessage("[ERROR] " + error64, ConsoleColor.Red, true, Flags); return false; } } return true; } + + } + + + + [Flags] + public enum BuildFlags + { + None, + Build32bit = 0x1, + Build64bit = 0x2, + BuildDebug = 0x4, + BuildVerbose = 0x8 } } diff --git a/tools/CustomBuildTool/Source Files/Program.cs b/tools/CustomBuildTool/Source Files/Program.cs index 43dd36a01569..52e7258d2990 100644 --- a/tools/CustomBuildTool/Source Files/Program.cs +++ b/tools/CustomBuildTool/Source Files/Program.cs @@ -7,30 +7,20 @@ public static class Program { public static Dictionary ProgramArgs; - public static void PrintColorMessage(string Message, ConsoleColor Color, bool Newline = true) - { - Console.ForegroundColor = Color; - - if (Newline) - Console.WriteLine(Message); - else - Console.Write(Message); - - Console.ResetColor(); - } - public static void Main(string[] args) { ProgramArgs = ParseArgs(args); if (ProgramArgs.ContainsKey("-cleanup")) { - if (!Build.InitializeBuildEnvironment(false)) + if (!Build.InitializeBuildEnvironment(true)) return; - + Build.CleanupAppxSignature(); + Build.CleanupBuildEnvironment(); - return; + + Build.ShowBuildStats(true); } else if (ProgramArgs.ContainsKey("-phapppub_gen")) { @@ -38,12 +28,10 @@ public static void Main(string[] args) return; Build.BuildPublicHeaderFiles(); - return; } else if (ProgramArgs.ContainsKey("-sign")) { Build.BuildKphSignatureFile(false); - return; } else if (ProgramArgs.ContainsKey("-sdk")) { @@ -52,41 +40,36 @@ public static void Main(string[] args) if (!Build.CopyPluginSdkHeaders()) return; - if (!Build.CopyVersionHeader()) return; - if (!Build.FixupResourceHeader()) return; - if (!Build.CopyLibFiles(false)) + if (!Build.CopyLibFiles(BuildFlags.Build32bit | BuildFlags.Build64bit | BuildFlags.BuildVerbose)) return; Build.ShowBuildStats(false); - return; } else if (ProgramArgs.ContainsKey("-cleansdk")) { if (!Build.InitializeBuildEnvironment(false)) return; - if (!Build.BuildSolution("ProcessHacker.sln", true, false, true)) + if (!Build.BuildSolution("ProcessHacker.sln", + BuildFlags.Build32bit | BuildFlags.Build64bit | BuildFlags.BuildVerbose)) return; - + if (!Build.CopyPluginSdkHeaders()) return; - if (!Build.CopyVersionHeader()) return; - if (!Build.FixupResourceHeader()) return; - - if (!Build.CopyLibFiles(false)) + if (!Build.CopyLibFiles( + BuildFlags.Build32bit | BuildFlags.Build64bit | BuildFlags.BuildVerbose)) return; Build.ShowBuildStats(false); - return; } else if (ProgramArgs.ContainsKey("-bin")) { @@ -94,41 +77,37 @@ public static void Main(string[] args) return; Build.ShowBuildEnvironment(false); - Build.BuildSecureFiles(); - Build.UpdateHeaderFileVersion(); - if (!Build.BuildSolution("ProcessHacker.sln", true, false, true)) + if (!Build.BuildSolution("ProcessHacker.sln", + BuildFlags.Build32bit | BuildFlags.Build64bit | BuildFlags.BuildVerbose)) return; - + if (!Build.BuildKphSignatureFile(false)) return; - if (!Build.CopyTextFiles()) return; - if (!Build.CopyKProcessHacker(false)) return; - if (!Build.CopyPluginSdkHeaders()) return; - if (!Build.CopyVersionHeader()) return; - if (!Build.FixupResourceHeader()) return; - if (!Build.CopyLibFiles(false)) + if (!Build.CopyLibFiles( + BuildFlags.Build32bit | BuildFlags.Build64bit | BuildFlags.BuildVerbose)) return; - if (!Build.BuildSolution("plugins\\Plugins.sln", true, false, true)) + if (!Build.BuildSolution("plugins\\Plugins.sln", + BuildFlags.Build32bit | BuildFlags.Build64bit | BuildFlags.BuildVerbose)) return; - if (!Build.CopyWow64Files(false)) + if (!Build.CopyWow64Files(BuildFlags.None)) return; - + if (!Build.BuildBinZip()) return; @@ -140,12 +119,11 @@ public static void Main(string[] args) return; Build.ShowBuildEnvironment(true); - Build.BuildSecureFiles(); - Build.UpdateHeaderFileVersion(); - - if (!Build.BuildSolution("ProcessHacker.sln", true, true, true)) + if (!Build.BuildSolution("ProcessHacker.sln", + BuildFlags.Build32bit | BuildFlags.Build64bit | + BuildFlags.BuildDebug | BuildFlags.BuildVerbose)) return; if (!Build.BuildKphSignatureFile(true)) @@ -154,36 +132,38 @@ public static void Main(string[] args) return; if (!Build.CopyKProcessHacker(true)) return; - if (!Build.CopyPluginSdkHeaders()) return; if (!Build.CopyVersionHeader()) return; if (!Build.FixupResourceHeader()) return; - if (!Build.CopyLibFiles(true)) + if (!Build.CopyLibFiles( + BuildFlags.Build32bit | BuildFlags.Build64bit | + BuildFlags.BuildDebug | BuildFlags.BuildVerbose)) return; - if (!Build.BuildSolution("plugins\\Plugins.sln", true, true, true)) + if (!Build.BuildSolution("plugins\\Plugins.sln", + BuildFlags.Build32bit | BuildFlags.Build64bit | + BuildFlags.BuildDebug | BuildFlags.BuildVerbose)) return; - if (!Build.CopyWow64Files(true)) + if (!Build.CopyWow64Files(BuildFlags.BuildDebug)) return; Build.ShowBuildStats(true); } else if (ProgramArgs.ContainsKey("-release")) { - if (!Build.InitializeBuildEnvironment(false)) + if (!Build.InitializeBuildEnvironment(true)) return; - Build.ShowBuildEnvironment(false); - + Build.ShowBuildEnvironment(true); Build.BuildSecureFiles(); - Build.UpdateHeaderFileVersion(); - if (!Build.BuildSolution("ProcessHacker.sln", true, false, true)) + if (!Build.BuildSolution("ProcessHacker.sln", + BuildFlags.Build32bit | BuildFlags.Build64bit | BuildFlags.BuildVerbose)) return; if (!Build.BuildKphSignatureFile(false)) @@ -192,45 +172,44 @@ public static void Main(string[] args) return; if (!Build.CopyKProcessHacker(false)) return; - if (!Build.CopyPluginSdkHeaders()) return; if (!Build.CopyVersionHeader()) return; if (!Build.FixupResourceHeader()) return; - if (!Build.CopyLibFiles(false)) + if (!Build.CopyLibFiles( + BuildFlags.Build32bit | BuildFlags.Build64bit | BuildFlags.BuildVerbose)) return; - if (!Build.BuildSolution("plugins\\Plugins.sln", true, false, true)) + if (!Build.BuildSolution("plugins\\Plugins.sln", + BuildFlags.Build32bit | BuildFlags.Build64bit | BuildFlags.BuildVerbose)) return; - if (!Build.CopyWow64Files(false)) + if (!Build.CopyWow64Files(BuildFlags.None)) return; if (!Build.BuildBinZip()) return; if (!Build.BuildSetupExe()) return; - Build.BuildPdbZip(); - Build.BuildSdkZip(); - Build.BuildSrcZip(); + + Build.ShowBuildStats(true); } else if (ProgramArgs.ContainsKey("-appveyor")) { - if (!Build.InitializeBuildEnvironment(false)) + if (!Build.InitializeBuildEnvironment(true)) return; Build.ShowBuildEnvironment(false); - Build.BuildSecureFiles(); - Build.UpdateHeaderFileVersion(); - if (!Build.BuildSolution("ProcessHacker.sln", true, false, true)) + if (!Build.BuildSolution("ProcessHacker.sln", + BuildFlags.Build32bit | BuildFlags.Build64bit | BuildFlags.BuildVerbose)) return; if (!Build.BuildKphSignatureFile(false)) @@ -239,27 +218,27 @@ public static void Main(string[] args) return; if (!Build.CopyKProcessHacker(false)) return; - if (!Build.CopyPluginSdkHeaders()) return; if (!Build.CopyVersionHeader()) return; if (!Build.FixupResourceHeader()) return; - if (!Build.CopyLibFiles(false)) + if (!Build.CopyLibFiles( + BuildFlags.Build32bit | BuildFlags.Build64bit | BuildFlags.BuildVerbose)) return; - if (!Build.BuildSolution("plugins\\Plugins.sln", true, false, true)) + if (!Build.BuildSolution("plugins\\Plugins.sln", + BuildFlags.Build32bit | BuildFlags.Build64bit | BuildFlags.BuildVerbose)) return; - if (!Build.CopyWow64Files(false)) + if (!Build.CopyWow64Files(BuildFlags.None)) return; if (!Build.BuildBinZip()) return; if (!Build.BuildSetupExe()) return; - if (!Build.BuildChecksumsFile()) return; if (!Build.BuildUpdateSignature()) @@ -268,6 +247,50 @@ public static void Main(string[] args) if (Build.AppveyorUploadBuildFiles()) Build.WebServiceUpdateConfig(); } + else if (ProgramArgs.ContainsKey("-appxbuild")) + { + if (!Build.InitializeBuildEnvironment(true)) + return; + + Build.ShowBuildEnvironment(true); + Build.BuildSecureFiles(); + Build.UpdateHeaderFileVersion(); + + if (!Build.BuildSolution("ProcessHacker.sln", BuildFlags.Build64bit | BuildFlags.BuildVerbose)) + return; + + if (!Build.CopyTextFiles()) + return; + if (!Build.CopyPluginSdkHeaders()) + return; + if (!Build.CopyVersionHeader()) + return; + if (!Build.FixupResourceHeader()) + return; + if (!Build.CopyLibFiles(BuildFlags.Build64bit | BuildFlags.BuildVerbose)) + return; + + if (!Build.BuildSolution("plugins\\Plugins.sln", BuildFlags.Build64bit | BuildFlags.BuildVerbose)) + return; + + if (!Build.CopyWow64Files(BuildFlags.None)) + return; + + Build.BuildAppxPackage(); + + Build.ShowBuildStats(true); + } + else if (ProgramArgs.ContainsKey("-appxmakecert")) + { + if (!Build.InitializeBuildEnvironment(false)) + return; + + Build.ShowBuildEnvironment(true); + + Build.BuildAppxSignature(); + + Build.ShowBuildStats(true); + } else { Console.WriteLine("Invalid arguments.\n"); @@ -305,5 +328,18 @@ private static Dictionary ParseArgs(string[] args) return dict; } + + public static void PrintColorMessage(string Message, ConsoleColor Color, bool Newline = true, BuildFlags Flags = BuildFlags.BuildVerbose) + { + if ((Flags & BuildFlags.BuildVerbose) != BuildFlags.BuildVerbose) + return; + + Console.ForegroundColor = Color; + if (Newline) + Console.WriteLine(Message); + else + Console.Write(Message); + Console.ResetColor(); + } } } \ No newline at end of file diff --git a/tools/CustomBuildTool/Source Files/Zip.cs b/tools/CustomBuildTool/Source Files/Zip.cs index 129c79a707b6..08cc138439fe 100644 --- a/tools/CustomBuildTool/Source Files/Zip.cs +++ b/tools/CustomBuildTool/Source Files/Zip.cs @@ -31,12 +31,6 @@ private static string[] GetEntryNames(string[] names, string sourceFolder, bool public static void CreateCompressedFolder(string sourceDirectoryName, string destinationArchiveFileName) { - if (string.IsNullOrEmpty(sourceDirectoryName)) - throw new ArgumentNullException("sourceDirectoryName"); - - if (string.IsNullOrEmpty(destinationArchiveFileName)) - throw new ArgumentNullException("destinationArchiveFileName"); - string[] filesToAdd = Directory.GetFiles(sourceDirectoryName, "*", SearchOption.AllDirectories); string[] entryNames = GetEntryNames(filesToAdd, sourceDirectoryName, false); @@ -65,5 +59,30 @@ public static void CreateCompressedFolder(string sourceDirectoryName, string des } } } + + public static void CreateCompressedPdbFromFolder(string sourceDirectoryName, string destinationArchiveFileName) + { + string[] filesToAdd = Directory.GetFiles(sourceDirectoryName, "*", SearchOption.AllDirectories); + string[] entryNames = GetEntryNames(filesToAdd, sourceDirectoryName, false); + + using (FileStream zipFileStream = new FileStream(destinationArchiveFileName, FileMode.Create)) + using (ZipArchive archive = new ZipArchive(zipFileStream, ZipArchiveMode.Create)) + { + for (int i = 0; i < filesToAdd.Length; i++) + { + // Ignore junk files + if (!filesToAdd[i].EndsWith(".pdb", StringComparison.OrdinalIgnoreCase)) + continue; + + // Ignore junk directories + if (filesToAdd[i].Contains("bin\\Debug") || + filesToAdd[i].Contains("obj\\") || + filesToAdd[i].Contains("tests\\")) + continue; + + archive.CreateEntryFromFile(filesToAdd[i], entryNames[i], CompressionLevel.Optimal); + } + } + } } } \ No newline at end of file diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe b/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe index 28649ca0c27566b3a0dfc7e3bdcec903df5a4071..dcbe0cfce5d8a9b4b677332a982064ef728fe15c 100644 GIT binary patch delta 29963 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 /// Looks up a localized string similar to <?xml version='1.0' encoding='utf-8' standalone='yes'?> ///<Package - /// xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10" - /// xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10" - /// xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"> - /// <Identity - /// Name="ProcessHacker" - /// Version="PH_APPX_VERSION" - /// ProcessorArchitecture="x86" - /// Publisher="CN=ProcessHacker, O=ProcessHacker, C=AU" /> - /// <Properties> - /// <Displa [rest of string was truncated]";. + /// xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10" + /// xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10" + /// xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities" + /// xmlns:desktop="http://schemas.microsoft.com/appx/manifest/desktop/windows10"> + /// <Identity + /// Name="ProcessHacker" + /// Version="PH_APPX_VERSION" + /// ProcessorArchi [rest of string was truncated]";. /// internal static string AppxManifest { get { diff --git a/tools/CustomBuildTool/Properties/Resources.resx b/tools/CustomBuildTool/Properties/Resources.resx index 65d0c238f84a..083dd1a65c62 100644 --- a/tools/CustomBuildTool/Properties/Resources.resx +++ b/tools/CustomBuildTool/Properties/Resources.resx @@ -120,23 +120,24 @@ <?xml version='1.0' encoding='utf-8' standalone='yes'?> <Package - xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10" - xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10" - xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"> - <Identity - Name="ProcessHacker" - Version="PH_APPX_VERSION" - ProcessorArchitecture="x86" - Publisher="CN=ProcessHacker, O=ProcessHacker, C=AU" /> - <Properties> - <DisplayName>Process Hacker</DisplayName> - <PublisherDisplayName>Process Hacker</PublisherDisplayName> - <Description>ProcessHacker</Description> - <Logo>Assets\ProcessHacker-48.png</Logo> - </Properties> - <Resources> - <Resource Language="en-US" /> - </Resources> + xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10" + xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10" + xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities" + xmlns:desktop="http://schemas.microsoft.com/appx/manifest/desktop/windows10"> + <Identity + Name="ProcessHacker" + Version="PH_APPX_VERSION" + ProcessorArchitecture="PH_APPX_ARCH" + Publisher="CN=ProcessHacker, O=ProcessHacker, C=AU" /> + <Properties> + <DisplayName>Process Hacker</DisplayName> + <PublisherDisplayName>Process Hacker</PublisherDisplayName> + <Description>ProcessHacker</Description> + <Logo>Assets\ProcessHacker-44.png</Logo> + </Properties> + <Resources> + <Resource Language="en-US" /> + </Resources> <Dependencies> <TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.14316.0" MaxVersionTested="10.0.15063.0" /> </Dependencies> @@ -145,18 +146,18 @@ </Capabilities> <Applications> <Application Id="ProcessHacker" Executable="ProcessHacker.exe" EntryPoint="Windows.FullTrustApplication"> - <uap:VisualElements - BackgroundColor="transparent" - DisplayName="ProcessHacker" - Square150x150Logo="Assets\ProcessHacker-150.png" - Square44x44Logo="Assets\ProcessHacker-44.png" - Description="ProcessHacker"> - <uap:DefaultTile> - <uap:ShowNameOnTiles> - <uap:ShowOn Tile="square150x150Logo" /> - </uap:ShowNameOnTiles> - </uap:DefaultTile> - </uap:VisualElements> + <uap:VisualElements + BackgroundColor="transparent" + DisplayName="ProcessHacker" + Square150x150Logo="Assets\ProcessHacker-150.png" + Square44x44Logo="Assets\ProcessHacker-44.png" + Description="ProcessHacker"> + <uap:DefaultTile> + <uap:ShowNameOnTiles> + <uap:ShowOn Tile="square150x150Logo" /> + </uap:ShowNameOnTiles> + </uap:DefaultTile> + </uap:VisualElements> </Application> </Applications> </Package> diff --git a/tools/CustomBuildTool/Source Files/Build.cs b/tools/CustomBuildTool/Source Files/Build.cs index 779095ae0fc3..12ea6f115927 100644 --- a/tools/CustomBuildTool/Source Files/Build.cs +++ b/tools/CustomBuildTool/Source Files/Build.cs @@ -196,19 +196,20 @@ public static void CleanupBuildEnvironment() BuildOutputFolder + "\\processhacker-build-src.zip", BuildOutputFolder + "\\processhacker-build-sdk.zip", BuildOutputFolder + "\\processhacker-build-pdb.zip", - BuildOutputFolder + "\\processhacker-build-package.appx", BuildOutputFolder + "\\processhacker-build-checksums.txt", + BuildOutputFolder + "\\processhacker-build-package.appxbundle", BuildOutputFolder + "\\processhacker-" + BuildVersion + "-setup.exe", BuildOutputFolder + "\\processhacker-" + BuildVersion + "-bin.zip", BuildOutputFolder + "\\processhacker-" + BuildVersion + "-src.zip", BuildOutputFolder + "\\processhacker-" + BuildVersion + "-sdk.zip", BuildOutputFolder + "\\processhacker-" + BuildVersion + "-pdb.zip", - BuildOutputFolder + "\\processhacker-" + BuildVersion + "-package.appx", BuildOutputFolder + "\\processhacker-" + BuildVersion + "-checksums.txt" }; try { + Directory.Delete("build\\output", true); + for (int i = 0; i < cleanupFileArray.Length; i++) { if (File.Exists(cleanupFileArray[i])) @@ -490,6 +491,67 @@ public static bool CopyVersionHeader() return true; } + public static bool CopyRedistFiles(BuildFlags Flags) + { + string dbghelp32RedistDll = Environment.ExpandEnvironmentVariables("%ProgramFiles(x86)%\\Windows Kits\\10\\Debuggers\\x86\\dbghelp.dll"); + string dbghelp64RedistDll = Environment.ExpandEnvironmentVariables("%ProgramFiles(x86)%\\Windows Kits\\10\\Debuggers\\x64\\dbghelp.dll"); + string symsrv32RedistDll = Environment.ExpandEnvironmentVariables("%ProgramFiles(x86)%\\Windows Kits\\10\\Debuggers\\x86\\symsrv.dll"); + string symsrv64RedistDll = Environment.ExpandEnvironmentVariables("%ProgramFiles(x86)%\\Windows Kits\\10\\Debuggers\\x64\\symsrv.dll"); + + Program.PrintColorMessage("Copying redist files...", ConsoleColor.Cyan); + + try + { + if (Flags.HasFlag(BuildFlags.BuildDebug)) + { + if (Flags.HasFlag(BuildFlags.Build32bit)) + { + if (File.Exists(dbghelp32RedistDll)) + File.Copy(dbghelp32RedistDll, "bin\\Debug32\\dbghelp.dll", true); + + if (File.Exists(symsrv32RedistDll)) + File.Copy(symsrv32RedistDll, "bin\\Debug32\\symsrv.dll", true); + } + + if (Flags.HasFlag(BuildFlags.Build64bit)) + { + if (File.Exists(dbghelp64RedistDll)) + File.Copy(dbghelp64RedistDll, "bin\\Debug64\\dbghelp.dll", true); + + if (File.Exists(symsrv64RedistDll)) + File.Copy(symsrv64RedistDll, "bin\\Debug64\\symsrv.dll", true); + } + } + else + { + if (Flags.HasFlag(BuildFlags.Build32bit)) + { + if (File.Exists(dbghelp32RedistDll)) + File.Copy(dbghelp32RedistDll, "bin\\Release32\\dbghelp.dll", true); + + if (File.Exists(symsrv32RedistDll)) + File.Copy(symsrv32RedistDll, "bin\\Release32\\symsrv.dll", true); + } + + if (Flags.HasFlag(BuildFlags.Build64bit)) + { + if (File.Exists(dbghelp64RedistDll)) + File.Copy(dbghelp64RedistDll, "bin\\Release64\\dbghelp.dll", true); + + if (File.Exists(symsrv64RedistDll)) + File.Copy(symsrv64RedistDll, "bin\\Release64\\symsrv.dll", true); + } + } + } + catch (Exception ex) + { + Program.PrintColorMessage("[ERROR] " + ex, ConsoleColor.Red); + return false; + } + + return true; + } + public static bool FixupResourceHeader() { Program.PrintColorMessage("Building Plugin SDK resource header...", ConsoleColor.Cyan); @@ -1063,65 +1125,148 @@ public static bool BuildSolution(string Solution, BuildFlags Flags) } #region Appx Package - public static void BuildAppxPackage() + public static void BuildAppxPackage(BuildFlags Flags) { - Program.PrintColorMessage("Building processhacker-build-package.appx...", ConsoleColor.Cyan); + string error; + string signToolExePath = Environment.ExpandEnvironmentVariables("%ProgramFiles(x86)%\\Windows Kits\\10\\bin\\x64\\SignTool.exe"); + + Program.PrintColorMessage("Building processhacker-build-package.appxbundle...", ConsoleColor.Cyan); try { - StringBuilder sb = new StringBuilder(0x100); - int startIndex = "bin\\Release64\\".Length; - string[] filesToAdd; + if (!Directory.Exists("build\\output")) + Directory.CreateDirectory("build\\output"); - File.WriteAllText("build\\AppxManifest.xml", Properties.Resources.AppxManifest.Replace("PH_APPX_VERSION", BuildLongVersion)); + if (File.Exists(BuildOutputFolder + "\\processhacker-build-package.appxbundle")) + File.Delete(BuildOutputFolder + "\\processhacker-build-package.appxbundle"); - sb.AppendLine("[Files]"); - sb.AppendLine("\"build\\AppxManifest.xml\" \"AppxManifest.xml\""); - sb.AppendLine("\"ProcessHacker\\resources\\ProcessHacker.png\" \"Assets\\ProcessHacker-44.png\""); - sb.AppendLine("\"ProcessHacker\\resources\\ProcessHacker.png\" \"Assets\\ProcessHacker-48.png\""); - sb.AppendLine("\"ProcessHacker\\resources\\ProcessHacker.png\" \"Assets\\ProcessHacker-150.png\""); + Win32.ImageResizeFile(44, "ProcessHacker\\resources\\ProcessHacker.png", "build\\output\\ProcessHacker-44.png"); + Win32.ImageResizeFile(50, "ProcessHacker\\resources\\ProcessHacker.png", "build\\output\\ProcessHacker-50.png"); + Win32.ImageResizeFile(150, "ProcessHacker\\resources\\ProcessHacker.png", "build\\output\\ProcessHacker-150.png"); - filesToAdd = Directory.GetFiles("bin\\Release64", "*", SearchOption.AllDirectories); + if ((Flags & BuildFlags.Build32bit) == BuildFlags.Build32bit) + { + // create the package manifest + string appxManifestString = Properties.Resources.AppxManifest; + appxManifestString = appxManifestString.Replace("PH_APPX_ARCH", "x86"); + appxManifestString = appxManifestString.Replace("PH_APPX_VERSION", BuildLongVersion); + File.WriteAllText("build\\output\\AppxManifest32.xml", appxManifestString); + + // create the package mapping file + StringBuilder packageMap32 = new StringBuilder(0x100); + packageMap32.AppendLine("[Files]"); + packageMap32.AppendLine("\"build\\output\\AppxManifest32.xml\" \"AppxManifest.xml\""); + packageMap32.AppendLine("\"build\\output\\ProcessHacker-44.png\" \"Assets\\ProcessHacker-44.png\""); + packageMap32.AppendLine("\"build\\output\\ProcessHacker-50.png\" \"Assets\\ProcessHacker-50.png\""); + packageMap32.AppendLine("\"build\\output\\ProcessHacker-150.png\" \"Assets\\ProcessHacker-150.png\""); + + var filesToAdd = Directory.GetFiles("bin\\Release32", "*", SearchOption.AllDirectories); + for (int i = 0; i < filesToAdd.Length; i++) + { + string filePath = filesToAdd[i]; + + // Ignore junk files + if (filePath.EndsWith(".pdb", StringComparison.OrdinalIgnoreCase) || + filePath.EndsWith(".iobj", StringComparison.OrdinalIgnoreCase) || + filePath.EndsWith(".ipdb", StringComparison.OrdinalIgnoreCase) || + filePath.EndsWith(".exp", StringComparison.OrdinalIgnoreCase) || + filePath.EndsWith(".lib", StringComparison.OrdinalIgnoreCase)) + { + continue; + } + + packageMap32.AppendLine("\"" + filePath + "\" \"" + filePath.Substring("bin\\Release32\\".Length) + "\""); + } + File.WriteAllText("build\\output\\package32.map", packageMap32.ToString()); + + // create the package + error = Win32.ExecCommand( + MakeAppxExePath, + "pack /o /f build\\output\\package32.map /p " + BuildOutputFolder + "\\output\\processhacker-build-package-x32.appx" + ); + Program.PrintColorMessage(Environment.NewLine + error, ConsoleColor.Gray); + + // sign the package + error = Win32.ExecCommand( + signToolExePath, + "sign /v /fd SHA256 /a /f build\\processhacker-appx.pfx /td SHA256 " + BuildOutputFolder + "\\output\\processhacker-build-package-x32.appx" + ); + Program.PrintColorMessage(Environment.NewLine + error, ConsoleColor.Gray); + } - for (int i = 0; i < filesToAdd.Length; i++) + if ((Flags & BuildFlags.Build64bit) == BuildFlags.Build64bit) { - string filePath = filesToAdd[i]; - - // Ignore junk files - if (filePath.EndsWith(".pdb", StringComparison.OrdinalIgnoreCase) || - filePath.EndsWith(".iobj", StringComparison.OrdinalIgnoreCase) || - filePath.EndsWith(".ipdb", StringComparison.OrdinalIgnoreCase) || - filePath.EndsWith(".exp", StringComparison.OrdinalIgnoreCase) || - filePath.EndsWith(".lib", StringComparison.OrdinalIgnoreCase)) + // create the package manifest + string appxManifestString = Properties.Resources.AppxManifest; + appxManifestString = appxManifestString.Replace("PH_APPX_ARCH", "x64"); + appxManifestString = appxManifestString.Replace("PH_APPX_VERSION", BuildLongVersion); + File.WriteAllText("build\\output\\AppxManifest64.xml", appxManifestString); + + StringBuilder packageMap64 = new StringBuilder(0x100); + packageMap64.AppendLine("[Files]"); + packageMap64.AppendLine("\"build\\output\\AppxManifest64.xml\" \"AppxManifest.xml\""); + packageMap64.AppendLine("\"build\\output\\ProcessHacker-44.png\" \"Assets\\ProcessHacker-44.png\""); + packageMap64.AppendLine("\"build\\output\\ProcessHacker-50.png\" \"Assets\\ProcessHacker-50.png\""); + packageMap64.AppendLine("\"build\\output\\ProcessHacker-150.png\" \"Assets\\ProcessHacker-150.png\""); + + var filesToAdd = Directory.GetFiles("bin\\Release64", "*", SearchOption.AllDirectories); + for (int i = 0; i < filesToAdd.Length; i++) { - continue; + string filePath = filesToAdd[i]; + + // Ignore junk files + if (filePath.EndsWith(".pdb", StringComparison.OrdinalIgnoreCase) || + filePath.EndsWith(".iobj", StringComparison.OrdinalIgnoreCase) || + filePath.EndsWith(".ipdb", StringComparison.OrdinalIgnoreCase) || + filePath.EndsWith(".exp", StringComparison.OrdinalIgnoreCase) || + filePath.EndsWith(".lib", StringComparison.OrdinalIgnoreCase)) + { + continue; + } + + packageMap64.AppendLine("\"" + filePath + "\" \"" + filePath.Substring("bin\\Release64\\".Length) + "\""); } - - sb.AppendLine("\"" + filePath + "\" \"" + filePath.Substring(startIndex) + "\""); + File.WriteAllText("build\\output\\package64.map", packageMap64.ToString()); + + // create the package + error = Win32.ExecCommand( + MakeAppxExePath, + "pack /o /f build\\output\\package64.map /p " + BuildOutputFolder + "\\output\\processhacker-build-package-x64.appx" + ); + Program.PrintColorMessage(Environment.NewLine + error, ConsoleColor.Gray); + + // sign the package + error = Win32.ExecCommand( + signToolExePath, + "sign /v /fd SHA256 /a /f build\\processhacker-appx.pfx /td SHA256 " + BuildOutputFolder + "\\output\\processhacker-build-package-x64.appx" + ); + Program.PrintColorMessage(Environment.NewLine + error, ConsoleColor.Gray); } - File.WriteAllText("build\\package.map", sb.ToString()); - - string error = Win32.ExecCommand( - MakeAppxExePath, - "pack /o /f build\\package.map /p " + BuildOutputFolder + "\\processhacker-build-package.appx" - ); - - Program.PrintColorMessage(Environment.NewLine + error, ConsoleColor.Gray); - - if (File.Exists("build\\AppxManifest.xml")) - File.Delete("build\\AppxManifest.xml"); - if (File.Exists("build\\package.map")) - File.Delete("build\\package.map"); - - string signToolExePath = Environment.ExpandEnvironmentVariables("%ProgramFiles(x86)%\\Windows Kits\\10\\bin\\x64\\SignTool.exe"); - - error = Win32.ExecCommand( - signToolExePath, - "sign /v /fd SHA256 /a /f build\\processhacker-appx.pfx /td SHA256 " + BuildOutputFolder + "\\processhacker-build-package.appx" - ); + { + // create the appx bundle map + StringBuilder bundleMap = new StringBuilder(0x100); + bundleMap.AppendLine("[Files]"); + bundleMap.AppendLine("\"" + BuildOutputFolder + "\\output\\processhacker-build-package-x32.appx\" \"processhacker-build-package-x32.appx\""); + bundleMap.AppendLine("\"" + BuildOutputFolder + "\\output\\processhacker-build-package-x64.appx\" \"processhacker-build-package-x64.appx\""); + File.WriteAllText("build\\output\\bundle.map", bundleMap.ToString()); + + // create the appx bundle package + error = Win32.ExecCommand( + MakeAppxExePath, + "bundle /f build\\output\\bundle.map /p " + BuildOutputFolder + "\\processhacker-build-package.appxbundle" + ); + Program.PrintColorMessage(Environment.NewLine + error, ConsoleColor.Gray); + + // sign the appx bundle package + error = Win32.ExecCommand( + signToolExePath, + "sign /v /fd SHA256 /a /f build\\processhacker-appx.pfx /td SHA256 " + BuildOutputFolder + "\\processhacker-build-package.appxbundle" + ); + Program.PrintColorMessage(Environment.NewLine + error, ConsoleColor.Gray); + } - Program.PrintColorMessage(Environment.NewLine + error, ConsoleColor.Gray); + Directory.Delete("build\\output", true); } catch (Exception ex) { diff --git a/tools/CustomBuildTool/Source Files/NativeMethods.cs b/tools/CustomBuildTool/Source Files/NativeMethods.cs index f173c3cff2fa..865a24548d52 100644 --- a/tools/CustomBuildTool/Source Files/NativeMethods.cs +++ b/tools/CustomBuildTool/Source Files/NativeMethods.cs @@ -30,6 +30,21 @@ public static string ExecCommand(string FileName, string args) return output; } + public static void ImageResizeFile(int size, string FileName, string OutName) + { + using (var src = System.Drawing.Image.FromFile(FileName)) + using (var dst = new System.Drawing.Bitmap(size, size)) + using (var g = System.Drawing.Graphics.FromImage(dst)) + { + g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias; + g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic; + + g.DrawImage(src, 0, 0, dst.Width, dst.Height); + + dst.Save(OutName, System.Drawing.Imaging.ImageFormat.Png); + } + } + public const int STD_OUTPUT_HANDLE = -11; public const int STD_INPUT_HANDLE = -10; public const int STD_ERROR_HANDLE = -12; diff --git a/tools/CustomBuildTool/Source Files/Program.cs b/tools/CustomBuildTool/Source Files/Program.cs index 8245aef57288..b70f7ea3cc08 100644 --- a/tools/CustomBuildTool/Source Files/Program.cs +++ b/tools/CustomBuildTool/Source Files/Program.cs @@ -51,6 +51,11 @@ public static void Main(string[] args) if (!Build.CopyLibFiles(BuildFlags.Build32bit | BuildFlags.Build64bit | BuildFlags.BuildVerbose)) return; + Build.CopyRedistFiles( + BuildFlags.Build32bit | BuildFlags.Build64bit | + BuildFlags.BuildDebug | BuildFlags.BuildVerbose + ); + Build.ShowBuildStats(false); } else if (ProgramArgs.ContainsKey("-cleansdk")) @@ -154,6 +159,10 @@ public static void Main(string[] args) if (!Build.CopyWow64Files(BuildFlags.BuildDebug)) return; + Build.CopyRedistFiles( + BuildFlags.Build32bit | BuildFlags.Build64bit | + BuildFlags.BuildDebug | BuildFlags.BuildVerbose); + Build.ShowBuildStats(true); } else if (ProgramArgs.ContainsKey("-release")) @@ -192,6 +201,8 @@ public static void Main(string[] args) if (!Build.CopyWow64Files(BuildFlags.None)) return; + Build.CopyRedistFiles(BuildFlags.Build32bit | BuildFlags.Build64bit | BuildFlags.BuildVerbose); + if (!Build.BuildBinZip()) return; if (!Build.BuildSetupExe()) @@ -259,7 +270,7 @@ public static void Main(string[] args) Build.BuildSecureFiles(); Build.UpdateHeaderFileVersion(); - if (!Build.BuildSolution("ProcessHacker.sln", BuildFlags.Build64bit | BuildFlags.BuildVerbose)) + if (!Build.BuildSolution("ProcessHacker.sln", BuildFlags.Build32bit | BuildFlags.Build64bit | BuildFlags.BuildVerbose)) return; if (!Build.CopyTextFiles()) @@ -270,16 +281,16 @@ public static void Main(string[] args) return; if (!Build.FixupResourceHeader()) return; - if (!Build.CopyLibFiles(BuildFlags.Build64bit | BuildFlags.BuildVerbose)) + if (!Build.CopyLibFiles(BuildFlags.Build32bit | BuildFlags.Build64bit | BuildFlags.BuildVerbose)) return; - if (!Build.BuildSolution("plugins\\Plugins.sln", BuildFlags.Build64bit | BuildFlags.BuildVerbose)) + if (!Build.BuildSolution("plugins\\Plugins.sln", BuildFlags.Build32bit | BuildFlags.Build64bit | BuildFlags.BuildVerbose)) return; if (!Build.CopyWow64Files(BuildFlags.None)) return; - Build.BuildAppxPackage(); + Build.BuildAppxPackage(BuildFlags.Build32bit | BuildFlags.Build64bit | BuildFlags.BuildVerbose); Build.ShowBuildStats(true); } diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe b/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe index 6071333ab93cf8ba6e32052da998c7ef9a4dfe6d..f64000cd50f9ba6d558ea03818794a11b5969893 100644 GIT binary patch delta 23423 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 delta 20132 zcmb_^34ByVwtn4vyKk@Q^pbRE>!brDG}$14vKTOkfG942Y>IRh?RH z-Ky%A*1x-2Uvb@Z^{L+s$ekptzx|?%@F=~6*ayY+3TwYTf+R*F@kUctg|Lwdf4Z3n zv3oPYgFNdaM3@6C^26BTa7VE>F)l=J5a^&*=JmdHe3bFEwlMjOP0WpV5yE{>MYIL& zv`LR$%x$rgR1GN}XIts9wjmi?nd?~N*es*_SmTT=qbGT+bzzp(d#v%AEMv~G#{1Gn zci2-M)*ZLSyCU`)CrLdZIU*B14*iCiy+7%Qc;!yGJLAy`7|Ohn()bc|XosjmS1W$% z^fQ$%^Ncz6aPkNo%RFJzLoLg-q!u4_kxNGxbw^e=^Wx>BkiQ})a2%z9!I>I;`GWk7+M|hs`fY%HP8_W+T@kcw~(F(s?}~NdMJsx zXftED6J{={)d`(8z=knysYP~g3x?WO6Exi#9G086x>wovG_HEkP939HS~OrUI-law zE6p6gq;r_Ozso8ir^S~<$#QN=5wf|s5w%_7b*Nb0MFyHx>5g-itSxYw#rd5XpLkEyUL``kY~m7(CT4aZUIJAMI>#2r zWAApy>w(3~^UM)@3$g&fqOM~|{s|%s-lTjB*chXIR*cUpkNyflg;*i2W zE9#UQJ$@YQl~u(EVm5-nLluyXa4hp!eIYLfldXVA{CN1vyNExL;T^<(%`{}G%0X4l z0qa!N%g(A~E0me4u8&}aDPoNGLz8MwQJF-tRDQV&d8Fz~m2J8dWVuX~jj+ng(k|7* zf32LYJ~8w^7vz^ebuQ@Nv?Jem#g(6I$o-FPX_lA5Azq1g)p|@B55K!o-j=0i*;GFd zwbcEoX3A3`%4He;Jn>*4ZBI^vEFVlO`rn0VBYy->)ycA1cxf=BX4zDaAvLdjeo3-i z39zQuzAPKbvM7|cO@lZhm63>iBx6+bGKG>X&j4hm;J?g^Do;Q6J#aDSg)z(1P}Bh$ zu=4{ff6T}z#Mt5KmdwkC*_mZFWwVX|*6xra;0Vz2{i5s*UpXFNHS03sk7qbH?Tri% zhG8EAu>4mN|2)Iv5s}1W7)d)|T4m3wW2caO3a;|UjQ_v_@MQq2f_=p63e)^ri1Nz} zKc@)%DS+wUQ4$Kd_~8n;vLEEb-hSuxE>86#7Ut$MfLl*scy)OhEb?)HRp}?h!zF3n z08!3K^NvCfSK-L6;o6)olO|)1;mr|{_ro{+Aal-mf6Q*T9v?sxzC@RQry|`^F*h-g z4D6%FPk{WZrLV}1kE(&UIjh`~WqK8}B1IKi~@gt?{ToEBhBuVj#8_USy}n*ZcOo4Bwf@>BRg+PkX{G$wAA|Lvt;3l(7ll= znOkOs4qG+kESoyuLwYjl`A+4Y(b+@p%*y=>+mhC*kD||uWqO5W?v>S9T9#SM_Q41- zaUwvnAx*gf@=eN!$6v2-o3FyKY%QmyI@5PBCc{;x`#RXN-3R`i8gpisf5{Q9;w2>2 z#AbM8b%J~oJY~!8+S#@coNYC3$#M^oMD&}o)GTuo*&*E~(pH&5w;0$Qq@dCW$vv)@*+#Z6PUR@yH`-3rQJ^ zxdW?JBUL)a1?{i#%kGs~9Tl#!c7J|3wX@#b)4>0h&UzvDK*4j<5pSb);A7%icWNB- z?hxha04MW~q8!-_=8C(s_6S#pYQwicn|_Mq%fwvqLSs*;uAWDwYaDIiGr_qU`h@0E zybVbbohD?EL!1(DcnxlWeI^hRAO5lgR6QqU_4_GElQUtJCcWgnN02KMKW9&$ z3(aRZ&nz^f?P26ZRw$PncSq`ym!pDK6l7~2hN#`T{1W9QhC{B@WmPpILN8hScUt6A zrUsZ&GP_Y3<`zEVc1*?AJ0bg(0)xxby5%T9ju7QQlZ7I@x zDT=E|Dty3toGKYXU3MX9`GAy|$qp{ca|)Se5tmQEHGxwG#9p-s5{C`z1kZh$IL5-~ zceczU3rCu0W|87dEI|EGQ<#Z`EK-n(MG)g7QL8mY5xtzQAV^*?Ny;pK9{CvpF)buz zEEqAXAFNdlr3C7%pv`xdr>FI@498DJb1+*jI(VH> zQaStp@?cYZoBSsPb1u@US86@6e&qwmXfE3{M=P<-bjo_@vCqzW6|65gJ(-I(Ymq6D z#;5Qalr!L?#>Y`viy(5*IHhZR=9WpQ%G@b-6){i5w6&ldTS@8?WCct(Qfqvy%Q_O) zI^-8HRomrJ_9&1^S1)ocG|%%6o+&W*WNndbSouq!~uIN-LOB@ZV|6 zl_(i)Nm@<&KWWVJ|KGNF97%J%Hyh(Hp8&7br{SsyZV+_w0~QtBOa(*PaR%(Sh4g?f?}4p2fxAj~?e9Pz%FqizH)rTX(5IOu*?T1T zOBwS(J$;?VS7sHF0N^Lvl19s;PGf$lH%P+sk{m7H` z>Szg|L!_-Qx`y9&$u@dh(sIb}-yD7kxp*9+sjC|9Qa)F^&F-Z~mkUm9bEy)(X_UiJ zGB11~Tfinar|bE5)nI3sss{^`gXeT0`?W@^7cM7~UPvgU|v2IFwt@<2-T$Z^L*Yc?op5^m9r8MS1YwY#&lER$B3T0fLQi;LH~ zgX`gxXY{A>KNt4eVmS@OJjthTS;IN+UyYa@@>1B$%tjQi8_OZgsh3D8r1t zCL$99je!->aald}KkF#kgVP;JrxpI8iayEfP+Kc){^V+sXfl?jmQUJ0WBHW#!9rJ& z+c+(h?{HcqzvHx6=AJLjpVO$U=Co7};eApC91 zP%hg{p^IE$3SH%WrqE4pYBW~GE0ZsSFTtv0Q{{IgVl}dL zzYpQGK#t|KP|oBO-;Z!wEN|qrM6TsDD%&|NmCtgDet&leuIPbWhxg_ydK7=kr2WE56a zDCNe9RRfefV^LKv$PZQxR`QL5Rh7xxv4qiE4m;i&EPzX}0&%r8~4^BB6Ts%x_E=}Q*ED|-W2yu zsMjg`4>KC-iqzi2jEQxB?uHj*KwV6eQc@<3-|^Tx;!Nz0JA|nAG?yB^dUjI^jB!1u zD22vjJtydxuYs0YBiL({zY&?_a4LNuawKYuIlZcEz4MzNG5XhUPCknDn*P-IWoTF{ zPQ11j0y&Cu{1G{7;w;BoV8>Z062}W#uT`q(yC}Uft^y-*l%iLe8Gn<`=ntoTbI8|n zxHRqH3>U|-4@g^DnY5$4g3&V|$ONaX{27(hAK7wMYrj#Gfk=z3~mYW%~ zn*UZhgewq2y0_#f&_}XDFe}eZ6&m4=pl)5+w>%v}Zs!ov-bHaMgibyGb-L<@I#sO> z?_Bl2YrWMfyD%Q;Tb7RDzugUSY;d?+@RC9oV-p9&J6x~q6lD<6@WdL>-YLq;&QTWr z9}iMGx_m22Jk1wnAl3Njo>~~ zs)-GFh}{+PQM4}cr14_E>LgxK0ab3L4*D4<0#^s_#7+R1 z-(*h{vqBt)5b=J)7x{Fx25$J&~@HWp)fn(KGdFD?JUP9gF$lqLtT=U&{L*Prh;~{$r zmt);iy$+mAok1;u>887C)x4^3$kx9VxtsypZOtp7tqIvlPK<>d(pfwkV#^G?Un*)N zl`TyWe%3cY*Zh)k%fQmX{Sa48IgX83pR2?5k$^pM4Xkn+g0^O<7O+;b;Vx?UxH9=9llC6{)W+`q3e{c)QlRNdPA)v%v;eaJUm+bO}P3M z&Ae-IY6;Zku2#ZsJzU>itLdickx7ZSplf*>P?wkCdx_ih$V9h#!%W-^{-L2qvK!SQ zGxs3a)`a6L5i6!N>UY=Z8s7zI1j>_)o|4?d&30-fK2Zm`wH#03Wm%&qr(ZJUX zQWsA{ZMx3$7gP2Cv|;wo?9ziu;!|>VY7W{P8S5KkvCpAM90VZ72Pj5bL8^vp)Ze-c zpJII0SUc!uESX(f5K&Bs=kVz|cD|fB=fY-a#B+`Kz2Pa)jTj7ta`xJ&neL+jUE?y6MHJ>;$`h9^ey7|a@E{Ao*P3>FB zt<3e1eyoo)pR@if?t|OZ#^SJO@;#Lo7Ji^E<|hlt^?}&lfG)lb5b8k}`k=j-@Gq!L z7rR*V5X%?XT(Kf?O74O@pLo!_JEDtsF({}wvJ92Ik^eCCrQY12Pk3{3gSxn>l*$kL z3D?1_lbKV+oNvrSjlDR@C`s+yp>A> z@gxSqEnYB(BjAR9y^~6q7@(2|q68lvA{vzI@(2$U6XxdA03GpMlq?R4JDk+v>kFnJ zv%7$@y@MjcVpPFXXwA`lYTsd=2O5vrm)vJxMyQ&1c`RqU_6B_7P8WIF%1HkN_g`^{ zdT|Kjrw)?qST5lb9(8!NWRZB=u^_Kh)R!#CD-u`7sADUF3otfSF`CbNxIeB&57F}w zPze?MuT9Alhx9SQ(aaP)fxTSB!q{06TM!~vh<#5Re#QERAXX+SIA4KcvhG4j;yK&n z7!!O3raGa3`Mt!BBj)!Df0SGsz}Dg!zby|xBLnNnOcrLd)t0Rf+pa|wc(UPGi<)*(NjVW}p{vd-n&44Ht{K zN&AYaNh9#93+f9sMz+(L z2D;JWTyeY5%KhRSjo4&yC)?0GuxVmlmaR#w$A$d2rJp+jqEGB^z~26KA{h{uMb?oa zMA$8la4pNVPLl5md!=rBmk@pg z)Wvf5I-!fc#fKq#ihg$ByXEn*b!hp^h2J_9@dGj_Vv>tAUxf+t3)YG8tyimk^zp3= z882WgVtiTaqt}ajRfkj8-`3pD@vSvl4zMrdX^e9jFK0ZDajZ%{4UEY!tKMa@iseTb zH?!tz#xB5A1$*5AWPU9`*k&WVp7Cf2$>(?jPDQ+BqtI{G2}6uM8K*LiWPF}+agvjj zc5X4Ug~gHLe6EaIyw_cdLf?-Pe$Lq4Px60xN}c7xY5$v}T>Or)5+#(2^^8<;xoBYd zVV2)vc^l(l#wSo$xtL^6(sVdK)WsPPt3BPFx>yulhleIdt#O7iwR!j@P@xn1H`933c_&y5ry+7(3!6*y z>SeMixx`+v*jXslCHmHzw#m$DdYkNIW}=VD`ZGJ*V#8gO&v_i%lHz0!(FaT_{+PQ( zxWu}CX2z?z`uPJ)HaGtvcov*svY#AVgh%urWU@&p#Urj5Y_f})O+Jy>ih^eg$g}53 z#FiE8z&ir@ES5CsnxSND6T6GrQH-E%6tk!4XWAC)UcA?tE4B|K+cHsr9gJVxj6E26 zD&jMzU%ba`l~|hFqy$96NV2UGZMk1KgW_h3{i0ta_*H^=wJP>x()pbedk_2(-QxHM zrcsJL=MXMzTkuD=`^y}zqBMKH%mYS0$Vj!Ygl(GNY@x}7*kzwt7I0{8CVI2k(4up)Ja5M^WjtxLGYq4h#b~f$Gwa`Fr_s*1(r9NGjdq67 zXlEFWc7`1-nvxYv*W4yojW~{moXzEBgkSZ7$qPeXpN z2^O1;p6My3SnRTZAM7HFO$#;&{078gi6C}?Vv)sG!d5TZEOs|+_2OEKT?SikvGP=I z|1#%QF!mO=TgDsEHGRar7P}+t2Ybk3S0K>7;?EYl34!(%+bp&#w+Z{kXDs$ot{?0r zi{+z#j~8!QtQ?Eg@w_6U{pNzvPwZ#oDse|>rmLU019wPRTEthy30HqneipG+;tc0v z*8p(}vlZf}(m7&~c+O&4aG7hc@Z*MwJP(yFcbzC6u-HdnCy7Sdv%wZ}jTXbiR$}!2 zTjXDlt>RB?Tp{{6Zgve9Z;d6_WzOp`^@fWMi=BM2vua&#NO2$zYD}-LW&NV`;W420^M4Za0VjV8gsP(@A8zmYhFiVO?&@-&J(^7sr zoh9-nlF@M95P8^jmN?yFZJu_pvn{sVvjuFj#k^(fvE$8t$Bh>A*|t<%C=Mv2#p}$> zx8azyC%^y3hz~5+bz-|~jQHMS*NSIcW5rR6ZBX{O&K6F(L=a2G^UB+0MbP(viWn2Z z)sonT*QFw!4GXbS#JnpDe6#*2+y%|>xY=@cik$UYc3&~HBGS=)?5#t)4itkE@(E#<^UV8`b|~0<77EWecHWV zT%$hWZbrpl<~_>t7O_LDFWv@BIt#aPK|5ghvg}zDcXI4?agDM%cOT?S%Mha)a!{cj zhpH@6mz6mc3eKmj#T9-Nd|ci_Wv%*}2WKaBY_3yjLqI)%ByT{A{bGYUEihQw%{{kU z{Ly`qvH^J~DjQXI5=D4tmRd#w+JXexXcB|8D$B9=}o4P=G2L&yL)o;5( zIjHW9>LO26mfos-C~kG!seHrLA5otSjTTgmf^eq=wxPE^EqVswwg+AYM*VLC%S%X( zmmE+I!ZUdoNirnVgJM;&LoL_Z3v$$N#QM^p+Cy6%ZQ|~Vz&bHE3jK_-JJD_$%M!+J zmfT)&x>|!=w<ABfdjyaxtrAn z&d`9$W z`?bqZ&0n-D*m}L?b7lCDcC+|A*u|E-!&3Ds8;K*aS=mF;OKg{MJ9=Oa`^6A#x|i?? zH!jnFwCSK0Kg2D5h&_jBFYpW~Dqdqdq8`K>eyZBPv`MU0{_1SE%|tof#XNo@Mr+HX zTWznZMWqXrc}b}imYe>ZSf@je?l?YE8AE{}d{o1{@!Ptv@(`M^`l2zR*rz)g@B zDThn{Zd;^$m46hT7exK6xl>uB^efZsGqtaEOix8C)x|uNqlm5IaM>(%k+#7Tvu{OH zEA3O&r7yiYrK7tGAw!? z@CMg(`wH#P*oI8fKG*zWwRR*|+K<5V68krb%iC&StL-XYX5XNFTDIS|L3>WyZ(F2J zvK1;Dw2p$??JjjkvS6)!t@?QWBXD{NssQHs)Am9j?!>iI{4dydYi|D=_NT3($@BbT zuh-ryE!B4@E8Ts7Yk?a?k?nZk?O0fjsF%2@^JU3U{fN3HdE*zw`iEMH zYnHxNsf;C)`T(e|1cv;}^{MLe+|~LER%OQrUr-g>chLv+H$ph;Ye3AI;uip#_|z*cb>c!l^U@M`?T)G4kPcHr+JyTq-mS&jW4 z$Q}4*I*6M)GOQ7~a9YdqI*|wYK9(O4h49(H@fdZWXBQ-LVgHJ9>zn;x{>UxKt=}*Wqj*2NsJFz^>vfU^QbOaUtXr#BAVD z)|@8V+;vHO0Y-*%8K;X|A}2_4$mQOTS=Q9);xwhcHfMYy&2dfyr7IIqhKlkWq1SHpU^0QyJSB z*D~&4{E!j9@j?mPy@dN2MGna^#zw~T8Cx0G5GEblne1m2KF+|{$ap?uE8`l*?Tq^w zMK1d@uJMz+opC>-2(Xp0k@0-SR>n1q$?cr%XB0uoFhF!TP7wPYgOHwx&uDzc;xkTs z?3f@9I3^)=;ud?b<0L%aH;X^uYq$@^cjBKSUx_I_mE)CDl(ovAlugQe$|0qzIz?Tm zexk0j-EVu@_62?w*=V0>zux|seV_dUdsR|z&`;AB>A%-E>-pI272z=|p&!wUhixi0 zk2CTJ9|#aO2MO{u1C0H})JVF^*hLZFI&FN6AI z5m3c9A`##+>}pkU6&4s=CyOZX8rrwJ*k*o)~4HpapgCm0HDJzsg>M(VJx>8-Ou2DCtPpZAO$=cQ0 zo!XzY?b^Fq$W~`N*LI`rQJc$t*nXG(M_u4(`J_|9PJOJ{f-f(GGEO|l=>&0q8SzQt z`7%}5S|MUsGk^5$ktc=&%@0l7^+xJf2V>cd~88F_PS!(!x`*VBAtlmod z_=`2W@tb+Wj0fh8v=5szJ<(+3%Teuf<%vrBmgd)O?Zzcr)%J;te^%NrSaPFkD6Qk$ zr?q~iwx7B5a+@)?z1p}5OTbxIyNy?_8ljXK^V&;|Wmiv8ijBsri&Q0Q{CHKgJ$lW@ z;r4a+y7H7sMr`vKXC3ad@P%S@`Z(6`=g?{nD!UqUv*Mif1mB! z%eZxm&*-ytSVh-#$@tE0E`BpN9gogb9#A|m+T0I{FTksf0?-9r86HpTKeYxv9H`@ta+nyz-~RJD8bfODG9W`V~?qd z&&Q;#!sW09Ck4+_gXdw21;*I~OirPxK3|~iIOCT$jxz?n*}vv=y8|Aoj&B!zJ{4Kj zVCyphhbQWD`cfa*9S$w%Hy(Ji(y#cO4!h6igA%KQ;xqQXIXpVmj(8ptS+IE7-(yA#8j07y7sM#z?FfvYs~1E+hZtj zMf>)*{-AnZ4Yb_{KPA{U+W6f&J(8n!hw2NqZgUE>eOs{YVRklgqa#1qx*Co2IqWHk z+Q9*CbEBW~gKayMke~uXBBbCsN7sGfL^rg46KwsS99zGkD9l6+v^~SRZCuN4r(-5O zj|N-uZ#F4WyU#&wj@s$FEYiiGbNbNrtw(}wh#3F3bH;bPa6}7&ZSMry-ske$Mk7de zaRu9QxGZj@(?O+BYhT%SuJWN#^KQ2x$Qpni9Uf>q=rTJa(Dp@+um#(`hmAV(h}{9V zC|7rseS>Y3VzAoE+gH51LeZl(9kLOB|0?6L_Zy9$-k*T-&+h2w{z45*Mpqzgt8o_&V>y!#o2!7@DHluY5(ZR4~ml0zVDy? z6eYJkcyyCbiEet{qik|2m76ZlQ{L8<+D+#aD+}#P@2g&mDVtu4sXHCYz)h>->ZS_i z{7q+^p>Fak^ET;I)LUH2rJL@$NL^@ClDC9st9z8>rjKT;cWcVhO_$G8le+6`A@Dm* O@%I6nc9bZGmH!7ZG%YUx diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb b/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb index 36e68b0ff3c85f8f83f4682ae074f6078778e0ce..4e225c154ca5823753ffbbae3475884e2ccee083 100644 GIT binary patch delta 20967 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 eaiegfanBdbjy9tTTl6wZ&muURe|PJ5^Zx

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 AX8-^I diff --git a/tools/CustomSetupTool/CustomSetupTool/resource.rc b/tools/CustomSetupTool/CustomSetupTool/resource.rc index 3a349180c3a3..3ffc04f2b300 100644 --- a/tools/CustomSetupTool/CustomSetupTool/resource.rc +++ b/tools/CustomSetupTool/CustomSetupTool/resource.rc @@ -281,7 +281,7 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_AUS // RCDATA // -IDR_BIN_DATA RCDATA "..\\..\\..\\ClientBin\\processhacker-build-bin.zip" +IDR_BIN_DATA RCDATA "..\\..\\..\\build\\processhacker-build-bin.zip" IDR_LICENCE_DATA RCDATA "resources\\Licence.txt" From 53de62e53204b9a166a1b2e9a2a2054159739e17 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 7 May 2017 03:13:02 +1000 Subject: [PATCH 0057/2058] Updater: Fix 3.x build detection --- plugins/Updater/updater.c | 18 ++++++++++++++++-- tools/CustomSetupTool/CustomSetupTool/setup.c | 4 ++-- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/plugins/Updater/updater.c b/plugins/Updater/updater.c index de808e1da9bc..5ca195aa507a 100644 --- a/plugins/Updater/updater.c +++ b/plugins/Updater/updater.c @@ -121,11 +121,12 @@ BOOLEAN UpdaterInstalledUsingSetup( VOID ) { - static PH_STRINGREF keyName = PH_STRINGREF_INIT(L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Process_Hacker2_is1"); + static PH_STRINGREF keyName = PH_STRINGREF_INIT(L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\ProcessHacker"); + static PH_STRINGREF key2xName = PH_STRINGREF_INIT(L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Process_Hacker2_is1"); HANDLE keyHandle = NULL; - // Check uninstall entries for the 'Process_Hacker2_is1' registry key. + // Check uninstall entries for the 'ProcessHacker' registry key. if (NT_SUCCESS(PhOpenKey( &keyHandle, KEY_READ, @@ -138,6 +139,19 @@ BOOLEAN UpdaterInstalledUsingSetup( return TRUE; } + // Check uninstall entries for the 2.x branch 'Process_Hacker2_is1' registry key. + if (NT_SUCCESS(PhOpenKey( + &keyHandle, + KEY_READ, + PH_KEY_LOCAL_MACHINE, + &key2xName, + 0 + ))) + { + NtClose(keyHandle); + return TRUE; + } + return FALSE; } diff --git a/tools/CustomSetupTool/CustomSetupTool/setup.c b/tools/CustomSetupTool/CustomSetupTool/setup.c index 9309fa223e2f..fd9cbe189fc9 100644 --- a/tools/CustomSetupTool/CustomSetupTool/setup.c +++ b/tools/CustomSetupTool/CustomSetupTool/setup.c @@ -38,7 +38,7 @@ NTSTATUS SetupCreateUninstallKey( status = PhCreateKey( &keyHandle, - KEY_ALL_ACCESS, + KEY_ALL_ACCESS | KEY_WOW64_64KEY, PH_KEY_LOCAL_MACHINE, &UninstallKeyName, 0, @@ -106,7 +106,7 @@ NTSTATUS SetupDeleteUninstallKey( status = PhOpenKey( &keyHandle, - KEY_WRITE | DELETE, + KEY_WRITE | DELETE | KEY_WOW64_64KEY, PH_KEY_LOCAL_MACHINE, &UninstallKeyName, 0 From 4e2987d984efd299a67e54ed792ea4a96db6d646 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 7 May 2017 04:32:50 +1000 Subject: [PATCH 0058/2058] Plugins: Remove deprecated winhttp flags --- plugins/ExtraPlugins/cloud.c | 9 +++---- plugins/ExtraPlugins/setup/updater.c | 20 ++++++---------- plugins/NetworkTools/update.c | 27 +++++++-------------- plugins/OnlineChecks/main.c | 2 +- plugins/OnlineChecks/upload.c | 10 +++----- plugins/OnlineChecks/virustotal.c | 24 ++++++------------- plugins/Updater/updater.c | 35 ++++++++-------------------- 7 files changed, 40 insertions(+), 87 deletions(-) diff --git a/plugins/ExtraPlugins/cloud.c b/plugins/ExtraPlugins/cloud.c index 68dc3343b6ac..57509cc969c0 100644 --- a/plugins/ExtraPlugins/cloud.c +++ b/plugins/ExtraPlugins/cloud.c @@ -51,19 +51,16 @@ NTSTATUS QueryPluginsCallbackThread( HINTERNET httpSessionHandle = NULL; HINTERNET httpConnectionHandle = NULL; HINTERNET httpRequestHandle = NULL; - WINHTTP_CURRENT_USER_IE_PROXY_CONFIG proxyConfig = { 0 }; ULONG xmlStringBufferLength = 0; PSTR xmlStringBuffer = NULL; PVOID rootJsonObject; PWCT_CONTEXT context = Parameter; - WinHttpGetIEProxyConfigForCurrentUser(&proxyConfig); - if (!(httpSessionHandle = WinHttpOpen( L"ExtraPlugins_1.0", - proxyConfig.lpszProxy ? WINHTTP_ACCESS_TYPE_NAMED_PROXY : WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, - proxyConfig.lpszProxy, - proxyConfig.lpszProxyBypass, + WindowsVersion >= WINDOWS_8_1 ? WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY : WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, + WINHTTP_NO_PROXY_NAME, + WINHTTP_NO_PROXY_BYPASS, 0 ))) { diff --git a/plugins/ExtraPlugins/setup/updater.c b/plugins/ExtraPlugins/setup/updater.c index a17321e1cc1c..77662132c054 100644 --- a/plugins/ExtraPlugins/setup/updater.c +++ b/plugins/ExtraPlugins/setup/updater.c @@ -312,7 +312,6 @@ NTSTATUS UpdateDownloadThread( ULONG indexOfFileName = -1; GUID randomGuid; URL_COMPONENTS httpUrlComponents = { sizeof(URL_COMPONENTS) }; - WINHTTP_CURRENT_USER_IE_PROXY_CONFIG proxyConfig = { 0 }; LARGE_INTEGER timeNow; LARGE_INTEGER timeStart; ULONG64 timeTicks = 0; @@ -403,7 +402,7 @@ NTSTATUS UpdateDownloadThread( httpUrlComponents.dwUrlPathLength = (ULONG)-1; if (!WinHttpCrackUrl( - PhGetStringOrEmpty(context->FileDownloadUrl), + PhGetString(context->FileDownloadUrl), 0, 0, &httpUrlComponents @@ -417,19 +416,14 @@ NTSTATUS UpdateDownloadThread( // Create the Path string. downloadUrlPath = PhCreateStringEx(httpUrlComponents.lpszUrlPath, httpUrlComponents.dwUrlPathLength * sizeof(WCHAR)); - SendMessage(context->DialogHandle, TDM_UPDATE_ELEMENT_TEXT, TDE_MAIN_INSTRUCTION, (LPARAM)L"Connecting..."); - - // Query the current system proxy - WinHttpGetIEProxyConfigForCurrentUser(&proxyConfig); - // Open the HTTP session with the system proxy configuration if available if (!(httpSessionHandle = WinHttpOpen( - PhGetStringOrEmpty(userAgentString), - proxyConfig.lpszProxy != NULL ? WINHTTP_ACCESS_TYPE_NAMED_PROXY : WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, - proxyConfig.lpszProxy, - proxyConfig.lpszProxyBypass, + PhGetString(userAgentString), + WindowsVersion >= WINDOWS_8_1 ? WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY : WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, + WINHTTP_NO_PROXY_NAME, + WINHTTP_NO_PROXY_BYPASS, 0 ))) { @@ -450,7 +444,7 @@ NTSTATUS UpdateDownloadThread( if (!(httpConnectionHandle = WinHttpConnect( httpSessionHandle, - PhGetStringOrEmpty(downloadHostPath), + PhGetString(downloadHostPath), httpUrlComponents.nScheme == INTERNET_SCHEME_HTTP ? INTERNET_DEFAULT_HTTP_PORT : INTERNET_DEFAULT_HTTPS_PORT, 0 ))) @@ -461,7 +455,7 @@ NTSTATUS UpdateDownloadThread( if (!(httpRequestHandle = WinHttpOpenRequest( httpConnectionHandle, NULL, - PhGetStringOrEmpty(downloadUrlPath), + PhGetString(downloadUrlPath), NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, diff --git a/plugins/NetworkTools/update.c b/plugins/NetworkTools/update.c index 36a113ec6b45..988029df021f 100644 --- a/plugins/NetworkTools/update.c +++ b/plugins/NetworkTools/update.c @@ -154,17 +154,14 @@ PPH_STRING QueryFwLinkUrl( HINTERNET httpSessionHandle = NULL; HINTERNET httpConnectionHandle = NULL; HINTERNET httpRequestHandle = NULL; - WINHTTP_CURRENT_USER_IE_PROXY_CONFIG proxyConfig = { 0 }; PPH_STRING versionHeader = UpdateVersionString(L"ProcessHacker_Build: "); PPH_STRING windowsHeader = UpdateWindowsString(); - WinHttpGetIEProxyConfigForCurrentUser(&proxyConfig); - if (!(httpSessionHandle = WinHttpOpen( NULL, - proxyConfig.lpszProxy ? WINHTTP_ACCESS_TYPE_NAMED_PROXY : WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, - proxyConfig.lpszProxy, - proxyConfig.lpszProxyBypass, + WindowsVersion >= WINDOWS_8_1 ? WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY : WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, + WINHTTP_NO_PROXY_NAME, + WINHTTP_NO_PROXY_BYPASS, 0 ))) { @@ -320,7 +317,6 @@ NTSTATUS GeoIPUpdateThread( ULONG indexOfFileName = -1; GUID randomGuid; URL_COMPONENTS httpUrlComponents = { sizeof(URL_COMPONENTS) }; - WINHTTP_CURRENT_USER_IE_PROXY_CONFIG proxyConfig = { 0 }; LARGE_INTEGER timeNow; LARGE_INTEGER timeStart; ULONG64 timeTicks = 0; @@ -417,15 +413,11 @@ NTSTATUS GeoIPUpdateThread( if (PhIsNullOrEmptyString(downloadUrlPath)) goto CleanupExit; - // Query the current system proxy - WinHttpGetIEProxyConfigForCurrentUser(&proxyConfig); - - // Open the HTTP session with the system proxy configuration if available if (!(httpSessionHandle = WinHttpOpen( - PhGetStringOrEmpty(userAgentString), - proxyConfig.lpszProxy ? WINHTTP_ACCESS_TYPE_NAMED_PROXY : WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, - proxyConfig.lpszProxy, - proxyConfig.lpszProxyBypass, + PhGetString(userAgentString), + WindowsVersion >= WINDOWS_8_1 ? WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY : WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, + WINHTTP_NO_PROXY_NAME, + WINHTTP_NO_PROXY_BYPASS, 0 ))) { @@ -435,13 +427,12 @@ NTSTATUS GeoIPUpdateThread( if (WindowsVersion >= WINDOWS_8_1) { ULONG httpFlags = WINHTTP_DECOMPRESSION_FLAG_GZIP | WINHTTP_DECOMPRESSION_FLAG_DEFLATE; - WinHttpSetOption(httpSessionHandle, WINHTTP_OPTION_DECOMPRESSION, &httpFlags, sizeof(ULONG)); } if (!(httpConnectionHandle = WinHttpConnect( httpSessionHandle, - PhGetStringOrEmpty(downloadHostPath), + PhGetString(downloadHostPath), httpUrlComponents.nScheme == INTERNET_SCHEME_HTTP ? INTERNET_DEFAULT_HTTP_PORT : INTERNET_DEFAULT_HTTPS_PORT, 0 ))) @@ -452,7 +443,7 @@ NTSTATUS GeoIPUpdateThread( if (!(httpRequestHandle = WinHttpOpenRequest( httpConnectionHandle, NULL, - PhGetStringOrEmpty(downloadUrlPath), + PhGetString(downloadUrlPath), NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, diff --git a/plugins/OnlineChecks/main.c b/plugins/OnlineChecks/main.c index 9167e0a386db..5da0db55f840 100644 --- a/plugins/OnlineChecks/main.c +++ b/plugins/OnlineChecks/main.c @@ -49,7 +49,7 @@ VOID ProcessesUpdatedCallback( _In_opt_ PVOID Context ) { -#ifdef VIRUSTOTAL_API +#ifdef PH_BUILD_API static ULONG ProcessesUpdatedCount = 0; PLIST_ENTRY listEntry; diff --git a/plugins/OnlineChecks/upload.c b/plugins/OnlineChecks/upload.c index 3c8ff16e74c7..60d99ffd515a 100644 --- a/plugins/OnlineChecks/upload.c +++ b/plugins/OnlineChecks/upload.c @@ -962,7 +962,6 @@ NTSTATUS UploadCheckThreadStart( HANDLE fileHandle = NULL; PPH_STRING phVersion = NULL; PPH_STRING userAgent = NULL; - WINHTTP_CURRENT_USER_IE_PROXY_CONFIG proxyConfig = { 0 }; PUPLOAD_CONTEXT context = (PUPLOAD_CONTEXT)Parameter; //context->Extension = VirusTotalGetCachedResult(context->FileName); @@ -1014,13 +1013,11 @@ NTSTATUS UploadCheckThreadStart( phVersion = PhGetPhVersion(); userAgent = PhConcatStrings2(L"ProcessHacker_", phVersion->Buffer); - WinHttpGetIEProxyConfigForCurrentUser(&proxyConfig); - if (!(context->HttpHandle = WinHttpOpen( userAgent->Buffer, - proxyConfig.lpszProxy ? WINHTTP_ACCESS_TYPE_NAMED_PROXY : WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, - proxyConfig.lpszProxy, - proxyConfig.lpszProxyBypass, + WindowsVersion >= WINDOWS_8_1 ? WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY : WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, + WINHTTP_NO_PROXY_NAME, + WINHTTP_NO_PROXY_BYPASS, 0 ))) { @@ -1030,7 +1027,6 @@ NTSTATUS UploadCheckThreadStart( if (WindowsVersion >= WINDOWS_8_1) { ULONG gzipFlags = WINHTTP_DECOMPRESSION_FLAG_ALL; - WinHttpSetOption(context->HttpHandle, WINHTTP_OPTION_DECOMPRESSION, &gzipFlags, sizeof(ULONG)); } diff --git a/plugins/OnlineChecks/virustotal.c b/plugins/OnlineChecks/virustotal.c index 430a63d840ee..b9f08f1e694e 100644 --- a/plugins/OnlineChecks/virustotal.c +++ b/plugins/OnlineChecks/virustotal.c @@ -286,20 +286,15 @@ PSTR VirusTotalSendHttpRequest( PPH_STRING userAgent = NULL; PPH_STRING keyString = NULL; PPH_STRING urlString = NULL; - WINHTTP_CURRENT_USER_IE_PROXY_CONFIG proxyConfig = { 0 }; phVersion = PhGetPhVersion(); userAgent = PhConcatStrings2(L"ProcessHacker_", phVersion->Buffer); -#ifdef _DEBUG - WinHttpGetIEProxyConfigForCurrentUser(&proxyConfig); -#endif - if (!(httpSessionHandle = WinHttpOpen( userAgent->Buffer, - proxyConfig.lpszProxy ? WINHTTP_ACCESS_TYPE_NAMED_PROXY : WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, - proxyConfig.lpszProxy, - proxyConfig.lpszProxyBypass, + WINHTTP_ACCESS_TYPE_NO_PROXY, + WINHTTP_NO_PROXY_NAME, + WINHTTP_NO_PROXY_BYPASS, 0 ))) { @@ -332,7 +327,7 @@ PSTR VirusTotalSendHttpRequest( if (!(requestHandle = WinHttpOpenRequest( connectHandle, L"POST", - PhGetStringOrEmpty(urlString), + PhGetString(urlString), NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, @@ -432,20 +427,15 @@ PVIRUSTOTAL_FILE_REPORT_RESULT VirusTotalSendHttpFileReportRequest( PPH_STRING userAgent = NULL; PPH_STRING keyString = NULL; PPH_STRING urlString = NULL; - WINHTTP_CURRENT_USER_IE_PROXY_CONFIG proxyConfig = { 0 }; phVersion = PhGetPhVersion(); userAgent = PhConcatStrings2(L"ProcessHacker_", phVersion->Buffer); -#ifdef _DEBUG - WinHttpGetIEProxyConfigForCurrentUser(&proxyConfig); -#endif - if (!(httpSessionHandle = WinHttpOpen( userAgent->Buffer, - proxyConfig.lpszProxy ? WINHTTP_ACCESS_TYPE_NAMED_PROXY : WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, - proxyConfig.lpszProxy, - proxyConfig.lpszProxyBypass, + WINHTTP_ACCESS_TYPE_NO_PROXY, + WINHTTP_NO_PROXY_NAME, + WINHTTP_NO_PROXY_BYPASS, 0 ))) { diff --git a/plugins/Updater/updater.c b/plugins/Updater/updater.c index 5ca195aa507a..55c88a814a7f 100644 --- a/plugins/Updater/updater.c +++ b/plugins/Updater/updater.c @@ -319,7 +319,6 @@ BOOLEAN QueryUpdateData( HINTERNET httpSessionHandle = NULL; HINTERNET httpConnectionHandle = NULL; HINTERNET httpRequestHandle = NULL; - WINHTTP_CURRENT_USER_IE_PROXY_CONFIG proxyConfig = { 0 }; ULONG stringBufferLength = 0; PSTR stringBuffer = NULL; PVOID jsonObject = NULL; @@ -327,15 +326,11 @@ BOOLEAN QueryUpdateData( PPH_STRING versionHeader = UpdateVersionString(); PPH_STRING windowsHeader = UpdateWindowsString(); - // Query the current system proxy - WinHttpGetIEProxyConfigForCurrentUser(&proxyConfig); - - // Open the HTTP session with the system proxy configuration if available if (!(httpSessionHandle = WinHttpOpen( NULL, - proxyConfig.lpszProxy ? WINHTTP_ACCESS_TYPE_NAMED_PROXY : WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY, - proxyConfig.lpszProxy, - proxyConfig.lpszProxyBypass, + WindowsVersion >= WINDOWS_8_1 ? WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY : WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, + WINHTTP_NO_PROXY_NAME, + WINHTTP_NO_PROXY_BYPASS, 0 ))) { @@ -648,7 +643,6 @@ NTSTATUS UpdateDownloadThread( ULONG indexOfFileName = -1; GUID randomGuid; URL_COMPONENTS httpUrlComponents = { sizeof(URL_COMPONENTS) }; - WINHTTP_CURRENT_USER_IE_PROXY_CONFIG proxyConfig = { 0 }; LARGE_INTEGER timeNow; LARGE_INTEGER timeStart; ULONG64 timeTicks = 0; @@ -764,15 +758,12 @@ NTSTATUS UpdateDownloadThread( SendMessage(context->DialogHandle, TDM_UPDATE_ELEMENT_TEXT, TDE_MAIN_INSTRUCTION, (LPARAM)L"Connecting..."); - // Query the current system proxy - WinHttpGetIEProxyConfigForCurrentUser(&proxyConfig); - // Open the HTTP session with the system proxy configuration if available if (!(httpSessionHandle = WinHttpOpen( - PhGetStringOrEmpty(userAgentString), - proxyConfig.lpszProxy ? WINHTTP_ACCESS_TYPE_NAMED_PROXY : WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, - proxyConfig.lpszProxy, - proxyConfig.lpszProxyBypass, + PhGetString(userAgentString), + WindowsVersion >= WINDOWS_8_1 ? WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY : WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, + WINHTTP_NO_PROXY_NAME, + WINHTTP_NO_PROXY_BYPASS, 0 ))) { @@ -783,18 +774,12 @@ NTSTATUS UpdateDownloadThread( if (WindowsVersion >= WINDOWS_8_1) { ULONG httpFlags = WINHTTP_DECOMPRESSION_FLAG_GZIP | WINHTTP_DECOMPRESSION_FLAG_DEFLATE; - - WinHttpSetOption( - httpSessionHandle, - WINHTTP_OPTION_DECOMPRESSION, - &httpFlags, - sizeof(ULONG) - ); + WinHttpSetOption(httpSessionHandle, WINHTTP_OPTION_DECOMPRESSION, &httpFlags, sizeof(ULONG)); } if (!(httpConnectionHandle = WinHttpConnect( httpSessionHandle, - PhGetStringOrEmpty(downloadHostPath), + PhGetString(downloadHostPath), httpUrlComponents.nScheme == INTERNET_SCHEME_HTTP ? INTERNET_DEFAULT_HTTP_PORT : INTERNET_DEFAULT_HTTPS_PORT, 0 ))) @@ -806,7 +791,7 @@ NTSTATUS UpdateDownloadThread( if (!(httpRequestHandle = WinHttpOpenRequest( httpConnectionHandle, NULL, - PhGetStringOrEmpty(downloadUrlPath), + PhGetString(downloadUrlPath), NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, From e11b772b0b0a967e7b65e2c81001ef98aedf828c Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 7 May 2017 05:40:52 +1000 Subject: [PATCH 0059/2058] OnlineChecks: Fix typo --- plugins/OnlineChecks/db.c | 1 + plugins/OnlineChecks/db.h | 4 +- plugins/OnlineChecks/main.c | 2 - plugins/OnlineChecks/onlnchk.h | 13 ++---- plugins/OnlineChecks/upload.c | 20 ++++---- plugins/OnlineChecks/virustotal.c | 76 ++++++++++++++++++++++--------- 6 files changed, 73 insertions(+), 43 deletions(-) diff --git a/plugins/OnlineChecks/db.c b/plugins/OnlineChecks/db.c index 093578f518df..683b5264bc9e 100644 --- a/plugins/OnlineChecks/db.c +++ b/plugins/OnlineChecks/db.c @@ -24,6 +24,7 @@ PPH_HASHTABLE ProcessObjectDb; PH_QUEUED_LOCK ProcessObjectDbLock = PH_QUEUED_LOCK_INIT; +PH_STRINGREF ProcessObjectDbHash = PH_STRINGREF_INIT(L"386f3b6b3f6c35346c69346c6b343d69396b6b3468386b683d383d356b3e383e38356b343f69393b683d3b3a39386b3c6b3a3a3e696835696e686f6b38683e6e"); BOOLEAN NTAPI ProcessObjectDbEqualFunction( _In_ PVOID Entry1, diff --git a/plugins/OnlineChecks/db.h b/plugins/OnlineChecks/db.h index 194762118818..4a6568c3db54 100644 --- a/plugins/OnlineChecks/db.h +++ b/plugins/OnlineChecks/db.h @@ -2,7 +2,7 @@ * Process Hacker Online Checks - * database functions * - * Copyright (C) 2016 dmex + * Copyright (C) 2016-2017 dmex * * This file is part of Process Hacker. * @@ -23,6 +23,8 @@ #ifndef DB_H #define DB_H +extern PH_STRINGREF ProcessObjectDbHash; + typedef struct _PROCESS_DB_OBJECT { PH_STRINGREF FileName; diff --git a/plugins/OnlineChecks/main.c b/plugins/OnlineChecks/main.c index 5da0db55f840..35ef25384a98 100644 --- a/plugins/OnlineChecks/main.c +++ b/plugins/OnlineChecks/main.c @@ -49,7 +49,6 @@ VOID ProcessesUpdatedCallback( _In_opt_ PVOID Context ) { -#ifdef PH_BUILD_API static ULONG ProcessesUpdatedCount = 0; PLIST_ENTRY listEntry; @@ -132,7 +131,6 @@ VOID ProcessesUpdatedCallback( listEntry = listEntry->Flink; } -#endif } VOID NTAPI LoadCallback( diff --git a/plugins/OnlineChecks/onlnchk.h b/plugins/OnlineChecks/onlnchk.h index b53854ca4e17..130be7849571 100644 --- a/plugins/OnlineChecks/onlnchk.h +++ b/plugins/OnlineChecks/onlnchk.h @@ -41,13 +41,6 @@ #define SETTING_NAME_VIRUSTOTAL_SCAN_ENABLED (PLUGIN_NAME L".EnableVirusTotalScanning") #define SETTING_NAME_VIRUSTOTAL_HIGHLIGHT_DETECTIONS (PLUGIN_NAME L".VirusTotalHighlightDetection") -#ifdef PH_BUILD_API -#include "virustotal.h" -#else -#define VIRUSTOTAL_URLPATH L"" -#define VIRUSTOTAL_APIKEY L"" -#endif - #define UM_UPLOAD (WM_APP + 1) #define UM_EXISTS (WM_APP + 2) #define UM_LAUNCH (WM_APP + 3) @@ -134,8 +127,6 @@ typedef struct _UPLOAD_CONTEXT PPH_STRING FileSize; PPH_STRING ErrorString; - PPH_STRING KeyString; - PPH_STRING FileName; PPH_STRING BaseFileName; PPH_STRING WindowFileName; @@ -252,6 +243,10 @@ PVIRUSTOTAL_FILE_HASH_ENTRY VirusTotalGetCachedResult( _In_ PPH_STRING FileName ); +PPH_BYTES VirusTotalGetCachedDbHash( + VOID + ); + VOID InitializeVirusTotalProcessMonitor( VOID ); diff --git a/plugins/OnlineChecks/upload.c b/plugins/OnlineChecks/upload.c index 60d99ffd515a..803689827131 100644 --- a/plugins/OnlineChecks/upload.c +++ b/plugins/OnlineChecks/upload.c @@ -185,7 +185,6 @@ VOID UploadContextDeleteProcedure( } PhClearReference(&context->ErrorString); - PhClearReference(&context->KeyString); PhClearReference(&context->FileName); PhClearReference(&context->BaseFileName); PhClearReference(&context->WindowFileName); @@ -494,7 +493,7 @@ NTSTATUS UploadFileThreadStart( httpComponents.dwUrlPathLength = (ULONG)-1; if (!WinHttpCrackUrl( - PhGetStringOrEmpty(context->UploadUrl), + PhGetString(context->UploadUrl), 0, 0, &httpComponents @@ -523,7 +522,7 @@ NTSTATUS UploadFileThreadStart( if (!NT_SUCCESS(status = PhCreateFileWin32( &fileHandle, - PhGetStringOrEmpty(context->FileName), + PhGetString(context->FileName), FILE_GENERIC_READ, 0, FILE_SHARE_READ | FILE_SHARE_DELETE, @@ -549,7 +548,7 @@ NTSTATUS UploadFileThreadStart( if (!(requestHandle = WinHttpOpenRequest( connectHandle, L"POST", - PhGetStringOrEmpty(httpHostPath), + PhGetString(httpHostPath), NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, @@ -1046,8 +1045,6 @@ NTSTATUS UploadCheckThreadStart( subObjectName = PhConcatStrings2(L"/file/upload/?sha256=", hashString->Buffer); - //if (PhIsNullOrEmptyString(context->KeyString)) - // Create the default launch URL PhMoveReference(&context->LaunchCommand, PhFormatString( L"https://www.virustotal.com/file/%s/analysis/", PhGetString(hashString) @@ -1099,15 +1096,19 @@ NTSTATUS UploadCheckThreadStart( )); } - if (context->VtApiUpload && !PhIsNullOrEmptyString(context->KeyString)) + if (context->VtApiUpload) { + PPH_BYTES resource = VirusTotalGetCachedDbHash(); + PhMoveReference(&context->UploadUrl, PhFormatString( - L"%s%s?apikey=%s&resource=%s", + L"%s%s?apikey=%S&resource=%s", L"https://www.virustotal.com/", L"/vtapi/v2/file/scan", - PhGetString(context->KeyString), + resource->Buffer, PhGetString(hashString) )); + + PhClearReference(&resource); } if (!PhIsNullOrEmptyString(context->UploadUrl)) @@ -1323,7 +1324,6 @@ VOID UploadToOnlineService( context->Service = Service; context->FileName = FileName; context->BaseFileName = PhGetBaseName(context->FileName); - context->KeyString = PhCreateString(VIRUSTOTAL_APIKEY); if (dialogThread = PhCreateThread(0, ShowUpdateDialogThread, (PVOID)context)) { diff --git a/plugins/OnlineChecks/virustotal.c b/plugins/OnlineChecks/virustotal.c index b9f08f1e694e..642ce0ddd9f3 100644 --- a/plugins/OnlineChecks/virustotal.c +++ b/plugins/OnlineChecks/virustotal.c @@ -101,7 +101,9 @@ PVIRUSTOTAL_FILE_HASH_ENTRY VirusTotalAddCacheResult( return result; } -VOID VirusTotalRemoveCacheResult(_In_ PPROCESS_EXTENSION Extension) +VOID VirusTotalRemoveCacheResult( + _In_ PPROCESS_EXTENSION Extension + ) { PhAcquireQueuedLockExclusive(&ProcessListLock); @@ -177,6 +179,30 @@ PVIRUSTOTAL_FILE_HASH_ENTRY VirusTotalGetCachedResultFromHash( return NULL; } +PPH_BYTES VirusTotalGetCachedDbHash( + VOID + ) +{ + ULONG length; + PUCHAR buffer; + PPH_BYTES string; + + length = (ULONG)ProcessObjectDbHash.Length / sizeof(WCHAR) / 2; + + buffer = PhAllocate(length + 1); + memset(buffer, 0, length + 1); + + PhHexStringToBuffer(&ProcessObjectDbHash, buffer); + + string = PhCreateBytes(buffer); + + for (SIZE_T i = 0; i < string->Length; i++) + string->Buffer[i] = string->Buffer[i] ^ 0x0D06F00D; + + PhFree(buffer); + return string; +} + PPH_LIST VirusTotalJsonToResultList( _In_ PVOID JsonObject ) @@ -284,7 +310,6 @@ PSTR VirusTotalSendHttpRequest( PSTR subRequestBuffer = NULL; PPH_STRING phVersion = NULL; PPH_STRING userAgent = NULL; - PPH_STRING keyString = NULL; PPH_STRING urlString = NULL; phVersion = PhGetPhVersion(); @@ -292,7 +317,7 @@ PSTR VirusTotalSendHttpRequest( if (!(httpSessionHandle = WinHttpOpen( userAgent->Buffer, - WINHTTP_ACCESS_TYPE_NO_PROXY, + WindowsVersion >= WINDOWS_8_1 ? WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY : WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0 @@ -304,7 +329,6 @@ PSTR VirusTotalSendHttpRequest( if (WindowsVersion >= WINDOWS_8_1) { ULONG gzipFlags = WINHTTP_DECOMPRESSION_FLAG_GZIP | WINHTTP_DECOMPRESSION_FLAG_DEFLATE; - WinHttpSetOption(httpSessionHandle, WINHTTP_OPTION_DECOMPRESSION, &gzipFlags, sizeof(ULONG)); } @@ -318,12 +342,19 @@ PSTR VirusTotalSendHttpRequest( goto CleanupExit; } - keyString = PhCreateString(VIRUSTOTAL_APIKEY); + PPH_BYTES resourceString = VirusTotalGetCachedDbHash(); + urlString = PhFormatString( - L"/partners/sysinternals/file-reports?apikey=%s", - keyString->Buffer + L"%s%s%s%s%S", + L"/partners", + L"/sysinternals", + L"/file-reports", + L"?apikey=", + resourceString->Buffer ); + PhClearReference(&resourceString); + if (!(requestHandle = WinHttpOpenRequest( connectHandle, L"POST", @@ -334,12 +365,10 @@ PSTR VirusTotalSendHttpRequest( WINHTTP_FLAG_SECURE ))) { - PhClearReference(&keyString); PhClearReference(&urlString); goto CleanupExit; } - PhClearReference(&keyString); PhClearReference(&urlString); if (!WinHttpAddRequestHeaders(requestHandle, L"Content-Type: application/json", -1L, 0)) @@ -425,7 +454,6 @@ PVIRUSTOTAL_FILE_REPORT_RESULT VirusTotalSendHttpFileReportRequest( PSTR subRequestBuffer = NULL; PPH_STRING phVersion = NULL; PPH_STRING userAgent = NULL; - PPH_STRING keyString = NULL; PPH_STRING urlString = NULL; phVersion = PhGetPhVersion(); @@ -433,7 +461,7 @@ PVIRUSTOTAL_FILE_REPORT_RESULT VirusTotalSendHttpFileReportRequest( if (!(httpSessionHandle = WinHttpOpen( userAgent->Buffer, - WINHTTP_ACCESS_TYPE_NO_PROXY, + WindowsVersion >= WINDOWS_8_1 ? WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY : WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0 @@ -458,31 +486,35 @@ PVIRUSTOTAL_FILE_REPORT_RESULT VirusTotalSendHttpFileReportRequest( goto CleanupExit; } - keyString = PhCreateString(VIRUSTOTAL_APIKEY); + PPH_BYTES resourceString = VirusTotalGetCachedDbHash(); + urlString = PhFormatString( - L"/vtapi/v2/file/report?apikey=%s&resource=%s", - keyString->Buffer, - PhGetStringOrEmpty(FileHash) + L"%s%s%s%s%S%s%s", + L"/vtapi", + L"/v2", + L"/file", + L"/report", + L"?apikey=", + resourceString->Buffer, + L"&resource=", + PhGetString(FileHash) ); + PhClearReference(&resourceString); + if (!(requestHandle = WinHttpOpenRequest( connectHandle, L"POST", - PhGetStringOrEmpty(urlString), + PhGetString(urlString), NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, WINHTTP_FLAG_SECURE ))) { - PhClearReference(&keyString); - PhClearReference(&urlString); goto CleanupExit; } - PhClearReference(&keyString); - PhClearReference(&urlString); - if (!WinHttpAddRequestHeaders(requestHandle, L"Content-Type: application/json", -1L, 0)) goto CleanupExit; @@ -536,6 +568,8 @@ PVIRUSTOTAL_FILE_REPORT_RESULT VirusTotalSendHttpFileReportRequest( CleanupExit: + PhClearReference(&urlString); + if (requestHandle) WinHttpCloseHandle(requestHandle); From 0f11d181d4fe0b1ee50a1511778a61533d57a1d2 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 7 May 2017 05:42:19 +1000 Subject: [PATCH 0060/2058] BuildTools: Fix building sdk release --- tools/CustomBuildTool/Source Files/Build.cs | 426 +++++++++--------- tools/CustomBuildTool/Source Files/Program.cs | 22 +- tools/CustomBuildTool/Source Files/Zip.cs | 24 + .../bin/Release/CustomBuildTool.exe | Bin 155648 -> 155648 bytes .../bin/Release/CustomBuildTool.pdb | Bin 71168 -> 71168 bytes 5 files changed, 245 insertions(+), 227 deletions(-) diff --git a/tools/CustomBuildTool/Source Files/Build.cs b/tools/CustomBuildTool/Source Files/Build.cs index 3963a1f96c54..386702e3c8b0 100644 --- a/tools/CustomBuildTool/Source Files/Build.cs +++ b/tools/CustomBuildTool/Source Files/Build.cs @@ -220,9 +220,10 @@ public static void CleanupBuildEnvironment() } } - public static void ShowBuildEnvironment(bool ShowBuildInfo) + public static void ShowBuildEnvironment(string Platform, bool ShowBuildInfo) { - Program.PrintColorMessage("Setting up build environment...", ConsoleColor.Cyan); + Program.PrintColorMessage("Build: ", ConsoleColor.Cyan, false); + Program.PrintColorMessage(Platform, ConsoleColor.White, false); string currentGitTag = Win32.ExecCommand(GitExePath, "describe --abbrev=0 --tags --always"); string latestGitRevision = Win32.ExecCommand(GitExePath, "rev-list --count \"" + currentGitTag + ".." + BuildBranch + "\""); @@ -497,176 +498,48 @@ public static bool FixupResourceHeader() return true; } -#region Appx Package - public static void BuildAppxPackage() - { - Program.PrintColorMessage("Building processhacker-build-package.appx...", ConsoleColor.Cyan); - - try - { - StringBuilder sb = new StringBuilder(0x100); - int startIndex = "bin\\Release64\\".Length; - string[] filesToAdd; - - File.WriteAllText("build\\AppxManifest.xml", Properties.Resources.AppxManifest.Replace("PH_APPX_VERSION", BuildLongVersion)); - - sb.AppendLine("[Files]"); - sb.AppendLine("\"build\\AppxManifest.xml\" \"AppxManifest.xml\""); - sb.AppendLine("\"ProcessHacker\\resources\\ProcessHacker.png\" \"Assets\\ProcessHacker-44.png\""); - sb.AppendLine("\"ProcessHacker\\resources\\ProcessHacker.png\" \"Assets\\ProcessHacker-48.png\""); - sb.AppendLine("\"ProcessHacker\\resources\\ProcessHacker.png\" \"Assets\\ProcessHacker-150.png\""); - - filesToAdd = Directory.GetFiles("bin\\Release64", "*", SearchOption.AllDirectories); - - for (int i = 0; i < filesToAdd.Length; i++) - { - string filePath = filesToAdd[i]; - - // Ignore junk files - if (filePath.EndsWith(".pdb", StringComparison.OrdinalIgnoreCase) || - filePath.EndsWith(".iobj", StringComparison.OrdinalIgnoreCase) || - filePath.EndsWith(".ipdb", StringComparison.OrdinalIgnoreCase) || - filePath.EndsWith(".exp", StringComparison.OrdinalIgnoreCase) || - filePath.EndsWith(".lib", StringComparison.OrdinalIgnoreCase)) - { - continue; - } - - sb.AppendLine("\"" + filePath + "\" \"" + filePath.Substring(startIndex) + "\""); - } - - File.WriteAllText("build\\package.map", sb.ToString()); - - string error = Win32.ExecCommand( - MakeAppxExePath, - "pack /o /f build\\package.map /p " + BuildOutputFolder + "\\processhacker-build-package.appx" - ); - - if (File.Exists("build\\AppxManifest.xml")) - File.Delete("build\\AppxManifest.xml"); - if (File.Exists("build\\package.map")) - File.Delete("build\\package.map"); - - if (string.IsNullOrEmpty(error) || !error.EndsWith("Package creation succeeded.", StringComparison.OrdinalIgnoreCase)) - { - Program.PrintColorMessage("[ERROR] " + error, ConsoleColor.Red); - return; - } - - string signToolExePath = Environment.ExpandEnvironmentVariables("%ProgramFiles(x86)%\\Windows Kits\\10\\bin\\x64\\SignTool.exe"); - - error = Win32.ExecCommand( - signToolExePath, - "sign /v /fd SHA256 /a /f build\\appx.pfx /td SHA256 " + BuildOutputFolder + "\\processhacker-build-package.appx" - ); - - if (string.IsNullOrEmpty(error) || error.Contains("Successfully signed")) - { - Program.PrintColorMessage(Environment.NewLine + error, ConsoleColor.DarkGray); - return; - } - } - catch (Exception ex) - { - Program.PrintColorMessage("[ERROR] " + ex, ConsoleColor.Red); - } - } - - public static bool BuildAppxSignature() + public static bool UpdateHeaderFileVersion() { - Program.PrintColorMessage("Building Appx Signature...", ConsoleColor.Cyan); - - var makeCertExePath = Environment.ExpandEnvironmentVariables("%ProgramFiles(x86)%\\Windows Kits\\10\\bin\\x64\\MakeCert.exe"); - var pvk2PfxExePath = Environment.ExpandEnvironmentVariables("%ProgramFiles(x86)%\\Windows Kits\\10\\bin\\x64\\Pvk2Pfx.exe"); - try { - if (File.Exists("build\\processhacker-appx.pvk")) - File.Delete("build\\processhacker-appx.pvk"); - if (File.Exists("build\\processhacker-appx.cer")) - File.Delete("build\\processhacker-appx.cer"); - if (File.Exists("build\\processhacker-appx.pfx")) - File.Delete("build\\processhacker-appx.pfx"); - - string output = Win32.ExecCommand(makeCertExePath, - "/n " + - "\"CN=ProcessHacker, O=ProcessHacker, C=AU\" " + - "/r /h 0 " + - "/eku \"1.3.6.1.5.5.7.3.3,1.3.6.1.4.1.311.10.3.13\" " + - "/sv " + - "build\\processhacker-appx.pvk " + - "build\\processhacker-appx.cer " - ); - - if (string.IsNullOrEmpty(output) || !output.Equals("Succeeded", StringComparison.OrdinalIgnoreCase)) - { - Program.PrintColorMessage("[MakeCert] " + output, ConsoleColor.Red); - return false; - } - - output = Win32.ExecCommand(pvk2PfxExePath, - "/pvk build\\processhacker-appx.pvk " + - "/spc build\\processhacker-appx.cer " + - "/pfx build\\processhacker-appx.pfx " - ); + if (File.Exists("ProcessHacker\\include\\phapprev.h")) + File.Delete("ProcessHacker\\include\\phapprev.h"); - if (!string.IsNullOrEmpty(output)) - { - Program.PrintColorMessage("[Pvk2Pfx] " + output, ConsoleColor.Red); - return false; - } + File.WriteAllText("ProcessHacker\\include\\phapprev.h", +@"#ifndef PHAPPREV_H +#define PHAPPREV_H - output = Win32.ExecCommand(CertUtilExePath, - "-addStore TrustedPeople build\\processhacker-appx.cer" - ); +#define PHAPP_VERSION_REVISION " + BuildRevision + @" - if (string.IsNullOrEmpty(output) || !output.Contains("command completed successfully")) - { - Program.PrintColorMessage("[Certutil] " + output, ConsoleColor.Red); - return false; - } +#endif // PHAPPREV_H +"); } catch (Exception ex) { - Program.PrintColorMessage("[ERROR] " + ex, ConsoleColor.Red); + Program.PrintColorMessage("[phapprev] " + ex.ToString(), ConsoleColor.Yellow); return false; } return true; } - public static bool CleanupAppxSignature() + public static bool BuildPublicHeaderFiles() { + Program.PrintColorMessage("Building public SDK headers...", ConsoleColor.Cyan); + try { - X509Store store = new X509Store(StoreName.TrustedPeople, StoreLocation.LocalMachine); - store.Open(OpenFlags.ReadWrite); - - foreach (X509Certificate2 c in store.Certificates) - { - if (c.Subject.Equals("CN=ProcessHacker, O=ProcessHacker, C=AU", StringComparison.OrdinalIgnoreCase)) - { - Console.WriteLine("Removing: {0}", c.Subject); - store.Remove(c); - } - } - - if (File.Exists("build\\processhacker-appx.pvk")) - File.Delete("build\\processhacker-appx.pvk"); - if (File.Exists("build\\processhacker-appx.cer")) - File.Delete("build\\processhacker-appx.cer"); - if (File.Exists("build\\processhacker-appx.pfx")) - File.Delete("build\\processhacker-appx.pfx"); + HeaderGen gen = new HeaderGen(); + gen.Execute(); } catch (Exception ex) { - Program.PrintColorMessage("[ERROR] " + ex, ConsoleColor.Red); + Program.PrintColorMessage("[ERROR] " + ex.ToString(), ConsoleColor.Red); return false; } return true; } -#endregion public static bool BuildKphSignatureFile(bool DebugBuild) { @@ -830,10 +703,9 @@ public static bool BuildSdkZip() try { - if (File.Exists(BuildOutputFolder + "\\processhacker-build-sdk.zip")) - File.Delete(BuildOutputFolder + "\\processhacker-build-sdk.zip"); + File.Copy("ProcessHacker\\sdk\\readme.txt", "sdk\\readme.txt", true); - Zip.CreateCompressedFolder("sdk", BuildOutputFolder + "\\processhacker-build-sdk.zip"); + Zip.CreateCompressedSdkFromFolder("sdk\\", BuildOutputFolder + "\\processhacker-build-sdk.zip"); } catch (Exception ex) { @@ -889,27 +761,27 @@ public static bool BuildSrcZip() { if (File.Exists(BuildOutputFolder + "\\processhacker-build-src.zip")) File.Delete(BuildOutputFolder + "\\processhacker-build-src.zip"); + + string output = Win32.ExecCommand( + GitExePath, + "--git-dir=.git " + + "--work-tree=.\\ archive " + + "--format zip " + + "--output " + BuildOutputFolder + "\\processhacker-build-src.zip " + + BuildBranch + ); + + if (!string.IsNullOrEmpty(output)) + { + Program.PrintColorMessage("[ERROR] " + output, ConsoleColor.Red); + return false; + } } catch (Exception ex) { Program.PrintColorMessage("[ERROR] " + ex, ConsoleColor.Red); return false; } - - string output = Win32.ExecCommand( - GitExePath, - "--git-dir=.git " + - "--work-tree=.\\ archive " + - "--format zip " + - "--output " + BuildOutputFolder + "\\processhacker-build-src.zip " + - BuildBranch - ); - - if (!string.IsNullOrEmpty(output)) - { - Program.PrintColorMessage("[ERROR] " + output, ConsoleColor.Red); - return false; - } return true; } @@ -997,7 +869,6 @@ public static bool BuildUpdateSignature() return true; } - public static void WebServiceUpdateConfig() { string buildPostString; @@ -1135,103 +1006,216 @@ public static bool AppveyorUploadBuildFiles() return true; } - - public static bool UpdateHeaderFileVersion() + public static bool BuildSolution(string Solution, BuildFlags Flags) { - try + if ((Flags & BuildFlags.Build32bit) == BuildFlags.Build32bit) { - if (File.Exists("ProcessHacker\\include\\phapprev.h")) - File.Delete("ProcessHacker\\include\\phapprev.h"); - - File.WriteAllText("ProcessHacker\\include\\phapprev.h", -@"#ifndef PHAPPREV_H -#define PHAPPREV_H - -#define PHAPP_VERSION_REVISION " + BuildRevision + @" + Program.PrintColorMessage("Building " + Path.GetFileNameWithoutExtension(Solution) + " (", ConsoleColor.Cyan, false, Flags); + Program.PrintColorMessage("x32", ConsoleColor.Green, false, Flags); + Program.PrintColorMessage(")...", ConsoleColor.Cyan, true, Flags); -#endif // PHAPPREV_H -"); + string error32 = Win32.ExecCommand( + MSBuildExePath, + "/m /nologo /verbosity:quiet " + + "/p:Configuration=" + (Flags.HasFlag(BuildFlags.BuildDebug) ? "Debug" : "Release") + " " + + "/p:Platform=Win32" + (BuildNightly ? " /p:ExternalCompilerOptions=PH_BUILD_API" : string.Empty) + " " + Solution + ); + + if (!string.IsNullOrEmpty(error32)) + { + Program.PrintColorMessage("[ERROR] " + error32, ConsoleColor.Red, true, Flags); + return false; + } } - catch (Exception ex) + + if ((Flags & BuildFlags.Build64bit) == BuildFlags.Build64bit) { - Program.PrintColorMessage("[phapprev] " + ex.ToString(), ConsoleColor.Yellow); - return false; + Program.PrintColorMessage("Building " + Path.GetFileNameWithoutExtension(Solution) + " (", ConsoleColor.Cyan, false, Flags); + Program.PrintColorMessage("x64", ConsoleColor.Green, false, Flags); + Program.PrintColorMessage(")...", ConsoleColor.Cyan, true, Flags); + + string error64 = Win32.ExecCommand( + MSBuildExePath, + "/m /nologo /verbosity:quiet " + + "/p:Configuration=" + (Flags.HasFlag(BuildFlags.BuildDebug) ? "Debug" : "Release") + " " + + "/p:Platform=x64" + (BuildNightly ? " /p:ExternalCompilerOptions=PH_BUILD_API" : string.Empty) + " " + Solution + ); + + if (!string.IsNullOrEmpty(error64)) + { + Program.PrintColorMessage("[ERROR] " + error64, ConsoleColor.Red, true, Flags); + return false; + } } return true; } - public static bool BuildPublicHeaderFiles() +#region Appx Package + public static void BuildAppxPackage() { - Program.PrintColorMessage("Building public SDK headers...", ConsoleColor.Cyan); + Program.PrintColorMessage("Building processhacker-build-package.appx...", ConsoleColor.Cyan); try { - HeaderGen gen = new HeaderGen(); - gen.Execute(); + StringBuilder sb = new StringBuilder(0x100); + int startIndex = "bin\\Release64\\".Length; + string[] filesToAdd; + + File.WriteAllText("build\\AppxManifest.xml", Properties.Resources.AppxManifest.Replace("PH_APPX_VERSION", BuildLongVersion)); + + sb.AppendLine("[Files]"); + sb.AppendLine("\"build\\AppxManifest.xml\" \"AppxManifest.xml\""); + sb.AppendLine("\"ProcessHacker\\resources\\ProcessHacker.png\" \"Assets\\ProcessHacker-44.png\""); + sb.AppendLine("\"ProcessHacker\\resources\\ProcessHacker.png\" \"Assets\\ProcessHacker-48.png\""); + sb.AppendLine("\"ProcessHacker\\resources\\ProcessHacker.png\" \"Assets\\ProcessHacker-150.png\""); + + filesToAdd = Directory.GetFiles("bin\\Release64", "*", SearchOption.AllDirectories); + + for (int i = 0; i < filesToAdd.Length; i++) + { + string filePath = filesToAdd[i]; + + // Ignore junk files + if (filePath.EndsWith(".pdb", StringComparison.OrdinalIgnoreCase) || + filePath.EndsWith(".iobj", StringComparison.OrdinalIgnoreCase) || + filePath.EndsWith(".ipdb", StringComparison.OrdinalIgnoreCase) || + filePath.EndsWith(".exp", StringComparison.OrdinalIgnoreCase) || + filePath.EndsWith(".lib", StringComparison.OrdinalIgnoreCase)) + { + continue; + } + + sb.AppendLine("\"" + filePath + "\" \"" + filePath.Substring(startIndex) + "\""); + } + + File.WriteAllText("build\\package.map", sb.ToString()); + + string error = Win32.ExecCommand( + MakeAppxExePath, + "pack /o /f build\\package.map /p " + BuildOutputFolder + "\\processhacker-build-package.appx" + ); + + Program.PrintColorMessage(error, ConsoleColor.Gray); + + if (File.Exists("build\\AppxManifest.xml")) + File.Delete("build\\AppxManifest.xml"); + if (File.Exists("build\\package.map")) + File.Delete("build\\package.map"); + + string signToolExePath = Environment.ExpandEnvironmentVariables("%ProgramFiles(x86)%\\Windows Kits\\10\\bin\\x64\\SignTool.exe"); + + error = Win32.ExecCommand( + signToolExePath, + "sign /v /fd SHA256 /a /f build\\appx.pfx /td SHA256 " + BuildOutputFolder + "\\processhacker-build-package.appx" + ); + + if (!string.IsNullOrEmpty(error) && !error.Contains("Successfully signed")) + { + Program.PrintColorMessage(Environment.NewLine + error, ConsoleColor.DarkGray); + return; + } } catch (Exception ex) { - Program.PrintColorMessage("[ERROR] " + ex.ToString(), ConsoleColor.Red); - return false; + Program.PrintColorMessage("[ERROR] " + ex, ConsoleColor.Red); } - - return true; } - - public static bool BuildSolution(string Solution, BuildFlags Flags) + public static bool BuildAppxSignature() { - if ((Flags & BuildFlags.Build32bit) == BuildFlags.Build32bit) + Program.PrintColorMessage("Building Appx Signature...", ConsoleColor.Cyan); + + var makeCertExePath = Environment.ExpandEnvironmentVariables("%ProgramFiles(x86)%\\Windows Kits\\10\\bin\\x64\\MakeCert.exe"); + var pvk2PfxExePath = Environment.ExpandEnvironmentVariables("%ProgramFiles(x86)%\\Windows Kits\\10\\bin\\x64\\Pvk2Pfx.exe"); + + try { - Program.PrintColorMessage("Building " + Path.GetFileNameWithoutExtension(Solution) + " (", ConsoleColor.Cyan, false, Flags); - Program.PrintColorMessage("x32", ConsoleColor.Green, false, Flags); - Program.PrintColorMessage(")...", ConsoleColor.Cyan, true, Flags); + if (File.Exists("build\\processhacker-appx.pvk")) + File.Delete("build\\processhacker-appx.pvk"); + if (File.Exists("build\\processhacker-appx.cer")) + File.Delete("build\\processhacker-appx.cer"); + if (File.Exists("build\\processhacker-appx.pfx")) + File.Delete("build\\processhacker-appx.pfx"); - string error32 = Win32.ExecCommand( - MSBuildExePath, - "/m /nologo /verbosity:quiet /p:Configuration=" + (Flags.HasFlag(BuildFlags.BuildDebug) ? "Debug" : "Release") + " /p:Platform=Win32 " + Solution + string output = Win32.ExecCommand(makeCertExePath, + "/n " + + "\"CN=ProcessHacker, O=ProcessHacker, C=AU\" " + + "/r /h 0 " + + "/eku \"1.3.6.1.5.5.7.3.3,1.3.6.1.4.1.311.10.3.13\" " + + "/sv " + + "build\\processhacker-appx.pvk " + + "build\\processhacker-appx.cer " ); - if (!string.IsNullOrEmpty(error32)) + if (!string.IsNullOrEmpty(output) && !output.Equals("Succeeded", StringComparison.OrdinalIgnoreCase)) { - Program.PrintColorMessage("[ERROR] " + error32, ConsoleColor.Red, true, Flags); + Program.PrintColorMessage("[MakeCert] " + output, ConsoleColor.Red); return false; } - } - if ((Flags & BuildFlags.Build64bit) == BuildFlags.Build64bit) - { - Program.PrintColorMessage("Building " + Path.GetFileNameWithoutExtension(Solution) + " (", ConsoleColor.Cyan, false, Flags); - Program.PrintColorMessage("x64", ConsoleColor.Green, false, Flags); - Program.PrintColorMessage(")...", ConsoleColor.Cyan, true, Flags); + output = Win32.ExecCommand(pvk2PfxExePath, + "/pvk build\\processhacker-appx.pvk " + + "/spc build\\processhacker-appx.cer " + + "/pfx build\\processhacker-appx.pfx " + ); - string error64 = Win32.ExecCommand( - MSBuildExePath, - "/m /nologo /verbosity:quiet /p:Configuration=" + (Flags.HasFlag(BuildFlags.BuildDebug) ? "Debug" : "Release") + " /p:Platform=x64 /p:ExternalCompilerOptions=PH_BUILD_API " + Solution + if (!string.IsNullOrEmpty(output)) + { + Program.PrintColorMessage("[Pvk2Pfx] " + output, ConsoleColor.Red); + return false; + } + + output = Win32.ExecCommand(CertUtilExePath, + "-addStore TrustedPeople build\\processhacker-appx.cer" ); - if (!string.IsNullOrEmpty(error64)) + if (!string.IsNullOrEmpty(output) && !output.Contains("command completed successfully")) { - Program.PrintColorMessage("[ERROR] " + error64, ConsoleColor.Red, true, Flags); + Program.PrintColorMessage("[Certutil] " + output, ConsoleColor.Red); return false; } } + catch (Exception ex) + { + Program.PrintColorMessage("[ERROR] " + ex, ConsoleColor.Red); + return false; + } return true; } - - } + public static bool CleanupAppxSignature() + { + try + { + X509Store store = new X509Store(StoreName.TrustedPeople, StoreLocation.LocalMachine); + store.Open(OpenFlags.ReadWrite); + + foreach (X509Certificate2 c in store.Certificates) + { + if (c.Subject.Equals("CN=ProcessHacker, O=ProcessHacker, C=AU", StringComparison.OrdinalIgnoreCase)) + { + Console.WriteLine("Removing: {0}", c.Subject); + store.Remove(c); + } + } + if (File.Exists("build\\processhacker-appx.pvk")) + File.Delete("build\\processhacker-appx.pvk"); + if (File.Exists("build\\processhacker-appx.cer")) + File.Delete("build\\processhacker-appx.cer"); + if (File.Exists("build\\processhacker-appx.pfx")) + File.Delete("build\\processhacker-appx.pfx"); + } + catch (Exception ex) + { + Program.PrintColorMessage("[ERROR] " + ex, ConsoleColor.Red); + return false; + } - [Flags] - public enum BuildFlags - { - None, - Build32bit = 0x1, - Build64bit = 0x2, - BuildDebug = 0x4, - BuildVerbose = 0x8 + return true; + } +#endregion } } diff --git a/tools/CustomBuildTool/Source Files/Program.cs b/tools/CustomBuildTool/Source Files/Program.cs index 52e7258d2990..b08dbfb0c40f 100644 --- a/tools/CustomBuildTool/Source Files/Program.cs +++ b/tools/CustomBuildTool/Source Files/Program.cs @@ -76,7 +76,7 @@ public static void Main(string[] args) if (!Build.InitializeBuildEnvironment(false)) return; - Build.ShowBuildEnvironment(false); + Build.ShowBuildEnvironment("bin", false); Build.BuildSecureFiles(); Build.UpdateHeaderFileVersion(); @@ -118,7 +118,7 @@ public static void Main(string[] args) if (!Build.InitializeBuildEnvironment(true)) return; - Build.ShowBuildEnvironment(true); + Build.ShowBuildEnvironment("debug", true); Build.BuildSecureFiles(); if (!Build.BuildSolution("ProcessHacker.sln", @@ -158,7 +158,7 @@ public static void Main(string[] args) if (!Build.InitializeBuildEnvironment(true)) return; - Build.ShowBuildEnvironment(true); + Build.ShowBuildEnvironment("release", true); Build.BuildSecureFiles(); Build.UpdateHeaderFileVersion(); @@ -204,7 +204,7 @@ public static void Main(string[] args) if (!Build.InitializeBuildEnvironment(true)) return; - Build.ShowBuildEnvironment(false); + Build.ShowBuildEnvironment("nightly", false); Build.BuildSecureFiles(); Build.UpdateHeaderFileVersion(); @@ -252,7 +252,7 @@ public static void Main(string[] args) if (!Build.InitializeBuildEnvironment(true)) return; - Build.ShowBuildEnvironment(true); + Build.ShowBuildEnvironment("appx", true); Build.BuildSecureFiles(); Build.UpdateHeaderFileVersion(); @@ -285,7 +285,7 @@ public static void Main(string[] args) if (!Build.InitializeBuildEnvironment(false)) return; - Build.ShowBuildEnvironment(true); + Build.ShowBuildEnvironment("appxcert", true); Build.BuildAppxSignature(); @@ -342,4 +342,14 @@ public static void PrintColorMessage(string Message, ConsoleColor Color, bool Ne Console.ResetColor(); } } + + [Flags] + public enum BuildFlags + { + None, + Build32bit = 0x1, + Build64bit = 0x2, + BuildDebug = 0x4, + BuildVerbose = 0x8 + } } \ No newline at end of file diff --git a/tools/CustomBuildTool/Source Files/Zip.cs b/tools/CustomBuildTool/Source Files/Zip.cs index 08cc138439fe..cddb9f950b88 100644 --- a/tools/CustomBuildTool/Source Files/Zip.cs +++ b/tools/CustomBuildTool/Source Files/Zip.cs @@ -34,6 +34,9 @@ public static void CreateCompressedFolder(string sourceDirectoryName, string des string[] filesToAdd = Directory.GetFiles(sourceDirectoryName, "*", SearchOption.AllDirectories); string[] entryNames = GetEntryNames(filesToAdd, sourceDirectoryName, false); + if (File.Exists(destinationArchiveFileName)) + File.Delete(destinationArchiveFileName); + using (FileStream zipFileStream = new FileStream(destinationArchiveFileName, FileMode.Create)) using (ZipArchive archive = new ZipArchive(zipFileStream, ZipArchiveMode.Create)) { @@ -60,11 +63,32 @@ public static void CreateCompressedFolder(string sourceDirectoryName, string des } } + public static void CreateCompressedSdkFromFolder(string sourceDirectoryName, string destinationArchiveFileName) + { + string[] filesToAdd = Directory.GetFiles(sourceDirectoryName, "*", SearchOption.AllDirectories); + string[] entryNames = GetEntryNames(filesToAdd, sourceDirectoryName, false); + + if (File.Exists(destinationArchiveFileName)) + File.Delete(destinationArchiveFileName); + + using (FileStream zipFileStream = new FileStream(destinationArchiveFileName, FileMode.Create)) + using (ZipArchive archive = new ZipArchive(zipFileStream, ZipArchiveMode.Create)) + { + for (int i = 0; i < filesToAdd.Length; i++) + { + archive.CreateEntryFromFile(filesToAdd[i], entryNames[i], CompressionLevel.Optimal); + } + } + } + public static void CreateCompressedPdbFromFolder(string sourceDirectoryName, string destinationArchiveFileName) { string[] filesToAdd = Directory.GetFiles(sourceDirectoryName, "*", SearchOption.AllDirectories); string[] entryNames = GetEntryNames(filesToAdd, sourceDirectoryName, false); + if (File.Exists(destinationArchiveFileName)) + File.Delete(destinationArchiveFileName); + using (FileStream zipFileStream = new FileStream(destinationArchiveFileName, FileMode.Create)) using (ZipArchive archive = new ZipArchive(zipFileStream, ZipArchiveMode.Create)) { diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe b/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe index dcbe0cfce5d8a9b4b677332a982064ef728fe15c..c7103426b509e6da18aced66ecf171e3f0db4c6c 100644 GIT binary patch delta 18057 zcmb_^378bs)%K~X?&@`VdYS3Hdzxj2W|%=n_5oyAL=X^=T_AuApAgW2JD7-s=^hs% zMpP_B(O^K4xW)xHTo7D{8kay&Q3!!x5;2-!f_`cg{`cJK4U#W^zUTkjXWo0>bIv{Y z+*7x1-Rc?4?sQ~#I&QvB`(uq~?N1Ww-p|)QFr_~GIng-ck3#!bD^fZQHmT%>V&rk6 zxY4ku&X}%rQTOjLu2R}+o^t-FW;)ha> zv>}@1?&_#mY5dk2u4{)jYlEtr%hpmy||VI z4^3SFeIc}3*HNrv@2?8pqK_N=rvS5ex0LDeVL@Yh#LMy?`S@|;*ABb!sl77uJ=lt4 z+z`TAib_oPMgDaoRY^i6DzDgrKH_j8sOb_eahWEP9=Kct$YnO-U&Xn@L%sfeAg}oF z^gyK(NMxer|2FwnF%1ss8cd|#Wy)CD&Khw=iCW60`aY<|M}XYLOMAha0Xcpj^W#OH zY4SmF9l&(xcNcCwu^&7?rj*U#-!L1%?n41BjckxUdU^ole59x`rp!OeLf99v zJ!0c)hPPQ3rzv-Zx0J+InB*=c28ZD^5C$_=(kU*7MsFEp{4Uw2^BTy7yh^8kD2eoO zXWHP{zpB2>LS@**96ao=!p84>;mj%S>d9>sp;~cXB$rLSSImQ4VpIDc;g!VeQRWMe zji-Bvf0Xp@8$GSJxD`A}zc2QbsHH5YFCET-L(5>UhBOpto1eGqvKZoFx$4zU zb88KXXQ0yM@+hPotTnw4#*D-Mip-DW|H4Bq@%)q?gh!z_3R0FRPIoNiQrjbWTb)x# zS?2!N60MY_R@&zl<{+e{K+Po2O8(Q7eh*b{O77fM%1_B%^-ta}RvG&OsdJrtfse5{ z!PR3)KEiT~(wE9xSSngvqM=}ENE!Vrsxq^oD9kumYm=46rm*33y*;mg=X5;@tpjcd zUR1Vp8{dyH<^uq_$!9aa2Vj@{P_#_^3CxkMM&?z<`xR#gT^*4_;aN6}nIj!Bsw#UX zZUbqv@M@T$VNU!kPd5Sb`$@y_Df!zB*S93fOfaz?kh|@lfM^E7J(3Hw7Ww7_$wyPD zTYrk+S){~zSm?ui;2oWezQI13zafI$VC!6h&COgr4lKB@*^PV1zUiSjtQ2M)H@u+=*E2}a#S7uW&c<1xu)3yR3%wbd$K3`5;$$(_buLW2@N zsLp48o+Y38EoanGH@+YC+i-&Pi62!PSBGb~h9UX%a6r~!jERJex574WVdkx-)d)u} z$(#!xr!JnyC@mu(*XZIa9uf1j$b*&KBl9L_%^7YO^Pk+zI=`CF7F#MOQ`oV2^DNBV zI2q}y4z1yhGkNC5$!j{lhqTogmqt4`?Zo&cH;;LbJGT)LCZii4N1RVXyOyXe`=js}!DTE?Iev97o?TgF0k*!1)T ztg45q74HYmmhpgq#b;@m00GT~tegm_uM*?nl~)ZiE{liVlVCV_C=#&3X512QR6NF8 z@f~V=S7S|LpsNYiL-Bwv!1pD3_uYp6HlOVd@j3*vO7eKS2UHx*8Ot5<`*c5$k! z(UhE&3G~qEb`-E2OH2#R4mG`ms*0Yqv_wr$#yH|Uh%zP)-Q18Q#o(j<=zF_e-Ty4>* z4r^Y=Wsy%bdAI6f7?gbLXLwtfm?JDdSRyyo7x#pB3$nQZFYeC!GY)1>cQ9b>hy9=I zKI9QpVfZj!ol-TojN6cfj%YsRhy4DfxX=``3 zH#K=^^F(sb}_9$5! zVhor}$SHQ@MVIK_P)uIRGWi7!lqt*!WJy}8?=EqcGHZ2lkkwo&w|Sna?`juadh&Ij z$+L-x0U+kVbQS{+#B-?-+ZqRmK~beh81rS{a`(NeTi`EEac(TLoMIqd|PG%Tjl^<-5P8yb0N6xEf=E^ zUm=c}bzMk|?9F>P>(lc9y1k_tjjd%qu>P0-bLC13hhx^isT?2LrWl)jJu^FSJM$-) zg82zOr&niNUdRyoAkrr;DqO#!b@ zrr;KfO`%L=O~E79n?kvGz!bb0vBQ*nVxKAa#Yd(P5GPEbLfHH9pjDM3ZVEwBYYHK8 zjwyu2g{BY@|78kMvCI@=;zm=5i-$}hA>L#mTR~)W?dZxJlIoE7n{30v*`J4th@@hxW(J1P$mwWf=8S%g>sS68|C!8 zB5Vpi(a{wAqL(QI#28bk5Eq+5rC4SPL2x0Tt}+&MN@wl>U5Q=EqKX|XVmGp= zq5O*dgq>GLSyxq+SAHuagoJw_j}{h5*+xV!*+#`k*~Y|0vW<(yvQ3CK*(Sv;vPHGG z4#ZZ4e4XMMQ{@tGnu1##GKDg6!W2BhK1fckT*OVmE6z3rpBP~ZelgP&0%D0NREVog zp;D|jg`jxI6hh)92pJ3?7W+(9M0{)tQSq%Q#DxDGIci+gm_kA{nnF@sz{1LytX(tY zm3U;JjK*MyNr>3*`K@UPHV53hzSc{y`8Zn_09_iNX`SwFKBKIl*AKW?w@cL(QDad}#KD)}XFaKJFxJ#GDN~KN zYa&SJY6&EYZ3K&ThN9B4PX?UDFtVwdH20>>>iu=Ujn0SmZHV zKKOFBqFc*NaE4pRIJav&2I8bUd6qh$_G}NAhtFojvr9_Oiwf!K!QJYkv#RJD~-fMP&iAq6M~<`q(aVo+Wo1t`wRE2IDgzP>Vp4mMVH8=0X%50%#A zLC7C9eI+hJ7B9Y*HU?48#e4+ysf&fu3T*XCZ5ox=Ytne0>Y+3`>b0it;DWC=Snw@l z-<-pYf`dJn#u|{>!4bFF_y0)SgWwFrP7%YYUt##j4Cu8%>0rFu>!{Mv*xtJa55B{_M-06P2>P0u~B-DWAI=br(Q|5EZrT>dLXyMkqn3CHb zYW)q`vS7f{E$HARZ1@SLjR*VsE;)Lr!cnI?%!N~2Or^PWo>t7I&&9=De(}G^#W=rj zv~RJVbxkF;KyLLtB%ds6!`!UZ?0l_K#&dlg!~VHm`Et$QP)zZM_n0z2(dv<6XI%2O zsd$Xlr^Ka(wO?<29WTtMji!F#i>i4&$YYs2CTQl_U_VlD>Xkj!V6AD?<(D7w_w;Qu z5US)1^iu?D{Qw=RvusJ1;p9`>z4cDx@qQhZpz&_ME+cC&h$cI?+$JN7J(yUm<#CX@ z(YpAPWYd`qQdi7D6x_ea*cqDMatKXO`lqKF!}|{l-;43G7sID^gvMFv;?HK4e%8P1 zpih%n;%!9Ja4YV^Pp65?#KOxiX+;^R4v+lK!=Rfyk;Y#ozuuxw=S?0p9JV>&#|>*^ zPwQ5&DaN42m{Ma*Zyb`@5Y}m)hjE>IM!1~n`0+^Zy608sbW<7Q5{c(~SPn`&OQI(A zyWCfzZ%SfcsY#ZtDA(!Siu+?aO)6uY<$j_{r*;qHALCd0bsFkqyt>ko(R6yag2`S# zKg$^!YpJe^(np>H0S}FEpA|v}TnL@M3VsS~tPE6m=vi0R=b`)DS)WcH zB{=Bg<&1hIf*@CqTK3wJL;!4I~Tbu z{3`k`kr(1QLRsN!YYV5}Halff6he#bMu2^6Fx zzUcMR0Y9?{RZ%;BowSdbRZ%rq1%(xpbs+@@;)iX|_+G`srB1SkT+Dhh^LptAarSHk z+l)gMRXl^kR3mmKX8XfMmLWP7FlmD{UXLNzwU=b?ASkoml8wNC%=$`pUdUvFCF`EE z4UueiF3Kp$=H+Y`N%p4G>~}Fww~@Y=G&60M^Bo~)KO6@Zo?%mr=X5UpNZOKB>^WMp z3R-J?a84}qMkVW}5}u~0-QUAEMwl6-p>`KSH-V<~)kNm-!eMSQuL+&Wp4BrR%8iLet=$vtxgfJvh~6&f~B&Bp3%ue7T(E z8Ls2D4)j;c4&W^74#PEMK!z*4+kXPs+x0cd@>YBc^}%0boU{e$PEzeb%90ECGo=!^ zQ>g|XP^}$kG|jh>nOx)Wc*?RWe(aV=qazxWTkNAX(GdCc8_rojI0v$bP+~EklQ$Oe=buuA|GhuIhHYL80P|_b~-D1EjnINVC(H}`Z&kdL?5u1Q@?X%7<$5^<1TlPH2W#E z-R`AHlC7tz@@B+Q8{teT zy)piAiSd`-&q~<#@KHMsRJou7B7ZMoVlyyHXXk}odQXFDs;8e-*7uYS1RAKlO`pLTvn%&k_t};iFz2#`8Op$K$mbz|5 z-bLHzj`x)!`(?%Z3QpDXv)g)+cbX#aT{#2~DDPIuc)%j#0gH^s!$a5n?6&fNMI#Sb zWIUj}>19wJFkR?(*cEWdEkN4l;8GNsBM~mKeS!gtw#D%TY`O7wTbJ55Dn;W7S1G$c z(y=5=-_yeI)h_nqt6gM#wTlc_yM*z@hRqy*x0SDU(Uq@uk@3|ovU$-iCCR+#sdLoQ z!=tzytL)dHUpIO($8NTG!FJ?W6H=?A-8nWU;01eUlpKGR-QjD-iRAs9G3@h#9nP`W zVCzmF=h(Zjb*ImB>?_#LqOWtz>i2@F=bOp=9=0Cj%(2hVuLlKk>;x*)K(X`X{8!o4 zpck}r&iIMHna-xV9QzVM&!*lvb}`D%W#J$ND<@Q2RK}dp-5A4|DXT`y^XS%X}9&2GH@Gt!HwwV<25O z-t_DSHkeWqO!kF+0>0(_X^vHTe@?^bpk!;Q(l*mEjGp3S5H8cDSZl**2eS<5aV)lB zv^!^uHT+JpDGuGWRQnV*-7g zqi-lbb6iNrbLNP z1HIzlLMXHtZ_-MJ@TbZ+8g;@$P@#D~#y54warlxjkEZ4T-c!|_z6p;zg|5Y8PNn5e z{-+8F2WvJ-{YEJdvau#4Bd>!-rA0F4t#;NwY*(Q%lB4|%^Ac)Gr3FBZW>}OI5=kg< z`P$3)n*ie+>3(NG#Za#qb4M?oYX&p15g}FjH01SawAktOT5@StAwh*W9hKGsH8M43 zI%jGW!g&tZ7_O{>13QgrgMgWg{4p_zJ;&J6r5EV|7vsMMt5R&DZ@`WjUhh` z$04dqSivg+pKl^SCpOeBVcupK`%4@mag@Xf5~oX?3#_DtQeH}3GU%{elGVT{tp)0| zLE>D6<#vf1fGN5k*oC$OyVL7Zzei$3?Go-y9e{Wj2M(b7X-jZ&Y+i_!%3$FV8& zm>lIXI-ZzKbJd-=zbB~g#4`(Mq54|#}mM(`e^V<$m;?rfgO@f?FOO?^oaUd|%lkefCiIc#D$Ru8y+w zrd_H9FfBxQ#%JH5D%ju-ILxIP^~f1 zSCQ^G-#ftVl0Je z!Fr1gfJ&z~zl(bmxg{*IQP<}^!_qbyr;G9|9C z{D`*d7@(`t#rSMoD8uu6Nap*HoL_^sKwj@`bd%+ndM&on3F-}rX4Mn0>{2gFT&^rtzDd3U`H}M1fpxJDE$nmHGDLeX{zuCwjq5r}yU$Yz{7I5= zmctADQwC(YGB|m{vRs*5`5j!JjpOEoW}~uPxgx1qr)%%)xLC?mtch4f~;3?ce%hf-Hw$pO$*78x-V@PY9^@wt> zYpS(ftBYl3SyyXn)nUtOZKrnFvQTZZM3mLq@UXCc4c9BIYt?w=weaZ$je@0mr_}+} zX|wiG`90SAwXNk3T3^YP_fhA2)(%>A@(b%Or8~ZF-lYrz-cO3940sTG!!fnO$rarn zi|WVJs$f+HO*~koe~!WMl{rH9(|2hn?L+m=%FwDQdRJ&>0v{=F)+eZ4%a`bH<_7z@ z?@jfHc3z@g-$z;HIc*<#l-uQUdtX^h&wFmwk7@V1?n1AdLd~=oYvK{zj_-F~17_(h z;5D>Y&)8`Vy{|jyW}qEAA9k)u9h6RorPD{` zu&MM1^5FMG$Dpy}dpb@ut{eoW6i%+Q!fB?W}%odr2FfO@0B0SP#oMgb>E!wiY@Xbv=s=z3r)-R2xdKfwT_FhFD3 zLf{2utAVr2?gw68_Oi6T4*4f#NAYFLLH!uypOt9}%MRsbdaA6Gat|GGc2efiC(f?Q z%NhDr*)Zins&Ea1YKUtToDP)DgS^N!PuT|7tEK*GDc=M6R@XgJei`zMu9u~J6!J0G zQ7LQcJPNoqmHT#rJjmTi%EKUE;vOdDd63t-=RwY30FdY0S4+b^>T}5Ss48<;51?oc zjj@x)^S)a975%||we}k+8^C)s#+M}?m8e-*la)Bc#`0W=?GiUj+$He{V@6l(?9@Tx z5Q%e5bg;f%;%14vBp#8dIAt%1LnO|X*e-Fi#9b1zZuZ&}UMzX_7cc zVpifNi9018mPj7%kdoLWagM~S#7z=+N<1vF$;_yNWAQT%KNILl+eCWWHW{rQUxRvWLvc^9qX+Selq2+a`Uh1i zDdjAsk1|r(tURtftsGH4Q97x!)gP)Ksp~CUE$>(|pW$zTnymAzH&`FDK4n$(fZkCb zuP@eb(kpQki{d7V^WVwRI?Ee4?)@sjINZnhfkcO&<bdGv^%ix5x=DRZ-JzbX&D5^bHfoP!vp=8(EZr?L zEH_ymwK%MASufXD881#9kaQf2Qs!9No{ArZ#L^O6{7FLgm1kp_^!)>@02W*l7F*o!NGWk_IEn0en(R@MY&4*j^5GA z6r1Hc8e|D5tY2gaDc3{3-m+FXZZ+`pq_PrEqbZo!w)dtz>$i+wJa^f)pDeOljLTcR z+QjBX+pcT*4le|Qj9=Uu-L~n9-&#H8L+NrHnHN(tek+mM_FUU6pEAT)x+=PD&Vyr= zZ4>WU>s0zPKX)dz!f6rBBti3OF62wmcBf@@1%4>;Z>^4;)tGQcrEzM@EG1^_xi-3O z#=W0djfWoEqEs6b9`3Bt1Y`5V<2|IM@E6cm;QQ=eL>-Lwhf~`^Hy>AxPR4!Pv~}b4 zRN18%zZIj-M=s>LxG)8>$#J&1e=)?BaW%uvwoCAP+P$}nG6gdUz5pxOt z`vLUJsRjN@`DG~0CA0t|E#^M}sm%LaA>*25QygZ$EAaOrMf;^>tlwVl_vLN#5LIxU zw%xn^MaBC{X71=eFL`mqQ_poC?Hk)|kFo5zjY{0`KR>kht3I16;jw%2KmJ*&&8GRi zXmy+BL1Rs+9*@ULs^Y=7xf*1Taq9VKhRv#f7JJW!8>;BErWF5tPq|HpkAGpM|5C-j z)IZCT;+~cM3dKLkN{T0db*CtZOaAuhRsznor!>Wb*5gj8W;d{f=)(~#DLiixUiI1> z2~HHF+5MSWXe~D6R%WyN=i3t)(~f){q_OC0Uv5jOD%yG;-wseccAFI@B<-?U{g?Zf z`&S~ABc&?7_LaW&c0Hv)x>hE(8l(D`Gpv+Tk7I6%e`UmGsq|;t6~8-!_FA-+zU*o= zezz@W;Fb;eepT86WXt)uY-+(9;nVdwNiT>{^t}zf4t80*uDhLrmGM zQ9K;kpMg&Rzq^&be2wgO9{FL_!&gj+hXYdT1 zkg0%~r{C>~o1Pog zq?y{8zHnjR4cy7abIooEak@K=?$}=^W#l8PB z3-l{Ea=((oxKeU{86|-FpB~dw(#_-ZD(u)^oMSoY!-cqhx4Srq-<@;M)q)#~6IVz# z%Zvjn4~3jiFct0;ETmz5CX3a~yOIZ1iebQ;H+c`Be z%HRIFul+5)aS#lS{_NL&EUb1b2FfL4x1}&1%zW=BtQMQ%Ul7DC+sj{<@Q<|H{R@04 z#9yQM$K+PX7&U^mD|K?|maGqzi!#QA(y}l95N^?~Cj6tohjumAKdfrJzBLOes>W8i z0IWPgw;fwSfV=_xrrliOM&PARUB19y>{`BLIKjZrNDDtCEh+uk9@ z(QdYWx2lI#-J$8eIDS%6&BX$lY0P~&kl}P3?EJ8b^;~XB`K;74xW{|C9lHlB0|{kREWi_M8>c!NS(IVX;d zeFZB6I>f=cM%XaEXH(U%*B9rYVPD*V5cY(BxEH%A`Rf>lbD!bpNeTZziDN7&#pSUZ z;uU}26uUq{{(cPO0SOQ6aUKNA*hQQYmo4FOqV^tN_A|`EcF!~Y*o?2Y+o>y!U<1{^sW;$hSS_QN!vJpBtXN%~yN& UJ?+`2e6w2J*YNZ%Rryl+Kg1pD%K!iX delta 17645 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 Wcb@jVBmHBsJh=DMzTWcp(*FZr_?giF diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb b/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb index 93863aa4f8b31961925b03a96ed5e13fa7f51171..89c01e4031cdb2ac1332bc6d3c6bb6f584ba701e 100644 GIT binary patch delta 17240 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 delta 16757 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 NF8FOrs$>N_{vWS=aAyDj From 31187326a8311066344adb8b9c4e5da8105ec711 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 7 May 2017 09:53:53 +1000 Subject: [PATCH 0061/2058] BuildTools: Add script for creating appx package certificates --- .gitignore | 3 +++ build/build_appx_makecert.cmd | 7 +++++ tools/CustomBuildTool/Source Files/Build.cs | 20 +++++++-------- .../Source Files/NativeMethods.cs | 6 +++++ tools/CustomBuildTool/Source Files/Program.cs | 24 +++++++++++++++++- .../bin/Release/CustomBuildTool.exe | Bin 155648 -> 156160 bytes .../bin/Release/CustomBuildTool.pdb | Bin 71168 -> 71168 bytes 7 files changed, 48 insertions(+), 12 deletions(-) create mode 100644 build/build_appx_makecert.cmd diff --git a/.gitignore b/.gitignore index c8bba02b98ab..334d389b9df0 100644 --- a/.gitignore +++ b/.gitignore @@ -9,13 +9,16 @@ # Build results *.appx +*.cer *.ilk *.meta *.obj *.pch *.pdb +*.pfx *.pgc *.pgd +*.pvk *.rsp *.sbr *.tlb diff --git a/build/build_appx_makecert.cmd b/build/build_appx_makecert.cmd new file mode 100644 index 000000000000..d65686b5a244 --- /dev/null +++ b/build/build_appx_makecert.cmd @@ -0,0 +1,7 @@ +@echo off +@setlocal enableextensions +@cd /d "%~dp0\..\" + +start /B /W "" "tools\CustomBuildTool\bin\Release\CustomBuildTool.exe" "-appxmakecert" + +pause \ No newline at end of file diff --git a/tools/CustomBuildTool/Source Files/Build.cs b/tools/CustomBuildTool/Source Files/Build.cs index 386702e3c8b0..26fe6b66fbd7 100644 --- a/tools/CustomBuildTool/Source Files/Build.cs +++ b/tools/CustomBuildTool/Source Files/Build.cs @@ -222,8 +222,11 @@ public static void CleanupBuildEnvironment() public static void ShowBuildEnvironment(string Platform, bool ShowBuildInfo) { - Program.PrintColorMessage("Build: ", ConsoleColor.Cyan, false); - Program.PrintColorMessage(Platform, ConsoleColor.White, false); + if (ShowBuildInfo) + { + Program.PrintColorMessage("Build: ", ConsoleColor.Cyan, false); + Program.PrintColorMessage(Platform, ConsoleColor.White, false); + } string currentGitTag = Win32.ExecCommand(GitExePath, "describe --abbrev=0 --tags --always"); string latestGitRevision = Win32.ExecCommand(GitExePath, "rev-list --count \"" + currentGitTag + ".." + BuildBranch + "\""); @@ -301,7 +304,7 @@ public static bool CopyTextFiles() } catch (Exception ex) { - Program.PrintColorMessage("[ERROR] " + ex, ConsoleColor.Red); + Program.PrintColorMessage("[CopyTextFiles] " + ex, ConsoleColor.Red); return false; } @@ -462,7 +465,6 @@ public static bool CopyVersionHeader() File.Copy("ProcessHacker\\sdk\\phapppub.h", "sdk\\include\\phapppub.h", true); File.Copy("ProcessHacker\\sdk\\phdk.h", "sdk\\include\\phdk.h", true); - File.Copy("ProcessHacker\\mxml\\mxml.h", "sdk\\include\\mxml.h", true); File.Copy("ProcessHacker\\resource.h", "sdk\\include\\phappresource.h", true); } catch (Exception ex) @@ -1096,7 +1098,7 @@ public static void BuildAppxPackage() "pack /o /f build\\package.map /p " + BuildOutputFolder + "\\processhacker-build-package.appx" ); - Program.PrintColorMessage(error, ConsoleColor.Gray); + Program.PrintColorMessage(Environment.NewLine + error, ConsoleColor.Gray); if (File.Exists("build\\AppxManifest.xml")) File.Delete("build\\AppxManifest.xml"); @@ -1107,14 +1109,10 @@ public static void BuildAppxPackage() error = Win32.ExecCommand( signToolExePath, - "sign /v /fd SHA256 /a /f build\\appx.pfx /td SHA256 " + BuildOutputFolder + "\\processhacker-build-package.appx" + "sign /v /fd SHA256 /a /f build\\processhacker-appx.pfx /td SHA256 " + BuildOutputFolder + "\\processhacker-build-package.appx" ); - if (!string.IsNullOrEmpty(error) && !error.Contains("Successfully signed")) - { - Program.PrintColorMessage(Environment.NewLine + error, ConsoleColor.DarkGray); - return; - } + Program.PrintColorMessage(Environment.NewLine + error, ConsoleColor.Gray); } catch (Exception ex) { diff --git a/tools/CustomBuildTool/Source Files/NativeMethods.cs b/tools/CustomBuildTool/Source Files/NativeMethods.cs index 0115f4209f27..f173c3cff2fa 100644 --- a/tools/CustomBuildTool/Source Files/NativeMethods.cs +++ b/tools/CustomBuildTool/Source Files/NativeMethods.cs @@ -33,6 +33,8 @@ public static string ExecCommand(string FileName, string args) public const int STD_OUTPUT_HANDLE = -11; public const int STD_INPUT_HANDLE = -10; public const int STD_ERROR_HANDLE = -12; + public const int SW_HIDE = 0; + public const int SW_SHOW = 5; static readonly IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1); @@ -42,6 +44,10 @@ public static string ExecCommand(string FileName, string args) public static extern bool GetConsoleMode(IntPtr ConsoleHandle, out ConsoleMode Mode); [DllImport("kernel32.dll")] public static extern bool SetConsoleMode(IntPtr ConsoleHandle, ConsoleMode Mode); + [DllImport("kernel32.dll")] + public static extern IntPtr GetConsoleWindow(); + [DllImport("user32.dll")] + public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow); } [Flags] diff --git a/tools/CustomBuildTool/Source Files/Program.cs b/tools/CustomBuildTool/Source Files/Program.cs index b08dbfb0c40f..dbf2eeac7091 100644 --- a/tools/CustomBuildTool/Source Files/Program.cs +++ b/tools/CustomBuildTool/Source Files/Program.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Security.Principal; namespace CustomBuildTool { @@ -204,7 +205,7 @@ public static void Main(string[] args) if (!Build.InitializeBuildEnvironment(true)) return; - Build.ShowBuildEnvironment("nightly", false); + Build.ShowBuildEnvironment("nightly", true); Build.BuildSecureFiles(); Build.UpdateHeaderFileVersion(); @@ -282,6 +283,27 @@ public static void Main(string[] args) } else if (ProgramArgs.ContainsKey("-appxmakecert")) { + WindowsIdentity identity = WindowsIdentity.GetCurrent(); + WindowsPrincipal principal = new WindowsPrincipal(identity); + + if (!principal.IsInRole(WindowsBuiltInRole.Administrator)) + { + Win32.ShowWindow(Win32.GetConsoleWindow(), Win32.SW_HIDE); + + try + { + System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo + { + FileName = System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName, + Arguments = "-appxmakecert", + Verb = "runas" + }); + } + catch (Exception) { } + + return; + } + if (!Build.InitializeBuildEnvironment(false)) return; diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe b/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe index c7103426b509e6da18aced66ecf171e3f0db4c6c..2e2e7c96ad00663d985f6ceeaca78ff8c94556f7 100644 GIT binary patch delta 17440 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 delta 16952 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 F{{y4GK->TT diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb b/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb index 89c01e4031cdb2ac1332bc6d3c6bb6f584ba701e..f00ca518a704458cd1de236ee07322455c4e43a0 100644 GIT binary patch delta 11834 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 From 2fadc93976165d48b265b036965d74c8c00d648c Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 7 May 2017 09:55:54 +1000 Subject: [PATCH 0062/2058] Fix typo --- tools/CustomBuildTool/Source Files/Build.cs | 1 + .../bin/Release/CustomBuildTool.exe | Bin 156160 -> 156672 bytes .../bin/Release/CustomBuildTool.pdb | Bin 71168 -> 71168 bytes 3 files changed, 1 insertion(+) diff --git a/tools/CustomBuildTool/Source Files/Build.cs b/tools/CustomBuildTool/Source Files/Build.cs index 26fe6b66fbd7..ee89924e1f81 100644 --- a/tools/CustomBuildTool/Source Files/Build.cs +++ b/tools/CustomBuildTool/Source Files/Build.cs @@ -465,6 +465,7 @@ public static bool CopyVersionHeader() File.Copy("ProcessHacker\\sdk\\phapppub.h", "sdk\\include\\phapppub.h", true); File.Copy("ProcessHacker\\sdk\\phdk.h", "sdk\\include\\phdk.h", true); + File.Copy("ProcessHacker\\mxml\\mxml.h", "sdk\\include\\mxml.h", true); File.Copy("ProcessHacker\\resource.h", "sdk\\include\\phappresource.h", true); } catch (Exception ex) diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe b/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe index 2e2e7c96ad00663d985f6ceeaca78ff8c94556f7..7b84b6df2e08ae2b6f57b291c5479b10b71f10ec 100644 GIT binary patch delta 6730 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 aRw|>}r=QF|tz7z^&R6^7vwG!I<-Y;ITgoK> delta 6610 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 diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb b/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb index f00ca518a704458cd1de236ee07322455c4e43a0..6e330471040d46fe1645c4748f46dedb70f5a334 100644 GIT binary patch delta 7588 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 F_kY(nfr9`5 delta 7434 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 MwCVvt_Eo?C0WBJGBme*a From a78459e5a5c3c1010546037f9dad27589964779f Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 7 May 2017 20:03:54 +1000 Subject: [PATCH 0063/2058] BuildTools: Fix missing sdk files --- tools/CustomBuildTool/CustomBuildTool.sln | 2 +- tools/CustomBuildTool/Source Files/Build.cs | 19 +++++++++++++++++- .../bin/Release/CustomBuildTool.exe | Bin 156672 -> 158208 bytes .../bin/Release/CustomBuildTool.pdb | Bin 71168 -> 71168 bytes 4 files changed, 19 insertions(+), 2 deletions(-) diff --git a/tools/CustomBuildTool/CustomBuildTool.sln b/tools/CustomBuildTool/CustomBuildTool.sln index 811b822b2e06..0558a6f4e5a1 100644 --- a/tools/CustomBuildTool/CustomBuildTool.sln +++ b/tools/CustomBuildTool/CustomBuildTool.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 -VisualStudioVersion = 15.0.26403.0 +VisualStudioVersion = 15.0.26403.7 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CustomBuildTool", "CustomBuildTool.csproj", "{CD644DF2-A658-4CBC-9497-CA5DD13CFEC3}" EndProject diff --git a/tools/CustomBuildTool/Source Files/Build.cs b/tools/CustomBuildTool/Source Files/Build.cs index ee89924e1f81..26a1dcbd8aad 100644 --- a/tools/CustomBuildTool/Source Files/Build.cs +++ b/tools/CustomBuildTool/Source Files/Build.cs @@ -444,6 +444,23 @@ public static bool CopyPluginSdkHeaders() { File.Copy("phlib\\include\\" + file, "sdk\\include\\" + file, true); } + + // Copy readme + File.Copy("ProcessHacker\\sdk\\readme.txt", "sdk\\readme.txt", true); + // Copy symbols + File.Copy("bin\\Release32\\ProcessHacker.pdb", "sdk\\dbg\\i386\\ProcessHacker.pdb", true); + File.Copy("bin\\Release64\\ProcessHacker.pdb", "sdk\\dbg\\amd64\\ProcessHacker.pdb", true); + File.Copy("KProcessHacker\\bin\\i386\\kprocesshacker.pdb", "sdk\\dbg\\i386\\kprocesshacker.pdb", true); + File.Copy("KProcessHacker\\bin\\amd64\\kprocesshacker.pdb", "sdk\\dbg\\amd64\\kprocesshacker.pdb", true); + // Copy libs + File.Copy("bin\\Release32\\ProcessHacker.lib", "sdk\\lib\\i386\\ProcessHacker.lib", true); + File.Copy("bin\\Release64\\ProcessHacker.lib", "sdk\\lib\\amd64\\ProcessHacker.lib", true); + // Copy sample plugin + File.Copy("plugins\\SamplePlugin\\main.c", "sdk\\samples\\SamplePlugin\\main.c", true); + File.Copy("plugins\\SamplePlugin\\SamplePlugin.sln", "sdk\\samples\\SamplePlugin\\SamplePlugin.sln", true); + File.Copy("plugins\\SamplePlugin\\SamplePlugin.vcxproj", "sdk\\samples\\SamplePlugin\\SamplePlugin.vcxproj", true); + File.Copy("plugins\\SamplePlugin\\SamplePlugin.vcxproj.filters", "sdk\\samples\\SamplePlugin\\SamplePlugin.vcxproj.filters", true); + File.Copy("plugins\\SamplePlugin\\bin\\Release32\\SamplePlugin.dll", "sdk\\samples\\SamplePlugin\\bin\\Release32\\SamplePlugin.dll", true); } catch (Exception ex) { @@ -708,7 +725,7 @@ public static bool BuildSdkZip() { File.Copy("ProcessHacker\\sdk\\readme.txt", "sdk\\readme.txt", true); - Zip.CreateCompressedSdkFromFolder("sdk\\", BuildOutputFolder + "\\processhacker-build-sdk.zip"); + Zip.CreateCompressedSdkFromFolder("sdk", BuildOutputFolder + "\\processhacker-build-sdk.zip"); } catch (Exception ex) { diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe b/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe index 7b84b6df2e08ae2b6f57b291c5479b10b71f10ec..cc4447fd6e5f2b48ee48b907c54786ec1cd927ae 100644 GIT binary patch delta 6504 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 AKmY&$ delta 5907 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 lbg3@&t4pb(vtKD}=xkuhGI!iEr+m3j^|c;O diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb b/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb index 6e330471040d46fe1645c4748f46dedb70f5a334..1e6ddc2eb2b1a931c70e25314f94a06444b9bffb 100644 GIT binary patch delta 8009 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 N_A8aW9rn7Q{{v^kVS)ev delta 7857 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 SZKSW=p^5ETJ1EfJ;q`yN*4%jj From 6e38952cf281b7bf8ec6382beefab36345318253 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 8 May 2017 01:17:55 +1000 Subject: [PATCH 0064/2058] peview: Add settings support for all tabs, Move settings support from main into phlib --- .gitignore | 2 +- ProcessHacker/ProcessHacker.def | 36 + ProcessHacker/ProcessHacker.vcxproj | 15 +- ProcessHacker/ProcessHacker.vcxproj.filters | 57 +- ProcessHacker/actions.c | 3 +- ProcessHacker/appsup.c | 126 +- ProcessHacker/hndllist.c | 3 +- ProcessHacker/include/appsup.h | 40 - ProcessHacker/include/phsettings.h | 67 + ProcessHacker/include/settingsp.h | 46 - ProcessHacker/logwnd.c | 1 + ProcessHacker/mainwnd.c | 1 + ProcessHacker/memlists.c | 1 + ProcessHacker/modlist.c | 3 +- ProcessHacker/mwpgproc.c | 1 + ProcessHacker/netlist.c | 3 +- ProcessHacker/notifico.c | 5 +- ProcessHacker/options.c | 3 +- ProcessHacker/procprp.c | 3 +- ProcessHacker/proctree.c | 3 +- ProcessHacker/prpgenv.c | 1 + ProcessHacker/prpgperf.c | 2 + ProcessHacker/sessshad.c | 3 +- ProcessHacker/settings.c | 1067 +------------- ProcessHacker/srvctl.c | 1 + ProcessHacker/srvlist.c | 3 +- ProcessHacker/sysinfo.c | 3 +- ProcessHacker/syssccpu.c | 3 +- ProcessHacker/sysscio.c | 3 +- ProcessHacker/sysscmem.c | 3 +- ProcessHacker/thrdlist.c | 3 +- ProcessHacker/tokprp.c | 1 + {plugins/OnlineChecks => build}/virustotal.s | Bin phlib/guisup.c | 126 -- phlib/icotobmp.c | 4 +- phlib/include/guisup.h | 11 - {ProcessHacker => phlib}/include/settings.h | 151 +- {ProcessHacker => phlib}/mxml/COPYING | 0 {ProcessHacker => phlib}/mxml/config.h | 0 {ProcessHacker => phlib}/mxml/mxml-attr.c | 0 {ProcessHacker => phlib}/mxml/mxml-entity.c | 0 {ProcessHacker => phlib}/mxml/mxml-file.c | 0 {ProcessHacker => phlib}/mxml/mxml-get.c | 0 {ProcessHacker => phlib}/mxml/mxml-index.c | 0 {ProcessHacker => phlib}/mxml/mxml-node.c | 0 {ProcessHacker => phlib}/mxml/mxml-private.c | 0 {ProcessHacker => phlib}/mxml/mxml-private.h | 0 {ProcessHacker => phlib}/mxml/mxml-search.c | 0 {ProcessHacker => phlib}/mxml/mxml-set.c | 0 {ProcessHacker => phlib}/mxml/mxml-string.c | 0 {ProcessHacker => phlib}/mxml/mxml.h | 0 phlib/phlib.vcxproj | 14 + phlib/phlib.vcxproj.filters | 42 + phlib/settings.c | 1251 +++++++++++++++++ plugins/DotNetTools/dn.h | 1 + plugins/ExtendedNotifications/filelog.c | 1 + plugins/ExtendedNotifications/main.c | 1 + plugins/ExtendedServices/extsrv.h | 1 + plugins/ExtendedTools/exttools.h | 1 + plugins/ExtraPlugins/main.h | 1 + plugins/HardwareDevices/devices.h | 1 + plugins/NetworkTools/nettools.h | 1 + plugins/OnlineChecks/onlnchk.h | 1 + plugins/SbieSupport/main.c | 1 + plugins/ToolStatus/toolstatus.h | 1 + plugins/Updater/updater.h | 1 + plugins/UserNotes/usernotes.h | 1 + plugins/WindowExplorer/wndexp.h | 1 + tools/CustomBuildTool/Source Files/Build.cs | 15 +- .../CustomBuildTool/Source Files/HeaderGen.cs | 1 - tools/CustomBuildTool/Source Files/Program.cs | 48 +- .../bin/Release/CustomBuildTool.exe | Bin 158208 -> 157696 bytes .../bin/Release/CustomBuildTool.pdb | Bin 71168 -> 71168 bytes tools/peview/include/peview.h | 12 + tools/peview/include/prpsh.h | 1 + tools/peview/main.c | 6 +- tools/peview/peprp.c | 59 +- tools/peview/peview.vcxproj | 1 + tools/peview/peview.vcxproj.filters | 3 + tools/peview/prpsh.c | 63 +- tools/peview/settings.c | 141 ++ 81 files changed, 1911 insertions(+), 1564 deletions(-) create mode 100644 ProcessHacker/include/phsettings.h delete mode 100644 ProcessHacker/include/settingsp.h rename {plugins/OnlineChecks => build}/virustotal.s (100%) rename {ProcessHacker => phlib}/include/settings.h (54%) rename {ProcessHacker => phlib}/mxml/COPYING (100%) rename {ProcessHacker => phlib}/mxml/config.h (100%) rename {ProcessHacker => phlib}/mxml/mxml-attr.c (100%) rename {ProcessHacker => phlib}/mxml/mxml-entity.c (100%) rename {ProcessHacker => phlib}/mxml/mxml-file.c (100%) rename {ProcessHacker => phlib}/mxml/mxml-get.c (100%) rename {ProcessHacker => phlib}/mxml/mxml-index.c (100%) rename {ProcessHacker => phlib}/mxml/mxml-node.c (100%) rename {ProcessHacker => phlib}/mxml/mxml-private.c (100%) rename {ProcessHacker => phlib}/mxml/mxml-private.h (100%) rename {ProcessHacker => phlib}/mxml/mxml-search.c (100%) rename {ProcessHacker => phlib}/mxml/mxml-set.c (100%) rename {ProcessHacker => phlib}/mxml/mxml-string.c (100%) rename {ProcessHacker => phlib}/mxml/mxml.h (100%) create mode 100644 phlib/settings.c create mode 100644 tools/peview/settings.c diff --git a/.gitignore b/.gitignore index 334d389b9df0..91909cdebcd6 100644 --- a/.gitignore +++ b/.gitignore @@ -75,7 +75,7 @@ Desktop.ini build/*.exe build/*.zip -ProcessHacker/include/phapprev.h +build/*.h ProcessHacker/sdk/phapppub.h plugins-extra/ /sdk/ diff --git a/ProcessHacker/ProcessHacker.def b/ProcessHacker/ProcessHacker.def index fec35a00d451..97692aee76bf 100644 --- a/ProcessHacker/ProcessHacker.def +++ b/ProcessHacker/ProcessHacker.def @@ -523,6 +523,33 @@ EXPORTS PhInitializeMappedImage PhLoadMappedImage +; settings + PhAddSetting + PhAddSettings + PhClearIgnoredSettings + PhConvertIgnoredSettings + PhGetIntegerSetting + PhGetIntegerPairSetting + PhGetScalableIntegerPairSetting + PhGetStringSetting + PhLoadSettings + PhLoadListViewColumnSettings + PhLoadListViewColumnsFromSetting + PhLoadWindowPlacementFromSetting + PhResetSettings + PhSaveListViewColumnSettings + PhSaveListViewColumnsToSetting + PhSaveWindowPlacementToSetting + PhSettingsInitialization + PhSetIntegerSetting + PhSetIntegerPairSetting + PhSetScalableIntegerPairSetting + PhSetScalableIntegerPairSetting2 + PhSetStringSetting + PhSetStringSetting2 + PhSaveSettings + PhUpdateCachedSettings + ; secedit PhCreateSecurityPage PhEditSecurity @@ -576,3 +603,12 @@ EXPORTS PhQueueItemWorkQueue PhQueueItemWorkQueueEx PhWaitForWorkQueue + +; mxml + mxmlDelete + mxmlElementSetAttr + mxmlLoadFd + mxmlNewOpaque + mxmlNewElement + mxmlSaveFd + mxml_opaque_cb \ No newline at end of file diff --git a/ProcessHacker/ProcessHacker.vcxproj b/ProcessHacker/ProcessHacker.vcxproj index abad4684afab..f212a670d21b 100644 --- a/ProcessHacker/ProcessHacker.vcxproj +++ b/ProcessHacker/ProcessHacker.vcxproj @@ -317,15 +317,6 @@ - - - - - - - - - @@ -353,6 +344,7 @@ + @@ -361,11 +353,8 @@ - - - @@ -382,8 +371,6 @@ - - diff --git a/ProcessHacker/ProcessHacker.vcxproj.filters b/ProcessHacker/ProcessHacker.vcxproj.filters index 0af73f22ef55..671c41cb8543 100644 --- a/ProcessHacker/ProcessHacker.vcxproj.filters +++ b/ProcessHacker/ProcessHacker.vcxproj.filters @@ -16,18 +16,12 @@ {3fa0b151-12c1-4832-94fb-e16c52584b65} - - {eaabb14f-9091-4b18-8764-45c8350f4887} - {84a3be0b-42cf-42ae-bcd3-16f165caa0db} {e72b6c69-b510-4578-9ed5-34a16d8dffc1} - - {c4b014d0-6bd0-4848-a23f-e639563d998e} - {67c40321-0b28-4c16-8c48-dc0b64c148d7} @@ -165,9 +159,6 @@ Process Hacker - - Process Hacker - Process Hacker @@ -189,33 +180,6 @@ Process Hacker - - Mini-XML - - - Mini-XML - - - Mini-XML - - - Mini-XML - - - Mini-XML - - - Mini-XML - - - Mini-XML - - - Mini-XML - - - Mini-XML - Process Hacker @@ -414,6 +378,9 @@ Process Hacker + + Process Hacker + @@ -437,12 +404,6 @@ Headers - - Headers - - - Headers - Headers @@ -506,15 +467,6 @@ PCRE\Headers - - Mini-XML\Headers - - - Mini-XML\Headers - - - Mini-XML\Headers - Headers @@ -587,6 +539,9 @@ Headers + + Headers + diff --git a/ProcessHacker/actions.c b/ProcessHacker/actions.c index f0f7526594fc..c9113390bc08 100644 --- a/ProcessHacker/actions.c +++ b/ProcessHacker/actions.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include @@ -43,7 +44,7 @@ #include #include #include -#include +#include #include #include diff --git a/ProcessHacker/appsup.c b/ProcessHacker/appsup.c index 1d09f88b4014..4e6a5d25f525 100644 --- a/ProcessHacker/appsup.c +++ b/ProcessHacker/appsup.c @@ -30,13 +30,13 @@ #include #include #include +#include #include #include #include -#include +#include -#include "mxml/mxml.h" #include "pcre/pcre2.h" typedef LONG (WINAPI *_GetPackageFullName)( @@ -901,20 +901,6 @@ PPH_STRING PhUnescapeStringForDelimiter( return PhFinalStringBuilderString(&stringBuilder); } -PPH_STRING PhGetOpaqueXmlNodeText( - _In_ mxml_node_t *node - ) -{ - if (node->child && node->child->type == MXML_OPAQUE && node->child->value.opaque) - { - return PhConvertUtf8ToUtf16(node->child->value.opaque); - } - else - { - return PhReferenceEmptyString(); - } -} - VOID PhSearchOnlineString( _In_ HWND hWnd, _In_ PWSTR String @@ -1184,114 +1170,6 @@ VOID PhSetWindowOpacity( ); } -VOID PhLoadWindowPlacementFromSetting( - _In_opt_ PWSTR PositionSettingName, - _In_opt_ PWSTR SizeSettingName, - _In_ HWND WindowHandle - ) -{ - PH_RECTANGLE windowRectangle; - - if (PositionSettingName && SizeSettingName) - { - RECT rectForAdjust; - - windowRectangle.Position = PhGetIntegerPairSetting(PositionSettingName); - windowRectangle.Size = PhGetScalableIntegerPairSetting(SizeSettingName, TRUE).Pair; - PhAdjustRectangleToWorkingArea(NULL, &windowRectangle); - - // Let the window adjust for the minimum size if needed. - rectForAdjust = PhRectangleToRect(windowRectangle); - SendMessage(WindowHandle, WM_SIZING, WMSZ_BOTTOMRIGHT, (LPARAM)&rectForAdjust); - windowRectangle = PhRectToRectangle(rectForAdjust); - - MoveWindow(WindowHandle, windowRectangle.Left, windowRectangle.Top, - windowRectangle.Width, windowRectangle.Height, FALSE); - } - else - { - PH_INTEGER_PAIR position; - PH_INTEGER_PAIR size; - ULONG flags; - - flags = SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOREDRAW | SWP_NOSIZE | SWP_NOZORDER; - - if (PositionSettingName) - { - position = PhGetIntegerPairSetting(PositionSettingName); - flags &= ~SWP_NOMOVE; - } - else - { - position.X = 0; - position.Y = 0; - } - - if (SizeSettingName) - { - size = PhGetScalableIntegerPairSetting(SizeSettingName, TRUE).Pair; - flags &= ~SWP_NOSIZE; - } - else - { - size.X = 16; - size.Y = 16; - } - - SetWindowPos(WindowHandle, NULL, position.X, position.Y, size.X, size.Y, flags); - } -} - -VOID PhSaveWindowPlacementToSetting( - _In_opt_ PWSTR PositionSettingName, - _In_opt_ PWSTR SizeSettingName, - _In_ HWND WindowHandle - ) -{ - WINDOWPLACEMENT placement = { sizeof(placement) }; - PH_RECTANGLE windowRectangle; - MONITORINFO monitorInfo = { sizeof(MONITORINFO) }; - - GetWindowPlacement(WindowHandle, &placement); - windowRectangle = PhRectToRectangle(placement.rcNormalPosition); - - // The rectangle is in workspace coordinates. Convert the values back to screen coordinates. - if (GetMonitorInfo(MonitorFromRect(&placement.rcNormalPosition, MONITOR_DEFAULTTOPRIMARY), &monitorInfo)) - { - windowRectangle.Left += monitorInfo.rcWork.left - monitorInfo.rcMonitor.left; - windowRectangle.Top += monitorInfo.rcWork.top - monitorInfo.rcMonitor.top; - } - - if (PositionSettingName) - PhSetIntegerPairSetting(PositionSettingName, windowRectangle.Position); - if (SizeSettingName) - PhSetScalableIntegerPairSetting2(SizeSettingName, windowRectangle.Size); -} - -VOID PhLoadListViewColumnsFromSetting( - _In_ PWSTR Name, - _In_ HWND ListViewHandle - ) -{ - PPH_STRING string; - - string = PhGetStringSetting(Name); - PhLoadListViewColumnSettings(ListViewHandle, string); - PhDereferenceObject(string); -} - -VOID PhSaveListViewColumnsToSetting( - _In_ PWSTR Name, - _In_ HWND ListViewHandle - ) -{ - PPH_STRING string; - - string = PhSaveListViewColumnSettings(ListViewHandle); - PhSetStringSetting2(Name, &string->sr); - PhDereferenceObject(string); -} - PPH_STRING PhGetPhVersion( VOID ) diff --git a/ProcessHacker/hndllist.c b/ProcessHacker/hndllist.c index 517f838e79ee..6777cefe7159 100644 --- a/ProcessHacker/hndllist.c +++ b/ProcessHacker/hndllist.c @@ -26,11 +26,12 @@ #include #include +#include #include #include #include -#include +#include BOOLEAN PhpHandleNodeHashtableEqualFunction( _In_ PVOID Entry1, diff --git a/ProcessHacker/include/appsup.h b/ProcessHacker/include/appsup.h index e631485c30b9..fe34c8977206 100644 --- a/ProcessHacker/include/appsup.h +++ b/ProcessHacker/include/appsup.h @@ -124,12 +124,6 @@ PPH_STRING PhUnescapeStringForDelimiter( _In_ WCHAR Delimiter ); -typedef struct mxml_node_s mxml_node_t; - -PPH_STRING PhGetOpaqueXmlNodeText( - _In_ mxml_node_t *node - ); - // begin_phapppub PHAPPAPI VOID @@ -221,40 +215,6 @@ VOID PhSetWindowOpacity( #define PH_ID_TO_OPACITY(Id) (100 - (((Id) - ID_OPACITY_10) + 1) * 10) // begin_phapppub -PHAPPAPI -VOID -NTAPI -PhLoadWindowPlacementFromSetting( - _In_opt_ PWSTR PositionSettingName, - _In_opt_ PWSTR SizeSettingName, - _In_ HWND WindowHandle - ); - -PHAPPAPI -VOID -NTAPI -PhSaveWindowPlacementToSetting( - _In_opt_ PWSTR PositionSettingName, - _In_opt_ PWSTR SizeSettingName, - _In_ HWND WindowHandle - ); - -PHAPPAPI -VOID -NTAPI -PhLoadListViewColumnsFromSetting( - _In_ PWSTR Name, - _In_ HWND ListViewHandle - ); - -PHAPPAPI -VOID -NTAPI -PhSaveListViewColumnsToSetting( - _In_ PWSTR Name, - _In_ HWND ListViewHandle - ); - PHAPPAPI PPH_STRING NTAPI diff --git a/ProcessHacker/include/phsettings.h b/ProcessHacker/include/phsettings.h new file mode 100644 index 000000000000..d722745c8815 --- /dev/null +++ b/ProcessHacker/include/phsettings.h @@ -0,0 +1,67 @@ +#ifndef PH_SETTINGS_H +#define PH_SETTINGS_H + +// Cached settings + +#undef EXT + +#ifdef PH_SETTINGS_PRIVATE +#define EXT +#else +#define EXT extern +#endif + +EXT ULONG PhCsCollapseServicesOnStart; +EXT ULONG PhCsForceNoParent; +EXT ULONG PhCsHighlightingDuration; +EXT ULONG PhCsPropagateCpuUsage; +EXT ULONG PhCsScrollToNewProcesses; +EXT ULONG PhCsShowCpuBelow001; +EXT ULONG PhCsUpdateInterval; + +EXT ULONG PhCsColorNew; +EXT ULONG PhCsColorRemoved; +EXT ULONG PhCsUseColorOwnProcesses; +EXT ULONG PhCsColorOwnProcesses; +EXT ULONG PhCsUseColorSystemProcesses; +EXT ULONG PhCsColorSystemProcesses; +EXT ULONG PhCsUseColorServiceProcesses; +EXT ULONG PhCsColorServiceProcesses; +EXT ULONG PhCsUseColorJobProcesses; +EXT ULONG PhCsColorJobProcesses; +EXT ULONG PhCsUseColorWow64Processes; +EXT ULONG PhCsColorWow64Processes; +EXT ULONG PhCsUseColorDebuggedProcesses; +EXT ULONG PhCsColorDebuggedProcesses; +EXT ULONG PhCsUseColorElevatedProcesses; +EXT ULONG PhCsColorElevatedProcesses; +EXT ULONG PhCsUseColorPicoProcesses; +EXT ULONG PhCsColorPicoProcesses; +EXT ULONG PhCsUseColorImmersiveProcesses; +EXT ULONG PhCsColorImmersiveProcesses; +EXT ULONG PhCsUseColorSuspended; +EXT ULONG PhCsColorSuspended; +EXT ULONG PhCsUseColorDotNet; +EXT ULONG PhCsColorDotNet; +EXT ULONG PhCsUseColorPacked; +EXT ULONG PhCsColorPacked; +EXT ULONG PhCsUseColorGuiThreads; +EXT ULONG PhCsColorGuiThreads; +EXT ULONG PhCsUseColorRelocatedModules; +EXT ULONG PhCsColorRelocatedModules; +EXT ULONG PhCsUseColorProtectedHandles; +EXT ULONG PhCsColorProtectedHandles; +EXT ULONG PhCsUseColorInheritHandles; +EXT ULONG PhCsColorInheritHandles; +EXT ULONG PhCsGraphShowText; +EXT ULONG PhCsGraphColorMode; +EXT ULONG PhCsColorCpuKernel; +EXT ULONG PhCsColorCpuUser; +EXT ULONG PhCsColorIoReadOther; +EXT ULONG PhCsColorIoWrite; +EXT ULONG PhCsColorPrivate; +EXT ULONG PhCsColorPhysical; + +#define PH_SET_INTEGER_CACHED_SETTING(Name, Value) (PhSetIntegerSetting(L#Name, PhCs##Name = (Value))) + +#endif diff --git a/ProcessHacker/include/settingsp.h b/ProcessHacker/include/settingsp.h deleted file mode 100644 index 8b31daaaea08..000000000000 --- a/ProcessHacker/include/settingsp.h +++ /dev/null @@ -1,46 +0,0 @@ -#ifndef PH_SETTINGSP_H -#define PH_SETTINGSP_H - -#include - -BOOLEAN NTAPI PhpSettingsHashtableEqualFunction( - _In_ PVOID Entry1, - _In_ PVOID Entry2 - ); - -ULONG NTAPI PhpSettingsHashtableHashFunction( - _In_ PVOID Entry - ); - -VOID PhpAddSetting( - _In_ PH_SETTING_TYPE Type, - _In_ PPH_STRINGREF Name, - _In_ PPH_STRINGREF DefaultValue - ); - -ULONG PhpGetCurrentScale( - VOID - ); - -PPH_STRING PhpSettingToString( - _In_ PH_SETTING_TYPE Type, - _In_ PPH_SETTING Setting - ); - -BOOLEAN PhpSettingFromString( - _In_ PH_SETTING_TYPE Type, - _In_ PPH_STRINGREF StringRef, - _In_opt_ PPH_STRING String, - _Inout_ PPH_SETTING Setting - ); - -VOID PhpFreeSettingValue( - _In_ PH_SETTING_TYPE Type, - _In_ PPH_SETTING Setting - ); - -PVOID PhpLookupSetting( - _In_ PPH_STRINGREF Name - ); - -#endif diff --git a/ProcessHacker/logwnd.c b/ProcessHacker/logwnd.c index d35acede54ac..0a9b71a94b62 100644 --- a/ProcessHacker/logwnd.c +++ b/ProcessHacker/logwnd.c @@ -21,6 +21,7 @@ */ #include +#include #include diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index 033a4850bd32..0154356736f9 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include diff --git a/ProcessHacker/memlists.c b/ProcessHacker/memlists.c index 732e15b07729..6f73a3f3d918 100644 --- a/ProcessHacker/memlists.c +++ b/ProcessHacker/memlists.c @@ -23,6 +23,7 @@ #include #include +#include #include #include diff --git a/ProcessHacker/modlist.c b/ProcessHacker/modlist.c index 3cca62efabd0..93704252428f 100644 --- a/ProcessHacker/modlist.c +++ b/ProcessHacker/modlist.c @@ -25,11 +25,12 @@ #include #include +#include #include #include #include -#include +#include BOOLEAN PhpModuleNodeHashtableEqualFunction( _In_ PVOID Entry1, diff --git a/ProcessHacker/mwpgproc.c b/ProcessHacker/mwpgproc.c index e9d633637bc9..11307c937294 100644 --- a/ProcessHacker/mwpgproc.c +++ b/ProcessHacker/mwpgproc.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include diff --git a/ProcessHacker/netlist.c b/ProcessHacker/netlist.c index 6efb1357d811..bfc42aca3fb6 100644 --- a/ProcessHacker/netlist.c +++ b/ProcessHacker/netlist.c @@ -25,14 +25,15 @@ #include #include +#include #include #include #include #include #include +#include #include -#include BOOLEAN PhpNetworkNodeHashtableEqualFunction( _In_ PVOID Entry1, diff --git a/ProcessHacker/notifico.c b/ProcessHacker/notifico.c index ccaedd1c3915..729f81412e78 100644 --- a/ProcessHacker/notifico.c +++ b/ProcessHacker/notifico.c @@ -21,6 +21,7 @@ */ #include +#include #include #include @@ -757,7 +758,7 @@ VOID PhNfpBeginBitmap2( { HDC screenHdc; - screenHdc = GetDC(NULL); + screenHdc = CreateIC(L"DISPLAY", NULL, NULL, NULL); Context->Hdc = CreateCompatibleDC(screenHdc); memset(&Context->Header, 0, sizeof(BITMAPINFOHEADER)); @@ -768,7 +769,7 @@ VOID PhNfpBeginBitmap2( Context->Header.biBitCount = 32; Context->Bitmap = CreateDIBSection(screenHdc, (BITMAPINFO *)&Context->Header, DIB_RGB_COLORS, &Context->Bits, NULL, 0); - ReleaseDC(NULL, screenHdc); + DeleteDC(screenHdc); Context->Initialized = TRUE; } diff --git a/ProcessHacker/options.c b/ProcessHacker/options.c index 32782a527ce9..c93fcbef6a06 100644 --- a/ProcessHacker/options.c +++ b/ProcessHacker/options.c @@ -27,10 +27,11 @@ #include #include +#include #include #include -#include +#include #include #define WM_PH_CHILD_EXIT (WM_APP + 301) diff --git a/ProcessHacker/procprp.c b/ProcessHacker/procprp.c index 17488331c501..03236a716ee7 100644 --- a/ProcessHacker/procprp.c +++ b/ProcessHacker/procprp.c @@ -27,10 +27,11 @@ #include #include +#include #include +#include #include -#include PPH_OBJECT_TYPE PhpProcessPropContextType; PPH_OBJECT_TYPE PhpProcessPropPageContextType; diff --git a/ProcessHacker/proctree.c b/ProcessHacker/proctree.c index 9cdd693494ed..b27671f789fb 100644 --- a/ProcessHacker/proctree.c +++ b/ProcessHacker/proctree.c @@ -34,13 +34,14 @@ #include #include #include +#include #include #include #include #include +#include #include -#include typedef enum _PHP_AGGREGATE_TYPE { diff --git a/ProcessHacker/prpgenv.c b/ProcessHacker/prpgenv.c index 46f6d895bd5b..2f8f181b94a0 100644 --- a/ProcessHacker/prpgenv.c +++ b/ProcessHacker/prpgenv.c @@ -28,6 +28,7 @@ #include #include +#include #include diff --git a/ProcessHacker/prpgperf.c b/ProcessHacker/prpgperf.c index cfa46d60d7c3..9efb80e93072 100644 --- a/ProcessHacker/prpgperf.c +++ b/ProcessHacker/prpgperf.c @@ -25,10 +25,12 @@ #include #include +#include #include #include #include +#include static VOID NTAPI PerformanceUpdateHandler( _In_opt_ PVOID Parameter, diff --git a/ProcessHacker/sessshad.c b/ProcessHacker/sessshad.c index 58c03ced17f6..62bd01a8317a 100644 --- a/ProcessHacker/sessshad.c +++ b/ProcessHacker/sessshad.c @@ -21,12 +21,11 @@ */ #include +#include #include #include -#include - #define SIP(String, Integer) { (String), (PVOID)(Integer) } static PH_KEY_VALUE_PAIR VirtualKeyPairs[] = diff --git a/ProcessHacker/settings.c b/ProcessHacker/settings.c index 5412d4960e18..91077674310b 100644 --- a/ProcessHacker/settings.c +++ b/ProcessHacker/settings.c @@ -1,8 +1,9 @@ /* * Process Hacker - - * program settings + * program settings cache * * Copyright (C) 2010-2016 wj32 + * Copyright (C) 2017 dmex * * This file is part of Process Hacker. * @@ -20,59 +21,15 @@ * along with Process Hacker. If not, see . */ -/* - * This file contains a program-specific settings system. All possible - * settings are defined at program startup and added to a hashtable. - * The values of these settings can then be read in from a XML file or - * saved to a XML file at any time. Settings which are not recognized - * are added to a list of "ignored settings"; this is necessary to - * support plugin settings, as we don't want their settings to get - * deleted whenever the plugins are disabled. - * - * The get/set functions are very strict. If the wrong function is used - * (the get-integer-setting function is used on a string setting) or - * the setting does not exist, an exception will be raised. - */ - #include -#define PH_SETTINGS_PRIVATE #include -#include - -#include "mxml/mxml.h" - -PPH_HASHTABLE PhSettingsHashtable; -PH_QUEUED_LOCK PhSettingsLock = PH_QUEUED_LOCK_INIT; - -PPH_LIST PhIgnoredSettings; - -// These macros make sure the C strings can be seamlessly converted into -// PH_STRINGREFs at compile time, for a small speed boost. - -#define ADD_SETTING_WRAPPER(Type, Name, DefaultValue) \ - { \ - static PH_STRINGREF name = PH_STRINGREF_INIT(Name); \ - static PH_STRINGREF defaultValue = PH_STRINGREF_INIT(DefaultValue); \ - PhpAddSetting(Type, &name, &defaultValue); \ - } - -#define PhpAddStringSetting(A, B) ADD_SETTING_WRAPPER(StringSettingType, A, B) -#define PhpAddIntegerSetting(A, B) ADD_SETTING_WRAPPER(IntegerSettingType, A, B) -#define PhpAddIntegerPairSetting(A, B) ADD_SETTING_WRAPPER(IntegerPairSettingType, A, B) -#define PhpAddScalableIntegerPairSetting(A, B) ADD_SETTING_WRAPPER(ScalableIntegerPairSettingType, A, B) +#define PH_SETTINGS_PRIVATE +#include -VOID PhSettingsInitialization( +VOID PhAddDefaultSettings( VOID ) { - PhSettingsHashtable = PhCreateHashtable( - sizeof(PH_SETTING), - PhpSettingsHashtableEqualFunction, - PhpSettingsHashtableHashFunction, - 256 - ); - PhIgnoredSettings = PhCreateList(4); - PhpAddIntegerSetting(L"AllowOnlyOneInstance", L"1"); PhpAddIntegerSetting(L"CloseOnEscape", L"0"); PhpAddIntegerSetting(L"CollapseServicesOnStart", L"0"); @@ -189,8 +146,7 @@ VOID PhSettingsInitialization( PhpAddStringSetting(L"TokenPrivilegesListViewColumns", L""); PhpAddIntegerSetting(L"UpdateInterval", L"3e8"); // 1000ms - // Colors are specified with R in the lowest byte, then G, then B. - // So: bbggrr. + // Colors are specified with R in the lowest byte, then G, then B. So: bbggrr. PhpAddIntegerSetting(L"ColorNew", L"00ff7f"); // Chartreuse PhpAddIntegerSetting(L"ColorRemoved", L"283cff"); PhpAddIntegerSetting(L"UseColorOwnProcesses", L"1"); @@ -234,968 +190,61 @@ VOID PhSettingsInitialization( PhpAddIntegerSetting(L"ColorIoWrite", L"ff0077"); PhpAddIntegerSetting(L"ColorPrivate", L"0077ff"); PhpAddIntegerSetting(L"ColorPhysical", L"ffff00"); - - PhUpdateCachedSettings(); } VOID PhUpdateCachedSettings( VOID ) { -#define UPDATE_INTEGER_CS(Name) (PhCs##Name = PhGetIntegerSetting(L#Name)) - - UPDATE_INTEGER_CS(CollapseServicesOnStart); - UPDATE_INTEGER_CS(ForceNoParent); - UPDATE_INTEGER_CS(HighlightingDuration); - UPDATE_INTEGER_CS(PropagateCpuUsage); - UPDATE_INTEGER_CS(ScrollToNewProcesses); - UPDATE_INTEGER_CS(ShowCpuBelow001); - UPDATE_INTEGER_CS(UpdateInterval); - - UPDATE_INTEGER_CS(ColorNew); - UPDATE_INTEGER_CS(ColorRemoved); - UPDATE_INTEGER_CS(UseColorOwnProcesses); - UPDATE_INTEGER_CS(ColorOwnProcesses); - UPDATE_INTEGER_CS(UseColorSystemProcesses); - UPDATE_INTEGER_CS(ColorSystemProcesses); - UPDATE_INTEGER_CS(UseColorServiceProcesses); - UPDATE_INTEGER_CS(ColorServiceProcesses); - UPDATE_INTEGER_CS(UseColorJobProcesses); - UPDATE_INTEGER_CS(ColorJobProcesses); - UPDATE_INTEGER_CS(UseColorWow64Processes); - UPDATE_INTEGER_CS(ColorWow64Processes); - UPDATE_INTEGER_CS(UseColorDebuggedProcesses); - UPDATE_INTEGER_CS(ColorDebuggedProcesses); - UPDATE_INTEGER_CS(UseColorElevatedProcesses); - UPDATE_INTEGER_CS(ColorElevatedProcesses); - UPDATE_INTEGER_CS(UseColorPicoProcesses); - UPDATE_INTEGER_CS(ColorPicoProcesses); - UPDATE_INTEGER_CS(UseColorImmersiveProcesses); - UPDATE_INTEGER_CS(ColorImmersiveProcesses); - UPDATE_INTEGER_CS(UseColorSuspended); - UPDATE_INTEGER_CS(ColorSuspended); - UPDATE_INTEGER_CS(UseColorDotNet); - UPDATE_INTEGER_CS(ColorDotNet); - UPDATE_INTEGER_CS(UseColorPacked); - UPDATE_INTEGER_CS(ColorPacked); - UPDATE_INTEGER_CS(UseColorGuiThreads); - UPDATE_INTEGER_CS(ColorGuiThreads); - UPDATE_INTEGER_CS(UseColorRelocatedModules); - UPDATE_INTEGER_CS(ColorRelocatedModules); - UPDATE_INTEGER_CS(UseColorProtectedHandles); - UPDATE_INTEGER_CS(ColorProtectedHandles); - UPDATE_INTEGER_CS(UseColorInheritHandles); - UPDATE_INTEGER_CS(ColorInheritHandles); - UPDATE_INTEGER_CS(GraphShowText); - UPDATE_INTEGER_CS(GraphColorMode); - UPDATE_INTEGER_CS(ColorCpuKernel); - UPDATE_INTEGER_CS(ColorCpuUser); - UPDATE_INTEGER_CS(ColorIoReadOther); - UPDATE_INTEGER_CS(ColorIoWrite); - UPDATE_INTEGER_CS(ColorPrivate); - UPDATE_INTEGER_CS(ColorPhysical); -} - -BOOLEAN NTAPI PhpSettingsHashtableEqualFunction( - _In_ PVOID Entry1, - _In_ PVOID Entry2 - ) -{ - PPH_SETTING setting1 = (PPH_SETTING)Entry1; - PPH_SETTING setting2 = (PPH_SETTING)Entry2; - - return PhEqualStringRef(&setting1->Name, &setting2->Name, FALSE); -} - -ULONG NTAPI PhpSettingsHashtableHashFunction( - _In_ PVOID Entry - ) -{ - PPH_SETTING setting = (PPH_SETTING)Entry; - - return PhHashBytes((PUCHAR)setting->Name.Buffer, setting->Name.Length); -} - -static VOID PhpAddSetting( - _In_ PH_SETTING_TYPE Type, - _In_ PPH_STRINGREF Name, - _In_ PPH_STRINGREF DefaultValue - ) -{ - PH_SETTING setting; - - setting.Type = Type; - setting.Name = *Name; - setting.DefaultValue = *DefaultValue; - memset(&setting.u, 0, sizeof(setting.u)); - - PhpSettingFromString(Type, &setting.DefaultValue, NULL, &setting); - - PhAddEntryHashtable(PhSettingsHashtable, &setting); -} - -static ULONG PhpGetCurrentScale( - VOID - ) -{ - static PH_INITONCE initOnce; - static ULONG dpi = 96; - - if (PhBeginInitOnce(&initOnce)) - { - HDC hdc; - - if (hdc = GetDC(NULL)) - { - dpi = GetDeviceCaps(hdc, LOGPIXELSY); - ReleaseDC(NULL, hdc); - } - - PhEndInitOnce(&initOnce); - } - - return dpi; -} - -static PPH_STRING PhpSettingToString( - _In_ PH_SETTING_TYPE Type, - _In_ PPH_SETTING Setting - ) -{ - switch (Type) - { - case StringSettingType: - { - if (!Setting->u.Pointer) - return PhReferenceEmptyString(); - - PhReferenceObject(Setting->u.Pointer); - - return (PPH_STRING)Setting->u.Pointer; - } - case IntegerSettingType: - { - return PhFormatString(L"%x", Setting->u.Integer); - } - case IntegerPairSettingType: - { - PPH_INTEGER_PAIR integerPair = &Setting->u.IntegerPair; - - return PhFormatString(L"%d,%d", integerPair->X, integerPair->Y); - } - case ScalableIntegerPairSettingType: - { - PPH_SCALABLE_INTEGER_PAIR scalableIntegerPair = Setting->u.Pointer; - - if (!scalableIntegerPair) - return PhReferenceEmptyString(); - - return PhFormatString(L"@%u|%d,%d", scalableIntegerPair->Scale, scalableIntegerPair->X, scalableIntegerPair->Y); - } - } - - return PhReferenceEmptyString(); -} - -static BOOLEAN PhpSettingFromString( - _In_ PH_SETTING_TYPE Type, - _In_ PPH_STRINGREF StringRef, - _In_opt_ PPH_STRING String, - _Inout_ PPH_SETTING Setting - ) -{ - switch (Type) - { - case StringSettingType: - { - if (String) - { - PhSetReference(&Setting->u.Pointer, String); - } - else - { - Setting->u.Pointer = PhCreateString2(StringRef); - } - - return TRUE; - } - case IntegerSettingType: - { - ULONG64 integer; - - if (PhStringToInteger64(StringRef, 16, &integer)) - { - Setting->u.Integer = (ULONG)integer; - return TRUE; - } - else - { - return FALSE; - } - } - case IntegerPairSettingType: - { - LONG64 x; - LONG64 y; - PH_STRINGREF xString; - PH_STRINGREF yString; - - if (!PhSplitStringRefAtChar(StringRef, ',', &xString, &yString)) - return FALSE; - - if (PhStringToInteger64(&xString, 10, &x) && PhStringToInteger64(&yString, 10, &y)) - { - Setting->u.IntegerPair.X = (LONG)x; - Setting->u.IntegerPair.Y = (LONG)y; - return TRUE; - } - else - { - return FALSE; - } - } - case ScalableIntegerPairSettingType: - { - ULONG64 scale; - LONG64 x; - LONG64 y; - PH_STRINGREF stringRef; - PH_STRINGREF firstPart; - PH_STRINGREF secondPart; - PPH_SCALABLE_INTEGER_PAIR scalableIntegerPair; - - stringRef = *StringRef; - - if (stringRef.Length != 0 && stringRef.Buffer[0] == '@') - { - PhSkipStringRef(&stringRef, sizeof(WCHAR)); - - if (!PhSplitStringRefAtChar(&stringRef, '|', &firstPart, &stringRef)) - return FALSE; - if (!PhStringToInteger64(&firstPart, 10, &scale)) - return FALSE; - } - else - { - scale = PhpGetCurrentScale(); - } - - if (!PhSplitStringRefAtChar(&stringRef, ',', &firstPart, &secondPart)) - return FALSE; - - if (PhStringToInteger64(&firstPart, 10, &x) && PhStringToInteger64(&secondPart, 10, &y)) - { - scalableIntegerPair = PhAllocate(sizeof(PH_SCALABLE_INTEGER_PAIR)); - scalableIntegerPair->X = (LONG)x; - scalableIntegerPair->Y = (LONG)y; - scalableIntegerPair->Scale = (ULONG)scale; - Setting->u.Pointer = scalableIntegerPair; - return TRUE; - } - else - { - return FALSE; - } - } - } - - return FALSE; -} - -static VOID PhpFreeSettingValue( - _In_ PH_SETTING_TYPE Type, - _In_ PPH_SETTING Setting - ) -{ - switch (Type) - { - case StringSettingType: - PhClearReference(&Setting->u.Pointer); - break; - case ScalableIntegerPairSettingType: - PhFree(Setting->u.Pointer); - Setting->u.Pointer = NULL; - break; - } -} - -static PVOID PhpLookupSetting( - _In_ PPH_STRINGREF Name - ) -{ - PH_SETTING lookupSetting; - PPH_SETTING setting; - - lookupSetting.Name = *Name; - setting = (PPH_SETTING)PhFindEntryHashtable( - PhSettingsHashtable, - &lookupSetting - ); - - return setting; -} - -_May_raise_ ULONG PhGetIntegerSetting( - _In_ PWSTR Name - ) -{ - PPH_SETTING setting; - PH_STRINGREF name; - ULONG value; - - PhInitializeStringRef(&name, Name); - - PhAcquireQueuedLockShared(&PhSettingsLock); - - setting = PhpLookupSetting(&name); - - if (setting && setting->Type == IntegerSettingType) - { - value = setting->u.Integer; - } - else - { - setting = NULL; - } - - PhReleaseQueuedLockShared(&PhSettingsLock); - - if (!setting) - PhRaiseStatus(STATUS_NOT_FOUND); - - return value; -} - -_May_raise_ PH_INTEGER_PAIR PhGetIntegerPairSetting( - _In_ PWSTR Name - ) -{ - PPH_SETTING setting; - PH_STRINGREF name; - PH_INTEGER_PAIR value; - - PhInitializeStringRef(&name, Name); - - PhAcquireQueuedLockShared(&PhSettingsLock); - - setting = PhpLookupSetting(&name); - - if (setting && setting->Type == IntegerPairSettingType) - { - value = setting->u.IntegerPair; - } - else - { - setting = NULL; - } - - PhReleaseQueuedLockShared(&PhSettingsLock); - - if (!setting) - PhRaiseStatus(STATUS_NOT_FOUND); - - return value; -} - -_May_raise_ PH_SCALABLE_INTEGER_PAIR PhGetScalableIntegerPairSetting( - _In_ PWSTR Name, - _In_ BOOLEAN ScaleToCurrent - ) -{ - PPH_SETTING setting; - PH_STRINGREF name; - PH_SCALABLE_INTEGER_PAIR value; - - PhInitializeStringRef(&name, Name); - - PhAcquireQueuedLockShared(&PhSettingsLock); - - setting = PhpLookupSetting(&name); - - if (setting && setting->Type == ScalableIntegerPairSettingType) - { - value = *(PPH_SCALABLE_INTEGER_PAIR)setting->u.Pointer; - } - else - { - setting = NULL; - } - - PhReleaseQueuedLockShared(&PhSettingsLock); - - if (!setting) - PhRaiseStatus(STATUS_NOT_FOUND); - - if (ScaleToCurrent) - { - ULONG currentScale; - - currentScale = PhpGetCurrentScale(); - - if (value.Scale != currentScale && value.Scale != 0) - { - value.X = PhMultiplyDivideSigned(value.X, currentScale, value.Scale); - value.Y = PhMultiplyDivideSigned(value.Y, currentScale, value.Scale); - value.Scale = currentScale; - } - } - - return value; -} - -_May_raise_ PPH_STRING PhGetStringSetting( - _In_ PWSTR Name - ) -{ - PPH_SETTING setting; - PH_STRINGREF name; - PPH_STRING value; - - PhInitializeStringRef(&name, Name); - - PhAcquireQueuedLockShared(&PhSettingsLock); - - setting = PhpLookupSetting(&name); - - if (setting && setting->Type == StringSettingType) - { - if (setting->u.Pointer) - { - PhSetReference(&value, setting->u.Pointer); - } - else - { - // Set to NULL, create an empty string - // outside of the lock. - value = NULL; - } - } - else - { - setting = NULL; - } - - PhReleaseQueuedLockShared(&PhSettingsLock); - - if (!setting) - PhRaiseStatus(STATUS_NOT_FOUND); - - if (!value) - value = PhReferenceEmptyString(); - - return value; -} - -_May_raise_ VOID PhSetIntegerSetting( - _In_ PWSTR Name, - _In_ ULONG Value - ) -{ - PPH_SETTING setting; - PH_STRINGREF name; - - PhInitializeStringRef(&name, Name); - - PhAcquireQueuedLockExclusive(&PhSettingsLock); - - setting = PhpLookupSetting(&name); - - if (setting && setting->Type == IntegerSettingType) - { - setting->u.Integer = Value; - } - - PhReleaseQueuedLockExclusive(&PhSettingsLock); - - if (!setting) - PhRaiseStatus(STATUS_NOT_FOUND); -} - -_May_raise_ VOID PhSetIntegerPairSetting( - _In_ PWSTR Name, - _In_ PH_INTEGER_PAIR Value - ) -{ - PPH_SETTING setting; - PH_STRINGREF name; - - PhInitializeStringRef(&name, Name); - - PhAcquireQueuedLockExclusive(&PhSettingsLock); - - setting = PhpLookupSetting(&name); - - if (setting && setting->Type == IntegerPairSettingType) - { - setting->u.IntegerPair = Value; - } - - PhReleaseQueuedLockExclusive(&PhSettingsLock); - - if (!setting) - PhRaiseStatus(STATUS_NOT_FOUND); -} - -_May_raise_ VOID PhSetScalableIntegerPairSetting( - _In_ PWSTR Name, - _In_ PH_SCALABLE_INTEGER_PAIR Value - ) -{ - PPH_SETTING setting; - PH_STRINGREF name; - - PhInitializeStringRef(&name, Name); - - PhAcquireQueuedLockExclusive(&PhSettingsLock); - - setting = PhpLookupSetting(&name); - - if (setting && setting->Type == ScalableIntegerPairSettingType) - { - PhpFreeSettingValue(ScalableIntegerPairSettingType, setting); - setting->u.Pointer = PhAllocateCopy(&Value, sizeof(PH_SCALABLE_INTEGER_PAIR)); - } - - PhReleaseQueuedLockExclusive(&PhSettingsLock); - - if (!setting) - PhRaiseStatus(STATUS_NOT_FOUND); -} - -_May_raise_ VOID PhSetScalableIntegerPairSetting2( - _In_ PWSTR Name, - _In_ PH_INTEGER_PAIR Value - ) -{ - PH_SCALABLE_INTEGER_PAIR scalableIntegerPair; - - scalableIntegerPair.Pair = Value; - scalableIntegerPair.Scale = PhpGetCurrentScale(); - PhSetScalableIntegerPairSetting(Name, scalableIntegerPair); -} - -_May_raise_ VOID PhSetStringSetting( - _In_ PWSTR Name, - _In_ PWSTR Value - ) -{ - PPH_SETTING setting; - PH_STRINGREF name; - - PhInitializeStringRef(&name, Name); - - PhAcquireQueuedLockExclusive(&PhSettingsLock); - - setting = PhpLookupSetting(&name); - - if (setting && setting->Type == StringSettingType) - { - PhpFreeSettingValue(StringSettingType, setting); - setting->u.Pointer = PhCreateString(Value); - } - - PhReleaseQueuedLockExclusive(&PhSettingsLock); - - if (!setting) - PhRaiseStatus(STATUS_NOT_FOUND); -} - -_May_raise_ VOID PhSetStringSetting2( - _In_ PWSTR Name, - _In_ PPH_STRINGREF Value - ) -{ - PPH_SETTING setting; - PH_STRINGREF name; - - PhInitializeStringRef(&name, Name); - - PhAcquireQueuedLockExclusive(&PhSettingsLock); - - setting = PhpLookupSetting(&name); - - if (setting && setting->Type == StringSettingType) - { - PhpFreeSettingValue(StringSettingType, setting); - setting->u.Pointer = PhCreateString2(Value); - } - - PhReleaseQueuedLockExclusive(&PhSettingsLock); - - if (!setting) - PhRaiseStatus(STATUS_NOT_FOUND); -} - -VOID PhpFreeIgnoredSetting( - _In_ PPH_SETTING Setting - ) -{ - PhFree(Setting->Name.Buffer); - PhDereferenceObject(Setting->u.Pointer); - - PhFree(Setting); -} - -VOID PhpClearIgnoredSettings( - VOID - ) -{ - ULONG i; - - PhAcquireQueuedLockExclusive(&PhSettingsLock); - - for (i = 0; i < PhIgnoredSettings->Count; i++) - { - PhpFreeIgnoredSetting(PhIgnoredSettings->Items[i]); - } - - PhClearList(PhIgnoredSettings); - - PhReleaseQueuedLockExclusive(&PhSettingsLock); -} - -VOID PhClearIgnoredSettings( - VOID - ) -{ - PhpClearIgnoredSettings(); -} - -VOID PhConvertIgnoredSettings( - VOID - ) -{ - ULONG i; - - PhAcquireQueuedLockExclusive(&PhSettingsLock); - - for (i = 0; i < PhIgnoredSettings->Count; i++) - { - PPH_SETTING ignoredSetting = PhIgnoredSettings->Items[i]; - PPH_SETTING setting; - - setting = PhpLookupSetting(&ignoredSetting->Name); - - if (setting) - { - PhpFreeSettingValue(setting->Type, setting); - - if (!PhpSettingFromString( - setting->Type, - &((PPH_STRING)ignoredSetting->u.Pointer)->sr, - ignoredSetting->u.Pointer, - setting - )) - { - PhpSettingFromString( - setting->Type, - &setting->DefaultValue, - NULL, - setting - ); - } - - PhpFreeIgnoredSetting(ignoredSetting); - - PhRemoveItemList(PhIgnoredSettings, i); - i--; - } - } - - PhReleaseQueuedLockExclusive(&PhSettingsLock); -} - -NTSTATUS PhLoadSettings( - _In_ PWSTR FileName - ) -{ - NTSTATUS status; - HANDLE fileHandle; - LARGE_INTEGER fileSize; - mxml_node_t *topNode; - mxml_node_t *currentNode; - - PhpClearIgnoredSettings(); - - status = PhCreateFileWin32( - &fileHandle, - FileName, - FILE_GENERIC_READ, - 0, - FILE_SHARE_READ | FILE_SHARE_DELETE, - FILE_OPEN, - FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT - ); - - if (!NT_SUCCESS(status)) - return status; - - if (NT_SUCCESS(PhGetFileSize(fileHandle, &fileSize)) && fileSize.QuadPart == 0) - { - // A blank file is OK. There are no settings to load. - NtClose(fileHandle); - return status; - } - - topNode = mxmlLoadFd(NULL, fileHandle, MXML_OPAQUE_CALLBACK); - NtClose(fileHandle); - - if (!topNode) - return STATUS_FILE_CORRUPT_ERROR; - - if (topNode->type != MXML_ELEMENT) - { - mxmlDelete(topNode); - return STATUS_FILE_CORRUPT_ERROR; - } - - currentNode = topNode->child; - - while (currentNode) - { - PPH_STRING settingName = NULL; - - if ( - currentNode->type == MXML_ELEMENT && - currentNode->value.element.num_attrs >= 1 && - _stricmp(currentNode->value.element.attrs[0].name, "name") == 0 - ) - { - settingName = PhConvertUtf8ToUtf16(currentNode->value.element.attrs[0].value); - } - - if (settingName) - { - PPH_STRING settingValue; - - settingValue = PhGetOpaqueXmlNodeText(currentNode); - - PhAcquireQueuedLockExclusive(&PhSettingsLock); - - { - PPH_SETTING setting; - - setting = PhpLookupSetting(&settingName->sr); - - if (setting) - { - PhpFreeSettingValue(setting->Type, setting); - - if (!PhpSettingFromString( - setting->Type, - &settingValue->sr, - settingValue, - setting - )) - { - PhpSettingFromString( - setting->Type, - &setting->DefaultValue, - NULL, - setting - ); - } - } - else - { - setting = PhAllocate(sizeof(PH_SETTING)); - setting->Name.Buffer = PhAllocateCopy(settingName->Buffer, settingName->Length + sizeof(WCHAR)); - setting->Name.Length = settingName->Length; - PhReferenceObject(settingValue); - setting->u.Pointer = settingValue; - - PhAddItemList(PhIgnoredSettings, setting); - } - } - - PhReleaseQueuedLockExclusive(&PhSettingsLock); - - PhDereferenceObject(settingValue); - PhDereferenceObject(settingName); - } - - currentNode = currentNode->next; - } - - mxmlDelete(topNode); - - PhUpdateCachedSettings(); - - return STATUS_SUCCESS; -} - -char *PhpSettingsSaveCallback( - _In_ mxml_node_t *node, - _In_ int position - ) -{ - if (PhEqualBytesZ(node->value.element.name, "setting", TRUE)) - { - if (position == MXML_WS_BEFORE_OPEN) - return " "; - else if (position == MXML_WS_AFTER_CLOSE) - return "\r\n"; - } - else if (PhEqualBytesZ(node->value.element.name, "settings", TRUE)) - { - if (position == MXML_WS_AFTER_OPEN) - return "\r\n"; - } - - return NULL; -} - -mxml_node_t *PhpCreateSettingElement( - _Inout_ mxml_node_t *ParentNode, - _In_ PPH_STRINGREF SettingName, - _In_ PPH_STRINGREF SettingValue - ) -{ - mxml_node_t *settingNode; - mxml_node_t *textNode; - PPH_BYTES settingNameUtf8; - PPH_BYTES settingValueUtf8; - - // Create the setting element. - - settingNode = mxmlNewElement(ParentNode, "setting"); - - settingNameUtf8 = PhConvertUtf16ToUtf8Ex(SettingName->Buffer, SettingName->Length); - mxmlElementSetAttr(settingNode, "name", settingNameUtf8->Buffer); - PhDereferenceObject(settingNameUtf8); - - // Set the value. - - settingValueUtf8 = PhConvertUtf16ToUtf8Ex(SettingValue->Buffer, SettingValue->Length); - textNode = mxmlNewOpaque(settingNode, settingValueUtf8->Buffer); - PhDereferenceObject(settingValueUtf8); - - return settingNode; -} - -NTSTATUS PhSaveSettings( - _In_ PWSTR FileName - ) -{ - NTSTATUS status; - HANDLE fileHandle; - mxml_node_t *topNode; - PH_HASHTABLE_ENUM_CONTEXT enumContext; - PPH_SETTING setting; - - topNode = mxmlNewElement(MXML_NO_PARENT, "settings"); - - PhAcquireQueuedLockShared(&PhSettingsLock); - - PhBeginEnumHashtable(PhSettingsHashtable, &enumContext); - - while (setting = PhNextEnumHashtable(&enumContext)) - { - PPH_STRING settingValue; - - settingValue = PhpSettingToString(setting->Type, setting); - PhpCreateSettingElement(topNode, &setting->Name, &settingValue->sr); - PhDereferenceObject(settingValue); - } - - // Write the ignored settings. - { - ULONG i; - - for (i = 0; i < PhIgnoredSettings->Count; i++) - { - PPH_STRING settingValue; - - setting = PhIgnoredSettings->Items[i]; - settingValue = setting->u.Pointer; - PhpCreateSettingElement(topNode, &setting->Name, &settingValue->sr); - } - } - - PhReleaseQueuedLockShared(&PhSettingsLock); - - // Create the directory if it does not exist. - { - PPH_STRING fullPath; - ULONG indexOfFileName; - PPH_STRING directoryName; - - fullPath = PhGetFullPath(FileName, &indexOfFileName); - - if (fullPath) - { - if (indexOfFileName != -1) - { - directoryName = PhSubstring(fullPath, 0, indexOfFileName); - SHCreateDirectoryEx(NULL, directoryName->Buffer, NULL); - PhDereferenceObject(directoryName); - } - - PhDereferenceObject(fullPath); - } - } - - status = PhCreateFileWin32( - &fileHandle, - FileName, - FILE_GENERIC_WRITE, - 0, - FILE_SHARE_READ, - FILE_OVERWRITE_IF, - FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT - ); - - if (!NT_SUCCESS(status)) - { - mxmlDelete(topNode); - return status; - } - - mxmlSaveFd(topNode, fileHandle, PhpSettingsSaveCallback); - mxmlDelete(topNode); - NtClose(fileHandle); - - return STATUS_SUCCESS; -} - -VOID PhResetSettings( - VOID - ) -{ - PH_HASHTABLE_ENUM_CONTEXT enumContext; - PPH_SETTING setting; - - PhAcquireQueuedLockExclusive(&PhSettingsLock); - - PhBeginEnumHashtable(PhSettingsHashtable, &enumContext); - - while (setting = PhNextEnumHashtable(&enumContext)) - { - PhpFreeSettingValue(setting->Type, setting); - PhpSettingFromString(setting->Type, &setting->DefaultValue, NULL, setting); - } - - PhReleaseQueuedLockExclusive(&PhSettingsLock); -} - -VOID PhAddSettings( - _In_ PPH_SETTING_CREATE Settings, - _In_ ULONG NumberOfSettings - ) -{ - ULONG i; - - PhAcquireQueuedLockExclusive(&PhSettingsLock); - - for (i = 0; i < NumberOfSettings; i++) - { - PH_STRINGREF name; - PH_STRINGREF defaultValue; - - PhInitializeStringRefLongHint(&name, Settings[i].Name); - PhInitializeStringRefLongHint(&defaultValue, Settings[i].DefaultValue); - PhpAddSetting(Settings[i].Type, &name, &defaultValue); - } - - PhReleaseQueuedLockExclusive(&PhSettingsLock); -} + #define PH_UPDATE_SETTING(Name) (PhCs##Name = PhGetIntegerSetting(L#Name)) + + PH_UPDATE_SETTING(CollapseServicesOnStart); + PH_UPDATE_SETTING(ForceNoParent); + PH_UPDATE_SETTING(HighlightingDuration); + PH_UPDATE_SETTING(PropagateCpuUsage); + PH_UPDATE_SETTING(ScrollToNewProcesses); + PH_UPDATE_SETTING(ShowCpuBelow001); + PH_UPDATE_SETTING(UpdateInterval); + PH_UPDATE_SETTING(ColorNew); + PH_UPDATE_SETTING(ColorRemoved); + PH_UPDATE_SETTING(UseColorOwnProcesses); + PH_UPDATE_SETTING(ColorOwnProcesses); + PH_UPDATE_SETTING(UseColorSystemProcesses); + PH_UPDATE_SETTING(ColorSystemProcesses); + PH_UPDATE_SETTING(UseColorServiceProcesses); + PH_UPDATE_SETTING(ColorServiceProcesses); + PH_UPDATE_SETTING(UseColorJobProcesses); + PH_UPDATE_SETTING(ColorJobProcesses); + PH_UPDATE_SETTING(UseColorWow64Processes); + PH_UPDATE_SETTING(ColorWow64Processes); + PH_UPDATE_SETTING(UseColorDebuggedProcesses); + PH_UPDATE_SETTING(ColorDebuggedProcesses); + PH_UPDATE_SETTING(UseColorElevatedProcesses); + PH_UPDATE_SETTING(ColorElevatedProcesses); + PH_UPDATE_SETTING(UseColorPicoProcesses); + PH_UPDATE_SETTING(ColorPicoProcesses); + PH_UPDATE_SETTING(UseColorImmersiveProcesses); + PH_UPDATE_SETTING(ColorImmersiveProcesses); + PH_UPDATE_SETTING(UseColorSuspended); + PH_UPDATE_SETTING(ColorSuspended); + PH_UPDATE_SETTING(UseColorDotNet); + PH_UPDATE_SETTING(ColorDotNet); + PH_UPDATE_SETTING(UseColorPacked); + PH_UPDATE_SETTING(ColorPacked); + PH_UPDATE_SETTING(UseColorGuiThreads); + PH_UPDATE_SETTING(ColorGuiThreads); + PH_UPDATE_SETTING(UseColorRelocatedModules); + PH_UPDATE_SETTING(ColorRelocatedModules); + PH_UPDATE_SETTING(UseColorProtectedHandles); + PH_UPDATE_SETTING(ColorProtectedHandles); + PH_UPDATE_SETTING(UseColorInheritHandles); + PH_UPDATE_SETTING(ColorInheritHandles); + PH_UPDATE_SETTING(GraphShowText); + PH_UPDATE_SETTING(GraphColorMode); + PH_UPDATE_SETTING(ColorCpuKernel); + PH_UPDATE_SETTING(ColorCpuUser); + PH_UPDATE_SETTING(ColorIoReadOther); + PH_UPDATE_SETTING(ColorIoWrite); + PH_UPDATE_SETTING(ColorPrivate); + PH_UPDATE_SETTING(ColorPhysical); +} \ No newline at end of file diff --git a/ProcessHacker/srvctl.c b/ProcessHacker/srvctl.c index 72b9066b80ab..a53d1f769498 100644 --- a/ProcessHacker/srvctl.c +++ b/ProcessHacker/srvctl.c @@ -23,6 +23,7 @@ #include #include +#include #include #include diff --git a/ProcessHacker/srvlist.c b/ProcessHacker/srvlist.c index 897399a6bb29..003e86f51e31 100644 --- a/ProcessHacker/srvlist.c +++ b/ProcessHacker/srvlist.c @@ -26,12 +26,13 @@ #include #include #include +#include #include #include #include #include -#include +#include #include BOOLEAN PhpServiceNodeHashtableEqualFunction( diff --git a/ProcessHacker/sysinfo.c b/ProcessHacker/sysinfo.c index e8e389dbce97..317667b112a2 100644 --- a/ProcessHacker/sysinfo.c +++ b/ProcessHacker/sysinfo.c @@ -46,6 +46,7 @@ */ #include +#include #include #include @@ -55,8 +56,8 @@ #include #include +#include #include -#include static HANDLE PhSipThread = NULL; HWND PhSipWindow = NULL; diff --git a/ProcessHacker/syssccpu.c b/ProcessHacker/syssccpu.c index 357159c9f330..b7b82704742f 100644 --- a/ProcessHacker/syssccpu.c +++ b/ProcessHacker/syssccpu.c @@ -21,6 +21,7 @@ */ #include +#include #include #include @@ -28,7 +29,7 @@ #include #include -#include +#include static PPH_SYSINFO_SECTION CpuSection; static HWND CpuDialog; diff --git a/ProcessHacker/sysscio.c b/ProcessHacker/sysscio.c index 2f72b2b37ffa..87626b41a007 100644 --- a/ProcessHacker/sysscio.c +++ b/ProcessHacker/sysscio.c @@ -21,11 +21,12 @@ */ #include +#include #include #include #include -#include +#include static PPH_SYSINFO_SECTION IoSection; static HWND IoDialog; diff --git a/ProcessHacker/sysscmem.c b/ProcessHacker/sysscmem.c index 9d26867685c1..f375ad8fb9d7 100644 --- a/ProcessHacker/sysscmem.c +++ b/ProcessHacker/sysscmem.c @@ -27,9 +27,10 @@ #include #include #include +#include #include -#include +#include static PPH_SYSINFO_SECTION MemorySection; static HWND MemoryDialog; diff --git a/ProcessHacker/thrdlist.c b/ProcessHacker/thrdlist.c index cae5d04594aa..37ad2e9c7698 100644 --- a/ProcessHacker/thrdlist.c +++ b/ProcessHacker/thrdlist.c @@ -24,12 +24,13 @@ #include #include +#include #include #include +#include #include #include -#include #include BOOLEAN PhpThreadNodeHashtableEqualFunction( diff --git a/ProcessHacker/tokprp.c b/ProcessHacker/tokprp.c index 897ba39e005e..88ec93705383 100644 --- a/ProcessHacker/tokprp.c +++ b/ProcessHacker/tokprp.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include diff --git a/plugins/OnlineChecks/virustotal.s b/build/virustotal.s similarity index 100% rename from plugins/OnlineChecks/virustotal.s rename to build/virustotal.s diff --git a/phlib/guisup.c b/phlib/guisup.c index a9e1436ab891..3ae41b72c5a4 100644 --- a/phlib/guisup.c +++ b/phlib/guisup.c @@ -219,132 +219,6 @@ VOID PhSetListViewSubItem( ListView_SetItem(ListViewHandle, &item); } -BOOLEAN PhLoadListViewColumnSettings( - _In_ HWND ListViewHandle, - _In_ PPH_STRING Settings - ) -{ -#define ORDER_LIMIT 50 - PH_STRINGREF remainingPart; - ULONG columnIndex; - ULONG orderArray[ORDER_LIMIT]; // HACK, but reasonable limit - ULONG maxOrder; - ULONG scale; - - if (Settings->Length == 0) - return FALSE; - - remainingPart = Settings->sr; - columnIndex = 0; - memset(orderArray, 0, sizeof(orderArray)); - maxOrder = 0; - - if (remainingPart.Length != 0 && remainingPart.Buffer[0] == '@') - { - PH_STRINGREF scalePart; - ULONG64 integer; - - PhSkipStringRef(&remainingPart, sizeof(WCHAR)); - PhSplitStringRefAtChar(&remainingPart, '|', &scalePart, &remainingPart); - - if (scalePart.Length == 0 || !PhStringToInteger64(&scalePart, 10, &integer)) - return FALSE; - - scale = (ULONG)integer; - } - else - { - scale = PhGlobalDpi; - } - - while (remainingPart.Length != 0) - { - PH_STRINGREF columnPart; - PH_STRINGREF orderPart; - PH_STRINGREF widthPart; - ULONG64 integer; - ULONG order; - ULONG width; - LVCOLUMN lvColumn; - - PhSplitStringRefAtChar(&remainingPart, '|', &columnPart, &remainingPart); - - if (columnPart.Length == 0) - return FALSE; - - PhSplitStringRefAtChar(&columnPart, ',', &orderPart, &widthPart); - - if (orderPart.Length == 0 || widthPart.Length == 0) - return FALSE; - - // Order - - if (!PhStringToInteger64(&orderPart, 10, &integer)) - return FALSE; - - order = (ULONG)integer; - - if (order < ORDER_LIMIT) - { - orderArray[order] = columnIndex; - - if (maxOrder < order + 1) - maxOrder = order + 1; - } - - // Width - - if (!PhStringToInteger64(&widthPart, 10, &integer)) - return FALSE; - - width = (ULONG)integer; - - if (scale != PhGlobalDpi && scale != 0) - width = PhMultiplyDivide(width, PhGlobalDpi, scale); - - lvColumn.mask = LVCF_WIDTH; - lvColumn.cx = width; - ListView_SetColumn(ListViewHandle, columnIndex, &lvColumn); - - columnIndex++; - } - - ListView_SetColumnOrderArray(ListViewHandle, maxOrder, orderArray); - - return TRUE; -} - -PPH_STRING PhSaveListViewColumnSettings( - _In_ HWND ListViewHandle - ) -{ - PH_STRING_BUILDER stringBuilder; - ULONG i = 0; - LVCOLUMN lvColumn; - - PhInitializeStringBuilder(&stringBuilder, 20); - - PhAppendFormatStringBuilder(&stringBuilder, L"@%u|", PhGlobalDpi); - - lvColumn.mask = LVCF_WIDTH | LVCF_ORDER; - - while (ListView_GetColumn(ListViewHandle, i, &lvColumn)) - { - PhAppendFormatStringBuilder( - &stringBuilder, - L"%u,%u|", - lvColumn.iOrder, - lvColumn.cx - ); - i++; - } - - if (stringBuilder.String->Length != 0) - PhRemoveEndStringBuilder(&stringBuilder, 1); - - return PhFinalStringBuilderString(&stringBuilder); -} - INT PhAddTabControlTab( _In_ HWND TabControlHandle, _In_ INT Index, diff --git a/phlib/icotobmp.c b/phlib/icotobmp.c index 9d4ce2878c84..b70d72c5b1af 100644 --- a/phlib/icotobmp.c +++ b/phlib/icotobmp.c @@ -160,10 +160,10 @@ HBITMAP PhIconToBitmap( iconRectangle.right = Width; iconRectangle.bottom = Height; - screenHdc = GetDC(NULL); + screenHdc = CreateIC(L"DISPLAY", NULL, NULL, NULL); hdc = CreateCompatibleDC(screenHdc); bitmap = PhpCreateBitmap32(screenHdc, Width, Height, NULL); - ReleaseDC(NULL, screenHdc); + DeleteDC(screenHdc); oldBitmap = SelectObject(hdc, bitmap); paintParams.dwFlags = BPPF_ERASE; diff --git a/phlib/include/guisup.h b/phlib/include/guisup.h index b1fe736ed688..d825dd31fe48 100644 --- a/phlib/include/guisup.h +++ b/phlib/include/guisup.h @@ -251,17 +251,6 @@ VOID PhSetListViewSubItem( _In_ PWSTR Text ); -PHLIBAPI -BOOLEAN PhLoadListViewColumnSettings( - _In_ HWND ListViewHandle, - _In_ PPH_STRING Settings - ); - -PHLIBAPI -PPH_STRING PhSaveListViewColumnSettings( - _In_ HWND ListViewHandle - ); - PHLIBAPI INT PhAddTabControlTab( _In_ HWND TabControlHandle, diff --git a/ProcessHacker/include/settings.h b/phlib/include/settings.h similarity index 54% rename from ProcessHacker/include/settings.h rename to phlib/include/settings.h index bf0e871bb5c6..5fadd004d4b8 100644 --- a/ProcessHacker/include/settings.h +++ b/phlib/include/settings.h @@ -1,7 +1,27 @@ -#ifndef PH_SETTINGS_H -#define PH_SETTINGS_H +#ifndef PHLIB_SETTINGS_H +#define PHLIB_SETTINGS_H + +#ifdef __cplusplus +extern "C" { +#endif // begin_phapppub + +// These macros make sure the C strings can be seamlessly converted into +// PH_STRINGREFs at compile time, for a small speed boost. + +#define ADD_SETTING_WRAPPER(Type, Name, DefaultValue) \ + { \ + static PH_STRINGREF name = PH_STRINGREF_INIT(Name); \ + static PH_STRINGREF defaultValue = PH_STRINGREF_INIT(DefaultValue); \ + PhAddSetting(Type, &name, &defaultValue); \ + } + +#define PhpAddStringSetting(A, B) ADD_SETTING_WRAPPER(StringSettingType, A, B) +#define PhpAddIntegerSetting(A, B) ADD_SETTING_WRAPPER(IntegerSettingType, A, B) +#define PhpAddIntegerPairSetting(A, B) ADD_SETTING_WRAPPER(IntegerPairSettingType, A, B) +#define PhpAddScalableIntegerPairSetting(A, B) ADD_SETTING_WRAPPER(ScalableIntegerPairSettingType, A, B) + typedef enum _PH_SETTING_TYPE { StringSettingType, @@ -25,17 +45,25 @@ typedef struct _PH_SETTING } u; } PH_SETTING, *PPH_SETTING; -VOID PhSettingsInitialization( +PHLIBAPI +VOID +PhSettingsInitialization( VOID ); +// Note: Program specific function. +VOID PhAddDefaultSettings( + VOID + ); + +// Note: Program specific function. VOID PhUpdateCachedSettings( VOID ); // begin_phapppub _May_raise_ -PHAPPAPI +PHLIBAPI ULONG NTAPI PhGetIntegerSetting( @@ -43,7 +71,7 @@ PhGetIntegerSetting( ); _May_raise_ -PHAPPAPI +PHLIBAPI PH_INTEGER_PAIR NTAPI PhGetIntegerPairSetting( @@ -51,7 +79,7 @@ PhGetIntegerPairSetting( ); _May_raise_ -PHAPPAPI +PHLIBAPI PH_SCALABLE_INTEGER_PAIR NTAPI PhGetScalableIntegerPairSetting( @@ -60,7 +88,7 @@ PhGetScalableIntegerPairSetting( ); _May_raise_ -PHAPPAPI +PHLIBAPI PPH_STRING NTAPI PhGetStringSetting( @@ -68,7 +96,7 @@ PhGetStringSetting( ); _May_raise_ -PHAPPAPI +PHLIBAPI VOID NTAPI PhSetIntegerSetting( @@ -77,7 +105,7 @@ PhSetIntegerSetting( ); _May_raise_ -PHAPPAPI +PHLIBAPI VOID NTAPI PhSetIntegerPairSetting( @@ -86,7 +114,7 @@ PhSetIntegerPairSetting( ); _May_raise_ -PHAPPAPI +PHLIBAPI VOID NTAPI PhSetScalableIntegerPairSetting( @@ -95,7 +123,7 @@ PhSetScalableIntegerPairSetting( ); _May_raise_ -PHAPPAPI +PHLIBAPI VOID NTAPI PhSetScalableIntegerPairSetting2( @@ -104,7 +132,7 @@ PhSetScalableIntegerPairSetting2( ); _May_raise_ -PHAPPAPI +PHLIBAPI VOID NTAPI PhSetStringSetting( @@ -113,7 +141,7 @@ PhSetStringSetting( ); _May_raise_ -PHAPPAPI +PHLIBAPI VOID NTAPI PhSetStringSetting2( @@ -147,6 +175,12 @@ VOID PhResetSettings( // begin_phapppub // High-level settings creation +VOID PhAddSetting( + _In_ PH_SETTING_TYPE Type, + _In_ PPH_STRINGREF Name, + _In_ PPH_STRINGREF DefaultValue + ); + typedef struct _PH_SETTING_CREATE { PH_SETTING_TYPE Type; @@ -154,76 +188,49 @@ typedef struct _PH_SETTING_CREATE PWSTR DefaultValue; } PH_SETTING_CREATE, *PPH_SETTING_CREATE; -PHAPPAPI +PHLIBAPI VOID NTAPI PhAddSettings( _In_ PPH_SETTING_CREATE Settings, _In_ ULONG NumberOfSettings ); -// end_phapppub -// Cached settings +VOID +NTAPI +PhLoadWindowPlacementFromSetting( + _In_opt_ PWSTR PositionSettingName, + _In_opt_ PWSTR SizeSettingName, + _In_ HWND WindowHandle + ); -#undef EXT +VOID +NTAPI +PhSaveWindowPlacementToSetting( + _In_opt_ PWSTR PositionSettingName, + _In_opt_ PWSTR SizeSettingName, + _In_ HWND WindowHandle + ); -#ifdef PH_SETTINGS_PRIVATE -#define EXT -#else -#define EXT extern -#endif +VOID +NTAPI +PhLoadListViewColumnsFromSetting( + _In_ PWSTR Name, + _In_ HWND ListViewHandle + ); -EXT ULONG PhCsCollapseServicesOnStart; -EXT ULONG PhCsForceNoParent; -EXT ULONG PhCsHighlightingDuration; -EXT ULONG PhCsPropagateCpuUsage; -EXT ULONG PhCsScrollToNewProcesses; -EXT ULONG PhCsShowCpuBelow001; -EXT ULONG PhCsUpdateInterval; - -EXT ULONG PhCsColorNew; -EXT ULONG PhCsColorRemoved; -EXT ULONG PhCsUseColorOwnProcesses; -EXT ULONG PhCsColorOwnProcesses; -EXT ULONG PhCsUseColorSystemProcesses; -EXT ULONG PhCsColorSystemProcesses; -EXT ULONG PhCsUseColorServiceProcesses; -EXT ULONG PhCsColorServiceProcesses; -EXT ULONG PhCsUseColorJobProcesses; -EXT ULONG PhCsColorJobProcesses; -EXT ULONG PhCsUseColorWow64Processes; -EXT ULONG PhCsColorWow64Processes; -EXT ULONG PhCsUseColorDebuggedProcesses; -EXT ULONG PhCsColorDebuggedProcesses; -EXT ULONG PhCsUseColorElevatedProcesses; -EXT ULONG PhCsColorElevatedProcesses; -EXT ULONG PhCsUseColorPicoProcesses; -EXT ULONG PhCsColorPicoProcesses; -EXT ULONG PhCsUseColorImmersiveProcesses; -EXT ULONG PhCsColorImmersiveProcesses; -EXT ULONG PhCsUseColorSuspended; -EXT ULONG PhCsColorSuspended; -EXT ULONG PhCsUseColorDotNet; -EXT ULONG PhCsColorDotNet; -EXT ULONG PhCsUseColorPacked; -EXT ULONG PhCsColorPacked; -EXT ULONG PhCsUseColorGuiThreads; -EXT ULONG PhCsColorGuiThreads; -EXT ULONG PhCsUseColorRelocatedModules; -EXT ULONG PhCsColorRelocatedModules; -EXT ULONG PhCsUseColorProtectedHandles; -EXT ULONG PhCsColorProtectedHandles; -EXT ULONG PhCsUseColorInheritHandles; -EXT ULONG PhCsColorInheritHandles; -EXT ULONG PhCsGraphShowText; -EXT ULONG PhCsGraphColorMode; -EXT ULONG PhCsColorCpuKernel; -EXT ULONG PhCsColorCpuUser; -EXT ULONG PhCsColorIoReadOther; -EXT ULONG PhCsColorIoWrite; -EXT ULONG PhCsColorPrivate; -EXT ULONG PhCsColorPhysical; +VOID +NTAPI +PhSaveListViewColumnsToSetting( + _In_ PWSTR Name, + _In_ HWND ListViewHandle + ); +// end_phapppub #define PH_SET_INTEGER_CACHED_SETTING(Name, Value) (PhSetIntegerSetting(L#Name, PhCs##Name = (Value))) +#ifdef __cplusplus +} +#endif + #endif diff --git a/ProcessHacker/mxml/COPYING b/phlib/mxml/COPYING similarity index 100% rename from ProcessHacker/mxml/COPYING rename to phlib/mxml/COPYING diff --git a/ProcessHacker/mxml/config.h b/phlib/mxml/config.h similarity index 100% rename from ProcessHacker/mxml/config.h rename to phlib/mxml/config.h diff --git a/ProcessHacker/mxml/mxml-attr.c b/phlib/mxml/mxml-attr.c similarity index 100% rename from ProcessHacker/mxml/mxml-attr.c rename to phlib/mxml/mxml-attr.c diff --git a/ProcessHacker/mxml/mxml-entity.c b/phlib/mxml/mxml-entity.c similarity index 100% rename from ProcessHacker/mxml/mxml-entity.c rename to phlib/mxml/mxml-entity.c diff --git a/ProcessHacker/mxml/mxml-file.c b/phlib/mxml/mxml-file.c similarity index 100% rename from ProcessHacker/mxml/mxml-file.c rename to phlib/mxml/mxml-file.c diff --git a/ProcessHacker/mxml/mxml-get.c b/phlib/mxml/mxml-get.c similarity index 100% rename from ProcessHacker/mxml/mxml-get.c rename to phlib/mxml/mxml-get.c diff --git a/ProcessHacker/mxml/mxml-index.c b/phlib/mxml/mxml-index.c similarity index 100% rename from ProcessHacker/mxml/mxml-index.c rename to phlib/mxml/mxml-index.c diff --git a/ProcessHacker/mxml/mxml-node.c b/phlib/mxml/mxml-node.c similarity index 100% rename from ProcessHacker/mxml/mxml-node.c rename to phlib/mxml/mxml-node.c diff --git a/ProcessHacker/mxml/mxml-private.c b/phlib/mxml/mxml-private.c similarity index 100% rename from ProcessHacker/mxml/mxml-private.c rename to phlib/mxml/mxml-private.c diff --git a/ProcessHacker/mxml/mxml-private.h b/phlib/mxml/mxml-private.h similarity index 100% rename from ProcessHacker/mxml/mxml-private.h rename to phlib/mxml/mxml-private.h diff --git a/ProcessHacker/mxml/mxml-search.c b/phlib/mxml/mxml-search.c similarity index 100% rename from ProcessHacker/mxml/mxml-search.c rename to phlib/mxml/mxml-search.c diff --git a/ProcessHacker/mxml/mxml-set.c b/phlib/mxml/mxml-set.c similarity index 100% rename from ProcessHacker/mxml/mxml-set.c rename to phlib/mxml/mxml-set.c diff --git a/ProcessHacker/mxml/mxml-string.c b/phlib/mxml/mxml-string.c similarity index 100% rename from ProcessHacker/mxml/mxml-string.c rename to phlib/mxml/mxml-string.c diff --git a/ProcessHacker/mxml/mxml.h b/phlib/mxml/mxml.h similarity index 100% rename from ProcessHacker/mxml/mxml.h rename to phlib/mxml/mxml.h diff --git a/phlib/phlib.vcxproj b/phlib/phlib.vcxproj index aba1e17fe699..f9b2a7f82826 100644 --- a/phlib/phlib.vcxproj +++ b/phlib/phlib.vcxproj @@ -167,12 +167,22 @@ + + + + + + + + + + @@ -208,6 +218,7 @@ + @@ -235,6 +246,9 @@ + + + diff --git a/phlib/phlib.vcxproj.filters b/phlib/phlib.vcxproj.filters index 176452ccb152..e9859bc8d171 100644 --- a/phlib/phlib.vcxproj.filters +++ b/phlib/phlib.vcxproj.filters @@ -140,6 +140,36 @@ Source Files + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + @@ -316,5 +346,17 @@ Header Files + + Header Files + + + Header Files + + + Header Files + + + Header Files + \ No newline at end of file diff --git a/phlib/settings.c b/phlib/settings.c new file mode 100644 index 000000000000..5687b891d26b --- /dev/null +++ b/phlib/settings.c @@ -0,0 +1,1251 @@ +/* + * Process Hacker - + * settings + * + * Copyright (C) 2010-2016 wj32 + * Copyright (C) 2017 dmex + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +/* + * This file contains a program-specific settings system. All possible + * settings are defined at program startup and added to a hashtable. + * The values of these settings can then be read in from a XML file or + * saved to a XML file at any time. Settings which are not recognized + * are added to a list of "ignored settings"; this is necessary to + * support plugin settings, as we don't want their settings to get + * deleted whenever the plugins are disabled. + * + * The get/set functions are very strict. If the wrong function is used + * (the get-integer-setting function is used on a string setting) or + * the setting does not exist, an exception will be raised. + */ + +#include +#include +#include +#include + +#include + +#include "mxml/mxml.h" + +BOOLEAN NTAPI PhpSettingsHashtableEqualFunction( + _In_ PVOID Entry1, + _In_ PVOID Entry2 + ); + +ULONG NTAPI PhpSettingsHashtableHashFunction( + _In_ PVOID Entry + ); + +ULONG PhpGetCurrentScale( + VOID + ); + +PPH_STRING PhpSettingToString( + _In_ PH_SETTING_TYPE Type, + _In_ PPH_SETTING Setting + ); + +BOOLEAN PhpSettingFromString( + _In_ PH_SETTING_TYPE Type, + _In_ PPH_STRINGREF StringRef, + _In_opt_ PPH_STRING String, + _Inout_ PPH_SETTING Setting + ); + +VOID PhpFreeSettingValue( + _In_ PH_SETTING_TYPE Type, + _In_ PPH_SETTING Setting + ); + +PVOID PhpLookupSetting( + _In_ PPH_STRINGREF Name + ); + +PPH_HASHTABLE PhSettingsHashtable; +PH_QUEUED_LOCK PhSettingsLock = PH_QUEUED_LOCK_INIT; +PPH_LIST PhIgnoredSettings; + +VOID PhSettingsInitialization( + VOID + ) +{ + PhSettingsHashtable = PhCreateHashtable( + sizeof(PH_SETTING), + PhpSettingsHashtableEqualFunction, + PhpSettingsHashtableHashFunction, + 256 + ); + PhIgnoredSettings = PhCreateList(4); + + PhAddDefaultSettings(); + PhUpdateCachedSettings(); +} + +BOOLEAN NTAPI PhpSettingsHashtableEqualFunction( + _In_ PVOID Entry1, + _In_ PVOID Entry2 + ) +{ + PPH_SETTING setting1 = (PPH_SETTING)Entry1; + PPH_SETTING setting2 = (PPH_SETTING)Entry2; + + return PhEqualStringRef(&setting1->Name, &setting2->Name, FALSE); +} + +ULONG NTAPI PhpSettingsHashtableHashFunction( + _In_ PVOID Entry + ) +{ + PPH_SETTING setting = (PPH_SETTING)Entry; + + return PhHashBytes((PUCHAR)setting->Name.Buffer, setting->Name.Length); +} + +static ULONG PhpGetCurrentScale( + VOID + ) +{ + static PH_INITONCE initOnce; + static ULONG dpi = 96; + + if (PhBeginInitOnce(&initOnce)) + { + HDC hdc; + + if (hdc = CreateIC(L"DISPLAY", NULL, NULL, NULL)) + { + dpi = GetDeviceCaps(hdc, LOGPIXELSY); + DeleteDC(hdc); + } + + PhEndInitOnce(&initOnce); + } + + return dpi; +} + +static PPH_STRING PhpSettingToString( + _In_ PH_SETTING_TYPE Type, + _In_ PPH_SETTING Setting + ) +{ + switch (Type) + { + case StringSettingType: + { + if (!Setting->u.Pointer) + return PhReferenceEmptyString(); + + PhReferenceObject(Setting->u.Pointer); + + return (PPH_STRING)Setting->u.Pointer; + } + case IntegerSettingType: + { + return PhFormatString(L"%x", Setting->u.Integer); + } + case IntegerPairSettingType: + { + PPH_INTEGER_PAIR integerPair = &Setting->u.IntegerPair; + + return PhFormatString(L"%d,%d", integerPair->X, integerPair->Y); + } + case ScalableIntegerPairSettingType: + { + PPH_SCALABLE_INTEGER_PAIR scalableIntegerPair = Setting->u.Pointer; + + if (!scalableIntegerPair) + return PhReferenceEmptyString(); + + return PhFormatString(L"@%u|%d,%d", scalableIntegerPair->Scale, scalableIntegerPair->X, scalableIntegerPair->Y); + } + } + + return PhReferenceEmptyString(); +} + +static BOOLEAN PhpSettingFromString( + _In_ PH_SETTING_TYPE Type, + _In_ PPH_STRINGREF StringRef, + _In_opt_ PPH_STRING String, + _Inout_ PPH_SETTING Setting + ) +{ + switch (Type) + { + case StringSettingType: + { + if (String) + { + PhSetReference(&Setting->u.Pointer, String); + } + else + { + Setting->u.Pointer = PhCreateString2(StringRef); + } + + return TRUE; + } + case IntegerSettingType: + { + ULONG64 integer; + + if (PhStringToInteger64(StringRef, 16, &integer)) + { + Setting->u.Integer = (ULONG)integer; + return TRUE; + } + else + { + return FALSE; + } + } + case IntegerPairSettingType: + { + LONG64 x; + LONG64 y; + PH_STRINGREF xString; + PH_STRINGREF yString; + + if (!PhSplitStringRefAtChar(StringRef, ',', &xString, &yString)) + return FALSE; + + if (PhStringToInteger64(&xString, 10, &x) && PhStringToInteger64(&yString, 10, &y)) + { + Setting->u.IntegerPair.X = (LONG)x; + Setting->u.IntegerPair.Y = (LONG)y; + return TRUE; + } + else + { + return FALSE; + } + } + case ScalableIntegerPairSettingType: + { + ULONG64 scale; + LONG64 x; + LONG64 y; + PH_STRINGREF stringRef; + PH_STRINGREF firstPart; + PH_STRINGREF secondPart; + PPH_SCALABLE_INTEGER_PAIR scalableIntegerPair; + + stringRef = *StringRef; + + if (stringRef.Length != 0 && stringRef.Buffer[0] == '@') + { + PhSkipStringRef(&stringRef, sizeof(WCHAR)); + + if (!PhSplitStringRefAtChar(&stringRef, '|', &firstPart, &stringRef)) + return FALSE; + if (!PhStringToInteger64(&firstPart, 10, &scale)) + return FALSE; + } + else + { + scale = PhpGetCurrentScale(); + } + + if (!PhSplitStringRefAtChar(&stringRef, ',', &firstPart, &secondPart)) + return FALSE; + + if (PhStringToInteger64(&firstPart, 10, &x) && PhStringToInteger64(&secondPart, 10, &y)) + { + scalableIntegerPair = PhAllocate(sizeof(PH_SCALABLE_INTEGER_PAIR)); + scalableIntegerPair->X = (LONG)x; + scalableIntegerPair->Y = (LONG)y; + scalableIntegerPair->Scale = (ULONG)scale; + Setting->u.Pointer = scalableIntegerPair; + return TRUE; + } + else + { + return FALSE; + } + } + } + + return FALSE; +} + +static VOID PhpFreeSettingValue( + _In_ PH_SETTING_TYPE Type, + _In_ PPH_SETTING Setting + ) +{ + switch (Type) + { + case StringSettingType: + PhClearReference(&Setting->u.Pointer); + break; + case ScalableIntegerPairSettingType: + PhFree(Setting->u.Pointer); + Setting->u.Pointer = NULL; + break; + } +} + +static PVOID PhpLookupSetting( + _In_ PPH_STRINGREF Name + ) +{ + PH_SETTING lookupSetting; + PPH_SETTING setting; + + lookupSetting.Name = *Name; + setting = (PPH_SETTING)PhFindEntryHashtable( + PhSettingsHashtable, + &lookupSetting + ); + + return setting; +} + +_May_raise_ ULONG PhGetIntegerSetting( + _In_ PWSTR Name + ) +{ + PPH_SETTING setting; + PH_STRINGREF name; + ULONG value; + + PhInitializeStringRef(&name, Name); + + PhAcquireQueuedLockShared(&PhSettingsLock); + + setting = PhpLookupSetting(&name); + + if (setting && setting->Type == IntegerSettingType) + { + value = setting->u.Integer; + } + else + { + setting = NULL; + } + + PhReleaseQueuedLockShared(&PhSettingsLock); + + if (!setting) + PhRaiseStatus(STATUS_NOT_FOUND); + + return value; +} + +_May_raise_ PH_INTEGER_PAIR PhGetIntegerPairSetting( + _In_ PWSTR Name + ) +{ + PPH_SETTING setting; + PH_STRINGREF name; + PH_INTEGER_PAIR value; + + PhInitializeStringRef(&name, Name); + + PhAcquireQueuedLockShared(&PhSettingsLock); + + setting = PhpLookupSetting(&name); + + if (setting && setting->Type == IntegerPairSettingType) + { + value = setting->u.IntegerPair; + } + else + { + setting = NULL; + } + + PhReleaseQueuedLockShared(&PhSettingsLock); + + if (!setting) + PhRaiseStatus(STATUS_NOT_FOUND); + + return value; +} + +_May_raise_ PH_SCALABLE_INTEGER_PAIR PhGetScalableIntegerPairSetting( + _In_ PWSTR Name, + _In_ BOOLEAN ScaleToCurrent + ) +{ + PPH_SETTING setting; + PH_STRINGREF name; + PH_SCALABLE_INTEGER_PAIR value; + + PhInitializeStringRef(&name, Name); + + PhAcquireQueuedLockShared(&PhSettingsLock); + + setting = PhpLookupSetting(&name); + + if (setting && setting->Type == ScalableIntegerPairSettingType) + { + value = *(PPH_SCALABLE_INTEGER_PAIR)setting->u.Pointer; + } + else + { + setting = NULL; + } + + PhReleaseQueuedLockShared(&PhSettingsLock); + + if (!setting) + PhRaiseStatus(STATUS_NOT_FOUND); + + if (ScaleToCurrent) + { + ULONG currentScale; + + currentScale = PhpGetCurrentScale(); + + if (value.Scale != currentScale && value.Scale != 0) + { + value.X = PhMultiplyDivideSigned(value.X, currentScale, value.Scale); + value.Y = PhMultiplyDivideSigned(value.Y, currentScale, value.Scale); + value.Scale = currentScale; + } + } + + return value; +} + +_May_raise_ PPH_STRING PhGetStringSetting( + _In_ PWSTR Name + ) +{ + PPH_SETTING setting; + PH_STRINGREF name; + PPH_STRING value; + + PhInitializeStringRef(&name, Name); + + PhAcquireQueuedLockShared(&PhSettingsLock); + + setting = PhpLookupSetting(&name); + + if (setting && setting->Type == StringSettingType) + { + if (setting->u.Pointer) + { + PhSetReference(&value, setting->u.Pointer); + } + else + { + // Set to NULL, create an empty string + // outside of the lock. + value = NULL; + } + } + else + { + setting = NULL; + } + + PhReleaseQueuedLockShared(&PhSettingsLock); + + if (!setting) + PhRaiseStatus(STATUS_NOT_FOUND); + + if (!value) + value = PhReferenceEmptyString(); + + return value; +} + +_May_raise_ VOID PhSetIntegerSetting( + _In_ PWSTR Name, + _In_ ULONG Value + ) +{ + PPH_SETTING setting; + PH_STRINGREF name; + + PhInitializeStringRef(&name, Name); + + PhAcquireQueuedLockExclusive(&PhSettingsLock); + + setting = PhpLookupSetting(&name); + + if (setting && setting->Type == IntegerSettingType) + { + setting->u.Integer = Value; + } + + PhReleaseQueuedLockExclusive(&PhSettingsLock); + + if (!setting) + PhRaiseStatus(STATUS_NOT_FOUND); +} + +_May_raise_ VOID PhSetIntegerPairSetting( + _In_ PWSTR Name, + _In_ PH_INTEGER_PAIR Value + ) +{ + PPH_SETTING setting; + PH_STRINGREF name; + + PhInitializeStringRef(&name, Name); + + PhAcquireQueuedLockExclusive(&PhSettingsLock); + + setting = PhpLookupSetting(&name); + + if (setting && setting->Type == IntegerPairSettingType) + { + setting->u.IntegerPair = Value; + } + + PhReleaseQueuedLockExclusive(&PhSettingsLock); + + if (!setting) + PhRaiseStatus(STATUS_NOT_FOUND); +} + +_May_raise_ VOID PhSetScalableIntegerPairSetting( + _In_ PWSTR Name, + _In_ PH_SCALABLE_INTEGER_PAIR Value + ) +{ + PPH_SETTING setting; + PH_STRINGREF name; + + PhInitializeStringRef(&name, Name); + + PhAcquireQueuedLockExclusive(&PhSettingsLock); + + setting = PhpLookupSetting(&name); + + if (setting && setting->Type == ScalableIntegerPairSettingType) + { + PhpFreeSettingValue(ScalableIntegerPairSettingType, setting); + setting->u.Pointer = PhAllocateCopy(&Value, sizeof(PH_SCALABLE_INTEGER_PAIR)); + } + + PhReleaseQueuedLockExclusive(&PhSettingsLock); + + if (!setting) + PhRaiseStatus(STATUS_NOT_FOUND); +} + +_May_raise_ VOID PhSetScalableIntegerPairSetting2( + _In_ PWSTR Name, + _In_ PH_INTEGER_PAIR Value + ) +{ + PH_SCALABLE_INTEGER_PAIR scalableIntegerPair; + + scalableIntegerPair.Pair = Value; + scalableIntegerPair.Scale = PhpGetCurrentScale(); + PhSetScalableIntegerPairSetting(Name, scalableIntegerPair); +} + +_May_raise_ VOID PhSetStringSetting( + _In_ PWSTR Name, + _In_ PWSTR Value + ) +{ + PPH_SETTING setting; + PH_STRINGREF name; + + PhInitializeStringRef(&name, Name); + + PhAcquireQueuedLockExclusive(&PhSettingsLock); + + setting = PhpLookupSetting(&name); + + if (setting && setting->Type == StringSettingType) + { + PhpFreeSettingValue(StringSettingType, setting); + setting->u.Pointer = PhCreateString(Value); + } + + PhReleaseQueuedLockExclusive(&PhSettingsLock); + + if (!setting) + PhRaiseStatus(STATUS_NOT_FOUND); +} + +_May_raise_ VOID PhSetStringSetting2( + _In_ PWSTR Name, + _In_ PPH_STRINGREF Value + ) +{ + PPH_SETTING setting; + PH_STRINGREF name; + + PhInitializeStringRef(&name, Name); + + PhAcquireQueuedLockExclusive(&PhSettingsLock); + + setting = PhpLookupSetting(&name); + + if (setting && setting->Type == StringSettingType) + { + PhpFreeSettingValue(StringSettingType, setting); + setting->u.Pointer = PhCreateString2(Value); + } + + PhReleaseQueuedLockExclusive(&PhSettingsLock); + + if (!setting) + PhRaiseStatus(STATUS_NOT_FOUND); +} + +VOID PhpFreeIgnoredSetting( + _In_ PPH_SETTING Setting + ) +{ + PhFree(Setting->Name.Buffer); + PhDereferenceObject(Setting->u.Pointer); + + PhFree(Setting); +} + +VOID PhpClearIgnoredSettings( + VOID + ) +{ + ULONG i; + + PhAcquireQueuedLockExclusive(&PhSettingsLock); + + for (i = 0; i < PhIgnoredSettings->Count; i++) + { + PhpFreeIgnoredSetting(PhIgnoredSettings->Items[i]); + } + + PhClearList(PhIgnoredSettings); + + PhReleaseQueuedLockExclusive(&PhSettingsLock); +} + +VOID PhClearIgnoredSettings( + VOID + ) +{ + PhpClearIgnoredSettings(); +} + +VOID PhConvertIgnoredSettings( + VOID + ) +{ + ULONG i; + + PhAcquireQueuedLockExclusive(&PhSettingsLock); + + for (i = 0; i < PhIgnoredSettings->Count; i++) + { + PPH_SETTING ignoredSetting = PhIgnoredSettings->Items[i]; + PPH_SETTING setting; + + setting = PhpLookupSetting(&ignoredSetting->Name); + + if (setting) + { + PhpFreeSettingValue(setting->Type, setting); + + if (!PhpSettingFromString( + setting->Type, + &((PPH_STRING)ignoredSetting->u.Pointer)->sr, + ignoredSetting->u.Pointer, + setting + )) + { + PhpSettingFromString( + setting->Type, + &setting->DefaultValue, + NULL, + setting + ); + } + + PhpFreeIgnoredSetting(ignoredSetting); + + PhRemoveItemList(PhIgnoredSettings, i); + i--; + } + } + + PhReleaseQueuedLockExclusive(&PhSettingsLock); +} + +PPH_STRING PhpGetOpaqueXmlNodeText( + _In_ mxml_node_t *node + ) +{ + if (node->child && node->child->type == MXML_OPAQUE && node->child->value.opaque) + { + return PhConvertUtf8ToUtf16(node->child->value.opaque); + } + else + { + return PhReferenceEmptyString(); + } +} + +NTSTATUS PhLoadSettings( + _In_ PWSTR FileName + ) +{ + NTSTATUS status; + HANDLE fileHandle; + LARGE_INTEGER fileSize; + mxml_node_t *topNode; + mxml_node_t *currentNode; + + PhpClearIgnoredSettings(); + + status = PhCreateFileWin32( + &fileHandle, + FileName, + FILE_GENERIC_READ, + 0, + FILE_SHARE_READ | FILE_SHARE_DELETE, + FILE_OPEN, + FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT + ); + + if (!NT_SUCCESS(status)) + return status; + + if (NT_SUCCESS(PhGetFileSize(fileHandle, &fileSize)) && fileSize.QuadPart == 0) + { + // A blank file is OK. There are no settings to load. + NtClose(fileHandle); + return status; + } + + topNode = mxmlLoadFd(NULL, fileHandle, MXML_OPAQUE_CALLBACK); + NtClose(fileHandle); + + if (!topNode) + return STATUS_FILE_CORRUPT_ERROR; + + if (topNode->type != MXML_ELEMENT) + { + mxmlDelete(topNode); + return STATUS_FILE_CORRUPT_ERROR; + } + + currentNode = topNode->child; + + while (currentNode) + { + PPH_STRING settingName = NULL; + + if ( + currentNode->type == MXML_ELEMENT && + currentNode->value.element.num_attrs >= 1 && + _stricmp(currentNode->value.element.attrs[0].name, "name") == 0 + ) + { + settingName = PhConvertUtf8ToUtf16(currentNode->value.element.attrs[0].value); + } + + if (settingName) + { + PPH_STRING settingValue = 0; + + settingValue = PhpGetOpaqueXmlNodeText(currentNode); + + PhAcquireQueuedLockExclusive(&PhSettingsLock); + + { + PPH_SETTING setting; + + setting = PhpLookupSetting(&settingName->sr); + + if (setting) + { + PhpFreeSettingValue(setting->Type, setting); + + if (!PhpSettingFromString( + setting->Type, + &settingValue->sr, + settingValue, + setting + )) + { + PhpSettingFromString( + setting->Type, + &setting->DefaultValue, + NULL, + setting + ); + } + } + else + { + setting = PhAllocate(sizeof(PH_SETTING)); + setting->Name.Buffer = PhAllocateCopy(settingName->Buffer, settingName->Length + sizeof(WCHAR)); + setting->Name.Length = settingName->Length; + PhReferenceObject(settingValue); + setting->u.Pointer = settingValue; + + PhAddItemList(PhIgnoredSettings, setting); + } + } + + PhReleaseQueuedLockExclusive(&PhSettingsLock); + + PhDereferenceObject(settingValue); + PhDereferenceObject(settingName); + } + + currentNode = currentNode->next; + } + + mxmlDelete(topNode); + + PhUpdateCachedSettings(); + + return STATUS_SUCCESS; +} + +char *PhpSettingsSaveCallback( + _In_ mxml_node_t *node, + _In_ int position + ) +{ + if (PhEqualBytesZ(node->value.element.name, "setting", TRUE)) + { + if (position == MXML_WS_BEFORE_OPEN) + return " "; + else if (position == MXML_WS_AFTER_CLOSE) + return "\r\n"; + } + else if (PhEqualBytesZ(node->value.element.name, "settings", TRUE)) + { + if (position == MXML_WS_AFTER_OPEN) + return "\r\n"; + } + + return NULL; +} + +mxml_node_t *PhpCreateSettingElement( + _Inout_ mxml_node_t *ParentNode, + _In_ PPH_STRINGREF SettingName, + _In_ PPH_STRINGREF SettingValue + ) +{ + mxml_node_t *settingNode; + mxml_node_t *textNode; + PPH_BYTES settingNameUtf8; + PPH_BYTES settingValueUtf8; + + // Create the setting element. + + settingNode = mxmlNewElement(ParentNode, "setting"); + + settingNameUtf8 = PhConvertUtf16ToUtf8Ex(SettingName->Buffer, SettingName->Length); + mxmlElementSetAttr(settingNode, "name", settingNameUtf8->Buffer); + PhDereferenceObject(settingNameUtf8); + + // Set the value. + + settingValueUtf8 = PhConvertUtf16ToUtf8Ex(SettingValue->Buffer, SettingValue->Length); + textNode = mxmlNewOpaque(settingNode, settingValueUtf8->Buffer); + PhDereferenceObject(settingValueUtf8); + + return settingNode; +} + +NTSTATUS PhSaveSettings( + _In_ PWSTR FileName + ) +{ + NTSTATUS status; + HANDLE fileHandle; + mxml_node_t *topNode; + PH_HASHTABLE_ENUM_CONTEXT enumContext; + PPH_SETTING setting; + + topNode = mxmlNewElement(MXML_NO_PARENT, "settings"); + + PhAcquireQueuedLockShared(&PhSettingsLock); + + PhBeginEnumHashtable(PhSettingsHashtable, &enumContext); + + while (setting = PhNextEnumHashtable(&enumContext)) + { + PPH_STRING settingValue; + + settingValue = PhpSettingToString(setting->Type, setting); + PhpCreateSettingElement(topNode, &setting->Name, &settingValue->sr); + PhDereferenceObject(settingValue); + } + + // Write the ignored settings. + { + ULONG i; + + for (i = 0; i < PhIgnoredSettings->Count; i++) + { + PPH_STRING settingValue; + + setting = PhIgnoredSettings->Items[i]; + settingValue = setting->u.Pointer; + PhpCreateSettingElement(topNode, &setting->Name, &settingValue->sr); + } + } + + PhReleaseQueuedLockShared(&PhSettingsLock); + + // Create the directory if it does not exist. + { + PPH_STRING fullPath; + ULONG indexOfFileName; + PPH_STRING directoryName; + + fullPath = PhGetFullPath(FileName, &indexOfFileName); + + if (fullPath) + { + if (indexOfFileName != -1) + { + directoryName = PhSubstring(fullPath, 0, indexOfFileName); + //SHCreateDirectoryEx(NULL, directoryName->Buffer, NULL); + PhDereferenceObject(directoryName); + } + + PhDereferenceObject(fullPath); + } + } + + status = PhCreateFileWin32( + &fileHandle, + FileName, + FILE_GENERIC_WRITE, + 0, + FILE_SHARE_READ, + FILE_OVERWRITE_IF, + FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT + ); + + if (!NT_SUCCESS(status)) + { + mxmlDelete(topNode); + return status; + } + + mxmlSaveFd(topNode, fileHandle, PhpSettingsSaveCallback); + mxmlDelete(topNode); + NtClose(fileHandle); + + return STATUS_SUCCESS; +} + +VOID PhResetSettings( + VOID + ) +{ + PH_HASHTABLE_ENUM_CONTEXT enumContext; + PPH_SETTING setting; + + PhAcquireQueuedLockExclusive(&PhSettingsLock); + + PhBeginEnumHashtable(PhSettingsHashtable, &enumContext); + + while (setting = PhNextEnumHashtable(&enumContext)) + { + PhpFreeSettingValue(setting->Type, setting); + PhpSettingFromString(setting->Type, &setting->DefaultValue, NULL, setting); + } + + PhReleaseQueuedLockExclusive(&PhSettingsLock); +} + +VOID PhAddSetting( + _In_ PH_SETTING_TYPE Type, + _In_ PPH_STRINGREF Name, + _In_ PPH_STRINGREF DefaultValue + ) +{ + PH_SETTING setting; + + setting.Type = Type; + setting.Name = *Name; + setting.DefaultValue = *DefaultValue; + memset(&setting.u, 0, sizeof(setting.u)); + + PhpSettingFromString(Type, &setting.DefaultValue, NULL, &setting); + + PhAddEntryHashtable(PhSettingsHashtable, &setting); +} + +VOID PhAddSettings( + _In_ PPH_SETTING_CREATE Settings, + _In_ ULONG NumberOfSettings + ) +{ + ULONG i; + + PhAcquireQueuedLockExclusive(&PhSettingsLock); + + for (i = 0; i < NumberOfSettings; i++) + { + PH_STRINGREF name; + PH_STRINGREF defaultValue; + + PhInitializeStringRefLongHint(&name, Settings[i].Name); + PhInitializeStringRefLongHint(&defaultValue, Settings[i].DefaultValue); + PhAddSetting(Settings[i].Type, &name, &defaultValue); + } + + PhReleaseQueuedLockExclusive(&PhSettingsLock); +} + +VOID PhLoadWindowPlacementFromSetting( + _In_opt_ PWSTR PositionSettingName, + _In_opt_ PWSTR SizeSettingName, + _In_ HWND WindowHandle + ) +{ + PH_RECTANGLE windowRectangle; + + if (PositionSettingName && SizeSettingName) + { + RECT rectForAdjust; + + windowRectangle.Position = PhGetIntegerPairSetting(PositionSettingName); + windowRectangle.Size = PhGetScalableIntegerPairSetting(SizeSettingName, TRUE).Pair; + PhAdjustRectangleToWorkingArea(NULL, &windowRectangle); + + // Let the window adjust for the minimum size if needed. + rectForAdjust = PhRectangleToRect(windowRectangle); + SendMessage(WindowHandle, WM_SIZING, WMSZ_BOTTOMRIGHT, (LPARAM)&rectForAdjust); + windowRectangle = PhRectToRectangle(rectForAdjust); + + MoveWindow(WindowHandle, windowRectangle.Left, windowRectangle.Top, + windowRectangle.Width, windowRectangle.Height, FALSE); + } + else + { + PH_INTEGER_PAIR position; + PH_INTEGER_PAIR size; + ULONG flags; + + flags = SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOREDRAW | SWP_NOSIZE | SWP_NOZORDER; + + if (PositionSettingName) + { + position = PhGetIntegerPairSetting(PositionSettingName); + flags &= ~SWP_NOMOVE; + } + else + { + position.X = 0; + position.Y = 0; + } + + if (SizeSettingName) + { + size = PhGetScalableIntegerPairSetting(SizeSettingName, TRUE).Pair; + flags &= ~SWP_NOSIZE; + } + else + { + size.X = 16; + size.Y = 16; + } + + SetWindowPos(WindowHandle, NULL, position.X, position.Y, size.X, size.Y, flags); + } +} + +VOID PhSaveWindowPlacementToSetting( + _In_opt_ PWSTR PositionSettingName, + _In_opt_ PWSTR SizeSettingName, + _In_ HWND WindowHandle + ) +{ + WINDOWPLACEMENT placement = { sizeof(placement) }; + PH_RECTANGLE windowRectangle; + MONITORINFO monitorInfo = { sizeof(MONITORINFO) }; + + GetWindowPlacement(WindowHandle, &placement); + windowRectangle = PhRectToRectangle(placement.rcNormalPosition); + + // The rectangle is in workspace coordinates. Convert the values back to screen coordinates. + if (GetMonitorInfo(MonitorFromRect(&placement.rcNormalPosition, MONITOR_DEFAULTTOPRIMARY), &monitorInfo)) + { + windowRectangle.Left += monitorInfo.rcWork.left - monitorInfo.rcMonitor.left; + windowRectangle.Top += monitorInfo.rcWork.top - monitorInfo.rcMonitor.top; + } + + if (PositionSettingName) + PhSetIntegerPairSetting(PositionSettingName, windowRectangle.Position); + if (SizeSettingName) + PhSetScalableIntegerPairSetting2(SizeSettingName, windowRectangle.Size); +} + +BOOLEAN PhLoadListViewColumnSettings( + _In_ HWND ListViewHandle, + _In_ PPH_STRING Settings + ) +{ +#define ORDER_LIMIT 50 + PH_STRINGREF remainingPart; + ULONG columnIndex; + ULONG orderArray[ORDER_LIMIT]; // HACK, but reasonable limit + ULONG maxOrder; + ULONG scale; + + if (Settings->Length == 0) + return FALSE; + + remainingPart = Settings->sr; + columnIndex = 0; + memset(orderArray, 0, sizeof(orderArray)); + maxOrder = 0; + + if (remainingPart.Length != 0 && remainingPart.Buffer[0] == '@') + { + PH_STRINGREF scalePart; + ULONG64 integer; + + PhSkipStringRef(&remainingPart, sizeof(WCHAR)); + PhSplitStringRefAtChar(&remainingPart, '|', &scalePart, &remainingPart); + + if (scalePart.Length == 0 || !PhStringToInteger64(&scalePart, 10, &integer)) + return FALSE; + + scale = (ULONG)integer; + } + else + { + scale = PhGlobalDpi; + } + + while (remainingPart.Length != 0) + { + PH_STRINGREF columnPart; + PH_STRINGREF orderPart; + PH_STRINGREF widthPart; + ULONG64 integer; + ULONG order; + ULONG width; + LVCOLUMN lvColumn; + + PhSplitStringRefAtChar(&remainingPart, '|', &columnPart, &remainingPart); + + if (columnPart.Length == 0) + return FALSE; + + PhSplitStringRefAtChar(&columnPart, ',', &orderPart, &widthPart); + + if (orderPart.Length == 0 || widthPart.Length == 0) + return FALSE; + + // Order + + if (!PhStringToInteger64(&orderPart, 10, &integer)) + return FALSE; + + order = (ULONG)integer; + + if (order < ORDER_LIMIT) + { + orderArray[order] = columnIndex; + + if (maxOrder < order + 1) + maxOrder = order + 1; + } + + // Width + + if (!PhStringToInteger64(&widthPart, 10, &integer)) + return FALSE; + + width = (ULONG)integer; + + if (scale != PhGlobalDpi && scale != 0) + width = PhMultiplyDivide(width, PhGlobalDpi, scale); + + lvColumn.mask = LVCF_WIDTH; + lvColumn.cx = width; + ListView_SetColumn(ListViewHandle, columnIndex, &lvColumn); + + columnIndex++; + } + + ListView_SetColumnOrderArray(ListViewHandle, maxOrder, orderArray); + + return TRUE; +} + +PPH_STRING PhSaveListViewColumnSettings( + _In_ HWND ListViewHandle + ) +{ + PH_STRING_BUILDER stringBuilder; + ULONG i = 0; + LVCOLUMN lvColumn; + + PhInitializeStringBuilder(&stringBuilder, 20); + + PhAppendFormatStringBuilder(&stringBuilder, L"@%u|", PhGlobalDpi); + + lvColumn.mask = LVCF_WIDTH | LVCF_ORDER; + + while (ListView_GetColumn(ListViewHandle, i, &lvColumn)) + { + PhAppendFormatStringBuilder( + &stringBuilder, + L"%u,%u|", + lvColumn.iOrder, + lvColumn.cx + ); + i++; + } + + if (stringBuilder.String->Length != 0) + PhRemoveEndStringBuilder(&stringBuilder, 1); + + return PhFinalStringBuilderString(&stringBuilder); +} + +VOID PhLoadListViewColumnsFromSetting( + _In_ PWSTR Name, + _In_ HWND ListViewHandle + ) +{ + PPH_STRING string; + + string = PhGetStringSetting(Name); + PhLoadListViewColumnSettings(ListViewHandle, string); + PhDereferenceObject(string); +} + +VOID PhSaveListViewColumnsToSetting( + _In_ PWSTR Name, + _In_ HWND ListViewHandle + ) +{ + PPH_STRING string; + + string = PhSaveListViewColumnSettings(ListViewHandle); + PhSetStringSetting2(Name, &string->sr); + PhDereferenceObject(string); +} \ No newline at end of file diff --git a/plugins/DotNetTools/dn.h b/plugins/DotNetTools/dn.h index 72f7e24132f3..95b2a6323cac 100644 --- a/plugins/DotNetTools/dn.h +++ b/plugins/DotNetTools/dn.h @@ -26,6 +26,7 @@ #define CINTERFACE #define COBJMACROS #include +#include #include #include "resource.h" diff --git a/plugins/ExtendedNotifications/filelog.c b/plugins/ExtendedNotifications/filelog.c index 372dc978958b..e1cc06587719 100644 --- a/plugins/ExtendedNotifications/filelog.c +++ b/plugins/ExtendedNotifications/filelog.c @@ -21,6 +21,7 @@ */ #include +#include #include "extnoti.h" VOID NTAPI LoggedCallback( diff --git a/plugins/ExtendedNotifications/main.c b/plugins/ExtendedNotifications/main.c index 293db5c4deab..33abdab44813 100644 --- a/plugins/ExtendedNotifications/main.c +++ b/plugins/ExtendedNotifications/main.c @@ -22,6 +22,7 @@ #include #include +#include #include #include "extnoti.h" #include "resource.h" diff --git a/plugins/ExtendedServices/extsrv.h b/plugins/ExtendedServices/extsrv.h index ff6ee0bd3648..2a15f62d44fe 100644 --- a/plugins/ExtendedServices/extsrv.h +++ b/plugins/ExtendedServices/extsrv.h @@ -2,6 +2,7 @@ #define ES_EXTSRV_H #include +#include #include #include "resource.h" diff --git a/plugins/ExtendedTools/exttools.h b/plugins/ExtendedTools/exttools.h index e76d42f99688..47ddf23fb115 100644 --- a/plugins/ExtendedTools/exttools.h +++ b/plugins/ExtendedTools/exttools.h @@ -2,6 +2,7 @@ #define EXTTOOLS_H #include +#include #include #include diff --git a/plugins/ExtraPlugins/main.h b/plugins/ExtraPlugins/main.h index aaa69f001f96..8bb75a8fb1d5 100644 --- a/plugins/ExtraPlugins/main.h +++ b/plugins/ExtraPlugins/main.h @@ -27,6 +27,7 @@ #define COBJMACROS #include #include +#include #include #include #include diff --git a/plugins/HardwareDevices/devices.h b/plugins/HardwareDevices/devices.h index 466df57edf2a..e6b70f33d775 100644 --- a/plugins/HardwareDevices/devices.h +++ b/plugins/HardwareDevices/devices.h @@ -37,6 +37,7 @@ #define COBJMACROS #include #include +#include #include #include diff --git a/plugins/NetworkTools/nettools.h b/plugins/NetworkTools/nettools.h index 47b8722f86a8..64ff271dc3c5 100644 --- a/plugins/NetworkTools/nettools.h +++ b/plugins/NetworkTools/nettools.h @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include diff --git a/plugins/OnlineChecks/onlnchk.h b/plugins/OnlineChecks/onlnchk.h index 130be7849571..6e57a920a0f6 100644 --- a/plugins/OnlineChecks/onlnchk.h +++ b/plugins/OnlineChecks/onlnchk.h @@ -28,6 +28,7 @@ #define COBJMACROS #include #include +#include #include #include #include diff --git a/plugins/SbieSupport/main.c b/plugins/SbieSupport/main.c index a355a0acfd99..ff84ca975af1 100644 --- a/plugins/SbieSupport/main.c +++ b/plugins/SbieSupport/main.c @@ -21,6 +21,7 @@ */ #include +#include #include "resource.h" #include "sbiedll.h" diff --git a/plugins/ToolStatus/toolstatus.h b/plugins/ToolStatus/toolstatus.h index 0bc63b8f4fd1..04751703fb12 100644 --- a/plugins/ToolStatus/toolstatus.h +++ b/plugins/ToolStatus/toolstatus.h @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include diff --git a/plugins/Updater/updater.h b/plugins/Updater/updater.h index 41899d0c5cbf..a6835fa9268b 100644 --- a/plugins/Updater/updater.h +++ b/plugins/Updater/updater.h @@ -31,6 +31,7 @@ #include #include #include +#include #include #include diff --git a/plugins/UserNotes/usernotes.h b/plugins/UserNotes/usernotes.h index 1d323c874c8a..afe98aa95911 100644 --- a/plugins/UserNotes/usernotes.h +++ b/plugins/UserNotes/usernotes.h @@ -26,6 +26,7 @@ #include #include +#include #include #include diff --git a/plugins/WindowExplorer/wndexp.h b/plugins/WindowExplorer/wndexp.h index 6be77e09186f..dba7a96bc9a2 100644 --- a/plugins/WindowExplorer/wndexp.h +++ b/plugins/WindowExplorer/wndexp.h @@ -3,6 +3,7 @@ #include #include +#include #include "wndtree.h" extern BOOLEAN IsHookClient; diff --git a/tools/CustomBuildTool/Source Files/Build.cs b/tools/CustomBuildTool/Source Files/Build.cs index 26a1dcbd8aad..779095ae0fc3 100644 --- a/tools/CustomBuildTool/Source Files/Build.cs +++ b/tools/CustomBuildTool/Source Files/Build.cs @@ -108,6 +108,7 @@ public static class Build "queuedlock.h", "ref.h", "secedit.h", + "settings.h", "svcsup.h", "symprv.h", "templ.h", @@ -436,14 +437,10 @@ public static bool CopyPluginSdkHeaders() // Copy the plugin SDK headers foreach (string file in phnt_headers) - { File.Copy("phnt\\include\\" + file, "sdk\\include\\" + file, true); - } - foreach (string file in phlib_headers) - { File.Copy("phlib\\include\\" + file, "sdk\\include\\" + file, true); - } + File.Copy("phlib\\mxml\\mxml.h", "sdk\\include\\mxml.h", true); // Copy readme File.Copy("ProcessHacker\\sdk\\readme.txt", "sdk\\readme.txt", true); @@ -482,7 +479,6 @@ public static bool CopyVersionHeader() File.Copy("ProcessHacker\\sdk\\phapppub.h", "sdk\\include\\phapppub.h", true); File.Copy("ProcessHacker\\sdk\\phdk.h", "sdk\\include\\phdk.h", true); - File.Copy("ProcessHacker\\mxml\\mxml.h", "sdk\\include\\mxml.h", true); File.Copy("ProcessHacker\\resource.h", "sdk\\include\\phappresource.h", true); } catch (Exception ex) @@ -680,7 +676,7 @@ public static bool BuildSecureFiles() { Verify.Decrypt("build\\kph.s", "build\\kph.key", kphKey); Verify.Decrypt("build\\nightly.s", "build\\nightly.key", buildKey); - Verify.Decrypt("plugins\\OnlineChecks\\virustotal.s", "plugins\\OnlineChecks\\virustotal.h", vtBuildKey); + Verify.Decrypt("build\\virustotal.s", "build\\virustotal.h", vtBuildKey); } catch (Exception ex) { @@ -723,8 +719,6 @@ public static bool BuildSdkZip() try { - File.Copy("ProcessHacker\\sdk\\readme.txt", "sdk\\readme.txt", true); - Zip.CreateCompressedSdkFromFolder("sdk", BuildOutputFolder + "\\processhacker-build-sdk.zip"); } catch (Exception ex) @@ -810,9 +804,6 @@ public static bool BuildPdbZip() { try { - if (File.Exists(BuildOutputFolder + "\\processhacker-build-pdb.zip")) - File.Delete(BuildOutputFolder + "\\processhacker-build-pdb.zip"); - Zip.CreateCompressedPdbFromFolder(".\\", BuildOutputFolder + "\\processhacker-build-pdb.zip"); } catch (Exception ex) diff --git a/tools/CustomBuildTool/Source Files/HeaderGen.cs b/tools/CustomBuildTool/Source Files/HeaderGen.cs index e4df545defbd..cd4c1dbe70a4 100644 --- a/tools/CustomBuildTool/Source Files/HeaderGen.cs +++ b/tools/CustomBuildTool/Source Files/HeaderGen.cs @@ -50,7 +50,6 @@ public HeaderGen() "extmgr.h", "mainwnd.h", "notifico.h", - "settings.h", "phplug.h", "actions.h", "procprp.h", diff --git a/tools/CustomBuildTool/Source Files/Program.cs b/tools/CustomBuildTool/Source Files/Program.cs index dbf2eeac7091..8245aef57288 100644 --- a/tools/CustomBuildTool/Source Files/Program.cs +++ b/tools/CustomBuildTool/Source Files/Program.cs @@ -14,11 +14,13 @@ public static void Main(string[] args) if (ProgramArgs.ContainsKey("-cleanup")) { + if (Restart("-cleanup")) + return; + if (!Build.InitializeBuildEnvironment(true)) return; Build.CleanupAppxSignature(); - Build.CleanupBuildEnvironment(); Build.ShowBuildStats(true); @@ -283,26 +285,8 @@ public static void Main(string[] args) } else if (ProgramArgs.ContainsKey("-appxmakecert")) { - WindowsIdentity identity = WindowsIdentity.GetCurrent(); - WindowsPrincipal principal = new WindowsPrincipal(identity); - - if (!principal.IsInRole(WindowsBuiltInRole.Administrator)) - { - Win32.ShowWindow(Win32.GetConsoleWindow(), Win32.SW_HIDE); - - try - { - System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo - { - FileName = System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName, - Arguments = "-appxmakecert", - Verb = "runas" - }); - } - catch (Exception) { } - + if (Restart("-appxmakecert")) return; - } if (!Build.InitializeBuildEnvironment(false)) return; @@ -363,6 +347,30 @@ public static void PrintColorMessage(string Message, ConsoleColor Color, bool Ne Console.Write(Message); Console.ResetColor(); } + + private static bool Restart(string Arguments) + { + WindowsIdentity identity = WindowsIdentity.GetCurrent(); + WindowsPrincipal principal = new WindowsPrincipal(identity); + + if (principal.IsInRole(WindowsBuiltInRole.Administrator)) + return false; + + Win32.ShowWindow(Win32.GetConsoleWindow(), Win32.SW_HIDE); + + try + { + System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo + { + FileName = System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName, + Arguments = Arguments, + Verb = "runas" + }); + } + catch (Exception) { } + + return true; + } } [Flags] diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe b/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe index cc4447fd6e5f2b48ee48b907c54786ec1cd927ae..6071333ab93cf8ba6e32052da998c7ef9a4dfe6d 100644 GIT binary patch delta 7604 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 GlfMJd&!Wx% delta 7718 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/j$Ho_mV3I2p>cp202 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 V`#)}|=G3w#>2tTw3$Xe){|_QkKkfhk delta 15004 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 x?`Kap2A+-o`Nd{{aDe8{_~0 diff --git a/tools/peview/include/peview.h b/tools/peview/include/peview.h index bcb62f34d4ce..9de0f19c7411 100644 --- a/tools/peview/include/peview.h +++ b/tools/peview/include/peview.h @@ -5,6 +5,8 @@ #include #include #include +#include + #include "resource.h" extern PPH_STRING PvFileName; @@ -36,4 +38,14 @@ VOID PvHandleListViewNotifyForCopy( _In_ HWND ListViewHandle ); +// settings + +VOID PeInitializeSettings( + VOID + ); + +VOID PeSaveSettings( + VOID + ); + #endif diff --git a/tools/peview/include/prpsh.h b/tools/peview/include/prpsh.h index 4f57f384f7d2..1290e7f63120 100644 --- a/tools/peview/include/prpsh.h +++ b/tools/peview/include/prpsh.h @@ -37,6 +37,7 @@ typedef struct _PV_PROPSHEETCONTEXT typedef struct _PV_PROPCONTEXT { PPH_STRING Title; + PPH_STRING StartPage; PROPSHEETHEADER PropSheetHeader; HPROPSHEETPAGE *PropSheetPages; } PV_PROPCONTEXT, *PPV_PROPCONTEXT; diff --git a/tools/peview/main.c b/tools/peview/main.c index d3e580a7ec82..5b223fde2635 100644 --- a/tools/peview/main.c +++ b/tools/peview/main.c @@ -46,7 +46,7 @@ static VOID PvpInitializeDpi( if (hdc = CreateIC(L"DISPLAY", NULL, NULL, NULL)) { PhGlobalDpi = GetDeviceCaps(hdc, LOGPIXELSY); - ReleaseDC(NULL, hdc); + DeleteDC(hdc); } } @@ -68,6 +68,8 @@ INT WINAPI wWinMain( PhGuiSupportInitialization(); PvpInitializeDpi(); + PhSettingsInitialization(); + PeInitializeSettings(); PvPropInitialization(); PhApplicationName = L"PE Viewer"; @@ -124,5 +126,7 @@ INT WINAPI wWinMain( else PvLibProperties(); + PeSaveSettings(); + return 0; } diff --git a/tools/peview/peprp.c b/tools/peview/peprp.c index 5d7b9fc84053..26d6bb7606ec 100644 --- a/tools/peview/peprp.c +++ b/tools/peview/peprp.c @@ -344,8 +344,6 @@ INT_PTR CALLBACK PvpPeGeneralDlgProc( PWSTR type; PH_STRING_BUILDER stringBuilder; - PhCenterWindow(GetParent(hwndDlg), NULL); - // File version information { @@ -755,6 +753,7 @@ INT_PTR CALLBACK PvpPeImportsDlgProc( PhAddListViewColumn(lvHandle, 2, 2, 2, LVCFMT_LEFT, 50, L"Hint"); PhSetExtendedListView(lvHandle); ExtendedListView_AddFallbackColumns(lvHandle, 3, fallbackColumns); + PhLoadListViewColumnsFromSetting(L"ImageImportsListViewColumns", lvHandle); if (NT_SUCCESS(PhGetMappedImageImports(&imports, &PvMappedImage))) { @@ -771,6 +770,11 @@ INT_PTR CALLBACK PvpPeImportsDlgProc( EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); } break; + case WM_DESTROY: + { + PhSaveListViewColumnsToSetting(L"ImageImportsListViewColumns", GetDlgItem(hwndDlg, IDC_LIST)); + } + break; case WM_SHOWWINDOW: { if (!propPageContext->LayoutInitialized) @@ -824,10 +828,12 @@ INT_PTR CALLBACK PvpPeExportsDlgProc( lvHandle = GetDlgItem(hwndDlg, IDC_LIST); PhSetListViewStyle(lvHandle, FALSE, TRUE); PhSetControlTheme(lvHandle, L"explorer"); - PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 220, L"Name"); - PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 50, L"Ordinal"); - PhAddListViewColumn(lvHandle, 2, 2, 2, LVCFMT_LEFT, 120, L"RVA"); + PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 40, L"#"); + PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_RIGHT, 80, L"RVA"); + PhAddListViewColumn(lvHandle, 2, 2, 2, LVCFMT_LEFT, 250, L"Name"); + PhAddListViewColumn(lvHandle, 3, 3, 3, LVCFMT_LEFT, 50, L"Ordinal"); PhSetExtendedListView(lvHandle); + PhLoadListViewColumnsFromSetting(L"ImageExportsListViewColumns", lvHandle); if (NT_SUCCESS(PhGetMappedImageExports(&exports, &PvMappedImage))) { @@ -849,31 +855,34 @@ INT_PTR CALLBACK PvpPeExportsDlgProc( if (!exportFunction.Function) continue; - if (exportEntry.Name) + PhPrintUInt64(number, i + 1); + lvItemIndex = PhAddListViewItem(lvHandle, MAXINT, number, NULL); + + if (exportFunction.ForwardedName) { - name = PhZeroExtendToUtf16(exportEntry.Name); - lvItemIndex = PhAddListViewItem(lvHandle, MAXINT, name->Buffer, NULL); + name = PhZeroExtendToUtf16(exportFunction.ForwardedName); + PhSetListViewSubItem(lvHandle, lvItemIndex, 1, name->Buffer); PhDereferenceObject(name); } else { - lvItemIndex = PhAddListViewItem(lvHandle, MAXINT, L"(unnamed)", NULL); + PhPrintPointer(pointer, exportFunction.Function); + PhSetListViewSubItem(lvHandle, lvItemIndex, 1, pointer); } - PhPrintUInt32(number, exportEntry.Ordinal); - PhSetListViewSubItem(lvHandle, lvItemIndex, 1, number); - - if (exportFunction.ForwardedName) + if (exportEntry.Name) { - name = PhZeroExtendToUtf16(exportFunction.ForwardedName); + name = PhZeroExtendToUtf16(exportEntry.Name); PhSetListViewSubItem(lvHandle, lvItemIndex, 2, name->Buffer); PhDereferenceObject(name); } else { - PhPrintPointer(pointer, exportFunction.Function); - PhSetListViewSubItem(lvHandle, lvItemIndex, 2, pointer); + PhSetListViewSubItem(lvHandle, lvItemIndex, 2, L"(unnamed)"); } + + PhPrintUInt32(number, exportEntry.Ordinal); + PhSetListViewSubItem(lvHandle, lvItemIndex, 3, number); } } } @@ -883,6 +892,11 @@ INT_PTR CALLBACK PvpPeExportsDlgProc( EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); } break; + case WM_DESTROY: + { + PhSaveListViewColumnsToSetting(L"ImageExportsListViewColumns", GetDlgItem(hwndDlg, IDC_LIST)); + } + break; case WM_SHOWWINDOW: { if (!propPageContext->LayoutInitialized) @@ -936,6 +950,8 @@ INT_PTR CALLBACK PvpPeLoadConfigDlgProc( PhSetControlTheme(lvHandle, L"explorer"); PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 220, L"Name"); PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 170, L"Value"); + PhSetExtendedListView(lvHandle); + PhLoadListViewColumnsFromSetting(L"ImageLoadCfgListViewColumns", lvHandle); #define ADD_VALUE(Name, Value) \ { \ @@ -1012,6 +1028,11 @@ INT_PTR CALLBACK PvpPeLoadConfigDlgProc( EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); } break; + case WM_DESTROY: + { + PhSaveListViewColumnsToSetting(L"ImageLoadCfgListViewColumns", GetDlgItem(hwndDlg, IDC_LIST)); + } + break; case WM_SHOWWINDOW: { if (!propPageContext->LayoutInitialized) @@ -1148,6 +1169,7 @@ INT_PTR CALLBACK PvpPeCgfDlgProc( PhAddListViewColumn(lvHandle, 2, 2, 2, LVCFMT_LEFT, 250, L"Name"); PhAddListViewColumn(lvHandle, 3, 3, 3, LVCFMT_LEFT, 100, L"Flags"); PhSetExtendedListView(lvHandle); + PhLoadListViewColumnsFromSetting(L"ImageCfgListViewColumns", lvHandle); // Init symbol resolver if (PvpLoadDbgHelp(&symbolProvider)) @@ -1247,6 +1269,11 @@ INT_PTR CALLBACK PvpPeCgfDlgProc( EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); } break; + case WM_DESTROY: + { + PhSaveListViewColumnsToSetting(L"ImageCfgListViewColumns", GetDlgItem(hwndDlg, IDC_LIST)); + } + break; case WM_SHOWWINDOW: { if (!propPageContext->LayoutInitialized) diff --git a/tools/peview/peview.vcxproj b/tools/peview/peview.vcxproj index 29c125003e18..e37234a5e523 100644 --- a/tools/peview/peview.vcxproj +++ b/tools/peview/peview.vcxproj @@ -196,6 +196,7 @@ + diff --git a/tools/peview/peview.vcxproj.filters b/tools/peview/peview.vcxproj.filters index ff1f55b4ac2f..4abd9aaa1ebb 100644 --- a/tools/peview/peview.vcxproj.filters +++ b/tools/peview/peview.vcxproj.filters @@ -30,6 +30,9 @@ Source Files + + Source Files + diff --git a/tools/peview/prpsh.c b/tools/peview/prpsh.c index e6ac16b05e8e..717f1d1f4222 100644 --- a/tools/peview/prpsh.c +++ b/tools/peview/prpsh.c @@ -23,6 +23,7 @@ // NOTE: Copied from processhacker2\ProcessHacker\procprp.c #include +#include PPH_OBJECT_TYPE PvpPropContextType; PPH_OBJECT_TYPE PvpPropPageContextType; @@ -80,6 +81,7 @@ PPV_PROPCONTEXT PvCreatePropContext( memset(propContext, 0, sizeof(PV_PROPCONTEXT)); propContext->Title = Caption; + propContext->StartPage = PhGetStringSetting(L"MainWindowPage"); propContext->PropSheetPages = PhAllocate(sizeof(HPROPSHEETPAGE) * PV_PROPCONTEXT_MAXPAGES); memset(&propSheetHeader, 0, sizeof(PROPSHEETHEADER)); @@ -97,6 +99,9 @@ PPV_PROPCONTEXT PvCreatePropContext( propSheetHeader.nStartPage = 0; propSheetHeader.phpage = propContext->PropSheetPages; + propSheetHeader.dwFlags |= PSH_USEPSTARTPAGE; + propSheetHeader.pStartPage = propContext->StartPage->Buffer; + memcpy(&propContext->PropSheetHeader, &propSheetHeader, sizeof(PROPSHEETHEADER)); return propContext; @@ -110,7 +115,9 @@ VOID NTAPI PvpPropContextDeleteProcedure( PPV_PROPCONTEXT propContext = (PPV_PROPCONTEXT)Object; PhFree(propContext->PropSheetPages); + PhDereferenceObject(propContext->Title); + PhDereferenceObject(propContext->StartPage); } INT CALLBACK PvpPropSheetProc( @@ -189,6 +196,30 @@ LRESULT CALLBACK PvpPropSheetWndProc( switch (uMsg) { + case WM_DESTROY: + { + HWND tabControl; + TCITEM tabItem; + WCHAR text[128]; + + // Save the window position and size. + + PhSaveWindowPlacementToSetting(L"MainWindowPosition", L"MainWindowSize", hWnd); + + // Save the selected tab. + + tabControl = PropSheet_GetTabControl(hWnd); + + tabItem.mask = TCIF_TEXT; + tabItem.pszText = text; + tabItem.cchTextMax = sizeof(text) / 2 - 1; + + if (TabCtrl_GetItem(tabControl, TabCtrl_GetCurSel(tabControl), &tabItem)) + { + PhSetStringSetting(L"MainWindowPage", text); + } + } + break; case WM_NCDESTROY: { RemoveWindowSubclass(hWnd, PvpPropSheetWndProc, uIdSubclass); @@ -262,6 +293,32 @@ BOOLEAN PhpInitializePropSheetLayoutStage1( return FALSE; } +VOID PhpInitializePropSheetLayoutStage2( + _In_ HWND hwnd + ) +{ + PH_RECTANGLE windowRectangle; + + windowRectangle.Position = PhGetIntegerPairSetting(L"MainWindowPosition"); + windowRectangle.Size = PhGetScalableIntegerPairSetting(L"MainWindowSize", TRUE).Pair; + + if (windowRectangle.Size.X < MinimumSize.right) + windowRectangle.Size.X = MinimumSize.right; + if (windowRectangle.Size.Y < MinimumSize.bottom) + windowRectangle.Size.Y = MinimumSize.bottom; + + PhAdjustRectangleToWorkingArea(NULL, &windowRectangle); + + MoveWindow(hwnd, windowRectangle.Left, windowRectangle.Top, + windowRectangle.Width, windowRectangle.Height, FALSE); + + // Implement cascading by saving an offsetted rectangle. + windowRectangle.Left += 20; + windowRectangle.Top += 20; + + PhSetIntegerPairSetting(L"MainWindowPosition", windowRectangle.Position); +} + BOOLEAN PvAddPropPage( _Inout_ PPV_PROPCONTEXT PropContext, _In_ _Assume_refs_(1) PPV_PROPPAGECONTEXT PropPageContext @@ -378,13 +435,14 @@ PPH_LAYOUT_ITEM PvAddPropPageLayoutItem( PPV_PROPSHEETCONTEXT propSheetContext; PPH_LAYOUT_MANAGER layoutManager; PPH_LAYOUT_ITEM realParentItem; + BOOLEAN doLayoutStage2; PPH_LAYOUT_ITEM item; parent = GetParent(hwnd); propSheetContext = PvpGetPropSheetContext(parent); layoutManager = &propSheetContext->LayoutManager; - PhpInitializePropSheetLayoutStage1(propSheetContext, parent); + doLayoutStage2 = PhpInitializePropSheetLayoutStage1(propSheetContext, parent); if (ParentItem != PH_PROP_PAGE_TAB_CONTROL_PARENT) realParentItem = ParentItem; @@ -424,6 +482,9 @@ PPH_LAYOUT_ITEM PvAddPropPageLayoutItem( item = PhAddLayoutItem(layoutManager, Handle, realParentItem, Anchor); } + if (doLayoutStage2) + PhpInitializePropSheetLayoutStage2(parent); + return item; } diff --git a/tools/peview/settings.c b/tools/peview/settings.c new file mode 100644 index 000000000000..4470b16fea46 --- /dev/null +++ b/tools/peview/settings.c @@ -0,0 +1,141 @@ +/* + * PE viewer - + * program settings + * + * Copyright (C) 2017 dmex + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include +#include + +static PPH_STRING PeSettingsFileName = NULL; + +VOID PhAddDefaultSettings( + VOID + ) +{ + PhpAddIntegerSetting(L"FirstRun", L"1"); + PhpAddStringSetting(L"Font", L""); // null + PhpAddIntegerSetting(L"MaxSizeUnit", L"6"); + PhpAddStringSetting(L"MainWindowPage", L"General"); + PhpAddIntegerPairSetting(L"MainWindowPosition", L"150,150"); + PhpAddScalableIntegerPairSetting(L"MainWindowSize", L"@96|550,580"); + PhpAddStringSetting(L"ImageCfgListViewColumns", L""); + PhpAddStringSetting(L"ImageExportsListViewColumns", L""); + PhpAddStringSetting(L"ImageImportsListViewColumns", L""); + PhpAddStringSetting(L"ImageLoadCfgListViewColumns", L""); +} + +VOID PhUpdateCachedSettings( + VOID + ) +{ + NOTHING; +} + +VOID PeInitializeSettings( + VOID + ) +{ + static PH_STRINGREF settingsSuffix = PH_STRINGREF_INIT(L".peview.xml"); + NTSTATUS status; + PPH_STRING appFileName; + PPH_STRING tempFileName; + + // There are three possible locations for the settings file: + // 1. A file named peview.exe.peview.xml in the program directory. (This changes + // based on the executable file name.) + // 2. The default location. + + // 1. File in program directory + + appFileName = PhGetApplicationFileName(); + tempFileName = PhConcatStringRef2(&appFileName->sr, &settingsSuffix); + PhDereferenceObject(appFileName); + + if (RtlDoesFileExists_U(tempFileName->Buffer)) + { + PeSettingsFileName = tempFileName; + } + else + { + PhDereferenceObject(tempFileName); + } + + // 2. Default location + if (!PeSettingsFileName) + { + PeSettingsFileName = PhGetKnownLocation(CSIDL_APPDATA, L"\\Process Hacker\\peview.xml"); + } + + if (PeSettingsFileName) + { + status = PhLoadSettings(PeSettingsFileName->Buffer); + + // If we didn't find the file, it will be created. Otherwise, + // there was probably a parsing error and we don't want to + // change anything. + if (status == STATUS_FILE_CORRUPT_ERROR) + { + if (PhShowMessage( + NULL, + MB_ICONWARNING | MB_YESNO, + L"PE View's settings file is corrupt. Do you want to reset it?\n" + L"If you select No, the settings system will not function properly." + ) == IDYES) + { + HANDLE fileHandle; + IO_STATUS_BLOCK isb; + CHAR data[] = ""; + + // This used to delete the file. But it's better to keep the file there + // and overwrite it with some valid XML, especially with case (2) above. + if (NT_SUCCESS(PhCreateFileWin32( + &fileHandle, + PeSettingsFileName->Buffer, + FILE_GENERIC_WRITE, + 0, + FILE_SHARE_READ | FILE_SHARE_DELETE, + FILE_OVERWRITE, + FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT + ))) + { + NtWriteFile(fileHandle, NULL, NULL, NULL, &isb, data, sizeof(data) - 1, NULL, NULL); + NtClose(fileHandle); + } + } + else + { + // Pretend we don't have a settings store so bad things don't happen. + PhDereferenceObject(PeSettingsFileName); + PeSettingsFileName = NULL; + } + } + } + + // Apply basic global settings. + PhMaxSizeUnit = PhGetIntegerSetting(L"MaxSizeUnit"); +} + +VOID PeSaveSettings( + VOID + ) +{ + if (PeSettingsFileName) + PhSaveSettings(PeSettingsFileName->Buffer); +} From 1aa9b357ee06454687a3e907895eb9da9d1102d2 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 8 May 2017 01:32:43 +1000 Subject: [PATCH 0065/2058] phlib: Fix solution filters --- phlib/phlib.vcxproj.filters | 42 +++++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/phlib/phlib.vcxproj.filters b/phlib/phlib.vcxproj.filters index e9859bc8d171..aef40882c991 100644 --- a/phlib/phlib.vcxproj.filters +++ b/phlib/phlib.vcxproj.filters @@ -9,6 +9,12 @@ {93995380-89BD-4b04-88EB-625FBE52EBFB} h;hpp;hxx;hm;inl;inc;xsd + + {7d0c2da2-811d-4844-9704-0c87067c7be1} + + + {874b89c3-fb60-46f3-a62c-49ac88e3026d} + @@ -140,35 +146,35 @@ Source Files - + Source Files + + Mini-XML + - Source Files + Mini-XML - Source Files + Mini-XML - Source Files + Mini-XML - Source Files + Mini-XML - Source Files + Mini-XML - Source Files + Mini-XML - Source Files + Mini-XML - Source Files - - - Source Files + Mini-XML @@ -346,17 +352,17 @@ Header Files - + Header Files - - Header Files + + Mini-XML\Headers - Header Files + Mini-XML\Headers - - Header Files + + Mini-XML\Headers \ No newline at end of file From b7dba3db05ab83b35aa3160a0a1c2cd779aa5889 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 8 May 2017 03:05:31 +1000 Subject: [PATCH 0066/2058] peview: Fix lib support (some lib files were not showing exported object data) --- phlib/maplib.c | 2 -- tools/peview/main.c | 6 +++--- tools/peview/peprp.c | 6 +++--- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/phlib/maplib.c b/phlib/maplib.c index 41b80cdfbafc..4600b375909f 100644 --- a/phlib/maplib.c +++ b/phlib/maplib.c @@ -371,8 +371,6 @@ NTSTATUS PhGetMappedArchiveImportEntry( importHeader = (IMPORT_OBJECT_HEADER *)Member->Data; - if (Member->Type != NormalArchiveMemberType) - return STATUS_INVALID_PARAMETER; if ( importHeader->Sig1 != IMAGE_FILE_MACHINE_UNKNOWN || importHeader->Sig2 != IMPORT_OBJECT_HDR_SIG2 diff --git a/tools/peview/main.c b/tools/peview/main.c index 5b223fde2635..893e7ee0cb48 100644 --- a/tools/peview/main.c +++ b/tools/peview/main.c @@ -121,10 +121,10 @@ INT WINAPI wWinMain( PhMoveReference(&PvFileName, targetFileName); } - if (!PhEndsWithString2(PvFileName, L".lib", TRUE)) - PvPeProperties(); - else + if (PhEndsWithString2(PvFileName, L".lib", TRUE)) PvLibProperties(); + else + PvPeProperties(); PeSaveSettings(); diff --git a/tools/peview/peprp.c b/tools/peview/peprp.c index 26d6bb7606ec..38947aaf0420 100644 --- a/tools/peview/peprp.c +++ b/tools/peview/peprp.c @@ -695,10 +695,10 @@ VOID PvpProcessImports( PPH_STRING name; WCHAR number[PH_INT32_STR_LEN_1]; - if (!DelayImports) - name = PhZeroExtendToUtf16(importDll.Name); - else + if (DelayImports) name = PhFormatString(L"%S (Delay)", importDll.Name); + else + name = PhZeroExtendToUtf16(importDll.Name); lvItemIndex = PhAddListViewItem(ListViewHandle, MAXINT, name->Buffer, NULL); PhDereferenceObject(name); From 6e91ac11bc2c6fec05b102b17637736cf9f66171 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 8 May 2017 07:28:25 +1000 Subject: [PATCH 0067/2058] SbieSupport: Move to plugins-extras --- plugins/Plugins.sln | 12 +- plugins/SbieSupport/SbieSupport.rc | 146 ----- plugins/SbieSupport/SbieSupport.vcxproj | 65 -- .../SbieSupport/SbieSupport.vcxproj.filters | 35 -- plugins/SbieSupport/main.c | 556 ------------------ plugins/SbieSupport/resource.h | 18 - plugins/SbieSupport/sbiedll.h | 42 -- 7 files changed, 1 insertion(+), 873 deletions(-) delete mode 100644 plugins/SbieSupport/SbieSupport.rc delete mode 100644 plugins/SbieSupport/SbieSupport.vcxproj delete mode 100644 plugins/SbieSupport/SbieSupport.vcxproj.filters delete mode 100644 plugins/SbieSupport/main.c delete mode 100644 plugins/SbieSupport/resource.h delete mode 100644 plugins/SbieSupport/sbiedll.h diff --git a/plugins/Plugins.sln b/plugins/Plugins.sln index ae4f9f9a95bd..15c2c8271d2b 100644 --- a/plugins/Plugins.sln +++ b/plugins/Plugins.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 -VisualStudioVersion = 15.0.26228.4 +VisualStudioVersion = 15.0.26403.7 MinimumVisualStudioVersion = 15.0.26228.4 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{53C3AE07-D96F-4F5C-B407-4195084472CF}" ProjectSection(SolutionItems) = preProject @@ -10,8 +10,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution include\toolstatusintf.h = include\toolstatusintf.h EndProjectSection EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SbieSupport", "SbieSupport\SbieSupport.vcxproj", "{EEF1E81D-D286-422A-89E6-C6C8F3BE648A}" -EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ExtendedNotifications", "ExtendedNotifications\ExtendedNotifications.vcxproj", "{80E791B8-AC98-407E-8FF9-5154AF50E887}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ToolStatus", "ToolStatus\ToolStatus.vcxproj", "{60B43533-C75E-4741-9E19-C4D581BEF51C}" @@ -46,14 +44,6 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {EEF1E81D-D286-422A-89E6-C6C8F3BE648A}.Debug|Win32.ActiveCfg = Debug|Win32 - {EEF1E81D-D286-422A-89E6-C6C8F3BE648A}.Debug|Win32.Build.0 = Debug|Win32 - {EEF1E81D-D286-422A-89E6-C6C8F3BE648A}.Debug|x64.ActiveCfg = Debug|x64 - {EEF1E81D-D286-422A-89E6-C6C8F3BE648A}.Debug|x64.Build.0 = Debug|x64 - {EEF1E81D-D286-422A-89E6-C6C8F3BE648A}.Release|Win32.ActiveCfg = Release|Win32 - {EEF1E81D-D286-422A-89E6-C6C8F3BE648A}.Release|Win32.Build.0 = Release|Win32 - {EEF1E81D-D286-422A-89E6-C6C8F3BE648A}.Release|x64.ActiveCfg = Release|x64 - {EEF1E81D-D286-422A-89E6-C6C8F3BE648A}.Release|x64.Build.0 = Release|x64 {80E791B8-AC98-407E-8FF9-5154AF50E887}.Debug|Win32.ActiveCfg = Debug|Win32 {80E791B8-AC98-407E-8FF9-5154AF50E887}.Debug|Win32.Build.0 = Debug|Win32 {80E791B8-AC98-407E-8FF9-5154AF50E887}.Debug|x64.ActiveCfg = Debug|x64 diff --git a/plugins/SbieSupport/SbieSupport.rc b/plugins/SbieSupport/SbieSupport.rc deleted file mode 100644 index 82c4ae0686ab..000000000000 --- a/plugins/SbieSupport/SbieSupport.rc +++ /dev/null @@ -1,146 +0,0 @@ -// Microsoft Visual C++ generated resource script. -// -#include "resource.h" - -#define APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// -#include "winres.h" -///////////////////////////////////////////////////////////////////////////// -#undef APSTUDIO_READONLY_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -// English (Australia) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENA) -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_AUS -#pragma code_page(1252) - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -1 TEXTINCLUDE -BEGIN - "resource.h\0" -END - -2 TEXTINCLUDE -BEGIN - "#include ""winres.h""\0" -END - -3 TEXTINCLUDE -BEGIN - "\r\n" - "\0" -END - -#endif // APSTUDIO_INVOKED - - -///////////////////////////////////////////////////////////////////////////// -// -// Version -// - -VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,0,0,0 - PRODUCTVERSION 1,0,0,0 - FILEFLAGSMASK 0x3fL -#ifdef _DEBUG - FILEFLAGS 0x1L -#else - FILEFLAGS 0x0L -#endif - FILEOS 0x40004L - FILETYPE 0x2L - FILESUBTYPE 0x0L -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "0c0904b0" - BEGIN - VALUE "CompanyName", "wj32" - VALUE "FileDescription", "Sandboxie Support for Process Hacker" - VALUE "FileVersion", "1.0" - VALUE "InternalName", "ProcessHacker.SbieSupport" - VALUE "LegalCopyright", "Licensed under the GNU GPL, v3." - VALUE "OriginalFilename", "SbieSupport.dll" - VALUE "ProductName", "Sandboxie Support for Process Hacker" - VALUE "ProductVersion", "1.0" - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0xc09, 1200 - END -END - - -///////////////////////////////////////////////////////////////////////////// -// -// Dialog -// - -IDD_OPTIONS DIALOGEX 0, 0, 268, 50 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Options" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "SbieDll.dll path:",IDC_STATIC,7,9,50,8 - EDITTEXT IDC_SBIEDLLPATH,63,8,143,12,ES_AUTOHSCROLL - PUSHBUTTON "Browse...",IDC_BROWSE,211,7,50,14 - PUSHBUTTON "OK",IDOK,158,29,50,14 - PUSHBUTTON "Cancel",IDCANCEL,211,29,50,14 -END - - -///////////////////////////////////////////////////////////////////////////// -// -// DESIGNINFO -// - -#ifdef APSTUDIO_INVOKED -GUIDELINES DESIGNINFO -BEGIN - IDD_OPTIONS, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 261 - TOPMARGIN, 7 - BOTTOMMARGIN, 43 - END -END -#endif // APSTUDIO_INVOKED - - -///////////////////////////////////////////////////////////////////////////// -// -// AFX_DIALOG_LAYOUT -// - -IDD_OPTIONS AFX_DIALOG_LAYOUT -BEGIN - 0 -END - -#endif // English (Australia) resources -///////////////////////////////////////////////////////////////////////////// - - - -#ifndef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// - - -///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED - diff --git a/plugins/SbieSupport/SbieSupport.vcxproj b/plugins/SbieSupport/SbieSupport.vcxproj deleted file mode 100644 index 08a3a4d34cab..000000000000 --- a/plugins/SbieSupport/SbieSupport.vcxproj +++ /dev/null @@ -1,65 +0,0 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {EEF1E81D-D286-422A-89E6-C6C8F3BE648A} - SbieSupport - Win32Proj - SbieSupport - 10.0.15063.0 - - - - DynamicLibrary - Unicode - v141 - - - DynamicLibrary - Unicode - v141 - - - DynamicLibrary - Unicode - v141 - - - DynamicLibrary - Unicode - v141 - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/plugins/SbieSupport/SbieSupport.vcxproj.filters b/plugins/SbieSupport/SbieSupport.vcxproj.filters deleted file mode 100644 index 1c000f9ebf8b..000000000000 --- a/plugins/SbieSupport/SbieSupport.vcxproj.filters +++ /dev/null @@ -1,35 +0,0 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hpp;hxx;hm;inl;inc;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav - - - - - Source Files - - - - - Header Files - - - Header Files - - - - - Resource Files - - - \ No newline at end of file diff --git a/plugins/SbieSupport/main.c b/plugins/SbieSupport/main.c deleted file mode 100644 index ff84ca975af1..000000000000 --- a/plugins/SbieSupport/main.c +++ /dev/null @@ -1,556 +0,0 @@ -/* - * Process Hacker Sandboxie Support - - * main program - * - * Copyright (C) 2010-2011 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include -#include -#include "resource.h" -#include "sbiedll.h" - -typedef struct _BOX_INFO -{ - WCHAR BoxName[34]; - PH_STRINGREF IpcRoot; - WCHAR IpcRootBuffer[256]; -} BOX_INFO, *PBOX_INFO; - -typedef struct _BOXED_PROCESS -{ - HANDLE ProcessId; - WCHAR BoxName[34]; -} BOXED_PROCESS, *PBOXED_PROCESS; - -VOID NTAPI LoadCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ); - -VOID NTAPI ShowOptionsCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ); - -VOID NTAPI MenuItemCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ); - -VOID NTAPI MainMenuInitializingCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ); - -VOID NTAPI ProcessesUpdatedCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ); - -VOID NTAPI GetProcessHighlightingColorCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ); - -VOID NTAPI GetProcessTooltipTextCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ); - -VOID NTAPI GetIsDotNetDirectoryNamesCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ); - -VOID NTAPI RefreshSandboxieInfo( - _In_opt_ PVOID Context, - _In_ BOOLEAN TimerOrWaitFired - ); - -INT_PTR CALLBACK OptionsDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -PPH_PLUGIN PluginInstance; -PH_CALLBACK_REGISTRATION PluginLoadCallbackRegistration; -PH_CALLBACK_REGISTRATION PluginShowOptionsCallbackRegistration; -PH_CALLBACK_REGISTRATION PluginMenuItemCallbackRegistration; -PH_CALLBACK_REGISTRATION MainMenuInitializingCallbackRegistration; -PH_CALLBACK_REGISTRATION ProcessesUpdatedCallbackRegistration; -PH_CALLBACK_REGISTRATION GetProcessHighlightingColorCallbackRegistration; -PH_CALLBACK_REGISTRATION GetProcessTooltipTextCallbackRegistration; - -P_SbieApi_QueryBoxPath SbieApi_QueryBoxPath; -P_SbieApi_EnumBoxes SbieApi_EnumBoxes; -P_SbieApi_EnumProcessEx SbieApi_EnumProcessEx; -P_SbieDll_KillAll SbieDll_KillAll; - -PPH_HASHTABLE BoxedProcessesHashtable; -PH_QUEUED_LOCK BoxedProcessesLock = PH_QUEUED_LOCK_INIT; -BOOLEAN BoxedProcessesUpdated = FALSE; - -BOX_INFO BoxInfo[16]; -ULONG BoxInfoCount; - -LOGICAL DllMain( - _In_ HINSTANCE Instance, - _In_ ULONG Reason, - _Reserved_ PVOID Reserved - ) -{ - switch (Reason) - { - case DLL_PROCESS_ATTACH: - { - PPH_PLUGIN_INFORMATION info; - - PluginInstance = PhRegisterPlugin(PLUGIN_NAME, Instance, &info); - - if (!PluginInstance) - return FALSE; - - info->DisplayName = L"Sandboxie Support"; - info->Author = L"wj32"; - info->Description = L"Provides functionality for sandboxed processes."; - info->Url = L"https://wj32.org/processhacker/forums/viewtopic.php?t=1115"; - info->HasOptions = TRUE; - - PhRegisterCallback( - PhGetPluginCallback(PluginInstance, PluginCallbackLoad), - LoadCallback, - NULL, - &PluginLoadCallbackRegistration - ); - PhRegisterCallback( - PhGetPluginCallback(PluginInstance, PluginCallbackShowOptions), - ShowOptionsCallback, - NULL, - &PluginShowOptionsCallbackRegistration - ); - PhRegisterCallback( - PhGetPluginCallback(PluginInstance, PluginCallbackMenuItem), - MenuItemCallback, - NULL, - &PluginMenuItemCallbackRegistration - ); - - PhRegisterCallback( - PhGetGeneralCallback(GeneralCallbackMainMenuInitializing), - MainMenuInitializingCallback, - NULL, - &MainMenuInitializingCallbackRegistration - ); - PhRegisterCallback( - PhGetGeneralCallback(GeneralCallbackProcessesUpdated), - ProcessesUpdatedCallback, - NULL, - &ProcessesUpdatedCallbackRegistration - ); - PhRegisterCallback( - PhGetGeneralCallback(GeneralCallbackGetProcessHighlightingColor), - GetProcessHighlightingColorCallback, - NULL, - &GetProcessHighlightingColorCallbackRegistration - ); - PhRegisterCallback( - PhGetGeneralCallback(GeneralCallbackGetProcessTooltipText), - GetProcessTooltipTextCallback, - NULL, - &GetProcessTooltipTextCallbackRegistration - ); - - { - static PH_SETTING_CREATE settings[] = - { - { StringSettingType, SETTING_NAME_SBIE_DLL_PATH, L"C:\\Program Files\\Sandboxie\\SbieDll.dll" } - }; - - PhAddSettings(settings, sizeof(settings) / sizeof(PH_SETTING_CREATE)); - } - } - break; - } - - return TRUE; -} - -BOOLEAN NTAPI BoxedProcessesEqualFunction( - _In_ PVOID Entry1, - _In_ PVOID Entry2 - ) -{ - return ((PBOXED_PROCESS)Entry1)->ProcessId == ((PBOXED_PROCESS)Entry2)->ProcessId; -} - -ULONG NTAPI BoxedProcessesHashFunction( - _In_ PVOID Entry - ) -{ - return HandleToUlong(((PBOXED_PROCESS)Entry)->ProcessId) / 4; -} - -VOID NTAPI LoadCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - PPH_STRING sbieDllPath; - HMODULE module; - HANDLE timerQueueHandle; - HANDLE timerHandle; - - BoxedProcessesHashtable = PhCreateHashtable( - sizeof(BOXED_PROCESS), - BoxedProcessesEqualFunction, - BoxedProcessesHashFunction, - 32 - ); - - sbieDllPath = PhaGetStringSetting(SETTING_NAME_SBIE_DLL_PATH); - module = LoadLibrary(sbieDllPath->Buffer); - - SbieApi_QueryBoxPath = PhGetProcedureAddress(module, SbieApi_QueryBoxPath_Name, 0); - SbieApi_EnumBoxes = PhGetProcedureAddress(module, SbieApi_EnumBoxes_Name, 0); - SbieApi_EnumProcessEx = PhGetProcedureAddress(module, SbieApi_EnumProcessEx_Name, 0); - SbieDll_KillAll = PhGetProcedureAddress(module, SbieDll_KillAll_Name, 0); - - if (NT_SUCCESS(RtlCreateTimerQueue(&timerQueueHandle))) - { - RtlCreateTimer(timerQueueHandle, &timerHandle, RefreshSandboxieInfo, NULL, 0, 4000, 0); - } -} - -VOID NTAPI ShowOptionsCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - DialogBox( - PluginInstance->DllBase, - MAKEINTRESOURCE(IDD_OPTIONS), - (HWND)Parameter, - OptionsDlgProc - ); -} - -VOID NTAPI MenuItemCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - PPH_PLUGIN_MENU_ITEM menuItem = Parameter; - - switch (menuItem->Id) - { - case 1: - { - if (PhShowConfirmMessage( - PhMainWndHandle, - L"terminate", - L"all sandboxed processes", - NULL, - FALSE - )) - { - PBOXED_PROCESS boxedProcess; - ULONG enumerationKey = 0; - - // Make sure we have an update-to-date list. - RefreshSandboxieInfo(NULL, FALSE); - - PhAcquireQueuedLockShared(&BoxedProcessesLock); - - while (PhEnumHashtable(BoxedProcessesHashtable, &boxedProcess, &enumerationKey)) - { - HANDLE processHandle; - - if (NT_SUCCESS(PhOpenProcess(&processHandle, PROCESS_TERMINATE, boxedProcess->ProcessId))) - { - PhTerminateProcess(processHandle, STATUS_SUCCESS); - NtClose(processHandle); - } - } - - PhReleaseQueuedLockShared(&BoxedProcessesLock); - } - } - break; - } -} - -VOID NTAPI MainMenuInitializingCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - PPH_PLUGIN_MENU_INFORMATION menuInfo = Parameter; - - if (!SbieDll_KillAll) - return; - if (menuInfo->u.MainMenu.SubMenuIndex != PH_MENU_ITEM_LOCATION_TOOLS) - return; - - PhInsertEMenuItem(menuInfo->Menu, PhPluginCreateEMenuItem(PluginInstance, PH_EMENU_SEPARATOR, 0, NULL, NULL), -1); - PhInsertEMenuItem(menuInfo->Menu, PhPluginCreateEMenuItem(PluginInstance, 0, 1, L"Terminate sandboxed processes", NULL), -1); -} - -VOID NTAPI ProcessesUpdatedCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - PBOXED_PROCESS boxedProcess; - ULONG enumerationKey = 0; - - if (BoxedProcessesUpdated) - { - // Invalidate the nodes of boxed processes (so they use the correct highlighting color). - - PhAcquireQueuedLockShared(&BoxedProcessesLock); - - if (BoxedProcessesUpdated) - { - while (PhEnumHashtable(BoxedProcessesHashtable, &boxedProcess, &enumerationKey)) - { - PPH_PROCESS_NODE processNode; - - if (processNode = PhFindProcessNode(boxedProcess->ProcessId)) - PhUpdateProcessNode(processNode); - } - - BoxedProcessesUpdated = FALSE; - } - - PhReleaseQueuedLockShared(&BoxedProcessesLock); - } -} - -VOID NTAPI GetProcessHighlightingColorCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - PPH_PLUGIN_GET_HIGHLIGHTING_COLOR getHighlightingColor = Parameter; - BOXED_PROCESS lookupBoxedProcess; - PBOXED_PROCESS boxedProcess; - - PhAcquireQueuedLockShared(&BoxedProcessesLock); - - lookupBoxedProcess.ProcessId = ((PPH_PROCESS_ITEM)getHighlightingColor->Parameter)->ProcessId; - - if (boxedProcess = PhFindEntryHashtable(BoxedProcessesHashtable, &lookupBoxedProcess)) - { - getHighlightingColor->BackColor = RGB(0x33, 0x33, 0x00); - getHighlightingColor->Cache = TRUE; - getHighlightingColor->Handled = TRUE; - } - - PhReleaseQueuedLockShared(&BoxedProcessesLock); -} - -VOID NTAPI GetProcessTooltipTextCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - PPH_PLUGIN_GET_TOOLTIP_TEXT getTooltipText = Parameter; - BOXED_PROCESS lookupBoxedProcess; - PBOXED_PROCESS boxedProcess; - - PhAcquireQueuedLockShared(&BoxedProcessesLock); - - lookupBoxedProcess.ProcessId = ((PPH_PROCESS_ITEM)getTooltipText->Parameter)->ProcessId; - - if (boxedProcess = PhFindEntryHashtable(BoxedProcessesHashtable, &lookupBoxedProcess)) - { - PhAppendFormatStringBuilder(getTooltipText->StringBuilder, L"Sandboxie:\n Box name: %s\n", boxedProcess->BoxName); - } - - PhReleaseQueuedLockShared(&BoxedProcessesLock); -} - -VOID NTAPI RefreshSandboxieInfo( - _In_opt_ PVOID Context, - _In_ BOOLEAN TimerOrWaitFired - ) -{ - LONG index; - WCHAR boxName[34]; - ULONG pids[512]; - PBOX_INFO boxInfo; - - if (!SbieApi_QueryBoxPath || !SbieApi_EnumBoxes || !SbieApi_EnumProcessEx) - return; - - PhAcquireQueuedLockExclusive(&BoxedProcessesLock); - - PhClearHashtable(BoxedProcessesHashtable); - - BoxInfoCount = 0; - - index = -1; - - while ((index = SbieApi_EnumBoxes(index, boxName)) != -1) - { - if (SbieApi_EnumProcessEx(boxName, TRUE, 0, pids) == 0) - { - ULONG count; - PULONG pid; - - count = pids[0]; - pid = &pids[1]; - - while (count != 0) - { - BOXED_PROCESS boxedProcess; - - boxedProcess.ProcessId = UlongToHandle(*pid); - memcpy(boxedProcess.BoxName, boxName, sizeof(boxName)); - - PhAddEntryHashtable(BoxedProcessesHashtable, &boxedProcess); - - count--; - pid++; - } - } - - if (BoxInfoCount < 16) - { - ULONG filePathLength = 0; - ULONG keyPathLength = 0; - ULONG ipcPathLength = 0; - - boxInfo = &BoxInfo[BoxInfoCount++]; - memcpy(boxInfo->BoxName, boxName, sizeof(boxName)); - - SbieApi_QueryBoxPath( - boxName, - NULL, - NULL, - NULL, - &filePathLength, - &keyPathLength, - &ipcPathLength - ); - - if (ipcPathLength < sizeof(boxInfo->IpcRootBuffer)) - { - boxInfo->IpcRootBuffer[0] = 0; - SbieApi_QueryBoxPath( - boxName, - NULL, - NULL, - boxInfo->IpcRootBuffer, - NULL, - NULL, - &ipcPathLength - ); - - if (boxInfo->IpcRootBuffer[0] != 0) - { - PhInitializeStringRef(&boxInfo->IpcRoot, boxInfo->IpcRootBuffer); - } - else - { - BoxInfoCount--; - } - } - else - { - BoxInfoCount--; - } - } - } - - BoxedProcessesUpdated = TRUE; - - PhReleaseQueuedLockExclusive(&BoxedProcessesLock); -} - -INT_PTR CALLBACK OptionsDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - switch (uMsg) - { - case WM_INITDIALOG: - { - PPH_STRING sbieDllPath; - - PhCenterWindow(hwndDlg, GetParent(hwndDlg)); - - sbieDllPath = PhaGetStringSetting(SETTING_NAME_SBIE_DLL_PATH); - SetDlgItemText(hwndDlg, IDC_SBIEDLLPATH, sbieDllPath->Buffer); - - SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hwndDlg, IDCANCEL), TRUE); - } - break; - case WM_COMMAND: - { - switch (LOWORD(wParam)) - { - case IDCANCEL: - EndDialog(hwndDlg, IDCANCEL); - break; - case IDOK: - { - PhSetStringSetting2(SETTING_NAME_SBIE_DLL_PATH, - &PhaGetDlgItemText(hwndDlg, IDC_SBIEDLLPATH)->sr); - - EndDialog(hwndDlg, IDOK); - } - break; - case IDC_BROWSE: - { - static PH_FILETYPE_FILTER filters[] = - { - { L"SbieDll.dll", L"SbieDll.dll" }, - { L"All files (*.*)", L"*.*" } - }; - PVOID fileDialog; - PPH_STRING fileName; - - fileDialog = PhCreateOpenFileDialog(); - PhSetFileDialogFilter(fileDialog, filters, sizeof(filters) / sizeof(PH_FILETYPE_FILTER)); - - fileName = PH_AUTO(PhGetFileName(PhaGetDlgItemText(hwndDlg, IDC_SBIEDLLPATH))); - PhSetFileDialogFileName(fileDialog, fileName->Buffer); - - if (PhShowFileDialog(hwndDlg, fileDialog)) - { - fileName = PH_AUTO(PhGetFileDialogFileName(fileDialog)); - SetDlgItemText(hwndDlg, IDC_SBIEDLLPATH, fileName->Buffer); - } - - PhFreeFileDialog(fileDialog); - } - break; - } - } - break; - } - - return FALSE; -} diff --git a/plugins/SbieSupport/resource.h b/plugins/SbieSupport/resource.h deleted file mode 100644 index b338721498ca..000000000000 --- a/plugins/SbieSupport/resource.h +++ /dev/null @@ -1,18 +0,0 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by SbieSupport.rc -// -#define IDD_OPTIONS 101 -#define IDC_SBIEDLLPATH 1001 -#define IDC_BROWSE 1002 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 102 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1003 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif diff --git a/plugins/SbieSupport/sbiedll.h b/plugins/SbieSupport/sbiedll.h deleted file mode 100644 index fab2af6674ac..000000000000 --- a/plugins/SbieSupport/sbiedll.h +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef SBIEDLL_H -#define SBIEDLL_H - -#define PLUGIN_NAME L"ProcessHacker.SbieSupport" -#define SETTING_NAME_SBIE_DLL_PATH (PLUGIN_NAME L".SbieDllPath") - -typedef LONG (__stdcall *P_SbieApi_QueryBoxPath)( - const WCHAR *box_name, // pointer to WCHAR [34] - WCHAR *file_path, - WCHAR *key_path, - WCHAR *ipc_path, - ULONG *file_path_len, - ULONG *key_path_len, - ULONG *ipc_path_len); - -typedef LONG (__stdcall *P_SbieApi_EnumBoxes)( - LONG index, // initialize to -1 - WCHAR *box_name); // pointer to WCHAR [34] - -typedef LONG (__stdcall *P_SbieApi_EnumProcessEx)( - const WCHAR *box_name, // pointer to WCHAR [34] - BOOLEAN all_sessions, - ULONG which_session, - ULONG *boxed_pids); // pointer to ULONG [512] - -typedef BOOLEAN (__stdcall *P_SbieDll_KillAll)( - ULONG session_id, - const WCHAR *box_name); - -#ifdef _WIN64 -#define SbieApi_QueryBoxPath_Name "SbieApi_QueryBoxPath" -#define SbieApi_EnumBoxes_Name "SbieApi_EnumBoxes" -#define SbieApi_EnumProcessEx_Name "SbieApi_EnumProcessEx" -#define SbieDll_KillAll_Name "SbieDll_KillAll" -#else -#define SbieApi_QueryBoxPath_Name "_SbieApi_QueryBoxPath@28" -#define SbieApi_EnumBoxes_Name "_SbieApi_EnumBoxes@8" -#define SbieApi_EnumProcessEx_Name "_SbieApi_EnumProcessEx@16" -#define SbieDll_KillAll_Name "_SbieDll_KillAll@8" -#endif - -#endif From 1c19c94c46846455f82cf6c6619284a15454564b Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 8 May 2017 08:16:03 +1000 Subject: [PATCH 0068/2058] peview: Add experimental symbols tab and pdb support, Fix lib properties window resize and settings --- tools/peview/include/pdb.h | 468 +++++ tools/peview/include/peview.h | 18 + tools/peview/libprp.c | 69 +- tools/peview/main.c | 4 +- tools/peview/pdb.c | 2609 +++++++++++++++++++++++++++ tools/peview/peprp.c | 266 +-- tools/peview/peview.rc | 21 + tools/peview/peview.vcxproj | 2 + tools/peview/peview.vcxproj.filters | 8 +- tools/peview/resource.h | 3 +- tools/peview/settings.c | 2 + 11 files changed, 3316 insertions(+), 154 deletions(-) create mode 100644 tools/peview/include/pdb.h create mode 100644 tools/peview/pdb.c diff --git a/tools/peview/include/pdb.h b/tools/peview/include/pdb.h new file mode 100644 index 000000000000..7b49cc6f668f --- /dev/null +++ b/tools/peview/include/pdb.h @@ -0,0 +1,468 @@ +/* + * Process Hacker - + * property sheet + * + * Copyright (C) 2017 dmex + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#ifndef PV_PDB_H +#define PV_PDB_H + +// Originally based on dbghelptypeinfo by Oleg Starodumov: +// http://www.debuginfo.com/articles/dbghelptypeinfo.html + +#define _NO_CVCONST_H +#define DBGHELP_TRANSLATE_TCHAR +#include + +// Types from Cvconst.h (DIA SDK) +#ifdef _NO_CVCONST_H + +// BasicType, originally from CVCONST.H in DIA SDK +typedef enum _BasicType +{ + btNoType = 0, + btVoid = 1, + btChar = 2, + btWChar = 3, + btInt = 6, + btUInt = 7, + btFloat = 8, + btBCD = 9, + btBool = 10, + btLong = 13, + btULong = 14, + btCurrency = 25, + btDate = 26, + btVariant = 27, + btComplex = 28, + btBit = 29, + btBSTR = 30, + btHresult = 31 +} BasicType; + +// UDtKind, originally from CVCONST.H in DIA SDK +typedef enum _UdtKind +{ + UdtStruct, + UdtClass, + UdtUnion +} UdtKind; + +// CV_call_e, originally from CVCONST.H in DIA SDK +typedef enum _CV_call_e +{ + CV_CALL_NEAR_C = 0x00, // near right to left push, caller pops stack + CV_CALL_FAR_C = 0x01, // far right to left push, caller pops stack + CV_CALL_NEAR_PASCAL = 0x02, // near left to right push, callee pops stack + CV_CALL_FAR_PASCAL = 0x03, // far left to right push, callee pops stack + CV_CALL_NEAR_FAST = 0x04, // near left to right push with regs, callee pops stack + CV_CALL_FAR_FAST = 0x05, // far left to right push with regs, callee pops stack + CV_CALL_SKIPPED = 0x06, // skipped (unused) call index + CV_CALL_NEAR_STD = 0x07, // near standard call + CV_CALL_FAR_STD = 0x08, // far standard call + CV_CALL_NEAR_SYS = 0x09, // near sys call + CV_CALL_FAR_SYS = 0x0a, // far sys call + CV_CALL_THISCALL = 0x0b, // this call (this passed in register) + CV_CALL_MIPSCALL = 0x0c, // Mips call + CV_CALL_GENERIC = 0x0d, // Generic call sequence + CV_CALL_ALPHACALL = 0x0e, // Alpha call + CV_CALL_PPCCALL = 0x0f, // PPC call + CV_CALL_SHCALL = 0x10, // Hitachi SuperH call + CV_CALL_ARMCALL = 0x11, // ARM call + CV_CALL_AM33CALL = 0x12, // AM33 call + CV_CALL_TRICALL = 0x13, // TriCore Call + CV_CALL_SH5CALL = 0x14, // Hitachi SuperH-5 call + CV_CALL_M32RCALL = 0x15, // M32R Call + CV_CALL_RESERVED = 0x16 // first unused call enumeration +} CV_call_e; + +// DataKind, originally from CVCONST.H in DIA SDK +typedef enum _DataKind +{ + DataIsUnknown, + DataIsLocal, + DataIsStaticLocal, + DataIsParam, + DataIsObjectPtr, + DataIsFileStatic, + DataIsGlobal, + DataIsMember, + DataIsStaticMember, + DataIsConstant +} DataKind; + +// CV_HREG_e, originally from CVCONST.H in DIA SDK +typedef enum _CV_HREG_e +{ + // Only a limited number of registers included here + + CV_REG_EAX = 17, + CV_REG_ECX = 18, + CV_REG_EDX = 19, + CV_REG_EBX = 20, + CV_REG_ESP = 21, + CV_REG_EBP = 22, + CV_REG_ESI = 23, + CV_REG_EDI = 24, + +} CV_HREG_e; + +// LocatonType, originally from CVCONST.H in DIA SDK +typedef enum _LocationType +{ + LocIsNull, + LocIsStatic, + LocIsTLS, + LocIsRegRel, + LocIsThisRel, + LocIsEnregistered, + LocIsBitField, + LocIsSlot, + LocIsIlRel, + LocInMetaData, + LocIsConstant, + LocTypeMax +} LocationType; + +#endif // _NO_CVCONST_H + +// Maximal length of name buffers (in characters) +#define TIS_MAXNAMELEN 256 +// Maximal number of children (member variables, member functions, base classes, etc.) +#define TIS_MAXNUMCHILDREN 64 +// Maximal number of dimensions of an array +#define TIS_MAXARRAYDIMS 64 + +// SymTagBaseType symbol +typedef struct _BaseTypeInfo +{ + // Basic type (DIA: baseType) + BasicType BaseType; + + // Length (in bytes) (DIA: length) + ULONG64 Length; +} BaseTypeInfo; + +// SymTagTypedef symbol +typedef struct _TypedefInfo +{ + // Name (DIA: name) + WCHAR Name[TIS_MAXNAMELEN]; + + // Index of the underlying type (DIA: typeId) + ULONG TypeIndex; +} TypedefInfo; + +// SymTagPointerType symbol +typedef struct _PointerTypeInfo +{ + // Length (in bytes) (DIA: length) + ULONG64 Length; + + // Index of the type the pointer points to (DIA: typeId) + ULONG TypeIndex; +} PointerTypeInfo; + +// SymTagUDT symbol (Class or structure) +typedef struct _UdtClassInfo +{ + // Name (DIA: name) + WCHAR Name[TIS_MAXNAMELEN]; + + // Length (DIA: length) + ULONG64 Length; + + // UDT kind (class, structure or union) (DIA: udtKind) + UdtKind UDTKind; + + // Nested ("true" if the declaration is nested in another UDT) (DIA: nested) + BOOL Nested; + + // Number of member variables + ULONG NumVariables; + + // Member variables + ULONG Variables[TIS_MAXNUMCHILDREN]; + + // Number of member functions + ULONG NumFunctions; + + // Member functions + ULONG Functions[TIS_MAXNUMCHILDREN]; + + // Number of base classes + ULONG NumBaseClasses; + + // Base classes + ULONG BaseClasses[TIS_MAXNUMCHILDREN]; +} UdtClassInfo; + +// SymTagUDT symbol (Union) +typedef struct _UdtUnionInfo +{ + // Name (DIA: name) + WCHAR Name[TIS_MAXNAMELEN]; + + // Length (in bytes) (DIA: length) + ULONG64 Length; + + // UDT kind (class, structure or union) (DIA: udtKind) + UdtKind UDTKind; + + // Nested ("true" if the declaration is nested in another UDT) (DIA: nested) + BOOL Nested; + + // Number of members + ULONG NumMembers; + + // Members + ULONG Members[TIS_MAXNUMCHILDREN]; +} UdtUnionInfo; + +// SymTagBaseClass symbol +typedef struct _BaseClassInfo +{ + // Index of the UDT symbol that represents the base class (DIA: type) + ULONG TypeIndex; + + // Virtual ("true" if the base class is a virtual base class) (DIA: virtualBaseClass) + BOOL Virtual; + + // Offset of the base class within the class/structure (DIA: offset) + // (defined only if Virtual is "false") + LONG Offset; + + // Virtual base pointer offset (DIA: virtualBasePointerOffset) + // (defined only if Virtual is "true") + LONG VirtualBasePointerOffset; +} BaseClassInfo; + +// SymTagEnum symbol +typedef struct _EnumInfo +{ + // Name (DIA: name) + WCHAR Name[TIS_MAXNAMELEN]; + + // Index of the symbol that represent the type of the enumerators (DIA: typeId) + ULONG TypeIndex; + + // Nested ("true" if the declaration is nested in a UDT) (DIA: nested) + BOOL Nested; + + // Number of enumerators + ULONG NumEnums; + + // Enumerators (their type indices) + ULONG Enums[TIS_MAXNUMCHILDREN]; +} EnumInfo; + +// SymTagArrayType symbol +typedef struct _ArrayTypeInfo +{ + // Index of the symbol that represents the type of the array element + ULONG ElementTypeIndex; + + // Index of the symbol that represents the type of the array index (DIA: arrayIndexTypeId) + ULONG IndexTypeIndex; + + // Size of the array (in bytes) (DIA: length) + ULONG64 Length; + + // Number of dimensions + ULONG NumDimensions; + + // Dimensions + ULONG64 Dimensions[TIS_MAXARRAYDIMS]; +} ArrayTypeInfo; + +// SymTagFunctionType +typedef struct FunctionTypeInfo +{ + // Index of the return value type symbol (DIA: objectPointerType) + ULONG RetTypeIndex; + + // Number of arguments (DIA: count) + ULONG NumArgs; + + // Function arguments + ULONG Args[TIS_MAXNUMCHILDREN]; + + // Calling convention (DIA: callingConvention) + CV_call_e CallConv; + + // "Is member function" flag (member function, if "true") + BOOL MemberFunction; + + // Class symbol index (DIA: classParent) + // (defined only if MemberFunction is "true") + ULONG ClassIndex; + + // "this" adjustment (DIA: thisAdjust) + // (defined only if MemberFunction is "true") + LONG ThisAdjust; + + // "Is static function" flag (static, if "true") + // (defined only if MemberFunction is "true") + BOOL StaticFunction; +} FunctionTypeInfo; + +// SymTagFunctionArgType +typedef struct FunctionArgTypeInfo +{ + // Index of the symbol that represents the type of the argument (DIA: typeId) + ULONG TypeIndex; +} FunctionArgTypeInfo; + +// SymTagData +typedef struct DataInfo +{ + // Name (DIA: name) + WCHAR Name[TIS_MAXNAMELEN]; + + // Index of the symbol that represents the type of the variable (DIA: type) + ULONG TypeIndex; + + // Data kind (local, global, member, etc.) (DIA: dataKind) + DataKind dataKind; + + // Address (defined if dataKind is: DataIsGlobal, DataIsStaticLocal, + // DataIsFileStatic, DataIsStaticMember) (DIA: address) + ULONG64 Address; + + // Offset (defined if dataKind is: DataIsLocal, DataIsParam, + // DataIsObjectPtr, DataIsMember) (DIA: offset) + ULONG Offset; // Verify it for all listed data kinds + + // Note: Length is not available - use the type symbol to obtain it +} DataInfo; + +typedef struct _TypeInfo +{ + // Symbol tag + enum SymTagEnum Tag; + + // UDT kind (defined only if "Tag" is SymTagUDT: "true" if the symbol is + // a class or a structure, "false" if the symbol is a union) + BOOL UdtKind; + + // Union of all type information structures + union // TypeInfoStructures + { + BaseTypeInfo sBaseTypeInfo; // If Tag == SymTagBaseType + TypedefInfo sTypedefInfo; // If Tag == SymTagTypedef + PointerTypeInfo sPointerTypeInfo; // If Tag == SymTagPointerType + UdtClassInfo sUdtClassInfo; // If Tag == SymTagUDT and UdtKind is "true" + UdtUnionInfo sUdtUnionInfo; // If Tag == SymTagUDT and UdtKind is "false" + BaseClassInfo sBaseClassInfo; // If Tag == SymTagBaseClass + EnumInfo sEnumInfo; // If Tag == SymTagEnum + ArrayTypeInfo sArrayTypeInfo; // If Tag == SymTagArrayType + FunctionTypeInfo sFunctionTypeInfo; // If Tag == SymTagFunctionType + FunctionArgTypeInfo sFunctionArgTypeInfo; // If Tag == SymTagFunctionArgType + DataInfo sDataInfo; // If Tag == SymTagData + }; +} TypeInfo; + +typedef struct _PDB_SYMBOL_CONTEXT +{ + HWND ListviewHandle; + ULONG64 BaseAddress; + PPH_LIST UdtList; +} PDB_SYMBOL_CONTEXT, *PPDB_SYMBOL_CONTEXT; + +BOOLEAN SymInfoDump_DumpBasicType(_Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, BaseTypeInfo* Info); +BOOLEAN SymInfoDump_DumpPointerType(_Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, PointerTypeInfo* Info); +BOOLEAN SymInfoDump_DumpTypedef(_Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, TypedefInfo* Info); +BOOLEAN SymInfoDump_DumpEnum(_Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, EnumInfo* Info); +BOOLEAN SymInfoDump_DumpArrayType(_Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, ArrayTypeInfo* Info); +BOOLEAN SymInfoDump_DumpUDT(_Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, TypeInfo* Info); +BOOLEAN SymInfoDump_DumpUDTClass(_Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, UdtClassInfo* Info); +BOOLEAN SymInfoDump_DumpUDTUnion(_Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, UdtUnionInfo* Info); +BOOLEAN SymInfoDump_DumpFunctionType(_Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, FunctionTypeInfo* Info); +BOOLEAN SymInfoDump_DumpFunctionArgType(_Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, FunctionArgTypeInfo* Info); +BOOLEAN SymInfoDump_DumpBaseClass(_Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, BaseClassInfo* Info); +BOOLEAN SymInfoDump_DumpData(_Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, DataInfo* Info); +BOOLEAN SymInfoDump_DumpType(_Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, TypeInfo* Info); +BOOLEAN SymInfoDump_DumpSymbolType(_Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, TypeInfo* Info, ULONG* TypeIndex); + +BOOLEAN SymInfoDump_CheckTag( + _Inout_ PPDB_SYMBOL_CONTEXT Context, + _In_ ULONG Index, + _In_ ULONG Tag + ); + +BOOLEAN SymInfoDump_SymbolSize(_Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, ULONG64* Size); +BOOLEAN SymInfoDump_ArrayElementTypeIndex(_Inout_ PPDB_SYMBOL_CONTEXT Context, ULONG ArrayIndex, ULONG* ElementTypeIndex); +BOOLEAN SymInfoDump_ArrayDims(_Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, ULONG64* pDims, ULONG* Dims, _In_ ULONG MaxDims); +BOOLEAN SymInfoDump_UdtVariables(_Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, ULONG* pVars, ULONG* Vars, _In_ ULONG MaxVars); +BOOLEAN SymInfoDump_UdtFunctions(_Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, ULONG* pFuncs, ULONG* Funcs, _In_ ULONG MaxFuncs); +BOOLEAN SymInfoDump_UdtBaseClasses(_Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, ULONG* pBases, ULONG* Bases, _In_ ULONG MaxBases); +BOOLEAN SymInfoDump_UdtUnionMembers(_Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, ULONG* pMembers, ULONG* Members, _In_ ULONG MaxMembers); +BOOLEAN SymInfoDump_FunctionArguments(_Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, ULONG* pArgs, ULONG* Args, _In_ ULONG MaxArgs); +BOOLEAN SymInfoDump_Enumerators(_Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, ULONG* pEnums, ULONG* Enums, _In_ ULONG MaxEnums); +BOOLEAN SymInfoDump_TypeDefType(_Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, ULONG* UndTypeIndex); +BOOLEAN SymInfoDump_PointerType(_Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, ULONG* UndTypeIndex, ULONG* NumPointers); + +BOOLEAN SymInfoDump_GetTypeNameHelper( + _In_ ULONG Index, + _Inout_ PPDB_SYMBOL_CONTEXT Context, + _Out_ PWSTR *VarName, + _Out_ PWSTR *TypeName + ); +BOOLEAN SymInfoDump_GetTypeName( + _Inout_ PPDB_SYMBOL_CONTEXT Context, + _In_ ULONG Index, + _In_ PWSTR pVarName, + _In_ PWSTR pTypeName, + _In_ ULONG MaxChars + ); +PWSTR SymInfoDump_TagStr(enum SymTagEnum Tag); +PWSTR SymInfoDump_BaseTypeStr(BasicType Type, ULONG64 Length); +PWSTR SymInfoDump_CallConvStr(CV_call_e CallConv); +PWSTR SymInfoDump_DataKindFromSymbolInfo(_In_ PSYMBOL_INFOW rSymbol); +PWSTR SymInfoDump_DataKindStr(DataKind dataKind); +VOID SymInfoDump_SymbolLocationStr(PSYMBOL_INFOW rSymbol, PWSTR pBuffer); +PWSTR SymInfoDump_RegisterStr(CV_HREG_e RegCode); +PWSTR SymInfoDump_UdtKindStr(UdtKind KindType); +PWSTR SymInfoDump_LocationTypeStr(LocationType LocType); + + +VOID PrintDataInfo( + _In_ PPDB_SYMBOL_CONTEXT Context, + _In_ PSYMBOL_INFOW SymbolInfo + ); + +VOID PrintFunctionInfo( + _In_ PPDB_SYMBOL_CONTEXT Context, + _In_ PSYMBOL_INFOW SymbolInfo + ); + +VOID PrintDefaultInfo( + _In_ PPDB_SYMBOL_CONTEXT Context, + _In_ PSYMBOL_INFOW SymbolInfo + ); + +VOID PrintClassInfo( + _In_ PPDB_SYMBOL_CONTEXT Context, + _In_ ULONG Index, + _In_ UdtClassInfo* Info + ); + +VOID PrintUserDefinedTypes(PPDB_SYMBOL_CONTEXT Context); + +#endif diff --git a/tools/peview/include/peview.h b/tools/peview/include/peview.h index 9de0f19c7411..639222135ceb 100644 --- a/tools/peview/include/peview.h +++ b/tools/peview/include/peview.h @@ -48,4 +48,22 @@ VOID PeSaveSettings( VOID ); +// symbols + +INT_PTR CALLBACK PvpSymbolsDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +VOID PeDumpFileSymbols( + _In_ HWND ListViewHandle, + _In_ PWSTR FileName + ); + +VOID PvPdbProperties( + VOID + ); + #endif diff --git a/tools/peview/libprp.c b/tools/peview/libprp.c index b7ee42316c31..6f8b89a1b1ef 100644 --- a/tools/peview/libprp.c +++ b/tools/peview/libprp.c @@ -38,9 +38,7 @@ VOID PvLibProperties( ) { NTSTATUS status; - PROPSHEETHEADER propSheetHeader = { sizeof(propSheetHeader) }; - PROPSHEETPAGE propSheetPage; - HPROPSHEETPAGE pages[1]; + PPV_PROPCONTEXT propContext; status = PhLoadMappedArchive(PvFileName->Buffer, NULL, TRUE, &PvMappedArchive); @@ -50,24 +48,22 @@ VOID PvLibProperties( return; } - propSheetHeader.dwFlags = - PSH_NOAPPLYNOW | - PSH_NOCONTEXTHELP | - PSH_PROPTITLE; - propSheetHeader.hwndParent = NULL; - propSheetHeader.pszCaption = PvFileName->Buffer; - propSheetHeader.nPages = 0; - propSheetHeader.nStartPage = 0; - propSheetHeader.phpage = pages; - - // Exports page - memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); - propSheetPage.dwSize = sizeof(PROPSHEETPAGE); - propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_LIBEXPORTS); - propSheetPage.pfnDlgProc = PvpLibExportsDlgProc; - pages[propSheetHeader.nPages++] = CreatePropertySheetPage(&propSheetPage); - - PhModalPropertySheet(&propSheetHeader); + if (propContext = PvCreatePropContext(PvFileName)) + { + PPV_PROPPAGECONTEXT newPage; + + // Lib page + newPage = PvCreatePropPageContext( + MAKEINTRESOURCE(IDD_LIBEXPORTS), + PvpLibExportsDlgProc, + NULL + ); + PvAddPropPage(propContext, newPage); + + PhModalPropertySheet(&propContext->PropSheetHeader); + + PhDereferenceObject(propContext); + } PhUnloadMappedArchive(&PvMappedArchive); } @@ -79,6 +75,12 @@ INT_PTR CALLBACK PvpLibExportsDlgProc( _In_ LPARAM lParam ) { + LPPROPSHEETPAGE propSheetPage; + PPV_PROPPAGECONTEXT propPageContext; + + if (!PvPropPageDlgProcHeader(hwndDlg, uMsg, lParam, &propSheetPage, &propPageContext)) + return FALSE; + switch (uMsg) { case WM_INITDIALOG: @@ -88,8 +90,6 @@ INT_PTR CALLBACK PvpLibExportsDlgProc( PH_MAPPED_ARCHIVE_MEMBER member; PH_MAPPED_ARCHIVE_IMPORT_ENTRY importEntry; - PhCenterWindow(GetParent(hwndDlg), NULL); - lvHandle = GetDlgItem(hwndDlg, IDC_LIST); PhSetListViewStyle(lvHandle, FALSE, TRUE); PhSetControlTheme(lvHandle, L"explorer"); @@ -100,6 +100,7 @@ INT_PTR CALLBACK PvpLibExportsDlgProc( PhAddListViewColumn(lvHandle, 4, 4, 4, LVCFMT_LEFT, 60, L"Name type"); PhSetExtendedListView(lvHandle); ExtendedListView_AddFallbackColumns(lvHandle, 4, fallbackColumns); + PhLoadListViewColumnsFromSetting(L"LibListViewColumns", lvHandle); member = *PvMappedArchive.LastStandardMember; @@ -170,6 +171,28 @@ INT_PTR CALLBACK PvpLibExportsDlgProc( EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); } break; + case WM_DESTROY: + { + PhSaveListViewColumnsToSetting(L"LibListViewColumns", GetDlgItem(hwndDlg, IDC_LIST)); + } + break; + case WM_SHOWWINDOW: + { + if (!propPageContext->LayoutInitialized) + { + PPH_LAYOUT_ITEM dialogItem; + + dialogItem = PvAddPropPageLayoutItem(hwndDlg, hwndDlg, + PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL); + PvAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_LIST), + dialogItem, PH_ANCHOR_ALL); + + PvDoPropPageLayout(hwndDlg); + + propPageContext->LayoutInitialized = TRUE; + } + } + break; case WM_NOTIFY: { PvHandleListViewNotifyForCopy(lParam, GetDlgItem(hwndDlg, IDC_LIST)); diff --git a/tools/peview/main.c b/tools/peview/main.c index 893e7ee0cb48..4c845c4e9193 100644 --- a/tools/peview/main.c +++ b/tools/peview/main.c @@ -89,7 +89,7 @@ INT WINAPI wWinMain( { static PH_FILETYPE_FILTER filters[] = { - { L"Supported files (*.exe;*.dll;*.ocx;*.sys;*.scr;*.cpl;*.ax;*.acm;*.lib;*.winmd;*.efi)", L"*.exe;*.dll;*.ocx;*.sys;*.scr;*.cpl;*.ax;*.acm;*.lib;*.winmd;*.efi" }, + { L"Supported files (*.exe;*.dll;*.ocx;*.sys;*.scr;*.cpl;*.ax;*.acm;*.lib;*.winmd;*.efi;*.pdb)", L"*.exe;*.dll;*.ocx;*.sys;*.scr;*.cpl;*.ax;*.acm;*.lib;*.winmd;*.efi;*.pdb" }, { L"All files (*.*)", L"*.*" } }; PVOID fileDialog; @@ -123,6 +123,8 @@ INT WINAPI wWinMain( if (PhEndsWithString2(PvFileName, L".lib", TRUE)) PvLibProperties(); + //else if (PhEndsWithString2(PvFileName, L".pdb", TRUE)) + // PvPdbProperties(); else PvPeProperties(); diff --git a/tools/peview/pdb.c b/tools/peview/pdb.c new file mode 100644 index 000000000000..a68ed42d0144 --- /dev/null +++ b/tools/peview/pdb.c @@ -0,0 +1,2609 @@ +/* + * PE viewer - + * pdb support + * + * Copyright (C) 2017 dmex + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include +#include +#include +#include + +typedef BOOL (WINAPI *_SymInitialize)( + _In_ HANDLE hProcess, + _In_opt_ PCSTR UserSearchPath, + _In_ BOOL fInvadeProcess + ); + +typedef BOOL (WINAPI *_SymCleanup)( + _In_ HANDLE hProcess + ); + +typedef BOOL (CALLBACK *_SymGetTypeInfo)( + _In_ HANDLE hProcess, + _In_ ULONG64 ModBase, + _In_ ULONG TypeId, + _In_ IMAGEHLP_SYMBOL_TYPE_INFO GetType, + _Out_ PVOID pInfo + ); + +typedef BOOL (WINAPI *_SymEnumSymbolsW)( + _In_ HANDLE hProcess, + _In_ ULONG64 BaseOfDll, + _In_opt_ PCWSTR Mask, + _In_ PSYM_ENUMERATESYMBOLS_CALLBACKW EnumSymbolsCallback, + _In_opt_ const PVOID UserContext + ); + +typedef BOOL (WINAPI *_SymSetSearchPathW)( + _In_ HANDLE hProcess, + _In_opt_ PCWSTR SearchPath + ); + +typedef ULONG (WINAPI *_SymGetOptions)(); + +typedef ULONG (WINAPI *_SymSetOptions)( + _In_ ULONG SymOptions + ); + +typedef ULONG64 (WINAPI *_SymLoadModuleExW)( + _In_ HANDLE hProcess, + _In_ HANDLE hFile, + _In_ PCWSTR ImageName, + _In_ PCWSTR ModuleName, + _In_ ULONG64 BaseOfDll, + _In_ ULONG DllSize, + _In_ PMODLOAD_DATA Data, + _In_ ULONG Flags + ); + +typedef BOOL(WINAPI *_SymGetModuleInfoW64)( + _In_ HANDLE hProcess, + _In_ ULONG64 qwAddr, + _Out_ PIMAGEHLP_MODULEW64 ModuleInfo + ); + +_SymInitialize SymInitialize_I = NULL; +_SymCleanup SymCleanup_I = NULL; +_SymEnumSymbolsW SymEnumSymbolsW_I = NULL; +_SymSetSearchPathW SymSetSearchPathW_I = NULL; +_SymGetOptions SymGetOptions_I = NULL; +_SymSetOptions SymSetOptions_I = NULL; +_SymLoadModuleExW SymLoadModuleExW_I = NULL; +_SymGetModuleInfoW64 SymGetModuleInfoW64_I = NULL; +_SymGetTypeInfo SymGetTypeInfo_I = NULL; + +BOOLEAN SymInfoDump_DumpBasicType( + _Inout_ PPDB_SYMBOL_CONTEXT Context, + _In_ ULONG Index, + _Inout_ BaseTypeInfo *Info + ) +{ + ULONG baseType = btNoType; + ULONG64 length = 0; + + if (!SymInfoDump_CheckTag(Context, Index, SymTagBaseType)) + return FALSE; + + // Basic type ("basicType" in DIA) + if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, Index, TI_GET_BASETYPE, &baseType)) + return FALSE; + + // Length ("length" in DIA) + if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, Index, TI_GET_LENGTH, &length)) + return FALSE; + + Info->BaseType = (BasicType)baseType; + Info->Length = length; + return TRUE; +} + +BOOLEAN SymInfoDump_DumpPointerType( + _Inout_ PPDB_SYMBOL_CONTEXT Context, + _In_ ULONG Index, + _Inout_ PointerTypeInfo* Info + ) +{ + ULONG TypeIndex = 0; + ULONG64 Length = 0; + + if (!SymInfoDump_CheckTag(Context, Index, SymTagPointerType)) + return FALSE; + + // Type index ("typeId" in DIA) + if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, Index, TI_GET_TYPEID, &TypeIndex)) + return FALSE; + + // Length ("length" in DIA) + if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, Index, TI_GET_LENGTH, &Length)) + return FALSE; + + // Reference ("reference" in DIA) + // This property is not available via SymGetTypeInfo_I?? + // TODO: Figure out how DIA determines if the pointer is a pointer or a reference. + + Info->TypeIndex = TypeIndex; + Info->Length = Length; + + return TRUE; +} + +BOOLEAN SymInfoDump_DumpTypedef( + _Inout_ PPDB_SYMBOL_CONTEXT Context, + _In_ ULONG Index, + _Inout_ TypedefInfo* Info + ) +{ + ULONG typeIndex = 0; + PWSTR symbolName = NULL; + + if (!SymInfoDump_CheckTag(Context, Index, SymTagTypedef)) + return FALSE; + + // Type index ("typeId" in DIA) + if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, Index, TI_GET_TYPEID, &typeIndex)) + return FALSE; + + // Name ("name" in DIA) + if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, Index, TI_GET_SYMNAME, &symbolName) || !symbolName) + return FALSE; + + Info->TypeIndex = typeIndex; + + wcsncpy(Info->Name, symbolName, ARRAYSIZE(Info->Name)); + Info->Name[ARRAYSIZE(Info->Name) - 1] = 0; + LocalFree(symbolName); + + return TRUE; +} + +BOOLEAN SymInfoDump_DumpEnum( + _Inout_ PPDB_SYMBOL_CONTEXT Context, + _In_ ULONG Index, + _Inout_ EnumInfo* Info + ) +{ + ULONG TypeIndex = 0; + ULONG Nested = 0; + PWSTR symbolName = NULL; + + if (!SymInfoDump_CheckTag(Context, Index, SymTagEnum)) + return FALSE; + + // Name ("name" in DIA) + if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, Index, TI_GET_SYMNAME, &symbolName) || !symbolName) + return FALSE; + + wcsncpy(Info->Name, symbolName, ARRAYSIZE(Info->Name)); + Info->Name[ARRAYSIZE(Info->Name) - 1] = 0; + LocalFree(symbolName); + + // Type index ("typeId" in DIA) + if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, Index, TI_GET_TYPEID, &TypeIndex)) + return FALSE; + + // Nested ("nested" in DIA) + if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, Index, TI_GET_NESTED, &Nested)) + return FALSE; + + // Enumerators + if (!SymInfoDump_Enumerators(Context, Index, Info->Enums, &Info->NumEnums, ARRAYSIZE(Info->Enums))) + return FALSE; + + Info->TypeIndex = TypeIndex; + Info->Nested = (Nested != 0); + + return TRUE; +} + +BOOLEAN SymInfoDump_DumpArrayType( + _Inout_ PPDB_SYMBOL_CONTEXT Context, + _In_ ULONG Index, + _Inout_ ArrayTypeInfo* Info + ) +{ + ULONG elementTypeIndex = 0; + ULONG64 length = 0; + ULONG indexTypeIndex = 0; + + // Check if it is really SymTagArrayType + if (!SymInfoDump_CheckTag(Context, Index, SymTagArrayType)) + return FALSE; + + // Element type index + if (!SymInfoDump_ArrayElementTypeIndex(Context, Index, &elementTypeIndex)) + return FALSE; + + // Length ("length" in DIA) + if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, Index, TI_GET_LENGTH, &length)) + return FALSE; + + // Type index of the array index element + if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, Index, TI_GET_ARRAYINDEXTYPEID, &indexTypeIndex)) + return FALSE; + + Info->ElementTypeIndex = elementTypeIndex; + Info->Length = length; + Info->IndexTypeIndex = indexTypeIndex; + + if (length > 0) + { + // Dimensions + if (!SymInfoDump_ArrayDims( + Context, + Index, + Info->Dimensions, + &Info->NumDimensions, + ARRAYSIZE(Info->Dimensions) + ) || (Info->NumDimensions == 0)) + { + return FALSE; + } + } + else + { + Info->NumDimensions = 0; // No dimensions + } + + return TRUE; +} + +BOOLEAN SymInfoDump_DumpUDT( + _Inout_ PPDB_SYMBOL_CONTEXT Context, + _In_ ULONG Index, + _Inout_ TypeInfo* Info + ) +{ + ULONG UDTKind = 0; + BOOLEAN result = FALSE; + + if (!SymInfoDump_CheckTag(Context, Index, SymTagUDT)) + return FALSE; + + // Determine UDT kind (class/structure or union?) + if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, Index, TI_GET_UDTKIND, &UDTKind)) + return FALSE; + + switch (UDTKind) + { + case UdtStruct: + Info->UdtKind = TRUE; + result = SymInfoDump_DumpUDTClass(Context, Index, &Info->sUdtClassInfo); + break; + case UdtClass: + Info->UdtKind = TRUE; + result = SymInfoDump_DumpUDTClass(Context, Index, &Info->sUdtClassInfo); + break; + case UdtUnion: + Info->UdtKind = FALSE; + result = SymInfoDump_DumpUDTUnion(Context, Index, &Info->sUdtUnionInfo); + break; + } + + return result; +} + +BOOLEAN SymInfoDump_DumpUDTClass( + _Inout_ PPDB_SYMBOL_CONTEXT Context, + _In_ ULONG Index, + _Inout_ UdtClassInfo* Info + ) +{ + ULONG UDTKind = 0; + PWSTR symbolName = NULL; + ULONG64 Length = 0; + ULONG Nested = 0; + + if (!SymInfoDump_CheckTag(Context, Index, SymTagUDT)) + return FALSE; + + // Check if it is really a class or structure UDT ? + if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, Index, TI_GET_UDTKIND, &UDTKind)) + return FALSE; + + if ((UDTKind != UdtStruct) && (UDTKind != UdtClass)) + return FALSE; + + // Name ("name" in DIA) + if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, Index, TI_GET_SYMNAME, &symbolName) || !symbolName) + return FALSE; + + wcsncpy(Info->Name, symbolName, ARRAYSIZE(Info->Name)); + Info->Name[ARRAYSIZE(Info->Name) - 1] = 0; + LocalFree(symbolName); + + // Length ("length" in DIA) + if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, Index, TI_GET_LENGTH, &Length)) + return FALSE; + + // Nested ("nested" in DIA) + if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, Index, TI_GET_NESTED, &Nested)) + return FALSE; + + // Member variables + if (!SymInfoDump_UdtVariables(Context, Index, Info->Variables, &Info->NumVariables, ARRAYSIZE(Info->Variables))) + return FALSE; + + // Member functions + if (!SymInfoDump_UdtFunctions(Context, Index, Info->Functions, &Info->NumFunctions, ARRAYSIZE(Info->Functions))) + return FALSE; + + // Base classes + if (!SymInfoDump_UdtBaseClasses(Context, Index, Info->BaseClasses, &Info->NumBaseClasses, ARRAYSIZE(Info->BaseClasses))) + return FALSE; + + Info->UDTKind = (UdtKind)UDTKind; + Info->Length = Length; + Info->Nested = (Nested != 0); + + return TRUE; +} + +BOOLEAN SymInfoDump_DumpUDTUnion( + _Inout_ PPDB_SYMBOL_CONTEXT Context, + _In_ ULONG Index, + _Inout_ UdtUnionInfo *Info + ) +{ + ULONG UDTKind = 0; + PWSTR symbolName = 0; + ULONG64 Length = 0; + ULONG Nested = 0; + + if (!SymInfoDump_CheckTag(Context, Index, SymTagUDT)) + return FALSE; + + // Check if it is really a union UDT ? + if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, Index, TI_GET_UDTKIND, &UDTKind)) + return FALSE; + + if (UDTKind != UdtUnion) + return FALSE; + + // Name ("name" in DIA) + if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, Index, TI_GET_SYMNAME, &symbolName) || !symbolName) + return FALSE; + + wcsncpy(Info->Name, symbolName, ARRAYSIZE(Info->Name)); + Info->Name[ARRAYSIZE(Info->Name) - 1] = 0; + LocalFree(symbolName); + + // Length ("length" in DIA) + if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, Index, TI_GET_LENGTH, &Length)) + return FALSE; + + // Nested ("nested" in DIA) + if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, Index, TI_GET_NESTED, &Nested)) + return FALSE; + + // Union members + if (!SymInfoDump_UdtUnionMembers(Context, Index, Info->Members, &Info->NumMembers, ARRAYSIZE(Info->Members))) + return FALSE; + + Info->UDTKind = (UdtKind)UDTKind; + Info->Length = Length; + Info->Nested = (Nested != 0); + + return TRUE; +} + +BOOLEAN SymInfoDump_DumpFunctionType( + _Inout_ PPDB_SYMBOL_CONTEXT Context, + _In_ ULONG Index, + _Inout_ FunctionTypeInfo *Info + ) +{ + ULONG RetTypeIndex = 0; + ULONG NumArgs = 0; + ULONG CallConv = 0; + ULONG ClassIndex = 0; + + if (!SymInfoDump_CheckTag(Context, Index, SymTagFunctionType)) + return FALSE; + + // Index of the return type symbol ("typeId" in DIA) + if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, Index, TI_GET_TYPEID, &RetTypeIndex)) + return FALSE; + + // Number of arguments ("count" in DIA) + // Note: For non-static member functions, it includes "this" + if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, Index, TI_GET_COUNT, &NumArgs)) + return FALSE; + + // Do not save it in the data structure, since we obtain the number of arguments + // again using FunctionArguments() (see below). + // But later we will use this value to determine whether the function + // is static or not (if it is a member function) + + // Calling convention ("callingConvention" in DIA) + if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, Index, TI_GET_CALLING_CONVENTION, &CallConv)) + return FALSE; + + // Parent class type index ("classParent" in DIA) + if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, Index, TI_GET_CLASSPARENTID, &ClassIndex)) + { + // The function is not a member function + Info->ClassIndex = 0; + Info->MemberFunction = FALSE; + } + else + { + // This is a member function of a class + Info->ClassIndex = ClassIndex; + Info->MemberFunction = TRUE; + } + + // If this is a member function, obtain additional data + if (Info->MemberFunction) + { + LONG ThisAdjust = 0; + + // "this" adjustment ("thisAdjust" in DIA) + if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, Index, TI_GET_THISADJUST, &ThisAdjust)) + return FALSE; + + Info->ThisAdjust = ThisAdjust; + } + + // Test for GetChildren() + /* + ULONG cMaxChildren = 4; + ULONG Children[cMaxChildren]; + ULONG NumChildren = 0; + + if( !GetChildren( m_hProcess, BaseAddress, Index, Children, NumChildren, cMaxChildren ) ) + { + ULONG ErrCode = 0; + _ASSERTE( !_T("GetChildren() failed.") ); + } + else + { + ULONG ErrCode = 0; + } + */ + + // Dump function arguments + if (!SymInfoDump_FunctionArguments(Context, Index, Info->Args, &Info->NumArgs, ARRAYSIZE(Info->Args))) + return FALSE; + + // Is the function static ? (If it is a member function) + if (Info->MemberFunction) + { + // The function is static if the value of Count property + // it the same as the number of child FunctionArgType symbols + Info->StaticFunction = (NumArgs == Info->NumArgs); + } + + Info->RetTypeIndex = RetTypeIndex; + Info->CallConv = (CV_call_e)CallConv; + + return TRUE; +} + +BOOLEAN SymInfoDump_DumpFunctionArgType( + _Inout_ PPDB_SYMBOL_CONTEXT Context, + _In_ ULONG Index, + _Inout_ FunctionArgTypeInfo *Info + ) +{ + ULONG typeIndex = 0; + + if (!SymInfoDump_CheckTag(Context, Index, SymTagFunctionArgType)) + return FALSE; + + // Index of the argument type ("typeId" in DIA) + if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, Index, TI_GET_TYPEID, &typeIndex)) + return FALSE; + + Info->TypeIndex = typeIndex; + + return TRUE; +} + +BOOLEAN SymInfoDump_DumpBaseClass( + _Inout_ PPDB_SYMBOL_CONTEXT Context, + _In_ ULONG Index, + _Inout_ BaseClassInfo *Info + ) +{ + ULONG typeIndex = 0; + ULONG virtualBase = 0; + + if (!SymInfoDump_CheckTag(Context, Index, SymTagBaseClass)) + return FALSE; + + // Base class UDT + if (!SymGetTypeInfo_I( + NtCurrentProcess(), + Context->BaseAddress, + Index, + TI_GET_TYPEID, + &typeIndex + )) + { + return FALSE; + } + + // Is this base class virtual ? + if (!SymGetTypeInfo_I( + NtCurrentProcess(), + Context->BaseAddress, + Index, + TI_GET_VIRTUALBASECLASS, + &virtualBase + )) + { + return FALSE; + } + + Info->TypeIndex = typeIndex; + Info->Virtual = (virtualBase != 0); + + if (virtualBase) + { + ULONG virtualBasePtrOffset = 0; + + // Virtual base pointer offset + if (!SymGetTypeInfo_I( + NtCurrentProcess(), + Context->BaseAddress, + Index, + TI_GET_VIRTUALBASEPOINTEROFFSET, + &virtualBasePtrOffset + )) + { + return FALSE; + } + + Info->Offset = 0; + Info->VirtualBasePointerOffset = virtualBasePtrOffset; + } + else + { + ULONG offset = 0; + + // Offset in the parent UDT + if (!SymGetTypeInfo_I( + NtCurrentProcess(), + Context->BaseAddress, + Index, + TI_GET_OFFSET, + &offset + )) + { + return FALSE; + } + + Info->Offset = offset; + Info->VirtualBasePointerOffset = 0; + } + + return TRUE; +} + +BOOLEAN SymInfoDump_DumpData( + _Inout_ PPDB_SYMBOL_CONTEXT Context, + _In_ ULONG Index, + _Inout_ DataInfo *Info + ) +{ + PWSTR symbolName = NULL; + ULONG TypeIndex = 0; + ULONG dataKind = 0; + + if (!SymInfoDump_CheckTag(Context, Index, SymTagData)) + return FALSE; + + // Name ("name" in DIA) + if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, Index, TI_GET_SYMNAME, &symbolName) || !symbolName) + return FALSE; + + wcsncpy(Info->Name, symbolName, ARRAYSIZE(Info->Name)); + Info->Name[ARRAYSIZE(Info->Name) - 1] = 0; + LocalFree(symbolName); + + // Index of type symbol ("typeId" in DIA) + if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, Index, TI_GET_TYPEID, &TypeIndex)) + return FALSE; + + // Data kind ("dataKind" in DIA) + if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, Index, TI_GET_DATAKIND, &dataKind)) + return FALSE; + + Info->TypeIndex = TypeIndex; + Info->dataKind = (DataKind)dataKind; + + // Location, depending on the data kind + switch (dataKind) + { + case DataIsGlobal: + case DataIsStaticLocal: + case DataIsFileStatic: + case DataIsStaticMember: + { + // Use Address; Offset is not defined + // Note: If it is DataIsStaticMember, then this is a static member of a class defined in another module + // (it does not have an address in this module) + + ULONG64 address = 0; + + if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, Index, TI_GET_ADDRESS, &address)) + return FALSE; + + Info->Address = address; + Info->Offset = 0; + } + break; + + case DataIsLocal: + case DataIsParam: + case DataIsObjectPtr: + case DataIsMember: + { + // Use Offset; Address is not defined + ULONG offset = 0; + + if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, Index, TI_GET_OFFSET, &offset)) + return FALSE; + + Info->Offset = offset; + Info->Address = 0; + } + break; + + default: + // Unknown location + Info->Address = 0; + Info->Offset = 0; + break; + } + + return TRUE; +} + +BOOLEAN SymInfoDump_DumpType( + _Inout_ PPDB_SYMBOL_CONTEXT Context, + _In_ ULONG Index, + _Inout_ TypeInfo *Info + ) +{ + ULONG tag = SymTagNull; + BOOLEAN result = FALSE; + + // Get the symbol's tag + if (!SymGetTypeInfo_I( + NtCurrentProcess(), + Context->BaseAddress, + Index, + TI_GET_SYMTAG, + &tag + )) + { + return FALSE; + } + + Info->Tag = (enum SymTagEnum)tag; + + // Dump information about the symbol (depending on the tag). + switch (tag) + { + case SymTagBaseType: + result = SymInfoDump_DumpBasicType(Context, Index, &Info->sBaseTypeInfo); + break; + case SymTagPointerType: + result = SymInfoDump_DumpPointerType(Context, Index, &Info->sPointerTypeInfo); + break; + case SymTagTypedef: + result = SymInfoDump_DumpTypedef(Context, Index, &Info->sTypedefInfo); + break; + case SymTagEnum: + result = SymInfoDump_DumpEnum(Context, Index, &Info->sEnumInfo); + break; + case SymTagArrayType: + result = SymInfoDump_DumpArrayType(Context, Index, &Info->sArrayTypeInfo); + break; + case SymTagUDT: + result = SymInfoDump_DumpUDT(Context, Index, Info); + break; + case SymTagFunctionType: + result = SymInfoDump_DumpFunctionType(Context, Index, &Info->sFunctionTypeInfo); + break; + case SymTagFunctionArgType: + result = SymInfoDump_DumpFunctionArgType(Context, Index, &Info->sFunctionArgTypeInfo); + break; + case SymTagBaseClass: + result = SymInfoDump_DumpBaseClass(Context, Index, &Info->sBaseClassInfo); + break; + case SymTagData: + result = SymInfoDump_DumpData(Context, Index, &Info->sDataInfo); + break; + } + + return result; +} + +BOOLEAN SymInfoDump_DumpSymbolType( + _Inout_ PPDB_SYMBOL_CONTEXT Context, + _In_ ULONG Index, + _Inout_ TypeInfo *Info, + _Inout_ ULONG *TypeIndex + ) +{ + // Obtain the index of the symbol's type symbol + if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, Index, TI_GET_TYPEID, &TypeIndex)) + return FALSE; + + // Dump the type symbol + return SymInfoDump_DumpType(Context, *TypeIndex, Info); +} + +BOOLEAN SymInfoDump_CheckTag( + _Inout_ PPDB_SYMBOL_CONTEXT Context, + _In_ ULONG Index, + _In_ ULONG Tag + ) +{ + ULONG symTag = SymTagNull; + + if (!SymGetTypeInfo_I( + NtCurrentProcess(), + Context->BaseAddress, + Index, + TI_GET_SYMTAG, + &symTag + )) + { + return FALSE; + } + + return symTag == Tag; +} + +BOOLEAN SymInfoDump_SymbolSize( + _Inout_ PPDB_SYMBOL_CONTEXT Context, + _In_ ULONG Index, + _Inout_ ULONG64* Size + ) +{ + ULONG index; + ULONG64 length = 0; + + // Does the symbol support "length" property ? + if (SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, Index, TI_GET_LENGTH, &length)) + { + *Size = length; + return TRUE; + } + else + { + // No, it does not - it can be SymTagTypedef + if (!SymInfoDump_CheckTag(Context, Index, SymTagTypedef)) + { + // No, this symbol does not have length + return FALSE; + } + else + { + // Yes, it is a SymTagTypedef - skip to its underlying type + index = Index; + + do + { + ULONG tempIndex = 0; + + if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, index, TI_GET_TYPEID, &tempIndex)) + return FALSE; + + index = tempIndex; + + } while (SymInfoDump_CheckTag(Context, index, SymTagTypedef)); + + // And get the length + if (SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, index, TI_GET_LENGTH, &length)) + { + *Size = length; + return TRUE; + } + } + } + + return FALSE; +} + +BOOLEAN SymInfoDump_ArrayElementTypeIndex( + _Inout_ PPDB_SYMBOL_CONTEXT Context, + _In_ ULONG ArrayIndex, + _Inout_ ULONG* ElementTypeIndex + ) +{ + ULONG index; + ULONG elementIndex = 0; + + if (!SymInfoDump_CheckTag(Context, ArrayIndex, SymTagArrayType)) + return FALSE; + + // Get the array element type + if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, ArrayIndex, TI_GET_TYPEID, &elementIndex)) + return FALSE; + + // If the array element type is SymTagArrayType, skip to its type + index = elementIndex; + + while (SymInfoDump_CheckTag(Context, elementIndex, SymTagArrayType)) + { + if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, index, TI_GET_TYPEID, &elementIndex)) + return FALSE; + + index = elementIndex; + } + + // We have found the ultimate type of the array element + *ElementTypeIndex = elementIndex; + + return TRUE; +} + +BOOLEAN SymInfoDump_ArrayDims( + _Inout_ PPDB_SYMBOL_CONTEXT Context, + _In_ ULONG Index, + _Inout_ ULONG64* pDims, + _Inout_ ULONG* Dims, + _In_ ULONG MaxDims + ) +{ + ULONG index; + ULONG dimCount; + + if (!SymInfoDump_CheckTag(Context, Index, SymTagArrayType)) + return FALSE; + + if (MaxDims <= 0) + return FALSE; + + index = Index; + dimCount = 0; + + for (ULONG i = 0; i < MaxDims; i++) + { + ULONG typeIndex = 0; + ULONG64 length = 0; + ULONG64 typeSize = 0; + + // Length ("length" in DIA) + if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, index, TI_GET_LENGTH, &length) || (length == 0)) + return FALSE; + + // Size of the current dimension + // (it is the size of its SymTagArrayType symbol divided by the size of its + // type symbol, which can be another SymTagArrayType symbol or the array element symbol) + + // Its type + if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, index, TI_GET_TYPEID, &typeIndex)) + { + // No type - we are done + break; + } + + // Size of its type + if (!SymInfoDump_SymbolSize(Context, typeIndex, &typeSize) || (typeSize == 0)) + return FALSE; + + // Size of the dimension + pDims[i] = length / typeSize; + dimCount++; + + // Test only +/* + ULONG ElemCount = 0; + if( !SymGetTypeInfo_I( m_hProcess, BaseAddress, CurIndex, TI_GET_COUNT, &ElemCount ) ) + { + // and continue ... + } + else if( ElemCount != pDims[i] ) + { + _ASSERTE( !_T("TI_GET_COUNT does not match.") ); + } + else + { + //_ASSERTE( !_T("TI_GET_COUNT works!") ); + } +*/ + // If the type symbol is not SymTagArrayType, we are done + if (!SymInfoDump_CheckTag(Context, typeIndex, SymTagArrayType)) + break; + + index = typeIndex; + } + + if (dimCount == 0) + return FALSE; + + *Dims = dimCount; + + return TRUE; +} + +BOOLEAN SymInfoDump_UdtVariables( + _Inout_ PPDB_SYMBOL_CONTEXT Context, + _In_ ULONG Index, + _Inout_ ULONG* pVars, + _Inout_ ULONG* Vars, + _In_ ULONG MaxVars + ) +{ + ULONG childrenLength = 0; + + if (!SymInfoDump_CheckTag(Context, Index, SymTagUDT)) + return FALSE; + + if (MaxVars <= 0) + return FALSE; + + // Get the number of children + if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, Index, TI_GET_CHILDRENCOUNT, &childrenLength)) + return FALSE; + + if (childrenLength == 0) + { + *Vars = 0; + return TRUE; // No children -> no member variables + } + + // Get the children + ULONG FindChildrenSize = sizeof(TI_FINDCHILDREN_PARAMS) + childrenLength * sizeof(ULONG); + TI_FINDCHILDREN_PARAMS* params = (TI_FINDCHILDREN_PARAMS*)_alloca(FindChildrenSize); + memset(params, 0, FindChildrenSize); + params->Count = childrenLength; + + if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, Index, TI_FINDCHILDREN, params)) + return FALSE; + + *Vars = 0; + + // Enumerate children, looking for base classes, and copy their indexes. + for (ULONG i = 0; i < childrenLength; i++) + { + if (SymInfoDump_CheckTag(Context, params->ChildId[i], SymTagData)) + { + pVars[*Vars] = params->ChildId[i]; + + (*Vars)++; + + if (*Vars == MaxVars) + break; + } + } + + return TRUE; +} + +BOOLEAN SymInfoDump_UdtFunctions( + _Inout_ PPDB_SYMBOL_CONTEXT Context, + _In_ ULONG Index, + _Inout_ ULONG* pFuncs, + _Inout_ ULONG* Funcs, + _In_ ULONG MaxFuncs + ) +{ + ULONG childrenLength = 0; + + if (!SymInfoDump_CheckTag(Context, Index, SymTagUDT)) + return FALSE; + + if (MaxFuncs <= 0) + return FALSE; + + // Get the number of children + if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, Index, TI_GET_CHILDRENCOUNT, &childrenLength)) + return FALSE; + + if (childrenLength == 0) + { + *Funcs = 0; // No children -> no member variables + return TRUE; + } + + // Get the children + ULONG FindChildrenSize = sizeof(TI_FINDCHILDREN_PARAMS) + childrenLength * sizeof(ULONG); + TI_FINDCHILDREN_PARAMS* params = (TI_FINDCHILDREN_PARAMS*)_alloca(FindChildrenSize); + memset(params, 0, FindChildrenSize); + + params->Count = childrenLength; + + if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, Index, TI_FINDCHILDREN, params)) + return FALSE; + + *Funcs = 0; + + // Enumerate children, looking for base classes, and copy their indexes. + for (ULONG i = 0; i < childrenLength; i++) + { + if (SymInfoDump_CheckTag(Context, params->ChildId[i], SymTagFunction)) + { + pFuncs[*Funcs] = params->ChildId[i]; + + (*Funcs)++; + + if (*Funcs == MaxFuncs) + break; + } + } + + return TRUE; +} + +BOOLEAN SymInfoDump_UdtBaseClasses( + _Inout_ PPDB_SYMBOL_CONTEXT Context, + _In_ ULONG Index, + _Inout_ ULONG* pBases, + _Inout_ ULONG* Bases, + _In_ ULONG MaxBases + ) +{ + ULONG childrenLength = 0; + + if (!SymInfoDump_CheckTag(Context, Index, SymTagUDT)) + return FALSE; + + if (MaxBases <= 0) + return FALSE; + + // Get the number of children + if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, Index, TI_GET_CHILDRENCOUNT, &childrenLength)) + return FALSE; + + if (childrenLength == 0) + { + *Bases = 0; // No children -> no member variables + return TRUE; + } + + // Get the children + ULONG FindChildrenSize = sizeof(TI_FINDCHILDREN_PARAMS) + childrenLength * sizeof(ULONG); + TI_FINDCHILDREN_PARAMS* params = (TI_FINDCHILDREN_PARAMS*)_alloca(FindChildrenSize); + memset(params, 0, FindChildrenSize); + + params->Count = childrenLength; + + if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, Index, TI_FINDCHILDREN, params)) + return FALSE; + + *Bases = 0; + + // Enumerate children, looking for base classes, and copy their indexes. + for (ULONG i = 0; i < childrenLength; i++) + { + if (SymInfoDump_CheckTag(Context, params->ChildId[i], SymTagBaseClass)) + { + pBases[*Bases] = params->ChildId[i]; + + (*Bases)++; + + if (*Bases == MaxBases) + break; + } + } + + return TRUE; +} + +BOOLEAN SymInfoDump_UdtUnionMembers( + _Inout_ PPDB_SYMBOL_CONTEXT Context, + _In_ ULONG Index, + _Inout_ ULONG* pMembers, + _Inout_ ULONG* Members, + _In_ ULONG MaxMembers + ) +{ + ULONG childrenLength = 0; + + if (!SymInfoDump_CheckTag(Context, Index, SymTagUDT)) + return FALSE; + + if (MaxMembers <= 0) + return FALSE; + + // Get the number of children + if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, Index, TI_GET_CHILDRENCOUNT, &childrenLength)) + return FALSE; + + if (childrenLength == 0) + { + *Members = 0; + return TRUE; // No children -> no members + } + + // Get the children + ULONG FindChildrenSize = sizeof(TI_FINDCHILDREN_PARAMS) + childrenLength * sizeof(ULONG); + TI_FINDCHILDREN_PARAMS* params = (TI_FINDCHILDREN_PARAMS*)_alloca(FindChildrenSize); + memset(params, 0, FindChildrenSize); + + params->Count = childrenLength; + + if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, Index, TI_FINDCHILDREN, params)) + return FALSE; + + *Members = 0; + + // Enumerate children, looking for enumerators, and copy their indexes. + for (ULONG i = 0; i < childrenLength; i++) + { + if (SymInfoDump_CheckTag(Context, params->ChildId[i], SymTagData)) + { + pMembers[*Members] = params->ChildId[i]; + + (*Members)++; + + if (*Members == MaxMembers) + break; + } + } + + return TRUE; +} + +BOOLEAN SymInfoDump_FunctionArguments( + _Inout_ PPDB_SYMBOL_CONTEXT Context, + _In_ ULONG Index, + _Inout_ ULONG* pArgs, + _Inout_ ULONG* Args, + _In_ ULONG MaxArgs + ) +{ + ULONG childrenLength = 0; + + if (!SymInfoDump_CheckTag(Context, Index, SymTagFunctionType)) + return FALSE; + + if (MaxArgs <= 0) + return FALSE; + + // Get the number of children + if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, Index, TI_GET_CHILDRENCOUNT, &childrenLength)) + return FALSE; + + if (childrenLength == 0) + { + *Args = 0; + return TRUE; // No children -> no member variables + } + + // Get the children + ULONG FindChildrenSize = sizeof(TI_FINDCHILDREN_PARAMS) + childrenLength * sizeof(ULONG); + TI_FINDCHILDREN_PARAMS* params = (TI_FINDCHILDREN_PARAMS*)_alloca(FindChildrenSize); + memset(params, 0, FindChildrenSize); + + params->Count = childrenLength; + + if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, Index, TI_FINDCHILDREN, params)) + return FALSE; + + *Args = 0; + + // Enumerate children, looking for enumerators, and copy their indexes. + for (ULONG i = 0; i < childrenLength; i++) + { + if (SymInfoDump_CheckTag(Context, params->ChildId[i], SymTagFunctionArgType)) + { + pArgs[*Args] = params->ChildId[i]; + + (*Args)++; + + if (*Args == MaxArgs) + break; + } + } + + return TRUE; +} + +BOOLEAN SymInfoDump_Enumerators( + _Inout_ PPDB_SYMBOL_CONTEXT Context, + _In_ ULONG Index, + _Inout_ ULONG *pEnums, + _Inout_ ULONG *Enums, + _In_ ULONG MaxEnums + ) +{ + ULONG childrenLength = 0; + + if (!SymInfoDump_CheckTag(Context, Index, SymTagEnum)) + return FALSE; + + if (MaxEnums <= 0) + return FALSE; + + // Get the number of children + if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, Index, TI_GET_CHILDRENCOUNT, &childrenLength)) + return FALSE; + + if (childrenLength == 0) + { + // No children -> no enumerators + *Enums = 0; + return TRUE; + } + + ULONG FindChildrenSize = sizeof(TI_FINDCHILDREN_PARAMS) + childrenLength * sizeof(ULONG); + TI_FINDCHILDREN_PARAMS* params = (TI_FINDCHILDREN_PARAMS*)_alloca(FindChildrenSize); + memset(params, 0, FindChildrenSize); + params->Count = childrenLength; + + // Get the children + if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, Index, TI_FINDCHILDREN, params)) + return FALSE; + + *Enums = 0; + + // Enumerate children, looking for enumerators, and copy their indexes. + for (ULONG i = 0; i < childrenLength; i++) + { + if (SymInfoDump_CheckTag(Context, params->ChildId[i], SymTagData)) + { + pEnums[*Enums] = params->ChildId[i]; + + (*Enums)++; + + if (*Enums == MaxEnums) + break; + } + } + + return TRUE; +} + +BOOLEAN SymInfoDump_TypeDefType( + _Inout_ PPDB_SYMBOL_CONTEXT Context, + _In_ ULONG Index, + _Inout_ ULONG *UndTypeIndex + ) +{ + ULONG index; + + if (!SymInfoDump_CheckTag(Context, Index, SymTagTypedef)) + return FALSE; + + // Skip to the type behind the type definition + index = Index; + + while (SymInfoDump_CheckTag(Context, index, SymTagTypedef)) + { + if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, index, TI_GET_TYPEID, UndTypeIndex)) + return FALSE; + + index = *UndTypeIndex; + } + + return TRUE; +} + +BOOLEAN SymInfoDump_PointerType( + _Inout_ PPDB_SYMBOL_CONTEXT Context, + _In_ ULONG Index, + _Inout_ ULONG *UndTypeIndex, + _Inout_ ULONG *NumPointers + ) +{ + ULONG index; + + if (!SymInfoDump_CheckTag(Context, Index, SymTagPointerType)) + return FALSE; + + // Skip to the type pointer points to + *NumPointers = 0; + index = Index; + + while (SymInfoDump_CheckTag(Context, index, SymTagPointerType)) + { + if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, index, TI_GET_TYPEID, UndTypeIndex)) + return FALSE; + + (*NumPointers)++; + + index = *UndTypeIndex; + } + + return TRUE; +} + +BOOLEAN SymInfoDump_GetTypeNameHelper( + _In_ ULONG Index, + _Inout_ PPDB_SYMBOL_CONTEXT Obj, + _Out_ PWSTR *VarName, + _Out_ PWSTR *TypeName + ) +{ + TypeInfo Info; + + // Get the type information + if (!SymInfoDump_DumpType(Obj, Index, &Info)) + { + return FALSE; + } + else + { + // Is it a pointer ? + ULONG numPointers = 0; + + if (Info.Tag == SymTagPointerType) + { + // Yes, get the number of * to show + ULONG typeIndex = 0; + + if (!SymInfoDump_PointerType(Obj, Index, &typeIndex, &numPointers)) + return FALSE; + + // Get more information about the type the pointer points to + if (!SymInfoDump_DumpType(Obj, typeIndex, &Info)) + return FALSE; + + // Save the index of the type the pointer points to + Index = typeIndex; + + // ... and proceed with that type + } + + switch (Info.Tag) + { + case SymTagBaseType: + *TypeName = SymInfoDump_BaseTypeStr(Info.sBaseTypeInfo.BaseType, Info.sBaseTypeInfo.Length); + break; + + case SymTagTypedef: + *TypeName = _wcsdup(Info.sTypedefInfo.Name); + break; + + case SymTagUDT: + { + if (Info.UdtKind) + { + // A class/structure + *TypeName = _wcsdup(Info.sUdtClassInfo.Name); + + // Add the UDT and its base classes to the collection of UDT indexes + PhAddItemList(Obj->UdtList, UlongToPtr(Index)); + } + else + { + // A union + *TypeName = _wcsdup(Info.sUdtUnionInfo.Name); + } + } + break; + + case SymTagEnum: + *TypeName = _wcsdup(Info.sEnumInfo.Name); + break; + + case SymTagFunctionType: + { + if (Info.sFunctionTypeInfo.MemberFunction && Info.sFunctionTypeInfo.StaticFunction) + { + //*TypeName = L"static "; + } + + // Print return value + if (!SymInfoDump_GetTypeNameHelper(Info.sFunctionTypeInfo.RetTypeIndex, Obj, VarName, TypeName)) + return FALSE; + + // Print calling convention + //TypeName += " "; + //TypeName += SymInfoDump_CallConvStr(Info.Info.sFunctionTypeInfo.CallConv); + //TypeName += " "; + + // If member function, save the class type index + if (Info.sFunctionTypeInfo.MemberFunction) + { + PhAddItemList(Obj->UdtList, UlongToPtr(Info.sFunctionTypeInfo.ClassIndex)); + + /* + // It is not needed to print the class name here, because + // it is contained in the function name + if( !SymInfoDump_GetTypeNameHelper( Info.Info.sFunctionTypeInfo.ClassIndex, Obj, VarName, TypeName ) ) + return false; + + TypeName += "::"); + */ + } + + // Print that it is a function + //TypeName += VarName; + // Print parameters + //TypeName += " ("; + for (ULONG i = 0; i < Info.sFunctionTypeInfo.NumArgs; i++) + { + if (!SymInfoDump_GetTypeNameHelper(Info.sFunctionTypeInfo.Args[i], Obj, VarName, TypeName)) + return FALSE; + + //if (i < (Info.sFunctionTypeInfo.NumArgs - 1)) + //TypeName += ", "; + } + //TypeName += ")"; + + // Print "this" adjustment value + if (Info.sFunctionTypeInfo.MemberFunction && Info.sFunctionTypeInfo.ThisAdjust != 0) + { + WCHAR buffer[MAX_PATH + 1] = L""; + + //TypeName += "ThisAdjust: "; + _snwprintf(buffer, ARRAYSIZE(buffer), L"this+%u", Info.sFunctionTypeInfo.ThisAdjust); + //TypeName += buffer; + + *TypeName = _wcsdup(buffer); + } + } + break; + + case SymTagFunctionArgType: + { + if (!SymInfoDump_GetTypeNameHelper(Info.sFunctionArgTypeInfo.TypeIndex, Obj, VarName, TypeName)) + return FALSE; + } + break; + + case SymTagArrayType: + { + // Print element type name + if (!SymInfoDump_GetTypeNameHelper(Info.sArrayTypeInfo.ElementTypeIndex, Obj, VarName, TypeName)) + return FALSE; + + //TypeName += " "; + //TypeName += VarName; + + // Print dimensions + for (ULONG i = 0; i < Info.sArrayTypeInfo.NumDimensions; i++) + { + //WCHAR buffer[MAX_PATH + 1] = L""; + //_snwprintf(buffer, cTempBufSize, "[%u]"), Info.Info.sArrayTypeInfo.Dimensions[i]); + //TypeName += buffer; + } + } + break; + default: + { + WCHAR buffer[MAX_PATH + 1] = L""; + + _snwprintf(buffer, ARRAYSIZE(buffer), L"Unknown(%lu)", Info.Tag); + + *TypeName = _wcsdup(buffer); + } + break; + } + + // If it is a pointer, display * characters + if (numPointers != 0) + { + //for (ULONG i = 0; i < NumPointers; i++) + // TypeName += "*"; + } + } + + return TRUE; +} + +BOOLEAN SymInfoDump_GetTypeName( + _Inout_ PPDB_SYMBOL_CONTEXT Context, + _In_ ULONG Index, + _In_ PWSTR pVarName, + _In_ PWSTR pTypeName, + _In_ ULONG MaxChars + ) +{ + PWSTR VarName = NULL; + PWSTR TypeName = NULL; + + if (!pTypeName) + return FALSE; + + if (pVarName) + VarName = pVarName; + + // Obtain the type name + if (!SymInfoDump_GetTypeNameHelper(Index, Context, &VarName, &TypeName)) + return FALSE; + + if (!wcslen(TypeName)) + return FALSE; + + // Return the type name to the caller + _snwprintf(pTypeName, MaxChars, L"%s", TypeName); + + return TRUE; +} + +/////////////////////////////////////////////////////////////////////////////// +// Data-to-string conversion functions +PWSTR SymInfoDump_TagStr( + _In_ enum SymTagEnum Tag + ) +{ + switch (Tag) + { + case SymTagNull: + return L"Null"; + case SymTagExe: + return L"Exe"; + case SymTagCompiland: + return L"Compiland"; + case SymTagCompilandDetails: + return L"CompilandDetails"; + case SymTagCompilandEnv: + return L"CompilandEnv"; + case SymTagFunction: + return L"Function"; + case SymTagBlock: + return L"Block"; + case SymTagData: + return L"Data"; + case SymTagAnnotation: + return L"Annotation"; + case SymTagLabel: + return L"Label"; + case SymTagPublicSymbol: + return L"PublicSymbol"; + case SymTagUDT: + return L"UDT"; + case SymTagEnum: + return L"Enum"; + case SymTagFunctionType: + return L"FunctionType"; + case SymTagPointerType: + return L"PointerType"; + case SymTagArrayType: + return L"ArrayType"; + case SymTagBaseType: + return L"BaseType"; + case SymTagTypedef: + return L"Typedef"; + case SymTagBaseClass: + return L"BaseClass"; + case SymTagFriend: + return L"Friend"; + case SymTagFunctionArgType: + return L"FunctionArgType"; + case SymTagFuncDebugStart: + return L"FuncDebugStart"; + case SymTagFuncDebugEnd: + return L"FuncDebugEnd"; + case SymTagUsingNamespace: + return L"UsingNamespace"; + case SymTagVTableShape: + return L"VTableShape"; + case SymTagVTable: + return L"VTable"; + case SymTagCustom: + return L"Custom"; + case SymTagThunk: + return L"Thunk"; + case SymTagCustomType: + return L"CustomType"; + case SymTagManagedType: + return L"ManagedType"; + case SymTagDimension: + return L"Dimension"; + } + + return L"Unknown"; + +} + +PWSTR SymInfoDump_BaseTypeStr( + _In_ BasicType Type, + _In_ ULONG64 Length + ) +{ + switch (Type) + { + case btNoType: + return L"NoType"; + case btVoid: + return L"void"; + case btChar: + return L"char"; + case btWChar: + return L"wchar_t"; + case btInt: + { + if (Length == 0) + { + return L"int"; + } + else + { + if (Length == 1) + return L"char"; + else if (Length == 2) + return L"short"; + else + return L"int"; + } + } + case btUInt: + { + if (Length == 0) + { + return L"unsigned int"; + } + else + { + if (Length == 1) + return L"unsigned char"; + else if (Length == 2) + return L"unsigned short"; + else + return L"unsigned int"; + } + } + break; + case btFloat: + { + if (Length == 0) + { + return L"float"; + } + else + { + if (Length == 4) + return L"float"; + else + return L"double"; + } + } + break; + case btBCD: + return L"BCD"; + case btBool: + return L"bool"; + case btLong: + return L"long"; + case btULong: + return L"unsigned long"; + case btCurrency: + return L"Currency"; + case btDate: + return L"Date"; + case btVariant: + return L"Variant"; + case btComplex: + return L"Complex"; + case btBit: + return L"Bit"; + case btBSTR: + return L"BSTR"; + case btHresult: + return L"HRESULT"; + } + + return L"Unknown"; + +} + +PWSTR SymInfoDump_CallConvStr( + _In_ CV_call_e CallConv + ) +{ + switch (CallConv) + { + case CV_CALL_NEAR_C: + return L"NEAR_C"; + case CV_CALL_FAR_C: + return L"FAR_C"; + case CV_CALL_NEAR_PASCAL: + return L"NEAR_PASCAL"; + case CV_CALL_FAR_PASCAL: + return L"FAR_PASCAL"; + case CV_CALL_NEAR_FAST: + return L"NEAR_FAST"; + case CV_CALL_FAR_FAST: + return L"FAR_FAST"; + case CV_CALL_SKIPPED: + return L"SKIPPED"; + case CV_CALL_NEAR_STD: + return L"NEAR_STD"; + case CV_CALL_FAR_STD: + return L"FAR_STD"; + case CV_CALL_NEAR_SYS: + return L"NEAR_SYS"; + case CV_CALL_FAR_SYS: + return L"FAR_SYS"; + case CV_CALL_THISCALL: + return L"THISCALL"; + case CV_CALL_MIPSCALL: + return L"MIPSCALL"; + case CV_CALL_GENERIC: + return L"GENERIC"; + case CV_CALL_ALPHACALL: + return L"ALPHACALL"; + case CV_CALL_PPCCALL: + return L"PPCCALL"; + case CV_CALL_SHCALL: + return L"SHCALL"; + case CV_CALL_ARMCALL: + return L"ARMCALL"; + case CV_CALL_AM33CALL: + return L"AM33CALL"; + case CV_CALL_TRICALL: + return L"TRICALL"; + case CV_CALL_SH5CALL: + return L"SH5CALL"; + case CV_CALL_M32RCALL: + return L"M32RCALL"; + case CV_CALL_RESERVED: + return L"RESERVED"; + } + + return L"UNKNOWN"; + +} + +PWSTR SymInfoDump_DataKindFromSymbolInfo( + _In_ PSYMBOL_INFOW SymbolInfo + ) +{ + ULONG dataKindType = 0; + + if (!SymGetTypeInfo_I(NtCurrentProcess(), SymbolInfo->ModBase, SymbolInfo->Index, TI_GET_DATAKIND, &dataKindType)) + return L"UNKNOWN"; + + return SymInfoDump_DataKindStr(dataKindType); +} + +PWSTR SymInfoDump_DataKindStr( + _In_ DataKind SymDataKind + ) +{ + switch (SymDataKind) + { + case DataIsLocal: + return L"LOCAL_VAR"; + case DataIsStaticLocal: + return L"STATIC_LOCAL_VAR"; + case DataIsParam: + return L"PARAMETER"; + case DataIsObjectPtr: + return L"OBJECT_PTR"; + case DataIsFileStatic: + return L"STATIC_VAR"; + case DataIsGlobal: + return L"GLOBAL_VAR"; + case DataIsMember: + return L"MEMBER"; + case DataIsStaticMember: + return L"STATIC_MEMBER"; + case DataIsConstant: + return L"CONSTANT"; + } + + return L"UNKNOWN"; +} + +VOID SymInfoDump_SymbolLocationStr( + _In_ PSYMBOL_INFOW SymbolInfo, + _In_ PWSTR Buffer + ) +{ + if (SymbolInfo->Flags & SYMFLAG_REGISTER) + { + PWSTR regString = SymInfoDump_RegisterStr((CV_HREG_e)SymbolInfo->Register); + + if (regString) + wcscpy(Buffer, regString); + else + _swprintf(Buffer, L"Reg%u", SymbolInfo->Register); + + return; + } + else if (SymbolInfo->Flags & SYMFLAG_REGREL) + { + WCHAR szReg[32]; + PWSTR regString = SymInfoDump_RegisterStr((CV_HREG_e)SymbolInfo->Register); + + if (regString) + wcscpy(szReg, regString); + else + _swprintf(szReg, L"Reg%u", SymbolInfo->Register); + + _swprintf(Buffer, L"%s%+lu", szReg, (long)SymbolInfo->Address); + + return; + } + else if (SymbolInfo->Flags & SYMFLAG_FRAMEREL) + { + wcscpy(Buffer, L"N/A"); + return; + } + else + { + //_swprintf(Buffer, L"%16I64x", SymbolInfo->Address); + PhPrintPointer(Buffer, (PVOID)SymbolInfo->Address); + } +} + +PWSTR SymInfoDump_RegisterStr( + _In_ CV_HREG_e RegCode + ) +{ + switch (RegCode) + { + case CV_REG_EAX: + return L"EAX"; + case CV_REG_ECX: + return L"ECX"; + case CV_REG_EDX: + return L"EDX"; + case CV_REG_EBX: + return L"EBX"; + case CV_REG_ESP: + return L"ESP"; + case CV_REG_EBP: + return L"EBP"; + case CV_REG_ESI: + return L"ESI"; + case CV_REG_EDI: + return L"EDI"; + } + + return L"Unknown"; +} + +PWSTR SymInfoDump_UdtKindStr( + _In_ UdtKind KindType + ) +{ + switch (KindType) + { + case UdtStruct: + return L"STRUCT"; + case UdtClass: + return L"CLASS"; + case UdtUnion: + return L"UNION"; + } + + return L"UNKNOWN"; +} + +PWSTR SymInfoDump_LocationTypeStr( + _In_ LocationType LocType + ) +{ + switch (LocType) + { + case LocIsNull: + return L"Null"; + case LocIsStatic: + return L"Static"; + case LocIsTLS: + return L"TLS"; + case LocIsRegRel: + return L"RegRel"; + case LocIsThisRel: + return L"ThisRel"; + case LocIsEnregistered: + return L"Enregistered"; + case LocIsBitField: + return L"BitField"; + case LocIsSlot: + return L"Slot"; + case LocIsIlRel: + return L"IlRel"; + case LocInMetaData: + return L"MetaData"; + case LocIsConstant: + return L"Constant"; + } + + return L"Unknown"; +} + +/////////////////////////////////////////////////////////////////////////////// + +BOOL CALLBACK EnumCallbackProc( + _In_ PSYMBOL_INFOW SymbolInfo, + _In_ ULONG SymbolSize, + _In_ PVOID Context + ) +{ + if (!SymbolInfo) // Try to enumerate other symbols + return TRUE; + + switch (SymbolInfo->Tag) + { + case SymTagFunction: + PrintFunctionInfo(Context, SymbolInfo); + break; + case SymTagData: + PrintDataInfo(Context, SymbolInfo); + break; + default: + PrintDefaultInfo(Context, SymbolInfo); + break; + } + + return TRUE; +} + +VOID PrintDataInfo( + _In_ PPDB_SYMBOL_CONTEXT Context, + _In_ PSYMBOL_INFOW SymbolInfo + ) +{ + INT lvItemIndex; + PWSTR symDataKind; + WCHAR pointer[PH_PTR_STR_LEN_1] = L""; + + if (SymbolInfo->Tag != SymTagData) + return; + + // Type + symDataKind = SymInfoDump_DataKindFromSymbolInfo(SymbolInfo); + lvItemIndex = PhAddListViewItem(Context->ListviewHandle, MAXINT, symDataKind, NULL); + + // Name + PhSetListViewSubItem(Context->ListviewHandle, lvItemIndex, 1, SymbolInfo->Name); + + // Address + SymInfoDump_SymbolLocationStr(SymbolInfo, pointer); + PhSetListViewSubItem(Context->ListviewHandle, lvItemIndex, 2, pointer); + + // Size + PhSetListViewSubItem(Context->ListviewHandle, lvItemIndex, 3, PhaFormatString(L"%lu", SymbolInfo->Size)->Buffer); + + // Data + //if (SymInfoDump_GetTypeName(Context, SymbolInfo->TypeIndex, SymbolInfo->Name, szTypeName, cMaxTypeNameLen)) + // PhSetListViewSubItem(Context->ListviewHandle, lvItemIndex, 4, szTypeName); + + // Flags: %x, SymbolInfo->Flags + // Index: %8u, TypeIndex: %8u, SymbolInfo->Index, SymbolInfo->TypeIndex +} + +VOID PrintFunctionInfo( + _In_ PPDB_SYMBOL_CONTEXT Context, + _In_ PSYMBOL_INFOW SymbolInfo + ) +{ + INT lvItemIndex; + WCHAR pointer[PH_PTR_STR_LEN_1] = L""; + + if (SymbolInfo->Tag != SymTagFunction) + return; + + // Type + lvItemIndex = PhAddListViewItem(Context->ListviewHandle, MAXINT, L"FUNCTION", NULL); + + // Address + SymInfoDump_SymbolLocationStr(SymbolInfo, pointer); + PhSetListViewSubItem(Context->ListviewHandle, lvItemIndex, 1, pointer); + + // Name + PhSetListViewSubItem(Context->ListviewHandle, lvItemIndex, 2, SymbolInfo->Name); + + // Size + PhSetListViewSubItem(Context->ListviewHandle, lvItemIndex, 3, PhaFormatString(L"%lu", SymbolInfo->Size)->Buffer); + + // Data + //if (SymInfoDump_GetTypeName(Context, SymbolInfo->TypeIndex, SymbolInfo->Name, szTypeName, cMaxTypeNameLen)) + // PhSetListViewSubItem(Context->ListviewHandle, lvItemIndex, 4, szTypeName); + + // Flags: %x, SymbolInfo->Flags + // Index: %8u, TypeIndex: %8u, SymbolInfo->Index, SymbolInfo->TypeIndex + + // Enumerate function parameters and local variables... + //IMAGEHLP_STACK_FRAME sf; + //sf.InstructionOffset = SymbolInfo->Address; + //SymSetContext(NtCurrentProcess(), &sf, 0); + //SymEnumSymbolsW(NtCurrentProcess(), 0, NULL, EnumCallbackProc, pTypeInfo); +} + +VOID PrintDefaultInfo( + _In_ PPDB_SYMBOL_CONTEXT Context, + _In_ PSYMBOL_INFOW SymbolInfo + ) +{ + INT lvItemIndex; + WCHAR pointer[PH_PTR_STR_LEN_1] = L""; + + if (SymbolInfo->Tag != SymTagPublicSymbol) + return; + + // Type + lvItemIndex = PhAddListViewItem(Context->ListviewHandle, MAXINT, L"SYMBOL", NULL); + + // Address + SymInfoDump_SymbolLocationStr(SymbolInfo, pointer); + PhSetListViewSubItem(Context->ListviewHandle, lvItemIndex, 1, pointer); + + // Name + PhSetListViewSubItem(Context->ListviewHandle, lvItemIndex, 2, SymbolInfo->Name); + + // Size + PhSetListViewSubItem(Context->ListviewHandle, lvItemIndex, 3, PhaFormatString(L"%lu", SymbolInfo->Size)->Buffer); + + // Data + //if (SymInfoDump_GetTypeName(Context, SymbolInfo->TypeIndex, SymbolInfo->Name, szTypeName, cMaxTypeNameLen)) + // PhSetListViewSubItem(Context->ListviewHandle, lvItemIndex, 4, szTypeName); + + // Flags: %x, SymbolInfo->Flags + // Index: %8u, TypeIndex: %8u, SymbolInfo->Index, SymbolInfo->TypeIndex +} + +VOID PrintClassInfo( + _In_ PPDB_SYMBOL_CONTEXT Context, + _In_ ULONG Index, + _In_ UdtClassInfo* Info + ) +{ + // UDT kind + //OutputDebugString(PhaFormatString(L"%s", SymInfoDump_UdtKindStr(Info->UDTKind))->Buffer); + // Name + //OutputDebugString(PhaFormatString(L" %s \n", Info->Name)->Buffer); + // Size + //OutputDebugString(PhaFormatString(L"Size: %I64u", Info->Length)->Buffer); + + // Nested + //if (Info.Nested) + //OutputDebugString(L" Nested"); + // Number of member variables + //OutputDebugString(PhaFormatString(L" Variables: %d", Info->NumVariables)->Buffer); + // Number of member functions + //OutputDebugString(PhaFormatString(L" Functions: %d", Info->NumFunctions)->Buffer); + // Number of base classes + //OutputDebugString(PhaFormatString(L" Base classes: %d", Info->NumBaseClasses)->Buffer); + // Extended information about member variables + //OutputDebugString(L"\n"); + + for (ULONG i = 0; i < Info->NumVariables; i++) + { + TypeInfo VarInfo; + + if (!SymInfoDump_DumpType(Context, Info->Variables[i], &VarInfo)) + { + //_ASSERTE(!_T("SymInfoDump::DumpType() failed.")); + // Continue with the next variable + } + else if (VarInfo.Tag != SymTagData) + { + //_ASSERTE(!_T("Unexpected symbol tag.")); + // Continue with the next variable + } + else + { + // Display information about the variable + //_tprintf(_T("%s"), Context->DataKindStr(VarInfo.Info.sDataInfo.dataKind)); + + // Name + //wprintf(L" %s \n", VarInfo.Info.sDataInfo.Name); + // Type name + //_tprintf(_T(" Type: ")); + + //#define cMaxTypeNameLen 1024 + //TCHAR szTypeName[cMaxTypeNameLen + 1] = _T(""); + + //if (SymInfoDump_GetTypeName(VarInfo.Info.sDataInfo.TypeIndex, W2T(VarInfo.Info.sDataInfo.Name), szTypeName, cMaxTypeNameLen)) + //_tprintf(szTypeName); + //else + //_tprintf(_T("n/a")); + //_tprintf(_T("\n")); + + // Location + switch (VarInfo.sDataInfo.dataKind) + { + case DataIsGlobal: + case DataIsStaticLocal: + case DataIsFileStatic: + case DataIsStaticMember: + { + // Use Address + //_tprintf(_T(" Address: %16I64x"), VarInfo.Info.sDataInfo.Address); + } + break; + case DataIsLocal: + case DataIsParam: + case DataIsObjectPtr: + case DataIsMember: + { + // Use Offset + //_tprintf(_T(" Offset: %8d"), (long)VarInfo.Info.sDataInfo.Offset); + } + break; + default: + break; // Add support for constants + } + + // Indices + //_tprintf(_T(" Index: %8u TypeIndex: %8u"), Index, VarInfo.Info.sDataInfo.TypeIndex); + //_tprintf(_T("\n")); + } + } + + // Extended information about member functions + // Implement + // Extended information about base classes + // Implement + + for (ULONG i = 0; i < Info->NumBaseClasses; i++) + { + TypeInfo baseInfo; + + if (!SymInfoDump_DumpType(Context, Info->BaseClasses[i], &baseInfo)) + { + //_ASSERTE(!_T("SymInfoDump::DumpType() failed.")); + // Continue with the next base class + } + else if (baseInfo.Tag != SymTagBaseClass) + { + //_ASSERTE(!_T("Unexpected symbol tag.")); + // Continue with the next base class + } + else + { + // Obtain the name of the base class + TypeInfo BaseUdtInfo; + + if (!SymInfoDump_DumpType(Context, baseInfo.sBaseClassInfo.TypeIndex, &BaseUdtInfo)) + { + //_ASSERTE(!_T("SymInfoDump::DumpType() failed.")); + // Continue with the next base class + } + else if (BaseUdtInfo.Tag != SymTagUDT) + { + //_ASSERTE(!_T("Unexpected symbol tag.")); + // Continue with the next base class + } + else + { + // Print the name of the base class + if (baseInfo.sBaseClassInfo.Virtual) + { + //wprintf(L"VIRTUAL_BASE_CLASS %s \n", BaseUdtInfo.Info.sUdtClassInfo.Name); + } + else + { + //wprintf(L"BASE_CLASS %s \n", BaseUdtInfo.Info.sUdtClassInfo.Name); + } + } + } + } +} + +VOID PrintUserDefinedTypes( + _In_ PPDB_SYMBOL_CONTEXT Context + ) +{ + ULONG i; + ULONG index; + TypeInfo info; + + for (i = 0; i < Context->UdtList->Count; i++) + { + index = PtrToUlong(Context->UdtList->Items[i]); + + if (SymInfoDump_DumpType(Context, index, &info)) + { + if (info.Tag == SymTagUDT) + { + if (info.UdtKind) + { + // Print information about the class + PrintClassInfo(Context, index, &info.sUdtClassInfo); + + // Print information about its base classes + for (ULONG i = 0; i < info.sUdtClassInfo.NumBaseClasses; i++) + { + TypeInfo baseInfo; + + if (!SymInfoDump_DumpType(Context, info.sUdtClassInfo.BaseClasses[i], &baseInfo)) + { + //_ASSERTE(!_T("SymInfoDump::DumpType() failed.")); + // Continue with the next base class + } + else if (baseInfo.Tag != SymTagBaseClass) + { + //_ASSERTE(!_T("Unexpected symbol tag.")); + // Continue with the next base class + } + else + { + // Obtain information about the base class + TypeInfo baseUdtInfo; + + if (!SymInfoDump_DumpType(Context, baseInfo.sBaseClassInfo.TypeIndex, &baseUdtInfo)) + { + //_ASSERTE(!_T("SymInfoDump::DumpType() failed.")); + // Continue with the next base class + } + else if (baseUdtInfo.Tag != SymTagUDT) + { + //_ASSERTE(!_T("Unexpected symbol tag.")); + // Continue with the next base class + } + else + { + // Print information about the base class + PrintClassInfo(Context, baseInfo.sBaseClassInfo.TypeIndex, &baseUdtInfo.sUdtClassInfo); + } + } + } + } + else + { + // UDT kind + //printf("%s", Context->UdtKindStr(Info.Info.sUdtClassInfo.UDTKind)); + // + // Name + //printf("%s", Info.Info.sUdtClassInfo.Name); + // + // Size + //printf("Size: %I64u", Info.Info.sUdtClassInfo.Length); + // + // Nested + //if (Info.Info.sUdtClassInfo.Nested) + // printf("Nested"); + // + // Number of members + //printf(" Members: %d", Info.Info.sUdtClassInfo.NumVariables); + } + } + } + } +} + +/////////////////////////////////////////////////////////////////////////////// +BOOLEAN GetFileParamsSize(_In_ PWSTR pFileName, _Out_ ULONG* FileLength) +{ + HANDLE hFile = CreateFile( + pFileName, + GENERIC_READ, + FILE_SHARE_READ, + NULL, + OPEN_EXISTING, + 0, + NULL + ); + + if (hFile == INVALID_HANDLE_VALUE) + { + return FALSE; + } + + *FileLength = GetFileSize(hFile, NULL); + NtClose(hFile); + + return (*FileLength != INVALID_FILE_SIZE); +} + +BOOLEAN GetFileParams(_In_ PWSTR pFileName, _Out_ ULONG64 *BaseAddress, _Out_ ULONG* FileLength) +{ + TCHAR szFileExt[_MAX_EXT] = { 0 }; + + _wsplitpath(pFileName, NULL, NULL, NULL, szFileExt); + + // Is it .PDB file ? + if (_wcsicmp(szFileExt, L".PDB") == 0) + { + // Yes, it is a .PDB file + *BaseAddress = 0x10000000; + + // Determine its size, and use a dummy base address. + // it can be any non-zero value, but if we load symbols + // from more than one file, memory regions specified + // for different files should not overlap + // (region is "base address + file size") + + if (!GetFileParamsSize(pFileName, FileLength)) + { + return FALSE; + } + } + else + { + *BaseAddress = 0; + *FileLength = 0; + } + + return TRUE; +} + +/////////////////////////////////////////////////////////////////////////////// +VOID PdbLoadDbgHelpFromPath( + _In_ PWSTR DbgHelpPath + ) +{ + HMODULE dbghelpModule; + + if (dbghelpModule = LoadLibrary(DbgHelpPath)) + { + PPH_STRING fullDbghelpPath; + ULONG indexOfFileName; + PH_STRINGREF dbghelpFolder; + PPH_STRING symsrvPath; + + fullDbghelpPath = PhGetDllFileName(dbghelpModule, &indexOfFileName); + + if (fullDbghelpPath) + { + if (indexOfFileName != 0) + { + static PH_STRINGREF symsrvString = PH_STRINGREF_INIT(L"\\symsrv.dll"); + + dbghelpFolder.Buffer = fullDbghelpPath->Buffer; + dbghelpFolder.Length = indexOfFileName * sizeof(WCHAR); + + symsrvPath = PhConcatStringRef2(&dbghelpFolder, &symsrvString); + + LoadLibrary(symsrvPath->Buffer); + + PhDereferenceObject(symsrvPath); + } + + PhDereferenceObject(fullDbghelpPath); + } + } + else + { + dbghelpModule = LoadLibrary(L"dbghelp.dll"); + } + + PhSymbolProviderCompleteInitialization(dbghelpModule); +} + + +VOID ShowSymbolInfo( + _In_ ULONG64 BaseAddress + ) +{ + IMAGEHLP_MODULE64 info; + + memset(&info, 0, sizeof(IMAGEHLP_MODULE64)); + info.SizeOfStruct = sizeof(IMAGEHLP_MODULE64); + + if (!SymGetModuleInfoW64_I(NtCurrentProcess(), BaseAddress, &info)) + return; + + switch (info.SymType) + { + case SymNone: + //OutputDebugString(L"No symbols available for the module.\r\n"); + break; + case SymExport: + //OutputDebugString(L"Loaded symbols: Exports\r\n"); + break; + case SymCoff: + //OutputDebugString(L"Loaded symbols: COFF\r\n"); + break; + case SymCv: + //OutputDebugString(L"Loaded symbols: CodeView\r\n"); + break; + case SymSym: + //OutputDebugString(L"Loaded symbols: SYM\r\n"); + break; + case SymVirtual: + //OutputDebugString(L"Loaded symbols: Virtual\r\n"); + break; + case SymPdb: + //OutputDebugString(L"Loaded symbols: PDB\r\n"); + break; + case SymDia: + //OutputDebugString(L"Loaded symbols: DIA\r\n"); + break; + case SymDeferred: + //OutputDebugString(L"Loaded symbols: Deferred\r\n"); // not actually loaded + break; + default: + //OutputDebugString(L"Loaded symbols: Unknown format.\r\n"); + break; + } + + // Image name + if (wcslen(info.ImageName) > 0) + { + //OutputDebugString(PhaFormatString(L"Image name: %s\n", info.ImageName)->Buffer); + } + + // Loaded image name + if (wcslen(info.LoadedImageName) > 0) + { + //OutputDebugString(PhaFormatString(L"Loaded image name: %s\n", info.LoadedImageName)->Buffer); + } + + // Loaded PDB name + if (wcslen(info.LoadedPdbName) > 0) + { + //OutputDebugString(PhaFormatString(L"PDB file name: %s\n", info.LoadedPdbName)->Buffer); + } + + // Is debug information unmatched ? + // (It can only happen if the debug information is contained in a separate file (.DBG or .PDB) + if (info.PdbUnmatched || info.DbgUnmatched) + { + OutputDebugString(L"Warning: Unmatched symbols. \n"); + } + + // Load address: BaseAddress + //OutputDebugString(PhaFormatString(L"Line numbers: %s\n", info.LineNumbers ? L"Available" : L"Not available")->Buffer); + //OutputDebugString(PhaFormatString(L"Global symbols: %s\n", info.GlobalSymbols ? L"Available" : L"Not available")->Buffer); + //OutputDebugString(PhaFormatString(L"Type information: %s\n", info.TypeInfo ? L"Available" : L"Not available")->Buffer); + //OutputDebugString(PhaFormatString(L"Source indexing: %s\n", info.SourceIndexed ? L"Yes" : L"No")->Buffer); + //OutputDebugString(PhaFormatString(L"Public symbols: %s\n", info.Publics ? L"Available" : L"Not available")->Buffer); +} + + +VOID PeDumpFileSymbols( + _In_ HWND ListViewHandle, + _In_ PWSTR FileName + ) +{ + HMODULE dbghelpHandle; + HMODULE symsrvHandle; + ULONG64 symbolBaseAddress = 0; + ULONG64 baseAddress = 0; + ULONG fileLength = 0; + + PdbLoadDbgHelpFromPath(L"C:\\Program Files (x86)\\Windows Kits\\10\\Debuggers\\x64\\dbghelp.dll"); + + if (!(dbghelpHandle = GetModuleHandle(L"dbghelp.dll"))) + return; + + symsrvHandle = GetModuleHandle(L"symsrv.dll"); + SymInitialize_I = PhGetProcedureAddress(dbghelpHandle, "SymInitialize", 0); + SymCleanup_I = PhGetProcedureAddress(dbghelpHandle, "SymCleanup", 0); + SymEnumSymbolsW_I = PhGetProcedureAddress(dbghelpHandle, "SymEnumSymbolsW", 0); + SymSetSearchPathW_I = PhGetProcedureAddress(dbghelpHandle, "SymSetSearchPathW", 0); + SymGetOptions_I = PhGetProcedureAddress(dbghelpHandle, "SymGetOptions", 0); + SymSetOptions_I = PhGetProcedureAddress(dbghelpHandle, "SymSetOptions", 0); + SymLoadModuleExW_I = PhGetProcedureAddress(dbghelpHandle, "SymLoadModuleExW", 0); + SymGetModuleInfoW64_I = PhGetProcedureAddress(dbghelpHandle, "SymGetModuleInfoW64", 0); + SymGetTypeInfo_I = PhGetProcedureAddress(dbghelpHandle, "SymGetTypeInfo", 0); + + SymSetOptions_I(SymGetOptions_I() | SYMOPT_DEBUG | SYMOPT_UNDNAME); // SYMOPT_DEFERRED_LOADS | SYMOPT_FAVOR_COMPRESSED + + if (!SymInitialize_I(NtCurrentProcess(), NULL, FALSE)) + return; + + if (!SymSetSearchPathW_I(NtCurrentProcess(), L"SRV*C:\\symbols*http://msdl.microsoft.com/download/symbols")) + return; + + if (GetFileParams(FileName, &baseAddress, &fileLength)) + { + if ((symbolBaseAddress = SymLoadModuleExW_I( + NtCurrentProcess(), + NULL, + FileName, + NULL, + baseAddress, + fileLength, + NULL, + 0 + ))) + { + PDB_SYMBOL_CONTEXT context; + + context.ListviewHandle = ListViewHandle; + context.BaseAddress = symbolBaseAddress; + context.UdtList = PhCreateList(0x100); + + ShowSymbolInfo(symbolBaseAddress); + + SymEnumSymbolsW_I(NtCurrentProcess(), symbolBaseAddress, NULL, EnumCallbackProc, &context); + + // Print information about used defined types + //PrintUserDefinedTypes(&context); + } + } + + SymCleanup_I(NtCurrentProcess()); +} + +VOID PvPdbProperties( + VOID + ) +{ + PPV_PROPCONTEXT propContext; + + if (!RtlDoesFileExists_U(PvFileName->Buffer)) + { + PhShowStatus(NULL, L"Unable to load the pdb file", STATUS_FILE_NOT_AVAILABLE, 0); + return; + } + + if (propContext = PvCreatePropContext(PvFileName)) + { + PPV_PROPPAGECONTEXT newPage; + + // Symbols page + newPage = PvCreatePropPageContext( + MAKEINTRESOURCE(IDD_PESYMBOLS), + PvpSymbolsDlgProc, + NULL + ); + PvAddPropPage(propContext, newPage); + + PhModalPropertySheet(&propContext->PropSheetHeader); + + PhDereferenceObject(propContext); + } +} + +INT_PTR CALLBACK PvpSymbolsDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + LPPROPSHEETPAGE propSheetPage; + PPV_PROPPAGECONTEXT propPageContext; + + if (!PvPropPageDlgProcHeader(hwndDlg, uMsg, lParam, &propSheetPage, &propPageContext)) + return FALSE; + + switch (uMsg) + { + case WM_INITDIALOG: + { + HWND lvHandle; + + lvHandle = GetDlgItem(hwndDlg, IDC_LIST); + PhSetListViewStyle(lvHandle, FALSE, TRUE); + PhSetControlTheme(lvHandle, L"explorer"); + PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 40, L"Type"); + PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_RIGHT, 80, L"VA"); + PhAddListViewColumn(lvHandle, 2, 2, 2, LVCFMT_LEFT, 250, L"Name"); + PhAddListViewColumn(lvHandle, 3, 3, 3, LVCFMT_LEFT, 40, L"Size"); + PhSetExtendedListView(lvHandle); + PhLoadListViewColumnsFromSetting(L"PdbListViewColumns", lvHandle); + + PeDumpFileSymbols(lvHandle, PvFileName->Buffer); + + ExtendedListView_SortItems(lvHandle); + + EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); + } + break; + case WM_DESTROY: + { + PhSaveListViewColumnsToSetting(L"PdbListViewColumns", GetDlgItem(hwndDlg, IDC_LIST)); + } + break; + case WM_SHOWWINDOW: + { + if (!propPageContext->LayoutInitialized) + { + PPH_LAYOUT_ITEM dialogItem; + + dialogItem = PvAddPropPageLayoutItem(hwndDlg, hwndDlg, + PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL); + PvAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_LIST), + dialogItem, PH_ANCHOR_ALL); + + PvDoPropPageLayout(hwndDlg); + + propPageContext->LayoutInitialized = TRUE; + } + } + break; + case WM_NOTIFY: + { + PvHandleListViewNotifyForCopy(lParam, GetDlgItem(hwndDlg, IDC_LIST)); + } + break; + } + + return FALSE; +} diff --git a/tools/peview/peprp.c b/tools/peview/peprp.c index 38947aaf0420..6d3b832abaa7 100644 --- a/tools/peview/peprp.c +++ b/tools/peview/peprp.c @@ -195,6 +195,16 @@ VOID PvPeProperties( PvAddPropPage(propContext, newPage); } + // PDB page + { + newPage = PvCreatePropPageContext( + MAKEINTRESOURCE(IDD_PESYMBOLS), + PvpSymbolsDlgProc, + NULL + ); + PvAddPropPage(propContext, newPage); + } + PhModalPropertySheet(&propContext->PropSheetHeader); PhDereferenceObject(propContext); @@ -1139,6 +1149,134 @@ BOOLEAN PvpLoadDbgHelp( return TRUE; } +INT_PTR CALLBACK PvpPeClrDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + LPPROPSHEETPAGE propSheetPage; + PPV_PROPPAGECONTEXT propPageContext; + + if (!PvPropPageDlgProcHeader(hwndDlg, uMsg, lParam, &propSheetPage, &propPageContext)) + return FALSE; + + switch (uMsg) + { + case WM_INITDIALOG: + { + PH_STRING_BUILDER stringBuilder; + PPH_STRING string; + PVOID metaData; + ULONG versionStringLength; + + string = PhaFormatString(L"%u.%u", PvImageCor20Header->MajorRuntimeVersion, + PvImageCor20Header->MinorRuntimeVersion); + SetDlgItemText(hwndDlg, IDC_RUNTIMEVERSION, string->Buffer); + + PhInitializeStringBuilder(&stringBuilder, 256); + + if (PvImageCor20Header->Flags & COMIMAGE_FLAGS_ILONLY) + PhAppendStringBuilder2(&stringBuilder, L"IL only, "); + if (PvImageCor20Header->Flags & COMIMAGE_FLAGS_32BITREQUIRED) + PhAppendStringBuilder2(&stringBuilder, L"32-bit only, "); + if (PvImageCor20Header->Flags & COMIMAGE_FLAGS_32BITPREFERRED) + PhAppendStringBuilder2(&stringBuilder, L"32-bit preferred, "); + if (PvImageCor20Header->Flags & COMIMAGE_FLAGS_IL_LIBRARY) + PhAppendStringBuilder2(&stringBuilder, L"IL library, "); + + if (PvImageCor20Header->StrongNameSignature.VirtualAddress != 0 && PvImageCor20Header->StrongNameSignature.Size != 0) + { + if (PvImageCor20Header->Flags & COMIMAGE_FLAGS_STRONGNAMESIGNED) + PhAppendStringBuilder2(&stringBuilder, L"Strong-name signed, "); + else + PhAppendStringBuilder2(&stringBuilder, L"Strong-name delay signed, "); + } + + if (PvImageCor20Header->Flags & COMIMAGE_FLAGS_NATIVE_ENTRYPOINT) + PhAppendStringBuilder2(&stringBuilder, L"Native entry-point, "); + if (PvImageCor20Header->Flags & COMIMAGE_FLAGS_TRACKDEBUGDATA) + PhAppendStringBuilder2(&stringBuilder, L"Track debug data, "); + + if (PhEndsWithString2(stringBuilder.String, L", ", FALSE)) + PhRemoveEndStringBuilder(&stringBuilder, 2); + + SetDlgItemText(hwndDlg, IDC_FLAGS, stringBuilder.String->Buffer); + PhDeleteStringBuilder(&stringBuilder); + + metaData = PhMappedImageRvaToVa(&PvMappedImage, PvImageCor20Header->MetaData.VirtualAddress, NULL); + + if (metaData) + { + __try + { + PhProbeAddress(metaData, PvImageCor20Header->MetaData.Size, PvMappedImage.ViewBase, PvMappedImage.Size, 4); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + metaData = NULL; + } + } + + versionStringLength = 0; + + if (metaData) + { + // Skip 12 bytes. + // First 4 bytes contains the length of the version string. + // The version string follows. + versionStringLength = *(PULONG)((PCHAR)metaData + 12); + + // Make sure the length is valid. + if (versionStringLength >= 0x100) + versionStringLength = 0; + } + + if (versionStringLength != 0) + { + string = PhZeroExtendToUtf16Ex((PCHAR)metaData + 12 + 4, versionStringLength); + SetDlgItemText(hwndDlg, IDC_VERSIONSTRING, string->Buffer); + PhDereferenceObject(string); + } + else + { + SetDlgItemText(hwndDlg, IDC_VERSIONSTRING, L"N/A"); + } + } + break; + case WM_SHOWWINDOW: + { + if (!propPageContext->LayoutInitialized) + { + PvAddPropPageLayoutItem(hwndDlg, hwndDlg, + PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL); + + PvDoPropPageLayout(hwndDlg); + + propPageContext->LayoutInitialized = TRUE; + } + } + break; + case WM_NOTIFY: + { + LPNMHDR header = (LPNMHDR)lParam; + + switch (header->code) + { + case PSN_QUERYINITIALFOCUS: + { + SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, (LONG_PTR)GetDlgItem(hwndDlg, IDC_RUNTIMEVERSION)); + } + return TRUE; + } + } + break; + } + + return FALSE; +} + INT_PTR CALLBACK PvpPeCgfDlgProc( _In_ HWND hwndDlg, _In_ UINT uMsg, @@ -1300,131 +1438,3 @@ INT_PTR CALLBACK PvpPeCgfDlgProc( return FALSE; } - -INT_PTR CALLBACK PvpPeClrDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - LPPROPSHEETPAGE propSheetPage; - PPV_PROPPAGECONTEXT propPageContext; - - if (!PvPropPageDlgProcHeader(hwndDlg, uMsg, lParam, &propSheetPage, &propPageContext)) - return FALSE; - - switch (uMsg) - { - case WM_INITDIALOG: - { - PH_STRING_BUILDER stringBuilder; - PPH_STRING string; - PVOID metaData; - ULONG versionStringLength; - - string = PhaFormatString(L"%u.%u", PvImageCor20Header->MajorRuntimeVersion, - PvImageCor20Header->MinorRuntimeVersion); - SetDlgItemText(hwndDlg, IDC_RUNTIMEVERSION, string->Buffer); - - PhInitializeStringBuilder(&stringBuilder, 256); - - if (PvImageCor20Header->Flags & COMIMAGE_FLAGS_ILONLY) - PhAppendStringBuilder2(&stringBuilder, L"IL only, "); - if (PvImageCor20Header->Flags & COMIMAGE_FLAGS_32BITREQUIRED) - PhAppendStringBuilder2(&stringBuilder, L"32-bit only, "); - if (PvImageCor20Header->Flags & COMIMAGE_FLAGS_32BITPREFERRED) - PhAppendStringBuilder2(&stringBuilder, L"32-bit preferred, "); - if (PvImageCor20Header->Flags & COMIMAGE_FLAGS_IL_LIBRARY) - PhAppendStringBuilder2(&stringBuilder, L"IL library, "); - - if (PvImageCor20Header->StrongNameSignature.VirtualAddress != 0 && PvImageCor20Header->StrongNameSignature.Size != 0) - { - if (PvImageCor20Header->Flags & COMIMAGE_FLAGS_STRONGNAMESIGNED) - PhAppendStringBuilder2(&stringBuilder, L"Strong-name signed, "); - else - PhAppendStringBuilder2(&stringBuilder, L"Strong-name delay signed, "); - } - - if (PvImageCor20Header->Flags & COMIMAGE_FLAGS_NATIVE_ENTRYPOINT) - PhAppendStringBuilder2(&stringBuilder, L"Native entry-point, "); - if (PvImageCor20Header->Flags & COMIMAGE_FLAGS_TRACKDEBUGDATA) - PhAppendStringBuilder2(&stringBuilder, L"Track debug data, "); - - if (PhEndsWithString2(stringBuilder.String, L", ", FALSE)) - PhRemoveEndStringBuilder(&stringBuilder, 2); - - SetDlgItemText(hwndDlg, IDC_FLAGS, stringBuilder.String->Buffer); - PhDeleteStringBuilder(&stringBuilder); - - metaData = PhMappedImageRvaToVa(&PvMappedImage, PvImageCor20Header->MetaData.VirtualAddress, NULL); - - if (metaData) - { - __try - { - PhProbeAddress(metaData, PvImageCor20Header->MetaData.Size, PvMappedImage.ViewBase, PvMappedImage.Size, 4); - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - metaData = NULL; - } - } - - versionStringLength = 0; - - if (metaData) - { - // Skip 12 bytes. - // First 4 bytes contains the length of the version string. - // The version string follows. - versionStringLength = *(PULONG)((PCHAR)metaData + 12); - - // Make sure the length is valid. - if (versionStringLength >= 0x100) - versionStringLength = 0; - } - - if (versionStringLength != 0) - { - string = PhZeroExtendToUtf16Ex((PCHAR)metaData + 12 + 4, versionStringLength); - SetDlgItemText(hwndDlg, IDC_VERSIONSTRING, string->Buffer); - PhDereferenceObject(string); - } - else - { - SetDlgItemText(hwndDlg, IDC_VERSIONSTRING, L"N/A"); - } - } - break; - case WM_SHOWWINDOW: - { - if (!propPageContext->LayoutInitialized) - { - PvAddPropPageLayoutItem(hwndDlg, hwndDlg, - PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL); - - PvDoPropPageLayout(hwndDlg); - - propPageContext->LayoutInitialized = TRUE; - } - } - break; - case WM_NOTIFY: - { - LPNMHDR header = (LPNMHDR)lParam; - - switch (header->code) - { - case PSN_QUERYINITIALFOCUS: - { - SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, (LONG_PTR)GetDlgItem(hwndDlg, IDC_RUNTIMEVERSION)); - } - return TRUE; - } - } - break; - } - - return FALSE; -} diff --git a/tools/peview/peview.rc b/tools/peview/peview.rc index d8c1288b8a65..6151830379f2 100644 --- a/tools/peview/peview.rc +++ b/tools/peview/peview.rc @@ -108,6 +108,14 @@ BEGIN TOPMARGIN, 7 BOTTOMMARGIN, 273 END + + IDD_PESYMBOLS, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 293 + TOPMARGIN, 7 + BOTTOMMARGIN, 273 + END END #endif // APSTUDIO_INVOKED @@ -202,6 +210,14 @@ BEGIN CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,7,286,266 END +IDD_PESYMBOLS DIALOGEX 0, 0, 300, 280 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Symbols" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,7,286,266 +END + ///////////////////////////////////////////////////////////////////////////// // @@ -223,6 +239,11 @@ BEGIN 0 END +IDD_PESYMBOLS AFX_DIALOG_LAYOUT +BEGIN + 0 +END + #endif // English (Australia) resources ///////////////////////////////////////////////////////////////////////////// diff --git a/tools/peview/peview.vcxproj b/tools/peview/peview.vcxproj index e37234a5e523..65d0ed06345b 100644 --- a/tools/peview/peview.vcxproj +++ b/tools/peview/peview.vcxproj @@ -194,11 +194,13 @@ + + diff --git a/tools/peview/peview.vcxproj.filters b/tools/peview/peview.vcxproj.filters index 4abd9aaa1ebb..87d782e3bcb4 100644 --- a/tools/peview/peview.vcxproj.filters +++ b/tools/peview/peview.vcxproj.filters @@ -1,4 +1,4 @@ - + @@ -33,6 +33,9 @@ Source Files + + Source Files + @@ -44,6 +47,9 @@ Header Files + + Header Files + diff --git a/tools/peview/resource.h b/tools/peview/resource.h index aa0350eaa2d3..6c6e0f0a2ed0 100644 --- a/tools/peview/resource.h +++ b/tools/peview/resource.h @@ -9,6 +9,7 @@ #define IDD_PECLR 106 #define IDD_PELOADCONFIG 107 #define IDD_PECFG 108 +#define IDD_PESYMBOLS 109 #define IDC_TARGETMACHINE 1003 #define IDC_CHECKSUM 1004 #define IDC_SUBSYSTEM 1005 @@ -32,7 +33,7 @@ // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 110 +#define _APS_NEXT_RESOURCE_VALUE 111 #define _APS_NEXT_COMMAND_VALUE 40001 #define _APS_NEXT_CONTROL_VALUE 1017 #define _APS_NEXT_SYMED_VALUE 101 diff --git a/tools/peview/settings.c b/tools/peview/settings.c index 4470b16fea46..1d9da291d023 100644 --- a/tools/peview/settings.c +++ b/tools/peview/settings.c @@ -39,6 +39,8 @@ VOID PhAddDefaultSettings( PhpAddStringSetting(L"ImageExportsListViewColumns", L""); PhpAddStringSetting(L"ImageImportsListViewColumns", L""); PhpAddStringSetting(L"ImageLoadCfgListViewColumns", L""); + PhpAddStringSetting(L"LibListViewColumns", L""); + PhpAddStringSetting(L"PdbListViewColumns", L""); } VOID PhUpdateCachedSettings( From d6bf0164847fc982c7e07e500c70141a71445c29 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 8 May 2017 08:26:51 +1000 Subject: [PATCH 0069/2058] Add missing line from previous commit --- tools/peview/pdb.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tools/peview/pdb.c b/tools/peview/pdb.c index a68ed42d0144..a9e4f4d5c58c 100644 --- a/tools/peview/pdb.c +++ b/tools/peview/pdb.c @@ -1955,12 +1955,12 @@ VOID PrintDataInfo( symDataKind = SymInfoDump_DataKindFromSymbolInfo(SymbolInfo); lvItemIndex = PhAddListViewItem(Context->ListviewHandle, MAXINT, symDataKind, NULL); - // Name - PhSetListViewSubItem(Context->ListviewHandle, lvItemIndex, 1, SymbolInfo->Name); - // Address SymInfoDump_SymbolLocationStr(SymbolInfo, pointer); - PhSetListViewSubItem(Context->ListviewHandle, lvItemIndex, 2, pointer); + PhSetListViewSubItem(Context->ListviewHandle, lvItemIndex, 1, pointer); + + // Name + PhSetListViewSubItem(Context->ListviewHandle, lvItemIndex, 2, SymbolInfo->Name); // Size PhSetListViewSubItem(Context->ListviewHandle, lvItemIndex, 3, PhaFormatString(L"%lu", SymbolInfo->Size)->Buffer); From ae1599b09d2b552cb3c87a462f6a3877fd126c64 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 8 May 2017 20:49:43 +1000 Subject: [PATCH 0070/2058] BuildTools: Fix building multi-architecture appx packages, Fix setup installer object paths, Fix setup text clipping --- .gitignore | 1 + tools/CustomBuildTool/CustomBuildTool.csproj | 1 + .../Properties/Resources.Designer.cs | 18 +- .../CustomBuildTool/Properties/Resources.resx | 59 ++--- tools/CustomBuildTool/Source Files/Build.cs | 239 ++++++++++++++---- .../Source Files/NativeMethods.cs | 15 ++ tools/CustomBuildTool/Source Files/Program.cs | 19 +- .../bin/Release/CustomBuildTool.exe | Bin 157696 -> 162304 bytes .../bin/Release/CustomBuildTool.pdb | Bin 71168 -> 75264 bytes .../CustomSetupTool/CustomSetupTool.vcxproj | 2 +- .../CustomSetupTool.vcxproj.filters | 2 +- .../CustomSetupTool/CustomSetupTool/extract.c | 17 +- .../CustomSetupTool/resource.rc | 2 +- 13 files changed, 278 insertions(+), 97 deletions(-) diff --git a/.gitignore b/.gitignore index 91909cdebcd6..d38240e8b4e3 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ # Build results *.appx +*.appxbundle *.cer *.ilk *.meta diff --git a/tools/CustomBuildTool/CustomBuildTool.csproj b/tools/CustomBuildTool/CustomBuildTool.csproj index a5f7110ee6c5..2e456e11dfed 100644 --- a/tools/CustomBuildTool/CustomBuildTool.csproj +++ b/tools/CustomBuildTool/CustomBuildTool.csproj @@ -68,6 +68,7 @@ + diff --git a/tools/CustomBuildTool/Properties/Resources.Designer.cs b/tools/CustomBuildTool/Properties/Resources.Designer.cs index 88851ef585cc..7135019864c9 100644 --- a/tools/CustomBuildTool/Properties/Resources.Designer.cs +++ b/tools/CustomBuildTool/Properties/Resources.Designer.cs @@ -63,16 +63,14 @@ internal Resources() { ///

- + diff --git a/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj.filters b/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj.filters index f3ed066b91de..fd0778f3dc06 100644 --- a/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj.filters +++ b/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj.filters @@ -105,7 +105,7 @@ - + Resource Files\Binary diff --git a/tools/CustomSetupTool/CustomSetupTool/extract.c b/tools/CustomSetupTool/CustomSetupTool/extract.c index f89aa45dbbef..c4a0d02c5c01 100644 --- a/tools/CustomSetupTool/CustomSetupTool/extract.c +++ b/tools/CustomSetupTool/CustomSetupTool/extract.c @@ -57,6 +57,7 @@ BOOLEAN SetupExtractBuild( ULONG64 totalLength = 0; ULONG64 currentLength = 0; mz_zip_archive zip_archive = { 0 }; + PPH_STRING extractPath = NULL; PVOID resourceBuffer; ULONG resourceLength; SYSTEM_INFO info; @@ -94,9 +95,10 @@ BOOLEAN SetupExtractBuild( } totalLength += zipFileStat.m_uncomp_size; - InterlockedExchange64(&ExtractTotalLength, totalLength); } + InterlockedExchange64(&ExtractTotalLength, totalLength); + SendMessage(Context, WM_START_SETUP, 0, 0); for (mz_uint i = 0; i < mz_zip_reader_get_num_files(&zip_archive); i++) @@ -106,7 +108,6 @@ BOOLEAN SetupExtractBuild( ULONG indexOfFileName = -1; PPH_STRING fileName; PPH_STRING fullSetupPath; - PPH_STRING extractPath; PVOID buffer; mz_ulong zipFileCrc32 = 0; ULONG bufferLength = 0; @@ -213,19 +214,27 @@ BOOLEAN SetupExtractBuild( goto CleanupExit; currentLength += bufferLength; - InterlockedExchange64(&ExtractCurrentLength, currentLength); - SendMessage(Context, WM_UPDATE_SETUP, 0, (LPARAM)extractPath); + SendMessage(Context, WM_UPDATE_SETUP, 0, (LPARAM)PhGetBaseName(extractPath)); NtClose(fileHandle); mz_free(buffer); } mz_zip_reader_end(&zip_archive); + + if (extractPath) + PhDereferenceObject(extractPath); + return TRUE; CleanupExit: + mz_zip_reader_end(&zip_archive); + + if (extractPath) + PhDereferenceObject(extractPath); + return FALSE; } diff --git a/tools/CustomSetupTool/CustomSetupTool/resource.rc b/tools/CustomSetupTool/CustomSetupTool/resource.rc index 3ffc04f2b300..cf68f769845f 100644 --- a/tools/CustomSetupTool/CustomSetupTool/resource.rc +++ b/tools/CustomSetupTool/CustomSetupTool/resource.rc @@ -81,7 +81,7 @@ STYLE DS_SETFONT | DS_MODALFRAME | DS_NOFAILCREATE | WS_POPUP | WS_CAPTION | WS_ EXSTYLE WS_EX_CONTROLPARENT FONT 8, "MS Shell Dlg 2", 400, 0, 0x1 BEGIN - LTEXT "Preparing installation...",IDC_INSTALL_STATUS,15,147,243,13 + LTEXT "Preparing installation...",IDC_INSTALL_STATUS,15,147,380,13 CONTROL "",IDC_INSTALL_PROGRESS,"msctls_progress32",PBS_SMOOTH,15,164,370,11,WS_EX_CLIENTEDGE CONTROL "",IDC_PROJECT_ICON,"Static",SS_BLACKFRAME,271,15,92,75 LTEXT "Preparing installation...",IDC_MAINHEADER,15,26,259,24 From e5d8b4e9a3be2eb12912c5005fd263cf47257f1e Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 10 May 2017 14:57:49 +1000 Subject: [PATCH 0071/2058] BuildTools: Fix cleanup --- .gitattributes | 2 +- build/build_appx_makecert.cmd | 4 +--- tools/CustomBuildTool/Source Files/Build.cs | 3 ++- .../bin/Release/CustomBuildTool.exe | Bin 162304 -> 162304 bytes .../bin/Release/CustomBuildTool.pdb | Bin 75264 -> 75264 bytes 5 files changed, 4 insertions(+), 5 deletions(-) diff --git a/.gitattributes b/.gitattributes index 961777c2611a..8d499c1de08f 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,5 +1,5 @@ # Auto detect text files -* text=auto +* text=crlf # Custom for Visual Studio *.cs diff=csharp diff --git a/build/build_appx_makecert.cmd b/build/build_appx_makecert.cmd index d65686b5a244..282352f0efaa 100644 --- a/build/build_appx_makecert.cmd +++ b/build/build_appx_makecert.cmd @@ -2,6 +2,4 @@ @setlocal enableextensions @cd /d "%~dp0\..\" -start /B /W "" "tools\CustomBuildTool\bin\Release\CustomBuildTool.exe" "-appxmakecert" - -pause \ No newline at end of file +start /B /W "" "tools\CustomBuildTool\bin\Release\CustomBuildTool.exe" "-appxmakecert" \ No newline at end of file diff --git a/tools/CustomBuildTool/Source Files/Build.cs b/tools/CustomBuildTool/Source Files/Build.cs index 12ea6f115927..10fea83a4cbc 100644 --- a/tools/CustomBuildTool/Source Files/Build.cs +++ b/tools/CustomBuildTool/Source Files/Build.cs @@ -208,7 +208,8 @@ public static void CleanupBuildEnvironment() try { - Directory.Delete("build\\output", true); + if (Directory.Exists("build\\output")) + Directory.Delete("build\\output", true); for (int i = 0; i < cleanupFileArray.Length; i++) { diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe b/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe index f64000cd50f9ba6d558ea03818794a11b5969893..6675d24006fe65a5d44294098977dbb2bd994260 100644 GIT binary patch delta 1724 zcmY+_drVtZ90&04DHQIxz_^qG#TIZg@~q2v45XF`gULpDI2dn+Q>zl4IFm&**-{>p zFke|ytmCjH}czrS~ij&$02N3&u;jFy!<9k+y*NFJw!$KhI@%8G>Iv72NH$ZSma1$yU1s~r0*VVJqh(4*xeQ+`S2~d(<*rc5HO@dsex*{qdHN-fQck+Y zb-d?Qs?w5qBBpDUE{Iu@fLf*ROhs!U&mVN`%{+r79DPWJ)*31QX6Q zo`gOBDVMLpJZaJC;VJMon6u#Jhl4?X&j&}mYW)YU-FsVp{75JD`F0u+lNOc*0+>g&m ztr>>Uc~Ysk&`NwmdQebi)37TTJz%pEKvA@W(fViXI?Cs zSr|V1W$wkrZStuFaoQE-RcLRQ3gZLq8sC6Drh@n(XAm24n{?9l8?QxOhpN1ov&ic( z*I_P_FuoG3$L>xQzR0(t0l$;7Q;xxhbzL$GqA~t&?t|VfHLiWHeZ+jQkJu%x z4?C5_x{nunxJTW@6=#y(h^SORJhsaj4%UKbuMESmI~;5)cJ(POimZ)VF=oC#?by6s zW+AQ4k*>F6gtU<05}F__C#(@VK>8!+7&=xov;$LS78t`*SYjQB7oXRE-`CC+rJYDM zvoTDfK<`8W=@qQiyHHFz!pcNfyri#Lwcdj|(skCT_pX?;4~;4-K@scL`|u@|F0w6r zJFc2iACLYO1N-qyWT-WB)TlZC^T5z1U&9;LbL+bg&K5=veLI=%7F&z?#4X}pTwa2?`vVQ=Z#$ojU delta 1723 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 Y^pF2)mZAy82U|Uv<-BjuS0R9Vv+yDRo delta 9518 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 From 59fa7403d3b50a1ced6271d8d9f6fd2f18e0b496 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 11 May 2017 17:02:48 +1000 Subject: [PATCH 0072/2058] Fix about window debug version, Update about window text --- ProcessHacker/about.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/ProcessHacker/about.c b/ProcessHacker/about.c index 834b055bd054..957c741c0b97 100644 --- a/ProcessHacker/about.c +++ b/ProcessHacker/about.c @@ -3,6 +3,7 @@ * about dialog * * Copyright (C) 2010-2016 wj32 + * Copyright (C) 2017 dmex * * This file is part of Process Hacker. * @@ -48,7 +49,7 @@ static INT_PTR CALLBACK PhpAboutDlgProc( PhCenterWindow(hwndDlg, GetParent(hwndDlg)); -#if (PHAPP_VERSION_REVISION != 0) +#if (PHAPP_VERSION_REVISION != 0x0D06F00D) appName = PhFormatString( L"Process Hacker %u.%u.%u", PHAPP_VERSION_MAJOR, @@ -67,12 +68,11 @@ static INT_PTR CALLBACK PhpAboutDlgProc( PhDereferenceObject(appName); SetDlgItemText(hwndDlg, IDC_CREDITS, - L" Installer by XhmikosR\n" L"Thanks to:\n" - L" dmex\n" - L" Donors - thank you for your support!\n" - L" Sysinternals Forums\n" - L" ReactOS\n" + L" wj32 - Wen Jia Liu\n" + L" dmex - Steven G\n" + L" XhmikosR\n" + L" Donors - thank you for your support!\n\n" L"Process Hacker uses the following components:\n" L" Mini-XML by Michael Sweet\n" L" PCRE\n" From 3af1cf35e79a196e8d3b3b4b79270ce2ac7887ab Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 11 May 2017 17:03:48 +1000 Subject: [PATCH 0073/2058] phlib: remove legacy icon imports --- phlib/guisup.c | 11 ++--------- phlib/include/guisupp.h | 15 --------------- 2 files changed, 2 insertions(+), 24 deletions(-) diff --git a/phlib/guisup.c b/phlib/guisup.c index 3ae41b72c5a4..c8f8f6e3298e 100644 --- a/phlib/guisup.c +++ b/phlib/guisup.c @@ -565,17 +565,12 @@ HICON PhLoadIcon( _In_opt_ ULONG Height ) { - static _LoadIconMetric loadIconMetric; - static _LoadIconWithScaleDown loadIconWithScaleDown; - PHP_ICON_ENTRY entry; PPHP_ICON_ENTRY actualEntry; HICON icon = NULL; if (PhBeginInitOnce(&SharedIconCacheInitOnce)) { - loadIconMetric = (_LoadIconMetric)PhGetModuleProcAddress(L"comctl32.dll", "LoadIconMetric"); - loadIconWithScaleDown = (_LoadIconWithScaleDown)PhGetModuleProcAddress(L"comctl32.dll", "LoadIconWithScaleDown"); SharedIconCacheHashtable = PhCreateHashtable(sizeof(PHP_ICON_ENTRY), SharedIconCacheHashtableEqualFunction, SharedIconCacheHashtableHashFunction, 10); PhEndInitOnce(&SharedIconCacheInitOnce); @@ -601,13 +596,11 @@ HICON PhLoadIcon( if (Flags & (PH_LOAD_ICON_SIZE_SMALL | PH_LOAD_ICON_SIZE_LARGE)) { - if (loadIconMetric) - loadIconMetric(InstanceHandle, Name, (Flags & PH_LOAD_ICON_SIZE_SMALL) ? LIM_SMALL : LIM_LARGE, &icon); + LoadIconMetric(InstanceHandle, Name, (Flags & PH_LOAD_ICON_SIZE_SMALL) ? LIM_SMALL : LIM_LARGE, &icon); } else { - if (loadIconWithScaleDown) - loadIconWithScaleDown(InstanceHandle, Name, Width, Height, &icon); + LoadIconWithScaleDown(InstanceHandle, Name, Width, Height, &icon); } if (!icon && !(Flags & PH_LOAD_ICON_STRICT)) diff --git a/phlib/include/guisupp.h b/phlib/include/guisupp.h index a2372bd3ddb5..9fd0465ff20e 100644 --- a/phlib/include/guisupp.h +++ b/phlib/include/guisupp.h @@ -1,21 +1,6 @@ #ifndef _PH_GUISUPP_H #define _PH_GUISUPP_H -typedef HRESULT (WINAPI *_LoadIconMetric)( - _In_ HINSTANCE hinst, - _In_ PCWSTR pszName, - _In_ int lims, - _Out_ HICON *phico - ); - -typedef HRESULT (WINAPI *_LoadIconWithScaleDown)( - _In_ HINSTANCE hinst, - _In_ PCWSTR pszName, - _In_ int cx, - _In_ int cy, - _Out_ HICON *phico - ); - typedef struct _PHP_ICON_ENTRY { HINSTANCE InstanceHandle; From d5cae0ddd91338de7c93c3005b73bcaed9afabe2 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 11 May 2017 17:06:17 +1000 Subject: [PATCH 0074/2058] Improve window icon scaling, Add sysinfo window icons --- ProcessHacker/mainwnd.c | 4 ++-- ProcessHacker/miniinfo.c | 4 ++-- ProcessHacker/sysinfo.c | 3 +++ 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index 0154356736f9..3d4c8539dd18 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -342,12 +342,12 @@ BOOLEAN PhMwpInitializeWindowClass( wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = PhInstanceHandle; - wcex.hIcon = LoadIcon(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER)); + wcex.hIcon = PH_LOAD_SHARED_ICON_LARGE(MAKEINTRESOURCE(IDI_PROCESSHACKER)); wcex.hCursor = LoadCursor(NULL, IDC_ARROW); //wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); wcex.lpszMenuName = MAKEINTRESOURCE(IDR_MAINWND); wcex.lpszClassName = PH_MAINWND_CLASSNAME; - wcex.hIconSm = (HICON)LoadImage(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER), IMAGE_ICON, 16, 16, 0); + wcex.hIconSm = PH_LOAD_SHARED_ICON_SMALL(MAKEINTRESOURCE(IDI_PROCESSHACKER)); if (!RegisterClassEx(&wcex)) return FALSE; diff --git a/ProcessHacker/miniinfo.c b/ProcessHacker/miniinfo.c index 743efd387a2b..01d139a083e8 100644 --- a/ProcessHacker/miniinfo.c +++ b/ProcessHacker/miniinfo.c @@ -110,11 +110,11 @@ VOID PhPinMiniInformation( wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = PhInstanceHandle; - wcex.hIcon = LoadIcon(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER)); + wcex.hIcon = PH_LOAD_SHARED_ICON_LARGE(MAKEINTRESOURCE(IDI_PROCESSHACKER)); wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1); wcex.lpszClassName = MIP_CONTAINER_CLASSNAME; - wcex.hIconSm = (HICON)LoadImage(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER), IMAGE_ICON, 16, 16, 0); + wcex.hIconSm = PH_LOAD_SHARED_ICON_SMALL(MAKEINTRESOURCE(IDI_PROCESSHACKER)); RegisterClassEx(&wcex); PhMipContainerWindow = CreateWindow( diff --git a/ProcessHacker/sysinfo.c b/ProcessHacker/sysinfo.c index 317667b112a2..5dcbb236ea54 100644 --- a/ProcessHacker/sysinfo.c +++ b/ProcessHacker/sysinfo.c @@ -281,6 +281,9 @@ VOID PhSipOnInitDialog( VOID ) { + SendMessage(PhSipWindow, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(MAKEINTRESOURCE(IDI_PROCESSHACKER))); + SendMessage(PhSipWindow, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(MAKEINTRESOURCE(IDI_PROCESSHACKER))); + PhInitializeLayoutManager(&WindowLayoutManager, PhSipWindow); PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(PhSipWindow, IDC_INSTRUCTION), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_BOTTOM); From f7cc1e00da46c57b0b8e34b7bf458d64ad0e1043 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 11 May 2017 17:14:01 +1000 Subject: [PATCH 0075/2058] NetworkTools: Fix graph layout bug --- plugins/NetworkTools/ping.c | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/NetworkTools/ping.c b/plugins/NetworkTools/ping.c index 56f39a697b02..0ccb364a7005 100644 --- a/plugins/NetworkTools/ping.c +++ b/plugins/NetworkTools/ping.c @@ -325,6 +325,7 @@ INT_PTR CALLBACK NetworkPingWndProc( PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_ANON_ADDR), NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_LEFT); panelItem = PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_PING_LAYOUT), NULL, PH_ANCHOR_ALL); PhAddLayoutItemEx(&context->LayoutManager, context->PingGraphHandle, NULL, PH_ANCHOR_ALL, panelItem->Margin); + PhLayoutManagerLayout(&context->LayoutManager); if (PhGetIntegerPairSetting(SETTING_NAME_PING_WINDOW_POSITION).X != 0) PhLoadWindowPlacementFromSetting(SETTING_NAME_PING_WINDOW_POSITION, SETTING_NAME_PING_WINDOW_SIZE, hwndDlg); From 7d8fc713defafbb7c6b1f71cc7cf275f4088b462 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 11 May 2017 19:18:22 +1000 Subject: [PATCH 0076/2058] BuildTools: Add vswere support, Fix various issues --- build/build_appx_makecert.cmd | 4 +- build/build_appx_package.cmd | 2 +- build/build_clean.cmd | 2 + build/build_sdk.cmd | 2 + tools/CustomBuildTool/Source Files/Build.cs | 57 +++++++++--------- .../Source Files/NativeMethods.cs | 2 +- tools/CustomBuildTool/Source Files/Program.cs | 16 ++--- .../Source Files/VisualStudio.cs | 32 ++++++++-- .../bin/Release/CustomBuildTool.exe | Bin 162304 -> 162304 bytes .../bin/Release/CustomBuildTool.pdb | Bin 75264 -> 75264 bytes 10 files changed, 71 insertions(+), 46 deletions(-) diff --git a/build/build_appx_makecert.cmd b/build/build_appx_makecert.cmd index 282352f0efaa..f28f3479e3b5 100644 --- a/build/build_appx_makecert.cmd +++ b/build/build_appx_makecert.cmd @@ -2,4 +2,6 @@ @setlocal enableextensions @cd /d "%~dp0\..\" -start /B /W "" "tools\CustomBuildTool\bin\Release\CustomBuildTool.exe" "-appxmakecert" \ No newline at end of file +start /B /W "" "tools\CustomBuildTool\bin\Release\CustomBuildTool.exe" "-appxmakecert" + +pause diff --git a/build/build_appx_package.cmd b/build/build_appx_package.cmd index 54a1f86cb0c3..06227454c85e 100644 --- a/build/build_appx_package.cmd +++ b/build/build_appx_package.cmd @@ -4,4 +4,4 @@ start /B /W "" "tools\CustomBuildTool\bin\Release\CustomBuildTool.exe" "-appxbuild" -pause \ No newline at end of file +pause diff --git a/build/build_clean.cmd b/build/build_clean.cmd index 40de19df02f2..2d0f2c182fe3 100644 --- a/build/build_clean.cmd +++ b/build/build_clean.cmd @@ -3,3 +3,5 @@ @cd /d "%~dp0\..\" start /B /W "" "tools\CustomBuildTool\bin\Release\CustomBuildTool.exe" "-cleanup" + +pause diff --git a/build/build_sdk.cmd b/build/build_sdk.cmd index c3dc6044491f..7a3a7fe039a6 100644 --- a/build/build_sdk.cmd +++ b/build/build_sdk.cmd @@ -3,3 +3,5 @@ @cd /d "%~dp0\..\" start /B /W "" "tools\CustomBuildTool\bin\Release\CustomBuildTool.exe" "-sdk" + +pause diff --git a/tools/CustomBuildTool/Source Files/Build.cs b/tools/CustomBuildTool/Source Files/Build.cs index 10fea83a4cbc..3cb18c2ddfc8 100644 --- a/tools/CustomBuildTool/Source Files/Build.cs +++ b/tools/CustomBuildTool/Source Files/Build.cs @@ -121,11 +121,11 @@ public static class Build public static bool InitializeBuildEnvironment(bool CheckDependencies) { TimeStart = DateTime.Now; + MSBuildExePath = VisualStudio.GetMsbuildFilePath(); + CustomSignToolPath = "tools\\CustomSignTool\\bin\\Release32\\CustomSignTool.exe"; GitExePath = Environment.ExpandEnvironmentVariables("%ProgramFiles%\\Git\\cmd\\git.exe"); - MSBuildExePath = Environment.ExpandEnvironmentVariables(VisualStudio.GetMsbuildFilePath()); CertUtilExePath = Environment.ExpandEnvironmentVariables("%SystemRoot%\\system32\\Certutil.exe"); MakeAppxExePath = Environment.ExpandEnvironmentVariables("%ProgramFiles(x86)%\\Windows Kits\\10\\bin\\x64\\MakeAppx.exe"); - CustomSignToolPath = "tools\\CustomSignTool\\bin\\Release32\\CustomSignTool.exe"; BuildNightly = !string.Equals(Environment.ExpandEnvironmentVariables("%APPVEYOR_BUILD_API%"), "%APPVEYOR_BUILD_API%", StringComparison.OrdinalIgnoreCase); try @@ -231,8 +231,8 @@ public static void ShowBuildEnvironment(string Platform, bool ShowBuildInfo) Program.PrintColorMessage(Platform, ConsoleColor.White, false); } - string currentGitTag = Win32.ExecCommand(GitExePath, "describe --abbrev=0 --tags --always"); - string latestGitRevision = Win32.ExecCommand(GitExePath, "rev-list --count \"" + currentGitTag + ".." + BuildBranch + "\""); + string currentGitTag = Win32.ShellExecute(GitExePath, "describe --abbrev=0 --tags --always"); + string latestGitRevision = Win32.ShellExecute(GitExePath, "rev-list --count \"" + currentGitTag + ".." + BuildBranch + "\""); if (string.IsNullOrEmpty(latestGitRevision)) BuildRevision = "0"; @@ -241,7 +241,7 @@ public static void ShowBuildEnvironment(string Platform, bool ShowBuildInfo) BuildVersion = "3.0." + BuildRevision; BuildLongVersion = "3.0.0." + BuildRevision; - BuildMessage = Win32.ExecCommand(GitExePath, "log -n 5 --date=format:%Y-%m-%d --pretty=format:\"[%cd] %an %s\" --abbrev-commit"); + BuildMessage = Win32.ShellExecute(GitExePath, "log -n 5 --date=format:%Y-%m-%d --pretty=format:\"[%cd] %an %s\" --abbrev-commit"); if (ShowBuildInfo) { @@ -249,17 +249,17 @@ public static void ShowBuildEnvironment(string Platform, bool ShowBuildInfo) if (BuildNightly) { - buildMessage = Win32.ExecCommand(GitExePath, "log -n 5 --date=format:%Y-%m-%d --pretty=format:\"[%cd] %an: %<(65,trunc)%s (%h)\" --abbrev-commit"); + buildMessage = Win32.ShellExecute(GitExePath, "log -n 5 --date=format:%Y-%m-%d --pretty=format:\"[%cd] %an: %<(65,trunc)%s (%h)\" --abbrev-commit"); } else { Win32.GetConsoleMode(Win32.GetStdHandle(Win32.STD_OUTPUT_HANDLE), out ConsoleMode mode); Win32.SetConsoleMode(Win32.GetStdHandle(Win32.STD_OUTPUT_HANDLE), mode | ConsoleMode.ENABLE_VIRTUAL_TERMINAL_PROCESSING); - buildMessage = Win32.ExecCommand(GitExePath, "log -n 5 --date=format:%Y-%m-%d --pretty=format:\"%C(green)[%cd]%Creset %C(bold blue)%an%Creset %<(65,trunc)%s%Creset (%C(yellow)%h%Creset)\" --abbrev-commit"); + buildMessage = Win32.ShellExecute(GitExePath, "log -n 5 --date=format:%Y-%m-%d --pretty=format:\"%C(green)[%cd]%Creset %C(bold blue)%an%Creset %<(65,trunc)%s%Creset (%C(yellow)%h%Creset)\" --abbrev-commit"); } - string currentBranch = Win32.ExecCommand(GitExePath, "rev-parse --abbrev-ref HEAD"); - string currentCommitTag = Win32.ExecCommand(GitExePath, "rev-parse --short HEAD"); // rev-parse HEAD + string currentBranch = Win32.ShellExecute(GitExePath, "rev-parse --abbrev-ref HEAD"); + string currentCommitTag = Win32.ShellExecute(GitExePath, "rev-parse --short HEAD"); // rev-parse HEAD //string latestGitCount = Win32.GitExecCommand("rev-list --count " + BuildBranch); if (!string.IsNullOrEmpty(currentBranch)) @@ -284,14 +284,13 @@ public static void ShowBuildEnvironment(string Platform, bool ShowBuildInfo) } } - public static void ShowBuildStats(bool block) + public static void ShowBuildStats() { TimeSpan buildTime = DateTime.Now - TimeStart; Console.WriteLine(); Console.WriteLine("Build Time: " + buildTime.Minutes + " minute(s), " + buildTime.Seconds + " second(s)"); Console.WriteLine("Build complete."); - if (!BuildNightly && block) Console.ReadKey(); } public static bool CopyTextFiles() @@ -660,13 +659,13 @@ public static bool BuildKphSignatureFile(bool DebugBuild) File.Create("bin\\Debug32\\ProcessHacker.sig").Dispose(); File.Create("bin\\Debug64\\ProcessHacker.sig").Dispose(); - if (!string.IsNullOrEmpty(output = Win32.ExecCommand(CustomSignToolPath, "sign -k build\\kph.key bin\\Debug32\\ProcessHacker.exe -s bin\\Debug32\\ProcessHacker.sig"))) + if (!string.IsNullOrEmpty(output = Win32.ShellExecute(CustomSignToolPath, "sign -k build\\kph.key bin\\Debug32\\ProcessHacker.exe -s bin\\Debug32\\ProcessHacker.sig"))) { Program.PrintColorMessage("[WARN] (Debug32) " + output, ConsoleColor.Yellow); return false; } - if (!string.IsNullOrEmpty(output = Win32.ExecCommand(CustomSignToolPath, "sign -k build\\kph.key bin\\Debug64\\ProcessHacker.exe -s bin\\Debug64\\ProcessHacker.sig"))) + if (!string.IsNullOrEmpty(output = Win32.ShellExecute(CustomSignToolPath, "sign -k build\\kph.key bin\\Debug64\\ProcessHacker.exe -s bin\\Debug64\\ProcessHacker.sig"))) { Program.PrintColorMessage("[WARN] (Debug64) " + output, ConsoleColor.Yellow); return false; @@ -694,13 +693,13 @@ public static bool BuildKphSignatureFile(bool DebugBuild) File.Create("bin\\Release32\\ProcessHacker.sig").Dispose(); File.Create("bin\\Release64\\ProcessHacker.sig").Dispose(); - if (!string.IsNullOrEmpty(output = Win32.ExecCommand(CustomSignToolPath, "sign -k build\\kph.key bin\\Release32\\ProcessHacker.exe -s bin\\Release32\\ProcessHacker.sig"))) + if (!string.IsNullOrEmpty(output = Win32.ShellExecute(CustomSignToolPath, "sign -k build\\kph.key bin\\Release32\\ProcessHacker.exe -s bin\\Release32\\ProcessHacker.sig"))) { Program.PrintColorMessage("[ERROR] (Release32) " + output, ConsoleColor.Red); return false; } - if (!string.IsNullOrEmpty(output = Win32.ExecCommand(CustomSignToolPath, "sign -k build\\kph.key bin\\Release64\\ProcessHacker.exe -s bin\\Release64\\ProcessHacker.sig"))) + if (!string.IsNullOrEmpty(output = Win32.ShellExecute(CustomSignToolPath, "sign -k build\\kph.key bin\\Release64\\ProcessHacker.exe -s bin\\Release64\\ProcessHacker.sig"))) { Program.PrintColorMessage("[ERROR] (Release64) " + output, ConsoleColor.Red); return false; @@ -839,7 +838,7 @@ public static bool BuildSrcZip() if (File.Exists(BuildOutputFolder + "\\processhacker-build-src.zip")) File.Delete(BuildOutputFolder + "\\processhacker-build-src.zip"); - string output = Win32.ExecCommand( + string output = Win32.ShellExecute( GitExePath, "--git-dir=.git " + "--work-tree=.\\ archive " + @@ -935,7 +934,7 @@ public static bool BuildUpdateSignature() return false; } - BuildSetupSig = Win32.ExecCommand( + BuildSetupSig = Win32.ShellExecute( CustomSignToolPath, "sign -k build\\nightly.key " + BuildOutputFolder + "\\processhacker-build-setup.exe -h" ); @@ -1067,7 +1066,7 @@ public static bool AppveyorUploadBuildFiles() try { - Win32.ExecCommand("appveyor", "PushArtifact " + releaseFileArray[i]); + Win32.ShellExecute("appveyor", "PushArtifact " + releaseFileArray[i]); } catch (Exception ex) { @@ -1088,7 +1087,7 @@ public static bool BuildSolution(string Solution, BuildFlags Flags) Program.PrintColorMessage("x32", ConsoleColor.Green, false, Flags); Program.PrintColorMessage(")...", ConsoleColor.Cyan, true, Flags); - string error32 = Win32.ExecCommand( + string error32 = Win32.ShellExecute( MSBuildExePath, "/m /nologo /verbosity:quiet " + "/p:Configuration=" + (Flags.HasFlag(BuildFlags.BuildDebug) ? "Debug" : "Release") + " " + @@ -1108,7 +1107,7 @@ public static bool BuildSolution(string Solution, BuildFlags Flags) Program.PrintColorMessage("x64", ConsoleColor.Green, false, Flags); Program.PrintColorMessage(")...", ConsoleColor.Cyan, true, Flags); - string error64 = Win32.ExecCommand( + string error64 = Win32.ShellExecute( MSBuildExePath, "/m /nologo /verbosity:quiet " + "/p:Configuration=" + (Flags.HasFlag(BuildFlags.BuildDebug) ? "Debug" : "Release") + " " + @@ -1181,14 +1180,14 @@ public static void BuildAppxPackage(BuildFlags Flags) File.WriteAllText("build\\output\\package32.map", packageMap32.ToString()); // create the package - error = Win32.ExecCommand( + error = Win32.ShellExecute( MakeAppxExePath, "pack /o /f build\\output\\package32.map /p " + BuildOutputFolder + "\\output\\processhacker-build-package-x32.appx" ); Program.PrintColorMessage(Environment.NewLine + error, ConsoleColor.Gray); // sign the package - error = Win32.ExecCommand( + error = Win32.ShellExecute( signToolExePath, "sign /v /fd SHA256 /a /f build\\processhacker-appx.pfx /td SHA256 " + BuildOutputFolder + "\\output\\processhacker-build-package-x32.appx" ); @@ -1230,14 +1229,14 @@ public static void BuildAppxPackage(BuildFlags Flags) File.WriteAllText("build\\output\\package64.map", packageMap64.ToString()); // create the package - error = Win32.ExecCommand( + error = Win32.ShellExecute( MakeAppxExePath, "pack /o /f build\\output\\package64.map /p " + BuildOutputFolder + "\\output\\processhacker-build-package-x64.appx" ); Program.PrintColorMessage(Environment.NewLine + error, ConsoleColor.Gray); // sign the package - error = Win32.ExecCommand( + error = Win32.ShellExecute( signToolExePath, "sign /v /fd SHA256 /a /f build\\processhacker-appx.pfx /td SHA256 " + BuildOutputFolder + "\\output\\processhacker-build-package-x64.appx" ); @@ -1253,14 +1252,14 @@ public static void BuildAppxPackage(BuildFlags Flags) File.WriteAllText("build\\output\\bundle.map", bundleMap.ToString()); // create the appx bundle package - error = Win32.ExecCommand( + error = Win32.ShellExecute( MakeAppxExePath, "bundle /f build\\output\\bundle.map /p " + BuildOutputFolder + "\\processhacker-build-package.appxbundle" ); Program.PrintColorMessage(Environment.NewLine + error, ConsoleColor.Gray); // sign the appx bundle package - error = Win32.ExecCommand( + error = Win32.ShellExecute( signToolExePath, "sign /v /fd SHA256 /a /f build\\processhacker-appx.pfx /td SHA256 " + BuildOutputFolder + "\\processhacker-build-package.appxbundle" ); @@ -1291,7 +1290,7 @@ public static bool BuildAppxSignature() if (File.Exists("build\\processhacker-appx.pfx")) File.Delete("build\\processhacker-appx.pfx"); - string output = Win32.ExecCommand(makeCertExePath, + string output = Win32.ShellExecute(makeCertExePath, "/n " + "\"CN=ProcessHacker, O=ProcessHacker, C=AU\" " + "/r /h 0 " + @@ -1307,7 +1306,7 @@ public static bool BuildAppxSignature() return false; } - output = Win32.ExecCommand(pvk2PfxExePath, + output = Win32.ShellExecute(pvk2PfxExePath, "/pvk build\\processhacker-appx.pvk " + "/spc build\\processhacker-appx.cer " + "/pfx build\\processhacker-appx.pfx " @@ -1319,7 +1318,7 @@ public static bool BuildAppxSignature() return false; } - output = Win32.ExecCommand(CertUtilExePath, + output = Win32.ShellExecute(CertUtilExePath, "-addStore TrustedPeople build\\processhacker-appx.cer" ); diff --git a/tools/CustomBuildTool/Source Files/NativeMethods.cs b/tools/CustomBuildTool/Source Files/NativeMethods.cs index 865a24548d52..3f16de01e59d 100644 --- a/tools/CustomBuildTool/Source Files/NativeMethods.cs +++ b/tools/CustomBuildTool/Source Files/NativeMethods.cs @@ -7,7 +7,7 @@ namespace CustomBuildTool [System.Security.SuppressUnmanagedCodeSecurity] public static class Win32 { - public static string ExecCommand(string FileName, string args) + public static string ShellExecute(string FileName, string args) { string output = string.Empty; using (Process process = Process.Start(new ProcessStartInfo diff --git a/tools/CustomBuildTool/Source Files/Program.cs b/tools/CustomBuildTool/Source Files/Program.cs index b70f7ea3cc08..86e74aaceef4 100644 --- a/tools/CustomBuildTool/Source Files/Program.cs +++ b/tools/CustomBuildTool/Source Files/Program.cs @@ -23,7 +23,7 @@ public static void Main(string[] args) Build.CleanupAppxSignature(); Build.CleanupBuildEnvironment(); - Build.ShowBuildStats(true); + Build.ShowBuildStats(); } else if (ProgramArgs.ContainsKey("-phapppub_gen")) { @@ -56,7 +56,7 @@ public static void Main(string[] args) BuildFlags.BuildDebug | BuildFlags.BuildVerbose ); - Build.ShowBuildStats(false); + Build.ShowBuildStats(); } else if (ProgramArgs.ContainsKey("-cleansdk")) { @@ -77,7 +77,7 @@ public static void Main(string[] args) BuildFlags.Build32bit | BuildFlags.Build64bit | BuildFlags.BuildVerbose)) return; - Build.ShowBuildStats(false); + Build.ShowBuildStats(); } else if (ProgramArgs.ContainsKey("-bin")) { @@ -119,7 +119,7 @@ public static void Main(string[] args) if (!Build.BuildBinZip()) return; - Build.ShowBuildStats(false); + Build.ShowBuildStats(); } else if (ProgramArgs.ContainsKey("-debug")) { @@ -163,7 +163,7 @@ public static void Main(string[] args) BuildFlags.Build32bit | BuildFlags.Build64bit | BuildFlags.BuildDebug | BuildFlags.BuildVerbose); - Build.ShowBuildStats(true); + Build.ShowBuildStats(); } else if (ProgramArgs.ContainsKey("-release")) { @@ -211,7 +211,7 @@ public static void Main(string[] args) Build.BuildSdkZip(); Build.BuildSrcZip(); - Build.ShowBuildStats(true); + Build.ShowBuildStats(); } else if (ProgramArgs.ContainsKey("-appveyor")) { @@ -292,7 +292,7 @@ public static void Main(string[] args) Build.BuildAppxPackage(BuildFlags.Build32bit | BuildFlags.Build64bit | BuildFlags.BuildVerbose); - Build.ShowBuildStats(true); + Build.ShowBuildStats(); } else if (ProgramArgs.ContainsKey("-appxmakecert")) { @@ -306,7 +306,7 @@ public static void Main(string[] args) Build.BuildAppxSignature(); - Build.ShowBuildStats(true); + Build.ShowBuildStats(); } else { diff --git a/tools/CustomBuildTool/Source Files/VisualStudio.cs b/tools/CustomBuildTool/Source Files/VisualStudio.cs index f185d5be5f4d..adef9214779a 100644 --- a/tools/CustomBuildTool/Source Files/VisualStudio.cs +++ b/tools/CustomBuildTool/Source Files/VisualStudio.cs @@ -9,17 +9,37 @@ public static class VisualStudio { public static string GetMsbuildFilePath() { - VisualStudioInstance instance = FindVisualStudioInstance(); + string vswhere = Environment.ExpandEnvironmentVariables("%ProgramFiles(x86)%\\Microsoft Visual Studio\\Installer\\vswhere.exe"); - if (instance != null) + // Note: vswere.exe was only released with build 15.0.26418.1 + if (File.Exists(vswhere)) { - if (File.Exists(instance.Path + "\\MSBuild\\15.0\\Bin\\MSBuild.exe")) + string vswhereResult = Win32.ShellExecute(vswhere, + "-latest " + + "-requires Microsoft.Component.MSBuild " + + "-property installationPath " + ); + + if (string.IsNullOrEmpty(vswhereResult)) + return null; + + if (File.Exists(vswhereResult + "\\MSBuild\\15.0\\Bin\\MSBuild.exe")) + return vswhereResult + "\\MSBuild\\15.0\\Bin\\MSBuild.exe"; + + return null; + } + else + { + VisualStudioInstance instance = FindVisualStudioInstance(); + + if (instance != null) { - return instance.Path + "\\MSBuild\\15.0\\Bin\\MSBuild.exe"; + if (File.Exists(instance.Path + "\\MSBuild\\15.0\\Bin\\MSBuild.exe")) + return instance.Path + "\\MSBuild\\15.0\\Bin\\MSBuild.exe"; } - } - return null; + return null; + } } private static VisualStudioInstance FindVisualStudioInstance() diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe b/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe index 6675d24006fe65a5d44294098977dbb2bd994260..849821b11f52a0e3e5df8888a492e1be6d1b1e31 100644 GIT binary patch delta 14051 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 delta 14004 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 diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb b/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb index 7f64725b18499f7050cdefb749e8a03e49e92f30..46d5a6f6accef820c7b1ea63aa124c0101187bc6 100644 GIT binary patch delta 13303 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 From fae9aa74492f90f49186f4b2f1be8ba8231dcb43 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 11 May 2017 19:52:49 +1000 Subject: [PATCH 0077/2058] CommonUtil: Fix file encoding --- .gitattributes | 1 + plugins/CommonUtil/resource.h | Bin 1174 -> 567 bytes plugins/CommonUtil/resource.rc | Bin 5726 -> 2743 bytes plugins/Plugins.sln | 2 +- 4 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitattributes b/.gitattributes index 8d499c1de08f..0fb12ca3d9a1 100644 --- a/.gitattributes +++ b/.gitattributes @@ -15,6 +15,7 @@ *.config eol=crlf *.cmd eol=crlf *.csproj eol=crlf +*.filters eol=crlf *.h eol=crlf *.md eol=crlf *.manifest eol=crlf diff --git a/plugins/CommonUtil/resource.h b/plugins/CommonUtil/resource.h index 5be361921482250531dd764876da8bb0a181d13b..72caa7b05f55651c274fe1c7a6dd444148d73e91 100644 GIT binary patch literal 567 zcmaKp%WA_g5JmU?iUBVJvDBs?;7Ed++EVa~W+fbZTvUt=e)K`ezt>J_69>1m(QtKi zxubEM<54Qj#ZE{rB=bacI$4ebfyvvZYswx{(+yb#Y_)a4AaY-|PiDca+>Mv7TIT zrsV!VcIHgU#+pWv_|e0dI~%GV-m+@I4$7v58sDKgykg#W6K2__94T;jQJip3X-}r= zN$^RpXBVMxxsv`~NBdx_{OC849^Yyyo?{(~NF^Z?I(7X-{KTTXXz4nn2-u9c-K&8PdWeBq~ znLRtR=OkaB1r_v;MQUoOKsB{^BEO1MRh_7#5A0MY)E49vYNoMPS}Ng*wI>+za;23yVco(u+HHm+=`AQ&|foVosoQ0{%{_!XTJ?CdEg;u99GP6HsiPD#FjTXmloEKW&$*Myz( z#E=#IsFJh1RVU9pF`gUDbrc!4eFq;O&|dV_xfvlxy_0O!F$2{^AU?Rrv@P$k2VS7H z1(6zfrHzxQEhluJka6``Mao6;r=r1HqJd= z?vvu+_;lIv$7_-l6qfWTbVw$IMQ6*7%SDsVL&>|11bNw+=b>9k6q)lhs0nPHKs`xk?O>@f^i#RFBZye<~X33`iy4~^X zxP@mqEySBehULL$LtQj4wtW=1zt@rhrgri?(oZvU%@*Mzd}4|75+evPES!_&Ev9ZF3TFDY}j7?E(KrBvDslUDL^UiS0 zE-X$UskGH~a{|1E>?;-ZOg`=2kY=SM7JJgxOko z5a!*5b>jV#U0TPw*0WP0emOeuL8Cd2Tf*E&9H{FqH3dblxV`Krib$ zzC%k>dqDmL+L0c*Nc}6%CQ_dur}R;W{)&6uBA>RwhoIlMF0cRcY0MEt?|4L4@}xWD z-p@B&^Uk+it)ok@?u7We$5JUikl6Rg`$&I*y%nWno-YclpJrld9Q5>EE~bWo(;40r zW2r;j^oXhxb{ybUEiUo>i!0f>vJ0BG`0jvJ7xZ6*U0d`np!R4R!9Sf6=QZHnBu0O> zm+k0vZH0*l?9{5v`QIepFN6leZ@92O~tP8;48d4X8je)ZHQj)iD=h-4nig# z5?RVF@ltju$~2qa<~Ax_mgHx| znO0}tI9;m~W;BWH`r4cX4}OW?`5ot8!oQ6N_Q*lq&syQ!&qDTSfbN`Z(INH|xPP?Q zSg;l3kyoy=hVomToYNyp@;FzVB8TIr^|$2O6g@pZ|0pwGCzN*0uV{lW@_qwGU2m3a zR@&-P$y|ak&U>}-K4#4PEZ?~}_LX1T=vA7jfIz2*YO)a)8Y9^)cA9{7x)zPa+&n7s zT#u;mj_k)E(L0{`xL&O(%1!>(+dg(wbt4^Az^y81#z{A^Kk>V3Mz_#)dQ{M|MjyBA zSIp6+K4oRLZjBM(oa4R^Au1B~SN%E)dP{1o1HSXU5anah zksMP|Z_{Y8gtDh<^*OETgmtauac5Cim->!!_uwKADYjbVR=wVBfV;=Ifu37o<$I#Kx)YlAa(DT=G~u?_DC7!w3@b@?ZN@9?9;WwWZrkE^vuaGK+OEJN?;hKGVt5c@SeCyb z#;f)Ytg~f|3TH7!RSLy8zZS+A@t=>=HC`@%a5Rq2Tb(`n%JQ*V-No9@YC3P}$R$sE zZnTd_%!uL9&K|Ks@wG61$|KfsZvPhevhQ-YY57|BB5z~m{M_G`&2OOcN#%$nmHOU( j>3=tUlRp37&GqOA%GV0vc0Zp`!RgQN=3ll=yNlDmybi1J diff --git a/plugins/Plugins.sln b/plugins/Plugins.sln index 15c2c8271d2b..931a8541035a 100644 --- a/plugins/Plugins.sln +++ b/plugins/Plugins.sln @@ -1,4 +1,4 @@ - + Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 VisualStudioVersion = 15.0.26403.7 From 1f49a46b4c3216c021396650bdab6fe32cec5bd0 Mon Sep 17 00:00:00 2001 From: ForeverOf14 Date: Thu, 11 May 2017 19:44:16 +0800 Subject: [PATCH 0078/2058] PHNT header - new APIs (#137) * Add API-Def: LdrDisableThreadCalloutsForDll * Add API-Def EtwEventRegister * Create ntsmss.h * Add APIs * Complete basic API def * Update ntsmss.h --- phnt/include/ntdbg.h | 11 +++++++++++ phnt/include/ntldr.h | 7 +++++++ phnt/include/ntsmss.h | 22 ++++++++++++++++++++++ 3 files changed, 40 insertions(+) create mode 100644 phnt/include/ntsmss.h diff --git a/phnt/include/ntdbg.h b/phnt/include/ntdbg.h index 2be47c2263d4..6d3ea5435607 100644 --- a/phnt/include/ntdbg.h +++ b/phnt/include/ntdbg.h @@ -244,4 +244,15 @@ DbgUiConvertStateChangeStructure( _Out_ struct _DEBUG_EVENT *DebugEvent ); + +NTSYSAPI +NTSTATUS +NTAPI +EtwEventRegister( + _In_ LPCGUID ProviderId, + _In_opt_ PENABLECALLBACK EnableCallback, + _In_opt_ PVOID CallbackContext, + _Out_ PREGHANDLE RegHandle + ); + #endif diff --git a/phnt/include/ntldr.h b/phnt/include/ntldr.h index 2434c2bfe125..9eef05a15b73 100644 --- a/phnt/include/ntldr.h +++ b/phnt/include/ntldr.h @@ -525,6 +525,13 @@ LdrGetFileNameFromLoadAsDataTable( #endif +NTSYSAPI +NTSTATUS +NTAPI +LdrDisableThreadCalloutsForDll( + _In_ PVOID DllImageBase + ); + #endif // (PHNT_MODE != PHNT_MODE_KERNEL) // Module information diff --git a/phnt/include/ntsmss.h b/phnt/include/ntsmss.h new file mode 100644 index 000000000000..07b91b530b03 --- /dev/null +++ b/phnt/include/ntsmss.h @@ -0,0 +1,22 @@ +#ifndef _NTSMSS_H +#define _NTSMSS_H + +NTSYSAPI +NTSTATUS +NTAPI +RtlConnectToSm( + _In_ PUNICODE_STRING ApiPortName, + _In_ HANDLE ApiPortHandle, + _In_ DWORD ProcessImageType, + _Out_ PHANDLE SmssConnection + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlSendMsgToSm( + _In_ HANDLE ApiPortHandle, + _In_ PPORT_MESSAGE MessageData + ); + +#endif From c911c86808e7d8ad6d09e9b3eddb6aef7e0bb698 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 11 May 2017 21:47:51 +1000 Subject: [PATCH 0079/2058] Fix spacing --- phnt/include/ntdbg.h | 11 +++++------ phnt/include/ntsmss.h | 12 ++++++------ 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/phnt/include/ntdbg.h b/phnt/include/ntdbg.h index 6d3ea5435607..f47d1240614d 100644 --- a/phnt/include/ntdbg.h +++ b/phnt/include/ntdbg.h @@ -244,15 +244,14 @@ DbgUiConvertStateChangeStructure( _Out_ struct _DEBUG_EVENT *DebugEvent ); - NTSYSAPI NTSTATUS NTAPI EtwEventRegister( - _In_ LPCGUID ProviderId, - _In_opt_ PENABLECALLBACK EnableCallback, - _In_opt_ PVOID CallbackContext, - _Out_ PREGHANDLE RegHandle - ); + _In_ LPCGUID ProviderId, + _In_opt_ PENABLECALLBACK EnableCallback, + _In_opt_ PVOID CallbackContext, + _Out_ PREGHANDLE RegHandle + ); #endif diff --git a/phnt/include/ntsmss.h b/phnt/include/ntsmss.h index 07b91b530b03..8f377ac64142 100644 --- a/phnt/include/ntsmss.h +++ b/phnt/include/ntsmss.h @@ -5,18 +5,18 @@ NTSYSAPI NTSTATUS NTAPI RtlConnectToSm( - _In_ PUNICODE_STRING ApiPortName, - _In_ HANDLE ApiPortHandle, - _In_ DWORD ProcessImageType, - _Out_ PHANDLE SmssConnection + _In_ PUNICODE_STRING ApiPortName, + _In_ HANDLE ApiPortHandle, + _In_ DWORD ProcessImageType, + _Out_ PHANDLE SmssConnection ); NTSYSAPI NTSTATUS NTAPI RtlSendMsgToSm( - _In_ HANDLE ApiPortHandle, - _In_ PPORT_MESSAGE MessageData + _In_ HANDLE ApiPortHandle, + _In_ PPORT_MESSAGE MessageData ); #endif From 30c4820d068ec6d3711c4ed2bba352d534772ca4 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 12 May 2017 01:49:07 +1000 Subject: [PATCH 0080/2058] Add missing defs from PR #137 --- phnt/include/ntdbg.h | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/phnt/include/ntdbg.h b/phnt/include/ntdbg.h index f47d1240614d..5cc3b32d4e10 100644 --- a/phnt/include/ntdbg.h +++ b/phnt/include/ntdbg.h @@ -244,6 +244,25 @@ DbgUiConvertStateChangeStructure( _Out_ struct _DEBUG_EVENT *DebugEvent ); +typedef struct _EVENT_FILTER_DESCRIPTOR +{ + ULONGLONG Ptr; + ULONG Size; + ULONG Type; +} EVENT_FILTER_DESCRIPTOR, *PEVENT_FILTER_DESCRIPTOR; + +typedef VOID (NTAPI *PENABLECALLBACK)( + _In_ LPCGUID SourceId, + _In_ ULONG IsEnabled, + _In_ UCHAR Level, + _In_ ULONGLONG MatchAnyKeyword, + _In_ ULONGLONG MatchAllKeyword, + _In_opt_ PEVENT_FILTER_DESCRIPTOR FilterData, + _Inout_opt_ PVOID CallbackContext + ); + +typedef ULONGLONG REGHANDLE, *PREGHANDLE; + NTSYSAPI NTSTATUS NTAPI From db0a24949cc2003220d1ee8ac98fbd14297c252a Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 12 May 2017 01:54:35 +1000 Subject: [PATCH 0081/2058] *Fix last commit --- phnt/include/ntdbg.h | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/phnt/include/ntdbg.h b/phnt/include/ntdbg.h index 5cc3b32d4e10..deb804e5cee0 100644 --- a/phnt/include/ntdbg.h +++ b/phnt/include/ntdbg.h @@ -244,12 +244,7 @@ DbgUiConvertStateChangeStructure( _Out_ struct _DEBUG_EVENT *DebugEvent ); -typedef struct _EVENT_FILTER_DESCRIPTOR -{ - ULONGLONG Ptr; - ULONG Size; - ULONG Type; -} EVENT_FILTER_DESCRIPTOR, *PEVENT_FILTER_DESCRIPTOR; +struct _EVENT_FILTER_DESCRIPTOR; typedef VOID (NTAPI *PENABLECALLBACK)( _In_ LPCGUID SourceId, @@ -257,7 +252,7 @@ typedef VOID (NTAPI *PENABLECALLBACK)( _In_ UCHAR Level, _In_ ULONGLONG MatchAnyKeyword, _In_ ULONGLONG MatchAllKeyword, - _In_opt_ PEVENT_FILTER_DESCRIPTOR FilterData, + _In_opt_ struct _EVENT_FILTER_DESCRIPTOR *FilterData, _Inout_opt_ PVOID CallbackContext ); From c9218f35837ed4878bbe51eb5db64bf53598709b Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 12 May 2017 01:57:16 +1000 Subject: [PATCH 0082/2058] peview: Fix symbol VA column --- tools/peview/pdb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/peview/pdb.c b/tools/peview/pdb.c index a9e4f4d5c58c..124b0209c8b8 100644 --- a/tools/peview/pdb.c +++ b/tools/peview/pdb.c @@ -1831,7 +1831,7 @@ VOID SymInfoDump_SymbolLocationStr( else { //_swprintf(Buffer, L"%16I64x", SymbolInfo->Address); - PhPrintPointer(Buffer, (PVOID)SymbolInfo->Address); + PhPrintPointer(Buffer, PTR_SUB_OFFSET(SymbolInfo->Address, SymbolInfo->ModBase)); } } From bcec265f015e48b4f9431b52fcb1926dfdb6deb2 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 12 May 2017 14:45:23 +1000 Subject: [PATCH 0083/2058] Update ntpsapi.h --- phnt/include/ntpsapi.h | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/phnt/include/ntpsapi.h b/phnt/include/ntpsapi.h index 50d71d513272..2011aa3915cc 100644 --- a/phnt/include/ntpsapi.h +++ b/phnt/include/ntpsapi.h @@ -1174,12 +1174,11 @@ NtWaitForAlertByThreadId( // Attributes -// begin_rev +// private #define PS_ATTRIBUTE_NUMBER_MASK 0x0000ffff -#define PS_ATTRIBUTE_THREAD 0x00010000 // can be used with threads +#define PS_ATTRIBUTE_THREAD 0x00010000 // may be used with thread creation #define PS_ATTRIBUTE_INPUT 0x00020000 // input only -#define PS_ATTRIBUTE_UNKNOWN 0x00040000 -// end_rev +#define PS_ATTRIBUTE_ADDITIVE 0x00040000 // "accumulated" e.g. bitmasks, counters, etc. // private typedef enum _PS_ATTRIBUTE_NUM @@ -1215,18 +1214,18 @@ typedef enum _PS_ATTRIBUTE_NUM // begin_rev -#define PsAttributeValue(Number, Thread, Input, Unknown) \ +#define PsAttributeValue(Number, Thread, Input, Additive) \ (((Number) & PS_ATTRIBUTE_NUMBER_MASK) | \ ((Thread) ? PS_ATTRIBUTE_THREAD : 0) | \ ((Input) ? PS_ATTRIBUTE_INPUT : 0) | \ - ((Unknown) ? PS_ATTRIBUTE_UNKNOWN : 0)) + ((Additive) ? PS_ATTRIBUTE_ADDITIVE : 0)) #define PS_ATTRIBUTE_PARENT_PROCESS \ - PsAttributeValue(PsAttributeParentProcess, FALSE, TRUE, TRUE) + PsAttributeValue(PsAttributeParentProcess, FALSE, TRUE, FALSE) #define PS_ATTRIBUTE_DEBUG_PORT \ - PsAttributeValue(PsAttributeDebugPort, FALSE, TRUE, TRUE) + PsAttributeValue(PsAttributeDebugPort, FALSE, TRUE, FALSE) #define PS_ATTRIBUTE_TOKEN \ - PsAttributeValue(PsAttributeToken, FALSE, TRUE, TRUE) + PsAttributeValue(PsAttributeToken, FALSE, TRUE, FALSE) #define PS_ATTRIBUTE_CLIENT_ID \ PsAttributeValue(PsAttributeClientId, TRUE, FALSE, FALSE) #define PS_ATTRIBUTE_TEB_ADDRESS \ From ace57e91087a89aae3d41b7eb2bfe5f54f4d7349 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 12 May 2017 15:02:42 +1000 Subject: [PATCH 0084/2058] BuildTools: update binaries, update installer --- tools/CustomBuildTool/Source Files/Build.cs | 2 +- tools/CustomBuildTool/Source Files/Program.cs | 11 +++--- .../bin/Release/CustomBuildTool.exe | Bin 162304 -> 162304 bytes .../bin/Release/CustomBuildTool.pdb | Bin 75264 -> 75264 bytes .../CustomSetupTool/CustomSetupTool/extract.c | 37 ++++++++---------- tools/CustomSetupTool/CustomSetupTool/setup.c | 2 +- 6 files changed, 24 insertions(+), 28 deletions(-) diff --git a/tools/CustomBuildTool/Source Files/Build.cs b/tools/CustomBuildTool/Source Files/Build.cs index 3cb18c2ddfc8..ddacc7449635 100644 --- a/tools/CustomBuildTool/Source Files/Build.cs +++ b/tools/CustomBuildTool/Source Files/Build.cs @@ -277,7 +277,7 @@ public static void ShowBuildEnvironment(string Platform, bool ShowBuildInfo) Program.PrintColorMessage("Commit: ", ConsoleColor.Cyan, false); Program.PrintColorMessage(currentCommitTag + Environment.NewLine, ConsoleColor.White); - if (!BuildNightly && !string.IsNullOrEmpty(buildMessage)) + if (!string.IsNullOrEmpty(buildMessage)) { Console.WriteLine(buildMessage + Environment.NewLine); } diff --git a/tools/CustomBuildTool/Source Files/Program.cs b/tools/CustomBuildTool/Source Files/Program.cs index 86e74aaceef4..a86af9947fed 100644 --- a/tools/CustomBuildTool/Source Files/Program.cs +++ b/tools/CustomBuildTool/Source Files/Program.cs @@ -159,10 +159,6 @@ public static void Main(string[] args) if (!Build.CopyWow64Files(BuildFlags.BuildDebug)) return; - Build.CopyRedistFiles( - BuildFlags.Build32bit | BuildFlags.Build64bit | - BuildFlags.BuildDebug | BuildFlags.BuildVerbose); - Build.ShowBuildStats(); } else if (ProgramArgs.ContainsKey("-release")) @@ -201,8 +197,6 @@ public static void Main(string[] args) if (!Build.CopyWow64Files(BuildFlags.None)) return; - Build.CopyRedistFiles(BuildFlags.Build32bit | BuildFlags.Build64bit | BuildFlags.BuildVerbose); - if (!Build.BuildBinZip()) return; if (!Build.BuildSetupExe()) @@ -249,6 +243,11 @@ public static void Main(string[] args) if (!Build.CopyWow64Files(BuildFlags.None)) return; + Build.CopyRedistFiles( + BuildFlags.Build32bit | BuildFlags.Build64bit | + BuildFlags.BuildDebug | BuildFlags.BuildVerbose + ); + if (!Build.BuildBinZip()) return; if (!Build.BuildSetupExe()) diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe b/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe index 849821b11f52a0e3e5df8888a492e1be6d1b1e31..3ee36479e5975a4aa2752484c2f7ebc0eea2e8a4 100644 GIT binary patch delta 1805 zcmY+_4NTN!90&04a~$x0{&&cqoo=f1z^`9E*B zr}qKveLxTI4;d<38aR|dt_DuGkR3W9siCDRLA-urCR1-CsboUmOMFSEECl@JW^WTh zVSgTQybJJO_W)s;!6Z{h2)V593H{piH*|N{omeF;6Hv1>C2bY^PD|z=tJz0-ur7Qc zom>ds&YmQsPrs1c8cout234Vbr2Z@?=rkFmm{5A-&dUq6yd^|N`3{<|xce5xnr z`AyD9{U=vU@O<94(LQ$yAJ-s4myg4Y&!mpUEhuKVSBk90G0${UDmLzs5{k>IB2$^d zQ1*mSMZ$s-4r_+c&KRx%sW(_*(#^Y}m3q>q5Q;OZCLfMLiS};&9bb<9^#dL+xHA7>STmeUC>^Q7AR1N-ozoR)e zjB$W%-~amSS+2d<92Z5c=;SBIP%@3cgw#}AKGhKK;h7&hBf}7dxpktFU=58z;d-t? z{1VwiY#5Td6Inx}F~?-#;f}~2*wL>asA(XH!CN&6A-=3y-p;R_GkcMZJgG0t8q?EK zuiCxHLA6w$U1O@1(rjMjqD9JS)0j3%{lhXBdZet;8q+qZRncDLVW&^Bl!bZNCl$-W zd>oW|oMrjYrB=jvQGg>-*)bZ^38^GD&_bM%%3=d8#OQyOnioa5C{?6sOjm1-W8qge zDqa-hx(v4{8WY0mYD$hFa(@LCaHjc$0-e;^vRf`C>(&w-im!xb_Bk;i8%Ci86%B*@>yJ9IC#Z@82H`D_U6Pv$ZdCw@Vm*MPE9=1z07!6;L zN-?xW>U%@mr7GD8@?e)#iS-d1Xul9!!w}Vjo^~;bPvWRrgE=lATegp5Y-9uGI(RsU z-Sv3CX;^C3vYhFZ)D7ndnig$n6D}E< zuMeAXpESX_k#{Qou+57~n~`B;eK>&>wHf772a&F}V6D_?vRZ9LqtrK~RBc12)NSHc z+ZXlO0k6n%kU^T%4&0KZ56K$ZiFrd}FkOopc7X&>*8jOrn>zkx!Nsxe^&ci*xm!4z zJrMk8YIs>DyQGX2H?g_Ivpc7iT~VzwKz&11L#lJ=%kQ>@R_%}Oem(unkGq1qXA}}~ pR9;wo_UH7#y*P48AGz19ml3UR$?W+hvt;3b>8q0SQ6AGn@-K@abqxRj delta 1793 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 zai�JjmoAP7~a}{bBwE0!`&Hw?4fw#ID@-}cTTHxcKTEC zR=5zyFvoIeT~T4I?Sehs*(izNF|JZ16vp;gV9Cx5Pc0MLi*A}N&Wk$Omiv%*r4Gxj zo4?u?;6?s^p`yjvcS>arzHGRJ%1?26b|q{b2p=>ar{)lid6K$LtxJwlwAMaTV9R`5 zuTPuSt^BO7Yg;f`uel_T36nl?;UOvq ztA{9k+xm-3^w6$C!#UI$+&kQlr)9=dobmI;N&YFCRr)e8)zzj)hg!TMOnyp53(gFkQLyzJ50CT@y2HTc;Y7cw4UP6eJJIL)~#)8ZGl_r z=e87KRT!nM5QjEL@LZ`UqJ&uCT!Efi4vrT6oF2MsxP74wbZQFGBAt#LLFz_&6L!^8 z6u61&?rO2UzUwU9My$K*jAB<@cURhaUCYH&yA2Iv<_PW@&fw76+LD!|B_CUVC52Le ztutVYP?DD|Nl78p$&o=_W%+qoUjA4%%kn^39_~o3YUiq)Evpk{wLq>s^RfJ%EYFeU z1+x5uQ|@5BpC!Ftx?W?w#r>=&*L*)KJw}N4of)3macG!3NAT3HLd*SAO<_#yDSvv9 zWS;_$eQO~^mj^x`n)CtSXC+Vau)*o|n zM#gy=O)@UaxFO?r84qQ6*)%HD^OMnDhE7I=tyD!iEbhxj9DAK^DLpPHub2ETFUg*o zbjoyXKc1R&h^+q8HrL(F#Hmv{&P$=4)nfrmU($NW8oo`sFK+3h8g?f~@YKp%H|kMu zCA8o_t+(T@Rr-A5y7&CVj#hWmgG}lBlB=S>NPWB$k$8})!FNX2Rd{M4(6Hk?Jn(J6*R50Lw9Z6UFn0U#;FCg8X1L9;1$`n>KO{4 d`n{W;p$T43{ol^supk=aLj`*aJJK@0{|7ah5DfqT delta 6661 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 / 2) - 4)); } else { - if (strstr(zipFileStat.m_filename, "x64\\")) + if (!strncmp(zipFileStat.m_filename, "x64\\", 4)) + continue; + if (!strncmp(zipFileStat.m_filename, "x86\\", 4)) continue; + + fileName = PhConvertUtf8ToUtf16(zipFileStat.m_filename); + + if (PhFindStringInString(fileName, 0, L"x32\\") != -1) + PhMoveReference(&fileName, PhSubstring(fileName, 4, (fileName->Length / 2) - 4)); } if (!(buffer = mz_zip_reader_extract_to_heap( @@ -140,21 +152,6 @@ BOOLEAN SetupExtractBuild( if ((zipFileCrc32 = mz_crc32(zipFileCrc32, buffer, bufferLength)) != zipFileStat.m_crc32) goto CleanupExit; - if (info.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) - { - fileName = PhConvertUtf8ToUtf16(zipFileStat.m_filename); - - if (PhFindStringInString(fileName, 0, L"x64\\") != -1) - PhMoveReference(&fileName, PhSubstring(fileName, 4, (fileName->Length / 2) - 4)); - } - else - { - fileName = PhConvertUtf8ToUtf16(zipFileStat.m_filename); - - if (PhFindStringInString(fileName, 0, L"x32\\") != -1) - PhMoveReference(&fileName, PhSubstring(fileName, 4, (fileName->Length / 2) - 4)); - } - extractPath = PhConcatStrings(3, PhGetString(SetupInstallPath), L"\\", PhGetString(fileName)); //OutputDebugString(PhFormatString(L"%s\r\n", extractPath->Buffer)->Buffer); diff --git a/tools/CustomSetupTool/CustomSetupTool/setup.c b/tools/CustomSetupTool/CustomSetupTool/setup.c index fd9cbe189fc9..a53268c0c517 100644 --- a/tools/CustomSetupTool/CustomSetupTool/setup.c +++ b/tools/CustomSetupTool/CustomSetupTool/setup.c @@ -265,7 +265,7 @@ VOID SetupInstallKph( VOID ) { - PPH_STRING clientPath = PhFormatString(L"%s\\ProcessHacker.exe", PhGetString(SetupInstallPath)); + PPH_STRING clientPath = PhConcatStrings2(PhGetString(SetupInstallPath), L"\\ProcessHacker.exe"); if (RtlDoesFileExists_U(PhGetString(clientPath))) { From 361b6b39f485c46861b06b5f57eaf64ac21f23e3 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 12 May 2017 15:41:40 +1000 Subject: [PATCH 0085/2058] Remove splitter hack --- ProcessHacker/include/splitter.h | 2 +- ProcessHacker/splitter.c | 19 ++++++------------- 2 files changed, 7 insertions(+), 14 deletions(-) diff --git a/ProcessHacker/include/splitter.h b/ProcessHacker/include/splitter.h index f872c7a7483a..c1d6fcb4a3dd 100644 --- a/ProcessHacker/include/splitter.h +++ b/ProcessHacker/include/splitter.h @@ -18,7 +18,7 @@ typedef struct _PH_HSPLITTER_CONTEXT LONG SplitterOffset; LONG SplitterPosition; - ULONG SplitterLayoutCount; + PH_LAYOUT_MANAGER LayoutManager; PPH_LAYOUT_ITEM Topitem; PPH_LAYOUT_ITEM Bottomitem; diff --git a/ProcessHacker/splitter.c b/ProcessHacker/splitter.c index ddecd07f23aa..f07d3a0d45f5 100644 --- a/ProcessHacker/splitter.c +++ b/ProcessHacker/splitter.c @@ -45,7 +45,7 @@ PPH_HSPLITTER_CONTEXT PhInitializeHSplitter( PhInitializeLayoutManager(&context->LayoutManager, Parent); context->SplitterOffset = -4; - context->SplitterPosition = PhGetIntegerSetting(L"TokenSplitterPosition"); + context->SplitterPosition = 250;// PhGetIntegerSetting(L"TokenSplitterPosition"); context->Topitem = PhAddLayoutItem(&context->LayoutManager, TopChild, NULL, PH_ANCHOR_ALL); context->Bottomitem = PhAddLayoutItem(&context->LayoutManager, BottomChild, NULL, PH_ANCHOR_ALL); @@ -68,18 +68,11 @@ VOID PhHSplitterHandleWmSize( ) { // HACK: Use the PH layout manager as the 'splitter' control by abusing layout margins. - - if (Context->SplitterLayoutCount >= 2) - { - // BUG: If the window is maximized and you move the splitter to the bottom, restoring the window causes - // the bottom control to get moved outside the visible area... Just move the splitter back up. - if ((Context->Bottomitem->Rect.bottom - Context->Bottomitem->Rect.top) <= 100) - Context->SplitterPosition = Context->Topitem->Rect.bottom - Context->Topitem->Rect.top - SPLITTER_PADDING; - } - else - { - Context->SplitterLayoutCount++; - } + + // BUG: If the window is maximized and you move the splitter to the bottom, restoring the window causes + // the bottom control to get moved outside the visible area... Just move the splitter back up. + if ((Context->Bottomitem->Rect.bottom - Context->Bottomitem->Rect.top) <= 100) + Context->SplitterPosition = Context->Topitem->Rect.bottom - Context->Topitem->Rect.top - SPLITTER_PADDING; // Set the bottom margin of the top control. Context->Topitem->Margin.bottom = Height - Context->SplitterPosition - SPLITTER_PADDING; From 281a5336c9dcf73d641ba055fb66cafcf938693b Mon Sep 17 00:00:00 2001 From: lucasg Date: Fri, 12 May 2017 07:42:33 +0200 Subject: [PATCH 0086/2058] Add description for strict CFG and AuditNonSystemFont (#140) --- ProcessHacker/procmtgn.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/ProcessHacker/procmtgn.c b/ProcessHacker/procmtgn.c index 26b9915e41e2..4a2c99011157 100644 --- a/ProcessHacker/procmtgn.c +++ b/ProcessHacker/procmtgn.c @@ -276,10 +276,21 @@ BOOLEAN PhDescribeProcessMitigationPolicy( if (data->EnableControlFlowGuard) { if (ShortDescription) - *ShortDescription = PhCreateString(L"CF Guard"); + { + PhInitializeStringBuilder(&sb, 50); + if (data->StrictMode) PhAppendStringBuilder2(&sb, L"Strict "); + PhAppendStringBuilder2(&sb, L"CF Guard"); + *ShortDescription = PhFinalStringBuilderString(&sb); + } if (LongDescription) - *LongDescription = PhCreateString(L"Control Flow Guard (CFG) is enabled for the process.\r\n"); + { + PhInitializeStringBuilder(&sb, 100); + PhAppendStringBuilder2(&sb, L"Control Flow Guard (CFG) is enabled for the process.\r\n"); + if (data->StrictMode) PhAppendStringBuilder2(&sb, L"Strict CFG : only CFG modules can be loaded.\r\n"); + if (data->EnableExportSuppression) PhAppendStringBuilder2(&sb, L"Dll Exports can be marked as CFG invalid targets.\r\n"); + *LongDescription = PhFinalStringBuilderString(&sb); + } result = TRUE; } @@ -327,7 +338,12 @@ BOOLEAN PhDescribeProcessMitigationPolicy( *ShortDescription = PhCreateString(L"Non-system fonts disabled"); if (LongDescription) - *LongDescription = PhCreateString(L"Non-system fonts cannot be used in this process.\r\n"); + { + PhInitializeStringBuilder(&sb, 100); + PhAppendStringBuilder2(&sb, L"Non-system fonts cannot be used in this process.\r\n"); + if (data->AuditNonSystemFontLoading) PhAppendStringBuilder2(&sb, L"Loading a non-system font in this process will trigger an ETW event.\r\n"); + *LongDescription = PhFinalStringBuilderString(&sb); + } result = TRUE; } From 782ec39aba03dc0e80eac3408d986f59f6bf6cdd Mon Sep 17 00:00:00 2001 From: lucasg Date: Fri, 12 May 2017 09:00:52 +0200 Subject: [PATCH 0087/2058] Add support for undecorate C++ names (#139) * phlib : Add PhUndecorateName(W) * peviewer : undecorate names on import and export entries --- phlib/include/symprv.h | 16 ++++++++++ phlib/include/symprvp.h | 14 +++++++++ phlib/symprv.c | 66 ++++++++++++++++++++++++++++++++++++++++- tools/peview/peprp.c | 37 +++++++++++++++++++---- 4 files changed, 126 insertions(+), 7 deletions(-) diff --git a/phlib/include/symprv.h b/phlib/include/symprv.h index 4d02924180bf..7c747fb9b913 100644 --- a/phlib/include/symprv.h +++ b/phlib/include/symprv.h @@ -296,6 +296,22 @@ PhWalkThreadStack( _In_opt_ PVOID Context ); +PHLIBAPI +PPH_STRING +NTAPI +PhUndecorateName( + _In_ HANDLE ProcessHandle, + _In_ PCSTR DecoratedName +); + +PHLIBAPI +PPH_STRING +NTAPI +PhUndecorateNameW( + _In_ HANDLE ProcessHandle, + _In_ PWSTR DecoratedName +); + #ifdef __cplusplus } #endif diff --git a/phlib/include/symprvp.h b/phlib/include/symprvp.h index e4435bfc9bb0..a760e142594e 100644 --- a/phlib/include/symprvp.h +++ b/phlib/include/symprvp.h @@ -167,4 +167,18 @@ typedef BOOL (CALLBACK *_SymbolServerSetOptions)( _In_ ULONG64 data ); +typedef DWORD(WINAPI *_UnDecorateSymbolName)( + _In_ PCSTR DecoratedName, + _Out_ PSTR UnDecoratedName, + _In_ DWORD UndecoratedLength, + _In_ DWORD Flags + ); + +typedef DWORD(WINAPI *_UnDecorateSymbolNameW)( + _In_ PCWSTR DecoratedName, + _Out_ PWSTR UnDecoratedName, + _In_ DWORD UndecoratedLength, + _In_ DWORD Flags + ); + #endif \ No newline at end of file diff --git a/phlib/symprv.c b/phlib/symprv.c index 837c92c65efb..641ad92da130 100644 --- a/phlib/symprv.c +++ b/phlib/symprv.c @@ -96,6 +96,8 @@ _StackWalk64 StackWalk64_I; _MiniDumpWriteDump MiniDumpWriteDump_I; _SymbolServerGetOptions SymbolServerGetOptions; _SymbolServerSetOptions SymbolServerSetOptions; +_UnDecorateSymbolName UnDecorateSymbolName_I; +_UnDecorateSymbolNameW UnDecorateSymbolNameW_I; BOOLEAN PhSymbolProviderInitialization( VOID @@ -150,9 +152,11 @@ VOID PhSymbolProviderCompleteInitialization( MiniDumpWriteDump_I = PhGetProcedureAddress(dbghelpHandle, "MiniDumpWriteDump", 0); SymbolServerGetOptions = PhGetProcedureAddress(symsrvHandle, "SymbolServerGetOptions", 0); SymbolServerSetOptions = PhGetProcedureAddress(symsrvHandle, "SymbolServerSetOptions", 0); + UnDecorateSymbolName_I = PhGetProcedureAddress(dbghelpHandle, "UnDecorateSymbolName", 0); + UnDecorateSymbolNameW_I = PhGetProcedureAddress(dbghelpHandle, "UnDecorateSymbolNameW", 0); if (SymGetOptions_I && SymSetOptions_I) - SymSetOptions_I(SymGetOptions_I() | SYMOPT_DEFERRED_LOADS | SYMOPT_FAVOR_COMPRESSED); + SymSetOptions_I(SymGetOptions_I() | SYMOPT_DEFERRED_LOADS | SYMOPT_FAVOR_COMPRESSED | SYMOPT_UNDNAME); } PPH_SYMBOL_PROVIDER PhCreateSymbolProvider( @@ -1758,3 +1762,63 @@ NTSTATUS PhWalkThreadStack( return status; } + + +PPH_STRING PhUndecorateName( + _In_ HANDLE ProcessHandle, + _In_ PCSTR DecoratedName +) +{ + PPH_STRING UndecoratedStr = NULL; + PSTR UndecoratedName = NULL; + DWORD CandidateSize = 512; // there is no way to know the resulting length of an undecorated name + // if there is not enough place, the function does not fail. Instead it + // return a truncated name. + + if ((!SymInitialize_I) || (!UnDecorateSymbolName_I)) + return NULL; + + + SymInitialize_I(ProcessHandle, NULL, TRUE); + + UndecoratedName = PhAllocate(CandidateSize*sizeof(CHAR)); + + DWORD Length = UnDecorateSymbolName_I(DecoratedName, UndecoratedName, CandidateSize, UNDNAME_COMPLETE); + if (Length > 0) + { + UndecoratedStr = PhZeroExtendToUtf16(UndecoratedName); + } + + PhFree(UndecoratedName); + return UndecoratedStr; +} + +PPH_STRING PhUndecorateNameW( + _In_ HANDLE ProcessHandle, + _In_ PWSTR DecoratedName +) +{ + + PPH_STRING UndecoratedStr = NULL; + PWSTR UndecoratedName = NULL; + DWORD CandidateSize = 512; // there is no way to know the resulting length of an undecorated name + // if there is not enough place, the function does not fail. Instead it + // return a truncated name. + + if ((!SymInitialize_I) || (!UnDecorateSymbolNameW_I)) + return NULL; + + + SymInitialize_I(ProcessHandle, NULL, TRUE); + + UndecoratedName = PhAllocate(CandidateSize *sizeof(WCHAR)); + + if (UnDecorateSymbolNameW_I(DecoratedName, UndecoratedName, CandidateSize, UNDNAME_COMPLETE)) + { + UndecoratedStr = PhCreateString(UndecoratedName); + } + + PhFree(UndecoratedName); + return UndecoratedStr; + +} \ No newline at end of file diff --git a/tools/peview/peprp.c b/tools/peview/peprp.c index 6d3b832abaa7..da280bd14f44 100644 --- a/tools/peview/peprp.c +++ b/tools/peview/peprp.c @@ -31,6 +31,10 @@ #include #include +BOOLEAN PvpLoadDbgHelp( + _Inout_ PPH_SYMBOL_PROVIDER *SymbolProvider +); + #define PVM_CHECKSUM_DONE (WM_APP + 1) #define PVM_VERIFY_DONE (WM_APP + 2) @@ -78,6 +82,7 @@ INT_PTR CALLBACK PvpPeCgfDlgProc( PH_MAPPED_IMAGE PvMappedImage; PIMAGE_COR20_HEADER PvImageCor20Header; +PPH_SYMBOL_PROVIDER symbolProvider; HICON PvImageLargeIcon; PH_IMAGE_VERSION_INFO PvImageVersionInfo; @@ -105,6 +110,10 @@ VOID PvPeProperties( return; } + // Failing to load dbghelp is not critical : it just won't be possible + // to look up symbol names. No need to check the returned value. + PvpLoadDbgHelp(&symbolProvider); + if (propContext = PvCreatePropContext(PvFileName)) { PPV_PROPPAGECONTEXT newPage; @@ -705,6 +714,8 @@ VOID PvpProcessImports( PPH_STRING name; WCHAR number[PH_INT32_STR_LEN_1]; + + if (DelayImports) name = PhFormatString(L"%S (Delay)", importDll.Name); else @@ -715,7 +726,12 @@ VOID PvpProcessImports( if (importEntry.Name) { - name = PhZeroExtendToUtf16(importEntry.Name); + name = PhUndecorateName(symbolProvider->ProcessHandle, importEntry.Name); + if (!name) + { + name = PhZeroExtendToUtf16(importEntry.Name); + } + PhSetListViewSubItem(ListViewHandle, lvItemIndex, 1, name->Buffer); PhDereferenceObject(name); @@ -870,8 +886,14 @@ INT_PTR CALLBACK PvpPeExportsDlgProc( if (exportFunction.ForwardedName) { - name = PhZeroExtendToUtf16(exportFunction.ForwardedName); - PhSetListViewSubItem(lvHandle, lvItemIndex, 1, name->Buffer); + name = PhUndecorateName(symbolProvider->ProcessHandle, exportFunction.ForwardedName); + if (!name) + { + name = PhZeroExtendToUtf16(exportFunction.ForwardedName); + } + + + lvItemIndex = PhAddListViewItem(lvHandle, MAXINT, name->Buffer, NULL); PhDereferenceObject(name); } else @@ -882,7 +904,11 @@ INT_PTR CALLBACK PvpPeExportsDlgProc( if (exportEntry.Name) { - name = PhZeroExtendToUtf16(exportEntry.Name); + name = PhUndecorateName(symbolProvider->ProcessHandle, exportEntry.Name); + if (!name) + { + name = PhZeroExtendToUtf16(exportEntry.Name); + } PhSetListViewSubItem(lvHandle, lvItemIndex, 2, name->Buffer); PhDereferenceObject(name); } @@ -898,7 +924,7 @@ INT_PTR CALLBACK PvpPeExportsDlgProc( } ExtendedListView_SortItems(lvHandle); - + EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); } break; @@ -1295,7 +1321,6 @@ INT_PTR CALLBACK PvpPeCgfDlgProc( case WM_INITDIALOG: { HWND lvHandle; - PPH_SYMBOL_PROVIDER symbolProvider = NULL; PH_MAPPED_IMAGE_CFG cfgConfig = { 0 }; lvHandle = GetDlgItem(hwndDlg, IDC_LIST); From c73c5c0e73632eefa50bc2c1c5aea308dd762580 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 12 May 2017 17:22:18 +1000 Subject: [PATCH 0088/2058] peview: Add image import index column, Improve undecorate symbols performance (only undecorate symbols starting with ?) --- tools/peview/peprp.c | 81 ++++++++++++++++++++++++++------------------ 1 file changed, 48 insertions(+), 33 deletions(-) diff --git a/tools/peview/peprp.c b/tools/peview/peprp.c index da280bd14f44..e6b4d38e9466 100644 --- a/tools/peview/peprp.c +++ b/tools/peview/peprp.c @@ -694,7 +694,8 @@ INT_PTR CALLBACK PvpPeGeneralDlgProc( VOID PvpProcessImports( _In_ HWND ListViewHandle, _In_ PPH_MAPPED_IMAGE_IMPORTS Imports, - _In_ BOOLEAN DelayImports + _In_ BOOLEAN DelayImports, + _Inout_ ULONG *Count ) { PH_MAPPED_IMAGE_IMPORT_DLL importDll; @@ -714,34 +715,39 @@ VOID PvpProcessImports( PPH_STRING name; WCHAR number[PH_INT32_STR_LEN_1]; - - if (DelayImports) name = PhFormatString(L"%S (Delay)", importDll.Name); else name = PhZeroExtendToUtf16(importDll.Name); - lvItemIndex = PhAddListViewItem(ListViewHandle, MAXINT, name->Buffer, NULL); + PhPrintUInt64(number, ++(*Count)); // HACK + lvItemIndex = PhAddListViewItem(ListViewHandle, MAXINT, number, NULL); + + PhSetListViewSubItem(ListViewHandle, lvItemIndex, 1, name->Buffer); PhDereferenceObject(name); if (importEntry.Name) { - name = PhUndecorateName(symbolProvider->ProcessHandle, importEntry.Name); - if (!name) - { - name = PhZeroExtendToUtf16(importEntry.Name); - } + PPH_STRING importName = NULL; - PhSetListViewSubItem(ListViewHandle, lvItemIndex, 1, name->Buffer); - PhDereferenceObject(name); + if (importEntry.Name[0] == '?') + importName = PhUndecorateName(symbolProvider->ProcessHandle, importEntry.Name); + else + importName = PhZeroExtendToUtf16(importEntry.Name); + + if (!importName) + importName = PhZeroExtendToUtf16(importEntry.Name); + + PhSetListViewSubItem(ListViewHandle, lvItemIndex, 2, importName->Buffer); + PhDereferenceObject(importName); PhPrintUInt32(number, importEntry.NameHint); - PhSetListViewSubItem(ListViewHandle, lvItemIndex, 2, number); + PhSetListViewSubItem(ListViewHandle, lvItemIndex, 3, number); } else { name = PhFormatString(L"(Ordinal %u)", importEntry.Ordinal); - PhSetListViewSubItem(ListViewHandle, lvItemIndex, 1, name->Buffer); + PhSetListViewSubItem(ListViewHandle, lvItemIndex, 2, name->Buffer); PhDereferenceObject(name); } } @@ -767,6 +773,7 @@ INT_PTR CALLBACK PvpPeImportsDlgProc( { case WM_INITDIALOG: { + ULONG count = 0; ULONG fallbackColumns[] = { 0, 1, 2 }; HWND lvHandle; PH_MAPPED_IMAGE_IMPORTS imports; @@ -774,21 +781,22 @@ INT_PTR CALLBACK PvpPeImportsDlgProc( lvHandle = GetDlgItem(hwndDlg, IDC_LIST); PhSetListViewStyle(lvHandle, FALSE, TRUE); PhSetControlTheme(lvHandle, L"explorer"); - PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 130, L"DLL"); - PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 210, L"Name"); - PhAddListViewColumn(lvHandle, 2, 2, 2, LVCFMT_LEFT, 50, L"Hint"); + PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 40, L"#"); + PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 130, L"DLL"); + PhAddListViewColumn(lvHandle, 2, 2, 2, LVCFMT_LEFT, 210, L"Name"); + PhAddListViewColumn(lvHandle, 3, 3, 3, LVCFMT_LEFT, 50, L"Hint"); PhSetExtendedListView(lvHandle); ExtendedListView_AddFallbackColumns(lvHandle, 3, fallbackColumns); PhLoadListViewColumnsFromSetting(L"ImageImportsListViewColumns", lvHandle); if (NT_SUCCESS(PhGetMappedImageImports(&imports, &PvMappedImage))) { - PvpProcessImports(lvHandle, &imports, FALSE); + PvpProcessImports(lvHandle, &imports, FALSE, &count); } if (NT_SUCCESS(PhGetMappedImageDelayImports(&imports, &PvMappedImage))) { - PvpProcessImports(lvHandle, &imports, TRUE); + PvpProcessImports(lvHandle, &imports, TRUE, &count); } ExtendedListView_SortItems(lvHandle); @@ -871,7 +879,6 @@ INT_PTR CALLBACK PvpPeExportsDlgProc( ) { INT lvItemIndex; - PPH_STRING name; WCHAR number[PH_INT32_STR_LEN_1]; WCHAR pointer[PH_PTR_STR_LEN_1]; @@ -886,15 +893,18 @@ INT_PTR CALLBACK PvpPeExportsDlgProc( if (exportFunction.ForwardedName) { - name = PhUndecorateName(symbolProvider->ProcessHandle, exportFunction.ForwardedName); - if (!name) - { - name = PhZeroExtendToUtf16(exportFunction.ForwardedName); - } + PPH_STRING forwardName = NULL; + if (exportFunction.ForwardedName[0] == '?') + forwardName = PhUndecorateName(symbolProvider->ProcessHandle, exportFunction.ForwardedName); + else + forwardName = PhZeroExtendToUtf16(exportFunction.ForwardedName); - lvItemIndex = PhAddListViewItem(lvHandle, MAXINT, name->Buffer, NULL); - PhDereferenceObject(name); + if (!forwardName) + forwardName = PhZeroExtendToUtf16(exportFunction.ForwardedName); + + lvItemIndex = PhAddListViewItem(lvHandle, MAXINT, forwardName->Buffer, NULL); + PhDereferenceObject(forwardName); } else { @@ -904,13 +914,18 @@ INT_PTR CALLBACK PvpPeExportsDlgProc( if (exportEntry.Name) { - name = PhUndecorateName(symbolProvider->ProcessHandle, exportEntry.Name); - if (!name) - { - name = PhZeroExtendToUtf16(exportEntry.Name); - } - PhSetListViewSubItem(lvHandle, lvItemIndex, 2, name->Buffer); - PhDereferenceObject(name); + PPH_STRING exportName = NULL; + + if (exportEntry.Name[0] == '?') + exportName = PhUndecorateName(symbolProvider->ProcessHandle, exportEntry.Name); + else + exportName = PhZeroExtendToUtf16(exportEntry.Name); + + if (!exportName) + exportName = PhZeroExtendToUtf16(exportEntry.Name); + + PhSetListViewSubItem(lvHandle, lvItemIndex, 2, exportName->Buffer); + PhDereferenceObject(exportName); } else { From 88b9822887071135d923474817e4ab7bdecf87e2 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 12 May 2017 18:23:58 +1000 Subject: [PATCH 0089/2058] peview: Fix display of module export forwarders --- tools/peview/peprp.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/tools/peview/peprp.c b/tools/peview/peprp.c index e6b4d38e9466..aebb9ea6fd34 100644 --- a/tools/peview/peprp.c +++ b/tools/peview/peprp.c @@ -33,7 +33,7 @@ BOOLEAN PvpLoadDbgHelp( _Inout_ PPH_SYMBOL_PROVIDER *SymbolProvider -); + ); #define PVM_CHECKSUM_DONE (WM_APP + 1) #define PVM_VERIFY_DONE (WM_APP + 2) @@ -882,12 +882,6 @@ INT_PTR CALLBACK PvpPeExportsDlgProc( WCHAR number[PH_INT32_STR_LEN_1]; WCHAR pointer[PH_PTR_STR_LEN_1]; - // TODO: user32.dll and some other dlls have many (unnamed) exports with (invalid) 0x0 RVA, - // they might be exported variables or caused by incorrect math, ignore these entries - // until more information is available. - if (!exportFunction.Function) - continue; - PhPrintUInt64(number, i + 1); lvItemIndex = PhAddListViewItem(lvHandle, MAXINT, number, NULL); @@ -903,7 +897,7 @@ INT_PTR CALLBACK PvpPeExportsDlgProc( if (!forwardName) forwardName = PhZeroExtendToUtf16(exportFunction.ForwardedName); - lvItemIndex = PhAddListViewItem(lvHandle, MAXINT, forwardName->Buffer, NULL); + PhSetListViewSubItem(lvHandle, lvItemIndex, 1, forwardName->Buffer); PhDereferenceObject(forwardName); } else From 9fdfd0a65b9237f8c2ed03b70de66c3290c1c451 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 12 May 2017 18:25:13 +1000 Subject: [PATCH 0090/2058] Add missing handles tab searchbox filters --- ProcessHacker/prpghndl.c | 42 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 39 insertions(+), 3 deletions(-) diff --git a/ProcessHacker/prpghndl.c b/ProcessHacker/prpghndl.c index ada104e8e0b3..6f0861eee24f 100644 --- a/ProcessHacker/prpghndl.c +++ b/ProcessHacker/prpghndl.c @@ -250,15 +250,17 @@ BOOLEAN PhpHandleTreeFilterCallback( ) { PPH_HANDLES_CONTEXT handlesContext = Context; - PPH_HANDLE_NODE processNode = (PPH_HANDLE_NODE)Node; - PPH_HANDLE_ITEM handleItem = processNode->HandleItem; + PPH_HANDLE_NODE handleNode = (PPH_HANDLE_NODE)Node; + PPH_HANDLE_ITEM handleItem = handleNode->HandleItem; - if (handlesContext->ListContext.HideUnnamedHandles && PhIsNullOrEmptyString(handleItem->BestObjectName)) + if (handlesContext->ListContext.HideUnnamedHandles && PhIsNullOrEmptyString(handleItem->ObjectName)) return FALSE; if (PhIsNullOrEmptyString(handlesContext->SearchboxText)) return TRUE; + // handle properties + if (!PhIsNullOrEmptyString(handleItem->TypeName)) { if (PhpWordMatchHandleStringRef(handlesContext->SearchboxText, &handleItem->TypeName->sr)) @@ -277,6 +279,40 @@ BOOLEAN PhpHandleTreeFilterCallback( return TRUE; } + if (handleItem->HandleString[0]) + { + if (PhpWordMatchHandleStringZ(handlesContext->SearchboxText, handleItem->HandleString)) + return TRUE; + } + + if (handleItem->ObjectString[0]) + { + if (PhpWordMatchHandleStringZ(handlesContext->SearchboxText, handleItem->ObjectString)) + return TRUE; + } + + if (handleItem->GrantedAccessString[0]) + { + if (PhpWordMatchHandleStringZ(handlesContext->SearchboxText, handleItem->GrantedAccessString)) + return TRUE; + } + + // TODO: Add search for handleItem->Attributes + + // node properties + + if (!PhIsNullOrEmptyString(handleNode->GrantedAccessSymbolicText)) + { + if (PhpWordMatchHandleStringRef(handlesContext->SearchboxText, &handleNode->GrantedAccessSymbolicText->sr)) + return TRUE; + } + + if (handleNode->FileShareAccessText[0]) + { + if (PhpWordMatchHandleStringZ(handlesContext->SearchboxText, handleNode->FileShareAccessText)) + return TRUE; + } + return FALSE; } From 122e15c1a92472cbaf36eb0de4f16bb53b104f09 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 12 May 2017 18:30:01 +1000 Subject: [PATCH 0091/2058] peview: enable column reordering --- tools/peview/peprp.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tools/peview/peprp.c b/tools/peview/peprp.c index aebb9ea6fd34..2995b7aefb07 100644 --- a/tools/peview/peprp.c +++ b/tools/peview/peprp.c @@ -552,7 +552,7 @@ INT_PTR CALLBACK PvpPeGeneralDlgProc( PhDeleteStringBuilder(&stringBuilder); lvHandle = GetDlgItem(hwndDlg, IDC_LIST); - PhSetListViewStyle(lvHandle, FALSE, TRUE); + PhSetListViewStyle(lvHandle, TRUE, TRUE); PhSetControlTheme(lvHandle, L"explorer"); PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 80, L"Name"); PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 80, L"VA"); @@ -779,7 +779,7 @@ INT_PTR CALLBACK PvpPeImportsDlgProc( PH_MAPPED_IMAGE_IMPORTS imports; lvHandle = GetDlgItem(hwndDlg, IDC_LIST); - PhSetListViewStyle(lvHandle, FALSE, TRUE); + PhSetListViewStyle(lvHandle, TRUE, TRUE); PhSetControlTheme(lvHandle, L"explorer"); PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 40, L"#"); PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 130, L"DLL"); @@ -860,7 +860,7 @@ INT_PTR CALLBACK PvpPeExportsDlgProc( ULONG i; lvHandle = GetDlgItem(hwndDlg, IDC_LIST); - PhSetListViewStyle(lvHandle, FALSE, TRUE); + PhSetListViewStyle(lvHandle, TRUE, TRUE); PhSetControlTheme(lvHandle, L"explorer"); PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 40, L"#"); PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_RIGHT, 80, L"RVA"); @@ -991,7 +991,7 @@ INT_PTR CALLBACK PvpPeLoadConfigDlgProc( PIMAGE_LOAD_CONFIG_DIRECTORY64 config64; lvHandle = GetDlgItem(hwndDlg, IDC_LIST); - PhSetListViewStyle(lvHandle, FALSE, TRUE); + PhSetListViewStyle(lvHandle, TRUE, TRUE); PhSetControlTheme(lvHandle, L"explorer"); PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 220, L"Name"); PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 170, L"Value"); @@ -1333,7 +1333,7 @@ INT_PTR CALLBACK PvpPeCgfDlgProc( PH_MAPPED_IMAGE_CFG cfgConfig = { 0 }; lvHandle = GetDlgItem(hwndDlg, IDC_LIST); - PhSetListViewStyle(lvHandle, FALSE, TRUE); + PhSetListViewStyle(lvHandle, TRUE, TRUE); PhSetControlTheme(lvHandle, L"explorer"); PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 40, L"#"); From 5ed9fc8eed594d8c2a9afa7bbba126c9b761f249 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 13 May 2017 17:39:09 +1000 Subject: [PATCH 0092/2058] peview: fix unicode string parameters --- tools/peview/peprp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/peview/peprp.c b/tools/peview/peprp.c index 2995b7aefb07..36db629c6fb6 100644 --- a/tools/peview/peprp.c +++ b/tools/peview/peprp.c @@ -1158,6 +1158,7 @@ BOOLEAN PvpLoadDbgHelp( UNICODE_STRING symbolPathUs = { .Buffer = buffer, + .Length = sizeof(buffer) - sizeof(UNICODE_NULL), .MaximumLength = sizeof(buffer) }; From 0e30a883b26167ac248613382d6cb5e964a449d2 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 13 May 2017 17:40:24 +1000 Subject: [PATCH 0093/2058] BuildTool: Remove redist files --- tools/CustomBuildTool/Source Files/Program.cs | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/tools/CustomBuildTool/Source Files/Program.cs b/tools/CustomBuildTool/Source Files/Program.cs index a86af9947fed..dfaa12b29ea7 100644 --- a/tools/CustomBuildTool/Source Files/Program.cs +++ b/tools/CustomBuildTool/Source Files/Program.cs @@ -51,11 +51,6 @@ public static void Main(string[] args) if (!Build.CopyLibFiles(BuildFlags.Build32bit | BuildFlags.Build64bit | BuildFlags.BuildVerbose)) return; - Build.CopyRedistFiles( - BuildFlags.Build32bit | BuildFlags.Build64bit | - BuildFlags.BuildDebug | BuildFlags.BuildVerbose - ); - Build.ShowBuildStats(); } else if (ProgramArgs.ContainsKey("-cleansdk")) @@ -243,11 +238,6 @@ public static void Main(string[] args) if (!Build.CopyWow64Files(BuildFlags.None)) return; - Build.CopyRedistFiles( - BuildFlags.Build32bit | BuildFlags.Build64bit | - BuildFlags.BuildDebug | BuildFlags.BuildVerbose - ); - if (!Build.BuildBinZip()) return; if (!Build.BuildSetupExe()) From 3fb3d8f183db671b194474e004e56bca374a84f1 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 13 May 2017 19:48:54 +1000 Subject: [PATCH 0094/2058] Improve CfgBitmap memory tagging for wow64, Update LDR_INIT_BLOCK with correct definitions --- ProcessHacker/memprv.c | 79 ++++++++++-------------------------------- phnt/include/ntldr.h | 36 ++++++++++++++----- 2 files changed, 46 insertions(+), 69 deletions(-) diff --git a/ProcessHacker/memprv.c b/ProcessHacker/memprv.c index cf5979bd1fc8..998ed6eeca73 100644 --- a/ProcessHacker/memprv.c +++ b/ProcessHacker/memprv.c @@ -489,7 +489,7 @@ NTSTATUS PhpUpdateMemoryRegionTypes( #ifdef _WIN64 - LDR_INIT_BLOCK ldrInitBlock = { 0 }; + PS_SYSTEM_DLL_INIT_BLOCK ldrInitBlock = { 0 }; PVOID ldrInitBlockBaseAddress = NULL; PPH_MEMORY_ITEM cfgBitmapMemoryItem; PPH_STRING ntdllFileName; @@ -510,7 +510,7 @@ NTSTATUS PhpUpdateMemoryRegionTypes( ProcessHandle, ldrInitBlockBaseAddress, &ldrInitBlock, - sizeof(LDR_INIT_BLOCK), + sizeof(PS_SYSTEM_DLL_INIT_BLOCK), NULL ); } @@ -520,24 +520,23 @@ NTSTATUS PhpUpdateMemoryRegionTypes( if (NT_SUCCESS(status) && ldrInitBlock.Size) { PVOID cfgBitmapAddress = NULL; + PVOID cfgBitmapWow64Address = NULL; - // TODO: Remove this code once most users have updated their machines. - if (ldrInitBlock.Size == sizeof(LDR_INIT_BLOCK)) - cfgBitmapAddress = ldrInitBlock.CfgBitmapAddress; // 15063 - else if (ldrInitBlock.Size == 128) - cfgBitmapAddress = ldrInitBlock.Unknown1[11]; // 14393 + if (ldrInitBlock.Size == sizeof(PS_SYSTEM_DLL_INIT_BLOCK)) + { + cfgBitmapAddress = (PVOID)ldrInitBlock.CfgBitMap; + cfgBitmapWow64Address = (PVOID)ldrInitBlock.Wow64CfgBitMap; + } if (cfgBitmapAddress && (cfgBitmapMemoryItem = PhLookupMemoryItemList(List, cfgBitmapAddress))) { PLIST_ENTRY listEntry = &cfgBitmapMemoryItem->ListEntry; PPH_MEMORY_ITEM memoryItem = CONTAINING_RECORD(listEntry, PH_MEMORY_ITEM, ListEntry); - // Tagging memory items while (memoryItem->AllocationBaseItem == cfgBitmapMemoryItem) { - // NB : we could do a finer tagging since each MEM_COMMIT memory - // map is the CFG bitmap of a loaded module. However that would - // imply to heavily rely on reverse-engineer results, and might be + // lucasg: We could do a finer tagging since each MEM_COMMIT memory + // map is the CFG bitmap of a loaded module. However that might be // brittle to changes made by Windows dev teams. memoryItem->RegionType = CfgBitmapRegion; @@ -545,61 +544,19 @@ NTSTATUS PhpUpdateMemoryRegionTypes( memoryItem = CONTAINING_RECORD(listEntry, PH_MEMORY_ITEM, ListEntry); } } - } - - if (isWow64) - { - LDR_INIT_BLOCK ldrInitBlock32 = { 0 }; - PVOID ldrInitBlockBaseAddress32 = NULL; - PPH_MEMORY_ITEM cfgBitmapMemoryItem32; - PPH_STRING ntdllWow64FileName; - - ntdllWow64FileName = PhConcatStrings2(USER_SHARED_DATA->NtSystemRoot, L"\\SysWow64\\ntdll.dll"); - status = PhGetProcedureAddressRemote( - ProcessHandle, - ntdllWow64FileName->Buffer, - "LdrSystemDllInitBlock", - 0, - &ldrInitBlockBaseAddress32, - NULL - ); - - if (NT_SUCCESS(status) && ldrInitBlockBaseAddress32) - { - status = NtReadVirtualMemory( - ProcessHandle, - ldrInitBlockBaseAddress32, - &ldrInitBlock32, - sizeof(LDR_INIT_BLOCK), - NULL - ); - } - - PhDereferenceObject(ntdllWow64FileName); - if (NT_SUCCESS(status) && ldrInitBlock32.Size) + // Note: Wow64 processes on 64bit also have CfgBitmap regions. + if (isWow64 && cfgBitmapWow64Address && (cfgBitmapMemoryItem = PhLookupMemoryItemList(List, cfgBitmapWow64Address))) { - PVOID cfgBitmapAddress = NULL; - - // TODO: Remove this code once most users have updated their machines. - if (ldrInitBlock32.Size == sizeof(LDR_INIT_BLOCK)) - cfgBitmapAddress = ldrInitBlock32.CfgBitmapAddress; // 15063 - else if (ldrInitBlock32.Size == 128) - cfgBitmapAddress = ldrInitBlock32.Unknown1[11]; // 14393 + PLIST_ENTRY listEntry = &cfgBitmapMemoryItem->ListEntry; + PPH_MEMORY_ITEM memoryItem = CONTAINING_RECORD(listEntry, PH_MEMORY_ITEM, ListEntry); - if (cfgBitmapAddress && (cfgBitmapMemoryItem32 = PhLookupMemoryItemList(List, cfgBitmapAddress))) + while (memoryItem->AllocationBaseItem == cfgBitmapMemoryItem) { - PLIST_ENTRY listEntry = &cfgBitmapMemoryItem32->ListEntry; - PPH_MEMORY_ITEM memoryItem = CONTAINING_RECORD(listEntry, PH_MEMORY_ITEM, ListEntry); - - // Tagging memory items - while (memoryItem->AllocationBaseItem == cfgBitmapMemoryItem32) - { - memoryItem->RegionType = CfgBitmap32Region; + memoryItem->RegionType = CfgBitmap32Region; - listEntry = listEntry->Flink; - memoryItem = CONTAINING_RECORD(listEntry, PH_MEMORY_ITEM, ListEntry); - } + listEntry = listEntry->Flink; + memoryItem = CONTAINING_RECORD(listEntry, PH_MEMORY_ITEM, ListEntry); } } } diff --git a/phnt/include/ntldr.h b/phnt/include/ntldr.h index 9eef05a15b73..6ec947c0f407 100644 --- a/phnt/include/ntldr.h +++ b/phnt/include/ntldr.h @@ -468,20 +468,40 @@ LdrUnregisterDllNotification( // end_msdn -// rev -typedef struct _LDR_INIT_BLOCK +// private +typedef struct _PS_MITIGATION_OPTIONS_MAP +{ + ULONG_PTR Map[2]; +} PS_MITIGATION_OPTIONS_MAP, *PPS_MITIGATION_OPTIONS_MAP; + +// private +typedef struct _PS_SYSTEM_DLL_INIT_BLOCK { ULONG Size; - PVOID Unknown1[21]; - PVOID CfgBitmapAddress; - ULONG_PTR CfgBitmapSize; - PVOID Unknown2[2]; -} LDR_INIT_BLOCK, *PLDR_INIT_BLOCK; + ULONG_PTR SystemDllWowRelocation; + ULONG_PTR SystemDllNativeRelocation; + ULONG_PTR Wow64SharedInformation[16]; + ULONG RngData; + union + { + ULONG Flags; + struct + { + ULONG CfgOverride : 1; + ULONG Reserved : 31; + }; + }; + PS_MITIGATION_OPTIONS_MAP MitigationOptionsMap; + ULONG_PTR CfgBitMap; + ULONG_PTR CfgBitMapSize; + ULONG_PTR Wow64CfgBitMap; + ULONG_PTR Wow64CfgBitMapSize; +} PS_SYSTEM_DLL_INIT_BLOCK, *PPS_SYSTEM_DLL_INIT_BLOCK; #if (PHNT_VERSION >= PHNT_THRESHOLD) // rev NTSYSAPI -PLDR_INIT_BLOCK +PPS_SYSTEM_DLL_INIT_BLOCK NTAPI LdrSystemDllInitBlock( VOID From 4a5826078dc27840c42b3779e7a8ba7d26d22472 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 14 May 2017 05:54:15 +1000 Subject: [PATCH 0095/2058] Add initial CustomStartTool project --- .../CustomStartTool/CustomStartTool.manifest | 46 ++++ tools/CustomStartTool/CustomStartTool.sln | 28 +++ tools/CustomStartTool/CustomStartTool.vcxproj | 212 ++++++++++++++++++ .../CustomStartTool.vcxproj.filters | 27 +++ tools/CustomStartTool/main.c | 155 +++++++++++++ 5 files changed, 468 insertions(+) create mode 100644 tools/CustomStartTool/CustomStartTool.manifest create mode 100644 tools/CustomStartTool/CustomStartTool.sln create mode 100644 tools/CustomStartTool/CustomStartTool.vcxproj create mode 100644 tools/CustomStartTool/CustomStartTool.vcxproj.filters create mode 100644 tools/CustomStartTool/main.c diff --git a/tools/CustomStartTool/CustomStartTool.manifest b/tools/CustomStartTool/CustomStartTool.manifest new file mode 100644 index 000000000000..49febae436ae --- /dev/null +++ b/tools/CustomStartTool/CustomStartTool.manifest @@ -0,0 +1,46 @@ + + + + CustomStartTool + + + + + + + + + + + + + + + + + + + + + + + + true + + + true + + + \ No newline at end of file diff --git a/tools/CustomStartTool/CustomStartTool.sln b/tools/CustomStartTool/CustomStartTool.sln new file mode 100644 index 000000000000..ed99573d0794 --- /dev/null +++ b/tools/CustomStartTool/CustomStartTool.sln @@ -0,0 +1,28 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.26430.4 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CustomStartTool", "CustomStartTool.vcxproj", "{E8CD0A41-1537-4EA6-98AC-E80CD59C478E}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|32bit = Debug|32bit + Debug|64bit = Debug|64bit + Release|32bit = Release|32bit + Release|64bit = Release|64bit + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {E8CD0A41-1537-4EA6-98AC-E80CD59C478E}.Debug|32bit.ActiveCfg = Debug|Win32 + {E8CD0A41-1537-4EA6-98AC-E80CD59C478E}.Debug|32bit.Build.0 = Debug|Win32 + {E8CD0A41-1537-4EA6-98AC-E80CD59C478E}.Debug|64bit.ActiveCfg = Debug|x64 + {E8CD0A41-1537-4EA6-98AC-E80CD59C478E}.Debug|64bit.Build.0 = Debug|x64 + {E8CD0A41-1537-4EA6-98AC-E80CD59C478E}.Release|32bit.ActiveCfg = Release|Win32 + {E8CD0A41-1537-4EA6-98AC-E80CD59C478E}.Release|32bit.Build.0 = Release|Win32 + {E8CD0A41-1537-4EA6-98AC-E80CD59C478E}.Release|64bit.ActiveCfg = Release|x64 + {E8CD0A41-1537-4EA6-98AC-E80CD59C478E}.Release|64bit.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/tools/CustomStartTool/CustomStartTool.vcxproj b/tools/CustomStartTool/CustomStartTool.vcxproj new file mode 100644 index 000000000000..787cb050f1df --- /dev/null +++ b/tools/CustomStartTool/CustomStartTool.vcxproj @@ -0,0 +1,212 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {E8CD0A41-1537-4EA6-98AC-E80CD59C478E} + CustomStartTool + Win32Proj + 10.0.15063.0 + + + + Application + Unicode + true + v141 + + + Application + Unicode + v141 + + + Application + Unicode + true + v141 + + + Application + Unicode + v141 + + + + + + + + + + + + + + + + + + + $(ProjectDir)bin\$(Configuration)$(PlatformArchitecture)\ + $(ProjectDir)obj\$(Configuration)$(PlatformArchitecture)\ + true + $(ProjectDir)bin\$(Configuration)$(PlatformArchitecture)\ + $(ProjectDir)obj\$(Configuration)$(PlatformArchitecture)\ + true + $(ProjectDir)bin\$(Configuration)$(PlatformArchitecture)\ + $(ProjectDir)obj\$(Configuration)$(PlatformArchitecture)\ + false + $(ProjectDir)bin\$(Configuration)$(PlatformArchitecture)\ + $(ProjectDir)obj\$(Configuration)$(PlatformArchitecture)\ + false + + + bootstrap + + + bootstrap + + + bootstrap + + + bootstrap + + + + Disabled + ..\..\phnt\include;..\..\phlib\include;include;%(AdditionalIncludeDirectories) + _PHLIB_;_WINDOWS;WIN32;DEBUG;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + Level3 + ProgramDatabase + StdCall + true + true + + + noenv.obj;phlib.lib;ntdll.lib;bcrypt.lib;%(AdditionalDependencies) + ..\..\phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) + + + true + Windows + MachineX86 + 6.01 + + + + + Disabled + ..\..\phnt\include;..\..\phlib\include;include;%(AdditionalIncludeDirectories) + _PHLIB_;_WINDOWS;WIN64;DEBUG;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + Level3 + ProgramDatabase + StdCall + true + true + + + noenv.obj;phlib.lib;ntdll.lib;bcrypt.lib;%(AdditionalDependencies) + ..\..\phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) + + + true + Windows + MachineX64 + 6.01 + + + + + MaxSpeed + true + ..\..\phnt\include;..\..\phlib\include;include;%(AdditionalIncludeDirectories) + _PHLIB_;_WINDOWS;WIN32;NDEBUG;%(PreprocessorDefinitions) + MultiThreaded + true + Level3 + ProgramDatabase + StdCall + true + StreamingSIMDExtensions + true + + + noenv.obj;phlib.lib;ntdll.lib;bcrypt.lib;%(AdditionalDependencies) + ..\..\phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) + + + true + Windows + true + true + MachineX86 + true + 6.01 + + + + + MaxSpeed + true + ..\..\phnt\include;..\..\phlib\include;include;%(AdditionalIncludeDirectories) + _PHLIB_;_WINDOWS;WIN64;DEBUG;%(PreprocessorDefinitions) + MultiThreaded + true + Level3 + ProgramDatabase + StdCall + true + true + + + noenv.obj;phlib.lib;ntdll.lib;bcrypt.lib;%(AdditionalDependencies) + ..\..\phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) + + + true + Windows + true + true + MachineX64 + true + 6.01 + + + + + + + + {477d0215-f252-41a1-874b-f27e3ea1ed17} + false + + + + + + + + + \ No newline at end of file diff --git a/tools/CustomStartTool/CustomStartTool.vcxproj.filters b/tools/CustomStartTool/CustomStartTool.vcxproj.filters new file mode 100644 index 000000000000..948f2cbc045f --- /dev/null +++ b/tools/CustomStartTool/CustomStartTool.vcxproj.filters @@ -0,0 +1,27 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav + + + + + Source Files + + + + + Resource Files + + + \ No newline at end of file diff --git a/tools/CustomStartTool/main.c b/tools/CustomStartTool/main.c new file mode 100644 index 000000000000..e967ae3f8434 --- /dev/null +++ b/tools/CustomStartTool/main.c @@ -0,0 +1,155 @@ +/* + * Process Hacker - + * Custom Bootstrap Tool + * + * Copyright (C) 2017 dmex + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include +#include + +static ULONG64 PhMitigationPolicy = + //PROCESS_CREATION_MITIGATION_POLICY_FORCE_RELOCATE_IMAGES_ALWAYS_ON | + PROCESS_CREATION_MITIGATION_POLICY_HEAP_TERMINATE_ALWAYS_ON | + PROCESS_CREATION_MITIGATION_POLICY_BOTTOM_UP_ASLR_ALWAYS_ON | + PROCESS_CREATION_MITIGATION_POLICY_HIGH_ENTROPY_ASLR_ALWAYS_ON | + //PROCESS_CREATION_MITIGATION_POLICY_STRICT_HANDLE_CHECKS_ALWAYS_ON | + PROCESS_CREATION_MITIGATION_POLICY_EXTENSION_POINT_DISABLE_ALWAYS_ON | + PROCESS_CREATION_MITIGATION_POLICY_PROHIBIT_DYNAMIC_CODE_ALWAYS_ON | + PROCESS_CREATION_MITIGATION_POLICY_CONTROL_FLOW_GUARD_ALWAYS_ON | + PROCESS_CREATION_MITIGATION_POLICY_FONT_DISABLE_ALWAYS_ON | + PROCESS_CREATION_MITIGATION_POLICY_IMAGE_LOAD_NO_REMOTE_ALWAYS_ON | + PROCESS_CREATION_MITIGATION_POLICY_IMAGE_LOAD_NO_LOW_LABEL_ALWAYS_ON; + +PPH_STRING GetProcessHackerInstallPath(VOID) +{ + static PH_STRINGREF UninstallKeyName = PH_STRINGREF_INIT(L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\ProcessHacker"); + HANDLE keyHandle; + PPH_STRING installPath = NULL; + + if (NT_SUCCESS(PhOpenKey( + &keyHandle, + KEY_READ | KEY_WOW64_64KEY, + PH_KEY_LOCAL_MACHINE, + &UninstallKeyName, + 0 + ))) + { + installPath = PhQueryRegistryString(keyHandle, L"InstallLocation"); + NtClose(keyHandle); + } + + return installPath; +} + +PPH_STRING GetProcessHackerPath(VOID) +{ + PPH_STRING installPath; + PPH_STRING path = NULL; + + installPath = GetProcessHackerInstallPath(); + + if (!PhIsNullOrEmptyString(installPath)) + { + path = PhConcatStrings2(PhGetString(installPath), L"\\ProcessHacker.exe"); + } + + PhClearReference(&installPath); + + return path; +} + +BOOLEAN CheckProcessHackerInstalled(VOID) +{ + BOOLEAN installed = FALSE; + PPH_STRING installPath; + PPH_STRING path; + + installPath = GetProcessHackerInstallPath(); + + if (!PhIsNullOrEmptyString(installPath)) + { + path = PhConcatStrings2(PhGetString(installPath), L"\\ProcessHacker.exe"); + installed = GetFileAttributes(path->Buffer) != INVALID_FILE_ATTRIBUTES; + PhClearReference(&path); + } + + PhClearReference(&installPath); + + return installed; +} + +INT WINAPI wWinMain( + _In_ HINSTANCE hInstance, + _In_opt_ HINSTANCE hPrevInstance, + _In_ PWSTR lpCmdLine, + _In_ INT nCmdShow + ) +{ + SIZE_T attributeListLength = 0; + PROCESS_INFORMATION processInfo = { 0 }; + STARTUPINFOEX info = { sizeof(STARTUPINFOEX) }; + PPH_STRING fileName; + PPH_STRING currentDirectory; + + if (!NT_SUCCESS(PhInitializePhLibEx(0, 0, 0))) + return 1; + + if (!InitializeProcThreadAttributeList(NULL, 1, 0, &attributeListLength) && GetLastError() != ERROR_INSUFFICIENT_BUFFER) + return 1; + + info.lpAttributeList = PhAllocate(attributeListLength); + + if (!InitializeProcThreadAttributeList(info.lpAttributeList, 1, 0, &attributeListLength)) + return 1; + + if (!UpdateProcThreadAttribute(info.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY, &PhMitigationPolicy, sizeof(ULONG64), NULL, NULL)) + return 1; + + currentDirectory = PhGetApplicationDirectory(); + fileName = PhConcatStrings2(currentDirectory->Buffer, L"\\ProcessHacker.exe"); + PhMoveReference(&fileName, PhGetFullPath(fileName->Buffer, NULL)); + + if (!RtlDoesFileExists_U(fileName->Buffer) && CheckProcessHackerInstalled()) + PhMoveReference(&fileName, GetProcessHackerPath()); + + CreateProcess( + NULL, + fileName->Buffer, + NULL, + NULL, + FALSE, + EXTENDED_STARTUPINFO_PRESENT, + NULL, + NULL, + &info.StartupInfo, + &processInfo + ); + + PhDereferenceObject(fileName); + + if (processInfo.hProcess) + NtClose(processInfo.hProcess); + + if (processInfo.hThread) + NtClose(processInfo.hThread); + + DeleteProcThreadAttributeList(info.lpAttributeList); + + return 0; +} From aef144bdaae0a86cf05aa5df075784a0e14c0ca1 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 14 May 2017 20:01:40 +1000 Subject: [PATCH 0096/2058] peview: update project file layout (needed for future additions) --- tools/peview/cfgprp.c | 173 +++++++ tools/peview/clrprp.c | 152 ++++++ tools/peview/expprp.c | 157 ++++++ tools/peview/impprp.c | 169 ++++++ tools/peview/include/pdb.h | 78 +-- tools/peview/include/peview.h | 44 ++ tools/peview/ldprp.c | 160 ++++++ tools/peview/pdb.c | 292 ++++++----- tools/peview/peprp.c | 778 +--------------------------- tools/peview/peview.vcxproj | 7 +- tools/peview/peview.vcxproj.filters | 147 +++--- 11 files changed, 1148 insertions(+), 1009 deletions(-) create mode 100644 tools/peview/cfgprp.c create mode 100644 tools/peview/clrprp.c create mode 100644 tools/peview/expprp.c create mode 100644 tools/peview/impprp.c create mode 100644 tools/peview/ldprp.c diff --git a/tools/peview/cfgprp.c b/tools/peview/cfgprp.c new file mode 100644 index 000000000000..eafb3d8bea3f --- /dev/null +++ b/tools/peview/cfgprp.c @@ -0,0 +1,173 @@ +/* + * Process Hacker - + * PE viewer + * + * Copyright (C) 2010-2011 wj32 + * Copyright (C) 2017 dmex + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include + +INT_PTR CALLBACK PvpPeCgfDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + LPPROPSHEETPAGE propSheetPage; + PPV_PROPPAGECONTEXT propPageContext; + + if (!PvPropPageDlgProcHeader(hwndDlg, uMsg, lParam, &propSheetPage, &propPageContext)) + return FALSE; + + switch (uMsg) + { + case WM_INITDIALOG: + { + HWND lvHandle; + PH_MAPPED_IMAGE_CFG cfgConfig = { 0 }; + + lvHandle = GetDlgItem(hwndDlg, IDC_LIST); + PhSetListViewStyle(lvHandle, TRUE, TRUE); + PhSetControlTheme(lvHandle, L"explorer"); + + PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 40, L"#"); + PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_RIGHT, 80, L"VA"); + PhAddListViewColumn(lvHandle, 2, 2, 2, LVCFMT_LEFT, 250, L"Name"); + PhAddListViewColumn(lvHandle, 3, 3, 3, LVCFMT_LEFT, 100, L"Flags"); + PhSetExtendedListView(lvHandle); + PhLoadListViewColumnsFromSetting(L"ImageCfgListViewColumns", lvHandle); + + // Retrieve Cfg Table entry and characteristics + if (NT_SUCCESS(PhGetMappedImageCfg(&cfgConfig, &PvMappedImage))) + { + for (ULONGLONG i = 0; i < cfgConfig.NumberOfGuardFunctionEntries; i++) + { + INT lvItemIndex; + ULONG64 displacement; + PPH_STRING symbol; + PPH_STRING symbolName = NULL; + PH_SYMBOL_RESOLVE_LEVEL symbolResolveLevel = PhsrlInvalid; + IMAGE_CFG_ENTRY cfgFunctionEntry = { 0 }; + WCHAR number[PH_INT64_STR_LEN_1]; + WCHAR pointer[PH_PTR_STR_LEN_1]; + + // Parse cfg entry : if it fails, just skip it ? + if (!NT_SUCCESS(PhGetMappedImageCfgEntry(&cfgConfig, i, ControlFlowGuardFunction, &cfgFunctionEntry))) + continue; + + PhPrintUInt64(number, i + 1); + lvItemIndex = PhAddListViewItem(lvHandle, MAXINT, number, NULL); + + PhPrintPointer(pointer, UlongToPtr(cfgFunctionEntry.Rva)); + PhSetListViewSubItem(lvHandle, lvItemIndex, 1, pointer); + + // Resolve name based on public symbols + if (!(symbol = PhGetSymbolFromAddress( + PvSymbolProvider, + (ULONG64)PTR_ADD_OFFSET(PvMappedImage.NtHeaders->OptionalHeader.ImageBase, cfgFunctionEntry.Rva), + &symbolResolveLevel, + NULL, + &symbolName, + &displacement + ))) + { + continue; + } + + switch (symbolResolveLevel) + { + case PhsrlFunction: + { + if (displacement) + { + PhSetListViewSubItem( + lvHandle, + lvItemIndex, + 2, + PhaFormatString(L"%s+0x%x", symbolName->Buffer, displacement)->Buffer + ); + } + else + { + PhSetListViewSubItem(lvHandle, lvItemIndex, 2, symbolName->Buffer); + } + } + break; + case PhsrlModule: + case PhsrlAddress: + { + PhSetListViewSubItem(lvHandle, lvItemIndex, 2, symbol->Buffer); + } + break; + default: + case PhsrlInvalid: + { + PhSetListViewSubItem(lvHandle, lvItemIndex, 2, L"(unnamed)"); + } + break; + } + + // Add additional flags + if (cfgFunctionEntry.SuppressedCall) + PhSetListViewSubItem(lvHandle, lvItemIndex, 3, L"SuppressedCall"); + else + PhSetListViewSubItem(lvHandle, lvItemIndex, 3, L""); + + if (symbolName) + PhDereferenceObject(symbolName); + PhDereferenceObject(symbol); + } + } + + ExtendedListView_SortItems(lvHandle); + EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); + } + break; + case WM_DESTROY: + { + PhSaveListViewColumnsToSetting(L"ImageCfgListViewColumns", GetDlgItem(hwndDlg, IDC_LIST)); + } + break; + case WM_SHOWWINDOW: + { + if (!propPageContext->LayoutInitialized) + { + PPH_LAYOUT_ITEM dialogItem; + + dialogItem = PvAddPropPageLayoutItem(hwndDlg, hwndDlg, + PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL); + PvAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_LIST), + dialogItem, PH_ANCHOR_ALL); + + PvDoPropPageLayout(hwndDlg); + + propPageContext->LayoutInitialized = TRUE; + } + } + break; + case WM_NOTIFY: + { + PvHandleListViewNotifyForCopy(lParam, GetDlgItem(hwndDlg, IDC_LIST)); + } + break; + } + + return FALSE; +} diff --git a/tools/peview/clrprp.c b/tools/peview/clrprp.c new file mode 100644 index 000000000000..d0c46d7bccf6 --- /dev/null +++ b/tools/peview/clrprp.c @@ -0,0 +1,152 @@ +/* + * Process Hacker - + * PE viewer + * + * Copyright (C) 2010-2011 wj32 + * Copyright (C) 2017 dmex + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include + +INT_PTR CALLBACK PvpPeClrDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + LPPROPSHEETPAGE propSheetPage; + PPV_PROPPAGECONTEXT propPageContext; + + if (!PvPropPageDlgProcHeader(hwndDlg, uMsg, lParam, &propSheetPage, &propPageContext)) + return FALSE; + + switch (uMsg) + { + case WM_INITDIALOG: + { + PH_STRING_BUILDER stringBuilder; + PPH_STRING string; + PVOID metaData; + ULONG versionStringLength; + + string = PhaFormatString(L"%u.%u", PvImageCor20Header->MajorRuntimeVersion, + PvImageCor20Header->MinorRuntimeVersion); + SetDlgItemText(hwndDlg, IDC_RUNTIMEVERSION, string->Buffer); + + PhInitializeStringBuilder(&stringBuilder, 256); + + if (PvImageCor20Header->Flags & COMIMAGE_FLAGS_ILONLY) + PhAppendStringBuilder2(&stringBuilder, L"IL only, "); + if (PvImageCor20Header->Flags & COMIMAGE_FLAGS_32BITREQUIRED) + PhAppendStringBuilder2(&stringBuilder, L"32-bit only, "); + if (PvImageCor20Header->Flags & COMIMAGE_FLAGS_32BITPREFERRED) + PhAppendStringBuilder2(&stringBuilder, L"32-bit preferred, "); + if (PvImageCor20Header->Flags & COMIMAGE_FLAGS_IL_LIBRARY) + PhAppendStringBuilder2(&stringBuilder, L"IL library, "); + + if (PvImageCor20Header->StrongNameSignature.VirtualAddress != 0 && PvImageCor20Header->StrongNameSignature.Size != 0) + { + if (PvImageCor20Header->Flags & COMIMAGE_FLAGS_STRONGNAMESIGNED) + PhAppendStringBuilder2(&stringBuilder, L"Strong-name signed, "); + else + PhAppendStringBuilder2(&stringBuilder, L"Strong-name delay signed, "); + } + + if (PvImageCor20Header->Flags & COMIMAGE_FLAGS_NATIVE_ENTRYPOINT) + PhAppendStringBuilder2(&stringBuilder, L"Native entry-point, "); + if (PvImageCor20Header->Flags & COMIMAGE_FLAGS_TRACKDEBUGDATA) + PhAppendStringBuilder2(&stringBuilder, L"Track debug data, "); + + if (PhEndsWithString2(stringBuilder.String, L", ", FALSE)) + PhRemoveEndStringBuilder(&stringBuilder, 2); + + SetDlgItemText(hwndDlg, IDC_FLAGS, stringBuilder.String->Buffer); + PhDeleteStringBuilder(&stringBuilder); + + metaData = PhMappedImageRvaToVa(&PvMappedImage, PvImageCor20Header->MetaData.VirtualAddress, NULL); + + if (metaData) + { + __try + { + PhProbeAddress(metaData, PvImageCor20Header->MetaData.Size, PvMappedImage.ViewBase, PvMappedImage.Size, 4); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + metaData = NULL; + } + } + + versionStringLength = 0; + + if (metaData) + { + // Skip 12 bytes. + // First 4 bytes contains the length of the version string. + // The version string follows. + versionStringLength = *(PULONG)((PCHAR)metaData + 12); + + // Make sure the length is valid. + if (versionStringLength >= 0x100) + versionStringLength = 0; + } + + if (versionStringLength != 0) + { + string = PhZeroExtendToUtf16Ex((PCHAR)metaData + 12 + 4, versionStringLength); + SetDlgItemText(hwndDlg, IDC_VERSIONSTRING, string->Buffer); + PhDereferenceObject(string); + } + else + { + SetDlgItemText(hwndDlg, IDC_VERSIONSTRING, L"N/A"); + } + } + break; + case WM_SHOWWINDOW: + { + if (!propPageContext->LayoutInitialized) + { + PvAddPropPageLayoutItem(hwndDlg, hwndDlg, + PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL); + + PvDoPropPageLayout(hwndDlg); + + propPageContext->LayoutInitialized = TRUE; + } + } + break; + case WM_NOTIFY: + { + LPNMHDR header = (LPNMHDR)lParam; + + switch (header->code) + { + case PSN_QUERYINITIALFOCUS: + { + SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, (LONG_PTR)GetDlgItem(hwndDlg, IDC_RUNTIMEVERSION)); + } + return TRUE; + } + } + break; + } + + return FALSE; +} \ No newline at end of file diff --git a/tools/peview/expprp.c b/tools/peview/expprp.c new file mode 100644 index 000000000000..0688891d8c11 --- /dev/null +++ b/tools/peview/expprp.c @@ -0,0 +1,157 @@ +/* + * Process Hacker - + * PE viewer + * + * Copyright (C) 2010-2011 wj32 + * Copyright (C) 2017 dmex + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include + +INT_PTR CALLBACK PvpPeExportsDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + LPPROPSHEETPAGE propSheetPage; + PPV_PROPPAGECONTEXT propPageContext; + + if (!PvPropPageDlgProcHeader(hwndDlg, uMsg, lParam, &propSheetPage, &propPageContext)) + return FALSE; + + switch (uMsg) + { + case WM_INITDIALOG: + { + HWND lvHandle; + PH_MAPPED_IMAGE_EXPORTS exports; + PH_MAPPED_IMAGE_EXPORT_ENTRY exportEntry; + PH_MAPPED_IMAGE_EXPORT_FUNCTION exportFunction; + ULONG i; + + lvHandle = GetDlgItem(hwndDlg, IDC_LIST); + PhSetListViewStyle(lvHandle, TRUE, TRUE); + PhSetControlTheme(lvHandle, L"explorer"); + PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 40, L"#"); + PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_RIGHT, 80, L"RVA"); + PhAddListViewColumn(lvHandle, 2, 2, 2, LVCFMT_LEFT, 250, L"Name"); + PhAddListViewColumn(lvHandle, 3, 3, 3, LVCFMT_LEFT, 50, L"Ordinal"); + PhSetExtendedListView(lvHandle); + PhLoadListViewColumnsFromSetting(L"ImageExportsListViewColumns", lvHandle); + + if (NT_SUCCESS(PhGetMappedImageExports(&exports, &PvMappedImage))) + { + for (i = 0; i < exports.NumberOfEntries; i++) + { + if ( + NT_SUCCESS(PhGetMappedImageExportEntry(&exports, i, &exportEntry)) && + NT_SUCCESS(PhGetMappedImageExportFunction(&exports, NULL, exportEntry.Ordinal, &exportFunction)) + ) + { + INT lvItemIndex; + WCHAR number[PH_INT32_STR_LEN_1]; + WCHAR pointer[PH_PTR_STR_LEN_1]; + + PhPrintUInt64(number, i + 1); + lvItemIndex = PhAddListViewItem(lvHandle, MAXINT, number, NULL); + + if (exportFunction.ForwardedName) + { + PPH_STRING forwardName = NULL; + + if (exportFunction.ForwardedName[0] == '?') + forwardName = PhUndecorateName(PvSymbolProvider->ProcessHandle, exportFunction.ForwardedName); + else + forwardName = PhZeroExtendToUtf16(exportFunction.ForwardedName); + + if (!forwardName) + forwardName = PhZeroExtendToUtf16(exportFunction.ForwardedName); + + PhSetListViewSubItem(lvHandle, lvItemIndex, 1, forwardName->Buffer); + PhDereferenceObject(forwardName); + } + else + { + PhPrintPointer(pointer, exportFunction.Function); + PhSetListViewSubItem(lvHandle, lvItemIndex, 1, pointer); + } + + if (exportEntry.Name) + { + PPH_STRING exportName = NULL; + + if (exportEntry.Name[0] == '?') + exportName = PhUndecorateName(PvSymbolProvider->ProcessHandle, exportEntry.Name); + else + exportName = PhZeroExtendToUtf16(exportEntry.Name); + + if (!exportName) + exportName = PhZeroExtendToUtf16(exportEntry.Name); + + PhSetListViewSubItem(lvHandle, lvItemIndex, 2, exportName->Buffer); + PhDereferenceObject(exportName); + } + else + { + PhSetListViewSubItem(lvHandle, lvItemIndex, 2, L"(unnamed)"); + } + + PhPrintUInt32(number, exportEntry.Ordinal); + PhSetListViewSubItem(lvHandle, lvItemIndex, 3, number); + } + } + } + + ExtendedListView_SortItems(lvHandle); + + EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); + } + break; + case WM_DESTROY: + { + PhSaveListViewColumnsToSetting(L"ImageExportsListViewColumns", GetDlgItem(hwndDlg, IDC_LIST)); + } + break; + case WM_SHOWWINDOW: + { + if (!propPageContext->LayoutInitialized) + { + PPH_LAYOUT_ITEM dialogItem; + + dialogItem = PvAddPropPageLayoutItem(hwndDlg, hwndDlg, + PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL); + PvAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_LIST), + dialogItem, PH_ANCHOR_ALL); + + PvDoPropPageLayout(hwndDlg); + + propPageContext->LayoutInitialized = TRUE; + } + } + break; + case WM_NOTIFY: + { + PvHandleListViewNotifyForCopy(lParam, GetDlgItem(hwndDlg, IDC_LIST)); + } + break; + } + + return FALSE; +} diff --git a/tools/peview/impprp.c b/tools/peview/impprp.c new file mode 100644 index 000000000000..9a1dd38b2256 --- /dev/null +++ b/tools/peview/impprp.c @@ -0,0 +1,169 @@ +/* + * Process Hacker - + * PE viewer + * + * Copyright (C) 2010-2011 wj32 + * Copyright (C) 2017 dmex + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include + +VOID PvpProcessImports( + _In_ HWND ListViewHandle, + _In_ PPH_MAPPED_IMAGE_IMPORTS Imports, + _In_ BOOLEAN DelayImports, + _Inout_ ULONG *Count + ) +{ + PH_MAPPED_IMAGE_IMPORT_DLL importDll; + PH_MAPPED_IMAGE_IMPORT_ENTRY importEntry; + ULONG i; + ULONG j; + + for (i = 0; i < Imports->NumberOfDlls; i++) + { + if (NT_SUCCESS(PhGetMappedImageImportDll(Imports, i, &importDll))) + { + for (j = 0; j < importDll.NumberOfEntries; j++) + { + if (NT_SUCCESS(PhGetMappedImageImportEntry(&importDll, j, &importEntry))) + { + INT lvItemIndex; + PPH_STRING name; + WCHAR number[PH_INT32_STR_LEN_1]; + + if (DelayImports) + name = PhFormatString(L"%S (Delay)", importDll.Name); + else + name = PhZeroExtendToUtf16(importDll.Name); + + PhPrintUInt64(number, ++(*Count)); // HACK + lvItemIndex = PhAddListViewItem(ListViewHandle, MAXINT, number, NULL); + + PhSetListViewSubItem(ListViewHandle, lvItemIndex, 1, name->Buffer); + PhDereferenceObject(name); + + if (importEntry.Name) + { + PPH_STRING importName = NULL; + + if (importEntry.Name[0] == '?') + importName = PhUndecorateName(PvSymbolProvider->ProcessHandle, importEntry.Name); + else + importName = PhZeroExtendToUtf16(importEntry.Name); + + if (!importName) + importName = PhZeroExtendToUtf16(importEntry.Name); + + PhSetListViewSubItem(ListViewHandle, lvItemIndex, 2, importName->Buffer); + PhDereferenceObject(importName); + + PhPrintUInt32(number, importEntry.NameHint); + PhSetListViewSubItem(ListViewHandle, lvItemIndex, 3, number); + } + else + { + name = PhFormatString(L"(Ordinal %u)", importEntry.Ordinal); + PhSetListViewSubItem(ListViewHandle, lvItemIndex, 2, name->Buffer); + PhDereferenceObject(name); + } + } + } + } + } +} + +INT_PTR CALLBACK PvpPeImportsDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + LPPROPSHEETPAGE propSheetPage; + PPV_PROPPAGECONTEXT propPageContext; + + if (!PvPropPageDlgProcHeader(hwndDlg, uMsg, lParam, &propSheetPage, &propPageContext)) + return FALSE; + + switch (uMsg) + { + case WM_INITDIALOG: + { + ULONG count = 0; + ULONG fallbackColumns[] = { 0, 1, 2 }; + HWND lvHandle; + PH_MAPPED_IMAGE_IMPORTS imports; + + lvHandle = GetDlgItem(hwndDlg, IDC_LIST); + PhSetListViewStyle(lvHandle, TRUE, TRUE); + PhSetControlTheme(lvHandle, L"explorer"); + PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 40, L"#"); + PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 130, L"DLL"); + PhAddListViewColumn(lvHandle, 2, 2, 2, LVCFMT_LEFT, 210, L"Name"); + PhAddListViewColumn(lvHandle, 3, 3, 3, LVCFMT_LEFT, 50, L"Hint"); + PhSetExtendedListView(lvHandle); + ExtendedListView_AddFallbackColumns(lvHandle, 3, fallbackColumns); + PhLoadListViewColumnsFromSetting(L"ImageImportsListViewColumns", lvHandle); + + if (NT_SUCCESS(PhGetMappedImageImports(&imports, &PvMappedImage))) + { + PvpProcessImports(lvHandle, &imports, FALSE, &count); + } + + if (NT_SUCCESS(PhGetMappedImageDelayImports(&imports, &PvMappedImage))) + { + PvpProcessImports(lvHandle, &imports, TRUE, &count); + } + + ExtendedListView_SortItems(lvHandle); + + EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); + } + break; + case WM_DESTROY: + { + PhSaveListViewColumnsToSetting(L"ImageImportsListViewColumns", GetDlgItem(hwndDlg, IDC_LIST)); + } + break; + case WM_SHOWWINDOW: + { + if (!propPageContext->LayoutInitialized) + { + PPH_LAYOUT_ITEM dialogItem; + + dialogItem = PvAddPropPageLayoutItem(hwndDlg, hwndDlg, + PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL); + PvAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_LIST), + dialogItem, PH_ANCHOR_ALL); + + PvDoPropPageLayout(hwndDlg); + + propPageContext->LayoutInitialized = TRUE; + } + } + break; + case WM_NOTIFY: + { + PvHandleListViewNotifyForCopy(lParam, GetDlgItem(hwndDlg, IDC_LIST)); + } + break; + } + + return FALSE; +} diff --git a/tools/peview/include/pdb.h b/tools/peview/include/pdb.h index 7b49cc6f668f..b21ac2d946c7 100644 --- a/tools/peview/include/pdb.h +++ b/tools/peview/include/pdb.h @@ -385,61 +385,61 @@ typedef struct _PDB_SYMBOL_CONTEXT PPH_LIST UdtList; } PDB_SYMBOL_CONTEXT, *PPDB_SYMBOL_CONTEXT; -BOOLEAN SymInfoDump_DumpBasicType(_Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, BaseTypeInfo* Info); -BOOLEAN SymInfoDump_DumpPointerType(_Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, PointerTypeInfo* Info); -BOOLEAN SymInfoDump_DumpTypedef(_Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, TypedefInfo* Info); -BOOLEAN SymInfoDump_DumpEnum(_Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, EnumInfo* Info); -BOOLEAN SymInfoDump_DumpArrayType(_Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, ArrayTypeInfo* Info); -BOOLEAN SymInfoDump_DumpUDT(_Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, TypeInfo* Info); -BOOLEAN SymInfoDump_DumpUDTClass(_Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, UdtClassInfo* Info); -BOOLEAN SymInfoDump_DumpUDTUnion(_Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, UdtUnionInfo* Info); -BOOLEAN SymInfoDump_DumpFunctionType(_Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, FunctionTypeInfo* Info); -BOOLEAN SymInfoDump_DumpFunctionArgType(_Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, FunctionArgTypeInfo* Info); -BOOLEAN SymInfoDump_DumpBaseClass(_Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, BaseClassInfo* Info); -BOOLEAN SymInfoDump_DumpData(_Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, DataInfo* Info); -BOOLEAN SymInfoDump_DumpType(_Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, TypeInfo* Info); -BOOLEAN SymInfoDump_DumpSymbolType(_Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, TypeInfo* Info, ULONG* TypeIndex); - -BOOLEAN SymInfoDump_CheckTag( +BOOLEAN SymbolInfo_DumpBasicType(_Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, BaseTypeInfo* Info); +BOOLEAN SymbolInfo_DumpPointerType(_Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, PointerTypeInfo* Info); +BOOLEAN SymbolInfo_DumpTypedef(_Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, TypedefInfo* Info); +BOOLEAN SymbolInfo_DumpEnum(_Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, EnumInfo* Info); +BOOLEAN SymbolInfo_DumpArrayType(_Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, ArrayTypeInfo* Info); +BOOLEAN SymbolInfo_DumpUDT(_Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, TypeInfo* Info); +BOOLEAN SymbolInfo_DumpUDTClass(_Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, UdtClassInfo* Info); +BOOLEAN SymbolInfo_DumpUDTUnion(_Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, UdtUnionInfo* Info); +BOOLEAN SymbolInfo_DumpFunctionType(_Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, FunctionTypeInfo* Info); +BOOLEAN SymbolInfo_DumpFunctionArgType(_Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, FunctionArgTypeInfo* Info); +BOOLEAN SymbolInfo_DumpBaseClass(_Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, BaseClassInfo* Info); +BOOLEAN SymbolInfo_DumpData(_Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, DataInfo* Info); +BOOLEAN SymbolInfo_DumpType(_Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, TypeInfo* Info); +BOOLEAN SymbolInfo_DumpSymbolType(_Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, TypeInfo* Info, ULONG* TypeIndex); + +BOOLEAN SymbolInfo_CheckTag( _Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, _In_ ULONG Tag ); -BOOLEAN SymInfoDump_SymbolSize(_Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, ULONG64* Size); -BOOLEAN SymInfoDump_ArrayElementTypeIndex(_Inout_ PPDB_SYMBOL_CONTEXT Context, ULONG ArrayIndex, ULONG* ElementTypeIndex); -BOOLEAN SymInfoDump_ArrayDims(_Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, ULONG64* pDims, ULONG* Dims, _In_ ULONG MaxDims); -BOOLEAN SymInfoDump_UdtVariables(_Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, ULONG* pVars, ULONG* Vars, _In_ ULONG MaxVars); -BOOLEAN SymInfoDump_UdtFunctions(_Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, ULONG* pFuncs, ULONG* Funcs, _In_ ULONG MaxFuncs); -BOOLEAN SymInfoDump_UdtBaseClasses(_Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, ULONG* pBases, ULONG* Bases, _In_ ULONG MaxBases); -BOOLEAN SymInfoDump_UdtUnionMembers(_Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, ULONG* pMembers, ULONG* Members, _In_ ULONG MaxMembers); -BOOLEAN SymInfoDump_FunctionArguments(_Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, ULONG* pArgs, ULONG* Args, _In_ ULONG MaxArgs); -BOOLEAN SymInfoDump_Enumerators(_Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, ULONG* pEnums, ULONG* Enums, _In_ ULONG MaxEnums); -BOOLEAN SymInfoDump_TypeDefType(_Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, ULONG* UndTypeIndex); -BOOLEAN SymInfoDump_PointerType(_Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, ULONG* UndTypeIndex, ULONG* NumPointers); - -BOOLEAN SymInfoDump_GetTypeNameHelper( +BOOLEAN SymbolInfo_SymbolSize(_Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, ULONG64* Size); +BOOLEAN SymbolInfo_ArrayElementTypeIndex(_Inout_ PPDB_SYMBOL_CONTEXT Context, ULONG ArrayIndex, ULONG* ElementTypeIndex); +BOOLEAN SymbolInfo_ArrayDims(_Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, ULONG64* pDims, ULONG* Dims, _In_ ULONG MaxDims); +BOOLEAN SymbolInfo_UdtVariables(_Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, ULONG* pVars, ULONG* Vars, _In_ ULONG MaxVars); +BOOLEAN SymbolInfo_UdtFunctions(_Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, ULONG* pFuncs, ULONG* Funcs, _In_ ULONG MaxFuncs); +BOOLEAN SymbolInfo_UdtBaseClasses(_Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, ULONG* pBases, ULONG* Bases, _In_ ULONG MaxBases); +BOOLEAN SymbolInfo_UdtUnionMembers(_Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, ULONG* pMembers, ULONG* Members, _In_ ULONG MaxMembers); +BOOLEAN SymbolInfo_FunctionArguments(_Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, ULONG* pArgs, ULONG* Args, _In_ ULONG MaxArgs); +BOOLEAN SymbolInfo_Enumerators(_Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, ULONG* pEnums, ULONG* Enums, _In_ ULONG MaxEnums); +BOOLEAN SymbolInfo_TypeDefType(_Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, ULONG* UndTypeIndex); +BOOLEAN SymbolInfo_PointerType(_Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, ULONG* UndTypeIndex, ULONG* NumPointers); + +BOOLEAN SymbolInfo_GetTypeNameHelper( _In_ ULONG Index, _Inout_ PPDB_SYMBOL_CONTEXT Context, _Out_ PWSTR *VarName, _Out_ PWSTR *TypeName ); -BOOLEAN SymInfoDump_GetTypeName( +BOOLEAN SymbolInfo_GetTypeName( _Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, _In_ PWSTR pVarName, _In_ PWSTR pTypeName, _In_ ULONG MaxChars ); -PWSTR SymInfoDump_TagStr(enum SymTagEnum Tag); -PWSTR SymInfoDump_BaseTypeStr(BasicType Type, ULONG64 Length); -PWSTR SymInfoDump_CallConvStr(CV_call_e CallConv); -PWSTR SymInfoDump_DataKindFromSymbolInfo(_In_ PSYMBOL_INFOW rSymbol); -PWSTR SymInfoDump_DataKindStr(DataKind dataKind); -VOID SymInfoDump_SymbolLocationStr(PSYMBOL_INFOW rSymbol, PWSTR pBuffer); -PWSTR SymInfoDump_RegisterStr(CV_HREG_e RegCode); -PWSTR SymInfoDump_UdtKindStr(UdtKind KindType); -PWSTR SymInfoDump_LocationTypeStr(LocationType LocType); +PWSTR SymbolInfo_TagStr(enum SymTagEnum Tag); +PWSTR SymbolInfo_BaseTypeStr(BasicType Type, ULONG64 Length); +PWSTR SymbolInfo_CallConvStr(CV_call_e CallConv); +PWSTR SymbolInfo_DataKindFromSymbolInfo(_In_ PSYMBOL_INFOW rSymbol); +PWSTR SymbolInfo_DataKindStr(DataKind dataKind); +VOID SymbolInfo_SymbolLocationStr(PSYMBOL_INFOW rSymbol, PWSTR pBuffer); +PWSTR SymbolInfo_RegisterStr(CV_HREG_e RegCode); +PWSTR SymbolInfo_UdtKindStr(UdtKind KindType); +PWSTR SymbolInfo_LocationTypeStr(LocationType LocType); VOID PrintDataInfo( diff --git a/tools/peview/include/peview.h b/tools/peview/include/peview.h index 639222135ceb..04a3cb8152a2 100644 --- a/tools/peview/include/peview.h +++ b/tools/peview/include/peview.h @@ -3,13 +3,20 @@ #include #include +#include #include #include #include +#include + +#include #include "resource.h" extern PPH_STRING PvFileName; +extern PH_MAPPED_IMAGE PvMappedImage; +extern PIMAGE_COR20_HEADER PvImageCor20Header; +extern PPH_SYMBOL_PROVIDER PvSymbolProvider; // peprp @@ -66,4 +73,41 @@ VOID PvPdbProperties( VOID ); +// + +INT_PTR CALLBACK PvpPeImportsDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +INT_PTR CALLBACK PvpPeExportsDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +INT_PTR CALLBACK PvpPeLoadConfigDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +INT_PTR CALLBACK PvpPeClrDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +INT_PTR CALLBACK PvpPeCgfDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + #endif diff --git a/tools/peview/ldprp.c b/tools/peview/ldprp.c new file mode 100644 index 000000000000..22d6e24d5117 --- /dev/null +++ b/tools/peview/ldprp.c @@ -0,0 +1,160 @@ +/* + * Process Hacker - + * PE viewer + * + * Copyright (C) 2010-2011 wj32 + * Copyright (C) 2017 dmex + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include + +INT_PTR CALLBACK PvpPeLoadConfigDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + LPPROPSHEETPAGE propSheetPage; + PPV_PROPPAGECONTEXT propPageContext; + + if (!PvPropPageDlgProcHeader(hwndDlg, uMsg, lParam, &propSheetPage, &propPageContext)) + return FALSE; + + switch (uMsg) + { + case WM_INITDIALOG: + { + HWND lvHandle; + PIMAGE_LOAD_CONFIG_DIRECTORY32 config32; + PIMAGE_LOAD_CONFIG_DIRECTORY64 config64; + + lvHandle = GetDlgItem(hwndDlg, IDC_LIST); + PhSetListViewStyle(lvHandle, TRUE, TRUE); + PhSetControlTheme(lvHandle, L"explorer"); + PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 220, L"Name"); + PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 170, L"Value"); + PhSetExtendedListView(lvHandle); + PhLoadListViewColumnsFromSetting(L"ImageLoadCfgListViewColumns", lvHandle); + + #define ADD_VALUE(Name, Value) \ + { \ + INT lvItemIndex; \ + lvItemIndex = PhAddListViewItem(lvHandle, MAXINT, Name, NULL); \ + PhSetListViewSubItem(lvHandle, lvItemIndex, 1, Value); \ + } + + #define ADD_VALUES(Type, Config) \ + { \ + LARGE_INTEGER time; \ + SYSTEMTIME systemTime; \ + \ + RtlSecondsSince1970ToTime((Config)->TimeDateStamp, &time); \ + PhLargeIntegerToLocalSystemTime(&systemTime, &time); \ + \ + ADD_VALUE(L"Time stamp", PhaFormatDateTime(&systemTime)->Buffer); \ + ADD_VALUE(L"Version", PhaFormatString(L"%u.%u", (Config)->MajorVersion, (Config)->MinorVersion)->Buffer); \ + ADD_VALUE(L"Global flags to clear", PhaFormatString(L"0x%x", (Config)->GlobalFlagsClear)->Buffer); \ + ADD_VALUE(L"Global flags to set", PhaFormatString(L"0x%x", (Config)->GlobalFlagsSet)->Buffer); \ + ADD_VALUE(L"Critical section default timeout", PhaFormatUInt64((Config)->CriticalSectionDefaultTimeout, TRUE)->Buffer); \ + ADD_VALUE(L"De-commit free block threshold", PhaFormatUInt64((Config)->DeCommitFreeBlockThreshold, TRUE)->Buffer); \ + ADD_VALUE(L"De-commit total free threshold", PhaFormatUInt64((Config)->DeCommitTotalFreeThreshold, TRUE)->Buffer); \ + ADD_VALUE(L"LOCK prefix table", PhaFormatString(L"0x%Ix", (Config)->LockPrefixTable)->Buffer); \ + ADD_VALUE(L"Maximum allocation size", PhaFormatString(L"0x%Ix", (Config)->MaximumAllocationSize)->Buffer); \ + ADD_VALUE(L"Virtual memory threshold", PhaFormatString(L"0x%Ix", (Config)->VirtualMemoryThreshold)->Buffer); \ + ADD_VALUE(L"Process affinity mask", PhaFormatString(L"0x%Ix", (Config)->ProcessAffinityMask)->Buffer); \ + ADD_VALUE(L"Process heap flags", PhaFormatString(L"0x%Ix", (Config)->ProcessHeapFlags)->Buffer); \ + ADD_VALUE(L"CSD version", PhaFormatString(L"%u", (Config)->CSDVersion)->Buffer); \ + ADD_VALUE(L"Edit list", PhaFormatString(L"0x%Ix", (Config)->EditList)->Buffer); \ + ADD_VALUE(L"Security cookie", PhaFormatString(L"0x%Ix", (Config)->SecurityCookie)->Buffer); \ + ADD_VALUE(L"SEH handler table", PhaFormatString(L"0x%Ix", (Config)->SEHandlerTable)->Buffer); \ + ADD_VALUE(L"SEH handler count", PhaFormatUInt64((Config)->SEHandlerCount, TRUE)->Buffer); \ + \ + if ((Config)->Size >= (ULONG)FIELD_OFFSET(Type, GuardAddressTakenIatEntryTable)) \ + { \ + ADD_VALUE(L"CFG GuardFlags", PhaFormatString(L"0x%Ix", (Config)->GuardFlags)->Buffer); \ + ADD_VALUE(L"CFG Check Function pointer", PhaFormatString(L"0x%Ix", (Config)->GuardCFCheckFunctionPointer)->Buffer); \ + ADD_VALUE(L"CFG Check Dispatch pointer", PhaFormatString(L"0x%Ix", (Config)->GuardCFDispatchFunctionPointer)->Buffer); \ + ADD_VALUE(L"CFG Function table", PhaFormatString(L"0x%Ix", (Config)->GuardCFFunctionTable)->Buffer); \ + ADD_VALUE(L"CFG Function table entry count", PhaFormatUInt64((Config)->GuardCFFunctionCount, TRUE)->Buffer); \ + if ((Config)->Size >= (ULONG)FIELD_OFFSET(Type, GuardAddressTakenIatEntryTable) \ + + sizeof((Config)->GuardAddressTakenIatEntryTable) \ + + sizeof((Config)->GuardAddressTakenIatEntryCount)) \ + { \ + ADD_VALUE(L"CFG IatEntry table", PhaFormatString(L"0x%Ix", (Config)->GuardAddressTakenIatEntryTable)->Buffer); \ + ADD_VALUE(L"CFG IatEntry table entry count", PhaFormatUInt64((Config)->GuardAddressTakenIatEntryCount, TRUE)->Buffer); \ + } \ + if ((Config)->Size >= (ULONG)FIELD_OFFSET(Type, GuardLongJumpTargetTable) \ + + sizeof((Config)->GuardLongJumpTargetTable) \ + + sizeof((Config)->GuardLongJumpTargetCount))\ + { \ + ADD_VALUE(L"CFG LongJump table", PhaFormatString(L"0x%Ix", (Config)->GuardLongJumpTargetTable)->Buffer); \ + ADD_VALUE(L"CFG LongJump table entry count", PhaFormatUInt64((Config)->GuardLongJumpTargetCount, TRUE)->Buffer); \ + } \ + } \ + } + + if (PvMappedImage.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) + { + if (NT_SUCCESS(PhGetMappedImageLoadConfig32(&PvMappedImage, &config32))) + { + ADD_VALUES(IMAGE_LOAD_CONFIG_DIRECTORY32, config32); + } + } + else + { + if (NT_SUCCESS(PhGetMappedImageLoadConfig64(&PvMappedImage, &config64))) + { + ADD_VALUES(IMAGE_LOAD_CONFIG_DIRECTORY64, config64); + } + } + + EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); + } + break; + case WM_DESTROY: + { + PhSaveListViewColumnsToSetting(L"ImageLoadCfgListViewColumns", GetDlgItem(hwndDlg, IDC_LIST)); + } + break; + case WM_SHOWWINDOW: + { + if (!propPageContext->LayoutInitialized) + { + PPH_LAYOUT_ITEM dialogItem; + + dialogItem = PvAddPropPageLayoutItem(hwndDlg, hwndDlg, + PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL); + PvAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_LIST), + dialogItem, PH_ANCHOR_ALL); + + PvDoPropPageLayout(hwndDlg); + + propPageContext->LayoutInitialized = TRUE; + } + } + break; + case WM_NOTIFY: + { + PvHandleListViewNotifyForCopy(lParam, GetDlgItem(hwndDlg, IDC_LIST)); + } + break; + } + + return FALSE; +} diff --git a/tools/peview/pdb.c b/tools/peview/pdb.c index 124b0209c8b8..19fc41cdcde2 100644 --- a/tools/peview/pdb.c +++ b/tools/peview/pdb.c @@ -73,12 +73,18 @@ typedef ULONG64 (WINAPI *_SymLoadModuleExW)( _In_ ULONG Flags ); -typedef BOOL(WINAPI *_SymGetModuleInfoW64)( +typedef BOOL (WINAPI *_SymGetModuleInfoW64)( _In_ HANDLE hProcess, _In_ ULONG64 qwAddr, _Out_ PIMAGEHLP_MODULEW64 ModuleInfo ); +typedef BOOL (WINAPI *_SymSetContext)( + _In_ HANDLE hProcess, + _In_ PIMAGEHLP_STACK_FRAME StackFrame, + _In_opt_ PIMAGEHLP_CONTEXT Context + ); + _SymInitialize SymInitialize_I = NULL; _SymCleanup SymCleanup_I = NULL; _SymEnumSymbolsW SymEnumSymbolsW_I = NULL; @@ -88,8 +94,9 @@ _SymSetOptions SymSetOptions_I = NULL; _SymLoadModuleExW SymLoadModuleExW_I = NULL; _SymGetModuleInfoW64 SymGetModuleInfoW64_I = NULL; _SymGetTypeInfo SymGetTypeInfo_I = NULL; +_SymSetContext SymSetContext_I = NULL; -BOOLEAN SymInfoDump_DumpBasicType( +BOOLEAN SymbolInfo_DumpBasicType( _Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, _Inout_ BaseTypeInfo *Info @@ -98,7 +105,7 @@ BOOLEAN SymInfoDump_DumpBasicType( ULONG baseType = btNoType; ULONG64 length = 0; - if (!SymInfoDump_CheckTag(Context, Index, SymTagBaseType)) + if (!SymbolInfo_CheckTag(Context, Index, SymTagBaseType)) return FALSE; // Basic type ("basicType" in DIA) @@ -114,7 +121,7 @@ BOOLEAN SymInfoDump_DumpBasicType( return TRUE; } -BOOLEAN SymInfoDump_DumpPointerType( +BOOLEAN SymbolInfo_DumpPointerType( _Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, _Inout_ PointerTypeInfo* Info @@ -123,7 +130,7 @@ BOOLEAN SymInfoDump_DumpPointerType( ULONG TypeIndex = 0; ULONG64 Length = 0; - if (!SymInfoDump_CheckTag(Context, Index, SymTagPointerType)) + if (!SymbolInfo_CheckTag(Context, Index, SymTagPointerType)) return FALSE; // Type index ("typeId" in DIA) @@ -144,7 +151,7 @@ BOOLEAN SymInfoDump_DumpPointerType( return TRUE; } -BOOLEAN SymInfoDump_DumpTypedef( +BOOLEAN SymbolInfo_DumpTypedef( _Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, _Inout_ TypedefInfo* Info @@ -153,7 +160,7 @@ BOOLEAN SymInfoDump_DumpTypedef( ULONG typeIndex = 0; PWSTR symbolName = NULL; - if (!SymInfoDump_CheckTag(Context, Index, SymTagTypedef)) + if (!SymbolInfo_CheckTag(Context, Index, SymTagTypedef)) return FALSE; // Type index ("typeId" in DIA) @@ -173,7 +180,7 @@ BOOLEAN SymInfoDump_DumpTypedef( return TRUE; } -BOOLEAN SymInfoDump_DumpEnum( +BOOLEAN SymbolInfo_DumpEnum( _Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, _Inout_ EnumInfo* Info @@ -183,7 +190,7 @@ BOOLEAN SymInfoDump_DumpEnum( ULONG Nested = 0; PWSTR symbolName = NULL; - if (!SymInfoDump_CheckTag(Context, Index, SymTagEnum)) + if (!SymbolInfo_CheckTag(Context, Index, SymTagEnum)) return FALSE; // Name ("name" in DIA) @@ -203,7 +210,7 @@ BOOLEAN SymInfoDump_DumpEnum( return FALSE; // Enumerators - if (!SymInfoDump_Enumerators(Context, Index, Info->Enums, &Info->NumEnums, ARRAYSIZE(Info->Enums))) + if (!SymbolInfo_Enumerators(Context, Index, Info->Enums, &Info->NumEnums, ARRAYSIZE(Info->Enums))) return FALSE; Info->TypeIndex = TypeIndex; @@ -212,7 +219,7 @@ BOOLEAN SymInfoDump_DumpEnum( return TRUE; } -BOOLEAN SymInfoDump_DumpArrayType( +BOOLEAN SymbolInfo_DumpArrayType( _Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, _Inout_ ArrayTypeInfo* Info @@ -223,11 +230,11 @@ BOOLEAN SymInfoDump_DumpArrayType( ULONG indexTypeIndex = 0; // Check if it is really SymTagArrayType - if (!SymInfoDump_CheckTag(Context, Index, SymTagArrayType)) + if (!SymbolInfo_CheckTag(Context, Index, SymTagArrayType)) return FALSE; // Element type index - if (!SymInfoDump_ArrayElementTypeIndex(Context, Index, &elementTypeIndex)) + if (!SymbolInfo_ArrayElementTypeIndex(Context, Index, &elementTypeIndex)) return FALSE; // Length ("length" in DIA) @@ -245,7 +252,7 @@ BOOLEAN SymInfoDump_DumpArrayType( if (length > 0) { // Dimensions - if (!SymInfoDump_ArrayDims( + if (!SymbolInfo_ArrayDims( Context, Index, Info->Dimensions, @@ -264,7 +271,7 @@ BOOLEAN SymInfoDump_DumpArrayType( return TRUE; } -BOOLEAN SymInfoDump_DumpUDT( +BOOLEAN SymbolInfo_DumpUDT( _Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, _Inout_ TypeInfo* Info @@ -273,7 +280,7 @@ BOOLEAN SymInfoDump_DumpUDT( ULONG UDTKind = 0; BOOLEAN result = FALSE; - if (!SymInfoDump_CheckTag(Context, Index, SymTagUDT)) + if (!SymbolInfo_CheckTag(Context, Index, SymTagUDT)) return FALSE; // Determine UDT kind (class/structure or union?) @@ -284,22 +291,22 @@ BOOLEAN SymInfoDump_DumpUDT( { case UdtStruct: Info->UdtKind = TRUE; - result = SymInfoDump_DumpUDTClass(Context, Index, &Info->sUdtClassInfo); + result = SymbolInfo_DumpUDTClass(Context, Index, &Info->sUdtClassInfo); break; case UdtClass: Info->UdtKind = TRUE; - result = SymInfoDump_DumpUDTClass(Context, Index, &Info->sUdtClassInfo); + result = SymbolInfo_DumpUDTClass(Context, Index, &Info->sUdtClassInfo); break; case UdtUnion: Info->UdtKind = FALSE; - result = SymInfoDump_DumpUDTUnion(Context, Index, &Info->sUdtUnionInfo); + result = SymbolInfo_DumpUDTUnion(Context, Index, &Info->sUdtUnionInfo); break; } return result; } -BOOLEAN SymInfoDump_DumpUDTClass( +BOOLEAN SymbolInfo_DumpUDTClass( _Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, _Inout_ UdtClassInfo* Info @@ -310,7 +317,7 @@ BOOLEAN SymInfoDump_DumpUDTClass( ULONG64 Length = 0; ULONG Nested = 0; - if (!SymInfoDump_CheckTag(Context, Index, SymTagUDT)) + if (!SymbolInfo_CheckTag(Context, Index, SymTagUDT)) return FALSE; // Check if it is really a class or structure UDT ? @@ -337,15 +344,15 @@ BOOLEAN SymInfoDump_DumpUDTClass( return FALSE; // Member variables - if (!SymInfoDump_UdtVariables(Context, Index, Info->Variables, &Info->NumVariables, ARRAYSIZE(Info->Variables))) + if (!SymbolInfo_UdtVariables(Context, Index, Info->Variables, &Info->NumVariables, ARRAYSIZE(Info->Variables))) return FALSE; // Member functions - if (!SymInfoDump_UdtFunctions(Context, Index, Info->Functions, &Info->NumFunctions, ARRAYSIZE(Info->Functions))) + if (!SymbolInfo_UdtFunctions(Context, Index, Info->Functions, &Info->NumFunctions, ARRAYSIZE(Info->Functions))) return FALSE; // Base classes - if (!SymInfoDump_UdtBaseClasses(Context, Index, Info->BaseClasses, &Info->NumBaseClasses, ARRAYSIZE(Info->BaseClasses))) + if (!SymbolInfo_UdtBaseClasses(Context, Index, Info->BaseClasses, &Info->NumBaseClasses, ARRAYSIZE(Info->BaseClasses))) return FALSE; Info->UDTKind = (UdtKind)UDTKind; @@ -355,7 +362,7 @@ BOOLEAN SymInfoDump_DumpUDTClass( return TRUE; } -BOOLEAN SymInfoDump_DumpUDTUnion( +BOOLEAN SymbolInfo_DumpUDTUnion( _Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, _Inout_ UdtUnionInfo *Info @@ -366,7 +373,7 @@ BOOLEAN SymInfoDump_DumpUDTUnion( ULONG64 Length = 0; ULONG Nested = 0; - if (!SymInfoDump_CheckTag(Context, Index, SymTagUDT)) + if (!SymbolInfo_CheckTag(Context, Index, SymTagUDT)) return FALSE; // Check if it is really a union UDT ? @@ -393,7 +400,7 @@ BOOLEAN SymInfoDump_DumpUDTUnion( return FALSE; // Union members - if (!SymInfoDump_UdtUnionMembers(Context, Index, Info->Members, &Info->NumMembers, ARRAYSIZE(Info->Members))) + if (!SymbolInfo_UdtUnionMembers(Context, Index, Info->Members, &Info->NumMembers, ARRAYSIZE(Info->Members))) return FALSE; Info->UDTKind = (UdtKind)UDTKind; @@ -403,7 +410,7 @@ BOOLEAN SymInfoDump_DumpUDTUnion( return TRUE; } -BOOLEAN SymInfoDump_DumpFunctionType( +BOOLEAN SymbolInfo_DumpFunctionType( _Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, _Inout_ FunctionTypeInfo *Info @@ -414,7 +421,7 @@ BOOLEAN SymInfoDump_DumpFunctionType( ULONG CallConv = 0; ULONG ClassIndex = 0; - if (!SymInfoDump_CheckTag(Context, Index, SymTagFunctionType)) + if (!SymbolInfo_CheckTag(Context, Index, SymTagFunctionType)) return FALSE; // Index of the return type symbol ("typeId" in DIA) @@ -479,7 +486,7 @@ BOOLEAN SymInfoDump_DumpFunctionType( */ // Dump function arguments - if (!SymInfoDump_FunctionArguments(Context, Index, Info->Args, &Info->NumArgs, ARRAYSIZE(Info->Args))) + if (!SymbolInfo_FunctionArguments(Context, Index, Info->Args, &Info->NumArgs, ARRAYSIZE(Info->Args))) return FALSE; // Is the function static ? (If it is a member function) @@ -496,7 +503,7 @@ BOOLEAN SymInfoDump_DumpFunctionType( return TRUE; } -BOOLEAN SymInfoDump_DumpFunctionArgType( +BOOLEAN SymbolInfo_DumpFunctionArgType( _Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, _Inout_ FunctionArgTypeInfo *Info @@ -504,7 +511,7 @@ BOOLEAN SymInfoDump_DumpFunctionArgType( { ULONG typeIndex = 0; - if (!SymInfoDump_CheckTag(Context, Index, SymTagFunctionArgType)) + if (!SymbolInfo_CheckTag(Context, Index, SymTagFunctionArgType)) return FALSE; // Index of the argument type ("typeId" in DIA) @@ -516,7 +523,7 @@ BOOLEAN SymInfoDump_DumpFunctionArgType( return TRUE; } -BOOLEAN SymInfoDump_DumpBaseClass( +BOOLEAN SymbolInfo_DumpBaseClass( _Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, _Inout_ BaseClassInfo *Info @@ -525,7 +532,7 @@ BOOLEAN SymInfoDump_DumpBaseClass( ULONG typeIndex = 0; ULONG virtualBase = 0; - if (!SymInfoDump_CheckTag(Context, Index, SymTagBaseClass)) + if (!SymbolInfo_CheckTag(Context, Index, SymTagBaseClass)) return FALSE; // Base class UDT @@ -597,7 +604,7 @@ BOOLEAN SymInfoDump_DumpBaseClass( return TRUE; } -BOOLEAN SymInfoDump_DumpData( +BOOLEAN SymbolInfo_DumpData( _Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, _Inout_ DataInfo *Info @@ -607,7 +614,7 @@ BOOLEAN SymInfoDump_DumpData( ULONG TypeIndex = 0; ULONG dataKind = 0; - if (!SymInfoDump_CheckTag(Context, Index, SymTagData)) + if (!SymbolInfo_CheckTag(Context, Index, SymTagData)) return FALSE; // Name ("name" in DIA) @@ -677,7 +684,7 @@ BOOLEAN SymInfoDump_DumpData( return TRUE; } -BOOLEAN SymInfoDump_DumpType( +BOOLEAN SymbolInfo_DumpType( _Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, _Inout_ TypeInfo *Info @@ -704,41 +711,41 @@ BOOLEAN SymInfoDump_DumpType( switch (tag) { case SymTagBaseType: - result = SymInfoDump_DumpBasicType(Context, Index, &Info->sBaseTypeInfo); + result = SymbolInfo_DumpBasicType(Context, Index, &Info->sBaseTypeInfo); break; case SymTagPointerType: - result = SymInfoDump_DumpPointerType(Context, Index, &Info->sPointerTypeInfo); + result = SymbolInfo_DumpPointerType(Context, Index, &Info->sPointerTypeInfo); break; case SymTagTypedef: - result = SymInfoDump_DumpTypedef(Context, Index, &Info->sTypedefInfo); + result = SymbolInfo_DumpTypedef(Context, Index, &Info->sTypedefInfo); break; case SymTagEnum: - result = SymInfoDump_DumpEnum(Context, Index, &Info->sEnumInfo); + result = SymbolInfo_DumpEnum(Context, Index, &Info->sEnumInfo); break; case SymTagArrayType: - result = SymInfoDump_DumpArrayType(Context, Index, &Info->sArrayTypeInfo); + result = SymbolInfo_DumpArrayType(Context, Index, &Info->sArrayTypeInfo); break; case SymTagUDT: - result = SymInfoDump_DumpUDT(Context, Index, Info); + result = SymbolInfo_DumpUDT(Context, Index, Info); break; case SymTagFunctionType: - result = SymInfoDump_DumpFunctionType(Context, Index, &Info->sFunctionTypeInfo); + result = SymbolInfo_DumpFunctionType(Context, Index, &Info->sFunctionTypeInfo); break; case SymTagFunctionArgType: - result = SymInfoDump_DumpFunctionArgType(Context, Index, &Info->sFunctionArgTypeInfo); + result = SymbolInfo_DumpFunctionArgType(Context, Index, &Info->sFunctionArgTypeInfo); break; case SymTagBaseClass: - result = SymInfoDump_DumpBaseClass(Context, Index, &Info->sBaseClassInfo); + result = SymbolInfo_DumpBaseClass(Context, Index, &Info->sBaseClassInfo); break; case SymTagData: - result = SymInfoDump_DumpData(Context, Index, &Info->sDataInfo); + result = SymbolInfo_DumpData(Context, Index, &Info->sDataInfo); break; } return result; } -BOOLEAN SymInfoDump_DumpSymbolType( +BOOLEAN SymbolInfo_DumpSymbolType( _Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, _Inout_ TypeInfo *Info, @@ -750,10 +757,10 @@ BOOLEAN SymInfoDump_DumpSymbolType( return FALSE; // Dump the type symbol - return SymInfoDump_DumpType(Context, *TypeIndex, Info); + return SymbolInfo_DumpType(Context, *TypeIndex, Info); } -BOOLEAN SymInfoDump_CheckTag( +BOOLEAN SymbolInfo_CheckTag( _Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, _In_ ULONG Tag @@ -761,21 +768,13 @@ BOOLEAN SymInfoDump_CheckTag( { ULONG symTag = SymTagNull; - if (!SymGetTypeInfo_I( - NtCurrentProcess(), - Context->BaseAddress, - Index, - TI_GET_SYMTAG, - &symTag - )) - { + if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, Index, TI_GET_SYMTAG, &symTag)) return FALSE; - } return symTag == Tag; } -BOOLEAN SymInfoDump_SymbolSize( +BOOLEAN SymbolInfo_SymbolSize( _Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, _Inout_ ULONG64* Size @@ -793,7 +792,7 @@ BOOLEAN SymInfoDump_SymbolSize( else { // No, it does not - it can be SymTagTypedef - if (!SymInfoDump_CheckTag(Context, Index, SymTagTypedef)) + if (!SymbolInfo_CheckTag(Context, Index, SymTagTypedef)) { // No, this symbol does not have length return FALSE; @@ -812,7 +811,7 @@ BOOLEAN SymInfoDump_SymbolSize( index = tempIndex; - } while (SymInfoDump_CheckTag(Context, index, SymTagTypedef)); + } while (SymbolInfo_CheckTag(Context, index, SymTagTypedef)); // And get the length if (SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, index, TI_GET_LENGTH, &length)) @@ -826,7 +825,7 @@ BOOLEAN SymInfoDump_SymbolSize( return FALSE; } -BOOLEAN SymInfoDump_ArrayElementTypeIndex( +BOOLEAN SymbolInfo_ArrayElementTypeIndex( _Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG ArrayIndex, _Inout_ ULONG* ElementTypeIndex @@ -835,7 +834,7 @@ BOOLEAN SymInfoDump_ArrayElementTypeIndex( ULONG index; ULONG elementIndex = 0; - if (!SymInfoDump_CheckTag(Context, ArrayIndex, SymTagArrayType)) + if (!SymbolInfo_CheckTag(Context, ArrayIndex, SymTagArrayType)) return FALSE; // Get the array element type @@ -845,7 +844,7 @@ BOOLEAN SymInfoDump_ArrayElementTypeIndex( // If the array element type is SymTagArrayType, skip to its type index = elementIndex; - while (SymInfoDump_CheckTag(Context, elementIndex, SymTagArrayType)) + while (SymbolInfo_CheckTag(Context, elementIndex, SymTagArrayType)) { if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, index, TI_GET_TYPEID, &elementIndex)) return FALSE; @@ -859,7 +858,7 @@ BOOLEAN SymInfoDump_ArrayElementTypeIndex( return TRUE; } -BOOLEAN SymInfoDump_ArrayDims( +BOOLEAN SymbolInfo_ArrayDims( _Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, _Inout_ ULONG64* pDims, @@ -870,7 +869,7 @@ BOOLEAN SymInfoDump_ArrayDims( ULONG index; ULONG dimCount; - if (!SymInfoDump_CheckTag(Context, Index, SymTagArrayType)) + if (!SymbolInfo_CheckTag(Context, Index, SymTagArrayType)) return FALSE; if (MaxDims <= 0) @@ -901,7 +900,7 @@ BOOLEAN SymInfoDump_ArrayDims( } // Size of its type - if (!SymInfoDump_SymbolSize(Context, typeIndex, &typeSize) || (typeSize == 0)) + if (!SymbolInfo_SymbolSize(Context, typeIndex, &typeSize) || (typeSize == 0)) return FALSE; // Size of the dimension @@ -925,7 +924,7 @@ BOOLEAN SymInfoDump_ArrayDims( } */ // If the type symbol is not SymTagArrayType, we are done - if (!SymInfoDump_CheckTag(Context, typeIndex, SymTagArrayType)) + if (!SymbolInfo_CheckTag(Context, typeIndex, SymTagArrayType)) break; index = typeIndex; @@ -939,7 +938,7 @@ BOOLEAN SymInfoDump_ArrayDims( return TRUE; } -BOOLEAN SymInfoDump_UdtVariables( +BOOLEAN SymbolInfo_UdtVariables( _Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, _Inout_ ULONG* pVars, @@ -949,7 +948,7 @@ BOOLEAN SymInfoDump_UdtVariables( { ULONG childrenLength = 0; - if (!SymInfoDump_CheckTag(Context, Index, SymTagUDT)) + if (!SymbolInfo_CheckTag(Context, Index, SymTagUDT)) return FALSE; if (MaxVars <= 0) @@ -979,7 +978,7 @@ BOOLEAN SymInfoDump_UdtVariables( // Enumerate children, looking for base classes, and copy their indexes. for (ULONG i = 0; i < childrenLength; i++) { - if (SymInfoDump_CheckTag(Context, params->ChildId[i], SymTagData)) + if (SymbolInfo_CheckTag(Context, params->ChildId[i], SymTagData)) { pVars[*Vars] = params->ChildId[i]; @@ -993,7 +992,7 @@ BOOLEAN SymInfoDump_UdtVariables( return TRUE; } -BOOLEAN SymInfoDump_UdtFunctions( +BOOLEAN SymbolInfo_UdtFunctions( _Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, _Inout_ ULONG* pFuncs, @@ -1003,7 +1002,7 @@ BOOLEAN SymInfoDump_UdtFunctions( { ULONG childrenLength = 0; - if (!SymInfoDump_CheckTag(Context, Index, SymTagUDT)) + if (!SymbolInfo_CheckTag(Context, Index, SymTagUDT)) return FALSE; if (MaxFuncs <= 0) @@ -1034,7 +1033,7 @@ BOOLEAN SymInfoDump_UdtFunctions( // Enumerate children, looking for base classes, and copy their indexes. for (ULONG i = 0; i < childrenLength; i++) { - if (SymInfoDump_CheckTag(Context, params->ChildId[i], SymTagFunction)) + if (SymbolInfo_CheckTag(Context, params->ChildId[i], SymTagFunction)) { pFuncs[*Funcs] = params->ChildId[i]; @@ -1048,7 +1047,7 @@ BOOLEAN SymInfoDump_UdtFunctions( return TRUE; } -BOOLEAN SymInfoDump_UdtBaseClasses( +BOOLEAN SymbolInfo_UdtBaseClasses( _Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, _Inout_ ULONG* pBases, @@ -1058,7 +1057,7 @@ BOOLEAN SymInfoDump_UdtBaseClasses( { ULONG childrenLength = 0; - if (!SymInfoDump_CheckTag(Context, Index, SymTagUDT)) + if (!SymbolInfo_CheckTag(Context, Index, SymTagUDT)) return FALSE; if (MaxBases <= 0) @@ -1089,7 +1088,7 @@ BOOLEAN SymInfoDump_UdtBaseClasses( // Enumerate children, looking for base classes, and copy their indexes. for (ULONG i = 0; i < childrenLength; i++) { - if (SymInfoDump_CheckTag(Context, params->ChildId[i], SymTagBaseClass)) + if (SymbolInfo_CheckTag(Context, params->ChildId[i], SymTagBaseClass)) { pBases[*Bases] = params->ChildId[i]; @@ -1103,7 +1102,7 @@ BOOLEAN SymInfoDump_UdtBaseClasses( return TRUE; } -BOOLEAN SymInfoDump_UdtUnionMembers( +BOOLEAN SymbolInfo_UdtUnionMembers( _Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, _Inout_ ULONG* pMembers, @@ -1113,7 +1112,7 @@ BOOLEAN SymInfoDump_UdtUnionMembers( { ULONG childrenLength = 0; - if (!SymInfoDump_CheckTag(Context, Index, SymTagUDT)) + if (!SymbolInfo_CheckTag(Context, Index, SymTagUDT)) return FALSE; if (MaxMembers <= 0) @@ -1144,7 +1143,7 @@ BOOLEAN SymInfoDump_UdtUnionMembers( // Enumerate children, looking for enumerators, and copy their indexes. for (ULONG i = 0; i < childrenLength; i++) { - if (SymInfoDump_CheckTag(Context, params->ChildId[i], SymTagData)) + if (SymbolInfo_CheckTag(Context, params->ChildId[i], SymTagData)) { pMembers[*Members] = params->ChildId[i]; @@ -1158,7 +1157,7 @@ BOOLEAN SymInfoDump_UdtUnionMembers( return TRUE; } -BOOLEAN SymInfoDump_FunctionArguments( +BOOLEAN SymbolInfo_FunctionArguments( _Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, _Inout_ ULONG* pArgs, @@ -1168,7 +1167,7 @@ BOOLEAN SymInfoDump_FunctionArguments( { ULONG childrenLength = 0; - if (!SymInfoDump_CheckTag(Context, Index, SymTagFunctionType)) + if (!SymbolInfo_CheckTag(Context, Index, SymTagFunctionType)) return FALSE; if (MaxArgs <= 0) @@ -1199,7 +1198,7 @@ BOOLEAN SymInfoDump_FunctionArguments( // Enumerate children, looking for enumerators, and copy their indexes. for (ULONG i = 0; i < childrenLength; i++) { - if (SymInfoDump_CheckTag(Context, params->ChildId[i], SymTagFunctionArgType)) + if (SymbolInfo_CheckTag(Context, params->ChildId[i], SymTagFunctionArgType)) { pArgs[*Args] = params->ChildId[i]; @@ -1213,7 +1212,7 @@ BOOLEAN SymInfoDump_FunctionArguments( return TRUE; } -BOOLEAN SymInfoDump_Enumerators( +BOOLEAN SymbolInfo_Enumerators( _Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, _Inout_ ULONG *pEnums, @@ -1223,7 +1222,7 @@ BOOLEAN SymInfoDump_Enumerators( { ULONG childrenLength = 0; - if (!SymInfoDump_CheckTag(Context, Index, SymTagEnum)) + if (!SymbolInfo_CheckTag(Context, Index, SymTagEnum)) return FALSE; if (MaxEnums <= 0) @@ -1254,7 +1253,7 @@ BOOLEAN SymInfoDump_Enumerators( // Enumerate children, looking for enumerators, and copy their indexes. for (ULONG i = 0; i < childrenLength; i++) { - if (SymInfoDump_CheckTag(Context, params->ChildId[i], SymTagData)) + if (SymbolInfo_CheckTag(Context, params->ChildId[i], SymTagData)) { pEnums[*Enums] = params->ChildId[i]; @@ -1268,7 +1267,7 @@ BOOLEAN SymInfoDump_Enumerators( return TRUE; } -BOOLEAN SymInfoDump_TypeDefType( +BOOLEAN SymbolInfo_TypeDefType( _Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, _Inout_ ULONG *UndTypeIndex @@ -1276,13 +1275,13 @@ BOOLEAN SymInfoDump_TypeDefType( { ULONG index; - if (!SymInfoDump_CheckTag(Context, Index, SymTagTypedef)) + if (!SymbolInfo_CheckTag(Context, Index, SymTagTypedef)) return FALSE; // Skip to the type behind the type definition index = Index; - while (SymInfoDump_CheckTag(Context, index, SymTagTypedef)) + while (SymbolInfo_CheckTag(Context, index, SymTagTypedef)) { if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, index, TI_GET_TYPEID, UndTypeIndex)) return FALSE; @@ -1293,7 +1292,7 @@ BOOLEAN SymInfoDump_TypeDefType( return TRUE; } -BOOLEAN SymInfoDump_PointerType( +BOOLEAN SymbolInfo_PointerType( _Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, _Inout_ ULONG *UndTypeIndex, @@ -1302,14 +1301,14 @@ BOOLEAN SymInfoDump_PointerType( { ULONG index; - if (!SymInfoDump_CheckTag(Context, Index, SymTagPointerType)) + if (!SymbolInfo_CheckTag(Context, Index, SymTagPointerType)) return FALSE; // Skip to the type pointer points to *NumPointers = 0; index = Index; - while (SymInfoDump_CheckTag(Context, index, SymTagPointerType)) + while (SymbolInfo_CheckTag(Context, index, SymTagPointerType)) { if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, index, TI_GET_TYPEID, UndTypeIndex)) return FALSE; @@ -1322,7 +1321,7 @@ BOOLEAN SymInfoDump_PointerType( return TRUE; } -BOOLEAN SymInfoDump_GetTypeNameHelper( +BOOLEAN SymbolInfo_GetTypeNameHelper( _In_ ULONG Index, _Inout_ PPDB_SYMBOL_CONTEXT Obj, _Out_ PWSTR *VarName, @@ -1332,7 +1331,7 @@ BOOLEAN SymInfoDump_GetTypeNameHelper( TypeInfo Info; // Get the type information - if (!SymInfoDump_DumpType(Obj, Index, &Info)) + if (!SymbolInfo_DumpType(Obj, Index, &Info)) { return FALSE; } @@ -1346,11 +1345,11 @@ BOOLEAN SymInfoDump_GetTypeNameHelper( // Yes, get the number of * to show ULONG typeIndex = 0; - if (!SymInfoDump_PointerType(Obj, Index, &typeIndex, &numPointers)) + if (!SymbolInfo_PointerType(Obj, Index, &typeIndex, &numPointers)) return FALSE; // Get more information about the type the pointer points to - if (!SymInfoDump_DumpType(Obj, typeIndex, &Info)) + if (!SymbolInfo_DumpType(Obj, typeIndex, &Info)) return FALSE; // Save the index of the type the pointer points to @@ -1362,7 +1361,7 @@ BOOLEAN SymInfoDump_GetTypeNameHelper( switch (Info.Tag) { case SymTagBaseType: - *TypeName = SymInfoDump_BaseTypeStr(Info.sBaseTypeInfo.BaseType, Info.sBaseTypeInfo.Length); + *TypeName = SymbolInfo_BaseTypeStr(Info.sBaseTypeInfo.BaseType, Info.sBaseTypeInfo.Length); break; case SymTagTypedef: @@ -1399,12 +1398,12 @@ BOOLEAN SymInfoDump_GetTypeNameHelper( } // Print return value - if (!SymInfoDump_GetTypeNameHelper(Info.sFunctionTypeInfo.RetTypeIndex, Obj, VarName, TypeName)) + if (!SymbolInfo_GetTypeNameHelper(Info.sFunctionTypeInfo.RetTypeIndex, Obj, VarName, TypeName)) return FALSE; // Print calling convention //TypeName += " "; - //TypeName += SymInfoDump_CallConvStr(Info.Info.sFunctionTypeInfo.CallConv); + //TypeName += SymbolInfo_CallConvStr(Info.Info.sFunctionTypeInfo.CallConv); //TypeName += " "; // If member function, save the class type index @@ -1415,7 +1414,7 @@ BOOLEAN SymInfoDump_GetTypeNameHelper( /* // It is not needed to print the class name here, because // it is contained in the function name - if( !SymInfoDump_GetTypeNameHelper( Info.Info.sFunctionTypeInfo.ClassIndex, Obj, VarName, TypeName ) ) + if( !SymbolInfo_GetTypeNameHelper( Info.Info.sFunctionTypeInfo.ClassIndex, Obj, VarName, TypeName ) ) return false; TypeName += "::"); @@ -1428,7 +1427,7 @@ BOOLEAN SymInfoDump_GetTypeNameHelper( //TypeName += " ("; for (ULONG i = 0; i < Info.sFunctionTypeInfo.NumArgs; i++) { - if (!SymInfoDump_GetTypeNameHelper(Info.sFunctionTypeInfo.Args[i], Obj, VarName, TypeName)) + if (!SymbolInfo_GetTypeNameHelper(Info.sFunctionTypeInfo.Args[i], Obj, VarName, TypeName)) return FALSE; //if (i < (Info.sFunctionTypeInfo.NumArgs - 1)) @@ -1452,7 +1451,7 @@ BOOLEAN SymInfoDump_GetTypeNameHelper( case SymTagFunctionArgType: { - if (!SymInfoDump_GetTypeNameHelper(Info.sFunctionArgTypeInfo.TypeIndex, Obj, VarName, TypeName)) + if (!SymbolInfo_GetTypeNameHelper(Info.sFunctionArgTypeInfo.TypeIndex, Obj, VarName, TypeName)) return FALSE; } break; @@ -1460,7 +1459,7 @@ BOOLEAN SymInfoDump_GetTypeNameHelper( case SymTagArrayType: { // Print element type name - if (!SymInfoDump_GetTypeNameHelper(Info.sArrayTypeInfo.ElementTypeIndex, Obj, VarName, TypeName)) + if (!SymbolInfo_GetTypeNameHelper(Info.sArrayTypeInfo.ElementTypeIndex, Obj, VarName, TypeName)) return FALSE; //TypeName += " "; @@ -1497,7 +1496,7 @@ BOOLEAN SymInfoDump_GetTypeNameHelper( return TRUE; } -BOOLEAN SymInfoDump_GetTypeName( +BOOLEAN SymbolInfo_GetTypeName( _Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, _In_ PWSTR pVarName, @@ -1515,7 +1514,7 @@ BOOLEAN SymInfoDump_GetTypeName( VarName = pVarName; // Obtain the type name - if (!SymInfoDump_GetTypeNameHelper(Index, Context, &VarName, &TypeName)) + if (!SymbolInfo_GetTypeNameHelper(Index, Context, &VarName, &TypeName)) return FALSE; if (!wcslen(TypeName)) @@ -1529,7 +1528,7 @@ BOOLEAN SymInfoDump_GetTypeName( /////////////////////////////////////////////////////////////////////////////// // Data-to-string conversion functions -PWSTR SymInfoDump_TagStr( +PWSTR SymbolInfo_TagStr( _In_ enum SymTagEnum Tag ) { @@ -1603,7 +1602,7 @@ PWSTR SymInfoDump_TagStr( } -PWSTR SymInfoDump_BaseTypeStr( +PWSTR SymbolInfo_BaseTypeStr( _In_ BasicType Type, _In_ ULONG64 Length ) @@ -1694,7 +1693,7 @@ PWSTR SymInfoDump_BaseTypeStr( } -PWSTR SymInfoDump_CallConvStr( +PWSTR SymbolInfo_CallConvStr( _In_ CV_call_e CallConv ) { @@ -1752,7 +1751,7 @@ PWSTR SymInfoDump_CallConvStr( } -PWSTR SymInfoDump_DataKindFromSymbolInfo( +PWSTR SymbolInfo_DataKindFromSymbolInfo( _In_ PSYMBOL_INFOW SymbolInfo ) { @@ -1761,10 +1760,10 @@ PWSTR SymInfoDump_DataKindFromSymbolInfo( if (!SymGetTypeInfo_I(NtCurrentProcess(), SymbolInfo->ModBase, SymbolInfo->Index, TI_GET_DATAKIND, &dataKindType)) return L"UNKNOWN"; - return SymInfoDump_DataKindStr(dataKindType); + return SymbolInfo_DataKindStr(dataKindType); } -PWSTR SymInfoDump_DataKindStr( +PWSTR SymbolInfo_DataKindStr( _In_ DataKind SymDataKind ) { @@ -1793,14 +1792,14 @@ PWSTR SymInfoDump_DataKindStr( return L"UNKNOWN"; } -VOID SymInfoDump_SymbolLocationStr( +VOID SymbolInfo_SymbolLocationStr( _In_ PSYMBOL_INFOW SymbolInfo, _In_ PWSTR Buffer ) { if (SymbolInfo->Flags & SYMFLAG_REGISTER) { - PWSTR regString = SymInfoDump_RegisterStr((CV_HREG_e)SymbolInfo->Register); + PWSTR regString = SymbolInfo_RegisterStr(SymbolInfo->Register); if (regString) wcscpy(Buffer, regString); @@ -1812,7 +1811,7 @@ VOID SymInfoDump_SymbolLocationStr( else if (SymbolInfo->Flags & SYMFLAG_REGREL) { WCHAR szReg[32]; - PWSTR regString = SymInfoDump_RegisterStr((CV_HREG_e)SymbolInfo->Register); + PWSTR regString = SymbolInfo_RegisterStr(SymbolInfo->Register); if (regString) wcscpy(szReg, regString); @@ -1830,12 +1829,11 @@ VOID SymInfoDump_SymbolLocationStr( } else { - //_swprintf(Buffer, L"%16I64x", SymbolInfo->Address); PhPrintPointer(Buffer, PTR_SUB_OFFSET(SymbolInfo->Address, SymbolInfo->ModBase)); } } -PWSTR SymInfoDump_RegisterStr( +PWSTR SymbolInfo_RegisterStr( _In_ CV_HREG_e RegCode ) { @@ -1862,7 +1860,7 @@ PWSTR SymInfoDump_RegisterStr( return L"Unknown"; } -PWSTR SymInfoDump_UdtKindStr( +PWSTR SymbolInfo_UdtKindStr( _In_ UdtKind KindType ) { @@ -1879,7 +1877,7 @@ PWSTR SymInfoDump_UdtKindStr( return L"UNKNOWN"; } -PWSTR SymInfoDump_LocationTypeStr( +PWSTR SymbolInfo_LocationTypeStr( _In_ LocationType LocType ) { @@ -1952,11 +1950,11 @@ VOID PrintDataInfo( return; // Type - symDataKind = SymInfoDump_DataKindFromSymbolInfo(SymbolInfo); + symDataKind = SymbolInfo_DataKindFromSymbolInfo(SymbolInfo); lvItemIndex = PhAddListViewItem(Context->ListviewHandle, MAXINT, symDataKind, NULL); // Address - SymInfoDump_SymbolLocationStr(SymbolInfo, pointer); + SymbolInfo_SymbolLocationStr(SymbolInfo, pointer); PhSetListViewSubItem(Context->ListviewHandle, lvItemIndex, 1, pointer); // Name @@ -1966,7 +1964,7 @@ VOID PrintDataInfo( PhSetListViewSubItem(Context->ListviewHandle, lvItemIndex, 3, PhaFormatString(L"%lu", SymbolInfo->Size)->Buffer); // Data - //if (SymInfoDump_GetTypeName(Context, SymbolInfo->TypeIndex, SymbolInfo->Name, szTypeName, cMaxTypeNameLen)) + //if (SymbolInfo_GetTypeName(Context, SymbolInfo->TypeIndex, SymbolInfo->Name, szTypeName, cMaxTypeNameLen)) // PhSetListViewSubItem(Context->ListviewHandle, lvItemIndex, 4, szTypeName); // Flags: %x, SymbolInfo->Flags @@ -1988,7 +1986,7 @@ VOID PrintFunctionInfo( lvItemIndex = PhAddListViewItem(Context->ListviewHandle, MAXINT, L"FUNCTION", NULL); // Address - SymInfoDump_SymbolLocationStr(SymbolInfo, pointer); + SymbolInfo_SymbolLocationStr(SymbolInfo, pointer); PhSetListViewSubItem(Context->ListviewHandle, lvItemIndex, 1, pointer); // Name @@ -1998,7 +1996,7 @@ VOID PrintFunctionInfo( PhSetListViewSubItem(Context->ListviewHandle, lvItemIndex, 3, PhaFormatString(L"%lu", SymbolInfo->Size)->Buffer); // Data - //if (SymInfoDump_GetTypeName(Context, SymbolInfo->TypeIndex, SymbolInfo->Name, szTypeName, cMaxTypeNameLen)) + //if (SymbolInfo_GetTypeName(Context, SymbolInfo->TypeIndex, SymbolInfo->Name, szTypeName, cMaxTypeNameLen)) // PhSetListViewSubItem(Context->ListviewHandle, lvItemIndex, 4, szTypeName); // Flags: %x, SymbolInfo->Flags @@ -2007,8 +2005,8 @@ VOID PrintFunctionInfo( // Enumerate function parameters and local variables... //IMAGEHLP_STACK_FRAME sf; //sf.InstructionOffset = SymbolInfo->Address; - //SymSetContext(NtCurrentProcess(), &sf, 0); - //SymEnumSymbolsW(NtCurrentProcess(), 0, NULL, EnumCallbackProc, pTypeInfo); + //SymSetContext_I(NtCurrentProcess(), &sf, 0); + //SymEnumSymbolsW_I(NtCurrentProcess(), 0, NULL, EnumCallbackProc, Context); } VOID PrintDefaultInfo( @@ -2026,7 +2024,7 @@ VOID PrintDefaultInfo( lvItemIndex = PhAddListViewItem(Context->ListviewHandle, MAXINT, L"SYMBOL", NULL); // Address - SymInfoDump_SymbolLocationStr(SymbolInfo, pointer); + SymbolInfo_SymbolLocationStr(SymbolInfo, pointer); PhSetListViewSubItem(Context->ListviewHandle, lvItemIndex, 1, pointer); // Name @@ -2036,7 +2034,7 @@ VOID PrintDefaultInfo( PhSetListViewSubItem(Context->ListviewHandle, lvItemIndex, 3, PhaFormatString(L"%lu", SymbolInfo->Size)->Buffer); // Data - //if (SymInfoDump_GetTypeName(Context, SymbolInfo->TypeIndex, SymbolInfo->Name, szTypeName, cMaxTypeNameLen)) + //if (SymbolInfo_GetTypeName(Context, SymbolInfo->TypeIndex, SymbolInfo->Name, szTypeName, cMaxTypeNameLen)) // PhSetListViewSubItem(Context->ListviewHandle, lvItemIndex, 4, szTypeName); // Flags: %x, SymbolInfo->Flags @@ -2050,7 +2048,7 @@ VOID PrintClassInfo( ) { // UDT kind - //OutputDebugString(PhaFormatString(L"%s", SymInfoDump_UdtKindStr(Info->UDTKind))->Buffer); + //OutputDebugString(PhaFormatString(L"%s", SymbolInfo_UdtKindStr(Info->UDTKind))->Buffer); // Name //OutputDebugString(PhaFormatString(L" %s \n", Info->Name)->Buffer); // Size @@ -2072,9 +2070,9 @@ VOID PrintClassInfo( { TypeInfo VarInfo; - if (!SymInfoDump_DumpType(Context, Info->Variables[i], &VarInfo)) + if (!SymbolInfo_DumpType(Context, Info->Variables[i], &VarInfo)) { - //_ASSERTE(!_T("SymInfoDump::DumpType() failed.")); + //_ASSERTE(!_T("SymbolInfo::DumpType() failed.")); // Continue with the next variable } else if (VarInfo.Tag != SymTagData) @@ -2095,7 +2093,7 @@ VOID PrintClassInfo( //#define cMaxTypeNameLen 1024 //TCHAR szTypeName[cMaxTypeNameLen + 1] = _T(""); - //if (SymInfoDump_GetTypeName(VarInfo.Info.sDataInfo.TypeIndex, W2T(VarInfo.Info.sDataInfo.Name), szTypeName, cMaxTypeNameLen)) + //if (SymbolInfo_GetTypeName(VarInfo.Info.sDataInfo.TypeIndex, W2T(VarInfo.Info.sDataInfo.Name), szTypeName, cMaxTypeNameLen)) //_tprintf(szTypeName); //else //_tprintf(_T("n/a")); @@ -2141,9 +2139,9 @@ VOID PrintClassInfo( { TypeInfo baseInfo; - if (!SymInfoDump_DumpType(Context, Info->BaseClasses[i], &baseInfo)) + if (!SymbolInfo_DumpType(Context, Info->BaseClasses[i], &baseInfo)) { - //_ASSERTE(!_T("SymInfoDump::DumpType() failed.")); + //_ASSERTE(!_T("SymbolInfo::DumpType() failed.")); // Continue with the next base class } else if (baseInfo.Tag != SymTagBaseClass) @@ -2156,9 +2154,9 @@ VOID PrintClassInfo( // Obtain the name of the base class TypeInfo BaseUdtInfo; - if (!SymInfoDump_DumpType(Context, baseInfo.sBaseClassInfo.TypeIndex, &BaseUdtInfo)) + if (!SymbolInfo_DumpType(Context, baseInfo.sBaseClassInfo.TypeIndex, &BaseUdtInfo)) { - //_ASSERTE(!_T("SymInfoDump::DumpType() failed.")); + //_ASSERTE(!_T("SymbolInfo::DumpType() failed.")); // Continue with the next base class } else if (BaseUdtInfo.Tag != SymTagUDT) @@ -2194,7 +2192,7 @@ VOID PrintUserDefinedTypes( { index = PtrToUlong(Context->UdtList->Items[i]); - if (SymInfoDump_DumpType(Context, index, &info)) + if (SymbolInfo_DumpType(Context, index, &info)) { if (info.Tag == SymTagUDT) { @@ -2208,9 +2206,9 @@ VOID PrintUserDefinedTypes( { TypeInfo baseInfo; - if (!SymInfoDump_DumpType(Context, info.sUdtClassInfo.BaseClasses[i], &baseInfo)) + if (!SymbolInfo_DumpType(Context, info.sUdtClassInfo.BaseClasses[i], &baseInfo)) { - //_ASSERTE(!_T("SymInfoDump::DumpType() failed.")); + //_ASSERTE(!_T("SymbolInfo::DumpType() failed.")); // Continue with the next base class } else if (baseInfo.Tag != SymTagBaseClass) @@ -2223,9 +2221,9 @@ VOID PrintUserDefinedTypes( // Obtain information about the base class TypeInfo baseUdtInfo; - if (!SymInfoDump_DumpType(Context, baseInfo.sBaseClassInfo.TypeIndex, &baseUdtInfo)) + if (!SymbolInfo_DumpType(Context, baseInfo.sBaseClassInfo.TypeIndex, &baseUdtInfo)) { - //_ASSERTE(!_T("SymInfoDump::DumpType() failed.")); + //_ASSERTE(!_T("SymbolInfo::DumpType() failed.")); // Continue with the next base class } else if (baseUdtInfo.Tag != SymTagUDT) @@ -2443,7 +2441,6 @@ VOID ShowSymbolInfo( //OutputDebugString(PhaFormatString(L"Public symbols: %s\n", info.Publics ? L"Available" : L"Not available")->Buffer); } - VOID PeDumpFileSymbols( _In_ HWND ListViewHandle, _In_ PWSTR FileName @@ -2451,12 +2448,12 @@ VOID PeDumpFileSymbols( { HMODULE dbghelpHandle; HMODULE symsrvHandle; - ULONG64 symbolBaseAddress = 0; + ULONG64 symbolBaseAddress; ULONG64 baseAddress = 0; ULONG fileLength = 0; PdbLoadDbgHelpFromPath(L"C:\\Program Files (x86)\\Windows Kits\\10\\Debuggers\\x64\\dbghelp.dll"); - + if (!(dbghelpHandle = GetModuleHandle(L"dbghelp.dll"))) return; @@ -2470,8 +2467,9 @@ VOID PeDumpFileSymbols( SymLoadModuleExW_I = PhGetProcedureAddress(dbghelpHandle, "SymLoadModuleExW", 0); SymGetModuleInfoW64_I = PhGetProcedureAddress(dbghelpHandle, "SymGetModuleInfoW64", 0); SymGetTypeInfo_I = PhGetProcedureAddress(dbghelpHandle, "SymGetTypeInfo", 0); + SymSetContext_I = PhGetProcedureAddress(dbghelpHandle, "SymSetContext", 0); - SymSetOptions_I(SymGetOptions_I() | SYMOPT_DEBUG | SYMOPT_UNDNAME); // SYMOPT_DEFERRED_LOADS | SYMOPT_FAVOR_COMPRESSED + SymSetOptions_I(SymGetOptions_I() | SYMOPT_DEBUG | SYMOPT_UNDNAME | SYMOPT_ALLOW_ZERO_ADDRESS); // SYMOPT_DEFERRED_LOADS | SYMOPT_FAVOR_COMPRESSED if (!SymInitialize_I(NtCurrentProcess(), NULL, FALSE)) return; @@ -2498,7 +2496,7 @@ VOID PeDumpFileSymbols( context.BaseAddress = symbolBaseAddress; context.UdtList = PhCreateList(0x100); - ShowSymbolInfo(symbolBaseAddress); + //ShowSymbolInfo(symbolBaseAddress); SymEnumSymbolsW_I(NtCurrentProcess(), symbolBaseAddress, NULL, EnumCallbackProc, &context); @@ -2560,7 +2558,7 @@ INT_PTR CALLBACK PvpSymbolsDlgProc( HWND lvHandle; lvHandle = GetDlgItem(hwndDlg, IDC_LIST); - PhSetListViewStyle(lvHandle, FALSE, TRUE); + PhSetListViewStyle(lvHandle, TRUE, TRUE); PhSetControlTheme(lvHandle, L"explorer"); PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 40, L"Type"); PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_RIGHT, 80, L"VA"); diff --git a/tools/peview/peprp.c b/tools/peview/peprp.c index 36db629c6fb6..73ee2331031a 100644 --- a/tools/peview/peprp.c +++ b/tools/peview/peprp.c @@ -23,57 +23,19 @@ #include #include -#include #include #include #include -#include #include -#include - -BOOLEAN PvpLoadDbgHelp( - _Inout_ PPH_SYMBOL_PROVIDER *SymbolProvider - ); #define PVM_CHECKSUM_DONE (WM_APP + 1) #define PVM_VERIFY_DONE (WM_APP + 2) -INT_PTR CALLBACK PvpPeGeneralDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -INT_PTR CALLBACK PvpPeImportsDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -INT_PTR CALLBACK PvpPeExportsDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -INT_PTR CALLBACK PvpPeLoadConfigDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -INT_PTR CALLBACK PvpPeClrDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam +BOOLEAN PvpLoadDbgHelp( + _Inout_ PPH_SYMBOL_PROVIDER *SymbolProvider ); -INT_PTR CALLBACK PvpPeCgfDlgProc( +INT_PTR CALLBACK PvpPeGeneralDlgProc( _In_ HWND hwndDlg, _In_ UINT uMsg, _In_ WPARAM wParam, @@ -81,13 +43,12 @@ INT_PTR CALLBACK PvpPeCgfDlgProc( ); PH_MAPPED_IMAGE PvMappedImage; -PIMAGE_COR20_HEADER PvImageCor20Header; -PPH_SYMBOL_PROVIDER symbolProvider; - -HICON PvImageLargeIcon; -PH_IMAGE_VERSION_INFO PvImageVersionInfo; -VERIFY_RESULT PvImageVerifyResult; -PPH_STRING PvImageSignerName; +PIMAGE_COR20_HEADER PvImageCor20Header = NULL; +PPH_SYMBOL_PROVIDER PvSymbolProvider = NULL; +static HICON PvImageLargeIcon; +static PH_IMAGE_VERSION_INFO PvImageVersionInfo; +static VERIFY_RESULT PvImageVerifyResult; +static PPH_STRING PvImageSignerName; VOID PvPeProperties( VOID @@ -110,9 +71,17 @@ VOID PvPeProperties( return; } - // Failing to load dbghelp is not critical : it just won't be possible - // to look up symbol names. No need to check the returned value. - PvpLoadDbgHelp(&symbolProvider); + if (PvpLoadDbgHelp(&PvSymbolProvider)) + { + // Load current PE pdb + // TODO: Move into seperate thread. + PhLoadModuleSymbolProvider( + PvSymbolProvider, + PvFileName->Buffer, + (ULONG64)PvMappedImage.NtHeaders->OptionalHeader.ImageBase, + PvMappedImage.NtHeaders->OptionalHeader.SizeOfImage + ); + } if (propContext = PvCreatePropContext(PvFileName)) { @@ -204,7 +173,7 @@ VOID PvPeProperties( PvAddPropPage(propContext, newPage); } - // PDB page + // Symbols page { newPage = PvCreatePropPageContext( MAKEINTRESOURCE(IDD_PESYMBOLS), @@ -691,420 +660,6 @@ INT_PTR CALLBACK PvpPeGeneralDlgProc( return FALSE; } -VOID PvpProcessImports( - _In_ HWND ListViewHandle, - _In_ PPH_MAPPED_IMAGE_IMPORTS Imports, - _In_ BOOLEAN DelayImports, - _Inout_ ULONG *Count - ) -{ - PH_MAPPED_IMAGE_IMPORT_DLL importDll; - PH_MAPPED_IMAGE_IMPORT_ENTRY importEntry; - ULONG i; - ULONG j; - - for (i = 0; i < Imports->NumberOfDlls; i++) - { - if (NT_SUCCESS(PhGetMappedImageImportDll(Imports, i, &importDll))) - { - for (j = 0; j < importDll.NumberOfEntries; j++) - { - if (NT_SUCCESS(PhGetMappedImageImportEntry(&importDll, j, &importEntry))) - { - INT lvItemIndex; - PPH_STRING name; - WCHAR number[PH_INT32_STR_LEN_1]; - - if (DelayImports) - name = PhFormatString(L"%S (Delay)", importDll.Name); - else - name = PhZeroExtendToUtf16(importDll.Name); - - PhPrintUInt64(number, ++(*Count)); // HACK - lvItemIndex = PhAddListViewItem(ListViewHandle, MAXINT, number, NULL); - - PhSetListViewSubItem(ListViewHandle, lvItemIndex, 1, name->Buffer); - PhDereferenceObject(name); - - if (importEntry.Name) - { - PPH_STRING importName = NULL; - - if (importEntry.Name[0] == '?') - importName = PhUndecorateName(symbolProvider->ProcessHandle, importEntry.Name); - else - importName = PhZeroExtendToUtf16(importEntry.Name); - - if (!importName) - importName = PhZeroExtendToUtf16(importEntry.Name); - - PhSetListViewSubItem(ListViewHandle, lvItemIndex, 2, importName->Buffer); - PhDereferenceObject(importName); - - PhPrintUInt32(number, importEntry.NameHint); - PhSetListViewSubItem(ListViewHandle, lvItemIndex, 3, number); - } - else - { - name = PhFormatString(L"(Ordinal %u)", importEntry.Ordinal); - PhSetListViewSubItem(ListViewHandle, lvItemIndex, 2, name->Buffer); - PhDereferenceObject(name); - } - } - } - } - } -} - -INT_PTR CALLBACK PvpPeImportsDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - LPPROPSHEETPAGE propSheetPage; - PPV_PROPPAGECONTEXT propPageContext; - - if (!PvPropPageDlgProcHeader(hwndDlg, uMsg, lParam, &propSheetPage, &propPageContext)) - return FALSE; - - switch (uMsg) - { - case WM_INITDIALOG: - { - ULONG count = 0; - ULONG fallbackColumns[] = { 0, 1, 2 }; - HWND lvHandle; - PH_MAPPED_IMAGE_IMPORTS imports; - - lvHandle = GetDlgItem(hwndDlg, IDC_LIST); - PhSetListViewStyle(lvHandle, TRUE, TRUE); - PhSetControlTheme(lvHandle, L"explorer"); - PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 40, L"#"); - PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 130, L"DLL"); - PhAddListViewColumn(lvHandle, 2, 2, 2, LVCFMT_LEFT, 210, L"Name"); - PhAddListViewColumn(lvHandle, 3, 3, 3, LVCFMT_LEFT, 50, L"Hint"); - PhSetExtendedListView(lvHandle); - ExtendedListView_AddFallbackColumns(lvHandle, 3, fallbackColumns); - PhLoadListViewColumnsFromSetting(L"ImageImportsListViewColumns", lvHandle); - - if (NT_SUCCESS(PhGetMappedImageImports(&imports, &PvMappedImage))) - { - PvpProcessImports(lvHandle, &imports, FALSE, &count); - } - - if (NT_SUCCESS(PhGetMappedImageDelayImports(&imports, &PvMappedImage))) - { - PvpProcessImports(lvHandle, &imports, TRUE, &count); - } - - ExtendedListView_SortItems(lvHandle); - - EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); - } - break; - case WM_DESTROY: - { - PhSaveListViewColumnsToSetting(L"ImageImportsListViewColumns", GetDlgItem(hwndDlg, IDC_LIST)); - } - break; - case WM_SHOWWINDOW: - { - if (!propPageContext->LayoutInitialized) - { - PPH_LAYOUT_ITEM dialogItem; - - dialogItem = PvAddPropPageLayoutItem(hwndDlg, hwndDlg, - PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL); - PvAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_LIST), - dialogItem, PH_ANCHOR_ALL); - - PvDoPropPageLayout(hwndDlg); - - propPageContext->LayoutInitialized = TRUE; - } - } - break; - case WM_NOTIFY: - { - PvHandleListViewNotifyForCopy(lParam, GetDlgItem(hwndDlg, IDC_LIST)); - } - break; - } - - return FALSE; -} - -INT_PTR CALLBACK PvpPeExportsDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - LPPROPSHEETPAGE propSheetPage; - PPV_PROPPAGECONTEXT propPageContext; - - if (!PvPropPageDlgProcHeader(hwndDlg, uMsg, lParam, &propSheetPage, &propPageContext)) - return FALSE; - - switch (uMsg) - { - case WM_INITDIALOG: - { - HWND lvHandle; - PH_MAPPED_IMAGE_EXPORTS exports; - PH_MAPPED_IMAGE_EXPORT_ENTRY exportEntry; - PH_MAPPED_IMAGE_EXPORT_FUNCTION exportFunction; - ULONG i; - - lvHandle = GetDlgItem(hwndDlg, IDC_LIST); - PhSetListViewStyle(lvHandle, TRUE, TRUE); - PhSetControlTheme(lvHandle, L"explorer"); - PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 40, L"#"); - PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_RIGHT, 80, L"RVA"); - PhAddListViewColumn(lvHandle, 2, 2, 2, LVCFMT_LEFT, 250, L"Name"); - PhAddListViewColumn(lvHandle, 3, 3, 3, LVCFMT_LEFT, 50, L"Ordinal"); - PhSetExtendedListView(lvHandle); - PhLoadListViewColumnsFromSetting(L"ImageExportsListViewColumns", lvHandle); - - if (NT_SUCCESS(PhGetMappedImageExports(&exports, &PvMappedImage))) - { - for (i = 0; i < exports.NumberOfEntries; i++) - { - if ( - NT_SUCCESS(PhGetMappedImageExportEntry(&exports, i, &exportEntry)) && - NT_SUCCESS(PhGetMappedImageExportFunction(&exports, NULL, exportEntry.Ordinal, &exportFunction)) - ) - { - INT lvItemIndex; - WCHAR number[PH_INT32_STR_LEN_1]; - WCHAR pointer[PH_PTR_STR_LEN_1]; - - PhPrintUInt64(number, i + 1); - lvItemIndex = PhAddListViewItem(lvHandle, MAXINT, number, NULL); - - if (exportFunction.ForwardedName) - { - PPH_STRING forwardName = NULL; - - if (exportFunction.ForwardedName[0] == '?') - forwardName = PhUndecorateName(symbolProvider->ProcessHandle, exportFunction.ForwardedName); - else - forwardName = PhZeroExtendToUtf16(exportFunction.ForwardedName); - - if (!forwardName) - forwardName = PhZeroExtendToUtf16(exportFunction.ForwardedName); - - PhSetListViewSubItem(lvHandle, lvItemIndex, 1, forwardName->Buffer); - PhDereferenceObject(forwardName); - } - else - { - PhPrintPointer(pointer, exportFunction.Function); - PhSetListViewSubItem(lvHandle, lvItemIndex, 1, pointer); - } - - if (exportEntry.Name) - { - PPH_STRING exportName = NULL; - - if (exportEntry.Name[0] == '?') - exportName = PhUndecorateName(symbolProvider->ProcessHandle, exportEntry.Name); - else - exportName = PhZeroExtendToUtf16(exportEntry.Name); - - if (!exportName) - exportName = PhZeroExtendToUtf16(exportEntry.Name); - - PhSetListViewSubItem(lvHandle, lvItemIndex, 2, exportName->Buffer); - PhDereferenceObject(exportName); - } - else - { - PhSetListViewSubItem(lvHandle, lvItemIndex, 2, L"(unnamed)"); - } - - PhPrintUInt32(number, exportEntry.Ordinal); - PhSetListViewSubItem(lvHandle, lvItemIndex, 3, number); - } - } - } - - ExtendedListView_SortItems(lvHandle); - - EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); - } - break; - case WM_DESTROY: - { - PhSaveListViewColumnsToSetting(L"ImageExportsListViewColumns", GetDlgItem(hwndDlg, IDC_LIST)); - } - break; - case WM_SHOWWINDOW: - { - if (!propPageContext->LayoutInitialized) - { - PPH_LAYOUT_ITEM dialogItem; - - dialogItem = PvAddPropPageLayoutItem(hwndDlg, hwndDlg, - PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL); - PvAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_LIST), - dialogItem, PH_ANCHOR_ALL); - - PvDoPropPageLayout(hwndDlg); - - propPageContext->LayoutInitialized = TRUE; - } - } - break; - case WM_NOTIFY: - { - PvHandleListViewNotifyForCopy(lParam, GetDlgItem(hwndDlg, IDC_LIST)); - } - break; - } - - return FALSE; -} - -INT_PTR CALLBACK PvpPeLoadConfigDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - LPPROPSHEETPAGE propSheetPage; - PPV_PROPPAGECONTEXT propPageContext; - - if (!PvPropPageDlgProcHeader(hwndDlg, uMsg, lParam, &propSheetPage, &propPageContext)) - return FALSE; - - switch (uMsg) - { - case WM_INITDIALOG: - { - HWND lvHandle; - PIMAGE_LOAD_CONFIG_DIRECTORY32 config32; - PIMAGE_LOAD_CONFIG_DIRECTORY64 config64; - - lvHandle = GetDlgItem(hwndDlg, IDC_LIST); - PhSetListViewStyle(lvHandle, TRUE, TRUE); - PhSetControlTheme(lvHandle, L"explorer"); - PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 220, L"Name"); - PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 170, L"Value"); - PhSetExtendedListView(lvHandle); - PhLoadListViewColumnsFromSetting(L"ImageLoadCfgListViewColumns", lvHandle); - - #define ADD_VALUE(Name, Value) \ - { \ - INT lvItemIndex; \ - lvItemIndex = PhAddListViewItem(lvHandle, MAXINT, Name, NULL); \ - PhSetListViewSubItem(lvHandle, lvItemIndex, 1, Value); \ - } - - #define ADD_VALUES(Type, Config) \ - { \ - LARGE_INTEGER time; \ - SYSTEMTIME systemTime; \ - \ - RtlSecondsSince1970ToTime((Config)->TimeDateStamp, &time); \ - PhLargeIntegerToLocalSystemTime(&systemTime, &time); \ - \ - ADD_VALUE(L"Time stamp", PhaFormatDateTime(&systemTime)->Buffer); \ - ADD_VALUE(L"Version", PhaFormatString(L"%u.%u", (Config)->MajorVersion, (Config)->MinorVersion)->Buffer); \ - ADD_VALUE(L"Global flags to clear", PhaFormatString(L"0x%x", (Config)->GlobalFlagsClear)->Buffer); \ - ADD_VALUE(L"Global flags to set", PhaFormatString(L"0x%x", (Config)->GlobalFlagsSet)->Buffer); \ - ADD_VALUE(L"Critical section default timeout", PhaFormatUInt64((Config)->CriticalSectionDefaultTimeout, TRUE)->Buffer); \ - ADD_VALUE(L"De-commit free block threshold", PhaFormatUInt64((Config)->DeCommitFreeBlockThreshold, TRUE)->Buffer); \ - ADD_VALUE(L"De-commit total free threshold", PhaFormatUInt64((Config)->DeCommitTotalFreeThreshold, TRUE)->Buffer); \ - ADD_VALUE(L"LOCK prefix table", PhaFormatString(L"0x%Ix", (Config)->LockPrefixTable)->Buffer); \ - ADD_VALUE(L"Maximum allocation size", PhaFormatString(L"0x%Ix", (Config)->MaximumAllocationSize)->Buffer); \ - ADD_VALUE(L"Virtual memory threshold", PhaFormatString(L"0x%Ix", (Config)->VirtualMemoryThreshold)->Buffer); \ - ADD_VALUE(L"Process affinity mask", PhaFormatString(L"0x%Ix", (Config)->ProcessAffinityMask)->Buffer); \ - ADD_VALUE(L"Process heap flags", PhaFormatString(L"0x%Ix", (Config)->ProcessHeapFlags)->Buffer); \ - ADD_VALUE(L"CSD version", PhaFormatString(L"%u", (Config)->CSDVersion)->Buffer); \ - ADD_VALUE(L"Edit list", PhaFormatString(L"0x%Ix", (Config)->EditList)->Buffer); \ - ADD_VALUE(L"Security cookie", PhaFormatString(L"0x%Ix", (Config)->SecurityCookie)->Buffer); \ - ADD_VALUE(L"SEH handler table", PhaFormatString(L"0x%Ix", (Config)->SEHandlerTable)->Buffer); \ - ADD_VALUE(L"SEH handler count", PhaFormatUInt64((Config)->SEHandlerCount, TRUE)->Buffer); \ - \ - if ((Config)->Size >= (ULONG)FIELD_OFFSET(Type, GuardAddressTakenIatEntryTable)) \ - { \ - ADD_VALUE(L"CFG GuardFlags", PhaFormatString(L"0x%Ix", (Config)->GuardFlags)->Buffer); \ - ADD_VALUE(L"CFG Check Function pointer", PhaFormatString(L"0x%Ix", (Config)->GuardCFCheckFunctionPointer)->Buffer); \ - ADD_VALUE(L"CFG Check Dispatch pointer", PhaFormatString(L"0x%Ix", (Config)->GuardCFDispatchFunctionPointer)->Buffer); \ - ADD_VALUE(L"CFG Function table", PhaFormatString(L"0x%Ix", (Config)->GuardCFFunctionTable)->Buffer); \ - ADD_VALUE(L"CFG Function table entry count", PhaFormatUInt64((Config)->GuardCFFunctionCount, TRUE)->Buffer); \ - if ((Config)->Size >= (ULONG)FIELD_OFFSET(Type, GuardAddressTakenIatEntryTable) \ - + sizeof((Config)->GuardAddressTakenIatEntryTable) \ - + sizeof((Config)->GuardAddressTakenIatEntryCount)) \ - { \ - ADD_VALUE(L"CFG IatEntry table", PhaFormatString(L"0x%Ix", (Config)->GuardAddressTakenIatEntryTable)->Buffer); \ - ADD_VALUE(L"CFG IatEntry table entry count", PhaFormatUInt64((Config)->GuardAddressTakenIatEntryCount, TRUE)->Buffer); \ - } \ - if ((Config)->Size >= (ULONG)FIELD_OFFSET(Type, GuardLongJumpTargetTable) \ - + sizeof((Config)->GuardLongJumpTargetTable) \ - + sizeof((Config)->GuardLongJumpTargetCount))\ - { \ - ADD_VALUE(L"CFG LongJump table", PhaFormatString(L"0x%Ix", (Config)->GuardLongJumpTargetTable)->Buffer); \ - ADD_VALUE(L"CFG LongJump table entry count", PhaFormatUInt64((Config)->GuardLongJumpTargetCount, TRUE)->Buffer); \ - } \ - } \ - } - - if (PvMappedImage.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) - { - if (NT_SUCCESS(PhGetMappedImageLoadConfig32(&PvMappedImage, &config32))) - { - ADD_VALUES(IMAGE_LOAD_CONFIG_DIRECTORY32, config32); - } - } - else - { - if (NT_SUCCESS(PhGetMappedImageLoadConfig64(&PvMappedImage, &config64))) - { - ADD_VALUES(IMAGE_LOAD_CONFIG_DIRECTORY64, config64); - } - } - - EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); - } - break; - case WM_DESTROY: - { - PhSaveListViewColumnsToSetting(L"ImageLoadCfgListViewColumns", GetDlgItem(hwndDlg, IDC_LIST)); - } - break; - case WM_SHOWWINDOW: - { - if (!propPageContext->LayoutInitialized) - { - PPH_LAYOUT_ITEM dialogItem; - - dialogItem = PvAddPropPageLayoutItem(hwndDlg, hwndDlg, - PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL); - PvAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_LIST), - dialogItem, PH_ANCHOR_ALL); - - PvDoPropPageLayout(hwndDlg); - - propPageContext->LayoutInitialized = TRUE; - } - } - break; - case WM_NOTIFY: - { - PvHandleListViewNotifyForCopy(lParam, GetDlgItem(hwndDlg, IDC_LIST)); - } - break; - } - - return FALSE; -} - VOID PvpLoadDbgHelpFromPath( _In_ PWSTR DbgHelpPath ) @@ -1183,293 +738,4 @@ BOOLEAN PvpLoadDbgHelp( *SymbolProvider = symbolProvider; return TRUE; -} - -INT_PTR CALLBACK PvpPeClrDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - LPPROPSHEETPAGE propSheetPage; - PPV_PROPPAGECONTEXT propPageContext; - - if (!PvPropPageDlgProcHeader(hwndDlg, uMsg, lParam, &propSheetPage, &propPageContext)) - return FALSE; - - switch (uMsg) - { - case WM_INITDIALOG: - { - PH_STRING_BUILDER stringBuilder; - PPH_STRING string; - PVOID metaData; - ULONG versionStringLength; - - string = PhaFormatString(L"%u.%u", PvImageCor20Header->MajorRuntimeVersion, - PvImageCor20Header->MinorRuntimeVersion); - SetDlgItemText(hwndDlg, IDC_RUNTIMEVERSION, string->Buffer); - - PhInitializeStringBuilder(&stringBuilder, 256); - - if (PvImageCor20Header->Flags & COMIMAGE_FLAGS_ILONLY) - PhAppendStringBuilder2(&stringBuilder, L"IL only, "); - if (PvImageCor20Header->Flags & COMIMAGE_FLAGS_32BITREQUIRED) - PhAppendStringBuilder2(&stringBuilder, L"32-bit only, "); - if (PvImageCor20Header->Flags & COMIMAGE_FLAGS_32BITPREFERRED) - PhAppendStringBuilder2(&stringBuilder, L"32-bit preferred, "); - if (PvImageCor20Header->Flags & COMIMAGE_FLAGS_IL_LIBRARY) - PhAppendStringBuilder2(&stringBuilder, L"IL library, "); - - if (PvImageCor20Header->StrongNameSignature.VirtualAddress != 0 && PvImageCor20Header->StrongNameSignature.Size != 0) - { - if (PvImageCor20Header->Flags & COMIMAGE_FLAGS_STRONGNAMESIGNED) - PhAppendStringBuilder2(&stringBuilder, L"Strong-name signed, "); - else - PhAppendStringBuilder2(&stringBuilder, L"Strong-name delay signed, "); - } - - if (PvImageCor20Header->Flags & COMIMAGE_FLAGS_NATIVE_ENTRYPOINT) - PhAppendStringBuilder2(&stringBuilder, L"Native entry-point, "); - if (PvImageCor20Header->Flags & COMIMAGE_FLAGS_TRACKDEBUGDATA) - PhAppendStringBuilder2(&stringBuilder, L"Track debug data, "); - - if (PhEndsWithString2(stringBuilder.String, L", ", FALSE)) - PhRemoveEndStringBuilder(&stringBuilder, 2); - - SetDlgItemText(hwndDlg, IDC_FLAGS, stringBuilder.String->Buffer); - PhDeleteStringBuilder(&stringBuilder); - - metaData = PhMappedImageRvaToVa(&PvMappedImage, PvImageCor20Header->MetaData.VirtualAddress, NULL); - - if (metaData) - { - __try - { - PhProbeAddress(metaData, PvImageCor20Header->MetaData.Size, PvMappedImage.ViewBase, PvMappedImage.Size, 4); - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - metaData = NULL; - } - } - - versionStringLength = 0; - - if (metaData) - { - // Skip 12 bytes. - // First 4 bytes contains the length of the version string. - // The version string follows. - versionStringLength = *(PULONG)((PCHAR)metaData + 12); - - // Make sure the length is valid. - if (versionStringLength >= 0x100) - versionStringLength = 0; - } - - if (versionStringLength != 0) - { - string = PhZeroExtendToUtf16Ex((PCHAR)metaData + 12 + 4, versionStringLength); - SetDlgItemText(hwndDlg, IDC_VERSIONSTRING, string->Buffer); - PhDereferenceObject(string); - } - else - { - SetDlgItemText(hwndDlg, IDC_VERSIONSTRING, L"N/A"); - } - } - break; - case WM_SHOWWINDOW: - { - if (!propPageContext->LayoutInitialized) - { - PvAddPropPageLayoutItem(hwndDlg, hwndDlg, - PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL); - - PvDoPropPageLayout(hwndDlg); - - propPageContext->LayoutInitialized = TRUE; - } - } - break; - case WM_NOTIFY: - { - LPNMHDR header = (LPNMHDR)lParam; - - switch (header->code) - { - case PSN_QUERYINITIALFOCUS: - { - SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, (LONG_PTR)GetDlgItem(hwndDlg, IDC_RUNTIMEVERSION)); - } - return TRUE; - } - } - break; - } - - return FALSE; -} - -INT_PTR CALLBACK PvpPeCgfDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - LPPROPSHEETPAGE propSheetPage; - PPV_PROPPAGECONTEXT propPageContext; - - if (!PvPropPageDlgProcHeader(hwndDlg, uMsg, lParam, &propSheetPage, &propPageContext)) - return FALSE; - - switch (uMsg) - { - case WM_INITDIALOG: - { - HWND lvHandle; - PH_MAPPED_IMAGE_CFG cfgConfig = { 0 }; - - lvHandle = GetDlgItem(hwndDlg, IDC_LIST); - PhSetListViewStyle(lvHandle, TRUE, TRUE); - PhSetControlTheme(lvHandle, L"explorer"); - - PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 40, L"#"); - PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_RIGHT, 80, L"VA"); - PhAddListViewColumn(lvHandle, 2, 2, 2, LVCFMT_LEFT, 250, L"Name"); - PhAddListViewColumn(lvHandle, 3, 3, 3, LVCFMT_LEFT, 100, L"Flags"); - PhSetExtendedListView(lvHandle); - PhLoadListViewColumnsFromSetting(L"ImageCfgListViewColumns", lvHandle); - - // Init symbol resolver - if (PvpLoadDbgHelp(&symbolProvider)) - { - // Load current PE's pdb - PhLoadModuleSymbolProvider( - symbolProvider, - PvFileName->Buffer, - (ULONG64)PvMappedImage.NtHeaders->OptionalHeader.ImageBase, - PvMappedImage.NtHeaders->OptionalHeader.SizeOfImage - ); - } - - // Retrieve Cfg Table entry and characteristics - if (NT_SUCCESS(PhGetMappedImageCfg(&cfgConfig, &PvMappedImage))) - { - for (ULONGLONG i = 0; i < cfgConfig.NumberOfGuardFunctionEntries; i++) - { - INT lvItemIndex; - ULONG64 displacement; - PPH_STRING symbol; - PPH_STRING symbolName = NULL; - PH_SYMBOL_RESOLVE_LEVEL symbolResolveLevel = PhsrlInvalid; - IMAGE_CFG_ENTRY cfgFunctionEntry = { 0 }; - WCHAR number[PH_INT64_STR_LEN_1]; - WCHAR pointer[PH_PTR_STR_LEN_1]; - - // Parse cfg entry : if it fails, just skip it ? - if (!NT_SUCCESS(PhGetMappedImageCfgEntry(&cfgConfig, i, ControlFlowGuardFunction, &cfgFunctionEntry))) - continue; - - PhPrintUInt64(number, i + 1); - lvItemIndex = PhAddListViewItem(lvHandle, MAXINT, number, NULL); - - PhPrintPointer(pointer, UlongToPtr(cfgFunctionEntry.Rva)); - PhSetListViewSubItem(lvHandle, lvItemIndex, 1, pointer); - - // Resolve name based on public symbols - if (!(symbol = PhGetSymbolFromAddress( - symbolProvider, - (ULONG64)PTR_ADD_OFFSET(PvMappedImage.NtHeaders->OptionalHeader.ImageBase, cfgFunctionEntry.Rva), - &symbolResolveLevel, - NULL, - &symbolName, - &displacement - ))) - { - continue; - } - - switch (symbolResolveLevel) - { - case PhsrlFunction: - { - if (displacement) - { - PhSetListViewSubItem( - lvHandle, - lvItemIndex, - 2, - PhaFormatString(L"%s+0x%x", symbolName->Buffer, displacement)->Buffer - ); - } - else - { - PhSetListViewSubItem(lvHandle, lvItemIndex, 2, symbolName->Buffer); - } - } - break; - case PhsrlModule: - case PhsrlAddress: - { - PhSetListViewSubItem(lvHandle, lvItemIndex, 2, symbol->Buffer); - } - break; - default: - case PhsrlInvalid: - { - PhSetListViewSubItem(lvHandle, lvItemIndex, 2, L"(unnamed)"); - } - break; - } - - // Add additional flags - if (cfgFunctionEntry.SuppressedCall) - PhSetListViewSubItem(lvHandle, lvItemIndex, 3, L"SuppressedCall"); - else - PhSetListViewSubItem(lvHandle, lvItemIndex, 3, L""); - - if (symbolName) - PhDereferenceObject(symbolName); - PhDereferenceObject(symbol); - } - } - - ExtendedListView_SortItems(lvHandle); - EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); - } - break; - case WM_DESTROY: - { - PhSaveListViewColumnsToSetting(L"ImageCfgListViewColumns", GetDlgItem(hwndDlg, IDC_LIST)); - } - break; - case WM_SHOWWINDOW: - { - if (!propPageContext->LayoutInitialized) - { - PPH_LAYOUT_ITEM dialogItem; - - dialogItem = PvAddPropPageLayoutItem(hwndDlg, hwndDlg, - PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL); - PvAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_LIST), - dialogItem, PH_ANCHOR_ALL); - - PvDoPropPageLayout(hwndDlg); - - propPageContext->LayoutInitialized = TRUE; - } - } - break; - case WM_NOTIFY: - { - PvHandleListViewNotifyForCopy(lParam, GetDlgItem(hwndDlg, IDC_LIST)); - } - break; - } - - return FALSE; -} +} \ No newline at end of file diff --git a/tools/peview/peview.vcxproj b/tools/peview/peview.vcxproj index 65d0ed06345b..54d1bce3d038 100644 --- a/tools/peview/peview.vcxproj +++ b/tools/peview/peview.vcxproj @@ -1,4 +1,4 @@ - + @@ -191,6 +191,11 @@ + + + + + diff --git a/tools/peview/peview.vcxproj.filters b/tools/peview/peview.vcxproj.filters index 87d782e3bcb4..a073793965cd 100644 --- a/tools/peview/peview.vcxproj.filters +++ b/tools/peview/peview.vcxproj.filters @@ -1,67 +1,82 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hpp;hxx;hm;inl;inc;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - - - Resource Files - - - Resource Files - - - - - Resource Files - - + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Resource Files + + + Resource Files + + + + + Resource Files + + \ No newline at end of file From 1b1d08c37faf541ae9028c8f82073b26f31188d3 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 15 May 2017 00:58:15 +1000 Subject: [PATCH 0097/2058] Fix file encoding --- ProcessHacker.sln | 140 +-- ProcessHacker/ProcessHacker.vcxproj | 2 +- ProcessHacker/ProcessHacker.vcxproj.filters | 1226 +++++++++---------- plugins/Plugins.sln | 2 +- tools/CustomSignTool/CustomSignTool.vcxproj | 2 +- 5 files changed, 686 insertions(+), 686 deletions(-) diff --git a/ProcessHacker.sln b/ProcessHacker.sln index 490ed238ad0c..b9f1116bcef8 100644 --- a/ProcessHacker.sln +++ b/ProcessHacker.sln @@ -1,70 +1,70 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.26403.7 -MinimumVisualStudioVersion = 15.0.26228.4 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tools", "Tools", "{2758DC86-368B-430C-9D29-F1EF20032A71}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ProcessHacker", "ProcessHacker\ProcessHacker.vcxproj", "{0271DD27-6707-4290-8DFE-285702B7115D}" - ProjectSection(ProjectDependencies) = postProject - {477D0215-F252-41A1-874B-F27E3EA1ED17} = {477D0215-F252-41A1-874B-F27E3EA1ED17} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "phlib", "phlib\phlib.vcxproj", "{477D0215-F252-41A1-874B-F27E3EA1ED17}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fixlib", "tools\fixlib\fixlib.vcxproj", "{31F4AA06-7ED5-4A6D-B901-19AD4BD16175}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "peview", "tools\peview\peview.vcxproj", "{72C124A2-3C80-41C6-ABA1-C4948B713204}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CustomSignTool", "tools\CustomSignTool\CustomSignTool.vcxproj", "{E8CD0A41-1537-4EA6-98AC-E80CD59C478E}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Win32 = Debug|Win32 - Debug|x64 = Debug|x64 - Release|Win32 = Release|Win32 - Release|x64 = Release|x64 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {0271DD27-6707-4290-8DFE-285702B7115D}.Debug|Win32.ActiveCfg = Debug|Win32 - {0271DD27-6707-4290-8DFE-285702B7115D}.Debug|Win32.Build.0 = Debug|Win32 - {0271DD27-6707-4290-8DFE-285702B7115D}.Debug|x64.ActiveCfg = Debug|x64 - {0271DD27-6707-4290-8DFE-285702B7115D}.Debug|x64.Build.0 = Debug|x64 - {0271DD27-6707-4290-8DFE-285702B7115D}.Release|Win32.ActiveCfg = Release|Win32 - {0271DD27-6707-4290-8DFE-285702B7115D}.Release|Win32.Build.0 = Release|Win32 - {0271DD27-6707-4290-8DFE-285702B7115D}.Release|x64.ActiveCfg = Release|x64 - {0271DD27-6707-4290-8DFE-285702B7115D}.Release|x64.Build.0 = Release|x64 - {477D0215-F252-41A1-874B-F27E3EA1ED17}.Debug|Win32.ActiveCfg = Debug|Win32 - {477D0215-F252-41A1-874B-F27E3EA1ED17}.Debug|Win32.Build.0 = Debug|Win32 - {477D0215-F252-41A1-874B-F27E3EA1ED17}.Debug|x64.ActiveCfg = Debug|x64 - {477D0215-F252-41A1-874B-F27E3EA1ED17}.Debug|x64.Build.0 = Debug|x64 - {477D0215-F252-41A1-874B-F27E3EA1ED17}.Release|Win32.ActiveCfg = Release|Win32 - {477D0215-F252-41A1-874B-F27E3EA1ED17}.Release|Win32.Build.0 = Release|Win32 - {477D0215-F252-41A1-874B-F27E3EA1ED17}.Release|x64.ActiveCfg = Release|x64 - {477D0215-F252-41A1-874B-F27E3EA1ED17}.Release|x64.Build.0 = Release|x64 - {31F4AA06-7ED5-4A6D-B901-19AD4BD16175}.Debug|Win32.ActiveCfg = Debug|Win32 - {31F4AA06-7ED5-4A6D-B901-19AD4BD16175}.Debug|x64.ActiveCfg = Debug|Win32 - {31F4AA06-7ED5-4A6D-B901-19AD4BD16175}.Release|Win32.ActiveCfg = Release|Win32 - {31F4AA06-7ED5-4A6D-B901-19AD4BD16175}.Release|x64.ActiveCfg = Release|Win32 - {72C124A2-3C80-41C6-ABA1-C4948B713204}.Debug|Win32.ActiveCfg = Debug|Win32 - {72C124A2-3C80-41C6-ABA1-C4948B713204}.Debug|Win32.Build.0 = Debug|Win32 - {72C124A2-3C80-41C6-ABA1-C4948B713204}.Debug|x64.ActiveCfg = Debug|x64 - {72C124A2-3C80-41C6-ABA1-C4948B713204}.Debug|x64.Build.0 = Debug|x64 - {72C124A2-3C80-41C6-ABA1-C4948B713204}.Release|Win32.ActiveCfg = Release|Win32 - {72C124A2-3C80-41C6-ABA1-C4948B713204}.Release|Win32.Build.0 = Release|Win32 - {72C124A2-3C80-41C6-ABA1-C4948B713204}.Release|x64.ActiveCfg = Release|x64 - {72C124A2-3C80-41C6-ABA1-C4948B713204}.Release|x64.Build.0 = Release|x64 - {E8CD0A41-1537-4EA6-98AC-E80CD59C478E}.Debug|Win32.ActiveCfg = Debug|Win32 - {E8CD0A41-1537-4EA6-98AC-E80CD59C478E}.Debug|x64.ActiveCfg = Debug|x64 - {E8CD0A41-1537-4EA6-98AC-E80CD59C478E}.Release|Win32.ActiveCfg = Release|Win32 - {E8CD0A41-1537-4EA6-98AC-E80CD59C478E}.Release|x64.ActiveCfg = Release|x64 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(NestedProjects) = preSolution - {31F4AA06-7ED5-4A6D-B901-19AD4BD16175} = {2758DC86-368B-430C-9D29-F1EF20032A71} - {72C124A2-3C80-41C6-ABA1-C4948B713204} = {2758DC86-368B-430C-9D29-F1EF20032A71} - {E8CD0A41-1537-4EA6-98AC-E80CD59C478E} = {2758DC86-368B-430C-9D29-F1EF20032A71} - EndGlobalSection -EndGlobal + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.26403.7 +MinimumVisualStudioVersion = 15.0.26228.4 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tools", "Tools", "{2758DC86-368B-430C-9D29-F1EF20032A71}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ProcessHacker", "ProcessHacker\ProcessHacker.vcxproj", "{0271DD27-6707-4290-8DFE-285702B7115D}" + ProjectSection(ProjectDependencies) = postProject + {477D0215-F252-41A1-874B-F27E3EA1ED17} = {477D0215-F252-41A1-874B-F27E3EA1ED17} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "phlib", "phlib\phlib.vcxproj", "{477D0215-F252-41A1-874B-F27E3EA1ED17}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fixlib", "tools\fixlib\fixlib.vcxproj", "{31F4AA06-7ED5-4A6D-B901-19AD4BD16175}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "peview", "tools\peview\peview.vcxproj", "{72C124A2-3C80-41C6-ABA1-C4948B713204}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CustomSignTool", "tools\CustomSignTool\CustomSignTool.vcxproj", "{E8CD0A41-1537-4EA6-98AC-E80CD59C478E}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {0271DD27-6707-4290-8DFE-285702B7115D}.Debug|Win32.ActiveCfg = Debug|Win32 + {0271DD27-6707-4290-8DFE-285702B7115D}.Debug|Win32.Build.0 = Debug|Win32 + {0271DD27-6707-4290-8DFE-285702B7115D}.Debug|x64.ActiveCfg = Debug|x64 + {0271DD27-6707-4290-8DFE-285702B7115D}.Debug|x64.Build.0 = Debug|x64 + {0271DD27-6707-4290-8DFE-285702B7115D}.Release|Win32.ActiveCfg = Release|Win32 + {0271DD27-6707-4290-8DFE-285702B7115D}.Release|Win32.Build.0 = Release|Win32 + {0271DD27-6707-4290-8DFE-285702B7115D}.Release|x64.ActiveCfg = Release|x64 + {0271DD27-6707-4290-8DFE-285702B7115D}.Release|x64.Build.0 = Release|x64 + {477D0215-F252-41A1-874B-F27E3EA1ED17}.Debug|Win32.ActiveCfg = Debug|Win32 + {477D0215-F252-41A1-874B-F27E3EA1ED17}.Debug|Win32.Build.0 = Debug|Win32 + {477D0215-F252-41A1-874B-F27E3EA1ED17}.Debug|x64.ActiveCfg = Debug|x64 + {477D0215-F252-41A1-874B-F27E3EA1ED17}.Debug|x64.Build.0 = Debug|x64 + {477D0215-F252-41A1-874B-F27E3EA1ED17}.Release|Win32.ActiveCfg = Release|Win32 + {477D0215-F252-41A1-874B-F27E3EA1ED17}.Release|Win32.Build.0 = Release|Win32 + {477D0215-F252-41A1-874B-F27E3EA1ED17}.Release|x64.ActiveCfg = Release|x64 + {477D0215-F252-41A1-874B-F27E3EA1ED17}.Release|x64.Build.0 = Release|x64 + {31F4AA06-7ED5-4A6D-B901-19AD4BD16175}.Debug|Win32.ActiveCfg = Debug|Win32 + {31F4AA06-7ED5-4A6D-B901-19AD4BD16175}.Debug|x64.ActiveCfg = Debug|Win32 + {31F4AA06-7ED5-4A6D-B901-19AD4BD16175}.Release|Win32.ActiveCfg = Release|Win32 + {31F4AA06-7ED5-4A6D-B901-19AD4BD16175}.Release|x64.ActiveCfg = Release|Win32 + {72C124A2-3C80-41C6-ABA1-C4948B713204}.Debug|Win32.ActiveCfg = Debug|Win32 + {72C124A2-3C80-41C6-ABA1-C4948B713204}.Debug|Win32.Build.0 = Debug|Win32 + {72C124A2-3C80-41C6-ABA1-C4948B713204}.Debug|x64.ActiveCfg = Debug|x64 + {72C124A2-3C80-41C6-ABA1-C4948B713204}.Debug|x64.Build.0 = Debug|x64 + {72C124A2-3C80-41C6-ABA1-C4948B713204}.Release|Win32.ActiveCfg = Release|Win32 + {72C124A2-3C80-41C6-ABA1-C4948B713204}.Release|Win32.Build.0 = Release|Win32 + {72C124A2-3C80-41C6-ABA1-C4948B713204}.Release|x64.ActiveCfg = Release|x64 + {72C124A2-3C80-41C6-ABA1-C4948B713204}.Release|x64.Build.0 = Release|x64 + {E8CD0A41-1537-4EA6-98AC-E80CD59C478E}.Debug|Win32.ActiveCfg = Debug|Win32 + {E8CD0A41-1537-4EA6-98AC-E80CD59C478E}.Debug|x64.ActiveCfg = Debug|x64 + {E8CD0A41-1537-4EA6-98AC-E80CD59C478E}.Release|Win32.ActiveCfg = Release|Win32 + {E8CD0A41-1537-4EA6-98AC-E80CD59C478E}.Release|x64.ActiveCfg = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {31F4AA06-7ED5-4A6D-B901-19AD4BD16175} = {2758DC86-368B-430C-9D29-F1EF20032A71} + {72C124A2-3C80-41C6-ABA1-C4948B713204} = {2758DC86-368B-430C-9D29-F1EF20032A71} + {E8CD0A41-1537-4EA6-98AC-E80CD59C478E} = {2758DC86-368B-430C-9D29-F1EF20032A71} + EndGlobalSection +EndGlobal diff --git a/ProcessHacker/ProcessHacker.vcxproj b/ProcessHacker/ProcessHacker.vcxproj index f212a670d21b..6273867a710a 100644 --- a/ProcessHacker/ProcessHacker.vcxproj +++ b/ProcessHacker/ProcessHacker.vcxproj @@ -1,4 +1,4 @@ - + diff --git a/ProcessHacker/ProcessHacker.vcxproj.filters b/ProcessHacker/ProcessHacker.vcxproj.filters index 671c41cb8543..5517737409be 100644 --- a/ProcessHacker/ProcessHacker.vcxproj.filters +++ b/ProcessHacker/ProcessHacker.vcxproj.filters @@ -1,614 +1,614 @@ - - - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hpp;hxx;hm;inl;inc;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {3fa0b151-12c1-4832-94fb-e16c52584b65} - - - {84a3be0b-42cf-42ae-bcd3-16f165caa0db} - - - {e72b6c69-b510-4578-9ed5-34a16d8dffc1} - - - {67c40321-0b28-4c16-8c48-dc0b64c148d7} - - - - - Process Hacker - - - Process Hacker - - - Process Hacker - - - Process Hacker - - - Process Hacker - - - Process Hacker - - - Process Hacker - - - Process Hacker - - - Process Hacker - - - Process Hacker - - - Process Hacker - - - Process Hacker - - - Process Hacker - - - Process Hacker - - - Process Hacker - - - Process Hacker - - - Process Hacker - - - Process Hacker - - - Process Hacker - - - Process Hacker - - - Process Hacker - - - Process Hacker - - - Process Hacker - - - Process Hacker - - - Process Hacker - - - Process Hacker - - - Process Hacker - - - Process Hacker - - - Process Hacker - - - Process Hacker - - - Process Hacker - - - Process Hacker - - - Process Hacker - - - Process Hacker - - - Process Hacker - - - Process Hacker - - - Process Hacker - - - Process Hacker - - - Process Hacker - - - Process Hacker - - - Process Hacker - - - Process Hacker - - - Process Hacker - - - Process Hacker - - - Process Hacker - - - Process Hacker - - - Process Hacker - - - Process Hacker - - - Process Hacker - - - Process Hacker - - - Process Hacker - - - Process Hacker - - - Process Hacker - - - Process Hacker - - - phsvc - - - phsvc - - - phsvc - - - phsvc - - - phsvc - - - Process Hacker - - - Process Hacker - - - Process Hacker - - - Process Hacker - - - Process Hacker - - - Process Hacker - - - Process Hacker - - - Process Hacker - - - Process Hacker - - - Process Hacker - - - Process Hacker - - - PCRE - - - PCRE - - - PCRE - - - PCRE - - - PCRE - - - PCRE - - - PCRE - - - PCRE - - - PCRE - - - PCRE - - - PCRE - - - PCRE - - - PCRE - - - PCRE - - - PCRE - - - PCRE - - - PCRE - - - PCRE - - - PCRE - - - PCRE - - - PCRE - - - PCRE - - - PCRE - - - PCRE - - - PCRE - - - Process Hacker - - - Process Hacker - - - Process Hacker - - - Process Hacker - - - Process Hacker - - - Process Hacker - - - Process Hacker - - - Process Hacker - - - Process Hacker - - - Process Hacker - - - Process Hacker - - - Process Hacker - - - Process Hacker - - - Process Hacker - - - Process Hacker - - - Process Hacker - - - Process Hacker - - - Process Hacker - - - Process Hacker - - - Process Hacker - - - Process Hacker - - - Process Hacker - - - Process Hacker - - - - - Headers - - - Headers - - - Headers - - - Headers - - - Headers - - - Headers - - - Headers - - - Headers - - - Headers - - - Headers - - - Headers - - - Headers - - - Headers - - - Headers - - - Headers - - - Headers - - - Headers - - - Headers - - - Headers - - - Headers - - - Headers - - - Headers - - - PCRE\Headers - - - PCRE\Headers - - - PCRE\Headers - - - PCRE\Headers - - - PCRE\Headers - - - PCRE\Headers - - - Headers - - - Headers - - - Headers - - - Headers - - - Headers - - - Headers - - - Headers - - - Headers - - - Headers - - - Headers - - - Headers - - - Headers - - - Headers - - - Headers - - - Headers - - - Headers - - - Headers - - - Headers - - - Headers - - - Headers - - - Headers - - - Headers - - - Headers - - - Headers - - - Headers - - - - - Resources - - - Resources - - - Resources - - - Resources - - - Resources - - - Resources - - - Resources - - - Resources - - - Module - - - - - Resources - - - Resources - - - - - Resources - - - - - Resources - - - Resources - - - Resources - - - Resources - - - Resources - - - Resources - - - Resources - - - Resources - - + + + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {3fa0b151-12c1-4832-94fb-e16c52584b65} + + + {84a3be0b-42cf-42ae-bcd3-16f165caa0db} + + + {e72b6c69-b510-4578-9ed5-34a16d8dffc1} + + + {67c40321-0b28-4c16-8c48-dc0b64c148d7} + + + + + Process Hacker + + + Process Hacker + + + Process Hacker + + + Process Hacker + + + Process Hacker + + + Process Hacker + + + Process Hacker + + + Process Hacker + + + Process Hacker + + + Process Hacker + + + Process Hacker + + + Process Hacker + + + Process Hacker + + + Process Hacker + + + Process Hacker + + + Process Hacker + + + Process Hacker + + + Process Hacker + + + Process Hacker + + + Process Hacker + + + Process Hacker + + + Process Hacker + + + Process Hacker + + + Process Hacker + + + Process Hacker + + + Process Hacker + + + Process Hacker + + + Process Hacker + + + Process Hacker + + + Process Hacker + + + Process Hacker + + + Process Hacker + + + Process Hacker + + + Process Hacker + + + Process Hacker + + + Process Hacker + + + Process Hacker + + + Process Hacker + + + Process Hacker + + + Process Hacker + + + Process Hacker + + + Process Hacker + + + Process Hacker + + + Process Hacker + + + Process Hacker + + + Process Hacker + + + Process Hacker + + + Process Hacker + + + Process Hacker + + + Process Hacker + + + Process Hacker + + + Process Hacker + + + Process Hacker + + + Process Hacker + + + phsvc + + + phsvc + + + phsvc + + + phsvc + + + phsvc + + + Process Hacker + + + Process Hacker + + + Process Hacker + + + Process Hacker + + + Process Hacker + + + Process Hacker + + + Process Hacker + + + Process Hacker + + + Process Hacker + + + Process Hacker + + + Process Hacker + + + PCRE + + + PCRE + + + PCRE + + + PCRE + + + PCRE + + + PCRE + + + PCRE + + + PCRE + + + PCRE + + + PCRE + + + PCRE + + + PCRE + + + PCRE + + + PCRE + + + PCRE + + + PCRE + + + PCRE + + + PCRE + + + PCRE + + + PCRE + + + PCRE + + + PCRE + + + PCRE + + + PCRE + + + PCRE + + + Process Hacker + + + Process Hacker + + + Process Hacker + + + Process Hacker + + + Process Hacker + + + Process Hacker + + + Process Hacker + + + Process Hacker + + + Process Hacker + + + Process Hacker + + + Process Hacker + + + Process Hacker + + + Process Hacker + + + Process Hacker + + + Process Hacker + + + Process Hacker + + + Process Hacker + + + Process Hacker + + + Process Hacker + + + Process Hacker + + + Process Hacker + + + Process Hacker + + + Process Hacker + + + + + Headers + + + Headers + + + Headers + + + Headers + + + Headers + + + Headers + + + Headers + + + Headers + + + Headers + + + Headers + + + Headers + + + Headers + + + Headers + + + Headers + + + Headers + + + Headers + + + Headers + + + Headers + + + Headers + + + Headers + + + Headers + + + Headers + + + PCRE\Headers + + + PCRE\Headers + + + PCRE\Headers + + + PCRE\Headers + + + PCRE\Headers + + + PCRE\Headers + + + Headers + + + Headers + + + Headers + + + Headers + + + Headers + + + Headers + + + Headers + + + Headers + + + Headers + + + Headers + + + Headers + + + Headers + + + Headers + + + Headers + + + Headers + + + Headers + + + Headers + + + Headers + + + Headers + + + Headers + + + Headers + + + Headers + + + Headers + + + Headers + + + Headers + + + + + Resources + + + Resources + + + Resources + + + Resources + + + Resources + + + Resources + + + Resources + + + Resources + + + Module + + + + + Resources + + + Resources + + + + + Resources + + + + + Resources + + + Resources + + + Resources + + + Resources + + + Resources + + + Resources + + + Resources + + + Resources + + \ No newline at end of file diff --git a/plugins/Plugins.sln b/plugins/Plugins.sln index 931a8541035a..15c2c8271d2b 100644 --- a/plugins/Plugins.sln +++ b/plugins/Plugins.sln @@ -1,4 +1,4 @@ - + Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 VisualStudioVersion = 15.0.26403.7 diff --git a/tools/CustomSignTool/CustomSignTool.vcxproj b/tools/CustomSignTool/CustomSignTool.vcxproj index 9e345451a89b..c8a08527627b 100644 --- a/tools/CustomSignTool/CustomSignTool.vcxproj +++ b/tools/CustomSignTool/CustomSignTool.vcxproj @@ -1,4 +1,4 @@ - + From caa7280f544b1696a48b01c7878f48c9ef31ad09 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 15 May 2017 01:27:09 +1000 Subject: [PATCH 0098/2058] peview: Add CLR sections --- tools/peview/clrprp.c | 108 ++++++++++++++++++++++++++++++++--------- tools/peview/peview.rc | 2 + 2 files changed, 88 insertions(+), 22 deletions(-) diff --git a/tools/peview/clrprp.c b/tools/peview/clrprp.c index d0c46d7bccf6..8584c433bdb2 100644 --- a/tools/peview/clrprp.c +++ b/tools/peview/clrprp.c @@ -23,6 +23,39 @@ #include +// CLR structure reference: +// https://github.com/dotnet/coreclr/blob/master/src/md/inc/mdfileformat.h +// https://github.com/dotnet/coreclr/blob/master/src/utilcode/pedecoder.cpp +// https://github.com/dotnet/coreclr/blob/master/src/debug/daccess/nidump.cpp + +#define STORAGE_MAGIC_SIG 0x424A5342 // BSJB + +#include +typedef struct _STORAGESIGNATURE +{ + ULONG Signature; + USHORT MajorVersion; + USHORT MinorVersion; + ULONG ExtraData; // Offset to next structure of information + ULONG VersionLength; // Length of version string + UCHAR VersionString[1]; // dmex: added for convenience. +} STORAGESIGNATURE, *PSTORAGESIGNATURE; + +typedef struct _STORAGEHEADER +{ + BYTE Flags; // STGHDR_xxx flags. + BYTE Reserved; + USHORT Streams; // How many streams are there. +} STORAGEHEADER, *PSTORAGEHEADER; + +typedef struct _STORAGESTREAM +{ + ULONG Offset; // Offset in file for this stream. + ULONG Size; // Size of the file. + CHAR Name[32]; // Start of name, null terminated. +} STORAGESTREAM, *PSTORAGESTREAM; +#include + INT_PTR CALLBACK PvpPeClrDlgProc( _In_ HWND hwndDlg, _In_ UINT uMsg, @@ -40,12 +73,21 @@ INT_PTR CALLBACK PvpPeClrDlgProc( { case WM_INITDIALOG: { - PH_STRING_BUILDER stringBuilder; + HWND lvHandle; PPH_STRING string; - PVOID metaData; - ULONG versionStringLength; - - string = PhaFormatString(L"%u.%u", PvImageCor20Header->MajorRuntimeVersion, + PH_STRING_BUILDER stringBuilder; + PSTORAGESIGNATURE metaData; + + lvHandle = GetDlgItem(hwndDlg, IDC_LIST); + PhSetListViewStyle(lvHandle, TRUE, TRUE); + PhSetControlTheme(lvHandle, L"explorer"); + PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 80, L"Name"); + PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 80, L"VA"); + PhAddListViewColumn(lvHandle, 2, 2, 2, LVCFMT_LEFT, 80, L"Size"); + + string = PhaFormatString( + L"%u.%u", + PvImageCor20Header->MajorRuntimeVersion, PvImageCor20Header->MinorRuntimeVersion); SetDlgItemText(hwndDlg, IDC_RUNTIMEVERSION, string->Buffer); @@ -93,25 +135,43 @@ INT_PTR CALLBACK PvpPeClrDlgProc( } } - versionStringLength = 0; - - if (metaData) - { - // Skip 12 bytes. - // First 4 bytes contains the length of the version string. - // The version string follows. - versionStringLength = *(PULONG)((PCHAR)metaData + 12); - - // Make sure the length is valid. - if (versionStringLength >= 0x100) - versionStringLength = 0; - } - - if (versionStringLength != 0) + if (metaData && metaData->VersionLength != 0) { - string = PhZeroExtendToUtf16Ex((PCHAR)metaData + 12 + 4, versionStringLength); + string = PhZeroExtendToUtf16Ex((PCHAR)metaData->VersionString, metaData->VersionLength); SetDlgItemText(hwndDlg, IDC_VERSIONSTRING, string->Buffer); PhDereferenceObject(string); + + { + PSTORAGEHEADER storageHeader = PTR_ADD_OFFSET(metaData, (sizeof(STORAGESIGNATURE) - sizeof(UCHAR)) + metaData->VersionLength); + PSTORAGESTREAM streamHeader = PTR_ADD_OFFSET(storageHeader, sizeof(STORAGEHEADER)); + + for (USHORT i = 0; i < storageHeader->Streams; i++) + { + INT lvItemIndex; + WCHAR sectionName[65]; + WCHAR pointer[PH_PTR_STR_LEN_1]; + + if (PhCopyStringZFromBytes( + streamHeader->Name, + sizeof(streamHeader->Name), + sectionName, + ARRAYSIZE(sectionName), + NULL + )) + { + lvItemIndex = PhAddListViewItem(lvHandle, MAXINT, sectionName, NULL); + + PhPrintPointer(pointer, UlongToPtr(streamHeader->Offset)); + + PhSetListViewSubItem(lvHandle, lvItemIndex, 1, pointer); + PhSetListViewSubItem(lvHandle, lvItemIndex, 2, PhaFormatSize(streamHeader->Size, -1)->Buffer); + } + + // Stream headers don't have fixed sizes... + // The size is aligned up based on a variable length string at the end. + streamHeader = PTR_ADD_OFFSET(streamHeader, ALIGN_UP(FIELD_OFFSET(STORAGESTREAM, Name) + strlen(streamHeader->Name) + 1, 4)); + } + } } else { @@ -123,8 +183,12 @@ INT_PTR CALLBACK PvpPeClrDlgProc( { if (!propPageContext->LayoutInitialized) { - PvAddPropPageLayoutItem(hwndDlg, hwndDlg, + PPH_LAYOUT_ITEM dialogItem; + + dialogItem = PvAddPropPageLayoutItem(hwndDlg, hwndDlg, PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL); + PvAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_LIST), + dialogItem, PH_ANCHOR_ALL); PvDoPropPageLayout(hwndDlg); diff --git a/tools/peview/peview.rc b/tools/peview/peview.rc index 6151830379f2..ed559acfa245 100644 --- a/tools/peview/peview.rc +++ b/tools/peview/peview.rc @@ -192,6 +192,8 @@ BEGIN EDITTEXT IDC_FLAGS,76,19,217,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER LTEXT "Version String:",IDC_STATIC,7,31,48,8 LTEXT "Static",IDC_VERSIONSTRING,78,31,215,8 + CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,57,286,216 + LTEXT "Sections:",IDC_STATIC,7,47,30,8 END IDD_PELOADCONFIG DIALOGEX 0, 0, 300, 280 From 9831e2550acf687dbe84b4375d4fa7267dd21545 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 15 May 2017 12:42:01 +1000 Subject: [PATCH 0099/2058] peview: Fix loader config version check --- tools/peview/ldprp.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/peview/ldprp.c b/tools/peview/ldprp.c index 22d6e24d5117..826ec0d6a711 100644 --- a/tools/peview/ldprp.c +++ b/tools/peview/ldprp.c @@ -67,7 +67,7 @@ INT_PTR CALLBACK PvpPeLoadConfigDlgProc( RtlSecondsSince1970ToTime((Config)->TimeDateStamp, &time); \ PhLargeIntegerToLocalSystemTime(&systemTime, &time); \ \ - ADD_VALUE(L"Time stamp", PhaFormatDateTime(&systemTime)->Buffer); \ + ADD_VALUE(L"Time stamp", (Config)->TimeDateStamp ? PhaFormatDateTime(&systemTime)->Buffer : L"0"); \ ADD_VALUE(L"Version", PhaFormatString(L"%u.%u", (Config)->MajorVersion, (Config)->MinorVersion)->Buffer); \ ADD_VALUE(L"Global flags to clear", PhaFormatString(L"0x%x", (Config)->GlobalFlagsClear)->Buffer); \ ADD_VALUE(L"Global flags to set", PhaFormatString(L"0x%x", (Config)->GlobalFlagsSet)->Buffer); \ @@ -85,7 +85,7 @@ INT_PTR CALLBACK PvpPeLoadConfigDlgProc( ADD_VALUE(L"SEH handler table", PhaFormatString(L"0x%Ix", (Config)->SEHandlerTable)->Buffer); \ ADD_VALUE(L"SEH handler count", PhaFormatUInt64((Config)->SEHandlerCount, TRUE)->Buffer); \ \ - if ((Config)->Size >= (ULONG)FIELD_OFFSET(Type, GuardAddressTakenIatEntryTable)) \ + if ((Config)->Size >= (ULONG)FIELD_OFFSET(Type, GuardCFCheckFunctionPointer)) \ { \ ADD_VALUE(L"CFG GuardFlags", PhaFormatString(L"0x%Ix", (Config)->GuardFlags)->Buffer); \ ADD_VALUE(L"CFG Check Function pointer", PhaFormatString(L"0x%Ix", (Config)->GuardCFCheckFunctionPointer)->Buffer); \ @@ -101,7 +101,7 @@ INT_PTR CALLBACK PvpPeLoadConfigDlgProc( } \ if ((Config)->Size >= (ULONG)FIELD_OFFSET(Type, GuardLongJumpTargetTable) \ + sizeof((Config)->GuardLongJumpTargetTable) \ - + sizeof((Config)->GuardLongJumpTargetCount))\ + + sizeof((Config)->GuardLongJumpTargetCount)) \ { \ ADD_VALUE(L"CFG LongJump table", PhaFormatString(L"0x%Ix", (Config)->GuardLongJumpTargetTable)->Buffer); \ ADD_VALUE(L"CFG LongJump table entry count", PhaFormatUInt64((Config)->GuardLongJumpTargetCount, TRUE)->Buffer); \ From 8f143ed66b4c98fa386e9817026b82a1770a0538 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 15 May 2017 12:48:09 +1000 Subject: [PATCH 0100/2058] ExtendedTools: Update UnloadedModules window --- plugins/ExtendedTools/ExtendedTools.rc | 7 +++++- plugins/ExtendedTools/exttools.h | 7 +++++- plugins/ExtendedTools/main.c | 7 ++++-- plugins/ExtendedTools/unldll.c | 31 ++++++++++++++++++++++++-- 4 files changed, 46 insertions(+), 6 deletions(-) diff --git a/plugins/ExtendedTools/ExtendedTools.rc b/plugins/ExtendedTools/ExtendedTools.rc index 6b90a093c160..6535eaeda856 100644 --- a/plugins/ExtendedTools/ExtendedTools.rc +++ b/plugins/ExtendedTools/ExtendedTools.rc @@ -88,7 +88,7 @@ END // IDD_UNLOADEDDLLS DIALOGEX 0, 0, 342, 265 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +STYLE DS_SETFONT | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME CAPTION "Unloaded Modules" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN @@ -526,6 +526,11 @@ BEGIN 0 END +IDD_UNLOADEDDLLS AFX_DIALOG_LAYOUT +BEGIN + 0 +END + #endif // English (Australia) resources ///////////////////////////////////////////////////////////////////////////// diff --git a/plugins/ExtendedTools/exttools.h b/plugins/ExtendedTools/exttools.h index 47ddf23fb115..abff31baadd4 100644 --- a/plugins/ExtendedTools/exttools.h +++ b/plugins/ExtendedTools/exttools.h @@ -2,6 +2,7 @@ #define EXTTOOLS_H #include +#include #include #include #include @@ -22,8 +23,13 @@ extern HWND NetworkTreeNewHandle; #define SETTING_NAME_ENABLE_SYSINFO_GRAPHS (PLUGIN_NAME L".EnableSysInfoGraphs") #define SETTING_NAME_GPU_NODE_BITMAP (PLUGIN_NAME L".GpuNodeBitmap") #define SETTING_NAME_GPU_LAST_NODE_COUNT (PLUGIN_NAME L".GpuLastNodeCount") +#define SETTING_NAME_UNLOADED_WINDOW_POSITION (PLUGIN_NAME L".TracertWindowPosition") +#define SETTING_NAME_UNLOADED_WINDOW_SIZE (PLUGIN_NAME L".TracertWindowSize") +#define SETTING_NAME_UNLOADED_COLUMNS (PLUGIN_NAME L".UnloadedListColumns") #define ET_SCALE_DPI(Value) PhMultiplyDivide(Value, PhGlobalDpi, 96) +#define ET_LOAD_SHARED_ICON_SMALL(Name) PhLoadIcon(NtCurrentPeb()->ImageBaseAddress, (Name), PH_LOAD_ICON_SHARED | PH_LOAD_ICON_SIZE_SMALL, 0, 0) +#define ET_LOAD_SHARED_ICON_LARGE(Name) PhLoadIcon(NtCurrentPeb()->ImageBaseAddress, (Name), PH_LOAD_ICON_SHARED | PH_LOAD_ICON_SIZE_LARGE, 0, 0) // Graph update message @@ -536,7 +542,6 @@ BOOLEAN EtUiCancelIoThread( // unldll VOID EtShowUnloadedDllsDialog( - _In_ HWND ParentWindowHandle, _In_ PPH_PROCESS_ITEM ProcessItem ); diff --git a/plugins/ExtendedTools/main.c b/plugins/ExtendedTools/main.c index 108a747d714e..22c279729158 100644 --- a/plugins/ExtendedTools/main.c +++ b/plugins/ExtendedTools/main.c @@ -86,7 +86,7 @@ VOID NTAPI MenuItemCallback( { case ID_PROCESS_UNLOADEDMODULES: { - EtShowUnloadedDllsDialog(PhMainWndHandle, menuItem->Context); + EtShowUnloadedDllsDialog(menuItem->Context); } break; case ID_PROCESS_WSWATCH: @@ -604,7 +604,10 @@ LOGICAL DllMain( { IntegerSettingType, SETTING_NAME_ENABLE_GPU_MONITOR, L"1" }, { IntegerSettingType, SETTING_NAME_ENABLE_SYSINFO_GRAPHS, L"1" }, { StringSettingType, SETTING_NAME_GPU_NODE_BITMAP, L"01000000" }, - { IntegerSettingType, SETTING_NAME_GPU_LAST_NODE_COUNT, L"0" } + { IntegerSettingType, SETTING_NAME_GPU_LAST_NODE_COUNT, L"0" }, + { IntegerPairSettingType, SETTING_NAME_UNLOADED_WINDOW_POSITION, L"0,0" }, + { ScalableIntegerPairSettingType, SETTING_NAME_UNLOADED_WINDOW_SIZE, L"@96|350,270" }, + { StringSettingType, SETTING_NAME_UNLOADED_COLUMNS, L"" }, }; PhAddSettings(settings, sizeof(settings) / sizeof(PH_SETTING_CREATE)); diff --git a/plugins/ExtendedTools/unldll.c b/plugins/ExtendedTools/unldll.c index 5145c62348e4..54d9f4b8ae27 100644 --- a/plugins/ExtendedTools/unldll.c +++ b/plugins/ExtendedTools/unldll.c @@ -26,6 +26,7 @@ typedef struct _UNLOADED_DLLS_CONTEXT { PPH_PROCESS_ITEM ProcessItem; HWND ListViewHandle; + PH_LAYOUT_MANAGER LayoutManager; PVOID CapturedEventTrace; } UNLOADED_DLLS_CONTEXT, *PUNLOADED_DLLS_CONTEXT; @@ -37,7 +38,6 @@ INT_PTR CALLBACK EtpUnloadedDllsDlgProc( ); VOID EtShowUnloadedDllsDialog( - _In_ HWND ParentWindowHandle, _In_ PPH_PROCESS_ITEM ProcessItem ) { @@ -49,7 +49,7 @@ VOID EtShowUnloadedDllsDialog( DialogBoxParam( PluginInstance->DllBase, MAKEINTRESOURCE(IDD_UNLOADEDDLLS), - ParentWindowHandle, + NULL, EtpUnloadedDllsDlgProc, (LPARAM)&context ); @@ -305,6 +305,9 @@ INT_PTR CALLBACK EtpUnloadedDllsDlgProc( { HWND lvHandle; + SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)ET_LOAD_SHARED_ICON_SMALL(MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); + SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)ET_LOAD_SHARED_ICON_LARGE(MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); + PhCenterWindow(hwndDlg, GetParent(hwndDlg)); context->ListViewHandle = lvHandle = GetDlgItem(hwndDlg, IDC_LIST); @@ -324,6 +327,17 @@ INT_PTR CALLBACK EtpUnloadedDllsDlgProc( ExtendedListView_SetCompareFunction(lvHandle, 3, EtpSizeCompareFunction); ExtendedListView_SetCompareFunction(lvHandle, 4, EtpTimeStampCompareFunction); ExtendedListView_SetCompareFunction(lvHandle, 5, EtpCheckSumCompareFunction); + PhLoadListViewColumnsFromSetting(SETTING_NAME_UNLOADED_COLUMNS, lvHandle); + + PhInitializeLayoutManager(&context->LayoutManager, hwndDlg); + PhAddLayoutItem(&context->LayoutManager, lvHandle, NULL, PH_ANCHOR_ALL); + PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_REFRESH), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_BOTTOM); + PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDOK), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); + + if (PhGetIntegerPairSetting(SETTING_NAME_UNLOADED_WINDOW_POSITION).X != 0) + PhLoadWindowPlacementFromSetting(SETTING_NAME_UNLOADED_WINDOW_POSITION, SETTING_NAME_UNLOADED_WINDOW_SIZE, hwndDlg); + else + PhCenterWindow(hwndDlg, PhMainWndHandle); if (!EtpRefreshUnloadedDlls(hwndDlg, context)) { @@ -332,6 +346,14 @@ INT_PTR CALLBACK EtpUnloadedDllsDlgProc( } } break; + case WM_DESTROY: + { + PhSaveListViewColumnsToSetting(SETTING_NAME_UNLOADED_COLUMNS, context->ListViewHandle); + PhSaveWindowPlacementToSetting(SETTING_NAME_UNLOADED_WINDOW_POSITION, SETTING_NAME_UNLOADED_WINDOW_SIZE, hwndDlg); + + PhDeleteLayoutManager(&context->LayoutManager); + } + break; case WM_COMMAND: { switch (LOWORD(wParam)) @@ -351,6 +373,11 @@ INT_PTR CALLBACK EtpUnloadedDllsDlgProc( PhHandleListViewNotifyForCopy(lParam, context->ListViewHandle); } break; + case WM_SIZE: + { + PhLayoutManagerLayout(&context->LayoutManager); + } + break; } return FALSE; From f73312e162c0aa07036c4199424955ede9f67481 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 15 May 2017 15:21:47 +1000 Subject: [PATCH 0101/2058] Add PS_MITIGATION_OPTION --- phnt/include/ntpsapi.h | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/phnt/include/ntpsapi.h b/phnt/include/ntpsapi.h index 2011aa3915cc..ead669d1bb9e 100644 --- a/phnt/include/ntpsapi.h +++ b/phnt/include/ntpsapi.h @@ -1322,6 +1322,31 @@ typedef enum _PS_CREATE_STATE PsCreateMaximumStates } PS_CREATE_STATE; +// private +typedef enum _PS_MITIGATION_OPTION +{ + PS_MITIGATION_OPTION_NX, + PS_MITIGATION_OPTION_SEHOP, + PS_MITIGATION_OPTION_FORCE_RELOCATE_IMAGES, + PS_MITIGATION_OPTION_HEAP_TERMINATE, + PS_MITIGATION_OPTION_BOTTOM_UP_ASLR, + PS_MITIGATION_OPTION_HIGH_ENTROPY_ASLR, + PS_MITIGATION_OPTION_STRICT_HANDLE_CHECKS, + PS_MITIGATION_OPTION_WIN32K_SYSTEM_CALL_DISABLE, + PS_MITIGATION_OPTION_EXTENSION_POINT_DISABLE, + PS_MITIGATION_OPTION_PROHIBIT_DYNAMIC_CODE, + PS_MITIGATION_OPTION_CONTROL_FLOW_GUARD, + PS_MITIGATION_OPTION_BLOCK_NON_MICROSOFT_BINARIES, + PS_MITIGATION_OPTION_FONT_DISABLE, + PS_MITIGATION_OPTION_IMAGE_LOAD_NO_REMOTE, + PS_MITIGATION_OPTION_IMAGE_LOAD_NO_LOW_LABEL, + PS_MITIGATION_OPTION_IMAGE_LOAD_PREFER_SYSTEM32, + PS_MITIGATION_OPTION_RETURN_FLOW_GUARD, + PS_MITIGATION_OPTION_LOADER_INTEGRITY_CONTINUITY, + PS_MITIGATION_OPTION_STRICT_CONTROL_FLOW_GUARD, + PS_MITIGATION_OPTION_RESTRICT_SET_THREAD_CONTEXT +} PS_MITIGATION_OPTION; + typedef struct _PS_CREATE_INFO { SIZE_T Size; From efb9503bbc357defe58596f90e5ea2ff977787dc Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 15 May 2017 16:27:23 +1000 Subject: [PATCH 0102/2058] Fix HideUnnamedHandles regression --- ProcessHacker/prpghndl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ProcessHacker/prpghndl.c b/ProcessHacker/prpghndl.c index 6f0861eee24f..36d1d027dd3c 100644 --- a/ProcessHacker/prpghndl.c +++ b/ProcessHacker/prpghndl.c @@ -253,7 +253,7 @@ BOOLEAN PhpHandleTreeFilterCallback( PPH_HANDLE_NODE handleNode = (PPH_HANDLE_NODE)Node; PPH_HANDLE_ITEM handleItem = handleNode->HandleItem; - if (handlesContext->ListContext.HideUnnamedHandles && PhIsNullOrEmptyString(handleItem->ObjectName)) + if (handlesContext->ListContext.HideUnnamedHandles && PhIsNullOrEmptyString(handleItem->BestObjectName)) return FALSE; if (PhIsNullOrEmptyString(handlesContext->SearchboxText)) From cf1f4ba485bfa003b8a7b8fb8b54bb0bc64999ba Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 16 May 2017 03:48:03 +1000 Subject: [PATCH 0103/2058] ExtendedTools: Fix crash on devices with special graphics cards --- plugins/ExtendedTools/gpumon.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/plugins/ExtendedTools/gpumon.c b/plugins/ExtendedTools/gpumon.c index 7f941d54a4be..ca608783baa3 100644 --- a/plugins/ExtendedTools/gpumon.c +++ b/plugins/ExtendedTools/gpumon.c @@ -33,7 +33,7 @@ BOOLEAN EtGpuEnabled; static PPH_LIST EtpGpuAdapterList; static PH_CALLBACK_REGISTRATION ProcessesUpdatedCallbackRegistration; -ULONG EtGpuTotalNodeCount; +ULONG EtGpuTotalNodeCount = 0; ULONG EtGpuTotalSegmentCount; ULONG64 EtGpuDedicatedLimit; ULONG64 EtGpuSharedLimit; @@ -274,6 +274,9 @@ BOOLEAN EtpInitializeD3DStatistics( PhFree(deviceInterfaceList); + if (EtGpuTotalNodeCount == 0) + return FALSE; + EtGpuNodeBitMapBuffer = PhAllocate(BYTES_NEEDED_FOR_BITS(EtGpuTotalNodeCount)); RtlInitializeBitMap(&EtGpuNodeBitMap, EtGpuNodeBitMapBuffer, EtGpuTotalNodeCount); RtlSetBits(&EtGpuNodeBitMap, 0, 1); From af48478d200c4a65c7b2985a280dbfa6d0449d5f Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 17 May 2017 05:07:50 +1000 Subject: [PATCH 0104/2058] peview: Add symbol treelist support, Fix symbol paramaters --- tools/peview/colmgr.c | 600 ++++++++++++++++++++++ tools/peview/colmgr.h | 87 ++++ tools/peview/include/pdb.h | 52 +- tools/peview/include/peview.h | 125 ++++- tools/peview/main.c | 5 +- tools/peview/pdb.c | 750 +++++++++++++--------------- tools/peview/pdbprp.c | 714 ++++++++++++++++++++++++++ tools/peview/peview.rc | 31 +- tools/peview/peview.vcxproj | 7 +- tools/peview/peview.vcxproj.filters | 11 +- tools/peview/resource.h | 13 +- tools/peview/settings.c | 2 +- 12 files changed, 1922 insertions(+), 475 deletions(-) create mode 100644 tools/peview/colmgr.c create mode 100644 tools/peview/colmgr.h create mode 100644 tools/peview/pdbprp.c diff --git a/tools/peview/colmgr.c b/tools/peview/colmgr.c new file mode 100644 index 000000000000..dc4b4c963cc4 --- /dev/null +++ b/tools/peview/colmgr.c @@ -0,0 +1,600 @@ +/* + * Process Hacker - + * tree new column manager + * + * Copyright (C) 2011-2016 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include +#include "colmgr.h" +//#include +//#include + +typedef struct _PH_CM_SORT_CONTEXT +{ + //PPH_PLUGIN_TREENEW_SORT_FUNCTION SortFunction; + ULONG SubId; + PVOID Context; + PPH_CM_POST_SORT_FUNCTION PostSortFunction; + PH_SORT_ORDER SortOrder; +} PH_CM_SORT_CONTEXT, *PPH_CM_SORT_CONTEXT; + +/** + * Parses an application name and sub-ID pair. + * + * \param CompoundId The compound identifier. + * \param AppName A variable which receives the application name. + * \param SubId A variable which receives the sub-ID. + */ +BOOLEAN PhEmParseCompoundId( + _In_ PPH_STRINGREF CompoundId, + _Out_ PPH_STRINGREF AppName, + _Out_ PULONG SubId + ) +{ + PH_STRINGREF firstPart; + PH_STRINGREF secondPart; + ULONG64 integer; + + firstPart = *CompoundId; + + if (firstPart.Length == 0) + return FALSE; + if (firstPart.Buffer[0] != '+') + return FALSE; + + PhSkipStringRef(&firstPart, sizeof(WCHAR)); + PhSplitStringRefAtChar(&firstPart, '+', &firstPart, &secondPart); + + if (firstPart.Length == 0 || secondPart.Length == 0) + return FALSE; + + if (!PhStringToInteger64(&secondPart, 10, &integer)) + return FALSE; + + *AppName = firstPart; + *SubId = (ULONG)integer; + + return TRUE; +} + +VOID PhCmInitializeManager( + _Out_ PPH_CM_MANAGER Manager, + _In_ HWND Handle, + _In_ ULONG MinId, + _In_ PPH_CM_POST_SORT_FUNCTION PostSortFunction + ) +{ + Manager->Handle = Handle; + Manager->MinId = MinId; + Manager->NextId = MinId; + Manager->PostSortFunction = PostSortFunction; + InitializeListHead(&Manager->ColumnListHead); + Manager->NotifyList = NULL; +} + +VOID PhCmDeleteManager( + _In_ PPH_CM_MANAGER Manager + ) +{ + PLIST_ENTRY listEntry; + PPH_CM_COLUMN column; + + listEntry = Manager->ColumnListHead.Flink; + + while (listEntry != &Manager->ColumnListHead) + { + column = CONTAINING_RECORD(listEntry, PH_CM_COLUMN, ListEntry); + listEntry = listEntry->Flink; + + PhFree(column); + } + + if (Manager->NotifyList) + PhDereferenceObject(Manager->NotifyList); +} + +PPH_CM_COLUMN PhCmCreateColumn( + _Inout_ PPH_CM_MANAGER Manager, + _In_ PPH_TREENEW_COLUMN Column, + _In_ struct _PV_SYMBOL_NODE *Symbol, + _In_ ULONG SubId, + _In_opt_ PVOID Context, + _In_ PVOID SortFunction + ) +{ + PPH_CM_COLUMN column; + PH_TREENEW_COLUMN tnColumn; + + column = PhAllocate(sizeof(PH_CM_COLUMN)); + memset(column, 0, sizeof(PH_CM_COLUMN)); + column->Id = Manager->NextId++; + //column->Symbol = Symbol; + column->SubId = SubId; + column->Context = Context; + column->SortFunction = SortFunction; + InsertTailList(&Manager->ColumnListHead, &column->ListEntry); + + memset(&tnColumn, 0, sizeof(PH_TREENEW_COLUMN)); + tnColumn.Id = column->Id; + tnColumn.Context = column; + tnColumn.Visible = Column->Visible; + tnColumn.CustomDraw = Column->CustomDraw; + tnColumn.SortDescending = Column->SortDescending; + tnColumn.Text = Column->Text; + tnColumn.Width = Column->Width; + tnColumn.Alignment = Column->Alignment; + tnColumn.DisplayIndex = Column->Visible ? Column->DisplayIndex : -1; + tnColumn.TextFlags = Column->TextFlags; + TreeNew_AddColumn(Manager->Handle, &tnColumn); + + return column; +} + +VOID PhCmSetNotifyPlugin( + _In_ PPH_CM_MANAGER Manager, + _In_ struct _PH_PLUGIN *Plugin + ) +{ + if (!Manager->NotifyList) + { + Manager->NotifyList = PhCreateList(8); + } + else + { + if (PhFindItemList(Manager->NotifyList, Plugin) != -1) + return; + } + + PhAddItemList(Manager->NotifyList, Plugin); +} + +PPH_CM_COLUMN PhCmFindColumn( + _In_ PPH_CM_MANAGER Manager, + _In_ PPH_STRINGREF PluginName, + _In_ ULONG SubId + ) +{ + PLIST_ENTRY listEntry; + PPH_CM_COLUMN column; + + listEntry = Manager->ColumnListHead.Flink; + + while (listEntry != &Manager->ColumnListHead) + { + column = CONTAINING_RECORD(listEntry, PH_CM_COLUMN, ListEntry); + + if (column->SubId == SubId && PhEqualStringRef(PluginName, &column->Symbol->Name->sr, FALSE)) + return column; + + listEntry = listEntry->Flink; + } + + return NULL; +} + +BOOLEAN PhCmLoadSettingsEx( + _In_ HWND TreeNewHandle, + _In_opt_ PPH_CM_MANAGER Manager, + _In_ ULONG Flags, + _In_ PPH_STRINGREF Settings, + _In_opt_ PPH_STRINGREF SortSettings + ) +{ + BOOLEAN result = FALSE; + PH_STRINGREF scalePart; + PH_STRINGREF columnPart; + PH_STRINGREF remainingColumnPart; + PH_STRINGREF valuePart; + PH_STRINGREF subPart; + ULONG64 integer; + ULONG scale; + ULONG total; + BOOLEAN hasFixedColumn; + ULONG count; + ULONG i; + PPH_HASHTABLE columnHashtable; + PH_HASHTABLE_ENUM_CONTEXT enumContext; + PPH_KEY_VALUE_PAIR pair; + LONG orderArray[PH_CM_ORDER_LIMIT]; + LONG maxOrder; + + if (Settings->Length != 0) + { + columnHashtable = PhCreateSimpleHashtable(20); + + remainingColumnPart = *Settings; + + if (remainingColumnPart.Length != 0 && remainingColumnPart.Buffer[0] == '@') + { + PhSkipStringRef(&remainingColumnPart, sizeof(WCHAR)); + PhSplitStringRefAtChar(&remainingColumnPart, '|', &scalePart, &remainingColumnPart); + + if (scalePart.Length == 0 || !PhStringToInteger64(&scalePart, 10, &integer)) + goto CleanupExit; + + scale = (ULONG)integer; + } + else + { + scale = PhGlobalDpi; + } + + while (remainingColumnPart.Length != 0) + { + PPH_TREENEW_COLUMN column; + ULONG id; + ULONG displayIndex; + ULONG width; + + PhSplitStringRefAtChar(&remainingColumnPart, '|', &columnPart, &remainingColumnPart); + + if (columnPart.Length != 0) + { + // Id + + PhSplitStringRefAtChar(&columnPart, ',', &valuePart, &columnPart); + + if (valuePart.Length == 0) + goto CleanupExit; + + if (valuePart.Buffer[0] == '+') + { + PH_STRINGREF pluginName; + ULONG subId; + PPH_CM_COLUMN cmColumn; + + // This is a plugin-owned column. + + if (!Manager) + continue; + if (!PhEmParseCompoundId(&valuePart, &pluginName, &subId)) + continue; + + cmColumn = PhCmFindColumn(Manager, &pluginName, subId); + + if (!cmColumn) + continue; // can't find the column, skip this part + + id = cmColumn->Id; + } + else + { + if (!PhStringToInteger64(&valuePart, 10, &integer)) + goto CleanupExit; + + id = (ULONG)integer; + } + + // Display Index + + PhSplitStringRefAtChar(&columnPart, ',', &valuePart, &columnPart); + + if (!(Flags & PH_CM_COLUMN_WIDTHS_ONLY)) + { + if (valuePart.Length == 0 || !PhStringToInteger64(&valuePart, 10, &integer)) + goto CleanupExit; + + displayIndex = (ULONG)integer; + } + else + { + if (valuePart.Length != 0) + goto CleanupExit; + + displayIndex = -1; + } + + // Width + + if (columnPart.Length == 0 || !PhStringToInteger64(&columnPart, 10, &integer)) + goto CleanupExit; + + width = (ULONG)integer; + + if (scale != PhGlobalDpi && scale != 0) + width = PhMultiplyDivide(width, PhGlobalDpi, scale); + + column = PhAllocate(sizeof(PH_TREENEW_COLUMN)); + column->Id = id; + column->DisplayIndex = displayIndex; + column->Width = width; + PhAddItemSimpleHashtable(columnHashtable, UlongToPtr(column->Id), column); + } + } + + TreeNew_SetRedraw(TreeNewHandle, FALSE); + + // Set visibility and width. + + i = 0; + count = 0; + total = TreeNew_GetColumnCount(TreeNewHandle); + hasFixedColumn = !!TreeNew_GetFixedColumn(TreeNewHandle); + memset(orderArray, 0, sizeof(orderArray)); + maxOrder = 0; + + while (count < total) + { + PH_TREENEW_COLUMN setColumn; + PPH_TREENEW_COLUMN *columnPtr; + + if (TreeNew_GetColumn(TreeNewHandle, i, &setColumn)) + { + columnPtr = (PPH_TREENEW_COLUMN *)PhFindItemSimpleHashtable(columnHashtable, UlongToPtr(i)); + + if (!(Flags & PH_CM_COLUMN_WIDTHS_ONLY)) + { + if (columnPtr) + { + setColumn.Visible = TRUE; + setColumn.Width = (*columnPtr)->Width; + TreeNew_SetColumn(TreeNewHandle, TN_COLUMN_FLAG_VISIBLE | TN_COLUMN_WIDTH, &setColumn); + + if (!setColumn.Fixed) + { + // For compatibility reasons, normal columns have their display indicies stored + // one higher than usual (so they start from 1, not 0). Fix that here. + if (hasFixedColumn && (*columnPtr)->DisplayIndex != 0) + (*columnPtr)->DisplayIndex--; + + if ((*columnPtr)->DisplayIndex < PH_CM_ORDER_LIMIT) + { + orderArray[(*columnPtr)->DisplayIndex] = i; + + if ((ULONG)maxOrder < (*columnPtr)->DisplayIndex + 1) + maxOrder = (*columnPtr)->DisplayIndex + 1; + } + } + } + else if (!setColumn.Fixed) // never hide the fixed column + { + setColumn.Visible = FALSE; + TreeNew_SetColumn(TreeNewHandle, TN_COLUMN_FLAG_VISIBLE, &setColumn); + } + } + else + { + if (columnPtr) + { + setColumn.Width = (*columnPtr)->Width; + TreeNew_SetColumn(TreeNewHandle, TN_COLUMN_WIDTH, &setColumn); + } + } + + count++; + } + + i++; + } + + if (!(Flags & PH_CM_COLUMN_WIDTHS_ONLY)) + { + // Set the order array. + TreeNew_SetColumnOrderArray(TreeNewHandle, maxOrder, orderArray); + } + + TreeNew_SetRedraw(TreeNewHandle, TRUE); + + result = TRUE; + +CleanupExit: + PhBeginEnumHashtable(columnHashtable, &enumContext); + + while (pair = PhNextEnumHashtable(&enumContext)) + PhFree(pair->Value); + + PhDereferenceObject(columnHashtable); + } + + // Load sort settings. + + if (SortSettings && SortSettings->Length != 0) + { + PhSplitStringRefAtChar(SortSettings, ',', &valuePart, &subPart); + + if (valuePart.Length != 0 && subPart.Length != 0) + { + ULONG sortColumn; + PH_SORT_ORDER sortOrder; + + sortColumn = -1; + + if (valuePart.Buffer[0] == '+') + { + PH_STRINGREF pluginName; + ULONG subId; + PPH_CM_COLUMN cmColumn; + + if ( + Manager && + PhEmParseCompoundId(&valuePart, &pluginName, &subId) && + (cmColumn = PhCmFindColumn(Manager, &pluginName, subId)) + ) + { + sortColumn = cmColumn->Id; + } + } + else + { + PhStringToInteger64(&valuePart, 10, &integer); + sortColumn = (ULONG)integer; + } + + PhStringToInteger64(&subPart, 10, &integer); + sortOrder = (PH_SORT_ORDER)integer; + + if (sortColumn != -1 && sortOrder <= DescendingSortOrder) + { + TreeNew_SetSort(TreeNewHandle, sortColumn, sortOrder); + } + } + } + + return result; +} + +BOOLEAN PhCmLoadSettings( + _In_ HWND TreeNewHandle, + _In_ PPH_STRINGREF Settings + ) +{ + return PhCmLoadSettingsEx(TreeNewHandle, NULL, 0, Settings, NULL); +} + +PPH_STRING PhCmSaveSettingsEx( + _In_ HWND TreeNewHandle, + _In_opt_ PPH_CM_MANAGER Manager, + _In_ ULONG Flags, + _Out_opt_ PPH_STRING *SortSettings + ) +{ + PH_STRING_BUILDER stringBuilder; + ULONG i = 0; + ULONG count = 0; + ULONG total; + ULONG increment; + PH_TREENEW_COLUMN column; + + total = TreeNew_GetColumnCount(TreeNewHandle); + + if (TreeNew_GetFixedColumn(TreeNewHandle)) + increment = 1; // the first normal column should have a display index that starts with 1, for compatibility + else + increment = 0; + + PhInitializeStringBuilder(&stringBuilder, 100); + + PhAppendFormatStringBuilder(&stringBuilder, L"@%u|", PhGlobalDpi); + + while (count < total) + { + if (TreeNew_GetColumn(TreeNewHandle, i, &column)) + { + if (!(Flags & PH_CM_COLUMN_WIDTHS_ONLY)) + { + if (column.Visible) + { + if (!Manager || i < Manager->MinId) + { + PhAppendFormatStringBuilder( + &stringBuilder, + L"%u,%u,%u|", + i, + column.Fixed ? 0 : column.DisplayIndex + increment, + column.Width + ); + } + else + { + PPH_CM_COLUMN cmColumn; + + cmColumn = column.Context; + PhAppendFormatStringBuilder( + &stringBuilder, + L"+%u,%u,%u|", + cmColumn->SubId, + column.DisplayIndex + increment, + column.Width + ); + } + } + } + else + { + if (!Manager || i < Manager->MinId) + { + PhAppendFormatStringBuilder( + &stringBuilder, + L"%u,,%u|", + i, + column.Width + ); + } + else + { + PPH_CM_COLUMN cmColumn; + + cmColumn = column.Context; + PhAppendFormatStringBuilder( + &stringBuilder, + L"+%u,,%u|", + cmColumn->SubId, + column.Width + ); + } + } + + count++; + } + + i++; + } + + if (stringBuilder.String->Length != 0) + PhRemoveEndStringBuilder(&stringBuilder, 1); + + if (SortSettings) + { + ULONG sortColumn; + PH_SORT_ORDER sortOrder; + + if (TreeNew_GetSort(TreeNewHandle, &sortColumn, &sortOrder)) + { + if (sortOrder != NoSortOrder) + { + if (!Manager || sortColumn < Manager->MinId) + { + *SortSettings = PhFormatString(L"%u,%u", sortColumn, sortOrder); + } + else + { + PH_TREENEW_COLUMN column; + PPH_CM_COLUMN cmColumn; + + if (TreeNew_GetColumn(TreeNewHandle, sortColumn, &column)) + { + cmColumn = column.Context; + *SortSettings = PhFormatString(L"+%u,%u", cmColumn->SubId, sortOrder); + } + else + { + *SortSettings = PhReferenceEmptyString(); + } + } + } + else + { + *SortSettings = PhCreateString(L"0,0"); + } + } + else + { + *SortSettings = PhReferenceEmptyString(); + } + } + + return PhFinalStringBuilderString(&stringBuilder); +} + +PPH_STRING PhCmSaveSettings( + _In_ HWND TreeNewHandle + ) +{ + return PhCmSaveSettingsEx(TreeNewHandle, NULL, 0, NULL); +} diff --git a/tools/peview/colmgr.h b/tools/peview/colmgr.h new file mode 100644 index 000000000000..e6c54cc03b22 --- /dev/null +++ b/tools/peview/colmgr.h @@ -0,0 +1,87 @@ +#ifndef PH_COLMGR_H +#define PH_COLMGR_H + +#define PH_CM_ORDER_LIMIT 160 + +// begin_phapppub +typedef LONG (NTAPI *PPH_CM_POST_SORT_FUNCTION)( + _In_ LONG Result, + _In_ PVOID Node1, + _In_ PVOID Node2, + _In_ PH_SORT_ORDER SortOrder + ); +// end_phapppub + +typedef struct _PH_CM_MANAGER +{ + HWND Handle; + ULONG MinId; + ULONG NextId; + PPH_CM_POST_SORT_FUNCTION PostSortFunction; + LIST_ENTRY ColumnListHead; + PPH_LIST NotifyList; +} PH_CM_MANAGER, *PPH_CM_MANAGER; + +typedef struct _PH_CM_COLUMN +{ + LIST_ENTRY ListEntry; + ULONG Id; + struct _PV_SYMBOL_NODE *Symbol; + ULONG SubId; + PVOID Context; + PVOID SortFunction; +} PH_CM_COLUMN, *PPH_CM_COLUMN; + +VOID PhCmInitializeManager( + _Out_ PPH_CM_MANAGER Manager, + _In_ HWND Handle, + _In_ ULONG MinId, + _In_ PPH_CM_POST_SORT_FUNCTION PostSortFunction + ); + +VOID PhCmDeleteManager( + _In_ PPH_CM_MANAGER Manager + ); + +PPH_CM_COLUMN PhCmCreateColumn( + _Inout_ PPH_CM_MANAGER Manager, + _In_ PPH_TREENEW_COLUMN Column, + _In_ struct _PV_SYMBOL_NODE *Plugin, + _In_ ULONG SubId, + _In_opt_ PVOID Context, + _In_ PVOID SortFunction + ); + +PPH_CM_COLUMN PhCmFindColumn( + _In_ PPH_CM_MANAGER Manager, + _In_ PPH_STRINGREF PluginName, + _In_ ULONG SubId + ); + +BOOLEAN PhCmLoadSettings( + _In_ HWND TreeNewHandle, + _In_ PPH_STRINGREF Settings + ); + +#define PH_CM_COLUMN_WIDTHS_ONLY 0x1 + +BOOLEAN PhCmLoadSettingsEx( + _In_ HWND TreeNewHandle, + _In_opt_ PPH_CM_MANAGER Manager, + _In_ ULONG Flags, + _In_ PPH_STRINGREF Settings, + _In_opt_ PPH_STRINGREF SortSettings + ); + +PPH_STRING PhCmSaveSettings( + _In_ HWND TreeNewHandle + ); + +PPH_STRING PhCmSaveSettingsEx( + _In_ HWND TreeNewHandle, + _In_opt_ PPH_CM_MANAGER Manager, + _In_ ULONG Flags, + _Out_opt_ PPH_STRING *SortSettings + ); + +#endif diff --git a/tools/peview/include/pdb.h b/tools/peview/include/pdb.h index b21ac2d946c7..966415a1844e 100644 --- a/tools/peview/include/pdb.h +++ b/tools/peview/include/pdb.h @@ -112,15 +112,14 @@ typedef enum _CV_HREG_e { // Only a limited number of registers included here - CV_REG_EAX = 17, - CV_REG_ECX = 18, - CV_REG_EDX = 19, - CV_REG_EBX = 20, - CV_REG_ESP = 21, - CV_REG_EBP = 22, - CV_REG_ESI = 23, - CV_REG_EDI = 24, - + CV_REG_EAX = 17, + CV_REG_ECX = 18, + CV_REG_EDX = 19, + CV_REG_EBX = 20, + CV_REG_ESP = 21, + CV_REG_EBP = 22, + CV_REG_ESI = 23, + CV_REG_EDI = 24, } CV_HREG_e; // LocatonType, originally from CVCONST.H in DIA SDK @@ -361,8 +360,7 @@ typedef struct _TypeInfo // a class or a structure, "false" if the symbol is a union) BOOL UdtKind; - // Union of all type information structures - union // TypeInfoStructures + union { BaseTypeInfo sBaseTypeInfo; // If Tag == SymTagBaseType TypedefInfo sTypedefInfo; // If Tag == SymTagTypedef @@ -378,13 +376,6 @@ typedef struct _TypeInfo }; } TypeInfo; -typedef struct _PDB_SYMBOL_CONTEXT -{ - HWND ListviewHandle; - ULONG64 BaseAddress; - PPH_LIST UdtList; -} PDB_SYMBOL_CONTEXT, *PPDB_SYMBOL_CONTEXT; - BOOLEAN SymbolInfo_DumpBasicType(_Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, BaseTypeInfo* Info); BOOLEAN SymbolInfo_DumpPointerType(_Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, PointerTypeInfo* Info); BOOLEAN SymbolInfo_DumpTypedef(_Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, TypedefInfo* Info); @@ -422,15 +413,16 @@ BOOLEAN SymbolInfo_GetTypeNameHelper( _In_ ULONG Index, _Inout_ PPDB_SYMBOL_CONTEXT Context, _Out_ PWSTR *VarName, - _Out_ PWSTR *TypeName + _Inout_ PPH_STRING_BUILDER TypeName ); + BOOLEAN SymbolInfo_GetTypeName( _Inout_ PPDB_SYMBOL_CONTEXT Context, + _Inout_ PPH_STRING_BUILDER TypeName, _In_ ULONG Index, - _In_ PWSTR pVarName, - _In_ PWSTR pTypeName, - _In_ ULONG MaxChars + _In_ PWSTR VarName ); + PWSTR SymbolInfo_TagStr(enum SymTagEnum Tag); PWSTR SymbolInfo_BaseTypeStr(BasicType Type, ULONG64 Length); PWSTR SymbolInfo_CallConvStr(CV_call_e CallConv); @@ -441,22 +433,6 @@ PWSTR SymbolInfo_RegisterStr(CV_HREG_e RegCode); PWSTR SymbolInfo_UdtKindStr(UdtKind KindType); PWSTR SymbolInfo_LocationTypeStr(LocationType LocType); - -VOID PrintDataInfo( - _In_ PPDB_SYMBOL_CONTEXT Context, - _In_ PSYMBOL_INFOW SymbolInfo - ); - -VOID PrintFunctionInfo( - _In_ PPDB_SYMBOL_CONTEXT Context, - _In_ PSYMBOL_INFOW SymbolInfo - ); - -VOID PrintDefaultInfo( - _In_ PPDB_SYMBOL_CONTEXT Context, - _In_ PSYMBOL_INFOW SymbolInfo - ); - VOID PrintClassInfo( _In_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, diff --git a/tools/peview/include/peview.h b/tools/peview/include/peview.h index 04a3cb8152a2..69987ec41906 100644 --- a/tools/peview/include/peview.h +++ b/tools/peview/include/peview.h @@ -2,12 +2,15 @@ #define PEVIEW_H #include +#include #include #include #include #include +#include #include #include +#include #include @@ -57,6 +60,118 @@ VOID PeSaveSettings( // symbols + +typedef enum _WCT_TREE_COLUMN_ITEM_NAME +{ + TREE_COLUMN_ITEM_TYPE, + TREE_COLUMN_ITEM_VA, + TREE_COLUMN_ITEM_NAME, + TREE_COLUMN_ITEM_SYMBOL, + TREE_COLUMN_ITEM_MAXIMUM +} WCT_TREE_COLUMN_ITEM_NAME; + +typedef enum _PV_SYMBOL_TYPE +{ + PV_SYMBOL_TYPE_NONE, + PV_SYMBOL_TYPE_FUNCTION, + PV_SYMBOL_TYPE_SYMBOL, + PV_SYMBOL_TYPE_LOCAL_VAR, + PV_SYMBOL_TYPE_STATIC_LOCAL_VAR, + PV_SYMBOL_TYPE_PARAMETER, + PV_SYMBOL_TYPE_OBJECT_PTR, + PV_SYMBOL_TYPE_STATIC_VAR, + PV_SYMBOL_TYPE_GLOBAL_VAR, + PV_SYMBOL_TYPE_MEMBER, + PV_SYMBOL_TYPE_STATIC_MEMBER, + PV_SYMBOL_TYPE_CONSTANT +} PV_SYMBOL_TYPE; + +typedef struct _PV_SYMBOL_NODE +{ + PH_TREENEW_NODE Node; + + PV_SYMBOL_TYPE Type; + ULONG Size; + ULONG64 Address; + PPH_STRING Name; + PPH_STRING Data; + WCHAR Pointer[PH_PTR_STR_LEN_1]; + + PH_STRINGREF TextCache[TREE_COLUMN_ITEM_MAXIMUM]; +} PV_SYMBOL_NODE, *PPV_SYMBOL_NODE; + + +typedef struct _PH_TN_FILTER_SUPPORT +{ + PPH_LIST FilterList; + HWND TreeNewHandle; + PPH_LIST NodeList; +} PH_TN_FILTER_SUPPORT, *PPH_TN_FILTER_SUPPORT; + +typedef BOOLEAN (NTAPI *PPH_TN_FILTER_FUNCTION)( + _In_ PPH_TREENEW_NODE Node, + _In_opt_ PVOID Context + ); + +typedef struct _PH_TN_FILTER_ENTRY +{ + PPH_TN_FILTER_FUNCTION Filter; + PVOID Context; +} PH_TN_FILTER_ENTRY, *PPH_TN_FILTER_ENTRY; + +VOID PhInitializeTreeNewFilterSupport( + _Out_ PPH_TN_FILTER_SUPPORT Support, + _In_ HWND TreeNewHandle, + _In_ PPH_LIST NodeList + ); + +VOID PhDeleteTreeNewFilterSupport( + _In_ PPH_TN_FILTER_SUPPORT Support + ); + +PPH_TN_FILTER_ENTRY PhAddTreeNewFilter( + _In_ PPH_TN_FILTER_SUPPORT Support, + _In_ PPH_TN_FILTER_FUNCTION Filter, + _In_opt_ PVOID Context + ); + +VOID PhRemoveTreeNewFilter( + _In_ PPH_TN_FILTER_SUPPORT Support, + _In_ PPH_TN_FILTER_ENTRY Entry + ); + +BOOLEAN PhApplyTreeNewFiltersToNode( + _In_ PPH_TN_FILTER_SUPPORT Support, + _In_ PPH_TREENEW_NODE Node + ); + +VOID PhApplyTreeNewFilters( + _In_ PPH_TN_FILTER_SUPPORT Support + ); + +typedef struct _PDB_SYMBOL_CONTEXT +{ + HWND DialogHandle; + HWND SearchHandle; + HWND TreeNewHandle; + HWND ParentWindowHandle; + + ULONG64 BaseAddress; + PPH_STRING FileName; + PPH_STRING SearchboxText; + PPH_STRING TreeText; + PPH_LIST SymbolList; + PPH_LIST UdtList; + + PH_LAYOUT_MANAGER LayoutManager; + + ULONG TreeNewSortColumn; + PH_SORT_ORDER TreeNewSortOrder; + PH_TN_FILTER_SUPPORT FilterSupport; + PPH_HASHTABLE NodeHashtable; + PPH_LIST NodeList; +} PDB_SYMBOL_CONTEXT, *PPDB_SYMBOL_CONTEXT; + INT_PTR CALLBACK PvpSymbolsDlgProc( _In_ HWND hwndDlg, _In_ UINT uMsg, @@ -64,15 +179,19 @@ INT_PTR CALLBACK PvpSymbolsDlgProc( _In_ LPARAM lParam ); -VOID PeDumpFileSymbols( - _In_ HWND ListViewHandle, - _In_ PWSTR FileName +NTSTATUS PeDumpFileSymbols( + _In_ PPDB_SYMBOL_CONTEXT Context ); VOID PvPdbProperties( VOID ); +VOID PluginsAddTreeNode( + _In_ PPDB_SYMBOL_CONTEXT Context, + _In_ PPV_SYMBOL_NODE Entry + ); + // INT_PTR CALLBACK PvpPeImportsDlgProc( diff --git a/tools/peview/main.c b/tools/peview/main.c index 4c845c4e9193..a8de840ebf1a 100644 --- a/tools/peview/main.c +++ b/tools/peview/main.c @@ -71,6 +71,7 @@ INT WINAPI wWinMain( PhSettingsInitialization(); PeInitializeSettings(); PvPropInitialization(); + PhTreeNewInitialization(); PhApplicationName = L"PE Viewer"; @@ -123,8 +124,8 @@ INT WINAPI wWinMain( if (PhEndsWithString2(PvFileName, L".lib", TRUE)) PvLibProperties(); - //else if (PhEndsWithString2(PvFileName, L".pdb", TRUE)) - // PvPdbProperties(); + else if (PhEndsWithString2(PvFileName, L".pdb", TRUE)) + PvPdbProperties(); else PvPeProperties(); diff --git a/tools/peview/pdb.c b/tools/peview/pdb.c index 19fc41cdcde2..039dc60454e3 100644 --- a/tools/peview/pdb.c +++ b/tools/peview/pdb.c @@ -21,6 +21,7 @@ */ #include +#include #include #include #include @@ -691,9 +692,8 @@ BOOLEAN SymbolInfo_DumpType( ) { ULONG tag = SymTagNull; - BOOLEAN result = FALSE; - // Get the symbol's tag + // Get the symbol tag if (!SymGetTypeInfo_I( NtCurrentProcess(), Context->BaseAddress, @@ -711,38 +711,28 @@ BOOLEAN SymbolInfo_DumpType( switch (tag) { case SymTagBaseType: - result = SymbolInfo_DumpBasicType(Context, Index, &Info->sBaseTypeInfo); - break; + return SymbolInfo_DumpBasicType(Context, Index, &Info->sBaseTypeInfo); case SymTagPointerType: - result = SymbolInfo_DumpPointerType(Context, Index, &Info->sPointerTypeInfo); - break; + return SymbolInfo_DumpPointerType(Context, Index, &Info->sPointerTypeInfo); case SymTagTypedef: - result = SymbolInfo_DumpTypedef(Context, Index, &Info->sTypedefInfo); - break; + return SymbolInfo_DumpTypedef(Context, Index, &Info->sTypedefInfo); case SymTagEnum: - result = SymbolInfo_DumpEnum(Context, Index, &Info->sEnumInfo); - break; + return SymbolInfo_DumpEnum(Context, Index, &Info->sEnumInfo); case SymTagArrayType: - result = SymbolInfo_DumpArrayType(Context, Index, &Info->sArrayTypeInfo); - break; + return SymbolInfo_DumpArrayType(Context, Index, &Info->sArrayTypeInfo); case SymTagUDT: - result = SymbolInfo_DumpUDT(Context, Index, Info); - break; + return SymbolInfo_DumpUDT(Context, Index, Info); case SymTagFunctionType: - result = SymbolInfo_DumpFunctionType(Context, Index, &Info->sFunctionTypeInfo); - break; + return SymbolInfo_DumpFunctionType(Context, Index, &Info->sFunctionTypeInfo); case SymTagFunctionArgType: - result = SymbolInfo_DumpFunctionArgType(Context, Index, &Info->sFunctionArgTypeInfo); - break; + return SymbolInfo_DumpFunctionArgType(Context, Index, &Info->sFunctionArgTypeInfo); case SymTagBaseClass: - result = SymbolInfo_DumpBaseClass(Context, Index, &Info->sBaseClassInfo); - break; + return SymbolInfo_DumpBaseClass(Context, Index, &Info->sBaseClassInfo); case SymTagData: - result = SymbolInfo_DumpData(Context, Index, &Info->sDataInfo); - break; + return SymbolInfo_DumpData(Context, Index, &Info->sDataInfo); } - return result; + return FALSE; } BOOLEAN SymbolInfo_DumpSymbolType( @@ -1325,7 +1315,7 @@ BOOLEAN SymbolInfo_GetTypeNameHelper( _In_ ULONG Index, _Inout_ PPDB_SYMBOL_CONTEXT Obj, _Out_ PWSTR *VarName, - _Out_ PWSTR *TypeName + _Inout_ PPH_STRING_BUILDER TypeName ) { TypeInfo Info; @@ -1361,11 +1351,13 @@ BOOLEAN SymbolInfo_GetTypeNameHelper( switch (Info.Tag) { case SymTagBaseType: - *TypeName = SymbolInfo_BaseTypeStr(Info.sBaseTypeInfo.BaseType, Info.sBaseTypeInfo.Length); + PhAppendStringBuilder2(TypeName, SymbolInfo_BaseTypeStr(Info.sBaseTypeInfo.BaseType, Info.sBaseTypeInfo.Length)); + PhAppendStringBuilder2(TypeName, L" "); break; case SymTagTypedef: - *TypeName = _wcsdup(Info.sTypedefInfo.Name); + PhAppendStringBuilder2(TypeName, Info.sTypedefInfo.Name); + PhAppendStringBuilder2(TypeName, L" "); break; case SymTagUDT: @@ -1373,7 +1365,8 @@ BOOLEAN SymbolInfo_GetTypeNameHelper( if (Info.UdtKind) { // A class/structure - *TypeName = _wcsdup(Info.sUdtClassInfo.Name); + PhAppendStringBuilder2(TypeName, Info.sUdtClassInfo.Name); + PhAppendStringBuilder2(TypeName, L" "); // Add the UDT and its base classes to the collection of UDT indexes PhAddItemList(Obj->UdtList, UlongToPtr(Index)); @@ -1381,30 +1374,30 @@ BOOLEAN SymbolInfo_GetTypeNameHelper( else { // A union - *TypeName = _wcsdup(Info.sUdtUnionInfo.Name); + PhAppendStringBuilder2(TypeName, Info.sUdtUnionInfo.Name); + PhAppendStringBuilder2(TypeName, L" "); } } break; case SymTagEnum: - *TypeName = _wcsdup(Info.sEnumInfo.Name); + PhAppendStringBuilder2(TypeName, Info.sEnumInfo.Name); break; case SymTagFunctionType: { if (Info.sFunctionTypeInfo.MemberFunction && Info.sFunctionTypeInfo.StaticFunction) { - //*TypeName = L"static "; + PhAppendStringBuilder2(TypeName, L"static "); } - // Print return value + // return value if (!SymbolInfo_GetTypeNameHelper(Info.sFunctionTypeInfo.RetTypeIndex, Obj, VarName, TypeName)) return FALSE; - // Print calling convention - //TypeName += " "; - //TypeName += SymbolInfo_CallConvStr(Info.Info.sFunctionTypeInfo.CallConv); - //TypeName += " "; + // calling convention + PhAppendStringBuilder2(TypeName, SymbolInfo_CallConvStr(Info.sFunctionTypeInfo.CallConv)); + PhAppendStringBuilder2(TypeName, L" "); // If member function, save the class type index if (Info.sFunctionTypeInfo.MemberFunction) @@ -1412,39 +1405,42 @@ BOOLEAN SymbolInfo_GetTypeNameHelper( PhAddItemList(Obj->UdtList, UlongToPtr(Info.sFunctionTypeInfo.ClassIndex)); /* - // It is not needed to print the class name here, because - // it is contained in the function name - if( !SymbolInfo_GetTypeNameHelper( Info.Info.sFunctionTypeInfo.ClassIndex, Obj, VarName, TypeName ) ) + // It is not needed to print the class name here, because it is contained in the function name + if (!SymbolInfo_GetTypeNameHelper(Info.sFunctionTypeInfo.ClassIndex, Obj, VarName, TypeName)) return false; - TypeName += "::"); */ } // Print that it is a function - //TypeName += VarName; + PhAppendStringBuilder2(TypeName, *VarName); + // Print parameters - //TypeName += " ("; + PhAppendStringBuilder2(TypeName, L" ("); + for (ULONG i = 0; i < Info.sFunctionTypeInfo.NumArgs; i++) { if (!SymbolInfo_GetTypeNameHelper(Info.sFunctionTypeInfo.Args[i], Obj, VarName, TypeName)) return FALSE; - //if (i < (Info.sFunctionTypeInfo.NumArgs - 1)) - //TypeName += ", "; + if (i < (Info.sFunctionTypeInfo.NumArgs - 1)) + { + PhAppendStringBuilder2(TypeName, L", "); + } } - //TypeName += ")"; + + PhAppendStringBuilder2(TypeName, L") "); // Print "this" adjustment value if (Info.sFunctionTypeInfo.MemberFunction && Info.sFunctionTypeInfo.ThisAdjust != 0) { WCHAR buffer[MAX_PATH + 1] = L""; - //TypeName += "ThisAdjust: "; _snwprintf(buffer, ARRAYSIZE(buffer), L"this+%u", Info.sFunctionTypeInfo.ThisAdjust); - //TypeName += buffer; - *TypeName = _wcsdup(buffer); + PhAppendStringBuilder2(TypeName, L": "); + PhAppendStringBuilder2(TypeName, buffer); + PhAppendStringBuilder2(TypeName, L" "); } } break; @@ -1462,15 +1458,17 @@ BOOLEAN SymbolInfo_GetTypeNameHelper( if (!SymbolInfo_GetTypeNameHelper(Info.sArrayTypeInfo.ElementTypeIndex, Obj, VarName, TypeName)) return FALSE; - //TypeName += " "; - //TypeName += VarName; + PhAppendStringBuilder2(TypeName, L" "); + //PhAppendStringBuilder2(TypeName, *VarName); // Print dimensions for (ULONG i = 0; i < Info.sArrayTypeInfo.NumDimensions; i++) { - //WCHAR buffer[MAX_PATH + 1] = L""; - //_snwprintf(buffer, cTempBufSize, "[%u]"), Info.Info.sArrayTypeInfo.Dimensions[i]); - //TypeName += buffer; + WCHAR buffer[MAX_PATH + 1] = L""; + + _snwprintf(buffer, ARRAYSIZE(buffer), L"[%I64u]", Info.sArrayTypeInfo.Dimensions[i]); + + PhAppendStringBuilder2(TypeName, buffer); } } break; @@ -1480,7 +1478,7 @@ BOOLEAN SymbolInfo_GetTypeNameHelper( _snwprintf(buffer, ARRAYSIZE(buffer), L"Unknown(%lu)", Info.Tag); - *TypeName = _wcsdup(buffer); + PhAppendStringBuilder2(TypeName, buffer); } break; } @@ -1488,8 +1486,8 @@ BOOLEAN SymbolInfo_GetTypeNameHelper( // If it is a pointer, display * characters if (numPointers != 0) { - //for (ULONG i = 0; i < NumPointers; i++) - // TypeName += "*"; + for (ULONG i = 0; i < numPointers; i++) + PhAppendStringBuilder2(TypeName, L"*"); } } @@ -1498,30 +1496,22 @@ BOOLEAN SymbolInfo_GetTypeNameHelper( BOOLEAN SymbolInfo_GetTypeName( _Inout_ PPDB_SYMBOL_CONTEXT Context, + _Inout_ PPH_STRING_BUILDER TypeName, _In_ ULONG Index, - _In_ PWSTR pVarName, - _In_ PWSTR pTypeName, - _In_ ULONG MaxChars + _In_ PWSTR VarName ) { - PWSTR VarName = NULL; - PWSTR TypeName = NULL; - - if (!pTypeName) - return FALSE; + PWSTR typeVarName = NULL; - if (pVarName) - VarName = pVarName; + if (VarName) + typeVarName = VarName; // Obtain the type name - if (!SymbolInfo_GetTypeNameHelper(Index, Context, &VarName, &TypeName)) - return FALSE; - - if (!wcslen(TypeName)) + if (!SymbolInfo_GetTypeNameHelper(Index, Context, &typeVarName, TypeName)) return FALSE; // Return the type name to the caller - _snwprintf(pTypeName, MaxChars, L"%s", TypeName); + //_snwprintf(pTypeName, MaxChars, L"%s", TypeName.String->Buffer); return TRUE; } @@ -1804,9 +1794,7 @@ VOID SymbolInfo_SymbolLocationStr( if (regString) wcscpy(Buffer, regString); else - _swprintf(Buffer, L"Reg%u", SymbolInfo->Register); - - return; + _swprintf(Buffer, L"Reg+%u", SymbolInfo->Register); } else if (SymbolInfo->Flags & SYMFLAG_REGREL) { @@ -1816,16 +1804,13 @@ VOID SymbolInfo_SymbolLocationStr( if (regString) wcscpy(szReg, regString); else - _swprintf(szReg, L"Reg%u", SymbolInfo->Register); - - _swprintf(Buffer, L"%s%+lu", szReg, (long)SymbolInfo->Address); + _swprintf(szReg, L"Reg+%u", SymbolInfo->Register); - return; + _swprintf(Buffer, L"%s+%I64u", szReg, SymbolInfo->Address); } else if (SymbolInfo->Flags & SYMFLAG_FRAMEREL) { wcscpy(Buffer, L"N/A"); - return; } else { @@ -1918,127 +1903,148 @@ BOOL CALLBACK EnumCallbackProc( _In_ PVOID Context ) { - if (!SymbolInfo) // Try to enumerate other symbols - return TRUE; - - switch (SymbolInfo->Tag) + if (SymbolInfo) { - case SymTagFunction: - PrintFunctionInfo(Context, SymbolInfo); - break; - case SymTagData: - PrintDataInfo(Context, SymbolInfo); - break; - default: - PrintDefaultInfo(Context, SymbolInfo); - break; - } - - return TRUE; -} - -VOID PrintDataInfo( - _In_ PPDB_SYMBOL_CONTEXT Context, - _In_ PSYMBOL_INFOW SymbolInfo - ) -{ - INT lvItemIndex; - PWSTR symDataKind; - WCHAR pointer[PH_PTR_STR_LEN_1] = L""; - - if (SymbolInfo->Tag != SymTagData) - return; - - // Type - symDataKind = SymbolInfo_DataKindFromSymbolInfo(SymbolInfo); - lvItemIndex = PhAddListViewItem(Context->ListviewHandle, MAXINT, symDataKind, NULL); + switch (SymbolInfo->Tag) + { + case SymTagFunction: + { + PPDB_SYMBOL_CONTEXT context = Context; + PH_STRING_BUILDER typeName; + PPV_SYMBOL_NODE symbol; - // Address - SymbolInfo_SymbolLocationStr(SymbolInfo, pointer); - PhSetListViewSubItem(Context->ListviewHandle, lvItemIndex, 1, pointer); + symbol = PhAllocate(sizeof(PV_SYMBOL_NODE)); + symbol->Type = PV_SYMBOL_TYPE_FUNCTION; + symbol->Address = SymbolInfo->Address; + symbol->Size = SymbolInfo->Size; + symbol->Name = PhCreateStringEx(SymbolInfo->Name, SymbolInfo->NameLen * sizeof(WCHAR)); + SymbolInfo_SymbolLocationStr(SymbolInfo, symbol->Pointer); - // Name - PhSetListViewSubItem(Context->ListviewHandle, lvItemIndex, 2, SymbolInfo->Name); + PhInitializeStringBuilder(&typeName, 0x100); - // Size - PhSetListViewSubItem(Context->ListviewHandle, lvItemIndex, 3, PhaFormatString(L"%lu", SymbolInfo->Size)->Buffer); + if (SymbolInfo_GetTypeName(context, &typeName, SymbolInfo->TypeIndex, SymbolInfo->Name)) + symbol->Data = PhFinalStringBuilderString(&typeName); - // Data - //if (SymbolInfo_GetTypeName(Context, SymbolInfo->TypeIndex, SymbolInfo->Name, szTypeName, cMaxTypeNameLen)) - // PhSetListViewSubItem(Context->ListviewHandle, lvItemIndex, 4, szTypeName); + // Flags: %x, SymbolInfo->Flags + // Index: %8u, TypeIndex: %8u, SymbolInfo->Index, SymbolInfo->TypeIndex - // Flags: %x, SymbolInfo->Flags - // Index: %8u, TypeIndex: %8u, SymbolInfo->Index, SymbolInfo->TypeIndex -} + PluginsAddTreeNode(context, symbol); -VOID PrintFunctionInfo( - _In_ PPDB_SYMBOL_CONTEXT Context, - _In_ PSYMBOL_INFOW SymbolInfo - ) -{ - INT lvItemIndex; - WCHAR pointer[PH_PTR_STR_LEN_1] = L""; + // Enumerate function parameters and local variables... + IMAGEHLP_STACK_FRAME sf; + sf.InstructionOffset = SymbolInfo->Address; + SymSetContext_I(NtCurrentProcess(), &sf, 0); + SymEnumSymbolsW_I(NtCurrentProcess(), 0, NULL, EnumCallbackProc, context); + } + break; + case SymTagData: + { + PPDB_SYMBOL_CONTEXT context = Context; + PH_STRING_BUILDER typeName; + PPV_SYMBOL_NODE symbol; + PWSTR symDataKind; + ULONG dataKindType = 0; + + // TODO: Remove filter + if (!SymbolInfo->Address) + break; + + if (!SymGetTypeInfo_I(NtCurrentProcess(), SymbolInfo->ModBase, SymbolInfo->Index, TI_GET_DATAKIND, &dataKindType)) + break; + + // Type + symDataKind = SymbolInfo_DataKindStr(dataKindType); + + // TODO: Remove filter + if (!wcscmp(symDataKind, L"LOCAL_VAR") || + !wcscmp(symDataKind, L"OBJECT_PTR") || + !wcscmp(symDataKind, L"PARAMETER")) + { + break; + } - if (SymbolInfo->Tag != SymTagFunction) - return; - - // Type - lvItemIndex = PhAddListViewItem(Context->ListviewHandle, MAXINT, L"FUNCTION", NULL); + symbol = PhAllocate(sizeof(PV_SYMBOL_NODE)); - // Address - SymbolInfo_SymbolLocationStr(SymbolInfo, pointer); - PhSetListViewSubItem(Context->ListviewHandle, lvItemIndex, 1, pointer); + switch (dataKindType) + { + case DataIsLocal: + symbol->Type = PV_SYMBOL_TYPE_LOCAL_VAR; + break; + case DataIsStaticLocal: + symbol->Type = PV_SYMBOL_TYPE_STATIC_LOCAL_VAR; + break; + case DataIsParam: + symbol->Type = PV_SYMBOL_TYPE_PARAMETER; + break; + case DataIsObjectPtr: + symbol->Type = PV_SYMBOL_TYPE_OBJECT_PTR; + break; + case DataIsFileStatic: + symbol->Type = PV_SYMBOL_TYPE_STATIC_VAR; + break; + case DataIsGlobal: + symbol->Type = PV_SYMBOL_TYPE_GLOBAL_VAR; + break; + case DataIsMember: + symbol->Type = PV_SYMBOL_TYPE_MEMBER; + break; + case DataIsStaticMember: + symbol->Type = PV_SYMBOL_TYPE_STATIC_MEMBER; + break; + case DataIsConstant: + symbol->Type = PV_SYMBOL_TYPE_CONSTANT; + break; + } - // Name - PhSetListViewSubItem(Context->ListviewHandle, lvItemIndex, 2, SymbolInfo->Name); + symbol->Address = SymbolInfo->Address; + symbol->Size = SymbolInfo->Size; + symbol->Name = PhCreateStringEx(SymbolInfo->Name, SymbolInfo->NameLen * sizeof(WCHAR)); + SymbolInfo_SymbolLocationStr(SymbolInfo, symbol->Pointer); - // Size - PhSetListViewSubItem(Context->ListviewHandle, lvItemIndex, 3, PhaFormatString(L"%lu", SymbolInfo->Size)->Buffer); + PhInitializeStringBuilder(&typeName, 0x100); - // Data - //if (SymbolInfo_GetTypeName(Context, SymbolInfo->TypeIndex, SymbolInfo->Name, szTypeName, cMaxTypeNameLen)) - // PhSetListViewSubItem(Context->ListviewHandle, lvItemIndex, 4, szTypeName); + // Data + if (SymbolInfo_GetTypeName(context, &typeName, SymbolInfo->TypeIndex, SymbolInfo->Name)) + symbol->Data = PhFinalStringBuilderString(&typeName); - // Flags: %x, SymbolInfo->Flags - // Index: %8u, TypeIndex: %8u, SymbolInfo->Index, SymbolInfo->TypeIndex + // Flags: %x, SymbolInfo->Flags + // Index: %8u, TypeIndex: %8u, SymbolInfo->Index, SymbolInfo->TypeIndex - // Enumerate function parameters and local variables... - //IMAGEHLP_STACK_FRAME sf; - //sf.InstructionOffset = SymbolInfo->Address; - //SymSetContext_I(NtCurrentProcess(), &sf, 0); - //SymEnumSymbolsW_I(NtCurrentProcess(), 0, NULL, EnumCallbackProc, Context); -} + PluginsAddTreeNode(context, symbol); + } + break; + default: + { + PPDB_SYMBOL_CONTEXT context = Context; + PH_STRING_BUILDER typeName; + PPV_SYMBOL_NODE symbol; -VOID PrintDefaultInfo( - _In_ PPDB_SYMBOL_CONTEXT Context, - _In_ PSYMBOL_INFOW SymbolInfo - ) -{ - INT lvItemIndex; - WCHAR pointer[PH_PTR_STR_LEN_1] = L""; + // TODO: Remove filter + if (SymbolInfo->Tag != SymTagPublicSymbol) + break; - if (SymbolInfo->Tag != SymTagPublicSymbol) - return; - - // Type - lvItemIndex = PhAddListViewItem(Context->ListviewHandle, MAXINT, L"SYMBOL", NULL); + symbol = PhAllocate(sizeof(PV_SYMBOL_NODE)); + symbol->Type = PV_SYMBOL_TYPE_SYMBOL; + symbol->Address = SymbolInfo->Address; + symbol->Size = SymbolInfo->Size; + symbol->Name = PhCreateStringEx(SymbolInfo->Name, SymbolInfo->NameLen * sizeof(WCHAR)); + SymbolInfo_SymbolLocationStr(SymbolInfo, symbol->Pointer); - // Address - SymbolInfo_SymbolLocationStr(SymbolInfo, pointer); - PhSetListViewSubItem(Context->ListviewHandle, lvItemIndex, 1, pointer); + PhInitializeStringBuilder(&typeName, 0x100); - // Name - PhSetListViewSubItem(Context->ListviewHandle, lvItemIndex, 2, SymbolInfo->Name); + if (SymbolInfo_GetTypeName(context, &typeName, SymbolInfo->TypeIndex, SymbolInfo->Name)) + symbol->Data = PhFinalStringBuilderString(&typeName); - // Size - PhSetListViewSubItem(Context->ListviewHandle, lvItemIndex, 3, PhaFormatString(L"%lu", SymbolInfo->Size)->Buffer); + // Flags: %x, SymbolInfo->Flags + // Index: %8u, TypeIndex: %8u, SymbolInfo->Index, SymbolInfo->TypeIndex - // Data - //if (SymbolInfo_GetTypeName(Context, SymbolInfo->TypeIndex, SymbolInfo->Name, szTypeName, cMaxTypeNameLen)) - // PhSetListViewSubItem(Context->ListviewHandle, lvItemIndex, 4, szTypeName); + PluginsAddTreeNode(context, symbol); + } + break; + } + } - // Flags: %x, SymbolInfo->Flags - // Index: %8u, TypeIndex: %8u, SymbolInfo->Index, SymbolInfo->TypeIndex + return TRUE; } VOID PrintClassInfo( @@ -2047,133 +2053,174 @@ VOID PrintClassInfo( _In_ UdtClassInfo* Info ) { + //INT lvItemIndex; + + if (Info->UDTKind == UdtClass) + { + //PhAddItemList(L"CLASS", Info->Name) + //return; + } + // UDT kind - //OutputDebugString(PhaFormatString(L"%s", SymbolInfo_UdtKindStr(Info->UDTKind))->Buffer); - // Name - //OutputDebugString(PhaFormatString(L" %s \n", Info->Name)->Buffer); + //lvItemIndex = PhAddListViewItem(Context->ListviewHandle, MAXINT, SymbolInfo_UdtKindStr(Info->UDTKind), NULL); + // Name + //PhSetListViewSubItem(Context->ListviewHandle, lvItemIndex, 2, Info->Name); // Size - //OutputDebugString(PhaFormatString(L"Size: %I64u", Info->Length)->Buffer); + //PhSetListViewSubItem(Context->ListviewHandle, lvItemIndex, 3, PhaFormatSize(Info->Length, -1)->Buffer); // Nested - //if (Info.Nested) - //OutputDebugString(L" Nested"); + //if (Info.Nested) OutputDebugString(L" Nested"); // Number of member variables //OutputDebugString(PhaFormatString(L" Variables: %d", Info->NumVariables)->Buffer); // Number of member functions //OutputDebugString(PhaFormatString(L" Functions: %d", Info->NumFunctions)->Buffer); // Number of base classes //OutputDebugString(PhaFormatString(L" Base classes: %d", Info->NumBaseClasses)->Buffer); - // Extended information about member variables - //OutputDebugString(L"\n"); + // Extended information about member variables for (ULONG i = 0; i < Info->NumVariables; i++) { TypeInfo VarInfo; if (!SymbolInfo_DumpType(Context, Info->Variables[i], &VarInfo)) { - //_ASSERTE(!_T("SymbolInfo::DumpType() failed.")); - // Continue with the next variable + // Continue } else if (VarInfo.Tag != SymTagData) { - //_ASSERTE(!_T("Unexpected symbol tag.")); - // Continue with the next variable + // Unexpected symbol tag. } else { - // Display information about the variable - //_tprintf(_T("%s"), Context->DataKindStr(VarInfo.Info.sDataInfo.dataKind)); - - // Name - //wprintf(L" %s \n", VarInfo.Info.sDataInfo.Name); - // Type name - //_tprintf(_T(" Type: ")); - - //#define cMaxTypeNameLen 1024 - //TCHAR szTypeName[cMaxTypeNameLen + 1] = _T(""); - - //if (SymbolInfo_GetTypeName(VarInfo.Info.sDataInfo.TypeIndex, W2T(VarInfo.Info.sDataInfo.Name), szTypeName, cMaxTypeNameLen)) - //_tprintf(szTypeName); - //else - //_tprintf(_T("n/a")); - //_tprintf(_T("\n")); - + //INT lvItemSubIndex; + //PH_STRING_BUILDER typeName; + // + //PhInitializeStringBuilder(&typeName, 0x100); + // + //// Variable + //lvItemSubIndex = PhAddListViewItem(Context->ListviewHandle, MAXINT, SymbolInfo_DataKindStr(VarInfo.sDataInfo.dataKind), NULL); + // + //// Name + //PhSetListViewSubItem(Context->ListviewHandle, lvItemSubIndex, 2, VarInfo.sDataInfo.Name); + // + //// Data + //if (SymbolInfo_GetTypeName(Context, &typeName, VarInfo.sDataInfo.TypeIndex, VarInfo.sDataInfo.Name)) + // PhSetListViewSubItem(Context->ListviewHandle, lvItemSubIndex, 4, PhFinalStringBuilderString(&typeName)->Buffer); + //PhDeleteStringBuilder(&typeName); // Location - switch (VarInfo.sDataInfo.dataKind) - { - case DataIsGlobal: - case DataIsStaticLocal: - case DataIsFileStatic: - case DataIsStaticMember: - { - // Use Address - //_tprintf(_T(" Address: %16I64x"), VarInfo.Info.sDataInfo.Address); - } - break; - case DataIsLocal: - case DataIsParam: - case DataIsObjectPtr: - case DataIsMember: - { - // Use Offset - //_tprintf(_T(" Offset: %8d"), (long)VarInfo.Info.sDataInfo.Offset); - } - break; - default: - break; // Add support for constants - } - - // Indices - //_tprintf(_T(" Index: %8u TypeIndex: %8u"), Index, VarInfo.Info.sDataInfo.TypeIndex); - //_tprintf(_T("\n")); + //switch (VarInfo.sDataInfo.dataKind) + //{ + //case DataIsGlobal: + //case DataIsStaticLocal: + //case DataIsFileStatic: + //case DataIsStaticMember: + // { + // // Use Address + // // " Address: %16I64x" VarInfo.sDataInfo.Address + // } + // break; + //case DataIsLocal: + //case DataIsParam: + //case DataIsObjectPtr: + //case DataIsMember: + // { + // // Use Offset + // // " Offset: %8d" (long)VarInfo.sDataInfo.Offset + // } + // break; + //default: + // break; // TODO Add support for constants + //} + // + // Indices " Index: %8u TypeIndex: %8u" Index, VarInfo.sDataInfo.TypeIndex } } - // Extended information about member functions - // Implement - // Extended information about base classes - // Implement + // TODO Implement information about member functions + for (ULONG i = 0; i < Info->NumFunctions; i++) + { + TypeInfo VarInfo; + + if (!SymbolInfo_DumpType(Context, Info->Variables[i], &VarInfo)) + { + // Continue + } + else if (VarInfo.Tag != SymTagFunction) + { + // Unexpected symbol tag. + } + else + { + //INT lvItemSubIndex; + //PH_STRING_BUILDER typeName; + // + //PhInitializeStringBuilder(&typeName, 0x100); + // + // Type + //lvItemSubIndex = PhAddListViewItem(Context->ListviewHandle, MAXINT, L"VARIABLE", NULL); + + // Address + // SymbolInfo_SymbolLocationStr(Context, VarInfo.sDataInfo.Address); + //PhSetListViewSubItem(Context->ListviewHandle, lvItemIndex, 1, pointer); VarInfo.sDataInfo.Address + // + // Name : SymbolInfo_DataKindStr(VarInfo.sDataInfo.dataKind) + //PhSetListViewSubItem(Context->ListviewHandle, lvItemIndex, 2, VarInfo.sDataInfo.Name); + // + // Size + //PhSetListViewSubItem(Context->ListviewHandle, lvItemIndex, 3, VarInfo.sDataInfo.Offset + // + // Data + //if (SymbolInfo_GetTypeName(Context, &typeName, SymbolInfo->TypeIndex, SymbolInfo->Name)) + // PhSetListViewSubItem(Context->ListviewHandle, lvItemIndex, 4, PhFinalStringBuilderString(&typeName)->Buffer); + // + // Flags: %x, SymbolInfo->Flags + // Index: %8u, TypeIndex: %8u, SymbolInfo->Index, SymbolInfo->TypeIndex + // + //PhDeleteStringBuilder(&typeName); + // + // Enumerate function parameters and local variables... + // IMAGEHLP_STACK_FRAME sf; + //sf.InstructionOffset = SymbolInfo->Address; VarInfo.sDataInfo.Offset + //SymSetContext_I(NtCurrentProcess(), &sf, 0); + //SymEnumSymbolsW_I(NtCurrentProcess(), 0, NULL, EnumCallbackProc, Context); + } + } + // TODO Implement information about base classes for (ULONG i = 0; i < Info->NumBaseClasses; i++) { TypeInfo baseInfo; if (!SymbolInfo_DumpType(Context, Info->BaseClasses[i], &baseInfo)) { - //_ASSERTE(!_T("SymbolInfo::DumpType() failed.")); - // Continue with the next base class + // Continue } else if (baseInfo.Tag != SymTagBaseClass) { - //_ASSERTE(!_T("Unexpected symbol tag.")); - // Continue with the next base class + // Unexpected symbol tag } else { - // Obtain the name of the base class TypeInfo BaseUdtInfo; + // Obtain the next base class if (!SymbolInfo_DumpType(Context, baseInfo.sBaseClassInfo.TypeIndex, &BaseUdtInfo)) { - //_ASSERTE(!_T("SymbolInfo::DumpType() failed.")); - // Continue with the next base class + // Continue } else if (BaseUdtInfo.Tag != SymTagUDT) { - //_ASSERTE(!_T("Unexpected symbol tag.")); - // Continue with the next base class + // Unexpected symbol tag } else { - // Print the name of the base class if (baseInfo.sBaseClassInfo.Virtual) { - //wprintf(L"VIRTUAL_BASE_CLASS %s \n", BaseUdtInfo.Info.sUdtClassInfo.Name); + //PhAddItemList(L"VIRTUAL_BASE_CLASS", BaseUdtInfo.sUdtClassInfo.Name) } else { - //wprintf(L"BASE_CLASS %s \n", BaseUdtInfo.Info.sUdtClassInfo.Name); + //PhAddItemList(L"BASE_CLASS", BaseUdtInfo.sUdtClassInfo.Name) } } } @@ -2208,13 +2255,11 @@ VOID PrintUserDefinedTypes( if (!SymbolInfo_DumpType(Context, info.sUdtClassInfo.BaseClasses[i], &baseInfo)) { - //_ASSERTE(!_T("SymbolInfo::DumpType() failed.")); - // Continue with the next base class + // Continue } else if (baseInfo.Tag != SymTagBaseClass) { - //_ASSERTE(!_T("Unexpected symbol tag.")); - // Continue with the next base class + // Continue } else { @@ -2223,13 +2268,11 @@ VOID PrintUserDefinedTypes( if (!SymbolInfo_DumpType(Context, baseInfo.sBaseClassInfo.TypeIndex, &baseUdtInfo)) { - //_ASSERTE(!_T("SymbolInfo::DumpType() failed.")); - // Continue with the next base class + // Continue } else if (baseUdtInfo.Tag != SymTagUDT) { - //_ASSERTE(!_T("Unexpected symbol tag.")); - // Continue with the next base class + // Continue } else { @@ -2241,15 +2284,14 @@ VOID PrintUserDefinedTypes( } else { + //INT lvItemIndex; // UDT kind - //printf("%s", Context->UdtKindStr(Info.Info.sUdtClassInfo.UDTKind)); - // - // Name - //printf("%s", Info.Info.sUdtClassInfo.Name); - // + //lvItemIndex = PhAddListViewItem(Context->ListviewHandle, MAXINT, SymbolInfo_UdtKindStr(info.sUdtClassInfo.UDTKind), NULL); + // Name + //PhSetListViewSubItem(Context->ListviewHandle, lvItemIndex, 2, info.sUdtClassInfo.Name); // Size - //printf("Size: %I64u", Info.Info.sUdtClassInfo.Length); - // + //PhSetListViewSubItem(Context->ListviewHandle, lvItemIndex, 3, PhaFormatString(L"%I64u", info.sUdtClassInfo.Length)->Buffer); + // Nested //if (Info.Info.sUdtClassInfo.Nested) // printf("Nested"); @@ -2262,11 +2304,13 @@ VOID PrintUserDefinedTypes( } } -/////////////////////////////////////////////////////////////////////////////// -BOOLEAN GetFileParamsSize(_In_ PWSTR pFileName, _Out_ ULONG* FileLength) +BOOLEAN GetFileParamsSize( + _In_ PWSTR FileName, + _Out_ ULONG *FileLength + ) { HANDLE hFile = CreateFile( - pFileName, + FileName, GENERIC_READ, FILE_SHARE_READ, NULL, @@ -2286,28 +2330,22 @@ BOOLEAN GetFileParamsSize(_In_ PWSTR pFileName, _Out_ ULONG* FileLength) return (*FileLength != INVALID_FILE_SIZE); } -BOOLEAN GetFileParams(_In_ PWSTR pFileName, _Out_ ULONG64 *BaseAddress, _Out_ ULONG* FileLength) +BOOLEAN GetFileParams( + _In_ PWSTR FileName, + _Out_ ULONG64 *BaseAddress, + _Out_ ULONG *FileLength + ) { TCHAR szFileExt[_MAX_EXT] = { 0 }; - _wsplitpath(pFileName, NULL, NULL, NULL, szFileExt); + _wsplitpath(FileName, NULL, NULL, NULL, szFileExt); - // Is it .PDB file ? if (_wcsicmp(szFileExt, L".PDB") == 0) - { - // Yes, it is a .PDB file + { *BaseAddress = 0x10000000; - // Determine its size, and use a dummy base address. - // it can be any non-zero value, but if we load symbols - // from more than one file, memory regions specified - // for different files should not overlap - // (region is "base address + file size") - - if (!GetFileParamsSize(pFileName, FileLength)) - { + if (!GetFileParamsSize(FileName, FileLength)) return FALSE; - } } else { @@ -2318,7 +2356,10 @@ BOOLEAN GetFileParams(_In_ PWSTR pFileName, _Out_ ULONG64 *BaseAddress, _Out_ UL return TRUE; } -/////////////////////////////////////////////////////////////////////////////// +// +// TODO: Move to pdbprp.c +// + VOID PdbLoadDbgHelpFromPath( _In_ PWSTR DbgHelpPath ) @@ -2361,7 +2402,6 @@ VOID PdbLoadDbgHelpFromPath( PhSymbolProviderCompleteInitialization(dbghelpModule); } - VOID ShowSymbolInfo( _In_ ULONG64 BaseAddress ) @@ -2377,7 +2417,7 @@ VOID ShowSymbolInfo( switch (info.SymType) { case SymNone: - //OutputDebugString(L"No symbols available for the module.\r\n"); + OutputDebugString(L"No symbols available for the module.\r\n"); break; case SymExport: //OutputDebugString(L"Loaded symbols: Exports\r\n"); @@ -2441,9 +2481,8 @@ VOID ShowSymbolInfo( //OutputDebugString(PhaFormatString(L"Public symbols: %s\n", info.Publics ? L"Available" : L"Not available")->Buffer); } -VOID PeDumpFileSymbols( - _In_ HWND ListViewHandle, - _In_ PWSTR FileName +NTSTATUS PeDumpFileSymbols( + _In_ PPDB_SYMBOL_CONTEXT Context ) { HMODULE dbghelpHandle; @@ -2455,7 +2494,7 @@ VOID PeDumpFileSymbols( PdbLoadDbgHelpFromPath(L"C:\\Program Files (x86)\\Windows Kits\\10\\Debuggers\\x64\\dbghelp.dll"); if (!(dbghelpHandle = GetModuleHandle(L"dbghelp.dll"))) - return; + return 1; symsrvHandle = GetModuleHandle(L"symsrv.dll"); SymInitialize_I = PhGetProcedureAddress(dbghelpHandle, "SymInitialize", 0); @@ -2472,136 +2511,39 @@ VOID PeDumpFileSymbols( SymSetOptions_I(SymGetOptions_I() | SYMOPT_DEBUG | SYMOPT_UNDNAME | SYMOPT_ALLOW_ZERO_ADDRESS); // SYMOPT_DEFERRED_LOADS | SYMOPT_FAVOR_COMPRESSED if (!SymInitialize_I(NtCurrentProcess(), NULL, FALSE)) - return; + return 1; if (!SymSetSearchPathW_I(NtCurrentProcess(), L"SRV*C:\\symbols*http://msdl.microsoft.com/download/symbols")) - return; + goto CleanupExit; - if (GetFileParams(FileName, &baseAddress, &fileLength)) + if (GetFileParams(PvFileName->Buffer, &baseAddress, &fileLength)) { if ((symbolBaseAddress = SymLoadModuleExW_I( - NtCurrentProcess(), - NULL, - FileName, - NULL, - baseAddress, - fileLength, - NULL, + NtCurrentProcess(), + NULL, + PvFileName->Buffer, + NULL, + baseAddress, + fileLength, + NULL, 0 ))) { - PDB_SYMBOL_CONTEXT context; - - context.ListviewHandle = ListViewHandle; - context.BaseAddress = symbolBaseAddress; - context.UdtList = PhCreateList(0x100); + Context->BaseAddress = symbolBaseAddress; + Context->UdtList = PhCreateList(0x100); - //ShowSymbolInfo(symbolBaseAddress); + ShowSymbolInfo(symbolBaseAddress); - SymEnumSymbolsW_I(NtCurrentProcess(), symbolBaseAddress, NULL, EnumCallbackProc, &context); + SymEnumSymbolsW_I(NtCurrentProcess(), symbolBaseAddress, NULL, EnumCallbackProc, Context); // Print information about used defined types - //PrintUserDefinedTypes(&context); + PrintUserDefinedTypes(Context); } } - SymCleanup_I(NtCurrentProcess()); -} - -VOID PvPdbProperties( - VOID - ) -{ - PPV_PROPCONTEXT propContext; - - if (!RtlDoesFileExists_U(PvFileName->Buffer)) - { - PhShowStatus(NULL, L"Unable to load the pdb file", STATUS_FILE_NOT_AVAILABLE, 0); - return; - } - - if (propContext = PvCreatePropContext(PvFileName)) - { - PPV_PROPPAGECONTEXT newPage; - - // Symbols page - newPage = PvCreatePropPageContext( - MAKEINTRESOURCE(IDD_PESYMBOLS), - PvpSymbolsDlgProc, - NULL - ); - PvAddPropPage(propContext, newPage); - - PhModalPropertySheet(&propContext->PropSheetHeader); - - PhDereferenceObject(propContext); - } -} - -INT_PTR CALLBACK PvpSymbolsDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - LPPROPSHEETPAGE propSheetPage; - PPV_PROPPAGECONTEXT propPageContext; - - if (!PvPropPageDlgProcHeader(hwndDlg, uMsg, lParam, &propSheetPage, &propPageContext)) - return FALSE; - - switch (uMsg) - { - case WM_INITDIALOG: - { - HWND lvHandle; - - lvHandle = GetDlgItem(hwndDlg, IDC_LIST); - PhSetListViewStyle(lvHandle, TRUE, TRUE); - PhSetControlTheme(lvHandle, L"explorer"); - PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 40, L"Type"); - PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_RIGHT, 80, L"VA"); - PhAddListViewColumn(lvHandle, 2, 2, 2, LVCFMT_LEFT, 250, L"Name"); - PhAddListViewColumn(lvHandle, 3, 3, 3, LVCFMT_LEFT, 40, L"Size"); - PhSetExtendedListView(lvHandle); - PhLoadListViewColumnsFromSetting(L"PdbListViewColumns", lvHandle); - - PeDumpFileSymbols(lvHandle, PvFileName->Buffer); - - ExtendedListView_SortItems(lvHandle); - - EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); - } - break; - case WM_DESTROY: - { - PhSaveListViewColumnsToSetting(L"PdbListViewColumns", GetDlgItem(hwndDlg, IDC_LIST)); - } - break; - case WM_SHOWWINDOW: - { - if (!propPageContext->LayoutInitialized) - { - PPH_LAYOUT_ITEM dialogItem; +CleanupExit: - dialogItem = PvAddPropPageLayoutItem(hwndDlg, hwndDlg, - PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL); - PvAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_LIST), - dialogItem, PH_ANCHOR_ALL); - - PvDoPropPageLayout(hwndDlg); - - propPageContext->LayoutInitialized = TRUE; - } - } - break; - case WM_NOTIFY: - { - PvHandleListViewNotifyForCopy(lParam, GetDlgItem(hwndDlg, IDC_LIST)); - } - break; - } + SymCleanup_I(NtCurrentProcess()); - return FALSE; + return 0; } diff --git a/tools/peview/pdbprp.c b/tools/peview/pdbprp.c new file mode 100644 index 000000000000..93459540ebf7 --- /dev/null +++ b/tools/peview/pdbprp.c @@ -0,0 +1,714 @@ +/* + * PE viewer - + * pdb support + * + * Copyright (C) 2017 dmex + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include +#include +#include "colmgr.h" + +VOID PhInitializeTreeNewFilterSupport( + _Out_ PPH_TN_FILTER_SUPPORT Support, + _In_ HWND TreeNewHandle, + _In_ PPH_LIST NodeList + ) +{ + Support->FilterList = NULL; + Support->TreeNewHandle = TreeNewHandle; + Support->NodeList = NodeList; +} + +VOID PhDeleteTreeNewFilterSupport( + _In_ PPH_TN_FILTER_SUPPORT Support + ) +{ + PhDereferenceObject(Support->FilterList); +} + +PPH_TN_FILTER_ENTRY PhAddTreeNewFilter( + _In_ PPH_TN_FILTER_SUPPORT Support, + _In_ PPH_TN_FILTER_FUNCTION Filter, + _In_opt_ PVOID Context + ) +{ + PPH_TN_FILTER_ENTRY entry; + + entry = PhAllocate(sizeof(PH_TN_FILTER_ENTRY)); + entry->Filter = Filter; + entry->Context = Context; + + if (!Support->FilterList) + Support->FilterList = PhCreateList(2); + + PhAddItemList(Support->FilterList, entry); + + return entry; +} + +VOID PhRemoveTreeNewFilter( + _In_ PPH_TN_FILTER_SUPPORT Support, + _In_ PPH_TN_FILTER_ENTRY Entry + ) +{ + ULONG index; + + if (!Support->FilterList) + return; + + index = PhFindItemList(Support->FilterList, Entry); + + if (index != -1) + { + PhRemoveItemList(Support->FilterList, index); + PhFree(Entry); + } +} + +BOOLEAN PhApplyTreeNewFiltersToNode( + _In_ PPH_TN_FILTER_SUPPORT Support, + _In_ PPH_TREENEW_NODE Node + ) +{ + BOOLEAN show; + ULONG i; + + show = TRUE; + + if (Support->FilterList) + { + for (i = 0; i < Support->FilterList->Count; i++) + { + PPH_TN_FILTER_ENTRY entry; + + entry = Support->FilterList->Items[i]; + + if (!entry->Filter(Node, entry->Context)) + { + show = FALSE; + break; + } + } + } + + return show; +} + +VOID PhApplyTreeNewFilters( + _In_ PPH_TN_FILTER_SUPPORT Support + ) +{ + ULONG i; + + for (i = 0; i < Support->NodeList->Count; i++) + { + PPH_TREENEW_NODE node; + + node = Support->NodeList->Items[i]; + node->Visible = PhApplyTreeNewFiltersToNode(Support, node); + + if (!node->Visible && node->Selected) + { + node->Selected = FALSE; + } + } + + TreeNew_NodesStructured(Support->TreeNewHandle); +} + +BOOLEAN PluginsNodeHashtableCompareFunction( + _In_ PVOID Entry1, + _In_ PVOID Entry2 + ); +ULONG PluginsNodeHashtableHashFunction( + _In_ PVOID Entry + ); +VOID DestroyPluginsNode( + _In_ PPV_SYMBOL_NODE Node + ); + +VOID DeletePluginsTree( + _In_ PPDB_SYMBOL_CONTEXT Context + ) +{ + PPH_STRING settings = PhCmSaveSettings(Context->TreeNewHandle); + PhSetStringSetting2(L"PdbTreeListColumns", &settings->sr); + PhDereferenceObject(settings); + + for (ULONG i = 0; i < Context->NodeList->Count; i++) + { + DestroyPluginsNode(Context->NodeList->Items[i]); + } + + PhDereferenceObject(Context->NodeHashtable); + PhDereferenceObject(Context->NodeList); +} + +struct _PH_TN_FILTER_SUPPORT* GetPluginListFilterSupport( + _In_ PPDB_SYMBOL_CONTEXT Context + ) +{ + return &Context->FilterSupport; +} + +BOOLEAN PluginsNodeHashtableCompareFunction( + _In_ PVOID Entry1, + _In_ PVOID Entry2 + ) +{ + PPV_SYMBOL_NODE windowNode1 = *(PPV_SYMBOL_NODE *)Entry1; + PPV_SYMBOL_NODE windowNode2 = *(PPV_SYMBOL_NODE *)Entry2; + + return PhEqualString(windowNode1->Name, windowNode2->Name, TRUE); +} + +ULONG PluginsNodeHashtableHashFunction( + _In_ PVOID Entry + ) +{ + return PhHashStringRef(&(*(PPV_SYMBOL_NODE*)Entry)->Name->sr, TRUE); +} + +VOID PluginsAddTreeNode( + _In_ PPDB_SYMBOL_CONTEXT Context, + _In_ PPV_SYMBOL_NODE Entry + ) +{ + PhInitializeTreeNewNode(&Entry->Node); + + memset(Entry->TextCache, 0, sizeof(PH_STRINGREF) * TREE_COLUMN_ITEM_MAXIMUM); + Entry->Node.TextCache = Entry->TextCache; + Entry->Node.TextCacheSize = TREE_COLUMN_ITEM_MAXIMUM; + + PhAddEntryHashtable(Context->NodeHashtable, &Entry); + PhAddItemList(Context->NodeList, Entry); + + TreeNew_SetRedraw(Context->TreeNewHandle, FALSE); + TreeNew_NodesStructured(Context->TreeNewHandle); + TreeNew_SetRedraw(Context->TreeNewHandle, TRUE); + + if (Context->FilterSupport.NodeList) + { + Entry->Node.Visible = PhApplyTreeNewFiltersToNode(&Context->FilterSupport, &Entry->Node); + } +} + +PPV_SYMBOL_NODE FindTreeNode( + _In_ PPDB_SYMBOL_CONTEXT Context, + _In_ PPH_STRING Name + ) +{ + for (ULONG i = 0; i < Context->NodeList->Count; i++) + { + PPV_SYMBOL_NODE entry = Context->NodeList->Items[i]; + + if (PhEqualString(entry->Name, Name, TRUE)) + return entry; + } + + return NULL; +} + +VOID WeRemoveWindowNode( + _In_ PPDB_SYMBOL_CONTEXT Context, + _In_ PPV_SYMBOL_NODE Node + ) +{ + ULONG index = 0; + + // Remove from hashtable/list and cleanup. + PhRemoveEntryHashtable(Context->NodeHashtable, &Node); + + if ((index = PhFindItemList(Context->NodeList, Node)) != -1) + { + PhRemoveItemList(Context->NodeList, index); + } + + DestroyPluginsNode(Node); +} + +VOID DestroyPluginsNode( + _In_ PPV_SYMBOL_NODE Node + ) +{ + PhFree(Node); +} + +#define SORT_FUNCTION(Column) PmPoolTreeNewCompare##Column +#define BEGIN_SORT_FUNCTION(Column) static int __cdecl PmPoolTreeNewCompare##Column( \ + _In_ void *_context, \ + _In_ const void *_elem1, \ + _In_ const void *_elem2 \ + ) \ +{ \ + PPV_SYMBOL_NODE node1 = *(PPV_SYMBOL_NODE *)_elem1; \ + PPV_SYMBOL_NODE node2 = *(PPV_SYMBOL_NODE *)_elem2; \ + int sortResult = 0; + +#define END_SORT_FUNCTION \ + if (sortResult == 0) \ + sortResult = uintptrcmp((ULONG_PTR)node1->Node.Index, (ULONG_PTR)node2->Node.Index); \ + \ + return PhModifySort(sortResult, ((PPDB_SYMBOL_CONTEXT)_context)->TreeNewSortOrder); \ +} + +BEGIN_SORT_FUNCTION(Symbol) +{ + sortResult = PhCompareString(node1->Name, node2->Name, FALSE); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(VA) +{ + sortResult = PhCompareString(node1->Name, node2->Name, FALSE); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(Name) +{ + sortResult = PhCompareString(node1->Name, node2->Name, FALSE); +} +END_SORT_FUNCTION + +BOOLEAN NTAPI PluginsTreeNewCallback( + _In_ HWND hwnd, + _In_ PH_TREENEW_MESSAGE Message, + __in_opt PVOID Parameter1, + __in_opt PVOID Parameter2, + __in_opt PVOID Context + ) +{ + PPDB_SYMBOL_CONTEXT context; + PPV_SYMBOL_NODE node; + + context = Context; + + switch (Message) + { + case TreeNewGetChildren: + { + PPH_TREENEW_GET_CHILDREN getChildren = Parameter1; + node = (PPV_SYMBOL_NODE)getChildren->Node; + + if (!getChildren->Node) + { + static PVOID sortFunctions[] = + { + SORT_FUNCTION(Name), + SORT_FUNCTION(VA), + SORT_FUNCTION(Symbol) + }; + int (__cdecl *sortFunction)(void *, const void *, const void *); + + if (context->TreeNewSortColumn < TREE_COLUMN_ITEM_MAXIMUM) + sortFunction = sortFunctions[context->TreeNewSortColumn]; + else + sortFunction = NULL; + + if (sortFunction) + { + qsort_s(context->NodeList->Items, context->NodeList->Count, sizeof(PVOID), sortFunction, context); + } + + getChildren->Children = (PPH_TREENEW_NODE *)context->NodeList->Items; + getChildren->NumberOfChildren = context->NodeList->Count; + } + } + return TRUE; + case TreeNewIsLeaf: + { + PPH_TREENEW_IS_LEAF isLeaf = (PPH_TREENEW_IS_LEAF)Parameter1; + node = (PPV_SYMBOL_NODE)isLeaf->Node; + + isLeaf->IsLeaf = TRUE; + } + return TRUE; + case TreeNewGetCellText: + { + PPH_TREENEW_GET_CELL_TEXT getCellText = (PPH_TREENEW_GET_CELL_TEXT)Parameter1; + node = (PPV_SYMBOL_NODE)getCellText->Node; + + switch (getCellText->Id) + { + case TREE_COLUMN_ITEM_TYPE: + { + switch (node->Type) + { + case PV_SYMBOL_TYPE_FUNCTION: + PhInitializeStringRef(&getCellText->Text, L"FUNCTION"); + break; + case PV_SYMBOL_TYPE_SYMBOL: + PhInitializeStringRef(&getCellText->Text, L"SYMBOL"); + break; + case PV_SYMBOL_TYPE_LOCAL_VAR: + PhInitializeStringRef(&getCellText->Text, L"LOCAL_VAR"); + break; + case PV_SYMBOL_TYPE_STATIC_LOCAL_VAR: + PhInitializeStringRef(&getCellText->Text, L"STATIC_LOCAL_VAR"); + break; + case PV_SYMBOL_TYPE_PARAMETER: + PhInitializeStringRef(&getCellText->Text, L"PARAMETER"); + break; + case PV_SYMBOL_TYPE_OBJECT_PTR: + PhInitializeStringRef(&getCellText->Text, L"OBJECT_PTR"); + break; + case PV_SYMBOL_TYPE_STATIC_VAR: + PhInitializeStringRef(&getCellText->Text, L"STATIC_VAR"); + break; + case PV_SYMBOL_TYPE_GLOBAL_VAR: + PhInitializeStringRef(&getCellText->Text, L"GLOBAL_VAR"); + break; + case PV_SYMBOL_TYPE_MEMBER: + PhInitializeStringRef(&getCellText->Text, L"MEMBER"); + break; + case PV_SYMBOL_TYPE_STATIC_MEMBER: + PhInitializeStringRef(&getCellText->Text, L"STATIC_MEMBER"); + break; + case PV_SYMBOL_TYPE_CONSTANT: + PhInitializeStringRef(&getCellText->Text, L"CONSTANT"); + break; + } + } + break; + case TREE_COLUMN_ITEM_VA: + PhInitializeStringRefLongHint(&getCellText->Text, node->Pointer); + break; + case TREE_COLUMN_ITEM_NAME: + getCellText->Text = PhGetStringRef(node->Name); + break; + case TREE_COLUMN_ITEM_SYMBOL: + getCellText->Text = PhGetStringRef(node->Data); + break; + default: + return FALSE; + } + + getCellText->Flags = TN_CACHE; + } + return TRUE; + case TreeNewGetNodeColor: + { + PPH_TREENEW_GET_NODE_COLOR getNodeColor = (PPH_TREENEW_GET_NODE_COLOR)Parameter1; + node = (PPV_SYMBOL_NODE)getNodeColor->Node; + + getNodeColor->Flags = TN_CACHE | TN_AUTO_FORECOLOR; + } + return TRUE; + case TreeNewSortChanged: + { + TreeNew_GetSort(hwnd, &context->TreeNewSortColumn, &context->TreeNewSortOrder); + TreeNew_NodesStructured(hwnd); + } + return TRUE; + case TreeNewKeyDown: + case TreeNewNodeExpanding: + return TRUE; + case TreeNewLeftDoubleClick: + { + // SendMessage(context->ParentWindowHandle, WM_COMMAND, WM_ACTION, (LPARAM)context); + } + return TRUE; + case TreeNewContextMenu: + { + PPH_TREENEW_MOUSE_EVENT mouseEvent = (PPH_TREENEW_MOUSE_EVENT)Parameter1; + + //SendMessage(context->ParentWindowHandle, WM_COMMAND, ID_WCTSHOWCONTEXTMENU, MAKELONG(mouseEvent->Location.x, mouseEvent->Location.y)); + } + return TRUE; + case TreeNewHeaderRightClick: + { + /*PH_TN_COLUMN_MENU_DATA data; + + data.TreeNewHandle = hwnd; + data.MouseEvent = Parameter1; + data.DefaultSortColumn = 0; + data.DefaultSortOrder = AscendingSortOrder; + PhInitializeTreeNewColumnMenu(&data); + + data.Selection = PhShowEMenu(data.Menu, hwnd, PH_EMENU_SHOW_LEFTRIGHT, + PH_ALIGN_LEFT | PH_ALIGN_TOP, data.MouseEvent->ScreenLocation.x, data.MouseEvent->ScreenLocation.y); + PhHandleTreeNewColumnMenu(&data); + PhDeleteTreeNewColumnMenu(&data);*/ + } + return TRUE; + } + + return FALSE; +} + +VOID PluginsClearTree( + _In_ PPDB_SYMBOL_CONTEXT Context + ) +{ + for (ULONG i = 0; i < Context->NodeList->Count; i++) + DestroyPluginsNode(Context->NodeList->Items[i]); + + PhClearHashtable(Context->NodeHashtable); + PhClearList(Context->NodeList); +} + +PPV_SYMBOL_NODE WeGetSelectedWindowNode( + _In_ PPDB_SYMBOL_CONTEXT Context + ) +{ + for (ULONG i = 0; i < Context->NodeList->Count; i++) + { + PPV_SYMBOL_NODE windowNode = Context->NodeList->Items[i]; + + if (windowNode->Node.Selected) + return windowNode; + } + + return NULL; +} + +VOID WeGetSelectedWindowNodes( + _In_ PPDB_SYMBOL_CONTEXT Context, + _Out_ PPV_SYMBOL_NODE **Windows, + _Out_ PULONG NumberOfWindows + ) +{ + PPH_LIST list = PhCreateList(2); + + for (ULONG i = 0; i < Context->NodeList->Count; i++) + { + PPV_SYMBOL_NODE node = (PPV_SYMBOL_NODE)Context->NodeList->Items[i]; + + if (node->Node.Selected) + PhAddItemList(list, node); + } + + *Windows = PhAllocateCopy(list->Items, sizeof(PVOID) * list->Count); + *NumberOfWindows = list->Count; + + PhDereferenceObject(list); +} + +VOID InitializePluginsTree( + _In_ PPDB_SYMBOL_CONTEXT Context, + _In_ HWND ParentWindowHandle, + _In_ HWND TreeNewHandle + ) +{ + Context->NodeHashtable = PhCreateHashtable( + sizeof(PPV_SYMBOL_NODE), + PluginsNodeHashtableCompareFunction, + PluginsNodeHashtableHashFunction, + 100 + ); + Context->NodeList = PhCreateList(100); + + Context->ParentWindowHandle = ParentWindowHandle; + Context->TreeNewHandle = TreeNewHandle; + PhSetControlTheme(TreeNewHandle, L"explorer"); + + TreeNew_SetCallback(TreeNewHandle, PluginsTreeNewCallback, Context); + + PhAddTreeNewColumnEx2(TreeNewHandle, TREE_COLUMN_ITEM_TYPE, TRUE, L"Type", 80, PH_ALIGN_LEFT, TREE_COLUMN_ITEM_TYPE, 0, 0); + PhAddTreeNewColumnEx2(TreeNewHandle, TREE_COLUMN_ITEM_VA, TRUE, L"VA", 80, PH_ALIGN_LEFT, TREE_COLUMN_ITEM_VA, 0, 0); + PhAddTreeNewColumnEx2(TreeNewHandle, TREE_COLUMN_ITEM_NAME, TRUE, L"Symbol", 150, PH_ALIGN_LEFT, TREE_COLUMN_ITEM_NAME, 0, 0); + PhAddTreeNewColumnEx2(TreeNewHandle, TREE_COLUMN_ITEM_SYMBOL, TRUE, L"Data", 150, PH_ALIGN_LEFT, TREE_COLUMN_ITEM_SYMBOL, 0, 0); + /* + PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 40, L"Symbol"); + PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_RIGHT, 80, L"VA"); + PhAddListViewColumn(lvHandle, 2, 2, 2, LVCFMT_LEFT, 250, L"Name"); + PhAddListViewColumn(lvHandle, 3, 3, 3, LVCFMT_LEFT, 40, L"Size"); + PhAddListViewColumn(lvHandle, 4, 4, 4, LVCFMT_LEFT, 80, L"Type"); + */ + TreeNew_SetSort(TreeNewHandle, 0, NoSortOrder); + + PPH_STRING settings = PhGetStringSetting(L"PdbTreeListColumns"); + PhCmLoadSettings(TreeNewHandle, &settings->sr); + PhDereferenceObject(settings); + + PhInitializeTreeNewFilterSupport(&Context->FilterSupport, TreeNewHandle, Context->NodeList); +} + +BOOLEAN WordMatchStringRef( + _In_ PPDB_SYMBOL_CONTEXT Context, + _In_ PPH_STRINGREF Text + ) +{ + PH_STRINGREF part; + PH_STRINGREF remainingPart; + + remainingPart = Context->SearchboxText->sr; + + while (remainingPart.Length) + { + PhSplitStringRefAtChar(&remainingPart, '|', &part, &remainingPart); + + if (part.Length) + { + if (PhFindStringInStringRef(Text, &part, TRUE) != -1) + return TRUE; + } + } + + return FALSE; +} + +BOOLEAN WordMatchStringZ( + _In_ PPDB_SYMBOL_CONTEXT Context, + _In_ PWSTR Text + ) +{ + PH_STRINGREF text; + + PhInitializeStringRef(&text, Text); + return WordMatchStringRef(Context, &text); +} + +BOOLEAN TreeFilterCallback( + _In_ PPH_TREENEW_NODE Node, + _In_opt_ PVOID Context +) +{ + PPDB_SYMBOL_CONTEXT context = Context; + PPV_SYMBOL_NODE node = (PPV_SYMBOL_NODE)Node; + + //if (node->Address == 0) + // return TRUE; + + if (PhIsNullOrEmptyString(context->SearchboxText)) + return TRUE; + + if (!PhIsNullOrEmptyString(node->Name)) + { + if (WordMatchStringRef(context, &node->Name->sr)) + return TRUE; + } + + return FALSE; +} + + +INT_PTR CALLBACK PvpSymbolsDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + LPPROPSHEETPAGE propSheetPage; + PPV_PROPPAGECONTEXT propPageContext; + PPDB_SYMBOL_CONTEXT context; + + if (PvPropPageDlgProcHeader(hwndDlg, uMsg, lParam, &propSheetPage, &propPageContext)) + { + context = (PPDB_SYMBOL_CONTEXT)propPageContext->Context; + } + else + { + return FALSE; + } + + switch (uMsg) + { + case WM_INITDIALOG: + { + context = propPageContext->Context = PhAllocate(sizeof(PDB_SYMBOL_CONTEXT)); + memset(context, 0, sizeof(PDB_SYMBOL_CONTEXT)); + + context->DialogHandle = hwndDlg; + context->TreeNewHandle = GetDlgItem(hwndDlg, IDC_SYMBOLTREE); + context->SearchHandle = GetDlgItem(hwndDlg, IDC_SYMSEARCH); + context->SearchboxText = PhReferenceEmptyString(); + + InitializePluginsTree(context, hwndDlg, context->TreeNewHandle); + //PhAddTreeNewFilter(GetPluginListFilterSupport(context), TreeFilterCallback, context); + + PhQueueItemWorkQueue(PhGetGlobalWorkQueue(), PeDumpFileSymbols, context); + + //SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hwndDlg, IDC_OPTIONS), TRUE); + } + break; + case WM_DESTROY: + { + DeletePluginsTree(context); + } + break; + case WM_SHOWWINDOW: + { + if (!propPageContext->LayoutInitialized) + { + PPH_LAYOUT_ITEM dialogItem; + + dialogItem = PvAddPropPageLayoutItem(hwndDlg, hwndDlg, + PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL); + PvAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_SYMSEARCH), + dialogItem, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); + PvAddPropPageLayoutItem(hwndDlg, context->TreeNewHandle, dialogItem, PH_ANCHOR_ALL); + + PvDoPropPageLayout(hwndDlg); + + propPageContext->LayoutInitialized = TRUE; + } + } + break; + case WM_NOTIFY: + { + LPNMHDR header = (LPNMHDR)lParam; + + switch (header->code) + { + case NM_DBLCLK: + { + if (header->hwndFrom == context->TreeNewHandle) + { + + } + } + break; + } + } + break; + } + + return FALSE; +} + +VOID PvPdbProperties( + VOID + ) +{ + PPV_PROPCONTEXT propContext; + + if (!RtlDoesFileExists_U(PvFileName->Buffer)) + { + PhShowStatus(NULL, L"Unable to load the pdb file", STATUS_FILE_NOT_AVAILABLE, 0); + return; + } + + if (propContext = PvCreatePropContext(PvFileName)) + { + PPV_PROPPAGECONTEXT newPage; + + newPage = PvCreatePropPageContext( + MAKEINTRESOURCE(IDD_PESYMBOLS), + PvpSymbolsDlgProc, + NULL + ); + PvAddPropPage(propContext, newPage); + + PhModalPropertySheet(&propContext->PropSheetHeader); + + PhDereferenceObject(propContext); + } +} diff --git a/tools/peview/peview.rc b/tools/peview/peview.rc index ed559acfa245..7ca0f9265d2d 100644 --- a/tools/peview/peview.rc +++ b/tools/peview/peview.rc @@ -111,10 +111,10 @@ BEGIN IDD_PESYMBOLS, DIALOG BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 293 - TOPMARGIN, 7 - BOTTOMMARGIN, 273 + LEFTMARGIN, 3 + RIGHTMARGIN, 298 + TOPMARGIN, 3 + BOTTOMMARGIN, 277 END END #endif // APSTUDIO_INVOKED @@ -192,8 +192,9 @@ BEGIN EDITTEXT IDC_FLAGS,76,19,217,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER LTEXT "Version String:",IDC_STATIC,7,31,48,8 LTEXT "Static",IDC_VERSIONSTRING,78,31,215,8 - CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,57,286,216 + CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,57,286,85 LTEXT "Sections:",IDC_STATIC,7,47,30,8 + CONTROL "",IDC_SECTION,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,145,286,128 END IDD_PELOADCONFIG DIALOGEX 0, 0, 300, 280 @@ -212,12 +213,13 @@ BEGIN CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,7,286,266 END -IDD_PESYMBOLS DIALOGEX 0, 0, 300, 280 +IDD_PESYMBOLS DIALOGEX 0, 0, 301, 280 STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Symbols" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN - CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,7,286,266 + CONTROL "",IDC_SYMBOLTREE,"PhTreeNew",WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP | 0xa,3,20,295,257,WS_EX_CLIENTEDGE + EDITTEXT IDC_SYMSEARCH,166,3,132,14,ES_AUTOHSCROLL END @@ -226,21 +228,6 @@ END // AFX_DIALOG_LAYOUT // -IDD_PELOADCONFIG AFX_DIALOG_LAYOUT -BEGIN - 0 -END - -IDD_PEGENERAL AFX_DIALOG_LAYOUT -BEGIN - 0 -END - -IDD_PECFG AFX_DIALOG_LAYOUT -BEGIN - 0 -END - IDD_PESYMBOLS AFX_DIALOG_LAYOUT BEGIN 0 diff --git a/tools/peview/peview.vcxproj b/tools/peview/peview.vcxproj index 54d1bce3d038..c3d2df1f85af 100644 --- a/tools/peview/peview.vcxproj +++ b/tools/peview/peview.vcxproj @@ -1,4 +1,4 @@ - + @@ -146,6 +146,7 @@ StreamingSIMDExtensions true true + true noarg.obj;noenv.obj;phlib.lib;ntdll.lib;uxtheme.lib;%(AdditionalDependencies) @@ -175,6 +176,7 @@ true true true + true noarg.obj;noenv.obj;phlib.lib;ntdll.lib;uxtheme.lib;%(AdditionalDependencies) @@ -193,6 +195,7 @@ + @@ -200,11 +203,13 @@ + + diff --git a/tools/peview/peview.vcxproj.filters b/tools/peview/peview.vcxproj.filters index a073793965cd..7395ed945c8f 100644 --- a/tools/peview/peview.vcxproj.filters +++ b/tools/peview/peview.vcxproj.filters @@ -1,4 +1,4 @@ - + @@ -51,6 +51,12 @@ Source Files + + Source Files + + + Source Files + @@ -65,6 +71,9 @@ Header Files + + Header Files + diff --git a/tools/peview/resource.h b/tools/peview/resource.h index 6c6e0f0a2ed0..56994a3e0af7 100644 --- a/tools/peview/resource.h +++ b/tools/peview/resource.h @@ -10,6 +10,11 @@ #define IDD_PELOADCONFIG 107 #define IDD_PECFG 108 #define IDD_PESYMBOLS 109 +#define IDC_SYMBOLTREE 110 +#define IDB_SEARCH_ACTIVE 111 +#define IDB_SEARCH_INACTIVE 112 +#define IDB_SEARCH_ACTIVE_BMP 113 +#define IDB_SEARCH_INACTIVE_BMP 114 #define IDC_TARGETMACHINE 1003 #define IDC_CHECKSUM 1004 #define IDC_SUBSYSTEM 1005 @@ -17,6 +22,7 @@ #define IDC_CHARACTERISTICS 1007 #define IDC_LIST 1008 #define IDC_FILEICON 1009 +#define IDC_SECTION 1009 #define IDC_TIMESTAMP 1010 #define IDC_RUNTIMEVERSION 1011 #define IDC_FILE 1011 @@ -26,6 +32,7 @@ #define IDC_VERSIONSTRING 1014 #define IDC_IMAGEBASE 1015 #define IDC_ENTRYPOINT 1016 +#define IDC_SYMSEARCH 1017 #define IDC_NAME 1044 #define IDC_COMPANYNAME_LINK 1279 @@ -33,9 +40,9 @@ // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 111 +#define _APS_NEXT_RESOURCE_VALUE 116 #define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1017 -#define _APS_NEXT_SYMED_VALUE 101 +#define _APS_NEXT_CONTROL_VALUE 1019 +#define _APS_NEXT_SYMED_VALUE 116 #endif #endif diff --git a/tools/peview/settings.c b/tools/peview/settings.c index 1d9da291d023..750ce1ace2ea 100644 --- a/tools/peview/settings.c +++ b/tools/peview/settings.c @@ -40,7 +40,7 @@ VOID PhAddDefaultSettings( PhpAddStringSetting(L"ImageImportsListViewColumns", L""); PhpAddStringSetting(L"ImageLoadCfgListViewColumns", L""); PhpAddStringSetting(L"LibListViewColumns", L""); - PhpAddStringSetting(L"PdbListViewColumns", L""); + PhpAddStringSetting(L"PdbTreeListColumns", L""); } VOID PhUpdateCachedSettings( From e83471cf44606da43a53dc3a3ed5c8f5d0907970 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 17 May 2017 05:20:51 +1000 Subject: [PATCH 0105/2058] Updater: Fix missing changelog --- plugins/Updater/page4.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/Updater/page4.c b/plugins/Updater/page4.c index 2f636ac13d0b..237e49e5de0b 100644 --- a/plugins/Updater/page4.c +++ b/plugins/Updater/page4.c @@ -62,7 +62,7 @@ VOID ShowProgressDialog( memset(&config, 0, sizeof(TASKDIALOGCONFIG)); config.cbSize = sizeof(TASKDIALOGCONFIG); - config.dwFlags = TDF_USE_HICON_MAIN | TDF_ALLOW_DIALOG_CANCELLATION | TDF_CAN_BE_MINIMIZED | TDF_ENABLE_HYPERLINKS | TDF_SHOW_PROGRESS_BAR; + config.dwFlags = TDF_USE_HICON_MAIN | TDF_ALLOW_DIALOG_CANCELLATION | TDF_CAN_BE_MINIMIZED | TDF_ENABLE_HYPERLINKS | TDF_SHOW_PROGRESS_BAR | TDF_EXPAND_FOOTER_AREA; config.dwCommonButtons = TDCBF_CANCEL_BUTTON; config.hMainIcon = Context->IconLargeHandle; config.cxWidth = 200; @@ -76,7 +76,7 @@ VOID ShowProgressDialog( Context->RevisionVersion )->Buffer; config.pszContent = L"Downloaded: ~ of ~ (0%)\r\nSpeed: ~ KB/s"; - config.pszExpandedInformation = L"View Changelog"; + config.pszExpandedInformation = PhGetString(Context->BuildMessage); SendMessage(Context->DialogHandle, TDM_NAVIGATE_PAGE, 0, (LPARAM)&config); } \ No newline at end of file From 8610f0b6c38fdde7c447252f7fc836cdff140a6c Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 17 May 2017 07:19:22 +1000 Subject: [PATCH 0106/2058] ExtendedTools: Add gpu nodes window icon --- plugins/ExtendedTools/exttools.h | 4 ++-- plugins/ExtendedTools/gpunodes.c | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/plugins/ExtendedTools/exttools.h b/plugins/ExtendedTools/exttools.h index abff31baadd4..967f6d30f356 100644 --- a/plugins/ExtendedTools/exttools.h +++ b/plugins/ExtendedTools/exttools.h @@ -28,8 +28,8 @@ extern HWND NetworkTreeNewHandle; #define SETTING_NAME_UNLOADED_COLUMNS (PLUGIN_NAME L".UnloadedListColumns") #define ET_SCALE_DPI(Value) PhMultiplyDivide(Value, PhGlobalDpi, 96) -#define ET_LOAD_SHARED_ICON_SMALL(Name) PhLoadIcon(NtCurrentPeb()->ImageBaseAddress, (Name), PH_LOAD_ICON_SHARED | PH_LOAD_ICON_SIZE_SMALL, 0, 0) -#define ET_LOAD_SHARED_ICON_LARGE(Name) PhLoadIcon(NtCurrentPeb()->ImageBaseAddress, (Name), PH_LOAD_ICON_SHARED | PH_LOAD_ICON_SIZE_LARGE, 0, 0) +#define ET_LOAD_SHARED_ICON_SMALL(Name) PhLoadIcon(PhLibImageBase, (Name), PH_LOAD_ICON_SHARED | PH_LOAD_ICON_SIZE_SMALL, 0, 0) +#define ET_LOAD_SHARED_ICON_LARGE(Name) PhLoadIcon(PhLibImageBase, (Name), PH_LOAD_ICON_SHARED | PH_LOAD_ICON_SIZE_LARGE, 0, 0) // Graph update message diff --git a/plugins/ExtendedTools/gpunodes.c b/plugins/ExtendedTools/gpunodes.c index bc863cb45bc2..fe9467dda387 100644 --- a/plugins/ExtendedTools/gpunodes.c +++ b/plugins/ExtendedTools/gpunodes.c @@ -121,6 +121,9 @@ INT_PTR CALLBACK EtpGpuNodesDlgProc( WindowHandle = hwndDlg; + SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)ET_LOAD_SHARED_ICON_SMALL(MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); + SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)ET_LOAD_SHARED_ICON_LARGE(MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); + PhInitializeLayoutManager(&LayoutManager, hwndDlg); PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDOK), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); LayoutMargin = PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDC_LAYOUT), NULL, PH_ANCHOR_ALL)->Margin; From 8a5fc2313ffe7cd477706703d917b5c637381f8b Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 17 May 2017 22:47:47 +1000 Subject: [PATCH 0107/2058] peview: Fix Symbol tab crash, Add Searchbox, Add more symbol types --- tools/peview/include/pdb.h | 3 +- tools/peview/include/peview.h | 65 +- tools/peview/pdb.c | 581 ++++++++-------- tools/peview/pdbprp.c | 474 ++++++++++++-- tools/peview/peview.rc | 99 ++- tools/peview/peview.vcxproj | 16 +- tools/peview/peview.vcxproj.filters | 20 + tools/peview/resource.h | 39 +- tools/peview/resources/ProcessHacker.ico | Bin 0 -> 97449 bytes tools/peview/resources/active_search.bmp | Bin 0 -> 1494 bytes tools/peview/resources/active_search.png | Bin 0 -> 569 bytes tools/peview/resources/inactive_search.bmp | Bin 0 -> 1494 bytes tools/peview/resources/inactive_search.png | Bin 0 -> 755 bytes tools/peview/searchbox.c | 728 +++++++++++++++++++++ 14 files changed, 1614 insertions(+), 411 deletions(-) create mode 100644 tools/peview/resources/ProcessHacker.ico create mode 100644 tools/peview/resources/active_search.bmp create mode 100644 tools/peview/resources/active_search.png create mode 100644 tools/peview/resources/inactive_search.bmp create mode 100644 tools/peview/resources/inactive_search.png create mode 100644 tools/peview/searchbox.c diff --git a/tools/peview/include/pdb.h b/tools/peview/include/pdb.h index 966415a1844e..b9e7ef2addaa 100644 --- a/tools/peview/include/pdb.h +++ b/tools/peview/include/pdb.h @@ -416,9 +416,8 @@ BOOLEAN SymbolInfo_GetTypeNameHelper( _Inout_ PPH_STRING_BUILDER TypeName ); -BOOLEAN SymbolInfo_GetTypeName( +PPH_STRING SymbolInfo_GetTypeName( _Inout_ PPDB_SYMBOL_CONTEXT Context, - _Inout_ PPH_STRING_BUILDER TypeName, _In_ ULONG Index, _In_ PWSTR VarName ); diff --git a/tools/peview/include/peview.h b/tools/peview/include/peview.h index 69987ec41906..f626710a2439 100644 --- a/tools/peview/include/peview.h +++ b/tools/peview/include/peview.h @@ -12,7 +12,9 @@ #include #include +#include #include +#include #include "resource.h" @@ -60,6 +62,16 @@ VOID PeSaveSettings( // symbols +#define WM_PV_SEARCH_FINISHED (WM_APP + 701) + +extern ULONG SearchResultsAddIndex; +extern PPH_LIST SearchResults; +extern PH_QUEUED_LOCK SearchResultsLock; + +VOID PvCreateSearchControl( + _In_ HWND WindowHandle, + _In_opt_ PWSTR BannerText + ); typedef enum _WCT_TREE_COLUMN_ITEM_NAME { @@ -67,12 +79,13 @@ typedef enum _WCT_TREE_COLUMN_ITEM_NAME TREE_COLUMN_ITEM_VA, TREE_COLUMN_ITEM_NAME, TREE_COLUMN_ITEM_SYMBOL, + TREE_COLUMN_ITEM_SIZE, TREE_COLUMN_ITEM_MAXIMUM } WCT_TREE_COLUMN_ITEM_NAME; typedef enum _PV_SYMBOL_TYPE { - PV_SYMBOL_TYPE_NONE, + PV_SYMBOL_TYPE_UNKNOWN, PV_SYMBOL_TYPE_FUNCTION, PV_SYMBOL_TYPE_SYMBOL, PV_SYMBOL_TYPE_LOCAL_VAR, @@ -81,15 +94,17 @@ typedef enum _PV_SYMBOL_TYPE PV_SYMBOL_TYPE_OBJECT_PTR, PV_SYMBOL_TYPE_STATIC_VAR, PV_SYMBOL_TYPE_GLOBAL_VAR, - PV_SYMBOL_TYPE_MEMBER, + PV_SYMBOL_TYPE_STRUCT, PV_SYMBOL_TYPE_STATIC_MEMBER, - PV_SYMBOL_TYPE_CONSTANT + PV_SYMBOL_TYPE_CONSTANT, + PV_SYMBOL_TYPE_CLASS, } PV_SYMBOL_TYPE; typedef struct _PV_SYMBOL_NODE { PH_TREENEW_NODE Node; + ULONG64 Index; PV_SYMBOL_TYPE Type; ULONG Size; ULONG64 Address; @@ -100,6 +115,43 @@ typedef struct _PV_SYMBOL_NODE PH_STRINGREF TextCache[TREE_COLUMN_ITEM_MAXIMUM]; } PV_SYMBOL_NODE, *PPV_SYMBOL_NODE; +typedef struct _PH_TN_COLUMN_MENU_DATA +{ + HWND TreeNewHandle; + PPH_TREENEW_HEADER_MOUSE_EVENT MouseEvent; + ULONG DefaultSortColumn; + PH_SORT_ORDER DefaultSortOrder; + + struct _PH_EMENU_ITEM *Menu; + struct _PH_EMENU_ITEM *Selection; + ULONG ProcessedId; +} PH_TN_COLUMN_MENU_DATA, *PPH_TN_COLUMN_MENU_DATA; + +#define PH_TN_COLUMN_MENU_HIDE_COLUMN_ID ((ULONG)-1) +#define PH_TN_COLUMN_MENU_CHOOSE_COLUMNS_ID ((ULONG)-2) +#define PH_TN_COLUMN_MENU_SIZE_COLUMN_TO_FIT_ID ((ULONG)-3) +#define PH_TN_COLUMN_MENU_SIZE_ALL_COLUMNS_TO_FIT_ID ((ULONG)-4) +#define PH_TN_COLUMN_MENU_RESET_SORT_ID ((ULONG)-5) + + VOID PhInitializeTreeNewColumnMenu( + _Inout_ PPH_TN_COLUMN_MENU_DATA Data + ); + +#define PH_TN_COLUMN_MENU_NO_VISIBILITY 0x1 +#define PH_TN_COLUMN_MENU_SHOW_RESET_SORT 0x2 + +VOID PhInitializeTreeNewColumnMenuEx( + _Inout_ PPH_TN_COLUMN_MENU_DATA Data, + _In_ ULONG Flags + ); + +BOOLEAN PhHandleTreeNewColumnMenu( + _Inout_ PPH_TN_COLUMN_MENU_DATA Data + ); + +VOID PhDeleteTreeNewColumnMenu( + _In_ PPH_TN_COLUMN_MENU_DATA Data + ); typedef struct _PH_TN_FILTER_SUPPORT { @@ -155,14 +207,17 @@ typedef struct _PDB_SYMBOL_CONTEXT HWND SearchHandle; HWND TreeNewHandle; HWND ParentWindowHandle; + HANDLE SearchThreadHandle; + HANDLE UpdateTimer; ULONG64 BaseAddress; PPH_STRING FileName; PPH_STRING SearchboxText; PPH_STRING TreeText; + PPH_LIST SymbolList; PPH_LIST UdtList; - + PH_LAYOUT_MANAGER LayoutManager; ULONG TreeNewSortColumn; @@ -187,7 +242,7 @@ VOID PvPdbProperties( VOID ); -VOID PluginsAddTreeNode( +VOID PvSymbolAddTreeNode( _In_ PPDB_SYMBOL_CONTEXT Context, _In_ PPV_SYMBOL_NODE Entry ); diff --git a/tools/peview/pdb.c b/tools/peview/pdb.c index 039dc60454e3..12ebe46f59bd 100644 --- a/tools/peview/pdb.c +++ b/tools/peview/pdb.c @@ -97,6 +97,10 @@ _SymGetModuleInfoW64 SymGetModuleInfoW64_I = NULL; _SymGetTypeInfo SymGetTypeInfo_I = NULL; _SymSetContext SymSetContext_I = NULL; +ULONG SearchResultsAddIndex = 0; +PPH_LIST SearchResults = NULL; +PH_QUEUED_LOCK SearchResultsLock = PH_QUEUED_LOCK_INIT; + BOOLEAN SymbolInfo_DumpBasicType( _Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, @@ -284,7 +288,6 @@ BOOLEAN SymbolInfo_DumpUDT( if (!SymbolInfo_CheckTag(Context, Index, SymTagUDT)) return FALSE; - // Determine UDT kind (class/structure or union?) if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, Index, TI_GET_UDTKIND, &UDTKind)) return FALSE; @@ -637,7 +640,6 @@ BOOLEAN SymbolInfo_DumpData( Info->TypeIndex = TypeIndex; Info->dataKind = (DataKind)dataKind; - // Location, depending on the data kind switch (dataKind) { case DataIsGlobal: @@ -645,12 +647,12 @@ BOOLEAN SymbolInfo_DumpData( case DataIsFileStatic: case DataIsStaticMember: { + ULONG64 address = 0; + // Use Address; Offset is not defined // Note: If it is DataIsStaticMember, then this is a static member of a class defined in another module // (it does not have an address in this module) - ULONG64 address = 0; - if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, Index, TI_GET_ADDRESS, &address)) return FALSE; @@ -664,9 +666,9 @@ BOOLEAN SymbolInfo_DumpData( case DataIsObjectPtr: case DataIsMember: { - // Use Offset; Address is not defined ULONG offset = 0; + // Use Offset; Address is not defined if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, Index, TI_GET_OFFSET, &offset)) return FALSE; @@ -676,7 +678,6 @@ BOOLEAN SymbolInfo_DumpData( break; default: - // Unknown location Info->Address = 0; Info->Offset = 0; break; @@ -693,7 +694,6 @@ BOOLEAN SymbolInfo_DumpType( { ULONG tag = SymTagNull; - // Get the symbol tag if (!SymGetTypeInfo_I( NtCurrentProcess(), Context->BaseAddress, @@ -707,7 +707,6 @@ BOOLEAN SymbolInfo_DumpType( Info->Tag = (enum SymTagEnum)tag; - // Dump information about the symbol (depending on the tag). switch (tag) { case SymTagBaseType: @@ -1494,30 +1493,26 @@ BOOLEAN SymbolInfo_GetTypeNameHelper( return TRUE; } -BOOLEAN SymbolInfo_GetTypeName( +PPH_STRING SymbolInfo_GetTypeName( _Inout_ PPDB_SYMBOL_CONTEXT Context, - _Inout_ PPH_STRING_BUILDER TypeName, _In_ ULONG Index, _In_ PWSTR VarName ) { PWSTR typeVarName = NULL; + PH_STRING_BUILDER typeNamesb; + + PhInitializeStringBuilder(&typeNamesb, 0x100); if (VarName) typeVarName = VarName; - // Obtain the type name - if (!SymbolInfo_GetTypeNameHelper(Index, Context, &typeVarName, TypeName)) - return FALSE; - - // Return the type name to the caller - //_snwprintf(pTypeName, MaxChars, L"%s", TypeName.String->Buffer); + if (!SymbolInfo_GetTypeNameHelper(Index, Context, &typeVarName, &typeNamesb)) + return NULL; - return TRUE; + return PhFinalStringBuilderString(&typeNamesb); } -/////////////////////////////////////////////////////////////////////////////// -// Data-to-string conversion functions PWSTR SymbolInfo_TagStr( _In_ enum SymTagEnum Tag ) @@ -1814,7 +1809,8 @@ VOID SymbolInfo_SymbolLocationStr( } else { - PhPrintPointer(Buffer, PTR_SUB_OFFSET(SymbolInfo->Address, SymbolInfo->ModBase)); + if (SymbolInfo->Address) + PhPrintPointer(Buffer, PTR_SUB_OFFSET(SymbolInfo->Address, SymbolInfo->ModBase)); } } @@ -1910,27 +1906,29 @@ BOOL CALLBACK EnumCallbackProc( case SymTagFunction: { PPDB_SYMBOL_CONTEXT context = Context; - PH_STRING_BUILDER typeName; PPV_SYMBOL_NODE symbol; symbol = PhAllocate(sizeof(PV_SYMBOL_NODE)); + memset(symbol, 0, sizeof(PV_SYMBOL_NODE)); + symbol->Type = PV_SYMBOL_TYPE_FUNCTION; symbol->Address = SymbolInfo->Address; symbol->Size = SymbolInfo->Size; symbol->Name = PhCreateStringEx(SymbolInfo->Name, SymbolInfo->NameLen * sizeof(WCHAR)); + symbol->Data = SymbolInfo_GetTypeName( + context, + SymbolInfo->TypeIndex, + SymbolInfo->Name + ); SymbolInfo_SymbolLocationStr(SymbolInfo, symbol->Pointer); - PhInitializeStringBuilder(&typeName, 0x100); - - if (SymbolInfo_GetTypeName(context, &typeName, SymbolInfo->TypeIndex, SymbolInfo->Name)) - symbol->Data = PhFinalStringBuilderString(&typeName); - // Flags: %x, SymbolInfo->Flags // Index: %8u, TypeIndex: %8u, SymbolInfo->Index, SymbolInfo->TypeIndex + PhAcquireQueuedLockExclusive(&SearchResultsLock); + PhAddItemList(SearchResults, symbol); + PhReleaseQueuedLockExclusive(&SearchResultsLock); - PluginsAddTreeNode(context, symbol); - - // Enumerate function parameters and local variables... + // Enumerate parameters and variables... IMAGEHLP_STACK_FRAME sf; sf.InstructionOffset = SymbolInfo->Address; SymSetContext_I(NtCurrentProcess(), &sf, 0); @@ -1940,30 +1938,27 @@ BOOL CALLBACK EnumCallbackProc( case SymTagData: { PPDB_SYMBOL_CONTEXT context = Context; - PH_STRING_BUILDER typeName; PPV_SYMBOL_NODE symbol; PWSTR symDataKind; ULONG dataKindType = 0; - // TODO: Remove filter if (!SymbolInfo->Address) break; if (!SymGetTypeInfo_I(NtCurrentProcess(), SymbolInfo->ModBase, SymbolInfo->Index, TI_GET_DATAKIND, &dataKindType)) break; - // Type symDataKind = SymbolInfo_DataKindStr(dataKindType); - // TODO: Remove filter - if (!wcscmp(symDataKind, L"LOCAL_VAR") || - !wcscmp(symDataKind, L"OBJECT_PTR") || - !wcscmp(symDataKind, L"PARAMETER")) - { - break; - } + //if (dataKindType == DataIsLocal || + // dataKindType == DataIsObjectPtr || + // dataKindType == DataIsParam) + //{ + // break; + //} symbol = PhAllocate(sizeof(PV_SYMBOL_NODE)); + memset(symbol, 0, sizeof(PV_SYMBOL_NODE)); switch (dataKindType) { @@ -1986,7 +1981,7 @@ BOOL CALLBACK EnumCallbackProc( symbol->Type = PV_SYMBOL_TYPE_GLOBAL_VAR; break; case DataIsMember: - symbol->Type = PV_SYMBOL_TYPE_MEMBER; + symbol->Type = PV_SYMBOL_TYPE_STRUCT; break; case DataIsStaticMember: symbol->Type = PV_SYMBOL_TYPE_STATIC_MEMBER; @@ -1994,51 +1989,48 @@ BOOL CALLBACK EnumCallbackProc( case DataIsConstant: symbol->Type = PV_SYMBOL_TYPE_CONSTANT; break; + default: + symbol->Type = PV_SYMBOL_TYPE_UNKNOWN; + break; } symbol->Address = SymbolInfo->Address; symbol->Size = SymbolInfo->Size; symbol->Name = PhCreateStringEx(SymbolInfo->Name, SymbolInfo->NameLen * sizeof(WCHAR)); + symbol->Data = SymbolInfo_GetTypeName(context, SymbolInfo->TypeIndex, SymbolInfo->Name); SymbolInfo_SymbolLocationStr(SymbolInfo, symbol->Pointer); - PhInitializeStringBuilder(&typeName, 0x100); - - // Data - if (SymbolInfo_GetTypeName(context, &typeName, SymbolInfo->TypeIndex, SymbolInfo->Name)) - symbol->Data = PhFinalStringBuilderString(&typeName); - // Flags: %x, SymbolInfo->Flags // Index: %8u, TypeIndex: %8u, SymbolInfo->Index, SymbolInfo->TypeIndex - - PluginsAddTreeNode(context, symbol); + PhAcquireQueuedLockExclusive(&SearchResultsLock); + PhAddItemList(SearchResults, symbol); + PhReleaseQueuedLockExclusive(&SearchResultsLock); } break; default: { PPDB_SYMBOL_CONTEXT context = Context; - PH_STRING_BUILDER typeName; PPV_SYMBOL_NODE symbol; // TODO: Remove filter - if (SymbolInfo->Tag != SymTagPublicSymbol) - break; + //if (SymbolInfo->Tag != SymTagPublicSymbol) + // break; symbol = PhAllocate(sizeof(PV_SYMBOL_NODE)); + memset(symbol, 0, sizeof(PV_SYMBOL_NODE)); + symbol->Type = PV_SYMBOL_TYPE_SYMBOL; symbol->Address = SymbolInfo->Address; symbol->Size = SymbolInfo->Size; symbol->Name = PhCreateStringEx(SymbolInfo->Name, SymbolInfo->NameLen * sizeof(WCHAR)); + symbol->Data = SymbolInfo_GetTypeName(context, SymbolInfo->TypeIndex, SymbolInfo->Name); SymbolInfo_SymbolLocationStr(SymbolInfo, symbol->Pointer); - PhInitializeStringBuilder(&typeName, 0x100); - - if (SymbolInfo_GetTypeName(context, &typeName, SymbolInfo->TypeIndex, SymbolInfo->Name)) - symbol->Data = PhFinalStringBuilderString(&typeName); - // Flags: %x, SymbolInfo->Flags // Index: %8u, TypeIndex: %8u, SymbolInfo->Index, SymbolInfo->TypeIndex - - PluginsAddTreeNode(context, symbol); + PhAcquireQueuedLockExclusive(&SearchResultsLock); + PhAddItemList(SearchResults, symbol); + PhReleaseQueuedLockExclusive(&SearchResultsLock); } break; } @@ -2053,31 +2045,31 @@ VOID PrintClassInfo( _In_ UdtClassInfo* Info ) { - //INT lvItemIndex; + PPV_SYMBOL_NODE symbol; + + symbol = PhAllocate(sizeof(PV_SYMBOL_NODE)); + memset(symbol, 0, sizeof(PV_SYMBOL_NODE)); + + symbol->Type = PV_SYMBOL_TYPE_CLASS; + //symbol->Address = VarInfo.sDataInfo.Address; + //symbol->Size = (ULONG)Info->Offset; + symbol->Name = SymbolInfo_GetTypeName(Context, Index, Info->Name);// PhCreateString(SymbolInfo_UdtKindStr(Info->UDTKind)); + //symbol->Data = SymbolInfo_GetTypeName(Context, Index, Info->Name); - if (Info->UDTKind == UdtClass) - { - //PhAddItemList(L"CLASS", Info->Name) - //return; - } + if (PhEqualString2(symbol->Name, L"STRUCT", TRUE)) + symbol->Type = PV_SYMBOL_TYPE_STRUCT; + + //SymbolInfo_SymbolLocationStr(SymbolInfo, symbol->Pointer); + + PhAcquireQueuedLockExclusive(&SearchResultsLock); + PhAddItemList(SearchResults, symbol); + PhReleaseQueuedLockExclusive(&SearchResultsLock); + + // Info.Nested + // Info->NumVariables + // Info->NumFunctions + // Info->NumBaseClasses - // UDT kind - //lvItemIndex = PhAddListViewItem(Context->ListviewHandle, MAXINT, SymbolInfo_UdtKindStr(Info->UDTKind), NULL); - // Name - //PhSetListViewSubItem(Context->ListviewHandle, lvItemIndex, 2, Info->Name); - // Size - //PhSetListViewSubItem(Context->ListviewHandle, lvItemIndex, 3, PhaFormatSize(Info->Length, -1)->Buffer); - - // Nested - //if (Info.Nested) OutputDebugString(L" Nested"); - // Number of member variables - //OutputDebugString(PhaFormatString(L" Variables: %d", Info->NumVariables)->Buffer); - // Number of member functions - //OutputDebugString(PhaFormatString(L" Functions: %d", Info->NumFunctions)->Buffer); - // Number of base classes - //OutputDebugString(PhaFormatString(L" Base classes: %d", Info->NumBaseClasses)->Buffer); - - // Extended information about member variables for (ULONG i = 0; i < Info->NumVariables; i++) { TypeInfo VarInfo; @@ -2091,22 +2083,7 @@ VOID PrintClassInfo( // Unexpected symbol tag. } else - { - //INT lvItemSubIndex; - //PH_STRING_BUILDER typeName; - // - //PhInitializeStringBuilder(&typeName, 0x100); - // - //// Variable - //lvItemSubIndex = PhAddListViewItem(Context->ListviewHandle, MAXINT, SymbolInfo_DataKindStr(VarInfo.sDataInfo.dataKind), NULL); - // - //// Name - //PhSetListViewSubItem(Context->ListviewHandle, lvItemSubIndex, 2, VarInfo.sDataInfo.Name); - // - //// Data - //if (SymbolInfo_GetTypeName(Context, &typeName, VarInfo.sDataInfo.TypeIndex, VarInfo.sDataInfo.Name)) - // PhSetListViewSubItem(Context->ListviewHandle, lvItemSubIndex, 4, PhFinalStringBuilderString(&typeName)->Buffer); - //PhDeleteStringBuilder(&typeName); + { // Location //switch (VarInfo.sDataInfo.dataKind) //{ @@ -2132,11 +2109,39 @@ VOID PrintClassInfo( // break; // TODO Add support for constants //} // - // Indices " Index: %8u TypeIndex: %8u" Index, VarInfo.sDataInfo.TypeIndex + //PPV_SYMBOL_NODE symbol; + // + //symbol = PhAllocate(sizeof(PV_SYMBOL_NODE)); + //memset(symbol, 0, sizeof(PV_SYMBOL_NODE)); + // + //symbol->Type = PV_SYMBOL_TYPE_MEMBER; + //symbol->Address = VarInfo.sDataInfo.Address; + //symbol->Size = (ULONG)VarInfo.sDataInfo.Offset; + //symbol->Name = PhCreateString(VarInfo.sDataInfo.Name); + //SymbolInfo_SymbolLocationStr(SymbolInfo, symbol->Pointer); + // + // Data + //if (SymbolInfo_GetTypeName(Context, &typeName, VarInfo.sDataInfo.TypeIndex, VarInfo.sDataInfo.Name)) + // symbol->Data = PhFinalStringBuilderString(&typeName); + // Flags: %x, SymbolInfo->Flags + // Index: %8u, TypeIndex: %8u, SymbolInfo->Index, SymbolInfo->TypeIndex + // Nested + //if (Info.Info.sUdtClassInfo.Nested) + // printf("Nested"); + // + // Number of members + //printf(" Members: %d", Info.Info.sUdtClassInfo.NumVariables); + // + //PhAcquireQueuedLockExclusive(&SearchResultsLock); + //PhAddItemList(SearchResults, symbol); + //PhReleaseQueuedLockExclusive(&SearchResultsLock); + // + // Update the search results in batches of 2000. + //if (SearchResults->Count % 2000 == 0) + // PostMessage(Context->DialogHandle, WM_PV_SEARCH_UPDATE, 0, 0); } } - // TODO Implement information about member functions for (ULONG i = 0; i < Info->NumFunctions; i++) { TypeInfo VarInfo; @@ -2151,42 +2156,34 @@ VOID PrintClassInfo( } else { - //INT lvItemSubIndex; - //PH_STRING_BUILDER typeName; - // - //PhInitializeStringBuilder(&typeName, 0x100); - // - // Type - //lvItemSubIndex = PhAddListViewItem(Context->ListviewHandle, MAXINT, L"VARIABLE", NULL); + PPV_SYMBOL_NODE symbol; + + symbol = PhAllocate(sizeof(PV_SYMBOL_NODE)); + memset(symbol, 0, sizeof(PV_SYMBOL_NODE)); + + symbol->Type = PV_SYMBOL_TYPE_STRUCT; + symbol->Address = VarInfo.sDataInfo.Address; + symbol->Size = (ULONG)VarInfo.sDataInfo.Offset; + symbol->Name = PhCreateString(VarInfo.sDataInfo.Name); + symbol->Data = SymbolInfo_GetTypeName(Context, VarInfo.sDataInfo.TypeIndex, VarInfo.sDataInfo.Name); + //SymbolInfo_SymbolLocationStr(SymbolInfo, symbol->Pointer); + // Info.Info.sUdtClassInfo.Nested + // Info.Info.sUdtClassInfo.NumVariables + + PhAcquireQueuedLockExclusive(&SearchResultsLock); + PhAddItemList(SearchResults, symbol); + PhReleaseQueuedLockExclusive(&SearchResultsLock); - // Address - // SymbolInfo_SymbolLocationStr(Context, VarInfo.sDataInfo.Address); - //PhSetListViewSubItem(Context->ListviewHandle, lvItemIndex, 1, pointer); VarInfo.sDataInfo.Address - // - // Name : SymbolInfo_DataKindStr(VarInfo.sDataInfo.dataKind) - //PhSetListViewSubItem(Context->ListviewHandle, lvItemIndex, 2, VarInfo.sDataInfo.Name); - // - // Size - //PhSetListViewSubItem(Context->ListviewHandle, lvItemIndex, 3, VarInfo.sDataInfo.Offset - // - // Data - //if (SymbolInfo_GetTypeName(Context, &typeName, SymbolInfo->TypeIndex, SymbolInfo->Name)) - // PhSetListViewSubItem(Context->ListviewHandle, lvItemIndex, 4, PhFinalStringBuilderString(&typeName)->Buffer); - // - // Flags: %x, SymbolInfo->Flags - // Index: %8u, TypeIndex: %8u, SymbolInfo->Index, SymbolInfo->TypeIndex - // - //PhDeleteStringBuilder(&typeName); - // // Enumerate function parameters and local variables... - // IMAGEHLP_STACK_FRAME sf; - //sf.InstructionOffset = SymbolInfo->Address; VarInfo.sDataInfo.Offset - //SymSetContext_I(NtCurrentProcess(), &sf, 0); - //SymEnumSymbolsW_I(NtCurrentProcess(), 0, NULL, EnumCallbackProc, Context); + IMAGEHLP_STACK_FRAME sf; + + sf.InstructionOffset = VarInfo.sDataInfo.Address; + + SymSetContext_I(NtCurrentProcess(), &sf, 0); + SymEnumSymbolsW_I(NtCurrentProcess(), 0, NULL, EnumCallbackProc, Context); } } - // TODO Implement information about base classes for (ULONG i = 0; i < Info->NumBaseClasses; i++) { TypeInfo baseInfo; @@ -2284,132 +2281,56 @@ VOID PrintUserDefinedTypes( } else { - //INT lvItemIndex; - // UDT kind - //lvItemIndex = PhAddListViewItem(Context->ListviewHandle, MAXINT, SymbolInfo_UdtKindStr(info.sUdtClassInfo.UDTKind), NULL); - // Name - //PhSetListViewSubItem(Context->ListviewHandle, lvItemIndex, 2, info.sUdtClassInfo.Name); - // Size - //PhSetListViewSubItem(Context->ListviewHandle, lvItemIndex, 3, PhaFormatString(L"%I64u", info.sUdtClassInfo.Length)->Buffer); - - // Nested - //if (Info.Info.sUdtClassInfo.Nested) - // printf("Nested"); - // - // Number of members - //printf(" Members: %d", Info.Info.sUdtClassInfo.NumVariables); - } - } - } - } -} + PPV_SYMBOL_NODE symbol; -BOOLEAN GetFileParamsSize( - _In_ PWSTR FileName, - _Out_ ULONG *FileLength - ) -{ - HANDLE hFile = CreateFile( - FileName, - GENERIC_READ, - FILE_SHARE_READ, - NULL, - OPEN_EXISTING, - 0, - NULL - ); + symbol = PhAllocate(sizeof(PV_SYMBOL_NODE)); + memset(symbol, 0, sizeof(PV_SYMBOL_NODE)); - if (hFile == INVALID_HANDLE_VALUE) - { - return FALSE; - } + symbol->Type = PV_SYMBOL_TYPE_CLASS; + //symbol->Address = VarInfo.sDataInfo.Address; + //symbol->Size = (ULONG)Info->Offset; + symbol->Name = SymbolInfo_GetTypeName(Context, index, info.sUdtUnionInfo.Name); + // PhCreateString(SymbolInfo_UdtKindStr(Info->UDTKind)); + symbol->Data = SymbolInfo_GetTypeName(Context, index, info.sUdtUnionInfo.Name); - *FileLength = GetFileSize(hFile, NULL); - NtClose(hFile); + if (PhEqualString2(symbol->Name, L"STRUCT", TRUE)) + symbol->Type = PV_SYMBOL_TYPE_STRUCT; - return (*FileLength != INVALID_FILE_SIZE); -} - -BOOLEAN GetFileParams( - _In_ PWSTR FileName, - _Out_ ULONG64 *BaseAddress, - _Out_ ULONG *FileLength - ) -{ - TCHAR szFileExt[_MAX_EXT] = { 0 }; - - _wsplitpath(FileName, NULL, NULL, NULL, szFileExt); - - if (_wcsicmp(szFileExt, L".PDB") == 0) - { - *BaseAddress = 0x10000000; - - if (!GetFileParamsSize(FileName, FileLength)) - return FALSE; - } - else - { - *BaseAddress = 0; - *FileLength = 0; - } - - return TRUE; -} - -// -// TODO: Move to pdbprp.c -// - -VOID PdbLoadDbgHelpFromPath( - _In_ PWSTR DbgHelpPath - ) -{ - HMODULE dbghelpModule; - - if (dbghelpModule = LoadLibrary(DbgHelpPath)) - { - PPH_STRING fullDbghelpPath; - ULONG indexOfFileName; - PH_STRINGREF dbghelpFolder; - PPH_STRING symsrvPath; - - fullDbghelpPath = PhGetDllFileName(dbghelpModule, &indexOfFileName); - - if (fullDbghelpPath) - { - if (indexOfFileName != 0) - { - static PH_STRINGREF symsrvString = PH_STRINGREF_INIT(L"\\symsrv.dll"); + //SymbolInfo_SymbolLocationStr(SymbolInfo, symbol->Pointer); - dbghelpFolder.Buffer = fullDbghelpPath->Buffer; - dbghelpFolder.Length = indexOfFileName * sizeof(WCHAR); + PhAcquireQueuedLockExclusive(&SearchResultsLock); + PhAddItemList(SearchResults, symbol); + PhReleaseQueuedLockExclusive(&SearchResultsLock); - symsrvPath = PhConcatStringRef2(&dbghelpFolder, &symsrvString); + // Print information about the union + for (ULONG i = 0; i < info.sUdtUnionInfo.NumMembers; i++) + { + TypeInfo baseInfo; - LoadLibrary(symsrvPath->Buffer); + if (!SymbolInfo_DumpType(Context, info.sUdtUnionInfo.Members[i], &baseInfo)) + { + // Continue + } + else if (baseInfo.Tag != SymTagBaseClass) + { + // Continue + } + else + { - PhDereferenceObject(symsrvPath); + } + } + } } - - PhDereferenceObject(fullDbghelpPath); } } - else - { - dbghelpModule = LoadLibrary(L"dbghelp.dll"); - } - - PhSymbolProviderCompleteInitialization(dbghelpModule); } -VOID ShowSymbolInfo( +VOID ShowModuleSymbolInfo( _In_ ULONG64 BaseAddress ) { - IMAGEHLP_MODULE64 info; - - memset(&info, 0, sizeof(IMAGEHLP_MODULE64)); - info.SizeOfStruct = sizeof(IMAGEHLP_MODULE64); + IMAGEHLP_MODULE64 info = { sizeof(IMAGEHLP_MODULE64) }; if (!SymGetModuleInfoW64_I(NtCurrentProcess(), BaseAddress, &info)) return; @@ -2417,86 +2338,130 @@ VOID ShowSymbolInfo( switch (info.SymType) { case SymNone: - OutputDebugString(L"No symbols available for the module.\r\n"); + //PhCreateString(L"No symbols available for the module."); break; case SymExport: - //OutputDebugString(L"Loaded symbols: Exports\r\n"); + //PhFormatString(L"Loaded Exports symbols, Type information: %s", info.TypeInfo ? L"Available" : L"Not available"); break; case SymCoff: - //OutputDebugString(L"Loaded symbols: COFF\r\n"); + //PhFormatString(L"Loaded COFF symbols, Type information: %s", info.TypeInfo ? L"Available" : L"Not available"); break; case SymCv: - //OutputDebugString(L"Loaded symbols: CodeView\r\n"); + //PhFormatString(L"Loaded CodeView symbols, Type information: %s", info.TypeInfo ? L"Available" : L"Not available"); break; case SymSym: - //OutputDebugString(L"Loaded symbols: SYM\r\n"); + //PhFormatString(L"Loaded SYM symbols, Type information: %s", info.TypeInfo ? L"Available" : L"Not available"); break; case SymVirtual: - //OutputDebugString(L"Loaded symbols: Virtual\r\n"); + //PhFormatString(L"Loaded Virtual symbols, Type information: %s", info.TypeInfo ? L"Available" : L"Not available"); break; case SymPdb: - //OutputDebugString(L"Loaded symbols: PDB\r\n"); + //PhFormatString(L"Loaded PDB symbols, Type information: %s", info.TypeInfo ? L"Available" : L"Not available"); break; case SymDia: - //OutputDebugString(L"Loaded symbols: DIA\r\n"); + //PhFormatString(L"Loaded DIA symbols, Type information: %s", info.TypeInfo ? L"Available" : L"Not available"); break; case SymDeferred: - //OutputDebugString(L"Loaded symbols: Deferred\r\n"); // not actually loaded + //PhCreateString(L"Loaded Deferred symbols"); // not actually loaded break; default: - //OutputDebugString(L"Loaded symbols: Unknown format.\r\n"); + //PhCreateString(L"Error: Unknown symbol format."); break; } - // Image name - if (wcslen(info.ImageName) > 0) - { - //OutputDebugString(PhaFormatString(L"Image name: %s\n", info.ImageName)->Buffer); - } + //if (wcslen(info.ImageName) > 0) + //L"Image name: %s\n" info.ImageName + //if (wcslen(info.LoadedImageName) > 0) + //L"Loaded image name: %s\n" info.LoadedImageName + //if (wcslen(info.LoadedPdbName) > 0) + //L"PDB file name: %s\n" info.LoadedPdbName + // (It can only happen if the debug information is contained in a separate file (.DBG or .PDB) + //if (info.PdbUnmatched || info.DbgUnmatched) + // L"Warning: Unmatched symbols. + + //PhaFormatString(L"Line numbers: %s\n", info.LineNumbers ? L"Available" : L"Not available")->Buffer + //PhaFormatString(L"Global symbols: %s\n", info.GlobalSymbols ? L"Available" : L"Not available")->Buffer + //PhaFormatString(L"Type information: %s\n", info.TypeInfo ? L"Available" : L"Not available")->Buffer + //PhaFormatString(L"Source indexing: %s\n", info.SourceIndexed ? L"Yes" : L"No")->Buffer + //PhaFormatString(L"Public symbols: %s\n", info.Publics ? L"Available" : L"Not available")->Buffer +} - // Loaded image name - if (wcslen(info.LoadedImageName) > 0) +PPH_STRING PvFindDbghelpPath( + _In_ ULONG Type + ) +{ + static struct { - //OutputDebugString(PhaFormatString(L"Loaded image name: %s\n", info.LoadedImageName)->Buffer); - } - - // Loaded PDB name - if (wcslen(info.LoadedPdbName) > 0) + BOOLEAN Type; + ULONG Folder; + PWSTR AppendPath; + } locations[] = { - //OutputDebugString(PhaFormatString(L"PDB file name: %s\n", info.LoadedPdbName)->Buffer); - } +#ifdef _WIN64 + { FALSE, CSIDL_PROGRAM_FILESX86, L"\\Windows Kits\\10\\Debuggers\\x64\\dbghelp.dll" }, + { FALSE, CSIDL_PROGRAM_FILESX86, L"\\Windows Kits\\8.1\\Debuggers\\x64\\dbghelp.dll" }, + { FALSE, CSIDL_PROGRAM_FILESX86, L"\\Windows Kits\\8.0\\Debuggers\\x64\\dbghelp.dll" }, + { FALSE, CSIDL_PROGRAM_FILES, L"\\Debugging Tools for Windows (x64)\\dbghelp.dll" }, + { TRUE, CSIDL_PROGRAM_FILESX86, L"\\Windows Kits\\10\\Debuggers\\x64\\symsrv.dll" }, + { TRUE, CSIDL_PROGRAM_FILESX86, L"\\Windows Kits\\8.1\\Debuggers\\x64\\symsrv.dll" }, + { TRUE, CSIDL_PROGRAM_FILESX86, L"\\Windows Kits\\8.0\\Debuggers\\x64\\symsrv.dll" }, + { TRUE, CSIDL_PROGRAM_FILES, L"\\Debugging Tools for Windows (x64)\\symsrv.dll" } +#else + { FALSE, CSIDL_PROGRAM_FILES, L"\\Windows Kits\\10\\Debuggers\\x86\\dbghelp.dll" }, + { FALSE, CSIDL_PROGRAM_FILES, L"\\Windows Kits\\8.1\\Debuggers\\x86\\dbghelp.dll" }, + { FALSE, CSIDL_PROGRAM_FILES, L"\\Windows Kits\\8.0\\Debuggers\\x86\\dbghelp.dll" }, + { FALSE, CSIDL_PROGRAM_FILES, L"\\Debugging Tools for Windows (x86)\\dbghelp.dll" }, + { TRUE, CSIDL_PROGRAM_FILES, L"\\Windows Kits\\10\\Debuggers\\x86\\symsrv.dll" }, + { TRUE, CSIDL_PROGRAM_FILES, L"\\Windows Kits\\8.1\\Debuggers\\x86\\symsrv.dll" }, + { TRUE, CSIDL_PROGRAM_FILES, L"\\Windows Kits\\8.0\\Debuggers\\x86\\symsrv.dll" }, + { TRUE, CSIDL_PROGRAM_FILES, L"\\Debugging Tools for Windows (x86)\\symsrv.dll" } +#endif + }; + + PPH_STRING path; + ULONG i; - // Is debug information unmatched ? - // (It can only happen if the debug information is contained in a separate file (.DBG or .PDB) - if (info.PdbUnmatched || info.DbgUnmatched) + for (i = 0; i < sizeof(locations) / sizeof(locations[0]); i++) { - OutputDebugString(L"Warning: Unmatched symbols. \n"); + if (locations[i].Type != Type) + continue; + + path = PhGetKnownLocation(locations[i].Folder, locations[i].AppendPath); + + if (path) + { + if (RtlDoesFileExists_U(path->Buffer)) + return path; + + PhDereferenceObject(path); + } } - // Load address: BaseAddress - //OutputDebugString(PhaFormatString(L"Line numbers: %s\n", info.LineNumbers ? L"Available" : L"Not available")->Buffer); - //OutputDebugString(PhaFormatString(L"Global symbols: %s\n", info.GlobalSymbols ? L"Available" : L"Not available")->Buffer); - //OutputDebugString(PhaFormatString(L"Type information: %s\n", info.TypeInfo ? L"Available" : L"Not available")->Buffer); - //OutputDebugString(PhaFormatString(L"Source indexing: %s\n", info.SourceIndexed ? L"Yes" : L"No")->Buffer); - //OutputDebugString(PhaFormatString(L"Public symbols: %s\n", info.Publics ? L"Available" : L"Not available")->Buffer); + return NULL; } NTSTATUS PeDumpFileSymbols( _In_ PPDB_SYMBOL_CONTEXT Context ) { + NTSTATUS status; + HANDLE fileHandle; HMODULE dbghelpHandle; HMODULE symsrvHandle; ULONG64 symbolBaseAddress; ULONG64 baseAddress = 0; - ULONG fileLength = 0; + LARGE_INTEGER fileSize; + PPH_STRING dbghelpPath; + PPH_STRING symsrvPath; - PdbLoadDbgHelpFromPath(L"C:\\Program Files (x86)\\Windows Kits\\10\\Debuggers\\x64\\dbghelp.dll"); + dbghelpPath = PvFindDbghelpPath(FALSE); + symsrvPath = PvFindDbghelpPath(TRUE); + dbghelpHandle = LoadLibrary(dbghelpPath->Buffer); + symsrvHandle = LoadLibrary(symsrvPath->Buffer); if (!(dbghelpHandle = GetModuleHandle(L"dbghelp.dll"))) return 1; - - symsrvHandle = GetModuleHandle(L"symsrv.dll"); + SymInitialize_I = PhGetProcedureAddress(dbghelpHandle, "SymInitialize", 0); SymCleanup_I = PhGetProcedureAddress(dbghelpHandle, "SymCleanup", 0); SymEnumSymbolsW_I = PhGetProcedureAddress(dbghelpHandle, "SymEnumSymbolsW", 0); @@ -2516,34 +2481,56 @@ NTSTATUS PeDumpFileSymbols( if (!SymSetSearchPathW_I(NtCurrentProcess(), L"SRV*C:\\symbols*http://msdl.microsoft.com/download/symbols")) goto CleanupExit; - if (GetFileParams(PvFileName->Buffer, &baseAddress, &fileLength)) + status = PhCreateFileWin32( + &fileHandle, + PhGetString(PvFileName), + FILE_GENERIC_READ, + 0, + FILE_SHARE_READ | FILE_SHARE_DELETE, + FILE_OPEN, + FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT + ); + + if (!NT_SUCCESS(status)) + return status; + + if (NT_SUCCESS(PhGetFileSize(fileHandle, &fileSize)) && fileSize.QuadPart == 0) { - if ((symbolBaseAddress = SymLoadModuleExW_I( - NtCurrentProcess(), - NULL, - PvFileName->Buffer, - NULL, - baseAddress, - fileLength, - NULL, - 0 - ))) - { - Context->BaseAddress = symbolBaseAddress; - Context->UdtList = PhCreateList(0x100); + NtClose(fileHandle); + return status; + } - ShowSymbolInfo(symbolBaseAddress); + if (PhEndsWithString2(PvFileName, L".pdb", TRUE)) + baseAddress = 0x10000000; - SymEnumSymbolsW_I(NtCurrentProcess(), symbolBaseAddress, NULL, EnumCallbackProc, Context); + if ((symbolBaseAddress = SymLoadModuleExW_I( + NtCurrentProcess(), + NULL, + PhGetString(PvFileName), + NULL, + baseAddress, + (ULONG)fileSize.QuadPart, + NULL, + 0 + ))) + { + Context->UdtList = PhCreateList(0x100); + Context->BaseAddress = symbolBaseAddress; - // Print information about used defined types - PrintUserDefinedTypes(Context); - } + //ShowModuleSymbolInfo(symbolBaseAddress); + SymEnumSymbolsW_I(NtCurrentProcess(), symbolBaseAddress, NULL, EnumCallbackProc, Context); + + // Enumerate user defined types + PrintUserDefinedTypes(Context); } CleanupExit: SymCleanup_I(NtCurrentProcess()); + NtClose(fileHandle); + + PostMessage(Context->DialogHandle, WM_PV_SEARCH_FINISHED, 0, 0); + return 0; } diff --git a/tools/peview/pdbprp.c b/tools/peview/pdbprp.c index 93459540ebf7..4b04ccfd2605 100644 --- a/tools/peview/pdbprp.c +++ b/tools/peview/pdbprp.c @@ -22,8 +22,232 @@ #include #include +#include #include "colmgr.h" +VOID PhInitializeTreeNewColumnMenu( + _Inout_ PPH_TN_COLUMN_MENU_DATA Data + ) +{ + PhInitializeTreeNewColumnMenuEx(Data, 0); +} + +VOID PhInitializeTreeNewColumnMenuEx( + _Inout_ PPH_TN_COLUMN_MENU_DATA Data, + _In_ ULONG Flags + ) +{ + PPH_EMENU_ITEM resetSortMenuItem = NULL; + PPH_EMENU_ITEM sizeColumnToFitMenuItem; + PPH_EMENU_ITEM sizeAllColumnsToFitMenuItem; + PPH_EMENU_ITEM hideColumnMenuItem; + PPH_EMENU_ITEM chooseColumnsMenuItem; + ULONG minimumNumberOfColumns; + + Data->Menu = PhCreateEMenu(); + Data->Selection = NULL; + Data->ProcessedId = 0; + + sizeColumnToFitMenuItem = PhCreateEMenuItem(0, PH_TN_COLUMN_MENU_SIZE_COLUMN_TO_FIT_ID, L"Size column to fit", NULL, NULL); + sizeAllColumnsToFitMenuItem = PhCreateEMenuItem(0, PH_TN_COLUMN_MENU_SIZE_ALL_COLUMNS_TO_FIT_ID, L"Size all columns to fit", NULL, NULL); + + if (!(Flags & PH_TN_COLUMN_MENU_NO_VISIBILITY)) + { + hideColumnMenuItem = PhCreateEMenuItem(0, PH_TN_COLUMN_MENU_HIDE_COLUMN_ID, L"Hide column", NULL, NULL); + chooseColumnsMenuItem = PhCreateEMenuItem(0, PH_TN_COLUMN_MENU_CHOOSE_COLUMNS_ID, L"Choose columns...", NULL, NULL); + } + + if (Flags & PH_TN_COLUMN_MENU_SHOW_RESET_SORT) + { + ULONG sortColumn; + PH_SORT_ORDER sortOrder; + + TreeNew_GetSort(Data->TreeNewHandle, &sortColumn, &sortOrder); + + if (sortOrder != Data->DefaultSortOrder || (Data->DefaultSortOrder != NoSortOrder && sortColumn != Data->DefaultSortColumn)) + resetSortMenuItem = PhCreateEMenuItem(0, PH_TN_COLUMN_MENU_RESET_SORT_ID, L"Reset sort", NULL, NULL); + } + + PhInsertEMenuItem(Data->Menu, sizeColumnToFitMenuItem, -1); + PhInsertEMenuItem(Data->Menu, sizeAllColumnsToFitMenuItem, -1); + + if (!(Flags & PH_TN_COLUMN_MENU_NO_VISIBILITY)) + { + PhInsertEMenuItem(Data->Menu, hideColumnMenuItem, -1); + + if (resetSortMenuItem) + PhInsertEMenuItem(Data->Menu, resetSortMenuItem, -1); + + PhInsertEMenuItem(Data->Menu, PhCreateEMenuItem(PH_EMENU_SEPARATOR, 0, L"", NULL, NULL), -1); + PhInsertEMenuItem(Data->Menu, chooseColumnsMenuItem, -1); + + if (TreeNew_GetFixedColumn(Data->TreeNewHandle)) + minimumNumberOfColumns = 2; // don't allow user to remove all normal columns (the fixed column can never be removed) + else + minimumNumberOfColumns = 1; + + if (!Data->MouseEvent || !Data->MouseEvent->Column || + Data->MouseEvent->Column->Fixed || // don't allow the fixed column to be hidden + TreeNew_GetVisibleColumnCount(Data->TreeNewHandle) < minimumNumberOfColumns + 1 + ) + { + hideColumnMenuItem->Flags |= PH_EMENU_DISABLED; + } + } + else + { + if (resetSortMenuItem) + PhInsertEMenuItem(Data->Menu, resetSortMenuItem, -1); + } + + if (!Data->MouseEvent || !Data->MouseEvent->Column) + { + sizeColumnToFitMenuItem->Flags |= PH_EMENU_DISABLED; + } +} + +VOID PhpEnsureValidSortColumnTreeNew( + _Inout_ HWND TreeNewHandle, + _In_ ULONG DefaultSortColumn, + _In_ PH_SORT_ORDER DefaultSortOrder + ) +{ + ULONG sortColumn; + PH_SORT_ORDER sortOrder; + + // Make sure the column we're sorting by is actually visible, and if not, don't sort anymore. + + TreeNew_GetSort(TreeNewHandle, &sortColumn, &sortOrder); + + if (sortOrder != NoSortOrder) + { + PH_TREENEW_COLUMN column; + + TreeNew_GetColumn(TreeNewHandle, sortColumn, &column); + + if (!column.Visible) + { + if (DefaultSortOrder != NoSortOrder) + { + // Make sure the default sort column is visible. + TreeNew_GetColumn(TreeNewHandle, DefaultSortColumn, &column); + + if (!column.Visible) + { + ULONG maxId; + ULONG id; + BOOLEAN found; + + // Use the first visible column. + maxId = TreeNew_GetMaxId(TreeNewHandle); + id = 0; + found = FALSE; + + while (id <= maxId) + { + if (TreeNew_GetColumn(TreeNewHandle, id, &column)) + { + if (column.Visible) + { + DefaultSortColumn = id; + found = TRUE; + break; + } + } + + id++; + } + + if (!found) + { + DefaultSortColumn = 0; + DefaultSortOrder = NoSortOrder; + } + } + } + + TreeNew_SetSort(TreeNewHandle, DefaultSortColumn, DefaultSortOrder); + } + } +} + +BOOLEAN PhHandleTreeNewColumnMenu( + _Inout_ PPH_TN_COLUMN_MENU_DATA Data + ) +{ + if (!Data->Selection) + return FALSE; + + switch (Data->Selection->Id) + { + case PH_TN_COLUMN_MENU_RESET_SORT_ID: + { + TreeNew_SetSort(Data->TreeNewHandle, Data->DefaultSortColumn, Data->DefaultSortOrder); + } + break; + case PH_TN_COLUMN_MENU_SIZE_COLUMN_TO_FIT_ID: + { + if (Data->MouseEvent && Data->MouseEvent->Column) + { + TreeNew_AutoSizeColumn(Data->TreeNewHandle, Data->MouseEvent->Column->Id, 0); + } + } + break; + case PH_TN_COLUMN_MENU_SIZE_ALL_COLUMNS_TO_FIT_ID: + { + ULONG maxId; + ULONG id; + + maxId = TreeNew_GetMaxId(Data->TreeNewHandle); + id = 0; + + while (id <= maxId) + { + TreeNew_AutoSizeColumn(Data->TreeNewHandle, id, 0); + id++; + } + } + break; + case PH_TN_COLUMN_MENU_HIDE_COLUMN_ID: + { + PH_TREENEW_COLUMN column; + + if (Data->MouseEvent && Data->MouseEvent->Column && !Data->MouseEvent->Column->Fixed) + { + column.Id = Data->MouseEvent->Column->Id; + column.Visible = FALSE; + TreeNew_SetColumn(Data->TreeNewHandle, TN_COLUMN_FLAG_VISIBLE, &column); + PhpEnsureValidSortColumnTreeNew(Data->TreeNewHandle, Data->DefaultSortColumn, Data->DefaultSortOrder); + InvalidateRect(Data->TreeNewHandle, NULL, FALSE); + } + } + break; + case PH_TN_COLUMN_MENU_CHOOSE_COLUMNS_ID: + { + //PhShowChooseColumnsDialog(Data->TreeNewHandle, Data->TreeNewHandle, PH_CONTROL_TYPE_TREE_NEW); + PhpEnsureValidSortColumnTreeNew(Data->TreeNewHandle, Data->DefaultSortColumn, Data->DefaultSortOrder); + } + break; + default: + return FALSE; + } + + Data->ProcessedId = Data->Selection->Id; + + return TRUE; +} + +VOID PhDeleteTreeNewColumnMenu( + _In_ PPH_TN_COLUMN_MENU_DATA Data + ) +{ + if (Data->Menu) + { + PhDestroyEMenu(Data->Menu); + Data->Menu = NULL; + } +} + VOID PhInitializeTreeNewFilterSupport( _Out_ PPH_TN_FILTER_SUPPORT Support, _In_ HWND TreeNewHandle, @@ -132,18 +356,18 @@ VOID PhApplyTreeNewFilters( TreeNew_NodesStructured(Support->TreeNewHandle); } -BOOLEAN PluginsNodeHashtableCompareFunction( +BOOLEAN SymbolNodeHashtableCompareFunction( _In_ PVOID Entry1, _In_ PVOID Entry2 ); -ULONG PluginsNodeHashtableHashFunction( +ULONG SymbolNodeHashtableHashFunction( _In_ PVOID Entry ); -VOID DestroyPluginsNode( +VOID PvDestroySymbolNode( _In_ PPV_SYMBOL_NODE Node ); -VOID DeletePluginsTree( +VOID PvDeleteSymbolTree( _In_ PPDB_SYMBOL_CONTEXT Context ) { @@ -153,21 +377,21 @@ VOID DeletePluginsTree( for (ULONG i = 0; i < Context->NodeList->Count; i++) { - DestroyPluginsNode(Context->NodeList->Items[i]); + PvDestroySymbolNode(Context->NodeList->Items[i]); } PhDereferenceObject(Context->NodeHashtable); PhDereferenceObject(Context->NodeList); } -struct _PH_TN_FILTER_SUPPORT* GetPluginListFilterSupport( +struct _PH_TN_FILTER_SUPPORT* GetSymbolListFilterSupport( _In_ PPDB_SYMBOL_CONTEXT Context ) { return &Context->FilterSupport; } -BOOLEAN PluginsNodeHashtableCompareFunction( +BOOLEAN SymbolNodeHashtableCompareFunction( _In_ PVOID Entry1, _In_ PVOID Entry2 ) @@ -178,20 +402,23 @@ BOOLEAN PluginsNodeHashtableCompareFunction( return PhEqualString(windowNode1->Name, windowNode2->Name, TRUE); } -ULONG PluginsNodeHashtableHashFunction( +ULONG SymbolNodeHashtableHashFunction( _In_ PVOID Entry ) { - return PhHashStringRef(&(*(PPV_SYMBOL_NODE*)Entry)->Name->sr, TRUE); + return PhHashInt64((*(PPV_SYMBOL_NODE*)Entry)->Index); } -VOID PluginsAddTreeNode( +VOID PvSymbolAddTreeNode( _In_ PPDB_SYMBOL_CONTEXT Context, _In_ PPV_SYMBOL_NODE Entry ) { + static ULONG64 index = 0; + PhInitializeTreeNewNode(&Entry->Node); + Entry->Index = index++; memset(Entry->TextCache, 0, sizeof(PH_STRINGREF) * TREE_COLUMN_ITEM_MAXIMUM); Entry->Node.TextCache = Entry->TextCache; Entry->Node.TextCacheSize = TREE_COLUMN_ITEM_MAXIMUM; @@ -199,17 +426,13 @@ VOID PluginsAddTreeNode( PhAddEntryHashtable(Context->NodeHashtable, &Entry); PhAddItemList(Context->NodeList, Entry); - TreeNew_SetRedraw(Context->TreeNewHandle, FALSE); - TreeNew_NodesStructured(Context->TreeNewHandle); - TreeNew_SetRedraw(Context->TreeNewHandle, TRUE); - if (Context->FilterSupport.NodeList) { Entry->Node.Visible = PhApplyTreeNewFiltersToNode(&Context->FilterSupport, &Entry->Node); } } -PPV_SYMBOL_NODE FindTreeNode( +PPV_SYMBOL_NODE PvFindSymbolNode( _In_ PPDB_SYMBOL_CONTEXT Context, _In_ PPH_STRING Name ) @@ -225,25 +448,22 @@ PPV_SYMBOL_NODE FindTreeNode( return NULL; } -VOID WeRemoveWindowNode( +VOID PvRemoveSymbolNode( _In_ PPDB_SYMBOL_CONTEXT Context, _In_ PPV_SYMBOL_NODE Node ) { ULONG index = 0; - // Remove from hashtable/list and cleanup. PhRemoveEntryHashtable(Context->NodeHashtable, &Node); if ((index = PhFindItemList(Context->NodeList, Node)) != -1) - { PhRemoveItemList(Context->NodeList, index); - } - DestroyPluginsNode(Node); + PvDestroySymbolNode(Node); } -VOID DestroyPluginsNode( +VOID PvDestroySymbolNode( _In_ PPV_SYMBOL_NODE Node ) { @@ -276,7 +496,7 @@ END_SORT_FUNCTION BEGIN_SORT_FUNCTION(VA) { - sortResult = PhCompareString(node1->Name, node2->Name, FALSE); + sortResult = uintptrcmp(node1->Address, node2->Address); } END_SORT_FUNCTION @@ -286,7 +506,7 @@ BEGIN_SORT_FUNCTION(Name) } END_SORT_FUNCTION -BOOLEAN NTAPI PluginsTreeNewCallback( +BOOLEAN NTAPI PvSymbolTreeNewCallback( _In_ HWND hwnd, _In_ PH_TREENEW_MESSAGE Message, __in_opt PVOID Parameter1, @@ -374,8 +594,8 @@ BOOLEAN NTAPI PluginsTreeNewCallback( case PV_SYMBOL_TYPE_GLOBAL_VAR: PhInitializeStringRef(&getCellText->Text, L"GLOBAL_VAR"); break; - case PV_SYMBOL_TYPE_MEMBER: - PhInitializeStringRef(&getCellText->Text, L"MEMBER"); + case PV_SYMBOL_TYPE_STRUCT: + PhInitializeStringRef(&getCellText->Text, L"STRUCT"); break; case PV_SYMBOL_TYPE_STATIC_MEMBER: PhInitializeStringRef(&getCellText->Text, L"STATIC_MEMBER"); @@ -383,6 +603,9 @@ BOOLEAN NTAPI PluginsTreeNewCallback( case PV_SYMBOL_TYPE_CONSTANT: PhInitializeStringRef(&getCellText->Text, L"CONSTANT"); break; + case PV_SYMBOL_TYPE_CLASS: + PhInitializeStringRef(&getCellText->Text, L"CLASS"); + break; } } break; @@ -433,7 +656,7 @@ BOOLEAN NTAPI PluginsTreeNewCallback( return TRUE; case TreeNewHeaderRightClick: { - /*PH_TN_COLUMN_MENU_DATA data; + PH_TN_COLUMN_MENU_DATA data; data.TreeNewHandle = hwnd; data.MouseEvent = Parameter1; @@ -444,7 +667,7 @@ BOOLEAN NTAPI PluginsTreeNewCallback( data.Selection = PhShowEMenu(data.Menu, hwnd, PH_EMENU_SHOW_LEFTRIGHT, PH_ALIGN_LEFT | PH_ALIGN_TOP, data.MouseEvent->ScreenLocation.x, data.MouseEvent->ScreenLocation.y); PhHandleTreeNewColumnMenu(&data); - PhDeleteTreeNewColumnMenu(&data);*/ + PhDeleteTreeNewColumnMenu(&data); } return TRUE; } @@ -452,18 +675,18 @@ BOOLEAN NTAPI PluginsTreeNewCallback( return FALSE; } -VOID PluginsClearTree( +VOID PvSymbolClearTree( _In_ PPDB_SYMBOL_CONTEXT Context ) { for (ULONG i = 0; i < Context->NodeList->Count; i++) - DestroyPluginsNode(Context->NodeList->Items[i]); + PvDestroySymbolNode(Context->NodeList->Items[i]); PhClearHashtable(Context->NodeHashtable); PhClearList(Context->NodeList); } -PPV_SYMBOL_NODE WeGetSelectedWindowNode( +PPV_SYMBOL_NODE PvGetSelectedSymbolNode( _In_ PPDB_SYMBOL_CONTEXT Context ) { @@ -478,7 +701,7 @@ PPV_SYMBOL_NODE WeGetSelectedWindowNode( return NULL; } -VOID WeGetSelectedWindowNodes( +VOID PvGetSelectedSymbolNodes( _In_ PPDB_SYMBOL_CONTEXT Context, _Out_ PPV_SYMBOL_NODE **Windows, _Out_ PULONG NumberOfWindows @@ -500,7 +723,7 @@ VOID WeGetSelectedWindowNodes( PhDereferenceObject(list); } -VOID InitializePluginsTree( +VOID PvInitializeSymbolTree( _In_ PPDB_SYMBOL_CONTEXT Context, _In_ HWND ParentWindowHandle, _In_ HWND TreeNewHandle @@ -508,8 +731,8 @@ VOID InitializePluginsTree( { Context->NodeHashtable = PhCreateHashtable( sizeof(PPV_SYMBOL_NODE), - PluginsNodeHashtableCompareFunction, - PluginsNodeHashtableHashFunction, + SymbolNodeHashtableCompareFunction, + SymbolNodeHashtableHashFunction, 100 ); Context->NodeList = PhCreateList(100); @@ -518,19 +741,14 @@ VOID InitializePluginsTree( Context->TreeNewHandle = TreeNewHandle; PhSetControlTheme(TreeNewHandle, L"explorer"); - TreeNew_SetCallback(TreeNewHandle, PluginsTreeNewCallback, Context); + TreeNew_SetCallback(TreeNewHandle, PvSymbolTreeNewCallback, Context); PhAddTreeNewColumnEx2(TreeNewHandle, TREE_COLUMN_ITEM_TYPE, TRUE, L"Type", 80, PH_ALIGN_LEFT, TREE_COLUMN_ITEM_TYPE, 0, 0); PhAddTreeNewColumnEx2(TreeNewHandle, TREE_COLUMN_ITEM_VA, TRUE, L"VA", 80, PH_ALIGN_LEFT, TREE_COLUMN_ITEM_VA, 0, 0); PhAddTreeNewColumnEx2(TreeNewHandle, TREE_COLUMN_ITEM_NAME, TRUE, L"Symbol", 150, PH_ALIGN_LEFT, TREE_COLUMN_ITEM_NAME, 0, 0); PhAddTreeNewColumnEx2(TreeNewHandle, TREE_COLUMN_ITEM_SYMBOL, TRUE, L"Data", 150, PH_ALIGN_LEFT, TREE_COLUMN_ITEM_SYMBOL, 0, 0); - /* - PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 40, L"Symbol"); - PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_RIGHT, 80, L"VA"); - PhAddListViewColumn(lvHandle, 2, 2, 2, LVCFMT_LEFT, 250, L"Name"); - PhAddListViewColumn(lvHandle, 3, 3, 3, LVCFMT_LEFT, 40, L"Size"); - PhAddListViewColumn(lvHandle, 4, 4, 4, LVCFMT_LEFT, 80, L"Type"); - */ + PhAddTreeNewColumnEx2(TreeNewHandle, TREE_COLUMN_ITEM_SIZE, FALSE, L"Size", 40, PH_ALIGN_LEFT, TREE_COLUMN_ITEM_SIZE, 0, 0); + TreeNew_SetSort(TreeNewHandle, 0, NoSortOrder); PPH_STRING settings = PhGetStringSetting(L"PdbTreeListColumns"); @@ -575,29 +793,107 @@ BOOLEAN WordMatchStringZ( return WordMatchStringRef(Context, &text); } -BOOLEAN TreeFilterCallback( +BOOLEAN PvSymbolTreeFilterCallback( _In_ PPH_TREENEW_NODE Node, _In_opt_ PVOID Context -) + ) { PPDB_SYMBOL_CONTEXT context = Context; PPV_SYMBOL_NODE node = (PPV_SYMBOL_NODE)Node; //if (node->Address == 0) - // return TRUE; + // return TRUE; if (PhIsNullOrEmptyString(context->SearchboxText)) return TRUE; + switch (node->Type) + { + case PV_SYMBOL_TYPE_FUNCTION: + if (WordMatchStringZ(context, L"FUNCTION")) + return TRUE; + break; + case PV_SYMBOL_TYPE_SYMBOL: + if (WordMatchStringZ(context, L"SYMBOL")) + return TRUE; + break; + case PV_SYMBOL_TYPE_LOCAL_VAR: + if (WordMatchStringZ(context, L"LOCAL_VAR")) + return TRUE; + break; + case PV_SYMBOL_TYPE_STATIC_LOCAL_VAR: + if (WordMatchStringZ(context, L"STATIC_LOCAL_VAR")) + return TRUE; + break; + case PV_SYMBOL_TYPE_PARAMETER: + if (WordMatchStringZ(context, L"PARAMETER")) + return TRUE; + break; + case PV_SYMBOL_TYPE_OBJECT_PTR: + if (WordMatchStringZ(context, L"OBJECT_PTR")) + return TRUE; + break; + case PV_SYMBOL_TYPE_STATIC_VAR: + if (WordMatchStringZ(context, L"STATIC_VAR")) + return TRUE; + break; + case PV_SYMBOL_TYPE_GLOBAL_VAR: + if (WordMatchStringZ(context, L"GLOBAL_VAR")) + return TRUE; + break; + case PV_SYMBOL_TYPE_STRUCT: + if (WordMatchStringZ(context, L"MEMBER")) + return TRUE; + break; + case PV_SYMBOL_TYPE_STATIC_MEMBER: + if (WordMatchStringZ(context, L"STATIC_MEMBER")) + return TRUE; + break; + case PV_SYMBOL_TYPE_CONSTANT: + if (WordMatchStringZ(context, L"CONSTANT")) + return TRUE; + break; + } + if (!PhIsNullOrEmptyString(node->Name)) { if (WordMatchStringRef(context, &node->Name->sr)) return TRUE; } + if (!PhIsNullOrEmptyString(node->Data)) + { + if (WordMatchStringRef(context, &node->Data->sr)) + return TRUE; + } + return FALSE; } +VOID CALLBACK PvSymbolTreeUpdateCallback( + _In_ PPDB_SYMBOL_CONTEXT Context, + _In_ BOOLEAN TimerOrWaitFired + ) +{ + ULONG i; + + TreeNew_SetRedraw(Context->TreeNewHandle, FALSE); + + PhAcquireQueuedLockExclusive(&SearchResultsLock); + + for (i = SearchResultsAddIndex; i < SearchResults->Count; i++) + { + PvSymbolAddTreeNode(Context, SearchResults->Items[i]); + } + SearchResultsAddIndex = i; + + PhReleaseQueuedLockExclusive(&SearchResultsLock); + + TreeNew_NodesStructured(Context->TreeNewHandle); + TreeNew_SetRedraw(Context->TreeNewHandle, TRUE); + + ChangeTimerQueueTimer(NULL, Context->UpdateTimer, 1000, INFINITE); +} INT_PTR CALLBACK PvpSymbolsDlgProc( _In_ HWND hwndDlg, @@ -623,6 +919,8 @@ INT_PTR CALLBACK PvpSymbolsDlgProc( { case WM_INITDIALOG: { + HANDLE treeNewTimer = NULL; + context = propPageContext->Context = PhAllocate(sizeof(PDB_SYMBOL_CONTEXT)); memset(context, 0, sizeof(PDB_SYMBOL_CONTEXT)); @@ -631,17 +929,41 @@ INT_PTR CALLBACK PvpSymbolsDlgProc( context->SearchHandle = GetDlgItem(hwndDlg, IDC_SYMSEARCH); context->SearchboxText = PhReferenceEmptyString(); - InitializePluginsTree(context, hwndDlg, context->TreeNewHandle); - //PhAddTreeNewFilter(GetPluginListFilterSupport(context), TreeFilterCallback, context); + PvCreateSearchControl(context->SearchHandle, L"Search Symbols (Ctrl+K)"); + + PvInitializeSymbolTree(context, hwndDlg, context->TreeNewHandle); + PhAddTreeNewFilter(GetSymbolListFilterSupport(context), PvSymbolTreeFilterCallback, context); + + PhSetWindowStyle(GetDlgItem(hwndDlg, IDC_PROGRESS), PBS_MARQUEE, PBS_MARQUEE); + SendMessage(GetDlgItem(hwndDlg, IDC_PROGRESS), PBM_SETMARQUEE, TRUE, 75); + + SearchResults = PhCreateList(0x1000); + context->SearchThreadHandle = PhCreateThread(0, PeDumpFileSymbols, context); + + if (CreateTimerQueueTimer( + &treeNewTimer, + NULL, + PvSymbolTreeUpdateCallback, + context, + 1000, + 1000, + 0 + )) + { + context->UpdateTimer = treeNewTimer; + } - PhQueueItemWorkQueue(PhGetGlobalWorkQueue(), PeDumpFileSymbols, context); - - //SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hwndDlg, IDC_OPTIONS), TRUE); + EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); } break; case WM_DESTROY: { - DeletePluginsTree(context); + if (context->UpdateTimer) + DeleteTimerQueueTimer(NULL, context->UpdateTimer, NULL); + + NtClose(context->SearchThreadHandle); + + PvDeleteSymbolTree(context); } break; case WM_SHOWWINDOW: @@ -652,7 +974,7 @@ INT_PTR CALLBACK PvpSymbolsDlgProc( dialogItem = PvAddPropPageLayoutItem(hwndDlg, hwndDlg, PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL); - PvAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_SYMSEARCH), + PvAddPropPageLayoutItem(hwndDlg, context->SearchHandle, dialogItem, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); PvAddPropPageLayoutItem(hwndDlg, context->TreeNewHandle, dialogItem, PH_ANCHOR_ALL); @@ -662,23 +984,59 @@ INT_PTR CALLBACK PvpSymbolsDlgProc( } } break; - case WM_NOTIFY: + case WM_COMMAND: { - LPNMHDR header = (LPNMHDR)lParam; - - switch (header->code) + switch (GET_WM_COMMAND_CMD(wParam, lParam)) { - case NM_DBLCLK: + case EN_CHANGE: { - if (header->hwndFrom == context->TreeNewHandle) + PPH_STRING newSearchboxText; + + newSearchboxText = PH_AUTO(PhGetWindowText(context->SearchHandle)); + + if (!PhEqualString(context->SearchboxText, newSearchboxText, FALSE)) { + PhSwapReference(&context->SearchboxText, newSearchboxText); + + if (!PhIsNullOrEmptyString(context->SearchboxText)) + { + //PhExpandAllProcessNodes(TRUE); + //PhDeselectAllProcessNodes(); + } + PhApplyTreeNewFilters(GetSymbolListFilterSupport(context)); } } break; } } break; + case WM_PV_SEARCH_FINISHED: + { + // Add any un-added items. + //SendMessage(hwndDlg, WM_PV_SEARCH_UPDATE, 0, 0); + + //NtWaitForSingleObject(context->SearchThreadHandle, FALSE, NULL); + //SearchStop = FALSE; + } + break; + case WM_NOTIFY: + { + LPNMHDR header = (LPNMHDR)lParam; + LPPSHNOTIFY pageNotify = (LPPSHNOTIFY)header; + + switch (pageNotify->hdr.code) + { + case PSN_SETACTIVE: + PostMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(GetParent(hwndDlg), IDCANCEL), TRUE); // HACK + break; + case PSN_QUERYINITIALFOCUS: + SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, (LPARAM)GetDlgItem(GetParent(hwndDlg), IDCANCEL)); + return TRUE; + } + } + break; + } return FALSE; diff --git a/tools/peview/peview.rc b/tools/peview/peview.rc index 7ca0f9265d2d..4a1db839071e 100644 --- a/tools/peview/peview.rc +++ b/tools/peview/peview.rc @@ -63,26 +63,26 @@ BEGIN IDD_PEIMPORTS, DIALOG BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 293 - TOPMARGIN, 7 - BOTTOMMARGIN, 273 + LEFTMARGIN, 3 + RIGHTMARGIN, 297 + TOPMARGIN, 3 + BOTTOMMARGIN, 277 END IDD_PEEXPORTS, DIALOG BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 293 - TOPMARGIN, 7 - BOTTOMMARGIN, 273 + LEFTMARGIN, 3 + RIGHTMARGIN, 297 + TOPMARGIN, 3 + BOTTOMMARGIN, 277 END IDD_LIBEXPORTS, DIALOG BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 293 - TOPMARGIN, 7 - BOTTOMMARGIN, 273 + LEFTMARGIN, 3 + RIGHTMARGIN, 297 + TOPMARGIN, 3 + BOTTOMMARGIN, 277 END IDD_PECLR, DIALOG @@ -95,18 +95,18 @@ BEGIN IDD_PELOADCONFIG, DIALOG BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 293 - TOPMARGIN, 7 - BOTTOMMARGIN, 273 + LEFTMARGIN, 3 + RIGHTMARGIN, 297 + TOPMARGIN, 3 + BOTTOMMARGIN, 277 END IDD_PECFG, DIALOG BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 292 - TOPMARGIN, 7 - BOTTOMMARGIN, 273 + LEFTMARGIN, 3 + RIGHTMARGIN, 296 + TOPMARGIN, 3 + BOTTOMMARGIN, 277 END IDD_PESYMBOLS, DIALOG @@ -162,7 +162,7 @@ STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSM CAPTION "Imports" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN - CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,7,286,266 + CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,3,3,294,274 END IDD_PEEXPORTS DIALOGEX 0, 0, 300, 280 @@ -170,7 +170,7 @@ STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSM CAPTION "Exports" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN - CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,7,286,266 + CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,3,3,294,274 END IDD_LIBEXPORTS DIALOGEX 0, 0, 300, 280 @@ -178,7 +178,7 @@ STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSM CAPTION "Exports" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN - CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,6,6,287,267 + CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,3,3,294,274 END IDD_PECLR DIALOGEX 0, 0, 300, 280 @@ -202,7 +202,7 @@ STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSM CAPTION "Load config" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN - CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,7,286,266 + CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,3,3,294,274 END IDD_PECFG DIALOGEX 0, 0, 299, 280 @@ -210,7 +210,7 @@ STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSM CAPTION "CFG" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN - CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,7,286,266 + CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,3,3,293,274 END IDD_PESYMBOLS DIALOGEX 0, 0, 301, 280 @@ -218,8 +218,8 @@ STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSM CAPTION "Symbols" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN - CONTROL "",IDC_SYMBOLTREE,"PhTreeNew",WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP | 0xa,3,20,295,257,WS_EX_CLIENTEDGE - EDITTEXT IDC_SYMSEARCH,166,3,132,14,ES_AUTOHSCROLL + CONTROL "",IDC_SYMBOLTREE,"PhTreeNew",WS_CLIPSIBLINGS | WS_CLIPCHILDREN | 0x2,3,21,295,256,WS_EX_CLIENTEDGE + EDITTEXT IDC_SYMSEARCH,157,3,141,14,ES_AUTOHSCROLL END @@ -233,6 +233,51 @@ BEGIN 0 END +IDD_PELOADCONFIG AFX_DIALOG_LAYOUT +BEGIN + 0 +END + +IDD_PEIMPORTS AFX_DIALOG_LAYOUT +BEGIN + 0 +END + +IDD_PEEXPORTS AFX_DIALOG_LAYOUT +BEGIN + 0 +END + +IDD_PECFG AFX_DIALOG_LAYOUT +BEGIN + 0 +END + +IDD_LIBEXPORTS AFX_DIALOG_LAYOUT +BEGIN + 0 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Bitmap +// + +IDB_SEARCH_ACTIVE_BMP BITMAP "resources\\active_search.bmp" + +IDB_SEARCH_INACTIVE_BMP BITMAP "resources\\inactive_search.bmp" + + +///////////////////////////////////////////////////////////////////////////// +// +// PNG +// + +IDB_SEARCH_ACTIVE PNG "resources\\active_search.png" + +IDB_SEARCH_INACTIVE PNG "resources\\inactive_search.png" + #endif // English (Australia) resources ///////////////////////////////////////////////////////////////////////////// diff --git a/tools/peview/peview.vcxproj b/tools/peview/peview.vcxproj index c3d2df1f85af..1ce6cc5d5354 100644 --- a/tools/peview/peview.vcxproj +++ b/tools/peview/peview.vcxproj @@ -96,7 +96,7 @@ true - noarg.obj;noenv.obj;phlib.lib;ntdll.lib;uxtheme.lib;%(AdditionalDependencies) + noarg.obj;noenv.obj;phlib.lib;ntdll.lib;uxtheme.lib;windowscodecs.lib;%(AdditionalDependencies) ..\..\phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) @@ -121,7 +121,7 @@ true - noarg.obj;noenv.obj;phlib.lib;ntdll.lib;uxtheme.lib;%(AdditionalDependencies) + noarg.obj;noenv.obj;phlib.lib;ntdll.lib;uxtheme.lib;windowscodecs.lib;%(AdditionalDependencies) ..\..\phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) @@ -149,7 +149,7 @@ true - noarg.obj;noenv.obj;phlib.lib;ntdll.lib;uxtheme.lib;%(AdditionalDependencies) + noarg.obj;noenv.obj;phlib.lib;ntdll.lib;uxtheme.lib;windowscodecs.lib;%(AdditionalDependencies) ..\..\phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) @@ -179,7 +179,7 @@ true - noarg.obj;noenv.obj;phlib.lib;ntdll.lib;uxtheme.lib;%(AdditionalDependencies) + noarg.obj;noenv.obj;phlib.lib;ntdll.lib;uxtheme.lib;windowscodecs.lib;%(AdditionalDependencies) ..\..\phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) @@ -206,6 +206,7 @@ + @@ -228,6 +229,13 @@ + + + + + + + diff --git a/tools/peview/peview.vcxproj.filters b/tools/peview/peview.vcxproj.filters index 7395ed945c8f..95f381deb897 100644 --- a/tools/peview/peview.vcxproj.filters +++ b/tools/peview/peview.vcxproj.filters @@ -57,6 +57,9 @@ Source Files + + Source Files + @@ -88,4 +91,21 @@ Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + \ No newline at end of file diff --git a/tools/peview/resource.h b/tools/peview/resource.h index 56994a3e0af7..010f9d43fd37 100644 --- a/tools/peview/resource.h +++ b/tools/peview/resource.h @@ -2,19 +2,19 @@ // Microsoft Visual C++ generated include file. // Used by peview.rc // -#define IDD_PEGENERAL 102 -#define IDD_PEIMPORTS 103 -#define IDD_PEEXPORTS 104 -#define IDD_LIBEXPORTS 105 -#define IDD_PECLR 106 -#define IDD_PELOADCONFIG 107 -#define IDD_PECFG 108 -#define IDD_PESYMBOLS 109 -#define IDC_SYMBOLTREE 110 -#define IDB_SEARCH_ACTIVE 111 -#define IDB_SEARCH_INACTIVE 112 -#define IDB_SEARCH_ACTIVE_BMP 113 -#define IDB_SEARCH_INACTIVE_BMP 114 +#define IDD_PEGENERAL 101 +#define IDD_PEIMPORTS 102 +#define IDD_PEEXPORTS 103 +#define IDD_LIBEXPORTS 104 +#define IDD_PECLR 105 +#define IDD_PELOADCONFIG 106 +#define IDD_PECFG 107 +#define IDD_PESYMBOLS 108 +#define IDB_SEARCH_ACTIVE 110 +#define IDB_SEARCH_INACTIVE 111 +#define IDB_SEARCH_ACTIVE_BMP 112 +#define IDB_SEARCH_INACTIVE_BMP 113 +#define IDC_SYMBOLTREE 119 #define IDC_TARGETMACHINE 1003 #define IDC_CHECKSUM 1004 #define IDC_SUBSYSTEM 1005 @@ -33,16 +33,19 @@ #define IDC_IMAGEBASE 1015 #define IDC_ENTRYPOINT 1016 #define IDC_SYMSEARCH 1017 -#define IDC_NAME 1044 -#define IDC_COMPANYNAME_LINK 1279 +#define IDC_NAME 1019 +#define IDC_COMPANYNAME_LINK 1020 +#define IDC_BUTTON1 1021 +#define IDC_STOP 1021 +#define IDC_PROGRESS 1022 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 116 +#define _APS_NEXT_RESOURCE_VALUE 119 #define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1019 -#define _APS_NEXT_SYMED_VALUE 116 +#define _APS_NEXT_CONTROL_VALUE 1023 +#define _APS_NEXT_SYMED_VALUE 115 #endif #endif diff --git a/tools/peview/resources/ProcessHacker.ico b/tools/peview/resources/ProcessHacker.ico new file mode 100644 index 0000000000000000000000000000000000000000..5225637d781f268469054fe92a7d4980ecb7fff8 GIT binary patch literal 97449 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 AX8-^I literal 0 HcmV?d00001 diff --git a/tools/peview/resources/active_search.bmp b/tools/peview/resources/active_search.bmp new file mode 100644 index 0000000000000000000000000000000000000000..61b13de9a1152694de72dd81c01c47282773298e GIT binary patch literal 1494 zcmZ?ry~fG_24+A~1Bk_eSOka}8650^YlUPk4#vGuUW6N6R zWNHFQJcaSx|X%2hHw&(QFzR`wykGxlOd1cH4UFR%aZTy0vQ4UK=!p| e$uJ%|jmI2xrFi+H=HLw;0_g|8USwG+hBE*$K{!VM literal 0 HcmV?d00001 diff --git a/tools/peview/resources/active_search.png b/tools/peview/resources/active_search.png new file mode 100644 index 0000000000000000000000000000000000000000..1cf29576b0b50ed5ee88c1ea8565fe2e9adb9b69 GIT binary patch literal 569 zcmV-90>=G`P)sM}kty8!R#X_B;6=p#3k05!yiVY9d zlP4*H^pRy55Oc`+@ds70n9+mE9;(NrCYe{xn9wV|9VBsU+d(|PXf{(L44hUrH>@-V-11oc);or!AQP^ zGA=1rIynoT>*g-{55qdy^B+mtM4?zjp=AgQmBSj+v@_=Xhhe3lstAxc%pz)8#;6wA zW~r4l^}SZ|wEr*+mw^5uN{4!`dE+8h9B2g+;~9Laf!o+nq2=@QC~4{5 zzNMIgKr``}1C-rcX?bp5HnP>n`l5h>$RZFnesj((%HG>#cy3wt`|HP^U*3CeUNVq- zZ5@_$h2I>YUDuXnAL}xNqidV67y?vA&>V=f-`}3|{{B)38!JhqIau`~3l2ha0LuUq A!~g&Q literal 0 HcmV?d00001 diff --git a/tools/peview/resources/inactive_search.png b/tools/peview/resources/inactive_search.png new file mode 100644 index 0000000000000000000000000000000000000000..29eaa91305b3de1ce3854f19d86780a552bff734 GIT binary patch literal 755 zcmV;^k2Oj%`vu0L~h9Ndt{Z?B0N*TK5C5_$jUJj2-f3Mf; z=Q4%>h(lx3%*O9D(}M#pG|-AZmB~Y^5Kn3OGXm_qV;y8!p2Ycr{A~&Vh&eaG$uG|C z6Av0_h0HQDGp8TB=MgF`eoUj*zR2Kp69(V&kV6d|aG`-#)NJOFTW(>}f=4uY!z&#( zy!b0FYT$qi4YZzi z!U4p{@mX8WMy*7RX54w@=Gkk?VfutyFI>F1**tDmn1AarCNdTRhz$lqT^w#vqiIjf z++4ek*{XCNwS|Dwx6J)v#I?d`27J0X0K~|N-h&;@?7SR0m@dn1EiEQs_o;`$Fyb>) z{!a}>%}S)Dt6pr_b2g-Y=aI^?%}2xWn%Jm@kdeTRQJW3s_yq*>%`QLV|Bc0r1Qr_O lJMbXX`SgwQ{nsmReE`jH|7l`4W6l5o002ovPDHLkV1naFZkYf8 literal 0 HcmV?d00001 diff --git a/tools/peview/searchbox.c b/tools/peview/searchbox.c new file mode 100644 index 000000000000..17d89f752726 --- /dev/null +++ b/tools/peview/searchbox.c @@ -0,0 +1,728 @@ +/* + * Process Hacker - + * Searchbox control + * + * Copyright (C) 2012-2017 dmex + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + * + */ + +#include +#include +#define CINTERFACE +#define COBJMACROS +#include +#include +#include +#include + +typedef struct _EDIT_CONTEXT +{ + union + { + ULONG Flags; + struct + { + ULONG Hot : 1; + ULONG Pushed : 1; + ULONG Spare : 30; + }; + }; + + LONG CXWidth; + INT CXBorder; + INT ImageWidth; + INT ImageHeight; + HWND WindowHandle; + HFONT WindowFont; + HICON BitmapActive; + HICON BitmapInactive; + HBRUSH BrushNormal; + HBRUSH BrushPushed; + HBRUSH BrushHot; +} EDIT_CONTEXT, *PEDIT_CONTEXT; + +HICON PhpSearchBitmapToIcon( + _In_ HBITMAP BitmapHandle, + _In_ INT Width, + _In_ INT Height + ); + +VOID PhpSearchFreeTheme( + _Inout_ PEDIT_CONTEXT Context + ) +{ + if (Context->BrushNormal) + DeleteObject(Context->BrushNormal); + + if (Context->BrushHot) + DeleteObject(Context->BrushHot); + + if (Context->BrushPushed) + DeleteObject(Context->BrushPushed); +} + +VOID PhpSearchInitializeFont( + _Inout_ PEDIT_CONTEXT Context + ) +{ + LOGFONT logFont; + + if (Context->WindowFont) + DeleteObject(Context->WindowFont); + + if (!SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(LOGFONT), &logFont, 0)) + return; + + Context->WindowFont = CreateFont( + -PhMultiplyDivideSigned(10, PhGlobalDpi, 72), + 0, + 0, + 0, + FW_MEDIUM, + FALSE, + FALSE, + FALSE, + ANSI_CHARSET, + OUT_DEFAULT_PRECIS, + CLIP_DEFAULT_PRECIS, + CLEARTYPE_QUALITY | ANTIALIASED_QUALITY, + DEFAULT_PITCH, + logFont.lfFaceName + ); + + SendMessage(Context->WindowHandle, WM_SETFONT, (WPARAM)Context->WindowFont, TRUE); +} + +VOID PhpSearchInitializeTheme( + _Inout_ PEDIT_CONTEXT Context + ) +{ + Context->CXWidth = 20;// PH_SCALE_DPI(20); + Context->BrushNormal = GetSysColorBrush(COLOR_WINDOW); + Context->BrushHot = CreateSolidBrush(RGB(205, 232, 255)); + Context->BrushPushed = CreateSolidBrush(RGB(153, 209, 255)); + + if (IsThemeActive()) + { + HTHEME themeDataHandle; + + if (themeDataHandle = OpenThemeData(Context->WindowHandle, VSCLASS_EDIT)) + { + //IsThemePartDefined_I(themeDataHandle, EP_EDITBORDER_NOSCROLL, EPSHV_NORMAL); + + if (!SUCCEEDED(GetThemeInt( + themeDataHandle, + EP_EDITBORDER_NOSCROLL, + EPSHV_NORMAL, + TMT_BORDERSIZE, + &Context->CXBorder + ))) + { + Context->CXBorder = GetSystemMetrics(SM_CXBORDER) * 2; + } + + CloseThemeData(themeDataHandle); + } + else + { + Context->CXBorder = GetSystemMetrics(SM_CXBORDER) * 2; + } + } + else + { + Context->CXBorder = GetSystemMetrics(SM_CXBORDER) * 2; + } +} + +HBITMAP PhLoadPngImageFromResource( + _In_ PVOID DllBase, + _In_ UINT Width, + _In_ UINT Height, + _In_ PCWSTR Name, + _In_ BOOLEAN RGBAImage + ) +{ + BOOLEAN success = FALSE; + UINT frameCount = 0; + ULONG resourceLength = 0; + HGLOBAL resourceHandle = NULL; + HRSRC resourceHandleSource = NULL; + WICInProcPointer resourceBuffer = NULL; + HDC screenHdc = NULL; + HDC bufferDc = NULL; + BITMAPINFO bitmapInfo = { 0 }; + HBITMAP bitmapHandle = NULL; + PVOID bitmapBuffer = NULL; + IWICStream* wicStream = NULL; + IWICBitmapSource* wicBitmapSource = NULL; + IWICBitmapDecoder* wicDecoder = NULL; + IWICBitmapFrameDecode* wicFrame = NULL; + IWICImagingFactory* wicFactory = NULL; + IWICBitmapScaler* wicScaler = NULL; + WICPixelFormatGUID pixelFormat; + WICRect rect = { 0, 0, Width, Height }; + + // Create the ImagingFactory + if (FAILED(CoCreateInstance(&CLSID_WICImagingFactory1, NULL, CLSCTX_INPROC_SERVER, &IID_IWICImagingFactory, &wicFactory))) + goto CleanupExit; + + // Find the resource + if ((resourceHandleSource = FindResource(DllBase, Name, L"PNG")) == NULL) + goto CleanupExit; + + // Get the resource length + resourceLength = SizeofResource(DllBase, resourceHandleSource); + + // Load the resource + if ((resourceHandle = LoadResource(DllBase, resourceHandleSource)) == NULL) + goto CleanupExit; + + if ((resourceBuffer = (WICInProcPointer)LockResource(resourceHandle)) == NULL) + goto CleanupExit; + + // Create the Stream + if (FAILED(IWICImagingFactory_CreateStream(wicFactory, &wicStream))) + goto CleanupExit; + + // Initialize the Stream from Memory + if (FAILED(IWICStream_InitializeFromMemory(wicStream, resourceBuffer, resourceLength))) + goto CleanupExit; + + if (FAILED(IWICImagingFactory_CreateDecoder(wicFactory, &GUID_ContainerFormatPng, NULL, &wicDecoder))) + goto CleanupExit; + + if (FAILED(IWICBitmapDecoder_Initialize(wicDecoder, (IStream*)wicStream, WICDecodeMetadataCacheOnLoad))) + goto CleanupExit; + + // Get the Frame count + if (FAILED(IWICBitmapDecoder_GetFrameCount(wicDecoder, &frameCount)) || frameCount < 1) + goto CleanupExit; + + // Get the Frame + if (FAILED(IWICBitmapDecoder_GetFrame(wicDecoder, 0, &wicFrame))) + goto CleanupExit; + + // Get the WicFrame image format + if (FAILED(IWICBitmapFrameDecode_GetPixelFormat(wicFrame, &pixelFormat))) + goto CleanupExit; + + // Check if the image format is supported: + if (IsEqualGUID(&pixelFormat, RGBAImage ? &GUID_WICPixelFormat32bppPRGBA : &GUID_WICPixelFormat32bppPBGRA)) + { + wicBitmapSource = (IWICBitmapSource*)wicFrame; + } + else + { + IWICFormatConverter* wicFormatConverter = NULL; + + if (FAILED(IWICImagingFactory_CreateFormatConverter(wicFactory, &wicFormatConverter))) + goto CleanupExit; + + if (FAILED(IWICFormatConverter_Initialize( + wicFormatConverter, + (IWICBitmapSource*)wicFrame, + RGBAImage ? &GUID_WICPixelFormat32bppPRGBA : &GUID_WICPixelFormat32bppPBGRA, + WICBitmapDitherTypeNone, + NULL, + 0.0, + WICBitmapPaletteTypeCustom + ))) + { + IWICFormatConverter_Release(wicFormatConverter); + goto CleanupExit; + } + + // Convert the image to the correct format: + IWICFormatConverter_QueryInterface(wicFormatConverter, &IID_IWICBitmapSource, &wicBitmapSource); + + // Cleanup the converter. + IWICFormatConverter_Release(wicFormatConverter); + + // Dispose the old frame now that the converted frame is in wicBitmapSource. + IWICBitmapFrameDecode_Release(wicFrame); + } + + bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bitmapInfo.bmiHeader.biWidth = rect.Width; + bitmapInfo.bmiHeader.biHeight = -((LONG)rect.Height); + bitmapInfo.bmiHeader.biPlanes = 1; + bitmapInfo.bmiHeader.biBitCount = 32; + bitmapInfo.bmiHeader.biCompression = BI_RGB; + + screenHdc = CreateIC(L"DISPLAY", NULL, NULL, NULL); + bufferDc = CreateCompatibleDC(screenHdc); + bitmapHandle = CreateDIBSection(screenHdc, &bitmapInfo, DIB_RGB_COLORS, &bitmapBuffer, NULL, 0); + + // Check if it's the same rect as the requested size. + //if (width != rect.Width || height != rect.Height) + if (FAILED(IWICImagingFactory_CreateBitmapScaler(wicFactory, &wicScaler))) + goto CleanupExit; + if (FAILED(IWICBitmapScaler_Initialize(wicScaler, wicBitmapSource, rect.Width, rect.Height, WICBitmapInterpolationModeFant))) + goto CleanupExit; + if (FAILED(IWICBitmapScaler_CopyPixels(wicScaler, &rect, rect.Width * 4, rect.Width * rect.Height * 4, (PBYTE)bitmapBuffer))) + goto CleanupExit; + + success = TRUE; + +CleanupExit: + + if (wicScaler) + IWICBitmapScaler_Release(wicScaler); + + if (bufferDc) + DeleteDC(bufferDc); + + if (screenHdc) + DeleteDC(screenHdc); + + if (wicBitmapSource) + IWICBitmapSource_Release(wicBitmapSource); + + if (wicStream) + IWICStream_Release(wicStream); + + if (wicDecoder) + IWICBitmapDecoder_Release(wicDecoder); + + if (wicFactory) + IWICImagingFactory_Release(wicFactory); + + if (resourceHandle) + FreeResource(resourceHandle); + + if (success) + { + return bitmapHandle; + } + + DeleteObject(bitmapHandle); + return NULL; +} + +VOID PhpSearchInitializeImages( + _Inout_ PEDIT_CONTEXT Context + ) +{ + HBITMAP bitmap; + + Context->ImageWidth = GetSystemMetrics(SM_CXSMICON) + 4; + Context->ImageHeight = GetSystemMetrics(SM_CYSMICON) + 4; + + if (bitmap = PhLoadPngImageFromResource(PhLibImageBase, Context->ImageWidth, Context->ImageHeight, MAKEINTRESOURCE(IDB_SEARCH_ACTIVE), TRUE)) + { + Context->BitmapActive = PhpSearchBitmapToIcon(bitmap, Context->ImageWidth, Context->ImageHeight); + DeleteObject(bitmap); + } + else if (bitmap = LoadImage(PhLibImageBase, MAKEINTRESOURCE(IDB_SEARCH_ACTIVE_BMP), IMAGE_BITMAP, 0, 0, 0)) + { + Context->BitmapActive = PhpSearchBitmapToIcon(bitmap, Context->ImageWidth, Context->ImageHeight); + DeleteObject(bitmap); + } + + if (bitmap = PhLoadPngImageFromResource(PhLibImageBase, Context->ImageWidth, Context->ImageHeight, MAKEINTRESOURCE(IDB_SEARCH_INACTIVE), TRUE)) + { + Context->BitmapInactive = PhpSearchBitmapToIcon(bitmap, Context->ImageWidth, Context->ImageHeight); + DeleteObject(bitmap); + } + else if (bitmap = LoadImage(PhLibImageBase, MAKEINTRESOURCE(IDB_SEARCH_INACTIVE_BMP), IMAGE_BITMAP, 0, 0, 0)) + { + Context->BitmapInactive = PhpSearchBitmapToIcon(bitmap, Context->ImageWidth, Context->ImageHeight); + DeleteObject(bitmap); + } +} + +VOID PhpSearchGetButtonRect( + _Inout_ PEDIT_CONTEXT Context, + _Inout_ PRECT ButtonRect + ) +{ + ButtonRect->left = (ButtonRect->right - Context->CXWidth) - Context->CXBorder - 1; // offset left border by 1 + ButtonRect->bottom -= Context->CXBorder; + ButtonRect->right -= Context->CXBorder; + ButtonRect->top += Context->CXBorder; +} + +VOID PhpSearchDrawButton( + _Inout_ PEDIT_CONTEXT Context, + _In_ RECT ButtonRect + ) +{ + HDC hdc; + HDC bufferDc; + HBITMAP bufferBitmap; + HBITMAP oldBufferBitmap; + RECT bufferRect = + { + 0, 0, + ButtonRect.right - ButtonRect.left, + ButtonRect.bottom - ButtonRect.top + }; + + if (!(hdc = GetWindowDC(Context->WindowHandle))) + return; + + bufferDc = CreateCompatibleDC(hdc); + bufferBitmap = CreateCompatibleBitmap(hdc, bufferRect.right, bufferRect.bottom); + oldBufferBitmap = SelectObject(bufferDc, bufferBitmap); + + if (Context->Pushed) + { + FillRect(bufferDc, &bufferRect, Context->BrushPushed); + //FrameRect(bufferDc, &bufferRect, CreateSolidBrush(RGB(0xff, 0, 0))); + } + else if (Context->Hot) + { + FillRect(bufferDc, &bufferRect, Context->BrushHot); + //FrameRect(bufferDc, &bufferRect, CreateSolidBrush(RGB(38, 160, 218))); + } + else + { + FillRect(bufferDc, &bufferRect, Context->BrushNormal); + } + + if (Edit_GetTextLength(Context->WindowHandle) > 0) + { + DrawIconEx( + bufferDc, + bufferRect.left + 1, // offset + bufferRect.top, + Context->BitmapActive, + Context->ImageWidth, + Context->ImageHeight, + 0, + NULL, + DI_NORMAL + ); + } + else + { + DrawIconEx( + bufferDc, + bufferRect.left + 2, // offset + bufferRect.top + 1, // offset + Context->BitmapInactive, + Context->ImageWidth, + Context->ImageHeight, + 0, + NULL, + DI_NORMAL + ); + } + + BitBlt(hdc, ButtonRect.left, ButtonRect.top, ButtonRect.right, ButtonRect.bottom, bufferDc, 0, 0, SRCCOPY); + SelectObject(bufferDc, oldBufferBitmap); + DeleteObject(bufferBitmap); + DeleteDC(bufferDc); + + ReleaseDC(Context->WindowHandle, hdc); +} + +LRESULT CALLBACK PhpSearchWndSubclassProc( + _In_ HWND hWnd, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam, + _In_ UINT_PTR uIdSubclass, + _In_ ULONG_PTR dwRefData + ) +{ + PEDIT_CONTEXT context; + + context = (PEDIT_CONTEXT)GetProp(hWnd, L"SearchBoxContext"); + + switch (uMsg) + { + case WM_NCDESTROY: + { + PhpSearchFreeTheme(context); + + if (context->WindowFont) + DeleteObject(context->WindowFont); + + RemoveWindowSubclass(hWnd, PhpSearchWndSubclassProc, uIdSubclass); + RemoveProp(hWnd, L"SearchBoxContext"); + PhFree(context); + } + break; + case WM_ERASEBKGND: + return 1; + case WM_NCCALCSIZE: + { + LPNCCALCSIZE_PARAMS ncCalcSize = (NCCALCSIZE_PARAMS*)lParam; + + // Let Windows handle the non-client defaults. + DefSubclassProc(hWnd, uMsg, wParam, lParam); + + // Deflate the client area to accommodate the custom button. + ncCalcSize->rgrc[0].right -= context->CXWidth; + } + return 0; + case WM_NCPAINT: + { + RECT windowRect; + + // Let Windows handle the non-client defaults. + DefSubclassProc(hWnd, uMsg, wParam, lParam); + + // Get the screen coordinates of the window. + GetWindowRect(hWnd, &windowRect); + + // Adjust the coordinates (start from 0,0). + OffsetRect(&windowRect, -windowRect.left, -windowRect.top); + + // Get the position of the inserted button. + PhpSearchGetButtonRect(context, &windowRect); + + // Draw the button. + PhpSearchDrawButton(context, windowRect); + } + return 0; + case WM_NCHITTEST: + { + POINT windowPoint; + RECT windowRect; + + // Get the screen coordinates of the mouse. + if (!GetCursorPos(&windowPoint)) + break; + + // Get the screen coordinates of the window. + GetWindowRect(hWnd, &windowRect); + + // Get the position of the inserted button. + PhpSearchGetButtonRect(context, &windowRect); + + // Check that the mouse is within the inserted button. + if (PtInRect(&windowRect, windowPoint)) + { + return HTBORDER; + } + } + break; + case WM_NCLBUTTONDOWN: + { + POINT windowPoint; + RECT windowRect; + + // Get the screen coordinates of the mouse. + if (!GetCursorPos(&windowPoint)) + break; + + // Get the screen coordinates of the window. + GetWindowRect(hWnd, &windowRect); + + // Get the position of the inserted button. + PhpSearchGetButtonRect(context, &windowRect); + + // Check that the mouse is within the inserted button. + if (PtInRect(&windowRect, windowPoint)) + { + context->Pushed = TRUE; + + SetCapture(hWnd); + + RedrawWindow(hWnd, NULL, NULL, RDW_FRAME | RDW_INVALIDATE); + } + } + break; + case WM_LBUTTONUP: + { + POINT windowPoint; + RECT windowRect; + + // Get the screen coordinates of the mouse. + if (!GetCursorPos(&windowPoint)) + break; + + // Get the screen coordinates of the window. + GetWindowRect(hWnd, &windowRect); + + // Get the position of the inserted button. + PhpSearchGetButtonRect(context, &windowRect); + + // Check that the mouse is within the inserted button. + if (PtInRect(&windowRect, windowPoint)) + { + // Forward click notification. + //SendMessage(GetParent(context->WindowHandle), WM_COMMAND, MAKEWPARAM(context->CommandID, BN_CLICKED), 0); + + SetFocus(hWnd); + Static_SetText(hWnd, L""); + } + + if (GetCapture() == hWnd) + { + context->Pushed = FALSE; + ReleaseCapture(); + } + + RedrawWindow(hWnd, NULL, NULL, RDW_FRAME | RDW_INVALIDATE); + } + break; + case WM_CUT: + case WM_CLEAR: + case WM_PASTE: + case WM_UNDO: + case WM_KEYUP: + case WM_SETTEXT: + case WM_KILLFOCUS: + RedrawWindow(hWnd, NULL, NULL, RDW_FRAME | RDW_INVALIDATE); + break; + case WM_SETTINGCHANGE: + case WM_SYSCOLORCHANGE: + case WM_THEMECHANGED: + { + PhpSearchFreeTheme(context); + PhpSearchInitializeTheme(context); + PhpSearchInitializeFont(context); + + // Reset the client area margins. + SendMessage(hWnd, EM_SETMARGINS, EC_LEFTMARGIN, MAKELPARAM(0, 0)); + + // Refresh the non-client area. + SetWindowPos(hWnd, NULL, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED); + + // Force the edit control to update its non-client area. + RedrawWindow(hWnd, NULL, NULL, RDW_FRAME | RDW_INVALIDATE); + } + break; + case WM_NCMOUSEMOVE: + { + POINT windowPoint; + RECT windowRect; + + // Get the screen coordinates of the mouse. + if (!GetCursorPos(&windowPoint)) + break; + + // Get the screen coordinates of the window. + GetWindowRect(hWnd, &windowRect); + + // Get the position of the inserted button. + PhpSearchGetButtonRect(context, &windowRect); + + // Check that the mouse is within the inserted button. + if (PtInRect(&windowRect, windowPoint) && !context->Hot) + { + TRACKMOUSEEVENT trackMouseEvent; + + trackMouseEvent.cbSize = sizeof(TRACKMOUSEEVENT); + trackMouseEvent.dwFlags = TME_LEAVE | TME_NONCLIENT; + trackMouseEvent.hwndTrack = hWnd; + trackMouseEvent.dwHoverTime = 0; + + context->Hot = TRUE; + + RedrawWindow(hWnd, NULL, NULL, RDW_FRAME | RDW_INVALIDATE); + + TrackMouseEvent(&trackMouseEvent); + } + } + break; + case WM_NCMOUSELEAVE: + { + if (context->Hot) + { + context->Hot = FALSE; + RedrawWindow(hWnd, NULL, NULL, RDW_FRAME | RDW_INVALIDATE); + } + } + break; + case WM_MOUSEMOVE: + { + if ((wParam & MK_LBUTTON) && GetCapture() == hWnd) + { + POINT windowPoint; + RECT windowRect; + + // Get the screen coordinates of the mouse. + if (!GetCursorPos(&windowPoint)) + break; + + // Get the screen coordinates of the window. + GetWindowRect(hWnd, &windowRect); + + // Get the position of the inserted button. + PhpSearchGetButtonRect(context, &windowRect); + + // Check that the mouse is within the inserted button. + context->Pushed = PtInRect(&windowRect, windowPoint); + + RedrawWindow(hWnd, NULL, NULL, RDW_FRAME | RDW_INVALIDATE); + } + } + break; + } + + return DefSubclassProc(hWnd, uMsg, wParam, lParam); +} + +HICON PhpSearchBitmapToIcon( + _In_ HBITMAP BitmapHandle, + _In_ INT Width, + _In_ INT Height + ) +{ + HICON icon; + HDC screenDc; + HBITMAP screenBitmap; + ICONINFO iconInfo = { 0 }; + + screenDc = CreateIC(L"DISPLAY", NULL, NULL, NULL); + screenBitmap = CreateCompatibleBitmap(screenDc, Width, Height); + + iconInfo.fIcon = TRUE; + iconInfo.hbmColor = BitmapHandle; + iconInfo.hbmMask = screenBitmap; + + icon = CreateIconIndirect(&iconInfo); + + DeleteObject(screenBitmap); + DeleteDC(screenDc); + + return icon; +} + +VOID PvCreateSearchControl( + _In_ HWND WindowHandle, + _In_opt_ PWSTR BannerText + ) +{ + PEDIT_CONTEXT context; + + context = (PEDIT_CONTEXT)PhAllocate(sizeof(EDIT_CONTEXT)); + memset(context, 0, sizeof(EDIT_CONTEXT)); + + context->WindowHandle = WindowHandle; + + //PhpSearchInitializeTheme(context); + PhpSearchInitializeImages(context); + + // Set initial text + if (BannerText) + Edit_SetCueBannerText(context->WindowHandle, BannerText); + + // Set our window context data. + SetProp(context->WindowHandle, L"SearchBoxContext", (HANDLE)context); + + // Subclass the Edit control window procedure. + SetWindowSubclass(context->WindowHandle, PhpSearchWndSubclassProc, 0, (ULONG_PTR)context); + + // Initialize the theme parameters. + SendMessage(context->WindowHandle, WM_THEMECHANGED, 0, 0); +} From 9f7caa491adcfe34f9cca6e62092283ffd09978e Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 17 May 2017 23:47:08 +1000 Subject: [PATCH 0108/2058] peview: Fix symbol filter --- tools/peview/include/peview.h | 1 + tools/peview/pdb.c | 173 ++++++++++------------------------ tools/peview/pdbprp.c | 5 + 3 files changed, 55 insertions(+), 124 deletions(-) diff --git a/tools/peview/include/peview.h b/tools/peview/include/peview.h index f626710a2439..91d189acc697 100644 --- a/tools/peview/include/peview.h +++ b/tools/peview/include/peview.h @@ -97,6 +97,7 @@ typedef enum _PV_SYMBOL_TYPE PV_SYMBOL_TYPE_STRUCT, PV_SYMBOL_TYPE_STATIC_MEMBER, PV_SYMBOL_TYPE_CONSTANT, + PV_SYMBOL_TYPE_MEMBER, PV_SYMBOL_TYPE_CLASS, } PV_SYMBOL_TYPE; diff --git a/tools/peview/pdb.c b/tools/peview/pdb.c index 12ebe46f59bd..af7357660b51 100644 --- a/tools/peview/pdb.c +++ b/tools/peview/pdb.c @@ -478,15 +478,7 @@ BOOLEAN SymbolInfo_DumpFunctionType( ULONG Children[cMaxChildren]; ULONG NumChildren = 0; - if( !GetChildren( m_hProcess, BaseAddress, Index, Children, NumChildren, cMaxChildren ) ) - { - ULONG ErrCode = 0; - _ASSERTE( !_T("GetChildren() failed.") ); - } - else - { - ULONG ErrCode = 0; - } + GetChildren( m_hProcess, BaseAddress, Index, Children, NumChildren, cMaxChildren) */ // Dump function arguments @@ -1922,8 +1914,6 @@ BOOL CALLBACK EnumCallbackProc( ); SymbolInfo_SymbolLocationStr(SymbolInfo, symbol->Pointer); - // Flags: %x, SymbolInfo->Flags - // Index: %8u, TypeIndex: %8u, SymbolInfo->Index, SymbolInfo->TypeIndex PhAcquireQueuedLockExclusive(&SearchResultsLock); PhAddItemList(SearchResults, symbol); PhReleaseQueuedLockExclusive(&SearchResultsLock); @@ -2045,30 +2035,21 @@ VOID PrintClassInfo( _In_ UdtClassInfo* Info ) { - PPV_SYMBOL_NODE symbol; - - symbol = PhAllocate(sizeof(PV_SYMBOL_NODE)); - memset(symbol, 0, sizeof(PV_SYMBOL_NODE)); - - symbol->Type = PV_SYMBOL_TYPE_CLASS; + //PPV_SYMBOL_NODE symbol; + //symbol = PhAllocate(sizeof(PV_SYMBOL_NODE)); + //memset(symbol, 0, sizeof(PV_SYMBOL_NODE)); + //symbol->Type = PV_SYMBOL_TYPE_CLASS; //symbol->Address = VarInfo.sDataInfo.Address; //symbol->Size = (ULONG)Info->Offset; - symbol->Name = SymbolInfo_GetTypeName(Context, Index, Info->Name);// PhCreateString(SymbolInfo_UdtKindStr(Info->UDTKind)); + //symbol->Name = SymbolInfo_GetTypeName(Context, Index, Info->Name);// PhCreateString(SymbolInfo_UdtKindStr(Info->UDTKind)); //symbol->Data = SymbolInfo_GetTypeName(Context, Index, Info->Name); - - if (PhEqualString2(symbol->Name, L"STRUCT", TRUE)) - symbol->Type = PV_SYMBOL_TYPE_STRUCT; - //SymbolInfo_SymbolLocationStr(SymbolInfo, symbol->Pointer); - - PhAcquireQueuedLockExclusive(&SearchResultsLock); - PhAddItemList(SearchResults, symbol); - PhReleaseQueuedLockExclusive(&SearchResultsLock); - - // Info.Nested - // Info->NumVariables - // Info->NumFunctions - // Info->NumBaseClasses + //Info.Nested + //if (PhEqualString2(symbol->Name, L"STRUCT", TRUE)) + // symbol->Type = PV_SYMBOL_TYPE_STRUCT; + //PhAcquireQueuedLockExclusive(&SearchResultsLock); + //PhAddItemList(SearchResults, symbol); + //PhReleaseQueuedLockExclusive(&SearchResultsLock); for (ULONG i = 0; i < Info->NumVariables; i++) { @@ -2083,62 +2064,46 @@ VOID PrintClassInfo( // Unexpected symbol tag. } else - { - // Location - //switch (VarInfo.sDataInfo.dataKind) - //{ - //case DataIsGlobal: - //case DataIsStaticLocal: - //case DataIsFileStatic: - //case DataIsStaticMember: - // { - // // Use Address - // // " Address: %16I64x" VarInfo.sDataInfo.Address - // } - // break; - //case DataIsLocal: - //case DataIsParam: - //case DataIsObjectPtr: - //case DataIsMember: - // { - // // Use Offset - // // " Offset: %8d" (long)VarInfo.sDataInfo.Offset - // } - // break; - //default: - // break; // TODO Add support for constants - //} - // + { //PPV_SYMBOL_NODE symbol; // //symbol = PhAllocate(sizeof(PV_SYMBOL_NODE)); //memset(symbol, 0, sizeof(PV_SYMBOL_NODE)); // //symbol->Type = PV_SYMBOL_TYPE_MEMBER; - //symbol->Address = VarInfo.sDataInfo.Address; + // + // Location + switch (VarInfo.sDataInfo.dataKind) + { + case DataIsGlobal: + case DataIsStaticLocal: + case DataIsFileStatic: + case DataIsStaticMember: + { + //symbol->Address = VarInfo.sDataInfo.Address; + } + break; + case DataIsLocal: + case DataIsParam: + case DataIsObjectPtr: + case DataIsMember: + { + //symbol->Address = VarInfo.sDataInfo.Offset; + } + break; + default: + break; // TODO Add support for constants + } + //symbol->Size = (ULONG)VarInfo.sDataInfo.Offset; //symbol->Name = PhCreateString(VarInfo.sDataInfo.Name); + //symbol->Data = SymbolInfo_GetTypeName(Context, VarInfo.sDataInfo.TypeIndex, VarInfo.sDataInfo.Name); //SymbolInfo_SymbolLocationStr(SymbolInfo, symbol->Pointer); - // - // Data - //if (SymbolInfo_GetTypeName(Context, &typeName, VarInfo.sDataInfo.TypeIndex, VarInfo.sDataInfo.Name)) - // symbol->Data = PhFinalStringBuilderString(&typeName); - // Flags: %x, SymbolInfo->Flags - // Index: %8u, TypeIndex: %8u, SymbolInfo->Index, SymbolInfo->TypeIndex - // Nested - //if (Info.Info.sUdtClassInfo.Nested) - // printf("Nested"); - // - // Number of members - //printf(" Members: %d", Info.Info.sUdtClassInfo.NumVariables); - // + //Info.Info.sUdtClassInfo.Nested + //Info.Info.sUdtClassInfo.NumVariables //PhAcquireQueuedLockExclusive(&SearchResultsLock); //PhAddItemList(SearchResults, symbol); //PhReleaseQueuedLockExclusive(&SearchResultsLock); - // - // Update the search results in batches of 2000. - //if (SearchResults->Count % 2000 == 0) - // PostMessage(Context->DialogHandle, WM_PV_SEARCH_UPDATE, 0, 0); } } @@ -2161,7 +2126,7 @@ VOID PrintClassInfo( symbol = PhAllocate(sizeof(PV_SYMBOL_NODE)); memset(symbol, 0, sizeof(PV_SYMBOL_NODE)); - symbol->Type = PV_SYMBOL_TYPE_STRUCT; + symbol->Type = PV_SYMBOL_TYPE_FUNCTION; symbol->Address = VarInfo.sDataInfo.Address; symbol->Size = (ULONG)VarInfo.sDataInfo.Offset; symbol->Name = PhCreateString(VarInfo.sDataInfo.Name); @@ -2281,45 +2246,9 @@ VOID PrintUserDefinedTypes( } else { - PPV_SYMBOL_NODE symbol; - - symbol = PhAllocate(sizeof(PV_SYMBOL_NODE)); - memset(symbol, 0, sizeof(PV_SYMBOL_NODE)); - - symbol->Type = PV_SYMBOL_TYPE_CLASS; - //symbol->Address = VarInfo.sDataInfo.Address; - //symbol->Size = (ULONG)Info->Offset; - symbol->Name = SymbolInfo_GetTypeName(Context, index, info.sUdtUnionInfo.Name); - // PhCreateString(SymbolInfo_UdtKindStr(Info->UDTKind)); - symbol->Data = SymbolInfo_GetTypeName(Context, index, info.sUdtUnionInfo.Name); - - if (PhEqualString2(symbol->Name, L"STRUCT", TRUE)) - symbol->Type = PV_SYMBOL_TYPE_STRUCT; - - //SymbolInfo_SymbolLocationStr(SymbolInfo, symbol->Pointer); - - PhAcquireQueuedLockExclusive(&SearchResultsLock); - PhAddItemList(SearchResults, symbol); - PhReleaseQueuedLockExclusive(&SearchResultsLock); - - // Print information about the union - for (ULONG i = 0; i < info.sUdtUnionInfo.NumMembers; i++) - { - TypeInfo baseInfo; - - if (!SymbolInfo_DumpType(Context, info.sUdtUnionInfo.Members[i], &baseInfo)) - { - // Continue - } - else if (baseInfo.Tag != SymTagBaseClass) - { - // Continue - } - else - { - - } - } + //info.sUdtUnionInfo.Name + //PhCreateString(SymbolInfo_UdtKindStr(Info->UDTKind)); + //SymbolInfo_GetTypeName(Context, index, info.sUdtUnionInfo.Name); } } } @@ -2448,7 +2377,6 @@ NTSTATUS PeDumpFileSymbols( HANDLE fileHandle; HMODULE dbghelpHandle; HMODULE symsrvHandle; - ULONG64 symbolBaseAddress; ULONG64 baseAddress = 0; LARGE_INTEGER fileSize; PPH_STRING dbghelpPath; @@ -2473,7 +2401,7 @@ NTSTATUS PeDumpFileSymbols( SymGetTypeInfo_I = PhGetProcedureAddress(dbghelpHandle, "SymGetTypeInfo", 0); SymSetContext_I = PhGetProcedureAddress(dbghelpHandle, "SymSetContext", 0); - SymSetOptions_I(SymGetOptions_I() | SYMOPT_DEBUG | SYMOPT_UNDNAME | SYMOPT_ALLOW_ZERO_ADDRESS); // SYMOPT_DEFERRED_LOADS | SYMOPT_FAVOR_COMPRESSED + SymSetOptions_I(SymGetOptions_I() | SYMOPT_DEBUG | SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS); if (!SymInitialize_I(NtCurrentProcess(), NULL, FALSE)) return 1; @@ -2503,22 +2431,19 @@ NTSTATUS PeDumpFileSymbols( if (PhEndsWithString2(PvFileName, L".pdb", TRUE)) baseAddress = 0x10000000; - if ((symbolBaseAddress = SymLoadModuleExW_I( + if (Context->BaseAddress = SymLoadModuleExW_I( NtCurrentProcess(), - NULL, + fileHandle, PhGetString(PvFileName), NULL, baseAddress, (ULONG)fileSize.QuadPart, NULL, 0 - ))) + )) { - Context->UdtList = PhCreateList(0x100); - Context->BaseAddress = symbolBaseAddress; - //ShowModuleSymbolInfo(symbolBaseAddress); - SymEnumSymbolsW_I(NtCurrentProcess(), symbolBaseAddress, NULL, EnumCallbackProc, Context); + SymEnumSymbolsW_I(NtCurrentProcess(), Context->BaseAddress, NULL, EnumCallbackProc, Context); // Enumerate user defined types PrintUserDefinedTypes(Context); diff --git a/tools/peview/pdbprp.c b/tools/peview/pdbprp.c index 4b04ccfd2605..64f8ffdb0742 100644 --- a/tools/peview/pdbprp.c +++ b/tools/peview/pdbprp.c @@ -606,6 +606,9 @@ BOOLEAN NTAPI PvSymbolTreeNewCallback( case PV_SYMBOL_TYPE_CLASS: PhInitializeStringRef(&getCellText->Text, L"CLASS"); break; + case PV_SYMBOL_TYPE_MEMBER: + PhInitializeStringRef(&getCellText->Text, L"MEMBER"); + break; } } break; @@ -938,6 +941,8 @@ INT_PTR CALLBACK PvpSymbolsDlgProc( SendMessage(GetDlgItem(hwndDlg, IDC_PROGRESS), PBM_SETMARQUEE, TRUE, 75); SearchResults = PhCreateList(0x1000); + context->UdtList = PhCreateList(0x100); + context->SearchThreadHandle = PhCreateThread(0, PeDumpFileSymbols, context); if (CreateTimerQueueTimer( From 9f672ba0ac23a6f18cc49c28b36bf59f4e1b4cb7 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 17 May 2017 23:52:34 +1000 Subject: [PATCH 0109/2058] peview: Fix symbol size column --- tools/peview/include/peview.h | 1 + tools/peview/pdbprp.c | 13 +++++++++++++ 2 files changed, 14 insertions(+) diff --git a/tools/peview/include/peview.h b/tools/peview/include/peview.h index 91d189acc697..253606b17cdf 100644 --- a/tools/peview/include/peview.h +++ b/tools/peview/include/peview.h @@ -111,6 +111,7 @@ typedef struct _PV_SYMBOL_NODE ULONG64 Address; PPH_STRING Name; PPH_STRING Data; + PPH_STRING SizeText; WCHAR Pointer[PH_PTR_STR_LEN_1]; PH_STRINGREF TextCache[TREE_COLUMN_ITEM_MAXIMUM]; diff --git a/tools/peview/pdbprp.c b/tools/peview/pdbprp.c index 64f8ffdb0742..f067dff423c8 100644 --- a/tools/peview/pdbprp.c +++ b/tools/peview/pdbprp.c @@ -621,6 +621,19 @@ BOOLEAN NTAPI PvSymbolTreeNewCallback( case TREE_COLUMN_ITEM_SYMBOL: getCellText->Text = PhGetStringRef(node->Data); break; + case TREE_COLUMN_ITEM_SIZE: + { + if (node->Size != 0) + { + PH_FORMAT format[1]; + + PhInitFormatSize(&format[0], node->Size); + + PhMoveReference(&node->SizeText, PhFormat(format, 1, 0)); + getCellText->Text = node->SizeText->sr; + } + } + break; default: return FALSE; } From 496a629b6681d5b73009377d9cd4cd759ef59fa6 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 18 May 2017 01:45:46 +1000 Subject: [PATCH 0110/2058] Fix modules tab LoadCount for x64 (1/2) --- phlib/native.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/phlib/native.c b/phlib/native.c index 6a70c8fe1400..056c2a60e809 100644 --- a/phlib/native.c +++ b/phlib/native.c @@ -3136,6 +3136,24 @@ BOOLEAN NTAPI PhpEnumProcessModulesCallback( } } + if (WindowsVersion >= WINDOWS_8) + { + LDR_DDAG_NODE ldrDagNode = { 0 }; + + if (NT_SUCCESS(NtReadVirtualMemory( + ProcessHandle, + Entry->DdagNode, + &ldrDagNode, + sizeof(LDR_DDAG_NODE), + NULL + ))) + { + // HACK: Fixup the module load count (64bit only). + // Temp fix until PhpModuleQueryWorker can be updated with Stage2. + Entry->ObsoleteLoadCount = (USHORT)ldrDagNode.LoadCount; + } + } + // Execute the callback. cont = parameters->Callback(Entry, parameters->Context); From dc6a8a94f7e4b381090b46eb8e1b9fd7de052dbe Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 18 May 2017 02:00:14 +1000 Subject: [PATCH 0111/2058] Fix build warnings --- ProcessHacker.sln | 2 +- ProcessHacker/ProcessHacker.vcxproj | 2 +- phlib/phlib.vcxproj | 2 +- phlib/phlib.vcxproj.filters | 734 ++++++++++++++-------------- tools/peview/pdb.c | 20 +- tools/peview/pdbprp.c | 6 +- 6 files changed, 381 insertions(+), 385 deletions(-) diff --git a/ProcessHacker.sln b/ProcessHacker.sln index b9f1116bcef8..c2fa6bcc9b31 100644 --- a/ProcessHacker.sln +++ b/ProcessHacker.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 -VisualStudioVersion = 15.0.26403.7 +VisualStudioVersion = 15.0.26430.6 MinimumVisualStudioVersion = 15.0.26228.4 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tools", "Tools", "{2758DC86-368B-430C-9D29-F1EF20032A71}" EndProject diff --git a/ProcessHacker/ProcessHacker.vcxproj b/ProcessHacker/ProcessHacker.vcxproj index 6273867a710a..f212a670d21b 100644 --- a/ProcessHacker/ProcessHacker.vcxproj +++ b/ProcessHacker/ProcessHacker.vcxproj @@ -1,4 +1,4 @@ - + diff --git a/phlib/phlib.vcxproj b/phlib/phlib.vcxproj index f9b2a7f82826..cf67c6719a83 100644 --- a/phlib/phlib.vcxproj +++ b/phlib/phlib.vcxproj @@ -1,4 +1,4 @@ - + diff --git a/phlib/phlib.vcxproj.filters b/phlib/phlib.vcxproj.filters index aef40882c991..cae851a27dce 100644 --- a/phlib/phlib.vcxproj.filters +++ b/phlib/phlib.vcxproj.filters @@ -1,368 +1,368 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hpp;hxx;hm;inl;inc;xsd - - - {7d0c2da2-811d-4844-9704-0c87067c7be1} - - - {874b89c3-fb60-46f3-a62c-49ac88e3026d} - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Mini-XML - - - Mini-XML - - - Mini-XML - - - Mini-XML - - - Mini-XML - - - Mini-XML - - - Mini-XML - - - Mini-XML - - - Mini-XML - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Mini-XML\Headers - - - Mini-XML\Headers - - - Mini-XML\Headers - - + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {7d0c2da2-811d-4844-9704-0c87067c7be1} + + + {874b89c3-fb60-46f3-a62c-49ac88e3026d} + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Mini-XML + + + Mini-XML + + + Mini-XML + + + Mini-XML + + + Mini-XML + + + Mini-XML + + + Mini-XML + + + Mini-XML + + + Mini-XML + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Mini-XML\Headers + + + Mini-XML\Headers + + + Mini-XML\Headers + + \ No newline at end of file diff --git a/tools/peview/pdb.c b/tools/peview/pdb.c index af7357660b51..b1efe29dedc2 100644 --- a/tools/peview/pdb.c +++ b/tools/peview/pdb.c @@ -2374,7 +2374,7 @@ NTSTATUS PeDumpFileSymbols( ) { NTSTATUS status; - HANDLE fileHandle; + HANDLE fileHandle = NULL; HMODULE dbghelpHandle; HMODULE symsrvHandle; ULONG64 baseAddress = 0; @@ -2407,9 +2407,9 @@ NTSTATUS PeDumpFileSymbols( return 1; if (!SymSetSearchPathW_I(NtCurrentProcess(), L"SRV*C:\\symbols*http://msdl.microsoft.com/download/symbols")) - goto CleanupExit; + return 1; - status = PhCreateFileWin32( + if (!NT_SUCCESS(status = PhCreateFileWin32( &fileHandle, PhGetString(PvFileName), FILE_GENERIC_READ, @@ -2417,16 +2417,11 @@ NTSTATUS PeDumpFileSymbols( FILE_SHARE_READ | FILE_SHARE_DELETE, FILE_OPEN, FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT - ); - - if (!NT_SUCCESS(status)) - return status; + ))) + return 1; if (NT_SUCCESS(PhGetFileSize(fileHandle, &fileSize)) && fileSize.QuadPart == 0) - { - NtClose(fileHandle); - return status; - } + goto CleanupExit; if (PhEndsWithString2(PvFileName, L".pdb", TRUE)) baseAddress = 0x10000000; @@ -2453,7 +2448,8 @@ NTSTATUS PeDumpFileSymbols( SymCleanup_I(NtCurrentProcess()); - NtClose(fileHandle); + if (fileHandle) + NtClose(fileHandle); PostMessage(Context->DialogHandle, WM_PV_SEARCH_FINISHED, 0, 0); diff --git a/tools/peview/pdbprp.c b/tools/peview/pdbprp.c index f067dff423c8..05e833a0d16c 100644 --- a/tools/peview/pdbprp.c +++ b/tools/peview/pdbprp.c @@ -40,8 +40,8 @@ VOID PhInitializeTreeNewColumnMenuEx( PPH_EMENU_ITEM resetSortMenuItem = NULL; PPH_EMENU_ITEM sizeColumnToFitMenuItem; PPH_EMENU_ITEM sizeAllColumnsToFitMenuItem; - PPH_EMENU_ITEM hideColumnMenuItem; - PPH_EMENU_ITEM chooseColumnsMenuItem; + PPH_EMENU_ITEM hideColumnMenuItem = NULL; + PPH_EMENU_ITEM chooseColumnsMenuItem = NULL; ULONG minimumNumberOfColumns; Data->Menu = PhCreateEMenu(); @@ -496,7 +496,7 @@ END_SORT_FUNCTION BEGIN_SORT_FUNCTION(VA) { - sortResult = uintptrcmp(node1->Address, node2->Address); + sortResult = uintptrcmp((ULONG_PTR)node1->Address, (ULONG_PTR)node2->Address); } END_SORT_FUNCTION From 7195ce76c0d35bb4cbc3b9661440b0cbb7f7ae1e Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 18 May 2017 08:08:19 +1000 Subject: [PATCH 0112/2058] peview: Re-add some filters --- tools/peview/pdb.c | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/tools/peview/pdb.c b/tools/peview/pdb.c index b1efe29dedc2..6b12b042e63a 100644 --- a/tools/peview/pdb.c +++ b/tools/peview/pdb.c @@ -1935,17 +1935,24 @@ BOOL CALLBACK EnumCallbackProc( if (!SymbolInfo->Address) break; - if (!SymGetTypeInfo_I(NtCurrentProcess(), SymbolInfo->ModBase, SymbolInfo->Index, TI_GET_DATAKIND, &dataKindType)) + if (!SymGetTypeInfo_I( + NtCurrentProcess(), + SymbolInfo->ModBase, + SymbolInfo->Index, + TI_GET_DATAKIND, + &dataKindType + )) + { break; + } symDataKind = SymbolInfo_DataKindStr(dataKindType); - //if (dataKindType == DataIsLocal || - // dataKindType == DataIsObjectPtr || - // dataKindType == DataIsParam) - //{ - // break; - //} + if ( + dataKindType == DataIsLocal || + dataKindType == DataIsParam + ) // || dataKindType == DataIsObjectPtr) + break; symbol = PhAllocate(sizeof(PV_SYMBOL_NODE)); memset(symbol, 0, sizeof(PV_SYMBOL_NODE)); @@ -1990,8 +1997,6 @@ BOOL CALLBACK EnumCallbackProc( symbol->Data = SymbolInfo_GetTypeName(context, SymbolInfo->TypeIndex, SymbolInfo->Name); SymbolInfo_SymbolLocationStr(SymbolInfo, symbol->Pointer); - // Flags: %x, SymbolInfo->Flags - // Index: %8u, TypeIndex: %8u, SymbolInfo->Index, SymbolInfo->TypeIndex PhAcquireQueuedLockExclusive(&SearchResultsLock); PhAddItemList(SearchResults, symbol); PhReleaseQueuedLockExclusive(&SearchResultsLock); @@ -2016,8 +2021,6 @@ BOOL CALLBACK EnumCallbackProc( symbol->Data = SymbolInfo_GetTypeName(context, SymbolInfo->TypeIndex, SymbolInfo->Name); SymbolInfo_SymbolLocationStr(SymbolInfo, symbol->Pointer); - // Flags: %x, SymbolInfo->Flags - // Index: %8u, TypeIndex: %8u, SymbolInfo->Index, SymbolInfo->TypeIndex PhAcquireQueuedLockExclusive(&SearchResultsLock); PhAddItemList(SearchResults, symbol); PhReleaseQueuedLockExclusive(&SearchResultsLock); From 71f40f7a34357e4d18e05f34368db493479d0eed Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 18 May 2017 08:13:44 +1000 Subject: [PATCH 0113/2058] BuildTool: Update binaries to latest revision --- build/build_changelog.cmd | 7 + tools/CustomBuildTool/Source Files/Build.cs | 395 ++++++++---------- .../Source Files/NativeMethods.cs | 35 +- tools/CustomBuildTool/Source Files/Program.cs | 227 +++++----- .../bin/Release/CustomBuildTool.exe | Bin 162304 -> 160256 bytes .../bin/Release/CustomBuildTool.pdb | Bin 75264 -> 73216 bytes .../CustomSetupTool/CustomSetupTool/extract.c | 4 +- 7 files changed, 305 insertions(+), 363 deletions(-) create mode 100644 build/build_changelog.cmd diff --git a/build/build_changelog.cmd b/build/build_changelog.cmd new file mode 100644 index 000000000000..3a1df98f5065 --- /dev/null +++ b/build/build_changelog.cmd @@ -0,0 +1,7 @@ +@echo off +@setlocal enableextensions +@cd /d "%~dp0\..\" + +start /B /W "" "tools\CustomBuildTool\bin\Release\CustomBuildTool.exe" "-graph" + +pause diff --git a/tools/CustomBuildTool/Source Files/Build.cs b/tools/CustomBuildTool/Source Files/Build.cs index ddacc7449635..f0073edf10fd 100644 --- a/tools/CustomBuildTool/Source Files/Build.cs +++ b/tools/CustomBuildTool/Source Files/Build.cs @@ -16,6 +16,7 @@ public static class Build private static string BuildOutputFolder = "build"; private static string BuildVersion; private static string BuildLongVersion; + private static string BuildCount; private static string BuildRevision; private static string BuildMessage; private static long BuildSetupFileLength; @@ -223,63 +224,51 @@ public static void CleanupBuildEnvironment() } } - public static void ShowBuildEnvironment(string Platform, bool ShowBuildInfo) + public static string GetBuildLogString() { - if (ShowBuildInfo) - { - Program.PrintColorMessage("Build: ", ConsoleColor.Cyan, false); - Program.PrintColorMessage(Platform, ConsoleColor.White, false); - } - - string currentGitTag = Win32.ShellExecute(GitExePath, "describe --abbrev=0 --tags --always"); - string latestGitRevision = Win32.ShellExecute(GitExePath, "rev-list --count \"" + currentGitTag + ".." + BuildBranch + "\""); + return Win32.ShellExecute(GitExePath, "log -n 1800 --graph --pretty=format:\"%C(yellow)%h%Creset %C(bold blue)%an%Creset %s %C(dim green)(%cr)\" --abbrev-commit ").Trim(); + } - if (string.IsNullOrEmpty(latestGitRevision)) + public static void ShowBuildEnvironment(string Platform, bool ShowBuildInfo, bool ShowLogInfo) + { + string currentBranch = Win32.ShellExecute(GitExePath, "rev-parse --abbrev-ref HEAD"); + string currentCommitTag = Win32.ShellExecute(GitExePath, "rev-parse --short HEAD"); // rev-parse HEAD + Program.PrintColorMessage("Branch: ", ConsoleColor.Cyan, false); + Program.PrintColorMessage(currentBranch, ConsoleColor.White); + Program.PrintColorMessage("Commit: ", ConsoleColor.Cyan, false); + Program.PrintColorMessage(currentCommitTag, ConsoleColor.White); + + string currentGitTag = Win32.ShellExecute(GitExePath, "describe --abbrev=0 --tags --always").Trim(); + BuildRevision = Win32.ShellExecute(GitExePath, "rev-list --count \"" + currentGitTag + ".." + BuildBranch + "\"").Trim(); + BuildCount = Win32.ShellExecute(GitExePath, "rev-list --count " + BuildBranch).Trim(); + + if (string.IsNullOrEmpty(BuildRevision)) BuildRevision = "0"; - else - BuildRevision = latestGitRevision.Trim(); + if (string.IsNullOrEmpty(BuildCount)) + BuildCount = "0"; BuildVersion = "3.0." + BuildRevision; - BuildLongVersion = "3.0.0." + BuildRevision; - BuildMessage = Win32.ShellExecute(GitExePath, "log -n 5 --date=format:%Y-%m-%d --pretty=format:\"[%cd] %an %s\" --abbrev-commit"); - + BuildLongVersion = "3.0." + BuildCount + "." + BuildRevision; + if (ShowBuildInfo) { - string buildMessage = string.Empty; + Program.PrintColorMessage("Version: ", ConsoleColor.Cyan, false); + Program.PrintColorMessage(BuildLongVersion + Environment.NewLine, ConsoleColor.White); - if (BuildNightly) + if (ShowLogInfo) { - buildMessage = Win32.ShellExecute(GitExePath, "log -n 5 --date=format:%Y-%m-%d --pretty=format:\"[%cd] %an: %<(65,trunc)%s (%h)\" --abbrev-commit"); - } - else - { - Win32.GetConsoleMode(Win32.GetStdHandle(Win32.STD_OUTPUT_HANDLE), out ConsoleMode mode); - Win32.SetConsoleMode(Win32.GetStdHandle(Win32.STD_OUTPUT_HANDLE), mode | ConsoleMode.ENABLE_VIRTUAL_TERMINAL_PROCESSING); - buildMessage = Win32.ShellExecute(GitExePath, "log -n 5 --date=format:%Y-%m-%d --pretty=format:\"%C(green)[%cd]%Creset %C(bold blue)%an%Creset %<(65,trunc)%s%Creset (%C(yellow)%h%Creset)\" --abbrev-commit"); - } - - string currentBranch = Win32.ShellExecute(GitExePath, "rev-parse --abbrev-ref HEAD"); - string currentCommitTag = Win32.ShellExecute(GitExePath, "rev-parse --short HEAD"); // rev-parse HEAD - //string latestGitCount = Win32.GitExecCommand("rev-list --count " + BuildBranch); - - if (!string.IsNullOrEmpty(currentBranch)) - { - Program.PrintColorMessage(Environment.NewLine + "Branch: ", ConsoleColor.Cyan, false); - Program.PrintColorMessage(currentBranch, ConsoleColor.White); - } - - if (!string.IsNullOrEmpty(BuildVersion)) - { - Program.PrintColorMessage("Version: ", ConsoleColor.Cyan, false); - Program.PrintColorMessage(BuildVersion, ConsoleColor.White); - } + if (BuildNightly) + BuildMessage = Win32.ShellExecute(GitExePath, "log -n 5 --date=format:%Y-%m-%d --pretty=format:\"[%cd] %an: %<(65,trunc)%s (%h)\" --abbrev-commit"); + else + { + Win32.GetConsoleMode(Win32.GetStdHandle(Win32.STD_OUTPUT_HANDLE), out ConsoleMode mode); + Win32.SetConsoleMode(Win32.GetStdHandle(Win32.STD_OUTPUT_HANDLE), mode | ConsoleMode.ENABLE_VIRTUAL_TERMINAL_PROCESSING); - Program.PrintColorMessage("Commit: ", ConsoleColor.Cyan, false); - Program.PrintColorMessage(currentCommitTag + Environment.NewLine, ConsoleColor.White); + //BuildMessage = Win32.ShellExecute(GitExePath, "log -n 5 --date=format:%Y-%m-%d --pretty=format:\"[%cd] %an %s\" --abbrev-commit"); + BuildMessage = Win32.ShellExecute(GitExePath, "log -n 5 --date=format:%Y-%m-%d --pretty=format:\"%C(green)[%cd]%Creset %C(bold blue)%an%Creset %<(65,trunc)%s%Creset (%C(yellow)%h%Creset)\" --abbrev-commit"); + } - if (!string.IsNullOrEmpty(buildMessage)) - { - Console.WriteLine(buildMessage + Environment.NewLine); + Console.WriteLine(BuildMessage + Environment.NewLine); } } } @@ -288,21 +277,20 @@ public static void ShowBuildStats() { TimeSpan buildTime = DateTime.Now - TimeStart; - Console.WriteLine(); - Console.WriteLine("Build Time: " + buildTime.Minutes + " minute(s), " + buildTime.Seconds + " second(s)"); - Console.WriteLine("Build complete."); + Console.WriteLine( + Environment.NewLine + "Build Time: " + + buildTime.Minutes + " minute(s), " + + buildTime.Seconds + " second(s)"); } public static bool CopyTextFiles() { - Program.PrintColorMessage("Copying text files...", ConsoleColor.Cyan); - try { - File.Copy("README.md", "bin\\README.txt", true); - File.Copy("CHANGELOG.txt", "bin\\CHANGELOG.txt", true); - File.Copy("COPYRIGHT.txt", "bin\\COPYRIGHT.txt", true); - File.Copy("LICENSE.txt", "bin\\LICENSE.txt", true); + Win32.CopyIfNewer("README.md", "bin\\README.txt"); + Win32.CopyIfNewer("CHANGELOG.txt", "bin\\CHANGELOG.txt"); + Win32.CopyIfNewer("COPYRIGHT.txt", "bin\\COPYRIGHT.txt"); + Win32.CopyIfNewer("LICENSE.txt", "bin\\LICENSE.txt"); } catch (Exception ex) { @@ -313,53 +301,45 @@ public static bool CopyTextFiles() return true; } - public static bool CopyKProcessHacker(bool DebugBuild) - { - Program.PrintColorMessage("Copying KPH driver...", ConsoleColor.Cyan); - - try - { - if (DebugBuild) - { - File.Copy("KProcessHacker\\bin-signed\\i386\\kprocesshacker.sys", "bin\\Debug32\\kprocesshacker.sys", true); - File.Copy("KProcessHacker\\bin-signed\\amd64\\kprocesshacker.sys", "bin\\Debug64\\kprocesshacker.sys", true); - } - else - { - File.Copy("KProcessHacker\\bin-signed\\i386\\kprocesshacker.sys", "bin\\Release32\\kprocesshacker.sys", true); - File.Copy("KProcessHacker\\bin-signed\\amd64\\kprocesshacker.sys", "bin\\Release64\\kprocesshacker.sys", true); - } - } - catch (Exception ex) - { - Program.PrintColorMessage("[ERROR] " + ex, ConsoleColor.Red); - return false; - } - - return true; - } - public static bool CopyLibFiles(BuildFlags Flags) { - Program.PrintColorMessage("Copying Plugin SDK linker files...", ConsoleColor.Cyan); - try { if (Flags.HasFlag(BuildFlags.BuildDebug)) { if (Flags.HasFlag(BuildFlags.Build32bit)) - File.Copy("bin\\Debug32\\ProcessHacker.lib", "sdk\\lib\\i386\\ProcessHacker.lib", true); + { + Win32.CopyIfNewer( + "bin\\Debug32\\ProcessHacker.lib", + "sdk\\lib\\i386\\ProcessHacker.lib" + ); + } if (Flags.HasFlag(BuildFlags.Build64bit)) - File.Copy("bin\\Debug64\\ProcessHacker.lib", "sdk\\lib\\amd64\\ProcessHacker.lib", true); + { + Win32.CopyIfNewer( + "bin\\Debug64\\ProcessHacker.lib", + "sdk\\lib\\amd64\\ProcessHacker.lib" + ); + } } else { if (Flags.HasFlag(BuildFlags.Build32bit)) - File.Copy("bin\\Release32\\ProcessHacker.lib", "sdk\\lib\\i386\\ProcessHacker.lib", true); + { + Win32.CopyIfNewer( + "bin\\Release32\\ProcessHacker.lib", + "sdk\\lib\\i386\\ProcessHacker.lib" + ); + } if (Flags.HasFlag(BuildFlags.Build64bit)) - File.Copy("bin\\Release64\\ProcessHacker.lib", "sdk\\lib\\amd64\\ProcessHacker.lib", true); + { + Win32.CopyIfNewer( + "bin\\Release64\\ProcessHacker.lib", + "sdk\\lib\\amd64\\ProcessHacker.lib" + ); + } } } catch (Exception ex) @@ -384,10 +364,10 @@ public static bool CopyWow64Files(BuildFlags Flags) if (!Directory.Exists("bin\\Debug64\\x86\\plugins")) Directory.CreateDirectory("bin\\Debug64\\x86\\plugins"); - File.Copy("bin\\Debug32\\ProcessHacker.exe", "bin\\Debug64\\x86\\ProcessHacker.exe", true); - File.Copy("bin\\Debug32\\ProcessHacker.pdb", "bin\\Debug64\\x86\\ProcessHacker.pdb", true); - File.Copy("bin\\Debug32\\plugins\\DotNetTools.dll", "bin\\Debug64\\x86\\plugins\\DotNetTools.dll", true); - File.Copy("bin\\Debug32\\plugins\\DotNetTools.pdb", "bin\\Debug64\\x86\\plugins\\DotNetTools.pdb", true); + Win32.CopyIfNewer("bin\\Debug32\\ProcessHacker.exe", "bin\\Debug64\\x86\\ProcessHacker.exe"); + Win32.CopyIfNewer("bin\\Debug32\\ProcessHacker.pdb", "bin\\Debug64\\x86\\ProcessHacker.pdb"); + Win32.CopyIfNewer("bin\\Debug32\\plugins\\DotNetTools.dll", "bin\\Debug64\\x86\\plugins\\DotNetTools.dll"); + Win32.CopyIfNewer("bin\\Debug32\\plugins\\DotNetTools.pdb", "bin\\Debug64\\x86\\plugins\\DotNetTools.pdb"); } else { @@ -396,14 +376,22 @@ public static bool CopyWow64Files(BuildFlags Flags) if (!Directory.Exists("bin\\Release64\\x86\\plugins")) Directory.CreateDirectory("bin\\Release64\\x86\\plugins"); - if (File.Exists("bin\\Release32\\ProcessHacker.exe")) - File.Copy("bin\\Release32\\ProcessHacker.exe", "bin\\Release64\\x86\\ProcessHacker.exe", true); - if (File.Exists("bin\\Release32\\ProcessHacker.pdb")) - File.Copy("bin\\Release32\\ProcessHacker.pdb", "bin\\Release64\\x86\\ProcessHacker.pdb", true); - if (File.Exists("bin\\Release32\\plugins\\DotNetTools.dll")) - File.Copy("bin\\Release32\\plugins\\DotNetTools.dll", "bin\\Release64\\x86\\plugins\\DotNetTools.dll", true); - if (File.Exists("bin\\Release32\\plugins\\DotNetTools.pdb")) - File.Copy("bin\\Release32\\plugins\\DotNetTools.pdb", "bin\\Release64\\x86\\plugins\\DotNetTools.pdb", true); + Win32.CopyIfNewer( + "bin\\Release32\\ProcessHacker.exe", + "bin\\Release64\\x86\\ProcessHacker.exe" + ); + Win32.CopyIfNewer( + "bin\\Release32\\ProcessHacker.pdb", + "bin\\Release64\\x86\\ProcessHacker.pdb" + ); + Win32.CopyIfNewer( + "bin\\Release32\\plugins\\DotNetTools.dll", + "bin\\Release64\\x86\\plugins\\DotNetTools.dll" + ); + Win32.CopyIfNewer( + "bin\\Release32\\plugins\\DotNetTools.pdb", + "bin\\Release64\\x86\\plugins\\DotNetTools.pdb" + ); } } catch (Exception ex) @@ -417,8 +405,6 @@ public static bool CopyWow64Files(BuildFlags Flags) public static bool CopyPluginSdkHeaders() { - Program.PrintColorMessage("Copying Plugin SDK headers...", ConsoleColor.Cyan); - try { foreach (string folder in sdk_directories) @@ -438,27 +424,28 @@ public static bool CopyPluginSdkHeaders() // Copy the plugin SDK headers foreach (string file in phnt_headers) - File.Copy("phnt\\include\\" + file, "sdk\\include\\" + file, true); + Win32.CopyIfNewer("phnt\\include\\" + file, "sdk\\include\\" + file); foreach (string file in phlib_headers) - File.Copy("phlib\\include\\" + file, "sdk\\include\\" + file, true); - File.Copy("phlib\\mxml\\mxml.h", "sdk\\include\\mxml.h", true); + Win32.CopyIfNewer("phlib\\include\\" + file, "sdk\\include\\" + file); + + Win32.CopyIfNewer("phlib\\mxml\\mxml.h", "sdk\\include\\mxml.h"); // Copy readme - File.Copy("ProcessHacker\\sdk\\readme.txt", "sdk\\readme.txt", true); + Win32.CopyIfNewer("ProcessHacker\\sdk\\readme.txt", "sdk\\readme.txt"); // Copy symbols - File.Copy("bin\\Release32\\ProcessHacker.pdb", "sdk\\dbg\\i386\\ProcessHacker.pdb", true); - File.Copy("bin\\Release64\\ProcessHacker.pdb", "sdk\\dbg\\amd64\\ProcessHacker.pdb", true); - File.Copy("KProcessHacker\\bin\\i386\\kprocesshacker.pdb", "sdk\\dbg\\i386\\kprocesshacker.pdb", true); - File.Copy("KProcessHacker\\bin\\amd64\\kprocesshacker.pdb", "sdk\\dbg\\amd64\\kprocesshacker.pdb", true); + Win32.CopyIfNewer("bin\\Release32\\ProcessHacker.pdb", "sdk\\dbg\\i386\\ProcessHacker.pdb"); + Win32.CopyIfNewer("bin\\Release64\\ProcessHacker.pdb", "sdk\\dbg\\amd64\\ProcessHacker.pdb"); + Win32.CopyIfNewer("KProcessHacker\\bin\\i386\\kprocesshacker.pdb", "sdk\\dbg\\i386\\kprocesshacker.pdb"); + Win32.CopyIfNewer("KProcessHacker\\bin\\amd64\\kprocesshacker.pdb", "sdk\\dbg\\amd64\\kprocesshacker.pdb"); // Copy libs - File.Copy("bin\\Release32\\ProcessHacker.lib", "sdk\\lib\\i386\\ProcessHacker.lib", true); - File.Copy("bin\\Release64\\ProcessHacker.lib", "sdk\\lib\\amd64\\ProcessHacker.lib", true); + Win32.CopyIfNewer("bin\\Release32\\ProcessHacker.lib", "sdk\\lib\\i386\\ProcessHacker.lib"); + Win32.CopyIfNewer("bin\\Release64\\ProcessHacker.lib", "sdk\\lib\\amd64\\ProcessHacker.lib"); // Copy sample plugin - File.Copy("plugins\\SamplePlugin\\main.c", "sdk\\samples\\SamplePlugin\\main.c", true); - File.Copy("plugins\\SamplePlugin\\SamplePlugin.sln", "sdk\\samples\\SamplePlugin\\SamplePlugin.sln", true); - File.Copy("plugins\\SamplePlugin\\SamplePlugin.vcxproj", "sdk\\samples\\SamplePlugin\\SamplePlugin.vcxproj", true); - File.Copy("plugins\\SamplePlugin\\SamplePlugin.vcxproj.filters", "sdk\\samples\\SamplePlugin\\SamplePlugin.vcxproj.filters", true); - File.Copy("plugins\\SamplePlugin\\bin\\Release32\\SamplePlugin.dll", "sdk\\samples\\SamplePlugin\\bin\\Release32\\SamplePlugin.dll", true); + Win32.CopyIfNewer("plugins\\SamplePlugin\\main.c", "sdk\\samples\\SamplePlugin\\main.c"); + Win32.CopyIfNewer("plugins\\SamplePlugin\\SamplePlugin.sln", "sdk\\samples\\SamplePlugin\\SamplePlugin.sln"); + Win32.CopyIfNewer("plugins\\SamplePlugin\\SamplePlugin.vcxproj", "sdk\\samples\\SamplePlugin\\SamplePlugin.vcxproj"); + Win32.CopyIfNewer("plugins\\SamplePlugin\\SamplePlugin.vcxproj.filters", "sdk\\samples\\SamplePlugin\\SamplePlugin.vcxproj.filters"); + Win32.CopyIfNewer("plugins\\SamplePlugin\\bin\\Release32\\SamplePlugin.dll", "sdk\\samples\\SamplePlugin\\bin\\Release32\\SamplePlugin.dll"); } catch (Exception ex) { @@ -471,77 +458,14 @@ public static bool CopyPluginSdkHeaders() public static bool CopyVersionHeader() { - Program.PrintColorMessage("Copying Plugin SDK version header...", ConsoleColor.Cyan); - try { HeaderGen gen = new HeaderGen(); gen.Execute(); - File.Copy("ProcessHacker\\sdk\\phapppub.h", "sdk\\include\\phapppub.h", true); - File.Copy("ProcessHacker\\sdk\\phdk.h", "sdk\\include\\phdk.h", true); - File.Copy("ProcessHacker\\resource.h", "sdk\\include\\phappresource.h", true); - } - catch (Exception ex) - { - Program.PrintColorMessage("[ERROR] " + ex, ConsoleColor.Red); - return false; - } - - return true; - } - - public static bool CopyRedistFiles(BuildFlags Flags) - { - string dbghelp32RedistDll = Environment.ExpandEnvironmentVariables("%ProgramFiles(x86)%\\Windows Kits\\10\\Debuggers\\x86\\dbghelp.dll"); - string dbghelp64RedistDll = Environment.ExpandEnvironmentVariables("%ProgramFiles(x86)%\\Windows Kits\\10\\Debuggers\\x64\\dbghelp.dll"); - string symsrv32RedistDll = Environment.ExpandEnvironmentVariables("%ProgramFiles(x86)%\\Windows Kits\\10\\Debuggers\\x86\\symsrv.dll"); - string symsrv64RedistDll = Environment.ExpandEnvironmentVariables("%ProgramFiles(x86)%\\Windows Kits\\10\\Debuggers\\x64\\symsrv.dll"); - - Program.PrintColorMessage("Copying redist files...", ConsoleColor.Cyan); - - try - { - if (Flags.HasFlag(BuildFlags.BuildDebug)) - { - if (Flags.HasFlag(BuildFlags.Build32bit)) - { - if (File.Exists(dbghelp32RedistDll)) - File.Copy(dbghelp32RedistDll, "bin\\Debug32\\dbghelp.dll", true); - - if (File.Exists(symsrv32RedistDll)) - File.Copy(symsrv32RedistDll, "bin\\Debug32\\symsrv.dll", true); - } - - if (Flags.HasFlag(BuildFlags.Build64bit)) - { - if (File.Exists(dbghelp64RedistDll)) - File.Copy(dbghelp64RedistDll, "bin\\Debug64\\dbghelp.dll", true); - - if (File.Exists(symsrv64RedistDll)) - File.Copy(symsrv64RedistDll, "bin\\Debug64\\symsrv.dll", true); - } - } - else - { - if (Flags.HasFlag(BuildFlags.Build32bit)) - { - if (File.Exists(dbghelp32RedistDll)) - File.Copy(dbghelp32RedistDll, "bin\\Release32\\dbghelp.dll", true); - - if (File.Exists(symsrv32RedistDll)) - File.Copy(symsrv32RedistDll, "bin\\Release32\\symsrv.dll", true); - } - - if (Flags.HasFlag(BuildFlags.Build64bit)) - { - if (File.Exists(dbghelp64RedistDll)) - File.Copy(dbghelp64RedistDll, "bin\\Release64\\dbghelp.dll", true); - - if (File.Exists(symsrv64RedistDll)) - File.Copy(symsrv64RedistDll, "bin\\Release64\\symsrv.dll", true); - } - } + Win32.CopyIfNewer("ProcessHacker\\sdk\\phapppub.h", "sdk\\include\\phapppub.h"); + Win32.CopyIfNewer("ProcessHacker\\sdk\\phdk.h", "sdk\\include\\phdk.h"); + Win32.CopyIfNewer("ProcessHacker\\resource.h", "sdk\\include\\phappresource.h"); } catch (Exception ex) { @@ -554,8 +478,6 @@ public static bool CopyRedistFiles(BuildFlags Flags) public static bool FixupResourceHeader() { - Program.PrintColorMessage("Building Plugin SDK resource header...", ConsoleColor.Cyan); - try { string phappContent = File.ReadAllText("sdk\\include\\phappresource.h"); @@ -576,31 +498,6 @@ public static bool FixupResourceHeader() return true; } - public static bool UpdateHeaderFileVersion() - { - try - { - if (File.Exists("ProcessHacker\\include\\phapprev.h")) - File.Delete("ProcessHacker\\include\\phapprev.h"); - - File.WriteAllText("ProcessHacker\\include\\phapprev.h", -@"#ifndef PHAPPREV_H -#define PHAPPREV_H - -#define PHAPP_VERSION_REVISION " + BuildRevision + @" - -#endif // PHAPPREV_H -"); - } - catch (Exception ex) - { - Program.PrintColorMessage("[phapprev] " + ex.ToString(), ConsoleColor.Yellow); - return false; - } - - return true; - } - public static bool BuildPublicHeaderFiles() { Program.PrintColorMessage("Building public SDK headers...", ConsoleColor.Cyan); @@ -619,11 +516,9 @@ public static bool BuildPublicHeaderFiles() return true; } - public static bool BuildKphSignatureFile(bool DebugBuild) + public static bool CopyKProcessHacker(bool DebugBuild) { - string output; - - Program.PrintColorMessage("Building KPH signature...", ConsoleColor.Cyan); + Program.PrintColorMessage("Copying KPH driver...", ConsoleColor.Cyan); if (!File.Exists(CustomSignToolPath)) { @@ -659,13 +554,15 @@ public static bool BuildKphSignatureFile(bool DebugBuild) File.Create("bin\\Debug32\\ProcessHacker.sig").Dispose(); File.Create("bin\\Debug64\\ProcessHacker.sig").Dispose(); - if (!string.IsNullOrEmpty(output = Win32.ShellExecute(CustomSignToolPath, "sign -k build\\kph.key bin\\Debug32\\ProcessHacker.exe -s bin\\Debug32\\ProcessHacker.sig"))) + string output = Win32.ShellExecute(CustomSignToolPath, "sign -k build\\kph.key bin\\Debug32\\ProcessHacker.exe -s bin\\Debug32\\ProcessHacker.sig"); + if (!string.IsNullOrEmpty(output)) { Program.PrintColorMessage("[WARN] (Debug32) " + output, ConsoleColor.Yellow); return false; } - if (!string.IsNullOrEmpty(output = Win32.ShellExecute(CustomSignToolPath, "sign -k build\\kph.key bin\\Debug64\\ProcessHacker.exe -s bin\\Debug64\\ProcessHacker.sig"))) + output = Win32.ShellExecute(CustomSignToolPath, "sign -k build\\kph.key bin\\Debug64\\ProcessHacker.exe -s bin\\Debug64\\ProcessHacker.sig"); + if (!string.IsNullOrEmpty(output)) { Program.PrintColorMessage("[WARN] (Debug64) " + output, ConsoleColor.Yellow); return false; @@ -693,23 +590,56 @@ public static bool BuildKphSignatureFile(bool DebugBuild) File.Create("bin\\Release32\\ProcessHacker.sig").Dispose(); File.Create("bin\\Release64\\ProcessHacker.sig").Dispose(); - if (!string.IsNullOrEmpty(output = Win32.ShellExecute(CustomSignToolPath, "sign -k build\\kph.key bin\\Release32\\ProcessHacker.exe -s bin\\Release32\\ProcessHacker.sig"))) + string output = Win32.ShellExecute(CustomSignToolPath, "sign -k build\\kph.key bin\\Release32\\ProcessHacker.exe -s bin\\Release32\\ProcessHacker.sig"); + if (!string.IsNullOrEmpty(output)) { Program.PrintColorMessage("[ERROR] (Release32) " + output, ConsoleColor.Red); return false; } - if (!string.IsNullOrEmpty(output = Win32.ShellExecute(CustomSignToolPath, "sign -k build\\kph.key bin\\Release64\\ProcessHacker.exe -s bin\\Release64\\ProcessHacker.sig"))) + output = Win32.ShellExecute(CustomSignToolPath, "sign -k build\\kph.key bin\\Release64\\ProcessHacker.exe -s bin\\Release64\\ProcessHacker.sig"); + if (!string.IsNullOrEmpty(output)) { Program.PrintColorMessage("[ERROR] (Release64) " + output, ConsoleColor.Red); return false; } } + try + { + if (DebugBuild) + { + Win32.CopyIfNewer( + "KProcessHacker\\bin-signed\\i386\\kprocesshacker.sys", + "bin\\Debug32\\kprocesshacker.sys" + ); + Win32.CopyIfNewer( + "KProcessHacker\\bin-signed\\amd64\\kprocesshacker.sys", + "bin\\Debug64\\kprocesshacker.sys" + ); + } + else + { + Win32.CopyIfNewer( + "KProcessHacker\\bin-signed\\i386\\kprocesshacker.sys", + "bin\\Release32\\kprocesshacker.sys" + ); + Win32.CopyIfNewer( + "KProcessHacker\\bin-signed\\amd64\\kprocesshacker.sys", + "bin\\Release64\\kprocesshacker.sys" + ); + } + } + catch (Exception ex) + { + Program.PrintColorMessage("[ERROR] (kprocesshacker.sys)" + ex, ConsoleColor.Red); + return false; + } + return true; } - public static bool BuildSecureFiles() + public static bool CopyKeyFiles() { string buildKey = Environment.ExpandEnvironmentVariables("%NIGHTLY_BUILD_KEY%").Replace("%NIGHTLY_BUILD_KEY%", string.Empty); string kphKey = Environment.ExpandEnvironmentVariables("%KPH_BUILD_KEY%").Replace("%KPH_BUILD_KEY%", string.Empty); @@ -753,7 +683,7 @@ public static bool BuildSetupExe() { Program.PrintColorMessage("Building build-setup.exe...", ConsoleColor.Cyan, true, BuildFlags.BuildVerbose); - if (!BuildSolution("tools\\CustomSetupTool\\CustomSetupTool.sln", BuildFlags.Build32bit | BuildFlags.BuildVerbose)) + if (!BuildSolution("tools\\CustomSetupTool\\CustomSetupTool.sln", BuildFlags.Build32bit)) return false; try @@ -864,6 +794,8 @@ public static bool BuildSrcZip() public static bool BuildPdbZip() { + Program.PrintColorMessage("Building build-pdb.zip...", ConsoleColor.Cyan); + try { Zip.CreateCompressedPdbFromFolder(".\\", BuildOutputFolder + "\\processhacker-build-pdb.zip"); @@ -962,7 +894,7 @@ public static void WebServiceUpdateConfig() Updated = TimeStart.ToString("o"), Version = BuildVersion, FileLength = BuildSetupFileLength.ToString(), - ForumUrl = "https://wj32.org/processhacker/forums/viewtopic.php?t=2315", + ForumUrl = "https://wj32.org/processhacker/nightly.php", Setupurl = "https://ci.appveyor.com/api/projects/processhacker/processhacker2/artifacts/processhacker-" + BuildVersion + "-setup.exe", Binurl = "https://ci.appveyor.com/api/projects/processhacker/processhacker2/artifacts/processhacker-" + BuildVersion + "-bin.zip", HashSetup = BuildSetupHash, @@ -1076,11 +1008,26 @@ public static bool AppveyorUploadBuildFiles() } } + if (File.Exists(releaseFileArray[0])) + { + try + { + Win32.ShellExecute("appveyor", "UpdateBuild -Version \"1.0 -$version\" "); + } + catch (Exception ex) + { + Program.PrintColorMessage("[WebServicePushArtifact] " + ex, ConsoleColor.Red); + return false; + } + } + return true; } public static bool BuildSolution(string Solution, BuildFlags Flags) { + //string buildParams = "/p:DefineConstants=\"PH_BUILD_API=1;PHAPP_VERSION_REVISION=" + BuildRevision + "\" "; + if ((Flags & BuildFlags.Build32bit) == BuildFlags.Build32bit) { Program.PrintColorMessage("Building " + Path.GetFileNameWithoutExtension(Solution) + " (", ConsoleColor.Cyan, false, Flags); @@ -1091,7 +1038,9 @@ public static bool BuildSolution(string Solution, BuildFlags Flags) MSBuildExePath, "/m /nologo /verbosity:quiet " + "/p:Configuration=" + (Flags.HasFlag(BuildFlags.BuildDebug) ? "Debug" : "Release") + " " + - "/p:Platform=Win32" + (BuildNightly ? " /p:ExternalCompilerOptions=PH_BUILD_API" : string.Empty) + " " + Solution + "/p:Platform=Win32 " + + //buildParams + + Solution ); if (!string.IsNullOrEmpty(error32)) @@ -1111,7 +1060,9 @@ public static bool BuildSolution(string Solution, BuildFlags Flags) MSBuildExePath, "/m /nologo /verbosity:quiet " + "/p:Configuration=" + (Flags.HasFlag(BuildFlags.BuildDebug) ? "Debug" : "Release") + " " + - "/p:Platform=x64" + (BuildNightly ? " /p:ExternalCompilerOptions=PH_BUILD_API" : string.Empty) + " " + Solution + "/p:Platform=x64 " + + //buildParams + + Solution ); if (!string.IsNullOrEmpty(error64)) diff --git a/tools/CustomBuildTool/Source Files/NativeMethods.cs b/tools/CustomBuildTool/Source Files/NativeMethods.cs index 3f16de01e59d..6478cdda836d 100644 --- a/tools/CustomBuildTool/Source Files/NativeMethods.cs +++ b/tools/CustomBuildTool/Source Files/NativeMethods.cs @@ -1,5 +1,6 @@ using System; using System.Diagnostics; +using System.IO; using System.Runtime.InteropServices; namespace CustomBuildTool @@ -45,23 +46,33 @@ public static void ImageResizeFile(int size, string FileName, string OutName) } } - public const int STD_OUTPUT_HANDLE = -11; - public const int STD_INPUT_HANDLE = -10; - public const int STD_ERROR_HANDLE = -12; - public const int SW_HIDE = 0; - public const int SW_SHOW = 5; + public static void CopyIfNewer(string CurrentFile, string NewFile) + { + if (!File.Exists(CurrentFile)) + return; - static readonly IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1); + if (File.GetLastWriteTime(CurrentFile) > File.GetLastWriteTime(NewFile)) + { + File.Copy(CurrentFile, NewFile, true); + } + } - [DllImport("kernel32.dll")] - public static extern IntPtr GetStdHandle(int nStdHandle); - [DllImport("kernel32.dll")] + public const int SW_HIDE = 0; + public const int SW_SHOW = 5; + public static readonly IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1); + public static readonly IntPtr STD_OUTPUT_HANDLE = new IntPtr(-11); + public static readonly IntPtr STD_INPUT_HANDLE = new IntPtr(-10); + public static readonly IntPtr STD_ERROR_HANDLE = new IntPtr(-12); + + [DllImport("kernel32.dll", ExactSpelling = true)] + public static extern IntPtr GetStdHandle(IntPtr StdHandle); + [DllImport("kernel32.dll", ExactSpelling = true)] public static extern bool GetConsoleMode(IntPtr ConsoleHandle, out ConsoleMode Mode); - [DllImport("kernel32.dll")] + [DllImport("kernel32.dll", ExactSpelling = true)] public static extern bool SetConsoleMode(IntPtr ConsoleHandle, ConsoleMode Mode); - [DllImport("kernel32.dll")] + [DllImport("kernel32.dll", ExactSpelling = true)] public static extern IntPtr GetConsoleWindow(); - [DllImport("user32.dll")] + [DllImport("user32.dll", ExactSpelling = true)] public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow); } diff --git a/tools/CustomBuildTool/Source Files/Program.cs b/tools/CustomBuildTool/Source Files/Program.cs index dfaa12b29ea7..960cad65053f 100644 --- a/tools/CustomBuildTool/Source Files/Program.cs +++ b/tools/CustomBuildTool/Source Files/Program.cs @@ -8,6 +8,24 @@ public static class Program { public static Dictionary ProgramArgs; + private static bool BuildSdk(BuildFlags Flags) + { + PrintColorMessage("Copying Plugin SDK...", ConsoleColor.Cyan); + + if (!Build.CopyTextFiles()) + return false; + if (!Build.CopyPluginSdkHeaders()) + return false; + if (!Build.CopyVersionHeader()) + return false; + if (!Build.FixupResourceHeader()) + return false; + if (!Build.CopyLibFiles(Flags)) + return false; + + return true; + } + public static void Main(string[] args) { ProgramArgs = ParseArgs(args); @@ -32,24 +50,33 @@ public static void Main(string[] args) Build.BuildPublicHeaderFiles(); } + else if (ProgramArgs.ContainsKey("-graph")) + { + if (!Build.InitializeBuildEnvironment(true)) + return; + + Build.ShowBuildEnvironment("changelog", true, false); + + if (Win32.GetConsoleMode(Win32.GetStdHandle(Win32.STD_OUTPUT_HANDLE), out ConsoleMode mode)) + Win32.SetConsoleMode(Win32.GetStdHandle(Win32.STD_OUTPUT_HANDLE), mode | ConsoleMode.ENABLE_VIRTUAL_TERMINAL_PROCESSING); + + Console.WriteLine(Build.GetBuildLogString()); + + Build.ShowBuildStats(); + } else if (ProgramArgs.ContainsKey("-sign")) { - Build.BuildKphSignatureFile(false); + Build.CopyKProcessHacker(false); } else if (ProgramArgs.ContainsKey("-sdk")) { if (!Build.InitializeBuildEnvironment(false)) return; - if (!Build.CopyPluginSdkHeaders()) - return; - if (!Build.CopyVersionHeader()) - return; - if (!Build.FixupResourceHeader()) - return; - - if (!Build.CopyLibFiles(BuildFlags.Build32bit | BuildFlags.Build64bit | BuildFlags.BuildVerbose)) - return; + BuildSdk( + BuildFlags.Build32bit | BuildFlags.Build64bit | + BuildFlags.BuildDebug | BuildFlags.BuildVerbose + ); Build.ShowBuildStats(); } @@ -59,18 +86,14 @@ public static void Main(string[] args) return; if (!Build.BuildSolution("ProcessHacker.sln", - BuildFlags.Build32bit | BuildFlags.Build64bit | BuildFlags.BuildVerbose)) + BuildFlags.Build32bit | BuildFlags.Build64bit | + BuildFlags.BuildVerbose + )) + { return; + } - if (!Build.CopyPluginSdkHeaders()) - return; - if (!Build.CopyVersionHeader()) - return; - if (!Build.FixupResourceHeader()) - return; - if (!Build.CopyLibFiles( - BuildFlags.Build32bit | BuildFlags.Build64bit | BuildFlags.BuildVerbose)) - return; + BuildSdk(BuildFlags.Build32bit | BuildFlags.Build64bit | BuildFlags.BuildVerbose); Build.ShowBuildStats(); } @@ -79,29 +102,17 @@ public static void Main(string[] args) if (!Build.InitializeBuildEnvironment(false)) return; - Build.ShowBuildEnvironment("bin", false); - Build.BuildSecureFiles(); - Build.UpdateHeaderFileVersion(); + Build.ShowBuildEnvironment("bin", false, true); + Build.CopyKeyFiles(); if (!Build.BuildSolution("ProcessHacker.sln", BuildFlags.Build32bit | BuildFlags.Build64bit | BuildFlags.BuildVerbose)) return; - if (!Build.BuildKphSignatureFile(false)) - return; - if (!Build.CopyTextFiles()) - return; if (!Build.CopyKProcessHacker(false)) return; - if (!Build.CopyPluginSdkHeaders()) - return; - if (!Build.CopyVersionHeader()) - return; - if (!Build.FixupResourceHeader()) - return; - if (!Build.CopyLibFiles( - BuildFlags.Build32bit | BuildFlags.Build64bit | BuildFlags.BuildVerbose)) + if (!BuildSdk(BuildFlags.Build32bit | BuildFlags.Build64bit | BuildFlags.BuildVerbose)) return; if (!Build.BuildSolution("plugins\\Plugins.sln", @@ -121,118 +132,56 @@ public static void Main(string[] args) if (!Build.InitializeBuildEnvironment(true)) return; - Build.ShowBuildEnvironment("debug", true); - Build.BuildSecureFiles(); + Build.ShowBuildEnvironment("debug", true, true); + Build.CopyKeyFiles(); if (!Build.BuildSolution("ProcessHacker.sln", BuildFlags.Build32bit | BuildFlags.Build64bit | BuildFlags.BuildDebug | BuildFlags.BuildVerbose)) return; - if (!Build.BuildKphSignatureFile(true)) - return; - if (!Build.CopyTextFiles()) - return; if (!Build.CopyKProcessHacker(true)) return; - if (!Build.CopyPluginSdkHeaders()) - return; - if (!Build.CopyVersionHeader()) - return; - if (!Build.FixupResourceHeader()) - return; - if (!Build.CopyLibFiles( + + if (!BuildSdk( BuildFlags.Build32bit | BuildFlags.Build64bit | - BuildFlags.BuildDebug | BuildFlags.BuildVerbose)) + BuildFlags.BuildDebug | BuildFlags.BuildVerbose + )) + { return; + } if (!Build.BuildSolution("plugins\\Plugins.sln", BuildFlags.Build32bit | BuildFlags.Build64bit | - BuildFlags.BuildDebug | BuildFlags.BuildVerbose)) + BuildFlags.BuildDebug | BuildFlags.BuildVerbose + )) + { return; + } if (!Build.CopyWow64Files(BuildFlags.BuildDebug)) return; Build.ShowBuildStats(); } - else if (ProgramArgs.ContainsKey("-release")) - { - if (!Build.InitializeBuildEnvironment(true)) - return; - - Build.ShowBuildEnvironment("release", true); - Build.BuildSecureFiles(); - Build.UpdateHeaderFileVersion(); - - if (!Build.BuildSolution("ProcessHacker.sln", - BuildFlags.Build32bit | BuildFlags.Build64bit | BuildFlags.BuildVerbose)) - return; - - if (!Build.BuildKphSignatureFile(false)) - return; - if (!Build.CopyTextFiles()) - return; - if (!Build.CopyKProcessHacker(false)) - return; - if (!Build.CopyPluginSdkHeaders()) - return; - if (!Build.CopyVersionHeader()) - return; - if (!Build.FixupResourceHeader()) - return; - if (!Build.CopyLibFiles( - BuildFlags.Build32bit | BuildFlags.Build64bit | BuildFlags.BuildVerbose)) - return; - - if (!Build.BuildSolution("plugins\\Plugins.sln", - BuildFlags.Build32bit | BuildFlags.Build64bit | BuildFlags.BuildVerbose)) - return; - - if (!Build.CopyWow64Files(BuildFlags.None)) - return; - - if (!Build.BuildBinZip()) - return; - if (!Build.BuildSetupExe()) - return; - Build.BuildPdbZip(); - Build.BuildSdkZip(); - Build.BuildSrcZip(); - - Build.ShowBuildStats(); - } else if (ProgramArgs.ContainsKey("-appveyor")) { if (!Build.InitializeBuildEnvironment(true)) return; - Build.ShowBuildEnvironment("nightly", true); - Build.BuildSecureFiles(); - Build.UpdateHeaderFileVersion(); + Build.ShowBuildEnvironment("nightly", true, true); + Build.CopyKeyFiles(); if (!Build.BuildSolution("ProcessHacker.sln", BuildFlags.Build32bit | BuildFlags.Build64bit | BuildFlags.BuildVerbose)) return; - if (!Build.BuildKphSignatureFile(false)) - return; - if (!Build.CopyTextFiles()) - return; if (!Build.CopyKProcessHacker(false)) return; - if (!Build.CopyPluginSdkHeaders()) - return; - if (!Build.CopyVersionHeader()) - return; - if (!Build.FixupResourceHeader()) - return; - if (!Build.CopyLibFiles( - BuildFlags.Build32bit | BuildFlags.Build64bit | BuildFlags.BuildVerbose)) + if (!BuildSdk(BuildFlags.Build32bit | BuildFlags.Build64bit | BuildFlags.BuildVerbose)) return; - if (!Build.BuildSolution("plugins\\Plugins.sln", - BuildFlags.Build32bit | BuildFlags.Build64bit | BuildFlags.BuildVerbose)) + if (!Build.BuildSolution("plugins\\Plugins.sln", BuildFlags.Build32bit | BuildFlags.Build64bit | BuildFlags.BuildVerbose)) return; if (!Build.CopyWow64Files(BuildFlags.None)) @@ -255,22 +204,13 @@ public static void Main(string[] args) if (!Build.InitializeBuildEnvironment(true)) return; - Build.ShowBuildEnvironment("appx", true); - Build.BuildSecureFiles(); - Build.UpdateHeaderFileVersion(); + Build.ShowBuildEnvironment("appx", true, true); + Build.CopyKeyFiles(); if (!Build.BuildSolution("ProcessHacker.sln", BuildFlags.Build32bit | BuildFlags.Build64bit | BuildFlags.BuildVerbose)) return; - if (!Build.CopyTextFiles()) - return; - if (!Build.CopyPluginSdkHeaders()) - return; - if (!Build.CopyVersionHeader()) - return; - if (!Build.FixupResourceHeader()) - return; - if (!Build.CopyLibFiles(BuildFlags.Build32bit | BuildFlags.Build64bit | BuildFlags.BuildVerbose)) + if (!BuildSdk(BuildFlags.Build32bit | BuildFlags.Build64bit | BuildFlags.BuildVerbose)) return; if (!Build.BuildSolution("plugins\\Plugins.sln", BuildFlags.Build32bit | BuildFlags.Build64bit | BuildFlags.BuildVerbose)) @@ -291,7 +231,7 @@ public static void Main(string[] args) if (!Build.InitializeBuildEnvironment(false)) return; - Build.ShowBuildEnvironment("appxcert", true); + Build.ShowBuildEnvironment("appxcert", true, true); Build.BuildAppxSignature(); @@ -299,7 +239,38 @@ public static void Main(string[] args) } else { - Console.WriteLine("Invalid arguments.\n"); + if (!Build.InitializeBuildEnvironment(true)) + return; + + Build.ShowBuildEnvironment("release", true, true); + Build.CopyKeyFiles(); + + if (!Build.BuildSolution("ProcessHacker.sln", + BuildFlags.Build32bit | BuildFlags.Build64bit | BuildFlags.BuildVerbose)) + return; + + if (!Build.CopyKProcessHacker(false)) + return; + + if (!BuildSdk(BuildFlags.Build32bit | BuildFlags.Build64bit | BuildFlags.BuildVerbose)) + return; + + if (!Build.BuildSolution("plugins\\Plugins.sln", + BuildFlags.Build32bit | BuildFlags.Build64bit | BuildFlags.BuildVerbose)) + return; + + if (!Build.CopyWow64Files(BuildFlags.None)) + return; + + if (!Build.BuildBinZip()) + return; + if (!Build.BuildSetupExe()) + return; + Build.BuildPdbZip(); + Build.BuildSdkZip(); + Build.BuildSrcZip(); + + Build.ShowBuildStats(); } } @@ -369,6 +340,8 @@ private static bool Restart(string Arguments) } catch (Exception) { } + Environment.Exit(Environment.ExitCode); + return true; } } diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe b/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe index 3ee36479e5975a4aa2752484c2f7ebc0eea2e8a4..bf9224ba705bdcae546ae48bdc28a10b30dc3005 100644 GIT binary patch delta 21275 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 diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb b/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb index 09ff85a2e3d99f1d62ce3fc84e1fe604264cdf55..c9b211b16d3120a19e8d603bc851328efeb954d4 100644 GIT binary patch literal 73216 zcmeI534oPV`TyUG!wAYKyMTxT0)oP@4Vxkk%&;loAfTuy%yMC_%;ww~7Dc-#?i-rs z5*DT=mYEh7ZiS|Xg^G!VMP+4$g{ejTtW5u(?^*7B?{H@T!Qbz1a^RWoJ?A{nS)Q{m z@B2=RmDSb6YZlb!77i*r{`lN!GbiSb%o{v7=a6niGXqQu^FO$epKJLobFGB~fBy?K zu;HTv=CiDUQH|^HyPsukeD?Bw=#Pd(OdV)TMG#^71Rs5r1%C9=LB@XI&wsB5GL?Vd z1LgnUTi}gyc1zxn$iqMCepUqcZw!rpVPMJd!h1WP@lv}JPkz|5%1;zF+hz=F>=gDs z@cUDuflTdRqhPrImtEOujGvM$9!O?08aPn?%_!$H;Prm#jFX=~_||Jmo3`)2ied)T(x z@7{9rp-0U6)GOyRkb(VG{_`GvX3~cr=00=I@BVf05AvqHGIr%b^F9OW`_yM~f0h5R z8?L?d@qc%Xy?nwIhfTWgGLubj_72KHC^-!b-w+uL0H>tCN4Z~4&MFRc3a zgWtY&$!9=)pZYBBukt^B$C6(qB40oFC-*FxKH!fXHeSDNY{jQuIiGeu}fWzsf&a_T-&6TypmE?i1z~?8rM};kSAm zf`!R7LCU%O3D^R>xRy)uc@hw&n;|-*Vj~yZ-`Zv&%$ADaa~Pqw5~oDjn6$j z8n0=nLnN;#8jmfkj@IRs#e<-HcR`k!AWIdb;!wOk$hu^Z<)I+=I*~I?x^gGRDoN(q zv09~Tuajjnm%G3Oa-j`m-%@f$EZ$I3IkUc@JXW*sNm^_|izh?d$FxQ3Vhfh-hg2oQ z*|+pi&lc8|RPB3$s9ipweM`~w*uskX%Kf0C>Qq4cn4*&U*y8B4XnjRZd3@hBRc(T+ zN(HxXsXHZJQ@!trI^Tt|Z)uqvEh&%IO^WV^1XY-z7TTcpEmfvh-FFq4o>al~qeCCb z1+E?(<(KO?KZBXe8vVXKT&KTGSPAHBg!Ol5FvG?r&{qlf&yB(^U^Ll;pKcI$B>XEi zx;Ud_A&oeH!M&4rJb?d48aVQ|gClJyi9c@}^u@DZ{z*h7vp41tn6=QC+?bmWHlnH( zs(lK3%Kd#$oXc<37S#s%MGcqzqZ;aYYj2FzidQv5yz&e4s^)m!&Hc{5O}vU%yz&e4 zs>XZXo7^&@7j6E@5HNGE?)VCc~zS|Z|Tbm7m7Dr)5E-~^`7^_ zg2OKsuUdw}m0y@wt;_TFExrD5@v60nSAJn$wOG%)Vc?>N#H*GpUipQ2)iOPA&xLEh zC|BtXmN9@(SjVpm)33Gnd8dqgBCSso!~1P79Dp`sGcJ*5^&Gudh{H zVfUHQvWB`?{W7@^4e@*Tyu!L=we_0R)mALan=^dy=t3<>7R1U*>Z9=>XdjZ96umx&R9wj#yhVI~ZA<1<{P8gPpE=`wN zg=bfI3PJHohGv~nMsW=dva(({`A^S(`>dZ%d9qLI7EgSA-F(QJw$eh6`d%lZ5D6EW@R5#S_QjqW}pPS)(5&_A3nZ8axI4AW}W`oh< zYFu4ii76+^tDjs6zcvk;uJf9K*3CPnLwex}weoLOHNt6msN9`JC%i#IWv&RNy)|i{ocNt@mNi@)wI>~oA|FmR&t(K`Od|y0#aX?a<^?1H6-=S_CQisl35L@ezgL9 zo`qqVea*A4Ut6_6!%Vke{vJx6`?$D+iLs>(wSM!~=i26bD?IliFIms8e0RaE5*ie8 z_hS*NO6I$^qNKLAu%^0R6GV*qS1-Q?dFkMcMmh+~?=Kx}Cc`pgEttQ|2eRW{2WHGI zZYZscm01m>`iX6%b2ajk_58|1cihS$%_~-f@}R)OFKWU*Cfq zrG~On!*>R!>_>dQ)u*4z-l{hGC!39aQ$AZr<0djDInS#+x5aHP^c%wZj|;=knXx9z zy{4hQwt*7&PEA*-SN=~>txsAxFo=DN+*BGemgyr_Np7=4a%VCNr2;Q?` z{^FEnoLS-geFn?JyW#5pV_VPs>49Qbz+)Dc9A}1NoC-=6v z&4HBm@BS~OeX16Bn4eoPf2mN}Thh`#K2{w{`z@re3v!b2d`kN!+&ki~wBJPjd|OhW zjPJ>My1(j7feUfHB5`&GDafvRzT-O2lYhpsA_ z_Qw5=QTpk!$eA_q($qL1ne~wJ+zk$2Uc#`xH>C9;9%xK->SXtCY%=~FV zY@yM01?k;Fp-9&A`*{~#0wGvq#+u@qc)i=S5Rbyn$kR|)DJj4H&&V^bHm1Qx<+_$M ztR@Y$$Q;gZg{!uxu_r8BRv9z1KFJJ#|90p+cse;5jdQHS(_|{x|C?13Uxc%nJNWs7 z;@ph9>ct8tuQ7vuD@}f1>xJJto23mX%obB1_BT%1UvzN?<7#UcN0-&q&91GiDJeIj zUwBT?hBD4YK=NM3mlNGrdO1nZ?VS0&nlMjYlnu6cG{j}csAA&iLd7|m+${h)U1;O_|kQP^jN_*HIU{;&>Jc8Vu~+^O(g6q1wf!*V{J?(i;$j>iAa5Px5TELg!fHIYsc24(dVD_LmGdkc)C+IlA9iqV?NoW+{bC}eoi^H z3jt$Bh3XPc*)=Y1HxAZRHq^7~v}HSo^mTzrGM-Omu?qKX(9MLm)XDpCkS;b^ucCEz zHFd*=CgqvN#>wwOb6h8;uMQ%iXvh97GeEaca>5)W&c~_0x8QO35{Vsl+ZyM6l zViq1H3)Qch`bIj7kd>V0^?77CPtPMVzHbZr>H3kbCovfsz$b13% zkPg(|G#3cVvSM92t)x1(Ae!txO&n?`VZK_M>S-mlC>rDYvoOyBns$6v&A9S%o3}Sf z!xqx;5d5258hk$%mh)|?0^ZHgt?+Mg{EA0yDa@~UOh$26pXo{ZRK7Q}Pm2WBvM(I)83G+10_crpdi8Oo*zH9ldG$`M!Rnp{qzURZc5xN8a z&pUp_!<;RRe|PzALp^#1nTH5VaViYv5ouwRHdL2aMkz+z{dgmt6(CF0!Ns6YFXLO9 zY`AaPm$tHAoe^fBB65Z#XW!=HPPLWPEJS6y9RHQbO3w58afXJHY%5hIi=sLe^XG;{HcV$oish+(xSGgHWQX@JnxoV0y!YK5A^y|R}hxlSN-`p z)piYPn8z%bzr>yWtc%;9b*Z;WY0$RGC*fI#yktGUbo&AB%W=OwK^c9vV!yayJPI3iCrH%o&o9 zeX)x>$SW%&TOVtl`&Yu-=<0EVoXmH>d*lA3`@Nj%p|*c9$WR|#0xC(L0|$Z${*M7y zfSPw)3RZwufN}6I?|hhO0I$JLSiyDR=fNAnFM+GTHQ-g?qac2X?}E30>%lL8o50(^ zSHU~MUxTZ`x52x>cfd8^zrnA7tx5Ym;Gy7G!Nb6{U^nn|+9_=_ZForyNUCcMXeLhqN?b&Vw z8EXhOpu0Eb_a^-HCeOuq*mKrM^1N2sbp)TYE($zFbbxA0?0J;JygNB>> zk;CnScBbA8!%e)Zf2TtWp`PfqFJc$Ena-p~ zdhJ40I}hw`(sv^93`>Tw3U_-}8ZqalShepNtke%oFJuk}j{()M^aj@=kmi%qm~9pDo1UT`V+ zFt`kS0=x)){0RIU_&P`*b=h{1dViVP&~@c3Zk)c@e~U`Oy4FejKx zzNM=IbTt{A0?q*I93{X6Jks5G{7wN+1!sasrcrace1rJxnQbI__NzLfJp&oqYN8dW zzEgEucIoyWkR?=bA9$4W@9F%H1;2*-VCO#6+0`F?9rxMJ{T%0B3OX_oGcJ>DF z8@S)>+;4a8Yrt>f&iEF53;Z6q4tx=O6r}$Sz5~)H2Hypx>&HO)p5Sq?3&7x=0!Dqqc;B(*#a3e@L2QPrfQ(iLNf@9JDFv{XY zWA7In7xbs!vVI!d&NjdMGJf`F+)KGjBU%skqg>UO&4H>Qjinbt%R~0_`F#m=1@r~z zOQAkt*EX}7aP8S}Bzf+9C~oS*WL_ry+2Cfd4fqrANRU0g#Bm_?Au$?!4OFgv3aSs= z3KoN}gR{VG;2GdA!FJ3*+nIj31Uw5WX*P{Yi#^|sB+rS%{ps%rQ)&J^sQ&AZU~lj( za1i)sP;=fLpz7RTKr{A%r(pjpI2HUGXwx&6vN#7iquF$=M8=-EM(DY$(OPq<`~5$J zr#A6#up{^Z*bV#-*d6>3R2yNkolt2-g zPa=%%xXZLAET!d8P-(~k`+lu0z4Y5 z2YZ5-g1tcLr4Oib>kHlq9t(aI><2y!9tVCOJRW=r90>jj%me=b4hH`P4go&^^T9T> zr{Ulc;7IUza1_XR7@P!-22Tbjfd$|cun^SzV*;plI}ud7odVLI2d9Aa&%vqSmEctH zCU82q20RUJG^3Qv07*Z6MFwj;^2@h*fl0C$;{=tgz^axfpf z0-O$B1!~N>8q~bzT5ukCJ*e^i2CxQP1ug+^1}_Ic4_*o03f>6b25P=@JE-}N#;P^o zUD#FEzXWaozYJ~$*ML6(?*?B5?*ab^-V5#k?+5<^t_5>gMdkzv=w?WB*>Jf^4_Z5& z=X9dE@44nT;-JcL7IZdzeqMN{@ej`n*THMg!0C`Ah{=K0nqQ2;q(gnjL!kQpZ-Rbo z?}7c>*rnHX;AHSS)ZG&BaqMN_6JR;`6sW%Od*E{LY48&888C-lQ|n2Ut&GOFPG+1t zB9!)B$1jCv&%h(pHfve|mG1ZRgsrsy2-N)J$6$YO6R3XgC2%bGGB_Um30MTa3g!gT zRZX+;zYDKD$Brb=!Q12ZCM5GS!cqLc0DFVmz)|3@K*jTG@HFrZP^0{Bzy;v%K+SXB z1XqH809D7fgAamlflq*c0-pl^41N!M8&uu;3;0v;J#Z`dSJ39?4D_nC!BB8i2*>hU zRN-)Jv-wv3>=}5(oQGpYj&WZ9Nb>yq2;_5dm&qd>#Xl764GsfU$A*K`!4aU^1J5fZE(J${YrxT6wqOCMF?Sp|5*!bn4iRCkcXrKhW!Jut>S+O_xv%PIF;vxTnW^ux=j4&(`FR`MRA*#nkOt{& zCaC&38&v%~15}xv1!_)q4ydx43#xya2hIgc!1KXUP`ZsC6kMjU;C$>k%pKFm;e66t z4yo^+4XTZ)@9qF~HTyZYqZfN-9x>tg13X;Bi)({d>_0Ud>Xt5 zRKIs0_yg?U1b+yA7u*Ow2EG734*nQ?3ETv#AD6t!PxuD-3aIi^cxtn+V%J#oGf?HZ z75oT%9gLvIUx1y#ZD0>j^1U6ZP5%Zv`$;Ce!Qk((p9uaQoC&@Ks*V2%R2%;@SPQ-l zUJm{RyarS_s~p}2{tf%x;QxS+fbWCf2LB1NCJ+7%{s{a4WUa~KCrG>kMnLVQTGG6y z2PLH0hsK!^l$rKGIz#>Wy#VTq%Sp7bQ6av3+)v$wZxrkAqX;7$p6WzbcKlLdE=&tk z?YR^FswZ|Ix(vInZrWYSQHyUYp1r8W5&Q2kT^*asX34h9QB^`}MP z+2BNQ5jY9d+;B3u3Oogr4yJ)>Pt(DN!PCH}!D4U|I1~ICI15y}m<_%Io&o+FJQF+^ z9n1kcfM|pnP3830ImR8(*>7;tV@EG;7#D=AnS$T3h?XTmEd~t zD)2e*YLGc<(%! zc@(%5>;Ya19u3|A=7O4A^aSq&dx07kdV?y1KA_e>{Xos@`-APwntBL3LE~}J9`pe6 zzKr@m3F;pVX6?--4F>!Mp+GLQ|n~=sM_L=vinRL^0`H&Wyck z2b!;}gw{aop{>xn5PO@!07(6EImAAY_GE&M&>K+JL6ikF3Mz&)rmck5KIO_l-=m^2NbLS`)X z`Txz%M{_D~zRtanxARTWQxFql)#c&$R!ymn*YlupbZqIoc|+!@-_t!9g{gL=aJ+1D z?*RxuqdzrPeF0*D?#JxyGw@UyBllOZH)P|Em~>!O^<{lx4f_T3$5#fv4GfkiM(trf z^<>p&q^_u}{Jo%6QUK;)3+6B7n0*}!U89~nb1f)Y#&aC6_Yarx-j?4%HU?9E{$AG{ zS0)2P>0z##{du3Bh0*$X{?SD)ZE}lLL#avMEnsitCF}WBH@9HV#XT3i(}mM5$Td}- zHAAxM^S+8&SWJ49m%X{)C!I;g-vNHs9;4?n$@SD$4$n~mOt}2e#@xNk1@X(!{L{%*po^i8ypW(55${j$NaTZ@Eu6!!oAHt zlH#-F7NLZ#QSthIWt5TYXLyxntM|-lJ`rApL0X8bznOpfzRT(`^F5_$hJR+V?^66S z{h+l3sAt=^K<`6s$=m>_2$~P+nep2pZ=?%fo(0Y^G3@13ZvjMhg@+ZyV|o^=^yuST{*Say0z@;wb+Zbt^WYmn;} zmUEY*!)eu;R3@C)Ymw_2mUGX7i%+s%PZb$tnJZ=Y3(FS8;>%wMxdgyq#QRxVDv7w-F`-WmFc8<9ULEI*-|R}NV5aNaea zlL_l>6|zNPSsp1aZz!t|-%0mz`#vKqe-rYjhUNXVVoG_M-rmR%_sz(jzKd*SWf9M8 zDV<8YAKx^ml-X#({QW%gXLW?{Dt-;pshcsXWOs4H!V<8tyT8Q;Iy zHl6C1RHb|$Hk8W!cq^QxfQ z!9s8ZNTp7U2V>xA;Q1hWVYi4qEU*%60IR?iU^Pg;$IZGRq4`=ITn*NP_ki#wSbuPG zW%oXof{$Te20jj61U?5c?j(K)UIw;i9iGEJbq@PbIgG59e0F8!p z<}n7EgunKLv=5zcerqnVlki(Xex0BO{4kx^W@tOq3eQ|<6jTgVKnZ9yv<}(=?SR^} zroBT&&|GLabPKc&+63)@vJQa<8UqzWpQOnma6gt_<;q)S=nZ{PcJID!{O7?``}()k zI#2rm;`cn^H9(KhyVnY9Dl2)fG|#xj^Cm@kJ9MlJEvMf9ruV^RS_k$G@todJT~8O7 z=aa!3YI&)w-YlCg>)-R%EhIauqK;R!@(Qm!Jz*L*eXR0GpO@^j<34*-NcHuj@SjTl z=;nibrvu-gr^(e5HkI1<%X_fdgiY1@pHL<*>k)Ls8VLfTn2Esx!c1 zMekI;KYW!gd& zv|nA|y&YQj3Abev>0bU(QvGw!^smOC&!oAVA{d_U+W#2;t{C&yW43Cdaqaw!o;PH# z)^%TUW$x$G+g)sG2i|-Io>P+X@>p6~L%rQ*8cb|^w~lNapWjyq7YE}__KYUtV>!D| z`P-<5g9+#FUgA5aiTH5dr}#$Ec4flx-A8<-O~f}G-o06udwpu|K>H1B{m8sl)fj#% zcc?wDEz`_%l3U@;4b3HOc|>Tn)<})?yT*Lg@D56bYjv49+_mtI4hoXIRu7qZAAt8{ zZo2Ix7KUr{9$-b-586aR-iO*A%9sF6hAJQ(#IAwXLtCLwlTrKkTBIgRUu@cq!m>GK_y)B2FteVBQO zHlojYS ztoJNcOiWnsm%-DCgDsNC1Uj0g_f@2MGleI9&m%oNi~AgXvVMOhEXxONlKU%R_cHfpBgB*ScVFtU#yizH+b2d$|ERD@ zVsf6zP+{h=?9Z6zRdT@N@IMUH+C%f*9G<1rvyXPos)XB8yV z5m}A@oj}5)thhe|YHoZC$UNS})eRhgU2|Kl;r$$1c#5+tADR<)WbNFM7SWOUbjM%? zg*b%tDD-sW=h;f5ZHt-HsCl*0mA$=8L7fuIR6_A#b(Ub0iYkxt{kU6)+fX5TLt~&>P$jeyS`F=QL$gWF|J%59q*BSV6}0`|G66PTP0atb zK2{r4SX&^;dzt3u0-4tPyW2BRpGfeUk0tvM4yB_@Pg^jpq>fKj;b+H@J=hzCS8Fu& z%}TrE)NUt3HvN%giOFAUYncluTiTJ?x1wE`eJkBZX~4a!d0un~t@JqB*z#TGk*Ztk zD93G|Kv@#>UK{1h@BgUmWX4)Bf0tAKF_dk}-@fOud=Wmryw%3V?|H)Iy}Pmu`zPmu z#k^;|ELK}m`SHq;A=H$k-}BeLhz$33ljdUbbidEjw31jgKFZHlP-{c+dVjgM!fh6$ z{;+$0s|!Dtbr03UeR=1(^cp5D0`qg3uwO~t!s2MPHpy(5+B?!*@ND>Ra`9?RRh9AK+b==iY?p&F9GT|0MHF-Kb|Lv8HYsZ>%*hjrut8`TDMN92wPTZxY0Jq?`8! zoT1g1)ERxL9_%E231r0YdHh_mM@Yx9a$bGszFFb*9QLnGRdH8W_n@z$EZPvS*O~gM zwUBLhspn(Gvl^1od_v=@<`EkE>FZ3tMP)Gi_wB)4+&h5Bf*nDsx0y58KHWagt2u+# zcdWe=V?fOra<~hcLoaOa^y!Y9p0^m_P|wVT?e(Z^8lqwtMMjYmD^vU4kxQ_$B4-#i$14x{SSHKCN z`jUy@>)<5tPv8_#8|0UvJEqD=l0k|BD zgL?LW29US{Tnzs$;8N_jf)|2!ffs>a0?}RKK9GJY@l`Ove?6130(=m>6nqL?2|fp2 z4n7ZF3H}7U3fu~!^Gp8#UXT5c;Emur;41K4@MiSzPmsEk_!oF5_Es&pYmHsc1b+q8 z!RkF=d+XbJuT%mKH7JSV94cPBc5Z-Cvv-+)JgzXbK3@LW&8K}h1KAkR6_4<1jyr?bQU^qYDH{3M6!1NB~ke)u28 z+1APY)_V`cGuXN5xjWCV=eeu!zrpaO)8d_KR8!@mF-pH7vT-j$_rec2W9TjQMN zNrk_=d^Dw3pN~F->8W4xtcp7B=5vwcT(ARf??N(1PzN<;vhPS;WNZf8fm(-(PxdZg zcko!S2RH=e8N|d`uqQYU>;)ErJR4x1S2z|t4SPRu2FSRRml;8@t}0GXT5Xj^}r0P|uf*G%`ms3-Hfw zF2%*p0V7CS(+XhxGKR4)k1?y0hq%Mm3`K6 zpouS4w!M;Nuo_-F--{&YiqbjbkugPtqxdJ7@EGsGZrCS--N949e&F;-aQWFFYY8(S z;k_AVJ|dil`>v zmn@jSSD@FCE**S>CG)j-0rER&zIotGx~S-U{yvZ>TeuBkWm< zbQI?Ed7Mz)P!)xdS3OdrtS&O~#gSKh%0@>2iP3uYPs^1ErFRVxzE679K1y63{kkzt z-tia1tF_gI*khrxX^B0JKU6lVFKTmPe->-z(x38ja3eqW-dbfPS+0A#UR7I=4D%Gt z0bN~>B-;zkDfvzhnxE;H4+lHoP9d#48ax8K`eFJbv(}=YNSuiMNN^H(6gUO!37!U$ zzr^WaA5eWmUr>7L59TmKRzGW>!5U2;+LPaBfO>xaC`j*w>5KhrdI>#`YWI%cMc&q< zNU~10$L&o>h9WR&9}LQU2-p>*?QnO_u9wuu&=$@9>>3M(f@83s1VV|)AmfY~ z8w$|D1K1~Ge-M=1w;VnWo`U^(a4NV7oDSM|OiU%8>g(o0$C`Yk-uP9~M zGlHCeCNw7#zvgGDKGNUcQd`|lfweh|J`$P=eHM-SZh!u})hVDVq=@^e^Rax_|BngX z!=Rwm)+K*0BpJ`=`*P}NvTx$^iB(l}5t5;P1ZyDGk(*rD>L1ikg=NaItG(@QJN=St zr#@ed&&JU9l4dPDKh2acD)rv%DfzhmO33petAmKqhayuSHA_D*U!*?MF9dgiYCl@9 zvc{J#%sk*LU=%z0Oms5O9(<9SdySbB9Yt%mYeG*3(6n-Tb|UEcB!UFe+sHpHN+2XD+qVllt=4xq)On zUvp!B_)gxG)AIBzKplH|=H2(p?E2FDm(7waN@NIDE(A-H$4a;2^ ztJS>DAFG=3eFItDN2Hzy8=b7$_d$(hOX|uhxS3&O^e&GCbPYV4os1vChx@NDz;gk8m2?y|);(WToLE;=<%++MYvZJZVM(esuO!!2HTOn4%sEh9O7hmR|Y&c9$W>L zA=BQ;e3E7GSK`?K^)ziRV)|sPtQhTlRljp+nwlHqreVOG3A6(tGso)y9*?~vcske# zJOgB$F>6%KTT8HOuBUv_x0-kO$vuu;xC}fBwC@wr`^0^D=xCG1{@&i6;7 zv-6>I=|?ovm+tiL4DB1mi04GKFamyQ-5P&SLUUc)*QDkRtQ$;OinGYXWzQ9qSJnw8 zukohQ&SJn|`O(A!!DTFH18Q>gHc`J2T2~zHRkhkXZr1G_2dd71}?^F(^h{gefq6Z^f2`QlgT16 ze*UL^dh9j+ePX z_HVtc;%)RSrjPesCmW9Ud}QD9vWm9}S@trG3CBx4%6`wwDqhWqrrHT-IKLH6HXJW) zC;NRbt9YA`y*ER=)YEKrTE@%7TT|CiHQRigEgbI~8RDfbXCLfkO}v?9H7}D1=eGvg z!@aEHovBSE`%$=XymOpvIKQ>XcJ{K0w~?$rXV)25<9IJXwuhHhynMz|u_{h4w=qMU zb;$Mca*8t~=j(*duo}n5*pxlc%PBtHV>Ibaug3*Wwv`RS{H;ee-^(h_CS-XBpfO?n zHXu93%lddpvlzqr)w8BD;dmD#Tj*tdydhbyr*|{Ny9C)&y{zKpqgV<*tlxfW{Frc@ zwBzj4y`16<$$9;jJGpQ^8S}Hx_Hv3Zc|#*TpKCJ2N&lT);$;%>X+IF8gT=9m(we37} zxRgmEm(ullvu!(bxZ({zyKCEX=5U!=CXQjR(1&Z=Z{~2t+mEv-&uiOj=5U##q}4Oq zJ~M|a-f(@e?J;w>J>fly8KO^vZG)M^6>qpKY`e=GF6Ek*Ufa$xhbvyC*UxEq$FVVM z_`8ux_$KrLr0)w4hV*^na!7}4w?pfp&Ct70D<*rrp)t@Ls1~{ox)<62ZH0D1ZQ3(O zf(oFyP(8E?S_?f3ZG+y2+Oja|2NghbpjzlU=w4_8bijN(4P+ta?@DfQL7b(|(i!S- zc2TaImxSJrAi33$c)fpf`+niQJ^zlU@cqwB&j;JFYVXe8lrG8nGtEsdFXM3chSgd2 zT|Hf%POB@A)=f4KG-|pQhe>;JTfy6rm7M4G``T1DYOXbYzfpd$2VuYRn(C;y6kbO> zb$3dF-|A`O)?R>y?yyV+cBNmmH+x|!r*OWtk0^7x1@ku-o?p4RgC_F5nKWvyCppin z^tZuH&o3$cABNHoyY>o_`q*FT_j`GL6@fEEn?1OfE4N)AMKyZXTvPjZlJmU2+!&XV z>1xE#mlT|vi8_AX;v}hU` z!Cn5Et2IuK^G?>ceW`bTE;>dD!Q6~qydjy{XB^|o%^e}hPx{kdUn^w9?|GyP>z~ql zV_oPxT2+I+gJhZ3s3}Lw(;Bndn359ai!(V^+{=l(9Hqa4|F>QG{Qg{+Uv*miylXR< z5C2B&Pda|-R^=AvujS5g%)II#)s}sHx5LcdSny)+R3Ff)k-Tq1UM36utbk`!pOnlY z8Dzx2T8V*QO1aVTt3EO}O-rM%kG{Yx4llze|1=24#1Za;2b{)+5Us3=!@j+n6xt64*^wl_v| zP?Br*J*8vK9lL{&c}DlKqO{VpOL#XkX5nN9*3Kg|9X?c3N@zb50}*V%_Sf6`*k*mF41*Za1Q zX09jGnRMwLuHES=Wc(iNYJS@>Ad(zM4#jPim@uaihtgIIsy;GinEL{=K!v0|w_H&6 ze&B3SX^~y!E&o%%GqKMA=YTq|xA(Dnk-ibQW=dc0q`q`F#`g0O)8~s{yUNA5%giNA z=}Y^F(${&Qw&v!8(wEY}9=5U5PZ@iEuoVB1U^%EXE&$ao7lP`0`JG6B=YwAYwg0#V zWMOaahSzYdc?)*xQ{opOYh3f)rHjD#uwM-R6TAfcH~2a5KVX9Y+(R{YrMZ7<($x)A zI(vgx;-6#o$yI-jVITZhq@*KhTn$Ed2nW&E7l7??*L&5+nctnLHJw-mcf!9bEl%%f z?@Ar;_wV%XTG@5?PR7>*?K#=LIg;$xRkya_E~B(b$2X8X>Z7@rO<5Xu^lt3vFJK?` z`p3YvT|2M$(*k1sj0AB;Y z2kP5V3ir3p{%7!M+}{JA0Y3nL0Cs6%?^_=OK8L+O_(O0cDEZOOJ|5hN`zg+@`{D90 z0~Ox|&dztE%suRD!IyEr3ET{lZS>kN=&O?lOlL~a-V;6*oJ)!JG446R%0@gRLw@I) zvQG~q7kS;Q)ZHIpE@vNuO<3IsQ|~a;_w8g-aU4T9U6O4{ZPNC^srRBBgqsb;w0qOO zZz3P6ZJ!6*aYs?#p=!s|0y}YQ1^N31lG{q>v;)fO$a)YO1I>l%q1&N{p^eZR5Q#is z{+Bh7MSOl=kNdO6EDoiCcAote{ur;B717Gd)C5lR4av(>GM+EI4(uFy-$PNXWMOqp zygpVI=M*gc-B027LiqPQO{uPr*45PVuA{}VGDdcd`HGJI+Ms^>Z;vZ2s=psV+FV`h z((LC6VVT;x8iI=_=e-~I&WB%P&Zlk5sE_l8UOBr9e~jLyRPn6Z>Ct%X!l>pj;xXyP za{#iE^Sp9jihDoY#h7xpc|S6g_jp~I31=1jz2Tn)|Isc^&0`gJn7=$;Z}>OhkqiHL z{ErRsv8-nf+65Zlk0l;r z!1%FxEx&D@i6rZz<~^&$gy~Iq2ZNMBf~`Ep1bhBUIk5j|&&%O4=isBkfw)fq(OqH^ zsIhK_!*d*}o({s_z86662heu|bl)@z=@|+=D`?XRt12A%8S+o;>r6ZvM5t9pbVZ6$Rrb3m_N@xwV9@-3j8q7zSZmkEsH=oL? z_h(#BqSbG_MrMUMxCyJML_$5cCTxu&g?CVygfpo8!mflPRGkpM(9!wRAY||3!g-YH zAp0~I{$p*ey?=X)Z@c)PbK%_O>?b+-7hF1ix_cpq@-dByoZ z%}6Hy%Uyia_$~V@E*^cORQA_gIv#cL{?f&Jhl}@7Cm(fsy~E)n&i_Rxx5CBycNg!| zE`6GBn|NJ5t6Y41XT-QaLT4fWJ}x}XpJjj1#WURL_wOzpJ@J$OTP`0bIk}b&uXpkP z)9L?i$9K02_hOgcX)gQ~&i^Ktp5ZS4RW4n>bn#WWbo}1A_jmd0WcXE7R$k>1B^3&hBuW;o!(3MLcmyerVK1REA-s-|1?c&RE_PbnodOlL|&2aVY zQ5WAdm;P}szPDWZ-gfzT)W!db<9p53C%zMA!sAgvM~ zhbvrqE_dNS=kgVE`FhNS{~wpW7aY!Z;s3^!?+RBwm%I4xcKYh->~Fbx*3-q;)x~#* z%im+pZofCr_spDogA4yL7k)cBaOv@N7w%{mUd;Lb)9L4KAD-jC$+>rR`990(x06ff zi!Q#_F1)*4cuzUG_gpx$U3tcweTLJ|G#Bn;E?rZc|Mf1OWiJ1BJNNrs{axYgueNk7S@*wc-dZ?Mg!;F8>!h-P*f&!2UxAB(-vx1a-qD7D^e`|6b!YoE> zas_Rbf{iUG3NjS5XiKanQCK9OkkuJ4=k2+qF_|9gnB+CqNLz(zjr7+W8VqSZHW``) z&4((XrO--f6{NZAT4)`#0onv@h2DhTg+73E&tGS3xsdL4X)Rj>X&+E~gu1U)50NqR z&ClDxd!dJ+C!vjy_OsrAc0lh#x-X@5nBEak08NE-HdYSRLdzlDtG@+W13d_>hn|Ht zL))P3ke+P|XlJ?u-UaFnX?>z|Aim)m=vnyrP$je!S_!R&_;#mx*Zc->6SNh26ViR3 z48zv{S`O)6v+iiGfgXhPy`^WN&5-}@QXBdbeS4`lr0*~3Y-lnx3(|bE z5?Ttag!H|g)zDgK9kc=31icBp3w;3TjG-fx3+Y`Vqac0Pq8OSBRY3KS7C6^I`p(6@ z(8JJ^&_-wr^aiv8dLPQ7#w|q{1sLn5~yxLJDm=vuyvQujo@}!DhR^;WZzmprLJK|QZoVLQ7 zyeevz>>8<;wLDHXKNaU{+C@lqCXblL!+Ev-PHwo?^ES>R+5vfGLqkt8*_#DEF6-xH zSkQWzfD*7WQ)8v>GJ=<}eolsi39pkUlQL)4EE$pSq*7&J{hb_(X0MZ_)P2RJyc{r} zT@B>Yrl{h(7|k*K-hjHaR;KN#&U~hfvi@IfYL^vPHt?k%9)+{_Cg|OKpJV$7*LScP z==+>E(TeS-+{Jn;nUu5sPOc=?=WJ!Hi}138r46-ghSxOIl|`LoDo)GeWJ^&K^^DOvl}$jsQn>Js~fJTGf`oGfFnpJ!BbP`qbGOWnzl z4Zyw_BOJHobMlPCUcQalE8xR*i=)eG>Sotg)|8YR4L2%#%je`7lfACyu$k<1HM6F& z!FDcl(*-(3Y zvb$v6e5{eQkJs`zS=wV~H^14zVL>EthbW=)wC;|d_Lt}QHO3si2Okji@mhWxP6_e0 z4~26m@#>`|VctUn%R4$W$GL?#4-ND%g70opABps`mdDAWS6_x&Gg{fy#}d7a^>Z@l z)5~ZLd1#;q78G{HTlxq2yqxv7a-%}? z#iEd0@;}7Xh>v)@=)Wcd{ z#`-y#knXh3w=(G;+w*eP-^qn^SDBJa`^cV`v;I!5Jf-solX9w0sgLVu=>oGbVVsilkiVLwce3tiO|ET<~)D zrpqNiqUYnY{!Wgu!MDjbja+)0v~G@=c(d$~=Slnkr}7gO|5_R(>??(x*@E*>+CJ^f#S9+trDY^c%jOZ#De(h0#82>t@3q zS)K}e6}rj}QZH%t{MOy^hx&+>=nDQ_UU2N?tiO|^kMMcWo=0}*Ma7=qx?BEH=)%tz zl;>6|_r@=B!`;hT9w$qk@%mOBY}L%m%DlYgbMm464TXDHS{>InM^bx6hxv9GnoDil zMP@`&#`@WKN=BvE?L(Bu(93GV@f_mk3Zc3*nYJ#6h|te=$`5t1n|GMcyS zDr5beOi0J-|7<+Fj@Q=D$%N)q>yz>9Dr5beOi8ML+nJ0EVG>TcXG6G-!E1gIn5a-CLf~qaalhnQ=XDpn~G}}8SCd{XzxCrHNpOqO&d-w6oH8RSNdr&&0JL~6U=;yu6Ey;Lxm9c(KhQ8j* z=x&#-52=TveSWN;lcB%&GOZ5s`Po&*`Z*cesh24-GRlu+?8DGL9_#01LStPbEuM54 z>*r)>i@sldG8vD30NTf4-5oz|$n)<^#*xl%-5r0Z{ph^L>MQlIvya32Ihj!VsW38X zr@P8nKPOX?8ne{qTVz--wQzmlkkA;k)$s26V3<#r^|x^h3C&YCQ{a=e9d>7S@Bi7yVhvsDk+2U_BzY5I} ztiO{B)lum$i?f69#aEv%>*r*sJAO_!27P1&yI%VAa@OC;h5F%g^pR!G3{saMy^Qs9 zGSnkq?=~BmUDx5(-SJb#O`9(t=lw`_a07c?6TL%_?zaWMpEu$65PMhaoA6t}9#vCe zK8WA7irAR+_(rzl{ea%9QCc?Q_i7VzU+j>2Hi5V7rRA@tlRX>G6yN=wIcrp*8j~(} z8~ZE+n~3k(?&h8E8Raf!pX7&>ku~XI7UkOKXXO`Zl+L?)+GkHQ`RSRQ)8&C_ET?B- z{4t9&M$8*OIA33ye=%{2hX+Dmw<~&*<=cC(XvAC!j z$H8nPwqRLMICyyegd#02G0lhHJ;xoxMAb0 z_-^9qY|iq*CW`}(lV~xgZQ+|J7mJdQTc=O8BMKe zUT>X(dtF`cw+DKo>}#VuDjALE`3<^wFnYwWQTauMMSB!qx1g<4+I;wTr$0Ny@b&4u zF=NZ-&2yVZg_R}o_-GzT96WUB@CidF*eck3KDz{CTt2m)->Z0o5fk(CCyXENYI^hW z9Hn=N8*}g8#*>~u^Tg%gA>&328C^KRhPb;n(9wL$OT1(DAnr3lZ9wV`s5XVe#}8rp z5)6DiPuE3_neTrz>hI)!SrdN0L)UcM&ZPID@8kD_Cgh%=FQ4bd8pYR*cA)#~)})8o zfZvnetC5`UBX({gzDb;^U(tl$i=3IwX(CMBshi$}UmQQ~sXLRN&PVX8boH?DICoT= zAb8J~^$;ERvPTfya7@s0UT=Qu&dvbN%m(mVcO$%Eh}5$Sn7?c= zz@O&paEG8+4~t=*;r<4 zqYH})2ansMIF2y)ycEY4Xm@ewi}dq{1cUQOjTkm`gzY+;&qL4Tc#}nW?k@Z@W7Wfk z2E#^A95H&-$U>!RcV%$2x%VYLt#=xSFT0-mQ#+Rl&kZ8M(1rRY`*`cc9Qvuyd}`=I zeMjBPrTf|EV-`EPP!%%q>lu{=P59|~5Rzj|V>vy~!L&W2pWY93u=AtoCynx__d)r? z{KkHI|5HHSMh$@OVQPVZN0 zN>1-nYUMQCSf6@-Qd4q;&B*EfNKMJFxeW;Q0>@1u|Oomie_GKQ`IX(>AR*gGRoO+7c6&vUU#x8@A@{tOHKH-r15$FR*pv?xi-!Cb!f(~TQhz=oAK+{ zjNhPU{6;k6cTzKcMa}q~+Kk`n&G?;#-$tj$#`^3z#J*Qu-VF6gBVFs=xUV^v#(sL2 zY*iC}dME2cP552MzK1VcmTpO-_&$#x)zFy6ejD)f^|GU%Q4MK8u^`qpU*>MzZv-X^fmT7ry04@CjEYqulN0XUFRfIqW18Me7&Rp z2@_WRvq&)RaTG zh0uo6#KZ7w?w?}Op2i=++X#O;v;q54XcBIs*0|m3_{1xcd(jDVYwK#xkCxTP^+V57 zSC|V`L+94BhY+9JXc0blrn&ExYp&4DHM6`t9s}REVA2*HA1Acb3UqFA1)5jHgW3zL zqjme9K1~GoJ(T2>b>D-sJ0bfX4tmqB&Atc37Q?;=GCj7iqP}w3eh7$c+uLw$OZcI5x)2SyFhn)adJ*6&mF_m;dNk%xcO{Ve708$;t?7+5mA@ZQd6 zywvW*lOJBp{AUn5@{6WaFQ^FyRhLw;H$RBC4h*U=cPh*~#;n5v4(H;7%6Hc(l$qVX zQr+TIFQJ~p?EuZKb2mccdAxir+5SvyA2V=!!!*}O&%MxAwEY&|Vzb{7H+z1nDf=&A zvst-cgG9@|weGiMR;SwB{tMGIzp7O8+ixMC?>gfB7NBha3)xECpJi_vhC4!B8(qGe*s5H2ZoPHpzVs(u}Y-tyjGIqOWE*Lfu%zbF3Jg#>84Eb1BuT4Ygt}zxRat z!S^l;>h9E?_o;n)_D=7soCWC_yydD>RJk@<{1R?G)pR3Ocoo%iE^aHSh6T89Ck==M zS3p-nS3#=bs@YnzUJP9VT?8ed70{*7Wzb6Ka!4(t1Ef}@wSx97H5cy!snw{3s5PkO zt97X5s5PhssCB62w1>3U$vaxiJLS5A9OrS)Yu?LZ^wyK#y`W&J9@_nZwIvB`QcdDl!NxqwJ&fYGzK~e(w@c1PysX! z8V?mhMbHFjA~Xq_3{8Pfflh^{Lerq>&}mRHGy^&v(pqa4G#fetIup`<^;yu_koL+| z2hN4ggXTf=p%SPRDuc?QD6{}t2vtBa=zM4qR0&lqV2puq=j0UbI*lRwSpbvz4Km!Lfa6khGG;lxz2Q={isRsTZ%ZKe2 literal 75264 zcmeI53xJhXx&FUB3?sKu20;Nq2LuGgVSwSLr~@t`xqLZebv?$T2zb5Mc_pHm_-yZgiB6QACS@6!Y*IMtp zF7LXpZ++{V8Y`=-sjr#ekXtmU=%kZ!r%oTAJ0dSXKf7J`;^_eEDCaZa_4d4T&iL_RFXXJ79&A1P z&Wx`AU`}8NL5H zbZ71N*Wc9s=oz1Q<$MM*aIngM&cjbkc>n#}CoX*DUx)oi-qhz$U)5^PXFz?Q_$(f* z@*jHrbt@lzw_EJFQ?5RI!d++FdSth`gFo@g`3z*>V3q%C-7h=-?$IlMS-fcFckepl zZ{t@@S+V&upuSIh77teWpR{Yqf5ju;JnZLpE<9`CpN`zNcIW98pLpeb1~PE4%74=B z_b%G@y%+yD?WGAT9_;k_;cX%r4}AvI_leKq!7Be~*_JO|fBEd?J;s$3?#erQ!FP^5 z-Y*S5@jCi6XW(F!|9f{WJ90|KxZ)p|J-=?ylxaVzt?GL9r&({Gmb@LT@{jlX+@_^7 z|MUF!{&?drb0$R}sh;tCr%#KHJ`4GHYJ|kltt_7D@w~2M(c)@G}P2o)|V7D);H8tjctrome0VUWLjNKZM3c-7OgKi zH(FoQScgbnakM_RpgLNYS5_Yca!e*9Tdb2(mmBW$MPt@T#xh9m=aF(-sMj9rtwa3dXBK-&^HL{A5cES#^uo0;rdGoXAl%JnmmJ_ zP7rq{{M8y=oY7+;jW~b9y^D7|g#Sw#IOY%ekq(r^({J69xAUhzkEmq!$Fzf43w_Cr zzUeR{s#>Air?4m8-S5;Aeyg^qHpnk(xa=R*P|sU?L#$T3su|*yUzk@l$MbIQf5|Q4 zRlMSrUzk@l-t*qnvGg+WswIe5eqmnKX3u;3p37emuWGq?zc8;_tmiGxXzVLqwPf+iFU+f! z>3MrCxaZ5_Rf`p`{KC9g51G%H2B_Y_*xKmd}!Qsi@d6Ui#kV*LEofU1! zo7m7$tGL4M)1zgLb+LwJavu`n_wIQ`b<1iSG^wktSe7?ySpKLYElB3a%1Rre^+C`n zBr_wrw84hoDrX`;`jfz^Uhe0AsK!ukBKp=A4i#OPr&3i_Eayg9#>Hx?@mCxLFwG*4_psl~Z^+_pgK zD=q>huf9UTVojv~K-<76PR9?K-aQEF6oE51WnJpx4wUxEtiQDxG|_AZ89l#^e;h{1 zd0tazaa#^4{m=ay)9-a(Yp0ySvp(@4PFcIc>7Npt=TvXfzM1rmhDkD>Pifzc`$*iC z_S^aW@6x?b`@l9f(dU>-Vt?b5^{9*6=>GhgCBqAB>P`J1eQ!gO@qBW>54Sxo?SBLR zU1|4y=dEpRdhZOS9jC1JWWYG7-b|}(To9|CUcS(-xEYR({`27}hgq_oUwNp-eG7CX ze8;04d^SplELb)dLRz7b*MYOVZ=nxx5ab;z4Y)->Byr2o6>SUO& zepyw0-Qtws%owY2cwfGh;7pr%hIBtfx>cuUgUX}IgfS~c{y_EX+wX2oh%hA<%wL?c zE^~1Q<6}!3YyGCauT@sZyW!aavt&KL>Qz2&tDr%+U+cp0b0VrtLie>5rM0z1HPsDT zIAApXdil-BtBySy(t&glmOoG(_&M_CY{gC+v0(nSD29$%J{qfbic;Xw1@%ksg)6>`A5HfeCm8sy>*%p7)FC9_}L~vlJQSdvZud`47t+tbCUoLBN=7 zHAZJ}%Bo7q_vG4&={%1rZD_2Est|42Jw!VD!z@|P@7I4c#Y7p^G&a;WQcFMX9MR9S zmb!Oq-}DIuamu=sbVxt8jLfRmq|%R-b4g<{jFR)bem+YzO{CMzXD3IODJbPbVTSz| z)>ar_$x2;ezr_uvf*605{RZMJB+l;eP2sn%zv|1vatB(DejZfdaDKp^Mw= zrlGNR+)`J5%cW14B;)y%_J?ra3#kuzE|hkKdobIcPy23{_VJ3qnNFmAS8CeJ7xLgy z-ll&*W(y=4&nNd<+%`i>dl&NH^)9)8N80Zrp)$X*VE!`q${OP0wt62Ms}7}o59wQq zoMb$o(moKk21sdt<9{IS8#PJ9gbx{aChZ+apY-PHOkG(h?GKW^O5`Nt`IPq8a4*2U z8ut-S-uDG`CAe4w3_;c=?!(U>IG&`N@1tvX{@VM zGW@<(TAnerF%3Q{*EUp&y^uP~IiyG7sx4~l3CosM#?0(dGHc*}8@d>tsFTq+r@3=j zrh@(D8Kw0LaW><*pLZ(GeDbY&@w}5)U7{VN$RB9E@bk{NBEsBe3dH`#DeEsT?qE!9 z?c(UNn!1^_l{Ka1W^lGU0CxPSB&|~rki3`i<;1X)T22ylJF|Z8G0amJWdpa~OgU2a zZyzL%rBs|VNS^eor24)sEFUxO?DxXk0QJPaDa5aG3-gC{sIpT$FCjM(zMqBUr2DX( zk7qf&J0Y!;{v6_Ge;|cFT|5)fnJVLv#Od?Hyfj75$MY(26vMB0&I|FgmP_Fe$MbRL zh<+}yR1+@Dt)Y5>Q`RaMzZ=tPDjOTjCb9IliZm9(BpJ^q_bs@$!TkxsTkGWgn8xs& zs3Xz3x|+J7LlSE+$rU=eS?EAX@$<=jA}cx1>+?tkQ}al;Y9k6S?5Cq@I?Bexa$0Fah3SJf6K*C2 z{|%TQc4<)C(YPL#Wfi-0YH4+BKD+m>D>QMa&WHJGZK|i1vfY3e>m%DYg?Z-FOzUUV zj43a-ZM-82Q00377(;rLZr>+`<$Qfz5C2~1X80yKe#N795$0DsCZo8kzIu{AmG8a8 z`2!-WAS}hHe5;Lw!)PwwY8zp`WWK2=7^SCe6P~8|ZbSTUL*J1A==05*EG2B8?=|r3 zfo{WJvf@`ftW#3>KP=xPsYhxn$Adl$=5Q%t%xkPJuZ&WRxcjj~I;%v6Y7)HVWK~Yg zCsJg?{ltN^l~=X6#+fZghWO=JA z2+JL){`~x?b1ng69v$J(kcqCH@|0ZZK_VYlMogZJrGG(}j+o2N! z6W}-#G>ij3!TB z7jw;TpAXHa>~sA{;(S0ZA*{h&=2gO1oBMB24g62wG2oxUlfb`#YU|XIcoq0Ja2dE8 zTm_=5xcZB~gZF`Zz^&jv!5@QfgQ|D`0#)z!g0Fz@fqw*1ZycF`1AFn-q$vaJ0`fcF z7t8`xuc(Vg&(y{EdDuIEbHO7(>5U0d{8F$JcnwGx@h^f$f!_qXg5L$HyYc@3dxF`f z9!*2H)6m%^(C491rcUIbTh%AovuRzHw*bH1l*7GXC$I{-9(on~e5f2c1-t6gx%?gl zo(G-7Z_xthHaStxW{`LLd_R&nAJ7`NiI7Y$(#d=^I3DZ*_5m*h(TypWeqeTRD(UM5 zErEt4!lq5TXYvvAd>*UzJ%e@nfuY^TRj2bn^+kigJdiVv@zcS<;8`H`JU$KNrnLAu z;4n~if^vy#{xS+&2%Z9Fb0RN?I+;TbEESU`UpLRgP3<(<&K^R}K6j5Kp515Tb`K;& z+cIe!3#xw7m&AL4<3No$%jNSil?{?4SG{?4SC{w`jC5B)&A7%T

}?v?5%#^m}f4=9zPN@TR)5a_#6aN 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 literal 0 HcmV?d00001 diff --git a/tools/delaylib/bin/Release32/delaylib.lib b/tools/delaylib/bin/Release32/delaylib.lib new file mode 100644 index 0000000000000000000000000000000000000000..7e4fb20980bc276c072964297217d7e476865aac GIT binary patch literal 226114 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 +UJBUq z1cFe$rVXKhL?vLh2v}zcu+>+)Y8?TrA^&dAAULm3)As8GU_%stxZ08XK63k?L-5WK znzpNOd#KWr`l&F&a$9qla}qf3C+DE&5u7^Fs<2)Um3dMVLpa59F}h8rQj@IfUPSO? zQ6%J}gnv*Jzq`7S{{iy9{W5~w$&vhR!k=yN@1&o2knCI5BRB`M0P$E4caa66+1>it zQT&$z-gphcF;gN1DE%u>wd{|su4Q0eOXe58MsVl!$oh5_*gUCbB(vLhWPgb4mw$`k z%A+-HFBX_LL8_}_f5~ER?9|H`;C`6gCu~K~ag3(zsVa+$`<*Cmw|4SBLjH#D5F9i^ z(*}0p-_jwL&+61a&j<6PWNz(+W2*~morWsC%qw8?r1rp?9@WNXcIzhlIbGgNhH?Bummp!-R3r)Puvsriu|%*&!XEt1>Wf;b1fPmy=Z zDDa+%^Jp2-ydJ9ar0z*J^lD0H1lQB#8ao?xA?0&nSDCAUm*8ohk?5h(=T_QqI`Bk6t^2a`Clae zDVQ;Z4#6zU&9Bhk8qM#N*!kdoiQKDm!TkuhQ(0mO9;)=D-fuD5X1j+Ey6t7M*5rY; z_ov!tmlEXAMNeop*BzIF=rERjO$9c=@h=PWN)Udhp^Wu?5Q>g zd+#z$OR*;D3!>%Z)!_zJD{e>CV3in_v^YWSp1lA`uT#?8`H*z?_|{MI=6%M4YFym0miKBIDmsO!7~ngp44j;cX(ZVq-<9gW4qe5D0>@1-lC9sXF%;pm zD;2-BRTyT*1+e<|R_qi5No~DQ zB;~f$25<~gRgG(Ht@(Ac#N%yrxK+sM>6-Q~WzAawS*@#aVZ*8}4=4#?U#s;XO3hVX z8DM{p?4Fy!{^>0kN-XvlqS*^@J7i&4MtBEf1Z2EV8Q0wk8Ta3+X?-aJ%fs_DYhGOAmu|! z>G(IK?1+-GS)@!>QjE5$mbO-ILpY*jJH&G6{*d$$C7pC9@!YOyLj{jV2|3n+(pb~A zh>s~^^IZ^e`W>3~54VW97LF6@n!^afJ8y>qz$fIs`Cf3J_is#!tRmT@81vhk>+7nk z+Ux~BHe#)f`4wROl&r@-1lB$7Vn=i*O2TsmI6bLb6@Nr=xQk*O*gqrt0S|*cAM8@Y zdswB=da;zI(LS?P?JTgvur%KZ){SI+_9d`BbUzn-(A>k)JnvFr4cEnqRjqT-X}N0R zzaZgrO1R@KNVx4mV7JUZNihd-fupU~W(*s>2#jBlvHEQ={tCtcVst_)8l#7rJ*k%} z5&78vX{npp9u|X52YYv9G30EboL%3AoITfSS^)ugwbVl|6ZBM#UVKzGIvKm8yaG&L zlBw)-FrD$J)qYU-GcOmWs;*1xEAp<|4Bk)IahQZcPr`ZZOIX;R)Pt{wlwhp8tn@tg zzCzESGuccj>-R~}LKnY<#cJEq>DvGVp*^ru0iU`lS;#M1JDU{Oh7Y5A1gilWkz zV4yhHpos^IiK!QQv_NqYBnOMI#0|Y5se2_A7a0{nq?ThH6na-+!QRA$pmIfSIHZ@|~3OPDFSPBt$W>T2}UmO;hDTw`KIZXPlf99fxL94xFX2@pKgoefuc+i`NQ1!wWxeeCGEQD}W0 zuUEs{Dp}aI)2O^*L&-99>6KWfa>l$%ATOKi& zKwfc3f6aTb)fGvbR+WRTs)wo=*COY4V$W`9dbT~5Yf37o(1wbFqgXAL34m=F{DKt) zdBI#bY-&NUusnB40p7kUTb1MqORpq6{FgUj)KNrPR5S&_CTnYDt zUbky#g63U+okzolHKsr<3k_Um<`#eU2q;k{G6GqD7Tg1q$|9=p2C2dyva!Og<&`D* zrPE4SXDWaKKGej&C;7_YagfcZ9?9BE7}|p66~)2)=_R>SP^+ZA+6And-%x$K?qer+S@jc(+>diZ{m-2K30AH!_>>C74JH!X(sOd!iCZ$R2G%<453au z+Ny;C{5@?~9p>CU~%k!00I&E!Vapp~lyzD~< z^-tCgPHe?-lX%M;f=BE!RlStENcV+Dwu{WFL?si728+a7(1o*+P2pOc`m!ixso~#y=icA#l-T0+S*D6E zR{JVICZBfE4alUv1~BkN0P1H%Z+o}x*8#}8`C5-=RpQS5@-T>V`sIA9>n$r~|6VS= zGr+fsU9V*p78Mr|7?O?woA)kMbC%e&s=Btqrj~+vJWb+cytjwN^b3k<2VCkMgS%W> zu)S{V=(eW$=+;y>eG6WP2D4T-4=yvN8x;jpEa4U6hk==86=fKy3UW&-%YsLgmm&=0 zmIMll5fvBbTFwsQ-Ry=Z&$+HQw7*#KB--*I`8Wp&__e%ZLF_t#EeH7@ec@IjJ#f+AndfE1e+t8 z$`TQNhi@YKpkjKnht#u|eZ{%uM{uB)u@&h%Al=J}8@!y$`;M6Mxdw)B;lZUM>t<9@ zb~vgZS9Nq(nBjfmX~4o6T6tAnD`v=5ZSAdALpmSw?}UKUM8Jp$2Nsk}Eh@(}Vd^Mk zx(FbWwcDwoQycIu8L1Vv)YcZ)&1|V^Sx9VF7rBo03ZlK&j?}OK#ODF+^_Z?U*3{Qd zbD8h}5S)%|KJDaijqY4ao%&2DCu4e4Qo)v0Y2bJ^S<6m3qEaR_IrJ|&xNa4EWOeqgR-_J?-F?Jc@aUPe>D0vuDC~N7 zZN47D&%(Q8tzjh^xz+pw(@}qetk&)Z55*rsRI+v_n!3C#k2#bc0du@V6gn&qT-dCp z&r?F%;jcpC*#h8&{;}q%jnMm%9HLAkHRTBMkCBEv8+8kT9R?JIMddjLp%TFa#TBBQK0cRHqTg+)gM4RmhBMVOG3mcvn) z9!p11UYr{!Ko9mQw1`I%AnZX*_SqRjyPE264-YJ{#*BSfksgtT$eLq+Q;06lt0pv$ zpnR8$+ctDL7r{gc)2LDw<5w^uSv%hv0%dFr=2aFIt3s|vIe4>GX$6|v8?BD^Xg2)> zrE?EtxlnXoge4RQ?Xjb+Vf+2`vWn8l1tmeFw6Z)vGt;D~Dtu+r)Wm5n>ZO;v^PT2{ zvt&OKzET}DrR2F(`>x|87UgjDqu6)R{^YhFTGAf(DPq zFJwaKG zj8_W&DQFOC3m_ydV(Y#dKPId|W2$JvK5|vPO_JTxb1cf_Dq)|Km?z_4Te4P%?y{^5 zYsTXIa=T}{5*fYOu4%KH;kgz<1CZky5p`UmOqI|{Cu=8CR@Ytc)lx5Z8(glIMI}OR zj$Zkr5YChe_Cb2k>JTvMV^^XmVBlSfa2+m74lZIa;s46%Iouh0NyhIn54Njj%<*;% zvUzzz+^JJ>j@ZLZ_b^nVYhk)iD~np>-~^(mDYv?s-5x&Dj;OBAg2$(Md4AJblXKpu z>gtJ5bDenjicGHQVfOiA%^>tblVf#4%dw8)$ZIX$r{xx5p>8eV--k5sMqQKXAdU%Y z<@acZr&Spz`rtu79C{s6R|v+teOUGwmBke@ zFPrNsPiOmO0SeToowj>f)BM_&%GTPJDOC&V8rmDMrv=s0Tza54esr&3^jIsCxOy>u zUvzZ&_80ARFi<=tZ}!~jo9fF|=ZvgZNy}c2W)_|_Bl!S8^WNsF??!DyRr4HtMB<(W zj)$Hb>7fZpS`Z(gH8wd*n*AYnC0~7Gt&A+MmACUt&qj>BZPsQ2&kL0EdP3@Ah5K-93Kf*(a|fqr3Ti>*JnaXHzcmrU zo8|k`;4FTeYp>1*z?9V@@fGxL)_k_}kTJ>H4`e&e<&GY3PnLpMk3Rn|?P)xHHRMm0 zS(<^}OrW(UR<8nrPrE(b`v>ro3{6-?;Ok~<0_^JlM{3@(Y>mHgU@b;+UCWG{0qJJ3 z=21*oSm^eey$N1O)~Y&>e6d{ion&rGEMpPD(hSu8WUbg|^}%y7A4-%O!Fdci)gydm zQ%hxKqE>i|`eW0qq9_ln+r&u?ZoOTW)=w<0)_hm@ZY;$0%?5V$uD*RL#NH}~J{;ae zmWJa)6-m~%a8`Uoevxbs=H*rda5X6OhhS;$A1pX3P=KumOzF!DjzBl7rWYUrn3E!7 z(k_(o6bdZ27<1?n^u^d-%q(^>jfT7aBOFuF z{aE{;uIB1&*mE1*TZyk)>RMH!<()6p2kZqIcZrN_wR2)`hghq5pgu`TWw#`b`q);{ zw2Wl!USDy5RTSg)XV|z_3+dk^<2mS%*jDTgsX+XrJ%B1CExVkhk1Zi?6$L8G^W`WY zS?WklVx^jwK*No2IK|kT>EFQzK5d3tFcs9-&XXg83Vh=3S~I01%aU-@mo;J;KFoKu z_+F@syY3e3Vn&>-t;Dp8h3(!L*|uI}1OPZ2w&qkm&v>D0ab#yL(G?5{{I z?gz~ZYNF$5o?Y2 zkXRM)%jfSWMMaFtI>j@W^6RzW2^vnqD&;NcAER%>d~ z>Ec7oo#OiiXD`ePiW+9iqyhKXt6QM>PAQ{5u)Prb%`qrr_LXYkj@4~pq3mF+5WWGZ zTCCPZB}Emb*p`Gq9}M1)Ou()e#&#Z}Dj>!WBKRuv*RE zT@_u27rm$mIBom01>#-yvm1~HfNC{;V4I`19of3PL!Lm*i?OA~Q!w{j>JMao0FLqUf?=nMXI(UOdN{7- z9~3v9uuFK7qZ-4`hwGEr(6O?C4{m}FJQ}aO|CK?-s`U}S@f03aFoEytfT^H_N0+Ws zCAw?Rfz}36egXDnqVVNvoU$LxA}&kTUsj)zAn)|@NNUH9x@!H z#cZK?&E556?Hz2EN9|v~B`;Pc2B)a4N6Jz=kJraYyO#U5xg|!C)mtO;RuRx|a9h=E z*Gkc+O^RA_71uS?x%Wq1CrjKf+kJ4E#a=2N{>T@!2DZeKVRBohj^XW)ctDn>uquft@ky?-!jG4Sai z*))l#Dp&H+A#^^c47kD)!Od5^OI@M#x>vF6U2RmUHbno`wz zf~z|33bgmy6L)M#PsWN&#(36107=%a!|}DcLJ;aFD*pg64Wr66i`F6oD`$haLnUNdBW+Z0j z!HV)qgleH;uR->dl5YC5ZFZ>R=6bR=J5lCNG8HbBjWxXDwi-^q_Aak&uE+O!t%0VN zi8U=H?G3fq$<43S97)3$S(U|#_# zDL@5r-vN=cVf3`Q_}Vcv2n8tJW-ralZ>l=^-2O7lnT=!v`3r(8R~-|}q}!(*X`KW$ zwYOBeS2SF%Jk$9EN!ljQkdn157G2YSov* znZ;$UlyXV&2Afk#v7C?!bhP2tGx>;N^ut z^#8f-ZB6;Oa&29^RtJc#J)d;|@`}j5odX){Y*&|IUO|r(HGR1Y5|Xv`zF^FWjZb?C z_mQ}ksBNslKCgk*X=w`vE$lCXQ7RKBAA4ip)^#}{#@Tukw`y?54Xg0bRThH>P`W^S4G&d*5uf|?f-*RmZHS)goX!| zrG|Y?PLnFL$i30Hvu%=J0LiEQ)@3uCl6w@UttI)>it;Nax*8&VH(B=f(HhXK!c)G2 z1^8~crWPB0JDv3ylsv^olu8&|FyhUe0k{ICeetCPG2HT-pm z^Ijl#4Dd~Y>&ncH(DjCt+Zwwg>9o#!5Zb)^%Z;0;3pY1``%U3K_!^uY>}1CkM?r~d zdov?h>$|7ggzq#j_9m*?h}@8Ktq-kzS$F?^FI@SSsC^E%>Uo;zEbh^BRG`j3iyX;X z4rUcr_ikOh8k7`_bxrgmnH-EwoL3dB$5}fBsB3g9eD*Pa=j(8n{g zYqxO0V_%R^Gc^eRNz7ZqS^l5i-Nm(;aHZolEc|p#E3ezKTbDY=<@~Q*wm*BN>WqNc zVcCeCKTffm8t2uvv{kmv8acM2DYvz{t`0M89$8woHHebiAU2-5yP6uvl~dlm!ivi% zP?JC&?D(`z&T7E5$Kfmkc85PM?%bvP+4=LAQgwQCwGvkYyjqDTYcIw=s>V7zuadW| z2TSMngSGR+4Zg@-@=5m0IM#@)HoP{(p2s^Xwun1kL1RE~5neEG0~E_jHU=rVp76-A zzOq22>o7c7OX2NgY`H{SPgXZ`|LMAT6lDDY&WCn*(N$I?-yx#1CkroSS+AFRJPp?or zWp2i=<~t4Xv!aH0&Q3oP@k=@T33ny2YQ|wwF4w>(k=rldi$hwG?wXw>Yg0R)knHq= z$bM)~m;qdjwGFR_cHRi!rB|u%>=7rTb_HXtG@g)ByBw}(<&Sl={Vohn*8Y(wKa?kn zAD=c;O~t3ywY1?|sk#&8prN3V>yjGRS;GJ@)_3lEVr?mI0S=#b2V5%al+NbxX0>IG zPdgrqR7|09<+-Azy|pdBi9ePm$JHS&P9-0wIZt6fDr)Y@tDni*URYbvVAr=0kr)0u z#4rA&pz8*tmtXUtjnC?|KOXsEVE8iiC#WbsZK}0!vF;PQJ=6zS+Rzut*Cy6*dljmM z({xl#d6}CFs&ioXXx}d4Mu?Xmad)n@)-G6hA`ell9g*3d1G($jLj}!a-7L zmmwE+KkbiPV%6?LB;)RCkHUSO7(y1o&E9v^Xm@mNOOu*fRy4_w7qP1}14eu%z`nw| z%(+JrYZy=qvt8AyP;GHw!{-j`yg-)TYOj2t)TR_{bJW!1C;jmyo;82MazYCYu&W3Q z=ia?>25WC11*harB9*N+9-Mmghlvk)?1MO6THYJZs2jQ6;|#oB6m5T*W-FvvcpgWe zcH#L0#i6gTt^TEpf&*S$)?t2%`K`y&JFMmy=Q=4$^8ij{7Uhmi>LO;aHg@~OF z0f5hE^Ww*{)@)SjP{iMk2;UOk3`t*#q+L-RDamzw)tiF&X)?+x*2>yFTlh+ZtWLzQ zNLe3Ppc~tW8WC(5nLQ4uGQ^E*J0~4#nGp4nK|7QuYr9z=bXXgM>H~~fWru!H7>Brb`p*%gL18gkp7F z_lp5V_N6vwC2MbSCa@M|q9ob6@@i*ubiohp^DA^r?yT=H`asCHg6}@74#(Kl_40>& zcJ7sM2TiYR5os$?5YGK>r$E#s>a>UPj@xt2&GH^nA5KDdWOo|wlHw5I(~gb06W|)7 zcR@kk*eARtfzLs#GnPbga6fl%)a60>qoOLrp-O!~!;##5p5q0Qs#r4zeu6PSV&<^B z=KV@dsO`Zv=2b7NAbLRaR=CcmZR@hz$~OXK!HV1?T$>^6rC&yGg$8SM?yM&68os#e z_A2YYcdG@^`bsAzK-XQg@1$(M+WB@I>h#w#IjO~Zqs+QFAFJ}d1MSJ$2RoO9JAtkX zIq!{3eow942v}M4|)~)-|JOe+K)-g@k;-wm-$|=Re@784(bRj$0xz@+79Uo& zN}5-!tmp__Oe@aIFhA|JD)$oFmY(1}0Kc(zsnilm``4_|HV<^Q&q|7+V< z_>o}E+^T%_W3MRZsPwRNyhAzyKlnz#YP!m^-?$%X`x;BfeTel+co!ZD4Wx4|epVav zTX9(>UYcJ!kHzA_A1DRC_(czj#0MzpOH0x|E=jCwwj`E~EsD=BS@;Pr}R8yizIVD-?AkuG87Pj1n2wM6qopNh7e5)atRtx z@uOJ?DG)Y~C=io0bU)Axwb7i2By*_co7{A`<<$NWz8OX|Cn1-h0Tn-*#gGDFi--a- zNkbnEG}$(qB}g)}yYS5zqFIVuf(BIAXnKWiMjh+iul|eu>ODOK&Yg$|hoqrz2Ap4g z{-13`_cGHSc)f-XyY=gbI|Lq2`mes8xGAA&J!#N=u2)+6&+b?EyIv*8E3yffDX)CK zXCW}bLpcvvDF-4&^LUW*AXE0l!+-H0CU5JO$&XW>C-ev+noQErx5DH&(x?Rv`fN=x7Fe)Y8LRf4>7OnydQ`FzibfeBFYtd)`_PN2!pF@+{Sj|VYX zOX^N3zeahU(94KuGD$=K2`2YQ@_Ul39^!RoqRDUY!7;fX;xn3p6 zE63!w<(1py4OYrf$K-dILX+RcgP7d&&rIIQeBscfQcqT?XJ1&FW$2eA75Xnq@-I*F zpP%GE*Ru6M^P;3xc{ixJz&_)y0mo2eKS)MZ>E|y+k{^9MUkx|(%aY7g#6ttUU(HAGKUEHe&P70VlSzcHgD!f_O zCROw(^^7o=L-@^>@O{Q#pJbjd_$-)%$6c3{bv=-b1juZP2;rwXwF$&x<*e+;YZvq~ zYALLhd|!;|&uBxxGATlbW5AVSz=}8x=$W-5slr?88Dr>IM`7OAcG1Y0F|DKzxkP~C1x@~=+vuS)XYXjQi(%v;>m?QQ^{i0nmS7`G#75^UnD zVne?p$-FUEb-P1+c~4AV{z-Ma9d69JN2=QtL%%c0T zWUf+GSeforhr2|>nwT2?q&kQRYeYktUdQ%^rWiVib1tPs%3ax|%3V3pDfc5I9bPWw z4%f$3?r)-~LYx32;*=T%Dx{$g>Rsp`*xSEnZ>wX)j|6Mxp1nH)cUT>cz|i;Ty%zOU z3yq`!1AF6H@T-i#d`CucAWy@5D6c(dpWcwpYA%pL{RPN_BZhpgqy+Ld1^H(SGD$<9 z1jrM6`wMNz+mWgl0AOG%Ts#H{1v60Hm0?coy(+LKLlByUc)pL%Tk-Q|409$E>hIte zsG$A=)Ci=q==%q~%PAWoP6O#(nZfCM_bK%6)yKa_AIrP=y>HFjqfbY`jPUM&KFYg? z(7Su}vAwG@0{2r`@6v(ea zM7v2E`gnNo;1vHD+k>-^Djv+SJ$NuZ7;Wwtw;vA`b7zCoROu1s&aosa|K`xdIwZlr zhw}M^*b2j*jZk%%sH*QQvO$SFj3S$?*UE#Uv6-*wK~V8~u-~5I!9IxSL6U}k0z6ok z;-77Mus>48gNLEsPr$x`S(kzk(}#3(Hr)0Q8}&mO#VR=ggJpV7Jz?(xM!^UwevAh~ z3WV)TY=}u3`g~w)Pw}_f7>6QNFz#(*YzML>K5T5HYl5^D^dsEEc_;%3#LJBzdl9*S zc>NF}ctORF_i#voF#gdr;w5S5i-9+k;y)$Df3gjE0$vE@!)?f+D9EQo(IuCzw3PGluL;Uar zUwub?^aH5){jld=;)mT3(GMgIeLei}a*F>&+YfuGOnW2BdQ{qUOO2YE7ICf!H;pk!HokhdA*-%QDRgM#*jAXC!B0k1M`KPsXFK*jHX zVUPl02O^>aNE-UPaKMHX|68^LhO0~?5oLWO4#>u%{(g%2R%Zu{!Yer717aM5=ST;< z?>Io7%nhVd!~sf{+kxz7Vfq{pSQY5zmp0%HU ze9bqA2 z6}<2(G0w$vq!)g1yzqnbq=Z=ZONNZ`+fuTAql8vSFeOba|CwoR)IiHY#c%nkkOE=< zLPX0+8oHK>Ex;82cH8pBD$`O#Sv^yk?=(E>3907x&X#xJ6)f+Oifqg99BFw%Dk{B{ zw>+7D(0aROE*B>HlV#EITx85&N%miW|>!C|SQ`LOP2UZ^zZ{h4NGiWyK! z1Km;DytkA^JtCF`NkcyyweieUt2kOzjy6R4xvA!vsU3kQGDh6h@9~W6#r>LD1nqcb zo|_6P7yok3VPVWenz#g1{DpCf(tRQ#q9bYO7XaOPHoB0?u^5qlVXApvXLL*O%Dm7) zx18vfB2CbNiXYuMO7}8EL`M?4wLo`Cs{bMz;CVyL^vc3{TjfzD%F354d*JPnpY?|S4F_N8gFv0C7f&UByd2* z4`&smK-daIghSHMR{+j+HkQ>Y$1RBT8&l2efa;ly5%*+1osqpXvma~Lt$1bLmkZRrnSkGmcw-H75MVZe^&3Y1Va{f&?PvJ@6 zfQlc^%a8(L&mkfll7@Z{;M|q!zte`Z9;xP?3eH^-a9+imoO=o9H9QF%Q1Qcg7g8YX zEkuMv($Mb*oHaI<_f?J$5$O-4nrndSg^Uqva-Yw@rhhtX)<<|{K9CAZb{9;d`xt40 z4pjW;zErw5A|g7HhQ1c)9<wq(7W$KG+%Ew|Hef?4Wyy=(ZqD(1D5{-LFdb z4~U44B-Wuow=UKHhz)QXQq4yI>!A#D9Z_UolDk%F)^@zfd4h0$$CJPT6+fKBK~j_+ zM1(`q(4PgIr&Ik;+HibGHJ?;)o{oT%gf}_Q5l(MB2^>)I!%2q}2unpoI3x}IMZkI9 z#==_R5YfHXk|Dt>esO7}oSL`Txl zUj@2XY;=QFj{Oknucw-?bVj#7UYV~u=w2f_9ch9NRQ%|ME8PboB07?Wz5(doO7*{C z100D|^9{gSmtnp|6xrOj+`q;E_$KL)BN zxVyN;r;XsW0srWyX?SmLbfz<(5#muu6NsSVhghWm%s@nlB(W+5#4l6*U)U(Ck!pSc zY)@I(%r9jYVWF$R>zuENsTNOy2~_-;8XyJ2>JSkVN!*tJrf+RPO)AG+MEdus=C^?M z453{Bw{c9wKf0|2@6GR>vHCkgY(<(t1QkETlNEsZhzOCSq5leqKd1VCv{9adRP#q* zd(OgU{wzbJg>DgE=ln)YAv_5tQ1N401}PA>6cI6zH1t1!X}b;ROqJtoM7ow{ZU?j% z2yHps#tz>aCeOipQ%kdl$sL4vF46=dsQ4jXssJoUM2I8}Ju$7&?@jY3q*-f^%aLj( zq;Vip*i0|6*yygn>zrO`V80Sif(caom~Ma+2)h;$F_AR%WME3N0j*RyZbGD|q?t*8 z_7b682)D5}!#~!x)p&2Fq}gLYA40qtX#x>c{1ER_0B%P_h$IcYKOpu?^QYM;??I}W z25jprY-T@VvC-X&*Ezco(;7SpCQ$KXS_df*_7EasB5CLYfN3`y(BnwLs&XxQiN2w7 zo{H`UbgvN|x;HH5pTOY>&KA{i)EhO zVq;B0DmD;YSPzTDdPq#Hy}_1~ORULw60D%&$GQuoKv)_gVkK$l6M?lb&7W^$-3_Uc zel3i|njaJE?qJI)BGv(T60D%&$C?Q#5H=7Iv63|OGGHx9^B3D#_eE-?UrQpf7RSW8 zAJ}q^B-Z`$Bv?Vkk98QNKv)(cVkK$lM*-{9G=GJSbp%o|33SzgsgYPKVqzT$ww&q2 znvEyH3MziAIgkQjV-XQ6NkcytSZCNk4?z;Pm)2rN)i*SQ4QmFFz0a0}sUU`!XE4Mp z9h|A;hUXp-lvfKm!#& zv@%G6uwp_&Ow!Pg2edghv~nb2KJ9`wrweE&5SjrNfd(pmXfq%M!ln@tVv>g50%*-? z{zew+}@JR9o?NX4F*3+sYNtn*@Gtp{7qNyOTKC&3CTeysB#1;XYcB36>P zD*~*cH2*0!)&)q#62*lz6p8hem{=ErEoTX_o`@&G3MziAiy;NVPC-PhBn^ETuy)u$ zmm&!}d-zl)y>Dn1D?kU3eZdmPLIsWb1vF|L$nc`#;G8oE?KH3mG*IzFI|ouA>$!lvq4tVsKYnppwv1hVf~;#fwb zQNM&n%`e1q5#-!WXfJ?8pn-}X+Ut-4VXqJpVv;yF0JJqWv^SB29aR^!HC;e63GFSg z2sBXfL;Da?AnaX2LQK-o9|E-h+R#2m680io(Ei&6w1)}p6R-$0Q1L_C3@H%yIUyk? zY3NS^+T&^dbvC+hkc!P-Rr%UkrjMubRx!$0le-7&0QTo_5##P1_es75Th3F&x&=>y z6;%9Ke}xnX`vDQLlEnT!us)yWf7Zsj4XM}(c42)!66>=uv2F)j&P&AlJDvn9sQ9ra zW(ZafB4Qan}mp9NgDbu0Q*y#{|6iFkw}dkuz!jI`$J5y<>1Ttm0%4#30P3^gPj2> z5H<}F!IH!!ufDkCmFC}WgFP0hkt6mWQDC>n1RDfjj;Al=9)~9Z3o3rF6_W&PDI$U; ziO+%u;j`dD{t<($t@ui$nj;2bre(45FC3k!Bu> z+)ri5Ei&g0&V5P}64O0nYzg->ar~fB;P;G0K&d9uDthD`J}7Gfja^HDO1-)Ob_i1+ zVkX{?0~NmuR+ftkRv;pFl7>Dev(P^((<+Obkz|g_>e6&{Y^YlfY$AF7{J#;Pc zG0(k`d3Hgb%N#j@r6OldWS#-YbGefz{|w1JqKf{1i zqvayxzmZw?vxMZeA7Bf41UaN2$7Xh;AfJX5*#0;o79>eS&qF~@$n+m(m*q1^H4k&j zQk9fB0SUk3vWity&mxoH33La~tB?X5FA@i0lKA=#cqV503p4%sHl)|^!pwIdsfuA1 zB4Gz1shaV6WF}QJ%!!#Ds1?}^SnO{gli;4*9o+9j3WRMyMBF5?sS4aBnf_uM^an^a ziyhFahM6TuSPDE=75fmG1kaJ(!Sgw!0LQ1qftaMBR{&4B4dx3ZndMPn&?J^-$`86Y zcs3!Q;Hm5mo-L399A6U$Vv>e_H1Hf{|SNc zwRGASa^C|VVBZ733MUF3fvYleuFe#tSI4O|>p(!yOb}ZKA)>7$4Lxh9eKUSAXc<^T z+wrqdP>Ua{IdCX4?u!?q9aLNs57B-gq(ImZYDG-a(1$tNhk{nxw>jE}Q~N=9A=*L3 zuYDAxK-dUsMNHDrM>*O@gI3yqbF`19_Az)N+Cjyo{cb;`Wa5rLq5+7+^NjU{!wdcM zhx^-y`&)}4^A1ShnFv@=MM)dPwmcA ztMfE>ILi;)UHBc1rs3Eusl-3C!IgSK_?h3gqp(jL4vYsvtr!d{E`uiyhLj9^ZGdQR zeso}whW=5Y(EmZeGA|RaFz-}*4=cE*^Fe@9PC(wKwr>U_hamYl& z{~Sm@3-~{=!SFK=%$*dNl?3w{!2C`yzh{`AL;-U?1^J>oz{V(GBP?Jf4gFgH`#RwN zD&XH_V;f6slPqkjiS6qEXF!z<%&&lL2XXGmFgHcvJQ$qfz%AXuc^IU?f&U;r#3b<> zX27}CMtC@qFe7jk<<=-96OcoY{LmdF6Cni%@`(U3N!*14lAis9%X#qu>-$UE>HY{@jmE`+d~?D+P#l(s^2ro_2m@g3&esrAue51 z>X}>WX@HaF8u}TF3jL=q@}IUymDU3Mp5&7L_!SX>Q7m7s;fG1g(--kKRnQ6Ckzt;O z=dJAcou4f^6CzI(Ph*C&G(Uu@$jUb6ncc8_t5mQx$qY!1?hjdjV?pHXbTWm)o*4J2X|4xlK z#?AN_Ys5d@Jb%4LJfk2V3+^1k&$1GZLqg{oQH5002wI$F8C&hv+r1hQ=_*y9bK87L z(j{T~x+D2-)w6`~9fy0Bm9q(-6-4N`DoE=+Z1ni4qeN5;{3O;q(1rdsgsLm+ZSuJz zut9du=#Td@Ba&D&t|YA1H*lwA19yIs1>Ah9=mt1!ar3M1zPN28;1)RG`k8!=1c%RY zH)J~L`^awtokRqlbU`D}-9WQ@sb?3U+1=1j5i}<|Xa8B#aWO58(wr2+F zq3B%7kpkb&wYSM!kz!1WXOf+1kdwmtZ54;jXJ^WAGC3lZYZgITsYfkZ<+&TK(bZ2L z>W01)QVacy5vp1=q||djspmlbbflO}j28-y zHtiIbOKjn`q~aKO9N~7RDdM3EA-_A_9lTSDf0+7S4oQXnOA-1nMxZ=YQR%i?@laK% z=b!LUm7!k;NrnDv5c;n|pgc5FUx8P@lvwjmulW84+ z51bjm$CKUJ=xH2htxveCinT9-gqVqS>`8bV_tC)jXnd zEkZ8A{w?Hn3;XGi1k6hi5j#oz%8y|G0ipjp1eO8I@XjP1X@JRmxbiDD@sRO7R>ANb zD0D_NpVgJQ`C@bep)m4q@n)?sfGSu5L))}Pvx1UX&>57 zh=0i~XB(B{GB2J5jL_Yv>!B+l2?FuQeFY3jeEBJ0wuix7g=CX7mgC}CF0j?|RxWhx zP_V8>Hi0E{cVOKJNq}`d;UFey=m~4+BMqVDqm@WDN!ze^{N{qy1Fyin3fTmf(A|M` zJ0wBiErf%ZBtAkFSl%$KJCJOWwqb?66_Ff9+e5tAOTqm&*afc8-GRFXk^u8=!bD8c z(0dD9Ul{IvNH$5^aCsK)@?x@rbw9ERETOvt>tRR&oc|IIVv>fQDzN&5VLgImle7&> z9UpRWEZ#~}upUJ=fhBZzV7-WQ62N(uM>&W|;&z+B`UatYGXksPy@Yor6Zt*rxbN`* zhL@ShOxUTDMv^dOY2bQaM3N>+95_NZVXG0p64ma=!44mO=vTfu%H~%qoOUy(CxPVT zoF5=M%hI*}Z|Tw~K!jvb2(Z2u&Cf3HhfD_xMu07H5$APe6!&f=V|U#9EhItnSBU6d zlGy8qRP6R6^#6#!a_<(rGnpvv-Hrz^Y-J)dMY-3V6wAG~oIi8#?+~43>H7X}>2kT3 zLV)$hXnxDRHWtUdKOv*I_ctqB0ESv7GE+z3CwJ|2C%N2PDqGd4y|x_LtH$3F$ZJpVM%Q7aS#|huD9Exj&i-2( zT~4MDAg+t%r<3uM-!>vRd8^dnVPeIl~cnC1MNKAFLU+e4`$G~04n{<`ki>i%TJXD>2(7Zz zRjvaN>AxV^_QwjJ$y^w4Z40y9S(HhV*|upY-kTH=w&`b3P<;^Ih)qIw$EKWgv1u$K z+C&o9_wh%*ae*J9|9u3OVTa+JNxCC&s$4)On`WCRt!0t;pz!Fx@ME zl8nvH{VK6Hb9j=a$$bJIXr2J+Vv^8tne_V8B8fL>Adt6mXp&s0(I0)5COwSMzZQXI z(gBO)hC) zM}+t*3{Ka}J3!*2b-)*2*K7G`BqYHSKO*{wq@h0tsfGS$5c;1&VEHH;?@ZE>4l$W8 z(rs>Qd4VW`%kq(%tFw=I%_xFPIV3`tavN&hR@6Ftd}_BQ=O)tg02ZHfp5Dj`G^5mW z44g6ppW}Z{hfGE2uRx$2@=ue`ES_;Q@KEYG7MX)iB8u!sv;;C?^ai+gEH{tS$>Yw0 zA6{Ym@Fk#d<(g#`enVEto9X1kZVav+O&2ZIQtFCqU)78$jicF`{N(hS5eYOs7t)7p@ow1_v;{(^3N5uxSA3stU* z5b3WXndQo(EN#Nmr=D~6V3S$psZv6DJq2x5y)IU%#o6+byDOJa(0W_YCJK7))Rar4 zKMi$+<@JQk#MQFiiiU_U3TcvW{gh+oI$jm&PdqG;PJR~rn=GCO6K0xQmy zDCa%pg9o8od?0jpeDD+`!3R$wV$~#xA9xfWydU<#(@54o1}&D~4N5t}WFA+IlGj~z zC>YZ5i=SXxD-P-#+83Rwa4ic9r6QNmXeD+xWwq9ikQ>OK1HZUL=c($F`F zJ)ei|!2qQSf`89cm2PbK(n8h>{=OldVbql)R*6NidX2k+_CI8N~$dNRKN|DxFP}Cx{o%s)H6*#2Q+4$H~4bSlAK40K6&njzGKzl z@v(+}URYm{Q{&~1zVk(2mFSb_xb&SaQlM`t?1R4b)aQR0q5nk&&m&Of9Mnxbt3L&u z#Tv;>oEu`6w#8>MH~*G1=WH1!*_^+ACr-ns2RGnvQuUqxP+CWgp! zHw-zU)KddPPB8ShAhpo{215U92$T)=VxO{M7;WHt#|Cw_h`)`Ezer6UF@S->`8JYp z2rW3}xf?ha@(s(F@jy_?qI(Ik|2<0RK!lw(0_-PLjN{|{$CMT*#E7v-l?MhAkwvM9!+OHd)b;d z*voB$Exu7)U*>ZKbQd%3K%VH{fXt5FCZ$MuN{2wTVbihe*hW!z+dAPTtdgS?-GjF# z6(Ki%yT2{x4?KhGUZjh&gzk>B9)=_cG!fBRBn>?YW)%8+A+-GTh|2Y-iq;|0`_NC! z(uJQMW5#4=;;zyfvxCcGCWMhAo?r zE>04tF@x_xki=?3+ z4lRZLLlIhjN>sUesmO;&&%;}tS-S935;Nv9W0arB?D)xDqbRVmlX}|&4rZ%t~k zoiqW@u&EEy#YsYU$4NsV2?F;)#2Q7?(5FL7p??}ee*4ZRUs3jOs6{l_D)teb{+V!f+)n8&fsT|DHADxM}JLB&xJBiM!R4)$tD zg1{NXjF_aMw?j*zzZIc>E&>aCjmlc9qFIRa1$e77Ul$$C@yu^k%=ygE#_2MjG92?w z3Jdqk)E@SLJ$GyniK$Z6$sM!jX+$QI`s|)(9-d)g6Vk5+#N0*rCdhV zm@Zq2OeU4tE?bOeSaurH#brWw$7Sae27YoE5nV>o(9egKLjSo4{bwVv{Km7S|6}bu zz$_`Mx4*Limguq|C}|@FS18FaI|O%k-~tjBXrdxPqKXn^35qhLB_onVB%^?mGlhWU zoZ*j>gXFvf1w{CM@2ToAcP%4Mdo135b(kJ*;26B!K(l#}&awntolH9L^d}jfCc_q<MpGdmqQ$t!BBmniPE|R43K%4)Hq@N-E&JsVC*a?w1TLvq) z0eV~?%j$xbtc$vX+{(`w`CIAsx7`9dr}qk;`q6vI*e|(6w;Q&kwJZUxUeoK;tItsY zS5%#}_Oa^rCQ8%qiS&C&?2bsKPE@JlBbGWrrOL1GzZPmBcR*sV05Ux-HNv(8(#dn?BR))Vn1}0NN=6t<=mNL6oLH4CxP%I2e&i-Abj3kIMAPuqd@UeR3|R zPbe+ZcO+dz-8wJF^g89}!xTWB3urY;&D@DZY5L=l{#c1)B#uU;ns&v??TB8PK3Nwv z1-X^eC;xK#1oTy>?|0ae)@}r}=`+1fy}tqpz^ST}Rw}PwB?>QKMf#H^PC}$oe~p3h zQJFp&7Nu6FPtN7^38iKFPN$2g`vGd@m|mxxBR~RBCkHA=DlbSS3a>~-`m-g@M5J<# z#Gv(HBEzDbAdm8MRjx%v?goz7e0REJ?4Z7tISlFNsxF?KG<6+*ILHq$=ixynM-j+M zG`&uVCxHZ@&L&i%RQ^VcDEy5W(*GHes{1`-t<}kxk0y*CPEjh*aHGZK{(^QC)TR35J=5!yb{j|lUayj9 zrDpCnqBQ+2NPm;W-w>(3+c9W8l*q8CFUX^uJ-NP^QZx4` zQJVf?q<>K2enhJ8`Dp(_Z2n2({?4eAafh??7iIXE40lCTK1AePa1(@5&b(q5^aLeQ zevaf{pTq<;pH zsCz$}>V^s|KcsOlG3sR3fx3Um@I@K6P$%bty6UnLV9A>@7|7ed^YCqX`-st?m^p9% zWSgWvrr&roy$)}~1{({&8gEj03>+#CfBpi&ff=Y!{6-m8-J$P;qRLu0XULI z>rQIsx;_(spA*af7m=u&KbkHOn+0jyPz;^yI#9Qe42Q_Dg*rJG)K%A=088GK!9d>h zv``D*mbX!i2F1*I8_YK4ji%ptGrbOP-v$XlM(W^N==ntlY*&nYoGB9XUbwAX_^ zG1ra%?(2*?8FwI0e+A&?k>QEZP+50!F31Z)Dc7B1m;5P-f&A$Y1uTQM{MjD_C~VH( z+-#F~akIbab@-bYiI_km{-kDZG*OyE&b zH)Av?kDSY;*rw#o={GJ-ufyfGAOZLT8gVI=*Der+7cU?ajoU@5?PIe8ja!vbCzB2| z?kK}mWY|KZoC_MO%TIta%;8RXK5aSt5u-s#~3BaGxh(oD7 zUY{sDU?1t5h(zR`(R8oa>`mj=Wz@;81Cjg4a2*-8e16EeATkK0T#pJn!(9F%PpK`J zzhpEhkDSZ3*`{PYo5Z*@y$+Xp8VG;~(1=T^ncIXYO}`N`(WqyCFnV}wj-YXyGwNj0 zfyN_cxS0%FXq0n7V|6_WaE3WND$l1ahetCSltj+qrfgHpZ|FA;O|QeD9`XU;2{htR zYUZ{lO4DzP^xGg3k$TVvCa1;bbQ-r4qfT}mh&)4vJIb)-b4AVtkwGZsdQ{jM=28z1 zv6R|!c^0EVdE{K~z&7=qO}}wzdL1q=1PQ=%X~d<}%$rr!mbXuK#|T^yTBXxtu* zI+=8!@lqN7T!t+)%DJGix*i2M!yI0g=hK!$JyawpiJZgT*{0Mh=r;~cufySkAOUy> zjX0Fbt=L3q`lFEk2#Lca4nZVJAHvE_LysqX_H&G^3tEEQY<1Z!8S*z~?B^H(*@=t& z9HZO5zxW1?W3VNyM+s>4nqH^g=RgARAF7j9YUX}Nl%_uc>5r56Eh3frJO;)`<=j?= zMXA*lAm?HQ1fi5CXm+#4NpunQ1wgGF)9aM;4oCpLtTJe&X6`JaH2oP!f11Q85+@^4 zP48mWI(@P(Y6@~Ir%(Rn^a-f*^tIly%LjbjMOs`YUh*-{Wl>xBS%w0~D zroR;FFP69vk;<71gVr@E!=juZkMiIy*P^0!C%=PQuj*fc2bqi{kdZXB z6Q${IMEV;fu0y2ymcXEOG0L#0FUX^uJ-N;VbDWmOuj)Xd#U zl%~HO>2F1(>Q-W`wK~}p)m3Ltelu3uU3iee%0#i!Os`YgcR>PhvPzS^g6ul0uq2b(ug;yJWGct{80|lzbWxLB9XUiwBIc@yVJP$8Fe!5K;F+~_?`^U zLR8kBoD1@TP|9_u*d>2TVjzEe~1J8u2HU zM=BDf=|4sKPY{W^gQDrdv6)8Wx;}>y*>#}q5E%}VVGDI~E~u-nI{}uwDT9H$9h!%4 z%iCd$2F1*I`y3F;JDh&w&Gb6F{SG7mkD(E7QZqLP5u1KCq@M+mcsnVY{ysJ*)3_0g zI@xvL?GG~inhaa^S2-8F1)-EnPGJk`zU&kwKlYuHr_`3qQyC4)Bj<8Xwki2E`i)D| z>u`A}^zr^Nz8n+;$P9_~_yg-Hv$gqV*ITtimm!AM< zn8OS6eA;q&5u-s#rr86n9INADYfPDMn;43$hmB=P02UWZ(N#Q zhs*mw0`LwRaVeEo1`~ys1|t)V_eZM-V)G!4Tai&GlMXaKB*PVC*g~V63mU8IQGhed z;lp`8Z8>~|(V!%94wq+}QXi$?I5fQuhkAV+fcY!uq-JhEqBQ-lkp7nv`$+61F%^+` z9fzsgAKk5uh#$4z(cPQ!D+me#uytlvMucP>*_9DNo-_Gu{<55hDhc|W-mCRz=F^9_ zy=%4dJ$spRCY@;S240jbg0fJD?${b+PuKap=!=hK;x9D&Frw1Ma4_mj?@ZmyeShXp zn+DCf#mFI>%rZOtjwVdgABpsbOB^aOP2wPl0}zS8 zm9clnpt~Irk-*6!P|hWRLMaIpTuGpC3j&2-D2mgWP5XP3g2#y@6O>FVk9l9g<8Lsc z+DSMVkEYk+aebgbY|@BFshRr&VVeH;NdG&D6C{q4_$?w)xB;fdcw}#Nu_u>;z3Toc zm}377!ZWrcf`Cg+5sW;Ecw_M?bdlSJ1hlG6?_71C{(AWf7tc>X0`P|_mR2hF{Sk$m za8(Y;v*51ZYUguSG zkf@AGrbOJr+@_DaWo=LYUb`E zO4Hwi^mj?zA#ocb@pURz#%yI($hx4ax-$r&+!+K_E`MRREdTrIB9YSwVHKKQr@{+C z0`P2AMk_UQPY|W)|AF+6Njxg?u*8FiROTh}O#6V=QKedW7S#qplxH}?Dhn29S+LMs z3VxC<^16&*R14DUsh$bQh5_W-(V^niu8je z21$HIX#Xi9m8s{byWxzu&FGA))lLTGSJWB=P#&v=WaZk)pdgE5wVh}w#0q?=xcv|&659KcT#X;L#c7g3u2Ye+wb#B36?AQE3QVP(u# zc5GP}R8<$g5XxmCsB&2dvt?O~q>F@RCWI{u)9X|?I#xKZDg#(*<`yPO(=Ukh^Gkd~ zVqS@P5UI>Dn7YyEZjb)ULViW9K>+2l5K_4;1X(N#LC?stScLdN@mrTg-d8M(Q5aF1 z!@)>1y$)&1fdt^o(=Uqji%5)<7=uWBEsvEkTUi#eE~u(53n7%tLQv(h z5N6A=_!eCxvH~HjLeuM1*b5SXE2%PCshL}bC{4c<(tlfG2}CMxH4NNx=&k2-vMwqN zaw`{u{ENk4-|zHgG12ga2M2vq9320mzW9c-CgFp^x2}b}uUHGqVnjh};b2UeUWciT zK>~0+8Zjj`b3H_9`fj9O0g*`BgfSyAt^j+KnQRJvsw+T##R`buQ&ysj5Ss#Hxtm@m zcfHpEz%7(Bt<=o*5~b-UA^mqGRzai!^vVafI(q9aFYBU;Ah&Xs<^TU@mhJrw3g0@* zd0#Qht6@Yz#d{n~ufx=yk*Qr0Q&KaxHc^^>Eu>!qkx1H0B#FezEX$_gr#j2>YnkPB z=py&Mfw5UOy-w~2g9PBOlryc=%xy%Jrr!|h*OyoikqVd=?GK5~p)_t&MxBg1TvR(u zhMUMxXTGucwe{^)&PDM-D7H8xf?^l-2PIJ++44){hvykU+`yj&k6<(?Yo{fof4Z!B~X&6Ov(=nr8JPz)AM}VQhElXK}qD4?#MQkpGm(_YI+??F9Zp| zb7(}V)XeQcl&0Su>32mWA}@-j7suuj8n+jtPIeuLyi|sJ%CKcM%DEu2x+@B>WKkIm zxh;7DEXh+ErnX?NC3V_BPyk4?h>Lj{Y6NBfy7@V&O;bDZP|!D*u3fqtx^|ln$QB zDE$OLQ7ScaHxi}kZ$SF%B(6myHity}p|Kf8<8EQp$+!cXGs*B~8Md$~=Yq}Zt}Vcl zN~KX!seA@fIdh&&TPlY$8k9j!N|5}#wD)7aRIqj8Th>g3UZ&+#(+KN&8JsH{#o7kmbxl&ez-l$0uyl2WBKkkUo+ zeA-g#7!67yr}R;_seDoTjZ)L=P`VsQ04_lzN~LD*pG0Z;=aK$diKh{X&E=#03b9#{ z#=Xp_lW_+&yJh&23|rWgbHQeHbqcVgQfZV_DxZN=PRNsKOJxtEK^f#!zQ{HeuSCC5 zX?h(h*8&N^i8P{8Di5k93Jm3SMG`222kT01uD(72Bob@J%I=ejcdNQNz+ zMRG3q3_>YarxGYBRVF2+N@*aa>*e{hrF06TK}qD4{+n$oU!Q)X)bu)({s1HZH>MG# zQn@_0zbGAw^n)b^ArhNgM*FQ|vo(#Ig;6Kt4s32C!{IV)VN=cpo7L4Rz>-R(QBtXV z22%OMJejssZp&y;204{8vrWa@(Qj0mUWdxvK?3kcG@?=}x3Un0TUn6)>k@NI%!NpN z{yaME5u2$rZb3$!JUZ~XkL=SA77NI}<(E5Q6to6`m5Wq)l*}rjl38UoklB4LT6~b2 zklPacD~y72$qAmHZFu-K{YJ3qbqGE}X>|1+NF#!!X6}!C>ErSjvHT(u;}D74BcuIM zu{oN?EzYQuaR+XXm3`v&Te5HARu~1h)g>$3@>fx1Q~WBbtjb?S^KY0ZSft3SP}}l) zB1S=Zh*znZTZJf1zY@|<{va}8%CY%I&k{947ZlyGJFVE zF0#qF;4}!OT(k;X(7H~(-#?MZY)jUYj0OeD$=Zr-YI=%(Bg^zUWW53sfX~y2EUB6M zF;SX+CuHL3)oArvY+k2vKV{U(qytZH$Z%&Fw(un9f~V@*6W~CS-pm8GCFw0jgQDal z{e*35d7FMC$@DrTeF74I@6(7RshQh{C{4c?(oaPsrv4L6KaI_QY23byI@xt#>N6Ss zQii?#SCpI!rh-t)6{WBP$@)Bx*_Nz9GeedFRl!Bcfb32-1ubL9csk~EUhpeQ*> z)7Yk#x#>5OOs_-I-XHB!$o*O^FpyM}I75^6E@B~SG}2U~L7m*`f!>2-=f3?u;eSJAXmGj|bD zn*IW$|BJ+Vh*bCC7#KOR?hRD842!y}^DXD{%u6VR7JtIJm@c9o0jQN@dYy894-$aK zs0>=E{4pL;_+vbzzf$6IiAxcwrjxO1ol994H3hkqb1DB~!urppP>Z3qb6L5wbrMUu z=UP0-^i*;%3QVsZXB6NS6*kp2dV>kz5>3o$T?Dl;m>qWbEL%Gv6Z z2tp~eIHR}FMbwJ`wQ@|aQ_dYA0eHR2pp}}r2Z+-2_aXf~5_d`5A#ocb6?P}4t2fmc3R6vx<805iQYqWW5Dz}3_Jl6fDfv2TB(_Pk|<68 zIMV-J;{PNbk$4D^7jY!qM8SUSS&D%8YWk#KhJAACYBg2SWh}y1_DhUxqEz$+@7edOQ(e!BkKNg;wx3 zBoE(~x1o#%#msqok8R2uM!)f9dL7pwgj(*QBW>9!QDnNE?Ff|uosj`$*fW; z#tLTl%=2kW>0XQmC6QCQ2HRA=H~mJb>2)YQ7$g9HMI%b3@_;g;@PIO;-%w(GL}GJV zv_B*^htjys8Fe!5z~*5x+)RcoY|6P{v${wHSkM)eMoFdeDaHya56_cnOXU%a24#>_ zxhdOJd?fuwrRiUR%CY_a9!r1AclUvY^jH2=3&8w!i&FVP=pa!!A2Jbm9o_D8Ja~fB zbl!QpxekLGKd1Kzy>8<%y@rC3p84qm?t1JkKhx{vcU#QwMjB1E)Xa^s{6-=DLJ|ug zQl__K;ATRPi~k2oRE9;OK^`_M`Yt0+yHKp`0WE!sn*a9gFy(ije6!y)TYsy*@jZ2l*g_Jaxb4 z#w?GR{CV^c<81&edDH78|8C6a9U3JsHFK8|rRgt5`U?>$`RUR0JsNiy-7)zeD|wl= zCNIx(df(9U3F(gwFQbbf?}K33oBls#KaHo2fpm3DN$)gO_EIyq#KFq`TS&hcB4vLK zV?nx}R#v`QRXawIZN3M3wt>2qe#_DHIyt5no@y6Uj`4-3OB1E(mqe!YZd4x9r}e(g zU;6eQIDF8kiq7BvE;_CEy|GK3GkLoGA@HD43)mHvWn#KF<>{JUC*39%yck$we<x<(*YTe~4cyWKr#gub!e ztFS>Nz3eo|TYgLZaqNYomtao#GjX~O8oQe*qq-+X<9n*c>@pm*CfNaMCB_>v>QOe0 zgnb|88x66zr5Q2rSO4IRx*BquQinFZPZhuiX+)dU%&h@x)31*7y%LiUi8j47HS1ZM zj>cLDr=bdMGB4HDoG_|1$}!TY5u@?DY!KPrw<@$28im-uYjpQI(M7Lf4PVJ6{tdbU zclAyl1m#@QTN99mka|=|Bc<^Km<8j>itL_Lw+NS4Ey7;{3Bc!QM7Y$r_|U zMvM?#hkmQd^g7E(2Uh^|*R)E_+z*J-^xsGN%_TNPq^j&)t?6|8N3-zh&2gh|i4n}F z%=;H5-?Auyv@dE)M#w=gezl@ZuTvBc7Z9M{&#I}CnzB-;2!!2OQs@q>A)KA2@)oXG~c+4ln0$><>e;sZJe$R2a_ z6<)439b3}kTs78fdYyXpyj}o-wR)vy?jzKu{}|?r!ehi>CeWuqbCq41^_*9P6%ndn2<#Zwa=LGcsmG}=L)uiVG zyQk1A(62kmYIXYLTuz@*TBdJyx+q5v2DWlcuT#zqAOUz~Do1MO<|Rtg&x733r%xy?(>IDPqTUavm1BCHa-IMQz=u@^ zt<=mdN|dHw1nI{~j6tMwp2VQ_U?Rh!oFI?#dWu|&irPKnY{1La7Q=%~o+6NyXnLIz zUjYfg=TsW4)XaIJH2va8-$115US+JcI@uJ}RVPb+GgjKS@gRfOh+?IgUZ=DVK?3kC zl|(Bwb1M*~>6b(LWh9nDr277aLF=(ZhDCir9_8%Gb;e3u5f3u?H-W4~)9aKtl&4$) z_}^5b)Xc3+l&0@N`ffz3ZWv>&)ybx)t~z`2o3YYX!Gla@B8rt}dY#hdiKWf1k^q*P zxz&l%^u0(wN#Z+*RNvPzXg!q3u&6J{qntgt&RB^}Jjg^(EVdF&uT$a}kN})trO`^| z&tZwepTi>k8i-WgSjJkblTA@wb@t>pW2LQw2N~#z#a5c>bxK6NFOEykZyh1SL^^ zj^y_=E|+HjuLJ*Dc6mmF!t(9U&igiIn=)6R-}p1V4u6wC0;ZYRSQ>f~HdS6x;DEO}D~19@xa;oI`I2BSeSbKbUP zoATDA-*_{<4sYKB3BV0$#GBO2?M)Qkt&H@0NbHVCmkLM>v_cPmy9|YcOXws zEOx(;;SfY+-O0HiF9@YvcZyx|rz8gQXU{+uNL&8&;NzgMIe+`GP2StkZ~U2FhrgeJ z1mKP|;!kSkrV*v-4?_9_5Q(~7qG{zZ#O^Rgo$NYLXAdeqRE90o$+@7ey6yy6@}>+1 z@@7vp7D8Lz_8`@um^p8UuuXY-D6#QodL7=nkA1Co!L?W-v z6Npb{)XBI5d53`SelNp$5tVf(=YqT-lycoEcFCWT7|5SJgjgVL`Ll-*D{Ri+No-SQ z@epFu>+p91g#mbU;!i3!lM;oSNs<0cM56A*Xqp~dtVa^N^B8rq>p-0zTI|l1VGDI~ zE~u-nI{}uwDT9H$ot%en%bOm2927I>?Hsl#Q;#XOb!U1V-p&OHz%yvH?xbe!3ZgXq zWk`PsBJq}3+2e_?l3~l|gq#cBf>6pOr?3TeU-rc&|ID@L8w<59 zmwGI5P#!s#SF%mX7twEAnqG&?Yd`|rRp)o#-ZtTIJ_Gq0B@lY zhf=xilqlSGiuCs&5|Q^r(|cp1M-#h;8FjMjK;->0d`N~v5S2rqoC_j@P|EeFurti% z19?hqxzuBlgYw9^e2{HQ)>DyZidOX_M&oQztXbEz&)nz}&$lsXJ{SrYy zcH;6CUat0aY)NY|0$RPM*Qs|okN{jlb<#@B+=4`D`uUOm8xr#(QmM;hV0=^#>@qA$ zt*!t$7b_qLr945iujLETMbs4lwQ@|aQ%)~P0QRU1TB%$RCJGmXk$#-S7>QAcRMTo$ zwN9U`i<*Mm%ITATIeh}^JbkTyL9iGeB)0}(t!mTjRJ{pE0IsKMX{GW8U!w2^U!-4L zqJc;SZ;FAjQkg^<76n%)QO@Ng3Z-Qdm!gZPn*nO&m|mxx9Y6wbOO-(@HFMoWY5EnA zemRL{5UHFUF=$>1tVGl6 zl=yRy0Nh!n(MrwSszhn}m65&&k*eE+vDWHjQ&d--Ecwk?Y2U$v45kvrN;ADqY5Ri& z;65seRw}p05QW=gkiJ)95+c=i00ym#QHDi*K_2Do$#up`ToVs6IgmhBqUm)?JO(5H z^>lZYC^d8I5~b@rxit4JfC%+jhZ9P25;8>zqX{OgH?F^6rJV_ zcb5$JlA%rtD(gZn= z1mMFo;!kSk4kSv`?~nBRArf^@MAIi@^AwGn#;B8B2kM@d;lVO&p-#>Pb=7qzz>+s* zFp#%r^6+hW(*x>*V&=RZ#5U#Wk@Uu!>2-K}3nTzvrV(#aGj}Xen*JE1KN^vEdpnxG z6B|8Q-krdxlU)bi?78yC%dlmCm2<&c5K6h^6toWs-Erqp5d8;7RX;cx^<0M0@q4yE!=9ilY-`AGj~ zL?UvoXgV@BbJMs>7~u0B7;!M^{B8j%;nefl-hDRFQY+u&}?EnHY8t(iuN$f2q4Sb*9&$Za|lNyIO+Bj_TZgYrU6uT!WV z`wignDv(xc=H@3#(|-f$=ara8Vk9CJYL5V45WRJI$fdPRTN{EY*M{(lwISRuUmLBj zQ#gx6gHmW+8+l)`HWt8$%Ff2Y)`sbIDARMh0X$Ds(MrvnBTCbcNBXf6qa_wbB+B%F z?Jrmxaw>rgYBjx1t+yy`oX{B;? ziYQ#2Li)ue8i-V;9+~|GWy-!Nv$_ii|G?CJ2i-m0|1c@PqShdQ@-Qi+a#s*!u`39=^RCeUwL?!4 zKPZ0dPLTH%JHe_LLE6(e*upTq4ry(lO}-{kn!btjt4U0jn21Px>DlDQY~{!(>w>E4 zvJgVCEP|knCy5};mSwRPT~zo^UZLrAD%2CS0sIU=Eq$q(+n6X#pCSDQ5>q7Bl~@~* z%A5sLw<)^&xc{<{Ur}oiK)Ec0R4xla7Ry4=GqNn^AbwE%)@70R70Y51jHqo+9Bf&b zUWc>=K>~1Y8j&V7b6XRo>9<7sEhN4tu^A%qwGdXuY-L%6ci#E&F)l-OQkTSTgLN$lNj=Tj9YUU0jO4A>L^ao2ED6zl9euz}GJw02itWvaG z+7>OCvS{IzWeT{|6rrW)!|9@EJ%!tfHoZ>KdxHevuBm9LT%{ojS80&`Xo({csZ>3$ z+8vMHdU7f2qTV34au1Pzv4_~7683vfSBEbhttXcDY-)vX-6!(CVxKq;BMK`XT5WnA zrVfit9gvuknz@sS()1@G{fUS~(%~XWB*yh{sCEL`6#P_o0{Io|A%2he16|~<=VIF| zn_ee(Jz^Tb-zaBVshK;QC{2GR(w{DIDk2qd5(e&1=&hfTvM#C!aw}(9{{Mew`4qwj zg>RkZyswz$KVn2dr{Z8tnO=vf^aSiP#Sp+!Gj~2wn*Ps7e=Z`C^k>G5#L6torr@VK z%kpcPoxtm@m_iI1`@FL|*D>ZZ15T)s_Li#HtE|a)K;vz&UC1C2VMQ`1! zyUxR|6XXK;qdg2GgZ=LYGubA+F5w+<7+D4k`bx6AxBmi%r z5ouC0cMDOP{wAdVo5b}Je?=s|?!(HMjZ<$I5oBFZRh@bv6jL7rRUYDn*>Z@#l`ayw zpAc4|>2)g9W2gaqM3vD>&D_02Y5Kd7{!WS85vjPRqW#mcd4|S4z^IdPhs$;^$Ua?P zxnK7B(jECZLI*%$6#N8%*;0}SN};4kxs;^j*Wh0={P?6QVL|c0pCMnyC@6Y<+3r5J zDOyj)Ha1PK!=@f14WJ%sEjFd{Zfc_NZfc}|43UWZAew#{n}5-`rx|s!>p-MEuR0O= zlWbwaBX4%N1fZDS78Ad^&a~7Xun_~5FYGcv#IxK!OJ}y!Z zgcgfZGxu+zH2sH2|Gva@iFXi*&-tU%0Ob#p>#=*09=$tluFIq%!iB8 zVMsqjq6?AOTq@cx9h+rn+^mc`8FyfFSsBhE!xlE>T(DVPmI5rPR2n6f%4Z;z%jLk)0WbV(V!%9N*7?8 z$~U6lC^fwfrQ3i6;N~= zg-tmZY*tsN081*BMoFde8A#<0c`|LO+>z0s400+LXPb(5qTi@Ay$+Rof&}1CX+)(| zu80zaE22n0L1IOTC$q8PSZFo3wfawf_9cx#UkMC4Y)t@~0#Q@^?j^L0kT=WHcyj&fk`7Q|49l z8-J$P;qN|>0KAn({7KE+uZYt0zeM_dB=(Y+iby2hADteE&4V*x@ zuS%!nRe6<~5**0#r+Id5S^h7hK`G@dpUpO8=n478vgvhLo}Gu+0yu<5EKB9DTZzJ7 zw<7%|5*JBafJg+-5uN6Y&DUt$)r>lMbRc+y46l-53&CDvkv+Cv6mMlGUJ}6L5)~#$)lb$wj zWSL%vtQA25aA}c5E0sTNB?^DoicCCpN2>|3>7j8CGwNj0fv1&Z_>c@+c#?C$Q+4eL za3D!5=K1 zA9?z%POIfy@+6dj%xslMY0J#kj0QpH%)G%i1?VCA#*FE8nAsO30QE?FF(Wl|vm7C2 zW=8s95qvd(|UPkrTndQ-3nOVwxkR9LM?{czO<)& zZPBdQl4Bpyt$5Sx6n`X003M{GX{BavBvG1v1k%qbF*_pFeG~>pPOSTPs#}Id-POZ} zoQwGmLMgQPqubnc5%p+5tsK+ql=BCW06bP@&`QnRLPTl$1(5!m67xxX9g%7}1*_J% zlyy;4kXt#I@-HT=|6B^S7-~D0t$#kbFdk%jIyo2xrq`k15|98qPo>jJ2yWq?{arq?OwE|37cNoCMV<$gP& zaK9bWFD}tQq;l?#_V>i*UK+OyqfW*hj$rr6aA_H8&#zD+=YonLl=4Wg*hT$8NfcUf zCUJkBLEEF-1B?cR&5v$Nu}zr|(r^5kUWdOYK?3km8u2HUD_2C}$`#U2KqTs(il$G; z<{26{kx?hR4%9s>!|%wjg*rJG)KyoJ01KvqGAOiyx99TkZFzg1(V&<)Z>zFRc`wj! zyqR8yx3@t8@MRkDCN*>G5vA$ZLHh4XtcghEy%X)!l=FGC%r zD(g(-9g`CpB|FBTCcnjPyU2 z*hyjsL?UrabQ&9*aWrl>Mx8u5khq8pca`BFL}brSX5?J5CzSF7Pze}&_IC}+#J+s$ zWJVbkLv23*;|;rzrw5fc@;uv8{Vhg=lFO;yg>AeRr{AbHy$;nYf&}1_G@@E+=6+3- zrr#Ioe<86qBC*^Z?I*;hhsN#CsFQIAmRFWxpA1`AmUF=}9OxRAoi7To;4vtTf?}mp z41GDp6Z0h7Qap*#pv-cL_hTC-Cev>en_h?F^+5t~4H{7_HFLiuO4I)a>5q~)LgFw) z;(3GUv|(&A8h1RSP97b2-dKjm$*_fIITt(!p_Hpx2^4$=Wl~VBjEbSQR98;t@|z|$ z&$Dey`1cqMN--z=ShnHi`}7;(rq>~SN00#AibjM>&D@zpY5LQV{#1!SAQIO*Mf)Gc z=EpSdkBmAQci?(w8J;b}7Ov%7a9v%~0xZ}JN~0iJ=@dg>mFQjbRNE508>2z_ab%GzLzZBR zH8y$bAoAU#=Xu7Mp~G;pOiiybLw&yi3BV(iA+6NRy-Jj(e;MgtM5IiQVJt{LVC3kS zsVs73eD~{UHiwq!YiK=hAR6lbV!yH7ZzjLb3%`cC8gjPVa*KWv{4GgX<-)HuN52CJ zz~fXgtyEqk3o5UXMf$f8sq&K;3(^l7Ggqu!7P&HH3AQS8^d4gX{vIdG)bu)YbUH`? z{y`biO3mEIL}~heBmIYnl<66a1?dNk9TPK^MXrqR{tsF?N1veee2QqO|BL;`cK^w%BAwk+9Or@Af*3{fT{BH7z@(bO@an# zhuF#)f`ap(F|e#muaniqAOU#3vZ0llx#5=8Ov-8~B4u?6V?nyk{4_{AzI#?S%2}8N zt!FkwL;bDRW4mWh){%QzH`LXTOUb?ZN#;@lT9u~Psq$)&0POz)wz-JX^j|~zIS{Ez zdjXsDL-(IMXpnY%_uOohRgOgKnFrBOe`v8D+x_)q9jlaeLtPEIlvS#qr1WYxtJ3s3 zRi;CwBx%MWTUKd0kocl5DoRWT955s zI9bOkW!+F$LoQ{N>L;0-@+wWQQ{^2X0eB0IR;*NB!Alfg!He{x5UI*L84J?++zlF} z9pAkO8)cQ_(Rv)Bq5f9uvE7R%>sY0%8|rGvrL0o@By$%5Z7xl(Q{@970jL+qsYJ8GPfXo+T^i8gS6wjzs*KjrAO;o646k9tM%CKrIK~5Qq~Q1HRMuO zseY1qh=5k5>2<37J4gUNqUva+W^Q?+H2tzjzceCMX>Wg%K5g}hL4&m8yH{kRta1gk zo^C`#{h`HrZ1;p@9jlaeLtPEIlvS#qWFF6}G`&uh&&DeCQaM#Al?SE~g$Je~eGej4 z`5a?G`k@C;3L2yx-#w9yvdZtE^-MxE)Zc17wtI52j#bLKp{|Bp$|}`QGS3sx=F;>! zRlWiefd8aXl~Q?j8c}$58q)V7QkAbV7NqNKX5DMC5oA(mxW9&p+iuo)iQ;r!;K?oc z#(dG}!rQcXF?vlPdcKQj2oVgu@2)VMuy*WxL!CL+{B~Ypq)2>T{1Jpdc9yLM+h(|J%y2x0mZ9l&GHifEW{yS~O3mC(mf;R%hMsQAa6vXKLk+gg@JBJj zB{8%NO|O&T@*t7f(lp9YYUXye41b37J0lX26Bx5JU*S))C-R*o$ReM184gGpqn_Ou z0C^?6EoIZ|q&x{E09R3}v{HE;22pq&2GZ|=NGY$*n5F!3p0X_Rlx5g9<$V|cc@4ZR zWz*}VybeeJuBB9IrE&p~C|m$Urfk=ZR_n!PeHz!tXpo8WTqhM z0gR}=uI>ZbqBo;g5jLU?a>iN)gGO~96fHJp#Cj%aa`vOMkw!LU1lRA=xc%uj;=Y4s zOEQ7kE?xod8f-mzig9;Wj(PM^-3Q0OTY#k0en4wE7YWe0C7l}$Z6wpJ(PHV!1F*d4 zZDcm2M`brs#XnS+-YTh5Y8?T01c_9(qfwqxGj}McO+O8pCTXW=^`qGQgvK4tXpqT( zN%|?njUyScg1e7m3*?{Cs|dT$207=GG^YFLXt66J|Wi z%%-FQoF*wxu`)@?XjJ!aV&J{NRcd>u1iEaJlmMOk(8(kv(_bnD`3L1unWTMXHl#;o zH&VsFQkN#lkm~G7M}tHvhtnueshK;TP)&a<(jS9JGxZzB-2S|UGrhI_EI!Re*R0U9 zN06aD_#uNgo646GMBF;syN(KnE#gW8TeYlXEIPL;d4MD(X*5&t<=n&18UR%5$VrDq=e69 z%q?Fge15-#WmqOGU%s7g%zsPxJbW$Ta~Y_W@I@ez=wFm5t<=n20BY0!1?kU2q=YYK zEJ#;gc0@po96WTfxRjU5U&VV#t6f(=yS;O}E3j*~#75XYQ4KV>0El~tGUGR+;ao=@ zt7kpOWp@>LM#_Z@*COS5kRan)8j&J3bC-hJ^cN!&A2-nLE=M;mmLU!8tvAx!xPsmw zQ#!k^q-Efygm!c3HhFB<^2zNM^~xi66KL0v`O@&M409Y4ZX@B{PFGNPOeXQa=du{* z4w>rsW_q3D+kGIB_+2!jL2Bl%B}&s@gY;J+5*PO~7NnC%&>*cU7(8rnt`5sLhFZ3N z#R$*`aI|bquaoU#AOZN0vZR%oxtod7^fw~?4HDNOQp$hFAV??GCD^eB1zF_E&>*Lx z3Nsj-_n9`#R-e^!3#Nqp2Z&aS>2+#(79;?lPz|(FGj~5xn*Ls-zgyx?M5^UE41#oa zNL!8Lx*tNr^?62&h3lzhMBhamWP%{jwBrOJ<=Y9sb||j2j_i4W!JdZ^jfD2k8Aszo zjs27Fm?H@{!K)h zyDr9pI&Ch}lkrA%e@qXagBgv##!i~nd)c_2>2x>J*id;2Nh3CYi%#o3Zg>u6ztAnA zqr$R?z7dOZ>4Semm*A9P5bwC(e{LP?XR3mfF&LSd5o1F!Yq2paNC3`4BQ~UF?h{a( ziG$gq!JIViQ~KT8F7E4Bu<*FiCw?rAU^r+P-F8N+c}%~qT+tBE7#uXn7IxpDK{F4U z-ER7Xfg5Kx?{tx9WY2$8UsvB;z+1hh*O~qKVmWius9vc&u=FU+{$QjZgh-WtBbv@n z<7T4UoxU`u*H?`j(f3y!=46>pp)MK?5sYZk7Q{TrTpiuR*`RYFVcdxOYB%71liU?8 z{ix4NUUCOcK&~3cwKmQ^dWK=qGYg`TP)31LEVyLQkO2`!GiD6Q>wjAjvqmIc(FgEW z8Zji5OHGV%sR`+~L?niEEglnHL3i8H9W*wr_mO(Z0VXgfRECMEvcFN38+o~Bc$IEk=WAJZcKEI+WnO7ps|5$J;iu26a>Ly-v+-FGK$v)TZAJ>32b-n(Z>Qbk!L&+OHV9 ze4O`oPi1(()aRplH8P?aU1PRt_K;qun)g5g@Esb>pj580fyy;DWGdu+x@}(L;<}T? zRo;m+JjhZdlI1ODW$HBK;6Wh#kM#d+V_xl*xVB$@3t?an{o~i?KiV>&XI48a(0~3wH<+X z%-lsFHT?z1Nas#dx^}kDCS4YssC8PIVcQ&Li!jJ#Ky|l_ru5z$M{_R9w?_N;8{K`C zlI{8_@qXscXS-5p4pJ1l3x!7eU9HfImOBij5LoBfOgyQ&s#`uem_3~9)YJ#GJd z53$i2mG+$k5`ZVr5ZBbq-ARJQ8IRhHmpLq}>*+?x1nY%&A02^!EA=9N_FmG zpYD~}(6GuX=j>gqEUOQdWu2_P)n!>NN~5f#W^TmM%4$wz%4%`CTeH$||E!k4%Cee^ zp;}q#7fiCTA315IW^S})wJ_2zh)Ah@m$4vy;KWZDM|Y6JwBD!2b&qAEp)L^D#>*|h zwrC#O_q=wE+z^_d8dpFj(i`%|Q9oi@jbo($Pt5lmE2L$nbS(+v%Ve&J-t?;>V@b(~eLxbF3En9?;N$Wf#5Yv&qhJyQ^kIKEQ!EC(AJoYJ+jF(T_ajI2JTYa)!S z&RgU_;w^GWzoEqXh{#QIO4k}wy4IZ1_1&NmeQWOCl8q@{Yva0(`8INI;b#^g&lm%g7J)O%+9ex@qBdRH8@6n9#82W-Gv z2z%?d529=6Y^0G8#CzK=zqqUq8iWL!3`2!r+>SC2635df&8@wL)TuT%Px zAOWbuy-JswxxW#m>90qos+XcWNH43N)*HW-4$e;;bpuX6o1t7A)y~J{4k}i|GFVyW zH>#34nNI|Xj8~yi=2A0vt7U$3nYli8g7h-;w)3?F><%)DZ&PCYVHb{;sOfbQ-3=rF zf2ss&rSeo(OY|Q|{}>|ita~GZ^l82SseJnnva=)1;4y z5A3a?Cqb)4y?*zl68#pfillP-11hIK$W+YvbO-6vdi%!PfsTawU&`pa02|Bc!@4PKJq3Ee?s{qu|G>y!5QY_^=}YogP2GE+hm& zFfWy_M0uAC2M?|ev_`UvCoNx)65gop&jBV+`wf{^KN^=uk&olx-{|B6YtV5VQ<8nZ zUyI+sEFN2ij$|hC_#938#>b;c0@AO@d^8D&SoWi_zF664orQl7xB&8-mQ9J&%ncz* z({~}$GPyTe>9=4vjP9VZFPoAFqtl}_EmIo#-IOHf(cQBGOf~;U zNG&k^QtaL~igngGlPJ#dBE|aj($B?En|zC(dWQmqGFoaJAozYQt*j`1qMLBMuw;ws_j?s?FvU0tz@EM8L< z)B6*a$4Z1Xa11q zIFJC;4@at4YUVtsO}{uYRXm>VApJ`!EbL6)P9fEC;Z9by;8Z}$@o^%n7H|SIj zsC&@aNFzKosWP`3!JI!Ri&dLmr)t)}0DnWHs-Y0C(c*MEeRj0@lb!T)x1zktA4cU~X!;|Bkv#{})pIbSkuc5#!<{i({6mHj+KIjr zMnf2+a2D=Hh=6PDQs;vN;5jrRL~7=a1hwf8NBTo0rXdm`7hn)HB0`R)#py!&`V%6r zf`TCTLW|$zN7?iq#X!$*5RHU%F-ZMsnE|ARkVxkeK#Uy0*CHo?1mG1kB1dZGP6V~- zk4O4rC5}NPa<0W7Xhh_kM2pj3=`(WH9ip#@tQL6{zrqK(7g}5`zoV!%6SBT&ZbljBt0rkC#qI# zog?1AK?3l78cms0ZdoJ>w=5$4RfsfOA2AlBPwPFQk+BEA&dp- z{mXO9&=v0wnqLb=ZmB@K?pQ5wXe&f2F!w169EPD4cr$3V3Y-HZ3Y&#S1xn?ILQwgk z5b1A4qypz;EJ&Z$drIs4ook;}%%7a92jj_8yNdbyS}TCc`(RArLwWDo{EfiS%DW4+ zTIJ0L5@pRpqw=I??mkeP{vKqi>>G3k>HVk9cGi6HeY4dj&P{QRCa%2sv9iqXubcT; zkjQvp8f7jubB|i)4~#)3L^A>5K)ROjG9CjBeY7j!!l;#_ZxzGRJWbshYb zT^DI}O^dY}HFk0D({$bY6e(I%epRDEc5NfScF^}3_rZ;^&+q>ue{x(52jkTAItQzz zKmu?H8gVL>dsd0UJ*!CnI3jVnG-E-X{Rs>*=})sRS>}smnO3jFN!6;Pu_|2lLw(#Qi!p@n;unYb^~ zvDvZ^X~Btm0fGJ?7{&y3s>GEh_#@joB|_%9mGqtwj(m?%xZ6VmS>u^l4K~0Djmnjp zxxGMb`l-lN={(Wu>#>+ci>50h!v5ZSJ_cF(Ud zZ0w705heZAouTN4xvmw=t|7Z16V#v(v}3w|#Re&VQ)$r7PwRdu%WC|}{+%OeXSKhL z)R*r3TIK?He`UunG)%d*jj&*+2(6Amg;dg82fUGw6)&t#eL3Hoo?5Hm zdmsV0DUGOU!ZTdeT(<=Br-R@*`?ngLp{D{79>%2ze11H<=$*c}l=7Bw*FSOid zaNhWy)9@zX79d+Crq|hhw*?8ntyKZ7R311<6dpKWpRsN5d#FN#|wv+mI z40|3&G?L5HxVR_ih?B1IhQ^8f3`16uI&018J0Jo028~LRnz?5|ZThE?{z*it>s`iz zbgS!mHgK3;?QC1ua~Sr#fM_I__vIpRt>svoY#Oow@dJjfHg(pjZO|~Q?Y{u3HmR9= z2~=)dMy9g5=nm3V*8Ig*zA*FKlUb&t7O?LtFDoxD65?lhnqFsF%?T2KvnfAXshNAt z@_ePt^J{buIO=I!dH2uOj(XLh$`Pb`{C+)FG6H0)#Pm9qj0TAc7ElGWQh8RWRq_tf zza{YoB5^+kgP;-47AL$|Y62#D(@ngYk!u_ps>s0MSSh z#uK6SszypeS2aR4o{mkI$EzCsLRI?9C=ErSghdEoger8cCA>UH04_x%LZxQzKcF`K z$4LKgi4PHp&=oKU8WExYrNwE*AVmN-4(5 zw00dTUNBlg=NKs+qqY)}C$dx{4j?oITg8Gk6pUI{m8O#>8?Ccc*8>T_wP?hw)XWV# zLCg+8`YwsjiJF+5fs(F&iRH#?BbDe$$p= z&amwBrCeE9K@e^FnB~yFYL&tp(8zKpXjHz`%q>Thre6l>my-B4B9(s|2CdhhWSCE??Av4?1kt8HPU`Xu z68v_stt!*&RP_�DMH%&`QnR%0y}U9;EMc){V+EFrg3Xx5d>1LtKauZ96pkzE(peNldJ0JRs@>NT?qO^ zSc58A{a8M00PNnkpThLOA0E47$KyeEOjHr+9*~M}eqH!K_y_r?YCa#`y$%}Ld|DaF z(->@zK5Amnvo4~MOh3a^RPf|oo=K(QhK2$8oDq)YYpW}<)HPEidNA!*NqPWn>6Dk# zkra$LLjdF662(CqDouxRrBdr0cRr8+97&_aAvJRwf!g#NBK`Uj>mkzO_yz_+o#o=# z91YiRCW!fIQ5T5KLNsnuEP_BfEslj{*|Io_K*iz^RJk}t$!8O~+$UeKI8;QwI7;7q zag4z~$iG}1-$x_;v6Yd$-nck6#-L{lL?fAw$Fy7=8g6J9kVP0_aePl*iKRv9648s% zewCyL(AIBpC>UT3i_=gXv~Nk%;;_*=M~+oM0 zPo!x*aLT?saBh!Q&f;Y3gRsgq^&>PQ_9`OnY7uz#*sMY0cElnmcBeJ9rYu|5R1v6H zQ-Uh9SxY`U(B-;xq#~ygeZAEKjw`aaB%)`&qSnSc$h%xoKS860bt)rywQ)slhe6NI zh(rShZ_qVPZ$WU6RSx`XsQU!CfnHN5o(wyH&? zqF8|a8dTiywHJt1!9J>}P6d~NMCKPOb6TmHJIN|Iv8>>7y4?xr{E~4Szhtbf4{?q6 zzhh0e8rhYw>X1tLU<|+Ly{o^ceAj--xNUsT@9`$!6(CzBrq`+DEsy|wO%>2e<%UV3 zaKj|hUxi2$@-}1I)$E}Z6ZID+qL-(2PM)f6jtkuGEBk4^_vuPh`m@h>a4WjaaM1&L z&lnyA&-q^d0DyNfvy%Qwf33+GKeLrIhDIexcuqYUch3YSW*E^k*PaeY-Ojq)+R8y(r=> z6>(dkrrkftHyxY#DWAFF$#Q?9j}Ur;x8-hnow@lFNC2Lxoc~{G*8v|z(Y|l*s7e&E ze#!@zyWC!)-ywnpP(cVp`2d3k#r6pyIUo{}kV3JBVgL&&h!s)9f?ZM3v-gUqq1&c^7x+O!h@RxtFIQPR_pKIYta8kF zh~&sURw*msAtCYV{=VC>gqEcTQwv(Ex+Nn!@Jj=kRtsUNYk&p~nK4=m8s)Fwq09P8;P za$zw&*0s5S9==&iRVf%^20WK$Ku4YrMa1g(xLHhO>rf*li!rt~7xX(DLg4xt2z$@@ z)->7QU;^Q0?8tk{mf3Tlr6e&6+e9-qP6+-HqT9tTuoG7dVrS2T5H%*86%QJ$WXS-z7kqW5{t1-ETYY2 zw7CQur}e_3Qoh(l#4aj!G3?6ht0A0j#eUZ#TXY>Z4j^MtL_ms!skulYH`h`mV2n*v z*vGNAuOUgYhFi<2;?-KHP=pFaH&6wtMQzh(84^JDcPI}a%4>BA&&EWJ1W7K*l%!>a zb10zTz-p?GUwf9lwg;*y?P=~5MUg!qN>NSC`LYW^>w#3=D65D?|AhQOWF?1)oJ#jb zK)nEsYTJ*(QRGCSHx;$%M-5U$vF5&ZFcngtx(X$&ngx#m6BG}^j+&3MW%li0ElI4v zHgOAWZlcYN*f@P^sHijyJNr%)r%04~1qo)ycLd~8L?j2IXc1XUHp8)*VsxH}(N2mv zL8{EnP)gN}vP!>dhLMox7~TQeR>iOqOo-hW>?nqmEwk?jYf0ihY!mm;<}PfU@FgLT zqC9&=A{0B4O2^JUT5u5ftDxTlkO2R9RA<9E-Rlgn&mW9MZ(-0flnx1$Qm_T?vcGP~9#di{5 z3cizoZQ>Q$yo8O@6K@vsw_<0%iDF*3;oNyMuFf>m3X5u?&(I2se)mc&#a56w9WcdG zY&HoJvphcVdW^KR6wiqvV7&0e45X2zNSi|Vou%7}^<3vyG&(o)uVH7BIG0fFfM`l$ zib~mcC&AJnsZ|b`y8v>q-+%?Jny*gSnS*^Cb`)&N;^+VH;{qj#ZrCQeV&la5L|`c@ zY$l`w& zP2njV(dxYwn%vsR_$WN6`#=EI#)>K5X%2yM1at}Zy#Xh!HLMi7@deLjM2SlW`3CiCJ@fVj@pN^W%iNKQj$0vTc>?mP;65^MH|P%J$BM_op#FG$BE2b zNJ~iWDJ1Q8%G0xLcFN<^f&QR`>UpTeK5@P^K3xJP5MG2G`9#?=dmyxwBnDvX__Pqk zHsw>a!8b5=kqNT3OUGa@lu<)3$`mBL`%e2f@Z}Pw?`Z6~n^U@2mg=NCt4ddR!ReRl{3*JlBz8bLPUk%09iQ~;E z<{l&Nj$KQ~4ua7c_#nf!9W89T6|!s_=UZdjn_z-XtH~zpDO+ZbW!p~2HgOs@j)89p z(RZ-3$D!Ch6&oB9pT#SsOUYWQK$nsDihhb}(hQE=1u;5AKFdFY{2r>Os5%w&sYC*5 z-`5LqT$DdxS`N5h5}P7N@IwgdZ{h-T=jIzICM2J}jxO$XVA@Z@?inIKnr_IqY)DX+5AxNIGXo3|5xJQE~qYG)O zAtJ)|UBJb*bG|jU?*%5<+=Xn$p0Z`O&9)b$ZQol+{R=z05XClOunTW~($(EISV|z> z8^3ZK7)+Dsek7RL>F!MXdJFkVM9%%F-#Vm-QBES+e#e1=w<~zrZ_c;I?*idb7(4Qt zvSoHJXemkb#5U0b8>iu7z_OgVFYU~2voob#>m{BYq@AMD6;%Hr@3EjavR>v(>Ikm`?}U5sKLp8CKe+4R6ecV5A#;RC3` zGJLWej}HWz?EFqpjGKg`uLFZty4Y`8i+bdO3a^wPzS~h0>WN%zBOJC1rrEM zup_T2i-R?^;9!ldh7ygnLrVBAO` z>^0|GWsFI*34~ zi6?vs^a2Rnabg*}v|9^S+>JnnwyVTkpUhQ3GzlnTF;&p5jtFaNz>|?jX*H^`x z4Xa?cSYN;_`rX<=P5bakJJo3^ewbD>^fZHbh~fTNifE`vc)_n1yoI7tt2>*{=~kHD zqtx0TruQhbKLl$@;(crr?_wiNKQKiF_<*x^;zTxwom1q4{9OyPYmy??+Q3?p_#WHDx7Y~N$CO%Q@muZoPbl&Cg6>8}>~)Y+!AEx^ z4~Q-8f%9ASXQYS{mp8ZrM*IART&Xn)rc|fM2I{iR#<;pn;dF+{xE?2J)Jh)iuWOk_ ze5r`jt%%Hd_?{5VIj_wA1FR*9-?2@s$3{e^xfwsVg`quD>}F$UZvwg_QThvVDoXo` zC=qj3l$tLDZHj2qk=lkF^j-u6<~3hT5@cHoJzqr3XovKtS{49Cu$)SlYIGd1KLy!k zBt;hwINyq(H7^4btfDUvk#&?Uvn~7xXGvl^bS3`A#tGn!LUg&<-He?bg5Zt>unpug z14zu-0lW*eDWXjWup@FX?QS4s;yolmw$WK!ikJ~VtatREeZLnnh@w+-rN+ro3<^g2 zA`wTC^R0>EvtWX0Phv+VQnt+A1zJiHov=;pgpCu$=Y;6Cq=aBDDH_IOydtOU{4=cNRe&a4T+gp(*5vl;E148i$1C#`8a~R3byx1 ziuxhvTNA@^ADInxP{!np0Z_j1X@ZGVQdrKuyNeMPq*!mJ5-NmS>+C{&CqmB zR2l9>Q3S2+*)n^7Xemh)Vw(1P$)AEvMm z2D$?t+J`_+HC9}BN6cyOoMUTqAJC?VHa%SXA_vp@0wELokp$Vs$5~?bJkB;B4mk{4 zr#5}8Lh^Dy?=4vSlN1eG&bKC#BftdnhGIu%Qnt+Q4=p8$Bd|^M!^Vl^u|l*|?2g0E zJ_@LRBQ;Dw4K{Br#`4@?_Aah*m|i?-1l*+9?{su^52zA_qK;Kr*gcaCPKq*^h{}-$!iDR%$lwjio zbfOTg61z#**~5YQ2UINkMnFyl^dJ#XV$KdIef1+nwCR8zj~q;E)DRBnFq9WL;8X(1 zU_MBby6l7WbT0xB&pwp>UCt+p3GtW}p4Ex8R2x^vtitXooYwTYMCJ^3Dc4JT3GCK(^C5Z}b6Xn=A z_R|Mc>?#%ikFrmOyYd+$)oUqUlRj*~v4QW$Qbd*E&Uh3->my)hcR1e~cU}e)2%jf6 zu%~R9JsDa`5|gk^RAJ+|^9nG3cerPzsGjR6xR-E;s50ECK@qgR1!i`K^R02m`CNzm zs0U@s>?UX_Ni<-an1YSt&X>TTo4)LU-8b0T(}3=PhxT;HslG>Nm}o3wPJ1Vhg6lw= zB3d=o^f?Z^rj)HR_ry{wxh$Jy* zM=}qzDWX-8>^l!Rn6`_Ca4cq_yvPAN6G#U0QIOQh@VbwJUA#y@zB|e}phViLi8}%& z5O%|k0!mrDgaKB(gn?~hJ~mE3>5C(Fy_z__c1_$QtU`tnN1c!ArbEU-Sb!p^DFPMS z&-vDLh(2Hf;lX4#_LMENFNcv-jw#>c*T1pbPVVk%W8^@iA!2I2* zV|Sqm9CxMz z^LIxaR;eDIdrZ4SV;`N3s50Dn07cMx9+=r3&bP)L+?6N7`Q!%nl*NOm(1Hg~u}wUL zjpGi!152WpVrR#(tPnQ>wqpp{k3$M0U)%=}PEl>w1%OU)YFjKtgc(jfh9VGO31W7N z^R02}W??CPBZr)#Y?=Kmw3H;C#y0UJHjY#D-5Q9jz%J9N=OLBh6xD7io`sV-=jKKi z;S>>OIQ1NgKzt8~*(uJq#;M1Jr77&lDaw}FuR=>n;$>_TFJj|3Mc-?I$dh9Cl-SWX zSM1jyl>zX zndNa>EQ8Wl@m_-@7D7(_H#BBG?yVNQ^aT};DCb)f(a*pH13$)&45e(D{Q+9|rGivdl98BTqH zBIpi;9H%(n8mH*HA|TuuJ93J$W%l>bQj+)<+r-z{I8M=*MIf@9*mV&*`Z|dHBZM;j zT#GX0Cr@1VPohZl{oRF+#Gm$2_WiD4O%bc=`+a{w4%+{%A>7PApuETdyAw!e)71u6 zCkKS{>@IHoi&qTuy=XvBp9bkQ>-jw#?oST1pcC!ZxutHjX=&0NW9Fs9sC)?P+)L(ba))ho~~#>53v~y#mba z4(D6r&QdUe@EURhd&=Sm1)&8$D2Q#MJ2s9x*8{WPzCm`jgR)yk95AUKenB?v4t2J> z?G#aExKn^4XuSo@><;H!wE(oqK@UcdE|TFWVh4 zcBo!U@nddx9246<@Xu&{$oXgb>ylen|~=&vN{89+@^WHreFN|N3L(IiEdBt6vN zV-Ewn;8EJ6RBifI3az%tx@xCY%i4odr8FWCcW)9-ZT@IVs>lGCjS;No+(kPfJm{rT7h-;wKzSk&L^D+;OlML=4^Wcw7yE8eeADf~h1i8Qa7pY($_Ylv-8x6lBx=%qBFQ z~6!( zUIa89ffUs+2jzCXh7%OMMs`r{pc?C=A}C`J6#H^$Ko~x;S#>%fcao$ld}Me!d`>+l zeDtUthi@T-{(s@yyIrXjF15NMXkomXfXjn;H38d1Z)`-s^6kDzb9kIzQHzvX(Ne3R z)QXi_cBvIFwF>d5vE2`1b}wxBb+{BUv=o2I^P>n8buIcxlz7mOzj}IreWbY-4N-AH zEM1FV1pALYz+8)lW@fD)Y#jX(_EF|q^ixWnwGJfDxkDX=ggqG)Xs=W_MeaIpSm1}- z`c6W&)ar>q9%LUudY0tldG;mwotqb;#ra3adqT&eINnQmgde#k_cAVT^unvB)u>z~ z*bWBUA%bmWFR-nOc5c3%29;YkUmWRE!v-9RDu<~Svz!*|gCFUrC0-%a4?>6ABT(S< z`gR54IyHW$1~1ks1kKj2;O@9;O0?Zwae8O>u6SAqZnP^{8BbBSA%`Gz9}C^5387Ki z72F?JhJzy&9>!10yMJs6S5^b^hyDVM$`UkByMm2abq6+fpsAzS{>~Qf$*-dEM6N*Z zjUA|MHi(~4p|e|dPb3CKn$HbPeu^?g@L&B+z&@y6Y7N8B7*LQ(t>L)jO3hGe9c%Z; zK1Ce|KmTTno~?O$13t1xeNlk8nj64}^9Dr%=?=?XZ)A#SNXQAe)7R*E`(}*d=AF4b z+@}s=rPgt1pX2S5kv7&tpWKcI59QCql-Y+v+CGt9^rr#Vxj9AsgeYK+hyaZ{ga>bR zQU6RY=;gJwQRsYAfD{QMPJ|Jo?Nf<1J*d6iaJ)qeJR0XN6-3wGh!4a<8Df2sr*W!n zQl!HfNk-#NMw5_nSdpd3RWiSCJr|q?L;q)wMY^?yo^B_>;xtjln2?C?n2JjI@t=X9;7sB6haK#!W;K@EQ7 zo(d1|(*WJ2Ry`V~q10*whbWkq!QtwMDLN9+1R^+8C+*&+5kQI#Liiz1&XiiyK|RBs zeULb&K1&8^WUHby#Lt9Ys#P;L0Zf19dLO(5#;&h^`>`k{_y{Z>bl{wq;Ggr2apBlUz(=z6ga-r($)(LNYzbEC+& zSphtOd4+p-TY`PBt`F)s#0@)z)}cU*ML} zI10G=@pgbwtt28}r%#Zez8%)&RF9@H!KSR=LZG%KgIY&;!o? zL1({8Md5a^_(Wlaf;A6B6m9{OD+)KcWi$>w3i!cKQxvQaezwyLt~7y&LHC{H2>8jrU>wBX>hf=YH}4OE=}}M?hYly(pXRXN0Orwu@y=$O{attW4HaYS#3Zeoa?( zn^awOL^x}!-H4`wnPhVsIWL{g$Ez}YZOAqkqw3wxLx2#nr;z4Y^6?`l&P+DCX zKpl%`_T9OKo_Dmp=xBS%(e|>^_KcUdr#xaU6}{l8=p9GVdyb;_9Yr4~MQ?g3dOeq0 z?|N$c)Y102qwNbv+m}k)$6ne#%%$x!Pi@~i+P-(R{orW(QEB_iCtlxqa{laa{_1f4 z=5Vf8oNIkJfAQqpQTNURhx*nfE{vUZ`78VZJX z5q-GLE}{>&#YZ7UAO6Qn(Ka8Cg1dNi-`=b!&&tDk?%-VlgUajct7y^`2RB+cbiw4@ zUr8ZTtY|&UTj+Rr=^@?DL7r`|-36?8@8$7HZ>Ue&WB%ec`2jTf{@O*`;d$Uj7+dS*uqw3zN z;UU3oS+|=EA0|D2P!X*3BDgmvK}r#<^00n{yFi{OQv1aByU)gIQDI-b8N$b=c`<74L_dM&aQFTAm zaCPW<-(>B=j=N@0ud>7CNpe?*+e6jeO~X~E+0~?6b(()Eg1tPHkCO9AcO}-gIRP=OoyPbWgTpa!O7COfr_BN7r_xZ35F_y5-)=%HE<=@6V&nY8CMmIreqs$utWH`zhgyyf zq4}0oW3swJnsb&SnC?X|H7CJrMbPX;aBfb5`HG;$!_$e<&`XrqMSfz7mDoZ*vFnuB zHPUM5;*dp`hORPMJz1J_vm&_Bi{OTw1a~Qd+r0=@QHeb#t=3P}pD|fIO`7wDB3SK3@JddC4-~<>UIcIFB=}SjeC*-r3~A`sO6&_i zu^*M#cYb2)mDn%R>hwvDIGtZ-vRqvk*sMtYG?8q~Nn&-D2it#4B-?V59MVma^y-F_ zHe4eTS5|rO^yH#JKCRcOmqTvWVgUn2XQW-^Ad=za37j4FWmOd4-}VISC1>Nm^7qjYE^x0jdoUfmTcr= zC4W?YU}SAAu2-s4&vPJTS^am2XPDwS2J+R(@|vc)qw8y%>Wa&2Dw5UGl0Zuv%*}jv zU>38NxTQ7i=P^EbhqNE3v>%%v7+BF*HI*;n7T4mI#B}{^dJdBg-yzZy6zTChB!8-s zKWT^L%a#1;`GLXJ)yLoxS9SJZ@w&s~Tr$H&+%i*Tfy-nxeRBc1XTS$=C0Y{B@A0%a%OS_CG+&9H?gw)-z`w zD97=%0|O(=CnQJK*ES~6gJ`&DL%Qj}z`*Ki-032OZf3dAh64j9RwbvoZyDeyI^{rI zDQQUJYH5A4LBBO7CcN4M1Eu4~H{g1Yeh8TiL+WcQP{Gh6CLM?tu1=09udBn=X-^>z z!B@p{F8I7SP**Wd?^|jD_(2JM3!%n3{ic8A9W0Fb!sm@1K~oLcfMC z2KJ9;){TmFy;*3B653Q8m|Ux0ix$EC!(2BoSO(_rVsoe7Y9?r-2&}=z$aYXdZOuYM zAS5oe4;mc6<$cxVxCJjbPoi_r%Ra56TN;*i{&|Lz!zp~Uz%k*5rB;A=Lctr65(l2; zNbO8FTSNCFC2qIUp=B9zfySzeN#eH3yuJ7$_RK(Yp!q|n<4f5OLPqdCgp}ZW7%9Q` zGE!;2RmkPyoAvjH8dWREZ5ugV^U6cCeLDF5whvIgwNB2&nDp^HI4O{ zzSJR3&|1M}0tZ!B)!=q=2rlyxia;wklb{k02*#YR@y{YTqvcj`F5ybQOGS&1iVHOr z^Kz)Th;VN&E+)uJJG@xLDn$G*b;&u0Y7T_8fFK_SFDKkfJ5*ewskqXtVsQ=?*Ai}M zi)EUMrIKe^-P z-K5EGB-tS~O_OoEt+7^LdH%qPH{{^j%3NY>{*^;^yC%DhWREFtm^i9@oNER2v$Qg_ zN=!L)S1y3GzjS*|x=l{$oi*tWIi+{iq&wx5UeD5WSMhhG#GT%aPKtc_g&3S0^_lmY z>-c8rI+DFW28)YTs;;nx5s zMY;|{+N6t)OO|yAN%-mdQ~LGe=qh zeqpg%TF%I4i@MOkaRZe%CMVYoZ>qw0v? zv}3*%{7Z3o=>W^uPo~511=4{*RgEKS8>+IFte-g`)`>JBxgK$_c5@D=&){dAwrl&3H zCy_TYZg}Kl6aynY&X#$_GS*?EuK7O}buZPMsCCQJsnyYT9nAg3s_n15Yq!eAb;zJbeq18bYRTDz)Lgp_@M({d+o__v4U?i zIBIfT;1$4Do6Z4-!_-E>cNiQpy^)_gqWbgzf~pTaA82~s_0#jApPr9$>iJaD^Rc6c z3=ZiAb31>jNq*)?dV2m9gMQ9^r%`=vra~CjYLeeOlHTV1rb+(Hl7q4v#yrU{u)|*r| zW?=mUTB>QoR2)uTXH-0hse$5=%GC^()YeZf*K5-AP~2D_X=>j0Rr78Rrmr-n&wZIb zWz=BsnjC6=(A0eEtLEz*OzSnKUwoO?F={Y)Z4Nb?G&LK2)ojSY^pD20m1W%~(IXqp zqS-h5QCY$53?H9tXsSl9pvM#F?5NQS2DWDOG-r`aJq^8hC&2RbwLOcvdlp+D`j!>k znFTzQbn;j7FHOl_ENXOf4~E?~Sb=6~!M+T8Sg;=h+JJJq83QccjCiPUxoMk}#Ql{V ztSLE&MU8GA$gt7PLm2jO^H2tiZXN|#x_P9B3YVJ$O-cs&D>+3|GCEV#IR_H+*a?if zgMh{q9lDG`LkQ3_$7*W+=d0$_986Uj(|BK|N=6L^kISK^R#Q{$tLBUxOj9+c29|Z3 zq)iJ`{HUzpG=@Do(sTxl9cdO|*^$okP~qxGvrS6o_$#?gQ?h_Xjc#7Vu%WY9!G#Qa zxVeY{qnpP5h%tMggb z%za`hTNHCN?OvqDpIv#*-v zj2c{B#-OLGyl}l+Q*(!}n%izv=1}vvrsfe}H4o=tdO>4))|csN zMhyl(nM2KLP0h=`YF^C2^q$7_Hp{wA(vDDXnyD=7bp{PR+zP(Wu*baq0RviZcQ5z8 z1}q207cA=Tc4}U?tj`!WTJR0S9u|DdfYE}DfTacNS=1PyUm12A=q!0H>t_ay=KaC2 zhk1W8U^FlIPujfg9{RNa{q1i-2uy)79u~A=z-YnlngyL%)EJ;$7&Zi`6NAP8?ZL2z zd3!QoG%p{pY`<ejCXs4K%p3nC1ASP*5vXhBcF(t-qw8Uu6y!)^n$lcs|h_OPHA z14avu04y!&>!Cu$fUcb#X;RYPU&$~{$uTTybhCtEqnpDS_Hc6q14cJT1D0-%@=)P& z^CXj!ll_&9*OXMSsL{=GhK+7cVA#XWi3}LstOqRJto2aga#PKTN($U2%tHs1+!y-R5m*r5iTvKy{ubQQd8eCn% zpuyE^7&NWomj-MpA(m95?M}QL9`0EwDSR$HQBk6 z(JVW~GmQ6YYBKr@ZtmZ$p_&ou`Nn5~OCz3QS(6b@Fly)yk1?2KA>ALctVbC13)RD# zgl47e(a$k#YVX&9N*7*bNs|jNGitE%MF#z>d|s2tvJwrt2DmijLzXoe@;;-6SiZ}k z!OFK8^t19!O~T8{Z-GlIzhYUFm0vJwu<|no4OV`_ps>=*hF^e78-8M0lMO%msrf#K znk|}|O}=XW@Kf`puq+R%q3O*S0rrv}~()|dwRG7VtV;LVYKYOLT8hE3iK2P(Z8 z%918;j`mXnZ%)vdj%Qi7y}Y0m=bj_YRF-utgNC`-3ZBStraO2-Wi$ht_3m@e34o=e zl`LvBZydv(-NUlRGU(TdPuC=}I!)_N;kY8ia&w*Dp2@eO}W7xxi_Zcuc@C{(;z?UrQwonW5=M4MV_^Br0 zVdJ+9d)W9L14bJ+0hTsyWKm;~H!$pWK?V6Y2K^lPMU(Jw;4g+f9N5f&(Si0e(+;#j zIxxmy5NA=hg&bsY;vHky(?*SNlPn>vL!TlNbuBw*>^2o`lapmp+L z3>#e-%CMgcM{5!uE*!_OhYQCuV02*&VClkXENX0`Qy6x8=rj>6oX0ZkVL>?qMhhkZ zmKIF(P@#fIN~%ptCi^QnQ&TdHMU8GYF>G}6EQUSYJevWdn=OE)o3lMsxZIp;QZmn9 z$t{|a<(Z!r&Wbq4{BDVFHhGw2xt%esz1(N(pMD4wpyslYwJrK5MUtQHfO4Yzx% z5fj!5Z#4vp8-1FZhkVsM$f&{9`x!L2dLM&kSDytgU44pWO|CxSr{=L7YTne;yymOs zRYnc2zRaM()fXA`n}D9zB)r=F6W}r!AF-?{7#}cdu<|_y4OYIxpr4g*X%b#megj-u z`6bJ`?ciY;;w!=3^Lz5N+kd{CDE`!Myh-u;<4+GUPdz-&`ZJ64_ytWJ&&D%{gZx zInZB|@NnQ5hCLh@%7D><(SW4`qgd2!p%&!h8TPYrq$c5E<4FvA*myDnMjQ9V@8?My z_eL5YZ>XBA|8~qN^3nf@CfVI2X<7efh+e53S~I$~z7ju#BVXNh7UKJ{gz#1KL@dOy zcvzt+x>>L_x?WMNq!(bVr-;nNubYRS}=?LRA?oci(4!|YxyNFZpi2mlJxEVBk&gBuo#>E;LT4Z)0yPOK5vXdUC{XlzcoON%@KkV_yIsn;Om7!?wp}HV zCTcQgb-<8#gM2-Pl#JOgNSp7@tz*B6YN)y@nWY}kcCvkl#W%U12mvZhwu*H6tpIn)$tYGS@>qKq0`&1cZlRi6HP zXlf4dRa2CM=`fAyU|*(Qj2aB?nM2KynwoyTYWn10D$$sVeVGO_YA|>}4mHCyHA8*X z9G!#d1dZuyfYd0Fz+k|jONV+EX|w4qHg_K zfMzjlv|t{?9u~}Jz-Yl$fTabCS=1PyMGU(QQ~|n-L8EzBGwfmBH4GTdy9KZ`Z#j#) z^=koI#<0)2ii(wBp-)6w*<|lxqn;&_oaJl)ZNy%saN`BIm z{J^3{H@{=p=;k_xJ>2}60i&Cn082MFdZ=)@`Ikw_W`8An;^%Utk}gP_7l54^bq4`` zR;+b*VbC)Kmeq+t!+675_us&!4g0dJ78BQ6cOO4Bd*x75sHuths);gca5bMngR9*c zG`rdpxO6qavL;s#@KaNiLrq^z&7r<(4rbKgYA*&oUF8Mf08PyizH0jAU^+%)8sf`T z%&5WOfjQJ1tEn00t7d2prqLSHD3*1b#Di0ejpNN!mNk+=Lx-_~Co$|Xcbv?C)_L6P zsU%?8&&IK+yA{>kVOe7tHd-*AVGj!?FkrM`Dqv|r1B)61G=*Wefoi!>%b?M`X$*Uq zH=O~ad2;|u^JcQBTfY{d^B6W-a6ZEx7PK&6v|tfnX~Cr|Y7Ec^vLmnzz zZa!*K@|eGpw)4|Uf=HW>qX9s1X=MRRnyid4YH0B=g9aD6F_?8NU$iG8)f2e1A;GdH8xHVOQ8(k4wAKKIO|3N)sEkwzOPV4zm{Eh3gBbL)@+eIr z%StraiNK{HWh`qlasq?Kr^=EH`#DjeNn|-;1*b4<3iUZa zrH5y-q{+kSj2fJn%AnDSMuz>IsMjR2oIp!l09@KRmt{?Mp3kVk&e;qa?VQQ5pPlDv z5?*#L0xs>mlx0nJE@0HqV=iLQ(+OHDUCywnO|JziZMcdhO*UNNrv_2KNn={(%XB@X z25+wOQ)2~hX4vG-oj|2Gx3Q$jn_Kp^#G5?MXS z3O>THDHzWImBDzLB~8J2l2OkdgdYfJ(9g<8HHj=M5zE(rOG92^S$DK}%_~k%Ut-u` z$qRmZtl;YmXGQ}r3%$XB=Dhp#bPZr>-iIve)~}Z2mi0cvA{JSmTER~k_ORen28!j5eMQSlW0hiyCb_nPER0 zM{5!uHjZJ~!^W`;7;QWku(a_k7BzN+84SB!P#s|!gMJP)X%Zd|oX4<-1I-K=9asQZ zI&dM2x-HZ?!hDAPY@Dk}c-VLe!yYzX%7D?v<$$G)H?XKN$V(Y^yP$%+ghAs<_Zo)% z{JTn%@bK>@hCTednE|7J4+56{tz=QR16mv0%dpXfyBYR#;Z9A$!-Z80d${lr14b8~ z11w#5nnjIG^d!S>51l5Wb^P-Tdsy%S14awp1S~Ch%|nF>A}M*xq~vXXC7)|bK4DR# zn;$c5bn^>_J>2|~0i&Bg0hVt5;Gx3h<~oy-pZ%5WbYWUad!)@5R@*Y_4gwleta3vP zdWHZ`6f!8fs@4(J&Sb!7<3hmF#!Fb# z803o?cDta0d?AB=4$RjiJRDfWu!jSeGhlS!M!?d6>si!op%&!p81}RAT1~>k#^nrq z*mx5IMjJl>+&vJ&*U&yhiob>y{79ufR;e{kiXMS~7wJH0J%5N!y_d0spDcfyptKd@ z@Ptq9;i}M=fMhg2BeALF)lJD>fmuX>j}ZmxEb9|hevnqq)qmvbWawI?grPsF)H)|c z=6#2>BBwVch&*gr->7nst8yma07%;Qs}k!Km_xP&QGGYOkEhBH(#pB|7OqaVZAD7h zwoRq}c2Z>9CZwfp>Mf3Z%lbo=gIvDdk%0F85bU9b=$koZV zosbf??W|IroD|vC4rxVBHqh6h@YYEiRgTv@R5_D(0VI0Q?ha8XxQ9yZ>707R!Xk%(=;{eTg1m=A6bc@wQazm%k?)VRBA2nn z_r?oVxfb&XTYe}YL4KG+6bklHslHB%$a^EL$lE#%dX!}yq{>0A%9(rsAVGeVLlg=Q zRH;EuipY;ZT9VHr5{mgi%j&1f5pz|}v zI^JJ&iY8h^qWJEo%c^QF#OLNUuar$QwAxd>YB&1TK96ft;AbHvzW6;GDe<1u9He-L z2%Ybws0q$S+7u*waGOw`%EbwQDt+ zt4RI?hesRISL^`KGL2^`$%E$5gSCm#vX<-s&8-^EO(aj|5RaMzE$hY|;JHiVxt-)k z)>h&B)A(Ym8g2AhRLfei17s_ij7ItcNQowY5GiVMYTkQ@!|5(6Y;=v{egZ0Ln`$sh za4hD-QiNY`d=!Wr;SZD4(e>puP1WV~RgL&IydtrzRo>iKl{~9aJVjE2lQp%It7^n& zvo(q*2s}3ZMQsgw%z?(~-?9~x^&3o2~)0F>&~@J`WH}F%2#r?GAA)n7u!bC)2eEE_mXQ@)zQ#L+FmU6cR)%s zVn-)MmIRRwjI6J%$auq8eBdxZ=!n|Nrs`w{E~XDW8AlS6S%RYHTn$(SQ=z;9plHq{ zQbPH7Cq>G~QsrZl(@Mvkk*v^N6(jR>f(3Sb5-a`Gp*nt>7yp;T(?DSYpPH72{VL;|Dnz*BBYUQ;a`q zj9=$u{GKFgr`04Y>3q-<=ZS3N&&(+1nYB52e(~Z#-}-}D0z6x7AemxJQ_knz)g-C9 z$!-foH>aMs3(|qn<&%;_rt*B8EuHU3hk_BL#Iz6%2Oq4GM+{j6L&jM4n5xqGrpF3aiPX&w%7-@5{m za#6F0YROO7t3&c-R64l4v0R&Nq@7n1R#97r^^ZD|ICJ>JOiV4BLQ2j<4^jp11Epo% zPhe&r+#n~mrn9|6<){3ApUMZ7*Vk9MmZDpw zU4LjC8%P$%=0+SG@u7AtVu3EsFO6+xaf-`!q(n~(EJ{b{&m0t1a0^LfPj=j#ZNMas zUOQ==7SeuZS;4j>kTK9ll!i_9U+NL5Ud*KwSRy?u19@pGxWsT`LfFC!hmBrdsu_-hh zn+T{RSxd;mk26sw2hKEEQKRG4@oW|%^>dICjeWk8B4?Ya;?M~-we`tjIs;E%D736| z3B#*6RW%dzUqTTx$k}O7zZyXxE4~=Gn9mj*O&ZKL!I@7Vg$xZqQuHv%i<22`CJ^qdN^@!0p0blaqtQI+L-V*l&C43i3!XHh zJ3YtPjK-vXLe*6o^SZ|JDoKg}dD;CQi;BVdHi@24Q&mx0nary3Ck{cD^`<}DXUryo zxyC4pv&LMScue%WoSH`1b{Nv8K5z(OrasU+4eEVBG@KPYoZtq`D=pd@V{Zf!Ge$8m zssAXFGYo_NX%+gw7yaglH0Y&&Fu?}>!+|+#ETm|JP$wNqH4K&^Rf|mQz(NiONeR>I#o#P4-cME*I6N$45c z1ve`=gNmwLMQ2e_qjnf}F7GZyxs2qsBxC3qF!)AI^m-EYo1b{rc$sU^A^cUO#BpV{ zlcMqS0=!J|6%Qz4$|iE)@L8Ns(ReQdP5E zU#RL|s_I{9)jy@`gOlUSo2nbLSVZSrLn2w2^87o%vQ@tJ7hS7~e(x{3fkmk~en(0) z$3`bbZvRTv4I}Ai!i2&4#7Y)h)=z0rpIDVU+klIB|BaMT{Ew3&#haxr~pgPrmG!;cYD&n3hgex&06;?1osQFlU2w>@BFA_BbvnMOb zJO~LNdoY%H5K=xKsj2AaqoR+e3gP3SJ}RtWe?ra2xe~x)@cb7k(TRr1RA{(Ljc`)b zv5JxAGeqr-&awtlX<1`=edExY$|TlA+HIKu0;AKltd`Eh$UTN|kEz@W9Zd+9O707n zC!kbVeKJzQ>QiJYbgD|7=A_8#Nu{ct6j@!4G*(yR#8}mWC)$1t!`?yvpTIoLw}MGRy%xjN9uowJ(Vww0vO?nt z%5tp{rE;iDA&HDf=x`gTmWmCLo-8m=Q!&%cV0Lk;Gu2=8Y8Dl%_bW(rkm<8| z(>WwEPU=w?mWd9Qo$ru^Li3Rl=NuOxB_eqtQgqG{YI~7H+g>cuwhJ7T;yep!U$2@; zz~q$`oJ%n7m(=SQzo)}SD>#p!%x4I!U<(!Nr!;i_lGheKT?K@q9SU8Cl<;XOQo^U} zkz$|P+#u05%N&$ES&X#uq_nzH*{n6uB9hTDS1Vc8WjY6Lbb4`I!ZI4>;-Hqhh9taW zvV@>2dDs-)En)?)rQ(|8^u{5ck-VB~xsHua$nF3lJLn3MI;OnA{j|U>RH|s50m%(y z-9(UIkG_!vR1C8Gyp!NeXV8uhpj;j!?jxBjqwb+nKh1ZMfJrk{Jm#nf1)oN$J$0Jk zGf1`L)U!ynMGp*xo=1w0zinPnsTZ9Tb($2?hUh#*ke`hYl7PuZEBGYASaVLTs%>ge z4dBc$VuUzwJo0ZcafYLY`w^)vJpmf?GJ+RUYzQ_Pnykx;fbb9nZ$ zf^QOBRXL=OQj(RcPG(nTn1Q z|3OL|B@#%9d7vj!@+c8U+MtLA;sFF_#&;p92|-PNpt74DPLkOVLP2VfCN&@}m42*? zkJU$OQiIb{>B9p{m9rE%R*95Y7bcw)^~Tewru$$<_Yp1YGy=-1CfCuA^P3`P1;>$C zRbz581>I>LI%2|&y{=9>yF1coYWlvs);hG#WGnxziSA3H@`{)?k?!M95z#2RlW5ke zR-G8dHPHeRbuB3AZf=B{vXCI$maJ=Jn;qw9%?0OrYaBgE&~(DvBMs^&yvp@H8qpyn z>+$k{5VnGS2{&0ZNFy3Rf`$NC!D2!&u+jpKZxkW;cC^Mc*q7;;984oMrV%9TinJBL z(tVgv;CX5{RA8p1`&&!W9qe_aakIFgs$yu(_}co({cx1Y4ZQ(PI#Jtm7q^&Qsl=kfNzB6x@cC zwCi`OJG5bR?KC{6ntp^Z%u~*K0{vUZ3T`4H53By7@@axsoY0GbOw(@gI%!Ksq@*p| zSzU4*JqWChOk%bF_l{T+0+*L1ZK&K}$*#(hJvB=@QH`MugOWHy9Go22G+_dsRZ80= zqO%hT<%-U3BveThBWvsVKuAMddqAZ#31o$jTWmi-^5C=&iLoi-;kvBBBI2|ciTT@v z@JBV`Fx40`Jz3Gzm@KI-pP+Yp(Koy85a$6JXCc)XT0647s#ZJ_tXlI`9!T~MG4^&C zL&3gC$xhOf>y}SQdaw(7d*o)v=g3JYE9_SA5Gt?J=xO$H4XD@UfEoZ%aUweeDQVvk zL{L1VqB@!J(Vr*}seT0eH;@%PiiA9j8%X69lAA4?N7rmRi=qA&EJN!KgOsrAc%-CV z$536Y#~Ny}eyD9|bZl_VMWPRtkYp|sN01O6|IMJ2=O;YWt>AEy%5nrYo&-R4?Gs37 zAZ{t*QI{Db${X-7r&whO603}Ge|x|+{fcl_X_vGQ+9}RyvA8UHGGaY zYnZp3q()7wPnK6^jZj*~@#3mRqn$(*bW<~iO4W`KPIU-F!LyN)E#5#?M`~SJo593L znUa&-3Qi-LtR}RA)2V#N2FfgmiVissDQVt$L|`5$=Md~0Nh>&;WISw}L*?di@`V^D z3m_%?;DuDfrw`62+}9d(!NnTkLaLy*YgQM$bVn$cXp~n|1@3_ZYbuA<4y@qoD(H)*`f6z}k=$yIbgOZCCunC|+Vba!fWw~@45pk*;`WX4-_GCrU& z-bd2x_z6{bPXPB<_?bf8(7%}Wo}9FgX|ySlHZRE@B6w8oq-2dDj8^b*5~)u%Hr3ap z&yVEsJ%S$boTlz+5*|{WoXRWVQ8ViF^WNa@bc*+6Zk5mHQn}huiQDW*$-(wARTIiR zRx&RV>hJ1nB;qmDUZ?V;^vZRhY)d``-yi{FjCh^%Aw=Xre2>J-@VqZB*H%^NP28SC z^bXHaTB$>#W$stvEInUt*b z_C*|tza}wn0dX*~fuxz%ZD!q-q((F~me(|zX}fB)|Dp<|c;Tbo`&z*MOuP4v&=zR4`BcFt z2ECcKJ4uy^$I#8@{zv02%E5aC^Tq}5Ri>{iDA+#Q7dCdg6*18v;FtErlh@b~lXk23@my%Y5 zBu#{sl2FVknmTZu!Cc~oD0wPXV%e3W-n{ysW;El?kiok>GH8`vEWSCMUSAkJ4+5cp;i3%4Rg+ zB5TGu-Y6$T7m>txd`4B^+I{s?A%QS0)D&KlQ{lxq6)y5sh#w~=99J0W)2=3)`YfaA zg&wV%gcMDapQ$;ir5ZUU-j_H8>A=v*b+{U$y|v@qlM;u$ z-Xx;#mN-zk6WRd;;wm`mkCHbJoU5f1Az}rOAOZ1KXL|TJ5_}~+*qo}uGfFUg$hl94Z!X%>-C z(xk--jm=#jYrIZ@oiH)s{5P=k>3i;Z_vQ=3N5{??c-cMw8}{4cD<85@KDgg$aGGAF zZJ-2Q51v?#`|I_+PHU{Kt!_B2GFe?dqq=I`X|?0dIPG|>IPsQ9?_R37M_uK(!0#K@ z?-OXh=lEIS`QeMgmxZ^4FVDX=|I+w9`S<5PkpE8pqxswO-^%|n{%-z<`5)zflK)x$ zm-%1kf0zG#{!jTo=6?`hm;Y=2Z~4FH|B?S!{^tB``OT5pk@F+-A{Rv#N3Mw65VKdyKQ=EmKXz&Cve@F-qS)23 zhhmS#Qn6d(kH?;lJrjFA_CoBX*y`Bpu{UCG#XgRG7W*XjTKx0a7qK5>zr=ou-Bh?P z_G+E0bt?}ROf8ty1PvhI{kK%vZ@5HZ( zZ;UUAe-&RE-w?keesBDd_~Y^C;xERZk6%&vX8hv9&*HZfejdND@Z0!`!nN^V;=jgk zEZh{IUpTYyj>6f6mlZB3yu7gaK=jtoZe4Z{=SQM-QyQCQcet#>!VZf%+|XfJhZ{RA z@9HfGo*h0Pjd(%$LNw&X;RWGK(433HmxmXJuLxfizB+tucxiZf_~!7f z;XA^2hwlxq3_lQF6@Dn33O^ctJp4rXsqoX`XTr~hp9?=9ej)r~_@(g6;a9@1hF6DQ z3%?$IBm7qQ{qUOb7vXQiYs0^WH=?U-4gVe99-fsyC%+|se*VJz%kvlKUy*-h{#E%` z=U;(R9~qI3Pp-D?Xv*miWWndoG5(9K%V(JoM3?Z(K>krk2KBDY8Gh}?yacW-268}*Y>WI8*&dl0ofVxEog1AOy&!sV^wQ{}=;hHXqE|+*jxLEVjV_Dc6umWi zd-Sg8z0sA?`=bv=SD~Xn5`7~2RP>qXv(e|G&qrTG$A1M~|F!7r(Kn-SMc+H}b&! z3qyBX?4Q^yTMXd2_I&$79>$kA1NjR3Dh%dp?dve0m)XlPsBht6eLDvB-S)j0-1lR6 zKV+vc#2>>Tf69Ia1O0g(>Mvuk(?EX%L;W55UHg3u_BHk=_GcLKU-F>;0mJ@h4E*2i zt@bwiZ~Gtn()eZZh4Dog_}60KUx$Hzef-Awt?}F9w_^ghD}Fa7f&1bsroZ8lk0j^RX$qY#@fCe6HVZ#@yYVW9zArqivT`+zEmtnqw%%LRe`eT_1)m#?BHe~%i&Lw~h z%T(2HF&+9sRyBoosKi1OVrBmtr!i8(mD2m~?S z7v8rhpyGjdt0;$f;eETVx30SCs*Ac_$nSaH>h9^847g7Auit0kld68J-}kMj-g>LL zuI?FjSXFcN{38;_q=)|-H{pi9%W(|T!I+)umvJMze2 z-sIreDS4BpOevdQP!cGeT-MxJUE9(!t*ZLO+U6rC)Gn?)a(Hg;WbMdcpsBU4v7yCi zZEUWZS3CL0agYwyH&$2G2U}We>KcPh&2K) znO0lhRNI`b{dwEjRy;n@1LOS^CkE6!VgLWXw_1eR{>bAd9%Oss@rn64vzwY5PpGYK zZQ%u7X}-8p_UzWi#`>1oQb+Z5b7nWrIbn8rZGCN3OYOu7vlmp=HH=1*mN>?)0!!)c zavwK#?8J$1_3Z3}#wrB#_g%X@TFuJ2SEbLI^!vTZx4eCO$@;6`cpyVJwj?z6(E26! z(s=LF1wFJ>)Gz;yhCfxeF056Qrk#$9QLKFTzr<8+bah?*@VWDx)Y0I%ErM^dmO5GZ z=G8lV?bVw07W~Nl&*7_UaFR#h>X^9>DHjf3?PBM~Dm_kHx;ws>B@SQpUp1}YdEps5 z`fBDle2wv%ws2k#hvo(OV19pfuun4LX#+`+T+8W${RLmOQ(dq&>u3aR}P1DE3_j2<_3 zG^!0ebLtvqPit&xJ!aCx*^A)^)!CzK>gzMo`vZl)bxBigOtJs4$v63_w-17poF7TnorWwu8FUfrYluE*Hy)f z>KbYq7qz6HScfJ(ZtU#3hU)sZnp#|r9y@v*+TQrlV`sNjH@D8NW_^vGucdnS*?j7` zzhxe?@yx|XZCLrpUC*Tr@O4K!x{&7Dn%Q&ERkXI$NDhUi)%$#W%=e=bng)Nc^q`*} zPrD|eJ2@!)jpzxQTZ0Q~7gRSb3ARW^w_HBA{66p3?`~YJ@49ML=jybHiT|~X7PZKe zOY(_ZU6(QZ^dAq|=cj%84tQYBU(>GYet}%-hrCgpRR5Rh9q%QqY#N?bc2nBb-K*~f zv*8yFtqOWVdgY62Jw3iy@xU47+KSm}I}YrYi5A#Tj@J3jwN*7ORZVr0PwiRzt$4lk z=wH$Y-d-~B@hgu>J8eui^Fd8FHZQUDH!hg;SbBQRtlE|@@~?S#{V{1th27C_c`fWD zEmn$f^2-+*->y6SZ#@RTS2!u_!uGVZ;oZriO{#(ILbR`Z;s znfYO9+R5AhjG9G_izZGGMN>|BCgJRpFZ;FMnoj?S++Ti5Tk?7LtS6nyf~tCqktKs$ zufHX~!`tKcDb)wx*6`86RcTND`d`SP+Um8`7`(c%VQ$?#$?o1Gi@*OZXX2}ue(~W` z)t>4X(zg9Kvs;9m>KY}Z)bVQ%pV$yz{nl3Vi#4}DxIXQzo&Uvhp_9ajLNYoz?eZ;K zPTHsPr5jIp;DfB=CZ-*~BCcEh9oFqHYOPzK+EL)ab*1m`x})fu+b+8z@%H_%O*8)+ z`Lrx)ncdP_rTWbCo;z&m$ZzWJc;S}fz@TMMznb>Mf1`31RpUu1rn=+n4gWW7%i8lj zJAN&e!k?AS4!g6m8`8jctCb~8i%ZV>`mNynrr8ZmQ|O`JMx?}|8_;ncUSb>aq`No zX;=OkEhn|rw$;|4m7XZdwtjL{`8)gFbzWy#&o6FIJ@|{Xtc(8yq^9|xsMJ7R{%%PfEkQ zT}#XVbJ_E0U|ZLpJmmE)=d7D}z*R*_PhIpyeA+A5{HdZeRJGPEtgUNMJ#FrgH=pQR zuxwr2z>C%edJOcY9dX^C($>~mrxXo8aMo+%U-{&SpZ@mF_19-?IyWsleh*b1F>kcS z_o<#WS08v`_KAFbBZuM(y0X#ad^Np1yQVYww5oUxj7J00PG04vlbV)qZN1NGP z*IH}M=#fdUo*Fr4Ad_9Z$jC(SGei=YNt~AQq9qc_#U;{CNE;}UlMoVlHLN7#CTc4@ zJ>#hSIOMX7B9n(BI0YhhQQitGN`%OAio8dW2VElXhnEF1c43Z3HXW2Xb$%{i1AdjNvZT*&%bGNF9jGUrm}amtKL z4wYtrf>vI&D7>AVNAA)C5!8V@$!aGhm<>}q+47}?%-$y*Sl07 z=BSRStxL$hgX|x;l;?+(N7U3R@?SOv!Qhk-@_%J$6-`{utwYawa%~>Q%yY16SkSPr zuDP+n!M6tZE~SEssR-U2fQ2fnB6d-MQQK-uR>;h;32RP{@U0NOjKV{T5cJy1G6kxo zS7x|y9u_4V+M1>|H?}o7;_D%PImPdwcmU#Q%)5t{GB84%T{BmZxLWRr6Z#btUp5^< z`9MB0R9`zJLcF}Hx^`w=>-_xs5cazueI=y_6(d*<8Sz++$}@xiK(xCAR3>Z-A7XsAsFTlOE2y@9gj zix5n~clZBe)2?q__RT$=GYy4i#}J&v#W6wp9|Q z=O*g8ntHZ`^t>c`Qhy_$h1H9!{h839WHJD(reIPBf*la-uLdS8gXiB2QieuIx3~s1 zl)stsr>;P7Gx}_|yaq{6%IFCBrU?04D8KUz1eNHE-SP<{e}*lu${r4W4TWzzAHgGj zN0@f=oG!wv!i6KTuci1=7b2)1t!aCyvb)4D{M|##&FyNr=_vU+N^iUj!Ixt-Z6Kw+ zabmfXAm>S09U<+`o$|L*{?scFyfH3Z{#22FAVS`4Im+Kg`9rTlusJ(i{!EcS2U{V6 zKGJd&zMaCIcO!W7P)Asbz8qqnl($Lj( z$0GMTD86Ykf}weurc=D9GTj&mdQzGr#ohVOgn~P%;MXk(K7xV~R1mKeOcw=fECqJ< z)h@3ifV(I^>`4UQ6=<3a$HM?T79k&UJ4)Y8=}Au`I2;e60RrE{EIlbtiy%sF=Nyv! zKS*w%WY#kXK8B=tyVt|aJSqQ($kJV8W_k}rw{1r-6Hg#F40+?_u=iu^Nx9~^0Yc+%)pzr}-B1oGR?r%py%#$)NT-a?pia$v4e|?2uC&c%4xvLUC%@S`| z6q)&4NIyjBP5(sj`LUX|kMdS=b|rmQgtR+%%A1tm@(qIXkJGflUF26{>dJ=NrGGvX z!Vgn8jvF^W)Hn@Q>^=`-o|G%Yh242m{1J+8j)(XMwc+B;BECLc++ArDf0W|w+#=dO zH(dNQ5ntJ=4qc|T6+o?{`Mh3B)ogE;_lo|L+9X=l8AEo3)QcJesLeg#>pjWRn=N-M?CtEoK0 zq&8D3D;rX6i#2V3G2Hwkd1GsU8lut!e$cQ1v`jjc9?Y zBQbvIZH;`FMQWK+hXXt3IXbg+h`$LvFHq0RZO}8|%8;Jz)KfOUq^-WS zuBm=We%-=4?AqJwVh=;^Mas=y3b~qV&|a87CSt8T?EtyPg;<7~TZ{8U)wRx4=4FVz zM6tzZLhPLD`P_zBoF^Ajo|LspHZ%u4S{8+iVGT#cJ5cd5RlIW+R9taGXhGvnC2g&+ zg+yV-`nDDTF)p|Yo4n=tKqjcWG46l#)h*0ixy(<3epTYGVwMR`(AzeLpJHrM81 zkD;m>F42--H&@Jz38Pi1d#7pI>(n&sMritEEsi2s&aq9&hYYMHRH!J&HadjgpztSa zAzXPI9vYVLTam&AIQ6iktA>ft@Fq2M+y)IN1&DN#xaPQpnSmkPV^lcC~ms#tI*R5Yy*SMhIAF+-^^ zTC18{TR6>k^f)#=5NiHPHFNGF5~w*)ka(1aItxTY%^u|6q5P{GApg@Hns%sL{!|OW ziFHk`ysfpXJmmd1%3gRMWVO36+_9?Q2PKx@)>L0tUDayOhiw0h&kAUoZlPs(`sx#W=w5U0_o#*|Kd!KR} zUVz+~hd6~po;|EQJ1!TwkjG7{YMGCY$nm!h$bUfj)o((6$Rk!yg86@^63xT$gVtJG z%+7Wt#6G0h+_xZh0>t)~qQ;$umgZruo|K!Ff_$u}G}p~(3n{VJ56*&;kEkT$9Vj{H zQB9jhLwmK9(klcub47=Y6PE*B@!X7wOVWPoA1n$4^8%Hn6$Rx6q+WueByD4SFvwjNSth9sHmQe9 z3+^YR^8Q16yzlL){HYLUlZvZaTG=HPHH6%`GcHj;7s6zp0d$gFRFoH$a_Mky z^yEp}oxoZ)Em$z4ptJ&sJ0(t5u+Z2(0{kmISb|{D+7rqQ6t%b@7?xpA$?yv}XBje_mTOF_$ejYFf}<;Qi-U!g zrFkq0GQR|d^Cq1^mzc{v>xmQU#Vdg%+zQ1cHl>&Z|>>{R6xYZ-)-v|r#`%q1^S znqOq8eGP)%35RL*XcpBAnr1>{qG;TRO8-(c4me*bWoGVlz_M!Q4S~IK4QyXl9>^;& zjNp`9qbSd9f56&I(5setG_9>_QE*XpOZ9xN5_*;YB8RV#gZD-kLw#+7))}W5-T=eb z0^tr{S#h9rDw-a)`QkNf#a_^_qVdGqhT^&gjE&?{Yxmgp?gyP#_a^;?azkXSd~gj= z{ZsU2qGj90vg}@3SwaI<6dXejyg&@M=oXZ-qF_oe7qu~?AXr$QTY^Q3_P4|#9`qS- zJ#hC;(#}P;ROtBiI8iXfvi#AN1(gN)LF_VP#@;Trf1+ArTd8cq@#vWj#QRb7Zw2Dl zaImtH%8Fb#T{IJq0tWAA2^x%x!|5UGZij~NXkE@K(T&)LQ5Gy{YzWP4IUZFWv;sBy zFUj$9X|JOKQ-XmhM-}9u^#y|ExfKOstsqbygab_}pw9Pbrz4!ERTtj2eiGP|(R)=C zm7tG_)^Qb50~dW^X*t}3P}QHkB;?roP?Yy)Q8^}oO@)8bK`q_usKz-sK?}=C4^>%I z&OL%UF=UI@{tp;JIw`N_eIIU$A=%t6<6HwCT3dt1bRs$%jJA>4FOu0^zOqWEWoE*N z-gE87Z1pHoY~^BG;F71KBGcO!_OL5kb*oNYXTcc1iS*KV zl_`*9NWI;UfgD@ilvx!8MtMOYZVZ?DeflzWBe%Rfm)-j!NqvS-p6M0S$_sMy>3tP! z%OB9z*V*9Fn(ELUI_4$xU6T3PY#q`KMy;~JP?Mw;pcrMUUZb_y>0t6{Y3Mz1f}02O z4gA5c!=4@w*%dPgyz_7JXqNMLea=jPI_EiawDl+{3-IYxE>9a2Z;6!ry3E3&;sOFg zQWZwXm_dV4-X_#U-K|a2Of&+@1lh?Hz3GZFLhTv^FksI`9W^dl_yg zX*t8oj9ErSL5ZdMSh2#}8D$k^cnTNfmR6PprXE}oJrz2FL%)~7w2 zK~^gj?X)ORUQ{s)CZ3U7jK_8RDsV{|duZN=tiHXm0mEL^x3>gmIDO}O6m_}48k-=_ zsoFxOcTuti&u?%)Vvc~?4wjHx8@p{~!H^@co$;telD2QcH1u1=v}6zQ!ow4abIYf4 z2qL2fr0)-AFUO#;a4ruWV(jX`{1G?L5KZ^Nec4N?hlcXs!6=0HgzW%@*J{eE>RK?o zuWD^;kv7;4-5VjkQpCRwGhIRHjG}T3erAjZ(`6_gMsC#KrFD2q#%qPmwY9}{bDFD~ zmpJY0Db(GWQ0%Q6&ka7D&u^>8h`XVtzBcrHdJ?&Jg2|`-f@h=U#a%tq@nOQ~jb>L` z!S+^ZV6QewyC`95r3}SB5_g%2`(>4-MR|ez0?QT{;b4ITc_nGv#F@$hfnp>rMY+6R ztb=u|2ZO8SsEuZ)IPb!c=ZKxg_$r-|TV|5B$yZ!9Q}zBQvEv#jK3?y3@H>(7xyr_v z{|2odBX1U5I!I4<_W(fkDY8n^a?$qXZh6$_bqUJqU8|sD>f-`#Szoh_}CK4ZUs*XdQm+viZVmx$43?{PeXkru{b0oGt& zah_|fr=>hbgHtMtidFqKqZYh}tBT5NY-_Ok++#6NS2+#^!z#(~9!wJXXrDO2dbp?d zFRKVlFDMNffy(kc7O}rn(`H{-3tqzzze zwS8nyK7G541k|HT+AQ#WDfmuhw-#l{e+F&8D@nt68e=He2w^Yee7T@o!G=J;ay`YI zNhvaTRWKei@E93-a2O1KsYF$%iQc!!!J~1)4ucdez>A&eS8FvMLyeoP-Ke!|?LP{{ zWynW)I-9FK*?mW}ZygZCh}#-)D<8tcibL<*Jem0`hjhc*A%f?pODoI6)3*qZW6Z4W z3Ft49>5M(NRA}0iEdKN)de}UxiybG8q<^T7n8{QAuHMhpMeL(_c~W8bkK@p+g^%N_ z#p(}+FHfigqHS}qGzOF7+!@^B-algTF1N>jVN)_S8+{l$u0d89jM4CNoT&`8Q)Zv< zX{YH|a=t%E^Ky9-{aV=a8dp~BnM)RUuZ1@6#wdfCY-f;g7uc?o@;!_Oqt-#%<#F}M z{u*EVt3YF`XvCs;RlQ9*dDNiBt{35z@l)i%*_xz%ijK6b40GAy{Bpa`y9tcmt>|>@ z$Eg|y+F19)?HfhU>G3k4LdTt?{YXW7?vZa6m-!>+O*EgnX7>QE9owCaIX8BbPr= zWfzG%_U#|Ex(^H+uuxN!XW(9%C|d8cXC9bD3~~AyH)FCeHe&E>J95-#@}Xe!a?iU< z7vvlo2#o-bhRfXqYxuN|h^ZBJRf-yOtE<^X;`Qe+=XR!9KF!M=sjfLWJD94sI~&=o z7NgJ1+@Mg?ffH*n9q2L&4BkLsJWlvynWSxDIzsIgQ!{RZa8p`i|3vjzlKwXqoF1v>@IZYiM+) zKO>>^R^IyAnnPLEDsSWKnGJX}w_3{;_PjY6`Q0W)>$C<_@~8!pQX=88jjn!SogM)q zY!Nj=cf;r^^t|z?v@5TBEL?0l}voi0rLV za2~#E(1>{lUPQLX#i23eIL*7y1dX2+uqH3LPKS9n0No*Fc>$vt*0w$OZ-Whzv`e}^ z7^4~N-@<%ed>JbU^J>!wz=~rYF$f z+THC#K$@hLanz$Gn=-)~3y(_D>bb}{HNQv}I;Z4TjZ=e}A@M)eq>#s>ucRY&=_(gSn^(BR-;gG-MXJdtDk;NCgS{#S3!Z~o@;)?@>oVMA zE8uqrup6m%Y&OAo4@)iIL<87O$mvU>O(nNVneO)G&qOn(2{XMsuG#e|X#Ii$YsG+$4HjU|h?QjqRb)?gAIBt7wRyG_E8ceCCvipI- zzfpxjOrl_bJCU77s$)Zz$IumJ}LFg~{z8u7}Mwp9%LSiF6QkPo$d^}3pSgtAOmKsG?PY&jRsBx^hWwut$bInVA+G!E9x#GG7 zb?)U^*H#%9?LN#bv&1XK!lem8>j{}58I0N2YBKo&BRCB^P144>a^uqmhnh>l;@WB) zMk%bXnuj$;r@3Sx2XF5(*QhH{S%K9=;O~Rl^YSQZ7vFB_(&KUx`2>vb)B0hStFNhTc4nw20Ns;)} zu-$&N9nU{;X~uOlpnz`?tF_GW5PMq0hPh{!oPGNL$>vjR2t!vrBuV>{>r*HVG~gXefar_bF3XF2%HJmdd%f(@ zijCYL7E&<_2v(F=B2<$id%iPVT;`BJ+8#i5+!RRC&WM-6m<+ogl|?_?;*wvI_Wpk5 zwN3SS8?hy?v3Xieb7|XxTC76n<2Cq(+7__slGiKNG-e8>zD3gQcu`f@Z$m3BQ(M>3 z#)88n`=O{y#beFaGLh`%>FwS2H=(sL_BStyWgp@6rmmrp(_hT2j!p>c9B;Jd=8-!M zO@i~#;l34`^U0`z%4ifrG6Sx-udc~9?zc@VKQvgEokDlWy}25syX$c zUDunz`?4VX4hT8_f`Uc#luKOeK%7crU~Tnt(_n#DL}rc8C^{B1S&WmDv@^@=+b_L2ep~?9uL-U@ea(EQhkEY3f|w z4VlGduHyuAg!NPQTGM6i5yvYqB!_tqK*^G{Wtr1T0{NA)Y_ydIe_8dzSZ2h5Ikk=N z+Qq*I74?P`?)1!Qb~_ISp>7+6lPzIXw-SwZ*l-$jyeT@4dkDU>n2ZTCid^6>~yl6C~9&k^I8$DtufJ2D{{b%f*7 z-opVa&M0adYOt1UUJp{#1I12e|M$mn3BFg5!#tOkXf3-%*?yZL3#2$0wLn9k* zn+6Q~Jfcs0WrKTVb9W0ZI|0e3joM=iE6F_u5G>nP`?v?X7Mg)JkGb%k$va(n9? z*wUxHhHA8y#?@n(ThnOVJhmj>kceZPSZ6&S7!|ZR+r=k4ZM`Jzi^0}TdY9?pR>1Q_R6u{kv|N>e;|1luScuE zZm6>yfG(y2E#yUTV7P>1fmT1?&O>cU+Gz>FXs363p%7Rci(gn3tj9S4C{PCp`y|-g z&yfcLleDWdgRWk)O4`H1gfeI0P1c%|v=nq1a)z%xjcd>EUIuq5u4%@~4?aU+ovN_Q z^)+C8DCK&?T2Ko;`s1WThr)d#&ej0zV1eJCQ-eP|K<(3d1A^s(JS|p^@5J(yGkbUO zKu+-w++%CBC$P?=4v)JXSV`n)ys=?nZF6g7>)de@D;jfKs_W`pgYsGw;v*^GeS_4q zUryrkgcxRFMu8dva>vN0&0Ay7GF*!u&fH-j>g%bly~`hMj(;OooaioH-N6}Xy; zsU|&Ls;wt1vK=kj-Xl<3vU~B+H`ZXnPJQ#ha+3BgPght+Y@&@LKZa&+Cma#g$^&N3 zjErZFK9O47Vl5wcJxgSWp(~Juy?(jd<5q77YqGOLY#%TgC{5~!A@=+``npIxxV&2v zzS*aXDYG<)GEsMN}-P`TfL* zi?CeK^~HnEc&@`@#O$4@Mj_5yb5X`0pAqDHI6H*Lh$A*BHcAeNzyvI zZnf<8?RnVjvs9o{bQ-Rnep;b zKbhJ1v{h=bJ)^F<74M+coh&;R1r3~Z)VRjpgOKxeUHhGAON>7Nhfg~aCY5PO*Wz$Y zX%)w(C1M7OAvDf(S2VY^wB|SRYixW5;taIiGjp^v0S*^21l?bXGZGUg7TERfN%%Vu z=ZRg;O$fS9YkJq%g9r>I!`?f10nO)2dM4kTL=P~x%VN6w70l3i@~krGi*+8_ zZNX#|;zRUP@-C3|ob|(PoQ9=5sT9>~bsg+F?PF0~AMx@H`L14Vt(t{qv0M}W8gP=d zf4bJS@cuyfF@3a^Y;o$nQB_ziwO>Js=KWKI@in!2;XV)zCCgwj@8{|=5piJR8cK?U>0jy`wcP`S8MGV z;(!CN>`_yXPx<4$NNXU)Z~C`q*j@$HbJg1o))tOh72Jm6d?S_l*?!m@w%4J8CAmkD z%2uls;=lCEcFdxk9m28Fk}FV!YLFYgaO6D1xfwD}M(@^pSV`JONaIxu>r|C;h*oQgVy)w(zyjW<6Eu8b znTw{*2J>jt*T1AJ=duUo3tsNiBhFF)J5et`Y|^C#IftY|k4PR;*&#~5#&n2?o$dvI zFK1)qo6OdTR@}?|Qxf*Tb_djaFKW`^rc~qF7VAqbd{-RR)ODtApSj_n;|EdkWIVp6 zWxZ&Uq#b49ig-`r6evY!X}#8BEextTz{l)-fL;ypN26}|@{oFcQEe)$XWgnpm+roY zXTOrPXhN7$X}Q)9A`TX2tyM9$&)EXXBkKXc1}H_sHG zc45S61=mBrKZJYq4lQ-y4H#<^Cq)c@0ZeQw#t9qi09Q0yKM8aAwBP9}>Wv`|4cr?> zUfjMU+E9e=oh%9)iVW1eKdRBW{cMhMV$G_CMCAJ$4CmAQd+fLJjl8m8MebDB5(_)& z_t9OU(HdQQt5fz09Z-&JE8gEMc-BivQQ%qqFb~x2lzLt85KI$&fe(J(PwMeg&MNjW zarpq+lC-MbYr=s>*P;0oQ91|g>dZ@*cLtI10PuJ(4Vy?f9d8}({VukB7iPkgclS$u z+~|EWe5o(=Sg`g=Kk2gWWWUsWCCcSpEE^$VFF%b(&%X-*yuYia$hGr5y|>+-N&D=u z7keVMxcK5kl2&LRYme+?=EaAdA+wH+9U|@EG@cs@8wB7$Z|^9*C5DSVybZ1RJ(AJ* z=(Og=>yXv0_2aV@g#`q@MJI%O)*0W+;I9Soy?3ogn$>dD?H7Wkh9{%3*zS>S&b_@4#-XMz7&;C~kQuUH^3wB0-ChW0>u`|ny{eDAqwgMB00 z@22XM*=apyBeaYm z#`_3tQlbwMH(L_7AVvW<3cU9In3Y&;l`LMdDn)01Ld7P3~nV49dn^ao&;m zI^NA0=ckWancJ$FUb&r=3nC|h*{p&3iXK^#ARQl_LRQ6pS|7fGr>q9; zv0LpvXaP8U&rPgG($M?DYJGhE-adblZMFMx!|bE1*3TDVCY2sClW)Yzj_;GlqUhuC z=NUe!9}Vz;mB)jK^_E^6X{PqUG_xg72Qqt$-70a@OmZ%Z#f)jxf{(e;jH2;jYV!G% zrlBrPtXx|YYspr{YnLv3p-q_(nqxBI0J~xVjDE#d!Fo3I!(qZhZR4#)l6k1Fv*Ski z%koTZ)XFItS}uZ|BdCDhApQ?3b{MQeD8p9)1%}k9o(CAYHjKLoBiDifw}qpo0Y+|G zPCj95uwj6T9R}+M%IGh&21!FN0*t9P3=>J_RNtB@H(Ay|y(hCj=t#~via=PcVh>QU z1K9#CQ1&6=GpkjydI-awK$D-1>(-Lx%d zHetMp+X4er>@ePg7ASj%*&`-t=v9Cbv|+rDBr_NWBSRatB4e1Aiy&tXv3vj?!2&9F zET2IOlzoDTSV$WBd|;VtWBD9O=GVf+iX1qP_tVf+j&Q1&CUM@-VtTLGilhVcuM%;qo{X{ecDeNi*R z`sTC|%dg-OETCe?(gO?XP`1m$LekJr0hT2;7B7;_CGv!jXRy2Ro=PA+!5~0D#SWym z0+K)gP)gF!mjTF98%PS0%%$kgZtmKhEhmsZU=SdnVh1u1TA-{S0U#!6=w|}R88(nX zNHWie-ko(4$lhQOAfRFgG7MUvYzP4$CTZyB0mwNvkPIZ5=S1(|&nJ*fFbEJ(u>%g87v%{Xug8c?yLnFK9Rb`Vh@ zCTZwb0nHUQnnRFeUSXlZledf8UQIMP;1V>TVn>q;El_p@Q6MI1=r;n*^){L*NHVXF z>}6Nxb@k}}x{yrI>dd8@*n2Poi7X60!jmvxWz%T1CeY)I`e)PwL3UAi$ z2^Bp8p0Vb4P`=($KJ*YR(fmdLS~xQ%?Mlef5(A!b0GUk{?f8_kHknvRd1UaaL@F`d zW11#u3UnnIi!n!kW!SdrnH48FOmbT=;5h_!vU?^#6o{UqQ6(7zh|PqN1}4Ysb)f=+ZEGL%hSML6vB~= zq@z$w-YPcq-ic<9#3-)VI}x>hNWZA&{R3A_hGnz*CDIj3482dH*$Wxi?&x?(AIYG9 z%o+5T3`#NCOEh~*p{=qz9@1BG7!WmwKkyJK!T`ykOn;hf5zVw6KSQTknMlQ}a;b_} zMszCv=x~FVOU1+VF;)CTR8>2t%ZOxlW|4+|8l2#iME?@2`rGkwcMK{LJ3BU{3xJ{H zIbG8iCvIfiK7j=|B@x$xUoisnhVHkKd{9PKhJGs`uTAvdVnhB7clDbAu;V+JcoGl_a-h0D-CPULG1CR1c?+%|=Jj{U z#h7e;mz;AOq3*Pyg8C1jh9Q;3qN~u}+ZWziZM{1?Hq)S+(~DJd9D1s>oV$8M-53ap z2Y`wl<1A=_vI=5DOw!Pw1jZ+N`?uH_k436roCUi~#!{5|L~n$ZyxIbcTZwTiFiLV< zF4A+JBF5t&C>TM-j`5`4g7HK|#7NT6m!uT>7p3^yQv59`mML2lU#p7RRJ2e!la0ah?WUb`&ndCi18EHpP8VQfmMJXtCCH~B% zR4%=gWW%ds8F1RR>V&*`I{9V2QaX+FNu7e@ET!8#g_iNz5@)O2JDK~rl$P7#PA4<% zJl^LrE~wbu>2hd+vWpPW<|GaM0=Uz8DgJX({Abzjbfx0EN<~+z=vqYjCCVt@TSn0@ zrsu3qHqUWPa+ZAs&r!Z`9R)9nu;zJ=H7~XW%uDPmN0h&YYF@-->HjaJDQ-ZTm;zMn zrf3=>rl?0mQ;;xzK)1<8*RD90BhsJfV{Yn-t^>EsCmeKJ ziEahb1Rbc@(VeIA?nFd%Bn|x;pnIy1f13^P0;HPT0PCrA^C_apzPRs`(ra9ZJ2}r1 z&PBKqIG|#Oa}~5e*`t6`hG&=3gCjZxh|aNE39R zVn?@C<^32Uq9bYO?*rYtef;m(0JkC4d(d!}%MuK-pV} z2#2Jhe*rk3*;w9F93LRkzwBdv22{_dk9{Ebxpd4r)96_r;+FYkA5b!$`UlZ{gfu}1 zDt2`LPEHG-zv_za8{9I#bGlw2Aa0o$S}p4*!xk+SiUuJ~(1D5_UAoG9Fe0KO zY3Sb6LVsMU^{mcN9K#Xm@u_B9Y8Q0-1F~^WM8pti+ENx?&KsB&Ujo298j^tISg8$>|jKMLlWx{fYT?{ z-`j?B1X9i33QnIeI7i}6P8#7%#+ASU6+4`AXo0d)M1(`q&<6lcKO0Mh;+TO*ADC+P z1FCIU?eF+DSsTk?1OC`?&BT3kU@9mXZ0$ve#~@80f{Gntl>#su5h0Q^^dW$_Z>oQ9 z8)Y?8&Aox`DGQsqFR|F@YH&MeKVquIm0$uDJEjHD0%diGh>4`3X8=>W4X9CZoP&l`VQH^Uzr={npuk8pa~!wKYr?*ybr17 zWMJEBVKb*l=Vqb1AGdP~i0J`b2_{gnW7+~OQ1%!iVj_v-7{D~u2J{4yFss~%o&vwv z%Qd*EK=&Hap?kyBd0Tq%C@d3bxd?KOBD8G~5on-dhxR08{;O7;M)jL=?!h(H4sJG8f;1aVrY{f1Pm5vUEqnQRI3 zQn^0HmQjhotOeM&Lk;7pbnfD{?}S*+3B>w4t^_Nn*s=B+Dp=zX5i3bUKM7bHQ~e8U ztO-cP0)h)`V>s3YQL!dMET@@RlW-+iLB)=>KeRwuA4J4T5{tjUx+vA(W@Ft8so{2A z6ppnmD%ODz%Q=}?2jNPvf{GpMFld3Y!H9^JB#v?b>(W&JX*SkOq=wsdX*kx?qGBBm zv7F_^x<9T2E2!A9j)oQ}%R)q~Bn|y6U_CR{e};{9EK)HDbos!U;aJazigg^sa?U2! zY+MOeP_bjpffgv6h=^E8V#O9%&$EFZh9oR6ZN#Vwzs}8ubsmtt$CiYlARaN#;1S~- z@Vb!D4u^<90~I^80%(D zWyOSqn53a!4QN-|(8`g7@w5xtm3x484WStj5on-dhc+8ppll`~Atq_)s{!rCRR8rh zy1yV5%U;U)s#vEtrlJbvG*~4n+PofMKMqy#cGX!1A(nG9u^x{r!3rvNtaZ==Wi^P1 zm87BH4y?DP`q$c6Pedx##9UZ!4ad4RD%N_4<*X;x1-KHdpkl|m5L%$@Bt*nY($Mb( z)(xrtyKJnBk%}pb3+sk(tanAlx&&f5_Yv#KxDu?OV#m51TA=K7M8rzc&`n@{&<45! zNm$v#;p;T~;x!%MK_L5_HI9i28ujyN)XqWYhY9TrhzK-Lu|qo#TA=JKLPAW^&>si1 zjW)Ckkc4GD7qpFgfVPRyE`*3c0~I^8E1(6+RuK|nl7_ww(6-vpu0j%KdoE~O_W

    6&j9S# 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%0A*$>*bS@O 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

    yV;NxiP3t8@?ORrTnliSwGmJ&F+WnK7_A_bs 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 literal 0 HcmV?d00001 diff --git a/tools/delaylib/delaylib.sln b/tools/delaylib/delaylib.sln new file mode 100644 index 000000000000..e94606b52622 --- /dev/null +++ b/tools/delaylib/delaylib.sln @@ -0,0 +1,28 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.26430.6 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "delaylib", "delaylib.vcxproj", "{9648DD70-47A8-4B73-B379-12368E8EF919}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {9648DD70-47A8-4B73-B379-12368E8EF919}.Debug|x64.ActiveCfg = Debug|x64 + {9648DD70-47A8-4B73-B379-12368E8EF919}.Debug|x64.Build.0 = Debug|x64 + {9648DD70-47A8-4B73-B379-12368E8EF919}.Debug|x86.ActiveCfg = Debug|Win32 + {9648DD70-47A8-4B73-B379-12368E8EF919}.Debug|x86.Build.0 = Debug|Win32 + {9648DD70-47A8-4B73-B379-12368E8EF919}.Release|x64.ActiveCfg = Release|x64 + {9648DD70-47A8-4B73-B379-12368E8EF919}.Release|x64.Build.0 = Release|x64 + {9648DD70-47A8-4B73-B379-12368E8EF919}.Release|x86.ActiveCfg = Release|Win32 + {9648DD70-47A8-4B73-B379-12368E8EF919}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/tools/delaylib/delaylib.vcxproj b/tools/delaylib/delaylib.vcxproj new file mode 100644 index 000000000000..a06c38f4c7eb --- /dev/null +++ b/tools/delaylib/delaylib.vcxproj @@ -0,0 +1,184 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + + + + 15.0 + {9648DD70-47A8-4B73-B379-12368E8EF919} + Win32Proj + delaylib + 10.0.15063.0 + delaylib + + + + StaticLibrary + true + v141 + Unicode + + + StaticLibrary + false + v141 + true + Unicode + + + StaticLibrary + true + v141 + Unicode + + + StaticLibrary + false + v141 + true + Unicode + + + + + + + + + + + + + + + + + + + + + $(ProjectDir)bin\$(Configuration)$(PlatformArchitecture)\ + $(ProjectDir)obj\$(Configuration)$(PlatformArchitecture)\ + + + $(ProjectDir)bin\$(Configuration)$(PlatformArchitecture)\ + $(ProjectDir)obj\$(Configuration)$(PlatformArchitecture)\ + + + $(ProjectDir)bin\$(Configuration)$(PlatformArchitecture)\ + $(ProjectDir)obj\$(Configuration)$(PlatformArchitecture)\ + + + $(ProjectDir)bin\$(Configuration)$(PlatformArchitecture)\ + $(ProjectDir)obj\$(Configuration)$(PlatformArchitecture)\ + + + + + + Level3 + Disabled + _DEBUG;_LIB;%(PreprocessorDefinitions) + true + StdCall + false + MultiThreadedDebug + ..\..\phnt\include;..\..\phlib\include;include;%(AdditionalIncludeDirectories) + true + true + true + ProgramDatabase + + + Windows + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + true + StdCall + false + MultiThreadedDebug + ..\..\phnt\include;..\..\phlib\include;include;%(AdditionalIncludeDirectories) + true + true + true + ProgramDatabase + + + Windows + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + true + StdCall + MultiThreaded + ..\..\phnt\include;..\..\phlib\include;include;%(AdditionalIncludeDirectories) + true + true + true + + + Windows + true + true + + + + + Level3 + + + MaxSpeed + true + true + NDEBUG;_LIB;%(PreprocessorDefinitions) + true + StdCall + MultiThreaded + ..\..\phnt\include;..\..\phlib\include;include;%(AdditionalIncludeDirectories) + true + true + true + + + Windows + true + true + + + + + + \ No newline at end of file diff --git a/tools/delaylib/delaylib.vcxproj.filters b/tools/delaylib/delaylib.vcxproj.filters new file mode 100644 index 000000000000..6827613af933 --- /dev/null +++ b/tools/delaylib/delaylib.vcxproj.filters @@ -0,0 +1,22 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + \ No newline at end of file diff --git a/tools/delaylib/main.c b/tools/delaylib/main.c new file mode 100644 index 000000000000..1907bb64f22c --- /dev/null +++ b/tools/delaylib/main.c @@ -0,0 +1,125 @@ +/* + * Process Hacker Toolchain - + * Image DelayLoad Helper + * + * Copyright (C) 2017 dmex + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include +#include + +extern const IMAGE_DOS_HEADER __ImageBase; + +PVOID WINAPI __delayLoadHelper2( + _In_ PIMAGE_DELAYLOAD_DESCRIPTOR Entry, + _Out_ PVOID *ImportAddress + ) +{ + BOOLEAN needsFree = FALSE; + PSTR importName; + PVOID procedureAddress; + PVOID moduleHandle; + PVOID* importHandle; + PIMAGE_THUNK_DATA entry; + PIMAGE_THUNK_DATA importTable; + PIMAGE_THUNK_DATA importNameTable; + + importName = PTR_ADD_OFFSET(&__ImageBase, Entry->DllNameRVA); + importHandle = PTR_ADD_OFFSET(&__ImageBase, Entry->ModuleHandleRVA); + importTable = PTR_ADD_OFFSET(&__ImageBase, Entry->ImportAddressTableRVA); + importNameTable = PTR_ADD_OFFSET(&__ImageBase, Entry->ImportNameTableRVA); + + if (!strcmp(importName, "ProcessHacker.exe")) + { + moduleHandle = NtCurrentPeb()->ImageBaseAddress; + } + else + { + if (moduleHandle = LoadLibraryA(importName)) + { + needsFree = TRUE; + } + else + { + DelayLoadInfo dli = + { + sizeof(DelayLoadInfo), + (PCImgDelayDescr)Entry, + (FARPROC*)ImportAddress, + importName + }; + + RaiseException( + VcppException(ERROR_SEVERITY_ERROR, ERROR_MOD_NOT_FOUND), + 0, + 1, + (PULONG_PTR)&dli + ); + + return NULL; + } + } + + entry = PTR_ADD_OFFSET(importNameTable, (ULONG)((PBYTE)ImportAddress - (PBYTE)importTable)); + + if (IMAGE_SNAP_BY_ORDINAL(entry->u1.Ordinal)) + { + ULONG procedureOrdinal = IMAGE_ORDINAL(entry->u1.Ordinal); + procedureAddress = PhGetProcedureAddress(moduleHandle, NULL, procedureOrdinal); + } + else + { + PSTR procedureName = ((PIMAGE_IMPORT_BY_NAME)PTR_ADD_OFFSET(&__ImageBase, entry->u1.AddressOfData))->Name; + procedureAddress = PhGetProcedureAddress(moduleHandle, procedureName, 0); + } + + if (!procedureAddress) + { + PSTR procedureName = ((PIMAGE_IMPORT_BY_NAME)PTR_ADD_OFFSET(&__ImageBase, entry->u1.AddressOfData))->Name; + DelayLoadInfo dli = + { + sizeof(DelayLoadInfo), + (PCImgDelayDescr)Entry, + (FARPROC*)ImportAddress, + procedureName + }; + + RaiseException( + VcppException(ERROR_SEVERITY_ERROR, ERROR_PROC_NOT_FOUND), + 0, + 1, + (PULONG_PTR)&dli + ); + + return NULL; + } + + // Cache the procedure address (Fixes CRT delayload bug). + if (InterlockedExchangePointer(ImportAddress, procedureAddress)) + { + NOTHING; + } + + // Cache the module handle in the IAT entry (required) (Fixes CRT use-after-free bug). + if (InterlockedExchangePointer(importHandle, moduleHandle) == moduleHandle && needsFree) + { + FreeLibrary(moduleHandle); // A different thread has already updated the cache. + } + + return procedureAddress; +} From e0dd4c16826895dd4aa5479a1adb1937be8eba1a Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 21 May 2017 06:59:30 +1000 Subject: [PATCH 0138/2058] Improve plugin abstraction (see below notes) Improve plugin callbacks Improve plugin resource sharing Improve plugin error handling Add delayload support --- .gitignore | 1 + ProcessHacker.sln | 5 + ProcessHacker/ProcessHacker.def | 20 ++-- ProcessHacker/ProcessHacker.vcxproj | 21 ++-- ProcessHacker/ProcessHacker.vcxproj.filters | 3 + ProcessHacker/exports.c | 97 +++++++++++++++++++ ProcessHacker/include/appsup.h | 4 +- ProcessHacker/include/mainwnd.h | 2 +- ProcessHacker/include/netprv.h | 4 - ProcessHacker/include/phapp.h | 88 ++++++++++++++++- ProcessHacker/include/phplug.h | 13 +++ ProcessHacker/include/procprv.h | 5 - ProcessHacker/include/srvprv.h | 5 - ProcessHacker/log.c | 5 +- ProcessHacker/logwnd.c | 5 +- ProcessHacker/main.c | 2 +- ProcessHacker/mainwnd.c | 6 +- ProcessHacker/memlists.c | 5 +- ProcessHacker/miniinfo.c | 12 +-- ProcessHacker/mwpgnet.c | 8 +- ProcessHacker/mwpgproc.c | 8 +- ProcessHacker/mwpgsrv.c | 8 +- ProcessHacker/netprv.c | 14 +-- ProcessHacker/notifico.c | 2 +- ProcessHacker/plugin.c | 20 ++-- ProcessHacker/procprv.c | 15 +-- ProcessHacker/procrec.c | 2 +- ProcessHacker/prpggen.c | 4 +- ProcessHacker/prpgperf.c | 5 +- ProcessHacker/prpgstat.c | 5 +- ProcessHacker/prpgthrd.c | 2 +- ProcessHacker/srvctl.c | 5 +- ProcessHacker/srvlist.c | 8 +- ProcessHacker/srvprv.c | 14 +-- ProcessHacker/sysinfo.c | 8 +- ProcessHacker/thrdprv.c | 5 +- phlib/global.c | 34 ++++--- phlib/include/phconfig.h | 71 ++++++-------- phlib/include/phsup.h | 8 ++ phlib/phlib.vcxproj.filters | 2 +- phnt/include/phnt.h | 10 ++ plugins/DotNetTools/clrsup.c | 2 +- plugins/DotNetTools/perfpage.c | 2 +- plugins/DotNetTools/stackext.c | 2 +- plugins/ExtendedNotifications/filelog.c | 2 +- plugins/ExtendedServices/main.c | 20 ++-- plugins/ExtendedServices/other.c | 2 +- plugins/ExtendedServices/recovery.c | 4 +- plugins/ExtendedTools/disktab.c | 34 +++---- plugins/ExtendedTools/etwdisk.c | 2 +- plugins/ExtendedTools/etwmon.c | 8 +- plugins/ExtendedTools/etwprprp.c | 14 +-- plugins/ExtendedTools/etwstat.c | 8 +- plugins/ExtendedTools/exttools.h | 4 - plugins/ExtendedTools/gpumon.c | 10 +- plugins/ExtendedTools/gpunodes.c | 10 +- plugins/ExtendedTools/gpuprprp.c | 16 +-- plugins/ExtendedTools/main.c | 6 +- plugins/ExtendedTools/unldll.c | 6 +- plugins/ExtendedTools/wswatch.c | 2 +- plugins/ExtraPlugins/cloud.c | 2 +- plugins/ExtraPlugins/dialog.c | 2 +- plugins/ExtraPlugins/setup/page5.c | 8 +- plugins/ExtraPlugins/setup/updater.c | 28 ++---- plugins/HardwareDevices/disknotify.c | 6 +- plugins/HardwareDevices/main.c | 4 +- plugins/HardwareDevices/netdetails.c | 4 +- plugins/HardwareDevices/netoptions.c | 4 +- plugins/HardwareDevices/storage.c | 6 +- plugins/NetworkTools/pages.c | 6 +- plugins/NetworkTools/ping.c | 8 +- plugins/NetworkTools/tracert.c | 7 +- plugins/NetworkTools/update.c | 63 ++++-------- plugins/NetworkTools/whois.c | 5 +- plugins/OnlineChecks/main.c | 14 +-- plugins/OnlineChecks/page1.c | 2 +- plugins/OnlineChecks/page2.c | 2 +- plugins/OnlineChecks/page3.c | 2 +- plugins/OnlineChecks/page4.c | 4 +- plugins/OnlineChecks/upload.c | 40 ++------ plugins/OnlineChecks/virustotal.c | 8 +- plugins/Plugins.props | 8 +- plugins/ToolStatus/customizesb.c | 4 +- plugins/ToolStatus/customizetb.c | 10 +- plugins/ToolStatus/graph.c | 14 +-- plugins/ToolStatus/main.c | 58 +++++------ plugins/ToolStatus/options.c | 6 +- plugins/ToolStatus/statusbar.c | 8 +- plugins/ToolStatus/toolbar.c | 6 +- plugins/Updater/options.c | 4 +- plugins/Updater/page5.c | 8 +- plugins/Updater/updater.c | 24 ++--- plugins/Updater/updater.h | 3 - plugins/UserNotes/main.c | 15 +-- plugins/WindowExplorer/WindowExplorer.vcxproj | 4 +- plugins/WindowExplorer/main.c | 2 +- plugins/WindowExplorer/wndexp.h | 4 +- plugins/WindowExplorer/wndprp.c | 2 +- tools/peview/peview.vcxproj | 20 ++-- 99 files changed, 634 insertions(+), 506 deletions(-) create mode 100644 ProcessHacker/exports.c diff --git a/.gitignore b/.gitignore index 53afad1c8da7..230b4fd6ceab 100644 --- a/.gitignore +++ b/.gitignore @@ -117,3 +117,4 @@ tools/GenerateZw/GenerateZw/bin/Release/* !tools/GenerateZw/GenerateZw/bin/Release/GenerateZw.exe !tools/delaylib/bin/ +!*pdb* diff --git a/ProcessHacker.sln b/ProcessHacker.sln index 4e87a04af677..241b7a6e05d2 100644 --- a/ProcessHacker.sln +++ b/ProcessHacker.sln @@ -12,6 +12,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "phlib", "phlib\phlib.vcxpro EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "peview", "tools\peview\peview.vcxproj", "{72C124A2-3C80-41C6-ABA1-C4948B713204}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tools", "Tools", "{9963724D-4A1D-4442-AD5A-1CE899D30D96}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 @@ -48,4 +50,7 @@ Global GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {72C124A2-3C80-41C6-ABA1-C4948B713204} = {9963724D-4A1D-4442-AD5A-1CE899D30D96} + EndGlobalSection EndGlobal diff --git a/ProcessHacker/ProcessHacker.def b/ProcessHacker/ProcessHacker.def index 97692aee76bf..99e444c9bc65 100644 --- a/ProcessHacker/ProcessHacker.def +++ b/ProcessHacker/ProcessHacker.def @@ -37,18 +37,16 @@ EXPORTS PhfWakeForReleaseQueuedLock ; phconfig - PhGlobalDpi DATA - PhHeapHandle DATA + PhGetSystemBasicInformation + PhWindowsVersion + PhGetGlobalDpi + PhGetImageBase PhIsExecutingInWow64 - PhLibImageBase DATA - PhOsVersion DATA - PhSystemBasicInformation DATA - ProcessAllAccess DATA - ProcessQueryAccess DATA - ThreadAllAccess DATA - ThreadQueryAccess DATA - ThreadSetAccess DATA - WindowsVersion DATA + PhProcessAllAccess + PhProcessQueryAccess + PhThreadAllAccess + PhThreadQueryAccess + PhThreadSetAccess ; phbasesup PhAddElementAvlTree diff --git a/ProcessHacker/ProcessHacker.vcxproj b/ProcessHacker/ProcessHacker.vcxproj index 5e3e2d24f2de..9b9b462afac4 100644 --- a/ProcessHacker/ProcessHacker.vcxproj +++ b/ProcessHacker/ProcessHacker.vcxproj @@ -95,14 +95,15 @@ true - aclui.lib;comctl32.lib;iphlpapi.lib;noarg.obj;noenv.obj;ntdll.lib;phlib.lib;uxtheme.lib;version.lib;windowscodecs.lib;winsta.lib;ws2_32.lib;%(AdditionalDependencies) + aclui.lib;comctl32.lib;delaylib.lib;iphlpapi.lib;noarg.obj;noenv.obj;ntdll.lib;phlib.lib;uxtheme.lib;version.lib;windowscodecs.lib;winsta.lib;ws2_32.lib;%(AdditionalDependencies) true Windows MachineX86 6.01 - ..\phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) + ..\phlib\bin\$(Configuration)$(PlatformArchitecture);..\tools\delaylib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) ProcessHacker.def aclui.dll;iphlpapi.dll;ws2_32.dll;%(DelayLoadDLLs) + __delayLoadHelper2 _UNICODE;UNICODE;%(PreprocessorDefinitions);$(ExternalCompilerOptions) @@ -126,14 +127,15 @@ true - aclui.lib;comctl32.lib;iphlpapi.lib;noarg.obj;noenv.obj;ntdll.lib;phlib.lib;uxtheme.lib;version.lib;windowscodecs.lib;winsta.lib;ws2_32.lib;%(AdditionalDependencies) + aclui.lib;comctl32.lib;delaylib.lib;iphlpapi.lib;noarg.obj;noenv.obj;ntdll.lib;phlib.lib;uxtheme.lib;version.lib;windowscodecs.lib;winsta.lib;ws2_32.lib;%(AdditionalDependencies) true Windows MachineX64 6.01 - ..\phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) + ..\phlib\bin\$(Configuration)$(PlatformArchitecture);..\tools\delaylib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) ProcessHacker.def aclui.dll;iphlpapi.dll;ws2_32.dll;%(DelayLoadDLLs) + __delayLoadHelper2 _UNICODE;UNICODE;%(PreprocessorDefinitions);$(ExternalCompilerOptions) @@ -162,7 +164,7 @@ StreamingSIMDExtensions - aclui.lib;comctl32.lib;iphlpapi.lib;noarg.obj;noenv.obj;ntdll.lib;phlib.lib;uxtheme.lib;version.lib;windowscodecs.lib;winsta.lib;ws2_32.lib;%(AdditionalDependencies) + aclui.lib;comctl32.lib;delaylib.lib;iphlpapi.lib;noarg.obj;noenv.obj;ntdll.lib;phlib.lib;uxtheme.lib;version.lib;windowscodecs.lib;winsta.lib;ws2_32.lib;%(AdditionalDependencies) true Windows true @@ -170,9 +172,10 @@ MachineX86 true 6.01 - ..\phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) + ..\phlib\bin\$(Configuration)$(PlatformArchitecture);..\tools\delaylib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) ProcessHacker.def aclui.dll;iphlpapi.dll;ws2_32.dll;%(DelayLoadDLLs) + __delayLoadHelper2 _UNICODE;UNICODE;%(PreprocessorDefinitions);$(ExternalCompilerOptions) @@ -196,7 +199,7 @@ true - aclui.lib;comctl32.lib;iphlpapi.lib;noarg.obj;noenv.obj;ntdll.lib;phlib.lib;uxtheme.lib;version.lib;windowscodecs.lib;winsta.lib;ws2_32.lib;%(AdditionalDependencies) + aclui.lib;comctl32.lib;delaylib.lib;iphlpapi.lib;noarg.obj;noenv.obj;ntdll.lib;phlib.lib;uxtheme.lib;version.lib;windowscodecs.lib;winsta.lib;ws2_32.lib;%(AdditionalDependencies) true Windows true @@ -204,9 +207,10 @@ MachineX64 true 6.01 - ..\phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) + ..\phlib\bin\$(Configuration)$(PlatformArchitecture);..\tools\delaylib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) ProcessHacker.def aclui.dll;iphlpapi.dll;ws2_32.dll;%(DelayLoadDLLs) + __delayLoadHelper2 _UNICODE;UNICODE;%(PreprocessorDefinitions);$(ExternalCompilerOptions) @@ -225,6 +229,7 @@ + diff --git a/ProcessHacker/ProcessHacker.vcxproj.filters b/ProcessHacker/ProcessHacker.vcxproj.filters index e4fac5fddc0e..d8d900f22ea6 100644 --- a/ProcessHacker/ProcessHacker.vcxproj.filters +++ b/ProcessHacker/ProcessHacker.vcxproj.filters @@ -381,6 +381,9 @@ Process Hacker + + Process Hacker + diff --git a/ProcessHacker/exports.c b/ProcessHacker/exports.c new file mode 100644 index 000000000000..c20fa19ae156 --- /dev/null +++ b/ProcessHacker/exports.c @@ -0,0 +1,97 @@ +/* + * Process Hacker - + * exported variables + * + * Copyright (C) 2017 dmex + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include +#include +#include +#include +#include + +HFONT PhGetApplicationFont( + VOID + ) +{ + return PhApplicationFont; +} + +HWND PhGetMainWndHandle( + VOID + ) +{ + return PhMainWndHandle; +} + +PVOID PhGetImageBase( + VOID + ) +{ + return PhLibImageBase; +} + +ULONG PhGetGlobalDpi( + VOID + ) +{ + return PhGlobalDpi; +} + +SYSTEM_BASIC_INFORMATION PhGetSystemBasicInformation( + VOID + ) +{ + return PhSystemBasicInformation; +} + +ACCESS_MASK PhProcessQueryAccess( + VOID + ) +{ + return ProcessQueryAccess; +} + +ACCESS_MASK PhProcessAllAccess( + VOID + ) +{ + return ProcessAllAccess; +} + +ACCESS_MASK PhThreadQueryAccess( + VOID + ) +{ + return ThreadQueryAccess; +} + +ACCESS_MASK PhThreadSetAccess( + VOID + ) +{ + return ThreadSetAccess; +} + +ACCESS_MASK PhThreadAllAccess( + VOID + ) +{ + return ThreadAllAccess; +} \ No newline at end of file diff --git a/ProcessHacker/include/appsup.h b/ProcessHacker/include/appsup.h index fe34c8977206..275273f6d4e8 100644 --- a/ProcessHacker/include/appsup.h +++ b/ProcessHacker/include/appsup.h @@ -416,8 +416,8 @@ PPH_STRING PhPcre2GetErrorMessage( _In_ INT ErrorCode ); -#define PH_LOAD_SHARED_ICON_SMALL(Name) PhLoadIcon(PhInstanceHandle, (Name), PH_LOAD_ICON_SHARED | PH_LOAD_ICON_SIZE_SMALL, 0, 0) -#define PH_LOAD_SHARED_ICON_LARGE(Name) PhLoadIcon(PhInstanceHandle, (Name), PH_LOAD_ICON_SHARED | PH_LOAD_ICON_SIZE_LARGE, 0, 0) +#define PH_LOAD_SHARED_ICON_SMALL(BaseAddress, Name) PhLoadIcon(BaseAddress, (Name), PH_LOAD_ICON_SHARED | PH_LOAD_ICON_SIZE_SMALL, 0, 0) // phapppub +#define PH_LOAD_SHARED_ICON_LARGE(BaseAddress, Name) PhLoadIcon(BaseAddress, (Name), PH_LOAD_ICON_SHARED | PH_LOAD_ICON_SIZE_LARGE, 0, 0) // phapppub FORCEINLINE PVOID PhpGenericPropertyPageHeader( _In_ HWND hwndDlg, diff --git a/ProcessHacker/include/mainwnd.h b/ProcessHacker/include/mainwnd.h index d7607624acd1..d93cc50263ac 100644 --- a/ProcessHacker/include/mainwnd.h +++ b/ProcessHacker/include/mainwnd.h @@ -3,7 +3,7 @@ #define PH_MAINWND_CLASSNAME L"ProcessHacker" // phapppub -PHAPPAPI extern HWND PhMainWndHandle; // phapppub +extern HWND PhMainWndHandle; extern BOOLEAN PhMainWndExiting; #define WM_PH_FIRST (WM_APP + 99) diff --git a/ProcessHacker/include/netprv.h b/ProcessHacker/include/netprv.h index beaecea2b4a1..b4b34835f35f 100644 --- a/ProcessHacker/include/netprv.h +++ b/ProcessHacker/include/netprv.h @@ -2,10 +2,6 @@ #define PH_NETPRV_H extern PPH_OBJECT_TYPE PhNetworkItemType; -PHAPPAPI extern PH_CALLBACK PhNetworkItemAddedEvent; // phapppub -PHAPPAPI extern PH_CALLBACK PhNetworkItemModifiedEvent; // phapppub -PHAPPAPI extern PH_CALLBACK PhNetworkItemRemovedEvent; // phapppub -PHAPPAPI extern PH_CALLBACK PhNetworkItemsUpdatedEvent; // phapppub extern BOOLEAN PhEnableNetworkProviderResolve; diff --git a/ProcessHacker/include/phapp.h b/ProcessHacker/include/phapp.h index 5a9914f8a514..d0160089cf5b 100644 --- a/ProcessHacker/include/phapp.h +++ b/ProcessHacker/include/phapp.h @@ -74,7 +74,7 @@ typedef struct _PH_STARTUP_PARAMETERS extern PPH_STRING PhApplicationDirectory; extern PPH_STRING PhApplicationFileName; -PHAPPAPI extern HFONT PhApplicationFont; // phapppub +extern HFONT PhApplicationFont; extern PPH_STRING PhCurrentUserName; extern HINSTANCE PhInstanceHandle; extern PPH_STRING PhLocalSystemName; @@ -87,8 +87,6 @@ extern PH_STARTUP_PARAMETERS PhStartupParameters; extern PH_PROVIDER_THREAD PhPrimaryProviderThread; extern PH_PROVIDER_THREAD PhSecondaryProviderThread; -#define PH_SCALE_DPI(Value) PhMultiplyDivide(Value, PhGlobalDpi, 96) // phapppub - // begin_phapppub PHAPPAPI VOID @@ -135,6 +133,87 @@ VOID PhInitializeFont( _In_ HWND hWnd ); +// begin_phapppub +PHAPPAPI +HFONT +NTAPI +PhGetApplicationFont( + VOID + ); + +PHAPPAPI +HWND +NTAPI +PhGetMainWndHandle( + VOID + ); + +#define PhMainWindowHandle \ + PhGetMainWndHandle() + +PHLIBAPI +PVOID +NTAPI +PhGetImageBase( + VOID + ); + +#define PhImageBaseAddress \ + PhGetImageBase() + +PHLIBAPI +ULONG +NTAPI +PhGetGlobalDpi( + VOID + ); + +#define PH_SCALE_DPI(Value) \ + PhMultiplyDivide(Value, PhGetGlobalDpi(), 96) + +PHLIBAPI +SYSTEM_BASIC_INFORMATION +NTAPI +PhGetSystemBasicInformation( + VOID + ); + +PHLIBAPI +ACCESS_MASK +NTAPI +PhProcessQueryAccess( + VOID + ); + +PHLIBAPI +ACCESS_MASK +NTAPI +PhProcessAllAccess( + VOID + ); + +PHLIBAPI +ACCESS_MASK +NTAPI +PhThreadQueryAccess( + VOID + ); + +PHLIBAPI +ACCESS_MASK +NTAPI +PhThreadSetAccess( + VOID + ); + +PHLIBAPI +ACCESS_MASK +NTAPI +PhThreadAllAccess( + VOID + ); +// end_phapppub + // plugin extern PH_AVL_TREE PhPluginsByName; @@ -211,7 +290,6 @@ typedef struct _PH_LOG_ENTRY } PH_LOG_ENTRY, *PPH_LOG_ENTRY; extern PH_CIRCULAR_BUFFER_PVOID PhLogBuffer; -PHAPPAPI extern PH_CALLBACK PhLoggedCallback; // phapppub VOID PhLogInitialization( VOID @@ -643,7 +721,7 @@ PhCreateCommonFont( return NULL; fontHandle = CreateFont( - -PhMultiplyDivideSigned(Size, PhGlobalDpi, 72), + -PhMultiplyDivideSigned(Size, PhGetGlobalDpi(), 72), 0, 0, 0, diff --git a/ProcessHacker/include/phplug.h b/ProcessHacker/include/phplug.h index 68ea5602ede1..cc2de419a98c 100644 --- a/ProcessHacker/include/phplug.h +++ b/ProcessHacker/include/phplug.h @@ -44,6 +44,19 @@ typedef enum _PH_GENERAL_CALLBACK GeneralCallbackMemoryItemListControl = 31, // PPH_PLUGIN_MEMORY_ITEM_LIST_CONTROL Data [properties thread] GeneralCallbackMiniInformationInitializing = 32, // PPH_PLUGIN_MINIINFO_POINTERS Data [main thread] GeneralCallbackMiListSectionMenuInitializing = 33, // PPH_PLUGIN_MENU_INFORMATION Data [main thread] + GeneralCallbackLoggedEvent = 34, // PPH_LOG_ENTRY data [provider thread] + GeneralCallbackProcessProviderAdded = 35, // PPH_PROCESS_ITEM data [provider thread] + GeneralCallbackProcessProviderModified = 36, // PPH_PROCESS_ITEM data [provider thread] + GeneralCallbackProcessProviderRemoved = 37, // PPH_PROCESS_ITEM data [provider thread] + GeneralCallbackProcessProviderUpdated = 38, // [provider thread] + GeneralCallbackServiceProviderAdded = 39, // PPH_SERVICE_ITEM data [provider thread] + GeneralCallbackServiceProviderModified = 40, // PPH_SERVICE_ITEM data [provider thread] + GeneralCallbackServiceProviderRemoved = 41, // PPH_SERVICE_ITEM data [provider thread] + GeneralCallbackServiceProviderUpdated = 42, // [provider thread] + GeneralCallbackNetworkProviderAdded = 43, // PPH_NETWORK_ITEM data [provider thread] + GeneralCallbackNetworkProviderModified = 44, // PPH_NETWORK_ITEM data [provider thread] + GeneralCallbackNetworkProviderRemoved = 45, // PPH_NETWORK_ITEM data [provider thread] + GeneralCallbackNetworkProviderUpdated = 46, // [provider thread] GeneralCallbackMaximum } PH_GENERAL_CALLBACK, *PPH_GENERAL_CALLBACK; diff --git a/ProcessHacker/include/procprv.h b/ProcessHacker/include/procprv.h index f79546f534fd..169268452962 100644 --- a/ProcessHacker/include/procprv.h +++ b/ProcessHacker/include/procprv.h @@ -6,11 +6,6 @@ extern PPH_OBJECT_TYPE PhProcessItemType; -PHAPPAPI extern PH_CALLBACK PhProcessAddedEvent; // phapppub -PHAPPAPI extern PH_CALLBACK PhProcessModifiedEvent; // phapppub -PHAPPAPI extern PH_CALLBACK PhProcessRemovedEvent; // phapppub -PHAPPAPI extern PH_CALLBACK PhProcessesUpdatedEvent; // phapppub - extern PPH_LIST PhProcessRecordList; extern PH_QUEUED_LOCK PhProcessRecordListLock; diff --git a/ProcessHacker/include/srvprv.h b/ProcessHacker/include/srvprv.h index a01349d8005e..d511db7cdf69 100644 --- a/ProcessHacker/include/srvprv.h +++ b/ProcessHacker/include/srvprv.h @@ -3,11 +3,6 @@ extern PPH_OBJECT_TYPE PhServiceItemType; -PHAPPAPI extern PH_CALLBACK PhServiceAddedEvent; // phapppub -PHAPPAPI extern PH_CALLBACK PhServiceModifiedEvent; // phapppub -PHAPPAPI extern PH_CALLBACK PhServiceRemovedEvent; // phapppub -PHAPPAPI extern PH_CALLBACK PhServicesUpdatedEvent; // phapppub - extern BOOLEAN PhEnableServiceNonPoll; // begin_phapppub diff --git a/ProcessHacker/log.c b/ProcessHacker/log.c index a57862b1c614..b5334c064109 100644 --- a/ProcessHacker/log.c +++ b/ProcessHacker/log.c @@ -21,11 +21,10 @@ */ #include - +#include #include PH_CIRCULAR_BUFFER_PVOID PhLogBuffer; -PHAPPAPI PH_CALLBACK_DECLARE(PhLoggedCallback); VOID PhLogInitialization( VOID @@ -155,7 +154,7 @@ VOID PhpLogEntry( if (oldEntry) PhpFreeLogEntry(oldEntry); - PhInvokeCallback(&PhLoggedCallback, Entry); + PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackLoggedEvent), Entry); } VOID PhClearLogEntries( diff --git a/ProcessHacker/logwnd.c b/ProcessHacker/logwnd.c index 0a9b71a94b62..2be84a749e1e 100644 --- a/ProcessHacker/logwnd.c +++ b/ProcessHacker/logwnd.c @@ -21,6 +21,7 @@ */ #include +#include #include #include @@ -187,7 +188,7 @@ INT_PTR CALLBACK PhpLogDlgProc( Button_SetCheck(GetDlgItem(hwndDlg, IDC_AUTOSCROLL), BST_CHECKED); - PhRegisterCallback(&PhLoggedCallback, LoggedCallback, NULL, &LoggedRegistration); + PhRegisterCallback(PhGetGeneralCallback(GeneralCallbackLoggedEvent), LoggedCallback, NULL, &LoggedRegistration); PhpUpdateLogList(); ListView_EnsureVisible(ListViewHandle, ListViewCount - 1, FALSE); } @@ -199,7 +200,7 @@ INT_PTR CALLBACK PhpLogDlgProc( PhDeleteLayoutManager(&WindowLayoutManager); - PhUnregisterCallback(&PhLoggedCallback, &LoggedRegistration); + PhUnregisterCallback(PhGetGeneralCallback(GeneralCallbackLoggedEvent), &LoggedRegistration); PhUnregisterDialog(PhLogWindowHandle); PhLogWindowHandle = NULL; } diff --git a/ProcessHacker/main.c b/ProcessHacker/main.c index 3d8b82255a96..f25656fa2284 100644 --- a/ProcessHacker/main.c +++ b/ProcessHacker/main.c @@ -77,7 +77,7 @@ VOID PhpEnablePrivileges( PPH_STRING PhApplicationDirectory; PPH_STRING PhApplicationFileName; -PHAPPAPI HFONT PhApplicationFont; +HFONT PhApplicationFont; PPH_STRING PhCurrentUserName = NULL; HINSTANCE PhInstanceHandle; PPH_STRING PhLocalSystemName = NULL; diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index 3d4c8539dd18..b6b7a5d9c4c6 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -57,7 +57,7 @@ #define RUNAS_MODE_ADMIN 1 #define RUNAS_MODE_LIMITED 2 -PHAPPAPI HWND PhMainWndHandle; +HWND PhMainWndHandle; BOOLEAN PhMainWndExiting = FALSE; HMENU PhMainWndMenuHandle; @@ -342,12 +342,12 @@ BOOLEAN PhMwpInitializeWindowClass( wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = PhInstanceHandle; - wcex.hIcon = PH_LOAD_SHARED_ICON_LARGE(MAKEINTRESOURCE(IDI_PROCESSHACKER)); + wcex.hIcon = PH_LOAD_SHARED_ICON_LARGE(PhLibImageBase, MAKEINTRESOURCE(IDI_PROCESSHACKER)); wcex.hCursor = LoadCursor(NULL, IDC_ARROW); //wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); wcex.lpszMenuName = MAKEINTRESOURCE(IDR_MAINWND); wcex.lpszClassName = PH_MAINWND_CLASSNAME; - wcex.hIconSm = PH_LOAD_SHARED_ICON_SMALL(MAKEINTRESOURCE(IDI_PROCESSHACKER)); + wcex.hIconSm = PH_LOAD_SHARED_ICON_SMALL(PhLibImageBase, MAKEINTRESOURCE(IDI_PROCESSHACKER)); if (!RegisterClassEx(&wcex)) return FALSE; diff --git a/ProcessHacker/memlists.c b/ProcessHacker/memlists.c index 6f73a3f3d918..093db01c7a5b 100644 --- a/ProcessHacker/memlists.c +++ b/ProcessHacker/memlists.c @@ -21,6 +21,7 @@ */ #include +#include #include #include @@ -171,7 +172,7 @@ INT_PTR CALLBACK PhpMemoryListsDlgProc( { case WM_INITDIALOG: { - PhRegisterCallback(&PhProcessesUpdatedEvent, ProcessesUpdatedCallback, NULL, &ProcessesUpdatedRegistration); + PhRegisterCallback(PhGetGeneralCallback(GeneralCallbackProcessProviderUpdated), ProcessesUpdatedCallback, NULL, &ProcessesUpdatedRegistration); PhpUpdateMemoryListInfo(hwndDlg); PhLoadWindowPlacementFromSetting(L"MemoryListsWindowPosition", NULL, hwndDlg); @@ -183,7 +184,7 @@ INT_PTR CALLBACK PhpMemoryListsDlgProc( PhUnregisterDialog(hwndDlg); PhSaveWindowPlacementToSetting(L"MemoryListsWindowPosition", NULL, hwndDlg); - PhUnregisterCallback(&PhProcessesUpdatedEvent, &ProcessesUpdatedRegistration); + PhUnregisterCallback(PhGetGeneralCallback(GeneralCallbackProcessProviderUpdated), &ProcessesUpdatedRegistration); UnregisterDialogFunction(hwndDlg); PhMemoryListsWindowHandle = NULL; diff --git a/ProcessHacker/miniinfo.c b/ProcessHacker/miniinfo.c index 01d139a083e8..b3e2f4105b47 100644 --- a/ProcessHacker/miniinfo.c +++ b/ProcessHacker/miniinfo.c @@ -110,11 +110,11 @@ VOID PhPinMiniInformation( wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = PhInstanceHandle; - wcex.hIcon = PH_LOAD_SHARED_ICON_LARGE(MAKEINTRESOURCE(IDI_PROCESSHACKER)); + wcex.hIcon = PH_LOAD_SHARED_ICON_LARGE(PhLibImageBase, MAKEINTRESOURCE(IDI_PROCESSHACKER)); wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1); wcex.lpszClassName = MIP_CONTAINER_CLASSNAME; - wcex.hIconSm = PH_LOAD_SHARED_ICON_SMALL(MAKEINTRESOURCE(IDI_PROCESSHACKER)); + wcex.hIconSm = PH_LOAD_SHARED_ICON_SMALL(PhLibImageBase, MAKEINTRESOURCE(IDI_PROCESSHACKER)); RegisterClassEx(&wcex); PhMipContainerWindow = CreateWindow( @@ -337,7 +337,7 @@ VOID PhMipContainerOnShowWindow( PhMipMessageLoopFilterEntry = PhRegisterMessageLoopFilter(PhMipMessageLoopFilter, NULL); PhRegisterCallback( - &PhProcessesUpdatedEvent, + PhGetGeneralCallback(GeneralCallbackProcessProviderUpdated), PhMipUpdateHandler, NULL, &ProcessesUpdatedRegistration @@ -357,7 +357,7 @@ VOID PhMipContainerOnShowWindow( PhSetIntegerSetting(L"MiniInfoWindowPinned", FALSE); PhUnregisterCallback( - &PhProcessesUpdatedEvent, + PhGetGeneralCallback(GeneralCallbackProcessProviderUpdated), &ProcessesUpdatedRegistration ); @@ -448,10 +448,10 @@ VOID PhMipOnInitDialog( HICON cog; HICON pin; - cog = PH_LOAD_SHARED_ICON_SMALL(MAKEINTRESOURCE(IDI_COG)); + cog = PH_LOAD_SHARED_ICON_SMALL(PhLibImageBase, MAKEINTRESOURCE(IDI_COG)); SET_BUTTON_ICON(PhMipWindow, IDC_OPTIONS, cog); - pin = PH_LOAD_SHARED_ICON_SMALL(MAKEINTRESOURCE(IDI_PIN)); + pin = PH_LOAD_SHARED_ICON_SMALL(PhLibImageBase, MAKEINTRESOURCE(IDI_PIN)); SET_BUTTON_ICON(PhMipWindow, IDC_PIN, pin); PhInitializeLayoutManager(&PhMipLayoutManager, PhMipWindow); diff --git a/ProcessHacker/mwpgnet.c b/ProcessHacker/mwpgnet.c index c8fa1d5cd18f..4229dd858ed3 100644 --- a/ProcessHacker/mwpgnet.c +++ b/ProcessHacker/mwpgnet.c @@ -62,25 +62,25 @@ BOOLEAN PhMwpNetworkPageCallback( PhMwpNetworkPage = Page; PhRegisterCallback( - &PhNetworkItemAddedEvent, + PhGetGeneralCallback(GeneralCallbackNetworkProviderAdded), PhMwpNetworkItemAddedHandler, NULL, &NetworkItemAddedRegistration ); PhRegisterCallback( - &PhNetworkItemModifiedEvent, + PhGetGeneralCallback(GeneralCallbackNetworkProviderModified), PhMwpNetworkItemModifiedHandler, NULL, &NetworkItemModifiedRegistration ); PhRegisterCallback( - &PhNetworkItemRemovedEvent, + PhGetGeneralCallback(GeneralCallbackNetworkProviderRemoved), PhMwpNetworkItemRemovedHandler, NULL, &NetworkItemRemovedRegistration ); PhRegisterCallback( - &PhNetworkItemsUpdatedEvent, + PhGetGeneralCallback(GeneralCallbackNetworkProviderUpdated), PhMwpNetworkItemsUpdatedHandler, NULL, &NetworkItemsUpdatedRegistration diff --git a/ProcessHacker/mwpgproc.c b/ProcessHacker/mwpgproc.c index 11307c937294..6d0fbad59d2b 100644 --- a/ProcessHacker/mwpgproc.c +++ b/ProcessHacker/mwpgproc.c @@ -70,25 +70,25 @@ BOOLEAN PhMwpProcessesPageCallback( PhMwpProcessesPage = Page; PhRegisterCallback( - &PhProcessAddedEvent, + PhGetGeneralCallback(GeneralCallbackProcessProviderAdded), PhMwpProcessAddedHandler, NULL, &ProcessAddedRegistration ); PhRegisterCallback( - &PhProcessModifiedEvent, + PhGetGeneralCallback(GeneralCallbackProcessProviderModified), PhMwpProcessModifiedHandler, NULL, &ProcessModifiedRegistration ); PhRegisterCallback( - &PhProcessRemovedEvent, + PhGetGeneralCallback(GeneralCallbackProcessProviderRemoved), PhMwpProcessRemovedHandler, NULL, &ProcessRemovedRegistration ); PhRegisterCallback( - &PhProcessesUpdatedEvent, + PhGetGeneralCallback(GeneralCallbackProcessProviderUpdated), PhMwpProcessesUpdatedHandler, NULL, &ProcessesUpdatedRegistration diff --git a/ProcessHacker/mwpgsrv.c b/ProcessHacker/mwpgsrv.c index 866ca49dc2e3..f9e1ff1832a7 100644 --- a/ProcessHacker/mwpgsrv.c +++ b/ProcessHacker/mwpgsrv.c @@ -63,25 +63,25 @@ BOOLEAN PhMwpServicesPageCallback( PhMwpServicesPage = Page; PhRegisterCallback( - &PhServiceAddedEvent, + PhGetGeneralCallback(GeneralCallbackServiceProviderAdded), PhMwpServiceAddedHandler, NULL, &ServiceAddedRegistration ); PhRegisterCallback( - &PhServiceModifiedEvent, + PhGetGeneralCallback(GeneralCallbackServiceProviderModified), PhMwpServiceModifiedHandler, NULL, &ServiceModifiedRegistration ); PhRegisterCallback( - &PhServiceRemovedEvent, + PhGetGeneralCallback(GeneralCallbackServiceProviderRemoved), PhMwpServiceRemovedHandler, NULL, &ServiceRemovedRegistration ); PhRegisterCallback( - &PhServicesUpdatedEvent, + PhGetGeneralCallback(GeneralCallbackServiceProviderUpdated), PhMwpServicesUpdatedHandler, NULL, &ServicesUpdatedRegistration diff --git a/ProcessHacker/netprv.c b/ProcessHacker/netprv.c index d3cc1187db6a..1247c49721d1 100644 --- a/ProcessHacker/netprv.c +++ b/ProcessHacker/netprv.c @@ -23,6 +23,7 @@ #include #include +#include #include #include @@ -94,11 +95,6 @@ PPH_OBJECT_TYPE PhNetworkItemType; PPH_HASHTABLE PhNetworkHashtable; PH_QUEUED_LOCK PhNetworkHashtableLock = PH_QUEUED_LOCK_INIT; -PHAPPAPI PH_CALLBACK_DECLARE(PhNetworkItemAddedEvent); -PHAPPAPI PH_CALLBACK_DECLARE(PhNetworkItemModifiedEvent); -PHAPPAPI PH_CALLBACK_DECLARE(PhNetworkItemRemovedEvent); -PHAPPAPI PH_CALLBACK_DECLARE(PhNetworkItemsUpdatedEvent); - PH_INITONCE PhNetworkProviderWorkQueueInitOnce = PH_INITONCE_INIT; PH_WORK_QUEUE PhNetworkProviderWorkQueue; SLIST_HEADER PhNetworkItemQueryListHead; @@ -503,7 +499,7 @@ VOID PhNetworkProviderUpdate( if (!found) { - PhInvokeCallback(&PhNetworkItemRemovedEvent, *networkItem); + PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackNetworkProviderRemoved), *networkItem); if (!connectionsToRemove) connectionsToRemove = PhCreateList(2); @@ -666,7 +662,7 @@ VOID PhNetworkProviderUpdate( PhReleaseQueuedLockExclusive(&PhNetworkHashtableLock); // Raise the network item added event. - PhInvokeCallback(&PhNetworkItemAddedEvent, networkItem); + PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackNetworkProviderAdded), networkItem); } else { @@ -710,7 +706,7 @@ VOID PhNetworkProviderUpdate( if (modified) { // Raise the network item modified event. - PhInvokeCallback(&PhNetworkItemModifiedEvent, networkItem); + PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackNetworkProviderModified), networkItem); } PhDereferenceObject(networkItem); @@ -719,7 +715,7 @@ VOID PhNetworkProviderUpdate( PhFree(connections); - PhInvokeCallback(&PhNetworkItemsUpdatedEvent, NULL); + PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackNetworkProviderUpdated), NULL); } PWSTR PhGetProtocolTypeName( diff --git a/ProcessHacker/notifico.c b/ProcessHacker/notifico.c index 729f81412e78..7ad86bbb1486 100644 --- a/ProcessHacker/notifico.c +++ b/ProcessHacker/notifico.c @@ -113,7 +113,7 @@ VOID PhNfLoadStage2( } PhRegisterCallback( - &PhProcessesUpdatedEvent, + PhGetGeneralCallback(GeneralCallbackProcessProviderUpdated), PhNfpProcessesUpdatedHandler, NULL, &PhNfpProcessesUpdatedRegistration diff --git a/ProcessHacker/plugin.c b/ProcessHacker/plugin.c index 8f30f4e9da33..efb22a49c654 100644 --- a/ProcessHacker/plugin.c +++ b/ProcessHacker/plugin.c @@ -264,30 +264,30 @@ VOID PhLoadPlugins( // In certain startup modes we want to ignore all plugin load errors. if (LoadErrors && LoadErrors->Count != 0 && !PhStartupParameters.PhSvc) { - PH_STRING_BUILDER sb; + PH_STRING_BUILDER stringBuilder; ULONG i; PPHP_PLUGIN_LOAD_ERROR loadError; PPH_STRING baseName; - PhInitializeStringBuilder(&sb, 100); - PhAppendStringBuilder2(&sb, L"Unable to load the following plugin(s):\n\n"); + PhInitializeStringBuilder(&stringBuilder, 100); for (i = 0; i < LoadErrors->Count; i++) { loadError = LoadErrors->Items[i]; baseName = PhGetBaseName(loadError->FileName); - PhAppendFormatStringBuilder(&sb, L"%s: %s\n", + PhAppendFormatStringBuilder(&stringBuilder, L"%s: %s\n", baseName->Buffer, PhGetStringOrDefault(loadError->ErrorMessage, L"An unknown error occurred.")); PhDereferenceObject(baseName); } - PhAppendStringBuilder2(&sb, L"\nDo you want to disable the above plugin(s)?"); + if (stringBuilder.String->Length != 0) + PhRemoveEndStringBuilder(&stringBuilder, 1); - if (PhShowMessage( + if (PhShowError2( NULL, - MB_ICONERROR | MB_YESNO, - sb.String->Buffer - ) == IDYES) + L"Unable to load the following plugin(s):", + stringBuilder.String->Buffer + )) { ULONG i; @@ -300,7 +300,7 @@ VOID PhLoadPlugins( } } - PhDeleteStringBuilder(&sb); + PhDeleteStringBuilder(&stringBuilder); } // When we loaded settings before, we didn't know about plugin settings, so they diff --git a/ProcessHacker/procprv.c b/ProcessHacker/procprv.c index 9445050002f7..06ba7e4c6a69 100644 --- a/ProcessHacker/procprv.c +++ b/ProcessHacker/procprv.c @@ -179,11 +179,6 @@ PH_QUEUED_LOCK PhProcessHashSetLock = PH_QUEUED_LOCK_INIT; SLIST_HEADER PhProcessQueryDataListHead; -PHAPPAPI PH_CALLBACK_DECLARE(PhProcessAddedEvent); -PHAPPAPI PH_CALLBACK_DECLARE(PhProcessModifiedEvent); -PHAPPAPI PH_CALLBACK_DECLARE(PhProcessRemovedEvent); -PHAPPAPI PH_CALLBACK_DECLARE(PhProcessesUpdatedEvent); - PPH_LIST PhProcessRecordList; PH_QUEUED_LOCK PhProcessRecordListLock = PH_QUEUED_LOCK_INIT; @@ -1901,7 +1896,7 @@ VOID PhFlushProcessQueryData( // which will lead to very bad things happening. PhAcquireQueuedLockExclusive(&data->ProcessItem->RemoveLock); if (!(data->ProcessItem->State & PH_PROCESS_ITEM_REMOVED)) - PhInvokeCallback(&PhProcessModifiedEvent, data->ProcessItem); + PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackProcessProviderModified), data->ProcessItem); PhReleaseQueuedLockExclusive(&data->ProcessItem->RemoveLock); } else @@ -2176,7 +2171,7 @@ VOID PhProcessProviderUpdate( // Raise the process removed event. // See PhFlushProcessQueryData for why we need to lock here. PhAcquireQueuedLockExclusive(&processItem->RemoveLock); - PhInvokeCallback(&PhProcessRemovedEvent, processItem); + PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackProcessProviderRemoved), processItem); PhReleaseQueuedLockExclusive(&processItem->RemoveLock); if (!processesToRemove) @@ -2298,7 +2293,7 @@ VOID PhProcessProviderUpdate( PhReleaseQueuedLockExclusive(&PhProcessHashSetLock); // Raise the process added event. - PhInvokeCallback(&PhProcessAddedEvent, processItem); + PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackProcessProviderAdded), processItem); processItem->AddedEventSent = TRUE; // (Ref: for the process item being in the hashtable.) @@ -2461,7 +2456,7 @@ VOID PhProcessProviderUpdate( if (modified) { - PhInvokeCallback(&PhProcessModifiedEvent, processItem); + PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackProcessProviderModified), processItem); } // No reference added by PhpLookupProcessItem. @@ -2562,7 +2557,7 @@ VOID PhProcessProviderUpdate( } } - PhInvokeCallback(&PhProcessesUpdatedEvent, NULL); + PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackProcessProviderUpdated), NULL); runCount++; } diff --git a/ProcessHacker/procrec.c b/ProcessHacker/procrec.c index 486a3db8841c..dbcb2c98019a 100644 --- a/ProcessHacker/procrec.c +++ b/ProcessHacker/procrec.c @@ -186,7 +186,7 @@ INT_PTR CALLBACK PhpProcessRecordDlgProc( context->FileIcon = PhGetFileShellIcon(PhGetString(context->Record->FileName), L".exe", TRUE); SendMessage(GetDlgItem(hwndDlg, IDC_OPENFILENAME), BM_SETIMAGE, IMAGE_ICON, - (LPARAM)PH_LOAD_SHARED_ICON_SMALL(MAKEINTRESOURCE(IDI_FOLDER))); + (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhLibImageBase, MAKEINTRESOURCE(IDI_FOLDER))); SendMessage(GetDlgItem(hwndDlg, IDC_FILEICON), STM_SETICON, (WPARAM)context->FileIcon, 0); diff --git a/ProcessHacker/prpggen.c b/ProcessHacker/prpggen.c index 30b2115d2695..76318e4492e0 100644 --- a/ProcessHacker/prpggen.c +++ b/ProcessHacker/prpggen.c @@ -147,8 +147,8 @@ INT_PTR CALLBACK PhpProcessGeneralDlgProc( HICON folder; HICON magnifier; - folder = PH_LOAD_SHARED_ICON_SMALL(MAKEINTRESOURCE(IDI_FOLDER)); - magnifier = PH_LOAD_SHARED_ICON_SMALL(MAKEINTRESOURCE(IDI_MAGNIFIER)); + folder = PH_LOAD_SHARED_ICON_SMALL(PhLibImageBase, MAKEINTRESOURCE(IDI_FOLDER)); + magnifier = PH_LOAD_SHARED_ICON_SMALL(PhLibImageBase, MAKEINTRESOURCE(IDI_MAGNIFIER)); SET_BUTTON_ICON(IDC_INSPECT, magnifier); SET_BUTTON_ICON(IDC_OPENFILENAME, folder); diff --git a/ProcessHacker/prpgperf.c b/ProcessHacker/prpgperf.c index 9efb80e93072..d525919ab666 100644 --- a/ProcessHacker/prpgperf.c +++ b/ProcessHacker/prpgperf.c @@ -21,6 +21,7 @@ */ #include +#include #include #include @@ -74,7 +75,7 @@ INT_PTR CALLBACK PhpProcessPerformanceDlgProc( performanceContext->WindowHandle = hwndDlg; PhRegisterCallback( - &PhProcessesUpdatedEvent, + PhGetGeneralCallback(GeneralCallbackProcessProviderUpdated), PerformanceUpdateHandler, performanceContext, &performanceContext->ProcessesUpdatedRegistration @@ -113,7 +114,7 @@ INT_PTR CALLBACK PhpProcessPerformanceDlgProc( PhDeleteGraphState(&performanceContext->IoGraphState); PhUnregisterCallback( - &PhProcessesUpdatedEvent, + PhGetGeneralCallback(GeneralCallbackProcessProviderUpdated), &performanceContext->ProcessesUpdatedRegistration ); PhFree(performanceContext); diff --git a/ProcessHacker/prpgstat.c b/ProcessHacker/prpgstat.c index 97b0127b4ea9..4953d401b699 100644 --- a/ProcessHacker/prpgstat.c +++ b/ProcessHacker/prpgstat.c @@ -21,6 +21,7 @@ */ #include +#include #include #include @@ -246,7 +247,7 @@ INT_PTR CALLBACK PhpProcessStatisticsDlgProc( ); PhRegisterCallback( - &PhProcessesUpdatedEvent, + PhGetGeneralCallback(GeneralCallbackProcessProviderUpdated), StatisticsUpdateHandler, statisticsContext, &statisticsContext->ProcessesUpdatedRegistration @@ -258,7 +259,7 @@ INT_PTR CALLBACK PhpProcessStatisticsDlgProc( case WM_DESTROY: { PhUnregisterCallback( - &PhProcessesUpdatedEvent, + PhGetGeneralCallback(GeneralCallbackProcessProviderUpdated), &statisticsContext->ProcessesUpdatedRegistration ); diff --git a/ProcessHacker/prpgthrd.c b/ProcessHacker/prpgthrd.c index 53e2cf7797e5..cf23dd2cccc2 100644 --- a/ProcessHacker/prpgthrd.c +++ b/ProcessHacker/prpgthrd.c @@ -639,7 +639,7 @@ INT_PTR CALLBACK PhpProcessThreadsDlgProc( PhThreadProviderInitialUpdate(threadsContext->Provider); PhRegisterThreadProvider(threadsContext->Provider, &threadsContext->ProviderRegistration); - SET_BUTTON_ICON(IDC_OPENSTARTMODULE, PH_LOAD_SHARED_ICON_SMALL(MAKEINTRESOURCE(IDI_FOLDER))); + SET_BUTTON_ICON(IDC_OPENSTARTMODULE, PH_LOAD_SHARED_ICON_SMALL(PhLibImageBase, MAKEINTRESOURCE(IDI_FOLDER))); } break; case WM_DESTROY: diff --git a/ProcessHacker/srvctl.c b/ProcessHacker/srvctl.c index a53d1f769498..3596d3176853 100644 --- a/ProcessHacker/srvctl.c +++ b/ProcessHacker/srvctl.c @@ -21,6 +21,7 @@ */ #include +#include #include #include @@ -229,7 +230,7 @@ INT_PTR CALLBACK PhpServicesPageProc( ULONG i; PhRegisterCallback( - &PhServiceModifiedEvent, + PhGetGeneralCallback(GeneralCallbackServiceProviderModified), ServiceModifiedHandler, servicesContext, &servicesContext->ModifiedEventRegistration @@ -280,7 +281,7 @@ INT_PTR CALLBACK PhpServicesPageProc( PhFree(servicesContext->Services); PhUnregisterCallback( - &PhServiceModifiedEvent, + PhGetGeneralCallback(GeneralCallbackServiceProviderModified), &servicesContext->ModifiedEventRegistration ); diff --git a/ProcessHacker/srvlist.c b/ProcessHacker/srvlist.c index 003e86f51e31..1e2eaeb655df 100644 --- a/ProcessHacker/srvlist.c +++ b/ProcessHacker/srvlist.c @@ -689,10 +689,10 @@ BOOLEAN NTAPI PhpServiceTreeNewCallback( if (!ServiceIconsLoaded) { - ServiceApplicationIcon = PH_LOAD_SHARED_ICON_SMALL(MAKEINTRESOURCE(IDI_PHAPPLICATION)); - ServiceApplicationGoIcon = PH_LOAD_SHARED_ICON_SMALL(MAKEINTRESOURCE(IDI_PHAPPLICATIONGO)); - ServiceCogIcon = PH_LOAD_SHARED_ICON_SMALL(MAKEINTRESOURCE(IDI_COG)); - ServiceCogGoIcon = PH_LOAD_SHARED_ICON_SMALL(MAKEINTRESOURCE(IDI_COGGO)); + ServiceApplicationIcon = PH_LOAD_SHARED_ICON_SMALL(PhLibImageBase, MAKEINTRESOURCE(IDI_PHAPPLICATION)); + ServiceApplicationGoIcon = PH_LOAD_SHARED_ICON_SMALL(PhLibImageBase, MAKEINTRESOURCE(IDI_PHAPPLICATIONGO)); + ServiceCogIcon = PH_LOAD_SHARED_ICON_SMALL(PhLibImageBase, MAKEINTRESOURCE(IDI_COG)); + ServiceCogGoIcon = PH_LOAD_SHARED_ICON_SMALL(PhLibImageBase, MAKEINTRESOURCE(IDI_COGGO)); ServiceIconsLoaded = TRUE; } diff --git a/ProcessHacker/srvprv.c b/ProcessHacker/srvprv.c index 18f258c7aa3d..b716fa37a141 100644 --- a/ProcessHacker/srvprv.c +++ b/ProcessHacker/srvprv.c @@ -22,6 +22,7 @@ #include #include +#include #include #include @@ -93,11 +94,6 @@ PPH_OBJECT_TYPE PhServiceItemType; PPH_HASHTABLE PhServiceHashtable; PH_QUEUED_LOCK PhServiceHashtableLock = PH_QUEUED_LOCK_INIT; -PHAPPAPI PH_CALLBACK_DECLARE(PhServiceAddedEvent); -PHAPPAPI PH_CALLBACK_DECLARE(PhServiceModifiedEvent); -PHAPPAPI PH_CALLBACK_DECLARE(PhServiceRemovedEvent); -PHAPPAPI PH_CALLBACK_DECLARE(PhServicesUpdatedEvent); - BOOLEAN PhEnableServiceNonPoll = FALSE; static BOOLEAN PhpNonPollInitialized = FALSE; static BOOLEAN PhpNonPollActive = FALSE; @@ -579,7 +575,7 @@ VOID PhServiceProviderUpdate( } // Raise the service removed event. - PhInvokeCallback(&PhServiceRemovedEvent, *serviceItem); + PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackServiceProviderRemoved), *serviceItem); if (!servicesToRemove) servicesToRemove = PhCreateList(2); @@ -654,7 +650,7 @@ VOID PhServiceProviderUpdate( PhReleaseQueuedLockExclusive(&PhServiceHashtableLock); // Raise the service added event. - PhInvokeCallback(&PhServiceAddedEvent, serviceItem); + PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackServiceProviderAdded), serviceItem); } else { @@ -758,7 +754,7 @@ VOID PhServiceProviderUpdate( } // Raise the service modified event. - PhInvokeCallback(&PhServiceModifiedEvent, &serviceModifiedData); + PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackServiceProviderModified), &serviceModifiedData); } } } @@ -767,7 +763,7 @@ VOID PhServiceProviderUpdate( PhFree(services); UpdateEnd: - PhInvokeCallback(&PhServicesUpdatedEvent, NULL); + PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackServiceProviderUpdated), NULL); runCount++; } diff --git a/ProcessHacker/sysinfo.c b/ProcessHacker/sysinfo.c index 5dcbb236ea54..ee2feb3038ad 100644 --- a/ProcessHacker/sysinfo.c +++ b/ProcessHacker/sysinfo.c @@ -281,8 +281,8 @@ VOID PhSipOnInitDialog( VOID ) { - SendMessage(PhSipWindow, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(MAKEINTRESOURCE(IDI_PROCESSHACKER))); - SendMessage(PhSipWindow, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(MAKEINTRESOURCE(IDI_PROCESSHACKER))); + SendMessage(PhSipWindow, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhLibImageBase, MAKEINTRESOURCE(IDI_PROCESSHACKER))); + SendMessage(PhSipWindow, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhLibImageBase, MAKEINTRESOURCE(IDI_PROCESSHACKER))); PhInitializeLayoutManager(&WindowLayoutManager, PhSipWindow); @@ -291,7 +291,7 @@ VOID PhSipOnInitDialog( PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(PhSipWindow, IDOK), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); PhRegisterCallback( - &PhProcessesUpdatedEvent, + PhGetGeneralCallback(GeneralCallbackProcessProviderUpdated), PhSipSysInfoUpdateHandler, NULL, &ProcessesUpdatedRegistration @@ -313,7 +313,7 @@ VOID PhSipOnDestroy( ) { PhUnregisterCallback( - &PhProcessesUpdatedEvent, + PhGetGeneralCallback(GeneralCallbackProcessProviderUpdated), &ProcessesUpdatedRegistration ); diff --git a/ProcessHacker/thrdprv.c b/ProcessHacker/thrdprv.c index 8f7a60b85b6a..ac616f887e03 100644 --- a/ProcessHacker/thrdprv.c +++ b/ProcessHacker/thrdprv.c @@ -27,6 +27,7 @@ */ #include +#include #include #include @@ -212,7 +213,7 @@ VOID PhRegisterThreadProvider( ) { PhReferenceObject(ThreadProvider); - PhRegisterCallback(&PhProcessesUpdatedEvent, PhpThreadProviderCallbackHandler, ThreadProvider, CallbackRegistration); + PhRegisterCallback(PhGetGeneralCallback(GeneralCallbackProcessProviderUpdated), PhpThreadProviderCallbackHandler, ThreadProvider, CallbackRegistration); } VOID PhUnregisterThreadProvider( @@ -220,7 +221,7 @@ VOID PhUnregisterThreadProvider( _In_ PPH_CALLBACK_REGISTRATION CallbackRegistration ) { - PhUnregisterCallback(&PhProcessesUpdatedEvent, CallbackRegistration); + PhUnregisterCallback(PhGetGeneralCallback(GeneralCallbackProcessProviderUpdated), CallbackRegistration); PhDereferenceObject(ThreadProvider); } diff --git a/phlib/global.c b/phlib/global.c index fb8a44453ab0..34c6ddf1eaf4 100644 --- a/phlib/global.c +++ b/phlib/global.c @@ -38,20 +38,19 @@ VOID PhInitializeWindowsVersion( VOID ); -PHLIBAPI PVOID PhLibImageBase; - -PHLIBAPI PWSTR PhApplicationName = L"Application"; -PHLIBAPI ULONG PhGlobalDpi = 96; -PHLIBAPI PVOID PhHeapHandle; -PHLIBAPI RTL_OSVERSIONINFOEXW PhOsVersion; -PHLIBAPI SYSTEM_BASIC_INFORMATION PhSystemBasicInformation; -PHLIBAPI ULONG WindowsVersion; - -PHLIBAPI ACCESS_MASK ProcessQueryAccess; -PHLIBAPI ACCESS_MASK ProcessAllAccess; -PHLIBAPI ACCESS_MASK ThreadQueryAccess; -PHLIBAPI ACCESS_MASK ThreadSetAccess; -PHLIBAPI ACCESS_MASK ThreadAllAccess; +PVOID PhLibImageBase; +PWSTR PhApplicationName = L"Application"; +ULONG PhGlobalDpi = 96; +PVOID PhHeapHandle; +RTL_OSVERSIONINFOEXW PhOsVersion; +SYSTEM_BASIC_INFORMATION PhSystemBasicInformation; +ULONG WindowsVersion; + +ACCESS_MASK ProcessQueryAccess; +ACCESS_MASK ProcessAllAccess; +ACCESS_MASK ThreadQueryAccess; +ACCESS_MASK ThreadSetAccess; +ACCESS_MASK ThreadAllAccess; // Internal data #ifdef DEBUG @@ -237,3 +236,10 @@ static VOID PhInitializeWindowsVersion( ThreadAllAccess = STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x3ff; } } + +ULONG PhWindowsVersion( + VOID + ) +{ + return WindowsVersion; +} \ No newline at end of file diff --git a/phlib/include/phconfig.h b/phlib/include/phconfig.h index 75892b856fe8..d163c60ecaed 100644 --- a/phlib/include/phconfig.h +++ b/phlib/include/phconfig.h @@ -7,47 +7,19 @@ extern "C" { #define _User_set_ -PHLIBAPI extern _User_set_ PVOID PhLibImageBase; - -PHLIBAPI extern _User_set_ PWSTR PhApplicationName; -PHLIBAPI extern _User_set_ ULONG PhGlobalDpi; -PHLIBAPI extern PVOID PhHeapHandle; -PHLIBAPI extern RTL_OSVERSIONINFOEXW PhOsVersion; -PHLIBAPI extern SYSTEM_BASIC_INFORMATION PhSystemBasicInformation; -PHLIBAPI extern ULONG WindowsVersion; - -PHLIBAPI extern ACCESS_MASK ProcessQueryAccess; -PHLIBAPI extern ACCESS_MASK ProcessAllAccess; -PHLIBAPI extern ACCESS_MASK ThreadQueryAccess; -PHLIBAPI extern ACCESS_MASK ThreadSetAccess; -PHLIBAPI extern ACCESS_MASK ThreadAllAccess; - -#define WINDOWS_ANCIENT 0 -#define WINDOWS_XP 51 -#define WINDOWS_SERVER_2003 52 -#define WINDOWS_VISTA 60 -#define WINDOWS_7 61 -#define WINDOWS_8 62 -#define WINDOWS_8_1 63 -#define WINDOWS_10 100 -#define WINDOWS_NEW MAXLONG - -#define WINDOWS_HAS_CONSOLE_HOST (WindowsVersion >= WINDOWS_7) -#define WINDOWS_HAS_CYCLE_TIME (WindowsVersion >= WINDOWS_VISTA) -#define WINDOWS_HAS_IFILEDIALOG (WindowsVersion >= WINDOWS_VISTA) -#define WINDOWS_HAS_IMAGE_FILE_NAME_BY_PROCESS_ID (WindowsVersion >= WINDOWS_VISTA) -#define WINDOWS_HAS_IMMERSIVE (WindowsVersion >= WINDOWS_8) -#define WINDOWS_HAS_LIMITED_ACCESS (WindowsVersion >= WINDOWS_VISTA) -#define WINDOWS_HAS_SERVICE_TAGS (WindowsVersion >= WINDOWS_VISTA) -#define WINDOWS_HAS_UAC (WindowsVersion >= WINDOWS_VISTA) - -// Debugging - -#ifdef DEBUG -#define dprintf(format, ...) DbgPrint(format, __VA_ARGS__) -#else -#define dprintf(format, ...) -#endif +extern _User_set_ PVOID PhLibImageBase; +extern _User_set_ PWSTR PhApplicationName; +extern _User_set_ ULONG PhGlobalDpi; +extern PVOID PhHeapHandle; +extern RTL_OSVERSIONINFOEXW PhOsVersion; +extern SYSTEM_BASIC_INFORMATION PhSystemBasicInformation; +extern ULONG WindowsVersion; + +extern ACCESS_MASK ProcessQueryAccess; +extern ACCESS_MASK ProcessAllAccess; +extern ACCESS_MASK ThreadQueryAccess; +extern ACCESS_MASK ThreadSetAccess; +extern ACCESS_MASK ThreadAllAccess; // global @@ -102,6 +74,23 @@ PhIsExecutingInWow64( ); #endif + +PHLIBAPI +ULONG +NTAPI +PhWindowsVersion( + VOID + ); + +#define WINDOWS_HAS_CONSOLE_HOST (PhWindowsVersion() >= WINDOWS_7) +#define WINDOWS_HAS_CYCLE_TIME (PhWindowsVersion() >= WINDOWS_VISTA) +#define WINDOWS_HAS_IFILEDIALOG (PhWindowsVersion() >= WINDOWS_VISTA) +#define WINDOWS_HAS_IMAGE_FILE_NAME_BY_PROCESS_ID (PhWindowsVersion() >= WINDOWS_VISTA) +#define WINDOWS_HAS_IMMERSIVE (PhWindowsVersion() >= WINDOWS_8) +#define WINDOWS_HAS_LIMITED_ACCESS (PhWindowsVersion() >= WINDOWS_VISTA) +#define WINDOWS_HAS_SERVICE_TAGS (PhWindowsVersion() >= WINDOWS_VISTA) +#define WINDOWS_HAS_UAC (PhWindowsVersion() >= WINDOWS_VISTA) + #ifdef __cplusplus } #endif diff --git a/phlib/include/phsup.h b/phlib/include/phsup.h index 55e36cf5160f..82e4b306303e 100644 --- a/phlib/include/phsup.h +++ b/phlib/include/phsup.h @@ -8,6 +8,14 @@ #include #include +// Debugging + +#ifdef DEBUG +#define dprintf(format, ...) DbgPrint(format, __VA_ARGS__) +#else +#define dprintf(format, ...) +#endif + // Memory #define PTR_ADD_OFFSET(Pointer, Offset) ((PVOID)((ULONG_PTR)(Pointer) + (ULONG_PTR)(Offset))) diff --git a/phlib/phlib.vcxproj.filters b/phlib/phlib.vcxproj.filters index cae851a27dce..dee92e1b386b 100644 --- a/phlib/phlib.vcxproj.filters +++ b/phlib/phlib.vcxproj.filters @@ -1,4 +1,4 @@ - + diff --git a/phnt/include/phnt.h b/phnt/include/phnt.h index 42bf2a9d8007..1d7dffcca31e 100644 --- a/phnt/include/phnt.h +++ b/phnt/include/phnt.h @@ -24,6 +24,16 @@ #define PHNT_MODE_USER 1 // Version +#define WINDOWS_ANCIENT 0 +#define WINDOWS_XP 51 +#define WINDOWS_SERVER_2003 52 +#define WINDOWS_VISTA 60 +#define WINDOWS_7 61 +#define WINDOWS_8 62 +#define WINDOWS_8_1 63 +#define WINDOWS_10 100 +#define WINDOWS_NEW MAXLONG + #define PHNT_WIN2K 50 #define PHNT_WINXP 51 #define PHNT_WS03 52 diff --git a/plugins/DotNetTools/clrsup.c b/plugins/DotNetTools/clrsup.c index 3fca660cb6ce..afc00b24cbf5 100644 --- a/plugins/DotNetTools/clrsup.c +++ b/plugins/DotNetTools/clrsup.c @@ -283,7 +283,7 @@ ICLRDataTarget *DnCLRDataTarget_Create( HANDLE processHandle; BOOLEAN isWow64; - if (!NT_SUCCESS(PhOpenProcess(&processHandle, ProcessQueryAccess | PROCESS_VM_READ, ProcessId))) + if (!NT_SUCCESS(PhOpenProcess(&processHandle, PhProcessQueryAccess() | PROCESS_VM_READ, ProcessId))) return NULL; #ifdef _WIN64 diff --git a/plugins/DotNetTools/perfpage.c b/plugins/DotNetTools/perfpage.c index c5cf54c72bcf..1b3094966b8c 100644 --- a/plugins/DotNetTools/perfpage.c +++ b/plugins/DotNetTools/perfpage.c @@ -765,7 +765,7 @@ INT_PTR CALLBACK DotNetPerfPageDlgProc( if (NT_SUCCESS(PhOpenProcess( &context->ProcessHandle, - PROCESS_VM_READ | ProcessQueryAccess | PROCESS_DUP_HANDLE | SYNCHRONIZE, + PROCESS_VM_READ | PhProcessQueryAccess() | PROCESS_DUP_HANDLE | SYNCHRONIZE, context->ProcessItem->ProcessId ))) { diff --git a/plugins/DotNetTools/stackext.c b/plugins/DotNetTools/stackext.c index 13ef6a3aca5c..30528fb5b856 100644 --- a/plugins/DotNetTools/stackext.c +++ b/plugins/DotNetTools/stackext.c @@ -93,7 +93,7 @@ VOID ProcessThreadStackControl( context->ThreadHandle = Control->u.Initializing.ThreadHandle; #if _WIN64 - if (NT_SUCCESS(PhOpenProcess(&processHandle, ProcessQueryAccess, Control->u.Initializing.ProcessId))) + if (NT_SUCCESS(PhOpenProcess(&processHandle, PhProcessQueryAccess(), Control->u.Initializing.ProcessId))) { PhGetProcessIsWow64(processHandle, &context->IsWow64); NtClose(processHandle); diff --git a/plugins/ExtendedNotifications/filelog.c b/plugins/ExtendedNotifications/filelog.c index e1cc06587719..e0c3d10163b8 100644 --- a/plugins/ExtendedNotifications/filelog.c +++ b/plugins/ExtendedNotifications/filelog.c @@ -55,7 +55,7 @@ VOID FileLogInitialization( if (NT_SUCCESS(status)) { PhRegisterCallback( - &PhLoggedCallback, + PhGetGeneralCallback(GeneralCallbackLoggedEvent), LoggedCallback, NULL, &LoggedCallbackRegistration diff --git a/plugins/ExtendedServices/main.c b/plugins/ExtendedServices/main.c index c36e3b8f38f7..335c99fff0f1 100644 --- a/plugins/ExtendedServices/main.c +++ b/plugins/ExtendedServices/main.c @@ -57,28 +57,28 @@ VOID NTAPI MenuItemCallback( { case ID_SERVICE_GOTOSERVICE: { - ProcessHacker_SelectTabPage(PhMainWndHandle, 1); - ProcessHacker_SelectServiceItem(PhMainWndHandle, (PPH_SERVICE_ITEM)menuItem->Context); + ProcessHacker_SelectTabPage(PhMainWindowHandle, 1); + ProcessHacker_SelectServiceItem(PhMainWindowHandle, (PPH_SERVICE_ITEM)menuItem->Context); } break; case ID_SERVICE_START: { - PhUiStartService(PhMainWndHandle, (PPH_SERVICE_ITEM)menuItem->Context); + PhUiStartService(PhMainWindowHandle, (PPH_SERVICE_ITEM)menuItem->Context); } break; case ID_SERVICE_CONTINUE: { - PhUiContinueService(PhMainWndHandle, (PPH_SERVICE_ITEM)menuItem->Context); + PhUiContinueService(PhMainWindowHandle, (PPH_SERVICE_ITEM)menuItem->Context); } break; case ID_SERVICE_PAUSE: { - PhUiPauseService(PhMainWndHandle, (PPH_SERVICE_ITEM)menuItem->Context); + PhUiPauseService(PhMainWindowHandle, (PPH_SERVICE_ITEM)menuItem->Context); } break; case ID_SERVICE_STOP: { - PhUiStopService(PhMainWndHandle, (PPH_SERVICE_ITEM)menuItem->Context); + PhUiStopService(PhMainWindowHandle, (PPH_SERVICE_ITEM)menuItem->Context); } break; case ID_SERVICE_RESTART: @@ -89,7 +89,7 @@ VOID NTAPI MenuItemCallback( if (serviceHandle = PhOpenService(serviceItem->Name->Buffer, SERVICE_QUERY_STATUS)) { - EsRestartServiceWithProgress(PhMainWndHandle, serviceItem, serviceHandle); + EsRestartServiceWithProgress(PhMainWindowHandle, serviceItem, serviceHandle); CloseServiceHandle(serviceHandle); } else @@ -100,7 +100,7 @@ VOID NTAPI MenuItemCallback( if (win32Result != 0) { PhShowStatus( - PhMainWndHandle, + PhMainWindowHandle, PhaFormatString(L"Unable to restart %s", serviceItem->Name->Buffer)->Buffer, 0, win32Result @@ -348,7 +348,7 @@ NTAPI ServicePropertiesInitializingCallback( } // Other - if (WindowsVersion >= WINDOWS_7 && objectProperties->NumberOfPages < objectProperties->MaximumNumberOfPages) + if (PhWindowsVersion() >= WINDOWS_7 && objectProperties->NumberOfPages < objectProperties->MaximumNumberOfPages) { memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); propSheetPage.dwSize = sizeof(PROPSHEETPAGE); @@ -362,7 +362,7 @@ NTAPI ServicePropertiesInitializingCallback( } // Other - if (WindowsVersion >= WINDOWS_VISTA && objectProperties->NumberOfPages < objectProperties->MaximumNumberOfPages) + if (PhWindowsVersion() >= WINDOWS_VISTA && objectProperties->NumberOfPages < objectProperties->MaximumNumberOfPages) { memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); propSheetPage.dwSize = sizeof(PROPSHEETPAGE); diff --git a/plugins/ExtendedServices/other.c b/plugins/ExtendedServices/other.c index 5b7957afa653..7c94a31beacd 100644 --- a/plugins/ExtendedServices/other.c +++ b/plugins/ExtendedServices/other.c @@ -365,7 +365,7 @@ INT_PTR CALLBACK EspServiceOtherDlgProc( PhAddComboBoxStrings(GetDlgItem(hwndDlg, IDC_PROTECTION), EspServiceLaunchProtectedStrings, sizeof(EspServiceLaunchProtectedStrings) / sizeof(PWSTR)); - if (WindowsVersion < WINDOWS_8_1) + if (PhWindowsVersion() < WINDOWS_8_1) EnableWindow(GetDlgItem(hwndDlg, IDC_PROTECTION), FALSE); SetDlgItemText(hwndDlg, IDC_SERVICESID, diff --git a/plugins/ExtendedServices/recovery.c b/plugins/ExtendedServices/recovery.c index b917b0334498..245bce8a6372 100644 --- a/plugins/ExtendedServices/recovery.c +++ b/plugins/ExtendedServices/recovery.c @@ -214,7 +214,7 @@ NTSTATUS EspLoadRecoveryInfo( // Enable actions for stops with errors // This is Vista and above only. - if (WindowsVersion >= WINDOWS_VISTA && QueryServiceConfig2( + if (PhWindowsVersion() >= WINDOWS_VISTA && QueryServiceConfig2( serviceHandle, SERVICE_CONFIG_FAILURE_ACTIONS_FLAG, (BYTE *)&failureActionsFlag, @@ -320,7 +320,7 @@ INT_PTR CALLBACK EspServiceRecoveryDlgProc( { SetDlgItemText(hwndDlg, IDC_RESETFAILCOUNT, L"0"); - if (WindowsVersion >= WINDOWS_VISTA) + if (PhWindowsVersion() >= WINDOWS_VISTA) { context->EnableFlagCheckBox = TRUE; EnableWindow(GetDlgItem(hwndDlg, IDC_ENABLEFORERRORSTOPS), TRUE); diff --git a/plugins/ExtendedTools/disktab.c b/plugins/ExtendedTools/disktab.c index b8b1ae72e953..daf90924b520 100644 --- a/plugins/ExtendedTools/disktab.c +++ b/plugins/ExtendedTools/disktab.c @@ -62,7 +62,7 @@ VOID EtInitializeDiskTab( memset(&page, 0, sizeof(PH_MAIN_TAB_PAGE)); PhInitializeStringRef(&page.Name, L"Disk"); page.Callback = EtpDiskPageCallback; - DiskPage = ProcessHacker_CreateTabPage(PhMainWndHandle, &page); + DiskPage = ProcessHacker_CreateTabPage(PhMainWindowHandle, &page); if (ToolStatusInterface) { @@ -101,7 +101,7 @@ BOOLEAN EtpDiskPageCallback( 0, 3, 3, - PhMainWndHandle, + PhMainWindowHandle, NULL, NULL, NULL @@ -115,7 +115,7 @@ BOOLEAN EtpDiskPageCallback( *(HWND *)Parameter1 = CreateDialog( PluginInstance->DllBase, MAKEINTRESOURCE(IDD_DISKTABERROR), - PhMainWndHandle, + PhMainWindowHandle, EtpDiskTabErrorDialogProc ); return TRUE; @@ -829,17 +829,17 @@ VOID EtHandleDiskCommand( if ((processNode = PhFindProcessNode(diskItem->ProcessId)) && processNode->ProcessItem->CreateTime.QuadPart == diskItem->ProcessRecord->CreateTime.QuadPart) { - ProcessHacker_SelectTabPage(PhMainWndHandle, 0); + ProcessHacker_SelectTabPage(PhMainWindowHandle, 0); PhSelectAndEnsureVisibleProcessNode(processNode); } else { - PhShowProcessRecordDialog(PhMainWndHandle, diskItem->ProcessRecord); + PhShowProcessRecordDialog(PhMainWindowHandle, diskItem->ProcessRecord); } } else { - PhShowError(PhMainWndHandle, L"The process does not exist."); + PhShowError(PhMainWindowHandle, L"The process does not exist."); } PhDereferenceObject(diskItem); @@ -852,7 +852,7 @@ VOID EtHandleDiskCommand( if (diskItem) { - PhShellExploreFile(PhMainWndHandle, diskItem->FileNameWin32->Buffer); + PhShellExploreFile(PhMainWindowHandle, diskItem->FileNameWin32->Buffer); } } break; @@ -867,7 +867,7 @@ VOID EtHandleDiskCommand( if (diskItem) { - PhShellProperties(PhMainWndHandle, diskItem->FileNameWin32->Buffer); + PhShellProperties(PhMainWindowHandle, diskItem->FileNameWin32->Buffer); } } break; @@ -937,7 +937,7 @@ VOID EtShowDiskContextMenu( item = PhShowEMenu( menu, - PhMainWndHandle, + PhMainWindowHandle, PH_EMENU_SHOW_LEFTRIGHT, PH_ALIGN_LEFT | PH_ALIGN_TOP, Location.x, @@ -963,7 +963,7 @@ VOID NTAPI EtpDiskItemAddedHandler( PET_DISK_ITEM diskItem = (PET_DISK_ITEM)Parameter; PhReferenceObject(diskItem); - ProcessHacker_Invoke(PhMainWndHandle, EtpOnDiskItemAdded, diskItem); + ProcessHacker_Invoke(PhMainWindowHandle, EtpOnDiskItemAdded, diskItem); } VOID NTAPI EtpDiskItemModifiedHandler( @@ -971,7 +971,7 @@ VOID NTAPI EtpDiskItemModifiedHandler( _In_opt_ PVOID Context ) { - ProcessHacker_Invoke(PhMainWndHandle, EtpOnDiskItemModified, (PET_DISK_ITEM)Parameter); + ProcessHacker_Invoke(PhMainWindowHandle, EtpOnDiskItemModified, (PET_DISK_ITEM)Parameter); } VOID NTAPI EtpDiskItemRemovedHandler( @@ -979,7 +979,7 @@ VOID NTAPI EtpDiskItemRemovedHandler( _In_opt_ PVOID Context ) { - ProcessHacker_Invoke(PhMainWndHandle, EtpOnDiskItemRemoved, (PET_DISK_ITEM)Parameter); + ProcessHacker_Invoke(PhMainWindowHandle, EtpOnDiskItemRemoved, (PET_DISK_ITEM)Parameter); } VOID NTAPI EtpDiskItemsUpdatedHandler( @@ -987,7 +987,7 @@ VOID NTAPI EtpDiskItemsUpdatedHandler( _In_opt_ PVOID Context ) { - ProcessHacker_Invoke(PhMainWndHandle, EtpOnDiskItemsUpdated, NULL); + ProcessHacker_Invoke(PhMainWindowHandle, EtpOnDiskItemsUpdated, NULL); } VOID NTAPI EtpOnDiskItemAdded( @@ -1136,10 +1136,10 @@ INT_PTR CALLBACK EtpDiskTabErrorDialogProc( switch (LOWORD(wParam)) { case IDC_RESTART: - ProcessHacker_PrepareForEarlyShutdown(PhMainWndHandle); + ProcessHacker_PrepareForEarlyShutdown(PhMainWindowHandle); if (PhShellProcessHacker( - PhMainWndHandle, + PhMainWindowHandle, L"-v -selecttab Disk", SW_SHOW, PH_SHELL_EXECUTE_ADMIN, @@ -1148,11 +1148,11 @@ INT_PTR CALLBACK EtpDiskTabErrorDialogProc( NULL )) { - ProcessHacker_Destroy(PhMainWndHandle); + ProcessHacker_Destroy(PhMainWindowHandle); } else { - ProcessHacker_CancelEarlyShutdown(PhMainWndHandle); + ProcessHacker_CancelEarlyShutdown(PhMainWindowHandle); } break; diff --git a/plugins/ExtendedTools/etwdisk.c b/plugins/ExtendedTools/etwdisk.c index c8512f20a01d..237e34715d71 100644 --- a/plugins/ExtendedTools/etwdisk.c +++ b/plugins/ExtendedTools/etwdisk.c @@ -95,7 +95,7 @@ VOID EtInitializeDiskInformation( EtStartEtwRundown(); PhRegisterCallback( - &PhProcessesUpdatedEvent, + PhGetGeneralCallback(GeneralCallbackProcessProviderUpdated), EtpDiskProcessesUpdatedCallback, NULL, &ProcessesUpdatedCallbackRegistration diff --git a/plugins/ExtendedTools/etwmon.c b/plugins/ExtendedTools/etwmon.c index 7c4823ae21ba..402b3417a27e 100644 --- a/plugins/ExtendedTools/etwmon.c +++ b/plugins/ExtendedTools/etwmon.c @@ -117,7 +117,7 @@ VOID EtStartEtwSession( ULONG result; ULONG bufferSize; - if (WindowsVersion >= WINDOWS_8) + if (PhWindowsVersion() >= WINDOWS_8) { EtpActualKernelLoggerName = &EtpPrivateKernelLoggerName; EtpActualSessionGuid = &ProcessHackerGuid; @@ -146,7 +146,7 @@ VOID EtStartEtwSession( EtpTraceProperties->LogFileNameOffset = 0; EtpTraceProperties->LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES); - if (WindowsVersion >= WINDOWS_8) + if (PhWindowsVersion() >= WINDOWS_8) EtpTraceProperties->LogFileMode |= EVENT_TRACE_SYSTEM_LOGGER_MODE; result = StartTrace(&EtpSessionHandle, EtpActualKernelLoggerName->Buffer, EtpTraceProperties); @@ -240,7 +240,7 @@ VOID NTAPI EtpEtwEventCallback( { DiskIo_TypeGroup1 *data = EventRecord->UserData; - if (WindowsVersion >= WINDOWS_8) + if (PhWindowsVersion() >= WINDOWS_8) { diskEvent.ClientId.UniqueThread = UlongToHandle(data->IssuingThreadId); diskEvent.ClientId.UniqueProcess = EtThreadIdToProcessId(diskEvent.ClientId.UniqueThread); @@ -387,7 +387,7 @@ NTSTATUS EtpEtwMonitorThreadStart( TRACEHANDLE traceHandle; // See comment in EtEtwProcessesUpdatedCallback. - if (WindowsVersion >= WINDOWS_8) + if (PhWindowsVersion() >= WINDOWS_8) EtUpdateProcessInformation(); memset(&logFile, 0, sizeof(EVENT_TRACE_LOGFILE)); diff --git a/plugins/ExtendedTools/etwprprp.c b/plugins/ExtendedTools/etwprprp.c index 1e87ffbd4672..ba8059a07b8e 100644 --- a/plugins/ExtendedTools/etwprprp.c +++ b/plugins/ExtendedTools/etwprprp.c @@ -148,9 +148,9 @@ VOID EtwDiskNetworkLayoutGraphs( HDWP deferHandle; RECT clientRect; RECT panelRect; - RECT margin = { ET_SCALE_DPI(13), ET_SCALE_DPI(13), ET_SCALE_DPI(13), ET_SCALE_DPI(13) }; - RECT innerMargin = { ET_SCALE_DPI(10), ET_SCALE_DPI(20), ET_SCALE_DPI(10), ET_SCALE_DPI(10) }; - LONG between = ET_SCALE_DPI(3); + RECT margin = { PH_SCALE_DPI(13), PH_SCALE_DPI(13), PH_SCALE_DPI(13), PH_SCALE_DPI(13) }; + RECT innerMargin = { PH_SCALE_DPI(10), PH_SCALE_DPI(20), PH_SCALE_DPI(10), PH_SCALE_DPI(10) }; + LONG between = PH_SCALE_DPI(3); ULONG graphWidth; ULONG graphHeight; @@ -326,7 +326,7 @@ INT_PTR CALLBACK EtwDiskNetworkPageDlgProc( EtwDiskNetworkUpdatePanel(context); PhRegisterCallback( - &PhProcessesUpdatedEvent, + PhGetGeneralCallback(GeneralCallbackProcessProviderUpdated), EtwDiskNetworkUpdateHandler, context, &context->ProcessesUpdatedRegistration @@ -352,7 +352,7 @@ INT_PTR CALLBACK EtwDiskNetworkPageDlgProc( if (context->PanelHandle) DestroyWindow(context->PanelHandle); - PhUnregisterCallback(&PhProcessesUpdatedEvent, &context->ProcessesUpdatedRegistration); + PhUnregisterCallback(PhGetGeneralCallback(GeneralCallbackProcessProviderUpdated), &context->ProcessesUpdatedRegistration); PhFree(context); PhPropPageDlgProcDestroy(hwndDlg); @@ -394,7 +394,7 @@ INT_PTR CALLBACK EtwDiskNetworkPageDlgProc( )); hdc = Graph_GetBufferedContext(context->DiskGraphHandle); - SelectObject(hdc, PhApplicationFont); + SelectObject(hdc, PhGetApplicationFont()); PhSetGraphText(hdc, drawInfo, &context->DiskGraphState.Text->sr, &NormalGraphTextMargin, &NormalGraphTextPadding, PH_ALIGN_TOP | PH_ALIGN_LEFT); } @@ -462,7 +462,7 @@ INT_PTR CALLBACK EtwDiskNetworkPageDlgProc( )); hdc = Graph_GetBufferedContext(context->NetworkGraphHandle); - SelectObject(hdc, PhApplicationFont); + SelectObject(hdc, PhGetApplicationFont()); PhSetGraphText(hdc, drawInfo, &context->NetworkGraphState.Text->sr, &NormalGraphTextMargin, &NormalGraphTextPadding, PH_ALIGN_TOP | PH_ALIGN_LEFT); } diff --git a/plugins/ExtendedTools/etwstat.c b/plugins/ExtendedTools/etwstat.c index 33ee65dd33ee..663613de863e 100644 --- a/plugins/ExtendedTools/etwstat.c +++ b/plugins/ExtendedTools/etwstat.c @@ -85,13 +85,13 @@ VOID EtEtwStatisticsInitialization( PhInitializeCircularBuffer_ULONG(&EtMaxNetworkHistory, sampleCount); PhRegisterCallback( - &PhProcessesUpdatedEvent, + PhGetGeneralCallback(GeneralCallbackProcessProviderUpdated), EtEtwProcessesUpdatedCallback, NULL, &EtpProcessesUpdatedCallbackRegistration ); PhRegisterCallback( - &PhNetworkItemsUpdatedEvent, + PhGetGeneralCallback(GeneralCallbackNetworkProviderUpdated), EtEtwNetworkItemsUpdatedCallback, NULL, &EtpNetworkItemsUpdatedCallbackRegistration @@ -224,7 +224,7 @@ VOID NTAPI EtEtwProcessesUpdatedCallback( // Since Windows 8, we no longer get the correct process/thread IDs in the // event headers for disk events. We need to update our process information since // etwmon uses our EtThreadIdToProcessId function. - if (WindowsVersion >= WINDOWS_8) + if (PhWindowsVersion() >= WINDOWS_8) EtUpdateProcessInformation(); // ETW is extremely lazy when it comes to flushing buffers, so we must do it @@ -357,7 +357,7 @@ VOID NTAPI EtEtwNetworkItemsUpdatedCallback( { // Values have changed. Invalidate the network node. PhReferenceObject(block->NetworkItem); - ProcessHacker_Invoke(PhMainWndHandle, EtpInvalidateNetworkNode, block->NetworkItem); + ProcessHacker_Invoke(PhMainWindowHandle, EtpInvalidateNetworkNode, block->NetworkItem); } listEntry = listEntry->Flink; diff --git a/plugins/ExtendedTools/exttools.h b/plugins/ExtendedTools/exttools.h index 967f6d30f356..c5201b3fabc5 100644 --- a/plugins/ExtendedTools/exttools.h +++ b/plugins/ExtendedTools/exttools.h @@ -27,10 +27,6 @@ extern HWND NetworkTreeNewHandle; #define SETTING_NAME_UNLOADED_WINDOW_SIZE (PLUGIN_NAME L".TracertWindowSize") #define SETTING_NAME_UNLOADED_COLUMNS (PLUGIN_NAME L".UnloadedListColumns") -#define ET_SCALE_DPI(Value) PhMultiplyDivide(Value, PhGlobalDpi, 96) -#define ET_LOAD_SHARED_ICON_SMALL(Name) PhLoadIcon(PhLibImageBase, (Name), PH_LOAD_ICON_SHARED | PH_LOAD_ICON_SIZE_SMALL, 0, 0) -#define ET_LOAD_SHARED_ICON_LARGE(Name) PhLoadIcon(PhLibImageBase, (Name), PH_LOAD_ICON_SHARED | PH_LOAD_ICON_SIZE_LARGE, 0, 0) - // Graph update message #define UPDATE_MSG (WM_APP + 1) diff --git a/plugins/ExtendedTools/gpumon.c b/plugins/ExtendedTools/gpumon.c index ca608783baa3..4905e6fe2374 100644 --- a/plugins/ExtendedTools/gpumon.c +++ b/plugins/ExtendedTools/gpumon.c @@ -97,7 +97,7 @@ VOID EtGpuMonitorInitialization( } PhRegisterCallback( - &PhProcessesUpdatedEvent, + PhGetGeneralCallback(GeneralCallbackProcessProviderUpdated), EtGpuProcessesUpdatedCallback, NULL, &ProcessesUpdatedCallbackRegistration @@ -244,7 +244,7 @@ BOOLEAN EtpInitializeD3DStatistics( ULONG64 commitLimit; ULONG aperture; - if (WindowsVersion >= WINDOWS_8) + if (PhWindowsVersion() >= WINDOWS_8) { commitLimit = queryStatistics.QueryResult.SegmentInformation.CommitLimit; aperture = queryStatistics.QueryResult.SegmentInformation.Aperture; @@ -418,7 +418,7 @@ VOID EtpUpdateSegmentInformation( { ULONG64 bytesCommitted; - if (WindowsVersion >= WINDOWS_8) + if (PhWindowsVersion() >= WINDOWS_8) { bytesCommitted = queryStatistics.QueryResult.ProcessSegmentInformation.BytesCommitted; } @@ -436,7 +436,7 @@ VOID EtpUpdateSegmentInformation( { ULONG64 bytesCommitted; - if (WindowsVersion >= WINDOWS_8) + if (PhWindowsVersion() >= WINDOWS_8) { bytesCommitted = queryStatistics.QueryResult.SegmentInformation.BytesResident; } @@ -777,7 +777,7 @@ VOID EtQueryProcessGpuStatistics( { ULONG64 bytesCommitted; - if (WindowsVersion >= WINDOWS_8) + if (PhWindowsVersion() >= WINDOWS_8) { bytesCommitted = queryStatistics.QueryResult.ProcessSegmentInformation.BytesCommitted; } diff --git a/plugins/ExtendedTools/gpunodes.c b/plugins/ExtendedTools/gpunodes.c index fe9467dda387..6b1e083f01e4 100644 --- a/plugins/ExtendedTools/gpunodes.c +++ b/plugins/ExtendedTools/gpunodes.c @@ -121,15 +121,13 @@ INT_PTR CALLBACK EtpGpuNodesDlgProc( WindowHandle = hwndDlg; - SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)ET_LOAD_SHARED_ICON_SMALL(MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); - SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)ET_LOAD_SHARED_ICON_LARGE(MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); + SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhImageBaseAddress, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); + SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhImageBaseAddress, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); PhInitializeLayoutManager(&LayoutManager, hwndDlg); PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDOK), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); LayoutMargin = PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDC_LAYOUT), NULL, PH_ANCHOR_ALL)->Margin; - PhRegisterCallback(&PhProcessesUpdatedEvent, ProcessesUpdatedCallback, NULL, &ProcessesUpdatedCallbackRegistration); - GraphHandle = PhAllocate(sizeof(HWND) * EtGpuTotalNodeCount); CheckBoxHandle = PhAllocate(sizeof(HWND) * EtGpuTotalNodeCount); GraphState = PhAllocate(sizeof(PH_GRAPH_STATE) * EtGpuTotalNodeCount); @@ -206,6 +204,8 @@ INT_PTR CALLBACK EtpGpuNodesDlgProc( PhCenterWindow(hwndDlg, GetParent(hwndDlg)); EtpLoadNodeBitMap(); + + PhRegisterCallback(PhGetGeneralCallback(GeneralCallbackProcessProviderUpdated), ProcessesUpdatedCallback, NULL, &ProcessesUpdatedCallbackRegistration); } break; case WM_DESTROY: @@ -214,7 +214,7 @@ INT_PTR CALLBACK EtpGpuNodesDlgProc( EtpSaveNodeBitMap(); - PhUnregisterCallback(&PhProcessesUpdatedEvent, &ProcessesUpdatedCallbackRegistration); + PhUnregisterCallback(PhGetGeneralCallback(GeneralCallbackProcessProviderUpdated), &ProcessesUpdatedCallbackRegistration); for (i = 0; i < EtGpuTotalNodeCount; i++) { diff --git a/plugins/ExtendedTools/gpuprprp.c b/plugins/ExtendedTools/gpuprprp.c index 882b3c453d75..6661ee3e747c 100644 --- a/plugins/ExtendedTools/gpuprprp.c +++ b/plugins/ExtendedTools/gpuprprp.c @@ -263,9 +263,9 @@ VOID GpuPropLayoutGraphs( HDWP deferHandle; RECT clientRect; RECT panelRect; - RECT margin = { ET_SCALE_DPI(13), ET_SCALE_DPI(13), ET_SCALE_DPI(13), ET_SCALE_DPI(13) }; - RECT innerMargin = { ET_SCALE_DPI(10), ET_SCALE_DPI(20), ET_SCALE_DPI(10), ET_SCALE_DPI(10) }; - LONG between = ET_SCALE_DPI(3); + RECT margin = { PH_SCALE_DPI(13), PH_SCALE_DPI(13), PH_SCALE_DPI(13), PH_SCALE_DPI(13) }; + RECT innerMargin = { PH_SCALE_DPI(10), PH_SCALE_DPI(20), PH_SCALE_DPI(10), PH_SCALE_DPI(10) }; + LONG between = PH_SCALE_DPI(3); ULONG graphWidth; ULONG graphHeight; @@ -474,7 +474,7 @@ INT_PTR CALLBACK EtpGpuPageDlgProc( GpuPropUpdatePanel(context); PhRegisterCallback( - &PhProcessesUpdatedEvent, + PhGetGeneralCallback(GeneralCallbackProcessProviderUpdated), ProcessesUpdatedHandler, context, &context->ProcessesUpdatedRegistration @@ -502,7 +502,7 @@ INT_PTR CALLBACK EtpGpuPageDlgProc( if (context->PanelHandle) DestroyWindow(context->PanelHandle); - PhUnregisterCallback(&PhProcessesUpdatedEvent, &context->ProcessesUpdatedRegistration); + PhUnregisterCallback(PhGetGeneralCallback(GeneralCallbackProcessProviderUpdated), &context->ProcessesUpdatedRegistration); PhFree(context); PhPropPageDlgProcDestroy(hwndDlg); @@ -543,7 +543,7 @@ INT_PTR CALLBACK EtpGpuPageDlgProc( )); hdc = Graph_GetBufferedContext(context->GpuGraphHandle); - SelectObject(hdc, PhApplicationFont); + SelectObject(hdc, PhGetApplicationFont()); PhSetGraphText(hdc, drawInfo, &context->GpuGraphState.Text->sr, &NormalGraphTextMargin, &NormalGraphTextPadding, PH_ALIGN_TOP | PH_ALIGN_LEFT); } @@ -574,7 +574,7 @@ INT_PTR CALLBACK EtpGpuPageDlgProc( )); hdc = Graph_GetBufferedContext(context->MemGraphHandle); - SelectObject(hdc, PhApplicationFont); + SelectObject(hdc, PhGetApplicationFont()); PhSetGraphText( hdc, drawInfo, @@ -630,7 +630,7 @@ INT_PTR CALLBACK EtpGpuPageDlgProc( )); hdc = Graph_GetBufferedContext(context->SharedGraphHandle); - SelectObject(hdc, PhApplicationFont); + SelectObject(hdc, PhGetApplicationFont()); PhSetGraphText(hdc, drawInfo, &context->MemorySharedGraphState.Text->sr, &NormalGraphTextMargin, &NormalGraphTextPadding, PH_ALIGN_TOP | PH_ALIGN_LEFT); } diff --git a/plugins/ExtendedTools/main.c b/plugins/ExtendedTools/main.c index 22c279729158..542438278ebd 100644 --- a/plugins/ExtendedTools/main.c +++ b/plugins/ExtendedTools/main.c @@ -91,7 +91,7 @@ VOID NTAPI MenuItemCallback( break; case ID_PROCESS_WSWATCH: { - EtShowWsWatchDialog(PhMainWndHandle, menuItem->Context); + EtShowWsWatchDialog(PhMainWindowHandle, menuItem->Context); } break; case ID_THREAD_CANCELIO: @@ -565,13 +565,13 @@ LOGICAL DllMain( ); PhRegisterCallback( - &PhProcessesUpdatedEvent, + PhGetGeneralCallback(GeneralCallbackProcessProviderUpdated), ProcessesUpdatedCallback, NULL, &ProcessesUpdatedCallbackRegistration ); PhRegisterCallback( - &PhNetworkItemsUpdatedEvent, + PhGetGeneralCallback(GeneralCallbackNetworkProviderUpdated), NetworkItemsUpdatedCallback, NULL, &NetworkItemsUpdatedCallbackRegistration diff --git a/plugins/ExtendedTools/unldll.c b/plugins/ExtendedTools/unldll.c index 54d9f4b8ae27..04fd28abfce5 100644 --- a/plugins/ExtendedTools/unldll.c +++ b/plugins/ExtendedTools/unldll.c @@ -305,8 +305,8 @@ INT_PTR CALLBACK EtpUnloadedDllsDlgProc( { HWND lvHandle; - SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)ET_LOAD_SHARED_ICON_SMALL(MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); - SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)ET_LOAD_SHARED_ICON_LARGE(MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); + SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhImageBaseAddress, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); + SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhImageBaseAddress, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); PhCenterWindow(hwndDlg, GetParent(hwndDlg)); @@ -337,7 +337,7 @@ INT_PTR CALLBACK EtpUnloadedDllsDlgProc( if (PhGetIntegerPairSetting(SETTING_NAME_UNLOADED_WINDOW_POSITION).X != 0) PhLoadWindowPlacementFromSetting(SETTING_NAME_UNLOADED_WINDOW_POSITION, SETTING_NAME_UNLOADED_WINDOW_SIZE, hwndDlg); else - PhCenterWindow(hwndDlg, PhMainWndHandle); + PhCenterWindow(hwndDlg, PhMainWindowHandle); if (!EtpRefreshUnloadedDlls(hwndDlg, context)) { diff --git a/plugins/ExtendedTools/wswatch.c b/plugins/ExtendedTools/wswatch.c index 470092cb3b0d..29094695fd0d 100644 --- a/plugins/ExtendedTools/wswatch.c +++ b/plugins/ExtendedTools/wswatch.c @@ -389,7 +389,7 @@ static BOOLEAN NTAPI EnumGenericModulesCallback( // in Windows 7. if ( context->LoadingSymbolsForProcessId == SYSTEM_PROCESS_ID && - (ULONG_PTR)Module->BaseAddress <= PhSystemBasicInformation.MaximumUserModeAddress + (ULONG_PTR)Module->BaseAddress <= PhGetSystemBasicInformation().MaximumUserModeAddress ) return TRUE; diff --git a/plugins/ExtraPlugins/cloud.c b/plugins/ExtraPlugins/cloud.c index 57509cc969c0..ac286ad2b0be 100644 --- a/plugins/ExtraPlugins/cloud.c +++ b/plugins/ExtraPlugins/cloud.c @@ -58,7 +58,7 @@ NTSTATUS QueryPluginsCallbackThread( if (!(httpSessionHandle = WinHttpOpen( L"ExtraPlugins_1.0", - WindowsVersion >= WINDOWS_8_1 ? WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY : WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, + PhWindowsVersion() >= WINDOWS_8_1 ? WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY : WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0 diff --git a/plugins/ExtraPlugins/dialog.c b/plugins/ExtraPlugins/dialog.c index b924fe09d2d9..ab5c5ea929d2 100644 --- a/plugins/ExtraPlugins/dialog.c +++ b/plugins/ExtraPlugins/dialog.c @@ -243,7 +243,7 @@ INT_PTR CALLBACK CloudPluginsDlgProc( context->NormalFontHandle = PhCreateCommonFont(-14, FW_NORMAL, NULL); context->BoldFontHandle = PhCreateCommonFont(-16, FW_BOLD, NULL); - PhCenterWindow(hwndDlg, PhMainWndHandle); + PhCenterWindow(hwndDlg, PhMainWindowHandle); InitializePluginsTree(context, hwndDlg, context->TreeNewHandle); PhAddTreeNewFilter(GetPluginListFilterSupport(context), ProcessTreeFilterCallback, context); diff --git a/plugins/ExtraPlugins/setup/page5.c b/plugins/ExtraPlugins/setup/page5.c index e703258e37b6..256c6a8d52dc 100644 --- a/plugins/ExtraPlugins/setup/page5.c +++ b/plugins/ExtraPlugins/setup/page5.c @@ -45,9 +45,9 @@ HRESULT CALLBACK RestartTaskDialogCallbackProc( { if ((INT)wParam == IDYES) { - ProcessHacker_PrepareForEarlyShutdown(PhMainWndHandle); + ProcessHacker_PrepareForEarlyShutdown(PhMainWindowHandle); PhShellProcessHacker( - PhMainWndHandle, + PhMainWindowHandle, L"-v", SW_SHOW, 0, @@ -56,7 +56,7 @@ HRESULT CALLBACK RestartTaskDialogCallbackProc( NULL ); //PhShellProcessHacker( - // PhMainWndHandle, + // PhMainWindowHandle, // L"-plugin " PLUGIN_NAME L":INSTALL -plugin " PLUGIN_NAME L":hex64value", // SW_SHOW, // 0, @@ -64,7 +64,7 @@ HRESULT CALLBACK RestartTaskDialogCallbackProc( // 0, // NULL // ); - ProcessHacker_Destroy(PhMainWndHandle); + ProcessHacker_Destroy(PhMainWindowHandle); } } break; diff --git a/plugins/ExtraPlugins/setup/updater.c b/plugins/ExtraPlugins/setup/updater.c index 77662132c054..02e2e37eddb7 100644 --- a/plugins/ExtraPlugins/setup/updater.c +++ b/plugins/ExtraPlugins/setup/updater.c @@ -60,22 +60,8 @@ VOID TaskDialogCreateIcons( ) { // Load the Process Hacker window icon - Context->IconLargeHandle = (HICON)LoadImage( - NtCurrentPeb()->ImageBaseAddress, - MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER), - IMAGE_ICON, - GetSystemMetrics(SM_CXICON), - GetSystemMetrics(SM_CYICON), - LR_SHARED - ); - Context->IconSmallHandle = (HICON)LoadImage( - NtCurrentPeb()->ImageBaseAddress, - MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER), - IMAGE_ICON, - GetSystemMetrics(SM_CXSMICON), - GetSystemMetrics(SM_CYSMICON), - LR_SHARED - ); + Context->IconSmallHandle = PH_LOAD_SHARED_ICON_SMALL(PhImageBaseAddress, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER)); + Context->IconLargeHandle = PH_LOAD_SHARED_ICON_LARGE(PhImageBaseAddress, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER)); // Set the TaskDialog window icons SendMessage(Context->DialogHandle, WM_SETICON, ICON_SMALL, (LPARAM)Context->IconSmallHandle); @@ -421,7 +407,7 @@ NTSTATUS UpdateDownloadThread( // Open the HTTP session with the system proxy configuration if available if (!(httpSessionHandle = WinHttpOpen( PhGetString(userAgentString), - WindowsVersion >= WINDOWS_8_1 ? WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY : WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, + PhWindowsVersion() >= WINDOWS_8_1 ? WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY : WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0 @@ -430,7 +416,7 @@ NTSTATUS UpdateDownloadThread( goto CleanupExit; } - if (WindowsVersion >= WINDOWS_8_1) + if (PhWindowsVersion() >= WINDOWS_8_1) { ULONG httpFlags = WINHTTP_DECOMPRESSION_FLAG_GZIP | WINHTTP_DECOMPRESSION_FLAG_DEFLATE; @@ -465,7 +451,7 @@ NTSTATUS UpdateDownloadThread( goto CleanupExit; } - if (WindowsVersion >= WINDOWS_7) + if (PhWindowsVersion() >= WINDOWS_7) { ULONG keepAlive = WINHTTP_DISABLE_KEEP_ALIVE; WinHttpSetOption(httpRequestHandle, WINHTTP_OPTION_DISABLE_FEATURE, &keepAlive, sizeof(ULONG)); @@ -738,11 +724,11 @@ LRESULT CALLBACK TaskDialogSubclassProc( // break; //case WM_NCACTIVATE: // { - // if (IsWindowVisible(PhMainWndHandle) && !IsMinimized(PhMainWndHandle)) + // if (IsWindowVisible(PhMainWindowHandle) && !IsMinimized(PhMainWindowHandle)) // { // if (!context->FixedWindowStyles) // { - // SetWindowLongPtr(hwndDlg, GWLP_HWNDPARENT, (LONG_PTR)PhMainWndHandle); + // SetWindowLongPtr(hwndDlg, GWLP_HWNDPARENT, (LONG_PTR)PhMainWindowHandle); // PhSetWindowExStyle(hwndDlg, WS_EX_APPWINDOW, WS_EX_APPWINDOW); // context->FixedWindowStyles = TRUE; // } diff --git a/plugins/HardwareDevices/disknotify.c b/plugins/HardwareDevices/disknotify.c index f212a04d456a..a68605ffbbd5 100644 --- a/plugins/HardwareDevices/disknotify.c +++ b/plugins/HardwareDevices/disknotify.c @@ -94,7 +94,7 @@ VOID AddRemoveDeviceChangeCallback( ) { // We get called during the plugin LoadCallback, don't do anything. - if (!PhMainWndHandle) + if (!PhMainWindowHandle) return; // Add the subclass only when disks are being monitored, remove when no longer needed. @@ -103,7 +103,7 @@ VOID AddRemoveDeviceChangeCallback( if (!SubclassActive) { // We have a disk device, subclass the main window to detect drive letter changes. - SetWindowSubclass(PhMainWndHandle, MainWndDevicesSubclassProc, 0, 0); + SetWindowSubclass(PhMainWindowHandle, MainWndDevicesSubclassProc, 0, 0); SubclassActive = TRUE; } } @@ -112,7 +112,7 @@ VOID AddRemoveDeviceChangeCallback( if (SubclassActive) { // The user has removed the last disk device, remove the subclass. - RemoveWindowSubclass(PhMainWndHandle, MainWndDevicesSubclassProc, 0); + RemoveWindowSubclass(PhMainWindowHandle, MainWndDevicesSubclassProc, 0); SubclassActive = FALSE; } } diff --git a/plugins/HardwareDevices/main.c b/plugins/HardwareDevices/main.c index 9b2e7c4a39bd..fd212f6d7e64 100644 --- a/plugins/HardwareDevices/main.c +++ b/plugins/HardwareDevices/main.c @@ -259,7 +259,7 @@ VOID ShowDeviceMenu( selectedItem = PhShowEMenu( menu, - PhMainWndHandle, + PhMainWindowHandle, PH_EMENU_SHOW_LEFTRIGHT, PH_ALIGN_LEFT | PH_ALIGN_TOP, cursorPos.x, @@ -364,7 +364,7 @@ LOGICAL DllMain( ); PhRegisterCallback( - &PhProcessesUpdatedEvent, + PhGetGeneralCallback(GeneralCallbackProcessProviderUpdated), ProcessesUpdatedCallback, NULL, &ProcessesUpdatedCallbackRegistration diff --git a/plugins/HardwareDevices/netdetails.c b/plugins/HardwareDevices/netdetails.c index 983a7ca071db..f703b9cd89d7 100644 --- a/plugins/HardwareDevices/netdetails.c +++ b/plugins/HardwareDevices/netdetails.c @@ -536,7 +536,7 @@ INT_PTR CALLBACK NetAdapterDetailsDlgProc( NetAdapterAddListViewItemGroups(context->ListViewHandle); PhRegisterCallback( - &PhProcessesUpdatedEvent, + PhGetGeneralCallback(GeneralCallbackProcessProviderUpdated), NetAdapterProcessesUpdatedHandler, context, &context->ProcessesUpdatedRegistration @@ -556,7 +556,7 @@ INT_PTR CALLBACK NetAdapterDetailsDlgProc( break; case WM_DESTROY: { - PhUnregisterCallback(&PhProcessesUpdatedEvent, &context->ProcessesUpdatedRegistration); + PhUnregisterCallback(PhGetGeneralCallback(GeneralCallbackProcessProviderUpdated), &context->ProcessesUpdatedRegistration); if (context->NotifyHandle) CancelMibChangeNotify2(context->NotifyHandle); diff --git a/plugins/HardwareDevices/netoptions.c b/plugins/HardwareDevices/netoptions.c index 0807ba9a9e3b..b82b52fd44e7 100644 --- a/plugins/HardwareDevices/netoptions.c +++ b/plugins/HardwareDevices/netoptions.c @@ -301,7 +301,7 @@ BOOLEAN QueryNetworkDeviceInterfaceDescription( if ((result = CM_Get_DevNode_Property( // CM_Get_DevNode_Registry_Property with CM_DRP_DEVICEDESC?? deviceInstanceHandle, - WindowsVersion >= WINDOWS_8 ? &DEVPKEY_Device_FriendlyName : &DEVPKEY_Device_DeviceDesc, + PhWindowsVersion() >= WINDOWS_8 ? &DEVPKEY_Device_FriendlyName : &DEVPKEY_Device_DeviceDesc, &devicePropertyType, (PBYTE)deviceDescription->Buffer, &bufferSize, @@ -313,7 +313,7 @@ BOOLEAN QueryNetworkDeviceInterfaceDescription( result = CM_Get_DevNode_Property( deviceInstanceHandle, - WindowsVersion >= WINDOWS_8 ? &DEVPKEY_Device_FriendlyName : &DEVPKEY_Device_DeviceDesc, + PhWindowsVersion() >= WINDOWS_8 ? &DEVPKEY_Device_FriendlyName : &DEVPKEY_Device_DeviceDesc, &devicePropertyType, (PBYTE)deviceDescription->Buffer, &bufferSize, diff --git a/plugins/HardwareDevices/storage.c b/plugins/HardwareDevices/storage.c index 2be01224b59c..5c7a4472b533 100644 --- a/plugins/HardwareDevices/storage.c +++ b/plugins/HardwareDevices/storage.c @@ -918,21 +918,21 @@ BOOLEAN DiskDriveQueryFileSystemInfo( case FILESYSTEM_STATISTICS_TYPE_NTFS: case FILESYSTEM_STATISTICS_TYPE_REFS: // ReFS uses the same statistics as NTFS. { - bufferLength = sizeof(NTFS_FILESYSTEM_STATISTICS) * 64 * (ULONG)PhSystemBasicInformation.NumberOfProcessors; + bufferLength = sizeof(NTFS_FILESYSTEM_STATISTICS) * 64 * (ULONG)PhGetSystemBasicInformation().NumberOfProcessors; buffer = PhReAllocate(buffer, bufferLength); memset(buffer, 0, bufferLength); } break; case FILESYSTEM_STATISTICS_TYPE_FAT: { - bufferLength = sizeof(FAT_FILESYSTEM_STATISTICS) * 64 * (ULONG)PhSystemBasicInformation.NumberOfProcessors; + bufferLength = sizeof(FAT_FILESYSTEM_STATISTICS) * 64 * (ULONG)PhGetSystemBasicInformation().NumberOfProcessors; buffer = PhReAllocate(buffer, bufferLength); memset(buffer, 0, bufferLength); } break; case FILESYSTEM_STATISTICS_TYPE_EXFAT: { - bufferLength = sizeof(EXFAT_FILESYSTEM_STATISTICS) * 64 * (ULONG)PhSystemBasicInformation.NumberOfProcessors; + bufferLength = sizeof(EXFAT_FILESYSTEM_STATISTICS) * 64 * (ULONG)PhGetSystemBasicInformation().NumberOfProcessors; buffer = PhReAllocate(buffer, bufferLength); memset(buffer, 0, bufferLength); } diff --git a/plugins/NetworkTools/pages.c b/plugins/NetworkTools/pages.c index f2bce861c8ca..887789488e94 100644 --- a/plugins/NetworkTools/pages.c +++ b/plugins/NetworkTools/pages.c @@ -107,9 +107,9 @@ HRESULT CALLBACK RestartTaskDialogCallbackProc( { if ((INT)wParam == IDYES) { - ProcessHacker_PrepareForEarlyShutdown(PhMainWndHandle); + ProcessHacker_PrepareForEarlyShutdown(PhMainWindowHandle); PhShellProcessHacker( - PhMainWndHandle, + PhMainWindowHandle, NULL, SW_SHOW, 0, @@ -117,7 +117,7 @@ HRESULT CALLBACK RestartTaskDialogCallbackProc( 0, NULL ); - ProcessHacker_Destroy(PhMainWndHandle); + ProcessHacker_Destroy(PhMainWindowHandle); } } break; diff --git a/plugins/NetworkTools/ping.c b/plugins/NetworkTools/ping.c index 0ccb364a7005..bbed74977946 100644 --- a/plugins/NetworkTools/ping.c +++ b/plugins/NetworkTools/ping.c @@ -330,7 +330,7 @@ INT_PTR CALLBACK NetworkPingWndProc( if (PhGetIntegerPairSetting(SETTING_NAME_PING_WINDOW_POSITION).X != 0) PhLoadWindowPlacementFromSetting(SETTING_NAME_PING_WINDOW_POSITION, SETTING_NAME_PING_WINDOW_SIZE, hwndDlg); else - PhCenterWindow(hwndDlg, PhMainWndHandle); + PhCenterWindow(hwndDlg, PhMainWindowHandle); SetWindowText(hwndDlg, PhaFormatString(L"Ping %s", context->IpAddressString)->Buffer); SetWindowText(context->StatusHandle, PhaFormatString(L"Pinging %s with %lu bytes of data...", @@ -339,7 +339,7 @@ INT_PTR CALLBACK NetworkPingWndProc( ); PhRegisterCallback( - &PhProcessesUpdatedEvent, + PhGetGeneralCallback(GeneralCallbackProcessProviderUpdated), NetworkPingUpdateHandler, context, &context->ProcessesUpdatedRegistration @@ -362,7 +362,7 @@ INT_PTR CALLBACK NetworkPingWndProc( case WM_DESTROY: { PhUnregisterCallback( - &PhProcessesUpdatedEvent, + PhGetGeneralCallback(GeneralCallbackProcessProviderUpdated), &context->ProcessesUpdatedRegistration ); @@ -447,7 +447,7 @@ INT_PTR CALLBACK NetworkPingWndProc( PhFormatString(L"%lu ms", context->CurrentPingMs) ); - SelectObject(hdc, PhApplicationFont); + SelectObject(hdc, PhGetApplicationFont()); PhSetGraphText(hdc, drawInfo, &context->PingGraphState.Text->sr, &NormalGraphTextMargin, &NormalGraphTextPadding, PH_ALIGN_TOP | PH_ALIGN_LEFT); } diff --git a/plugins/NetworkTools/tracert.c b/plugins/NetworkTools/tracert.c index 41550a1f123b..519bbf6b47f1 100644 --- a/plugins/NetworkTools/tracert.c +++ b/plugins/NetworkTools/tracert.c @@ -568,7 +568,10 @@ INT_PTR CALLBACK TracertDlgProc( { HANDLE tracertThread; - PhCenterWindow(hwndDlg, PhMainWndHandle); + SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhImageBaseAddress, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); + SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhImageBaseAddress, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); + + PhCenterWindow(hwndDlg, PhMainWindowHandle); Static_SetText(hwndDlg, PhaFormatString(L"Tracing %s...", context->IpAddressString)->Buffer @@ -592,7 +595,7 @@ INT_PTR CALLBACK TracertDlgProc( if (PhGetIntegerPairSetting(SETTING_NAME_TRACERT_WINDOW_POSITION).X != 0) PhLoadWindowPlacementFromSetting(SETTING_NAME_TRACERT_WINDOW_POSITION, SETTING_NAME_TRACERT_WINDOW_SIZE, hwndDlg); else - PhCenterWindow(hwndDlg, PhMainWndHandle); + PhCenterWindow(hwndDlg, PhMainWindowHandle); PhReferenceObject(context); diff --git a/plugins/NetworkTools/update.c b/plugins/NetworkTools/update.c index 988029df021f..c7ceba20e69f 100644 --- a/plugins/NetworkTools/update.c +++ b/plugins/NetworkTools/update.c @@ -35,21 +35,14 @@ VOID FreeUpdateContext( ) { //PhClearReference(&Context->Version); - // PhClearReference(&Context->RevVersion); + //PhClearReference(&Context->RevVersion); //PhClearReference(&Context->RelDate); - // PhClearReference(&Context->Size); + //PhClearReference(&Context->Size); //PhClearReference(&Context->Hash); - // PhClearReference(&Context->Signature); - // PhClearReference(&Context->ReleaseNotesUrl); + //PhClearReference(&Context->Signature); + //PhClearReference(&Context->ReleaseNotesUrl); //PhClearReference(&Context->SetupFilePath); - // PhClearReference(&Context->SetupFileDownloadUrl); - - if (Context->IconLargeHandle) - DestroyIcon(Context->IconLargeHandle); - - if (Context->IconSmallHandle) - DestroyIcon(Context->IconSmallHandle); - + //PhClearReference(&Context->SetupFileDownloadUrl); //PhClearReference(&Context); } @@ -57,29 +50,11 @@ VOID TaskDialogCreateIcons( _In_ PPH_UPDATER_CONTEXT Context ) { - HICON largeIcon; - HICON smallIcon; - - largeIcon = PhLoadIcon( - NtCurrentPeb()->ImageBaseAddress, - MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER), - PH_LOAD_ICON_SIZE_LARGE, - GetSystemMetrics(SM_CXICON), - GetSystemMetrics(SM_CYICON) - ); - smallIcon = PhLoadIcon( - NtCurrentPeb()->ImageBaseAddress, - MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER), - PH_LOAD_ICON_SIZE_LARGE, - GetSystemMetrics(SM_CXSMICON), - GetSystemMetrics(SM_CYSMICON) - ); - - Context->IconLargeHandle = largeIcon; - Context->IconSmallHandle = smallIcon; + Context->IconSmallHandle = PH_LOAD_SHARED_ICON_SMALL(PhImageBaseAddress, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER)); + Context->IconLargeHandle = PH_LOAD_SHARED_ICON_LARGE(PhImageBaseAddress, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER)); - SendMessage(Context->DialogHandle, WM_SETICON, ICON_SMALL, (LPARAM)largeIcon); - SendMessage(Context->DialogHandle, WM_SETICON, ICON_BIG, (LPARAM)smallIcon); + SendMessage(Context->DialogHandle, WM_SETICON, ICON_SMALL, (LPARAM)Context->IconLargeHandle); + SendMessage(Context->DialogHandle, WM_SETICON, ICON_BIG, (LPARAM)Context->IconSmallHandle); } VOID TaskDialogLinkClicked( @@ -159,7 +134,7 @@ PPH_STRING QueryFwLinkUrl( if (!(httpSessionHandle = WinHttpOpen( NULL, - WindowsVersion >= WINDOWS_8_1 ? WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY : WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, + PhWindowsVersion() >= WINDOWS_8_1 ? WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY : WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0 @@ -168,7 +143,7 @@ PPH_STRING QueryFwLinkUrl( goto CleanupExit; } - if (WindowsVersion >= WINDOWS_8_1) + if (PhWindowsVersion() >= WINDOWS_8_1) { ULONG httpFlags = WINHTTP_DECOMPRESSION_FLAG_GZIP | WINHTTP_DECOMPRESSION_FLAG_DEFLATE; @@ -223,7 +198,7 @@ PPH_STRING QueryFwLinkUrl( ); } - if (WindowsVersion >= WINDOWS_7) + if (PhWindowsVersion() >= WINDOWS_7) { ULONG option = WINHTTP_DISABLE_REDIRECTS; WinHttpSetOption(httpRequestHandle, WINHTTP_OPTION_DISABLE_FEATURE, &option, sizeof(ULONG)); @@ -415,7 +390,7 @@ NTSTATUS GeoIPUpdateThread( if (!(httpSessionHandle = WinHttpOpen( PhGetString(userAgentString), - WindowsVersion >= WINDOWS_8_1 ? WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY : WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, + PhWindowsVersion() >= WINDOWS_8_1 ? WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY : WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0 @@ -424,7 +399,7 @@ NTSTATUS GeoIPUpdateThread( goto CleanupExit; } - if (WindowsVersion >= WINDOWS_8_1) + if (PhWindowsVersion() >= WINDOWS_8_1) { ULONG httpFlags = WINHTTP_DECOMPRESSION_FLAG_GZIP | WINHTTP_DECOMPRESSION_FLAG_DEFLATE; WinHttpSetOption(httpSessionHandle, WINHTTP_OPTION_DECOMPRESSION, &httpFlags, sizeof(ULONG)); @@ -453,7 +428,7 @@ NTSTATUS GeoIPUpdateThread( goto CleanupExit; } - if (WindowsVersion >= WINDOWS_7) + if (PhWindowsVersion() >= WINDOWS_7) { ULONG option = WINHTTP_DISABLE_KEEP_ALIVE; WinHttpSetOption(httpRequestHandle, WINHTTP_OPTION_DISABLE_FEATURE, &option, sizeof(ULONG)); @@ -735,7 +710,7 @@ HRESULT CALLBACK TaskDialogBootstrapCallback( UpdateDialogHandle = context->DialogHandle = hwndDlg; // Center the update window on PH if it's visible else we center on the desktop. - PhCenterWindow(hwndDlg, (IsWindowVisible(PhMainWndHandle) && !IsMinimized(PhMainWndHandle)) ? PhMainWndHandle : NULL); + PhCenterWindow(hwndDlg, (IsWindowVisible(PhMainWindowHandle) && !IsMinimized(PhMainWindowHandle)) ? PhMainWindowHandle : NULL); // Create the Taskdialog icons TaskDialogCreateIcons(context); @@ -787,7 +762,7 @@ NTSTATUS GeoIPUpdateDialogThread( //info.hwnd = Parameter; //info.lpVerb = L"runas"; // - //ProcessHacker_PrepareForEarlyShutdown(PhMainWndHandle); + //ProcessHacker_PrepareForEarlyShutdown(PhMainWindowHandle); // //if (ShellExecuteEx(&info)) //{ @@ -810,7 +785,7 @@ NTSTATUS GeoIPUpdateDialogThread( // NULL // ); // - // ProcessHacker_Destroy(PhMainWndHandle); + // ProcessHacker_Destroy(PhMainWindowHandle); // } // } // @@ -818,7 +793,7 @@ NTSTATUS GeoIPUpdateDialogThread( //} //else //{ - // ProcessHacker_CancelEarlyShutdown(PhMainWndHandle); + // ProcessHacker_CancelEarlyShutdown(PhMainWindowHandle); //} } diff --git a/plugins/NetworkTools/whois.c b/plugins/NetworkTools/whois.c index bf6e602d0270..b7ea2d5a38d5 100644 --- a/plugins/NetworkTools/whois.c +++ b/plugins/NetworkTools/whois.c @@ -396,6 +396,9 @@ INT_PTR CALLBACK NetworkOutputDlgProc( { HANDLE dialogThread; + SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhImageBaseAddress, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); + SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhImageBaseAddress, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); + SetWindowText(hwndDlg, PhaFormatString(L"Whois %s...", context->IpAddressString)->Buffer); context->WindowHandle = hwndDlg; @@ -416,7 +419,7 @@ INT_PTR CALLBACK NetworkOutputDlgProc( if (PhGetIntegerPairSetting(SETTING_NAME_WHOIS_WINDOW_POSITION).X != 0) PhLoadWindowPlacementFromSetting(SETTING_NAME_WHOIS_WINDOW_POSITION, SETTING_NAME_WHOIS_WINDOW_SIZE, hwndDlg); else - PhCenterWindow(hwndDlg, PhMainWndHandle); + PhCenterWindow(hwndDlg, PhMainWindowHandle); if (dialogThread = PhCreateThread(0, NetworkWhoisThreadStart, (PVOID)context)) NtClose(dialogThread); diff --git a/plugins/OnlineChecks/main.c b/plugins/OnlineChecks/main.c index 35ef25384a98..687ba5defef1 100644 --- a/plugins/OnlineChecks/main.c +++ b/plugins/OnlineChecks/main.c @@ -178,13 +178,7 @@ VOID NTAPI MenuItemCallback( config.dwFlags = TDF_USE_HICON_MAIN | TDF_ALLOW_DIALOG_CANCELLATION; config.dwCommonButtons = TDCBF_YES_BUTTON | TDCBF_NO_BUTTON; config.hwndParent = menuItem->OwnerWindow; - config.hMainIcon = PhLoadIcon( - NtCurrentPeb()->ImageBaseAddress, - MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER), - PH_LOAD_ICON_SIZE_LARGE, - GetSystemMetrics(SM_CXICON), - GetSystemMetrics(SM_CYICON) - ); + config.hMainIcon = PH_LOAD_SHARED_ICON_LARGE(PhImageBaseAddress, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER)); config.cxWidth = 180; config.pszWindowTitle = L"Process Hacker - VirusTotal"; config.pszMainInstruction = L"VirusTotal scanning requires a restart of Process Hacker."; @@ -192,9 +186,9 @@ VOID NTAPI MenuItemCallback( if (SUCCEEDED(TaskDialogIndirect(&config, &result, NULL, NULL)) && result == IDYES) { - ProcessHacker_PrepareForEarlyShutdown(PhMainWndHandle); + ProcessHacker_PrepareForEarlyShutdown(PhMainWindowHandle); PhShellProcessHacker( - PhMainWndHandle, + PhMainWindowHandle, L"-v", SW_SHOW, 0, @@ -202,7 +196,7 @@ VOID NTAPI MenuItemCallback( 0, NULL ); - ProcessHacker_Destroy(PhMainWndHandle); + ProcessHacker_Destroy(PhMainWindowHandle); } DestroyIcon(config.hMainIcon); diff --git a/plugins/OnlineChecks/page1.c b/plugins/OnlineChecks/page1.c index 7b8489b72c95..2ce418db265f 100644 --- a/plugins/OnlineChecks/page1.c +++ b/plugins/OnlineChecks/page1.c @@ -40,7 +40,7 @@ HRESULT CALLBACK TaskDialogProcessingCallbackProc( SendMessage(hwndDlg, TDM_SET_PROGRESS_BAR_MARQUEE, TRUE, 1); if (context->TaskbarListClass) - ITaskbarList3_SetProgressState(context->TaskbarListClass, PhMainWndHandle, TBPF_INDETERMINATE); + ITaskbarList3_SetProgressState(context->TaskbarListClass, PhMainWindowHandle, TBPF_INDETERMINATE); PhReferenceObject(context); PhQueueItemWorkQueue(PhGetGlobalWorkQueue(), UploadCheckThreadStart, context); diff --git a/plugins/OnlineChecks/page2.c b/plugins/OnlineChecks/page2.c index aff040808c29..b6b972258f19 100644 --- a/plugins/OnlineChecks/page2.c +++ b/plugins/OnlineChecks/page2.c @@ -45,7 +45,7 @@ HRESULT CALLBACK TaskDialogResultFoundProc( { if (context->TaskbarListClass) { - ITaskbarList3_SetProgressState(context->TaskbarListClass, PhMainWndHandle, TBPF_NOPROGRESS); + ITaskbarList3_SetProgressState(context->TaskbarListClass, PhMainWindowHandle, TBPF_NOPROGRESS); } } break; diff --git a/plugins/OnlineChecks/page3.c b/plugins/OnlineChecks/page3.c index c35e7309c7ec..9d6fac0bc773 100644 --- a/plugins/OnlineChecks/page3.c +++ b/plugins/OnlineChecks/page3.c @@ -40,7 +40,7 @@ HRESULT CALLBACK TaskDialogProgressCallbackProc( SendMessage(hwndDlg, TDM_SET_PROGRESS_BAR_MARQUEE, TRUE, 1); if (context->TaskbarListClass) - ITaskbarList3_SetProgressState(context->TaskbarListClass, PhMainWndHandle, TBPF_INDETERMINATE); + ITaskbarList3_SetProgressState(context->TaskbarListClass, PhMainWindowHandle, TBPF_INDETERMINATE); PhReferenceObject(context); context->UploadThreadHandle = PhCreateThread(0, UploadFileThreadStart, context); diff --git a/plugins/OnlineChecks/page4.c b/plugins/OnlineChecks/page4.c index 849bdcd1e0cf..e174cb39f63c 100644 --- a/plugins/OnlineChecks/page4.c +++ b/plugins/OnlineChecks/page4.c @@ -38,8 +38,8 @@ HRESULT CALLBACK TaskDialogErrorProc( { if (context->TaskbarListClass) { - ITaskbarList3_SetProgressValue(context->TaskbarListClass, PhMainWndHandle, 1, 1); - ITaskbarList3_SetProgressState(context->TaskbarListClass, PhMainWndHandle, TBPF_ERROR); + ITaskbarList3_SetProgressValue(context->TaskbarListClass, PhMainWindowHandle, 1, 1); + ITaskbarList3_SetProgressState(context->TaskbarListClass, PhMainWindowHandle, TBPF_ERROR); } } break; diff --git a/plugins/OnlineChecks/upload.c b/plugins/OnlineChecks/upload.c index 803689827131..d0736ff8414e 100644 --- a/plugins/OnlineChecks/upload.c +++ b/plugins/OnlineChecks/upload.c @@ -172,18 +172,6 @@ VOID UploadContextDeleteProcedure( context->HttpHandle = NULL; } - if (context->IconLargeHandle) - { - DestroyIcon(context->IconLargeHandle); - context->IconLargeHandle = NULL; - } - - if (context->IconSmallHandle) - { - DestroyIcon(context->IconSmallHandle); - context->IconSmallHandle = NULL; - } - PhClearReference(&context->ErrorString); PhClearReference(&context->FileName); PhClearReference(&context->BaseFileName); @@ -205,7 +193,7 @@ VOID TaskDialogFreeContext( { // Reset Taskbar progress state(s) if (Context->TaskbarListClass) - ITaskbarList3_SetProgressState(Context->TaskbarListClass, PhMainWndHandle, TBPF_NOPROGRESS); + ITaskbarList3_SetProgressState(Context->TaskbarListClass, PhMainWindowHandle, TBPF_NOPROGRESS); if (Context->TaskbarListClass) ITaskbarList3_SetProgressState(Context->TaskbarListClass, Context->DialogHandle, TBPF_NOPROGRESS); @@ -217,20 +205,8 @@ VOID TaskDialogCreateIcons( _In_ PUPLOAD_CONTEXT Context ) { - Context->IconLargeHandle = PhLoadIcon( - NtCurrentPeb()->ImageBaseAddress, - MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER), - PH_LOAD_ICON_SIZE_LARGE, - GetSystemMetrics(SM_CXICON), - GetSystemMetrics(SM_CYICON) - ); - Context->IconSmallHandle = PhLoadIcon( - NtCurrentPeb()->ImageBaseAddress, - MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER), - PH_LOAD_ICON_SIZE_LARGE, - GetSystemMetrics(SM_CXICON), - GetSystemMetrics(SM_CYICON) - ); + Context->IconSmallHandle = PH_LOAD_SHARED_ICON_SMALL(PhImageBaseAddress, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER)); + Context->IconLargeHandle = PH_LOAD_SHARED_ICON_LARGE(PhImageBaseAddress, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER)); SendMessage(Context->DialogHandle, WM_SETICON, ICON_SMALL, (LPARAM)Context->IconSmallHandle); SendMessage(Context->DialogHandle, WM_SETICON, ICON_BIG, (LPARAM)Context->IconLargeHandle); @@ -710,7 +686,7 @@ NTSTATUS UploadFileThreadStart( { ITaskbarList3_SetProgressState( context->TaskbarListClass, - PhMainWndHandle, + PhMainWindowHandle, TBPF_NORMAL ); } @@ -914,7 +890,7 @@ NTSTATUS UploadFileThreadStart( // Reset Taskbar progress state(s) if (context->TaskbarListClass) { - ITaskbarList3_SetProgressState(context->TaskbarListClass, PhMainWndHandle, TBPF_NOPROGRESS); + ITaskbarList3_SetProgressState(context->TaskbarListClass, PhMainWindowHandle, TBPF_NOPROGRESS); ITaskbarList3_SetProgressState(context->TaskbarListClass, context->DialogHandle, TBPF_NOPROGRESS); } @@ -1014,7 +990,7 @@ NTSTATUS UploadCheckThreadStart( if (!(context->HttpHandle = WinHttpOpen( userAgent->Buffer, - WindowsVersion >= WINDOWS_8_1 ? WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY : WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, + PhWindowsVersion() >= WINDOWS_8_1 ? WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY : WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0 @@ -1023,7 +999,7 @@ NTSTATUS UploadCheckThreadStart( goto CleanupExit; } - if (WindowsVersion >= WINDOWS_8_1) + if (PhWindowsVersion() >= WINDOWS_8_1) { ULONG gzipFlags = WINHTTP_DECOMPRESSION_FLAG_ALL; WinHttpSetOption(context->HttpHandle, WINHTTP_OPTION_DECOMPRESSION, &gzipFlags, sizeof(ULONG)); @@ -1252,7 +1228,7 @@ HRESULT CALLBACK TaskDialogBootstrapCallback( context->DialogHandle = hwndDlg; // Center the update window on PH if it's visible else we center on the desktop. - PhCenterWindow(hwndDlg, (IsWindowVisible(PhMainWndHandle) && !IsMinimized(PhMainWndHandle)) ? PhMainWndHandle : NULL); + PhCenterWindow(hwndDlg, (IsWindowVisible(PhMainWindowHandle) && !IsMinimized(PhMainWindowHandle)) ? PhMainWindowHandle : NULL); // Create the Taskdialog icons TaskDialogCreateIcons(context); diff --git a/plugins/OnlineChecks/virustotal.c b/plugins/OnlineChecks/virustotal.c index 642ce0ddd9f3..bc93f9df57bd 100644 --- a/plugins/OnlineChecks/virustotal.c +++ b/plugins/OnlineChecks/virustotal.c @@ -317,7 +317,7 @@ PSTR VirusTotalSendHttpRequest( if (!(httpSessionHandle = WinHttpOpen( userAgent->Buffer, - WindowsVersion >= WINDOWS_8_1 ? WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY : WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, + PhWindowsVersion() >= WINDOWS_8_1 ? WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY : WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0 @@ -326,7 +326,7 @@ PSTR VirusTotalSendHttpRequest( goto CleanupExit; } - if (WindowsVersion >= WINDOWS_8_1) + if (PhWindowsVersion() >= WINDOWS_8_1) { ULONG gzipFlags = WINHTTP_DECOMPRESSION_FLAG_GZIP | WINHTTP_DECOMPRESSION_FLAG_DEFLATE; WinHttpSetOption(httpSessionHandle, WINHTTP_OPTION_DECOMPRESSION, &gzipFlags, sizeof(ULONG)); @@ -461,7 +461,7 @@ PVIRUSTOTAL_FILE_REPORT_RESULT VirusTotalSendHttpFileReportRequest( if (!(httpSessionHandle = WinHttpOpen( userAgent->Buffer, - WindowsVersion >= WINDOWS_8_1 ? WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY : WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, + PhWindowsVersion() >= WINDOWS_8_1 ? WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY : WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0 @@ -470,7 +470,7 @@ PVIRUSTOTAL_FILE_REPORT_RESULT VirusTotalSendHttpFileReportRequest( goto CleanupExit; } - if (WindowsVersion >= WINDOWS_8_1) + if (PhWindowsVersion() >= WINDOWS_8_1) { ULONG httpFlags = WINHTTP_DECOMPRESSION_FLAG_GZIP | WINHTTP_DECOMPRESSION_FLAG_DEFLATE; WinHttpSetOption(httpSessionHandle, WINHTTP_OPTION_DECOMPRESSION, &httpFlags, sizeof(ULONG)); diff --git a/plugins/Plugins.props b/plugins/Plugins.props index 0f074ebbd868..73e6bd500644 100644 --- a/plugins/Plugins.props +++ b/plugins/Plugins.props @@ -30,7 +30,9 @@ true - ProcessHacker.lib;ntdll.lib;%(AdditionalDependencies) + delaylib.lib;ProcessHacker.lib;ntdll.lib;%(AdditionalDependencies) + ProcessHacker.exe;%(DelayLoadDLLs) + __delayLoadHelper2 true 6.01 Windows @@ -75,7 +77,7 @@ StreamingSIMDExtensions - ..\..\sdk\lib\i386;%(AdditionalLibraryDirectories) + ..\..\sdk\lib\i386;..\..\tools\delaylib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) MachineX86 @@ -83,7 +85,7 @@ - ..\..\sdk\lib\amd64;%(AdditionalLibraryDirectories) + ..\..\sdk\lib\amd64;..\..\tools\delaylib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) MachineX64 diff --git a/plugins/ToolStatus/customizesb.c b/plugins/ToolStatus/customizesb.c index cd4dbd29034d..9b5ca897757d 100644 --- a/plugins/ToolStatus/customizesb.c +++ b/plugins/ToolStatus/customizesb.c @@ -310,7 +310,7 @@ INT_PTR CALLBACK CustomizeStatusBarDialogProc( { case WM_INITDIALOG: { - PhCenterWindow(hwndDlg, PhMainWndHandle); + PhCenterWindow(hwndDlg, PhMainWindowHandle); context->DialogHandle = hwndDlg; context->AvailableListHandle = GetDlgItem(hwndDlg, IDC_AVAILABLE); @@ -627,7 +627,7 @@ VOID StatusBarShowCustomizeDialog( DialogBox( PluginInstance->DllBase, MAKEINTRESOURCE(IDD_CUSTOMIZE_SB), - PhMainWndHandle, + PhMainWindowHandle, CustomizeStatusBarDialogProc ); } \ No newline at end of file diff --git a/plugins/ToolStatus/customizetb.c b/plugins/ToolStatus/customizetb.c index cef8fdffbb33..c457964c4ffc 100644 --- a/plugins/ToolStatus/customizetb.c +++ b/plugins/ToolStatus/customizetb.c @@ -509,7 +509,7 @@ INT_PTR CALLBACK CustomizeToolbarDialogProc( { case WM_INITDIALOG: { - PhCenterWindow(hwndDlg, PhMainWndHandle); + PhCenterWindow(hwndDlg, PhMainWindowHandle); context->DialogHandle = hwndDlg; context->AvailableListHandle = GetDlgItem(hwndDlg, IDC_AVAILABLE); @@ -788,12 +788,12 @@ INT_PTR CALLBACK CustomizeToolbarDialogProc( if (ToolStatusConfig.AutoHideMenu) { - SetMenu(PhMainWndHandle, NULL); + SetMenu(PhMainWindowHandle, NULL); } else { - SetMenu(PhMainWndHandle, MainMenu); - DrawMenuBar(PhMainWndHandle); + SetMenu(PhMainWindowHandle, MainMenu); + DrawMenuBar(PhMainWindowHandle); } } } @@ -937,7 +937,7 @@ VOID ToolBarShowCustomizeDialog( DialogBox( PluginInstance->DllBase, MAKEINTRESOURCE(IDD_CUSTOMIZE_TB), - PhMainWndHandle, + PhMainWindowHandle, CustomizeToolbarDialogProc ); } \ No newline at end of file diff --git a/plugins/ToolStatus/graph.c b/plugins/ToolStatus/graph.c index c8effcd4396e..97a62b7b1ae2 100644 --- a/plugins/ToolStatus/graph.c +++ b/plugins/ToolStatus/graph.c @@ -45,7 +45,7 @@ VOID ToolbarCreateGraphs(VOID) 0, 0, 0, - PhMainWndHandle, + PhMainWindowHandle, NULL, NULL, NULL @@ -65,7 +65,7 @@ VOID ToolbarCreateGraphs(VOID) 0, 0, 0, - PhMainWndHandle, + PhMainWindowHandle, NULL, NULL, NULL @@ -85,7 +85,7 @@ VOID ToolbarCreateGraphs(VOID) 0, 0, 0, - PhMainWndHandle, + PhMainWindowHandle, NULL, NULL, NULL @@ -105,7 +105,7 @@ VOID ToolbarCreateGraphs(VOID) 0, 0, 0, - PhMainWndHandle, + PhMainWindowHandle, NULL, NULL, NULL @@ -449,7 +449,7 @@ VOID ToolbarUpdateGraphsInfo(LPNMHDR Header) PhDivideSinglesBySingle( MemGraphState.Data1, - (FLOAT)PhSystemBasicInformation.NumberOfPhysicalPages, + (FLOAT)PhGetSystemBasicInformation().NumberOfPhysicalPages, drawInfo->LineDataCount ); @@ -617,7 +617,7 @@ VOID ToolbarUpdateGraphsInfo(LPNMHDR Header) if (record) { - PhShowProcessRecordDialog(PhMainWndHandle, record); + PhShowProcessRecordDialog(PhMainWindowHandle, record); PhDereferenceProcessRecord(record); } } @@ -651,7 +651,7 @@ VOID ToolbarUpdateGraphsInfo(LPNMHDR Header) if (record) { - PhShowProcessRecordDialog(PhMainWndHandle, record); + PhShowProcessRecordDialog(PhMainWindowHandle, record); PhDereferenceProcessRecord(record); } } diff --git a/plugins/ToolStatus/main.c b/plugins/ToolStatus/main.c index 2c81fa57babb..29f4ad589e31 100644 --- a/plugins/ToolStatus/main.c +++ b/plugins/ToolStatus/main.c @@ -252,7 +252,7 @@ VOID ShowCustomizeMenu( selectedItem = PhShowEMenu( menu, - PhMainWndHandle, + PhMainWindowHandle, PH_EMENU_SHOW_LEFTRIGHT, PH_ALIGN_LEFT | PH_ALIGN_TOP, cursorPos.x, @@ -271,12 +271,12 @@ VOID ShowCustomizeMenu( if (ToolStatusConfig.AutoHideMenu) { - SetMenu(PhMainWndHandle, NULL); + SetMenu(PhMainWindowHandle, NULL); } else { - SetMenu(PhMainWndHandle, MainMenu); - DrawMenuBar(PhMainWndHandle); + SetMenu(PhMainWindowHandle, MainMenu); + DrawMenuBar(PhMainWindowHandle); } } break; @@ -293,7 +293,7 @@ VOID ShowCustomizeMenu( { // Adding the Searchbox makes it focused, // reset the focus back to the main window. - SetFocus(PhMainWndHandle); + SetFocus(PhMainWindowHandle); } } break; @@ -452,8 +452,8 @@ VOID NTAPI LayoutPaddingCallback( SendMessage(RebarHandle, WM_SIZE, 0, 0); - // TODO: GetClientRect with PhMainWndHandle causes crash. - //GetClientRect(PhMainWndHandle, &clientRect); + // TODO: GetClientRect with PhMainWindowHandle causes crash. + //GetClientRect(PhMainWindowHandle, &clientRect); GetClientRect(RebarHandle, &rebarRect); // Adjust the PH client area and exclude the rebar width. @@ -556,22 +556,22 @@ BOOLEAN NTAPI MessageLoopFilter( ) { if ( - Message->hwnd == PhMainWndHandle || - IsChild(PhMainWndHandle, Message->hwnd) + Message->hwnd == PhMainWindowHandle || + IsChild(PhMainWindowHandle, Message->hwnd) ) { - if (TranslateAccelerator(PhMainWndHandle, AcceleratorTable, Message)) + if (TranslateAccelerator(PhMainWindowHandle, AcceleratorTable, Message)) return TRUE; - if (Message->message == WM_SYSCHAR && ToolStatusConfig.AutoHideMenu && !GetMenu(PhMainWndHandle)) + if (Message->message == WM_SYSCHAR && ToolStatusConfig.AutoHideMenu && !GetMenu(PhMainWindowHandle)) { ULONG key = (ULONG)Message->wParam; if (key == 'h' || key == 'v' || key == 't' || key == 'u' || key == 'e') { - SetMenu(PhMainWndHandle, MainMenu); - DrawMenuBar(PhMainWndHandle); - SendMessage(PhMainWndHandle, WM_SYSCHAR, Message->wParam, Message->lParam); + SetMenu(PhMainWindowHandle, MainMenu); + DrawMenuBar(PhMainWindowHandle); + SendMessage(PhMainWindowHandle, WM_SYSCHAR, Message->wParam, Message->lParam); return TRUE; } } @@ -774,7 +774,7 @@ LRESULT CALLBACK MainWndSubclassProc( case RBN_HEIGHTCHANGE: { // Invoke the LayoutPaddingCallback. - SendMessage(PhMainWndHandle, WM_SIZE, 0, 0); + SendMessage(PhMainWindowHandle, WM_SIZE, 0, 0); } break; case RBN_CHEVRONPUSHED: @@ -886,7 +886,7 @@ LRESULT CALLBACK MainWndSubclassProc( if (selectedItem && selectedItem->Id != -1) { - SendMessage(PhMainWndHandle, WM_COMMAND, MAKEWPARAM(selectedItem->Id, BN_CLICKED), 0); + SendMessage(PhMainWindowHandle, WM_COMMAND, MAKEWPARAM(selectedItem->Id, BN_CLICKED), 0); } PhDestroyEMenu(menu); @@ -997,7 +997,7 @@ LRESULT CALLBACK MainWndSubclassProc( if (selectedItem && selectedItem->Id != -1) { - SendMessage(PhMainWndHandle, WM_COMMAND, MAKEWPARAM(selectedItem->Id, BN_CLICKED), 0); + SendMessage(PhMainWindowHandle, WM_COMMAND, MAKEWPARAM(selectedItem->Id, BN_CLICKED), 0); } PhDestroyEMenu(menu); @@ -1123,7 +1123,7 @@ LRESULT CALLBACK MainWndSubclassProc( SetCursor(LoadCursor(NULL, IDC_ARROW)); // Bring the window back to the top, and preserve the Always on Top setting. - SetWindowPos(PhMainWndHandle, PhGetIntegerSetting(L"MainWindowAlwaysOnTop") ? HWND_TOPMOST : HWND_TOP, + SetWindowPos(PhMainWindowHandle, PhGetIntegerSetting(L"MainWindowAlwaysOnTop") ? HWND_TOPMOST : HWND_TOP, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE); TargetingWindow = FALSE; @@ -1236,7 +1236,7 @@ LRESULT CALLBACK MainWndSubclassProc( } } - SetWindowPos(PhMainWndHandle, PhGetIntegerSetting(L"MainWindowAlwaysOnTop") ? HWND_TOPMOST : HWND_TOP, + SetWindowPos(PhMainWindowHandle, PhGetIntegerSetting(L"MainWindowAlwaysOnTop") ? HWND_TOPMOST : HWND_TOP, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE); TargetingCompleted = TRUE; @@ -1263,14 +1263,14 @@ LRESULT CALLBACK MainWndSubclassProc( if (!ToolStatusConfig.AutoHideMenu) break; - if (GetMenu(PhMainWndHandle)) + if (GetMenu(PhMainWindowHandle)) { - SetMenu(PhMainWndHandle, NULL); + SetMenu(PhMainWindowHandle, NULL); } else { - SetMenu(PhMainWndHandle, MainMenu); - DrawMenuBar(PhMainWndHandle); + SetMenu(PhMainWindowHandle, MainMenu); + DrawMenuBar(PhMainWindowHandle); } } else if ((wParam & 0xFFF0) == SC_MINIMIZE) @@ -1288,9 +1288,9 @@ LRESULT CALLBACK MainWndSubclassProc( if (!ToolStatusConfig.AutoHideMenu) break; - if (GetMenu(PhMainWndHandle)) + if (GetMenu(PhMainWindowHandle)) { - SetMenu(PhMainWndHandle, NULL); + SetMenu(PhMainWindowHandle, NULL); } } break; @@ -1309,21 +1309,21 @@ VOID NTAPI MainWindowShowingCallback( { PhRegisterMessageLoopFilter(MessageLoopFilter, NULL); PhRegisterCallback( - ProcessHacker_GetCallbackLayoutPadding(PhMainWndHandle), + ProcessHacker_GetCallbackLayoutPadding(PhMainWindowHandle), LayoutPaddingCallback, NULL, &LayoutPaddingCallbackRegistration ); - SetWindowSubclass(PhMainWndHandle, MainWndSubclassProc, 0, 0); + SetWindowSubclass(PhMainWindowHandle, MainWndSubclassProc, 0, 0); ToolbarLoadSettings(); ReBarLoadLayoutSettings(); StatusBarLoadSettings(); - MainMenu = GetMenu(PhMainWndHandle); + MainMenu = GetMenu(PhMainWindowHandle); if (ToolStatusConfig.AutoHideMenu) { - SetMenu(PhMainWndHandle, NULL); + SetMenu(PhMainWindowHandle, NULL); } } diff --git a/plugins/ToolStatus/options.c b/plugins/ToolStatus/options.c index f46e5b5564ac..fed1a0811a97 100644 --- a/plugins/ToolStatus/options.c +++ b/plugins/ToolStatus/options.c @@ -66,12 +66,12 @@ INT_PTR CALLBACK OptionsDlgProc( if (ToolStatusConfig.AutoHideMenu) { - SetMenu(PhMainWndHandle, NULL); + SetMenu(PhMainWindowHandle, NULL); } else { - SetMenu(PhMainWndHandle, MainMenu); - DrawMenuBar(PhMainWndHandle); + SetMenu(PhMainWindowHandle, MainMenu); + DrawMenuBar(PhMainWindowHandle); } EndDialog(hwndDlg, IDOK); diff --git a/plugins/ToolStatus/statusbar.c b/plugins/ToolStatus/statusbar.c index 92a8515eb812..550771c7c7a3 100644 --- a/plugins/ToolStatus/statusbar.c +++ b/plugins/ToolStatus/statusbar.c @@ -229,7 +229,7 @@ VOID StatusBarShowMenu( selectedItem = PhShowEMenu( menu, - PhMainWndHandle, + PhMainWindowHandle, PH_EMENU_SHOW_LEFTRIGHT, PH_ALIGN_LEFT | PH_ALIGN_BOTTOM, cursorPos.x, @@ -324,8 +324,8 @@ VOID StatusBarUpdate( break; case ID_STATUS_PHYSICALMEMORY: { - ULONG physicalUsage = PhSystemBasicInformation.NumberOfPhysicalPages - SystemStatistics.Performance->AvailablePages; - FLOAT physicalFraction = (FLOAT)physicalUsage / PhSystemBasicInformation.NumberOfPhysicalPages * 100; + ULONG physicalUsage = PhGetSystemBasicInformation().NumberOfPhysicalPages - SystemStatistics.Performance->AvailablePages; + FLOAT physicalFraction = (FLOAT)physicalUsage / PhGetSystemBasicInformation().NumberOfPhysicalPages * 100; text[count] = PhFormatString( L"Physical memory: %s (%.2f%%)", @@ -337,7 +337,7 @@ VOID StatusBarUpdate( case ID_STATUS_FREEMEMORY: { ULONG physicalFree = SystemStatistics.Performance->AvailablePages; - FLOAT physicalFreeFraction = (FLOAT)physicalFree / PhSystemBasicInformation.NumberOfPhysicalPages * 100; + FLOAT physicalFreeFraction = (FLOAT)physicalFree / PhGetSystemBasicInformation().NumberOfPhysicalPages * 100; text[count] = PhFormatString( L"Free memory: %s (%.2f%%)", diff --git a/plugins/ToolStatus/toolbar.c b/plugins/ToolStatus/toolbar.c index c7b752460c7b..6393b2771090 100644 --- a/plugins/ToolStatus/toolbar.c +++ b/plugins/ToolStatus/toolbar.c @@ -127,7 +127,7 @@ VOID RebarLoadSettings( NULL, WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | CCS_NODIVIDER | CCS_TOP | RBS_VARHEIGHT | RBS_AUTOSIZE, // CCS_NOPARENTALIGN | RBS_FIXEDORDER CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, - PhMainWndHandle, + PhMainWindowHandle, NULL, NULL, NULL @@ -188,7 +188,7 @@ VOID RebarLoadSettings( NULL, WS_CHILD | WS_VISIBLE | CCS_BOTTOM | SBARS_SIZEGRIP, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, - PhMainWndHandle, + PhMainWindowHandle, NULL, NULL, NULL @@ -374,7 +374,7 @@ VOID ToolbarLoadSettings( } // Invoke the LayoutPaddingCallback. - SendMessage(PhMainWndHandle, WM_SIZE, 0, 0); + SendMessage(PhMainWindowHandle, WM_SIZE, 0, 0); } VOID ToolbarResetSettings( diff --git a/plugins/Updater/options.c b/plugins/Updater/options.c index 77c0c978bda6..902ba775c308 100644 --- a/plugins/Updater/options.c +++ b/plugins/Updater/options.c @@ -88,8 +88,8 @@ INT_PTR CALLBACK TextDlgProc( PhCenterWindow(hwndDlg, GetParent(hwndDlg)); - SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)UT_LOAD_SHARED_ICON_SMALL(MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); - SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)UT_LOAD_SHARED_ICON_LARGE(MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); + SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhImageBaseAddress, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); + SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhImageBaseAddress, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); PhInitializeLayoutManager(&LayoutManager, hwndDlg); PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDC_TEXT), NULL, PH_ANCHOR_ALL); diff --git a/plugins/Updater/page5.c b/plugins/Updater/page5.c index 0b766debcfeb..07b6e873b18d 100644 --- a/plugins/Updater/page5.c +++ b/plugins/Updater/page5.c @@ -71,16 +71,16 @@ HRESULT CALLBACK FinalTaskDialogCallbackProc( info.nShow = SW_SHOW; info.hwnd = hwndDlg; - ProcessHacker_PrepareForEarlyShutdown(PhMainWndHandle); + ProcessHacker_PrepareForEarlyShutdown(PhMainWindowHandle); if (ShellExecuteEx(&info)) { - ProcessHacker_Destroy(PhMainWndHandle); + ProcessHacker_Destroy(PhMainWindowHandle); } else { // Install failed, cancel the shutdown. - ProcessHacker_CancelEarlyShutdown(PhMainWndHandle); + ProcessHacker_CancelEarlyShutdown(PhMainWindowHandle); // Set button text for next action //Button_SetText(GetDlgItem(hwndDlg, IDOK), L"Retry"); @@ -144,7 +144,7 @@ VOID ShowLatestVersionDialog( config.lpCallbackData = (LONG_PTR)Context; // HACK - imageDosHeader = (PIMAGE_DOS_HEADER)NtCurrentPeb()->ImageBaseAddress; + imageDosHeader = (PIMAGE_DOS_HEADER)PhImageBaseAddress; imageNtHeader = (PIMAGE_NT_HEADERS)PTR_ADD_OFFSET(imageDosHeader, (ULONG)imageDosHeader->e_lfanew); RtlSecondsSince1970ToTime(imageNtHeader->FileHeader.TimeDateStamp, &time); PhLargeIntegerToLocalSystemTime(&systemTime, &time); diff --git a/plugins/Updater/updater.c b/plugins/Updater/updater.c index 6cc3cdc1facd..328bd6f35862 100644 --- a/plugins/Updater/updater.c +++ b/plugins/Updater/updater.c @@ -70,8 +70,8 @@ VOID TaskDialogCreateIcons( _In_ PPH_UPDATER_CONTEXT Context ) { - Context->IconSmallHandle = UT_LOAD_SHARED_ICON_SMALL(MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER)); - Context->IconLargeHandle = UT_LOAD_SHARED_ICON_LARGE(MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER)); + Context->IconSmallHandle = PH_LOAD_SHARED_ICON_SMALL(PhImageBaseAddress, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER)); + Context->IconLargeHandle = PH_LOAD_SHARED_ICON_LARGE(PhImageBaseAddress, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER)); SendMessage(Context->DialogHandle, WM_SETICON, ICON_SMALL, (LPARAM)Context->IconSmallHandle); SendMessage(Context->DialogHandle, WM_SETICON, ICON_BIG, (LPARAM)Context->IconLargeHandle); @@ -317,7 +317,7 @@ BOOLEAN QueryUpdateData( if (!(httpSessionHandle = WinHttpOpen( NULL, - WindowsVersion >= WINDOWS_8_1 ? WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY : WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, + PhWindowsVersion() >= WINDOWS_8_1 ? WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY : WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0 @@ -327,7 +327,7 @@ BOOLEAN QueryUpdateData( goto CleanupExit; } - if (WindowsVersion >= WINDOWS_8_1) + if (PhWindowsVersion() >= WINDOWS_8_1) { ULONG httpFlags = WINHTTP_DECOMPRESSION_FLAG_GZIP | WINHTTP_DECOMPRESSION_FLAG_DEFLATE; @@ -364,7 +364,7 @@ BOOLEAN QueryUpdateData( goto CleanupExit; } - if (WindowsVersion >= WINDOWS_7) + if (PhWindowsVersion() >= WINDOWS_7) { ULONG keepAlive = WINHTTP_DISABLE_KEEP_ALIVE; WinHttpSetOption(httpRequestHandle, WINHTTP_OPTION_DISABLE_FEATURE, &keepAlive, sizeof(ULONG)); @@ -760,7 +760,7 @@ NTSTATUS UpdateDownloadThread( // Open the HTTP session with the system proxy configuration if available if (!(httpSessionHandle = WinHttpOpen( PhGetString(userAgentString), - WindowsVersion >= WINDOWS_8_1 ? WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY : WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, + PhWindowsVersion() >= WINDOWS_8_1 ? WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY : WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0 @@ -770,7 +770,7 @@ NTSTATUS UpdateDownloadThread( goto CleanupExit; } - if (WindowsVersion >= WINDOWS_8_1) + if (PhWindowsVersion() >= WINDOWS_8_1) { ULONG httpFlags = WINHTTP_DECOMPRESSION_FLAG_GZIP | WINHTTP_DECOMPRESSION_FLAG_DEFLATE; WinHttpSetOption(httpSessionHandle, WINHTTP_OPTION_DECOMPRESSION, &httpFlags, sizeof(ULONG)); @@ -801,7 +801,7 @@ NTSTATUS UpdateDownloadThread( goto CleanupExit; } - if (WindowsVersion >= WINDOWS_7) + if (PhWindowsVersion() >= WINDOWS_7) { ULONG keepAlive = WINHTTP_DISABLE_KEEP_ALIVE; WinHttpSetOption(httpRequestHandle, WINHTTP_OPTION_DISABLE_FEATURE, &keepAlive, sizeof(ULONG)); @@ -1093,11 +1093,11 @@ LRESULT CALLBACK TaskDialogSubclassProc( // break; //case WM_NCACTIVATE: // { - // if (IsWindowVisible(PhMainWndHandle) && !IsMinimized(PhMainWndHandle)) + // if (IsWindowVisible(PhMainWindowHandle) && !IsMinimized(PhMainWindowHandle)) // { // if (!context->FixedWindowStyles) // { - // SetWindowLongPtr(hwndDlg, GWLP_HWNDPARENT, (LONG_PTR)PhMainWndHandle); + // SetWindowLongPtr(hwndDlg, GWLP_HWNDPARENT, (LONG_PTR)PhMainWindowHandle); // PhSetWindowExStyle(hwndDlg, WS_EX_APPWINDOW, WS_EX_APPWINDOW); // context->FixedWindowStyles = TRUE; // } @@ -1126,7 +1126,7 @@ HRESULT CALLBACK TaskDialogBootstrapCallback( UpdateDialogHandle = context->DialogHandle = hwndDlg; // Center the update window on PH if it's visible else we center on the desktop. - PhCenterWindow(hwndDlg, (IsWindowVisible(PhMainWndHandle) && !IsMinimized(PhMainWndHandle)) ? PhMainWndHandle : NULL); + PhCenterWindow(hwndDlg, (IsWindowVisible(PhMainWindowHandle) && !IsMinimized(PhMainWindowHandle)) ? PhMainWindowHandle : NULL); // Create the Taskdialog icons TaskDialogCreateIcons(context); @@ -1193,7 +1193,7 @@ VOID ShowUpdateDialog( { if (!(UpdateDialogThreadHandle = PhCreateThread(0, ShowUpdateDialogThread, Context))) { - PhShowStatus(PhMainWndHandle, L"Unable to create the updater window.", 0, GetLastError()); + PhShowStatus(PhMainWindowHandle, L"Unable to create the updater window.", 0, GetLastError()); return; } diff --git a/plugins/Updater/updater.h b/plugins/Updater/updater.h index ab8b850a635c..5afc567627b0 100644 --- a/plugins/Updater/updater.h +++ b/plugins/Updater/updater.h @@ -55,9 +55,6 @@ ((ULONGLONG)(build) << 16) | \ ((ULONGLONG)(revision) << 0)) -#define UT_LOAD_SHARED_ICON_SMALL(Name) PhLoadIcon(PhLibImageBase, (Name), PH_LOAD_ICON_SHARED | PH_LOAD_ICON_SIZE_SMALL, 0, 0) -#define UT_LOAD_SHARED_ICON_LARGE(Name) PhLoadIcon(PhLibImageBase, (Name), PH_LOAD_ICON_SHARED | PH_LOAD_ICON_SIZE_LARGE, 0, 0) - #ifdef _DEBUG // Force update checks to succeed (most of the below flags require this to be defined). //#define FORCE_UPDATE_CHECK diff --git a/plugins/UserNotes/main.c b/plugins/UserNotes/main.c index 88a55cfa438b..42026cb27874 100644 --- a/plugins/UserNotes/main.c +++ b/plugins/UserNotes/main.c @@ -181,7 +181,7 @@ ULONG GetProcessAffinity( if (NT_SUCCESS(PhOpenProcess( &processHandle, - ProcessQueryAccess, + PhProcessQueryAccess(), ProcessId ))) { @@ -208,7 +208,7 @@ IO_PRIORITY_HINT GetProcessIoPriority( if (NT_SUCCESS(PhOpenProcess( &processHandle, - ProcessQueryAccess, + PhProcessQueryAccess(), ProcessId ))) { @@ -425,7 +425,7 @@ VOID NTAPI MenuItemCallback( if (!highlightPresent) { CHOOSECOLOR chooseColor = { sizeof(CHOOSECOLOR) }; - chooseColor.hwndOwner = PhMainWndHandle; + chooseColor.hwndOwner = PhMainWindowHandle; chooseColor.lpCustColors = ProcessCustomColors; chooseColor.lpfnHook = ColorDlgHookProc; chooseColor.Flags = CC_ANYCOLOR | CC_FULLOPEN | CC_SOLIDCOLOR | CC_ENABLEHOOK; @@ -624,7 +624,7 @@ VOID NTAPI MenuHookCallback( affinityMask = GetProcessAffinity(processItem->ProcessId); // Show the affinity dialog (with our values). - if (PhShowProcessAffinityDialog2(PhMainWndHandle, affinityMask, &newAffinityMask)) + if (PhShowProcessAffinityDialog2(PhMainWindowHandle, affinityMask, &newAffinityMask)) { PDB_OBJECT object; @@ -1432,13 +1432,14 @@ LOGICAL DllMain( NULL, &MiListSectionMenuInitializingCallbackRegistration ); - PhRegisterCallback(&PhProcessModifiedEvent, + PhRegisterCallback( + PhGetGeneralCallback(GeneralCallbackProcessProviderModified), ProcessModifiedCallback, NULL, &ProcessModifiedCallbackRegistration ); PhRegisterCallback( - &PhProcessesUpdatedEvent, + PhGetGeneralCallback(GeneralCallbackProcessProviderUpdated), ProcessesUpdatedCallback, NULL, &ProcessesUpdatedCallbackRegistration @@ -1881,7 +1882,7 @@ UINT_PTR CALLBACK ColorDlgHookProc( { case WM_INITDIALOG: { - PhCenterWindow(hwndDlg, PhMainWndHandle); + PhCenterWindow(hwndDlg, PhMainWindowHandle); EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); } diff --git a/plugins/WindowExplorer/WindowExplorer.vcxproj b/plugins/WindowExplorer/WindowExplorer.vcxproj index f61d6d998529..955db20f5099 100644 --- a/plugins/WindowExplorer/WindowExplorer.vcxproj +++ b/plugins/WindowExplorer/WindowExplorer.vcxproj @@ -53,12 +53,12 @@ - ProcessHacker.exe;comctl32.dll;%(DelayLoadDLLs) + ProcessHacker.exe;comctl32.dll;gdi32.dll;user32.dll;%(DelayLoadDLLs) - ProcessHacker.exe;comctl32.dll;%(DelayLoadDLLs) + ProcessHacker.exe;comctl32.dll;gdi32.dll;user32.dll;%(DelayLoadDLLs) diff --git a/plugins/WindowExplorer/main.c b/plugins/WindowExplorer/main.c index c31834ae619d..987bdd8e6833 100644 --- a/plugins/WindowExplorer/main.c +++ b/plugins/WindowExplorer/main.c @@ -231,7 +231,7 @@ LOGICAL DllMain( isClient = FALSE; - if (!GetModuleHandle(L"ProcessHacker.exe") || !WeGetProcedureAddress("PhLibImageBase")) + if (!GetModuleHandle(L"ProcessHacker.exe") || !WeGetProcedureAddress("PhGetImageBase")) { isClient = TRUE; } diff --git a/plugins/WindowExplorer/wndexp.h b/plugins/WindowExplorer/wndexp.h index dba7a96bc9a2..2f03023ad597 100644 --- a/plugins/WindowExplorer/wndexp.h +++ b/plugins/WindowExplorer/wndexp.h @@ -116,8 +116,8 @@ VOID WeShowWindowProperties( // utils -#define WE_PhMainWndHandle (*(HWND *)WeGetProcedureAddress("PhMainWndHandle")) -#define WE_WindowsVersion (*(ULONG *)WeGetProcedureAddress("WindowsVersion")) +#define WE_PhMainWndHandle (*(HWND *)WeGetProcedureAddress("PhGetMainWndHandle")) +#define WE_WindowsVersion (*(ULONG *)WeGetProcedureAddress("PhWindowsVersion")) PVOID WeGetProcedureAddress( _In_ PSTR Name diff --git a/plugins/WindowExplorer/wndprp.c b/plugins/WindowExplorer/wndprp.c index 515b17ee9c40..7ed88dbf2a40 100644 --- a/plugins/WindowExplorer/wndprp.c +++ b/plugins/WindowExplorer/wndprp.c @@ -611,7 +611,7 @@ static VOID WepEnsureHookDataValid( #ifdef _WIN64 // We can't use the hook on WOW64 processes. - if (NT_SUCCESS(PhOpenProcess(&processHandle, *(PULONG)WeGetProcedureAddress("ProcessQueryAccess"), Context->ClientId.UniqueProcess))) + if (NT_SUCCESS(PhOpenProcess(&processHandle, *(PULONG)WeGetProcedureAddress("PhProcessQueryAccess"), Context->ClientId.UniqueProcess))) { PhGetProcessIsWow64(processHandle, &isWow64); NtClose(processHandle); diff --git a/tools/peview/peview.vcxproj b/tools/peview/peview.vcxproj index a5a6ae577e12..14e547b6dcc5 100644 --- a/tools/peview/peview.vcxproj +++ b/tools/peview/peview.vcxproj @@ -96,14 +96,15 @@ true - noarg.obj;noenv.obj;phlib.lib;ntdll.lib;uxtheme.lib;windowscodecs.lib;%(AdditionalDependencies) - ..\..\phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) + delaylib.lib;noarg.obj;noenv.obj;phlib.lib;ntdll.lib;uxtheme.lib;windowscodecs.lib;%(AdditionalDependencies) + ..\..\phlib\bin\$(Configuration)$(PlatformArchitecture);..\..\tools\delaylib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) true Windows MachineX86 6.01 + __delayLoadHelper2 ..\..\phnt\include;..\..\phlib\include;include;%(AdditionalIncludeDirectories) @@ -125,14 +126,15 @@ true - noarg.obj;noenv.obj;phlib.lib;ntdll.lib;uxtheme.lib;windowscodecs.lib;%(AdditionalDependencies) - ..\..\phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) + delaylib.lib;noarg.obj;noenv.obj;phlib.lib;ntdll.lib;uxtheme.lib;windowscodecs.lib;%(AdditionalDependencies) + ..\..\phlib\bin\$(Configuration)$(PlatformArchitecture);..\..\tools\delaylib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) true Windows MachineX64 6.01 + __delayLoadHelper2 ..\..\phnt\include;..\..\phlib\include;include;%(AdditionalIncludeDirectories) @@ -157,8 +159,8 @@ true - noarg.obj;noenv.obj;phlib.lib;ntdll.lib;uxtheme.lib;windowscodecs.lib;%(AdditionalDependencies) - ..\..\phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) + delaylib.lib;noarg.obj;noenv.obj;phlib.lib;ntdll.lib;uxtheme.lib;windowscodecs.lib;%(AdditionalDependencies) + ..\..\phlib\bin\$(Configuration)$(PlatformArchitecture);..\..\tools\delaylib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) true @@ -168,6 +170,7 @@ MachineX86 true 6.01 + __delayLoadHelper2 ..\..\phnt\include;..\..\phlib\include;include;%(AdditionalIncludeDirectories) @@ -191,8 +194,8 @@ true - noarg.obj;noenv.obj;phlib.lib;ntdll.lib;uxtheme.lib;windowscodecs.lib;%(AdditionalDependencies) - ..\..\phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) + delaylib.lib;noarg.obj;noenv.obj;phlib.lib;ntdll.lib;uxtheme.lib;windowscodecs.lib;%(AdditionalDependencies) + ..\..\phlib\bin\$(Configuration)$(PlatformArchitecture);..\..\tools\delaylib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) true @@ -202,6 +205,7 @@ MachineX64 true 6.01 + __delayLoadHelper2 ..\..\phnt\include;..\..\phlib\include;include;%(AdditionalIncludeDirectories) From 63a688a90e4b188496143607864363a2a2fe05ce Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 21 May 2017 11:58:14 +1000 Subject: [PATCH 0139/2058] Setup: Fix build, Fix licence window, Add initial web-setup --- .../CustomSetupTool/CustomSetupTool.vcxproj | 48 +- .../CustomSetupTool.vcxproj.filters | 131 ++- .../CustomSetupTool/download.c | 771 +++++++++++++++ .../CustomSetupTool/include/setup.h | 50 +- .../CustomSetupTool/json-c/AUTHORS | 5 + .../CustomSetupTool/json-c/COPYING | 42 + .../CustomSetupTool/json-c/ChangeLog | 214 +++++ .../CustomSetupTool/json-c/arraylist.c | 101 ++ .../CustomSetupTool/json-c/arraylist.h | 56 ++ .../CustomSetupTool/json-c/bits.h | 28 + .../CustomSetupTool/json-c/config.h | 89 ++ .../CustomSetupTool/json-c/config.h.in | 174 ++++ .../CustomSetupTool/json-c/debug.c | 83 ++ .../CustomSetupTool/json-c/debug.h | 71 ++ .../CustomSetupTool/json-c/json.h | 34 + .../CustomSetupTool/json-c/json_c_version.c | 20 + .../CustomSetupTool/json-c/json_c_version.h | 22 + .../CustomSetupTool/json-c/json_config.h | 3 + .../CustomSetupTool/json-c/json_inttypes.h | 28 + .../CustomSetupTool/json-c/json_object.c | 860 +++++++++++++++++ .../CustomSetupTool/json-c/json_object.h | 611 ++++++++++++ .../json-c/json_object_iterator.c | 168 ++++ .../json-c/json_object_iterator.h | 239 +++++ .../json-c/json_object_private.h | 47 + .../CustomSetupTool/json-c/json_tokener.c | 888 ++++++++++++++++++ .../CustomSetupTool/json-c/json_tokener.h | 208 ++++ .../CustomSetupTool/json-c/json_util.c | 301 ++++++ .../CustomSetupTool/json-c/json_util.h | 41 + .../CustomSetupTool/json-c/libjson.c | 26 + .../CustomSetupTool/json-c/linkhash.c | 604 ++++++++++++ .../CustomSetupTool/json-c/linkhash.h | 292 ++++++ .../CustomSetupTool/json-c/math_compat.h | 28 + .../CustomSetupTool/json-c/printbuf.c | 194 ++++ .../CustomSetupTool/json-c/printbuf.h | 81 ++ .../CustomSetupTool/json-c/random_seed.c | 238 +++++ .../CustomSetupTool/json-c/random_seed.h | 25 + tools/CustomSetupTool/CustomSetupTool/main.c | 10 + tools/CustomSetupTool/CustomSetupTool/page2.c | 16 +- tools/CustomSetupTool/CustomSetupTool/page5.c | 171 ++++ .../CustomSetupTool/resource.h | 25 +- .../CustomSetupTool/resource.rc | 117 +-- .../resources/{Licence.txt => LICENSE.txt} | 97 +- .../CustomSetupTool/resources/version.rc | 80 ++ .../CustomSetupTool/uninstall.c | 7 - .../CustomSetupTool/CustomSetupTool/update.c | 12 +- 45 files changed, 7162 insertions(+), 194 deletions(-) create mode 100644 tools/CustomSetupTool/CustomSetupTool/download.c create mode 100644 tools/CustomSetupTool/CustomSetupTool/json-c/AUTHORS create mode 100644 tools/CustomSetupTool/CustomSetupTool/json-c/COPYING create mode 100644 tools/CustomSetupTool/CustomSetupTool/json-c/ChangeLog create mode 100644 tools/CustomSetupTool/CustomSetupTool/json-c/arraylist.c create mode 100644 tools/CustomSetupTool/CustomSetupTool/json-c/arraylist.h create mode 100644 tools/CustomSetupTool/CustomSetupTool/json-c/bits.h create mode 100644 tools/CustomSetupTool/CustomSetupTool/json-c/config.h create mode 100644 tools/CustomSetupTool/CustomSetupTool/json-c/config.h.in create mode 100644 tools/CustomSetupTool/CustomSetupTool/json-c/debug.c create mode 100644 tools/CustomSetupTool/CustomSetupTool/json-c/debug.h create mode 100644 tools/CustomSetupTool/CustomSetupTool/json-c/json.h create mode 100644 tools/CustomSetupTool/CustomSetupTool/json-c/json_c_version.c create mode 100644 tools/CustomSetupTool/CustomSetupTool/json-c/json_c_version.h create mode 100644 tools/CustomSetupTool/CustomSetupTool/json-c/json_config.h create mode 100644 tools/CustomSetupTool/CustomSetupTool/json-c/json_inttypes.h create mode 100644 tools/CustomSetupTool/CustomSetupTool/json-c/json_object.c create mode 100644 tools/CustomSetupTool/CustomSetupTool/json-c/json_object.h create mode 100644 tools/CustomSetupTool/CustomSetupTool/json-c/json_object_iterator.c create mode 100644 tools/CustomSetupTool/CustomSetupTool/json-c/json_object_iterator.h create mode 100644 tools/CustomSetupTool/CustomSetupTool/json-c/json_object_private.h create mode 100644 tools/CustomSetupTool/CustomSetupTool/json-c/json_tokener.c create mode 100644 tools/CustomSetupTool/CustomSetupTool/json-c/json_tokener.h create mode 100644 tools/CustomSetupTool/CustomSetupTool/json-c/json_util.c create mode 100644 tools/CustomSetupTool/CustomSetupTool/json-c/json_util.h create mode 100644 tools/CustomSetupTool/CustomSetupTool/json-c/libjson.c create mode 100644 tools/CustomSetupTool/CustomSetupTool/json-c/linkhash.c create mode 100644 tools/CustomSetupTool/CustomSetupTool/json-c/linkhash.h create mode 100644 tools/CustomSetupTool/CustomSetupTool/json-c/math_compat.h create mode 100644 tools/CustomSetupTool/CustomSetupTool/json-c/printbuf.c create mode 100644 tools/CustomSetupTool/CustomSetupTool/json-c/printbuf.h create mode 100644 tools/CustomSetupTool/CustomSetupTool/json-c/random_seed.c create mode 100644 tools/CustomSetupTool/CustomSetupTool/json-c/random_seed.h create mode 100644 tools/CustomSetupTool/CustomSetupTool/page5.c rename tools/CustomSetupTool/CustomSetupTool/resources/{Licence.txt => LICENSE.txt} (67%) create mode 100644 tools/CustomSetupTool/CustomSetupTool/resources/version.rc diff --git a/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj b/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj index ec82116e1157..cd939c79a92a 100644 --- a/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj +++ b/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj @@ -69,6 +69,10 @@ Windows RequireAdministrator + + _UNICODE;UNICODE;%(PreprocessorDefinitions);$(ExternalCompilerOptions) + ..\..\..\phnt\include;..\..\..\phlib\include;include;%(AdditionalIncludeDirectories) + @@ -97,16 +101,33 @@ true RequireAdministrator + + _UNICODE;UNICODE;%(PreprocessorDefinitions);$(ExternalCompilerOptions) + ..\..\..\phnt\include;..\..\..\phlib\include;include;%(AdditionalIncludeDirectories) + + + + + + + + + + + + + + @@ -114,14 +135,29 @@ + + + + + + + + + + + + + + + + + - - _UNICODE;UNICODE;%(PreprocessorDefinitions);$(ExternalCompilerOptions) - ..\..\..\phnt\include;..\..\..\phlib\include;include;%(AdditionalIncludeDirectories) - + + @@ -133,10 +169,10 @@ - + - + diff --git a/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj.filters b/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj.filters index fd0778f3dc06..85f331c02a3f 100644 --- a/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj.filters +++ b/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj.filters @@ -13,24 +13,24 @@ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - - {3f81aff6-dff1-4573-bb20-ac132fa9297b} - - - {de42287f-b6af-40c6-b76a-f56ee7dcf507} - {c394360d-d423-4249-a23e-70558948e7f2} - - {fcf7dac9-ef61-47e6-8aae-818354f6b4df} - {5c3f4462-038f-468f-8ab2-7e153d301c33} {7a7dfb06-20d6-4ea2-8992-26ea6e6cf1d9} + + {0e40a0b6-7e1f-4ef2-9c13-14d083de096e} + + + {8d69960b-e11c-4029-b39e-dee698bb871b} + + + {3f81aff6-dff1-4573-bb20-ac132fa9297b} + @@ -66,6 +66,45 @@ Source Files + + Source Files + + + Source Files\pages + + + Source Files\json + + + Source Files\json + + + Source Files\json + + + Source Files\json + + + Source Files\json + + + Source Files\json + + + Source Files\json + + + Source Files\json + + + Source Files\json + + + Source Files\json + + + Source Files\json + @@ -80,33 +119,87 @@ Header Files\zip + + Header Files\json + + + Header Files\json + + + Header Files\json + + + Header Files\json + + + Header Files\json + + + Header Files\json + + + Header Files\json + + + Header Files\json + + + Header Files\json + + + Header Files\json + + + Header Files\json + + + Header Files\json + + + Header Files\json + + + Header Files\json + + + Header Files\json + + + Header Files\json + + + Header Files\json + - Resource Files\Images + Resource Files\Content - Resource Files\Images + Resource Files\Content Resource Files + + Resource Files + - - Resource Files\Text + + Resource Files\Content - - Resource Files - + + Resource Files\Content + - - Resource Files\Binary - + + Resource Files\Content + \ No newline at end of file diff --git a/tools/CustomSetupTool/CustomSetupTool/download.c b/tools/CustomSetupTool/CustomSetupTool/download.c new file mode 100644 index 000000000000..9ae9010c1566 --- /dev/null +++ b/tools/CustomSetupTool/CustomSetupTool/download.c @@ -0,0 +1,771 @@ +#include +#include +#include +#include + +#include "json-c\json.h" + +typedef struct _PH_SETUP_DOWNLOAD_CONTEXT +{ + HWND DialogHandle; + HICON IconSmallHandle; + HICON IconLargeHandle; +} PH_SETUP_DOWNLOAD_CONTEXT, *PPH_SETUP_DOWNLOAD_CONTEXT; + +PPH_STRING SetupGetVersion( + VOID +) +{ + PH_FORMAT format[7]; + + PhInitFormatU(&format[0], PHAPP_VERSION_MAJOR); + PhInitFormatC(&format[1], '.'); + PhInitFormatU(&format[2], PHAPP_VERSION_MINOR); + PhInitFormatC(&format[3], '.'); + PhInitFormatU(&format[4], PHAPP_VERSION_REVISION); + PhInitFormatC(&format[5], '.'); + PhInitFormatU(&format[6], PHAPP_VERSION_BUILD); + + return PhFormat(format, 7, 16); +} + +PPH_STRING UpdateVersionString( + VOID + ) +{ + PPH_STRING currentVersion = 0; + PPH_STRING versionHeader = NULL; + + if (currentVersion = SetupGetVersion()) + { + versionHeader = PhConcatStrings2(L"PH-SETUP-BUILD: ", currentVersion->Buffer); + PhDereferenceObject(currentVersion); + } + + return versionHeader; +} + +PPH_STRING UpdateWindowsString( + VOID + ) +{ + static PH_STRINGREF keyName = PH_STRINGREF_INIT(L"Software\\Microsoft\\Windows NT\\CurrentVersion"); + + HANDLE keyHandle; + PPH_STRING buildLabHeader = NULL; + + if (NT_SUCCESS(PhOpenKey( + &keyHandle, + KEY_READ, + PH_KEY_LOCAL_MACHINE, + &keyName, + 0 + ))) + { + PPH_STRING buildLabString; + + if (buildLabString = PhQueryRegistryString(keyHandle, L"BuildLabEx")) + { + buildLabHeader = PhConcatStrings2(L"PH-OsBuild: ", buildLabString->Buffer); + PhDereferenceObject(buildLabString); + } + else if (buildLabString = PhQueryRegistryString(keyHandle, L"BuildLab")) + { + buildLabHeader = PhConcatStrings2(L"PH-OsBuild: ", buildLabString->Buffer); + PhDereferenceObject(buildLabString); + } + + NtClose(keyHandle); + } + + return buildLabHeader; +} + +BOOLEAN ParseVersionString( + _Inout_ PPH_SETUP_DOWNLOAD_CONTEXT Context + ) +{ + PH_STRINGREF remaining, majorPart, minorPart, revisionPart; + ULONG64 majorInteger = 0, minorInteger = 0, revisionInteger = 0; + + //PhInitializeStringRef(&remaining, PhGetStringOrEmpty(Context->Version)); + + PhSplitStringRefAtChar(&remaining, '.', &majorPart, &remaining); + PhSplitStringRefAtChar(&remaining, '.', &minorPart, &remaining); + PhSplitStringRefAtChar(&remaining, '.', &revisionPart, &remaining); + + PhStringToInteger64(&majorPart, 10, &majorInteger); + PhStringToInteger64(&minorPart, 10, &minorInteger); + PhStringToInteger64(&revisionPart, 10, &revisionInteger); + + //Context->MajorVersion = (ULONG)majorInteger; + //Context->MinorVersion = (ULONG)minorInteger; + //Context->RevisionVersion = (ULONG)revisionInteger; + return TRUE; +} + +BOOLEAN ReadRequestString( + _In_ HINTERNET Handle, + _Out_ _Deref_post_z_cap_(*DataLength) PSTR *Data, + _Out_ ULONG *DataLength +) +{ + PSTR data; + ULONG allocatedLength; + ULONG dataLength; + ULONG returnLength; + BYTE buffer[PAGE_SIZE]; + + allocatedLength = sizeof(buffer); + data = (PSTR)PhAllocate(allocatedLength); + dataLength = 0; + + memset(buffer, 0, PAGE_SIZE); + memset(data, 0, allocatedLength); + + while (WinHttpReadData(Handle, buffer, PAGE_SIZE, &returnLength)) + { + if (returnLength == 0) + break; + + if (allocatedLength < dataLength + returnLength) + { + allocatedLength *= 2; + data = (PSTR)PhReAllocate(data, allocatedLength); + } + + memcpy(data + dataLength, buffer, returnLength); + + dataLength += returnLength; + } + + if (allocatedLength < dataLength + 1) + { + allocatedLength++; + data = (PSTR)PhReAllocate(data, allocatedLength); + } + + data[dataLength] = 0; + + *DataLength = dataLength; + *Data = data; + + return TRUE; +} + +json_object_ptr json_get_object( + _In_ json_object_ptr rootObj, + _In_ const PSTR key +) +{ + json_object_ptr returnObj; + + if (json_object_object_get_ex(rootObj, key, &returnObj)) + { + return returnObj; + } + + return NULL; +} + + +BOOLEAN SetupQueryUpdateData( + _Inout_ PPH_SETUP_UNINSTALL_CONTEXT Context + ) +{ + BOOLEAN success = FALSE; + HINTERNET httpSessionHandle = NULL; + HINTERNET httpConnectionHandle = NULL; + HINTERNET httpRequestHandle = NULL; + ULONG stringBufferLength = 0; + PSTR stringBuffer = NULL; + PVOID jsonObject = NULL; + PPH_STRING versionHeader = UpdateVersionString(); + PPH_STRING windowsHeader = UpdateWindowsString(); + + if (!(httpSessionHandle = WinHttpOpen( + NULL, + WindowsVersion >= WINDOWS_8_1 ? WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY : WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, + WINHTTP_NO_PROXY_NAME, + WINHTTP_NO_PROXY_BYPASS, + 0 + ))) + { + goto CleanupExit; + } + + if (WindowsVersion >= WINDOWS_8_1) + { + ULONG httpFlags = WINHTTP_DECOMPRESSION_FLAG_GZIP | WINHTTP_DECOMPRESSION_FLAG_DEFLATE; + + WinHttpSetOption( + httpSessionHandle, + WINHTTP_OPTION_DECOMPRESSION, + &httpFlags, + sizeof(ULONG) + ); + } + + if (!(httpConnectionHandle = WinHttpConnect( + httpSessionHandle, + L"wj32.org", + INTERNET_DEFAULT_HTTPS_PORT, + 0 + ))) + { + //Context->ErrorCode = GetLastError(); + goto CleanupExit; + } + + if (!(httpRequestHandle = WinHttpOpenRequest( + httpConnectionHandle, + NULL, + L"/processhacker/nightly.php?latest", + NULL, + WINHTTP_NO_REFERER, + WINHTTP_DEFAULT_ACCEPT_TYPES, + WINHTTP_FLAG_REFRESH | WINHTTP_FLAG_SECURE + ))) + { + //Context->ErrorCode = GetLastError(); + goto CleanupExit; + } + + if (WindowsVersion >= WINDOWS_7) + { + ULONG keepAlive = WINHTTP_DISABLE_KEEP_ALIVE; + WinHttpSetOption(httpRequestHandle, WINHTTP_OPTION_DISABLE_FEATURE, &keepAlive, sizeof(ULONG)); + } + + if (versionHeader) + { + WinHttpAddRequestHeaders( + httpRequestHandle, + versionHeader->Buffer, + (ULONG)versionHeader->Length / sizeof(WCHAR), + WINHTTP_ADDREQ_FLAG_ADD + ); + } + + if (windowsHeader) + { + WinHttpAddRequestHeaders( + httpRequestHandle, + windowsHeader->Buffer, + (ULONG)windowsHeader->Length / sizeof(WCHAR), + WINHTTP_ADDREQ_FLAG_ADD + ); + } + + if (!WinHttpSendRequest( + httpRequestHandle, + WINHTTP_NO_ADDITIONAL_HEADERS, + 0, + WINHTTP_NO_REQUEST_DATA, + 0, + WINHTTP_IGNORE_REQUEST_TOTAL_LENGTH, + 0 + )) + { + //Context->ErrorCode = GetLastError(); + goto CleanupExit; + } + + if (!WinHttpReceiveResponse(httpRequestHandle, NULL)) + { + //Context->ErrorCode = GetLastError(); + goto CleanupExit; + } + + if (!ReadRequestString(httpRequestHandle, &stringBuffer, &stringBufferLength)) + goto CleanupExit; + + // Check the buffer for valid data + if (stringBuffer == NULL || stringBuffer[0] == '\0') + goto CleanupExit; + + if (!(jsonObject = json_tokener_parse(stringBuffer))) + goto CleanupExit; + + Context->Version = PhConvertUtf8ToUtf16(json_object_get_string(json_get_object(jsonObject, "version"))); + //Context->RevVersion = PhConvertUtf8ToUtf16(json_object_get_string(json_get_object(jsonObject, "rev"))); + Context->RelDate = PhConvertUtf8ToUtf16(json_object_get_string(json_get_object(jsonObject, "updated"))); + Context->Size = PhFormatSize(json_object_get_int64(json_get_object(jsonObject, "size")), -1); + Context->Hash = PhConvertUtf8ToUtf16(json_object_get_string(json_get_object(jsonObject, "hash_setup"))); + Context->Signature = PhConvertUtf8ToUtf16(json_object_get_string(json_get_object(jsonObject, "sig"))); + Context->ReleaseNotesUrl = PhConvertUtf8ToUtf16(json_object_get_string(json_get_object(jsonObject, "forum_url"))); + Context->BinFileDownloadUrl = PhConvertUtf8ToUtf16(json_object_get_string(json_get_object(jsonObject, "bin_url"))); + Context->SetupFileDownloadUrl = PhConvertUtf8ToUtf16(json_object_get_string(json_get_object(jsonObject, "setup_url"))); + //Context->BuildMessage = PhConvertUtf8ToUtf16(GetJsonValueAsString(jsonObject, "message")); + + PH_STRINGREF remaining, majorPart, minorPart, revisionPart; + ULONG64 majorInteger = 0, minorInteger = 0, revisionInteger = 0; + + PhInitializeStringRef(&remaining, PhGetStringOrEmpty(Context->Version)); + + PhSplitStringRefAtChar(&remaining, '.', &majorPart, &remaining); + PhSplitStringRefAtChar(&remaining, '.', &minorPart, &remaining); + PhSplitStringRefAtChar(&remaining, '.', &revisionPart, &remaining); + + PhStringToInteger64(&majorPart, 10, &majorInteger); + PhStringToInteger64(&minorPart, 10, &minorInteger); + PhStringToInteger64(&revisionPart, 10, &revisionInteger); + + Context->LatestMajorVersion = (ULONG)majorInteger; + Context->LatestMinorVersion = (ULONG)minorInteger; + Context->LatestRevisionVersion = (ULONG)revisionInteger; + + /* Context->Version = PhConvertUtf8ToUtf16(GetJsonValueAsString(jsonObject, "version")); + Context->RevVersion = PhConvertUtf8ToUtf16(GetJsonValueAsString(jsonObject, "version")); + Context->RelDate = PhConvertUtf8ToUtf16(GetJsonValueAsString(jsonObject, "updated")); + Context->Size = PhFormatSize(GetJsonValueAsUlong(jsonObject, "size"), 2); + Context->Hash = PhConvertUtf8ToUtf16(GetJsonValueAsString(jsonObject, "hash_setup")); + Context->Signature = PhConvertUtf8ToUtf16(GetJsonValueAsString(jsonObject, "sig")); + Context->ReleaseNotesUrl = PhConvertUtf8ToUtf16(GetJsonValueAsString(jsonObject, "forum_url")); + Context->SetupFileDownloadUrl = PhConvertUtf8ToUtf16(GetJsonValueAsString(jsonObject, "setup_url")); + Context->BuildMessage = PhConvertUtf8ToUtf16(GetJsonValueAsString(jsonObject, "message")); + + PH_STRING_BUILDER sb; + PhInitializeStringBuilder(&sb, 0x100); + for (size_t i = 0; i < Context->BuildMessage->Length; i++) + { + if (Context->BuildMessage->Data[i] == '\n') + PhAppendFormatStringBuilder(&sb, L"\r\n"); + else + PhAppendCharStringBuilder(&sb, Context->BuildMessage->Data[i]); + } + PhMoveReference(&Context->BuildMessage, PhFinalStringBuilderString(&sb)); + + CleanupJsonParser(jsonObject); + + if (PhIsNullOrEmptyString(Context->Signature)) + goto CleanupExit; + + if (!ParseVersionString(Context)) + goto CleanupExit; + + if (PhIsNullOrEmptyString(Context->Version)) + goto CleanupExit; + if (PhIsNullOrEmptyString(Context->RevVersion)) + goto CleanupExit; + if (PhIsNullOrEmptyString(Context->RelDate)) + goto CleanupExit; + if (PhIsNullOrEmptyString(Context->Size)) + goto CleanupExit; + if (PhIsNullOrEmptyString(Context->Hash)) + goto CleanupExit; + if (PhIsNullOrEmptyString(Context->ReleaseNotesUrl)) + goto CleanupExit; + if (PhIsNullOrEmptyString(Context->SetupFileDownloadUrl)) + goto CleanupExit;*/ + + success = TRUE; + +CleanupExit: + + if (httpRequestHandle) + WinHttpCloseHandle(httpRequestHandle); + + if (httpConnectionHandle) + WinHttpCloseHandle(httpConnectionHandle); + + if (httpSessionHandle) + WinHttpCloseHandle(httpSessionHandle); + + //if (xmlNode) + // mxmlDelete(xmlNode); + + if (stringBuffer) + PhFree(stringBuffer); + + PhClearReference(&versionHeader); + PhClearReference(&windowsHeader); + + return success; +} + + +//NTSTATUS UpdateCheckThread( +// _In_ PVOID Parameter +//) +//{ +// PPH_UPDATER_CONTEXT context = NULL; +// ULONGLONG currentVersion = 0; +// ULONGLONG latestVersion = 0; +// +// context = (PPH_UPDATER_CONTEXT)Parameter; +// context->ErrorCode = STATUS_SUCCESS; +// +// // Check if we have cached update data +// if (!context->HaveData) +// { +// context->HaveData = QueryUpdateData(context); +// } +// +// if (!context->HaveData) +// { +// PostMessage(context->DialogHandle, PH_UPDATEISERRORED, 0, 0); +// +// PhDereferenceObject(context); +// return STATUS_SUCCESS; +// } +// +// currentVersion = MAKE_VERSION_ULONGLONG( +// context->CurrentMajorVersion, +// context->CurrentMinorVersion, +// context->CurrentRevisionVersion, +// 0 +// ); +// +//#ifdef FORCE_UPDATE_CHECK +// latestVersion = MAKE_VERSION_ULONGLONG( +// 9999, +// 9999, +// 9999, +// 0 +// ); +//#else +// latestVersion = MAKE_VERSION_ULONGLONG( +// context->MajorVersion, +// context->MinorVersion, +// context->RevisionVersion, +// 0 +// ); +//#endif +// +// if (currentVersion == latestVersion) +// { +// // User is running the latest version +// PostMessage(context->DialogHandle, PH_UPDATEISCURRENT, 0, 0); +// } +// else if (currentVersion > latestVersion) +// { +// // User is running a newer version +// PostMessage(context->DialogHandle, PH_UPDATENEWER, 0, 0); +// } +// else +// { +// // User is running an older version +// PostMessage(context->DialogHandle, PH_UPDATEAVAILABLE, 0, 0); +// } +// +// PhDereferenceObject(context); +// return STATUS_SUCCESS; +//} + +BOOLEAN UpdateDownloadUpdateData( + _In_ PPH_SETUP_UNINSTALL_CONTEXT Context + ) +{ + BOOLEAN downloadSuccess = FALSE; +// BOOLEAN hashSuccess = FALSE; +// BOOLEAN signatureSuccess = FALSE; + HANDLE tempFileHandle = NULL; + HINTERNET httpSessionHandle = NULL; + HINTERNET httpConnectionHandle = NULL; + HINTERNET httpRequestHandle = NULL; + PPH_STRING setupTempPath = NULL; + PPH_STRING downloadHostPath = NULL; + PPH_STRING downloadUrlPath = NULL; + PPH_STRING userAgentString = NULL; + PPH_STRING fullSetupPath = NULL; + PPH_STRING randomGuidString = NULL; +// PUPDATER_HASH_CONTEXT hashContext = NULL; + ULONG indexOfFileName = -1; + GUID randomGuid; + URL_COMPONENTS httpUrlComponents = { sizeof(URL_COMPONENTS) }; + LARGE_INTEGER timeNow; + LARGE_INTEGER timeStart; + ULONG64 timeTicks = 0; + ULONG64 timeBitsPerSecond = 0; + + SetWindowText(Context->MainHeaderHandle, L"Initializing download request..."); + + userAgentString = PhFormatString( + L"PH_%lu.%lu_%lu", + Context->CurrentMajorVersion, + Context->CurrentMinorVersion, + Context->CurrentRevisionVersion + ); + + setupTempPath = PhCreateStringEx(NULL, GetTempPath(0, NULL) * sizeof(WCHAR)); + + if (GetTempPath((ULONG)setupTempPath->Length / sizeof(WCHAR), setupTempPath->Buffer) == 0) + goto CleanupExit; + + PhGenerateGuid(&randomGuid); + + if (randomGuidString = PhFormatGuid(&randomGuid)) + { + PhMoveReference( + &randomGuidString, + PhSubstring(randomGuidString, 1, randomGuidString->Length / sizeof(WCHAR) - 2) + ); + } + + Context->SetupFilePath = PhFormatString( + L"%s%s\\processhacker-%lu.%lu.%lu-bin.zip", + PhGetStringOrEmpty(setupTempPath), + PhGetStringOrEmpty(randomGuidString), + Context->LatestMajorVersion, + Context->LatestMinorVersion, + Context->LatestRevisionVersion + ); + if (PhIsNullOrEmptyString(Context->SetupFilePath)) + goto CleanupExit; + + if (fullSetupPath = PhGetFullPath(PhGetString(Context->SetupFilePath), &indexOfFileName)) + { + PPH_STRING directoryPath; + + if (indexOfFileName == -1) + goto CleanupExit; + + if (directoryPath = PhSubstring(fullSetupPath, 0, indexOfFileName)) + { + SHCreateDirectoryEx(NULL, directoryPath->Buffer, NULL); + PhDereferenceObject(directoryPath); + } + } + + if (!NT_SUCCESS(PhCreateFileWin32( + &tempFileHandle, + PhGetString(Context->SetupFilePath), + FILE_GENERIC_READ | FILE_GENERIC_WRITE, + FILE_ATTRIBUTE_NOT_CONTENT_INDEXED | FILE_ATTRIBUTE_TEMPORARY, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + FILE_OVERWRITE_IF, + FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT + ))) + { + goto CleanupExit; + } + + httpUrlComponents.dwSchemeLength = (ULONG)-1; + httpUrlComponents.dwHostNameLength = (ULONG)-1; + httpUrlComponents.dwUrlPathLength = (ULONG)-1; + + if (!WinHttpCrackUrl( + PhGetStringOrEmpty(Context->SetupFileDownloadUrl), + 0, + 0, + &httpUrlComponents + )) + { + //context->ErrorCode = GetLastError(); + goto CleanupExit; + } + + downloadHostPath = PhCreateStringEx( + httpUrlComponents.lpszHostName, + httpUrlComponents.dwHostNameLength * sizeof(WCHAR) + ); + downloadUrlPath = PhCreateStringEx( + httpUrlComponents.lpszUrlPath, + httpUrlComponents.dwUrlPathLength * sizeof(WCHAR) + ); + + SetWindowText(Context->MainHeaderHandle, PhFormatString(L"Downloading Process Hacker %lu.%lu.%lu...", + Context->LatestMajorVersion, + Context->CurrentMinorVersion, + Context->LatestRevisionVersion + )->Buffer); + + //SetWindowText(Context->SubHeaderHandle, L"Progress: ~ of ~ (0.0%)"); + //SendMessage(Context->ProgressHandle, PBM_SETRANGE32, 0, (LPARAM)ExtractTotalLength); + + if (!(httpSessionHandle = WinHttpOpen( + PhGetString(userAgentString), + WindowsVersion >= WINDOWS_8_1 ? WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY : WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, + WINHTTP_NO_PROXY_NAME, + WINHTTP_NO_PROXY_BYPASS, + 0 + ))) + { + //context->ErrorCode = GetLastError(); + goto CleanupExit; + } + + if (WindowsVersion >= WINDOWS_8_1) + { + ULONG httpFlags = WINHTTP_DECOMPRESSION_FLAG_GZIP | WINHTTP_DECOMPRESSION_FLAG_DEFLATE; + WinHttpSetOption(httpSessionHandle, WINHTTP_OPTION_DECOMPRESSION, &httpFlags, sizeof(ULONG)); + } + + if (!(httpConnectionHandle = WinHttpConnect( + httpSessionHandle, + PhGetString(downloadHostPath), + httpUrlComponents.nScheme == INTERNET_SCHEME_HTTP ? INTERNET_DEFAULT_HTTP_PORT : INTERNET_DEFAULT_HTTPS_PORT, + 0 + ))) + { + //context->ErrorCode = GetLastError(); + goto CleanupExit; + } + + if (!(httpRequestHandle = WinHttpOpenRequest( + httpConnectionHandle, + NULL, + PhGetString(downloadUrlPath), + NULL, + WINHTTP_NO_REFERER, + WINHTTP_DEFAULT_ACCEPT_TYPES, + WINHTTP_FLAG_REFRESH | (httpUrlComponents.nScheme == INTERNET_SCHEME_HTTPS ? WINHTTP_FLAG_SECURE : 0) + ))) + { + //context->ErrorCode = GetLastError(); + goto CleanupExit; + } + + if (WindowsVersion >= WINDOWS_7) + { + ULONG keepAlive = WINHTTP_DISABLE_KEEP_ALIVE; + WinHttpSetOption(httpRequestHandle, WINHTTP_OPTION_DISABLE_FEATURE, &keepAlive, sizeof(ULONG)); + } + + if (!WinHttpSendRequest( + httpRequestHandle, + WINHTTP_NO_ADDITIONAL_HEADERS, + 0, + WINHTTP_NO_REQUEST_DATA, + 0, + WINHTTP_IGNORE_REQUEST_TOTAL_LENGTH, + 0 + )) + { + // context->ErrorCode = GetLastError(); + goto CleanupExit; + } + + if (!WinHttpReceiveResponse(httpRequestHandle, NULL)) + { + //context->ErrorCode = GetLastError(); + goto CleanupExit; + } + else + { + ULONG bytesDownloaded = 0; + ULONG downloadedBytes = 0; + ULONG contentLengthSize = sizeof(ULONG); + ULONG contentLength = 0; + PPH_STRING status; + IO_STATUS_BLOCK isb; + BYTE buffer[PAGE_SIZE]; + + //SendMessage(context->DialogHandle, TDM_SET_MARQUEE_PROGRESS_BAR, FALSE, 0); + + PhQuerySystemTime(&timeStart); + + if (!WinHttpQueryHeaders( + httpRequestHandle, + WINHTTP_QUERY_CONTENT_LENGTH | WINHTTP_QUERY_FLAG_NUMBER, + WINHTTP_HEADER_NAME_BY_INDEX, + &contentLength, + &contentLengthSize, + 0 + )) + { + //context->ErrorCode = GetLastError(); + goto CleanupExit; + } + + memset(buffer, 0, PAGE_SIZE); + + while (WinHttpReadData(httpRequestHandle, buffer, PAGE_SIZE, &bytesDownloaded)) + { + if (bytesDownloaded == 0) + break; + + if (!NT_SUCCESS(NtWriteFile( + tempFileHandle, + NULL, + NULL, + NULL, + &isb, + buffer, + bytesDownloaded, + NULL, + NULL + ))) + { + goto CleanupExit; + } + + downloadedBytes += (ULONG)isb.Information; + + if (bytesDownloaded != isb.Information) + goto CleanupExit; + + PhQuerySystemTime(&timeNow); + + timeTicks = (timeNow.QuadPart - timeStart.QuadPart) / PH_TICKS_PER_SEC; + timeBitsPerSecond = downloadedBytes / __max(timeTicks, 1); + + { + FLOAT percent = ((FLOAT)downloadedBytes / contentLength * 100); + PPH_STRING totalLength = PhFormatSize(contentLength, -1); + PPH_STRING totalDownloaded = PhFormatSize(downloadedBytes, -1); + PPH_STRING totalSpeed = PhFormatSize(timeBitsPerSecond, -1); + PPH_STRING statusMessage = PhFormatString( + L"Downloaded: %s of %s (%.0f%%)", + PhGetStringOrEmpty(totalDownloaded), + PhGetStringOrEmpty(totalLength), + percent + ); + PPH_STRING subMessage = PhFormatString( + L"Speed: %s/s", + PhGetStringOrEmpty(totalSpeed) + ); + + SetWindowText(Context->StatusHandle, statusMessage->Buffer); + SetWindowText(Context->SubStatusHandle, subMessage->Buffer); + SendMessage(Context->ProgressHandle, PBM_SETPOS, (WPARAM)percent, 0); + + PhDereferenceObject(subMessage); + PhDereferenceObject(statusMessage); + PhDereferenceObject(totalSpeed); + PhDereferenceObject(totalLength); + PhDereferenceObject(totalDownloaded); + } + } + } + +CleanupExit: + + if (tempFileHandle) + NtClose(tempFileHandle); + + if (httpRequestHandle) + WinHttpCloseHandle(httpRequestHandle); + + if (httpConnectionHandle) + WinHttpCloseHandle(httpConnectionHandle); + + if (httpSessionHandle) + WinHttpCloseHandle(httpSessionHandle); + + PhClearReference(&randomGuidString); + PhClearReference(&fullSetupPath); + PhClearReference(&setupTempPath); + PhClearReference(&downloadHostPath); + PhClearReference(&downloadUrlPath); + PhClearReference(&userAgentString); + + //if (UpdateDialogThreadHandle) + //{ + // if (downloadSuccess && hashSuccess && signatureSuccess) + // { + // PostMessage(context->DialogHandle, PH_UPDATESUCCESS, 0, 0); + // } + // else if (downloadSuccess) + // { + // PostMessage(context->DialogHandle, PH_UPDATEFAILURE, signatureSuccess, hashSuccess); + // } + // else + // { + // PostMessage(context->DialogHandle, PH_UPDATEISERRORED, 0, 0); + // } + //} + + return STATUS_SUCCESS; +} diff --git a/tools/CustomSetupTool/CustomSetupTool/include/setup.h b/tools/CustomSetupTool/CustomSetupTool/include/setup.h index f703b2f2a180..c01ad508d6d5 100644 --- a/tools/CustomSetupTool/CustomSetupTool/include/setup.h +++ b/tools/CustomSetupTool/CustomSetupTool/include/setup.h @@ -40,9 +40,9 @@ #include #include -#include "resource.h" #include +#include "resource.h" #include "..\..\ProcessHacker\include\phappres.h" // Win32 PropertySheet Control IDs @@ -121,6 +121,13 @@ INT_PTR CALLBACK SetupPropPage4_WndProc( _Inout_ LPARAM lParam ); +INT_PTR CALLBACK SetupPropPage5_WndProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _Inout_ WPARAM wParam, + _Inout_ LPARAM lParam + ); + // page4.c typedef struct _SETUP_PROGRESS_THREAD @@ -176,6 +183,47 @@ VOID SetupUpgradeSettingsFile( VOID ); +// download.c + +typedef struct _PH_SETUP_UNINSTALL_CONTEXT +{ + HWND DialogHandle; + HWND MainHeaderHandle; + HWND StatusHandle; + HWND SubStatusHandle; + HWND ProgressHandle; + HICON IconSmallHandle; + HICON IconLargeHandle; + + ULONG CurrentMajorVersion; + ULONG CurrentMinorVersion; + ULONG CurrentRevisionVersion; + ULONG LatestMajorVersion; + ULONG LatestMinorVersion; + ULONG LatestRevisionVersion; + + ULONG ErrorCode; + PPH_STRING Version; + PPH_STRING RevVersion; + PPH_STRING RelDate; + PPH_STRING Size; + PPH_STRING Hash; + PPH_STRING Signature; + PPH_STRING ReleaseNotesUrl; + + PPH_STRING BinFileDownloadUrl; + PPH_STRING SetupFileDownloadUrl; + PPH_STRING SetupFilePath; +} PH_SETUP_UNINSTALL_CONTEXT, *PPH_SETUP_UNINSTALL_CONTEXT; + +BOOLEAN SetupQueryUpdateData( + _In_ PPH_SETUP_UNINSTALL_CONTEXT Context + ); + +BOOLEAN UpdateDownloadUpdateData( + _In_ PPH_SETUP_UNINSTALL_CONTEXT Context + ); + // extract.c BOOLEAN SetupExtractBuild( diff --git a/tools/CustomSetupTool/CustomSetupTool/json-c/AUTHORS b/tools/CustomSetupTool/CustomSetupTool/json-c/AUTHORS new file mode 100644 index 000000000000..b389989c452b --- /dev/null +++ b/tools/CustomSetupTool/CustomSetupTool/json-c/AUTHORS @@ -0,0 +1,5 @@ +Michael Clark +Jehiah Czebotar +Eric Haszlakiewicz +C. Watford (christopher.watford@gmail.com) + diff --git a/tools/CustomSetupTool/CustomSetupTool/json-c/COPYING b/tools/CustomSetupTool/CustomSetupTool/json-c/COPYING new file mode 100644 index 000000000000..740d1258d425 --- /dev/null +++ b/tools/CustomSetupTool/CustomSetupTool/json-c/COPYING @@ -0,0 +1,42 @@ + +Copyright (c) 2009-2012 Eric Haszlakiewicz + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +---------------------------------------------------------------- + +Copyright (c) 2004, 2005 Metaparadigm Pte Ltd + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/tools/CustomSetupTool/CustomSetupTool/json-c/ChangeLog b/tools/CustomSetupTool/CustomSetupTool/json-c/ChangeLog new file mode 100644 index 000000000000..451b8f68403a --- /dev/null +++ b/tools/CustomSetupTool/CustomSetupTool/json-c/ChangeLog @@ -0,0 +1,214 @@ + +0.12 + + * Address security issues: + * CVE-2013-6371: hash collision denial of service + * CVE-2013-6370: buffer overflow if size_t is larger than int + + * Avoid potential overflow in json_object_get_double + + * Eliminate the mc_abort() function and MC_ABORT macro. + + * Make the json_tokener_errors array local. It has been deprecated for + a while, and json_tokener_error_desc() should be used instead. + + * change the floating point output format to %.17g so values with + more than 6 digits show up in the output. + + * Remove the old libjson.so name compatibility support. The library is + only created as libjson-c.so now and headers are only installed + into the ${prefix}/json-c directory. + + * When supported by the linker, add the -Bsymbolic-functions flag. + + * Various changes to fix the build on MSVC. + + * Make strict mode more strict: + * number must not start with 0 + * no single-quote strings + * no comments + * trailing char not allowed + * only allow lowercase literals + + * Added a json_object_new_double_s() convenience function to allow + an exact string representation of a double to be specified when + creating the object and use it in json_tokener_parse_ex() so + a re-serialized object more exactly matches the input. + + * Add support NaN and Infinity + + +0.11 + + * IMPORTANT: the name of the library has changed to libjson-c.so and + the header files are now in include/json-c. + The pkgconfig name has also changed from json to json-c. + You should change your build to use appropriate -I and -l options. + A compatibility shim is in place so builds using the old name will + continue to work, but that will be removed in the next release. + * Maximum recursion depth is now a runtime option. + json_tokener_new() is provided for compatibility. + json_tokener_new_ex(depth) + * Include json_object_iterator.h in the installed headers. + * Add support for building on Android. + * Rewrite json_object_object_add to replace just the value if the key already exists so keys remain valid. + * Make it safe to delete keys while iterating with the json_object_object_foreach macro. + * Add a json_set_serializer() function to allow the string output of a json_object to be customized. + * Make float parsing locale independent. + * Add a json_tokener_set_flags() function and a JSON_TOKENER_STRICT flag. + * Enable -Werror when building. + * speed improvements to parsing 64-bit integers on systems with working sscanf + * Add a json_object_object_length function. + * Fix a bug (buffer overrun) when expanding arrays to more than 64 entries. + +0.10 + + * Add a json_object_to_json_string_ext() function to allow output to be + formatted in a more human readable form. + * Add json_object_object_get_ex(), a NULL-safe get object method, to be able + to distinguish between a key not present and the value being NULL. + * Add an alternative iterator implementation, see json_object_iterator.h + * Make json_object_iter public to enable external use of the + json_object_object_foreachC macro. + * Add a printbuf_memset() function to provide an effecient way to set and + append things like whitespace indentation. + * Adjust json_object_is_type and json_object_get_type so they return + json_type_null for NULL objects and handle NULL passed to + json_objct_object_get(). + * Rename boolean type to json_bool. + * Fix various compile issues for Visual Studio and MinGW. + * Allow json_tokener_parse_ex() to be re-used to parse multiple object. + Also, fix some parsing issues with capitalized hexadecimal numbers and + number in E notation. + * Add json_tokener_get_error() and json_tokener_error_desc() to better + encapsulate the process of retrieving errors while parsing. + * Various improvements to the documentation of many functions. + * Add new json_object_array_sort() function. + * Fix a bug in json_object_get_int(), which would incorrectly return 0 + when called on a string type object. + Eric Haszlakiewicz + * Add a json_type_to_name() function. + Eric Haszlakiewicz + * Add a json_tokener_parse_verbose() function. + Jehiah Czebotar + * Improve support for null bytes within JSON strings. + Jehiah Czebotar + * Fix file descriptor leak if memory allocation fails in json_util + Zachary Blair, zack_blair at hotmail dot com + * Add int64 support. Two new functions json_object_net_int64 and + json_object_get_int64. Binary compatibility preserved. + Eric Haszlakiewicz, EHASZLA at transunion com + Rui Miguel Silva Seabra, rms at 1407 dot org + * Fix subtle bug in linkhash where lookup could hang after all slots + were filled then successively freed. + Spotted by Jean-Marc Naud, j dash m at newtraxtech dot com + * Make json_object_from_file take const char *filename + Spotted by Vikram Raj V, vsagar at attinteractive dot com + * Add handling of surrogate pairs (json_tokener.c, test4.c, Makefile.am) + Brent Miller, bdmiller at yahoo dash inc dot com + * Correction to comment describing printbuf_memappend in printbuf.h + Brent Miller, bdmiller at yahoo dash inc dot com + +0.9 + * Add README.html README-WIN32.html config.h.win32 to Makefile.am + Michael Clark, + * Add const qualifier to the json_tokener_parse functions + Eric Haszlakiewicz, EHASZLA at transunion dot com + * Rename min and max so we can never clash with C or C++ std library + Ian Atha, thatha at yahoo dash inc dot com + * Fix any noticeable spelling or grammar errors. + * Make sure every va_start has a va_end. + * Check all pointers for validity. + Erik Hovland, erik at hovland dot org + * Fix json_object_get_boolean to return false for empty string + Spotted by Vitaly Kruglikov, Vitaly dot Kruglikov at palm dot com + * optimizations to json_tokener_parse_ex(), printbuf_memappend() + Brent Miller, bdmiller at yahoo dash inc dot com + * Disable REFCOUNT_DEBUG by default in json_object.c + * Don't use this as a variable, so we can compile with a C++ compiler + * Add casts from void* to type of assignment when using malloc + * Add #ifdef __cplusplus guards to all of the headers + * Add typedefs for json_object, json_tokener, array_list, printbuf, lh_table + Michael Clark, + * Null pointer dereference fix. Fix json_object_get_boolean strlen test + to not return TRUE for zero length string. Remove redundant includes. + Erik Hovland, erik at hovland dot org + * Fixed warning reported by adding -Wstrict-prototypes + -Wold-style-definition to the compilatin flags. + Dotan Barak, dotanba at gmail dot com + * Add const correctness to public interfaces + Gerard Krol, g dot c dot krol at student dot tudelft dot nl + +0.8 + * Add va_end for every va_start + Dotan Barak, dotanba at gmail dot com + * Add macros to enable compiling out debug code + Geoffrey Young, geoff at modperlcookbook dot org + * Fix bug with use of capital E in numbers with exponents + Mateusz Loskot, mateusz at loskot dot net + * Add stddef.h include + * Patch allows for json-c compile with -Werror and not fail due to + -Wmissing-prototypes -Wstrict-prototypes -Wmissing-declarations + Geoffrey Young, geoff at modperlcookbook dot org + +0.7 + * Add escaping of backslash to json output + * Add escaping of foward slash on tokenizing and output + * Changes to internal tokenizer from using recursion to + using a depth state structure to allow incremental parsing + +0.6 + * Fix bug in escaping of control characters + Johan Bj�rklund, johbjo09 at kth dot se + * Remove include "config.h" from headers (should only + be included from .c files) + Michael Clark + +0.5 + * Make headers C++ compatible by change *this to *obj + * Add ifdef C++ extern "C" to headers + * Use simpler definition of min and max in bits.h + Larry Lansing, llansing at fuzzynerd dot com + + * Remove automake 1.6 requirement + * Move autogen commands into autogen.sh. Update README + * Remove error pointer special case for Windows + * Change license from LGPL to MIT + Michael Clark + +0.4 + * Fix additional error case in object parsing + * Add back sign reversal in nested object parse as error pointer + value is negative, while error value is positive. + Michael Clark + +0.3 + * fix pointer arithmetic bug for error pointer check in is_error() macro + * fix type passed to printbuf_memappend in json_tokener + * update autotools bootstrap instructions in README + Michael Clark + +0.2 + * printbuf.c - C. Watford (christopher.watford@gmail.com) + Added a Win32/Win64 compliant implementation of vasprintf + * debug.c - C. Watford (christopher.watford@gmail.com) + Removed usage of vsyslog on Win32/Win64 systems, needs to be handled + by a configure script + * json_object.c - C. Watford (christopher.watford@gmail.com) + Added scope operator to wrap usage of json_object_object_foreach, this + needs to be rethought to be more ANSI C friendly + * json_object.h - C. Watford (christopher.watford@gmail.com) + Added Microsoft C friendly version of json_object_object_foreach + * json_tokener.c - C. Watford (christopher.watford@gmail.com) + Added a Win32/Win64 compliant implementation of strndup + * json_util.c - C. Watford (christopher.watford@gmail.com) + Added cast and mask to suffice size_t v. unsigned int conversion + correctness + * json_tokener.c - sign reversal issue on error info for nested object parse + spotted by Johan Bj�rklund (johbjo09 at kth.se) + * json_object.c - escape " in json_escape_str + * Change to automake and libtool to build shared and static library + Michael Clark + +0.1 + * initial release diff --git a/tools/CustomSetupTool/CustomSetupTool/json-c/arraylist.c b/tools/CustomSetupTool/CustomSetupTool/json-c/arraylist.c new file mode 100644 index 000000000000..97f2c921711b --- /dev/null +++ b/tools/CustomSetupTool/CustomSetupTool/json-c/arraylist.c @@ -0,0 +1,101 @@ +/* + * $Id: arraylist.c,v 1.4 2006/01/26 02:16:28 mclark Exp $ + * + * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. + * Michael Clark + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See COPYING for details. + * + */ + +#include "config.h" + +#ifdef STDC_HEADERS +# include +# include +#endif /* STDC_HEADERS */ + +#if defined(HAVE_STRINGS_H) && !defined(_STRING_H) && !defined(__USE_BSD) +# include +#endif /* HAVE_STRINGS_H */ + +#include "bits.h" +#include "arraylist.h" + +struct array_list* +array_list_new(array_list_free_fn *free_fn) +{ + struct array_list *arr; + + arr = (struct array_list*)calloc(1, sizeof(struct array_list)); + if(!arr) return NULL; + arr->size = ARRAY_LIST_DEFAULT_SIZE; + arr->length = 0; + arr->free_fn = free_fn; + if(!(arr->array = (void**)calloc(sizeof(void*), arr->size))) { + free(arr); + return NULL; + } + return arr; +} + +extern void +array_list_free(struct array_list *arr) +{ + int i; + for(i = 0; i < arr->length; i++) + if(arr->array[i]) arr->free_fn(arr->array[i]); + free(arr->array); + free(arr); +} + +void* +array_list_get_idx(struct array_list *arr, int i) +{ + if(i >= arr->length) return NULL; + return arr->array[i]; +} + +static int array_list_expand_internal(struct array_list *arr, int max) +{ + void *t; + int new_size; + + if(max < arr->size) return 0; + new_size = json_max(arr->size << 1, max); + if(!(t = realloc(arr->array, new_size*sizeof(void*)))) return -1; + arr->array = (void**)t; + (void)memset(arr->array + arr->size, 0, (new_size-arr->size)*sizeof(void*)); + arr->size = new_size; + return 0; +} + +int +array_list_put_idx(struct array_list *arr, int idx, void *data) +{ + if(array_list_expand_internal(arr, idx+1)) return -1; + if(arr->array[idx]) arr->free_fn(arr->array[idx]); + arr->array[idx] = data; + if(arr->length <= idx) arr->length = idx + 1; + return 0; +} + +int +array_list_add(struct array_list *arr, void *data) +{ + return array_list_put_idx(arr, arr->length, data); +} + +void +array_list_sort(struct array_list *arr, int(__cdecl* sort_fn)(const void *, const void *)) +{ + qsort(arr->array, arr->length, sizeof(arr->array[0]), + (int (__cdecl*)(const void *, const void *))sort_fn); +} + +int +array_list_length(struct array_list *arr) +{ + return arr->length; +} diff --git a/tools/CustomSetupTool/CustomSetupTool/json-c/arraylist.h b/tools/CustomSetupTool/CustomSetupTool/json-c/arraylist.h new file mode 100644 index 000000000000..089be0bd7215 --- /dev/null +++ b/tools/CustomSetupTool/CustomSetupTool/json-c/arraylist.h @@ -0,0 +1,56 @@ +/* + * $Id: arraylist.h,v 1.4 2006/01/26 02:16:28 mclark Exp $ + * + * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. + * Michael Clark + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See COPYING for details. + * + */ + +#ifndef _arraylist_h_ +#define _arraylist_h_ + +#ifdef __cplusplus +extern "C" { +#endif + +#define ARRAY_LIST_DEFAULT_SIZE 32 + +typedef void (array_list_free_fn) (void *data); + +struct array_list +{ + void **array; + int length; + int size; + array_list_free_fn *free_fn; +}; + +extern struct array_list* +array_list_new(array_list_free_fn *free_fn); + +extern void +array_list_free(struct array_list *al); + +extern void* +array_list_get_idx(struct array_list *al, int i); + +extern int +array_list_put_idx(struct array_list *al, int i, void *data); + +extern int +array_list_add(struct array_list *al, void *data); + +extern int +array_list_length(struct array_list *al); + +extern void +array_list_sort(struct array_list *arr, int(__cdecl* compar)(const void *, const void *)); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/tools/CustomSetupTool/CustomSetupTool/json-c/bits.h b/tools/CustomSetupTool/CustomSetupTool/json-c/bits.h new file mode 100644 index 000000000000..c8cbbc820d5b --- /dev/null +++ b/tools/CustomSetupTool/CustomSetupTool/json-c/bits.h @@ -0,0 +1,28 @@ +/* + * $Id: bits.h,v 1.10 2006/01/30 23:07:57 mclark Exp $ + * + * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. + * Michael Clark + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See COPYING for details. + * + */ + +#ifndef _bits_h_ +#define _bits_h_ + +#ifndef json_min +#define json_min(a,b) ((a) < (b) ? (a) : (b)) +#endif + +#ifndef json_max +#define json_max(a,b) ((a) > (b) ? (a) : (b)) +#endif + +#define hexdigit(x) (((x) <= '9') ? (x) - '0' : ((x) & 7) + 9) +#define error_ptr(error) ((void*)error) +#define error_description(error) (json_tokener_errors[error]) +#define is_error(ptr) (ptr == NULL) + +#endif diff --git a/tools/CustomSetupTool/CustomSetupTool/json-c/config.h b/tools/CustomSetupTool/CustomSetupTool/json-c/config.h new file mode 100644 index 000000000000..df46f0a481a7 --- /dev/null +++ b/tools/CustomSetupTool/CustomSetupTool/json-c/config.h @@ -0,0 +1,89 @@ +#define PACKAGE_STRING "JSON C Library 0.12-20140410" +#define PACKAGE_BUGREPORT "json-c@googlegroups.com" +#define PACKAGE_NAME "JSON C Library" +#define PACKAGE_TARNAME "json-c" +#define PACKAGE_VERSION "0.12-20140410" + + +#define HAVE_SETLOCALE 1 +#define HAVE_LOCALE_H 1 + +#define HAVE_DECL_NAN 1 +#define HAVE_DECL_INFINITY 1 +//#define HAVE_DECL__ISNAN 1 +//#define HAVE_DECL__FINITE 1 + +/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */ +/* #undef HAVE_DOPRNT */ + +/* Define to 1 if you have the header file. */ +#define HAVE_FCNTL_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_LIMITS_H 1 + +/* Define to 1 if your system has a GNU libc compatible `malloc' function, and + to 0 otherwise. */ +#define HAVE_MALLOC 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the `open' function. */ +#define HAVE_OPEN 1 + +/* Define to 1 if your system has a GNU libc compatible `realloc' function, + and to 0 otherwise. */ +#define HAVE_REALLOC 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the `strdup' function. */ +#define HAVE_STRNDUP 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDARG_H 1 + +/* Define to 1 if you have the `strerror' function. */ +#define HAVE_STRERROR 1 + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYSLOG_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_PARAM_H + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +#undef HAVE_UNISTD_H + +/* Define to 1 if you have the `vprintf' function. */ +#undef HAVE_VPRINTF + +/* Define to 1 if you have the `vsyslog' function. */ +#undef HAVE_VSYSLOG + +/* Define to 1 if you have the `strncasecmp' function. */ +#undef HAVE_STRNCASECMP + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + diff --git a/tools/CustomSetupTool/CustomSetupTool/json-c/config.h.in b/tools/CustomSetupTool/CustomSetupTool/json-c/config.h.in new file mode 100644 index 000000000000..0dcab1a30015 --- /dev/null +++ b/tools/CustomSetupTool/CustomSetupTool/json-c/config.h.in @@ -0,0 +1,174 @@ +/* config.h.in. Generated from configure.ac by autoheader. */ + +/* Enable RDRANR Hardware RNG Hash Seed */ +#undef ENABLE_RDRAND + +/* Define if .gnu.warning accepts long strings. */ +#undef HAS_GNU_WARNING_LONG + +/* Define to 1 if you have the declaration of `INFINITY', and to 0 if you + don't. */ +#undef HAVE_DECL_INFINITY + +/* Define to 1 if you have the declaration of `isinf', and to 0 if you don't. + */ +#undef HAVE_DECL_ISINF + +/* Define to 1 if you have the declaration of `isnan', and to 0 if you don't. + */ +#undef HAVE_DECL_ISNAN + +/* Define to 1 if you have the declaration of `nan', and to 0 if you don't. */ +#undef HAVE_DECL_NAN + +/* Define to 1 if you have the declaration of `_finite', and to 0 if you + don't. */ +#undef HAVE_DECL__FINITE + +/* Define to 1 if you have the declaration of `_isnan', and to 0 if you don't. + */ +#undef HAVE_DECL__ISNAN + +/* Define to 1 if you have the header file. */ +#undef HAVE_DLFCN_H + +/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */ +#undef HAVE_DOPRNT + +/* Define to 1 if you have the header file. */ +#undef HAVE_ENDIAN_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_FCNTL_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_INTTYPES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_LIMITS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_LOCALE_H + +/* Define to 1 if your system has a GNU libc compatible `malloc' function, and + to 0 otherwise. */ +#undef HAVE_MALLOC + +/* Define to 1 if you have the header file. */ +#undef HAVE_MEMORY_H + +/* Define to 1 if you have the `open' function. */ +#undef HAVE_OPEN + +/* Define to 1 if your system has a GNU libc compatible `realloc' function, + and to 0 otherwise. */ +#undef HAVE_REALLOC + +/* Define to 1 if you have the `setlocale' function. */ +#undef HAVE_SETLOCALE + +/* Define to 1 if you have the `snprintf' function. */ +#undef HAVE_SNPRINTF + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDARG_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDLIB_H + +/* Define to 1 if you have the `strcasecmp' function. */ +#undef HAVE_STRCASECMP + +/* Define to 1 if you have the `strdup' function. */ +#undef HAVE_STRDUP + +/* Define to 1 if you have the `strerror' function. */ +#undef HAVE_STRERROR + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRING_H + +/* Define to 1 if you have the `strncasecmp' function. */ +#undef HAVE_STRNCASECMP + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYSLOG_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_CDEFS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_PARAM_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_UNISTD_H + +/* Define to 1 if you have the `vasprintf' function. */ +#undef HAVE_VASPRINTF + +/* Define to 1 if you have the `vprintf' function. */ +#undef HAVE_VPRINTF + +/* Define to 1 if you have the `vsnprintf' function. */ +#undef HAVE_VSNPRINTF + +/* Define to 1 if you have the `vsyslog' function. */ +#undef HAVE_VSYSLOG + +/* Public define for json_inttypes.h */ +#undef JSON_C_HAVE_INTTYPES_H + +/* Define to the sub-directory in which libtool stores uninstalled libraries. + */ +#undef LT_OBJDIR + +/* Name of package */ +#undef PACKAGE + +/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#undef PACKAGE_NAME + +/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the home page for this package. */ +#undef PACKAGE_URL + +/* Define to the version of this package. */ +#undef PACKAGE_VERSION + +/* Define to 1 if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Version number of package */ +#undef VERSION + +/* Define to empty if `const' does not conform to ANSI C. */ +#undef const + +/* Define to rpl_malloc if the replacement function should be used. */ +#undef malloc + +/* Define to rpl_realloc if the replacement function should be used. */ +#undef realloc + +/* Define to `unsigned int' if does not define. */ +#undef size_t diff --git a/tools/CustomSetupTool/CustomSetupTool/json-c/debug.c b/tools/CustomSetupTool/CustomSetupTool/json-c/debug.c new file mode 100644 index 000000000000..9dff7818bf86 --- /dev/null +++ b/tools/CustomSetupTool/CustomSetupTool/json-c/debug.c @@ -0,0 +1,83 @@ +/* + * $Id: debug.c,v 1.5 2006/01/26 02:16:28 mclark Exp $ + * + * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. + * Michael Clark + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See COPYING for details. + * + */ + +#include "config.h" + +#include +#include +#include +#include + +#if HAVE_SYSLOG_H +# include +#endif /* HAVE_SYSLOG_H */ + +#if HAVE_UNISTD_H +# include +#endif /* HAVE_UNISTD_H */ + +#if HAVE_SYS_PARAM_H +#include +#endif /* HAVE_SYS_PARAM_H */ + +#include "debug.h" + +static int _syslog = 0; +static int _debug = 0; + +void mc_set_debug(int debug) { _debug = debug; } +int mc_get_debug(void) { return _debug; } + +extern void mc_set_syslog(int syslog) +{ + _syslog = syslog; +} + +void mc_debug(const char *msg, ...) +{ + va_list ap; + if(_debug) { + va_start(ap, msg); +#if HAVE_VSYSLOG + if(_syslog) { + vsyslog(LOG_DEBUG, msg, ap); + } else +#endif + vprintf(msg, ap); + va_end(ap); + } +} + +void mc_error(const char *msg, ...) +{ + va_list ap; + va_start(ap, msg); +#if HAVE_VSYSLOG + if(_syslog) { + vsyslog(LOG_ERR, msg, ap); + } else +#endif + vfprintf(stderr, msg, ap); + va_end(ap); +} + +void mc_info(const char *msg, ...) +{ + va_list ap; + va_start(ap, msg); +#if HAVE_VSYSLOG + if(_syslog) { + vsyslog(LOG_INFO, msg, ap); + } else +#endif + vfprintf(stderr, msg, ap); + va_end(ap); +} diff --git a/tools/CustomSetupTool/CustomSetupTool/json-c/debug.h b/tools/CustomSetupTool/CustomSetupTool/json-c/debug.h new file mode 100644 index 000000000000..80ca3e43042e --- /dev/null +++ b/tools/CustomSetupTool/CustomSetupTool/json-c/debug.h @@ -0,0 +1,71 @@ +/* + * $Id: debug.h,v 1.5 2006/01/30 23:07:57 mclark Exp $ + * + * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. + * Michael Clark + * Copyright (c) 2009 Hewlett-Packard Development Company, L.P. + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See COPYING for details. + * + */ + +#ifndef _DEBUG_H_ +#define _DEBUG_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern void mc_set_debug(int debug); +extern int mc_get_debug(void); + +extern void mc_set_syslog(int syslog); + +extern void mc_debug(const char *msg, ...); +extern void mc_error(const char *msg, ...); +extern void mc_info(const char *msg, ...); + +#ifndef __STRING +#define __STRING(x) #x +#endif + +#ifndef PARSER_BROKEN_FIXED + +#define JASSERT(cond) do {} while(0) + +#else + +#define JASSERT(cond) do { \ + if (!(cond)) { \ + mc_error("cjson assert failure %s:%d : cond \"" __STRING(cond) "failed\n", __FILE__, __LINE__); \ + *(int *)0 = 1;\ + abort(); \ + }\ + } while(0) + +#endif + +#define MC_ERROR(x, ...) mc_error(x, ##__VA_ARGS__) + +#ifdef MC_MAINTAINER_MODE +#define MC_SET_DEBUG(x) mc_set_debug(x) +#define MC_GET_DEBUG() mc_get_debug() +#define MC_SET_SYSLOG(x) mc_set_syslog(x) +#define MC_DEBUG(x, ...) mc_debug(x, ##__VA_ARGS__) +#define MC_INFO(x, ...) mc_info(x, ##__VA_ARGS__) +#else +#define MC_SET_DEBUG(x) if (0) mc_set_debug(x) +#define MC_GET_DEBUG() (0) +#define MC_SET_SYSLOG(x) if (0) mc_set_syslog(x) +#define MC_DEBUG(x, ...) if (0) mc_debug(x, ##__VA_ARGS__) +#define MC_INFO(x, ...) if (0) mc_info(x, ##__VA_ARGS__) +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/tools/CustomSetupTool/CustomSetupTool/json-c/json.h b/tools/CustomSetupTool/CustomSetupTool/json-c/json.h new file mode 100644 index 000000000000..4339b20e9060 --- /dev/null +++ b/tools/CustomSetupTool/CustomSetupTool/json-c/json.h @@ -0,0 +1,34 @@ +/* + * $Id: json.h,v 1.6 2006/01/26 02:16:28 mclark Exp $ + * + * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. + * Michael Clark + * Copyright (c) 2009 Hewlett-Packard Development Company, L.P. + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See COPYING for details. + * + */ + +#ifndef _json_h_ +#define _json_h_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "bits.h" +#include "debug.h" +#include "linkhash.h" +#include "arraylist.h" +#include "json_util.h" +#include "json_object.h" +#include "json_tokener.h" +#include "json_object_iterator.h" +#include "json_c_version.h" + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/tools/CustomSetupTool/CustomSetupTool/json-c/json_c_version.c b/tools/CustomSetupTool/CustomSetupTool/json-c/json_c_version.c new file mode 100644 index 000000000000..13eb18855423 --- /dev/null +++ b/tools/CustomSetupTool/CustomSetupTool/json-c/json_c_version.c @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2012 Eric Haszlakiewicz + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See COPYING for details. + */ +#include "config.h" + +#include "json_c_version.h" + +const char *json_c_version(void) +{ + return JSON_C_VERSION; +} + +int json_c_version_num(void) +{ + return JSON_C_VERSION_NUM; +} + diff --git a/tools/CustomSetupTool/CustomSetupTool/json-c/json_c_version.h b/tools/CustomSetupTool/CustomSetupTool/json-c/json_c_version.h new file mode 100644 index 000000000000..eed98a497501 --- /dev/null +++ b/tools/CustomSetupTool/CustomSetupTool/json-c/json_c_version.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2012 Eric Haszlakiewicz + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See COPYING for details. + */ + +#ifndef _json_c_version_h_ +#define _json_c_version_h_ + +#define JSON_C_MAJOR_VERSION 0 +#define JSON_C_MINOR_VERSION 12 +#define JSON_C_MICRO_VERSION 0 +#define JSON_C_VERSION_NUM ((JSON_C_MAJOR_VERSION << 16) | \ + (JSON_C_MINOR_VERSION << 8) | \ + JSON_C_MICRO_VERSION) +#define JSON_C_VERSION "0.12" + +const char *json_c_version(void); /* Returns JSON_C_VERSION */ +int json_c_version_num(void); /* Returns JSON_C_VERSION_NUM */ + +#endif diff --git a/tools/CustomSetupTool/CustomSetupTool/json-c/json_config.h b/tools/CustomSetupTool/CustomSetupTool/json-c/json_config.h new file mode 100644 index 000000000000..405fda20dc5b --- /dev/null +++ b/tools/CustomSetupTool/CustomSetupTool/json-c/json_config.h @@ -0,0 +1,3 @@ + +/* Define to 1 if you have the header file. */ +#define JSON_C_HAVE_INTTYPES_H 1 diff --git a/tools/CustomSetupTool/CustomSetupTool/json-c/json_inttypes.h b/tools/CustomSetupTool/CustomSetupTool/json-c/json_inttypes.h new file mode 100644 index 000000000000..9de8d246d9dd --- /dev/null +++ b/tools/CustomSetupTool/CustomSetupTool/json-c/json_inttypes.h @@ -0,0 +1,28 @@ + +#ifndef _json_inttypes_h_ +#define _json_inttypes_h_ + +#include "json_config.h" + +#if defined(_MSC_VER) && _MSC_VER <= 1700 + +/* Anything less than Visual Studio C++ 10 is missing stdint.h and inttypes.h */ +typedef __int32 int32_t; +#define INT32_MIN ((int32_t)_I32_MIN) +#define INT32_MAX ((int32_t)_I32_MAX) +typedef __int64 int64_t; +#define INT64_MIN ((int64_t)_I64_MIN) +#define INT64_MAX ((int64_t)_I64_MAX) +#define PRId64 "I64d" +#define SCNd64 "I64d" + +#else + +#ifdef JSON_C_HAVE_INTTYPES_H +#include +#endif +/* inttypes.h includes stdint.h */ + +#endif + +#endif diff --git a/tools/CustomSetupTool/CustomSetupTool/json-c/json_object.c b/tools/CustomSetupTool/CustomSetupTool/json-c/json_object.c new file mode 100644 index 000000000000..57f3f0d237d5 --- /dev/null +++ b/tools/CustomSetupTool/CustomSetupTool/json-c/json_object.c @@ -0,0 +1,860 @@ +/* + * $Id: json_object.c,v 1.17 2006/07/25 03:24:50 mclark Exp $ + * + * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. + * Michael Clark + * Copyright (c) 2009 Hewlett-Packard Development Company, L.P. + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See COPYING for details. + * + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include + +#include "debug.h" +#include "printbuf.h" +#include "linkhash.h" +#include "arraylist.h" +#include "json_inttypes.h" +#include "json_object.h" +#include "json_object_private.h" +#include "json_util.h" +#include "math_compat.h" + +#if !defined(HAVE_STRDUP) && defined(_MSC_VER) + /* MSC has the version as _strdup */ +# define strdup _strdup +#elif !defined(HAVE_STRDUP) +# error You do not have strdup on your system. +#endif /* HAVE_STRDUP */ + +#if !defined(HAVE_SNPRINTF) && defined(_MSC_VER) + /* MSC has the version as _snprintf */ +# define snprintf _snprintf +#elif !defined(HAVE_SNPRINTF) +# error You do not have snprintf on your system. +#endif /* HAVE_SNPRINTF */ + +// Don't define this. It's not thread-safe. +/* #define REFCOUNT_DEBUG 1 */ + +const char *json_number_chars = "0123456789.+-eE"; +const char *json_hex_chars = "0123456789abcdefABCDEF"; + +static void json_object_generic_delete(struct json_object* jso); +static struct json_object* json_object_new(enum json_type o_type); + +static json_object_to_json_string_fn json_object_object_to_json_string; +static json_object_to_json_string_fn json_object_boolean_to_json_string; +static json_object_to_json_string_fn json_object_int_to_json_string; +static json_object_to_json_string_fn json_object_double_to_json_string; +static json_object_to_json_string_fn json_object_string_to_json_string; +static json_object_to_json_string_fn json_object_array_to_json_string; + + +/* ref count debugging */ + +#ifdef REFCOUNT_DEBUG + +static struct lh_table *json_object_table; + +static void json_object_init(void) __attribute__ ((constructor)); +static void json_object_init(void) { + MC_DEBUG("json_object_init: creating object table\n"); + json_object_table = lh_kptr_table_new(128, "json_object_table", NULL); +} + +static void json_object_fini(void) __attribute__ ((destructor)); +static void json_object_fini(void) { + struct lh_entry *ent; + if(MC_GET_DEBUG()) { + if (json_object_table->count) { + MC_DEBUG("json_object_fini: %d referenced objects at exit\n", + json_object_table->count); + lh_foreach(json_object_table, ent) { + struct json_object* obj = (struct json_object*)ent->v; + MC_DEBUG("\t%s:%p\n", json_type_to_name(obj->o_type), obj); + } + } + } + MC_DEBUG("json_object_fini: freeing object table\n"); + lh_table_free(json_object_table); +} +#endif /* REFCOUNT_DEBUG */ + + +/* string escaping */ + +static int json_escape_str(struct printbuf *pb, char *str, size_t len) +{ + int pos = 0, start_offset = 0; + unsigned char c; + while (len--) { + c = str[pos]; + switch(c) { + case '\b': + case '\n': + case '\r': + case '\t': + case '\f': + case '"': + case '\\': + case '/': + if(pos - start_offset > 0) + printbuf_memappend(pb, str + start_offset, pos - start_offset); + if(c == '\b') printbuf_memappend(pb, "\\b", 2); + else if(c == '\n') printbuf_memappend(pb, "\\n", 2); + else if(c == '\r') printbuf_memappend(pb, "\\r", 2); + else if(c == '\t') printbuf_memappend(pb, "\\t", 2); + else if(c == '\f') printbuf_memappend(pb, "\\f", 2); + else if(c == '"') printbuf_memappend(pb, "\\\"", 2); + else if(c == '\\') printbuf_memappend(pb, "\\\\", 2); + else if(c == '/') printbuf_memappend(pb, "\\/", 2); + start_offset = ++pos; + break; + default: + if(c < ' ') { + if(pos - start_offset > 0) + printbuf_memappend(pb, str + start_offset, pos - start_offset); + sprintbuf(pb, "\\u00%c%c", + json_hex_chars[c >> 4], + json_hex_chars[c & 0xf]); + start_offset = ++pos; + } else pos++; + } + } + if(pos - start_offset > 0) + printbuf_memappend(pb, str + start_offset, pos - start_offset); + return 0; +} + + +/* reference counting */ + +extern struct json_object* json_object_get(struct json_object *jso) +{ + if(jso) { + jso->_ref_count++; + } + return jso; +} + +int json_object_put(struct json_object *jso) +{ + if(jso) + { + jso->_ref_count--; + if(!jso->_ref_count) + { + if (jso->_user_delete) + jso->_user_delete(jso, jso->_userdata); + jso->_delete(jso); + return 1; + } + } + return 0; +} + + +/* generic object construction and destruction parts */ + +static void json_object_generic_delete(struct json_object* jso) +{ +#ifdef REFCOUNT_DEBUG + MC_DEBUG("json_object_delete_%s: %p\n", + json_type_to_name(jso->o_type), jso); + lh_table_delete(json_object_table, jso); +#endif /* REFCOUNT_DEBUG */ + printbuf_free(jso->_pb); + free(jso); +} + +static struct json_object* json_object_new(enum json_type o_type) +{ + struct json_object *jso; + + jso = (struct json_object*)calloc(sizeof(struct json_object), 1); + if(!jso) return NULL; + jso->o_type = o_type; + jso->_ref_count = 1; + jso->_delete = &json_object_generic_delete; +#ifdef REFCOUNT_DEBUG + lh_table_insert(json_object_table, jso, jso); + MC_DEBUG("json_object_new_%s: %p\n", json_type_to_name(jso->o_type), jso); +#endif /* REFCOUNT_DEBUG */ + return jso; +} + + +/* type checking functions */ + +int json_object_is_type(struct json_object *jso, enum json_type type) +{ + if (!jso) + return (type == json_type_null); + return (jso->o_type == type); +} + +enum json_type json_object_get_type(struct json_object *jso) +{ + if (!jso) + return json_type_null; + return jso->o_type; +} + +/* set a custom conversion to string */ + +void json_object_set_serializer(json_object *jso, + json_object_to_json_string_fn to_string_func, + void *userdata, + json_object_delete_fn *user_delete) +{ + // First, clean up any previously existing user info + if (jso->_user_delete) + { + jso->_user_delete(jso, jso->_userdata); + } + jso->_userdata = NULL; + jso->_user_delete = NULL; + + if (to_string_func == NULL) + { + // Reset to the standard serialization function + switch(jso->o_type) + { + case json_type_null: + jso->_to_json_string = NULL; + break; + case json_type_boolean: + jso->_to_json_string = &json_object_boolean_to_json_string; + break; + case json_type_double: + jso->_to_json_string = &json_object_double_to_json_string; + break; + case json_type_int: + jso->_to_json_string = &json_object_int_to_json_string; + break; + case json_type_object: + jso->_to_json_string = &json_object_object_to_json_string; + break; + case json_type_array: + jso->_to_json_string = &json_object_array_to_json_string; + break; + case json_type_string: + jso->_to_json_string = &json_object_string_to_json_string; + break; + } + return; + } + + jso->_to_json_string = to_string_func; + jso->_userdata = userdata; + jso->_user_delete = user_delete; +} + + +/* extended conversion to string */ + +char* json_object_to_json_string_ext(struct json_object *jso, int flags) +{ + if (!jso) + return "null"; + + if ((!jso->_pb) && !(jso->_pb = printbuf_new())) + return NULL; + + printbuf_reset(jso->_pb); + + if(jso->_to_json_string(jso, jso->_pb, 0, flags) < 0) + return NULL; + + return jso->_pb->buf; +} + +/* backwards-compatible conversion to string */ + +char* json_object_to_json_string(struct json_object *jso) +{ + return json_object_to_json_string_ext(jso, JSON_C_TO_STRING_SPACED); +} + +static void indent(struct printbuf *pb, int level, int flags) +{ + if (flags & JSON_C_TO_STRING_PRETTY) + { + printbuf_memset(pb, -1, ' ', level * 2); + } +} + +/* json_object_object */ + +static int json_object_object_to_json_string(struct json_object* jso, + struct printbuf *pb, + int level, + int flags) +{ + int had_children = 0; + struct json_object_iter iter; + + sprintbuf(pb, "{" /*}*/); + if (flags & JSON_C_TO_STRING_PRETTY) + sprintbuf(pb, "\n"); + json_object_object_foreachC(jso, iter) + { + if (had_children) + { + sprintbuf(pb, ","); + if (flags & JSON_C_TO_STRING_PRETTY) + sprintbuf(pb, "\n"); + } + had_children = 1; + if (flags & JSON_C_TO_STRING_SPACED) + sprintbuf(pb, " "); + indent(pb, level+1, flags); + sprintbuf(pb, "\""); + json_escape_str(pb, iter.key, strlen(iter.key)); + if (flags & JSON_C_TO_STRING_SPACED) + sprintbuf(pb, "\": "); + else + sprintbuf(pb, "\":"); + if(iter.val == NULL) + sprintbuf(pb, "null"); + else + iter.val->_to_json_string(iter.val, pb, level+1,flags); + } + if (flags & JSON_C_TO_STRING_PRETTY) + { + if (had_children) + sprintbuf(pb, "\n"); + indent(pb,level,flags); + } + if (flags & JSON_C_TO_STRING_SPACED) + return sprintbuf(pb, /*{*/ " }"); + else + return sprintbuf(pb, /*{*/ "}"); +} + + +static void json_object_lh_entry_free(struct lh_entry *ent) +{ + free(ent->k); + json_object_put((struct json_object*)ent->v); +} + +static void json_object_object_delete(struct json_object* jso) +{ + lh_table_free(jso->o.c_object); + json_object_generic_delete(jso); +} + +struct json_object* json_object_new_object(void) +{ + struct json_object* jso = json_object_new(json_type_object); + + if (!jso) + { + return NULL; + } + + jso->_delete = &json_object_object_delete; + jso->_to_json_string = &json_object_object_to_json_string; + jso->o.c_object = lh_kchar_table_new(JSON_OBJECT_DEF_HASH_ENTRIES, NULL, &json_object_lh_entry_free); + + return jso; +} + +struct lh_table* json_object_get_object(struct json_object *jso) +{ + if(!jso) return NULL; + switch(jso->o_type) { + case json_type_object: + return jso->o.c_object; + default: + return NULL; + } +} + +void json_object_object_add(struct json_object* jso, const char *key, + struct json_object *val) +{ + // We lookup the entry and replace the value, rather than just deleting + // and re-adding it, so the existing key remains valid. + json_object *existing_value = NULL; + struct lh_entry *existing_entry; + existing_entry = lh_table_lookup_entry(jso->o.c_object, (void*)key); + if (!existing_entry) + { + lh_table_insert(jso->o.c_object, strdup(key), val); + return; + } + existing_value = (void *)existing_entry->v; + if (existing_value) + json_object_put(existing_value); + existing_entry->v = val; +} + +int json_object_object_length(struct json_object *jso) +{ + return lh_table_length(jso->o.c_object); +} + +struct json_object* json_object_object_get(struct json_object* jso, const char *key) +{ + struct json_object *result = NULL; + json_object_object_get_ex(jso, key, &result); + return result; +} + +json_bool json_object_object_get_ex(struct json_object* jso, const char *key, struct json_object **value) +{ + if (value != NULL) + *value = NULL; + + if (NULL == jso) + return FALSE; + + switch(jso->o_type) + { + case json_type_object: + return lh_table_lookup_ex(jso->o.c_object, (void*)key, (void**)value); + default: + if (value != NULL) + *value = NULL; + return FALSE; + } +} + +void json_object_object_del(struct json_object* jso, const char *key) +{ + lh_table_delete(jso->o.c_object, key); +} + + +/* json_object_boolean */ + +static int json_object_boolean_to_json_string(struct json_object* jso, + struct printbuf *pb, + int level, + int flags) +{ + if(jso->o.c_boolean) return sprintbuf(pb, "true"); + else return sprintbuf(pb, "false"); +} + +struct json_object* json_object_new_boolean(json_bool b) +{ + struct json_object *jso = json_object_new(json_type_boolean); + if(!jso) return NULL; + jso->_to_json_string = &json_object_boolean_to_json_string; + jso->o.c_boolean = b; + return jso; +} + +json_bool json_object_get_boolean(struct json_object *jso) +{ + if(!jso) return FALSE; + switch(jso->o_type) { + case json_type_boolean: + return jso->o.c_boolean; + case json_type_int: + return (jso->o.c_int64 != 0); + case json_type_double: + return (jso->o.c_double != 0); + case json_type_string: + return (jso->o.c_string.len != 0); + default: + return FALSE; + } +} + + +/* json_object_int */ + +static int json_object_int_to_json_string(struct json_object* jso, + struct printbuf *pb, + int level, + int flags) +{ + return sprintbuf(pb, "%"PRId64, jso->o.c_int64); +} + +struct json_object* json_object_new_int(int32_t i) +{ + struct json_object *jso = json_object_new(json_type_int); + if(!jso) return NULL; + jso->_to_json_string = &json_object_int_to_json_string; + jso->o.c_int64 = i; + return jso; +} + +int32_t json_object_get_int(struct json_object *jso) +{ + int64_t cint64; + enum json_type o_type; + + if(!jso) return 0; + + o_type = jso->o_type; + cint64 = jso->o.c_int64; + + if (o_type == json_type_string) + { + /* + * Parse strings into 64-bit numbers, then use the + * 64-to-32-bit number handling below. + */ + if (json_parse_int64(jso->o.c_string.str, &cint64) != 0) + return 0; /* whoops, it didn't work. */ + o_type = json_type_int; + } + + switch(o_type) { + case json_type_int: + /* Make sure we return the correct values for out of range numbers. */ + if (cint64 <= INT32_MIN) + return INT32_MIN; + else if (cint64 >= INT32_MAX) + return INT32_MAX; + else + return (int32_t)cint64; + case json_type_double: + return (int32_t)jso->o.c_double; + case json_type_boolean: + return jso->o.c_boolean; + default: + return 0; + } +} + +struct json_object* json_object_new_int64(int64_t i) +{ + struct json_object *jso = json_object_new(json_type_int); + if(!jso) return NULL; + jso->_to_json_string = &json_object_int_to_json_string; + jso->o.c_int64 = i; + return jso; +} + +int64_t json_object_get_int64(struct json_object *jso) +{ + int64_t cint; + + if(!jso) return 0; + switch(jso->o_type) { + case json_type_int: + return jso->o.c_int64; + case json_type_double: + return (int64_t)jso->o.c_double; + case json_type_boolean: + return jso->o.c_boolean; + case json_type_string: + if (json_parse_int64(jso->o.c_string.str, &cint) == 0) return cint; + default: + return 0; + } +} + + +/* json_object_double */ + +static int json_object_double_to_json_string(struct json_object* jso, + struct printbuf *pb, + int level, + int flags) +{ + char buf[128], *p, *q; + size_t size; + /* Although JSON RFC does not support + NaN or Infinity as numeric values + ECMA 262 section 9.8.1 defines + how to handle these cases as strings */ + if(isnan(jso->o.c_double)) + size = _snprintf_s(buf, sizeof(buf), _TRUNCATE, "NaN"); + else if(isinf(jso->o.c_double)) + if(jso->o.c_double > 0) + size = _snprintf_s(buf, sizeof(buf), _TRUNCATE, "Infinity"); + else + size = _snprintf_s(buf, sizeof(buf), _TRUNCATE, "-Infinity"); + else + size = _snprintf_s(buf, sizeof(buf), _TRUNCATE, "%.17g", jso->o.c_double); + + p = strchr(buf, ','); + if (p) { + *p = '.'; + } else { + p = strchr(buf, '.'); + } + if (p && (flags & JSON_C_TO_STRING_NOZERO)) { + /* last useful digit, always keep 1 zero */ + p++; + for (q=p ; *q ; q++) { + if (*q!='0') p=q; + } + /* drop trailing zeroes */ + *(++p) = 0; + size = p-buf; + } + printbuf_memappend(pb, buf, size); + return (int)size; +} + +struct json_object* json_object_new_double(double d) +{ + struct json_object *jso = json_object_new(json_type_double); + if (!jso) + return NULL; + jso->_to_json_string = &json_object_double_to_json_string; + jso->o.c_double = d; + return jso; +} + +struct json_object* json_object_new_double_s(double d, const char *ds) +{ + struct json_object *jso = json_object_new_double(d); + if (!jso) + return NULL; + + json_object_set_serializer(jso, json_object_userdata_to_json_string, strdup(ds), json_object_free_userdata); + return jso; +} + +int json_object_userdata_to_json_string(struct json_object *jso, struct printbuf *pb, int level, int flags) +{ + size_t userdata_len = strlen(jso->_userdata); + printbuf_memappend(pb, jso->_userdata, userdata_len); + return (int)userdata_len; +} + +void json_object_free_userdata(struct json_object *jso, void *userdata) +{ + free(userdata); +} + +double json_object_get_double(struct json_object *jso) +{ + double cdouble; + char *errPtr = NULL; + + if(!jso) return 0.0; + switch(jso->o_type) { + case json_type_double: + return jso->o.c_double; + case json_type_int: + return (double)jso->o.c_int64; + case json_type_boolean: + return jso->o.c_boolean; + case json_type_string: + errno = 0; + cdouble = strtod(jso->o.c_string.str,&errPtr); + + /* if conversion stopped at the first character, return 0.0 */ + if (errPtr == jso->o.c_string.str) + return 0.0; + + /* + * Check that the conversion terminated on something sensible + * + * For example, { "pay" : 123AB } would parse as 123. + */ + if (*errPtr != '\0') + return 0.0; + + /* + * If strtod encounters a string which would exceed the + * capacity of a double, it returns +/- HUGE_VAL and sets + * errno to ERANGE. But +/- HUGE_VAL is also a valid result + * from a conversion, so we need to check errno. + * + * Underflow also sets errno to ERANGE, but it returns 0 in + * that case, which is what we will return anyway. + * + * See CERT guideline ERR30-C + */ + if ((HUGE_VAL == cdouble || -HUGE_VAL == cdouble) && + (ERANGE == errno)) + cdouble = 0.0; + return cdouble; + default: + return 0.0; + } +} + + +/* json_object_string */ + +static int json_object_string_to_json_string(struct json_object* jso, + struct printbuf *pb, + int level, + int flags) +{ + sprintbuf(pb, "\""); + json_escape_str(pb, jso->o.c_string.str, jso->o.c_string.len); + sprintbuf(pb, "\""); + return 0; +} + +static void json_object_string_delete(struct json_object* jso) +{ + free(jso->o.c_string.str); + json_object_generic_delete(jso); +} + +struct json_object* json_object_new_string(const char *s) +{ + struct json_object *jso = json_object_new(json_type_string); + if(!jso) return NULL; + jso->_delete = &json_object_string_delete; + jso->_to_json_string = &json_object_string_to_json_string; + jso->o.c_string.str = strdup(s); + jso->o.c_string.len = (int)strlen(s); + return jso; +} + +struct json_object* json_object_new_string_len(const char *s, size_t len) +{ + struct json_object *jso = json_object_new(json_type_string); + if(!jso) return NULL; + jso->_delete = &json_object_string_delete; + jso->_to_json_string = &json_object_string_to_json_string; + jso->o.c_string.str = (char*)malloc(len + 1); + memcpy(jso->o.c_string.str, (void *)s, len); + jso->o.c_string.str[len] = '\0'; + jso->o.c_string.len = len; + return jso; +} + +char* json_object_get_string(struct json_object *jso) +{ + if (!jso) + return NULL; + switch (jso->o_type) + { + case json_type_string: + return jso->o.c_string.str; + default: + return json_object_to_json_string(jso); + } +} + +int json_object_get_string_len(struct json_object *jso) { + if(!jso) return 0; + switch(jso->o_type) { + case json_type_string: + return (int)jso->o.c_string.len; + default: + return 0; + } +} + + +/* json_object_array */ + +static int json_object_array_to_json_string(struct json_object* jso, + struct printbuf *pb, + int level, + int flags) +{ + int had_children = 0; + int ii; + sprintbuf(pb, "["); + if (flags & JSON_C_TO_STRING_PRETTY) + sprintbuf(pb, "\n"); + for(ii=0; ii < json_object_array_length(jso); ii++) + { + struct json_object *val; + if (had_children) + { + sprintbuf(pb, ","); + if (flags & JSON_C_TO_STRING_PRETTY) + sprintbuf(pb, "\n"); + } + had_children = 1; + if (flags & JSON_C_TO_STRING_SPACED) + sprintbuf(pb, " "); + indent(pb, level + 1, flags); + val = json_object_array_get_idx(jso, ii); + if(val == NULL) + sprintbuf(pb, "null"); + else + val->_to_json_string(val, pb, level+1, flags); + } + if (flags & JSON_C_TO_STRING_PRETTY) + { + if (had_children) + sprintbuf(pb, "\n"); + indent(pb,level,flags); + } + + if (flags & JSON_C_TO_STRING_SPACED) + return sprintbuf(pb, " ]"); + else + return sprintbuf(pb, "]"); +} + +static void json_object_array_entry_free(void *data) +{ + json_object_put((struct json_object*)data); +} + +static void json_object_array_delete(struct json_object* jso) +{ + array_list_free(jso->o.c_array); + json_object_generic_delete(jso); +} + +struct json_object* json_object_new_array(void) +{ + struct json_object *jso = json_object_new(json_type_array); + if(!jso) return NULL; + jso->_delete = &json_object_array_delete; + jso->_to_json_string = &json_object_array_to_json_string; + jso->o.c_array = array_list_new(&json_object_array_entry_free); + return jso; +} + +struct array_list* json_object_get_array(struct json_object *jso) +{ + if(!jso) return NULL; + switch(jso->o_type) { + case json_type_array: + return jso->o.c_array; + default: + return NULL; + } +} + +void json_object_array_sort(struct json_object *jso, int(__cdecl* sort_fn)(const void *, const void *)) +{ + array_list_sort(jso->o.c_array, sort_fn); +} + +int json_object_array_length(struct json_object *jso) +{ + return array_list_length(jso->o.c_array); +} + +int json_object_array_add(struct json_object *jso,struct json_object *val) +{ + return array_list_add(jso->o.c_array, val); +} + +int json_object_array_put_idx(struct json_object *jso, int idx, + struct json_object *val) +{ + return array_list_put_idx(jso->o.c_array, idx, val); +} + +struct json_object* json_object_array_get_idx(struct json_object *jso, + int idx) +{ + return (struct json_object*)array_list_get_idx(jso->o.c_array, idx); +} + diff --git a/tools/CustomSetupTool/CustomSetupTool/json-c/json_object.h b/tools/CustomSetupTool/CustomSetupTool/json-c/json_object.h new file mode 100644 index 000000000000..c649ab7c7bfb --- /dev/null +++ b/tools/CustomSetupTool/CustomSetupTool/json-c/json_object.h @@ -0,0 +1,611 @@ +/* + * $Id: json_object.h,v 1.12 2006/01/30 23:07:57 mclark Exp $ + * + * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. + * Michael Clark + * Copyright (c) 2009 Hewlett-Packard Development Company, L.P. + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See COPYING for details. + * + */ + +#ifndef _json_object_h_ +#define _json_object_h_ + +#ifdef __GNUC__ +#define THIS_FUNCTION_IS_DEPRECATED(func) func __attribute__ ((deprecated)) +#elif defined(_MSC_VER) +#define THIS_FUNCTION_IS_DEPRECATED(func) __declspec(deprecated) func +#else +#define THIS_FUNCTION_IS_DEPRECATED(func) func +#endif + +#include "json_inttypes.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define JSON_OBJECT_DEF_HASH_ENTRIES 16 + +/** + * A flag for the json_object_to_json_string_ext() and + * json_object_to_file_ext() functions which causes the output + * to have no extra whitespace or formatting applied. + */ +#define JSON_C_TO_STRING_PLAIN 0 +/** + * A flag for the json_object_to_json_string_ext() and + * json_object_to_file_ext() functions which causes the output to have + * minimal whitespace inserted to make things slightly more readable. + */ +#define JSON_C_TO_STRING_SPACED (1<<0) +/** + * A flag for the json_object_to_json_string_ext() and + * json_object_to_file_ext() functions which causes + * the output to be formatted. + * + * See the "Two Space Tab" option at http://jsonformatter.curiousconcept.com/ + * for an example of the format. + */ +#define JSON_C_TO_STRING_PRETTY (1<<1) +/** + * A flag to drop trailing zero for float values + */ +#define JSON_C_TO_STRING_NOZERO (1<<2) + +#undef FALSE +#define FALSE ((json_bool)0) + +#undef TRUE +#define TRUE ((json_bool)1) + +extern const char *json_number_chars; +extern const char *json_hex_chars; + +/* CAW: added for ANSI C iteration correctness */ +struct json_object_iter +{ + char *key; + struct json_object *val; + struct lh_entry *entry; +}; + +/* forward structure definitions */ + +typedef int json_bool; +typedef struct printbuf printbuf; +typedef struct lh_table lh_table; +typedef struct array_list array_list; +typedef struct json_object json_object, *json_object_ptr; +typedef struct json_object_iter json_object_iter; +typedef struct json_tokener json_tokener; + +/** + * Type of custom user delete functions. See json_object_set_serializer. + */ +typedef void (json_object_delete_fn)(struct json_object *jso, void *userdata); + +/** + * Type of a custom serialization function. See json_object_set_serializer. + */ +typedef int (json_object_to_json_string_fn)(struct json_object *jso, + struct printbuf *pb, + int level, + int flags); + +/* supported object types */ + +typedef enum json_type { + /* If you change this, be sure to update json_type_to_name() too */ + json_type_null, + json_type_boolean, + json_type_double, + json_type_int, + json_type_object, + json_type_array, + json_type_string, +} json_type; + +/* reference counting functions */ + +/** + * Increment the reference count of json_object, thereby grabbing shared + * ownership of obj. + * + * @param obj the json_object instance + */ +extern struct json_object* json_object_get(struct json_object *obj); + +/** + * Decrement the reference count of json_object and free if it reaches zero. + * You must have ownership of obj prior to doing this or you will cause an + * imbalance in the reference count. + * + * @param obj the json_object instance + * @returns 1 if the object was freed. + */ +int json_object_put(struct json_object *obj); + +/** + * Check if the json_object is of a given type + * @param obj the json_object instance + * @param type one of: + json_type_null (i.e. obj == NULL), + json_type_boolean, + json_type_double, + json_type_int, + json_type_object, + json_type_array, + json_type_string, + */ +extern int json_object_is_type(struct json_object *obj, enum json_type type); + +/** + * Get the type of the json_object. See also json_type_to_name() to turn this + * into a string suitable, for instance, for logging. + * + * @param obj the json_object instance + * @returns type being one of: + json_type_null (i.e. obj == NULL), + json_type_boolean, + json_type_double, + json_type_int, + json_type_object, + json_type_array, + json_type_string, + */ +extern enum json_type json_object_get_type(struct json_object *obj); + + +/** Stringify object to json format. + * Equivalent to json_object_to_json_string_ext(obj, JSON_C_TO_STRING_SPACED) + * @param obj the json_object instance + * @returns a string in JSON format + */ +extern char* json_object_to_json_string(struct json_object *obj); + +/** Stringify object to json format + * @param obj the json_object instance + * @param flags formatting options, see JSON_C_TO_STRING_PRETTY and other constants + * @returns a string in JSON format + */ +extern char* json_object_to_json_string_ext(struct json_object *obj, int flags); + +/** + * Set a custom serialization function to be used when this particular object + * is converted to a string by json_object_to_json_string. + * + * If a custom serializer is already set on this object, any existing + * user_delete function is called before the new one is set. + * + * If to_string_func is NULL, the other parameters are ignored + * and the default behaviour is reset. + * + * The userdata parameter is optional and may be passed as NULL. If provided, + * it is passed to to_string_func as-is. This parameter may be NULL even + * if user_delete is non-NULL. + * + * The user_delete parameter is optional and may be passed as NULL, even if + * the userdata parameter is non-NULL. It will be called just before the + * json_object is deleted, after it's reference count goes to zero + * (see json_object_put()). + * If this is not provided, it is up to the caller to free the userdata at + * an appropriate time. (i.e. after the json_object is deleted) + * + * @param jso the object to customize + * @param to_string_func the custom serialization function + * @param userdata an optional opaque cookie + * @param user_delete an optional function from freeing userdata + */ +extern void json_object_set_serializer(json_object *jso, + json_object_to_json_string_fn to_string_func, + void *userdata, + json_object_delete_fn *user_delete); + +/** + * Simply call free on the userdata pointer. + * Can be used with json_object_set_serializer(). + * + * @param jso unused + * @param userdata the pointer that is passed to free(). + */ +json_object_delete_fn json_object_free_userdata; + +/** + * Copy the jso->_userdata string over to pb as-is. + * Can be used with json_object_set_serializer(). + * + * @param jso The object whose _userdata is used. + * @param pb The destination buffer. + * @param level Ignored. + * @param flags Ignored. + */ +json_object_to_json_string_fn json_object_userdata_to_json_string; + + +/* object type methods */ + +/** Create a new empty object with a reference count of 1. The caller of + * this object initially has sole ownership. Remember, when using + * json_object_object_add or json_object_array_put_idx, ownership will + * transfer to the object/array. Call json_object_get if you want to maintain + * shared ownership or also add this object as a child of multiple objects or + * arrays. Any ownerships you acquired but did not transfer must be released + * through json_object_put. + * + * @returns a json_object of type json_type_object + */ +extern struct json_object* json_object_new_object(void); + +/** Get the hashtable of a json_object of type json_type_object + * @param obj the json_object instance + * @returns a linkhash + */ +extern struct lh_table* json_object_get_object(struct json_object *obj); + +/** Get the size of an object in terms of the number of fields it has. + * @param obj the json_object whose length to return + */ +extern int json_object_object_length(struct json_object* obj); + +/** Add an object field to a json_object of type json_type_object + * + * The reference count will *not* be incremented. This is to make adding + * fields to objects in code more compact. If you want to retain a reference + * to an added object, independent of the lifetime of obj, you must wrap the + * passed object with json_object_get. + * + * Upon calling this, the ownership of val transfers to obj. Thus you must + * make sure that you do in fact have ownership over this object. For instance, + * json_object_new_object will give you ownership until you transfer it, + * whereas json_object_object_get does not. + * + * @param obj the json_object instance + * @param key the object field name (a private copy will be duplicated) + * @param val a json_object or NULL member to associate with the given field + */ +extern void json_object_object_add(struct json_object* obj, const char *key, + struct json_object *val); + +/** Get the json_object associate with a given object field + * + * *No* reference counts will be changed. There is no need to manually adjust + * reference counts through the json_object_put/json_object_get methods unless + * you need to have the child (value) reference maintain a different lifetime + * than the owning parent (obj). Ownership of the returned value is retained + * by obj (do not do json_object_put unless you have done a json_object_get). + * If you delete the value from obj (json_object_object_del) and wish to access + * the returned reference afterwards, make sure you have first gotten shared + * ownership through json_object_get (& don't forget to do a json_object_put + * or transfer ownership to prevent a memory leak). + * + * @param obj the json_object instance + * @param key the object field name + * @returns the json_object associated with the given field name + * @deprecated Please use json_object_object_get_ex + */ +THIS_FUNCTION_IS_DEPRECATED(extern struct json_object* json_object_object_get(struct json_object* obj, + const char *key)); + +/** Get the json_object associated with a given object field. + * + * This returns true if the key is found, false in all other cases (including + * if obj isn't a json_type_object). + * + * *No* reference counts will be changed. There is no need to manually adjust + * reference counts through the json_object_put/json_object_get methods unless + * you need to have the child (value) reference maintain a different lifetime + * than the owning parent (obj). Ownership of value is retained by obj. + * + * @param obj the json_object instance + * @param key the object field name + * @param value a pointer where to store a reference to the json_object + * associated with the given field name. + * + * It is safe to pass a NULL value. + * @returns whether or not the key exists + */ +extern json_bool json_object_object_get_ex(struct json_object* obj, + const char *key, + struct json_object **value); + +/** Delete the given json_object field + * + * The reference count will be decremented for the deleted object. If there + * are no more owners of the value represented by this key, then the value is + * freed. Otherwise, the reference to the value will remain in memory. + * + * @param obj the json_object instance + * @param key the object field name + */ +extern void json_object_object_del(struct json_object* obj, const char *key); + +/** + * Iterate through all keys and values of an object. + * + * Adding keys to the object while iterating is NOT allowed. + * + * Deleting an existing key, or replacing an existing key with a + * new value IS allowed. + * + * @param obj the json_object instance + * @param key the local name for the char* key variable defined in the body + * @param val the local name for the json_object* object variable defined in + * the body + */ +#if defined(__GNUC__) && !defined(__STRICT_ANSI__) && __STDC_VERSION__ >= 199901L + +# define json_object_object_foreach(obj,key,val) \ + char *key; \ + struct json_object *val __attribute__((__unused__)); \ + for(struct lh_entry *entry ## key = json_object_get_object(obj)->head, *entry_next ## key = NULL; \ + ({ if(entry ## key) { \ + key = (char*)entry ## key->k; \ + val = (struct json_object*)entry ## key->v; \ + entry_next ## key = entry ## key->next; \ + } ; entry ## key; }); \ + entry ## key = entry_next ## key ) + +#else /* ANSI C or MSC */ + +# define json_object_object_foreach(obj,key,val) \ + char *key;\ + struct json_object *val; \ + struct lh_entry *entry ## key; \ + struct lh_entry *entry_next ## key = NULL; \ + for(entry ## key = json_object_get_object(obj)->head; \ + (entry ## key ? ( \ + key = (char*)entry ## key->k, \ + val = (struct json_object*)entry ## key->v, \ + entry_next ## key = entry ## key->next, \ + entry ## key) : 0); \ + entry ## key = entry_next ## key) + +#endif /* defined(__GNUC__) && !defined(__STRICT_ANSI__) && __STDC_VERSION__ >= 199901L */ + +/** Iterate through all keys and values of an object (ANSI C Safe) + * @param obj the json_object instance + * @param iter the object iterator + */ +#define json_object_object_foreachC(obj,iter) \ + for(iter.entry = json_object_get_object(obj)->head; (iter.entry ? (iter.key = (char*)iter.entry->k, iter.val = (struct json_object*)iter.entry->v, iter.entry) : 0); iter.entry = iter.entry->next) + +/* Array type methods */ + +/** Create a new empty json_object of type json_type_array + * @returns a json_object of type json_type_array + */ +extern struct json_object* json_object_new_array(void); + +/** Get the arraylist of a json_object of type json_type_array + * @param obj the json_object instance + * @returns an arraylist + */ +extern struct array_list* json_object_get_array(struct json_object *obj); + +/** Get the length of a json_object of type json_type_array + * @param obj the json_object instance + * @returns an int + */ +extern int json_object_array_length(struct json_object *obj); + +/** Sorts the elements of jso of type json_type_array +* +* Pointers to the json_object pointers will be passed as the two arguments +* to @sort_fn +* +* @param obj the json_object instance +* @param sort_fn a sorting function +*/ +extern void json_object_array_sort(struct json_object *jso, int(__cdecl* sort_fn)(const void *, const void *)); + +/** Add an element to the end of a json_object of type json_type_array + * + * The reference count will *not* be incremented. This is to make adding + * fields to objects in code more compact. If you want to retain a reference + * to an added object you must wrap the passed object with json_object_get + * + * @param obj the json_object instance + * @param val the json_object to be added + */ +extern int json_object_array_add(struct json_object *obj, + struct json_object *val); + +/** Insert or replace an element at a specified index in an array (a json_object of type json_type_array) + * + * The reference count will *not* be incremented. This is to make adding + * fields to objects in code more compact. If you want to retain a reference + * to an added object you must wrap the passed object with json_object_get + * + * The reference count of a replaced object will be decremented. + * + * The array size will be automatically be expanded to the size of the + * index if the index is larger than the current size. + * + * @param obj the json_object instance + * @param idx the index to insert the element at + * @param val the json_object to be added + */ +extern int json_object_array_put_idx(struct json_object *obj, int idx, + struct json_object *val); + +/** Get the element at specificed index of the array (a json_object of type json_type_array) + * @param obj the json_object instance + * @param idx the index to get the element at + * @returns the json_object at the specified index (or NULL) + */ +extern struct json_object* json_object_array_get_idx(struct json_object *obj, + int idx); + +/* json_bool type methods */ + +/** Create a new empty json_object of type json_type_boolean + * @param b a json_bool TRUE or FALSE (0 or 1) + * @returns a json_object of type json_type_boolean + */ +extern struct json_object* json_object_new_boolean(json_bool b); + +/** Get the json_bool value of a json_object + * + * The type is coerced to a json_bool if the passed object is not a json_bool. + * integer and double objects will return FALSE if there value is zero + * or TRUE otherwise. If the passed object is a string it will return + * TRUE if it has a non zero length. If any other object type is passed + * TRUE will be returned if the object is not NULL. + * + * @param obj the json_object instance + * @returns a json_bool + */ +extern json_bool json_object_get_boolean(struct json_object *obj); + + +/* int type methods */ + +/** Create a new empty json_object of type json_type_int + * Note that values are stored as 64-bit values internally. + * To ensure the full range is maintained, use json_object_new_int64 instead. + * @param i the integer + * @returns a json_object of type json_type_int + */ +extern struct json_object* json_object_new_int(int32_t i); + + +/** Create a new empty json_object of type json_type_int + * @param i the integer + * @returns a json_object of type json_type_int + */ +extern struct json_object* json_object_new_int64(int64_t i); + + +/** Get the int value of a json_object + * + * The type is coerced to a int if the passed object is not a int. + * double objects will return their integer conversion. Strings will be + * parsed as an integer. If no conversion exists then 0 is returned + * and errno is set to EINVAL. null is equivalent to 0 (no error values set) + * + * Note that integers are stored internally as 64-bit values. + * If the value of too big or too small to fit into 32-bit, INT32_MAX or + * INT32_MIN are returned, respectively. + * + * @param obj the json_object instance + * @returns an int + */ +extern int32_t json_object_get_int(struct json_object *obj); + +/** Get the int value of a json_object + * + * The type is coerced to a int64 if the passed object is not a int64. + * double objects will return their int64 conversion. Strings will be + * parsed as an int64. If no conversion exists then 0 is returned. + * + * NOTE: Set errno to 0 directly before a call to this function to determine + * whether or not conversion was successful (it does not clear the value for + * you). + * + * @param obj the json_object instance + * @returns an int64 + */ +extern int64_t json_object_get_int64(struct json_object *obj); + + +/* double type methods */ + +/** Create a new empty json_object of type json_type_double + * @param d the double + * @returns a json_object of type json_type_double + */ +extern struct json_object* json_object_new_double(double d); + +/** + * Create a new json_object of type json_type_double, using + * the exact serialized representation of the value. + * + * This allows for numbers that would otherwise get displayed + * inefficiently (e.g. 12.3 => "12.300000000000001") to be + * serialized with the more convenient form. + * + * Note: this is used by json_tokener_parse_ex() to allow for + * an exact re-serialization of a parsed object. + * + * An equivalent sequence of calls is: + * @code + * jso = json_object_new_double(d); + * json_object_set_serializer(d, json_object_userdata_to_json_string, + * strdup(ds), json_object_free_userdata) + * @endcode + * + * @param d the numeric value of the double. + * @param ds the string representation of the double. This will be copied. + */ +extern struct json_object* json_object_new_double_s(double d, const char *ds); + +/** Get the double floating point value of a json_object + * + * The type is coerced to a double if the passed object is not a double. + * integer objects will return their double conversion. Strings will be + * parsed as a double. If no conversion exists then 0.0 is returned and + * errno is set to EINVAL. null is equivalent to 0 (no error values set) + * + * If the value is too big to fit in a double, then the value is set to + * the closest infinity with errno set to ERANGE. If strings cannot be + * converted to their double value, then EINVAL is set & NaN is returned. + * + * Arrays of length 0 are interpreted as 0 (with no error flags set). + * Arrays of length 1 are effectively cast to the equivalent object and + * converted using the above rules. All other arrays set the error to + * EINVAL & return NaN. + * + * NOTE: Set errno to 0 directly before a call to this function to + * determine whether or not conversion was successful (it does not clear + * the value for you). + * + * @param obj the json_object instance + * @returns a double floating point number + */ +extern double json_object_get_double(struct json_object *obj); + + +/* string type methods */ + +/** Create a new empty json_object of type json_type_string + * + * A copy of the string is made and the memory is managed by the json_object + * + * @param s the string + * @returns a json_object of type json_type_string + */ +extern struct json_object* json_object_new_string(const char *s); + +extern struct json_object* json_object_new_string_len(const char *s, size_t len); + +/** Get the string value of a json_object + * + * If the passed object is not of type json_type_string then the JSON + * representation of the object is returned. + * + * The returned string memory is managed by the json_object and will + * be freed when the reference count of the json_object drops to zero. + * + * @param obj the json_object instance + * @returns a string + */ +extern char* json_object_get_string(struct json_object *obj); + +/** Get the string length of a json_object + * + * If the passed object is not of type json_type_string then zero + * will be returned. + * + * @param obj the json_object instance + * @returns int + */ +extern int json_object_get_string_len(struct json_object *obj); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/tools/CustomSetupTool/CustomSetupTool/json-c/json_object_iterator.c b/tools/CustomSetupTool/CustomSetupTool/json-c/json_object_iterator.c new file mode 100644 index 000000000000..7066649c3bc5 --- /dev/null +++ b/tools/CustomSetupTool/CustomSetupTool/json-c/json_object_iterator.c @@ -0,0 +1,168 @@ +/** +******************************************************************************* +* @file json_object_iterator.c +* +* Copyright (c) 2009-2012 Hewlett-Packard Development Company, L.P. +* +* This library is free software; you can redistribute it and/or modify +* it under the terms of the MIT license. See COPYING for details. +* +* @brief json-c forces clients to use its private data +* structures for JSON Object iteration. This API +* implementation corrects that by abstracting the +* private json-c details. +* +******************************************************************************* +*/ + +#include + +#include "json.h" +#include "json_object_private.h" + +#include "json_object_iterator.h" + +/** + * How It Works + * + * For each JSON Object, json-c maintains a linked list of zero + * or more lh_entry (link-hash entry) structures inside the + * Object's link-hash table (lh_table). + * + * Each lh_entry structure on the JSON Object's linked list + * represents a single name/value pair. The "next" field of the + * last lh_entry in the list is set to NULL, which terminates + * the list. + * + * We represent a valid iterator that refers to an actual + * name/value pair via a pointer to the pair's lh_entry + * structure set as the iterator's opaque_ field. + * + * We follow json-c's current pair list representation by + * representing a valid "end" iterator (one that refers past the + * last pair) with a NULL value in the iterator's opaque_ field. + * + * A JSON Object without any pairs in it will have the "head" + * field of its lh_table structure set to NULL. For such an + * object, json_object_iter_begin will return an iterator with + * the opaque_ field set to NULL, which is equivalent to the + * "end" iterator. + * + * When iterating, we simply update the iterator's opaque_ field + * to point to the next lh_entry structure in the linked list. + * opaque_ will become NULL once we iterate past the last pair + * in the list, which makes the iterator equivalent to the "end" + * iterator. + */ + +/// Our current representation of the "end" iterator; +/// +/// @note May not always be NULL +static const void* kObjectEndIterValue = NULL; + +/** + * **************************************************************************** + */ +struct json_object_iterator +json_object_iter_begin(struct json_object* obj) +{ + struct json_object_iterator iter; + struct lh_table* pTable; + + /// @note json_object_get_object will return NULL if passed NULL + /// or a non-json_type_object instance + pTable = json_object_get_object(obj); + JASSERT(NULL != pTable); + + /// @note For a pair-less Object, head is NULL, which matches our + /// definition of the "end" iterator + iter.opaque_ = pTable->head; + return iter; +} + +/** + * **************************************************************************** + */ +struct json_object_iterator +json_object_iter_end(const struct json_object* obj) +{ + struct json_object_iterator iter; + + JASSERT(NULL != obj); + JASSERT(json_object_is_type(obj, json_type_object)); + + iter.opaque_ = kObjectEndIterValue; + + return iter; +} + +/** + * **************************************************************************** + */ +void +json_object_iter_next(struct json_object_iterator* iter) +{ + JASSERT(NULL != iter); + JASSERT(kObjectEndIterValue != iter->opaque_); + + iter->opaque_ = ((struct lh_entry *)iter->opaque_)->next; +} + + +/** + * **************************************************************************** + */ +const char* +json_object_iter_peek_name(const struct json_object_iterator* iter) +{ + JASSERT(NULL != iter); + JASSERT(kObjectEndIterValue != iter->opaque_); + + return (const char*)(((struct lh_entry *)iter->opaque_)->k); +} + + +/** + * **************************************************************************** + */ +struct json_object* +json_object_iter_peek_value(const struct json_object_iterator* iter) +{ + JASSERT(NULL != iter); + JASSERT(kObjectEndIterValue != iter->opaque_); + + return (struct json_object*)(((struct lh_entry *)iter->opaque_)->v); +} + + +/** + * **************************************************************************** + */ +json_bool +json_object_iter_equal(const struct json_object_iterator* iter1, + const struct json_object_iterator* iter2) +{ + JASSERT(NULL != iter1); + JASSERT(NULL != iter2); + + return (iter1->opaque_ == iter2->opaque_); +} + + +/** + * **************************************************************************** + */ +struct json_object_iterator +json_object_iter_init_default(void) +{ + struct json_object_iterator iter; + + /** + * @note Make this a negative, invalid value, such that + * accidental access to it would likely be trapped by the + * hardware as an invalid address. + */ + iter.opaque_ = NULL; + + return iter; +} diff --git a/tools/CustomSetupTool/CustomSetupTool/json-c/json_object_iterator.h b/tools/CustomSetupTool/CustomSetupTool/json-c/json_object_iterator.h new file mode 100644 index 000000000000..44c9fb25b6ca --- /dev/null +++ b/tools/CustomSetupTool/CustomSetupTool/json-c/json_object_iterator.h @@ -0,0 +1,239 @@ +/** +******************************************************************************* +* @file json_object_iterator.h +* +* Copyright (c) 2009-2012 Hewlett-Packard Development Company, L.P. +* +* This library is free software; you can redistribute it and/or modify +* it under the terms of the MIT license. See COPYING for details. +* +* @brief json-c forces clients to use its private data +* structures for JSON Object iteration. This API +* corrects that by abstracting the private json-c +* details. +* +* API attributes:
    +* * Thread-safe: NO
    +* * Reentrant: NO +* +******************************************************************************* +*/ + + +#ifndef JSON_OBJECT_ITERATOR_H +#define JSON_OBJECT_ITERATOR_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Forward declaration for the opaque iterator information. + */ +struct json_object_iter_info_; + +/** + * The opaque iterator that references a name/value pair within + * a JSON Object instance or the "end" iterator value. + */ +struct json_object_iterator { + const void* opaque_; +}; + + +/** + * forward declaration of json-c's JSON value instance structure + */ +struct json_object; + + +/** + * Initializes an iterator structure to a "default" value that + * is convenient for initializing an iterator variable to a + * default state (e.g., initialization list in a class' + * constructor). + * + * @code + * struct json_object_iterator iter = json_object_iter_init_default(); + * MyClass() : iter_(json_object_iter_init_default()) + * @endcode + * + * @note The initialized value doesn't reference any specific + * pair, is considered an invalid iterator, and MUST NOT + * be passed to any json-c API that expects a valid + * iterator. + * + * @note User and internal code MUST NOT make any assumptions + * about and dependencies on the value of the "default" + * iterator value. + * + * @return json_object_iterator + */ +struct json_object_iterator +json_object_iter_init_default(void); + +/** Retrieves an iterator to the first pair of the JSON Object. + * + * @warning Any modification of the underlying pair invalidates all + * iterators to that pair. + * + * @param obj JSON Object instance (MUST be of type json_object) + * + * @return json_object_iterator If the JSON Object has at + * least one pair, on return, the iterator refers + * to the first pair. If the JSON Object doesn't + * have any pairs, the returned iterator is + * equivalent to the "end" iterator for the same + * JSON Object instance. + * + * @code + * struct json_object_iterator it; + * struct json_object_iterator itEnd; + * struct json_object* obj; + * + * obj = json_tokener_parse("{'first':'george', 'age':100}"); + * it = json_object_iter_begin(obj); + * itEnd = json_object_iter_end(obj); + * + * while (!json_object_iter_equal(&it, &itEnd)) { + * printf("%s\n", + * json_object_iter_peek_name(&it)); + * json_object_iter_next(&it); + * } + * + * @endcode + */ +struct json_object_iterator +json_object_iter_begin(struct json_object* obj); + +/** Retrieves the iterator that represents the position beyond the + * last pair of the given JSON Object instance. + * + * @warning Do NOT write code that assumes that the "end" + * iterator value is NULL, even if it is so in a + * particular instance of the implementation. + * + * @note The reason we do not (and MUST NOT) provide + * "json_object_iter_is_end(json_object_iterator* iter)" + * type of API is because it would limit the underlying + * representation of name/value containment (or force us + * to add additional, otherwise unnecessary, fields to + * the iterator structure). The "end" iterator and the + * equality test method, on the other hand, permit us to + * cleanly abstract pretty much any reasonable underlying + * representation without burdening the iterator + * structure with unnecessary data. + * + * @note For performance reasons, memorize the "end" iterator prior + * to any loop. + * + * @param obj JSON Object instance (MUST be of type json_object) + * + * @return json_object_iterator On return, the iterator refers + * to the "end" of the Object instance's pairs + * (i.e., NOT the last pair, but "beyond the last + * pair" value) + */ +struct json_object_iterator +json_object_iter_end(const struct json_object* obj); + +/** Returns an iterator to the next pair, if any + * + * @warning Any modification of the underlying pair + * invalidates all iterators to that pair. + * + * @param iter [IN/OUT] Pointer to iterator that references a + * name/value pair; MUST be a valid, non-end iterator. + * WARNING: bad things will happen if invalid or "end" + * iterator is passed. Upon return will contain the + * reference to the next pair if there is one; if there + * are no more pairs, will contain the "end" iterator + * value, which may be compared against the return value + * of json_object_iter_end() for the same JSON Object + * instance. + */ +void +json_object_iter_next(struct json_object_iterator* iter); + + +/** Returns a const pointer to the name of the pair referenced + * by the given iterator. + * + * @param iter pointer to iterator that references a name/value + * pair; MUST be a valid, non-end iterator. + * + * @warning bad things will happen if an invalid or + * "end" iterator is passed. + * + * @return const char* Pointer to the name of the referenced + * name/value pair. The name memory belongs to the + * name/value pair, will be freed when the pair is + * deleted or modified, and MUST NOT be modified or + * freed by the user. + */ +const char* +json_object_iter_peek_name(const struct json_object_iterator* iter); + + +/** Returns a pointer to the json-c instance representing the + * value of the referenced name/value pair, without altering + * the instance's reference count. + * + * @param iter pointer to iterator that references a name/value + * pair; MUST be a valid, non-end iterator. + * + * @warning bad things will happen if invalid or + * "end" iterator is passed. + * + * @return struct json_object* Pointer to the json-c value + * instance of the referenced name/value pair; the + * value's reference count is not changed by this + * function: if you plan to hold on to this json-c node, + * take a look at json_object_get() and + * json_object_put(). IMPORTANT: json-c API represents + * the JSON Null value as a NULL json_object instance + * pointer. + */ +struct json_object* +json_object_iter_peek_value(const struct json_object_iterator* iter); + + +/** Tests two iterators for equality. Typically used to test + * for end of iteration by comparing an iterator to the + * corresponding "end" iterator (that was derived from the same + * JSON Object instance). + * + * @note The reason we do not (and MUST NOT) provide + * "json_object_iter_is_end(json_object_iterator* iter)" + * type of API is because it would limit the underlying + * representation of name/value containment (or force us + * to add additional, otherwise unnecessary, fields to + * the iterator structure). The equality test method, on + * the other hand, permits us to cleanly abstract pretty + * much any reasonable underlying representation. + * + * @param iter1 Pointer to first valid, non-NULL iterator + * @param iter2 POinter to second valid, non-NULL iterator + * + * @warning if a NULL iterator pointer or an uninitialized + * or invalid iterator, or iterators derived from + * different JSON Object instances are passed, bad things + * will happen! + * + * @return json_bool non-zero if iterators are equal (i.e., both + * reference the same name/value pair or are both at + * "end"); zero if they are not equal. + */ +json_bool +json_object_iter_equal(const struct json_object_iterator* iter1, + const struct json_object_iterator* iter2); + + +#ifdef __cplusplus +} +#endif + + +#endif /* JSON_OBJECT_ITERATOR_H */ diff --git a/tools/CustomSetupTool/CustomSetupTool/json-c/json_object_private.h b/tools/CustomSetupTool/CustomSetupTool/json-c/json_object_private.h new file mode 100644 index 000000000000..deff7e8df48f --- /dev/null +++ b/tools/CustomSetupTool/CustomSetupTool/json-c/json_object_private.h @@ -0,0 +1,47 @@ +/* + * $Id: json_object_private.h,v 1.4 2006/01/26 02:16:28 mclark Exp $ + * + * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. + * Michael Clark + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See COPYING for details. + * + */ + +#ifndef _json_object_private_h_ +#define _json_object_private_h_ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void (json_object_private_delete_fn)(struct json_object *o); + +struct json_object +{ + enum json_type o_type; + json_object_private_delete_fn *_delete; + json_object_to_json_string_fn *_to_json_string; + int _ref_count; + struct printbuf *_pb; + union data { + json_bool c_boolean; + double c_double; + int64_t c_int64; + struct lh_table *c_object; + struct array_list *c_array; + struct { + char *str; + size_t len; + } c_string; + } o; + json_object_delete_fn *_user_delete; + void *_userdata; +}; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/tools/CustomSetupTool/CustomSetupTool/json-c/json_tokener.c b/tools/CustomSetupTool/CustomSetupTool/json-c/json_tokener.c new file mode 100644 index 000000000000..2959cbd6aea2 --- /dev/null +++ b/tools/CustomSetupTool/CustomSetupTool/json-c/json_tokener.c @@ -0,0 +1,888 @@ +/* + * $Id: json_tokener.c,v 1.20 2006/07/25 03:24:50 mclark Exp $ + * + * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. + * Michael Clark + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See COPYING for details. + * + * + * Copyright (c) 2008-2009 Yahoo! Inc. All rights reserved. + * The copyrights to the contents of this file are licensed under the MIT License + * (http://www.opensource.org/licenses/mit-license.php) + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "bits.h" +#include "debug.h" +#include "printbuf.h" +#include "arraylist.h" +#include "json_inttypes.h" +#include "json_object.h" +#include "json_tokener.h" +#include "json_util.h" + +#ifdef HAVE_LOCALE_H +#include +#endif /* HAVE_LOCALE_H */ + +#if !HAVE_STRDUP && defined(_MSC_VER) + /* MSC has the version as _strdup */ +# define strdup _strdup +#elif !HAVE_STRDUP +# error You do not have strdup on your system. +#endif /* HAVE_STRDUP */ + +#if !HAVE_STRNCASECMP && defined(_MSC_VER) + /* MSC has the version as _strnicmp */ +# define strncasecmp _strnicmp +#elif !HAVE_STRNCASECMP +# error You do not have strncasecmp on your system. +#endif /* HAVE_STRNCASECMP */ + +/* Use C99 NAN by default; if not available, nan("") should work too. */ +#ifndef NAN +#define NAN nan("") +#endif /* !NAN */ + +static const char json_null_str[] = "null"; +static const int json_null_str_len = sizeof(json_null_str) - 1; +static const char json_inf_str[] = "Infinity"; +static const int json_inf_str_len = sizeof(json_inf_str) - 1; +static const char json_nan_str[] = "NaN"; +static const int json_nan_str_len = sizeof(json_nan_str) - 1; +static const char json_true_str[] = "true"; +static const int json_true_str_len = sizeof(json_true_str) - 1; +static const char json_false_str[] = "false"; +static const int json_false_str_len = sizeof(json_false_str) - 1; + +static const char* json_tokener_errors[] = { + "success", + "continue", + "nesting too deep", + "unexpected end of data", + "unexpected character", + "null expected", + "boolean expected", + "number expected", + "array value separator ',' expected", + "quoted object property name expected", + "object property name separator ':' expected", + "object value separator ',' expected", + "invalid string sequence", + "expected comment", + "buffer size overflow" +}; + +const char *json_tokener_error_desc(enum json_tokener_error jerr) +{ + int jerr_int = (int)jerr; + if (jerr_int < 0 || jerr_int >= (int)(sizeof(json_tokener_errors) / sizeof(json_tokener_errors[0]))) + return "Unknown error, invalid json_tokener_error value passed to json_tokener_error_desc()"; + return json_tokener_errors[jerr]; +} + +enum json_tokener_error json_tokener_get_error(json_tokener *tok) +{ + return tok->err; +} + +/* Stuff for decoding unicode sequences */ +#define IS_HIGH_SURROGATE(uc) (((uc) & 0xFC00) == 0xD800) +#define IS_LOW_SURROGATE(uc) (((uc) & 0xFC00) == 0xDC00) +#define DECODE_SURROGATE_PAIR(hi,lo) ((((hi) & 0x3FF) << 10) + ((lo) & 0x3FF) + 0x10000) +static unsigned char utf8_replacement_char[3] = { 0xEF, 0xBF, 0xBD }; + +struct json_tokener* json_tokener_new_ex(int depth) +{ + struct json_tokener *tok; + + tok = (struct json_tokener*)calloc(1, sizeof(struct json_tokener)); + if (!tok) return NULL; + tok->stack = (struct json_tokener_srec *)calloc(depth, sizeof(struct json_tokener_srec)); + if (!tok->stack) { + free(tok); + return NULL; + } + tok->pb = printbuf_new(); + tok->max_depth = depth; + json_tokener_reset(tok); + return tok; +} + +struct json_tokener* json_tokener_new(void) +{ + return json_tokener_new_ex(JSON_TOKENER_DEFAULT_DEPTH); +} + +void json_tokener_free(struct json_tokener *tok) +{ + json_tokener_reset(tok); + if (tok->pb) printbuf_free(tok->pb); + if (tok->stack) free(tok->stack); + free(tok); +} + +static void json_tokener_reset_level(struct json_tokener *tok, int depth) +{ + tok->stack[depth].state = json_tokener_state_eatws; + tok->stack[depth].saved_state = json_tokener_state_start; + json_object_put(tok->stack[depth].current); + tok->stack[depth].current = NULL; + free(tok->stack[depth].obj_field_name); + tok->stack[depth].obj_field_name = NULL; +} + +void json_tokener_reset(struct json_tokener *tok) +{ + int i; + if (!tok) + return; + + for(i = tok->depth; i >= 0; i--) + json_tokener_reset_level(tok, i); + tok->depth = 0; + tok->err = json_tokener_success; +} + +struct json_object* json_tokener_parse(const char *str) +{ + enum json_tokener_error jerr_ignored; + struct json_object* obj; + obj = json_tokener_parse_verbose(str, &jerr_ignored); + return obj; +} + +struct json_object* json_tokener_parse_verbose(const char *str, enum json_tokener_error *error) +{ + struct json_tokener* tok; + struct json_object* obj; + + tok = json_tokener_new(); + if (!tok) + return NULL; + obj = json_tokener_parse_ex(tok, str, -1); + *error = tok->err; + if(tok->err != json_tokener_success) { + if (obj != NULL) + json_object_put(obj); + obj = NULL; + } + + json_tokener_free(tok); + return obj; +} + +#define state tok->stack[tok->depth].state +#define saved_state tok->stack[tok->depth].saved_state +#define current tok->stack[tok->depth].current +#define obj_field_name tok->stack[tok->depth].obj_field_name + +/* Optimization: + * json_tokener_parse_ex() consumed a lot of CPU in its main loop, + * iterating character-by character. A large performance boost is + * achieved by using tighter loops to locally handle units such as + * comments and strings. Loops that handle an entire token within + * their scope also gather entire strings and pass them to + * printbuf_memappend() in a single call, rather than calling + * printbuf_memappend() one char at a time. + * + * PEEK_CHAR() and ADVANCE_CHAR() macros are used for code that is + * common to both the main loop and the tighter loops. + */ + +/* PEEK_CHAR(dest, tok) macro: + * Peeks at the current char and stores it in dest. + * Returns 1 on success, sets tok->err and returns 0 if no more chars. + * Implicit inputs: str, len vars + */ +#define PEEK_CHAR(dest, tok) \ + (((tok)->char_offset == len) ? \ + (((tok)->depth == 0 && state == json_tokener_state_eatws && saved_state == json_tokener_state_finish) ? \ + (((tok)->err = json_tokener_success), 0) \ + : \ + (((tok)->err = json_tokener_continue), 0) \ + ) : \ + (((dest) = *str), 1) \ + ) + +/* ADVANCE_CHAR() macro: + * Incrementes str & tok->char_offset. + * For convenience of existing conditionals, returns the old value of c (0 on eof) + * Implicit inputs: c var + */ +#define ADVANCE_CHAR(str, tok) \ + ( ++(str), ((tok)->char_offset)++, c) + + +/* End optimization macro defs */ + + +struct json_object* json_tokener_parse_ex(struct json_tokener *tok, + const char *str, int len) +{ + struct json_object *obj = NULL; + char c = '\1'; +#ifdef HAVE_SETLOCALE + char *oldlocale=NULL, *tmplocale; + + tmplocale = setlocale(LC_NUMERIC, NULL); + if (tmplocale) oldlocale = strdup(tmplocale); + setlocale(LC_NUMERIC, "C"); +#endif + + tok->char_offset = 0; + tok->err = json_tokener_success; + + /* this interface is presently not 64-bit clean due to the int len argument + and the internal printbuf interface that takes 32-bit int len arguments + so the function limits the maximum string size to INT32_MAX (2GB). + If the function is called with len == -1 then strlen is called to check + the string length is less than INT32_MAX (2GB) */ + if ((len < -1) || (len == -1 && strlen(str) > INT32_MAX)) { + tok->err = json_tokener_error_size; + return NULL; + } + + while (PEEK_CHAR(c, tok)) { + + redo_char: + switch(state) { + + case json_tokener_state_eatws: + /* Advance until we change state */ + while (isspace((int)c)) { + if ((!ADVANCE_CHAR(str, tok)) || (!PEEK_CHAR(c, tok))) + goto out; + } + if(c == '/' && !(tok->flags & JSON_TOKENER_STRICT)) { + printbuf_reset(tok->pb); + printbuf_memappend_fast(tok->pb, &c, 1); + state = json_tokener_state_comment_start; + } else { + state = saved_state; + goto redo_char; + } + break; + + case json_tokener_state_start: + switch(c) { + case '{': + state = json_tokener_state_eatws; + saved_state = json_tokener_state_object_field_start; + current = json_object_new_object(); + break; + case '[': + state = json_tokener_state_eatws; + saved_state = json_tokener_state_array; + current = json_object_new_array(); + break; + case 'I': + case 'i': + state = json_tokener_state_inf; + printbuf_reset(tok->pb); + tok->st_pos = 0; + goto redo_char; + case 'N': + case 'n': + state = json_tokener_state_null; // or NaN + printbuf_reset(tok->pb); + tok->st_pos = 0; + goto redo_char; + case '\'': + if (tok->flags & JSON_TOKENER_STRICT) { + /* in STRICT mode only double-quote are allowed */ + tok->err = json_tokener_error_parse_unexpected; + goto out; + } + case '"': + state = json_tokener_state_string; + printbuf_reset(tok->pb); + tok->quote_char = c; + break; + case 'T': + case 't': + case 'F': + case 'f': + state = json_tokener_state_boolean; + printbuf_reset(tok->pb); + tok->st_pos = 0; + goto redo_char; +#if defined(__GNUC__) + case '0' ... '9': +#else + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': +#endif + case '-': + state = json_tokener_state_number; + printbuf_reset(tok->pb); + tok->is_double = 0; + goto redo_char; + default: + tok->err = json_tokener_error_parse_unexpected; + goto out; + } + break; + + case json_tokener_state_finish: + if(tok->depth == 0) goto out; + obj = json_object_get(current); + json_tokener_reset_level(tok, tok->depth); + tok->depth--; + goto redo_char; + + case json_tokener_state_inf: /* aka starts with 'i' */ + { + int size; + int size_inf; + int is_negative = 0; + + printbuf_memappend_fast(tok->pb, &c, 1); + size = json_min(tok->st_pos+1, json_null_str_len); + size_inf = json_min(tok->st_pos+1, json_inf_str_len); + char *infbuf = tok->pb->buf; + if (*infbuf == '-') + { + infbuf++; + is_negative = 1; + } + if ((!(tok->flags & JSON_TOKENER_STRICT) && + strncasecmp(json_inf_str, infbuf, size_inf) == 0) || + (strncmp(json_inf_str, infbuf, size_inf) == 0) + ) + { + if (tok->st_pos == json_inf_str_len) + { + current = json_object_new_double(is_negative ? -INFINITY : INFINITY); + saved_state = json_tokener_state_finish; + state = json_tokener_state_eatws; + goto redo_char; + } + } else { + tok->err = json_tokener_error_parse_unexpected; + goto out; + } + tok->st_pos++; + } + break; + case json_tokener_state_null: /* aka starts with 'n' */ + { + int size; + int size_nan; + printbuf_memappend_fast(tok->pb, &c, 1); + size = json_min(tok->st_pos+1, json_null_str_len); + size_nan = json_min(tok->st_pos+1, json_nan_str_len); + if((!(tok->flags & JSON_TOKENER_STRICT) && + strncasecmp(json_null_str, tok->pb->buf, size) == 0) + || (strncmp(json_null_str, tok->pb->buf, size) == 0) + ) { + if (tok->st_pos == json_null_str_len) { + current = NULL; + saved_state = json_tokener_state_finish; + state = json_tokener_state_eatws; + goto redo_char; + } + } + else if ((!(tok->flags & JSON_TOKENER_STRICT) && + strncasecmp(json_nan_str, tok->pb->buf, size_nan) == 0) || + (strncmp(json_nan_str, tok->pb->buf, size_nan) == 0) + ) + { + if (tok->st_pos == json_nan_str_len) + { + current = json_object_new_double(NAN); + saved_state = json_tokener_state_finish; + state = json_tokener_state_eatws; + goto redo_char; + } + } else { + tok->err = json_tokener_error_parse_null; + goto out; + } + tok->st_pos++; + } + break; + + case json_tokener_state_comment_start: + if(c == '*') { + state = json_tokener_state_comment; + } else if(c == '/') { + state = json_tokener_state_comment_eol; + } else { + tok->err = json_tokener_error_parse_comment; + goto out; + } + printbuf_memappend_fast(tok->pb, &c, 1); + break; + + case json_tokener_state_comment: + { + /* Advance until we change state */ + const char *case_start = str; + while(c != '*') { + if (!ADVANCE_CHAR(str, tok) || !PEEK_CHAR(c, tok)) { + printbuf_memappend_fast(tok->pb, case_start, str-case_start); + goto out; + } + } + printbuf_memappend_fast(tok->pb, case_start, 1+str-case_start); + state = json_tokener_state_comment_end; + } + break; + + case json_tokener_state_comment_eol: + { + /* Advance until we change state */ + const char *case_start = str; + while(c != '\n') { + if (!ADVANCE_CHAR(str, tok) || !PEEK_CHAR(c, tok)) { + printbuf_memappend_fast(tok->pb, case_start, str-case_start); + goto out; + } + } + printbuf_memappend_fast(tok->pb, case_start, str-case_start); + MC_DEBUG("json_tokener_comment: %s\n", tok->pb->buf); + state = json_tokener_state_eatws; + } + break; + + case json_tokener_state_comment_end: + printbuf_memappend_fast(tok->pb, &c, 1); + if(c == '/') { + MC_DEBUG("json_tokener_comment: %s\n", tok->pb->buf); + state = json_tokener_state_eatws; + } else { + state = json_tokener_state_comment; + } + break; + + case json_tokener_state_string: + { + /* Advance until we change state */ + const char *case_start = str; + while(1) { + if(c == tok->quote_char) { + printbuf_memappend_fast(tok->pb, case_start, str-case_start); + current = json_object_new_string_len(tok->pb->buf, tok->pb->bpos); + saved_state = json_tokener_state_finish; + state = json_tokener_state_eatws; + break; + } else if(c == '\\') { + printbuf_memappend_fast(tok->pb, case_start, str-case_start); + saved_state = json_tokener_state_string; + state = json_tokener_state_string_escape; + break; + } + if (!ADVANCE_CHAR(str, tok) || !PEEK_CHAR(c, tok)) { + printbuf_memappend_fast(tok->pb, case_start, str-case_start); + goto out; + } + } + } + break; + + case json_tokener_state_string_escape: + switch(c) { + case '"': + case '\\': + case '/': + printbuf_memappend_fast(tok->pb, &c, 1); + state = saved_state; + break; + case 'b': + case 'n': + case 'r': + case 't': + case 'f': + if(c == 'b') printbuf_memappend_fast(tok->pb, "\b", 1); + else if(c == 'n') printbuf_memappend_fast(tok->pb, "\n", 1); + else if(c == 'r') printbuf_memappend_fast(tok->pb, "\r", 1); + else if(c == 't') printbuf_memappend_fast(tok->pb, "\t", 1); + else if(c == 'f') printbuf_memappend_fast(tok->pb, "\f", 1); + state = saved_state; + break; + case 'u': + tok->ucs_char = 0; + tok->st_pos = 0; + state = json_tokener_state_escape_unicode; + break; + default: + tok->err = json_tokener_error_parse_string; + goto out; + } + break; + + case json_tokener_state_escape_unicode: + { + unsigned int got_hi_surrogate = 0; + + /* Handle a 4-byte sequence, or two sequences if a surrogate pair */ + while(1) { + if(strchr(json_hex_chars, c)) { + tok->ucs_char += ((unsigned int)hexdigit(c) << ((3-tok->st_pos++)*4)); + if(tok->st_pos == 4) { + unsigned char unescaped_utf[4]; + + if (got_hi_surrogate) { + if (IS_LOW_SURROGATE(tok->ucs_char)) { + /* Recalculate the ucs_char, then fall thru to process normally */ + tok->ucs_char = DECODE_SURROGATE_PAIR(got_hi_surrogate, tok->ucs_char); + } else { + /* Hi surrogate was not followed by a low surrogate */ + /* Replace the hi and process the rest normally */ + printbuf_memappend_fast(tok->pb, (char*)utf8_replacement_char, 3); + } + got_hi_surrogate = 0; + } + + if (tok->ucs_char < 0x80) { + unescaped_utf[0] = tok->ucs_char; + printbuf_memappend_fast(tok->pb, (char*)unescaped_utf, 1); + } else if (tok->ucs_char < 0x800) { + unescaped_utf[0] = 0xc0 | (tok->ucs_char >> 6); + unescaped_utf[1] = 0x80 | (tok->ucs_char & 0x3f); + printbuf_memappend_fast(tok->pb, (char*)unescaped_utf, 2); + } else if (IS_HIGH_SURROGATE(tok->ucs_char)) { + /* Got a high surrogate. Remember it and look for the + * the beginning of another sequence, which should be the + * low surrogate. + */ + got_hi_surrogate = tok->ucs_char; + /* Not at end, and the next two chars should be "\u" */ + if ((tok->char_offset+1 != len) && + (tok->char_offset+2 != len) && + (str[1] == '\\') && + (str[2] == 'u')) + { + /* Advance through the 16 bit surrogate, and move on to the + * next sequence. The next step is to process the following + * characters. + */ + if( !ADVANCE_CHAR(str, tok) || !ADVANCE_CHAR(str, tok) ) { + printbuf_memappend_fast(tok->pb, (char*)utf8_replacement_char, 3); + } + /* Advance to the first char of the next sequence and + * continue processing with the next sequence. + */ + if (!ADVANCE_CHAR(str, tok) || !PEEK_CHAR(c, tok)) { + printbuf_memappend_fast(tok->pb, (char*)utf8_replacement_char, 3); + goto out; + } + tok->ucs_char = 0; + tok->st_pos = 0; + continue; /* other json_tokener_state_escape_unicode */ + } else { + /* Got a high surrogate without another sequence following + * it. Put a replacement char in for the hi surrogate + * and pretend we finished. + */ + printbuf_memappend_fast(tok->pb, (char*)utf8_replacement_char, 3); + } + } else if (IS_LOW_SURROGATE(tok->ucs_char)) { + /* Got a low surrogate not preceded by a high */ + printbuf_memappend_fast(tok->pb, (char*)utf8_replacement_char, 3); + } else if (tok->ucs_char < 0x10000) { + unescaped_utf[0] = 0xe0 | (tok->ucs_char >> 12); + unescaped_utf[1] = 0x80 | ((tok->ucs_char >> 6) & 0x3f); + unescaped_utf[2] = 0x80 | (tok->ucs_char & 0x3f); + printbuf_memappend_fast(tok->pb, (char*)unescaped_utf, 3); + } else if (tok->ucs_char < 0x110000) { + unescaped_utf[0] = 0xf0 | ((tok->ucs_char >> 18) & 0x07); + unescaped_utf[1] = 0x80 | ((tok->ucs_char >> 12) & 0x3f); + unescaped_utf[2] = 0x80 | ((tok->ucs_char >> 6) & 0x3f); + unescaped_utf[3] = 0x80 | (tok->ucs_char & 0x3f); + printbuf_memappend_fast(tok->pb, (char*)unescaped_utf, 4); + } else { + /* Don't know what we got--insert the replacement char */ + printbuf_memappend_fast(tok->pb, (char*)utf8_replacement_char, 3); + } + state = saved_state; + break; + } + } else { + tok->err = json_tokener_error_parse_string; + goto out; + } + if (!ADVANCE_CHAR(str, tok) || !PEEK_CHAR(c, tok)) { + if (got_hi_surrogate) /* Clean up any pending chars */ + printbuf_memappend_fast(tok->pb, (char*)utf8_replacement_char, 3); + goto out; + } + } + } + break; + + case json_tokener_state_boolean: + { + int size1, size2; + printbuf_memappend_fast(tok->pb, &c, 1); + size1 = json_min(tok->st_pos+1, json_true_str_len); + size2 = json_min(tok->st_pos+1, json_false_str_len); + if((!(tok->flags & JSON_TOKENER_STRICT) && + strncasecmp(json_true_str, tok->pb->buf, size1) == 0) + || (strncmp(json_true_str, tok->pb->buf, size1) == 0) + ) { + if(tok->st_pos == json_true_str_len) { + current = json_object_new_boolean(1); + saved_state = json_tokener_state_finish; + state = json_tokener_state_eatws; + goto redo_char; + } + } else if((!(tok->flags & JSON_TOKENER_STRICT) && + strncasecmp(json_false_str, tok->pb->buf, size2) == 0) + || (strncmp(json_false_str, tok->pb->buf, size2) == 0)) { + if(tok->st_pos == json_false_str_len) { + current = json_object_new_boolean(0); + saved_state = json_tokener_state_finish; + state = json_tokener_state_eatws; + goto redo_char; + } + } else { + tok->err = json_tokener_error_parse_boolean; + goto out; + } + tok->st_pos++; + } + break; + + case json_tokener_state_number: + { + /* Advance until we change state */ + const char *case_start = str; + int case_len=0; + while(c && strchr(json_number_chars, c)) { + ++case_len; + if(c == '.' || c == 'e' || c == 'E') + tok->is_double = 1; + if (!ADVANCE_CHAR(str, tok) || !PEEK_CHAR(c, tok)) { + printbuf_memappend_fast(tok->pb, case_start, case_len); + goto out; + } + } + if (case_len>0) + printbuf_memappend_fast(tok->pb, case_start, case_len); + + // Check for -Infinity + if (tok->pb->buf[0] == '-' && case_len == 1 && + (c == 'i' || c == 'I')) + { + state = json_tokener_state_inf; + goto redo_char; + } + } + { + int64_t num64; + double numd; + if (!tok->is_double && json_parse_int64(tok->pb->buf, &num64) == 0) { + if (num64 && tok->pb->buf[0]=='0' && (tok->flags & JSON_TOKENER_STRICT)) { + /* in strict mode, number must not start with 0 */ + tok->err = json_tokener_error_parse_number; + goto out; + } + current = json_object_new_int64(num64); + } + else if(tok->is_double && json_parse_double(tok->pb->buf, &numd) == 0) + { + current = json_object_new_double_s(numd, tok->pb->buf); + } else { + tok->err = json_tokener_error_parse_number; + goto out; + } + saved_state = json_tokener_state_finish; + state = json_tokener_state_eatws; + goto redo_char; + } + break; + + case json_tokener_state_array_after_sep: + case json_tokener_state_array: + if(c == ']') { + if (state == json_tokener_state_array_after_sep && + (tok->flags & JSON_TOKENER_STRICT)) + { + tok->err = json_tokener_error_parse_unexpected; + goto out; + } + saved_state = json_tokener_state_finish; + state = json_tokener_state_eatws; + } else { + if(tok->depth >= tok->max_depth-1) { + tok->err = json_tokener_error_depth; + goto out; + } + state = json_tokener_state_array_add; + tok->depth++; + json_tokener_reset_level(tok, tok->depth); + goto redo_char; + } + break; + + case json_tokener_state_array_add: + json_object_array_add(current, obj); + saved_state = json_tokener_state_array_sep; + state = json_tokener_state_eatws; + goto redo_char; + + case json_tokener_state_array_sep: + if(c == ']') { + saved_state = json_tokener_state_finish; + state = json_tokener_state_eatws; + } else if(c == ',') { + saved_state = json_tokener_state_array_after_sep; + state = json_tokener_state_eatws; + } else { + tok->err = json_tokener_error_parse_array; + goto out; + } + break; + + case json_tokener_state_object_field_start: + case json_tokener_state_object_field_start_after_sep: + if(c == '}') { + if (state == json_tokener_state_object_field_start_after_sep && + (tok->flags & JSON_TOKENER_STRICT)) + { + tok->err = json_tokener_error_parse_unexpected; + goto out; + } + saved_state = json_tokener_state_finish; + state = json_tokener_state_eatws; + } else if (c == '"' || c == '\'') { + tok->quote_char = c; + printbuf_reset(tok->pb); + state = json_tokener_state_object_field; + } else { + tok->err = json_tokener_error_parse_object_key_name; + goto out; + } + break; + + case json_tokener_state_object_field: + { + /* Advance until we change state */ + const char *case_start = str; + while(1) { + if(c == tok->quote_char) { + printbuf_memappend_fast(tok->pb, case_start, str-case_start); + obj_field_name = strdup(tok->pb->buf); + saved_state = json_tokener_state_object_field_end; + state = json_tokener_state_eatws; + break; + } else if(c == '\\') { + printbuf_memappend_fast(tok->pb, case_start, str-case_start); + saved_state = json_tokener_state_object_field; + state = json_tokener_state_string_escape; + break; + } + if (!ADVANCE_CHAR(str, tok) || !PEEK_CHAR(c, tok)) { + printbuf_memappend_fast(tok->pb, case_start, str-case_start); + goto out; + } + } + } + break; + + case json_tokener_state_object_field_end: + if(c == ':') { + saved_state = json_tokener_state_object_value; + state = json_tokener_state_eatws; + } else { + tok->err = json_tokener_error_parse_object_key_sep; + goto out; + } + break; + + case json_tokener_state_object_value: + if(tok->depth >= tok->max_depth-1) { + tok->err = json_tokener_error_depth; + goto out; + } + state = json_tokener_state_object_value_add; + tok->depth++; + json_tokener_reset_level(tok, tok->depth); + goto redo_char; + + case json_tokener_state_object_value_add: + json_object_object_add(current, obj_field_name, obj); + free(obj_field_name); + obj_field_name = NULL; + saved_state = json_tokener_state_object_sep; + state = json_tokener_state_eatws; + goto redo_char; + + case json_tokener_state_object_sep: + if(c == '}') { + saved_state = json_tokener_state_finish; + state = json_tokener_state_eatws; + } else if(c == ',') { + saved_state = json_tokener_state_object_field_start_after_sep; + state = json_tokener_state_eatws; + } else { + tok->err = json_tokener_error_parse_object_value_sep; + goto out; + } + break; + + } + if (!ADVANCE_CHAR(str, tok)) + goto out; + } /* while(POP_CHAR) */ + + out: + if (c && + (state == json_tokener_state_finish) && + (tok->depth == 0) && + (tok->flags & JSON_TOKENER_STRICT)) { + /* unexpected char after JSON data */ + tok->err = json_tokener_error_parse_unexpected; + } + if (!c) { /* We hit an eof char (0) */ + if(state != json_tokener_state_finish && + saved_state != json_tokener_state_finish) + tok->err = json_tokener_error_parse_eof; + } + +#ifdef HAVE_SETLOCALE + setlocale(LC_NUMERIC, oldlocale); + if (oldlocale) free(oldlocale); +#endif + + if (tok->err == json_tokener_success) + { + json_object *ret = json_object_get(current); + int ii; + + /* Partially reset, so we parse additional objects on subsequent calls. */ + for(ii = tok->depth; ii >= 0; ii--) + json_tokener_reset_level(tok, ii); + return ret; + } + + MC_DEBUG("json_tokener_parse_ex: error %s at offset %d\n", + json_tokener_errors[tok->err], tok->char_offset); + return NULL; +} + +void json_tokener_set_flags(struct json_tokener *tok, int flags) +{ + tok->flags = flags; +} diff --git a/tools/CustomSetupTool/CustomSetupTool/json-c/json_tokener.h b/tools/CustomSetupTool/CustomSetupTool/json-c/json_tokener.h new file mode 100644 index 000000000000..a72d2bdefe00 --- /dev/null +++ b/tools/CustomSetupTool/CustomSetupTool/json-c/json_tokener.h @@ -0,0 +1,208 @@ +/* + * $Id: json_tokener.h,v 1.10 2006/07/25 03:24:50 mclark Exp $ + * + * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. + * Michael Clark + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See COPYING for details. + * + */ + +#ifndef _json_tokener_h_ +#define _json_tokener_h_ + +#include +#include "json_object.h" + +#ifdef __cplusplus +extern "C" { +#endif + +enum json_tokener_error { + json_tokener_success, + json_tokener_continue, + json_tokener_error_depth, + json_tokener_error_parse_eof, + json_tokener_error_parse_unexpected, + json_tokener_error_parse_null, + json_tokener_error_parse_boolean, + json_tokener_error_parse_number, + json_tokener_error_parse_array, + json_tokener_error_parse_object_key_name, + json_tokener_error_parse_object_key_sep, + json_tokener_error_parse_object_value_sep, + json_tokener_error_parse_string, + json_tokener_error_parse_comment, + json_tokener_error_size +}; + +enum json_tokener_state { + json_tokener_state_eatws, + json_tokener_state_start, + json_tokener_state_finish, + json_tokener_state_null, + json_tokener_state_comment_start, + json_tokener_state_comment, + json_tokener_state_comment_eol, + json_tokener_state_comment_end, + json_tokener_state_string, + json_tokener_state_string_escape, + json_tokener_state_escape_unicode, + json_tokener_state_boolean, + json_tokener_state_number, + json_tokener_state_array, + json_tokener_state_array_add, + json_tokener_state_array_sep, + json_tokener_state_object_field_start, + json_tokener_state_object_field, + json_tokener_state_object_field_end, + json_tokener_state_object_value, + json_tokener_state_object_value_add, + json_tokener_state_object_sep, + json_tokener_state_array_after_sep, + json_tokener_state_object_field_start_after_sep, + json_tokener_state_inf +}; + +struct json_tokener_srec +{ + enum json_tokener_state state, saved_state; + struct json_object *obj; + struct json_object *current; + char *obj_field_name; +}; + +#define JSON_TOKENER_DEFAULT_DEPTH 32 + +struct json_tokener +{ + char *str; + struct printbuf *pb; + int max_depth, depth, is_double, st_pos, char_offset; + enum json_tokener_error err; + unsigned int ucs_char; + char quote_char; + struct json_tokener_srec *stack; + int flags; +}; + +/** + * Be strict when parsing JSON input. Use caution with + * this flag as what is considered valid may become more + * restrictive from one release to the next, causing your + * code to fail on previously working input. + * + * This flag is not set by default. + * + * @see json_tokener_set_flags() + */ +#define JSON_TOKENER_STRICT 0x01 + +/** + * Given an error previously returned by json_tokener_get_error(), + * return a human readable description of the error. + * + * @return a generic error message is returned if an invalid error value is provided. + */ +const char *json_tokener_error_desc(enum json_tokener_error jerr); + +/** + * Retrieve the error caused by the last call to json_tokener_parse_ex(), + * or json_tokener_success if there is no error. + * + * When parsing a JSON string in pieces, if the tokener is in the middle + * of parsing this will return json_tokener_continue. + * + * See also json_tokener_error_desc(). + */ +enum json_tokener_error json_tokener_get_error(struct json_tokener *tok); + +extern struct json_tokener* json_tokener_new(void); +extern struct json_tokener* json_tokener_new_ex(int depth); +extern void json_tokener_free(struct json_tokener *tok); +extern void json_tokener_reset(struct json_tokener *tok); +extern struct json_object* json_tokener_parse(const char *str); +extern struct json_object* json_tokener_parse_verbose(const char *str, enum json_tokener_error *error); + +/** + * Set flags that control how parsing will be done. + */ +extern void json_tokener_set_flags(struct json_tokener *tok, int flags); + +/** + * Parse a string and return a non-NULL json_object if a valid JSON value + * is found. The string does not need to be a JSON object or array; + * it can also be a string, number or boolean value. + * + * A partial JSON string can be parsed. If the parsing is incomplete, + * NULL will be returned and json_tokener_get_error() will be return + * json_tokener_continue. + * json_tokener_parse_ex() can then be called with additional bytes in str + * to continue the parsing. + * + * If json_tokener_parse_ex() returns NULL and the error anything other than + * json_tokener_continue, a fatal error has occurred and parsing must be + * halted. Then tok object must not be re-used until json_tokener_reset() is + * called. + * + * When a valid JSON value is parsed, a non-NULL json_object will be + * returned. Also, json_tokener_get_error() will return json_tokener_success. + * Be sure to check the type with json_object_is_type() or + * json_object_get_type() before using the object. + * + * @b XXX this shouldn't use internal fields: + * Trailing characters after the parsed value do not automatically cause an + * error. It is up to the caller to decide whether to treat this as an + * error or to handle the additional characters, perhaps by parsing another + * json value starting from that point. + * + * Extra characters can be detected by comparing the tok->char_offset against + * the length of the last len parameter passed in. + * + * The tokener does \b not maintain an internal buffer so the caller is + * responsible for calling json_tokener_parse_ex with an appropriate str + * parameter starting with the extra characters. + * + * This interface is presently not 64-bit clean due to the int len argument + * so the function limits the maximum string size to INT32_MAX (2GB). + * If the function is called with len == -1 then strlen is called to check + * the string length is less than INT32_MAX (2GB) + * + * Example: + * @code +json_object *jobj = NULL; +const char *mystring = NULL; +int stringlen = 0; +enum json_tokener_error jerr; +do { + mystring = ... // get JSON string, e.g. read from file, etc... + stringlen = strlen(mystring); + jobj = json_tokener_parse_ex(tok, mystring, stringlen); +} while ((jerr = json_tokener_get_error(tok)) == json_tokener_continue); +if (jerr != json_tokener_success) +{ + fprintf(stderr, "Error: %s\n", json_tokener_error_desc(jerr)); + // Handle errors, as appropriate for your application. +} +if (tok->char_offset < stringlen) // XXX shouldn't access internal fields +{ + // Handle extra characters after parsed object as desired. + // e.g. issue an error, parse another object from that point, etc... +} +// Success, use jobj here. + +@endcode + * + * @param tok a json_tokener previously allocated with json_tokener_new() + * @param str an string with any valid JSON expression, or portion of. This does not need to be null terminated. + * @param len the length of str + */ +extern struct json_object* json_tokener_parse_ex(struct json_tokener *tok, + const char *str, int len); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/tools/CustomSetupTool/CustomSetupTool/json-c/json_util.c b/tools/CustomSetupTool/CustomSetupTool/json-c/json_util.c new file mode 100644 index 000000000000..fda5d1ec00a7 --- /dev/null +++ b/tools/CustomSetupTool/CustomSetupTool/json-c/json_util.c @@ -0,0 +1,301 @@ +/* + * $Id: json_util.c,v 1.4 2006/01/30 23:07:57 mclark Exp $ + * + * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. + * Michael Clark + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See COPYING for details. + * + */ + +#include "config.h" +#undef realloc + +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_SYS_TYPES_H +#include +#endif /* HAVE_SYS_TYPES_H */ + +#ifdef HAVE_SYS_STAT_H +#include +#endif /* HAVE_SYS_STAT_H */ + +#ifdef HAVE_FCNTL_H +#include +#endif /* HAVE_FCNTL_H */ + +#ifdef HAVE_UNISTD_H +# include +#endif /* HAVE_UNISTD_H */ + +#ifdef _WIN32 +# define WIN32_LEAN_AND_MEAN +# include +# include +#endif /* defined(_WIN32) */ + +#if !defined(HAVE_OPEN) && defined(_WIN32) +# define open _open +#endif + +#if !defined(HAVE_SNPRINTF) && defined(_MSC_VER) + /* MSC has the version as _snprintf */ +# define snprintf _snprintf +#elif !defined(HAVE_SNPRINTF) +# error You do not have snprintf on your system. +#endif /* HAVE_SNPRINTF */ + +#include "bits.h" +#include "debug.h" +#include "printbuf.h" +#include "json_inttypes.h" +#include "json_object.h" +#include "json_tokener.h" +#include "json_util.h" + +static int sscanf_is_broken = 0; +static int sscanf_is_broken_testdone = 0; +static void sscanf_is_broken_test(void); + +struct json_object* json_object_from_file(const char *filename) +{ + //struct printbuf *pb; + //struct json_object *obj; + //char buf[JSON_FILE_BUF_SIZE]; + //int fd, ret; + + //if((fd = open(filename, O_RDONLY)) < 0) { + // MC_ERROR("json_object_from_file: error opening file %s: %s\n", + // filename, strerror(errno)); + // return NULL; + //} + //if(!(pb = printbuf_new())) { + // close(fd); + // MC_ERROR("json_object_from_file: printbuf_new failed\n"); + // return NULL; + //} + //while((ret = read(fd, buf, JSON_FILE_BUF_SIZE)) > 0) { + // printbuf_memappend(pb, buf, ret); + //} + //close(fd); + //if(ret < 0) { + // MC_ERROR("json_object_from_file: error reading file %s: %s\n", + // filename, strerror(errno)); + // printbuf_free(pb); + // return NULL; + //} + //obj = json_tokener_parse(pb->buf); + //printbuf_free(pb); + return NULL;//obj; +} + +/* extended "format and write to file" function */ + +int json_object_to_file_ext(const char *filename, struct json_object *obj, int flags) +{ + //const char *json_str; + //int fd, ret; + //unsigned int wpos, wsize; + + //if(!obj) { + // MC_ERROR("json_object_to_file: object is null\n"); + // return -1; + //} + + //if((fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT, 0644)) < 0) { + // MC_ERROR("json_object_to_file: error opening file %s: %s\n", + // filename, strerror(errno)); + // return -1; + //} + + //if(!(json_str = json_object_to_json_string_ext(obj,flags))) { + // close(fd); + // return -1; + //} + + //wsize = (unsigned int)(strlen(json_str) & UINT_MAX); /* CAW: probably unnecessary, but the most 64bit safe */ + //wpos = 0; + //while(wpos < wsize) { + // if((ret = write(fd, json_str + wpos, wsize-wpos)) < 0) { + // close(fd); + // MC_ERROR("json_object_to_file: error writing file %s: %s\n", + // filename, strerror(errno)); + // return -1; + // } + + // /* because of the above check for ret < 0, we can safely cast and add */ + // wpos += (unsigned int)ret; + //} + + //close(fd); + return 0; +} + +// backwards compatible "format and write to file" function + +int json_object_to_file(const char *filename, struct json_object *obj) +{ + return json_object_to_file_ext(filename, obj, JSON_C_TO_STRING_PLAIN); +} + +int json_parse_double(const char *buf, double *retval) +{ + return (sscanf_s(buf, "%lf", retval)==1 ? 0 : 1); +} + +/* + * Not all implementations of sscanf actually work properly. + * Check whether the one we're currently using does, and if + * it's broken, enable the workaround code. + */ +static void sscanf_is_broken_test() +{ + int64_t num64; + int ret_errno, is_int64_min, ret_errno2, is_int64_max; + + sscanf_s(" -01234567890123456789012345", "%" SCNd64, &num64); + ret_errno = errno; + is_int64_min = (num64 == INT64_MIN); + + sscanf_s(" 01234567890123456789012345", "%" SCNd64, &num64); + ret_errno2 = errno; + is_int64_max = (num64 == INT64_MAX); + + if (ret_errno != ERANGE || !is_int64_min || + ret_errno2 != ERANGE || !is_int64_max) + { + MC_DEBUG("sscanf_is_broken_test failed, enabling workaround code\n"); + sscanf_is_broken = 1; + } +} + +int json_parse_int64(const char *buf, int64_t *retval) +{ + int64_t num64; + const char *buf_sig_digits; + int orig_has_neg; + int saved_errno; + + if (!sscanf_is_broken_testdone) + { + sscanf_is_broken_test(); + sscanf_is_broken_testdone = 1; + } + + // Skip leading spaces + while (isspace((int)*buf) && *buf) + buf++; + + errno = 0; // sscanf won't always set errno, so initialize + + if (sscanf_s(buf, "%" SCNd64, &num64) != 1) + { + MC_DEBUG("Failed to parse, sscanf != 1\n"); + return 1; + } + + saved_errno = errno; + buf_sig_digits = buf; + orig_has_neg = 0; + if (*buf_sig_digits == '-') + { + buf_sig_digits++; + orig_has_neg = 1; + } + + // Not all sscanf implementations actually work + if (sscanf_is_broken && saved_errno != ERANGE) + { + char buf_cmp[100]; + char *buf_cmp_start = buf_cmp; + int recheck_has_neg = 0; + int buf_cmp_len; + + // Skip leading zeros, but keep at least one digit + while (buf_sig_digits[0] == '0' && buf_sig_digits[1] != '\0') + buf_sig_digits++; + if (num64 == 0) // assume all sscanf impl's will parse -0 to 0 + orig_has_neg = 0; // "-0" is the same as just plain "0" + + _snprintf_s(buf_cmp_start, sizeof(buf_cmp), _TRUNCATE, "%" PRId64, num64); + if (*buf_cmp_start == '-') + { + recheck_has_neg = 1; + buf_cmp_start++; + } + // No need to skip leading spaces or zeros here. + + buf_cmp_len = (int)strlen(buf_cmp_start); + /** + * If the sign is different, or + * some of the digits are different, or + * there is another digit present in the original string + * then we have NOT successfully parsed the value. + */ + if (orig_has_neg != recheck_has_neg || + strncmp(buf_sig_digits, buf_cmp_start, strlen(buf_cmp_start)) != 0 || + ((int)strlen(buf_sig_digits) != buf_cmp_len && + isdigit((int)buf_sig_digits[buf_cmp_len]) + ) + ) + { + saved_errno = ERANGE; + } + } + + // Not all sscanf impl's set the value properly when out of range. + // Always do this, even for properly functioning implementations, + // since it shouldn't slow things down much. + if (saved_errno == ERANGE) + { + if (orig_has_neg) + num64 = INT64_MIN; + else + num64 = INT64_MAX; + } + *retval = num64; + return 0; +} + +#ifndef HAVE_REALLOC +void* rpl_realloc(void* p, size_t n) +{ + if (n == 0) + n = 1; + if (p == 0) + return malloc(n); + return realloc(p, n); +} +#endif + +#define NELEM(a) (sizeof(a) / sizeof(a[0])) +static const char* json_type_name[] = { + /* If you change this, be sure to update the enum json_type definition too */ + "null", + "boolean", + "double", + "int", + "object", + "array", + "string", +}; + +const char *json_type_to_name(enum json_type o_type) +{ + int o_type_int = (int)o_type; + if (o_type_int < 0 || o_type_int >= (int)NELEM(json_type_name)) + { + MC_ERROR("json_type_to_name: type %d is out of range [0,%d]\n", o_type, NELEM(json_type_name)); + return NULL; + } + return json_type_name[o_type]; +} + diff --git a/tools/CustomSetupTool/CustomSetupTool/json-c/json_util.h b/tools/CustomSetupTool/CustomSetupTool/json-c/json_util.h new file mode 100644 index 000000000000..1005e58c5b0d --- /dev/null +++ b/tools/CustomSetupTool/CustomSetupTool/json-c/json_util.h @@ -0,0 +1,41 @@ +/* + * $Id: json_util.h,v 1.4 2006/01/30 23:07:57 mclark Exp $ + * + * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. + * Michael Clark + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See COPYING for details. + * + */ + +#ifndef _json_util_h_ +#define _json_util_h_ + +#include "json_object.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define JSON_FILE_BUF_SIZE 4096 + +/* utility functions */ +extern struct json_object* json_object_from_file(const char *filename); +extern int json_object_to_file(const char *filename, struct json_object *obj); +extern int json_object_to_file_ext(const char *filename, struct json_object *obj, int flags); +extern int json_parse_int64(const char *buf, int64_t *retval); +extern int json_parse_double(const char *buf, double *retval); + + +/** + * Return a string describing the type of the object. + * e.g. "int", or "object", etc... + */ +extern const char *json_type_to_name(enum json_type o_type); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/tools/CustomSetupTool/CustomSetupTool/json-c/libjson.c b/tools/CustomSetupTool/CustomSetupTool/json-c/libjson.c new file mode 100644 index 000000000000..5284fd0e70b7 --- /dev/null +++ b/tools/CustomSetupTool/CustomSetupTool/json-c/libjson.c @@ -0,0 +1,26 @@ + +/* dummy source file for compatibility purposes */ + +#if defined(HAVE_CDEFS_H) +#include +#endif + +#ifndef __warn_references + +#if defined(__GNUC__) && defined (HAS_GNU_WARNING_LONG) + +#define __warn_references(sym,msg) \ + __asm__(".section .gnu" #sym ",\n\t.ascii \"" msg "\"\n\t.text"); + +#else +#define __warn_references(sym,msg) /* nothing */ +#endif + +#endif + +#include "json_object.h" + +__warn_references(json_object_get, "Warning: please link against libjson-c instead of libjson"); + +/* __asm__(".section .gnu.warning." __STRING(sym) \ + " ; .ascii \"" msg "\" ; .text") */ diff --git a/tools/CustomSetupTool/CustomSetupTool/json-c/linkhash.c b/tools/CustomSetupTool/CustomSetupTool/json-c/linkhash.c new file mode 100644 index 000000000000..50de485638e7 --- /dev/null +++ b/tools/CustomSetupTool/CustomSetupTool/json-c/linkhash.c @@ -0,0 +1,604 @@ +/* + * $Id: linkhash.c,v 1.4 2006/01/26 02:16:28 mclark Exp $ + * + * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. + * Michael Clark + * Copyright (c) 2009 Hewlett-Packard Development Company, L.P. + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See COPYING for details. + * + */ + +#include +#include +#include +#include +#include +#include + +#include + +#ifdef HAVE_ENDIAN_H +# include /* attempt to define endianness */ +#endif + +#include "random_seed.h" +#include "linkhash.h" + +void lh_abort(const char *msg, ...) +{ + va_list ap; + va_start(ap, msg); + vprintf(msg, ap); + va_end(ap); + exit(1); +} + +unsigned long lh_ptr_hash(const void *k) +{ + /* CAW: refactored to be 64bit nice */ + return (unsigned long)((((ptrdiff_t)k * LH_PRIME) >> 4) & ULONG_MAX); +} + +int lh_ptr_equal(const void *k1, const void *k2) +{ + return (k1 == k2); +} + +/* + * hashlittle from lookup3.c, by Bob Jenkins, May 2006, Public Domain. + * http://burtleburtle.net/bob/c/lookup3.c + * minor modifications to make functions static so no symbols are exported + * minor mofifications to compile with -Werror + */ + +/* +------------------------------------------------------------------------------- +lookup3.c, by Bob Jenkins, May 2006, Public Domain. + +These are functions for producing 32-bit hashes for hash table lookup. +hashword(), hashlittle(), hashlittle2(), hashbig(), mix(), and final() +are externally useful functions. Routines to test the hash are included +if SELF_TEST is defined. You can use this free for any purpose. It's in +the public domain. It has no warranty. + +You probably want to use hashlittle(). hashlittle() and hashbig() +hash byte arrays. hashlittle() is is faster than hashbig() on +little-endian machines. Intel and AMD are little-endian machines. +On second thought, you probably want hashlittle2(), which is identical to +hashlittle() except it returns two 32-bit hashes for the price of one. +You could implement hashbig2() if you wanted but I haven't bothered here. + +If you want to find a hash of, say, exactly 7 integers, do + a = i1; b = i2; c = i3; + mix(a,b,c); + a += i4; b += i5; c += i6; + mix(a,b,c); + a += i7; + final(a,b,c); +then use c as the hash value. If you have a variable length array of +4-byte integers to hash, use hashword(). If you have a byte array (like +a character string), use hashlittle(). If you have several byte arrays, or +a mix of things, see the comments above hashlittle(). + +Why is this so big? I read 12 bytes at a time into 3 4-byte integers, +then mix those integers. This is fast (you can do a lot more thorough +mixing with 12*3 instructions on 3 integers than you can with 3 instructions +on 1 byte), but shoehorning those bytes into integers efficiently is messy. +------------------------------------------------------------------------------- +*/ + +/* + * My best guess at if you are big-endian or little-endian. This may + * need adjustment. + */ +#if (defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && \ + __BYTE_ORDER == __LITTLE_ENDIAN) || \ + (defined(i386) || defined(__i386__) || defined(__i486__) || \ + defined(__i586__) || defined(__i686__) || defined(vax) || defined(MIPSEL)) +# define HASH_LITTLE_ENDIAN 1 +# define HASH_BIG_ENDIAN 0 +#elif (defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) && \ + __BYTE_ORDER == __BIG_ENDIAN) || \ + (defined(sparc) || defined(POWERPC) || defined(mc68000) || defined(sel)) +# define HASH_LITTLE_ENDIAN 0 +# define HASH_BIG_ENDIAN 1 +#else +# define HASH_LITTLE_ENDIAN 0 +# define HASH_BIG_ENDIAN 0 +#endif + +#define hashsize(n) ((uint32_t)1<<(n)) +#define hashmask(n) (hashsize(n)-1) +#define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k)))) + +/* +------------------------------------------------------------------------------- +mix -- mix 3 32-bit values reversibly. + +This is reversible, so any information in (a,b,c) before mix() is +still in (a,b,c) after mix(). + +If four pairs of (a,b,c) inputs are run through mix(), or through +mix() in reverse, there are at least 32 bits of the output that +are sometimes the same for one pair and different for another pair. +This was tested for: +* pairs that differed by one bit, by two bits, in any combination + of top bits of (a,b,c), or in any combination of bottom bits of + (a,b,c). +* "differ" is defined as +, -, ^, or ~^. For + and -, I transformed + the output delta to a Gray code (a^(a>>1)) so a string of 1's (as + is commonly produced by subtraction) look like a single 1-bit + difference. +* the base values were pseudorandom, all zero but one bit set, or + all zero plus a counter that starts at zero. + +Some k values for my "a-=c; a^=rot(c,k); c+=b;" arrangement that +satisfy this are + 4 6 8 16 19 4 + 9 15 3 18 27 15 + 14 9 3 7 17 3 +Well, "9 15 3 18 27 15" didn't quite get 32 bits diffing +for "differ" defined as + with a one-bit base and a two-bit delta. I +used http://burtleburtle.net/bob/hash/avalanche.html to choose +the operations, constants, and arrangements of the variables. + +This does not achieve avalanche. There are input bits of (a,b,c) +that fail to affect some output bits of (a,b,c), especially of a. The +most thoroughly mixed value is c, but it doesn't really even achieve +avalanche in c. + +This allows some parallelism. Read-after-writes are good at doubling +the number of bits affected, so the goal of mixing pulls in the opposite +direction as the goal of parallelism. I did what I could. Rotates +seem to cost as much as shifts on every machine I could lay my hands +on, and rotates are much kinder to the top and bottom bits, so I used +rotates. +------------------------------------------------------------------------------- +*/ +#define mix(a,b,c) \ +{ \ + a -= c; a ^= rot(c, 4); c += b; \ + b -= a; b ^= rot(a, 6); a += c; \ + c -= b; c ^= rot(b, 8); b += a; \ + a -= c; a ^= rot(c,16); c += b; \ + b -= a; b ^= rot(a,19); a += c; \ + c -= b; c ^= rot(b, 4); b += a; \ +} + +/* +------------------------------------------------------------------------------- +final -- final mixing of 3 32-bit values (a,b,c) into c + +Pairs of (a,b,c) values differing in only a few bits will usually +produce values of c that look totally different. This was tested for +* pairs that differed by one bit, by two bits, in any combination + of top bits of (a,b,c), or in any combination of bottom bits of + (a,b,c). +* "differ" is defined as +, -, ^, or ~^. For + and -, I transformed + the output delta to a Gray code (a^(a>>1)) so a string of 1's (as + is commonly produced by subtraction) look like a single 1-bit + difference. +* the base values were pseudorandom, all zero but one bit set, or + all zero plus a counter that starts at zero. + +These constants passed: + 14 11 25 16 4 14 24 + 12 14 25 16 4 14 24 +and these came close: + 4 8 15 26 3 22 24 + 10 8 15 26 3 22 24 + 11 8 15 26 3 22 24 +------------------------------------------------------------------------------- +*/ +#define final(a,b,c) \ +{ \ + c ^= b; c -= rot(b,14); \ + a ^= c; a -= rot(c,11); \ + b ^= a; b -= rot(a,25); \ + c ^= b; c -= rot(b,16); \ + a ^= c; a -= rot(c,4); \ + b ^= a; b -= rot(a,14); \ + c ^= b; c -= rot(b,24); \ +} + + +/* +------------------------------------------------------------------------------- +hashlittle() -- hash a variable-length key into a 32-bit value + k : the key (the unaligned variable-length array of bytes) + length : the length of the key, counting by bytes + initval : can be any 4-byte value +Returns a 32-bit value. Every bit of the key affects every bit of +the return value. Two keys differing by one or two bits will have +totally different hash values. + +The best hash table sizes are powers of 2. There is no need to do +mod a prime (mod is sooo slow!). If you need less than 32 bits, +use a bitmask. For example, if you need only 10 bits, do + h = (h & hashmask(10)); +In which case, the hash table should have hashsize(10) elements. + +If you are hashing n strings (uint8_t **)k, do it like this: + for (i=0, h=0; i 12) + { + a += k[0]; + b += k[1]; + c += k[2]; + mix(a,b,c); + length -= 12; + k += 3; + } + + /*----------------------------- handle the last (probably partial) block */ + /* + * "k[2]&0xffffff" actually reads beyond the end of the string, but + * then masks off the part it's not allowed to read. Because the + * string is aligned, the masked-off tail is in the same word as the + * rest of the string. Every machine with memory protection I've seen + * does it on word boundaries, so is OK with this. But VALGRIND will + * still catch it and complain. The masking trick does make the hash + * noticably faster for short strings (like English words). + */ +#ifndef VALGRIND + + switch(length) + { + case 12: c+=k[2]; b+=k[1]; a+=k[0]; break; + case 11: c+=k[2]&0xffffff; b+=k[1]; a+=k[0]; break; + case 10: c+=k[2]&0xffff; b+=k[1]; a+=k[0]; break; + case 9 : c+=k[2]&0xff; b+=k[1]; a+=k[0]; break; + case 8 : b+=k[1]; a+=k[0]; break; + case 7 : b+=k[1]&0xffffff; a+=k[0]; break; + case 6 : b+=k[1]&0xffff; a+=k[0]; break; + case 5 : b+=k[1]&0xff; a+=k[0]; break; + case 4 : a+=k[0]; break; + case 3 : a+=k[0]&0xffffff; break; + case 2 : a+=k[0]&0xffff; break; + case 1 : a+=k[0]&0xff; break; + case 0 : return c; /* zero length strings require no mixing */ + } + +#else /* make valgrind happy */ + + const uint8_t *k8 = (const uint8_t *)k; + switch(length) + { + case 12: c+=k[2]; b+=k[1]; a+=k[0]; break; + case 11: c+=((uint32_t)k8[10])<<16; /* fall through */ + case 10: c+=((uint32_t)k8[9])<<8; /* fall through */ + case 9 : c+=k8[8]; /* fall through */ + case 8 : b+=k[1]; a+=k[0]; break; + case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */ + case 6 : b+=((uint32_t)k8[5])<<8; /* fall through */ + case 5 : b+=k8[4]; /* fall through */ + case 4 : a+=k[0]; break; + case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */ + case 2 : a+=((uint32_t)k8[1])<<8; /* fall through */ + case 1 : a+=k8[0]; break; + case 0 : return c; + } + +#endif /* !valgrind */ + + } else if (HASH_LITTLE_ENDIAN && ((u.i & 0x1) == 0)) { + const uint16_t *k = (const uint16_t *)key; /* read 16-bit chunks */ + const uint8_t *k8; + + /*--------------- all but last block: aligned reads and different mixing */ + while (length > 12) + { + a += k[0] + (((uint32_t)k[1])<<16); + b += k[2] + (((uint32_t)k[3])<<16); + c += k[4] + (((uint32_t)k[5])<<16); + mix(a,b,c); + length -= 12; + k += 6; + } + + /*----------------------------- handle the last (probably partial) block */ + k8 = (const uint8_t *)k; + switch(length) + { + case 12: c+=k[4]+(((uint32_t)k[5])<<16); + b+=k[2]+(((uint32_t)k[3])<<16); + a+=k[0]+(((uint32_t)k[1])<<16); + break; + case 11: c+=((uint32_t)k8[10])<<16; /* fall through */ + case 10: c+=k[4]; + b+=k[2]+(((uint32_t)k[3])<<16); + a+=k[0]+(((uint32_t)k[1])<<16); + break; + case 9 : c+=k8[8]; /* fall through */ + case 8 : b+=k[2]+(((uint32_t)k[3])<<16); + a+=k[0]+(((uint32_t)k[1])<<16); + break; + case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */ + case 6 : b+=k[2]; + a+=k[0]+(((uint32_t)k[1])<<16); + break; + case 5 : b+=k8[4]; /* fall through */ + case 4 : a+=k[0]+(((uint32_t)k[1])<<16); + break; + case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */ + case 2 : a+=k[0]; + break; + case 1 : a+=k8[0]; + break; + case 0 : return c; /* zero length requires no mixing */ + } + + } else { /* need to read the key one byte at a time */ + const uint8_t *k = (const uint8_t *)key; + + /*--------------- all but the last block: affect some 32 bits of (a,b,c) */ + while (length > 12) + { + a += k[0]; + a += ((uint32_t)k[1])<<8; + a += ((uint32_t)k[2])<<16; + a += ((uint32_t)k[3])<<24; + b += k[4]; + b += ((uint32_t)k[5])<<8; + b += ((uint32_t)k[6])<<16; + b += ((uint32_t)k[7])<<24; + c += k[8]; + c += ((uint32_t)k[9])<<8; + c += ((uint32_t)k[10])<<16; + c += ((uint32_t)k[11])<<24; + mix(a,b,c); + length -= 12; + k += 12; + } + + /*-------------------------------- last block: affect all 32 bits of (c) */ + switch(length) /* all the case statements fall through */ + { + case 12: c+=((uint32_t)k[11])<<24; + case 11: c+=((uint32_t)k[10])<<16; + case 10: c+=((uint32_t)k[9])<<8; + case 9 : c+=k[8]; + case 8 : b+=((uint32_t)k[7])<<24; + case 7 : b+=((uint32_t)k[6])<<16; + case 6 : b+=((uint32_t)k[5])<<8; + case 5 : b+=k[4]; + case 4 : a+=((uint32_t)k[3])<<24; + case 3 : a+=((uint32_t)k[2])<<16; + case 2 : a+=((uint32_t)k[1])<<8; + case 1 : a+=k[0]; + break; + case 0 : return c; + } + } + + final(a,b,c); + return c; +} + +unsigned long lh_char_hash(const void *k) +{ + static volatile int random_seed = -1; + + if (random_seed == -1) { + int seed; + /* we can't use -1 as it is the unitialized sentinel */ + while ((seed = json_c_get_random_seed()) == -1); +#if defined __GNUC__ + __sync_val_compare_and_swap(&random_seed, -1, seed); +#elif defined _MSC_VER + InterlockedCompareExchange(&random_seed, seed, -1); +#else +#warning "racy random seed initializtion if used by multiple threads" + random_seed = seed; /* potentially racy */ +#endif + } + + return hashlittle((const char*)k, strlen((const char*)k), random_seed); +} + +int lh_char_equal(const void *k1, const void *k2) +{ + return (strcmp((const char*)k1, (const char*)k2) == 0); +} + +struct lh_table* lh_table_new(int size, const char *name, + lh_entry_free_fn *free_fn, + lh_hash_fn *hash_fn, + lh_equal_fn *equal_fn) +{ + int i; + struct lh_table *t; + + t = (struct lh_table*)calloc(1, sizeof(struct lh_table)); + if(!t) lh_abort("lh_table_new: calloc failed\n"); + t->count = 0; + t->size = size; + t->name = name; + t->table = (struct lh_entry*)calloc(size, sizeof(struct lh_entry)); + if(!t->table) lh_abort("lh_table_new: calloc failed\n"); + t->free_fn = free_fn; + t->hash_fn = hash_fn; + t->equal_fn = equal_fn; + for(i = 0; i < size; i++) t->table[i].k = LH_EMPTY; + return t; +} + +struct lh_table* lh_kchar_table_new(int size, const char *name, + lh_entry_free_fn *free_fn) +{ + return lh_table_new(size, name, free_fn, lh_char_hash, lh_char_equal); +} + +struct lh_table* lh_kptr_table_new(int size, const char *name, + lh_entry_free_fn *free_fn) +{ + return lh_table_new(size, name, free_fn, lh_ptr_hash, lh_ptr_equal); +} + +void lh_table_resize(struct lh_table *t, int new_size) +{ + struct lh_table *new_t; + struct lh_entry *ent; + + new_t = lh_table_new(new_size, t->name, NULL, t->hash_fn, t->equal_fn); + ent = t->head; + while(ent) { + lh_table_insert(new_t, ent->k, ent->v); + ent = ent->next; + } + free(t->table); + t->table = new_t->table; + t->size = new_size; + t->head = new_t->head; + t->tail = new_t->tail; + t->resizes++; + free(new_t); +} + +void lh_table_free(struct lh_table *t) +{ + struct lh_entry *c; + for(c = t->head; c != NULL; c = c->next) { + if(t->free_fn) { + t->free_fn(c); + } + } + free(t->table); + free(t); +} + + +int lh_table_insert(struct lh_table *t, void *k, const void *v) +{ + unsigned long h, n; + + t->inserts++; + if(t->count >= t->size * LH_LOAD_FACTOR) lh_table_resize(t, t->size * 2); + + h = t->hash_fn(k); + n = h % t->size; + + while( 1 ) { + if(t->table[n].k == LH_EMPTY || t->table[n].k == LH_FREED) break; + t->collisions++; + if ((int)++n == t->size) n = 0; + } + + t->table[n].k = k; + t->table[n].v = v; + t->count++; + + if(t->head == NULL) { + t->head = t->tail = &t->table[n]; + t->table[n].next = t->table[n].prev = NULL; + } else { + t->tail->next = &t->table[n]; + t->table[n].prev = t->tail; + t->table[n].next = NULL; + t->tail = &t->table[n]; + } + + return 0; +} + + +struct lh_entry* lh_table_lookup_entry(struct lh_table *t, const void *k) +{ + unsigned long h = t->hash_fn(k); + unsigned long n = h % t->size; + int count = 0; + + t->lookups++; + while( count < t->size ) { + if(t->table[n].k == LH_EMPTY) return NULL; + if(t->table[n].k != LH_FREED && + t->equal_fn(t->table[n].k, k)) return &t->table[n]; + if ((int)++n == t->size) n = 0; + count++; + } + return NULL; +} + + +const void* lh_table_lookup(struct lh_table *t, const void *k) +{ + void *result; + lh_table_lookup_ex(t, k, &result); + return result; +} + +json_bool lh_table_lookup_ex(struct lh_table* t, const void* k, void **v) +{ + struct lh_entry *e = lh_table_lookup_entry(t, k); + if (e != NULL) { + if (v != NULL) *v = (void *)e->v; + return TRUE; /* key found */ + } + if (v != NULL) *v = NULL; + return FALSE; /* key not found */ +} + +int lh_table_delete_entry(struct lh_table *t, struct lh_entry *e) +{ + ptrdiff_t n = (ptrdiff_t)(e - t->table); /* CAW: fixed to be 64bit nice, still need the crazy negative case... */ + + /* CAW: this is bad, really bad, maybe stack goes other direction on this machine... */ + if(n < 0) { return -2; } + + if(t->table[n].k == LH_EMPTY || t->table[n].k == LH_FREED) return -1; + t->count--; + if(t->free_fn) t->free_fn(e); + t->table[n].v = NULL; + t->table[n].k = LH_FREED; + if(t->tail == &t->table[n] && t->head == &t->table[n]) { + t->head = t->tail = NULL; + } else if (t->head == &t->table[n]) { + t->head->next->prev = NULL; + t->head = t->head->next; + } else if (t->tail == &t->table[n]) { + t->tail->prev->next = NULL; + t->tail = t->tail->prev; + } else { + t->table[n].prev->next = t->table[n].next; + t->table[n].next->prev = t->table[n].prev; + } + t->table[n].next = t->table[n].prev = NULL; + return 0; +} + + +int lh_table_delete(struct lh_table *t, const void *k) +{ + struct lh_entry *e = lh_table_lookup_entry(t, k); + if(!e) return -1; + return lh_table_delete_entry(t, e); +} + +int lh_table_length(struct lh_table *t) +{ + return t->count; +} diff --git a/tools/CustomSetupTool/CustomSetupTool/json-c/linkhash.h b/tools/CustomSetupTool/CustomSetupTool/json-c/linkhash.h new file mode 100644 index 000000000000..950d09f35d70 --- /dev/null +++ b/tools/CustomSetupTool/CustomSetupTool/json-c/linkhash.h @@ -0,0 +1,292 @@ +/* + * $Id: linkhash.h,v 1.6 2006/01/30 23:07:57 mclark Exp $ + * + * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. + * Michael Clark + * Copyright (c) 2009 Hewlett-Packard Development Company, L.P. + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See COPYING for details. + * + */ + +#ifndef _linkhash_h_ +#define _linkhash_h_ + +#include "json_object.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * golden prime used in hash functions + */ +#define LH_PRIME 0x9e370001UL + +/** + * The fraction of filled hash buckets until an insert will cause the table + * to be resized. + * This can range from just above 0 up to 1.0. + */ +#define LH_LOAD_FACTOR 0.66 + +/** + * sentinel pointer value for empty slots + */ +#define LH_EMPTY (void*)-1 + +/** + * sentinel pointer value for freed slots + */ +#define LH_FREED (void*)-2 + +struct lh_entry; + +/** + * callback function prototypes + */ +typedef void (lh_entry_free_fn) (struct lh_entry *e); +/** + * callback function prototypes + */ +typedef unsigned long (lh_hash_fn) (const void *k); +/** + * callback function prototypes + */ +typedef int (lh_equal_fn) (const void *k1, const void *k2); + +/** + * An entry in the hash table + */ +struct lh_entry { + /** + * The key. + */ + void *k; + /** + * The value. + */ + const void *v; + /** + * The next entry + */ + struct lh_entry *next; + /** + * The previous entry. + */ + struct lh_entry *prev; +}; + + +/** + * The hash table structure. + */ +struct lh_table { + /** + * Size of our hash. + */ + int size; + /** + * Numbers of entries. + */ + int count; + + /** + * Number of collisions. + */ + int collisions; + + /** + * Number of resizes. + */ + int resizes; + + /** + * Number of lookups. + */ + int lookups; + + /** + * Number of inserts. + */ + int inserts; + + /** + * Number of deletes. + */ + int deletes; + + /** + * Name of the hash table. + */ + const char *name; + + /** + * The first entry. + */ + struct lh_entry *head; + + /** + * The last entry. + */ + struct lh_entry *tail; + + struct lh_entry *table; + + /** + * A pointer onto the function responsible for freeing an entry. + */ + lh_entry_free_fn *free_fn; + lh_hash_fn *hash_fn; + lh_equal_fn *equal_fn; +}; + + +/** + * Pre-defined hash and equality functions + */ +extern unsigned long lh_ptr_hash(const void *k); +extern int lh_ptr_equal(const void *k1, const void *k2); + +extern unsigned long lh_char_hash(const void *k); +extern int lh_char_equal(const void *k1, const void *k2); + + +/** + * Convenience list iterator. + */ +#define lh_foreach(table, entry) \ +for(entry = table->head; entry; entry = entry->next) + +/** + * lh_foreach_safe allows calling of deletion routine while iterating. + */ +#define lh_foreach_safe(table, entry, tmp) \ +for(entry = table->head; entry && ((tmp = entry->next) || 1); entry = tmp) + + + +/** + * Create a new linkhash table. + * @param size initial table size. The table is automatically resized + * although this incurs a performance penalty. + * @param name the table name. + * @param free_fn callback function used to free memory for entries + * when lh_table_free or lh_table_delete is called. + * If NULL is provided, then memory for keys and values + * must be freed by the caller. + * @param hash_fn function used to hash keys. 2 standard ones are defined: + * lh_ptr_hash and lh_char_hash for hashing pointer values + * and C strings respectively. + * @param equal_fn comparison function to compare keys. 2 standard ones defined: + * lh_ptr_hash and lh_char_hash for comparing pointer values + * and C strings respectively. + * @return a pointer onto the linkhash table. + */ +extern struct lh_table* lh_table_new(int size, const char *name, + lh_entry_free_fn *free_fn, + lh_hash_fn *hash_fn, + lh_equal_fn *equal_fn); + +/** + * Convenience function to create a new linkhash + * table with char keys. + * @param size initial table size. + * @param name table name. + * @param free_fn callback function used to free memory for entries. + * @return a pointer onto the linkhash table. + */ +extern struct lh_table* lh_kchar_table_new(int size, const char *name, + lh_entry_free_fn *free_fn); + + +/** + * Convenience function to create a new linkhash + * table with ptr keys. + * @param size initial table size. + * @param name table name. + * @param free_fn callback function used to free memory for entries. + * @return a pointer onto the linkhash table. + */ +extern struct lh_table* lh_kptr_table_new(int size, const char *name, + lh_entry_free_fn *free_fn); + + +/** + * Free a linkhash table. + * If a callback free function is provided then it is called for all + * entries in the table. + * @param t table to free. + */ +extern void lh_table_free(struct lh_table *t); + + +/** + * Insert a record into the table. + * @param t the table to insert into. + * @param k a pointer to the key to insert. + * @param v a pointer to the value to insert. + */ +extern int lh_table_insert(struct lh_table *t, void *k, const void *v); + + +/** + * Lookup a record into the table. + * @param t the table to lookup + * @param k a pointer to the key to lookup + * @return a pointer to the record structure of the value or NULL if it does not exist. + */ +extern struct lh_entry* lh_table_lookup_entry(struct lh_table *t, const void *k); + +/** + * Lookup a record into the table + * @param t the table to lookup + * @param k a pointer to the key to lookup + * @return a pointer to the found value or NULL if it does not exist. + * @deprecated Use lh_table_lookup_ex instead. + */ +THIS_FUNCTION_IS_DEPRECATED(extern const void* lh_table_lookup(struct lh_table *t, const void *k)); + +/** + * Lookup a record in the table + * @param t the table to lookup + * @param k a pointer to the key to lookup + * @param v a pointer to a where to store the found value (set to NULL if it doesn't exist). + * @return whether or not the key was found + */ +extern json_bool lh_table_lookup_ex(struct lh_table *t, const void *k, void **v); + +/** + * Delete a record from the table. + * If a callback free function is provided then it is called for the + * for the item being deleted. + * @param t the table to delete from. + * @param e a pointer to the entry to delete. + * @return 0 if the item was deleted. + * @return -1 if it was not found. + */ +extern int lh_table_delete_entry(struct lh_table *t, struct lh_entry *e); + + +/** + * Delete a record from the table. + * If a callback free function is provided then it is called for the + * for the item being deleted. + * @param t the table to delete from. + * @param k a pointer to the key to delete. + * @return 0 if the item was deleted. + * @return -1 if it was not found. + */ +extern int lh_table_delete(struct lh_table *t, const void *k); + +extern int lh_table_length(struct lh_table *t); + +void lh_abort(const char *msg, ...); +void lh_table_resize(struct lh_table *t, int new_size); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/tools/CustomSetupTool/CustomSetupTool/json-c/math_compat.h b/tools/CustomSetupTool/CustomSetupTool/json-c/math_compat.h new file mode 100644 index 000000000000..f40b8faf8fd4 --- /dev/null +++ b/tools/CustomSetupTool/CustomSetupTool/json-c/math_compat.h @@ -0,0 +1,28 @@ +#ifndef __math_compat_h +#define __math_compat_h + +/* Define isnan and isinf on Windows/MSVC */ + +#ifndef HAVE_DECL_ISNAN +# ifdef HAVE_DECL__ISNAN +#include +#define isnan(x) _isnan(x) +# endif +#endif + +#ifndef HAVE_DECL_ISINF +# ifdef HAVE_DECL__FINITE +#include +#define isinf(x) (!_finite(x)) +# endif +#endif + +#ifndef HAVE_DECL_NAN +#error This platform does not have nan() +#endif + +#ifndef HAVE_DECL_INFINITY +#error This platform does not have INFINITY +#endif + +#endif diff --git a/tools/CustomSetupTool/CustomSetupTool/json-c/printbuf.c b/tools/CustomSetupTool/CustomSetupTool/json-c/printbuf.c new file mode 100644 index 000000000000..94d41b0d6a5e --- /dev/null +++ b/tools/CustomSetupTool/CustomSetupTool/json-c/printbuf.c @@ -0,0 +1,194 @@ +/* + * $Id: printbuf.c,v 1.5 2006/01/26 02:16:28 mclark Exp $ + * + * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. + * Michael Clark + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See COPYING for details. + * + * + * Copyright (c) 2008-2009 Yahoo! Inc. All rights reserved. + * The copyrights to the contents of this file are licensed under the MIT License + * (http://www.opensource.org/licenses/mit-license.php) + */ + +#include "config.h" + +#include +#include +#include + +#ifdef HAVE_STDARG_H +# include +#else /* !HAVE_STDARG_H */ +# error Not enough var arg support! +#endif /* HAVE_STDARG_H */ + +#include "bits.h" +#include "debug.h" +#include "printbuf.h" + +static int printbuf_extend(struct printbuf *p, size_t min_size); + +struct printbuf* printbuf_new(void) +{ + struct printbuf *p; + + p = (struct printbuf*)calloc(1, sizeof(struct printbuf)); + if(!p) return NULL; + p->size = 32; + p->bpos = 0; + if(!(p->buf = (char*)malloc(p->size))) { + free(p); + return NULL; + } + return p; +} + + +/** + * Extend the buffer p so it has a size of at least min_size. + * + * If the current size is large enough, nothing is changed. + * + * Note: this does not check the available space! The caller + * is responsible for performing those calculations. + */ +static int printbuf_extend(struct printbuf *p, size_t min_size) +{ + char *t; + size_t new_size; + + if (p->size >= min_size) + return 0; + + new_size = json_max(p->size * 2, min_size + 8); +#ifdef PRINTBUF_DEBUG + MC_DEBUG("printbuf_memappend: realloc " + "bpos=%d min_size=%d old_size=%d new_size=%d\n", + p->bpos, min_size, p->size, new_size); +#endif /* PRINTBUF_DEBUG */ + if(!(t = (char*)realloc(p->buf, new_size))) + return -1; + p->size = new_size; + p->buf = t; + return 0; +} + +size_t printbuf_memappend(struct printbuf *p, const char *buf, size_t size) +{ + if (p->size <= p->bpos + size + 1) { + if (printbuf_extend(p, p->bpos + size + 1) < 0) + return -1; + } + memcpy(p->buf + p->bpos, buf, size); + p->bpos += size; + p->buf[p->bpos]= '\0'; + return size; +} + +int printbuf_memset(struct printbuf *pb, size_t offset, int charvalue, size_t len) +{ + size_t size_needed; + + if (offset == -1) + offset = pb->bpos; + size_needed = offset + len; + if (pb->size < size_needed) + { + if (printbuf_extend(pb, size_needed) < 0) + return -1; + } + + memset(pb->buf + offset, charvalue, len); + if (pb->bpos < size_needed) + pb->bpos = size_needed; + + return 0; +} + +#if !defined(HAVE_VSNPRINTF) && defined(_MSC_VER) +# define vsnprintf _vsnprintf +#elif !defined(HAVE_VSNPRINTF) /* !HAVE_VSNPRINTF */ +# error Need vsnprintf! +#endif /* !HAVE_VSNPRINTF && defined(_WIN32) */ + +#if !defined(HAVE_VASPRINTF) +/* CAW: compliant version of vasprintf */ +static int vasprintf(char **buf, const char *fmt, va_list ap) +{ +#ifndef _WIN32 + static char _T_emptybuffer = '\0'; +#endif /* !defined(_WIN32) */ + int chars; + char *b; + + if(!buf) { return -1; } + +#ifdef _WIN32 + chars = _vscprintf(fmt, ap)+1; +#else /* !defined(_WIN32) */ + /* CAW: RAWR! We have to hope to god here that vsnprintf doesn't overwrite + our buffer like on some 64bit sun systems.... but hey, its time to move on */ + chars = vsnprintf(&_T_emptybuffer, 0, fmt, ap)+1; + if(chars < 0) { chars *= -1; } /* CAW: old glibc versions have this problem */ +#endif /* defined(_WIN32) */ + + b = (char*)malloc(sizeof(char) * chars); + if(!b) { return -1; } + + if ((chars = vsprintf_s(b, sizeof(char), fmt, ap)) < 0) + { + free(b); + } + else + { + *buf = b; + } + + return chars; +} +#endif /* !HAVE_VASPRINTF */ + +int sprintbuf(struct printbuf *p, const char *msg, ...) +{ + va_list ap; + char *t; + int size; + char buf[128]; + + /* user stack buffer first */ + va_start(ap, msg); + size = _vsnprintf_s(buf, sizeof(buf), _TRUNCATE, msg, ap); + va_end(ap); + /* if string is greater than stack buffer, then use dynamic string + with vasprintf. Note: some implementation of vsnprintf return -1 + if output is truncated whereas some return the number of bytes that + would have been written - this code handles both cases. */ + if(size == -1 || size > 127) { + va_start(ap, msg); + if((size = vasprintf(&t, msg, ap)) < 0) { va_end(ap); return -1; } + va_end(ap); + printbuf_memappend(p, t, size); + free(t); + return size; + } else { + printbuf_memappend(p, buf, size); + return size; + } +} + +void printbuf_reset(struct printbuf *p) +{ + p->buf[0] = '\0'; + p->bpos = 0; +} + +void printbuf_free(struct printbuf *p) +{ + if(p) { + free(p->buf); + free(p); + } +} diff --git a/tools/CustomSetupTool/CustomSetupTool/json-c/printbuf.h b/tools/CustomSetupTool/CustomSetupTool/json-c/printbuf.h new file mode 100644 index 000000000000..ed003b61f3c2 --- /dev/null +++ b/tools/CustomSetupTool/CustomSetupTool/json-c/printbuf.h @@ -0,0 +1,81 @@ +/* + * $Id: printbuf.h,v 1.4 2006/01/26 02:16:28 mclark Exp $ + * + * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. + * Michael Clark + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See COPYING for details. + * + * + * Copyright (c) 2008-2009 Yahoo! Inc. All rights reserved. + * The copyrights to the contents of this file are licensed under the MIT License + * (http://www.opensource.org/licenses/mit-license.php) + */ + +#ifndef _printbuf_h_ +#define _printbuf_h_ + +#ifdef __cplusplus +extern "C" { +#endif + +struct printbuf { + char *buf; + size_t bpos; + size_t size; +}; + +extern struct printbuf* +printbuf_new(void); + +/* As an optimization, printbuf_memappend_fast is defined as a macro + * that handles copying data if the buffer is large enough; otherwise + * it invokes printbuf_memappend_real() which performs the heavy + * lifting of realloc()ing the buffer and copying data. + * Your code should not use printbuf_memappend directly--use + * printbuf_memappend_fast instead. + */ +extern size_t printbuf_memappend(struct printbuf *p, const char *buf, size_t size); + +__inline void printbuf_memappend_fast(struct printbuf *p, const char *bufptr, size_t bufsize) +{ + if ((p->size - p->bpos) > bufsize) + { + memcpy(p->buf + p->bpos, (bufptr), bufsize); + p->bpos += (int)bufsize; + p->buf[p->bpos] = '\0'; + } + else + { + printbuf_memappend(p, (bufptr), bufsize); + } +} + +#define printbuf_length(p) ((p)->bpos) + +/** + * Set len bytes of the buffer to charvalue, starting at offset offset. + * Similar to calling memset(x, charvalue, len); + * + * The memory allocated for the buffer is extended as necessary. + * + * If offset is -1, this starts at the end of the current data in the buffer. + */ +extern int +printbuf_memset(struct printbuf *pb, size_t offset, int charvalue, size_t len); + +extern int +sprintbuf(struct printbuf *p, const char *msg, ...); + +extern void +printbuf_reset(struct printbuf *p); + +extern void +printbuf_free(struct printbuf *p); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/tools/CustomSetupTool/CustomSetupTool/json-c/random_seed.c b/tools/CustomSetupTool/CustomSetupTool/json-c/random_seed.c new file mode 100644 index 000000000000..ece374e5b74e --- /dev/null +++ b/tools/CustomSetupTool/CustomSetupTool/json-c/random_seed.c @@ -0,0 +1,238 @@ +/* + * random_seed.c + * + * Copyright (c) 2013 Metaparadigm Pte. Ltd. + * Michael Clark + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See COPYING for details. + * + */ + +#include +#include "config.h" + +#define DEBUG_SEED(s) + + +#if defined ENABLE_RDRAND + +/* cpuid */ + +#if defined __GNUC__ && (defined __i386__ || defined __x86_64__) +#define HAS_X86_CPUID 1 + +static void do_cpuid(int regs[], int h) +{ + __asm__ __volatile__( +#if defined __x86_64__ + "pushq %%rbx;\n" +#else + "pushl %%ebx;\n" +#endif + "cpuid;\n" +#if defined __x86_64__ + "popq %%rbx;\n" +#else + "popl %%ebx;\n" +#endif + : "=a"(regs[0]), [ebx] "=r"(regs[1]), "=c"(regs[2]), "=d"(regs[3]) + : "a"(h)); +} + +#elif defined _MSC_VER + +#define HAS_X86_CPUID 1 +#define do_cpuid __cpuid + +#endif + +/* has_rdrand */ + +#if HAS_X86_CPUID + +static int has_rdrand() +{ + // CPUID.01H:ECX.RDRAND[bit 30] == 1 + int regs[4]; + do_cpuid(regs, 1); + return (regs[2] & (1 << 30)) != 0; +} + +#endif + +/* get_rdrand_seed - GCC x86 and X64 */ + +#if defined __GNUC__ && (defined __i386__ || defined __x86_64__) + +#define HAVE_RDRAND 1 + +static int get_rdrand_seed() +{ + DEBUG_SEED("get_rdrand_seed"); + int _eax; + // rdrand eax + __asm__ __volatile__("1: .byte 0x0F\n" + " .byte 0xC7\n" + " .byte 0xF0\n" + " jnc 1b;\n" + : "=a" (_eax)); + return _eax; +} + +#endif + +#if defined _MSC_VER + +#if _MSC_VER >= 1700 +#define HAVE_RDRAND 1 + +/* get_rdrand_seed - Visual Studio 2012 and above */ + +static int get_rdrand_seed() +{ + DEBUG_SEED("get_rdrand_seed"); + int r; + while (_rdrand32_step(&r) == 0); + return r; +} + +#elif defined _M_IX86 +#define HAVE_RDRAND 1 + +/* get_rdrand_seed - Visual Studio 2010 and below - x86 only */ + +static int get_rdrand_seed() +{ + DEBUG_SEED("get_rdrand_seed"); + int _eax; +retry: + // rdrand eax + __asm _emit 0x0F __asm _emit 0xC7 __asm _emit 0xF0 + __asm jnc retry + __asm mov _eax, eax + return _eax; +} + +#endif +#endif + +#endif /* defined ENABLE_RDRAND */ + + +/* has_dev_urandom */ + +#if defined (__APPLE__) || defined(__unix__) || defined(__linux__) + +#include +#include +#include +#include +#include +#include + +#define HAVE_DEV_RANDOM 1 + +static const char *dev_random_file = "/dev/urandom"; + +static int has_dev_urandom() +{ + struct stat buf; + if (stat(dev_random_file, &buf)) { + return 0; + } + return ((buf.st_mode & S_IFCHR) != 0); +} + + +/* get_dev_random_seed */ + +static int get_dev_random_seed() +{ + DEBUG_SEED("get_dev_random_seed"); + + int fd = open(dev_random_file, O_RDONLY); + if (fd < 0) { + fprintf(stderr, "error opening %s: %s", dev_random_file, strerror(errno)); + exit(1); + } + + int r; + ssize_t nread = read(fd, &r, sizeof(r)); + if (nread != sizeof(r)) { + fprintf(stderr, "error read %s: %s", dev_random_file, strerror(errno)); + exit(1); + } + else if (nread != sizeof(r)) { + fprintf(stderr, "error short read %s", dev_random_file); + exit(1); + } + close(fd); + return r; +} + +#endif + + +/* get_cryptgenrandom_seed */ + +#ifdef _WIN32 + +#define HAVE_CRYPTGENRANDOM 1 + +#include + +static int get_cryptgenrandom_seed() +{ + DEBUG_SEED("get_cryptgenrandom_seed"); + + HCRYPTPROV hProvider = 0; + int r; + + if (!CryptAcquireContextW(&hProvider, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) + { + fprintf(stderr, "error CryptAcquireContextW"); + exit(1); + } + + if (!CryptGenRandom(hProvider, sizeof(r), (BYTE*)&r)) + { + fprintf(stderr, "error CryptGenRandom"); + exit(1); + } + + CryptReleaseContext(hProvider, 0); + + return r; +} + +#endif + + +/* get_time_seed */ + +#include + +static int get_time_seed() +{ + DEBUG_SEED("get_time_seed"); + + return (int)time(NULL) * 433494437; +} + + +/* json_c_get_random_seed */ + +int json_c_get_random_seed() +{ +#if HAVE_RDRAND + if (has_rdrand()) return get_rdrand_seed(); +#endif +#if HAVE_DEV_RANDOM + if (has_dev_urandom()) return get_dev_random_seed(); +#endif +#if HAVE_CRYPTGENRANDOM + return get_cryptgenrandom_seed(); +#endif + return get_time_seed(); +} diff --git a/tools/CustomSetupTool/CustomSetupTool/json-c/random_seed.h b/tools/CustomSetupTool/CustomSetupTool/json-c/random_seed.h new file mode 100644 index 000000000000..7362d67d9cd5 --- /dev/null +++ b/tools/CustomSetupTool/CustomSetupTool/json-c/random_seed.h @@ -0,0 +1,25 @@ +/* + * random_seed.h + * + * Copyright (c) 2013 Metaparadigm Pte. Ltd. + * Michael Clark + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See COPYING for details. + * + */ + +#ifndef seed_h +#define seed_h + +#ifdef __cplusplus +extern "C" { +#endif + +extern int json_c_get_random_seed(); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/tools/CustomSetupTool/CustomSetupTool/main.c b/tools/CustomSetupTool/CustomSetupTool/main.c index 19103442a8c2..9318c1dd44a9 100644 --- a/tools/CustomSetupTool/CustomSetupTool/main.c +++ b/tools/CustomSetupTool/CustomSetupTool/main.c @@ -170,6 +170,7 @@ INT WINAPI wWinMain( propSheetPage.pfnDlgProc = SetupPropPage3_WndProc; pages[propSheetHeader.nPages++] = CreatePropertySheetPage(&propSheetPage); +#ifdef PH_BUILD_API memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); propSheetPage.dwSize = sizeof(PROPSHEETPAGE); propSheetPage.dwFlags = PSP_USETITLE; @@ -177,6 +178,15 @@ INT WINAPI wWinMain( propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_DIALOG4); propSheetPage.pfnDlgProc = SetupPropPage4_WndProc; pages[propSheetHeader.nPages++] = CreatePropertySheetPage(&propSheetPage); +#else + memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); + propSheetPage.dwSize = sizeof(PROPSHEETPAGE); + propSheetPage.dwFlags = PSP_USETITLE; + propSheetPage.pszTitle = PhApplicationName; + propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_DIALOG4); + propSheetPage.pfnDlgProc = SetupPropPage5_WndProc; + pages[propSheetHeader.nPages++] = CreatePropertySheetPage(&propSheetPage); +#endif PhModalPropertySheet(&propSheetHeader); } diff --git a/tools/CustomSetupTool/CustomSetupTool/page2.c b/tools/CustomSetupTool/CustomSetupTool/page2.c index 3d04a4a180d6..016a431d7e9e 100644 --- a/tools/CustomSetupTool/CustomSetupTool/page2.c +++ b/tools/CustomSetupTool/CustomSetupTool/page2.c @@ -40,21 +40,9 @@ INT_PTR CALLBACK SetupPropPage2_WndProc( if (resourceBuffer = ExtractResourceToBuffer(MAKEINTRESOURCE(IDR_LICENCE_DATA))) { - if (eulaTextString = PhConvertMultiByteToUtf16(resourceBuffer)) + if (eulaTextString = PhConvertUtf8ToUtf16(resourceBuffer)) { - ULONG startPos, endPos; - - SendMessage(GetDlgItem(hwndDlg, IDC_EDIT1), EM_GETSEL, (WPARAM)&startPos, (WPARAM)&endPos); - - // move the caret to the end of the text - int outLength = GetWindowTextLength(GetDlgItem(hwndDlg, IDC_EDIT1)); - SendMessage(GetDlgItem(hwndDlg, IDC_EDIT1), EM_SETSEL, outLength, outLength); - - // insert the text at the new caret position - SendMessage(GetDlgItem(hwndDlg, IDC_EDIT1), EM_REPLACESEL, TRUE, (WPARAM)eulaTextString->Buffer); - - // restore the previous selection - SendMessage(GetDlgItem(hwndDlg, IDC_EDIT1), EM_SETSEL, startPos, endPos); + SetWindowText(GetDlgItem(hwndDlg, IDC_EDIT1), eulaTextString->Buffer); PhDereferenceObject(eulaTextString); } diff --git a/tools/CustomSetupTool/CustomSetupTool/page5.c b/tools/CustomSetupTool/CustomSetupTool/page5.c new file mode 100644 index 000000000000..dd6749c90bdc --- /dev/null +++ b/tools/CustomSetupTool/CustomSetupTool/page5.c @@ -0,0 +1,171 @@ +/* + * Process Hacker Toolchain - + * project setup + * + * Copyright (C) 2017 dmex + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include + +ULONG64 DownloadCurrentLength = 0; +ULONG64 DownloadTotalLength = 0; + +NTSTATUS SetupDownloadProgressThread( + _In_ PPH_SETUP_UNINSTALL_CONTEXT Context + ) +{ + if (SetupQueryUpdateData(Context)) + { + UpdateDownloadUpdateData(Context); + } + + PhDereferenceObject(Context); + return STATUS_SUCCESS; +} + +INT_PTR CALLBACK SetupPropPage5_WndProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _Inout_ WPARAM wParam, + _Inout_ LPARAM lParam + ) +{ + switch (uMsg) + { + case WM_INITDIALOG: + { + SetupLoadImage(GetDlgItem(hwndDlg, IDC_PROJECT_ICON), MAKEINTRESOURCE(IDB_PNG1)); + SetupInitializeFont(GetDlgItem(hwndDlg, IDC_MAINHEADER), -17, FW_SEMIBOLD); + //SetupInitializeFont(GetDlgItem(hwndDlg, IDC_SUBHEADER), -12, FW_NORMAL); + SetupInitializeFont(GetDlgItem(hwndDlg, IDC_INSTALL_STATUS), -12, FW_SEMIBOLD); + SetupInitializeFont(GetDlgItem(hwndDlg, IDC_INSTALL_SUBSTATUS), -12, FW_NORMAL); + + SetWindowText(GetDlgItem(hwndDlg, IDC_MAINHEADER), L"Starting download..."); + SetWindowText(GetDlgItem(hwndDlg, IDC_INSTALL_STATUS), L"Starting download..."); + SetWindowText(GetDlgItem(hwndDlg, IDC_INSTALL_SUBSTATUS), L""); + + // Setup the progress thread + PPH_SETUP_UNINSTALL_CONTEXT progress = PhCreateAlloc(sizeof(PH_SETUP_UNINSTALL_CONTEXT)); + memset(progress, 0, sizeof(PH_SETUP_UNINSTALL_CONTEXT)); + + progress->DialogHandle = hwndDlg; + progress->MainHeaderHandle = GetDlgItem(hwndDlg, IDC_MAINHEADER); + progress->StatusHandle = GetDlgItem(hwndDlg, IDC_INSTALL_STATUS); + progress->SubStatusHandle = GetDlgItem(hwndDlg, IDC_INSTALL_SUBSTATUS); + progress->ProgressHandle = GetDlgItem(hwndDlg, IDC_INSTALL_PROGRESS); + progress->CurrentMajorVersion = PHAPP_VERSION_MAJOR; + progress->CurrentMinorVersion = PHAPP_VERSION_MINOR; + progress->CurrentRevisionVersion = PHAPP_VERSION_REVISION; + + RtlQueueWorkItem(SetupDownloadProgressThread, progress, 0); + + EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); + } + break; + case WM_NOTIFY: + { + LPNMHDR header = (LPNMHDR)lParam; + LPPSHNOTIFY pageNotify = (LPPSHNOTIFY)header; + + switch (pageNotify->hdr.code) + { + case PSN_QUERYCANCEL: + { + if (SetupRunning && DialogPromptExit(hwndDlg)) + { + //PropSheet_CancelToClose(GetParent(hwndDlg)); + //EnableMenuItem(GetSystemMenu(GetParent(hwndDlg), FALSE), SC_CLOSE, MF_GRAYED); + //EnableMenuItem(GetSystemMenu(GetParent(hwndDlg), FALSE), SC_CLOSE, MF_ENABLED); + SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, (LPARAM)TRUE); + return TRUE; + } + } + break; + case PSN_SETACTIVE: + { + //HWND hwPropSheet; + //HANDLE threadHandle; + //PSETUP_PROGRESS_THREAD progress; + + //hwPropSheet = pageNotify->hdr.hwndFrom; + + //// Disable Next/Back buttons + //PropSheet_SetWizButtons(hwPropSheet, 0); + + //if (!SetupRunning) + //{ + // SetupRunning = TRUE; + + // // Setup the progress thread + // progress = PhCreateAlloc(sizeof(SETUP_PROGRESS_THREAD)); + // progress->DialogHandle = hwndDlg; + // progress->PropSheetHandle = hwPropSheet; + + // if (threadHandle = PhCreateThread(0, SetupDownloadProgressThread, progress)) + // NtClose(threadHandle); + //} + } + break; + } + } + break; + case WM_START_SETUP: + { + //SetWindowText(GetDlgItem(hwndDlg, IDC_MAINHEADER), + // PhaFormatString(L"Downloading Process Hacker %lu.%lu.%lu", PHAPP_VERSION_MAJOR, PHAPP_VERSION_MINOR, PHAPP_VERSION_REVISION)->Buffer); + //SetWindowText(GetDlgItem(hwndDlg, IDC_INSTALL_SUBSTATUS), L"Progress: ~ of ~ (0.0%)"); + //SendMessage(GetDlgItem(hwndDlg, IDC_INSTALL_PROGRESS), PBM_SETRANGE32, 0, (LPARAM)ExtractTotalLength); + } + break; + case WM_UPDATE_SETUP: + { + //PPH_STRING currentFile = (PPH_STRING)lParam; + // + ////SetWindowText(GetDlgItem(hwndDlg, IDC_INSTALL_STATUS), + //// PhaConcatStrings2(L"Extracting: ", currentFile->Buffer)->Buffer + //// ); + //SetWindowText(GetDlgItem(hwndDlg, IDC_INSTALL_SUBSTATUS), PhaFormatString( + // L"Progress: %s of %s (%.2f%%)", + // PhaFormatSize(ExtractCurrentLength, -1)->Buffer, + // PhaFormatSize(ExtractTotalLength, -1)->Buffer, + // (FLOAT)((double)ExtractCurrentLength / (double)ExtractTotalLength) * 100 + // )->Buffer); + //SendMessage(GetDlgItem(hwndDlg, IDC_INSTALL_PROGRESS), PBM_SETPOS, (WPARAM)ExtractCurrentLength, 0); + // + //PhDereferenceObject(currentFile); + } + break; + case WM_END_SETUP: + { + SetupRunning = FALSE; + + SetWindowText(GetDlgItem(hwndDlg, IDC_MAINHEADER), L"Setup Complete"); + SetWindowText(GetDlgItem(hwndDlg, IDC_INSTALL_STATUS), L"Extract complete"); + Button_SetText(GetDlgItem(GetParent(hwndDlg), IDC_PROPSHEET_CANCEL), L"Close"); + + if (SetupStartAppAfterExit) + { + SetupExecuteProcessHacker(GetParent(hwndDlg)); + PropSheet_PressButton(GetParent(hwndDlg), PSBTN_FINISH); + } + } + break; + } + + return FALSE; +} \ No newline at end of file diff --git a/tools/CustomSetupTool/CustomSetupTool/resource.h b/tools/CustomSetupTool/CustomSetupTool/resource.h index a16b725cff7e..49bdd138ee8f 100644 --- a/tools/CustomSetupTool/CustomSetupTool/resource.h +++ b/tools/CustomSetupTool/CustomSetupTool/resource.h @@ -3,15 +3,16 @@ // Used by resource.rc // #define IDD_DIALOG1 101 -#define IDD_DIALOG2 103 -#define IDD_DIALOG4 105 -#define IDD_DIALOG3 108 -#define IDD_ERROR 109 -#define IDI_ICON1 143 -#define IDB_PNG1 144 -#define IDR_BIN_DATA 150 -#define IDR_LICENCE_DATA 155 +#define IDD_DIALOG2 102 +#define IDD_DIALOG4 103 +#define IDD_DIALOG3 104 +#define IDD_ERROR 105 +#define IDI_ICON1 106 +#define IDB_PNG1 107 +#define IDR_LICENCE_DATA 108 +#define IDR_BIN_DATA 109 #define IDC_MAINHEADER 1001 +#define IDC_MAINHEADER2 1002 #define IDC_INSTALL_PROGRESS 1005 #define IDC_SUBHEADER 1047 #define IDC_EDIT1 1048 @@ -29,7 +30,6 @@ #define IDC_INSTALL_DIRECTORY 1065 #define IDC_INSTALL_SUBSTATUS 1065 #define IDC_RESET_CHECK 1066 -#define IDC_DEVBUILDS_CHECK 1066 #define IDC_RESET_CHECK2 1067 #define IDC_SHORTCUT_CHECK 1068 #define IDC_STATIC1 1069 @@ -37,16 +37,15 @@ #define IDC_STATIC3 1071 #define IDC_SYSLINK1 1076 #define IDC_SYSLINK2 1077 -#define IDC_BUTTON1 1079 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NO_MFC 1 -#define _APS_NEXT_RESOURCE_VALUE 156 +#define _APS_NEXT_RESOURCE_VALUE 110 #define _APS_NEXT_COMMAND_VALUE 40002 -#define _APS_NEXT_CONTROL_VALUE 1080 -#define _APS_NEXT_SYMED_VALUE 101 +#define _APS_NEXT_CONTROL_VALUE 1078 +#define _APS_NEXT_SYMED_VALUE 110 #endif #endif diff --git a/tools/CustomSetupTool/CustomSetupTool/resource.rc b/tools/CustomSetupTool/CustomSetupTool/resource.rc index 887108157590..3599828e2a54 100644 --- a/tools/CustomSetupTool/CustomSetupTool/resource.rc +++ b/tools/CustomSetupTool/CustomSetupTool/resource.rc @@ -33,8 +33,8 @@ BEGIN CONTROL "Process Hacker - Setup",IDC_MAINHEADER,"Static",SS_SIMPLE | WS_GROUP,15,15,209,18 LTEXT "A free, powerful, multi-purpose tool that helps you monitor system resources, debug software and detect malware.",IDC_SUBHEADER,15,46,211,36 CONTROL "",IDC_PROJECT_ICON,"Static",SS_BLACKFRAME,271,15,92,75 - CONTROL "
    View Changelog",IDC_SYSLINK1,"SysLink",WS_TABSTOP,15,120,110,14 - CONTROL "Project Website",IDC_SYSLINK2,"SysLink",WS_TABSTOP,15,102,110,14 + CONTROL "View Changelog",IDC_SYSLINK1,"SysLink",NOT WS_VISIBLE | WS_TABSTOP,15,120,110,14 + CONTROL "Project Website",IDC_SYSLINK2,"SysLink",NOT WS_VISIBLE | WS_TABSTOP,15,102,110,14 END IDD_DIALOG2 DIALOGEX 0, 0, 400, 225 @@ -42,7 +42,8 @@ STYLE DS_SETFONT | DS_MODALFRAME | DS_NOFAILCREATE | WS_POPUP | WS_CAPTION | WS_ EXSTYLE WS_EX_CONTROLPARENT FONT 8, "MS Shell Dlg 2", 400, 0, 0x1 BEGIN - EDITTEXT IDC_EDIT1,0,0,400,225,ES_MULTILINE | ES_READONLY | NOT WS_BORDER | WS_VSCROLL + EDITTEXT IDC_EDIT1,13,39,387,186,ES_MULTILINE | ES_READONLY | NOT WS_BORDER | WS_VSCROLL + CONTROL "License Agreement",IDC_MAINHEADER,"Static",SS_SIMPLE | WS_GROUP,15,15,209,18 END IDD_DIALOG3 DIALOGEX 0, 0, 400, 225 @@ -50,31 +51,31 @@ STYLE DS_SETFONT | DS_MODALFRAME | DS_NOFAILCREATE | WS_POPUP | WS_CAPTION | WS_ EXSTYLE WS_EX_CONTROLPARENT FONT 8, "MS Shell Dlg 2", 400, 0, 0x1 BEGIN - CONTROL "Create a desktop shortcut",IDC_SHORTCUT_CHECK,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,20,90,168,10 - CONTROL "Launch on system startup",IDC_STARTUP_CHECK,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,200,90,173,10 + CONTROL "Create a desktop shortcut",IDC_SHORTCUT_CHECK,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,20,101,168,10 + CONTROL "Launch on system startup",IDC_STARTUP_CHECK,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,200,101,173,10 CONTROL "Set as the default Windows Task Manager",IDC_TASKMANAGER_CHECK, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,20,120,345,10 - EDITTEXT IDC_INSTALL_DIRECTORY,20,48,307,14,ES_AUTOHSCROLL | ES_READONLY - PUSHBUTTON "Browse",IDC_FOLDER_BROWSE,330,48,50,14 - CONTROL "Setup Options",IDC_MAINHEADER,"Static",SS_SIMPLE | WS_GROUP,10,7,142,24 - GROUPBOX "Options",IDC_STATIC2,10,74,380,62 + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,20,131,345,10 + EDITTEXT IDC_INSTALL_DIRECTORY,20,59,307,14,ES_AUTOHSCROLL | ES_READONLY + PUSHBUTTON "Browse",IDC_FOLDER_BROWSE,330,59,50,14 + GROUPBOX "Options",IDC_STATIC2,10,85,380,62 CONTROL "Associate file extensions with PE Viewer",IDC_PEVIEW_CHECK, - "Button",BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,20,150,168,10 + "Button",BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,20,161,168,10 CONTROL "Create a desktop shortcut for all users",IDC_SHORTCUT_ALL_CHECK, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,20,105,168,10 + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,20,116,168,10 CONTROL "Launch minimized on system tray",IDC_STARTMIN_CHECK, - "Button",BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,200,105,173,10 + "Button",BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,200,116,173,10 CONTROL "Install Debugging Tools for Windows",IDC_DBGTOOLS_CHECK, - "Button",BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,20,165,168,10 + "Button",BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,20,176,168,10 CONTROL "Install KProcessHacker as a service",IDC_KPH_CHECK, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,20,179,168,10 + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,20,190,168,10 CONTROL "Install latest nightly build (not recommended)",IDC_RESET_CHECK, - "Button",BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,201,150,173,10 - GROUPBOX "Installation Folder",IDC_STATIC1,10,32,380,40 - CONTROL "Reset Process Hacker settings",IDC_RESET_CHECK2,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,201,165,173,10 - GROUPBOX "Additional Options",IDC_STATIC3,10,137,380,59 + "Button",BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,201,161,173,10 + GROUPBOX "Installation Folder",IDC_STATIC1,10,43,380,40 + CONTROL "Reset Process Hacker settings",IDC_RESET_CHECK2,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,201,176,173,10 + GROUPBOX "Additional Options",IDC_STATIC3,10,148,380,59 CONTROL "Start Process Hacker after setup exits",IDC_PHSTART_CHECK, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,201,179,138,10 + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,201,190,138,10 + CONTROL "Setup Options",IDC_MAINHEADER,"Static",SS_SIMPLE | WS_GROUP,15,15,209,18 END IDD_DIALOG4 DIALOGEX 0, 0, 400, 225 @@ -148,71 +149,6 @@ END #endif // APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// AFX_DIALOG_LAYOUT -// - -IDD_DIALOG1 AFX_DIALOG_LAYOUT -BEGIN - 0 -END - -IDD_DIALOG2 AFX_DIALOG_LAYOUT -BEGIN - 0 -END - -IDD_DIALOG4 AFX_DIALOG_LAYOUT -BEGIN - 0 -END - -IDD_DIALOG3 AFX_DIALOG_LAYOUT -BEGIN - 0 -END - - -///////////////////////////////////////////////////////////////////////////// -// -// Version -// - -VS_VERSION_INFO VERSIONINFO - FILEVERSION PHAPP_VERSION_NUMBER - PRODUCTVERSION PHAPP_VERSION_NUMBER - FILEFLAGSMASK 0x3fL -#ifdef _DEBUG - FILEFLAGS 0x1L -#else - FILEFLAGS 0x0L -#endif - FILEOS 0x40004L - FILETYPE 0x1L - FILESUBTYPE 0x0L -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "000904b0" - BEGIN - VALUE "CompanyName", "Process Hacker" - VALUE "FileDescription", "Process Hacker Setup" - VALUE "FileVersion", PHAPP_VERSION_STRING - VALUE "InternalName", "Process Hacker Setup" - VALUE "LegalCopyright", "Licensed under the GNU GPL, v3. Copyright (C) 2017" - VALUE "OriginalFilename", "ProcessHackerSetup.exe" - VALUE "ProductName", "Process Hacker Setup" - VALUE "ProductVersion", PHAPP_VERSION_STRING - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x9, 1200 - END -END - - ///////////////////////////////////////////////////////////////////////////// // // Icon @@ -255,7 +191,7 @@ END 2 TEXTINCLUDE BEGIN "#include ""winres.h""\r\n" - "#include ""../../../include/phappres.h""\r\n" + "#include ""../../../ProcessHacker/include/phappres.h""\r\n" "\0" END @@ -283,10 +219,13 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_AUS // RCDATA // -IDR_BIN_DATA RCDATA "..\\..\\..\\build\\processhacker-build-bin.zip" - -IDR_LICENCE_DATA RCDATA "resources\\Licence.txt" +IDR_LICENCE_DATA RCDATA "resources\\LICENSE.txt" +#if defined(APSTUDIO_INVOKED) || defined(PH_BUILD_API) +#if defined(APSTUDIO_INVOKED) +IDR_BIN_DATA$(PH_BUILD_API) RCDATA "..\\..\\..\\build\\output\\processhacker-build-bin.zip" +#endif +#endif #endif // English (Australia) resources ///////////////////////////////////////////////////////////////////////////// diff --git a/tools/CustomSetupTool/CustomSetupTool/resources/Licence.txt b/tools/CustomSetupTool/CustomSetupTool/resources/LICENSE.txt similarity index 67% rename from tools/CustomSetupTool/CustomSetupTool/resources/Licence.txt rename to tools/CustomSetupTool/CustomSetupTool/resources/LICENSE.txt index 4a64d83271e1..af63d5321326 100644 --- a/tools/CustomSetupTool/CustomSetupTool/resources/Licence.txt +++ b/tools/CustomSetupTool/CustomSetupTool/resources/LICENSE.txt @@ -2,7 +2,7 @@ GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 -Copyright � 2007 Free Software Foundation, Inc. +Copyright © 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. @@ -31,36 +31,39 @@ The precise terms and conditions for copying, distribution and modification foll TERMS AND CONDITIONS 0. Definitions. -�This License� refers to version 3 of the GNU General Public License. -�Copyright� also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. +“This License” refers to version 3 of the GNU General Public License. -�The Program� refers to any copyrightable work licensed under this License. Each licensee is addressed as �you�. �Licensees� and �recipients� may be individuals or organizations. +“Copyright” also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. -To �modify� a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a �modified version� of the earlier work or a work �based on� the earlier work. +“The Program” refers to any copyrightable work licensed under this License. Each licensee is addressed as “you”. “Licensees” and “recipients” may be individuals or organizations. -A �covered work� means either the unmodified Program or a work based on the Program. +To “modify” a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a “modified version” of the earlier work or a work “based on” the earlier work. -To �propagate� a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. +A “covered work” means either the unmodified Program or a work based on the Program. -To �convey� a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. +To “propagate” a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. -An interactive user interface displays �Appropriate Legal Notices� to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. +To “convey” a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. + +An interactive user interface displays “Appropriate Legal Notices” to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. -The �source code� for a work means the preferred form of the work for making modifications to it. �Object code� means any non-source form of a work. -A �Standard Interface� means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. +The “source code” for a work means the preferred form of the work for making modifications to it. “Object code” means any non-source form of a work. + +A “Standard Interface” means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. -The �System Libraries� of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A �Major Component�, in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. +The “System Libraries” of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A “Major Component”, in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. -The �Corresponding Source� for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. +The “Corresponding Source” for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. + All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. @@ -68,25 +71,29 @@ You may make, run and propagate covered works that you do not convey, without co Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. + You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. + You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. -b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to �keep intact all notices�. +b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to “keep intact all notices”. c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. -A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an �aggregate� if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. +A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an “aggregate” if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. + You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. @@ -96,9 +103,9 @@ d) Convey the object code by offering access from a designated place (gratis or e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. -A �User Product� is either (1) a �consumer product�, which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, �normally used� refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. +A “User Product” is either (1) a “consumer product”, which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, “normally used” refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. -�Installation Information� for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. +“Installation Information” for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). @@ -107,7 +114,8 @@ The requirement to provide Installation Information does not include a requireme Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. -�Additional permissions� are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. + +“Additional permissions” are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. @@ -119,13 +127,14 @@ c) Prohibiting misrepresentation of the origin of that material, or requiring th d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. -All other non-permissive additional terms are considered �further restrictions� within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. +All other non-permissive additional terms are considered “further restrictions” within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. + You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. @@ -135,54 +144,63 @@ Moreover, your license from a particular copyright holder is reinstated permanen Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. + You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. + Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. -An �entity transaction� is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. +An “entity transaction” is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. -A �contributor� is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's �contributor version�. -A contributor's �essential patent claims� are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, �control� includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. +A “contributor” is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's “contributor version”. + +A contributor's “essential patent claims” are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, “control” includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. -In the following three paragraphs, a �patent license� is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To �grant� such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. +In the following three paragraphs, a “patent license” is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To “grant” such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. -If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. �Knowingly relying� means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. +If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. “Knowingly relying” means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. -A patent license is �discriminatory� if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. +A patent license is “discriminatory” if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. + If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. + Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. + The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. -Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License �or any later version� applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. +Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License “or any later version” applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. -THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM �AS IS� WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + +THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM “AS IS” WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. + If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS @@ -191,7 +209,7 @@ How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. -To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the �copyright� line and a pointer to where the full notice is found. +To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the “copyright” line and a pointer to where the full notice is found. Copyright (C) @@ -216,19 +234,20 @@ If the program does terminal interaction, make it output a short notice like thi This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. -The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an �about box�. +The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an “about box”. -You should also get your employer (if you work as a programmer) or school, if any, to sign a �copyright disclaimer� for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . +You should also get your employer (if you work as a programmer) or school, if any, to sign a “copyright disclaimer” for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . -Process Hacker is distributed under the GNU GPL version 3, -with the following exception: +Process Hacker is distributed under the GNU GPL version 3, with the +following exception: + + Permission is granted to dynamically (but not statically) link this + program with independent modules, regardless of the license terms of + these independent modules, provided that this program is not modified + in any way. An independent module is a module which is not derived + from or based on this program. If you modify this program, this + additional permission no longer applies unless authorized by the + copyright holders. -Permission is granted to dynamically (but not statically) link this -program with independent modules, regardless of the license terms of -these independent modules, provided that this program is not modified -in any way. An independent module is a module which is not derived -from or based on this program. If you modify this program, this -additional permission no longer applies unless authorized by the -copyright holders. \ No newline at end of file diff --git a/tools/CustomSetupTool/CustomSetupTool/resources/version.rc b/tools/CustomSetupTool/CustomSetupTool/resources/version.rc new file mode 100644 index 000000000000..8eced112f05c --- /dev/null +++ b/tools/CustomSetupTool/CustomSetupTool/resources/version.rc @@ -0,0 +1,80 @@ +#include "../resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +#include "winres.h" +#include "../../../ProcessHacker/include/phappres.h" +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION PHAPP_VERSION_NUMBER + PRODUCTVERSION PHAPP_VERSION_NUMBER + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "000904b0" + BEGIN + VALUE "CompanyName", "Process Hacker" + VALUE "FileDescription", "Process Hacker Setup" + VALUE "FileVersion", PHAPP_VERSION_STRING + VALUE "InternalName", "Process Hacker Setup" + VALUE "LegalCopyright", "Licensed under the GNU GPL, v3. Copyright (C) 2017" + VALUE "OriginalFilename", "ProcessHackerSetup.exe" + VALUE "ProductName", "Process Hacker Setup" + VALUE "ProductVersion", PHAPP_VERSION_STRING + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x9, 1200 + END +END + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""winres.h""\r\n" + "#include ""../../../ProcessHacker/include/phappres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// diff --git a/tools/CustomSetupTool/CustomSetupTool/uninstall.c b/tools/CustomSetupTool/CustomSetupTool/uninstall.c index 4de1817f7517..92acc4d711af 100644 --- a/tools/CustomSetupTool/CustomSetupTool/uninstall.c +++ b/tools/CustomSetupTool/CustomSetupTool/uninstall.c @@ -22,13 +22,6 @@ #include #include -typedef struct _PH_SETUP_UNINSTALL_CONTEXT -{ - HWND DialogHandle; - HICON IconSmallHandle; - HICON IconLargeHandle; -} PH_SETUP_UNINSTALL_CONTEXT, *PPH_SETUP_UNINSTALL_CONTEXT; - #define WM_TASKDIALOGINIT (WM_APP + 550) HWND UninstallDialogHandle = NULL; HANDLE UninstallDialogThreadHandle = NULL; diff --git a/tools/CustomSetupTool/CustomSetupTool/update.c b/tools/CustomSetupTool/CustomSetupTool/update.c index 01db439aa0e1..231bd124a266 100644 --- a/tools/CustomSetupTool/CustomSetupTool/update.c +++ b/tools/CustomSetupTool/CustomSetupTool/update.c @@ -93,14 +93,14 @@ VOID FreeUpdateContext( ) { //PhClearReference(&Context->Version); - // PhClearReference(&Context->RevVersion); + //PhClearReference(&Context->RevVersion); //PhClearReference(&Context->RelDate); - // PhClearReference(&Context->Size); + //PhClearReference(&Context->Size); //PhClearReference(&Context->Hash); - // PhClearReference(&Context->Signature); - // PhClearReference(&Context->ReleaseNotesUrl); + //PhClearReference(&Context->Signature); + //PhClearReference(&Context->ReleaseNotesUrl); //PhClearReference(&Context->SetupFilePath); - // PhClearReference(&Context->SetupFileDownloadUrl); + //PhClearReference(&Context->SetupFileDownloadUrl); if (Context->IconLargeHandle) DestroyIcon(Context->IconLargeHandle); @@ -144,7 +144,7 @@ VOID TaskDialogLinkClicked( _In_ PPH_SETUP_UPDATE_CONTEXT Context ) { - PhShellExecute(Context->DialogHandle, L"https://www.maxmind.com/", NULL); + } LRESULT CALLBACK TaskDialogSubclassProc( From c7fc42e3041fb8eb466c2abaaaa51765c1c6369a Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 21 May 2017 12:20:01 +1000 Subject: [PATCH 0140/2058] Fix symbol references, Enable CFG builds for plugins (requires tools\CustomStartTool\bootstrap.exe) --- ProcessHacker/ProcessHacker.vcxproj | 4 ++-- plugins/Plugins.props | 4 +++- tools/peview/peprp.c | 2 +- tools/peview/peview.vcxproj | 4 ++-- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/ProcessHacker/ProcessHacker.vcxproj b/ProcessHacker/ProcessHacker.vcxproj index 9b9b462afac4..67fcd39e46f5 100644 --- a/ProcessHacker/ProcessHacker.vcxproj +++ b/ProcessHacker/ProcessHacker.vcxproj @@ -103,7 +103,7 @@ ..\phlib\bin\$(Configuration)$(PlatformArchitecture);..\tools\delaylib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) ProcessHacker.def aclui.dll;iphlpapi.dll;ws2_32.dll;%(DelayLoadDLLs) - __delayLoadHelper2 + ___delayLoadHelper2@8 _UNICODE;UNICODE;%(PreprocessorDefinitions);$(ExternalCompilerOptions) @@ -175,7 +175,7 @@ ..\phlib\bin\$(Configuration)$(PlatformArchitecture);..\tools\delaylib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) ProcessHacker.def aclui.dll;iphlpapi.dll;ws2_32.dll;%(DelayLoadDLLs) - __delayLoadHelper2 + ___delayLoadHelper2@8 _UNICODE;UNICODE;%(PreprocessorDefinitions);$(ExternalCompilerOptions) diff --git a/plugins/Plugins.props b/plugins/Plugins.props index 73e6bd500644..88e4574b2c86 100644 --- a/plugins/Plugins.props +++ b/plugins/Plugins.props @@ -24,6 +24,7 @@ Level3 true StdCall + Guard false true ProgramDatabase @@ -32,7 +33,6 @@ delaylib.lib;ProcessHacker.lib;ntdll.lib;%(AdditionalDependencies) ProcessHacker.exe;%(DelayLoadDLLs) - __delayLoadHelper2 true 6.01 Windows @@ -79,6 +79,7 @@ ..\..\sdk\lib\i386;..\..\tools\delaylib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) MachineX86 + ___delayLoadHelper2@8 @@ -87,6 +88,7 @@ ..\..\sdk\lib\amd64;..\..\tools\delaylib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) MachineX64 + __delayLoadHelper2 diff --git a/tools/peview/peprp.c b/tools/peview/peprp.c index 75ce0487a33f..b2d8d744382f 100644 --- a/tools/peview/peprp.c +++ b/tools/peview/peprp.c @@ -174,7 +174,7 @@ VOID PvPeProperties( } // Symbols page - if (NT_SUCCESS(PhGetMappedImageDataEntry(&PvMappedImage, IMAGE_DIRECTORY_ENTRY_DEBUG, &entry)) && entry->VirtualAddress) + if (NT_SUCCESS(PhGetMappedImageDataEntry(&PvMappedImage, IMAGE_DIRECTORY_ENTRY_DEBUG, &entry)) && entry->VirtualAddress) { newPage = PvCreatePropPageContext( MAKEINTRESOURCE(IDD_PESYMBOLS), diff --git a/tools/peview/peview.vcxproj b/tools/peview/peview.vcxproj index 14e547b6dcc5..ba8868d0c4f1 100644 --- a/tools/peview/peview.vcxproj +++ b/tools/peview/peview.vcxproj @@ -104,7 +104,7 @@ Windows MachineX86 6.01 - __delayLoadHelper2 + ___delayLoadHelper2@8 ..\..\phnt\include;..\..\phlib\include;include;%(AdditionalIncludeDirectories) @@ -170,7 +170,7 @@ MachineX86 true 6.01 - __delayLoadHelper2 + ___delayLoadHelper2@8 ..\..\phnt\include;..\..\phlib\include;include;%(AdditionalIncludeDirectories) From d0878a98434a72205e9d3b3471deeefc440366a6 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 21 May 2017 13:21:41 +1000 Subject: [PATCH 0141/2058] Fix build --- .../CustomSetupTool/download.c | 2 +- tools/delaylib/bin/Debug32/delaylib.lib | Bin 20588 -> 21434 bytes tools/delaylib/bin/Debug32/delaylib.pdb | Bin 135168 -> 135168 bytes tools/delaylib/bin/Debug64/delaylib.lib | Bin 21430 -> 21430 bytes tools/delaylib/bin/Debug64/delaylib.pdb | Bin 135168 -> 135168 bytes tools/delaylib/bin/Release32/delaylib.lib | Bin 226114 -> 226982 bytes tools/delaylib/bin/Release64/delaylib.lib | Bin 225886 -> 225884 bytes tools/delaylib/main.c | 40 +++++++++++++++++- 8 files changed, 39 insertions(+), 3 deletions(-) diff --git a/tools/CustomSetupTool/CustomSetupTool/download.c b/tools/CustomSetupTool/CustomSetupTool/download.c index 9ae9010c1566..977872b81370 100644 --- a/tools/CustomSetupTool/CustomSetupTool/download.c +++ b/tools/CustomSetupTool/CustomSetupTool/download.c @@ -648,7 +648,7 @@ BOOLEAN UpdateDownloadUpdateData( ULONG downloadedBytes = 0; ULONG contentLengthSize = sizeof(ULONG); ULONG contentLength = 0; - PPH_STRING status; + //PPH_STRING status; IO_STATUS_BLOCK isb; BYTE buffer[PAGE_SIZE]; diff --git a/tools/delaylib/bin/Debug32/delaylib.lib b/tools/delaylib/bin/Debug32/delaylib.lib index 418c0549ec1d5c58d058709cb9f229f93ce16b8c..ee4b17dfbb1762135f84694395e1e18ae06262fb 100644 GIT binary patch delta 3613 zcmai0dr*|u6+d@@1$GIr?1JIFEDuElmp2pL?p& z>hJ==(K>+5^Y9_T8VA{QU{0t>eTd+>dUS@GRACJ`5SpVlGytSD;&x)3jrblhZRCGP zBi^Luy#xmug9%}IEWkZGOru7~F3ch@oob;}|0m^i(pP{(C#yxl`%EXq<;~bB4HJY8 zf46USQ=hM+-rwEtA1Hzph>PXcr_$6YRNov28u%8DtL=DEorYoIYhq(StLvYfoHUWT zYp8cQt_?SfWD}7W^#Gl{&-USg@OE|?^${;KA8w79MfgNS&C{ouG{%S2EE+0xj24Ke zkL0@L8};Yq`X5QJ0+$Z%P~&>p2=B-zcc1Dxgy&#UiZ-UNRE=sB>5^y56LYgTS>l2vY+ISNNymxgXH%}zD1IUc^$QPj8IC2UOxY^sB$~Aw((}m{ZIbTJmOWMI$_>16pN zDFK@OJ$(bKt-ckV?G3bs13kXM&c0qqq6VdSHoA{#gVvaA)x2EtU|y5U;%#s`gceJy zU9foU7Fy5Z%w^#_Mq( zv1&Y`H^vx=<{L<8wl}*xi}6gHK6pu=!dNlhGvu;LG{(Qes_>ooTkH;QOE{*gG~ig4 zKG-#F4^xF1P?u<%rl$cNbq#{oZWXK+udNY_i7@6{bm10Qh>&%F6rv4y0o%-_F$PQVIddy9GiWTB;n&d85PPxmq zd(zTF9_RsUqm63Fq~5dfA8DVnSUi_*VxQr?^qDLVGmPad7Z)3oQ&Y%W_y2^)wSZ!3 z7b8cmjTz4;UZnxt^+JQwYj@Z^g4;rYjUl@^!Iv@)var8%HTGpD;{41+X2Ru}%?~}2vcM1;_xnqk?oobJA4Iijj_`6*%gnqI+ z7*kvk8DCLh%r`!5tTr06ib{-GUbC^VvIv*Vc_XliuE(uplHV2Ka8*WHxF#bFnCY%4 zqM8;;WTb%_Ld7CylaU6Tgi1utBO?tgB~&VMJ{f7Cn^2+1^)m>FPy^p3(kzkz8EIfA zT{7G)Exauw4g5jj&L~_MU3XHuNEy-XtZ;J`ZiT|FRJgzfh1{r+sBo_<+%ARNt8hVu zJEU;O74Ch7JEw3TE8K*H=F;qLE95yfK$$q>k7c9*T6g#k#K*V2Q(&769<^?Nx!Ih* zXa7zL6VzdUNfMq8OU89`_0jybYF#+`>w0=}juha|xqnk_Vz{x!N3YHGnk9kjA5epl zyIs(gGP;?+OP($mu}8VPCMV-b166nVqQmg`i{ZuN*S8ZKxjQ=AMh)k8)sAdl#Cwbk z^N#LsbQlUP9{-|$r1|#zkp)p6(F%1P<`1HKM6xilIphBsFr&BDW#F@@nviUKzVy8a zc=okWJY1U|;MRCBc;Zf^NKkxP#W$B<|6)!fO)X`$xJP+F)nK7gLT&{K3R*^}lCm25 zsZ645fHhR6iU_I92vDJhZB+7~CWClD_&{p7rEqz)DE$A(09Ayf;hGhW9|4KmM@Z`X zGeVNRvxG85dzTb0g!Xv4$Z1qGzSJ?Rh9eF9l1gq!3rA(7 zffI!IfLb^yBMqD<#GTc`MHy*eh*nJ+W3`MlFl%uw!(Am>32+qOzL;iu)vR?Y(tSu_RciFUHhbw~p7l(1T A)c^nh delta 2855 zcmZXW3v5%@8OOil*p9K&B#z^}6JHzSggouUkQb0Re&NnZjBQfVmRi4zTHcYy8Q`)8z}E)pVxzVba=YpWQ!6(PIg_#qu!3My zJ2qxG>SHwhlXig0MY6G+IssxU>PJ&!qt3O%vI<}#h;-mX87_UY10bstU(Rso7j;r- zAO4l_Pd`#r z_^F|mSU0Pqeu~MfPg?*q&})WkG%iv^ZsKWtM`M9F3!j^HzV%HStq0h8occ}FPg1{` z`fJp0q5fOyAEcf?;4v3K4P=_D@&Op0x0YuGdwgBdAT)9jb4*P-Zqjm7ULfI*iAi4= z+{%hfE}Q#&(MUiHMSbA}RFh>A_nT_iB%U!nY;(|JfWbAZ6Qctoqp^{7t5O>_tR5bM zBDl@`odrj-PB53$cH1__oOmqT#;)LJ*<%$`^t49k9vEA_cH`RQy(6iCL2@vff)esy zjhM5Jfs~OuM-!@`0HJ8FFB$0xiwR#}Q1r!vKF9`x*-a+Vzce0*#3`J?Jdclq%lyGu zGSb^4#)JOecmS+qX_SWZ+L<<&Cg5-F1^Axjb=HUv@SJt7ww_xT7FA+h zfymsrv*2rX2_Gyx%Ic-oqPLjlx&{AJ>@PIXv~VCICWBpKmoMpG3=WD=iyhTP*>}b3N;)JtV_YF-I@s(;T zUT`{fR=$V0t)fVpJtxeV1@CjYm;oPm^-HNQee=pkxIYjK5)u$-tq ztqmw-gq8Fr^Jpgcxdz75XoQ`rIH8acj;q>9RlBZgH&m@DW5!{#LPqebT3FQ*s&YFkyUNe^^c@T{8^G6KIo?*yy$tIscFoc-^U;TNl>5AVEa`z1Xp1klq~ zf@gH4*xhN#=GSB29XtOxcJt=Vw;VX!c~SENV8S;*m*8RF-8uhSxMS(n_>N#!jPE<0 ztgha1zNURTJ>D_3{9Oa&*yw7M%WLF^?;$T+{*UPf;fsq``F9~deMER5J$$WdHT3MW)7Ew(IdHeC z@k1bMFA&LV4-v`!-XSVWul<1NE*UQo@^7ymuBa1#AmXQrehAu-Iq4YULz;Pb4RCm`GmxK2Z%-J)EJoHcg*VTbCv+hQbMUUV0|{1{>!amkG``PdC{o7B?<$ETl%t=m}lN?socvuI%`Llc3RAtE3Cvd)WBU%v9>hNQFM@YLONG8}Kp<1Z9pS z3zXfAa#~Tes&Y|L_}P~IT>pt;b+Q?4X3|fUChUmyNBH|wMSl3bkO9tUkH<^ozD423 zKYEM8-_XUXLIdbR-I95%7u%_Q0M{>>XP;1V$RTS6p8^NftbkHKiYJyV!7Cs Ihq!_L51jf3ssI20 diff --git a/tools/delaylib/bin/Debug32/delaylib.pdb b/tools/delaylib/bin/Debug32/delaylib.pdb index 41880c99c59b0050976d95b7cacfc7241c617645..c3dd1f5dfc764cb77ce138247c5d5970092a7d36 100644 GIT binary patch delta 2858 zcmbVOc~F#B67S#laSe(vTyhGiL=X{Bk)VPgVpJRvSv<UiNLT(6iscwn0T>n zVn*!>-Unqgi>phmUoB;fQHep;gXl(G;~jOqMYCCtxNLvS7-MbapPj0n_xkm(`}OPB zuluXn;8C-|W2Z|-&~*2xsUV{1+xusAG&YS`_ns*+zW&oqjbRzRT~XecnSIDTs>P4U z;zKk{fZfO~@U-x%@WqJ^{#(1jG!1Qy7Sr2G*oyv1_+_gTd`|nML-kbxR550VsT@=GhOMI1TxqqH(Svp!tvJypb9uR?c$BroQf4l-8(aOV zRi|X4Wro22SJTBQe_=hl>gOokx~mhD{~L3Kr8vu0T55gC2OZ<)#EdC5&#=5OV6Sa4 zOmqJwAF``R*Y$A9CsbHxi|aEi#UsqKtVJ)Zlu`Rwat|;NDU}kLuO!5UrfgI0#Hsf4 z?ZIx2>B<@e__p^T___&3b#YLOJ?cSlwi_K59ZynxTJ^DpC{S<$>BRMvv6Ez>8+rKX zd$^Me9dYU$b?9(h48je^or`Up7lR1H2`78fZhjKs>hLM)X|Qwl#j^mcvtNA{QLX#q zLYXBcwxZ69lM`C#;e&QBIlsQQ$IoOFDr}XOqDp!$>q?H>%eT&ZNymrsE6tUbpK$*4 zT=Rw9Ao|tZatrlnA5X3U?h?RL;_&ld*iT`6$z}V#>w$bU1_oXqgOBkKPK`xA&hoNY z@K{XD8bHAPsRY5>&Y0RVP+Rh874OktdsA^U}MK?XiW z1S3TRB36=*C$QQK44|Hd_LOH=i``=XP*m2O~7=;>RRob(ZXkH2EqehixhZ7B5 ztkC{4(6L1d-?Je&YjJ;~C9KlkJ_=QSBgv8l+PV;wa9E{+ZA9ma6q?WkiW{m@_#%Z? z=YpQx23=@UDRhuR+uan-DMz^X=&LH#T8Rv;3h}GpIpvtD9ID{2%Q3{$Wgk(pT<-MC zyE6B7TUCRu(V4>DzeZAQJ392@)zP6h3Mni`2W7~7q?S~JW8U_Qxskg+go|hRd3o@K zg~gT<^W1SZbMa_PNx7wB0JZDQ>LN$gA;oxEARf}Q{H5FJ%ipoJ4q5moH`HMoZn9xD z;*7TiWE9Xi#R0m@*{jj&c3-b2Mh;wqYdFcz)}Yq)fh=|9WozZd{+lz`q0sfQtORiV zI#l=kk4*Lcn3m`;qsp0d{&JdwclYN}>rtl|RmDqS~lG ziUD$H89E*A!O@$LZ;TXPcX60>3jG{CwI!S22fV^-H)9rJ*|-I7%adQWMNGx>7h6zh zOb{KDnA+><&`IK?dI1gOhI*v9=@%d=d9xnx04Z$UDrZXN@K3NHwkIJ_grs+r@s)XR zSt{mEvQ|{SWiD}aZoRteP7LMxPcSDW#0l4%i4*6n)*P}8e?XeHZJX|EhW6QZeBcuB zp7`{>&_ba_LSxA_a50D3!W+OB#OwI>Ye?5o$Ou8VTtteaCqR;g@_>SkE8{ zu+W|}AonDdM!73=dyPW=vev!=RIpH`&GLGFm2655qqANI-sl1R47u$ zXrY@Ig&5IMY5?`5~T;vZ$@ZZZ$Y(9QE2!;mF}%m>Gk{a z)gWtc&K8HHWVAHM4o^W%JydGlLA2vOsJjG8sZuG1+nUiUEl1!vQf02m5lckW)mNcO zJt0t)>ZF()?Jo0&D*f?wqPu^ScP6>4|DxrBgS4bC@wuV14lEOXbfVrDUakX!>CM=0jH{K>CI_LE{sBW3TATGT~cNcb;zt>4T5 delta 2159 zcmZ`*X>^v=5q_R~v$G^$z9a<52MG{K!jgo|ni5TnNF;`}p;8XSR1yoO5S6eRrm&LdoPtz#CND@u4^HMKQ3uO-RaW%md0ug5^-{!Z z65oe4{FigA4;`{z=Kn&EyD7fMxQ(~u9*DF zKv|K=oeY+-PqNH3i>Ms^sZRp4==*((rt_k}a6f(g=8CN@TK>cl6c(cEK=>il)z!Gd zT&|Dy$WL)81_l;RnTQ7Wk{-o=$SxQ^rdY$c-S8WY!e|uXGCzwSF+$Rx($q&eo1W4H zGTJ%NPoIyiiaX9KJjI1>f1Z(vuVjVsd|RT{W|IaQayk%&bk47 z-ulJ6xcfjgN*KsnwsQpJ>_D}3OTf_*c+oP^Su@lh+h9%s@ot#K58*_Gm#Cj_aG=WK zi*W`8_YCeP7}O+MWN$Qht(a&Q3rz9>zx)G1-O1C55l_KtoFeL>-dMMSRqAL{);+ zL4=MVSA0w=7BPz_W$z-6Ti{H!S}BbN2-8k(ZGnqkhNbjGBHd+$Wa5Y@|G_dc$BwMx^~*) zv*QLcb_21B+sQ?ZIk$r@KOSPRdZopJOBV5phu^cvIbra+cA4w@*XJyPmCw8Zgeq^L z)a?y}%JCL2=JDZC2XAQiNnWkKd@HG_W!v77s&(KwgC}}g++1qWR`Iw=K>QqFSCx9d zN7QM1R^K98)~)8@2E#k(WV)rvNHN%)WKn&`V#8=) zXN)$C7Nz@j(ua<5GQZ-s;Q52Y9yWA^imoKPL;n98x>JCvE4h}voYegc{n`Hkar!HS cSfw1L>pC3VFIM}jweo27-^+dZYRu8>ikm~3yf_q#7#JGX zGchpC2GVDM^jsi)9Y`+#(szLL!p#S`_G$=7_Cz(kG;EJ)^KE(m^S2q(oh$e&0_idf{84Wip`A%U20D*Bt#Q*>R delta 195 zcmdnCoN?Q7#tE{lh6V-(CX+WXicPdwi{MORTn*=xLs>dZYRp^aDQpg9^5Re|WMF7m z&&0q`4y4Zj=}I7d9Z1&z={rEWcJl$Qy&3{@Bw|H;7{h8iox}t-wrt9r+-rP7p!4vH z%E^~}nO68NPc;`cQka}-5+JZ_w)O-gS?T-`0tr(P*=h?-Vuw?3qDQ diff --git a/tools/delaylib/bin/Debug64/delaylib.pdb b/tools/delaylib/bin/Debug64/delaylib.pdb index 4f5770e5944b0847f1b65f42e03d24b05b22a533..db51cbc0e1c9128f5672ec9111a56f7227dbab6f 100644 GIT binary patch delta 104 zcmZozz|pXPV*`tWL=?MXBqIX@L)|2oOCRt5_nZ{C=f=v2CWFl~4m>O@1wfhU4RaX1 dHcR=RG{6TryRg3z$N{0d{IH2@_+BEkRw diff --git a/tools/delaylib/bin/Release32/delaylib.lib b/tools/delaylib/bin/Release32/delaylib.lib index 7e4fb20980bc276c072964297217d7e476865aac..c068ed7e2912139ff721034307bd0ed3db79f851 100644 GIT binary patch delta 6370 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 delta 2840 zcmY+G4^-4u7RP`0HwZX@{1XHb7(jk7$S4ki1Bfz^(@sjb4d$_eW9p`^t03kdN;eV@ z!HRd+|(rj!JuoDV_uso}t_hJ2W>exyL4{Jywug@Wn+?=?RmAvrl& zr!yLp5|WcxXpL479z6nKec20d=vJG4Y4Cif?Qhv3Kr8<6uf z7vQKI>=NU)u3ZrP4~p_lO`x3T;te|+wzymc*xRtc^_;t3#g(CA`Bt`gI{UrfEetT~ z{QTv`-tqEm?^8Z+2IWm(4o~l`$PDzU-+yjX!)@>YejFU~z1a)lIXN;q8FtI7qcfpHelt1?o|Su|v&Ek)<$2Olh?aLqR#+{6 zCM|+~`JrTnQh9MqDkT)hWWpBtVvGgW%9_|E&?INYra`s*N~{T%%IE2`xBQ>jg-|cY z>z6>C{0Dt9ydc-?J21=v zA+Qru9S{b)F^@Tm@f8PH;$IU4;z~+sBCQf;+N23ewiw1}G>p)|>y(t^0|zY7RuGaa z=7Rn{*4}`WnhtQouN)A7`)@%YRO5+TupbVit_iGIaEttZY$E@0Jk|sY;C1{b^KWW` zfEn(Utcoj*1{WICDyMMCZP>4^byk^*y={YPb!_oo6S%N^_bB@U>$*YvV{cB<3}w}sI@yQMDPj~Eo=>U2>2XN+@ZwF=-JBF zaEB@wl?n;0!raLU|G-yUN$HwXDUmC!Y$c@?ZKU*X+|Wi!4s2~BrL;EkC%2Qo6|>vP z--egk$sf^96|$8I%UA{LWQ86~?4Sz0&I(WR3T_>wBzBV05C(TbBn;!CPRN3LSkej8 zVFZtLLNbiuzdGr_$8n?+tnvP!oU}Jh?4+4#lh!L$*RrZ>CaVVEnr|Q-g7M@xV2ugm zi6LqtGi}mlC2`Yajt-}F(G4*hGrA~8&vPU-hnY5Mo03y7nKK8^QjT^WMU`(~ zeo%JiNj|N>t342w@)TM61JtYXK$$A(6YZK!&CI3QUO~PxvmXP5aMM9fti;e>2zFn^ z#h%5*y|60&IW;YhW<}4u&rg?H&NK4Knd_oI#H}@Wxfg<_KhK<+RMvoAt-ThDMZ#aUSJEzEpo3kCGY$j=v0!{xWCX$3UfW%4-}5Me@2 z6jDT4lG5W5a_ZGc5k;utPVD;@Rz1HWtUDtI5i9Dzi5fIp0Y-u*kS@;&NDp;G(-uyGV(eSRcw zu12qB{scHN3cqs0uODCjCh27Q=sOG<;8kdQ?C$J9E;GCYELHD0xJ$aFcjY z*>e$J9iz>2!9S0|Vp@)782$@vJPg~gyh@xCY Date: Sun, 21 May 2017 14:04:43 +1000 Subject: [PATCH 0142/2058] BuildTools: Fix git dependency, Fix delaylib pdb --- tools/CustomBuildTool/Source Files/Build.cs | 42 +++++++++--------- .../bin/Release/CustomBuildTool.exe | Bin 160768 -> 160768 bytes .../bin/Release/CustomBuildTool.pdb | Bin 69120 -> 69120 bytes tools/delaylib/bin/Debug32/delaylib.lib | Bin 21434 -> 21434 bytes tools/delaylib/bin/Debug32/delaylib.pdb | Bin 135168 -> 135168 bytes tools/delaylib/bin/Debug64/delaylib.lib | Bin 21430 -> 21430 bytes tools/delaylib/bin/Debug64/delaylib.pdb | Bin 135168 -> 135168 bytes tools/delaylib/bin/Release32/delaylib.lib | Bin 226982 -> 226982 bytes tools/delaylib/bin/Release32/delaylib.pdb | Bin 0 -> 126976 bytes tools/delaylib/bin/Release64/delaylib.lib | Bin 225884 -> 225884 bytes tools/delaylib/bin/Release64/delaylib.pdb | Bin 0 -> 126976 bytes tools/delaylib/delaylib.vcxproj | 14 +++--- 12 files changed, 28 insertions(+), 28 deletions(-) create mode 100644 tools/delaylib/bin/Release32/delaylib.pdb create mode 100644 tools/delaylib/bin/Release64/delaylib.pdb diff --git a/tools/CustomBuildTool/Source Files/Build.cs b/tools/CustomBuildTool/Source Files/Build.cs index 8e010b9ace8b..2031e4364c1a 100644 --- a/tools/CustomBuildTool/Source Files/Build.cs +++ b/tools/CustomBuildTool/Source Files/Build.cs @@ -33,6 +33,7 @@ namespace CustomBuildTool public static class Build { private static DateTime TimeStart; + private static bool GitExportBuild; private static bool BuildNightly; private static string BuildBranch; private static string BuildOutputFolder; @@ -187,9 +188,13 @@ public static bool InitializeBuildEnvironment(bool CheckDependencies) return false; } - if (CheckDependencies) + if (File.Exists(GitExePath)) { - if (!File.Exists(GitExePath)) + GitExportBuild = string.Equals(Win32.ShellExecute(GitExePath, "rev-parse --is-inside-work-tree"), string.Empty, StringComparison.OrdinalIgnoreCase); + } + else + { + if (CheckDependencies) { Program.PrintColorMessage("Git not installed... Exiting.", ConsoleColor.Red); return false; @@ -237,16 +242,20 @@ public static void CleanupBuildEnvironment() public static void ShowBuildEnvironment(string Platform, bool ShowBuildInfo, bool ShowLogInfo) { - BuildBranch = Win32.ShellExecute(GitExePath, "rev-parse --abbrev-ref HEAD").Trim(); - BuildCommit = Win32.ShellExecute(GitExePath, "rev-parse --short HEAD").Trim(); - Program.PrintColorMessage("Branch: ", ConsoleColor.Cyan, false); - Program.PrintColorMessage(BuildBranch, ConsoleColor.White); - Program.PrintColorMessage("Commit: ", ConsoleColor.Cyan, false); - Program.PrintColorMessage(BuildCommit, ConsoleColor.White); + if (!GitExportBuild) + { + BuildBranch = Win32.ShellExecute(GitExePath, "rev-parse --abbrev-ref HEAD").Trim(); + BuildCommit = Win32.ShellExecute(GitExePath, "rev-parse --short HEAD").Trim(); - string currentGitTag = Win32.ShellExecute(GitExePath, "describe --abbrev=0 --tags --always").Trim(); - BuildRevision = Win32.ShellExecute(GitExePath, "rev-list --count \"" + currentGitTag + ".." + BuildBranch + "\"").Trim(); - BuildCount = Win32.ShellExecute(GitExePath, "rev-list --count " + BuildBranch).Trim(); + Program.PrintColorMessage("Branch: ", ConsoleColor.Cyan, false); + Program.PrintColorMessage(BuildBranch, ConsoleColor.White); + Program.PrintColorMessage("Commit: ", ConsoleColor.Cyan, false); + Program.PrintColorMessage(BuildCommit, ConsoleColor.White); + + string currentGitTag = Win32.ShellExecute(GitExePath, "describe --abbrev=0 --tags --always").Trim(); + BuildRevision = Win32.ShellExecute(GitExePath, "rev-list --count \"" + currentGitTag + ".." + BuildBranch + "\"").Trim(); + BuildCount = Win32.ShellExecute(GitExePath, "rev-list --count " + BuildBranch).Trim(); + } if (string.IsNullOrEmpty(BuildRevision)) BuildRevision = "0"; @@ -255,8 +264,8 @@ public static void ShowBuildEnvironment(string Platform, bool ShowBuildInfo, boo BuildVersion = "3.0." + BuildRevision; BuildLongVersion = "3.0." + BuildCount + "." + BuildRevision; - - if (ShowBuildInfo) + + if (ShowBuildInfo && !GitExportBuild) { Program.PrintColorMessage("Version: ", ConsoleColor.Cyan, false); Program.PrintColorMessage(BuildVersion + Environment.NewLine, ConsoleColor.White); @@ -525,16 +534,9 @@ public static bool CopyKProcessHacker(bool DebugBuild) Program.PrintColorMessage("Copying KPH driver...", ConsoleColor.Cyan); if (!File.Exists(CustomSignToolPath)) - { - Program.PrintColorMessage("[SKIPPED] CustomSignTool not found.", ConsoleColor.Yellow); return true; - } - if (!File.Exists("build\\kph.key")) - { - Program.PrintColorMessage("[SKIPPED] kph.key not found.", ConsoleColor.Yellow); return true; - } if (DebugBuild) { diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe b/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe index fc9e59071d2563b2d76ea3a8c6eb0350d3a977b5..4f1449cb3744c750cdcb24fc9aa41e20f818a47e 100644 GIT binary patch delta 16949 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 C>HGWu delta 17107 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 X-uK~yz7Mr;HtNp|crY+lKc@XJpGXKi diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb b/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb index 8a6ef390251d29c386caf969281fd9efd5b8d05d..790a3d5de5df704d99bfcbce5cb91749d835306a 100644 GIT binary patch delta 11582 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 Cf!-hh delta 11758 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 diff --git a/tools/delaylib/bin/Debug32/delaylib.lib b/tools/delaylib/bin/Debug32/delaylib.lib index ee4b17dfbb1762135f84694395e1e18ae06262fb..70b36d7a10a74d8054b3fb190f8a56a266db2252 100644 GIT binary patch delta 98 zcmdnBoN?E3#tCvPmc~Y=lNA`nCt5y+vA@9>Vv`M+k|3OEOlnNFf}8g-x!Q`lJUn*E nvs%Y%b^#y%p8Cx!j0_A6E|U$dq$XcrVv`M+k|3OEOlnLC?3?#7x!Q^*tkQG- jzj>F_ycS;r-KDD+F)}bPxJ)**lA3&hReH0pL#{9YMAID^ diff --git a/tools/delaylib/bin/Debug32/delaylib.pdb b/tools/delaylib/bin/Debug32/delaylib.pdb index c3dd1f5dfc764cb77ce138247c5d5970092a7d36..71941c98c2d36c2f5796a7d8690334a12b623f7a 100644 GIT binary patch delta 92 zcmZozz|pXPV*`tWgsq@rBqIX@gUiEXmprR=yk-~h@$aeM%(7X=;RQcV*=Cu5?J@z3 adI`))nR(lNH!$88WvZICUGEsLoDeCuME--N1NXlxa=ecD-YamplQ>@gZmc diff --git a/tools/delaylib/bin/Debug64/delaylib.lib b/tools/delaylib/bin/Debug64/delaylib.lib index ece9f7a57318b6a2a5010aa7eafd93ca6e426c37..7ebf690d5d9f7770babd812de496725c92cc06fc 100644 GIT binary patch delta 88 zcmdnCoN?Q7#tCvPmd54=lQ%GmO|)1CXHQ~W17lY}7&=U9Oj&}PLzt?q1wz@ae@nh% c_t||(HYI;mHpk@qwtCD-nR%N9?3RfF0MAw&cK`qY delta 88 zcmdnCoN?Q7#tCvPX6BZrlQ%GmO|)1CXHQ~W17lY}7&=U9OwsI{Lzt?q1?ncbT>5zb czvraDJvUZHG#O03Z>u-?48eKD#f;rsS{6=GZLb@PZ$wY_m+jc9{Ui aZ}H4YnR(kqH!vEDF=-oZ_d3S7%@Y7dkRAH~ delta 92 zcmZozz|pXPV*`tWL=?MXBqIX@L)|2oOCRt5_nZ{C=f=v2CWFl~4lnp|$~MacY?ldO b{1(rgpOm#-bOWQY7}ME<+r5r4Zu0~HcPS*s diff --git a/tools/delaylib/bin/Release32/delaylib.lib b/tools/delaylib/bin/Release32/delaylib.lib index c068ed7e2912139ff721034307bd0ed3db79f851..d84aba5d43a4a3e4b815e2850b5b964a6adf80c3 100644 GIT binary patch delta 145 zcmZ4XmUr1(-U)Inmd3_rlm9V^ZM2ABgmX5pVhn)usvyEO%vy3Df{KwA|2Fe1y}8C delta 141 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 z�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 z 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 Nu}N$<$Y$1I2LO22BM<-p delta 124 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%0Dx8nS+1+e&DzB0mDCopW__l*xTyhYQV>_+PzrY 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 z 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 literal 0 HcmV?d00001 diff --git a/tools/delaylib/delaylib.vcxproj b/tools/delaylib/delaylib.vcxproj index a06c38f4c7eb..112cba61cfd8 100644 --- a/tools/delaylib/delaylib.vcxproj +++ b/tools/delaylib/delaylib.vcxproj @@ -92,8 +92,6 @@ - - Level3 Disabled _DEBUG;_LIB;%(PreprocessorDefinitions) @@ -106,6 +104,7 @@ true true ProgramDatabase + $(OutDir)$(TargetName).pdb Windows @@ -113,8 +112,6 @@ - - Level3 Disabled WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) @@ -127,6 +124,7 @@ true true ProgramDatabase + $(OutDir)$(TargetName).pdb Windows @@ -135,8 +133,6 @@ Level3 - - MaxSpeed true true @@ -148,6 +144,8 @@ true true true + ProgramDatabase + $(OutDir)$(TargetName).pdb Windows @@ -158,8 +156,6 @@ Level3 - - MaxSpeed true true @@ -171,6 +167,8 @@ true true true + ProgramDatabase + $(OutDir)$(TargetName).pdb Windows From adaa37287aff1e657c8a5462b929a9f0aafb17a2 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 21 May 2017 14:16:57 +1000 Subject: [PATCH 0143/2058] Fix setup build --- tools/CustomSetupTool/CustomSetupTool/resource.rc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tools/CustomSetupTool/CustomSetupTool/resource.rc b/tools/CustomSetupTool/CustomSetupTool/resource.rc index 3599828e2a54..51ef2760a531 100644 --- a/tools/CustomSetupTool/CustomSetupTool/resource.rc +++ b/tools/CustomSetupTool/CustomSetupTool/resource.rc @@ -222,10 +222,11 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_AUS IDR_LICENCE_DATA RCDATA "resources\\LICENSE.txt" #if defined(APSTUDIO_INVOKED) || defined(PH_BUILD_API) -#if defined(APSTUDIO_INVOKED) -IDR_BIN_DATA$(PH_BUILD_API) RCDATA "..\\..\\..\\build\\output\\processhacker-build-bin.zip" -#endif + +IDR_BIN_DATA RCDATA "..\\..\\..\\build\\output\\processhacker-build-bin.zip" + #endif + #endif // English (Australia) resources ///////////////////////////////////////////////////////////////////////////// From e121b8c62358bdb60f197c39e58f2882d5daa9d5 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 21 May 2017 14:30:17 +1000 Subject: [PATCH 0144/2058] Fix delayload bug --- tools/delaylib/bin/Debug32/delaylib.lib | Bin 21434 -> 21466 bytes tools/delaylib/bin/Debug32/delaylib.pdb | Bin 135168 -> 135168 bytes tools/delaylib/bin/Debug64/delaylib.lib | Bin 21430 -> 22424 bytes tools/delaylib/bin/Debug64/delaylib.pdb | Bin 135168 -> 135168 bytes tools/delaylib/bin/Release32/delaylib.lib | Bin 226982 -> 227024 bytes tools/delaylib/bin/Release32/delaylib.pdb | Bin 126976 -> 126976 bytes tools/delaylib/bin/Release64/delaylib.lib | Bin 225884 -> 226788 bytes tools/delaylib/bin/Release64/delaylib.pdb | Bin 126976 -> 135168 bytes tools/delaylib/main.c | 18 ++++++++---------- 9 files changed, 8 insertions(+), 10 deletions(-) diff --git a/tools/delaylib/bin/Debug32/delaylib.lib b/tools/delaylib/bin/Debug32/delaylib.lib index 70b36d7a10a74d8054b3fb190f8a56a266db2252..cc2d9ac662d043be09abfdc7695e9b120c70135a 100644 GIT binary patch delta 2395 zcmaJ@e{54#6h3X&@ir#gWIu=n8J4l3LpnCb1}@nck4;!%8><<_nq&Y zbKgDZ-QL>|j~T8UGwh#cF0_>t6|*cu=7Eyyy79ZtGMLTiv}r+EF;~9LR#a4!l{L?{ zV1Z5ZG$d9VlIh*d8LJPoA!9|tg<_&xMxs;fA(PdxoaLLW2^JI4@lv95Y#p>>)@jNy zS1cyF$4;26<~bEadF(RSdrOE;v%kR_Dv5?!cAV8b3KnAaIICe6+Y*;!p8qsaDLV|? z%Z6ZgE+g`@9}&3^j0Muod4^K{!a*VuaPunZc z`B60-4x13Zxz)Sg?doWCm%Ci8?zT2cr-`YKzIzVb-A0I+pE1!*Rqb5O_T!9 zKy-X}OMB~f%7hYx!Y9@2b#*kkqoZcP(H{+sOr_q*<_gmd-E5^`Ny*08lMPyt7DVn~ zFABLSvtTcbhlD zqV{ww0)BlOwO2i0?~dA+;WyIC)L#)>6&-`;S=eg{Rw<9jw-DAGU={F5;IqKFzzx8B z;7h;)pbRVoD!>K6W55#NaUjOwMjTWLeKwgIMCa@QH1b7hmR^ao*-q|T9$F6^Oc3Rn?^R2Td7 zzYA!+Bf54`*S^-ZZ*?uCYjCL*R!$R%|J>J5diqm8r8TC8q@{b( zHeFS({_r|J2Q6Xw3m;(@&B?61Y?U;uI0R*}V1|QaaZs@fN^Mf-Sbx4YRKuPU9tHt*6jpDq&8qe`^{53FmK|S@H zXc2PnbKt1VzZNL_8?>iOdp1fMG~tO#d-zb1Vx|8mHo$up@{nh0k7KkBlN6I`JmHv@ z_|=^g&=$TQ@XpnNn=7G45xB_*|rL4EBwP;|Z9Y_&JY80gXUy@C+2N5tB z$yp=@J1ohk#e06WeKI~hd@*lQM3r4zY^&odl3)B7m>Qup0zR&HgYz!(i??B%yP7tV zcE_9&{19PlE4EAdSO9#ZPor`$zWC#5wXQYm+9j|@HSZO$*;>Y3Fsr6v8;)u-z@}?j zuCA4W@hPW~L-($YcqNEiboU;xEG_v!#0~EeFq@{m4aSezG&%*AtFe#uxDhaH>6rc~ z*gTEh0K@hU?PoA-@L+#|&DWSix$O#ETJn)#xWM+=E0g#!&Rb!=J!N0uy8Q#Aa~^;3 t1tjn$n`mbBihP_3bTLNZgJmG~ehlxT5ToEsp|}_Y|8+2A;7-ku@gKctQQiOm delta 2179 zcmZXVZERCj7{{O6uB9uJb+Yod0fjOLZfdu|U@Q~pxH6DC*jxoMD8)fw!Wb|_WY{)y z>h;hFIZjOwd|^6>Ba(Cq3LiQ&Kq4ZqqGU0{?86K-san23bpFq6cg*x=%kTgEpXa>X zbMBtq>{Pz$RQ64@l$4be&*Cm+?EbP}WN=5SG2CPFdyFF2u&2o5DJ?B^xr#lrOJ*CH zHTI=SCRJojd8&o?m@3nwbBKO55gq0CncYeyFEYE+O=hCQ6+|EN)$qphkU8Hn)k}1f zA2Yix8I?pM`E{u9LZWv57u38(7{T+>+?EqiSGktvRxEsLTD~QFF;Ol*h`5^fAYQYC zsGk3Z%0{Sd5vQe4sSpdEBqAGr#Zw58k0=fLcl=I9ehw|l61kyAjLAn};xAjTD{y6BSL!O~uHD9gWZPLnCr3 z24Fnq7%HyvH`b>rmm=|_n5A+37II){e`?xwjm_J3(O5V!?y!wh`uGgn!-d_*_M*Ig z(?&9pm7HXjTb_&sM=QqWb1`hJUTNX> z^pdrmNt>crXcU!YT}s6lQn7-|6wmjmc)@?-7gF(c)ca2D7J&IUgP@p%Q0f#u*05FbzQPY{OgTuSUl(jSAuom)1Ww_)!+v38L%D1=7QbeX7Cia6TAfm z@iPFng7@PL-T=pdVbBe}3D$ydgHM`rhz>wB!8i!Ef**jdf*(e1+S_M1iZ5P#E@N5S zXLDAZJ^WJI&mED#%%DB+5ego_YmKB&Qp!%>N$;}sEckkpb?GT(r@7L5RC?Q`w^Mqp z(tAyMJgEX$_#J5;mW7?ti%9Q;^uCtfIq6-M-VN!+q!*XoRVz`c@xnKtCJAXL@prq5 zoX&-}&R$u(yKu>Yrcs%v1CcbIGe0yd!F)F6wOLR@x;nr#8>`6(oiRdRA5(3t$`R@@ zLald$AoC^o<@popVz;+2j84=JI)z=H7!c6aSnHk`HCxZB_mtb(IkkHlT+E}ZCz+O^ zYo{?p_eD#hy84Z-p4Zh2x_U`hudzf}>*n(oObG17cfoua1-?GBuUGf=Gqs=DLbotY zuz3nYY|0xP6f1Qxt*fR1wXxdN+VR`2WOWbjmUQii$R4R>YHayXMeCk8?eH_LpJj#4 z7*)QGb8RhX7O9Qq>1xo}=_}0Fq5EDJJKd|R`*ig!U42(q-@{JBEj-^l(ebT#wL}9o z;)aRJB;y8x!f`8}`a@%8(}y^BXQLh)|m8G28l#i~O! zVsp8|#AEbV(Th7!BTrb?MzlFSBRJ}c8NLb;5=fn*xly-*&*+YcrF8D-P^P}2?7 zCF@Q@p-*Dr^HAuNP}iVJ4AloU(@-%e^iO1cELI;$EIegXqWrkFC`0_S6GsvGVds|- zbM@yYe^D92lNcb*(@fKrRu`ewQgoOjru}=EBc{JQ%n|2$XPAT5O>t9Xd`*u@vHt@N CSMksQ diff --git a/tools/delaylib/bin/Debug32/delaylib.pdb b/tools/delaylib/bin/Debug32/delaylib.pdb index 71941c98c2d36c2f5796a7d8690334a12b623f7a..37c40a7dd5a473a493e4a1da035d44b9289762b5 100644 GIT binary patch delta 73 zcmZozz|pXPV*`tW#0qi6NJa(*2Ag*x8G>Kx-MU1w?;p7TYWijwhZp=fWt(LJw#x)C HKG_cd&lwz* delta 73 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 M7K>)Obo1!{0b`i2OaK4? delta 3967 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 CVqCHS diff --git a/tools/delaylib/bin/Release32/delaylib.lib b/tools/delaylib/bin/Release32/delaylib.lib index d84aba5d43a4a3e4b815e2850b5b964a6adf80c3..667e7b009d508510365868b9312929583b421cfa 100644 GIT binary patch delta 1673 zcmZ`(ZA?>F7(O4RR)MSv!sKI?QZJO00WH(EQs_r!GAUfc$2LYlXe4#fTL|(o1ff!Q zw+U9TnPp9+>ey3~^R@jAyk^C(VR6kINe0GfUX{acfM3@ZgjQEE z^5gm3qBi@}c*d2LFB-nQcxTZlG~e8IjH0ZJO^C-H#D1XPY9EynWDCahn%vkWO?q1M zZwQ%U3z`x<9RF4GGsctgtJ>mp{lZ^&|F~J`KK6vE2~cBh-RJ zIAC3teT&8V@U<+25;bgon(WwThqyy*O{=y@;JH8s`WHc?T8|*Fcg>5R*x$ zMAn+-bT-*LXtK&)W4$1wm#G)c(*t& zSP`Ay%2&|&Iy80^BIe_;i1J;^+jngF*oI8`uiFgdq48stuC~s*?$-lS$>JCKFI6lXCxe zGKbesCdenVt84;EH+V^WcD);?)CWbVn)_MFESw4_^Uo4j<8i29bYuD$q@Peq92aht zFGIid;amJ1IFmJHm&m?TFd`p6ah?G;rxu)S{v62x=)Y%)Ve=`tCx9M)mz|v@IYt>w zKpj_5!ykYp3}?d8kLdK_ANkRDvG#K$zs)|OW}HsGJ_S!enO0v<2BZA-b;9<-TZ)`@ z66bW4AnZADWvK$-y7;~~RIVK;M_A?kFvHqd^#j4+9S-ylv=E z&(ZD?e{c7p{ez(+NG3|kWu!w!Oq}e5MDuYSyCBgT>}3xmYGQQ~O)Gd?>g(+vXzZ4H zoUrbw77(ahXcLQxK+Za$#I?7JREMaX2mi`;8i7~F-Wzvli6bVZ;akM06bTWrr z*6iwpL0L1;!{!90JWS0pn}Am(G0v%(3Hmf8GfRBY`7qs^Z=2ugEkhi!Nzb|8zu)&e z-|yV}<6ZOIU32E~B2SCQ)119ewp{gg;#Dhm8Oy8YP$6)FT3t=eHu&`xBlO?_MiKl> z>DDgq{haB8%R0Wg^D0G~OdF7heVzT5es26_J3*e8vlc^n_B}&MQRo&z zk7chI95|Z$$*_d+Xl~AEFR{3nmJXZbQ&+s5-&{Iwxcz=^x%4e7?o0PM-|TbZg+3>_ z-9vXUA0HVbR(^PlRMIC|P*@)9ih&Ja`NS&yKF z+QjPf=E?1i8R`WM8AoEYUK~`$`&bBetrZqEe1|#JJ+(+{%3IfLPBlC&A#FErn;^Bc zT?_Gx6QrCEPmnUxemKN)tVL`N3ib&k_W~N=p_+6T=cIfO-J_IwhF@JxL4j z%p@t>7K4$$4jJ{wVUh7cK<#AR0>=%DPA9}0CdsbGL+j#;IU@nCiK>FW5Aj`Ha8iLU z<8IBLPe@BGC-RQxq1Own7oH#KMSEDBn=^2C;<_4fU5z*-i-s#|^y+HFbv0gEt43U? z;i^kKDnt@U=^T#Acu>a2xMK<=@8^*z5)6(2FGWEJI{jBcWfa^{Je)s(k_L-iZ&(CI z7UjCQ0sZ{5DNq}ciTM5>96$of8u)uqoHx5D13x(eA3fQzupYHeK;46iI zGjETG^Iz172pq7c!FqVh{{7}DGYdDe#Jcz|xV8%?MfQNTi|q^GRxleu3jzW9A;-#KS*v~~K_rx^TM nY}}C@Fjg&G7@#+e6u#Pge~NDAr&H8SLbrH(ik9(@Q`G(sLd?tE diff --git a/tools/delaylib/bin/Release32/delaylib.pdb b/tools/delaylib/bin/Release32/delaylib.pdb index a39cad85a921cd2a5f67dc568aa9b71582950f3b..0bf14ba171d73ac093d01ba017edea9e59be0c84 100644 GIT binary patch delta 73 zcmZp8z~1nHeFKYw#5!@sNJa(*2FJhEE1y}~JMGIh%l)YzB)eJ0;RQcV*=Cu5?J@z3 HPv!#v&Y~LG delta 73 zcmZp8z~1nHeFKYwgomJFBqIX@!=_~qCH6e8^qZ=a;OnrUb;o8IhZp=fWt(LJw#x)C HKA8^y+O!+P diff --git a/tools/delaylib/bin/Release64/delaylib.lib b/tools/delaylib/bin/Release64/delaylib.lib index 9a4e68d5ee6894cafef8e41cdb7095448ebeea2e..b02b934e17e3e210055d34ce0fbb739c1a0788ba 100644 GIT binary patch delta 5041 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 delta 4103 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 diff --git a/tools/delaylib/bin/Release64/delaylib.pdb b/tools/delaylib/bin/Release64/delaylib.pdb index 12ca4d89de69107a8c599032fcf8bf29b52c2506..05e18d14c67d6fc6ac455d1e2dce98390b49f515 100644 GIT binary patch delta 3445 zcma)933QZ260WcRoE$kPAt47jAO}%M$OYs8Btb9~k*%Igi0*s7xBq)J)n9dWb#-@D zbx%{9XVXTn*_3(ld7sMwdNXo z*E@lYhO1|qWp0(Vc1rDEt@Sl#n>6V{m$vNY>c3&nmOua3T3W~5rBiyRx!zJa(OOee zW&2+p50}oA8uMIBU#C6nu=gK5f6s^f`K0Z8x%x}$tL_ok=UOUnG0&@-(`TiYx^5%S zAa5dNlfBq0+c~=^zo>ZHO#3U>Lp@y0L)U{EyCMkz9-?E&k0yN-n#YPPR=5v&`2|Ru z$b;UMzJ8?q_6r|CpkNv6COy6SG1884jnVUx?ACj(G4H#^^pi0<5Z?CJwgbKVdK5t) zx)cxEyDmlcx)^;m)V;^=l*>U_Z-3y&A&q)AFPczYZJpyh7+Jf8E?(#wC_AG)@cUI? zNxju(nPVf}r&kn0J?C0lweUA%qNvnnwppBd+Qv}o9oc6$fyx%tStzn=D!B)F%GQ1? z9`}C9H#Yb;F53$`f_Z%$yxAIuHTaah<57wuJS!drILce&@g6?sh6LP&FZgrKaUIEl($-NKB3w@% zDqKf$T<_%0{;8JvHgd+(V8LEA*<4#$ZK;h&DHAI;96F)^Rt%9Rt2 z;F;s(6o&9e#i<57M1kjANfxJ~1BHkSPD$=bDbX)+;*=Y>!ih)Sz;#ZXdIL8(aoP>M+=$}k(_IkX&&2;w#6V&oS7t{kzL=a|vj_BA#tUy61xz4XXS%@j5F)8{dePaKE4E>uAum z1Vt^01}!ujw56TsLY6@%4=B1Pf+%Z=qNf)bRD7pF`QIy2Q)SAna_*-=+holBRWhbr z(HXgA{O?v|J7SO})u5XuC>nXdpmNbYF-K9!>!638HYj4TqJ0mlY$ifa%59`+ytK<4DNQ)&Yi}!#YF&=iUO2{UR!b>7&O28l)Bl864wScvNp3OyRyoB# zua<)SB|o+Xi_yXUYmwytwJ7l?qA~bH#=`rqZ;@b6SRh}k}+kg+1 zw}~%rKs$W+*haZS{CVIeH2Uk(m!_8~OVlofbMq#Y`bP@Zo@UE2YH^eU&&gsD&k>vP z4obm!P-Sw7tJ8E9QIv|t1 zUzB@i4DWss>tbRE!7@AP_rp}%?G2Xt1=FkQZ4Kt?p4S>(?OellggCFP6m$4@JQGttv zo)mgY=n0_f8DX+Ti`+5Teh8PC8ES5Vxls9igaQa6*PbXN8{;8vV9}i5Jlw z9~rcG3}|01(E*VUeMHf+B1P|5BqAl34vB0~ry_0hFrR3VP5qd!wIH@J$=9H+tsw8G zKu4uFH-V`2O_1;36n!gM^Cu5Q$3#9d*Pv6vi{cbjXDIsf`=Aqo7p#NRs{tW$DGJS! z;^A@0ppdJIF8E16FEq$Ul{8Dt9K^{*i^F-VkRWRh^< zK6fb^EIeLl)p5`p#}(aMOf*bzf9`ktnnd={AVmSfS6()# zVFXc#mVHkYEL@u&{s_@?380nN4d)a;pH&paN@# zTFNO&J$bn9k_|h!S5cfe-1Gs_DXFg8r5=7E)$+_gC5I*U^_L{E;N_UmikH20rEp&% zxRd?&AaG!wJR&q{O(_n0@YetPk0n~-L|^_?AoQ@*9sMOF6NL&dlNri5`Vel7kaFu3 i4Hh0Iq>GZyltDt_J0>jh-I4abZ;M}Dr|*iAy#E4Vo=1xS delta 2586 zcmZ`*X;f5K60Yw)c7>*Cp+#s}+*pMc1e8TODsf*za5+auJ=#G}bliv|8AmWmG@u4Y zl2UPBCX#UpVUF);W+w578pSU!Vz>ej7$Z&lqc z-0D$S?_L_=9YRFQM2x3%RoLVjlS@5OVHHAuF?}BD654TqIcz-Sa|-G5_v z+M_osI+j%hXI^ZFQ&r|+54E)`M|!enDXhU|J?;4aBSy8q6z)avGyEMf6Zw#bZ=Spp zfsR>-yh!;Tx2)Z~Cz!WKVmnUqz$j#+hSx`7C{FXuDAeFAS4QJ)oM&4MM&cWu6@wDg z^3xb3;1b8i!isNsU@X4TE?bBjViC;AJ>kR^-qaIoQK#GE&;z)}jHm^m}c zIVJC%dCvLtxG{@d{o4_#hg_M0rD)W9_dzP~gy;4}GXBjKeG#piEPSaiR{Q-V4%*8G z6qDxX?XS_#7G98wV(+KIzkDJ%EENG9Vnt`&kp>IYe=IyE9fw?=ixt~5VCCoxEK$uC z-j{(+AU=_S9scM*6i?aCnQu{Jlmz7=K`CC+50l`+4gF-RT={7~9EUp}&O`w`+2KHH zPCFT9gcKlWkn210ftXx&CJW5vcM_( zZ20Zi!VPjxndY2FPg=P^;X*OYnLA}_{!7mAxfSDP&5Cc0$H1Q%*xrV}GH|ape9piL zuW$j?8${wOf*u*TcN-=pIH?W$8aTNPhZ;Dg4aXa}PaDoOusxoPg&6^kYQgpwxF6Bv z7NXZHgE=iY;T0}y!HKVMX$$V%f;(~L>vGgVoIgm4%EqS$VLn21$6#o136t4)_7H^e zj3JWpUG%V_DA3SN-!=j!pod;L5+xcU_4I5xMMUd4Z%XwcmUrcV5y$Ccq^PXAa}4?e zfm|^bL4kH-%Sl%BhBJ4@{5GM#dTxFNdh;Gl|<~#IpZYtytsCpgq6&Zy+xz7H$f8zE4pU|=gx-BJ=2@W zZJOee+2~!+Ase*pGteJ>rLLsyd|&|``~%2+0@3|7iuO1)>b{t$elX~1grcfQjaHT` z+I^kqajHgEVh7K2W4aXtc0GlB@x=SH>)!q0#A;if(xlZI0F` z?~+E&1TCKGqCs&dHOdj=x~Ymr9Rj_z7-UqpR=tYM`WaGc9 zuXKFx^Kl{Cck3(A_m*r6H8&gO+}y0mFVP*}R>_q22;E+YvnD;X6ze>2h7Ybo5YBP! zIwYGfh+B);c96d9Lv8^V*|uJK?sr_V9?S7P+czNEd{vB0Vl+&(8vTQ3ZNNR(dZC~5 z#B$ujaUQ%8C9cYYWb(Uo9N471yEh)2(t1xN+<@6qt<`)l04!Q7v(s`ET2hZMFzD zB2AOSGM3}7hi#X|$~}?3Lt0a3zPkf)2<5vMh8E|dc?9Qlb{9X+}36O{AD-3UfJAKZQr6R>5B_bb)JZ@a$NICEo>Va?dyN6{u zvtKdjid^OqNg7=ieU0}Xfi?Yxyml>8R5D!3#VJ`MiQOQa^^v06qHl^!NL2K08mMsy z=!>sGSr;_A^bl0Ts74p>J)cV#t^j#{2s**`YFJ-8BctLnG`c8ycy~oJlN9~t6zGEB z{PNa7>g3&+Y2qKP!4HWk~O8GBX!fqm#NB!hfnp=SZ)PMB(DkTeQ#HiY%go zMLxa)`s)=%i$)T45**6+B_i}-^HEs(bQ5N&RZ%<9Wj|{4PEScJgL@$7E86fDRYbHs z0#x=)Yw`O0j*?WHcofMtt9*X;K2bRq&u-|jdC|{#wT~`TJ%I0&hcqhumYlvYyK)0X6 zm;dv(D@^Wn Date: Mon, 22 May 2017 04:30:46 +1000 Subject: [PATCH 0145/2058] Revert --- .gitignore | 1 - ProcessHacker.sln | 5 - ProcessHacker/ProcessHacker.def | 20 ++-- ProcessHacker/ProcessHacker.vcxproj | 21 ++-- ProcessHacker/ProcessHacker.vcxproj.filters | 3 - ProcessHacker/exports.c | 97 ------------------- ProcessHacker/include/appsup.h | 4 +- ProcessHacker/include/mainwnd.h | 2 +- ProcessHacker/include/netprv.h | 4 + ProcessHacker/include/phapp.h | 88 +---------------- ProcessHacker/include/phplug.h | 13 --- ProcessHacker/include/procprv.h | 5 + ProcessHacker/include/srvprv.h | 5 + ProcessHacker/log.c | 5 +- ProcessHacker/logwnd.c | 5 +- ProcessHacker/main.c | 2 +- ProcessHacker/mainwnd.c | 6 +- ProcessHacker/memlists.c | 5 +- ProcessHacker/miniinfo.c | 12 +-- ProcessHacker/mwpgnet.c | 8 +- ProcessHacker/mwpgproc.c | 8 +- ProcessHacker/mwpgsrv.c | 8 +- ProcessHacker/netprv.c | 14 ++- ProcessHacker/notifico.c | 2 +- ProcessHacker/plugin.c | 20 ++-- ProcessHacker/procprv.c | 15 ++- ProcessHacker/procrec.c | 2 +- ProcessHacker/prpggen.c | 4 +- ProcessHacker/prpgperf.c | 5 +- ProcessHacker/prpgstat.c | 5 +- ProcessHacker/prpgthrd.c | 2 +- ProcessHacker/srvctl.c | 5 +- ProcessHacker/srvlist.c | 8 +- ProcessHacker/srvprv.c | 14 ++- ProcessHacker/sysinfo.c | 8 +- ProcessHacker/thrdprv.c | 5 +- phlib/global.c | 34 +++---- phlib/include/phconfig.h | 71 ++++++++------ phlib/include/phsup.h | 8 -- phnt/include/phnt.h | 10 -- plugins/DotNetTools/clrsup.c | 2 +- plugins/DotNetTools/perfpage.c | 2 +- plugins/DotNetTools/stackext.c | 2 +- plugins/ExtendedNotifications/filelog.c | 2 +- plugins/ExtendedServices/main.c | 20 ++-- plugins/ExtendedServices/other.c | 2 +- plugins/ExtendedServices/recovery.c | 4 +- plugins/ExtendedTools/disktab.c | 34 +++---- plugins/ExtendedTools/etwdisk.c | 2 +- plugins/ExtendedTools/etwmon.c | 8 +- plugins/ExtendedTools/etwprprp.c | 14 +-- plugins/ExtendedTools/etwstat.c | 8 +- plugins/ExtendedTools/exttools.h | 4 + plugins/ExtendedTools/gpumon.c | 10 +- plugins/ExtendedTools/gpunodes.c | 10 +- plugins/ExtendedTools/gpuprprp.c | 16 +-- plugins/ExtendedTools/main.c | 6 +- plugins/ExtendedTools/unldll.c | 6 +- plugins/ExtendedTools/wswatch.c | 2 +- plugins/ExtraPlugins/cloud.c | 2 +- plugins/ExtraPlugins/dialog.c | 2 +- plugins/ExtraPlugins/setup/page5.c | 8 +- plugins/ExtraPlugins/setup/updater.c | 28 ++++-- plugins/HardwareDevices/disknotify.c | 6 +- plugins/HardwareDevices/main.c | 4 +- plugins/HardwareDevices/netdetails.c | 4 +- plugins/HardwareDevices/netoptions.c | 4 +- plugins/HardwareDevices/storage.c | 6 +- plugins/NetworkTools/pages.c | 6 +- plugins/NetworkTools/ping.c | 8 +- plugins/NetworkTools/tracert.c | 7 +- plugins/NetworkTools/update.c | 63 ++++++++---- plugins/NetworkTools/whois.c | 5 +- plugins/OnlineChecks/main.c | 14 ++- plugins/OnlineChecks/page1.c | 2 +- plugins/OnlineChecks/page2.c | 2 +- plugins/OnlineChecks/page3.c | 2 +- plugins/OnlineChecks/page4.c | 4 +- plugins/OnlineChecks/upload.c | 40 ++++++-- plugins/OnlineChecks/virustotal.c | 8 +- plugins/Plugins.props | 9 +- plugins/ToolStatus/customizesb.c | 4 +- plugins/ToolStatus/customizetb.c | 10 +- plugins/ToolStatus/graph.c | 14 +-- plugins/ToolStatus/main.c | 58 +++++------ plugins/ToolStatus/options.c | 6 +- plugins/ToolStatus/statusbar.c | 8 +- plugins/ToolStatus/toolbar.c | 6 +- plugins/Updater/options.c | 4 +- plugins/Updater/page5.c | 8 +- plugins/Updater/updater.c | 24 ++--- plugins/Updater/updater.h | 3 + plugins/UserNotes/main.c | 15 ++- plugins/WindowExplorer/WindowExplorer.vcxproj | 4 +- plugins/WindowExplorer/main.c | 2 +- plugins/WindowExplorer/wndexp.h | 4 +- plugins/WindowExplorer/wndprp.c | 2 +- tools/peview/peview.vcxproj | 20 ++-- 98 files changed, 505 insertions(+), 634 deletions(-) delete mode 100644 ProcessHacker/exports.c diff --git a/.gitignore b/.gitignore index 230b4fd6ceab..53afad1c8da7 100644 --- a/.gitignore +++ b/.gitignore @@ -117,4 +117,3 @@ tools/GenerateZw/GenerateZw/bin/Release/* !tools/GenerateZw/GenerateZw/bin/Release/GenerateZw.exe !tools/delaylib/bin/ -!*pdb* diff --git a/ProcessHacker.sln b/ProcessHacker.sln index 241b7a6e05d2..4e87a04af677 100644 --- a/ProcessHacker.sln +++ b/ProcessHacker.sln @@ -12,8 +12,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "phlib", "phlib\phlib.vcxpro EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "peview", "tools\peview\peview.vcxproj", "{72C124A2-3C80-41C6-ABA1-C4948B713204}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tools", "Tools", "{9963724D-4A1D-4442-AD5A-1CE899D30D96}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 @@ -50,7 +48,4 @@ Global GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection - GlobalSection(NestedProjects) = preSolution - {72C124A2-3C80-41C6-ABA1-C4948B713204} = {9963724D-4A1D-4442-AD5A-1CE899D30D96} - EndGlobalSection EndGlobal diff --git a/ProcessHacker/ProcessHacker.def b/ProcessHacker/ProcessHacker.def index 99e444c9bc65..97692aee76bf 100644 --- a/ProcessHacker/ProcessHacker.def +++ b/ProcessHacker/ProcessHacker.def @@ -37,16 +37,18 @@ EXPORTS PhfWakeForReleaseQueuedLock ; phconfig - PhGetSystemBasicInformation - PhWindowsVersion - PhGetGlobalDpi - PhGetImageBase + PhGlobalDpi DATA + PhHeapHandle DATA PhIsExecutingInWow64 - PhProcessAllAccess - PhProcessQueryAccess - PhThreadAllAccess - PhThreadQueryAccess - PhThreadSetAccess + PhLibImageBase DATA + PhOsVersion DATA + PhSystemBasicInformation DATA + ProcessAllAccess DATA + ProcessQueryAccess DATA + ThreadAllAccess DATA + ThreadQueryAccess DATA + ThreadSetAccess DATA + WindowsVersion DATA ; phbasesup PhAddElementAvlTree diff --git a/ProcessHacker/ProcessHacker.vcxproj b/ProcessHacker/ProcessHacker.vcxproj index 67fcd39e46f5..5e3e2d24f2de 100644 --- a/ProcessHacker/ProcessHacker.vcxproj +++ b/ProcessHacker/ProcessHacker.vcxproj @@ -95,15 +95,14 @@ true - aclui.lib;comctl32.lib;delaylib.lib;iphlpapi.lib;noarg.obj;noenv.obj;ntdll.lib;phlib.lib;uxtheme.lib;version.lib;windowscodecs.lib;winsta.lib;ws2_32.lib;%(AdditionalDependencies) + aclui.lib;comctl32.lib;iphlpapi.lib;noarg.obj;noenv.obj;ntdll.lib;phlib.lib;uxtheme.lib;version.lib;windowscodecs.lib;winsta.lib;ws2_32.lib;%(AdditionalDependencies) true Windows MachineX86 6.01 - ..\phlib\bin\$(Configuration)$(PlatformArchitecture);..\tools\delaylib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) + ..\phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) ProcessHacker.def aclui.dll;iphlpapi.dll;ws2_32.dll;%(DelayLoadDLLs) - ___delayLoadHelper2@8 _UNICODE;UNICODE;%(PreprocessorDefinitions);$(ExternalCompilerOptions) @@ -127,15 +126,14 @@ true - aclui.lib;comctl32.lib;delaylib.lib;iphlpapi.lib;noarg.obj;noenv.obj;ntdll.lib;phlib.lib;uxtheme.lib;version.lib;windowscodecs.lib;winsta.lib;ws2_32.lib;%(AdditionalDependencies) + aclui.lib;comctl32.lib;iphlpapi.lib;noarg.obj;noenv.obj;ntdll.lib;phlib.lib;uxtheme.lib;version.lib;windowscodecs.lib;winsta.lib;ws2_32.lib;%(AdditionalDependencies) true Windows MachineX64 6.01 - ..\phlib\bin\$(Configuration)$(PlatformArchitecture);..\tools\delaylib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) + ..\phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) ProcessHacker.def aclui.dll;iphlpapi.dll;ws2_32.dll;%(DelayLoadDLLs) - __delayLoadHelper2 _UNICODE;UNICODE;%(PreprocessorDefinitions);$(ExternalCompilerOptions) @@ -164,7 +162,7 @@ StreamingSIMDExtensions - aclui.lib;comctl32.lib;delaylib.lib;iphlpapi.lib;noarg.obj;noenv.obj;ntdll.lib;phlib.lib;uxtheme.lib;version.lib;windowscodecs.lib;winsta.lib;ws2_32.lib;%(AdditionalDependencies) + aclui.lib;comctl32.lib;iphlpapi.lib;noarg.obj;noenv.obj;ntdll.lib;phlib.lib;uxtheme.lib;version.lib;windowscodecs.lib;winsta.lib;ws2_32.lib;%(AdditionalDependencies) true Windows true @@ -172,10 +170,9 @@ MachineX86 true 6.01 - ..\phlib\bin\$(Configuration)$(PlatformArchitecture);..\tools\delaylib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) + ..\phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) ProcessHacker.def aclui.dll;iphlpapi.dll;ws2_32.dll;%(DelayLoadDLLs) - ___delayLoadHelper2@8 _UNICODE;UNICODE;%(PreprocessorDefinitions);$(ExternalCompilerOptions) @@ -199,7 +196,7 @@ true - aclui.lib;comctl32.lib;delaylib.lib;iphlpapi.lib;noarg.obj;noenv.obj;ntdll.lib;phlib.lib;uxtheme.lib;version.lib;windowscodecs.lib;winsta.lib;ws2_32.lib;%(AdditionalDependencies) + aclui.lib;comctl32.lib;iphlpapi.lib;noarg.obj;noenv.obj;ntdll.lib;phlib.lib;uxtheme.lib;version.lib;windowscodecs.lib;winsta.lib;ws2_32.lib;%(AdditionalDependencies) true Windows true @@ -207,10 +204,9 @@ MachineX64 true 6.01 - ..\phlib\bin\$(Configuration)$(PlatformArchitecture);..\tools\delaylib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) + ..\phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) ProcessHacker.def aclui.dll;iphlpapi.dll;ws2_32.dll;%(DelayLoadDLLs) - __delayLoadHelper2 _UNICODE;UNICODE;%(PreprocessorDefinitions);$(ExternalCompilerOptions) @@ -229,7 +225,6 @@ - diff --git a/ProcessHacker/ProcessHacker.vcxproj.filters b/ProcessHacker/ProcessHacker.vcxproj.filters index d8d900f22ea6..e4fac5fddc0e 100644 --- a/ProcessHacker/ProcessHacker.vcxproj.filters +++ b/ProcessHacker/ProcessHacker.vcxproj.filters @@ -381,9 +381,6 @@ Process Hacker - - Process Hacker - diff --git a/ProcessHacker/exports.c b/ProcessHacker/exports.c deleted file mode 100644 index c20fa19ae156..000000000000 --- a/ProcessHacker/exports.c +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Process Hacker - - * exported variables - * - * Copyright (C) 2017 dmex - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include -#include -#include -#include -#include - -HFONT PhGetApplicationFont( - VOID - ) -{ - return PhApplicationFont; -} - -HWND PhGetMainWndHandle( - VOID - ) -{ - return PhMainWndHandle; -} - -PVOID PhGetImageBase( - VOID - ) -{ - return PhLibImageBase; -} - -ULONG PhGetGlobalDpi( - VOID - ) -{ - return PhGlobalDpi; -} - -SYSTEM_BASIC_INFORMATION PhGetSystemBasicInformation( - VOID - ) -{ - return PhSystemBasicInformation; -} - -ACCESS_MASK PhProcessQueryAccess( - VOID - ) -{ - return ProcessQueryAccess; -} - -ACCESS_MASK PhProcessAllAccess( - VOID - ) -{ - return ProcessAllAccess; -} - -ACCESS_MASK PhThreadQueryAccess( - VOID - ) -{ - return ThreadQueryAccess; -} - -ACCESS_MASK PhThreadSetAccess( - VOID - ) -{ - return ThreadSetAccess; -} - -ACCESS_MASK PhThreadAllAccess( - VOID - ) -{ - return ThreadAllAccess; -} \ No newline at end of file diff --git a/ProcessHacker/include/appsup.h b/ProcessHacker/include/appsup.h index 275273f6d4e8..fe34c8977206 100644 --- a/ProcessHacker/include/appsup.h +++ b/ProcessHacker/include/appsup.h @@ -416,8 +416,8 @@ PPH_STRING PhPcre2GetErrorMessage( _In_ INT ErrorCode ); -#define PH_LOAD_SHARED_ICON_SMALL(BaseAddress, Name) PhLoadIcon(BaseAddress, (Name), PH_LOAD_ICON_SHARED | PH_LOAD_ICON_SIZE_SMALL, 0, 0) // phapppub -#define PH_LOAD_SHARED_ICON_LARGE(BaseAddress, Name) PhLoadIcon(BaseAddress, (Name), PH_LOAD_ICON_SHARED | PH_LOAD_ICON_SIZE_LARGE, 0, 0) // phapppub +#define PH_LOAD_SHARED_ICON_SMALL(Name) PhLoadIcon(PhInstanceHandle, (Name), PH_LOAD_ICON_SHARED | PH_LOAD_ICON_SIZE_SMALL, 0, 0) +#define PH_LOAD_SHARED_ICON_LARGE(Name) PhLoadIcon(PhInstanceHandle, (Name), PH_LOAD_ICON_SHARED | PH_LOAD_ICON_SIZE_LARGE, 0, 0) FORCEINLINE PVOID PhpGenericPropertyPageHeader( _In_ HWND hwndDlg, diff --git a/ProcessHacker/include/mainwnd.h b/ProcessHacker/include/mainwnd.h index d93cc50263ac..d7607624acd1 100644 --- a/ProcessHacker/include/mainwnd.h +++ b/ProcessHacker/include/mainwnd.h @@ -3,7 +3,7 @@ #define PH_MAINWND_CLASSNAME L"ProcessHacker" // phapppub -extern HWND PhMainWndHandle; +PHAPPAPI extern HWND PhMainWndHandle; // phapppub extern BOOLEAN PhMainWndExiting; #define WM_PH_FIRST (WM_APP + 99) diff --git a/ProcessHacker/include/netprv.h b/ProcessHacker/include/netprv.h index b4b34835f35f..beaecea2b4a1 100644 --- a/ProcessHacker/include/netprv.h +++ b/ProcessHacker/include/netprv.h @@ -2,6 +2,10 @@ #define PH_NETPRV_H extern PPH_OBJECT_TYPE PhNetworkItemType; +PHAPPAPI extern PH_CALLBACK PhNetworkItemAddedEvent; // phapppub +PHAPPAPI extern PH_CALLBACK PhNetworkItemModifiedEvent; // phapppub +PHAPPAPI extern PH_CALLBACK PhNetworkItemRemovedEvent; // phapppub +PHAPPAPI extern PH_CALLBACK PhNetworkItemsUpdatedEvent; // phapppub extern BOOLEAN PhEnableNetworkProviderResolve; diff --git a/ProcessHacker/include/phapp.h b/ProcessHacker/include/phapp.h index d0160089cf5b..5a9914f8a514 100644 --- a/ProcessHacker/include/phapp.h +++ b/ProcessHacker/include/phapp.h @@ -74,7 +74,7 @@ typedef struct _PH_STARTUP_PARAMETERS extern PPH_STRING PhApplicationDirectory; extern PPH_STRING PhApplicationFileName; -extern HFONT PhApplicationFont; +PHAPPAPI extern HFONT PhApplicationFont; // phapppub extern PPH_STRING PhCurrentUserName; extern HINSTANCE PhInstanceHandle; extern PPH_STRING PhLocalSystemName; @@ -87,6 +87,8 @@ extern PH_STARTUP_PARAMETERS PhStartupParameters; extern PH_PROVIDER_THREAD PhPrimaryProviderThread; extern PH_PROVIDER_THREAD PhSecondaryProviderThread; +#define PH_SCALE_DPI(Value) PhMultiplyDivide(Value, PhGlobalDpi, 96) // phapppub + // begin_phapppub PHAPPAPI VOID @@ -133,87 +135,6 @@ VOID PhInitializeFont( _In_ HWND hWnd ); -// begin_phapppub -PHAPPAPI -HFONT -NTAPI -PhGetApplicationFont( - VOID - ); - -PHAPPAPI -HWND -NTAPI -PhGetMainWndHandle( - VOID - ); - -#define PhMainWindowHandle \ - PhGetMainWndHandle() - -PHLIBAPI -PVOID -NTAPI -PhGetImageBase( - VOID - ); - -#define PhImageBaseAddress \ - PhGetImageBase() - -PHLIBAPI -ULONG -NTAPI -PhGetGlobalDpi( - VOID - ); - -#define PH_SCALE_DPI(Value) \ - PhMultiplyDivide(Value, PhGetGlobalDpi(), 96) - -PHLIBAPI -SYSTEM_BASIC_INFORMATION -NTAPI -PhGetSystemBasicInformation( - VOID - ); - -PHLIBAPI -ACCESS_MASK -NTAPI -PhProcessQueryAccess( - VOID - ); - -PHLIBAPI -ACCESS_MASK -NTAPI -PhProcessAllAccess( - VOID - ); - -PHLIBAPI -ACCESS_MASK -NTAPI -PhThreadQueryAccess( - VOID - ); - -PHLIBAPI -ACCESS_MASK -NTAPI -PhThreadSetAccess( - VOID - ); - -PHLIBAPI -ACCESS_MASK -NTAPI -PhThreadAllAccess( - VOID - ); -// end_phapppub - // plugin extern PH_AVL_TREE PhPluginsByName; @@ -290,6 +211,7 @@ typedef struct _PH_LOG_ENTRY } PH_LOG_ENTRY, *PPH_LOG_ENTRY; extern PH_CIRCULAR_BUFFER_PVOID PhLogBuffer; +PHAPPAPI extern PH_CALLBACK PhLoggedCallback; // phapppub VOID PhLogInitialization( VOID @@ -721,7 +643,7 @@ PhCreateCommonFont( return NULL; fontHandle = CreateFont( - -PhMultiplyDivideSigned(Size, PhGetGlobalDpi(), 72), + -PhMultiplyDivideSigned(Size, PhGlobalDpi, 72), 0, 0, 0, diff --git a/ProcessHacker/include/phplug.h b/ProcessHacker/include/phplug.h index cc2de419a98c..68ea5602ede1 100644 --- a/ProcessHacker/include/phplug.h +++ b/ProcessHacker/include/phplug.h @@ -44,19 +44,6 @@ typedef enum _PH_GENERAL_CALLBACK GeneralCallbackMemoryItemListControl = 31, // PPH_PLUGIN_MEMORY_ITEM_LIST_CONTROL Data [properties thread] GeneralCallbackMiniInformationInitializing = 32, // PPH_PLUGIN_MINIINFO_POINTERS Data [main thread] GeneralCallbackMiListSectionMenuInitializing = 33, // PPH_PLUGIN_MENU_INFORMATION Data [main thread] - GeneralCallbackLoggedEvent = 34, // PPH_LOG_ENTRY data [provider thread] - GeneralCallbackProcessProviderAdded = 35, // PPH_PROCESS_ITEM data [provider thread] - GeneralCallbackProcessProviderModified = 36, // PPH_PROCESS_ITEM data [provider thread] - GeneralCallbackProcessProviderRemoved = 37, // PPH_PROCESS_ITEM data [provider thread] - GeneralCallbackProcessProviderUpdated = 38, // [provider thread] - GeneralCallbackServiceProviderAdded = 39, // PPH_SERVICE_ITEM data [provider thread] - GeneralCallbackServiceProviderModified = 40, // PPH_SERVICE_ITEM data [provider thread] - GeneralCallbackServiceProviderRemoved = 41, // PPH_SERVICE_ITEM data [provider thread] - GeneralCallbackServiceProviderUpdated = 42, // [provider thread] - GeneralCallbackNetworkProviderAdded = 43, // PPH_NETWORK_ITEM data [provider thread] - GeneralCallbackNetworkProviderModified = 44, // PPH_NETWORK_ITEM data [provider thread] - GeneralCallbackNetworkProviderRemoved = 45, // PPH_NETWORK_ITEM data [provider thread] - GeneralCallbackNetworkProviderUpdated = 46, // [provider thread] GeneralCallbackMaximum } PH_GENERAL_CALLBACK, *PPH_GENERAL_CALLBACK; diff --git a/ProcessHacker/include/procprv.h b/ProcessHacker/include/procprv.h index 169268452962..f79546f534fd 100644 --- a/ProcessHacker/include/procprv.h +++ b/ProcessHacker/include/procprv.h @@ -6,6 +6,11 @@ extern PPH_OBJECT_TYPE PhProcessItemType; +PHAPPAPI extern PH_CALLBACK PhProcessAddedEvent; // phapppub +PHAPPAPI extern PH_CALLBACK PhProcessModifiedEvent; // phapppub +PHAPPAPI extern PH_CALLBACK PhProcessRemovedEvent; // phapppub +PHAPPAPI extern PH_CALLBACK PhProcessesUpdatedEvent; // phapppub + extern PPH_LIST PhProcessRecordList; extern PH_QUEUED_LOCK PhProcessRecordListLock; diff --git a/ProcessHacker/include/srvprv.h b/ProcessHacker/include/srvprv.h index d511db7cdf69..a01349d8005e 100644 --- a/ProcessHacker/include/srvprv.h +++ b/ProcessHacker/include/srvprv.h @@ -3,6 +3,11 @@ extern PPH_OBJECT_TYPE PhServiceItemType; +PHAPPAPI extern PH_CALLBACK PhServiceAddedEvent; // phapppub +PHAPPAPI extern PH_CALLBACK PhServiceModifiedEvent; // phapppub +PHAPPAPI extern PH_CALLBACK PhServiceRemovedEvent; // phapppub +PHAPPAPI extern PH_CALLBACK PhServicesUpdatedEvent; // phapppub + extern BOOLEAN PhEnableServiceNonPoll; // begin_phapppub diff --git a/ProcessHacker/log.c b/ProcessHacker/log.c index b5334c064109..a57862b1c614 100644 --- a/ProcessHacker/log.c +++ b/ProcessHacker/log.c @@ -21,10 +21,11 @@ */ #include -#include + #include PH_CIRCULAR_BUFFER_PVOID PhLogBuffer; +PHAPPAPI PH_CALLBACK_DECLARE(PhLoggedCallback); VOID PhLogInitialization( VOID @@ -154,7 +155,7 @@ VOID PhpLogEntry( if (oldEntry) PhpFreeLogEntry(oldEntry); - PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackLoggedEvent), Entry); + PhInvokeCallback(&PhLoggedCallback, Entry); } VOID PhClearLogEntries( diff --git a/ProcessHacker/logwnd.c b/ProcessHacker/logwnd.c index 2be84a749e1e..0a9b71a94b62 100644 --- a/ProcessHacker/logwnd.c +++ b/ProcessHacker/logwnd.c @@ -21,7 +21,6 @@ */ #include -#include #include #include @@ -188,7 +187,7 @@ INT_PTR CALLBACK PhpLogDlgProc( Button_SetCheck(GetDlgItem(hwndDlg, IDC_AUTOSCROLL), BST_CHECKED); - PhRegisterCallback(PhGetGeneralCallback(GeneralCallbackLoggedEvent), LoggedCallback, NULL, &LoggedRegistration); + PhRegisterCallback(&PhLoggedCallback, LoggedCallback, NULL, &LoggedRegistration); PhpUpdateLogList(); ListView_EnsureVisible(ListViewHandle, ListViewCount - 1, FALSE); } @@ -200,7 +199,7 @@ INT_PTR CALLBACK PhpLogDlgProc( PhDeleteLayoutManager(&WindowLayoutManager); - PhUnregisterCallback(PhGetGeneralCallback(GeneralCallbackLoggedEvent), &LoggedRegistration); + PhUnregisterCallback(&PhLoggedCallback, &LoggedRegistration); PhUnregisterDialog(PhLogWindowHandle); PhLogWindowHandle = NULL; } diff --git a/ProcessHacker/main.c b/ProcessHacker/main.c index f25656fa2284..3d8b82255a96 100644 --- a/ProcessHacker/main.c +++ b/ProcessHacker/main.c @@ -77,7 +77,7 @@ VOID PhpEnablePrivileges( PPH_STRING PhApplicationDirectory; PPH_STRING PhApplicationFileName; -HFONT PhApplicationFont; +PHAPPAPI HFONT PhApplicationFont; PPH_STRING PhCurrentUserName = NULL; HINSTANCE PhInstanceHandle; PPH_STRING PhLocalSystemName = NULL; diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index b6b7a5d9c4c6..3d4c8539dd18 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -57,7 +57,7 @@ #define RUNAS_MODE_ADMIN 1 #define RUNAS_MODE_LIMITED 2 -HWND PhMainWndHandle; +PHAPPAPI HWND PhMainWndHandle; BOOLEAN PhMainWndExiting = FALSE; HMENU PhMainWndMenuHandle; @@ -342,12 +342,12 @@ BOOLEAN PhMwpInitializeWindowClass( wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = PhInstanceHandle; - wcex.hIcon = PH_LOAD_SHARED_ICON_LARGE(PhLibImageBase, MAKEINTRESOURCE(IDI_PROCESSHACKER)); + wcex.hIcon = PH_LOAD_SHARED_ICON_LARGE(MAKEINTRESOURCE(IDI_PROCESSHACKER)); wcex.hCursor = LoadCursor(NULL, IDC_ARROW); //wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); wcex.lpszMenuName = MAKEINTRESOURCE(IDR_MAINWND); wcex.lpszClassName = PH_MAINWND_CLASSNAME; - wcex.hIconSm = PH_LOAD_SHARED_ICON_SMALL(PhLibImageBase, MAKEINTRESOURCE(IDI_PROCESSHACKER)); + wcex.hIconSm = PH_LOAD_SHARED_ICON_SMALL(MAKEINTRESOURCE(IDI_PROCESSHACKER)); if (!RegisterClassEx(&wcex)) return FALSE; diff --git a/ProcessHacker/memlists.c b/ProcessHacker/memlists.c index 093db01c7a5b..6f73a3f3d918 100644 --- a/ProcessHacker/memlists.c +++ b/ProcessHacker/memlists.c @@ -21,7 +21,6 @@ */ #include -#include #include #include @@ -172,7 +171,7 @@ INT_PTR CALLBACK PhpMemoryListsDlgProc( { case WM_INITDIALOG: { - PhRegisterCallback(PhGetGeneralCallback(GeneralCallbackProcessProviderUpdated), ProcessesUpdatedCallback, NULL, &ProcessesUpdatedRegistration); + PhRegisterCallback(&PhProcessesUpdatedEvent, ProcessesUpdatedCallback, NULL, &ProcessesUpdatedRegistration); PhpUpdateMemoryListInfo(hwndDlg); PhLoadWindowPlacementFromSetting(L"MemoryListsWindowPosition", NULL, hwndDlg); @@ -184,7 +183,7 @@ INT_PTR CALLBACK PhpMemoryListsDlgProc( PhUnregisterDialog(hwndDlg); PhSaveWindowPlacementToSetting(L"MemoryListsWindowPosition", NULL, hwndDlg); - PhUnregisterCallback(PhGetGeneralCallback(GeneralCallbackProcessProviderUpdated), &ProcessesUpdatedRegistration); + PhUnregisterCallback(&PhProcessesUpdatedEvent, &ProcessesUpdatedRegistration); UnregisterDialogFunction(hwndDlg); PhMemoryListsWindowHandle = NULL; diff --git a/ProcessHacker/miniinfo.c b/ProcessHacker/miniinfo.c index b3e2f4105b47..01d139a083e8 100644 --- a/ProcessHacker/miniinfo.c +++ b/ProcessHacker/miniinfo.c @@ -110,11 +110,11 @@ VOID PhPinMiniInformation( wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = PhInstanceHandle; - wcex.hIcon = PH_LOAD_SHARED_ICON_LARGE(PhLibImageBase, MAKEINTRESOURCE(IDI_PROCESSHACKER)); + wcex.hIcon = PH_LOAD_SHARED_ICON_LARGE(MAKEINTRESOURCE(IDI_PROCESSHACKER)); wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1); wcex.lpszClassName = MIP_CONTAINER_CLASSNAME; - wcex.hIconSm = PH_LOAD_SHARED_ICON_SMALL(PhLibImageBase, MAKEINTRESOURCE(IDI_PROCESSHACKER)); + wcex.hIconSm = PH_LOAD_SHARED_ICON_SMALL(MAKEINTRESOURCE(IDI_PROCESSHACKER)); RegisterClassEx(&wcex); PhMipContainerWindow = CreateWindow( @@ -337,7 +337,7 @@ VOID PhMipContainerOnShowWindow( PhMipMessageLoopFilterEntry = PhRegisterMessageLoopFilter(PhMipMessageLoopFilter, NULL); PhRegisterCallback( - PhGetGeneralCallback(GeneralCallbackProcessProviderUpdated), + &PhProcessesUpdatedEvent, PhMipUpdateHandler, NULL, &ProcessesUpdatedRegistration @@ -357,7 +357,7 @@ VOID PhMipContainerOnShowWindow( PhSetIntegerSetting(L"MiniInfoWindowPinned", FALSE); PhUnregisterCallback( - PhGetGeneralCallback(GeneralCallbackProcessProviderUpdated), + &PhProcessesUpdatedEvent, &ProcessesUpdatedRegistration ); @@ -448,10 +448,10 @@ VOID PhMipOnInitDialog( HICON cog; HICON pin; - cog = PH_LOAD_SHARED_ICON_SMALL(PhLibImageBase, MAKEINTRESOURCE(IDI_COG)); + cog = PH_LOAD_SHARED_ICON_SMALL(MAKEINTRESOURCE(IDI_COG)); SET_BUTTON_ICON(PhMipWindow, IDC_OPTIONS, cog); - pin = PH_LOAD_SHARED_ICON_SMALL(PhLibImageBase, MAKEINTRESOURCE(IDI_PIN)); + pin = PH_LOAD_SHARED_ICON_SMALL(MAKEINTRESOURCE(IDI_PIN)); SET_BUTTON_ICON(PhMipWindow, IDC_PIN, pin); PhInitializeLayoutManager(&PhMipLayoutManager, PhMipWindow); diff --git a/ProcessHacker/mwpgnet.c b/ProcessHacker/mwpgnet.c index 4229dd858ed3..c8fa1d5cd18f 100644 --- a/ProcessHacker/mwpgnet.c +++ b/ProcessHacker/mwpgnet.c @@ -62,25 +62,25 @@ BOOLEAN PhMwpNetworkPageCallback( PhMwpNetworkPage = Page; PhRegisterCallback( - PhGetGeneralCallback(GeneralCallbackNetworkProviderAdded), + &PhNetworkItemAddedEvent, PhMwpNetworkItemAddedHandler, NULL, &NetworkItemAddedRegistration ); PhRegisterCallback( - PhGetGeneralCallback(GeneralCallbackNetworkProviderModified), + &PhNetworkItemModifiedEvent, PhMwpNetworkItemModifiedHandler, NULL, &NetworkItemModifiedRegistration ); PhRegisterCallback( - PhGetGeneralCallback(GeneralCallbackNetworkProviderRemoved), + &PhNetworkItemRemovedEvent, PhMwpNetworkItemRemovedHandler, NULL, &NetworkItemRemovedRegistration ); PhRegisterCallback( - PhGetGeneralCallback(GeneralCallbackNetworkProviderUpdated), + &PhNetworkItemsUpdatedEvent, PhMwpNetworkItemsUpdatedHandler, NULL, &NetworkItemsUpdatedRegistration diff --git a/ProcessHacker/mwpgproc.c b/ProcessHacker/mwpgproc.c index 6d0fbad59d2b..11307c937294 100644 --- a/ProcessHacker/mwpgproc.c +++ b/ProcessHacker/mwpgproc.c @@ -70,25 +70,25 @@ BOOLEAN PhMwpProcessesPageCallback( PhMwpProcessesPage = Page; PhRegisterCallback( - PhGetGeneralCallback(GeneralCallbackProcessProviderAdded), + &PhProcessAddedEvent, PhMwpProcessAddedHandler, NULL, &ProcessAddedRegistration ); PhRegisterCallback( - PhGetGeneralCallback(GeneralCallbackProcessProviderModified), + &PhProcessModifiedEvent, PhMwpProcessModifiedHandler, NULL, &ProcessModifiedRegistration ); PhRegisterCallback( - PhGetGeneralCallback(GeneralCallbackProcessProviderRemoved), + &PhProcessRemovedEvent, PhMwpProcessRemovedHandler, NULL, &ProcessRemovedRegistration ); PhRegisterCallback( - PhGetGeneralCallback(GeneralCallbackProcessProviderUpdated), + &PhProcessesUpdatedEvent, PhMwpProcessesUpdatedHandler, NULL, &ProcessesUpdatedRegistration diff --git a/ProcessHacker/mwpgsrv.c b/ProcessHacker/mwpgsrv.c index f9e1ff1832a7..866ca49dc2e3 100644 --- a/ProcessHacker/mwpgsrv.c +++ b/ProcessHacker/mwpgsrv.c @@ -63,25 +63,25 @@ BOOLEAN PhMwpServicesPageCallback( PhMwpServicesPage = Page; PhRegisterCallback( - PhGetGeneralCallback(GeneralCallbackServiceProviderAdded), + &PhServiceAddedEvent, PhMwpServiceAddedHandler, NULL, &ServiceAddedRegistration ); PhRegisterCallback( - PhGetGeneralCallback(GeneralCallbackServiceProviderModified), + &PhServiceModifiedEvent, PhMwpServiceModifiedHandler, NULL, &ServiceModifiedRegistration ); PhRegisterCallback( - PhGetGeneralCallback(GeneralCallbackServiceProviderRemoved), + &PhServiceRemovedEvent, PhMwpServiceRemovedHandler, NULL, &ServiceRemovedRegistration ); PhRegisterCallback( - PhGetGeneralCallback(GeneralCallbackServiceProviderUpdated), + &PhServicesUpdatedEvent, PhMwpServicesUpdatedHandler, NULL, &ServicesUpdatedRegistration diff --git a/ProcessHacker/netprv.c b/ProcessHacker/netprv.c index 1247c49721d1..d3cc1187db6a 100644 --- a/ProcessHacker/netprv.c +++ b/ProcessHacker/netprv.c @@ -23,7 +23,6 @@ #include #include -#include #include #include @@ -95,6 +94,11 @@ PPH_OBJECT_TYPE PhNetworkItemType; PPH_HASHTABLE PhNetworkHashtable; PH_QUEUED_LOCK PhNetworkHashtableLock = PH_QUEUED_LOCK_INIT; +PHAPPAPI PH_CALLBACK_DECLARE(PhNetworkItemAddedEvent); +PHAPPAPI PH_CALLBACK_DECLARE(PhNetworkItemModifiedEvent); +PHAPPAPI PH_CALLBACK_DECLARE(PhNetworkItemRemovedEvent); +PHAPPAPI PH_CALLBACK_DECLARE(PhNetworkItemsUpdatedEvent); + PH_INITONCE PhNetworkProviderWorkQueueInitOnce = PH_INITONCE_INIT; PH_WORK_QUEUE PhNetworkProviderWorkQueue; SLIST_HEADER PhNetworkItemQueryListHead; @@ -499,7 +503,7 @@ VOID PhNetworkProviderUpdate( if (!found) { - PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackNetworkProviderRemoved), *networkItem); + PhInvokeCallback(&PhNetworkItemRemovedEvent, *networkItem); if (!connectionsToRemove) connectionsToRemove = PhCreateList(2); @@ -662,7 +666,7 @@ VOID PhNetworkProviderUpdate( PhReleaseQueuedLockExclusive(&PhNetworkHashtableLock); // Raise the network item added event. - PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackNetworkProviderAdded), networkItem); + PhInvokeCallback(&PhNetworkItemAddedEvent, networkItem); } else { @@ -706,7 +710,7 @@ VOID PhNetworkProviderUpdate( if (modified) { // Raise the network item modified event. - PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackNetworkProviderModified), networkItem); + PhInvokeCallback(&PhNetworkItemModifiedEvent, networkItem); } PhDereferenceObject(networkItem); @@ -715,7 +719,7 @@ VOID PhNetworkProviderUpdate( PhFree(connections); - PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackNetworkProviderUpdated), NULL); + PhInvokeCallback(&PhNetworkItemsUpdatedEvent, NULL); } PWSTR PhGetProtocolTypeName( diff --git a/ProcessHacker/notifico.c b/ProcessHacker/notifico.c index 7ad86bbb1486..729f81412e78 100644 --- a/ProcessHacker/notifico.c +++ b/ProcessHacker/notifico.c @@ -113,7 +113,7 @@ VOID PhNfLoadStage2( } PhRegisterCallback( - PhGetGeneralCallback(GeneralCallbackProcessProviderUpdated), + &PhProcessesUpdatedEvent, PhNfpProcessesUpdatedHandler, NULL, &PhNfpProcessesUpdatedRegistration diff --git a/ProcessHacker/plugin.c b/ProcessHacker/plugin.c index efb22a49c654..8f30f4e9da33 100644 --- a/ProcessHacker/plugin.c +++ b/ProcessHacker/plugin.c @@ -264,30 +264,30 @@ VOID PhLoadPlugins( // In certain startup modes we want to ignore all plugin load errors. if (LoadErrors && LoadErrors->Count != 0 && !PhStartupParameters.PhSvc) { - PH_STRING_BUILDER stringBuilder; + PH_STRING_BUILDER sb; ULONG i; PPHP_PLUGIN_LOAD_ERROR loadError; PPH_STRING baseName; - PhInitializeStringBuilder(&stringBuilder, 100); + PhInitializeStringBuilder(&sb, 100); + PhAppendStringBuilder2(&sb, L"Unable to load the following plugin(s):\n\n"); for (i = 0; i < LoadErrors->Count; i++) { loadError = LoadErrors->Items[i]; baseName = PhGetBaseName(loadError->FileName); - PhAppendFormatStringBuilder(&stringBuilder, L"%s: %s\n", + PhAppendFormatStringBuilder(&sb, L"%s: %s\n", baseName->Buffer, PhGetStringOrDefault(loadError->ErrorMessage, L"An unknown error occurred.")); PhDereferenceObject(baseName); } - if (stringBuilder.String->Length != 0) - PhRemoveEndStringBuilder(&stringBuilder, 1); + PhAppendStringBuilder2(&sb, L"\nDo you want to disable the above plugin(s)?"); - if (PhShowError2( + if (PhShowMessage( NULL, - L"Unable to load the following plugin(s):", - stringBuilder.String->Buffer - )) + MB_ICONERROR | MB_YESNO, + sb.String->Buffer + ) == IDYES) { ULONG i; @@ -300,7 +300,7 @@ VOID PhLoadPlugins( } } - PhDeleteStringBuilder(&stringBuilder); + PhDeleteStringBuilder(&sb); } // When we loaded settings before, we didn't know about plugin settings, so they diff --git a/ProcessHacker/procprv.c b/ProcessHacker/procprv.c index 06ba7e4c6a69..9445050002f7 100644 --- a/ProcessHacker/procprv.c +++ b/ProcessHacker/procprv.c @@ -179,6 +179,11 @@ PH_QUEUED_LOCK PhProcessHashSetLock = PH_QUEUED_LOCK_INIT; SLIST_HEADER PhProcessQueryDataListHead; +PHAPPAPI PH_CALLBACK_DECLARE(PhProcessAddedEvent); +PHAPPAPI PH_CALLBACK_DECLARE(PhProcessModifiedEvent); +PHAPPAPI PH_CALLBACK_DECLARE(PhProcessRemovedEvent); +PHAPPAPI PH_CALLBACK_DECLARE(PhProcessesUpdatedEvent); + PPH_LIST PhProcessRecordList; PH_QUEUED_LOCK PhProcessRecordListLock = PH_QUEUED_LOCK_INIT; @@ -1896,7 +1901,7 @@ VOID PhFlushProcessQueryData( // which will lead to very bad things happening. PhAcquireQueuedLockExclusive(&data->ProcessItem->RemoveLock); if (!(data->ProcessItem->State & PH_PROCESS_ITEM_REMOVED)) - PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackProcessProviderModified), data->ProcessItem); + PhInvokeCallback(&PhProcessModifiedEvent, data->ProcessItem); PhReleaseQueuedLockExclusive(&data->ProcessItem->RemoveLock); } else @@ -2171,7 +2176,7 @@ VOID PhProcessProviderUpdate( // Raise the process removed event. // See PhFlushProcessQueryData for why we need to lock here. PhAcquireQueuedLockExclusive(&processItem->RemoveLock); - PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackProcessProviderRemoved), processItem); + PhInvokeCallback(&PhProcessRemovedEvent, processItem); PhReleaseQueuedLockExclusive(&processItem->RemoveLock); if (!processesToRemove) @@ -2293,7 +2298,7 @@ VOID PhProcessProviderUpdate( PhReleaseQueuedLockExclusive(&PhProcessHashSetLock); // Raise the process added event. - PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackProcessProviderAdded), processItem); + PhInvokeCallback(&PhProcessAddedEvent, processItem); processItem->AddedEventSent = TRUE; // (Ref: for the process item being in the hashtable.) @@ -2456,7 +2461,7 @@ VOID PhProcessProviderUpdate( if (modified) { - PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackProcessProviderModified), processItem); + PhInvokeCallback(&PhProcessModifiedEvent, processItem); } // No reference added by PhpLookupProcessItem. @@ -2557,7 +2562,7 @@ VOID PhProcessProviderUpdate( } } - PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackProcessProviderUpdated), NULL); + PhInvokeCallback(&PhProcessesUpdatedEvent, NULL); runCount++; } diff --git a/ProcessHacker/procrec.c b/ProcessHacker/procrec.c index dbcb2c98019a..486a3db8841c 100644 --- a/ProcessHacker/procrec.c +++ b/ProcessHacker/procrec.c @@ -186,7 +186,7 @@ INT_PTR CALLBACK PhpProcessRecordDlgProc( context->FileIcon = PhGetFileShellIcon(PhGetString(context->Record->FileName), L".exe", TRUE); SendMessage(GetDlgItem(hwndDlg, IDC_OPENFILENAME), BM_SETIMAGE, IMAGE_ICON, - (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhLibImageBase, MAKEINTRESOURCE(IDI_FOLDER))); + (LPARAM)PH_LOAD_SHARED_ICON_SMALL(MAKEINTRESOURCE(IDI_FOLDER))); SendMessage(GetDlgItem(hwndDlg, IDC_FILEICON), STM_SETICON, (WPARAM)context->FileIcon, 0); diff --git a/ProcessHacker/prpggen.c b/ProcessHacker/prpggen.c index 76318e4492e0..30b2115d2695 100644 --- a/ProcessHacker/prpggen.c +++ b/ProcessHacker/prpggen.c @@ -147,8 +147,8 @@ INT_PTR CALLBACK PhpProcessGeneralDlgProc( HICON folder; HICON magnifier; - folder = PH_LOAD_SHARED_ICON_SMALL(PhLibImageBase, MAKEINTRESOURCE(IDI_FOLDER)); - magnifier = PH_LOAD_SHARED_ICON_SMALL(PhLibImageBase, MAKEINTRESOURCE(IDI_MAGNIFIER)); + folder = PH_LOAD_SHARED_ICON_SMALL(MAKEINTRESOURCE(IDI_FOLDER)); + magnifier = PH_LOAD_SHARED_ICON_SMALL(MAKEINTRESOURCE(IDI_MAGNIFIER)); SET_BUTTON_ICON(IDC_INSPECT, magnifier); SET_BUTTON_ICON(IDC_OPENFILENAME, folder); diff --git a/ProcessHacker/prpgperf.c b/ProcessHacker/prpgperf.c index d525919ab666..9efb80e93072 100644 --- a/ProcessHacker/prpgperf.c +++ b/ProcessHacker/prpgperf.c @@ -21,7 +21,6 @@ */ #include -#include #include #include @@ -75,7 +74,7 @@ INT_PTR CALLBACK PhpProcessPerformanceDlgProc( performanceContext->WindowHandle = hwndDlg; PhRegisterCallback( - PhGetGeneralCallback(GeneralCallbackProcessProviderUpdated), + &PhProcessesUpdatedEvent, PerformanceUpdateHandler, performanceContext, &performanceContext->ProcessesUpdatedRegistration @@ -114,7 +113,7 @@ INT_PTR CALLBACK PhpProcessPerformanceDlgProc( PhDeleteGraphState(&performanceContext->IoGraphState); PhUnregisterCallback( - PhGetGeneralCallback(GeneralCallbackProcessProviderUpdated), + &PhProcessesUpdatedEvent, &performanceContext->ProcessesUpdatedRegistration ); PhFree(performanceContext); diff --git a/ProcessHacker/prpgstat.c b/ProcessHacker/prpgstat.c index 4953d401b699..97b0127b4ea9 100644 --- a/ProcessHacker/prpgstat.c +++ b/ProcessHacker/prpgstat.c @@ -21,7 +21,6 @@ */ #include -#include #include #include @@ -247,7 +246,7 @@ INT_PTR CALLBACK PhpProcessStatisticsDlgProc( ); PhRegisterCallback( - PhGetGeneralCallback(GeneralCallbackProcessProviderUpdated), + &PhProcessesUpdatedEvent, StatisticsUpdateHandler, statisticsContext, &statisticsContext->ProcessesUpdatedRegistration @@ -259,7 +258,7 @@ INT_PTR CALLBACK PhpProcessStatisticsDlgProc( case WM_DESTROY: { PhUnregisterCallback( - PhGetGeneralCallback(GeneralCallbackProcessProviderUpdated), + &PhProcessesUpdatedEvent, &statisticsContext->ProcessesUpdatedRegistration ); diff --git a/ProcessHacker/prpgthrd.c b/ProcessHacker/prpgthrd.c index cf23dd2cccc2..53e2cf7797e5 100644 --- a/ProcessHacker/prpgthrd.c +++ b/ProcessHacker/prpgthrd.c @@ -639,7 +639,7 @@ INT_PTR CALLBACK PhpProcessThreadsDlgProc( PhThreadProviderInitialUpdate(threadsContext->Provider); PhRegisterThreadProvider(threadsContext->Provider, &threadsContext->ProviderRegistration); - SET_BUTTON_ICON(IDC_OPENSTARTMODULE, PH_LOAD_SHARED_ICON_SMALL(PhLibImageBase, MAKEINTRESOURCE(IDI_FOLDER))); + SET_BUTTON_ICON(IDC_OPENSTARTMODULE, PH_LOAD_SHARED_ICON_SMALL(MAKEINTRESOURCE(IDI_FOLDER))); } break; case WM_DESTROY: diff --git a/ProcessHacker/srvctl.c b/ProcessHacker/srvctl.c index 3596d3176853..a53d1f769498 100644 --- a/ProcessHacker/srvctl.c +++ b/ProcessHacker/srvctl.c @@ -21,7 +21,6 @@ */ #include -#include #include #include @@ -230,7 +229,7 @@ INT_PTR CALLBACK PhpServicesPageProc( ULONG i; PhRegisterCallback( - PhGetGeneralCallback(GeneralCallbackServiceProviderModified), + &PhServiceModifiedEvent, ServiceModifiedHandler, servicesContext, &servicesContext->ModifiedEventRegistration @@ -281,7 +280,7 @@ INT_PTR CALLBACK PhpServicesPageProc( PhFree(servicesContext->Services); PhUnregisterCallback( - PhGetGeneralCallback(GeneralCallbackServiceProviderModified), + &PhServiceModifiedEvent, &servicesContext->ModifiedEventRegistration ); diff --git a/ProcessHacker/srvlist.c b/ProcessHacker/srvlist.c index 1e2eaeb655df..003e86f51e31 100644 --- a/ProcessHacker/srvlist.c +++ b/ProcessHacker/srvlist.c @@ -689,10 +689,10 @@ BOOLEAN NTAPI PhpServiceTreeNewCallback( if (!ServiceIconsLoaded) { - ServiceApplicationIcon = PH_LOAD_SHARED_ICON_SMALL(PhLibImageBase, MAKEINTRESOURCE(IDI_PHAPPLICATION)); - ServiceApplicationGoIcon = PH_LOAD_SHARED_ICON_SMALL(PhLibImageBase, MAKEINTRESOURCE(IDI_PHAPPLICATIONGO)); - ServiceCogIcon = PH_LOAD_SHARED_ICON_SMALL(PhLibImageBase, MAKEINTRESOURCE(IDI_COG)); - ServiceCogGoIcon = PH_LOAD_SHARED_ICON_SMALL(PhLibImageBase, MAKEINTRESOURCE(IDI_COGGO)); + ServiceApplicationIcon = PH_LOAD_SHARED_ICON_SMALL(MAKEINTRESOURCE(IDI_PHAPPLICATION)); + ServiceApplicationGoIcon = PH_LOAD_SHARED_ICON_SMALL(MAKEINTRESOURCE(IDI_PHAPPLICATIONGO)); + ServiceCogIcon = PH_LOAD_SHARED_ICON_SMALL(MAKEINTRESOURCE(IDI_COG)); + ServiceCogGoIcon = PH_LOAD_SHARED_ICON_SMALL(MAKEINTRESOURCE(IDI_COGGO)); ServiceIconsLoaded = TRUE; } diff --git a/ProcessHacker/srvprv.c b/ProcessHacker/srvprv.c index b716fa37a141..18f258c7aa3d 100644 --- a/ProcessHacker/srvprv.c +++ b/ProcessHacker/srvprv.c @@ -22,7 +22,6 @@ #include #include -#include #include #include @@ -94,6 +93,11 @@ PPH_OBJECT_TYPE PhServiceItemType; PPH_HASHTABLE PhServiceHashtable; PH_QUEUED_LOCK PhServiceHashtableLock = PH_QUEUED_LOCK_INIT; +PHAPPAPI PH_CALLBACK_DECLARE(PhServiceAddedEvent); +PHAPPAPI PH_CALLBACK_DECLARE(PhServiceModifiedEvent); +PHAPPAPI PH_CALLBACK_DECLARE(PhServiceRemovedEvent); +PHAPPAPI PH_CALLBACK_DECLARE(PhServicesUpdatedEvent); + BOOLEAN PhEnableServiceNonPoll = FALSE; static BOOLEAN PhpNonPollInitialized = FALSE; static BOOLEAN PhpNonPollActive = FALSE; @@ -575,7 +579,7 @@ VOID PhServiceProviderUpdate( } // Raise the service removed event. - PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackServiceProviderRemoved), *serviceItem); + PhInvokeCallback(&PhServiceRemovedEvent, *serviceItem); if (!servicesToRemove) servicesToRemove = PhCreateList(2); @@ -650,7 +654,7 @@ VOID PhServiceProviderUpdate( PhReleaseQueuedLockExclusive(&PhServiceHashtableLock); // Raise the service added event. - PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackServiceProviderAdded), serviceItem); + PhInvokeCallback(&PhServiceAddedEvent, serviceItem); } else { @@ -754,7 +758,7 @@ VOID PhServiceProviderUpdate( } // Raise the service modified event. - PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackServiceProviderModified), &serviceModifiedData); + PhInvokeCallback(&PhServiceModifiedEvent, &serviceModifiedData); } } } @@ -763,7 +767,7 @@ VOID PhServiceProviderUpdate( PhFree(services); UpdateEnd: - PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackServiceProviderUpdated), NULL); + PhInvokeCallback(&PhServicesUpdatedEvent, NULL); runCount++; } diff --git a/ProcessHacker/sysinfo.c b/ProcessHacker/sysinfo.c index ee2feb3038ad..5dcbb236ea54 100644 --- a/ProcessHacker/sysinfo.c +++ b/ProcessHacker/sysinfo.c @@ -281,8 +281,8 @@ VOID PhSipOnInitDialog( VOID ) { - SendMessage(PhSipWindow, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhLibImageBase, MAKEINTRESOURCE(IDI_PROCESSHACKER))); - SendMessage(PhSipWindow, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhLibImageBase, MAKEINTRESOURCE(IDI_PROCESSHACKER))); + SendMessage(PhSipWindow, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(MAKEINTRESOURCE(IDI_PROCESSHACKER))); + SendMessage(PhSipWindow, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(MAKEINTRESOURCE(IDI_PROCESSHACKER))); PhInitializeLayoutManager(&WindowLayoutManager, PhSipWindow); @@ -291,7 +291,7 @@ VOID PhSipOnInitDialog( PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(PhSipWindow, IDOK), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); PhRegisterCallback( - PhGetGeneralCallback(GeneralCallbackProcessProviderUpdated), + &PhProcessesUpdatedEvent, PhSipSysInfoUpdateHandler, NULL, &ProcessesUpdatedRegistration @@ -313,7 +313,7 @@ VOID PhSipOnDestroy( ) { PhUnregisterCallback( - PhGetGeneralCallback(GeneralCallbackProcessProviderUpdated), + &PhProcessesUpdatedEvent, &ProcessesUpdatedRegistration ); diff --git a/ProcessHacker/thrdprv.c b/ProcessHacker/thrdprv.c index ac616f887e03..8f7a60b85b6a 100644 --- a/ProcessHacker/thrdprv.c +++ b/ProcessHacker/thrdprv.c @@ -27,7 +27,6 @@ */ #include -#include #include #include @@ -213,7 +212,7 @@ VOID PhRegisterThreadProvider( ) { PhReferenceObject(ThreadProvider); - PhRegisterCallback(PhGetGeneralCallback(GeneralCallbackProcessProviderUpdated), PhpThreadProviderCallbackHandler, ThreadProvider, CallbackRegistration); + PhRegisterCallback(&PhProcessesUpdatedEvent, PhpThreadProviderCallbackHandler, ThreadProvider, CallbackRegistration); } VOID PhUnregisterThreadProvider( @@ -221,7 +220,7 @@ VOID PhUnregisterThreadProvider( _In_ PPH_CALLBACK_REGISTRATION CallbackRegistration ) { - PhUnregisterCallback(PhGetGeneralCallback(GeneralCallbackProcessProviderUpdated), CallbackRegistration); + PhUnregisterCallback(&PhProcessesUpdatedEvent, CallbackRegistration); PhDereferenceObject(ThreadProvider); } diff --git a/phlib/global.c b/phlib/global.c index 34c6ddf1eaf4..fb8a44453ab0 100644 --- a/phlib/global.c +++ b/phlib/global.c @@ -38,19 +38,20 @@ VOID PhInitializeWindowsVersion( VOID ); -PVOID PhLibImageBase; -PWSTR PhApplicationName = L"Application"; -ULONG PhGlobalDpi = 96; -PVOID PhHeapHandle; -RTL_OSVERSIONINFOEXW PhOsVersion; -SYSTEM_BASIC_INFORMATION PhSystemBasicInformation; -ULONG WindowsVersion; - -ACCESS_MASK ProcessQueryAccess; -ACCESS_MASK ProcessAllAccess; -ACCESS_MASK ThreadQueryAccess; -ACCESS_MASK ThreadSetAccess; -ACCESS_MASK ThreadAllAccess; +PHLIBAPI PVOID PhLibImageBase; + +PHLIBAPI PWSTR PhApplicationName = L"Application"; +PHLIBAPI ULONG PhGlobalDpi = 96; +PHLIBAPI PVOID PhHeapHandle; +PHLIBAPI RTL_OSVERSIONINFOEXW PhOsVersion; +PHLIBAPI SYSTEM_BASIC_INFORMATION PhSystemBasicInformation; +PHLIBAPI ULONG WindowsVersion; + +PHLIBAPI ACCESS_MASK ProcessQueryAccess; +PHLIBAPI ACCESS_MASK ProcessAllAccess; +PHLIBAPI ACCESS_MASK ThreadQueryAccess; +PHLIBAPI ACCESS_MASK ThreadSetAccess; +PHLIBAPI ACCESS_MASK ThreadAllAccess; // Internal data #ifdef DEBUG @@ -236,10 +237,3 @@ static VOID PhInitializeWindowsVersion( ThreadAllAccess = STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x3ff; } } - -ULONG PhWindowsVersion( - VOID - ) -{ - return WindowsVersion; -} \ No newline at end of file diff --git a/phlib/include/phconfig.h b/phlib/include/phconfig.h index d163c60ecaed..75892b856fe8 100644 --- a/phlib/include/phconfig.h +++ b/phlib/include/phconfig.h @@ -7,19 +7,47 @@ extern "C" { #define _User_set_ -extern _User_set_ PVOID PhLibImageBase; -extern _User_set_ PWSTR PhApplicationName; -extern _User_set_ ULONG PhGlobalDpi; -extern PVOID PhHeapHandle; -extern RTL_OSVERSIONINFOEXW PhOsVersion; -extern SYSTEM_BASIC_INFORMATION PhSystemBasicInformation; -extern ULONG WindowsVersion; - -extern ACCESS_MASK ProcessQueryAccess; -extern ACCESS_MASK ProcessAllAccess; -extern ACCESS_MASK ThreadQueryAccess; -extern ACCESS_MASK ThreadSetAccess; -extern ACCESS_MASK ThreadAllAccess; +PHLIBAPI extern _User_set_ PVOID PhLibImageBase; + +PHLIBAPI extern _User_set_ PWSTR PhApplicationName; +PHLIBAPI extern _User_set_ ULONG PhGlobalDpi; +PHLIBAPI extern PVOID PhHeapHandle; +PHLIBAPI extern RTL_OSVERSIONINFOEXW PhOsVersion; +PHLIBAPI extern SYSTEM_BASIC_INFORMATION PhSystemBasicInformation; +PHLIBAPI extern ULONG WindowsVersion; + +PHLIBAPI extern ACCESS_MASK ProcessQueryAccess; +PHLIBAPI extern ACCESS_MASK ProcessAllAccess; +PHLIBAPI extern ACCESS_MASK ThreadQueryAccess; +PHLIBAPI extern ACCESS_MASK ThreadSetAccess; +PHLIBAPI extern ACCESS_MASK ThreadAllAccess; + +#define WINDOWS_ANCIENT 0 +#define WINDOWS_XP 51 +#define WINDOWS_SERVER_2003 52 +#define WINDOWS_VISTA 60 +#define WINDOWS_7 61 +#define WINDOWS_8 62 +#define WINDOWS_8_1 63 +#define WINDOWS_10 100 +#define WINDOWS_NEW MAXLONG + +#define WINDOWS_HAS_CONSOLE_HOST (WindowsVersion >= WINDOWS_7) +#define WINDOWS_HAS_CYCLE_TIME (WindowsVersion >= WINDOWS_VISTA) +#define WINDOWS_HAS_IFILEDIALOG (WindowsVersion >= WINDOWS_VISTA) +#define WINDOWS_HAS_IMAGE_FILE_NAME_BY_PROCESS_ID (WindowsVersion >= WINDOWS_VISTA) +#define WINDOWS_HAS_IMMERSIVE (WindowsVersion >= WINDOWS_8) +#define WINDOWS_HAS_LIMITED_ACCESS (WindowsVersion >= WINDOWS_VISTA) +#define WINDOWS_HAS_SERVICE_TAGS (WindowsVersion >= WINDOWS_VISTA) +#define WINDOWS_HAS_UAC (WindowsVersion >= WINDOWS_VISTA) + +// Debugging + +#ifdef DEBUG +#define dprintf(format, ...) DbgPrint(format, __VA_ARGS__) +#else +#define dprintf(format, ...) +#endif // global @@ -74,23 +102,6 @@ PhIsExecutingInWow64( ); #endif - -PHLIBAPI -ULONG -NTAPI -PhWindowsVersion( - VOID - ); - -#define WINDOWS_HAS_CONSOLE_HOST (PhWindowsVersion() >= WINDOWS_7) -#define WINDOWS_HAS_CYCLE_TIME (PhWindowsVersion() >= WINDOWS_VISTA) -#define WINDOWS_HAS_IFILEDIALOG (PhWindowsVersion() >= WINDOWS_VISTA) -#define WINDOWS_HAS_IMAGE_FILE_NAME_BY_PROCESS_ID (PhWindowsVersion() >= WINDOWS_VISTA) -#define WINDOWS_HAS_IMMERSIVE (PhWindowsVersion() >= WINDOWS_8) -#define WINDOWS_HAS_LIMITED_ACCESS (PhWindowsVersion() >= WINDOWS_VISTA) -#define WINDOWS_HAS_SERVICE_TAGS (PhWindowsVersion() >= WINDOWS_VISTA) -#define WINDOWS_HAS_UAC (PhWindowsVersion() >= WINDOWS_VISTA) - #ifdef __cplusplus } #endif diff --git a/phlib/include/phsup.h b/phlib/include/phsup.h index 82e4b306303e..55e36cf5160f 100644 --- a/phlib/include/phsup.h +++ b/phlib/include/phsup.h @@ -8,14 +8,6 @@ #include #include -// Debugging - -#ifdef DEBUG -#define dprintf(format, ...) DbgPrint(format, __VA_ARGS__) -#else -#define dprintf(format, ...) -#endif - // Memory #define PTR_ADD_OFFSET(Pointer, Offset) ((PVOID)((ULONG_PTR)(Pointer) + (ULONG_PTR)(Offset))) diff --git a/phnt/include/phnt.h b/phnt/include/phnt.h index 1d7dffcca31e..42bf2a9d8007 100644 --- a/phnt/include/phnt.h +++ b/phnt/include/phnt.h @@ -24,16 +24,6 @@ #define PHNT_MODE_USER 1 // Version -#define WINDOWS_ANCIENT 0 -#define WINDOWS_XP 51 -#define WINDOWS_SERVER_2003 52 -#define WINDOWS_VISTA 60 -#define WINDOWS_7 61 -#define WINDOWS_8 62 -#define WINDOWS_8_1 63 -#define WINDOWS_10 100 -#define WINDOWS_NEW MAXLONG - #define PHNT_WIN2K 50 #define PHNT_WINXP 51 #define PHNT_WS03 52 diff --git a/plugins/DotNetTools/clrsup.c b/plugins/DotNetTools/clrsup.c index afc00b24cbf5..3fca660cb6ce 100644 --- a/plugins/DotNetTools/clrsup.c +++ b/plugins/DotNetTools/clrsup.c @@ -283,7 +283,7 @@ ICLRDataTarget *DnCLRDataTarget_Create( HANDLE processHandle; BOOLEAN isWow64; - if (!NT_SUCCESS(PhOpenProcess(&processHandle, PhProcessQueryAccess() | PROCESS_VM_READ, ProcessId))) + if (!NT_SUCCESS(PhOpenProcess(&processHandle, ProcessQueryAccess | PROCESS_VM_READ, ProcessId))) return NULL; #ifdef _WIN64 diff --git a/plugins/DotNetTools/perfpage.c b/plugins/DotNetTools/perfpage.c index 1b3094966b8c..c5cf54c72bcf 100644 --- a/plugins/DotNetTools/perfpage.c +++ b/plugins/DotNetTools/perfpage.c @@ -765,7 +765,7 @@ INT_PTR CALLBACK DotNetPerfPageDlgProc( if (NT_SUCCESS(PhOpenProcess( &context->ProcessHandle, - PROCESS_VM_READ | PhProcessQueryAccess() | PROCESS_DUP_HANDLE | SYNCHRONIZE, + PROCESS_VM_READ | ProcessQueryAccess | PROCESS_DUP_HANDLE | SYNCHRONIZE, context->ProcessItem->ProcessId ))) { diff --git a/plugins/DotNetTools/stackext.c b/plugins/DotNetTools/stackext.c index 30528fb5b856..13ef6a3aca5c 100644 --- a/plugins/DotNetTools/stackext.c +++ b/plugins/DotNetTools/stackext.c @@ -93,7 +93,7 @@ VOID ProcessThreadStackControl( context->ThreadHandle = Control->u.Initializing.ThreadHandle; #if _WIN64 - if (NT_SUCCESS(PhOpenProcess(&processHandle, PhProcessQueryAccess(), Control->u.Initializing.ProcessId))) + if (NT_SUCCESS(PhOpenProcess(&processHandle, ProcessQueryAccess, Control->u.Initializing.ProcessId))) { PhGetProcessIsWow64(processHandle, &context->IsWow64); NtClose(processHandle); diff --git a/plugins/ExtendedNotifications/filelog.c b/plugins/ExtendedNotifications/filelog.c index e0c3d10163b8..e1cc06587719 100644 --- a/plugins/ExtendedNotifications/filelog.c +++ b/plugins/ExtendedNotifications/filelog.c @@ -55,7 +55,7 @@ VOID FileLogInitialization( if (NT_SUCCESS(status)) { PhRegisterCallback( - PhGetGeneralCallback(GeneralCallbackLoggedEvent), + &PhLoggedCallback, LoggedCallback, NULL, &LoggedCallbackRegistration diff --git a/plugins/ExtendedServices/main.c b/plugins/ExtendedServices/main.c index 335c99fff0f1..c36e3b8f38f7 100644 --- a/plugins/ExtendedServices/main.c +++ b/plugins/ExtendedServices/main.c @@ -57,28 +57,28 @@ VOID NTAPI MenuItemCallback( { case ID_SERVICE_GOTOSERVICE: { - ProcessHacker_SelectTabPage(PhMainWindowHandle, 1); - ProcessHacker_SelectServiceItem(PhMainWindowHandle, (PPH_SERVICE_ITEM)menuItem->Context); + ProcessHacker_SelectTabPage(PhMainWndHandle, 1); + ProcessHacker_SelectServiceItem(PhMainWndHandle, (PPH_SERVICE_ITEM)menuItem->Context); } break; case ID_SERVICE_START: { - PhUiStartService(PhMainWindowHandle, (PPH_SERVICE_ITEM)menuItem->Context); + PhUiStartService(PhMainWndHandle, (PPH_SERVICE_ITEM)menuItem->Context); } break; case ID_SERVICE_CONTINUE: { - PhUiContinueService(PhMainWindowHandle, (PPH_SERVICE_ITEM)menuItem->Context); + PhUiContinueService(PhMainWndHandle, (PPH_SERVICE_ITEM)menuItem->Context); } break; case ID_SERVICE_PAUSE: { - PhUiPauseService(PhMainWindowHandle, (PPH_SERVICE_ITEM)menuItem->Context); + PhUiPauseService(PhMainWndHandle, (PPH_SERVICE_ITEM)menuItem->Context); } break; case ID_SERVICE_STOP: { - PhUiStopService(PhMainWindowHandle, (PPH_SERVICE_ITEM)menuItem->Context); + PhUiStopService(PhMainWndHandle, (PPH_SERVICE_ITEM)menuItem->Context); } break; case ID_SERVICE_RESTART: @@ -89,7 +89,7 @@ VOID NTAPI MenuItemCallback( if (serviceHandle = PhOpenService(serviceItem->Name->Buffer, SERVICE_QUERY_STATUS)) { - EsRestartServiceWithProgress(PhMainWindowHandle, serviceItem, serviceHandle); + EsRestartServiceWithProgress(PhMainWndHandle, serviceItem, serviceHandle); CloseServiceHandle(serviceHandle); } else @@ -100,7 +100,7 @@ VOID NTAPI MenuItemCallback( if (win32Result != 0) { PhShowStatus( - PhMainWindowHandle, + PhMainWndHandle, PhaFormatString(L"Unable to restart %s", serviceItem->Name->Buffer)->Buffer, 0, win32Result @@ -348,7 +348,7 @@ NTAPI ServicePropertiesInitializingCallback( } // Other - if (PhWindowsVersion() >= WINDOWS_7 && objectProperties->NumberOfPages < objectProperties->MaximumNumberOfPages) + if (WindowsVersion >= WINDOWS_7 && objectProperties->NumberOfPages < objectProperties->MaximumNumberOfPages) { memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); propSheetPage.dwSize = sizeof(PROPSHEETPAGE); @@ -362,7 +362,7 @@ NTAPI ServicePropertiesInitializingCallback( } // Other - if (PhWindowsVersion() >= WINDOWS_VISTA && objectProperties->NumberOfPages < objectProperties->MaximumNumberOfPages) + if (WindowsVersion >= WINDOWS_VISTA && objectProperties->NumberOfPages < objectProperties->MaximumNumberOfPages) { memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); propSheetPage.dwSize = sizeof(PROPSHEETPAGE); diff --git a/plugins/ExtendedServices/other.c b/plugins/ExtendedServices/other.c index 7c94a31beacd..5b7957afa653 100644 --- a/plugins/ExtendedServices/other.c +++ b/plugins/ExtendedServices/other.c @@ -365,7 +365,7 @@ INT_PTR CALLBACK EspServiceOtherDlgProc( PhAddComboBoxStrings(GetDlgItem(hwndDlg, IDC_PROTECTION), EspServiceLaunchProtectedStrings, sizeof(EspServiceLaunchProtectedStrings) / sizeof(PWSTR)); - if (PhWindowsVersion() < WINDOWS_8_1) + if (WindowsVersion < WINDOWS_8_1) EnableWindow(GetDlgItem(hwndDlg, IDC_PROTECTION), FALSE); SetDlgItemText(hwndDlg, IDC_SERVICESID, diff --git a/plugins/ExtendedServices/recovery.c b/plugins/ExtendedServices/recovery.c index 245bce8a6372..b917b0334498 100644 --- a/plugins/ExtendedServices/recovery.c +++ b/plugins/ExtendedServices/recovery.c @@ -214,7 +214,7 @@ NTSTATUS EspLoadRecoveryInfo( // Enable actions for stops with errors // This is Vista and above only. - if (PhWindowsVersion() >= WINDOWS_VISTA && QueryServiceConfig2( + if (WindowsVersion >= WINDOWS_VISTA && QueryServiceConfig2( serviceHandle, SERVICE_CONFIG_FAILURE_ACTIONS_FLAG, (BYTE *)&failureActionsFlag, @@ -320,7 +320,7 @@ INT_PTR CALLBACK EspServiceRecoveryDlgProc( { SetDlgItemText(hwndDlg, IDC_RESETFAILCOUNT, L"0"); - if (PhWindowsVersion() >= WINDOWS_VISTA) + if (WindowsVersion >= WINDOWS_VISTA) { context->EnableFlagCheckBox = TRUE; EnableWindow(GetDlgItem(hwndDlg, IDC_ENABLEFORERRORSTOPS), TRUE); diff --git a/plugins/ExtendedTools/disktab.c b/plugins/ExtendedTools/disktab.c index daf90924b520..b8b1ae72e953 100644 --- a/plugins/ExtendedTools/disktab.c +++ b/plugins/ExtendedTools/disktab.c @@ -62,7 +62,7 @@ VOID EtInitializeDiskTab( memset(&page, 0, sizeof(PH_MAIN_TAB_PAGE)); PhInitializeStringRef(&page.Name, L"Disk"); page.Callback = EtpDiskPageCallback; - DiskPage = ProcessHacker_CreateTabPage(PhMainWindowHandle, &page); + DiskPage = ProcessHacker_CreateTabPage(PhMainWndHandle, &page); if (ToolStatusInterface) { @@ -101,7 +101,7 @@ BOOLEAN EtpDiskPageCallback( 0, 3, 3, - PhMainWindowHandle, + PhMainWndHandle, NULL, NULL, NULL @@ -115,7 +115,7 @@ BOOLEAN EtpDiskPageCallback( *(HWND *)Parameter1 = CreateDialog( PluginInstance->DllBase, MAKEINTRESOURCE(IDD_DISKTABERROR), - PhMainWindowHandle, + PhMainWndHandle, EtpDiskTabErrorDialogProc ); return TRUE; @@ -829,17 +829,17 @@ VOID EtHandleDiskCommand( if ((processNode = PhFindProcessNode(diskItem->ProcessId)) && processNode->ProcessItem->CreateTime.QuadPart == diskItem->ProcessRecord->CreateTime.QuadPart) { - ProcessHacker_SelectTabPage(PhMainWindowHandle, 0); + ProcessHacker_SelectTabPage(PhMainWndHandle, 0); PhSelectAndEnsureVisibleProcessNode(processNode); } else { - PhShowProcessRecordDialog(PhMainWindowHandle, diskItem->ProcessRecord); + PhShowProcessRecordDialog(PhMainWndHandle, diskItem->ProcessRecord); } } else { - PhShowError(PhMainWindowHandle, L"The process does not exist."); + PhShowError(PhMainWndHandle, L"The process does not exist."); } PhDereferenceObject(diskItem); @@ -852,7 +852,7 @@ VOID EtHandleDiskCommand( if (diskItem) { - PhShellExploreFile(PhMainWindowHandle, diskItem->FileNameWin32->Buffer); + PhShellExploreFile(PhMainWndHandle, diskItem->FileNameWin32->Buffer); } } break; @@ -867,7 +867,7 @@ VOID EtHandleDiskCommand( if (diskItem) { - PhShellProperties(PhMainWindowHandle, diskItem->FileNameWin32->Buffer); + PhShellProperties(PhMainWndHandle, diskItem->FileNameWin32->Buffer); } } break; @@ -937,7 +937,7 @@ VOID EtShowDiskContextMenu( item = PhShowEMenu( menu, - PhMainWindowHandle, + PhMainWndHandle, PH_EMENU_SHOW_LEFTRIGHT, PH_ALIGN_LEFT | PH_ALIGN_TOP, Location.x, @@ -963,7 +963,7 @@ VOID NTAPI EtpDiskItemAddedHandler( PET_DISK_ITEM diskItem = (PET_DISK_ITEM)Parameter; PhReferenceObject(diskItem); - ProcessHacker_Invoke(PhMainWindowHandle, EtpOnDiskItemAdded, diskItem); + ProcessHacker_Invoke(PhMainWndHandle, EtpOnDiskItemAdded, diskItem); } VOID NTAPI EtpDiskItemModifiedHandler( @@ -971,7 +971,7 @@ VOID NTAPI EtpDiskItemModifiedHandler( _In_opt_ PVOID Context ) { - ProcessHacker_Invoke(PhMainWindowHandle, EtpOnDiskItemModified, (PET_DISK_ITEM)Parameter); + ProcessHacker_Invoke(PhMainWndHandle, EtpOnDiskItemModified, (PET_DISK_ITEM)Parameter); } VOID NTAPI EtpDiskItemRemovedHandler( @@ -979,7 +979,7 @@ VOID NTAPI EtpDiskItemRemovedHandler( _In_opt_ PVOID Context ) { - ProcessHacker_Invoke(PhMainWindowHandle, EtpOnDiskItemRemoved, (PET_DISK_ITEM)Parameter); + ProcessHacker_Invoke(PhMainWndHandle, EtpOnDiskItemRemoved, (PET_DISK_ITEM)Parameter); } VOID NTAPI EtpDiskItemsUpdatedHandler( @@ -987,7 +987,7 @@ VOID NTAPI EtpDiskItemsUpdatedHandler( _In_opt_ PVOID Context ) { - ProcessHacker_Invoke(PhMainWindowHandle, EtpOnDiskItemsUpdated, NULL); + ProcessHacker_Invoke(PhMainWndHandle, EtpOnDiskItemsUpdated, NULL); } VOID NTAPI EtpOnDiskItemAdded( @@ -1136,10 +1136,10 @@ INT_PTR CALLBACK EtpDiskTabErrorDialogProc( switch (LOWORD(wParam)) { case IDC_RESTART: - ProcessHacker_PrepareForEarlyShutdown(PhMainWindowHandle); + ProcessHacker_PrepareForEarlyShutdown(PhMainWndHandle); if (PhShellProcessHacker( - PhMainWindowHandle, + PhMainWndHandle, L"-v -selecttab Disk", SW_SHOW, PH_SHELL_EXECUTE_ADMIN, @@ -1148,11 +1148,11 @@ INT_PTR CALLBACK EtpDiskTabErrorDialogProc( NULL )) { - ProcessHacker_Destroy(PhMainWindowHandle); + ProcessHacker_Destroy(PhMainWndHandle); } else { - ProcessHacker_CancelEarlyShutdown(PhMainWindowHandle); + ProcessHacker_CancelEarlyShutdown(PhMainWndHandle); } break; diff --git a/plugins/ExtendedTools/etwdisk.c b/plugins/ExtendedTools/etwdisk.c index 237e34715d71..c8512f20a01d 100644 --- a/plugins/ExtendedTools/etwdisk.c +++ b/plugins/ExtendedTools/etwdisk.c @@ -95,7 +95,7 @@ VOID EtInitializeDiskInformation( EtStartEtwRundown(); PhRegisterCallback( - PhGetGeneralCallback(GeneralCallbackProcessProviderUpdated), + &PhProcessesUpdatedEvent, EtpDiskProcessesUpdatedCallback, NULL, &ProcessesUpdatedCallbackRegistration diff --git a/plugins/ExtendedTools/etwmon.c b/plugins/ExtendedTools/etwmon.c index 402b3417a27e..7c4823ae21ba 100644 --- a/plugins/ExtendedTools/etwmon.c +++ b/plugins/ExtendedTools/etwmon.c @@ -117,7 +117,7 @@ VOID EtStartEtwSession( ULONG result; ULONG bufferSize; - if (PhWindowsVersion() >= WINDOWS_8) + if (WindowsVersion >= WINDOWS_8) { EtpActualKernelLoggerName = &EtpPrivateKernelLoggerName; EtpActualSessionGuid = &ProcessHackerGuid; @@ -146,7 +146,7 @@ VOID EtStartEtwSession( EtpTraceProperties->LogFileNameOffset = 0; EtpTraceProperties->LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES); - if (PhWindowsVersion() >= WINDOWS_8) + if (WindowsVersion >= WINDOWS_8) EtpTraceProperties->LogFileMode |= EVENT_TRACE_SYSTEM_LOGGER_MODE; result = StartTrace(&EtpSessionHandle, EtpActualKernelLoggerName->Buffer, EtpTraceProperties); @@ -240,7 +240,7 @@ VOID NTAPI EtpEtwEventCallback( { DiskIo_TypeGroup1 *data = EventRecord->UserData; - if (PhWindowsVersion() >= WINDOWS_8) + if (WindowsVersion >= WINDOWS_8) { diskEvent.ClientId.UniqueThread = UlongToHandle(data->IssuingThreadId); diskEvent.ClientId.UniqueProcess = EtThreadIdToProcessId(diskEvent.ClientId.UniqueThread); @@ -387,7 +387,7 @@ NTSTATUS EtpEtwMonitorThreadStart( TRACEHANDLE traceHandle; // See comment in EtEtwProcessesUpdatedCallback. - if (PhWindowsVersion() >= WINDOWS_8) + if (WindowsVersion >= WINDOWS_8) EtUpdateProcessInformation(); memset(&logFile, 0, sizeof(EVENT_TRACE_LOGFILE)); diff --git a/plugins/ExtendedTools/etwprprp.c b/plugins/ExtendedTools/etwprprp.c index ba8059a07b8e..1e87ffbd4672 100644 --- a/plugins/ExtendedTools/etwprprp.c +++ b/plugins/ExtendedTools/etwprprp.c @@ -148,9 +148,9 @@ VOID EtwDiskNetworkLayoutGraphs( HDWP deferHandle; RECT clientRect; RECT panelRect; - RECT margin = { PH_SCALE_DPI(13), PH_SCALE_DPI(13), PH_SCALE_DPI(13), PH_SCALE_DPI(13) }; - RECT innerMargin = { PH_SCALE_DPI(10), PH_SCALE_DPI(20), PH_SCALE_DPI(10), PH_SCALE_DPI(10) }; - LONG between = PH_SCALE_DPI(3); + RECT margin = { ET_SCALE_DPI(13), ET_SCALE_DPI(13), ET_SCALE_DPI(13), ET_SCALE_DPI(13) }; + RECT innerMargin = { ET_SCALE_DPI(10), ET_SCALE_DPI(20), ET_SCALE_DPI(10), ET_SCALE_DPI(10) }; + LONG between = ET_SCALE_DPI(3); ULONG graphWidth; ULONG graphHeight; @@ -326,7 +326,7 @@ INT_PTR CALLBACK EtwDiskNetworkPageDlgProc( EtwDiskNetworkUpdatePanel(context); PhRegisterCallback( - PhGetGeneralCallback(GeneralCallbackProcessProviderUpdated), + &PhProcessesUpdatedEvent, EtwDiskNetworkUpdateHandler, context, &context->ProcessesUpdatedRegistration @@ -352,7 +352,7 @@ INT_PTR CALLBACK EtwDiskNetworkPageDlgProc( if (context->PanelHandle) DestroyWindow(context->PanelHandle); - PhUnregisterCallback(PhGetGeneralCallback(GeneralCallbackProcessProviderUpdated), &context->ProcessesUpdatedRegistration); + PhUnregisterCallback(&PhProcessesUpdatedEvent, &context->ProcessesUpdatedRegistration); PhFree(context); PhPropPageDlgProcDestroy(hwndDlg); @@ -394,7 +394,7 @@ INT_PTR CALLBACK EtwDiskNetworkPageDlgProc( )); hdc = Graph_GetBufferedContext(context->DiskGraphHandle); - SelectObject(hdc, PhGetApplicationFont()); + SelectObject(hdc, PhApplicationFont); PhSetGraphText(hdc, drawInfo, &context->DiskGraphState.Text->sr, &NormalGraphTextMargin, &NormalGraphTextPadding, PH_ALIGN_TOP | PH_ALIGN_LEFT); } @@ -462,7 +462,7 @@ INT_PTR CALLBACK EtwDiskNetworkPageDlgProc( )); hdc = Graph_GetBufferedContext(context->NetworkGraphHandle); - SelectObject(hdc, PhGetApplicationFont()); + SelectObject(hdc, PhApplicationFont); PhSetGraphText(hdc, drawInfo, &context->NetworkGraphState.Text->sr, &NormalGraphTextMargin, &NormalGraphTextPadding, PH_ALIGN_TOP | PH_ALIGN_LEFT); } diff --git a/plugins/ExtendedTools/etwstat.c b/plugins/ExtendedTools/etwstat.c index 663613de863e..33ee65dd33ee 100644 --- a/plugins/ExtendedTools/etwstat.c +++ b/plugins/ExtendedTools/etwstat.c @@ -85,13 +85,13 @@ VOID EtEtwStatisticsInitialization( PhInitializeCircularBuffer_ULONG(&EtMaxNetworkHistory, sampleCount); PhRegisterCallback( - PhGetGeneralCallback(GeneralCallbackProcessProviderUpdated), + &PhProcessesUpdatedEvent, EtEtwProcessesUpdatedCallback, NULL, &EtpProcessesUpdatedCallbackRegistration ); PhRegisterCallback( - PhGetGeneralCallback(GeneralCallbackNetworkProviderUpdated), + &PhNetworkItemsUpdatedEvent, EtEtwNetworkItemsUpdatedCallback, NULL, &EtpNetworkItemsUpdatedCallbackRegistration @@ -224,7 +224,7 @@ VOID NTAPI EtEtwProcessesUpdatedCallback( // Since Windows 8, we no longer get the correct process/thread IDs in the // event headers for disk events. We need to update our process information since // etwmon uses our EtThreadIdToProcessId function. - if (PhWindowsVersion() >= WINDOWS_8) + if (WindowsVersion >= WINDOWS_8) EtUpdateProcessInformation(); // ETW is extremely lazy when it comes to flushing buffers, so we must do it @@ -357,7 +357,7 @@ VOID NTAPI EtEtwNetworkItemsUpdatedCallback( { // Values have changed. Invalidate the network node. PhReferenceObject(block->NetworkItem); - ProcessHacker_Invoke(PhMainWindowHandle, EtpInvalidateNetworkNode, block->NetworkItem); + ProcessHacker_Invoke(PhMainWndHandle, EtpInvalidateNetworkNode, block->NetworkItem); } listEntry = listEntry->Flink; diff --git a/plugins/ExtendedTools/exttools.h b/plugins/ExtendedTools/exttools.h index c5201b3fabc5..967f6d30f356 100644 --- a/plugins/ExtendedTools/exttools.h +++ b/plugins/ExtendedTools/exttools.h @@ -27,6 +27,10 @@ extern HWND NetworkTreeNewHandle; #define SETTING_NAME_UNLOADED_WINDOW_SIZE (PLUGIN_NAME L".TracertWindowSize") #define SETTING_NAME_UNLOADED_COLUMNS (PLUGIN_NAME L".UnloadedListColumns") +#define ET_SCALE_DPI(Value) PhMultiplyDivide(Value, PhGlobalDpi, 96) +#define ET_LOAD_SHARED_ICON_SMALL(Name) PhLoadIcon(PhLibImageBase, (Name), PH_LOAD_ICON_SHARED | PH_LOAD_ICON_SIZE_SMALL, 0, 0) +#define ET_LOAD_SHARED_ICON_LARGE(Name) PhLoadIcon(PhLibImageBase, (Name), PH_LOAD_ICON_SHARED | PH_LOAD_ICON_SIZE_LARGE, 0, 0) + // Graph update message #define UPDATE_MSG (WM_APP + 1) diff --git a/plugins/ExtendedTools/gpumon.c b/plugins/ExtendedTools/gpumon.c index 4905e6fe2374..ca608783baa3 100644 --- a/plugins/ExtendedTools/gpumon.c +++ b/plugins/ExtendedTools/gpumon.c @@ -97,7 +97,7 @@ VOID EtGpuMonitorInitialization( } PhRegisterCallback( - PhGetGeneralCallback(GeneralCallbackProcessProviderUpdated), + &PhProcessesUpdatedEvent, EtGpuProcessesUpdatedCallback, NULL, &ProcessesUpdatedCallbackRegistration @@ -244,7 +244,7 @@ BOOLEAN EtpInitializeD3DStatistics( ULONG64 commitLimit; ULONG aperture; - if (PhWindowsVersion() >= WINDOWS_8) + if (WindowsVersion >= WINDOWS_8) { commitLimit = queryStatistics.QueryResult.SegmentInformation.CommitLimit; aperture = queryStatistics.QueryResult.SegmentInformation.Aperture; @@ -418,7 +418,7 @@ VOID EtpUpdateSegmentInformation( { ULONG64 bytesCommitted; - if (PhWindowsVersion() >= WINDOWS_8) + if (WindowsVersion >= WINDOWS_8) { bytesCommitted = queryStatistics.QueryResult.ProcessSegmentInformation.BytesCommitted; } @@ -436,7 +436,7 @@ VOID EtpUpdateSegmentInformation( { ULONG64 bytesCommitted; - if (PhWindowsVersion() >= WINDOWS_8) + if (WindowsVersion >= WINDOWS_8) { bytesCommitted = queryStatistics.QueryResult.SegmentInformation.BytesResident; } @@ -777,7 +777,7 @@ VOID EtQueryProcessGpuStatistics( { ULONG64 bytesCommitted; - if (PhWindowsVersion() >= WINDOWS_8) + if (WindowsVersion >= WINDOWS_8) { bytesCommitted = queryStatistics.QueryResult.ProcessSegmentInformation.BytesCommitted; } diff --git a/plugins/ExtendedTools/gpunodes.c b/plugins/ExtendedTools/gpunodes.c index 6b1e083f01e4..fe9467dda387 100644 --- a/plugins/ExtendedTools/gpunodes.c +++ b/plugins/ExtendedTools/gpunodes.c @@ -121,13 +121,15 @@ INT_PTR CALLBACK EtpGpuNodesDlgProc( WindowHandle = hwndDlg; - SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhImageBaseAddress, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); - SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhImageBaseAddress, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); + SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)ET_LOAD_SHARED_ICON_SMALL(MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); + SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)ET_LOAD_SHARED_ICON_LARGE(MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); PhInitializeLayoutManager(&LayoutManager, hwndDlg); PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDOK), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); LayoutMargin = PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDC_LAYOUT), NULL, PH_ANCHOR_ALL)->Margin; + PhRegisterCallback(&PhProcessesUpdatedEvent, ProcessesUpdatedCallback, NULL, &ProcessesUpdatedCallbackRegistration); + GraphHandle = PhAllocate(sizeof(HWND) * EtGpuTotalNodeCount); CheckBoxHandle = PhAllocate(sizeof(HWND) * EtGpuTotalNodeCount); GraphState = PhAllocate(sizeof(PH_GRAPH_STATE) * EtGpuTotalNodeCount); @@ -204,8 +206,6 @@ INT_PTR CALLBACK EtpGpuNodesDlgProc( PhCenterWindow(hwndDlg, GetParent(hwndDlg)); EtpLoadNodeBitMap(); - - PhRegisterCallback(PhGetGeneralCallback(GeneralCallbackProcessProviderUpdated), ProcessesUpdatedCallback, NULL, &ProcessesUpdatedCallbackRegistration); } break; case WM_DESTROY: @@ -214,7 +214,7 @@ INT_PTR CALLBACK EtpGpuNodesDlgProc( EtpSaveNodeBitMap(); - PhUnregisterCallback(PhGetGeneralCallback(GeneralCallbackProcessProviderUpdated), &ProcessesUpdatedCallbackRegistration); + PhUnregisterCallback(&PhProcessesUpdatedEvent, &ProcessesUpdatedCallbackRegistration); for (i = 0; i < EtGpuTotalNodeCount; i++) { diff --git a/plugins/ExtendedTools/gpuprprp.c b/plugins/ExtendedTools/gpuprprp.c index 6661ee3e747c..882b3c453d75 100644 --- a/plugins/ExtendedTools/gpuprprp.c +++ b/plugins/ExtendedTools/gpuprprp.c @@ -263,9 +263,9 @@ VOID GpuPropLayoutGraphs( HDWP deferHandle; RECT clientRect; RECT panelRect; - RECT margin = { PH_SCALE_DPI(13), PH_SCALE_DPI(13), PH_SCALE_DPI(13), PH_SCALE_DPI(13) }; - RECT innerMargin = { PH_SCALE_DPI(10), PH_SCALE_DPI(20), PH_SCALE_DPI(10), PH_SCALE_DPI(10) }; - LONG between = PH_SCALE_DPI(3); + RECT margin = { ET_SCALE_DPI(13), ET_SCALE_DPI(13), ET_SCALE_DPI(13), ET_SCALE_DPI(13) }; + RECT innerMargin = { ET_SCALE_DPI(10), ET_SCALE_DPI(20), ET_SCALE_DPI(10), ET_SCALE_DPI(10) }; + LONG between = ET_SCALE_DPI(3); ULONG graphWidth; ULONG graphHeight; @@ -474,7 +474,7 @@ INT_PTR CALLBACK EtpGpuPageDlgProc( GpuPropUpdatePanel(context); PhRegisterCallback( - PhGetGeneralCallback(GeneralCallbackProcessProviderUpdated), + &PhProcessesUpdatedEvent, ProcessesUpdatedHandler, context, &context->ProcessesUpdatedRegistration @@ -502,7 +502,7 @@ INT_PTR CALLBACK EtpGpuPageDlgProc( if (context->PanelHandle) DestroyWindow(context->PanelHandle); - PhUnregisterCallback(PhGetGeneralCallback(GeneralCallbackProcessProviderUpdated), &context->ProcessesUpdatedRegistration); + PhUnregisterCallback(&PhProcessesUpdatedEvent, &context->ProcessesUpdatedRegistration); PhFree(context); PhPropPageDlgProcDestroy(hwndDlg); @@ -543,7 +543,7 @@ INT_PTR CALLBACK EtpGpuPageDlgProc( )); hdc = Graph_GetBufferedContext(context->GpuGraphHandle); - SelectObject(hdc, PhGetApplicationFont()); + SelectObject(hdc, PhApplicationFont); PhSetGraphText(hdc, drawInfo, &context->GpuGraphState.Text->sr, &NormalGraphTextMargin, &NormalGraphTextPadding, PH_ALIGN_TOP | PH_ALIGN_LEFT); } @@ -574,7 +574,7 @@ INT_PTR CALLBACK EtpGpuPageDlgProc( )); hdc = Graph_GetBufferedContext(context->MemGraphHandle); - SelectObject(hdc, PhGetApplicationFont()); + SelectObject(hdc, PhApplicationFont); PhSetGraphText( hdc, drawInfo, @@ -630,7 +630,7 @@ INT_PTR CALLBACK EtpGpuPageDlgProc( )); hdc = Graph_GetBufferedContext(context->SharedGraphHandle); - SelectObject(hdc, PhGetApplicationFont()); + SelectObject(hdc, PhApplicationFont); PhSetGraphText(hdc, drawInfo, &context->MemorySharedGraphState.Text->sr, &NormalGraphTextMargin, &NormalGraphTextPadding, PH_ALIGN_TOP | PH_ALIGN_LEFT); } diff --git a/plugins/ExtendedTools/main.c b/plugins/ExtendedTools/main.c index 542438278ebd..22c279729158 100644 --- a/plugins/ExtendedTools/main.c +++ b/plugins/ExtendedTools/main.c @@ -91,7 +91,7 @@ VOID NTAPI MenuItemCallback( break; case ID_PROCESS_WSWATCH: { - EtShowWsWatchDialog(PhMainWindowHandle, menuItem->Context); + EtShowWsWatchDialog(PhMainWndHandle, menuItem->Context); } break; case ID_THREAD_CANCELIO: @@ -565,13 +565,13 @@ LOGICAL DllMain( ); PhRegisterCallback( - PhGetGeneralCallback(GeneralCallbackProcessProviderUpdated), + &PhProcessesUpdatedEvent, ProcessesUpdatedCallback, NULL, &ProcessesUpdatedCallbackRegistration ); PhRegisterCallback( - PhGetGeneralCallback(GeneralCallbackNetworkProviderUpdated), + &PhNetworkItemsUpdatedEvent, NetworkItemsUpdatedCallback, NULL, &NetworkItemsUpdatedCallbackRegistration diff --git a/plugins/ExtendedTools/unldll.c b/plugins/ExtendedTools/unldll.c index 04fd28abfce5..54d9f4b8ae27 100644 --- a/plugins/ExtendedTools/unldll.c +++ b/plugins/ExtendedTools/unldll.c @@ -305,8 +305,8 @@ INT_PTR CALLBACK EtpUnloadedDllsDlgProc( { HWND lvHandle; - SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhImageBaseAddress, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); - SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhImageBaseAddress, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); + SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)ET_LOAD_SHARED_ICON_SMALL(MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); + SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)ET_LOAD_SHARED_ICON_LARGE(MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); PhCenterWindow(hwndDlg, GetParent(hwndDlg)); @@ -337,7 +337,7 @@ INT_PTR CALLBACK EtpUnloadedDllsDlgProc( if (PhGetIntegerPairSetting(SETTING_NAME_UNLOADED_WINDOW_POSITION).X != 0) PhLoadWindowPlacementFromSetting(SETTING_NAME_UNLOADED_WINDOW_POSITION, SETTING_NAME_UNLOADED_WINDOW_SIZE, hwndDlg); else - PhCenterWindow(hwndDlg, PhMainWindowHandle); + PhCenterWindow(hwndDlg, PhMainWndHandle); if (!EtpRefreshUnloadedDlls(hwndDlg, context)) { diff --git a/plugins/ExtendedTools/wswatch.c b/plugins/ExtendedTools/wswatch.c index 29094695fd0d..470092cb3b0d 100644 --- a/plugins/ExtendedTools/wswatch.c +++ b/plugins/ExtendedTools/wswatch.c @@ -389,7 +389,7 @@ static BOOLEAN NTAPI EnumGenericModulesCallback( // in Windows 7. if ( context->LoadingSymbolsForProcessId == SYSTEM_PROCESS_ID && - (ULONG_PTR)Module->BaseAddress <= PhGetSystemBasicInformation().MaximumUserModeAddress + (ULONG_PTR)Module->BaseAddress <= PhSystemBasicInformation.MaximumUserModeAddress ) return TRUE; diff --git a/plugins/ExtraPlugins/cloud.c b/plugins/ExtraPlugins/cloud.c index ac286ad2b0be..57509cc969c0 100644 --- a/plugins/ExtraPlugins/cloud.c +++ b/plugins/ExtraPlugins/cloud.c @@ -58,7 +58,7 @@ NTSTATUS QueryPluginsCallbackThread( if (!(httpSessionHandle = WinHttpOpen( L"ExtraPlugins_1.0", - PhWindowsVersion() >= WINDOWS_8_1 ? WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY : WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, + WindowsVersion >= WINDOWS_8_1 ? WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY : WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0 diff --git a/plugins/ExtraPlugins/dialog.c b/plugins/ExtraPlugins/dialog.c index ab5c5ea929d2..b924fe09d2d9 100644 --- a/plugins/ExtraPlugins/dialog.c +++ b/plugins/ExtraPlugins/dialog.c @@ -243,7 +243,7 @@ INT_PTR CALLBACK CloudPluginsDlgProc( context->NormalFontHandle = PhCreateCommonFont(-14, FW_NORMAL, NULL); context->BoldFontHandle = PhCreateCommonFont(-16, FW_BOLD, NULL); - PhCenterWindow(hwndDlg, PhMainWindowHandle); + PhCenterWindow(hwndDlg, PhMainWndHandle); InitializePluginsTree(context, hwndDlg, context->TreeNewHandle); PhAddTreeNewFilter(GetPluginListFilterSupport(context), ProcessTreeFilterCallback, context); diff --git a/plugins/ExtraPlugins/setup/page5.c b/plugins/ExtraPlugins/setup/page5.c index 256c6a8d52dc..e703258e37b6 100644 --- a/plugins/ExtraPlugins/setup/page5.c +++ b/plugins/ExtraPlugins/setup/page5.c @@ -45,9 +45,9 @@ HRESULT CALLBACK RestartTaskDialogCallbackProc( { if ((INT)wParam == IDYES) { - ProcessHacker_PrepareForEarlyShutdown(PhMainWindowHandle); + ProcessHacker_PrepareForEarlyShutdown(PhMainWndHandle); PhShellProcessHacker( - PhMainWindowHandle, + PhMainWndHandle, L"-v", SW_SHOW, 0, @@ -56,7 +56,7 @@ HRESULT CALLBACK RestartTaskDialogCallbackProc( NULL ); //PhShellProcessHacker( - // PhMainWindowHandle, + // PhMainWndHandle, // L"-plugin " PLUGIN_NAME L":INSTALL -plugin " PLUGIN_NAME L":hex64value", // SW_SHOW, // 0, @@ -64,7 +64,7 @@ HRESULT CALLBACK RestartTaskDialogCallbackProc( // 0, // NULL // ); - ProcessHacker_Destroy(PhMainWindowHandle); + ProcessHacker_Destroy(PhMainWndHandle); } } break; diff --git a/plugins/ExtraPlugins/setup/updater.c b/plugins/ExtraPlugins/setup/updater.c index 02e2e37eddb7..77662132c054 100644 --- a/plugins/ExtraPlugins/setup/updater.c +++ b/plugins/ExtraPlugins/setup/updater.c @@ -60,8 +60,22 @@ VOID TaskDialogCreateIcons( ) { // Load the Process Hacker window icon - Context->IconSmallHandle = PH_LOAD_SHARED_ICON_SMALL(PhImageBaseAddress, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER)); - Context->IconLargeHandle = PH_LOAD_SHARED_ICON_LARGE(PhImageBaseAddress, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER)); + Context->IconLargeHandle = (HICON)LoadImage( + NtCurrentPeb()->ImageBaseAddress, + MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER), + IMAGE_ICON, + GetSystemMetrics(SM_CXICON), + GetSystemMetrics(SM_CYICON), + LR_SHARED + ); + Context->IconSmallHandle = (HICON)LoadImage( + NtCurrentPeb()->ImageBaseAddress, + MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER), + IMAGE_ICON, + GetSystemMetrics(SM_CXSMICON), + GetSystemMetrics(SM_CYSMICON), + LR_SHARED + ); // Set the TaskDialog window icons SendMessage(Context->DialogHandle, WM_SETICON, ICON_SMALL, (LPARAM)Context->IconSmallHandle); @@ -407,7 +421,7 @@ NTSTATUS UpdateDownloadThread( // Open the HTTP session with the system proxy configuration if available if (!(httpSessionHandle = WinHttpOpen( PhGetString(userAgentString), - PhWindowsVersion() >= WINDOWS_8_1 ? WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY : WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, + WindowsVersion >= WINDOWS_8_1 ? WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY : WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0 @@ -416,7 +430,7 @@ NTSTATUS UpdateDownloadThread( goto CleanupExit; } - if (PhWindowsVersion() >= WINDOWS_8_1) + if (WindowsVersion >= WINDOWS_8_1) { ULONG httpFlags = WINHTTP_DECOMPRESSION_FLAG_GZIP | WINHTTP_DECOMPRESSION_FLAG_DEFLATE; @@ -451,7 +465,7 @@ NTSTATUS UpdateDownloadThread( goto CleanupExit; } - if (PhWindowsVersion() >= WINDOWS_7) + if (WindowsVersion >= WINDOWS_7) { ULONG keepAlive = WINHTTP_DISABLE_KEEP_ALIVE; WinHttpSetOption(httpRequestHandle, WINHTTP_OPTION_DISABLE_FEATURE, &keepAlive, sizeof(ULONG)); @@ -724,11 +738,11 @@ LRESULT CALLBACK TaskDialogSubclassProc( // break; //case WM_NCACTIVATE: // { - // if (IsWindowVisible(PhMainWindowHandle) && !IsMinimized(PhMainWindowHandle)) + // if (IsWindowVisible(PhMainWndHandle) && !IsMinimized(PhMainWndHandle)) // { // if (!context->FixedWindowStyles) // { - // SetWindowLongPtr(hwndDlg, GWLP_HWNDPARENT, (LONG_PTR)PhMainWindowHandle); + // SetWindowLongPtr(hwndDlg, GWLP_HWNDPARENT, (LONG_PTR)PhMainWndHandle); // PhSetWindowExStyle(hwndDlg, WS_EX_APPWINDOW, WS_EX_APPWINDOW); // context->FixedWindowStyles = TRUE; // } diff --git a/plugins/HardwareDevices/disknotify.c b/plugins/HardwareDevices/disknotify.c index a68605ffbbd5..f212a04d456a 100644 --- a/plugins/HardwareDevices/disknotify.c +++ b/plugins/HardwareDevices/disknotify.c @@ -94,7 +94,7 @@ VOID AddRemoveDeviceChangeCallback( ) { // We get called during the plugin LoadCallback, don't do anything. - if (!PhMainWindowHandle) + if (!PhMainWndHandle) return; // Add the subclass only when disks are being monitored, remove when no longer needed. @@ -103,7 +103,7 @@ VOID AddRemoveDeviceChangeCallback( if (!SubclassActive) { // We have a disk device, subclass the main window to detect drive letter changes. - SetWindowSubclass(PhMainWindowHandle, MainWndDevicesSubclassProc, 0, 0); + SetWindowSubclass(PhMainWndHandle, MainWndDevicesSubclassProc, 0, 0); SubclassActive = TRUE; } } @@ -112,7 +112,7 @@ VOID AddRemoveDeviceChangeCallback( if (SubclassActive) { // The user has removed the last disk device, remove the subclass. - RemoveWindowSubclass(PhMainWindowHandle, MainWndDevicesSubclassProc, 0); + RemoveWindowSubclass(PhMainWndHandle, MainWndDevicesSubclassProc, 0); SubclassActive = FALSE; } } diff --git a/plugins/HardwareDevices/main.c b/plugins/HardwareDevices/main.c index fd212f6d7e64..9b2e7c4a39bd 100644 --- a/plugins/HardwareDevices/main.c +++ b/plugins/HardwareDevices/main.c @@ -259,7 +259,7 @@ VOID ShowDeviceMenu( selectedItem = PhShowEMenu( menu, - PhMainWindowHandle, + PhMainWndHandle, PH_EMENU_SHOW_LEFTRIGHT, PH_ALIGN_LEFT | PH_ALIGN_TOP, cursorPos.x, @@ -364,7 +364,7 @@ LOGICAL DllMain( ); PhRegisterCallback( - PhGetGeneralCallback(GeneralCallbackProcessProviderUpdated), + &PhProcessesUpdatedEvent, ProcessesUpdatedCallback, NULL, &ProcessesUpdatedCallbackRegistration diff --git a/plugins/HardwareDevices/netdetails.c b/plugins/HardwareDevices/netdetails.c index f703b9cd89d7..983a7ca071db 100644 --- a/plugins/HardwareDevices/netdetails.c +++ b/plugins/HardwareDevices/netdetails.c @@ -536,7 +536,7 @@ INT_PTR CALLBACK NetAdapterDetailsDlgProc( NetAdapterAddListViewItemGroups(context->ListViewHandle); PhRegisterCallback( - PhGetGeneralCallback(GeneralCallbackProcessProviderUpdated), + &PhProcessesUpdatedEvent, NetAdapterProcessesUpdatedHandler, context, &context->ProcessesUpdatedRegistration @@ -556,7 +556,7 @@ INT_PTR CALLBACK NetAdapterDetailsDlgProc( break; case WM_DESTROY: { - PhUnregisterCallback(PhGetGeneralCallback(GeneralCallbackProcessProviderUpdated), &context->ProcessesUpdatedRegistration); + PhUnregisterCallback(&PhProcessesUpdatedEvent, &context->ProcessesUpdatedRegistration); if (context->NotifyHandle) CancelMibChangeNotify2(context->NotifyHandle); diff --git a/plugins/HardwareDevices/netoptions.c b/plugins/HardwareDevices/netoptions.c index b82b52fd44e7..0807ba9a9e3b 100644 --- a/plugins/HardwareDevices/netoptions.c +++ b/plugins/HardwareDevices/netoptions.c @@ -301,7 +301,7 @@ BOOLEAN QueryNetworkDeviceInterfaceDescription( if ((result = CM_Get_DevNode_Property( // CM_Get_DevNode_Registry_Property with CM_DRP_DEVICEDESC?? deviceInstanceHandle, - PhWindowsVersion() >= WINDOWS_8 ? &DEVPKEY_Device_FriendlyName : &DEVPKEY_Device_DeviceDesc, + WindowsVersion >= WINDOWS_8 ? &DEVPKEY_Device_FriendlyName : &DEVPKEY_Device_DeviceDesc, &devicePropertyType, (PBYTE)deviceDescription->Buffer, &bufferSize, @@ -313,7 +313,7 @@ BOOLEAN QueryNetworkDeviceInterfaceDescription( result = CM_Get_DevNode_Property( deviceInstanceHandle, - PhWindowsVersion() >= WINDOWS_8 ? &DEVPKEY_Device_FriendlyName : &DEVPKEY_Device_DeviceDesc, + WindowsVersion >= WINDOWS_8 ? &DEVPKEY_Device_FriendlyName : &DEVPKEY_Device_DeviceDesc, &devicePropertyType, (PBYTE)deviceDescription->Buffer, &bufferSize, diff --git a/plugins/HardwareDevices/storage.c b/plugins/HardwareDevices/storage.c index 5c7a4472b533..2be01224b59c 100644 --- a/plugins/HardwareDevices/storage.c +++ b/plugins/HardwareDevices/storage.c @@ -918,21 +918,21 @@ BOOLEAN DiskDriveQueryFileSystemInfo( case FILESYSTEM_STATISTICS_TYPE_NTFS: case FILESYSTEM_STATISTICS_TYPE_REFS: // ReFS uses the same statistics as NTFS. { - bufferLength = sizeof(NTFS_FILESYSTEM_STATISTICS) * 64 * (ULONG)PhGetSystemBasicInformation().NumberOfProcessors; + bufferLength = sizeof(NTFS_FILESYSTEM_STATISTICS) * 64 * (ULONG)PhSystemBasicInformation.NumberOfProcessors; buffer = PhReAllocate(buffer, bufferLength); memset(buffer, 0, bufferLength); } break; case FILESYSTEM_STATISTICS_TYPE_FAT: { - bufferLength = sizeof(FAT_FILESYSTEM_STATISTICS) * 64 * (ULONG)PhGetSystemBasicInformation().NumberOfProcessors; + bufferLength = sizeof(FAT_FILESYSTEM_STATISTICS) * 64 * (ULONG)PhSystemBasicInformation.NumberOfProcessors; buffer = PhReAllocate(buffer, bufferLength); memset(buffer, 0, bufferLength); } break; case FILESYSTEM_STATISTICS_TYPE_EXFAT: { - bufferLength = sizeof(EXFAT_FILESYSTEM_STATISTICS) * 64 * (ULONG)PhGetSystemBasicInformation().NumberOfProcessors; + bufferLength = sizeof(EXFAT_FILESYSTEM_STATISTICS) * 64 * (ULONG)PhSystemBasicInformation.NumberOfProcessors; buffer = PhReAllocate(buffer, bufferLength); memset(buffer, 0, bufferLength); } diff --git a/plugins/NetworkTools/pages.c b/plugins/NetworkTools/pages.c index 887789488e94..f2bce861c8ca 100644 --- a/plugins/NetworkTools/pages.c +++ b/plugins/NetworkTools/pages.c @@ -107,9 +107,9 @@ HRESULT CALLBACK RestartTaskDialogCallbackProc( { if ((INT)wParam == IDYES) { - ProcessHacker_PrepareForEarlyShutdown(PhMainWindowHandle); + ProcessHacker_PrepareForEarlyShutdown(PhMainWndHandle); PhShellProcessHacker( - PhMainWindowHandle, + PhMainWndHandle, NULL, SW_SHOW, 0, @@ -117,7 +117,7 @@ HRESULT CALLBACK RestartTaskDialogCallbackProc( 0, NULL ); - ProcessHacker_Destroy(PhMainWindowHandle); + ProcessHacker_Destroy(PhMainWndHandle); } } break; diff --git a/plugins/NetworkTools/ping.c b/plugins/NetworkTools/ping.c index bbed74977946..0ccb364a7005 100644 --- a/plugins/NetworkTools/ping.c +++ b/plugins/NetworkTools/ping.c @@ -330,7 +330,7 @@ INT_PTR CALLBACK NetworkPingWndProc( if (PhGetIntegerPairSetting(SETTING_NAME_PING_WINDOW_POSITION).X != 0) PhLoadWindowPlacementFromSetting(SETTING_NAME_PING_WINDOW_POSITION, SETTING_NAME_PING_WINDOW_SIZE, hwndDlg); else - PhCenterWindow(hwndDlg, PhMainWindowHandle); + PhCenterWindow(hwndDlg, PhMainWndHandle); SetWindowText(hwndDlg, PhaFormatString(L"Ping %s", context->IpAddressString)->Buffer); SetWindowText(context->StatusHandle, PhaFormatString(L"Pinging %s with %lu bytes of data...", @@ -339,7 +339,7 @@ INT_PTR CALLBACK NetworkPingWndProc( ); PhRegisterCallback( - PhGetGeneralCallback(GeneralCallbackProcessProviderUpdated), + &PhProcessesUpdatedEvent, NetworkPingUpdateHandler, context, &context->ProcessesUpdatedRegistration @@ -362,7 +362,7 @@ INT_PTR CALLBACK NetworkPingWndProc( case WM_DESTROY: { PhUnregisterCallback( - PhGetGeneralCallback(GeneralCallbackProcessProviderUpdated), + &PhProcessesUpdatedEvent, &context->ProcessesUpdatedRegistration ); @@ -447,7 +447,7 @@ INT_PTR CALLBACK NetworkPingWndProc( PhFormatString(L"%lu ms", context->CurrentPingMs) ); - SelectObject(hdc, PhGetApplicationFont()); + SelectObject(hdc, PhApplicationFont); PhSetGraphText(hdc, drawInfo, &context->PingGraphState.Text->sr, &NormalGraphTextMargin, &NormalGraphTextPadding, PH_ALIGN_TOP | PH_ALIGN_LEFT); } diff --git a/plugins/NetworkTools/tracert.c b/plugins/NetworkTools/tracert.c index 519bbf6b47f1..41550a1f123b 100644 --- a/plugins/NetworkTools/tracert.c +++ b/plugins/NetworkTools/tracert.c @@ -568,10 +568,7 @@ INT_PTR CALLBACK TracertDlgProc( { HANDLE tracertThread; - SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhImageBaseAddress, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); - SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhImageBaseAddress, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); - - PhCenterWindow(hwndDlg, PhMainWindowHandle); + PhCenterWindow(hwndDlg, PhMainWndHandle); Static_SetText(hwndDlg, PhaFormatString(L"Tracing %s...", context->IpAddressString)->Buffer @@ -595,7 +592,7 @@ INT_PTR CALLBACK TracertDlgProc( if (PhGetIntegerPairSetting(SETTING_NAME_TRACERT_WINDOW_POSITION).X != 0) PhLoadWindowPlacementFromSetting(SETTING_NAME_TRACERT_WINDOW_POSITION, SETTING_NAME_TRACERT_WINDOW_SIZE, hwndDlg); else - PhCenterWindow(hwndDlg, PhMainWindowHandle); + PhCenterWindow(hwndDlg, PhMainWndHandle); PhReferenceObject(context); diff --git a/plugins/NetworkTools/update.c b/plugins/NetworkTools/update.c index c7ceba20e69f..988029df021f 100644 --- a/plugins/NetworkTools/update.c +++ b/plugins/NetworkTools/update.c @@ -35,14 +35,21 @@ VOID FreeUpdateContext( ) { //PhClearReference(&Context->Version); - //PhClearReference(&Context->RevVersion); + // PhClearReference(&Context->RevVersion); //PhClearReference(&Context->RelDate); - //PhClearReference(&Context->Size); + // PhClearReference(&Context->Size); //PhClearReference(&Context->Hash); - //PhClearReference(&Context->Signature); - //PhClearReference(&Context->ReleaseNotesUrl); + // PhClearReference(&Context->Signature); + // PhClearReference(&Context->ReleaseNotesUrl); //PhClearReference(&Context->SetupFilePath); - //PhClearReference(&Context->SetupFileDownloadUrl); + // PhClearReference(&Context->SetupFileDownloadUrl); + + if (Context->IconLargeHandle) + DestroyIcon(Context->IconLargeHandle); + + if (Context->IconSmallHandle) + DestroyIcon(Context->IconSmallHandle); + //PhClearReference(&Context); } @@ -50,11 +57,29 @@ VOID TaskDialogCreateIcons( _In_ PPH_UPDATER_CONTEXT Context ) { - Context->IconSmallHandle = PH_LOAD_SHARED_ICON_SMALL(PhImageBaseAddress, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER)); - Context->IconLargeHandle = PH_LOAD_SHARED_ICON_LARGE(PhImageBaseAddress, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER)); + HICON largeIcon; + HICON smallIcon; + + largeIcon = PhLoadIcon( + NtCurrentPeb()->ImageBaseAddress, + MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER), + PH_LOAD_ICON_SIZE_LARGE, + GetSystemMetrics(SM_CXICON), + GetSystemMetrics(SM_CYICON) + ); + smallIcon = PhLoadIcon( + NtCurrentPeb()->ImageBaseAddress, + MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER), + PH_LOAD_ICON_SIZE_LARGE, + GetSystemMetrics(SM_CXSMICON), + GetSystemMetrics(SM_CYSMICON) + ); + + Context->IconLargeHandle = largeIcon; + Context->IconSmallHandle = smallIcon; - SendMessage(Context->DialogHandle, WM_SETICON, ICON_SMALL, (LPARAM)Context->IconLargeHandle); - SendMessage(Context->DialogHandle, WM_SETICON, ICON_BIG, (LPARAM)Context->IconSmallHandle); + SendMessage(Context->DialogHandle, WM_SETICON, ICON_SMALL, (LPARAM)largeIcon); + SendMessage(Context->DialogHandle, WM_SETICON, ICON_BIG, (LPARAM)smallIcon); } VOID TaskDialogLinkClicked( @@ -134,7 +159,7 @@ PPH_STRING QueryFwLinkUrl( if (!(httpSessionHandle = WinHttpOpen( NULL, - PhWindowsVersion() >= WINDOWS_8_1 ? WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY : WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, + WindowsVersion >= WINDOWS_8_1 ? WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY : WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0 @@ -143,7 +168,7 @@ PPH_STRING QueryFwLinkUrl( goto CleanupExit; } - if (PhWindowsVersion() >= WINDOWS_8_1) + if (WindowsVersion >= WINDOWS_8_1) { ULONG httpFlags = WINHTTP_DECOMPRESSION_FLAG_GZIP | WINHTTP_DECOMPRESSION_FLAG_DEFLATE; @@ -198,7 +223,7 @@ PPH_STRING QueryFwLinkUrl( ); } - if (PhWindowsVersion() >= WINDOWS_7) + if (WindowsVersion >= WINDOWS_7) { ULONG option = WINHTTP_DISABLE_REDIRECTS; WinHttpSetOption(httpRequestHandle, WINHTTP_OPTION_DISABLE_FEATURE, &option, sizeof(ULONG)); @@ -390,7 +415,7 @@ NTSTATUS GeoIPUpdateThread( if (!(httpSessionHandle = WinHttpOpen( PhGetString(userAgentString), - PhWindowsVersion() >= WINDOWS_8_1 ? WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY : WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, + WindowsVersion >= WINDOWS_8_1 ? WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY : WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0 @@ -399,7 +424,7 @@ NTSTATUS GeoIPUpdateThread( goto CleanupExit; } - if (PhWindowsVersion() >= WINDOWS_8_1) + if (WindowsVersion >= WINDOWS_8_1) { ULONG httpFlags = WINHTTP_DECOMPRESSION_FLAG_GZIP | WINHTTP_DECOMPRESSION_FLAG_DEFLATE; WinHttpSetOption(httpSessionHandle, WINHTTP_OPTION_DECOMPRESSION, &httpFlags, sizeof(ULONG)); @@ -428,7 +453,7 @@ NTSTATUS GeoIPUpdateThread( goto CleanupExit; } - if (PhWindowsVersion() >= WINDOWS_7) + if (WindowsVersion >= WINDOWS_7) { ULONG option = WINHTTP_DISABLE_KEEP_ALIVE; WinHttpSetOption(httpRequestHandle, WINHTTP_OPTION_DISABLE_FEATURE, &option, sizeof(ULONG)); @@ -710,7 +735,7 @@ HRESULT CALLBACK TaskDialogBootstrapCallback( UpdateDialogHandle = context->DialogHandle = hwndDlg; // Center the update window on PH if it's visible else we center on the desktop. - PhCenterWindow(hwndDlg, (IsWindowVisible(PhMainWindowHandle) && !IsMinimized(PhMainWindowHandle)) ? PhMainWindowHandle : NULL); + PhCenterWindow(hwndDlg, (IsWindowVisible(PhMainWndHandle) && !IsMinimized(PhMainWndHandle)) ? PhMainWndHandle : NULL); // Create the Taskdialog icons TaskDialogCreateIcons(context); @@ -762,7 +787,7 @@ NTSTATUS GeoIPUpdateDialogThread( //info.hwnd = Parameter; //info.lpVerb = L"runas"; // - //ProcessHacker_PrepareForEarlyShutdown(PhMainWindowHandle); + //ProcessHacker_PrepareForEarlyShutdown(PhMainWndHandle); // //if (ShellExecuteEx(&info)) //{ @@ -785,7 +810,7 @@ NTSTATUS GeoIPUpdateDialogThread( // NULL // ); // - // ProcessHacker_Destroy(PhMainWindowHandle); + // ProcessHacker_Destroy(PhMainWndHandle); // } // } // @@ -793,7 +818,7 @@ NTSTATUS GeoIPUpdateDialogThread( //} //else //{ - // ProcessHacker_CancelEarlyShutdown(PhMainWindowHandle); + // ProcessHacker_CancelEarlyShutdown(PhMainWndHandle); //} } diff --git a/plugins/NetworkTools/whois.c b/plugins/NetworkTools/whois.c index b7ea2d5a38d5..bf6e602d0270 100644 --- a/plugins/NetworkTools/whois.c +++ b/plugins/NetworkTools/whois.c @@ -396,9 +396,6 @@ INT_PTR CALLBACK NetworkOutputDlgProc( { HANDLE dialogThread; - SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhImageBaseAddress, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); - SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhImageBaseAddress, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); - SetWindowText(hwndDlg, PhaFormatString(L"Whois %s...", context->IpAddressString)->Buffer); context->WindowHandle = hwndDlg; @@ -419,7 +416,7 @@ INT_PTR CALLBACK NetworkOutputDlgProc( if (PhGetIntegerPairSetting(SETTING_NAME_WHOIS_WINDOW_POSITION).X != 0) PhLoadWindowPlacementFromSetting(SETTING_NAME_WHOIS_WINDOW_POSITION, SETTING_NAME_WHOIS_WINDOW_SIZE, hwndDlg); else - PhCenterWindow(hwndDlg, PhMainWindowHandle); + PhCenterWindow(hwndDlg, PhMainWndHandle); if (dialogThread = PhCreateThread(0, NetworkWhoisThreadStart, (PVOID)context)) NtClose(dialogThread); diff --git a/plugins/OnlineChecks/main.c b/plugins/OnlineChecks/main.c index 687ba5defef1..35ef25384a98 100644 --- a/plugins/OnlineChecks/main.c +++ b/plugins/OnlineChecks/main.c @@ -178,7 +178,13 @@ VOID NTAPI MenuItemCallback( config.dwFlags = TDF_USE_HICON_MAIN | TDF_ALLOW_DIALOG_CANCELLATION; config.dwCommonButtons = TDCBF_YES_BUTTON | TDCBF_NO_BUTTON; config.hwndParent = menuItem->OwnerWindow; - config.hMainIcon = PH_LOAD_SHARED_ICON_LARGE(PhImageBaseAddress, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER)); + config.hMainIcon = PhLoadIcon( + NtCurrentPeb()->ImageBaseAddress, + MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER), + PH_LOAD_ICON_SIZE_LARGE, + GetSystemMetrics(SM_CXICON), + GetSystemMetrics(SM_CYICON) + ); config.cxWidth = 180; config.pszWindowTitle = L"Process Hacker - VirusTotal"; config.pszMainInstruction = L"VirusTotal scanning requires a restart of Process Hacker."; @@ -186,9 +192,9 @@ VOID NTAPI MenuItemCallback( if (SUCCEEDED(TaskDialogIndirect(&config, &result, NULL, NULL)) && result == IDYES) { - ProcessHacker_PrepareForEarlyShutdown(PhMainWindowHandle); + ProcessHacker_PrepareForEarlyShutdown(PhMainWndHandle); PhShellProcessHacker( - PhMainWindowHandle, + PhMainWndHandle, L"-v", SW_SHOW, 0, @@ -196,7 +202,7 @@ VOID NTAPI MenuItemCallback( 0, NULL ); - ProcessHacker_Destroy(PhMainWindowHandle); + ProcessHacker_Destroy(PhMainWndHandle); } DestroyIcon(config.hMainIcon); diff --git a/plugins/OnlineChecks/page1.c b/plugins/OnlineChecks/page1.c index 2ce418db265f..7b8489b72c95 100644 --- a/plugins/OnlineChecks/page1.c +++ b/plugins/OnlineChecks/page1.c @@ -40,7 +40,7 @@ HRESULT CALLBACK TaskDialogProcessingCallbackProc( SendMessage(hwndDlg, TDM_SET_PROGRESS_BAR_MARQUEE, TRUE, 1); if (context->TaskbarListClass) - ITaskbarList3_SetProgressState(context->TaskbarListClass, PhMainWindowHandle, TBPF_INDETERMINATE); + ITaskbarList3_SetProgressState(context->TaskbarListClass, PhMainWndHandle, TBPF_INDETERMINATE); PhReferenceObject(context); PhQueueItemWorkQueue(PhGetGlobalWorkQueue(), UploadCheckThreadStart, context); diff --git a/plugins/OnlineChecks/page2.c b/plugins/OnlineChecks/page2.c index b6b972258f19..aff040808c29 100644 --- a/plugins/OnlineChecks/page2.c +++ b/plugins/OnlineChecks/page2.c @@ -45,7 +45,7 @@ HRESULT CALLBACK TaskDialogResultFoundProc( { if (context->TaskbarListClass) { - ITaskbarList3_SetProgressState(context->TaskbarListClass, PhMainWindowHandle, TBPF_NOPROGRESS); + ITaskbarList3_SetProgressState(context->TaskbarListClass, PhMainWndHandle, TBPF_NOPROGRESS); } } break; diff --git a/plugins/OnlineChecks/page3.c b/plugins/OnlineChecks/page3.c index 9d6fac0bc773..c35e7309c7ec 100644 --- a/plugins/OnlineChecks/page3.c +++ b/plugins/OnlineChecks/page3.c @@ -40,7 +40,7 @@ HRESULT CALLBACK TaskDialogProgressCallbackProc( SendMessage(hwndDlg, TDM_SET_PROGRESS_BAR_MARQUEE, TRUE, 1); if (context->TaskbarListClass) - ITaskbarList3_SetProgressState(context->TaskbarListClass, PhMainWindowHandle, TBPF_INDETERMINATE); + ITaskbarList3_SetProgressState(context->TaskbarListClass, PhMainWndHandle, TBPF_INDETERMINATE); PhReferenceObject(context); context->UploadThreadHandle = PhCreateThread(0, UploadFileThreadStart, context); diff --git a/plugins/OnlineChecks/page4.c b/plugins/OnlineChecks/page4.c index e174cb39f63c..849bdcd1e0cf 100644 --- a/plugins/OnlineChecks/page4.c +++ b/plugins/OnlineChecks/page4.c @@ -38,8 +38,8 @@ HRESULT CALLBACK TaskDialogErrorProc( { if (context->TaskbarListClass) { - ITaskbarList3_SetProgressValue(context->TaskbarListClass, PhMainWindowHandle, 1, 1); - ITaskbarList3_SetProgressState(context->TaskbarListClass, PhMainWindowHandle, TBPF_ERROR); + ITaskbarList3_SetProgressValue(context->TaskbarListClass, PhMainWndHandle, 1, 1); + ITaskbarList3_SetProgressState(context->TaskbarListClass, PhMainWndHandle, TBPF_ERROR); } } break; diff --git a/plugins/OnlineChecks/upload.c b/plugins/OnlineChecks/upload.c index d0736ff8414e..803689827131 100644 --- a/plugins/OnlineChecks/upload.c +++ b/plugins/OnlineChecks/upload.c @@ -172,6 +172,18 @@ VOID UploadContextDeleteProcedure( context->HttpHandle = NULL; } + if (context->IconLargeHandle) + { + DestroyIcon(context->IconLargeHandle); + context->IconLargeHandle = NULL; + } + + if (context->IconSmallHandle) + { + DestroyIcon(context->IconSmallHandle); + context->IconSmallHandle = NULL; + } + PhClearReference(&context->ErrorString); PhClearReference(&context->FileName); PhClearReference(&context->BaseFileName); @@ -193,7 +205,7 @@ VOID TaskDialogFreeContext( { // Reset Taskbar progress state(s) if (Context->TaskbarListClass) - ITaskbarList3_SetProgressState(Context->TaskbarListClass, PhMainWindowHandle, TBPF_NOPROGRESS); + ITaskbarList3_SetProgressState(Context->TaskbarListClass, PhMainWndHandle, TBPF_NOPROGRESS); if (Context->TaskbarListClass) ITaskbarList3_SetProgressState(Context->TaskbarListClass, Context->DialogHandle, TBPF_NOPROGRESS); @@ -205,8 +217,20 @@ VOID TaskDialogCreateIcons( _In_ PUPLOAD_CONTEXT Context ) { - Context->IconSmallHandle = PH_LOAD_SHARED_ICON_SMALL(PhImageBaseAddress, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER)); - Context->IconLargeHandle = PH_LOAD_SHARED_ICON_LARGE(PhImageBaseAddress, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER)); + Context->IconLargeHandle = PhLoadIcon( + NtCurrentPeb()->ImageBaseAddress, + MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER), + PH_LOAD_ICON_SIZE_LARGE, + GetSystemMetrics(SM_CXICON), + GetSystemMetrics(SM_CYICON) + ); + Context->IconSmallHandle = PhLoadIcon( + NtCurrentPeb()->ImageBaseAddress, + MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER), + PH_LOAD_ICON_SIZE_LARGE, + GetSystemMetrics(SM_CXICON), + GetSystemMetrics(SM_CYICON) + ); SendMessage(Context->DialogHandle, WM_SETICON, ICON_SMALL, (LPARAM)Context->IconSmallHandle); SendMessage(Context->DialogHandle, WM_SETICON, ICON_BIG, (LPARAM)Context->IconLargeHandle); @@ -686,7 +710,7 @@ NTSTATUS UploadFileThreadStart( { ITaskbarList3_SetProgressState( context->TaskbarListClass, - PhMainWindowHandle, + PhMainWndHandle, TBPF_NORMAL ); } @@ -890,7 +914,7 @@ NTSTATUS UploadFileThreadStart( // Reset Taskbar progress state(s) if (context->TaskbarListClass) { - ITaskbarList3_SetProgressState(context->TaskbarListClass, PhMainWindowHandle, TBPF_NOPROGRESS); + ITaskbarList3_SetProgressState(context->TaskbarListClass, PhMainWndHandle, TBPF_NOPROGRESS); ITaskbarList3_SetProgressState(context->TaskbarListClass, context->DialogHandle, TBPF_NOPROGRESS); } @@ -990,7 +1014,7 @@ NTSTATUS UploadCheckThreadStart( if (!(context->HttpHandle = WinHttpOpen( userAgent->Buffer, - PhWindowsVersion() >= WINDOWS_8_1 ? WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY : WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, + WindowsVersion >= WINDOWS_8_1 ? WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY : WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0 @@ -999,7 +1023,7 @@ NTSTATUS UploadCheckThreadStart( goto CleanupExit; } - if (PhWindowsVersion() >= WINDOWS_8_1) + if (WindowsVersion >= WINDOWS_8_1) { ULONG gzipFlags = WINHTTP_DECOMPRESSION_FLAG_ALL; WinHttpSetOption(context->HttpHandle, WINHTTP_OPTION_DECOMPRESSION, &gzipFlags, sizeof(ULONG)); @@ -1228,7 +1252,7 @@ HRESULT CALLBACK TaskDialogBootstrapCallback( context->DialogHandle = hwndDlg; // Center the update window on PH if it's visible else we center on the desktop. - PhCenterWindow(hwndDlg, (IsWindowVisible(PhMainWindowHandle) && !IsMinimized(PhMainWindowHandle)) ? PhMainWindowHandle : NULL); + PhCenterWindow(hwndDlg, (IsWindowVisible(PhMainWndHandle) && !IsMinimized(PhMainWndHandle)) ? PhMainWndHandle : NULL); // Create the Taskdialog icons TaskDialogCreateIcons(context); diff --git a/plugins/OnlineChecks/virustotal.c b/plugins/OnlineChecks/virustotal.c index bc93f9df57bd..642ce0ddd9f3 100644 --- a/plugins/OnlineChecks/virustotal.c +++ b/plugins/OnlineChecks/virustotal.c @@ -317,7 +317,7 @@ PSTR VirusTotalSendHttpRequest( if (!(httpSessionHandle = WinHttpOpen( userAgent->Buffer, - PhWindowsVersion() >= WINDOWS_8_1 ? WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY : WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, + WindowsVersion >= WINDOWS_8_1 ? WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY : WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0 @@ -326,7 +326,7 @@ PSTR VirusTotalSendHttpRequest( goto CleanupExit; } - if (PhWindowsVersion() >= WINDOWS_8_1) + if (WindowsVersion >= WINDOWS_8_1) { ULONG gzipFlags = WINHTTP_DECOMPRESSION_FLAG_GZIP | WINHTTP_DECOMPRESSION_FLAG_DEFLATE; WinHttpSetOption(httpSessionHandle, WINHTTP_OPTION_DECOMPRESSION, &gzipFlags, sizeof(ULONG)); @@ -461,7 +461,7 @@ PVIRUSTOTAL_FILE_REPORT_RESULT VirusTotalSendHttpFileReportRequest( if (!(httpSessionHandle = WinHttpOpen( userAgent->Buffer, - PhWindowsVersion() >= WINDOWS_8_1 ? WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY : WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, + WindowsVersion >= WINDOWS_8_1 ? WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY : WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0 @@ -470,7 +470,7 @@ PVIRUSTOTAL_FILE_REPORT_RESULT VirusTotalSendHttpFileReportRequest( goto CleanupExit; } - if (PhWindowsVersion() >= WINDOWS_8_1) + if (WindowsVersion >= WINDOWS_8_1) { ULONG httpFlags = WINHTTP_DECOMPRESSION_FLAG_GZIP | WINHTTP_DECOMPRESSION_FLAG_DEFLATE; WinHttpSetOption(httpSessionHandle, WINHTTP_OPTION_DECOMPRESSION, &httpFlags, sizeof(ULONG)); diff --git a/plugins/Plugins.props b/plugins/Plugins.props index 88e4574b2c86..f47cc8f6e6d0 100644 --- a/plugins/Plugins.props +++ b/plugins/Plugins.props @@ -31,8 +31,7 @@ true - delaylib.lib;ProcessHacker.lib;ntdll.lib;%(AdditionalDependencies) - ProcessHacker.exe;%(DelayLoadDLLs) + ProcessHacker.lib;ntdll.lib;%(AdditionalDependencies) true 6.01 Windows @@ -77,18 +76,16 @@ StreamingSIMDExtensions - ..\..\sdk\lib\i386;..\..\tools\delaylib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) + ..\..\sdk\lib\i386;%(AdditionalLibraryDirectories) MachineX86 - ___delayLoadHelper2@8 - ..\..\sdk\lib\amd64;..\..\tools\delaylib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) + ..\..\sdk\lib\amd64;%(AdditionalLibraryDirectories) MachineX64 - __delayLoadHelper2 diff --git a/plugins/ToolStatus/customizesb.c b/plugins/ToolStatus/customizesb.c index 9b5ca897757d..cd4dbd29034d 100644 --- a/plugins/ToolStatus/customizesb.c +++ b/plugins/ToolStatus/customizesb.c @@ -310,7 +310,7 @@ INT_PTR CALLBACK CustomizeStatusBarDialogProc( { case WM_INITDIALOG: { - PhCenterWindow(hwndDlg, PhMainWindowHandle); + PhCenterWindow(hwndDlg, PhMainWndHandle); context->DialogHandle = hwndDlg; context->AvailableListHandle = GetDlgItem(hwndDlg, IDC_AVAILABLE); @@ -627,7 +627,7 @@ VOID StatusBarShowCustomizeDialog( DialogBox( PluginInstance->DllBase, MAKEINTRESOURCE(IDD_CUSTOMIZE_SB), - PhMainWindowHandle, + PhMainWndHandle, CustomizeStatusBarDialogProc ); } \ No newline at end of file diff --git a/plugins/ToolStatus/customizetb.c b/plugins/ToolStatus/customizetb.c index c457964c4ffc..cef8fdffbb33 100644 --- a/plugins/ToolStatus/customizetb.c +++ b/plugins/ToolStatus/customizetb.c @@ -509,7 +509,7 @@ INT_PTR CALLBACK CustomizeToolbarDialogProc( { case WM_INITDIALOG: { - PhCenterWindow(hwndDlg, PhMainWindowHandle); + PhCenterWindow(hwndDlg, PhMainWndHandle); context->DialogHandle = hwndDlg; context->AvailableListHandle = GetDlgItem(hwndDlg, IDC_AVAILABLE); @@ -788,12 +788,12 @@ INT_PTR CALLBACK CustomizeToolbarDialogProc( if (ToolStatusConfig.AutoHideMenu) { - SetMenu(PhMainWindowHandle, NULL); + SetMenu(PhMainWndHandle, NULL); } else { - SetMenu(PhMainWindowHandle, MainMenu); - DrawMenuBar(PhMainWindowHandle); + SetMenu(PhMainWndHandle, MainMenu); + DrawMenuBar(PhMainWndHandle); } } } @@ -937,7 +937,7 @@ VOID ToolBarShowCustomizeDialog( DialogBox( PluginInstance->DllBase, MAKEINTRESOURCE(IDD_CUSTOMIZE_TB), - PhMainWindowHandle, + PhMainWndHandle, CustomizeToolbarDialogProc ); } \ No newline at end of file diff --git a/plugins/ToolStatus/graph.c b/plugins/ToolStatus/graph.c index 97a62b7b1ae2..c8effcd4396e 100644 --- a/plugins/ToolStatus/graph.c +++ b/plugins/ToolStatus/graph.c @@ -45,7 +45,7 @@ VOID ToolbarCreateGraphs(VOID) 0, 0, 0, - PhMainWindowHandle, + PhMainWndHandle, NULL, NULL, NULL @@ -65,7 +65,7 @@ VOID ToolbarCreateGraphs(VOID) 0, 0, 0, - PhMainWindowHandle, + PhMainWndHandle, NULL, NULL, NULL @@ -85,7 +85,7 @@ VOID ToolbarCreateGraphs(VOID) 0, 0, 0, - PhMainWindowHandle, + PhMainWndHandle, NULL, NULL, NULL @@ -105,7 +105,7 @@ VOID ToolbarCreateGraphs(VOID) 0, 0, 0, - PhMainWindowHandle, + PhMainWndHandle, NULL, NULL, NULL @@ -449,7 +449,7 @@ VOID ToolbarUpdateGraphsInfo(LPNMHDR Header) PhDivideSinglesBySingle( MemGraphState.Data1, - (FLOAT)PhGetSystemBasicInformation().NumberOfPhysicalPages, + (FLOAT)PhSystemBasicInformation.NumberOfPhysicalPages, drawInfo->LineDataCount ); @@ -617,7 +617,7 @@ VOID ToolbarUpdateGraphsInfo(LPNMHDR Header) if (record) { - PhShowProcessRecordDialog(PhMainWindowHandle, record); + PhShowProcessRecordDialog(PhMainWndHandle, record); PhDereferenceProcessRecord(record); } } @@ -651,7 +651,7 @@ VOID ToolbarUpdateGraphsInfo(LPNMHDR Header) if (record) { - PhShowProcessRecordDialog(PhMainWindowHandle, record); + PhShowProcessRecordDialog(PhMainWndHandle, record); PhDereferenceProcessRecord(record); } } diff --git a/plugins/ToolStatus/main.c b/plugins/ToolStatus/main.c index 29f4ad589e31..2c81fa57babb 100644 --- a/plugins/ToolStatus/main.c +++ b/plugins/ToolStatus/main.c @@ -252,7 +252,7 @@ VOID ShowCustomizeMenu( selectedItem = PhShowEMenu( menu, - PhMainWindowHandle, + PhMainWndHandle, PH_EMENU_SHOW_LEFTRIGHT, PH_ALIGN_LEFT | PH_ALIGN_TOP, cursorPos.x, @@ -271,12 +271,12 @@ VOID ShowCustomizeMenu( if (ToolStatusConfig.AutoHideMenu) { - SetMenu(PhMainWindowHandle, NULL); + SetMenu(PhMainWndHandle, NULL); } else { - SetMenu(PhMainWindowHandle, MainMenu); - DrawMenuBar(PhMainWindowHandle); + SetMenu(PhMainWndHandle, MainMenu); + DrawMenuBar(PhMainWndHandle); } } break; @@ -293,7 +293,7 @@ VOID ShowCustomizeMenu( { // Adding the Searchbox makes it focused, // reset the focus back to the main window. - SetFocus(PhMainWindowHandle); + SetFocus(PhMainWndHandle); } } break; @@ -452,8 +452,8 @@ VOID NTAPI LayoutPaddingCallback( SendMessage(RebarHandle, WM_SIZE, 0, 0); - // TODO: GetClientRect with PhMainWindowHandle causes crash. - //GetClientRect(PhMainWindowHandle, &clientRect); + // TODO: GetClientRect with PhMainWndHandle causes crash. + //GetClientRect(PhMainWndHandle, &clientRect); GetClientRect(RebarHandle, &rebarRect); // Adjust the PH client area and exclude the rebar width. @@ -556,22 +556,22 @@ BOOLEAN NTAPI MessageLoopFilter( ) { if ( - Message->hwnd == PhMainWindowHandle || - IsChild(PhMainWindowHandle, Message->hwnd) + Message->hwnd == PhMainWndHandle || + IsChild(PhMainWndHandle, Message->hwnd) ) { - if (TranslateAccelerator(PhMainWindowHandle, AcceleratorTable, Message)) + if (TranslateAccelerator(PhMainWndHandle, AcceleratorTable, Message)) return TRUE; - if (Message->message == WM_SYSCHAR && ToolStatusConfig.AutoHideMenu && !GetMenu(PhMainWindowHandle)) + if (Message->message == WM_SYSCHAR && ToolStatusConfig.AutoHideMenu && !GetMenu(PhMainWndHandle)) { ULONG key = (ULONG)Message->wParam; if (key == 'h' || key == 'v' || key == 't' || key == 'u' || key == 'e') { - SetMenu(PhMainWindowHandle, MainMenu); - DrawMenuBar(PhMainWindowHandle); - SendMessage(PhMainWindowHandle, WM_SYSCHAR, Message->wParam, Message->lParam); + SetMenu(PhMainWndHandle, MainMenu); + DrawMenuBar(PhMainWndHandle); + SendMessage(PhMainWndHandle, WM_SYSCHAR, Message->wParam, Message->lParam); return TRUE; } } @@ -774,7 +774,7 @@ LRESULT CALLBACK MainWndSubclassProc( case RBN_HEIGHTCHANGE: { // Invoke the LayoutPaddingCallback. - SendMessage(PhMainWindowHandle, WM_SIZE, 0, 0); + SendMessage(PhMainWndHandle, WM_SIZE, 0, 0); } break; case RBN_CHEVRONPUSHED: @@ -886,7 +886,7 @@ LRESULT CALLBACK MainWndSubclassProc( if (selectedItem && selectedItem->Id != -1) { - SendMessage(PhMainWindowHandle, WM_COMMAND, MAKEWPARAM(selectedItem->Id, BN_CLICKED), 0); + SendMessage(PhMainWndHandle, WM_COMMAND, MAKEWPARAM(selectedItem->Id, BN_CLICKED), 0); } PhDestroyEMenu(menu); @@ -997,7 +997,7 @@ LRESULT CALLBACK MainWndSubclassProc( if (selectedItem && selectedItem->Id != -1) { - SendMessage(PhMainWindowHandle, WM_COMMAND, MAKEWPARAM(selectedItem->Id, BN_CLICKED), 0); + SendMessage(PhMainWndHandle, WM_COMMAND, MAKEWPARAM(selectedItem->Id, BN_CLICKED), 0); } PhDestroyEMenu(menu); @@ -1123,7 +1123,7 @@ LRESULT CALLBACK MainWndSubclassProc( SetCursor(LoadCursor(NULL, IDC_ARROW)); // Bring the window back to the top, and preserve the Always on Top setting. - SetWindowPos(PhMainWindowHandle, PhGetIntegerSetting(L"MainWindowAlwaysOnTop") ? HWND_TOPMOST : HWND_TOP, + SetWindowPos(PhMainWndHandle, PhGetIntegerSetting(L"MainWindowAlwaysOnTop") ? HWND_TOPMOST : HWND_TOP, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE); TargetingWindow = FALSE; @@ -1236,7 +1236,7 @@ LRESULT CALLBACK MainWndSubclassProc( } } - SetWindowPos(PhMainWindowHandle, PhGetIntegerSetting(L"MainWindowAlwaysOnTop") ? HWND_TOPMOST : HWND_TOP, + SetWindowPos(PhMainWndHandle, PhGetIntegerSetting(L"MainWindowAlwaysOnTop") ? HWND_TOPMOST : HWND_TOP, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE); TargetingCompleted = TRUE; @@ -1263,14 +1263,14 @@ LRESULT CALLBACK MainWndSubclassProc( if (!ToolStatusConfig.AutoHideMenu) break; - if (GetMenu(PhMainWindowHandle)) + if (GetMenu(PhMainWndHandle)) { - SetMenu(PhMainWindowHandle, NULL); + SetMenu(PhMainWndHandle, NULL); } else { - SetMenu(PhMainWindowHandle, MainMenu); - DrawMenuBar(PhMainWindowHandle); + SetMenu(PhMainWndHandle, MainMenu); + DrawMenuBar(PhMainWndHandle); } } else if ((wParam & 0xFFF0) == SC_MINIMIZE) @@ -1288,9 +1288,9 @@ LRESULT CALLBACK MainWndSubclassProc( if (!ToolStatusConfig.AutoHideMenu) break; - if (GetMenu(PhMainWindowHandle)) + if (GetMenu(PhMainWndHandle)) { - SetMenu(PhMainWindowHandle, NULL); + SetMenu(PhMainWndHandle, NULL); } } break; @@ -1309,21 +1309,21 @@ VOID NTAPI MainWindowShowingCallback( { PhRegisterMessageLoopFilter(MessageLoopFilter, NULL); PhRegisterCallback( - ProcessHacker_GetCallbackLayoutPadding(PhMainWindowHandle), + ProcessHacker_GetCallbackLayoutPadding(PhMainWndHandle), LayoutPaddingCallback, NULL, &LayoutPaddingCallbackRegistration ); - SetWindowSubclass(PhMainWindowHandle, MainWndSubclassProc, 0, 0); + SetWindowSubclass(PhMainWndHandle, MainWndSubclassProc, 0, 0); ToolbarLoadSettings(); ReBarLoadLayoutSettings(); StatusBarLoadSettings(); - MainMenu = GetMenu(PhMainWindowHandle); + MainMenu = GetMenu(PhMainWndHandle); if (ToolStatusConfig.AutoHideMenu) { - SetMenu(PhMainWindowHandle, NULL); + SetMenu(PhMainWndHandle, NULL); } } diff --git a/plugins/ToolStatus/options.c b/plugins/ToolStatus/options.c index fed1a0811a97..f46e5b5564ac 100644 --- a/plugins/ToolStatus/options.c +++ b/plugins/ToolStatus/options.c @@ -66,12 +66,12 @@ INT_PTR CALLBACK OptionsDlgProc( if (ToolStatusConfig.AutoHideMenu) { - SetMenu(PhMainWindowHandle, NULL); + SetMenu(PhMainWndHandle, NULL); } else { - SetMenu(PhMainWindowHandle, MainMenu); - DrawMenuBar(PhMainWindowHandle); + SetMenu(PhMainWndHandle, MainMenu); + DrawMenuBar(PhMainWndHandle); } EndDialog(hwndDlg, IDOK); diff --git a/plugins/ToolStatus/statusbar.c b/plugins/ToolStatus/statusbar.c index 550771c7c7a3..92a8515eb812 100644 --- a/plugins/ToolStatus/statusbar.c +++ b/plugins/ToolStatus/statusbar.c @@ -229,7 +229,7 @@ VOID StatusBarShowMenu( selectedItem = PhShowEMenu( menu, - PhMainWindowHandle, + PhMainWndHandle, PH_EMENU_SHOW_LEFTRIGHT, PH_ALIGN_LEFT | PH_ALIGN_BOTTOM, cursorPos.x, @@ -324,8 +324,8 @@ VOID StatusBarUpdate( break; case ID_STATUS_PHYSICALMEMORY: { - ULONG physicalUsage = PhGetSystemBasicInformation().NumberOfPhysicalPages - SystemStatistics.Performance->AvailablePages; - FLOAT physicalFraction = (FLOAT)physicalUsage / PhGetSystemBasicInformation().NumberOfPhysicalPages * 100; + ULONG physicalUsage = PhSystemBasicInformation.NumberOfPhysicalPages - SystemStatistics.Performance->AvailablePages; + FLOAT physicalFraction = (FLOAT)physicalUsage / PhSystemBasicInformation.NumberOfPhysicalPages * 100; text[count] = PhFormatString( L"Physical memory: %s (%.2f%%)", @@ -337,7 +337,7 @@ VOID StatusBarUpdate( case ID_STATUS_FREEMEMORY: { ULONG physicalFree = SystemStatistics.Performance->AvailablePages; - FLOAT physicalFreeFraction = (FLOAT)physicalFree / PhGetSystemBasicInformation().NumberOfPhysicalPages * 100; + FLOAT physicalFreeFraction = (FLOAT)physicalFree / PhSystemBasicInformation.NumberOfPhysicalPages * 100; text[count] = PhFormatString( L"Free memory: %s (%.2f%%)", diff --git a/plugins/ToolStatus/toolbar.c b/plugins/ToolStatus/toolbar.c index 6393b2771090..c7b752460c7b 100644 --- a/plugins/ToolStatus/toolbar.c +++ b/plugins/ToolStatus/toolbar.c @@ -127,7 +127,7 @@ VOID RebarLoadSettings( NULL, WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | CCS_NODIVIDER | CCS_TOP | RBS_VARHEIGHT | RBS_AUTOSIZE, // CCS_NOPARENTALIGN | RBS_FIXEDORDER CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, - PhMainWindowHandle, + PhMainWndHandle, NULL, NULL, NULL @@ -188,7 +188,7 @@ VOID RebarLoadSettings( NULL, WS_CHILD | WS_VISIBLE | CCS_BOTTOM | SBARS_SIZEGRIP, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, - PhMainWindowHandle, + PhMainWndHandle, NULL, NULL, NULL @@ -374,7 +374,7 @@ VOID ToolbarLoadSettings( } // Invoke the LayoutPaddingCallback. - SendMessage(PhMainWindowHandle, WM_SIZE, 0, 0); + SendMessage(PhMainWndHandle, WM_SIZE, 0, 0); } VOID ToolbarResetSettings( diff --git a/plugins/Updater/options.c b/plugins/Updater/options.c index 902ba775c308..77c0c978bda6 100644 --- a/plugins/Updater/options.c +++ b/plugins/Updater/options.c @@ -88,8 +88,8 @@ INT_PTR CALLBACK TextDlgProc( PhCenterWindow(hwndDlg, GetParent(hwndDlg)); - SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhImageBaseAddress, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); - SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhImageBaseAddress, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); + SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)UT_LOAD_SHARED_ICON_SMALL(MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); + SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)UT_LOAD_SHARED_ICON_LARGE(MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); PhInitializeLayoutManager(&LayoutManager, hwndDlg); PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDC_TEXT), NULL, PH_ANCHOR_ALL); diff --git a/plugins/Updater/page5.c b/plugins/Updater/page5.c index 07b6e873b18d..0b766debcfeb 100644 --- a/plugins/Updater/page5.c +++ b/plugins/Updater/page5.c @@ -71,16 +71,16 @@ HRESULT CALLBACK FinalTaskDialogCallbackProc( info.nShow = SW_SHOW; info.hwnd = hwndDlg; - ProcessHacker_PrepareForEarlyShutdown(PhMainWindowHandle); + ProcessHacker_PrepareForEarlyShutdown(PhMainWndHandle); if (ShellExecuteEx(&info)) { - ProcessHacker_Destroy(PhMainWindowHandle); + ProcessHacker_Destroy(PhMainWndHandle); } else { // Install failed, cancel the shutdown. - ProcessHacker_CancelEarlyShutdown(PhMainWindowHandle); + ProcessHacker_CancelEarlyShutdown(PhMainWndHandle); // Set button text for next action //Button_SetText(GetDlgItem(hwndDlg, IDOK), L"Retry"); @@ -144,7 +144,7 @@ VOID ShowLatestVersionDialog( config.lpCallbackData = (LONG_PTR)Context; // HACK - imageDosHeader = (PIMAGE_DOS_HEADER)PhImageBaseAddress; + imageDosHeader = (PIMAGE_DOS_HEADER)NtCurrentPeb()->ImageBaseAddress; imageNtHeader = (PIMAGE_NT_HEADERS)PTR_ADD_OFFSET(imageDosHeader, (ULONG)imageDosHeader->e_lfanew); RtlSecondsSince1970ToTime(imageNtHeader->FileHeader.TimeDateStamp, &time); PhLargeIntegerToLocalSystemTime(&systemTime, &time); diff --git a/plugins/Updater/updater.c b/plugins/Updater/updater.c index 328bd6f35862..6cc3cdc1facd 100644 --- a/plugins/Updater/updater.c +++ b/plugins/Updater/updater.c @@ -70,8 +70,8 @@ VOID TaskDialogCreateIcons( _In_ PPH_UPDATER_CONTEXT Context ) { - Context->IconSmallHandle = PH_LOAD_SHARED_ICON_SMALL(PhImageBaseAddress, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER)); - Context->IconLargeHandle = PH_LOAD_SHARED_ICON_LARGE(PhImageBaseAddress, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER)); + Context->IconSmallHandle = UT_LOAD_SHARED_ICON_SMALL(MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER)); + Context->IconLargeHandle = UT_LOAD_SHARED_ICON_LARGE(MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER)); SendMessage(Context->DialogHandle, WM_SETICON, ICON_SMALL, (LPARAM)Context->IconSmallHandle); SendMessage(Context->DialogHandle, WM_SETICON, ICON_BIG, (LPARAM)Context->IconLargeHandle); @@ -317,7 +317,7 @@ BOOLEAN QueryUpdateData( if (!(httpSessionHandle = WinHttpOpen( NULL, - PhWindowsVersion() >= WINDOWS_8_1 ? WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY : WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, + WindowsVersion >= WINDOWS_8_1 ? WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY : WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0 @@ -327,7 +327,7 @@ BOOLEAN QueryUpdateData( goto CleanupExit; } - if (PhWindowsVersion() >= WINDOWS_8_1) + if (WindowsVersion >= WINDOWS_8_1) { ULONG httpFlags = WINHTTP_DECOMPRESSION_FLAG_GZIP | WINHTTP_DECOMPRESSION_FLAG_DEFLATE; @@ -364,7 +364,7 @@ BOOLEAN QueryUpdateData( goto CleanupExit; } - if (PhWindowsVersion() >= WINDOWS_7) + if (WindowsVersion >= WINDOWS_7) { ULONG keepAlive = WINHTTP_DISABLE_KEEP_ALIVE; WinHttpSetOption(httpRequestHandle, WINHTTP_OPTION_DISABLE_FEATURE, &keepAlive, sizeof(ULONG)); @@ -760,7 +760,7 @@ NTSTATUS UpdateDownloadThread( // Open the HTTP session with the system proxy configuration if available if (!(httpSessionHandle = WinHttpOpen( PhGetString(userAgentString), - PhWindowsVersion() >= WINDOWS_8_1 ? WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY : WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, + WindowsVersion >= WINDOWS_8_1 ? WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY : WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0 @@ -770,7 +770,7 @@ NTSTATUS UpdateDownloadThread( goto CleanupExit; } - if (PhWindowsVersion() >= WINDOWS_8_1) + if (WindowsVersion >= WINDOWS_8_1) { ULONG httpFlags = WINHTTP_DECOMPRESSION_FLAG_GZIP | WINHTTP_DECOMPRESSION_FLAG_DEFLATE; WinHttpSetOption(httpSessionHandle, WINHTTP_OPTION_DECOMPRESSION, &httpFlags, sizeof(ULONG)); @@ -801,7 +801,7 @@ NTSTATUS UpdateDownloadThread( goto CleanupExit; } - if (PhWindowsVersion() >= WINDOWS_7) + if (WindowsVersion >= WINDOWS_7) { ULONG keepAlive = WINHTTP_DISABLE_KEEP_ALIVE; WinHttpSetOption(httpRequestHandle, WINHTTP_OPTION_DISABLE_FEATURE, &keepAlive, sizeof(ULONG)); @@ -1093,11 +1093,11 @@ LRESULT CALLBACK TaskDialogSubclassProc( // break; //case WM_NCACTIVATE: // { - // if (IsWindowVisible(PhMainWindowHandle) && !IsMinimized(PhMainWindowHandle)) + // if (IsWindowVisible(PhMainWndHandle) && !IsMinimized(PhMainWndHandle)) // { // if (!context->FixedWindowStyles) // { - // SetWindowLongPtr(hwndDlg, GWLP_HWNDPARENT, (LONG_PTR)PhMainWindowHandle); + // SetWindowLongPtr(hwndDlg, GWLP_HWNDPARENT, (LONG_PTR)PhMainWndHandle); // PhSetWindowExStyle(hwndDlg, WS_EX_APPWINDOW, WS_EX_APPWINDOW); // context->FixedWindowStyles = TRUE; // } @@ -1126,7 +1126,7 @@ HRESULT CALLBACK TaskDialogBootstrapCallback( UpdateDialogHandle = context->DialogHandle = hwndDlg; // Center the update window on PH if it's visible else we center on the desktop. - PhCenterWindow(hwndDlg, (IsWindowVisible(PhMainWindowHandle) && !IsMinimized(PhMainWindowHandle)) ? PhMainWindowHandle : NULL); + PhCenterWindow(hwndDlg, (IsWindowVisible(PhMainWndHandle) && !IsMinimized(PhMainWndHandle)) ? PhMainWndHandle : NULL); // Create the Taskdialog icons TaskDialogCreateIcons(context); @@ -1193,7 +1193,7 @@ VOID ShowUpdateDialog( { if (!(UpdateDialogThreadHandle = PhCreateThread(0, ShowUpdateDialogThread, Context))) { - PhShowStatus(PhMainWindowHandle, L"Unable to create the updater window.", 0, GetLastError()); + PhShowStatus(PhMainWndHandle, L"Unable to create the updater window.", 0, GetLastError()); return; } diff --git a/plugins/Updater/updater.h b/plugins/Updater/updater.h index 5afc567627b0..ab8b850a635c 100644 --- a/plugins/Updater/updater.h +++ b/plugins/Updater/updater.h @@ -55,6 +55,9 @@ ((ULONGLONG)(build) << 16) | \ ((ULONGLONG)(revision) << 0)) +#define UT_LOAD_SHARED_ICON_SMALL(Name) PhLoadIcon(PhLibImageBase, (Name), PH_LOAD_ICON_SHARED | PH_LOAD_ICON_SIZE_SMALL, 0, 0) +#define UT_LOAD_SHARED_ICON_LARGE(Name) PhLoadIcon(PhLibImageBase, (Name), PH_LOAD_ICON_SHARED | PH_LOAD_ICON_SIZE_LARGE, 0, 0) + #ifdef _DEBUG // Force update checks to succeed (most of the below flags require this to be defined). //#define FORCE_UPDATE_CHECK diff --git a/plugins/UserNotes/main.c b/plugins/UserNotes/main.c index 42026cb27874..88a55cfa438b 100644 --- a/plugins/UserNotes/main.c +++ b/plugins/UserNotes/main.c @@ -181,7 +181,7 @@ ULONG GetProcessAffinity( if (NT_SUCCESS(PhOpenProcess( &processHandle, - PhProcessQueryAccess(), + ProcessQueryAccess, ProcessId ))) { @@ -208,7 +208,7 @@ IO_PRIORITY_HINT GetProcessIoPriority( if (NT_SUCCESS(PhOpenProcess( &processHandle, - PhProcessQueryAccess(), + ProcessQueryAccess, ProcessId ))) { @@ -425,7 +425,7 @@ VOID NTAPI MenuItemCallback( if (!highlightPresent) { CHOOSECOLOR chooseColor = { sizeof(CHOOSECOLOR) }; - chooseColor.hwndOwner = PhMainWindowHandle; + chooseColor.hwndOwner = PhMainWndHandle; chooseColor.lpCustColors = ProcessCustomColors; chooseColor.lpfnHook = ColorDlgHookProc; chooseColor.Flags = CC_ANYCOLOR | CC_FULLOPEN | CC_SOLIDCOLOR | CC_ENABLEHOOK; @@ -624,7 +624,7 @@ VOID NTAPI MenuHookCallback( affinityMask = GetProcessAffinity(processItem->ProcessId); // Show the affinity dialog (with our values). - if (PhShowProcessAffinityDialog2(PhMainWindowHandle, affinityMask, &newAffinityMask)) + if (PhShowProcessAffinityDialog2(PhMainWndHandle, affinityMask, &newAffinityMask)) { PDB_OBJECT object; @@ -1432,14 +1432,13 @@ LOGICAL DllMain( NULL, &MiListSectionMenuInitializingCallbackRegistration ); - PhRegisterCallback( - PhGetGeneralCallback(GeneralCallbackProcessProviderModified), + PhRegisterCallback(&PhProcessModifiedEvent, ProcessModifiedCallback, NULL, &ProcessModifiedCallbackRegistration ); PhRegisterCallback( - PhGetGeneralCallback(GeneralCallbackProcessProviderUpdated), + &PhProcessesUpdatedEvent, ProcessesUpdatedCallback, NULL, &ProcessesUpdatedCallbackRegistration @@ -1882,7 +1881,7 @@ UINT_PTR CALLBACK ColorDlgHookProc( { case WM_INITDIALOG: { - PhCenterWindow(hwndDlg, PhMainWindowHandle); + PhCenterWindow(hwndDlg, PhMainWndHandle); EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); } diff --git a/plugins/WindowExplorer/WindowExplorer.vcxproj b/plugins/WindowExplorer/WindowExplorer.vcxproj index 955db20f5099..f61d6d998529 100644 --- a/plugins/WindowExplorer/WindowExplorer.vcxproj +++ b/plugins/WindowExplorer/WindowExplorer.vcxproj @@ -53,12 +53,12 @@ - ProcessHacker.exe;comctl32.dll;gdi32.dll;user32.dll;%(DelayLoadDLLs) + ProcessHacker.exe;comctl32.dll;%(DelayLoadDLLs) - ProcessHacker.exe;comctl32.dll;gdi32.dll;user32.dll;%(DelayLoadDLLs) + ProcessHacker.exe;comctl32.dll;%(DelayLoadDLLs) diff --git a/plugins/WindowExplorer/main.c b/plugins/WindowExplorer/main.c index 987bdd8e6833..c31834ae619d 100644 --- a/plugins/WindowExplorer/main.c +++ b/plugins/WindowExplorer/main.c @@ -231,7 +231,7 @@ LOGICAL DllMain( isClient = FALSE; - if (!GetModuleHandle(L"ProcessHacker.exe") || !WeGetProcedureAddress("PhGetImageBase")) + if (!GetModuleHandle(L"ProcessHacker.exe") || !WeGetProcedureAddress("PhLibImageBase")) { isClient = TRUE; } diff --git a/plugins/WindowExplorer/wndexp.h b/plugins/WindowExplorer/wndexp.h index 2f03023ad597..dba7a96bc9a2 100644 --- a/plugins/WindowExplorer/wndexp.h +++ b/plugins/WindowExplorer/wndexp.h @@ -116,8 +116,8 @@ VOID WeShowWindowProperties( // utils -#define WE_PhMainWndHandle (*(HWND *)WeGetProcedureAddress("PhGetMainWndHandle")) -#define WE_WindowsVersion (*(ULONG *)WeGetProcedureAddress("PhWindowsVersion")) +#define WE_PhMainWndHandle (*(HWND *)WeGetProcedureAddress("PhMainWndHandle")) +#define WE_WindowsVersion (*(ULONG *)WeGetProcedureAddress("WindowsVersion")) PVOID WeGetProcedureAddress( _In_ PSTR Name diff --git a/plugins/WindowExplorer/wndprp.c b/plugins/WindowExplorer/wndprp.c index 7ed88dbf2a40..515b17ee9c40 100644 --- a/plugins/WindowExplorer/wndprp.c +++ b/plugins/WindowExplorer/wndprp.c @@ -611,7 +611,7 @@ static VOID WepEnsureHookDataValid( #ifdef _WIN64 // We can't use the hook on WOW64 processes. - if (NT_SUCCESS(PhOpenProcess(&processHandle, *(PULONG)WeGetProcedureAddress("PhProcessQueryAccess"), Context->ClientId.UniqueProcess))) + if (NT_SUCCESS(PhOpenProcess(&processHandle, *(PULONG)WeGetProcedureAddress("ProcessQueryAccess"), Context->ClientId.UniqueProcess))) { PhGetProcessIsWow64(processHandle, &isWow64); NtClose(processHandle); diff --git a/tools/peview/peview.vcxproj b/tools/peview/peview.vcxproj index ba8868d0c4f1..a5a6ae577e12 100644 --- a/tools/peview/peview.vcxproj +++ b/tools/peview/peview.vcxproj @@ -96,15 +96,14 @@ true - delaylib.lib;noarg.obj;noenv.obj;phlib.lib;ntdll.lib;uxtheme.lib;windowscodecs.lib;%(AdditionalDependencies) - ..\..\phlib\bin\$(Configuration)$(PlatformArchitecture);..\..\tools\delaylib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) + noarg.obj;noenv.obj;phlib.lib;ntdll.lib;uxtheme.lib;windowscodecs.lib;%(AdditionalDependencies) + ..\..\phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) true Windows MachineX86 6.01 - ___delayLoadHelper2@8 ..\..\phnt\include;..\..\phlib\include;include;%(AdditionalIncludeDirectories) @@ -126,15 +125,14 @@ true - delaylib.lib;noarg.obj;noenv.obj;phlib.lib;ntdll.lib;uxtheme.lib;windowscodecs.lib;%(AdditionalDependencies) - ..\..\phlib\bin\$(Configuration)$(PlatformArchitecture);..\..\tools\delaylib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) + noarg.obj;noenv.obj;phlib.lib;ntdll.lib;uxtheme.lib;windowscodecs.lib;%(AdditionalDependencies) + ..\..\phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) true Windows MachineX64 6.01 - __delayLoadHelper2 ..\..\phnt\include;..\..\phlib\include;include;%(AdditionalIncludeDirectories) @@ -159,8 +157,8 @@ true - delaylib.lib;noarg.obj;noenv.obj;phlib.lib;ntdll.lib;uxtheme.lib;windowscodecs.lib;%(AdditionalDependencies) - ..\..\phlib\bin\$(Configuration)$(PlatformArchitecture);..\..\tools\delaylib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) + noarg.obj;noenv.obj;phlib.lib;ntdll.lib;uxtheme.lib;windowscodecs.lib;%(AdditionalDependencies) + ..\..\phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) true @@ -170,7 +168,6 @@ MachineX86 true 6.01 - ___delayLoadHelper2@8 ..\..\phnt\include;..\..\phlib\include;include;%(AdditionalIncludeDirectories) @@ -194,8 +191,8 @@ true - delaylib.lib;noarg.obj;noenv.obj;phlib.lib;ntdll.lib;uxtheme.lib;windowscodecs.lib;%(AdditionalDependencies) - ..\..\phlib\bin\$(Configuration)$(PlatformArchitecture);..\..\tools\delaylib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) + noarg.obj;noenv.obj;phlib.lib;ntdll.lib;uxtheme.lib;windowscodecs.lib;%(AdditionalDependencies) + ..\..\phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) true @@ -205,7 +202,6 @@ MachineX64 true 6.01 - __delayLoadHelper2 ..\..\phnt\include;..\..\phlib\include;include;%(AdditionalIncludeDirectories) From 6baf027f476d46c227f15d7ea4a6f66e38184828 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 22 May 2017 21:08:35 +1000 Subject: [PATCH 0146/2058] Add missing symbolic access_mask PROCESS_SET_LIMITED_INFORMATION --- phlib/secdata.c | 1 + 1 file changed, 1 insertion(+) diff --git a/phlib/secdata.c b/phlib/secdata.c index fe08d207ac82..d87f74df6a5e 100644 --- a/phlib/secdata.c +++ b/phlib/secdata.c @@ -256,6 +256,7 @@ ACCESS_ENTRIES(Process60) { L"Query limited information", PROCESS_QUERY_LIMITED_INFORMATION, TRUE, TRUE }, { L"Query information", PROCESS_QUERY_INFORMATION | PROCESS_QUERY_LIMITED_INFORMATION, TRUE, TRUE }, { L"Set information", PROCESS_SET_INFORMATION, TRUE, TRUE }, + { L"Set limited information", PROCESS_SET_LIMITED_INFORMATION, TRUE, TRUE }, { L"Set quotas", PROCESS_SET_QUOTA, TRUE, TRUE }, { L"Set session ID", PROCESS_SET_SESSIONID, TRUE, TRUE }, { L"Create threads", PROCESS_CREATE_THREAD, TRUE, TRUE }, From a7aa27ffb6f00b4b96558efa4432ac80a22884e0 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 22 May 2017 21:58:30 +1000 Subject: [PATCH 0147/2058] BuildTools: Fix changelog string format --- tools/CustomBuildTool/Source Files/Build.cs | 2 +- .../bin/Release/CustomBuildTool.exe | Bin 160768 -> 160768 bytes .../bin/Release/CustomBuildTool.pdb | Bin 69120 -> 69120 bytes 3 files changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/CustomBuildTool/Source Files/Build.cs b/tools/CustomBuildTool/Source Files/Build.cs index 2031e4364c1a..3cf61d381a22 100644 --- a/tools/CustomBuildTool/Source Files/Build.cs +++ b/tools/CustomBuildTool/Source Files/Build.cs @@ -894,7 +894,7 @@ public static void WebServiceUpdateConfig() if (string.IsNullOrEmpty(BuildSetupSig)) return; - string buildChangelog = Win32.ShellExecute(GitExePath, "log -n 30 --pretty=format:\"%h %an %s (%cr)\""); + string buildChangelog = Win32.ShellExecute(GitExePath, "log -n 30 --date=format:%Y-%m-%d --pretty=format:\"[%cd] %an %s\""); string buildSummary = Win32.ShellExecute(GitExePath, "log -n 5 --date=format:%Y-%m-%d --pretty=format:\"[%cd] %an %s\" --abbrev-commit"); string buildPostString = Json.Serialize(new BuildUpdateRequest { diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe b/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe index 4f1449cb3744c750cdcb24fc9aa41e20f818a47e..ef4b4940de3aa5582192417cf4abdbb58da3875c 100644 GIT binary patch delta 3979 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 Js|@24UH~2Fb@KoK delta 442 zcmZpe!_qK^WdjSB1V680BqIX@gXi;aMYdr}JXV-aDwyQ9!fUe(myUo);LWFvw~p+~ z72jI-^7Tjgw5lV^R5v=VVO-21!^XjR|8dKciet50p!T3ZToe8Za=Z;*iq<$^j7=pz32_hyqGDLFHIC Z&;4r1%5+nA^Mzj~tT>}&s|@24UI62eimU(t From b02f88961887ee086feeec361eda558c82e0796f Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 22 May 2017 22:02:51 +1000 Subject: [PATCH 0148/2058] Fix remaining window icons --- ProcessHacker/include/appsup.h | 4 +-- ProcessHacker/mainwnd.c | 4 +-- ProcessHacker/memedit.c | 3 ++ ProcessHacker/miniinfo.c | 8 +++--- ProcessHacker/procrec.c | 2 +- ProcessHacker/prpgenv.c | 8 +++--- ProcessHacker/prpggen.c | 4 +-- ProcessHacker/prpgthrd.c | 2 +- ProcessHacker/srvlist.c | 8 +++--- ProcessHacker/sysinfo.c | 4 +-- ProcessHacker/thrdstk.c | 3 ++ plugins/ExtendedTools/etwprprp.c | 6 ++-- plugins/ExtendedTools/exttools.h | 4 --- plugins/ExtendedTools/gpunodes.c | 4 +-- plugins/ExtendedTools/gpuprprp.c | 6 ++-- plugins/ExtendedTools/unldll.c | 4 +-- plugins/ExtraPlugins/setup/updater.c | 18 ++---------- plugins/NetworkTools/ping.c | 3 ++ plugins/NetworkTools/tracert.c | 3 ++ plugins/NetworkTools/update.c | 43 ++++++---------------------- plugins/NetworkTools/whois.c | 3 ++ plugins/OnlineChecks/main.c | 2 +- plugins/OnlineChecks/upload.c | 28 ++---------------- plugins/Updater/options.c | 6 ++-- plugins/Updater/updater.c | 4 +-- plugins/Updater/updater.h | 3 -- 26 files changed, 66 insertions(+), 121 deletions(-) diff --git a/ProcessHacker/include/appsup.h b/ProcessHacker/include/appsup.h index fe34c8977206..275273f6d4e8 100644 --- a/ProcessHacker/include/appsup.h +++ b/ProcessHacker/include/appsup.h @@ -416,8 +416,8 @@ PPH_STRING PhPcre2GetErrorMessage( _In_ INT ErrorCode ); -#define PH_LOAD_SHARED_ICON_SMALL(Name) PhLoadIcon(PhInstanceHandle, (Name), PH_LOAD_ICON_SHARED | PH_LOAD_ICON_SIZE_SMALL, 0, 0) -#define PH_LOAD_SHARED_ICON_LARGE(Name) PhLoadIcon(PhInstanceHandle, (Name), PH_LOAD_ICON_SHARED | PH_LOAD_ICON_SIZE_LARGE, 0, 0) +#define PH_LOAD_SHARED_ICON_SMALL(BaseAddress, Name) PhLoadIcon(BaseAddress, (Name), PH_LOAD_ICON_SHARED | PH_LOAD_ICON_SIZE_SMALL, 0, 0) // phapppub +#define PH_LOAD_SHARED_ICON_LARGE(BaseAddress, Name) PhLoadIcon(BaseAddress, (Name), PH_LOAD_ICON_SHARED | PH_LOAD_ICON_SIZE_LARGE, 0, 0) // phapppub FORCEINLINE PVOID PhpGenericPropertyPageHeader( _In_ HWND hwndDlg, diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index 3d4c8539dd18..26533a980e4c 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -342,12 +342,12 @@ BOOLEAN PhMwpInitializeWindowClass( wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = PhInstanceHandle; - wcex.hIcon = PH_LOAD_SHARED_ICON_LARGE(MAKEINTRESOURCE(IDI_PROCESSHACKER)); + wcex.hIcon = PH_LOAD_SHARED_ICON_LARGE(PhLibImageBase, MAKEINTRESOURCE(IDI_PROCESSHACKER)); wcex.hCursor = LoadCursor(NULL, IDC_ARROW); //wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); wcex.lpszMenuName = MAKEINTRESOURCE(IDR_MAINWND); wcex.lpszClassName = PH_MAINWND_CLASSNAME; - wcex.hIconSm = PH_LOAD_SHARED_ICON_SMALL(MAKEINTRESOURCE(IDI_PROCESSHACKER)); + wcex.hIconSm = PH_LOAD_SHARED_ICON_SMALL(PhLibImageBase, MAKEINTRESOURCE(IDI_PROCESSHACKER)); if (!RegisterClassEx(&wcex)) return FALSE; diff --git a/ProcessHacker/memedit.c b/ProcessHacker/memedit.c index 4cf0897ad7e9..1dfbef18a22c 100644 --- a/ProcessHacker/memedit.c +++ b/ProcessHacker/memedit.c @@ -185,6 +185,9 @@ INT_PTR CALLBACK PhpMemoryEditorDlgProc( { NTSTATUS status; + SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhLibImageBase, MAKEINTRESOURCE(IDI_PROCESSHACKER))); + SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhLibImageBase, MAKEINTRESOURCE(IDI_PROCESSHACKER))); + if (context->Title) { SetWindowText(hwndDlg, context->Title->Buffer); diff --git a/ProcessHacker/miniinfo.c b/ProcessHacker/miniinfo.c index 01d139a083e8..64bf00ebfe15 100644 --- a/ProcessHacker/miniinfo.c +++ b/ProcessHacker/miniinfo.c @@ -110,11 +110,11 @@ VOID PhPinMiniInformation( wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = PhInstanceHandle; - wcex.hIcon = PH_LOAD_SHARED_ICON_LARGE(MAKEINTRESOURCE(IDI_PROCESSHACKER)); + wcex.hIcon = PH_LOAD_SHARED_ICON_LARGE(PhLibImageBase, MAKEINTRESOURCE(IDI_PROCESSHACKER)); wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1); wcex.lpszClassName = MIP_CONTAINER_CLASSNAME; - wcex.hIconSm = PH_LOAD_SHARED_ICON_SMALL(MAKEINTRESOURCE(IDI_PROCESSHACKER)); + wcex.hIconSm = PH_LOAD_SHARED_ICON_SMALL(PhLibImageBase, MAKEINTRESOURCE(IDI_PROCESSHACKER)); RegisterClassEx(&wcex); PhMipContainerWindow = CreateWindow( @@ -448,10 +448,10 @@ VOID PhMipOnInitDialog( HICON cog; HICON pin; - cog = PH_LOAD_SHARED_ICON_SMALL(MAKEINTRESOURCE(IDI_COG)); + cog = PH_LOAD_SHARED_ICON_SMALL(PhLibImageBase, MAKEINTRESOURCE(IDI_COG)); SET_BUTTON_ICON(PhMipWindow, IDC_OPTIONS, cog); - pin = PH_LOAD_SHARED_ICON_SMALL(MAKEINTRESOURCE(IDI_PIN)); + pin = PH_LOAD_SHARED_ICON_SMALL(PhLibImageBase, MAKEINTRESOURCE(IDI_PIN)); SET_BUTTON_ICON(PhMipWindow, IDC_PIN, pin); PhInitializeLayoutManager(&PhMipLayoutManager, PhMipWindow); diff --git a/ProcessHacker/procrec.c b/ProcessHacker/procrec.c index 486a3db8841c..dbcb2c98019a 100644 --- a/ProcessHacker/procrec.c +++ b/ProcessHacker/procrec.c @@ -186,7 +186,7 @@ INT_PTR CALLBACK PhpProcessRecordDlgProc( context->FileIcon = PhGetFileShellIcon(PhGetString(context->Record->FileName), L".exe", TRUE); SendMessage(GetDlgItem(hwndDlg, IDC_OPENFILENAME), BM_SETIMAGE, IMAGE_ICON, - (LPARAM)PH_LOAD_SHARED_ICON_SMALL(MAKEINTRESOURCE(IDI_FOLDER))); + (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhLibImageBase, MAKEINTRESOURCE(IDI_FOLDER))); SendMessage(GetDlgItem(hwndDlg, IDC_FILEICON), STM_SETICON, (WPARAM)context->FileIcon, 0); diff --git a/ProcessHacker/prpgenv.c b/ProcessHacker/prpgenv.c index 2f8f181b94a0..e819a260440c 100644 --- a/ProcessHacker/prpgenv.c +++ b/ProcessHacker/prpgenv.c @@ -454,6 +454,9 @@ INT_PTR CALLBACK PhpEditEnvDlgProc( { case WM_INITDIALOG: { + SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhLibImageBase, MAKEINTRESOURCE(IDI_PROCESSHACKER))); + SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhLibImageBase, MAKEINTRESOURCE(IDI_PROCESSHACKER))); + PhCenterWindow(hwndDlg, GetParent(hwndDlg)); PhInitializeLayoutManager(&context->LayoutManager, hwndDlg); @@ -476,10 +479,7 @@ INT_PTR CALLBACK PhpEditEnvDlgProc( SetDlgItemText(hwndDlg, IDC_NAME, context->Name); SetDlgItemText(hwndDlg, IDC_VALUE, context->Value ? context->Value : L""); - if (context->Value) - { - SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hwndDlg, IDC_VALUE), TRUE); - } + SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hwndDlg, IDCANCEL), TRUE); } break; case WM_DESTROY: diff --git a/ProcessHacker/prpggen.c b/ProcessHacker/prpggen.c index 30b2115d2695..76318e4492e0 100644 --- a/ProcessHacker/prpggen.c +++ b/ProcessHacker/prpggen.c @@ -147,8 +147,8 @@ INT_PTR CALLBACK PhpProcessGeneralDlgProc( HICON folder; HICON magnifier; - folder = PH_LOAD_SHARED_ICON_SMALL(MAKEINTRESOURCE(IDI_FOLDER)); - magnifier = PH_LOAD_SHARED_ICON_SMALL(MAKEINTRESOURCE(IDI_MAGNIFIER)); + folder = PH_LOAD_SHARED_ICON_SMALL(PhLibImageBase, MAKEINTRESOURCE(IDI_FOLDER)); + magnifier = PH_LOAD_SHARED_ICON_SMALL(PhLibImageBase, MAKEINTRESOURCE(IDI_MAGNIFIER)); SET_BUTTON_ICON(IDC_INSPECT, magnifier); SET_BUTTON_ICON(IDC_OPENFILENAME, folder); diff --git a/ProcessHacker/prpgthrd.c b/ProcessHacker/prpgthrd.c index 53e2cf7797e5..cf23dd2cccc2 100644 --- a/ProcessHacker/prpgthrd.c +++ b/ProcessHacker/prpgthrd.c @@ -639,7 +639,7 @@ INT_PTR CALLBACK PhpProcessThreadsDlgProc( PhThreadProviderInitialUpdate(threadsContext->Provider); PhRegisterThreadProvider(threadsContext->Provider, &threadsContext->ProviderRegistration); - SET_BUTTON_ICON(IDC_OPENSTARTMODULE, PH_LOAD_SHARED_ICON_SMALL(MAKEINTRESOURCE(IDI_FOLDER))); + SET_BUTTON_ICON(IDC_OPENSTARTMODULE, PH_LOAD_SHARED_ICON_SMALL(PhLibImageBase, MAKEINTRESOURCE(IDI_FOLDER))); } break; case WM_DESTROY: diff --git a/ProcessHacker/srvlist.c b/ProcessHacker/srvlist.c index 003e86f51e31..1e2eaeb655df 100644 --- a/ProcessHacker/srvlist.c +++ b/ProcessHacker/srvlist.c @@ -689,10 +689,10 @@ BOOLEAN NTAPI PhpServiceTreeNewCallback( if (!ServiceIconsLoaded) { - ServiceApplicationIcon = PH_LOAD_SHARED_ICON_SMALL(MAKEINTRESOURCE(IDI_PHAPPLICATION)); - ServiceApplicationGoIcon = PH_LOAD_SHARED_ICON_SMALL(MAKEINTRESOURCE(IDI_PHAPPLICATIONGO)); - ServiceCogIcon = PH_LOAD_SHARED_ICON_SMALL(MAKEINTRESOURCE(IDI_COG)); - ServiceCogGoIcon = PH_LOAD_SHARED_ICON_SMALL(MAKEINTRESOURCE(IDI_COGGO)); + ServiceApplicationIcon = PH_LOAD_SHARED_ICON_SMALL(PhLibImageBase, MAKEINTRESOURCE(IDI_PHAPPLICATION)); + ServiceApplicationGoIcon = PH_LOAD_SHARED_ICON_SMALL(PhLibImageBase, MAKEINTRESOURCE(IDI_PHAPPLICATIONGO)); + ServiceCogIcon = PH_LOAD_SHARED_ICON_SMALL(PhLibImageBase, MAKEINTRESOURCE(IDI_COG)); + ServiceCogGoIcon = PH_LOAD_SHARED_ICON_SMALL(PhLibImageBase, MAKEINTRESOURCE(IDI_COGGO)); ServiceIconsLoaded = TRUE; } diff --git a/ProcessHacker/sysinfo.c b/ProcessHacker/sysinfo.c index 5dcbb236ea54..889066c520c7 100644 --- a/ProcessHacker/sysinfo.c +++ b/ProcessHacker/sysinfo.c @@ -281,8 +281,8 @@ VOID PhSipOnInitDialog( VOID ) { - SendMessage(PhSipWindow, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(MAKEINTRESOURCE(IDI_PROCESSHACKER))); - SendMessage(PhSipWindow, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(MAKEINTRESOURCE(IDI_PROCESSHACKER))); + SendMessage(PhSipWindow, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhLibImageBase, MAKEINTRESOURCE(IDI_PROCESSHACKER))); + SendMessage(PhSipWindow, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhLibImageBase, MAKEINTRESOURCE(IDI_PROCESSHACKER))); PhInitializeLayoutManager(&WindowLayoutManager, PhSipWindow); diff --git a/ProcessHacker/thrdstk.c b/ProcessHacker/thrdstk.c index 5e7d9e053328..35ac287e38a5 100644 --- a/ProcessHacker/thrdstk.c +++ b/ProcessHacker/thrdstk.c @@ -169,6 +169,9 @@ static INT_PTR CALLBACK PhpThreadStackDlgProc( HWND lvHandle; PPH_LAYOUT_MANAGER layoutManager; + SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhLibImageBase, MAKEINTRESOURCE(IDI_PROCESSHACKER))); + SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhLibImageBase, MAKEINTRESOURCE(IDI_PROCESSHACKER))); + threadStackContext = (PTHREAD_STACK_CONTEXT)lParam; SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)threadStackContext); diff --git a/plugins/ExtendedTools/etwprprp.c b/plugins/ExtendedTools/etwprprp.c index 1e87ffbd4672..67e7ce1b0cd6 100644 --- a/plugins/ExtendedTools/etwprprp.c +++ b/plugins/ExtendedTools/etwprprp.c @@ -148,9 +148,9 @@ VOID EtwDiskNetworkLayoutGraphs( HDWP deferHandle; RECT clientRect; RECT panelRect; - RECT margin = { ET_SCALE_DPI(13), ET_SCALE_DPI(13), ET_SCALE_DPI(13), ET_SCALE_DPI(13) }; - RECT innerMargin = { ET_SCALE_DPI(10), ET_SCALE_DPI(20), ET_SCALE_DPI(10), ET_SCALE_DPI(10) }; - LONG between = ET_SCALE_DPI(3); + RECT margin = { PH_SCALE_DPI(13), PH_SCALE_DPI(13), PH_SCALE_DPI(13), PH_SCALE_DPI(13) }; + RECT innerMargin = { PH_SCALE_DPI(10), PH_SCALE_DPI(20), PH_SCALE_DPI(10), PH_SCALE_DPI(10) }; + LONG between = PH_SCALE_DPI(3); ULONG graphWidth; ULONG graphHeight; diff --git a/plugins/ExtendedTools/exttools.h b/plugins/ExtendedTools/exttools.h index 967f6d30f356..c5201b3fabc5 100644 --- a/plugins/ExtendedTools/exttools.h +++ b/plugins/ExtendedTools/exttools.h @@ -27,10 +27,6 @@ extern HWND NetworkTreeNewHandle; #define SETTING_NAME_UNLOADED_WINDOW_SIZE (PLUGIN_NAME L".TracertWindowSize") #define SETTING_NAME_UNLOADED_COLUMNS (PLUGIN_NAME L".UnloadedListColumns") -#define ET_SCALE_DPI(Value) PhMultiplyDivide(Value, PhGlobalDpi, 96) -#define ET_LOAD_SHARED_ICON_SMALL(Name) PhLoadIcon(PhLibImageBase, (Name), PH_LOAD_ICON_SHARED | PH_LOAD_ICON_SIZE_SMALL, 0, 0) -#define ET_LOAD_SHARED_ICON_LARGE(Name) PhLoadIcon(PhLibImageBase, (Name), PH_LOAD_ICON_SHARED | PH_LOAD_ICON_SIZE_LARGE, 0, 0) - // Graph update message #define UPDATE_MSG (WM_APP + 1) diff --git a/plugins/ExtendedTools/gpunodes.c b/plugins/ExtendedTools/gpunodes.c index fe9467dda387..cc56abcd55b6 100644 --- a/plugins/ExtendedTools/gpunodes.c +++ b/plugins/ExtendedTools/gpunodes.c @@ -121,8 +121,8 @@ INT_PTR CALLBACK EtpGpuNodesDlgProc( WindowHandle = hwndDlg; - SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)ET_LOAD_SHARED_ICON_SMALL(MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); - SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)ET_LOAD_SHARED_ICON_LARGE(MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); + SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhLibImageBase, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); + SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhLibImageBase, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); PhInitializeLayoutManager(&LayoutManager, hwndDlg); PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDOK), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); diff --git a/plugins/ExtendedTools/gpuprprp.c b/plugins/ExtendedTools/gpuprprp.c index 882b3c453d75..fc9138bf0915 100644 --- a/plugins/ExtendedTools/gpuprprp.c +++ b/plugins/ExtendedTools/gpuprprp.c @@ -263,9 +263,9 @@ VOID GpuPropLayoutGraphs( HDWP deferHandle; RECT clientRect; RECT panelRect; - RECT margin = { ET_SCALE_DPI(13), ET_SCALE_DPI(13), ET_SCALE_DPI(13), ET_SCALE_DPI(13) }; - RECT innerMargin = { ET_SCALE_DPI(10), ET_SCALE_DPI(20), ET_SCALE_DPI(10), ET_SCALE_DPI(10) }; - LONG between = ET_SCALE_DPI(3); + RECT margin = { PH_SCALE_DPI(13), PH_SCALE_DPI(13), PH_SCALE_DPI(13), PH_SCALE_DPI(13) }; + RECT innerMargin = { PH_SCALE_DPI(10), PH_SCALE_DPI(20), PH_SCALE_DPI(10), PH_SCALE_DPI(10) }; + LONG between = PH_SCALE_DPI(3); ULONG graphWidth; ULONG graphHeight; diff --git a/plugins/ExtendedTools/unldll.c b/plugins/ExtendedTools/unldll.c index 54d9f4b8ae27..93325b16fbf3 100644 --- a/plugins/ExtendedTools/unldll.c +++ b/plugins/ExtendedTools/unldll.c @@ -305,8 +305,8 @@ INT_PTR CALLBACK EtpUnloadedDllsDlgProc( { HWND lvHandle; - SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)ET_LOAD_SHARED_ICON_SMALL(MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); - SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)ET_LOAD_SHARED_ICON_LARGE(MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); + SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhLibImageBase, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); + SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhLibImageBase, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); PhCenterWindow(hwndDlg, GetParent(hwndDlg)); diff --git a/plugins/ExtraPlugins/setup/updater.c b/plugins/ExtraPlugins/setup/updater.c index 77662132c054..0cc2c26e9d32 100644 --- a/plugins/ExtraPlugins/setup/updater.c +++ b/plugins/ExtraPlugins/setup/updater.c @@ -60,22 +60,8 @@ VOID TaskDialogCreateIcons( ) { // Load the Process Hacker window icon - Context->IconLargeHandle = (HICON)LoadImage( - NtCurrentPeb()->ImageBaseAddress, - MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER), - IMAGE_ICON, - GetSystemMetrics(SM_CXICON), - GetSystemMetrics(SM_CYICON), - LR_SHARED - ); - Context->IconSmallHandle = (HICON)LoadImage( - NtCurrentPeb()->ImageBaseAddress, - MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER), - IMAGE_ICON, - GetSystemMetrics(SM_CXSMICON), - GetSystemMetrics(SM_CYSMICON), - LR_SHARED - ); + Context->IconLargeHandle = PH_LOAD_SHARED_ICON_SMALL(PhLibImageBase, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER)); + Context->IconSmallHandle = PH_LOAD_SHARED_ICON_LARGE(PhLibImageBase, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER)); // Set the TaskDialog window icons SendMessage(Context->DialogHandle, WM_SETICON, ICON_SMALL, (LPARAM)Context->IconSmallHandle); diff --git a/plugins/NetworkTools/ping.c b/plugins/NetworkTools/ping.c index 0ccb364a7005..cb6165e4e30d 100644 --- a/plugins/NetworkTools/ping.c +++ b/plugins/NetworkTools/ping.c @@ -285,6 +285,9 @@ INT_PTR CALLBACK NetworkPingWndProc( { PPH_LAYOUT_ITEM panelItem; + SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhLibImageBase, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); + SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhLibImageBase, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); + // We have already set the group boxes to have WS_EX_TRANSPARENT to fix // the drawing issue that arises when using WS_CLIPCHILDREN. However // in removing the flicker from the graphs the group boxes will now flicker. diff --git a/plugins/NetworkTools/tracert.c b/plugins/NetworkTools/tracert.c index 41550a1f123b..f5fc427381e8 100644 --- a/plugins/NetworkTools/tracert.c +++ b/plugins/NetworkTools/tracert.c @@ -568,6 +568,9 @@ INT_PTR CALLBACK TracertDlgProc( { HANDLE tracertThread; + SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhLibImageBase, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); + SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhLibImageBase, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); + PhCenterWindow(hwndDlg, PhMainWndHandle); Static_SetText(hwndDlg, diff --git a/plugins/NetworkTools/update.c b/plugins/NetworkTools/update.c index 988029df021f..579feb6015cc 100644 --- a/plugins/NetworkTools/update.c +++ b/plugins/NetworkTools/update.c @@ -35,21 +35,14 @@ VOID FreeUpdateContext( ) { //PhClearReference(&Context->Version); - // PhClearReference(&Context->RevVersion); + //PhClearReference(&Context->RevVersion); //PhClearReference(&Context->RelDate); - // PhClearReference(&Context->Size); + //PhClearReference(&Context->Size); //PhClearReference(&Context->Hash); - // PhClearReference(&Context->Signature); - // PhClearReference(&Context->ReleaseNotesUrl); + //PhClearReference(&Context->Signature); + //PhClearReference(&Context->ReleaseNotesUrl); //PhClearReference(&Context->SetupFilePath); - // PhClearReference(&Context->SetupFileDownloadUrl); - - if (Context->IconLargeHandle) - DestroyIcon(Context->IconLargeHandle); - - if (Context->IconSmallHandle) - DestroyIcon(Context->IconSmallHandle); - + //PhClearReference(&Context->SetupFileDownloadUrl); //PhClearReference(&Context); } @@ -57,29 +50,11 @@ VOID TaskDialogCreateIcons( _In_ PPH_UPDATER_CONTEXT Context ) { - HICON largeIcon; - HICON smallIcon; - - largeIcon = PhLoadIcon( - NtCurrentPeb()->ImageBaseAddress, - MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER), - PH_LOAD_ICON_SIZE_LARGE, - GetSystemMetrics(SM_CXICON), - GetSystemMetrics(SM_CYICON) - ); - smallIcon = PhLoadIcon( - NtCurrentPeb()->ImageBaseAddress, - MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER), - PH_LOAD_ICON_SIZE_LARGE, - GetSystemMetrics(SM_CXSMICON), - GetSystemMetrics(SM_CYSMICON) - ); - - Context->IconLargeHandle = largeIcon; - Context->IconSmallHandle = smallIcon; + Context->IconSmallHandle = PH_LOAD_SHARED_ICON_SMALL(PhLibImageBase, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER)); + Context->IconLargeHandle = PH_LOAD_SHARED_ICON_LARGE(PhLibImageBase, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER)); - SendMessage(Context->DialogHandle, WM_SETICON, ICON_SMALL, (LPARAM)largeIcon); - SendMessage(Context->DialogHandle, WM_SETICON, ICON_BIG, (LPARAM)smallIcon); + SendMessage(Context->DialogHandle, WM_SETICON, ICON_SMALL, (LPARAM)Context->IconSmallHandle); + SendMessage(Context->DialogHandle, WM_SETICON, ICON_BIG, (LPARAM)Context->IconLargeHandle); } VOID TaskDialogLinkClicked( diff --git a/plugins/NetworkTools/whois.c b/plugins/NetworkTools/whois.c index bf6e602d0270..5be18698f44d 100644 --- a/plugins/NetworkTools/whois.c +++ b/plugins/NetworkTools/whois.c @@ -396,6 +396,9 @@ INT_PTR CALLBACK NetworkOutputDlgProc( { HANDLE dialogThread; + SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhLibImageBase, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); + SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhLibImageBase, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); + SetWindowText(hwndDlg, PhaFormatString(L"Whois %s...", context->IpAddressString)->Buffer); context->WindowHandle = hwndDlg; diff --git a/plugins/OnlineChecks/main.c b/plugins/OnlineChecks/main.c index 35ef25384a98..fda5277f68f6 100644 --- a/plugins/OnlineChecks/main.c +++ b/plugins/OnlineChecks/main.c @@ -179,7 +179,7 @@ VOID NTAPI MenuItemCallback( config.dwCommonButtons = TDCBF_YES_BUTTON | TDCBF_NO_BUTTON; config.hwndParent = menuItem->OwnerWindow; config.hMainIcon = PhLoadIcon( - NtCurrentPeb()->ImageBaseAddress, + PhLibImageBase, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER), PH_LOAD_ICON_SIZE_LARGE, GetSystemMetrics(SM_CXICON), diff --git a/plugins/OnlineChecks/upload.c b/plugins/OnlineChecks/upload.c index 803689827131..926bd6dc73ec 100644 --- a/plugins/OnlineChecks/upload.c +++ b/plugins/OnlineChecks/upload.c @@ -172,18 +172,6 @@ VOID UploadContextDeleteProcedure( context->HttpHandle = NULL; } - if (context->IconLargeHandle) - { - DestroyIcon(context->IconLargeHandle); - context->IconLargeHandle = NULL; - } - - if (context->IconSmallHandle) - { - DestroyIcon(context->IconSmallHandle); - context->IconSmallHandle = NULL; - } - PhClearReference(&context->ErrorString); PhClearReference(&context->FileName); PhClearReference(&context->BaseFileName); @@ -217,20 +205,8 @@ VOID TaskDialogCreateIcons( _In_ PUPLOAD_CONTEXT Context ) { - Context->IconLargeHandle = PhLoadIcon( - NtCurrentPeb()->ImageBaseAddress, - MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER), - PH_LOAD_ICON_SIZE_LARGE, - GetSystemMetrics(SM_CXICON), - GetSystemMetrics(SM_CYICON) - ); - Context->IconSmallHandle = PhLoadIcon( - NtCurrentPeb()->ImageBaseAddress, - MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER), - PH_LOAD_ICON_SIZE_LARGE, - GetSystemMetrics(SM_CXICON), - GetSystemMetrics(SM_CYICON) - ); + Context->IconLargeHandle = PH_LOAD_SHARED_ICON_SMALL(PhLibImageBase, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER)); + Context->IconSmallHandle = PH_LOAD_SHARED_ICON_LARGE(PhLibImageBase, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER)); SendMessage(Context->DialogHandle, WM_SETICON, ICON_SMALL, (LPARAM)Context->IconSmallHandle); SendMessage(Context->DialogHandle, WM_SETICON, ICON_BIG, (LPARAM)Context->IconLargeHandle); diff --git a/plugins/Updater/options.c b/plugins/Updater/options.c index 77c0c978bda6..17c421487a64 100644 --- a/plugins/Updater/options.c +++ b/plugins/Updater/options.c @@ -86,10 +86,10 @@ INT_PTR CALLBACK TextDlgProc( { PPH_UPDATER_CONTEXT context = (PPH_UPDATER_CONTEXT)lParam; - PhCenterWindow(hwndDlg, GetParent(hwndDlg)); + SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhLibImageBase, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); + SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhLibImageBase, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); - SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)UT_LOAD_SHARED_ICON_SMALL(MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); - SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)UT_LOAD_SHARED_ICON_LARGE(MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); + PhCenterWindow(hwndDlg, GetParent(hwndDlg)); PhInitializeLayoutManager(&LayoutManager, hwndDlg); PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDC_TEXT), NULL, PH_ANCHOR_ALL); diff --git a/plugins/Updater/updater.c b/plugins/Updater/updater.c index 6cc3cdc1facd..85943fe115c4 100644 --- a/plugins/Updater/updater.c +++ b/plugins/Updater/updater.c @@ -70,8 +70,8 @@ VOID TaskDialogCreateIcons( _In_ PPH_UPDATER_CONTEXT Context ) { - Context->IconSmallHandle = UT_LOAD_SHARED_ICON_SMALL(MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER)); - Context->IconLargeHandle = UT_LOAD_SHARED_ICON_LARGE(MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER)); + Context->IconSmallHandle = PH_LOAD_SHARED_ICON_SMALL(PhLibImageBase, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER)); + Context->IconLargeHandle = PH_LOAD_SHARED_ICON_LARGE(PhLibImageBase, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER)); SendMessage(Context->DialogHandle, WM_SETICON, ICON_SMALL, (LPARAM)Context->IconSmallHandle); SendMessage(Context->DialogHandle, WM_SETICON, ICON_BIG, (LPARAM)Context->IconLargeHandle); diff --git a/plugins/Updater/updater.h b/plugins/Updater/updater.h index ab8b850a635c..5afc567627b0 100644 --- a/plugins/Updater/updater.h +++ b/plugins/Updater/updater.h @@ -55,9 +55,6 @@ ((ULONGLONG)(build) << 16) | \ ((ULONGLONG)(revision) << 0)) -#define UT_LOAD_SHARED_ICON_SMALL(Name) PhLoadIcon(PhLibImageBase, (Name), PH_LOAD_ICON_SHARED | PH_LOAD_ICON_SIZE_SMALL, 0, 0) -#define UT_LOAD_SHARED_ICON_LARGE(Name) PhLoadIcon(PhLibImageBase, (Name), PH_LOAD_ICON_SHARED | PH_LOAD_ICON_SIZE_LARGE, 0, 0) - #ifdef _DEBUG // Force update checks to succeed (most of the below flags require this to be defined). //#define FORCE_UPDATE_CHECK From 43dce8aab32983ddb4ea6039eacbc9d99e59826a Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 22 May 2017 22:07:02 +1000 Subject: [PATCH 0149/2058] OnlineChecks: Fix window icon --- plugins/OnlineChecks/main.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/plugins/OnlineChecks/main.c b/plugins/OnlineChecks/main.c index fda5277f68f6..36187905b825 100644 --- a/plugins/OnlineChecks/main.c +++ b/plugins/OnlineChecks/main.c @@ -178,13 +178,7 @@ VOID NTAPI MenuItemCallback( config.dwFlags = TDF_USE_HICON_MAIN | TDF_ALLOW_DIALOG_CANCELLATION; config.dwCommonButtons = TDCBF_YES_BUTTON | TDCBF_NO_BUTTON; config.hwndParent = menuItem->OwnerWindow; - config.hMainIcon = PhLoadIcon( - PhLibImageBase, - MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER), - PH_LOAD_ICON_SIZE_LARGE, - GetSystemMetrics(SM_CXICON), - GetSystemMetrics(SM_CYICON) - ); + config.hMainIcon = PH_LOAD_SHARED_ICON_LARGE(PhLibImageBase, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); config.cxWidth = 180; config.pszWindowTitle = L"Process Hacker - VirusTotal"; config.pszMainInstruction = L"VirusTotal scanning requires a restart of Process Hacker."; From 904e478f5430d5258d80ba19f04c532aaa055b9e Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 22 May 2017 22:07:12 +1000 Subject: [PATCH 0150/2058] Updater: Fix changelog window layout --- plugins/Updater/options.c | 1 + plugins/Updater/updater.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/Updater/options.c b/plugins/Updater/options.c index 17c421487a64..2ca69914fc11 100644 --- a/plugins/Updater/options.c +++ b/plugins/Updater/options.c @@ -93,6 +93,7 @@ INT_PTR CALLBACK TextDlgProc( PhInitializeLayoutManager(&LayoutManager, hwndDlg); PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDC_TEXT), NULL, PH_ANCHOR_ALL); + PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDCANCEL), NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_RIGHT); SetWindowText(GetDlgItem(hwndDlg, IDC_TEXT), PhGetString(context->BuildMessage)); diff --git a/plugins/Updater/updater.c b/plugins/Updater/updater.c index 85943fe115c4..1db671fcfa02 100644 --- a/plugins/Updater/updater.c +++ b/plugins/Updater/updater.c @@ -428,7 +428,7 @@ BOOLEAN QueryUpdateData( Context->Signature = PhConvertUtf8ToUtf16(GetJsonValueAsString(jsonObject, "sig")); Context->ReleaseNotesUrl = PhConvertUtf8ToUtf16(GetJsonValueAsString(jsonObject, "forum_url")); Context->SetupFileDownloadUrl = PhConvertUtf8ToUtf16(GetJsonValueAsString(jsonObject, "setup_url")); - Context->BuildMessage = PhConvertUtf8ToUtf16(GetJsonValueAsString(jsonObject, "message")); + Context->BuildMessage = PhConvertUtf8ToUtf16(GetJsonValueAsString(jsonObject, "changelog")); PhInitializeStringBuilder(&sb, 0x100); for (SIZE_T i = 0; i < Context->BuildMessage->Length; i++) From b1b3a043fe62bb82d299501e5a4361911d70ffcd Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 22 May 2017 22:36:10 +1000 Subject: [PATCH 0151/2058] Fix typo --- plugins/OnlineChecks/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/OnlineChecks/main.c b/plugins/OnlineChecks/main.c index 36187905b825..8bbfe03f7b1a 100644 --- a/plugins/OnlineChecks/main.c +++ b/plugins/OnlineChecks/main.c @@ -178,7 +178,7 @@ VOID NTAPI MenuItemCallback( config.dwFlags = TDF_USE_HICON_MAIN | TDF_ALLOW_DIALOG_CANCELLATION; config.dwCommonButtons = TDCBF_YES_BUTTON | TDCBF_NO_BUTTON; config.hwndParent = menuItem->OwnerWindow; - config.hMainIcon = PH_LOAD_SHARED_ICON_LARGE(PhLibImageBase, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); + config.hMainIcon = PH_LOAD_SHARED_ICON_LARGE(PhLibImageBase, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER)); config.cxWidth = 180; config.pszWindowTitle = L"Process Hacker - VirusTotal"; config.pszMainInstruction = L"VirusTotal scanning requires a restart of Process Hacker."; From 7812a4f2a235e54c5c9d75c6e4fa5d5c4c425dd9 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 22 May 2017 22:50:36 +1000 Subject: [PATCH 0152/2058] Updater: Fix crash --- plugins/Updater/updater.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/plugins/Updater/updater.c b/plugins/Updater/updater.c index 1db671fcfa02..eda63f54957e 100644 --- a/plugins/Updater/updater.c +++ b/plugins/Updater/updater.c @@ -430,15 +430,20 @@ BOOLEAN QueryUpdateData( Context->SetupFileDownloadUrl = PhConvertUtf8ToUtf16(GetJsonValueAsString(jsonObject, "setup_url")); Context->BuildMessage = PhConvertUtf8ToUtf16(GetJsonValueAsString(jsonObject, "changelog")); - PhInitializeStringBuilder(&sb, 0x100); - for (SIZE_T i = 0; i < Context->BuildMessage->Length; i++) + if (Context->BuildMessage) { - if (Context->BuildMessage->Data[i] == '\n') - PhAppendStringBuilder2(&sb, L"\r\n"); - else - PhAppendCharStringBuilder(&sb, Context->BuildMessage->Data[i]); + PhInitializeStringBuilder(&sb, 0x100); + + for (SIZE_T i = 0; i < Context->BuildMessage->Length; i++) + { + if (Context->BuildMessage->Data[i] == '\n') + PhAppendStringBuilder2(&sb, L"\r\n"); + else + PhAppendCharStringBuilder(&sb, Context->BuildMessage->Data[i]); + } + + PhMoveReference(&Context->BuildMessage, PhFinalStringBuilderString(&sb)); } - PhMoveReference(&Context->BuildMessage, PhFinalStringBuilderString(&sb)); CleanupJsonParser(jsonObject); From 8286d59c400365b14b9a8f9c2d517b2a12547ced Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 23 May 2017 00:15:19 +1000 Subject: [PATCH 0153/2058] Remove relative paths from solutions (improves msbuild logging output) --- ProcessHacker/ProcessHacker.vcxproj | 28 +++++++++---------- phlib/phlib.vcxproj | 8 +++--- plugins/Plugins.props | 6 ++-- .../CustomSetupTool/CustomSetupTool.vcxproj | 12 ++++---- 4 files changed, 27 insertions(+), 27 deletions(-) diff --git a/ProcessHacker/ProcessHacker.vcxproj b/ProcessHacker/ProcessHacker.vcxproj index 5e3e2d24f2de..9168ea48f7b7 100644 --- a/ProcessHacker/ProcessHacker.vcxproj +++ b/ProcessHacker/ProcessHacker.vcxproj @@ -84,7 +84,7 @@ Disabled - ..\phnt\include;..\phlib\include;include;%(AdditionalIncludeDirectories) + $(SolutionDir)phnt\include;$(SolutionDir)phlib\include;include;%(AdditionalIncludeDirectories) _PHLIB_;_PHAPP_;_WINDOWS;WIN32;DEBUG;%(PreprocessorDefinitions);$(ExternalCompilerOptions) EnableFastChecks MultiThreadedDebug @@ -100,22 +100,22 @@ Windows MachineX86 6.01 - ..\phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) + $(SolutionDir)phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) ProcessHacker.def aclui.dll;iphlpapi.dll;ws2_32.dll;%(DelayLoadDLLs) _UNICODE;UNICODE;%(PreprocessorDefinitions);$(ExternalCompilerOptions) - ..\phnt\include;..\phlib\include;include;%(AdditionalIncludeDirectories) + $(SolutionDir)phnt\include;$(SolutionDir)phlib\include;include;%(AdditionalIncludeDirectories) - ..\build\build_sdk.cmd + $(SolutionDir)build\build_sdk.cmd Disabled - ..\phnt\include;..\phlib\include;include;%(AdditionalIncludeDirectories) + $(SolutionDir)phnt\include;$(SolutionDir)phlib\include;include;%(AdditionalIncludeDirectories) _PHLIB_;_PHAPP_;_WINDOWS;WIN64;DEBUG;%(PreprocessorDefinitions);$(ExternalCompilerOptions) EnableFastChecks MultiThreadedDebug @@ -131,24 +131,24 @@ Windows MachineX64 6.01 - ..\phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) + $(SolutionDir)phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) ProcessHacker.def aclui.dll;iphlpapi.dll;ws2_32.dll;%(DelayLoadDLLs) _UNICODE;UNICODE;%(PreprocessorDefinitions);$(ExternalCompilerOptions) - ..\phnt\include;..\phlib\include;include;%(AdditionalIncludeDirectories) + $(SolutionDir)phnt\include;$(SolutionDir)phlib\include;include;%(AdditionalIncludeDirectories) - ..\build\build_sdk.cmd + $(SolutionDir)build\build_sdk.cmd MaxSpeed true - ..\phnt\include;..\phlib\include;include;%(AdditionalIncludeDirectories) + $(SolutionDir)phnt\include;$(SolutionDir)phlib\include;include;%(AdditionalIncludeDirectories) _PHLIB_;_PHAPP_;_WINDOWS;WIN32;NDEBUG;%(PreprocessorDefinitions);$(ExternalCompilerOptions) true MultiThreaded @@ -170,20 +170,20 @@ MachineX86 true 6.01 - ..\phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) + $(SolutionDir)phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) ProcessHacker.def aclui.dll;iphlpapi.dll;ws2_32.dll;%(DelayLoadDLLs) _UNICODE;UNICODE;%(PreprocessorDefinitions);$(ExternalCompilerOptions) - ..\phnt\include;..\phlib\include;include;%(AdditionalIncludeDirectories) + $(SolutionDir)phnt\include;$(SolutionDir)phlib\include;include;%(AdditionalIncludeDirectories) MaxSpeed true - ..\phnt\include;..\phlib\include;include;%(AdditionalIncludeDirectories) + $(SolutionDir)phnt\include;$(SolutionDir)phlib\include;include;%(AdditionalIncludeDirectories) _PHLIB_;_PHAPP_;_WINDOWS;WIN64;NDEBUG;%(PreprocessorDefinitions);$(ExternalCompilerOptions) true MultiThreaded @@ -204,13 +204,13 @@ MachineX64 true 6.01 - ..\phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) + $(SolutionDir)phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) ProcessHacker.def aclui.dll;iphlpapi.dll;ws2_32.dll;%(DelayLoadDLLs) _UNICODE;UNICODE;%(PreprocessorDefinitions);$(ExternalCompilerOptions) - ..\phnt\include;..\phlib\include;include;%(AdditionalIncludeDirectories) + $(SolutionDir)phnt\include;$(SolutionDir)phlib\include;include;%(AdditionalIncludeDirectories) diff --git a/phlib/phlib.vcxproj b/phlib/phlib.vcxproj index cf67c6719a83..e395b2239ea8 100644 --- a/phlib/phlib.vcxproj +++ b/phlib/phlib.vcxproj @@ -76,7 +76,7 @@ Disabled - ..\phnt\include;include;%(AdditionalIncludeDirectories) + $(SolutionDir)phnt\include;include;%(AdditionalIncludeDirectories) DEBUG;_PHLIB_;%(PreprocessorDefinitions) true EnableFastChecks @@ -91,7 +91,7 @@ Disabled - ..\phnt\include;include;%(AdditionalIncludeDirectories) + $(SolutionDir)phnt\include;include;%(AdditionalIncludeDirectories) DEBUG;_PHLIB_;%(PreprocessorDefinitions) true EnableFastChecks @@ -107,7 +107,7 @@ MaxSpeed true - ..\phnt\include;include;%(AdditionalIncludeDirectories) + $(SolutionDir)phnt\include;include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_PHLIB_;%(PreprocessorDefinitions) true MultiThreaded @@ -125,7 +125,7 @@ MaxSpeed true - ..\phnt\include;include;%(AdditionalIncludeDirectories) + $(SolutionDir)phnt\include;include;%(AdditionalIncludeDirectories) WIN64;NDEBUG;_WINDOWS;_PHLIB_;%(PreprocessorDefinitions) true MultiThreaded diff --git a/plugins/Plugins.props b/plugins/Plugins.props index f47cc8f6e6d0..5069f7f3deee 100644 --- a/plugins/Plugins.props +++ b/plugins/Plugins.props @@ -19,7 +19,7 @@ - ..\include;..\..\sdk\include;%(AdditionalIncludeDirectories) + $(SolutionDir)include;$(SolutionDir)..\sdk\include;%(AdditionalIncludeDirectories) true Level3 true @@ -76,7 +76,7 @@ StreamingSIMDExtensions - ..\..\sdk\lib\i386;%(AdditionalLibraryDirectories) + $(SolutionDir)..\sdk\lib\i386;%(AdditionalLibraryDirectories) MachineX86 @@ -84,7 +84,7 @@ - ..\..\sdk\lib\amd64;%(AdditionalLibraryDirectories) + $(SolutionDir)..\sdk\lib\amd64;%(AdditionalLibraryDirectories) MachineX64 diff --git a/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj b/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj index cd939c79a92a..f158b962a908 100644 --- a/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj +++ b/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj @@ -53,7 +53,7 @@ Level3 Disabled true - ..\..\..\phnt\include;..\..\..\phlib\include;include;%(AdditionalIncludeDirectories) + $(SolutionDir)..\..\phnt\include;$(SolutionDir)..\..\phlib\include;include;%(AdditionalIncludeDirectories) false StdCall MultiThreadedDebug @@ -65,13 +65,13 @@ true uxtheme.lib;winhttp.lib;phlib.lib;ntdll.lib;%(AdditionalDependencies) - ..\..\..\phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) + $(SolutionDir)..\..\phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) Windows RequireAdministrator _UNICODE;UNICODE;%(PreprocessorDefinitions);$(ExternalCompilerOptions) - ..\..\..\phnt\include;..\..\..\phlib\include;include;%(AdditionalIncludeDirectories) + $(SolutionDir)..\..\phnt\include;$(SolutionDir)..\..\phlib\include;include;%(AdditionalIncludeDirectories) @@ -81,7 +81,7 @@ true true true - ..\..\..\phnt\include;..\..\..\phlib\include;include;%(AdditionalIncludeDirectories) + $(SolutionDir)..\..\phnt\include;$(SolutionDir)..\..\phlib\include;include;%(AdditionalIncludeDirectories) StdCall _PHLIB_;_WINDOWS;WIN32;NDEBUG;%(PreprocessorDefinitions);$(ExternalCompilerOptions) MultiThreaded @@ -95,7 +95,7 @@ true true uxtheme.lib;winhttp.lib;phlib.lib;ntdll.lib;%(AdditionalDependencies) - ..\..\..\phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) + $(SolutionDir)..\..\phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) Windows 5.01 true @@ -103,7 +103,7 @@ _UNICODE;UNICODE;%(PreprocessorDefinitions);$(ExternalCompilerOptions) - ..\..\..\phnt\include;..\..\..\phlib\include;include;%(AdditionalIncludeDirectories) + $(SolutionDir)..\..\phnt\include;$(SolutionDir)..\..\phlib\include;include;%(AdditionalIncludeDirectories) From cf43d189b118de91a9e141377fe505219f2ae25b Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 23 May 2017 02:04:21 +1000 Subject: [PATCH 0154/2058] Fix setup replacing existing settings file, Add initial setup error page, Add more web-setup support (incomplete) --- .../CustomSetupTool/CustomSetupTool.vcxproj | 1 + .../CustomSetupTool.vcxproj.filters | 3 + .../CustomSetupTool/download.c | 93 ++----------- tools/CustomSetupTool/CustomSetupTool/error.c | 48 +++++++ .../CustomSetupTool/include/setup.h | 73 ++++++++-- tools/CustomSetupTool/CustomSetupTool/main.c | 45 ++++-- tools/CustomSetupTool/CustomSetupTool/page1.c | 16 +-- tools/CustomSetupTool/CustomSetupTool/page2.c | 13 +- tools/CustomSetupTool/CustomSetupTool/page3.c | 12 +- tools/CustomSetupTool/CustomSetupTool/page4.c | 9 +- tools/CustomSetupTool/CustomSetupTool/page5.c | 125 ++++++----------- .../CustomSetupTool/resource.h | 6 +- .../CustomSetupTool/resource.rc | 128 +++++++++--------- .../CustomSetupTool/resources/version.rc | 88 ++++++++---- tools/CustomSetupTool/CustomSetupTool/setup.c | 8 +- .../CustomSetupTool/uninstall.c | 6 +- 16 files changed, 363 insertions(+), 311 deletions(-) create mode 100644 tools/CustomSetupTool/CustomSetupTool/error.c diff --git a/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj b/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj index f158b962a908..227ad5d2ce4f 100644 --- a/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj +++ b/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj @@ -108,6 +108,7 @@ + diff --git a/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj.filters b/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj.filters index 85f331c02a3f..6557bf933011 100644 --- a/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj.filters +++ b/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj.filters @@ -105,6 +105,9 @@ Source Files\json + + Source Files\pages + diff --git a/tools/CustomSetupTool/CustomSetupTool/download.c b/tools/CustomSetupTool/CustomSetupTool/download.c index 977872b81370..7d050109e1b8 100644 --- a/tools/CustomSetupTool/CustomSetupTool/download.c +++ b/tools/CustomSetupTool/CustomSetupTool/download.c @@ -5,13 +5,6 @@ #include "json-c\json.h" -typedef struct _PH_SETUP_DOWNLOAD_CONTEXT -{ - HWND DialogHandle; - HICON IconSmallHandle; - HICON IconLargeHandle; -} PH_SETUP_DOWNLOAD_CONTEXT, *PPH_SETUP_DOWNLOAD_CONTEXT; - PPH_STRING SetupGetVersion( VOID ) @@ -170,7 +163,7 @@ json_object_ptr json_get_object( BOOLEAN SetupQueryUpdateData( - _Inout_ PPH_SETUP_UNINSTALL_CONTEXT Context + _Inout_ PPH_SETUP_DOWNLOAD_CONTEXT Context ) { BOOLEAN success = FALSE; @@ -372,8 +365,8 @@ BOOLEAN SetupQueryUpdateData( if (httpSessionHandle) WinHttpCloseHandle(httpSessionHandle); - //if (xmlNode) - // mxmlDelete(xmlNode); + if (jsonObject) + json_object_put(jsonObject); if (stringBuffer) PhFree(stringBuffer); @@ -384,82 +377,11 @@ BOOLEAN SetupQueryUpdateData( return success; } - -//NTSTATUS UpdateCheckThread( -// _In_ PVOID Parameter -//) -//{ -// PPH_UPDATER_CONTEXT context = NULL; -// ULONGLONG currentVersion = 0; -// ULONGLONG latestVersion = 0; -// -// context = (PPH_UPDATER_CONTEXT)Parameter; -// context->ErrorCode = STATUS_SUCCESS; -// -// // Check if we have cached update data -// if (!context->HaveData) -// { -// context->HaveData = QueryUpdateData(context); -// } -// -// if (!context->HaveData) -// { -// PostMessage(context->DialogHandle, PH_UPDATEISERRORED, 0, 0); -// -// PhDereferenceObject(context); -// return STATUS_SUCCESS; -// } -// -// currentVersion = MAKE_VERSION_ULONGLONG( -// context->CurrentMajorVersion, -// context->CurrentMinorVersion, -// context->CurrentRevisionVersion, -// 0 -// ); -// -//#ifdef FORCE_UPDATE_CHECK -// latestVersion = MAKE_VERSION_ULONGLONG( -// 9999, -// 9999, -// 9999, -// 0 -// ); -//#else -// latestVersion = MAKE_VERSION_ULONGLONG( -// context->MajorVersion, -// context->MinorVersion, -// context->RevisionVersion, -// 0 -// ); -//#endif -// -// if (currentVersion == latestVersion) -// { -// // User is running the latest version -// PostMessage(context->DialogHandle, PH_UPDATEISCURRENT, 0, 0); -// } -// else if (currentVersion > latestVersion) -// { -// // User is running a newer version -// PostMessage(context->DialogHandle, PH_UPDATENEWER, 0, 0); -// } -// else -// { -// // User is running an older version -// PostMessage(context->DialogHandle, PH_UPDATEAVAILABLE, 0, 0); -// } -// -// PhDereferenceObject(context); -// return STATUS_SUCCESS; -//} - BOOLEAN UpdateDownloadUpdateData( - _In_ PPH_SETUP_UNINSTALL_CONTEXT Context + _In_ PPH_SETUP_DOWNLOAD_CONTEXT Context ) { BOOLEAN downloadSuccess = FALSE; -// BOOLEAN hashSuccess = FALSE; -// BOOLEAN signatureSuccess = FALSE; HANDLE tempFileHandle = NULL; HINTERNET httpSessionHandle = NULL; HINTERNET httpConnectionHandle = NULL; @@ -470,7 +392,6 @@ BOOLEAN UpdateDownloadUpdateData( PPH_STRING userAgentString = NULL; PPH_STRING fullSetupPath = NULL; PPH_STRING randomGuidString = NULL; -// PUPDATER_HASH_CONTEXT hashContext = NULL; ULONG indexOfFileName = -1; GUID randomGuid; URL_COMPONENTS httpUrlComponents = { sizeof(URL_COMPONENTS) }; @@ -546,7 +467,7 @@ BOOLEAN UpdateDownloadUpdateData( httpUrlComponents.dwUrlPathLength = (ULONG)-1; if (!WinHttpCrackUrl( - PhGetStringOrEmpty(Context->SetupFileDownloadUrl), + PhGetString(Context->SetupFileDownloadUrl), 0, 0, &httpUrlComponents @@ -728,6 +649,8 @@ BOOLEAN UpdateDownloadUpdateData( PhDereferenceObject(totalDownloaded); } } + + downloadSuccess = TRUE; } CleanupExit: @@ -767,5 +690,5 @@ BOOLEAN UpdateDownloadUpdateData( // } //} - return STATUS_SUCCESS; + return downloadSuccess; } diff --git a/tools/CustomSetupTool/CustomSetupTool/error.c b/tools/CustomSetupTool/CustomSetupTool/error.c new file mode 100644 index 000000000000..ec3eb5ff1eb1 --- /dev/null +++ b/tools/CustomSetupTool/CustomSetupTool/error.c @@ -0,0 +1,48 @@ +/* + * Process Hacker Toolchain - + * project setup + * + * Copyright (C) 2017 dmex + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include + +INT_PTR CALLBACK SetupErrorPage_WndProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _Inout_ WPARAM wParam, + _Inout_ LPARAM lParam + ) +{ + PPH_SETUP_CONTEXT context = (PPH_SETUP_CONTEXT)GetProp(GetParent(hwndDlg), L"SetupContext"); + + switch (uMsg) + { + case WM_INITDIALOG: + { + SetupLoadImage(GetDlgItem(hwndDlg, IDC_PROJECT_ICON), MAKEINTRESOURCE(IDB_PNG1)); + SetupInitializeFont(GetDlgItem(hwndDlg, IDC_MAINHEADER), -18, FW_SEMIBOLD); + SetupInitializeFont(GetDlgItem(hwndDlg, IDC_SUBHEADER), 0, FW_NORMAL); + + EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); + } + break; + } + + return FALSE; +} \ No newline at end of file diff --git a/tools/CustomSetupTool/CustomSetupTool/include/setup.h b/tools/CustomSetupTool/CustomSetupTool/include/setup.h index c01ad508d6d5..6c9f40621a2d 100644 --- a/tools/CustomSetupTool/CustomSetupTool/include/setup.h +++ b/tools/CustomSetupTool/CustomSetupTool/include/setup.h @@ -32,6 +32,8 @@ #include #include #include +#include + #include #include #include @@ -40,9 +42,9 @@ #include #include -#include - #include "resource.h" + +// Version Information #include "..\..\ProcessHacker\include\phappres.h" // Win32 PropertySheet Control IDs @@ -82,11 +84,27 @@ typedef enum _SETUP_COMMAND_TYPE SETUP_COMMAND_REPAIR, } SETUP_COMMAND_TYPE; -typedef struct _SETUP_INSTANCE +typedef struct _PH_SETUP_CONTEXT { - ULONG Version; HWND WindowHandle; -} SETUP_INSTANCE, *PSETUP_INSTANCE; + HWND PropSheetHandle; + + HICON IconSmallHandle; + HICON IconLargeHandle; + + ULONG ErrorCode; + PPH_STRING Version; + PPH_STRING RevVersion; + PPH_STRING RelDate; + PPH_STRING Size; + PPH_STRING Hash; + PPH_STRING Signature; + PPH_STRING ReleaseNotesUrl; + + PPH_STRING BinFileDownloadUrl; + PPH_STRING SetupFileDownloadUrl; + PPH_STRING SetupFilePath; +} PH_SETUP_CONTEXT, *PPH_SETUP_CONTEXT; VOID SetupLoadImage( _In_ HWND WindowHandle, @@ -128,6 +146,13 @@ INT_PTR CALLBACK SetupPropPage5_WndProc( _Inout_ LPARAM lParam ); +INT_PTR CALLBACK SetupErrorPage_WndProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _Inout_ WPARAM wParam, + _Inout_ LPARAM lParam + ); + // page4.c typedef struct _SETUP_PROGRESS_THREAD @@ -185,15 +210,14 @@ VOID SetupUpgradeSettingsFile( // download.c -typedef struct _PH_SETUP_UNINSTALL_CONTEXT +typedef struct _PH_SETUP_DOWNLOAD_CONTEXT { HWND DialogHandle; + HWND PropSheetHandle; HWND MainHeaderHandle; HWND StatusHandle; HWND SubStatusHandle; HWND ProgressHandle; - HICON IconSmallHandle; - HICON IconLargeHandle; ULONG CurrentMajorVersion; ULONG CurrentMinorVersion; @@ -214,14 +238,14 @@ typedef struct _PH_SETUP_UNINSTALL_CONTEXT PPH_STRING BinFileDownloadUrl; PPH_STRING SetupFileDownloadUrl; PPH_STRING SetupFilePath; -} PH_SETUP_UNINSTALL_CONTEXT, *PPH_SETUP_UNINSTALL_CONTEXT; +} PH_SETUP_DOWNLOAD_CONTEXT, *PPH_SETUP_DOWNLOAD_CONTEXT; BOOLEAN SetupQueryUpdateData( - _In_ PPH_SETUP_UNINSTALL_CONTEXT Context + _In_ PPH_SETUP_DOWNLOAD_CONTEXT Context ); BOOLEAN UpdateDownloadUpdateData( - _In_ PPH_SETUP_UNINSTALL_CONTEXT Context + _In_ PPH_SETUP_DOWNLOAD_CONTEXT Context ); // extract.c @@ -238,6 +262,33 @@ VOID SetupShowUpdateDialog( // uninstall.c +typedef struct _PH_SETUP_UNINSTALL_CONTEXT +{ + HWND DialogHandle; + HICON IconSmallHandle; + HICON IconLargeHandle; + + ULONG CurrentMajorVersion; + ULONG CurrentMinorVersion; + ULONG CurrentRevisionVersion; + ULONG LatestMajorVersion; + ULONG LatestMinorVersion; + ULONG LatestRevisionVersion; + + ULONG ErrorCode; + PPH_STRING Version; + PPH_STRING RevVersion; + PPH_STRING RelDate; + PPH_STRING Size; + PPH_STRING Hash; + PPH_STRING Signature; + PPH_STRING ReleaseNotesUrl; + + PPH_STRING BinFileDownloadUrl; + PPH_STRING SetupFileDownloadUrl; + PPH_STRING SetupFilePath; +} PH_SETUP_UNINSTALL_CONTEXT, *PPH_SETUP_UNINSTALL_CONTEXT; + VOID SetupShowUninstallDialog( VOID ); diff --git a/tools/CustomSetupTool/CustomSetupTool/main.c b/tools/CustomSetupTool/CustomSetupTool/main.c index 9318c1dd44a9..fe2fb4e1d8a1 100644 --- a/tools/CustomSetupTool/CustomSetupTool/main.c +++ b/tools/CustomSetupTool/CustomSetupTool/main.c @@ -82,16 +82,29 @@ INT CALLBACK MainPropSheet_Callback( { switch (uMsg) { - case PSCB_INITIALIZED: - break; case PSCB_PRECREATE: { if (lParam) { - ((LPDLGTEMPLATE)lParam)->style |= WS_MINIMIZEBOX; + if (((DLGTEMPLATEEX *)lParam)->signature == USHORT_MAX) + ((DLGTEMPLATEEX *)lParam)->style |= WS_MINIMIZEBOX; + else + ((DLGTEMPLATE *)lParam)->style |= WS_MINIMIZEBOX; } } break; + case PSCB_INITIALIZED: + { + PPH_SETUP_CONTEXT context; + + context = PhAllocate(sizeof(PH_SETUP_CONTEXT)); + memset(context, 0, sizeof(PH_SETUP_CONTEXT)); + + context->PropSheetHandle = hwndDlg; + + SetProp(hwndDlg, L"SetupContext", (HANDLE)context); + } + break; } return FALSE; @@ -140,7 +153,7 @@ INT WINAPI wWinMain( { PROPSHEETPAGE propSheetPage = { sizeof(PROPSHEETPAGE) }; PROPSHEETHEADER propSheetHeader = { sizeof(PROPSHEETHEADER) }; - HPROPSHEETPAGE pages[4]; + HPROPSHEETPAGE pages[6]; propSheetHeader.dwFlags = PSH_NOAPPLYNOW | PSH_NOCONTEXTHELP | PSH_USECALLBACK | PSH_WIZARD_LITE; propSheetHeader.hInstance = PhLibImageBase; @@ -148,6 +161,7 @@ INT WINAPI wWinMain( propSheetHeader.pfnCallback = MainPropSheet_Callback; propSheetHeader.phpage = pages; + // welcome page memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); propSheetPage.dwSize = sizeof(PROPSHEETPAGE); propSheetPage.dwFlags = PSP_USETITLE; @@ -156,6 +170,7 @@ INT WINAPI wWinMain( propSheetPage.pfnDlgProc = SetupPropPage1_WndProc; pages[propSheetHeader.nPages++] = CreatePropertySheetPage(&propSheetPage); + // eula page memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); propSheetPage.dwSize = sizeof(PROPSHEETPAGE); propSheetPage.dwFlags = PSP_USETITLE; @@ -164,13 +179,25 @@ INT WINAPI wWinMain( propSheetPage.pfnDlgProc = SetupPropPage2_WndProc; pages[propSheetHeader.nPages++] = CreatePropertySheetPage(&propSheetPage); + // config page memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); propSheetPage.dwSize = sizeof(PROPSHEETPAGE); + propSheetPage.dwFlags = PSP_USETITLE; + propSheetPage.pszTitle = PhApplicationName; propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_DIALOG3); propSheetPage.pfnDlgProc = SetupPropPage3_WndProc; pages[propSheetHeader.nPages++] = CreatePropertySheetPage(&propSheetPage); -#ifdef PH_BUILD_API + // download page + memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); + propSheetPage.dwSize = sizeof(PROPSHEETPAGE); + propSheetPage.dwFlags = PSP_USETITLE; + propSheetPage.pszTitle = PhApplicationName; + propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_DIALOG5); + propSheetPage.pfnDlgProc = SetupPropPage5_WndProc; + pages[propSheetHeader.nPages++] = CreatePropertySheetPage(&propSheetPage); + + // extract page memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); propSheetPage.dwSize = sizeof(PROPSHEETPAGE); propSheetPage.dwFlags = PSP_USETITLE; @@ -178,15 +205,15 @@ INT WINAPI wWinMain( propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_DIALOG4); propSheetPage.pfnDlgProc = SetupPropPage4_WndProc; pages[propSheetHeader.nPages++] = CreatePropertySheetPage(&propSheetPage); -#else + + // error page memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); propSheetPage.dwSize = sizeof(PROPSHEETPAGE); propSheetPage.dwFlags = PSP_USETITLE; propSheetPage.pszTitle = PhApplicationName; - propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_DIALOG4); - propSheetPage.pfnDlgProc = SetupPropPage5_WndProc; + propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_ERROR); + propSheetPage.pfnDlgProc = SetupErrorPage_WndProc; pages[propSheetHeader.nPages++] = CreatePropertySheetPage(&propSheetPage); -#endif PhModalPropertySheet(&propSheetHeader); } diff --git a/tools/CustomSetupTool/CustomSetupTool/page1.c b/tools/CustomSetupTool/CustomSetupTool/page1.c index 4ce65ad5c163..8c98be740860 100644 --- a/tools/CustomSetupTool/CustomSetupTool/page1.c +++ b/tools/CustomSetupTool/CustomSetupTool/page1.c @@ -73,6 +73,8 @@ INT_PTR CALLBACK SetupPropPage1_WndProc( _Inout_ LPARAM lParam ) { + PPH_SETUP_CONTEXT context = (PPH_SETUP_CONTEXT)GetProp(GetParent(hwndDlg), L"SetupContext"); + switch (uMsg) { case WM_INITDIALOG: @@ -98,27 +100,23 @@ INT_PTR CALLBACK SetupPropPage1_WndProc( { case PSN_SETACTIVE: { - HWND hwPropSheet = pageNotify->hdr.hwndFrom; - // Reset the button state. - PropSheet_SetWizButtons(hwPropSheet, PSWIZB_NEXT); + PropSheet_SetWizButtons(context->PropSheetHandle, PSWIZB_NEXT); // Hide the back button. - //ShowWindow(GetDlgItem(hwPropSheet, IDC_PROPSHEET_BACK), SW_HIDE); + //ShowWindow(GetDlgItem(context->PropSheetHandle, IDC_PROPSHEET_BACK), SW_HIDE); // HACK: Focus the next button (reset after changing button state). - PostMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hwPropSheet, IDC_PROPSHEET_NEXT), TRUE); + PostMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(context->PropSheetHandle, IDC_PROPSHEET_NEXT), TRUE); } break; case PSN_KILLACTIVE: { - HWND hwPropSheet = pageNotify->hdr.hwndFrom; - // Enable the back button. - PropSheet_SetWizButtons(hwPropSheet, PSWIZB_NEXT | PSWIZB_BACK); + PropSheet_SetWizButtons(context->PropSheetHandle, PSWIZB_NEXT | PSWIZB_BACK); // Show the back button. - //ShowWindow(GetDlgItem(hwPropSheet, IDC_PROPSHEET_BACK), SW_SHOW); + //ShowWindow(GetDlgItem(context->PropSheetHandle, IDC_PROPSHEET_BACK), SW_SHOW); } break; } diff --git a/tools/CustomSetupTool/CustomSetupTool/page2.c b/tools/CustomSetupTool/CustomSetupTool/page2.c index 016a431d7e9e..a987b93b5c80 100644 --- a/tools/CustomSetupTool/CustomSetupTool/page2.c +++ b/tools/CustomSetupTool/CustomSetupTool/page2.c @@ -27,6 +27,8 @@ INT_PTR CALLBACK SetupPropPage2_WndProc( _Inout_ LPARAM lParam ) { + PPH_SETUP_CONTEXT context = (PPH_SETUP_CONTEXT)GetProp(GetParent(hwndDlg), L"SetupContext"); + switch (uMsg) { case WM_INITDIALOG: @@ -62,20 +64,15 @@ INT_PTR CALLBACK SetupPropPage2_WndProc( { case PSN_SETACTIVE: { - HWND hwPropSheet = pageNotify->hdr.hwndFrom; - - PostMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hwPropSheet, IDC_PROPSHEET_NEXT), TRUE); + PostMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(context->PropSheetHandle, IDC_PROPSHEET_NEXT), TRUE); // Disable the Next button - //PropSheet_SetWizButtons(hwPropSheet, PSWIZB_BACK); + //PropSheet_SetWizButtons(context->PropSheetHandle, PSWIZB_BACK); } break; case PSN_QUERYINITIALFOCUS: { - HWND hwPropSheet = pageNotify->hdr.hwndFrom; - HWND hwnd = GetDlgItem(hwPropSheet, IDC_PROPSHEET_CANCEL); - - SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, (LPARAM)hwnd); + SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, (LPARAM)GetDlgItem(context->PropSheetHandle, IDC_PROPSHEET_CANCEL)); } return TRUE; } diff --git a/tools/CustomSetupTool/CustomSetupTool/page3.c b/tools/CustomSetupTool/CustomSetupTool/page3.c index aa1344a04c70..800f73b38a39 100644 --- a/tools/CustomSetupTool/CustomSetupTool/page3.c +++ b/tools/CustomSetupTool/CustomSetupTool/page3.c @@ -41,6 +41,8 @@ INT_PTR CALLBACK SetupPropPage3_WndProc( _Inout_ LPARAM lParam ) { + PPH_SETUP_CONTEXT context = (PPH_SETUP_CONTEXT)GetProp(GetParent(hwndDlg), L"SetupContext"); + switch (uMsg) { case WM_INITDIALOG: @@ -123,7 +125,7 @@ INT_PTR CALLBACK SetupPropPage3_WndProc( switch (pageNotify->hdr.code) { - case PSN_KILLACTIVE: + case PSN_WIZNEXT: { SetupInstallPath = PhGetWindowText(GetDlgItem(hwndDlg, IDC_INSTALL_DIRECTORY)); SetupCreateDesktopShortcut = Button_GetCheck(GetDlgItem(hwndDlg, IDC_SHORTCUT_CHECK)) == BST_CHECKED; @@ -136,8 +138,14 @@ INT_PTR CALLBACK SetupPropPage3_WndProc( SetupInstallKphService = Button_GetCheck(GetDlgItem(hwndDlg, IDC_KPH_CHECK)) == BST_CHECKED; SetupResetSettings = Button_GetCheck(GetDlgItem(hwndDlg, IDC_RESET_CHECK)) == BST_CHECKED; SetupStartAppAfterExit = Button_GetCheck(GetDlgItem(hwndDlg, IDC_PHSTART_CHECK)) == BST_CHECKED; + +#ifdef PH_BUILD_API + SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, (LPARAM)IDD_DIALOG4); +#else + SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, (LPARAM)IDD_DIALOG5); +#endif } - break; + return TRUE; case PSN_QUERYINITIALFOCUS: SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, (LPARAM)GetDlgItem(hwndDlg, IDC_FOLDER_BROWSE)); return TRUE; diff --git a/tools/CustomSetupTool/CustomSetupTool/page4.c b/tools/CustomSetupTool/CustomSetupTool/page4.c index 236086b28f38..f0984811c876 100644 --- a/tools/CustomSetupTool/CustomSetupTool/page4.c +++ b/tools/CustomSetupTool/CustomSetupTool/page4.c @@ -85,6 +85,8 @@ INT_PTR CALLBACK SetupPropPage4_WndProc( _Inout_ LPARAM lParam ) { + PPH_SETUP_CONTEXT context = (PPH_SETUP_CONTEXT)GetProp(GetParent(hwndDlg), L"SetupContext"); + switch (uMsg) { case WM_INITDIALOG: @@ -119,14 +121,11 @@ INT_PTR CALLBACK SetupPropPage4_WndProc( break; case PSN_SETACTIVE: { - HWND hwPropSheet; HANDLE threadHandle; PSETUP_PROGRESS_THREAD progress; - hwPropSheet = pageNotify->hdr.hwndFrom; - // Disable Next/Back buttons - PropSheet_SetWizButtons(hwPropSheet, 0); + PropSheet_SetWizButtons(context->PropSheetHandle, 0); if (!SetupRunning) { @@ -135,7 +134,7 @@ INT_PTR CALLBACK SetupPropPage4_WndProc( // Setup the progress thread progress = PhCreateAlloc(sizeof(SETUP_PROGRESS_THREAD)); progress->DialogHandle = hwndDlg; - progress->PropSheetHandle = hwPropSheet; + progress->PropSheetHandle = context->PropSheetHandle; if (threadHandle = PhCreateThread(0, SetupProgressThread, progress)) NtClose(threadHandle); diff --git a/tools/CustomSetupTool/CustomSetupTool/page5.c b/tools/CustomSetupTool/CustomSetupTool/page5.c index dd6749c90bdc..7fdd40939b22 100644 --- a/tools/CustomSetupTool/CustomSetupTool/page5.c +++ b/tools/CustomSetupTool/CustomSetupTool/page5.c @@ -22,20 +22,25 @@ #include -ULONG64 DownloadCurrentLength = 0; -ULONG64 DownloadTotalLength = 0; - NTSTATUS SetupDownloadProgressThread( - _In_ PPH_SETUP_UNINSTALL_CONTEXT Context + _In_ PPH_SETUP_DOWNLOAD_CONTEXT Context ) { - if (SetupQueryUpdateData(Context)) - { - UpdateDownloadUpdateData(Context); - } + if (!SetupQueryUpdateData(Context)) + goto CleanupExit; + + if (!UpdateDownloadUpdateData(Context)) + goto CleanupExit; + PostMessage(Context->PropSheetHandle, PSM_SETCURSELID, 0, IDD_DIALOG4); PhDereferenceObject(Context); return STATUS_SUCCESS; + +CleanupExit: + + PostMessage(Context->PropSheetHandle, PSM_SETCURSELID, 0, IDD_ERROR); + PhDereferenceObject(Context); + return STATUS_FAIL_CHECK; } INT_PTR CALLBACK SetupPropPage5_WndProc( @@ -45,6 +50,8 @@ INT_PTR CALLBACK SetupPropPage5_WndProc( _Inout_ LPARAM lParam ) { + PPH_SETUP_CONTEXT context = (PPH_SETUP_CONTEXT)GetProp(GetParent(hwndDlg), L"SetupContext"); + switch (uMsg) { case WM_INITDIALOG: @@ -59,21 +66,6 @@ INT_PTR CALLBACK SetupPropPage5_WndProc( SetWindowText(GetDlgItem(hwndDlg, IDC_INSTALL_STATUS), L"Starting download..."); SetWindowText(GetDlgItem(hwndDlg, IDC_INSTALL_SUBSTATUS), L""); - // Setup the progress thread - PPH_SETUP_UNINSTALL_CONTEXT progress = PhCreateAlloc(sizeof(PH_SETUP_UNINSTALL_CONTEXT)); - memset(progress, 0, sizeof(PH_SETUP_UNINSTALL_CONTEXT)); - - progress->DialogHandle = hwndDlg; - progress->MainHeaderHandle = GetDlgItem(hwndDlg, IDC_MAINHEADER); - progress->StatusHandle = GetDlgItem(hwndDlg, IDC_INSTALL_STATUS); - progress->SubStatusHandle = GetDlgItem(hwndDlg, IDC_INSTALL_SUBSTATUS); - progress->ProgressHandle = GetDlgItem(hwndDlg, IDC_INSTALL_PROGRESS); - progress->CurrentMajorVersion = PHAPP_VERSION_MAJOR; - progress->CurrentMinorVersion = PHAPP_VERSION_MINOR; - progress->CurrentRevisionVersion = PHAPP_VERSION_REVISION; - - RtlQueueWorkItem(SetupDownloadProgressThread, progress, 0); - EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); } break; @@ -88,9 +80,6 @@ INT_PTR CALLBACK SetupPropPage5_WndProc( { if (SetupRunning && DialogPromptExit(hwndDlg)) { - //PropSheet_CancelToClose(GetParent(hwndDlg)); - //EnableMenuItem(GetSystemMenu(GetParent(hwndDlg), FALSE), SC_CLOSE, MF_GRAYED); - //EnableMenuItem(GetSystemMenu(GetParent(hwndDlg), FALSE), SC_CLOSE, MF_ENABLED); SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, (LPARAM)TRUE); return TRUE; } @@ -98,73 +87,37 @@ INT_PTR CALLBACK SetupPropPage5_WndProc( break; case PSN_SETACTIVE: { - //HWND hwPropSheet; - //HANDLE threadHandle; - //PSETUP_PROGRESS_THREAD progress; - - //hwPropSheet = pageNotify->hdr.hwndFrom; + HANDLE threadHandle; + PPH_SETUP_DOWNLOAD_CONTEXT progress; - //// Disable Next/Back buttons - //PropSheet_SetWizButtons(hwPropSheet, 0); + // Disable Next/Back buttons + PropSheet_SetWizButtons(context->PropSheetHandle, 0); - //if (!SetupRunning) - //{ - // SetupRunning = TRUE; - - // // Setup the progress thread - // progress = PhCreateAlloc(sizeof(SETUP_PROGRESS_THREAD)); - // progress->DialogHandle = hwndDlg; - // progress->PropSheetHandle = hwPropSheet; - - // if (threadHandle = PhCreateThread(0, SetupDownloadProgressThread, progress)) - // NtClose(threadHandle); - //} + if (!SetupRunning) + { + SetupRunning = TRUE; + + progress = PhCreateAlloc(sizeof(PH_SETUP_DOWNLOAD_CONTEXT)); + memset(progress, 0, sizeof(PH_SETUP_DOWNLOAD_CONTEXT)); + + progress->DialogHandle = hwndDlg; + progress->PropSheetHandle = context->PropSheetHandle; + progress->CurrentMajorVersion = PHAPP_VERSION_MAJOR; + progress->CurrentMinorVersion = PHAPP_VERSION_MINOR; + progress->CurrentRevisionVersion = PHAPP_VERSION_REVISION; + progress->MainHeaderHandle = GetDlgItem(hwndDlg, IDC_MAINHEADER); + progress->StatusHandle = GetDlgItem(hwndDlg, IDC_INSTALL_STATUS); + progress->SubStatusHandle = GetDlgItem(hwndDlg, IDC_INSTALL_SUBSTATUS); + progress->ProgressHandle = GetDlgItem(hwndDlg, IDC_INSTALL_PROGRESS); + + if (threadHandle = PhCreateThread(0, SetupDownloadProgressThread, progress)) + NtClose(threadHandle); + } } break; } } break; - case WM_START_SETUP: - { - //SetWindowText(GetDlgItem(hwndDlg, IDC_MAINHEADER), - // PhaFormatString(L"Downloading Process Hacker %lu.%lu.%lu", PHAPP_VERSION_MAJOR, PHAPP_VERSION_MINOR, PHAPP_VERSION_REVISION)->Buffer); - //SetWindowText(GetDlgItem(hwndDlg, IDC_INSTALL_SUBSTATUS), L"Progress: ~ of ~ (0.0%)"); - //SendMessage(GetDlgItem(hwndDlg, IDC_INSTALL_PROGRESS), PBM_SETRANGE32, 0, (LPARAM)ExtractTotalLength); - } - break; - case WM_UPDATE_SETUP: - { - //PPH_STRING currentFile = (PPH_STRING)lParam; - // - ////SetWindowText(GetDlgItem(hwndDlg, IDC_INSTALL_STATUS), - //// PhaConcatStrings2(L"Extracting: ", currentFile->Buffer)->Buffer - //// ); - //SetWindowText(GetDlgItem(hwndDlg, IDC_INSTALL_SUBSTATUS), PhaFormatString( - // L"Progress: %s of %s (%.2f%%)", - // PhaFormatSize(ExtractCurrentLength, -1)->Buffer, - // PhaFormatSize(ExtractTotalLength, -1)->Buffer, - // (FLOAT)((double)ExtractCurrentLength / (double)ExtractTotalLength) * 100 - // )->Buffer); - //SendMessage(GetDlgItem(hwndDlg, IDC_INSTALL_PROGRESS), PBM_SETPOS, (WPARAM)ExtractCurrentLength, 0); - // - //PhDereferenceObject(currentFile); - } - break; - case WM_END_SETUP: - { - SetupRunning = FALSE; - - SetWindowText(GetDlgItem(hwndDlg, IDC_MAINHEADER), L"Setup Complete"); - SetWindowText(GetDlgItem(hwndDlg, IDC_INSTALL_STATUS), L"Extract complete"); - Button_SetText(GetDlgItem(GetParent(hwndDlg), IDC_PROPSHEET_CANCEL), L"Close"); - - if (SetupStartAppAfterExit) - { - SetupExecuteProcessHacker(GetParent(hwndDlg)); - PropSheet_PressButton(GetParent(hwndDlg), PSBTN_FINISH); - } - } - break; } return FALSE; diff --git a/tools/CustomSetupTool/CustomSetupTool/resource.h b/tools/CustomSetupTool/CustomSetupTool/resource.h index 49bdd138ee8f..5a7083fb3d6e 100644 --- a/tools/CustomSetupTool/CustomSetupTool/resource.h +++ b/tools/CustomSetupTool/CustomSetupTool/resource.h @@ -8,11 +8,11 @@ #define IDD_DIALOG3 104 #define IDD_ERROR 105 #define IDI_ICON1 106 +#define IDD_DIALOG5 106 #define IDB_PNG1 107 #define IDR_LICENCE_DATA 108 -#define IDR_BIN_DATA 109 +#define IDR_BIN_DATA 111 #define IDC_MAINHEADER 1001 -#define IDC_MAINHEADER2 1002 #define IDC_INSTALL_PROGRESS 1005 #define IDC_SUBHEADER 1047 #define IDC_EDIT1 1048 @@ -46,6 +46,6 @@ #define _APS_NEXT_RESOURCE_VALUE 110 #define _APS_NEXT_COMMAND_VALUE 40002 #define _APS_NEXT_CONTROL_VALUE 1078 -#define _APS_NEXT_SYMED_VALUE 110 +#define _APS_NEXT_SYMED_VALUE 112 #endif #endif diff --git a/tools/CustomSetupTool/CustomSetupTool/resource.rc b/tools/CustomSetupTool/CustomSetupTool/resource.rc index 51ef2760a531..e8ea912af48c 100644 --- a/tools/CustomSetupTool/CustomSetupTool/resource.rc +++ b/tools/CustomSetupTool/CustomSetupTool/resource.rc @@ -8,16 +8,53 @@ // Generated from the TEXTINCLUDE 2 resource. // #include "winres.h" -#include "../../../ProcessHacker/include/phappres.h" +#include "../../../../ProcessHacker/include/phappres.h" ///////////////////////////////////////////////////////////////////////////// #undef APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// -// English resources +// English (United States) resources #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) -LANGUAGE LANG_ENGLISH, SUBLANG_NEUTRAL +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""winres.h""\r\n" + "#include ""../../../../ProcessHacker/include/phappres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////// +// English (Australia) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENA) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_AUS #pragma code_page(1252) ///////////////////////////////////////////////////////////////////////////// @@ -96,9 +133,21 @@ EXSTYLE WS_EX_CONTROLPARENT FONT 8, "MS Shell Dlg 2", 400, 0, 0x1 BEGIN CONTROL "",IDC_PROJECT_ICON,"Static",SS_BLACKFRAME,271,15,92,75 - CONTROL "Setup failed to install Process Hacker.",IDC_MAINHEADER, - "Static",SS_SIMPLE | WS_GROUP,22,26,267,24 - LTEXT "Click Retry to try installing Process Hacker again or click Close to exit.",IDC_SUBHEADER,22,51,245,21 + CONTROL "Setup failed to install Process Hacker :(",IDC_MAINHEADER, + "Static",SS_SIMPLE | WS_GROUP,15,26,267,24 + LTEXT "Select Retry to try installing Process Hacker again or Cancel to exit.",IDC_SUBHEADER,15,51,245,34 +END + +IDD_DIALOG5 DIALOGEX 0, 0, 400, 225 +STYLE DS_SETFONT | DS_MODALFRAME | DS_NOFAILCREATE | WS_POPUP | WS_CAPTION | WS_SYSMENU +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg 2", 400, 0, 0x1 +BEGIN + LTEXT "Preparing installation...",IDC_INSTALL_STATUS,15,147,380,13 + CONTROL "",IDC_INSTALL_PROGRESS,"msctls_progress32",PBS_SMOOTH,15,164,370,11,WS_EX_CLIENTEDGE + CONTROL "",IDC_PROJECT_ICON,"Static",SS_BLACKFRAME,271,15,92,75 + LTEXT "Preparing installation...",IDC_MAINHEADER,15,26,259,24 + LTEXT "Preparing installation...",IDC_INSTALL_SUBSTATUS,15,184,370,32 END @@ -140,9 +189,17 @@ BEGIN IDD_ERROR, DIALOG BEGIN - LEFTMARGIN, 22 - RIGHTMARGIN, 378 - TOPMARGIN, 10 + LEFTMARGIN, 15 + RIGHTMARGIN, 385 + TOPMARGIN, 7 + BOTTOMMARGIN, 216 + END + + IDD_DIALOG5, DIALOG + BEGIN + LEFTMARGIN, 15 + RIGHTMARGIN, 385 + TOPMARGIN, 7 BOTTOMMARGIN, 216 END END @@ -166,53 +223,6 @@ IDI_ICON1 ICON "resources\\ProcessHacker.ico" IDB_PNG1 PNG "resources\\ProcessHacker.png" -#endif // English resources -///////////////////////////////////////////////////////////////////////////// - - -///////////////////////////////////////////////////////////////////////////// -// English (United States) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US -#pragma code_page(1252) - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -1 TEXTINCLUDE -BEGIN - "resource.h\0" -END - -2 TEXTINCLUDE -BEGIN - "#include ""winres.h""\r\n" - "#include ""../../../ProcessHacker/include/phappres.h""\r\n" - "\0" -END - -3 TEXTINCLUDE -BEGIN - "\r\n" - "\0" -END - -#endif // APSTUDIO_INVOKED - -#endif // English (United States) resources -///////////////////////////////////////////////////////////////////////////// - - -///////////////////////////////////////////////////////////////////////////// -// English (Australia) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENA) -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_AUS -#pragma code_page(1252) ///////////////////////////////////////////////////////////////////////////// // @@ -221,12 +231,6 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_AUS IDR_LICENCE_DATA RCDATA "resources\\LICENSE.txt" -#if defined(APSTUDIO_INVOKED) || defined(PH_BUILD_API) - -IDR_BIN_DATA RCDATA "..\\..\\..\\build\\output\\processhacker-build-bin.zip" - -#endif - #endif // English (Australia) resources ///////////////////////////////////////////////////////////////////////////// diff --git a/tools/CustomSetupTool/CustomSetupTool/resources/version.rc b/tools/CustomSetupTool/CustomSetupTool/resources/version.rc index 8eced112f05c..aad29825fe0b 100644 --- a/tools/CustomSetupTool/CustomSetupTool/resources/version.rc +++ b/tools/CustomSetupTool/CustomSetupTool/resources/version.rc @@ -1,8 +1,16 @@ +// Microsoft Visual C++ generated resource script. +// #include "../resource.h" #define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// #include "winres.h" -#include "../../../ProcessHacker/include/phappres.h" +#include "../../../../ProcessHacker/include/phappres.h" + +///////////////////////////////////////////////////////////////////////////// #undef APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// @@ -12,14 +20,51 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US #pragma code_page(1252) +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "../resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""winres.h""\r\n" + "#include ""../../../../ProcessHacker/include/phappres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////// +// English (Australia) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENA) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_AUS +#pragma code_page(1252) + ///////////////////////////////////////////////////////////////////////////// // // Version // VS_VERSION_INFO VERSIONINFO - FILEVERSION PHAPP_VERSION_NUMBER - PRODUCTVERSION PHAPP_VERSION_NUMBER + FILEVERSION 3,0,0,0 + PRODUCTVERSION 3,0,0,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -36,12 +81,12 @@ BEGIN BEGIN VALUE "CompanyName", "Process Hacker" VALUE "FileDescription", "Process Hacker Setup" - VALUE "FileVersion", PHAPP_VERSION_STRING + VALUE "FileVersion", "3.0.0.0" VALUE "InternalName", "Process Hacker Setup" VALUE "LegalCopyright", "Licensed under the GNU GPL, v3. Copyright (C) 2017" VALUE "OriginalFilename", "ProcessHackerSetup.exe" VALUE "ProductName", "Process Hacker Setup" - VALUE "ProductVersion", PHAPP_VERSION_STRING + VALUE "ProductVersion", "3.0.0.0" END END BLOCK "VarFileInfo" @@ -50,31 +95,26 @@ BEGIN END END -#ifdef APSTUDIO_INVOKED + ///////////////////////////////////////////////////////////////////////////// // -// TEXTINCLUDE +// RCDATA // -1 TEXTINCLUDE -BEGIN - "resource.h\0" -END +IDR_BIN_DATA RCDATA "../../../../build/output/processhacker-build-bin.zip" -2 TEXTINCLUDE -BEGIN - "#include ""winres.h""\r\n" - "#include ""../../../ProcessHacker/include/phappres.h""\r\n" - "\0" -END +#endif // English (Australia) resources +///////////////////////////////////////////////////////////////////////////// -3 TEXTINCLUDE -BEGIN - "\r\n" - "\0" -END -#endif // APSTUDIO_INVOKED -#endif // English (United States) resources +#ifndef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/tools/CustomSetupTool/CustomSetupTool/setup.c b/tools/CustomSetupTool/CustomSetupTool/setup.c index a53268c0c517..eb83f76e620f 100644 --- a/tools/CustomSetupTool/CustomSetupTool/setup.c +++ b/tools/CustomSetupTool/CustomSetupTool/setup.c @@ -556,11 +556,11 @@ VOID SetupUpgradeSettingsFile( settingsFilePath = PhGetKnownLocation(CSIDL_APPDATA, L"\\Process Hacker\\settings.xml"); oldSettingsFileName = PhGetKnownLocation(CSIDL_APPDATA, L"\\Process Hacker 2\\settings.xml"); - if (RtlDoesFileExists_U(settingsFilePath->Buffer)) - SetupDeleteDirectoryFile(settingsFilePath->Buffer); + if (!RtlDoesFileExists_U(settingsFilePath->Buffer)) + { + CopyFile(oldSettingsFileName->Buffer, settingsFilePath->Buffer, FALSE); + } - CopyFile(oldSettingsFileName->Buffer, settingsFilePath->Buffer, FALSE); - PhDereferenceObject(oldSettingsFileName); PhDereferenceObject(settingsFilePath); } \ No newline at end of file diff --git a/tools/CustomSetupTool/CustomSetupTool/uninstall.c b/tools/CustomSetupTool/CustomSetupTool/uninstall.c index 92acc4d711af..08c4009b0a16 100644 --- a/tools/CustomSetupTool/CustomSetupTool/uninstall.c +++ b/tools/CustomSetupTool/CustomSetupTool/uninstall.c @@ -60,13 +60,13 @@ NTSTATUS SetupUninstallBuild( // Remove the uninstaller. SetupDeleteUninstallFile(); + // Remove the ARP uninstall entry. + SetupDeleteUninstallKey(); + // Remove the previous installation. if (!RemoveDirectoryPath(PhGetString(SetupInstallPath))) goto CleanupExit; - // Remove the ARP uninstall entry. - SetupDeleteUninstallKey(); - ShowUninstallCompleteDialog(Context); return STATUS_SUCCESS; From d6b1d872fcf1afbd71fb7e3bb18f233918f6c612 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 23 May 2017 02:58:21 +1000 Subject: [PATCH 0155/2058] Updater: Fix crash --- plugins/Updater/updater.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/Updater/updater.c b/plugins/Updater/updater.c index eda63f54957e..f0ca93c4a37e 100644 --- a/plugins/Updater/updater.c +++ b/plugins/Updater/updater.c @@ -434,7 +434,7 @@ BOOLEAN QueryUpdateData( { PhInitializeStringBuilder(&sb, 0x100); - for (SIZE_T i = 0; i < Context->BuildMessage->Length; i++) + for (SIZE_T i = 0; i < Context->BuildMessage->Length / sizeof(WCHAR); i++) { if (Context->BuildMessage->Data[i] == '\n') PhAppendStringBuilder2(&sb, L"\r\n"); From d6dc974c2c405958705a96a7df2ab9f9b09ebd41 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 23 May 2017 05:20:14 +1000 Subject: [PATCH 0156/2058] Add web-setup to installer (build CustomSetupTool for web-setup, run build_release.cmd for full-setup) --- .../CustomSetupTool/download.c | 91 ++++---------- tools/CustomSetupTool/CustomSetupTool/error.c | 15 ++- .../CustomSetupTool/CustomSetupTool/extract.c | 27 +++- .../CustomSetupTool/include/appsup.h | 2 +- .../CustomSetupTool/include/setup.h | 110 +++++++--------- tools/CustomSetupTool/CustomSetupTool/main.c | 11 ++ tools/CustomSetupTool/CustomSetupTool/page1.c | 49 ++++---- tools/CustomSetupTool/CustomSetupTool/page2.c | 23 +++- tools/CustomSetupTool/CustomSetupTool/page3.c | 64 +++++----- tools/CustomSetupTool/CustomSetupTool/page4.c | 89 ++++++++----- tools/CustomSetupTool/CustomSetupTool/page5.c | 64 ++++------ tools/CustomSetupTool/CustomSetupTool/setup.c | 77 ++++++------ .../CustomSetupTool/uninstall.c | 10 +- .../CustomSetupTool/CustomSetupTool/update.c | 117 ++++++------------ 14 files changed, 357 insertions(+), 392 deletions(-) diff --git a/tools/CustomSetupTool/CustomSetupTool/download.c b/tools/CustomSetupTool/CustomSetupTool/download.c index 7d050109e1b8..9b6ee0885a3a 100644 --- a/tools/CustomSetupTool/CustomSetupTool/download.c +++ b/tools/CustomSetupTool/CustomSetupTool/download.c @@ -75,13 +75,13 @@ PPH_STRING UpdateWindowsString( } BOOLEAN ParseVersionString( - _Inout_ PPH_SETUP_DOWNLOAD_CONTEXT Context + _Inout_ PPH_SETUP_CONTEXT Context ) { PH_STRINGREF remaining, majorPart, minorPart, revisionPart; ULONG64 majorInteger = 0, minorInteger = 0, revisionInteger = 0; - //PhInitializeStringRef(&remaining, PhGetStringOrEmpty(Context->Version)); + PhInitializeStringRef(&remaining, PhGetStringOrEmpty(Context->Version)); PhSplitStringRefAtChar(&remaining, '.', &majorPart, &remaining); PhSplitStringRefAtChar(&remaining, '.', &minorPart, &remaining); @@ -91,9 +91,9 @@ BOOLEAN ParseVersionString( PhStringToInteger64(&minorPart, 10, &minorInteger); PhStringToInteger64(&revisionPart, 10, &revisionInteger); - //Context->MajorVersion = (ULONG)majorInteger; - //Context->MinorVersion = (ULONG)minorInteger; - //Context->RevisionVersion = (ULONG)revisionInteger; + Context->LatestMajorVersion = (ULONG)majorInteger; + Context->LatestMinorVersion = (ULONG)minorInteger; + Context->LatestRevisionVersion = (ULONG)revisionInteger; return TRUE; } @@ -163,7 +163,7 @@ json_object_ptr json_get_object( BOOLEAN SetupQueryUpdateData( - _Inout_ PPH_SETUP_DOWNLOAD_CONTEXT Context + _Inout_ PPH_SETUP_CONTEXT Context ) { BOOLEAN success = FALSE; @@ -196,7 +196,7 @@ BOOLEAN SetupQueryUpdateData( WINHTTP_OPTION_DECOMPRESSION, &httpFlags, sizeof(ULONG) - ); + ); } if (!(httpConnectionHandle = WinHttpConnect( @@ -213,7 +213,7 @@ BOOLEAN SetupQueryUpdateData( if (!(httpRequestHandle = WinHttpOpenRequest( httpConnectionHandle, NULL, - L"/processhacker/nightly.php?latest", + L"/processhacker/nightly.php?phsetup", NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, @@ -288,58 +288,15 @@ BOOLEAN SetupQueryUpdateData( Context->Signature = PhConvertUtf8ToUtf16(json_object_get_string(json_get_object(jsonObject, "sig"))); Context->ReleaseNotesUrl = PhConvertUtf8ToUtf16(json_object_get_string(json_get_object(jsonObject, "forum_url"))); Context->BinFileDownloadUrl = PhConvertUtf8ToUtf16(json_object_get_string(json_get_object(jsonObject, "bin_url"))); - Context->SetupFileDownloadUrl = PhConvertUtf8ToUtf16(json_object_get_string(json_get_object(jsonObject, "setup_url"))); - //Context->BuildMessage = PhConvertUtf8ToUtf16(GetJsonValueAsString(jsonObject, "message")); - - PH_STRINGREF remaining, majorPart, minorPart, revisionPart; - ULONG64 majorInteger = 0, minorInteger = 0, revisionInteger = 0; + //Context->SetupFileDownloadUrl = PhConvertUtf8ToUtf16(json_object_get_string(json_get_object(jsonObject, "setup_url"))); + //Context->BuildMessage = PhConvertUtf8ToUtf16(GetJsonValueAsString(jsonObject, "changelog")); - PhInitializeStringRef(&remaining, PhGetStringOrEmpty(Context->Version)); - - PhSplitStringRefAtChar(&remaining, '.', &majorPart, &remaining); - PhSplitStringRefAtChar(&remaining, '.', &minorPart, &remaining); - PhSplitStringRefAtChar(&remaining, '.', &revisionPart, &remaining); - - PhStringToInteger64(&majorPart, 10, &majorInteger); - PhStringToInteger64(&minorPart, 10, &minorInteger); - PhStringToInteger64(&revisionPart, 10, &revisionInteger); - - Context->LatestMajorVersion = (ULONG)majorInteger; - Context->LatestMinorVersion = (ULONG)minorInteger; - Context->LatestRevisionVersion = (ULONG)revisionInteger; - - /* Context->Version = PhConvertUtf8ToUtf16(GetJsonValueAsString(jsonObject, "version")); - Context->RevVersion = PhConvertUtf8ToUtf16(GetJsonValueAsString(jsonObject, "version")); - Context->RelDate = PhConvertUtf8ToUtf16(GetJsonValueAsString(jsonObject, "updated")); - Context->Size = PhFormatSize(GetJsonValueAsUlong(jsonObject, "size"), 2); - Context->Hash = PhConvertUtf8ToUtf16(GetJsonValueAsString(jsonObject, "hash_setup")); - Context->Signature = PhConvertUtf8ToUtf16(GetJsonValueAsString(jsonObject, "sig")); - Context->ReleaseNotesUrl = PhConvertUtf8ToUtf16(GetJsonValueAsString(jsonObject, "forum_url")); - Context->SetupFileDownloadUrl = PhConvertUtf8ToUtf16(GetJsonValueAsString(jsonObject, "setup_url")); - Context->BuildMessage = PhConvertUtf8ToUtf16(GetJsonValueAsString(jsonObject, "message")); - - PH_STRING_BUILDER sb; - PhInitializeStringBuilder(&sb, 0x100); - for (size_t i = 0; i < Context->BuildMessage->Length; i++) - { - if (Context->BuildMessage->Data[i] == '\n') - PhAppendFormatStringBuilder(&sb, L"\r\n"); - else - PhAppendCharStringBuilder(&sb, Context->BuildMessage->Data[i]); - } - PhMoveReference(&Context->BuildMessage, PhFinalStringBuilderString(&sb)); - - CleanupJsonParser(jsonObject); - - if (PhIsNullOrEmptyString(Context->Signature)) + if (PhIsNullOrEmptyString(Context->Version)) goto CleanupExit; - if (!ParseVersionString(Context)) goto CleanupExit; - if (PhIsNullOrEmptyString(Context->Version)) - goto CleanupExit; - if (PhIsNullOrEmptyString(Context->RevVersion)) + if (PhIsNullOrEmptyString(Context->Signature)) goto CleanupExit; if (PhIsNullOrEmptyString(Context->RelDate)) goto CleanupExit; @@ -349,9 +306,9 @@ BOOLEAN SetupQueryUpdateData( goto CleanupExit; if (PhIsNullOrEmptyString(Context->ReleaseNotesUrl)) goto CleanupExit; - if (PhIsNullOrEmptyString(Context->SetupFileDownloadUrl)) - goto CleanupExit;*/ - + if (PhIsNullOrEmptyString(Context->BinFileDownloadUrl)) + goto CleanupExit; + success = TRUE; CleanupExit: @@ -378,7 +335,7 @@ BOOLEAN SetupQueryUpdateData( } BOOLEAN UpdateDownloadUpdateData( - _In_ PPH_SETUP_DOWNLOAD_CONTEXT Context + _In_ PPH_SETUP_CONTEXT Context ) { BOOLEAN downloadSuccess = FALSE; @@ -467,13 +424,13 @@ BOOLEAN UpdateDownloadUpdateData( httpUrlComponents.dwUrlPathLength = (ULONG)-1; if (!WinHttpCrackUrl( - PhGetString(Context->SetupFileDownloadUrl), + PhGetString(Context->BinFileDownloadUrl), 0, 0, &httpUrlComponents )) { - //context->ErrorCode = GetLastError(); + Context->ErrorCode = GetLastError(); goto CleanupExit; } @@ -503,7 +460,7 @@ BOOLEAN UpdateDownloadUpdateData( 0 ))) { - //context->ErrorCode = GetLastError(); + Context->ErrorCode = GetLastError(); goto CleanupExit; } @@ -520,7 +477,7 @@ BOOLEAN UpdateDownloadUpdateData( 0 ))) { - //context->ErrorCode = GetLastError(); + Context->ErrorCode = GetLastError(); goto CleanupExit; } @@ -534,7 +491,7 @@ BOOLEAN UpdateDownloadUpdateData( WINHTTP_FLAG_REFRESH | (httpUrlComponents.nScheme == INTERNET_SCHEME_HTTPS ? WINHTTP_FLAG_SECURE : 0) ))) { - //context->ErrorCode = GetLastError(); + Context->ErrorCode = GetLastError(); goto CleanupExit; } @@ -554,13 +511,13 @@ BOOLEAN UpdateDownloadUpdateData( 0 )) { - // context->ErrorCode = GetLastError(); + Context->ErrorCode = GetLastError(); goto CleanupExit; } if (!WinHttpReceiveResponse(httpRequestHandle, NULL)) { - //context->ErrorCode = GetLastError(); + Context->ErrorCode = GetLastError(); goto CleanupExit; } else @@ -586,7 +543,7 @@ BOOLEAN UpdateDownloadUpdateData( 0 )) { - //context->ErrorCode = GetLastError(); + Context->ErrorCode = GetLastError(); goto CleanupExit; } diff --git a/tools/CustomSetupTool/CustomSetupTool/error.c b/tools/CustomSetupTool/CustomSetupTool/error.c index ec3eb5ff1eb1..024920e772f7 100644 --- a/tools/CustomSetupTool/CustomSetupTool/error.c +++ b/tools/CustomSetupTool/CustomSetupTool/error.c @@ -29,7 +29,20 @@ INT_PTR CALLBACK SetupErrorPage_WndProc( _Inout_ LPARAM lParam ) { - PPH_SETUP_CONTEXT context = (PPH_SETUP_CONTEXT)GetProp(GetParent(hwndDlg), L"SetupContext"); + PPH_SETUP_CONTEXT context = NULL; + + if (uMsg == WM_INITDIALOG) + { + context = GetProp(GetParent(hwndDlg), L"SetupContext"); + SetProp(hwndDlg, L"Context", (HANDLE)context); + } + else + { + context = (PPH_SETUP_CONTEXT)GetProp(hwndDlg, L"Context"); + } + + if (context == NULL) + return FALSE; switch (uMsg) { diff --git a/tools/CustomSetupTool/CustomSetupTool/extract.c b/tools/CustomSetupTool/CustomSetupTool/extract.c index 405c429a6cb0..6a1709ea3746 100644 --- a/tools/CustomSetupTool/CustomSetupTool/extract.c +++ b/tools/CustomSetupTool/CustomSetupTool/extract.c @@ -50,7 +50,7 @@ PVOID GetZipResourceData( } BOOLEAN SetupExtractBuild( - _In_ HWND Context + _In_ PPH_SETUP_CONTEXT Context ) { mz_bool status = MZ_FALSE; @@ -58,17 +58,32 @@ BOOLEAN SetupExtractBuild( ULONG64 currentLength = 0; mz_zip_archive zip_archive = { 0 }; PPH_STRING extractPath = NULL; - PVOID resourceBuffer; - ULONG resourceLength; SYSTEM_INFO info; GetNativeSystemInfo(&info); +#ifdef PH_BUILD_API + ULONG resourceLength; + PVOID resourceBuffer; + if (!(resourceBuffer = GetZipResourceData(&resourceLength))) goto CleanupExit; if (!(status = mz_zip_reader_init_mem(&zip_archive, resourceBuffer, resourceLength, 0))) goto CleanupExit; +#else + PPH_BYTES zipPathUtf8; + + if (!Context->SetupFilePath) + goto CleanupExit; + + zipPathUtf8 = PhConvertUtf16ToUtf8(PhGetString(Context->SetupFilePath)); + + if (!(status = mz_zip_reader_init_file(&zip_archive, zipPathUtf8->Buffer, 0))) + goto CleanupExit; + + PhDereferenceObject(zipPathUtf8); +#endif // Remove outdated files //for (ULONG i = 0; i < ARRAYSIZE(SetupRemoveFiles); i++) @@ -98,7 +113,7 @@ BOOLEAN SetupExtractBuild( } InterlockedExchange64(&ExtractTotalLength, totalLength); - SendMessage(Context, WM_START_SETUP, 0, 0); + SendMessage(Context->ExtractPageHandle, WM_START_SETUP, 0, 0); for (mz_uint i = 0; i < mz_zip_reader_get_num_files(&zip_archive); i++) { @@ -151,7 +166,7 @@ BOOLEAN SetupExtractBuild( if ((zipFileCrc32 = mz_crc32(zipFileCrc32, buffer, bufferLength)) != zipFileStat.m_crc32) goto CleanupExit; - extractPath = PhConcatStrings(3, PhGetString(SetupInstallPath), L"\\", PhGetString(fileName)); + extractPath = PhConcatStrings(3, PhGetString(Context->SetupInstallPath), L"\\", PhGetString(fileName)); if (fullSetupPath = PhGetFullPath(extractPath->Buffer, &indexOfFileName)) { @@ -212,7 +227,7 @@ BOOLEAN SetupExtractBuild( InterlockedExchange64(&ExtractCurrentLength, currentLength); - SendMessage(Context, WM_UPDATE_SETUP, 0, (LPARAM)PhGetBaseName(extractPath)); + SendMessage(Context->ExtractPageHandle, WM_UPDATE_SETUP, 0, (LPARAM)PhGetBaseName(extractPath)); NtClose(fileHandle); mz_free(buffer); diff --git a/tools/CustomSetupTool/CustomSetupTool/include/appsup.h b/tools/CustomSetupTool/CustomSetupTool/include/appsup.h index e74fa065ef9f..8b71866e1cdf 100644 --- a/tools/CustomSetupTool/CustomSetupTool/include/appsup.h +++ b/tools/CustomSetupTool/CustomSetupTool/include/appsup.h @@ -36,7 +36,7 @@ typedef struct _SETUP_REMOVE_FILE PWSTR FileName; } SETUP_REMOVE_FILE, *PSETUP_REMOVE_FILE; -VOID SetupFindInstallDirectory( +PPH_STRING SetupFindInstallDirectory( VOID ); diff --git a/tools/CustomSetupTool/CustomSetupTool/include/setup.h b/tools/CustomSetupTool/CustomSetupTool/include/setup.h index 6c9f40621a2d..462141663909 100644 --- a/tools/CustomSetupTool/CustomSetupTool/include/setup.h +++ b/tools/CustomSetupTool/CustomSetupTool/include/setup.h @@ -64,17 +64,6 @@ #define WM_END_SETUP (WM_APP + 3) extern HANDLE MutantHandle; -extern PPH_STRING SetupInstallPath; -extern BOOLEAN SetupCreateDesktopShortcut; -extern BOOLEAN SetupCreateDesktopShortcutAllUsers; -extern BOOLEAN SetupCreateDefaultTaskManager; -extern BOOLEAN SetupCreateSystemStartup; -extern BOOLEAN SetupCreateMinimizedSystemStartup; -extern BOOLEAN SetupInstallDebuggingTools; -extern BOOLEAN SetupInstallPeViewAssociations; -extern BOOLEAN SetupInstallKphService; -extern BOOLEAN SetupResetSettings; -extern BOOLEAN SetupStartAppAfterExit; typedef enum _SETUP_COMMAND_TYPE { @@ -86,12 +75,34 @@ typedef enum _SETUP_COMMAND_TYPE typedef struct _PH_SETUP_CONTEXT { - HWND WindowHandle; HWND PropSheetHandle; + HWND PropSheetBackHandle; + HWND PropSheetForwardHandle; + HWND PropSheetCancelHandle; + + HWND WelcomePageHandle; + HWND EulaPageHandle; + HWND ConfigPageHandle; + HWND DownloadPageHandle; + HWND ExtractPageHandle; + HWND FinalPageHandle; + HWND ErrorPageHandle; HICON IconSmallHandle; HICON IconLargeHandle; + PPH_STRING SetupInstallPath; + BOOLEAN SetupCreateDesktopShortcut; + BOOLEAN SetupCreateDesktopShortcutAllUsers; + BOOLEAN SetupCreateDefaultTaskManager; + BOOLEAN SetupCreateSystemStartup; + BOOLEAN SetupCreateMinimizedSystemStartup; + BOOLEAN SetupInstallDebuggingTools; + BOOLEAN SetupInstallPeViewAssociations; + BOOLEAN SetupInstallKphService; + BOOLEAN SetupResetSettings; + BOOLEAN SetupStartAppAfterExit; + ULONG ErrorCode; PPH_STRING Version; PPH_STRING RevVersion; @@ -102,8 +113,21 @@ typedef struct _PH_SETUP_CONTEXT PPH_STRING ReleaseNotesUrl; PPH_STRING BinFileDownloadUrl; - PPH_STRING SetupFileDownloadUrl; + //PPH_STRING SetupFileDownloadUrl; PPH_STRING SetupFilePath; + + HWND MainHeaderHandle; + HWND StatusHandle; + HWND SubStatusHandle; + HWND ProgressHandle; + + BOOLEAN SetupRunning; + ULONG CurrentMajorVersion; + ULONG CurrentMinorVersion; + ULONG CurrentRevisionVersion; + ULONG LatestMajorVersion; + ULONG LatestMinorVersion; + ULONG LatestRevisionVersion; } PH_SETUP_CONTEXT, *PPH_SETUP_CONTEXT; VOID SetupLoadImage( @@ -155,21 +179,13 @@ INT_PTR CALLBACK SetupErrorPage_WndProc( // page4.c -typedef struct _SETUP_PROGRESS_THREAD -{ - HWND DialogHandle; - HWND PropSheetHandle; - HICON PropSheetIcon; -} SETUP_PROGRESS_THREAD, *PSETUP_PROGRESS_THREAD; - -extern BOOLEAN SetupRunning; extern ULONG64 ExtractCurrentLength; extern ULONG64 ExtractTotalLength; // setup.c -VOID SetupInstallKph( - VOID +VOID SetupStartKph( + _In_ PPH_SETUP_CONTEXT Context ); ULONG SetupUninstallKph( @@ -177,7 +193,7 @@ ULONG SetupUninstallKph( ); NTSTATUS SetupCreateUninstallKey( - VOID + _In_ PPH_SETUP_CONTEXT Context ); NTSTATUS SetupDeleteUninstallKey( @@ -185,23 +201,23 @@ NTSTATUS SetupDeleteUninstallKey( ); VOID SetupSetWindowsOptions( - VOID + _In_ PPH_SETUP_CONTEXT Context ); VOID SetupDeleteWindowsOptions( - VOID + _In_ PPH_SETUP_CONTEXT Context ); VOID SetupCreateUninstallFile( - VOID + _In_ PPH_SETUP_CONTEXT Context ); VOID SetupDeleteUninstallFile( - VOID + _In_ PPH_SETUP_CONTEXT Context ); BOOLEAN SetupExecuteProcessHacker( - _In_ HWND Parent + _In_ PPH_SETUP_CONTEXT Context ); VOID SetupUpgradeSettingsFile( @@ -210,48 +226,18 @@ VOID SetupUpgradeSettingsFile( // download.c -typedef struct _PH_SETUP_DOWNLOAD_CONTEXT -{ - HWND DialogHandle; - HWND PropSheetHandle; - HWND MainHeaderHandle; - HWND StatusHandle; - HWND SubStatusHandle; - HWND ProgressHandle; - - ULONG CurrentMajorVersion; - ULONG CurrentMinorVersion; - ULONG CurrentRevisionVersion; - ULONG LatestMajorVersion; - ULONG LatestMinorVersion; - ULONG LatestRevisionVersion; - - ULONG ErrorCode; - PPH_STRING Version; - PPH_STRING RevVersion; - PPH_STRING RelDate; - PPH_STRING Size; - PPH_STRING Hash; - PPH_STRING Signature; - PPH_STRING ReleaseNotesUrl; - - PPH_STRING BinFileDownloadUrl; - PPH_STRING SetupFileDownloadUrl; - PPH_STRING SetupFilePath; -} PH_SETUP_DOWNLOAD_CONTEXT, *PPH_SETUP_DOWNLOAD_CONTEXT; - BOOLEAN SetupQueryUpdateData( - _In_ PPH_SETUP_DOWNLOAD_CONTEXT Context + _In_ PPH_SETUP_CONTEXT Context ); BOOLEAN UpdateDownloadUpdateData( - _In_ PPH_SETUP_DOWNLOAD_CONTEXT Context + _In_ PPH_SETUP_CONTEXT Context ); // extract.c BOOLEAN SetupExtractBuild( - _In_ HWND Context + _In_ PPH_SETUP_CONTEXT Context ); // update.c diff --git a/tools/CustomSetupTool/CustomSetupTool/main.c b/tools/CustomSetupTool/CustomSetupTool/main.c index fe2fb4e1d8a1..7d0f039d82c2 100644 --- a/tools/CustomSetupTool/CustomSetupTool/main.c +++ b/tools/CustomSetupTool/CustomSetupTool/main.c @@ -99,8 +99,19 @@ INT CALLBACK MainPropSheet_Callback( context = PhAllocate(sizeof(PH_SETUP_CONTEXT)); memset(context, 0, sizeof(PH_SETUP_CONTEXT)); + + context->CurrentMajorVersion = PHAPP_VERSION_MAJOR; + context->CurrentMinorVersion = PHAPP_VERSION_MINOR; + context->CurrentRevisionVersion = PHAPP_VERSION_REVISION; context->PropSheetHandle = hwndDlg; + context->PropSheetBackHandle = GetDlgItem(hwndDlg, IDC_PROPSHEET_BACK); + context->PropSheetForwardHandle = GetDlgItem(hwndDlg, IDC_PROPSHEET_NEXT); + context->PropSheetCancelHandle = GetDlgItem(hwndDlg, IDC_PROPSHEET_CANCEL); + + SetupInitializeFont(context->PropSheetBackHandle, -12, FW_NORMAL); + SetupInitializeFont(context->PropSheetForwardHandle, -12, FW_NORMAL); + SetupInitializeFont(context->PropSheetCancelHandle, -12, FW_NORMAL); SetProp(hwndDlg, L"SetupContext", (HANDLE)context); } diff --git a/tools/CustomSetupTool/CustomSetupTool/page1.c b/tools/CustomSetupTool/CustomSetupTool/page1.c index 8c98be740860..3d8dbf6fa0d2 100644 --- a/tools/CustomSetupTool/CustomSetupTool/page1.c +++ b/tools/CustomSetupTool/CustomSetupTool/page1.c @@ -22,23 +22,16 @@ #include -VOID SetupPropSheetParent( - _In_ HWND hwndDlg +VOID SetupPropSheetCenterWindow( + _In_ PPH_SETUP_CONTEXT Context ) { - HWND parent = GetParent(hwndDlg); - - // Center the property sheet on the desktop - PhCenterWindow(parent, NULL); - SetForegroundWindow(parent); - - // Set the fonts for the Property Sheet buttons - SetupInitializeFont(GetDlgItem(parent, IDC_PROPSHEET_BACK), -12, FW_NORMAL); - SetupInitializeFont(GetDlgItem(parent, IDC_PROPSHEET_NEXT), -12, FW_NORMAL); - SetupInitializeFont(GetDlgItem(parent, IDC_PROPSHEET_CANCEL), -12, FW_NORMAL); + // Center the PropertySheet on the desktop. + PhCenterWindow(Context->PropSheetHandle, NULL); + SetForegroundWindow(Context->PropSheetHandle); } -static VOID LoadSetupIcons( +static VOID SetupLoadIcons( _In_ HWND hwndDlg ) { @@ -73,15 +66,30 @@ INT_PTR CALLBACK SetupPropPage1_WndProc( _Inout_ LPARAM lParam ) { - PPH_SETUP_CONTEXT context = (PPH_SETUP_CONTEXT)GetProp(GetParent(hwndDlg), L"SetupContext"); + PPH_SETUP_CONTEXT context = NULL; + + if (uMsg == WM_INITDIALOG) + { + context = GetProp(GetParent(hwndDlg), L"SetupContext"); + SetProp(hwndDlg, L"Context", (HANDLE)context); + } + else + { + context = (PPH_SETUP_CONTEXT)GetProp(hwndDlg, L"Context"); + } + + if (context == NULL) + return FALSE; switch (uMsg) { case WM_INITDIALOG: { - SetupPropSheetParent(hwndDlg); + context->WelcomePageHandle = hwndDlg; + + SetupPropSheetCenterWindow(context); - LoadSetupIcons(hwndDlg); + SetupLoadIcons(hwndDlg); SetupLoadImage(GetDlgItem(hwndDlg, IDC_PROJECT_ICON), MAKEINTRESOURCE(IDB_PNG1)); SetupInitializeFont(GetDlgItem(hwndDlg, IDC_MAINHEADER), -18, FW_SEMIBOLD); SetupInitializeFont(GetDlgItem(hwndDlg, IDC_SUBHEADER), 0, FW_NORMAL); @@ -102,21 +110,12 @@ INT_PTR CALLBACK SetupPropPage1_WndProc( { // Reset the button state. PropSheet_SetWizButtons(context->PropSheetHandle, PSWIZB_NEXT); - - // Hide the back button. - //ShowWindow(GetDlgItem(context->PropSheetHandle, IDC_PROPSHEET_BACK), SW_HIDE); - - // HACK: Focus the next button (reset after changing button state). - PostMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(context->PropSheetHandle, IDC_PROPSHEET_NEXT), TRUE); } break; case PSN_KILLACTIVE: { // Enable the back button. PropSheet_SetWizButtons(context->PropSheetHandle, PSWIZB_NEXT | PSWIZB_BACK); - - // Show the back button. - //ShowWindow(GetDlgItem(context->PropSheetHandle, IDC_PROPSHEET_BACK), SW_SHOW); } break; } diff --git a/tools/CustomSetupTool/CustomSetupTool/page2.c b/tools/CustomSetupTool/CustomSetupTool/page2.c index a987b93b5c80..a756f9f1a836 100644 --- a/tools/CustomSetupTool/CustomSetupTool/page2.c +++ b/tools/CustomSetupTool/CustomSetupTool/page2.c @@ -27,7 +27,20 @@ INT_PTR CALLBACK SetupPropPage2_WndProc( _Inout_ LPARAM lParam ) { - PPH_SETUP_CONTEXT context = (PPH_SETUP_CONTEXT)GetProp(GetParent(hwndDlg), L"SetupContext"); + PPH_SETUP_CONTEXT context = NULL; + + if (uMsg == WM_INITDIALOG) + { + context = GetProp(GetParent(hwndDlg), L"SetupContext"); + SetProp(hwndDlg, L"Context", (HANDLE)context); + } + else + { + context = (PPH_SETUP_CONTEXT)GetProp(hwndDlg, L"Context"); + } + + if (context == NULL) + return FALSE; switch (uMsg) { @@ -64,15 +77,13 @@ INT_PTR CALLBACK SetupPropPage2_WndProc( { case PSN_SETACTIVE: { - PostMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(context->PropSheetHandle, IDC_PROPSHEET_NEXT), TRUE); - - // Disable the Next button - //PropSheet_SetWizButtons(context->PropSheetHandle, PSWIZB_BACK); + // HACK: Prevent the textbox text from being selected (temp fix). + PostMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)context->PropSheetForwardHandle, TRUE); } break; case PSN_QUERYINITIALFOCUS: { - SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, (LPARAM)GetDlgItem(context->PropSheetHandle, IDC_PROPSHEET_CANCEL)); + SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, (LPARAM)context->PropSheetCancelHandle); } return TRUE; } diff --git a/tools/CustomSetupTool/CustomSetupTool/page3.c b/tools/CustomSetupTool/CustomSetupTool/page3.c index 800f73b38a39..b4dbe1e2adb2 100644 --- a/tools/CustomSetupTool/CustomSetupTool/page3.c +++ b/tools/CustomSetupTool/CustomSetupTool/page3.c @@ -22,18 +22,6 @@ #include -PPH_STRING SetupInstallPath = NULL; -BOOLEAN SetupCreateDesktopShortcut = FALSE; -BOOLEAN SetupCreateDesktopShortcutAllUsers = FALSE; -BOOLEAN SetupCreateDefaultTaskManager = FALSE; -BOOLEAN SetupCreateSystemStartup = FALSE; -BOOLEAN SetupCreateMinimizedSystemStartup = FALSE; -BOOLEAN SetupInstallDebuggingTools = FALSE; -BOOLEAN SetupInstallPeViewAssociations = FALSE; -BOOLEAN SetupInstallKphService = FALSE; -BOOLEAN SetupResetSettings = FALSE; -BOOLEAN SetupStartAppAfterExit = FALSE; - INT_PTR CALLBACK SetupPropPage3_WndProc( _In_ HWND hwndDlg, _In_ UINT uMsg, @@ -41,14 +29,25 @@ INT_PTR CALLBACK SetupPropPage3_WndProc( _Inout_ LPARAM lParam ) { - PPH_SETUP_CONTEXT context = (PPH_SETUP_CONTEXT)GetProp(GetParent(hwndDlg), L"SetupContext"); + PPH_SETUP_CONTEXT context = NULL; + + if (uMsg == WM_INITDIALOG) + { + context = GetProp(GetParent(hwndDlg), L"SetupContext"); + SetProp(hwndDlg, L"Context", (HANDLE)context); + } + else + { + context = (PPH_SETUP_CONTEXT)GetProp(hwndDlg, L"Context"); + } + + if (context == NULL) + return FALSE; switch (uMsg) { case WM_INITDIALOG: { - SetupFindInstallDirectory(); - SetupInitializeFont(GetDlgItem(hwndDlg, IDC_MAINHEADER), -17, FW_SEMIBOLD); SetupInitializeFont(GetDlgItem(hwndDlg, IDC_SUBHEADER), -12, FW_NORMAL); SetupInitializeFont(GetDlgItem(hwndDlg, IDC_STATIC1), -12, FW_NORMAL); @@ -66,7 +65,9 @@ INT_PTR CALLBACK SetupPropPage3_WndProc( SetupInitializeFont(GetDlgItem(hwndDlg, IDC_DBGTOOLS_CHECK), -12, FW_NORMAL); SetupInitializeFont(GetDlgItem(hwndDlg, IDC_RESET_CHECK), -12, FW_NORMAL); - SetDlgItemText(hwndDlg, IDC_INSTALL_DIRECTORY, PhGetString(SetupInstallPath)); + context->SetupInstallPath = SetupFindInstallDirectory(); + + SetDlgItemText(hwndDlg, IDC_INSTALL_DIRECTORY, PhGetString(context->SetupInstallPath)); Button_SetCheck(GetDlgItem(hwndDlg, IDC_SHORTCUT_CHECK), TRUE); Button_SetCheck(GetDlgItem(hwndDlg, IDC_SHORTCUT_ALL_CHECK), TRUE); //Button_SetCheck(GetDlgItem(hwndDlg, IDC_KPH_CHECK), TRUE); @@ -96,8 +97,8 @@ INT_PTR CALLBACK SetupPropPage3_WndProc( PhFreeFileDialog(fileDialog); - PhSwapReference(&SetupInstallPath, fileDialogFolderPath); - SetDlgItemText(hwndDlg, IDC_INSTALL_DIRECTORY, PhGetStringOrEmpty(SetupInstallPath)); + PhSwapReference(&context->SetupInstallPath, fileDialogFolderPath); + SetDlgItemText(hwndDlg, IDC_INSTALL_DIRECTORY, PhGetStringOrEmpty(context->SetupInstallPath)); } } break; @@ -127,25 +128,24 @@ INT_PTR CALLBACK SetupPropPage3_WndProc( { case PSN_WIZNEXT: { - SetupInstallPath = PhGetWindowText(GetDlgItem(hwndDlg, IDC_INSTALL_DIRECTORY)); - SetupCreateDesktopShortcut = Button_GetCheck(GetDlgItem(hwndDlg, IDC_SHORTCUT_CHECK)) == BST_CHECKED; - SetupCreateDesktopShortcutAllUsers = Button_GetCheck(GetDlgItem(hwndDlg, IDC_SHORTCUT_ALL_CHECK)) == BST_CHECKED; - SetupCreateDefaultTaskManager = Button_GetCheck(GetDlgItem(hwndDlg, IDC_TASKMANAGER_CHECK)) == BST_CHECKED; - SetupCreateSystemStartup = Button_GetCheck(GetDlgItem(hwndDlg, IDC_STARTUP_CHECK)) == BST_CHECKED; - SetupCreateMinimizedSystemStartup = Button_GetCheck(GetDlgItem(hwndDlg, IDC_STARTMIN_CHECK)) == BST_CHECKED; - SetupInstallDebuggingTools = Button_GetCheck(GetDlgItem(hwndDlg, IDC_DBGTOOLS_CHECK)) == BST_CHECKED; - SetupInstallPeViewAssociations = Button_GetCheck(GetDlgItem(hwndDlg, IDC_PEVIEW_CHECK)) == BST_CHECKED; - SetupInstallKphService = Button_GetCheck(GetDlgItem(hwndDlg, IDC_KPH_CHECK)) == BST_CHECKED; - SetupResetSettings = Button_GetCheck(GetDlgItem(hwndDlg, IDC_RESET_CHECK)) == BST_CHECKED; - SetupStartAppAfterExit = Button_GetCheck(GetDlgItem(hwndDlg, IDC_PHSTART_CHECK)) == BST_CHECKED; + context->SetupInstallPath = PhGetWindowText(GetDlgItem(hwndDlg, IDC_INSTALL_DIRECTORY)); + context->SetupCreateDesktopShortcut = Button_GetCheck(GetDlgItem(hwndDlg, IDC_SHORTCUT_CHECK)) == BST_CHECKED; + context->SetupCreateDesktopShortcutAllUsers = Button_GetCheck(GetDlgItem(hwndDlg, IDC_SHORTCUT_ALL_CHECK)) == BST_CHECKED; + context->SetupCreateDefaultTaskManager = Button_GetCheck(GetDlgItem(hwndDlg, IDC_TASKMANAGER_CHECK)) == BST_CHECKED; + context->SetupCreateSystemStartup = Button_GetCheck(GetDlgItem(hwndDlg, IDC_STARTUP_CHECK)) == BST_CHECKED; + context->SetupCreateMinimizedSystemStartup = Button_GetCheck(GetDlgItem(hwndDlg, IDC_STARTMIN_CHECK)) == BST_CHECKED; + context->SetupInstallDebuggingTools = Button_GetCheck(GetDlgItem(hwndDlg, IDC_DBGTOOLS_CHECK)) == BST_CHECKED; + context->SetupInstallPeViewAssociations = Button_GetCheck(GetDlgItem(hwndDlg, IDC_PEVIEW_CHECK)) == BST_CHECKED; + context->SetupInstallKphService = Button_GetCheck(GetDlgItem(hwndDlg, IDC_KPH_CHECK)) == BST_CHECKED; + context->SetupResetSettings = Button_GetCheck(GetDlgItem(hwndDlg, IDC_RESET_CHECK)) == BST_CHECKED; + context->SetupStartAppAfterExit = Button_GetCheck(GetDlgItem(hwndDlg, IDC_PHSTART_CHECK)) == BST_CHECKED; #ifdef PH_BUILD_API SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, (LPARAM)IDD_DIALOG4); -#else - SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, (LPARAM)IDD_DIALOG5); + return TRUE; #endif } - return TRUE; + break; case PSN_QUERYINITIALFOCUS: SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, (LPARAM)GetDlgItem(hwndDlg, IDC_FOLDER_BROWSE)); return TRUE; diff --git a/tools/CustomSetupTool/CustomSetupTool/page4.c b/tools/CustomSetupTool/CustomSetupTool/page4.c index f0984811c876..40900e620fa1 100644 --- a/tools/CustomSetupTool/CustomSetupTool/page4.c +++ b/tools/CustomSetupTool/CustomSetupTool/page4.c @@ -27,7 +27,7 @@ ULONG64 ExtractCurrentLength = 0; ULONG64 ExtractTotalLength = 0; NTSTATUS SetupProgressThread( - _In_ PSETUP_PROGRESS_THREAD Context + _In_ PPH_SETUP_CONTEXT Context ) { //if (SetupInstallDebuggingTools) @@ -42,39 +42,37 @@ NTSTATUS SetupProgressThread( goto CleanupExit; // Create the install folder path. - if (!CreateDirectoryPath(PhGetString(SetupInstallPath))) + if (!CreateDirectoryPath(PhGetString(Context->SetupInstallPath))) goto CleanupExit; // Upgrade the 2.x settings file. SetupUpgradeSettingsFile(); // Remove the previous installation. - if (SetupResetSettings) - RemoveDirectoryPath(PhGetString(SetupInstallPath)); + if (Context->SetupResetSettings) + RemoveDirectoryPath(PhGetString(Context->SetupInstallPath)); // Create the ARP uninstall entries. - SetupCreateUninstallKey(); + SetupCreateUninstallKey(Context); // Create the uninstaller. - SetupCreateUninstallFile(); + SetupCreateUninstallFile(Context); // Create autorun and shortcuts. - SetupSetWindowsOptions(); + SetupSetWindowsOptions(Context); // Setup new installation. - if (!SetupExtractBuild(Context->DialogHandle)) + if (!SetupExtractBuild(Context)) goto CleanupExit; // Install updated kernel driver - if (SetupInstallKphService) - SetupInstallKph(); + if (Context->SetupInstallKphService) + SetupStartKph(Context); - PostMessage(Context->DialogHandle, WM_END_SETUP, 0, 0); - PhDereferenceObject(Context); + PostMessage(Context->ExtractPageHandle, WM_END_SETUP, 0, 0); return STATUS_SUCCESS; CleanupExit: PostMessage(Context->PropSheetHandle, PSM_SETCURSELID, 0, IDD_ERROR); - PhDereferenceObject(Context); return STATUS_FAIL_CHECK; } @@ -85,12 +83,27 @@ INT_PTR CALLBACK SetupPropPage4_WndProc( _Inout_ LPARAM lParam ) { - PPH_SETUP_CONTEXT context = (PPH_SETUP_CONTEXT)GetProp(GetParent(hwndDlg), L"SetupContext"); + PPH_SETUP_CONTEXT context = NULL; + + if (uMsg == WM_INITDIALOG) + { + context = GetProp(GetParent(hwndDlg), L"SetupContext"); + SetProp(hwndDlg, L"Context", (HANDLE)context); + } + else + { + context = (PPH_SETUP_CONTEXT)GetProp(hwndDlg, L"Context"); + } + + if (context == NULL) + return FALSE; switch (uMsg) { case WM_INITDIALOG: { + context->ExtractPageHandle = hwndDlg; + SetupLoadImage(GetDlgItem(hwndDlg, IDC_PROJECT_ICON), MAKEINTRESOURCE(IDB_PNG1)); SetupInitializeFont(GetDlgItem(hwndDlg, IDC_MAINHEADER), -17, FW_SEMIBOLD); SetupInitializeFont(GetDlgItem(hwndDlg, IDC_SUBHEADER), -12, FW_NORMAL); @@ -122,7 +135,15 @@ INT_PTR CALLBACK SetupPropPage4_WndProc( case PSN_SETACTIVE: { HANDLE threadHandle; - PSETUP_PROGRESS_THREAD progress; + + context->MainHeaderHandle = GetDlgItem(hwndDlg, IDC_MAINHEADER); + context->StatusHandle = GetDlgItem(hwndDlg, IDC_INSTALL_STATUS); + context->SubStatusHandle = GetDlgItem(hwndDlg, IDC_INSTALL_SUBSTATUS); + context->ProgressHandle = GetDlgItem(hwndDlg, IDC_INSTALL_PROGRESS); + + SetWindowText(context->MainHeaderHandle, L"Installing..."); + SetWindowText(context->StatusHandle, L""); + SetWindowText(context->SubStatusHandle, L"Progress: ~ of ~ (0.0%)"); // Disable Next/Back buttons PropSheet_SetWizButtons(context->PropSheetHandle, 0); @@ -131,12 +152,7 @@ INT_PTR CALLBACK SetupPropPage4_WndProc( { SetupRunning = TRUE; - // Setup the progress thread - progress = PhCreateAlloc(sizeof(SETUP_PROGRESS_THREAD)); - progress->DialogHandle = hwndDlg; - progress->PropSheetHandle = context->PropSheetHandle; - - if (threadHandle = PhCreateThread(0, SetupProgressThread, progress)) + if (threadHandle = PhCreateThread(0, SetupProgressThread, context)) NtClose(threadHandle); } } @@ -146,26 +162,34 @@ INT_PTR CALLBACK SetupPropPage4_WndProc( break; case WM_START_SETUP: { - SetWindowText(GetDlgItem(hwndDlg, IDC_MAINHEADER), +#ifdef PH_BUILD_API + SetWindowText(context->MainHeaderHandle, PhaFormatString(L"Installing Process Hacker %lu.%lu.%lu", PHAPP_VERSION_MAJOR, PHAPP_VERSION_MINOR, PHAPP_VERSION_REVISION)->Buffer); - SetWindowText(GetDlgItem(hwndDlg, IDC_INSTALL_SUBSTATUS), L"Progress: ~ of ~ (0.0%)"); - SendMessage(GetDlgItem(hwndDlg, IDC_INSTALL_PROGRESS), PBM_SETRANGE32, 0, (LPARAM)ExtractTotalLength); +#else + SetWindowText(context->MainHeaderHandle, PhaFormatString( + L"Installing Process Hacker %lu.%lu.%lu", + context->LatestMajorVersion, + context->LatestMinorVersion, + context->LatestRevisionVersion + )->Buffer); +#endif + SendMessage(context->ProgressHandle, PBM_SETRANGE32, 0, (LPARAM)ExtractTotalLength); } break; case WM_UPDATE_SETUP: { PPH_STRING currentFile = (PPH_STRING)lParam; - SetWindowText(GetDlgItem(hwndDlg, IDC_INSTALL_STATUS), + SetWindowText(context->StatusHandle, PhaConcatStrings2(L"Extracting: ", currentFile->Buffer)->Buffer ); - SetWindowText(GetDlgItem(hwndDlg, IDC_INSTALL_SUBSTATUS), PhaFormatString( + SetWindowText(context->SubStatusHandle, PhaFormatString( L"Progress: %s of %s (%.2f%%)", PhaFormatSize(ExtractCurrentLength, -1)->Buffer, PhaFormatSize(ExtractTotalLength, -1)->Buffer, (FLOAT)((double)ExtractCurrentLength / (double)ExtractTotalLength) * 100 )->Buffer); - SendMessage(GetDlgItem(hwndDlg, IDC_INSTALL_PROGRESS), PBM_SETPOS, (WPARAM)ExtractCurrentLength, 0); + SendMessage(context->ProgressHandle, PBM_SETPOS, (WPARAM)ExtractCurrentLength, 0); PhDereferenceObject(currentFile); } @@ -174,13 +198,14 @@ INT_PTR CALLBACK SetupPropPage4_WndProc( { SetupRunning = FALSE; - SetWindowText(GetDlgItem(hwndDlg, IDC_MAINHEADER), L"Setup Complete"); - SetWindowText(GetDlgItem(hwndDlg, IDC_INSTALL_STATUS), L"Extract complete"); - Button_SetText(GetDlgItem(GetParent(hwndDlg), IDC_PROPSHEET_CANCEL), L"Close"); + SetWindowText(context->MainHeaderHandle, L"Setup Complete"); + SetWindowText(context->StatusHandle, L"Extract complete"); + Button_SetText(context->PropSheetCancelHandle, L"Close"); - if (SetupStartAppAfterExit) + if (context->SetupStartAppAfterExit) { - SetupExecuteProcessHacker(GetParent(hwndDlg)); + SetupExecuteProcessHacker(context); + PropSheet_PressButton(GetParent(hwndDlg), PSBTN_FINISH); } } diff --git a/tools/CustomSetupTool/CustomSetupTool/page5.c b/tools/CustomSetupTool/CustomSetupTool/page5.c index 7fdd40939b22..737cab677e7a 100644 --- a/tools/CustomSetupTool/CustomSetupTool/page5.c +++ b/tools/CustomSetupTool/CustomSetupTool/page5.c @@ -23,7 +23,7 @@ #include NTSTATUS SetupDownloadProgressThread( - _In_ PPH_SETUP_DOWNLOAD_CONTEXT Context + _In_ PPH_SETUP_CONTEXT Context ) { if (!SetupQueryUpdateData(Context)) @@ -33,13 +33,11 @@ NTSTATUS SetupDownloadProgressThread( goto CleanupExit; PostMessage(Context->PropSheetHandle, PSM_SETCURSELID, 0, IDD_DIALOG4); - PhDereferenceObject(Context); return STATUS_SUCCESS; CleanupExit: PostMessage(Context->PropSheetHandle, PSM_SETCURSELID, 0, IDD_ERROR); - PhDereferenceObject(Context); return STATUS_FAIL_CHECK; } @@ -50,7 +48,20 @@ INT_PTR CALLBACK SetupPropPage5_WndProc( _Inout_ LPARAM lParam ) { - PPH_SETUP_CONTEXT context = (PPH_SETUP_CONTEXT)GetProp(GetParent(hwndDlg), L"SetupContext"); + PPH_SETUP_CONTEXT context = NULL; + + if (uMsg == WM_INITDIALOG) + { + context = GetProp(GetParent(hwndDlg), L"SetupContext"); + SetProp(hwndDlg, L"Context", (HANDLE)context); + } + else + { + context = (PPH_SETUP_CONTEXT)GetProp(hwndDlg, L"Context"); + } + + if (context == NULL) + return FALSE; switch (uMsg) { @@ -62,10 +73,6 @@ INT_PTR CALLBACK SetupPropPage5_WndProc( SetupInitializeFont(GetDlgItem(hwndDlg, IDC_INSTALL_STATUS), -12, FW_SEMIBOLD); SetupInitializeFont(GetDlgItem(hwndDlg, IDC_INSTALL_SUBSTATUS), -12, FW_NORMAL); - SetWindowText(GetDlgItem(hwndDlg, IDC_MAINHEADER), L"Starting download..."); - SetWindowText(GetDlgItem(hwndDlg, IDC_INSTALL_STATUS), L"Starting download..."); - SetWindowText(GetDlgItem(hwndDlg, IDC_INSTALL_SUBSTATUS), L""); - EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); } break; @@ -76,43 +83,24 @@ INT_PTR CALLBACK SetupPropPage5_WndProc( switch (pageNotify->hdr.code) { - case PSN_QUERYCANCEL: - { - if (SetupRunning && DialogPromptExit(hwndDlg)) - { - SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, (LPARAM)TRUE); - return TRUE; - } - } - break; case PSN_SETACTIVE: { HANDLE threadHandle; - PPH_SETUP_DOWNLOAD_CONTEXT progress; + + context->MainHeaderHandle = GetDlgItem(hwndDlg, IDC_MAINHEADER); + context->StatusHandle = GetDlgItem(hwndDlg, IDC_INSTALL_STATUS); + context->SubStatusHandle = GetDlgItem(hwndDlg, IDC_INSTALL_SUBSTATUS); + context->ProgressHandle = GetDlgItem(hwndDlg, IDC_INSTALL_PROGRESS); + + SetWindowText(context->MainHeaderHandle, L"Starting download..."); + SetWindowText(context->StatusHandle, L"Starting download..."); + SetWindowText(context->SubStatusHandle, L""); // Disable Next/Back buttons PropSheet_SetWizButtons(context->PropSheetHandle, 0); - if (!SetupRunning) - { - SetupRunning = TRUE; - - progress = PhCreateAlloc(sizeof(PH_SETUP_DOWNLOAD_CONTEXT)); - memset(progress, 0, sizeof(PH_SETUP_DOWNLOAD_CONTEXT)); - - progress->DialogHandle = hwndDlg; - progress->PropSheetHandle = context->PropSheetHandle; - progress->CurrentMajorVersion = PHAPP_VERSION_MAJOR; - progress->CurrentMinorVersion = PHAPP_VERSION_MINOR; - progress->CurrentRevisionVersion = PHAPP_VERSION_REVISION; - progress->MainHeaderHandle = GetDlgItem(hwndDlg, IDC_MAINHEADER); - progress->StatusHandle = GetDlgItem(hwndDlg, IDC_INSTALL_STATUS); - progress->SubStatusHandle = GetDlgItem(hwndDlg, IDC_INSTALL_SUBSTATUS); - progress->ProgressHandle = GetDlgItem(hwndDlg, IDC_INSTALL_PROGRESS); - - if (threadHandle = PhCreateThread(0, SetupDownloadProgressThread, progress)) - NtClose(threadHandle); - } + if (threadHandle = PhCreateThread(0, SetupDownloadProgressThread, context)) + NtClose(threadHandle); } break; } diff --git a/tools/CustomSetupTool/CustomSetupTool/setup.c b/tools/CustomSetupTool/CustomSetupTool/setup.c index eb83f76e620f..43affc76c917 100644 --- a/tools/CustomSetupTool/CustomSetupTool/setup.c +++ b/tools/CustomSetupTool/CustomSetupTool/setup.c @@ -27,7 +27,7 @@ PH_STRINGREF UninstallKeyName = PH_STRINGREF_INIT(L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\ProcessHacker"); NTSTATUS SetupCreateUninstallKey( - VOID + _In_ PPH_SETUP_CONTEXT Context ) { NTSTATUS status; @@ -50,7 +50,7 @@ NTSTATUS SetupCreateUninstallKey( { PPH_STRING tempString; - tempString = PhConcatStrings2(PhGetString(SetupInstallPath), L"\\processhacker.exe,0"); + tempString = PhConcatStrings2(PhGetString(Context->SetupInstallPath), L"\\processhacker.exe,0"); PhStringRefToUnicodeString(&tempString->sr, &value); RtlInitUnicodeString(&name, L"DisplayIcon"); PhStringRefToUnicodeString(&tempString->sr, &value); @@ -70,7 +70,7 @@ NTSTATUS SetupCreateUninstallKey( NtSetValueKey(keyHandle, &name, 0, REG_SZ, value.Buffer, (ULONG)value.MaximumLength); RtlInitUnicodeString(&name, L"InstallLocation"); - RtlInitUnicodeString(&value, PhGetString(SetupInstallPath)); + RtlInitUnicodeString(&value, PhGetString(Context->SetupInstallPath)); NtSetValueKey(keyHandle, &name, 0, REG_SZ, value.Buffer, (ULONG)value.MaximumLength); RtlInitUnicodeString(&name, L"Publisher"); @@ -78,7 +78,7 @@ NTSTATUS SetupCreateUninstallKey( NtSetValueKey(keyHandle, &name, 0, REG_SZ, value.Buffer, (ULONG)value.MaximumLength); RtlInitUnicodeString(&name, L"UninstallString"); - tempString = PhFormatString(L"\"%s\\processhacker-setup.exe\" -uninstall", PhGetString(SetupInstallPath)); + tempString = PhFormatString(L"\"%s\\processhacker-setup.exe\" -uninstall", PhGetString(Context->SetupInstallPath)); PhStringRefToUnicodeString(&tempString->sr, &value); NtSetValueKey(keyHandle, &name, 0, REG_SZ, value.Buffer, (ULONG)value.MaximumLength); PhDereferenceObject(tempString); @@ -121,15 +121,15 @@ NTSTATUS SetupDeleteUninstallKey( return status; } -VOID SetupFindInstallDirectory( +PPH_STRING SetupFindInstallDirectory( VOID ) { // Find the current installation path. - SetupInstallPath = GetProcessHackerInstallPath(); + PPH_STRING setupInstallPath = GetProcessHackerInstallPath(); // Check if the string is valid. - if (PhIsNullOrEmptyString(SetupInstallPath)) + if (PhIsNullOrEmptyString(setupInstallPath)) { PH_STRINGREF programW6432 = PH_STRINGREF_INIT(L"%ProgramW6432%"); PH_STRINGREF programFiles = PH_STRINGREF_INIT(L"%ProgramFiles%"); @@ -143,36 +143,38 @@ VOID SetupFindInstallDirectory( { if (expandedString = PH_AUTO(PhExpandEnvironmentStrings(&programW6432))) { - SetupInstallPath = PhConcatStringRef2(&expandedString->sr, &defaultDirectoryName); + setupInstallPath = PhConcatStringRef2(&expandedString->sr, &defaultDirectoryName); } } else { if (expandedString = PH_AUTO(PhExpandEnvironmentStrings(&programFiles))) { - SetupInstallPath = PhConcatStringRef2(&expandedString->sr, &defaultDirectoryName); + setupInstallPath = PhConcatStringRef2(&expandedString->sr, &defaultDirectoryName); } } } - if (PhIsNullOrEmptyString(SetupInstallPath)) + if (PhIsNullOrEmptyString(setupInstallPath)) { - SetupInstallPath = PhCreateString(L"C:\\Program Files\\Process Hacker\\"); + setupInstallPath = PhCreateString(L"C:\\Program Files\\Process Hacker\\"); } // Remove extra backslashes - PathRemoveBackslash(PhGetString(SetupInstallPath)); + PathRemoveBackslash(PhGetString(setupInstallPath)); + + return setupInstallPath; } VOID SetupCreateUninstallFile( - VOID + _In_ PPH_SETUP_CONTEXT Context ) { PPH_STRING backupFilePath; PPH_STRING uninstallFilePath; - backupFilePath = PhConcatStrings2(PhGetString(SetupInstallPath), L"\\processhacker-setup.bak"); - uninstallFilePath = PhConcatStrings2(PhGetString(SetupInstallPath), L"\\processhacker-setup.exe"); + backupFilePath = PhConcatStrings2(PhGetString(Context->SetupInstallPath), L"\\processhacker-setup.bak"); + uninstallFilePath = PhConcatStrings2(PhGetString(Context->SetupInstallPath), L"\\processhacker-setup.exe"); if (RtlDoesFileExists_U(backupFilePath->Buffer)) { @@ -191,13 +193,12 @@ VOID SetupCreateUninstallFile( } VOID SetupDeleteUninstallFile( - VOID + _In_ PPH_SETUP_CONTEXT Context ) { PPH_STRING uninstallFilePath; - // NtCurrentPeb()->ProcessParameters->ImagePathName.Buffer - uninstallFilePath = PhConcatStrings2(PhGetString(SetupInstallPath), L"\\processhacker-setup.exe"); + uninstallFilePath = PhConcatStrings2(PhGetString(Context->SetupInstallPath), L"\\processhacker-setup.exe"); if (RtlDoesFileExists_U(uninstallFilePath->Buffer)) { @@ -261,11 +262,11 @@ VOID SetupDeleteUninstallFile( PhDereferenceObject(uninstallFilePath); } -VOID SetupInstallKph( - VOID +VOID SetupStartKph( + _In_ PPH_SETUP_CONTEXT Context ) { - PPH_STRING clientPath = PhConcatStrings2(PhGetString(SetupInstallPath), L"\\ProcessHacker.exe"); + PPH_STRING clientPath = PhConcatStrings2(PhGetString(Context->SetupInstallPath), L"\\ProcessHacker.exe"); if (RtlDoesFileExists_U(PhGetString(clientPath))) { @@ -336,7 +337,7 @@ ULONG SetupUninstallKph( } VOID SetupSetWindowsOptions( - VOID + _In_ PPH_SETUP_CONTEXT Context ) { static PH_STRINGREF TaskMgrImageOptionsKeyName = PH_STRINGREF_INIT(L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\taskmgr.exe"); @@ -344,33 +345,33 @@ VOID SetupSetWindowsOptions( PPH_STRING clientPathString; PPH_STRING startmenuFolderString; - clientPathString = PhConcatStrings2(PhGetString(SetupInstallPath), L"\\ProcessHacker.exe"); + clientPathString = PhConcatStrings2(PhGetString(Context->SetupInstallPath), L"\\ProcessHacker.exe"); if (startmenuFolderString = PhGetKnownLocation(CSIDL_COMMON_PROGRAMS, L"\\Process Hacker.lnk")) { SetupCreateLink( PhGetString(startmenuFolderString), PhGetString(clientPathString), - PhGetString(SetupInstallPath) + PhGetString(Context->SetupInstallPath) ); PhDereferenceObject(startmenuFolderString); } if (startmenuFolderString = PhGetKnownLocation(CSIDL_COMMON_PROGRAMS, L"\\PE Viewer.lnk")) { - PPH_STRING peviewPathString = PhConcatStrings2(PhGetString(SetupInstallPath), L"\\peview.exe"); + PPH_STRING peviewPathString = PhConcatStrings2(PhGetString(Context->SetupInstallPath), L"\\peview.exe"); SetupCreateLink( PhGetString(startmenuFolderString), PhGetString(peviewPathString), - PhGetString(SetupInstallPath) + PhGetString(Context->SetupInstallPath) ); PhDereferenceObject(peviewPathString); PhDereferenceObject(startmenuFolderString); } - if (SetupResetSettings) + if (Context->SetupResetSettings) { PPH_STRING settingsFileName = PhGetKnownLocation(CSIDL_APPDATA, L"\\Process Hacker\\settings.xml"); @@ -378,7 +379,7 @@ VOID SetupSetWindowsOptions( PhDereferenceObject(settingsFileName); } - if (SetupCreateDefaultTaskManager) + if (Context->SetupCreateDefaultTaskManager) { HANDLE keyHandle; @@ -401,7 +402,7 @@ VOID SetupSetWindowsOptions( } } - if (SetupCreateSystemStartup) + if (Context->SetupCreateSystemStartup) { HANDLE keyHandle; @@ -418,7 +419,7 @@ VOID SetupSetWindowsOptions( RtlInitUnicodeString(&valueName, L"Process Hacker"); - if (SetupCreateMinimizedSystemStartup) + if (Context->SetupCreateMinimizedSystemStartup) value = PhConcatStrings(3, L"\"", PhGetString(clientPathString), L"\" -hide"); else value = PhConcatStrings(3, L"\"", PhGetString(clientPathString), L"\""); @@ -428,7 +429,7 @@ VOID SetupSetWindowsOptions( } } - if (SetupCreateDesktopShortcut) + if (Context->SetupCreateDesktopShortcut) { PPH_STRING desktopFolderString; @@ -437,12 +438,12 @@ VOID SetupSetWindowsOptions( SetupCreateLink( PhGetString(desktopFolderString), PhGetString(clientPathString), - PhGetString(SetupInstallPath) + PhGetString(Context->SetupInstallPath) ); PhDereferenceObject(desktopFolderString); } } - else if (SetupCreateDesktopShortcutAllUsers) + else if (Context->SetupCreateDesktopShortcutAllUsers) { PPH_STRING startmenuFolderString; @@ -451,7 +452,7 @@ VOID SetupSetWindowsOptions( SetupCreateLink( PhGetString(startmenuFolderString), PhGetString(clientPathString), - PhGetString(SetupInstallPath) + PhGetString(Context->SetupInstallPath) ); PhDereferenceObject(startmenuFolderString); } @@ -459,7 +460,7 @@ VOID SetupSetWindowsOptions( } VOID SetupDeleteWindowsOptions( - VOID + _In_ PPH_SETUP_CONTEXT Context ) { static PH_STRINGREF TaskMgrImageOptionsKeyName = PH_STRINGREF_INIT(L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\taskmgr.exe"); @@ -521,18 +522,18 @@ VOID SetupDeleteWindowsOptions( } BOOLEAN SetupExecuteProcessHacker( - _In_ HWND Parent + _In_ PPH_SETUP_CONTEXT Context ) { BOOLEAN success = FALSE; PPH_STRING clientPath; - clientPath = PhConcatStrings2(PhGetString(SetupInstallPath), L"\\ProcessHacker.exe"); + clientPath = PhConcatStrings2(PhGetString(Context->SetupInstallPath), L"\\ProcessHacker.exe"); if (RtlDoesFileExists_U(clientPath->Buffer)) { success = PhShellExecuteEx( - Parent, + Context->PropSheetHandle, clientPath->Buffer, NULL, SW_SHOWDEFAULT, diff --git a/tools/CustomSetupTool/CustomSetupTool/uninstall.c b/tools/CustomSetupTool/CustomSetupTool/uninstall.c index 08c4009b0a16..c03dbaf6713f 100644 --- a/tools/CustomSetupTool/CustomSetupTool/uninstall.c +++ b/tools/CustomSetupTool/CustomSetupTool/uninstall.c @@ -44,7 +44,7 @@ NTSTATUS SetupUninstallBuild( _In_ PPH_SETUP_UNINSTALL_CONTEXT Context ) { - SetupFindInstallDirectory(); + //context->SetupInstallPath = SetupFindInstallDirectory(); // Stop Process Hacker. if (!ShutdownProcessHacker()) @@ -55,17 +55,17 @@ NTSTATUS SetupUninstallBuild( goto CleanupExit; // Remove autorun and shortcuts. - SetupDeleteWindowsOptions(); + //SetupDeleteWindowsOptions(); // Remove the uninstaller. - SetupDeleteUninstallFile(); + //SetupDeleteUninstallFile(); // Remove the ARP uninstall entry. SetupDeleteUninstallKey(); // Remove the previous installation. - if (!RemoveDirectoryPath(PhGetString(SetupInstallPath))) - goto CleanupExit; + //if (!RemoveDirectoryPath(PhGetString(SetupInstallPath))) + // goto CleanupExit; ShowUninstallCompleteDialog(Context); return STATUS_SUCCESS; diff --git a/tools/CustomSetupTool/CustomSetupTool/update.c b/tools/CustomSetupTool/CustomSetupTool/update.c index 231bd124a266..277057873142 100644 --- a/tools/CustomSetupTool/CustomSetupTool/update.c +++ b/tools/CustomSetupTool/CustomSetupTool/update.c @@ -22,28 +22,16 @@ #include #include -typedef struct _PH_SETUP_UPDATE_CONTEXT -{ - HWND DialogHandle; - HICON IconSmallHandle; - HICON IconLargeHandle; - - PPH_STRING FileDownloadUrl; - PPH_STRING RevVersion; - PPH_STRING Size; - PPH_STRING SetupFilePath; -} PH_SETUP_UPDATE_CONTEXT, *PPH_SETUP_UPDATE_CONTEXT; - #define WM_TASKDIALOGINIT (WM_APP + 550) HWND UpdateDialogHandle = NULL; HANDLE UpdateDialogThreadHandle = NULL; PH_EVENT InitializedEvent = PH_EVENT_INIT; NTSTATUS SetupUpdateBuild( - _In_ PPH_SETUP_UPDATE_CONTEXT Context + _In_ PPH_SETUP_CONTEXT Context ) { - SetupFindInstallDirectory(); + Context->SetupInstallPath = SetupFindInstallDirectory(); if (!ShutdownProcessHacker()) goto CleanupExit; @@ -51,68 +39,42 @@ NTSTATUS SetupUpdateBuild( if (!SetupUninstallKph()) goto CleanupExit; - SetupCreateUninstallKey(); - SetupCreateUninstallFile(); - //SetupSetWindowsOptions(); + SetupCreateUninstallKey(Context); + SetupCreateUninstallFile(Context); - if (!SetupExtractBuild(Context->DialogHandle)) + if (!SetupExtractBuild(Context)) goto CleanupExit; - if (SetupInstallKphService) - SetupInstallKph(); + SetupStartKph(Context); - if (!SetupExecuteProcessHacker(Context->DialogHandle)) + if (!SetupExecuteProcessHacker(Context)) goto CleanupExit; - PostMessage(Context->DialogHandle, WM_QUIT, 0, 0); + PostMessage(Context->PropSheetHandle, WM_QUIT, 0, 0); PhDereferenceObject(Context); return STATUS_SUCCESS; CleanupExit: - PostMessage(Context->DialogHandle, IDD_ERROR, 0, 0); + PostMessage(Context->PropSheetHandle, IDD_ERROR, 0, 0); PhDereferenceObject(Context); return STATUS_FAIL_CHECK; } - -PPH_SETUP_UPDATE_CONTEXT CreateUpdateContext( +PPH_SETUP_CONTEXT CreateUpdateContext( VOID ) { - PPH_SETUP_UPDATE_CONTEXT context; + PPH_SETUP_CONTEXT context; - context = (PPH_SETUP_UPDATE_CONTEXT)PhCreateAlloc(sizeof(PH_SETUP_UPDATE_CONTEXT)); - memset(context, 0, sizeof(PH_SETUP_UPDATE_CONTEXT)); + context = (PPH_SETUP_CONTEXT)PhCreateAlloc(sizeof(PH_SETUP_CONTEXT)); + memset(context, 0, sizeof(PH_SETUP_CONTEXT)); return context; } -VOID FreeUpdateContext( - _In_ _Post_invalid_ PPH_SETUP_UPDATE_CONTEXT Context - ) -{ - //PhClearReference(&Context->Version); - //PhClearReference(&Context->RevVersion); - //PhClearReference(&Context->RelDate); - //PhClearReference(&Context->Size); - //PhClearReference(&Context->Hash); - //PhClearReference(&Context->Signature); - //PhClearReference(&Context->ReleaseNotesUrl); - //PhClearReference(&Context->SetupFilePath); - //PhClearReference(&Context->SetupFileDownloadUrl); - - if (Context->IconLargeHandle) - DestroyIcon(Context->IconLargeHandle); - - if (Context->IconSmallHandle) - DestroyIcon(Context->IconSmallHandle); - - //PhClearReference(&Context); -} - VOID TaskDialogCreateIcons( - _In_ PPH_SETUP_UPDATE_CONTEXT Context + _In_ PPH_SETUP_CONTEXT Context ) { HICON largeIcon; @@ -136,15 +98,8 @@ VOID TaskDialogCreateIcons( Context->IconLargeHandle = largeIcon; Context->IconSmallHandle = smallIcon; - SendMessage(Context->DialogHandle, WM_SETICON, ICON_SMALL, (LPARAM)largeIcon); - SendMessage(Context->DialogHandle, WM_SETICON, ICON_BIG, (LPARAM)smallIcon); -} - -VOID TaskDialogLinkClicked( - _In_ PPH_SETUP_UPDATE_CONTEXT Context - ) -{ - + SendMessage(Context->PropSheetHandle, WM_SETICON, ICON_SMALL, (LPARAM)largeIcon); + SendMessage(Context->PropSheetHandle, WM_SETICON, ICON_BIG, (LPARAM)smallIcon); } LRESULT CALLBACK TaskDialogSubclassProc( @@ -156,7 +111,7 @@ LRESULT CALLBACK TaskDialogSubclassProc( _In_ ULONG_PTR dwRefData ) { - PPH_SETUP_UPDATE_CONTEXT context = (PPH_SETUP_UPDATE_CONTEXT)dwRefData; + PPH_SETUP_CONTEXT context = (PPH_SETUP_CONTEXT)dwRefData; switch (uMsg) { @@ -180,7 +135,7 @@ LRESULT CALLBACK TaskDialogSubclassProc( return DefSubclassProc(hwndDlg, uMsg, wParam, lParam); } -HRESULT CALLBACK CheckingForUpdatesCallbackProc( +HRESULT CALLBACK SetupUpdatingTaskDialogCallbackProc( _In_ HWND hwndDlg, _In_ UINT uMsg, _In_ WPARAM wParam, @@ -188,7 +143,7 @@ HRESULT CALLBACK CheckingForUpdatesCallbackProc( _In_ LONG_PTR dwRefData ) { - PPH_SETUP_UPDATE_CONTEXT context = (PPH_SETUP_UPDATE_CONTEXT)dwRefData; + PPH_SETUP_CONTEXT context = (PPH_SETUP_CONTEXT)dwRefData; switch (uMsg) { @@ -205,8 +160,8 @@ HRESULT CALLBACK CheckingForUpdatesCallbackProc( return S_OK; } -VOID ShowCheckForUpdatesDialog( - _In_ PPH_SETUP_UPDATE_CONTEXT Context +VOID SetupShowUpdatingDialog( + _In_ PPH_SETUP_CONTEXT Context ) { TASKDIALOGCONFIG config; @@ -214,15 +169,20 @@ VOID ShowCheckForUpdatesDialog( memset(&config, 0, sizeof(TASKDIALOGCONFIG)); config.cbSize = sizeof(TASKDIALOGCONFIG); config.dwFlags = TDF_USE_HICON_MAIN | TDF_ALLOW_DIALOG_CANCELLATION | TDF_SHOW_MARQUEE_PROGRESS_BAR | TDF_CAN_BE_MINIMIZED | TDF_ENABLE_HYPERLINKS; + config.cxWidth = 200; config.dwCommonButtons = TDCBF_CANCEL_BUTTON; config.hMainIcon = Context->IconLargeHandle; - config.pfCallback = CheckingForUpdatesCallbackProc; + config.pfCallback = SetupUpdatingTaskDialogCallbackProc; config.lpCallbackData = (LONG_PTR)Context; config.pszWindowTitle = PhApplicationName; - config.pszMainInstruction = PhaFormatString(L"Updating to version %lu.%lu.%lu...", PHAPP_VERSION_MAJOR, PHAPP_VERSION_MINOR, PHAPP_VERSION_REVISION)->Buffer; - config.cxWidth = 200; - - SendMessage(Context->DialogHandle, TDM_NAVIGATE_PAGE, 0, (LPARAM)&config); + config.pszMainInstruction = PhaFormatString( + L"Updating to version %lu.%lu.%lu...", + PHAPP_VERSION_MAJOR, + PHAPP_VERSION_MINOR, + PHAPP_VERSION_REVISION + )->Buffer; + + SendMessage(Context->PropSheetHandle, TDM_NAVIGATE_PAGE, 0, (LPARAM)&config); } HRESULT CALLBACK TaskDialogBootstrapCallback( @@ -233,22 +193,22 @@ HRESULT CALLBACK TaskDialogBootstrapCallback( _In_ LONG_PTR dwRefData ) { - PPH_SETUP_UPDATE_CONTEXT context = (PPH_SETUP_UPDATE_CONTEXT)dwRefData; + PPH_SETUP_CONTEXT context = (PPH_SETUP_CONTEXT)dwRefData; switch (uMsg) { case TDN_CREATED: { - context->DialogHandle = hwndDlg; + context->PropSheetHandle = hwndDlg; - // Center the window on the desktop + // Center the window on the desktop. PhCenterWindow(hwndDlg, NULL); - // Create the Taskdialog icons + // Create the Taskdialog icons. TaskDialogCreateIcons(context); - // Subclass the Taskdialog + // Subclass the Taskdialog. SetWindowSubclass(hwndDlg, TaskDialogSubclassProc, 0, (ULONG_PTR)context); - // Navigate to the first page - ShowCheckForUpdatesDialog(context); + // Navigate to the first page. + SetupShowUpdatingDialog(context); SendMessage(hwndDlg, WM_TASKDIALOGINIT, 0, 0); } @@ -280,6 +240,5 @@ VOID SetupShowUpdateDialog( TaskDialogIndirect(&config, NULL, NULL, NULL); - FreeUpdateContext(context); PhDeleteAutoPool(&autoPool); } \ No newline at end of file From 72dfd061f0b219beb31b06d6882519152a1b3fce Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 23 May 2017 05:21:18 +1000 Subject: [PATCH 0157/2058] Updater: Fix error checking --- plugins/Updater/updater.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/plugins/Updater/updater.c b/plugins/Updater/updater.c index f0ca93c4a37e..65ffb77af54e 100644 --- a/plugins/Updater/updater.c +++ b/plugins/Updater/updater.c @@ -447,14 +447,11 @@ BOOLEAN QueryUpdateData( CleanupJsonParser(jsonObject); - if (PhIsNullOrEmptyString(Context->Signature)) + if (PhIsNullOrEmptyString(Context->Version)) goto CleanupExit; - if (!ParseVersionString(Context)) goto CleanupExit; - if (PhIsNullOrEmptyString(Context->Version)) - goto CleanupExit; if (PhIsNullOrEmptyString(Context->RevVersion)) goto CleanupExit; if (PhIsNullOrEmptyString(Context->RelDate)) @@ -467,6 +464,8 @@ BOOLEAN QueryUpdateData( goto CleanupExit; if (PhIsNullOrEmptyString(Context->SetupFileDownloadUrl)) goto CleanupExit; + if (PhIsNullOrEmptyString(Context->Signature)) + goto CleanupExit; success = TRUE; From 6cd629e5e18e3752bd2592321bc82b048769f903 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 23 May 2017 05:21:44 +1000 Subject: [PATCH 0158/2058] Add Information and Log window icons --- ProcessHacker/infodlg.c | 3 +++ ProcessHacker/logwnd.c | 3 +++ 2 files changed, 6 insertions(+) diff --git a/ProcessHacker/infodlg.c b/ProcessHacker/infodlg.c index 41947bfe8f86..176140cc2662 100644 --- a/ProcessHacker/infodlg.c +++ b/ProcessHacker/infodlg.c @@ -46,6 +46,9 @@ static INT_PTR CALLBACK PhpInformationDlgProc( PINFORMATION_CONTEXT context = (PINFORMATION_CONTEXT)lParam; PPH_LAYOUT_MANAGER layoutManager; + SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhLibImageBase, MAKEINTRESOURCE(IDI_PROCESSHACKER))); + SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhLibImageBase, MAKEINTRESOURCE(IDI_PROCESSHACKER))); + PhCenterWindow(hwndDlg, GetParent(hwndDlg)); SetDlgItemText(hwndDlg, IDC_TEXT, context->String); diff --git a/ProcessHacker/logwnd.c b/ProcessHacker/logwnd.c index 0a9b71a94b62..0fde6d46e648 100644 --- a/ProcessHacker/logwnd.c +++ b/ProcessHacker/logwnd.c @@ -156,6 +156,9 @@ INT_PTR CALLBACK PhpLogDlgProc( { case WM_INITDIALOG: { + SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhLibImageBase, MAKEINTRESOURCE(IDI_PROCESSHACKER))); + SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhLibImageBase, MAKEINTRESOURCE(IDI_PROCESSHACKER))); + ListViewHandle = GetDlgItem(hwndDlg, IDC_LIST); PhSetListViewStyle(ListViewHandle, FALSE, TRUE); PhSetControlTheme(ListViewHandle, L"explorer"); From deca2034938e21d2c9b5d106ed38902bf22bd100 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 23 May 2017 07:38:46 +1000 Subject: [PATCH 0159/2058] Setup: Fix binary version, Fix update error handling, Fix re-running setup from installation directory, Remove focus workaround --- .../CustomSetupTool/CustomSetupTool.vcxproj | 3 - .../CustomSetupTool.vcxproj.filters | 5 -- .../CustomSetupTool/CustomSetupTool/extract.c | 17 +++++- .../CustomSetupTool/include/setup.h | 2 +- tools/CustomSetupTool/CustomSetupTool/page2.c | 26 +++++--- tools/CustomSetupTool/CustomSetupTool/page4.c | 18 +++--- .../CustomSetupTool/resources/version.rc | 11 ++-- tools/CustomSetupTool/CustomSetupTool/setup.c | 30 ++++++++-- .../CustomSetupTool/CustomSetupTool/update.c | 60 ++++++++++++++++++- 9 files changed, 135 insertions(+), 37 deletions(-) diff --git a/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj b/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj index 227ad5d2ce4f..888e8bbaa14f 100644 --- a/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj +++ b/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj @@ -172,9 +172,6 @@ - - - diff --git a/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj.filters b/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj.filters index 6557bf933011..b2499c2417c6 100644 --- a/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj.filters +++ b/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj.filters @@ -195,11 +195,6 @@ Resource Files\Content - - - Resource Files\Content - - Resource Files\Content diff --git a/tools/CustomSetupTool/CustomSetupTool/extract.c b/tools/CustomSetupTool/CustomSetupTool/extract.c index 6a1709ea3746..850a2322074c 100644 --- a/tools/CustomSetupTool/CustomSetupTool/extract.c +++ b/tools/CustomSetupTool/CustomSetupTool/extract.c @@ -190,7 +190,22 @@ BOOLEAN SetupExtractBuild( PhDereferenceObject(fullSetupPath); } - // TODO: Rename existing folder items and restore if the setup fails. + // TODO: Backup file and restore if the setup fails. + //{ + // PPH_STRING backupFilePath; + // + // backupFilePath = PhConcatStrings( + // 4, + // PhGetString(Context->SetupInstallPath), + // L"\\", + // PhGetString(fileName), + // L".bak" + // ); + // + // MoveFile(extractPath->Buffer, backupFilePath->Buffer); + // + // PhDereferenceObject(backupFilePath); + //} if (!NT_SUCCESS(PhCreateFileWin32( &fileHandle, diff --git a/tools/CustomSetupTool/CustomSetupTool/include/setup.h b/tools/CustomSetupTool/CustomSetupTool/include/setup.h index 462141663909..1c8852690d86 100644 --- a/tools/CustomSetupTool/CustomSetupTool/include/setup.h +++ b/tools/CustomSetupTool/CustomSetupTool/include/setup.h @@ -208,7 +208,7 @@ VOID SetupDeleteWindowsOptions( _In_ PPH_SETUP_CONTEXT Context ); -VOID SetupCreateUninstallFile( +BOOLEAN SetupCreateUninstallFile( _In_ PPH_SETUP_CONTEXT Context ); diff --git a/tools/CustomSetupTool/CustomSetupTool/page2.c b/tools/CustomSetupTool/CustomSetupTool/page2.c index a756f9f1a836..87c3bdbe90c1 100644 --- a/tools/CustomSetupTool/CustomSetupTool/page2.c +++ b/tools/CustomSetupTool/CustomSetupTool/page2.c @@ -58,7 +58,6 @@ INT_PTR CALLBACK SetupPropPage2_WndProc( if (eulaTextString = PhConvertUtf8ToUtf16(resourceBuffer)) { SetWindowText(GetDlgItem(hwndDlg, IDC_EDIT1), eulaTextString->Buffer); - PhDereferenceObject(eulaTextString); } @@ -75,17 +74,26 @@ INT_PTR CALLBACK SetupPropPage2_WndProc( switch (pageNotify->hdr.code) { - case PSN_SETACTIVE: - { - // HACK: Prevent the textbox text from being selected (temp fix). - PostMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)context->PropSheetForwardHandle, TRUE); - } - break; case PSN_QUERYINITIALFOCUS: + SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, (LPARAM)context->PropSheetCancelHandle); + return TRUE; + } + } + break; + case WM_COMMAND: + { + switch (GET_WM_COMMAND_CMD(wParam, lParam)) + { + case EN_SETFOCUS: { - SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, (LPARAM)context->PropSheetCancelHandle); + HWND handle = (HWND)lParam; + + // Prevent the edit control text from being selected. + SendMessage(handle, EM_SETSEL, -1, 0); + + SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, (LPARAM)TRUE); + return TRUE; } - return TRUE; } } break; diff --git a/tools/CustomSetupTool/CustomSetupTool/page4.c b/tools/CustomSetupTool/CustomSetupTool/page4.c index 40900e620fa1..1c6b89477a95 100644 --- a/tools/CustomSetupTool/CustomSetupTool/page4.c +++ b/tools/CustomSetupTool/CustomSetupTool/page4.c @@ -30,9 +30,6 @@ NTSTATUS SetupProgressThread( _In_ PPH_SETUP_CONTEXT Context ) { - //if (SetupInstallDebuggingTools) - // SetupDownloadThread(Arguments) - // Stop Process Hacker. if (!ShutdownProcessHacker()) goto CleanupExit; @@ -52,10 +49,13 @@ NTSTATUS SetupProgressThread( if (Context->SetupResetSettings) RemoveDirectoryPath(PhGetString(Context->SetupInstallPath)); + // Create the uninstaller. + if (!SetupCreateUninstallFile(Context)) + goto CleanupExit; + // Create the ARP uninstall entries. SetupCreateUninstallKey(Context); - // Create the uninstaller. - SetupCreateUninstallFile(Context); + // Create autorun and shortcuts. SetupSetWindowsOptions(Context); @@ -163,8 +163,12 @@ INT_PTR CALLBACK SetupPropPage4_WndProc( case WM_START_SETUP: { #ifdef PH_BUILD_API - SetWindowText(context->MainHeaderHandle, - PhaFormatString(L"Installing Process Hacker %lu.%lu.%lu", PHAPP_VERSION_MAJOR, PHAPP_VERSION_MINOR, PHAPP_VERSION_REVISION)->Buffer); + SetWindowText(context->MainHeaderHandle, PhaFormatString( + L"Installing Process Hacker %lu.%lu.%lu", + PHAPP_VERSION_MAJOR, + PHAPP_VERSION_MINOR, + PHAPP_VERSION_REVISION + )->Buffer); #else SetWindowText(context->MainHeaderHandle, PhaFormatString( L"Installing Process Hacker %lu.%lu.%lu", diff --git a/tools/CustomSetupTool/CustomSetupTool/resources/version.rc b/tools/CustomSetupTool/CustomSetupTool/resources/version.rc index aad29825fe0b..780765938665 100644 --- a/tools/CustomSetupTool/CustomSetupTool/resources/version.rc +++ b/tools/CustomSetupTool/CustomSetupTool/resources/version.rc @@ -63,8 +63,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_AUS // VS_VERSION_INFO VERSIONINFO - FILEVERSION 3,0,0,0 - PRODUCTVERSION 3,0,0,0 + FILEVERSION PHAPP_VERSION_NUMBER + PRODUCTVERSION PHAPP_VERSION_NUMBER FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -81,12 +81,12 @@ BEGIN BEGIN VALUE "CompanyName", "Process Hacker" VALUE "FileDescription", "Process Hacker Setup" - VALUE "FileVersion", "3.0.0.0" + VALUE "FileVersion", PHAPP_VERSION_STRING VALUE "InternalName", "Process Hacker Setup" VALUE "LegalCopyright", "Licensed under the GNU GPL, v3. Copyright (C) 2017" VALUE "OriginalFilename", "ProcessHackerSetup.exe" VALUE "ProductName", "Process Hacker Setup" - VALUE "ProductVersion", "3.0.0.0" + VALUE "ProductVersion", PHAPP_VERSION_STRING END END BLOCK "VarFileInfo" @@ -100,9 +100,12 @@ END // // RCDATA // +#if defined(APSTUDIO_INVOKED) || defined(PH_BUILD_API) IDR_BIN_DATA RCDATA "../../../../build/output/processhacker-build-bin.zip" +#endif + #endif // English (Australia) resources ///////////////////////////////////////////////////////////////////////////// diff --git a/tools/CustomSetupTool/CustomSetupTool/setup.c b/tools/CustomSetupTool/CustomSetupTool/setup.c index 43affc76c917..9f0a316e62d4 100644 --- a/tools/CustomSetupTool/CustomSetupTool/setup.c +++ b/tools/CustomSetupTool/CustomSetupTool/setup.c @@ -166,30 +166,50 @@ PPH_STRING SetupFindInstallDirectory( return setupInstallPath; } -VOID SetupCreateUninstallFile( +BOOLEAN SetupCreateUninstallFile( _In_ PPH_SETUP_CONTEXT Context ) { + PH_STRINGREF currentFilePath; PPH_STRING backupFilePath; PPH_STRING uninstallFilePath; + PhUnicodeStringToStringRef(&NtCurrentPeb()->ProcessParameters->ImagePathName, ¤tFilePath); + + // Check if the user has started the setup from the installation folder. + if (PhStartsWithStringRef2(¤tFilePath, PhGetString(Context->SetupInstallPath), TRUE)) + { + // Do nothing, latest version already in the installation folder. + return TRUE; + } + backupFilePath = PhConcatStrings2(PhGetString(Context->SetupInstallPath), L"\\processhacker-setup.bak"); uninstallFilePath = PhConcatStrings2(PhGetString(Context->SetupInstallPath), L"\\processhacker-setup.exe"); if (RtlDoesFileExists_U(backupFilePath->Buffer)) { - // Move to temp directory - //MoveFile(uninstallFilePath->Buffer, backupFilePath->Buffer); + // TODO: Move to temp directory } if (RtlDoesFileExists_U(uninstallFilePath->Buffer)) { - MoveFile(uninstallFilePath->Buffer, backupFilePath->Buffer); + if (!MoveFile(uninstallFilePath->Buffer, backupFilePath->Buffer)) + { + Context->ErrorCode = GetLastError(); + PhDereferenceObject(uninstallFilePath); + return FALSE; + } } - CopyFile(NtCurrentPeb()->ProcessParameters->ImagePathName.Buffer, uninstallFilePath->Buffer, FALSE); + if (!CopyFile(currentFilePath.Buffer, uninstallFilePath->Buffer, FALSE)) + { + Context->ErrorCode = GetLastError(); + PhDereferenceObject(uninstallFilePath); + return FALSE; + } PhDereferenceObject(uninstallFilePath); + return TRUE; } VOID SetupDeleteUninstallFile( diff --git a/tools/CustomSetupTool/CustomSetupTool/update.c b/tools/CustomSetupTool/CustomSetupTool/update.c index 277057873142..1ba229e2cf3e 100644 --- a/tools/CustomSetupTool/CustomSetupTool/update.c +++ b/tools/CustomSetupTool/CustomSetupTool/update.c @@ -39,8 +39,10 @@ NTSTATUS SetupUpdateBuild( if (!SetupUninstallKph()) goto CleanupExit; + if (!SetupCreateUninstallFile(Context)) + goto CleanupExit; + SetupCreateUninstallKey(Context); - SetupCreateUninstallFile(Context); if (!SetupExtractBuild(Context)) goto CleanupExit; @@ -56,7 +58,7 @@ NTSTATUS SetupUpdateBuild( CleanupExit: - PostMessage(Context->PropSheetHandle, IDD_ERROR, 0, 0); + PostMessage(Context->PropSheetHandle, WM_APP + IDD_ERROR, 0, 0); PhDereferenceObject(Context); return STATUS_FAIL_CHECK; } @@ -102,6 +104,55 @@ VOID TaskDialogCreateIcons( SendMessage(Context->PropSheetHandle, WM_SETICON, ICON_BIG, (LPARAM)smallIcon); } +HRESULT CALLBACK SetupErrorTaskDialogCallbackProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam, + _In_ LONG_PTR dwRefData + ) +{ + PPH_SETUP_CONTEXT context = (PPH_SETUP_CONTEXT)dwRefData; + + switch (uMsg) + { + case TDN_NAVIGATED: + { + + } + break; + } + + return S_OK; +} + +VOID SetupShowUpdatingErrorDialog( + _In_ PPH_SETUP_CONTEXT Context + ) +{ + TASKDIALOGCONFIG config; + + memset(&config, 0, sizeof(TASKDIALOGCONFIG)); + config.cbSize = sizeof(TASKDIALOGCONFIG); + config.dwFlags = TDF_USE_HICON_MAIN | TDF_ALLOW_DIALOG_CANCELLATION | TDF_SHOW_MARQUEE_PROGRESS_BAR | TDF_CAN_BE_MINIMIZED | TDF_ENABLE_HYPERLINKS; + config.cxWidth = 200; + config.dwCommonButtons = TDCBF_CLOSE_BUTTON; + config.hMainIcon = Context->IconLargeHandle; + config.pfCallback = SetupErrorTaskDialogCallbackProc; + config.lpCallbackData = (LONG_PTR)Context; + config.pszWindowTitle = PhApplicationName; + config.pszMainInstruction = PhaFormatString( + L"Error updating to the latest version...", + PHAPP_VERSION_MAJOR, + PHAPP_VERSION_MINOR, + PHAPP_VERSION_REVISION + )->Buffer; + + if (Context->ErrorCode) + config.pszContent = PhGetStatusMessage(0, Context->ErrorCode)->Buffer; + SendMessage(Context->PropSheetHandle, TDM_NAVIGATE_PAGE, 0, (LPARAM)&config); +} + LRESULT CALLBACK TaskDialogSubclassProc( _In_ HWND hwndDlg, _In_ UINT uMsg, @@ -130,6 +181,11 @@ LRESULT CALLBACK TaskDialogSubclassProc( RemoveWindowSubclass(hwndDlg, TaskDialogSubclassProc, uIdSubclass); } break; + case WM_APP + IDD_ERROR: + { + SetupShowUpdatingErrorDialog(context); + } + break; } return DefSubclassProc(hwndDlg, uMsg, wParam, lParam); From 2973c03390ff0c9e494d55caf8c822d5862347c1 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 24 May 2017 17:21:52 +1000 Subject: [PATCH 0160/2058] Update ntpsapi.h Add missing PROCESS_HANDLE_TRACING flags --- phnt/include/ntpsapi.h | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/phnt/include/ntpsapi.h b/phnt/include/ntpsapi.h index ead669d1bb9e..62a3e96da340 100644 --- a/phnt/include/ntpsapi.h +++ b/phnt/include/ntpsapi.h @@ -439,21 +439,27 @@ typedef struct _PROCESS_SESSION_INFORMATION ULONG SessionId; } PROCESS_SESSION_INFORMATION, *PPROCESS_SESSION_INFORMATION; +#define PROCESS_HANDLE_RAISE_EXCEPTION_ON_INVALID_HANDLE_CLOSE_DISABLED 0x00000000 +#define PROCESS_HANDLE_RAISE_EXCEPTION_ON_INVALID_HANDLE_CLOSE_ENABLED 0x00000001 + typedef struct _PROCESS_HANDLE_TRACING_ENABLE { - ULONG Flags; // 0 to disable, 1 to enable + ULONG Flags; } PROCESS_HANDLE_TRACING_ENABLE, *PPROCESS_HANDLE_TRACING_ENABLE; +#define PROCESS_HANDLE_TRACING_MAX_SLOTS 0x20000 + typedef struct _PROCESS_HANDLE_TRACING_ENABLE_EX { - ULONG Flags; // 0 to disable, 1 to enable + ULONG Flags; ULONG TotalSlots; } PROCESS_HANDLE_TRACING_ENABLE_EX, *PPROCESS_HANDLE_TRACING_ENABLE_EX; #define PROCESS_HANDLE_TRACING_MAX_STACKS 16 -#define HANDLE_TRACE_DB_OPEN 1 -#define HANDLE_TRACE_DB_CLOSE 2 -#define HANDLE_TRACE_DB_BADREF 3 + +#define PROCESS_HANDLE_TRACE_TYPE_OPEN 1 +#define PROCESS_HANDLE_TRACE_TYPE_CLOSE 2 +#define PROCESS_HANDLE_TRACE_TYPE_BADREF 3 typedef struct _PROCESS_HANDLE_TRACING_ENTRY { From 35b0b98971d217ce52cd49cf6112b494f174ad46 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 24 May 2017 17:37:49 +1000 Subject: [PATCH 0161/2058] Add missing window icons --- ProcessHacker/memrslt.c | 3 +++ plugins/ExtraPlugins/dialog.c | 3 +++ 2 files changed, 6 insertions(+) diff --git a/ProcessHacker/memrslt.c b/ProcessHacker/memrslt.c index 36d36deaf05e..28c177c91ede 100644 --- a/ProcessHacker/memrslt.c +++ b/ProcessHacker/memrslt.c @@ -278,6 +278,9 @@ INT_PTR CALLBACK PhpMemoryResultsDlgProc( { HWND lvHandle; + SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhLibImageBase, MAKEINTRESOURCE(IDI_PROCESSHACKER))); + SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhLibImageBase, MAKEINTRESOURCE(IDI_PROCESSHACKER))); + PhRegisterDialog(hwndDlg); { diff --git a/plugins/ExtraPlugins/dialog.c b/plugins/ExtraPlugins/dialog.c index b924fe09d2d9..1e0c1b42c6b2 100644 --- a/plugins/ExtraPlugins/dialog.c +++ b/plugins/ExtraPlugins/dialog.c @@ -232,6 +232,9 @@ INT_PTR CALLBACK CloudPluginsDlgProc( { case WM_INITDIALOG: { + SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhLibImageBase, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); + SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhLibImageBase, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); + context->DialogHandle = hwndDlg; context->PluginMenuActiveId = IDC_INSTALLED; context->PluginMenuActive = GetDlgItem(hwndDlg, IDC_INSTALLED); From d57d7da602bc9b3cd404e08703784ee636958c4a Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 28 May 2017 15:00:36 +1000 Subject: [PATCH 0162/2058] Fix modules tab LoadCount for x32 (2/2) --- phlib/native.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/phlib/native.c b/phlib/native.c index 056c2a60e809..d00fdb099868 100644 --- a/phlib/native.c +++ b/phlib/native.c @@ -3148,8 +3148,8 @@ BOOLEAN NTAPI PhpEnumProcessModulesCallback( NULL ))) { - // HACK: Fixup the module load count (64bit only). - // Temp fix until PhpModuleQueryWorker can be updated with Stage2. + // HACK: Fixup the module load count. + // Temp fix until PhpModuleQueryWorker can be used for 'Stage2'. Entry->ObsoleteLoadCount = (USHORT)ldrDagNode.LoadCount; } } @@ -3529,6 +3529,24 @@ BOOLEAN NTAPI PhpEnumProcessModules32Callback( nativeEntry.FullDllName.Buffer = fullDllNameBuffer; } + if (WindowsVersion >= WINDOWS_8) + { + LDR_DDAG_NODE32 ldrDagNode32 = { 0 }; + + if (NT_SUCCESS(NtReadVirtualMemory( + ProcessHandle, + UlongToPtr(Entry->DdagNode), + &ldrDagNode32, + sizeof(LDR_DDAG_NODE32), + NULL + ))) + { + // HACK: Fixup the module load count. + // Temp fix until PhpModuleQueryWorker can be used for 'Stage2'. + nativeEntry.ObsoleteLoadCount = (USHORT)ldrDagNode32.LoadCount; + } + } + // Execute the callback. cont = parameters->Callback(&nativeEntry, parameters->Context); From 229741683fe9d7c983e9ec0af19050302bb9bc10 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 28 May 2017 15:25:44 +1000 Subject: [PATCH 0163/2058] Updater: Save changelog window position --- plugins/Updater/main.c | 4 +++- plugins/Updater/options.c | 9 +++++++-- plugins/Updater/updater.h | 2 ++ 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/plugins/Updater/main.c b/plugins/Updater/main.c index a6a73649f820..a6eb9efcde40 100644 --- a/plugins/Updater/main.c +++ b/plugins/Updater/main.c @@ -90,7 +90,9 @@ LOGICAL DllMain( PH_SETTING_CREATE settings[] = { { IntegerSettingType, SETTING_NAME_AUTO_CHECK, L"1" }, - { StringSettingType, SETTING_NAME_LAST_CHECK, L"0" }, + { StringSettingType, SETTING_NAME_LAST_CHECK, L"0" }, + { IntegerPairSettingType, SETTING_NAME_CHANGELOG_WINDOW_POSITION, L"0,0" }, + { ScalableIntegerPairSettingType, SETTING_NAME_CHANGELOG_WINDOW_SIZE, L"@96|420,250" }, }; PluginInstance = PhRegisterPlugin(PLUGIN_NAME, Instance, &info); diff --git a/plugins/Updater/options.c b/plugins/Updater/options.c index 2ca69914fc11..5b9deb95b995 100644 --- a/plugins/Updater/options.c +++ b/plugins/Updater/options.c @@ -89,19 +89,24 @@ INT_PTR CALLBACK TextDlgProc( SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhLibImageBase, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhLibImageBase, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); - PhCenterWindow(hwndDlg, GetParent(hwndDlg)); + SetWindowText(GetDlgItem(hwndDlg, IDC_TEXT), PhGetString(context->BuildMessage)); PhInitializeLayoutManager(&LayoutManager, hwndDlg); PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDC_TEXT), NULL, PH_ANCHOR_ALL); PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDCANCEL), NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_RIGHT); - SetWindowText(GetDlgItem(hwndDlg, IDC_TEXT), PhGetString(context->BuildMessage)); + if (PhGetIntegerPairSetting(SETTING_NAME_CHANGELOG_WINDOW_POSITION).X != 0) + PhLoadWindowPlacementFromSetting(SETTING_NAME_CHANGELOG_WINDOW_POSITION, SETTING_NAME_CHANGELOG_WINDOW_SIZE, hwndDlg); + else + PhCenterWindow(hwndDlg, GetParent(hwndDlg)); SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hwndDlg, IDCANCEL), TRUE); } break; case WM_DESTROY: { + PhSaveWindowPlacementToSetting(SETTING_NAME_CHANGELOG_WINDOW_POSITION, SETTING_NAME_CHANGELOG_WINDOW_SIZE, hwndDlg); + PhDeleteLayoutManager(&LayoutManager); } break; diff --git a/plugins/Updater/updater.h b/plugins/Updater/updater.h index 5afc567627b0..ae1d6e5e9f46 100644 --- a/plugins/Updater/updater.h +++ b/plugins/Updater/updater.h @@ -48,6 +48,8 @@ #define PLUGIN_NAME L"ProcessHacker.UpdateChecker" #define SETTING_NAME_AUTO_CHECK (PLUGIN_NAME L".PromptStart") #define SETTING_NAME_LAST_CHECK (PLUGIN_NAME L".LastUpdateCheckTime") +#define SETTING_NAME_CHANGELOG_WINDOW_POSITION (PLUGIN_NAME L".ChangelogWindowPosition") +#define SETTING_NAME_CHANGELOG_WINDOW_SIZE (PLUGIN_NAME L".ChangelogWindowSize") #define MAKE_VERSION_ULONGLONG(major, minor, build, revision) \ (((ULONGLONG)(major) << 48) | \ From a9ba83e163fb5a82cb769937c1854254c8121eee Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 28 May 2017 17:32:29 +1000 Subject: [PATCH 0164/2058] Remove unnecessary handle from ProcessQueryStage1 --- ProcessHacker/procprv.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/ProcessHacker/procprv.c b/ProcessHacker/procprv.c index 9445050002f7..510b16268626 100644 --- a/ProcessHacker/procprv.c +++ b/ProcessHacker/procprv.c @@ -949,9 +949,7 @@ VOID PhpProcessQueryStage1( NTSTATUS status; PPH_PROCESS_ITEM processItem = Data->Header.ProcessItem; HANDLE processId = processItem->ProcessId; - HANDLE processHandleLimited = NULL; - - PhOpenProcess(&processHandleLimited, ProcessQueryAccess, processId); + HANDLE processHandleLimited = processItem->QueryHandle; if (processItem->FileName) { @@ -1167,9 +1165,6 @@ VOID PhpProcessQueryStage1( Data->PackageFullName = PhGetProcessPackageFullName(processHandleLimited); } - if (processHandleLimited) - NtClose(processHandleLimited); - PhpQueueProcessQueryStage2(processItem); } From 6864383ebb268962c49f5569c3db1ebd5d0c0288 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 28 May 2017 18:20:35 +1000 Subject: [PATCH 0165/2058] Update ntpsapi.h with more RS2 types --- phnt/include/ntpsapi.h | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/phnt/include/ntpsapi.h b/phnt/include/ntpsapi.h index 62a3e96da340..23ae8b712e56 100644 --- a/phnt/include/ntpsapi.h +++ b/phnt/include/ntpsapi.h @@ -172,14 +172,14 @@ typedef enum _PROCESSINFOCLASS ProcessIumChallengeResponse, ProcessChildProcessInformation, // PROCESS_CHILD_PROCESS_INFORMATION ProcessHighGraphicsPriorityInformation, - ProcessSubsystemInformation, // since REDSTONE2 + ProcessSubsystemInformation, // q: SUBSYSTEM_INFORMATION_TYPE // since REDSTONE2 ProcessEnergyValues, - ProcessActivityThrottleState, - ProcessActivityThrottlePolicy, + ProcessActivityThrottleState, // PROCESS_ACTIVITY_THROTTLE_STATE + ProcessActivityThrottlePolicy, // PROCESS_ACTIVITY_THROTTLE_POLICY ProcessWin32kSyscallFilterInformation, ProcessDisableSystemAllowedCpuSets, - ProcessWakeInformation, - ProcessEnergyTrackingState, + ProcessWakeInformation, // PROCESS_WAKE_INFORMATION + ProcessEnergyTrackingState, // PROCESS_ENERGY_TRACKING_STATE MaxProcessInfoClass } PROCESSINFOCLASS; #endif @@ -232,7 +232,7 @@ typedef enum _THREADINFOCLASS ThreadDynamicCodePolicyInfo, ThreadExplicitCaseSensitivity, ThreadWorkOnBehalfTicket, - ThreadSubsystemInformation, // since REDSTONE2 + ThreadSubsystemInformation, // q: SUBSYSTEM_INFORMATION_TYPE // since REDSTONE2 ThreadDbgkWerReportActive, ThreadAttachContainer, MaxThreadInfoClass @@ -701,6 +701,22 @@ typedef struct _PROCESS_CHILD_PROCESS_INFORMATION BOOLEAN EnableAutomaticOverride; } PROCESS_CHILD_PROCESS_INFORMATION, *PPROCESS_CHILD_PROCESS_INFORMATION; +typedef struct _PROCESS_WAKE_INFORMATION +{ + ULONGLONG NotificationChannel; + ULONG WakeCounters[7]; + struct _JOBOBJECT_WAKE_FILTER* WakeFilter; +} PROCESS_WAKE_INFORMATION, *PPROCESS_WAKE_INFORMATION; + +typedef struct _PROCESS_ENERGY_TRACKING_STATE +{ + ULONG StateUpdateMask; + ULONG StateDesiredValue; + ULONG StateSequence; + ULONG UpdateTag : 1; + WCHAR Tag[64]; +} PROCESS_ENERGY_TRACKING_STATE, *PPROCESS_ENERGY_TRACKING_STATE; + // end_private #endif From 28d696011fe4277d6a23d197c52243a1caafb588 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 28 May 2017 18:55:57 +1000 Subject: [PATCH 0166/2058] Revert version.rc merge, Fix about window layout --- ProcessHacker/ProcessHacker.rc | 40 +------- ProcessHacker/ProcessHacker.vcxproj | 1 + ProcessHacker/ProcessHacker.vcxproj.filters | 3 + ProcessHacker/version.rc | 101 ++++++++++++++++++++ 4 files changed, 106 insertions(+), 39 deletions(-) create mode 100644 ProcessHacker/version.rc diff --git a/ProcessHacker/ProcessHacker.rc b/ProcessHacker/ProcessHacker.rc index e9bcdd06a676..4f52ab152a7d 100644 --- a/ProcessHacker/ProcessHacker.rc +++ b/ProcessHacker/ProcessHacker.rc @@ -636,7 +636,7 @@ BEGIN ICON IDI_PROCESSHACKER,IDC_STATIC,16,15,20,20 LTEXT "Process Hacker",IDC_ABOUT_NAME,45,14,192,8 LTEXT "Licensed under the GNU GPL, v3.",IDC_STATIC,45,27,193,8 - LTEXT "Copyright (c) 2008-2017 Wen Jia Liu (wj32)",IDC_STATIC,15,40,140,8 + LTEXT "Copyright (c) 2008-2017",IDC_STATIC,45,40,80,8 CONTROL "Credits.",IDC_CREDITS,"SysLink",WS_TABSTOP,15,55,248,115 CONTROL "Process Hacker on SourceForge.net",IDC_LINK_SF, "SysLink",WS_TABSTOP,7,177,130,11 @@ -2535,44 +2535,6 @@ IDB_SEARCH_ACTIVE PNG "resources\\active_search.png" IDB_SEARCH_INACTIVE PNG "resources\\inactive_search.png" -///////////////////////////////////////////////////////////////////////////// -// -// Version -// - -VS_VERSION_INFO VERSIONINFO - FILEVERSION PHAPP_VERSION_NUMBER - PRODUCTVERSION PHAPP_VERSION_NUMBER - FILEFLAGSMASK 0x3fL -#ifdef _DEBUG - FILEFLAGS 0x1L -#else - FILEFLAGS 0x0L -#endif - FILEOS 0x40004L - FILETYPE 0x1L - FILESUBTYPE 0x0L -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "0c0904b0" - BEGIN - VALUE "CompanyName", "Process Hacker" - VALUE "FileDescription", "Process Hacker" - VALUE "FileVersion", PHAPP_VERSION_STRING - VALUE "InternalName", "ProcessHacker.exe" - VALUE "LegalCopyright", "Licensed under the GNU GPL, v3. Copyright (C) 2017" - VALUE "OriginalFilename", "ProcessHacker.exe" - VALUE "ProductName", "Process Hacker" - VALUE "ProductVersion", PHAPP_VERSION_STRING - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0xc09, 1200 - END -END - #endif // English (Australia) resources ///////////////////////////////////////////////////////////////////////////// diff --git a/ProcessHacker/ProcessHacker.vcxproj b/ProcessHacker/ProcessHacker.vcxproj index 9168ea48f7b7..03188043fdab 100644 --- a/ProcessHacker/ProcessHacker.vcxproj +++ b/ProcessHacker/ProcessHacker.vcxproj @@ -401,6 +401,7 @@ + diff --git a/ProcessHacker/ProcessHacker.vcxproj.filters b/ProcessHacker/ProcessHacker.vcxproj.filters index e4fac5fddc0e..f93d2a3fb8b1 100644 --- a/ProcessHacker/ProcessHacker.vcxproj.filters +++ b/ProcessHacker/ProcessHacker.vcxproj.filters @@ -576,6 +576,9 @@ Resources + + Resources + diff --git a/ProcessHacker/version.rc b/ProcessHacker/version.rc new file mode 100644 index 000000000000..d9685eada357 --- /dev/null +++ b/ProcessHacker/version.rc @@ -0,0 +1,101 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "winres.h" +#include "include/phappres.h" +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (Australia) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENA) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_AUS +#pragma code_page(1252) + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""winres.h""\r\n" + "#include ""include/phappres.h""\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION PHAPP_VERSION_NUMBER + PRODUCTVERSION PHAPP_VERSION_NUMBER + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "0c0904b0" + BEGIN + VALUE "CompanyName", "Process Hacker" + VALUE "FileDescription", "Process Hacker" + VALUE "FileVersion", PHAPP_VERSION_STRING + VALUE "InternalName", "ProcessHacker.exe" + VALUE "LegalCopyright", "Licensed under the GNU GPL, v3. Copyright (C) 2017" + VALUE "OriginalFilename", "ProcessHacker.exe" + VALUE "ProductName", "Process Hacker" + VALUE "ProductVersion", PHAPP_VERSION_STRING + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0xc09, 1200 + END +END + + +#endif // English (Australia) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + From c583fd2e512c6dafae8a26e4cd3f2a80dce4582a Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 28 May 2017 22:05:18 +1000 Subject: [PATCH 0167/2058] Update SYSTEM_INFORMATION_CLASS types --- phnt/include/ntexapi.h | 257 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 239 insertions(+), 18 deletions(-) diff --git a/phnt/include/ntexapi.h b/phnt/include/ntexapi.h index 8fad61a03a9d..22ffd1b62362 100644 --- a/phnt/include/ntexapi.h +++ b/phnt/include/ntexapi.h @@ -1209,8 +1209,8 @@ typedef enum _SYSTEM_INFORMATION_CLASS SystemFlagsInformation, // q: SYSTEM_FLAGS_INFORMATION SystemCallTimeInformation, // not implemented // SYSTEM_CALL_TIME_INFORMATION // 10 SystemModuleInformation, // q: RTL_PROCESS_MODULES - SystemLocksInformation, // q: SYSTEM_LOCK_INFORMATION - SystemStackTraceInformation, + SystemLocksInformation, // q: RTL_PROCESS_LOCKS + SystemStackTraceInformation, // q: RTL_PROCESS_BACKTRACES SystemPagedPoolInformation, // not implemented SystemNonPagedPoolInformation, // not implemented SystemHandleInformation, // q: SYSTEM_HANDLE_INFORMATION @@ -1228,7 +1228,7 @@ typedef enum _SYSTEM_INFORMATION_CLASS SystemTimeAdjustmentInformation, // q: SYSTEM_QUERY_TIME_ADJUST_INFORMATION; s: SYSTEM_SET_TIME_ADJUST_INFORMATION (requires SeSystemtimePrivilege) SystemSummaryMemoryInformation, // not implemented SystemMirrorMemoryInformation, // s (requires license value "Kernel-MemoryMirroringSupported") (requires SeShutdownPrivilege) // 30 - SystemPerformanceTraceInformation, // s + SystemPerformanceTraceInformation, // q; s: (type depends on EVENT_TRACE_INFORMATION_CLASS) SystemObsolete0, // not implemented SystemExceptionInformation, // q: SYSTEM_EXCEPTION_INFORMATION SystemCrashDumpStateInformation, // s (requires SeDebugPrivilege) @@ -1324,10 +1324,10 @@ typedef enum _SYSTEM_INFORMATION_CLASS SystemQueryPerformanceCounterInformation, // q: SYSTEM_QUERY_PERFORMANCE_COUNTER_INFORMATION // since WIN7 SP1 SystemSessionBigPoolInformation, // q: SYSTEM_SESSION_POOLTAG_INFORMATION // since WIN8 SystemBootGraphicsInformation, // q; s: SYSTEM_BOOT_GRAPHICS_INFORMATION (kernel-mode only) - SystemScrubPhysicalMemoryInformation, + SystemScrubPhysicalMemoryInformation, // q; s: MEMORY_SCRUB_INFORMATION SystemBadPageInformation, - SystemProcessorProfileControlArea, - SystemCombinePhysicalMemoryInformation, // 130 + SystemProcessorProfileControlArea, // q; s: SYSTEM_PROCESSOR_PROFILE_CONTROL_AREA + SystemCombinePhysicalMemoryInformation, // s: MEMORY_COMBINE_INFORMATION, MEMORY_COMBINE_INFORMATION_EX, MEMORY_COMBINE_INFORMATION_EX2 // 130 SystemEntropyInterruptTimingCallback, SystemConsoleInformation, // q: SYSTEM_CONSOLE_INFORMATION SystemPlatformBinaryInformation, // q: SYSTEM_PLATFORM_BINARY_INFORMATION @@ -1619,30 +1619,46 @@ typedef struct _SYSTEM_CALL_TIME_INFORMATION } SYSTEM_CALL_TIME_INFORMATION, *PSYSTEM_CALL_TIME_INFORMATION; // private -typedef struct _SYSTEM_LOCK_TABLE_ENTRY_INFO +typedef struct _RTL_PROCESS_LOCK_INFORMATION { PVOID Address; USHORT Type; - USHORT Reserved1; - ULONG ExclusiveOwnerThreadId; - ULONG ActiveCount; USHORT CreatorBackTraceIndex; HANDLE OwningThread; LONG LockCount; ULONG ContentionCount; - ULONG Reserved2[2]; ULONG EntryCount; LONG RecursionCount; - ULONG NumberOfSharedWaiters; - ULONG NumberOfExclusiveWaiters; -} SYSTEM_LOCK_TABLE_ENTRY_INFO, *PSYSTEM_LOCK_TABLE_ENTRY_INFO; + ULONG NumberOfWaitingShared; + ULONG NumberOfWaitingExclusive; +} RTL_PROCESS_LOCK_INFORMATION, *PRTL_PROCESS_LOCK_INFORMATION; // private -typedef struct _SYSTEM_LOCK_INFORMATION +typedef struct _RTL_PROCESS_LOCKS { - ULONG Count; - SYSTEM_LOCK_TABLE_ENTRY_INFO Locks[1]; -} SYSTEM_LOCK_INFORMATION, *PSYSTEM_LOCK_INFORMATION; + ULONG NumberOfLocks; + RTL_PROCESS_LOCK_INFORMATION Locks[1]; +} RTL_PROCESS_LOCKS, *PRTL_PROCESS_LOCKS; + +// private +typedef struct _RTL_PROCESS_BACKTRACE_INFORMATION +{ + PCHAR SymbolicBackTrace; + ULONG TraceCount; + USHORT Index; + USHORT Depth; + PVOID BackTrace[32]; +} RTL_PROCESS_BACKTRACE_INFORMATION, *PRTL_PROCESS_BACKTRACE_INFORMATION; + +// private +typedef struct _RTL_PROCESS_BACKTRACES +{ + ULONG CommittedMemory; + ULONG ReservedMemory; + ULONG NumberOfBackTraceLookups; + ULONG NumberOfBackTraces; + RTL_PROCESS_BACKTRACE_INFORMATION BackTraces[1]; +} RTL_PROCESS_BACKTRACES, *PRTL_PROCESS_BACKTRACES; typedef struct _SYSTEM_HANDLE_TABLE_ENTRY_INFO { @@ -1780,6 +1796,147 @@ typedef struct _SYSTEM_SET_TIME_ADJUST_INFORMATION BOOLEAN Enable; } SYSTEM_SET_TIME_ADJUST_INFORMATION, *PSYSTEM_SET_TIME_ADJUST_INFORMATION; +typedef enum _EVENT_TRACE_INFORMATION_CLASS +{ + EventTraceKernelVersionInformation, // EVENT_TRACE_VERSION_INFORMATION + EventTraceGroupMaskInformation, // EVENT_TRACE_GROUPMASK_INFORMATION + EventTracePerformanceInformation, // EVENT_TRACE_PERFORMANCE_INFORMATION + EventTraceTimeProfileInformation, // EVENT_TRACE_TIME_PROFILE_INFORMATION + EventTraceSessionSecurityInformation, // EVENT_TRACE_SESSION_SECURITY_INFORMATION + EventTraceSpinlockInformation, // EVENT_TRACE_SPINLOCK_INFORMATION + EventTraceStackTracingInformation, // EVENT_TRACE_SYSTEM_EVENT_INFORMATION + EventTraceExecutiveResourceInformation, // EVENT_TRACE_EXECUTIVE_RESOURCE_INFORMATION + EventTraceHeapTracingInformation, // EVENT_TRACE_HEAP_TRACING_INFORMATION + EventTraceHeapSummaryTracingInformation, // EVENT_TRACE_HEAP_TRACING_INFORMATION + EventTracePoolTagFilterInformation, // EVENT_TRACE_TAG_FILTER_INFORMATION + EventTracePebsTracingInformation, // EVENT_TRACE_SYSTEM_EVENT_INFORMATION + EventTraceProfileConfigInformation, // EVENT_TRACE_PROFILE_COUNTER_INFORMATION + EventTraceProfileSourceListInformation, // EVENT_TRACE_PROFILE_LIST_INFORMATION + EventTraceProfileEventListInformation, // EVENT_TRACE_SYSTEM_EVENT_INFORMATION + EventTraceProfileCounterListInformation, // EVENT_TRACE_PROFILE_COUNTER_INFORMATION + EventTraceStackCachingInformation, // EVENT_TRACE_STACK_CACHING_INFORMATION + EventTraceObjectTypeFilterInformation, // EVENT_TRACE_TAG_FILTER_INFORMATION + EventTraceSoftRestartInformation, // EVENT_TRACE_SOFT_RESTART_INFORMATION + MaxEventTraceInfoClass +} EVENT_TRACE_INFORMATION_CLASS; + +typedef struct _EVENT_TRACE_VERSION_INFORMATION +{ + EVENT_TRACE_INFORMATION_CLASS EventTraceInformationClass; + ULONG EventTraceKernelVersion; +} EVENT_TRACE_VERSION_INFORMATION, *PEVENT_TRACE_VERSION_INFORMATION; + +typedef struct _PERFINFO_GROUPMASK +{ + ULONG Masks[8]; +} PERFINFO_GROUPMASK, *PPERFINFO_GROUPMASK; + +typedef struct _EVENT_TRACE_GROUPMASK_INFORMATION +{ + EVENT_TRACE_INFORMATION_CLASS EventTraceInformationClass; + HANDLE TraceHandle; + PERFINFO_GROUPMASK EventTraceGroupMasks; +} EVENT_TRACE_GROUPMASK_INFORMATION, *PEVENT_TRACE_GROUPMASK_INFORMATION; + +typedef struct _EVENT_TRACE_PERFORMANCE_INFORMATION +{ + EVENT_TRACE_INFORMATION_CLASS EventTraceInformationClass; + LARGE_INTEGER LogfileBytesWritten; +} EVENT_TRACE_PERFORMANCE_INFORMATION, *PEVENT_TRACE_PERFORMANCE_INFORMATION; + +typedef struct _EVENT_TRACE_TIME_PROFILE_INFORMATION +{ + EVENT_TRACE_INFORMATION_CLASS EventTraceInformationClass; + ULONG ProfileInterval; +} EVENT_TRACE_TIME_PROFILE_INFORMATION, *PEVENT_TRACE_TIME_PROFILE_INFORMATION; + +typedef struct _EVENT_TRACE_SESSION_SECURITY_INFORMATION +{ + EVENT_TRACE_INFORMATION_CLASS EventTraceInformationClass; + ULONG SecurityInformation; + HANDLE TraceHandle; + UCHAR SecurityDescriptor[1]; +} EVENT_TRACE_SESSION_SECURITY_INFORMATION, *PEVENT_TRACE_SESSION_SECURITY_INFORMATION; + +typedef struct _EVENT_TRACE_SPINLOCK_INFORMATION +{ + EVENT_TRACE_INFORMATION_CLASS EventTraceInformationClass; + ULONG SpinLockSpinThreshold; + ULONG SpinLockAcquireSampleRate; + ULONG SpinLockContentionSampleRate; + ULONG SpinLockHoldThreshold; +} EVENT_TRACE_SPINLOCK_INFORMATION, *PEVENT_TRACE_SPINLOCK_INFORMATION; + +typedef struct _EVENT_TRACE_SYSTEM_EVENT_INFORMATION +{ + EVENT_TRACE_INFORMATION_CLASS EventTraceInformationClass; + HANDLE TraceHandle; + ULONG HookId[1]; +} EVENT_TRACE_SYSTEM_EVENT_INFORMATION, *PEVENT_TRACE_SYSTEM_EVENT_INFORMATION; + +typedef struct _EVENT_TRACE_EXECUTIVE_RESOURCE_INFORMATION +{ + EVENT_TRACE_INFORMATION_CLASS EventTraceInformationClass; + ULONG ReleaseSamplingRate; + ULONG ContentionSamplingRate; + ULONG NumberOfExcessiveTimeouts; +} EVENT_TRACE_EXECUTIVE_RESOURCE_INFORMATION, *PEVENT_TRACE_EXECUTIVE_RESOURCE_INFORMATION; + +typedef struct _EVENT_TRACE_HEAP_TRACING_INFORMATION +{ + EVENT_TRACE_INFORMATION_CLASS EventTraceInformationClass; + ULONG ProcessId; +} EVENT_TRACE_HEAP_TRACING_INFORMATION, *PEVENT_TRACE_HEAP_TRACING_INFORMATION; + +typedef struct _EVENT_TRACE_TAG_FILTER_INFORMATION +{ + EVENT_TRACE_INFORMATION_CLASS EventTraceInformationClass; + HANDLE TraceHandle; + ULONG Filter[1]; +} EVENT_TRACE_TAG_FILTER_INFORMATION, *PEVENT_TRACE_TAG_FILTER_INFORMATION; + +typedef struct _EVENT_TRACE_PROFILE_COUNTER_INFORMATION +{ + EVENT_TRACE_INFORMATION_CLASS EventTraceInformationClass; + HANDLE TraceHandle; + ULONG ProfileSource[1]; +} EVENT_TRACE_PROFILE_COUNTER_INFORMATION, *PEVENT_TRACE_PROFILE_COUNTER_INFORMATION; + +typedef struct _PROFILE_SOURCE_INFO +{ + ULONG NextEntryOffset; + ULONG Source; + ULONG MinInterval; + ULONG MaxInterval; + ULONGLONG Reserved; + WCHAR Description[1]; +} PROFILE_SOURCE_INFO, *PPROFILE_SOURCE_INFO; + +typedef struct _EVENT_TRACE_PROFILE_LIST_INFORMATION +{ + EVENT_TRACE_INFORMATION_CLASS EventTraceInformationClass; + ULONG Spare; + PROFILE_SOURCE_INFO Profile[1]; +} EVENT_TRACE_PROFILE_LIST_INFORMATION, *PEVENT_TRACE_PROFILE_LIST_INFORMATION; + +typedef struct _EVENT_TRACE_STACK_CACHING_INFORMATION +{ + EVENT_TRACE_INFORMATION_CLASS EventTraceInformationClass; + HANDLE TraceHandle; + BOOLEAN Enabled; + UCHAR Reserved[3]; + ULONG CacheSize; + ULONG BucketCount; +} EVENT_TRACE_STACK_CACHING_INFORMATION, *PEVENT_TRACE_STACK_CACHING_INFORMATION; + +typedef struct _EVENT_TRACE_SOFT_RESTART_INFORMATION +{ + EVENT_TRACE_INFORMATION_CLASS EventTraceInformationClass; + HANDLE TraceHandle; + BOOLEAN PersistTraceBuffers; + WCHAR FileName[1]; +} EVENT_TRACE_SOFT_RESTART_INFORMATION, *PEVENT_TRACE_SOFT_RESTART_INFORMATION; + typedef struct _SYSTEM_EXCEPTION_INFORMATION { ULONG AlignmentFixupCount; @@ -2331,6 +2488,70 @@ typedef struct _SYSTEM_BOOT_GRAPHICS_INFORMATION ULONG DisplayRotation; } SYSTEM_BOOT_GRAPHICS_INFORMATION, *PSYSTEM_BOOT_GRAPHICS_INFORMATION; +// private +typedef struct _MEMORY_SCRUB_INFORMATION +{ + HANDLE Handle; + ULONG PagesScrubbed; +} MEMORY_SCRUB_INFORMATION, *PMEMORY_SCRUB_INFORMATION; + +// private +typedef struct _PEBS_DS_SAVE_AREA +{ + ULONGLONG BtsBufferBase; + ULONGLONG BtsIndex; + ULONGLONG BtsAbsoluteMaximum; + ULONGLONG BtsInterruptThreshold; + ULONGLONG PebsBufferBase; + ULONGLONG PebsIndex; + ULONGLONG PebsAbsoluteMaximum; + ULONGLONG PebsInterruptThreshold; + ULONGLONG PebsCounterReset0; + ULONGLONG PebsCounterReset1; + ULONGLONG PebsCounterReset2; + ULONGLONG PebsCounterReset3; +} PEBS_DS_SAVE_AREA, *PPEBS_DS_SAVE_AREA; + +// private +typedef struct _PROCESSOR_PROFILE_CONTROL_AREA +{ + PEBS_DS_SAVE_AREA PebsDsSaveArea; +} PROCESSOR_PROFILE_CONTROL_AREA, *PPROCESSOR_PROFILE_CONTROL_AREA; + +// private +typedef struct _SYSTEM_PROCESSOR_PROFILE_CONTROL_AREA +{ + PROCESSOR_PROFILE_CONTROL_AREA ProcessorProfileControlArea; + BOOLEAN Allocate; +} SYSTEM_PROCESSOR_PROFILE_CONTROL_AREA, *PSYSTEM_PROCESSOR_PROFILE_CONTROL_AREA; + +// private +typedef struct _MEMORY_COMBINE_INFORMATION +{ + HANDLE Handle; + ULONG_PTR PagesCombined; +} MEMORY_COMBINE_INFORMATION, *PMEMORY_COMBINE_INFORMATION; + +// rev +#define MEMORY_COMBINE_FLAGS_COMMON_PAGES_ONLY 0x4 + +// private +typedef struct _MEMORY_COMBINE_INFORMATION_EX +{ + HANDLE Handle; + ULONG_PTR PagesCombined; + ULONG Flags; +} MEMORY_COMBINE_INFORMATION_EX, *PMEMORY_COMBINE_INFORMATION_EX; + +// private +typedef struct _MEMORY_COMBINE_INFORMATION_EX2 +{ + HANDLE Handle; + ULONG_PTR PagesCombined; + ULONG Flags; + HANDLE ProcessHandle; +} MEMORY_COMBINE_INFORMATION_EX2, *PMEMORY_COMBINE_INFORMATION_EX2; + // private typedef struct _SYSTEM_CONSOLE_INFORMATION { From 7ce6b0aa13b3b559e227bb3dd7e06fb586407d50 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 28 May 2017 22:35:26 +1000 Subject: [PATCH 0168/2058] Update SYSTEM_INFORMATION_CLASS with more RS2 types --- phnt/include/ntexapi.h | 44 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 41 insertions(+), 3 deletions(-) diff --git a/phnt/include/ntexapi.h b/phnt/include/ntexapi.h index 22ffd1b62362..8667b40190de 100644 --- a/phnt/include/ntexapi.h +++ b/phnt/include/ntexapi.h @@ -1384,10 +1384,10 @@ typedef enum _SYSTEM_INFORMATION_CLASS SystemPhysicalMemoryInformation, // q: SYSTEM_PHYSICAL_MEMORY_INFORMATION // since REDSTONE2 SystemControlFlowTransition, SystemKernelDebuggingAllowed, - SystemActivityModerationExeState, - SystemActivityModerationUserSettings, + SystemActivityModerationExeState, // SYSTEM_ACTIVITY_MODERATION_EXE_STATE + SystemActivityModerationUserSettings, // SYSTEM_ACTIVITY_MODERATION_USER_SETTINGS SystemCodeIntegrityPoliciesFullInformation, - SystemCodeIntegrityUnlockInformation, // 190 + SystemCodeIntegrityUnlockInformation, // SYSTEM_CODEINTEGRITY_UNLOCK_INFORMATION // 190 SystemIntegrityQuotaInformation, SystemFlushInformation, // q: SYSTEM_FLUSH_INFORMATION MaxSystemInfoClass @@ -2918,6 +2918,44 @@ typedef struct _SYSTEM_PHYSICAL_MEMORY_INFORMATION ULONGLONG HighestPhysicalAddress; } SYSTEM_PHYSICAL_MEMORY_INFORMATION, *PSYSTEM_PHYSICAL_MEMORY_INFORMATION; +// private +typedef enum _SYSTEM_ACTIVITY_MODERATION_STATE +{ + SystemActivityModerationStateSystemManaged, + SystemActivityModerationStateAlwaysThrottled, + SystemActivityModerationStateNeverThrottled, + MaxSystemActivityModerationState +} SYSTEM_ACTIVITY_MODERATION_STATE; + +// private +typedef struct _SYSTEM_ACTIVITY_MODERATION_EXE_STATE +{ + UNICODE_STRING ExePathNt; + SYSTEM_ACTIVITY_MODERATION_STATE ModerationState; +} SYSTEM_ACTIVITY_MODERATION_EXE_STATE, *PSYSTEM_ACTIVITY_MODERATION_EXE_STATE; + +// private +typedef struct _SYSTEM_ACTIVITY_MODERATION_USER_SETTINGS +{ + HANDLE UserKeyHandle; +} SYSTEM_ACTIVITY_MODERATION_USER_SETTINGS, *PSYSTEM_ACTIVITY_MODERATION_USER_SETTINGS; + +// private +typedef struct _SYSTEM_CODEINTEGRITY_UNLOCK_INFORMATION +{ + union + { + ULONG Flags; + struct + { + ULONG Locked : 1; + ULONG Unlockable : 1; + ULONG UnlockApplied : 1; + ULONG Reserved : 29; + }; + }; +} SYSTEM_CODEINTEGRITY_UNLOCK_INFORMATION, *PSYSTEM_CODEINTEGRITY_UNLOCK_INFORMATION; + // private typedef struct _SYSTEM_FLUSH_INFORMATION { From 5904915bdd79d5208ba6ffb8afa8e8faed00b35e Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 28 May 2017 23:30:04 +1000 Subject: [PATCH 0169/2058] Remove PROFILE_SOURCE_INFO due to SDK conflict --- phnt/include/ntexapi.h | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/phnt/include/ntexapi.h b/phnt/include/ntexapi.h index 8667b40190de..545f81e9ad52 100644 --- a/phnt/include/ntexapi.h +++ b/phnt/include/ntexapi.h @@ -1902,21 +1902,11 @@ typedef struct _EVENT_TRACE_PROFILE_COUNTER_INFORMATION ULONG ProfileSource[1]; } EVENT_TRACE_PROFILE_COUNTER_INFORMATION, *PEVENT_TRACE_PROFILE_COUNTER_INFORMATION; -typedef struct _PROFILE_SOURCE_INFO -{ - ULONG NextEntryOffset; - ULONG Source; - ULONG MinInterval; - ULONG MaxInterval; - ULONGLONG Reserved; - WCHAR Description[1]; -} PROFILE_SOURCE_INFO, *PPROFILE_SOURCE_INFO; - typedef struct _EVENT_TRACE_PROFILE_LIST_INFORMATION { EVENT_TRACE_INFORMATION_CLASS EventTraceInformationClass; ULONG Spare; - PROFILE_SOURCE_INFO Profile[1]; + struct _PROFILE_SOURCE_INFO* Profile[1]; } EVENT_TRACE_PROFILE_LIST_INFORMATION, *PEVENT_TRACE_PROFILE_LIST_INFORMATION; typedef struct _EVENT_TRACE_STACK_CACHING_INFORMATION From 7e2abf1068fefd6c8637e170e88e7c78641d10a0 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 29 May 2017 10:06:58 +1000 Subject: [PATCH 0170/2058] peview: Tidy up names --- tools/peview/include/pdb.h | 205 +++++++++++--- tools/peview/include/peview.h | 7 +- tools/peview/pdb.c | 511 ++++++++++++++++++---------------- 3 files changed, 437 insertions(+), 286 deletions(-) diff --git a/tools/peview/include/pdb.h b/tools/peview/include/pdb.h index b9e7ef2addaa..5b04419d4d39 100644 --- a/tools/peview/include/pdb.h +++ b/tools/peview/include/pdb.h @@ -175,7 +175,10 @@ typedef struct _PointerTypeInfo ULONG64 Length; // Index of the type the pointer points to (DIA: typeId) - ULONG TypeIndex; + ULONG TypeIndex; + + // Reference ("reference" in DIA) + BOOL TypeReference; } PointerTypeInfo; // SymTagUDT symbol (Class or structure) @@ -362,52 +365,176 @@ typedef struct _TypeInfo union { - BaseTypeInfo sBaseTypeInfo; // If Tag == SymTagBaseType - TypedefInfo sTypedefInfo; // If Tag == SymTagTypedef - PointerTypeInfo sPointerTypeInfo; // If Tag == SymTagPointerType - UdtClassInfo sUdtClassInfo; // If Tag == SymTagUDT and UdtKind is "true" - UdtUnionInfo sUdtUnionInfo; // If Tag == SymTagUDT and UdtKind is "false" - BaseClassInfo sBaseClassInfo; // If Tag == SymTagBaseClass - EnumInfo sEnumInfo; // If Tag == SymTagEnum - ArrayTypeInfo sArrayTypeInfo; // If Tag == SymTagArrayType - FunctionTypeInfo sFunctionTypeInfo; // If Tag == SymTagFunctionType - FunctionArgTypeInfo sFunctionArgTypeInfo; // If Tag == SymTagFunctionArgType - DataInfo sDataInfo; // If Tag == SymTagData + BaseTypeInfo BaseTypeInfo; // If Tag == SymTagBaseType + TypedefInfo TypedefInfo; // If Tag == SymTagTypedef + PointerTypeInfo PointerTypeInfo; // If Tag == SymTagPointerType + UdtClassInfo UdtClassInfo; // If Tag == SymTagUDT and UdtKind is "true" + UdtUnionInfo UdtUnionInfo; // If Tag == SymTagUDT and UdtKind is "false" + BaseClassInfo BaseClassInfo; // If Tag == SymTagBaseClass + EnumInfo EnumInfo; // If Tag == SymTagEnum + ArrayTypeInfo ArrayTypeInfo; // If Tag == SymTagArrayType + FunctionTypeInfo FunctionTypeInfo; // If Tag == SymTagFunctionType + FunctionArgTypeInfo FunctionArgTypeInfo; // If Tag == SymTagFunctionArgType + DataInfo DataInfo; // If Tag == SymTagData }; } TypeInfo; -BOOLEAN SymbolInfo_DumpBasicType(_Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, BaseTypeInfo* Info); -BOOLEAN SymbolInfo_DumpPointerType(_Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, PointerTypeInfo* Info); -BOOLEAN SymbolInfo_DumpTypedef(_Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, TypedefInfo* Info); -BOOLEAN SymbolInfo_DumpEnum(_Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, EnumInfo* Info); -BOOLEAN SymbolInfo_DumpArrayType(_Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, ArrayTypeInfo* Info); -BOOLEAN SymbolInfo_DumpUDT(_Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, TypeInfo* Info); -BOOLEAN SymbolInfo_DumpUDTClass(_Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, UdtClassInfo* Info); -BOOLEAN SymbolInfo_DumpUDTUnion(_Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, UdtUnionInfo* Info); -BOOLEAN SymbolInfo_DumpFunctionType(_Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, FunctionTypeInfo* Info); -BOOLEAN SymbolInfo_DumpFunctionArgType(_Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, FunctionArgTypeInfo* Info); -BOOLEAN SymbolInfo_DumpBaseClass(_Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, BaseClassInfo* Info); -BOOLEAN SymbolInfo_DumpData(_Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, DataInfo* Info); -BOOLEAN SymbolInfo_DumpType(_Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, TypeInfo* Info); +BOOLEAN PdbGetSymbolBasicType( + _In_ ULONG64 BaseAddress, + _In_ ULONG Index, + _Inout_ BaseTypeInfo* Info + ); + +BOOLEAN PdbGetSymbolPointerType( + _In_ ULONG64 BaseAddress, + _In_ ULONG Index, + _Inout_ PointerTypeInfo* Info + ); + +BOOLEAN PdbGetSymbolTypedefType( + _In_ ULONG64 BaseAddress, + _In_ ULONG Index, + _Inout_ TypedefInfo* Info + ); + +BOOLEAN PdbGetSymbolEnumType( + _In_ ULONG64 BaseAddress, + _In_ ULONG Index, + _Inout_ EnumInfo* Info + ); + +BOOLEAN PdbGetSymbolArrayType( + _In_ ULONG64 BaseAddress, + _In_ ULONG Index, + _Inout_ ArrayTypeInfo* Info + ); + +BOOLEAN SymbolInfo_DumpUDT(_In_ ULONG64 BaseAddress, _In_ ULONG Index, TypeInfo* Info); + +BOOLEAN PdbGetSymbolUDTClass( + _In_ ULONG64 BaseAddress, + _In_ ULONG Index, + _Inout_ UdtClassInfo* Info + ); + +BOOLEAN PdbGetSymbolUDTUnion( + _In_ ULONG64 BaseAddress, + _In_ ULONG Index, + _Inout_ UdtUnionInfo *Info + ); + +BOOLEAN PdbGetSymbolFunctionType( + _In_ ULONG64 BaseAddress, + _In_ ULONG Index, + _Inout_ FunctionTypeInfo *Info + ); + +BOOLEAN PdbGetSymbolFunctionArgType( + _In_ ULONG64 BaseAddress, + _In_ ULONG Index, + _Inout_ FunctionArgTypeInfo *Info + ); + +BOOLEAN PdbGetSymbolBaseClass( + _In_ ULONG64 BaseAddress, + _In_ ULONG Index, + _Inout_ BaseClassInfo *Info + ); + +BOOLEAN PdbGetSymbolData( + _In_ ULONG64 BaseAddress, + _In_ ULONG Index, + _Inout_ DataInfo *Info + ); + +BOOLEAN SymbolInfo_DumpType(_In_ ULONG64 BaseAddress, _In_ ULONG Index, TypeInfo* Info); BOOLEAN SymbolInfo_DumpSymbolType(_Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, TypeInfo* Info, ULONG* TypeIndex); -BOOLEAN SymbolInfo_CheckTag( - _Inout_ PPDB_SYMBOL_CONTEXT Context, +BOOLEAN PdbCheckTagType( + _In_ ULONG64 BaseAddress, _In_ ULONG Index, _In_ ULONG Tag ); -BOOLEAN SymbolInfo_SymbolSize(_Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, ULONG64* Size); -BOOLEAN SymbolInfo_ArrayElementTypeIndex(_Inout_ PPDB_SYMBOL_CONTEXT Context, ULONG ArrayIndex, ULONG* ElementTypeIndex); -BOOLEAN SymbolInfo_ArrayDims(_Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, ULONG64* pDims, ULONG* Dims, _In_ ULONG MaxDims); -BOOLEAN SymbolInfo_UdtVariables(_Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, ULONG* pVars, ULONG* Vars, _In_ ULONG MaxVars); -BOOLEAN SymbolInfo_UdtFunctions(_Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, ULONG* pFuncs, ULONG* Funcs, _In_ ULONG MaxFuncs); -BOOLEAN SymbolInfo_UdtBaseClasses(_Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, ULONG* pBases, ULONG* Bases, _In_ ULONG MaxBases); -BOOLEAN SymbolInfo_UdtUnionMembers(_Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, ULONG* pMembers, ULONG* Members, _In_ ULONG MaxMembers); -BOOLEAN SymbolInfo_FunctionArguments(_Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, ULONG* pArgs, ULONG* Args, _In_ ULONG MaxArgs); -BOOLEAN SymbolInfo_Enumerators(_Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, ULONG* pEnums, ULONG* Enums, _In_ ULONG MaxEnums); -BOOLEAN SymbolInfo_TypeDefType(_Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, ULONG* UndTypeIndex); -BOOLEAN SymbolInfo_PointerType(_Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, ULONG* UndTypeIndex, ULONG* NumPointers); +BOOLEAN PdbGetSymbolSize( + _In_ ULONG64 BaseAddress, + _In_ ULONG Index, + _Inout_ ULONG64* Size + ); + +BOOLEAN PdbGetSymbolArrayElementTypeIndex( + _In_ ULONG64 BaseAddress, + _In_ ULONG ArrayIndex, + _Inout_ ULONG* ElementTypeIndex + ); + +BOOLEAN PdbGetSymbolArrayDimensions( + _In_ ULONG64 BaseAddress, + _In_ ULONG Index, + _Inout_ ULONG64* pDims, + _Inout_ ULONG* Dims, + _In_ ULONG MaxDims + ); + +BOOLEAN PdbGetSymbolUdtVariables( + _In_ ULONG64 BaseAddress, + _In_ ULONG Index, + _Inout_ ULONG* pVars, + _Inout_ ULONG* Vars, + _In_ ULONG MaxVars + ); + +BOOLEAN PdbGetSymbolUdtFunctions( + _In_ ULONG64 BaseAddress, + _In_ ULONG Index, + _Inout_ ULONG* pFuncs, + _Inout_ ULONG* Funcs, + _In_ ULONG MaxFuncs + ); + +BOOLEAN PdbGetSymbolUdtBaseClasses( + _In_ ULONG64 BaseAddress, + _In_ ULONG Index, + _Inout_ ULONG* pBases, + _Inout_ ULONG* Bases, + _In_ ULONG MaxBases); + +BOOLEAN PdbGetSymbolUdtUnionMembers( + _In_ ULONG64 BaseAddress, + _In_ ULONG Index, + _Inout_ ULONG* pMembers, + _Inout_ ULONG* Members, + _In_ ULONG MaxMembers + ); + +BOOLEAN PdbGetSymbolFunctionArguments( + _In_ ULONG64 BaseAddress, + _In_ ULONG Index, + _Inout_ ULONG* pArgs, + _Inout_ ULONG* Args, + _In_ ULONG MaxArgs + ); + +BOOLEAN PdbGetSymbolEnumerations( + _In_ ULONG64 BaseAddress, + _In_ ULONG Index, + _Inout_ ULONG *pEnums, + _Inout_ ULONG *Enums, + _In_ ULONG MaxEnums + ); + +BOOLEAN PdbGetSymbolTypeDefTypeIndex( + _In_ ULONG64 BaseAddress, + _In_ ULONG Index, + _Inout_ ULONG *UndTypeIndex + ); + +BOOLEAN PdbGetSymbolPointers( + _In_ ULONG64 BaseAddress, + _In_ ULONG Index, + _Inout_ ULONG *UndTypeIndex, + _Inout_ ULONG *NumPointers + ); BOOLEAN SymbolInfo_GetTypeNameHelper( _In_ ULONG Index, @@ -415,13 +542,11 @@ BOOLEAN SymbolInfo_GetTypeNameHelper( _Out_ PWSTR *VarName, _Inout_ PPH_STRING_BUILDER TypeName ); - PPH_STRING SymbolInfo_GetTypeName( _Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, _In_ PWSTR VarName ); - PWSTR SymbolInfo_TagStr(enum SymTagEnum Tag); PWSTR SymbolInfo_BaseTypeStr(BasicType Type, ULONG64 Length); PWSTR SymbolInfo_CallConvStr(CV_call_e CallConv); diff --git a/tools/peview/include/peview.h b/tools/peview/include/peview.h index 253606b17cdf..10a4cc2c73bc 100644 --- a/tools/peview/include/peview.h +++ b/tools/peview/include/peview.h @@ -135,7 +135,7 @@ typedef struct _PH_TN_COLUMN_MENU_DATA #define PH_TN_COLUMN_MENU_SIZE_ALL_COLUMNS_TO_FIT_ID ((ULONG)-4) #define PH_TN_COLUMN_MENU_RESET_SORT_ID ((ULONG)-5) - VOID PhInitializeTreeNewColumnMenu( +VOID PhInitializeTreeNewColumnMenu( _Inout_ PPH_TN_COLUMN_MENU_DATA Data ); @@ -240,6 +240,11 @@ NTSTATUS PeDumpFileSymbols( _In_ PPDB_SYMBOL_CONTEXT Context ); +VOID PdbDumpAddress( + _In_ PPDB_SYMBOL_CONTEXT Context, + _In_ ULONG64 Address + ); + VOID PvPdbProperties( VOID ); diff --git a/tools/peview/pdb.c b/tools/peview/pdb.c index 7fac14523a91..61e222ad8daa 100644 --- a/tools/peview/pdb.c +++ b/tools/peview/pdb.c @@ -52,6 +52,13 @@ typedef BOOL (WINAPI *_SymEnumSymbolsW)( _In_opt_ const PVOID UserContext ); +typedef BOOL (WINAPI *_SymEnumTypesW)( + _In_ HANDLE hProcess, + _In_ ULONG64 BaseOfDll, + _In_ PSYM_ENUMERATESYMBOLS_CALLBACKW EnumSymbolsCallback, + _In_opt_ PVOID UserContext + ); + typedef BOOL (WINAPI *_SymSetSearchPathW)( _In_ HANDLE hProcess, _In_opt_ PCWSTR SearchPath @@ -80,6 +87,13 @@ typedef BOOL (WINAPI *_SymGetModuleInfoW64)( _Out_ PIMAGEHLP_MODULEW64 ModuleInfo ); +typedef BOOL (WINAPI *_SymGetTypeFromNameW)( + _In_ HANDLE hProcess, + _In_ ULONG64 BaseOfDll, + _In_ PCTSTR Name, + _Inout_ PSYMBOL_INFO Symbol + ); + typedef BOOL (WINAPI *_SymSetContext)( _In_ HANDLE hProcess, _In_ PIMAGEHLP_STACK_FRAME StackFrame, @@ -89,11 +103,13 @@ typedef BOOL (WINAPI *_SymSetContext)( _SymInitialize SymInitialize_I = NULL; _SymCleanup SymCleanup_I = NULL; _SymEnumSymbolsW SymEnumSymbolsW_I = NULL; +_SymEnumTypesW SymEnumTypesW_I = NULL; _SymSetSearchPathW SymSetSearchPathW_I = NULL; _SymGetOptions SymGetOptions_I = NULL; _SymSetOptions SymSetOptions_I = NULL; _SymLoadModuleExW SymLoadModuleExW_I = NULL; _SymGetModuleInfoW64 SymGetModuleInfoW64_I = NULL; +_SymGetTypeFromNameW SymGetTypeFromNameW_I = NULL; _SymGetTypeInfo SymGetTypeInfo_I = NULL; _SymSetContext SymSetContext_I = NULL; @@ -101,8 +117,8 @@ ULONG SearchResultsAddIndex = 0; PPH_LIST SearchResults = NULL; PH_QUEUED_LOCK SearchResultsLock = PH_QUEUED_LOCK_INIT; -BOOLEAN SymbolInfo_DumpBasicType( - _Inout_ PPDB_SYMBOL_CONTEXT Context, +BOOLEAN PdbGetSymbolBasicType( + _In_ ULONG64 BaseAddress, _In_ ULONG Index, _Inout_ BaseTypeInfo *Info ) @@ -110,54 +126,57 @@ BOOLEAN SymbolInfo_DumpBasicType( ULONG baseType = btNoType; ULONG64 length = 0; - if (!SymbolInfo_CheckTag(Context, Index, SymTagBaseType)) + if (!PdbCheckTagType(BaseAddress, Index, SymTagBaseType)) return FALSE; // Basic type ("basicType" in DIA) - if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, Index, TI_GET_BASETYPE, &baseType)) + if (!SymGetTypeInfo_I(NtCurrentProcess(), BaseAddress, Index, TI_GET_BASETYPE, &baseType)) return FALSE; // Length ("length" in DIA) - if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, Index, TI_GET_LENGTH, &length)) + if (!SymGetTypeInfo_I(NtCurrentProcess(), BaseAddress, Index, TI_GET_LENGTH, &length)) return FALSE; Info->BaseType = (BasicType)baseType; Info->Length = length; + return TRUE; } -BOOLEAN SymbolInfo_DumpPointerType( - _Inout_ PPDB_SYMBOL_CONTEXT Context, +BOOLEAN PdbGetSymbolPointerType( + _In_ ULONG64 BaseAddress, _In_ ULONG Index, _Inout_ PointerTypeInfo* Info ) { - ULONG TypeIndex = 0; - ULONG64 Length = 0; - - if (!SymbolInfo_CheckTag(Context, Index, SymTagPointerType)) + ULONG typeIndex = 0; + ULONG64 length = 0; + BOOL reference = FALSE; + + if (!PdbCheckTagType(BaseAddress, Index, SymTagPointerType)) return FALSE; // Type index ("typeId" in DIA) - if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, Index, TI_GET_TYPEID, &TypeIndex)) + if (!SymGetTypeInfo_I(NtCurrentProcess(), BaseAddress, Index, TI_GET_TYPEID, &typeIndex)) return FALSE; // Length ("length" in DIA) - if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, Index, TI_GET_LENGTH, &Length)) + if (!SymGetTypeInfo_I(NtCurrentProcess(), BaseAddress, Index, TI_GET_LENGTH, &length)) return FALSE; // Reference ("reference" in DIA) - // This property is not available via SymGetTypeInfo_I?? - // TODO: Figure out how DIA determines if the pointer is a pointer or a reference. + if (!SymGetTypeInfo_I(NtCurrentProcess(), BaseAddress, Index, TI_GET_IS_REFERENCE, &reference)) + return FALSE; - Info->TypeIndex = TypeIndex; - Info->Length = Length; + Info->TypeIndex = typeIndex; + Info->Length = length; + Info->TypeReference = reference; return TRUE; } -BOOLEAN SymbolInfo_DumpTypedef( - _Inout_ PPDB_SYMBOL_CONTEXT Context, +BOOLEAN PdbGetSymbolTypedefType( + _In_ ULONG64 BaseAddress, _In_ ULONG Index, _Inout_ TypedefInfo* Info ) @@ -165,15 +184,15 @@ BOOLEAN SymbolInfo_DumpTypedef( ULONG typeIndex = 0; PWSTR symbolName = NULL; - if (!SymbolInfo_CheckTag(Context, Index, SymTagTypedef)) + if (!PdbCheckTagType(BaseAddress, Index, SymTagTypedef)) return FALSE; // Type index ("typeId" in DIA) - if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, Index, TI_GET_TYPEID, &typeIndex)) + if (!SymGetTypeInfo_I(NtCurrentProcess(), BaseAddress, Index, TI_GET_TYPEID, &typeIndex)) return FALSE; // Name ("name" in DIA) - if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, Index, TI_GET_SYMNAME, &symbolName) || !symbolName) + if (!SymGetTypeInfo_I(NtCurrentProcess(), BaseAddress, Index, TI_GET_SYMNAME, &symbolName) || !symbolName) return FALSE; Info->TypeIndex = typeIndex; @@ -185,8 +204,8 @@ BOOLEAN SymbolInfo_DumpTypedef( return TRUE; } -BOOLEAN SymbolInfo_DumpEnum( - _Inout_ PPDB_SYMBOL_CONTEXT Context, +BOOLEAN PdbGetSymbolEnumType( + _In_ ULONG64 BaseAddress, _In_ ULONG Index, _Inout_ EnumInfo* Info ) @@ -195,11 +214,11 @@ BOOLEAN SymbolInfo_DumpEnum( ULONG Nested = 0; PWSTR symbolName = NULL; - if (!SymbolInfo_CheckTag(Context, Index, SymTagEnum)) + if (!PdbCheckTagType(BaseAddress, Index, SymTagEnum)) return FALSE; // Name ("name" in DIA) - if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, Index, TI_GET_SYMNAME, &symbolName) || !symbolName) + if (!SymGetTypeInfo_I(NtCurrentProcess(), BaseAddress, Index, TI_GET_SYMNAME, &symbolName) || !symbolName) return FALSE; wcsncpy(Info->Name, symbolName, ARRAYSIZE(Info->Name)); @@ -207,15 +226,15 @@ BOOLEAN SymbolInfo_DumpEnum( LocalFree(symbolName); // Type index ("typeId" in DIA) - if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, Index, TI_GET_TYPEID, &TypeIndex)) + if (!SymGetTypeInfo_I(NtCurrentProcess(), BaseAddress, Index, TI_GET_TYPEID, &TypeIndex)) return FALSE; // Nested ("nested" in DIA) - if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, Index, TI_GET_NESTED, &Nested)) + if (!SymGetTypeInfo_I(NtCurrentProcess(), BaseAddress, Index, TI_GET_NESTED, &Nested)) return FALSE; // Enumerators - if (!SymbolInfo_Enumerators(Context, Index, Info->Enums, &Info->NumEnums, ARRAYSIZE(Info->Enums))) + if (!PdbGetSymbolEnumerations(BaseAddress, Index, Info->Enums, &Info->NumEnums, ARRAYSIZE(Info->Enums))) return FALSE; Info->TypeIndex = TypeIndex; @@ -224,8 +243,8 @@ BOOLEAN SymbolInfo_DumpEnum( return TRUE; } -BOOLEAN SymbolInfo_DumpArrayType( - _Inout_ PPDB_SYMBOL_CONTEXT Context, +BOOLEAN PdbGetSymbolArrayType( + _In_ ULONG64 BaseAddress, _In_ ULONG Index, _Inout_ ArrayTypeInfo* Info ) @@ -235,19 +254,19 @@ BOOLEAN SymbolInfo_DumpArrayType( ULONG indexTypeIndex = 0; // Check if it is really SymTagArrayType - if (!SymbolInfo_CheckTag(Context, Index, SymTagArrayType)) + if (!PdbCheckTagType(BaseAddress, Index, SymTagArrayType)) return FALSE; // Element type index - if (!SymbolInfo_ArrayElementTypeIndex(Context, Index, &elementTypeIndex)) + if (!PdbGetSymbolArrayElementTypeIndex(BaseAddress, Index, &elementTypeIndex)) return FALSE; // Length ("length" in DIA) - if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, Index, TI_GET_LENGTH, &length)) + if (!SymGetTypeInfo_I(NtCurrentProcess(), BaseAddress, Index, TI_GET_LENGTH, &length)) return FALSE; // Type index of the array index element - if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, Index, TI_GET_ARRAYINDEXTYPEID, &indexTypeIndex)) + if (!SymGetTypeInfo_I(NtCurrentProcess(), BaseAddress, Index, TI_GET_ARRAYINDEXTYPEID, &indexTypeIndex)) return FALSE; Info->ElementTypeIndex = elementTypeIndex; @@ -256,9 +275,8 @@ BOOLEAN SymbolInfo_DumpArrayType( if (length > 0) { - // Dimensions - if (!SymbolInfo_ArrayDims( - Context, + if (!PdbGetSymbolArrayDimensions( + BaseAddress, Index, Info->Dimensions, &Info->NumDimensions, @@ -277,7 +295,7 @@ BOOLEAN SymbolInfo_DumpArrayType( } BOOLEAN SymbolInfo_DumpUDT( - _Inout_ PPDB_SYMBOL_CONTEXT Context, + _In_ ULONG64 BaseAddress, _In_ ULONG Index, _Inout_ TypeInfo* Info ) @@ -285,33 +303,33 @@ BOOLEAN SymbolInfo_DumpUDT( ULONG UDTKind = 0; BOOLEAN result = FALSE; - if (!SymbolInfo_CheckTag(Context, Index, SymTagUDT)) + if (!PdbCheckTagType(BaseAddress, Index, SymTagUDT)) return FALSE; - if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, Index, TI_GET_UDTKIND, &UDTKind)) + if (!SymGetTypeInfo_I(NtCurrentProcess(), BaseAddress, Index, TI_GET_UDTKIND, &UDTKind)) return FALSE; switch (UDTKind) { case UdtStruct: Info->UdtKind = TRUE; - result = SymbolInfo_DumpUDTClass(Context, Index, &Info->sUdtClassInfo); + result = PdbGetSymbolUDTClass(BaseAddress, Index, &Info->UdtClassInfo); break; case UdtClass: Info->UdtKind = TRUE; - result = SymbolInfo_DumpUDTClass(Context, Index, &Info->sUdtClassInfo); + result = PdbGetSymbolUDTClass(BaseAddress, Index, &Info->UdtClassInfo); break; case UdtUnion: Info->UdtKind = FALSE; - result = SymbolInfo_DumpUDTUnion(Context, Index, &Info->sUdtUnionInfo); + result = PdbGetSymbolUDTUnion(BaseAddress, Index, &Info->UdtUnionInfo); break; } return result; } -BOOLEAN SymbolInfo_DumpUDTClass( - _Inout_ PPDB_SYMBOL_CONTEXT Context, +BOOLEAN PdbGetSymbolUDTClass( + _In_ ULONG64 BaseAddress, _In_ ULONG Index, _Inout_ UdtClassInfo* Info ) @@ -321,18 +339,18 @@ BOOLEAN SymbolInfo_DumpUDTClass( ULONG64 Length = 0; ULONG Nested = 0; - if (!SymbolInfo_CheckTag(Context, Index, SymTagUDT)) + if (!PdbCheckTagType(BaseAddress, Index, SymTagUDT)) return FALSE; // Check if it is really a class or structure UDT ? - if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, Index, TI_GET_UDTKIND, &UDTKind)) + if (!SymGetTypeInfo_I(NtCurrentProcess(), BaseAddress, Index, TI_GET_UDTKIND, &UDTKind)) return FALSE; if ((UDTKind != UdtStruct) && (UDTKind != UdtClass)) return FALSE; // Name ("name" in DIA) - if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, Index, TI_GET_SYMNAME, &symbolName) || !symbolName) + if (!SymGetTypeInfo_I(NtCurrentProcess(), BaseAddress, Index, TI_GET_SYMNAME, &symbolName) || !symbolName) return FALSE; wcsncpy(Info->Name, symbolName, ARRAYSIZE(Info->Name)); @@ -340,23 +358,23 @@ BOOLEAN SymbolInfo_DumpUDTClass( LocalFree(symbolName); // Length ("length" in DIA) - if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, Index, TI_GET_LENGTH, &Length)) + if (!SymGetTypeInfo_I(NtCurrentProcess(), BaseAddress, Index, TI_GET_LENGTH, &Length)) return FALSE; // Nested ("nested" in DIA) - if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, Index, TI_GET_NESTED, &Nested)) + if (!SymGetTypeInfo_I(NtCurrentProcess(), BaseAddress, Index, TI_GET_NESTED, &Nested)) return FALSE; // Member variables - if (!SymbolInfo_UdtVariables(Context, Index, Info->Variables, &Info->NumVariables, ARRAYSIZE(Info->Variables))) + if (!PdbGetSymbolUdtVariables(BaseAddress, Index, Info->Variables, &Info->NumVariables, ARRAYSIZE(Info->Variables))) return FALSE; // Member functions - if (!SymbolInfo_UdtFunctions(Context, Index, Info->Functions, &Info->NumFunctions, ARRAYSIZE(Info->Functions))) + if (!PdbGetSymbolUdtFunctions(BaseAddress, Index, Info->Functions, &Info->NumFunctions, ARRAYSIZE(Info->Functions))) return FALSE; // Base classes - if (!SymbolInfo_UdtBaseClasses(Context, Index, Info->BaseClasses, &Info->NumBaseClasses, ARRAYSIZE(Info->BaseClasses))) + if (!PdbGetSymbolUdtBaseClasses(BaseAddress, Index, Info->BaseClasses, &Info->NumBaseClasses, ARRAYSIZE(Info->BaseClasses))) return FALSE; Info->UDTKind = (UdtKind)UDTKind; @@ -366,8 +384,8 @@ BOOLEAN SymbolInfo_DumpUDTClass( return TRUE; } -BOOLEAN SymbolInfo_DumpUDTUnion( - _Inout_ PPDB_SYMBOL_CONTEXT Context, +BOOLEAN PdbGetSymbolUDTUnion( + _In_ ULONG64 BaseAddress, _In_ ULONG Index, _Inout_ UdtUnionInfo *Info ) @@ -377,18 +395,18 @@ BOOLEAN SymbolInfo_DumpUDTUnion( ULONG64 Length = 0; ULONG Nested = 0; - if (!SymbolInfo_CheckTag(Context, Index, SymTagUDT)) + if (!PdbCheckTagType(BaseAddress, Index, SymTagUDT)) return FALSE; // Check if it is really a union UDT ? - if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, Index, TI_GET_UDTKIND, &UDTKind)) + if (!SymGetTypeInfo_I(NtCurrentProcess(), BaseAddress, Index, TI_GET_UDTKIND, &UDTKind)) return FALSE; if (UDTKind != UdtUnion) return FALSE; // Name ("name" in DIA) - if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, Index, TI_GET_SYMNAME, &symbolName) || !symbolName) + if (!SymGetTypeInfo_I(NtCurrentProcess(), BaseAddress, Index, TI_GET_SYMNAME, &symbolName) || !symbolName) return FALSE; wcsncpy(Info->Name, symbolName, ARRAYSIZE(Info->Name)); @@ -396,15 +414,15 @@ BOOLEAN SymbolInfo_DumpUDTUnion( LocalFree(symbolName); // Length ("length" in DIA) - if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, Index, TI_GET_LENGTH, &Length)) + if (!SymGetTypeInfo_I(NtCurrentProcess(), BaseAddress, Index, TI_GET_LENGTH, &Length)) return FALSE; // Nested ("nested" in DIA) - if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, Index, TI_GET_NESTED, &Nested)) + if (!SymGetTypeInfo_I(NtCurrentProcess(), BaseAddress, Index, TI_GET_NESTED, &Nested)) return FALSE; // Union members - if (!SymbolInfo_UdtUnionMembers(Context, Index, Info->Members, &Info->NumMembers, ARRAYSIZE(Info->Members))) + if (!PdbGetSymbolUdtUnionMembers(BaseAddress, Index, Info->Members, &Info->NumMembers, ARRAYSIZE(Info->Members))) return FALSE; Info->UDTKind = (UdtKind)UDTKind; @@ -414,8 +432,8 @@ BOOLEAN SymbolInfo_DumpUDTUnion( return TRUE; } -BOOLEAN SymbolInfo_DumpFunctionType( - _Inout_ PPDB_SYMBOL_CONTEXT Context, +BOOLEAN PdbGetSymbolFunctionType( + _In_ ULONG64 BaseAddress, _In_ ULONG Index, _Inout_ FunctionTypeInfo *Info ) @@ -425,16 +443,16 @@ BOOLEAN SymbolInfo_DumpFunctionType( ULONG CallConv = 0; ULONG ClassIndex = 0; - if (!SymbolInfo_CheckTag(Context, Index, SymTagFunctionType)) + if (!PdbCheckTagType(BaseAddress, Index, SymTagFunctionType)) return FALSE; // Index of the return type symbol ("typeId" in DIA) - if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, Index, TI_GET_TYPEID, &RetTypeIndex)) + if (!SymGetTypeInfo_I(NtCurrentProcess(), BaseAddress, Index, TI_GET_TYPEID, &RetTypeIndex)) return FALSE; // Number of arguments ("count" in DIA) // Note: For non-static member functions, it includes "this" - if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, Index, TI_GET_COUNT, &NumArgs)) + if (!SymGetTypeInfo_I(NtCurrentProcess(), BaseAddress, Index, TI_GET_COUNT, &NumArgs)) return FALSE; // Do not save it in the data structure, since we obtain the number of arguments @@ -443,11 +461,11 @@ BOOLEAN SymbolInfo_DumpFunctionType( // is static or not (if it is a member function) // Calling convention ("callingConvention" in DIA) - if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, Index, TI_GET_CALLING_CONVENTION, &CallConv)) + if (!SymGetTypeInfo_I(NtCurrentProcess(), BaseAddress, Index, TI_GET_CALLING_CONVENTION, &CallConv)) return FALSE; // Parent class type index ("classParent" in DIA) - if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, Index, TI_GET_CLASSPARENTID, &ClassIndex)) + if (!SymGetTypeInfo_I(NtCurrentProcess(), BaseAddress, Index, TI_GET_CLASSPARENTID, &ClassIndex)) { // The function is not a member function Info->ClassIndex = 0; @@ -466,7 +484,7 @@ BOOLEAN SymbolInfo_DumpFunctionType( LONG ThisAdjust = 0; // "this" adjustment ("thisAdjust" in DIA) - if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, Index, TI_GET_THISADJUST, &ThisAdjust)) + if (!SymGetTypeInfo_I(NtCurrentProcess(), BaseAddress, Index, TI_GET_THISADJUST, &ThisAdjust)) return FALSE; Info->ThisAdjust = ThisAdjust; @@ -482,7 +500,7 @@ BOOLEAN SymbolInfo_DumpFunctionType( */ // Dump function arguments - if (!SymbolInfo_FunctionArguments(Context, Index, Info->Args, &Info->NumArgs, ARRAYSIZE(Info->Args))) + if (!PdbGetSymbolFunctionArguments(BaseAddress, Index, Info->Args, &Info->NumArgs, ARRAYSIZE(Info->Args))) return FALSE; // Is the function static ? (If it is a member function) @@ -499,19 +517,19 @@ BOOLEAN SymbolInfo_DumpFunctionType( return TRUE; } -BOOLEAN SymbolInfo_DumpFunctionArgType( - _Inout_ PPDB_SYMBOL_CONTEXT Context, +BOOLEAN PdbGetSymbolFunctionArgType( + _In_ ULONG64 BaseAddress, _In_ ULONG Index, _Inout_ FunctionArgTypeInfo *Info ) { ULONG typeIndex = 0; - if (!SymbolInfo_CheckTag(Context, Index, SymTagFunctionArgType)) + if (!PdbCheckTagType(BaseAddress, Index, SymTagFunctionArgType)) return FALSE; // Index of the argument type ("typeId" in DIA) - if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, Index, TI_GET_TYPEID, &typeIndex)) + if (!SymGetTypeInfo_I(NtCurrentProcess(), BaseAddress, Index, TI_GET_TYPEID, &typeIndex)) return FALSE; Info->TypeIndex = typeIndex; @@ -519,8 +537,8 @@ BOOLEAN SymbolInfo_DumpFunctionArgType( return TRUE; } -BOOLEAN SymbolInfo_DumpBaseClass( - _Inout_ PPDB_SYMBOL_CONTEXT Context, +BOOLEAN PdbGetSymbolBaseClass( + _In_ ULONG64 BaseAddress, _In_ ULONG Index, _Inout_ BaseClassInfo *Info ) @@ -528,13 +546,13 @@ BOOLEAN SymbolInfo_DumpBaseClass( ULONG typeIndex = 0; ULONG virtualBase = 0; - if (!SymbolInfo_CheckTag(Context, Index, SymTagBaseClass)) + if (!PdbCheckTagType(BaseAddress, Index, SymTagBaseClass)) return FALSE; // Base class UDT if (!SymGetTypeInfo_I( NtCurrentProcess(), - Context->BaseAddress, + BaseAddress, Index, TI_GET_TYPEID, &typeIndex @@ -546,7 +564,7 @@ BOOLEAN SymbolInfo_DumpBaseClass( // Is this base class virtual ? if (!SymGetTypeInfo_I( NtCurrentProcess(), - Context->BaseAddress, + BaseAddress, Index, TI_GET_VIRTUALBASECLASS, &virtualBase @@ -565,7 +583,7 @@ BOOLEAN SymbolInfo_DumpBaseClass( // Virtual base pointer offset if (!SymGetTypeInfo_I( NtCurrentProcess(), - Context->BaseAddress, + BaseAddress, Index, TI_GET_VIRTUALBASEPOINTEROFFSET, &virtualBasePtrOffset @@ -584,7 +602,7 @@ BOOLEAN SymbolInfo_DumpBaseClass( // Offset in the parent UDT if (!SymGetTypeInfo_I( NtCurrentProcess(), - Context->BaseAddress, + BaseAddress, Index, TI_GET_OFFSET, &offset @@ -600,8 +618,8 @@ BOOLEAN SymbolInfo_DumpBaseClass( return TRUE; } -BOOLEAN SymbolInfo_DumpData( - _Inout_ PPDB_SYMBOL_CONTEXT Context, +BOOLEAN PdbGetSymbolData( + _In_ ULONG64 BaseAddress, _In_ ULONG Index, _Inout_ DataInfo *Info ) @@ -610,11 +628,11 @@ BOOLEAN SymbolInfo_DumpData( ULONG TypeIndex = 0; ULONG dataKind = 0; - if (!SymbolInfo_CheckTag(Context, Index, SymTagData)) + if (!PdbCheckTagType(BaseAddress, Index, SymTagData)) return FALSE; // Name ("name" in DIA) - if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, Index, TI_GET_SYMNAME, &symbolName) || !symbolName) + if (!SymGetTypeInfo_I(NtCurrentProcess(), BaseAddress, Index, TI_GET_SYMNAME, &symbolName) || !symbolName) return FALSE; wcsncpy(Info->Name, symbolName, ARRAYSIZE(Info->Name)); @@ -622,11 +640,11 @@ BOOLEAN SymbolInfo_DumpData( LocalFree(symbolName); // Index of type symbol ("typeId" in DIA) - if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, Index, TI_GET_TYPEID, &TypeIndex)) + if (!SymGetTypeInfo_I(NtCurrentProcess(), BaseAddress, Index, TI_GET_TYPEID, &TypeIndex)) return FALSE; // Data kind ("dataKind" in DIA) - if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, Index, TI_GET_DATAKIND, &dataKind)) + if (!SymGetTypeInfo_I(NtCurrentProcess(), BaseAddress, Index, TI_GET_DATAKIND, &dataKind)) return FALSE; Info->TypeIndex = TypeIndex; @@ -645,7 +663,7 @@ BOOLEAN SymbolInfo_DumpData( // Note: If it is DataIsStaticMember, then this is a static member of a class defined in another module // (it does not have an address in this module) - if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, Index, TI_GET_ADDRESS, &address)) + if (!SymGetTypeInfo_I(NtCurrentProcess(), BaseAddress, Index, TI_GET_ADDRESS, &address)) return FALSE; Info->Address = address; @@ -661,7 +679,7 @@ BOOLEAN SymbolInfo_DumpData( ULONG offset = 0; // Use Offset; Address is not defined - if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, Index, TI_GET_OFFSET, &offset)) + if (!SymGetTypeInfo_I(NtCurrentProcess(), BaseAddress, Index, TI_GET_OFFSET, &offset)) return FALSE; Info->Offset = offset; @@ -679,7 +697,7 @@ BOOLEAN SymbolInfo_DumpData( } BOOLEAN SymbolInfo_DumpType( - _Inout_ PPDB_SYMBOL_CONTEXT Context, + _In_ ULONG64 BaseAddress, _In_ ULONG Index, _Inout_ TypeInfo *Info ) @@ -688,7 +706,7 @@ BOOLEAN SymbolInfo_DumpType( if (!SymGetTypeInfo_I( NtCurrentProcess(), - Context->BaseAddress, + BaseAddress, Index, TI_GET_SYMTAG, &tag @@ -702,25 +720,25 @@ BOOLEAN SymbolInfo_DumpType( switch (tag) { case SymTagBaseType: - return SymbolInfo_DumpBasicType(Context, Index, &Info->sBaseTypeInfo); + return PdbGetSymbolBasicType(BaseAddress, Index, &Info->BaseTypeInfo); case SymTagPointerType: - return SymbolInfo_DumpPointerType(Context, Index, &Info->sPointerTypeInfo); + return PdbGetSymbolPointerType(BaseAddress, Index, &Info->PointerTypeInfo); case SymTagTypedef: - return SymbolInfo_DumpTypedef(Context, Index, &Info->sTypedefInfo); + return PdbGetSymbolTypedefType(BaseAddress, Index, &Info->TypedefInfo); case SymTagEnum: - return SymbolInfo_DumpEnum(Context, Index, &Info->sEnumInfo); + return PdbGetSymbolEnumType(BaseAddress, Index, &Info->EnumInfo); case SymTagArrayType: - return SymbolInfo_DumpArrayType(Context, Index, &Info->sArrayTypeInfo); + return PdbGetSymbolArrayType(BaseAddress, Index, &Info->ArrayTypeInfo); case SymTagUDT: - return SymbolInfo_DumpUDT(Context, Index, Info); + return SymbolInfo_DumpUDT(BaseAddress, Index, Info); case SymTagFunctionType: - return SymbolInfo_DumpFunctionType(Context, Index, &Info->sFunctionTypeInfo); + return PdbGetSymbolFunctionType(BaseAddress, Index, &Info->FunctionTypeInfo); case SymTagFunctionArgType: - return SymbolInfo_DumpFunctionArgType(Context, Index, &Info->sFunctionArgTypeInfo); + return PdbGetSymbolFunctionArgType(BaseAddress, Index, &Info->FunctionArgTypeInfo); case SymTagBaseClass: - return SymbolInfo_DumpBaseClass(Context, Index, &Info->sBaseClassInfo); + return PdbGetSymbolBaseClass(BaseAddress, Index, &Info->BaseClassInfo); case SymTagData: - return SymbolInfo_DumpData(Context, Index, &Info->sDataInfo); + return PdbGetSymbolData(BaseAddress, Index, &Info->DataInfo); } return FALSE; @@ -738,25 +756,25 @@ BOOLEAN SymbolInfo_DumpSymbolType( return FALSE; // Dump the type symbol - return SymbolInfo_DumpType(Context, *TypeIndex, Info); + return SymbolInfo_DumpType(Context->BaseAddress, *TypeIndex, Info); } -BOOLEAN SymbolInfo_CheckTag( - _Inout_ PPDB_SYMBOL_CONTEXT Context, +BOOLEAN PdbCheckTagType( + _In_ ULONG64 BaseAddress, _In_ ULONG Index, _In_ ULONG Tag ) { ULONG symTag = SymTagNull; - if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, Index, TI_GET_SYMTAG, &symTag)) + if (!SymGetTypeInfo_I(NtCurrentProcess(), BaseAddress, Index, TI_GET_SYMTAG, &symTag)) return FALSE; return symTag == Tag; } -BOOLEAN SymbolInfo_SymbolSize( - _Inout_ PPDB_SYMBOL_CONTEXT Context, +BOOLEAN PdbGetSymbolSize( + _In_ ULONG64 BaseAddress, _In_ ULONG Index, _Inout_ ULONG64* Size ) @@ -765,7 +783,7 @@ BOOLEAN SymbolInfo_SymbolSize( ULONG64 length = 0; // Does the symbol support "length" property ? - if (SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, Index, TI_GET_LENGTH, &length)) + if (SymGetTypeInfo_I(NtCurrentProcess(), BaseAddress, Index, TI_GET_LENGTH, &length)) { *Size = length; return TRUE; @@ -773,7 +791,7 @@ BOOLEAN SymbolInfo_SymbolSize( else { // No, it does not - it can be SymTagTypedef - if (!SymbolInfo_CheckTag(Context, Index, SymTagTypedef)) + if (!PdbCheckTagType(BaseAddress, Index, SymTagTypedef)) { // No, this symbol does not have length return FALSE; @@ -787,15 +805,15 @@ BOOLEAN SymbolInfo_SymbolSize( { ULONG tempIndex = 0; - if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, index, TI_GET_TYPEID, &tempIndex)) + if (!SymGetTypeInfo_I(NtCurrentProcess(), BaseAddress, index, TI_GET_TYPEID, &tempIndex)) return FALSE; index = tempIndex; - } while (SymbolInfo_CheckTag(Context, index, SymTagTypedef)); + } while (PdbCheckTagType(BaseAddress, index, SymTagTypedef)); // And get the length - if (SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, index, TI_GET_LENGTH, &length)) + if (SymGetTypeInfo_I(NtCurrentProcess(), BaseAddress, index, TI_GET_LENGTH, &length)) { *Size = length; return TRUE; @@ -806,8 +824,8 @@ BOOLEAN SymbolInfo_SymbolSize( return FALSE; } -BOOLEAN SymbolInfo_ArrayElementTypeIndex( - _Inout_ PPDB_SYMBOL_CONTEXT Context, +BOOLEAN PdbGetSymbolArrayElementTypeIndex( + _In_ ULONG64 BaseAddress, _In_ ULONG ArrayIndex, _Inout_ ULONG* ElementTypeIndex ) @@ -815,19 +833,19 @@ BOOLEAN SymbolInfo_ArrayElementTypeIndex( ULONG index; ULONG elementIndex = 0; - if (!SymbolInfo_CheckTag(Context, ArrayIndex, SymTagArrayType)) + if (!PdbCheckTagType(BaseAddress, ArrayIndex, SymTagArrayType)) return FALSE; // Get the array element type - if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, ArrayIndex, TI_GET_TYPEID, &elementIndex)) + if (!SymGetTypeInfo_I(NtCurrentProcess(), BaseAddress, ArrayIndex, TI_GET_TYPEID, &elementIndex)) return FALSE; // If the array element type is SymTagArrayType, skip to its type index = elementIndex; - while (SymbolInfo_CheckTag(Context, elementIndex, SymTagArrayType)) + while (PdbCheckTagType(BaseAddress, elementIndex, SymTagArrayType)) { - if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, index, TI_GET_TYPEID, &elementIndex)) + if (!SymGetTypeInfo_I(NtCurrentProcess(), BaseAddress, index, TI_GET_TYPEID, &elementIndex)) return FALSE; index = elementIndex; @@ -839,8 +857,8 @@ BOOLEAN SymbolInfo_ArrayElementTypeIndex( return TRUE; } -BOOLEAN SymbolInfo_ArrayDims( - _Inout_ PPDB_SYMBOL_CONTEXT Context, +BOOLEAN PdbGetSymbolArrayDimensions( + _In_ ULONG64 BaseAddress, _In_ ULONG Index, _Inout_ ULONG64* pDims, _Inout_ ULONG* Dims, @@ -850,7 +868,7 @@ BOOLEAN SymbolInfo_ArrayDims( ULONG index; ULONG dimCount; - if (!SymbolInfo_CheckTag(Context, Index, SymTagArrayType)) + if (!PdbCheckTagType(BaseAddress, Index, SymTagArrayType)) return FALSE; if (MaxDims <= 0) @@ -866,7 +884,7 @@ BOOLEAN SymbolInfo_ArrayDims( ULONG64 typeSize = 0; // Length ("length" in DIA) - if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, index, TI_GET_LENGTH, &length) || (length == 0)) + if (!SymGetTypeInfo_I(NtCurrentProcess(), BaseAddress, index, TI_GET_LENGTH, &length) || (length == 0)) return FALSE; // Size of the current dimension @@ -874,38 +892,33 @@ BOOLEAN SymbolInfo_ArrayDims( // type symbol, which can be another SymTagArrayType symbol or the array element symbol) // Its type - if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, index, TI_GET_TYPEID, &typeIndex)) + if (!SymGetTypeInfo_I(NtCurrentProcess(), BaseAddress, index, TI_GET_TYPEID, &typeIndex)) { // No type - we are done break; } // Size of its type - if (!SymbolInfo_SymbolSize(Context, typeIndex, &typeSize) || (typeSize == 0)) + if (!PdbGetSymbolSize(BaseAddress, typeIndex, &typeSize) || (typeSize == 0)) return FALSE; // Size of the dimension pDims[i] = length / typeSize; dimCount++; - // Test only -/* + /* ULONG ElemCount = 0; - if( !SymGetTypeInfo_I( m_hProcess, BaseAddress, CurIndex, TI_GET_COUNT, &ElemCount ) ) + if( !SymGetTypeInfo_I(NtCurrentProcess(), BaseAddress, CurIndex, TI_GET_COUNT, &ElemCount)) { // and continue ... } else if( ElemCount != pDims[i] ) { _ASSERTE( !_T("TI_GET_COUNT does not match.") ); - } - else - { - //_ASSERTE( !_T("TI_GET_COUNT works!") ); - } -*/ + }*/ + // If the type symbol is not SymTagArrayType, we are done - if (!SymbolInfo_CheckTag(Context, typeIndex, SymTagArrayType)) + if (!PdbCheckTagType(BaseAddress, typeIndex, SymTagArrayType)) break; index = typeIndex; @@ -920,7 +933,7 @@ BOOLEAN SymbolInfo_ArrayDims( } BOOLEAN PdbGetSymbolChildren( - _Inout_ PPDB_SYMBOL_CONTEXT Context, + _In_ ULONG64 BaseAddress, _In_ ULONG Index, _Inout_ ULONG* Count, _Inout_ TI_FINDCHILDREN_PARAMS **Params @@ -932,7 +945,7 @@ BOOLEAN PdbGetSymbolChildren( if (!SymGetTypeInfo_I( NtCurrentProcess(), - Context->BaseAddress, + BaseAddress, Index, TI_GET_CHILDRENCOUNT, &symbolCount @@ -950,7 +963,7 @@ BOOLEAN PdbGetSymbolChildren( symbols->Count = symbolCount; - if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, Index, TI_FINDCHILDREN, symbols)) + if (!SymGetTypeInfo_I(NtCurrentProcess(), BaseAddress, Index, TI_FINDCHILDREN, symbols)) return FALSE; *Count = symbolCount; @@ -959,8 +972,8 @@ BOOLEAN PdbGetSymbolChildren( return TRUE; } -BOOLEAN SymbolInfo_UdtVariables( - _Inout_ PPDB_SYMBOL_CONTEXT Context, +BOOLEAN PdbGetSymbolUdtVariables( + _In_ ULONG64 BaseAddress, _In_ ULONG Index, _Inout_ ULONG* pVars, _Inout_ ULONG* Vars, @@ -970,20 +983,20 @@ BOOLEAN SymbolInfo_UdtVariables( ULONG childrenLength = 0; TI_FINDCHILDREN_PARAMS* symbolParams; - if (!SymbolInfo_CheckTag(Context, Index, SymTagUDT)) + if (!PdbCheckTagType(BaseAddress, Index, SymTagUDT)) return FALSE; if (MaxVars <= 0) return FALSE; - if (!PdbGetSymbolChildren(Context, Index, &childrenLength, &symbolParams)) + if (!PdbGetSymbolChildren(BaseAddress, Index, &childrenLength, &symbolParams)) return FALSE; *Vars = 0; for (ULONG i = 0; i < childrenLength; i++) { - if (SymbolInfo_CheckTag(Context, symbolParams->ChildId[i], SymTagData)) + if (PdbCheckTagType(BaseAddress, symbolParams->ChildId[i], SymTagData)) { pVars[*Vars] = symbolParams->ChildId[i]; @@ -997,8 +1010,8 @@ BOOLEAN SymbolInfo_UdtVariables( return TRUE; } -BOOLEAN SymbolInfo_UdtFunctions( - _Inout_ PPDB_SYMBOL_CONTEXT Context, +BOOLEAN PdbGetSymbolUdtFunctions( + _In_ ULONG64 BaseAddress, _In_ ULONG Index, _Inout_ ULONG* pFuncs, _Inout_ ULONG* Funcs, @@ -1008,20 +1021,20 @@ BOOLEAN SymbolInfo_UdtFunctions( ULONG childrenLength = 0; TI_FINDCHILDREN_PARAMS* symbolParams; - if (!SymbolInfo_CheckTag(Context, Index, SymTagUDT)) + if (!PdbCheckTagType(BaseAddress, Index, SymTagUDT)) return FALSE; if (MaxFuncs <= 0) return FALSE; - if (!PdbGetSymbolChildren(Context, Index, &childrenLength, &symbolParams)) + if (!PdbGetSymbolChildren(BaseAddress, Index, &childrenLength, &symbolParams)) return FALSE; *Funcs = 0; for (ULONG i = 0; i < childrenLength; i++) { - if (SymbolInfo_CheckTag(Context, symbolParams->ChildId[i], SymTagFunction)) + if (PdbCheckTagType(BaseAddress, symbolParams->ChildId[i], SymTagFunction)) { pFuncs[*Funcs] = symbolParams->ChildId[i]; @@ -1035,8 +1048,8 @@ BOOLEAN SymbolInfo_UdtFunctions( return TRUE; } -BOOLEAN SymbolInfo_UdtBaseClasses( - _Inout_ PPDB_SYMBOL_CONTEXT Context, +BOOLEAN PdbGetSymbolUdtBaseClasses( + _In_ ULONG64 BaseAddress, _In_ ULONG Index, _Inout_ ULONG* pBases, _Inout_ ULONG* Bases, @@ -1046,20 +1059,20 @@ BOOLEAN SymbolInfo_UdtBaseClasses( ULONG childrenLength = 0; TI_FINDCHILDREN_PARAMS* symbolParams; - if (!SymbolInfo_CheckTag(Context, Index, SymTagUDT)) + if (!PdbCheckTagType(BaseAddress, Index, SymTagUDT)) return FALSE; if (MaxBases <= 0) return FALSE; - if (!PdbGetSymbolChildren(Context, Index, &childrenLength, &symbolParams)) + if (!PdbGetSymbolChildren(BaseAddress, Index, &childrenLength, &symbolParams)) return FALSE; *Bases = 0; for (ULONG i = 0; i < childrenLength; i++) { - if (SymbolInfo_CheckTag(Context, symbolParams->ChildId[i], SymTagBaseClass)) + if (PdbCheckTagType(BaseAddress, symbolParams->ChildId[i], SymTagBaseClass)) { pBases[*Bases] = symbolParams->ChildId[i]; @@ -1073,8 +1086,8 @@ BOOLEAN SymbolInfo_UdtBaseClasses( return TRUE; } -BOOLEAN SymbolInfo_UdtUnionMembers( - _Inout_ PPDB_SYMBOL_CONTEXT Context, +BOOLEAN PdbGetSymbolUdtUnionMembers( + _In_ ULONG64 BaseAddress, _In_ ULONG Index, _Inout_ ULONG* pMembers, _Inout_ ULONG* Members, @@ -1084,20 +1097,20 @@ BOOLEAN SymbolInfo_UdtUnionMembers( ULONG childrenLength = 0; TI_FINDCHILDREN_PARAMS* symbolParams; - if (!SymbolInfo_CheckTag(Context, Index, SymTagUDT)) + if (!PdbCheckTagType(BaseAddress, Index, SymTagUDT)) return FALSE; if (MaxMembers <= 0) return FALSE; - if (!PdbGetSymbolChildren(Context, Index, &childrenLength, &symbolParams)) + if (!PdbGetSymbolChildren(BaseAddress, Index, &childrenLength, &symbolParams)) return FALSE; *Members = 0; for (ULONG i = 0; i < childrenLength; i++) { - if (SymbolInfo_CheckTag(Context, symbolParams->ChildId[i], SymTagData)) + if (PdbCheckTagType(BaseAddress, symbolParams->ChildId[i], SymTagData)) { pMembers[*Members] = symbolParams->ChildId[i]; @@ -1111,8 +1124,8 @@ BOOLEAN SymbolInfo_UdtUnionMembers( return TRUE; } -BOOLEAN SymbolInfo_FunctionArguments( - _Inout_ PPDB_SYMBOL_CONTEXT Context, +BOOLEAN PdbGetSymbolFunctionArguments( + _In_ ULONG64 BaseAddress, _In_ ULONG Index, _Inout_ ULONG* pArgs, _Inout_ ULONG* Args, @@ -1122,20 +1135,20 @@ BOOLEAN SymbolInfo_FunctionArguments( ULONG childrenLength = 0; TI_FINDCHILDREN_PARAMS* symbolParams; - if (!SymbolInfo_CheckTag(Context, Index, SymTagFunctionType)) + if (!PdbCheckTagType(BaseAddress, Index, SymTagFunctionType)) return FALSE; if (MaxArgs <= 0) return FALSE; - if (!PdbGetSymbolChildren(Context, Index, &childrenLength, &symbolParams)) + if (!PdbGetSymbolChildren(BaseAddress, Index, &childrenLength, &symbolParams)) return FALSE; *Args = 0; for (ULONG i = 0; i < childrenLength; i++) { - if (SymbolInfo_CheckTag(Context, symbolParams->ChildId[i], SymTagFunctionArgType)) + if (PdbCheckTagType(BaseAddress, symbolParams->ChildId[i], SymTagFunctionArgType)) { pArgs[*Args] = symbolParams->ChildId[i]; @@ -1149,8 +1162,8 @@ BOOLEAN SymbolInfo_FunctionArguments( return TRUE; } -BOOLEAN SymbolInfo_Enumerators( - _Inout_ PPDB_SYMBOL_CONTEXT Context, +BOOLEAN PdbGetSymbolEnumerations( + _In_ ULONG64 BaseAddress, _In_ ULONG Index, _Inout_ ULONG *pEnums, _Inout_ ULONG *Enums, @@ -1160,20 +1173,20 @@ BOOLEAN SymbolInfo_Enumerators( ULONG childrenLength = 0; TI_FINDCHILDREN_PARAMS* symbolParams; - if (!SymbolInfo_CheckTag(Context, Index, SymTagEnum)) + if (!PdbCheckTagType(BaseAddress, Index, SymTagEnum)) return FALSE; if (MaxEnums <= 0) return FALSE; - if (!PdbGetSymbolChildren(Context, Index, &childrenLength, &symbolParams)) + if (!PdbGetSymbolChildren(BaseAddress, Index, &childrenLength, &symbolParams)) return FALSE; *Enums = 0; for (ULONG i = 0; i < childrenLength; i++) { - if (SymbolInfo_CheckTag(Context, symbolParams->ChildId[i], SymTagData)) + if (PdbCheckTagType(BaseAddress, symbolParams->ChildId[i], SymTagData)) { pEnums[*Enums] = symbolParams->ChildId[i]; @@ -1187,23 +1200,23 @@ BOOLEAN SymbolInfo_Enumerators( return TRUE; } -BOOLEAN SymbolInfo_TypeDefType( - _Inout_ PPDB_SYMBOL_CONTEXT Context, +BOOLEAN PdbGetSymbolTypeDefTypeIndex( + _In_ ULONG64 BaseAddress, _In_ ULONG Index, _Inout_ ULONG *UndTypeIndex ) { ULONG index; - if (!SymbolInfo_CheckTag(Context, Index, SymTagTypedef)) + if (!PdbCheckTagType(BaseAddress, Index, SymTagTypedef)) return FALSE; // Skip to the type behind the type definition index = Index; - while (SymbolInfo_CheckTag(Context, index, SymTagTypedef)) + while (PdbCheckTagType(BaseAddress, index, SymTagTypedef)) { - if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, index, TI_GET_TYPEID, UndTypeIndex)) + if (!SymGetTypeInfo_I(NtCurrentProcess(), BaseAddress, index, TI_GET_TYPEID, UndTypeIndex)) return FALSE; index = *UndTypeIndex; @@ -1212,8 +1225,8 @@ BOOLEAN SymbolInfo_TypeDefType( return TRUE; } -BOOLEAN SymbolInfo_PointerType( - _Inout_ PPDB_SYMBOL_CONTEXT Context, +BOOLEAN PdbGetSymbolPointers( + _In_ ULONG64 BaseAddress, _In_ ULONG Index, _Inout_ ULONG *UndTypeIndex, _Inout_ ULONG *NumPointers @@ -1221,16 +1234,16 @@ BOOLEAN SymbolInfo_PointerType( { ULONG index; - if (!SymbolInfo_CheckTag(Context, Index, SymTagPointerType)) + if (!PdbCheckTagType(BaseAddress, Index, SymTagPointerType)) return FALSE; // Skip to the type pointer points to *NumPointers = 0; index = Index; - while (SymbolInfo_CheckTag(Context, index, SymTagPointerType)) + while (PdbCheckTagType(BaseAddress, index, SymTagPointerType)) { - if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, index, TI_GET_TYPEID, UndTypeIndex)) + if (!SymGetTypeInfo_I(NtCurrentProcess(), BaseAddress, index, TI_GET_TYPEID, UndTypeIndex)) return FALSE; (*NumPointers)++; @@ -1250,7 +1263,7 @@ BOOLEAN SymbolInfo_GetTypeNameHelper( { TypeInfo Info; - if (!SymbolInfo_DumpType(Obj, Index, &Info)) + if (!SymbolInfo_DumpType(Obj->BaseAddress, Index, &Info)) { return FALSE; } @@ -1263,11 +1276,11 @@ BOOLEAN SymbolInfo_GetTypeNameHelper( ULONG typeIndex = 0; // Yes, get the number of * to show - if (!SymbolInfo_PointerType(Obj, Index, &typeIndex, &numPointers)) + if (!PdbGetSymbolPointers(Obj->BaseAddress, Index, &typeIndex, &numPointers)) return FALSE; // Get more information about the type the pointer points to - if (!SymbolInfo_DumpType(Obj, typeIndex, &Info)) + if (!SymbolInfo_DumpType(Obj->BaseAddress, typeIndex, &Info)) return FALSE; // Save the index of the type the pointer points to @@ -1279,11 +1292,11 @@ BOOLEAN SymbolInfo_GetTypeNameHelper( switch (Info.Tag) { case SymTagBaseType: - PhAppendStringBuilder2(TypeName, SymbolInfo_BaseTypeStr(Info.sBaseTypeInfo.BaseType, Info.sBaseTypeInfo.Length)); + PhAppendStringBuilder2(TypeName, SymbolInfo_BaseTypeStr(Info.BaseTypeInfo.BaseType, Info.BaseTypeInfo.Length)); PhAppendStringBuilder2(TypeName, L" "); break; case SymTagTypedef: - PhAppendStringBuilder2(TypeName, Info.sTypedefInfo.Name); + PhAppendStringBuilder2(TypeName, Info.TypedefInfo.Name); PhAppendStringBuilder2(TypeName, L" "); break; case SymTagUDT: @@ -1291,7 +1304,7 @@ BOOLEAN SymbolInfo_GetTypeNameHelper( if (Info.UdtKind) { // A class/structure - PhAppendStringBuilder2(TypeName, Info.sUdtClassInfo.Name); + PhAppendStringBuilder2(TypeName, Info.UdtClassInfo.Name); PhAppendStringBuilder2(TypeName, L" "); // Add the UDT and its base classes to the collection of UDT indexes @@ -1300,31 +1313,31 @@ BOOLEAN SymbolInfo_GetTypeNameHelper( else { // A union - PhAppendStringBuilder2(TypeName, Info.sUdtUnionInfo.Name); + PhAppendStringBuilder2(TypeName, Info.UdtUnionInfo.Name); PhAppendStringBuilder2(TypeName, L" "); } } break; case SymTagEnum: - PhAppendStringBuilder2(TypeName, Info.sEnumInfo.Name); + PhAppendStringBuilder2(TypeName, Info.EnumInfo.Name); break; case SymTagFunctionType: { - if (Info.sFunctionTypeInfo.MemberFunction && Info.sFunctionTypeInfo.StaticFunction) + if (Info.FunctionTypeInfo.MemberFunction && Info.FunctionTypeInfo.StaticFunction) PhAppendStringBuilder2(TypeName, L"static "); // return value - if (!SymbolInfo_GetTypeNameHelper(Info.sFunctionTypeInfo.RetTypeIndex, Obj, VarName, TypeName)) + if (!SymbolInfo_GetTypeNameHelper(Info.FunctionTypeInfo.RetTypeIndex, Obj, VarName, TypeName)) return FALSE; // calling convention - PhAppendStringBuilder2(TypeName, SymbolInfo_CallConvStr(Info.sFunctionTypeInfo.CallConv)); + PhAppendStringBuilder2(TypeName, SymbolInfo_CallConvStr(Info.FunctionTypeInfo.CallConv)); PhAppendStringBuilder2(TypeName, L" "); // If member function, save the class type index - if (Info.sFunctionTypeInfo.MemberFunction) + if (Info.FunctionTypeInfo.MemberFunction) { - PhAddItemList(Obj->UdtList, UlongToPtr(Info.sFunctionTypeInfo.ClassIndex)); + PhAddItemList(Obj->UdtList, UlongToPtr(Info.FunctionTypeInfo.ClassIndex)); /* // It is not needed to print the class name here, because it is contained in the function name @@ -1338,42 +1351,42 @@ BOOLEAN SymbolInfo_GetTypeNameHelper( PhAppendStringBuilder2(TypeName, *VarName); // Print parameters - PhAppendStringBuilder2(TypeName, L" ("); + PhAppendStringBuilder2(TypeName, L"("); - for (ULONG i = 0; i < Info.sFunctionTypeInfo.NumArgs; i++) + for (ULONG i = 0; i < Info.FunctionTypeInfo.NumArgs; i++) { - if (!SymbolInfo_GetTypeNameHelper(Info.sFunctionTypeInfo.Args[i], Obj, VarName, TypeName)) + if (!SymbolInfo_GetTypeNameHelper(Info.FunctionTypeInfo.Args[i], Obj, VarName, TypeName)) return FALSE; - if (i < (Info.sFunctionTypeInfo.NumArgs - 1)) + if (i < (Info.FunctionTypeInfo.NumArgs - 1)) PhAppendStringBuilder2(TypeName, L", "); } PhAppendStringBuilder2(TypeName, L") "); // Print "this" adjustment value - if (Info.sFunctionTypeInfo.MemberFunction && Info.sFunctionTypeInfo.ThisAdjust != 0) - PhAppendFormatStringBuilder(TypeName, L": this+%u ", Info.sFunctionTypeInfo.ThisAdjust); + if (Info.FunctionTypeInfo.MemberFunction && Info.FunctionTypeInfo.ThisAdjust != 0) + PhAppendFormatStringBuilder(TypeName, L": this+%u ", Info.FunctionTypeInfo.ThisAdjust); } break; case SymTagFunctionArgType: { - if (!SymbolInfo_GetTypeNameHelper(Info.sFunctionArgTypeInfo.TypeIndex, Obj, VarName, TypeName)) + if (!SymbolInfo_GetTypeNameHelper(Info.FunctionArgTypeInfo.TypeIndex, Obj, VarName, TypeName)) return FALSE; } break; case SymTagArrayType: { // Print element type name - if (!SymbolInfo_GetTypeNameHelper(Info.sArrayTypeInfo.ElementTypeIndex, Obj, VarName, TypeName)) + if (!SymbolInfo_GetTypeNameHelper(Info.ArrayTypeInfo.ElementTypeIndex, Obj, VarName, TypeName)) return FALSE; PhAppendStringBuilder2(TypeName, L" "); // Print dimensions - for (ULONG i = 0; i < Info.sArrayTypeInfo.NumDimensions; i++) - PhAppendFormatStringBuilder(TypeName, L"[%I64u]", Info.sArrayTypeInfo.Dimensions[i]); + for (ULONG i = 0; i < Info.ArrayTypeInfo.NumDimensions; i++) + PhAppendFormatStringBuilder(TypeName, L"[%I64u]", Info.ArrayTypeInfo.Dimensions[i]); } break; default: @@ -1829,10 +1842,7 @@ BOOL CALLBACK EnumCallbackProc( PhReleaseQueuedLockExclusive(&SearchResultsLock); // Enumerate parameters and variables... - IMAGEHLP_STACK_FRAME sf; - sf.InstructionOffset = SymbolInfo->Address; - SymSetContext_I(NtCurrentProcess(), &sf, 0); - SymEnumSymbolsW_I(NtCurrentProcess(), 0, NULL, EnumCallbackProc, context); + PdbDumpAddress(context, SymbolInfo->Address); } break; case SymTagData: @@ -1842,9 +1852,9 @@ BOOL CALLBACK EnumCallbackProc( PWSTR symDataKind; ULONG dataKindType = 0; - if (!SymbolInfo->Address) + if (SymbolInfo->Address == 0) break; - + if (!SymGetTypeInfo_I( NtCurrentProcess(), SymbolInfo->ModBase, @@ -1858,12 +1868,12 @@ BOOL CALLBACK EnumCallbackProc( symDataKind = SymbolInfo_DataKindStr(dataKindType); - if (dataKindType == DataIsLocal || - dataKindType == DataIsParam || - dataKindType == DataIsObjectPtr) - { - break; - } + //if (dataKindType == DataIsLocal || + // dataKindType == DataIsParam || + // dataKindType == DataIsObjectPtr) + //{ + // break; + //} symbol = PhAllocate(sizeof(PV_SYMBOL_NODE)); memset(symbol, 0, sizeof(PV_SYMBOL_NODE)); @@ -1872,7 +1882,8 @@ BOOL CALLBACK EnumCallbackProc( { case DataIsLocal: { - SymbolInfo->Address = SymbolInfo->ModBase + SymbolInfo->Address; + // TODO: The address variable is FUNCTION+OFFSET + //SymbolInfo->Address = SymbolInfo->Address; symbol->Type = PV_SYMBOL_TYPE_LOCAL_VAR; } break; @@ -1972,7 +1983,7 @@ VOID PrintClassInfo( { TypeInfo VarInfo; - if (!SymbolInfo_DumpType(Context, Info->Variables[i], &VarInfo)) + if (!SymbolInfo_DumpType(Context->BaseAddress, Info->Variables[i], &VarInfo)) { // Continue } @@ -1990,7 +2001,7 @@ VOID PrintClassInfo( //symbol->Type = PV_SYMBOL_TYPE_MEMBER; // // Location - switch (VarInfo.sDataInfo.dataKind) + switch (VarInfo.DataInfo.dataKind) { case DataIsGlobal: case DataIsStaticLocal: @@ -2028,7 +2039,7 @@ VOID PrintClassInfo( { TypeInfo VarInfo; - if (!SymbolInfo_DumpType(Context, Info->Variables[i], &VarInfo)) + if (!SymbolInfo_DumpType(Context->BaseAddress, Info->Variables[i], &VarInfo)) { // Continue } @@ -2044,10 +2055,10 @@ VOID PrintClassInfo( memset(symbol, 0, sizeof(PV_SYMBOL_NODE)); symbol->Type = PV_SYMBOL_TYPE_FUNCTION; - symbol->Address = VarInfo.sDataInfo.Address; - symbol->Size = (ULONG)VarInfo.sDataInfo.Offset; - symbol->Name = PhCreateString(VarInfo.sDataInfo.Name); - symbol->Data = SymbolInfo_GetTypeName(Context, VarInfo.sDataInfo.TypeIndex, VarInfo.sDataInfo.Name); + symbol->Address = VarInfo.DataInfo.Address; + symbol->Size = (ULONG)VarInfo.DataInfo.Offset; + symbol->Name = PhCreateString(VarInfo.DataInfo.Name); + symbol->Data = SymbolInfo_GetTypeName(Context, VarInfo.DataInfo.TypeIndex, VarInfo.DataInfo.Name); //SymbolInfo_SymbolLocationStr(SymbolInfo, symbol->Pointer); // Info.Info.sUdtClassInfo.Nested // Info.Info.sUdtClassInfo.NumVariables @@ -2057,12 +2068,7 @@ VOID PrintClassInfo( PhReleaseQueuedLockExclusive(&SearchResultsLock); // Enumerate function parameters and local variables... - IMAGEHLP_STACK_FRAME sf; - - sf.InstructionOffset = VarInfo.sDataInfo.Address; - - SymSetContext_I(NtCurrentProcess(), &sf, 0); - SymEnumSymbolsW_I(NtCurrentProcess(), 0, NULL, EnumCallbackProc, Context); + PdbDumpAddress(Context, VarInfo.DataInfo.Address); } } @@ -2070,7 +2076,7 @@ VOID PrintClassInfo( { TypeInfo baseInfo; - if (!SymbolInfo_DumpType(Context, Info->BaseClasses[i], &baseInfo)) + if (!SymbolInfo_DumpType(Context->BaseAddress, Info->BaseClasses[i], &baseInfo)) { // Continue } @@ -2083,7 +2089,7 @@ VOID PrintClassInfo( TypeInfo BaseUdtInfo; // Obtain the next base class - if (!SymbolInfo_DumpType(Context, baseInfo.sBaseClassInfo.TypeIndex, &BaseUdtInfo)) + if (!SymbolInfo_DumpType(Context->BaseAddress, baseInfo.BaseClassInfo.TypeIndex, &BaseUdtInfo)) { // Continue } @@ -2093,7 +2099,7 @@ VOID PrintClassInfo( } else { - if (baseInfo.sBaseClassInfo.Virtual) + if (baseInfo.BaseClassInfo.Virtual) { //PhAddItemList(L"VIRTUAL_BASE_CLASS", BaseUdtInfo.sUdtClassInfo.Name) } @@ -2118,21 +2124,21 @@ VOID PrintUserDefinedTypes( { index = PtrToUlong(Context->UdtList->Items[i]); - if (SymbolInfo_DumpType(Context, index, &info)) + if (SymbolInfo_DumpType(Context->BaseAddress, index, &info)) { if (info.Tag == SymTagUDT) { if (info.UdtKind) { // Print information about the class - PrintClassInfo(Context, index, &info.sUdtClassInfo); + PrintClassInfo(Context, index, &info.UdtClassInfo); // Print information about its base classes - for (ULONG i = 0; i < info.sUdtClassInfo.NumBaseClasses; i++) + for (ULONG i = 0; i < info.UdtClassInfo.NumBaseClasses; i++) { TypeInfo baseInfo; - if (!SymbolInfo_DumpType(Context, info.sUdtClassInfo.BaseClasses[i], &baseInfo)) + if (!SymbolInfo_DumpType(Context->BaseAddress, info.UdtClassInfo.BaseClasses[i], &baseInfo)) { // Continue } @@ -2145,7 +2151,7 @@ VOID PrintUserDefinedTypes( // Obtain information about the base class TypeInfo baseUdtInfo; - if (!SymbolInfo_DumpType(Context, baseInfo.sBaseClassInfo.TypeIndex, &baseUdtInfo)) + if (!SymbolInfo_DumpType(Context->BaseAddress, baseInfo.BaseClassInfo.TypeIndex, &baseUdtInfo)) { // Continue } @@ -2156,7 +2162,7 @@ VOID PrintUserDefinedTypes( else { // Print information about the base class - PrintClassInfo(Context, baseInfo.sBaseClassInfo.TypeIndex, &baseUdtInfo.sUdtClassInfo); + PrintClassInfo(Context, baseInfo.BaseClassInfo.TypeIndex, &baseUdtInfo.UdtClassInfo); } } } @@ -2304,30 +2310,31 @@ NTSTATUS PeDumpFileSymbols( if (!(symsrvPath = PvFindDbghelpPath(TRUE))) return 1; - dbghelpHandle = LoadLibrary(dbghelpPath->Buffer); - symsrvHandle = LoadLibrary(symsrvPath->Buffer); - - if (!(dbghelpHandle = GetModuleHandle(L"dbghelp.dll"))) + if (!(dbghelpHandle = LoadLibrary(dbghelpPath->Buffer))) + return 1; + if (!(symsrvHandle = LoadLibrary(symsrvPath->Buffer))) return 1; - + SymInitialize_I = PhGetProcedureAddress(dbghelpHandle, "SymInitialize", 0); SymCleanup_I = PhGetProcedureAddress(dbghelpHandle, "SymCleanup", 0); SymEnumSymbolsW_I = PhGetProcedureAddress(dbghelpHandle, "SymEnumSymbolsW", 0); + SymEnumTypesW_I = PhGetProcedureAddress(dbghelpHandle, "SymEnumTypesW", 0); SymSetSearchPathW_I = PhGetProcedureAddress(dbghelpHandle, "SymSetSearchPathW", 0); SymGetOptions_I = PhGetProcedureAddress(dbghelpHandle, "SymGetOptions", 0); SymSetOptions_I = PhGetProcedureAddress(dbghelpHandle, "SymSetOptions", 0); SymLoadModuleExW_I = PhGetProcedureAddress(dbghelpHandle, "SymLoadModuleExW", 0); SymGetModuleInfoW64_I = PhGetProcedureAddress(dbghelpHandle, "SymGetModuleInfoW64", 0); + SymGetTypeFromNameW_I = PhGetProcedureAddress(dbghelpHandle, "SymGetTypeFromNameW", 0); SymGetTypeInfo_I = PhGetProcedureAddress(dbghelpHandle, "SymGetTypeInfo", 0); SymSetContext_I = PhGetProcedureAddress(dbghelpHandle, "SymSetContext", 0); - SymSetOptions_I(SymGetOptions_I() | SYMOPT_DEBUG | SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS); + SymSetOptions_I(SymGetOptions_I() | SYMOPT_DEBUG | SYMOPT_UNDNAME); if (!SymInitialize_I(NtCurrentProcess(), NULL, FALSE)) return 1; if (!SymSetSearchPathW_I(NtCurrentProcess(), L"SRV*C:\\symbols*http://msdl.microsoft.com/download/symbols")) - return 1; + goto CleanupExit; if (!NT_SUCCESS(status = PhCreateFileWin32( &fileHandle, @@ -2338,7 +2345,7 @@ NTSTATUS PeDumpFileSymbols( FILE_OPEN, FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT ))) - return 1; + goto CleanupExit; if (NT_SUCCESS(PhGetFileSize(fileHandle, &fileSize)) && fileSize.QuadPart == 0) goto CleanupExit; @@ -2361,7 +2368,8 @@ NTSTATUS PeDumpFileSymbols( SymEnumSymbolsW_I(NtCurrentProcess(), Context->BaseAddress, NULL, EnumCallbackProc, Context); // Enumerate user defined types - PrintUserDefinedTypes(Context); + //PrintUserDefinedTypes(Context); + //SymEnumTypesW_I(NtCurrentProcess(), Context->BaseAddress, EnumCallbackProc, Context); } CleanupExit: @@ -2375,3 +2383,16 @@ NTSTATUS PeDumpFileSymbols( return 0; } + +VOID PdbDumpAddress( + _In_ PPDB_SYMBOL_CONTEXT Context, + _In_ ULONG64 Address + ) +{ + IMAGEHLP_STACK_FRAME sf; + + sf.InstructionOffset = Address; + + SymSetContext_I(NtCurrentProcess(), &sf, 0); + SymEnumSymbolsW_I(NtCurrentProcess(), 0, NULL, EnumCallbackProc, Context); +} \ No newline at end of file From 3fc71eb033e7ed26216f9fd7e876cc882cd97af3 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 29 May 2017 10:09:01 +1000 Subject: [PATCH 0171/2058] BuildTools: Update minimum framework version --- tools/CustomBuildTool/CustomBuildTool.csproj | 2 +- .../bin/Release/CustomBuildTool.exe | Bin 160768 -> 160768 bytes .../bin/Release/CustomBuildTool.pdb | Bin 69120 -> 69120 bytes 3 files changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/CustomBuildTool/CustomBuildTool.csproj b/tools/CustomBuildTool/CustomBuildTool.csproj index 83a5df2111b6..86a7da4e9202 100644 --- a/tools/CustomBuildTool/CustomBuildTool.csproj +++ b/tools/CustomBuildTool/CustomBuildTool.csproj @@ -9,7 +9,7 @@ Properties CustomBuildTool CustomBuildTool - v4.5 + v4.6.1 512 true diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe b/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe index ef4b4940de3aa5582192417cf4abdbb58da3875c..ae3e4917aa65f38bfe6005a4a561bab2d4bdd05b 100644 GIT binary patch delta 511 zcmZp8!P)SFb3zBROrr9{Zdpd9i7UeyFHB}+RA-&R%*Y@!S@D_9>wUxFxwf(uHkV8vy*}BWjx7Xb~BKDfu|YFUJPXa z;#mx4uVg&T@R;{7P(%etf=oLJ6!{*-`xq$X2P8p4FM&ebe9TPA3>Cc0Odt_Xro#*} ze40Sgh|ig6GeZ`;Cy?#ImkA_e_?nrzfg+tib}`>dAlbop5=hSAdkG}hOnx1$%(!SX zf6US%fy?_$bRO*p^I6bhs#=p*p1k?Uxd3iIUtnx88i6=&w> z*_N5;nduoaGKBDnz$INWiwklREB%0KML@a~;4%te)tlpPS#j$CV}DYQ3{Nwdy%@;; z#5UIK;K`IwoK8A^DWnLr|(OotgH z_%wl}9-lMQW`-c@HI1a14TN4?0mkJK(dAJB#@lK_Yz31nEX0gnQ`7` z{+Ojj0@qq*|B_yNzO?((`i-aVtv9O)bwa%GL=>Eh^5; z&$BHv(KBUa2;mcfOSxng7vv;X`T@zA1fon^o>ePlAC`% d6J?xez|ze3Vmsdp#$TOG3Z~lyU6{Tx0szn>n(hDq diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb b/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb index 65e7ad0ab95c5520814db5dadb6dd0c927b21d5c..7f1693848601036610aee5335abd529cbffc4f95 100644 GIT binary patch delta 380 zcmZpe!_qK^WdjSBgiNAxBqIX@!^-?_;YZc>&bz~>l|I*e<+oXe>y0=EQBB0_tlZ)Plz}b)9Le$y4;hF6B4k5np zT?|}}*?S*2d*1s55PLJ<2MZ>+VA3ZSIQ!5i4>()xGlX6D8Dh!3&ll=7wfE^TFjND5 z1Om(quWmzF3=E76n%b7S3=CJH0_bvldJGJ?IOM88o$x2~6$U%Xj{>y0?aoox#9K3%%R zIJxkH@WcSw%??WMPBJktOg4BE2cjlGs1I+_Ac9hpi{6I7n2+8Dz?gpT;G+B9#lS?( z-uu9q^WG-_nVUYiF~LNVKDoe{hdz10m};NF%!1Eg>o0u1SI@w(Plth_8t4NMV1`g& y667mOT?U4$P%(5lK0OA8TpV)MK)H1|ESq(|UdJ7XTV)uZ@B#qf31FW9 From 88ebde21366f48b49f056557a86d78e9d442255a Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 29 May 2017 10:32:37 +1000 Subject: [PATCH 0172/2058] Fix setup crash --- tools/CustomSetupTool/CustomSetupTool/setup.c | 7 +++++++ tools/CustomSetupTool/CustomSetupTool/update.c | 8 +++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/tools/CustomSetupTool/CustomSetupTool/setup.c b/tools/CustomSetupTool/CustomSetupTool/setup.c index 9f0a316e62d4..495bffc05082 100644 --- a/tools/CustomSetupTool/CustomSetupTool/setup.c +++ b/tools/CustomSetupTool/CustomSetupTool/setup.c @@ -193,6 +193,13 @@ BOOLEAN SetupCreateUninstallFile( if (RtlDoesFileExists_U(uninstallFilePath->Buffer)) { + if (!DeleteFile(backupFilePath->Buffer)) + { + Context->ErrorCode = GetLastError(); + PhDereferenceObject(uninstallFilePath); + return FALSE; + } + if (!MoveFile(uninstallFilePath->Buffer, backupFilePath->Buffer)) { Context->ErrorCode = GetLastError(); diff --git a/tools/CustomSetupTool/CustomSetupTool/update.c b/tools/CustomSetupTool/CustomSetupTool/update.c index 1ba229e2cf3e..b1c57350a315 100644 --- a/tools/CustomSetupTool/CustomSetupTool/update.c +++ b/tools/CustomSetupTool/CustomSetupTool/update.c @@ -149,7 +149,13 @@ VOID SetupShowUpdatingErrorDialog( )->Buffer; if (Context->ErrorCode) - config.pszContent = PhGetStatusMessage(0, Context->ErrorCode)->Buffer; + { + PPH_STRING errorString; + + if (errorString = PhGetStatusMessage(0, Context->ErrorCode)) + config.pszContent = PhGetString(errorString); + } + SendMessage(Context->PropSheetHandle, TDM_NAVIGATE_PAGE, 0, (LPARAM)&config); } From cc0f158e33235051cd15d6f759eb680b24264016 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 29 May 2017 13:19:42 +1000 Subject: [PATCH 0173/2058] Fix setup hanging on update --- .../CustomSetupTool/include/setup.h | 4 +-- tools/CustomSetupTool/CustomSetupTool/page4.c | 2 +- tools/CustomSetupTool/CustomSetupTool/setup.c | 25 ++++++++----------- .../CustomSetupTool/uninstall.c | 2 +- .../CustomSetupTool/CustomSetupTool/update.c | 2 +- 5 files changed, 16 insertions(+), 19 deletions(-) diff --git a/tools/CustomSetupTool/CustomSetupTool/include/setup.h b/tools/CustomSetupTool/CustomSetupTool/include/setup.h index 1c8852690d86..0696dba7bfd0 100644 --- a/tools/CustomSetupTool/CustomSetupTool/include/setup.h +++ b/tools/CustomSetupTool/CustomSetupTool/include/setup.h @@ -188,8 +188,8 @@ VOID SetupStartKph( _In_ PPH_SETUP_CONTEXT Context ); -ULONG SetupUninstallKph( - VOID +BOOLEAN SetupUninstallKph( + _In_ PPH_SETUP_CONTEXT Context ); NTSTATUS SetupCreateUninstallKey( diff --git a/tools/CustomSetupTool/CustomSetupTool/page4.c b/tools/CustomSetupTool/CustomSetupTool/page4.c index 1c6b89477a95..e179d5dedd43 100644 --- a/tools/CustomSetupTool/CustomSetupTool/page4.c +++ b/tools/CustomSetupTool/CustomSetupTool/page4.c @@ -35,7 +35,7 @@ NTSTATUS SetupProgressThread( goto CleanupExit; // Stop the kernel driver(s). - if (!SetupUninstallKph()) + if (!SetupUninstallKph(Context)) goto CleanupExit; // Create the install folder path. diff --git a/tools/CustomSetupTool/CustomSetupTool/setup.c b/tools/CustomSetupTool/CustomSetupTool/setup.c index 495bffc05082..4356a30eefec 100644 --- a/tools/CustomSetupTool/CustomSetupTool/setup.c +++ b/tools/CustomSetupTool/CustomSetupTool/setup.c @@ -332,35 +332,32 @@ VOID SetupStartKph( PhDereferenceObject(clientPath); } -ULONG SetupUninstallKph( - VOID +BOOLEAN SetupUninstallKph( + _In_ PPH_SETUP_CONTEXT Context ) { - ULONG status = ERROR_SUCCESS; - SC_HANDLE scmHandle; + BOOLEAN deleted = FALSE; SC_HANDLE serviceHandle; SERVICE_STATUS serviceStatus; - if (!(scmHandle = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT))) - return GetLastError(); - - if (serviceHandle = OpenService(scmHandle, L"KProcessHacker3", SERVICE_STOP | DELETE)) + if (serviceHandle = PhOpenService( + L"KProcessHacker3", + SERVICE_STOP | DELETE + )) { ControlService(serviceHandle, SERVICE_CONTROL_STOP, &serviceStatus); - if (!DeleteService(serviceHandle)) - status = GetLastError(); + if (!(deleted = DeleteService(serviceHandle))) + Context->ErrorCode = GetLastError(); CloseServiceHandle(serviceHandle); } else { - status = GetLastError(); + deleted = TRUE; } - CloseServiceHandle(scmHandle); - - return status; + return deleted; } VOID SetupSetWindowsOptions( diff --git a/tools/CustomSetupTool/CustomSetupTool/uninstall.c b/tools/CustomSetupTool/CustomSetupTool/uninstall.c index c03dbaf6713f..c79116583ac8 100644 --- a/tools/CustomSetupTool/CustomSetupTool/uninstall.c +++ b/tools/CustomSetupTool/CustomSetupTool/uninstall.c @@ -51,7 +51,7 @@ NTSTATUS SetupUninstallBuild( goto CleanupExit; // Stop the kernel driver(s). - if (!SetupUninstallKph()) + if (!SetupUninstallKph(Context)) goto CleanupExit; // Remove autorun and shortcuts. diff --git a/tools/CustomSetupTool/CustomSetupTool/update.c b/tools/CustomSetupTool/CustomSetupTool/update.c index b1c57350a315..0298b54e56c2 100644 --- a/tools/CustomSetupTool/CustomSetupTool/update.c +++ b/tools/CustomSetupTool/CustomSetupTool/update.c @@ -36,7 +36,7 @@ NTSTATUS SetupUpdateBuild( if (!ShutdownProcessHacker()) goto CleanupExit; - if (!SetupUninstallKph()) + if (!SetupUninstallKph(Context)) goto CleanupExit; if (!SetupCreateUninstallFile(Context)) From 5d356872af61bea2fe4672c1f0a190345eb704e3 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 29 May 2017 13:41:13 +1000 Subject: [PATCH 0174/2058] Fix setup build error --- .../CustomSetupTool/include/setup.h | 29 +--------------- tools/CustomSetupTool/CustomSetupTool/main.c | 2 +- tools/CustomSetupTool/CustomSetupTool/page1.c | 8 ++--- tools/CustomSetupTool/CustomSetupTool/page4.c | 4 +-- tools/CustomSetupTool/CustomSetupTool/page5.c | 6 ++-- tools/CustomSetupTool/CustomSetupTool/setup.c | 5 ++- .../CustomSetupTool/uninstall.c | 33 ++++++++++--------- .../CustomSetupTool/CustomSetupTool/update.c | 14 ++++---- 8 files changed, 37 insertions(+), 64 deletions(-) diff --git a/tools/CustomSetupTool/CustomSetupTool/include/setup.h b/tools/CustomSetupTool/CustomSetupTool/include/setup.h index 0696dba7bfd0..60498e436fd2 100644 --- a/tools/CustomSetupTool/CustomSetupTool/include/setup.h +++ b/tools/CustomSetupTool/CustomSetupTool/include/setup.h @@ -75,7 +75,7 @@ typedef enum _SETUP_COMMAND_TYPE typedef struct _PH_SETUP_CONTEXT { - HWND PropSheetHandle; + HWND DialogHandle; HWND PropSheetBackHandle; HWND PropSheetForwardHandle; HWND PropSheetCancelHandle; @@ -248,33 +248,6 @@ VOID SetupShowUpdateDialog( // uninstall.c -typedef struct _PH_SETUP_UNINSTALL_CONTEXT -{ - HWND DialogHandle; - HICON IconSmallHandle; - HICON IconLargeHandle; - - ULONG CurrentMajorVersion; - ULONG CurrentMinorVersion; - ULONG CurrentRevisionVersion; - ULONG LatestMajorVersion; - ULONG LatestMinorVersion; - ULONG LatestRevisionVersion; - - ULONG ErrorCode; - PPH_STRING Version; - PPH_STRING RevVersion; - PPH_STRING RelDate; - PPH_STRING Size; - PPH_STRING Hash; - PPH_STRING Signature; - PPH_STRING ReleaseNotesUrl; - - PPH_STRING BinFileDownloadUrl; - PPH_STRING SetupFileDownloadUrl; - PPH_STRING SetupFilePath; -} PH_SETUP_UNINSTALL_CONTEXT, *PPH_SETUP_UNINSTALL_CONTEXT; - VOID SetupShowUninstallDialog( VOID ); diff --git a/tools/CustomSetupTool/CustomSetupTool/main.c b/tools/CustomSetupTool/CustomSetupTool/main.c index 7d0f039d82c2..fe45e4258011 100644 --- a/tools/CustomSetupTool/CustomSetupTool/main.c +++ b/tools/CustomSetupTool/CustomSetupTool/main.c @@ -104,7 +104,7 @@ INT CALLBACK MainPropSheet_Callback( context->CurrentMinorVersion = PHAPP_VERSION_MINOR; context->CurrentRevisionVersion = PHAPP_VERSION_REVISION; - context->PropSheetHandle = hwndDlg; + context->DialogHandle = hwndDlg; context->PropSheetBackHandle = GetDlgItem(hwndDlg, IDC_PROPSHEET_BACK); context->PropSheetForwardHandle = GetDlgItem(hwndDlg, IDC_PROPSHEET_NEXT); context->PropSheetCancelHandle = GetDlgItem(hwndDlg, IDC_PROPSHEET_CANCEL); diff --git a/tools/CustomSetupTool/CustomSetupTool/page1.c b/tools/CustomSetupTool/CustomSetupTool/page1.c index 3d8dbf6fa0d2..526f37d9d727 100644 --- a/tools/CustomSetupTool/CustomSetupTool/page1.c +++ b/tools/CustomSetupTool/CustomSetupTool/page1.c @@ -27,8 +27,8 @@ VOID SetupPropSheetCenterWindow( ) { // Center the PropertySheet on the desktop. - PhCenterWindow(Context->PropSheetHandle, NULL); - SetForegroundWindow(Context->PropSheetHandle); + PhCenterWindow(Context->DialogHandle, NULL); + SetForegroundWindow(Context->DialogHandle); } static VOID SetupLoadIcons( @@ -109,13 +109,13 @@ INT_PTR CALLBACK SetupPropPage1_WndProc( case PSN_SETACTIVE: { // Reset the button state. - PropSheet_SetWizButtons(context->PropSheetHandle, PSWIZB_NEXT); + PropSheet_SetWizButtons(context->DialogHandle, PSWIZB_NEXT); } break; case PSN_KILLACTIVE: { // Enable the back button. - PropSheet_SetWizButtons(context->PropSheetHandle, PSWIZB_NEXT | PSWIZB_BACK); + PropSheet_SetWizButtons(context->DialogHandle, PSWIZB_NEXT | PSWIZB_BACK); } break; } diff --git a/tools/CustomSetupTool/CustomSetupTool/page4.c b/tools/CustomSetupTool/CustomSetupTool/page4.c index e179d5dedd43..94d2571c126d 100644 --- a/tools/CustomSetupTool/CustomSetupTool/page4.c +++ b/tools/CustomSetupTool/CustomSetupTool/page4.c @@ -72,7 +72,7 @@ NTSTATUS SetupProgressThread( CleanupExit: - PostMessage(Context->PropSheetHandle, PSM_SETCURSELID, 0, IDD_ERROR); + PostMessage(Context->DialogHandle, PSM_SETCURSELID, 0, IDD_ERROR); return STATUS_FAIL_CHECK; } @@ -146,7 +146,7 @@ INT_PTR CALLBACK SetupPropPage4_WndProc( SetWindowText(context->SubStatusHandle, L"Progress: ~ of ~ (0.0%)"); // Disable Next/Back buttons - PropSheet_SetWizButtons(context->PropSheetHandle, 0); + PropSheet_SetWizButtons(context->DialogHandle, 0); if (!SetupRunning) { diff --git a/tools/CustomSetupTool/CustomSetupTool/page5.c b/tools/CustomSetupTool/CustomSetupTool/page5.c index 737cab677e7a..b480f83c671b 100644 --- a/tools/CustomSetupTool/CustomSetupTool/page5.c +++ b/tools/CustomSetupTool/CustomSetupTool/page5.c @@ -32,12 +32,12 @@ NTSTATUS SetupDownloadProgressThread( if (!UpdateDownloadUpdateData(Context)) goto CleanupExit; - PostMessage(Context->PropSheetHandle, PSM_SETCURSELID, 0, IDD_DIALOG4); + PostMessage(Context->DialogHandle, PSM_SETCURSELID, 0, IDD_DIALOG4); return STATUS_SUCCESS; CleanupExit: - PostMessage(Context->PropSheetHandle, PSM_SETCURSELID, 0, IDD_ERROR); + PostMessage(Context->DialogHandle, PSM_SETCURSELID, 0, IDD_ERROR); return STATUS_FAIL_CHECK; } @@ -97,7 +97,7 @@ INT_PTR CALLBACK SetupPropPage5_WndProc( SetWindowText(context->SubStatusHandle, L""); // Disable Next/Back buttons - PropSheet_SetWizButtons(context->PropSheetHandle, 0); + PropSheet_SetWizButtons(context->DialogHandle, 0); if (threadHandle = PhCreateThread(0, SetupDownloadProgressThread, context)) NtClose(threadHandle); diff --git a/tools/CustomSetupTool/CustomSetupTool/setup.c b/tools/CustomSetupTool/CustomSetupTool/setup.c index 4356a30eefec..be2a2500c977 100644 --- a/tools/CustomSetupTool/CustomSetupTool/setup.c +++ b/tools/CustomSetupTool/CustomSetupTool/setup.c @@ -347,8 +347,7 @@ BOOLEAN SetupUninstallKph( { ControlService(serviceHandle, SERVICE_CONTROL_STOP, &serviceStatus); - if (!(deleted = DeleteService(serviceHandle))) - Context->ErrorCode = GetLastError(); + deleted = DeleteService(serviceHandle); CloseServiceHandle(serviceHandle); } @@ -557,7 +556,7 @@ BOOLEAN SetupExecuteProcessHacker( if (RtlDoesFileExists_U(clientPath->Buffer)) { success = PhShellExecuteEx( - Context->PropSheetHandle, + Context->DialogHandle, clientPath->Buffer, NULL, SW_SHOWDEFAULT, diff --git a/tools/CustomSetupTool/CustomSetupTool/uninstall.c b/tools/CustomSetupTool/CustomSetupTool/uninstall.c index c79116583ac8..1fe866ca7671 100644 --- a/tools/CustomSetupTool/CustomSetupTool/uninstall.c +++ b/tools/CustomSetupTool/CustomSetupTool/uninstall.c @@ -28,20 +28,20 @@ HANDLE UninstallDialogThreadHandle = NULL; PH_EVENT UninstallInitializedEvent = PH_EVENT_INIT; VOID ShowUninstallConfirmDialog( - _In_ PPH_SETUP_UNINSTALL_CONTEXT Context + _In_ PPH_SETUP_CONTEXT Context ); VOID ShowUninstallDialog( - _In_ PPH_SETUP_UNINSTALL_CONTEXT Context + _In_ PPH_SETUP_CONTEXT Context ); VOID ShowUninstallCompleteDialog( - _In_ PPH_SETUP_UNINSTALL_CONTEXT Context + _In_ PPH_SETUP_CONTEXT Context ); VOID ShowUninstallErrorDialog( - _In_ PPH_SETUP_UNINSTALL_CONTEXT Context + _In_ PPH_SETUP_CONTEXT Context ); NTSTATUS SetupUninstallBuild( - _In_ PPH_SETUP_UNINSTALL_CONTEXT Context + _In_ PPH_SETUP_CONTEXT Context ) { //context->SetupInstallPath = SetupFindInstallDirectory(); @@ -76,7 +76,7 @@ NTSTATUS SetupUninstallBuild( } static VOID TaskDialogCreateIcons( - _In_ PPH_SETUP_UNINSTALL_CONTEXT Context + _In_ PPH_SETUP_CONTEXT Context ) { HICON largeIcon; @@ -112,7 +112,7 @@ HRESULT CALLBACK TaskDialogUninstallConfirmCallbackProc( _In_ LONG_PTR dwRefData ) { - PPH_SETUP_UNINSTALL_CONTEXT context = (PPH_SETUP_UNINSTALL_CONTEXT)dwRefData; + PPH_SETUP_CONTEXT context = (PPH_SETUP_CONTEXT)dwRefData; switch (uMsg) { @@ -143,7 +143,7 @@ HRESULT CALLBACK TaskDialogUninstallCallbackProc( _In_ LONG_PTR dwRefData ) { - PPH_SETUP_UNINSTALL_CONTEXT context = (PPH_SETUP_UNINSTALL_CONTEXT)dwRefData; + PPH_SETUP_CONTEXT context = (PPH_SETUP_CONTEXT)dwRefData; switch (uMsg) { @@ -168,7 +168,7 @@ HRESULT CALLBACK TaskDialogUninstallCompleteCallbackProc( _In_ LONG_PTR dwRefData ) { - PPH_SETUP_UNINSTALL_CONTEXT context = (PPH_SETUP_UNINSTALL_CONTEXT)dwRefData; + PPH_SETUP_CONTEXT context = (PPH_SETUP_CONTEXT)dwRefData; switch (uMsg) { @@ -181,7 +181,7 @@ HRESULT CALLBACK TaskDialogUninstallCompleteCallbackProc( } VOID ShowUninstallCompleteDialog( - _In_ PPH_SETUP_UNINSTALL_CONTEXT Context + _In_ PPH_SETUP_CONTEXT Context ) { TASKDIALOGCONFIG config; @@ -202,7 +202,7 @@ VOID ShowUninstallCompleteDialog( } VOID ShowUninstallConfirmDialog( - _In_ PPH_SETUP_UNINSTALL_CONTEXT Context + _In_ PPH_SETUP_CONTEXT Context ) { TASKDIALOGCONFIG config; @@ -224,7 +224,7 @@ VOID ShowUninstallConfirmDialog( } VOID ShowUninstallDialog( - _In_ PPH_SETUP_UNINSTALL_CONTEXT Context + _In_ PPH_SETUP_CONTEXT Context ) { TASKDIALOGCONFIG config; @@ -244,7 +244,7 @@ VOID ShowUninstallDialog( } VOID ShowUninstallErrorDialog( - _In_ PPH_SETUP_UNINSTALL_CONTEXT Context + _In_ PPH_SETUP_CONTEXT Context ) { TASKDIALOGCONFIG config; @@ -271,7 +271,7 @@ HRESULT CALLBACK TaskDialogUninstallBootstrapCallback( _In_ LONG_PTR dwRefData ) { - PPH_SETUP_UNINSTALL_CONTEXT context = (PPH_SETUP_UNINSTALL_CONTEXT)dwRefData; + PPH_SETUP_CONTEXT context = (PPH_SETUP_CONTEXT)dwRefData; switch (uMsg) { @@ -303,8 +303,9 @@ VOID SetupShowUninstallDialog( memset(&config, 0, sizeof(TASKDIALOGCONFIG)); PhInitializeAutoPool(&autoPool); - context = (PPH_SETUP_UNINSTALL_CONTEXT)PhCreateAlloc(sizeof(PH_SETUP_UNINSTALL_CONTEXT)); - memset(context, 0, sizeof(PH_SETUP_UNINSTALL_CONTEXT)); + + context = (PPH_SETUP_CONTEXT)PhCreateAlloc(sizeof(PH_SETUP_CONTEXT)); + memset(context, 0, sizeof(PH_SETUP_CONTEXT)); config.cbSize = sizeof(TASKDIALOGCONFIG); config.dwFlags = TDF_POSITION_RELATIVE_TO_WINDOW; diff --git a/tools/CustomSetupTool/CustomSetupTool/update.c b/tools/CustomSetupTool/CustomSetupTool/update.c index 0298b54e56c2..ae71b4ecb5a7 100644 --- a/tools/CustomSetupTool/CustomSetupTool/update.c +++ b/tools/CustomSetupTool/CustomSetupTool/update.c @@ -52,13 +52,13 @@ NTSTATUS SetupUpdateBuild( if (!SetupExecuteProcessHacker(Context)) goto CleanupExit; - PostMessage(Context->PropSheetHandle, WM_QUIT, 0, 0); + PostMessage(Context->DialogHandle, WM_QUIT, 0, 0); PhDereferenceObject(Context); return STATUS_SUCCESS; CleanupExit: - PostMessage(Context->PropSheetHandle, WM_APP + IDD_ERROR, 0, 0); + PostMessage(Context->DialogHandle, WM_APP + IDD_ERROR, 0, 0); PhDereferenceObject(Context); return STATUS_FAIL_CHECK; } @@ -100,8 +100,8 @@ VOID TaskDialogCreateIcons( Context->IconLargeHandle = largeIcon; Context->IconSmallHandle = smallIcon; - SendMessage(Context->PropSheetHandle, WM_SETICON, ICON_SMALL, (LPARAM)largeIcon); - SendMessage(Context->PropSheetHandle, WM_SETICON, ICON_BIG, (LPARAM)smallIcon); + SendMessage(Context->DialogHandle, WM_SETICON, ICON_SMALL, (LPARAM)largeIcon); + SendMessage(Context->DialogHandle, WM_SETICON, ICON_BIG, (LPARAM)smallIcon); } HRESULT CALLBACK SetupErrorTaskDialogCallbackProc( @@ -156,7 +156,7 @@ VOID SetupShowUpdatingErrorDialog( config.pszContent = PhGetString(errorString); } - SendMessage(Context->PropSheetHandle, TDM_NAVIGATE_PAGE, 0, (LPARAM)&config); + SendMessage(Context->DialogHandle, TDM_NAVIGATE_PAGE, 0, (LPARAM)&config); } LRESULT CALLBACK TaskDialogSubclassProc( @@ -244,7 +244,7 @@ VOID SetupShowUpdatingDialog( PHAPP_VERSION_REVISION )->Buffer; - SendMessage(Context->PropSheetHandle, TDM_NAVIGATE_PAGE, 0, (LPARAM)&config); + SendMessage(Context->DialogHandle, TDM_NAVIGATE_PAGE, 0, (LPARAM)&config); } HRESULT CALLBACK TaskDialogBootstrapCallback( @@ -261,7 +261,7 @@ HRESULT CALLBACK TaskDialogBootstrapCallback( { case TDN_CREATED: { - context->PropSheetHandle = hwndDlg; + context->DialogHandle = hwndDlg; // Center the window on the desktop. PhCenterWindow(hwndDlg, NULL); From 276005f8acaa3ea3ebb2b363541c6533bd0688f3 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 29 May 2017 14:07:14 +1000 Subject: [PATCH 0175/2058] Fix appveyor build version --- tools/CustomBuildTool/Source Files/Build.cs | 2 +- .../bin/Release/CustomBuildTool.exe | Bin 160768 -> 160768 bytes .../bin/Release/CustomBuildTool.pdb | Bin 69120 -> 69120 bytes 3 files changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/CustomBuildTool/Source Files/Build.cs b/tools/CustomBuildTool/Source Files/Build.cs index 3cf61d381a22..8c08ea46f01b 100644 --- a/tools/CustomBuildTool/Source Files/Build.cs +++ b/tools/CustomBuildTool/Source Files/Build.cs @@ -263,7 +263,7 @@ public static void ShowBuildEnvironment(string Platform, bool ShowBuildInfo, boo BuildCount = "0"; BuildVersion = "3.0." + BuildRevision; - BuildLongVersion = "3.0." + BuildCount + "." + BuildRevision; + BuildLongVersion = "3.0." + BuildRevision + "." + BuildCount; if (ShowBuildInfo && !GitExportBuild) { diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe b/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe index ae3e4917aa65f38bfe6005a4a561bab2d4bdd05b..402eed5c4938f85546126704a750ea62597dce88 100644 GIT binary patch delta 118 zcmV-+0Ez#A=m~)636O{bTb?Vii!ucZ3IG5Ea;E_RaDEB1$OY`k5ZVO;a?QKOM7Kx& z1aH2NPP4?$*cJm@o-31|<{Da;E_RaDEE2$OY`k5YxUiEaJFUOrV4{ zC46poW3$B0*cJmEVIz~DDe6uE0000)I$UsaZ)#;@baRv8 RcXA1Mgax3n$w&F?%Ny=YedcqtL#r-{H}^##FE3Zz>~`&Oi#sY@ z`^42Q_s>xkne-UxR!NYTe@W?7U{T~+>z zJ8Qd}y^>I>1C}U8s-*qpl@m<#V#L5mB%c5(z#OE!7Q27m9&ukK+Q~kRiUok(O8#a&W_l6r)W6PDG79M-!Y*)#+|t`TL{o z`D2iF2jUtElBHFtrotf%n1_KgUfbZD?)?i9ZAwYW2y>xU2Q5R5efdvR0magiD3-AB z*kY+8by@`>w3Kj!Hlk)}&%cyKS!k0KOIUa;ZBmV0nDLiLv9x)LB`iGFDcNVm>1p$X zIu+-vmn-29c* zgw7nfjhwyb*6Tr3vRga#=T*Sk{9uLRe$mF;>JPsP8mnUfBDRDUq@bL)FzQv|waa@H4R)^RX4J`c!j@vtm z3Ce<@4&IaVN?OcuQKL>hSCl(y;swolbsjOD26mCbyUgJE!g-!CAH2#S-U=s<;oW8M z9x!;GXAEKwgV@X9^)qxXU;CsCR!Q9bjAm5V|cAg zhk54*yhI!ET3)C8=bovg zf54|dT1eFTStx8w2Ag&_qgJ1(4KHf^7fcLT&IO2N;n;2ySUC35>DqXH;(sYvK^(tf z(I=xGL2X2RT;9opB|a5RdR%%@qES{NY*6gcS#VYWUBaLEaxO);Yzk>KxiUdc5#ZP4 zgJ>T@iA33tQiHM&r50tc+#$d;@XFl+#6hh5NB~RcI{^y7Sc>pYlya0Zc|#=3hiadr Q9-!W5e*m2`bztK^0g7=-XaE2J delta 2279 zcmaJ?ZD?C%6n@XmZF2KT+SF{;#5USiv!=DR?dU{m!wTCE*F{>H!-8&Ii7V92eyq-J zOLYp0AZ9P@GFt+3S}1PA?jjK<#j2=NWPYO#wo%xGVLvic{WG2CG`CrDcXKa1ob#UN zdET$fy=QDf9Gei|3>6&^7-LDW!Ff0%xCOYZ6pMcqt@Z7=cRL_6wdZxu+~^}4&u%+9 z{73LwhvKt^+@;G0y(wX0{h!~4(nf40xms|9Netr`P?W`RYc3rU- zw;CPT(O=gysM&a%u3mPF;Jj`2L_l}XetEA5)?gW4$|PbQK~EFj?tVlB?|&R|6;X>f z*TusrPdp+O&md``m!m$N@$edO#>1W?m68OXfAsaHAAbP;+;tTDd0S=acAD*e6yG&h z4<|QI)^%e}t8`){u2-Fi0D;T@2iINdCN13uX^G3#T6ja1$4VDKtVP*Ub)i+bDk$rAB}_1>oQp>7 z7#apgXf(BNM1+VE7%i7@6h3^PfTP{7Y;(bkGRsGbu(;vadsMtKzSRm%O7pu(D;DQZ zN1a%F{Nq6jj?R6y)g6zBitneAGG6U)^VWsPN=&HnzlA5%x`Piac4hOq#f+|X!NEJ0 zZq;X&y0e<~sYkPUBK0)oitD;pfEHer4rHmF>Go{?X?k-uuU^jNhn6!-U0nVy7Oa^G zF*b_VLyw7FyO7Bk0~V~=P|MiQYC+4n>KN-Uz>OkzT9;!i_yA-3R8CZC|2ZYZ7~@U& ze$=8>jTG?JvA2+u)S8xi+rT$v;G53%;riK!7W~k__(`rY>&k5OO9S6|17GYH1LH*l z;}rwnyn!#B@4Iz=I{gg;qp7*@tFR+i=oOY2_{y4h7B&V9j6s71>ovX;EjNUXm+^Ep zc*G&ZCd~El2G&Wp3esqQ|MY{_)~M0s*H(I!rq-qzH*#tv`MySuz378p7>9V|;UhNj z&O$BJFZ%_k*J~^*%`l|LH0TvqnwPiVKpaFILd4`*GkD}*&ESKQWXcSk;M|S%XAn_DpZu5v YHPh`cL(xk(Je(}H!J;WyVFQQoKg!qH{{R30 From fa5aa92c2575339a13d2bd327412bb5a6dad869f Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 29 May 2017 19:25:04 +1000 Subject: [PATCH 0176/2058] Remove extra gitattributes --- .gitattributes | 2 -- 1 file changed, 2 deletions(-) diff --git a/.gitattributes b/.gitattributes index 0fb12ca3d9a1..b895d0391026 100644 --- a/.gitattributes +++ b/.gitattributes @@ -15,9 +15,7 @@ *.config eol=crlf *.cmd eol=crlf *.csproj eol=crlf -*.filters eol=crlf *.h eol=crlf -*.md eol=crlf *.manifest eol=crlf *.rc eol=crlf *.sln eol=crlf From e8718db3fd333e2bcba0b53099de34ceb75a26b1 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 29 May 2017 19:45:47 +1000 Subject: [PATCH 0177/2058] Backport deprecated v2 debug code --- .../bin-signed/amd64/kprocesshacker.sys | Bin 45208 -> 40088 bytes .../bin-signed/i386/kprocesshacker.sys | Bin 41624 -> 36376 bytes ProcessHacker/main.c | 15 +- phlib/include/kphapi.h | 55 +-- phlib/include/kphuser.h | 51 ++- phlib/kph.c | 411 +++++------------- phlib/native.c | 61 +-- phlib/phlib.vcxproj | 3 +- phlib/phlib.vcxproj.filters | 3 - 9 files changed, 167 insertions(+), 432 deletions(-) diff --git a/KProcessHacker/bin-signed/amd64/kprocesshacker.sys b/KProcessHacker/bin-signed/amd64/kprocesshacker.sys index 7d4695902a56f21840791f0efcdf74d35bad3c34..4da0af31c218fe951f263f863345fdc66545eced 100644 GIT binary patch delta 19905 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 Uc5kunx$lO(f8lPu>jT;U0^YzbjsO4v delta 22087 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 diff --git a/KProcessHacker/bin-signed/i386/kprocesshacker.sys b/KProcessHacker/bin-signed/i386/kprocesshacker.sys index 4f5372a8bd5b0e3530c2871c4dc771a9e4d6550d..6771d7266b67b245778ed488935031d585c92f48 100644 GIT binary patch literal 36376 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 Z5f6WBy*w?#JL%zwcX$1j^YQD<{{d(wt0w>e delta 21033 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 diff --git a/ProcessHacker/main.c b/ProcessHacker/main.c index 3d8b82255a96..688a815cf533 100644 --- a/ProcessHacker/main.c +++ b/ProcessHacker/main.c @@ -553,32 +553,19 @@ VOID PhInitializeKph( ) { static PH_STRINGREF kprocesshacker = PH_STRINGREF_INIT(L"kprocesshacker.sys"); - static PH_STRINGREF processhackerSig = PH_STRINGREF_INIT(L"ProcessHacker.sig"); - PPH_STRING kprocesshackerFileName; - PPH_STRING processhackerSigFileName; KPH_PARAMETERS parameters; - PUCHAR signature; - ULONG signatureSize; if (WindowsVersion < WINDOWS_7) return; kprocesshackerFileName = PhConcatStringRef2(&PhApplicationDirectory->sr, &kprocesshacker); - processhackerSigFileName = PhConcatStringRef2(&PhApplicationDirectory->sr, &processhackerSig); parameters.SecurityLevel = KphSecurityPrivilegeCheck; parameters.CreateDynamicConfiguration = TRUE; KphConnect2Ex(KPH_DEVICE_SHORT_NAME, kprocesshackerFileName->Buffer, ¶meters); - if (signature = PhpReadSignature(processhackerSigFileName->Buffer, &signatureSize)) - { - KphVerifyClient(signature, signatureSize); - PhFree(signature); - } - PhDereferenceObject(kprocesshackerFileName); - PhDereferenceObject(processhackerSigFileName); } BOOLEAN PhInitializeAppSystem( @@ -980,7 +967,7 @@ VOID PhpProcessStartupParameters( kprocesshackerFileName = PhConcatStrings2(PhApplicationDirectory->Buffer, L"\\kprocesshacker.sys"); - parameters.SecurityLevel = KphSecuritySignatureCheck; + parameters.SecurityLevel = KphSecurityPrivilegeCheck; parameters.CreateDynamicConfiguration = TRUE; status = KphInstallEx(KPH_DEVICE_SHORT_NAME, kprocesshackerFileName->Buffer, ¶meters); diff --git a/phlib/include/kphapi.h b/phlib/include/kphapi.h index f905de9a09d3..36d03742e9e9 100644 --- a/phlib/include/kphapi.h +++ b/phlib/include/kphapi.h @@ -114,7 +114,7 @@ typedef struct _ETWREG_BASIC_INFORMATION // Device -#define KPH_DEVICE_SHORT_NAME L"KProcessHacker3" +#define KPH_DEVICE_SHORT_NAME L"KProcessHacker2" #define KPH_DEVICE_TYPE 0x9999 #define KPH_DEVICE_NAME (L"\\Device\\" KPH_DEVICE_SHORT_NAME) @@ -124,8 +124,6 @@ typedef enum _KPH_SECURITY_LEVEL { KphSecurityNone = 0, // all clients are allowed KphSecurityPrivilegeCheck = 1, // require SeDebugPrivilege - KphSecuritySignatureCheck = 2, // require trusted signature - KphSecuritySignatureAndPrivilegeCheck = 3, // require trusted signature and SeDebugPrivilege KphMaxSecurityLevel } KPH_SECURITY_LEVEL, *PKPH_SECURITY_LEVEL; @@ -135,7 +133,7 @@ typedef struct _KPH_DYN_STRUCT_DATA SHORT EpObjectTable; SHORT Reserved0; SHORT Reserved1; - SHORT Reserved2; + SHORT EpRundownProtect; SHORT EreGuidEntry; SHORT HtHandleContentionEvent; SHORT OtName; @@ -154,7 +152,7 @@ typedef struct _KPH_DYN_PACKAGE KPH_DYN_STRUCT_DATA StructData; } KPH_DYN_PACKAGE, *PKPH_DYN_PACKAGE; -#define KPH_DYN_CONFIGURATION_VERSION 3 +#define KPH_DYN_CONFIGURATION_VERSION 2 #define KPH_DYN_MAXIMUM_PACKAGES 64 typedef struct _KPH_DYN_CONFIGURATION @@ -164,33 +162,6 @@ typedef struct _KPH_DYN_CONFIGURATION KPH_DYN_PACKAGE Packages[1]; } KPH_DYN_CONFIGURATION, *PKPH_DYN_CONFIGURATION; -// Verification - -#ifdef __BCRYPT_H__ -#define KPH_SIGN_ALGORITHM BCRYPT_ECDSA_P256_ALGORITHM -#define KPH_SIGN_ALGORITHM_BITS 256 -#define KPH_HASH_ALGORITHM BCRYPT_SHA256_ALGORITHM -#define KPH_BLOB_PUBLIC BCRYPT_ECCPUBLIC_BLOB -#endif - -#define KPH_SIGNATURE_MAX_SIZE (128 * 1024) // 128 kB - -typedef ULONG KPH_KEY, *PKPH_KEY; - -typedef enum _KPH_KEY_LEVEL -{ - KphKeyLevel1 = 1, - KphKeyLevel2 = 2 -} KPH_KEY_LEVEL; - -#define KPH_KEY_BACKOFF_TIME ((LONGLONG)(100 * 1000 * 10)) // 100ms - -#define KPH_PROCESS_READ_ACCESS (STANDARD_RIGHTS_READ | SYNCHRONIZE | PROCESS_QUERY_INFORMATION | \ - PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_VM_READ) -#define KPH_THREAD_READ_ACCESS (STANDARD_RIGHTS_READ | SYNCHRONIZE | THREAD_QUERY_INFORMATION | \ - THREAD_QUERY_LIMITED_INFORMATION | THREAD_GET_CONTEXT) -#define KPH_TOKEN_READ_ACCESS TOKEN_READ - // Features // No features defined. @@ -201,26 +172,24 @@ typedef enum _KPH_KEY_LEVEL // General #define KPH_GETFEATURES KPH_CTL_CODE(0) -#define KPH_VERIFYCLIENT KPH_CTL_CODE(1) -#define KPH_RETRIEVEKEY KPH_CTL_CODE(2) // User-mode only // Processes -#define KPH_OPENPROCESS KPH_CTL_CODE(50) // L1/L2 protected API -#define KPH_OPENPROCESSTOKEN KPH_CTL_CODE(51) // L1/L2 protected API +#define KPH_OPENPROCESS KPH_CTL_CODE(50) +#define KPH_OPENPROCESSTOKEN KPH_CTL_CODE(51) #define KPH_OPENPROCESSJOB KPH_CTL_CODE(52) -#define KPH_RESERVED53 KPH_CTL_CODE(53) -#define KPH_RESERVED54 KPH_CTL_CODE(54) -#define KPH_TERMINATEPROCESS KPH_CTL_CODE(55) // L2 protected API +#define KPH_SUSPENDPROCESS KPH_CTL_CODE(53) +#define KPH_RESUMEPROCESS KPH_CTL_CODE(54) +#define KPH_TERMINATEPROCESS KPH_CTL_CODE(55) #define KPH_RESERVED56 KPH_CTL_CODE(56) #define KPH_RESERVED57 KPH_CTL_CODE(57) -#define KPH_READVIRTUALMEMORYUNSAFE KPH_CTL_CODE(58) // L2 protected API +#define KPH_READVIRTUALMEMORYUNSAFE KPH_CTL_CODE(58) #define KPH_QUERYINFORMATIONPROCESS KPH_CTL_CODE(59) #define KPH_SETINFORMATIONPROCESS KPH_CTL_CODE(60) // Threads -#define KPH_OPENTHREAD KPH_CTL_CODE(100) // L1/L2 protected API +#define KPH_OPENTHREAD KPH_CTL_CODE(100) #define KPH_OPENTHREADPROCESS KPH_CTL_CODE(101) -#define KPH_RESERVED102 KPH_CTL_CODE(102) +#define KPH_TERMINATETHREAD KPH_CTL_CODE(102) #define KPH_RESERVED103 KPH_CTL_CODE(103) #define KPH_RESERVED104 KPH_CTL_CODE(104) #define KPH_RESERVED105 KPH_CTL_CODE(105) @@ -232,7 +201,7 @@ typedef enum _KPH_KEY_LEVEL #define KPH_ENUMERATEPROCESSHANDLES KPH_CTL_CODE(150) #define KPH_QUERYINFORMATIONOBJECT KPH_CTL_CODE(151) #define KPH_SETINFORMATIONOBJECT KPH_CTL_CODE(152) -#define KPH_RESERVED153 KPH_CTL_CODE(153) +#define KPH_DUPLICATEOBJECT KPH_CTL_CODE(153) // Misc. #define KPH_OPENDRIVER KPH_CTL_CODE(200) diff --git a/phlib/include/kphuser.h b/phlib/include/kphuser.h index 102534b55a62..a6905cb2f5ab 100644 --- a/phlib/include/kphuser.h +++ b/phlib/include/kphuser.h @@ -51,13 +51,6 @@ KphIsConnected( VOID ); -PHLIBAPI -BOOLEAN -NTAPI -KphIsVerified( - VOID - ); - PHLIBAPI NTSTATUS NTAPI @@ -97,14 +90,6 @@ KphGetFeatures( _Out_ PULONG Features ); -PHLIBAPI -NTSTATUS -NTAPI -KphVerifyClient( - _In_reads_bytes_(SignatureSize) PUCHAR Signature, - _In_ ULONG SignatureSize - ); - PHLIBAPI NTSTATUS NTAPI @@ -132,6 +117,20 @@ KphOpenProcessJob( _Out_ PHANDLE JobHandle ); +PHLIBAPI +NTSTATUS +NTAPI +KphSuspendProcess( + _In_ HANDLE ProcessHandle + ); + +PHLIBAPI +NTSTATUS +NTAPI +KphResumeProcess( + _In_ HANDLE ProcessHandle + ); + PHLIBAPI NTSTATUS NTAPI @@ -190,6 +189,14 @@ KphOpenThreadProcess( _Out_ PHANDLE ProcessHandle ); +PHLIBAPI +NTSTATUS +NTAPI +KphTerminateThread( + _In_ HANDLE ThreadHandle, + _In_ NTSTATUS ExitStatus + ); + PHLIBAPI NTSTATUS NTAPI @@ -264,12 +271,24 @@ KphSetInformationObject( _In_ ULONG ObjectInformationLength ); +PHLIBAPI +NTSTATUS +NTAPI +KphDuplicateObject( + _In_ HANDLE SourceProcessHandle, + _In_ HANDLE SourceHandle, + _In_opt_ HANDLE TargetProcessHandle, + _Out_opt_ PHANDLE TargetHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ ULONG HandleAttributes, + _In_ ULONG Options + ); + PHLIBAPI NTSTATUS NTAPI KphOpenDriver( _Out_ PHANDLE DriverHandle, - _In_ ACCESS_MASK DesiredAccess, _In_ POBJECT_ATTRIBUTES ObjectAttributes ); diff --git a/phlib/kph.c b/phlib/kph.c index 0acd7d0baa27..8311273e632e 100644 --- a/phlib/kph.c +++ b/phlib/kph.c @@ -22,11 +22,8 @@ #include #include -#include HANDLE PhKphHandle = NULL; -BOOLEAN PhKphVerified; -KPH_KEY PhKphL1Key; NTSTATUS KphConnect( _In_opt_ PWSTR DeviceName @@ -79,8 +76,6 @@ NTSTATUS KphConnect( ); PhKphHandle = kphHandle; - PhKphVerified = FALSE; - PhKphL1Key = 0; } return status; @@ -245,8 +240,6 @@ NTSTATUS KphDisconnect( status = NtClose(PhKphHandle); PhKphHandle = NULL; - PhKphVerified = FALSE; - PhKphL1Key = 0; return status; } @@ -258,52 +251,42 @@ BOOLEAN KphIsConnected( return PhKphHandle != NULL; } -BOOLEAN KphIsVerified( - VOID - ) -{ - return PhKphVerified; -} - NTSTATUS KphSetParameters( _In_opt_ PWSTR DeviceName, _In_ PKPH_PARAMETERS Parameters ) { + static PH_STRINGREF keyName = PH_STRINGREF_INIT(L"System\\CurrentControlSet\\Services\\kph2\\Parameters"); NTSTATUS status; HANDLE parametersKeyHandle = NULL; - PPH_STRING parametersKeyName; ULONG disposition; UNICODE_STRING valueName; - if (!DeviceName) - DeviceName = KPH_DEVICE_SHORT_NAME; - - parametersKeyName = PhConcatStrings( - 3, - L"System\\CurrentControlSet\\Services\\", - DeviceName, - L"\\Parameters" - ); - status = PhCreateKey( + if (!NT_SUCCESS(status = PhCreateKey( ¶metersKeyHandle, KEY_WRITE | DELETE, PH_KEY_LOCAL_MACHINE, - ¶metersKeyName->sr, + &keyName, 0, 0, &disposition - ); - PhDereferenceObject(parametersKeyName); - - if (!NT_SUCCESS(status)) + ))) + { return status; + } RtlInitUnicodeString(&valueName, L"SecurityLevel"); - status = NtSetValueKey(parametersKeyHandle, &valueName, 0, REG_DWORD, &Parameters->SecurityLevel, sizeof(ULONG)); - - if (!NT_SUCCESS(status)) + if (!NT_SUCCESS(status = NtSetValueKey( + parametersKeyHandle, + &valueName, + 0, + REG_DWORD, + &Parameters->SecurityLevel, + sizeof(ULONG) + ))) + { goto SetValuesEnd; + } if (Parameters->CreateDynamicConfiguration) { @@ -316,10 +299,14 @@ NTSTATUS KphSetParameters( if (NT_SUCCESS(KphInitializeDynamicPackage(&configuration.Packages[0]))) { - status = NtSetValueKey(parametersKeyHandle, &valueName, 0, REG_BINARY, &configuration, sizeof(KPH_DYN_CONFIGURATION)); - - if (!NT_SUCCESS(status)) - goto SetValuesEnd; + status = NtSetValueKey( + parametersKeyHandle, + &valueName, + 0, + REG_BINARY, + &configuration, + sizeof(KPH_DYN_CONFIGURATION) + ); } } @@ -449,6 +436,28 @@ NTSTATUS KphUninstall( return status; } +NTSTATUS KphpDeviceIoControl( + _In_ ULONG KphControlCode, + _In_ PVOID InBuffer, + _In_ ULONG InBufferLength + ) +{ + IO_STATUS_BLOCK isb; + + return NtDeviceIoControlFile( + PhKphHandle, + NULL, + NULL, + NULL, + &isb, + KphControlCode, + InBuffer, + InBufferLength, + NULL, + 0 + ); +} + NTSTATUS KphGetFeatures( _Out_ PULONG Features ) @@ -465,52 +474,24 @@ NTSTATUS KphGetFeatures( ); } -NTSTATUS KphVerifyClient( - _In_reads_bytes_(SignatureSize) PUCHAR Signature, - _In_ ULONG SignatureSize +NTSTATUS KphOpenProcess( + _Out_ PHANDLE ProcessHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ PCLIENT_ID ClientId ) { - NTSTATUS status; struct { - PVOID CodeAddress; - PUCHAR Signature; - ULONG SignatureSize; - } input = { KphpWithKeyApcRoutine, Signature, SignatureSize }; + PHANDLE ProcessHandle; + ACCESS_MASK DesiredAccess; + PCLIENT_ID ClientId; + } input = { ProcessHandle, DesiredAccess, ClientId }; - status = KphpDeviceIoControl( - KPH_VERIFYCLIENT, + return KphpDeviceIoControl( + KPH_OPENPROCESS, &input, sizeof(input) ); - - if (NT_SUCCESS(status)) - PhKphVerified = TRUE; - - return status; -} - -NTSTATUS KphOpenProcess( - _Out_ PHANDLE ProcessHandle, - _In_ ACCESS_MASK DesiredAccess, - _In_ PCLIENT_ID ClientId - ) -{ - KPH_OPEN_PROCESS_INPUT input = { ProcessHandle, DesiredAccess, ClientId, 0 }; - - if ((DesiredAccess & KPH_PROCESS_READ_ACCESS) == DesiredAccess) - { - KphpGetL1Key(&input.Key); - return KphpDeviceIoControl( - KPH_OPENPROCESS, - &input, - sizeof(input) - ); - } - else - { - return KphpWithKey(KphKeyLevel2, KphpOpenProcessContinuation, &input); - } } NTSTATUS KphOpenProcessToken( @@ -519,21 +500,18 @@ NTSTATUS KphOpenProcessToken( _Out_ PHANDLE TokenHandle ) { - KPH_OPEN_PROCESS_TOKEN_INPUT input = { ProcessHandle, DesiredAccess, TokenHandle, 0 }; - - if ((DesiredAccess & KPH_TOKEN_READ_ACCESS) == DesiredAccess) - { - KphpGetL1Key(&input.Key); - return KphpDeviceIoControl( - KPH_OPENPROCESSTOKEN, - &input, - sizeof(input) - ); - } - else + struct { - return KphpWithKey(KphKeyLevel2, KphpOpenProcessTokenContinuation, &input); - } + HANDLE ProcessHandle; + ACCESS_MASK DesiredAccess; + PHANDLE TokenHandle; + } input = { ProcessHandle, DesiredAccess, TokenHandle }; + + return KphpDeviceIoControl( + KPH_OPENPROCESSTOKEN, + &input, + sizeof(input) + ); } NTSTATUS KphOpenProcessJob( @@ -562,11 +540,20 @@ NTSTATUS KphTerminateProcess( ) { NTSTATUS status; - KPH_TERMINATE_PROCESS_INPUT input = { ProcessHandle, ExitStatus, 0 }; + struct + { + HANDLE ProcessHandle; + NTSTATUS ExitStatus; + } input = { ProcessHandle, ExitStatus }; - status = KphpWithKey(KphKeyLevel2, KphpTerminateProcessContinuation, &input); + status = KphpDeviceIoControl( + KPH_TERMINATEPROCESS, + &input, + sizeof(input) + ); - // Check if we're trying to terminate the current process, because kernel-mode can't do it. + // Check if we're trying to terminate the current process, + // because kernel-mode can't do it. if (status == STATUS_CANT_TERMINATE_SELF) { RtlExitUserProcess(ExitStatus); @@ -583,9 +570,20 @@ NTSTATUS KphReadVirtualMemoryUnsafe( _Out_opt_ PSIZE_T NumberOfBytesRead ) { - KPH_READ_VIRTUAL_MEMORY_UNSAFE_INPUT input = { ProcessHandle, BaseAddress, Buffer, BufferSize, NumberOfBytesRead, 0 }; + struct + { + HANDLE ProcessHandle; + PVOID BaseAddress; + PVOID Buffer; + SIZE_T BufferSize; + PSIZE_T NumberOfBytesRead; + } input = { ProcessHandle, BaseAddress, Buffer, BufferSize, NumberOfBytesRead }; - return KphpWithKey(KphKeyLevel2, KphpReadVirtualMemoryUnsafeContinuation, &input); + return KphpDeviceIoControl( + KPH_READVIRTUALMEMORYUNSAFE, + &input, + sizeof(input) + ); } NTSTATUS KphQueryInformationProcess( @@ -640,21 +638,18 @@ NTSTATUS KphOpenThread( _In_ PCLIENT_ID ClientId ) { - KPH_OPEN_THREAD_INPUT input = { ThreadHandle, DesiredAccess, ClientId, 0 }; - - if ((DesiredAccess & KPH_THREAD_READ_ACCESS) == DesiredAccess) - { - KphpGetL1Key(&input.Key); - return KphpDeviceIoControl( - KPH_OPENTHREAD, - &input, - sizeof(input) - ); - } - else + struct { - return KphpWithKey(KphKeyLevel2, KphpOpenThreadContinuation, &input); - } + PHANDLE ThreadHandle; + ACCESS_MASK DesiredAccess; + PCLIENT_ID ClientId; + } input = { ThreadHandle, DesiredAccess, ClientId }; + + return KphpDeviceIoControl( + KPH_OPENTHREAD, + &input, + sizeof(input) + ); } NTSTATUS KphOpenThreadProcess( @@ -865,16 +860,14 @@ NTSTATUS KphSetInformationObject( NTSTATUS KphOpenDriver( _Out_ PHANDLE DriverHandle, - _In_ ACCESS_MASK DesiredAccess, _In_ POBJECT_ATTRIBUTES ObjectAttributes ) { struct { PHANDLE DriverHandle; - ACCESS_MASK DesiredAccess; POBJECT_ATTRIBUTES ObjectAttributes; - } input = { DriverHandle, DesiredAccess, ObjectAttributes }; + } input = { DriverHandle, ObjectAttributes }; return KphpDeviceIoControl( KPH_OPENDRIVER, @@ -905,198 +898,4 @@ NTSTATUS KphQueryInformationDriver( &input, sizeof(input) ); -} - -NTSTATUS KphpDeviceIoControl( - _In_ ULONG KphControlCode, - _In_ PVOID InBuffer, - _In_ ULONG InBufferLength - ) -{ - IO_STATUS_BLOCK iosb; - - return NtDeviceIoControlFile( - PhKphHandle, - NULL, - NULL, - NULL, - &iosb, - KphControlCode, - InBuffer, - InBufferLength, - NULL, - 0 - ); -} - -VOID KphpWithKeyApcRoutine( - _In_ PVOID ApcContext, - _In_ PIO_STATUS_BLOCK IoStatusBlock, - _In_ ULONG Reserved - ) -{ - PKPHP_RETRIEVE_KEY_CONTEXT context = CONTAINING_RECORD(IoStatusBlock, KPHP_RETRIEVE_KEY_CONTEXT, Iosb); - KPH_KEY key = PtrToUlong(ApcContext); - - if (context->Continuation != KphpGetL1KeyContinuation && - context->Continuation != KphpOpenProcessContinuation && - context->Continuation != KphpOpenProcessTokenContinuation && - context->Continuation != KphpTerminateProcessContinuation && - context->Continuation != KphpReadVirtualMemoryUnsafeContinuation && - context->Continuation != KphpOpenThreadContinuation) - { - PhRaiseStatus(STATUS_ACCESS_DENIED); - context->Status = STATUS_ACCESS_DENIED; - return; - } - - context->Status = context->Continuation(key, context->Context); -} - -NTSTATUS KphpWithKey( - _In_ KPH_KEY_LEVEL KeyLevel, - _In_ PKPHP_WITH_KEY_CONTINUATION Continuation, - _In_ PVOID Context - ) -{ - NTSTATUS status; - struct - { - KPH_KEY_LEVEL KeyLevel; - } input = { KeyLevel }; - KPHP_RETRIEVE_KEY_CONTEXT context; - - context.Continuation = Continuation; - context.Context = Context; - context.Status = STATUS_UNSUCCESSFUL; - - status = NtDeviceIoControlFile( - PhKphHandle, - NULL, - KphpWithKeyApcRoutine, - NULL, - &context.Iosb, - KPH_RETRIEVEKEY, - &input, - sizeof(input), - NULL, - 0 - ); - - NtTestAlert(); - - if (!NT_SUCCESS(status)) - return status; - - return context.Status; -} - -NTSTATUS KphpGetL1KeyContinuation( - _In_ KPH_KEY Key, - _In_ PVOID Context - ) -{ - PKPHP_GET_L1_KEY_CONTEXT context = Context; - - *context->Key = Key; - PhKphL1Key = Key; - - return STATUS_SUCCESS; -} - -NTSTATUS KphpGetL1Key( - _Out_ PKPH_KEY Key - ) -{ - KPHP_GET_L1_KEY_CONTEXT context; - - if (PhKphL1Key) - { - *Key = PhKphL1Key; - return STATUS_SUCCESS; - } - - context.Key = Key; - - return KphpWithKey(KphKeyLevel1, KphpGetL1KeyContinuation, &context); -} - -NTSTATUS KphpOpenProcessContinuation( - _In_ KPH_KEY Key, - _In_ PVOID Context - ) -{ - PKPH_OPEN_PROCESS_INPUT input = Context; - - input->Key = Key; - - return KphpDeviceIoControl( - KPH_OPENPROCESS, - input, - sizeof(*input) - ); -} - -NTSTATUS KphpOpenProcessTokenContinuation( - _In_ KPH_KEY Key, - _In_ PVOID Context - ) -{ - PKPH_OPEN_PROCESS_TOKEN_INPUT input = Context; - - input->Key = Key; - - return KphpDeviceIoControl( - KPH_OPENPROCESSTOKEN, - input, - sizeof(*input) - ); -} - -NTSTATUS KphpTerminateProcessContinuation( - _In_ KPH_KEY Key, - _In_ PVOID Context - ) -{ - PKPH_TERMINATE_PROCESS_INPUT input = Context; - - input->Key = Key; - - return KphpDeviceIoControl( - KPH_TERMINATEPROCESS, - input, - sizeof(*input) - ); -} - -NTSTATUS KphpReadVirtualMemoryUnsafeContinuation( - _In_ KPH_KEY Key, - _In_ PVOID Context - ) -{ - PKPH_READ_VIRTUAL_MEMORY_UNSAFE_INPUT input = Context; - - input->Key = Key; - - return KphpDeviceIoControl( - KPH_READVIRTUALMEMORYUNSAFE, - input, - sizeof(*input) - ); -} - -NTSTATUS KphpOpenThreadContinuation( - _In_ KPH_KEY Key, - _In_ PVOID Context - ) -{ - PKPH_OPEN_PROCESS_INPUT input = Context; - - input->Key = Key; - - return KphpDeviceIoControl( - KPH_OPENTHREAD, - input, - sizeof(*input) - ); -} +} \ No newline at end of file diff --git a/phlib/native.c b/phlib/native.c index d00fdb099868..236d5a8a23c1 100644 --- a/phlib/native.c +++ b/phlib/native.c @@ -116,16 +116,15 @@ NTSTATUS PhOpenProcess( _In_ HANDLE ProcessId ) { - NTSTATUS status; OBJECT_ATTRIBUTES objectAttributes; CLIENT_ID clientId; clientId.UniqueProcess = ProcessId; clientId.UniqueThread = NULL; - if (KphIsVerified() && (DesiredAccess & KPH_PROCESS_READ_ACCESS) == DesiredAccess) + if (KphIsConnected()) { - status = KphOpenProcess( + return KphOpenProcess( ProcessHandle, DesiredAccess, &clientId @@ -134,24 +133,14 @@ NTSTATUS PhOpenProcess( else { InitializeObjectAttributes(&objectAttributes, NULL, 0, NULL, NULL); - status = NtOpenProcess( + + return NtOpenProcess( ProcessHandle, DesiredAccess, &objectAttributes, &clientId ); - - if (status == STATUS_ACCESS_DENIED && KphIsVerified()) - { - status = KphOpenProcess( - ProcessHandle, - DesiredAccess, - &clientId - ); - } } - - return status; } /** Limited API for untrusted/external code. */ @@ -189,16 +178,15 @@ NTSTATUS PhOpenThread( _In_ HANDLE ThreadId ) { - NTSTATUS status; OBJECT_ATTRIBUTES objectAttributes; CLIENT_ID clientId; clientId.UniqueProcess = NULL; clientId.UniqueThread = ThreadId; - if (KphIsVerified() && (DesiredAccess & KPH_THREAD_READ_ACCESS) == DesiredAccess) + if (KphIsConnected()) { - status = KphOpenThread( + return KphOpenThread( ThreadHandle, DesiredAccess, &clientId @@ -207,24 +195,14 @@ NTSTATUS PhOpenThread( else { InitializeObjectAttributes(&objectAttributes, NULL, 0, NULL, NULL); - status = NtOpenThread( + + return NtOpenThread( ThreadHandle, DesiredAccess, &objectAttributes, &clientId ); - - if (status == STATUS_ACCESS_DENIED && KphIsVerified()) - { - status = KphOpenThread( - ThreadHandle, - DesiredAccess, - &clientId - ); - } } - - return status; } /** Limited API for untrusted/external code. */ @@ -296,11 +274,9 @@ NTSTATUS PhOpenProcessToken( _Out_ PHANDLE TokenHandle ) { - NTSTATUS status; - - if (KphIsVerified() && (DesiredAccess & KPH_TOKEN_READ_ACCESS) == DesiredAccess) + if (KphIsConnected()) { - status = KphOpenProcessToken( + return KphOpenProcessToken( ProcessHandle, DesiredAccess, TokenHandle @@ -308,23 +284,12 @@ NTSTATUS PhOpenProcessToken( } else { - status = NtOpenProcessToken( + return NtOpenProcessToken( ProcessHandle, DesiredAccess, TokenHandle ); - - if (status == STATUS_ACCESS_DENIED && KphIsVerified()) - { - status = KphOpenProcessToken( - ProcessHandle, - DesiredAccess, - TokenHandle - ); - } } - - return status; } NTSTATUS PhGetObjectSecurity( @@ -403,7 +368,7 @@ NTSTATUS PhTerminateProcess( { NTSTATUS status; - if (KphIsVerified()) + if (KphIsConnected()) { status = KphTerminateProcess( ProcessHandle, @@ -2583,7 +2548,7 @@ BOOLEAN NTAPI PhpOpenDriverByBaseAddressCallback( NULL ); - status = KphOpenDriver(&driverHandle, SYNCHRONIZE, &objectAttributes); + status = KphOpenDriver(&driverHandle, &objectAttributes); PhDereferenceObject(driverName); if (!NT_SUCCESS(status)) diff --git a/phlib/phlib.vcxproj b/phlib/phlib.vcxproj index e395b2239ea8..042c17ad6cc6 100644 --- a/phlib/phlib.vcxproj +++ b/phlib/phlib.vcxproj @@ -1,4 +1,4 @@ - + @@ -202,7 +202,6 @@ - diff --git a/phlib/phlib.vcxproj.filters b/phlib/phlib.vcxproj.filters index dee92e1b386b..cfd2a295a596 100644 --- a/phlib/phlib.vcxproj.filters +++ b/phlib/phlib.vcxproj.filters @@ -346,9 +346,6 @@ Header Files - - Header Files - Header Files From 0ae8713d7cf455fa97e4292896169b911431bc33 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 29 May 2017 19:48:18 +1000 Subject: [PATCH 0178/2058] Update gitattributes --- .gitattributes | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitattributes b/.gitattributes index b895d0391026..ba1245642f8e 100644 --- a/.gitattributes +++ b/.gitattributes @@ -12,11 +12,13 @@ # Project files *.bat eol=crlf *.c eol=crlf +*.cs eol=crlf *.config eol=crlf *.cmd eol=crlf *.csproj eol=crlf *.h eol=crlf *.manifest eol=crlf +*.resx eol=crlf *.rc eol=crlf *.sln eol=crlf *.txt eol=crlf From 1a3b2fbe9e506ec5ac92462ae140d011c14ea323 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 30 May 2017 07:33:28 +1000 Subject: [PATCH 0179/2058] Fix sdk postbuild --- ProcessHacker/ProcessHacker.vcxproj | 6 +++++ tools/CustomBuildTool/Source Files/Build.cs | 24 +++++++++--------- tools/CustomBuildTool/Source Files/Program.cs | 20 +++++++++------ .../bin/Release/CustomBuildTool.exe | Bin 160768 -> 160768 bytes .../bin/Release/CustomBuildTool.pdb | Bin 69120 -> 69120 bytes 5 files changed, 30 insertions(+), 20 deletions(-) diff --git a/ProcessHacker/ProcessHacker.vcxproj b/ProcessHacker/ProcessHacker.vcxproj index 03188043fdab..2220ef6efe98 100644 --- a/ProcessHacker/ProcessHacker.vcxproj +++ b/ProcessHacker/ProcessHacker.vcxproj @@ -178,6 +178,9 @@ _UNICODE;UNICODE;%(PreprocessorDefinitions);$(ExternalCompilerOptions) $(SolutionDir)phnt\include;$(SolutionDir)phlib\include;include;%(AdditionalIncludeDirectories) + + $(SolutionDir)build\build_sdk.cmd + @@ -212,6 +215,9 @@ _UNICODE;UNICODE;%(PreprocessorDefinitions);$(ExternalCompilerOptions) $(SolutionDir)phnt\include;$(SolutionDir)phlib\include;include;%(AdditionalIncludeDirectories) + + $(SolutionDir)build\build_sdk.cmd + diff --git a/tools/CustomBuildTool/Source Files/Build.cs b/tools/CustomBuildTool/Source Files/Build.cs index 8c08ea46f01b..48b75f1d9eec 100644 --- a/tools/CustomBuildTool/Source Files/Build.cs +++ b/tools/CustomBuildTool/Source Files/Build.cs @@ -529,26 +529,26 @@ public static bool BuildPublicHeaderFiles() return true; } - public static bool CopyKProcessHacker(bool DebugBuild) + public static bool CopyKProcessHacker(BuildFlags Flags) { - Program.PrintColorMessage("Copying KPH driver...", ConsoleColor.Cyan); + Program.PrintColorMessage("Copying KPH driver...", ConsoleColor.Cyan, true, Flags); if (!File.Exists(CustomSignToolPath)) return true; if (!File.Exists("build\\kph.key")) return true; - if (DebugBuild) + if (Flags.HasFlag(BuildFlags.BuildDebug)) { if (!File.Exists("bin\\Debug32\\ProcessHacker.exe")) { - Program.PrintColorMessage("[SKIPPED] Debug32\\ProcessHacker.exe not found.", ConsoleColor.Yellow); + Program.PrintColorMessage("[SKIPPED] Debug32\\ProcessHacker.exe not found.", ConsoleColor.Yellow, true, Flags); return true; } if (!File.Exists("bin\\Debug64\\ProcessHacker.exe")) { - Program.PrintColorMessage("[SKIPPED] Debug64\\ProcessHacker.exe not found.", ConsoleColor.Yellow); + Program.PrintColorMessage("[SKIPPED] Debug64\\ProcessHacker.exe not found.", ConsoleColor.Yellow, true, Flags); return true; } @@ -563,14 +563,14 @@ public static bool CopyKProcessHacker(bool DebugBuild) string output = Win32.ShellExecute(CustomSignToolPath, "sign -k build\\kph.key bin\\Debug32\\ProcessHacker.exe -s bin\\Debug32\\ProcessHacker.sig"); if (!string.IsNullOrEmpty(output)) { - Program.PrintColorMessage("[WARN] (Debug32) " + output, ConsoleColor.Yellow); + Program.PrintColorMessage("[WARN] (Debug32) " + output, ConsoleColor.Yellow, true, Flags); return false; } output = Win32.ShellExecute(CustomSignToolPath, "sign -k build\\kph.key bin\\Debug64\\ProcessHacker.exe -s bin\\Debug64\\ProcessHacker.sig"); if (!string.IsNullOrEmpty(output)) { - Program.PrintColorMessage("[WARN] (Debug64) " + output, ConsoleColor.Yellow); + Program.PrintColorMessage("[WARN] (Debug64) " + output, ConsoleColor.Yellow, true, Flags); return false; } } @@ -578,13 +578,13 @@ public static bool CopyKProcessHacker(bool DebugBuild) { if (!File.Exists("bin\\Release32\\ProcessHacker.exe")) { - Program.PrintColorMessage("[SKIPPED] Release32\\ProcessHacker.exe not found.", ConsoleColor.Yellow); + Program.PrintColorMessage("[SKIPPED] Release32\\ProcessHacker.exe not found.", ConsoleColor.Yellow, true, Flags); return true; } if (!File.Exists("bin\\Release64\\ProcessHacker.exe")) { - Program.PrintColorMessage("[SKIPPED] Release64\\ProcessHacker.exe not found.", ConsoleColor.Yellow); + Program.PrintColorMessage("[SKIPPED] Release64\\ProcessHacker.exe not found.", ConsoleColor.Yellow, true, Flags); return true; } @@ -599,21 +599,21 @@ public static bool CopyKProcessHacker(bool DebugBuild) string output = Win32.ShellExecute(CustomSignToolPath, "sign -k build\\kph.key bin\\Release32\\ProcessHacker.exe -s bin\\Release32\\ProcessHacker.sig"); if (!string.IsNullOrEmpty(output)) { - Program.PrintColorMessage("[ERROR] (Release32) " + output, ConsoleColor.Red); + Program.PrintColorMessage("[ERROR] (Release32) " + output, ConsoleColor.Red, true, Flags); return false; } output = Win32.ShellExecute(CustomSignToolPath, "sign -k build\\kph.key bin\\Release64\\ProcessHacker.exe -s bin\\Release64\\ProcessHacker.sig"); if (!string.IsNullOrEmpty(output)) { - Program.PrintColorMessage("[ERROR] (Release64) " + output, ConsoleColor.Red); + Program.PrintColorMessage("[ERROR] (Release64) " + output, ConsoleColor.Red, true, Flags); return false; } } try { - if (DebugBuild) + if (Flags.HasFlag(BuildFlags.BuildDebug)) { Win32.CopyIfNewer( "KProcessHacker\\bin-signed\\i386\\kprocesshacker.sys", diff --git a/tools/CustomBuildTool/Source Files/Program.cs b/tools/CustomBuildTool/Source Files/Program.cs index f123314e63a1..2633a5abf563 100644 --- a/tools/CustomBuildTool/Source Files/Program.cs +++ b/tools/CustomBuildTool/Source Files/Program.cs @@ -86,15 +86,16 @@ public static void Main(string[] args) Build.ShowBuildStats(); } - else if (ProgramArgs.ContainsKey("-sign")) - { - Build.CopyKProcessHacker(false); - } else if (ProgramArgs.ContainsKey("-sdk")) { if (!Build.InitializeBuildEnvironment(false)) return; + Build.CopyKProcessHacker( + BuildFlags.Build32bit | BuildFlags.Build64bit | + BuildFlags.BuildDebug + ); + BuildSdk( BuildFlags.Build32bit | BuildFlags.Build64bit | BuildFlags.BuildDebug | BuildFlags.BuildVerbose @@ -129,7 +130,8 @@ public static void Main(string[] args) BuildFlags.Build32bit | BuildFlags.Build64bit | BuildFlags.BuildVerbose)) return; - if (!Build.CopyKProcessHacker(false)) + if (!Build.CopyKProcessHacker( + BuildFlags.Build32bit | BuildFlags.Build64bit | BuildFlags.BuildVerbose)) return; if (!BuildSdk(BuildFlags.Build32bit | BuildFlags.Build64bit | BuildFlags.BuildVerbose)) @@ -160,7 +162,9 @@ public static void Main(string[] args) BuildFlags.BuildDebug | BuildFlags.BuildVerbose)) return; - if (!Build.CopyKProcessHacker(true)) + if (!Build.CopyKProcessHacker( + BuildFlags.Build32bit | BuildFlags.Build64bit | + BuildFlags.BuildDebug | BuildFlags.BuildVerbose)) return; if (!BuildSdk( @@ -196,7 +200,7 @@ public static void Main(string[] args) BuildFlags.Build32bit | BuildFlags.Build64bit | BuildFlags.BuildVerbose)) return; - if (!Build.CopyKProcessHacker(false)) + if (!Build.CopyKProcessHacker(BuildFlags.Build32bit | BuildFlags.Build64bit | BuildFlags.BuildVerbose)) return; if (!BuildSdk(BuildFlags.Build32bit | BuildFlags.Build64bit | BuildFlags.BuildVerbose)) @@ -270,7 +274,7 @@ public static void Main(string[] args) BuildFlags.Build32bit | BuildFlags.Build64bit | BuildFlags.BuildVerbose)) return; - if (!Build.CopyKProcessHacker(false)) + if (!Build.CopyKProcessHacker(BuildFlags.Build32bit | BuildFlags.Build64bit | BuildFlags.BuildVerbose)) return; if (!BuildSdk(BuildFlags.Build32bit | BuildFlags.Build64bit | BuildFlags.BuildVerbose)) diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe b/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe index 402eed5c4938f85546126704a750ea62597dce88..fb97a2ee1ecc1d7046c6727053448910267db157 100644 GIT binary patch delta 7515 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

    oF#)=Hbwc& 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 K;O9tAvi}E5>yOp| delta 8601 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 Date: Tue, 30 May 2017 07:34:26 +1000 Subject: [PATCH 0180/2058] WindowExplorer: reset default settings --- plugins/WindowExplorer/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/WindowExplorer/main.c b/plugins/WindowExplorer/main.c index c31834ae619d..293fddfb2e29 100644 --- a/plugins/WindowExplorer/main.c +++ b/plugins/WindowExplorer/main.c @@ -223,7 +223,7 @@ LOGICAL DllMain( PPH_PLUGIN_INFORMATION info; PH_SETTING_CREATE settings[] = { - { IntegerSettingType, SETTING_NAME_SHOW_DESKTOP_WINDOWS, L"1" }, + { IntegerSettingType, SETTING_NAME_SHOW_DESKTOP_WINDOWS, L"0" }, { StringSettingType, SETTING_NAME_WINDOW_TREE_LIST_COLUMNS, L"" }, { IntegerPairSettingType, SETTING_NAME_WINDOWS_WINDOW_POSITION, L"100,100" }, { ScalableIntegerPairSettingType, SETTING_NAME_WINDOWS_WINDOW_SIZE, L"@96|690,540" } From ec0e81656ec7c11939c03bca3aca54df2a3adedd Mon Sep 17 00:00:00 2001 From: Steven G Date: Tue, 30 May 2017 07:40:33 +1000 Subject: [PATCH 0181/2058] Add module filter options, Add modules tab search support (#143) * Add modules tab search support * Update search keywords * Update options text --- ProcessHacker/ProcessHacker.rc | 30 +-- ProcessHacker/include/modlist.h | 32 +++- ProcessHacker/include/procprpp.h | 4 + ProcessHacker/modlist.c | 57 +++++- ProcessHacker/prpghndl.c | 3 + ProcessHacker/prpgmod.c | 306 ++++++++++++++++++++++++++++++- ProcessHacker/resource.h | 5 +- ProcessHacker/settings.c | 1 + 8 files changed, 416 insertions(+), 22 deletions(-) diff --git a/ProcessHacker/ProcessHacker.rc b/ProcessHacker/ProcessHacker.rc index 4f52ab152a7d..3df2a8103555 100644 --- a/ProcessHacker/ProcessHacker.rc +++ b/ProcessHacker/ProcessHacker.rc @@ -560,7 +560,9 @@ STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSM CAPTION "Modules" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN - CONTROL "",IDC_LIST,"PhTreeNew",WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP | 0xa,7,7,246,246,WS_EX_CLIENTEDGE + CONTROL "",IDC_LIST,"PhTreeNew",WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP | 0xa,2,19,256,239,WS_EX_CLIENTEDGE + EDITTEXT IDC_SEARCH,114,3,144,14,ES_AUTOHSCROLL + PUSHBUTTON "Options",IDC_FILTEROPTIONS,2,2,50,14 END IDD_PROCTHREADS DIALOGEX 0, 0, 260, 260 @@ -1130,10 +1132,10 @@ STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSM CAPTION "Memory" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN - PUSHBUTTON "Strings...",IDC_STRINGS,150,7,50,14 - PUSHBUTTON "Refresh",IDC_REFRESH,203,7,50,14 - CONTROL "",IDC_LIST,"PhTreeNew",WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP | 0xa,7,26,246,227,WS_EX_CLIENTEDGE - CONTROL "Hide free regions",IDC_HIDEFREEREGIONS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,9,71,10 + PUSHBUTTON "Strings...",IDC_STRINGS,155,2,50,14 + PUSHBUTTON "Refresh",IDC_REFRESH,208,2,50,14 + CONTROL "",IDC_LIST,"PhTreeNew",WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP | 0xa,2,19,256,239,WS_EX_CLIENTEDGE + CONTROL "Hide free regions",IDC_HIDEFREEREGIONS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,3,5,71,10 END IDD_CHOOSE DIALOGEX 0, 0, 199, 73 @@ -1940,10 +1942,10 @@ BEGIN IDD_PROCMODULES, DIALOG BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 253 - TOPMARGIN, 7 - BOTTOMMARGIN, 253 + LEFTMARGIN, 2 + RIGHTMARGIN, 258 + TOPMARGIN, 2 + BOTTOMMARGIN, 258 END IDD_PROCTHREADS, DIALOG @@ -1958,7 +1960,7 @@ BEGIN BEGIN LEFTMARGIN, 2 RIGHTMARGIN, 258 - TOPMARGIN, 3 + TOPMARGIN, 2 BOTTOMMARGIN, 258 END @@ -2176,10 +2178,10 @@ BEGIN IDD_PROCMEMORY, DIALOG BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 253 - TOPMARGIN, 7 - BOTTOMMARGIN, 253 + LEFTMARGIN, 2 + RIGHTMARGIN, 258 + TOPMARGIN, 2 + BOTTOMMARGIN, 258 END IDD_CHOOSE, DIALOG diff --git a/ProcessHacker/include/modlist.h b/ProcessHacker/include/modlist.h index d665a6564a06..099cf56fd4e3 100644 --- a/ProcessHacker/include/modlist.h +++ b/ProcessHacker/include/modlist.h @@ -55,18 +55,36 @@ typedef struct _PH_MODULE_NODE } PH_MODULE_NODE, *PPH_MODULE_NODE; // end_phapppub +#define PH_MODULE_FLAGS_DYNAMIC_OPTION 1 +#define PH_MODULE_FLAGS_MAPPED_OPTION 2 +#define PH_MODULE_FLAGS_STATIC_OPTION 3 +#define PH_MODULE_FLAGS_SIGNED_OPTION 4 + typedef struct _PH_MODULE_LIST_CONTEXT { HWND ParentWindowHandle; HWND TreeNewHandle; ULONG TreeNewSortColumn; + PH_TN_FILTER_SUPPORT TreeFilterSupport; PH_SORT_ORDER TreeNewSortOrder; PH_CM_MANAGER Cm; + union + { + ULONG Flags; + struct + { + ULONG EnableStateHighlighting : 1; + ULONG HideDynamicModules : 1; + ULONG HideMappedModules : 1; + ULONG HideSignedModules : 1; + ULONG HideStaticModules : 1; + ULONG Spare : 27; + }; + }; + PPH_HASHTABLE NodeHashtable; PPH_LIST NodeList; - - BOOLEAN EnableStateHighlighting; PPH_POINTER_LIST NodeStateList; HFONT BoldFont; @@ -90,6 +108,11 @@ VOID PhSaveSettingsModuleList( _Inout_ PPH_MODULE_LIST_CONTEXT Context ); +VOID PhSetOptionsModuleList( + _Inout_ PPH_MODULE_LIST_CONTEXT Context, + _In_ ULONG Options + ); + PPH_MODULE_NODE PhAddModuleNode( _Inout_ PPH_MODULE_LIST_CONTEXT Context, _In_ PPH_MODULE_ITEM ModuleItem, @@ -111,6 +134,11 @@ VOID PhUpdateModuleNode( _In_ PPH_MODULE_NODE ModuleNode ); +VOID PhExpandAllModuleNodes( + _In_ PPH_MODULE_LIST_CONTEXT Context, + _In_ BOOLEAN Expand + ); + VOID PhTickModuleNodes( _In_ PPH_MODULE_LIST_CONTEXT Context ); diff --git a/ProcessHacker/include/procprpp.h b/ProcessHacker/include/procprpp.h index 3d5538b7d97b..e0976375888c 100644 --- a/ProcessHacker/include/procprpp.h +++ b/ProcessHacker/include/procprpp.h @@ -224,6 +224,7 @@ typedef struct _PH_MODULES_CONTEXT PH_CALLBACK_REGISTRATION UpdatedEventRegistration; HWND WindowHandle; + HWND SearchboxHandle; // end_phapppub union @@ -238,6 +239,9 @@ typedef struct _PH_MODULES_CONTEXT PH_PROVIDER_EVENT_QUEUE EventQueue; NTSTATUS LastRunStatus; PPH_STRING ErrorMessage; + + PPH_STRING SearchboxText; + PPH_TN_FILTER_ENTRY FilterEntry; // begin_phapppub } PH_MODULES_CONTEXT, *PPH_MODULES_CONTEXT; // end_phapppub diff --git a/ProcessHacker/modlist.c b/ProcessHacker/modlist.c index 93704252428f..69ed34407c4d 100644 --- a/ProcessHacker/modlist.c +++ b/ProcessHacker/modlist.c @@ -121,6 +121,8 @@ VOID PhInitializeModuleList( TreeNew_SetSort(hwnd, 0, NoSortOrder); PhCmInitializeManager(&Context->Cm, hwnd, PHMOTLC_MAXIMUM, PhpModuleTreeNewPostSortFunction); + + PhInitializeTreeNewFilterSupport(&Context->TreeFilterSupport, hwnd, Context->NodeList); } VOID PhDeleteModuleList( @@ -187,6 +189,28 @@ VOID PhSaveSettingsModuleList( PhDereferenceObject(sortSettings); } +VOID PhSetOptionsModuleList( + _Inout_ PPH_MODULE_LIST_CONTEXT Context, + _In_ ULONG Options + ) +{ + switch (Options) + { + case PH_MODULE_FLAGS_DYNAMIC_OPTION: + Context->HideDynamicModules = !Context->HideDynamicModules; + break; + case PH_MODULE_FLAGS_MAPPED_OPTION: + Context->HideMappedModules = !Context->HideMappedModules; + break; + case PH_MODULE_FLAGS_STATIC_OPTION: + Context->HideStaticModules = !Context->HideStaticModules; + break; + case PH_MODULE_FLAGS_SIGNED_OPTION: + Context->HideSignedModules = !Context->HideSignedModules; + break; + } +} + PPH_MODULE_NODE PhAddModuleNode( _Inout_ PPH_MODULE_LIST_CONTEXT Context, _In_ PPH_MODULE_ITEM ModuleItem, @@ -221,6 +245,9 @@ PPH_MODULE_NODE PhAddModuleNode( PhAddEntryHashtable(Context->NodeHashtable, &moduleNode); PhAddItemList(Context->NodeList, moduleNode); + if (Context->TreeFilterSupport.FilterList) + moduleNode->Node.Visible = PhApplyTreeNewFiltersToNode(&Context->TreeFilterSupport, &moduleNode->Node); + PhEmCallObjectOperation(EmModuleNodeType, moduleNode, EmObjectCreate); TreeNew_NodesStructured(Context->TreeNewHandle); @@ -324,6 +351,30 @@ VOID PhUpdateModuleNode( TreeNew_NodesStructured(Context->TreeNewHandle); } +VOID PhExpandAllModuleNodes( + _In_ PPH_MODULE_LIST_CONTEXT Context, + _In_ BOOLEAN Expand + ) +{ + ULONG i; + BOOLEAN needsRestructure = FALSE; + + for (i = 0; i < Context->NodeList->Count; i++) + { + PPH_MODULE_NODE node = Context->NodeList->Items[i]; + + if (node->Node.Expanded != Expand) + { + node->Node.Expanded = Expand; + needsRestructure = TRUE; + } + } + + if (needsRestructure) + TreeNew_NodesStructured(Context->TreeNewHandle); +} + + VOID PhTickModuleNodes( _In_ PPH_MODULE_LIST_CONTEXT Context ) @@ -745,7 +796,11 @@ BOOLEAN NTAPI PhpModuleTreeNewCallback( { PWSTR string = L""; - if (moduleItem->Type == PH_MODULE_TYPE_MODULE || moduleItem->Type == PH_MODULE_TYPE_WOW64_MODULE) + if (moduleItem->Type == PH_MODULE_TYPE_KERNEL_MODULE) + { + string = L"Dynamic"; + } + else if (moduleItem->Type == PH_MODULE_TYPE_MODULE || moduleItem->Type == PH_MODULE_TYPE_WOW64_MODULE) { switch (moduleItem->LoadReason) { diff --git a/ProcessHacker/prpghndl.c b/ProcessHacker/prpghndl.c index 36d1d027dd3c..e17c8b313b58 100644 --- a/ProcessHacker/prpghndl.c +++ b/ProcessHacker/prpghndl.c @@ -693,6 +693,9 @@ INT_PTR CALLBACK PhpProcessHandlesDlgProc( InvalidateRect(tnHandle, NULL, FALSE); } + // Refresh the visible nodes. + PhApplyTreeNewFilters(&handlesContext->ListContext.TreeFilterSupport); + if (count != 0) TreeNew_SetRedraw(tnHandle, TRUE); } diff --git a/ProcessHacker/prpgmod.c b/ProcessHacker/prpgmod.c index d7e49874ca36..2dfe11953520 100644 --- a/ProcessHacker/prpgmod.c +++ b/ProcessHacker/prpgmod.c @@ -37,6 +37,7 @@ #include #include #include +#include static PH_STRINGREF EmptyModulesText = PH_STRINGREF_INIT(L"There are no modules to display."); @@ -178,6 +179,216 @@ VOID PhShowModuleContextMenu( PhFree(modules); } + +static BOOLEAN PhpWordMatchHandleStringRef( + _In_ PPH_STRING SearchText, + _In_ PPH_STRINGREF Text + ) +{ + PH_STRINGREF part; + PH_STRINGREF remainingPart; + + remainingPart = SearchText->sr; + + while (remainingPart.Length) + { + PhSplitStringRefAtChar(&remainingPart, '|', &part, &remainingPart); + + if (part.Length) + { + if (PhFindStringInStringRef(Text, &part, TRUE) != -1) + return TRUE; + } + } + + return FALSE; +} + +static BOOLEAN PhpWordMatchHandleStringZ( + _In_ PPH_STRING SearchText, + _In_ PWSTR Text + ) +{ + PH_STRINGREF text; + + PhInitializeStringRef(&text, Text); + + return PhpWordMatchHandleStringRef(SearchText, &text); +} + +BOOLEAN PhpModulesTreeFilterCallback( + _In_ PPH_TREENEW_NODE Node, + _In_opt_ PPH_MODULES_CONTEXT Context + ) +{ + PPH_MODULE_NODE moduleNode = (PPH_MODULE_NODE)Node; + PPH_MODULE_ITEM moduleItem = moduleNode->ModuleItem; + + switch (moduleItem->LoadReason) + { + case LoadReasonStaticDependency: + case LoadReasonStaticForwarderDependency: + { + if (Context->ListContext.HideStaticModules) + return FALSE; + } + break; + case LoadReasonDynamicForwarderDependency: + case LoadReasonDynamicLoad: + { + if (Context->ListContext.HideDynamicModules) + return FALSE; + } + break; + } + + switch (moduleItem->Type) + { + case PH_MODULE_TYPE_MAPPED_FILE: + case PH_MODULE_TYPE_MAPPED_IMAGE: + { + if (Context->ListContext.HideMappedModules) + return FALSE; + } + break; + } + + if (Context->ListContext.HideSignedModules && moduleItem->VerifyResult == VrTrusted) + return FALSE; + + if (PhIsNullOrEmptyString(Context->SearchboxText)) + return TRUE; + + //PVOID BaseAddress; + //ULONG Size; + //ULONG Flags; + //ULONG Type; + //ULONG ImageTimeDateStamp; + //USHORT ImageCharacteristics; + //USHORT ImageDllCharacteristics; + //LARGE_INTEGER LoadTime; + //LARGE_INTEGER FileLastWriteTime; + //LARGE_INTEGER FileEndOfFile; + + // module properties + + if (!PhIsNullOrEmptyString(moduleItem->Name)) + { + if (PhpWordMatchHandleStringRef(Context->SearchboxText, &moduleItem->Name->sr)) + return TRUE; + } + + if (!PhIsNullOrEmptyString(moduleItem->FileName)) + { + if (PhpWordMatchHandleStringRef(Context->SearchboxText, &moduleItem->FileName->sr)) + return TRUE; + } + + if (!PhIsNullOrEmptyString(moduleItem->VerifySignerName)) + { + if (PhpWordMatchHandleStringRef(Context->SearchboxText, &moduleItem->VerifySignerName->sr)) + return TRUE; + } + + if (moduleItem->BaseAddressString[0]) + { + if (PhpWordMatchHandleStringZ(Context->SearchboxText, moduleItem->BaseAddressString)) + return TRUE; + } + + if (!PhIsNullOrEmptyString(moduleItem->VersionInfo.CompanyName)) + { + if (PhpWordMatchHandleStringRef(Context->SearchboxText, &moduleItem->VersionInfo.CompanyName->sr)) + return TRUE; + } + + if (!PhIsNullOrEmptyString(moduleItem->VersionInfo.FileDescription)) + { + if (PhpWordMatchHandleStringRef(Context->SearchboxText, &moduleItem->VersionInfo.FileDescription->sr)) + return TRUE; + } + + if (!PhIsNullOrEmptyString(moduleItem->VersionInfo.FileVersion)) + { + if (PhpWordMatchHandleStringRef(Context->SearchboxText, &moduleItem->VersionInfo.FileVersion->sr)) + return TRUE; + } + + if (!PhIsNullOrEmptyString(moduleItem->VersionInfo.ProductName)) + { + if (PhpWordMatchHandleStringRef(Context->SearchboxText, &moduleItem->VersionInfo.ProductName->sr)) + return TRUE; + } + + switch (moduleItem->LoadReason) + { + case LoadReasonStaticDependency: + if (PhpWordMatchHandleStringZ(Context->SearchboxText, L"Static dependency")) + return TRUE; + break; + case LoadReasonStaticForwarderDependency: + if (PhpWordMatchHandleStringZ(Context->SearchboxText, L"Static forwarder dependency")) + return TRUE; + break; + case LoadReasonDynamicForwarderDependency: + if (PhpWordMatchHandleStringZ(Context->SearchboxText, L"Dynamic forwarder dependency")) + return TRUE; + break; + case LoadReasonDelayloadDependency: + if (PhpWordMatchHandleStringZ(Context->SearchboxText, L"Delay load dependency")) + return TRUE; + break; + case LoadReasonDynamicLoad: + if (PhpWordMatchHandleStringZ(Context->SearchboxText, L"Dynamic")) + return TRUE; + break; + case LoadReasonAsImageLoad: + if (PhpWordMatchHandleStringZ(Context->SearchboxText, L"Image")) + return TRUE; + break; + case LoadReasonAsDataLoad: + if (PhpWordMatchHandleStringZ(Context->SearchboxText, L"Data")) + return TRUE; + break; + } + + switch (moduleItem->VerifyResult) + { + case VrNoSignature: + if (PhpWordMatchHandleStringZ(Context->SearchboxText, L"No Signature")) + return TRUE; + break; + case VrExpired: + if (PhpWordMatchHandleStringZ(Context->SearchboxText, L"Expired")) + return TRUE; + break; + case VrRevoked: + case VrDistrust: + if (PhpWordMatchHandleStringZ(Context->SearchboxText, L"Revoked")) + return TRUE; + break; + } + + switch (moduleItem->VerifyResult) + { + case VrTrusted: + if (PhpWordMatchHandleStringZ(Context->SearchboxText, L"Trusted")) + return TRUE; + break; + case VrNoSignature: + case VrExpired: + case VrRevoked: + case VrDistrust: + case VrUnknown: + case VrBadSignature: + if (PhpWordMatchHandleStringZ(Context->SearchboxText, L"Bad")) + return TRUE; + break; + } + + return FALSE; +} + INT_PTR CALLBACK PhpProcessModulesDlgProc( _In_ HWND hwndDlg, _In_ UINT uMsg, @@ -248,6 +459,9 @@ INT_PTR CALLBACK PhpProcessModulesDlgProc( ); modulesContext->WindowHandle = hwndDlg; + modulesContext->SearchboxHandle = GetDlgItem(hwndDlg, IDC_SEARCH); + PhCreateSearchControl(hwndDlg, modulesContext->SearchboxHandle, L"Search Modules (Ctrl+K)"); + // Initialize the list. tnHandle = GetDlgItem(hwndDlg, IDC_LIST); BringWindowToTop(tnHandle); @@ -256,6 +470,8 @@ INT_PTR CALLBACK PhpProcessModulesDlgProc( PhInitializeProviderEventQueue(&modulesContext->EventQueue, 100); modulesContext->LastRunStatus = -1; modulesContext->ErrorMessage = NULL; + modulesContext->SearchboxText = PhReferenceEmptyString(); + modulesContext->FilterEntry = PhAddTreeNewFilter(&modulesContext->ListContext.TreeFilterSupport, PhpModulesTreeFilterCallback, modulesContext); PhEmCallObjectOperation(EmModulesContextType, modulesContext, EmObjectCreate); @@ -271,6 +487,8 @@ INT_PTR CALLBACK PhpProcessModulesDlgProc( PhLoadSettingsModuleList(&modulesContext->ListContext); + modulesContext->ListContext.Flags = PhGetIntegerSetting(L"ModuleListFlags"); + PhSetEnabledProvider(&modulesContext->ProviderRegistration, TRUE); PhBoostProvider(&modulesContext->ProviderRegistration, NULL); @@ -325,10 +543,9 @@ INT_PTR CALLBACK PhpProcessModulesDlgProc( { PPH_LAYOUT_ITEM dialogItem; - dialogItem = PhAddPropPageLayoutItem(hwndDlg, hwndDlg, - PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL); - PhAddPropPageLayoutItem(hwndDlg, modulesContext->ListContext.TreeNewHandle, - dialogItem, PH_ANCHOR_ALL); + dialogItem = PhAddPropPageLayoutItem(hwndDlg, hwndDlg, PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL); + PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_SEARCH), dialogItem, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); + PhAddPropPageLayoutItem(hwndDlg, modulesContext->ListContext.TreeNewHandle, dialogItem, PH_ANCHOR_ALL); PhDoPropPageLayout(hwndDlg); @@ -338,6 +555,34 @@ INT_PTR CALLBACK PhpProcessModulesDlgProc( break; case WM_COMMAND: { + switch (GET_WM_COMMAND_CMD(wParam, lParam)) + { + case EN_CHANGE: + { + PPH_STRING newSearchboxText; + + if (GET_WM_COMMAND_HWND(wParam, lParam) != modulesContext->SearchboxHandle) + break; + + newSearchboxText = PhGetWindowText(modulesContext->SearchboxHandle); + + if (!PhEqualString(modulesContext->SearchboxText, newSearchboxText, FALSE)) + { + // Cache the current search text for our callback. + PhMoveReference(&modulesContext->SearchboxText, newSearchboxText); + + if (!PhIsNullOrEmptyString(modulesContext->SearchboxText)) + { + // Expand any hidden nodes to make search results visible. + PhExpandAllModuleNodes(&modulesContext->ListContext, TRUE); + } + + PhApplyTreeNewFilters(&modulesContext->ListContext.TreeFilterSupport); + } + } + break; + } + switch (LOWORD(wParam)) { case ID_SHOWCONTEXTMENU: @@ -415,6 +660,56 @@ INT_PTR CALLBACK PhpProcessModulesDlgProc( PhDereferenceObject(text); } break; + case IDC_FILTEROPTIONS: + { + RECT rect; + PPH_EMENU menu; + PPH_EMENU_ITEM dynamicItem; + PPH_EMENU_ITEM mappedItem; + PPH_EMENU_ITEM staticItem; + PPH_EMENU_ITEM verifiedItem; + PPH_EMENU_ITEM selectedItem; + + GetWindowRect(GetDlgItem(hwndDlg, IDC_FILTEROPTIONS), &rect); + + menu = PhCreateEMenu(); + + PhInsertEMenuItem(menu, dynamicItem = PhCreateEMenuItem(0, PH_MODULE_FLAGS_DYNAMIC_OPTION, L"Hide dynamic", NULL, NULL), -1); + PhInsertEMenuItem(menu, mappedItem = PhCreateEMenuItem(0, PH_MODULE_FLAGS_MAPPED_OPTION, L"Hide mapped", NULL, NULL), -1); + PhInsertEMenuItem(menu, staticItem = PhCreateEMenuItem(0, PH_MODULE_FLAGS_STATIC_OPTION, L"Hide static", NULL, NULL), -1); + PhInsertEMenuItem(menu, verifiedItem = PhCreateEMenuItem(0, PH_MODULE_FLAGS_SIGNED_OPTION, L"Hide verified", NULL, NULL), -1); + + if (modulesContext->ListContext.HideDynamicModules) + dynamicItem->Flags |= PH_EMENU_CHECKED; + + if (modulesContext->ListContext.HideMappedModules) + mappedItem->Flags |= PH_EMENU_CHECKED; + + if (modulesContext->ListContext.HideStaticModules) + staticItem->Flags |= PH_EMENU_CHECKED; + + if (modulesContext->ListContext.HideSignedModules) + verifiedItem->Flags |= PH_EMENU_CHECKED; + + selectedItem = PhShowEMenu( + menu, + hwndDlg, + PH_EMENU_SHOW_LEFTRIGHT, + PH_ALIGN_LEFT | PH_ALIGN_TOP, + rect.left, + rect.bottom + ); + + if (selectedItem && selectedItem->Id) + { + PhSetOptionsModuleList(&modulesContext->ListContext, selectedItem->Id); + PhSetIntegerSetting(L"ModuleListFlags", modulesContext->ListContext.Flags); + PhApplyTreeNewFilters(&modulesContext->ListContext.TreeFilterSupport); + } + + PhDestroyEMenu(menu); + } + break; } } break; @@ -497,6 +792,9 @@ INT_PTR CALLBACK PhpProcessModulesDlgProc( InvalidateRect(tnHandle, NULL, FALSE); } + // Refresh the visible nodes. + PhApplyTreeNewFilters(&modulesContext->ListContext.TreeFilterSupport); + if (count != 0) TreeNew_SetRedraw(tnHandle, TRUE); } diff --git a/ProcessHacker/resource.h b/ProcessHacker/resource.h index d5f721adb148..aa9abe355ad4 100644 --- a/ProcessHacker/resource.h +++ b/ProcessHacker/resource.h @@ -533,6 +533,8 @@ #define IDC_EDIT 1383 #define IDC_NEW 1384 #define IDC_HANDLESEARCH 1385 +#define IDC_SEARCH 1387 +#define IDC_FILTEROPTIONS 1389 #define ID_MAINWND_PROCESSTL 2001 #define ID_MAINWND_SERVICETL 2002 #define ID_MAINWND_NETWORKTL 2003 @@ -744,8 +746,9 @@ #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 228 +#define _APS_NEXT_RESOURCE_VALUE 231 #define _APS_NEXT_COMMAND_VALUE 40295 -#define _APS_NEXT_CONTROL_VALUE 1387 +#define _APS_NEXT_CONTROL_VALUE 1390 #define _APS_NEXT_SYMED_VALUE 169 #endif #endif diff --git a/ProcessHacker/settings.c b/ProcessHacker/settings.c index 91077674310b..705ffe6b8ac7 100644 --- a/ProcessHacker/settings.c +++ b/ProcessHacker/settings.c @@ -103,6 +103,7 @@ VOID PhAddDefaultSettings( PhpAddIntegerPairSetting(L"MiniInfoWindowPosition", L"200,200"); PhpAddIntegerSetting(L"MiniInfoWindowRefreshAutomatically", L"1"); PhpAddScalableIntegerPairSetting(L"MiniInfoWindowSize", L"@96|10,200"); + PhpAddIntegerSetting(L"ModuleListFlags", L"0"); PhpAddStringSetting(L"ModuleTreeListColumns", L""); PhpAddStringSetting(L"ModuleTreeListSort", L"0,0"); // 0, NoSortOrder PhpAddStringSetting(L"NetworkTreeListColumns", L""); From 45e30c61a0fd4f62c92c899dcc1c53f1c4d7fa47 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 3 Jun 2017 01:05:22 +1000 Subject: [PATCH 0182/2058] Fix legacy config path --- phlib/kph.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phlib/kph.c b/phlib/kph.c index 8311273e632e..07008b4c39b6 100644 --- a/phlib/kph.c +++ b/phlib/kph.c @@ -256,7 +256,7 @@ NTSTATUS KphSetParameters( _In_ PKPH_PARAMETERS Parameters ) { - static PH_STRINGREF keyName = PH_STRINGREF_INIT(L"System\\CurrentControlSet\\Services\\kph2\\Parameters"); + static PH_STRINGREF keyName = PH_STRINGREF_INIT(L"System\\CurrentControlSet\\Services\\KProcessHacker2\\Parameters"); NTSTATUS status; HANDLE parametersKeyHandle = NULL; ULONG disposition; From 110d15bff897435f76b239bbc79da2c76137430b Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 3 Jun 2017 13:22:56 +1000 Subject: [PATCH 0183/2058] Add 'combine memory lists' option to memory list window --- ProcessHacker/ProcessHacker.rc | 2 +- ProcessHacker/memlists.c | 34 ++++++++++++ ProcessHacker/resource.h | 4 +- phlib/include/phutil.h | 10 ++++ phlib/util.c | 94 ++++++++++++++++++++++------------ 5 files changed, 109 insertions(+), 35 deletions(-) diff --git a/ProcessHacker/ProcessHacker.rc b/ProcessHacker/ProcessHacker.rc index 3df2a8103555..a05d04a0ca30 100644 --- a/ProcessHacker/ProcessHacker.rc +++ b/ProcessHacker/ProcessHacker.rc @@ -460,6 +460,7 @@ IDR_EMPTYMEMLISTS MENU BEGIN POPUP "Empty" BEGIN + MENUITEM "Combine memory lists", ID_EMPTY_COMBINEMEMORYLISTS MENUITEM "Empty working sets", ID_EMPTY_EMPTYWORKINGSETS MENUITEM "Empty modified page list", ID_EMPTY_EMPTYMODIFIEDPAGELIST MENUITEM "Empty standby list", ID_EMPTY_EMPTYSTANDBYLIST @@ -2536,7 +2537,6 @@ IDB_SEARCH_ACTIVE PNG "resources\\active_search.png" IDB_SEARCH_INACTIVE PNG "resources\\inactive_search.png" - #endif // English (Australia) resources ///////////////////////////////////////////////////////////////////////////// diff --git a/ProcessHacker/memlists.c b/ProcessHacker/memlists.c index 6f73a3f3d918..537e318f8c55 100644 --- a/ProcessHacker/memlists.c +++ b/ProcessHacker/memlists.c @@ -232,6 +232,40 @@ INT_PTR CALLBACK PhpMemoryListsDlgProc( case ID_EMPTY_EMPTYPRIORITY0STANDBYLIST: command = MemoryPurgeLowPriorityStandbyList; break; + case ID_EMPTY_COMBINEMEMORYLISTS: + { + NTSTATUS status; + HANDLE tokenHandle; + MEMORY_COMBINE_INFORMATION_EX combineInfo = { 0 }; + + if (NT_SUCCESS(NtOpenProcessToken(NtCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &tokenHandle))) + { + PhSetTokenPrivilege(tokenHandle, SE_PROF_SINGLE_PROCESS_NAME, NULL, SE_PRIVILEGE_ENABLED); + NtClose(tokenHandle); + } + + status = NtSetSystemInformation( + SystemCombinePhysicalMemoryInformation, + &combineInfo, + sizeof(MEMORY_COMBINE_INFORMATION_EX) + ); + + if (NT_SUCCESS(status)) + { + PhShowInformation2( + hwndDlg, + L"Memory pages combined", + L"%s (%llu pages)", + PhaFormatSize(combineInfo.PagesCombined * PAGE_SIZE, -1)->Buffer, + combineInfo.PagesCombined + ); + } + else + { + PhShowStatus(hwndDlg, L"Unable to combine memory pages", status, 0); + } + } + break; } } diff --git a/ProcessHacker/resource.h b/ProcessHacker/resource.h index aa9abe355ad4..07b320db4642 100644 --- a/ProcessHacker/resource.h +++ b/ProcessHacker/resource.h @@ -738,6 +738,7 @@ #define ID_ENVIRONMENT_COPY 40291 #define ID_ENVIRONMENT_DELETE 40292 #define IDC_MAXSCREEN 40293 +#define ID_EMPTY_COMBINEMEMORYLISTS 40295 #define IDDYNAMIC 50000 #define IDPLUGINS 55000 @@ -745,9 +746,8 @@ // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 228 #define _APS_NEXT_RESOURCE_VALUE 231 -#define _APS_NEXT_COMMAND_VALUE 40295 +#define _APS_NEXT_COMMAND_VALUE 40297 #define _APS_NEXT_CONTROL_VALUE 1390 #define _APS_NEXT_SYMED_VALUE 169 #endif diff --git a/phlib/include/phutil.h b/phlib/include/phutil.h index 0ee65e7c0fd3..7eff8ea6b88d 100644 --- a/phlib/include/phutil.h +++ b/phlib/include/phutil.h @@ -236,6 +236,16 @@ PhShowMessage_V( #define PhShowWarning(hWnd, Format, ...) PhShowMessage(hWnd, MB_OK | MB_ICONWARNING, Format, __VA_ARGS__) #define PhShowInformation(hWnd, Format, ...) PhShowMessage(hWnd, MB_OK | MB_ICONINFORMATION, Format, __VA_ARGS__) +PHLIBAPI +INT +NTAPI +PhShowInformation2( + _In_ HWND hWnd, + _In_opt_ PWSTR Title, + _In_ PWSTR Format, + ... + ); + PHLIBAPI INT NTAPI diff --git a/phlib/util.c b/phlib/util.c index 117339b56462..f20f04a60f26 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -406,48 +406,78 @@ INT PhShowMessage_V( return result; } +INT PhShowInformation2( + _In_ HWND hWnd, + _In_opt_ PWSTR Title, + _In_ PWSTR Format, + ... + ) +{ + va_list argptr; + INT button; + PPH_STRING message; + TASKDIALOGCONFIG config = { sizeof(config) }; + + va_start(argptr, Format); + message = PhFormatString_V(Format, argptr); + va_end(argptr); + + config.hwndParent = hWnd; + config.hInstance = PhLibImageBase; + config.dwFlags = TDF_ALLOW_DIALOG_CANCELLATION | (IsWindowVisible(hWnd) ? TDF_POSITION_RELATIVE_TO_WINDOW : 0); + config.dwCommonButtons = TDCBF_CLOSE_BUTTON; + config.pszWindowTitle = PhApplicationName; + config.pszMainIcon = TD_INFORMATION_ICON; + config.pszMainInstruction = Title; + config.pszContent = message->Buffer; + + if (TaskDialogIndirect( + &config, + &button, + NULL, + NULL + ) == S_OK) + { + PhDereferenceObject(message); + return button; + } + else + { + PhDereferenceObject(message); + return FALSE; + } +} + INT PhShowError2( _In_ HWND hWnd, _In_opt_ PWSTR Title, _In_opt_ PWSTR Message ) { - if (TaskDialogIndirect_Import()) + INT button; + TASKDIALOGCONFIG config = { sizeof(config) }; + + config.hwndParent = hWnd; + config.hInstance = PhLibImageBase; + config.dwFlags = TDF_ALLOW_DIALOG_CANCELLATION | (IsWindowVisible(hWnd) ? TDF_POSITION_RELATIVE_TO_WINDOW : 0); + config.dwCommonButtons = TDCBF_CLOSE_BUTTON; + config.pszWindowTitle = PhApplicationName; + config.pszMainIcon = TD_ERROR_ICON; + config.pszMainInstruction = Title; + config.pszContent = Message; + + if (TaskDialogIndirect( + &config, + &button, + NULL, + NULL + ) == S_OK) { - INT button; - TASKDIALOGCONFIG config = { sizeof(config) }; - - config.hwndParent = hWnd; - config.hInstance = PhLibImageBase; - config.dwFlags = TDF_ALLOW_DIALOG_CANCELLATION | (IsWindowVisible(hWnd) ? TDF_POSITION_RELATIVE_TO_WINDOW : 0); - config.dwCommonButtons = TDCBF_CLOSE_BUTTON; - config.pszWindowTitle = PhApplicationName; - config.pszMainIcon = TD_ERROR_ICON; - config.pszMainInstruction = Title; - config.pszContent = Message; - - if (TaskDialogIndirect_Import()( - &config, - &button, - NULL, - NULL - ) == S_OK) - { - return button == IDCLOSE; - } - else - { - return FALSE; - } + return button; } else { - return PhShowMessage( - hWnd, - MB_OK | MB_ICONERROR, - Title, - Message - ) == IDOK; + return FALSE; } } From c24b0ed369aed541af48267fae4b2c8e89ed5655 Mon Sep 17 00:00:00 2001 From: Steven G Date: Sat, 3 Jun 2017 20:16:19 +1000 Subject: [PATCH 0184/2058] Add memory tab search support (#144) --- ProcessHacker/ProcessHacker.rc | 6 +- ProcessHacker/include/memlist.h | 28 ++++- ProcessHacker/include/procprpp.h | 5 + ProcessHacker/memlist.c | 154 ++++++++++++++---------- ProcessHacker/prpghndl.c | 3 +- ProcessHacker/prpgmem.c | 199 +++++++++++++++++++++++++++---- ProcessHacker/prpgmod.c | 1 + ProcessHacker/settings.c | 1 + 8 files changed, 309 insertions(+), 88 deletions(-) diff --git a/ProcessHacker/ProcessHacker.rc b/ProcessHacker/ProcessHacker.rc index a05d04a0ca30..8a95c77ff329 100644 --- a/ProcessHacker/ProcessHacker.rc +++ b/ProcessHacker/ProcessHacker.rc @@ -1133,10 +1133,10 @@ STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSM CAPTION "Memory" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN - PUSHBUTTON "Strings...",IDC_STRINGS,155,2,50,14 - PUSHBUTTON "Refresh",IDC_REFRESH,208,2,50,14 + PUSHBUTTON "Refresh",IDC_REFRESH,53,2,50,14 CONTROL "",IDC_LIST,"PhTreeNew",WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP | 0xa,2,19,256,239,WS_EX_CLIENTEDGE - CONTROL "Hide free regions",IDC_HIDEFREEREGIONS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,3,5,71,10 + PUSHBUTTON "Options",IDC_FILTEROPTIONS,2,2,50,14 + EDITTEXT IDC_SEARCH,114,3,144,14,ES_AUTOHSCROLL END IDD_CHOOSE DIALOGEX 0, 0, 199, 73 diff --git a/ProcessHacker/include/memlist.h b/ProcessHacker/include/memlist.h index c5f3dcdf2dda..ed3712834558 100644 --- a/ProcessHacker/include/memlist.h +++ b/ProcessHacker/include/memlist.h @@ -53,14 +53,29 @@ typedef struct _PH_MEMORY_NODE } PH_MEMORY_NODE, *PPH_MEMORY_NODE; // end_phapppub +#define PH_MEMORY_FLAGS_FREE_OPTION 1 +#define PH_MEMORY_FLAGS_RESERVED_OPTION 2 + typedef struct _PH_MEMORY_LIST_CONTEXT { HWND ParentWindowHandle; HWND TreeNewHandle; ULONG TreeNewSortColumn; + PH_TN_FILTER_SUPPORT AllocationTreeFilterSupport; + PH_TN_FILTER_SUPPORT TreeFilterSupport; PH_SORT_ORDER TreeNewSortOrder; PH_CM_MANAGER Cm; - BOOLEAN HideFreeRegions; + + union + { + ULONG Flags; + struct + { + ULONG HideFreeRegions : 1; + ULONG HideReservedRegions : 1; + ULONG Spare : 30; + }; + }; PPH_LIST AllocationBaseNodeList; // Allocation base nodes (list should always be sorted by base address) PPH_LIST RegionNodeList; // Memory region nodes @@ -86,7 +101,7 @@ VOID PhSaveSettingsMemoryList( VOID PhSetOptionsMemoryList( _Inout_ PPH_MEMORY_LIST_CONTEXT Context, - _In_ BOOLEAN HideFreeRegions + _In_ ULONG Options ); VOID PhReplaceMemoryList( @@ -99,6 +114,15 @@ VOID PhUpdateMemoryNode( _In_ PPH_MEMORY_NODE MemoryNode ); +VOID PhExpandAllMemoryNodes( + _In_ PPH_MEMORY_LIST_CONTEXT Context, + _In_ BOOLEAN Expand + ); + +PPH_STRING PhGetMemoryRegionUseText( + _In_ PPH_MEMORY_ITEM MemoryItem + ); + PPH_MEMORY_NODE PhGetSelectedMemoryNode( _In_ PPH_MEMORY_LIST_CONTEXT Context ); diff --git a/ProcessHacker/include/procprpp.h b/ProcessHacker/include/procprpp.h index e0976375888c..500573f100f7 100644 --- a/ProcessHacker/include/procprpp.h +++ b/ProcessHacker/include/procprpp.h @@ -288,6 +288,7 @@ typedef struct _PH_MEMORY_CONTEXT { HANDLE ProcessId; HWND WindowHandle; + HWND SearchboxHandle; // end_phapppub union @@ -303,6 +304,10 @@ typedef struct _PH_MEMORY_CONTEXT BOOLEAN MemoryItemListValid; NTSTATUS LastRunStatus; PPH_STRING ErrorMessage; + + PPH_STRING SearchboxText; + PPH_TN_FILTER_ENTRY AllocationFilterEntry; + PPH_TN_FILTER_ENTRY FilterEntry; // begin_phapppub } PH_MEMORY_CONTEXT, *PPH_MEMORY_CONTEXT; // end_phapppub diff --git a/ProcessHacker/memlist.c b/ProcessHacker/memlist.c index 90f4ec268941..cd69766e2e9b 100644 --- a/ProcessHacker/memlist.c +++ b/ProcessHacker/memlist.c @@ -29,6 +29,7 @@ #include #include #include +#include VOID PhpClearMemoryList( _Inout_ PPH_MEMORY_LIST_CONTEXT Context @@ -96,6 +97,9 @@ VOID PhInitializeMemoryList( TreeNew_SetSort(hwnd, 0, NoSortOrder); PhCmInitializeManager(&Context->Cm, hwnd, PHMMTLC_MAXIMUM, PhpMemoryTreeNewPostSortFunction); + + PhInitializeTreeNewFilterSupport(&Context->AllocationTreeFilterSupport, hwnd, Context->AllocationBaseNodeList); + PhInitializeTreeNewFilterSupport(&Context->TreeFilterSupport, hwnd, Context->RegionNodeList); } VOID PhpClearMemoryList( @@ -117,6 +121,9 @@ VOID PhDeleteMemoryList( _In_ PPH_MEMORY_LIST_CONTEXT Context ) { + PhDeleteTreeNewFilterSupport(&Context->AllocationTreeFilterSupport); + PhDeleteTreeNewFilterSupport(&Context->TreeFilterSupport); + PhCmDeleteManager(&Context->Cm); PhpClearMemoryList(Context); @@ -128,12 +135,17 @@ VOID PhLoadSettingsMemoryList( _Inout_ PPH_MEMORY_LIST_CONTEXT Context ) { + ULONG flags; PPH_STRING settings; PPH_STRING sortSettings; + flags = PhGetIntegerSetting(L"MemoryListFlags"); settings = PhGetStringSetting(L"MemoryTreeListColumns"); sortSettings = PhGetStringSetting(L"MemoryTreeListSort"); + + Context->Flags = flags; PhCmLoadSettingsEx(Context->TreeNewHandle, &Context->Cm, 0, &settings->sr, &sortSettings->sr); + PhDereferenceObject(settings); PhDereferenceObject(sortSettings); } @@ -146,57 +158,28 @@ VOID PhSaveSettingsMemoryList( PPH_STRING sortSettings; settings = PhCmSaveSettingsEx(Context->TreeNewHandle, &Context->Cm, 0, &sortSettings); + + PhSetIntegerSetting(L"MemoryListFlags", Context->Flags); PhSetStringSetting2(L"MemoryTreeListColumns", &settings->sr); PhSetStringSetting2(L"MemoryTreeListSort", &sortSettings->sr); + PhDereferenceObject(settings); PhDereferenceObject(sortSettings); } VOID PhSetOptionsMemoryList( _Inout_ PPH_MEMORY_LIST_CONTEXT Context, - _In_ BOOLEAN HideFreeRegions + _In_ ULONG Options ) { - ULONG i; - ULONG k; - BOOLEAN modified; - - if (Context->HideFreeRegions != HideFreeRegions) + switch (Options) { - PPH_LIST lists[2]; - - Context->HideFreeRegions = HideFreeRegions; - modified = FALSE; - lists[0] = Context->AllocationBaseNodeList; - lists[1] = Context->RegionNodeList; - - for (k = 0; k < 2; k++) - { - for (i = 0; i < lists[k]->Count; i++) - { - PPH_MEMORY_NODE node = lists[k]->Items[i]; - BOOLEAN visible; - - visible = TRUE; - - if (HideFreeRegions && (node->MemoryItem->State & MEM_FREE)) - visible = FALSE; - - if (node->Node.Visible != visible) - { - node->Node.Visible = visible; - modified = TRUE; - - if (!visible) - node->Node.Selected = FALSE; - } - } - } - - if (modified) - { - TreeNew_NodesStructured(Context->TreeNewHandle); - } + case PH_MEMORY_FLAGS_FREE_OPTION: + Context->HideFreeRegions = !Context->HideFreeRegions; + break; + case PH_MEMORY_FLAGS_RESERVED_OPTION: + Context->HideReservedRegions = !Context->HideReservedRegions; + break; } } @@ -250,6 +233,9 @@ PPH_MEMORY_NODE PhpAddAllocationBaseNode( PhAddItemList(Context->AllocationBaseNodeList, memoryNode); + if (Context->AllocationTreeFilterSupport.FilterList) + memoryNode->Node.Visible = PhApplyTreeNewFiltersToNode(&Context->AllocationTreeFilterSupport, &memoryNode->Node); + PhEmCallObjectOperation(EmMemoryNodeType, memoryNode, EmObjectCreate); return memoryNode; @@ -276,6 +262,9 @@ PPH_MEMORY_NODE PhpAddRegionNode( PhAddItemList(Context->RegionNodeList, memoryNode); + if (Context->TreeFilterSupport.FilterList) + memoryNode->Node.Visible = PhApplyTreeNewFiltersToNode(&Context->TreeFilterSupport, &memoryNode->Node); + PhEmCallObjectOperation(EmMemoryNodeType, memoryNode, EmObjectCreate); return memoryNode; @@ -349,13 +338,12 @@ VOID PhReplaceMemoryList( if (memoryItem->AllocationBaseItem == memoryItem) { - if (memoryItem->State & MEM_FREE) - allocationBaseNode->MemoryItem->State = MEM_FREE; - allocationBaseNode->MemoryItem->Protect = memoryItem->AllocationProtect; - PhGetMemoryProtectionString(allocationBaseNode->MemoryItem->Protect, allocationBaseNode->ProtectionText); + allocationBaseNode->MemoryItem->State = memoryItem->State; allocationBaseNode->MemoryItem->Type = memoryItem->Type; + PhGetMemoryProtectionString(allocationBaseNode->MemoryItem->Protect, allocationBaseNode->ProtectionText); + if (memoryItem->RegionType != CustomRegion || memoryItem->u.Custom.PropertyOfAllocationBase) PhpCopyMemoryRegionTypeInfo(memoryItem, allocationBaseNode->MemoryItem); @@ -385,7 +373,41 @@ VOID PhUpdateMemoryNode( TreeNew_InvalidateNode(Context->TreeNewHandle, &MemoryNode->Node); } -PPH_STRING PhpGetMemoryRegionUseText( +VOID PhExpandAllMemoryNodes( + _In_ PPH_MEMORY_LIST_CONTEXT Context, + _In_ BOOLEAN Expand + ) +{ + ULONG i; + BOOLEAN needsRestructure = FALSE; + + for (i = 0; i < Context->AllocationBaseNodeList->Count; i++) + { + PPH_MEMORY_NODE node = Context->AllocationBaseNodeList->Items[i]; + + if (node->Node.Expanded != Expand) + { + node->Node.Expanded = Expand; + needsRestructure = TRUE; + } + } + + for (i = 0; i < Context->RegionNodeList->Count; i++) + { + PPH_MEMORY_NODE node = Context->RegionNodeList->Items[i]; + + if (node->Node.Expanded != Expand) + { + node->Node.Expanded = Expand; + needsRestructure = TRUE; + } + } + + if (needsRestructure) + TreeNew_NodesStructured(Context->TreeNewHandle); +} + +PPH_STRING PhGetMemoryRegionUseText( _In_ PPH_MEMORY_ITEM MemoryItem ) { @@ -438,7 +460,7 @@ VOID PhpUpdateMemoryNodeUseText( ) { if (!MemoryNode->UseText) - MemoryNode->UseText = PhpGetMemoryRegionUseText(MemoryNode->MemoryItem); + MemoryNode->UseText = PhGetMemoryRegionUseText(MemoryNode->MemoryItem); } PPH_STRING PhpFormatSizeIfNonZero( @@ -751,22 +773,34 @@ BOOLEAN NTAPI PhpMemoryTreeNewCallback( return TRUE; case TreeNewGetNodeColor: { - //PPH_TREENEW_GET_NODE_COLOR getNodeColor = Parameter1; - //PPH_MEMORY_ITEM memoryItem; - - //node = (PPH_MEMORY_NODE)getNodeColor->Node; - //memoryItem = node->MemoryItem; - - //if (!memoryItem) - // ; // Dummy - //else if (PhCsUseColorRelocatedModules && (memoryItem->Protect & PAGE_EXECUTE_WRITECOPY)) - // getNodeColor->BackColor = PhCsColorRelocatedModules; - //else if (PhCsUseColorRelocatedModules && (memoryItem->Protect & PAGE_EXECUTE_READWRITE)) - // getNodeColor->BackColor = PhCsColorRelocatedModules; - //else if (PhCsUseColorSystemProcesses && (memoryItem->Type & MEM_PRIVATE)) + PPH_TREENEW_GET_NODE_COLOR getNodeColor = Parameter1; + PPH_MEMORY_ITEM memoryItem; + + node = (PPH_MEMORY_NODE)getNodeColor->Node; + memoryItem = node->MemoryItem; + + if (!memoryItem) + ; // Dummy + //else if ( + // memoryItem->RegionType == StackRegion || memoryItem->RegionType == Stack32Region || + // memoryItem->RegionType == HeapRegion || memoryItem->RegionType == Heap32Region || + // memoryItem->RegionType == HeapSegmentRegion || memoryItem->RegionType == HeapSegment32Region + // ((memoryItem->Protect & PAGE_EXECUTE_WRITECOPY || memoryItem->Protect & PAGE_EXECUTE_READWRITE || + // memoryItem->Protect & PAGE_READWRITE) && !(memoryItem->Type & SEC_IMAGE)) + // ) + //{ + // getNodeColor->BackColor = PhCsColorElevatedProcesses; + //} + //else if (memoryItem->RegionType == CfgBitmapRegion || memoryItem->RegionType == CfgBitmap32Region) + // getNodeColor->BackColor = PhCsColorProtectedHandles; + //else if (memoryItem->Type & MEM_PRIVATE) + // getNodeColor->BackColor = PhCsColorOwnProcesses; + //else if (memoryItem->Type & MEM_MAPPED) // getNodeColor->BackColor = PhCsColorSystemProcesses; + //else if (memoryItem->Type & SEC_IMAGE) + // getNodeColor->BackColor = PhCsColorImmersiveProcesses; - //getNodeColor->Flags = TN_CACHE | TN_AUTO_FORECOLOR; + getNodeColor->Flags = TN_CACHE | TN_AUTO_FORECOLOR; } return TRUE; case TreeNewSortChanged: diff --git a/ProcessHacker/prpghndl.c b/ProcessHacker/prpghndl.c index e17c8b313b58..855c069953cb 100644 --- a/ProcessHacker/prpghndl.c +++ b/ProcessHacker/prpghndl.c @@ -3,6 +3,7 @@ * Process properties: Handles page * * Copyright (C) 2009-2016 wj32 + * Copyright (C) 2017 dmex * * This file is part of Process Hacker. * @@ -468,7 +469,7 @@ INT_PTR CALLBACK PhpProcessHandlesDlgProc( PPH_LAYOUT_ITEM dialogItem; dialogItem = PhAddPropPageLayoutItem(hwndDlg, hwndDlg, PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL); - PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_HANDLESEARCH), dialogItem, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); + PhAddPropPageLayoutItem(hwndDlg, handlesContext->SearchboxHandle, dialogItem, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_LIST), dialogItem, PH_ANCHOR_ALL); PhDoPropPageLayout(hwndDlg); diff --git a/ProcessHacker/prpgmem.c b/ProcessHacker/prpgmem.c index 1449dcebe0ed..0e70f9caadab 100644 --- a/ProcessHacker/prpgmem.c +++ b/ProcessHacker/prpgmem.c @@ -196,6 +196,98 @@ VOID PhShowMemoryContextMenu( PhFree(memoryNodes); } +static BOOLEAN PhpWordMatchHandleStringRef( + _In_ PPH_STRING SearchText, + _In_ PPH_STRINGREF Text + ) +{ + PH_STRINGREF part; + PH_STRINGREF remainingPart; + + remainingPart = SearchText->sr; + + while (remainingPart.Length) + { + PhSplitStringRefAtChar(&remainingPart, '|', &part, &remainingPart); + + if (part.Length) + { + if (PhFindStringInStringRef(Text, &part, TRUE) != -1) + return TRUE; + } + } + + return FALSE; +} + +static BOOLEAN PhpWordMatchHandleStringZ( + _In_ PPH_STRING SearchText, + _In_ PWSTR Text + ) +{ + PH_STRINGREF text; + + PhInitializeStringRef(&text, Text); + + return PhpWordMatchHandleStringRef(SearchText, &text); +} + +BOOLEAN PhpMemoryTreeFilterCallback( + _In_ PPH_TREENEW_NODE Node, + _In_opt_ PVOID Context + ) +{ + PPH_MEMORY_CONTEXT memoryContext = Context; + PPH_MEMORY_NODE memoryNode = (PPH_MEMORY_NODE)Node; + PPH_MEMORY_ITEM memoryItem = memoryNode->MemoryItem; + PPH_STRING useText; + PWSTR tempString; + + if (memoryContext->ListContext.HideFreeRegions && memoryItem->State & MEM_FREE) + return FALSE; + + if (memoryContext->ListContext.HideReservedRegions && + (memoryItem->Type & MEM_PRIVATE || memoryItem->Type & MEM_MAPPED) && + memoryItem->State & MEM_RESERVE && + memoryItem->AllocationBaseItem // Ignore root nodes + ) + { + return FALSE; + } + + if (PhIsNullOrEmptyString(memoryContext->SearchboxText)) + return TRUE; + + if (memoryNode->BaseAddressText[0]) + { + if (PhpWordMatchHandleStringZ(memoryContext->SearchboxText, memoryNode->BaseAddressText)) + return TRUE; + } + + useText = PH_AUTO(PhGetMemoryRegionUseText(memoryItem)); + if (!PhIsNullOrEmptyString(useText)) + { + if (PhpWordMatchHandleStringRef(memoryContext->SearchboxText, &useText->sr)) + return TRUE; + } + + tempString = PhGetMemoryTypeString(memoryItem->Type); + if (tempString[0]) + { + if (PhpWordMatchHandleStringZ(memoryContext->SearchboxText, tempString)) + return TRUE; + } + + tempString = PhGetMemoryStateString(memoryItem->State); + if (tempString[0]) + { + if (PhpWordMatchHandleStringZ(memoryContext->SearchboxText, tempString)) + return TRUE; + } + + return FALSE; +} + INT_PTR CALLBACK PhpProcessMemoryDlgProc( _In_ HWND hwndDlg, _In_ UINT uMsg, @@ -231,6 +323,9 @@ INT_PTR CALLBACK PhpProcessMemoryDlgProc( memset(memoryContext, 0, sizeof(PH_MEMORY_CONTEXT)); memoryContext->ProcessId = processItem->ProcessId; + memoryContext->SearchboxHandle = GetDlgItem(hwndDlg, IDC_SEARCH); + PhCreateSearchControl(hwndDlg, memoryContext->SearchboxHandle, L"Search Memory (Ctrl+K)"); + // Initialize the list. tnHandle = GetDlgItem(hwndDlg, IDC_LIST); BringWindowToTop(tnHandle); @@ -238,6 +333,9 @@ INT_PTR CALLBACK PhpProcessMemoryDlgProc( TreeNew_SetEmptyText(tnHandle, &PhpLoadingText, 0); memoryContext->LastRunStatus = -1; memoryContext->ErrorMessage = NULL; + memoryContext->SearchboxText = PhReferenceEmptyString(); + memoryContext->AllocationFilterEntry = PhAddTreeNewFilter(&memoryContext->ListContext.AllocationTreeFilterSupport, PhpMemoryTreeFilterCallback, memoryContext); + memoryContext->FilterEntry = PhAddTreeNewFilter(&memoryContext->ListContext.TreeFilterSupport, PhpMemoryTreeFilterCallback, memoryContext); PhEmCallObjectOperation(EmMemoryContextType, memoryContext, EmObjectCreate); @@ -252,9 +350,6 @@ INT_PTR CALLBACK PhpProcessMemoryDlgProc( } PhLoadSettingsMemoryList(&memoryContext->ListContext); - PhSetOptionsMemoryList(&memoryContext->ListContext, !!PhGetIntegerSetting(L"HideFreeRegions")); - Button_SetCheck(GetDlgItem(hwndDlg, IDC_HIDEFREEREGIONS), - memoryContext->ListContext.HideFreeRegions ? BST_CHECKED : BST_UNCHECKED); PhpRefreshProcessMemoryList(hwndDlg, propPageContext); } @@ -290,14 +385,9 @@ INT_PTR CALLBACK PhpProcessMemoryDlgProc( { PPH_LAYOUT_ITEM dialogItem; - dialogItem = PhAddPropPageLayoutItem(hwndDlg, hwndDlg, - PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL); - PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_STRINGS), - dialogItem, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); - PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_REFRESH), - dialogItem, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); - PhAddPropPageLayoutItem(hwndDlg, memoryContext->ListContext.TreeNewHandle, - dialogItem, PH_ANCHOR_ALL); + dialogItem = PhAddPropPageLayoutItem(hwndDlg, hwndDlg, PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL); + PhAddPropPageLayoutItem(hwndDlg, memoryContext->SearchboxHandle, dialogItem, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); + PhAddPropPageLayoutItem(hwndDlg, memoryContext->ListContext.TreeNewHandle, dialogItem, PH_ANCHOR_ALL); PhDoPropPageLayout(hwndDlg); @@ -307,6 +397,32 @@ INT_PTR CALLBACK PhpProcessMemoryDlgProc( break; case WM_COMMAND: { + switch (GET_WM_COMMAND_CMD(wParam, lParam)) + { + case EN_CHANGE: + { + PPH_STRING newSearchboxText; + + if (GET_WM_COMMAND_HWND(wParam, lParam) != memoryContext->SearchboxHandle) + break; + + newSearchboxText = PhGetWindowText(memoryContext->SearchboxHandle); + + if (!PhEqualString(memoryContext->SearchboxText, newSearchboxText, FALSE)) + { + // Cache the current search text for our callback. + PhMoveReference(&memoryContext->SearchboxText, newSearchboxText); + + // Expand any hidden nodes to make search results visible. + PhExpandAllMemoryNodes(&memoryContext->ListContext, TRUE); + + PhApplyTreeNewFilters(&memoryContext->ListContext.AllocationTreeFilterSupport); + PhApplyTreeNewFilters(&memoryContext->ListContext.TreeFilterSupport); + } + } + break; + } + switch (LOWORD(wParam)) { case ID_SHOWCONTEXTMENU: @@ -537,21 +653,60 @@ INT_PTR CALLBACK PhpProcessMemoryDlgProc( PhDereferenceObject(text); } break; - case IDC_HIDEFREEREGIONS: + case IDC_REFRESH: + PhpRefreshProcessMemoryList(hwndDlg, propPageContext); + break; + case IDC_FILTEROPTIONS: { - BOOLEAN hide; + RECT rect; + PPH_EMENU menu; + PPH_EMENU_ITEM freeItem; + PPH_EMENU_ITEM reservedItem; + PPH_EMENU_ITEM selectedItem; - hide = Button_GetCheck(GetDlgItem(hwndDlg, IDC_HIDEFREEREGIONS)) == BST_CHECKED; - PhSetIntegerSetting(L"HideFreeRegions", hide); - PhSetOptionsMemoryList(&memoryContext->ListContext, hide); + GetWindowRect(GetDlgItem(hwndDlg, IDC_FILTEROPTIONS), &rect); + + menu = PhCreateEMenu(); + + PhInsertEMenuItem(menu, freeItem = PhCreateEMenuItem(0, PH_MEMORY_FLAGS_FREE_OPTION, L"Hide free", NULL, NULL), -1); + PhInsertEMenuItem(menu, reservedItem = PhCreateEMenuItem(0, PH_MEMORY_FLAGS_RESERVED_OPTION, L"Hide reserved", NULL, NULL), -1); + PhInsertEMenuItem(menu, PhCreateEMenuItem(PH_EMENU_SEPARATOR, 0, NULL, NULL, NULL), -1); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, IDC_STRINGS, L"Strings...", NULL, NULL), -1); + + if (memoryContext->ListContext.HideFreeRegions) + freeItem->Flags |= PH_EMENU_CHECKED; + + if (memoryContext->ListContext.HideReservedRegions) + reservedItem->Flags |= PH_EMENU_CHECKED; + + selectedItem = PhShowEMenu( + menu, + hwndDlg, + PH_EMENU_SHOW_LEFTRIGHT, + PH_ALIGN_LEFT | PH_ALIGN_TOP, + rect.left, + rect.bottom + ); + + if (selectedItem && selectedItem->Id) + { + if (selectedItem->Id == IDC_STRINGS) + { + PhShowMemoryStringDialog(hwndDlg, processItem); + } + else + { + PhSetOptionsMemoryList(&memoryContext->ListContext, selectedItem->Id); + PhSaveSettingsMemoryList(&memoryContext->ListContext); + + PhApplyTreeNewFilters(&memoryContext->ListContext.AllocationTreeFilterSupport); + PhApplyTreeNewFilters(&memoryContext->ListContext.TreeFilterSupport); + } + } + + PhDestroyEMenu(menu); } break; - case IDC_STRINGS: - PhShowMemoryStringDialog(hwndDlg, processItem); - break; - case IDC_REFRESH: - PhpRefreshProcessMemoryList(hwndDlg, propPageContext); - break; } } break; diff --git a/ProcessHacker/prpgmod.c b/ProcessHacker/prpgmod.c index 2dfe11953520..718ed4023619 100644 --- a/ProcessHacker/prpgmod.c +++ b/ProcessHacker/prpgmod.c @@ -3,6 +3,7 @@ * Process properties: Modules page * * Copyright (C) 2009-2016 wj32 + * Copyright (C) 2017 dmex * * This file is part of Process Hacker. * diff --git a/ProcessHacker/settings.c b/ProcessHacker/settings.c index 705ffe6b8ac7..547591b0f0fd 100644 --- a/ProcessHacker/settings.c +++ b/ProcessHacker/settings.c @@ -93,6 +93,7 @@ VOID PhAddDefaultSettings( PhpAddStringSetting(L"MemResultsListViewColumns", L""); PhpAddIntegerPairSetting(L"MemResultsPosition", L"300,300"); PhpAddScalableIntegerPairSetting(L"MemResultsSize", L"@96|500,520"); + PhpAddIntegerSetting(L"MemoryListFlags", L"3"); PhpAddStringSetting(L"MemoryTreeListColumns", L""); PhpAddStringSetting(L"MemoryTreeListSort", L"0,0"); // 0, NoSortOrder PhpAddIntegerPairSetting(L"MemoryListsWindowPosition", L"400,400"); From bcca76e5e1e8393acd0703a4f482b8868c7926ff Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 3 Jun 2017 20:24:36 +1000 Subject: [PATCH 0185/2058] Fix search memory leak, Fix module tab settings, Fix memory window opening behind properties window --- ProcessHacker/hndllist.c | 2 ++ ProcessHacker/memrslt.c | 1 + ProcessHacker/modlist.c | 10 ++++++++++ ProcessHacker/prpgmod.c | 13 +++++-------- 4 files changed, 18 insertions(+), 8 deletions(-) diff --git a/ProcessHacker/hndllist.c b/ProcessHacker/hndllist.c index 6777cefe7159..d3a09bd54bbe 100644 --- a/ProcessHacker/hndllist.c +++ b/ProcessHacker/hndllist.c @@ -121,6 +121,8 @@ VOID PhDeleteHandleList( { ULONG i; + PhDeleteTreeNewFilterSupport(&Context->TreeFilterSupport); + PhCmDeleteManager(&Context->Cm); for (i = 0; i < Context->NodeList->Count; i++) diff --git a/ProcessHacker/memrslt.c b/ProcessHacker/memrslt.c index 28c177c91ede..3ea48045760c 100644 --- a/ProcessHacker/memrslt.c +++ b/ProcessHacker/memrslt.c @@ -81,6 +81,7 @@ VOID PhShowMemoryResultsDialog( (LPARAM)context ); ShowWindow(windowHandle, SW_SHOW); + SetForegroundWindow(windowHandle); } static PPH_STRING PhpGetStringForSelectedResults( diff --git a/ProcessHacker/modlist.c b/ProcessHacker/modlist.c index 69ed34407c4d..15df0c622cac 100644 --- a/ProcessHacker/modlist.c +++ b/ProcessHacker/modlist.c @@ -131,6 +131,8 @@ VOID PhDeleteModuleList( { ULONG i; + PhDeleteTreeNewFilterSupport(&Context->TreeFilterSupport); + if (Context->BoldFont) DeleteObject(Context->BoldFont); @@ -165,12 +167,17 @@ VOID PhLoadSettingsModuleList( _Inout_ PPH_MODULE_LIST_CONTEXT Context ) { + ULONG flags; PPH_STRING settings; PPH_STRING sortSettings; + flags = PhGetIntegerSetting(L"ModuleListFlags"); settings = PhGetStringSetting(L"ModuleTreeListColumns"); sortSettings = PhGetStringSetting(L"ModuleTreeListSort"); + + Context->Flags = flags; PhCmLoadSettingsEx(Context->TreeNewHandle, &Context->Cm, 0, &settings->sr, &sortSettings->sr); + PhDereferenceObject(settings); PhDereferenceObject(sortSettings); } @@ -183,8 +190,11 @@ VOID PhSaveSettingsModuleList( PPH_STRING sortSettings; settings = PhCmSaveSettingsEx(Context->TreeNewHandle, &Context->Cm, 0, &sortSettings); + + PhSetIntegerSetting(L"ModuleListFlags", Context->Flags); PhSetStringSetting2(L"ModuleTreeListColumns", &settings->sr); PhSetStringSetting2(L"ModuleTreeListSort", &sortSettings->sr); + PhDereferenceObject(settings); PhDereferenceObject(sortSettings); } diff --git a/ProcessHacker/prpgmod.c b/ProcessHacker/prpgmod.c index 718ed4023619..2b2e217827c4 100644 --- a/ProcessHacker/prpgmod.c +++ b/ProcessHacker/prpgmod.c @@ -488,8 +488,6 @@ INT_PTR CALLBACK PhpProcessModulesDlgProc( PhLoadSettingsModuleList(&modulesContext->ListContext); - modulesContext->ListContext.Flags = PhGetIntegerSetting(L"ModuleListFlags"); - PhSetEnabledProvider(&modulesContext->ProviderRegistration, TRUE); PhBoostProvider(&modulesContext->ProviderRegistration, NULL); @@ -572,11 +570,8 @@ INT_PTR CALLBACK PhpProcessModulesDlgProc( // Cache the current search text for our callback. PhMoveReference(&modulesContext->SearchboxText, newSearchboxText); - if (!PhIsNullOrEmptyString(modulesContext->SearchboxText)) - { - // Expand any hidden nodes to make search results visible. - PhExpandAllModuleNodes(&modulesContext->ListContext, TRUE); - } + // Expand any hidden nodes to make search results visible. + PhExpandAllModuleNodes(&modulesContext->ListContext, TRUE); PhApplyTreeNewFilters(&modulesContext->ListContext.TreeFilterSupport); } @@ -704,7 +699,9 @@ INT_PTR CALLBACK PhpProcessModulesDlgProc( if (selectedItem && selectedItem->Id) { PhSetOptionsModuleList(&modulesContext->ListContext, selectedItem->Id); - PhSetIntegerSetting(L"ModuleListFlags", modulesContext->ListContext.Flags); + + PhSaveSettingsModuleList(&modulesContext->ListContext); + PhApplyTreeNewFilters(&modulesContext->ListContext.TreeFilterSupport); } From 7feef2167de90ce906f71670a2cc8bb5a0ca1f40 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 3 Jun 2017 21:34:53 +1000 Subject: [PATCH 0186/2058] Update memory tab options --- ProcessHacker/ProcessHacker.rc | 1 - ProcessHacker/include/memlist.h | 10 +- ProcessHacker/memlist.c | 44 +++++++-- ProcessHacker/prpgmem.c | 166 +++++++++++++++++++------------- ProcessHacker/resource.h | 2 - 5 files changed, 144 insertions(+), 79 deletions(-) diff --git a/ProcessHacker/ProcessHacker.rc b/ProcessHacker/ProcessHacker.rc index 8a95c77ff329..b372627fd3a0 100644 --- a/ProcessHacker/ProcessHacker.rc +++ b/ProcessHacker/ProcessHacker.rc @@ -440,7 +440,6 @@ BEGIN MENUITEM "&Free", ID_MEMORY_FREE MENUITEM "&Decommit", ID_MEMORY_DECOMMIT MENUITEM SEPARATOR - MENUITEM "Read/Write &address...", ID_MEMORY_READWRITEADDRESS MENUITEM "&Copy\aCtrl+C", ID_MEMORY_COPY END END diff --git a/ProcessHacker/include/memlist.h b/ProcessHacker/include/memlist.h index ed3712834558..482f485a62cd 100644 --- a/ProcessHacker/include/memlist.h +++ b/ProcessHacker/include/memlist.h @@ -55,6 +55,10 @@ typedef struct _PH_MEMORY_NODE #define PH_MEMORY_FLAGS_FREE_OPTION 1 #define PH_MEMORY_FLAGS_RESERVED_OPTION 2 +#define PH_MEMORY_FLAGS_PRIVATE_OPTION 3 +#define PH_MEMORY_FLAGS_SYSTEM_OPTION 4 +#define PH_MEMORY_FLAGS_CFG_OPTION 5 +#define PH_MEMORY_FLAGS_EXECUTE_OPTION 6 typedef struct _PH_MEMORY_LIST_CONTEXT { @@ -73,7 +77,11 @@ typedef struct _PH_MEMORY_LIST_CONTEXT { ULONG HideFreeRegions : 1; ULONG HideReservedRegions : 1; - ULONG Spare : 30; + ULONG HighlightPrivatePages : 1; + ULONG HighlightSystemPages : 1; + ULONG HighlightCfgPages : 1; + ULONG HighlightExecutePages : 1; + ULONG Spare : 26; }; }; diff --git a/ProcessHacker/memlist.c b/ProcessHacker/memlist.c index cd69766e2e9b..078103a54ede 100644 --- a/ProcessHacker/memlist.c +++ b/ProcessHacker/memlist.c @@ -180,6 +180,18 @@ VOID PhSetOptionsMemoryList( case PH_MEMORY_FLAGS_RESERVED_OPTION: Context->HideReservedRegions = !Context->HideReservedRegions; break; + case PH_MEMORY_FLAGS_PRIVATE_OPTION: + Context->HighlightPrivatePages = !Context->HighlightPrivatePages; + break; + case PH_MEMORY_FLAGS_SYSTEM_OPTION: + Context->HighlightSystemPages = !Context->HighlightSystemPages; + break; + case PH_MEMORY_FLAGS_CFG_OPTION: + Context->HighlightCfgPages = !Context->HighlightCfgPages; + break; + case PH_MEMORY_FLAGS_EXECUTE_OPTION: + Context->HighlightExecutePages = !Context->HighlightExecutePages; + break; } } @@ -780,7 +792,29 @@ BOOLEAN NTAPI PhpMemoryTreeNewCallback( memoryItem = node->MemoryItem; if (!memoryItem) - ; // Dummy + NOTHING; + else if (context->HighlightExecutePages && ( + memoryItem->Protect & PAGE_EXECUTE || + memoryItem->Protect & PAGE_EXECUTE_READ || + memoryItem->Protect & PAGE_EXECUTE_READWRITE || + memoryItem->Protect & PAGE_EXECUTE_WRITECOPY)) + { + getNodeColor->BackColor = PhCsColorPacked; + } + else if (context->HighlightCfgPages && ( + memoryItem->RegionType == CfgBitmapRegion || + memoryItem->RegionType == CfgBitmap32Region)) + { + getNodeColor->BackColor = PhCsColorElevatedProcesses; + } + else if (context->HighlightSystemPages && memoryItem->Type & MEM_MAPPED) + { + getNodeColor->BackColor = PhCsColorSystemProcesses; + } + else if (context->HighlightPrivatePages && memoryItem->Type & MEM_PRIVATE) + { + getNodeColor->BackColor = PhCsColorOwnProcesses; + } //else if ( // memoryItem->RegionType == StackRegion || memoryItem->RegionType == Stack32Region || // memoryItem->RegionType == HeapRegion || memoryItem->RegionType == Heap32Region || @@ -791,16 +825,10 @@ BOOLEAN NTAPI PhpMemoryTreeNewCallback( //{ // getNodeColor->BackColor = PhCsColorElevatedProcesses; //} - //else if (memoryItem->RegionType == CfgBitmapRegion || memoryItem->RegionType == CfgBitmap32Region) - // getNodeColor->BackColor = PhCsColorProtectedHandles; - //else if (memoryItem->Type & MEM_PRIVATE) - // getNodeColor->BackColor = PhCsColorOwnProcesses; - //else if (memoryItem->Type & MEM_MAPPED) - // getNodeColor->BackColor = PhCsColorSystemProcesses; //else if (memoryItem->Type & SEC_IMAGE) // getNodeColor->BackColor = PhCsColorImmersiveProcesses; - getNodeColor->Flags = TN_CACHE | TN_AUTO_FORECOLOR; + getNodeColor->Flags = TN_AUTO_FORECOLOR; } return TRUE; case TreeNewSortChanged: diff --git a/ProcessHacker/prpgmem.c b/ProcessHacker/prpgmem.c index 0e70f9caadab..b6fed9159545 100644 --- a/ProcessHacker/prpgmem.c +++ b/ProcessHacker/prpgmem.c @@ -129,8 +129,6 @@ VOID PhpInitializeMemoryMenu( if (numberOfAllocationBase == 0 || numberOfAllocationBase == NumberOfMemoryNodes) PhEnableEMenuItem(Menu, ID_MEMORY_SAVE, TRUE); } - - PhEnableEMenuItem(Menu, ID_MEMORY_READWRITEADDRESS, TRUE); } VOID PhShowMemoryContextMenu( @@ -590,60 +588,6 @@ INT_PTR CALLBACK PhpProcessMemoryDlgProc( } } break; - case ID_MEMORY_READWRITEADDRESS: - { - PPH_STRING selectedChoice = NULL; - - if (!memoryContext->MemoryItemListValid) - break; - - while (PhaChoiceDialog( - hwndDlg, - L"Read/Write Address", - L"Enter an address:", - NULL, - 0, - NULL, - PH_CHOICE_DIALOG_USER_CHOICE, - &selectedChoice, - NULL, - L"MemoryReadWriteAddressChoices" - )) - { - ULONG64 address64; - PVOID address; - - if (selectedChoice->Length == 0) - continue; - - if (PhStringToInteger64(&selectedChoice->sr, 0, &address64)) - { - PPH_MEMORY_ITEM memoryItem; - - address = (PVOID)address64; - memoryItem = PhLookupMemoryItemList(&memoryContext->MemoryItemList, address); - - if (memoryItem) - { - PPH_SHOW_MEMORY_EDITOR showMemoryEditor = PhAllocate(sizeof(PH_SHOW_MEMORY_EDITOR)); - - memset(showMemoryEditor, 0, sizeof(PH_SHOW_MEMORY_EDITOR)); - showMemoryEditor->ProcessId = processItem->ProcessId; - showMemoryEditor->BaseAddress = memoryItem->BaseAddress; - showMemoryEditor->RegionSize = memoryItem->RegionSize; - showMemoryEditor->SelectOffset = (ULONG)((ULONG_PTR)address - (ULONG_PTR)memoryItem->BaseAddress); - showMemoryEditor->SelectLength = 0; - ProcessHacker_ShowMemoryEditor(PhMainWndHandle, showMemoryEditor); - break; - } - else - { - PhShowError(hwndDlg, L"Unable to find the memory region for the selected address."); - } - } - } - } - break; case ID_MEMORY_COPY: { PPH_STRING text; @@ -662,22 +606,52 @@ INT_PTR CALLBACK PhpProcessMemoryDlgProc( PPH_EMENU menu; PPH_EMENU_ITEM freeItem; PPH_EMENU_ITEM reservedItem; + PPH_EMENU_ITEM privateItem; + PPH_EMENU_ITEM systemItem; + PPH_EMENU_ITEM cfgItem; + PPH_EMENU_ITEM typeItem; PPH_EMENU_ITEM selectedItem; GetWindowRect(GetDlgItem(hwndDlg, IDC_FILTEROPTIONS), &rect); menu = PhCreateEMenu(); - PhInsertEMenuItem(menu, freeItem = PhCreateEMenuItem(0, PH_MEMORY_FLAGS_FREE_OPTION, L"Hide free", NULL, NULL), -1); - PhInsertEMenuItem(menu, reservedItem = PhCreateEMenuItem(0, PH_MEMORY_FLAGS_RESERVED_OPTION, L"Hide reserved", NULL, NULL), -1); + typedef enum _PH_MEMORY_FILTER_MENU_ITEM + { + PH_MEMORY_FILTER_MENU_HIDE_FREE = 1, + PH_MEMORY_FILTER_MENU_HIDE_RESERVED, + PH_MEMORY_FILTER_MENU_HIGHLIGHT_PRIVATE, + PH_MEMORY_FILTER_MENU_HIGHLIGHT_SYSTEM, + PH_MEMORY_FILTER_MENU_HIGHLIGHT_CFG, + PH_MEMORY_FILTER_MENU_HIGHLIGHT_EXECUTE, + PH_MEMORY_FILTER_MENU_READ_ADDRESS, + PH_MEMORY_FILTER_MENU_STRINGS, + } PH_MEMORY_FILTER_MENU_ITEM; + + PhInsertEMenuItem(menu, freeItem = PhCreateEMenuItem(0, PH_MEMORY_FILTER_MENU_HIDE_FREE, L"Hide free pages", NULL, NULL), -1); + PhInsertEMenuItem(menu, reservedItem = PhCreateEMenuItem(0, PH_MEMORY_FILTER_MENU_HIDE_RESERVED, L"Hide reserved pages", NULL, NULL), -1); PhInsertEMenuItem(menu, PhCreateEMenuItem(PH_EMENU_SEPARATOR, 0, NULL, NULL, NULL), -1); - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, IDC_STRINGS, L"Strings...", NULL, NULL), -1); - - if (memoryContext->ListContext.HideFreeRegions) - freeItem->Flags |= PH_EMENU_CHECKED; + PhInsertEMenuItem(menu, privateItem = PhCreateEMenuItem(0, PH_MEMORY_FILTER_MENU_HIGHLIGHT_PRIVATE, L"Highlight private pages", NULL, NULL), -1); + PhInsertEMenuItem(menu, systemItem = PhCreateEMenuItem(0, PH_MEMORY_FILTER_MENU_HIGHLIGHT_SYSTEM, L"Highlight system pages", NULL, NULL), -1); + PhInsertEMenuItem(menu, cfgItem = PhCreateEMenuItem(0, PH_MEMORY_FILTER_MENU_HIGHLIGHT_CFG, L"Highlight CFG pages", NULL, NULL), -1); + PhInsertEMenuItem(menu, typeItem = PhCreateEMenuItem(0, PH_MEMORY_FILTER_MENU_HIGHLIGHT_EXECUTE, L"Highlight executable pages", NULL, NULL), -1); + PhInsertEMenuItem(menu, PhCreateEMenuItem(PH_EMENU_SEPARATOR, 0, NULL, NULL, NULL), -1); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, PH_MEMORY_FILTER_MENU_READ_ADDRESS, L"Read/Write &address...", NULL, NULL), -1); + PhInsertEMenuItem(menu, PhCreateEMenuItem(PH_EMENU_SEPARATOR, 0, NULL, NULL, NULL), -1); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, PH_MEMORY_FILTER_MENU_STRINGS, L"Strings...", NULL, NULL), -1); + if (memoryContext->ListContext.HideFreeRegions) + freeItem->Flags |= PH_EMENU_CHECKED; if (memoryContext->ListContext.HideReservedRegions) reservedItem->Flags |= PH_EMENU_CHECKED; + if (memoryContext->ListContext.HighlightPrivatePages) + privateItem->Flags |= PH_EMENU_CHECKED; + if (memoryContext->ListContext.HighlightSystemPages) + systemItem->Flags |= PH_EMENU_CHECKED; + if (memoryContext->ListContext.HighlightCfgPages) + cfgItem->Flags |= PH_EMENU_CHECKED; + if (memoryContext->ListContext.HighlightExecutePages) + typeItem->Flags |= PH_EMENU_CHECKED; selectedItem = PhShowEMenu( menu, @@ -690,11 +664,12 @@ INT_PTR CALLBACK PhpProcessMemoryDlgProc( if (selectedItem && selectedItem->Id) { - if (selectedItem->Id == IDC_STRINGS) - { - PhShowMemoryStringDialog(hwndDlg, processItem); - } - else + if (selectedItem->Id == PH_MEMORY_FILTER_MENU_HIDE_FREE || + selectedItem->Id == PH_MEMORY_FILTER_MENU_HIDE_RESERVED || + selectedItem->Id == PH_MEMORY_FILTER_MENU_HIGHLIGHT_PRIVATE || + selectedItem->Id == PH_MEMORY_FILTER_MENU_HIGHLIGHT_SYSTEM || + selectedItem->Id == PH_MEMORY_FILTER_MENU_HIGHLIGHT_CFG || + selectedItem->Id == PH_MEMORY_FILTER_MENU_HIGHLIGHT_EXECUTE) { PhSetOptionsMemoryList(&memoryContext->ListContext, selectedItem->Id); PhSaveSettingsMemoryList(&memoryContext->ListContext); @@ -702,6 +677,63 @@ INT_PTR CALLBACK PhpProcessMemoryDlgProc( PhApplyTreeNewFilters(&memoryContext->ListContext.AllocationTreeFilterSupport); PhApplyTreeNewFilters(&memoryContext->ListContext.TreeFilterSupport); } + else if (selectedItem->Id == PH_MEMORY_FILTER_MENU_STRINGS) + { + PhShowMemoryStringDialog(hwndDlg, processItem); + } + else if (selectedItem->Id == PH_MEMORY_FILTER_MENU_READ_ADDRESS) + { + PPH_STRING selectedChoice = NULL; + + if (!memoryContext->MemoryItemListValid) + break; + + while (PhaChoiceDialog( + hwndDlg, + L"Read/Write Address", + L"Enter an address:", + NULL, + 0, + NULL, + PH_CHOICE_DIALOG_USER_CHOICE, + &selectedChoice, + NULL, + L"MemoryReadWriteAddressChoices" + )) + { + ULONG64 address64; + PVOID address; + + if (selectedChoice->Length == 0) + continue; + + if (PhStringToInteger64(&selectedChoice->sr, 0, &address64)) + { + PPH_MEMORY_ITEM memoryItem; + + address = (PVOID)address64; + memoryItem = PhLookupMemoryItemList(&memoryContext->MemoryItemList, address); + + if (memoryItem) + { + PPH_SHOW_MEMORY_EDITOR showMemoryEditor = PhAllocate(sizeof(PH_SHOW_MEMORY_EDITOR)); + + memset(showMemoryEditor, 0, sizeof(PH_SHOW_MEMORY_EDITOR)); + showMemoryEditor->ProcessId = processItem->ProcessId; + showMemoryEditor->BaseAddress = memoryItem->BaseAddress; + showMemoryEditor->RegionSize = memoryItem->RegionSize; + showMemoryEditor->SelectOffset = (ULONG)((ULONG_PTR)address - (ULONG_PTR)memoryItem->BaseAddress); + showMemoryEditor->SelectLength = 0; + ProcessHacker_ShowMemoryEditor(PhMainWndHandle, showMemoryEditor); + break; + } + else + { + PhShowError(hwndDlg, L"Unable to find the memory region for the selected address."); + } + } + } + } } PhDestroyEMenu(menu); diff --git a/ProcessHacker/resource.h b/ProcessHacker/resource.h index 07b320db4642..0b906b03259b 100644 --- a/ProcessHacker/resource.h +++ b/ProcessHacker/resource.h @@ -405,7 +405,6 @@ #define IDC_PRIVATE 1238 #define IDC_IMAGE 1239 #define IDC_MAPPED 1240 -#define IDC_STRINGS 1242 #define IDC_SHOWTEXT 1245 #define IDC_ICONPROCESSES 1248 #define IDC_CLEANUP 1251 @@ -681,7 +680,6 @@ #define ID_MEMORY_DECOMMIT 40211 #define ID_MEMORY_COPY 40213 #define ID_MEMORY_READWRITEMEMORY 40214 -#define ID_MEMORY_READWRITEADDRESS 40215 #define ID_FILTER_CONTAINS 40216 #define ID_FILTER_CONTAINS_CASEINSENSITIVE 40218 #define ID_FILTER_REGEX 40219 From 466d598f48b229463b8ee7fa31e0e775db8e73e0 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 4 Jun 2017 04:24:59 +1000 Subject: [PATCH 0187/2058] Update token properties splitter control --- ProcessHacker/include/splitter.h | 48 +--- ProcessHacker/splitter.c | 440 +++++++++++++++++-------------- ProcessHacker/tokprp.c | 9 - 3 files changed, 256 insertions(+), 241 deletions(-) diff --git a/ProcessHacker/include/splitter.h b/ProcessHacker/include/splitter.h index c1d6fcb4a3dd..9be37f0023cd 100644 --- a/ProcessHacker/include/splitter.h +++ b/ProcessHacker/include/splitter.h @@ -9,25 +9,23 @@ typedef struct _PH_HSPLITTER_CONTEXT struct { ULONG Hot : 1; - ULONG Pushed : 1; - ULONG Moved : 1; - ULONG DragMode : 1; - ULONG Spare : 28; + ULONG HasFocus : 1; + ULONG Spare : 30; }; }; LONG SplitterOffset; - LONG SplitterPosition; - PH_LAYOUT_MANAGER LayoutManager; - PPH_LAYOUT_ITEM Topitem; - PPH_LAYOUT_ITEM Bottomitem; + HWND Window; + HWND ParentWindow; + HWND TopWindow; + HWND BottomWindow; } PH_HSPLITTER_CONTEXT, *PPH_HSPLITTER_CONTEXT; PPH_HSPLITTER_CONTEXT PhInitializeHSplitter( - _In_ HWND Parent, - _In_ HWND TopChild, - _In_ HWND BottomChild + _In_ HWND ParentWindow, + _In_ HWND TopWindow, + _In_ HWND BottomWindow ); VOID PhDeleteHSplitter( @@ -40,32 +38,4 @@ VOID PhHSplitterHandleWmSize( _In_ INT Height ); -VOID PhHSplitterHandleLButtonDown( - _Inout_ PPH_HSPLITTER_CONTEXT Context, - _In_ HWND hwnd, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -VOID PhHSplitterHandleLButtonUp( - _Inout_ PPH_HSPLITTER_CONTEXT Context, - _In_ HWND hwnd, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -VOID PhHSplitterHandleMouseMove( - _Inout_ PPH_HSPLITTER_CONTEXT Context, - _In_ HWND hwnd, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -VOID PhHSplitterHandleMouseLeave( - _Inout_ PPH_HSPLITTER_CONTEXT Context, - _In_ HWND hwnd, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - #endif diff --git a/ProcessHacker/splitter.c b/ProcessHacker/splitter.c index f07d3a0d45f5..930ebb1d450a 100644 --- a/ProcessHacker/splitter.c +++ b/ProcessHacker/splitter.c @@ -27,244 +27,298 @@ #include #define SPLITTER_PADDING 6 -#define SPLITTER_MIN_HEIGHT 200 -VOID DrawXorBar(HDC hdc, INT x1, INT y1, INT width, INT height); - -PPH_HSPLITTER_CONTEXT PhInitializeHSplitter( - _In_ HWND Parent, - _In_ HWND TopChild, - _In_ HWND BottomChild - ) +LONG GetWindowWidth(HWND hwnd) { - PPH_HSPLITTER_CONTEXT context; - - context = PhAllocate(sizeof(PH_HSPLITTER_CONTEXT)); - memset(context, 0, sizeof(PH_HSPLITTER_CONTEXT)); - - PhInitializeLayoutManager(&context->LayoutManager, Parent); - - context->SplitterOffset = -4; - context->SplitterPosition = 250;// PhGetIntegerSetting(L"TokenSplitterPosition"); - context->Topitem = PhAddLayoutItem(&context->LayoutManager, TopChild, NULL, PH_ANCHOR_ALL); - context->Bottomitem = PhAddLayoutItem(&context->LayoutManager, BottomChild, NULL, PH_ANCHOR_ALL); + RECT Rect; - return context; + GetWindowRect(hwnd, &Rect); + return (Rect.right - Rect.left); } -VOID PhDeleteHSplitter( - _Inout_ PPH_HSPLITTER_CONTEXT Context - ) +LONG GetWindowHeight(HWND hwnd) { - PhSetIntegerSetting(L"TokenSplitterPosition", Context->SplitterPosition); - - PhDeleteLayoutManager(&Context->LayoutManager); -} + RECT Rect; -VOID PhHSplitterHandleWmSize( - _Inout_ PPH_HSPLITTER_CONTEXT Context, - _In_ INT Width, - _In_ INT Height - ) -{ - // HACK: Use the PH layout manager as the 'splitter' control by abusing layout margins. - - // BUG: If the window is maximized and you move the splitter to the bottom, restoring the window causes - // the bottom control to get moved outside the visible area... Just move the splitter back up. - if ((Context->Bottomitem->Rect.bottom - Context->Bottomitem->Rect.top) <= 100) - Context->SplitterPosition = Context->Topitem->Rect.bottom - Context->Topitem->Rect.top - SPLITTER_PADDING; - - // Set the bottom margin of the top control. - Context->Topitem->Margin.bottom = Height - Context->SplitterPosition - SPLITTER_PADDING; - // Set the top margin of the bottom control. - Context->Bottomitem->Margin.top = Context->SplitterPosition + SPLITTER_PADDING * 2; - - PhLayoutManagerLayout(&Context->LayoutManager); + GetWindowRect(hwnd, &Rect); + return (Rect.bottom - Rect.top); } -VOID PhHSplitterHandleLButtonDown( - _Inout_ PPH_HSPLITTER_CONTEXT Context, - _In_ HWND hwnd, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) +LONG GetClientWindowWidth(HWND hwnd) { - POINT pt; - HDC hdc; - RECT rect; - - pt.x = GET_X_LPARAM(lParam); - pt.y = GET_Y_LPARAM(lParam); + RECT Rect; - GetWindowRect(hwnd, &rect); - ClientToScreen(hwnd, &pt); - - pt.x -= rect.left; - pt.y -= rect.top; - - // Adjust the coordinates (start from 0,0). - OffsetRect(&rect, -rect.left, -rect.top); - - if (pt.y < Context->Topitem->OrigRect.top * 2) - pt.y = Context->Topitem->OrigRect.top * 2; - if (pt.y > Context->Bottomitem->Rect.bottom - SPLITTER_MIN_HEIGHT) - pt.y = Context->Bottomitem->Rect.bottom - SPLITTER_MIN_HEIGHT; - - Context->DragMode = TRUE; - SetCapture(hwnd); - - hdc = GetWindowDC(hwnd); - DrawXorBar(hdc, 1, pt.y - 2, rect.right - 2, 4); - ReleaseDC(hwnd, hdc); - - Context->SplitterOffset = pt.y; + GetClientRect(hwnd, &Rect); + return (Rect.right - Rect.left); } -VOID PhHSplitterHandleLButtonUp( - _Inout_ PPH_HSPLITTER_CONTEXT Context, - _In_ HWND hwnd, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) +LONG GetClientWindowHeight(HWND hwnd) { - HDC hdc; - RECT rect; - POINT pt; - - pt.x = GET_X_LPARAM(lParam); - pt.y = GET_Y_LPARAM(lParam); - - if (!Context->DragMode) - return; - - GetWindowRect(hwnd, &rect); - ClientToScreen(hwnd, &pt); - - pt.x -= rect.left; - pt.y -= rect.top; - - // Adjust the coordinates (start from 0,0). - OffsetRect(&rect, -rect.left, -rect.top); + RECT Rect; - if (pt.y < Context->Topitem->OrigRect.top * 2) - pt.y = Context->Topitem->OrigRect.top * 2; - if (pt.y > Context->Bottomitem->Rect.bottom - SPLITTER_MIN_HEIGHT) - pt.y = Context->Bottomitem->Rect.bottom - SPLITTER_MIN_HEIGHT; - - hdc = GetWindowDC(hwnd); - DrawXorBar(hdc, 1, Context->SplitterOffset - 2, rect.right - 2, 4); - ReleaseDC(hwnd, hdc); - - Context->SplitterOffset = pt.y; - - Context->DragMode = FALSE; - - GetWindowRect(hwnd, &rect); - pt.x += rect.left; - pt.y += rect.top; - ScreenToClient(hwnd, &pt); - GetClientRect(hwnd, &rect); - - Context->SplitterPosition = pt.y; - - // position the child controls - PhHSplitterHandleWmSize(Context, rect.right, rect.bottom); - - ReleaseCapture(); + GetClientRect(hwnd, &Rect); + return (Rect.bottom - Rect.top); } -VOID PhHSplitterHandleMouseMove( - _Inout_ PPH_HSPLITTER_CONTEXT Context, - _In_ HWND hwnd, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) +LRESULT CALLBACK HSplitterWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { - HDC hdc; - RECT windowRect; - POINT windowPoint; + PPH_HSPLITTER_CONTEXT context = NULL; - windowPoint.x = GET_X_LPARAM(lParam); - windowPoint.y = GET_Y_LPARAM(lParam); + if (uMsg == WM_CREATE) + { + LPCREATESTRUCT cs = (LPCREATESTRUCT)lParam; + context = cs->lpCreateParams; + SetProp(hwnd, PhMakeContextAtom(), (HANDLE)context); + } + else + { + context = (PPH_HSPLITTER_CONTEXT)GetProp(hwnd, PhMakeContextAtom()); + } - GetWindowRect(hwnd, &windowRect); - ClientToScreen(hwnd, &windowPoint); + if (!context) + return DefWindowProc(hwnd, uMsg, wParam, lParam); - if (Context->DragMode) + switch (uMsg) { - windowPoint.x -= windowRect.left; - windowPoint.y -= windowRect.top; + case WM_PAINT: + { + PAINTSTRUCT paintStruct; + RECT clientRect; + HDC hdc; - OffsetRect(&windowRect, -windowRect.left, -windowRect.top); + if (hdc = BeginPaint(hwnd, &paintStruct)) + { + GetClientRect(hwnd, &clientRect); - if (windowPoint.y < Context->Topitem->OrigRect.top * 2) - windowPoint.y = Context->Topitem->OrigRect.top * 2; - if (windowPoint.y > Context->Bottomitem->Rect.bottom - SPLITTER_MIN_HEIGHT) - windowPoint.y = Context->Bottomitem->Rect.bottom - SPLITTER_MIN_HEIGHT; + if (context->HasFocus) + FillRect(hdc, &clientRect, CreateSolidBrush(RGB(0x0, 0x0, 0x0))); + else if (context->Hot) + FillRect(hdc, &clientRect, CreateSolidBrush(RGB(0x44, 0x44, 0x44))); + else + FillRect(hdc, &clientRect, GetSysColorBrush(COLOR_WINDOW)); - if (windowPoint.y != Context->SplitterOffset) + EndPaint(hwnd, &paintStruct); + } + } + return 0; + case WM_ERASEBKGND: + return 1; + case WM_LBUTTONDOWN: { - hdc = GetWindowDC(hwnd); + context->HasFocus = TRUE; - if (wParam & MK_LBUTTON) + SetCapture(hwnd); + + InvalidateRect(hwnd, NULL, TRUE); + } + break; + case WM_LBUTTONUP: + case WM_RBUTTONDOWN: + { + if (GetCapture() == hwnd) { - DrawXorBar(hdc, 1, Context->SplitterOffset - 2, windowRect.right - 2, 4); - DrawXorBar(hdc, 1, windowPoint.y - 2, windowRect.right - 2, 4); + ReleaseCapture(); + + context->HasFocus = FALSE; + + InvalidateRect(hwnd, NULL, TRUE); } - else + } + break; + case WM_MOUSELEAVE: + { + context->Hot = FALSE; + InvalidateRect(hwnd, NULL, TRUE); + } + break; + case WM_SETFOCUS: + { + context->HasFocus = TRUE; + InvalidateRect(hwnd, NULL, TRUE); + } + return 0; + case WM_KILLFOCUS: + { + context->HasFocus = FALSE; + InvalidateRect(hwnd, NULL, TRUE); + } + return 0; + case WM_MOUSEMOVE: + { + if (!context->Hot) { - TRACKMOUSEEVENT trackMouseEvent; - - trackMouseEvent.cbSize = sizeof(TRACKMOUSEEVENT); + TRACKMOUSEEVENT trackMouseEvent = { sizeof(trackMouseEvent) }; + context->Hot = TRUE; + InvalidateRect(hwnd, NULL, TRUE); trackMouseEvent.dwFlags = TME_LEAVE; trackMouseEvent.hwndTrack = hwnd; - trackMouseEvent.dwHoverTime = 0; - - SetCursor(LoadCursor(NULL, IDC_SIZENS)); - TrackMouseEvent(&trackMouseEvent); } - ReleaseDC(hwnd, hdc); - Context->SplitterOffset = windowPoint.y; + if (!context->HasFocus) + break; + + int Width = GetClientWindowWidth(context->ParentWindow); + int NewPos; + HDWP deferHandle; + POINT cursorPos; + + GetCursorPos(&cursorPos); + ScreenToClient(context->ParentWindow, &cursorPos); + NewPos = cursorPos.y; + + if (NewPos < 200) + break; + if (NewPos > GetClientWindowHeight(context->ParentWindow) - 80) + break; + context->SplitterOffset = NewPos; + + deferHandle = BeginDeferWindowPos(3); + DeferWindowPos( + deferHandle, + context->TopWindow, + NULL, + SPLITTER_PADDING, + 90, + Width - SPLITTER_PADDING * 2, + cursorPos.y - 90, + SWP_NOZORDER | SWP_NOACTIVATE + ); + DeferWindowPos( + deferHandle, + context->Window, + NULL, + 0, + cursorPos.y, + Width, + SPLITTER_PADDING, + SWP_NOZORDER | SWP_NOACTIVATE + ); + DeferWindowPos( + deferHandle, + context->BottomWindow, + NULL, + SPLITTER_PADDING, + cursorPos.y + SPLITTER_PADDING, + Width - SPLITTER_PADDING * 2, + GetClientWindowHeight(context->ParentWindow) - (cursorPos.y + SPLITTER_PADDING) - 65, + SWP_NOZORDER | SWP_NOACTIVATE + ); + + EndDeferWindowPos(deferHandle); } + break; } -} -VOID PhHSplitterHandleMouseLeave( - _Inout_ PPH_HSPLITTER_CONTEXT Context, - _In_ HWND hwnd, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - // Reset the original cursor. - SetCursor(LoadCursor(NULL, IDC_ARROW)); + return DefWindowProc(hwnd, uMsg, wParam, lParam); } -// http://www.catch22.net/tuts/splitter-windows -VOID DrawXorBar(HDC hdc, INT x1, INT y1, INT width, INT height) +PPH_HSPLITTER_CONTEXT PhInitializeHSplitter( + _In_ HWND ParentWindow, + _In_ HWND TopWindow, + _In_ HWND BottomWindow + ) { - static WORD _dotPatternBmp[8] = - { - 0x00aa, 0x0055, 0x00aa, 0x0055, - 0x00aa, 0x0055, 0x00aa, 0x0055 - }; - - HBITMAP hbm; - HBRUSH hbr, hbrushOld; + static PH_INITONCE initOnce = PH_INITONCE_INIT; + PPH_HSPLITTER_CONTEXT context; - hbm = CreateBitmap(8, 8, 1, 1, _dotPatternBmp); - hbr = CreatePatternBrush(hbm); + context = PhAllocate(sizeof(PH_HSPLITTER_CONTEXT)); + memset(context, 0, sizeof(PH_HSPLITTER_CONTEXT)); + + context->ParentWindow = ParentWindow; + context->TopWindow = TopWindow; + context->BottomWindow = BottomWindow; + context->SplitterOffset = PhGetIntegerSetting(L"TokenSplitterPosition"); - SetBrushOrgEx(hdc, x1, y1, 0); - hbrushOld = (HBRUSH)SelectObject(hdc, hbr); + if (PhBeginInitOnce(&initOnce)) + { + WNDCLASSEX c = { sizeof(c) }; + + c.style = CS_GLOBALCLASS; + c.lpfnWndProc = HSplitterWindowProc; + c.cbClsExtra = 0; + c.cbWndExtra = sizeof(PVOID); + c.hInstance = PhLibImageBase; + c.hIcon = NULL; + c.hCursor = LoadCursor(NULL, IDC_SIZENS); + c.hbrBackground = NULL; + c.lpszMenuName = NULL; + c.lpszClassName = L"PhHSplitter"; + c.hIconSm = NULL; + + RegisterClassEx(&c); + + PhEndInitOnce(&initOnce); + } - PatBlt(hdc, x1, y1, width, height, PATINVERT); + context->Window = CreateWindowEx( + WS_EX_CONTROLPARENT | WS_EX_TRANSPARENT, + L"PhHSplitter", + NULL, + WS_CHILD | WS_VISIBLE, + 5, + 5, + 465, + 10, + ParentWindow, + NULL, + PhLibImageBase, + context + ); + + ShowWindow(context->Window, SW_SHOW); + UpdateWindow(context->Window); - SelectObject(hdc, hbrushOld); + return context; +} - DeleteObject(hbr); - DeleteObject(hbm); +VOID PhDeleteHSplitter( + _Inout_ PPH_HSPLITTER_CONTEXT Context + ) +{ + PhSetIntegerSetting(L"TokenSplitterPosition", Context->SplitterOffset); } +VOID PhHSplitterHandleWmSize( + _Inout_ PPH_HSPLITTER_CONTEXT Context, + _In_ INT Width, + _In_ INT Height + ) +{ + HDWP deferHandle; + + deferHandle = BeginDeferWindowPos(3); + DeferWindowPos( + deferHandle, + Context->TopWindow, + NULL, + SPLITTER_PADDING, + 90, + Width - SPLITTER_PADDING * 2, + Context->SplitterOffset - 90 - 65, + SWP_NOZORDER | SWP_NOACTIVATE + ); + + DeferWindowPos( + deferHandle, + Context->Window, + NULL, + 0, + Context->SplitterOffset - 65, + Width, + SPLITTER_PADDING, + SWP_NOZORDER | SWP_NOACTIVATE + ); + + DeferWindowPos( + deferHandle, + Context->BottomWindow, + NULL, + SPLITTER_PADDING, + Context->SplitterOffset + SPLITTER_PADDING - 65, + Width - SPLITTER_PADDING * 2, + GetClientWindowHeight(Context->ParentWindow) - (Context->SplitterOffset + SPLITTER_PADDING), + SWP_NOZORDER | SWP_NOACTIVATE + ); + EndDeferWindowPos(deferHandle); +} \ No newline at end of file diff --git a/ProcessHacker/tokprp.c b/ProcessHacker/tokprp.c index 88ec93705383..6a0f419656db 100644 --- a/ProcessHacker/tokprp.c +++ b/ProcessHacker/tokprp.c @@ -934,15 +934,6 @@ INT_PTR CALLBACK PhpTokenPageProc( case WM_SIZE: PhHSplitterHandleWmSize(tokenPageContext->HSplitterContext, LOWORD(lParam), HIWORD(lParam)); break; - case WM_LBUTTONDOWN: - PhHSplitterHandleLButtonDown(tokenPageContext->HSplitterContext, hwndDlg, wParam, lParam); - break; - case WM_LBUTTONUP: - PhHSplitterHandleLButtonUp(tokenPageContext->HSplitterContext, hwndDlg, wParam, lParam); - break; - case WM_MOUSEMOVE: - PhHSplitterHandleMouseMove(tokenPageContext->HSplitterContext, hwndDlg, wParam, lParam); - break; } REFLECT_MESSAGE_DLG(hwndDlg, tokenPageContext->GroupsListViewHandle, uMsg, wParam, lParam); From 2261ebc37147ffdfe2e0dae95daf72278b24dd92 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 4 Jun 2017 19:52:40 +1000 Subject: [PATCH 0188/2058] Fix typo --- plugins/ExtraPlugins/setup/updater.c | 4 ++-- plugins/OnlineChecks/page1.c | 4 ++-- plugins/OnlineChecks/upload.c | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/plugins/ExtraPlugins/setup/updater.c b/plugins/ExtraPlugins/setup/updater.c index 0cc2c26e9d32..19bd41c7b45c 100644 --- a/plugins/ExtraPlugins/setup/updater.c +++ b/plugins/ExtraPlugins/setup/updater.c @@ -60,8 +60,8 @@ VOID TaskDialogCreateIcons( ) { // Load the Process Hacker window icon - Context->IconLargeHandle = PH_LOAD_SHARED_ICON_SMALL(PhLibImageBase, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER)); - Context->IconSmallHandle = PH_LOAD_SHARED_ICON_LARGE(PhLibImageBase, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER)); + Context->IconLargeHandle = PH_LOAD_SHARED_ICON_LARGE(PhLibImageBase, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER)); + Context->IconSmallHandle = PH_LOAD_SHARED_ICON_SMALL(PhLibImageBase, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER)); // Set the TaskDialog window icons SendMessage(Context->DialogHandle, WM_SETICON, ICON_SMALL, (LPARAM)Context->IconSmallHandle); diff --git a/plugins/OnlineChecks/page1.c b/plugins/OnlineChecks/page1.c index 7b8489b72c95..5e37925ba30d 100644 --- a/plugins/OnlineChecks/page1.c +++ b/plugins/OnlineChecks/page1.c @@ -64,8 +64,8 @@ VOID ShowVirusTotalUploadDialog( config.dwCommonButtons = TDCBF_CLOSE_BUTTON; config.hMainIcon = Context->IconLargeHandle; - config.pszWindowTitle = PhaFormatString(L"Processing %s...", PhGetStringOrEmpty(Context->BaseFileName))->Buffer; - config.pszMainInstruction = PhaFormatString(L"Processing %s...", PhGetStringOrEmpty(Context->BaseFileName))->Buffer; + config.pszWindowTitle = PhaFormatString(L"Scanning %s...", PhGetStringOrEmpty(Context->BaseFileName))->Buffer; + config.pszMainInstruction = PhaFormatString(L"Scanning %s...", PhGetStringOrEmpty(Context->BaseFileName))->Buffer; config.cxWidth = 200; config.pfCallback = TaskDialogProcessingCallbackProc; diff --git a/plugins/OnlineChecks/upload.c b/plugins/OnlineChecks/upload.c index 926bd6dc73ec..0fb00a62503b 100644 --- a/plugins/OnlineChecks/upload.c +++ b/plugins/OnlineChecks/upload.c @@ -205,8 +205,8 @@ VOID TaskDialogCreateIcons( _In_ PUPLOAD_CONTEXT Context ) { - Context->IconLargeHandle = PH_LOAD_SHARED_ICON_SMALL(PhLibImageBase, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER)); - Context->IconSmallHandle = PH_LOAD_SHARED_ICON_LARGE(PhLibImageBase, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER)); + Context->IconLargeHandle = PH_LOAD_SHARED_ICON_LARGE(PhLibImageBase, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER)); + Context->IconSmallHandle = PH_LOAD_SHARED_ICON_SMALL(PhLibImageBase, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER)); SendMessage(Context->DialogHandle, WM_SETICON, ICON_SMALL, (LPARAM)Context->IconSmallHandle); SendMessage(Context->DialogHandle, WM_SETICON, ICON_BIG, (LPARAM)Context->IconLargeHandle); From fd455f696e22fa7daf05dad58709fc2904d3de34 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 4 Jun 2017 19:56:08 +1000 Subject: [PATCH 0189/2058] Add TaskDialog message macros --- ProcessHacker/ProcessHacker.def | 1 + ProcessHacker/plugin.c | 8 +++-- phlib/include/phutil.h | 17 +++++------ phlib/util.c | 54 ++++++++------------------------- 4 files changed, 26 insertions(+), 54 deletions(-) diff --git a/ProcessHacker/ProcessHacker.def b/ProcessHacker/ProcessHacker.def index 97692aee76bf..0258a7b3b934 100644 --- a/ProcessHacker/ProcessHacker.def +++ b/ProcessHacker/ProcessHacker.def @@ -377,6 +377,7 @@ EXPORTS PhShellProperties PhShowConfirmMessage PhShowContinueStatus + PhShowMessage2 PhShowFileDialog PhShowMessage PhShowMessage_V diff --git a/ProcessHacker/plugin.c b/ProcessHacker/plugin.c index 8f30f4e9da33..167a919d1454 100644 --- a/ProcessHacker/plugin.c +++ b/ProcessHacker/plugin.c @@ -270,7 +270,6 @@ VOID PhLoadPlugins( PPH_STRING baseName; PhInitializeStringBuilder(&sb, 100); - PhAppendStringBuilder2(&sb, L"Unable to load the following plugin(s):\n\n"); for (i = 0; i < LoadErrors->Count; i++) { @@ -283,9 +282,12 @@ VOID PhLoadPlugins( PhAppendStringBuilder2(&sb, L"\nDo you want to disable the above plugin(s)?"); - if (PhShowMessage( + if (PhShowMessage2( NULL, - MB_ICONERROR | MB_YESNO, + TDCBF_YES_BUTTON | TDCBF_NO_BUTTON, + TD_ERROR_ICON, + L"Unable to load the following plugin(s)", + L"%s", sb.String->Buffer ) == IDYES) { diff --git a/phlib/include/phutil.h b/phlib/include/phutil.h index 7eff8ea6b88d..9b6a440e9bbc 100644 --- a/phlib/include/phutil.h +++ b/phlib/include/phutil.h @@ -237,23 +237,20 @@ PhShowMessage_V( #define PhShowInformation(hWnd, Format, ...) PhShowMessage(hWnd, MB_OK | MB_ICONINFORMATION, Format, __VA_ARGS__) PHLIBAPI -INT +INT NTAPI -PhShowInformation2( +PhShowMessage2( _In_ HWND hWnd, + _In_ ULONG Buttons, + _In_opt_ PWSTR Icon, _In_opt_ PWSTR Title, _In_ PWSTR Format, ... ); -PHLIBAPI -INT -NTAPI -PhShowError2( - _In_ HWND hWnd, - _In_opt_ PWSTR Title, - _In_opt_ PWSTR Message - ); +#define PhShowError2(hWnd, Format, ...) PhShowMessage2(hWnd, TDCBF_CLOSE_BUTTON, TD_ERROR_ICON, Format, __VA_ARGS__) +#define PhShowWarning2(hWnd, Format, ...) PhShowMessage2(hWnd, TDCBF_CLOSE_BUTTON, TD_WARNING_ICON, Format, __VA_ARGS__) +#define PhShowInformation2(hWnd, Format, ...) PhShowMessage2(hWnd, TDCBF_CLOSE_BUTTON, TD_INFORMATION_ICON, Format, __VA_ARGS__) PHLIBAPI PPH_STRING diff --git a/phlib/util.c b/phlib/util.c index f20f04a60f26..ff2386b4a3b0 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -406,15 +406,17 @@ INT PhShowMessage_V( return result; } -INT PhShowInformation2( +INT PhShowMessage2( _In_ HWND hWnd, + _In_ ULONG Buttons, + _In_opt_ PWSTR Icon, _In_opt_ PWSTR Title, _In_ PWSTR Format, ... ) { + INT result; va_list argptr; - INT button; PPH_STRING message; TASKDIALOGCONFIG config = { sizeof(config) }; @@ -422,62 +424,32 @@ INT PhShowInformation2( message = PhFormatString_V(Format, argptr); va_end(argptr); + if (!message) + return -1; + config.hwndParent = hWnd; config.hInstance = PhLibImageBase; - config.dwFlags = TDF_ALLOW_DIALOG_CANCELLATION | (IsWindowVisible(hWnd) ? TDF_POSITION_RELATIVE_TO_WINDOW : 0); - config.dwCommonButtons = TDCBF_CLOSE_BUTTON; + config.dwFlags = TDF_ALLOW_DIALOG_CANCELLATION | (IsWindowVisible(hWnd) ? TDF_POSITION_RELATIVE_TO_WINDOW : 0) | TDF_SIZE_TO_CONTENT; + config.dwCommonButtons = Buttons; config.pszWindowTitle = PhApplicationName; - config.pszMainIcon = TD_INFORMATION_ICON; + config.pszMainIcon = Icon; config.pszMainInstruction = Title; config.pszContent = message->Buffer; if (TaskDialogIndirect( &config, - &button, + &result, NULL, NULL ) == S_OK) { PhDereferenceObject(message); - return button; + return result; } else { PhDereferenceObject(message); - return FALSE; - } -} - -INT PhShowError2( - _In_ HWND hWnd, - _In_opt_ PWSTR Title, - _In_opt_ PWSTR Message - ) -{ - INT button; - TASKDIALOGCONFIG config = { sizeof(config) }; - - config.hwndParent = hWnd; - config.hInstance = PhLibImageBase; - config.dwFlags = TDF_ALLOW_DIALOG_CANCELLATION | (IsWindowVisible(hWnd) ? TDF_POSITION_RELATIVE_TO_WINDOW : 0); - config.dwCommonButtons = TDCBF_CLOSE_BUTTON; - config.pszWindowTitle = PhApplicationName; - config.pszMainIcon = TD_ERROR_ICON; - config.pszMainInstruction = Title; - config.pszContent = Message; - - if (TaskDialogIndirect( - &config, - &button, - NULL, - NULL - ) == S_OK) - { - return button; - } - else - { - return FALSE; + return -1; } } From 60abdf1ae8807b95a3434ba5e4bc8cb6003628d5 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 4 Jun 2017 23:31:34 +1000 Subject: [PATCH 0190/2058] Fix system memory highlighting, Fix memory error dialog, Remove legacy node filtering --- ProcessHacker/include/mainwnd.h | 1 + ProcessHacker/include/phapp.h | 1 + ProcessHacker/mainwnd.c | 1 + ProcessHacker/memedit.c | 14 +++++++++----- ProcessHacker/memlist.c | 23 ++++++++++++----------- ProcessHacker/prpgmem.c | 29 +++++++++++++---------------- phlib/util.c | 2 +- 7 files changed, 38 insertions(+), 33 deletions(-) diff --git a/ProcessHacker/include/mainwnd.h b/ProcessHacker/include/mainwnd.h index d7607624acd1..bd6259c0c169 100644 --- a/ProcessHacker/include/mainwnd.h +++ b/ProcessHacker/include/mainwnd.h @@ -105,6 +105,7 @@ extern BOOLEAN PhMainWndExiting; typedef struct _PH_SHOW_MEMORY_EDITOR { + HWND OwnerWindow; HANDLE ProcessId; PVOID BaseAddress; SIZE_T RegionSize; diff --git a/ProcessHacker/include/phapp.h b/ProcessHacker/include/phapp.h index 5a9914f8a514..c213449420d2 100644 --- a/ProcessHacker/include/phapp.h +++ b/ProcessHacker/include/phapp.h @@ -439,6 +439,7 @@ VOID PhShowLogDialog( #define PH_MEMORY_EDITOR_UNMAP_VIEW_OF_SECTION 0x1 VOID PhShowMemoryEditorDialog( + _In_ HWND OwnerWindow, _In_ HANDLE ProcessId, _In_ PVOID BaseAddress, _In_ SIZE_T RegionSize, diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index 26533a980e4c..4ae19d682a3e 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -1973,6 +1973,7 @@ ULONG_PTR PhMwpOnUserMessage( PPH_SHOW_MEMORY_EDITOR showMemoryEditor = (PPH_SHOW_MEMORY_EDITOR)LParam; PhShowMemoryEditorDialog( + showMemoryEditor->OwnerWindow, showMemoryEditor->ProcessId, showMemoryEditor->BaseAddress, showMemoryEditor->RegionSize, diff --git a/ProcessHacker/memedit.c b/ProcessHacker/memedit.c index 1dfbef18a22c..8d30e574cfcc 100644 --- a/ProcessHacker/memedit.c +++ b/ProcessHacker/memedit.c @@ -47,8 +47,10 @@ typedef struct _MEMORY_EDITOR_CONTEXT }; HANDLE ProcessHandle; HWND WindowHandle; - PH_LAYOUT_MANAGER LayoutManager; + HWND OwnerHandle; HWND HexEditHandle; + PH_LAYOUT_MANAGER LayoutManager; + PUCHAR Buffer; ULONG SelectOffset; PPH_STRING Title; @@ -74,6 +76,7 @@ PH_AVL_TREE PhMemoryEditorSet = PH_AVL_TREE_INIT(PhpMemoryEditorCompareFunction) static RECT MinimumSize = { -1, -1, -1, -1 }; VOID PhShowMemoryEditorDialog( + _In_ HWND OwnerWindow, _In_ HANDLE ProcessId, _In_ PVOID BaseAddress, _In_ SIZE_T RegionSize, @@ -98,6 +101,7 @@ VOID PhShowMemoryEditorDialog( context = PhAllocate(sizeof(MEMORY_EDITOR_CONTEXT)); memset(context, 0, sizeof(MEMORY_EDITOR_CONTEXT)); + context->OwnerHandle = OwnerWindow; context->ProcessId = ProcessId; context->BaseAddress = BaseAddress; context->RegionSize = RegionSize; @@ -209,7 +213,7 @@ INT_PTR CALLBACK PhpMemoryEditorDlgProc( if (context->RegionSize > 1024 * 1024 * 1024) // 1 GB { - PhShowError(NULL, L"Unable to edit the memory region because it is too large."); + PhShowError(context->OwnerHandle, L"Unable to edit the memory region because it is too large."); return TRUE; } @@ -219,7 +223,7 @@ INT_PTR CALLBACK PhpMemoryEditorDlgProc( context->ProcessId ))) { - PhShowStatus(NULL, L"Unable to open the process", status, 0); + PhShowStatus(context->OwnerHandle, L"Unable to open the process", status, 0); return TRUE; } @@ -227,7 +231,7 @@ INT_PTR CALLBACK PhpMemoryEditorDlgProc( if (!context->Buffer) { - PhShowError(NULL, L"Unable to allocate memory for the buffer."); + PhShowError(context->OwnerHandle, L"Unable to allocate memory for the buffer."); return TRUE; } @@ -239,7 +243,7 @@ INT_PTR CALLBACK PhpMemoryEditorDlgProc( NULL ))) { - PhShowStatus(NULL, L"Unable to read memory", status, 0); + PhShowStatus(context->OwnerHandle, L"Unable to read memory", status, 0); return TRUE; } diff --git a/ProcessHacker/memlist.c b/ProcessHacker/memlist.c index 078103a54ede..c41417218ba2 100644 --- a/ProcessHacker/memlist.c +++ b/ProcessHacker/memlist.c @@ -327,9 +327,6 @@ VOID PhReplaceMemoryList( memoryNode = PhpAddRegionNode(Context, memoryItem); - if (Context->HideFreeRegions && (memoryItem->State & MEM_FREE)) - memoryNode->Node.Visible = FALSE; - if (allocationBaseNode && memoryItem->AllocationBase == allocationBaseNode->MemoryItem->BaseAddress) { if (!(memoryItem->State & MEM_FREE)) @@ -358,9 +355,6 @@ VOID PhReplaceMemoryList( if (memoryItem->RegionType != CustomRegion || memoryItem->u.Custom.PropertyOfAllocationBase) PhpCopyMemoryRegionTypeInfo(memoryItem, allocationBaseNode->MemoryItem); - - if (Context->HideFreeRegions && (allocationBaseNode->MemoryItem->State & MEM_FREE)) - allocationBaseNode->Node.Visible = FALSE; } else { @@ -793,21 +787,28 @@ BOOLEAN NTAPI PhpMemoryTreeNewCallback( if (!memoryItem) NOTHING; - else if (context->HighlightExecutePages && ( + else if ( + context->HighlightExecutePages && ( memoryItem->Protect & PAGE_EXECUTE || memoryItem->Protect & PAGE_EXECUTE_READ || memoryItem->Protect & PAGE_EXECUTE_READWRITE || - memoryItem->Protect & PAGE_EXECUTE_WRITECOPY)) + memoryItem->Protect & PAGE_EXECUTE_WRITECOPY + )) { getNodeColor->BackColor = PhCsColorPacked; } - else if (context->HighlightCfgPages && ( + else if ( + context->HighlightCfgPages && ( memoryItem->RegionType == CfgBitmapRegion || - memoryItem->RegionType == CfgBitmap32Region)) + memoryItem->RegionType == CfgBitmap32Region + )) { getNodeColor->BackColor = PhCsColorElevatedProcesses; } - else if (context->HighlightSystemPages && memoryItem->Type & MEM_MAPPED) + else if ( + context->HighlightSystemPages && ( + memoryItem->Type & SEC_IMAGE + )) { getNodeColor->BackColor = PhCsColorSystemProcesses; } diff --git a/ProcessHacker/prpgmem.c b/ProcessHacker/prpgmem.c index b6fed9159545..0dec99fbd5df 100644 --- a/ProcessHacker/prpgmem.c +++ b/ProcessHacker/prpgmem.c @@ -434,22 +434,19 @@ INT_PTR CALLBACK PhpProcessMemoryDlgProc( if (memoryNode && !memoryNode->IsAllocationBase) { - if (memoryNode->MemoryItem->State & MEM_COMMIT) - { - PPH_SHOW_MEMORY_EDITOR showMemoryEditor = PhAllocate(sizeof(PH_SHOW_MEMORY_EDITOR)); - - memset(showMemoryEditor, 0, sizeof(PH_SHOW_MEMORY_EDITOR)); - showMemoryEditor->ProcessId = processItem->ProcessId; - showMemoryEditor->BaseAddress = memoryNode->MemoryItem->BaseAddress; - showMemoryEditor->RegionSize = memoryNode->MemoryItem->RegionSize; - showMemoryEditor->SelectOffset = -1; - showMemoryEditor->SelectLength = 0; - ProcessHacker_ShowMemoryEditor(PhMainWndHandle, showMemoryEditor); - } - else - { - PhShowError(hwndDlg, L"Unable to edit the memory region because it is not committed."); - } + PPH_SHOW_MEMORY_EDITOR showMemoryEditor; + + showMemoryEditor = PhAllocate(sizeof(PH_SHOW_MEMORY_EDITOR)); + memset(showMemoryEditor, 0, sizeof(PH_SHOW_MEMORY_EDITOR)); + + showMemoryEditor->OwnerWindow = hwndDlg; + showMemoryEditor->ProcessId = processItem->ProcessId; + showMemoryEditor->BaseAddress = memoryNode->MemoryItem->BaseAddress; + showMemoryEditor->RegionSize = memoryNode->MemoryItem->RegionSize; + showMemoryEditor->SelectOffset = -1; + showMemoryEditor->SelectLength = 0; + + ProcessHacker_ShowMemoryEditor(PhMainWndHandle, showMemoryEditor); } } break; diff --git a/phlib/util.c b/phlib/util.c index ff2386b4a3b0..7e84cbb10dad 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -429,7 +429,7 @@ INT PhShowMessage2( config.hwndParent = hWnd; config.hInstance = PhLibImageBase; - config.dwFlags = TDF_ALLOW_DIALOG_CANCELLATION | (IsWindowVisible(hWnd) ? TDF_POSITION_RELATIVE_TO_WINDOW : 0) | TDF_SIZE_TO_CONTENT; + config.dwFlags = TDF_ALLOW_DIALOG_CANCELLATION | (IsWindowVisible(hWnd) ? TDF_POSITION_RELATIVE_TO_WINDOW : 0); config.dwCommonButtons = Buttons; config.pszWindowTitle = PhApplicationName; config.pszMainIcon = Icon; From 276e51ddf490a7067b7c4e98fb3afbc334293d3a Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 4 Jun 2017 23:33:05 +1000 Subject: [PATCH 0191/2058] Fix build file caching --- tools/CustomBuildTool/Source Files/Build.cs | 84 +++++++----------- tools/CustomBuildTool/Source Files/Utils.cs | 29 +++++- .../bin/Release/CustomBuildTool.exe | Bin 160768 -> 160256 bytes .../bin/Release/CustomBuildTool.pdb | Bin 69120 -> 69120 bytes 4 files changed, 59 insertions(+), 54 deletions(-) diff --git a/tools/CustomBuildTool/Source Files/Build.cs b/tools/CustomBuildTool/Source Files/Build.cs index 48b75f1d9eec..b6cff3c57df3 100644 --- a/tools/CustomBuildTool/Source Files/Build.cs +++ b/tools/CustomBuildTool/Source Files/Build.cs @@ -540,74 +540,54 @@ public static bool CopyKProcessHacker(BuildFlags Flags) if (Flags.HasFlag(BuildFlags.BuildDebug)) { - if (!File.Exists("bin\\Debug32\\ProcessHacker.exe")) + if (File.Exists("bin\\Debug32\\ProcessHacker.exe")) { - Program.PrintColorMessage("[SKIPPED] Debug32\\ProcessHacker.exe not found.", ConsoleColor.Yellow, true, Flags); - return true; - } + File.WriteAllText("bin\\Debug32\\ProcessHacker.sig", string.Empty); - if (!File.Exists("bin\\Debug64\\ProcessHacker.exe")) - { - Program.PrintColorMessage("[SKIPPED] Debug64\\ProcessHacker.exe not found.", ConsoleColor.Yellow, true, Flags); - return true; + string output = Win32.ShellExecute(CustomSignToolPath, "sign -k build\\kph.key bin\\Debug32\\ProcessHacker.exe -s bin\\Debug32\\ProcessHacker.sig"); + if (!string.IsNullOrEmpty(output)) + { + Program.PrintColorMessage("[WARN] (Debug32) " + output, ConsoleColor.Yellow, true, Flags); + return false; + } } - if (File.Exists("bin\\Debug32\\ProcessHacker.sig")) - File.Delete("bin\\Debug32\\ProcessHacker.sig"); - if (File.Exists("bin\\Debug64\\ProcessHacker.sig")) - File.Delete("bin\\Debug64\\ProcessHacker.sig"); - - File.Create("bin\\Debug32\\ProcessHacker.sig").Dispose(); - File.Create("bin\\Debug64\\ProcessHacker.sig").Dispose(); - - string output = Win32.ShellExecute(CustomSignToolPath, "sign -k build\\kph.key bin\\Debug32\\ProcessHacker.exe -s bin\\Debug32\\ProcessHacker.sig"); - if (!string.IsNullOrEmpty(output)) + if (File.Exists("bin\\Debug64\\ProcessHacker.exe")) { - Program.PrintColorMessage("[WARN] (Debug32) " + output, ConsoleColor.Yellow, true, Flags); - return false; - } + File.WriteAllText("bin\\Debug64\\ProcessHacker.sig", string.Empty); - output = Win32.ShellExecute(CustomSignToolPath, "sign -k build\\kph.key bin\\Debug64\\ProcessHacker.exe -s bin\\Debug64\\ProcessHacker.sig"); - if (!string.IsNullOrEmpty(output)) - { - Program.PrintColorMessage("[WARN] (Debug64) " + output, ConsoleColor.Yellow, true, Flags); - return false; + string output = Win32.ShellExecute(CustomSignToolPath, "sign -k build\\kph.key bin\\Debug64\\ProcessHacker.exe -s bin\\Debug64\\ProcessHacker.sig"); + if (!string.IsNullOrEmpty(output)) + { + Program.PrintColorMessage("[WARN] (Debug64) " + output, ConsoleColor.Yellow, true, Flags); + return false; + } } } else { - if (!File.Exists("bin\\Release32\\ProcessHacker.exe")) + if (File.Exists("bin\\Release32\\ProcessHacker.exe")) { - Program.PrintColorMessage("[SKIPPED] Release32\\ProcessHacker.exe not found.", ConsoleColor.Yellow, true, Flags); - return true; - } + File.WriteAllText("bin\\Release32\\ProcessHacker.sig", string.Empty); - if (!File.Exists("bin\\Release64\\ProcessHacker.exe")) - { - Program.PrintColorMessage("[SKIPPED] Release64\\ProcessHacker.exe not found.", ConsoleColor.Yellow, true, Flags); - return true; + string output = Win32.ShellExecute(CustomSignToolPath, "sign -k build\\kph.key bin\\Release32\\ProcessHacker.exe -s bin\\Release32\\ProcessHacker.sig"); + if (!string.IsNullOrEmpty(output)) + { + Program.PrintColorMessage("[WARN] (Release32) " + output, ConsoleColor.Yellow, true, Flags); + return false; + } } - if (File.Exists("bin\\Release32\\ProcessHacker.sig")) - File.Delete("bin\\Release32\\ProcessHacker.sig"); - if (File.Exists("bin\\Release64\\ProcessHacker.sig")) - File.Delete("bin\\Release64\\ProcessHacker.sig"); - - File.Create("bin\\Release32\\ProcessHacker.sig").Dispose(); - File.Create("bin\\Release64\\ProcessHacker.sig").Dispose(); - - string output = Win32.ShellExecute(CustomSignToolPath, "sign -k build\\kph.key bin\\Release32\\ProcessHacker.exe -s bin\\Release32\\ProcessHacker.sig"); - if (!string.IsNullOrEmpty(output)) + if (File.Exists("bin\\Release64\\ProcessHacker.exe")) { - Program.PrintColorMessage("[ERROR] (Release32) " + output, ConsoleColor.Red, true, Flags); - return false; - } + File.WriteAllText("bin\\Release64\\ProcessHacker.sig", string.Empty); - output = Win32.ShellExecute(CustomSignToolPath, "sign -k build\\kph.key bin\\Release64\\ProcessHacker.exe -s bin\\Release64\\ProcessHacker.sig"); - if (!string.IsNullOrEmpty(output)) - { - Program.PrintColorMessage("[ERROR] (Release64) " + output, ConsoleColor.Red, true, Flags); - return false; + string output = Win32.ShellExecute(CustomSignToolPath, "sign -k build\\kph.key bin\\Release64\\ProcessHacker.exe -s bin\\Release64\\ProcessHacker.sig"); + if (!string.IsNullOrEmpty(output)) + { + Program.PrintColorMessage("[WARN] (Release64) " + output, ConsoleColor.Yellow, true, Flags); + return false; + } } } diff --git a/tools/CustomBuildTool/Source Files/Utils.cs b/tools/CustomBuildTool/Source Files/Utils.cs index 3f3c9a5008a2..55a870ce71e8 100644 --- a/tools/CustomBuildTool/Source Files/Utils.cs +++ b/tools/CustomBuildTool/Source Files/Utils.cs @@ -78,8 +78,33 @@ public static void CopyIfNewer(string CurrentFile, string NewFile) if (!File.Exists(CurrentFile)) return; - if (File.GetLastWriteTime(CurrentFile) > File.GetLastWriteTime(NewFile)) - File.Copy(CurrentFile, NewFile, true); + if (CurrentFile.EndsWith(".sys", StringComparison.OrdinalIgnoreCase)) + { + if (!File.Exists(NewFile)) + { + File.Copy(CurrentFile, NewFile, true); + } + else + { + FileVersionInfo currentInfo = FileVersionInfo.GetVersionInfo(CurrentFile); + FileVersionInfo newInfo = FileVersionInfo.GetVersionInfo(NewFile); + var currentInfoVersion = new Version(currentInfo.FileVersion); + var newInfoVersion = new Version(newInfo.FileVersion); + + if ( + currentInfoVersion > newInfoVersion || + File.GetLastWriteTime(CurrentFile) > File.GetLastWriteTime(NewFile) + ) + { + File.Copy(CurrentFile, NewFile, true); + } + } + } + else + { + if (File.GetLastWriteTime(CurrentFile) > File.GetLastWriteTime(NewFile)) + File.Copy(CurrentFile, NewFile, true); + } } public const int SW_HIDE = 0; diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe b/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe index fb97a2ee1ecc1d7046c6727053448910267db157..604822da66d7cf6ba84cfa11fd1f7a9e9515ee69 100644 GIT binary patch delta 16925 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 delta 16942 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 delta 12484 zcmaKz349bq_Q$)2BqTtF3<zN5j*3ciizg55YUUhYKbyam| zC@%3UF7aEF=3i(t3}c^J&-~2XZ40rPU%MTCSN$U|tV?^q#Ij}I)_>o%@Ny6NE@kQN z__RWIlX_`^VRgUR)G~eAq#J!#&idCE+v4k8zyI2lvfLNU-C_3xgr)8s^lPu(?`I_S z8a=r4e!m||9@^f$EO)0FbTE?w*$%oLO>X!HoUSN7a^$qw6N>zHY#-*5H3`Lj87==l z(jAuAyg|Lu4Lr^>Y|^VuMnD=_l0|L81I}T%9w?jJWcYtY@}wMZ)5g&pdlb3A`i7zP z4i`sysQj(PJ?30Fn;y|J*{d6OO`kEZ&-i)03Z{&IRQ-%Pj&a2H2sVr>+vqGE=@@ftz*s23%??L~SUF$Z#f%MB5 z6Lr~JQZK6v&!HhDZIBN$oXt97J;<)s4OI%7f%XQw7IfGu$hNbgOludOch>7=V6J^zNDgsz2cv`bOT5pt|UVAOy{T8?2nVU_1ehf>$Qa-~CD@@N8@;Gx#N z-jix!CFuWPe+c~@>5!RXS0xfpEj}?sCS{JXz1v7W%?!7750ML*Bh2=an-vjwoLcCa zWZUUbc{Hnw*;LB1BFqc&VOC;rM^5}>7`+FN3-Yh5x9xLL_Mprrq-P^}zhg6d53;-1 z^O5>Cl7Dy12v)C)NP6zKBs+Vo*-^G+N0_H%Z+1#>Qe(sLi!h9@DfN_mpFPYz5hXp` zFuLJCH&ps{O0a*7l!g?8v?f%FI<*W|uZ>83koL*mPKm+o$*pIPLpdquJEdAB8I(N* z#TF*9ISKX>9DZeQg48oi`sGZBN{=MXR-#w#-H_-HpX4}`I}`sayIS{g73!pIJPYkG z`@7^1OK|5@yDB%m%Ie0_tMdfg8%}w(bGU7AxV+yv*4~~{mpTn&TYzC8{j+oH;2B6; zX_$r#P9I9EE^~r+qLiTQq}W2V&@Y4oD$ouwI%hXM&&p)Y9b@LWdxtb;~u0I zNPm`1-BPWy6{Bzp0aI z8N$0!iGb`lcl2GC>P7txeQ%&v!enUnIOKq165sDG*9cMxHluhXOokI-3Y-m_!?`dO zE`@3EDcA~bhOOZXFde#KTX+PvgC}5ncm`&|OE3#whMl1H#2lO9Dy~nW3ql<13gh8j zuodhHb6_vn1>Otqg?->K*ca;b*B_3D1K@Nx5H5g&;4(M_u7^Y6^Kck+!{IiUQT!%} z5eT2b2jOw}5IhG*!S7){yamU=-{7U6|5I$xmJ`W`!bvt`39V>MgS3J%6P;Et9wVOz z=RqoE6rm4>E=Z+}MUf;Z#8?ccz-5p^jO8+~e~hcA(b!nZ9&b2|s_7nRJ}BK#5RZP^N+C%+5601w0M@ECj%YRCK&{40DJeh2>ye}p_jR!4nR{0B~UdDaJJ zc+_Ud&jY)d8>H1BXZFXadbVRQ1s;bw!kvIE;pea``~v2|)367ukVS)1&9m~# zAgAjrnwD`6Cc$rDNB9q@zUN_ocmX~Lzk?It_wX_J16&G!gxcnpppNoC!#Ck&_!hhZ z55cQY+xi+jX&Cj48zfF6+?0WX2M2i;C#La+tlb*w`W2g2?mtj_j8VrZZVpVS7pTpe z3IoXJ!n#m?d>S@}I(0({E>;|ck(H(vUbK!ZI2mb?mKtGj+tvta!v zhK*F@g2WGVy5^%cKv`f}4Wkh16uuB@Rf?d_zAmWuXc5eUi{agHNgZSLWw?&~O(^hR z@M##zS)PHd;YOGVH$iQ`&9J*^xQu5>&5-qu}#!0^APg!9PKPFT>4n2Yd;> z0zZJS!4IK!;VO~ zu=@aRgCD`?p`Ktn{FwY}@EF_&kHh`&1Uvvgho8bPAP=S$f5ywN;g{&&LM@M;=Q7SB zXj7hpx8OJMH~1|ysquLj4llr1s0Ac>sa^9&^4io|V7ijL&gz%pV0aB`PrVMcr~U$G zz?*QH+1D`sMPe0#7PQ984Nwcz9%K4(CC~;>!#Yr#)(?IO1K?R$*H4;_*lq5UiV;p% zeZ(NHA{c51vO^uQ8^XJw!_Qcu%@|Eyo3RP}3yguEz<8+5mk6)HBxvI#$uI<_5MKz> z$uET&P%GOG(obwgmOS=gf7jq}&jY8cYTb0Qm|Mq68eMSJ$FD2YzMltm9=!|phdrRq zm%ZR@crPr3z2R!u2bRLVP}gVup$^Rh;74$vAL}n2Tm~WNf^0B!!XZ!}iu>W+a2V_j zwZZ$t2gnbFBmIn}Tj6-}-$M1%<&yF$d>97XSRUcWn$4IAS>YJ-(OCo-3;kGsJx!tr z;U(yTZ^B~8Bxfv!OkBni$OL38h0FoQGME6DLq<+x1snla!YObSoDQ|Zv*45D8A*&k zP=OEOM)KTvW0jsTR1+{3Zid-#3yyQ(c31{qLw^hIf*(P&;tOy$wE6QC!x*?1wu7(3 zyWxJ~m%(!QHvEg9v1%B%`V{sNFkfppl0*fmw34henox- z{5xC;&%sjo4crR9b;m!{#x$?Vz)?=ucZk}dzK7bOet=2vlAp0GA6_RvPV-c10=z-~ z5qJ~M_u7lSTmk>j&v?8X`uj7c!MgB&VIaH;>-!r^b=~eD-_tZk7@;I|Fb#wHdLQ9$ zEM5qm> z%z#d)7Zu~p>qWOm*BK)d>Wq;E`+4p6!%pOf!yNbk>;m;^>k4PWTsRBnL5DGcm2q1m z-N=&%^RsQddp(mMZCf`kDR4)oKHyA1Q_mzy|8Wj;hdX~xLW{KgsMZ z$rIu@_M9+1a3G_Q6>#oMg#2}aBibkEJL2b*)D&w|IJ|>&o$8dRhsT;lvhd-_yl{Tc z@d+6^aTsOg7dYkU#3n(WaMNfd@k>J26|@g3vQA(c0kW+iR0b4;5SU+(Mc}4_C(M51H~30$TdJdmdcaZ})lkbV zmE}lr)%qT_)UX=9pIK_-8onnjmD!g$EY+%m_Kvd>G{fnNL}dgpqG2P*$Zox(G=bXE zF_6w_FlSrKSl+;`X@wH3)muC)z@7jfgNbkvOoBSSG>7Y93#g0hmhgGVoL{^{Zziws z*3`-5Z>>PuKwW{fh3~-(_yNpze==j3X-<*knTfV3>GIIq(K2pk6GvhC?XI9*B2L!M zoNm4<=A$X`uX=6TeYj9#D|;t=e0sDDoEawn^Js+QZLgWeZXq*N}4!CXlg!Hw8oQz*E0-&L!rja(-cA{HI=LFat262CB1b`~{|iwlC~y`o_>evHc*&%|i;n#W-i%3KNc zaa#rT4e$whz!hgENldY`#TvA_XltQP%a`$3~ZEFYVw>d!y7k4(B%l^fq%&qRICG}17eMw%L$noB#ui5;X%fFY# zM*H!)s5i~m#fFgSO@3Z;$yioo9+k3Xi5$OJHrV`9S}b2+%T1FPmrt{ePm}N!35rfD zmQ!T;3N6w-^KpA!^Qe2#AL^LuxqMAg(D*bxgK12bMXpeH)3tu4EiOZvt!wFsqd)4o zeKSdta zIo|Zze9u|3luL?yzAj9Dl`v({qeQ5+jvQYXAwAYNG0%%BPAOa;7W`9{bNXX<25C)o zAflZ0PBU4~t{w$34Q(i8g7Q)$oEeVqaAXe zak?&`Y306yjo?LStuJ9R`5z%2!T1Skhr9w?L9G;xU|c2N1zv;q!0T`hyun4j3~!O& z2{mrFmj|H91oFOqTdG6iV+4Qq`DePBW{M*dzQ!Nd&Q^f2lDnDG_ zH|b+K?&!t#Xf0no+gjFaX<+u1_&=uDpTxksF{=`W5J0|F#2#48^N%r@_?!InVva4KgS7lpC!4*4OaP5L$a5g3gM9U;Oj}Y134bZmOq2Uw$}!u?N{%`5 z9>+W}Urw}bZ?AKiqdWJr#!~BLXCqac87(W9T6;XschzuyQwHL!YE|cVJkGt4t1h;< zHk?&$VYI3&`Gm*$UgWB4#tO?>Ro`k$SCZ#E&V6e*U$mT6t?GQ)F_tg$Hg81n zl_exuzN%Ke=rqgs!5ZbZvwT&pT5gWz`w(i?`sS&x`H=hU&bv+i8k_uTob5uqcM54Q zC9jSQ?8aoL52Tb`43*H=9JX$W((JW+f>diW4PvSGc)VI_z3N z$1K~G%JJ;3>E@4eUs*feb{Cc9*k&flp|U@lH>F^ABFELc7ubd-OFegM+e69H$=%g9 zy_w8+XP9T?6?Yq3+Z6fAz1X%Yh4omt%-s{F$*1-#r^1c*y0k*i>|GV)sflR}(%D8j zzy7#+!u{UsV@>m>yTu#dnZ&po9cW~;<+PDz2b%$Rzk>?Nia;4naN|!8y z7-zL-GePhzGSzVKXPsbUD9kc~7;be)(V?reymiDGH4HBu{drj~j)1%@Ycm-mWY~{B+V8rN87bjr7cP-Nxw*o$MgMD3th9PP0(DoQjCiA6T$F z*WXGE9yi(Z8-#G9h2_^#9yt|ZyJnYFr=p|vw-dg?+HzUG!ge*3L#LuM^%oJ9=C-%Z z`cnpP`IWzM@Rk2Uh}chuo1-Q9bYj$KPFYz%I~|ril^r7arxT-xG^%24&&!n8dbE+0 zo{qJFL#M<2^~VRM9LtL2!dVOXuHx3|2!H(rfhh;Gok2c5NxD=-#OPn{eb+yI%44$% zrcbMk>@1H|MDU}Bl@)Q(`e*sd>Sf=q-a)4vsYr;@KWA5(^KYAn%dLt;bGXExiHLeU zR()EJ9Xo6KOuY@hiahQfc;-~YW_-Oj{C~&n(LHxDb9`Cu9@BM_2KH>GakQ=el7;nz zcdKsGzyG}9Ga1!w`pc4Dwb=BBB2Va8U~Sdoy1TfiYkjsFh3bz(Xln0PJ@5jyE437Q ziW~fOEjIl{#qHl+oNTKLCu`HI*Dt%<0(?sK6JFyf`?Quq^(O&3iF>x{aoH^SZvUOX zs*TU@@qDY-k88S_#?A^)O4IyVi3c**E7Y{?K z(N^02&ylX9R)4FlKd3&!Q$LPXTkB}s^VrUKFRZ4GzqA;mYKha2#1Hyxt{R2T!^lG2 zyH!772ZmU_)BLWj58Y&WEwcGt(WzHWZhud+?ZYkE}*la3nMs(0hpv);$%yIz~|dX~pa{a(+~*U)#p<<_(v zP33je>x`{ewZPmo-uP}CtJ(C;bMo)nbg^Cbi&GcdpZ*fow4!H+N#@L&(bemd0v~pt40IqXER^J z`q!}O*Q8F~zo|KgT8WqT8nKZ zvorqIMhCAJx2C$yRn54ey0MzA^bWS|cd+fegU#KJnWDCu9=Jnb`5kQf3BI;6KdWi; z%~aZ?`hmW-K>bR8w3a5_&T_{W7gVFUcVgofSX)io9&E1K0^htt;5&CX;YW9fJMrIf zp6l1Eued|tx&IEdu1Mo9-XZSt9pY|Sao+Z?*)+f1Auxb$SzD9ZvDMb1jejpr&#zYz zbBDmB-wX7{rQIQ}-5ug`ym8j`*Sz|?I|TNwa>9BwI-CB5OFt*+R@0_`?D8$bs@O(Y zSHJWQg+76;v8T-cDpbFS4))rZEy;N{TGY5IKmF?T59CWzUAgjWgnvU)^{iA>rPkD! z%GPgGQ@zowh$}ZOX+5?GuTs;tL&|QYng`uyZ>9Lv`kw&yHL;mVezve~8}b6o%zLk~ z0@+D*yECy42-n|O@uJ4Qh+UgVC&Ah5bJ*vyKgK?veF1wRyM7)lVt4H;4=|UQ!3Crz jvOml|X~V!kGqtS8QqzAi*(LiN^~|5^>}y)jY+(C;RmEAQ From 93a959502db4902d5239537a5bdf76f9e97b42eb Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 4 Jun 2017 23:44:44 +1000 Subject: [PATCH 0192/2058] Fix reserved memory filter --- ProcessHacker/prpgmem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ProcessHacker/prpgmem.c b/ProcessHacker/prpgmem.c index 0dec99fbd5df..8a8dbc604144 100644 --- a/ProcessHacker/prpgmem.c +++ b/ProcessHacker/prpgmem.c @@ -245,7 +245,7 @@ BOOLEAN PhpMemoryTreeFilterCallback( return FALSE; if (memoryContext->ListContext.HideReservedRegions && - (memoryItem->Type & MEM_PRIVATE || memoryItem->Type & MEM_MAPPED) && + (memoryItem->Type & MEM_PRIVATE || memoryItem->Type & MEM_MAPPED || memoryItem->Type & MEM_IMAGE) && memoryItem->State & MEM_RESERVE && memoryItem->AllocationBaseItem // Ignore root nodes ) From d6b17c91884aad3af44ba8d11c7ea35d8bd1ac53 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 5 Jun 2017 05:32:53 +1000 Subject: [PATCH 0193/2058] update macro --- ProcessHacker/about.c | 3 ++- ProcessHacker/affinity.c | 4 ++-- ProcessHacker/chcol.c | 2 +- ProcessHacker/chdlg.c | 2 +- ProcessHacker/chproc.c | 4 ++-- ProcessHacker/findobj.c | 4 ++-- ProcessHacker/gdihndl.c | 5 ++--- ProcessHacker/hidnproc.c | 2 +- ProcessHacker/hndlstat.c | 5 ++--- ProcessHacker/infodlg.c | 2 +- ProcessHacker/jobprp.c | 5 ++--- ProcessHacker/logwnd.c | 2 +- ProcessHacker/mainwnd.c | 2 +- ProcessHacker/mdump.c | 4 ++-- ProcessHacker/memedit.c | 2 +- ProcessHacker/memlists.c | 5 ++--- ProcessHacker/memprot.c | 2 +- ProcessHacker/memrslt.c | 2 +- ProcessHacker/memsrch.c | 4 ++-- ProcessHacker/miniinfo.c | 4 ++-- ProcessHacker/mtgndlg.c | 4 ++-- ProcessHacker/netstk.c | 7 ++----- ProcessHacker/notifico.c | 2 +- ProcessHacker/ntobjprp.c | 21 +++++++++++---------- ProcessHacker/procprp.c | 3 ++- ProcessHacker/prpgenv.c | 10 ++++------ ProcessHacker/prpgmem.c | 2 +- plugins/DotNetTools/asmpage.c | 2 +- plugins/ExtendedNotifications/main.c | 22 +++------------------- plugins/ExtendedServices/options.c | 2 +- plugins/ExtendedServices/other.c | 6 +++--- plugins/ExtendedServices/recovery.c | 10 +++++----- plugins/ExtendedServices/srvprgrs.c | 2 +- plugins/ExtendedServices/trigger.c | 8 ++++---- plugins/ExtendedServices/triggpg.c | 2 +- plugins/ExtendedTools/disktab.c | 2 +- plugins/ExtendedTools/gpunodes.c | 2 +- plugins/ExtendedTools/gpusys.c | 2 +- plugins/ExtendedTools/modsrv.c | 2 +- plugins/ExtendedTools/options.c | 2 +- plugins/ExtendedTools/unldll.c | 2 +- plugins/ExtendedTools/wswatch.c | 2 +- plugins/HardwareDevices/prpsh.c | 2 +- plugins/NetworkTools/options.c | 2 +- plugins/NetworkTools/ping.c | 2 +- plugins/OnlineChecks/options.c | 2 +- plugins/UserNotes/main.c | 10 +++++----- plugins/WindowExplorer/wnddlg.c | 4 ++-- plugins/WindowExplorer/wndprp.c | 10 +++++----- 49 files changed, 96 insertions(+), 118 deletions(-) diff --git a/ProcessHacker/about.c b/ProcessHacker/about.c index 4a8b262e16f0..91c61818a748 100644 --- a/ProcessHacker/about.c +++ b/ProcessHacker/about.c @@ -23,6 +23,7 @@ #include +#include #include #include @@ -87,7 +88,7 @@ static INT_PTR CALLBACK PhpAboutDlgProc( break; case WM_COMMAND: { - switch (LOWORD(wParam)) + switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDCANCEL: case IDOK: diff --git a/ProcessHacker/affinity.c b/ProcessHacker/affinity.c index d019c3e2ac65..48c3a19f96c6 100644 --- a/ProcessHacker/affinity.c +++ b/ProcessHacker/affinity.c @@ -232,7 +232,7 @@ static INT_PTR CALLBACK PhpProcessAffinityDlgProc( break; case WM_COMMAND: { - switch (LOWORD(wParam)) + switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDCANCEL: EndDialog(hwndDlg, IDCANCEL); @@ -304,7 +304,7 @@ static INT_PTR CALLBACK PhpProcessAffinityDlgProc( HWND checkBox = GetDlgItem(hwndDlg, IDC_CPU0 + i); if (IsWindowEnabled(checkBox)) - Button_SetCheck(checkBox, LOWORD(wParam) == IDC_SELECTALL ? BST_CHECKED : BST_UNCHECKED); + Button_SetCheck(checkBox, GET_WM_COMMAND_ID(wParam, lParam) == IDC_SELECTALL ? BST_CHECKED : BST_UNCHECKED); } } break; diff --git a/ProcessHacker/chcol.c b/ProcessHacker/chcol.c index 5774a3a54550..68c16754a6c7 100644 --- a/ProcessHacker/chcol.c +++ b/ProcessHacker/chcol.c @@ -207,7 +207,7 @@ INT_PTR CALLBACK PhpColumnsDlgProc( break; case WM_COMMAND: { - switch (LOWORD(wParam)) + switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDCANCEL: EndDialog(hwndDlg, IDCANCEL); diff --git a/ProcessHacker/chdlg.c b/ProcessHacker/chdlg.c index bb4683bc5d0e..b7acd39a9ed4 100644 --- a/ProcessHacker/chdlg.c +++ b/ProcessHacker/chdlg.c @@ -272,7 +272,7 @@ INT_PTR CALLBACK PhpChoiceDlgProc( break; case WM_COMMAND: { - switch (LOWORD(wParam)) + switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDCANCEL: EndDialog(hwndDlg, IDCANCEL); diff --git a/ProcessHacker/chproc.c b/ProcessHacker/chproc.c index fd0578842349..4b83a8f176eb 100644 --- a/ProcessHacker/chproc.c +++ b/ProcessHacker/chproc.c @@ -21,8 +21,8 @@ */ #include - #include +#include typedef struct _CHOOSE_PROCESS_DIALOG_CONTEXT { @@ -257,7 +257,7 @@ INT_PTR CALLBACK PhpChooseProcessDlgProc( break; case WM_COMMAND: { - switch (LOWORD(wParam)) + switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDCANCEL: { diff --git a/ProcessHacker/findobj.c b/ProcessHacker/findobj.c index 926cc9549c2a..1865b4b54f99 100644 --- a/ProcessHacker/findobj.c +++ b/ProcessHacker/findobj.c @@ -293,7 +293,7 @@ static INT_PTR CALLBACK PhpFindObjectsDlgProc( break; case WM_COMMAND: { - switch (LOWORD(wParam)) + switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDOK: { @@ -477,7 +477,7 @@ static INT_PTR CALLBACK PhpFindObjectsDlgProc( info.TypeName = result->TypeName; info.BestObjectName = result->Name; - if (LOWORD(wParam) == ID_HANDLE_OBJECTPROPERTIES1) + if (GET_WM_COMMAND_ID(wParam, lParam) == ID_HANDLE_OBJECTPROPERTIES1) PhShowHandleObjectProperties1(hwndDlg, &info); else PhShowHandleObjectProperties2(hwndDlg, &info); diff --git a/ProcessHacker/gdihndl.c b/ProcessHacker/gdihndl.c index c8d192d049a0..e5d62f7018ae 100644 --- a/ProcessHacker/gdihndl.c +++ b/ProcessHacker/gdihndl.c @@ -21,10 +21,9 @@ */ #include - #include - #include +#include typedef struct _GDI_HANDLES_CONTEXT { @@ -357,7 +356,7 @@ INT_PTR CALLBACK PhpGdiHandlesDlgProc( break; case WM_COMMAND: { - switch (LOWORD(wParam)) + switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDCANCEL: case IDOK: diff --git a/ProcessHacker/hidnproc.c b/ProcessHacker/hidnproc.c index 926b16cb00eb..c3b16c7158b2 100644 --- a/ProcessHacker/hidnproc.c +++ b/ProcessHacker/hidnproc.c @@ -189,7 +189,7 @@ static INT_PTR CALLBACK PhpHiddenProcessesDlgProc( return TRUE; case WM_COMMAND: { - switch (LOWORD(wParam)) + switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDCANCEL: case IDOK: diff --git a/ProcessHacker/hndlstat.c b/ProcessHacker/hndlstat.c index 3835d47f750d..15c9e45bd720 100644 --- a/ProcessHacker/hndlstat.c +++ b/ProcessHacker/hndlstat.c @@ -21,10 +21,9 @@ */ #include - #include - #include +#include typedef struct _HANDLE_STATISTICS_ENTRY { @@ -220,7 +219,7 @@ INT_PTR CALLBACK PhpHandleStatisticsDlgProc( break; case WM_COMMAND: { - switch (LOWORD(wParam)) + switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDCANCEL: case IDOK: diff --git a/ProcessHacker/infodlg.c b/ProcessHacker/infodlg.c index 176140cc2662..8c8cf487cc57 100644 --- a/ProcessHacker/infodlg.c +++ b/ProcessHacker/infodlg.c @@ -96,7 +96,7 @@ static INT_PTR CALLBACK PhpInformationDlgProc( break; case WM_COMMAND: { - switch (LOWORD(wParam)) + switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDCANCEL: case IDOK: diff --git a/ProcessHacker/jobprp.c b/ProcessHacker/jobprp.c index c3ecb3db161a..a9668838d10d 100644 --- a/ProcessHacker/jobprp.c +++ b/ProcessHacker/jobprp.c @@ -21,12 +21,11 @@ */ #include - #include #include - #include #include +#include typedef struct _JOB_PAGE_CONTEXT { @@ -390,7 +389,7 @@ INT_PTR CALLBACK PhpJobPageProc( break; case WM_COMMAND: { - switch (LOWORD(wParam)) + switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDC_TERMINATE: { diff --git a/ProcessHacker/logwnd.c b/ProcessHacker/logwnd.c index 0fde6d46e648..1bcfe90a3f01 100644 --- a/ProcessHacker/logwnd.c +++ b/ProcessHacker/logwnd.c @@ -209,7 +209,7 @@ INT_PTR CALLBACK PhpLogDlgProc( break; case WM_COMMAND: { - switch (LOWORD(wParam)) + switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDCANCEL: case IDOK: diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index 4ae19d682a3e..76c9b25b83d7 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -262,7 +262,7 @@ LRESULT CALLBACK PhMwpWndProc( break; case WM_COMMAND: { - PhMwpOnCommand(LOWORD(wParam)); + PhMwpOnCommand(GET_WM_COMMAND_ID(wParam, lParam)); } break; case WM_SHOWWINDOW: diff --git a/ProcessHacker/mdump.c b/ProcessHacker/mdump.c index 92e88db305eb..e40ab800a630 100644 --- a/ProcessHacker/mdump.c +++ b/ProcessHacker/mdump.c @@ -22,8 +22,8 @@ #include +#include #include - #include #include @@ -401,7 +401,7 @@ INT_PTR CALLBACK PhpProcessMiniDumpDlgProc( break; case WM_COMMAND: { - switch (LOWORD(wParam)) + switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDCANCEL: { diff --git a/ProcessHacker/memedit.c b/ProcessHacker/memedit.c index 8d30e574cfcc..b76344d1c68a 100644 --- a/ProcessHacker/memedit.c +++ b/ProcessHacker/memedit.c @@ -349,7 +349,7 @@ INT_PTR CALLBACK PhpMemoryEditorDlgProc( break; case WM_COMMAND: { - switch (LOWORD(wParam)) + switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDCANCEL: case IDOK: diff --git a/ProcessHacker/memlists.c b/ProcessHacker/memlists.c index 537e318f8c55..c61d9a321db0 100644 --- a/ProcessHacker/memlists.c +++ b/ProcessHacker/memlists.c @@ -21,13 +21,12 @@ */ #include - #include #include - #include #include #include +#include #define MSG_UPDATE (WM_APP + 1) @@ -191,7 +190,7 @@ INT_PTR CALLBACK PhpMemoryListsDlgProc( break; case WM_COMMAND: { - switch (LOWORD(wParam)) + switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDCANCEL: case IDOK: diff --git a/ProcessHacker/memprot.c b/ProcessHacker/memprot.c index 5feec758b8b9..17b6d09f09e3 100644 --- a/ProcessHacker/memprot.c +++ b/ProcessHacker/memprot.c @@ -102,7 +102,7 @@ static INT_PTR CALLBACK PhpMemoryProtectDlgProc( break; case WM_COMMAND: { - switch (LOWORD(wParam)) + switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDCANCEL: EndDialog(hwndDlg, IDCANCEL); diff --git a/ProcessHacker/memrslt.c b/ProcessHacker/memrslt.c index 3ea48045760c..a066c5770f2b 100644 --- a/ProcessHacker/memrslt.c +++ b/ProcessHacker/memrslt.c @@ -369,7 +369,7 @@ INT_PTR CALLBACK PhpMemoryResultsDlgProc( break; case WM_COMMAND: { - switch (LOWORD(wParam)) + switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDCANCEL: case IDOK: diff --git a/ProcessHacker/memsrch.c b/ProcessHacker/memsrch.c index 41c2b0c8876e..0440ff6f4b30 100644 --- a/ProcessHacker/memsrch.c +++ b/ProcessHacker/memsrch.c @@ -554,7 +554,7 @@ INT_PTR CALLBACK PhpMemoryStringDlgProc( break; case WM_COMMAND: { - switch (LOWORD(wParam)) + switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDCANCEL: EndDialog(hwndDlg, IDCANCEL); @@ -679,7 +679,7 @@ INT_PTR CALLBACK PhpMemoryStringProgressDlgProc( break; case WM_COMMAND: { - switch (LOWORD(wParam)) + switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDCANCEL: { diff --git a/ProcessHacker/miniinfo.c b/ProcessHacker/miniinfo.c index 64bf00ebfe15..3a7b394662f0 100644 --- a/ProcessHacker/miniinfo.c +++ b/ProcessHacker/miniinfo.c @@ -219,7 +219,7 @@ LRESULT CALLBACK PhMipContainerWndProc( break; case WM_ACTIVATE: { - PhMipContainerOnActivate(LOWORD(wParam), !!HIWORD(wParam)); + PhMipContainerOnActivate(GET_WM_COMMAND_ID(wParam, lParam), !!HIWORD(wParam)); } break; case WM_SIZE: @@ -282,7 +282,7 @@ INT_PTR CALLBACK PhMipMiniInfoDialogProc( break; case WM_COMMAND: { - PhMipOnCommand(LOWORD(wParam), HIWORD(wParam)); + PhMipOnCommand(GET_WM_COMMAND_ID(wParam, lParam), HIWORD(wParam)); } break; case WM_NOTIFY: diff --git a/ProcessHacker/mtgndlg.c b/ProcessHacker/mtgndlg.c index 1c9e6249de3e..cd864ba0eba6 100644 --- a/ProcessHacker/mtgndlg.c +++ b/ProcessHacker/mtgndlg.c @@ -21,8 +21,8 @@ */ #include - #include +#include typedef struct _MITIGATION_POLICY_ENTRY { @@ -127,7 +127,7 @@ INT_PTR CALLBACK PhpProcessMitigationPolicyDlgProc( break; case WM_COMMAND: { - switch (LOWORD(wParam)) + switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDCANCEL: case IDOK: diff --git a/ProcessHacker/netstk.c b/ProcessHacker/netstk.c index 2e89b091a71a..8ae55638bfed 100644 --- a/ProcessHacker/netstk.c +++ b/ProcessHacker/netstk.c @@ -21,10 +21,9 @@ */ #include - #include - #include +#include typedef struct NETWORK_STACK_CONTEXT { @@ -210,9 +209,7 @@ static INT_PTR CALLBACK PhpNetworkStackDlgProc( break; case WM_COMMAND: { - INT id = LOWORD(wParam); - - switch (id) + switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDCANCEL: // Esc and X button to close case IDOK: diff --git a/ProcessHacker/notifico.c b/ProcessHacker/notifico.c index 729f81412e78..66aaa2891ae0 100644 --- a/ProcessHacker/notifico.c +++ b/ProcessHacker/notifico.c @@ -208,7 +208,7 @@ VOID PhNfForwardMessage( } } - switch (LOWORD(LParam)) + switch (GET_WM_COMMAND_ID(WParam, LParam)) { case WM_LBUTTONDOWN: { diff --git a/ProcessHacker/ntobjprp.c b/ProcessHacker/ntobjprp.c index 3864cfc5fd41..a0a9355a3603 100644 --- a/ProcessHacker/ntobjprp.c +++ b/ProcessHacker/ntobjprp.c @@ -23,9 +23,10 @@ #include #include - #include +#include + typedef struct _COMMON_PAGE_CONTEXT { PPH_OPEN_OBJECT OpenObject; @@ -227,7 +228,7 @@ INT_PTR CALLBACK PhpEventPageProc( break; case WM_COMMAND: { - switch (LOWORD(wParam)) + switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDC_SET: case IDC_RESET: @@ -242,7 +243,7 @@ INT_PTR CALLBACK PhpEventPageProc( pageContext->Context ))) { - switch (LOWORD(wParam)) + switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDC_SET: NtSetEvent(eventHandle, NULL); @@ -308,7 +309,7 @@ INT_PTR CALLBACK PhpEventPairPageProc( break; case WM_COMMAND: { - switch (LOWORD(wParam)) + switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDC_SETLOW: case IDC_SETHIGH: @@ -322,7 +323,7 @@ INT_PTR CALLBACK PhpEventPairPageProc( pageContext->Context ))) { - switch (LOWORD(wParam)) + switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDC_SETLOW: NtSetLowEventPair(eventPairHandle); @@ -609,7 +610,7 @@ INT_PTR CALLBACK PhpSemaphorePageProc( break; case WM_COMMAND: { - switch (LOWORD(wParam)) + switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDC_ACQUIRE: case IDC_RELEASE: @@ -619,11 +620,11 @@ INT_PTR CALLBACK PhpSemaphorePageProc( if (NT_SUCCESS(status = pageContext->OpenObject( &semaphoreHandle, - LOWORD(wParam) == IDC_ACQUIRE ? SYNCHRONIZE : SEMAPHORE_MODIFY_STATE, + GET_WM_COMMAND_ID(wParam, lParam) == IDC_ACQUIRE ? SYNCHRONIZE : SEMAPHORE_MODIFY_STATE, pageContext->Context ))) { - switch (LOWORD(wParam)) + switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDC_ACQUIRE: { @@ -719,7 +720,7 @@ INT_PTR CALLBACK PhpTimerPageProc( break; case WM_COMMAND: { - switch (LOWORD(wParam)) + switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDC_CANCEL: { @@ -732,7 +733,7 @@ INT_PTR CALLBACK PhpTimerPageProc( pageContext->Context ))) { - switch (LOWORD(wParam)) + switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDC_CANCEL: NtCancelTimer(timerHandle, NULL); diff --git a/ProcessHacker/procprp.c b/ProcessHacker/procprp.c index 03236a716ee7..bf6e302925ef 100644 --- a/ProcessHacker/procprp.c +++ b/ProcessHacker/procprp.c @@ -24,6 +24,7 @@ #include #include +#include #include #include @@ -242,7 +243,7 @@ LRESULT CALLBACK PhpPropSheetWndProc( break; case WM_COMMAND: { - switch (LOWORD(wParam)) + switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDOK: // Prevent the OK button from working (even though diff --git a/ProcessHacker/prpgenv.c b/ProcessHacker/prpgenv.c index e819a260440c..3806999f8fd1 100644 --- a/ProcessHacker/prpgenv.c +++ b/ProcessHacker/prpgenv.c @@ -23,14 +23,12 @@ #include #include #include - -#include - #include #include #include - #include +#include +#include typedef struct _EDIT_ENV_DIALOG_CONTEXT { @@ -243,7 +241,7 @@ INT_PTR CALLBACK PhpProcessEnvironmentDlgProc( break; case WM_COMMAND: { - switch (LOWORD(wParam)) + switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDC_NEW: { @@ -489,7 +487,7 @@ INT_PTR CALLBACK PhpEditEnvDlgProc( break; case WM_COMMAND: { - switch (LOWORD(wParam)) + switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDCANCEL: { diff --git a/ProcessHacker/prpgmem.c b/ProcessHacker/prpgmem.c index 8a8dbc604144..adb9146f7418 100644 --- a/ProcessHacker/prpgmem.c +++ b/ProcessHacker/prpgmem.c @@ -421,7 +421,7 @@ INT_PTR CALLBACK PhpProcessMemoryDlgProc( break; } - switch (LOWORD(wParam)) + switch (GET_WM_COMMAND_ID(wParam, lParam)) { case ID_SHOWCONTEXTMENU: { diff --git a/plugins/DotNetTools/asmpage.c b/plugins/DotNetTools/asmpage.c index 6ead4b55596d..fc9419e258b2 100644 --- a/plugins/DotNetTools/asmpage.c +++ b/plugins/DotNetTools/asmpage.c @@ -1270,7 +1270,7 @@ INT_PTR CALLBACK DotNetAsmPageDlgProc( break; case WM_COMMAND: { - switch (LOWORD(wParam)) + switch (GET_WM_COMMAND_ID(wParam, lParam)) { case ID_COPY: { diff --git a/plugins/ExtendedNotifications/main.c b/plugins/ExtendedNotifications/main.c index 33abdab44813..b272d100f136 100644 --- a/plugins/ExtendedNotifications/main.c +++ b/plugins/ExtendedNotifications/main.c @@ -695,11 +695,11 @@ INT_PTR HandleCommonMessages( break; case WM_COMMAND: { - switch (LOWORD(wParam)) + switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDC_LIST: { - if (HIWORD(wParam) == LBN_SELCHANGE) + if (GET_WM_COMMAND_CMD(wParam, lParam) == LBN_SELCHANGE) { ULONG i; @@ -900,14 +900,6 @@ INT_PTR CALLBACK ProcessesDlgProc( EditingProcessFilterList = NULL; } break; - case WM_COMMAND: - { - switch (LOWORD(wParam)) - { - NOTHING; - } - } - break; case WM_NOTIFY: { LPNMHDR header = (LPNMHDR)lParam; @@ -964,14 +956,6 @@ INT_PTR CALLBACK ServicesDlgProc( EditingServiceFilterList = NULL; } break; - case WM_COMMAND: - { - switch (LOWORD(wParam)) - { - NOTHING; - } - } - break; case WM_NOTIFY: { LPNMHDR header = (LPNMHDR)lParam; @@ -1016,7 +1000,7 @@ INT_PTR CALLBACK LoggingDlgProc( break; case WM_COMMAND: { - switch (LOWORD(wParam)) + switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDC_BROWSE: { diff --git a/plugins/ExtendedServices/options.c b/plugins/ExtendedServices/options.c index 51cb5d9ce2a1..019bfbd32dff 100644 --- a/plugins/ExtendedServices/options.c +++ b/plugins/ExtendedServices/options.c @@ -40,7 +40,7 @@ INT_PTR CALLBACK OptionsDlgProc( break; case WM_COMMAND: { - switch (LOWORD(wParam)) + switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDCANCEL: EndDialog(hwndDlg, IDCANCEL); diff --git a/plugins/ExtendedServices/other.c b/plugins/ExtendedServices/other.c index 5b7957afa653..28d98146d6a9 100644 --- a/plugins/ExtendedServices/other.c +++ b/plugins/ExtendedServices/other.c @@ -395,7 +395,7 @@ INT_PTR CALLBACK EspServiceOtherDlgProc( break; case WM_COMMAND: { - switch (LOWORD(wParam)) + switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDC_ADD: { @@ -535,7 +535,7 @@ INT_PTR CALLBACK EspServiceOtherDlgProc( break; } - switch (HIWORD(wParam)) + switch (GET_WM_COMMAND_CMD(wParam, lParam)) { case EN_CHANGE: case CBN_SELCHANGE: @@ -544,7 +544,7 @@ INT_PTR CALLBACK EspServiceOtherDlgProc( { context->Dirty = TRUE; - switch (LOWORD(wParam)) + switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDC_PRESHUTDOWNTIMEOUT: context->PreshutdownTimeoutValid = TRUE; diff --git a/plugins/ExtendedServices/recovery.c b/plugins/ExtendedServices/recovery.c index b917b0334498..91f42768cefe 100644 --- a/plugins/ExtendedServices/recovery.c +++ b/plugins/ExtendedServices/recovery.c @@ -343,13 +343,13 @@ INT_PTR CALLBACK EspServiceRecoveryDlgProc( break; case WM_COMMAND: { - switch (LOWORD(wParam)) + switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDC_FIRSTFAILURE: case IDC_SECONDFAILURE: case IDC_SUBSEQUENTFAILURES: { - if (HIWORD(wParam) == CBN_SELCHANGE) + if (GET_WM_COMMAND_CMD(wParam, lParam) == CBN_SELCHANGE) { EspFixControls(hwndDlg, context); } @@ -398,7 +398,7 @@ INT_PTR CALLBACK EspServiceRecoveryDlgProc( break; } - switch (HIWORD(wParam)) + switch (GET_WM_COMMAND_CMD(wParam, lParam)) { case EN_CHANGE: case CBN_SELCHANGE: @@ -627,7 +627,7 @@ INT_PTR CALLBACK RestartComputerDlgProc( break; case WM_COMMAND: { - switch (LOWORD(wParam)) + switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDCANCEL: EndDialog(hwndDlg, IDCANCEL); @@ -692,7 +692,7 @@ INT_PTR CALLBACK RestartComputerDlgProc( break; case IDC_RESTARTMESSAGE: { - if (HIWORD(wParam) == EN_CHANGE) + if (GET_WM_COMMAND_CMD(wParam, lParam) == EN_CHANGE) { // A zero length restart message disables it, so we might as well uncheck the box. Button_SetCheck(GetDlgItem(hwndDlg, IDC_ENABLERESTARTMESSAGE), diff --git a/plugins/ExtendedServices/srvprgrs.c b/plugins/ExtendedServices/srvprgrs.c index 0cde80360efb..3b19031596ef 100644 --- a/plugins/ExtendedServices/srvprgrs.c +++ b/plugins/ExtendedServices/srvprgrs.c @@ -79,7 +79,7 @@ INT_PTR CALLBACK EspRestartServiceDlgProc( break; case WM_COMMAND: { - switch (LOWORD(wParam)) + switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDCANCEL: { diff --git a/plugins/ExtendedServices/trigger.c b/plugins/ExtendedServices/trigger.c index e0aa2b667435..fb2c2803837e 100644 --- a/plugins/ExtendedServices/trigger.c +++ b/plugins/ExtendedServices/trigger.c @@ -1376,16 +1376,16 @@ INT_PTR CALLBACK EspServiceTriggerDlgProc( break; case WM_COMMAND: { - switch (LOWORD(wParam)) + switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDC_TYPE: - if (HIWORD(wParam) == CBN_SELCHANGE) + if (GET_WM_COMMAND_CMD(wParam, lParam) == CBN_SELCHANGE) { EspFixServiceTriggerControls(hwndDlg, context); } break; case IDC_SUBTYPE: - if (HIWORD(wParam) == CBN_SELCHANGE) + if (GET_WM_COMMAND_CMD(wParam, lParam) == CBN_SELCHANGE) { EspFixServiceTriggerControls(hwndDlg, context); } @@ -1702,7 +1702,7 @@ INT_PTR CALLBACK ValueDlgProc( break; case WM_COMMAND: { - switch (LOWORD(wParam)) + switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDCANCEL: EndDialog(hwndDlg, IDCANCEL); diff --git a/plugins/ExtendedServices/triggpg.c b/plugins/ExtendedServices/triggpg.c index 0188ddaead0f..514dd38a0d5b 100644 --- a/plugins/ExtendedServices/triggpg.c +++ b/plugins/ExtendedServices/triggpg.c @@ -107,7 +107,7 @@ INT_PTR CALLBACK EspServiceTriggersDlgProc( break; case WM_COMMAND: { - switch (LOWORD(wParam)) + switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDC_NEW: if (context->TriggerContext) diff --git a/plugins/ExtendedTools/disktab.c b/plugins/ExtendedTools/disktab.c index b8b1ae72e953..2ab3ad8c3cd5 100644 --- a/plugins/ExtendedTools/disktab.c +++ b/plugins/ExtendedTools/disktab.c @@ -1133,7 +1133,7 @@ INT_PTR CALLBACK EtpDiskTabErrorDialogProc( break; case WM_COMMAND: { - switch (LOWORD(wParam)) + switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDC_RESTART: ProcessHacker_PrepareForEarlyShutdown(PhMainWndHandle); diff --git a/plugins/ExtendedTools/gpunodes.c b/plugins/ExtendedTools/gpunodes.c index cc56abcd55b6..1526bd358a45 100644 --- a/plugins/ExtendedTools/gpunodes.c +++ b/plugins/ExtendedTools/gpunodes.c @@ -310,7 +310,7 @@ INT_PTR CALLBACK EtpGpuNodesDlgProc( break; case WM_COMMAND: { - switch (LOWORD(wParam)) + switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDCANCEL: case IDOK: diff --git a/plugins/ExtendedTools/gpusys.c b/plugins/ExtendedTools/gpusys.c index 57c9dcb68aae..aae9aec7745a 100644 --- a/plugins/ExtendedTools/gpusys.c +++ b/plugins/ExtendedTools/gpusys.c @@ -236,7 +236,7 @@ INT_PTR CALLBACK EtpGpuPanelDialogProc( { case WM_COMMAND: { - switch (LOWORD(wParam)) + switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDC_NODES: EtShowGpuNodesDialog(GpuDialog, GpuSection->Parameters); diff --git a/plugins/ExtendedTools/modsrv.c b/plugins/ExtendedTools/modsrv.c index 16b110ae4628..654578396009 100644 --- a/plugins/ExtendedTools/modsrv.c +++ b/plugins/ExtendedTools/modsrv.c @@ -158,7 +158,7 @@ INT_PTR CALLBACK EtpModuleServicesDlgProc( break; case WM_COMMAND: { - switch (LOWORD(wParam)) + switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDCANCEL: case IDOK: diff --git a/plugins/ExtendedTools/options.c b/plugins/ExtendedTools/options.c index a33671d5f1e5..cd4c21e63b7d 100644 --- a/plugins/ExtendedTools/options.c +++ b/plugins/ExtendedTools/options.c @@ -61,7 +61,7 @@ INT_PTR CALLBACK OptionsDlgProc( break; case WM_COMMAND: { - switch (LOWORD(wParam)) + switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDCANCEL: EndDialog(hwndDlg, IDCANCEL); diff --git a/plugins/ExtendedTools/unldll.c b/plugins/ExtendedTools/unldll.c index 93325b16fbf3..8a0f5a597649 100644 --- a/plugins/ExtendedTools/unldll.c +++ b/plugins/ExtendedTools/unldll.c @@ -356,7 +356,7 @@ INT_PTR CALLBACK EtpUnloadedDllsDlgProc( break; case WM_COMMAND: { - switch (LOWORD(wParam)) + switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDCANCEL: case IDOK: diff --git a/plugins/ExtendedTools/wswatch.c b/plugins/ExtendedTools/wswatch.c index 470092cb3b0d..9e7ca403c5b5 100644 --- a/plugins/ExtendedTools/wswatch.c +++ b/plugins/ExtendedTools/wswatch.c @@ -507,7 +507,7 @@ INT_PTR CALLBACK EtpWsWatchDlgProc( break; case WM_COMMAND: { - switch (LOWORD(wParam)) + switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDCANCEL: case IDOK: diff --git a/plugins/HardwareDevices/prpsh.c b/plugins/HardwareDevices/prpsh.c index 2aa401d4d246..546ec8f469db 100644 --- a/plugins/HardwareDevices/prpsh.c +++ b/plugins/HardwareDevices/prpsh.c @@ -198,7 +198,7 @@ LRESULT CALLBACK PvpPropSheetWndProc( break; case WM_COMMAND: { - switch (LOWORD(wParam)) + switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDOK: // Prevent the OK button from working (even though diff --git a/plugins/NetworkTools/options.c b/plugins/NetworkTools/options.c index 142402753dd7..caa320ccf068 100644 --- a/plugins/NetworkTools/options.c +++ b/plugins/NetworkTools/options.c @@ -42,7 +42,7 @@ INT_PTR CALLBACK OptionsDlgProc( break; case WM_COMMAND: { - switch (LOWORD(wParam)) + switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDCANCEL: { diff --git a/plugins/NetworkTools/ping.c b/plugins/NetworkTools/ping.c index cb6165e4e30d..fc415881497e 100644 --- a/plugins/NetworkTools/ping.c +++ b/plugins/NetworkTools/ping.c @@ -353,7 +353,7 @@ INT_PTR CALLBACK NetworkPingWndProc( return TRUE; case WM_COMMAND: { - switch (LOWORD(wParam)) + switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDCANCEL: case IDOK: diff --git a/plugins/OnlineChecks/options.c b/plugins/OnlineChecks/options.c index 328c96da5b34..c7f27a4acc97 100644 --- a/plugins/OnlineChecks/options.c +++ b/plugins/OnlineChecks/options.c @@ -43,7 +43,7 @@ INT_PTR CALLBACK OptionsDlgProc( break; case WM_COMMAND: { - switch (LOWORD(wParam)) + switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDCANCEL: { diff --git a/plugins/UserNotes/main.c b/plugins/UserNotes/main.c index 88a55cfa438b..d5bed8c6e40e 100644 --- a/plugins/UserNotes/main.c +++ b/plugins/UserNotes/main.c @@ -1492,7 +1492,7 @@ INT_PTR CALLBACK OptionsDlgProc( break; case WM_COMMAND: { - switch (LOWORD(wParam)) + switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDCANCEL: EndDialog(hwndDlg, IDCANCEL); @@ -1703,11 +1703,11 @@ INT_PTR CALLBACK ProcessCommentPageDlgProc( break; case WM_COMMAND: { - switch (LOWORD(wParam)) + switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDC_COMMENT: { - if (HIWORD(wParam) == EN_CHANGE) + if (GET_WM_COMMAND_CMD(wParam, lParam) == EN_CHANGE) EnableWindow(context->RevertHandle, TRUE); } break; @@ -1813,11 +1813,11 @@ INT_PTR CALLBACK ServiceCommentPageDlgProc( break; case WM_COMMAND: { - switch (LOWORD(wParam)) + switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDC_COMMENT: { - if (HIWORD(wParam) == EN_CHANGE) + if (GET_WM_COMMAND_CMD(wParam, lParam) == EN_CHANGE) EnableWindow(GetDlgItem(hwndDlg, IDC_REVERT), TRUE); } break; diff --git a/plugins/WindowExplorer/wnddlg.c b/plugins/WindowExplorer/wnddlg.c index baa2117ac900..ab97179b6f24 100644 --- a/plugins/WindowExplorer/wnddlg.c +++ b/plugins/WindowExplorer/wnddlg.c @@ -422,7 +422,7 @@ INT_PTR CALLBACK WepWindowsDlgProc( break; } - switch (LOWORD(wParam)) + switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDCANCEL: DestroyWindow(hwndDlg); @@ -847,7 +847,7 @@ INT_PTR CALLBACK WepWindowsPageProc( break; } - switch (LOWORD(wParam)) + switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDC_REFRESH: WepRefreshWindows(context); diff --git a/plugins/WindowExplorer/wndprp.c b/plugins/WindowExplorer/wndprp.c index 515b17ee9c40..c853353a0b11 100644 --- a/plugins/WindowExplorer/wndprp.c +++ b/plugins/WindowExplorer/wndprp.c @@ -413,7 +413,7 @@ LRESULT CALLBACK WepPropSheetWndProc( break; case WM_COMMAND: { - switch (LOWORD(wParam)) + switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDC_REFRESH: { @@ -845,7 +845,7 @@ INT_PTR CALLBACK WepWindowGeneralDlgProc( break; case WM_COMMAND: { - switch (LOWORD(wParam)) + switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDC_REFRESH: context->HookDataValid = FALSE; @@ -977,7 +977,7 @@ INT_PTR CALLBACK WepWindowStylesDlgProc( break; case WM_COMMAND: { - switch (LOWORD(wParam)) + switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDC_REFRESH: WepRefreshWindowStyles(hwndDlg, context); @@ -1092,7 +1092,7 @@ INT_PTR CALLBACK WepWindowClassDlgProc( break; case WM_COMMAND: { - switch (LOWORD(wParam)) + switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDC_REFRESH: context->HookDataValid = FALSE; @@ -1196,7 +1196,7 @@ INT_PTR CALLBACK WepWindowPropertiesDlgProc( break; case WM_COMMAND: { - switch (LOWORD(wParam)) + switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDC_REFRESH: WepRefreshWindowProps(hwndDlg, GetDlgItem(hwndDlg, IDC_LIST), context); From 5d6efceb6d88518fd78494a2d0cc46a3f08ccce1 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 6 Jun 2017 21:08:28 +1000 Subject: [PATCH 0194/2058] partial revert 60abdf1ae8807b95a3434ba5e4bc8cb6003628d5 --- ProcessHacker/memlist.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ProcessHacker/memlist.c b/ProcessHacker/memlist.c index c41417218ba2..87b45fcbdd9a 100644 --- a/ProcessHacker/memlist.c +++ b/ProcessHacker/memlist.c @@ -327,6 +327,9 @@ VOID PhReplaceMemoryList( memoryNode = PhpAddRegionNode(Context, memoryItem); + if (Context->HideFreeRegions && (memoryItem->State & MEM_FREE)) + memoryNode->Node.Visible = FALSE; + if (allocationBaseNode && memoryItem->AllocationBase == allocationBaseNode->MemoryItem->BaseAddress) { if (!(memoryItem->State & MEM_FREE)) @@ -355,6 +358,9 @@ VOID PhReplaceMemoryList( if (memoryItem->RegionType != CustomRegion || memoryItem->u.Custom.PropertyOfAllocationBase) PhpCopyMemoryRegionTypeInfo(memoryItem, allocationBaseNode->MemoryItem); + + if (Context->HideFreeRegions && (allocationBaseNode->MemoryItem->State & MEM_FREE)) + allocationBaseNode->Node.Visible = FALSE; } else { From a390a880138b7e1eb418fe5f6970c2b569545795 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 7 Jun 2017 00:38:23 +1000 Subject: [PATCH 0195/2058] Updater: disable installer mode --- plugins/Updater/page5.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/Updater/page5.c b/plugins/Updater/page5.c index 0b766debcfeb..0a94def0107c 100644 --- a/plugins/Updater/page5.c +++ b/plugins/Updater/page5.c @@ -66,7 +66,7 @@ HRESULT CALLBACK FinalTaskDialogCallbackProc( break; info.lpFile = PhGetStringOrEmpty(context->SetupFilePath); - info.lpParameters = L"-update"; + //info.lpParameters = L"-update"; info.lpVerb = PhGetOwnTokenAttributes().Elevated ? NULL : L"runas"; info.nShow = SW_SHOW; info.hwnd = hwndDlg; From a31181accdff1a1f29cce7ecde45f5e2b4b49478 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 7 Jun 2017 00:50:23 +1000 Subject: [PATCH 0196/2058] Fix regression --- ProcessHacker/notifico.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ProcessHacker/notifico.c b/ProcessHacker/notifico.c index 66aaa2891ae0..0dfe8e91674c 100644 --- a/ProcessHacker/notifico.c +++ b/ProcessHacker/notifico.c @@ -25,7 +25,6 @@ #include #include -#include #include #include @@ -208,7 +207,7 @@ VOID PhNfForwardMessage( } } - switch (GET_WM_COMMAND_ID(WParam, LParam)) + switch (LOWORD(LParam)) { case WM_LBUTTONDOWN: { From b8b063a9eba2a2ab533c848c152c6cee7e7e2423 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 7 Jun 2017 02:03:54 +1000 Subject: [PATCH 0197/2058] Add buildsdk command fix --- ProcessHacker/ProcessHacker.vcxproj | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ProcessHacker/ProcessHacker.vcxproj b/ProcessHacker/ProcessHacker.vcxproj index 2220ef6efe98..2e5b41dd74cf 100644 --- a/ProcessHacker/ProcessHacker.vcxproj +++ b/ProcessHacker/ProcessHacker.vcxproj @@ -109,7 +109,7 @@ $(SolutionDir)phnt\include;$(SolutionDir)phlib\include;include;%(AdditionalIncludeDirectories) - $(SolutionDir)build\build_sdk.cmd + "$(SolutionDir)build\build_sdk.cmd" @@ -141,7 +141,7 @@ - $(SolutionDir)build\build_sdk.cmd + "$(SolutionDir)build\build_sdk.cmd" @@ -179,7 +179,7 @@ $(SolutionDir)phnt\include;$(SolutionDir)phlib\include;include;%(AdditionalIncludeDirectories) - $(SolutionDir)build\build_sdk.cmd + "$(SolutionDir)build\build_sdk.cmd" @@ -216,7 +216,7 @@ $(SolutionDir)phnt\include;$(SolutionDir)phlib\include;include;%(AdditionalIncludeDirectories) - $(SolutionDir)build\build_sdk.cmd + "$(SolutionDir)build\build_sdk.cmd" From 6e866dae983ddb0fa91480b43fdb0a22d1bd9e70 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 7 Jun 2017 03:08:42 +1000 Subject: [PATCH 0198/2058] Fix PsAttributes #147, Fix spacing --- phnt/include/ntpsapi.h | 45 ++++++++++++++++++++------------- phnt/include/ntrtl.h | 56 +++++++++++++++++++++--------------------- 2 files changed, 56 insertions(+), 45 deletions(-) diff --git a/phnt/include/ntpsapi.h b/phnt/include/ntpsapi.h index 23ae8b712e56..002a83c1d48d 100644 --- a/phnt/include/ntpsapi.h +++ b/phnt/include/ntpsapi.h @@ -1222,15 +1222,15 @@ typedef enum _PS_ATTRIBUTE_NUM PsAttributeIdealProcessor, // in PPROCESSOR_NUMBER PsAttributeUmsThread, // ? in PUMS_CREATE_THREAD_ATTRIBUTES PsAttributeMitigationOptions, // in UCHAR - PsAttributeProtectionLevel, + PsAttributeProtectionLevel, // in ULONG PsAttributeSecureProcess, // since THRESHOLD PsAttributeJobList, PsAttributeChildProcessPolicy, // since THRESHOLD2 PsAttributeAllApplicationPackagesPolicy, // since REDSTONE PsAttributeWin32kFilter, PsAttributeSafeOpenPromptOriginClaim, - PsAttributeBnoIsolation, - PsAttributeDesktopAppPolicy, + PsAttributeBnoIsolation, // PS_BNO_ISOLATION_PARAMETERS + PsAttributeDesktopAppPolicy, // in ULONG PsAttributeMax } PS_ATTRIBUTE_NUM; @@ -1243,11 +1243,11 @@ typedef enum _PS_ATTRIBUTE_NUM ((Additive) ? PS_ATTRIBUTE_ADDITIVE : 0)) #define PS_ATTRIBUTE_PARENT_PROCESS \ - PsAttributeValue(PsAttributeParentProcess, FALSE, TRUE, FALSE) + PsAttributeValue(PsAttributeParentProcess, FALSE, TRUE, TRUE) #define PS_ATTRIBUTE_DEBUG_PORT \ - PsAttributeValue(PsAttributeDebugPort, FALSE, TRUE, FALSE) + PsAttributeValue(PsAttributeDebugPort, FALSE, TRUE, TRUE) #define PS_ATTRIBUTE_TOKEN \ - PsAttributeValue(PsAttributeToken, FALSE, TRUE, FALSE) + PsAttributeValue(PsAttributeToken, FALSE, TRUE, TRUE) #define PS_ATTRIBUTE_CLIENT_ID \ PsAttributeValue(PsAttributeClientId, TRUE, FALSE, FALSE) #define PS_ATTRIBUTE_TEB_ADDRESS \ @@ -1274,6 +1274,8 @@ typedef enum _PS_ATTRIBUTE_NUM PsAttributeValue(PsAttributeIdealProcessor, TRUE, TRUE, FALSE) #define PS_ATTRIBUTE_MITIGATION_OPTIONS \ PsAttributeValue(PsAttributeMitigationOptions, FALSE, TRUE, TRUE) +#define PS_ATTRIBUTE_PROTECTION_LEVEL \ + PsAttributeValue(PsAttributeProtectionLevel, FALSE, TRUE, FALSE) // end_rev @@ -1331,18 +1333,14 @@ typedef struct _PS_STD_HANDLE_INFO ULONG StdHandleSubsystemType; } PS_STD_HANDLE_INFO, *PPS_STD_HANDLE_INFO; -// windows-internals-book:"Chapter 5" -typedef enum _PS_CREATE_STATE +// private +typedef struct _PS_BNO_ISOLATION_PARAMETERS { - PsCreateInitialState, - PsCreateFailOnFileOpen, - PsCreateFailOnSectionCreate, - PsCreateFailExeFormat, - PsCreateFailMachineMismatch, - PsCreateFailExeName, // Debugger specified - PsCreateSuccess, - PsCreateMaximumStates -} PS_CREATE_STATE; + UNICODE_STRING IsolationPrefix; + ULONG HandleCount; + PVOID *Handles; + BOOLEAN IsolationEnabled; +} PS_BNO_ISOLATION_PARAMETERS, *PPS_BNO_ISOLATION_PARAMETERS; // private typedef enum _PS_MITIGATION_OPTION @@ -1369,6 +1367,19 @@ typedef enum _PS_MITIGATION_OPTION PS_MITIGATION_OPTION_RESTRICT_SET_THREAD_CONTEXT } PS_MITIGATION_OPTION; +// windows-internals-book:"Chapter 5" +typedef enum _PS_CREATE_STATE +{ + PsCreateInitialState, + PsCreateFailOnFileOpen, + PsCreateFailOnSectionCreate, + PsCreateFailExeFormat, + PsCreateFailMachineMismatch, + PsCreateFailExeName, // Debugger specified + PsCreateSuccess, + PsCreateMaximumStates +} PS_CREATE_STATE; + typedef struct _PS_CREATE_INFO { SIZE_T Size; diff --git a/phnt/include/ntrtl.h b/phnt/include/ntrtl.h index 1d904d2ead41..c7522fb38c09 100644 --- a/phnt/include/ntrtl.h +++ b/phnt/include/ntrtl.h @@ -323,13 +323,13 @@ typedef struct _RTL_SPLAY_LINKS } RTL_SPLAY_LINKS, *PRTL_SPLAY_LINKS; #define RtlInitializeSplayLinks(Links) \ - { \ - PRTL_SPLAY_LINKS _SplayLinks; \ - _SplayLinks = (PRTL_SPLAY_LINKS)(Links); \ - _SplayLinks->Parent = _SplayLinks; \ - _SplayLinks->LeftChild = NULL; \ - _SplayLinks->RightChild = NULL; \ - } +{ \ + PRTL_SPLAY_LINKS _SplayLinks; \ + _SplayLinks = (PRTL_SPLAY_LINKS)(Links); \ + _SplayLinks->Parent = _SplayLinks; \ + _SplayLinks->LeftChild = NULL; \ + _SplayLinks->RightChild = NULL; \ +} #define RtlParent(Links) ((PRTL_SPLAY_LINKS)(Links)->Parent) #define RtlLeftChild(Links) ((PRTL_SPLAY_LINKS)(Links)->LeftChild) @@ -339,24 +339,24 @@ typedef struct _RTL_SPLAY_LINKS #define RtlIsRightChild(Links) ((RtlRightChild(RtlParent(Links)) == (PRTL_SPLAY_LINKS)(Links))) #define RtlInsertAsLeftChild(ParentLinks, ChildLinks) \ - { \ - PRTL_SPLAY_LINKS _SplayParent; \ - PRTL_SPLAY_LINKS _SplayChild; \ - _SplayParent = (PRTL_SPLAY_LINKS)(ParentLinks); \ - _SplayChild = (PRTL_SPLAY_LINKS)(ChildLinks); \ - _SplayParent->LeftChild = _SplayChild; \ - _SplayChild->Parent = _SplayParent; \ - } +{ \ + PRTL_SPLAY_LINKS _SplayParent; \ + PRTL_SPLAY_LINKS _SplayChild; \ + _SplayParent = (PRTL_SPLAY_LINKS)(ParentLinks); \ + _SplayChild = (PRTL_SPLAY_LINKS)(ChildLinks); \ + _SplayParent->LeftChild = _SplayChild; \ + _SplayChild->Parent = _SplayParent; \ +} #define RtlInsertAsRightChild(ParentLinks, ChildLinks) \ - { \ - PRTL_SPLAY_LINKS _SplayParent; \ - PRTL_SPLAY_LINKS _SplayChild; \ - _SplayParent = (PRTL_SPLAY_LINKS)(ParentLinks); \ - _SplayChild = (PRTL_SPLAY_LINKS)(ChildLinks); \ - _SplayParent->RightChild = _SplayChild; \ - _SplayChild->Parent = _SplayParent; \ - } +{ \ + PRTL_SPLAY_LINKS _SplayParent; \ + PRTL_SPLAY_LINKS _SplayChild; \ + _SplayParent = (PRTL_SPLAY_LINKS)(ParentLinks); \ + _SplayChild = (PRTL_SPLAY_LINKS)(ChildLinks); \ + _SplayParent->RightChild = _SplayChild; \ + _SplayChild->Parent = _SplayParent; \ +} NTSYSAPI PRTL_SPLAY_LINKS @@ -954,11 +954,11 @@ typedef struct _RTL_RESOURCE RTL_CRITICAL_SECTION CriticalSection; HANDLE SharedSemaphore; - ULONG NumberOfWaitingShared; + volatile ULONG NumberOfWaitingShared; HANDLE ExclusiveSemaphore; - ULONG NumberOfWaitingExclusive; + volatile ULONG NumberOfWaitingExclusive; - LONG NumberOfActive; // negative: exclusive acquire; zero: not acquired; positive: shared acquire(s) + volatile LONG NumberOfActive; // negative: exclusive acquire; zero: not acquired; positive: shared acquire(s) HANDLE ExclusiveOwnerThread; ULONG Flags; // RTL_RESOURCE_FLAG_* @@ -2407,8 +2407,8 @@ typedef struct _RTL_USER_PROCESS_PARAMETERS UNICODE_STRING RuntimeData; RTL_DRIVE_LETTER_CURDIR CurrentDirectories[RTL_MAX_DRIVE_LETTERS]; - ULONG EnvironmentSize; - ULONG EnvironmentVersion; + ULONG_PTR EnvironmentSize; + ULONG_PTR EnvironmentVersion; PVOID PackageDependencyData; ULONG ProcessGroupId; ULONG LoaderThreads; From a94fef7c568d1897cb1d6b7c6d86277f755648bc Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 8 Jun 2017 00:33:17 +1000 Subject: [PATCH 0199/2058] Update ProcessEnergyValues & SystemFullProcessInformation --- ProcessHacker/settings.c | 1 + phnt/include/ntexapi.h | 67 +++++++++++++++++++++++++++++++++++----- phnt/include/ntpsapi.h | 2 +- 3 files changed, 61 insertions(+), 9 deletions(-) diff --git a/ProcessHacker/settings.c b/ProcessHacker/settings.c index 547591b0f0fd..3501aebaf6f4 100644 --- a/ProcessHacker/settings.c +++ b/ProcessHacker/settings.c @@ -46,6 +46,7 @@ VOID PhAddDefaultSettings( PhpAddIntegerSetting(L"EnableServiceNonPoll", L"1"); PhpAddIntegerSetting(L"EnableStage2", L"1"); PhpAddIntegerSetting(L"EnableWarnings", L"1"); + PhpAddIntegerSetting(L"EnableWindowText", L"1"); PhpAddStringSetting(L"EnvironmentListViewColumns", L""); PhpAddIntegerSetting(L"FindObjRegex", L"0"); PhpAddStringSetting(L"FindObjListViewColumns", L""); diff --git a/phnt/include/ntexapi.h b/phnt/include/ntexapi.h index 545f81e9ad52..5a42dbf6bffa 100644 --- a/phnt/include/ntexapi.h +++ b/phnt/include/ntexapi.h @@ -2662,6 +2662,18 @@ typedef struct _PROCESS_DISK_COUNTERS } PROCESS_DISK_COUNTERS, *PPROCESS_DISK_COUNTERS; // private +typedef struct _ENERGY_STATE_DURATION +{ + union + { + ULONGLONG Value; + ULONG LastChangeTime; + }; + + ULONG Duration : 31; + ULONG IsInState : 1; +} ENERGY_STATE_DURATION, *PENERGY_STATE_DURATION; + typedef struct _PROCESS_ENERGY_VALUES { ULONGLONG Cycles[2][4]; @@ -2672,19 +2684,55 @@ typedef struct _PROCESS_ENERGY_VALUES ULONGLONG MBBTxRxBytes; union { + ENERGY_STATE_DURATION Durations[3]; struct { - ULONG Foreground : 1; + ENERGY_STATE_DURATION ForegroundDuration; + ENERGY_STATE_DURATION DesktopVisibleDuration; + ENERGY_STATE_DURATION PSMForegroundDuration; }; - ULONG WindowInformation; }; - ULONG PixelArea; - LONGLONG PixelReportTimestamp; - ULONGLONG PixelTime; - LONGLONG ForegroundReportTimestamp; - ULONGLONG ForegroundTime; + ULONG CompositionRendered; + ULONG CompositionDirtyGenerated; + ULONG CompositionDirtyPropagated; + ULONG Reserved1; + ULONGLONG AttributedCycles[2][4]; + ULONGLONG WorkOnBehalfCycles[2][4]; } PROCESS_ENERGY_VALUES, *PPROCESS_ENERGY_VALUES; +typedef struct _TIMELINE_BITMAP +{ + ULONGLONG Value; + ULONG EndTime; + ULONG Bitmap; +} TIMELINE_BITMAP, *PTIMELINE_BITMAP; + +typedef struct _PROCESS_ENERGY_VALUES_EXTENSION +{ + union + { + TIMELINE_BITMAP Timelines[9]; + struct + { + TIMELINE_BITMAP CpuTimeline; + TIMELINE_BITMAP DiskTimeline; + TIMELINE_BITMAP NetworkTimeline; + TIMELINE_BITMAP MBBTimeline; + TIMELINE_BITMAP ForegroundTimeline; + TIMELINE_BITMAP DesktopVisibleTimeline; + TIMELINE_BITMAP CompositionRenderedTimeline; + TIMELINE_BITMAP CompositionDirtyGeneratedTimeline; + TIMELINE_BITMAP CompositionDirtyPropagatedTimeline; + }; + }; +} PROCESS_ENERGY_VALUES_EXTENSION, *PPROCESS_ENERGY_VALUES_EXTENSION; + +typedef struct _PROCESS_EXTENDED_ENERGY_VALUES +{ + PROCESS_ENERGY_VALUES Base; + PROCESS_ENERGY_VALUES_EXTENSION Extension; +} PROCESS_EXTENDED_ENERGY_VALUES, *PPROCESS_EXTENDED_ENERGY_VALUES; + // private typedef struct _SYSTEM_PROCESS_INFORMATION_EXTENSION { @@ -2696,7 +2744,9 @@ typedef struct _SYSTEM_PROCESS_INFORMATION_EXTENSION struct { ULONG HasStrongId : 1; - ULONG Spare : 31; + ULONG Classification : 4; + ULONG BackgroundActivityModerated : 1; + ULONG Spare : 26; }; }; ULONG UserSidOffset; @@ -2706,6 +2756,7 @@ typedef struct _SYSTEM_PROCESS_INFORMATION_EXTENSION SIZE_T SharedCommitCharge; // since THRESHOLD2 ULONG JobObjectId; // since REDSTONE ULONG SpareUlong; // since REDSTONE + ULONGLONG ProcessSequenceNumber; } SYSTEM_PROCESS_INFORMATION_EXTENSION, *PSYSTEM_PROCESS_INFORMATION_EXTENSION; // private diff --git a/phnt/include/ntpsapi.h b/phnt/include/ntpsapi.h index 002a83c1d48d..0e65c8dfd8f2 100644 --- a/phnt/include/ntpsapi.h +++ b/phnt/include/ntpsapi.h @@ -173,7 +173,7 @@ typedef enum _PROCESSINFOCLASS ProcessChildProcessInformation, // PROCESS_CHILD_PROCESS_INFORMATION ProcessHighGraphicsPriorityInformation, ProcessSubsystemInformation, // q: SUBSYSTEM_INFORMATION_TYPE // since REDSTONE2 - ProcessEnergyValues, + ProcessEnergyValues, // PROCESS_ENERGY_VALUES, PROCESS_EXTENDED_ENERGY_VALUES ProcessActivityThrottleState, // PROCESS_ACTIVITY_THROTTLE_STATE ProcessActivityThrottlePolicy, // PROCESS_ACTIVITY_THROTTLE_POLICY ProcessWin32kSyscallFilterInformation, From 53e8a37a66befc1e3726854d642dcc8637fb118a Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 8 Jun 2017 05:08:00 +1000 Subject: [PATCH 0200/2058] Update HEAP_INFORMATION_CLASS, Fix RTL_USER_PROCESS_PARAMETERS32 types --- ProcessHacker/dbgcon.c | 2 +- phnt/include/ntrtl.h | 40 ++++++++++++++++++++++++++++++++++++++-- phnt/include/ntwow64.h | 4 ++-- 3 files changed, 41 insertions(+), 5 deletions(-) diff --git a/ProcessHacker/dbgcon.c b/ProcessHacker/dbgcon.c index 7708ddbae347..2107da471b6b 100644 --- a/ProcessHacker/dbgcon.c +++ b/ProcessHacker/dbgcon.c @@ -1558,7 +1558,7 @@ NTSTATUS PhpDebugConsoleThreadStart( debuggingInfo.StackTraceDepth = 32; debuggingInfo.HeapLeakEnumerationRoutine = PhpLeakEnumerationRoutine; - if (!NT_SUCCESS(RtlSetHeapInformation(NULL, HeapDebuggingInformation, &debuggingInfo, sizeof(HEAP_DEBUGGING_INFORMATION)))) + if (!NT_SUCCESS(RtlSetHeapInformation(NULL, HeapSetDebuggingInformation, &debuggingInfo, sizeof(HEAP_DEBUGGING_INFORMATION)))) { wprintf(L"Unable to initialize heap debugging. Make sure that you are using Windows 7 or above."); } diff --git a/phnt/include/ntrtl.h b/phnt/include/ntrtl.h index c7522fb38c09..0f01ff0e065b 100644 --- a/phnt/include/ntrtl.h +++ b/phnt/include/ntrtl.h @@ -3595,8 +3595,44 @@ RtlWalkHeap( _Inout_ PRTL_HEAP_WALK_ENTRY Entry ); -// rev -#define HeapDebuggingInformation 0x80000002 +// HEAP_INFORMATION_CLASS +#define HeapCompatibilityInformation 0x0 // q; s: ULONG +#define HeapEnableTerminationOnCorruption 0x1 // q; s: NULL +#define HeapExtendedInformation 0x2 // q; s: HEAP_EXTENDED_INFORMATION +#define HeapOptimizeResources 0x3 // q; s: HEAP_OPTIMIZE_RESOURCES_INFORMATION +#define HeapTaggingInformation 0x4 +#define HeapStackDatabase 0x5 +#define HeapDetailedFailureInformation 0x80000001 +#define HeapSetDebuggingInformation 0x80000002 // q; s: HEAP_DEBUGGING_INFORMATION + +typedef struct _PROCESS_HEAP_INFORMATION +{ + ULONG_PTR ReserveSize; + ULONG_PTR CommitSize; + ULONG NumberOfHeaps; + ULONG_PTR FirstHeapInformationOffset; +} PROCESS_HEAP_INFORMATION, *PPROCESS_HEAP_INFORMATION; + +typedef struct _HEAP_INFORMATION +{ + ULONG_PTR Address; + ULONG Mode; + ULONG_PTR ReserveSize; + ULONG_PTR CommitSize; + ULONG_PTR FirstRegionInformationOffset; + ULONG_PTR NextHeapInformationOffset; +} HEAP_INFORMATION, *PHEAP_INFORMATION; + +typedef struct _HEAP_EXTENDED_INFORMATION +{ + HANDLE Process; + ULONG_PTR Heap; + ULONG Level; + PVOID CallbackRoutine; + PVOID CallbackContext; + PROCESS_HEAP_INFORMATION ProcessHeapInformation; + HEAP_INFORMATION HeapInformation; +} HEAP_EXTENDED_INFORMATION, *PHEAP_EXTENDED_INFORMATION; // rev typedef NTSTATUS (NTAPI *PRTL_HEAP_LEAK_ENUMERATION_ROUTINE)( diff --git a/phnt/include/ntwow64.h b/phnt/include/ntwow64.h index 985c5f0a911e..16948f927aae 100644 --- a/phnt/include/ntwow64.h +++ b/phnt/include/ntwow64.h @@ -219,8 +219,8 @@ typedef struct _RTL_USER_PROCESS_PARAMETERS32 UNICODE_STRING32 RuntimeData; RTL_DRIVE_LETTER_CURDIR32 CurrentDirectories[RTL_MAX_DRIVE_LETTERS]; - ULONG EnvironmentSize; - ULONG EnvironmentVersion; + WOW64_POINTER(ULONG_PTR) EnvironmentSize; + WOW64_POINTER(ULONG_PTR) EnvironmentVersion; WOW64_POINTER(PVOID) PackageDependencyData; ULONG ProcessGroupId; ULONG LoaderThreads; From ca494f6a683a397ac014421ad61acbe233d17e7a Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 8 Jun 2017 05:15:59 +1000 Subject: [PATCH 0201/2058] Update more default window icons --- ProcessHacker/findobj.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ProcessHacker/findobj.c b/ProcessHacker/findobj.c index 1865b4b54f99..2c222fa4f177 100644 --- a/ProcessHacker/findobj.c +++ b/ProcessHacker/findobj.c @@ -215,6 +215,9 @@ static INT_PTR CALLBACK PhpFindObjectsDlgProc( { HWND lvHandle; + SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhLibImageBase, MAKEINTRESOURCE(IDI_PROCESSHACKER))); + SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhLibImageBase, MAKEINTRESOURCE(IDI_PROCESSHACKER))); + PhCenterWindow(hwndDlg, GetParent(hwndDlg)); PhFindObjectsListViewHandle = lvHandle = GetDlgItem(hwndDlg, IDC_RESULTS); From 2aa3678afa717b841793f8c1ee92e4263203fb09 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 8 Jun 2017 20:09:04 +1000 Subject: [PATCH 0202/2058] DotNetTools: Remove XP support --- plugins/DotNetTools/asmpage.c | 20 +------------------- 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/plugins/DotNetTools/asmpage.c b/plugins/DotNetTools/asmpage.c index fc9419e258b2..f21322d1026f 100644 --- a/plugins/DotNetTools/asmpage.c +++ b/plugins/DotNetTools/asmpage.c @@ -113,18 +113,6 @@ typedef struct _FLAG_DEFINITION ULONG Flag; } FLAG_DEFINITION, *PFLAG_DEFINITION; -typedef ULONG (__stdcall *_EnableTraceEx)( - _In_ LPCGUID ProviderId, - _In_opt_ LPCGUID SourceId, - _In_ TRACEHANDLE TraceHandle, - _In_ ULONG IsEnabled, - _In_ UCHAR Level, - _In_ ULONGLONG MatchAnyKeyword, - _In_ ULONGLONG MatchAllKeyword, - _In_ ULONG EnableProperty, - _In_opt_ PEVENT_FILTER_DESCRIPTOR EnableFilterDesc - ); - VOID DestroyDotNetTraceQuery( _In_ PASMPAGE_QUERY_CONTEXT Context ); @@ -926,17 +914,11 @@ NTSTATUS UpdateDotNetTraceInfoThreadStart( _In_ PVOID Parameter ) { - static _EnableTraceEx EnableTraceEx_I = NULL; PASMPAGE_QUERY_CONTEXT context = Parameter; TRACEHANDLE sessionHandle; PEVENT_TRACE_PROPERTIES properties; PGUID guidToEnable; - if (!EnableTraceEx_I) - EnableTraceEx_I = PhGetModuleProcAddress(L"advapi32.dll", "EnableTraceEx"); - if (!EnableTraceEx_I) - return ERROR_NOT_SUPPORTED; - context->TraceResult = StartDotNetTrace(&sessionHandle, &properties); if (context->TraceResult != 0) @@ -947,7 +929,7 @@ NTSTATUS UpdateDotNetTraceInfoThreadStart( else guidToEnable = &ClrRuntimeProviderGuid; - EnableTraceEx_I( + EnableTraceEx( guidToEnable, NULL, sessionHandle, From 2cb7b9a3020e21cda5642378b17cbd3147c1605a Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 9 Jun 2017 09:46:41 +1000 Subject: [PATCH 0203/2058] Add PEB comment --- phnt/include/ntpebteb.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phnt/include/ntpebteb.h b/phnt/include/ntpebteb.h index 5b6801e5dd9c..60f3b02adc67 100644 --- a/phnt/include/ntpebteb.h +++ b/phnt/include/ntpebteb.h @@ -108,7 +108,7 @@ typedef struct _PEB ULARGE_INTEGER AppCompatFlags; ULARGE_INTEGER AppCompatFlagsUser; PVOID pShimData; - PVOID AppCompatInfo; + PVOID AppCompatInfo; // APPCOMPAT_EXE_DATA UNICODE_STRING CSDVersion; From c14c8ca0616b8d4c69ecd28008b245399b3925bd Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 11 Jun 2017 00:59:12 +1000 Subject: [PATCH 0204/2058] Remove unused resources (patch by tetyys) (1/2) --- ProcessHacker/include/mainwnd.h | 2 -- ProcessHacker/include/mainwndp.h | 2 +- ProcessHacker/mainwnd.c | 52 +++++++++++++++++--------------- ProcessHacker/resource.h | 4 --- ProcessHacker/settings.c | 1 + 5 files changed, 30 insertions(+), 31 deletions(-) diff --git a/ProcessHacker/include/mainwnd.h b/ProcessHacker/include/mainwnd.h index bd6259c0c169..12cfb2551d49 100644 --- a/ProcessHacker/include/mainwnd.h +++ b/ProcessHacker/include/mainwnd.h @@ -1,8 +1,6 @@ #ifndef PH_MAINWND_H #define PH_MAINWND_H -#define PH_MAINWND_CLASSNAME L"ProcessHacker" // phapppub - PHAPPAPI extern HWND PhMainWndHandle; // phapppub extern BOOLEAN PhMainWndExiting; diff --git a/ProcessHacker/include/mainwndp.h b/ProcessHacker/include/mainwndp.h index 239f6f720bbd..ef1b7c8ea106 100644 --- a/ProcessHacker/include/mainwndp.h +++ b/ProcessHacker/include/mainwndp.h @@ -33,7 +33,7 @@ LRESULT CALLBACK PhMwpWndProc( // Initialization -BOOLEAN PhMwpInitializeWindowClass( +RTL_ATOM PhMwpInitializeWindowClass( VOID ); diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index 76c9b25b83d7..1941ca980cab 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -3,6 +3,7 @@ * Main window * * Copyright (C) 2009-2016 wj32 + * Copyright (C) 2017 dmex * * This file is part of Process Hacker. * @@ -99,6 +100,7 @@ BOOLEAN PhMainWndInitialization( _In_ INT ShowCommand ) { + RTL_ATOM windowAtom; PH_STRING_BUILDER stringBuilder; PH_RECTANGLE windowRectangle; @@ -118,7 +120,7 @@ BOOLEAN PhMainWndInitialization( PhMwpInitializeProviders(); - if (!PhMwpInitializeWindowClass()) + if ((windowAtom = PhMwpInitializeWindowClass()) == INVALID_ATOM) return FALSE; windowRectangle.Position = PhGetIntegerPairSetting(L"MainWindowPosition"); @@ -127,23 +129,27 @@ BOOLEAN PhMainWndInitialization( // Create the window title. PhInitializeStringBuilder(&stringBuilder, 100); - PhAppendStringBuilder2(&stringBuilder, L"Process Hacker"); - if (PhCurrentUserName) + if (PhGetIntegerSetting(L"EnableWindowText")) { - PhAppendStringBuilder2(&stringBuilder, L" ["); - PhAppendStringBuilder(&stringBuilder, &PhCurrentUserName->sr); - PhAppendCharStringBuilder(&stringBuilder, ']'); - if (KphIsConnected()) PhAppendCharStringBuilder(&stringBuilder, '+'); - } + PhAppendStringBuilder2(&stringBuilder, L"Process Hacker"); + + if (PhCurrentUserName) + { + PhAppendStringBuilder2(&stringBuilder, L" ["); + PhAppendStringBuilder(&stringBuilder, &PhCurrentUserName->sr); + PhAppendCharStringBuilder(&stringBuilder, ']'); + if (KphIsConnected()) PhAppendCharStringBuilder(&stringBuilder, '+'); + } - if (WINDOWS_HAS_UAC && PhGetOwnTokenAttributes().ElevationType == TokenElevationTypeFull) - PhAppendStringBuilder2(&stringBuilder, L" (Administrator)"); + if (WINDOWS_HAS_UAC && PhGetOwnTokenAttributes().ElevationType == TokenElevationTypeFull) + PhAppendStringBuilder2(&stringBuilder, L" (Administrator)"); + } // Create the window. PhMainWndHandle = CreateWindow( - PH_MAINWND_CLASSNAME, + MAKEINTATOM(windowAtom), stringBuilder.String->Buffer, WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN, windowRectangle.Left, @@ -329,12 +335,13 @@ LRESULT CALLBACK PhMwpWndProc( return DefWindowProc(hWnd, uMsg, wParam, lParam); } -BOOLEAN PhMwpInitializeWindowClass( +RTL_ATOM PhMwpInitializeWindowClass( VOID ) { WNDCLASSEX wcex; - + PPH_STRING className; + memset(&wcex, 0, sizeof(WNDCLASSEX)); wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = 0; @@ -342,17 +349,14 @@ BOOLEAN PhMwpInitializeWindowClass( wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = PhInstanceHandle; - wcex.hIcon = PH_LOAD_SHARED_ICON_LARGE(PhLibImageBase, MAKEINTRESOURCE(IDI_PROCESSHACKER)); - wcex.hCursor = LoadCursor(NULL, IDC_ARROW); - //wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); + className = PhaGetStringSetting(L"MainWindowClassName"); + wcex.lpszClassName = PhGetStringOrDefault(className, L"MainWindowClassName"); wcex.lpszMenuName = MAKEINTRESOURCE(IDR_MAINWND); - wcex.lpszClassName = PH_MAINWND_CLASSNAME; + wcex.hCursor = LoadCursor(NULL, IDC_ARROW); + wcex.hIcon = PH_LOAD_SHARED_ICON_LARGE(PhLibImageBase, MAKEINTRESOURCE(IDI_PROCESSHACKER)); wcex.hIconSm = PH_LOAD_SHARED_ICON_SMALL(PhLibImageBase, MAKEINTRESOURCE(IDI_PROCESSHACKER)); - if (!RegisterClassEx(&wcex)) - return FALSE; - - return TRUE; + return RegisterClassEx(&wcex); } VOID PhMwpInitializeProviders( @@ -425,7 +429,7 @@ VOID PhMwpInitializeControls( 3, 3, PhMainWndHandle, - (HMENU)ID_MAINWND_PROCESSTL, + NULL, PhLibImageBase, NULL ); @@ -440,7 +444,7 @@ VOID PhMwpInitializeControls( 3, 3, PhMainWndHandle, - (HMENU)ID_MAINWND_SERVICETL, + NULL, PhLibImageBase, NULL ); @@ -455,7 +459,7 @@ VOID PhMwpInitializeControls( 3, 3, PhMainWndHandle, - (HMENU)ID_MAINWND_NETWORKTL, + NULL, PhLibImageBase, NULL ); diff --git a/ProcessHacker/resource.h b/ProcessHacker/resource.h index 0b906b03259b..b8c58833da9e 100644 --- a/ProcessHacker/resource.h +++ b/ProcessHacker/resource.h @@ -534,10 +534,6 @@ #define IDC_HANDLESEARCH 1385 #define IDC_SEARCH 1387 #define IDC_FILTEROPTIONS 1389 -#define ID_MAINWND_PROCESSTL 2001 -#define ID_MAINWND_SERVICETL 2002 -#define ID_MAINWND_NETWORKTL 2003 -#define ID_MAINWND_PROCESSLV 2004 #define ID_HACKER_EXIT 40001 #define ID_PROCESS_PROPERTIES 40006 #define ID_PROCESS_TERMINATE 40007 diff --git a/ProcessHacker/settings.c b/ProcessHacker/settings.c index 3501aebaf6f4..a2f16f8c98c2 100644 --- a/ProcessHacker/settings.c +++ b/ProcessHacker/settings.c @@ -81,6 +81,7 @@ VOID PhAddDefaultSettings( PhpAddIntegerPairSetting(L"LogWindowPosition", L"300,300"); PhpAddScalableIntegerPairSetting(L"LogWindowSize", L"@96|450,500"); PhpAddIntegerSetting(L"MainWindowAlwaysOnTop", L"0"); + PhpAddStringSetting(L"MainWindowClassName", L"MainWindowClassName"); PhpAddIntegerSetting(L"MainWindowOpacity", L"0"); // means 100% PhpAddIntegerPairSetting(L"MainWindowPosition", L"100,100"); PhpAddScalableIntegerPairSetting(L"MainWindowSize", L"@96|800,600"); From 15a09ae75d7b8c8e64b6850bd2dfad0cdcedad8a Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 11 Jun 2017 01:02:30 +1000 Subject: [PATCH 0205/2058] Improve startup performance, Improve installer mutant handling, Improve single instance (2/2) --- ProcessHacker/main.c | 59 ++++++++++++++++++++++++++++++++---------- phlib/include/phutil.h | 35 +++++++++++++++++++++++++ 2 files changed, 80 insertions(+), 14 deletions(-) diff --git a/ProcessHacker/main.c b/ProcessHacker/main.c index 3d8b82255a96..6b9a95c163f5 100644 --- a/ProcessHacker/main.c +++ b/ProcessHacker/main.c @@ -252,17 +252,26 @@ INT WINAPI wWinMain( HANDLE mutantHandle; OBJECT_ATTRIBUTES oa; UNICODE_STRING mutantName; + PPH_STRING objectName; + PH_FORMAT format[2]; + + PhInitFormatS(&format[0], L"PhMutant_"); + PhInitFormatU(&format[1], HandleToUlong(NtCurrentProcessId())); + + objectName = PhFormat(format, 2, 16); + PhStringRefToUnicodeString(&objectName->sr, &mutantName); - RtlInitUnicodeString(&mutantName, L"\\BaseNamedObjects\\ProcessHackerMutant"); InitializeObjectAttributes( &oa, &mutantName, - 0, - NULL, + OBJ_CASE_INSENSITIVE, + PhGetNamespaceHandle(), NULL ); NtCreateMutant(&mutantHandle, MUTANT_ALL_ACCESS, &oa, FALSE); + + PhDereferenceObject(objectName); } // Set priority. @@ -418,26 +427,48 @@ VOID PhUnregisterMessageLoopFilter( PhFree(FilterEntry); } -VOID PhActivatePreviousInstance( - VOID +static BOOLEAN NTAPI PhpPreviousInstancesCallback( + _In_ PPH_STRINGREF Name, + _In_ PPH_STRINGREF TypeName, + _In_opt_ PVOID Context ) { - HWND hwnd; - - hwnd = FindWindow(PH_MAINWND_CLASSNAME, NULL); + ULONG64 processId64; + PH_STRINGREF firstPart; + PH_STRINGREF secondPart; - if (hwnd) + if ( + PhStartsWithStringRef2(Name, L"PhMutant_", TRUE) && + PhSplitStringRefAtChar(Name, L'_', &firstPart, &secondPart) && + PhStringToInteger64(&secondPart, 10, &processId64) + ) { - ULONG_PTR result; + HWND hwnd; - SendMessageTimeout(hwnd, WM_PH_ACTIVATE, PhStartupParameters.SelectPid, 0, SMTO_BLOCK, 5000, &result); + hwnd = PhGetProcessMainWindow((HANDLE)processId64, NULL); - if (result == PH_ACTIVATE_REPLY) + if (hwnd) { - SetForegroundWindow(hwnd); - RtlExitUserProcess(STATUS_SUCCESS); + ULONG_PTR result; + + SendMessageTimeout(hwnd, WM_PH_ACTIVATE, PhStartupParameters.SelectPid, 0, SMTO_BLOCK, 5000, &result); + + if (result == PH_ACTIVATE_REPLY) + { + SetForegroundWindow(hwnd); + RtlExitUserProcess(STATUS_SUCCESS); + } } } + + return TRUE; +} + +VOID PhActivatePreviousInstance( + VOID + ) +{ + PhEnumDirectoryObjects(PhGetNamespaceHandle(), PhpPreviousInstancesCallback, NULL); } VOID PhInitializeCommonControls( diff --git a/phlib/include/phutil.h b/phlib/include/phutil.h index 9b6a440e9bbc..34a020c2ba4e 100644 --- a/phlib/include/phutil.h +++ b/phlib/include/phutil.h @@ -1059,6 +1059,41 @@ PhParseCommandLineFuzzy( _Out_opt_ PPH_STRING *FullFileName ); +FORCEINLINE +HANDLE +NTAPI +PhGetNamespaceHandle( + VOID + ) +{ + static PH_INITONCE initOnce = PH_INITONCE_INIT; + static UNICODE_STRING namespacePathUs = RTL_CONSTANT_STRING(L"\\BaseNamedObjects\\ProcessHacker"); + static HANDLE directory = NULL; + + if (PhBeginInitOnce(&initOnce)) + { + OBJECT_ATTRIBUTES objectAttributes; + + InitializeObjectAttributes( + &objectAttributes, + &namespacePathUs, + OBJ_OPENIF, + NULL, + NULL + ); + + NtCreateDirectoryObject( + &directory, + MAXIMUM_ALLOWED, + &objectAttributes + ); + + PhEndInitOnce(&initOnce); + } + + return directory; +} + #ifdef __cplusplus } #endif From 6b14d397d1ea662462d4e7efee1f4180ffa99ac4 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 11 Jun 2017 01:12:02 +1000 Subject: [PATCH 0206/2058] DotNetTools: Fix appdomain enumeration failing on weird machines --- plugins/DotNetTools/counters.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/DotNetTools/counters.c b/plugins/DotNetTools/counters.c index 2092908c9e35..669831c546db 100644 --- a/plugins/DotNetTools/counters.c +++ b/plugins/DotNetTools/counters.c @@ -476,7 +476,7 @@ BOOLEAN OpenDotNetPublicControlBlock_V2( InitializeObjectAttributes( &objectAttributes, §ionNameUs, - 0, + OBJ_CASE_INSENSITIVE, NULL, NULL ); @@ -714,7 +714,7 @@ PPH_LIST QueryDotNetAppDomainsForPid_V2( InitializeObjectAttributes( &objectAttributes, §ionNameUs, - 0, + OBJ_CASE_INSENSITIVE, NULL, NULL ); @@ -832,7 +832,7 @@ PPH_LIST QueryDotNetAppDomainsForPid_V4( InitializeObjectAttributes( &objectAttributes, §ionNameUs, - 0, + OBJ_CASE_INSENSITIVE, NULL, NULL ); From a80b39c10c064a88b76a6d59d0b746150156dbe2 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 11 Jun 2017 01:13:05 +1000 Subject: [PATCH 0207/2058] peview: Use native timer queue --- tools/peview/include/peview.h | 4 +++- tools/peview/pdbprp.c | 29 ++++++++++++++++------------- 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/tools/peview/include/peview.h b/tools/peview/include/peview.h index 10a4cc2c73bc..c2586e7db2b6 100644 --- a/tools/peview/include/peview.h +++ b/tools/peview/include/peview.h @@ -210,7 +210,9 @@ typedef struct _PDB_SYMBOL_CONTEXT HWND TreeNewHandle; HWND ParentWindowHandle; HANDLE SearchThreadHandle; - HANDLE UpdateTimer; + + HANDLE TimerQueueHandle; + HANDLE UpdateTimerHandle; ULONG64 BaseAddress; PPH_STRING FileName; diff --git a/tools/peview/pdbprp.c b/tools/peview/pdbprp.c index 05e833a0d16c..c72a7a9e8722 100644 --- a/tools/peview/pdbprp.c +++ b/tools/peview/pdbprp.c @@ -908,7 +908,7 @@ VOID CALLBACK PvSymbolTreeUpdateCallback( TreeNew_NodesStructured(Context->TreeNewHandle); TreeNew_SetRedraw(Context->TreeNewHandle, TRUE); - ChangeTimerQueueTimer(NULL, Context->UpdateTimer, 1000, INFINITE); + RtlUpdateTimer(Context->TimerQueueHandle, Context->UpdateTimerHandle, 1000, INFINITE); } INT_PTR CALLBACK PvpSymbolsDlgProc( @@ -958,17 +958,17 @@ INT_PTR CALLBACK PvpSymbolsDlgProc( context->SearchThreadHandle = PhCreateThread(0, PeDumpFileSymbols, context); - if (CreateTimerQueueTimer( - &treeNewTimer, - NULL, - PvSymbolTreeUpdateCallback, - context, - 1000, - 1000, - 0 - )) + if (NT_SUCCESS(RtlCreateTimerQueue(&context->TimerQueueHandle))) { - context->UpdateTimer = treeNewTimer; + RtlCreateTimer( + context->TimerQueueHandle, + &context->UpdateTimerHandle, + PvSymbolTreeUpdateCallback, + context, + 0, + 1000, + 0 + ); } EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); @@ -976,8 +976,11 @@ INT_PTR CALLBACK PvpSymbolsDlgProc( break; case WM_DESTROY: { - if (context->UpdateTimer) - DeleteTimerQueueTimer(NULL, context->UpdateTimer, NULL); + if (context->UpdateTimerHandle) + RtlDeleteTimer(context->TimerQueueHandle, context->UpdateTimerHandle, NULL); + + if (context->TimerQueueHandle) + RtlDeleteTimerQueue(context->TimerQueueHandle); NtClose(context->SearchThreadHandle); From aacc84ea8a15883605a37b84e9f1c715e26e0a77 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 11 Jun 2017 01:37:17 +1000 Subject: [PATCH 0208/2058] OnlineChecks: Update detection ratio string for easier readability, Reduce resource usage, Remove unused code --- plugins/OnlineChecks/db.c | 7 ++-- plugins/OnlineChecks/db.h | 4 +- plugins/OnlineChecks/main.c | 3 -- plugins/OnlineChecks/onlnchk.h | 4 +- plugins/OnlineChecks/virustotal.c | 70 +++++++++++++------------------ 5 files changed, 35 insertions(+), 53 deletions(-) diff --git a/plugins/OnlineChecks/db.c b/plugins/OnlineChecks/db.c index 683b5264bc9e..e1082a5bb5ff 100644 --- a/plugins/OnlineChecks/db.c +++ b/plugins/OnlineChecks/db.c @@ -108,8 +108,8 @@ PPROCESS_DB_OBJECT FindProcessDbObject( PPROCESS_DB_OBJECT CreateProcessDbObject( _In_ PPH_STRING FileName, _In_opt_ INT64 Positives, - _In_opt_ PPH_STRING Hash, - _In_opt_ PPH_STRING Result + _In_opt_ INT64 Total, + _In_opt_ PPH_STRING Hash ) { PPROCESS_DB_OBJECT object; @@ -122,10 +122,9 @@ PPROCESS_DB_OBJECT CreateProcessDbObject( PhInitializeStringRefLongHint(&object->FileName, FileName->Buffer); PhReferenceObject(FileName); - PhReferenceObject(Result); object->Positives = Positives; object->Hash = FileName; - object->Result = Result; + object->Result = PhFormatString(L"%lu | %lu", Positives, Total); realObject = PhAddEntryHashtableEx(ProcessObjectDb, &object, &added); diff --git a/plugins/OnlineChecks/db.h b/plugins/OnlineChecks/db.h index 4a6568c3db54..8753c31115f4 100644 --- a/plugins/OnlineChecks/db.h +++ b/plugins/OnlineChecks/db.h @@ -57,8 +57,8 @@ PPROCESS_DB_OBJECT FindProcessDbObject( PPROCESS_DB_OBJECT CreateProcessDbObject( _In_ PPH_STRING FileName, _In_opt_ INT64 Positives, - _In_opt_ PPH_STRING Hash, - _In_opt_ PPH_STRING Result + _In_opt_ INT64 Total, + _In_opt_ PPH_STRING Hash ); #endif diff --git a/plugins/OnlineChecks/main.c b/plugins/OnlineChecks/main.c index 8bbfe03f7b1a..652594742bfa 100644 --- a/plugins/OnlineChecks/main.c +++ b/plugins/OnlineChecks/main.c @@ -608,7 +608,6 @@ VOID NTAPI ProcessItemCreateCallback( memset(extension, 0, sizeof(PROCESS_EXTENSION)); extension->ProcessItem = processItem; - extension->VirusTotalResult = PhReferenceEmptyString(); PhAcquireQueuedLockExclusive(&ProcessesListLock); InsertTailList(&ProcessListHead, &extension->ListEntry); @@ -643,7 +642,6 @@ VOID NTAPI ModuleItemCreateCallback( memset(extension, 0, sizeof(PROCESS_EXTENSION)); extension->ModuleItem = moduleItem; - extension->VirusTotalResult = PhReferenceEmptyString(); PhAcquireQueuedLockExclusive(&ProcessesListLock); InsertTailList(&ProcessListHead, &extension->ListEntry); @@ -678,7 +676,6 @@ VOID NTAPI ServiceItemCreateCallback( memset(extension, 0, sizeof(PROCESS_EXTENSION)); extension->ServiceItem = serviceItem; - extension->VirusTotalResult = PhReferenceEmptyString(); PhAcquireQueuedLockExclusive(&ProcessesListLock); InsertTailList(&ProcessListHead, &extension->ListEntry); diff --git a/plugins/OnlineChecks/onlnchk.h b/plugins/OnlineChecks/onlnchk.h index 6e57a920a0f6..79b1ff043651 100644 --- a/plugins/OnlineChecks/onlnchk.h +++ b/plugins/OnlineChecks/onlnchk.h @@ -103,12 +103,12 @@ typedef struct _VIRUSTOTAL_FILE_HASH_ENTRY PPROCESS_EXTENSION Extension; INT64 Positives; + INT64 Total; PPH_STRING FileName; PPH_STRING FileHash; PPH_BYTES FileNameAnsi; PPH_BYTES FileHashAnsi; PPH_BYTES CreationTime; - PPH_STRING FileResult; } VIRUSTOTAL_FILE_HASH_ENTRY, *PVIRUSTOTAL_FILE_HASH_ENTRY; typedef struct _UPLOAD_CONTEXT @@ -227,9 +227,7 @@ typedef struct _VIRUSTOTAL_API_RESULT BOOLEAN Found; INT64 Positives; INT64 Total; - PPH_STRING Permalink; PPH_STRING FileHash; - PPH_STRING DetectionRatio; } VIRUSTOTAL_API_RESULT, *PVIRUSTOTAL_API_RESULT; extern PPH_LIST VirusTotalList; diff --git a/plugins/OnlineChecks/virustotal.c b/plugins/OnlineChecks/virustotal.c index 642ce0ddd9f3..4e7ed4ee645a 100644 --- a/plugins/OnlineChecks/virustotal.c +++ b/plugins/OnlineChecks/virustotal.c @@ -118,7 +118,7 @@ VOID VirusTotalRemoveCacheResult( PhClearReference(&extension->FileNameAnsi); PhClearReference(&extension->FileHashAnsi); PhClearReference(&extension->CreationTime); - PhClearReference(&extension->FileResult); + PhFree(extension); } @@ -220,9 +220,7 @@ PPH_LIST VirusTotalJsonToResultList( { PVIRUSTOTAL_API_RESULT result; PVOID jsonArrayObject; - PSTR fileLink; PSTR fileHash; - PSTR fileRatio; if (!(jsonArrayObject = JsonGetObjectArrayIndex(JsonObject, i))) continue; @@ -230,16 +228,11 @@ PPH_LIST VirusTotalJsonToResultList( result = PhAllocate(sizeof(VIRUSTOTAL_API_RESULT)); memset(result, 0, sizeof(VIRUSTOTAL_API_RESULT)); - fileLink = GetJsonValueAsString(jsonArrayObject, "permalink"); fileHash = GetJsonValueAsString(jsonArrayObject, "hash"); - fileRatio = GetJsonValueAsString(jsonArrayObject, "detection_ratio"); - result->Found = GetJsonValueAsBool(jsonArrayObject, "found") == TRUE; result->Positives = GetJsonValueAsUlong(jsonArrayObject, "positives"); result->Total = GetJsonValueAsUlong(jsonArrayObject, "total"); - result->Permalink = fileLink ? PhZeroExtendToUtf16(fileLink) : PhReferenceEmptyString(); - result->FileHash = fileHash ? PhZeroExtendToUtf16(fileHash) : PhReferenceEmptyString(); - result->DetectionRatio = fileRatio ? PhZeroExtendToUtf16(fileRatio) : PhReferenceEmptyString(); + result->FileHash = fileHash ? PhZeroExtendToUtf16(fileHash) : NULL; PhAddItemList(results, result); } @@ -581,7 +574,7 @@ PVIRUSTOTAL_FILE_REPORT_RESULT VirusTotalSendHttpFileReportRequest( PVOID jsonRootObject; - PVOID jsonScanObject; + //PVOID jsonScanObject; PVIRUSTOTAL_FILE_REPORT_RESULT result; if (!(jsonRootObject = CreateJsonParser(subRequestBuffer))) @@ -604,28 +597,28 @@ PVIRUSTOTAL_FILE_REPORT_RESULT VirusTotalSendHttpFileReportRequest( result->Permalink = PhZeroExtendToUtf16(GetJsonValueAsString(jsonRootObject, "permalink")); result->StatusMessage = PhZeroExtendToUtf16(GetJsonValueAsString(jsonRootObject, "verbose_msg")); - if (jsonScanObject = JsonGetObject(jsonRootObject, "scans")) - { - PPH_LIST jsonArrayList; - - if (jsonArrayList = JsonGetObjectArrayList(jsonScanObject)) - { - result->ScanResults = PhCreateList(jsonArrayList->Count); - - for (ULONG i = 0; i < jsonArrayList->Count; i++) - { - PJSON_ARRAY_LIST_OBJECT object = jsonArrayList->Items[i]; - //BOOLEAN detected = GetJsonValueAsBool(object->Entry, "detected") == TRUE; - //PSTR version = GetJsonValueAsString(object->Entry, "version"); - //PSTR result = GetJsonValueAsString(object->Entry, "result"); - //PSTR update = GetJsonValueAsString(object->Entry, "update"); - - PhFree(object); - } - - PhDereferenceObject(jsonArrayList); - } - } + //if (jsonScanObject = JsonGetObject(jsonRootObject, "scans")) + //{ + // PPH_LIST jsonArrayList; + // + // if (jsonArrayList = JsonGetObjectArrayList(jsonScanObject)) + // { + // result->ScanResults = PhCreateList(jsonArrayList->Count); + // + // for (ULONG i = 0; i < jsonArrayList->Count; i++) + // { + // PJSON_ARRAY_LIST_OBJECT object = jsonArrayList->Items[i]; + // //BOOLEAN detected = GetJsonValueAsBool(object->Entry, "detected") == TRUE; + // //PSTR version = GetJsonValueAsString(object->Entry, "version"); + // //PSTR result = GetJsonValueAsString(object->Entry, "result"); + // //PSTR update = GetJsonValueAsString(object->Entry, "update"); + // + // PhFree(object); + // } + // + // PhDereferenceObject(jsonArrayList); + // } + //} return result; } @@ -721,24 +714,19 @@ NTSTATUS NTAPI VirusTotalProcessApiThread( entry->Processed = TRUE; entry->Found = result->Found; entry->Positives = result->Positives; - - PhSwapReference(&entry->FileResult, result->DetectionRatio); - + entry->Total = result->Total; + if (!FindProcessDbObject(&entry->FileName->sr)) { CreateProcessDbObject( entry->FileName, entry->Positives, - result->FileHash, - entry->FileResult + entry->Total, + result->FileHash ); } } } - else - { - - } } } From d3ee123245de4b19644402a9f78b93319f66f949 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 11 Jun 2017 02:35:35 +1000 Subject: [PATCH 0209/2058] Fix single instance regression when application minimized --- ProcessHacker/appsup.c | 14 +++++++++++++- ProcessHacker/include/appsup.h | 6 ++++++ ProcessHacker/main.c | 2 +- 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/ProcessHacker/appsup.c b/ProcessHacker/appsup.c index 4e6a5d25f525..8d1c8eeaa023 100644 --- a/ProcessHacker/appsup.c +++ b/ProcessHacker/appsup.c @@ -3,6 +3,7 @@ * application support functions * * Copyright (C) 2010-2016 wj32 + * Copyright (C) 2017 dmex * * This file is part of Process Hacker. * @@ -723,6 +724,7 @@ typedef struct _GET_PROCESS_MAIN_WINDOW_CONTEXT HWND ImmersiveWindow; HANDLE ProcessId; BOOLEAN IsImmersive; + BOOLEAN SkipInvisible; } GET_PROCESS_MAIN_WINDOW_CONTEXT, *PGET_PROCESS_MAIN_WINDOW_CONTEXT; BOOL CALLBACK PhpGetProcessMainWindowEnumWindowsProc( @@ -735,7 +737,7 @@ BOOL CALLBACK PhpGetProcessMainWindowEnumWindowsProc( HWND parentWindow; WINDOWINFO windowInfo; - if (!IsWindowVisible(hwnd)) + if (context->SkipInvisible && !IsWindowVisible(hwnd)) return TRUE; GetWindowThreadProcessId(hwnd, &processId); @@ -769,12 +771,22 @@ HWND PhGetProcessMainWindow( _In_ HANDLE ProcessId, _In_opt_ HANDLE ProcessHandle ) +{ + return PhGetProcessMainWindowEx(ProcessId, ProcessHandle, TRUE); +} + +HWND PhGetProcessMainWindowEx( + _In_ HANDLE ProcessId, + _In_opt_ HANDLE ProcessHandle, + _In_ BOOLEAN SkipInvisible + ) { GET_PROCESS_MAIN_WINDOW_CONTEXT context; HANDLE processHandle = NULL; memset(&context, 0, sizeof(GET_PROCESS_MAIN_WINDOW_CONTEXT)); context.ProcessId = ProcessId; + context.SkipInvisible = SkipInvisible; if (ProcessHandle) processHandle = ProcessHandle; diff --git a/ProcessHacker/include/appsup.h b/ProcessHacker/include/appsup.h index 275273f6d4e8..0973ce98f32a 100644 --- a/ProcessHacker/include/appsup.h +++ b/ProcessHacker/include/appsup.h @@ -109,6 +109,12 @@ HWND PhGetProcessMainWindow( _In_opt_ HANDLE ProcessHandle ); +HWND PhGetProcessMainWindowEx( + _In_ HANDLE ProcessId, + _In_opt_ HANDLE ProcessHandle, + _In_ BOOLEAN SkipInvisible + ); + PPH_STRING PhGetServiceRelevantFileName( _In_ PPH_STRINGREF ServiceName, _In_ SC_HANDLE ServiceHandle diff --git a/ProcessHacker/main.c b/ProcessHacker/main.c index 6b9a95c163f5..d13513da6754 100644 --- a/ProcessHacker/main.c +++ b/ProcessHacker/main.c @@ -445,7 +445,7 @@ static BOOLEAN NTAPI PhpPreviousInstancesCallback( { HWND hwnd; - hwnd = PhGetProcessMainWindow((HANDLE)processId64, NULL); + hwnd = PhGetProcessMainWindowEx((HANDLE)processId64, NULL, FALSE); if (hwnd) { From 82e171a493807121864f1496547fa87fa015ee88 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 11 Jun 2017 04:36:35 +1000 Subject: [PATCH 0210/2058] Fix bug in previous commit --- ProcessHacker/appsup.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ProcessHacker/appsup.c b/ProcessHacker/appsup.c index 8d1c8eeaa023..e926582c6946 100644 --- a/ProcessHacker/appsup.c +++ b/ProcessHacker/appsup.c @@ -742,9 +742,9 @@ BOOL CALLBACK PhpGetProcessMainWindowEnumWindowsProc( GetWindowThreadProcessId(hwnd, &processId); - if (UlongToHandle(processId) == context->ProcessId && + if (UlongToHandle(processId) == context->ProcessId && (context->SkipInvisible ? !((parentWindow = GetParent(hwnd)) && IsWindowVisible(parentWindow)) && // skip windows with a visible parent - PhGetWindowTextEx(hwnd, PH_GET_WINDOW_TEXT_INTERNAL | PH_GET_WINDOW_TEXT_LENGTH_ONLY, NULL) != 0) // skip windows with no title + PhGetWindowTextEx(hwnd, PH_GET_WINDOW_TEXT_INTERNAL | PH_GET_WINDOW_TEXT_LENGTH_ONLY, NULL) != 0 : TRUE)) // skip windows with no title { if (!context->ImmersiveWindow && context->IsImmersive && GetProp(hwnd, L"Windows.ImmersiveShell.IdentifyAsMainCoreWindow")) From c765bded0cc8b71d16ce849ecd6225153611b226 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 11 Jun 2017 06:05:43 +1000 Subject: [PATCH 0211/2058] Remove legacy XP code --- ProcessHacker/ProcessHacker.rc | 58 -------------- ProcessHacker/actions.c | 4 +- ProcessHacker/anawait.c | 2 +- ProcessHacker/findobj.c | 2 +- ProcessHacker/hidnproc.c | 2 +- ProcessHacker/hndlprv.c | 2 +- ProcessHacker/mainwnd.c | 18 ++--- ProcessHacker/memprv.c | 40 ++-------- ProcessHacker/modlist.c | 11 +-- ProcessHacker/modprv.c | 15 ++-- ProcessHacker/mwpgproc.c | 30 +++---- ProcessHacker/netlist.c | 7 +- ProcessHacker/notifico.c | 9 +-- ProcessHacker/ntobjprp.c | 11 +-- ProcessHacker/procprv.c | 58 ++++++-------- ProcessHacker/proctree.c | 47 ++++------- ProcessHacker/prpggen.c | 2 +- ProcessHacker/prpgstat.c | 37 +++------ ProcessHacker/prpgthrd.c | 50 +++--------- ProcessHacker/resource.h | 1 - ProcessHacker/runas.c | 12 +-- ProcessHacker/srvprp.c | 50 +++++------- ProcessHacker/srvprv.c | 6 +- ProcessHacker/sysinfo.c | 2 +- ProcessHacker/sysscmem.c | 103 ++++++++++++------------ ProcessHacker/thrdprv.c | 11 ++- ProcessHacker/tokprp.c | 70 +++++++---------- phlib/global.c | 21 ++--- phlib/guisup.c | 15 +--- phlib/include/phconfig.h | 5 -- phlib/native.c | 140 ++++++++++----------------------- phlib/secdata.c | 6 +- phlib/treenew.c | 4 +- phlib/util.c | 87 ++++++-------------- phlib/verify.c | 6 +- phlib/workqueue.c | 35 ++++----- 36 files changed, 307 insertions(+), 672 deletions(-) diff --git a/ProcessHacker/ProcessHacker.rc b/ProcessHacker/ProcessHacker.rc index b372627fd3a0..3566b045ab4e 100644 --- a/ProcessHacker/ProcessHacker.rc +++ b/ProcessHacker/ProcessHacker.rc @@ -1827,60 +1827,6 @@ FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN END -IDD_SYSINFO_MEMPANELXP DIALOGEX 0, 0, 230, 171 -STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU -EXSTYLE WS_EX_CONTROLPARENT -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - GROUPBOX "Commit charge",-1,0,0,108,44 - LTEXT "Current",-1,7,11,26,8 - LTEXT "Peak",-1,7,21,16,8 - LTEXT "Limit",-1,7,31,15,8 - RTEXT "Static",IDC_ZCOMMITCURRENT_V,45,11,56,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZCOMMITPEAK_V,41,21,60,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZCOMMITLIMIT_V,40,31,61,8,SS_ENDELLIPSIS - GROUPBOX "Physical memory",-1,112,0,118,64 - LTEXT "Current",-1,120,11,26,8 - LTEXT "Cache WS",-1,120,31,34,8 - RTEXT "Static",IDC_ZPHYSICALCURRENT_V,165,11,57,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZPHYSICALTOTAL_V,167,21,55,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZPHYSICALCACHEWS_V,159,31,63,8,SS_ENDELLIPSIS - LTEXT "Total",-1,120,21,17,8 - LTEXT "Kernel WS",-1,120,41,34,8 - RTEXT "Static",IDC_ZPHYSICALKERNELWS_V,167,41,55,8,SS_ENDELLIPSIS - LTEXT "Driver WS",-1,120,51,33,8 - RTEXT "Static",IDC_ZPHYSICALDRIVERWS_V,163,51,59,8,SS_ENDELLIPSIS - GROUPBOX "Paged pool",-1,0,47,108,64 - LTEXT "Working set",-1,7,58,40,8 - LTEXT "Limit",-1,7,78,15,8 - RTEXT "Static",IDC_ZPAGEDWORKINGSET_V,54,58,47,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZPAGEDVIRTUALSIZE_V,52,68,49,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZPAGEDLIMIT_V,48,78,53,8,SS_ENDELLIPSIS - LTEXT "Virtual size",-1,7,68,36,8 - LTEXT "Allocs delta",-1,7,88,38,8 - RTEXT "Static",IDC_ZPAGEDALLOCSDELTA_V,53,88,48,8,SS_ENDELLIPSIS - LTEXT "Frees delta",-1,7,98,38,8 - RTEXT "Static",IDC_ZPAGEDFREESDELTA_V,51,98,50,8,SS_ENDELLIPSIS - GROUPBOX "Non-paged pool",-1,0,114,108,55 - LTEXT "Usage",-1,7,125,21,8 - LTEXT "Allocs delta",-1,7,145,38,8 - RTEXT "Static",IDC_ZNONPAGEDUSAGE_V,54,125,47,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZNONPAGEDLIMIT_V,52,135,49,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZNONPAGEDALLOCSDELTA_V,56,145,45,8,SS_ENDELLIPSIS - LTEXT "Limit",-1,7,135,15,8 - LTEXT "Frees delta",-1,7,155,38,8 - RTEXT "Static",IDC_ZNONPAGEDFREESDELTA_V,56,155,45,8,SS_ENDELLIPSIS - GROUPBOX "Paging",-1,112,67,118,55 - LTEXT "Page faults delta",-1,120,78,57,8 - LTEXT "Pagefile writes delta",-1,120,98,68,8 - RTEXT "Static",IDC_ZPAGINGPAGEFAULTSDELTA_V,183,78,39,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZPAGINGPAGEREADSDELTA_V,179,88,43,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZPAGINGPAGEFILEWRITESDELTA_V,189,98,33,8,SS_ENDELLIPSIS - LTEXT "Page reads delta",-1,120,88,58,8 - LTEXT "Mapped writes delta",-1,120,108,68,8 - RTEXT "Static",IDC_ZPAGINGMAPPEDWRITESDELTA_V,191,108,31,8,SS_ENDELLIPSIS -END - IDD_MINIINFO DIALOGEX 0, 0, 217, 150 STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD FONT 8, "MS Shell Dlg", 400, 0, 0x1 @@ -2428,10 +2374,6 @@ BEGIN BOTTOMMARGIN, 175 END - IDD_SYSINFO_MEMPANELXP, DIALOG - BEGIN - END - IDD_MINIINFO, DIALOG BEGIN LEFTMARGIN, 4 diff --git a/ProcessHacker/actions.c b/ProcessHacker/actions.c index c9113390bc08..41b523b581cc 100644 --- a/ProcessHacker/actions.c +++ b/ProcessHacker/actions.c @@ -164,7 +164,7 @@ BOOLEAN PhpShowErrorAndElevateAction( )) return FALSE; - if (!WINDOWS_HAS_UAC || PhGetOwnTokenAttributes().Elevated) + if (PhGetOwnTokenAttributes().Elevated) return FALSE; elevationLevel = PhGetIntegerSetting(L"ElevationLevel"); @@ -257,7 +257,7 @@ BOOLEAN PhpShowErrorAndConnectToPhSvc( )) return FALSE; - if (!WINDOWS_HAS_UAC || PhGetOwnTokenAttributes().Elevated) + if (PhGetOwnTokenAttributes().Elevated) return FALSE; elevationLevel = PhGetIntegerSetting(L"ElevationLevel"); diff --git a/ProcessHacker/anawait.c b/ProcessHacker/anawait.c index bc7c2af90f70..cbf30b17eb8a 100644 --- a/ProcessHacker/anawait.c +++ b/ProcessHacker/anawait.c @@ -439,7 +439,7 @@ static BOOLEAN NTAPI PhpWalkThreadStackAnalyzeCallback( PhAppendStringBuilder2( &context->StringBuilder, - WindowsVersion >= WINDOWS_VISTA ? L"Thread is waiting for an ALPC port:\r\n" : L"Thread is waiting for a LPC port:\r\n" + L"Thread is waiting for an ALPC port:\r\n" ); PhAppendStringBuilder( &context->StringBuilder, diff --git a/ProcessHacker/findobj.c b/ProcessHacker/findobj.c index 2c222fa4f177..78eb2690f0c0 100644 --- a/ProcessHacker/findobj.c +++ b/ProcessHacker/findobj.c @@ -901,7 +901,7 @@ static NTSTATUS PhpFindObjectsThreadStart( PH_WORK_QUEUE workQueue; processHandleHashtable = PhCreateSimpleHashtable(8); - if (!KphIsConnected() && WindowsVersion >= WINDOWS_VISTA) + if (!KphIsConnected()) { useWorkQueue = TRUE; PhInitializeWorkQueue(&workQueue, 1, 20, 1000); diff --git a/ProcessHacker/hidnproc.c b/ProcessHacker/hidnproc.c index c3b16c7158b2..f30b4f664328 100644 --- a/ProcessHacker/hidnproc.c +++ b/ProcessHacker/hidnproc.c @@ -808,7 +808,7 @@ NTSTATUS PhpEnumHiddenProcessesBruteForce( } // Use an alternative method if we don't have sufficient access. - if (status2 == STATUS_ACCESS_DENIED && WindowsVersion >= WINDOWS_VISTA) + if (status2 == STATUS_ACCESS_DENIED) { if (NT_SUCCESS(status2 = PhGetProcessImageFileNameByProcessId(UlongToHandle(pid), &fileName))) { diff --git a/ProcessHacker/hndlprv.c b/ProcessHacker/hndlprv.c index 5a21fe2d26f7..6a85795f1c24 100644 --- a/ProcessHacker/hndlprv.c +++ b/ProcessHacker/hndlprv.c @@ -487,7 +487,7 @@ VOID PhHandleProviderUpdate( ))) goto UpdateExit; - if (!KphIsConnected() && WindowsVersion >= WINDOWS_VISTA) + if (!KphIsConnected()) { useWorkQueue = TRUE; PhInitializeWorkQueue(&workQueue, 1, 20, 1000); diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index 1941ca980cab..bd7355eb1b69 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -142,7 +142,7 @@ BOOLEAN PhMainWndInitialization( if (KphIsConnected()) PhAppendCharStringBuilder(&stringBuilder, '+'); } - if (WINDOWS_HAS_UAC && PhGetOwnTokenAttributes().ElevationType == TokenElevationTypeFull) + if (PhGetOwnTokenAttributes().ElevationType == TokenElevationTypeFull) PhAppendStringBuilder2(&stringBuilder, L" (Administrator)"); } @@ -175,8 +175,7 @@ BOOLEAN PhMainWndInitialization( windowRectangle.Width, windowRectangle.Height, FALSE); // Allow WM_PH_ACTIVATE to pass through UIPI. - if (WINDOWS_HAS_UAC) - ChangeWindowMessageFilter_I(WM_PH_ACTIVATE, MSGFLT_ADD); + ChangeWindowMessageFilter_I(WM_PH_ACTIVATE, MSGFLT_ADD); PhMwpOnSettingChange(); @@ -3103,15 +3102,12 @@ VOID PhAddMiniProcessMenuItems( // I/O priority - if (WindowsVersion >= WINDOWS_VISTA) - { - ioPriorityMenu = PhCreateEMenuItem(0, 0, L"I/O priority", NULL, ProcessId); + ioPriorityMenu = PhCreateEMenuItem(0, 0, L"I/O priority", NULL, ProcessId); - PhInsertEMenuItem(ioPriorityMenu, PhCreateEMenuItem(0, ID_IOPRIORITY_HIGH, L"High", NULL, ProcessId), -1); - PhInsertEMenuItem(ioPriorityMenu, PhCreateEMenuItem(0, ID_IOPRIORITY_NORMAL, L"Normal", NULL, ProcessId), -1); - PhInsertEMenuItem(ioPriorityMenu, PhCreateEMenuItem(0, ID_IOPRIORITY_LOW, L"Low", NULL, ProcessId), -1); - PhInsertEMenuItem(ioPriorityMenu, PhCreateEMenuItem(0, ID_IOPRIORITY_VERYLOW, L"Very low", NULL, ProcessId), -1); - } + PhInsertEMenuItem(ioPriorityMenu, PhCreateEMenuItem(0, ID_IOPRIORITY_HIGH, L"High", NULL, ProcessId), -1); + PhInsertEMenuItem(ioPriorityMenu, PhCreateEMenuItem(0, ID_IOPRIORITY_NORMAL, L"Normal", NULL, ProcessId), -1); + PhInsertEMenuItem(ioPriorityMenu, PhCreateEMenuItem(0, ID_IOPRIORITY_LOW, L"Low", NULL, ProcessId), -1); + PhInsertEMenuItem(ioPriorityMenu, PhCreateEMenuItem(0, ID_IOPRIORITY_VERYLOW, L"Very low", NULL, ProcessId), -1); // Menu diff --git a/ProcessHacker/memprv.c b/ProcessHacker/memprv.c index 998ed6eeca73..14b155de1f6d 100644 --- a/ProcessHacker/memprv.c +++ b/ProcessHacker/memprv.c @@ -347,20 +347,6 @@ NTSTATUS PhpUpdateMemoryRegionTypes( { PSYSTEM_EXTENDED_THREAD_INFORMATION thread = (PSYSTEM_EXTENDED_THREAD_INFORMATION)process->Threads + i; - if (WindowsVersion < WINDOWS_VISTA) - { - HANDLE threadHandle; - THREAD_BASIC_INFORMATION basicInfo; - - if (NT_SUCCESS(PhOpenThread(&threadHandle, ThreadQueryAccess, thread->ThreadInfo.ClientId.UniqueThread))) - { - if (NT_SUCCESS(PhGetThreadBasicInformation(threadHandle, &basicInfo))) - thread->TebBase = basicInfo.TebBaseAddress; - - NtClose(threadHandle); - } - } - if (thread->TebBase) { NT_TIB ntTib; @@ -437,27 +423,13 @@ NTSTATUS PhpUpdateMemoryRegionTypes( PVOID candidateHeap = NULL; ULONG candidateHeap32 = 0; PPH_MEMORY_ITEM heapMemoryItem; + PHEAP_SEGMENT heapSegment = (PHEAP_SEGMENT)buffer; + PHEAP_SEGMENT32 heapSegment32 = (PHEAP_SEGMENT32)buffer; - if (WindowsVersion >= WINDOWS_VISTA) - { - PHEAP_SEGMENT heapSegment = (PHEAP_SEGMENT)buffer; - PHEAP_SEGMENT32 heapSegment32 = (PHEAP_SEGMENT32)buffer; - - if (heapSegment->SegmentSignature == HEAP_SEGMENT_SIGNATURE) - candidateHeap = heapSegment->Heap; - if (heapSegment32->SegmentSignature == HEAP_SEGMENT_SIGNATURE) - candidateHeap32 = heapSegment32->Heap; - } - else - { - PHEAP_SEGMENT_OLD heapSegment = (PHEAP_SEGMENT_OLD)buffer; - PHEAP_SEGMENT_OLD32 heapSegment32 = (PHEAP_SEGMENT_OLD32)buffer; - - if (heapSegment->Signature == HEAP_SEGMENT_SIGNATURE) - candidateHeap = heapSegment->Heap; - if (heapSegment32->Signature == HEAP_SEGMENT_SIGNATURE) - candidateHeap32 = heapSegment32->Heap; - } + if (heapSegment->SegmentSignature == HEAP_SEGMENT_SIGNATURE) + candidateHeap = heapSegment->Heap; + if (heapSegment32->SegmentSignature == HEAP_SEGMENT_SIGNATURE) + candidateHeap32 = heapSegment32->Heap; if (candidateHeap) { diff --git a/ProcessHacker/modlist.c b/ProcessHacker/modlist.c index 15df0c622cac..af8adadb31c9 100644 --- a/ProcessHacker/modlist.c +++ b/ProcessHacker/modlist.c @@ -747,15 +747,8 @@ BOOLEAN NTAPI PhpModuleTreeNewCallback( getCellText->Text = PhGetStringRef(moduleItem->VerifySignerName); break; case PHMOTLC_ASLR: - if (WindowsVersion >= WINDOWS_VISTA) - { - if (moduleItem->ImageDllCharacteristics & IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE) - PhInitializeStringRef(&getCellText->Text, L"ASLR"); - } - else - { - PhInitializeStringRef(&getCellText->Text, L"N/A"); - } + if (moduleItem->ImageDllCharacteristics & IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE) + PhInitializeStringRef(&getCellText->Text, L"ASLR"); break; case PHMOTLC_TIMESTAMP: { diff --git a/ProcessHacker/modprv.c b/ProcessHacker/modprv.c index 30c04ac6af7b..de4854d285c3 100644 --- a/ProcessHacker/modprv.c +++ b/ProcessHacker/modprv.c @@ -111,15 +111,12 @@ PPH_MODULE_PROVIDER PhCreateModuleProvider( ProcessId ))) { - if (WINDOWS_HAS_LIMITED_ACCESS) - { - // Try to get a handle with query limited information + vm read access. - status = PhOpenProcess( - &moduleProvider->ProcessHandle, - PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_VM_READ, - ProcessId - ); - } + // Try to get a handle with query limited information + vm read access. + status = PhOpenProcess( + &moduleProvider->ProcessHandle, + PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_VM_READ, + ProcessId + ); moduleProvider->RunStatus = status; } diff --git a/ProcessHacker/mwpgproc.c b/ProcessHacker/mwpgproc.c index 11307c937294..cce1265a13b7 100644 --- a/ProcessHacker/mwpgproc.c +++ b/ProcessHacker/mwpgproc.c @@ -363,10 +363,16 @@ VOID PhMwpSetProcessMenuPriorityChecks( { if (SetPriority) { - NtQueryInformationProcess(processHandle, ProcessPriorityClass, &priorityClass, sizeof(PROCESS_PRIORITY_CLASS), NULL); + NtQueryInformationProcess( + processHandle, + ProcessPriorityClass, + &priorityClass, + sizeof(PROCESS_PRIORITY_CLASS), + NULL + ); } - if (SetIoPriority && WindowsVersion >= WINDOWS_VISTA) + if (SetIoPriority) { if (!NT_SUCCESS(PhGetProcessIoPriority( processHandle, @@ -377,7 +383,7 @@ VOID PhMwpSetProcessMenuPriorityChecks( } } - if (SetPagePriority && WindowsVersion >= WINDOWS_VISTA) + if (SetPagePriority) { if (!NT_SUCCESS(PhGetProcessPagePriority( processHandle, @@ -545,17 +551,6 @@ VOID PhMwpInitializeProcessMenu( } } - // Remove irrelevant menu items. - if (WindowsVersion < WINDOWS_VISTA) - { - // Remove I/O priority. - if (item = PhFindEMenuItem(Menu, PH_EMENU_FIND_DESCEND, L"I/O Priority", 0)) - PhDestroyEMenuItem(item); - // Remove page priority. - if (item = PhFindEMenuItem(Menu, PH_EMENU_FIND_DESCEND, L"Page Priority", 0)) - PhDestroyEMenuItem(item); - } - // Suspend/Resume if (NumberOfProcesses == 1) { @@ -643,13 +638,6 @@ VOID PhMwpInitializeProcessMenu( item->Flags |= PH_EMENU_DISABLED; } } - - // Remove irrelevant menu items (continued) - if (!WINDOWS_HAS_UAC) - { - if (item = PhFindEMenuItem(Menu, 0, NULL, ID_PROCESS_VIRTUALIZATION)) - PhDestroyEMenuItem(item); - } } VOID PhShowProcessContextMenu( diff --git a/ProcessHacker/netlist.c b/ProcessHacker/netlist.c index bfc42aca3fb6..6c416a97f978 100644 --- a/ProcessHacker/netlist.c +++ b/ProcessHacker/netlist.c @@ -132,7 +132,7 @@ VOID PhInitializeNetworkTreeList( PhAddTreeNewColumn(hwnd, PHNETLC_REMOTEPORT, TRUE, L"Remote port", 50, PH_ALIGN_RIGHT, 4, DT_RIGHT); PhAddTreeNewColumn(hwnd, PHNETLC_PROTOCOL, TRUE, L"Protocol", 45, PH_ALIGN_LEFT, 5, 0); PhAddTreeNewColumn(hwnd, PHNETLC_STATE, TRUE, L"State", 70, PH_ALIGN_LEFT, 6, 0); - PhAddTreeNewColumn(hwnd, PHNETLC_OWNER, WINDOWS_HAS_SERVICE_TAGS, L"Owner", 80, PH_ALIGN_LEFT, 7, 0); + PhAddTreeNewColumn(hwnd, PHNETLC_OWNER, TRUE, L"Owner", 80, PH_ALIGN_LEFT, 7, 0); PhAddTreeNewColumnEx(hwnd, PHNETLC_TIMESTAMP, FALSE, L"Time stamp", 100, PH_ALIGN_LEFT, -1, 0, TRUE); PhAddTreeNewColumn(hwnd, PHNETLC_LOCALHOSTNAME, FALSE, L"Local hostname", 120, PH_ALIGN_LEFT, -1, 0); PhAddTreeNewColumn(hwnd, PHNETLC_REMOTEHOSTNAME, FALSE, L"Remote hostname", 120, PH_ALIGN_LEFT, -1, 0); @@ -538,10 +538,7 @@ BOOLEAN NTAPI PhpNetworkTreeNewCallback( PhInitializeEmptyStringRef(&getCellText->Text); break; case PHNETLC_OWNER: - if (WINDOWS_HAS_SERVICE_TAGS) - getCellText->Text = PhGetStringRef(networkItem->OwnerName); - else - PhInitializeStringRef(&getCellText->Text, L"N/A"); // make sure the user knows this column doesn't work on XP + getCellText->Text = PhGetStringRef(networkItem->OwnerName); break; case PHNETLC_TIMESTAMP: { diff --git a/ProcessHacker/notifico.c b/ProcessHacker/notifico.c index 0dfe8e91674c..726d858b7797 100644 --- a/ProcessHacker/notifico.c +++ b/ProcessHacker/notifico.c @@ -103,7 +103,7 @@ VOID PhNfLoadStage2( { ULONG i; - PhNfMiniInfoEnabled = WindowsVersion >= WINDOWS_VISTA && !!PhGetIntegerSetting(L"MiniInfoWindowEnabled"); + PhNfMiniInfoEnabled = !!PhGetIntegerSetting(L"MiniInfoWindowEnabled"); for (i = PH_ICON_MINIMUM; i != PhNfMaximumIconId; i <<= 1) { @@ -558,11 +558,8 @@ BOOLEAN PhNfpAddNotifyIcon( Shell_NotifyIcon(NIM_ADD, ¬ifyIcon); - if (WindowsVersion >= WINDOWS_VISTA) - { - notifyIcon.uVersion = NOTIFYICON_VERSION_4; - Shell_NotifyIcon(NIM_SETVERSION, ¬ifyIcon); - } + notifyIcon.uVersion = NOTIFYICON_VERSION_4; + Shell_NotifyIcon(NIM_SETVERSION, ¬ifyIcon); return TRUE; } diff --git a/ProcessHacker/ntobjprp.c b/ProcessHacker/ntobjprp.c index a0a9355a3603..5235537c7e18 100644 --- a/ProcessHacker/ntobjprp.c +++ b/ProcessHacker/ntobjprp.c @@ -388,10 +388,7 @@ static VOID PhpRefreshMutantPageInfo( SetDlgItemText(hwndDlg, IDC_ABANDONED, L"Unknown"); } - if ( - WindowsVersion >= WINDOWS_VISTA && - NT_SUCCESS(PhGetMutantOwnerInformation(mutantHandle, &ownerInfo)) - ) + if (NT_SUCCESS(PhGetMutantOwnerInformation(mutantHandle, &ownerInfo))) { PPH_STRING name; @@ -433,12 +430,6 @@ INT_PTR CALLBACK PhpMutantPageProc( { case WM_INITDIALOG: { - if (WindowsVersion < WINDOWS_VISTA) - { - EnableWindow(GetDlgItem(hwndDlg, IDC_OWNERLABEL), FALSE); - EnableWindow(GetDlgItem(hwndDlg, IDC_OWNER), FALSE); - } - PhpRefreshMutantPageInfo(hwndDlg, pageContext); } break; diff --git a/ProcessHacker/procprv.c b/ProcessHacker/procprv.c index 510b16268626..9f21779c5f5b 100644 --- a/ProcessHacker/procprv.c +++ b/ProcessHacker/procprv.c @@ -1072,32 +1072,29 @@ VOID PhpProcessQueryStage1( // Token information if (processHandleLimited) { - if (WINDOWS_HAS_UAC) - { - HANDLE tokenHandle; + HANDLE tokenHandle; - status = PhOpenProcessToken(processHandleLimited, TOKEN_QUERY, &tokenHandle); + status = PhOpenProcessToken(processHandleLimited, TOKEN_QUERY, &tokenHandle); - if (NT_SUCCESS(status)) + if (NT_SUCCESS(status)) + { + // Elevation + if (NT_SUCCESS(PhGetTokenElevationType( + tokenHandle, + &Data->ElevationType + ))) { - // Elevation - if (NT_SUCCESS(PhGetTokenElevationType( - tokenHandle, - &Data->ElevationType - ))) - { - Data->IsElevated = Data->ElevationType == TokenElevationTypeFull; - } + Data->IsElevated = Data->ElevationType == TokenElevationTypeFull; + } - // Integrity - PhGetTokenIntegrityLevel( - tokenHandle, - &Data->IntegrityLevel, - &Data->IntegrityString - ); + // Integrity + PhGetTokenIntegrityLevel( + tokenHandle, + &Data->IntegrityLevel, + &Data->IntegrityString + ); - NtClose(tokenHandle); - } + NtClose(tokenHandle); } } @@ -1360,24 +1357,13 @@ VOID PhpFillProcessItem( { PPH_STRING fileName; - if (WindowsVersion >= WINDOWS_VISTA) + if (processHandle) { - if (processHandle) - { - PhGetProcessImageFileNameWin32(processHandle, &ProcessItem->FileName); - } - else - { - if (NT_SUCCESS(PhGetProcessImageFileNameByProcessId(ProcessItem->ProcessId, &fileName))) - { - ProcessItem->FileName = PhGetFileName(fileName); - PhDereferenceObject(fileName); - } - } + PhGetProcessImageFileNameWin32(processHandle, &ProcessItem->FileName); } else { - if (processHandle && NT_SUCCESS(PhGetProcessImageFileName(processHandle, &fileName))) + if (NT_SUCCESS(PhGetProcessImageFileNameByProcessId(ProcessItem->ProcessId, &fileName))) { ProcessItem->FileName = PhGetFileName(fileName); PhDereferenceObject(fileName); @@ -2241,7 +2227,7 @@ VOID PhProcessProviderUpdate( { PhOpenProcess(&processItem->QueryHandle, PROCESS_QUERY_INFORMATION, processItem->ProcessId); - if (WINDOWS_HAS_LIMITED_ACCESS && !processItem->QueryHandle) + if (!processItem->QueryHandle) PhOpenProcess(&processItem->QueryHandle, PROCESS_QUERY_LIMITED_INFORMATION, processItem->ProcessId); } diff --git a/ProcessHacker/proctree.c b/ProcessHacker/proctree.c index b27671f789fb..10d78dc82b86 100644 --- a/ProcessHacker/proctree.c +++ b/ProcessHacker/proctree.c @@ -949,7 +949,7 @@ static VOID PhpUpdateProcessNodeToken( ProcessNode->VirtualizationAllowed = FALSE; ProcessNode->VirtualizationEnabled = FALSE; - if (WINDOWS_HAS_UAC && ProcessNode->ProcessItem->QueryHandle) + if (ProcessNode->ProcessItem->QueryHandle) { if (NT_SUCCESS(PhOpenProcessToken( ProcessNode->ProcessItem->QueryHandle, @@ -2359,16 +2359,8 @@ BOOLEAN NTAPI PhpProcessTreeNewCallback( break; case PHPRTLC_ASLR: PhpUpdateProcessNodeImage(node); - - if (WindowsVersion >= WINDOWS_VISTA) - { - if (node->ImageDllCharacteristics & IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE) - PhInitializeStringRef(&getCellText->Text, L"ASLR"); - } - else - { - PhInitializeStringRef(&getCellText->Text, L"N/A"); - } + if (node->ImageDllCharacteristics & IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE) + PhInitializeStringRef(&getCellText->Text, L"ASLR"); break; case PHPRTLC_RELATIVESTARTTIME: { @@ -2397,27 +2389,20 @@ BOOLEAN NTAPI PhpProcessTreeNewCallback( { PWSTR type; - if (WINDOWS_HAS_UAC) + switch (processItem->ElevationType) { - switch (processItem->ElevationType) - { - case TokenElevationTypeDefault: - type = L"N/A"; - break; - case TokenElevationTypeLimited: - type = L"Limited"; - break; - case TokenElevationTypeFull: - type = L"Full"; - break; - default: - type = L"N/A"; - break; - } - } - else - { - type = L""; + case TokenElevationTypeDefault: + type = L"N/A"; + break; + case TokenElevationTypeLimited: + type = L"Limited"; + break; + case TokenElevationTypeFull: + type = L"Full"; + break; + default: + type = L"N/A"; + break; } PhInitializeStringRefLongHint(&getCellText->Text, type); diff --git a/ProcessHacker/prpggen.c b/ProcessHacker/prpggen.c index 76318e4492e0..0fc4508d5593 100644 --- a/ProcessHacker/prpggen.c +++ b/ProcessHacker/prpggen.c @@ -344,7 +344,7 @@ INT_PTR CALLBACK PhpProcessGeneralDlgProc( SetDlgItemText(hwndDlg, IDC_PROTECTION, L"N/A"); - if (WINDOWS_HAS_LIMITED_ACCESS && processHandle) + if (processHandle) { if (WindowsVersion >= WINDOWS_8_1) { diff --git a/ProcessHacker/prpgstat.c b/ProcessHacker/prpgstat.c index 97b0127b4ea9..cb2ef363d4b5 100644 --- a/ProcessHacker/prpgstat.c +++ b/ProcessHacker/prpgstat.c @@ -123,18 +123,14 @@ VOID PhpUpdateProcessStatistics( gdiHandles = PhaFormatUInt64(GetGuiResources(ProcessItem->QueryHandle, GR_GDIOBJECTS), TRUE); // GDI handles userHandles = PhaFormatUInt64(GetGuiResources(ProcessItem->QueryHandle, GR_USEROBJECTS), TRUE); // USER handles - if (WINDOWS_HAS_CYCLE_TIME && - NT_SUCCESS(PhGetProcessCycleTime(ProcessItem->QueryHandle, &cycleTime))) + if (NT_SUCCESS(PhGetProcessCycleTime(ProcessItem->QueryHandle, &cycleTime))) { cycles = PhaFormatUInt64(cycleTime, TRUE); gotCycles = TRUE; } - if (WindowsVersion >= WINDOWS_VISTA) - { - PhGetProcessPagePriority(ProcessItem->QueryHandle, &pagePriority); - PhGetProcessIoPriority(ProcessItem->QueryHandle, &ioPriority); - } + PhGetProcessPagePriority(ProcessItem->QueryHandle, &pagePriority); + PhGetProcessIoPriority(ProcessItem->QueryHandle, &ioPriority); } if (Context->ProcessHandle) @@ -165,26 +161,17 @@ VOID PhpUpdateProcessStatistics( SetDlgItemText(hwndDlg, IDC_ZGDIHANDLES_V, PhGetStringOrDefault(gdiHandles, L"Unknown")); SetDlgItemText(hwndDlg, IDC_ZUSERHANDLES_V, PhGetStringOrDefault(userHandles, L"Unknown")); - SetDlgItemText(hwndDlg, IDC_ZCYCLES_V, - PhGetStringOrDefault(cycles, WINDOWS_HAS_CYCLE_TIME ? L"Unknown" : L"N/A")); + SetDlgItemText(hwndDlg, IDC_ZCYCLES_V, PhGetStringOrDefault(cycles, L"Unknown")); - if (WindowsVersion >= WINDOWS_VISTA) - { - if (pagePriority != -1 && pagePriority <= MEMORY_PRIORITY_NORMAL) - SetDlgItemText(hwndDlg, IDC_ZPAGEPRIORITY_V, PhPagePriorityNames[pagePriority]); - else - SetDlgItemText(hwndDlg, IDC_ZPAGEPRIORITY_V, L"Unknown"); - - if (ioPriority != -1 && ioPriority < MaxIoPriorityTypes) - SetDlgItemText(hwndDlg, IDC_ZIOPRIORITY_V, PhIoPriorityHintNames[ioPriority]); - else - SetDlgItemText(hwndDlg, IDC_ZIOPRIORITY_V, L"Unknown"); - } + if (pagePriority != -1 && pagePriority <= MEMORY_PRIORITY_NORMAL) + SetDlgItemText(hwndDlg, IDC_ZPAGEPRIORITY_V, PhPagePriorityNames[pagePriority]); else - { - SetDlgItemText(hwndDlg, IDC_ZPAGEPRIORITY_V, L"N/A"); - SetDlgItemText(hwndDlg, IDC_ZIOPRIORITY_V, L"N/A"); - } + SetDlgItemText(hwndDlg, IDC_ZPAGEPRIORITY_V, L"Unknown"); + + if (ioPriority != -1 && ioPriority < MaxIoPriorityTypes) + SetDlgItemText(hwndDlg, IDC_ZIOPRIORITY_V, PhIoPriorityHintNames[ioPriority]); + else + SetDlgItemText(hwndDlg, IDC_ZIOPRIORITY_V, L"Unknown"); SetDlgItemText(hwndDlg, IDC_ZPRIVATEWS_V, PhGetStringOrDefault(privateWs, L"Unknown")); SetDlgItemText(hwndDlg, IDC_ZSHAREABLEWS_V, PhGetStringOrDefault(shareableWs, L"Unknown")); diff --git a/ProcessHacker/prpgthrd.c b/ProcessHacker/prpgthrd.c index cf23dd2cccc2..35601d2d7fdf 100644 --- a/ProcessHacker/prpgthrd.c +++ b/ProcessHacker/prpgthrd.c @@ -102,8 +102,6 @@ VOID PhpInitializeThreadMenu( _In_ ULONG NumberOfThreads ) { - PPH_EMENU_ITEM item; - if (NumberOfThreads == 0) { PhSetFlagsAllEMenuItems(Menu, PH_EMENU_DISABLED, PH_EMENU_DISABLED); @@ -133,18 +131,6 @@ VOID PhpInitializeThreadMenu( } } - // Remove irrelevant menu items. - - if (WindowsVersion < WINDOWS_VISTA) - { - // Remove I/O priority. - if (item = PhFindEMenuItem(Menu, 0, L"I/O Priority", 0)) - PhDestroyEMenuItem(item); - // Remove page priority. - if (item = PhFindEMenuItem(Menu, 0, L"Page Priority", 0)) - PhDestroyEMenuItem(item); - } - PhEnableEMenuItem(Menu, ID_THREAD_TOKEN, FALSE); // Priority @@ -163,32 +149,25 @@ VOID PhpInitializeThreadMenu( ))) { THREAD_BASIC_INFORMATION basicInfo; + HANDLE tokenHandle; if (NT_SUCCESS(PhGetThreadBasicInformation(threadHandle, &basicInfo))) { threadPriority = basicInfo.BasePriority; } - if (WindowsVersion >= WINDOWS_VISTA) - { - PhGetThreadIoPriority(threadHandle, &ioPriority); - PhGetThreadPagePriority(threadHandle, &pagePriority); - } + PhGetThreadIoPriority(threadHandle, &ioPriority); + PhGetThreadPagePriority(threadHandle, &pagePriority); - // Token + if (NT_SUCCESS(NtOpenThreadToken( + threadHandle, + TOKEN_QUERY, + TRUE, + &tokenHandle + ))) { - HANDLE tokenHandle; - - if (NT_SUCCESS(NtOpenThreadToken( - threadHandle, - TOKEN_QUERY, - TRUE, - &tokenHandle - ))) - { - PhEnableEMenuItem(Menu, ID_THREAD_TOKEN, TRUE); - NtClose(tokenHandle); - } + PhEnableEMenuItem(Menu, ID_THREAD_TOKEN, TRUE); + NtClose(tokenHandle); } NtClose(threadHandle); @@ -363,9 +342,7 @@ VOID PhpUpdateThreadDetails( PhPrintTimeSpan(userTime, threadItem->UserTime.QuadPart, PH_TIMESPAN_HMSM); contextSwitches = PhaFormatUInt64(threadItem->ContextSwitchesDelta.Value, TRUE); - - if (WINDOWS_HAS_CYCLE_TIME) - cycles = PhaFormatUInt64(threadItem->CyclesDelta.Value, TRUE); + cycles = PhaFormatUInt64(threadItem->CyclesDelta.Value, TRUE); if (threadItem->State != Waiting) { @@ -588,7 +565,6 @@ INT_PTR CALLBACK PhpProcessThreadsDlgProc( // Use Cycles instead of Context Switches on Vista and above, but only when we can // open the process, since cycle time information requires sufficient access to the // threads. - if (WINDOWS_HAS_CYCLE_TIME) { HANDLE processHandle; @@ -619,7 +595,7 @@ INT_PTR CALLBACK PhpProcessThreadsDlgProc( } } - if (processItem->ServiceList && processItem->ServiceList->Count != 0 && WINDOWS_HAS_SERVICE_TAGS) + if (processItem->ServiceList && processItem->ServiceList->Count != 0) threadsContext->ListContext.HasServices = TRUE; PhEmCallObjectOperation(EmThreadsContextType, threadsContext, EmObjectCreate); diff --git a/ProcessHacker/resource.h b/ProcessHacker/resource.h index b8c58833da9e..82fb961b55c9 100644 --- a/ProcessHacker/resource.h +++ b/ProcessHacker/resource.h @@ -109,7 +109,6 @@ #define IDD_MEMLISTS 202 #define IDR_EMPTYMEMLISTS 204 #define IDD_CONTAINER 205 -#define IDD_SYSINFO_MEMPANELXP 206 #define IDD_MINIINFO 207 #define IDD_MINIINFO_LIST 210 #define IDR_MINIINFO 211 diff --git a/ProcessHacker/runas.c b/ProcessHacker/runas.c index 6abbef469ff3..c765e6293a38 100644 --- a/ProcessHacker/runas.c +++ b/ProcessHacker/runas.c @@ -349,9 +349,6 @@ INT_PTR CALLBACK PhpRunAsDlgProc( //if (!PhGetOwnTokenAttributes().Elevated) // SendMessage(GetDlgItem(hwndDlg, IDOK), BCM_SETSHIELD, 0, TRUE); - - if (!WINDOWS_HAS_UAC) - ShowWindow(GetDlgItem(hwndDlg, IDC_TOGGLEELEVATION), SW_HIDE); } break; case WM_DESTROY: @@ -407,11 +404,7 @@ INT_PTR CALLBACK PhpRunAsDlgProc( sessionId = GetDlgItemInt(hwndDlg, IDC_SESSIONID, NULL, FALSE); desktopName = PhaGetDlgItemText(hwndDlg, IDC_DESKTOP); - - if (WINDOWS_HAS_UAC) - useLinkedToken = Button_GetCheck(GetDlgItem(hwndDlg, IDC_TOGGLEELEVATION)) == BST_CHECKED; - else - useLinkedToken = FALSE; + useLinkedToken = Button_GetCheck(GetDlgItem(hwndDlg, IDC_TOGGLEELEVATION)) == BST_CHECKED; if (PhFindIntegerSiKeyValuePairs( PhpLogonTypePairs, @@ -444,8 +437,7 @@ INT_PTR CALLBACK PhpRunAsDlgProc( createInfo.Password = PhGetStringOrEmpty(password); // Whenever we can, try not to set the desktop name; it breaks a lot of things. - // Note that on XP we must set it, otherwise the program doesn't display correctly. - if (WindowsVersion < WINDOWS_VISTA || (desktopName->Length != 0 && !PhEqualString2(desktopName, L"WinSta0\\Default", TRUE))) + if (desktopName->Length != 0 && !PhEqualString2(desktopName, L"WinSta0\\Default", TRUE)) createInfo.DesktopName = desktopName->Buffer; PhSetDesktopWinStaAccess(); diff --git a/ProcessHacker/srvprp.c b/ProcessHacker/srvprp.c index 658efd1f439c..17508959dcc5 100644 --- a/ProcessHacker/srvprp.c +++ b/ProcessHacker/srvprp.c @@ -174,10 +174,7 @@ static VOID PhpRefreshControls( _In_ HWND hwndDlg ) { - if ( - WindowsVersion >= WINDOWS_VISTA && - PhEqualString2(PhaGetDlgItemText(hwndDlg, IDC_STARTTYPE), L"Auto start", FALSE) - ) + if (PhEqualString2(PhaGetDlgItemText(hwndDlg, IDC_STARTTYPE), L"Auto start", FALSE)) { EnableWindow(GetDlgItem(hwndDlg, IDC_DELAYEDSTART), TRUE); } @@ -254,10 +251,7 @@ INT_PTR CALLBACK PhpServiceGeneralDlgProc( PhDereferenceObject(description); } - if ( - WindowsVersion >= WINDOWS_VISTA && - PhGetServiceDelayedAutoStart(serviceHandle, &delayedStart) - ) + if (PhGetServiceDelayedAutoStart(serviceHandle, &delayedStart)) { context->OldDelayedStart = delayedStart; @@ -460,16 +454,13 @@ INT_PTR CALLBACK PhpServiceGeneralDlgProc( NULL )) { - if (WindowsVersion >= WINDOWS_VISTA) - { - BOOLEAN newDelayedStart; + BOOLEAN newDelayedStart; - newDelayedStart = Button_GetCheck(GetDlgItem(hwndDlg, IDC_DELAYEDSTART)) == BST_CHECKED; + newDelayedStart = Button_GetCheck(GetDlgItem(hwndDlg, IDC_DELAYEDSTART)) == BST_CHECKED; - if (newDelayedStart != context->OldDelayedStart) - { - PhSetServiceDelayedAutoStart(serviceHandle, newDelayedStart); - } + if (newDelayedStart != context->OldDelayedStart) + { + PhSetServiceDelayedAutoStart(serviceHandle, newDelayedStart); } PhMarkNeedsConfigUpdateServiceItem(serviceItem); @@ -503,23 +494,20 @@ INT_PTR CALLBACK PhpServiceGeneralDlgProc( NULL ))) { - if (WindowsVersion >= WINDOWS_VISTA) - { - BOOLEAN newDelayedStart; - - newDelayedStart = Button_GetCheck(GetDlgItem(hwndDlg, IDC_DELAYEDSTART)) == BST_CHECKED; + BOOLEAN newDelayedStart; - if (newDelayedStart != context->OldDelayedStart) - { - SERVICE_DELAYED_AUTO_START_INFO info; + newDelayedStart = Button_GetCheck(GetDlgItem(hwndDlg, IDC_DELAYEDSTART)) == BST_CHECKED; - info.fDelayedAutostart = newDelayedStart; - PhSvcCallChangeServiceConfig2( - serviceItem->Name->Buffer, - SERVICE_CONFIG_DELAYED_AUTO_START_INFO, - &info - ); - } + if (newDelayedStart != context->OldDelayedStart) + { + SERVICE_DELAYED_AUTO_START_INFO info; + + info.fDelayedAutostart = newDelayedStart; + PhSvcCallChangeServiceConfig2( + serviceItem->Name->Buffer, + SERVICE_CONFIG_DELAYED_AUTO_START_INFO, + &info + ); } PhMarkNeedsConfigUpdateServiceItem(serviceItem); diff --git a/ProcessHacker/srvprv.c b/ProcessHacker/srvprv.c index 18f258c7aa3d..22ae892d9122 100644 --- a/ProcessHacker/srvprv.c +++ b/ProcessHacker/srvprv.c @@ -463,11 +463,7 @@ VOID PhServiceProviderUpdate( { if (!PhpNonPollInitialized) { - if (WindowsVersion >= WINDOWS_VISTA) - { - PhpInitializeServiceNonPoll(); - } - + PhpInitializeServiceNonPoll(); PhpNonPollInitialized = TRUE; } diff --git a/ProcessHacker/sysinfo.c b/ProcessHacker/sysinfo.c index 889066c520c7..1f6184e83044 100644 --- a/ProcessHacker/sysinfo.c +++ b/ProcessHacker/sysinfo.c @@ -428,7 +428,7 @@ VOID PhSipOnShowWindow( MinimumSize.left = 0; MinimumSize.top = 0; - MinimumSize.right = WindowsVersion >= WINDOWS_VISTA ? 430 : 370; // XP doesn't have the Memory Lists group + MinimumSize.right = 430; MinimumSize.bottom = 290; MapDialogRect(PhSipWindow, &MinimumSize); diff --git a/ProcessHacker/sysscmem.c b/ProcessHacker/sysscmem.c index f375ad8fb9d7..f17d5ad36e05 100644 --- a/ProcessHacker/sysscmem.c +++ b/ProcessHacker/sysscmem.c @@ -320,7 +320,7 @@ INT_PTR CALLBACK PhSipMemoryDialogProc( MemoryPanel = CreateDialog( PhInstanceHandle, - WindowsVersion >= WINDOWS_VISTA ? MAKEINTRESOURCE(IDD_SYSINFO_MEMPANEL) : MAKEINTRESOURCE(IDD_SYSINFO_MEMPANELXP), + MAKEINTRESOURCE(IDD_SYSINFO_MEMPANEL), hwndDlg, PhSipMemoryPanelDialogProc ); @@ -777,64 +777,61 @@ VOID PhSipUpdateMemoryPanel( // Memory lists - if (WindowsVersion >= WINDOWS_VISTA) + if (NT_SUCCESS(NtQuerySystemInformation( + SystemMemoryListInformation, + &memoryListInfo, + sizeof(SYSTEM_MEMORY_LIST_INFORMATION), + NULL + ))) { - if (NT_SUCCESS(NtQuerySystemInformation( - SystemMemoryListInformation, - &memoryListInfo, - sizeof(SYSTEM_MEMORY_LIST_INFORMATION), - NULL - ))) - { - ULONG_PTR standbyPageCount; - ULONG_PTR repurposedPageCount; - ULONG i; + ULONG_PTR standbyPageCount; + ULONG_PTR repurposedPageCount; + ULONG i; - standbyPageCount = 0; - repurposedPageCount = 0; + standbyPageCount = 0; + repurposedPageCount = 0; - for (i = 0; i < 8; i++) - { - standbyPageCount += memoryListInfo.PageCountByPriority[i]; - repurposedPageCount += memoryListInfo.RepurposedPagesByPriority[i]; - } - - SetDlgItemText(MemoryPanel, IDC_ZLISTZEROED_V, PhaFormatSize((ULONG64)memoryListInfo.ZeroPageCount * PAGE_SIZE, -1)->Buffer); - SetDlgItemText(MemoryPanel, IDC_ZLISTFREE_V, PhaFormatSize((ULONG64)memoryListInfo.FreePageCount * PAGE_SIZE, -1)->Buffer); - SetDlgItemText(MemoryPanel, IDC_ZLISTMODIFIED_V, PhaFormatSize((ULONG64)memoryListInfo.ModifiedPageCount * PAGE_SIZE, -1)->Buffer); - SetDlgItemText(MemoryPanel, IDC_ZLISTMODIFIEDNOWRITE_V, PhaFormatSize((ULONG64)memoryListInfo.ModifiedNoWritePageCount * PAGE_SIZE, -1)->Buffer); - SetDlgItemText(MemoryPanel, IDC_ZLISTSTANDBY_V, PhaFormatSize((ULONG64)standbyPageCount * PAGE_SIZE, -1)->Buffer); - SetDlgItemText(MemoryPanel, IDC_ZLISTSTANDBY0_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[0] * PAGE_SIZE, -1)->Buffer); - SetDlgItemText(MemoryPanel, IDC_ZLISTSTANDBY1_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[1] * PAGE_SIZE, -1)->Buffer); - SetDlgItemText(MemoryPanel, IDC_ZLISTSTANDBY2_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[2] * PAGE_SIZE, -1)->Buffer); - SetDlgItemText(MemoryPanel, IDC_ZLISTSTANDBY3_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[3] * PAGE_SIZE, -1)->Buffer); - SetDlgItemText(MemoryPanel, IDC_ZLISTSTANDBY4_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[4] * PAGE_SIZE, -1)->Buffer); - SetDlgItemText(MemoryPanel, IDC_ZLISTSTANDBY5_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[5] * PAGE_SIZE, -1)->Buffer); - SetDlgItemText(MemoryPanel, IDC_ZLISTSTANDBY6_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[6] * PAGE_SIZE, -1)->Buffer); - SetDlgItemText(MemoryPanel, IDC_ZLISTSTANDBY7_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[7] * PAGE_SIZE, -1)->Buffer); - - if (WindowsVersion >= WINDOWS_8) - SetDlgItemText(MemoryPanel, IDC_ZLISTMODIFIEDPAGEFILE_V, PhaFormatSize((ULONG64)memoryListInfo.ModifiedPageCountPageFile * PAGE_SIZE, -1)->Buffer); - else - SetDlgItemText(MemoryPanel, IDC_ZLISTMODIFIEDPAGEFILE_V, L"N/A"); + for (i = 0; i < 8; i++) + { + standbyPageCount += memoryListInfo.PageCountByPriority[i]; + repurposedPageCount += memoryListInfo.RepurposedPagesByPriority[i]; } + + SetDlgItemText(MemoryPanel, IDC_ZLISTZEROED_V, PhaFormatSize((ULONG64)memoryListInfo.ZeroPageCount * PAGE_SIZE, -1)->Buffer); + SetDlgItemText(MemoryPanel, IDC_ZLISTFREE_V, PhaFormatSize((ULONG64)memoryListInfo.FreePageCount * PAGE_SIZE, -1)->Buffer); + SetDlgItemText(MemoryPanel, IDC_ZLISTMODIFIED_V, PhaFormatSize((ULONG64)memoryListInfo.ModifiedPageCount * PAGE_SIZE, -1)->Buffer); + SetDlgItemText(MemoryPanel, IDC_ZLISTMODIFIEDNOWRITE_V, PhaFormatSize((ULONG64)memoryListInfo.ModifiedNoWritePageCount * PAGE_SIZE, -1)->Buffer); + SetDlgItemText(MemoryPanel, IDC_ZLISTSTANDBY_V, PhaFormatSize((ULONG64)standbyPageCount * PAGE_SIZE, -1)->Buffer); + SetDlgItemText(MemoryPanel, IDC_ZLISTSTANDBY0_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[0] * PAGE_SIZE, -1)->Buffer); + SetDlgItemText(MemoryPanel, IDC_ZLISTSTANDBY1_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[1] * PAGE_SIZE, -1)->Buffer); + SetDlgItemText(MemoryPanel, IDC_ZLISTSTANDBY2_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[2] * PAGE_SIZE, -1)->Buffer); + SetDlgItemText(MemoryPanel, IDC_ZLISTSTANDBY3_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[3] * PAGE_SIZE, -1)->Buffer); + SetDlgItemText(MemoryPanel, IDC_ZLISTSTANDBY4_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[4] * PAGE_SIZE, -1)->Buffer); + SetDlgItemText(MemoryPanel, IDC_ZLISTSTANDBY5_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[5] * PAGE_SIZE, -1)->Buffer); + SetDlgItemText(MemoryPanel, IDC_ZLISTSTANDBY6_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[6] * PAGE_SIZE, -1)->Buffer); + SetDlgItemText(MemoryPanel, IDC_ZLISTSTANDBY7_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[7] * PAGE_SIZE, -1)->Buffer); + + if (WindowsVersion >= WINDOWS_8) + SetDlgItemText(MemoryPanel, IDC_ZLISTMODIFIEDPAGEFILE_V, PhaFormatSize((ULONG64)memoryListInfo.ModifiedPageCountPageFile * PAGE_SIZE, -1)->Buffer); else - { - SetDlgItemText(MemoryPanel, IDC_ZLISTZEROED_V, L"N/A"); - SetDlgItemText(MemoryPanel, IDC_ZLISTFREE_V, L"N/A"); - SetDlgItemText(MemoryPanel, IDC_ZLISTMODIFIED_V, L"N/A"); - SetDlgItemText(MemoryPanel, IDC_ZLISTMODIFIEDNOWRITE_V, L"N/A"); SetDlgItemText(MemoryPanel, IDC_ZLISTMODIFIEDPAGEFILE_V, L"N/A"); - SetDlgItemText(MemoryPanel, IDC_ZLISTSTANDBY_V, L"N/A"); - SetDlgItemText(MemoryPanel, IDC_ZLISTSTANDBY0_V, L"N/A"); - SetDlgItemText(MemoryPanel, IDC_ZLISTSTANDBY1_V, L"N/A"); - SetDlgItemText(MemoryPanel, IDC_ZLISTSTANDBY2_V, L"N/A"); - SetDlgItemText(MemoryPanel, IDC_ZLISTSTANDBY3_V, L"N/A"); - SetDlgItemText(MemoryPanel, IDC_ZLISTSTANDBY4_V, L"N/A"); - SetDlgItemText(MemoryPanel, IDC_ZLISTSTANDBY5_V, L"N/A"); - SetDlgItemText(MemoryPanel, IDC_ZLISTSTANDBY6_V, L"N/A"); - SetDlgItemText(MemoryPanel, IDC_ZLISTSTANDBY7_V, L"N/A"); - } + } + else + { + SetDlgItemText(MemoryPanel, IDC_ZLISTZEROED_V, L"N/A"); + SetDlgItemText(MemoryPanel, IDC_ZLISTFREE_V, L"N/A"); + SetDlgItemText(MemoryPanel, IDC_ZLISTMODIFIED_V, L"N/A"); + SetDlgItemText(MemoryPanel, IDC_ZLISTMODIFIEDNOWRITE_V, L"N/A"); + SetDlgItemText(MemoryPanel, IDC_ZLISTMODIFIEDPAGEFILE_V, L"N/A"); + SetDlgItemText(MemoryPanel, IDC_ZLISTSTANDBY_V, L"N/A"); + SetDlgItemText(MemoryPanel, IDC_ZLISTSTANDBY0_V, L"N/A"); + SetDlgItemText(MemoryPanel, IDC_ZLISTSTANDBY1_V, L"N/A"); + SetDlgItemText(MemoryPanel, IDC_ZLISTSTANDBY2_V, L"N/A"); + SetDlgItemText(MemoryPanel, IDC_ZLISTSTANDBY3_V, L"N/A"); + SetDlgItemText(MemoryPanel, IDC_ZLISTSTANDBY4_V, L"N/A"); + SetDlgItemText(MemoryPanel, IDC_ZLISTSTANDBY5_V, L"N/A"); + SetDlgItemText(MemoryPanel, IDC_ZLISTSTANDBY6_V, L"N/A"); + SetDlgItemText(MemoryPanel, IDC_ZLISTSTANDBY7_V, L"N/A"); } } diff --git a/ProcessHacker/thrdprv.c b/ProcessHacker/thrdprv.c index 8f7a60b85b6a..a0cf4bee575b 100644 --- a/ProcessHacker/thrdprv.c +++ b/ProcessHacker/thrdprv.c @@ -538,7 +538,7 @@ NTSTATUS PhpThreadQueryWorker( // Check if the process has services - we'll need to know before getting service tag/name // information. - if (WINDOWS_HAS_SERVICE_TAGS && !data->ThreadProvider->HasServicesKnown) + if (!data->ThreadProvider->HasServicesKnown) { PPH_PROCESS_ITEM processItem; @@ -552,9 +552,10 @@ NTSTATUS PhpThreadQueryWorker( } // Get the service tag, and the service name. - if (WINDOWS_HAS_SERVICE_TAGS && + if ( data->ThreadProvider->SymbolProvider->IsRealHandle && - data->ThreadItem->ThreadHandle) + data->ThreadItem->ThreadHandle + ) { PVOID serviceTag; @@ -869,7 +870,6 @@ VOID PhpThreadProviderUpdate( } // Get the cycle count. - if (WINDOWS_HAS_CYCLE_TIME) { ULONG64 cycles; @@ -1027,7 +1027,6 @@ VOID PhpThreadProviderUpdate( } // Update the cycle count. - if (WINDOWS_HAS_CYCLE_TIME) { ULONG64 cycles; ULONG64 oldDelta; @@ -1055,7 +1054,7 @@ VOID PhpThreadProviderUpdate( // Update the CPU usage. // If the cycle time isn't available, we'll fall back to using the CPU time. - if (WINDOWS_HAS_CYCLE_TIME && PhEnableCycleCpuUsage && (threadProvider->ProcessId == SYSTEM_IDLE_PROCESS_ID || threadItem->ThreadHandle)) + if (PhEnableCycleCpuUsage && (threadProvider->ProcessId == SYSTEM_IDLE_PROCESS_ID || threadItem->ThreadHandle)) { threadItem->CpuUsage = (FLOAT)threadItem->CyclesDelta.Delta / PhCpuTotalCycleDelta; } diff --git a/ProcessHacker/tokprp.c b/ProcessHacker/tokprp.c index 6a0f419656db..d5b6caa775db 100644 --- a/ProcessHacker/tokprp.c +++ b/ProcessHacker/tokprp.c @@ -450,9 +450,6 @@ INT_PTR CALLBACK PhpTokenPageProc( SetDlgItemText(hwndDlg, IDC_USERSID, L"Unknown"); SetDlgItemText(hwndDlg, IDC_APPCONTAINERSID, L"Unknown"); - if (!WINDOWS_HAS_UAC) - ShowWindow(GetDlgItem(hwndDlg, IDC_INTEGRITY), SW_HIDE); - if (NT_SUCCESS(tokenPageContext->OpenObject( &tokenHandle, TOKEN_QUERY, @@ -490,34 +487,26 @@ INT_PTR CALLBACK PhpTokenPageProc( if (NT_SUCCESS(PhGetTokenSessionId(tokenHandle, &sessionId))) SetDlgItemInt(hwndDlg, IDC_SESSIONID, sessionId, FALSE); - if (WINDOWS_HAS_UAC) - { - if (NT_SUCCESS(PhGetTokenElevationType(tokenHandle, &elevationType))) - SetDlgItemText(hwndDlg, IDC_ELEVATED, PhGetElevationTypeString(elevationType)); + if (NT_SUCCESS(PhGetTokenElevationType(tokenHandle, &elevationType))) + SetDlgItemText(hwndDlg, IDC_ELEVATED, PhGetElevationTypeString(elevationType)); - if (NT_SUCCESS(PhGetTokenIsVirtualizationAllowed(tokenHandle, &isVirtualizationAllowed))) + if (NT_SUCCESS(PhGetTokenIsVirtualizationAllowed(tokenHandle, &isVirtualizationAllowed))) + { + if (isVirtualizationAllowed) { - if (isVirtualizationAllowed) + if (NT_SUCCESS(PhGetTokenIsVirtualizationEnabled(tokenHandle, &isVirtualizationEnabled))) { - if (NT_SUCCESS(PhGetTokenIsVirtualizationEnabled(tokenHandle, &isVirtualizationEnabled))) - { - SetDlgItemText( - hwndDlg, - IDC_VIRTUALIZED, - isVirtualizationEnabled ? L"Yes" : L"No" - ); - } - } - else - { - SetDlgItemText(hwndDlg, IDC_VIRTUALIZED, L"Not allowed"); + SetDlgItemText( + hwndDlg, + IDC_VIRTUALIZED, + isVirtualizationEnabled ? L"Yes" : L"No" + ); } } - } - else - { - SetDlgItemText(hwndDlg, IDC_ELEVATED, L"N/A"); - SetDlgItemText(hwndDlg, IDC_VIRTUALIZED, L"N/A"); + else + { + SetDlgItemText(hwndDlg, IDC_VIRTUALIZED, L"Not allowed"); + } } if (WINDOWS_HAS_IMMERSIVE) @@ -1119,28 +1108,25 @@ INT_PTR CALLBACK PhpTokenGeneralPageProc( PhGetTokenSessionId(tokenHandle, &tokenSessionId); - if (WINDOWS_HAS_UAC) + if (NT_SUCCESS(PhGetTokenElevationType(tokenHandle, &elevationType))) { - if (NT_SUCCESS(PhGetTokenElevationType(tokenHandle, &elevationType))) - { - tokenElevated = PhGetElevationTypeString(elevationType); - hasLinkedToken = elevationType != TokenElevationTypeDefault; - } + tokenElevated = PhGetElevationTypeString(elevationType); + hasLinkedToken = elevationType != TokenElevationTypeDefault; + } - if (NT_SUCCESS(PhGetTokenIsVirtualizationAllowed(tokenHandle, &isVirtualizationAllowed))) + if (NT_SUCCESS(PhGetTokenIsVirtualizationAllowed(tokenHandle, &isVirtualizationAllowed))) + { + if (isVirtualizationAllowed) { - if (isVirtualizationAllowed) + if (NT_SUCCESS(PhGetTokenIsVirtualizationEnabled(tokenHandle, &isVirtualizationEnabled))) { - if (NT_SUCCESS(PhGetTokenIsVirtualizationEnabled(tokenHandle, &isVirtualizationEnabled))) - { - tokenVirtualization = isVirtualizationEnabled ? L"Enabled" : L"Disabled"; - } - } - else - { - tokenVirtualization = L"Not Allowed"; + tokenVirtualization = isVirtualizationEnabled ? L"Enabled" : L"Disabled"; } } + else + { + tokenVirtualization = L"Not Allowed"; + } } NtClose(tokenHandle); diff --git a/phlib/global.c b/phlib/global.c index fb8a44453ab0..004986fdc189 100644 --- a/phlib/global.c +++ b/phlib/global.c @@ -220,20 +220,9 @@ static VOID PhInitializeWindowsVersion( WindowsVersion = WINDOWS_NEW; } - if (WINDOWS_HAS_LIMITED_ACCESS) - { - ProcessQueryAccess = PROCESS_QUERY_LIMITED_INFORMATION; - ProcessAllAccess = STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x1fff; - ThreadQueryAccess = THREAD_QUERY_LIMITED_INFORMATION; - ThreadSetAccess = THREAD_SET_LIMITED_INFORMATION; - ThreadAllAccess = STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xfff; - } - else - { - ProcessQueryAccess = PROCESS_QUERY_INFORMATION; - ProcessAllAccess = STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xfff; - ThreadQueryAccess = THREAD_QUERY_INFORMATION; - ThreadSetAccess = THREAD_SET_INFORMATION; - ThreadAllAccess = STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x3ff; - } + ProcessQueryAccess = PROCESS_QUERY_LIMITED_INFORMATION; + ProcessAllAccess = STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x1fff; + ThreadQueryAccess = THREAD_QUERY_LIMITED_INFORMATION; + ThreadSetAccess = THREAD_SET_LIMITED_INFORMATION; + ThreadAllAccess = STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xfff; } diff --git a/phlib/guisup.c b/phlib/guisup.c index c8f8f6e3298e..c7d3d1143d75 100644 --- a/phlib/guisup.c +++ b/phlib/guisup.c @@ -50,8 +50,7 @@ VOID PhGuiSupportInitialization( shell32Handle = LoadLibrary(L"shell32.dll"); shlwapiHandle = LoadLibrary(L"shlwapi.dll"); - if (WINDOWS_HAS_UAC) - ChangeWindowMessageFilter_I = PhGetModuleProcAddress(L"user32.dll", "ChangeWindowMessageFilter"); + ChangeWindowMessageFilter_I = PhGetModuleProcAddress(L"user32.dll", "ChangeWindowMessageFilter"); if (WINDOWS_HAS_IMMERSIVE) IsImmersiveProcess_I = PhGetModuleProcAddress(L"user32.dll", "IsImmersiveProcess"); RunFileDlg = PhGetProcedureAddress(shell32Handle, NULL, 61); @@ -63,10 +62,7 @@ VOID PhSetControlTheme( _In_ PWSTR Theme ) { - if (WindowsVersion >= WINDOWS_VISTA) - { - SetWindowTheme(Handle, Theme, NULL); - } + SetWindowTheme(Handle, Theme, NULL); } INT PhAddListViewColumn( @@ -694,16 +690,11 @@ VOID PhGetStockApplicationIcon( PhInitializeStringRef(&dllBaseName, L"\\imageres.dll"); index = 11; } - else if (WindowsVersion >= WINDOWS_VISTA) + else { PhInitializeStringRef(&dllBaseName, L"\\user32.dll"); index = 0; } - else - { - PhInitializeStringRef(&dllBaseName, L"\\shell32.dll"); - index = 2; - } dllFileName = PhConcatStringRef2(&systemDirectory->sr, &dllBaseName); PhDereferenceObject(systemDirectory); diff --git a/phlib/include/phconfig.h b/phlib/include/phconfig.h index 75892b856fe8..6da596042c2f 100644 --- a/phlib/include/phconfig.h +++ b/phlib/include/phconfig.h @@ -33,13 +33,8 @@ PHLIBAPI extern ACCESS_MASK ThreadAllAccess; #define WINDOWS_NEW MAXLONG #define WINDOWS_HAS_CONSOLE_HOST (WindowsVersion >= WINDOWS_7) -#define WINDOWS_HAS_CYCLE_TIME (WindowsVersion >= WINDOWS_VISTA) -#define WINDOWS_HAS_IFILEDIALOG (WindowsVersion >= WINDOWS_VISTA) #define WINDOWS_HAS_IMAGE_FILE_NAME_BY_PROCESS_ID (WindowsVersion >= WINDOWS_VISTA) #define WINDOWS_HAS_IMMERSIVE (WindowsVersion >= WINDOWS_8) -#define WINDOWS_HAS_LIMITED_ACCESS (WindowsVersion >= WINDOWS_VISTA) -#define WINDOWS_HAS_SERVICE_TAGS (WindowsVersion >= WINDOWS_VISTA) -#define WINDOWS_HAS_UAC (WindowsVersion >= WINDOWS_VISTA) // Debugging diff --git a/phlib/native.c b/phlib/native.c index d00fdb099868..2ce8abb501dd 100644 --- a/phlib/native.c +++ b/phlib/native.c @@ -87,11 +87,8 @@ PH_TOKEN_ATTRIBUTES PhGetOwnTokenAttributes( BOOLEAN elevated = TRUE; TOKEN_ELEVATION_TYPE elevationType = TokenElevationTypeFull; - if (WINDOWS_HAS_UAC) - { - PhGetTokenIsElevated(attributes.TokenHandle, &elevated); - PhGetTokenElevationType(attributes.TokenHandle, &elevationType); - } + PhGetTokenIsElevated(attributes.TokenHandle, &elevated); + PhGetTokenElevationType(attributes.TokenHandle, &elevationType); attributes.Elevated = elevated; attributes.ElevationType = elevationType; @@ -1319,39 +1316,19 @@ NTSTATUS PhInjectDllProcess( ))) goto FreeExit; - // Vista seems to support native threads better than XP. - if (WindowsVersion >= WINDOWS_VISTA) - { - if (!NT_SUCCESS(status = RtlCreateUserThread( - ProcessHandle, - NULL, - FALSE, - 0, - 0, - 0, - (PUSER_THREAD_START_ROUTINE)threadStart, - baseAddress, - &threadHandle, - NULL - ))) - goto FreeExit; - } - else - { - if (!(threadHandle = CreateRemoteThread( - ProcessHandle, - NULL, - 0, - (PTHREAD_START_ROUTINE)threadStart, - baseAddress, - 0, - NULL - ))) - { - status = PhGetLastWin32ErrorAsNtStatus(); - goto FreeExit; - } - } + if (!NT_SUCCESS(status = RtlCreateUserThread( + ProcessHandle, + NULL, + FALSE, + 0, + 0, + 0, + (PUSER_THREAD_START_ROUTINE)threadStart, + baseAddress, + &threadHandle, + NULL + ))) + goto FreeExit; // Wait for the thread to finish. status = NtWaitForSingleObject(threadHandle, FALSE, Timeout); @@ -1465,36 +1442,18 @@ NTSTATUS PhUnloadDllProcess( } #endif - if (WindowsVersion >= WINDOWS_VISTA) - { - status = RtlCreateUserThread( - ProcessHandle, - NULL, - FALSE, - 0, - 0, - 0, - (PUSER_THREAD_START_ROUTINE)threadStart, - BaseAddress, - &threadHandle, - NULL - ); - } - else - { - if (!(threadHandle = CreateRemoteThread( - ProcessHandle, - NULL, - 0, - (PTHREAD_START_ROUTINE)threadStart, - BaseAddress, - 0, - NULL - ))) - { - status = PhGetLastWin32ErrorAsNtStatus(); - } - } + status = RtlCreateUserThread( + ProcessHandle, + NULL, + FALSE, + 0, + 0, + 0, + (PUSER_THREAD_START_ROUTINE)threadStart, + BaseAddress, + &threadHandle, + NULL + ); if (!NT_SUCCESS(status)) return status; @@ -1639,39 +1598,20 @@ NTSTATUS PhSetEnvironmentVariableRemote( } } - if (WindowsVersion >= WINDOWS_VISTA) - { - if (!NT_SUCCESS(status = RtlCreateUserThread( - ProcessHandle, - NULL, - TRUE, - 0, - 0, - 0, - (PUSER_THREAD_START_ROUTINE)rtlExitUserThread, - NULL, - &threadHandle, - NULL - ))) - { - goto CleanupExit; - } - } - else + if (!NT_SUCCESS(status = RtlCreateUserThread( + ProcessHandle, + NULL, + TRUE, + 0, + 0, + 0, + (PUSER_THREAD_START_ROUTINE)rtlExitUserThread, + NULL, + &threadHandle, + NULL + ))) { - if (!(threadHandle = CreateRemoteThread( - ProcessHandle, - NULL, - 0, - (PTHREAD_START_ROUTINE)rtlExitUserThread, - NULL, - CREATE_SUSPENDED, - NULL - ))) - { - status = PhGetLastWin32ErrorAsNtStatus(); - goto CleanupExit; - } + goto CleanupExit; } #ifdef _WIN64 diff --git a/phlib/secdata.c b/phlib/secdata.c index d87f74df6a5e..c4f4706c4f92 100644 --- a/phlib/secdata.c +++ b/phlib/secdata.c @@ -645,13 +645,11 @@ BOOLEAN PhGetAccessEntries( } else if (PhEqualStringZ(Type, L"Process", TRUE)) { - if (WindowsVersion >= WINDOWS_VISTA) - Type = L"Process60"; + Type = L"Process60"; } else if (PhEqualStringZ(Type, L"Thread", TRUE)) { - if (WindowsVersion >= WINDOWS_VISTA) - Type = L"Thread60"; + Type = L"Thread60"; } // Find the specific type. diff --git a/phlib/treenew.c b/phlib/treenew.c index c3e63846612b..6466a00bae9f 100644 --- a/phlib/treenew.c +++ b/phlib/treenew.c @@ -2049,13 +2049,13 @@ VOID PhTnpUpdateTextMetrics( } else { - if (WindowsVersion >= WINDOWS_VISTA && !(Context->Style & TN_STYLE_THIN_ROWS)) + if (!(Context->Style & TN_STYLE_THIN_ROWS)) Context->RowHeight += 1; // HACK } Context->RowHeight += 1; // HACK - if (WindowsVersion >= WINDOWS_VISTA && !(Context->Style & TN_STYLE_THIN_ROWS)) + if (!(Context->Style & TN_STYLE_THIN_ROWS)) Context->RowHeight += 2; // HACK } diff --git a/phlib/util.c b/phlib/util.c index 7e84cbb10dad..27ce988d2135 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -41,9 +41,6 @@ #include "sha.h" #include "sha256.h" -// We may want to change this for debugging purposes. -#define PHP_USE_IFILEDIALOG (WINDOWS_HAS_IFILEDIALOG) - typedef BOOLEAN (NTAPI *_WinStationQueryInformationW)( _In_opt_ HANDLE ServerHandle, _In_ ULONG LogonId, @@ -2849,15 +2846,8 @@ NTSTATUS PhCreateProcessAsUser( // Check if this is a service logon. if (PhEqualStringZ(Information->DomainName, L"NT AUTHORITY", TRUE)) { - if (PhEqualStringZ(Information->UserName, L"SYSTEM", TRUE)) - { - if (WindowsVersion >= WINDOWS_VISTA) - logonType = LOGON32_LOGON_SERVICE; - else - logonType = LOGON32_LOGON_NEW_CREDENTIALS; // HACK - } - - if (PhEqualStringZ(Information->UserName, L"LOCAL SERVICE", TRUE) || + if (PhEqualStringZ(Information->UserName, L"SYSTEM", TRUE) || + PhEqualStringZ(Information->UserName, L"LOCAL SERVICE", TRUE) || PhEqualStringZ(Information->UserName, L"NETWORK SERVICE", TRUE)) { logonType = LOGON32_LOGON_SERVICE; @@ -3154,7 +3144,6 @@ NTSTATUS PhFilterTokenForLimitedUser( return status; // Set the integrity level to Low if we're on Vista and above. - if (WINDOWS_HAS_UAC) { lowMandatoryLevelSid = (PSID)lowMandatoryLevelSidBuffer; RtlInitializeSid(lowMandatoryLevelSid, &mandatoryLabelAuthority, 1); @@ -3287,7 +3276,7 @@ BOOLEAN PhShellExecuteEx( info.nShow = ShowWindowType; info.hwnd = hWnd; - if ((Flags & PH_SHELL_EXECUTE_ADMIN) && WINDOWS_HAS_UAC) + if (Flags & PH_SHELL_EXECUTE_ADMIN) info.lpVerb = L"runas"; if (ShellExecuteEx(&info)) @@ -3418,11 +3407,7 @@ PPH_STRING PhExpandKeyName( if (Computer) { - if (WindowsVersion >= WINDOWS_VISTA) - tempString = PhConcatStrings2(L"Computer\\", keyName->Buffer); - else - tempString = PhConcatStrings2(L"My Computer\\", keyName->Buffer); - + tempString = PhConcatStrings2(L"Computer\\", keyName->Buffer); PhDereferenceObject(keyName); keyName = tempString; } @@ -3733,31 +3718,21 @@ PVOID PhCreateOpenFileDialog( VOID ) { - OPENFILENAME *ofn; - PVOID ofnFileDialog; + IFileDialog *fileDialog; - if (PHP_USE_IFILEDIALOG) + if (SUCCEEDED(CoCreateInstance( + &CLSID_FileOpenDialog, + NULL, + CLSCTX_INPROC_SERVER, + &IID_IFileDialog, + &fileDialog + ))) { - IFileDialog *fileDialog; - - if (SUCCEEDED(CoCreateInstance( - &CLSID_FileOpenDialog, - NULL, - CLSCTX_INPROC_SERVER, - &IID_IFileDialog, - &fileDialog - ))) - { - // The default options are fine. - return PhpCreateFileDialog(FALSE, NULL, fileDialog); - } + // The default options are fine. + return PhpCreateFileDialog(FALSE, NULL, fileDialog); } - ofn = PhpCreateOpenFileName(); - ofnFileDialog = PhpCreateFileDialog(FALSE, ofn, NULL); - PhSetFileDialogOptions(ofnFileDialog, PH_FILEDIALOG_PATHMUSTEXIST | PH_FILEDIALOG_FILEMUSTEXIST | PH_FILEDIALOG_STRICTFILETYPES); - - return ofnFileDialog; + return NULL; } /** @@ -3770,31 +3745,21 @@ PVOID PhCreateSaveFileDialog( VOID ) { - OPENFILENAME *ofn; - PVOID ofnFileDialog; + IFileDialog *fileDialog; - if (PHP_USE_IFILEDIALOG) + if (SUCCEEDED(CoCreateInstance( + &CLSID_FileSaveDialog, + NULL, + CLSCTX_INPROC_SERVER, + &IID_IFileDialog, + &fileDialog + ))) { - IFileDialog *fileDialog; - - if (SUCCEEDED(CoCreateInstance( - &CLSID_FileSaveDialog, - NULL, - CLSCTX_INPROC_SERVER, - &IID_IFileDialog, - &fileDialog - ))) - { - // The default options are fine. - return PhpCreateFileDialog(TRUE, NULL, fileDialog); - } + // The default options are fine. + return PhpCreateFileDialog(TRUE, NULL, fileDialog); } - ofn = PhpCreateOpenFileName(); - ofnFileDialog = PhpCreateFileDialog(TRUE, ofn, NULL); - PhSetFileDialogOptions(ofnFileDialog, PH_FILEDIALOG_PATHMUSTEXIST | PH_FILEDIALOG_OVERWRITEPROMPT | PH_FILEDIALOG_STRICTFILETYPES); - - return ofnFileDialog; + return NULL; } /** diff --git a/phlib/verify.c b/phlib/verify.c index 518076a6971f..1118bc495bf8 100644 --- a/phlib/verify.c +++ b/phlib/verify.c @@ -217,11 +217,7 @@ VERIFY_RESULT PhpVerifyFile( if (Information->Flags & PH_VERIFY_PREVENT_NETWORK_ACCESS) { trustData.fdwRevocationChecks = WTD_REVOKE_NONE; - - if (WindowsVersion >= WINDOWS_VISTA) - trustData.dwProvFlags |= WTD_CACHE_ONLY_URL_RETRIEVAL; - else - trustData.dwProvFlags |= WTD_REVOCATION_CHECK_NONE; + trustData.dwProvFlags |= WTD_CACHE_ONLY_URL_RETRIEVAL; } status = WinVerifyTrust_I(NULL, ActionId, &trustData); diff --git a/phlib/workqueue.c b/phlib/workqueue.c index b0f39740670f..2ccc3495e626 100644 --- a/phlib/workqueue.c +++ b/phlib/workqueue.c @@ -267,32 +267,29 @@ VOID PhpUpdateWorkQueueEnvironment( } } - if (WindowsVersion >= WINDOWS_VISTA) + if (CurrentEnvironment->IoPriority != NewEnvironment->IoPriority || NewEnvironment->ForceUpdate) { - if (CurrentEnvironment->IoPriority != NewEnvironment->IoPriority || NewEnvironment->ForceUpdate) - { - IO_PRIORITY_HINT ioPriority; + IO_PRIORITY_HINT ioPriority; - ioPriority = NewEnvironment->IoPriority; + ioPriority = NewEnvironment->IoPriority; - if (NT_SUCCESS(NtSetInformationThread(NtCurrentThread(), ThreadIoPriority, - &ioPriority, sizeof(IO_PRIORITY_HINT)))) - { - CurrentEnvironment->IoPriority = NewEnvironment->IoPriority; - } + if (NT_SUCCESS(NtSetInformationThread(NtCurrentThread(), ThreadIoPriority, + &ioPriority, sizeof(IO_PRIORITY_HINT)))) + { + CurrentEnvironment->IoPriority = NewEnvironment->IoPriority; } + } - if (CurrentEnvironment->PagePriority != NewEnvironment->PagePriority || NewEnvironment->ForceUpdate) - { - ULONG pagePriority; + if (CurrentEnvironment->PagePriority != NewEnvironment->PagePriority || NewEnvironment->ForceUpdate) + { + ULONG pagePriority; - pagePriority = NewEnvironment->PagePriority; + pagePriority = NewEnvironment->PagePriority; - if (NT_SUCCESS(NtSetInformationThread(NtCurrentThread(), ThreadPagePriority, - &pagePriority, sizeof(ULONG)))) - { - CurrentEnvironment->PagePriority = NewEnvironment->PagePriority; - } + if (NT_SUCCESS(NtSetInformationThread(NtCurrentThread(), ThreadPagePriority, + &pagePriority, sizeof(ULONG)))) + { + CurrentEnvironment->PagePriority = NewEnvironment->PagePriority; } } } From 43ef233feca961170e641bd87d27383cb069f548 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 11 Jun 2017 06:12:34 +1000 Subject: [PATCH 0212/2058] ToolStatus: Remove XP support --- plugins/ToolStatus/filter.c | 2 +- plugins/ToolStatus/toolbar.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/ToolStatus/filter.c b/plugins/ToolStatus/filter.c index 3e89fa21b0d3..4a20fa9d329b 100644 --- a/plugins/ToolStatus/filter.c +++ b/plugins/ToolStatus/filter.c @@ -201,7 +201,7 @@ BOOLEAN ProcessTreeFilterCallback( } } - if (WINDOWS_HAS_UAC && processNode->ProcessItem->ElevationType != TokenElevationTypeDefault) + if (processNode->ProcessItem->ElevationType != TokenElevationTypeDefault) { switch (processNode->ProcessItem->ElevationType) { diff --git a/plugins/ToolStatus/toolbar.c b/plugins/ToolStatus/toolbar.c index c7b752460c7b..018cd2b6380f 100644 --- a/plugins/ToolStatus/toolbar.c +++ b/plugins/ToolStatus/toolbar.c @@ -318,7 +318,7 @@ VOID ToolbarLoadSettings( { case PHAPP_ID_HACKER_SHOWDETAILSFORALLPROCESSES: { - if (WINDOWS_HAS_UAC && PhGetOwnTokenAttributes().Elevated) + if (PhGetOwnTokenAttributes().Elevated) { buttonInfo.fsState |= TBSTATE_HIDDEN; } From af3d39c918b95bb6f7bcfec52df15d47481fb17a Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 13 Jun 2017 03:09:50 +1000 Subject: [PATCH 0213/2058] [Setup] Fix minimum OS version --- .../CustomSetupTool/CustomSetupTool.vcxproj | 3 +- .../CustomSetupTool/CustomSetupTool/appsup.c | 41 +++++++++++-------- 2 files changed, 26 insertions(+), 18 deletions(-) diff --git a/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj b/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj index 888e8bbaa14f..02cea7f702b1 100644 --- a/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj +++ b/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj @@ -68,6 +68,7 @@ $(SolutionDir)..\..\phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) Windows RequireAdministrator + 6.01 _UNICODE;UNICODE;%(PreprocessorDefinitions);$(ExternalCompilerOptions) @@ -97,7 +98,7 @@ uxtheme.lib;winhttp.lib;phlib.lib;ntdll.lib;%(AdditionalDependencies) $(SolutionDir)..\..\phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) Windows - 5.01 + 6.01 true RequireAdministrator diff --git a/tools/CustomSetupTool/CustomSetupTool/appsup.c b/tools/CustomSetupTool/CustomSetupTool/appsup.c index 5e5d174eb8b7..aeaf18ed86e6 100644 --- a/tools/CustomSetupTool/CustomSetupTool/appsup.c +++ b/tools/CustomSetupTool/CustomSetupTool/appsup.c @@ -470,31 +470,31 @@ PPH_STRING GetProcessHackerInstallPath(VOID) return installPath; } -BOOLEAN ShutdownProcessHacker(VOID) +static BOOLEAN NTAPI PhpPreviousInstancesCallback( + _In_ PPH_STRINGREF Name, + _In_ PPH_STRINGREF TypeName, + _In_opt_ PVOID Context + ) { - HWND windowHandle; - HANDLE processHandle; - ULONG processID = 0; - - while (windowHandle = FindWindow(L"ProcessHacker", NULL)) + ULONG64 processId64; + PH_STRINGREF firstPart; + PH_STRINGREF secondPart; + + if ( + PhStartsWithStringRef2(Name, L"PhMutant_", TRUE) && + PhSplitStringRefAtChar(Name, L'_', &firstPart, &secondPart) && + PhStringToInteger64(&secondPart, 10, &processId64) + ) { - GetWindowThreadProcessId(windowHandle, &processID); + HANDLE processHandle; if (NT_SUCCESS(PhOpenProcess( &processHandle, SYNCHRONIZE | PROCESS_TERMINATE, - ULongToHandle(processID) + ULongToHandle((ULONG)processId64) ))) { - PostMessage(windowHandle, WM_QUIT, 0, 0); - - // Wait for process exit. - if (WaitForSingleObject(processHandle, 10 * 1000) != WAIT_OBJECT_0) - { - // Timed out, kill the process. - NtTerminateProcess(processHandle, 1); - } - + NtTerminateProcess(processHandle, 1); NtClose(processHandle); } } @@ -502,6 +502,13 @@ BOOLEAN ShutdownProcessHacker(VOID) return TRUE; } +BOOLEAN ShutdownProcessHacker(VOID) +{ + PhEnumDirectoryObjects(PhGetNamespaceHandle(), PhpPreviousInstancesCallback, NULL); + + return TRUE; +} + BOOLEAN CreateDirectoryPath(_In_ PWSTR DirPath) { BOOLEAN success = FALSE; From 9927969e2dbbc7a07a07bc782c6388433678ecc7 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 13 Jun 2017 03:12:34 +1000 Subject: [PATCH 0214/2058] Plugins: Remove legacy Vista support --- plugins/ExtendedServices/main.c | 4 ++-- plugins/ExtendedServices/recovery.c | 14 +++++--------- plugins/ExtraPlugins/setup/updater.c | 1 - plugins/NetworkTools/update.c | 2 -- plugins/Updater/updater.c | 2 -- plugins/WindowExplorer/hook.c | 1 - 6 files changed, 7 insertions(+), 17 deletions(-) diff --git a/plugins/ExtendedServices/main.c b/plugins/ExtendedServices/main.c index c36e3b8f38f7..af0e8f012988 100644 --- a/plugins/ExtendedServices/main.c +++ b/plugins/ExtendedServices/main.c @@ -348,7 +348,7 @@ NTAPI ServicePropertiesInitializingCallback( } // Other - if (WindowsVersion >= WINDOWS_7 && objectProperties->NumberOfPages < objectProperties->MaximumNumberOfPages) + if (objectProperties->NumberOfPages < objectProperties->MaximumNumberOfPages) { memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); propSheetPage.dwSize = sizeof(PROPSHEETPAGE); @@ -362,7 +362,7 @@ NTAPI ServicePropertiesInitializingCallback( } // Other - if (WindowsVersion >= WINDOWS_VISTA && objectProperties->NumberOfPages < objectProperties->MaximumNumberOfPages) + if (objectProperties->NumberOfPages < objectProperties->MaximumNumberOfPages) { memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); propSheetPage.dwSize = sizeof(PROPSHEETPAGE); diff --git a/plugins/ExtendedServices/recovery.c b/plugins/ExtendedServices/recovery.c index 91f42768cefe..47a55520c2f0 100644 --- a/plugins/ExtendedServices/recovery.c +++ b/plugins/ExtendedServices/recovery.c @@ -213,8 +213,7 @@ NTSTATUS EspLoadRecoveryInfo( // Enable actions for stops with errors - // This is Vista and above only. - if (WindowsVersion >= WINDOWS_VISTA && QueryServiceConfig2( + if (QueryServiceConfig2( serviceHandle, SERVICE_CONFIG_FAILURE_ACTIONS_FLAG, (BYTE *)&failureActionsFlag, @@ -319,13 +318,10 @@ INT_PTR CALLBACK EspServiceRecoveryDlgProc( else if (!NT_SUCCESS(status)) { SetDlgItemText(hwndDlg, IDC_RESETFAILCOUNT, L"0"); - - if (WindowsVersion >= WINDOWS_VISTA) - { - context->EnableFlagCheckBox = TRUE; - EnableWindow(GetDlgItem(hwndDlg, IDC_ENABLEFORERRORSTOPS), TRUE); - } - + + context->EnableFlagCheckBox = TRUE; + EnableWindow(GetDlgItem(hwndDlg, IDC_ENABLEFORERRORSTOPS), TRUE); + PhShowWarning(hwndDlg, L"Unable to query service recovery information: %s", ((PPH_STRING)PH_AUTO(PhGetNtMessage(status)))->Buffer); } diff --git a/plugins/ExtraPlugins/setup/updater.c b/plugins/ExtraPlugins/setup/updater.c index 19bd41c7b45c..f8fdf0111cad 100644 --- a/plugins/ExtraPlugins/setup/updater.c +++ b/plugins/ExtraPlugins/setup/updater.c @@ -451,7 +451,6 @@ NTSTATUS UpdateDownloadThread( goto CleanupExit; } - if (WindowsVersion >= WINDOWS_7) { ULONG keepAlive = WINHTTP_DISABLE_KEEP_ALIVE; WinHttpSetOption(httpRequestHandle, WINHTTP_OPTION_DISABLE_FEATURE, &keepAlive, sizeof(ULONG)); diff --git a/plugins/NetworkTools/update.c b/plugins/NetworkTools/update.c index 579feb6015cc..7e9cd5e07cc2 100644 --- a/plugins/NetworkTools/update.c +++ b/plugins/NetworkTools/update.c @@ -198,7 +198,6 @@ PPH_STRING QueryFwLinkUrl( ); } - if (WindowsVersion >= WINDOWS_7) { ULONG option = WINHTTP_DISABLE_REDIRECTS; WinHttpSetOption(httpRequestHandle, WINHTTP_OPTION_DISABLE_FEATURE, &option, sizeof(ULONG)); @@ -428,7 +427,6 @@ NTSTATUS GeoIPUpdateThread( goto CleanupExit; } - if (WindowsVersion >= WINDOWS_7) { ULONG option = WINHTTP_DISABLE_KEEP_ALIVE; WinHttpSetOption(httpRequestHandle, WINHTTP_OPTION_DISABLE_FEATURE, &option, sizeof(ULONG)); diff --git a/plugins/Updater/updater.c b/plugins/Updater/updater.c index 65ffb77af54e..29b737f7c63d 100644 --- a/plugins/Updater/updater.c +++ b/plugins/Updater/updater.c @@ -364,7 +364,6 @@ BOOLEAN QueryUpdateData( goto CleanupExit; } - if (WindowsVersion >= WINDOWS_7) { ULONG keepAlive = WINHTTP_DISABLE_KEEP_ALIVE; WinHttpSetOption(httpRequestHandle, WINHTTP_OPTION_DISABLE_FEATURE, &keepAlive, sizeof(ULONG)); @@ -805,7 +804,6 @@ NTSTATUS UpdateDownloadThread( goto CleanupExit; } - if (WindowsVersion >= WINDOWS_7) { ULONG keepAlive = WINHTTP_DISABLE_KEEP_ALIVE; WinHttpSetOption(httpRequestHandle, WINHTTP_OPTION_DISABLE_FEATURE, &keepAlive, sizeof(ULONG)); diff --git a/plugins/WindowExplorer/hook.c b/plugins/WindowExplorer/hook.c index abecae533993..3bd85bd6fa62 100644 --- a/plugins/WindowExplorer/hook.c +++ b/plugins/WindowExplorer/hook.c @@ -193,7 +193,6 @@ BOOLEAN WepCreateServerObjects( } // If mandatory labels are supported, set it to the lowest possible level. - if (WE_WindowsVersion >= WINDOWS_VISTA) { static SID_IDENTIFIER_AUTHORITY mandatoryLabelAuthority = SECURITY_MANDATORY_LABEL_AUTHORITY; From 4e89d8f121481fc9f51519b8f223aa0dbfe1e51a Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 13 Jun 2017 03:19:25 +1000 Subject: [PATCH 0215/2058] ExtendedTools: Fix unloaded modules window flicker --- plugins/ExtendedTools/unldll.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/ExtendedTools/unldll.c b/plugins/ExtendedTools/unldll.c index 8a0f5a597649..f7643e977197 100644 --- a/plugins/ExtendedTools/unldll.c +++ b/plugins/ExtendedTools/unldll.c @@ -78,7 +78,6 @@ BOOLEAN EtpRefreshUnloadedDlls( HWND lvHandle; lvHandle = GetDlgItem(hwndDlg, IDC_LIST); - ListView_DeleteAllItems(lvHandle); RtlGetUnloadEventTraceEx(&elementSize, &elementCount, &eventTrace); @@ -145,6 +144,8 @@ BOOLEAN EtpRefreshUnloadedDlls( ExtendedListView_SetRedraw(lvHandle, FALSE); + ListView_DeleteAllItems(lvHandle); + for (i = 0; i < capturedElementCount; i++) { PRTL_UNLOAD_EVENT_TRACE rtlEvent = currentEvent; From 8cdd6d81721e240458d15d2918200ab894735563 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 14 Jun 2017 09:06:46 +1000 Subject: [PATCH 0216/2058] Remove legacy Vista support --- ProcessHacker/ProcessHacker.rc | 1 - ProcessHacker/actions.c | 20 +----- ProcessHacker/chproc.c | 8 +-- ProcessHacker/hndlprv.c | 105 +++++++------------------------ ProcessHacker/main.c | 3 - ProcessHacker/mainwnd.c | 12 ---- ProcessHacker/memprv.c | 7 +-- ProcessHacker/mwpgnet.c | 6 -- ProcessHacker/mwpgproc.c | 2 +- ProcessHacker/netprv.c | 13 ---- ProcessHacker/options.c | 13 +--- ProcessHacker/procprv.c | 49 +++------------ ProcessHacker/proctree.c | 112 ++++++++++++--------------------- ProcessHacker/prpgstat.c | 41 +++++------- ProcessHacker/resource.h | 1 - ProcessHacker/runas.c | 14 +---- ProcessHacker/syssccpu.c | 18 +++--- phlib/global.c | 17 +---- phlib/hndlinfo.c | 38 +++-------- phlib/include/phconfig.h | 3 - phlib/native.c | 41 +++++------- 21 files changed, 124 insertions(+), 400 deletions(-) diff --git a/ProcessHacker/ProcessHacker.rc b/ProcessHacker/ProcessHacker.rc index 3566b045ab4e..d08e9ed52974 100644 --- a/ProcessHacker/ProcessHacker.rc +++ b/ProcessHacker/ProcessHacker.rc @@ -383,7 +383,6 @@ BEGIN BEGIN MENUITEM "&Go to process\aEnter", ID_NETWORK_GOTOPROCESS MENUITEM "Go to service", ID_NETWORK_GOTOSERVICE - MENUITEM "View &stack", ID_NETWORK_VIEWSTACK MENUITEM "C&lose", ID_NETWORK_CLOSE MENUITEM SEPARATOR MENUITEM "&Copy\aCtrl+C", ID_NETWORK_COPY diff --git a/ProcessHacker/actions.c b/ProcessHacker/actions.c index 41b523b581cc..b822fd9f75a8 100644 --- a/ProcessHacker/actions.c +++ b/ProcessHacker/actions.c @@ -726,7 +726,6 @@ static BOOLEAN PhpIsDangerousProcess( ) { NTSTATUS status; - HANDLE processHandle; PPH_STRING fileName; PPH_STRING systemDirectory; ULONG i; @@ -734,24 +733,7 @@ static BOOLEAN PhpIsDangerousProcess( if (ProcessId == SYSTEM_PROCESS_ID) return TRUE; - if (WINDOWS_HAS_IMAGE_FILE_NAME_BY_PROCESS_ID) - { - status = PhGetProcessImageFileNameByProcessId(ProcessId, &fileName); - } - else - { - if (!NT_SUCCESS(status = PhOpenProcess( - &processHandle, - ProcessQueryAccess, - ProcessId - ))) - return FALSE; - - status = PhGetProcessImageFileName(processHandle, &fileName); - NtClose(processHandle); - } - - if (!NT_SUCCESS(status)) + if (!NT_SUCCESS(status = PhGetProcessImageFileNameByProcessId(ProcessId, &fileName))) return FALSE; PhMoveReference(&fileName, PhGetFileName(fileName)); diff --git a/ProcessHacker/chproc.c b/ProcessHacker/chproc.c index 4b83a8f176eb..a39911ba828e 100644 --- a/ProcessHacker/chproc.c +++ b/ProcessHacker/chproc.c @@ -120,9 +120,6 @@ static VOID PhpRefreshProcessList( HANDLE tokenHandle; PTOKEN_USER user; - if (!WINDOWS_HAS_IMAGE_FILE_NAME_BY_PROCESS_ID && process->UniqueProcessId != SYSTEM_PROCESS_ID) - PhGetProcessImageFileName(processHandle, &fileName); - if (NT_SUCCESS(PhOpenProcessToken(processHandle, TOKEN_QUERY, &tokenHandle))) { if (NT_SUCCESS(PhGetTokenUser(tokenHandle, &user))) @@ -140,11 +137,10 @@ static VOID PhpRefreshProcessList( if (process->UniqueProcessId == SYSTEM_IDLE_PROCESS_ID && !userName && PhLocalSystemName) PhSetReference(&userName, PhLocalSystemName); - if (WINDOWS_HAS_IMAGE_FILE_NAME_BY_PROCESS_ID && process->UniqueProcessId != SYSTEM_PROCESS_ID) - PhGetProcessImageFileNameByProcessId(process->UniqueProcessId, &fileName); - if (process->UniqueProcessId == SYSTEM_PROCESS_ID) fileName = PhGetKernelFileName(); + else + PhGetProcessImageFileNameByProcessId(process->UniqueProcessId, &fileName); if (fileName) PhMoveReference(&fileName, PhGetFileName(fileName)); diff --git a/ProcessHacker/hndlprv.c b/ProcessHacker/hndlprv.c index 6a85795f1c24..8b7707c0f154 100644 --- a/ProcessHacker/hndlprv.c +++ b/ProcessHacker/hndlprv.c @@ -315,105 +315,44 @@ NTSTATUS PhEnumHandlesGeneric( // Enumerate handles using KProcessHacker. Unlike with NtQuerySystemInformation, // this only enumerates handles for a single process and saves a lot of processing. - if (NT_SUCCESS(status = KphEnumerateProcessHandles2(ProcessHandle, &handles))) - { - convertedHandles = PhAllocate( - FIELD_OFFSET(SYSTEM_HANDLE_INFORMATION_EX, Handles) + - sizeof(SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX) * handles->HandleCount - ); + if (!NT_SUCCESS(status = KphEnumerateProcessHandles2(ProcessHandle, &handles))) + return status; - convertedHandles->NumberOfHandles = handles->HandleCount; + convertedHandles = PhAllocate( + FIELD_OFFSET(SYSTEM_HANDLE_INFORMATION_EX, Handles) + + sizeof(SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX) * handles->HandleCount + ); - for (i = 0; i < handles->HandleCount; i++) - { - convertedHandles->Handles[i].Object = handles->Handles[i].Object; - convertedHandles->Handles[i].UniqueProcessId = (ULONG_PTR)ProcessId; - convertedHandles->Handles[i].HandleValue = (ULONG_PTR)handles->Handles[i].Handle; - convertedHandles->Handles[i].GrantedAccess = (ULONG)handles->Handles[i].GrantedAccess; - convertedHandles->Handles[i].CreatorBackTraceIndex = 0; - convertedHandles->Handles[i].ObjectTypeIndex = handles->Handles[i].ObjectTypeIndex; - convertedHandles->Handles[i].HandleAttributes = handles->Handles[i].HandleAttributes; - } + convertedHandles->NumberOfHandles = handles->HandleCount; - PhFree(handles); + for (i = 0; i < handles->HandleCount; i++) + { + convertedHandles->Handles[i].Object = handles->Handles[i].Object; + convertedHandles->Handles[i].UniqueProcessId = (ULONG_PTR)ProcessId; + convertedHandles->Handles[i].HandleValue = (ULONG_PTR)handles->Handles[i].Handle; + convertedHandles->Handles[i].GrantedAccess = (ULONG)handles->Handles[i].GrantedAccess; + convertedHandles->Handles[i].CreatorBackTraceIndex = 0; + convertedHandles->Handles[i].ObjectTypeIndex = handles->Handles[i].ObjectTypeIndex; + convertedHandles->Handles[i].HandleAttributes = handles->Handles[i].HandleAttributes; + } - *Handles = convertedHandles; - *FilterNeeded = FALSE; + PhFree(handles); - return status; - } + *Handles = convertedHandles; + *FilterNeeded = FALSE; } - - if (WindowsVersion >= WINDOWS_XP) + else { PSYSTEM_HANDLE_INFORMATION_EX handles; - // Enumerate handles using the new method; no conversion - // necessary. - if (!NT_SUCCESS(status = PhEnumHandlesEx(&handles))) return status; *Handles = handles; *FilterNeeded = TRUE; } - else - { - PSYSTEM_HANDLE_INFORMATION handles; - PSYSTEM_HANDLE_INFORMATION_EX convertedHandles; - ULONG count; - ULONG allocatedCount; - ULONG i; - - // Enumerate handles using the old info class and convert - // the relevant entries to the new format. - - if (!NT_SUCCESS(status = PhEnumHandles(&handles))) - return status; - - count = 0; - allocatedCount = 100; - - convertedHandles = PhAllocate( - FIELD_OFFSET(SYSTEM_HANDLE_INFORMATION_EX, Handles) + - sizeof(SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX) * allocatedCount - ); - - for (i = 0; i < handles->NumberOfHandles; i++) - { - if ((HANDLE)handles->Handles[i].UniqueProcessId != ProcessId) - continue; - - if (count == allocatedCount) - { - allocatedCount *= 2; - convertedHandles = PhReAllocate( - convertedHandles, - FIELD_OFFSET(SYSTEM_HANDLE_INFORMATION_EX, Handles) + - sizeof(SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX) * allocatedCount - ); - } - - convertedHandles->Handles[count].Object = handles->Handles[i].Object; - convertedHandles->Handles[count].UniqueProcessId = (ULONG_PTR)handles->Handles[i].UniqueProcessId; - convertedHandles->Handles[count].HandleValue = (ULONG_PTR)handles->Handles[i].HandleValue; - convertedHandles->Handles[count].GrantedAccess = handles->Handles[i].GrantedAccess; - convertedHandles->Handles[count].CreatorBackTraceIndex = handles->Handles[i].CreatorBackTraceIndex; - convertedHandles->Handles[count].ObjectTypeIndex = handles->Handles[i].ObjectTypeIndex; - convertedHandles->Handles[count].HandleAttributes = (ULONG)handles->Handles[i].HandleAttributes; - - count++; - } - - convertedHandles->NumberOfHandles = count; - - PhFree(handles); - - *Handles = convertedHandles; - *FilterNeeded = FALSE; - } - return STATUS_SUCCESS; + return status; } NTSTATUS PhpCreateHandleItemFunction( diff --git a/ProcessHacker/main.c b/ProcessHacker/main.c index d13513da6754..d972aac56428 100644 --- a/ProcessHacker/main.c +++ b/ProcessHacker/main.c @@ -592,9 +592,6 @@ VOID PhInitializeKph( PUCHAR signature; ULONG signatureSize; - if (WindowsVersion < WINDOWS_7) - return; - kprocesshackerFileName = PhConcatStringRef2(&PhApplicationDirectory->sr, &kprocesshacker); processhackerSigFileName = PhConcatStringRef2(&PhApplicationDirectory->sr, &processhackerSig); diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index bd7355eb1b69..cb6592fbca56 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -1520,18 +1520,6 @@ VOID PhMwpOnCommand( } } break; - case ID_NETWORK_VIEWSTACK: - { - PPH_NETWORK_ITEM networkItem = PhGetSelectedNetworkItem(); - - if (networkItem) - { - PhReferenceObject(networkItem); - PhShowNetworkStackDialog(PhMainWndHandle, networkItem); - PhDereferenceObject(networkItem); - } - } - break; case ID_NETWORK_CLOSE: { PPH_NETWORK_ITEM *networkItems; diff --git a/ProcessHacker/memprv.c b/ProcessHacker/memprv.c index 14b155de1f6d..0cd374fce86d 100644 --- a/ProcessHacker/memprv.c +++ b/ProcessHacker/memprv.c @@ -780,12 +780,7 @@ NTSTATUS PhQueryMemoryItemList( PhpUpdateMemoryRegionTypes(List, processHandle); if (Flags & PH_QUERY_MEMORY_WS_COUNTERS) - { - if (WindowsVersion >= WINDOWS_SERVER_2003) - PhpUpdateMemoryWsCounters(List, processHandle); - else - PhpUpdateMemoryWsCountersOld(List, processHandle); - } + PhpUpdateMemoryWsCounters(List, processHandle); NtClose(processHandle); diff --git a/ProcessHacker/mwpgnet.c b/ProcessHacker/mwpgnet.c index c8fa1d5cd18f..68832d0a5438 100644 --- a/ProcessHacker/mwpgnet.c +++ b/ProcessHacker/mwpgnet.c @@ -221,12 +221,6 @@ VOID PhMwpInitializeNetworkMenu( PhEnableEMenuItem(Menu, ID_NETWORK_COPY, TRUE); } - if (WindowsVersion >= WINDOWS_VISTA) - { - if (item = PhFindEMenuItem(Menu, 0, NULL, ID_NETWORK_VIEWSTACK)) - PhDestroyEMenuItem(item); - } - // Go to Service if (NumberOfNetworkItems != 1 || !NetworkItems[0]->OwnerName) { diff --git a/ProcessHacker/mwpgproc.c b/ProcessHacker/mwpgproc.c index cce1265a13b7..619dbe6c12ee 100644 --- a/ProcessHacker/mwpgproc.c +++ b/ProcessHacker/mwpgproc.c @@ -123,7 +123,7 @@ BOOLEAN PhMwpProcessesPageCallback( if (menuItem = PhFindEMenuItem(menu, 0, NULL, ID_VIEW_SHOWCPUBELOW001)) { - if (WindowsVersion >= WINDOWS_7 && PhEnableCycleCpuUsage) + if (PhEnableCycleCpuUsage) { if (PhCsShowCpuBelow001) menuItem->Flags |= PH_EMENU_CHECKED; diff --git a/ProcessHacker/netprv.c b/ProcessHacker/netprv.c index d3cc1187db6a..48f5b77c72f9 100644 --- a/ProcessHacker/netprv.c +++ b/ProcessHacker/netprv.c @@ -814,19 +814,6 @@ BOOLEAN PhGetNetworkConnections( tableSize = 0; GetExtendedTcpTable(NULL, &tableSize, FALSE, AF_INET6, TCP_TABLE_OWNER_MODULE_ALL, 0); - // Note: On Windows XP, GetExtendedTcpTable had a bug where it calculated the required buffer size - // for IPv6 TCP_TABLE_OWNER_MODULE_ALL requests incorrectly, causing it to return the wrong size - // and overrun the provided buffer instead of returning an error. The size should be: - // = FIELD_OFFSET(MIB_TCP6TABLE_OWNER_MODULE, table) + sizeof(MIB_TCP6ROW_OWNER_MODULE) * (number of entries) - // However, the function calculated it as: - // = FIELD_OFFSET(MIB_TCP6TABLE_OWNER_MODULE, table) + sizeof(MIB_TCP6ROW_OWNER_PID) * (number of entries) - // A workaround is implemented below. - if (WindowsVersion <= WINDOWS_XP && tableSize >= (ULONG)FIELD_OFFSET(MIB_TCP6TABLE_OWNER_MODULE, table)) // make sure we don't wrap around - { - tableSize = FIELD_OFFSET(MIB_TCP6TABLE_OWNER_MODULE, table) + - (tableSize - FIELD_OFFSET(MIB_TCP6TABLE_OWNER_MODULE, table)) / sizeof(MIB_TCP6ROW_OWNER_PID) * sizeof(MIB_TCP6ROW_OWNER_MODULE); - } - table = PhAllocate(tableSize); if (GetExtendedTcpTable(table, &tableSize, FALSE, AF_INET6, TCP_TABLE_OWNER_MODULE_ALL, 0) == 0) diff --git a/ProcessHacker/options.c b/ProcessHacker/options.c index c93fcbef6a06..988c32d5a3cb 100644 --- a/ProcessHacker/options.c +++ b/ProcessHacker/options.c @@ -680,9 +680,7 @@ VOID PhpAdvancedPageLoad( SetDlgItemCheckForSetting(hwndDlg, IDC_ENABLENETWORKRESOLVE, L"EnableNetworkResolve"); SetDlgItemCheckForSetting(hwndDlg, IDC_PROPAGATECPUUSAGE, L"PropagateCpuUsage"); SetDlgItemCheckForSetting(hwndDlg, IDC_ENABLEINSTANTTOOLTIPS, L"EnableInstantTooltips"); - - if (WindowsVersion >= WINDOWS_7) - SetDlgItemCheckForSetting(hwndDlg, IDC_ENABLECYCLECPUUSAGE, L"EnableCycleCpuUsage"); + SetDlgItemCheckForSetting(hwndDlg, IDC_ENABLECYCLECPUUSAGE, L"EnableCycleCpuUsage"); SetDlgItemInt(hwndDlg, IDC_SAMPLECOUNT, PhGetIntegerSetting(L"SampleCount"), FALSE); SetDlgItemCheckForSetting(hwndDlg, IDC_SAMPLECOUNTAUTOMATIC, L"SampleCountAutomatic"); @@ -762,9 +760,7 @@ VOID PhpAdvancedPageSave( SetSettingForDlgItemCheckRestartRequired(hwndDlg, IDC_ENABLENETWORKRESOLVE, L"EnableNetworkResolve"); SetSettingForDlgItemCheck(hwndDlg, IDC_PROPAGATECPUUSAGE, L"PropagateCpuUsage"); SetSettingForDlgItemCheck(hwndDlg, IDC_ENABLEINSTANTTOOLTIPS, L"EnableInstantTooltips"); - - if (WindowsVersion >= WINDOWS_7) - SetSettingForDlgItemCheckRestartRequired(hwndDlg, IDC_ENABLECYCLECPUUSAGE, L"EnableCycleCpuUsage"); + SetSettingForDlgItemCheckRestartRequired(hwndDlg, IDC_ENABLECYCLECPUUSAGE, L"EnableCycleCpuUsage"); sampleCount = GetDlgItemInt(hwndDlg, IDC_SAMPLECOUNT, NULL, FALSE); SetSettingForDlgItemCheckRestartRequired(hwndDlg, IDC_SAMPLECOUNTAUTOMATIC, L"SampleCountAutomatic"); @@ -874,11 +870,6 @@ INT_PTR CALLBACK PhpOptionsAdvancedDlgProc( EnableWindow(GetDlgItem(hwndDlg, IDC_SAMPLECOUNT), FALSE); EnableWindow(GetDlgItem(hwndDlg, IDC_SAMPLECOUNTAUTOMATIC), FALSE); } - else - { - if (WindowsVersion < WINDOWS_7) - EnableWindow(GetDlgItem(hwndDlg, IDC_ENABLECYCLECPUUSAGE), FALSE); // cycle-based CPU usage not available before Windows 7 - } } break; case WM_DESTROY: diff --git a/ProcessHacker/procprv.c b/ProcessHacker/procprv.c index 9f21779c5f5b..ebbff15f1ab8 100644 --- a/ProcessHacker/procprv.c +++ b/ProcessHacker/procprv.c @@ -1151,7 +1151,7 @@ VOID PhpProcessQueryStage1( } // Console host process - if (processHandleLimited && WINDOWS_HAS_CONSOLE_HOST) + if (processHandleLimited) { PhGetProcessConsoleHostProcessId(processHandleLimited, &Data->ConsoleHostProcessId); } @@ -1423,35 +1423,6 @@ VOID PhpFillProcessItem( } } - if (!ProcessItem->UserName && WindowsVersion <= WINDOWS_XP) - { - // In some cases we can get the user SID using WTS (only works on XP and below). - - if (!PhpTsProcesses) - { - WinStationGetAllProcesses( - NULL, - 0, - &PhpTsNumberOfProcesses, - &PhpTsProcesses - ); - } - - if (PhpTsProcesses) - { - ULONG i; - - for (i = 0; i < PhpTsNumberOfProcesses; i++) - { - if (UlongToHandle(PhpTsProcesses[i].pTsProcessInfo->UniqueProcessId) == ProcessItem->ProcessId) - { - ProcessItem->UserName = PhpGetSidFullNameCached(PhpTsProcesses[i].pSid); - break; - } - } - } - } - NtClose(processHandle); } @@ -1951,8 +1922,6 @@ VOID PhProcessProviderUpdate( PSYSTEM_PROCESS_INFORMATION process; ULONG bucketIndex; - BOOLEAN isCycleCpuUsageEnabled = FALSE; - ULONG64 sysTotalTime; // total time for this update period ULONG64 sysTotalCycleTime = 0; // total cycle time for this update period ULONG64 sysIdleCycleTime = 0; // total idle cycle time for this update period @@ -1974,8 +1943,6 @@ VOID PhProcessProviderUpdate( PhPurgeProcessRecords(); } - isCycleCpuUsageEnabled = WindowsVersion >= WINDOWS_7 && PhEnableCycleCpuUsage; - if (!PhProcessStatisticsInitialized) { PhpInitializeProcessStatistics(); @@ -1984,7 +1951,7 @@ VOID PhProcessProviderUpdate( PhpUpdatePerfInformation(); - if (isCycleCpuUsageEnabled) + if (PhEnableCycleCpuUsage) { PhpUpdateCpuInformation(FALSE, &sysTotalTime); PhpUpdateCpuCycleInformation(&sysIdleCycleTime); @@ -2053,7 +2020,7 @@ VOID PhProcessProviderUpdate( process->UniqueProcessKey = (ULONG_PTR)pidBuckets[bucketIndex]; pidBuckets[bucketIndex] = process; - if (isCycleCpuUsageEnabled) + if (PhEnableCycleCpuUsage) { PPH_PROCESS_ITEM processItem; @@ -2069,7 +2036,7 @@ VOID PhProcessProviderUpdate( // On Windows 7 the two fake processes are merged into "Interrupts" since we can only get cycle // time information both DPCs and Interrupts combined. - if (isCycleCpuUsageEnabled) + if (PhEnableCycleCpuUsage) { PhInterruptsProcessInformation.KernelTime.QuadPart = PhCpuTotals.DpcTime.QuadPart + PhCpuTotals.InterruptTime.QuadPart; PhInterruptsProcessInformation.CycleTime = PhCpuSystemCycleDelta.Value; @@ -2131,7 +2098,7 @@ VOID PhProcessProviderUpdate( exitTime = times.ExitTime; } - if (isCycleCpuUsageEnabled) + if (PhEnableCycleCpuUsage) { if (NT_SUCCESS(PhGetProcessCycleTime(processItem->QueryHandle, &finalCycleTime))) { @@ -2324,7 +2291,7 @@ VOID PhProcessProviderUpdate( if (InterlockedExchange(&processItem->JustProcessed, 0) != 0) modified = TRUE; - if (isCycleCpuUsageEnabled) + if (PhEnableCycleCpuUsage) { FLOAT totalDelta; @@ -2464,7 +2431,7 @@ VOID PhProcessProviderUpdate( if (process == NULL) { - if (isCycleCpuUsageEnabled) + if (PhEnableCycleCpuUsage) process = &PhInterruptsProcessInformation; else process = &PhDpcsProcessInformation; @@ -2489,7 +2456,7 @@ VOID PhProcessProviderUpdate( // I/O "deltas" will be huge because they are currently the raw accumulated values. if (runCount != 0) { - if (isCycleCpuUsageEnabled) + if (PhEnableCycleCpuUsage) PhpUpdateCpuCycleUsageInformation(sysTotalCycleTime, sysIdleCycleTime); PhpUpdateSystemHistory(); diff --git a/ProcessHacker/proctree.c b/ProcessHacker/proctree.c index 10d78dc82b86..7a9a18156528 100644 --- a/ProcessHacker/proctree.c +++ b/ProcessHacker/proctree.c @@ -427,7 +427,7 @@ PPH_PROCESS_NODE PhAddProcessNode( } } - if (WindowsVersion >= WINDOWS_7 && PhEnableCycleCpuUsage && ProcessItem->ProcessId == INTERRUPTS_PROCESS_ID) + if (PhEnableCycleCpuUsage && ProcessItem->ProcessId == INTERRUPTS_PROCESS_ID) PhInitializeStringRef(&processNode->DescriptionText, L"Interrupts and DPCs"); if (FilterSupport.FilterList) @@ -982,28 +982,25 @@ static VOID PhpUpdateProcessOsContext( { HANDLE processHandle; - if (WindowsVersion >= WINDOWS_7) + if (NT_SUCCESS(PhOpenProcess(&processHandle, ProcessQueryAccess | PROCESS_VM_READ, ProcessNode->ProcessId))) { - if (NT_SUCCESS(PhOpenProcess(&processHandle, ProcessQueryAccess | PROCESS_VM_READ, ProcessNode->ProcessId))) + if (NT_SUCCESS(PhGetProcessSwitchContext(processHandle, &ProcessNode->OsContextGuid))) { - if (NT_SUCCESS(PhGetProcessSwitchContext(processHandle, &ProcessNode->OsContextGuid))) - { - if (memcmp(&ProcessNode->OsContextGuid, &WINTHRESHOLD_CONTEXT_GUID, sizeof(GUID)) == 0) - ProcessNode->OsContextVersion = WINDOWS_10; - else if (memcmp(&ProcessNode->OsContextGuid, &WINBLUE_CONTEXT_GUID, sizeof(GUID)) == 0) - ProcessNode->OsContextVersion = WINDOWS_8_1; - else if (memcmp(&ProcessNode->OsContextGuid, &WIN8_CONTEXT_GUID, sizeof(GUID)) == 0) - ProcessNode->OsContextVersion = WINDOWS_8; - else if (memcmp(&ProcessNode->OsContextGuid, &WIN7_CONTEXT_GUID, sizeof(GUID)) == 0) - ProcessNode->OsContextVersion = WINDOWS_7; - else if (memcmp(&ProcessNode->OsContextGuid, &VISTA_CONTEXT_GUID, sizeof(GUID)) == 0) - ProcessNode->OsContextVersion = WINDOWS_VISTA; - else if (memcmp(&ProcessNode->OsContextGuid, &XP_CONTEXT_GUID, sizeof(GUID)) == 0) - ProcessNode->OsContextVersion = WINDOWS_XP; - } - - NtClose(processHandle); + if (memcmp(&ProcessNode->OsContextGuid, &WINTHRESHOLD_CONTEXT_GUID, sizeof(GUID)) == 0) + ProcessNode->OsContextVersion = WINDOWS_10; + else if (memcmp(&ProcessNode->OsContextGuid, &WINBLUE_CONTEXT_GUID, sizeof(GUID)) == 0) + ProcessNode->OsContextVersion = WINDOWS_8_1; + else if (memcmp(&ProcessNode->OsContextGuid, &WIN8_CONTEXT_GUID, sizeof(GUID)) == 0) + ProcessNode->OsContextVersion = WINDOWS_8; + else if (memcmp(&ProcessNode->OsContextGuid, &WIN7_CONTEXT_GUID, sizeof(GUID)) == 0) + ProcessNode->OsContextVersion = WINDOWS_7; + else if (memcmp(&ProcessNode->OsContextGuid, &VISTA_CONTEXT_GUID, sizeof(GUID)) == 0) + ProcessNode->OsContextVersion = WINDOWS_VISTA; + else if (memcmp(&ProcessNode->OsContextGuid, &XP_CONTEXT_GUID, sizeof(GUID)) == 0) + ProcessNode->OsContextVersion = WINDOWS_XP; } + + NtClose(processHandle); } ProcessNode->ValidMask |= PHPN_OSCONTEXT; @@ -1104,15 +1101,8 @@ static VOID PhpUpdateProcessNodeAppId( if (!NT_SUCCESS(PhOpenProcess(&processHandle, ProcessQueryAccess | PROCESS_VM_READ, ProcessNode->ProcessId))) { - if (WindowsVersion >= WINDOWS_7) - { - if (!NT_SUCCESS(PhOpenProcess(&processHandle, ProcessQueryAccess, ProcessNode->ProcessId))) - goto Done; - } - else - { + if (!NT_SUCCESS(PhOpenProcess(&processHandle, ProcessQueryAccess, ProcessNode->ProcessId))) goto Done; - } } if (NT_SUCCESS(PhGetProcessWindowTitle( @@ -2026,12 +2016,10 @@ BOOLEAN NTAPI PhpProcessTreeNewCallback( if (PhBeginInitOnce(&initOnce)) { - if (WindowsVersion >= WINDOWS_7) - { - sortFunctions[PHPRTLC_PRIVATEWS] = SORT_FUNCTION(PrivateWsWin7); - sortFunctions[PHPRTLC_CYCLES] = SORT_FUNCTION(CyclesWin7); - sortFunctions[PHPRTLC_CYCLESDELTA] = SORT_FUNCTION(CyclesDeltaWin7); - } + // TODO: Remove this. + sortFunctions[PHPRTLC_PRIVATEWS] = SORT_FUNCTION(PrivateWsWin7); + sortFunctions[PHPRTLC_CYCLES] = SORT_FUNCTION(CyclesWin7); + sortFunctions[PHPRTLC_CYCLESDELTA] = SORT_FUNCTION(CyclesDeltaWin7); PhEndInitOnce(&initOnce); } @@ -2421,7 +2409,6 @@ BOOLEAN NTAPI PhpProcessTreeNewCallback( break; case PHPRTLC_CYCLES: - if (WindowsVersion >= WINDOWS_7) { ULONG64 value = 0; PhpAggregateFieldIfNeeded(node, AggregateTypeInt64, AggregateLocationProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, CycleTimeDelta.Value), &value); @@ -2432,13 +2419,8 @@ BOOLEAN NTAPI PhpProcessTreeNewCallback( getCellText->Text = node->CyclesText->sr; } } - else - { - getCellText->Text = PhGetStringRef(node->CyclesText); - } break; case PHPRTLC_CYCLESDELTA: - if (WindowsVersion >= WINDOWS_7) { ULONG64 value = 0; PhpAggregateFieldIfNeeded(node, AggregateTypeInt64, AggregateLocationProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, CycleTimeDelta.Delta), &value); @@ -2449,10 +2431,6 @@ BOOLEAN NTAPI PhpProcessTreeNewCallback( getCellText->Text = node->CyclesDeltaText->sr; } } - else - { - getCellText->Text = PhGetStringRef(node->CyclesDeltaText); - } break; case PHPRTLC_DEP: PhpUpdateProcessNodeDepStatus(node); @@ -2559,34 +2537,26 @@ BOOLEAN NTAPI PhpProcessTreeNewCallback( break; case PHPRTLC_OSCONTEXT: PhpUpdateProcessOsContext(node); - - if (WindowsVersion >= WINDOWS_7) + switch (node->OsContextVersion) { - switch (node->OsContextVersion) - { - case WINDOWS_10: - PhInitializeStringRef(&getCellText->Text, L"Windows 10"); - break; - case WINDOWS_8_1: - PhInitializeStringRef(&getCellText->Text, L"Windows 8.1"); - break; - case WINDOWS_8: - PhInitializeStringRef(&getCellText->Text, L"Windows 8"); - break; - case WINDOWS_7: - PhInitializeStringRef(&getCellText->Text, L"Windows 7"); - break; - case WINDOWS_VISTA: - PhInitializeStringRef(&getCellText->Text, L"Windows Vista"); - break; - case WINDOWS_XP: - PhInitializeStringRef(&getCellText->Text, L"Windows XP"); - break; - } - } - else - { - PhInitializeStringRef(&getCellText->Text, L"N/A"); + case WINDOWS_10: + PhInitializeStringRef(&getCellText->Text, L"Windows 10"); + break; + case WINDOWS_8_1: + PhInitializeStringRef(&getCellText->Text, L"Windows 8.1"); + break; + case WINDOWS_8: + PhInitializeStringRef(&getCellText->Text, L"Windows 8"); + break; + case WINDOWS_7: + PhInitializeStringRef(&getCellText->Text, L"Windows 7"); + break; + case WINDOWS_VISTA: + PhInitializeStringRef(&getCellText->Text, L"Windows Vista"); + break; + case WINDOWS_XP: + PhInitializeStringRef(&getCellText->Text, L"Windows XP"); + break; } break; case PHPRTLC_PAGEDPOOL: diff --git a/ProcessHacker/prpgstat.c b/ProcessHacker/prpgstat.c index cb2ef363d4b5..3f0f2f862649 100644 --- a/ProcessHacker/prpgstat.c +++ b/ProcessHacker/prpgstat.c @@ -103,21 +103,17 @@ VOID PhpUpdateProcessStatistics( if (ProcessItem->QueryHandle) { ULONG64 cycleTime; - - if (WindowsVersion >= WINDOWS_7) + PROCESS_HANDLE_INFORMATION handleInfo; + + if (NT_SUCCESS(NtQueryInformationProcess( + ProcessItem->QueryHandle, + ProcessHandleCount, + &handleInfo, + sizeof(PROCESS_HANDLE_INFORMATION), + NULL + ))) { - PROCESS_HANDLE_INFORMATION handleInfo; - - if (NT_SUCCESS(NtQueryInformationProcess( - ProcessItem->QueryHandle, - ProcessHandleCount, - &handleInfo, - sizeof(PROCESS_HANDLE_INFORMATION), - NULL - ))) - { - peakHandles = PhaFormatUInt64(handleInfo.HandleCountHighWatermark, TRUE); - } + peakHandles = PhaFormatUInt64(handleInfo.HandleCountHighWatermark, TRUE); } gdiHandles = PhaFormatUInt64(GetGuiResources(ProcessItem->QueryHandle, GR_GDIOBJECTS), TRUE); // GDI handles @@ -146,19 +142,12 @@ VOID PhpUpdateProcessStatistics( } } - if (WindowsVersion >= WINDOWS_7) - { - if (!gotCycles) - cycles = PhaFormatUInt64(ProcessItem->CycleTimeDelta.Value, TRUE); - if (!gotWsCounters) - privateWs = PhaFormatSize(ProcessItem->WorkingSetPrivateSize, -1); - } - - if (WindowsVersion >= WINDOWS_7) - SetDlgItemText(hwndDlg, IDC_ZPEAKHANDLES_V, PhGetStringOrDefault(peakHandles, L"Unknown")); - else - SetDlgItemText(hwndDlg, IDC_ZPEAKHANDLES_V, L"N/A"); + if (!gotCycles) + cycles = PhaFormatUInt64(ProcessItem->CycleTimeDelta.Value, TRUE); + if (!gotWsCounters) + privateWs = PhaFormatSize(ProcessItem->WorkingSetPrivateSize, -1); + SetDlgItemText(hwndDlg, IDC_ZPEAKHANDLES_V, PhGetStringOrDefault(peakHandles, L"Unknown")); SetDlgItemText(hwndDlg, IDC_ZGDIHANDLES_V, PhGetStringOrDefault(gdiHandles, L"Unknown")); SetDlgItemText(hwndDlg, IDC_ZUSERHANDLES_V, PhGetStringOrDefault(userHandles, L"Unknown")); SetDlgItemText(hwndDlg, IDC_ZCYCLES_V, PhGetStringOrDefault(cycles, L"Unknown")); diff --git a/ProcessHacker/resource.h b/ProcessHacker/resource.h index 82fb961b55c9..ad488eaad530 100644 --- a/ProcessHacker/resource.h +++ b/ProcessHacker/resource.h @@ -645,7 +645,6 @@ #define ID_COMPUTER_HIBERNATE 40163 #define ID_COMPUTER_RESTART 40164 #define ID_COMPUTER_SHUTDOWN 40165 -#define ID_NETWORK_VIEWSTACK 40167 #define ID_TRAYICONS_IOHISTORY 40168 #define ID_ICON_EXIT 40169 #define ID_ICON_SHOWHIDEPROCESSHACKER 40171 diff --git a/ProcessHacker/runas.c b/ProcessHacker/runas.c index c765e6293a38..ed8eec32b283 100644 --- a/ProcessHacker/runas.c +++ b/ProcessHacker/runas.c @@ -538,19 +538,7 @@ INT_PTR CALLBACK PhpRunAsDlgProc( if (IsServiceAccount(userName)) { EnableWindow(GetDlgItem(hwndDlg, IDC_PASSWORD), FALSE); - - // Hack for Windows XP - if ( - PhEqualString2(userName, L"NT AUTHORITY\\SYSTEM", TRUE) && - WindowsVersion <= WINDOWS_XP - ) - { - PhSelectComboBoxString(GetDlgItem(hwndDlg, IDC_TYPE), L"New credentials", FALSE); - } - else - { - PhSelectComboBoxString(GetDlgItem(hwndDlg, IDC_TYPE), L"Service", FALSE); - } + PhSelectComboBoxString(GetDlgItem(hwndDlg, IDC_TYPE), L"Service", FALSE); } else { diff --git a/ProcessHacker/syssccpu.c b/ProcessHacker/syssccpu.c index b7b82704742f..c2a6cc7d9a69 100644 --- a/ProcessHacker/syssccpu.c +++ b/ProcessHacker/syssccpu.c @@ -177,8 +177,7 @@ VOID PhSipInitializeCpuDialog( CurrentPerformanceDistribution = NULL; PreviousPerformanceDistribution = NULL; - if (WindowsVersion >= WINDOWS_7) - PhSipQueryProcessorPerformanceDistribution(&CurrentPerformanceDistribution); + PhSipQueryProcessorPerformanceDistribution(&CurrentPerformanceDistribution); } VOID PhSipUninitializeCpuDialog( @@ -241,15 +240,12 @@ VOID PhSipTickCpuDialog( memset(PowerInformation, 0, sizeof(PROCESSOR_POWER_INFORMATION) * NumberOfProcessors); } - if (WindowsVersion >= WINDOWS_7) - { - if (PreviousPerformanceDistribution) - PhFree(PreviousPerformanceDistribution); + if (PreviousPerformanceDistribution) + PhFree(PreviousPerformanceDistribution); - PreviousPerformanceDistribution = CurrentPerformanceDistribution; - CurrentPerformanceDistribution = NULL; - PhSipQueryProcessorPerformanceDistribution(&CurrentPerformanceDistribution); - } + PreviousPerformanceDistribution = CurrentPerformanceDistribution; + CurrentPerformanceDistribution = NULL; + PhSipQueryProcessorPerformanceDistribution(&CurrentPerformanceDistribution); CpuTicked++; @@ -693,7 +689,7 @@ VOID PhSipUpdateCpuPanel( cpuGhz = 0; distributionSucceeded = FALSE; - if (WindowsVersion >= WINDOWS_7 && CurrentPerformanceDistribution && PreviousPerformanceDistribution) + if (CurrentPerformanceDistribution && PreviousPerformanceDistribution) { if (PhSipGetCpuFrequencyFromDistribution(&cpuFraction)) { diff --git a/phlib/global.c b/phlib/global.c index 004986fdc189..01388363c212 100644 --- a/phlib/global.c +++ b/phlib/global.c @@ -176,25 +176,10 @@ static VOID PhInitializeWindowsVersion( majorVersion = versionInfo.dwMajorVersion; minorVersion = versionInfo.dwMinorVersion; - if (majorVersion == 5 && minorVersion < 1 || majorVersion < 5) + if (majorVersion == 6 && minorVersion < 1 || majorVersion < 6) { WindowsVersion = WINDOWS_ANCIENT; } - /* Windows XP */ - else if (majorVersion == 5 && minorVersion == 1) - { - WindowsVersion = WINDOWS_XP; - } - /* Windows Server 2003 */ - else if (majorVersion == 5 && minorVersion == 2) - { - WindowsVersion = WINDOWS_SERVER_2003; - } - /* Windows Vista, Windows Server 2008 */ - else if (majorVersion == 6 && minorVersion == 0) - { - WindowsVersion = WINDOWS_VISTA; - } /* Windows 7, Windows Server 2008 R2 */ else if (majorVersion == 6 && minorVersion == 1) { diff --git a/phlib/hndlinfo.c b/phlib/hndlinfo.c index 77df87c8d7c1..58c22e8b8bbf 100644 --- a/phlib/hndlinfo.c +++ b/phlib/hndlinfo.c @@ -1294,31 +1294,12 @@ NTSTATUS PhGetHandleInformationEx( // If we're dealing with a file handle we must take special precautions so we don't hang. if (PhEqualString2(typeName, L"File", TRUE) && !KphIsConnected()) { -#define QUERY_NORMALLY 0 -#define QUERY_WITH_TIMEOUT 1 -#define QUERY_FAIL 2 - - ULONG hackLevel = QUERY_WITH_TIMEOUT; - - // We can't use the timeout method on XP because hanging threads can't even be terminated! - if (WindowsVersion <= WINDOWS_XP) - hackLevel = QUERY_FAIL; - - if (hackLevel == QUERY_NORMALLY || hackLevel == QUERY_WITH_TIMEOUT) - { - status = PhpGetObjectName( - ProcessHandle, - KphIsConnected() ? Handle : dupHandle, - hackLevel == QUERY_WITH_TIMEOUT, - &objectName - ); - } - else - { - // Pretend the file object has no name. - objectName = PhReferenceEmptyString(); - status = STATUS_SUCCESS; - } + status = PhpGetObjectName( + ProcessHandle, + KphIsConnected() ? Handle : dupHandle, + TRUE, + &objectName + ); } else { @@ -1453,14 +1434,9 @@ ULONG PhGetObjectTypeNumber( objectIndex = objectType->TypeIndex; break; } - else if (WindowsVersion >= WINDOWS_7) - { - objectIndex = i + 2; - break; - } else { - objectIndex = i + 1; + objectIndex = i + 2; break; } } diff --git a/phlib/include/phconfig.h b/phlib/include/phconfig.h index 6da596042c2f..95a4c95b35c1 100644 --- a/phlib/include/phconfig.h +++ b/phlib/include/phconfig.h @@ -24,7 +24,6 @@ PHLIBAPI extern ACCESS_MASK ThreadAllAccess; #define WINDOWS_ANCIENT 0 #define WINDOWS_XP 51 -#define WINDOWS_SERVER_2003 52 #define WINDOWS_VISTA 60 #define WINDOWS_7 61 #define WINDOWS_8 62 @@ -32,8 +31,6 @@ PHLIBAPI extern ACCESS_MASK ThreadAllAccess; #define WINDOWS_10 100 #define WINDOWS_NEW MAXLONG -#define WINDOWS_HAS_CONSOLE_HOST (WindowsVersion >= WINDOWS_7) -#define WINDOWS_HAS_IMAGE_FILE_NAME_BY_PROCESS_ID (WindowsVersion >= WINDOWS_VISTA) #define WINDOWS_HAS_IMMERSIVE (WindowsVersion >= WINDOWS_8) // Debugging diff --git a/phlib/native.c b/phlib/native.c index 2ce8abb501dd..55a0bfa54840 100644 --- a/phlib/native.c +++ b/phlib/native.c @@ -736,25 +736,21 @@ NTSTATUS PhGetProcessWindowTitle( BOOLEAN isWow64 = FALSE; #endif ULONG windowFlags; + PPROCESS_WINDOW_INFORMATION windowInfo; - if (WindowsVersion >= WINDOWS_7) - { - PPROCESS_WINDOW_INFORMATION windowInfo; - - status = PhpQueryProcessVariableSize( - ProcessHandle, - ProcessWindowInformation, - &windowInfo - ); + status = PhpQueryProcessVariableSize( + ProcessHandle, + ProcessWindowInformation, + &windowInfo + ); - if (NT_SUCCESS(status)) - { - *WindowFlags = windowInfo->WindowFlags; - *WindowTitle = PhCreateStringEx(windowInfo->WindowTitle, windowInfo->WindowTitleLength); - PhFree(windowInfo); + if (NT_SUCCESS(status)) + { + *WindowFlags = windowInfo->WindowFlags; + *WindowTitle = PhCreateStringEx(windowInfo->WindowTitle, windowInfo->WindowTitleLength); + PhFree(windowInfo); - return status; - } + return status; } #ifdef _WIN64 @@ -2918,10 +2914,8 @@ NTSTATUS PhpEnumProcessModules( if (WindowsVersion >= WINDOWS_8) dataTableEntrySize = LDR_DATA_TABLE_ENTRY_SIZE_WIN8; - else if (WindowsVersion >= WINDOWS_7) - dataTableEntrySize = LDR_DATA_TABLE_ENTRY_SIZE_WIN7; else - dataTableEntrySize = LDR_DATA_TABLE_ENTRY_SIZE_WINXP; + dataTableEntrySize = LDR_DATA_TABLE_ENTRY_SIZE_WIN7; // Traverse the linked list (in load order). @@ -3281,10 +3275,8 @@ NTSTATUS PhpEnumProcessModules32( if (WindowsVersion >= WINDOWS_8) dataTableEntrySize = LDR_DATA_TABLE_ENTRY_SIZE_WIN8_32; - else if (WindowsVersion >= WINDOWS_7) - dataTableEntrySize = LDR_DATA_TABLE_ENTRY_SIZE_WIN7_32; else - dataTableEntrySize = LDR_DATA_TABLE_ENTRY_SIZE_WINXP_32; + dataTableEntrySize = LDR_DATA_TABLE_ENTRY_SIZE_WIN7_32; // Traverse the linked list (in load order). @@ -4804,10 +4796,7 @@ VOID PhUpdateMupDevicePrefixes( PhDeviceMupPrefixes[PhDeviceMupPrefixesCount++] = PhCreateString(L"\\Device\\Mup"); // DFS claims an extra part of file names, which we don't handle. - /*if (WindowsVersion >= WINDOWS_VISTA) - PhDeviceMupPrefixes[PhDeviceMupPrefixesCount++] = PhCreateString(L"\\Device\\DfsClient"); - else - PhDeviceMupPrefixes[PhDeviceMupPrefixesCount++] = PhCreateString(L"\\Device\\WinDfs");*/ + // PhDeviceMupPrefixes[PhDeviceMupPrefixesCount++] = PhCreateString(L"\\Device\\DfsClient"); remainingPart = providerOrder->sr; From e86dbba2ce5c938644d097aa30d64f3d2afd6d9f Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 14 Jun 2017 10:24:16 +1000 Subject: [PATCH 0217/2058] Remove legacy cycle time information --- ProcessHacker/include/proctree.h | 2 - ProcessHacker/proctree.c | 161 ++----------------------------- 2 files changed, 9 insertions(+), 154 deletions(-) diff --git a/ProcessHacker/include/proctree.h b/ProcessHacker/include/proctree.h index bce21d481390..23c30a4f3b66 100644 --- a/ProcessHacker/include/proctree.h +++ b/ProcessHacker/include/proctree.h @@ -161,8 +161,6 @@ typedef struct _PH_PROCESS_NODE USHORT ImageDllCharacteristics; // App ID PPH_STRING AppIdText; - // Cycles (Vista only) - PH_UINT64_DELTA CyclesDelta; // DPI awareness ULONG DpiAwareness; // File attributes diff --git a/ProcessHacker/proctree.c b/ProcessHacker/proctree.c index 7a9a18156528..e59e448ffab8 100644 --- a/ProcessHacker/proctree.c +++ b/ProcessHacker/proctree.c @@ -61,14 +61,6 @@ VOID PhpRemoveProcessNode( _In_ PPH_PROCESS_NODE ProcessNode ); -VOID PhpUpdateNeedCyclesInformation( - VOID - ); - -VOID PhpUpdateProcessNodeCycles( - _Inout_ PPH_PROCESS_NODE ProcessNode - ); - LONG PhpProcessTreeNewPostSortFunction( _In_ LONG Result, _In_ PVOID Node1, @@ -92,13 +84,11 @@ static PH_CM_MANAGER ProcessTreeListCm; static PPH_HASH_ENTRY ProcessNodeHashSet[256] = PH_HASH_SET_INIT; // hashtable of all nodes static PPH_LIST ProcessNodeList; // list of all nodes, used when sorting is enabled static PPH_LIST ProcessNodeRootList; // list of root nodes +static PH_TN_FILTER_SUPPORT FilterSupport; BOOLEAN PhProcessTreeListStateHighlighting = TRUE; static PPH_POINTER_LIST ProcessNodeStateList = NULL; // list of nodes which need to be processed -static PH_TN_FILTER_SUPPORT FilterSupport; -static BOOLEAN NeedCyclesInformation = FALSE; - static HDC GraphContext = NULL; static ULONG GraphContextWidth = 0; static ULONG GraphContextHeight = 0; @@ -254,8 +244,6 @@ VOID PhLoadSettingsProcessTreeList( { SendMessage(TreeNew_GetTooltips(ProcessTreeListHandle), TTM_SETDELAYTIME, TTDT_INITIAL, 0); } - - PhpUpdateNeedCyclesInformation(); } VOID PhSaveSettingsProcessTreeList( @@ -624,10 +612,6 @@ VOID PhTickProcessNodes( node->CpuGraphBuffers.Valid = FALSE; node->PrivateGraphBuffers.Valid = FALSE; node->IoGraphBuffers.Valid = FALSE; - - // Updates cycles if necessary. - if (NeedCyclesInformation) - PhpUpdateProcessNodeCycles(node); } fullyInvalidated = FALSE; @@ -986,17 +970,17 @@ static VOID PhpUpdateProcessOsContext( { if (NT_SUCCESS(PhGetProcessSwitchContext(processHandle, &ProcessNode->OsContextGuid))) { - if (memcmp(&ProcessNode->OsContextGuid, &WINTHRESHOLD_CONTEXT_GUID, sizeof(GUID)) == 0) + if (IsEqualGUID(&ProcessNode->OsContextGuid, &WINTHRESHOLD_CONTEXT_GUID)) ProcessNode->OsContextVersion = WINDOWS_10; - else if (memcmp(&ProcessNode->OsContextGuid, &WINBLUE_CONTEXT_GUID, sizeof(GUID)) == 0) + else if (IsEqualGUID(&ProcessNode->OsContextGuid, &WINBLUE_CONTEXT_GUID)) ProcessNode->OsContextVersion = WINDOWS_8_1; - else if (memcmp(&ProcessNode->OsContextGuid, &WIN8_CONTEXT_GUID, sizeof(GUID)) == 0) + else if (IsEqualGUID(&ProcessNode->OsContextGuid, &WIN8_CONTEXT_GUID)) ProcessNode->OsContextVersion = WINDOWS_8; - else if (memcmp(&ProcessNode->OsContextGuid, &WIN7_CONTEXT_GUID, sizeof(GUID)) == 0) + else if (IsEqualGUID(&ProcessNode->OsContextGuid, &WIN7_CONTEXT_GUID)) ProcessNode->OsContextVersion = WINDOWS_7; - else if (memcmp(&ProcessNode->OsContextGuid, &VISTA_CONTEXT_GUID, sizeof(GUID)) == 0) + else if (IsEqualGUID(&ProcessNode->OsContextGuid, &VISTA_CONTEXT_GUID)) ProcessNode->OsContextVersion = WINDOWS_VISTA; - else if (memcmp(&ProcessNode->OsContextGuid, &XP_CONTEXT_GUID, sizeof(GUID)) == 0) + else if (IsEqualGUID(&ProcessNode->OsContextGuid, &XP_CONTEXT_GUID)) ProcessNode->OsContextVersion = WINDOWS_XP; } @@ -1182,91 +1166,6 @@ static VOID PhpUpdateProcessNodeFileAttributes( } } -static VOID PhpUpdateNeedCyclesInformation( - VOID - ) -{ - PH_TREENEW_COLUMN column; - - NeedCyclesInformation = FALSE; - - // Before Windows Vista, there is no cycle time measurement. - // On Windows 7 and above, cycle time information is available directly from the process item. - // We only need to query cycle time separately for Windows Vista. - if (WindowsVersion != WINDOWS_VISTA) - return; - - TreeNew_GetColumn(ProcessTreeListHandle, PHPRTLC_CYCLES, &column); - - if (column.Visible) - { - NeedCyclesInformation = TRUE; - return; - } - - TreeNew_GetColumn(ProcessTreeListHandle, PHPRTLC_CYCLESDELTA, &column); - - if (column.Visible) - { - NeedCyclesInformation = TRUE; - return; - } -} - -static VOID PhpUpdateProcessNodeCycles( - _Inout_ PPH_PROCESS_NODE ProcessNode - ) -{ - if (ProcessNode->ProcessId == SYSTEM_IDLE_PROCESS_ID) - { - PULARGE_INTEGER idleThreadCycleTimes; - ULONG64 cycleTime; - ULONG i; - - // System Idle Process requires special treatment. - - idleThreadCycleTimes = PhAllocate( - sizeof(ULARGE_INTEGER) * (ULONG)PhSystemBasicInformation.NumberOfProcessors - ); - - if (NT_SUCCESS(NtQuerySystemInformation( - SystemProcessorIdleCycleTimeInformation, - idleThreadCycleTimes, - sizeof(ULARGE_INTEGER) * (ULONG)PhSystemBasicInformation.NumberOfProcessors, - NULL - ))) - { - cycleTime = 0; - - for (i = 0; i < (ULONG)PhSystemBasicInformation.NumberOfProcessors; i++) - cycleTime += idleThreadCycleTimes[i].QuadPart; - - PhUpdateDelta(&ProcessNode->CyclesDelta, cycleTime); - } - - PhFree(idleThreadCycleTimes); - } - else if (ProcessNode->ProcessItem->QueryHandle) - { - ULONG64 cycleTime; - - if (NT_SUCCESS(PhGetProcessCycleTime(ProcessNode->ProcessItem->QueryHandle, &cycleTime))) - { - PhUpdateDelta(&ProcessNode->CyclesDelta, cycleTime); - } - } - - if (ProcessNode->CyclesDelta.Value != 0) - PhMoveReference(&ProcessNode->CyclesText, PhFormatUInt64(ProcessNode->CyclesDelta.Value, TRUE)); - else - PhClearReference(&ProcessNode->CyclesText); - - if (ProcessNode->CyclesDelta.Delta != 0) - PhMoveReference(&ProcessNode->CyclesDeltaText, PhFormatUInt64(ProcessNode->CyclesDelta.Delta, TRUE)); - else - PhClearReference(&ProcessNode->CyclesDeltaText); -} - #define SORT_FUNCTION(Column) PhpProcessTreeNewCompare##Column #define BEGIN_SORT_FUNCTION(Column) static int __cdecl PhpProcessTreeNewCompare##Column( \ @@ -1411,14 +1310,6 @@ BEGIN_SORT_FUNCTION(PeakWorkingSet) END_SORT_FUNCTION BEGIN_SORT_FUNCTION(PrivateWs) -{ - PhpUpdateProcessNodeWsCounters(node1); - PhpUpdateProcessNodeWsCounters(node2); - sortResult = uintptrcmp(node1->WsCounters.NumberOfPrivatePages, node2->WsCounters.NumberOfPrivatePages); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(PrivateWsWin7) { sortResult = uintptrcmp(processItem1->WorkingSetPrivateSize, processItem2->WorkingSetPrivateSize); } @@ -1661,24 +1552,12 @@ BEGIN_SORT_FUNCTION(WindowStatus) END_SORT_FUNCTION BEGIN_SORT_FUNCTION(Cycles) -{ - sortResult = uint64cmp(node1->CyclesDelta.Value, node2->CyclesDelta.Value); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(CyclesWin7) { sortResult = uint64cmp(processItem1->CycleTimeDelta.Value, processItem2->CycleTimeDelta.Value); } END_SORT_FUNCTION BEGIN_SORT_FUNCTION(CyclesDelta) -{ - sortResult = uint64cmp(node1->CyclesDelta.Delta, node2->CyclesDelta.Delta); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(CyclesDeltaWin7) { sortResult = uint64cmp(processItem1->CycleTimeDelta.Delta, processItem2->CycleTimeDelta.Delta); } @@ -2011,19 +1890,8 @@ BOOLEAN NTAPI PhpProcessTreeNewCallback( SORT_FUNCTION(FileModifiedTime), SORT_FUNCTION(FileSize) }; - static PH_INITONCE initOnce = PH_INITONCE_INIT; int (__cdecl *sortFunction)(const void *, const void *); - if (PhBeginInitOnce(&initOnce)) - { - // TODO: Remove this. - sortFunctions[PHPRTLC_PRIVATEWS] = SORT_FUNCTION(PrivateWsWin7); - sortFunctions[PHPRTLC_CYCLES] = SORT_FUNCTION(CyclesWin7); - sortFunctions[PHPRTLC_CYCLESDELTA] = SORT_FUNCTION(CyclesDeltaWin7); - - PhEndInitOnce(&initOnce); - } - if (!PhCmForwardSort( (PPH_TREENEW_NODE *)ProcessNodeList->Items, ProcessNodeList->Count, @@ -2183,15 +2051,7 @@ BOOLEAN NTAPI PhpProcessTreeNewCallback( getCellText->Text = node->PeakWorkingSetText->sr; break; case PHPRTLC_PRIVATEWS: - if (WindowsVersion >= WINDOWS_7) - { - PhMoveReference(&node->PrivateWsText, PhFormatSize(processItem->WorkingSetPrivateSize, -1)); - } - else - { - PhpUpdateProcessNodeWsCounters(node); - PhMoveReference(&node->PrivateWsText, PhFormatSize((ULONG64)node->WsCounters.NumberOfPrivatePages * PAGE_SIZE, -1)); - } + PhMoveReference(&node->PrivateWsText, PhFormatSize(processItem->WorkingSetPrivateSize, -1)); getCellText->Text = node->PrivateWsText->sr; break; case PHPRTLC_SHAREDWS: @@ -3101,11 +2961,8 @@ BOOLEAN NTAPI PhpProcessTreeNewCallback( data.Selection = PhShowEMenu(data.Menu, hwnd, PH_EMENU_SHOW_LEFTRIGHT, PH_ALIGN_LEFT | PH_ALIGN_TOP, data.MouseEvent->ScreenLocation.x, data.MouseEvent->ScreenLocation.y); - PhHandleTreeNewColumnMenu(&data); - - if (data.ProcessedId == PH_TN_COLUMN_MENU_HIDE_COLUMN_ID || data.ProcessedId == PH_TN_COLUMN_MENU_CHOOSE_COLUMNS_ID) - PhpUpdateNeedCyclesInformation(); + PhHandleTreeNewColumnMenu(&data); PhDeleteTreeNewColumnMenu(&data); } return TRUE; From c44ca0ae68ce7a6f0d3dacfdec2e3246623c36e2 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 14 Jun 2017 16:20:48 +1000 Subject: [PATCH 0218/2058] Update versioning for Windows 10, Fix process OS Context on Win10-RS2, Add PEB comments --- ProcessHacker/appsup.c | 13 ++++++++++++- phlib/global.c | 21 ++++++++++++++++++++- phlib/include/phconfig.h | 5 ++++- phlib/svcsup.c | 25 +++++++++++-------------- phnt/include/ntpebteb.h | 16 ++++++++-------- 5 files changed, 55 insertions(+), 25 deletions(-) diff --git a/ProcessHacker/appsup.c b/ProcessHacker/appsup.c index e926582c6946..163045b58ea1 100644 --- a/ProcessHacker/appsup.c +++ b/ProcessHacker/appsup.c @@ -178,7 +178,18 @@ NTSTATUS PhGetProcessSwitchContext( if (!data) return STATUS_UNSUCCESSFUL; // no compatibility context data - if (WindowsVersion >= WINDOWS_10) + if (WindowsVersion >= WINDOWS_10_RS2) + { + if (!NT_SUCCESS(status = NtReadVirtualMemory( + ProcessHandle, + PTR_ADD_OFFSET(data, 1544), + Guid, + sizeof(GUID), + NULL + ))) + return status; + } + else if (WindowsVersion >= WINDOWS_10) { if (!NT_SUCCESS(status = NtReadVirtualMemory( ProcessHandle, diff --git a/phlib/global.c b/phlib/global.c index 01388363c212..0afc6504abc1 100644 --- a/phlib/global.c +++ b/phlib/global.c @@ -163,6 +163,7 @@ static VOID PhInitializeWindowsVersion( RTL_OSVERSIONINFOEXW versionInfo; ULONG majorVersion; ULONG minorVersion; + ULONG buildVersion; versionInfo.dwOSVersionInfoSize = sizeof(RTL_OSVERSIONINFOEXW); @@ -175,6 +176,7 @@ static VOID PhInitializeWindowsVersion( memcpy(&PhOsVersion, &versionInfo, sizeof(RTL_OSVERSIONINFOEXW)); majorVersion = versionInfo.dwMajorVersion; minorVersion = versionInfo.dwMinorVersion; + buildVersion = versionInfo.dwBuildNumber; if (majorVersion == 6 && minorVersion < 1 || majorVersion < 6) { @@ -198,7 +200,24 @@ static VOID PhInitializeWindowsVersion( /* Windows 10 */ else if (majorVersion == 10 && minorVersion == 0) { - WindowsVersion = WINDOWS_10; + switch (buildVersion) + { + case 10240: + WindowsVersion = WINDOWS_10_TH1; + break; + case 10586: + WindowsVersion = WINDOWS_10_TH2; + break; + case 14393: + WindowsVersion = WINDOWS_10_RS1; + break; + case 15063: + WindowsVersion = WINDOWS_10_RS2; + break; + default: + WindowsVersion = WINDOWS_10; + break; + } } else if (majorVersion == 10 && minorVersion > 0 || majorVersion > 10) { diff --git a/phlib/include/phconfig.h b/phlib/include/phconfig.h index 95a4c95b35c1..420d3ed97dfc 100644 --- a/phlib/include/phconfig.h +++ b/phlib/include/phconfig.h @@ -8,7 +8,6 @@ extern "C" { #define _User_set_ PHLIBAPI extern _User_set_ PVOID PhLibImageBase; - PHLIBAPI extern _User_set_ PWSTR PhApplicationName; PHLIBAPI extern _User_set_ ULONG PhGlobalDpi; PHLIBAPI extern PVOID PhHeapHandle; @@ -29,6 +28,10 @@ PHLIBAPI extern ACCESS_MASK ThreadAllAccess; #define WINDOWS_8 62 #define WINDOWS_8_1 63 #define WINDOWS_10 100 +#define WINDOWS_10_TH1 101 +#define WINDOWS_10_TH2 102 +#define WINDOWS_10_RS1 103 +#define WINDOWS_10_RS2 104 #define WINDOWS_NEW MAXLONG #define WINDOWS_HAS_IMMERSIVE (WindowsVersion >= WINDOWS_8) diff --git a/phlib/svcsup.c b/phlib/svcsup.c index cd796658aca7..07e33948a58e 100644 --- a/phlib/svcsup.c +++ b/phlib/svcsup.c @@ -93,21 +93,18 @@ PVOID PhEnumServices( if (!Type) { - if (WindowsVersion >= WINDOWS_10) + if (WindowsVersion >= WINDOWS_10_RS1) { - if (PhOsVersion.dwBuildNumber >= 14393) - { - Type = SERVICE_TYPE_ALL; - } - else - { - Type = SERVICE_WIN32 | - SERVICE_ADAPTER | - SERVICE_DRIVER | - SERVICE_INTERACTIVE_PROCESS | - SERVICE_USER_SERVICE | - SERVICE_USERSERVICE_INSTANCE; - } + Type = SERVICE_TYPE_ALL; + } + else if (WindowsVersion >= WINDOWS_10) + { + Type = SERVICE_WIN32 | + SERVICE_ADAPTER | + SERVICE_DRIVER | + SERVICE_INTERACTIVE_PROCESS | + SERVICE_USER_SERVICE | + SERVICE_USERSERVICE_INSTANCE; } else { diff --git a/phnt/include/ntpebteb.h b/phnt/include/ntpebteb.h index 60f3b02adc67..6169a18d4f44 100644 --- a/phnt/include/ntpebteb.h +++ b/phnt/include/ntpebteb.h @@ -65,9 +65,9 @@ typedef struct _PEB PVOID ReadOnlySharedMemoryBase; PVOID HotpatchInformation; PVOID *ReadOnlyStaticServerData; - PVOID AnsiCodePageData; - PVOID OemCodePageData; - PVOID UnicodeCaseTableData; + PVOID AnsiCodePageData; // PCPTABLEINFO + PVOID OemCodePageData; // PCPTABLEINFO + PVOID UnicodeCaseTableData; // PNLSTABLEINFO ULONG NumberOfProcessors; ULONG NtGlobalFlag; @@ -80,7 +80,7 @@ typedef struct _PEB ULONG NumberOfHeaps; ULONG MaximumNumberOfHeaps; - PVOID *ProcessHeaps; + PVOID *ProcessHeaps; // PHEAP PVOID GdiSharedHandleTable; PVOID ProcessStarterHelper; @@ -112,10 +112,10 @@ typedef struct _PEB UNICODE_STRING CSDVersion; - PVOID ActivationContextData; - PVOID ProcessAssemblyStorageMap; - PVOID SystemDefaultActivationContextData; - PVOID SystemAssemblyStorageMap; + PVOID ActivationContextData; // ACTIVATION_CONTEXT_DATA + PVOID ProcessAssemblyStorageMap; // ASSEMBLY_STORAGE_MAP + PVOID SystemDefaultActivationContextData; // ACTIVATION_CONTEXT_DATA + PVOID SystemAssemblyStorageMap; // ASSEMBLY_STORAGE_MAP SIZE_T MinimumStackCommit; From 054af2fa4cf0d9708fd56f3594b4cb8f14192c97 Mon Sep 17 00:00:00 2001 From: Efreak Date: Wed, 14 Jun 2017 16:41:59 -0700 Subject: [PATCH 0219/2058] Add shortcut keys (#151) - View\Tray Icons contents - CPU &history - CPU &usage - &I/O history - &Commit charge history - &Physical memory history - Tools\Start &Task Manager - Process Context Menu\Miscellaneous contents - Reduce working &set - &Run as... - Run &as this user... - Services tab - View\&Hide driver services - Content menu items 'Affinity', 'Priority', 'I/O Priority' sub-items: - &Save for %s - Save &for this command line --- ProcessHacker/ProcessHacker.rc | 18 +++++++++--------- ProcessHacker/mwpgsrv.c | 2 +- plugins/ExtraPlugins/main.c | 4 ++-- plugins/UserNotes/main.c | 12 ++++++------ 4 files changed, 18 insertions(+), 18 deletions(-) diff --git a/ProcessHacker/ProcessHacker.rc b/ProcessHacker/ProcessHacker.rc index d08e9ed52974..675362f8993c 100644 --- a/ProcessHacker/ProcessHacker.rc +++ b/ProcessHacker/ProcessHacker.rc @@ -111,11 +111,11 @@ BEGIN MENUITEM "System &information\aCtrl+I", ID_VIEW_SYSTEMINFORMATION POPUP "&Tray icons" BEGIN - MENUITEM "CPU history", ID_TRAYICONS_CPUHISTORY - MENUITEM "CPU usage", ID_TRAYICONS_CPUUSAGE - MENUITEM "I/O history", ID_TRAYICONS_IOHISTORY - MENUITEM "Commit charge history", ID_TRAYICONS_COMMITHISTORY - MENUITEM "Physical memory history", ID_TRAYICONS_PHYSICALMEMORYHISTORY + MENUITEM "CPU &history", ID_TRAYICONS_CPUHISTORY + MENUITEM "CPU &usage", ID_TRAYICONS_CPUUSAGE + MENUITEM "&I/O history", ID_TRAYICONS_IOHISTORY + MENUITEM "&Commit charge history", ID_TRAYICONS_COMMITHISTORY + MENUITEM "&Physical memory history", ID_TRAYICONS_PHYSICALMEMORYHISTORY END MENUITEM SEPARATOR MENUITEM "
    ", ID_VIEW_SECTIONPLACEHOLDER @@ -152,7 +152,7 @@ BEGIN MENUITEM "Hidden processes", ID_TOOLS_HIDDENPROCESSES MENUITEM "Inspect executable file...", ID_TOOLS_INSPECTEXECUTABLEFILE MENUITEM "Pagefiles", ID_TOOLS_PAGEFILES - MENUITEM "Start Task Manager", ID_TOOLS_STARTTASKMANAGER + MENUITEM "Start &Task Manager", ID_TOOLS_STARTTASKMANAGER END POPUP "&Users" BEGIN @@ -301,9 +301,9 @@ BEGIN MENUITEM "Low", ID_PAGEPRIORITY_LOW MENUITEM "Very low", ID_PAGEPRIORITY_VERYLOW END - MENUITEM "Reduce working set", ID_MISCELLANEOUS_REDUCEWORKINGSET - MENUITEM "Run as...", ID_MISCELLANEOUS_RUNAS - MENUITEM "Run as this user...", ID_MISCELLANEOUS_RUNASTHISUSER + MENUITEM "Reduce working &set", ID_MISCELLANEOUS_REDUCEWORKINGSET + MENUITEM "&Run as...", ID_MISCELLANEOUS_RUNAS + MENUITEM "Run &as this user...", ID_MISCELLANEOUS_RUNASTHISUSER END POPUP "&Window" BEGIN diff --git a/ProcessHacker/mwpgsrv.c b/ProcessHacker/mwpgsrv.c index 866ca49dc2e3..8862e02ded39 100644 --- a/ProcessHacker/mwpgsrv.c +++ b/ProcessHacker/mwpgsrv.c @@ -108,7 +108,7 @@ BOOLEAN PhMwpServicesPageCallback( ULONG startIndex = menuInfo->StartIndex; PPH_EMENU_ITEM menuItem; - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_VIEW_HIDEDRIVERSERVICES, L"Hide driver services", NULL, NULL), startIndex); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_VIEW_HIDEDRIVERSERVICES, L"&Hide driver services", NULL, NULL), startIndex); if (DriverFilterEntry && (menuItem = PhFindEMenuItem(menu, 0, NULL, ID_VIEW_HIDEDRIVERSERVICES))) menuItem->Flags |= PH_EMENU_CHECKED; diff --git a/plugins/ExtraPlugins/main.c b/plugins/ExtraPlugins/main.c index 24daa6d24447..ed2be884c1f1 100644 --- a/plugins/ExtraPlugins/main.c +++ b/plugins/ExtraPlugins/main.c @@ -253,7 +253,7 @@ VOID NTAPI MainMenuInitializingCallback( if (pluginMenu = PhFindEMenuItem(menuInfo->Menu, PH_EMENU_FIND_DESCEND, NULL, PHAPP_ID_HACKER_PLUGINS)) { - PhInsertEMenuItem(menuInfo->Menu, PhPluginCreateEMenuItem(PluginInstance, 0, pluginMenu->Id, L"Plugins... (Beta)", NULL), PhIndexOfEMenuItem(menuInfo->Menu, pluginMenu)); + PhInsertEMenuItem(menuInfo->Menu, PhPluginCreateEMenuItem(PluginInstance, 0, pluginMenu->Id, L"&Plugins... (Beta)", NULL), PhIndexOfEMenuItem(menuInfo->Menu, pluginMenu)); PhRemoveEMenuItem(menuInfo->Menu, pluginMenu, 0); } } @@ -348,4 +348,4 @@ LOGICAL DllMain( } return TRUE; -} \ No newline at end of file +} diff --git a/plugins/UserNotes/main.c b/plugins/UserNotes/main.c index d5bed8c6e40e..6f2dde717b1c 100644 --- a/plugins/UserNotes/main.c +++ b/plugins/UserNotes/main.c @@ -870,8 +870,8 @@ VOID AddSavePriorityMenuItemsAndHook( // Insert standard menu-items PhInsertEMenuItem(affinityMenuItem, PhPluginCreateEMenuItem(PluginInstance, PH_EMENU_SEPARATOR, 0, NULL, NULL), -1); - PhInsertEMenuItem(affinityMenuItem, saveMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, PROCESS_AFFINITY_SAVE_ID, PhaFormatString(L"Save for %s", ProcessItem->ProcessName->Buffer)->Buffer, NULL), -1); - PhInsertEMenuItem(affinityMenuItem, saveForCommandLineMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, PROCESS_AFFINITY_SAVE_FOR_THIS_COMMAND_LINE_ID, L"Save for this command line", NULL), -1); + PhInsertEMenuItem(affinityMenuItem, saveMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, PROCESS_AFFINITY_SAVE_ID, PhaFormatString(L"&Save for %s", ProcessItem->ProcessName->Buffer)->Buffer, NULL), -1); + PhInsertEMenuItem(affinityMenuItem, saveForCommandLineMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, PROCESS_AFFINITY_SAVE_FOR_THIS_COMMAND_LINE_ID, L"Save &for this command line", NULL), -1); if (!ProcessItem->CommandLine) saveForCommandLineMenuItem->Flags |= PH_EMENU_DISABLED; @@ -890,8 +890,8 @@ VOID AddSavePriorityMenuItemsAndHook( if (priorityMenuItem = PhFindEMenuItem(MenuInfo->Menu, 0, L"Priority", 0)) { PhInsertEMenuItem(priorityMenuItem, PhPluginCreateEMenuItem(PluginInstance, PH_EMENU_SEPARATOR, 0, NULL, NULL), -1); - PhInsertEMenuItem(priorityMenuItem, saveMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, PROCESS_PRIORITY_SAVE_ID, PhaFormatString(L"Save for %s", ProcessItem->ProcessName->Buffer)->Buffer, NULL), -1); - PhInsertEMenuItem(priorityMenuItem, saveForCommandLineMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, PROCESS_PRIORITY_SAVE_FOR_THIS_COMMAND_LINE_ID, L"Save for this command line", NULL), -1); + PhInsertEMenuItem(priorityMenuItem, saveMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, PROCESS_PRIORITY_SAVE_ID, PhaFormatString(L"&Save for %s", ProcessItem->ProcessName->Buffer)->Buffer, NULL), -1); + PhInsertEMenuItem(priorityMenuItem, saveForCommandLineMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, PROCESS_PRIORITY_SAVE_FOR_THIS_COMMAND_LINE_ID, L"Save &for this command line", NULL), -1); if (!ProcessItem->CommandLine) saveForCommandLineMenuItem->Flags |= PH_EMENU_DISABLED; @@ -910,8 +910,8 @@ VOID AddSavePriorityMenuItemsAndHook( if (ioPriorityMenuItem = PhFindEMenuItem(MenuInfo->Menu, 0, L"I/O Priority", 0)) { PhInsertEMenuItem(ioPriorityMenuItem, PhPluginCreateEMenuItem(PluginInstance, PH_EMENU_SEPARATOR, 0, NULL, NULL), -1); - PhInsertEMenuItem(ioPriorityMenuItem, saveMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, PROCESS_IO_PRIORITY_SAVE_ID, PhaFormatString(L"Save for %s", ProcessItem->ProcessName->Buffer)->Buffer, NULL), -1); - PhInsertEMenuItem(ioPriorityMenuItem, saveForCommandLineMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, PROCESS_IO_PRIORITY_SAVE_FOR_THIS_COMMAND_LINE_ID, L"Save for this command line", NULL), -1); + PhInsertEMenuItem(ioPriorityMenuItem, saveMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, PROCESS_IO_PRIORITY_SAVE_ID, PhaFormatString(L"&Save for %s", ProcessItem->ProcessName->Buffer)->Buffer, NULL), -1); + PhInsertEMenuItem(ioPriorityMenuItem, saveForCommandLineMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, PROCESS_IO_PRIORITY_SAVE_FOR_THIS_COMMAND_LINE_ID, L"Save &for this command line", NULL), -1); if (!ProcessItem->CommandLine) saveForCommandLineMenuItem->Flags |= PH_EMENU_DISABLED; From 9edf49688764c1d9df5a3c0857d7cc49386fc43d Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 15 Jun 2017 10:33:31 +1000 Subject: [PATCH 0220/2058] Fix setup error checking --- .../CustomSetupTool/CustomSetupTool/appsup.c | 1 - tools/CustomSetupTool/CustomSetupTool/setup.c | 67 ++++++++++--------- .../CustomSetupTool/CustomSetupTool/update.c | 7 +- 3 files changed, 38 insertions(+), 37 deletions(-) diff --git a/tools/CustomSetupTool/CustomSetupTool/appsup.c b/tools/CustomSetupTool/CustomSetupTool/appsup.c index aeaf18ed86e6..92bdf7e63846 100644 --- a/tools/CustomSetupTool/CustomSetupTool/appsup.c +++ b/tools/CustomSetupTool/CustomSetupTool/appsup.c @@ -505,7 +505,6 @@ static BOOLEAN NTAPI PhpPreviousInstancesCallback( BOOLEAN ShutdownProcessHacker(VOID) { PhEnumDirectoryObjects(PhGetNamespaceHandle(), PhpPreviousInstancesCallback, NULL); - return TRUE; } diff --git a/tools/CustomSetupTool/CustomSetupTool/setup.c b/tools/CustomSetupTool/CustomSetupTool/setup.c index be2a2500c977..59e5ab6918c3 100644 --- a/tools/CustomSetupTool/CustomSetupTool/setup.c +++ b/tools/CustomSetupTool/CustomSetupTool/setup.c @@ -178,41 +178,51 @@ BOOLEAN SetupCreateUninstallFile( // Check if the user has started the setup from the installation folder. if (PhStartsWithStringRef2(¤tFilePath, PhGetString(Context->SetupInstallPath), TRUE)) - { - // Do nothing, latest version already in the installation folder. return TRUE; - } backupFilePath = PhConcatStrings2(PhGetString(Context->SetupInstallPath), L"\\processhacker-setup.bak"); uninstallFilePath = PhConcatStrings2(PhGetString(Context->SetupInstallPath), L"\\processhacker-setup.exe"); if (RtlDoesFileExists_U(backupFilePath->Buffer)) { - // TODO: Move to temp directory - } + GUID randomGuid; + PPH_STRING tempPath = NULL; + PPH_STRING guidString = NULL; - if (RtlDoesFileExists_U(uninstallFilePath->Buffer)) - { - if (!DeleteFile(backupFilePath->Buffer)) + tempPath = PhCreateStringEx(NULL, GetTempPath(0, NULL) * sizeof(WCHAR)); + GetTempPath((ULONG)tempPath->Length / sizeof(WCHAR), tempPath->Buffer); + + PhGenerateGuid(&randomGuid); + + if (guidString = PhFormatGuid(&randomGuid)) + { + PhMoveReference(&guidString, PhSubstring(guidString, 1, guidString->Length / sizeof(WCHAR) - 2)); + } + + PhMoveReference(&guidString, PhConcatStrings( + 3, + PhGetString(tempPath), + L"\\", + PhGetString(guidString) + )); + + if (!MoveFile(backupFilePath->Buffer, guidString->Buffer)) { Context->ErrorCode = GetLastError(); - PhDereferenceObject(uninstallFilePath); - return FALSE; } + } + if (RtlDoesFileExists_U(uninstallFilePath->Buffer)) + { if (!MoveFile(uninstallFilePath->Buffer, backupFilePath->Buffer)) { Context->ErrorCode = GetLastError(); - PhDereferenceObject(uninstallFilePath); - return FALSE; } } - if (!CopyFile(currentFilePath.Buffer, uninstallFilePath->Buffer, FALSE)) + if (!CopyFile(currentFilePath.Buffer, uninstallFilePath->Buffer, TRUE)) { Context->ErrorCode = GetLastError(); - PhDereferenceObject(uninstallFilePath); - return FALSE; } PhDereferenceObject(uninstallFilePath); @@ -336,27 +346,24 @@ BOOLEAN SetupUninstallKph( _In_ PPH_SETUP_CONTEXT Context ) { - BOOLEAN deleted = FALSE; - SC_HANDLE serviceHandle; - SERVICE_STATUS serviceStatus; - - if (serviceHandle = PhOpenService( - L"KProcessHacker3", - SERVICE_STOP | DELETE - )) + while (TRUE) { - ControlService(serviceHandle, SERVICE_CONTROL_STOP, &serviceStatus); + SC_HANDLE serviceHandle; + SERVICE_STATUS serviceStatus; - deleted = DeleteService(serviceHandle); + if (!(serviceHandle = PhOpenService( + L"KProcessHacker3", + SERVICE_STOP | DELETE + ))) + break; + + ControlService(serviceHandle, SERVICE_CONTROL_STOP, &serviceStatus); + DeleteService(serviceHandle); CloseServiceHandle(serviceHandle); } - else - { - deleted = TRUE; - } - return deleted; + return TRUE; } VOID SetupSetWindowsOptions( diff --git a/tools/CustomSetupTool/CustomSetupTool/update.c b/tools/CustomSetupTool/CustomSetupTool/update.c index ae71b4ecb5a7..79a22c0e495e 100644 --- a/tools/CustomSetupTool/CustomSetupTool/update.c +++ b/tools/CustomSetupTool/CustomSetupTool/update.c @@ -141,12 +141,7 @@ VOID SetupShowUpdatingErrorDialog( config.pfCallback = SetupErrorTaskDialogCallbackProc; config.lpCallbackData = (LONG_PTR)Context; config.pszWindowTitle = PhApplicationName; - config.pszMainInstruction = PhaFormatString( - L"Error updating to the latest version...", - PHAPP_VERSION_MAJOR, - PHAPP_VERSION_MINOR, - PHAPP_VERSION_REVISION - )->Buffer; + config.pszMainInstruction = L"Error updating to the latest version."; if (Context->ErrorCode) { From 0b79b2409e0bc6311dee5f3b5287a55f618f99d4 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 15 Jun 2017 10:37:48 +1000 Subject: [PATCH 0221/2058] Enable CFG builds --- ProcessHacker/ProcessHacker.vcxproj | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ProcessHacker/ProcessHacker.vcxproj b/ProcessHacker/ProcessHacker.vcxproj index 2e5b41dd74cf..0be944a9791b 100644 --- a/ProcessHacker/ProcessHacker.vcxproj +++ b/ProcessHacker/ProcessHacker.vcxproj @@ -160,6 +160,7 @@ true true StreamingSIMDExtensions + Guard aclui.lib;comctl32.lib;iphlpapi.lib;noarg.obj;noenv.obj;ntdll.lib;phlib.lib;uxtheme.lib;version.lib;windowscodecs.lib;winsta.lib;ws2_32.lib;%(AdditionalDependencies) @@ -197,6 +198,7 @@ StdCall true true + Guard aclui.lib;comctl32.lib;iphlpapi.lib;noarg.obj;noenv.obj;ntdll.lib;phlib.lib;uxtheme.lib;version.lib;windowscodecs.lib;winsta.lib;ws2_32.lib;%(AdditionalDependencies) From efbe81fbbf0574f1624e4013dd4cefdf626b5b00 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 17 Jun 2017 18:39:15 +1000 Subject: [PATCH 0222/2058] Update ntpsapi.h #152 --- phnt/include/ntpsapi.h | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/phnt/include/ntpsapi.h b/phnt/include/ntpsapi.h index 0e65c8dfd8f2..7390ad399e2e 100644 --- a/phnt/include/ntpsapi.h +++ b/phnt/include/ntpsapi.h @@ -1272,10 +1272,28 @@ typedef enum _PS_ATTRIBUTE_NUM PsAttributeValue(PsAttributePreferredNode, FALSE, TRUE, FALSE) #define PS_ATTRIBUTE_IDEAL_PROCESSOR \ PsAttributeValue(PsAttributeIdealProcessor, TRUE, TRUE, FALSE) +#define PS_ATTRIBUTE_UMS_THREAD \ + PsAttributeValue(PsAttributeUmsThread, TRUE, TRUE, FALSE) #define PS_ATTRIBUTE_MITIGATION_OPTIONS \ PsAttributeValue(PsAttributeMitigationOptions, FALSE, TRUE, TRUE) #define PS_ATTRIBUTE_PROTECTION_LEVEL \ - PsAttributeValue(PsAttributeProtectionLevel, FALSE, TRUE, FALSE) + PsAttributeValue(PsAttributeProtectionLevel, FALSE, TRUE, TRUE) +#define PS_ATTRIBUTE_SECURE_PROCESS \ + PsAttributeValue(PsAttributeSecureProcess, FALSE, TRUE, FALSE) +#define PS_ATTRIBUTE_JOB_LIST \ + PsAttributeValue(PsAttributeJobList, FALSE, TRUE, FALSE) +#define PS_ATTRIBUTE_CHILD_PROCESS_POLICY \ + PsAttributeValue(PsAttributeChildProcessPolicy, FALSE, TRUE, FALSE) +#define PS_ATTRIBUTE_ALL_APPLICATION_PACKAGES_POLICY \ + PsAttributeValue(PsAttributeAllApplicationPackagesPolicy, FALSE, TRUE, FALSE) +#define PS_ATTRIBUTE_WIN32K_FILTER \ + PsAttributeValue(PsAttributeWin32kFilter, FALSE, TRUE, FALSE) +#define PS_ATTRIBUTE_SAFE_OPEN_PROMPT_ORIGIN_CLAIM \ + PsAttributeValue(PsAttributeSafeOpenPromptOriginClaim, FALSE, TRUE, FALSE) +#define PS_ATTRIBUTE_BNO_ISOLATION \ + PsAttributeValue(PsAttributeBnoIsolation, FALSE, TRUE, FALSE) +#define PS_ATTRIBUTE_DESKTOP_APP_POLICY \ + PsAttributeValue(PsAttributeDesktopAppPolicy, FALSE, TRUE, FALSE) // end_rev From ac88ba9a2f6d744d17d257c63276c80039b20c1f Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 18 Jun 2017 17:13:31 +1000 Subject: [PATCH 0223/2058] Tidy up variables --- plugins/ExtraPlugins/setup/updater.c | 10 +++++--- plugins/NetworkTools/update.c | 38 ++++++++++++++++++---------- plugins/OnlineChecks/upload.c | 8 ++++-- plugins/OnlineChecks/virustotal.c | 16 +++++++++--- plugins/Updater/updater.c | 30 ++++++++++++++-------- 5 files changed, 68 insertions(+), 34 deletions(-) diff --git a/plugins/ExtraPlugins/setup/updater.c b/plugins/ExtraPlugins/setup/updater.c index f8fdf0111cad..7dfb62bb0acd 100644 --- a/plugins/ExtraPlugins/setup/updater.c +++ b/plugins/ExtraPlugins/setup/updater.c @@ -451,10 +451,12 @@ NTSTATUS UpdateDownloadThread( goto CleanupExit; } - { - ULONG keepAlive = WINHTTP_DISABLE_KEEP_ALIVE; - WinHttpSetOption(httpRequestHandle, WINHTTP_OPTION_DISABLE_FEATURE, &keepAlive, sizeof(ULONG)); - } + WinHttpSetOption( + httpRequestHandle, + WINHTTP_OPTION_DISABLE_FEATURE, + &(ULONG){ WINHTTP_DISABLE_KEEP_ALIVE }, + sizeof(ULONG) + ); SendMessage(context->DialogHandle, TDM_UPDATE_ELEMENT_TEXT, TDE_MAIN_INSTRUCTION, (LPARAM)L"Sending download request..."); diff --git a/plugins/NetworkTools/update.c b/plugins/NetworkTools/update.c index 7e9cd5e07cc2..565830343209 100644 --- a/plugins/NetworkTools/update.c +++ b/plugins/NetworkTools/update.c @@ -198,13 +198,19 @@ PPH_STRING QueryFwLinkUrl( ); } - { - ULONG option = WINHTTP_DISABLE_REDIRECTS; - WinHttpSetOption(httpRequestHandle, WINHTTP_OPTION_DISABLE_FEATURE, &option, sizeof(ULONG)); - - option = WINHTTP_DISABLE_KEEP_ALIVE; - WinHttpSetOption(httpRequestHandle, WINHTTP_OPTION_DISABLE_FEATURE, &option, sizeof(ULONG)); - } + WinHttpSetOption( + httpRequestHandle, + WINHTTP_OPTION_DISABLE_FEATURE, + &(ULONG){ WINHTTP_DISABLE_REDIRECTS }, + sizeof(ULONG) + ); + + WinHttpSetOption( + httpRequestHandle, + WINHTTP_OPTION_DISABLE_FEATURE, + &(ULONG){ WINHTTP_DISABLE_KEEP_ALIVE }, + sizeof(ULONG) + ); if (!WinHttpSendRequest( httpRequestHandle, @@ -400,8 +406,12 @@ NTSTATUS GeoIPUpdateThread( if (WindowsVersion >= WINDOWS_8_1) { - ULONG httpFlags = WINHTTP_DECOMPRESSION_FLAG_GZIP | WINHTTP_DECOMPRESSION_FLAG_DEFLATE; - WinHttpSetOption(httpSessionHandle, WINHTTP_OPTION_DECOMPRESSION, &httpFlags, sizeof(ULONG)); + WinHttpSetOption( + httpSessionHandle, + WINHTTP_OPTION_DECOMPRESSION, + &(ULONG){ WINHTTP_DECOMPRESSION_FLAG_GZIP | WINHTTP_DECOMPRESSION_FLAG_DEFLATE }, + sizeof(ULONG) + ); } if (!(httpConnectionHandle = WinHttpConnect( @@ -427,10 +437,12 @@ NTSTATUS GeoIPUpdateThread( goto CleanupExit; } - { - ULONG option = WINHTTP_DISABLE_KEEP_ALIVE; - WinHttpSetOption(httpRequestHandle, WINHTTP_OPTION_DISABLE_FEATURE, &option, sizeof(ULONG)); - } + WinHttpSetOption( + httpRequestHandle, + WINHTTP_OPTION_DISABLE_FEATURE, + &(ULONG){ WINHTTP_DISABLE_KEEP_ALIVE }, + sizeof(ULONG) + ); SendMessage(context->DialogHandle, TDM_UPDATE_ELEMENT_TEXT, TDE_MAIN_INSTRUCTION, (LPARAM)L"Sending download request..."); diff --git a/plugins/OnlineChecks/upload.c b/plugins/OnlineChecks/upload.c index 0fb00a62503b..5537dadbf63f 100644 --- a/plugins/OnlineChecks/upload.c +++ b/plugins/OnlineChecks/upload.c @@ -1001,8 +1001,12 @@ NTSTATUS UploadCheckThreadStart( if (WindowsVersion >= WINDOWS_8_1) { - ULONG gzipFlags = WINHTTP_DECOMPRESSION_FLAG_ALL; - WinHttpSetOption(context->HttpHandle, WINHTTP_OPTION_DECOMPRESSION, &gzipFlags, sizeof(ULONG)); + WinHttpSetOption( + context->HttpHandle, + WINHTTP_OPTION_DECOMPRESSION, + &(ULONG){ WINHTTP_DECOMPRESSION_FLAG_ALL }, + sizeof(ULONG) + ); } switch (context->Service) diff --git a/plugins/OnlineChecks/virustotal.c b/plugins/OnlineChecks/virustotal.c index 4e7ed4ee645a..a32907038f96 100644 --- a/plugins/OnlineChecks/virustotal.c +++ b/plugins/OnlineChecks/virustotal.c @@ -321,8 +321,12 @@ PSTR VirusTotalSendHttpRequest( if (WindowsVersion >= WINDOWS_8_1) { - ULONG gzipFlags = WINHTTP_DECOMPRESSION_FLAG_GZIP | WINHTTP_DECOMPRESSION_FLAG_DEFLATE; - WinHttpSetOption(httpSessionHandle, WINHTTP_OPTION_DECOMPRESSION, &gzipFlags, sizeof(ULONG)); + WinHttpSetOption( + httpSessionHandle, + WINHTTP_OPTION_DECOMPRESSION, + &(ULONG){ WINHTTP_DECOMPRESSION_FLAG_GZIP | WINHTTP_DECOMPRESSION_FLAG_DEFLATE }, + sizeof(ULONG) + ); } if (!(connectHandle = WinHttpConnect( @@ -465,8 +469,12 @@ PVIRUSTOTAL_FILE_REPORT_RESULT VirusTotalSendHttpFileReportRequest( if (WindowsVersion >= WINDOWS_8_1) { - ULONG httpFlags = WINHTTP_DECOMPRESSION_FLAG_GZIP | WINHTTP_DECOMPRESSION_FLAG_DEFLATE; - WinHttpSetOption(httpSessionHandle, WINHTTP_OPTION_DECOMPRESSION, &httpFlags, sizeof(ULONG)); + WinHttpSetOption( + httpSessionHandle, + WINHTTP_OPTION_DECOMPRESSION, + &(ULONG){ WINHTTP_DECOMPRESSION_FLAG_GZIP | WINHTTP_DECOMPRESSION_FLAG_DEFLATE }, + sizeof(ULONG) + ); } if (!(connectHandle = WinHttpConnect( diff --git a/plugins/Updater/updater.c b/plugins/Updater/updater.c index 29b737f7c63d..c09751490822 100644 --- a/plugins/Updater/updater.c +++ b/plugins/Updater/updater.c @@ -364,11 +364,13 @@ BOOLEAN QueryUpdateData( goto CleanupExit; } - { - ULONG keepAlive = WINHTTP_DISABLE_KEEP_ALIVE; - WinHttpSetOption(httpRequestHandle, WINHTTP_OPTION_DISABLE_FEATURE, &keepAlive, sizeof(ULONG)); - } - + WinHttpSetOption( + httpRequestHandle, + WINHTTP_OPTION_DISABLE_FEATURE, + &(ULONG){ WINHTTP_DISABLE_KEEP_ALIVE }, + sizeof(ULONG) + ); + if (versionHeader) { WinHttpAddRequestHeaders( @@ -775,8 +777,12 @@ NTSTATUS UpdateDownloadThread( if (WindowsVersion >= WINDOWS_8_1) { - ULONG httpFlags = WINHTTP_DECOMPRESSION_FLAG_GZIP | WINHTTP_DECOMPRESSION_FLAG_DEFLATE; - WinHttpSetOption(httpSessionHandle, WINHTTP_OPTION_DECOMPRESSION, &httpFlags, sizeof(ULONG)); + WinHttpSetOption( + httpSessionHandle, + WINHTTP_OPTION_DECOMPRESSION, + &(ULONG){ WINHTTP_DECOMPRESSION_FLAG_GZIP | WINHTTP_DECOMPRESSION_FLAG_DEFLATE }, + sizeof(ULONG) + ); } if (!(httpConnectionHandle = WinHttpConnect( @@ -804,10 +810,12 @@ NTSTATUS UpdateDownloadThread( goto CleanupExit; } - { - ULONG keepAlive = WINHTTP_DISABLE_KEEP_ALIVE; - WinHttpSetOption(httpRequestHandle, WINHTTP_OPTION_DISABLE_FEATURE, &keepAlive, sizeof(ULONG)); - } + WinHttpSetOption( + httpRequestHandle, + WINHTTP_OPTION_DISABLE_FEATURE, + &(ULONG){ WINHTTP_DISABLE_KEEP_ALIVE }, + sizeof(ULONG) + ); SendMessage(context->DialogHandle, TDM_UPDATE_ELEMENT_TEXT, TDE_MAIN_INSTRUCTION, (LPARAM)L"Sending download request..."); From e5df262b7b04e64506bf439c53354e1b766ac53b Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 18 Jun 2017 17:14:10 +1000 Subject: [PATCH 0224/2058] Updater: Re-enable express setup for updates --- plugins/Updater/page5.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/Updater/page5.c b/plugins/Updater/page5.c index 0a94def0107c..0b766debcfeb 100644 --- a/plugins/Updater/page5.c +++ b/plugins/Updater/page5.c @@ -66,7 +66,7 @@ HRESULT CALLBACK FinalTaskDialogCallbackProc( break; info.lpFile = PhGetStringOrEmpty(context->SetupFilePath); - //info.lpParameters = L"-update"; + info.lpParameters = L"-update"; info.lpVerb = PhGetOwnTokenAttributes().Elevated ? NULL : L"runas"; info.nShow = SW_SHOW; info.hwnd = hwndDlg; From d8bd0829415215520d2cd2d6b283bf752eed0dfd Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 20 Jun 2017 21:22:46 +1000 Subject: [PATCH 0225/2058] Tidy up code --- ProcessHacker/appsup.c | 36 +++++++++++++++++----------------- ProcessHacker/include/appsup.h | 11 ++++++++--- ProcessHacker/procgrp.c | 20 +++++++++---------- plugins/ToolStatus/main.c | 26 ++++++++---------------- plugins/ToolStatus/toolbar.c | 24 ++++++----------------- 5 files changed, 50 insertions(+), 67 deletions(-) diff --git a/ProcessHacker/appsup.c b/ProcessHacker/appsup.c index 163045b58ea1..44c042089b49 100644 --- a/ProcessHacker/appsup.c +++ b/ProcessHacker/appsup.c @@ -711,18 +711,18 @@ BOOLEAN PhaGetProcessKnownCommandLine( } VOID PhEnumChildWindows( - _In_opt_ HWND hWnd, + _In_opt_ HWND WindowHandle, _In_ ULONG Limit, - _In_ WNDENUMPROC Callback, - _In_ LPARAM lParam + _In_ PH_CHILD_ENUM_CALLBACK Callback, + _In_ PVOID Context ) { HWND childWindow = NULL; ULONG i = 0; - while (i < Limit && (childWindow = FindWindowEx(hWnd, childWindow, NULL, NULL))) + while (i < Limit && (childWindow = FindWindowEx(WindowHandle, childWindow, NULL, NULL))) { - if (!Callback(childWindow, lParam)) + if (!Callback(childWindow, Context)) return; i++; @@ -738,36 +738,36 @@ typedef struct _GET_PROCESS_MAIN_WINDOW_CONTEXT BOOLEAN SkipInvisible; } GET_PROCESS_MAIN_WINDOW_CONTEXT, *PGET_PROCESS_MAIN_WINDOW_CONTEXT; -BOOL CALLBACK PhpGetProcessMainWindowEnumWindowsProc( - _In_ HWND hwnd, - _In_ LPARAM lParam +BOOLEAN CALLBACK PhpGetProcessMainWindowEnumWindowsProc( + _In_ HWND WindowHandle, + _In_opt_ PVOID Context ) { - PGET_PROCESS_MAIN_WINDOW_CONTEXT context = (PGET_PROCESS_MAIN_WINDOW_CONTEXT)lParam; + PGET_PROCESS_MAIN_WINDOW_CONTEXT context = (PGET_PROCESS_MAIN_WINDOW_CONTEXT)Context; ULONG processId; HWND parentWindow; WINDOWINFO windowInfo; - if (context->SkipInvisible && !IsWindowVisible(hwnd)) + if (context->SkipInvisible && !IsWindowVisible(WindowHandle)) return TRUE; - GetWindowThreadProcessId(hwnd, &processId); + GetWindowThreadProcessId(WindowHandle, &processId); if (UlongToHandle(processId) == context->ProcessId && (context->SkipInvisible ? - !((parentWindow = GetParent(hwnd)) && IsWindowVisible(parentWindow)) && // skip windows with a visible parent - PhGetWindowTextEx(hwnd, PH_GET_WINDOW_TEXT_INTERNAL | PH_GET_WINDOW_TEXT_LENGTH_ONLY, NULL) != 0 : TRUE)) // skip windows with no title + !((parentWindow = GetParent(WindowHandle)) && IsWindowVisible(parentWindow)) && // skip windows with a visible parent + PhGetWindowTextEx(WindowHandle, PH_GET_WINDOW_TEXT_INTERNAL | PH_GET_WINDOW_TEXT_LENGTH_ONLY, NULL) != 0 : TRUE)) // skip windows with no title { if (!context->ImmersiveWindow && context->IsImmersive && - GetProp(hwnd, L"Windows.ImmersiveShell.IdentifyAsMainCoreWindow")) + GetProp(WindowHandle, L"Windows.ImmersiveShell.IdentifyAsMainCoreWindow")) { - context->ImmersiveWindow = hwnd; + context->ImmersiveWindow = WindowHandle; } windowInfo.cbSize = sizeof(WINDOWINFO); - if (!context->Window && GetWindowInfo(hwnd, &windowInfo) && (windowInfo.dwStyle & WS_DLGFRAME)) + if (!context->Window && GetWindowInfo(WindowHandle, &windowInfo) && (windowInfo.dwStyle & WS_DLGFRAME)) { - context->Window = hwnd; + context->Window = WindowHandle; // If we're not looking at an immersive process, there's no need to search any more windows. if (!context->IsImmersive) @@ -807,7 +807,7 @@ HWND PhGetProcessMainWindowEx( if (processHandle && IsImmersiveProcess_I) context.IsImmersive = IsImmersiveProcess_I(processHandle); - PhEnumChildWindows(NULL, 0x800, PhpGetProcessMainWindowEnumWindowsProc, (LPARAM)&context); + PhEnumChildWindows(NULL, 0x800, PhpGetProcessMainWindowEnumWindowsProc, &context); if (!ProcessHandle && processHandle) NtClose(processHandle); diff --git a/ProcessHacker/include/appsup.h b/ProcessHacker/include/appsup.h index 0973ce98f32a..db93af4c9627 100644 --- a/ProcessHacker/include/appsup.h +++ b/ProcessHacker/include/appsup.h @@ -97,11 +97,16 @@ PhaGetProcessKnownCommandLine( ); // end_phapppub +typedef BOOLEAN (CALLBACK *PH_CHILD_ENUM_CALLBACK)( + _In_ HWND WindowHandle, + _In_opt_ PVOID Context + ); + VOID PhEnumChildWindows( - _In_opt_ HWND hWnd, + _In_opt_ HWND WindowHandle, _In_ ULONG Limit, - _In_ WNDENUMPROC Callback, - _In_ LPARAM lParam + _In_ PH_CHILD_ENUM_CALLBACK Callback, + _In_ PVOID Context ); HWND PhGetProcessMainWindow( diff --git a/ProcessHacker/procgrp.c b/ProcessHacker/procgrp.c index e0e38b8ca587..be3325709507 100644 --- a/ProcessHacker/procgrp.c +++ b/ProcessHacker/procgrp.c @@ -114,29 +114,29 @@ typedef struct _QUERY_WINDOWS_CONTEXT PPH_HASHTABLE ProcessDataHashtable; } QUERY_WINDOWS_CONTEXT, *PQUERY_WINDOWS_CONTEXT; -BOOL CALLBACK PhpQueryWindowsEnumWindowsProc( - _In_ HWND hwnd, - _In_ LPARAM lParam +BOOLEAN CALLBACK PhpQueryWindowsEnumWindowsProc( + _In_ HWND WindowHandle, + _In_opt_ PVOID Context ) { - PQUERY_WINDOWS_CONTEXT context = (PQUERY_WINDOWS_CONTEXT)lParam; + PQUERY_WINDOWS_CONTEXT context = (PQUERY_WINDOWS_CONTEXT)Context; ULONG processId; PPHP_PROCESS_DATA processData; HWND parentWindow; - if (!IsWindowVisible(hwnd)) + if (!IsWindowVisible(WindowHandle)) return TRUE; - GetWindowThreadProcessId(hwnd, &processId); + GetWindowThreadProcessId(WindowHandle, &processId); processData = PhFindItemSimpleHashtable2(context->ProcessDataHashtable, UlongToHandle(processId)); if (!processData || processData->WindowHandle) return TRUE; - if (!((parentWindow = GetParent(hwnd)) && IsWindowVisible(parentWindow)) && // Skip windows with a visible parent - PhGetWindowTextEx(hwnd, PH_GET_WINDOW_TEXT_INTERNAL | PH_GET_WINDOW_TEXT_LENGTH_ONLY, NULL) != 0) // Skip windows with no title + if (!((parentWindow = GetParent(WindowHandle)) && IsWindowVisible(parentWindow)) && // Skip windows with a visible parent + PhGetWindowTextEx(WindowHandle, PH_GET_WINDOW_TEXT_INTERNAL | PH_GET_WINDOW_TEXT_LENGTH_ONLY, NULL) != 0) // Skip windows with no title { - processData->WindowHandle = hwnd; + processData->WindowHandle = WindowHandle; } return TRUE; @@ -285,7 +285,7 @@ PPH_LIST PhCreateProcessGroupList( PhpProcessDataListToHashtable(processDataList, &processDataHashtable); queryWindowsContext.ProcessDataHashtable = processDataHashtable; - PhEnumChildWindows(NULL, 0x800, PhpQueryWindowsEnumWindowsProc, (LPARAM)&queryWindowsContext); + PhEnumChildWindows(NULL, 0x800, PhpQueryWindowsEnumWindowsProc, &queryWindowsContext); processGroupList = PhCreateList(10); diff --git a/plugins/ToolStatus/main.c b/plugins/ToolStatus/main.c index 2c81fa57babb..afd88f8ced2c 100644 --- a/plugins/ToolStatus/main.c +++ b/plugins/ToolStatus/main.c @@ -666,10 +666,8 @@ LRESULT CALLBACK MainWndSubclassProc( PhInvokeCallback(&SearchChangedEvent, SearchboxText); } - - goto DefaultWndProc; } - break; + goto DefaultWndProc; case EN_KILLFOCUS: { if (GET_WM_COMMAND_HWND(wParam, lParam) != SearchboxHandle) @@ -683,10 +681,8 @@ LRESULT CALLBACK MainWndSubclassProc( if (RebarBandExists(REBAR_BAND_ID_SEARCHBOX)) RebarBandRemove(REBAR_BAND_ID_SEARCHBOX); } - - goto DefaultWndProc; } - break; + goto DefaultWndProc; } switch (GET_WM_COMMAND_ID(wParam, lParam)) @@ -720,11 +716,9 @@ LRESULT CALLBACK MainWndSubclassProc( SetFocus(SearchboxHandle); Edit_SetSel(SearchboxHandle, 0, -1); - } - - goto DefaultWndProc; + } } - break; + goto DefaultWndProc; case PHAPP_ID_VIEW_ALWAYSONTOP: { // Let Process Hacker perform the default processing. @@ -734,11 +728,9 @@ LRESULT CALLBACK MainWndSubclassProc( BOOLEAN isAlwaysOnTopEnabled = (BOOLEAN)PhGetIntegerSetting(L"MainWindowAlwaysOnTop"); // Set the pressed button state. - SendMessage(ToolBarHandle, TB_PRESSBUTTON, (WPARAM)PHAPP_ID_VIEW_ALWAYSONTOP, (LPARAM)(MAKELONG(isAlwaysOnTopEnabled, 0))); - - goto DefaultWndProc; + SendMessage(ToolBarHandle, TB_PRESSBUTTON, (WPARAM)PHAPP_ID_VIEW_ALWAYSONTOP, (LPARAM)(MAKELONG(isAlwaysOnTopEnabled, 0))); } - break; + goto DefaultWndProc; case PHAPP_ID_UPDATEINTERVAL_FAST: case PHAPP_ID_UPDATEINTERVAL_NORMAL: case PHAPP_ID_UPDATEINTERVAL_BELOWNORMAL: @@ -749,10 +741,8 @@ LRESULT CALLBACK MainWndSubclassProc( DefSubclassProc(hWnd, uMsg, wParam, lParam); StatusBarUpdate(TRUE); - - goto DefaultWndProc; } - break; + goto DefaultWndProc; case PHAPP_ID_VIEW_UPDATEAUTOMATICALLY: { UpdateAutomatically = !UpdateAutomatically; @@ -1142,7 +1132,7 @@ LRESULT CALLBACK MainWndSubclassProc( // This is an undocumented function exported by user32.dll that // retrieves the hung window represented by a ghost window. static HWND (WINAPI *HungWindowFromGhostWindow_I)( - _In_ HWND hWnd + _In_ HWND WindowHandle ); if (!HungWindowFromGhostWindow_I) diff --git a/plugins/ToolStatus/toolbar.c b/plugins/ToolStatus/toolbar.c index 018cd2b6380f..d5521bcdce06 100644 --- a/plugins/ToolStatus/toolbar.c +++ b/plugins/ToolStatus/toolbar.c @@ -109,23 +109,18 @@ VOID RebarLoadSettings( { if (ToolStatusConfig.ToolBarEnabled && !ToolBarImageList) { - // Enable scaling the Toolbar and images on high-DPI machines. - ToolBarImageSize.cx = PH_SCALE_DPI(16); - ToolBarImageSize.cy = PH_SCALE_DPI(16); - + ToolBarImageSize.cx = PH_SCALE_DPI(GetSystemMetrics(SM_CXSMICON)); + ToolBarImageSize.cy = PH_SCALE_DPI(GetSystemMetrics(SM_CYSMICON)); ToolBarImageList = ImageList_Create(ToolBarImageSize.cx, ToolBarImageSize.cy, ILC_COLOR32, 0, 0); } if (ToolStatusConfig.ToolBarEnabled && !RebarHandle) { - REBARINFO rebarInfo = { sizeof(REBARINFO) }; - ULONG toolbarButtonSize; - RebarHandle = CreateWindowEx( WS_EX_TOOLWINDOW, REBARCLASSNAME, NULL, - WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | CCS_NODIVIDER | CCS_TOP | RBS_VARHEIGHT | RBS_AUTOSIZE, // CCS_NOPARENTALIGN | RBS_FIXEDORDER + WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | CCS_NODIVIDER | CCS_TOP | RBS_VARHEIGHT | RBS_AUTOSIZE, // CCS_NOPARENTALIGN CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, PhMainWndHandle, NULL, @@ -137,7 +132,7 @@ VOID RebarLoadSettings( 0, TOOLBARCLASSNAME, NULL, - WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | CCS_NORESIZE | CCS_NOPARENTALIGN | CCS_NODIVIDER | TBSTYLE_FLAT | TBSTYLE_LIST | TBSTYLE_TRANSPARENT | TBSTYLE_TOOLTIPS | TBSTYLE_AUTOSIZE, // TBSTYLE_CUSTOMERASE TBSTYLE_ALTDRAG + WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | CCS_NORESIZE | CCS_NOPARENTALIGN | CCS_NODIVIDER | TBSTYLE_FLAT | TBSTYLE_LIST | TBSTYLE_TRANSPARENT | TBSTYLE_TOOLTIPS | TBSTYLE_AUTOSIZE, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, RebarHandle, NULL, @@ -146,7 +141,7 @@ VOID RebarLoadSettings( ); // Set the rebar info with no imagelist. - SendMessage(RebarHandle, RB_SETBARINFO, 0, (LPARAM)&rebarInfo); + SendMessage(RebarHandle, RB_SETBARINFO, 0, (LPARAM)&(REBARINFO){ sizeof(REBARINFO) }); // Set the toolbar struct size. SendMessage(ToolBarHandle, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0); // Set the toolbar extended toolbar styles. @@ -157,15 +152,9 @@ VOID RebarLoadSettings( ToolbarLoadButtonSettings(); // Resize the toolbar. SendMessage(ToolBarHandle, TB_AUTOSIZE, 0, 0); - // Query the toolbar width and height. - //SendMessage(ToolBarHandle, TB_GETMAXSIZE, 0, (LPARAM)&toolbarSize); - toolbarButtonSize = (ULONG)SendMessage(ToolBarHandle, TB_GETBUTTONSIZE, 0, 0); - - // Enable theming - // SendMessage(RebarHandle, RB_SETWINDOWTHEME, 0, (LPARAM)L"Media"); //Media/Communications/BrowserTabBar/Help - // SendMessage(ToolBarHandle, TB_SETWINDOWTHEME, 0, (LPARAM)L"Media"); //Media/Communications/BrowserTabBar/Help // Inset the toolbar into the rebar control. + ULONG toolbarButtonSize = (ULONG)SendMessage(ToolBarHandle, TB_GETBUTTONSIZE, 0, 0); RebarBandInsert(REBAR_BAND_ID_TOOLBAR, ToolBarHandle, LOWORD(toolbarButtonSize), HIWORD(toolbarButtonSize)); } @@ -181,7 +170,6 @@ VOID RebarLoadSettings( if (ToolStatusConfig.StatusBarEnabled && !StatusBarHandle) { - // Create the StatusBar window. StatusBarHandle = CreateWindowEx( 0, STATUSCLASSNAME, From e1c7fefd1c47fa94b3229e0603b812efb2e295c1 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 20 Jun 2017 21:34:49 +1000 Subject: [PATCH 0226/2058] Move font functions to sdk --- ProcessHacker/appsup.c | 18 ---------- ProcessHacker/include/appsup.h | 5 --- ProcessHacker/include/phapp.h | 59 ++++++++++++++++++++++++++++++++ ProcessHacker/main.c | 28 ++------------- plugins/ToolStatus/customizesb.c | 2 +- plugins/ToolStatus/customizetb.c | 2 +- plugins/include/commonutil.h | 13 ------- 7 files changed, 63 insertions(+), 64 deletions(-) diff --git a/ProcessHacker/appsup.c b/ProcessHacker/appsup.c index 44c042089b49..4271dced71dc 100644 --- a/ProcessHacker/appsup.c +++ b/ProcessHacker/appsup.c @@ -1148,24 +1148,6 @@ BOOLEAN PhGetListViewContextMenuPoint( return FALSE; } -HFONT PhDuplicateFontWithNewWeight( - _In_ HFONT Font, - _In_ LONG NewWeight - ) -{ - LOGFONT logFont; - - if (GetObject(Font, sizeof(LOGFONT), &logFont)) - { - logFont.lfWeight = NewWeight; - return CreateFontIndirect(&logFont); - } - else - { - return NULL; - } -} - VOID PhSetWindowOpacity( _In_ HWND WindowHandle, _In_ ULONG OpacityPercent diff --git a/ProcessHacker/include/appsup.h b/ProcessHacker/include/appsup.h index db93af4c9627..1843bae473ad 100644 --- a/ProcessHacker/include/appsup.h +++ b/ProcessHacker/include/appsup.h @@ -212,11 +212,6 @@ PhGetListViewContextMenuPoint( ); // end_phapppub -HFONT PhDuplicateFontWithNewWeight( - _In_ HFONT Font, - _In_ LONG NewWeight - ); - VOID PhSetWindowOpacity( _In_ HWND WindowHandle, _In_ ULONG OpacityPercent diff --git a/ProcessHacker/include/phapp.h b/ProcessHacker/include/phapp.h index c213449420d2..0237a4cb5ff1 100644 --- a/ProcessHacker/include/phapp.h +++ b/ProcessHacker/include/phapp.h @@ -629,6 +629,32 @@ PhLoadPngImageFromResource( _In_ BOOLEAN RGBAImage ); +FORCEINLINE +HFONT +PhCreateFont( + _In_ PWSTR Name, + _In_ ULONG Size, + _In_ ULONG Weight + ) +{ + return CreateFont( + -(LONG)PhMultiplyDivide(Size, PhGlobalDpi, 72), + 0, + 0, + 0, + Weight, + FALSE, + FALSE, + FALSE, + ANSI_CHARSET, + OUT_DEFAULT_PRECIS, + CLIP_DEFAULT_PRECIS, + DEFAULT_QUALITY, + DEFAULT_PITCH, + Name + ); +} + FORCEINLINE HFONT PhCreateCommonFont( @@ -668,6 +694,39 @@ PhCreateCommonFont( return fontHandle; } + +FORCEINLINE +HFONT +PhDuplicateFont( + _In_ HFONT Font + ) +{ + LOGFONT logFont; + + if (GetObject(Font, sizeof(LOGFONT), &logFont)) + return CreateFontIndirect(&logFont); + + return NULL; +} + +FORCEINLINE +HFONT +PhDuplicateFontWithNewWeight( + _In_ HFONT Font, + _In_ LONG NewWeight + ) +{ + LOGFONT logFont; + + if (GetObject(Font, sizeof(LOGFONT), &logFont)) + { + logFont.lfWeight = NewWeight; + return CreateFontIndirect(&logFont); + } + + return NULL; +} + // end_phapppub // sessmsg diff --git a/ProcessHacker/main.c b/ProcessHacker/main.c index d972aac56428..4aed3dd8f786 100644 --- a/ProcessHacker/main.c +++ b/ProcessHacker/main.c @@ -488,30 +488,6 @@ VOID PhInitializeCommonControls( InitCommonControlsEx(&icex); } -HFONT PhpCreateFont( - _In_ PWSTR Name, - _In_ ULONG Size, - _In_ ULONG Weight - ) -{ - return CreateFont( - -(LONG)PhMultiplyDivide(Size, PhGlobalDpi, 72), - 0, - 0, - 0, - Weight, - FALSE, - FALSE, - FALSE, - ANSI_CHARSET, - OUT_DEFAULT_PRECIS, - CLIP_DEFAULT_PRECIS, - DEFAULT_QUALITY, - DEFAULT_PITCH, - Name - ); -} - VOID PhInitializeFont( _In_ HWND hWnd ) @@ -533,8 +509,8 @@ VOID PhInitializeFont( success = !!SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, &metrics, 0); if ( - !(PhApplicationFont = PhpCreateFont(L"Microsoft Sans Serif", 8, FW_NORMAL)) && - !(PhApplicationFont = PhpCreateFont(L"Tahoma", 8, FW_NORMAL)) + !(PhApplicationFont = PhCreateFont(L"Microsoft Sans Serif", 8, FW_NORMAL)) && + !(PhApplicationFont = PhCreateFont(L"Tahoma", 8, FW_NORMAL)) ) { if (success) diff --git a/plugins/ToolStatus/customizesb.c b/plugins/ToolStatus/customizesb.c index cd4dbd29034d..e8ce99115092 100644 --- a/plugins/ToolStatus/customizesb.c +++ b/plugins/ToolStatus/customizesb.c @@ -319,7 +319,7 @@ INT_PTR CALLBACK CustomizeStatusBarDialogProc( context->MoveDownButtonHandle = GetDlgItem(hwndDlg, IDC_MOVEDOWN); context->AddButtonHandle = GetDlgItem(hwndDlg, IDC_ADD); context->RemoveButtonHandle = GetDlgItem(hwndDlg, IDC_REMOVE); - context->FontHandle = CommonDuplicateFont((HFONT)SendMessage(StatusBarHandle, WM_GETFONT, 0, 0)); + context->FontHandle = PhDuplicateFont((HFONT)SendMessage(StatusBarHandle, WM_GETFONT, 0, 0)); ListBox_SetItemHeight(context->AvailableListHandle, 0, PH_SCALE_DPI(22)); // BitmapHeight ListBox_SetItemHeight(context->CurrentListHandle, 0, PH_SCALE_DPI(22)); // BitmapHeight diff --git a/plugins/ToolStatus/customizetb.c b/plugins/ToolStatus/customizetb.c index cef8fdffbb33..27330c0c74ba 100644 --- a/plugins/ToolStatus/customizetb.c +++ b/plugins/ToolStatus/customizetb.c @@ -523,7 +523,7 @@ INT_PTR CALLBACK CustomizeToolbarDialogProc( context->BrushNormal = GetSysColorBrush(COLOR_WINDOW); context->BrushHot = CreateSolidBrush(RGB(145, 201, 247)); context->BrushPushed = CreateSolidBrush(RGB(153, 209, 255)); - context->FontHandle = CommonDuplicateFont((HFONT)SendMessage(ToolBarHandle, WM_GETFONT, 0, 0)); + context->FontHandle = PhDuplicateFont((HFONT)SendMessage(ToolBarHandle, WM_GETFONT, 0, 0)); ListBox_SetItemHeight(context->AvailableListHandle, 0, context->CXWidth + 6); // BitmapHeight ListBox_SetItemHeight(context->CurrentListHandle, 0, context->CXWidth + 6); // BitmapHeight diff --git a/plugins/include/commonutil.h b/plugins/include/commonutil.h index a6e265992413..c5511468865c 100644 --- a/plugins/include/commonutil.h +++ b/plugins/include/commonutil.h @@ -569,18 +569,5 @@ FormatAnsiString( return FormatAnsiString_V(Format, argptr); } -FORCEINLINE -HFONT -CommonDuplicateFont( - _In_ HFONT Font - ) -{ - LOGFONT logFont; - - if (GetObject(Font, sizeof(LOGFONT), &logFont)) - return CreateFontIndirect(&logFont); - else - return NULL; -} #endif \ No newline at end of file From bbe312f9826dea42826bb92c90474ed91a419ff0 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 21 Jun 2017 21:55:40 +1000 Subject: [PATCH 0227/2058] Add PhCreatePipe/PhCreateNamedPipe --- ProcessHacker/ProcessHacker.def | 2 + ProcessHacker/anawait.c | 4 +- phlib/include/phnative.h | 16 ++++ phlib/native.c | 156 ++++++++++++++++++++++++++++++++ phnt/include/ntioapi.h | 2 + 5 files changed, 179 insertions(+), 1 deletion(-) diff --git a/ProcessHacker/ProcessHacker.def b/ProcessHacker/ProcessHacker.def index 0258a7b3b934..d8af2e8f5d83 100644 --- a/ProcessHacker/ProcessHacker.def +++ b/ProcessHacker/ProcessHacker.def @@ -229,6 +229,8 @@ EXPORTS PhCreateFileWin32 PhCreateFileWin32Ex PhCreateKey + PhCreateNamedPipe + PhCreatePipe PhDeleteFileWin32 PhDisconnectNamedPipe PhEnumDirectoryFile diff --git a/ProcessHacker/anawait.c b/ProcessHacker/anawait.c index cbf30b17eb8a..7f1f75b4bf1b 100644 --- a/ProcessHacker/anawait.c +++ b/ProcessHacker/anawait.c @@ -832,7 +832,9 @@ static VOID PhpInitializeServiceNumbers( // NtReadFile - if (CreatePipe(&pipeReadHandle, &pipeWriteHandle, NULL, 0)) + status = PhCreatePipe(&pipeReadHandle, &pipeWriteHandle); + + if (NT_SUCCESS(status)) { if (threadHandle = PhCreateThread(0, PhpRfThreadStart, pipeReadHandle)) { diff --git a/phlib/include/phnative.h b/phlib/include/phnative.h index 6d1ff9b694fa..41390d6ec34d 100644 --- a/phlib/include/phnative.h +++ b/phlib/include/phnative.h @@ -973,6 +973,22 @@ PhDeleteFileWin32( _In_ PWSTR FileName ); +PHLIBAPI +NTSTATUS +NTAPI +PhCreatePipe( + _Out_ PHANDLE PipeReadHandle, + _Out_ PHANDLE PipeWriteHandle + ); + +PHLIBAPI +NTSTATUS +NTAPI +PhCreateNamedPipe( + _Out_ PHANDLE PipeHandle, + _In_ PWSTR PipeName + ); + PHLIBAPI NTSTATUS NTAPI diff --git a/phlib/native.c b/phlib/native.c index 55a0bfa54840..6394261a6f90 100644 --- a/phlib/native.c +++ b/phlib/native.c @@ -6172,6 +6172,162 @@ NTSTATUS PhDeleteFileWin32( return status; } +/** +* Creates an anonymous pipe. +* +* \param PipeReadHandle The pipe read handle. +* \param PipeWriteHandle The pipe write handle. +*/ +NTSTATUS PhCreatePipe( + _Out_ PHANDLE PipeReadHandle, + _Out_ PHANDLE PipeWriteHandle + ) +{ + NTSTATUS status; + HANDLE pipeDirectoryHandle; + HANDLE pipeReadHandle; + HANDLE pipeWriteHandle; + LARGE_INTEGER pipeTimeout; + UNICODE_STRING pipeNameUs; + OBJECT_ATTRIBUTES oa; + IO_STATUS_BLOCK isb; + + RtlInitUnicodeString(&pipeNameUs, DEVICE_NAMED_PIPE); + InitializeObjectAttributes( + &oa, + &pipeNameUs, + OBJ_CASE_INSENSITIVE, + NULL, + NULL + ); + + status = NtOpenFile( + &pipeDirectoryHandle, + GENERIC_READ | SYNCHRONIZE, + &oa, + &isb, + FILE_SHARE_READ | FILE_SHARE_WRITE, + FILE_SYNCHRONOUS_IO_NONALERT + ); + + if (!NT_SUCCESS(status)) + return status; + + InitializeObjectAttributes( + &oa, + &pipeNameUs, + OBJ_CASE_INSENSITIVE, + pipeDirectoryHandle, + NULL + ); + + status = NtCreateNamedPipeFile( + &pipeReadHandle, + FILE_WRITE_ATTRIBUTES | GENERIC_READ | SYNCHRONIZE, + &oa, + &isb, + FILE_SHARE_READ | FILE_SHARE_WRITE, + FILE_CREATE, + FILE_PIPE_INBOUND | FILE_SYNCHRONOUS_IO_NONALERT, + FILE_PIPE_BYTE_STREAM_TYPE, + FILE_PIPE_BYTE_STREAM_MODE, + FILE_PIPE_QUEUE_OPERATION, + PIPE_UNLIMITED_INSTANCES, // min: 1, max: ULONG_MAX + PAGE_SIZE, + PAGE_SIZE, + PhTimeoutFromMilliseconds(&pipeTimeout, 500) + ); + + if (!NT_SUCCESS(status)) + { + NtClose(pipeDirectoryHandle); + return status; + } + + InitializeObjectAttributes( + &oa, + &pipeNameUs, + OBJ_CASE_INSENSITIVE, + pipeReadHandle, + NULL + ); + + status = NtOpenFile( + &pipeWriteHandle, + FILE_READ_ATTRIBUTES | GENERIC_WRITE | SYNCHRONIZE, + &oa, + &isb, + FILE_SHARE_READ | FILE_SHARE_WRITE, + FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT + ); + + if (NT_SUCCESS(status)) + { + *PipeReadHandle = pipeReadHandle; + *PipeWriteHandle = pipeWriteHandle; + } + + NtClose(pipeDirectoryHandle); + return status; +} + +/** +* Creates an named pipe. +* +* \param PipeHandle The pipe read/write handle. +* \param PipeName The pipe name. +*/ +NTSTATUS PhCreateNamedPipe( + _Out_ PHANDLE PipeHandle, + _In_ PWSTR PipeName + ) +{ + NTSTATUS status; + HANDLE pipeHandle; + PPH_STRING pipeName; + LARGE_INTEGER pipeTimeout; + UNICODE_STRING pipeNameUs; + OBJECT_ATTRIBUTES oa; + IO_STATUS_BLOCK isb; + + pipeName = PhConcatStrings2(DEVICE_NAMED_PIPE, PipeName); + PhStringRefToUnicodeString(&pipeName->sr, &pipeNameUs); + PhTimeoutFromMilliseconds(&pipeTimeout, 500); + + InitializeObjectAttributes( + &oa, + &pipeNameUs, + OBJ_CASE_INSENSITIVE, + NULL, + NULL + ); + + status = NtCreateNamedPipeFile( + &pipeHandle, + FILE_GENERIC_READ | FILE_GENERIC_WRITE, + &oa, + &isb, + FILE_SHARE_READ | FILE_SHARE_WRITE, + FILE_CREATE, + FILE_PIPE_FULL_DUPLEX | FILE_SYNCHRONOUS_IO_NONALERT, + FILE_PIPE_MESSAGE_TYPE, + FILE_PIPE_MESSAGE_MODE, + FILE_PIPE_QUEUE_OPERATION, + PIPE_UNLIMITED_INSTANCES, // min: 1, max: ULONG_MAX + PAGE_SIZE, + PAGE_SIZE, + &pipeTimeout + ); + + if (NT_SUCCESS(status)) + { + *PipeHandle = pipeHandle; + } + + PhDereferenceObject(pipeName); + return status; +} + NTSTATUS PhListenNamedPipe( _In_ HANDLE FileHandle, _In_opt_ HANDLE Event, diff --git a/phnt/include/ntioapi.h b/phnt/include/ntioapi.h index 84e9c53724a2..c13aa19c3721 100644 --- a/phnt/include/ntioapi.h +++ b/phnt/include/ntioapi.h @@ -1667,6 +1667,8 @@ typedef struct _REPARSE_DATA_BUFFER // Named pipe FS control definitions +#define DEVICE_NAMED_PIPE L"\\Device\\NamedPipe\\" + #define FSCTL_PIPE_ASSIGN_EVENT CTL_CODE(FILE_DEVICE_NAMED_PIPE, 0, METHOD_BUFFERED, FILE_ANY_ACCESS) #define FSCTL_PIPE_DISCONNECT CTL_CODE(FILE_DEVICE_NAMED_PIPE, 1, METHOD_BUFFERED, FILE_ANY_ACCESS) #define FSCTL_PIPE_LISTEN CTL_CODE(FILE_DEVICE_NAMED_PIPE, 2, METHOD_BUFFERED, FILE_ANY_ACCESS) From 4745882618f8fb8cf15bcea783a562b1ccac878c Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 21 Jun 2017 21:56:51 +1000 Subject: [PATCH 0228/2058] Fix typo --- phlib/native.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/phlib/native.c b/phlib/native.c index 6394261a6f90..0a5bc388b634 100644 --- a/phlib/native.c +++ b/phlib/native.c @@ -6213,6 +6213,7 @@ NTSTATUS PhCreatePipe( if (!NT_SUCCESS(status)) return status; + RtlInitUnicodeString(&pipeNameUs, UNICODE_NULL); InitializeObjectAttributes( &oa, &pipeNameUs, @@ -6244,6 +6245,7 @@ NTSTATUS PhCreatePipe( return status; } + RtlInitUnicodeString(&pipeNameUs, UNICODE_NULL); InitializeObjectAttributes( &oa, &pipeNameUs, From 5e95d1b3b0aa6dbb0c2e6706de9ed0a226aa42ce Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 22 Jun 2017 14:27:31 +1000 Subject: [PATCH 0229/2058] Update imports --- phlib/apiimport.c | 6 +++--- phlib/symprv.c | 8 ++++---- phlib/treenew.c | 2 +- phlib/util.c | 4 ++-- plugins/OnlineChecks/upload.c | 2 +- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/phlib/apiimport.c b/phlib/apiimport.c index bcf06a49574a..12e2bc7e52d5 100644 --- a/phlib/apiimport.c +++ b/phlib/apiimport.c @@ -30,18 +30,18 @@ PVOID PhpImportProcedure( _In_ PSTR ProcedureName ) { - HMODULE module; + PVOID module; PVOID procedure; if (*CacheValid) return *Cache; - module = GetModuleHandle(ModuleName); + module = PhGetDllHandle(ModuleName); if (!module) return NULL; - procedure = GetProcAddress(module, ProcedureName); + procedure = PhGetProcedureAddress(module, ProcedureName, 0); *Cache = procedure; MemoryBarrier(); *CacheValid = TRUE; diff --git a/phlib/symprv.c b/phlib/symprv.c index 641ad92da130..2065b1887c1a 100644 --- a/phlib/symprv.c +++ b/phlib/symprv.c @@ -112,8 +112,8 @@ VOID PhSymbolProviderCompleteInitialization( _In_opt_ PVOID DbgHelpBase ) { - HMODULE dbghelpHandle; - HMODULE symsrvHandle; + PVOID dbghelpHandle; + PVOID symsrvHandle; // The user should have loaded dbghelp.dll and symsrv.dll already. If not, it's not our problem. @@ -122,9 +122,9 @@ VOID PhSymbolProviderCompleteInitialization( if (DbgHelpBase) dbghelpHandle = DbgHelpBase; else - dbghelpHandle = GetModuleHandle(L"dbghelp.dll"); + dbghelpHandle = PhGetDllHandle(L"dbghelp.dll"); - symsrvHandle = GetModuleHandle(L"symsrv.dll"); + symsrvHandle = PhGetDllHandle(L"symsrv.dll"); SymInitialize_I = PhGetProcedureAddress(dbghelpHandle, "SymInitialize", 0); SymCleanup_I = PhGetProcedureAddress(dbghelpHandle, "SymCleanup", 0); diff --git a/phlib/treenew.c b/phlib/treenew.c index 6466a00bae9f..f5bef8b20da0 100644 --- a/phlib/treenew.c +++ b/phlib/treenew.c @@ -77,7 +77,7 @@ BOOLEAN PhTreeNewInitialization( if (!RegisterClassEx(&c)) return FALSE; - ComCtl32Handle = GetModuleHandle(L"comctl32.dll"); + ComCtl32Handle = PhGetDllHandle(L"comctl32.dll"); SmallIconWidth = GetSystemMetrics(SM_CXSMICON); SmallIconHeight = GetSystemMetrics(SM_CYSMICON); diff --git a/phlib/util.c b/phlib/util.c index 27ce988d2135..8084ead139cf 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -301,7 +301,7 @@ PPH_STRING PhGetNtMessage( PPH_STRING message; if (!NT_NTWIN32(Status)) - message = PhGetMessage(GetModuleHandle(L"ntdll.dll"), 0xb, GetUserDefaultLangID(), (ULONG)Status); + message = PhGetMessage(PhGetDllHandle(L"ntdll.dll"), 0xb, GetUserDefaultLangID(), (ULONG)Status); else message = PhGetWin32Message(WIN32_FROM_NTSTATUS(Status)); @@ -343,7 +343,7 @@ PPH_STRING PhGetWin32Message( { PPH_STRING message; - message = PhGetMessage(GetModuleHandle(L"kernel32.dll"), 0xb, GetUserDefaultLangID(), Result); + message = PhGetMessage(PhGetDllHandle(L"kernel32.dll"), 0xb, GetUserDefaultLangID(), Result); if (message) PhTrimToNullTerminatorString(message); diff --git a/plugins/OnlineChecks/upload.c b/plugins/OnlineChecks/upload.c index 5537dadbf63f..f1040c0bfd7b 100644 --- a/plugins/OnlineChecks/upload.c +++ b/plugins/OnlineChecks/upload.c @@ -96,7 +96,7 @@ VOID RaiseUploadError( if (!Context->DialogHandle) return; - if (message = PhGetMessage(GetModuleHandle(L"winhttp.dll"), 0xb, GetUserDefaultLangID(), ErrorCode)) + if (message = PhGetMessage(PhGetDllHandle(L"winhttp.dll"), 0xb, GetUserDefaultLangID(), ErrorCode)) { PhTrimToNullTerminatorString(message); } From f3f0bda881c352b9c695017b1862cd430d6a31b8 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 22 Jun 2017 18:31:51 +1000 Subject: [PATCH 0230/2058] Update PhCreateThread, Remove legacy imports --- ProcessHacker/include/procprp.h | 2 +- ProcessHacker/mdump.c | 14 +--------- ProcessHacker/memsrch.c | 16 +---------- ProcessHacker/options.c | 7 ++--- ProcessHacker/phsvc/svcapiport.c | 6 +--- ProcessHacker/procprp.c | 17 ++---------- ProcessHacker/srvprv.c | 27 ++---------------- phlib/basesup.c | 47 ++++++++++++++++++++++++++++---- phlib/include/phbasesup.h | 8 ++++++ 9 files changed, 61 insertions(+), 83 deletions(-) diff --git a/ProcessHacker/include/procprp.h b/ProcessHacker/include/procprp.h index 3da58d000c31..065926df5f2a 100644 --- a/ProcessHacker/include/procprp.h +++ b/ProcessHacker/include/procprp.h @@ -156,7 +156,7 @@ PhEndPropPageLayout( } PHAPPAPI -BOOLEAN +VOID NTAPI PhShowProcessProperties( _In_ PPH_PROCESS_PROPCONTEXT Context diff --git a/ProcessHacker/mdump.c b/ProcessHacker/mdump.c index e40ab800a630..8214941f406a 100644 --- a/ProcessHacker/mdump.c +++ b/ProcessHacker/mdump.c @@ -48,7 +48,6 @@ typedef struct _PROCESS_MINIDUMP_CONTEXT HANDLE FileHandle; HWND WindowHandle; - HANDLE ThreadHandle; BOOLEAN Stop; BOOLEAN Succeeded; @@ -377,25 +376,14 @@ INT_PTR CALLBACK PhpProcessMiniDumpDlgProc( SendMessage(GetDlgItem(hwndDlg, IDC_PROGRESS), PBM_SETMARQUEE, TRUE, 75); context->WindowHandle = hwndDlg; - context->ThreadHandle = PhCreateThread(0, PhpProcessMiniDumpThreadStart, context); - if (!context->ThreadHandle) - { - PhShowStatus(hwndDlg, L"Unable to create the minidump thread", 0, GetLastError()); - EndDialog(hwndDlg, IDCANCEL); - } + PhCreateThread2(PhpProcessMiniDumpThreadStart, context); SetTimer(hwndDlg, 1, 500, NULL); } break; case WM_DESTROY: { - PPROCESS_MINIDUMP_CONTEXT context; - - context = (PPROCESS_MINIDUMP_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom()); - - NtClose(context->ThreadHandle); - RemoveProp(hwndDlg, PhMakeContextAtom()); } break; diff --git a/ProcessHacker/memsrch.c b/ProcessHacker/memsrch.c index 0440ff6f4b30..fb22ff01d98a 100644 --- a/ProcessHacker/memsrch.c +++ b/ProcessHacker/memsrch.c @@ -44,7 +44,6 @@ typedef struct _MEMORY_STRING_CONTEXT BOOLEAN Mapped; HWND WindowHandle; - HANDLE ThreadHandle; PH_MEMORY_STRING_OPTIONS Options; PPH_LIST Results; } MEMORY_STRING_CONTEXT, *PMEMORY_STRING_CONTEXT; @@ -653,27 +652,14 @@ INT_PTR CALLBACK PhpMemoryStringProgressDlgProc( SendMessage(GetDlgItem(hwndDlg, IDC_PROGRESS), PBM_SETMARQUEE, TRUE, 75); context->WindowHandle = hwndDlg; - context->ThreadHandle = PhCreateThread(0, PhpMemoryStringThreadStart, context); - if (!context->ThreadHandle) - { - PhShowStatus(hwndDlg, L"Unable to create the search thread", 0, GetLastError()); - EndDialog(hwndDlg, IDCANCEL); - return FALSE; - } + PhCreateThread2(PhpMemoryStringThreadStart, context); SetTimer(hwndDlg, 1, 500, NULL); } break; case WM_DESTROY: { - PMEMORY_STRING_CONTEXT context; - - context = (PMEMORY_STRING_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom()); - - if (context->ThreadHandle) - NtClose(context->ThreadHandle); - RemoveProp(hwndDlg, PhMakeContextAtom()); } break; diff --git a/ProcessHacker/options.c b/ProcessHacker/options.c index 988c32d5a3cb..4f27c293ce3e 100644 --- a/ProcessHacker/options.c +++ b/ProcessHacker/options.c @@ -883,7 +883,6 @@ INT_PTR CALLBACK PhpOptionsAdvancedDlgProc( { case IDC_CHANGE: { - HANDLE threadHandle; RECT windowRect; // Save the options so they don't get "overwritten" when @@ -892,15 +891,13 @@ INT_PTR CALLBACK PhpOptionsAdvancedDlgProc( GetWindowRect(GetParent(hwndDlg), &windowRect); WindowHandleForElevate = hwndDlg; - threadHandle = PhCreateThread(0, PhpElevateAdvancedThreadStart, PhFormatString( + + PhCreateThread2(PhpElevateAdvancedThreadStart, PhFormatString( L"-showoptions -hwnd %Ix -point %u,%u", (ULONG_PTR)GetParent(hwndDlg), windowRect.left + 20, windowRect.top + 20 )); - - if (threadHandle) - NtClose(threadHandle); } break; case IDC_SAMPLECOUNTAUTOMATIC: diff --git a/ProcessHacker/phsvc/svcapiport.c b/ProcessHacker/phsvc/svcapiport.c index fb31465e3e3c..7bfb8ebf49b8 100644 --- a/ProcessHacker/phsvc/svcapiport.c +++ b/ProcessHacker/phsvc/svcapiport.c @@ -48,7 +48,6 @@ NTSTATUS PhSvcApiPortInitialization( PSID administratorsSid; PACL dacl; ULONG i; - HANDLE threadHandle; // Create the API port. @@ -99,10 +98,7 @@ NTSTATUS PhSvcApiPortInitialization( for (i = 0; i < 2; i++) { - threadHandle = PhCreateThread(0, PhSvcApiRequestThreadStart, NULL); - - if (threadHandle) - NtClose(threadHandle); + PhCreateThread2(PhSvcApiRequestThreadStart, NULL); } return status; diff --git a/ProcessHacker/procprp.c b/ProcessHacker/procprp.c index bf6e302925ef..ae884db625e5 100644 --- a/ProcessHacker/procprp.c +++ b/ProcessHacker/procprp.c @@ -704,23 +704,10 @@ NTSTATUS PhpProcessPropertiesThreadStart( return STATUS_SUCCESS; } -BOOLEAN PhShowProcessProperties( +VOID PhShowProcessProperties( _In_ PPH_PROCESS_PROPCONTEXT Context ) { - HANDLE threadHandle; - PhReferenceObject(Context); - threadHandle = PhCreateThread(0, PhpProcessPropertiesThreadStart, Context); - - if (threadHandle) - { - NtClose(threadHandle); - return TRUE; - } - else - { - PhDereferenceObject(Context); - return FALSE; - } + PhCreateThread2(PhpProcessPropertiesThreadStart, Context); } diff --git a/ProcessHacker/srvprv.c b/ProcessHacker/srvprv.c index 22ae892d9122..fc2d8b6d1ba9 100644 --- a/ProcessHacker/srvprv.c +++ b/ProcessHacker/srvprv.c @@ -29,12 +29,6 @@ #include #include -typedef DWORD (WINAPI *_NotifyServiceStatusChangeW)( - _In_ SC_HANDLE hService, - _In_ DWORD dwNotifyMask, - _In_ PSERVICE_NOTIFYW pNotifyBuffer - ); - typedef struct _PHP_SERVICE_NAME_ENTRY { PH_HASH_ENTRY HashEntry; @@ -89,7 +83,6 @@ VOID PhpInitializeServiceNonPoll( ); PPH_OBJECT_TYPE PhServiceItemType; - PPH_HASHTABLE PhServiceHashtable; PH_QUEUED_LOCK PhServiceHashtableLock = PH_QUEUED_LOCK_INIT; @@ -101,9 +94,7 @@ PHAPPAPI PH_CALLBACK_DECLARE(PhServicesUpdatedEvent); BOOLEAN PhEnableServiceNonPoll = FALSE; static BOOLEAN PhpNonPollInitialized = FALSE; static BOOLEAN PhpNonPollActive = FALSE; -static HANDLE PhpNonPollThreadHandle; static ULONG PhpNonPollGate; -static _NotifyServiceStatusChangeW NotifyServiceStatusChangeW_I; static HANDLE PhpNonPollEventHandle; static PH_QUEUED_LOCK PhpNonPollServiceListLock = PH_QUEUED_LOCK_INIT; static LIST_ENTRY PhpNonPollServiceListHead; @@ -939,7 +930,8 @@ NTSTATUS PhpServiceNonPollThreadStart( notifyContext->Buffer.dwVersion = SERVICE_NOTIFY_STATUS_CHANGE; notifyContext->Buffer.pfnNotifyCallback = PhpServiceNonPollScNotifyCallback; notifyContext->Buffer.pContext = notifyContext; - result = NotifyServiceStatusChangeW_I( + + result = NotifyServiceStatusChange( notifyContext->ServiceHandle, notifyContext->IsServiceManager ? (SERVICE_NOTIFY_CREATED | SERVICE_NOTIFY_DELETED) @@ -1017,21 +1009,8 @@ VOID PhpInitializeServiceNonPoll( VOID ) { - // Dynamically import the required functions. - - NotifyServiceStatusChangeW_I = PhGetModuleProcAddress(L"advapi32.dll", "NotifyServiceStatusChangeW"); - - if (!NotifyServiceStatusChangeW_I) - return; - PhpNonPollActive = TRUE; PhpNonPollGate = 1; // initially the gate should be open since we only just initialized everything - PhpNonPollThreadHandle = PhCreateThread(0, PhpServiceNonPollThreadStart, NULL); - - if (!PhpNonPollThreadHandle) - { - PhpNonPollActive = FALSE; - return; - } + PhCreateThread2(PhpServiceNonPollThreadStart, NULL); } diff --git a/phlib/basesup.c b/phlib/basesup.c index 61ee300a3574..358bcbb9fe07 100644 --- a/phlib/basesup.c +++ b/phlib/basesup.c @@ -243,16 +243,18 @@ HANDLE PhCreateThread( context->StartAddress = StartAddress; context->Parameter = Parameter; - threadHandle = CreateThread( + if (NT_SUCCESS(RtlCreateUserThread( + NtCurrentProcess(), NULL, + FALSE, + 0, + 0, StackSize, PhpBaseThreadStart, context, - 0, + &threadHandle, NULL - ); - - if (threadHandle) + ))) { PHLIB_INC_STATISTIC(BaseThreadsCreated); return threadHandle; @@ -265,6 +267,41 @@ HANDLE PhCreateThread( } } +VOID PhCreateThread2( + _In_ PUSER_THREAD_START_ROUTINE StartAddress, + _In_opt_ PVOID Parameter + ) +{ + HANDLE threadHandle; + PPHP_BASE_THREAD_CONTEXT context; + + context = PhAllocateFromFreeList(&PhpBaseThreadContextFreeList); + context->StartAddress = StartAddress; + context->Parameter = Parameter; + + if (NT_SUCCESS(RtlCreateUserThread( + NtCurrentProcess(), + NULL, + FALSE, + 0, + 0, + 0, + PhpBaseThreadStart, + context, + &threadHandle, + NULL + ))) + { + PHLIB_INC_STATISTIC(BaseThreadsCreated); + NtClose(threadHandle); + } + else + { + PHLIB_INC_STATISTIC(BaseThreadsCreateFailed); + PhFreeToFreeList(&PhpBaseThreadContextFreeList, context); + } +} + /** * Gets the current system time (UTC). * diff --git a/phlib/include/phbasesup.h b/phlib/include/phbasesup.h index f59e12f07c38..3c75c1eecefe 100644 --- a/phlib/include/phbasesup.h +++ b/phlib/include/phbasesup.h @@ -40,6 +40,14 @@ PhCreateThread( _In_opt_ PVOID Parameter ); +PHLIBAPI +VOID +NTAPI +PhCreateThread2( + _In_ PUSER_THREAD_START_ROUTINE StartAddress, + _In_opt_ PVOID Parameter + ); + // DLLs FORCEINLINE From f93d5ccc4ea61befbedef462abb7061bdf2c1bcc Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 22 Jun 2017 18:56:27 +1000 Subject: [PATCH 0231/2058] Update thread functions --- ProcessHacker/ProcessHacker.def | 1 + plugins/HardwareDevices/diskdetails.c | 6 +----- plugins/HardwareDevices/netdetails.c | 6 +----- plugins/NetworkTools/ping.c | 12 ++---------- plugins/NetworkTools/tracert.c | 17 +++-------------- plugins/NetworkTools/update.c | 5 +---- plugins/NetworkTools/whois.c | 17 +++-------------- plugins/OnlineChecks/upload.c | 17 +---------------- plugins/Updater/updater.c | 5 +---- tools/peview/include/peview.h | 1 - tools/peview/pdbprp.c | 4 +--- 11 files changed, 15 insertions(+), 76 deletions(-) diff --git a/ProcessHacker/ProcessHacker.def b/ProcessHacker/ProcessHacker.def index d8af2e8f5d83..31e68e0bc05f 100644 --- a/ProcessHacker/ProcessHacker.def +++ b/ProcessHacker/ProcessHacker.def @@ -114,6 +114,7 @@ EXPORTS PhCreateString PhCreateStringEx PhCreateThread + PhCreateThread2 PhDecodeUnicodeDecoder PhDeleteArray PhDeleteBytesBuilder diff --git a/plugins/HardwareDevices/diskdetails.c b/plugins/HardwareDevices/diskdetails.c index 37f18f033e89..a6912b73bb20 100644 --- a/plugins/HardwareDevices/diskdetails.c +++ b/plugins/HardwareDevices/diskdetails.c @@ -755,7 +755,6 @@ VOID ShowDiskDriveDetailsDialog( _In_ PDV_DISK_SYSINFO_CONTEXT Context ) { - HANDLE dialogThread = NULL; PCOMMON_PAGE_CONTEXT pageContext; pageContext = PhAllocate(sizeof(COMMON_PAGE_CONTEXT)); @@ -768,8 +767,5 @@ VOID ShowDiskDriveDetailsDialog( PhSetReference(&pageContext->DiskName, Context->DiskEntry->DiskName); CopyDiskId(&pageContext->DiskId, &Context->DiskEntry->Id); - if (dialogThread = PhCreateThread(0, ShowDiskDriveDetailsDialogThread, pageContext)) - NtClose(dialogThread); - else - FreeDiskDriveDetailsContext(pageContext); + PhCreateThread2(ShowDiskDriveDetailsDialogThread, pageContext); } \ No newline at end of file diff --git a/plugins/HardwareDevices/netdetails.c b/plugins/HardwareDevices/netdetails.c index 983a7ca071db..03cd4e92cf0a 100644 --- a/plugins/HardwareDevices/netdetails.c +++ b/plugins/HardwareDevices/netdetails.c @@ -653,7 +653,6 @@ VOID ShowNetAdapterDetailsDialog( _In_ PDV_NETADAPTER_SYSINFO_CONTEXT Context ) { - HANDLE dialogThread = NULL; PDV_NETADAPTER_DETAILS_CONTEXT context; context = PhAllocate(sizeof(DV_NETADAPTER_DETAILS_CONTEXT)); @@ -663,8 +662,5 @@ VOID ShowNetAdapterDetailsDialog( PhSetReference(&context->AdapterName, Context->AdapterEntry->AdapterName); CopyNetAdapterId(&context->AdapterId, &Context->AdapterEntry->Id); - if (dialogThread = PhCreateThread(0, ShowNetAdapterDetailsDialogThread, context)) - NtClose(dialogThread); - else - FreeNetAdapterDetailsContext(context); + PhCreateThread2(ShowNetAdapterDetailsDialogThread, context); } \ No newline at end of file diff --git a/plugins/NetworkTools/ping.c b/plugins/NetworkTools/ping.c index fc415881497e..4dce3d99221e 100644 --- a/plugins/NetworkTools/ping.c +++ b/plugins/NetworkTools/ping.c @@ -567,7 +567,6 @@ VOID ShowPingWindow( _In_ PPH_NETWORK_ITEM NetworkItem ) { - HANDLE dialogThread; PNETWORK_PING_CONTEXT context; context = (PNETWORK_PING_CONTEXT)PhAllocate(sizeof(NETWORK_PING_CONTEXT)); @@ -580,17 +579,13 @@ VOID ShowPingWindow( context->RemoteEndpoint = NetworkItem->RemoteEndpoint; - if (dialogThread = PhCreateThread(0, NetworkPingDialogThreadStart, (PVOID)context)) - { - NtClose(dialogThread); - } + PhCreateThread2(NetworkPingDialogThreadStart, (PVOID)context); } VOID ShowPingWindowFromAddress( _In_ PH_IP_ENDPOINT RemoteEndpoint ) { - HANDLE dialogThread; PNETWORK_PING_CONTEXT context; context = (PNETWORK_PING_CONTEXT)PhAllocate(sizeof(NETWORK_PING_CONTEXT)); @@ -607,8 +602,5 @@ VOID ShowPingWindowFromAddress( context->RemoteEndpoint = RemoteEndpoint; - if (dialogThread = PhCreateThread(0, NetworkPingDialogThreadStart, (PVOID)context)) - { - NtClose(dialogThread); - } + PhCreateThread2(NetworkPingDialogThreadStart, (PVOID)context); } \ No newline at end of file diff --git a/plugins/NetworkTools/tracert.c b/plugins/NetworkTools/tracert.c index f5fc427381e8..1a0f3abff127 100644 --- a/plugins/NetworkTools/tracert.c +++ b/plugins/NetworkTools/tracert.c @@ -566,8 +566,6 @@ INT_PTR CALLBACK TracertDlgProc( { case WM_INITDIALOG: { - HANDLE tracertThread; - SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhLibImageBase, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhLibImageBase, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); @@ -599,8 +597,7 @@ INT_PTR CALLBACK TracertDlgProc( PhReferenceObject(context); - if (tracertThread = PhCreateThread(0, NetworkTracertThreadStart, (PVOID)context)) - NtClose(tracertThread); + PhCreateThread2(NetworkTracertThreadStart, (PVOID)context); EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); } @@ -724,7 +721,6 @@ VOID ShowTracertWindow( _In_ PPH_NETWORK_ITEM NetworkItem ) { - HANDLE dialogThread; PNETWORK_TRACERT_CONTEXT context; context = (PNETWORK_TRACERT_CONTEXT)PhCreateAlloc(sizeof(NETWORK_TRACERT_CONTEXT)); @@ -741,17 +737,13 @@ VOID ShowTracertWindow( RtlIpv6AddressToString(&NetworkItem->RemoteEndpoint.Address.In6Addr, context->IpAddressString); } - if (dialogThread = PhCreateThread(0, TracertDialogThreadStart, (PVOID)context)) - { - NtClose(dialogThread); - } + PhCreateThread2(TracertDialogThreadStart, (PVOID)context); } VOID ShowTracertWindowFromAddress( _In_ PH_IP_ENDPOINT RemoteEndpoint ) { - HANDLE dialogThread; PNETWORK_TRACERT_CONTEXT context; context = (PNETWORK_TRACERT_CONTEXT)PhCreateAlloc(sizeof(NETWORK_TRACERT_CONTEXT)); @@ -768,8 +760,5 @@ VOID ShowTracertWindowFromAddress( RtlIpv6AddressToString(&RemoteEndpoint.Address.In6Addr, context->IpAddressString); } - if (dialogThread = PhCreateThread(0, TracertDialogThreadStart, (PVOID)context)) - { - NtClose(dialogThread); - } + PhCreateThread2(TracertDialogThreadStart, (PVOID)context); } \ No newline at end of file diff --git a/plugins/NetworkTools/update.c b/plugins/NetworkTools/update.c index 565830343209..57d728413f45 100644 --- a/plugins/NetworkTools/update.c +++ b/plugins/NetworkTools/update.c @@ -811,8 +811,5 @@ VOID ShowGeoIPUpdateDialog( _In_opt_ HWND Parent ) { - HANDLE threadHandle; - - if (threadHandle = PhCreateThread(0, GeoIPUpdateDialogThread, Parent)) - NtClose(threadHandle); + PhCreateThread2(GeoIPUpdateDialogThread, Parent); } \ No newline at end of file diff --git a/plugins/NetworkTools/whois.c b/plugins/NetworkTools/whois.c index 5be18698f44d..3cca5ef466df 100644 --- a/plugins/NetworkTools/whois.c +++ b/plugins/NetworkTools/whois.c @@ -394,8 +394,6 @@ INT_PTR CALLBACK NetworkOutputDlgProc( { case WM_INITDIALOG: { - HANDLE dialogThread; - SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhLibImageBase, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhLibImageBase, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); @@ -421,8 +419,7 @@ INT_PTR CALLBACK NetworkOutputDlgProc( else PhCenterWindow(hwndDlg, PhMainWndHandle); - if (dialogThread = PhCreateThread(0, NetworkWhoisThreadStart, (PVOID)context)) - NtClose(dialogThread); + PhCreateThread2(NetworkWhoisThreadStart, (PVOID)context); EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); } @@ -556,7 +553,6 @@ VOID ShowWhoisWindow( _In_ PPH_NETWORK_ITEM NetworkItem ) { - HANDLE dialogThread; PNETWORK_WHOIS_CONTEXT context; context = (PNETWORK_WHOIS_CONTEXT)PhCreateAlloc(sizeof(NETWORK_WHOIS_CONTEXT)); @@ -573,17 +569,13 @@ VOID ShowWhoisWindow( RtlIpv6AddressToString(&NetworkItem->RemoteEndpoint.Address.In6Addr, context->IpAddressString); } - if (dialogThread = PhCreateThread(0, NetworkWhoisDialogThreadStart, (PVOID)context)) - { - NtClose(dialogThread); - } + PhCreateThread2(NetworkWhoisDialogThreadStart, (PVOID)context); } VOID ShowWhoisWindowFromAddress( _In_ PH_IP_ENDPOINT RemoteEndpoint ) { - HANDLE dialogThread; PNETWORK_WHOIS_CONTEXT context; context = (PNETWORK_WHOIS_CONTEXT)PhCreateAlloc(sizeof(NETWORK_WHOIS_CONTEXT)); @@ -600,8 +592,5 @@ VOID ShowWhoisWindowFromAddress( RtlIpv6AddressToString(&RemoteEndpoint.Address.In6Addr, context->IpAddressString); } - if (dialogThread = PhCreateThread(0, NetworkWhoisDialogThreadStart, (PVOID)context)) - { - NtClose(dialogThread); - } + PhCreateThread2(NetworkWhoisDialogThreadStart, (PVOID)context); } \ No newline at end of file diff --git a/plugins/OnlineChecks/upload.c b/plugins/OnlineChecks/upload.c index f1040c0bfd7b..542063e168f3 100644 --- a/plugins/OnlineChecks/upload.c +++ b/plugins/OnlineChecks/upload.c @@ -1175,16 +1175,6 @@ LRESULT CALLBACK TaskDialogSubclassProc( RemoveWindowSubclass(hwndDlg, TaskDialogSubclassProc, uIdSubclass); } break; - case UM_SHOWDIALOG: - { - if (IsMinimized(hwndDlg)) - ShowWindow(hwndDlg, SW_RESTORE); - else - ShowWindow(hwndDlg, SW_SHOW); - - SetForegroundWindow(hwndDlg); - } - break; case UM_UPLOAD: { ShowVirusTotalProgressDialog(context); @@ -1288,7 +1278,6 @@ VOID UploadToOnlineService( { static PH_INITONCE initOnce = PH_INITONCE_INIT; - HANDLE dialogThread; PUPLOAD_CONTEXT context; if (PhBeginInitOnce(&initOnce)) @@ -1305,9 +1294,5 @@ VOID UploadToOnlineService( context->FileName = FileName; context->BaseFileName = PhGetBaseName(context->FileName); - if (dialogThread = PhCreateThread(0, ShowUpdateDialogThread, (PVOID)context)) - { - PostMessage(dialogThread, UM_SHOWDIALOG, 0, 0); - NtClose(dialogThread); - } + PhCreateThread2(ShowUpdateDialogThread, (PVOID)context); } diff --git a/plugins/Updater/updater.c b/plugins/Updater/updater.c index c09751490822..7e65a8ee4807 100644 --- a/plugins/Updater/updater.c +++ b/plugins/Updater/updater.c @@ -1217,8 +1217,5 @@ VOID StartInitialCheck( VOID ) { - HANDLE silentCheckThread = NULL; - - if (silentCheckThread = PhCreateThread(0, UpdateCheckSilentThread, NULL)) - NtClose(silentCheckThread); + PhCreateThread2(UpdateCheckSilentThread, NULL); } \ No newline at end of file diff --git a/tools/peview/include/peview.h b/tools/peview/include/peview.h index c2586e7db2b6..d076b7649ac5 100644 --- a/tools/peview/include/peview.h +++ b/tools/peview/include/peview.h @@ -209,7 +209,6 @@ typedef struct _PDB_SYMBOL_CONTEXT HWND SearchHandle; HWND TreeNewHandle; HWND ParentWindowHandle; - HANDLE SearchThreadHandle; HANDLE TimerQueueHandle; HANDLE UpdateTimerHandle; diff --git a/tools/peview/pdbprp.c b/tools/peview/pdbprp.c index c72a7a9e8722..39d66924472e 100644 --- a/tools/peview/pdbprp.c +++ b/tools/peview/pdbprp.c @@ -956,7 +956,7 @@ INT_PTR CALLBACK PvpSymbolsDlgProc( SearchResults = PhCreateList(0x1000); context->UdtList = PhCreateList(0x100); - context->SearchThreadHandle = PhCreateThread(0, PeDumpFileSymbols, context); + PhCreateThread2(PeDumpFileSymbols, context); if (NT_SUCCESS(RtlCreateTimerQueue(&context->TimerQueueHandle))) { @@ -982,8 +982,6 @@ INT_PTR CALLBACK PvpSymbolsDlgProc( if (context->TimerQueueHandle) RtlDeleteTimerQueue(context->TimerQueueHandle); - NtClose(context->SearchThreadHandle); - PvDeleteSymbolTree(context); } break; From 0d40a08fbaccf39848db19b94d3e1f139c68027d Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 22 Jun 2017 19:37:22 +1000 Subject: [PATCH 0232/2058] Add PhConnectPipe --- ProcessHacker/ProcessHacker.def | 1 + phlib/include/phnative.h | 32 +++--- phlib/native.c | 175 ++++++++++++++++++++------------ 3 files changed, 128 insertions(+), 80 deletions(-) diff --git a/ProcessHacker/ProcessHacker.def b/ProcessHacker/ProcessHacker.def index 31e68e0bc05f..6804648802d8 100644 --- a/ProcessHacker/ProcessHacker.def +++ b/ProcessHacker/ProcessHacker.def @@ -232,6 +232,7 @@ EXPORTS PhCreateKey PhCreateNamedPipe PhCreatePipe + PhConnectPipe PhDeleteFileWin32 PhDisconnectNamedPipe PhEnumDirectoryFile diff --git a/phlib/include/phnative.h b/phlib/include/phnative.h index 41390d6ec34d..7b9d0baa713c 100644 --- a/phlib/include/phnative.h +++ b/phlib/include/phnative.h @@ -989,29 +989,33 @@ PhCreateNamedPipe( _In_ PWSTR PipeName ); +PHLIBAPI +NTSTATUS +NTAPI +PhConnectPipe( + _Out_ PHANDLE PipeHandle, + _In_ PWSTR PipeName + ); + PHLIBAPI NTSTATUS NTAPI PhListenNamedPipe( - _In_ HANDLE FileHandle, - _In_opt_ HANDLE Event, - _In_opt_ PIO_APC_ROUTINE ApcRoutine, - _In_opt_ PVOID ApcContext, - _Out_ PIO_STATUS_BLOCK IoStatusBlock + _In_ HANDLE PipeHandle ); PHLIBAPI NTSTATUS NTAPI PhDisconnectNamedPipe( - _In_ HANDLE FileHandle + _In_ HANDLE PipeHandle ); PHLIBAPI NTSTATUS NTAPI PhPeekNamedPipe( - _In_ HANDLE FileHandle, + _In_ HANDLE PipeHandle, _Out_writes_bytes_opt_(Length) PVOID Buffer, _In_ ULONG Length, _Out_opt_ PULONG NumberOfBytesRead, @@ -1023,11 +1027,7 @@ PHLIBAPI NTSTATUS NTAPI PhTransceiveNamedPipe( - _In_ HANDLE FileHandle, - _In_opt_ HANDLE Event, - _In_opt_ PIO_APC_ROUTINE ApcRoutine, - _In_opt_ PVOID ApcContext, - _Out_ PIO_STATUS_BLOCK IoStatusBlock, + _In_ HANDLE PipeHandle, _In_reads_bytes_(InputBufferLength) PVOID InputBuffer, _In_ ULONG InputBufferLength, _Out_writes_bytes_(OutputBufferLength) PVOID OutputBuffer, @@ -1038,17 +1038,15 @@ PHLIBAPI NTSTATUS NTAPI PhWaitForNamedPipe( - _In_opt_ PUNICODE_STRING FileSystemName, - _In_ PUNICODE_STRING Name, - _In_opt_ PLARGE_INTEGER Timeout, - _In_ BOOLEAN UseDefaultTimeout + _In_ PWSTR PipeName, + _In_opt_ ULONG Timeout ); PHLIBAPI NTSTATUS NTAPI PhImpersonateClientOfNamedPipe( - _In_ HANDLE FileHandle + _In_ HANDLE PipeHandle ); #ifdef __cplusplus diff --git a/phlib/native.c b/phlib/native.c index 0a5bc388b634..c3ee08b66cd8 100644 --- a/phlib/native.c +++ b/phlib/native.c @@ -1319,7 +1319,7 @@ NTSTATUS PhInjectDllProcess( 0, 0, 0, - (PUSER_THREAD_START_ROUTINE)threadStart, + threadStart, baseAddress, &threadHandle, NULL @@ -6310,7 +6310,7 @@ NTSTATUS PhCreateNamedPipe( &oa, &isb, FILE_SHARE_READ | FILE_SHARE_WRITE, - FILE_CREATE, + FILE_OPEN_IF, FILE_PIPE_FULL_DUPLEX | FILE_SYNCHRONOUS_IO_NONALERT, FILE_PIPE_MESSAGE_TYPE, FILE_PIPE_MESSAGE_MODE, @@ -6330,37 +6330,92 @@ NTSTATUS PhCreateNamedPipe( return status; } +NTSTATUS PhConnectPipe( + _Out_ PHANDLE PipeHandle, + _In_ PWSTR PipeName + ) +{ + NTSTATUS status; + HANDLE pipeHandle; + PPH_STRING pipeName; + UNICODE_STRING pipeNameUs; + OBJECT_ATTRIBUTES oa; + IO_STATUS_BLOCK isb; + + pipeName = PhConcatStrings2(DEVICE_NAMED_PIPE, PipeName); + PhStringRefToUnicodeString(&pipeName->sr, &pipeNameUs); + + InitializeObjectAttributes( + &oa, + &pipeNameUs, + OBJ_CASE_INSENSITIVE, + NULL, + NULL + ); + + status = NtCreateFile( + &pipeHandle, + FILE_GENERIC_READ | FILE_GENERIC_WRITE, + &oa, + &isb, + NULL, + FILE_ATTRIBUTE_NORMAL, + FILE_SHARE_READ | FILE_SHARE_WRITE, + FILE_OPEN, + FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, + NULL, + 0 + ); + + if (NT_SUCCESS(status)) + { + *PipeHandle = pipeHandle; + } + + PhDereferenceObject(pipeName); + return status; +} + NTSTATUS PhListenNamedPipe( - _In_ HANDLE FileHandle, - _In_opt_ HANDLE Event, - _In_opt_ PIO_APC_ROUTINE ApcRoutine, - _In_opt_ PVOID ApcContext, - _Out_ PIO_STATUS_BLOCK IoStatusBlock + _In_ HANDLE PipeHandle ) { - return NtFsControlFile( - FileHandle, - Event, - ApcRoutine, - ApcContext, - IoStatusBlock, + NTSTATUS status; + IO_STATUS_BLOCK isb; + + status = NtFsControlFile( + PipeHandle, + NULL, + NULL, + NULL, + &isb, FSCTL_PIPE_LISTEN, NULL, 0, NULL, 0 ); + + if (status == STATUS_PENDING) + { + status = NtWaitForSingleObject(PipeHandle, FALSE, NULL); + + if (NT_SUCCESS(status)) + status = isb.Status; + } + + return status; } NTSTATUS PhDisconnectNamedPipe( - _In_ HANDLE FileHandle + _In_ HANDLE PipeHandle ) { NTSTATUS status; IO_STATUS_BLOCK isb; status = NtFsControlFile( - FileHandle, + PipeHandle, NULL, NULL, NULL, @@ -6374,7 +6429,7 @@ NTSTATUS PhDisconnectNamedPipe( if (status == STATUS_PENDING) { - status = NtWaitForSingleObject(FileHandle, FALSE, NULL); + status = NtWaitForSingleObject(PipeHandle, FALSE, NULL); if (NT_SUCCESS(status)) status = isb.Status; @@ -6384,7 +6439,7 @@ NTSTATUS PhDisconnectNamedPipe( } NTSTATUS PhPeekNamedPipe( - _In_ HANDLE FileHandle, + _In_ HANDLE PipeHandle, _Out_writes_bytes_opt_(Length) PVOID Buffer, _In_ ULONG Length, _Out_opt_ PULONG NumberOfBytesRead, @@ -6401,7 +6456,7 @@ NTSTATUS PhPeekNamedPipe( peekBuffer = PhAllocate(peekBufferLength); status = NtFsControlFile( - FileHandle, + PipeHandle, NULL, NULL, NULL, @@ -6415,7 +6470,7 @@ NTSTATUS PhPeekNamedPipe( if (status == STATUS_PENDING) { - status = NtWaitForSingleObject(FileHandle, FALSE, NULL); + status = NtWaitForSingleObject(PipeHandle, FALSE, NULL); if (NT_SUCCESS(status)) status = isb.Status; @@ -6427,7 +6482,7 @@ NTSTATUS PhPeekNamedPipe( if (NT_SUCCESS(status)) { - ULONG numberOfBytesRead; + ULONG numberOfBytesRead = 0; if (Buffer || NumberOfBytesRead || NumberOfBytesLeftInMessage) numberOfBytesRead = (ULONG)(isb.Information - FIELD_OFFSET(FILE_PIPE_PEEK_BUFFER, Data)); @@ -6451,55 +6506,58 @@ NTSTATUS PhPeekNamedPipe( } NTSTATUS PhTransceiveNamedPipe( - _In_ HANDLE FileHandle, - _In_opt_ HANDLE Event, - _In_opt_ PIO_APC_ROUTINE ApcRoutine, - _In_opt_ PVOID ApcContext, - _Out_ PIO_STATUS_BLOCK IoStatusBlock, + _In_ HANDLE PipeHandle, _In_reads_bytes_(InputBufferLength) PVOID InputBuffer, _In_ ULONG InputBufferLength, _Out_writes_bytes_(OutputBufferLength) PVOID OutputBuffer, _In_ ULONG OutputBufferLength ) { - return NtFsControlFile( - FileHandle, - Event, - ApcRoutine, - ApcContext, - IoStatusBlock, + NTSTATUS status; + IO_STATUS_BLOCK isb; + + status = NtFsControlFile( + PipeHandle, + NULL, + NULL, + NULL, + &isb, FSCTL_PIPE_TRANSCEIVE, InputBuffer, InputBufferLength, OutputBuffer, OutputBufferLength ); + + if (status == STATUS_PENDING) + { + status = NtWaitForSingleObject(PipeHandle, FALSE, NULL); + + if (NT_SUCCESS(status)) + status = isb.Status; + } + + return status; } NTSTATUS PhWaitForNamedPipe( - _In_opt_ PUNICODE_STRING FileSystemName, - _In_ PUNICODE_STRING Name, - _In_opt_ PLARGE_INTEGER Timeout, - _In_ BOOLEAN UseDefaultTimeout + _In_ PWSTR PipeName, + _In_opt_ ULONG Timeout ) { NTSTATUS status; IO_STATUS_BLOCK isb; + PH_STRINGREF localNpfsNameSr; UNICODE_STRING localNpfsName; HANDLE fileSystemHandle; OBJECT_ATTRIBUTES oa; PFILE_PIPE_WAIT_FOR_BUFFER waitForBuffer; ULONG waitForBufferLength; - if (!FileSystemName) - { - RtlInitUnicodeString(&localNpfsName, L"\\Device\\NamedPipe"); - FileSystemName = &localNpfsName; - } - + RtlInitUnicodeString(&localNpfsName, DEVICE_NAMED_PIPE); InitializeObjectAttributes( &oa, - FileSystemName, + &localNpfsName, OBJ_CASE_INSENSITIVE, NULL, NULL @@ -6517,30 +6575,24 @@ NTSTATUS PhWaitForNamedPipe( if (!NT_SUCCESS(status)) return status; - waitForBufferLength = FIELD_OFFSET(FILE_PIPE_WAIT_FOR_BUFFER, Name) + Name->Length; + PhInitializeStringRefLongHint(&localNpfsNameSr, PipeName); + waitForBufferLength = FIELD_OFFSET(FILE_PIPE_WAIT_FOR_BUFFER, Name) + (ULONG)localNpfsNameSr.Length; waitForBuffer = PhAllocate(waitForBufferLength); - if (UseDefaultTimeout) + if (Timeout) { - waitForBuffer->TimeoutSpecified = FALSE; + PhTimeoutFromMilliseconds(&waitForBuffer->Timeout, Timeout); + waitForBuffer->TimeoutSpecified = TRUE; } else { - if (Timeout) - { - waitForBuffer->Timeout = *Timeout; - } - else - { - waitForBuffer->Timeout.LowPart = 0; - waitForBuffer->Timeout.HighPart = MINLONG; // a very long time - } - + waitForBuffer->Timeout.LowPart = 0; + waitForBuffer->Timeout.HighPart = MINLONG; // a very long time waitForBuffer->TimeoutSpecified = TRUE; } - waitForBuffer->NameLength = (ULONG)Name->Length; - memcpy(waitForBuffer->Name, Name->Buffer, Name->Length); + waitForBuffer->NameLength = (ULONG)localNpfsNameSr.Length; + memcpy(waitForBuffer->Name, localNpfsNameSr.Buffer, localNpfsNameSr.Length); status = NtFsControlFile( fileSystemHandle, @@ -6562,14 +6614,13 @@ NTSTATUS PhWaitForNamedPipe( } NTSTATUS PhImpersonateClientOfNamedPipe( - _In_ HANDLE FileHandle + _In_ HANDLE PipeHandle ) { - NTSTATUS status; IO_STATUS_BLOCK isb; - status = NtFsControlFile( - FileHandle, + return NtFsControlFile( + PipeHandle, NULL, NULL, NULL, @@ -6580,6 +6631,4 @@ NTSTATUS PhImpersonateClientOfNamedPipe( NULL, 0 ); - - return status; } From b2bc78c951df548a0621b27489839c38293a9cae Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 22 Jun 2017 19:44:34 +1000 Subject: [PATCH 0233/2058] Update find handles window layout --- ProcessHacker/ProcessHacker.rc | 28 ++++++++++++++-------------- ProcessHacker/findobj.c | 2 +- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/ProcessHacker/ProcessHacker.rc b/ProcessHacker/ProcessHacker.rc index 675362f8993c..bcbe1bc418c3 100644 --- a/ProcessHacker/ProcessHacker.rc +++ b/ProcessHacker/ProcessHacker.rc @@ -111,11 +111,11 @@ BEGIN MENUITEM "System &information\aCtrl+I", ID_VIEW_SYSTEMINFORMATION POPUP "&Tray icons" BEGIN - MENUITEM "CPU &history", ID_TRAYICONS_CPUHISTORY - MENUITEM "CPU &usage", ID_TRAYICONS_CPUUSAGE - MENUITEM "&I/O history", ID_TRAYICONS_IOHISTORY - MENUITEM "&Commit charge history", ID_TRAYICONS_COMMITHISTORY - MENUITEM "&Physical memory history", ID_TRAYICONS_PHYSICALMEMORYHISTORY + MENUITEM "CPU &history", ID_TRAYICONS_CPUHISTORY + MENUITEM "CPU &usage", ID_TRAYICONS_CPUUSAGE + MENUITEM "&I/O history", ID_TRAYICONS_IOHISTORY + MENUITEM "&Commit charge history", ID_TRAYICONS_COMMITHISTORY + MENUITEM "&Physical memory history", ID_TRAYICONS_PHYSICALMEMORYHISTORY END MENUITEM SEPARATOR MENUITEM "
    ", ID_VIEW_SECTIONPLACEHOLDER @@ -152,7 +152,7 @@ BEGIN MENUITEM "Hidden processes", ID_TOOLS_HIDDENPROCESSES MENUITEM "Inspect executable file...", ID_TOOLS_INSPECTEXECUTABLEFILE MENUITEM "Pagefiles", ID_TOOLS_PAGEFILES - MENUITEM "Start &Task Manager", ID_TOOLS_STARTTASKMANAGER + MENUITEM "Start &Task Manager", ID_TOOLS_STARTTASKMANAGER END POPUP "&Users" BEGIN @@ -301,9 +301,9 @@ BEGIN MENUITEM "Low", ID_PAGEPRIORITY_LOW MENUITEM "Very low", ID_PAGEPRIORITY_VERYLOW END - MENUITEM "Reduce working &set", ID_MISCELLANEOUS_REDUCEWORKINGSET - MENUITEM "&Run as...", ID_MISCELLANEOUS_RUNAS - MENUITEM "Run &as this user...", ID_MISCELLANEOUS_RUNASTHISUSER + MENUITEM "Reduce working &set", ID_MISCELLANEOUS_REDUCEWORKINGSET + MENUITEM "&Run as...", ID_MISCELLANEOUS_RUNAS + MENUITEM "Run &as this user...", ID_MISCELLANEOUS_RUNASTHISUSER END POPUP "&Window" BEGIN @@ -720,14 +720,14 @@ BEGIN END IDD_FINDOBJECTS DIALOGEX 0, 0, 357, 233 -STYLE DS_SETFONT | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME +STYLE DS_SETFONT | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME CAPTION "Find Handles or DLLs" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN LTEXT "Filter:",IDC_STATIC,7,9,20,8 EDITTEXT IDC_FILTER,32,8,224,14,ES_AUTOHSCROLL PUSHBUTTON "Find",IDOK,300,7,50,14 - CONTROL "",IDC_RESULTS,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,26,343,200 + CONTROL "",IDC_RESULTS,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,2,25,353,206 CONTROL "&Regex",IDC_REGEX,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,261,9,36,10 END @@ -1963,10 +1963,10 @@ BEGIN IDD_FINDOBJECTS, DIALOG BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 350 + LEFTMARGIN, 2 + RIGHTMARGIN, 355 TOPMARGIN, 7 - BOTTOMMARGIN, 226 + BOTTOMMARGIN, 231 END IDD_OBJTOKEN, DIALOG diff --git a/ProcessHacker/findobj.c b/ProcessHacker/findobj.c index 78eb2690f0c0..77e5ed193412 100644 --- a/ProcessHacker/findobj.c +++ b/ProcessHacker/findobj.c @@ -100,7 +100,7 @@ VOID PhShowFindObjectsDialog( PhFindObjectsWindowHandle = CreateDialog( PhInstanceHandle, MAKEINTRESOURCE(IDD_FINDOBJECTS), - PhMainWndHandle, + NULL, PhpFindObjectsDlgProc ); } From 8d3dd4b16fe1b4e9978ed5baa1c9b33b5f046d6e Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 23 Jun 2017 00:03:28 +1000 Subject: [PATCH 0234/2058] Add RtlInitEmptyUnicodeString --- phnt/include/ntrtl.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/phnt/include/ntrtl.h b/phnt/include/ntrtl.h index 0f01ff0e065b..66b9565e80e6 100644 --- a/phnt/include/ntrtl.h +++ b/phnt/include/ntrtl.h @@ -1371,6 +1371,20 @@ RtlUpperString( _In_ PSTRING SourceString ); +FORCEINLINE +VOID +NTAPI +RtlInitEmptyUnicodeString( + _Out_ PUNICODE_STRING DestinationString, + _In_ PWCHAR Buffer, + _In_ USHORT BufferSize + ) +{ + DestinationString->Length = 0; + DestinationString->MaximumLength = BufferSize; + DestinationString->Buffer = Buffer; +} + #ifndef PHNT_NO_INLINE_INIT_STRING FORCEINLINE VOID RtlInitUnicodeString( _Out_ PUNICODE_STRING DestinationString, From 095b9ae121fdf817775a6cc8b165c553149a3e41 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 23 Jun 2017 01:17:05 +1000 Subject: [PATCH 0235/2058] Remove legacy import --- ProcessHacker/mainwnd.c | 2 +- phlib/guisup.c | 2 -- phlib/include/guisup.h | 6 ------ phlib/include/phbasesup.h | 17 +++++++++++++++++ phlib/include/phsup.h | 15 --------------- 5 files changed, 18 insertions(+), 24 deletions(-) diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index cb6592fbca56..f73c3b15d263 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -175,7 +175,7 @@ BOOLEAN PhMainWndInitialization( windowRectangle.Width, windowRectangle.Height, FALSE); // Allow WM_PH_ACTIVATE to pass through UIPI. - ChangeWindowMessageFilter_I(WM_PH_ACTIVATE, MSGFLT_ADD); + ChangeWindowMessageFilter(WM_PH_ACTIVATE, MSGFLT_ADD); PhMwpOnSettingChange(); diff --git a/phlib/guisup.c b/phlib/guisup.c index c7d3d1143d75..4ecd51fb4500 100644 --- a/phlib/guisup.c +++ b/phlib/guisup.c @@ -31,7 +31,6 @@ #define SCALE_DPI(Value) PhMultiplyDivide(Value, PhGlobalDpi, 96) -_ChangeWindowMessageFilter ChangeWindowMessageFilter_I; _IsImmersiveProcess IsImmersiveProcess_I; _RunFileDlg RunFileDlg; _SHAutoComplete SHAutoComplete_I; @@ -50,7 +49,6 @@ VOID PhGuiSupportInitialization( shell32Handle = LoadLibrary(L"shell32.dll"); shlwapiHandle = LoadLibrary(L"shlwapi.dll"); - ChangeWindowMessageFilter_I = PhGetModuleProcAddress(L"user32.dll", "ChangeWindowMessageFilter"); if (WINDOWS_HAS_IMMERSIVE) IsImmersiveProcess_I = PhGetModuleProcAddress(L"user32.dll", "IsImmersiveProcess"); RunFileDlg = PhGetProcedureAddress(shell32Handle, NULL, 61); diff --git a/phlib/include/guisup.h b/phlib/include/guisup.h index d825dd31fe48..1a5c9beabd5b 100644 --- a/phlib/include/guisup.h +++ b/phlib/include/guisup.h @@ -11,11 +11,6 @@ extern "C" { // guisup -typedef BOOL (WINAPI *_ChangeWindowMessageFilter)( - _In_ UINT message, - _In_ DWORD dwFlag - ); - typedef BOOL (WINAPI *_IsImmersiveProcess)( _In_ HANDLE hProcess ); @@ -60,7 +55,6 @@ typedef HRESULT (WINAPI *_SHAutoComplete)( _In_ DWORD dwFlags ); -extern _ChangeWindowMessageFilter ChangeWindowMessageFilter_I; extern _IsImmersiveProcess IsImmersiveProcess_I; extern _RunFileDlg RunFileDlg; extern _SHAutoComplete SHAutoComplete_I; diff --git a/phlib/include/phbasesup.h b/phlib/include/phbasesup.h index 3c75c1eecefe..b2c6a1838710 100644 --- a/phlib/include/phbasesup.h +++ b/phlib/include/phbasesup.h @@ -105,6 +105,23 @@ PhGetProcedureAddress( return procedureAddress; } +FORCEINLINE +PVOID +PhGetModuleProcAddress( + _In_ PWSTR ModuleName, + _In_ PSTR ProcName + ) +{ + HMODULE module; + + module = PhGetDllHandle(ModuleName); + + if (module) + return PhGetProcedureAddress(module, ProcName, 0); + else + return NULL; +} + // Misc. system PHLIBAPI diff --git a/phlib/include/phsup.h b/phlib/include/phsup.h index 55e36cf5160f..2be65f1ddb46 100644 --- a/phlib/include/phsup.h +++ b/phlib/include/phsup.h @@ -528,19 +528,4 @@ FORCEINLINE NTSTATUS PhGetLastWin32ErrorAsNtStatus() return NTSTATUS_FROM_WIN32(win32Result); } -FORCEINLINE PVOID PhGetModuleProcAddress( - _In_ PWSTR ModuleName, - _In_ PSTR ProcName - ) -{ - HMODULE module; - - module = GetModuleHandle(ModuleName); - - if (module) - return GetProcAddress(module, ProcName); - else - return NULL; -} - #endif From 5138bfb8aa641702cd25da34905cf8740bb4bd5d Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 23 Jun 2017 01:24:22 +1000 Subject: [PATCH 0236/2058] Fix named pipe permissions, Add RtlDefaultNpAcl --- phlib/native.c | 28 ++++++++++++++++++++++++++-- phnt/include/ntrtl.h | 7 +++++++ 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/phlib/native.c b/phlib/native.c index c3ee08b66cd8..1a1f5f4e197f 100644 --- a/phlib/native.c +++ b/phlib/native.c @@ -6184,6 +6184,7 @@ NTSTATUS PhCreatePipe( ) { NTSTATUS status; + PACL pipeAcl; HANDLE pipeDirectoryHandle; HANDLE pipeReadHandle; HANDLE pipeWriteHandle; @@ -6222,6 +6223,17 @@ NTSTATUS PhCreatePipe( NULL ); + if (NT_SUCCESS(RtlDefaultNpAcl(&pipeAcl))) + { + SECURITY_DESCRIPTOR securityDescriptor; + + RtlCreateSecurityDescriptor(&securityDescriptor, SECURITY_DESCRIPTOR_REVISION); + RtlSetDaclSecurityDescriptor(&securityDescriptor, TRUE, pipeAcl, FALSE); + RtlFreeHeap(RtlProcessHeap(), 0, pipeAcl); + + oa.SecurityDescriptor = &securityDescriptor; + } + status = NtCreateNamedPipeFile( &pipeReadHandle, FILE_WRITE_ATTRIBUTES | GENERIC_READ | SYNCHRONIZE, @@ -6233,7 +6245,7 @@ NTSTATUS PhCreatePipe( FILE_PIPE_BYTE_STREAM_TYPE, FILE_PIPE_BYTE_STREAM_MODE, FILE_PIPE_QUEUE_OPERATION, - PIPE_UNLIMITED_INSTANCES, // min: 1, max: ULONG_MAX + ULONG_MAX, PAGE_SIZE, PAGE_SIZE, PhTimeoutFromMilliseconds(&pipeTimeout, 500) @@ -6285,6 +6297,7 @@ NTSTATUS PhCreateNamedPipe( ) { NTSTATUS status; + PACL pipeAcl; HANDLE pipeHandle; PPH_STRING pipeName; LARGE_INTEGER pipeTimeout; @@ -6304,6 +6317,17 @@ NTSTATUS PhCreateNamedPipe( NULL ); + if (NT_SUCCESS(RtlDefaultNpAcl(&pipeAcl))) + { + SECURITY_DESCRIPTOR securityDescriptor; + + RtlCreateSecurityDescriptor(&securityDescriptor, SECURITY_DESCRIPTOR_REVISION); + RtlSetDaclSecurityDescriptor(&securityDescriptor, TRUE, pipeAcl, FALSE); + RtlFreeHeap(RtlProcessHeap(), 0, pipeAcl); + + oa.SecurityDescriptor = &securityDescriptor; + } + status = NtCreateNamedPipeFile( &pipeHandle, FILE_GENERIC_READ | FILE_GENERIC_WRITE, @@ -6315,7 +6339,7 @@ NTSTATUS PhCreateNamedPipe( FILE_PIPE_MESSAGE_TYPE, FILE_PIPE_MESSAGE_MODE, FILE_PIPE_QUEUE_OPERATION, - PIPE_UNLIMITED_INSTANCES, // min: 1, max: ULONG_MAX + ULONG_MAX, PAGE_SIZE, PAGE_SIZE, &pipeTimeout diff --git a/phnt/include/ntrtl.h b/phnt/include/ntrtl.h index 66b9565e80e6..0aa4a316e604 100644 --- a/phnt/include/ntrtl.h +++ b/phnt/include/ntrtl.h @@ -5429,6 +5429,13 @@ RtlCreateAcl( _In_ ULONG AclRevision ); +NTSYSAPI +NTSTATUS +NTAPI +RtlDefaultNpAcl( + _Out_ PACL *Acl + ); + NTSYSAPI BOOLEAN NTAPI From f9196ae1252cdc4d92fb5457a0a4eb6f49c119f6 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 23 Jun 2017 01:26:05 +1000 Subject: [PATCH 0237/2058] Fix RtlInitEmptyUnicodeString definition --- phnt/include/ntrtl.h | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/phnt/include/ntrtl.h b/phnt/include/ntrtl.h index 0aa4a316e604..74bef7a7d37e 100644 --- a/phnt/include/ntrtl.h +++ b/phnt/include/ntrtl.h @@ -1371,18 +1371,28 @@ RtlUpperString( _In_ PSTRING SourceString ); -FORCEINLINE +FORCEINLINE VOID NTAPI RtlInitEmptyUnicodeString( _Out_ PUNICODE_STRING DestinationString, - _In_ PWCHAR Buffer, - _In_ USHORT BufferSize + _In_opt_ PWCHAR Buffer, + _In_opt_ USHORT MaximumLength ) { + if (Buffer) + { + DestinationString->Buffer = Buffer; + DestinationString->MaximumLength = MaximumLength; + } + else + { + PTEB currentTeb = NtCurrentTeb(); + DestinationString->Buffer = currentTeb->StaticUnicodeBuffer; + DestinationString->MaximumLength = sizeof(currentTeb->StaticUnicodeBuffer); + } + DestinationString->Length = 0; - DestinationString->MaximumLength = BufferSize; - DestinationString->Buffer = Buffer; } #ifndef PHNT_NO_INLINE_INIT_STRING From 840ed7fed5295093f02336b2fcbf92d45ca557c3 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 23 Jun 2017 02:17:19 +1000 Subject: [PATCH 0238/2058] Improve PhUpdateDosDevicePrefixes lookup --- phlib/native.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/phlib/native.c b/phlib/native.c index 1a1f5f4e197f..df12c4479901 100644 --- a/phlib/native.c +++ b/phlib/native.c @@ -4849,14 +4849,32 @@ VOID PhUpdateDosDevicePrefixes( ) { WCHAR deviceNameBuffer[7] = L"\\??\\ :"; - ULONG i; +#ifndef _WIN64 + PROCESS_DEVICEMAP_INFORMATION deviceMapInfo; +#else + PROCESS_DEVICEMAP_INFORMATION_EX deviceMapInfo; +#endif + memset(&deviceMapInfo, 0, sizeof(deviceMapInfo)); + + NtQueryInformationProcess( + NtCurrentProcess(), + ProcessDeviceMap, + &deviceMapInfo, + sizeof(deviceMapInfo), + NULL + ); - for (i = 0; i < 26; i++) { HANDLE linkHandle; OBJECT_ATTRIBUTES oa; UNICODE_STRING deviceName; + if (deviceMapInfo.Query.DriveMap) + { + if (!(deviceMapInfo.Query.DriveMap & (0x1 << i))) + continue; + } + deviceNameBuffer[4] = (WCHAR)('A' + i); deviceName.Buffer = deviceNameBuffer; deviceName.Length = 6 * sizeof(WCHAR); From 806a5ba3ce13a27eef4774e41ed0a12c1d50c0cf Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 23 Jun 2017 02:17:35 +1000 Subject: [PATCH 0239/2058] Fix typo --- phlib/native.c | 1 + 1 file changed, 1 insertion(+) diff --git a/phlib/native.c b/phlib/native.c index df12c4479901..2c2cbbb383a9 100644 --- a/phlib/native.c +++ b/phlib/native.c @@ -4864,6 +4864,7 @@ VOID PhUpdateDosDevicePrefixes( NULL ); + for (ULONG i = 0; i < 0x1A; i++) { HANDLE linkHandle; OBJECT_ATTRIBUTES oa; From db9e33d7d3474568735fb1b4fb9fbab6b32714f4 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 23 Jun 2017 02:26:33 +1000 Subject: [PATCH 0240/2058] Fix duplicate DosDevicePrefixes initialization --- ProcessHacker/procprv.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/ProcessHacker/procprv.c b/ProcessHacker/procprv.c index ebbff15f1ab8..cb48c8d9f16b 100644 --- a/ProcessHacker/procprv.c +++ b/ProcessHacker/procprv.c @@ -1932,11 +1932,6 @@ VOID PhProcessProviderUpdate( // Pre-update tasks - if (runCount % 5 == 0) - { - PhUpdateDosDevicePrefixes(); - } - if (runCount % 512 == 0) // yes, a very long time { if (PhEnablePurgeProcessRecords) From 8986f4ad6d8f2e63d50d180f6841382f5f4b9e61 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 23 Jun 2017 16:54:31 +1000 Subject: [PATCH 0241/2058] Update ntpsapi.h #152 --- phnt/include/ntpsapi.h | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/phnt/include/ntpsapi.h b/phnt/include/ntpsapi.h index 7390ad399e2e..1168592532ab 100644 --- a/phnt/include/ntpsapi.h +++ b/phnt/include/ntpsapi.h @@ -630,6 +630,24 @@ typedef enum _PS_PROTECTED_SIGNER PsProtectedSignerMax } PS_PROTECTED_SIGNER; +#define PS_PROTECTED_SIGNER_MASK 0xFF +#define PS_PROTECTED_AUDIT_MASK 0x08 +#define PS_PROTECTED_TYPE_MASK 0x07 + +// vProtectionLevel.Level = PsProtectedValue(PsProtectedSignerCodeGen, FALSE, PsProtectedTypeProtectedLight) +#define PsProtectedValue(aSigner, aAudit, aType) ( \ + ((aSigner & PS_PROTECTED_SIGNER_MASK) << 4) | \ + ((aAudit & PS_PROTECTED_AUDIT_MASK) << 3) | \ + (aType & PS_PROTECTED_TYPE_MASK)\ + ) + +// InitializePsProtection(&vProtectionLevel, PsProtectedSignerCodeGen, FALSE, PsProtectedTypeProtectedLight) +#define InitializePsProtection(aProtectionLevelPtr, aSigner, aAudit, aType) { \ + (aProtectionLevelPtr)->Signer = aSigner; \ + (aProtectionLevelPtr)->Audit = aAudit; \ + (aProtectionLevelPtr)->Type = aType; \ + } + typedef struct _PS_PROTECTION { union @@ -1475,12 +1493,19 @@ typedef struct _PS_CREATE_INFO // end_private -// Extended PROCESS_CREATE_FLAGS_* // begin_rev +#define PROCESS_CREATE_FLAGS_BREAKAWAY 0x00000001 +#define PROCESS_CREATE_FLAGS_NO_DEBUG_INHERIT 0x00000002 +#define PROCESS_CREATE_FLAGS_INHERIT_HANDLES 0x00000004 +#define PROCESS_CREATE_FLAGS_OVERRIDE_ADDRESS_SPACE 0x00000008 +#define PROCESS_CREATE_FLAGS_LARGE_PAGES 0x00000010 #define PROCESS_CREATE_FLAGS_LARGE_PAGE_SYSTEM_DLL 0x00000020 +// Extended PROCESS_CREATE_FLAGS_* #define PROCESS_CREATE_FLAGS_PROTECTED_PROCESS 0x00000040 #define PROCESS_CREATE_FLAGS_CREATE_SESSION 0x00000080 // ? #define PROCESS_CREATE_FLAGS_INHERIT_FROM_PARENT 0x00000100 +#define PROCESS_CREATE_FLAGS_SUSPENDED 0x00000200 +#define PROCESS_CREATE_FLAGS_EXTENDED_UNKNOWN 0x00000400 // end_rev #if (PHNT_VERSION >= PHNT_VISTA) From 59dcab4afda92b9b4ad3ec0f81541226b5350a4f Mon Sep 17 00:00:00 2001 From: Steven G Date: Sat, 1 Jul 2017 09:33:37 +1000 Subject: [PATCH 0242/2058] Improve startup performance (#155) * Improve startup performance * Improve commandline and .NET detection (removes multiple handles) --- ProcessHacker/procprv.c | 82 ++++++++++++++++++++-------------------- phlib/native.c | 84 +++++++++++++++++++++-------------------- 2 files changed, 83 insertions(+), 83 deletions(-) diff --git a/ProcessHacker/procprv.c b/ProcessHacker/procprv.c index cb48c8d9f16b..a6a1727ba6de 100644 --- a/ProcessHacker/procprv.c +++ b/ProcessHacker/procprv.c @@ -1007,66 +1007,64 @@ VOID PhpProcessQueryStage1( } // Command line, .NET + if (processHandleLimited) { - HANDLE processHandle; - BOOLEAN queryAccess = FALSE; - - status = PhOpenProcess( - &processHandle, - ProcessQueryAccess | PROCESS_VM_READ, - processId - ); + BOOLEAN isDotNet = FALSE; + PPH_STRING commandLine; + HANDLE processHandle = NULL; + ULONG processQueryFlags = 0; - if (!NT_SUCCESS(status) && WindowsVersion >= WINDOWS_8_1) + if (WindowsVersion >= WINDOWS_8_1) + { + processHandle = processHandleLimited; + processQueryFlags |= PH_CLR_USE_SECTION_CHECK; + status = STATUS_SUCCESS; + } + else { - queryAccess = TRUE; status = PhOpenProcess( &processHandle, - ProcessQueryAccess, + ProcessQueryAccess | PROCESS_VM_READ, processId ); } if (NT_SUCCESS(status)) { - BOOLEAN isDotNet = FALSE; - PPH_STRING commandLine; - ULONG i; + PhGetProcessIsDotNetEx( + processId, + processHandle, +#ifdef _WIN64 + processQueryFlags | PH_CLR_NO_WOW64_CHECK | (Data->IsWow64 ? PH_CLR_KNOWN_IS_WOW64 : 0), +#else + processQueryFlags, +#endif + &isDotNet, + NULL + ); + Data->IsDotNet = isDotNet; + } - if (NT_SUCCESS(status = PhGetProcessCommandLine(processHandle, &commandLine))) - { - // Some command lines (e.g. from taskeng.exe) have nulls in them. Since Windows - // can't display them, we'll replace them with spaces. - for (i = 0; i < (ULONG)commandLine->Length / 2; i++) - { - if (commandLine->Buffer[i] == 0) - commandLine->Buffer[i] = ' '; - } - } + if (NT_SUCCESS(status)) + { + status = PhGetProcessCommandLine(processHandle, &commandLine); + } - if (NT_SUCCESS(status)) + if (NT_SUCCESS(status)) + { + // Some command lines (e.g. from taskeng.exe) have nulls in them. Since Windows + // can't display them, we'll replace them with spaces. + for (ULONG i = 0; i < (ULONG)commandLine->Length / 2; i++) { - Data->CommandLine = commandLine; + if (commandLine->Buffer[i] == 0) + commandLine->Buffer[i] = ' '; } - if (!queryAccess) - { - PhGetProcessIsDotNetEx( - processId, - processHandle, -#ifdef _WIN64 - PH_CLR_NO_WOW64_CHECK | (Data->IsWow64 ? PH_CLR_KNOWN_IS_WOW64 : 0), -#else - 0, -#endif - &isDotNet, - NULL - ); - Data->IsDotNet = isDotNet; - } + Data->CommandLine = commandLine; + } + if (!(processQueryFlags & PH_CLR_USE_SECTION_CHECK) && processHandle) NtClose(processHandle); - } } // Token information diff --git a/phlib/native.c b/phlib/native.c index 2c2cbbb383a9..eaee8252253b 100644 --- a/phlib/native.c +++ b/phlib/native.c @@ -4365,15 +4365,9 @@ NTSTATUS PhGetProcessIsDotNetEx( _Out_opt_ PULONG Flags ) { - NTSTATUS status = STATUS_SUCCESS; - HANDLE processHandle; - ULONG flags; -#ifdef _WIN64 - BOOLEAN isWow64; -#endif - if (InFlags & PH_CLR_USE_SECTION_CHECK) { + NTSTATUS status; HANDLE sectionHandle; OBJECT_ATTRIBUTES objectAttributes; PPH_STRING sectionName; @@ -4456,53 +4450,61 @@ NTSTATUS PhGetProcessIsDotNetEx( return STATUS_SUCCESS; } - } - flags = 0; - processHandle = NULL; - - if (!ProcessHandle) + return status; + } + else { - if (!NT_SUCCESS(status = PhOpenProcess(&processHandle, ProcessQueryAccess | PROCESS_VM_READ, ProcessId))) - return status; + NTSTATUS status; + HANDLE processHandle = NULL; + ULONG flags = 0; +#ifdef _WIN64 + BOOLEAN isWow64; +#endif - ProcessHandle = processHandle; - } + if (!ProcessHandle) + { + if (!NT_SUCCESS(status = PhOpenProcess(&processHandle, ProcessQueryAccess | PROCESS_VM_READ, ProcessId))) + return status; + + ProcessHandle = processHandle; + } #ifdef _WIN64 - if (InFlags & PH_CLR_NO_WOW64_CHECK) - { - isWow64 = !!(InFlags & PH_CLR_KNOWN_IS_WOW64); - } - else - { - isWow64 = FALSE; - PhGetProcessIsWow64(ProcessHandle, &isWow64); - } + if (InFlags & PH_CLR_NO_WOW64_CHECK) + { + isWow64 = !!(InFlags & PH_CLR_KNOWN_IS_WOW64); + } + else + { + isWow64 = FALSE; + PhGetProcessIsWow64(ProcessHandle, &isWow64); + } - if (isWow64) - { - flags |= PH_CLR_PROCESS_IS_WOW64; - PhEnumProcessModules32(ProcessHandle, PhpIsDotNetEnumProcessModulesCallback, &flags); - } - else - { + if (isWow64) + { + flags |= PH_CLR_PROCESS_IS_WOW64; + status = PhEnumProcessModules32(ProcessHandle, PhpIsDotNetEnumProcessModulesCallback, &flags); + } + else + { #endif - PhEnumProcessModules(ProcessHandle, PhpIsDotNetEnumProcessModulesCallback, &flags); + status = PhEnumProcessModules(ProcessHandle, PhpIsDotNetEnumProcessModulesCallback, &flags); #ifdef _WIN64 - } + } #endif - if (processHandle) - NtClose(processHandle); + if (processHandle) + NtClose(processHandle); - if (IsDotNet) - *IsDotNet = (flags & PH_CLR_VERSION_MASK) && (flags & (PH_CLR_MSCORLIB_PRESENT | PH_CLR_JIT_PRESENT)); + if (IsDotNet) + *IsDotNet = (flags & PH_CLR_VERSION_MASK) && (flags & (PH_CLR_MSCORLIB_PRESENT | PH_CLR_JIT_PRESENT)); - if (Flags) - *Flags = flags; + if (Flags) + *Flags = flags; - return status; + return status; + } } /** From 9af31675fbe34ae391f6a3c23cbe189410c63767 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 2 Jul 2017 02:24:22 +1000 Subject: [PATCH 0243/2058] Add FileOpenExecutable setting Feature request: https://wj32.org/processhacker/forums/viewtopic.php?p=8673 --- ProcessHacker/prpggen.c | 14 ++++++++++---- ProcessHacker/settings.c | 1 + 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/ProcessHacker/prpggen.c b/ProcessHacker/prpggen.c index 0fc4508d5593..d8a6a1dc9be7 100644 --- a/ProcessHacker/prpggen.c +++ b/ProcessHacker/prpggen.c @@ -478,9 +478,7 @@ INT_PTR CALLBACK PhpProcessGeneralDlgProc( break; case WM_COMMAND: { - INT id = LOWORD(wParam); - - switch (id) + switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDC_INSPECT: { @@ -499,7 +497,15 @@ INT_PTR CALLBACK PhpProcessGeneralDlgProc( case IDC_OPENFILENAME: { if (processItem->FileName) - PhShellExploreFile(hwndDlg, processItem->FileName->Buffer); + { + PhShellExecuteUserString( + hwndDlg, + L"FileOpenExecutable", + processItem->FileName->Buffer, + FALSE, + L"Make sure the Explorer executable file is present." + ); + } } break; case IDC_VIEWCOMMANDLINE: diff --git a/ProcessHacker/settings.c b/ProcessHacker/settings.c index a2f16f8c98c2..2642ccf91953 100644 --- a/ProcessHacker/settings.c +++ b/ProcessHacker/settings.c @@ -48,6 +48,7 @@ VOID PhAddDefaultSettings( PhpAddIntegerSetting(L"EnableWarnings", L"1"); PhpAddIntegerSetting(L"EnableWindowText", L"1"); PhpAddStringSetting(L"EnvironmentListViewColumns", L""); + PhpAddStringSetting(L"FileOpenExecutable", L"explorer.exe \"/select,%s\""); PhpAddIntegerSetting(L"FindObjRegex", L"0"); PhpAddStringSetting(L"FindObjListViewColumns", L""); PhpAddIntegerPairSetting(L"FindObjWindowPosition", L"350,350"); From 99b37d5549d26b4835519c56e2860d9792a3f4f3 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 2 Jul 2017 02:37:31 +1000 Subject: [PATCH 0244/2058] Fix file encoding --- tools/GenerateZw/GenerateZw/Program.cs | 52 ++-- .../GenerateZw/Properties/AssemblyInfo.cs | 72 ++--- tools/GenerateZw/GenerateZw/ZwGen.cs | 246 +++++++++--------- 3 files changed, 185 insertions(+), 185 deletions(-) diff --git a/tools/GenerateZw/GenerateZw/Program.cs b/tools/GenerateZw/GenerateZw/Program.cs index 4962274d9ee0..20ba3a89ee3d 100644 --- a/tools/GenerateZw/GenerateZw/Program.cs +++ b/tools/GenerateZw/GenerateZw/Program.cs @@ -1,26 +1,26 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace GenerateZw -{ - class Program - { - static void Main(string[] args) - { - ZwGen gen = new ZwGen(); - string configFile = args.Length > 0 ? args[0] : "options.txt"; - - try - { - gen.LoadConfig(configFile); - gen.Execute(); - } - catch (Exception ex) - { - Console.WriteLine(ex.ToString()); - } - } - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace GenerateZw +{ + class Program + { + static void Main(string[] args) + { + ZwGen gen = new ZwGen(); + string configFile = args.Length > 0 ? args[0] : "options.txt"; + + try + { + gen.LoadConfig(configFile); + gen.Execute(); + } + catch (Exception ex) + { + Console.WriteLine(ex.ToString()); + } + } + } +} diff --git a/tools/GenerateZw/GenerateZw/Properties/AssemblyInfo.cs b/tools/GenerateZw/GenerateZw/Properties/AssemblyInfo.cs index e45ace10f142..49da97e1ccc5 100644 --- a/tools/GenerateZw/GenerateZw/Properties/AssemblyInfo.cs +++ b/tools/GenerateZw/GenerateZw/Properties/AssemblyInfo.cs @@ -1,36 +1,36 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("GenerateZw")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("GenerateZw")] -[assembly: AssemblyCopyright("Copyright © 2010")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("db557e10-0bf4-4a74-b8b4-ade1faa91177")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("GenerateZw")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("GenerateZw")] +[assembly: AssemblyCopyright("Copyright © 2010")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("db557e10-0bf4-4a74-b8b4-ade1faa91177")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/tools/GenerateZw/GenerateZw/ZwGen.cs b/tools/GenerateZw/GenerateZw/ZwGen.cs index 5cb58d9cfa16..737610f9e935 100644 --- a/tools/GenerateZw/GenerateZw/ZwGen.cs +++ b/tools/GenerateZw/GenerateZw/ZwGen.cs @@ -1,123 +1,123 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.IO; -using System.Text.RegularExpressions; - -namespace GenerateZw -{ - class ServiceDefinition - { - public string Name; - public string Text; - public int NameIndex; - } - - class ServiceDefinitionComparer : IEqualityComparer - { - public bool Equals(ServiceDefinition x, ServiceDefinition y) - { - return string.Equals(x.Name, y.Name); - } - - public int GetHashCode(ServiceDefinition obj) - { - return obj.Name.GetHashCode(); - } - } - - class ZwGen - { - private string _baseDirectory; - private string[] _files; - private string _outputFile; - private string _header = ""; - private string _footer = ""; - - private List _defs; - - private string UnEscape(string text) - { - return text.Replace("\\r", "\r").Replace("\\n", "\n").Replace("\\\\", "\\"); - } - - public void LoadConfig(string fileName) - { - string[] lines = File.ReadAllLines(fileName); - - foreach (string line in lines) - { - string[] split = line.Split(new char[] { '=' }, 2); - - switch (split[0]) - { - case "base": - _baseDirectory = split[1]; - break; - case "in": - _files = split[1].Split(';'); - break; - case "out": - _outputFile = split[1]; - break; - case "header": - _header = UnEscape(split[1]); - break; - case "footer": - _footer = UnEscape(split[1]); - break; - } - } - } - - private void Parse(string text) - { - Regex regex = new Regex(@"NTSYSCALLAPI[\w\s_]*NTAPI\s*(Nt(\w)*)\(.*?\);", RegexOptions.Compiled | RegexOptions.Singleline); - MatchCollection matches; - - matches = regex.Matches(text); - - foreach (Match match in matches) - { - _defs.Add(new ServiceDefinition() { Name = match.Groups[1].Value, Text = match.Value, NameIndex = match.Groups[1].Index - match.Index }); - } - } - - public void Execute() - { - // Build up a list of definitions. - - _defs = new List(); - - foreach (string fileName in _files) - Parse(File.ReadAllText(_baseDirectory + "\\" + fileName)); - - StreamWriter sw = new StreamWriter(_baseDirectory + "\\" + _outputFile); - - // Remove duplicates and sort. - _defs = new List(_defs.Distinct(new ServiceDefinitionComparer())); - _defs.Sort((x, y) => string.CompareOrdinal(x.Name, y.Name)); - - // Header - - sw.Write(_header); - - // Definitions - - foreach (var d in _defs) - { - Console.WriteLine("System service: " + d.Name); - - // Write the original definition, replacing "Nt" with "Zw". - sw.Write(d.Text.Substring(0, d.NameIndex) + "Zw" + d.Text.Substring(d.NameIndex + 2) + "\r\n\r\n"); - } - - // Footer - - sw.Write(_footer); - - sw.Close(); - } - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.IO; +using System.Text.RegularExpressions; + +namespace GenerateZw +{ + class ServiceDefinition + { + public string Name; + public string Text; + public int NameIndex; + } + + class ServiceDefinitionComparer : IEqualityComparer + { + public bool Equals(ServiceDefinition x, ServiceDefinition y) + { + return string.Equals(x.Name, y.Name); + } + + public int GetHashCode(ServiceDefinition obj) + { + return obj.Name.GetHashCode(); + } + } + + class ZwGen + { + private string _baseDirectory; + private string[] _files; + private string _outputFile; + private string _header = ""; + private string _footer = ""; + + private List _defs; + + private string UnEscape(string text) + { + return text.Replace("\\r", "\r").Replace("\\n", "\n").Replace("\\\\", "\\"); + } + + public void LoadConfig(string fileName) + { + string[] lines = File.ReadAllLines(fileName); + + foreach (string line in lines) + { + string[] split = line.Split(new char[] { '=' }, 2); + + switch (split[0]) + { + case "base": + _baseDirectory = split[1]; + break; + case "in": + _files = split[1].Split(';'); + break; + case "out": + _outputFile = split[1]; + break; + case "header": + _header = UnEscape(split[1]); + break; + case "footer": + _footer = UnEscape(split[1]); + break; + } + } + } + + private void Parse(string text) + { + Regex regex = new Regex(@"NTSYSCALLAPI[\w\s_]*NTAPI\s*(Nt(\w)*)\(.*?\);", RegexOptions.Compiled | RegexOptions.Singleline); + MatchCollection matches; + + matches = regex.Matches(text); + + foreach (Match match in matches) + { + _defs.Add(new ServiceDefinition() { Name = match.Groups[1].Value, Text = match.Value, NameIndex = match.Groups[1].Index - match.Index }); + } + } + + public void Execute() + { + // Build up a list of definitions. + + _defs = new List(); + + foreach (string fileName in _files) + Parse(File.ReadAllText(_baseDirectory + "\\" + fileName)); + + StreamWriter sw = new StreamWriter(_baseDirectory + "\\" + _outputFile); + + // Remove duplicates and sort. + _defs = new List(_defs.Distinct(new ServiceDefinitionComparer())); + _defs.Sort((x, y) => string.CompareOrdinal(x.Name, y.Name)); + + // Header + + sw.Write(_header); + + // Definitions + + foreach (var d in _defs) + { + Console.WriteLine("System service: " + d.Name); + + // Write the original definition, replacing "Nt" with "Zw". + sw.Write(d.Text.Substring(0, d.NameIndex) + "Zw" + d.Text.Substring(d.NameIndex + 2) + "\r\n\r\n"); + } + + // Footer + + sw.Write(_footer); + + sw.Close(); + } + } +} From c2f2bc8f74c7aa498e8ad66220fa6c84244bbb48 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 2 Jul 2017 03:03:38 +1000 Subject: [PATCH 0245/2058] Fix typo --- ProcessHacker/settings.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ProcessHacker/settings.c b/ProcessHacker/settings.c index 2642ccf91953..fba8a2719d3e 100644 --- a/ProcessHacker/settings.c +++ b/ProcessHacker/settings.c @@ -48,11 +48,11 @@ VOID PhAddDefaultSettings( PhpAddIntegerSetting(L"EnableWarnings", L"1"); PhpAddIntegerSetting(L"EnableWindowText", L"1"); PhpAddStringSetting(L"EnvironmentListViewColumns", L""); - PhpAddStringSetting(L"FileOpenExecutable", L"explorer.exe \"/select,%s\""); PhpAddIntegerSetting(L"FindObjRegex", L"0"); PhpAddStringSetting(L"FindObjListViewColumns", L""); PhpAddIntegerPairSetting(L"FindObjWindowPosition", L"350,350"); PhpAddScalableIntegerPairSetting(L"FindObjWindowSize", L"@96|550,420"); + PhpAddStringSetting(L"FileOpenExecutable", L"explorer.exe \"/select,%s\""); PhpAddIntegerSetting(L"FirstRun", L"1"); PhpAddStringSetting(L"Font", L""); // null PhpAddIntegerSetting(L"ForceNoParent", L"0"); From 510e3ce870be6eee23ba18d05e583b849238b292 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 2 Jul 2017 13:57:53 +1000 Subject: [PATCH 0246/2058] NetworkTools: Add hostname lookup support, Fix network tab GDI leak --- plugins/NetworkTools/CHANGELOG.txt | 1 + plugins/NetworkTools/NetworkTools.vcxproj | 16 +- plugins/NetworkTools/main.c | 173 +++++++++++----------- plugins/NetworkTools/nettools.h | 3 +- plugins/NetworkTools/tracetree.c | 1 + 5 files changed, 99 insertions(+), 95 deletions(-) diff --git a/plugins/NetworkTools/CHANGELOG.txt b/plugins/NetworkTools/CHANGELOG.txt index 17bdec0b9e13..ce778d88aafb 100644 --- a/plugins/NetworkTools/CHANGELOG.txt +++ b/plugins/NetworkTools/CHANGELOG.txt @@ -1,6 +1,7 @@ 1.8 * Added custom tracert and whois support * Added geoip lookup for country name and image + * Added Tools menu > Network Tools > options 1.7 * Added option to specify ping buffer length diff --git a/plugins/NetworkTools/NetworkTools.vcxproj b/plugins/NetworkTools/NetworkTools.vcxproj index 307ef4de731f..3f96a14ded81 100644 --- a/plugins/NetworkTools/NetworkTools.vcxproj +++ b/plugins/NetworkTools/NetworkTools.vcxproj @@ -53,27 +53,27 @@ - iphlpapi.lib;winhttp.lib;ws2_32.lib;uxtheme.lib;%(AdditionalDependencies) - iphlpapi.dll;winhttp.dll;ws2_32.dll;%(DelayLoadDLLs) + dnsapi.lib;iphlpapi.lib;winhttp.lib;ws2_32.lib;uxtheme.lib;%(AdditionalDependencies) + dnsapi.dll;iphlpapi.dll;winhttp.dll;ws2_32.dll;%(DelayLoadDLLs) - iphlpapi.lib;winhttp.lib;ws2_32.lib;uxtheme.lib;%(AdditionalDependencies) - iphlpapi.dll;winhttp.dll;ws2_32.dll;%(DelayLoadDLLs) + dnsapi.lib;iphlpapi.lib;winhttp.lib;ws2_32.lib;uxtheme.lib;%(AdditionalDependencies) + dnsapi.dll;iphlpapi.dll;winhttp.dll;ws2_32.dll;%(DelayLoadDLLs) - iphlpapi.lib;winhttp.lib;ws2_32.lib;uxtheme.lib;%(AdditionalDependencies) - iphlpapi.dll;winhttp.dll;ws2_32.dll;%(DelayLoadDLLs) + dnsapi.lib;iphlpapi.lib;winhttp.lib;ws2_32.lib;uxtheme.lib;%(AdditionalDependencies) + dnsapi.dll;iphlpapi.dll;winhttp.dll;ws2_32.dll;%(DelayLoadDLLs) - iphlpapi.lib;winhttp.lib;ws2_32.lib;uxtheme.lib;%(AdditionalDependencies) - iphlpapi.dll;winhttp.dll;ws2_32.dll;%(DelayLoadDLLs) + dnsapi.lib;iphlpapi.lib;winhttp.lib;ws2_32.lib;uxtheme.lib;%(AdditionalDependencies) + dnsapi.dll;iphlpapi.dll;winhttp.dll;ws2_32.dll;%(DelayLoadDLLs) diff --git a/plugins/NetworkTools/main.c b/plugins/NetworkTools/main.c index 9cd8d0992746..1542ea7612e5 100644 --- a/plugins/NetworkTools/main.c +++ b/plugins/NetworkTools/main.c @@ -22,7 +22,6 @@ */ #include "nettools.h" -#include "tracert.h" #include PPH_PLUGIN PluginInstance; @@ -51,22 +50,80 @@ VOID NTAPI ShowOptionsCallback( ShowOptionsDialog((HWND)Parameter); } -HRESULT CALLBACK ElevateActionCallbackProc( - _In_ HWND hwnd, - _In_ UINT uNotification, - _In_ WPARAM wParam, - _In_ LPARAM lParam, - _In_ LONG_PTR dwRefData +static BOOLEAN ValidAddressInfo( + _In_ PPH_IP_ENDPOINT RemoteEndpoint, + _In_ PPH_STRING Name ) { - switch (uNotification) + PWSTR terminator = NULL; + + if (DnsValidateName(Name->Buffer, DnsNameValidateTld) == ERROR_SUCCESS) { - case TDN_CREATED: - SendMessage(hwnd, TDM_SET_BUTTON_ELEVATION_REQUIRED_STATE, IDYES, TRUE); - break; + BOOLEAN success = FALSE; + PADDRINFOT result; + WSADATA wsaData; + + WSAStartup(WINSOCK_VERSION, &wsaData); + + if (GetAddrInfo(Name->Buffer, NULL, NULL, &result) == ERROR_SUCCESS) + { + for (PADDRINFOT i = result; i; i = i->ai_next) + { + if (i->ai_family == AF_INET) + { + RemoteEndpoint->Address.InAddr.s_addr = ((PSOCKADDR_IN)i->ai_addr)->sin_addr.s_addr; + RemoteEndpoint->Port = ((PSOCKADDR_IN)i->ai_addr)->sin_port; + RemoteEndpoint->Address.Type = PH_IPV4_NETWORK_TYPE; + success = TRUE; + break; + } + else if (i->ai_family == AF_INET6) + { + memcpy( + RemoteEndpoint->Address.In6Addr.s6_addr, + ((PSOCKADDR_IN6)i->ai_addr)->sin6_addr.s6_addr, + sizeof(RemoteEndpoint->Address.In6Addr.s6_addr) + ); + RemoteEndpoint->Port = ((PSOCKADDR_IN6)i->ai_addr)->sin6_port; + RemoteEndpoint->Address.Type = PH_IPV6_NETWORK_TYPE; + success = TRUE; + break; + } + } + + FreeAddrInfo(result); + } + + WSACleanup(); + + if (success) + return TRUE; + } + else + { + if (NT_SUCCESS(RtlIpv4StringToAddress( + Name->Buffer, + TRUE, + &terminator, + &RemoteEndpoint->Address.InAddr + ))) + { + RemoteEndpoint->Address.Type = PH_IPV4_NETWORK_TYPE; + return TRUE; + } + + if (NT_SUCCESS(RtlIpv6StringToAddress( + Name->Buffer, + &terminator, + &RemoteEndpoint->Address.In6Addr + ))) + { + RemoteEndpoint->Address.Type = PH_IPV6_NETWORK_TYPE; + return TRUE; + } } - return S_OK; + return FALSE; } VOID NTAPI MenuItemCallback( @@ -89,45 +146,26 @@ VOID NTAPI MenuItemCallback( ShowWhoisWindow(networkItem); break; case MAINMENU_ACTION_PING: - { - PH_IP_ENDPOINT RemoteEndpoint; + { PPH_STRING selectedChoice = NULL; + PH_IP_ENDPOINT remoteEndpoint = { 0 }; while (PhaChoiceDialog( menuItem->OwnerWindow, L"Ping", - L"IP address:", + L"Hostname or IP address:", NULL, 0, NULL, PH_CHOICE_DIALOG_USER_CHOICE, &selectedChoice, NULL, - SETTING_NAME_TRACERT_HISTORY + SETTING_NAME_ADDRESS_HISTORY )) { - PWSTR terminator = NULL; - - if (NT_SUCCESS(RtlIpv4StringToAddress( - selectedChoice->Buffer, - TRUE, - &terminator, - &RemoteEndpoint.Address.InAddr - ))) + if (ValidAddressInfo(&remoteEndpoint, selectedChoice)) { - RemoteEndpoint.Address.Type = PH_IPV4_NETWORK_TYPE; - ShowPingWindowFromAddress(RemoteEndpoint); - break; - } - - if (NT_SUCCESS(RtlIpv6StringToAddress( - selectedChoice->Buffer, - &terminator, - &RemoteEndpoint.Address.In6Addr - ))) - { - RemoteEndpoint.Address.Type = PH_IPV6_NETWORK_TYPE; - ShowPingWindowFromAddress(RemoteEndpoint); + ShowPingWindowFromAddress(remoteEndpoint); break; } } @@ -135,44 +173,25 @@ VOID NTAPI MenuItemCallback( break; case MAINMENU_ACTION_TRACERT: { - PH_IP_ENDPOINT RemoteEndpoint; PPH_STRING selectedChoice = NULL; + PH_IP_ENDPOINT remoteEndpoint = { 0 }; while (PhaChoiceDialog( menuItem->OwnerWindow, L"Tracert", - L"IP address:", + L"Hostname or IP address:", NULL, 0, NULL, PH_CHOICE_DIALOG_USER_CHOICE, &selectedChoice, NULL, - SETTING_NAME_TRACERT_HISTORY + SETTING_NAME_ADDRESS_HISTORY )) { - PWSTR terminator = NULL; - - if (NT_SUCCESS(RtlIpv4StringToAddress( - selectedChoice->Buffer, - TRUE, - &terminator, - &RemoteEndpoint.Address.InAddr - ))) - { - RemoteEndpoint.Address.Type = PH_IPV4_NETWORK_TYPE; - ShowTracertWindowFromAddress(RemoteEndpoint); - break; - } - - if (NT_SUCCESS(RtlIpv6StringToAddress( - selectedChoice->Buffer, - &terminator, - &RemoteEndpoint.Address.In6Addr - ))) + if (ValidAddressInfo(&remoteEndpoint, selectedChoice)) { - RemoteEndpoint.Address.Type = PH_IPV6_NETWORK_TYPE; - ShowTracertWindowFromAddress(RemoteEndpoint); + ShowTracertWindowFromAddress(remoteEndpoint); break; } } @@ -180,44 +199,25 @@ VOID NTAPI MenuItemCallback( break; case MAINMENU_ACTION_WHOIS: { - PH_IP_ENDPOINT RemoteEndpoint; PPH_STRING selectedChoice = NULL; + PH_IP_ENDPOINT remoteEndpoint = { 0 }; while (PhaChoiceDialog( menuItem->OwnerWindow, L"Whois", - L"IP address for Whois:", + L"Hostname or IP address:", NULL, 0, NULL, PH_CHOICE_DIALOG_USER_CHOICE, &selectedChoice, NULL, - SETTING_NAME_TRACERT_HISTORY + SETTING_NAME_ADDRESS_HISTORY )) { - PWSTR terminator = NULL; - - if (NT_SUCCESS(RtlIpv4StringToAddress( - selectedChoice->Buffer, - TRUE, - &terminator, - &RemoteEndpoint.Address.InAddr - ))) - { - RemoteEndpoint.Address.Type = PH_IPV4_NETWORK_TYPE; - ShowWhoisWindowFromAddress(RemoteEndpoint); - break; - } - - if (NT_SUCCESS(RtlIpv6StringToAddress( - selectedChoice->Buffer, - &terminator, - &RemoteEndpoint.Address.In6Addr - ))) + if (ValidAddressInfo(&remoteEndpoint, selectedChoice)) { - RemoteEndpoint.Address.Type = PH_IPV6_NETWORK_TYPE; - ShowWhoisWindowFromAddress(RemoteEndpoint); + ShowWhoisWindowFromAddress(remoteEndpoint); break; } } @@ -528,6 +528,7 @@ VOID NTAPI TreeNewMessageCallback( if (countryBitmap = PhLoadPngImageFromResource(PluginInstance->DllBase, 16, 11, MAKEINTRESOURCE(resourceCode), TRUE)) { extension->CountryIcon = CommonBitmapToIcon(countryBitmap, 16, 11); + DeleteObject(countryBitmap); } } } @@ -585,6 +586,7 @@ LOGICAL DllMain( PPH_PLUGIN_INFORMATION info; PH_SETTING_CREATE settings[] = { + { StringSettingType, SETTING_NAME_ADDRESS_HISTORY, L"" }, { IntegerPairSettingType, SETTING_NAME_PING_WINDOW_POSITION, L"0,0" }, { ScalableIntegerPairSettingType, SETTING_NAME_PING_WINDOW_SIZE, L"@96|420,250" }, { IntegerSettingType, SETTING_NAME_PING_MINIMUM_SCALING, L"1F4" }, // 500ms minimum scaling @@ -592,7 +594,6 @@ LOGICAL DllMain( { IntegerPairSettingType, SETTING_NAME_TRACERT_WINDOW_POSITION, L"0,0" }, { ScalableIntegerPairSettingType, SETTING_NAME_TRACERT_WINDOW_SIZE, L"@96|850,490" }, { StringSettingType, SETTING_NAME_TRACERT_LIST_COLUMNS, L"" }, - { StringSettingType, SETTING_NAME_TRACERT_HISTORY, L"" }, { IntegerSettingType, SETTING_NAME_TRACERT_MAX_HOPS, L"30" }, { IntegerPairSettingType, SETTING_NAME_WHOIS_WINDOW_POSITION, L"0,0" }, { ScalableIntegerPairSettingType, SETTING_NAME_WHOIS_WINDOW_SIZE, L"@96|600,365" }, diff --git a/plugins/NetworkTools/nettools.h b/plugins/NetworkTools/nettools.h index 64ff271dc3c5..d2ae5088edf9 100644 --- a/plugins/NetworkTools/nettools.h +++ b/plugins/NetworkTools/nettools.h @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -45,6 +46,7 @@ #define PLUGIN_NAME L"ProcessHacker.NetworkTools" #define SETTING_NAME_DB_TYPE (PLUGIN_NAME L".GeoIpType") +#define SETTING_NAME_ADDRESS_HISTORY (PLUGIN_NAME L".AddressHistory") #define SETTING_NAME_PING_WINDOW_POSITION (PLUGIN_NAME L".PingWindowPosition") #define SETTING_NAME_PING_WINDOW_SIZE (PLUGIN_NAME L".PingWindowSize") #define SETTING_NAME_PING_MINIMUM_SCALING (PLUGIN_NAME L".PingMinScaling") @@ -52,7 +54,6 @@ #define SETTING_NAME_TRACERT_WINDOW_POSITION (PLUGIN_NAME L".TracertWindowPosition") #define SETTING_NAME_TRACERT_WINDOW_SIZE (PLUGIN_NAME L".TracertWindowSize") #define SETTING_NAME_TRACERT_LIST_COLUMNS (PLUGIN_NAME L".TracertListColumns") -#define SETTING_NAME_TRACERT_HISTORY (PLUGIN_NAME L".TracertAddresses") #define SETTING_NAME_TRACERT_MAX_HOPS (PLUGIN_NAME L".TracertMaxHops") #define SETTING_NAME_WHOIS_WINDOW_POSITION (PLUGIN_NAME L".WhoisWindowPosition") #define SETTING_NAME_WHOIS_WINDOW_SIZE (PLUGIN_NAME L".WhoisWindowSize") diff --git a/plugins/NetworkTools/tracetree.c b/plugins/NetworkTools/tracetree.c index a8deb46521b9..5b1a945edcc8 100644 --- a/plugins/NetworkTools/tracetree.c +++ b/plugins/NetworkTools/tracetree.c @@ -414,6 +414,7 @@ BOOLEAN NTAPI TracertTreeNewCallback( if (countryBitmap = PhLoadPngImageFromResource(PluginInstance->DllBase, 16, 11, MAKEINTRESOURCE(resourceCode), TRUE)) { node->CountryIcon = CommonBitmapToIcon(countryBitmap, 16, 11); + DeleteObject(countryBitmap); } } } From 3281a6a0098c973a01e2355024eba1b42be26c13 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 2 Jul 2017 14:07:04 +1000 Subject: [PATCH 0247/2058] BuildTools: Fix cleanup script bug --- build/build_clean.cmd | 2 - tools/CustomBuildTool/Source Files/Build.cs | 120 ++++++++---------- tools/CustomBuildTool/Source Files/Program.cs | 2 - tools/CustomBuildTool/Source Files/Utils.cs | 6 - .../bin/Release/CustomBuildTool.exe | Bin 160256 -> 160256 bytes .../bin/Release/CustomBuildTool.pdb | Bin 69120 -> 69120 bytes 6 files changed, 53 insertions(+), 77 deletions(-) diff --git a/build/build_clean.cmd b/build/build_clean.cmd index 2d0f2c182fe3..40de19df02f2 100644 --- a/build/build_clean.cmd +++ b/build/build_clean.cmd @@ -3,5 +3,3 @@ @cd /d "%~dp0\..\" start /B /W "" "tools\CustomBuildTool\bin\Release\CustomBuildTool.exe" "-cleanup" - -pause diff --git a/tools/CustomBuildTool/Source Files/Build.cs b/tools/CustomBuildTool/Source Files/Build.cs index b6cff3c57df3..f915c51c8408 100644 --- a/tools/CustomBuildTool/Source Files/Build.cs +++ b/tools/CustomBuildTool/Source Files/Build.cs @@ -228,10 +228,10 @@ public static void CleanupBuildEnvironment() try { - for (int i = 0; i < cleanupFileArray.Length; i++) + foreach (string file in cleanupFileArray) { - if (Directory.Exists(cleanupFileArray[i])) - Directory.Delete(cleanupFileArray[i], true); + if (Directory.Exists(file)) + Directory.Delete(file, true); } } catch (Exception ex) @@ -522,7 +522,7 @@ public static bool BuildPublicHeaderFiles() } catch (Exception ex) { - Program.PrintColorMessage("[ERROR] " + ex.ToString(), ConsoleColor.Red); + Program.PrintColorMessage("[ERROR] " + ex, ConsoleColor.Red); return false; } @@ -531,8 +531,6 @@ public static bool BuildPublicHeaderFiles() public static bool CopyKProcessHacker(BuildFlags Flags) { - Program.PrintColorMessage("Copying KPH driver...", ConsoleColor.Cyan, true, Flags); - if (!File.Exists(CustomSignToolPath)) return true; if (!File.Exists("build\\kph.key")) @@ -667,7 +665,7 @@ public static bool CopyKeyFiles() public static bool BuildSetupExe() { - Program.PrintColorMessage("Building build-setup.exe...", ConsoleColor.Cyan, true, BuildFlags.BuildVerbose); + Program.PrintColorMessage("Building build-setup.exe...", ConsoleColor.Cyan); if (!BuildSolution("tools\\CustomSetupTool\\CustomSetupTool.sln", BuildFlags.Build32bit | BuildFlags.BuildVerbose)) return false; @@ -918,7 +916,7 @@ public static void WebServiceUpdateConfig() if (!httpTask.Result.IsSuccessStatusCode) { - Program.PrintColorMessage("[UpdateBuildWebService] " + httpTask.Result.ToString(), ConsoleColor.Red); + Program.PrintColorMessage("[UpdateBuildWebService] " + httpTask.Result, ConsoleColor.Red); } } } @@ -946,14 +944,14 @@ public static bool AppveyorUploadBuildFiles() if (!BuildNightly) return false; - // Cleanup existing output files - for (int i = 0; i < releaseFileArray.Length; i++) + // Cleanup existing release files. + foreach (string file in releaseFileArray) { - if (File.Exists(releaseFileArray[i])) + if (File.Exists(file)) { try { - File.Delete(releaseFileArray[i]); + File.Delete(file); } catch (Exception ex) { @@ -963,7 +961,7 @@ public static bool AppveyorUploadBuildFiles() } } - // Rename files with the current build version -3.1- + // Rename build files with the current version processhacker-3.1-abc.ext for (int i = 0; i < buildFileArray.Length; i++) { if (File.Exists(buildFileArray[i])) @@ -980,16 +978,16 @@ public static bool AppveyorUploadBuildFiles() } } - // Upload build files to Appveyor storage. - for (int i = 0; i < releaseFileArray.Length; i++) + // Upload build files to download server. + foreach (string file in releaseFileArray) { - if (File.Exists(releaseFileArray[i])) + if (File.Exists(file)) { - Console.WriteLine("Uploading " + releaseFileArray[i] + "..."); + Console.WriteLine("Uploading " + file + "..."); try { - Win32.ShellExecute("appveyor", "PushArtifact " + releaseFileArray[i]); + Win32.ShellExecute("appveyor", "PushArtifact " + file); } catch (Exception ex) { @@ -999,13 +997,8 @@ public static bool AppveyorUploadBuildFiles() } } - try - { - // Update Appveyor build version string. - Win32.ShellExecute("appveyor", "UpdateBuild -Version \"" + BuildLongVersion + " (" + BuildCommit + ")\" "); - } - catch (Exception) - { } + // Update Appveyor build version string. + Win32.ShellExecute("appveyor", "UpdateBuild -Version \"" + BuildLongVersion + " (" + BuildCommit + ")\" "); return true; } @@ -1062,7 +1055,20 @@ public static bool BuildSolution(string Solution, BuildFlags Flags) #region Appx Package public static void BuildAppxPackage(BuildFlags Flags) { + string[] cleanupAppxArray = + { + BuildOutputFolder + "\\AppxManifest32.xml", + BuildOutputFolder + "\\AppxManifest64.xml", + BuildOutputFolder + "\\package32.map", + BuildOutputFolder + "\\package64.map", + BuildOutputFolder + "\\bundle.map", + BuildOutputFolder + "\\ProcessHacker-44.png", + BuildOutputFolder + "\\ProcessHacker-50.png", + BuildOutputFolder + "\\ProcessHacker-150.png" + }; + Program.PrintColorMessage("Building processhacker-build-package.appxbundle...", ConsoleColor.Cyan); + string signToolExePath = Environment.ExpandEnvironmentVariables("%ProgramFiles(x86)%\\Windows Kits\\10\\bin\\x64\\SignTool.exe"); try @@ -1088,10 +1094,8 @@ public static void BuildAppxPackage(BuildFlags Flags) packageMap32.AppendLine("\"" + BuildOutputFolder + "\\ProcessHacker-150.png\" \"Assets\\ProcessHacker-150.png\""); var filesToAdd = Directory.GetFiles("bin\\Release32", "*", SearchOption.AllDirectories); - for (int i = 0; i < filesToAdd.Length; i++) + foreach (string filePath in filesToAdd) { - string filePath = filesToAdd[i]; - // Ignore junk files if (filePath.EndsWith(".pdb", StringComparison.OrdinalIgnoreCase) || filePath.EndsWith(".iobj", StringComparison.OrdinalIgnoreCase) || @@ -1103,13 +1107,13 @@ public static void BuildAppxPackage(BuildFlags Flags) } packageMap32.AppendLine("\"" + filePath + "\" \"" + filePath.Substring("bin\\Release32\\".Length) + "\""); - } + } File.WriteAllText(BuildOutputFolder + "\\package32.map", packageMap32.ToString()); // create the package Win32.ShellExecute( MakeAppxExePath, - "pack /o /f " + BuildOutputFolder + "\\package32.map /p " + + "pack /o /f " + BuildOutputFolder + "\\package32.map /p " + BuildOutputFolder + "\\processhacker-build-package-x32.appx" ); //Program.PrintColorMessage(Environment.NewLine + error, ConsoleColor.Gray); @@ -1117,7 +1121,7 @@ public static void BuildAppxPackage(BuildFlags Flags) // sign the package Win32.ShellExecute( signToolExePath, - "sign /v /fd SHA256 /a /f " + BuildOutputFolder + "\\processhacker-appx.pfx /td SHA256 " + + "sign /v /fd SHA256 /a /f " + BuildOutputFolder + "\\processhacker-appx.pfx /td SHA256 " + BuildOutputFolder + "\\processhacker-build-package-x32.appx" ); //Program.PrintColorMessage(Environment.NewLine + error, ConsoleColor.Gray); @@ -1139,10 +1143,8 @@ public static void BuildAppxPackage(BuildFlags Flags) packageMap64.AppendLine("\"" + BuildOutputFolder + "\\ProcessHacker-150.png\" \"Assets\\ProcessHacker-150.png\""); var filesToAdd = Directory.GetFiles("bin\\Release64", "*", SearchOption.AllDirectories); - for (int i = 0; i < filesToAdd.Length; i++) + foreach (string filePath in filesToAdd) { - string filePath = filesToAdd[i]; - // Ignore junk files if (filePath.EndsWith(".pdb", StringComparison.OrdinalIgnoreCase) || filePath.EndsWith(".iobj", StringComparison.OrdinalIgnoreCase) || @@ -1160,7 +1162,7 @@ public static void BuildAppxPackage(BuildFlags Flags) // create the package Win32.ShellExecute( MakeAppxExePath, - "pack /o /f " + BuildOutputFolder + "\\package64.map /p " + + "pack /o /f " + BuildOutputFolder + "\\package64.map /p " + BuildOutputFolder + "\\processhacker-build-package-x64.appx" ); //Program.PrintColorMessage(Environment.NewLine + error, ConsoleColor.Gray); @@ -1168,7 +1170,7 @@ public static void BuildAppxPackage(BuildFlags Flags) // sign the package Win32.ShellExecute( signToolExePath, - "sign /v /fd SHA256 /a /f " + BuildOutputFolder + "\\processhacker-appx.pfx /td SHA256 " + + "sign /v /fd SHA256 /a /f " + BuildOutputFolder + "\\processhacker-appx.pfx /td SHA256 " + BuildOutputFolder + "\\processhacker-build-package-x64.appx" ); //Program.PrintColorMessage(Environment.NewLine + error, ConsoleColor.Gray); @@ -1188,7 +1190,7 @@ public static void BuildAppxPackage(BuildFlags Flags) // create the appx bundle package Win32.ShellExecute( MakeAppxExePath, - "bundle /f " + BuildOutputFolder + "\\bundle.map /p " + + "bundle /f " + BuildOutputFolder + "\\bundle.map /p " + BuildOutputFolder + "\\processhacker-build-package.appxbundle" ); //Program.PrintColorMessage(Environment.NewLine + error, ConsoleColor.Gray); @@ -1196,33 +1198,17 @@ public static void BuildAppxPackage(BuildFlags Flags) // sign the appx bundle package Win32.ShellExecute( signToolExePath, - "sign /v /fd SHA256 /a /f " + BuildOutputFolder + "\\processhacker-appx.pfx /td SHA256 " + + "sign /v /fd SHA256 /a /f " + BuildOutputFolder + "\\processhacker-appx.pfx /td SHA256 " + BuildOutputFolder + "\\processhacker-build-package.appxbundle" ); //Program.PrintColorMessage(Environment.NewLine + error, ConsoleColor.Gray); } - try + foreach (string file in cleanupAppxArray) { - string[] cleanupAppxArray = - { - BuildOutputFolder + "\\AppxManifest32.xml", - BuildOutputFolder + "\\AppxManifest64.xml", - BuildOutputFolder + "\\package32.map", - BuildOutputFolder + "\\package64.map", - BuildOutputFolder + "\\bundle.map", - BuildOutputFolder + "\\ProcessHacker-44.png", - BuildOutputFolder + "\\ProcessHacker-50.png", - BuildOutputFolder + "\\ProcessHacker-150.png" - }; - - for (int i = 0; i < cleanupAppxArray.Length; i++) - { - if (File.Exists(cleanupAppxArray[i])) - File.Delete(cleanupAppxArray[i]); - } + if (File.Exists(file)) + File.Delete(file); } - catch (Exception) { } } catch (Exception ex) { @@ -1232,6 +1218,13 @@ public static void BuildAppxPackage(BuildFlags Flags) public static bool BuildAppxSignature() { + string[] cleanupAppxArray = + { + BuildOutputFolder + "\\processhacker-appx.pvk", + BuildOutputFolder + "\\processhacker-appx.cer", + BuildOutputFolder + "\\processhacker-appx.pfx" + }; + Program.PrintColorMessage("Building Appx Signature...", ConsoleColor.Cyan); var makeCertExePath = Environment.ExpandEnvironmentVariables("%ProgramFiles(x86)%\\Windows Kits\\10\\bin\\x64\\MakeCert.exe"); @@ -1239,17 +1232,10 @@ public static bool BuildAppxSignature() try { - string[] cleanupAppxArray = - { - BuildOutputFolder + "\\processhacker-appx.pvk", - BuildOutputFolder + "\\processhacker-appx.cer", - BuildOutputFolder + "\\processhacker-appx.pfx" - }; - - for (int i = 0; i < cleanupAppxArray.Length; i++) + foreach (string file in cleanupAppxArray) { - if (File.Exists(cleanupAppxArray[i])) - File.Delete(cleanupAppxArray[i]); + if (File.Exists(file)) + File.Delete(file); } string output = Win32.ShellExecute(makeCertExePath, diff --git a/tools/CustomBuildTool/Source Files/Program.cs b/tools/CustomBuildTool/Source Files/Program.cs index 2633a5abf563..18cd8d9e43b6 100644 --- a/tools/CustomBuildTool/Source Files/Program.cs +++ b/tools/CustomBuildTool/Source Files/Program.cs @@ -352,8 +352,6 @@ private static bool Restart(string Arguments) if (principal.IsInRole(WindowsBuiltInRole.Administrator)) return false; - Win32.ShowWindow(Win32.GetConsoleWindow(), Win32.SW_HIDE); - try { System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo diff --git a/tools/CustomBuildTool/Source Files/Utils.cs b/tools/CustomBuildTool/Source Files/Utils.cs index 55a870ce71e8..dd7677d380e8 100644 --- a/tools/CustomBuildTool/Source Files/Utils.cs +++ b/tools/CustomBuildTool/Source Files/Utils.cs @@ -107,8 +107,6 @@ public static void CopyIfNewer(string CurrentFile, string NewFile) } } - public const int SW_HIDE = 0; - public const int SW_SHOW = 5; public static readonly IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1); public static readonly IntPtr STD_OUTPUT_HANDLE = new IntPtr(-11); public static readonly IntPtr STD_INPUT_HANDLE = new IntPtr(-10); @@ -122,10 +120,6 @@ public static void CopyIfNewer(string CurrentFile, string NewFile) public static extern bool SetConsoleMode(IntPtr ConsoleHandle, ConsoleMode Mode); [DllImport("kernel32.dll", ExactSpelling = true)] public static extern IntPtr GetConsoleWindow(); - [DllImport("user32.dll", ExactSpelling = true)] - public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow); - [DllImport("user32.dll", CharSet = CharSet.Unicode)] - public static extern int MessageBox(IntPtr hWnd, string m, string c, int type); } public static class Json where T : class diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe b/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe index 604822da66d7cf6ba84cfa11fd1f7a9e9515ee69..ac40ae99e063999800bb18b2a9740a8b0b41da61 100644 GIT binary patch delta 16322 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 delta 16535 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 QnYv*n{pEsi^Ttj8514)mAOHXW delta 13990 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 PKg8_)OZ!ms!9D*Ai`+4q From 68c42c23acd14cb79140b924d7700641c40820fd Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 2 Jul 2017 14:42:24 +1000 Subject: [PATCH 0248/2058] NetworkTools: Remove whois dialog uxtheme hack --- plugins/NetworkTools/whois.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/plugins/NetworkTools/whois.c b/plugins/NetworkTools/whois.c index 3cca5ef466df..0649bd0a9168 100644 --- a/plugins/NetworkTools/whois.c +++ b/plugins/NetworkTools/whois.c @@ -402,10 +402,7 @@ INT_PTR CALLBACK NetworkOutputDlgProc( context->WindowHandle = hwndDlg; context->RichEditHandle = GetDlgItem(hwndDlg, IDC_NETOUTPUTEDIT); - // Reset the border style for richedit uxtheme borders - PhSetWindowStyle(context->RichEditHandle, WS_BORDER, WS_BORDER); - PhSetWindowExStyle(context->RichEditHandle, WS_EX_CLIENTEDGE, ~WS_EX_CLIENTEDGE); - //SendMessage(context->OutputHandle, EM_SETBKGNDCOLOR, RGB(0, 0, 0), 0); + //SendMessage(context->RichEditHandle, EM_SETBKGNDCOLOR, RGB(0, 0, 0), 0); SendMessage(context->RichEditHandle, EM_SETEVENTMASK, 0, SendMessage(context->RichEditHandle, EM_GETEVENTMASK, 0, 0) | ENM_LINK); SendMessage(context->RichEditHandle, EM_AUTOURLDETECT, AURL_ENABLEURL, 0); SendMessage(context->RichEditHandle, EM_SETWORDWRAPMODE, WBF_WORDWRAP, 0); From 7b1f8b32181da651952497599e8ebb85a7441560 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 3 Jul 2017 01:57:44 +1000 Subject: [PATCH 0249/2058] Improve ImageBaseAddress handling, Fix bootstrap resource lookup (1/2) --- ProcessHacker/ProcessHacker.def | 2 +- ProcessHacker/chproc.c | 3 +++ ProcessHacker/findobj.c | 4 ++-- ProcessHacker/hndlprp.c | 2 ++ ProcessHacker/include/phapp.h | 1 - ProcessHacker/infodlg.c | 4 ++-- ProcessHacker/jobprp.c | 4 ++++ ProcessHacker/logwnd.c | 4 ++-- ProcessHacker/main.c | 21 +++++++--------- ProcessHacker/mainwnd.c | 10 ++++---- ProcessHacker/memedit.c | 4 ++-- ProcessHacker/memrslt.c | 4 ++-- ProcessHacker/miniinfo.c | 8 +++---- ProcessHacker/ntobjprp.c | 1 + ProcessHacker/options.c | 6 +++++ ProcessHacker/plugin.c | 36 +++++++++++----------------- ProcessHacker/procprp.c | 6 ++--- ProcessHacker/procrec.c | 2 +- ProcessHacker/prpgenv.c | 4 ++-- ProcessHacker/prpggen.c | 4 ++-- ProcessHacker/prpgthrd.c | 2 +- ProcessHacker/splitter.c | 4 ++-- ProcessHacker/srvlist.c | 8 +++---- ProcessHacker/srvprp.c | 2 ++ ProcessHacker/sysinfo.c | 4 ++-- ProcessHacker/thrdstk.c | 4 ++-- ProcessHacker/tokprp.c | 8 +++++++ phlib/colorbox.c | 2 +- phlib/global.c | 8 +++---- phlib/graph.c | 4 ++-- phlib/hexedit.c | 2 +- phlib/include/phconfig.h | 3 ++- phlib/native.c | 2 +- phlib/treenew.c | 2 +- phlib/util.c | 4 ++-- plugins/ExtendedTools/gpunodes.c | 4 ++-- plugins/ExtendedTools/unldll.c | 4 ++-- plugins/ExtraPlugins/dialog.c | 4 ++-- plugins/ExtraPlugins/setup/updater.c | 4 ++-- plugins/NetworkTools/ping.c | 4 ++-- plugins/NetworkTools/tracert.c | 4 ++-- plugins/NetworkTools/update.c | 4 ++-- plugins/NetworkTools/whois.c | 4 ++-- plugins/OnlineChecks/main.c | 2 +- plugins/OnlineChecks/upload.c | 4 ++-- plugins/Updater/options.c | 4 ++-- plugins/Updater/updater.c | 4 ++-- tools/peview/main.c | 2 +- tools/peview/prpsh.c | 4 ++-- tools/peview/searchbox.c | 8 +++---- 50 files changed, 132 insertions(+), 117 deletions(-) diff --git a/ProcessHacker/ProcessHacker.def b/ProcessHacker/ProcessHacker.def index 6804648802d8..9e693cb33b12 100644 --- a/ProcessHacker/ProcessHacker.def +++ b/ProcessHacker/ProcessHacker.def @@ -40,7 +40,7 @@ EXPORTS PhGlobalDpi DATA PhHeapHandle DATA PhIsExecutingInWow64 - PhLibImageBase DATA + PhInstanceHandle DATA PhOsVersion DATA PhSystemBasicInformation DATA ProcessAllAccess DATA diff --git a/ProcessHacker/chproc.c b/ProcessHacker/chproc.c index a39911ba828e..e9f3c532d482 100644 --- a/ProcessHacker/chproc.c +++ b/ProcessHacker/chproc.c @@ -205,6 +205,9 @@ INT_PTR CALLBACK PhpChooseProcessDlgProc( { HWND lvHandle; + SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER))); + SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER))); + PhCenterWindow(hwndDlg, GetParent(hwndDlg)); SetDlgItemText(hwndDlg, IDC_MESSAGE, context->Message); diff --git a/ProcessHacker/findobj.c b/ProcessHacker/findobj.c index 77e5ed193412..57a673c25e03 100644 --- a/ProcessHacker/findobj.c +++ b/ProcessHacker/findobj.c @@ -215,8 +215,8 @@ static INT_PTR CALLBACK PhpFindObjectsDlgProc( { HWND lvHandle; - SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhLibImageBase, MAKEINTRESOURCE(IDI_PROCESSHACKER))); - SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhLibImageBase, MAKEINTRESOURCE(IDI_PROCESSHACKER))); + SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER))); + SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER))); PhCenterWindow(hwndDlg, GetParent(hwndDlg)); PhFindObjectsListViewHandle = lvHandle = GetDlgItem(hwndDlg, IDC_RESULTS); diff --git a/ProcessHacker/hndlprp.c b/ProcessHacker/hndlprp.c index 339a95476d44..e98ce8c949ad 100644 --- a/ProcessHacker/hndlprp.c +++ b/ProcessHacker/hndlprp.c @@ -94,6 +94,7 @@ VOID PhShowHandleProperties( PSH_NOAPPLYNOW | PSH_NOCONTEXTHELP | PSH_PROPTITLE; + propSheetHeader.hInstance = PhInstanceHandle; propSheetHeader.hwndParent = ParentWindowHandle; propSheetHeader.pszCaption = L"Handle"; propSheetHeader.nPages = 0; @@ -104,6 +105,7 @@ VOID PhShowHandleProperties( memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); propSheetPage.dwSize = sizeof(PROPSHEETPAGE); propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_HNDLGENERAL); + propSheetPage.hInstance = PhInstanceHandle; propSheetPage.pfnDlgProc = PhpHandleGeneralDlgProc; propSheetPage.lParam = (LPARAM)&context; pages[propSheetHeader.nPages++] = CreatePropertySheetPage(&propSheetPage); diff --git a/ProcessHacker/include/phapp.h b/ProcessHacker/include/phapp.h index 0237a4cb5ff1..82099e4e0225 100644 --- a/ProcessHacker/include/phapp.h +++ b/ProcessHacker/include/phapp.h @@ -76,7 +76,6 @@ extern PPH_STRING PhApplicationDirectory; extern PPH_STRING PhApplicationFileName; PHAPPAPI extern HFONT PhApplicationFont; // phapppub extern PPH_STRING PhCurrentUserName; -extern HINSTANCE PhInstanceHandle; extern PPH_STRING PhLocalSystemName; extern BOOLEAN PhPluginsEnabled; extern PPH_STRING PhSettingsFileName; diff --git a/ProcessHacker/infodlg.c b/ProcessHacker/infodlg.c index 8c8cf487cc57..73b8fa1916d3 100644 --- a/ProcessHacker/infodlg.c +++ b/ProcessHacker/infodlg.c @@ -46,8 +46,8 @@ static INT_PTR CALLBACK PhpInformationDlgProc( PINFORMATION_CONTEXT context = (PINFORMATION_CONTEXT)lParam; PPH_LAYOUT_MANAGER layoutManager; - SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhLibImageBase, MAKEINTRESOURCE(IDI_PROCESSHACKER))); - SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhLibImageBase, MAKEINTRESOURCE(IDI_PROCESSHACKER))); + SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER))); + SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER))); PhCenterWindow(hwndDlg, GetParent(hwndDlg)); diff --git a/ProcessHacker/jobprp.c b/ProcessHacker/jobprp.c index a9668838d10d..a8151338c781 100644 --- a/ProcessHacker/jobprp.c +++ b/ProcessHacker/jobprp.c @@ -73,6 +73,7 @@ VOID PhShowJobProperties( PSH_NOAPPLYNOW | PSH_NOCONTEXTHELP | PSH_PROPTITLE; + propSheetHeader.hInstance = PhInstanceHandle; propSheetHeader.hwndParent = ParentWindowHandle; propSheetHeader.pszCaption = Title ? Title : L"Job"; propSheetHeader.nPages = 1; @@ -104,6 +105,7 @@ HPROPSHEETPAGE PhCreateJobPage( propSheetPage.dwSize = sizeof(PROPSHEETPAGE); propSheetPage.dwFlags = PSP_USECALLBACK; propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_OBJJOB); + propSheetPage.hInstance = PhInstanceHandle; propSheetPage.pfnDlgProc = PhpJobPageProc; propSheetPage.lParam = (LPARAM)jobPageContext; propSheetPage.pfnCallback = PhpJobPropPageProc; @@ -500,6 +502,7 @@ VOID PhpShowJobAdvancedProperties( PSH_NOAPPLYNOW | PSH_NOCONTEXTHELP | PSH_PROPTITLE; + propSheetHeader.hInstance = PhInstanceHandle; propSheetHeader.hwndParent = ParentWindowHandle; propSheetHeader.pszCaption = L"Job"; propSheetHeader.nPages = 2; @@ -511,6 +514,7 @@ VOID PhpShowJobAdvancedProperties( memset(&statisticsPage, 0, sizeof(PROPSHEETPAGE)); statisticsPage.dwSize = sizeof(PROPSHEETPAGE); statisticsPage.pszTemplate = MAKEINTRESOURCE(IDD_JOBSTATISTICS); + statisticsPage.hInstance = PhInstanceHandle; statisticsPage.pfnDlgProc = PhpJobStatisticsPageProc; statisticsPage.lParam = (LPARAM)Context; pages[0] = CreatePropertySheetPage(&statisticsPage); diff --git a/ProcessHacker/logwnd.c b/ProcessHacker/logwnd.c index 1bcfe90a3f01..74d7e4fe7289 100644 --- a/ProcessHacker/logwnd.c +++ b/ProcessHacker/logwnd.c @@ -156,8 +156,8 @@ INT_PTR CALLBACK PhpLogDlgProc( { case WM_INITDIALOG: { - SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhLibImageBase, MAKEINTRESOURCE(IDI_PROCESSHACKER))); - SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhLibImageBase, MAKEINTRESOURCE(IDI_PROCESSHACKER))); + SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER))); + SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER))); ListViewHandle = GetDlgItem(hwndDlg, IDC_LIST); PhSetListViewStyle(ListViewHandle, FALSE, TRUE); diff --git a/ProcessHacker/main.c b/ProcessHacker/main.c index 1515bf3caefb..2ed7ebff5408 100644 --- a/ProcessHacker/main.c +++ b/ProcessHacker/main.c @@ -75,11 +75,10 @@ VOID PhpEnablePrivileges( VOID ); -PPH_STRING PhApplicationDirectory; -PPH_STRING PhApplicationFileName; -PHAPPAPI HFONT PhApplicationFont; +PPH_STRING PhApplicationDirectory = NULL; +PPH_STRING PhApplicationFileName = NULL; +PHAPPAPI HFONT PhApplicationFont = NULL; PPH_STRING PhCurrentUserName = NULL; -HINSTANCE PhInstanceHandle; PPH_STRING PhLocalSystemName = NULL; BOOLEAN PhPluginsEnabled = FALSE; PPH_STRING PhSettingsFileName = NULL; @@ -95,10 +94,10 @@ static PPH_LIST FilterList = NULL; static PH_AUTO_POOL BaseAutoPool; INT WINAPI wWinMain( - _In_ HINSTANCE hInstance, - _In_opt_ HINSTANCE hPrevInstance, - _In_ PWSTR lpCmdLine, - _In_ INT nCmdShow + _In_ HINSTANCE Instance, + _In_opt_ HINSTANCE PrevInstance, + _In_ PWSTR CmdLine, + _In_ INT CmdShow ) { LONG result; @@ -112,9 +111,7 @@ INT WINAPI wWinMain( SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX); #endif - PhInstanceHandle = (HINSTANCE)NtCurrentPeb()->ImageBaseAddress; - - if (!NT_SUCCESS(PhInitializePhLib())) + if (!NT_SUCCESS(PhInitializePhLibEx(ULONG_MAX, Instance, 0, 0))) return 1; if (!PhInitializeAppSystem()) return 1; @@ -287,7 +284,7 @@ INT WINAPI wWinMain( NtSetInformationProcess(NtCurrentProcess(), ProcessPriorityClass, &priorityClass, sizeof(PROCESS_PRIORITY_CLASS)); } - if (!PhMainWndInitialization(nCmdShow)) + if (!PhMainWndInitialization(CmdShow)) { PhShowError(NULL, L"Unable to initialize the main window."); return 1; diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index f73c3b15d263..6c2c41e4ea6a 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -352,8 +352,8 @@ RTL_ATOM PhMwpInitializeWindowClass( wcex.lpszClassName = PhGetStringOrDefault(className, L"MainWindowClassName"); wcex.lpszMenuName = MAKEINTRESOURCE(IDR_MAINWND); wcex.hCursor = LoadCursor(NULL, IDC_ARROW); - wcex.hIcon = PH_LOAD_SHARED_ICON_LARGE(PhLibImageBase, MAKEINTRESOURCE(IDI_PROCESSHACKER)); - wcex.hIconSm = PH_LOAD_SHARED_ICON_SMALL(PhLibImageBase, MAKEINTRESOURCE(IDI_PROCESSHACKER)); + wcex.hIcon = PH_LOAD_SHARED_ICON_LARGE(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER)); + wcex.hIconSm = PH_LOAD_SHARED_ICON_SMALL(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER)); return RegisterClassEx(&wcex); } @@ -429,7 +429,7 @@ VOID PhMwpInitializeControls( 3, PhMainWndHandle, NULL, - PhLibImageBase, + PhInstanceHandle, NULL ); BringWindowToTop(PhMwpProcessTreeNewHandle); @@ -444,7 +444,7 @@ VOID PhMwpInitializeControls( 3, PhMainWndHandle, NULL, - PhLibImageBase, + PhInstanceHandle, NULL ); BringWindowToTop(PhMwpServiceTreeNewHandle); @@ -459,7 +459,7 @@ VOID PhMwpInitializeControls( 3, PhMainWndHandle, NULL, - PhLibImageBase, + PhInstanceHandle, NULL ); BringWindowToTop(PhMwpNetworkTreeNewHandle); diff --git a/ProcessHacker/memedit.c b/ProcessHacker/memedit.c index b76344d1c68a..1d78c2caa17b 100644 --- a/ProcessHacker/memedit.c +++ b/ProcessHacker/memedit.c @@ -189,8 +189,8 @@ INT_PTR CALLBACK PhpMemoryEditorDlgProc( { NTSTATUS status; - SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhLibImageBase, MAKEINTRESOURCE(IDI_PROCESSHACKER))); - SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhLibImageBase, MAKEINTRESOURCE(IDI_PROCESSHACKER))); + SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER))); + SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER))); if (context->Title) { diff --git a/ProcessHacker/memrslt.c b/ProcessHacker/memrslt.c index a066c5770f2b..cb3c8b38e367 100644 --- a/ProcessHacker/memrslt.c +++ b/ProcessHacker/memrslt.c @@ -279,8 +279,8 @@ INT_PTR CALLBACK PhpMemoryResultsDlgProc( { HWND lvHandle; - SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhLibImageBase, MAKEINTRESOURCE(IDI_PROCESSHACKER))); - SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhLibImageBase, MAKEINTRESOURCE(IDI_PROCESSHACKER))); + SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER))); + SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER))); PhRegisterDialog(hwndDlg); diff --git a/ProcessHacker/miniinfo.c b/ProcessHacker/miniinfo.c index 3a7b394662f0..11be6ea18103 100644 --- a/ProcessHacker/miniinfo.c +++ b/ProcessHacker/miniinfo.c @@ -110,11 +110,11 @@ VOID PhPinMiniInformation( wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = PhInstanceHandle; - wcex.hIcon = PH_LOAD_SHARED_ICON_LARGE(PhLibImageBase, MAKEINTRESOURCE(IDI_PROCESSHACKER)); + wcex.hIcon = PH_LOAD_SHARED_ICON_LARGE(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER)); wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1); wcex.lpszClassName = MIP_CONTAINER_CLASSNAME; - wcex.hIconSm = PH_LOAD_SHARED_ICON_SMALL(PhLibImageBase, MAKEINTRESOURCE(IDI_PROCESSHACKER)); + wcex.hIconSm = PH_LOAD_SHARED_ICON_SMALL(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER)); RegisterClassEx(&wcex); PhMipContainerWindow = CreateWindow( @@ -448,10 +448,10 @@ VOID PhMipOnInitDialog( HICON cog; HICON pin; - cog = PH_LOAD_SHARED_ICON_SMALL(PhLibImageBase, MAKEINTRESOURCE(IDI_COG)); + cog = PH_LOAD_SHARED_ICON_SMALL(PhInstanceHandle, MAKEINTRESOURCE(IDI_COG)); SET_BUTTON_ICON(PhMipWindow, IDC_OPTIONS, cog); - pin = PH_LOAD_SHARED_ICON_SMALL(PhLibImageBase, MAKEINTRESOURCE(IDI_PIN)); + pin = PH_LOAD_SHARED_ICON_SMALL(PhInstanceHandle, MAKEINTRESOURCE(IDI_PIN)); SET_BUTTON_ICON(PhMipWindow, IDC_PIN, pin); PhInitializeLayoutManager(&PhMipLayoutManager, PhMipWindow); diff --git a/ProcessHacker/ntobjprp.c b/ProcessHacker/ntobjprp.c index 5235537c7e18..b2e892f6550f 100644 --- a/ProcessHacker/ntobjprp.c +++ b/ProcessHacker/ntobjprp.c @@ -108,6 +108,7 @@ static HPROPSHEETPAGE PhpCommonCreatePage( propSheetPage.dwSize = sizeof(PROPSHEETPAGE); propSheetPage.dwFlags = PSP_USECALLBACK; propSheetPage.pszTemplate = Template; + propSheetPage.hInstance = PhInstanceHandle; propSheetPage.pfnDlgProc = DlgProc; propSheetPage.lParam = (LPARAM)pageContext; propSheetPage.pfnCallback = PhpCommonPropPageProc; diff --git a/ProcessHacker/options.c b/ProcessHacker/options.c index 4f27c293ce3e..21944675fa3e 100644 --- a/ProcessHacker/options.c +++ b/ProcessHacker/options.c @@ -121,6 +121,7 @@ VOID PhShowOptionsDialog( PSH_NOCONTEXTHELP | PSH_USECALLBACK | PSH_USEPSTARTPAGE; + propSheetHeader.hInstance = PhInstanceHandle; propSheetHeader.hwndParent = ParentWindowHandle; propSheetHeader.pszCaption = L"Options"; propSheetHeader.nPages = 0; @@ -135,6 +136,7 @@ VOID PhShowOptionsDialog( memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); propSheetPage.dwSize = sizeof(PROPSHEETPAGE); propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_OPTGENERAL); + propSheetPage.hInstance = PhInstanceHandle; propSheetPage.pfnDlgProc = PhpOptionsGeneralDlgProc; pages[propSheetHeader.nPages++] = CreatePropertySheetPage(&propSheetPage); } @@ -143,6 +145,7 @@ VOID PhShowOptionsDialog( memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); propSheetPage.dwSize = sizeof(PROPSHEETPAGE); propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_OPTADVANCED); + propSheetPage.hInstance = PhInstanceHandle; propSheetPage.pfnDlgProc = PhpOptionsAdvancedDlgProc; pages[propSheetHeader.nPages++] = CreatePropertySheetPage(&propSheetPage); @@ -152,6 +155,7 @@ VOID PhShowOptionsDialog( memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); propSheetPage.dwSize = sizeof(PROPSHEETPAGE); propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_OPTSYMBOLS); + propSheetPage.hInstance = PhInstanceHandle; propSheetPage.pfnDlgProc = PhpOptionsSymbolsDlgProc; pages[propSheetHeader.nPages++] = CreatePropertySheetPage(&propSheetPage); } @@ -162,6 +166,7 @@ VOID PhShowOptionsDialog( memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); propSheetPage.dwSize = sizeof(PROPSHEETPAGE); propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_OPTHIGHLIGHTING); + propSheetPage.hInstance = PhInstanceHandle; propSheetPage.pfnDlgProc = PhpOptionsHighlightingDlgProc; pages[propSheetHeader.nPages++] = CreatePropertySheetPage(&propSheetPage); } @@ -172,6 +177,7 @@ VOID PhShowOptionsDialog( memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); propSheetPage.dwSize = sizeof(PROPSHEETPAGE); propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_OPTGRAPHS); + propSheetPage.hInstance = PhInstanceHandle; propSheetPage.pfnDlgProc = PhpOptionsGraphsDlgProc; pages[propSheetHeader.nPages++] = CreatePropertySheetPage(&propSheetPage); } diff --git a/ProcessHacker/plugin.c b/ProcessHacker/plugin.c index 167a919d1454..495b5eeab934 100644 --- a/ProcessHacker/plugin.c +++ b/ProcessHacker/plugin.c @@ -291,8 +291,6 @@ VOID PhLoadPlugins( sb.String->Buffer ) == IDYES) { - ULONG i; - for (i = 0; i < LoadErrors->Count; i++) { loadError = LoadErrors->Items[i]; @@ -334,43 +332,37 @@ BOOLEAN PhLoadPlugin( _In_ PPH_STRING FileName ) { - BOOLEAN success; PPH_STRING fileName; PPH_STRING errorMessage; + PPHP_PLUGIN_LOAD_ERROR loadError; fileName = PhGetFullPath(FileName->Buffer, NULL); if (!fileName) PhSetReference(&fileName, FileName); - success = TRUE; - - if (!LoadLibrary(fileName->Buffer)) + if (LoadLibrary(fileName->Buffer)) { - success = FALSE; - errorMessage = PhGetWin32Message(GetLastError()); + PhDereferenceObject(fileName); + return TRUE; } - if (!success) - { - PPHP_PLUGIN_LOAD_ERROR loadError; + errorMessage = PhGetWin32Message(GetLastError()); - loadError = PhAllocate(sizeof(PHP_PLUGIN_LOAD_ERROR)); - PhSetReference(&loadError->FileName, fileName); - PhSetReference(&loadError->ErrorMessage, errorMessage); + loadError = PhAllocate(sizeof(PHP_PLUGIN_LOAD_ERROR)); + PhSetReference(&loadError->FileName, fileName); + PhSetReference(&loadError->ErrorMessage, errorMessage); - if (!LoadErrors) - LoadErrors = PhCreateList(2); + if (!LoadErrors) + LoadErrors = PhCreateList(2); - PhAddItemList(LoadErrors, loadError); + PhAddItemList(LoadErrors, loadError); - if (errorMessage) - PhDereferenceObject(errorMessage); - } + if (errorMessage) + PhDereferenceObject(errorMessage); PhDereferenceObject(fileName); - - return success; + return FALSE; } VOID PhpExecuteCallbackForAllPlugins( diff --git a/ProcessHacker/procprp.c b/ProcessHacker/procprp.c index ae884db625e5..2380d83ec95b 100644 --- a/ProcessHacker/procprp.c +++ b/ProcessHacker/procprp.c @@ -85,6 +85,7 @@ PPH_PROCESS_PROPCONTEXT PhCreateProcessPropContext( PSH_PROPTITLE | PSH_USECALLBACK | PSH_USEHICON; + propSheetHeader.hInstance = PhInstanceHandle; propSheetHeader.hwndParent = ParentWindowHandle; propSheetHeader.hIcon = ProcessItem->SmallIcon; propSheetHeader.pszCaption = propContext->Title->Buffer; @@ -380,7 +381,7 @@ PPH_PROCESS_PROPPAGECONTEXT PhCreateProcessPropPageContext( _In_opt_ PVOID Context ) { - return PhCreateProcessPropPageContextEx(NULL, Template, DlgProc, Context); + return PhCreateProcessPropPageContextEx(PhInstanceHandle, Template, DlgProc, Context); } PPH_PROCESS_PROPPAGECONTEXT PhCreateProcessPropPageContextEx( @@ -396,8 +397,7 @@ PPH_PROCESS_PROPPAGECONTEXT PhCreateProcessPropPageContextEx( memset(propPageContext, 0, sizeof(PH_PROCESS_PROPPAGECONTEXT)); propPageContext->PropSheetPage.dwSize = sizeof(PROPSHEETPAGE); - propPageContext->PropSheetPage.dwFlags = - PSP_USECALLBACK; + propPageContext->PropSheetPage.dwFlags = PSP_USECALLBACK; propPageContext->PropSheetPage.hInstance = InstanceHandle; propPageContext->PropSheetPage.pszTemplate = Template; propPageContext->PropSheetPage.pfnDlgProc = DlgProc; diff --git a/ProcessHacker/procrec.c b/ProcessHacker/procrec.c index dbcb2c98019a..07268bea41bb 100644 --- a/ProcessHacker/procrec.c +++ b/ProcessHacker/procrec.c @@ -186,7 +186,7 @@ INT_PTR CALLBACK PhpProcessRecordDlgProc( context->FileIcon = PhGetFileShellIcon(PhGetString(context->Record->FileName), L".exe", TRUE); SendMessage(GetDlgItem(hwndDlg, IDC_OPENFILENAME), BM_SETIMAGE, IMAGE_ICON, - (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhLibImageBase, MAKEINTRESOURCE(IDI_FOLDER))); + (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhInstanceHandle, MAKEINTRESOURCE(IDI_FOLDER))); SendMessage(GetDlgItem(hwndDlg, IDC_FILEICON), STM_SETICON, (WPARAM)context->FileIcon, 0); diff --git a/ProcessHacker/prpgenv.c b/ProcessHacker/prpgenv.c index 3806999f8fd1..cb16b9606a21 100644 --- a/ProcessHacker/prpgenv.c +++ b/ProcessHacker/prpgenv.c @@ -452,8 +452,8 @@ INT_PTR CALLBACK PhpEditEnvDlgProc( { case WM_INITDIALOG: { - SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhLibImageBase, MAKEINTRESOURCE(IDI_PROCESSHACKER))); - SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhLibImageBase, MAKEINTRESOURCE(IDI_PROCESSHACKER))); + SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER))); + SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER))); PhCenterWindow(hwndDlg, GetParent(hwndDlg)); diff --git a/ProcessHacker/prpggen.c b/ProcessHacker/prpggen.c index d8a6a1dc9be7..f780a952ead1 100644 --- a/ProcessHacker/prpggen.c +++ b/ProcessHacker/prpggen.c @@ -147,8 +147,8 @@ INT_PTR CALLBACK PhpProcessGeneralDlgProc( HICON folder; HICON magnifier; - folder = PH_LOAD_SHARED_ICON_SMALL(PhLibImageBase, MAKEINTRESOURCE(IDI_FOLDER)); - magnifier = PH_LOAD_SHARED_ICON_SMALL(PhLibImageBase, MAKEINTRESOURCE(IDI_MAGNIFIER)); + folder = PH_LOAD_SHARED_ICON_SMALL(PhInstanceHandle, MAKEINTRESOURCE(IDI_FOLDER)); + magnifier = PH_LOAD_SHARED_ICON_SMALL(PhInstanceHandle, MAKEINTRESOURCE(IDI_MAGNIFIER)); SET_BUTTON_ICON(IDC_INSPECT, magnifier); SET_BUTTON_ICON(IDC_OPENFILENAME, folder); diff --git a/ProcessHacker/prpgthrd.c b/ProcessHacker/prpgthrd.c index 35601d2d7fdf..7b35b201c716 100644 --- a/ProcessHacker/prpgthrd.c +++ b/ProcessHacker/prpgthrd.c @@ -615,7 +615,7 @@ INT_PTR CALLBACK PhpProcessThreadsDlgProc( PhThreadProviderInitialUpdate(threadsContext->Provider); PhRegisterThreadProvider(threadsContext->Provider, &threadsContext->ProviderRegistration); - SET_BUTTON_ICON(IDC_OPENSTARTMODULE, PH_LOAD_SHARED_ICON_SMALL(PhLibImageBase, MAKEINTRESOURCE(IDI_FOLDER))); + SET_BUTTON_ICON(IDC_OPENSTARTMODULE, PH_LOAD_SHARED_ICON_SMALL(PhInstanceHandle, MAKEINTRESOURCE(IDI_FOLDER))); } break; case WM_DESTROY: diff --git a/ProcessHacker/splitter.c b/ProcessHacker/splitter.c index 930ebb1d450a..0516fc2cd81d 100644 --- a/ProcessHacker/splitter.c +++ b/ProcessHacker/splitter.c @@ -238,7 +238,7 @@ PPH_HSPLITTER_CONTEXT PhInitializeHSplitter( c.lpfnWndProc = HSplitterWindowProc; c.cbClsExtra = 0; c.cbWndExtra = sizeof(PVOID); - c.hInstance = PhLibImageBase; + c.hInstance = PhInstanceHandle; c.hIcon = NULL; c.hCursor = LoadCursor(NULL, IDC_SIZENS); c.hbrBackground = NULL; @@ -262,7 +262,7 @@ PPH_HSPLITTER_CONTEXT PhInitializeHSplitter( 10, ParentWindow, NULL, - PhLibImageBase, + PhInstanceHandle, context ); diff --git a/ProcessHacker/srvlist.c b/ProcessHacker/srvlist.c index 1e2eaeb655df..eb10d23e993a 100644 --- a/ProcessHacker/srvlist.c +++ b/ProcessHacker/srvlist.c @@ -689,10 +689,10 @@ BOOLEAN NTAPI PhpServiceTreeNewCallback( if (!ServiceIconsLoaded) { - ServiceApplicationIcon = PH_LOAD_SHARED_ICON_SMALL(PhLibImageBase, MAKEINTRESOURCE(IDI_PHAPPLICATION)); - ServiceApplicationGoIcon = PH_LOAD_SHARED_ICON_SMALL(PhLibImageBase, MAKEINTRESOURCE(IDI_PHAPPLICATIONGO)); - ServiceCogIcon = PH_LOAD_SHARED_ICON_SMALL(PhLibImageBase, MAKEINTRESOURCE(IDI_COG)); - ServiceCogGoIcon = PH_LOAD_SHARED_ICON_SMALL(PhLibImageBase, MAKEINTRESOURCE(IDI_COGGO)); + ServiceApplicationIcon = PH_LOAD_SHARED_ICON_SMALL(PhInstanceHandle, MAKEINTRESOURCE(IDI_PHAPPLICATION)); + ServiceApplicationGoIcon = PH_LOAD_SHARED_ICON_SMALL(PhInstanceHandle, MAKEINTRESOURCE(IDI_PHAPPLICATIONGO)); + ServiceCogIcon = PH_LOAD_SHARED_ICON_SMALL(PhInstanceHandle, MAKEINTRESOURCE(IDI_COG)); + ServiceCogGoIcon = PH_LOAD_SHARED_ICON_SMALL(PhInstanceHandle, MAKEINTRESOURCE(IDI_COGGO)); ServiceIconsLoaded = TRUE; } diff --git a/ProcessHacker/srvprp.c b/ProcessHacker/srvprp.c index 17508959dcc5..e9cc3f1ac26c 100644 --- a/ProcessHacker/srvprp.c +++ b/ProcessHacker/srvprp.c @@ -114,6 +114,7 @@ VOID PhShowServiceProperties( PSH_NOAPPLYNOW | PSH_NOCONTEXTHELP | PSH_PROPTITLE; + propSheetHeader.hInstance = PhInstanceHandle; propSheetHeader.hwndParent = ParentWindowHandle; propSheetHeader.pszCaption = ServiceItem->Name->Buffer; propSheetHeader.nPages = 0; @@ -130,6 +131,7 @@ VOID PhShowServiceProperties( memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); propSheetPage.dwSize = sizeof(PROPSHEETPAGE); propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_SRVGENERAL); + propSheetPage.hInstance = PhInstanceHandle; propSheetPage.pfnDlgProc = PhpServiceGeneralDlgProc; propSheetPage.lParam = (LPARAM)&context; pages[propSheetHeader.nPages++] = CreatePropertySheetPage(&propSheetPage); diff --git a/ProcessHacker/sysinfo.c b/ProcessHacker/sysinfo.c index 1f6184e83044..4e8f019f4ff3 100644 --- a/ProcessHacker/sysinfo.c +++ b/ProcessHacker/sysinfo.c @@ -281,8 +281,8 @@ VOID PhSipOnInitDialog( VOID ) { - SendMessage(PhSipWindow, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhLibImageBase, MAKEINTRESOURCE(IDI_PROCESSHACKER))); - SendMessage(PhSipWindow, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhLibImageBase, MAKEINTRESOURCE(IDI_PROCESSHACKER))); + SendMessage(PhSipWindow, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER))); + SendMessage(PhSipWindow, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER))); PhInitializeLayoutManager(&WindowLayoutManager, PhSipWindow); diff --git a/ProcessHacker/thrdstk.c b/ProcessHacker/thrdstk.c index 35ac287e38a5..050eaf9267ff 100644 --- a/ProcessHacker/thrdstk.c +++ b/ProcessHacker/thrdstk.c @@ -169,8 +169,8 @@ static INT_PTR CALLBACK PhpThreadStackDlgProc( HWND lvHandle; PPH_LAYOUT_MANAGER layoutManager; - SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhLibImageBase, MAKEINTRESOURCE(IDI_PROCESSHACKER))); - SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhLibImageBase, MAKEINTRESOURCE(IDI_PROCESSHACKER))); + SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER))); + SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER))); threadStackContext = (PTHREAD_STACK_CONTEXT)lParam; SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)threadStackContext); diff --git a/ProcessHacker/tokprp.c b/ProcessHacker/tokprp.c index d5b6caa775db..bfbd1f002a85 100644 --- a/ProcessHacker/tokprp.c +++ b/ProcessHacker/tokprp.c @@ -137,6 +137,7 @@ VOID PhShowTokenProperties( PSH_NOAPPLYNOW | PSH_NOCONTEXTHELP | PSH_PROPTITLE; + propSheetHeader.hInstance = PhInstanceHandle; propSheetHeader.hwndParent = ParentWindowHandle; propSheetHeader.pszCaption = Title ? Title : L"Token"; propSheetHeader.nPages = 1; @@ -168,6 +169,7 @@ HPROPSHEETPAGE PhCreateTokenPage( propSheetPage.dwSize = sizeof(PROPSHEETPAGE); propSheetPage.dwFlags = PSP_USECALLBACK; propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_OBJTOKEN); + propSheetPage.hInstance = PhInstanceHandle; propSheetPage.pfnDlgProc = PhpTokenPageProc; propSheetPage.lParam = (LPARAM)tokenPageContext; propSheetPage.pfnCallback = PhpTokenPropPageProc; @@ -948,6 +950,7 @@ VOID PhpShowTokenAdvancedProperties( PSH_NOAPPLYNOW | PSH_NOCONTEXTHELP | PSH_PROPTITLE; + propSheetHeader.hInstance = PhInstanceHandle; propSheetHeader.hwndParent = ParentWindowHandle; propSheetHeader.pszCaption = L"Token"; propSheetHeader.nStartPage = 0; @@ -960,6 +963,7 @@ VOID PhpShowTokenAdvancedProperties( memset(&page, 0, sizeof(PROPSHEETPAGE)); page.dwSize = sizeof(PROPSHEETPAGE); page.pszTemplate = MAKEINTRESOURCE(IDD_TOKGENERAL); + page.hInstance = PhInstanceHandle; page.pfnDlgProc = PhpTokenGeneralPageProc; page.lParam = (LPARAM)Context; pages[numberOfPages++] = CreatePropertySheetPage(&page); @@ -969,6 +973,7 @@ VOID PhpShowTokenAdvancedProperties( memset(&page, 0, sizeof(PROPSHEETPAGE)); page.dwSize = sizeof(PROPSHEETPAGE); page.pszTemplate = MAKEINTRESOURCE(IDD_TOKADVANCED); + page.hInstance = PhInstanceHandle; page.pfnDlgProc = PhpTokenAdvancedPageProc; page.lParam = (LPARAM)Context; pages[numberOfPages++] = CreatePropertySheetPage(&page); @@ -980,6 +985,7 @@ VOID PhpShowTokenAdvancedProperties( memset(&page, 0, sizeof(PROPSHEETPAGE)); page.dwSize = sizeof(PROPSHEETPAGE); page.pszTemplate = MAKEINTRESOURCE(IDD_TOKCAPABILITIES); + page.hInstance = PhInstanceHandle; page.pfnDlgProc = PhpTokenCapabilitiesPageProc; page.lParam = (LPARAM)Context; pages[numberOfPages++] = CreatePropertySheetPage(&page); @@ -990,6 +996,7 @@ VOID PhpShowTokenAdvancedProperties( page.dwSize = sizeof(PROPSHEETPAGE); page.dwFlags = PSP_USETITLE; page.pszTemplate = MAKEINTRESOURCE(IDD_TOKATTRIBUTES); + page.hInstance = PhInstanceHandle; page.pszTitle = L"Claims"; page.pfnDlgProc = PhpTokenClaimsPageProc; page.lParam = (LPARAM)Context; @@ -1001,6 +1008,7 @@ VOID PhpShowTokenAdvancedProperties( page.dwSize = sizeof(PROPSHEETPAGE); page.dwFlags = PSP_USETITLE; page.pszTemplate = MAKEINTRESOURCE(IDD_TOKATTRIBUTES); + page.hInstance = PhInstanceHandle; page.pszTitle = L"Attributes"; page.pfnDlgProc = PhpTokenAttributesPageProc; page.lParam = (LPARAM)Context; diff --git a/phlib/colorbox.c b/phlib/colorbox.c index 530690e9b458..89cdcdac3cc1 100644 --- a/phlib/colorbox.c +++ b/phlib/colorbox.c @@ -51,7 +51,7 @@ BOOLEAN PhColorBoxInitialization( c.lpfnWndProc = PhpColorBoxWndProc; c.cbClsExtra = 0; c.cbWndExtra = sizeof(PVOID); - c.hInstance = PhLibImageBase; + c.hInstance = PhInstanceHandle; c.hIcon = NULL; c.hCursor = LoadCursor(NULL, IDC_ARROW); c.hbrBackground = NULL; diff --git a/phlib/global.c b/phlib/global.c index 0afc6504abc1..8d8ed1026c9a 100644 --- a/phlib/global.c +++ b/phlib/global.c @@ -38,8 +38,7 @@ VOID PhInitializeWindowsVersion( VOID ); -PHLIBAPI PVOID PhLibImageBase; - +PHLIBAPI PVOID PhInstanceHandle; PHLIBAPI PWSTR PhApplicationName = L"Application"; PHLIBAPI ULONG PhGlobalDpi = 96; PHLIBAPI PVOID PhHeapHandle; @@ -64,6 +63,7 @@ NTSTATUS PhInitializePhLib( { return PhInitializePhLibEx( 0xffffffff, // all possible features + NtCurrentPeb()->ImageBaseAddress, 0, 0 ); @@ -71,10 +71,12 @@ NTSTATUS PhInitializePhLib( NTSTATUS PhInitializePhLibEx( _In_ ULONG Flags, + _In_ PVOID ImageBaseAddress, _In_opt_ SIZE_T HeapReserveSize, _In_opt_ SIZE_T HeapCommitSize ) { + PhInstanceHandle = ImageBaseAddress; PhHeapHandle = RtlCreateHeap( HEAP_GROWABLE | HEAP_CLASS_1, NULL, @@ -87,8 +89,6 @@ NTSTATUS PhInitializePhLibEx( if (!PhHeapHandle) return STATUS_INSUFFICIENT_RESOURCES; - PhLibImageBase = NtCurrentPeb()->ImageBaseAddress; - PhInitializeWindowsVersion(); PhInitializeSystemInformation(); diff --git a/phlib/graph.c b/phlib/graph.c index 8c47136d2ead..b74eeab067c1 100644 --- a/phlib/graph.c +++ b/phlib/graph.c @@ -76,7 +76,7 @@ BOOLEAN PhGraphControlInitialization( c.lpfnWndProc = PhpGraphWndProc; c.cbClsExtra = 0; c.cbWndExtra = sizeof(PVOID); - c.hInstance = PhLibImageBase; + c.hInstance = PhInstanceHandle; c.hIcon = NULL; c.hCursor = LoadCursor(NULL, IDC_ARROW); c.hbrBackground = NULL; @@ -1189,7 +1189,7 @@ LRESULT CALLBACK PhpGraphWndProc( CW_USEDEFAULT, NULL, NULL, - PhLibImageBase, + PhInstanceHandle, NULL ); diff --git a/phlib/hexedit.c b/phlib/hexedit.c index edd89248995d..82c1d614d83f 100644 --- a/phlib/hexedit.c +++ b/phlib/hexedit.c @@ -39,7 +39,7 @@ BOOLEAN PhHexEditInitialization( c.lpfnWndProc = PhpHexEditWndProc; c.cbClsExtra = 0; c.cbWndExtra = sizeof(PVOID); - c.hInstance = PhLibImageBase; + c.hInstance = PhInstanceHandle; c.hIcon = NULL; c.hCursor = LoadCursor(NULL, IDC_ARROW); c.hbrBackground = NULL; diff --git a/phlib/include/phconfig.h b/phlib/include/phconfig.h index 420d3ed97dfc..8daf5185a7a6 100644 --- a/phlib/include/phconfig.h +++ b/phlib/include/phconfig.h @@ -7,7 +7,7 @@ extern "C" { #define _User_set_ -PHLIBAPI extern _User_set_ PVOID PhLibImageBase; +PHLIBAPI extern _User_set_ PVOID PhInstanceHandle; PHLIBAPI extern _User_set_ PWSTR PhApplicationName; PHLIBAPI extern _User_set_ ULONG PhGlobalDpi; PHLIBAPI extern PVOID PhHeapHandle; @@ -75,6 +75,7 @@ NTSTATUS NTAPI PhInitializePhLibEx( _In_ ULONG Flags, + _In_ PVOID ImageBaseAddress, _In_opt_ SIZE_T HeapReserveSize, _In_opt_ SIZE_T HeapCommitSize ); diff --git a/phlib/native.c b/phlib/native.c index 24e067a783f2..9366ab375b56 100644 --- a/phlib/native.c +++ b/phlib/native.c @@ -4651,7 +4651,7 @@ NTSTATUS PhEnumDirectoryFile( { PFILE_DIRECTORY_INFORMATION information; - information = (PFILE_DIRECTORY_INFORMATION)(PTR_ADD_OFFSET(buffer, i)); + information = (PFILE_DIRECTORY_INFORMATION)PTR_ADD_OFFSET(buffer, i); if (!Callback( information, diff --git a/phlib/treenew.c b/phlib/treenew.c index f5bef8b20da0..bd96c52cfcc6 100644 --- a/phlib/treenew.c +++ b/phlib/treenew.c @@ -66,7 +66,7 @@ BOOLEAN PhTreeNewInitialization( c.lpfnWndProc = PhTnpWndProc; c.cbClsExtra = 0; c.cbWndExtra = sizeof(PVOID); - c.hInstance = PhLibImageBase; + c.hInstance = PhInstanceHandle; c.hIcon = NULL; c.hCursor = LoadCursor(NULL, IDC_ARROW); c.hbrBackground = NULL; diff --git a/phlib/util.c b/phlib/util.c index 8084ead139cf..44ba3a99ee4a 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -425,7 +425,7 @@ INT PhShowMessage2( return -1; config.hwndParent = hWnd; - config.hInstance = PhLibImageBase; + config.hInstance = PhInstanceHandle; config.dwFlags = TDF_ALLOW_DIALOG_CANCELLATION | (IsWindowVisible(hWnd) ? TDF_POSITION_RELATIVE_TO_WINDOW : 0); config.dwCommonButtons = Buttons; config.pszWindowTitle = PhApplicationName; @@ -614,7 +614,7 @@ BOOLEAN PhShowConfirmMessage( INT button; config.hwndParent = hWnd; - config.hInstance = PhLibImageBase; + config.hInstance = PhInstanceHandle; config.dwFlags = TDF_ALLOW_DIALOG_CANCELLATION | (IsWindowVisible(hWnd) ? TDF_POSITION_RELATIVE_TO_WINDOW : 0); config.pszWindowTitle = PhApplicationName; config.pszMainIcon = Warning ? TD_WARNING_ICON : NULL; diff --git a/plugins/ExtendedTools/gpunodes.c b/plugins/ExtendedTools/gpunodes.c index 1526bd358a45..fa1292a44ace 100644 --- a/plugins/ExtendedTools/gpunodes.c +++ b/plugins/ExtendedTools/gpunodes.c @@ -121,8 +121,8 @@ INT_PTR CALLBACK EtpGpuNodesDlgProc( WindowHandle = hwndDlg; - SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhLibImageBase, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); - SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhLibImageBase, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); + SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhInstanceHandle, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); + SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhInstanceHandle, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); PhInitializeLayoutManager(&LayoutManager, hwndDlg); PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDOK), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); diff --git a/plugins/ExtendedTools/unldll.c b/plugins/ExtendedTools/unldll.c index f7643e977197..7640363288c0 100644 --- a/plugins/ExtendedTools/unldll.c +++ b/plugins/ExtendedTools/unldll.c @@ -306,8 +306,8 @@ INT_PTR CALLBACK EtpUnloadedDllsDlgProc( { HWND lvHandle; - SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhLibImageBase, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); - SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhLibImageBase, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); + SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhInstanceHandle, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); + SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhInstanceHandle, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); PhCenterWindow(hwndDlg, GetParent(hwndDlg)); diff --git a/plugins/ExtraPlugins/dialog.c b/plugins/ExtraPlugins/dialog.c index 1e0c1b42c6b2..829a96ed8c49 100644 --- a/plugins/ExtraPlugins/dialog.c +++ b/plugins/ExtraPlugins/dialog.c @@ -232,8 +232,8 @@ INT_PTR CALLBACK CloudPluginsDlgProc( { case WM_INITDIALOG: { - SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhLibImageBase, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); - SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhLibImageBase, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); + SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhInstanceHandle, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); + SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhInstanceHandle, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); context->DialogHandle = hwndDlg; context->PluginMenuActiveId = IDC_INSTALLED; diff --git a/plugins/ExtraPlugins/setup/updater.c b/plugins/ExtraPlugins/setup/updater.c index 7dfb62bb0acd..0dc634b825aa 100644 --- a/plugins/ExtraPlugins/setup/updater.c +++ b/plugins/ExtraPlugins/setup/updater.c @@ -60,8 +60,8 @@ VOID TaskDialogCreateIcons( ) { // Load the Process Hacker window icon - Context->IconLargeHandle = PH_LOAD_SHARED_ICON_LARGE(PhLibImageBase, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER)); - Context->IconSmallHandle = PH_LOAD_SHARED_ICON_SMALL(PhLibImageBase, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER)); + Context->IconLargeHandle = PH_LOAD_SHARED_ICON_LARGE(PhInstanceHandle, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER)); + Context->IconSmallHandle = PH_LOAD_SHARED_ICON_SMALL(PhInstanceHandle, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER)); // Set the TaskDialog window icons SendMessage(Context->DialogHandle, WM_SETICON, ICON_SMALL, (LPARAM)Context->IconSmallHandle); diff --git a/plugins/NetworkTools/ping.c b/plugins/NetworkTools/ping.c index 4dce3d99221e..0d94de17499a 100644 --- a/plugins/NetworkTools/ping.c +++ b/plugins/NetworkTools/ping.c @@ -285,8 +285,8 @@ INT_PTR CALLBACK NetworkPingWndProc( { PPH_LAYOUT_ITEM panelItem; - SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhLibImageBase, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); - SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhLibImageBase, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); + SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhInstanceHandle, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); + SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhInstanceHandle, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); // We have already set the group boxes to have WS_EX_TRANSPARENT to fix // the drawing issue that arises when using WS_CLIPCHILDREN. However diff --git a/plugins/NetworkTools/tracert.c b/plugins/NetworkTools/tracert.c index 1a0f3abff127..dd98669b9af2 100644 --- a/plugins/NetworkTools/tracert.c +++ b/plugins/NetworkTools/tracert.c @@ -566,8 +566,8 @@ INT_PTR CALLBACK TracertDlgProc( { case WM_INITDIALOG: { - SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhLibImageBase, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); - SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhLibImageBase, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); + SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhInstanceHandle, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); + SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhInstanceHandle, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); PhCenterWindow(hwndDlg, PhMainWndHandle); diff --git a/plugins/NetworkTools/update.c b/plugins/NetworkTools/update.c index 57d728413f45..f57bd05db5ba 100644 --- a/plugins/NetworkTools/update.c +++ b/plugins/NetworkTools/update.c @@ -50,8 +50,8 @@ VOID TaskDialogCreateIcons( _In_ PPH_UPDATER_CONTEXT Context ) { - Context->IconSmallHandle = PH_LOAD_SHARED_ICON_SMALL(PhLibImageBase, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER)); - Context->IconLargeHandle = PH_LOAD_SHARED_ICON_LARGE(PhLibImageBase, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER)); + Context->IconSmallHandle = PH_LOAD_SHARED_ICON_SMALL(PhInstanceHandle, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER)); + Context->IconLargeHandle = PH_LOAD_SHARED_ICON_LARGE(PhInstanceHandle, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER)); SendMessage(Context->DialogHandle, WM_SETICON, ICON_SMALL, (LPARAM)Context->IconSmallHandle); SendMessage(Context->DialogHandle, WM_SETICON, ICON_BIG, (LPARAM)Context->IconLargeHandle); diff --git a/plugins/NetworkTools/whois.c b/plugins/NetworkTools/whois.c index 0649bd0a9168..0f8e0bf73469 100644 --- a/plugins/NetworkTools/whois.c +++ b/plugins/NetworkTools/whois.c @@ -394,8 +394,8 @@ INT_PTR CALLBACK NetworkOutputDlgProc( { case WM_INITDIALOG: { - SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhLibImageBase, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); - SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhLibImageBase, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); + SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhInstanceHandle, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); + SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhInstanceHandle, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); SetWindowText(hwndDlg, PhaFormatString(L"Whois %s...", context->IpAddressString)->Buffer); diff --git a/plugins/OnlineChecks/main.c b/plugins/OnlineChecks/main.c index 652594742bfa..a7ec2e294b99 100644 --- a/plugins/OnlineChecks/main.c +++ b/plugins/OnlineChecks/main.c @@ -178,7 +178,7 @@ VOID NTAPI MenuItemCallback( config.dwFlags = TDF_USE_HICON_MAIN | TDF_ALLOW_DIALOG_CANCELLATION; config.dwCommonButtons = TDCBF_YES_BUTTON | TDCBF_NO_BUTTON; config.hwndParent = menuItem->OwnerWindow; - config.hMainIcon = PH_LOAD_SHARED_ICON_LARGE(PhLibImageBase, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER)); + config.hMainIcon = PH_LOAD_SHARED_ICON_LARGE(PhInstanceHandle, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER)); config.cxWidth = 180; config.pszWindowTitle = L"Process Hacker - VirusTotal"; config.pszMainInstruction = L"VirusTotal scanning requires a restart of Process Hacker."; diff --git a/plugins/OnlineChecks/upload.c b/plugins/OnlineChecks/upload.c index 542063e168f3..11948fefec83 100644 --- a/plugins/OnlineChecks/upload.c +++ b/plugins/OnlineChecks/upload.c @@ -205,8 +205,8 @@ VOID TaskDialogCreateIcons( _In_ PUPLOAD_CONTEXT Context ) { - Context->IconLargeHandle = PH_LOAD_SHARED_ICON_LARGE(PhLibImageBase, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER)); - Context->IconSmallHandle = PH_LOAD_SHARED_ICON_SMALL(PhLibImageBase, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER)); + Context->IconLargeHandle = PH_LOAD_SHARED_ICON_LARGE(PhInstanceHandle, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER)); + Context->IconSmallHandle = PH_LOAD_SHARED_ICON_SMALL(PhInstanceHandle, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER)); SendMessage(Context->DialogHandle, WM_SETICON, ICON_SMALL, (LPARAM)Context->IconSmallHandle); SendMessage(Context->DialogHandle, WM_SETICON, ICON_BIG, (LPARAM)Context->IconLargeHandle); diff --git a/plugins/Updater/options.c b/plugins/Updater/options.c index 5b9deb95b995..de429ec1e990 100644 --- a/plugins/Updater/options.c +++ b/plugins/Updater/options.c @@ -86,8 +86,8 @@ INT_PTR CALLBACK TextDlgProc( { PPH_UPDATER_CONTEXT context = (PPH_UPDATER_CONTEXT)lParam; - SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhLibImageBase, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); - SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhLibImageBase, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); + SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhInstanceHandle, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); + SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhInstanceHandle, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); SetWindowText(GetDlgItem(hwndDlg, IDC_TEXT), PhGetString(context->BuildMessage)); diff --git a/plugins/Updater/updater.c b/plugins/Updater/updater.c index 7e65a8ee4807..9affa094d471 100644 --- a/plugins/Updater/updater.c +++ b/plugins/Updater/updater.c @@ -70,8 +70,8 @@ VOID TaskDialogCreateIcons( _In_ PPH_UPDATER_CONTEXT Context ) { - Context->IconSmallHandle = PH_LOAD_SHARED_ICON_SMALL(PhLibImageBase, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER)); - Context->IconLargeHandle = PH_LOAD_SHARED_ICON_LARGE(PhLibImageBase, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER)); + Context->IconSmallHandle = PH_LOAD_SHARED_ICON_SMALL(PhInstanceHandle, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER)); + Context->IconLargeHandle = PH_LOAD_SHARED_ICON_LARGE(PhInstanceHandle, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER)); SendMessage(Context->DialogHandle, WM_SETICON, ICON_SMALL, (LPARAM)Context->IconSmallHandle); SendMessage(Context->DialogHandle, WM_SETICON, ICON_BIG, (LPARAM)Context->IconLargeHandle); diff --git a/tools/peview/main.c b/tools/peview/main.c index a8de840ebf1a..f3bf35f5b892 100644 --- a/tools/peview/main.c +++ b/tools/peview/main.c @@ -63,7 +63,7 @@ INT WINAPI wWinMain( }; PH_STRINGREF commandLine; - if (!NT_SUCCESS(PhInitializePhLibEx(0, 0, 0))) + if (!NT_SUCCESS(PhInitializePhLib())) return 1; PhGuiSupportInitialization(); diff --git a/tools/peview/prpsh.c b/tools/peview/prpsh.c index 717f1d1f4222..f697d1bcb282 100644 --- a/tools/peview/prpsh.c +++ b/tools/peview/prpsh.c @@ -92,6 +92,7 @@ PPV_PROPCONTEXT PvCreatePropContext( PSH_NOCONTEXTHELP | PSH_PROPTITLE | PSH_USECALLBACK; + propSheetHeader.hInstance = PhInstanceHandle; propSheetHeader.hwndParent = NULL; propSheetHeader.pszCaption = propContext->Title->Buffer; propSheetHeader.pfnCallback = PvpPropSheetProc; @@ -382,8 +383,7 @@ PPV_PROPPAGECONTEXT PvCreatePropPageContextEx( memset(propPageContext, 0, sizeof(PV_PROPPAGECONTEXT)); propPageContext->PropSheetPage.dwSize = sizeof(PROPSHEETPAGE); - propPageContext->PropSheetPage.dwFlags = - PSP_USECALLBACK; + propPageContext->PropSheetPage.dwFlags = PSP_USECALLBACK; propPageContext->PropSheetPage.hInstance = InstanceHandle; propPageContext->PropSheetPage.pszTemplate = Template; propPageContext->PropSheetPage.pfnDlgProc = DlgProc; diff --git a/tools/peview/searchbox.c b/tools/peview/searchbox.c index 17d89f752726..a758b0e2816b 100644 --- a/tools/peview/searchbox.c +++ b/tools/peview/searchbox.c @@ -323,23 +323,23 @@ VOID PhpSearchInitializeImages( Context->ImageWidth = GetSystemMetrics(SM_CXSMICON) + 4; Context->ImageHeight = GetSystemMetrics(SM_CYSMICON) + 4; - if (bitmap = PhLoadPngImageFromResource(PhLibImageBase, Context->ImageWidth, Context->ImageHeight, MAKEINTRESOURCE(IDB_SEARCH_ACTIVE), TRUE)) + if (bitmap = PhLoadPngImageFromResource(PhInstanceHandle, Context->ImageWidth, Context->ImageHeight, MAKEINTRESOURCE(IDB_SEARCH_ACTIVE), TRUE)) { Context->BitmapActive = PhpSearchBitmapToIcon(bitmap, Context->ImageWidth, Context->ImageHeight); DeleteObject(bitmap); } - else if (bitmap = LoadImage(PhLibImageBase, MAKEINTRESOURCE(IDB_SEARCH_ACTIVE_BMP), IMAGE_BITMAP, 0, 0, 0)) + else if (bitmap = LoadImage(PhInstanceHandle, MAKEINTRESOURCE(IDB_SEARCH_ACTIVE_BMP), IMAGE_BITMAP, 0, 0, 0)) { Context->BitmapActive = PhpSearchBitmapToIcon(bitmap, Context->ImageWidth, Context->ImageHeight); DeleteObject(bitmap); } - if (bitmap = PhLoadPngImageFromResource(PhLibImageBase, Context->ImageWidth, Context->ImageHeight, MAKEINTRESOURCE(IDB_SEARCH_INACTIVE), TRUE)) + if (bitmap = PhLoadPngImageFromResource(PhInstanceHandle, Context->ImageWidth, Context->ImageHeight, MAKEINTRESOURCE(IDB_SEARCH_INACTIVE), TRUE)) { Context->BitmapInactive = PhpSearchBitmapToIcon(bitmap, Context->ImageWidth, Context->ImageHeight); DeleteObject(bitmap); } - else if (bitmap = LoadImage(PhLibImageBase, MAKEINTRESOURCE(IDB_SEARCH_INACTIVE_BMP), IMAGE_BITMAP, 0, 0, 0)) + else if (bitmap = LoadImage(PhInstanceHandle, MAKEINTRESOURCE(IDB_SEARCH_INACTIVE_BMP), IMAGE_BITMAP, 0, 0, 0)) { Context->BitmapInactive = PhpSearchBitmapToIcon(bitmap, Context->ImageWidth, Context->ImageHeight); DeleteObject(bitmap); From 518c283b9bfc31ac0cdd7ad6dc234ee83498fe07 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 3 Jul 2017 02:02:58 +1000 Subject: [PATCH 0250/2058] peview: Fix typo --- tools/peview/include/pdb.h | 2 +- tools/peview/include/peview.h | 23 +++++++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/tools/peview/include/pdb.h b/tools/peview/include/pdb.h index 5b04419d4d39..f4891ac22cd1 100644 --- a/tools/peview/include/pdb.h +++ b/tools/peview/include/pdb.h @@ -1,6 +1,6 @@ /* * Process Hacker - - * property sheet + * PE viewer * * Copyright (C) 2017 dmex * diff --git a/tools/peview/include/peview.h b/tools/peview/include/peview.h index d076b7649ac5..b3cc6ccdab5d 100644 --- a/tools/peview/include/peview.h +++ b/tools/peview/include/peview.h @@ -1,3 +1,26 @@ +/* + * Process Hacker - + * PE viewer + * + * Copyright (C) 2010-2011 wj32 + * Copyright (C) 2017 dmex + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + #ifndef PEVIEW_H #define PEVIEW_H From a47c56a700d25b1334cc2a4804a25b9a60d5d863 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 3 Jul 2017 02:11:12 +1000 Subject: [PATCH 0251/2058] Setup: Update to lastet sdk --- .../CustomSetupTool/CustomSetupTool/appsup.c | 20 +++++++++---------- .../CustomSetupTool/CustomSetupTool/extract.c | 6 +++--- tools/CustomSetupTool/CustomSetupTool/main.c | 18 +++++++++++------ tools/CustomSetupTool/CustomSetupTool/page1.c | 4 ++-- 4 files changed, 27 insertions(+), 21 deletions(-) diff --git a/tools/CustomSetupTool/CustomSetupTool/appsup.c b/tools/CustomSetupTool/CustomSetupTool/appsup.c index 92bdf7e63846..e4a887d1f3c5 100644 --- a/tools/CustomSetupTool/CustomSetupTool/appsup.c +++ b/tools/CustomSetupTool/CustomSetupTool/appsup.c @@ -34,12 +34,12 @@ VOID ExtractResourceToFile( PVOID resourceBuffer; IO_STATUS_BLOCK isb; - if (!(resourceHandle = FindResource(PhLibImageBase, Resource, RT_RCDATA))) + if (!(resourceHandle = FindResource(PhInstanceHandle, Resource, RT_RCDATA))) goto CleanupExit; - resourceLength = SizeofResource(PhLibImageBase, resourceHandle); + resourceLength = SizeofResource(PhInstanceHandle, resourceHandle); - if (!(resourceData = LoadResource(PhLibImageBase, resourceHandle))) + if (!(resourceData = LoadResource(PhInstanceHandle, resourceHandle))) goto CleanupExit; if (!(resourceBuffer = LockResource(resourceData))) @@ -95,12 +95,12 @@ PVOID ExtractResourceToBuffer( PVOID resourceBuffer; PVOID buffer = NULL; - if (!(resourceHandle = FindResource(PhLibImageBase, Resource, RT_RCDATA))) + if (!(resourceHandle = FindResource(PhInstanceHandle, Resource, RT_RCDATA))) goto CleanupExit; - resourceLength = SizeofResource(PhLibImageBase, resourceHandle); + resourceLength = SizeofResource(PhInstanceHandle, resourceHandle); - if (!(resourceData = LoadResource(PhLibImageBase, resourceHandle))) + if (!(resourceData = LoadResource(PhInstanceHandle, resourceHandle))) goto CleanupExit; if (!(resourceBuffer = LockResource(resourceData))) @@ -148,14 +148,14 @@ HBITMAP LoadPngImageFromResources( goto CleanupExit; // Find the resource - if ((resourceHandleSource = FindResource(PhLibImageBase, Name, L"PNG")) == NULL) + if ((resourceHandleSource = FindResource(PhInstanceHandle, Name, L"PNG")) == NULL) goto CleanupExit; // Get the resource length - resourceLength = SizeofResource(PhLibImageBase, resourceHandleSource); + resourceLength = SizeofResource(PhInstanceHandle, resourceHandleSource); // Load the resource - if ((resourceHandle = LoadResource(PhLibImageBase, resourceHandleSource)) == NULL) + if ((resourceHandle = LoadResource(PhInstanceHandle, resourceHandleSource)) == NULL) goto CleanupExit; if ((resourceBuffer = (WICInProcPointer)LockResource(resourceHandle)) == NULL) @@ -390,7 +390,7 @@ BOOLEAN DialogPromptExit( INT buttonPressed = 0; TASKDIALOGCONFIG config = { sizeof(TASKDIALOGCONFIG) }; config.hwndParent = hwndDlg; - config.hInstance = PhLibImageBase; + config.hInstance = PhInstanceHandle; config.dwFlags = TDF_POSITION_RELATIVE_TO_WINDOW; config.nDefaultButton = IDNO; config.dwCommonButtons = TDCBF_YES_BUTTON | TDCBF_NO_BUTTON; diff --git a/tools/CustomSetupTool/CustomSetupTool/extract.c b/tools/CustomSetupTool/CustomSetupTool/extract.c index 850a2322074c..6d7113314572 100644 --- a/tools/CustomSetupTool/CustomSetupTool/extract.c +++ b/tools/CustomSetupTool/CustomSetupTool/extract.c @@ -30,12 +30,12 @@ PVOID GetZipResourceData( HGLOBAL resourceData; PVOID resourceBuffer = NULL; - if (!(resourceHandle = FindResource(PhLibImageBase, MAKEINTRESOURCE(IDR_BIN_DATA), RT_RCDATA))) + if (!(resourceHandle = FindResource(PhInstanceHandle, MAKEINTRESOURCE(IDR_BIN_DATA), RT_RCDATA))) goto CleanupExit; - *resourceLength = SizeofResource(PhLibImageBase, resourceHandle); + *resourceLength = SizeofResource(PhInstanceHandle, resourceHandle); - if (!(resourceData = LoadResource(PhLibImageBase, resourceHandle))) + if (!(resourceData = LoadResource(PhInstanceHandle, resourceHandle))) goto CleanupExit; if (!(resourceBuffer = LockResource(resourceData))) diff --git a/tools/CustomSetupTool/CustomSetupTool/main.c b/tools/CustomSetupTool/CustomSetupTool/main.c index fe45e4258011..7daea4ac97a9 100644 --- a/tools/CustomSetupTool/CustomSetupTool/main.c +++ b/tools/CustomSetupTool/CustomSetupTool/main.c @@ -122,10 +122,10 @@ INT CALLBACK MainPropSheet_Callback( } INT WINAPI wWinMain( - _In_ HINSTANCE hInstance, - _In_opt_ HINSTANCE hPrevInstance, - _In_ PWSTR lpCmdLine, - _In_ INT nCmdShow + _In_ HINSTANCE Instance, + _In_opt_ HINSTANCE PrevInstance, + _In_ PWSTR CmdLine, + _In_ INT CmdShow ) { if (!NT_SUCCESS(CreateSetupMutant())) @@ -133,7 +133,7 @@ INT WINAPI wWinMain( CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE); - if (!NT_SUCCESS(PhInitializePhLibEx(0, 0, 0))) + if (!NT_SUCCESS(PhInitializePhLibEx(ULONG_MAX, Instance, 0, 0))) return 1; PhApplicationName = L"Process Hacker - Setup"; @@ -167,9 +167,9 @@ INT WINAPI wWinMain( HPROPSHEETPAGE pages[6]; propSheetHeader.dwFlags = PSH_NOAPPLYNOW | PSH_NOCONTEXTHELP | PSH_USECALLBACK | PSH_WIZARD_LITE; - propSheetHeader.hInstance = PhLibImageBase; propSheetHeader.pszIcon = MAKEINTRESOURCE(IDI_ICON1); propSheetHeader.pfnCallback = MainPropSheet_Callback; + propSheetHeader.hInstance = PhInstanceHandle; propSheetHeader.phpage = pages; // welcome page @@ -178,6 +178,7 @@ INT WINAPI wWinMain( propSheetPage.dwFlags = PSP_USETITLE; propSheetPage.pszTitle = PhApplicationName; propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_DIALOG1); + propSheetPage.hInstance = PhInstanceHandle; propSheetPage.pfnDlgProc = SetupPropPage1_WndProc; pages[propSheetHeader.nPages++] = CreatePropertySheetPage(&propSheetPage); @@ -187,6 +188,7 @@ INT WINAPI wWinMain( propSheetPage.dwFlags = PSP_USETITLE; propSheetPage.pszTitle = PhApplicationName; propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_DIALOG2); + propSheetPage.hInstance = PhInstanceHandle; propSheetPage.pfnDlgProc = SetupPropPage2_WndProc; pages[propSheetHeader.nPages++] = CreatePropertySheetPage(&propSheetPage); @@ -196,6 +198,7 @@ INT WINAPI wWinMain( propSheetPage.dwFlags = PSP_USETITLE; propSheetPage.pszTitle = PhApplicationName; propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_DIALOG3); + propSheetPage.hInstance = PhInstanceHandle; propSheetPage.pfnDlgProc = SetupPropPage3_WndProc; pages[propSheetHeader.nPages++] = CreatePropertySheetPage(&propSheetPage); @@ -205,6 +208,7 @@ INT WINAPI wWinMain( propSheetPage.dwFlags = PSP_USETITLE; propSheetPage.pszTitle = PhApplicationName; propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_DIALOG5); + propSheetPage.hInstance = PhInstanceHandle; propSheetPage.pfnDlgProc = SetupPropPage5_WndProc; pages[propSheetHeader.nPages++] = CreatePropertySheetPage(&propSheetPage); @@ -214,6 +218,7 @@ INT WINAPI wWinMain( propSheetPage.dwFlags = PSP_USETITLE; propSheetPage.pszTitle = PhApplicationName; propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_DIALOG4); + propSheetPage.hInstance = PhInstanceHandle; propSheetPage.pfnDlgProc = SetupPropPage4_WndProc; pages[propSheetHeader.nPages++] = CreatePropertySheetPage(&propSheetPage); @@ -223,6 +228,7 @@ INT WINAPI wWinMain( propSheetPage.dwFlags = PSP_USETITLE; propSheetPage.pszTitle = PhApplicationName; propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_ERROR); + propSheetPage.hInstance = PhInstanceHandle; propSheetPage.pfnDlgProc = SetupErrorPage_WndProc; pages[propSheetHeader.nPages++] = CreatePropertySheetPage(&propSheetPage); diff --git a/tools/CustomSetupTool/CustomSetupTool/page1.c b/tools/CustomSetupTool/CustomSetupTool/page1.c index 526f37d9d727..e473cf75ecaa 100644 --- a/tools/CustomSetupTool/CustomSetupTool/page1.c +++ b/tools/CustomSetupTool/CustomSetupTool/page1.c @@ -36,7 +36,7 @@ static VOID SetupLoadIcons( ) { HBITMAP smallIconHandle = (HBITMAP)LoadImage( - PhLibImageBase, + PhInstanceHandle, MAKEINTRESOURCE(IDI_ICON1), IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), @@ -44,7 +44,7 @@ static VOID SetupLoadIcons( LR_DEFAULTCOLOR ); HBITMAP largeIconHandle = (HBITMAP)LoadImage( - PhLibImageBase, + PhInstanceHandle, MAKEINTRESOURCE(IDI_ICON1), IMAGE_ICON, GetSystemMetrics(SM_CXICON), From 30df8107a0ec1ca92e0656d5881799be0b2adb3b Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 3 Jul 2017 17:36:23 +1000 Subject: [PATCH 0252/2058] Fix DLL_INIT_BLOCK version check --- ProcessHacker/memprv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ProcessHacker/memprv.c b/ProcessHacker/memprv.c index 0cd374fce86d..881a5d2500e7 100644 --- a/ProcessHacker/memprv.c +++ b/ProcessHacker/memprv.c @@ -494,7 +494,7 @@ NTSTATUS PhpUpdateMemoryRegionTypes( PVOID cfgBitmapAddress = NULL; PVOID cfgBitmapWow64Address = NULL; - if (ldrInitBlock.Size == sizeof(PS_SYSTEM_DLL_INIT_BLOCK)) + if (ldrInitBlock.Size >= (ULONG)FIELD_OFFSET(PS_SYSTEM_DLL_INIT_BLOCK, Wow64CfgBitMap)) { cfgBitmapAddress = (PVOID)ldrInitBlock.CfgBitMap; cfgBitmapWow64Address = (PVOID)ldrInitBlock.Wow64CfgBitMap; From 8a7bb0f383f124e965e654ce1c03ee6d7a4d6447 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 6 Jul 2017 10:47:32 +1000 Subject: [PATCH 0253/2058] Add more support for the FileOpenExecutable setting --- ProcessHacker/hndlmenu.c | 10 +++++++++- ProcessHacker/mainwnd.c | 16 ++++++++++++++-- ProcessHacker/miniinfo.c | 10 +++++++++- ProcessHacker/procrec.c | 10 +++++++++- ProcessHacker/prpgmod.c | 8 +++++++- ProcessHacker/prpgthrd.c | 8 +++++++- 6 files changed, 55 insertions(+), 7 deletions(-) diff --git a/ProcessHacker/hndlmenu.c b/ProcessHacker/hndlmenu.c index 8c842f7fd0d1..c4d2cdbef350 100644 --- a/ProcessHacker/hndlmenu.c +++ b/ProcessHacker/hndlmenu.c @@ -118,7 +118,15 @@ VOID PhShowHandleObjectProperties1( PhEqualString2(Info->TypeName, L"Mapped file", TRUE) || PhEqualString2(Info->TypeName, L"Mapped image", TRUE)) { if (Info->BestObjectName) - PhShellExploreFile(hWnd, Info->BestObjectName->Buffer); + { + PhShellExecuteUserString( + PhMainWndHandle, + L"FileOpenExecutable", + Info->BestObjectName->Buffer, + FALSE, + L"Make sure the Explorer executable file is present." + ); + } else PhShowError(hWnd, L"Unable to open file location because the object is unnamed."); } diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index 6c2c41e4ea6a..0bca69a69d8f 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -1309,7 +1309,13 @@ VOID PhMwpOnCommand( if (processItem && processItem->FileName) { PhReferenceObject(processItem); - PhShellExploreFile(PhMainWndHandle, processItem->FileName->Buffer); + PhShellExecuteUserString( + PhMainWndHandle, + L"FileOpenExecutable", + processItem->FileName->Buffer, + FALSE, + L"Make sure the Explorer executable file is present." + ); PhDereferenceObject(processItem); } } @@ -1459,7 +1465,13 @@ VOID PhMwpOnCommand( if (fileName = PhGetServiceRelevantFileName(&serviceItem->Name->sr, serviceHandle)) { - PhShellExploreFile(PhMainWndHandle, fileName->Buffer); + PhShellExecuteUserString( + PhMainWndHandle, + L"FileOpenExecutable", + fileName->Buffer, + FALSE, + L"Make sure the Explorer executable file is present." + ); PhDereferenceObject(fileName); } diff --git a/ProcessHacker/miniinfo.c b/ProcessHacker/miniinfo.c index 11be6ea18103..37becc411a4a 100644 --- a/ProcessHacker/miniinfo.c +++ b/ProcessHacker/miniinfo.c @@ -1700,7 +1700,15 @@ BOOLEAN PhMipListSectionTreeNewCallback( else { if (node->ProcessGroup->Representative->FileName) - PhShellExploreFile(listSection->DialogHandle, node->ProcessGroup->Representative->FileName->Buffer); + { + PhShellExecuteUserString( + listSection->DialogHandle, + L"FileOpenExecutable", + node->ProcessGroup->Representative->FileName->Buffer, + FALSE, + L"Make sure the Explorer executable file is present." + ); + } } } break; diff --git a/ProcessHacker/procrec.c b/ProcessHacker/procrec.c index 07268bea41bb..7dad38071e01 100644 --- a/ProcessHacker/procrec.c +++ b/ProcessHacker/procrec.c @@ -235,7 +235,15 @@ INT_PTR CALLBACK PhpProcessRecordDlgProc( case IDC_OPENFILENAME: { if (context->Record->FileName) - PhShellExploreFile(hwndDlg, context->Record->FileName->Buffer); + { + PhShellExecuteUserString( + PhMainWndHandle, + L"FileOpenExecutable", + context->Record->FileName->Buffer, + FALSE, + L"Make sure the Explorer executable file is present." + ); + } } break; case IDC_PROPERTIES: diff --git a/ProcessHacker/prpgmod.c b/ProcessHacker/prpgmod.c index 2b2e217827c4..5efd8288fd26 100644 --- a/ProcessHacker/prpgmod.c +++ b/ProcessHacker/prpgmod.c @@ -633,7 +633,13 @@ INT_PTR CALLBACK PhpProcessModulesDlgProc( if (moduleItem) { - PhShellExploreFile(hwndDlg, moduleItem->FileName->Buffer); + PhShellExecuteUserString( + hwndDlg, + L"FileOpenExecutable", + moduleItem->FileName->Buffer, + FALSE, + L"Make sure the Explorer executable file is present." + ); } } break; diff --git a/ProcessHacker/prpgthrd.c b/ProcessHacker/prpgthrd.c index 7b35b201c716..30670a03b358 100644 --- a/ProcessHacker/prpgthrd.c +++ b/ProcessHacker/prpgthrd.c @@ -996,7 +996,13 @@ INT_PTR CALLBACK PhpProcessThreadsDlgProc( if (threadItem && threadItem->StartAddressFileName) { - PhShellExploreFile(hwndDlg, threadItem->StartAddressFileName->Buffer); + PhShellExecuteUserString( + hwndDlg, + L"FileOpenExecutable", + threadItem->StartAddressFileName->Buffer, + FALSE, + L"Make sure the Explorer executable file is present." + ); } } break; From 9290359081cebee1eee2215f8495c2d8295fa0b6 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 6 Jul 2017 10:50:13 +1000 Subject: [PATCH 0254/2058] Fix version bug, Remove non-existent KPH functions --- phlib/global.c | 4 ++-- phlib/include/kphuser.h | 35 ----------------------------------- phlib/include/phconfig.h | 9 ++++----- 3 files changed, 6 insertions(+), 42 deletions(-) diff --git a/phlib/global.c b/phlib/global.c index 8d8ed1026c9a..26c69aa8a4a8 100644 --- a/phlib/global.c +++ b/phlib/global.c @@ -203,7 +203,7 @@ static VOID PhInitializeWindowsVersion( switch (buildVersion) { case 10240: - WindowsVersion = WINDOWS_10_TH1; + WindowsVersion = WINDOWS_10; break; case 10586: WindowsVersion = WINDOWS_10_TH2; @@ -215,7 +215,7 @@ static VOID PhInitializeWindowsVersion( WindowsVersion = WINDOWS_10_RS2; break; default: - WindowsVersion = WINDOWS_10; + WindowsVersion = WINDOWS_NEW; break; } } diff --git a/phlib/include/kphuser.h b/phlib/include/kphuser.h index a6905cb2f5ab..72eb102ed481 100644 --- a/phlib/include/kphuser.h +++ b/phlib/include/kphuser.h @@ -117,20 +117,6 @@ KphOpenProcessJob( _Out_ PHANDLE JobHandle ); -PHLIBAPI -NTSTATUS -NTAPI -KphSuspendProcess( - _In_ HANDLE ProcessHandle - ); - -PHLIBAPI -NTSTATUS -NTAPI -KphResumeProcess( - _In_ HANDLE ProcessHandle - ); - PHLIBAPI NTSTATUS NTAPI @@ -189,14 +175,6 @@ KphOpenThreadProcess( _Out_ PHANDLE ProcessHandle ); -PHLIBAPI -NTSTATUS -NTAPI -KphTerminateThread( - _In_ HANDLE ThreadHandle, - _In_ NTSTATUS ExitStatus - ); - PHLIBAPI NTSTATUS NTAPI @@ -271,19 +249,6 @@ KphSetInformationObject( _In_ ULONG ObjectInformationLength ); -PHLIBAPI -NTSTATUS -NTAPI -KphDuplicateObject( - _In_ HANDLE SourceProcessHandle, - _In_ HANDLE SourceHandle, - _In_opt_ HANDLE TargetProcessHandle, - _Out_opt_ PHANDLE TargetHandle, - _In_ ACCESS_MASK DesiredAccess, - _In_ ULONG HandleAttributes, - _In_ ULONG Options - ); - PHLIBAPI NTSTATUS NTAPI diff --git a/phlib/include/phconfig.h b/phlib/include/phconfig.h index 8daf5185a7a6..482921a90007 100644 --- a/phlib/include/phconfig.h +++ b/phlib/include/phconfig.h @@ -27,11 +27,10 @@ PHLIBAPI extern ACCESS_MASK ThreadAllAccess; #define WINDOWS_7 61 #define WINDOWS_8 62 #define WINDOWS_8_1 63 -#define WINDOWS_10 100 -#define WINDOWS_10_TH1 101 -#define WINDOWS_10_TH2 102 -#define WINDOWS_10_RS1 103 -#define WINDOWS_10_RS2 104 +#define WINDOWS_10 100 // TH1 +#define WINDOWS_10_TH2 101 +#define WINDOWS_10_RS1 102 +#define WINDOWS_10_RS2 103 #define WINDOWS_NEW MAXLONG #define WINDOWS_HAS_IMMERSIVE (WindowsVersion >= WINDOWS_8) From 2cfb68356bd62539efa2b95f5f71289a6eb3c9a7 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 6 Jul 2017 13:05:40 +1000 Subject: [PATCH 0255/2058] Fix CreateProcess parameter usage --- phlib/util.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/phlib/util.c b/phlib/util.c index 44ba3a99ee4a..fee2e8b0dee0 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -2583,6 +2583,7 @@ NTSTATUS PhCreateProcessWin32Ex( ) { NTSTATUS status; + PPH_STRING fileName = NULL; PPH_STRING commandLine = NULL; STARTUPINFO startupInfo; PROCESS_INFORMATION processInfo; @@ -2591,6 +2592,21 @@ NTSTATUS PhCreateProcessWin32Ex( if (CommandLine) // duplicate because CreateProcess modifies the string commandLine = PhCreateString(CommandLine); + if (FileName) + fileName = PhCreateString(FileName); + else + { + INT cmdlineArgCount; + PWSTR* cmdlineArgList; + + // Try extract the filename or CreateProcess might execute the wrong executable. + if (commandLine && (cmdlineArgList = CommandLineToArgvW(commandLine->Buffer, &cmdlineArgCount))) + { + PhMoveReference(&fileName, PhCreateString(cmdlineArgList[0])); + LocalFree(cmdlineArgList); + } + } + newFlags = 0; PhMapFlags1(&newFlags, Flags, PhpCreateProcessMappings, sizeof(PhpCreateProcessMappings) / sizeof(PH_FLAG_MAPPING)); @@ -2607,7 +2623,7 @@ NTSTATUS PhCreateProcessWin32Ex( if (!TokenHandle) { if (CreateProcess( - FileName, + PhGetString(fileName), PhGetString(commandLine), NULL, NULL, @@ -2626,7 +2642,7 @@ NTSTATUS PhCreateProcessWin32Ex( { if (CreateProcessAsUser( TokenHandle, - FileName, + PhGetString(fileName), PhGetString(commandLine), NULL, NULL, @@ -2642,6 +2658,8 @@ NTSTATUS PhCreateProcessWin32Ex( status = PhGetLastWin32ErrorAsNtStatus(); } + if (fileName) + PhDereferenceObject(fileName); if (commandLine) PhDereferenceObject(commandLine); From 036552a9e0d55052d584a5cf33ff910f75d6cc06 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 7 Jul 2017 12:30:40 +1000 Subject: [PATCH 0256/2058] Fix regression from previous commit --- ProcessHacker/appsup.c | 36 +++++++++++++++++++++++++++++++++++- phlib/util.c | 2 +- 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/ProcessHacker/appsup.c b/ProcessHacker/appsup.c index 4271dced71dc..f84bacb92f12 100644 --- a/ProcessHacker/appsup.c +++ b/ProcessHacker/appsup.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -953,7 +954,40 @@ VOID PhShellExecuteUserString( // Make sure the user executable string is absolute. We can't use RtlDetermineDosPathNameType_U // here because the string may be a URL. if (PhFindCharInString(executeString, 0, ':') == -1) - PhMoveReference(&executeString, PhConcatStringRef2(&PhApplicationDirectory->sr, &executeString->sr)); + { + INT stringArgCount; + PWSTR* stringArgList; + + // (dmex) HACK: Escape the individual executeString components. + if ((stringArgList = CommandLineToArgvW(executeString->Buffer, &stringArgCount)) && stringArgCount == 2) + { + PPH_STRING fileName = PhCreateString(stringArgList[0]); + PPH_STRING fileArgs = PhCreateString(stringArgList[1]); + + // Make sure the string is absolute and escape the filename. + if (RtlDetermineDosPathNameType_U(fileName->Buffer) == RtlPathTypeRelative) + PhMoveReference(&fileName, PhConcatStrings(4, L"\"", PhApplicationDirectory->Buffer, fileName->Buffer, L"\"")); + else + PhMoveReference(&fileName, PhConcatStrings(3, L"\"", fileName->Buffer, L"\"")); + + // Escape the parameters. + PhMoveReference(&fileArgs, PhConcatStrings(3, L"\"", fileArgs->Buffer, L"\"")); + + // Create the escaped execute string. + PhMoveReference(&executeString, PhConcatStrings(3, fileName->Buffer, L" ", fileArgs->Buffer)); + + PhDereferenceObject(fileArgs); + PhDereferenceObject(fileName); + LocalFree(stringArgList); + } + else + { + if (RtlDetermineDosPathNameType_U(executeString->Buffer) == RtlPathTypeRelative) + PhMoveReference(&executeString, PhConcatStrings(4, L"\"", PhApplicationDirectory->Buffer, executeString->Buffer, L"\"")); + else + PhMoveReference(&executeString, PhConcatStrings(3, L"\"", executeString->Buffer, L"\"")); + } + } // Replace the token with the string, or use the original string if the token is not present. if (PhSplitStringRefAtString(&executeString->sr, &replacementToken, FALSE, &stringBefore, &stringAfter)) diff --git a/phlib/util.c b/phlib/util.c index fee2e8b0dee0..0e68f3bd2136 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -2599,7 +2599,7 @@ NTSTATUS PhCreateProcessWin32Ex( INT cmdlineArgCount; PWSTR* cmdlineArgList; - // Try extract the filename or CreateProcess might execute the wrong executable. + // (dmex) Try extract the filename or CreateProcess might execute the wrong executable. if (commandLine && (cmdlineArgList = CommandLineToArgvW(commandLine->Buffer, &cmdlineArgCount))) { PhMoveReference(&fileName, PhCreateString(cmdlineArgList[0])); From 4cca64a04c3571b9a4f81ae21d4d01ebcf6faf5c Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 7 Jul 2017 12:50:44 +1000 Subject: [PATCH 0257/2058] Temporarily disable KPH by default until dynamic loading support has been merged --- ProcessHacker/settings.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ProcessHacker/settings.c b/ProcessHacker/settings.c index fba8a2719d3e..807de6727f13 100644 --- a/ProcessHacker/settings.c +++ b/ProcessHacker/settings.c @@ -40,7 +40,7 @@ VOID PhAddDefaultSettings( PhpAddIntegerSetting(L"ElevationLevel", L"1"); // PromptElevateAction PhpAddIntegerSetting(L"EnableCycleCpuUsage", L"1"); PhpAddIntegerSetting(L"EnableInstantTooltips", L"0"); - PhpAddIntegerSetting(L"EnableKph", L"1"); + PhpAddIntegerSetting(L"EnableKph", L"0"); PhpAddIntegerSetting(L"EnableNetworkResolve", L"1"); PhpAddIntegerSetting(L"EnablePlugins", L"1"); PhpAddIntegerSetting(L"EnableServiceNonPoll", L"1"); From 431541c85c5acfba7eaf64cbbd986d9b6e90dbe6 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 7 Jul 2017 13:23:42 +1000 Subject: [PATCH 0258/2058] Fix regression launching explorer.exe --- ProcessHacker/appsup.c | 3 +++ ProcessHacker/hndlmenu.c | 2 +- ProcessHacker/mainwnd.c | 4 ++-- ProcessHacker/miniinfo.c | 2 +- ProcessHacker/procrec.c | 2 +- ProcessHacker/prpggen.c | 2 +- ProcessHacker/prpgmod.c | 2 +- ProcessHacker/prpgthrd.c | 2 +- ProcessHacker/settings.c | 2 +- 9 files changed, 12 insertions(+), 9 deletions(-) diff --git a/ProcessHacker/appsup.c b/ProcessHacker/appsup.c index f84bacb92f12..4928ef98b55a 100644 --- a/ProcessHacker/appsup.c +++ b/ProcessHacker/appsup.c @@ -951,6 +951,9 @@ VOID PhShellExecuteUserString( executeString = PhGetStringSetting(Setting); + // Expand environment strings. + PhMoveReference(&executeString, PhExpandEnvironmentStrings(&executeString->sr)); + // Make sure the user executable string is absolute. We can't use RtlDetermineDosPathNameType_U // here because the string may be a URL. if (PhFindCharInString(executeString, 0, ':') == -1) diff --git a/ProcessHacker/hndlmenu.c b/ProcessHacker/hndlmenu.c index c4d2cdbef350..802e41c26ff1 100644 --- a/ProcessHacker/hndlmenu.c +++ b/ProcessHacker/hndlmenu.c @@ -121,7 +121,7 @@ VOID PhShowHandleObjectProperties1( { PhShellExecuteUserString( PhMainWndHandle, - L"FileOpenExecutable", + L"FileBrowseExecutable", Info->BestObjectName->Buffer, FALSE, L"Make sure the Explorer executable file is present." diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index 0bca69a69d8f..f30c396d2eb5 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -1311,7 +1311,7 @@ VOID PhMwpOnCommand( PhReferenceObject(processItem); PhShellExecuteUserString( PhMainWndHandle, - L"FileOpenExecutable", + L"FileBrowseExecutable", processItem->FileName->Buffer, FALSE, L"Make sure the Explorer executable file is present." @@ -1467,7 +1467,7 @@ VOID PhMwpOnCommand( { PhShellExecuteUserString( PhMainWndHandle, - L"FileOpenExecutable", + L"FileBrowseExecutable", fileName->Buffer, FALSE, L"Make sure the Explorer executable file is present." diff --git a/ProcessHacker/miniinfo.c b/ProcessHacker/miniinfo.c index 37becc411a4a..a6695a217eb1 100644 --- a/ProcessHacker/miniinfo.c +++ b/ProcessHacker/miniinfo.c @@ -1703,7 +1703,7 @@ BOOLEAN PhMipListSectionTreeNewCallback( { PhShellExecuteUserString( listSection->DialogHandle, - L"FileOpenExecutable", + L"FileBrowseExecutable", node->ProcessGroup->Representative->FileName->Buffer, FALSE, L"Make sure the Explorer executable file is present." diff --git a/ProcessHacker/procrec.c b/ProcessHacker/procrec.c index 7dad38071e01..8332a7180d2d 100644 --- a/ProcessHacker/procrec.c +++ b/ProcessHacker/procrec.c @@ -238,7 +238,7 @@ INT_PTR CALLBACK PhpProcessRecordDlgProc( { PhShellExecuteUserString( PhMainWndHandle, - L"FileOpenExecutable", + L"FileBrowseExecutable", context->Record->FileName->Buffer, FALSE, L"Make sure the Explorer executable file is present." diff --git a/ProcessHacker/prpggen.c b/ProcessHacker/prpggen.c index f780a952ead1..925398bfa7eb 100644 --- a/ProcessHacker/prpggen.c +++ b/ProcessHacker/prpggen.c @@ -500,7 +500,7 @@ INT_PTR CALLBACK PhpProcessGeneralDlgProc( { PhShellExecuteUserString( hwndDlg, - L"FileOpenExecutable", + L"FileBrowseExecutable", processItem->FileName->Buffer, FALSE, L"Make sure the Explorer executable file is present." diff --git a/ProcessHacker/prpgmod.c b/ProcessHacker/prpgmod.c index 5efd8288fd26..c803d20f97b7 100644 --- a/ProcessHacker/prpgmod.c +++ b/ProcessHacker/prpgmod.c @@ -635,7 +635,7 @@ INT_PTR CALLBACK PhpProcessModulesDlgProc( { PhShellExecuteUserString( hwndDlg, - L"FileOpenExecutable", + L"FileBrowseExecutable", moduleItem->FileName->Buffer, FALSE, L"Make sure the Explorer executable file is present." diff --git a/ProcessHacker/prpgthrd.c b/ProcessHacker/prpgthrd.c index 30670a03b358..68565ddee871 100644 --- a/ProcessHacker/prpgthrd.c +++ b/ProcessHacker/prpgthrd.c @@ -998,7 +998,7 @@ INT_PTR CALLBACK PhpProcessThreadsDlgProc( { PhShellExecuteUserString( hwndDlg, - L"FileOpenExecutable", + L"FileBrowseExecutable", threadItem->StartAddressFileName->Buffer, FALSE, L"Make sure the Explorer executable file is present." diff --git a/ProcessHacker/settings.c b/ProcessHacker/settings.c index 807de6727f13..bda87b5abf52 100644 --- a/ProcessHacker/settings.c +++ b/ProcessHacker/settings.c @@ -52,7 +52,7 @@ VOID PhAddDefaultSettings( PhpAddStringSetting(L"FindObjListViewColumns", L""); PhpAddIntegerPairSetting(L"FindObjWindowPosition", L"350,350"); PhpAddScalableIntegerPairSetting(L"FindObjWindowSize", L"@96|550,420"); - PhpAddStringSetting(L"FileOpenExecutable", L"explorer.exe \"/select,%s\""); + PhpAddStringSetting(L"FileBrowseExecutable", L"%SystemRoot%\\explorer.exe /select,\"%s\""); PhpAddIntegerSetting(L"FirstRun", L"1"); PhpAddStringSetting(L"Font", L""); // null PhpAddIntegerSetting(L"ForceNoParent", L"0"); From ad70e7d77f1945e39de95eb6a7619902e2de71f9 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 7 Jul 2017 13:42:26 +1000 Subject: [PATCH 0259/2058] Fix setup error during update, Fix KPH device name typo --- phlib/include/kphapi.h | 2 +- phlib/kph.c | 2 +- tools/CustomSetupTool/CustomSetupTool/setup.c | 17 +++++++++++++++++ 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/phlib/include/kphapi.h b/phlib/include/kphapi.h index 36d03742e9e9..533fad2d78e8 100644 --- a/phlib/include/kphapi.h +++ b/phlib/include/kphapi.h @@ -114,7 +114,7 @@ typedef struct _ETWREG_BASIC_INFORMATION // Device -#define KPH_DEVICE_SHORT_NAME L"KProcessHacker2" +#define KPH_DEVICE_SHORT_NAME L"KProcessHacker3" #define KPH_DEVICE_TYPE 0x9999 #define KPH_DEVICE_NAME (L"\\Device\\" KPH_DEVICE_SHORT_NAME) diff --git a/phlib/kph.c b/phlib/kph.c index 07008b4c39b6..71bf12115977 100644 --- a/phlib/kph.c +++ b/phlib/kph.c @@ -256,7 +256,7 @@ NTSTATUS KphSetParameters( _In_ PKPH_PARAMETERS Parameters ) { - static PH_STRINGREF keyName = PH_STRINGREF_INIT(L"System\\CurrentControlSet\\Services\\KProcessHacker2\\Parameters"); + static PH_STRINGREF keyName = PH_STRINGREF_INIT(L"System\\CurrentControlSet\\Services\\KProcessHacker3\\Parameters"); NTSTATUS status; HANDLE parametersKeyHandle = NULL; ULONG disposition; diff --git a/tools/CustomSetupTool/CustomSetupTool/setup.c b/tools/CustomSetupTool/CustomSetupTool/setup.c index 59e5ab6918c3..31009632e79a 100644 --- a/tools/CustomSetupTool/CustomSetupTool/setup.c +++ b/tools/CustomSetupTool/CustomSetupTool/setup.c @@ -346,6 +346,23 @@ BOOLEAN SetupUninstallKph( _In_ PPH_SETUP_CONTEXT Context ) { + while (TRUE) + { + SC_HANDLE serviceHandle; + SERVICE_STATUS serviceStatus; + + if (!(serviceHandle = PhOpenService( + L"KProcessHacker2", + SERVICE_STOP | DELETE + ))) + break; + + ControlService(serviceHandle, SERVICE_CONTROL_STOP, &serviceStatus); + DeleteService(serviceHandle); + + CloseServiceHandle(serviceHandle); + } + while (TRUE) { SC_HANDLE serviceHandle; From 5323554632562b7c30d4b25c8ed0a26aa59409cc Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 7 Jul 2017 14:20:41 +1000 Subject: [PATCH 0260/2058] Prevent KPH loading on unsupported builds of Win10 --- ProcessHacker/main.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ProcessHacker/main.c b/ProcessHacker/main.c index 2ed7ebff5408..815ef58ee872 100644 --- a/ProcessHacker/main.c +++ b/ProcessHacker/main.c @@ -560,6 +560,9 @@ VOID PhInitializeKph( PPH_STRING kprocesshackerFileName; KPH_PARAMETERS parameters; + if (WindowsVersion == WINDOWS_NEW) + return; + kprocesshackerFileName = PhConcatStringRef2(&PhApplicationDirectory->sr, &kprocesshacker); parameters.SecurityLevel = KphSecurityPrivilegeCheck; From a1ccdcebd568664b10b76701a3460052e0e24ed0 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 8 Jul 2017 03:31:12 +1000 Subject: [PATCH 0261/2058] Fix runas crash (thanks to diversenok for reporting the bug!) --- ProcessHacker/runas.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ProcessHacker/runas.c b/ProcessHacker/runas.c index ed8eec32b283..c7131fbb28ff 100644 --- a/ProcessHacker/runas.c +++ b/ProcessHacker/runas.c @@ -425,15 +425,15 @@ INT_PTR CALLBACK PhpRunAsDlgProc( // we need to be in the target session. PH_CREATE_PROCESS_AS_USER_INFO createInfo; - PPH_STRING domainPart; - PPH_STRING userPart; + PPH_STRING domainPart = NULL; + PPH_STRING userPart = NULL; PhpSplitUserName(userName->Buffer, &domainPart, &userPart); memset(&createInfo, 0, sizeof(PH_CREATE_PROCESS_AS_USER_INFO)); createInfo.CommandLine = program->Buffer; - createInfo.UserName = userPart->Buffer; - createInfo.DomainName = domainPart->Buffer; + createInfo.UserName = PhGetString(userPart); + createInfo.DomainName = PhGetString(domainPart); createInfo.Password = PhGetStringOrEmpty(password); // Whenever we can, try not to set the desktop name; it breaks a lot of things. From 9dc974beceff0c626324d7c706eb7534b1892e58 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 8 Jul 2017 03:32:01 +1000 Subject: [PATCH 0262/2058] Fix 64bit propertysheet style bug --- phlib/guisup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phlib/guisup.c b/phlib/guisup.c index 4ecd51fb4500..b9667e8d2509 100644 --- a/phlib/guisup.c +++ b/phlib/guisup.c @@ -906,7 +906,7 @@ BOOLEAN PhModalPropertySheet( oldFocus = GetFocus(); topLevelOwner = Header->hwndParent; - while (topLevelOwner && (GetWindowLong(topLevelOwner, GWL_STYLE) & WS_CHILD)) + while (topLevelOwner && (GetWindowLongPtr(topLevelOwner, GWL_STYLE) & WS_CHILD)) topLevelOwner = GetParent(topLevelOwner); if (topLevelOwner && (topLevelOwner == GetDesktopWindow() || EnableWindow(topLevelOwner, FALSE))) From 9df03a9ef02fa4d01b046142534d3f5ebaea7355 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 8 Jul 2017 15:06:31 +1000 Subject: [PATCH 0263/2058] Revert commit f922924765f2069a4dc924773bde8c1827b7a0c1 --- .../bin-signed/amd64/kprocesshacker.sys | Bin 40088 -> 45208 bytes .../bin-signed/i386/kprocesshacker.sys | Bin 36376 -> 41624 bytes ProcessHacker/main.c | 15 +- phlib/include/kphapi.h | 53 ++- phlib/include/kphuser.h | 16 + phlib/kph.c | 411 +++++++++++++----- phlib/native.c | 61 ++- phlib/phlib.vcxproj | 3 +- phlib/phlib.vcxproj.filters | 3 + 9 files changed, 431 insertions(+), 131 deletions(-) diff --git a/KProcessHacker/bin-signed/amd64/kprocesshacker.sys b/KProcessHacker/bin-signed/amd64/kprocesshacker.sys index 4da0af31c218fe951f263f863345fdc66545eced..7d4695902a56f21840791f0efcdf74d35bad3c34 100644 GIT binary patch delta 22087 zcmeHvcUV)))9^`1=nz_HQUXLkL=8<*1QQ5wA|NOt*g*(I0TBX%7mYL}9BH#jx&Xrl zqV@_5`@jS!#4t|;Q!%Vu43PfYX%8eML(P@V!>~%`LOV;N-ZE*f44NxA@MC}y`H5lc z1)X9%NZOE0Aa(f@Vi?{#Ax;(tblG32;n3||vhr1H&2M2n*E zqGv*!VBg~bTaS8NA?ADIMB#ow$B9oKw{Rj^fD;*-O72%f3=&e?-Qz_` z-k8TFoM=*v7bv-Ws3(r&L@4OMqp`(W6LmUQ5L6n&Wk< z>LyO$peTtsUUFKdQ-cPg%E3T9pyzttXqr`HBRwTDzIn80 zxF||ALKKY`JiAW~njLHlVxXxh=3juCP~sD=7|s{s#2nQui3FiUvUw;mg-1*=Ao9$` zb0!GGN}gwHAAABsZ0)IzVFgMx-ty(L9tBDbo*XiE1p5dNWc$FBv5P*aWgCj#1!7E~ zfXS_G{lvzwl6NvrSjju6QfETdQ>ZHVHWRwfp=+)}OKHMUt1&7nj-U)Z{ajmdv#uY&gdq}}r6J|8%vaS zs+)|F=f|L_k7%hI24>LQ`WEoJ5dHBV&{cp~pj-xqF6R{IQ-y6%;1s{2OnC>DucY#OsC){QA8n6t zdQkcCRQ@_O9r09tK9zTHfawS?P&y%~eGuGBZL1$8W~YMtbchKGmj4G02dXs8pr|`- z@gL}(n$l20kAUqZjL`bYYz~A`gFFq0U8c2$rgKKKiYAqs3i;30Y!ONkmr=x>(>jAD z2B!*BifrOXHa~OO>`!qCrnq#jc5j-Cs%wfy-en=l2T?@EKN7Jzh<;_li$_x=_d)et zhI$c-lpP>x|9cBwGYZ3u!5Y^8NWGXGD&@*yEwbN3%n(LUTM~F8CD#_pL~}`PZUW*? z>4M@;*>^IvQjk(((a1WDRoH@2Mu*nF5L`0wXyX@sGnZ*lOTW$h-|PNf6!>MLSp?gl zM71YMh$bc15M~=~h;yl(2knU(pqtRLReUsl2{BqAA+m%L;*n^)Xq;%QXv}zeOY7Xw z4A4f#gN?LoB!l=QAzrCnF8G82lN^>uZCf-ID!@Li5H8D%6gMw@VABFDBE1OXBsy)96En~}`A!daP`EZC$(4UZoE;Q7p;Xlh&?RRO|NW=X!TtUNR z8efHtVSbBMxnVRMN5ga)&QL))Hjl2@K*N1ByiLPrG-NGNF|?tfI}L+qIEscDG@M1l zbu?_C;X@jJqM#fC^`$Dty=fRq!(u9)>hV?YOO~Yq2)GSwZz^CCr8V;jjG7WQRIFE)~X;@FgD*#dd*h9MF z3k{9vIkl&uKMi9#=9-52G&G?{{*6=#_J)QJX?UK7M`&0@!^I?KOHs_EE81yQCe!88 z6>#L~)p5jvodO#VsnH&iDTWP;6h|&93zVlft_)f2GF#}&yHdv_r&x`bGi>!R+XOyl zJKO=Y^|Z%q8CIBiyXk$C3r4jD85qVe(Zoy=v@w(6T9^qePLp8<8Cnp0s%J7YTr8m- zdU=$IVecWKJc3%bXo4@kQ+F%61ncP8m)YdWC=*D)Q# z`a?qe5UhbzPnQwY;%Z{tdIO9r<6vA*eT=)?@InXeEjSmlA&Nk>8UW8ix=NR?rjehl zZR8!OKUZa)}&LKNf15GfP^R!)JeuLE+kY&P|HFav$(>+EM)qaMS>n?0Zc3waqoAG z#w-!TTp%HQ1l56u0nHCVmC}qrX@;OQP~Igh;*g3SpSb`cUHz6@}u6toTrl@X*= zvFQ7ZM*_}R8XrOOf~~n@ha}G@z?8?Uh!LCxX$f6k5>M*$+)WWG;(dA;hCP6U@{fj* zi98#*u8pe5nF*U*0fxEHg0ncl0yU_ojL`s$kpsr4kD2T?$Y7XjW9A7um^m1zIT)z9 zyUKJKMjDt=f(FCLQ=MVNU@>&Sm@OQU5j$cg3>!@EzRm@$T8#|#SU8kJpE@AIiIK3% z-;GoWfZ$39E7n3n@*y~D42Erigvtp1H5PO;PE|&57NnJQ89^p2LNiDRAHnI66m%Iu zVJut}Ktk;Z&W@8~*s?fP1%ig4OGiiu0l{&QlIb#n51?L)!@@YQ+&Gy!olEjT6o$Qq zgy;~ouw`RAVnrN|xNrpBCTFUNBfrXtWW;9$MGcp9TGRoAypqrr+i;%oA z(#F~*8BG{W05-A+ZeAcEz6c(J^o1^K6l2&LNE;xbb_#aR4$P7#%uvVdm}z5X!%ZmLn~Y({QO7t5 z8lVh-?m8LNl99nO0rRi`1z8N^-Z#ErSleN!4}Qb2kB|`k)O-x<1!-VD?UUm2$@5kg za%z1cVJ?rru&Er5=YTBa+;@h#h`7=KK{zZS~_ zGWJF9%z0#>VR2ahioqD$FT#cUo-gi~Q$4Hny{FN_cT$I#(`|juE;XKiCVJY1X-Dnv zUgCZs4V`$Tr&H-7XO=w35OnGU!5P2>kQyOh4lvOiCb$PAfS3hbsX2m(0M|hBb^yx- zgODL30-St+_aGr!WHW3VxH$tHG|UP}djV%Bz!kO_b^-F55g7Ia(uN*rQyq$7`@jY4 z1>!>h-$LR;XI}t5iNr8-$lo81Vb-Ag1%Sf`SO}@n8N*5e#(}P_fN3(o99Xhnx`RLf z*TU*J1hka^)xbp^f_hzmS&&vC9Dw(v(0?oxTBNYkBw-j2@52G0luxB=O3iX}(qVF9QelE7il6!ZBE(m*Yk)O0ln+VD`R#LM)iKL9{{I>pX_j1}0kk~`pnQdv^V zDP0A_hpW7n8i1%g7nRGnzj-1+9fiy7g zvTPgFpMsc4G0|(LDvA55k_~yql_zh+3B5Z=9A)>Mi%O*`)<-8F>d;e*Pzm<4dw`(2 zz1vCE+yIfTd#FUhm0U4UiaFKYj-sWRC{`Q8$EkbJ;Y5>&Q++v64E(&Q-vLT)A3#Qj zJ|SF;X3MqruRv#g9#8@YHJpglM0cbI8hR28~8J!S1MCVWy;|CHxzzAC82yljRnSpTT?jE!u@Tm05AaN3Ykdh+2`fJ2c0m{ zW#@3BS;;Lz^KdIq18$8~*T7suYMgWVFr7d$8rl(s03Gm#;?PY@XxUtT1vKJiizy`P zoG;oBJ)o|51{9qd&=noxZ-4^p0N8jfC$J8Vq(iEp0_GWSB0f@V6~066E0rx^l%ROJ z8+9f3aFbH0I>b^F0EgIZCy^kl_{|8jpuQHs_~Yca-qzfOfD4!0f5W7S72Vpj+q4Px z9a7N8L(k3~NeNt)+#yY5Mjv~ob`!a{j~&ytiLCC^m$~CS`La(hX61R(M$kj9mi?9( z$}0LKocbJ;ehE^UCiD{Ob2{^OpvP&E&&8Z5Ng1vS^TRH=t5k|=luC&CszqOX*wQ;n zWp+=9ITHo@PgTxT!QP?DnJd^^R5?opd%Y@W zrC_gyoJZ|(a+C*Oe+J~?_TMj)N9awsP0sa*W2)UIUwU}i*-MDiO76`wpkklnG7~~? z&n=j~k4l*qXCI4^s1TDep3cnhda}^di`?&N@3izAu%a%Jg>%~5LpgP7gq}Lk;A%~H zQGZOP>2XQPjXOg!yatZ=gcCQ4d>d~nm42DVMZTLMqs-Rce-N#M>97uF9-_<$ll6fc z=p!spxtKT!K0(PXIIC2Kl{}Vls0z5OZd7v9pstPGDkfKZ*~p_$1A^-61+MA0KneK} z4lqUE00bWIihRvbcbwwqz!oO}X)cA7YfiAg-9Q%Q3Ag|6vbCr-9<-s7Hbvcf0MRJ& z`QC%eSp8H>xGWgH!occ;wHSdF$rJd)u_E6az{oGt5^Mx5LvQdEsh}PlU9G=_g$s8# z-&^#*(k)lfl13J<e2&}h?a^HJrHMyw!<_hg(RtNYq9 zk2a7u`}QDN{l+lcPmvS)$(YPKvbkS0Gvzwz<{jub2l&Is1({)uO1a12GF!=&A<=YO zXMl|pd-*~JsSGi7i~!ZaO-wW_HcGG5_kk@?LVEQFRPc^lPm;~veEBM<-48Xjtvc{4 zo>Rp~#3i>l#e+5AD*Ff&Fj3FDoZ^>kI%C+8SqgGcO@S zqtH|fvmgYWi?LRS;NTKZlVe4ZTc<&(tF$2}khFFe>$^&O3raso zyP}?4GvLo4AE*c4DmI59x2Ay_iyD;u+0(Be%MJoX^=Ic%`2kcuo67fweAf=m>d6&8 zw$a;<|I|eqR3L?@RtR;2IRL8AXFMOmnghIWwPvtsJ!ixZ6sF{A!|-6>hf0{F1L<>(P??Y zK1SXdXl=X!(0|ZJ&ts&XuO)NyL9&OhjnOPHjjmMDDk_7Ysdm&+R6Qvwk@inix9UJ@ zFfJY@I)FAYw1{IwWkZ>i5AuT6A4Kr1BUyfKjB>KCpB-~h9XZm^*68FBV9~`C9qY(B zepbdaAprS-R$faU@N;1PbAY_-XVKdXKYW6aKkhtdan&W?&3PpyBko$2!5fIUgEI9%ulv8{NSc{1l;7`#P)P|O= zhY>J-ct%K~%d%TCaG6{t#7gPTCGKCX=lzcqMFL2v_Xw;zx2fj7} zMHE9RW4HjF!W?&uiCSb3@B#0(sa=PJA0?B7)_vB3?tV~G1yqzMb9)wj^Uk&gpO4~< zN=ojNEmr%!Ar|6Kedn>u;4k4vbj@t4tDf4%h3!~vP zGJFxN3nMPz5XS(X5Lck!1+2&!L(Ty_z8GA`Op4`Pf>kD$E`d>sPx5rKHnfzk-#?}Og#X|2qao1M6;N92qFMeG(t?~ zR-*|(OdL~k_rM@(kSU4F{NGR$v-Y4;`IwnY-b z2aK11*JgyKN{DJ=lw7t71>!{FcxyTEJOJi~iHQ2{1|~*W*-(bar=AmdMm%ROB}XVx z%&(vjuC`1ApG9%^Ku#5>oa#yNrZ64sZxBJ@z65Nk@c1B*Xr!Der4|TGK?ty1q$4GF z9281!DNE22Dd}|;F1#`(K;U*r*Jkba=KY_$63DGVl{)X@a=t@Bz zOlIDpA8L0N!muEgcnP0!jO9ppgaq543&{07tjLEFvY{Giq~$q{1SdWqA323q#npm` znh<%Hi9i=uIe`t|*{RGxL|kieH=}jo_HSLtXHYylba9T>1z4jmG$2htwh*#y?1OMr ztEDB;gc@2isu6Z*M!k*MVO5|fbreifuOejpWVGNjLg9TxE;2Nc>U9K}E%A{*qxiR0 zppjCx+$kqdJm)-U<`yjb@0#g#0BI&yhGc;acqtT-N?@itR)nxrhQ90SjYds`A+>RS zpXdf9*996tPWC|*149%>G5WTj^d2mfQ+D66){s7Df?R>b1$azB+z2J$3CShOVYf`; zst%8vp&f+$QVlDOMpq33L`EYKBBys2nIKQe?F&Nz;d7MS+mvufWS<7vNNUI;m{mCa zBgcTE0I=0cU`pGqYX7f+*@gp>0N7CWZAl4FTvu|XP^Bus0SoV74r9Cp^QPqf1)Msj z;};7Z883XEtHtHStC{)yTv*g1;-Y9j?2ur7pfV1{aSVL2EV=bPrlVH)8|b-BqiqbD zYk2&Eyb&6XfEu!R4g^4;o_qVKIjq6Zo{M&g-XIWY!V$>~;b<@v5o@`js(Xzh2doWi zQv^$(ArvT;GW8Yv zx=~UY&{FLI1XcIY^LX-Jco?&`n(Q56#avfShDJCV-2Ahv>%aZyp27$}2D5%Id2DDu zxg)2V3Fj??M3DkcY)pv)*MzK)31>Oj=7(vvZ2be|(@9joVMoNo6(UU-p!3gfeL6fa z<$z;1zX^KzkI`kUBgH^0nPa|6oU_2+^F6 z9edBKz~a+g-6|Zh+|Y2?t>_Cma;r@+y*MzX{RS9Z=5A_g!4Xm3{WBDi%K$$G1}H4e zr(DMKT}a?xxC|Mf!!t7#Z8&1}F1MSoSSbTRDJDAL`r1_+D$d3gYQ#x$^k8f9bCj!k z!3T7mO1g~b$u!?XMvt&%zTZvej<921*-fq-k;)QK?j((4 z`ZB*%k|8m^%)^!BoESUi&7I^QF%D!?jFWuYCZ%$w52h$Wjy#)#mxaVq9F*Mr9iWP$ zdO^qIGs-b``icL>O*nx#DnIZqH=zqn|8f)ZpZ$a_^a^uUBLs0MKM}N@nzjxJP z3;KWKCWceaEeox~|KKMG=oAUXqlAJjaW@cv^XhODXQBArO&li=u>x5dFc6Z>=9#Mj zvCk=@dAcKY|3wYzDAbX@?9r@Plv&00l!p?xC5q9S62&9~i6YA!Z9oD^SpW|w{*l0* zPqc;+4e&rgq6lbL-Fo3gr>vl;x{T8pWW= zVZ<{D@dagb(N9K;(*`hppL(L1Gxr$f!eOQ0WpwCMmda0L|lxUIo)WfSt zbRubmI0GXVQ#`+;;eZD59H7Z=$k7X;SV{;aB)p7;D~2%Q1SK&VEU#tN`p&^#2iZ_d z1Zu(IJS&U^%Y;{L-soi;x+J!_QLwjz&*`vNv|2E4%302+<*1prrA6Bj))3g~9+K6=Ql+>JxOjO9h-wREDACzTHAud2Mc- zxc>%fm&+c8#+Zw+iF#NPEsbkw6hBeVH`(*Sbj7eCQWira;>7iq-GD_|XTBxfDp3pq z0~RUN+cc>sw?HWIc_!1Z36aD2aAZ5qpeRbC5}!sH+)1~9G*s`X%x(z=o)Vugh=ihm zHU17T!c<(Kin?WcL=z<=A`OpAEkYpcc#K6HS3Sp?l$X@^s~5GD|G4)2;lEjV7r zz6DVpI@=3F%h*jo<#7p_B#!J)wJbN%w7H{@MWMMvDJ>J4>kJR&I|c*7Gw@%b=zQFYD{?h);yr+J zPDvWFZi2mGGj!-<0B@sVUDURIh5;(MgDRDBh(#9jE6{l1f+TE>YRllvJqa~PVcxJQ zONc8fXN*D>w6xIrRdU^dCE8y&bC*N80IpR4FtVpYE(Y!jvFx-Ov`45;jA$VZhc|ST z7^ku|DEHJBkIO;J@H!m&Xl$AB5h+E+7a*?rUO4Eu0$7T6GT`kt1R@)iN+CoXW*rTI z#0j`VZ#nxFO*{ibnm>d~ly8)lI!Wsw@lBRB~r-nhayOm+uG% zBvh#g#FgB~5Sc&@<{n*dD*|IsCIT|Cim}3Wt$}=>dx%=dS$#@P=`kHEddft90)T_E$t z>som_XLTANt`?%bN2uiP2Th8J77?fBxh-9_af2L2*v_eWVJq@^EBhNFPq2hoKtxQr zV#T%!;HucO0e&gbi*#5j98bV0ddZL(7AYB=k`YQ^Q-rYE)QKWQBZ29Ng*T(@{r1Qb zL4gpEq;_brsGdjrI=N~&!#NWD3k?ArDY7*@YFp7ND!Ifdo(oX)4r6kP3spImEMFx^ zD?{d9^pPRcpj6a0N#wHt^)EXnDT_&_j>Icqucnr0?csJXLokoFUVv4BuvT@T4q(b!J(+Fm$mns- z%(``C!8l*0(OR;0TyLgJ1=&9CH>PwgnKs@r#0z!-WUFxHa6H=v?iJh_2T*vT zfjA|BaF00O;gU{nqU}=!k0jFB2+~;5QtSmjp`Ps`V)%eIi<6}MFzrgE=*F!8YuCp&m15r)Af`1 zoX>Q_3HCxH6}cwCM*aX0NtZQGYIz#?gLfpnr)ne_y*r8dXJQwN!QO%vHaL$40js-&ar%yTuP#18vMco%1 z2XBt{NeJiLu2Qpg1-_KE1TF=2d)$I*Ve32)qIErzr1KgEr@Rw2eD<(as&fqN3LrD| zvlc3dW@Hj@nh8{LDS_b@2rL#nt(Y$mm!i!E9WBF%^Wf9OXm0Qpd(fJSjw-`PQ(#0* zO&i=W!;H0QdMH&g!KY1`G19CK91_}Cuo{KrN2wEOo7jutL53v;l9v(%WM;CBJQBk( z5$2A0VSPcq#>Q}L0yYtoV)2*^3k8^tB|$EkYC}sG$KtRoD2uTaXputx*LWSvJP->2 z+(_tSJQmTVAG+PL5g`OXQxxV89ZDdNU^wPamL+#%)-Kw!HF+F*W|BZ^PRw^SN6`)a zhqm4r9?aE(jv9FP0!s_yEwnTJpI6%d^Gf^w=U3X~!&I5^duE7KlAa<}N6;$$h4)5-YsCESNtU~Xbm`h?WU@slF5vywvrVx-<=>+aR8h%8b3l^C4QgqTy421B9>b(@ z2|+2TQjDCEX(2CHkCehd;$$6?OVZ+!q(kD;q!@My6e*Ub#^nX(O5?MU9)>4p0yTzp z13m$el}Ra1n7R5eS?aL3^n}T2fw|a}4oSPnufltw7M2#3o)(vZbSF)Sh$F{la>+TF zxpEuKKOi$NLl&MPO&6smP0mb_C8xoJGvQwot6Ig(z3gmtIuMo2SL67wQclG5X3*_klybbUbT4w@l9n+! zQx+o4i-=3fgm=t82m;mcAhUxNr4UuOmUJD=GYld_nkmb}CS^(E6B2r7=oMs>y5eXS(x38L1%a6L@=zyfWc&9fjkp~0*u6z4+~X_Fh$Zvt^*Q17SQ0V`PpBF1=`PwZvW_Nb!JCP7fhwh|PwSQTna z29s&PdG#{!@B}Mqbx7D_lkQXGWLR-Iv!8%`TD(x+*n90TiB_ZiOV5DYqD|!$wwx48 zkKKzlW;qVAKJai`eb58HkNjirtgzp1Tiw_`YRltUL;tD$+{<$D*(1i4C*K#v+c;Sa zTGIEZu-w~W*zS*~9-5?obGthEua8HcF1#9tqWh9tKYuvYJ1umU60V?2R41y`*Sv?`O15et@X|qE%jxJfYX`= zE{oRBeqrXsUvJdS@X%cNmrir84;c5HRdN5X=Py0eTqBPz(7HQ)q;2G?E7b=qGEJBG zD)TawLE~0=Bo9`<{490vsrA##ii`UWG`hO%^RuwotF!7K?&wpDbIcDi)fgCKeIet3 zppfw=Su)Gj#C89QrMv5PRZQQofM>D)2s`GUYc6?W)PPA|Iv5#jI{^ zwo#WaJ#2RxzpLlZz~$9@#%~o6xlIk0(}ylwF-Fh!vF(X5ca#^@eouX~Qj&jUdfiw_ zuL_L?6B}O*j)YzOnF+^C4BLZ-+%*~9(yRJ}k+_r<7~IC>+3zXH-Kn$Z?3|@~`rWq+3cGJ* zG8lq_*@7&xeY%j`QSS9`!+cYoV#1e=S=A$bQB%Z|Pq{DZ8BXPwO*P0V%Z=qL4`1&) zepfXk`MLMWic?pf=YPIE>!vL4;_-TwdYSZBC+3 z##iRfqrp2pthzUyIjcF%v-_~;$G&cHmDf#)9jcfbQ=L2OMSsUPJ6}ij=~uiGn|`%O z5O9HaJHpIm)>7@}QNF{21{o+)3c1#n>C2|wzJAyvaqNuViw2x6cy;BadU+r*^X}={ zWR~W&$>s5XsHx8xA0}Jz(pQOH0Pi@u~Iw;7}6=&W03Ooh<1%2H--TRFaICOdkEtZ=p%Oq;@vWC=18}^XW+m*64 zi3Jl6p7f>^C}3a)_N#Zr1*o4hA6Dwv7FSl);1e2g7BZ6Chmb=?4*KH1#?AZDfiWhGIqZI0l&h3y*VxBqR0-qA&d zk7c(U{N;B9K_z*uY6pxYC(E7~W7ZcNEP~@j85U;O7F-^E=uF|s8PgLd^*a8=E$6uI zpZ)LF-Fmk1#Jin#uijhFKmWJsZqH}$0{{3UeXpUurdz`4X7JOa>bhjQLK?U{wqegp#6M%S5-I&{(|9{uXHoK~K!)`UaWnMV78!+Q-Mz z;*e+m_f{vXe&fCoR1|U!f|KqJPFjz4(k$J*HsO0R>c<3#bB0cc>4SLEPM@IzUFV=x zW9B9B03XCsGjOxh;9I*rda&FRN_XG17(o`l^24#5To}VU|93 zL`Lzu3l6-waMt(U^tUTtMS0b()ZX6z-Sg&~F?Y7SUOlm(AYTRckB0UJIvbic;C9;4==v9q{;clb7uPJ^ zSg|p9wnc;QrqK)8j9pi-r6z7OS#$1hTEEfVZBaigRz;vcb(rOM*OSf^(fG34PnG?ReYFzL{D6mEd`Yc#I#Y4Kb425i*$JO6yxZ81w8 z{Q2qD&8B}TwU77vm{2=N2R;GjoVmwVW;VbFO#hsc6VD< zlI%1+aOeGL`F9-Othh3rv#E+zhfA$qN<4HfoeFYZve|K{R+DA>r86>e(cDMkbpGh* zHM<+{G4A{Bm5UmeUHjYD*5CJQ&+J0ofQZ)Ss*5-NdaSvOo!ukqNH4|oZKmUnxZnR1 zb}A9OH#;1bV?TO1>dY`$Fwk4V`P3(A#q7145B#J!K`OP0&CTm&XJe-4=HVuAcXx9a zz~3k{J$LUe#s7_kdvJ!GeDC0K(=|AvyY+8#O#2?5qHG!zo)xm{qTaW`XQN}rm6+aP za)&Q(pFglq7&F%(xuMxBWKiAvr1Rxg+dU5SvfiLQoUAWdch76r+gAfO@A3RR7C#+y zdV=^6zP!y@5_#Nrey#ppukzLjL+|-c62`q?iEcJ+9y4O;#gC!Y;^NumDe@i&Zu&H4Y4#$*GV_KqVo_wH z-?0F9Ez4QPDFZ(jxO=!KWM?@$T5Ad%d^9>%>;qV_cLYYAR;wvc2jhho&ZJYBBk4T9 zg4AB%Mt+=cNH)xOvkXUgJQgkp5_qd?(;*qgWT|2@7j1RTjxepu8vm6GAV)6fB?m`K zEs2Tx${EJ_>Kj99d(ZtCnV|KsCT5`^;#uRG2bU}R;6Z)OdtAtM9$!8}$g!z8yvt|y znA@Y9d3w(+O~bAl^6f%iIi)NxZZllVxcT+ZA$cRS4|}^zJpOK;sOOw@#C6x9LvO6A zXm~WFCbcs7(vXYEwsV=$K6`phoHtRQv<2Q4!J+-Ow zwtQOo`VZaeY0r|LyA>K*3JMKPshDlf|JsQ8OoLzTU`YA&=2=lNpJXgIHZoM#ruQ{1 z3zi$4P#C1~@&STAo!cEmG4?DT+4u@CTGKfAY{Aj)%UMs%r%(OxuDf69*tK&-XDh-g zi>Ziaw!tfxO6G4G%dQ_hczE89*DliByE}y*Uk{yHHoM00TTR^4S&kFg4tDqY6!)0l zKk)KJezRl6vhuBWLu*UcMrJY`UeA1~VR2xO(bM_+FMnw6nRvXe&316A)LTFKL}Y?d z)%xlukDttSVC?bQG98us*MvJ4_|HhXKIgEgDY1uN4$Qe-(<2y-}d8OW}Mh)be^4_YqnE?Rxtma!|pnP z|DQX|?yMjG;o{>jljIt0YYX+y3kvnmbOt7BY7o`v*FfFAPK~0dMt?I@t!FaS{vFj! zRoCg55d#QolF=Rq)6#ju(O?Mv9pX%AQF|)aIFpvp>toEv^v&xP6+I`qKS&oOM_m~< z>r~;%LZ(5e_M4Mpwev2f@2mKnBQsjeIqrfVLf48yojO6GdMSiL8MNPJp7&oolDXk^ zt#GGuDtR&dXTO{2rX$dTHP2EvW=4@;rhCfWz;vjP$oYqmh(~RS(gdDF%p0DP26qW@ zX&JC9@&ZHx zZcO!U*U_R1$2QOKlApP~a*yG;?YwEyOjoZycl&>I<}bXs_({bTn{mmy-pYt5w4H_%F8H_E{%y!N!=(V%1m}&aeAm>@IYgqbH=L=Gn;n>^;GuydCW=C7wwLPz@@L)&Js>JQuJ^DSr#-4vj@AjnSy{(G3XB?kc-8&}4@YJS=0iR9f-P+arx33_) z?Kl(0xmcI9yq|sM>nXG5?J-Wlra`iHpS+KCm08aFKI+~(G3V9!+EpLU2HMW(=JMt9 zU7L-q@poM0hnD%<8@CVFxiEN4h^Eam<n-8u?M4JB{#rkLonQ)b@wTjqf@Fbv1%zI+Tv6cF zjf$<}P~0O;=q1adLNB@O#wNgX&bZkyM+{Ay9k?CxKjmfY+!+A8mWt-x`e zx#YrxmFlNgRB5ECH*J_XYYKNq?_I*bFBVmK?cMY#u0Za7@b7?C@1t7dqueKLy7J(J zQ{Vh3_Y0%*4R*Yo5G!mxJLus)*D+fUbt^r{B~JHiFt=LeGt;q>6FvT0(+lZ>C5-fj zado3>mwb*IQgZ8E@$cE10~4pSS1K&4#_iD!`7=>urtM{BWj{V=;49aEG+wFgl4Mo{ z`Z%sU`rzi=hJGGNQqM~ZO~Ma}v!=ZE?6tW%xnaeweGXD>OCD$1!sDc6ZvKaUXJ7W4 z^>xyW-Kno1WuCKdGa6vC4%V<6#7`FVI@Vs>{n|D6ZZkxW**E(xJI4Ka9ZRYB>D$5{ zHsBFp>2(HA5K4V73NjIz`~Ue8Cs9mw_=5Y3kaP3pced0NE#!c_sM}8YG z9dv(X+oPahb<3z3I!-fc*S)Q{f7gBxgb7PNzg}Ns?`K|R__%$!TAEKuzSiXzV;ffJ z43|Hu)S5Esev`ccC%b7%<`C^a?gIGkivYpFGGrto@r8Jem$}IxIWL{b;s1#J#BUEM!8h8 zJ*_8hU;e>qUE)!#t+DrVHVhy+A9i1C&bOG*GOn<@O?{2kZ?1L^uZ?y!@d{wclXu_B zX5P;{Reo(?!V_EEznJ=s^u5^~1A zMM<9{;}n%|CoQdg6O*Es-@w>)z&X2md3=fe+_*D&i)W1dGMDpc@}CUHeW@E?%pPj@ zI3{*wjc%`=Y3u4|9IWr&GnlEFFWGLq&;3EZzrXWI^ASxV&wYtw_sM>HJHo@hkA2_W zA?pS&X@0wD-Y~a9W|*LmDWPJnSt{HAzu4ZG2EW=we~84&1(uz`ftH$^-VXtQ!0LM& zd$Jn`Hp?IGn|_YeJ~&O^vUzltpUc6vDesq`z-!5MzZtaD+DzFR)c7H7qK}|w7xqkD zH!Fdq08Zj8laqbl+^Nie;aeDgbVYZQy^)^D*T+#|o!b2eNoPmortceVa$311YSAOp zVd`78#zz zMT;#S8{9s4>=j`lx4oQqCOQwd!4cE$%njF9T`6@X_skE?(e(_Jw}_4w*RIOtSQ7EN1OPsc>b;K>e6|v yrhSdOozr3$$JF)vR%s)3KT=$@i0zW=b5HniD1Z8@yk(p40i%xfKBji9FZN$Urm)KZ delta 19905 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 Uc5kunx$lO(f8lPu>jT;U0^YzbjsO4v diff --git a/KProcessHacker/bin-signed/i386/kprocesshacker.sys b/KProcessHacker/bin-signed/i386/kprocesshacker.sys index 6771d7266b67b245778ed488935031d585c92f48..4f5372a8bd5b0e3530c2871c4dc771a9e4d6550d 100644 GIT binary patch delta 21033 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 literal 36376 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 Z5f6WBy*w?#JL%zwcX$1j^YQD<{{d(wt0w>e diff --git a/ProcessHacker/main.c b/ProcessHacker/main.c index 815ef58ee872..0923076ecf9a 100644 --- a/ProcessHacker/main.c +++ b/ProcessHacker/main.c @@ -557,19 +557,32 @@ VOID PhInitializeKph( ) { static PH_STRINGREF kprocesshacker = PH_STRINGREF_INIT(L"kprocesshacker.sys"); + static PH_STRINGREF processhackerSig = PH_STRINGREF_INIT(L"ProcessHacker.sig"); + PPH_STRING kprocesshackerFileName; + PPH_STRING processhackerSigFileName; KPH_PARAMETERS parameters; + PUCHAR signature; + ULONG signatureSize; if (WindowsVersion == WINDOWS_NEW) return; kprocesshackerFileName = PhConcatStringRef2(&PhApplicationDirectory->sr, &kprocesshacker); + processhackerSigFileName = PhConcatStringRef2(&PhApplicationDirectory->sr, &processhackerSig); parameters.SecurityLevel = KphSecurityPrivilegeCheck; parameters.CreateDynamicConfiguration = TRUE; KphConnect2Ex(KPH_DEVICE_SHORT_NAME, kprocesshackerFileName->Buffer, ¶meters); + if (signature = PhpReadSignature(processhackerSigFileName->Buffer, &signatureSize)) + { + KphVerifyClient(signature, signatureSize); + PhFree(signature); + } + PhDereferenceObject(kprocesshackerFileName); + PhDereferenceObject(processhackerSigFileName); } BOOLEAN PhInitializeAppSystem( @@ -971,7 +984,7 @@ VOID PhpProcessStartupParameters( kprocesshackerFileName = PhConcatStrings2(PhApplicationDirectory->Buffer, L"\\kprocesshacker.sys"); - parameters.SecurityLevel = KphSecurityPrivilegeCheck; + parameters.SecurityLevel = KphSecuritySignatureCheck; parameters.CreateDynamicConfiguration = TRUE; status = KphInstallEx(KPH_DEVICE_SHORT_NAME, kprocesshackerFileName->Buffer, ¶meters); diff --git a/phlib/include/kphapi.h b/phlib/include/kphapi.h index 533fad2d78e8..f905de9a09d3 100644 --- a/phlib/include/kphapi.h +++ b/phlib/include/kphapi.h @@ -124,6 +124,8 @@ typedef enum _KPH_SECURITY_LEVEL { KphSecurityNone = 0, // all clients are allowed KphSecurityPrivilegeCheck = 1, // require SeDebugPrivilege + KphSecuritySignatureCheck = 2, // require trusted signature + KphSecuritySignatureAndPrivilegeCheck = 3, // require trusted signature and SeDebugPrivilege KphMaxSecurityLevel } KPH_SECURITY_LEVEL, *PKPH_SECURITY_LEVEL; @@ -133,7 +135,7 @@ typedef struct _KPH_DYN_STRUCT_DATA SHORT EpObjectTable; SHORT Reserved0; SHORT Reserved1; - SHORT EpRundownProtect; + SHORT Reserved2; SHORT EreGuidEntry; SHORT HtHandleContentionEvent; SHORT OtName; @@ -152,7 +154,7 @@ typedef struct _KPH_DYN_PACKAGE KPH_DYN_STRUCT_DATA StructData; } KPH_DYN_PACKAGE, *PKPH_DYN_PACKAGE; -#define KPH_DYN_CONFIGURATION_VERSION 2 +#define KPH_DYN_CONFIGURATION_VERSION 3 #define KPH_DYN_MAXIMUM_PACKAGES 64 typedef struct _KPH_DYN_CONFIGURATION @@ -162,6 +164,33 @@ typedef struct _KPH_DYN_CONFIGURATION KPH_DYN_PACKAGE Packages[1]; } KPH_DYN_CONFIGURATION, *PKPH_DYN_CONFIGURATION; +// Verification + +#ifdef __BCRYPT_H__ +#define KPH_SIGN_ALGORITHM BCRYPT_ECDSA_P256_ALGORITHM +#define KPH_SIGN_ALGORITHM_BITS 256 +#define KPH_HASH_ALGORITHM BCRYPT_SHA256_ALGORITHM +#define KPH_BLOB_PUBLIC BCRYPT_ECCPUBLIC_BLOB +#endif + +#define KPH_SIGNATURE_MAX_SIZE (128 * 1024) // 128 kB + +typedef ULONG KPH_KEY, *PKPH_KEY; + +typedef enum _KPH_KEY_LEVEL +{ + KphKeyLevel1 = 1, + KphKeyLevel2 = 2 +} KPH_KEY_LEVEL; + +#define KPH_KEY_BACKOFF_TIME ((LONGLONG)(100 * 1000 * 10)) // 100ms + +#define KPH_PROCESS_READ_ACCESS (STANDARD_RIGHTS_READ | SYNCHRONIZE | PROCESS_QUERY_INFORMATION | \ + PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_VM_READ) +#define KPH_THREAD_READ_ACCESS (STANDARD_RIGHTS_READ | SYNCHRONIZE | THREAD_QUERY_INFORMATION | \ + THREAD_QUERY_LIMITED_INFORMATION | THREAD_GET_CONTEXT) +#define KPH_TOKEN_READ_ACCESS TOKEN_READ + // Features // No features defined. @@ -172,24 +201,26 @@ typedef struct _KPH_DYN_CONFIGURATION // General #define KPH_GETFEATURES KPH_CTL_CODE(0) +#define KPH_VERIFYCLIENT KPH_CTL_CODE(1) +#define KPH_RETRIEVEKEY KPH_CTL_CODE(2) // User-mode only // Processes -#define KPH_OPENPROCESS KPH_CTL_CODE(50) -#define KPH_OPENPROCESSTOKEN KPH_CTL_CODE(51) +#define KPH_OPENPROCESS KPH_CTL_CODE(50) // L1/L2 protected API +#define KPH_OPENPROCESSTOKEN KPH_CTL_CODE(51) // L1/L2 protected API #define KPH_OPENPROCESSJOB KPH_CTL_CODE(52) -#define KPH_SUSPENDPROCESS KPH_CTL_CODE(53) -#define KPH_RESUMEPROCESS KPH_CTL_CODE(54) -#define KPH_TERMINATEPROCESS KPH_CTL_CODE(55) +#define KPH_RESERVED53 KPH_CTL_CODE(53) +#define KPH_RESERVED54 KPH_CTL_CODE(54) +#define KPH_TERMINATEPROCESS KPH_CTL_CODE(55) // L2 protected API #define KPH_RESERVED56 KPH_CTL_CODE(56) #define KPH_RESERVED57 KPH_CTL_CODE(57) -#define KPH_READVIRTUALMEMORYUNSAFE KPH_CTL_CODE(58) +#define KPH_READVIRTUALMEMORYUNSAFE KPH_CTL_CODE(58) // L2 protected API #define KPH_QUERYINFORMATIONPROCESS KPH_CTL_CODE(59) #define KPH_SETINFORMATIONPROCESS KPH_CTL_CODE(60) // Threads -#define KPH_OPENTHREAD KPH_CTL_CODE(100) +#define KPH_OPENTHREAD KPH_CTL_CODE(100) // L1/L2 protected API #define KPH_OPENTHREADPROCESS KPH_CTL_CODE(101) -#define KPH_TERMINATETHREAD KPH_CTL_CODE(102) +#define KPH_RESERVED102 KPH_CTL_CODE(102) #define KPH_RESERVED103 KPH_CTL_CODE(103) #define KPH_RESERVED104 KPH_CTL_CODE(104) #define KPH_RESERVED105 KPH_CTL_CODE(105) @@ -201,7 +232,7 @@ typedef struct _KPH_DYN_CONFIGURATION #define KPH_ENUMERATEPROCESSHANDLES KPH_CTL_CODE(150) #define KPH_QUERYINFORMATIONOBJECT KPH_CTL_CODE(151) #define KPH_SETINFORMATIONOBJECT KPH_CTL_CODE(152) -#define KPH_DUPLICATEOBJECT KPH_CTL_CODE(153) +#define KPH_RESERVED153 KPH_CTL_CODE(153) // Misc. #define KPH_OPENDRIVER KPH_CTL_CODE(200) diff --git a/phlib/include/kphuser.h b/phlib/include/kphuser.h index 72eb102ed481..102534b55a62 100644 --- a/phlib/include/kphuser.h +++ b/phlib/include/kphuser.h @@ -51,6 +51,13 @@ KphIsConnected( VOID ); +PHLIBAPI +BOOLEAN +NTAPI +KphIsVerified( + VOID + ); + PHLIBAPI NTSTATUS NTAPI @@ -90,6 +97,14 @@ KphGetFeatures( _Out_ PULONG Features ); +PHLIBAPI +NTSTATUS +NTAPI +KphVerifyClient( + _In_reads_bytes_(SignatureSize) PUCHAR Signature, + _In_ ULONG SignatureSize + ); + PHLIBAPI NTSTATUS NTAPI @@ -254,6 +269,7 @@ NTSTATUS NTAPI KphOpenDriver( _Out_ PHANDLE DriverHandle, + _In_ ACCESS_MASK DesiredAccess, _In_ POBJECT_ATTRIBUTES ObjectAttributes ); diff --git a/phlib/kph.c b/phlib/kph.c index 71bf12115977..0acd7d0baa27 100644 --- a/phlib/kph.c +++ b/phlib/kph.c @@ -22,8 +22,11 @@ #include #include +#include HANDLE PhKphHandle = NULL; +BOOLEAN PhKphVerified; +KPH_KEY PhKphL1Key; NTSTATUS KphConnect( _In_opt_ PWSTR DeviceName @@ -76,6 +79,8 @@ NTSTATUS KphConnect( ); PhKphHandle = kphHandle; + PhKphVerified = FALSE; + PhKphL1Key = 0; } return status; @@ -240,6 +245,8 @@ NTSTATUS KphDisconnect( status = NtClose(PhKphHandle); PhKphHandle = NULL; + PhKphVerified = FALSE; + PhKphL1Key = 0; return status; } @@ -251,42 +258,52 @@ BOOLEAN KphIsConnected( return PhKphHandle != NULL; } +BOOLEAN KphIsVerified( + VOID + ) +{ + return PhKphVerified; +} + NTSTATUS KphSetParameters( _In_opt_ PWSTR DeviceName, _In_ PKPH_PARAMETERS Parameters ) { - static PH_STRINGREF keyName = PH_STRINGREF_INIT(L"System\\CurrentControlSet\\Services\\KProcessHacker3\\Parameters"); NTSTATUS status; HANDLE parametersKeyHandle = NULL; + PPH_STRING parametersKeyName; ULONG disposition; UNICODE_STRING valueName; - if (!NT_SUCCESS(status = PhCreateKey( + if (!DeviceName) + DeviceName = KPH_DEVICE_SHORT_NAME; + + parametersKeyName = PhConcatStrings( + 3, + L"System\\CurrentControlSet\\Services\\", + DeviceName, + L"\\Parameters" + ); + status = PhCreateKey( ¶metersKeyHandle, KEY_WRITE | DELETE, PH_KEY_LOCAL_MACHINE, - &keyName, + ¶metersKeyName->sr, 0, 0, &disposition - ))) - { + ); + PhDereferenceObject(parametersKeyName); + + if (!NT_SUCCESS(status)) return status; - } RtlInitUnicodeString(&valueName, L"SecurityLevel"); - if (!NT_SUCCESS(status = NtSetValueKey( - parametersKeyHandle, - &valueName, - 0, - REG_DWORD, - &Parameters->SecurityLevel, - sizeof(ULONG) - ))) - { + status = NtSetValueKey(parametersKeyHandle, &valueName, 0, REG_DWORD, &Parameters->SecurityLevel, sizeof(ULONG)); + + if (!NT_SUCCESS(status)) goto SetValuesEnd; - } if (Parameters->CreateDynamicConfiguration) { @@ -299,14 +316,10 @@ NTSTATUS KphSetParameters( if (NT_SUCCESS(KphInitializeDynamicPackage(&configuration.Packages[0]))) { - status = NtSetValueKey( - parametersKeyHandle, - &valueName, - 0, - REG_BINARY, - &configuration, - sizeof(KPH_DYN_CONFIGURATION) - ); + status = NtSetValueKey(parametersKeyHandle, &valueName, 0, REG_BINARY, &configuration, sizeof(KPH_DYN_CONFIGURATION)); + + if (!NT_SUCCESS(status)) + goto SetValuesEnd; } } @@ -436,28 +449,6 @@ NTSTATUS KphUninstall( return status; } -NTSTATUS KphpDeviceIoControl( - _In_ ULONG KphControlCode, - _In_ PVOID InBuffer, - _In_ ULONG InBufferLength - ) -{ - IO_STATUS_BLOCK isb; - - return NtDeviceIoControlFile( - PhKphHandle, - NULL, - NULL, - NULL, - &isb, - KphControlCode, - InBuffer, - InBufferLength, - NULL, - 0 - ); -} - NTSTATUS KphGetFeatures( _Out_ PULONG Features ) @@ -474,24 +465,52 @@ NTSTATUS KphGetFeatures( ); } -NTSTATUS KphOpenProcess( - _Out_ PHANDLE ProcessHandle, - _In_ ACCESS_MASK DesiredAccess, - _In_ PCLIENT_ID ClientId +NTSTATUS KphVerifyClient( + _In_reads_bytes_(SignatureSize) PUCHAR Signature, + _In_ ULONG SignatureSize ) { + NTSTATUS status; struct { - PHANDLE ProcessHandle; - ACCESS_MASK DesiredAccess; - PCLIENT_ID ClientId; - } input = { ProcessHandle, DesiredAccess, ClientId }; + PVOID CodeAddress; + PUCHAR Signature; + ULONG SignatureSize; + } input = { KphpWithKeyApcRoutine, Signature, SignatureSize }; - return KphpDeviceIoControl( - KPH_OPENPROCESS, + status = KphpDeviceIoControl( + KPH_VERIFYCLIENT, &input, sizeof(input) ); + + if (NT_SUCCESS(status)) + PhKphVerified = TRUE; + + return status; +} + +NTSTATUS KphOpenProcess( + _Out_ PHANDLE ProcessHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ PCLIENT_ID ClientId + ) +{ + KPH_OPEN_PROCESS_INPUT input = { ProcessHandle, DesiredAccess, ClientId, 0 }; + + if ((DesiredAccess & KPH_PROCESS_READ_ACCESS) == DesiredAccess) + { + KphpGetL1Key(&input.Key); + return KphpDeviceIoControl( + KPH_OPENPROCESS, + &input, + sizeof(input) + ); + } + else + { + return KphpWithKey(KphKeyLevel2, KphpOpenProcessContinuation, &input); + } } NTSTATUS KphOpenProcessToken( @@ -500,18 +519,21 @@ NTSTATUS KphOpenProcessToken( _Out_ PHANDLE TokenHandle ) { - struct - { - HANDLE ProcessHandle; - ACCESS_MASK DesiredAccess; - PHANDLE TokenHandle; - } input = { ProcessHandle, DesiredAccess, TokenHandle }; + KPH_OPEN_PROCESS_TOKEN_INPUT input = { ProcessHandle, DesiredAccess, TokenHandle, 0 }; - return KphpDeviceIoControl( - KPH_OPENPROCESSTOKEN, - &input, - sizeof(input) - ); + if ((DesiredAccess & KPH_TOKEN_READ_ACCESS) == DesiredAccess) + { + KphpGetL1Key(&input.Key); + return KphpDeviceIoControl( + KPH_OPENPROCESSTOKEN, + &input, + sizeof(input) + ); + } + else + { + return KphpWithKey(KphKeyLevel2, KphpOpenProcessTokenContinuation, &input); + } } NTSTATUS KphOpenProcessJob( @@ -540,20 +562,11 @@ NTSTATUS KphTerminateProcess( ) { NTSTATUS status; - struct - { - HANDLE ProcessHandle; - NTSTATUS ExitStatus; - } input = { ProcessHandle, ExitStatus }; + KPH_TERMINATE_PROCESS_INPUT input = { ProcessHandle, ExitStatus, 0 }; - status = KphpDeviceIoControl( - KPH_TERMINATEPROCESS, - &input, - sizeof(input) - ); + status = KphpWithKey(KphKeyLevel2, KphpTerminateProcessContinuation, &input); - // Check if we're trying to terminate the current process, - // because kernel-mode can't do it. + // Check if we're trying to terminate the current process, because kernel-mode can't do it. if (status == STATUS_CANT_TERMINATE_SELF) { RtlExitUserProcess(ExitStatus); @@ -570,20 +583,9 @@ NTSTATUS KphReadVirtualMemoryUnsafe( _Out_opt_ PSIZE_T NumberOfBytesRead ) { - struct - { - HANDLE ProcessHandle; - PVOID BaseAddress; - PVOID Buffer; - SIZE_T BufferSize; - PSIZE_T NumberOfBytesRead; - } input = { ProcessHandle, BaseAddress, Buffer, BufferSize, NumberOfBytesRead }; + KPH_READ_VIRTUAL_MEMORY_UNSAFE_INPUT input = { ProcessHandle, BaseAddress, Buffer, BufferSize, NumberOfBytesRead, 0 }; - return KphpDeviceIoControl( - KPH_READVIRTUALMEMORYUNSAFE, - &input, - sizeof(input) - ); + return KphpWithKey(KphKeyLevel2, KphpReadVirtualMemoryUnsafeContinuation, &input); } NTSTATUS KphQueryInformationProcess( @@ -638,18 +640,21 @@ NTSTATUS KphOpenThread( _In_ PCLIENT_ID ClientId ) { - struct - { - PHANDLE ThreadHandle; - ACCESS_MASK DesiredAccess; - PCLIENT_ID ClientId; - } input = { ThreadHandle, DesiredAccess, ClientId }; + KPH_OPEN_THREAD_INPUT input = { ThreadHandle, DesiredAccess, ClientId, 0 }; - return KphpDeviceIoControl( - KPH_OPENTHREAD, - &input, - sizeof(input) - ); + if ((DesiredAccess & KPH_THREAD_READ_ACCESS) == DesiredAccess) + { + KphpGetL1Key(&input.Key); + return KphpDeviceIoControl( + KPH_OPENTHREAD, + &input, + sizeof(input) + ); + } + else + { + return KphpWithKey(KphKeyLevel2, KphpOpenThreadContinuation, &input); + } } NTSTATUS KphOpenThreadProcess( @@ -860,14 +865,16 @@ NTSTATUS KphSetInformationObject( NTSTATUS KphOpenDriver( _Out_ PHANDLE DriverHandle, + _In_ ACCESS_MASK DesiredAccess, _In_ POBJECT_ATTRIBUTES ObjectAttributes ) { struct { PHANDLE DriverHandle; + ACCESS_MASK DesiredAccess; POBJECT_ATTRIBUTES ObjectAttributes; - } input = { DriverHandle, ObjectAttributes }; + } input = { DriverHandle, DesiredAccess, ObjectAttributes }; return KphpDeviceIoControl( KPH_OPENDRIVER, @@ -898,4 +905,198 @@ NTSTATUS KphQueryInformationDriver( &input, sizeof(input) ); -} \ No newline at end of file +} + +NTSTATUS KphpDeviceIoControl( + _In_ ULONG KphControlCode, + _In_ PVOID InBuffer, + _In_ ULONG InBufferLength + ) +{ + IO_STATUS_BLOCK iosb; + + return NtDeviceIoControlFile( + PhKphHandle, + NULL, + NULL, + NULL, + &iosb, + KphControlCode, + InBuffer, + InBufferLength, + NULL, + 0 + ); +} + +VOID KphpWithKeyApcRoutine( + _In_ PVOID ApcContext, + _In_ PIO_STATUS_BLOCK IoStatusBlock, + _In_ ULONG Reserved + ) +{ + PKPHP_RETRIEVE_KEY_CONTEXT context = CONTAINING_RECORD(IoStatusBlock, KPHP_RETRIEVE_KEY_CONTEXT, Iosb); + KPH_KEY key = PtrToUlong(ApcContext); + + if (context->Continuation != KphpGetL1KeyContinuation && + context->Continuation != KphpOpenProcessContinuation && + context->Continuation != KphpOpenProcessTokenContinuation && + context->Continuation != KphpTerminateProcessContinuation && + context->Continuation != KphpReadVirtualMemoryUnsafeContinuation && + context->Continuation != KphpOpenThreadContinuation) + { + PhRaiseStatus(STATUS_ACCESS_DENIED); + context->Status = STATUS_ACCESS_DENIED; + return; + } + + context->Status = context->Continuation(key, context->Context); +} + +NTSTATUS KphpWithKey( + _In_ KPH_KEY_LEVEL KeyLevel, + _In_ PKPHP_WITH_KEY_CONTINUATION Continuation, + _In_ PVOID Context + ) +{ + NTSTATUS status; + struct + { + KPH_KEY_LEVEL KeyLevel; + } input = { KeyLevel }; + KPHP_RETRIEVE_KEY_CONTEXT context; + + context.Continuation = Continuation; + context.Context = Context; + context.Status = STATUS_UNSUCCESSFUL; + + status = NtDeviceIoControlFile( + PhKphHandle, + NULL, + KphpWithKeyApcRoutine, + NULL, + &context.Iosb, + KPH_RETRIEVEKEY, + &input, + sizeof(input), + NULL, + 0 + ); + + NtTestAlert(); + + if (!NT_SUCCESS(status)) + return status; + + return context.Status; +} + +NTSTATUS KphpGetL1KeyContinuation( + _In_ KPH_KEY Key, + _In_ PVOID Context + ) +{ + PKPHP_GET_L1_KEY_CONTEXT context = Context; + + *context->Key = Key; + PhKphL1Key = Key; + + return STATUS_SUCCESS; +} + +NTSTATUS KphpGetL1Key( + _Out_ PKPH_KEY Key + ) +{ + KPHP_GET_L1_KEY_CONTEXT context; + + if (PhKphL1Key) + { + *Key = PhKphL1Key; + return STATUS_SUCCESS; + } + + context.Key = Key; + + return KphpWithKey(KphKeyLevel1, KphpGetL1KeyContinuation, &context); +} + +NTSTATUS KphpOpenProcessContinuation( + _In_ KPH_KEY Key, + _In_ PVOID Context + ) +{ + PKPH_OPEN_PROCESS_INPUT input = Context; + + input->Key = Key; + + return KphpDeviceIoControl( + KPH_OPENPROCESS, + input, + sizeof(*input) + ); +} + +NTSTATUS KphpOpenProcessTokenContinuation( + _In_ KPH_KEY Key, + _In_ PVOID Context + ) +{ + PKPH_OPEN_PROCESS_TOKEN_INPUT input = Context; + + input->Key = Key; + + return KphpDeviceIoControl( + KPH_OPENPROCESSTOKEN, + input, + sizeof(*input) + ); +} + +NTSTATUS KphpTerminateProcessContinuation( + _In_ KPH_KEY Key, + _In_ PVOID Context + ) +{ + PKPH_TERMINATE_PROCESS_INPUT input = Context; + + input->Key = Key; + + return KphpDeviceIoControl( + KPH_TERMINATEPROCESS, + input, + sizeof(*input) + ); +} + +NTSTATUS KphpReadVirtualMemoryUnsafeContinuation( + _In_ KPH_KEY Key, + _In_ PVOID Context + ) +{ + PKPH_READ_VIRTUAL_MEMORY_UNSAFE_INPUT input = Context; + + input->Key = Key; + + return KphpDeviceIoControl( + KPH_READVIRTUALMEMORYUNSAFE, + input, + sizeof(*input) + ); +} + +NTSTATUS KphpOpenThreadContinuation( + _In_ KPH_KEY Key, + _In_ PVOID Context + ) +{ + PKPH_OPEN_PROCESS_INPUT input = Context; + + input->Key = Key; + + return KphpDeviceIoControl( + KPH_OPENTHREAD, + input, + sizeof(*input) + ); +} diff --git a/phlib/native.c b/phlib/native.c index 9366ab375b56..0a6acd15f6b1 100644 --- a/phlib/native.c +++ b/phlib/native.c @@ -113,15 +113,16 @@ NTSTATUS PhOpenProcess( _In_ HANDLE ProcessId ) { + NTSTATUS status; OBJECT_ATTRIBUTES objectAttributes; CLIENT_ID clientId; clientId.UniqueProcess = ProcessId; clientId.UniqueThread = NULL; - if (KphIsConnected()) + if (KphIsVerified() && (DesiredAccess & KPH_PROCESS_READ_ACCESS) == DesiredAccess) { - return KphOpenProcess( + status = KphOpenProcess( ProcessHandle, DesiredAccess, &clientId @@ -130,14 +131,24 @@ NTSTATUS PhOpenProcess( else { InitializeObjectAttributes(&objectAttributes, NULL, 0, NULL, NULL); - - return NtOpenProcess( + status = NtOpenProcess( ProcessHandle, DesiredAccess, &objectAttributes, &clientId ); + + if (status == STATUS_ACCESS_DENIED && KphIsVerified()) + { + status = KphOpenProcess( + ProcessHandle, + DesiredAccess, + &clientId + ); + } } + + return status; } /** Limited API for untrusted/external code. */ @@ -175,15 +186,16 @@ NTSTATUS PhOpenThread( _In_ HANDLE ThreadId ) { + NTSTATUS status; OBJECT_ATTRIBUTES objectAttributes; CLIENT_ID clientId; clientId.UniqueProcess = NULL; clientId.UniqueThread = ThreadId; - if (KphIsConnected()) + if (KphIsVerified() && (DesiredAccess & KPH_THREAD_READ_ACCESS) == DesiredAccess) { - return KphOpenThread( + status = KphOpenThread( ThreadHandle, DesiredAccess, &clientId @@ -192,14 +204,24 @@ NTSTATUS PhOpenThread( else { InitializeObjectAttributes(&objectAttributes, NULL, 0, NULL, NULL); - - return NtOpenThread( + status = NtOpenThread( ThreadHandle, DesiredAccess, &objectAttributes, &clientId ); + + if (status == STATUS_ACCESS_DENIED && KphIsVerified()) + { + status = KphOpenThread( + ThreadHandle, + DesiredAccess, + &clientId + ); + } } + + return status; } /** Limited API for untrusted/external code. */ @@ -271,9 +293,11 @@ NTSTATUS PhOpenProcessToken( _Out_ PHANDLE TokenHandle ) { - if (KphIsConnected()) + NTSTATUS status; + + if (KphIsVerified() && (DesiredAccess & KPH_TOKEN_READ_ACCESS) == DesiredAccess) { - return KphOpenProcessToken( + status = KphOpenProcessToken( ProcessHandle, DesiredAccess, TokenHandle @@ -281,12 +305,23 @@ NTSTATUS PhOpenProcessToken( } else { - return NtOpenProcessToken( + status = NtOpenProcessToken( ProcessHandle, DesiredAccess, TokenHandle ); + + if (status == STATUS_ACCESS_DENIED && KphIsVerified()) + { + status = KphOpenProcessToken( + ProcessHandle, + DesiredAccess, + TokenHandle + ); + } } + + return status; } NTSTATUS PhGetObjectSecurity( @@ -365,7 +400,7 @@ NTSTATUS PhTerminateProcess( { NTSTATUS status; - if (KphIsConnected()) + if (KphIsVerified()) { status = KphTerminateProcess( ProcessHandle, @@ -2484,7 +2519,7 @@ BOOLEAN NTAPI PhpOpenDriverByBaseAddressCallback( NULL ); - status = KphOpenDriver(&driverHandle, &objectAttributes); + status = KphOpenDriver(&driverHandle, SYNCHRONIZE, &objectAttributes); PhDereferenceObject(driverName); if (!NT_SUCCESS(status)) diff --git a/phlib/phlib.vcxproj b/phlib/phlib.vcxproj index 042c17ad6cc6..e395b2239ea8 100644 --- a/phlib/phlib.vcxproj +++ b/phlib/phlib.vcxproj @@ -1,4 +1,4 @@ - + @@ -202,6 +202,7 @@ + diff --git a/phlib/phlib.vcxproj.filters b/phlib/phlib.vcxproj.filters index cfd2a295a596..dee92e1b386b 100644 --- a/phlib/phlib.vcxproj.filters +++ b/phlib/phlib.vcxproj.filters @@ -346,6 +346,9 @@ Header Files + + Header Files + Header Files From 292847078a9842666632ff3b6ea19b39317a7090 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 9 Jul 2017 03:45:43 +1000 Subject: [PATCH 0264/2058] Update PCRE to v10.23 --- ProcessHacker/pcre/config.h | 168 +- ProcessHacker/pcre/pcre2.h | 482 +- ProcessHacker/pcre/pcre2_auto_possess.c | 18 +- ProcessHacker/pcre/pcre2_compile.c | 12884 +++++++++++----------- ProcessHacker/pcre/pcre2_dfa_match.c | 21 +- ProcessHacker/pcre/pcre2_error.c | 28 +- ProcessHacker/pcre/pcre2_find_bracket.c | 4 +- ProcessHacker/pcre/pcre2_internal.h | 34 +- ProcessHacker/pcre/pcre2_intmodedep.h | 38 +- ProcessHacker/pcre/pcre2_jit_compile.c | 1 + ProcessHacker/pcre/pcre2_maketables.c | 1 + ProcessHacker/pcre/pcre2_match.c | 80 +- ProcessHacker/pcre/pcre2_match_data.c | 1 + ProcessHacker/pcre/pcre2_newline.c | 1 + ProcessHacker/pcre/pcre2_ord2utf.c | 6 +- ProcessHacker/pcre/pcre2_pattern_info.c | 2 + ProcessHacker/pcre/pcre2_printint.c | 4 +- ProcessHacker/pcre/pcre2_serialize.c | 1 + ProcessHacker/pcre/pcre2_string_utils.c | 1 + ProcessHacker/pcre/pcre2_study.c | 157 +- ProcessHacker/pcre/pcre2_substitute.c | 15 +- ProcessHacker/pcre/pcre2_tables.c | 2 +- ProcessHacker/pcre/pcre2_ucp.h | 6 +- ProcessHacker/pcre/pcre2_valid_utf.c | 8 +- ProcessHacker/pcre/pcre2_xclass.c | 1 + ProcessHacker/pcre/pcre2posix.c | 14 +- ProcessHacker/pcre/pcre2posix.h | 2 +- 27 files changed, 7288 insertions(+), 6692 deletions(-) diff --git a/ProcessHacker/pcre/config.h b/ProcessHacker/pcre/config.h index 566feb63c5ed..b71d730d3561 100644 --- a/ProcessHacker/pcre/config.h +++ b/ProcessHacker/pcre/config.h @@ -1,6 +1,6 @@ -/* src/config.h. Generated from config.h.in by configure. */ /* src/config.h.in. Generated from configure.ac by autoheader. */ + /* PCRE2 is written in Standard C, but there are a few non-standard things it can cope with, allowing it to run on SunOS4 and other "close to standard" systems. @@ -33,7 +33,7 @@ sure both macros are undefined; an emulation function will then be used. */ value), this is changed so that backslash-R matches only CR, LF, or CRLF. The build-time default can be overridden by the user of PCRE2 at runtime. */ -/* #undef BSR_ANYCRLF */ +#undef BSR_ANYCRLF /* If you are compiling for a system that uses EBCDIC instead of ASCII character codes, define this macro to any value. When EBCDIC is set, PCRE2 @@ -41,30 +41,30 @@ sure both macros are undefined; an emulation function will then be used. */ macro, PCRE2 will assume input strings are ASCII or UTF-8/16/32 Unicode. It is not possible to build a version of PCRE2 that supports both EBCDIC and UTF-8/16/32. */ -/* #undef EBCDIC */ +#undef EBCDIC /* In an EBCDIC environment, define this macro to any value to arrange for the NL character to be 0x25 instead of the default 0x15. NL plays the role that LF does in an ASCII/Unicode environment. */ -/* #undef EBCDIC_NL25 */ +#undef EBCDIC_NL25 /* Define to 1 if you have the `bcopy' function. */ -/* #undef HAVE_BCOPY */ +#undef HAVE_BCOPY /* Define to 1 if you have the header file. */ -/* #undef HAVE_BZLIB_H */ +#undef HAVE_BZLIB_H /* Define to 1 if you have the header file. */ -/* #undef HAVE_DIRENT_H */ +#undef HAVE_DIRENT_H /* Define to 1 if you have the header file. */ -/* #undef HAVE_DLFCN_H */ +#undef HAVE_DLFCN_H /* Define to 1 if you have the header file. */ -/* #undef HAVE_EDITLINE_READLINE_H */ +#undef HAVE_EDITLINE_READLINE_H /* Define to 1 if you have the header file. */ -/* #undef HAVE_EDIT_READLINE_READLINE_H */ +#undef HAVE_EDIT_READLINE_READLINE_H /* Define to 1 if you have the header file. */ #ifndef HAVE_INTTYPES_H @@ -86,17 +86,23 @@ sure both macros are undefined; an emulation function will then be used. */ #define HAVE_MEMORY_H 1 #endif +/* Define to 1 if you have the `mkostemp' function. */ +#undef HAVE_MKOSTEMP + /* Define if you have POSIX threads libraries and header files. */ -/* #undef HAVE_PTHREAD */ +#undef HAVE_PTHREAD /* Have PTHREAD_PRIO_INHERIT. */ -/* #undef HAVE_PTHREAD_PRIO_INHERIT */ +#undef HAVE_PTHREAD_PRIO_INHERIT /* Define to 1 if you have the header file. */ -/* #undef HAVE_READLINE_HISTORY_H */ +#undef HAVE_READLINE_HISTORY_H /* Define to 1 if you have the header file. */ -/* #undef HAVE_READLINE_READLINE_H */ +#undef HAVE_READLINE_READLINE_H + +/* Define to 1 if you have the `secure_getenv' function. */ +#undef HAVE_SECURE_GETENV /* Define to 1 if you have the header file. */ #ifndef HAVE_STDINT_H @@ -113,9 +119,8 @@ sure both macros are undefined; an emulation function will then be used. */ #define HAVE_STRERROR 1 #endif - /* Define to 1 if you have the header file. */ -/* #undef HAVE_STRINGS_H */ +#undef HAVE_STRINGS_H /* Define to 1 if you have the header file. */ #ifndef HAVE_STRING_H @@ -133,13 +138,13 @@ sure both macros are undefined; an emulation function will then be used. */ #endif /* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_WAIT_H */ +#undef HAVE_SYS_WAIT_H /* Define to 1 if you have the header file. */ -/* #undef HAVE_UNISTD_H */ +#undef HAVE_UNISTD_H /* Define to 1 if the compiler supports simple visibility declarations. */ -/* #undef HAVE_VISIBILITY */ +#undef HAVE_VISIBILITY /* Define to 1 if you have the header file. */ #ifndef HAVE_WINDOWS_H @@ -147,7 +152,7 @@ sure both macros are undefined; an emulation function will then be used. */ #endif /* Define to 1 if you have the header file. */ -/* #undef HAVE_ZLIB_H */ +#undef HAVE_ZLIB_H /* PCRE2 uses recursive function calls to handle backtracking while matching. This can sometimes be a problem on systems that have stacks of limited @@ -155,7 +160,7 @@ sure both macros are undefined; an emulation function will then be used. */ use recursion in the match() function; instead it creates its own stack by steam using memory from the heap. For more detail, see the comments and other stuff just above the match() function. */ -/* #undef HEAP_MATCH_RECURSE */ +#undef HEAP_MATCH_RECURSE /* The value of LINK_SIZE determines the number of bytes used to store links as offsets within the compiled regex. The default is 2, which allows for @@ -167,10 +172,7 @@ sure both macros are undefined; an emulation function will then be used. */ #endif /* Define to the sub-directory where libtool stores uninstalled libraries. */ -/* This is ignored unless you are using libtool. */ -#ifndef LT_OBJDIR -#define LT_OBJDIR ".libs/" -#endif +#undef LT_OBJDIR /* The value of MATCH_LIMIT determines the default number of times the internal match() function can be called during a single execution of @@ -209,36 +211,36 @@ sure both macros are undefined; an emulation function will then be used. */ #endif /* Defining NEVER_BACKSLASH_C locks out the use of \C in all patterns. */ -/* #undef NEVER_BACKSLASH_C */ +#undef NEVER_BACKSLASH_C /* The value of NEWLINE_DEFAULT determines the default newline character sequence. PCRE2 client programs can override this by selecting other values at run time. The valid values are 1 (CR), 2 (LF), 3 (CRLF), 4 (ANY), and 5 (ANYCRLF). */ #ifndef NEWLINE_DEFAULT -#define NEWLINE_DEFAULT 2 +#define NEWLINE_DEFAULT 4 #endif /* Name of package */ -#define PACKAGE "pcre2" +#undef PACKAGE /* Define to the address where bug reports for this package should be sent. */ -#define PACKAGE_BUGREPORT "" +#undef PACKAGE_BUGREPORT /* Define to the full name of this package. */ -#define PACKAGE_NAME "PCRE2" +#undef PACKAGE_NAME /* Define to the full name and version of this package. */ -#define PACKAGE_STRING "PCRE2 10.22" +#undef PACKAGE_STRING /* Define to the one symbol short name of this package. */ -#define PACKAGE_TARNAME "pcre2" +#undef PACKAGE_TARNAME /* Define to the home page for this package. */ -#define PACKAGE_URL "" +#undef PACKAGE_URL /* Define to the version of this package. */ -#define PACKAGE_VERSION "10.22" +#undef PACKAGE_VERSION /* The value of PARENS_NEST_LIMIT specifies the maximum depth of nested parentheses (of any kind) in a pattern. This limits the amount of system @@ -247,17 +249,36 @@ sure both macros are undefined; an emulation function will then be used. */ #define PARENS_NEST_LIMIT 250 #endif -/* The value of PCRE2GREP_BUFSIZE determines the size of buffer used by - pcre2grep to hold parts of the file it is searching. This is also the - minimum value. The actual amount of memory used by pcre2grep is three times - this number, because it allows for the buffering of "before" and "after" - lines. */ +/* The value of PCRE2GREP_BUFSIZE is the starting size of the buffer used by + pcre2grep to hold parts of the file it is searching. The buffer will be + expanded up to PCRE2GREP_MAX_BUFSIZE if necessary, for files containing + very long lines. The actual amount of memory used by pcre2grep is three + times this number, because it allows for the buffering of "before" and + "after" lines. */ #ifndef PCRE2GREP_BUFSIZE #define PCRE2GREP_BUFSIZE 20480 #endif +/* The value of PCRE2GREP_MAX_BUFSIZE specifies the maximum size of the buffer + used by pcre2grep to hold parts of the file it is searching. The actual + amount of memory used by pcre2grep is three times this number, because it + allows for the buffering of "before" and "after" lines. */ +#ifndef PCRE2GREP_MAX_BUFSIZE +#define PCRE2GREP_MAX_BUFSIZE 1048576 +#endif + +/* to make a symbol visible */ +#undef PCRE2POSIX_EXP_DECL + +/* to make a symbol visible */ +#undef PCRE2POSIX_EXP_DEFN + /* Define to any value to include debugging code. */ -/* #undef PCRE2_DEBUG */ +#undef PCRE2_DEBUG + +/* to make a symbol visible */ +#undef PCRE2_EXP_DECL + /* If you are compiling for a system other than a Unix-like system or Win32, and it needs some magic to be inserted before the definition @@ -268,7 +289,7 @@ sure both macros are undefined; an emulation function will then be used. */ This macro apears at the start of every exported function that is part of the external API. It does not appear on functions that are "external" in the C sense, but which are internal to the library. */ -/* #undef PCRE2_EXP_DEFN */ +#undef PCRE2_EXP_DEFN /* Define to any value if linking statically (TODO: make nice with Libtool) */ #ifndef PCRE2_STATIC @@ -277,7 +298,7 @@ sure both macros are undefined; an emulation function will then be used. */ /* Define to necessary symbol if this constant uses a non-standard name on your system. */ -/* #undef PTHREAD_CREATE_JOINABLE */ +#undef PTHREAD_CREATE_JOINABLE /* Define to 1 if you have the ANSI C header files. */ #ifndef STDC_HEADERS @@ -285,27 +306,28 @@ sure both macros are undefined; an emulation function will then be used. */ #endif /* Define to any value to enable support for Just-In-Time compiling. */ -/* #undef SUPPORT_JIT */ +#undef SUPPORT_JIT /* Define to any value to allow pcre2grep to be linked with libbz2, so that it is able to handle .bz2 files. */ -/* #undef SUPPORT_LIBBZ2 */ +#undef SUPPORT_LIBBZ2 /* Define to any value to allow pcre2test to be linked with libedit. */ -/* #undef SUPPORT_LIBEDIT */ +#undef SUPPORT_LIBEDIT /* Define to any value to allow pcre2test to be linked with libreadline. */ -/* #undef SUPPORT_LIBREADLINE */ +#undef SUPPORT_LIBREADLINE /* Define to any value to allow pcre2grep to be linked with libz, so that it is able to handle .gz files. */ -/* #undef SUPPORT_LIBZ */ +#undef SUPPORT_LIBZ /* Define to any value to enable callout script support in pcre2grep. */ -/* #undef SUPPORT_PCRE2GREP_CALLOUT */ +#undef SUPPORT_PCRE2GREP_CALLOUT -/* Define to any value to enable JIT support in pcre2grep. */ -/* #undef SUPPORT_PCRE2GREP_JIT */ +/* Define to any value to enable JIT support in pcre2grep. Note that this will + have no effect unless SUPPORT_JIT is also defined. */ +#undef SUPPORT_PCRE2GREP_JIT /* Define to any value to enable the 16 bit PCRE2 library. */ #ifndef SUPPORT_PCRE2_16 @@ -313,10 +335,10 @@ sure both macros are undefined; an emulation function will then be used. */ #endif /* Define to any value to enable the 32 bit PCRE2 library. */ -/* #undef SUPPORT_PCRE2_32 */ +//#undef SUPPORT_PCRE2_32 /* Define to any value to enable the 8 bit PCRE2 library. */ -/* #undef SUPPORT_PCRE2_8 */ +//#undef SUPPORT_PCRE2_8 /* Define to any value to enable support for Unicode and UTF encoding. This will work even in an EBCDIC environment, but it is incompatible with the @@ -327,17 +349,49 @@ sure both macros are undefined; an emulation function will then be used. */ #endif /* Define to any value for valgrind support to find invalid memory reads. */ -/* #undef SUPPORT_VALGRIND */ +#undef SUPPORT_VALGRIND + +/* Enable extensions on AIX 3, Interix. */ +#ifndef _ALL_SOURCE +# undef _ALL_SOURCE +#endif +/* Enable GNU extensions on systems that have them. */ +#ifndef _GNU_SOURCE +# undef _GNU_SOURCE +#endif +/* Enable threading extensions on Solaris. */ +#ifndef _POSIX_PTHREAD_SEMANTICS +# undef _POSIX_PTHREAD_SEMANTICS +#endif +/* Enable extensions on HP NonStop. */ +#ifndef _TANDEM_SOURCE +# undef _TANDEM_SOURCE +#endif +/* Enable general extensions on Solaris. */ +#ifndef __EXTENSIONS__ +# undef __EXTENSIONS__ +#endif + /* Version number of package */ -#define VERSION "10.22" +#undef VERSION + +/* Define to 1 if on MINIX. */ +#undef _MINIX + +/* Define to 2 if the system does not provide POSIX.1 features except with + this defined. */ +#undef _POSIX_1_SOURCE + +/* Define to 1 if you need to in order for `stat' and other things to work. */ +#undef _POSIX_SOURCE /* Define to empty if `const' does not conform to ANSI C. */ -/* #undef const */ +#undef const /* Define to the type of a signed integer type of width exactly 64 bits if such a type exists and the standard includes do not define it. */ -/* #undef int64_t */ +#undef int64_t /* Define to `unsigned int' if does not define. */ -/* #undef size_t */ +#undef size_t diff --git a/ProcessHacker/pcre/pcre2.h b/ProcessHacker/pcre/pcre2.h index 757784e97254..550a2b93d81f 100644 --- a/ProcessHacker/pcre/pcre2.h +++ b/ProcessHacker/pcre/pcre2.h @@ -5,22 +5,22 @@ /* This is the public header file for the PCRE library, second API, to be #included by applications that call PCRE2 functions. - Copyright (c) 2016 University of Cambridge +Copyright (c) 2016 University of Cambridge ----------------------------------------------------------------------------- Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. +* Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. +* Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. - * Neither the name of the University of Cambridge nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. +* Neither the name of the University of Cambridge nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE @@ -35,10 +35,6 @@ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ----------------------------------------------------------------------------- */ - -#ifndef _PCRE2_H -#define _PCRE2_H - // dmex: This must match PCRE2_STATIC in config.h #define PCRE2_STATIC 1 @@ -46,12 +42,15 @@ POSSIBILITY OF SUCH DAMAGE. #undef PCRE2_CODE_UNIT_WIDTH #define PCRE2_CODE_UNIT_WIDTH 16 +#ifndef PCRE2_H_IDEMPOTENT_GUARD +#define PCRE2_H_IDEMPOTENT_GUARD + /* The current PCRE version information. */ #define PCRE2_MAJOR 10 -#define PCRE2_MINOR 22 +#define PCRE2_MINOR 23 #define PCRE2_PRERELEASE -#define PCRE2_DATE 2016-07-29 +#define PCRE2_DATE 2017-02-14 /* When an application links to a PCRE DLL in Windows, the symbols that are imported have to be identified as such. When building PCRE2, the appropriate @@ -74,6 +73,20 @@ don't change existing definitions of PCRE2_EXP_DECL. */ # endif #endif +/* When compiling with the MSVC compiler, it is sometimes necessary to include +a "calling convention" before exported function names. (This is secondhand +information; I know nothing about MSVC myself). For example, something like + +void __cdecl function(....) + +might be needed. In order so make this easy, all the exported functions have +PCRE2_CALL_CONVENTION just before their names. It is rarely needed; if not +set, we ensure here that it has no effect. */ + +#ifndef PCRE2_CALL_CONVENTION +#define PCRE2_CALL_CONVENTION +#endif + /* Have to include limits.h, stdlib.h and stdint.h to ensure that size_t and uint8_t, UCHAR_MAX, etc are defined. */ @@ -87,23 +100,23 @@ uint8_t, UCHAR_MAX, etc are defined. */ extern "C" { #endif -/* The following option bits can be passed to pcre2_compile(), pcre2_match(), -or pcre2_dfa_match(). PCRE2_NO_UTF_CHECK affects only the function to which it -is passed. Put these bits at the most significant end of the options word so -others can be added next to them */ + /* The following option bits can be passed to pcre2_compile(), pcre2_match(), + or pcre2_dfa_match(). PCRE2_NO_UTF_CHECK affects only the function to which it + is passed. Put these bits at the most significant end of the options word so + others can be added next to them */ #define PCRE2_ANCHORED 0x80000000u #define PCRE2_NO_UTF_CHECK 0x40000000u -/* The following option bits can be passed only to pcre2_compile(). However, -they may affect compilation, JIT compilation, and/or interpretive execution. -The following tags indicate which: + /* The following option bits can be passed only to pcre2_compile(). However, + they may affect compilation, JIT compilation, and/or interpretive execution. + The following tags indicate which: -C alters what is compiled by pcre2_compile() -J alters what is compiled by pcre2_jit_compile() -M is inspected during pcre2_match() execution -D is inspected during pcre2_dfa_match() execution -*/ + C alters what is compiled by pcre2_compile() + J alters what is compiled by pcre2_jit_compile() + M is inspected during pcre2_match() execution + D is inspected during pcre2_dfa_match() execution + */ #define PCRE2_ALLOW_EMPTY_CLASS 0x00000001u /* C */ #define PCRE2_ALT_BSUX 0x00000002u /* C */ @@ -130,16 +143,16 @@ D is inspected during pcre2_dfa_match() execution #define PCRE2_ALT_VERBNAMES 0x00400000u /* C */ #define PCRE2_USE_OFFSET_LIMIT 0x00800000u /* J M D */ -/* These are for pcre2_jit_compile(). */ + /* These are for pcre2_jit_compile(). */ #define PCRE2_JIT_COMPLETE 0x00000001u /* For full matching */ #define PCRE2_JIT_PARTIAL_SOFT 0x00000002u #define PCRE2_JIT_PARTIAL_HARD 0x00000004u -/* These are for pcre2_match(), pcre2_dfa_match(), and pcre2_jit_match(). Note -that PCRE2_ANCHORED and PCRE2_NO_UTF_CHECK can also be passed to these -functions (though pcre2_jit_match() ignores the latter since it bypasses all -sanity checks). */ + /* These are for pcre2_match(), pcre2_dfa_match(), and pcre2_jit_match(). Note + that PCRE2_ANCHORED and PCRE2_NO_UTF_CHECK can also be passed to these + functions (though pcre2_jit_match() ignores the latter since it bypasses all + sanity checks). */ #define PCRE2_NOTBOL 0x00000001u #define PCRE2_NOTEOL 0x00000002u @@ -148,13 +161,13 @@ sanity checks). */ #define PCRE2_PARTIAL_SOFT 0x00000010u #define PCRE2_PARTIAL_HARD 0x00000020u -/* These are additional options for pcre2_dfa_match(). */ + /* These are additional options for pcre2_dfa_match(). */ #define PCRE2_DFA_RESTART 0x00000040u #define PCRE2_DFA_SHORTEST 0x00000080u -/* These are additional options for pcre2_substitute(), which passes any others -through to pcre2_match(). */ + /* These are additional options for pcre2_substitute(), which passes any others + through to pcre2_match(). */ #define PCRE2_SUBSTITUTE_GLOBAL 0x00000100u #define PCRE2_SUBSTITUTE_EXTENDED 0x00000200u @@ -162,14 +175,14 @@ through to pcre2_match(). */ #define PCRE2_SUBSTITUTE_UNKNOWN_UNSET 0x00000800u #define PCRE2_SUBSTITUTE_OVERFLOW_LENGTH 0x00001000u -/* A further option for pcre2_match(), not allowed for pcre2_dfa_match(), -ignored for pcre2_jit_match(). */ + /* A further option for pcre2_match(), not allowed for pcre2_dfa_match(), + ignored for pcre2_jit_match(). */ #define PCRE2_NO_JIT 0x00002000u -/* Newline and \R settings, for use in compile contexts. The newline values -must be kept in step with values set in config.h and both sets must all be -greater than zero. */ + /* Newline and \R settings, for use in compile contexts. The newline values + must be kept in step with values set in config.h and both sets must all be + greater than zero. */ #define PCRE2_NEWLINE_CR 1 #define PCRE2_NEWLINE_LF 2 @@ -180,12 +193,12 @@ greater than zero. */ #define PCRE2_BSR_UNICODE 1 #define PCRE2_BSR_ANYCRLF 2 -/* Error codes: no match and partial match are "expected" errors. */ + /* Error codes: no match and partial match are "expected" errors. */ #define PCRE2_ERROR_NOMATCH (-1) #define PCRE2_ERROR_PARTIAL (-2) -/* Error codes for UTF-8 validity checks */ + /* Error codes for UTF-8 validity checks */ #define PCRE2_ERROR_UTF8_ERR1 (-3) #define PCRE2_ERROR_UTF8_ERR2 (-4) @@ -209,21 +222,21 @@ greater than zero. */ #define PCRE2_ERROR_UTF8_ERR20 (-22) #define PCRE2_ERROR_UTF8_ERR21 (-23) -/* Error codes for UTF-16 validity checks */ + /* Error codes for UTF-16 validity checks */ #define PCRE2_ERROR_UTF16_ERR1 (-24) #define PCRE2_ERROR_UTF16_ERR2 (-25) #define PCRE2_ERROR_UTF16_ERR3 (-26) -/* Error codes for UTF-32 validity checks */ + /* Error codes for UTF-32 validity checks */ #define PCRE2_ERROR_UTF32_ERR1 (-27) #define PCRE2_ERROR_UTF32_ERR2 (-28) -/* Error codes for pcre2[_dfa]_match(), substring extraction functions, context -functions, and serializing functions. They are in numerical order. Originally -they were in alphabetical order too, but now that PCRE2 is released, the -numbers must not be changed. */ + /* Error codes for pcre2[_dfa]_match(), substring extraction functions, context + functions, and serializing functions. They are in numerical order. Originally + they were in alphabetical order too, but now that PCRE2 is released, the + numbers must not be changed. */ #define PCRE2_ERROR_BADDATA (-29) #define PCRE2_ERROR_MIXEDTABLES (-30) /* Name was changed */ @@ -260,7 +273,7 @@ numbers must not be changed. */ #define PCRE2_ERROR_TOOMANYREPLACE (-61) #define PCRE2_ERROR_BADSERIALIZEDDATA (-62) -/* Request types for pcre2_pattern_info() */ + /* Request types for pcre2_pattern_info() */ #define PCRE2_INFO_ALLOPTIONS 0 #define PCRE2_INFO_ARGOPTIONS 1 @@ -287,7 +300,7 @@ numbers must not be changed. */ #define PCRE2_INFO_SIZE 22 #define PCRE2_INFO_HASBACKSLASHC 23 -/* Request types for pcre2_config(). */ + /* Request types for pcre2_config(). */ #define PCRE2_CONFIG_BSR 0 #define PCRE2_CONFIG_JIT 1 @@ -302,28 +315,28 @@ numbers must not be changed. */ #define PCRE2_CONFIG_UNICODE_VERSION 10 #define PCRE2_CONFIG_VERSION 11 -/* Types for code units in patterns and subject strings. */ + /* Types for code units in patterns and subject strings. */ -typedef uint8_t PCRE2_UCHAR8; -typedef uint16_t PCRE2_UCHAR16; -typedef uint32_t PCRE2_UCHAR32; + typedef uint8_t PCRE2_UCHAR8; + typedef uint16_t PCRE2_UCHAR16; + typedef uint32_t PCRE2_UCHAR32; -typedef const PCRE2_UCHAR8 *PCRE2_SPTR8; -typedef const PCRE2_UCHAR16 *PCRE2_SPTR16; -typedef const PCRE2_UCHAR32 *PCRE2_SPTR32; + typedef const PCRE2_UCHAR8 *PCRE2_SPTR8; + typedef const PCRE2_UCHAR16 *PCRE2_SPTR16; + typedef const PCRE2_UCHAR32 *PCRE2_SPTR32; -/* The PCRE2_SIZE type is used for all string lengths and offsets in PCRE2, -including pattern offsets for errors and subject offsets after a match. We -define special values to indicate zero-terminated strings and unset offsets in -the offset vector (ovector). */ + /* The PCRE2_SIZE type is used for all string lengths and offsets in PCRE2, + including pattern offsets for errors and subject offsets after a match. We + define special values to indicate zero-terminated strings and unset offsets in + the offset vector (ovector). */ #define PCRE2_SIZE size_t #define PCRE2_SIZE_MAX SIZE_MAX #define PCRE2_ZERO_TERMINATED (~(PCRE2_SIZE)0) #define PCRE2_UNSET (~(PCRE2_SIZE)0) -/* Generic types for opaque structures and JIT callback functions. These -declarations are defined in a macro that is expanded for each width later. */ + /* Generic types for opaque structures and JIT callback functions. These + declarations are defined in a macro that is expanded for each width later. */ #define PCRE2_TYPES_LIST \ struct pcre2_real_general_context; \ @@ -347,11 +360,11 @@ typedef struct pcre2_real_jit_stack pcre2_jit_stack; \ typedef pcre2_jit_stack *(*pcre2_jit_callback)(void *); -/* The structure for passing out data via the pcre_callout_function. We use a -structure so that new fields can be added on the end in future versions, -without changing the API of the function, thereby allowing old clients to work -without modification. Define the generic version in a macro; the width-specific -versions are generated from this macro below. */ + /* The structure for passing out data via the pcre_callout_function. We use a + structure so that new fields can be added on the end in future versions, + without changing the API of the function, thereby allowing old clients to work + without modification. Define the generic version in a macro; the width-specific + versions are generated from this macro below. */ #define PCRE2_STRUCTURE_LIST \ typedef struct pcre2_callout_block { \ @@ -388,190 +401,212 @@ typedef struct pcre2_callout_enumerate_block { \ } pcre2_callout_enumerate_block; -/* List the generic forms of all other functions in macros, which will be -expanded for each width below. Start with functions that give general -information. */ + /* List the generic forms of all other functions in macros, which will be + expanded for each width below. Start with functions that give general + information. */ #define PCRE2_GENERAL_INFO_FUNCTIONS \ -PCRE2_EXP_DECL int pcre2_config(uint32_t, void *); +PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION pcre2_config(uint32_t, void *); -/* Functions for manipulating contexts. */ + /* Functions for manipulating contexts. */ #define PCRE2_GENERAL_CONTEXT_FUNCTIONS \ -PCRE2_EXP_DECL \ - pcre2_general_context *pcre2_general_context_copy(pcre2_general_context *); \ -PCRE2_EXP_DECL \ - pcre2_general_context *pcre2_general_context_create( \ - void *(*)(PCRE2_SIZE, void *), \ - void (*)(void *, void *), void *); \ -PCRE2_EXP_DECL void pcre2_general_context_free(pcre2_general_context *); +PCRE2_EXP_DECL pcre2_general_context PCRE2_CALL_CONVENTION \ + *pcre2_general_context_copy(pcre2_general_context *); \ +PCRE2_EXP_DECL pcre2_general_context PCRE2_CALL_CONVENTION \ + *pcre2_general_context_create(void *(*)(PCRE2_SIZE, void *), \ + void (*)(void *, void *), void *); \ +PCRE2_EXP_DECL void PCRE2_CALL_CONVENTION \ + pcre2_general_context_free(pcre2_general_context *); #define PCRE2_COMPILE_CONTEXT_FUNCTIONS \ -PCRE2_EXP_DECL \ - pcre2_compile_context *pcre2_compile_context_copy(pcre2_compile_context *); \ -PCRE2_EXP_DECL \ - pcre2_compile_context *pcre2_compile_context_create(pcre2_general_context *);\ -PCRE2_EXP_DECL void pcre2_compile_context_free(pcre2_compile_context *); \ -PCRE2_EXP_DECL int pcre2_set_bsr(pcre2_compile_context *, uint32_t); \ -PCRE2_EXP_DECL int pcre2_set_character_tables(pcre2_compile_context *, \ - const unsigned char *); \ -PCRE2_EXP_DECL int pcre2_set_max_pattern_length(pcre2_compile_context *, \ - PCRE2_SIZE); \ -PCRE2_EXP_DECL int pcre2_set_newline(pcre2_compile_context *, uint32_t); \ -PCRE2_EXP_DECL int pcre2_set_parens_nest_limit(pcre2_compile_context *, \ - uint32_t); \ -PCRE2_EXP_DECL int pcre2_set_compile_recursion_guard(\ - pcre2_compile_context *, int (*)(uint32_t, void *), \ - void *); +PCRE2_EXP_DECL pcre2_compile_context PCRE2_CALL_CONVENTION \ + *pcre2_compile_context_copy(pcre2_compile_context *); \ +PCRE2_EXP_DECL pcre2_compile_context PCRE2_CALL_CONVENTION \ + *pcre2_compile_context_create(pcre2_general_context *);\ +PCRE2_EXP_DECL void PCRE2_CALL_CONVENTION \ + pcre2_compile_context_free(pcre2_compile_context *); \ +PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \ + pcre2_set_bsr(pcre2_compile_context *, uint32_t); \ +PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \ + pcre2_set_character_tables(pcre2_compile_context *, const unsigned char *); \ +PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \ + pcre2_set_max_pattern_length(pcre2_compile_context *, PCRE2_SIZE); \ +PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \ + pcre2_set_newline(pcre2_compile_context *, uint32_t); \ +PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \ + pcre2_set_parens_nest_limit(pcre2_compile_context *, uint32_t); \ +PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \ + pcre2_set_compile_recursion_guard(pcre2_compile_context *, \ + int (*)(uint32_t, void *), void *); #define PCRE2_MATCH_CONTEXT_FUNCTIONS \ -PCRE2_EXP_DECL \ - pcre2_match_context *pcre2_match_context_copy(pcre2_match_context *); \ -PCRE2_EXP_DECL \ - pcre2_match_context *pcre2_match_context_create(pcre2_general_context *); \ -PCRE2_EXP_DECL void pcre2_match_context_free(pcre2_match_context *); \ -PCRE2_EXP_DECL int pcre2_set_callout(pcre2_match_context *, \ - int (*)(pcre2_callout_block *, void *), void *); \ -PCRE2_EXP_DECL int pcre2_set_match_limit(pcre2_match_context *, \ - uint32_t); \ -PCRE2_EXP_DECL int pcre2_set_offset_limit(pcre2_match_context *, \ - PCRE2_SIZE); \ -PCRE2_EXP_DECL int pcre2_set_recursion_limit(pcre2_match_context *, \ - uint32_t); \ -PCRE2_EXP_DECL int pcre2_set_recursion_memory_management( \ - pcre2_match_context *, void *(*)(PCRE2_SIZE, void *), \ - void (*)(void *, void *), void *); - - -/* Functions concerned with compiling a pattern to PCRE internal code. */ +PCRE2_EXP_DECL pcre2_match_context PCRE2_CALL_CONVENTION \ + *pcre2_match_context_copy(pcre2_match_context *); \ +PCRE2_EXP_DECL pcre2_match_context PCRE2_CALL_CONVENTION \ + *pcre2_match_context_create(pcre2_general_context *); \ +PCRE2_EXP_DECL void PCRE2_CALL_CONVENTION \ + pcre2_match_context_free(pcre2_match_context *); \ +PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \ + pcre2_set_callout(pcre2_match_context *, \ + int (*)(pcre2_callout_block *, void *), void *); \ +PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \ + pcre2_set_match_limit(pcre2_match_context *, uint32_t); \ +PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \ + pcre2_set_offset_limit(pcre2_match_context *, PCRE2_SIZE); \ +PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \ + pcre2_set_recursion_limit(pcre2_match_context *, uint32_t); \ +PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \ + pcre2_set_recursion_memory_management(pcre2_match_context *, \ + void *(*)(PCRE2_SIZE, void *), void (*)(void *, void *), void *); + + + /* Functions concerned with compiling a pattern to PCRE internal code. */ #define PCRE2_COMPILE_FUNCTIONS \ -PCRE2_EXP_DECL \ - pcre2_code *pcre2_compile(PCRE2_SPTR, PCRE2_SIZE, uint32_t, \ - int *, PCRE2_SIZE *, pcre2_compile_context *); \ -PCRE2_EXP_DECL void pcre2_code_free(pcre2_code *); \ -PCRE2_EXP_DECL \ - pcre2_code *pcre2_code_copy(const pcre2_code *); +PCRE2_EXP_DECL pcre2_code PCRE2_CALL_CONVENTION \ + *pcre2_compile(PCRE2_SPTR, PCRE2_SIZE, uint32_t, int *, PCRE2_SIZE *, \ + pcre2_compile_context *); \ +PCRE2_EXP_DECL void PCRE2_CALL_CONVENTION \ + pcre2_code_free(pcre2_code *); \ +PCRE2_EXP_DECL pcre2_code PCRE2_CALL_CONVENTION \ + *pcre2_code_copy(const pcre2_code *); \ +PCRE2_EXP_DECL pcre2_code PCRE2_CALL_CONVENTION \ + *pcre2_code_copy_with_tables(const pcre2_code *); -/* Functions that give information about a compiled pattern. */ + /* Functions that give information about a compiled pattern. */ #define PCRE2_PATTERN_INFO_FUNCTIONS \ -PCRE2_EXP_DECL int pcre2_pattern_info(const pcre2_code *, uint32_t, \ - void *); \ -PCRE2_EXP_DECL int pcre2_callout_enumerate(const pcre2_code *, \ - int (*)(pcre2_callout_enumerate_block *, void *), \ - void *); +PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \ + pcre2_pattern_info(const pcre2_code *, uint32_t, void *); \ +PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \ + pcre2_callout_enumerate(const pcre2_code *, \ + int (*)(pcre2_callout_enumerate_block *, void *), void *); -/* Functions for running a match and inspecting the result. */ + /* Functions for running a match and inspecting the result. */ #define PCRE2_MATCH_FUNCTIONS \ -PCRE2_EXP_DECL \ - pcre2_match_data *pcre2_match_data_create(uint32_t, \ - pcre2_general_context *); \ -PCRE2_EXP_DECL \ - pcre2_match_data *pcre2_match_data_create_from_pattern(\ - const pcre2_code *, \ - pcre2_general_context *); \ -PCRE2_EXP_DECL int pcre2_dfa_match(const pcre2_code *, PCRE2_SPTR, \ - PCRE2_SIZE, PCRE2_SIZE, uint32_t, \ - pcre2_match_data *, pcre2_match_context *, int *, \ - PCRE2_SIZE); \ -PCRE2_EXP_DECL int pcre2_match(const pcre2_code *, \ - PCRE2_SPTR, PCRE2_SIZE, PCRE2_SIZE, uint32_t, \ - pcre2_match_data *, pcre2_match_context *); \ -PCRE2_EXP_DECL void pcre2_match_data_free(pcre2_match_data *); \ -PCRE2_EXP_DECL PCRE2_SPTR pcre2_get_mark(pcre2_match_data *); \ -PCRE2_EXP_DECL uint32_t pcre2_get_ovector_count(pcre2_match_data *); \ -PCRE2_EXP_DECL PCRE2_SIZE *pcre2_get_ovector_pointer(pcre2_match_data *); \ -PCRE2_EXP_DECL PCRE2_SIZE pcre2_get_startchar(pcre2_match_data *); - - -/* Convenience functions for handling matched substrings. */ +PCRE2_EXP_DECL pcre2_match_data PCRE2_CALL_CONVENTION \ + *pcre2_match_data_create(uint32_t, pcre2_general_context *); \ +PCRE2_EXP_DECL pcre2_match_data PCRE2_CALL_CONVENTION \ + *pcre2_match_data_create_from_pattern(const pcre2_code *, \ + pcre2_general_context *); \ +PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \ + pcre2_dfa_match(const pcre2_code *, PCRE2_SPTR, PCRE2_SIZE, PCRE2_SIZE, \ + uint32_t, pcre2_match_data *, pcre2_match_context *, int *, PCRE2_SIZE); \ +PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \ + pcre2_match(const pcre2_code *, PCRE2_SPTR, PCRE2_SIZE, PCRE2_SIZE, \ + uint32_t, pcre2_match_data *, pcre2_match_context *); \ +PCRE2_EXP_DECL void PCRE2_CALL_CONVENTION \ + pcre2_match_data_free(pcre2_match_data *); \ +PCRE2_EXP_DECL PCRE2_SPTR PCRE2_CALL_CONVENTION \ + pcre2_get_mark(pcre2_match_data *); \ +PCRE2_EXP_DECL uint32_t PCRE2_CALL_CONVENTION \ + pcre2_get_ovector_count(pcre2_match_data *); \ +PCRE2_EXP_DECL PCRE2_SIZE PCRE2_CALL_CONVENTION \ + *pcre2_get_ovector_pointer(pcre2_match_data *); \ +PCRE2_EXP_DECL PCRE2_SIZE PCRE2_CALL_CONVENTION \ + pcre2_get_startchar(pcre2_match_data *); + + + /* Convenience functions for handling matched substrings. */ #define PCRE2_SUBSTRING_FUNCTIONS \ -PCRE2_EXP_DECL int pcre2_substring_copy_byname(pcre2_match_data *, \ - PCRE2_SPTR, PCRE2_UCHAR *, PCRE2_SIZE *); \ -PCRE2_EXP_DECL int pcre2_substring_copy_bynumber(pcre2_match_data *, \ - uint32_t, PCRE2_UCHAR *, PCRE2_SIZE *); \ -PCRE2_EXP_DECL void pcre2_substring_free(PCRE2_UCHAR *); \ -PCRE2_EXP_DECL int pcre2_substring_get_byname(pcre2_match_data *, \ - PCRE2_SPTR, PCRE2_UCHAR **, PCRE2_SIZE *); \ -PCRE2_EXP_DECL int pcre2_substring_get_bynumber(pcre2_match_data *, \ - uint32_t, PCRE2_UCHAR **, PCRE2_SIZE *); \ -PCRE2_EXP_DECL int pcre2_substring_length_byname(pcre2_match_data *, \ - PCRE2_SPTR, PCRE2_SIZE *); \ -PCRE2_EXP_DECL int pcre2_substring_length_bynumber(pcre2_match_data *, \ - uint32_t, PCRE2_SIZE *); \ -PCRE2_EXP_DECL int pcre2_substring_nametable_scan(const pcre2_code *, \ - PCRE2_SPTR, PCRE2_SPTR *, PCRE2_SPTR *); \ -PCRE2_EXP_DECL int pcre2_substring_number_from_name(\ - const pcre2_code *, PCRE2_SPTR); \ -PCRE2_EXP_DECL void pcre2_substring_list_free(PCRE2_SPTR *); \ -PCRE2_EXP_DECL int pcre2_substring_list_get(pcre2_match_data *, \ - PCRE2_UCHAR ***, PCRE2_SIZE **); - -/* Functions for serializing / deserializing compiled patterns. */ +PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \ + pcre2_substring_copy_byname(pcre2_match_data *, PCRE2_SPTR, PCRE2_UCHAR *, \ + PCRE2_SIZE *); \ +PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \ + pcre2_substring_copy_bynumber(pcre2_match_data *, uint32_t, PCRE2_UCHAR *, \ + PCRE2_SIZE *); \ +PCRE2_EXP_DECL void PCRE2_CALL_CONVENTION \ + pcre2_substring_free(PCRE2_UCHAR *); \ +PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \ + pcre2_substring_get_byname(pcre2_match_data *, PCRE2_SPTR, PCRE2_UCHAR **, \ + PCRE2_SIZE *); \ +PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \ + pcre2_substring_get_bynumber(pcre2_match_data *, uint32_t, PCRE2_UCHAR **, \ + PCRE2_SIZE *); \ +PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \ + pcre2_substring_length_byname(pcre2_match_data *, PCRE2_SPTR, PCRE2_SIZE *); \ +PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \ + pcre2_substring_length_bynumber(pcre2_match_data *, uint32_t, PCRE2_SIZE *); \ +PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \ + pcre2_substring_nametable_scan(const pcre2_code *, PCRE2_SPTR, PCRE2_SPTR *, \ + PCRE2_SPTR *); \ +PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \ + pcre2_substring_number_from_name(const pcre2_code *, PCRE2_SPTR); \ +PCRE2_EXP_DECL void PCRE2_CALL_CONVENTION \ + pcre2_substring_list_free(PCRE2_SPTR *); \ +PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \ + pcre2_substring_list_get(pcre2_match_data *, PCRE2_UCHAR ***, PCRE2_SIZE **); + + /* Functions for serializing / deserializing compiled patterns. */ #define PCRE2_SERIALIZE_FUNCTIONS \ -PCRE2_EXP_DECL int32_t pcre2_serialize_encode(const pcre2_code **, \ - int32_t, uint8_t **, PCRE2_SIZE *, \ - pcre2_general_context *); \ -PCRE2_EXP_DECL int32_t pcre2_serialize_decode(pcre2_code **, int32_t, \ - const uint8_t *, pcre2_general_context *); \ -PCRE2_EXP_DECL int32_t pcre2_serialize_get_number_of_codes(const uint8_t *); \ -PCRE2_EXP_DECL void pcre2_serialize_free(uint8_t *); +PCRE2_EXP_DECL int32_t PCRE2_CALL_CONVENTION \ + pcre2_serialize_encode(const pcre2_code **, int32_t, uint8_t **, \ + PCRE2_SIZE *, pcre2_general_context *); \ +PCRE2_EXP_DECL int32_t PCRE2_CALL_CONVENTION \ + pcre2_serialize_decode(pcre2_code **, int32_t, const uint8_t *, \ + pcre2_general_context *); \ +PCRE2_EXP_DECL int32_t PCRE2_CALL_CONVENTION \ + pcre2_serialize_get_number_of_codes(const uint8_t *); \ +PCRE2_EXP_DECL void PCRE2_CALL_CONVENTION \ + pcre2_serialize_free(uint8_t *); -/* Convenience function for match + substitute. */ + /* Convenience function for match + substitute. */ #define PCRE2_SUBSTITUTE_FUNCTION \ -PCRE2_EXP_DECL int pcre2_substitute(const pcre2_code *, \ - PCRE2_SPTR, PCRE2_SIZE, PCRE2_SIZE, uint32_t, \ - pcre2_match_data *, pcre2_match_context *, \ - PCRE2_SPTR, PCRE2_SIZE, PCRE2_UCHAR *, \ - PCRE2_SIZE *); +PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \ + pcre2_substitute(const pcre2_code *, PCRE2_SPTR, PCRE2_SIZE, PCRE2_SIZE, \ + uint32_t, pcre2_match_data *, pcre2_match_context *, PCRE2_SPTR, \ + PCRE2_SIZE, PCRE2_UCHAR *, PCRE2_SIZE *); -/* Functions for JIT processing */ + /* Functions for JIT processing */ #define PCRE2_JIT_FUNCTIONS \ -PCRE2_EXP_DECL int pcre2_jit_compile(pcre2_code *, uint32_t); \ -PCRE2_EXP_DECL int pcre2_jit_match(const pcre2_code *, \ - PCRE2_SPTR, PCRE2_SIZE, PCRE2_SIZE, uint32_t, \ - pcre2_match_data *, pcre2_match_context *); \ -PCRE2_EXP_DECL void pcre2_jit_free_unused_memory(pcre2_general_context *); \ -PCRE2_EXP_DECL \ - pcre2_jit_stack *pcre2_jit_stack_create(PCRE2_SIZE, PCRE2_SIZE, \ - pcre2_general_context *); \ -PCRE2_EXP_DECL void pcre2_jit_stack_assign(pcre2_match_context *, \ - pcre2_jit_callback, void *); \ -PCRE2_EXP_DECL void pcre2_jit_stack_free(pcre2_jit_stack *); - - -/* Other miscellaneous functions. */ +PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \ + pcre2_jit_compile(pcre2_code *, uint32_t); \ +PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \ + pcre2_jit_match(const pcre2_code *, PCRE2_SPTR, PCRE2_SIZE, PCRE2_SIZE, \ + uint32_t, pcre2_match_data *, pcre2_match_context *); \ +PCRE2_EXP_DECL void PCRE2_CALL_CONVENTION \ + pcre2_jit_free_unused_memory(pcre2_general_context *); \ +PCRE2_EXP_DECL pcre2_jit_stack PCRE2_CALL_CONVENTION \ + *pcre2_jit_stack_create(PCRE2_SIZE, PCRE2_SIZE, pcre2_general_context *); \ +PCRE2_EXP_DECL void PCRE2_CALL_CONVENTION \ + pcre2_jit_stack_assign(pcre2_match_context *, pcre2_jit_callback, void *); \ +PCRE2_EXP_DECL void PCRE2_CALL_CONVENTION \ + pcre2_jit_stack_free(pcre2_jit_stack *); + + + /* Other miscellaneous functions. */ #define PCRE2_OTHER_FUNCTIONS \ -PCRE2_EXP_DECL int pcre2_get_error_message(int, PCRE2_UCHAR *, PCRE2_SIZE); \ -PCRE2_EXP_DECL \ - const uint8_t *pcre2_maketables(pcre2_general_context *); \ +PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \ + pcre2_get_error_message(int, PCRE2_UCHAR *, PCRE2_SIZE); \ +PCRE2_EXP_DECL const uint8_t PCRE2_CALL_CONVENTION \ + *pcre2_maketables(pcre2_general_context *); \ -/* Define macros that generate width-specific names from generic versions. The -three-level macro scheme is necessary to get the macros expanded when we want -them to be. First we get the width from PCRE2_LOCAL_WIDTH, which is used for -generating three versions of everything below. After that, PCRE2_SUFFIX will be -re-defined to use PCRE2_CODE_UNIT_WIDTH, for use when macros such as -pcre2_compile are called by application code. */ + /* Define macros that generate width-specific names from generic versions. The + three-level macro scheme is necessary to get the macros expanded when we want + them to be. First we get the width from PCRE2_LOCAL_WIDTH, which is used for + generating three versions of everything below. After that, PCRE2_SUFFIX will be + re-defined to use PCRE2_CODE_UNIT_WIDTH, for use when macros such as + pcre2_compile are called by application code. */ #define PCRE2_JOIN(a,b) a ## b #define PCRE2_GLUE(a,b) PCRE2_JOIN(a,b) #define PCRE2_SUFFIX(a) PCRE2_GLUE(a,PCRE2_LOCAL_WIDTH) -/* Data types */ + /* Data types */ #define PCRE2_UCHAR PCRE2_SUFFIX(PCRE2_UCHAR) #define PCRE2_SPTR PCRE2_SUFFIX(PCRE2_SPTR) @@ -588,7 +623,7 @@ pcre2_compile are called by application code. */ #define pcre2_real_match_data PCRE2_SUFFIX(pcre2_real_match_data_) -/* Data blocks */ + /* Data blocks */ #define pcre2_callout_block PCRE2_SUFFIX(pcre2_callout_block_) #define pcre2_callout_enumerate_block PCRE2_SUFFIX(pcre2_callout_enumerate_block_) @@ -598,10 +633,11 @@ pcre2_compile are called by application code. */ #define pcre2_match_data PCRE2_SUFFIX(pcre2_match_data_) -/* Functions: the complete list in alphabetical order */ + /* Functions: the complete list in alphabetical order */ #define pcre2_callout_enumerate PCRE2_SUFFIX(pcre2_callout_enumerate_) #define pcre2_code_copy PCRE2_SUFFIX(pcre2_code_copy_) +#define pcre2_code_copy_with_tables PCRE2_SUFFIX(pcre2_code_copy_with_tables_) #define pcre2_code_free PCRE2_SUFFIX(pcre2_code_free_) #define pcre2_compile PCRE2_SUFFIX(pcre2_compile_) #define pcre2_compile_context_copy PCRE2_SUFFIX(pcre2_compile_context_copy_) @@ -661,8 +697,8 @@ pcre2_compile are called by application code. */ #define pcre2_substring_number_from_name PCRE2_SUFFIX(pcre2_substring_number_from_name_) -/* Now generate all three sets of width-specific structures and function -prototypes. */ + /* Now generate all three sets of width-specific structures and function + prototypes. */ #define PCRE2_TYPES_STRUCTURES_AND_FUNCTIONS \ PCRE2_TYPES_LIST \ @@ -681,18 +717,18 @@ PCRE2_JIT_FUNCTIONS \ PCRE2_OTHER_FUNCTIONS #define PCRE2_LOCAL_WIDTH 8 -PCRE2_TYPES_STRUCTURES_AND_FUNCTIONS + PCRE2_TYPES_STRUCTURES_AND_FUNCTIONS #undef PCRE2_LOCAL_WIDTH #define PCRE2_LOCAL_WIDTH 16 -PCRE2_TYPES_STRUCTURES_AND_FUNCTIONS + PCRE2_TYPES_STRUCTURES_AND_FUNCTIONS #undef PCRE2_LOCAL_WIDTH #define PCRE2_LOCAL_WIDTH 32 -PCRE2_TYPES_STRUCTURES_AND_FUNCTIONS + PCRE2_TYPES_STRUCTURES_AND_FUNCTIONS #undef PCRE2_LOCAL_WIDTH -/* Undefine the list macros; they are no longer needed. */ + /* Undefine the list macros; they are no longer needed. */ #undef PCRE2_TYPES_LIST #undef PCRE2_STRUCTURE_LIST @@ -710,9 +746,9 @@ PCRE2_TYPES_STRUCTURES_AND_FUNCTIONS #undef PCRE2_OTHER_FUNCTIONS #undef PCRE2_TYPES_STRUCTURES_AND_FUNCTIONS -/* PCRE2_CODE_UNIT_WIDTH must be defined. If it is 8, 16, or 32, redefine -PCRE2_SUFFIX to use it. If it is 0, undefine the other macros and make -PCRE2_SUFFIX a no-op. Otherwise, generate an error. */ + /* PCRE2_CODE_UNIT_WIDTH must be defined. If it is 8, 16, or 32, redefine + PCRE2_SUFFIX to use it. If it is 0, undefine the other macros and make + PCRE2_SUFFIX a no-op. Otherwise, generate an error. */ #undef PCRE2_SUFFIX #ifndef PCRE2_CODE_UNIT_WIDTH @@ -736,4 +772,6 @@ PCRE2_SUFFIX a no-op. Otherwise, generate an error. */ } /* extern "C" */ #endif -#endif /* End of pcre2.h */ +#endif /* PCRE2_H_IDEMPOTENT_GUARD */ + + /* End of pcre2.h */ diff --git a/ProcessHacker/pcre/pcre2_auto_possess.c b/ProcessHacker/pcre/pcre2_auto_possess.c index 24c0c2986523..2c987bbf5b76 100644 --- a/ProcessHacker/pcre/pcre2_auto_possess.c +++ b/ProcessHacker/pcre/pcre2_auto_possess.c @@ -41,7 +41,9 @@ POSSIBILITY OF SUCH DAMAGE. /* This module contains functions that scan a compiled pattern and change repeats into possessive repeats where possible. */ + #define HAVE_CONFIG_H + #ifdef HAVE_CONFIG_H #include "config.h" #endif @@ -589,6 +591,7 @@ for(;;) case OP_ASSERTBACK_NOT: case OP_ONCE: case OP_ONCE_NC: + /* Atomic sub-patterns and assertions can always auto-possessify their last iterator. However, if the group was entered as a result of checking a previous iterator, this is not possible. */ @@ -606,6 +609,9 @@ for(;;) next_code = code + GET(code, 1); code += PRIV(OP_lengths)[c]; + /* Check each branch. We have to recurse a level for all but the last + branch. */ + while (*next_code == OP_ALT) { if (!compare_opcodes(code, utf, cb, base_list, base_end, rec_limit)) @@ -1046,8 +1052,10 @@ but some compilers complain about an unreachable statement. */ /* Replaces single character iterations with their possessive alternatives if appropriate. This function modifies the compiled opcode! Hitting a -non-existant opcode may indicate a bug in PCRE2, but it can also be caused if a -bad UTF string was compiled with PCRE2_NO_UTF_CHECK. +non-existent opcode may indicate a bug in PCRE2, but it can also be caused if a +bad UTF string was compiled with PCRE2_NO_UTF_CHECK. The rec_limit catches +overly complicated or large patterns. In these cases, the check just stops, +leaving the remainder of the pattern unpossessified. Arguments: code points to start of the byte code @@ -1061,11 +1069,11 @@ Returns: 0 for success int PRIV(auto_possessify)(PCRE2_UCHAR *code, BOOL utf, const compile_block *cb) { -register PCRE2_UCHAR c; +PCRE2_UCHAR c; PCRE2_SPTR end; PCRE2_UCHAR *repeat_opcode; uint32_t list[8]; -int rec_limit; +int rec_limit = 1000; /* Was 10,000 but clang+ASAN uses a lot of stack. */ for (;;) { @@ -1080,7 +1088,6 @@ for (;;) get_chr_property_list(code, utf, cb->fcc, list) : NULL; list[1] = c == OP_STAR || c == OP_PLUS || c == OP_QUERY || c == OP_UPTO; - rec_limit = 1000; if (end != NULL && compare_opcodes(end, utf, cb, list, end, &rec_limit)) { switch(c) @@ -1137,7 +1144,6 @@ for (;;) list[1] = (c & 1) == 0; - rec_limit = 1000; if (compare_opcodes(end, utf, cb, list, end, &rec_limit)) { switch (c) diff --git a/ProcessHacker/pcre/pcre2_compile.c b/ProcessHacker/pcre/pcre2_compile.c index 0677e1fc6f19..0e8199ff4123 100644 --- a/ProcessHacker/pcre/pcre2_compile.c +++ b/ProcessHacker/pcre/pcre2_compile.c @@ -38,11 +38,11 @@ POSSIBILITY OF SUCH DAMAGE. ----------------------------------------------------------------------------- */ -// dmex: Disable warnings +// dmex: Disable warnings. #pragma warning(push) -#pragma warning(disable : 4244 4267) - +#pragma warning(disable : 4244 4267) #define HAVE_CONFIG_H + #ifdef HAVE_CONFIG_H #include "config.h" #endif @@ -62,9 +62,14 @@ POSSIBILITY OF SUCH DAMAGE. #define PRINTABLE(c) ((c) >= 32 && (c) < 127) #endif #include "pcre2_printint.c" -#define CALL_PRINTINT +#define DEBUG_CALL_PRINTINT #endif +/* Other debugging code can be enabled by these defines. */ + +// #define DEBUG_SHOW_CAPTURES +// #define DEBUG_SHOW_PARSED + /* There are a few things that vary with different code unit sizes. Handle them by defining macros in order to minimize #if usage. */ @@ -83,16 +88,56 @@ by defining macros in order to minimize #if usage. */ #endif #endif +/* Macros to store and retrieve a PCRE2_SIZE value in the parsed pattern, which +consists of uint32_t elements. Assume that if uint32_t can't hold it, two of +them will be able to (i.e. assume a 64-bit world). */ + +#if PCRE2_SIZE_MAX <= UINT32_MAX +#define PUTOFFSET(s,p) *p++ = s +#define GETOFFSET(s,p) s = *p++ +#define GETPLUSOFFSET(s,p) s = *(++p) +#define READPLUSOFFSET(s,p) s = p[1] +#define SKIPOFFSET(p) p++ +#define SIZEOFFSET 1 +#else +#define PUTOFFSET(s,p) \ + { *p++ = (uint32_t)(s >> 32); *p++ = (uint32_t)(s & 0xffffffff); } +#define GETOFFSET(s,p) \ + { s = ((PCRE2_SIZE)p[0] << 32) | (PCRE2_SIZE)p[1]; p += 2; } +#define GETPLUSOFFSET(s,p) \ + { s = ((PCRE2_SIZE)p[1] << 32) | (PCRE2_SIZE)p[2]; p += 2; } +#define READPLUSOFFSET(s,p) \ + { s = ((PCRE2_SIZE)p[1] << 32) | (PCRE2_SIZE)p[2]; } +#define SKIPOFFSET(p) p += 2 +#define SIZEOFFSET 2 +#endif + +/* Macros for manipulating elements of the parsed pattern vector. */ + +#define META_CODE(x) (x & 0xffff0000u) +#define META_DATA(x) (x & 0x0000ffffu) +#define META_DIFF(x,y) ((x-y)>>16) + /* Function definitions to allow mutual recursion */ +#ifdef SUPPORT_UNICODE static unsigned int - add_list_to_class(uint8_t *, PCRE2_UCHAR **, uint32_t, compile_block *, - const uint32_t *, unsigned int); + add_list_to_class_internal(uint8_t *, PCRE2_UCHAR **, uint32_t, + compile_block *, const uint32_t *, unsigned int); +#endif + +static int + compile_regex(uint32_t, PCRE2_UCHAR **, uint32_t **, int *, uint32_t, + uint32_t *, int32_t *, uint32_t *, int32_t *, branch_chain *, + compile_block *, PCRE2_SIZE *); + +static int + get_branchlength(uint32_t **, int *, int *, parsed_recurse_check *, + compile_block *); static BOOL - compile_regex(uint32_t, PCRE2_UCHAR **, PCRE2_SPTR *, int *, BOOL, BOOL, - uint32_t, int, uint32_t *, int32_t *, uint32_t *, int32_t *, - branch_chain *, compile_block *, size_t *); + set_lookbehind_lengths(uint32_t **, int *, int *, parsed_recurse_check *, + compile_block *); @@ -100,9 +145,15 @@ static BOOL * Code parameters and static tables * *************************************************/ -/* This value specifies the size of stack workspace, which is used in different -ways in the different pattern scans. The group-identifying pre-scan uses it to -handle nesting, and needs it to be 16-bit aligned. +#define MAX_GROUP_NUMBER 65535u +#define MAX_REPEAT_COUNT 65535u +#define REPEAT_UNLIMITED (MAX_REPEAT_COUNT+1) + +/* COMPILE_WORK_SIZE specifies the size of stack workspace, which is used in +different ways in the different pattern scans. The parsing and group- +identifying pre-scan uses it to handle nesting, and needs it to be 16-bit +aligned for this. Having defined the size in code units, we set up +C16_WORK_SIZE as the number of elements in the 16-bit vector. During the first compiling phase, when determining how much memory is required, the regex is partly compiled into this space, but the compiled parts are @@ -111,16 +162,18 @@ overrun. The code does, however, check for an overrun, which can occur for pathological patterns. The size of the workspace depends on LINK_SIZE because the length of compiled items varies with this. -In the real compile phase, the workspace is used for remembering data about -numbered groups, provided there are not too many of them (if there are, extra -memory is acquired). For this phase the memory must be 32-bit aligned. Having -defined the size in code units, we set up C32_WORK_SIZE as the number of -elements in the 32-bit vector. */ +In the real compile phase, this workspace is not currently used. */ #define COMPILE_WORK_SIZE (2048*LINK_SIZE) /* Size in code units */ -#define C32_WORK_SIZE \ - ((COMPILE_WORK_SIZE * sizeof(PCRE2_UCHAR))/sizeof(uint32_t)) +#define C16_WORK_SIZE \ + ((COMPILE_WORK_SIZE * sizeof(PCRE2_UCHAR))/sizeof(uint16_t)) + +/* A uint32_t vector is used for caching information about the size of +capturing groups, to improve performance. A default is created on the stack of +this size. */ + +#define GROUPINFO_DEFAULT_SIZE 256 /* The overrun tests check for a slightly smaller size so that they detect the overrun before it actually does run off the end of the data block. */ @@ -134,25 +187,176 @@ value is the number of slots in the list. */ #define NAMED_GROUP_LIST_SIZE 20 -/* The original PCRE required patterns to be zero-terminated, and it simplifies -the compiling code if it is guaranteed that there is a zero code unit at the -end of the pattern, because this means that tests for coding sequences such as -(*SKIP) or even just (?<= can check a sequence of code units without having to -keep checking for the end of the pattern. The new PCRE2 API allows zero code -units within patterns if a positive length is given, but in order to keep most -of the compiling code as it was, we copy such patterns and add a zero on the -end. This value determines the size of space on the stack that is used if the -pattern fits; if not, heap memory is used. */ +/* The pre-compiling pass over the pattern creates a parsed pattern in a vector +of uint32_t. For short patterns this lives on the stack, with this size. Heap +memory is used for longer patterns. */ -#define COPIED_PATTERN_SIZE 1024 +#define PARSED_PATTERN_DEFAULT_SIZE 1024 /* Maximum length value to check against when making sure that the variable that holds the compiled pattern length does not overflow. We make it a bit less -than INT_MAX to allow for adding in group terminating bytes, so that we don't -have to check them every time. */ +than INT_MAX to allow for adding in group terminating code units, so that we +don't have to check them every time. */ #define OFLOW_MAX (INT_MAX - 20) +/* Code values for parsed patterns, which are stored in a vector of 32-bit +unsigned ints. Values less than META_END are literal data values. The coding +for identifying the item is in the top 16-bits, leaving 16 bits for the +additional data that some of them need. The META_CODE, META_DATA, and META_DIFF +macros are used to manipulate parsed pattern elements. + +NOTE: When these definitions are changed, the table of extra lengths for each +code (meta_extra_lengths, just below) must be updated to remain in step. */ + +#define META_END 0x80000000u /* End of pattern */ + +#define META_ALT 0x80010000u /* alternation */ +#define META_ATOMIC 0x80020000u /* atomic group */ +#define META_BACKREF 0x80030000u /* Back ref */ +#define META_BACKREF_BYNAME 0x80040000u /* \k'name' */ +#define META_BIGVALUE 0x80050000u /* Next is a literal > META_END */ +#define META_CALLOUT_NUMBER 0x80060000u /* (?C with numerical argument */ +#define META_CALLOUT_STRING 0x80070000u /* (?C with string argument */ +#define META_CAPTURE 0x80080000u /* Capturing parenthesis */ +#define META_CIRCUMFLEX 0x80090000u /* ^ metacharacter */ +#define META_CLASS 0x800a0000u /* start non-empty class */ +#define META_CLASS_EMPTY 0x800b0000u /* empty class */ +#define META_CLASS_EMPTY_NOT 0x800c0000u /* negative empty class */ +#define META_CLASS_END 0x800d0000u /* end of non-empty class */ +#define META_CLASS_NOT 0x800e0000u /* start non-empty negative class */ +#define META_COND_ASSERT 0x800f0000u /* (?(?assertion)... */ +#define META_COND_DEFINE 0x80100000u /* (?(DEFINE)... */ +#define META_COND_NAME 0x80110000u /* (?()... */ +#define META_COND_NUMBER 0x80120000u /* (?(digits)... */ +#define META_COND_RNAME 0x80130000u /* (?(R&name)... */ +#define META_COND_RNUMBER 0x80140000u /* (?(Rdigits)... */ +#define META_COND_VERSION 0x80150000u /* (?(VERSIONx.y)... */ +#define META_DOLLAR 0x80160000u /* $ metacharacter */ +#define META_DOT 0x80170000u /* . metacharacter */ +#define META_ESCAPE 0x80180000u /* \d and friends */ +#define META_KET 0x80190000u /* closing parenthesis */ +#define META_NOCAPTURE 0x801a0000u /* no capture parens */ +#define META_OPTIONS 0x801b0000u /* (?i) and friends */ +#define META_POSIX 0x801c0000u /* POSIX class item */ +#define META_POSIX_NEG 0x801d0000u /* negative POSIX class item */ +#define META_RANGE_ESCAPED 0x801e0000u /* range with at least one escape */ +#define META_RANGE_LITERAL 0x801f0000u /* range defined literally */ +#define META_RECURSE 0x80200000u /* Recursion */ +#define META_RECURSE_BYNAME 0x80210000u /* (?&name) */ + +/* These must be kept together to make it easy to check that an assertion +is present where expected in a conditional group. */ + +#define META_LOOKAHEAD 0x80220000u /* (?= */ +#define META_LOOKAHEADNOT 0x80230000u /* (?! */ +#define META_LOOKBEHIND 0x80240000u /* (?<= */ +#define META_LOOKBEHINDNOT 0x80250000u /* (?= 10 */ + 1+SIZEOFFSET, /* META_BACKREF_BYNAME */ + 1, /* META_BIGVALUE */ + 3, /* META_CALLOUT_NUMBER */ + 3+SIZEOFFSET, /* META_CALLOUT_STRING */ + 0, /* META_CAPTURE */ + 0, /* META_CIRCUMFLEX */ + 0, /* META_CLASS */ + 0, /* META_CLASS_EMPTY */ + 0, /* META_CLASS_EMPTY_NOT */ + 0, /* META_CLASS_END */ + 0, /* META_CLASS_NOT */ + 0, /* META_COND_ASSERT */ + SIZEOFFSET, /* META_COND_DEFINE */ + 1+SIZEOFFSET, /* META_COND_NAME */ + 1+SIZEOFFSET, /* META_COND_NUMBER */ + 1+SIZEOFFSET, /* META_COND_RNAME */ + 1+SIZEOFFSET, /* META_COND_RNUMBER */ + 3, /* META_COND_VERSION */ + 0, /* META_DOLLAR */ + 0, /* META_DOT */ + 0, /* META_ESCAPE - more for ESC_P, ESC_p, ESC_g, ESC_k */ + 0, /* META_KET */ + 0, /* META_NOCAPTURE */ + 1, /* META_OPTIONS */ + 1, /* META_POSIX */ + 1, /* META_POSIX_NEG */ + 0, /* META_RANGE_ESCAPED */ + 0, /* META_RANGE_LITERAL */ + SIZEOFFSET, /* META_RECURSE */ + 1+SIZEOFFSET, /* META_RECURSE_BYNAME */ + 0, /* META_LOOKAHEAD */ + 0, /* META_LOOKAHEADNOT */ + SIZEOFFSET, /* META_LOOKBEHIND */ + SIZEOFFSET, /* META_LOOKBEHINDNOT */ + 1, /* META_MARK - plus the string length */ + 0, /* META_ACCEPT */ + 0, /* META_COMMIT */ + 0, /* META_FAIL */ + 0, /* META_PRUNE */ + 1, /* META_PRUNE_ARG - plus the string length */ + 0, /* META_SKIP */ + 1, /* META_SKIP_ARG - plus the string length */ + 0, /* META_THEN */ + 1, /* META_THEN_ARG - plus the string length */ + 0, /* META_ASTERISK */ + 0, /* META_ASTERISK_PLUS */ + 0, /* META_ASTERISK_QUERY */ + 0, /* META_PLUS */ + 0, /* META_PLUS_PLUS */ + 0, /* META_PLUS_QUERY */ + 0, /* META_QUERY */ + 0, /* META_QUERY_PLUS */ + 0, /* META_QUERY_QUERY */ + 2, /* META_MINMAX */ + 2, /* META_MINMAX_PLUS */ + 2 /* META_MINMAX_QUERY */ +}; + +/* Types for skipping parts of a parsed pattern. */ + +enum { PSKIP_ALT, PSKIP_CLASS, PSKIP_KET }; + /* Macro for setting individual bits in class bitmaps. It took some experimenting to figure out how to stop gcc 5.3.0 from warning with -Wconversion. This version gets a warning: @@ -174,17 +378,10 @@ compiler is clever with identical subexpressions. */ /* These flags are used in the groupinfo vector. */ -#define GI_SET_COULD_BE_EMPTY 0x80000000u -#define GI_COULD_BE_EMPTY 0x40000000u -#define GI_NOT_FIXED_LENGTH 0x20000000u -#define GI_SET_FIXED_LENGTH 0x10000000u +#define GI_SET_FIXED_LENGTH 0x80000000u +#define GI_NOT_FIXED_LENGTH 0x40000000u #define GI_FIXED_LENGTH_MASK 0x0000ffffu -/* This bit (which is greater than any UTF value) is used to indicate that a -variable contains a number of code units instead of an actual code point. */ - -#define UTF_LENGTH 0x10000000l - /* This simple test for a decimal digit works for both ASCII/Unicode and EBCDIC and is fast (a good compiler can turn it into a subtraction and unsigned comparison). */ @@ -195,8 +392,8 @@ comparison). */ locale, and may mark arbitrary characters as digits. We want to recognize only 0-9, a-z, and A-Z as hex digits, which is why we have a private table here. It costs 256 bytes, but it is a lot faster than doing character value tests (at -least in some simple cases I timed), and in some applications one wants PCRE to -compile efficiently as well as match efficiently. The value in the table is +least in some simple cases I timed), and in some applications one wants PCRE2 +to compile efficiently as well as match efficiently. The value in the table is the binary hex digit value, or 0xff for non-hex digits. */ /* This is the "normal" case, for ASCII systems, and EBCDIC systems running in @@ -384,9 +581,9 @@ string is built from string macros so that it works in UTF-8 mode on EBCDIC platforms. */ typedef struct verbitem { - int len; /* Length of verb name */ - int op; /* Op when no arg, or -1 if arg mandatory */ - int op_arg; /* Op when arg present, or -1 if not allowed */ + unsigned int len; /* Length of verb name */ + uint32_t meta; /* Base META_ code */ + int has_arg; /* Argument requirement */ } verbitem; static const char verbnames[] = @@ -401,32 +598,30 @@ static const char verbnames[] = STRING_THEN; static const verbitem verbs[] = { - { 0, -1, OP_MARK }, - { 4, -1, OP_MARK }, - { 6, OP_ACCEPT, -1 }, - { 6, OP_COMMIT, -1 }, - { 1, OP_FAIL, -1 }, - { 4, OP_FAIL, -1 }, - { 5, OP_PRUNE, OP_PRUNE_ARG }, - { 4, OP_SKIP, OP_SKIP_ARG }, - { 4, OP_THEN, OP_THEN_ARG } + { 0, META_MARK, +1 }, /* > 0 => must have an argument */ + { 4, META_MARK, +1 }, + { 6, META_ACCEPT, -1 }, /* < 0 => must not have an argument */ + { 6, META_COMMIT, -1 }, + { 1, META_FAIL, -1 }, + { 4, META_FAIL, -1 }, + { 5, META_PRUNE, 0 }, /* Argument is optional; bump META code if found */ + { 4, META_SKIP, 0 }, + { 4, META_THEN, 0 } }; static const int verbcount = sizeof(verbs)/sizeof(verbitem); +/* Verb opcodes, indexed by their META code offset from META_MARK. */ -/* Substitutes for [[:<:]] and [[:>:]], which mean start and end of word in -another regex library. */ +static const uint32_t verbops[] = { + OP_MARK, OP_ACCEPT, OP_COMMIT, OP_FAIL, OP_PRUNE, OP_PRUNE_ARG, OP_SKIP, + OP_SKIP_ARG, OP_THEN, OP_THEN_ARG }; -static const PCRE2_UCHAR sub_start_of_word[] = { - CHAR_BACKSLASH, CHAR_b, CHAR_LEFT_PARENTHESIS, CHAR_QUESTION_MARK, - CHAR_EQUALS_SIGN, CHAR_BACKSLASH, CHAR_w, CHAR_RIGHT_PARENTHESIS, '\0' }; - -static const PCRE2_UCHAR sub_end_of_word[] = { - CHAR_BACKSLASH, CHAR_b, CHAR_LEFT_PARENTHESIS, CHAR_QUESTION_MARK, - CHAR_LESS_THAN_SIGN, CHAR_EQUALS_SIGN, CHAR_BACKSLASH, CHAR_w, - CHAR_RIGHT_PARENTHESIS, '\0' }; +/* Offsets from OP_STAR for case-independent and negative repeat opcodes. */ +static uint32_t chartypeoffset[] = { + OP_STAR - OP_STAR, OP_STARI - OP_STAR, + OP_NOTSTAR - OP_STAR, OP_NOTSTARI - OP_STAR }; /* Tables of names of POSIX character classes and their lengths. The names are now all in a single string, to reduce the number of relocations when a shared @@ -448,7 +643,6 @@ static const uint8_t posix_name_lengths[] = { #define PC_PRINT 9 #define PC_PUNCT 10 - /* Table of class bit maps for each POSIX class. Each class is formed from a base map, with an optional addition or removal of another map. Then, for some classes, there is some additional tweaking: for [:blank:] the vertical space @@ -476,117 +670,28 @@ static const int posix_class_maps[] = { cbit_xdigit,-1, 0 /* xdigit */ }; -/* Table of substitutes for \d etc when PCRE2_UCP is set. They are replaced by -Unicode property escapes. */ - #ifdef SUPPORT_UNICODE -static const PCRE2_UCHAR string_PNd[] = { - CHAR_BACKSLASH, CHAR_P, CHAR_LEFT_CURLY_BRACKET, - CHAR_N, CHAR_d, CHAR_RIGHT_CURLY_BRACKET, '\0' }; -static const PCRE2_UCHAR string_pNd[] = { - CHAR_BACKSLASH, CHAR_p, CHAR_LEFT_CURLY_BRACKET, - CHAR_N, CHAR_d, CHAR_RIGHT_CURLY_BRACKET, '\0' }; -static const PCRE2_UCHAR string_PXsp[] = { - CHAR_BACKSLASH, CHAR_P, CHAR_LEFT_CURLY_BRACKET, - CHAR_X, CHAR_s, CHAR_p, CHAR_RIGHT_CURLY_BRACKET, '\0' }; -static const PCRE2_UCHAR string_pXsp[] = { - CHAR_BACKSLASH, CHAR_p, CHAR_LEFT_CURLY_BRACKET, - CHAR_X, CHAR_s, CHAR_p, CHAR_RIGHT_CURLY_BRACKET, '\0' }; -static const PCRE2_UCHAR string_PXwd[] = { - CHAR_BACKSLASH, CHAR_P, CHAR_LEFT_CURLY_BRACKET, - CHAR_X, CHAR_w, CHAR_d, CHAR_RIGHT_CURLY_BRACKET, '\0' }; -static const PCRE2_UCHAR string_pXwd[] = { - CHAR_BACKSLASH, CHAR_p, CHAR_LEFT_CURLY_BRACKET, - CHAR_X, CHAR_w, CHAR_d, CHAR_RIGHT_CURLY_BRACKET, '\0' }; - -static PCRE2_SPTR substitutes[] = { - string_PNd, /* \D */ - string_pNd, /* \d */ - string_PXsp, /* \S */ /* Xsp is Perl space, but from 8.34, Perl */ - string_pXsp, /* \s */ /* space and POSIX space are the same. */ - string_PXwd, /* \W */ - string_pXwd /* \w */ -}; -/* The POSIX class substitutes must be in the order of the POSIX class names, -defined above, and there are both positive and negative cases. NULL means no -general substitute of a Unicode property escape (\p or \P). However, for some -POSIX classes (e.g. graph, print, punct) a special property code is compiled -directly. */ - -static const PCRE2_UCHAR string_pCc[] = { - CHAR_BACKSLASH, CHAR_p, CHAR_LEFT_CURLY_BRACKET, - CHAR_C, CHAR_c, CHAR_RIGHT_CURLY_BRACKET, '\0' }; -static const PCRE2_UCHAR string_pL[] = { - CHAR_BACKSLASH, CHAR_p, CHAR_LEFT_CURLY_BRACKET, - CHAR_L, CHAR_RIGHT_CURLY_BRACKET, '\0' }; -static const PCRE2_UCHAR string_pLl[] = { - CHAR_BACKSLASH, CHAR_p, CHAR_LEFT_CURLY_BRACKET, - CHAR_L, CHAR_l, CHAR_RIGHT_CURLY_BRACKET, '\0' }; -static const PCRE2_UCHAR string_pLu[] = { - CHAR_BACKSLASH, CHAR_p, CHAR_LEFT_CURLY_BRACKET, - CHAR_L, CHAR_u, CHAR_RIGHT_CURLY_BRACKET, '\0' }; -static const PCRE2_UCHAR string_pXan[] = { - CHAR_BACKSLASH, CHAR_p, CHAR_LEFT_CURLY_BRACKET, - CHAR_X, CHAR_a, CHAR_n, CHAR_RIGHT_CURLY_BRACKET, '\0' }; -static const PCRE2_UCHAR string_h[] = { - CHAR_BACKSLASH, CHAR_h, '\0' }; -static const PCRE2_UCHAR string_pXps[] = { - CHAR_BACKSLASH, CHAR_p, CHAR_LEFT_CURLY_BRACKET, - CHAR_X, CHAR_p, CHAR_s, CHAR_RIGHT_CURLY_BRACKET, '\0' }; -static const PCRE2_UCHAR string_PCc[] = { - CHAR_BACKSLASH, CHAR_P, CHAR_LEFT_CURLY_BRACKET, - CHAR_C, CHAR_c, CHAR_RIGHT_CURLY_BRACKET, '\0' }; -static const PCRE2_UCHAR string_PL[] = { - CHAR_BACKSLASH, CHAR_P, CHAR_LEFT_CURLY_BRACKET, - CHAR_L, CHAR_RIGHT_CURLY_BRACKET, '\0' }; -static const PCRE2_UCHAR string_PLl[] = { - CHAR_BACKSLASH, CHAR_P, CHAR_LEFT_CURLY_BRACKET, - CHAR_L, CHAR_l, CHAR_RIGHT_CURLY_BRACKET, '\0' }; -static const PCRE2_UCHAR string_PLu[] = { - CHAR_BACKSLASH, CHAR_P, CHAR_LEFT_CURLY_BRACKET, - CHAR_L, CHAR_u, CHAR_RIGHT_CURLY_BRACKET, '\0' }; -static const PCRE2_UCHAR string_PXan[] = { - CHAR_BACKSLASH, CHAR_P, CHAR_LEFT_CURLY_BRACKET, - CHAR_X, CHAR_a, CHAR_n, CHAR_RIGHT_CURLY_BRACKET, '\0' }; -static const PCRE2_UCHAR string_H[] = { - CHAR_BACKSLASH, CHAR_H, '\0' }; -static const PCRE2_UCHAR string_PXps[] = { - CHAR_BACKSLASH, CHAR_P, CHAR_LEFT_CURLY_BRACKET, - CHAR_X, CHAR_p, CHAR_s, CHAR_RIGHT_CURLY_BRACKET, '\0' }; - -static PCRE2_SPTR posix_substitutes[] = { - string_pL, /* alpha */ - string_pLl, /* lower */ - string_pLu, /* upper */ - string_pXan, /* alnum */ - NULL, /* ascii */ - string_h, /* blank */ - string_pCc, /* cntrl */ - string_pNd, /* digit */ - NULL, /* graph */ - NULL, /* print */ - NULL, /* punct */ - string_pXps, /* space */ /* Xps is POSIX space, but from 8.34 */ - string_pXwd, /* word */ /* Perl and POSIX space are the same */ - NULL, /* xdigit */ - /* Negated cases */ - string_PL, /* ^alpha */ - string_PLl, /* ^lower */ - string_PLu, /* ^upper */ - string_PXan, /* ^alnum */ - NULL, /* ^ascii */ - string_H, /* ^blank */ - string_PCc, /* ^cntrl */ - string_PNd, /* ^digit */ - NULL, /* ^graph */ - NULL, /* ^print */ - NULL, /* ^punct */ - string_PXps, /* ^space */ /* Xps is POSIX space, but from 8.34 */ - string_PXwd, /* ^word */ /* Perl and POSIX space are the same */ - NULL /* ^xdigit */ +/* The POSIX class Unicode property substitutes that are used in UCP mode must +be in the order of the POSIX class names, defined above. */ + +static int posix_substitutes[] = { + PT_GC, ucp_L, /* alpha */ + PT_PC, ucp_Ll, /* lower */ + PT_PC, ucp_Lu, /* upper */ + PT_ALNUM, 0, /* alnum */ + -1, 0, /* ascii, treat as non-UCP */ + -1, 1, /* blank, treat as \h */ + PT_PC, ucp_Cc, /* cntrl */ + PT_PC, ucp_Nd, /* digit */ + PT_PXGRAPH, 0, /* graph */ + PT_PXPRINT, 0, /* print */ + PT_PXPUNCT, 0, /* punct */ + PT_PXSPACE, 0, /* space */ /* Xps is POSIX space, but from 8.34 */ + PT_WORD, 0, /* word */ /* Perl and POSIX space are the same */ + -1, 0 /* xdigit, treat as non-UCP */ }; -#define POSIX_SUBSIZE (sizeof(posix_substitutes) / sizeof(PCRE2_UCHAR *)) +#define POSIX_SUBSIZE (sizeof(posix_substitutes) / (2*sizeof(uint32_t))) #endif /* SUPPORT_UNICODE */ /* Masks for checking option settings. */ @@ -615,21 +720,7 @@ enum { ERR0 = COMPILE_ERROR_BASE, ERR51, ERR52, ERR53, ERR54, ERR55, ERR56, ERR57, ERR58, ERR59, ERR60, ERR61, ERR62, ERR63, ERR64, ERR65, ERR66, ERR67, ERR68, ERR69, ERR70, ERR71, ERR72, ERR73, ERR74, ERR75, ERR76, ERR77, ERR78, ERR79, ERR80, - ERR81, ERR82, ERR83, ERR84, ERR85, ERR86, ERR87, ERR88 }; - -/* Error codes that correspond to negative error codes returned by -find_fixedlength(). */ - -static int fixed_length_errors[] = - { - ERR0, /* Not an error */ - ERR0, /* Not an error; -1 is used for "process later" */ - ERR25, /* Lookbehind is not fixed length */ - ERR36, /* \C in lookbehind is not allowed */ - ERR87, /* Lookbehind is too long */ - ERR86, /* Pattern too complicated */ - ERR70 /* Internal error: unknown opcode encountered */ - }; + ERR81, ERR82, ERR83, ERR84, ERR85, ERR86, ERR87, ERR88, ERR89, ERR90 }; /* This is a table of start-of-pattern options such as (*UTF) and settings such as (*LIMIT_MATCH=nnnn) and (*CRLF). For completeness and backward @@ -732,6 +823,265 @@ static const uint8_t opcode_possessify[] = { }; +#ifdef DEBUG_SHOW_PARSED +/************************************************* +* Show the parsed pattern for debugging * +*************************************************/ + +/* For debugging the pre-scan, this code, which outputs the parsed data vector, +can be enabled. */ + +static void show_parsed(compile_block *cb) +{ +uint32_t *pptr = cb->parsed_pattern; + +for (;;) + { + int max, min; + PCRE2_SIZE offset; + uint32_t i; + uint32_t length; + uint32_t meta_arg = META_DATA(*pptr); + + fprintf(stderr, "+++ %02d %.8x ", (int)(pptr - cb->parsed_pattern), *pptr); + + if (*pptr < META_END) + { + if (*pptr > 32 && *pptr < 128) fprintf(stderr, "%c", *pptr); + pptr++; + } + + else switch (META_CODE(*pptr++)) + { + default: + fprintf(stderr, "**** OOPS - unknown META value - giving up ****\n"); + return; + + case META_END: + fprintf(stderr, "META_END\n"); + return; + + case META_CAPTURE: + fprintf(stderr, "META_CAPTURE %d", meta_arg); + break; + + case META_RECURSE: + GETOFFSET(offset, pptr); + fprintf(stderr, "META_RECURSE %d %zd", meta_arg, offset); + break; + + case META_BACKREF: + if (meta_arg < 10) + offset = cb->small_ref_offset[meta_arg]; + else + GETOFFSET(offset, pptr); + fprintf(stderr, "META_BACKREF %d %zd", meta_arg, offset); + break; + + case META_ESCAPE: + if (meta_arg == ESC_P || meta_arg == ESC_p) + { + uint32_t ptype = *pptr >> 16; + uint32_t pvalue = *pptr++ & 0xffff; + fprintf(stderr, "META \\%c %d %d", (meta_arg == ESC_P)? 'P':'p', + ptype, pvalue); + } + else + { + uint32_t cc; + /* There's just one escape we might have here that isn't negated in the + escapes table. */ + if (meta_arg == ESC_g) cc = CHAR_g; + else for (cc = ESCAPES_FIRST; cc <= ESCAPES_LAST; cc++) + { + if (meta_arg == (uint32_t)(-escapes[cc - ESCAPES_FIRST])) break; + } + if (cc > ESCAPES_LAST) cc = CHAR_QUESTION_MARK; + fprintf(stderr, "META \\%c", cc); + } + break; + + case META_MINMAX: + min = *pptr++; + max = *pptr++; + if (max != REPEAT_UNLIMITED) + fprintf(stderr, "META {%d,%d}", min, max); + else + fprintf(stderr, "META {%d,}", min); + break; + + case META_MINMAX_QUERY: + min = *pptr++; + max = *pptr++; + if (max != REPEAT_UNLIMITED) + fprintf(stderr, "META {%d,%d}?", min, max); + else + fprintf(stderr, "META {%d,}?", min); + break; + + case META_MINMAX_PLUS: + min = *pptr++; + max = *pptr++; + if (max != REPEAT_UNLIMITED) + fprintf(stderr, "META {%d,%d}+", min, max); + else + fprintf(stderr, "META {%d,}+", min); + break; + + case META_BIGVALUE: fprintf(stderr, "META_BIGVALUE %.8x", *pptr++); break; + case META_CIRCUMFLEX: fprintf(stderr, "META_CIRCUMFLEX"); break; + case META_COND_ASSERT: fprintf(stderr, "META_COND_ASSERT"); break; + case META_DOLLAR: fprintf(stderr, "META_DOLLAR"); break; + case META_DOT: fprintf(stderr, "META_DOT"); break; + case META_ASTERISK: fprintf(stderr, "META *"); break; + case META_ASTERISK_QUERY: fprintf(stderr, "META *?"); break; + case META_ASTERISK_PLUS: fprintf(stderr, "META *+"); break; + case META_PLUS: fprintf(stderr, "META +"); break; + case META_PLUS_QUERY: fprintf(stderr, "META +?"); break; + case META_PLUS_PLUS: fprintf(stderr, "META ++"); break; + case META_QUERY: fprintf(stderr, "META ?"); break; + case META_QUERY_QUERY: fprintf(stderr, "META ??"); break; + case META_QUERY_PLUS: fprintf(stderr, "META ?+"); break; + + case META_ATOMIC: fprintf(stderr, "META (?>"); break; + case META_NOCAPTURE: fprintf(stderr, "META (?:"); break; + case META_LOOKAHEAD: fprintf(stderr, "META (?="); break; + case META_LOOKAHEADNOT: fprintf(stderr, "META (?!"); break; + case META_KET: fprintf(stderr, "META )"); break; + case META_ALT: fprintf(stderr, "META | %d", meta_arg); break; + + case META_CLASS: fprintf(stderr, "META ["); break; + case META_CLASS_NOT: fprintf(stderr, "META [^"); break; + case META_CLASS_END: fprintf(stderr, "META ]"); break; + case META_CLASS_EMPTY: fprintf(stderr, "META []"); break; + case META_CLASS_EMPTY_NOT: fprintf(stderr, "META [^]"); break; + + case META_RANGE_LITERAL: fprintf(stderr, "META - (literal)"); break; + case META_RANGE_ESCAPED: fprintf(stderr, "META - (escaped)"); break; + + case META_POSIX: fprintf(stderr, "META_POSIX %d", *pptr++); break; + case META_POSIX_NEG: fprintf(stderr, "META_POSIX_NEG %d", *pptr++); break; + + case META_ACCEPT: fprintf(stderr, "META (*ACCEPT)"); break; + case META_COMMIT: fprintf(stderr, "META (*COMMIT)"); break; + case META_FAIL: fprintf(stderr, "META (*FAIL)"); break; + case META_PRUNE: fprintf(stderr, "META (*PRUNE)"); break; + case META_SKIP: fprintf(stderr, "META (*SKIP)"); break; + case META_THEN: fprintf(stderr, "META (*THEN)"); break; + + case META_OPTIONS: fprintf(stderr, "META_OPTIONS 0x%02x", *pptr++); break; + + case META_LOOKBEHIND: + fprintf(stderr, "META (?<= %d offset=", meta_arg); + GETOFFSET(offset, pptr); + fprintf(stderr, "%zd", offset); + break; + + case META_LOOKBEHINDNOT: + fprintf(stderr, "META (?="); + fprintf(stderr, "%d.", *pptr++); + fprintf(stderr, "%d)", *pptr++); + break; + + case META_COND_NAME: + fprintf(stderr, "META (?() length=%d offset=", *pptr++); + GETOFFSET(offset, pptr); + fprintf(stderr, "%zd", offset); + break; + + case META_COND_RNAME: + fprintf(stderr, "META (?(R&name) length=%d offset=", *pptr++); + GETOFFSET(offset, pptr); + fprintf(stderr, "%zd", offset); + break; + + /* This is kept as a name, because it might be. */ + + case META_COND_RNUMBER: + fprintf(stderr, "META (?(Rnumber) length=%d offset=", *pptr++); + GETOFFSET(offset, pptr); + fprintf(stderr, "%zd", offset); + break; + + case META_MARK: + fprintf(stderr, "META (*MARK:"); + goto SHOWARG; + + case META_PRUNE_ARG: + fprintf(stderr, "META (*PRUNE:"); + goto SHOWARG; + + case META_SKIP_ARG: + fprintf(stderr, "META (*SKIP:"); + goto SHOWARG; + + case META_THEN_ARG: + fprintf(stderr, "META (*THEN:"); + SHOWARG: + length = *pptr++; + for (i = 0; i < length; i++) + { + uint32_t cc = *pptr++; + if (cc > 32 && cc < 128) fprintf(stderr, "%c", cc); + else fprintf(stderr, "\\x{%x}", cc); + } + fprintf(stderr, ") length=%u", length); + break; + } + fprintf(stderr, "\n"); + } +return; +} +#endif /* DEBUG_SHOW_PARSED */ + + /************************************************* * Copy compiled code * @@ -766,6 +1116,45 @@ return newcode; +/************************************************* +* Copy compiled code and character tables * +*************************************************/ + +/* Compiled JIT code cannot be copied, so the new compiled block has no +associated JIT data. This version of code_copy also makes a separate copy of +the character tables. */ + +PCRE2_EXP_DEFN pcre2_code * PCRE2_CALL_CONVENTION +pcre2_code_copy_with_tables(const pcre2_code *code) +{ +PCRE2_SIZE* ref_count; +pcre2_code *newcode; +uint8_t *newtables; + +if (code == NULL) return NULL; +newcode = code->memctl.malloc(code->blocksize, code->memctl.memory_data); +if (newcode == NULL) return NULL; +memcpy(newcode, code, code->blocksize); +newcode->executable_jit = NULL; + +newtables = code->memctl.malloc(tables_length + sizeof(PCRE2_SIZE), + code->memctl.memory_data); +if (newtables == NULL) + { + code->memctl.free((void *)newcode, code->memctl.memory_data); + return NULL; + } +memcpy(newtables, code->tables, tables_length); +ref_count = (PCRE2_SIZE *)(newtables + tables_length); +*ref_count = 1; + +newcode->tables = newtables; +newcode->flags |= PCRE2_DEREF_TABLES; +return newcode; +} + + + /************************************************* * Free compiled code * *************************************************/ @@ -802,1043 +1191,212 @@ if (code != NULL) /************************************************* -* Insert an automatic callout point * +* Read a number, possibly signed * *************************************************/ -/* This function is called when the PCRE2_AUTO_CALLOUT option is set, to insert -callout points before each pattern item. +/* This function is used to read numbers in the pattern. The initial pointer +must be the sign or first digit of the number. When relative values (introduced +by + or -) are allowed, they are relative group numbers, and the result must be +greater than zero. Arguments: - code current code pointer - ptr current pattern pointer - cb general compile-time data - -Returns: new code pointer + ptrptr points to the character pointer variable + ptrend points to the end of the input string + allow_sign if < 0, sign not allowed; if >= 0, sign is relative to this + max_value the largest number allowed + max_error the error to give for an over-large number + intptr where to put the result + errcodeptr where to put an error code + +Returns: TRUE - a number was read + FALSE - errorcode == 0 => no number was found + errorcode != 0 => an error occurred */ -static PCRE2_UCHAR * -auto_callout(PCRE2_UCHAR *code, PCRE2_SPTR ptr, compile_block *cb) +static BOOL +read_number(PCRE2_SPTR *ptrptr, PCRE2_SPTR ptrend, int32_t allow_sign, + uint32_t max_value, uint32_t max_error, int *intptr, int *errorcodeptr) { -code[0] = OP_CALLOUT; -PUT(code, 1, ptr - cb->start_pattern); /* Pattern offset */ -PUT(code, 1 + LINK_SIZE, 0); /* Default length */ -code[1 + 2*LINK_SIZE] = 255; -return code + PRIV(OP_lengths)[OP_CALLOUT]; -} +int sign = 0; +uint32_t n = 0; +PCRE2_SPTR ptr = *ptrptr; +BOOL yield = FALSE; +*errorcodeptr = 0; +if (allow_sign >= 0 && ptr < ptrend) + { + if (*ptr == CHAR_PLUS) + { + sign = +1; + max_value -= allow_sign; + ptr++; + } + else if (*ptr == CHAR_MINUS) + { + sign = -1; + ptr++; + } + } -/************************************************* -* Complete a callout item * -*************************************************/ +if (ptr >= ptrend || !IS_DIGIT(*ptr)) return FALSE; +while (ptr < ptrend && IS_DIGIT(*ptr)) + { + n = n * 10 + *ptr++ - CHAR_0; + if (n > max_value) + { + *errorcodeptr = max_error; + goto EXIT; + } + } -/* A callout item contains the length of the next item in the pattern, which -we can't fill in till after we have reached the relevant point. This is used -for both automatic and manual callouts. +if (allow_sign >= 0 && sign != 0) + { + if (n == 0) + { + *errorcodeptr = ERR26; /* +0 and -0 are not allowed */ + goto EXIT; + } -Arguments: - previous_callout points to previous callout item - ptr current pattern pointer - cb general compile-time data + if (sign > 0) n += allow_sign; + else if ((int)n > allow_sign) + { + *errorcodeptr = ERR15; /* Non-existent subpattern */ + goto EXIT; + } + else n = allow_sign + 1 - n; + } -Returns: nothing -*/ +yield = TRUE; -static void -complete_callout(PCRE2_UCHAR *previous_callout, PCRE2_SPTR ptr, - compile_block *cb) -{ -size_t length = (size_t)(ptr - cb->start_pattern - GET(previous_callout, 1)); -PUT(previous_callout, 1 + LINK_SIZE, length); +EXIT: +*intptr = n; +*ptrptr = ptr; +return yield; } /************************************************* -* Find the fixed length of a branch * +* Read repeat counts * *************************************************/ -/* Scan a branch and compute the fixed length of subject that will match it, if -the length is fixed. This is needed for dealing with lookbehind assertions. In -UTF mode, the result is in code units rather than bytes. The branch is -temporarily terminated with OP_END when this function is called. - -This function is called when a lookbehind assertion is encountered, so that if -it fails, the error message can point to the correct place in the pattern. -However, we cannot do this when the assertion contains subroutine calls, -because they can be forward references. We solve this by remembering this case -and doing the check at the end; a flag specifies which mode we are running in. - -Lookbehind lengths are held in 16-bit fields and the maximum value is defined -as LOOKBEHIND_MAX. +/* Read an item of the form {n,m} and return the values if non-NULL pointers +are supplied. Repeat counts must be less than 65536 (MAX_REPEAT_COUNT); a +larger value is used for "unlimited". We have to use signed arguments for +read_number() because it is capable of returning a signed value. Arguments: - code points to the start of the pattern (the bracket) - utf TRUE in UTF mode - atend TRUE if called when the pattern is complete - cb the "compile data" structure - recurses chain of recurse_check to catch mutual recursion - countptr pointer to counter, to catch over-complexity - -Returns: if non-negative, the fixed length, - or -1 if an OP_RECURSE item was encountered and atend is FALSE - or -2 if there is no fixed length, - or -3 if \C was encountered (in UTF mode only) - or -4 if length is too long - or -5 if regex is too complicated - or -6 if an unknown opcode was encountered (internal error) -*/ + ptrptr points to pointer to character after'{' + ptrend pointer to end of input + minp if not NULL, pointer to int for min + maxp if not NULL, pointer to int for max (-1 if no max) + returned as -1 if no max + errorcodeptr points to error code variable -#define FFL_LATER (-1) -#define FFL_NOTFIXED (-2) -#define FFL_BACKSLASHC (-3) -#define FFL_TOOLONG (-4) -#define FFL_TOOCOMPLICATED (-5) -#define FFL_UNKNOWNOP (-6) +Returns: FALSE if not a repeat quantifier, errorcode set zero + FALSE on error, with errorcode set non-zero + TRUE on success, with pointer updated to point after '}' +*/ -static int -find_fixedlength(PCRE2_UCHAR *code, BOOL utf, BOOL atend, compile_block *cb, - recurse_check *recurses, int *countptr) +static BOOL +read_repeat_counts(PCRE2_SPTR *ptrptr, PCRE2_SPTR ptrend, uint32_t *minp, + uint32_t *maxp, int *errorcodeptr) { -uint32_t length = 0xffffffffu; /* Unset */ -uint32_t group = 0; -uint32_t groupinfo = 0; -recurse_check this_recurse; -register uint32_t branchlength = 0; -register PCRE2_UCHAR *cc = code + 1 + LINK_SIZE; - -/* If this is a capturing group, we may have the answer cached, but we can only -use this information if there are no (?| groups in the pattern, because -otherwise group numbers are not unique. */ - -if (*code == OP_CBRA || *code == OP_CBRAPOS || *code == OP_SCBRA || - *code == OP_SCBRAPOS) - { - group = GET2(cc, 0); - cc += IMM2_SIZE; - groupinfo = cb->groupinfo[group]; - if ((cb->external_flags & PCRE2_DUPCAPUSED) == 0) - { - if ((groupinfo & GI_NOT_FIXED_LENGTH) != 0) return FFL_NOTFIXED; - if ((groupinfo & GI_SET_FIXED_LENGTH) != 0) - return groupinfo & GI_FIXED_LENGTH_MASK; - } - } +PCRE2_SPTR p = *ptrptr; +BOOL yield = FALSE; +int32_t min = 0; +int32_t max = REPEAT_UNLIMITED; /* This value is larger than MAX_REPEAT_COUNT */ -/* A large and/or complex regex can take too long to process. This can happen -more often when (?| groups are present in the pattern. */ +/* NB read_number() initializes the error code to zero. The only error is for a +number that is too big. */ -if ((*countptr)++ > 2000) return FFL_TOOCOMPLICATED; +if (!read_number(&p, ptrend, -1, MAX_REPEAT_COUNT, ERR5, &min, errorcodeptr)) + goto EXIT; -/* Scan along the opcodes for this branch. If we get to the end of the -branch, check the length against that of the other branches. */ +if (p >= ptrend) goto EXIT; -for (;;) +if (*p == CHAR_RIGHT_CURLY_BRACKET) { - int d; - PCRE2_UCHAR *ce, *cs; - register PCRE2_UCHAR op = *cc; - - if (branchlength > LOOKBEHIND_MAX) return FFL_TOOLONG; + p++; + max = min; + } - switch (op) +else + { + if (*p++ != CHAR_COMMA || p >= ptrend) goto EXIT; + if (*p != CHAR_RIGHT_CURLY_BRACKET) { - /* We only need to continue for OP_CBRA (normal capturing bracket) and - OP_BRA (normal non-capturing bracket) because the other variants of these - opcodes are all concerned with unlimited repeated groups, which of course - are not of fixed length. */ - - case OP_CBRA: - case OP_BRA: - case OP_ONCE: - case OP_ONCE_NC: - case OP_COND: - d = find_fixedlength(cc, utf, atend, cb, recurses, countptr); - if (d < 0) return d; - branchlength += (uint32_t)d; - do cc += GET(cc, 1); while (*cc == OP_ALT); - cc += 1 + LINK_SIZE; - break; - - /* Reached end of a branch; if it's a ket it is the end of a nested call. - If it's ALT it is an alternation in a nested call. An ACCEPT is effectively - an ALT. If it is END it's the end of the outer call. All can be handled by - the same code. Note that we must not include the OP_KETRxxx opcodes here, - because they all imply an unlimited repeat. */ - - case OP_ALT: - case OP_KET: - case OP_END: - case OP_ACCEPT: - case OP_ASSERT_ACCEPT: - if (length == 0xffffffffu) length = branchlength; - else if (length != branchlength) goto ISNOTFIXED; - if (*cc != OP_ALT) - { - if (group > 0) - { - groupinfo |= (uint32_t)(GI_SET_FIXED_LENGTH | length); - cb->groupinfo[group] = groupinfo; - } - return (int)length; - } - cc += 1 + LINK_SIZE; - branchlength = 0; - break; - - /* A true recursion implies not fixed length, but a subroutine call may - be OK. If the subroutine is a forward reference, we can't deal with - it until the end of the pattern, so return FFL_LATER. */ - - case OP_RECURSE: - if (!atend) return FFL_LATER; - cs = ce = (PCRE2_UCHAR *)cb->start_code + GET(cc, 1); /* Start subpattern */ - do ce += GET(ce, 1); while (*ce == OP_ALT); /* End subpattern */ - if (cc > cs && cc < ce) goto ISNOTFIXED; /* Recursion */ - else /* Check for mutual recursion */ + if (!read_number(&p, ptrend, -1, MAX_REPEAT_COUNT, ERR5, &max, + errorcodeptr) || p >= ptrend || *p != CHAR_RIGHT_CURLY_BRACKET) + goto EXIT; + if (max < min) { - recurse_check *r = recurses; - for (r = recurses; r != NULL; r = r->prev) if (r->group == cs) break; - if (r != NULL) goto ISNOTFIXED; /* Mutual recursion */ + *errorcodeptr = ERR4; + goto EXIT; } - this_recurse.prev = recurses; - this_recurse.group = cs; - d = find_fixedlength(cs, utf, atend, cb, &this_recurse, countptr); - if (d < 0) return d; - branchlength += (uint32_t)d; - cc += 1 + LINK_SIZE; - break; + } + p++; + } - /* Skip over assertive subpatterns. Note that we must increment cc by - 1 + LINK_SIZE at the end, not by OP_length[*cc] because in a recursive - situation this assertion may be the one that is ultimately being checked - for having a fixed length, in which case its terminating OP_KET will have - been temporarily replaced by OP_END. */ +yield = TRUE; +if (minp != NULL) *minp = (uint32_t)min; +if (maxp != NULL) *maxp = (uint32_t)max; - case OP_ASSERT: - case OP_ASSERT_NOT: - case OP_ASSERTBACK: - case OP_ASSERTBACK_NOT: - do cc += GET(cc, 1); while (*cc == OP_ALT); - cc += 1 + LINK_SIZE; - break; +/* Update the pattern pointer on success, or after an error, but not when +the result is "not a repeat quantifier". */ - /* Skip over things that don't match chars */ +EXIT: +if (yield || *errorcodeptr != 0) *ptrptr = p; +return yield; - case OP_MARK: - case OP_PRUNE_ARG: - case OP_SKIP_ARG: - case OP_THEN_ARG: - cc += cc[1] + PRIV(OP_lengths)[*cc]; - break; - case OP_CALLOUT: - case OP_CIRC: - case OP_CIRCM: - case OP_CLOSE: - case OP_COMMIT: - case OP_CREF: - case OP_FALSE: - case OP_TRUE: - case OP_DNCREF: - case OP_DNRREF: - case OP_DOLL: - case OP_DOLLM: - case OP_EOD: - case OP_EODN: - case OP_FAIL: - case OP_NOT_WORD_BOUNDARY: - case OP_PRUNE: - case OP_REVERSE: - case OP_RREF: - case OP_SET_SOM: - case OP_SKIP: - case OP_SOD: - case OP_SOM: - case OP_THEN: - case OP_WORD_BOUNDARY: - cc += PRIV(OP_lengths)[*cc]; - break; - case OP_CALLOUT_STR: - cc += GET(cc, 1 + 2*LINK_SIZE); - break; +} - /* Handle literal characters */ - case OP_CHAR: - case OP_CHARI: - case OP_NOT: - case OP_NOTI: - branchlength++; - cc += 2; -#ifdef SUPPORT_UNICODE - if (utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]); -#endif - break; - /* Handle exact repetitions. The count is already in characters, but we - need to skip over a multibyte character in UTF8 mode. */ +/************************************************* +* Handle escapes * +*************************************************/ - case OP_EXACT: - case OP_EXACTI: - case OP_NOTEXACT: - case OP_NOTEXACTI: - branchlength += GET2(cc,1); - cc += 2 + IMM2_SIZE; -#ifdef SUPPORT_UNICODE - if (utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]); -#endif - break; +/* This function is called when a \ has been encountered. It either returns a +positive value for a simple escape such as \d, or 0 for a data character, which +is placed in chptr. A backreference to group n is returned as negative n. On +entry, ptr is pointing at the character after \. On exit, it points after the +final code unit of the escape sequence. - case OP_TYPEEXACT: - branchlength += GET2(cc,1); - if (cc[1 + IMM2_SIZE] == OP_PROP || cc[1 + IMM2_SIZE] == OP_NOTPROP) - cc += 2; - cc += 1 + IMM2_SIZE + 1; - break; +This function is also called from pcre2_substitute() to handle escape sequences +in replacement strings. In this case, the cb argument is NULL, and in the case +of escapes that have further processing, only sequences that define a data +character are recognised. The isclass argument is not relevant; the options +argument is the final value of the compiled pattern's options. - /* Handle single-char matchers */ +Arguments: + ptrptr points to the input position pointer + ptrend points to the end of the input + chptr points to a returned data character + errorcodeptr points to the errorcode variable (containing zero) + options the current options bits + isclass TRUE if inside a character class + cb compile data block - case OP_PROP: - case OP_NOTPROP: - cc += 2; - /* Fall through */ - - case OP_HSPACE: - case OP_VSPACE: - case OP_NOT_HSPACE: - case OP_NOT_VSPACE: - case OP_NOT_DIGIT: - case OP_DIGIT: - case OP_NOT_WHITESPACE: - case OP_WHITESPACE: - case OP_NOT_WORDCHAR: - case OP_WORDCHAR: - case OP_ANY: - case OP_ALLANY: - branchlength++; - cc++; - break; - - /* The single-byte matcher isn't allowed. This only happens in UTF-8 or - UTF-16 mode; otherwise \C is coded as OP_ALLANY. */ - - case OP_ANYBYTE: - return FFL_BACKSLASHC; - - /* Check a class for variable quantification */ - - case OP_CLASS: - case OP_NCLASS: -#ifdef SUPPORT_WIDE_CHARS - case OP_XCLASS: - /* The original code caused an unsigned overflow in 64 bit systems, - so now we use a conditional statement. */ - if (op == OP_XCLASS) - cc += GET(cc, 1); - else - cc += PRIV(OP_lengths)[OP_CLASS]; -#else - cc += PRIV(OP_lengths)[OP_CLASS]; -#endif - - switch (*cc) - { - case OP_CRSTAR: - case OP_CRMINSTAR: - case OP_CRPLUS: - case OP_CRMINPLUS: - case OP_CRQUERY: - case OP_CRMINQUERY: - case OP_CRPOSSTAR: - case OP_CRPOSPLUS: - case OP_CRPOSQUERY: - goto ISNOTFIXED; - - case OP_CRRANGE: - case OP_CRMINRANGE: - case OP_CRPOSRANGE: - if (GET2(cc,1) != GET2(cc,1+IMM2_SIZE)) goto ISNOTFIXED; - branchlength += GET2(cc,1); - cc += 1 + 2 * IMM2_SIZE; - break; - - default: - branchlength++; - } - break; - - /* Anything else is variable length */ - - case OP_ANYNL: - case OP_BRAMINZERO: - case OP_BRAPOS: - case OP_BRAPOSZERO: - case OP_BRAZERO: - case OP_CBRAPOS: - case OP_EXTUNI: - case OP_KETRMAX: - case OP_KETRMIN: - case OP_KETRPOS: - case OP_MINPLUS: - case OP_MINPLUSI: - case OP_MINQUERY: - case OP_MINQUERYI: - case OP_MINSTAR: - case OP_MINSTARI: - case OP_MINUPTO: - case OP_MINUPTOI: - case OP_NOTMINPLUS: - case OP_NOTMINPLUSI: - case OP_NOTMINQUERY: - case OP_NOTMINQUERYI: - case OP_NOTMINSTAR: - case OP_NOTMINSTARI: - case OP_NOTMINUPTO: - case OP_NOTMINUPTOI: - case OP_NOTPLUS: - case OP_NOTPLUSI: - case OP_NOTPOSPLUS: - case OP_NOTPOSPLUSI: - case OP_NOTPOSQUERY: - case OP_NOTPOSQUERYI: - case OP_NOTPOSSTAR: - case OP_NOTPOSSTARI: - case OP_NOTPOSUPTO: - case OP_NOTPOSUPTOI: - case OP_NOTQUERY: - case OP_NOTQUERYI: - case OP_NOTSTAR: - case OP_NOTSTARI: - case OP_NOTUPTO: - case OP_NOTUPTOI: - case OP_PLUS: - case OP_PLUSI: - case OP_POSPLUS: - case OP_POSPLUSI: - case OP_POSQUERY: - case OP_POSQUERYI: - case OP_POSSTAR: - case OP_POSSTARI: - case OP_POSUPTO: - case OP_POSUPTOI: - case OP_QUERY: - case OP_QUERYI: - case OP_REF: - case OP_REFI: - case OP_DNREF: - case OP_DNREFI: - case OP_SBRA: - case OP_SBRAPOS: - case OP_SCBRA: - case OP_SCBRAPOS: - case OP_SCOND: - case OP_SKIPZERO: - case OP_STAR: - case OP_STARI: - case OP_TYPEMINPLUS: - case OP_TYPEMINQUERY: - case OP_TYPEMINSTAR: - case OP_TYPEMINUPTO: - case OP_TYPEPLUS: - case OP_TYPEPOSPLUS: - case OP_TYPEPOSQUERY: - case OP_TYPEPOSSTAR: - case OP_TYPEPOSUPTO: - case OP_TYPEQUERY: - case OP_TYPESTAR: - case OP_TYPEUPTO: - case OP_UPTO: - case OP_UPTOI: - goto ISNOTFIXED; - - /* Catch unrecognized opcodes so that when new ones are added they - are not forgotten, as has happened in the past. */ - - default: - return FFL_UNKNOWNOP; - } - } -/* Control never gets here except by goto. */ - -ISNOTFIXED: -if (group > 0) - { - groupinfo |= GI_NOT_FIXED_LENGTH; - cb->groupinfo[group] = groupinfo; - } -return FFL_NOTFIXED; -} - - - -/************************************************* -* Find first significant op code * -*************************************************/ - -/* This is called by several functions that scan a compiled expression looking -for a fixed first character, or an anchoring op code etc. It skips over things -that do not influence this. For some calls, it makes sense to skip negative -forward and all backward assertions, and also the \b assertion; for others it -does not. - -Arguments: - code pointer to the start of the group - skipassert TRUE if certain assertions are to be skipped - -Returns: pointer to the first significant opcode -*/ - -static const PCRE2_UCHAR* -first_significant_code(PCRE2_SPTR code, BOOL skipassert) -{ -for (;;) - { - switch ((int)*code) - { - case OP_ASSERT_NOT: - case OP_ASSERTBACK: - case OP_ASSERTBACK_NOT: - if (!skipassert) return code; - do code += GET(code, 1); while (*code == OP_ALT); - code += PRIV(OP_lengths)[*code]; - break; - - case OP_WORD_BOUNDARY: - case OP_NOT_WORD_BOUNDARY: - if (!skipassert) return code; - /* Fall through */ - - case OP_CALLOUT: - case OP_CREF: - case OP_DNCREF: - case OP_RREF: - case OP_DNRREF: - case OP_FALSE: - case OP_TRUE: - code += PRIV(OP_lengths)[*code]; - break; - - case OP_CALLOUT_STR: - code += GET(code, 1 + 2*LINK_SIZE); - break; - - default: - return code; - } - } -/* Control never reaches here */ -} - - - -/************************************************* -* Scan compiled branch for non-emptiness * -*************************************************/ - -/* This function scans through a branch of a compiled pattern to see whether it -can match the empty string. It is called at the end of compiling to check the -entire pattern, and from compile_branch() when checking for an unlimited repeat -of a group that can match nothing. In the latter case it is called only when -doing the real compile, not during the pre-compile that measures the size of -the compiled pattern. - -Note that first_significant_code() skips over backward and negative forward -assertions when its final argument is TRUE. If we hit an unclosed bracket, we -return "empty" - this means we've struck an inner bracket whose current branch -will already have been scanned. - -Arguments: - code points to start of search - endcode points to where to stop - utf TRUE if in UTF mode - cb compile data - atend TRUE if being called to check an entire pattern - recurses chain of recurse_check to catch mutual recursion - countptr pointer to count to catch over-complicated pattern - -Returns: 0 if what is matched cannot be empty - 1 if what is matched could be empty - -1 if the pattern is too complicated -*/ - -#define CBE_NOTEMPTY 0 -#define CBE_EMPTY 1 -#define CBE_TOOCOMPLICATED (-1) - - -static int -could_be_empty_branch(PCRE2_SPTR code, PCRE2_SPTR endcode, BOOL utf, - compile_block *cb, BOOL atend, recurse_check *recurses, int *countptr) -{ -uint32_t group = 0; -uint32_t groupinfo = 0; -register PCRE2_UCHAR c; -recurse_check this_recurse; - -/* If what we are checking has already been set as "could be empty", we know -the answer. */ - -if (*code >= OP_SBRA && *code <= OP_SCOND) return CBE_EMPTY; - -/* If this is a capturing group, we may have the answer cached, but we can only -use this information if there are no (?| groups in the pattern, because -otherwise group numbers are not unique. */ - -if ((cb->external_flags & PCRE2_DUPCAPUSED) == 0 && - (*code == OP_CBRA || *code == OP_CBRAPOS)) - { - group = GET2(code, 1 + LINK_SIZE); - groupinfo = cb->groupinfo[group]; - if ((groupinfo & GI_SET_COULD_BE_EMPTY) != 0) - return ((groupinfo & GI_COULD_BE_EMPTY) != 0)? CBE_EMPTY : CBE_NOTEMPTY; - } - -/* A large and/or complex regex can take too long to process. We have to assume -it can match an empty string. This can happen more often when (?| groups are -present in the pattern and the caching is disabled. Setting the cap at 1100 -allows the test for more than 1023 capturing patterns to work. */ - -if ((*countptr)++ > 1100) return CBE_TOOCOMPLICATED; - -/* Scan the opcodes for this branch. */ - -for (code = first_significant_code(code + PRIV(OP_lengths)[*code], TRUE); - code < endcode; - code = first_significant_code(code + PRIV(OP_lengths)[c], TRUE)) - { - PCRE2_SPTR ccode; - - c = *code; - - /* Skip over forward assertions; the other assertions are skipped by - first_significant_code() with a TRUE final argument. */ - - if (c == OP_ASSERT) - { - do code += GET(code, 1); while (*code == OP_ALT); - c = *code; - continue; - } - - /* For a recursion/subroutine call we can scan the recursion when this - function is called at the end, to check a complete pattern. Before then, - recursions just have the group number as their argument and in any case may - be forward references. In that situation, we return CBE_EMPTY, just in case. - It means that unlimited repeats of groups that contain recursions are always - treated as "could be empty" - which just adds a bit more processing time - because of the runtime check. */ - - if (c == OP_RECURSE) - { - PCRE2_SPTR scode, endgroup; - BOOL empty_branch; - - if (!atend) goto ISTRUE; - scode = cb->start_code + GET(code, 1); - endgroup = scode; - - /* We need to detect whether this is a recursive call, as otherwise there - will be an infinite loop. If it is a recursion, just skip over it. Simple - recursions are easily detected. For mutual recursions we keep a chain on - the stack. */ - - do endgroup += GET(endgroup, 1); while (*endgroup == OP_ALT); - if (code >= scode && code <= endgroup) continue; /* Simple recursion */ - else - { - recurse_check *r = recurses; - for (r = recurses; r != NULL; r = r->prev) - if (r->group == scode) break; - if (r != NULL) continue; /* Mutual recursion */ - } - - /* Scan the referenced group, remembering it on the stack chain to detect - mutual recursions. */ - - empty_branch = FALSE; - this_recurse.prev = recurses; - this_recurse.group = scode; - - do - { - int rc = could_be_empty_branch(scode, endcode, utf, cb, atend, - &this_recurse, countptr); - if (rc < 0) return rc; - if (rc > 0) - { - empty_branch = TRUE; - break; - } - scode += GET(scode, 1); - } - while (*scode == OP_ALT); - - if (!empty_branch) goto ISFALSE; /* All branches are non-empty */ - continue; - } - - /* Groups with zero repeats can of course be empty; skip them. */ - - if (c == OP_BRAZERO || c == OP_BRAMINZERO || c == OP_SKIPZERO || - c == OP_BRAPOSZERO) - { - code += PRIV(OP_lengths)[c]; - do code += GET(code, 1); while (*code == OP_ALT); - c = *code; - continue; - } - - /* A nested group that is already marked as "could be empty" can just be - skipped. */ - - if (c == OP_SBRA || c == OP_SBRAPOS || - c == OP_SCBRA || c == OP_SCBRAPOS) - { - do code += GET(code, 1); while (*code == OP_ALT); - c = *code; - continue; - } - - /* For other groups, scan the branches. */ - - if (c == OP_BRA || c == OP_BRAPOS || - c == OP_CBRA || c == OP_CBRAPOS || - c == OP_ONCE || c == OP_ONCE_NC || - c == OP_COND || c == OP_SCOND) - { - BOOL empty_branch; - if (GET(code, 1) == 0) goto ISTRUE; /* Hit unclosed bracket */ - - /* If a conditional group has only one branch, there is a second, implied, - empty branch, so just skip over the conditional, because it could be empty. - Otherwise, scan the individual branches of the group. */ - - if (c == OP_COND && code[GET(code, 1)] != OP_ALT) - code += GET(code, 1); - else - { - empty_branch = FALSE; - do - { - if (!empty_branch) - { - int rc = could_be_empty_branch(code, endcode, utf, cb, atend, - recurses, countptr); - if (rc < 0) return rc; - if (rc > 0) empty_branch = TRUE; - } - code += GET(code, 1); - } - while (*code == OP_ALT); - if (!empty_branch) goto ISFALSE; /* All branches are non-empty */ - } - - c = *code; - continue; - } - - /* Handle the other opcodes */ - - switch (c) - { - /* Check for quantifiers after a class. XCLASS is used for classes that - cannot be represented just by a bit map. This includes negated single - high-valued characters. The length in PRIV(OP_lengths)[] is zero; the - actual length is stored in the compiled code, so we must update "code" - here. */ - -#if defined SUPPORT_UNICODE || PCRE2_CODE_UNIT_WIDTH != 8 - case OP_XCLASS: - ccode = code += GET(code, 1); - goto CHECK_CLASS_REPEAT; -#endif - - case OP_CLASS: - case OP_NCLASS: - ccode = code + PRIV(OP_lengths)[OP_CLASS]; - -#if defined SUPPORT_UNICODE || PCRE2_CODE_UNIT_WIDTH != 8 - CHECK_CLASS_REPEAT: -#endif - - switch (*ccode) - { - case OP_CRSTAR: /* These could be empty; continue */ - case OP_CRMINSTAR: - case OP_CRQUERY: - case OP_CRMINQUERY: - case OP_CRPOSSTAR: - case OP_CRPOSQUERY: - break; - - default: /* Non-repeat => class must match */ - case OP_CRPLUS: /* These repeats aren't empty */ - case OP_CRMINPLUS: - case OP_CRPOSPLUS: - goto ISFALSE; - - case OP_CRRANGE: - case OP_CRMINRANGE: - case OP_CRPOSRANGE: - if (GET2(ccode, 1) > 0) goto ISFALSE; /* Minimum > 0 */ - break; - } - break; - - /* Opcodes that must match a character */ - - case OP_ANY: - case OP_ALLANY: - case OP_ANYBYTE: - - case OP_PROP: - case OP_NOTPROP: - case OP_ANYNL: - - case OP_NOT_HSPACE: - case OP_HSPACE: - case OP_NOT_VSPACE: - case OP_VSPACE: - case OP_EXTUNI: - - case OP_NOT_DIGIT: - case OP_DIGIT: - case OP_NOT_WHITESPACE: - case OP_WHITESPACE: - case OP_NOT_WORDCHAR: - case OP_WORDCHAR: - - case OP_CHAR: - case OP_CHARI: - case OP_NOT: - case OP_NOTI: - - case OP_PLUS: - case OP_PLUSI: - case OP_MINPLUS: - case OP_MINPLUSI: - - case OP_NOTPLUS: - case OP_NOTPLUSI: - case OP_NOTMINPLUS: - case OP_NOTMINPLUSI: - - case OP_POSPLUS: - case OP_POSPLUSI: - case OP_NOTPOSPLUS: - case OP_NOTPOSPLUSI: - - case OP_EXACT: - case OP_EXACTI: - case OP_NOTEXACT: - case OP_NOTEXACTI: - - case OP_TYPEPLUS: - case OP_TYPEMINPLUS: - case OP_TYPEPOSPLUS: - case OP_TYPEEXACT: - goto ISFALSE; - - /* These are going to continue, as they may be empty, but we have to - fudge the length for the \p and \P cases. */ - - case OP_TYPESTAR: - case OP_TYPEMINSTAR: - case OP_TYPEPOSSTAR: - case OP_TYPEQUERY: - case OP_TYPEMINQUERY: - case OP_TYPEPOSQUERY: - if (code[1] == OP_PROP || code[1] == OP_NOTPROP) code += 2; - break; - - /* Same for these */ - - case OP_TYPEUPTO: - case OP_TYPEMINUPTO: - case OP_TYPEPOSUPTO: - if (code[1 + IMM2_SIZE] == OP_PROP || code[1 + IMM2_SIZE] == OP_NOTPROP) - code += 2; - break; - - /* End of branch */ - - case OP_KET: - case OP_KETRMAX: - case OP_KETRMIN: - case OP_KETRPOS: - case OP_ALT: - goto ISTRUE; - - /* In UTF-8 or UTF-16 mode, STAR, MINSTAR, POSSTAR, QUERY, MINQUERY, - POSQUERY, UPTO, MINUPTO, and POSUPTO and their caseless and negative - versions may be followed by a multibyte character. */ - -#ifdef MAYBE_UTF_MULTI - case OP_STAR: - case OP_STARI: - case OP_NOTSTAR: - case OP_NOTSTARI: - - case OP_MINSTAR: - case OP_MINSTARI: - case OP_NOTMINSTAR: - case OP_NOTMINSTARI: - - case OP_POSSTAR: - case OP_POSSTARI: - case OP_NOTPOSSTAR: - case OP_NOTPOSSTARI: - - case OP_QUERY: - case OP_QUERYI: - case OP_NOTQUERY: - case OP_NOTQUERYI: - - case OP_MINQUERY: - case OP_MINQUERYI: - case OP_NOTMINQUERY: - case OP_NOTMINQUERYI: - - case OP_POSQUERY: - case OP_POSQUERYI: - case OP_NOTPOSQUERY: - case OP_NOTPOSQUERYI: - if (utf && HAS_EXTRALEN(code[1])) code += GET_EXTRALEN(code[1]); - break; - - case OP_UPTO: - case OP_UPTOI: - case OP_NOTUPTO: - case OP_NOTUPTOI: - - case OP_MINUPTO: - case OP_MINUPTOI: - case OP_NOTMINUPTO: - case OP_NOTMINUPTOI: - - case OP_POSUPTO: - case OP_POSUPTOI: - case OP_NOTPOSUPTO: - case OP_NOTPOSUPTOI: - if (utf && HAS_EXTRALEN(code[1 + IMM2_SIZE])) code += GET_EXTRALEN(code[1 + IMM2_SIZE]); - break; -#endif /* MAYBE_UTF_MULTI */ - - /* MARK, and PRUNE/SKIP/THEN with an argument must skip over the argument - string. */ - - case OP_MARK: - case OP_PRUNE_ARG: - case OP_SKIP_ARG: - case OP_THEN_ARG: - code += code[1]; - break; - - /* None of the remaining opcodes are required to match a character. */ - - default: - break; - } - } - -ISTRUE: -groupinfo |= GI_COULD_BE_EMPTY; - -ISFALSE: -if (group > 0) cb->groupinfo[group] = groupinfo | GI_SET_COULD_BE_EMPTY; - -return ((groupinfo & GI_COULD_BE_EMPTY) != 0)? CBE_EMPTY : CBE_NOTEMPTY; -} - - - -/************************************************* -* Check for counted repeat * -*************************************************/ - -/* This function is called when a '{' is encountered in a place where it might -start a quantifier. It looks ahead to see if it really is a quantifier, that -is, one of the forms {ddd} {ddd,} or {ddd,ddd} where the ddds are digits. - -Argument: pointer to the first char after '{' -Returns: TRUE or FALSE -*/ - -static BOOL -is_counted_repeat(PCRE2_SPTR p) -{ -if (!IS_DIGIT(*p)) return FALSE; -p++; -while (IS_DIGIT(*p)) p++; -if (*p == CHAR_RIGHT_CURLY_BRACKET) return TRUE; - -if (*p++ != CHAR_COMMA) return FALSE; -if (*p == CHAR_RIGHT_CURLY_BRACKET) return TRUE; - -if (!IS_DIGIT(*p)) return FALSE; -p++; -while (IS_DIGIT(*p)) p++; - -return (*p == CHAR_RIGHT_CURLY_BRACKET); -} - - - -/************************************************* -* Handle escapes * -*************************************************/ - -/* This function is called when a \ has been encountered. It either returns a -positive value for a simple escape such as \d, or 0 for a data character, which -is placed in chptr. A backreference to group n is returned as negative n. On -entry, ptr is pointing at the \. On exit, it points the final code unit of the -escape sequence. - -This function is also called from pcre2_substitute() to handle escape sequences -in replacement strings. In this case, the cb argument is NULL, and only -sequences that define a data character are recognised. The isclass argument is -not relevant, but the options argument is the final value of the compiled -pattern's options. - -There is one "trick" case: when a sequence such as [[:>:]] or \s in UCP mode is -processed, it is replaced by a nested alternative sequence. If this contains a -backslash (which is usually does), ptrend does not point to its end - it still -points to the end of the whole pattern. However, we can detect this case -because cb->nestptr[0] will be non-NULL. The nested sequences are all zero- -terminated and there are only ever two levels of nesting. - -Arguments: - ptrptr points to the input position pointer - ptrend points to the end of the input - chptr points to a returned data character - errorcodeptr points to the errorcode variable (containing zero) - options the current options bits - isclass TRUE if inside a character class - cb compile data block - -Returns: zero => a data character - positive => a special escape sequence - negative => a back reference - on error, errorcodeptr is set non-zero -*/ +Returns: zero => a data character + positive => a special escape sequence + negative => a numerical back reference + on error, errorcodeptr is set non-zero +*/ int PRIV(check_escape)(PCRE2_SPTR *ptrptr, PCRE2_SPTR ptrend, uint32_t *chptr, int *errorcodeptr, uint32_t options, BOOL isclass, compile_block *cb) { BOOL utf = (options & PCRE2_UTF) != 0; -PCRE2_SPTR ptr = *ptrptr + 1; -register uint32_t c, cc; +PCRE2_SPTR ptr = *ptrptr; +uint32_t c, cc; int escape = 0; int i; -/* Find the end of a nested insert. */ - -if (cb != NULL && cb->nestptr[0] != NULL) - ptrend = ptr + PRIV(strlen)(ptr); - /* If backslash is at the end of the string, it's an error. */ if (ptr >= ptrend) @@ -1848,7 +1406,7 @@ if (ptr >= ptrend) } GETCHARINCTEST(c, ptr); /* Get character value, increment pointer */ -ptr--; /* Set pointer back to the last code unit */ +*errorcodeptr = 0; /* Be optimistic */ /* Non-alphanumerics are literals, so we just leave the value in c. An initial value test saves a memory lookup for code points outside the alphanumeric @@ -1862,7 +1420,7 @@ else if ((i = escapes[c - ESCAPES_FIRST]) != 0) if (i > 0) c = (uint32_t)i; else /* Positive is a data character */ { escape = -i; /* Else return a special escape */ - if (escape == ESC_P || escape == ESC_p || escape == ESC_X) + if (cb != NULL && (escape == ESC_P || escape == ESC_p || escape == ESC_X)) cb->external_flags |= PCRE2_HASBKPORX; /* Note \P, \p, or \X */ } } @@ -1874,8 +1432,8 @@ when BSUX is set). */ else { PCRE2_SPTR oldptr; - BOOL braced, negated, overflow; - unsigned int s; + BOOL overflow; + int s; /* Filter calls from pcre2_substitute(). */ @@ -1904,12 +1462,13 @@ else if ((options & PCRE2_ALT_BSUX) == 0) *errorcodeptr = ERR37; else { uint32_t xc; - if ((cc = XDIGIT(ptr[1])) == 0xff) break; /* Not a hex digit */ + if (ptrend - ptr < 4) break; /* Less than 4 chars */ + if ((cc = XDIGIT(ptr[0])) == 0xff) break; /* Not a hex digit */ + if ((xc = XDIGIT(ptr[1])) == 0xff) break; /* Not a hex digit */ + cc = (cc << 4) | xc; if ((xc = XDIGIT(ptr[2])) == 0xff) break; /* Not a hex digit */ cc = (cc << 4) | xc; if ((xc = XDIGIT(ptr[3])) == 0xff) break; /* Not a hex digit */ - cc = (cc << 4) | xc; - if ((xc = XDIGIT(ptr[4])) == 0xff) break; /* Not a hex digit */ c = (cc << 4) | xc; ptr += 4; if (utf) @@ -1921,9 +1480,10 @@ else } break; - case CHAR_U: /* \U is unrecognized unless PCRE2_ALT_BSUX is set, in which case it is an upper case letter. */ + + case CHAR_U: if ((options & PCRE2_ALT_BSUX) == 0) *errorcodeptr = ERR37; break; @@ -1937,87 +1497,71 @@ else (2) Perl 5.10 also supports \g{name} as a reference to a named group. This is part of Perl's movement towards a unified syntax for back references. As this is synonymous with \k{name}, we fudge it up by pretending it really - was \k. + was \k{name}. (3) For Oniguruma compatibility we also support \g followed by a name or a number either in angle brackets or in single quotes. However, these are - (possibly recursive) subroutine calls, _not_ backreferences. Just return - the ESC_g code (cf \k). */ + (possibly recursive) subroutine calls, _not_ backreferences. We return + the ESC_g code. + + Summary: Return a negative number for a numerical back reference, ESC_k for + a named back reference, and ESC_g for a named or numbered subroutine call. + */ case CHAR_g: if (isclass) break; - if (ptr[1] == CHAR_LESS_THAN_SIGN || ptr[1] == CHAR_APOSTROPHE) + + if (ptr >= ptrend) + { + *errorcodeptr = ERR57; + break; + } + + if (*ptr == CHAR_LESS_THAN_SIGN || *ptr == CHAR_APOSTROPHE) { escape = ESC_g; break; } - /* Handle the Perl-compatible cases */ + /* If there is a brace delimiter, try to read a numerical reference. If + there isn't one, assume we have a name and treat it as \k. */ - if (ptr[1] == CHAR_LEFT_CURLY_BRACKET) + if (*ptr == CHAR_LEFT_CURLY_BRACKET) { - PCRE2_SPTR p; - for (p = ptr+2; *p != CHAR_NULL && *p != CHAR_RIGHT_CURLY_BRACKET; p++) - if (*p != CHAR_MINUS && !IS_DIGIT(*p)) break; - if (*p != CHAR_NULL && *p != CHAR_RIGHT_CURLY_BRACKET) + PCRE2_SPTR p = ptr + 1; + if (!read_number(&p, ptrend, cb->bracount, MAX_GROUP_NUMBER, ERR61, &s, + errorcodeptr)) { - escape = ESC_k; + if (*errorcodeptr == 0) escape = ESC_k; /* No number found */ break; } - braced = TRUE; - ptr++; + if (p >= ptrend || *p != CHAR_RIGHT_CURLY_BRACKET) + { + *errorcodeptr = ERR57; + break; + } + ptr = p + 1; } - else braced = FALSE; - if (ptr[1] == CHAR_MINUS) - { - negated = TRUE; - ptr++; - } - else negated = FALSE; + /* Read an undelimited number */ - /* The integer range is limited by the machine's int representation. */ - s = 0; - overflow = FALSE; - while (IS_DIGIT(ptr[1])) + else { - if (s > INT_MAX / 10 - 1) /* Integer overflow */ + if (!read_number(&ptr, ptrend, cb->bracount, MAX_GROUP_NUMBER, ERR61, &s, + errorcodeptr)) { - overflow = TRUE; + if (*errorcodeptr == 0) *errorcodeptr = ERR57; /* No number found */ break; } - s = s * 10 + (unsigned int)(*(++ptr) - CHAR_0); - } - if (overflow) /* Integer overflow */ - { - while (IS_DIGIT(ptr[1])) ptr++; - *errorcodeptr = ERR61; - break; } - if (braced && *(++ptr) != CHAR_RIGHT_CURLY_BRACKET) + if (s <= 0) { - *errorcodeptr = ERR57; - break; - } - - if (s == 0) - { - *errorcodeptr = ERR58; + *errorcodeptr = ERR15; break; } - if (negated) - { - if (s > cb->bracount) - { - *errorcodeptr = ERR15; - break; - } - s = cb->bracount - (s - 1); - } - - escape = -(int)s; + escape = -s; break; /* The handling of escape sequences consisting of a string of digits @@ -2040,31 +1584,18 @@ else if (!isclass) { oldptr = ptr; - /* The integer range is limited by the machine's int representation. */ - s = c - CHAR_0; - overflow = FALSE; - while (IS_DIGIT(ptr[1])) - { - if (s > INT_MAX / 10 - 1) /* Integer overflow */ - { - overflow = TRUE; - break; - } - s = s * 10 + (unsigned int)(*(++ptr) - CHAR_0); - } - if (overflow) /* Integer overflow */ - { - while (IS_DIGIT(ptr[1])) ptr++; - *errorcodeptr = ERR61; + ptr--; /* Back to the digit */ + if (!read_number(&ptr, ptrend, -1, INT_MAX/10 - 1, ERR61, &s, + errorcodeptr)) break; - } /* \1 to \9 are always back references. \8x and \9x are too; \1x to \7x are octal escapes if there are not that many previous captures. */ - if (s < 10 || *oldptr >= CHAR_8 || s <= cb->bracount) + if (s < 10 || oldptr[-1] >= CHAR_8 || s <= (int)cb->bracount) { - escape = -(int)s; /* Indicates a back reference */ + if (s > (int)MAX_GROUP_NUMBER) *errorcodeptr = ERR61; + else escape = -s; /* Indicates a back reference */ break; } ptr = oldptr; /* Put the pointer back and fall through */ @@ -2072,11 +1603,10 @@ else /* Handle a digit following \ when the number is not a back reference, or we are within a character class. If the first digit is 8 or 9, Perl used to - generate a binary zero byte and then treat the digit as a following - literal. At least by Perl 5.18 this changed so as not to insert the binary - zero. */ + generate a binary zero and then treat the digit as a following literal. At + least by Perl 5.18 this changed so as not to insert the binary zero. */ - if ((c = *ptr) >= CHAR_8) break; + if (c >= CHAR_8) break; /* Fall through with a digit less than 8 */ @@ -2088,8 +1618,8 @@ else case CHAR_0: c -= CHAR_0; - while(i++ < 2 && ptr[1] >= CHAR_0 && ptr[1] <= CHAR_7) - c = c * 8 + *(++ptr) - CHAR_0; + while(i++ < 2 && ptr < ptrend && *ptr >= CHAR_0 && *ptr <= CHAR_7) + c = c * 8 + *ptr++ - CHAR_0; #if PCRE2_CODE_UNIT_WIDTH == 8 if (!utf && c > 0xff) *errorcodeptr = ERR51; #endif @@ -2099,13 +1629,18 @@ else specifying character codes in octal. The only supported form is \o{ddd}. */ case CHAR_o: - if (ptr[1] != CHAR_LEFT_CURLY_BRACKET) *errorcodeptr = ERR55; else - if (ptr[2] == CHAR_RIGHT_CURLY_BRACKET) *errorcodeptr = ERR78; else + if (ptr >= ptrend || *ptr++ != CHAR_LEFT_CURLY_BRACKET) + { + ptr--; + *errorcodeptr = ERR55; + } + else if (ptr >= ptrend || *ptr == CHAR_RIGHT_CURLY_BRACKET) + *errorcodeptr = ERR78; + else { - ptr += 2; c = 0; overflow = FALSE; - while (*ptr >= CHAR_0 && *ptr <= CHAR_7) + while (ptr < ptrend && *ptr >= CHAR_0 && *ptr <= CHAR_7) { cc = *ptr++; if (c == 0 && cc == CHAR_0) continue; /* Leading zeroes */ @@ -2123,14 +1658,22 @@ else } if (overflow) { - while (*ptr >= CHAR_0 && *ptr <= CHAR_7) ptr++; + while (ptr < ptrend && *ptr >= CHAR_0 && *ptr <= CHAR_7) ptr++; *errorcodeptr = ERR34; } - else if (*ptr == CHAR_RIGHT_CURLY_BRACKET) + else if (ptr < ptrend && *ptr++ == CHAR_RIGHT_CURLY_BRACKET) + { + if (utf && c >= 0xd800 && c <= 0xdfff) + { + ptr--; + *errorcodeptr = ERR73; + } + } + else { - if (utf && c >= 0xd800 && c <= 0xdfff) *errorcodeptr = ERR73; + ptr--; + *errorcodeptr = ERR64; } - else *errorcodeptr = ERR64; } break; @@ -2141,8 +1684,9 @@ else if ((options & PCRE2_ALT_BSUX) != 0) { uint32_t xc; - if ((cc = XDIGIT(ptr[1])) == 0xff) break; /* Not a hex digit */ - if ((xc = XDIGIT(ptr[2])) == 0xff) break; /* Not a hex digit */ + if (ptrend - ptr < 2) break; /* Less than 2 characters */ + if ((cc = XDIGIT(ptr[0])) == 0xff) break; /* Not a hex digit */ + if ((xc = XDIGIT(ptr[1])) == 0xff) break; /* Not a hex digit */ c = (cc << 4) | xc; ptr += 2; } /* End PCRE2_ALT_BSUX handling */ @@ -2156,10 +1700,9 @@ else else { - if (ptr[1] == CHAR_LEFT_CURLY_BRACKET) + if (ptr < ptrend && *ptr == CHAR_LEFT_CURLY_BRACKET) { - ptr += 2; - if (*ptr == CHAR_RIGHT_CURLY_BRACKET) + if (++ptr >= ptrend || *ptr == CHAR_RIGHT_CURLY_BRACKET) { *errorcodeptr = ERR78; break; @@ -2167,7 +1710,7 @@ else c = 0; overflow = FALSE; - while ((cc = XDIGIT(*ptr)) != 0xff) + while (ptr < ptrend && (cc = XDIGIT(*ptr)) != 0xff) { ptr++; if (c == 0 && cc == 0) continue; /* Leading zeroes */ @@ -2184,12 +1727,16 @@ else if (overflow) { - while (XDIGIT(*ptr) != 0xff) ptr++; + while (ptr < ptrend && XDIGIT(*ptr) != 0xff) ptr++; *errorcodeptr = ERR34; } - else if (*ptr == CHAR_RIGHT_CURLY_BRACKET) + else if (ptr < ptrend && *ptr++ == CHAR_RIGHT_CURLY_BRACKET) { - if (utf && c >= 0xd800 && c <= 0xdfff) *errorcodeptr = ERR73; + if (utf && c >= 0xd800 && c <= 0xdfff) + { + ptr--; + *errorcodeptr = ERR73; + } } /* If the sequence of hex digits does not end with '}', give an error. @@ -2197,18 +1744,22 @@ else \x handling, but nowadays Perl gives an error, which seems much more sensible, so we do too. */ - else *errorcodeptr = ERR67; + else + { + ptr--; + *errorcodeptr = ERR67; + } } /* End of \x{} processing */ - /* Read a single-byte hex-defined char (up to two hex digits after \x) */ + /* Read a up to two hex digits after \x */ else { c = 0; - if ((cc = XDIGIT(ptr[1])) == 0xff) break; /* Not a hex digit */ + if (ptr >= ptrend || (cc = XDIGIT(*ptr)) == 0xff) break; /* Not a hex digit */ ptr++; c = cc; - if ((cc = XDIGIT(ptr[1])) == 0xff) break; /* Not a hex digit */ + if (ptr >= ptrend || (cc = XDIGIT(*ptr)) == 0xff) break; /* Not a hex digit */ ptr++; c = (c << 4) | cc; } /* End of \xdd handling */ @@ -2234,14 +1785,13 @@ else #else case CHAR_c: #endif - - c = *(++ptr); - if (c >= CHAR_a && c <= CHAR_z) c = UPPER_CASE(c); - if (c == CHAR_NULL && ptr >= ptrend) + if (ptr >= ptrend) { *errorcodeptr = ERR2; break; } + c = *ptr; + if (c >= CHAR_a && c <= CHAR_z) c = UPPER_CASE(c); /* Handle \c in an ASCII/Unicode environment. */ @@ -2271,6 +1821,7 @@ else } #endif /* EBCDIC */ + ptr++; break; /* Any other alphanumeric following \ is an error. Perl gives an error only @@ -2278,7 +1829,8 @@ else default: *errorcodeptr = ERR3; - break; + *ptrptr = ptr - 1; /* Point to the character at fault */ + return 0; } } @@ -2286,16 +1838,16 @@ else newline". PCRE does not support \N{name}. However, it does support quantification such as \N{2,3}. */ -if (escape == ESC_N && ptr[1] == CHAR_LEFT_CURLY_BRACKET && - !is_counted_repeat(ptr+2)) - *errorcodeptr = ERR37; - -/* If PCRE2_UCP is set, we change the values for \d etc. */ - -if ((options & PCRE2_UCP) != 0 && escape >= ESC_D && escape <= ESC_w) - escape += (ESC_DU - ESC_D); +if (escape == ESC_N && ptr < ptrend && *ptr == CHAR_LEFT_CURLY_BRACKET && + ptrend - ptr > 2) + { + PCRE2_SPTR p = ptr + 1; + if (!read_repeat_counts(&p, ptrend, NULL, NULL, errorcodeptr) && + *errorcodeptr == 0) + *errorcodeptr = ERR37; + } -/* Set the pointer to the final character before returning. */ +/* Set the pointer to the next character before returning. */ *ptrptr = ptr; *chptr = c; @@ -2311,8 +1863,8 @@ return escape; /* This function is called after \P or \p has been encountered, provided that PCRE2 is compiled with support for UTF and Unicode properties. On entry, the -contents of ptrptr are pointing at the P or p. On exit, it is left pointing at -the final code unit of the escape sequence. +contents of ptrptr are pointing after the P or p. On exit, it is left pointing +after the final code unit of the escape sequence. Arguments: ptrptr the pattern position pointer @@ -2326,30 +1878,33 @@ Returns: TRUE if the type value was found, or FALSE for an invalid type */ static BOOL -get_ucp(PCRE2_SPTR *ptrptr, BOOL *negptr, unsigned int *ptypeptr, - unsigned int *pdataptr, int *errorcodeptr, compile_block *cb) +get_ucp(PCRE2_SPTR *ptrptr, BOOL *negptr, uint16_t *ptypeptr, + uint16_t *pdataptr, int *errorcodeptr, compile_block *cb) { -register PCRE2_UCHAR c; -size_t i, bot, top; +PCRE2_UCHAR c; +PCRE2_SIZE i, bot, top; PCRE2_SPTR ptr = *ptrptr; PCRE2_UCHAR name[32]; +if (ptr >= cb->end_pattern) goto ERROR_RETURN; +c = *ptr++; *negptr = FALSE; -c = *(++ptr); /* \P or \p can be followed by a name in {}, optionally preceded by ^ for negation. */ if (c == CHAR_LEFT_CURLY_BRACKET) { - if (ptr[1] == CHAR_CIRCUMFLEX_ACCENT) + if (ptr >= cb->end_pattern) goto ERROR_RETURN; + if (*ptr == CHAR_CIRCUMFLEX_ACCENT) { *negptr = TRUE; ptr++; } for (i = 0; i < (int)(sizeof(name) / sizeof(PCRE2_UCHAR)) - 1; i++) { - c = *(++ptr); + if (ptr >= cb->end_pattern) goto ERROR_RETURN; + c = *ptr++; if (c == CHAR_NULL) goto ERROR_RETURN; if (c == CHAR_RIGHT_CURLY_BRACKET) break; name[i] = c; @@ -2400,217 +1955,6 @@ return FALSE; -/************************************************* -* Read repeat counts * -*************************************************/ - -/* Read an item of the form {n,m} and return the values. This is called only -after is_counted_repeat() has confirmed that a repeat-count quantifier exists, -so the syntax is guaranteed to be correct, but we need to check the values. - -Arguments: - p pointer to first char after '{' - minp pointer to int for min - maxp pointer to int for max - returned as -1 if no max - errorcodeptr points to error code variable - -Returns: pointer to '}' on success; - current ptr on error, with errorcodeptr set non-zero -*/ - -static PCRE2_SPTR -read_repeat_counts(PCRE2_SPTR p, int *minp, int *maxp, int *errorcodeptr) -{ -int min = 0; -int max = -1; - -while (IS_DIGIT(*p)) - { - min = min * 10 + (int)(*p++ - CHAR_0); - if (min > 65535) - { - *errorcodeptr = ERR5; - return p; - } - } - -if (*p == CHAR_RIGHT_CURLY_BRACKET) max = min; else - { - if (*(++p) != CHAR_RIGHT_CURLY_BRACKET) - { - max = 0; - while(IS_DIGIT(*p)) - { - max = max * 10 + (int)(*p++ - CHAR_0); - if (max > 65535) - { - *errorcodeptr = ERR5; - return p; - } - } - if (max < min) - { - *errorcodeptr = ERR4; - return p; - } - } - } - -*minp = min; -*maxp = max; -return p; -} - - - -/************************************************* -* Scan compiled regex for recursion reference * -*************************************************/ - -/* This function scans through a compiled pattern until it finds an instance of -OP_RECURSE. - -Arguments: - code points to start of expression - utf TRUE in UTF mode - -Returns: pointer to the opcode for OP_RECURSE, or NULL if not found -*/ - -static PCRE2_SPTR -find_recurse(PCRE2_SPTR code, BOOL utf) -{ -for (;;) - { - register PCRE2_UCHAR c = *code; - if (c == OP_END) return NULL; - if (c == OP_RECURSE) return code; - - /* XCLASS is used for classes that cannot be represented just by a bit map. - This includes negated single high-valued characters. CALLOUT_STR is used for - callouts with string arguments. In both cases the length in the table is - zero; the actual length is stored in the compiled code. */ - - if (c == OP_XCLASS) code += GET(code, 1); - else if (c == OP_CALLOUT_STR) code += GET(code, 1 + 2*LINK_SIZE); - - /* Otherwise, we can get the item's length from the table, except that for - repeated character types, we have to test for \p and \P, which have an extra - two bytes of parameters, and for MARK/PRUNE/SKIP/THEN with an argument, we - must add in its length. */ - - else - { - switch(c) - { - case OP_TYPESTAR: - case OP_TYPEMINSTAR: - case OP_TYPEPLUS: - case OP_TYPEMINPLUS: - case OP_TYPEQUERY: - case OP_TYPEMINQUERY: - case OP_TYPEPOSSTAR: - case OP_TYPEPOSPLUS: - case OP_TYPEPOSQUERY: - if (code[1] == OP_PROP || code[1] == OP_NOTPROP) code += 2; - break; - - case OP_TYPEPOSUPTO: - case OP_TYPEUPTO: - case OP_TYPEMINUPTO: - case OP_TYPEEXACT: - if (code[1 + IMM2_SIZE] == OP_PROP || code[1 + IMM2_SIZE] == OP_NOTPROP) - code += 2; - break; - - case OP_MARK: - case OP_PRUNE_ARG: - case OP_SKIP_ARG: - case OP_THEN_ARG: - code += code[1]; - break; - } - - /* Add in the fixed length from the table */ - - code += PRIV(OP_lengths)[c]; - - /* In UTF-8 and UTF-16 modes, opcodes that are followed by a character may - be followed by a multi-unit character. The length in the table is a - minimum, so we have to arrange to skip the extra units. */ - -#ifdef MAYBE_UTF_MULTI - if (utf) switch(c) - { - case OP_CHAR: - case OP_CHARI: - case OP_NOT: - case OP_NOTI: - case OP_EXACT: - case OP_EXACTI: - case OP_NOTEXACT: - case OP_NOTEXACTI: - case OP_UPTO: - case OP_UPTOI: - case OP_NOTUPTO: - case OP_NOTUPTOI: - case OP_MINUPTO: - case OP_MINUPTOI: - case OP_NOTMINUPTO: - case OP_NOTMINUPTOI: - case OP_POSUPTO: - case OP_POSUPTOI: - case OP_NOTPOSUPTO: - case OP_NOTPOSUPTOI: - case OP_STAR: - case OP_STARI: - case OP_NOTSTAR: - case OP_NOTSTARI: - case OP_MINSTAR: - case OP_MINSTARI: - case OP_NOTMINSTAR: - case OP_NOTMINSTARI: - case OP_POSSTAR: - case OP_POSSTARI: - case OP_NOTPOSSTAR: - case OP_NOTPOSSTARI: - case OP_PLUS: - case OP_PLUSI: - case OP_NOTPLUS: - case OP_NOTPLUSI: - case OP_MINPLUS: - case OP_MINPLUSI: - case OP_NOTMINPLUS: - case OP_NOTMINPLUSI: - case OP_POSPLUS: - case OP_POSPLUSI: - case OP_NOTPOSPLUS: - case OP_NOTPOSPLUSI: - case OP_QUERY: - case OP_QUERYI: - case OP_NOTQUERY: - case OP_NOTQUERYI: - case OP_MINQUERY: - case OP_MINQUERYI: - case OP_NOTMINQUERY: - case OP_NOTMINQUERYI: - case OP_POSQUERY: - case OP_POSQUERYI: - case OP_NOTPOSQUERY: - case OP_NOTPOSQUERYI: - if (HAS_EXTRALEN(code[-1])) code += GET_EXTRALEN(code[-1]); - break; - } -#else - (void)(utf); /* Keep compiler happy by referencing function argument */ -#endif /* MAYBE_UTF_MULTI */ - } - } -} - - - /************************************************* * Check for POSIX class syntax * *************************************************/ @@ -2649,25 +1993,28 @@ seem right at all. PCRE does not allow closing square brackets in POSIX class names. Arguments: - ptr pointer to the initial [ + ptr pointer to the character after the initial [ (colon, dot, equals) + ptrend pointer to the end of the pattern endptr where to return a pointer to the terminating ':', '.', or '=' Returns: TRUE or FALSE */ static BOOL -check_posix_syntax(PCRE2_SPTR ptr, PCRE2_SPTR *endptr) +check_posix_syntax(PCRE2_SPTR ptr, PCRE2_SPTR ptrend, PCRE2_SPTR *endptr) { PCRE2_UCHAR terminator; /* Don't combine these lines; the Solaris cc */ -terminator = *(++ptr); /* compiler warns about "non-constant" initializer. */ +terminator = *ptr++; /* compiler warns about "non-constant" initializer. */ -for (++ptr; *ptr != CHAR_NULL; ptr++) +for (; ptrend - ptr >= 2; ptr++) { if (*ptr == CHAR_BACKSLASH && (ptr[1] == CHAR_RIGHT_SQUARE_BRACKET || ptr[1] == CHAR_BACKSLASH)) ptr++; + else if ((*ptr == CHAR_LEFT_SQUARE_BRACKET && ptr[1] == terminator) || *ptr == CHAR_RIGHT_SQUARE_BRACKET) return FALSE; + else if (*ptr == terminator && ptr[1] == CHAR_RIGHT_SQUARE_BRACKET) { *endptr = ptr; @@ -2698,7 +2045,7 @@ static int check_posix_name(PCRE2_SPTR ptr, int len) { const char *pn = posix_names; -register int yield = 0; +int yield = 0; while (posix_name_lengths[yield] != 0) { if (len == posix_name_lengths[yield] && @@ -2711,4338 +2058,3715 @@ return -1; -#ifdef SUPPORT_UNICODE /************************************************* -* Get othercase range * +* Read a subpattern or VERB name * *************************************************/ -/* This function is passed the start and end of a class range in UCT mode. It -searches up the characters, looking for ranges of characters in the "other" -case. Each call returns the next one, updating the start address. A character -with multiple other cases is returned on its own with a special return value. +/* This function is called from parse_regex() below whenever it needs to read +the name of a subpattern or a (*VERB). The initial pointer must be to the +character before the name. If that character is '*' we are reading a verb name. +The pointer is updated to point after the name, for a VERB, or after tha name's +terminator for a subpattern name. Returning both the offset and the name +pointer is redundant information, but some callers use one and some the other, +so it is simplest just to return both. Arguments: - cptr points to starting character value; updated - d end value - ocptr where to put start of othercase range - odptr where to put end of othercase range - -Yield: -1 when no more - 0 when a range is returned - >0 the CASESET offset for char with multiple other cases - in this case, ocptr contains the original + ptrptr points to the character pointer variable + ptrend points to the end of the input string + terminator the terminator of a subpattern name must be this + offsetptr where to put the offset from the start of the pattern + nameptr where to put a pointer to the name in the input + namelenptr where to put the length of the name + errcodeptr where to put an error code + cb pointer to the compile data block + +Returns: TRUE if a name was read + FALSE otherwise, with error code set */ -static int -get_othercase_range(uint32_t *cptr, uint32_t d, uint32_t *ocptr, - uint32_t *odptr) +static BOOL +read_name(PCRE2_SPTR *ptrptr, PCRE2_SPTR ptrend, uint32_t terminator, + PCRE2_SIZE *offsetptr, PCRE2_SPTR *nameptr, uint32_t *namelenptr, + int *errorcodeptr, compile_block *cb) { -uint32_t c, othercase, next; -unsigned int co; +PCRE2_SPTR ptr = *ptrptr; +BOOL is_verb = (*ptr == CHAR_ASTERISK); +uint32_t namelen = 0; +uint32_t ctype = is_verb? ctype_letter : ctype_word; -/* Find the first character that has an other case. If it has multiple other -cases, return its case offset value. */ +if (++ptr >= ptrend) + { + *errorcodeptr = is_verb? ERR60: /* Verb not recognized or malformed */ + ERR62; /* Subpattern name expected */ + goto FAILED; + } -for (c = *cptr; c <= d; c++) +*nameptr = ptr; +*offsetptr = (PCRE2_SIZE)(ptr - cb->start_pattern); + +if (IS_DIGIT(*ptr)) { - if ((co = UCD_CASESET(c)) != 0) + *errorcodeptr = ERR44; /* Group name must not start with digit */ + goto FAILED; + } + +while (ptr < ptrend && MAX_255(*ptr) && (cb->ctypes[*ptr] & ctype) != 0) + { + ptr++; + namelen++; + if (namelen > MAX_NAME_SIZE) { - *ocptr = c++; /* Character that has the set */ - *cptr = c; /* Rest of input range */ - return (int)co; + *errorcodeptr = ERR48; + goto FAILED; } - if ((othercase = UCD_OTHERCASE(c)) != c) break; } -if (c > d) return -1; /* Reached end of range */ - -/* Found a character that has a single other case. Search for the end of the -range, which is either the end of the input range, or a character that has zero -or more than one other cases. */ - -*ocptr = othercase; -next = othercase + 1; +/* Subpattern names must not be empty, and their terminator is checked here. +(What follows a verb name is checked separately.) */ -for (++c; c <= d; c++) +if (!is_verb) { - if ((co = UCD_CASESET(c)) != 0 || UCD_OTHERCASE(c) != next) break; - next++; + if (namelen == 0) + { + *errorcodeptr = ERR62; /* Subpattern name expected */ + goto FAILED; + } + if (ptr >= ptrend || *ptr != (PCRE2_UCHAR)terminator) + { + *errorcodeptr = ERR42; + goto FAILED; + } + ptr++; } -*odptr = next - 1; /* End of othercase range */ -*cptr = c; /* Rest of input range */ -return 0; +*namelenptr = namelen; +*ptrptr = ptr; +return TRUE; + +FAILED: +*ptrptr = ptr; +return FALSE; } -#endif /* SUPPORT_UNICODE */ /************************************************* -* Add a character or range to a class * +* Manage callouts at start of cycle * *************************************************/ -/* This function packages up the logic of adding a character or range of -characters to a class. The character values in the arguments will be within the -valid values for the current mode (8-bit, 16-bit, UTF, etc). This function is -mutually recursive with the function immediately below. +/* At the start of a new item in parse_regex() we are able to record the +details of the previous item in a prior callout, and also to set up an +automatic callout if enabled. Avoid having two adjacent automatic callouts, +which would otherwise happen for items such as \Q that contribute nothing to +the parsed pattern. Arguments: - classbits the bit map for characters < 256 - uchardptr points to the pointer for extra data - options the options word - cb compile data - start start of range character - end end of range character + ptr current pattern pointer + pcalloutptr points to a pointer to previous callout, or NULL + options the compiling options + parsed_pattern the parsed pattern pointer + cb compile block -Returns: the number of < 256 characters added - the pointer to extra data is updated +Returns: possibly updated parsed_pattern pointer. */ -static unsigned int -add_to_class(uint8_t *classbits, PCRE2_UCHAR **uchardptr, uint32_t options, - compile_block *cb, uint32_t start, uint32_t end) +static uint32_t * +manage_callouts(PCRE2_SPTR ptr, uint32_t **pcalloutptr, uint32_t options, + uint32_t *parsed_pattern, compile_block *cb) { -uint32_t c; -uint32_t classbits_end = (end <= 0xff ? end : 0xff); -unsigned int n8 = 0; +uint32_t *previous_callout = *pcalloutptr; -/* If caseless matching is required, scan the range and process alternate -cases. In Unicode, there are 8-bit characters that have alternate cases that -are greater than 255 and vice-versa. Sometimes we can just extend the original -range. */ +if (previous_callout != NULL) previous_callout[2] = ptr - cb->start_pattern - + (PCRE2_SIZE)previous_callout[1]; -if ((options & PCRE2_CASELESS) != 0) +if ((options & PCRE2_AUTO_CALLOUT) == 0) previous_callout = NULL; else { -#ifdef SUPPORT_UNICODE - if ((options & PCRE2_UTF) != 0) + if (previous_callout == NULL || + previous_callout != parsed_pattern - 4 || + previous_callout[3] != 255) { - int rc; - uint32_t oc, od; + previous_callout = parsed_pattern; /* Set up new automatic callout */ + parsed_pattern += 4; + previous_callout[0] = META_CALLOUT_NUMBER; + previous_callout[2] = 0; + previous_callout[3] = 255; + } + previous_callout[1] = (uint32_t)(ptr - cb->start_pattern); + } - options &= ~PCRE2_CASELESS; /* Remove for recursive calls */ - c = start; +*pcalloutptr = previous_callout; +return parsed_pattern; +} - while ((rc = get_othercase_range(&c, end, &oc, &od)) >= 0) - { - /* Handle a single character that has more than one other case. */ - if (rc > 0) n8 += add_list_to_class(classbits, uchardptr, options, cb, - PRIV(ucd_caseless_sets) + rc, oc); - /* Do nothing if the other case range is within the original range. */ +/************************************************* +* Parse regex and identify named groups * +*************************************************/ - else if (oc >= start && od <= end) continue; +/* This function is called first of all. It scans the pattern and does two +things: (1) It identifies capturing groups and makes a table of named capturing +groups so that information about them is fully available to both the compiling +scans. (2) It writes a parsed version of the pattern with comments omitted and +escapes processed into the parsed_pattern vector. - /* Extend the original range if there is overlap, noting that if oc < c, we - can't have od > end because a subrange is always shorter than the basic - range. Otherwise, use a recursive call to add the additional range. */ +Arguments: + ptr points to the start of the pattern + options compiling dynamic options (may change during the scan) + has_lookbehind points to a boolean, set TRUE if a lookbehind is found + cb pointer to the compile data block - else if (oc < start && od >= start - 1) start = oc; /* Extend downwards */ - else if (od > end && oc <= end + 1) - { - end = od; /* Extend upwards */ - if (end > classbits_end) classbits_end = (end <= 0xff ? end : 0xff); - } - else n8 += add_to_class(classbits, uchardptr, options, cb, oc, od); - } - } - else -#endif /* SUPPORT_UNICODE */ +Returns: zero on success or a non-zero error code, with the + error offset placed in the cb field +*/ - /* Not UTF mode */ +/* A structure and some flags for dealing with nested groups. */ - for (c = start; c <= classbits_end; c++) - { - SETBIT(classbits, cb->fcc[c]); - n8++; - } - } +typedef struct nest_save { + uint16_t nest_depth; + uint16_t reset_group; + uint16_t max_group; + uint16_t flags; +} nest_save; -/* Now handle the original range. Adjust the final value according to the bit -length - this means that the same lists of (e.g.) horizontal spaces can be used -in all cases. */ +#define NSF_RESET 0x0001u +#define NSF_EXTENDED 0x0002u +#define NSF_DUPNAMES 0x0004u +#define NSF_CONDASSERT 0x0008u -if ((options & PCRE2_UTF) == 0 && end > MAX_NON_UTF_CHAR) - end = MAX_NON_UTF_CHAR; +/* States used for analyzing ranges in character classes. The two OK values +must be last. */ -/* Use the bitmap for characters < 256. Otherwise use extra data.*/ +enum { RANGE_NO, RANGE_STARTED, RANGE_OK_ESCAPED, RANGE_OK_LITERAL }; -for (c = start; c <= classbits_end; c++) - { - /* Regardless of start, c will always be <= 255. */ - SETBIT(classbits, c); - n8++; +/* Only in 32-bit mode can there be literals > META_END. A macros encapsulates +the storing of literal values in the parsed pattern. */ + +#if PCRE2_CODE_UNIT_WIDTH == 32 +#define PARSED_LITERAL(c, p) \ + { \ + if (c >= META_END) *p++ = META_BIGVALUE; \ + *p++ = c; \ + okquantifier = TRUE; \ } +#else +#define PARSED_LITERAL(c, p) *p++ = c; okquantifier = TRUE; +#endif -#ifdef SUPPORT_WIDE_CHARS -if (start <= 0xff) start = 0xff + 1; +/* Here's the actual function. */ -if (end >= start) +static int parse_regex(PCRE2_SPTR ptr, uint32_t options, BOOL *has_lookbehind, + compile_block *cb) +{ +uint32_t c; +uint32_t delimiter; +uint32_t namelen; +uint32_t class_range_state; +uint32_t *verblengthptr = NULL; /* Value avoids compiler warning */ +uint32_t *previous_callout = NULL; +uint32_t *parsed_pattern = cb->parsed_pattern; +uint32_t *parsed_pattern_end = cb->parsed_pattern_end; +uint32_t meta_quantifier = 0; +uint16_t nest_depth = 0; +int after_manual_callout = 0; +int expect_cond_assert = 0; +int errorcode = 0; +int escape; +int i; +BOOL inescq = FALSE; +BOOL inverbname = FALSE; +BOOL utf = (options & PCRE2_UTF) != 0; +BOOL isdupname; +BOOL negate_class; +BOOL okquantifier = FALSE; +PCRE2_SPTR name; +PCRE2_SPTR ptrend = cb->end_pattern; +PCRE2_SPTR verbnamestart = NULL; /* Value avoids compiler warning */ +named_group *ng; +nest_save *top_nest = NULL; +nest_save *end_nests = (nest_save *)(cb->start_workspace + cb->workspace_size); + +/* The size of the nest_save structure might not be a factor of the size of the +workspace. Therefore we must round down end_nests so as to correctly avoid +creating a nest_save that spans the end of the workspace. */ + +end_nests = (nest_save *)((char *)end_nests - + ((cb->workspace_size * sizeof(PCRE2_UCHAR)) % sizeof(nest_save))); + +/* Now scan the pattern */ + +*has_lookbehind = FALSE; + +while (ptr < ptrend) { - PCRE2_UCHAR *uchardata = *uchardptr; + int prev_expect_cond_assert; + uint32_t min_repeat, max_repeat; + uint32_t set, unset, *optset; + uint32_t terminator; + uint32_t prev_meta_quantifier; + BOOL prev_okquantifier; + PCRE2_SPTR tempptr; + PCRE2_SPTR thisptr; + PCRE2_SIZE offset; + + if (parsed_pattern >= parsed_pattern_end) + { + errorcode = ERR63; /* Internal error (parsed pattern overflow) */ + goto FAILED; + } -#ifdef SUPPORT_UNICODE - if ((options & PCRE2_UTF) != 0) + if (nest_depth > cb->cx->parens_nest_limit) { - if (start < end) + errorcode = ERR19; + goto FAILED; + } + + /* Get next input character, save its position for callout handling. */ + + thisptr = ptr; + GETCHARINCTEST(c, ptr); + + /* Copy quoted literals until \E, allowing for the possibility of automatic + callouts, except when processing a (*VERB) "name". */ + + if (inescq) + { + if (c == CHAR_BACKSLASH && ptr < ptrend && *ptr == CHAR_E) { - *uchardata++ = XCL_RANGE; - uchardata += PRIV(ord2utf)(start, uchardata); - uchardata += PRIV(ord2utf)(end, uchardata); + inescq = FALSE; + ptr++; /* Skip E */ } - else if (start == end) + else { - *uchardata++ = XCL_SINGLE; - uchardata += PRIV(ord2utf)(start, uchardata); + if (expect_cond_assert > 0) /* A literal is not allowed if we are */ + { /* expecting a conditional assertion, */ + ptr--; /* but an empty \Q\E sequence is OK. */ + errorcode = ERR28; + goto FAILED; + } + if (!inverbname && after_manual_callout-- <= 0) + parsed_pattern = manage_callouts(thisptr, &previous_callout, options, + parsed_pattern, cb); + PARSED_LITERAL(c, parsed_pattern); + meta_quantifier = 0; } + continue; /* Next character */ } - else -#endif /* SUPPORT_UNICODE */ - - /* Without UTF support, character values are constrained by the bit length, - and can only be > 256 for 16-bit and 32-bit libraries. */ -#if PCRE2_CODE_UNIT_WIDTH == 8 - {} -#else - if (start < end) - { - *uchardata++ = XCL_RANGE; - *uchardata++ = start; - *uchardata++ = end; - } - else if (start == end) + /* If we are processing the "name" part of a (*VERB:NAME) item, all + characters up to the closing parenthesis are literals except when + PCRE2_ALT_VERBNAMES is set. That causes backslash interpretation, but only \Q + and \E and escaped characters are allowed (no character types such as \d). If + PCRE2_EXTENDED is also set, we must ignore white space and # comments. Do + this by not entering the special (*VERB:NAME) processing - they are then + picked up below. Note that c is a character, not a code unit, so we must not + use MAX_255 to test its size because MAX_255 tests code units and is assumed + TRUE in 8-bit mode. */ + + if (inverbname && + ( + /* EITHER: not both options set */ + ((options & (PCRE2_EXTENDED | PCRE2_ALT_VERBNAMES)) != + (PCRE2_EXTENDED | PCRE2_ALT_VERBNAMES)) || + /* OR: character > 255 */ + c > 255 || + /* OR: not a # comment or white space */ + (c != CHAR_NUMBER_SIGN && (cb->ctypes[c] & ctype_space) == 0) + )) { - *uchardata++ = XCL_SINGLE; - *uchardata++ = start; - } -#endif - *uchardptr = uchardata; /* Updata extra data pointer */ - } -#else - (void)uchardptr; /* Avoid compiler warning */ -#endif /* SUPPORT_WIDE_CHARS */ + PCRE2_SIZE verbnamelength; -return n8; /* Number of 8-bit characters */ -} + switch(c) + { + default: + PARSED_LITERAL(c, parsed_pattern); + break; + case CHAR_RIGHT_PARENTHESIS: + inverbname = FALSE; + okquantifier = FALSE; /* Was probably set by literals */ + /* This is the length in characters */ + verbnamelength = (PCRE2_SIZE)(parsed_pattern - verblengthptr - 1); + /* But the limit on the length is in code units */ + if (ptr - verbnamestart - 1 > (int)MAX_MARK) + { + ptr--; + errorcode = ERR76; + goto FAILED; + } + *verblengthptr = (uint32_t)verbnamelength; + break; + case CHAR_BACKSLASH: + if ((options & PCRE2_ALT_VERBNAMES) != 0) + { + escape = PRIV(check_escape)(&ptr, ptrend, &c, &errorcode, options, + FALSE, cb); + if (errorcode != 0) goto FAILED; + } + else escape = 0; /* Treat all as literal */ -/************************************************* -* Add a list of characters to a class * -*************************************************/ + switch(escape) + { + case 0: + PARSED_LITERAL(c, parsed_pattern); + break; -/* This function is used for adding a list of case-equivalent characters to a -class, and also for adding a list of horizontal or vertical whitespace. If the -list is in order (which it should be), ranges of characters are detected and -handled appropriately. This function is mutually recursive with the function -above. + case ESC_Q: + inescq = TRUE; + break; -Arguments: - classbits the bit map for characters < 256 - uchardptr points to the pointer for extra data - options the options word - cb contains pointers to tables etc. - p points to row of 32-bit values, terminated by NOTACHAR - except character to omit; this is used when adding lists of - case-equivalent characters to avoid including the one we - already know about + case ESC_E: /* Ignore */ + break; -Returns: the number of < 256 characters added - the pointer to extra data is updated -*/ + default: + errorcode = ERR40; /* Invalid in verb name */ + goto FAILED; + } + } + continue; /* Next character in pattern */ + } -static unsigned int -add_list_to_class(uint8_t *classbits, PCRE2_UCHAR **uchardptr, uint32_t options, - compile_block *cb, const uint32_t *p, unsigned int except) -{ -unsigned int n8 = 0; -while (p[0] < NOTACHAR) - { - unsigned int n = 0; - if (p[0] != except) - { - while(p[n+1] == p[0] + n + 1) n++; - n8 += add_to_class(classbits, uchardptr, options, cb, p[0], p[n]); - } - p += n + 1; - } -return n8; -} - - - -/************************************************* -* Add characters not in a list to a class * -*************************************************/ - -/* This function is used for adding the complement of a list of horizontal or -vertical whitespace to a class. The list must be in order. - -Arguments: - classbits the bit map for characters < 256 - uchardptr points to the pointer for extra data - options the options word - cb contains pointers to tables etc. - p points to row of 32-bit values, terminated by NOTACHAR - -Returns: the number of < 256 characters added - the pointer to extra data is updated -*/ - -static unsigned int -add_not_list_to_class(uint8_t *classbits, PCRE2_UCHAR **uchardptr, - uint32_t options, compile_block *cb, const uint32_t *p) -{ -BOOL utf = (options & PCRE2_UTF) != 0; -unsigned int n8 = 0; -if (p[0] > 0) - n8 += add_to_class(classbits, uchardptr, options, cb, 0, p[0] - 1); -while (p[0] < NOTACHAR) - { - while (p[1] == p[0] + 1) p++; - n8 += add_to_class(classbits, uchardptr, options, cb, p[0] + 1, - (p[1] == NOTACHAR) ? (utf ? 0x10ffffu : 0xffffffffu) : p[1] - 1); - p++; - } -return n8; -} - - - -/************************************************* -* Process (*VERB) name for escapes * -*************************************************/ - -/* This function is called when the PCRE2_ALT_VERBNAMES option is set, to -process the characters in a verb's name argument. It is called twice, once with -codeptr == NULL, to find out the length of the processed name, and again to put -the name into memory. - -Arguments: - ptrptr pointer to the input pointer - codeptr pointer to the compiled code pointer - errorcodeptr pointer to the error code - options the options bits - utf TRUE if processing UTF - cb compile data block - -Returns: length of the processed name, or < 0 on error -*/ - -static int -process_verb_name(PCRE2_SPTR *ptrptr, PCRE2_UCHAR **codeptr, int *errorcodeptr, - uint32_t options, BOOL utf, compile_block *cb) -{ -int32_t arglen = 0; -BOOL inescq = FALSE; -PCRE2_SPTR ptr = *ptrptr; -PCRE2_UCHAR *code = (codeptr == NULL)? NULL : *codeptr; - -for (; ptr < cb->end_pattern; ptr++) - { - uint32_t x = *ptr; + /* Not a verb name character. At this point we must process everything that + must not change the quantification state. This is mainly comments, but we + handle \Q and \E here as well, so that an item such as A\Q\E+ is treated as + A+, as in Perl. An isolated \E is ignored. */ - /* Skip over literals */ - - if (inescq) + if (c == CHAR_BACKSLASH && ptr < ptrend) { - if (x == CHAR_BACKSLASH && ptr[1] == CHAR_E) + if (*ptr == CHAR_Q || *ptr == CHAR_E) { - inescq = FALSE; - ptr++;; + inescq = *ptr == CHAR_Q; + ptr++; continue; } } - else /* Not a literal character */ - { - if (x == CHAR_RIGHT_PARENTHESIS) break; - - /* Skip over comments and whitespace in extended mode. */ + /* Skip over whitespace and # comments in extended mode. Note that c is a + character, not a code unit, so we must not use MAX_255 to test its size + because MAX_255 tests code units and is assumed TRUE in 8-bit mode. */ - if ((options & PCRE2_EXTENDED) != 0) + if ((options & PCRE2_EXTENDED) != 0) + { + if (c < 256 && (cb->ctypes[c] & ctype_space) != 0) continue; + if (c == CHAR_NUMBER_SIGN) { - PCRE2_SPTR wscptr = ptr; - while (MAX_255(x) && (cb->ctypes[x] & ctype_space) != 0) x = *(++ptr); - if (x == CHAR_NUMBER_SIGN) + while (ptr < ptrend) { + if (IS_NEWLINE(ptr)) /* For non-fixed-length newline cases, */ + { /* IS_NEWLINE sets cb->nllen. */ + ptr += cb->nllen; + break; + } ptr++; - while (*ptr != CHAR_NULL || ptr < cb->end_pattern) - { - if (IS_NEWLINE(ptr)) /* For non-fixed-length newline cases, */ - { /* IS_NEWLINE sets cb->nllen. */ - ptr += cb->nllen; - break; - } - ptr++; #ifdef SUPPORT_UNICODE - if (utf) FORWARDCHAR(ptr); + if (utf) FORWARDCHARTEST(ptr, ptrend); #endif - } - } - - /* If we have skipped any characters, restart the loop. */ - - if (ptr > wscptr) - { - ptr--; - continue; - } - } - - /* Process escapes */ - - if (x == '\\') - { - int rc; - *errorcodeptr = 0; - rc = PRIV(check_escape)(&ptr, cb->end_pattern, &x, errorcodeptr, options, - FALSE, cb); - *ptrptr = ptr; /* For possible error */ - if (*errorcodeptr != 0) return -1; - if (rc != 0) - { - if (rc == ESC_Q) - { - inescq = TRUE; - continue; - } - if (rc == ESC_E) continue; - *errorcodeptr = ERR40; - return -1; } + continue; /* Next character in pattern */ } } - /* We have the next character in the name. */ + /* Skip over bracketed comments */ -#ifdef SUPPORT_UNICODE - if (utf) + if (c == CHAR_LEFT_PARENTHESIS && ptrend - ptr >= 2 && + ptr[0] == CHAR_QUESTION_MARK && ptr[1] == CHAR_NUMBER_SIGN) { - if (code == NULL) /* Just want the length */ - { -#if PCRE2_CODE_UNIT_WIDTH == 8 - int i; - for (i = 0; i < PRIV(utf8_table1_size); i++) - if ((int)x <= PRIV(utf8_table1)[i]) break; - arglen += i; -#elif PCRE2_CODE_UNIT_WIDTH == 16 - if (x > 0xffff) arglen++; -#endif - } - else + while (++ptr < ptrend && *ptr != CHAR_RIGHT_PARENTHESIS); + if (ptr >= ptrend) { - PCRE2_UCHAR cbuff[8]; - x = PRIV(ord2utf)(x, cbuff); - memcpy(code, cbuff, CU2BYTES(x)); - code += x; + errorcode = ERR18; /* A special error for missing ) in a comment */ + goto FAILED; /* to make it easier to debug. */ } - } - else -#endif /* SUPPORT_UNICODE */ - - /* Not UTF */ - { - if (code != NULL) *code++ = (PCRE2_UCHAR)x; + ptr++; + continue; /* Next character in pattern */ } - arglen++; + /* If the next item is not a quantifier, fill in length of any previous + callout and create an auto callout if required. */ - if ((unsigned int)arglen > MAX_MARK) + if (c != CHAR_ASTERISK && c != CHAR_PLUS && c != CHAR_QUESTION_MARK && + (c != CHAR_LEFT_CURLY_BRACKET || + (tempptr = ptr, + !read_repeat_counts(&tempptr, ptrend, NULL, NULL, &errorcode)))) { - *errorcodeptr = ERR76; - *ptrptr = ptr; - return -1; + if (after_manual_callout-- <= 0) + parsed_pattern = manage_callouts(thisptr, &previous_callout, options, + parsed_pattern, cb); } - } -/* Update the pointers before returning. */ + /* If expect_cond_assert is 2, we have just passed (?( and are expecting an + assertion, possibly preceded by a callout. If the value is 1, we have just + had the callout and expect an assertion. There must be at least 3 more + characters in all cases. When expect_cond_assert is 2, we know that the + current character is an opening parenthesis, as otherwise we wouldn't be + here. However, when it is 1, we need to check, and it's easiest just to check + always. Note that expect_cond_assert may be negative, since all callouts just + decrement it. */ -*ptrptr = ptr; -if (codeptr != NULL) *codeptr = code; -return arglen; -} + if (expect_cond_assert > 0) + { + BOOL ok = c == CHAR_LEFT_PARENTHESIS && ptrend - ptr >= 3 && + ptr[0] == CHAR_QUESTION_MARK; + if (ok) switch(ptr[1]) + { + case CHAR_C: + ok = expect_cond_assert == 2; + break; + case CHAR_EQUALS_SIGN: + case CHAR_EXCLAMATION_MARK: + break; + case CHAR_LESS_THAN_SIGN: + ok = ptr[2] == CHAR_EQUALS_SIGN || ptr[2] == CHAR_EXCLAMATION_MARK; + break; -/************************************************* -* Macro for the next two functions * -*************************************************/ + default: + ok = FALSE; + } -/* Both scan_for_captures() and compile_branch() use this macro to generate a -fragment of code that reads the characters of a name and sets its length -(checking for not being too long). Count the characters dynamically, to avoid -the possibility of integer overflow. The same macro is used for reading *VERB -names. */ - -#define READ_NAME(ctype, errno, errset) \ - namelen = 0; \ - while (MAX_255(*ptr) && (cb->ctypes[*ptr] & ctype) != 0) \ - { \ - ptr++; \ - namelen++; \ - if (namelen > MAX_NAME_SIZE) \ - { \ - errset = errno; \ - goto FAILED; \ - } \ + if (!ok) + { + ptr--; /* Adjust error offset */ + errorcode = ERR28; + goto FAILED; + } } + /* Remember whether we are expecting a conditional assertion, and set the + default for this item. */ + prev_expect_cond_assert = expect_cond_assert; + expect_cond_assert = 0; -/************************************************* -* Scan regex to identify named groups * -*************************************************/ - -/* This function is called first of all, to scan for named capturing groups so -that information about them is fully available to both the compiling scans. -It skips over everything except parenthesized items. - -Arguments: - ptrptr points to pointer to the start of the pattern - options compiling dynamic options - cb pointer to the compile data block - -Returns: zero on success or a non-zero error code, with pointer updated -*/ - -typedef struct nest_save { - uint16_t nest_depth; - uint16_t reset_group; - uint16_t max_group; - uint16_t flags; -} nest_save; - -#define NSF_RESET 0x0001u -#define NSF_EXTENDED 0x0002u -#define NSF_DUPNAMES 0x0004u - -static int scan_for_captures(PCRE2_SPTR *ptrptr, uint32_t options, - compile_block *cb) -{ -uint32_t c; -uint32_t delimiter; -uint32_t set, unset, *optset; -uint32_t skiptoket = 0; -uint16_t nest_depth = 0; -int errorcode = 0; -int escape; -int namelen; -int i; -BOOL inescq = FALSE; -BOOL isdupname; -BOOL utf = (options & PCRE2_UTF) != 0; -BOOL negate_class; -PCRE2_SPTR name; -PCRE2_SPTR start; -PCRE2_SPTR ptr = *ptrptr; -named_group *ng; -nest_save *top_nest = NULL; -nest_save *end_nests = (nest_save *)(cb->start_workspace + cb->workspace_size); - -/* The size of the nest_save structure might not be a factor of the size of the -workspace. Therefore we must round down end_nests so as to correctly avoid -creating a nest_save that spans the end of the workspace. */ - -end_nests = (nest_save *)((char *)end_nests - - ((cb->workspace_size * sizeof(PCRE2_UCHAR)) % sizeof(nest_save))); - -/* Now scan the pattern */ - -for (; ptr < cb->end_pattern; ptr++) - { - c = *ptr; - - /* Parenthesized groups set skiptoket when all following characters up to the - next closing parenthesis must be ignored. The parenthesis itself must be - processed (to end the nested parenthesized item). */ + /* Remember quantification status for the previous significant item, then set + default for this item. */ - if (skiptoket != 0) - { - if (c != CHAR_RIGHT_PARENTHESIS) continue; - skiptoket = 0; - } + prev_okquantifier = okquantifier; + prev_meta_quantifier = meta_quantifier; + okquantifier = FALSE; + meta_quantifier = 0; - /* Skip over literals */ + /* If the previous significant item was a quantifier, adjust the parsed code + if there is a following modifier. The base meta value is always followed by + the PLUS and QUERY values, in that order. We do this here rather than after + reading a quantifier so that intervening comments and /x whitespace can be + ignored without having to replicate code. */ - if (inescq) + if (prev_meta_quantifier != 0 && (c == CHAR_QUESTION_MARK || c == CHAR_PLUS)) { - if (c == CHAR_BACKSLASH && ptr[1] == CHAR_E) - { - inescq = FALSE; - ptr++; - } - continue; + parsed_pattern[(prev_meta_quantifier == META_MINMAX)? -3 : -1] = + prev_meta_quantifier + ((c == CHAR_QUESTION_MARK)? + 0x00020000u : 0x00010000u); + continue; /* Next character in pattern */ } - /* Skip over # comments and whitespace in extended mode. */ - - if ((options & PCRE2_EXTENDED) != 0) - { - PCRE2_SPTR wscptr = ptr; - while (MAX_255(c) && (cb->ctypes[c] & ctype_space) != 0) c = *(++ptr); - if (c == CHAR_NUMBER_SIGN) - { - ptr++; - while (ptr < cb->end_pattern) - { - if (IS_NEWLINE(ptr)) /* For non-fixed-length newline cases, */ - { /* IS_NEWLINE sets cb->nllen. */ - ptr += cb->nllen; - break; - } - ptr++; -#ifdef SUPPORT_UNICODE - if (utf) FORWARDCHAR(ptr); -#endif - } - } - - /* If we skipped any characters, restart the loop. Otherwise, we didn't see - a comment. */ - - if (ptr > wscptr) - { - ptr--; - continue; - } - } - /* Process the next pattern item. */ + /* Process the next item in the main part of a pattern. */ switch(c) { - default: /* Most characters are just skipped */ + default: /* Non-special character */ + PARSED_LITERAL(c, parsed_pattern); break; - /* Skip escapes except for \Q */ + + /* ---- Escape sequence ---- */ case CHAR_BACKSLASH: - errorcode = 0; - escape = PRIV(check_escape)(&ptr, cb->end_pattern, &c, &errorcode, options, + escape = PRIV(check_escape)(&ptr, ptrend, &c, &errorcode, options, FALSE, cb); if (errorcode != 0) goto FAILED; - if (escape == ESC_Q) inescq = TRUE; - break; - /* Skip a character class. The syntax is complicated so we have to - replicate some of what happens when a class is processed for real. */ + /* The escape was a data character. */ - case CHAR_LEFT_SQUARE_BRACKET: - if (PRIV(strncmp_c8)(ptr+1, STRING_WEIRD_STARTWORD, 6) == 0 || - PRIV(strncmp_c8)(ptr+1, STRING_WEIRD_ENDWORD, 6) == 0) + if (escape == 0) { - ptr += 6; - break; + PARSED_LITERAL(c, parsed_pattern); } - /* If the first character is '^', set the negation flag (not actually used - here, except to recognize only one ^) and skip it. If the first few - characters (either before or after ^) are \Q\E or \E we skip them too. This - makes for compatibility with Perl. */ + /* The escape was a back (or forward) reference. We keep the offset in + order to give a more useful diagnostic for a bad forward reference. For + references to groups numbered less than 10 we can't use more than two items + in parsed_pattern because they may be just two characters in the input (and + in a 64-bit world an offset may need two elements). So for them, the offset + of the first occurrent is held in a special vector. */ - negate_class = FALSE; - for (;;) + else if (escape < 0) { - c = *(++ptr); /* First character in class */ - if (c == CHAR_BACKSLASH) + offset = (PCRE2_SIZE)(ptr - cb->start_pattern - 1); + escape = -escape; + *parsed_pattern++ = META_BACKREF | (uint32_t)escape; + if (escape < 10) { - if (ptr[1] == CHAR_E) - ptr++; - else if (PRIV(strncmp_c8)(ptr + 1, STR_Q STR_BACKSLASH STR_E, 3) == 0) - ptr += 3; - else - break; + if (cb->small_ref_offset[escape] == PCRE2_UNSET) + cb->small_ref_offset[escape] = offset; } - else if (!negate_class && c == CHAR_CIRCUMFLEX_ACCENT) - negate_class = TRUE; - else break; + else + { + PUTOFFSET(offset, parsed_pattern); + } + okquantifier = TRUE; } - if (c == CHAR_RIGHT_SQUARE_BRACKET && - (cb->external_options & PCRE2_ALLOW_EMPTY_CLASS) != 0) - break; - - /* Loop for the contents of the class */ - - for (;;) + /* The escape was a character class such as \d etc. or other special + escape indicator such as \A or \X. Most of them generate just a single + parsed item, but \P and \p are followed by a 16-bit type and a 16-bit + value. They are supported only when Unicode is available. The type and + value are packed into a single 32-bit value so that the whole sequences + uses only two elements in the parsed_vector. This is because the same + coding is used if \d (for example) is turned into \p{Nd} when PCRE2_UCP is + set. + + There are also some cases where the escape sequence is followed by a name: + \k{name}, \k, and \k'name' are backreferences by name, and \g + and \g'name' are subroutine calls by name; \g{name} is a synonym for + \k{name}. Note that \g and \g'number' are handled by check_escape() + and returned as a negative value (handled above). A name is coded as an + offset into the pattern and a length. */ + + else switch (escape) { - PCRE2_SPTR tempptr; - - if (c == CHAR_NULL && ptr >= cb->end_pattern) + case ESC_C: +#ifdef NEVER_BACKSLASH_C + errorcode = ERR85; + goto FAILED; +#else + if ((options & PCRE2_NEVER_BACKSLASH_C) != 0) { - errorcode = ERR6; /* Missing terminating ']' */ + errorcode = ERR83; goto FAILED; } +#endif + okquantifier = TRUE; + *parsed_pattern++ = META_ESCAPE + escape; + break; -#ifdef SUPPORT_UNICODE - if (utf && HAS_EXTRALEN(c)) - { /* Braces are required because the */ - GETCHARLEN(c, ptr, ptr); /* macro generates multiple statements */ - } + case ESC_X: +#ifndef SUPPORT_UNICODE + errorcode = ERR45; /* Supported only with Unicode support */ + goto FAILED; #endif + case ESC_H: + case ESC_h: + case ESC_N: + case ESC_R: + case ESC_V: + case ESC_v: + okquantifier = TRUE; + *parsed_pattern++ = META_ESCAPE + escape; + break; - /* Inside \Q...\E everything is literal except \E */ + default: /* \A, \B, \b, \G, \K, \Z, \z cannot be quantified. */ + *parsed_pattern++ = META_ESCAPE + escape; + break; - if (inescq) + /* Escapes that change in UCP mode. Note that PCRE2_UCP will never be set + without Unicode support because it is checked when pcre2_compile() is + called. */ + + case ESC_d: + case ESC_D: + case ESC_s: + case ESC_S: + case ESC_w: + case ESC_W: + okquantifier = TRUE; + if ((options & PCRE2_UCP) == 0) { - if (c == CHAR_BACKSLASH && ptr[1] == CHAR_E) /* If we are at \E */ - { - inescq = FALSE; /* Reset literal state */ - ptr++; /* Skip the 'E' */ - } - goto CONTINUE_CLASS; + *parsed_pattern++ = META_ESCAPE + escape; } - - /* Skip POSIX class names. */ - if (c == CHAR_LEFT_SQUARE_BRACKET && - (ptr[1] == CHAR_COLON || ptr[1] == CHAR_DOT || - ptr[1] == CHAR_EQUALS_SIGN) && check_posix_syntax(ptr, &tempptr)) + else { - ptr = tempptr + 1; - } - else if (c == CHAR_BACKSLASH) - { - errorcode = 0; - escape = PRIV(check_escape)(&ptr, cb->end_pattern, &c, &errorcode, - options, TRUE, cb); - if (errorcode != 0) goto FAILED; - if (escape == ESC_Q) inescq = TRUE; - } + *parsed_pattern++ = META_ESCAPE + + ((escape == ESC_d || escape == ESC_s || escape == ESC_w)? + ESC_p : ESC_P); + switch(escape) + { + case ESC_d: + case ESC_D: + *parsed_pattern++ = (PT_PC << 16) | ucp_Nd; + break; - CONTINUE_CLASS: - c = *(++ptr); - if (c == CHAR_RIGHT_SQUARE_BRACKET && !inescq) break; - } /* End of class-processing loop */ - break; + case ESC_s: + case ESC_S: + *parsed_pattern++ = PT_SPACE << 16; + break; - /* This is the real work of this function - handling parentheses. */ + case ESC_w: + case ESC_W: + *parsed_pattern++ = PT_WORD << 16; + break; + } + } + break; - case CHAR_LEFT_PARENTHESIS: - nest_depth++; + /* Unicode property matching */ - if (ptr[1] != CHAR_QUESTION_MARK) - { - if (ptr[1] != CHAR_ASTERISK) + case ESC_P: + case ESC_p: +#ifdef SUPPORT_UNICODE + { + BOOL negated; + uint16_t ptype = 0, pdata = 0; + if (!get_ucp(&ptr, &negated, &ptype, &pdata, &errorcode, cb)) + goto FAILED; + if (negated) escape = (escape == ESC_P)? ESC_p : ESC_P; + *parsed_pattern++ = META_ESCAPE + escape; + *parsed_pattern++ = (ptype << 16) | pdata; + okquantifier = TRUE; + } +#else + errorcode = ERR45; + goto FAILED; +#endif + break; /* End \P and \p */ + + /* When \g is used with quotes or angle brackets as delimiters, it is a + numerical or named subroutine call, and control comes here. When used + with brace delimiters it is a numberical back reference and does not come + here because check_escape() returns it directly as a reference. \k is + always a named back reference. */ + + case ESC_g: + case ESC_k: + if (ptr >= ptrend || (*ptr != CHAR_LEFT_CURLY_BRACKET && + *ptr != CHAR_LESS_THAN_SIGN && *ptr != CHAR_APOSTROPHE)) { - if ((options & PCRE2_NO_AUTO_CAPTURE) == 0) cb->bracount++; + errorcode = (escape == ESC_g)? ERR57 : ERR69; + goto FAILED; } + terminator = (*ptr == CHAR_LESS_THAN_SIGN)? + CHAR_GREATER_THAN_SIGN : (*ptr == CHAR_APOSTROPHE)? + CHAR_APOSTROPHE : CHAR_RIGHT_CURLY_BRACKET; - /* (*something) - skip over a name, and then just skip to closing ket - unless PCRE2_ALT_VERBNAMES is set, in which case we have to process - escapes in the string after a verb name terminated by a colon. */ + /* For a non-braced \g, check for a numerical recursion. */ - else + if (escape == ESC_g && terminator != CHAR_RIGHT_CURLY_BRACKET) { - ptr += 2; - while (MAX_255(*ptr) && (cb->ctypes[*ptr] & ctype_word) != 0) ptr++; - if (*ptr == CHAR_COLON && (options & PCRE2_ALT_VERBNAMES) != 0) + PCRE2_SPTR p = ptr + 1; + + if (read_number(&p, ptrend, cb->bracount, MAX_GROUP_NUMBER, ERR61, &i, + &errorcode)) { - ptr++; - if (process_verb_name(&ptr, NULL, &errorcode, options, utf, cb) < 0) + if (p >= ptrend || *p != terminator) + { + errorcode = ERR57; goto FAILED; + } + ptr = p; + goto SET_RECURSION; } - else - { - while (ptr < cb->end_pattern && *ptr != CHAR_RIGHT_PARENTHESIS) - ptr++; - } - nest_depth--; + if (errorcode != 0) goto FAILED; } - } - /* Handle (?...) groups */ + /* Not a numerical recursion */ - else switch(ptr[2]) - { - default: - ptr += 2; - if (ptr[0] == CHAR_R || /* (?R) */ - ptr[0] == CHAR_NUMBER_SIGN || /* (?#) */ - IS_DIGIT(ptr[0]) || /* (?n) */ - (ptr[0] == CHAR_MINUS && IS_DIGIT(ptr[1]))) /* (?-n) */ - { - skiptoket = ptr[0]; - break; - } + if (!read_name(&ptr, ptrend, terminator, &offset, &name, &namelen, + &errorcode, cb)) goto FAILED; - /* Handle (?| and (?imsxJU: which are the only other valid forms. Both - need a new block on the nest stack. */ + /* \k and \g when used with braces are back references, whereas \g used + with quotes or angle brackets is a recursion */ - if (top_nest == NULL) top_nest = (nest_save *)(cb->start_workspace); - else if (++top_nest >= end_nests) - { - errorcode = ERR84; - goto FAILED; - } - top_nest->nest_depth = nest_depth; - top_nest->flags = 0; - if ((options & PCRE2_EXTENDED) != 0) top_nest->flags |= NSF_EXTENDED; - if ((options & PCRE2_DUPNAMES) != 0) top_nest->flags |= NSF_DUPNAMES; + *parsed_pattern++ = + (escape == ESC_k || terminator == CHAR_RIGHT_CURLY_BRACKET)? + META_BACKREF_BYNAME : META_RECURSE_BYNAME; + *parsed_pattern++ = namelen; - if (*ptr == CHAR_VERTICAL_LINE) - { - top_nest->reset_group = (uint16_t)cb->bracount; - top_nest->max_group = (uint16_t)cb->bracount; - top_nest->flags |= NSF_RESET; - cb->external_flags |= PCRE2_DUPCAPUSED; - break; - } + PUTOFFSET(offset, parsed_pattern); + okquantifier = TRUE; + break; + } + break; /* End escape sequence processing */ - /* Scan options */ - top_nest->reset_group = 0; - top_nest->max_group = 0; + /* ---- Single-character special items ---- */ - set = unset = 0; - optset = &set; + case CHAR_CIRCUMFLEX_ACCENT: + *parsed_pattern++ = META_CIRCUMFLEX; + break; - /* Need only track (?x: and (?J: at this stage */ + case CHAR_DOLLAR_SIGN: + *parsed_pattern++ = META_DOLLAR; + break; - while (*ptr != CHAR_RIGHT_PARENTHESIS && *ptr != CHAR_COLON) - { - switch (*ptr++) - { - case CHAR_MINUS: optset = &unset; break; + case CHAR_DOT: + *parsed_pattern++ = META_DOT; + okquantifier = TRUE; + break; - case CHAR_x: *optset |= PCRE2_EXTENDED; break; - case CHAR_J: - *optset |= PCRE2_DUPNAMES; - cb->external_flags |= PCRE2_JCHANGED; - break; + /* ---- Single-character quantifiers ---- */ - case CHAR_i: - case CHAR_m: - case CHAR_s: - case CHAR_U: - break; + case CHAR_ASTERISK: + meta_quantifier = META_ASTERISK; + goto CHECK_QUANTIFIER; - default: - errorcode = ERR11; - ptr--; /* Correct the offset */ - goto FAILED; - } - } + case CHAR_PLUS: + meta_quantifier = META_PLUS; + goto CHECK_QUANTIFIER; - options = (options | set) & (~unset); + case CHAR_QUESTION_MARK: + meta_quantifier = META_QUERY; + goto CHECK_QUANTIFIER; - /* If the options ended with ')' this is not the start of a nested - group with option changes, so the options change at this level. If the - previous level set up a nest block, discard the one we have just created. - Otherwise adjust it for the previous level. */ - if (*ptr == CHAR_RIGHT_PARENTHESIS) - { - nest_depth--; - if (top_nest > (nest_save *)(cb->start_workspace) && - (top_nest-1)->nest_depth == nest_depth) top_nest --; - else top_nest->nest_depth = nest_depth; - } - break; + /* ---- Potential {n,m} quantifier ---- */ - /* Skip over a numerical or string argument for a callout. */ + case CHAR_LEFT_CURLY_BRACKET: + if (!read_repeat_counts(&ptr, ptrend, &min_repeat, &max_repeat, + &errorcode)) + { + if (errorcode != 0) goto FAILED; /* Error in quantifier. */ + PARSED_LITERAL(c, parsed_pattern); /* Not a quantifier */ + break; /* No more quantifier processing */ + } + meta_quantifier = META_MINMAX; + /* Fall through */ - case CHAR_C: - ptr += 2; - if (ptr[1] == CHAR_RIGHT_PARENTHESIS) break; - if (IS_DIGIT(ptr[1])) - { - while (IS_DIGIT(ptr[1])) ptr++; - } - /* Handle a string argument */ + /* ---- Quantifier post-processing ---- */ - else - { - ptr++; - delimiter = 0; - for (i = 0; PRIV(callout_start_delims)[i] != 0; i++) - { - if (*ptr == PRIV(callout_start_delims)[i]) - { - delimiter = PRIV(callout_end_delims)[i]; - break; - } - } + /* Check that a quantifier is allowed after the previous item. */ - if (delimiter == 0) - { - errorcode = ERR82; - goto FAILED; - } + CHECK_QUANTIFIER: + if (!prev_okquantifier) + { + errorcode = ERR9; + goto FAILED_BACK; + } - start = ptr; - do - { - if (++ptr >= cb->end_pattern) - { - errorcode = ERR81; - ptr = start; /* To give a more useful message */ - goto FAILED; - } - if (ptr[0] == delimiter && ptr[1] == delimiter) ptr += 2; - } - while (ptr[0] != delimiter); - } + /* Now we can put the quantifier into the parsed pattern vector. At this + stage, we have only the basic quantifier. The check for a following + or ? + modifier happens at the top of the loop, after any intervening comments + have been removed. */ - /* Check terminating ) */ + *parsed_pattern++ = meta_quantifier; + if (c == CHAR_LEFT_CURLY_BRACKET) + { + *parsed_pattern++ = min_repeat; + *parsed_pattern++ = max_repeat; + } + break; - if (ptr[1] != CHAR_RIGHT_PARENTHESIS) - { - errorcode = ERR39; - ptr++; - goto FAILED; - } - break; - /* Conditional group */ + /* ---- Character class ---- */ - case CHAR_LEFT_PARENTHESIS: - if (ptr[3] != CHAR_QUESTION_MARK) /* Not assertion or callout */ - { - nest_depth++; - ptr += 2; - break; - } + case CHAR_LEFT_SQUARE_BRACKET: + okquantifier = TRUE; - /* Must be an assertion or a callout */ + /* In another (POSIX) regex library, the ugly syntax [[:<:]] and [[:>:]] is + used for "start of word" and "end of word". As these are otherwise illegal + sequences, we don't break anything by recognizing them. They are replaced + by \b(?=\w) and \b(?<=\w) respectively. Sequences like [a[:<:]] are + erroneous and are handled by the normal code below. */ - switch(ptr[4]) - { - case CHAR_LESS_THAN_SIGN: - if (ptr[5] != CHAR_EXCLAMATION_MARK && ptr[5] != CHAR_EQUALS_SIGN) - goto MISSING_ASSERTION; - /* Fall through */ - - case CHAR_C: - case CHAR_EXCLAMATION_MARK: - case CHAR_EQUALS_SIGN: - ptr++; - break; + if (ptrend - ptr >= 6 && + (PRIV(strncmp_c8)(ptr, STRING_WEIRD_STARTWORD, 6) == 0 || + PRIV(strncmp_c8)(ptr, STRING_WEIRD_ENDWORD, 6) == 0)) + { + *parsed_pattern++ = META_ESCAPE + ESC_b; - default: - MISSING_ASSERTION: - ptr += 3; /* To improve error message */ - errorcode = ERR28; - goto FAILED; - } - break; + if (ptr[2] == CHAR_LESS_THAN_SIGN) + { + *parsed_pattern++ = META_LOOKAHEAD; + } + else + { + *parsed_pattern++ = META_LOOKBEHIND; + *has_lookbehind = TRUE; - case CHAR_COLON: - case CHAR_GREATER_THAN_SIGN: - case CHAR_EQUALS_SIGN: - case CHAR_EXCLAMATION_MARK: - case CHAR_AMPERSAND: - case CHAR_PLUS: - ptr += 2; - break; + /* The offset is used only for the "non-fixed length" error; this won't + occur here, so just store zero. */ - case CHAR_P: - if (ptr[3] != CHAR_LESS_THAN_SIGN) - { - ptr += 3; - break; + PUTOFFSET((PCRE2_SIZE)0, parsed_pattern); } - ptr++; - c = CHAR_GREATER_THAN_SIGN; /* Terminator */ - goto DEFINE_NAME; - case CHAR_LESS_THAN_SIGN: - if (ptr[3] == CHAR_EQUALS_SIGN || ptr[3] == CHAR_EXCLAMATION_MARK) + if ((options & PCRE2_UCP) == 0) + *parsed_pattern++ = META_ESCAPE + ESC_w; + else { - ptr += 3; - break; + *parsed_pattern++ = META_ESCAPE + ESC_p; + *parsed_pattern++ = PT_WORD << 16; } - c = CHAR_GREATER_THAN_SIGN; /* Terminator */ - goto DEFINE_NAME; + *parsed_pattern++ = META_KET; + ptr += 6; + break; + } - case CHAR_APOSTROPHE: - c = CHAR_APOSTROPHE; /* Terminator */ + /* PCRE supports POSIX class stuff inside a class. Perl gives an error if + they are encountered at the top level, so we'll do that too. */ - DEFINE_NAME: - name = ptr = ptr + 3; + if (ptr < ptrend && (*ptr == CHAR_COLON || *ptr == CHAR_DOT || + *ptr == CHAR_EQUALS_SIGN) && + check_posix_syntax(ptr, ptrend, &tempptr)) + { + errorcode = (*ptr-- == CHAR_COLON)? ERR12 : ERR13; + goto FAILED; + } - if (*ptr == c) /* Empty name */ - { - errorcode = ERR62; - goto FAILED; - } + /* Process a regular character class. If the first character is '^', set + the negation flag. If the first few characters (either before or after ^) + are \Q\E or \E we skip them too. This makes for compatibility with Perl. */ - if (IS_DIGIT(*ptr)) + negate_class = FALSE; + while (ptr < ptrend) + { + GETCHARINCTEST(c, ptr); + if (c == CHAR_BACKSLASH) { - errorcode = ERR44; /* Group name must start with non-digit */ - goto FAILED; + if (ptr < ptrend && *ptr == CHAR_E) ptr++; + else if (ptrend - ptr >= 3 && + PRIV(strncmp_c8)(ptr, STR_Q STR_BACKSLASH STR_E, 3) == 0) + ptr += 3; + else + break; } + else if (!negate_class && c == CHAR_CIRCUMFLEX_ACCENT) + negate_class = TRUE; + else break; + } - if (MAX_255(*ptr) && (cb->ctypes[*ptr] & ctype_word) == 0) - { - errorcode = ERR24; - goto FAILED; - } + /* Now the real contents of the class; c has the first "real" character. + Empty classes are permitted only if the option is set. */ - /* Advance ptr, set namelen and check its length. */ - READ_NAME(ctype_word, ERR48, errorcode); + if (c == CHAR_RIGHT_SQUARE_BRACKET && + (cb->external_options & PCRE2_ALLOW_EMPTY_CLASS) != 0) + { + *parsed_pattern++ = negate_class? META_CLASS_EMPTY_NOT : META_CLASS_EMPTY; + break; /* End of class processing */ + } - if (*ptr != c) - { - errorcode = ERR42; - goto FAILED; - } + /* Process a non-empty class. */ - if (cb->names_found >= MAX_NAME_COUNT) - { - errorcode = ERR49; - goto FAILED; - } + *parsed_pattern++ = negate_class? META_CLASS_NOT : META_CLASS; + class_range_state = RANGE_NO; - if (namelen + IMM2_SIZE + 1 > cb->name_entry_size) - cb->name_entry_size = (uint16_t)(namelen + IMM2_SIZE + 1); + /* In an EBCDIC environment, Perl treats alphabetic ranges specially + because there are holes in the encoding, and simply using the range A-Z + (for example) would include the characters in the holes. This applies only + to ranges where both values are literal; [\xC1-\xE9] is different to [A-Z] + in this respect. In order to accommodate this, we keep track of whether + character values are literal or not, and a state variable for handling + ranges. */ - /* We have a valid name for this capturing group. */ + /* Loop for the contents of the class */ - cb->bracount++; + for (;;) + { + BOOL char_is_literal = TRUE; - /* Scan the list to check for duplicates. For duplicate names, if the - number is the same, break the loop, which causes the name to be - discarded; otherwise, if DUPNAMES is not set, give an error. - If it is set, allow the name with a different number, but continue - scanning in case this is a duplicate with the same number. For - non-duplicate names, give an error if the number is duplicated. */ + /* Inside \Q...\E everything is literal except \E */ - isdupname = FALSE; - ng = cb->named_groups; - for (i = 0; i < cb->names_found; i++, ng++) + if (inescq) { - if (namelen == ng->length && - PRIV(strncmp)(name, ng->name, (size_t)namelen) == 0) + if (c == CHAR_BACKSLASH && ptr < ptrend && *ptr == CHAR_E) { - if (ng->number == cb->bracount) break; - if ((options & PCRE2_DUPNAMES) == 0) - { - errorcode = ERR43; - goto FAILED; - } - isdupname = ng->isdup = TRUE; /* Mark as a duplicate */ - cb->dupnames = TRUE; /* Duplicate names exist */ + inescq = FALSE; /* Reset literal state */ + ptr++; /* Skip the 'E' */ + goto CLASS_CONTINUE; } - else if (ng->number == cb->bracount) + goto CLASS_LITERAL; + } + + /* Handle POSIX class names. Perl allows a negation extension of the + form [:^name:]. A square bracket that doesn't match the syntax is + treated as a literal. We also recognize the POSIX constructions + [.ch.] and [=ch=] ("collating elements") and fault them, as Perl + 5.6 and 5.8 do. */ + + if (c == CHAR_LEFT_SQUARE_BRACKET && + ptrend - ptr >= 3 && + (*ptr == CHAR_COLON || *ptr == CHAR_DOT || + *ptr == CHAR_EQUALS_SIGN) && + check_posix_syntax(ptr, ptrend, &tempptr)) + { + BOOL posix_negate = FALSE; + int posix_class; + + /* Perl treats a hyphen before a POSIX class as a literal, not the + start of a range. However, it gives a warning in its warning mode. PCRE + does not have a warning mode, so we give an error, because this is + likely an error on the user's part. */ + + if (class_range_state == RANGE_STARTED) { - errorcode = ERR65; + errorcode = ERR50; goto FAILED; } - } - if (i < cb->names_found) break; /* Ignore duplicate with same number */ + if (*ptr != CHAR_COLON) + { + errorcode = ERR13; + goto FAILED_BACK; + } - /* Increase the list size if necessary */ + if (*(++ptr) == CHAR_CIRCUMFLEX_ACCENT) + { + posix_negate = TRUE; + ptr++; + } - if (cb->names_found >= cb->named_group_list_size) - { - uint32_t newsize = cb->named_group_list_size * 2; - named_group *newspace = - cb->cx->memctl.malloc(newsize * sizeof(named_group), - cb->cx->memctl.memory_data); - if (newspace == NULL) + posix_class = check_posix_name(ptr, (int)(tempptr - ptr)); + if (posix_class < 0) { - errorcode = ERR21; + errorcode = ERR30; goto FAILED; } + ptr = tempptr + 2; - memcpy(newspace, cb->named_groups, - cb->named_group_list_size * sizeof(named_group)); - if (cb->named_group_list_size > NAMED_GROUP_LIST_SIZE) - cb->cx->memctl.free((void *)cb->named_groups, - cb->cx->memctl.memory_data); - cb->named_groups = newspace; - cb->named_group_list_size = newsize; - } + /* Perl treats a hyphen after a POSIX class as a literal, not the + start of a range. However, it gives a warning in its warning mode. PCRE + does not have a warning mode, so we give an error, because this is + likely an error on the user's part. */ - /* Add this name to the list */ + if (ptr < ptrend && *ptr == CHAR_MINUS) + { + errorcode = ERR50; + goto FAILED; + } - cb->named_groups[cb->names_found].name = name; - cb->named_groups[cb->names_found].length = (uint16_t)namelen; - cb->named_groups[cb->names_found].number = cb->bracount; - cb->named_groups[cb->names_found].isdup = (uint16_t)isdupname; - cb->names_found++; - break; - } /* End of (? switch */ - break; /* End of ( handling */ + /* Set "a hyphen is not the start of a range" just in case the POSIX + class is followed by \E or \Q\E (possibly repeated - fuzzers do that + kind of thing) and *then* a hyphen. This causes that hyphen to be + treated as a literal. I don't think it's worth setting up special + apparatus to do otherwise. */ - /* At an alternation, reset the capture count if we are in a (?| group. */ + class_range_state = RANGE_NO; - case CHAR_VERTICAL_LINE: - if (top_nest != NULL && top_nest->nest_depth == nest_depth && - (top_nest->flags & NSF_RESET) != 0) - { - if (cb->bracount > top_nest->max_group) - top_nest->max_group = (uint16_t)cb->bracount; - cb->bracount = top_nest->reset_group; - } - break; + /* When PCRE2_UCP is set, some of the POSIX classes are converted to + use Unicode properties \p or \P or, in one case, \h or \H. The + substitutes table has two values per class, containing the type and + value of a \p or \P item. The special cases are specified with a + negative type: a non-zero value causes \h or \H to be used, and a zero + value falls through to behave like a non-UCP POSIX class. */ - /* At a right parenthesis, reset the capture count to the maximum if we - are in a (?| group and/or reset the extended option. */ +#ifdef SUPPORT_UNICODE + if ((options & PCRE2_UCP) != 0) + { + int ptype = posix_substitutes[2*posix_class]; + int pvalue = posix_substitutes[2*posix_class + 1]; + if (ptype >= 0) + { + *parsed_pattern++ = META_ESCAPE + (posix_negate? ESC_P : ESC_p); + *parsed_pattern++ = (ptype << 16) | pvalue; + goto CLASS_CONTINUE; + } - case CHAR_RIGHT_PARENTHESIS: - if (top_nest != NULL && top_nest->nest_depth == nest_depth) - { - if ((top_nest->flags & NSF_RESET) != 0 && - top_nest->max_group > cb->bracount) - cb->bracount = top_nest->max_group; - if ((top_nest->flags & NSF_EXTENDED) != 0) options |= PCRE2_EXTENDED; - else options &= ~PCRE2_EXTENDED; - if ((top_nest->flags & NSF_DUPNAMES) != 0) options |= PCRE2_DUPNAMES; - else options &= ~PCRE2_DUPNAMES; - if (top_nest == (nest_save *)(cb->start_workspace)) top_nest = NULL; - else top_nest--; - } - if (nest_depth == 0) /* Unmatched closing parenthesis */ - { - errorcode = ERR22; - goto FAILED; - } - nest_depth--; - break; - } - } + if (pvalue != 0) + { + *parsed_pattern++ = META_ESCAPE + (posix_negate? ESC_H : ESC_h); + goto CLASS_CONTINUE; + } -if (nest_depth == 0) - { - cb->final_bracount = cb->bracount; - return 0; - } + /* Fall through */ + } +#endif /* SUPPORT_UNICODE */ -/* We give a special error for a missing closing parentheses after (?# because -it might otherwise be hard to see where the missing character is. */ + /* Non-UCP POSIX class */ -errorcode = (skiptoket == CHAR_NUMBER_SIGN)? ERR18 : ERR14; + *parsed_pattern++ = posix_negate? META_POSIX_NEG : META_POSIX; + *parsed_pattern++ = posix_class; + } -FAILED: -*ptrptr = ptr; -return errorcode; -} + /* Handle potential start of range */ + else if (c == CHAR_MINUS && class_range_state >= RANGE_OK_ESCAPED) + { + *parsed_pattern++ = (class_range_state == RANGE_OK_LITERAL)? + META_RANGE_LITERAL : META_RANGE_ESCAPED; + class_range_state = RANGE_STARTED; + } + /* Handle a literal character */ -/************************************************* -* Compile one branch * -*************************************************/ + else if (c != CHAR_BACKSLASH) + { + CLASS_LITERAL: + if (class_range_state == RANGE_STARTED) + { + if (c == parsed_pattern[-2]) /* Optimize one-char range */ + parsed_pattern--; + else if (parsed_pattern[-2] > c) /* Check range is in order */ + { + errorcode = ERR8; + goto FAILED_BACK; + } + else + { + if (!char_is_literal && parsed_pattern[-1] == META_RANGE_LITERAL) + parsed_pattern[-1] = META_RANGE_ESCAPED; + PARSED_LITERAL(c, parsed_pattern); + } + class_range_state = RANGE_NO; + } + else /* Potential start of range */ + { + class_range_state = char_is_literal? + RANGE_OK_LITERAL : RANGE_OK_ESCAPED; + PARSED_LITERAL(c, parsed_pattern); + } + } -/* Scan the pattern, compiling it into the a vector. If the options are -changed during the branch, the pointer is used to change the external options -bits. This function is used during the pre-compile phase when we are trying -to find out the amount of memory needed, as well as during the real compile -phase. The value of lengthptr distinguishes the two phases. + /* Handle escapes in a class */ -Arguments: - optionsptr pointer to the option bits - codeptr points to the pointer to the current code point - ptrptr points to the current pattern pointer - errorcodeptr points to error code variable - firstcuptr place to put the first required code unit - firstcuflagsptr place to put the first code unit flags, or a negative number - reqcuptr place to put the last required code unit - reqcuflagsptr place to put the last required code unit flags, or a negative number - bcptr points to current branch chain - cond_depth conditional nesting depth - cb contains pointers to tables etc. - lengthptr NULL during the real compile phase - points to length accumulator during pre-compile phase + else + { + escape = PRIV(check_escape)(&ptr, ptrend, &c, &errorcode, + options, TRUE, cb); -Returns: TRUE on success - FALSE, with *errorcodeptr set non-zero on error -*/ + if (errorcode != 0) goto FAILED; + if (escape == 0) /* Escaped character code point is in c */ + { + char_is_literal = FALSE; + goto CLASS_LITERAL; + } -static BOOL -compile_branch(uint32_t *optionsptr, PCRE2_UCHAR **codeptr, - PCRE2_SPTR *ptrptr, int *errorcodeptr, - uint32_t *firstcuptr, int32_t *firstcuflagsptr, - uint32_t *reqcuptr, int32_t *reqcuflagsptr, - branch_chain *bcptr, int cond_depth, - compile_block *cb, size_t *lengthptr) -{ -int repeat_min = 0, repeat_max = 0; /* To please picky compilers */ -int bravalue = 0; -uint32_t greedy_default, greedy_non_default; -uint32_t repeat_type, op_type; -uint32_t options = *optionsptr; /* May change dynamically */ -uint32_t firstcu, reqcu; -int32_t firstcuflags, reqcuflags; -uint32_t zeroreqcu, zerofirstcu; -int32_t zeroreqcuflags, zerofirstcuflags; -int32_t req_caseopt, reqvary, tempreqvary; -int after_manual_callout = 0; -int escape; -size_t length_prevgroup = 0; -register uint32_t c; -register PCRE2_UCHAR *code = *codeptr; -PCRE2_UCHAR *last_code = code; -PCRE2_UCHAR *orig_code = code; -PCRE2_UCHAR *tempcode; -BOOL inescq = FALSE; -BOOL groupsetfirstcu = FALSE; -PCRE2_SPTR ptr = *ptrptr; -PCRE2_SPTR tempptr; -PCRE2_UCHAR *previous = NULL; -PCRE2_UCHAR *previous_callout = NULL; -uint8_t classbits[32]; + /* These three escapes do not alter the class range state. */ -/* We can fish out the UTF setting once and for all into a BOOL, but we must -not do this for other options (e.g. PCRE2_EXTENDED) because they may change -dynamically as we process the pattern. */ + if (escape == ESC_b) + { + c = CHAR_BS; /* \b is backspace in a class */ + char_is_literal = FALSE; + goto CLASS_LITERAL; + } -#ifdef SUPPORT_UNICODE -BOOL utf = (options & PCRE2_UTF) != 0; -#if PCRE2_CODE_UNIT_WIDTH != 32 -PCRE2_UCHAR utf_units[6]; /* For setting up multi-cu chars */ -#endif + else if (escape == ESC_Q) + { + inescq = TRUE; /* Enter literal mode */ + goto CLASS_CONTINUE; + } -#else /* No UTF support */ -BOOL utf = FALSE; -#endif + else if (escape == ESC_E) /* Ignore orphan \E */ + goto CLASS_CONTINUE; -/* Helper variables for OP_XCLASS opcode (for characters > 255). We define -class_uchardata always so that it can be passed to add_to_class() always, -though it will not be used in non-UTF 8-bit cases. This avoids having to supply -alternative calls for the different cases. */ + /* The second part of a range can be a single-character escape + sequence (detected above), but not any of the other escapes. Perl + treats a hyphen as a literal in such circumstances. However, in Perl's + warning mode, a warning is given, so PCRE now faults it, as it is + almost certainly a mistake on the user's part. */ -PCRE2_UCHAR *class_uchardata; -#ifdef SUPPORT_WIDE_CHARS -BOOL xclass; -PCRE2_UCHAR *class_uchardata_base; -#endif + if (class_range_state == RANGE_STARTED) + { + errorcode = ERR50; + goto FAILED; + } -/* Set up the default and non-default settings for greediness */ + /* Of the remaining escapes, only those that define characters are + allowed in a class. None may start a range. */ -greedy_default = ((options & PCRE2_UNGREEDY) != 0); -greedy_non_default = greedy_default ^ 1; + class_range_state = RANGE_NO; + switch(escape) + { + case ESC_N: + errorcode = ERR71; /* Not supported in a class */ + goto FAILED; -/* Initialize no first unit, no required unit. REQ_UNSET means "no char -matching encountered yet". It gets changed to REQ_NONE if we hit something that -matches a non-fixed first unit; reqcu just remains unset if we never find one. + case ESC_H: + case ESC_h: + case ESC_V: + case ESC_v: + *parsed_pattern++ = META_ESCAPE + escape; + break; -When we hit a repeat whose minimum is zero, we may have to adjust these values -to take the zero repeat into account. This is implemented by setting them to -zerofirstcu and zeroreqcu when such a repeat is encountered. The individual -item types that can be repeated set these backoff variables appropriately. */ + /* These escapes are converted to Unicode property tests when + PCRE2_UCP is set. */ -firstcu = reqcu = zerofirstcu = zeroreqcu = 0; -firstcuflags = reqcuflags = zerofirstcuflags = zeroreqcuflags = REQ_UNSET; + case ESC_d: + case ESC_D: + case ESC_s: + case ESC_S: + case ESC_w: + case ESC_W: + if ((options & PCRE2_UCP) == 0) + { + *parsed_pattern++ = META_ESCAPE + escape; + } + else + { + *parsed_pattern++ = META_ESCAPE + + ((escape == ESC_d || escape == ESC_s || escape == ESC_w)? + ESC_p : ESC_P); + switch(escape) + { + case ESC_d: + case ESC_D: + *parsed_pattern++ = (PT_PC << 16) | ucp_Nd; + break; -/* The variable req_caseopt contains either the REQ_CASELESS value or zero, -according to the current setting of the caseless flag. The REQ_CASELESS value -leaves the lower 28 bit empty. It is added into the firstcu or reqcu variables -to record the case status of the value. This is used only for ASCII characters. -*/ + case ESC_s: + case ESC_S: + *parsed_pattern++ = PT_SPACE << 16; + break; -req_caseopt = ((options & PCRE2_CASELESS) != 0)? REQ_CASELESS:0; + case ESC_w: + case ESC_W: + *parsed_pattern++ = PT_WORD << 16; + break; + } + } + break; -/* Switch on next character until the end of the branch */ + /* Explicit Unicode property matching */ -for (;; ptr++) - { - BOOL negate_class; - BOOL should_flip_negation; - BOOL match_all_or_no_wide_chars; - BOOL possessive_quantifier; - BOOL is_quantifier; - BOOL is_recurse; - BOOL is_dupname; - BOOL reset_bracount; - int class_has_8bitchar; - int class_one_char; -#ifdef SUPPORT_WIDE_CHARS - BOOL xclass_has_prop; + case ESC_P: + case ESC_p: +#ifdef SUPPORT_UNICODE + { + BOOL negated; + uint16_t ptype = 0, pdata = 0; + if (!get_ucp(&ptr, &negated, &ptype, &pdata, &errorcode, cb)) + goto FAILED; + if (negated) escape = (escape == ESC_P)? ESC_p : ESC_P; + *parsed_pattern++ = META_ESCAPE + escape; + *parsed_pattern++ = (ptype << 16) | pdata; + } +#else + errorcode = ERR45; + goto FAILED; #endif - int recno; /* Must be signed */ - int refsign; /* Must be signed */ - int terminator; /* Must be signed */ - unsigned int mclength; - unsigned int tempbracount; - uint32_t ec; - uint32_t newoptions; - uint32_t skipunits; - uint32_t subreqcu, subfirstcu; - int32_t subreqcuflags, subfirstcuflags; /* Must be signed */ - PCRE2_UCHAR mcbuffer[8]; - - /* Come here to restart the loop. */ - - REDO_LOOP: + break; /* End \P and \p */ - /* Get next character in the pattern */ - - c = *ptr; - - /* If we are at the end of a nested substitution, revert to the outer level - string. Nesting only happens one or two levels deep, and the inserted string - is always zero terminated. */ + default: /* All others are not allowed in a class */ + errorcode = ERR7; + goto FAILED_BACK; + } + } - if (c == CHAR_NULL && cb->nestptr[0] != NULL) - { - ptr = cb->nestptr[0]; - cb->nestptr[0] = cb->nestptr[1]; - cb->nestptr[1] = NULL; - c = *ptr; - } + /* Proceed to next thing in the class. */ - /* If we are in the pre-compile phase, accumulate the length used for the - previous cycle of this loop. */ + CLASS_CONTINUE: + if (ptr >= ptrend) + { + errorcode = ERR6; /* Missing terminating ']' */ + goto FAILED; + } + GETCHARINCTEST(c, ptr); + if (c == CHAR_RIGHT_SQUARE_BRACKET && !inescq) break; + } /* End of class-processing loop */ - if (lengthptr != NULL) - { - if (code > cb->start_workspace + cb->workspace_size - - WORK_SIZE_SAFETY_MARGIN) /* Check for overrun */ + if (class_range_state == RANGE_STARTED) { - *errorcodeptr = (code >= cb->start_workspace + cb->workspace_size)? - ERR52 : ERR86; - goto FAILED; + parsed_pattern[-1] = CHAR_MINUS; + class_range_state = RANGE_NO; } - /* There is at least one situation where code goes backwards: this is the - case of a zero quantifier after a class (e.g. [ab]{0}). At compile time, - the class is simply eliminated. However, it is created first, so we have to - allow memory for it. Therefore, don't ever reduce the length at this point. - */ + *parsed_pattern++ = META_CLASS_END; + break; /* End of character class */ - if (code < last_code) code = last_code; - /* Paranoid check for integer overflow */ + /* ---- Opening parenthesis ---- */ - if (OFLOW_MAX - *lengthptr < (size_t)(code - last_code)) - { - *errorcodeptr = ERR20; - goto FAILED; - } - *lengthptr += (size_t)(code - last_code); + case CHAR_LEFT_PARENTHESIS: + if (ptr >= ptrend) goto UNCLOSED_PARENTHESIS; - /* If "previous" is set and it is not at the start of the work space, move - it back to there, in order to avoid filling up the work space. Otherwise, - if "previous" is NULL, reset the current code pointer to the start. */ + /* If ( is not followed by ? it is either a capture or a special verb. */ - if (previous != NULL) + if (*ptr != CHAR_QUESTION_MARK) { - if (previous > orig_code) + const char *vn; + + /* Handle capturing brackets (or non-capturing if auto-capture is turned + off). */ + + if (*ptr != CHAR_ASTERISK) { - memmove(orig_code, previous, (size_t)CU2BYTES(code - previous)); - code -= previous - orig_code; - previous = orig_code; + nest_depth++; + if ((options & PCRE2_NO_AUTO_CAPTURE) == 0) + { + cb->bracount++; + *parsed_pattern++ = META_CAPTURE | cb->bracount; + } + else *parsed_pattern++ = META_NOCAPTURE; } - } - else code = orig_code; - /* Remember where this code item starts so we can pick up the length - next time round. */ - - last_code = code; - } - /* Before doing anything else we must handle all the special items that do - nothing, and which may come between an item and its quantifier. Otherwise, - when auto-callouts are enabled, a callout gets incorrectly inserted before - the quantifier is recognized. After recognizing a "do nothing" item, restart - the loop in case another one follows. */ + /* ---- Handle (*VERB) and (*VERB:NAME) ---- */ - /* If c is not NULL we are not at the end of the pattern. If it is NULL, we - may still be in the pattern with a NULL data item. In these cases, if we are - in \Q...\E, check for the \E that ends the literal string; if not, we have a - literal character. If not in \Q...\E, an isolated \E is ignored. */ + /* Do nothing for (*) so it gives a "bad quantifier" error rather than + "(*MARK) must have an argument". */ - if (c != CHAR_NULL || ptr < cb->end_pattern) - { - if (c == CHAR_BACKSLASH && ptr[1] == CHAR_E) - { - inescq = FALSE; - ptr++; - continue; - } - else if (inescq) /* Literal character */ - { - if (previous_callout != NULL) + else if (ptrend - ptr > 1 && ptr[1] != CHAR_RIGHT_PARENTHESIS) { - if (lengthptr == NULL) /* Don't attempt in pre-compile phase */ - complete_callout(previous_callout, ptr, cb); - previous_callout = NULL; - } - if ((options & PCRE2_AUTO_CALLOUT) != 0) - { - previous_callout = code; - code = auto_callout(code, ptr, cb); - } - goto NORMAL_CHAR; - } + vn = verbnames; + if (!read_name(&ptr, ptrend, 0, &offset, &name, &namelen, &errorcode, + cb)) goto FAILED; + if (ptr >= ptrend || (*ptr != CHAR_COLON && + *ptr != CHAR_RIGHT_PARENTHESIS)) + { + errorcode = ERR60; /* Malformed */ + goto FAILED; + } - /* Check for the start of a \Q...\E sequence. We must do this here rather - than later in case it is immediately followed by \E, which turns it into a - "do nothing" sequence. */ + /* Scan the table of verb names */ - if (c == CHAR_BACKSLASH && ptr[1] == CHAR_Q) - { - inescq = TRUE; - ptr++; - continue; - } - } - - /* In extended mode, skip white space and #-comments that end at newline. */ + for (i = 0; i < verbcount; i++) + { + if (namelen == verbs[i].len && + PRIV(strncmp_c8)(name, vn, namelen) == 0) + break; + vn += verbs[i].len + 1; + } - if ((options & PCRE2_EXTENDED) != 0) - { - PCRE2_SPTR wscptr = ptr; - while (MAX_255(c) && (cb->ctypes[c] & ctype_space) != 0) c = *(++ptr); - if (c == CHAR_NUMBER_SIGN) - { - ptr++; - while (ptr < cb->end_pattern) - { - if (IS_NEWLINE(ptr)) /* For non-fixed-length newline cases, */ - { /* IS_NEWLINE sets cb->nllen. */ - ptr += cb->nllen; - break; + if (i >= verbcount) + { + errorcode = ERR60; /* Verb not recognized */ + goto FAILED; } - ptr++; -#ifdef SUPPORT_UNICODE - if (utf) FORWARDCHAR(ptr); -#endif - } - } - /* If we skipped any characters, restart the loop. Otherwise, we didn't see - a comment. */ + /* An empty argument is treated as no argument. */ - if (ptr > wscptr) goto REDO_LOOP; - } + if (*ptr == CHAR_COLON && ptr + 1 < ptrend && + ptr[1] == CHAR_RIGHT_PARENTHESIS) + ptr++; /* Advance to the closing parens */ - /* Skip over (?# comments. */ + /* Check for mandatory non-empty argument; this is (*MARK) */ - if (c == CHAR_LEFT_PARENTHESIS && ptr[1] == CHAR_QUESTION_MARK && - ptr[2] == CHAR_NUMBER_SIGN) - { - ptr += 3; - while (ptr < cb->end_pattern && *ptr != CHAR_RIGHT_PARENTHESIS) ptr++; - if (*ptr != CHAR_RIGHT_PARENTHESIS) - { - *errorcodeptr = ERR18; - goto FAILED; - } - continue; - } + if (verbs[i].has_arg > 0 && *ptr != CHAR_COLON) + { + errorcode = ERR66; + goto FAILED; + } - /* End of processing "do nothing" items. See if the next thing is a - quantifier. */ + /* It appears that Perl allows any characters whatsoever, other than a + closing parenthesis, to appear in arguments ("names"), so we no longer + insist on letters, digits, and underscores. Perl does not, however, do + any interpretation within arguments, and has no means of including a + closing parenthesis. PCRE supports escape processing but only when it + is requested by an option. We set inverbname TRUE here, and let the + main loop take care of this so that escape and \x processing is done by + the main code above. */ - is_quantifier = - c == CHAR_ASTERISK || c == CHAR_PLUS || c == CHAR_QUESTION_MARK || - (c == CHAR_LEFT_CURLY_BRACKET && is_counted_repeat(ptr+1)); + if (*ptr++ == CHAR_COLON) /* Skip past : or ) */ + { + if (verbs[i].has_arg < 0) /* Argument is forbidden */ + { + errorcode = ERR59; + goto FAILED; + } + *parsed_pattern++ = verbs[i].meta + + ((verbs[i].meta != META_MARK)? 0x00010000u:0); + verblengthptr = parsed_pattern++; + verbnamestart = ptr; + inverbname = TRUE; + } + else /* No verb "name" argument */ + { + *parsed_pattern++ = verbs[i].meta; + } + } /* End of (*VERB) handling */ + break; /* Done with this parenthesis */ + } /* End of groups that don't start with (? */ - /* Fill in length of a previous callout and create an auto callout if - required, except when the next thing is a quantifier or when processing a - property substitution string for \w etc in UCP mode. */ - if (!is_quantifier && cb->nestptr[0] == NULL) - { - if (previous_callout != NULL && after_manual_callout-- <= 0) - { - if (lengthptr == NULL) /* Don't attempt in pre-compile phase */ - complete_callout(previous_callout, ptr, cb); - previous_callout = NULL; - } + /* ---- Items starting (? ---- */ - if ((options & PCRE2_AUTO_CALLOUT) != 0) - { - previous_callout = code; - code = auto_callout(code, ptr, cb); - } - } + /* The type of item is determined by what follows (?. Handle (?| and option + changes under "default" because both need a new block on the nest stack. + Comments starting with (?# are handled above. Note that there is some + ambiguity about the sequence (?- because if a digit follows it's a relative + recursion or subroutine call whereas otherwise it's an option unsetting. */ - /* Process the next pattern item. */ + if (++ptr >= ptrend) goto UNCLOSED_PARENTHESIS; - switch(c) - { - /* ===================================================================*/ - /* The branch terminates at string end or | or ) */ + switch(*ptr) + { + default: + if (*ptr == CHAR_MINUS && ptrend - ptr > 1 && IS_DIGIT(ptr[1])) + goto RECURSION_BYNUMBER; /* The + case is handled by CHAR_PLUS */ - case CHAR_NULL: - if (ptr < cb->end_pattern) goto NORMAL_CHAR; /* Zero data character */ - /* Fall through */ + /* We now have either (?| or a (possibly empty) option setting, + optionally followed by a non-capturing group. */ - case CHAR_VERTICAL_LINE: - case CHAR_RIGHT_PARENTHESIS: - *firstcuptr = firstcu; - *firstcuflagsptr = firstcuflags; - *reqcuptr = reqcu; - *reqcuflagsptr = reqcuflags; - *codeptr = code; - *ptrptr = ptr; - if (lengthptr != NULL) - { - if (OFLOW_MAX - *lengthptr < (size_t)(code - last_code)) + nest_depth++; + if (top_nest == NULL) top_nest = (nest_save *)(cb->start_workspace); + else if (++top_nest >= end_nests) { - *errorcodeptr = ERR20; + errorcode = ERR84; goto FAILED; } - *lengthptr += (size_t)(code - last_code); /* To include callout length */ - } - return TRUE; + top_nest->nest_depth = nest_depth; + top_nest->flags = 0; + if ((options & PCRE2_EXTENDED) != 0) top_nest->flags |= NSF_EXTENDED; + if ((options & PCRE2_DUPNAMES) != 0) top_nest->flags |= NSF_DUPNAMES; + /* Start of non-capturing group that resets the capture count for each + branch. */ - /* ===================================================================*/ - /* Handle single-character metacharacters. In multiline mode, ^ disables - the setting of any following char as a first character. */ + if (*ptr == CHAR_VERTICAL_LINE) + { + top_nest->reset_group = (uint16_t)cb->bracount; + top_nest->max_group = (uint16_t)cb->bracount; + top_nest->flags |= NSF_RESET; + cb->external_flags |= PCRE2_DUPCAPUSED; + *parsed_pattern++ = META_NOCAPTURE; + ptr++; + } - case CHAR_CIRCUMFLEX_ACCENT: - previous = NULL; - if ((options & PCRE2_MULTILINE) != 0) - { - if (firstcuflags == REQ_UNSET) - zerofirstcuflags = firstcuflags = REQ_NONE; - *code++ = OP_CIRCM; - } - else *code++ = OP_CIRC; - break; + /* Scan for options imsxJU. We need to keep track of (?x) and (?J) for + use while scanning. The other options are used during the compiling + phases. */ - case CHAR_DOLLAR_SIGN: - previous = NULL; - *code++ = ((options & PCRE2_MULTILINE) != 0)? OP_DOLLM : OP_DOLL; - break; + else + { + top_nest->reset_group = 0; + top_nest->max_group = 0; + set = unset = 0; + optset = &set; - /* There can never be a first char if '.' is first, whatever happens about - repeats. The value of reqcu doesn't change either. */ + while (ptr < ptrend && *ptr != CHAR_RIGHT_PARENTHESIS && + *ptr != CHAR_COLON) + { + switch (*ptr++) + { + case CHAR_MINUS: optset = &unset; break; - case CHAR_DOT: - if (firstcuflags == REQ_UNSET) firstcuflags = REQ_NONE; - zerofirstcu = firstcu; - zerofirstcuflags = firstcuflags; - zeroreqcu = reqcu; - zeroreqcuflags = reqcuflags; - previous = code; - *code++ = ((options & PCRE2_DOTALL) != 0)? OP_ALLANY: OP_ANY; - break; + case CHAR_J: /* Record that it changed in the external options */ + *optset |= PCRE2_DUPNAMES; + cb->external_flags |= PCRE2_JCHANGED; + break; + case CHAR_i: *optset |= PCRE2_CASELESS; break; + case CHAR_m: *optset |= PCRE2_MULTILINE; break; + case CHAR_s: *optset |= PCRE2_DOTALL; break; + case CHAR_x: *optset |= PCRE2_EXTENDED; break; + case CHAR_U: *optset |= PCRE2_UNGREEDY; break; - /* ===================================================================*/ - /* Character classes. If the included characters are all < 256, we build a - 32-byte bitmap of the permitted characters, except in the special case - where there is only one such character. For negated classes, we build the - map as usual, then invert it at the end. However, we use a different opcode - so that data characters > 255 can be handled correctly. + default: + errorcode = ERR11; + ptr--; /* Correct the offset */ + goto FAILED; + } + } + options = (options | set) & (~unset); - If the class contains characters outside the 0-255 range, a different - opcode is compiled. It may optionally have a bit map for characters < 256, - but those above are are explicitly listed afterwards. A flag byte tells - whether the bitmap is present, and whether this is a negated class or not. + /* If the options ended with ')' this is not the start of a nested + group with option changes, so the options change at this level. + In this case, if the previous level set up a nest block, discard the + one we have just created. Otherwise adjust it for the previous level. + If the options ended with ':' we are starting a non-capturing group, + possibly with an options setting. */ + + if (ptr >= ptrend) goto UNCLOSED_PARENTHESIS; + if (*ptr++ == CHAR_RIGHT_PARENTHESIS) + { + nest_depth--; /* This is not a nested group after all. */ + if (top_nest > (nest_save *)(cb->start_workspace) && + (top_nest-1)->nest_depth == nest_depth) top_nest--; + else top_nest->nest_depth = nest_depth; + } + else *parsed_pattern++ = META_NOCAPTURE; - An isolated ']' character is not treated specially, so is just another data - character. In earlier versions of PCRE that used the original API there was - a "JavaScript compatibility mode" in which it gave an error. However, - JavaScript itself has changed in this respect so there is no longer any - need for this special handling. + /* If nothing changed, no need to record. */ - In another (POSIX) regex library, the ugly syntax [[:<:]] and [[:>:]] is - used for "start of word" and "end of word". As these are otherwise illegal - sequences, we don't break anything by recognizing them. They are replaced - by \b(?=\w) and \b(?<=\w) respectively. This can only happen at the top - nesting level, as no other inserted sequences will contains these oddities. - Sequences like [a[:<:]] are erroneous and are handled by the normal code - below. */ + if (set != 0 || unset != 0) + { + *parsed_pattern++ = META_OPTIONS; + *parsed_pattern++ = options; + } + } /* End options processing */ + break; /* End default case after (? */ - case CHAR_LEFT_SQUARE_BRACKET: - if (PRIV(strncmp_c8)(ptr+1, STRING_WEIRD_STARTWORD, 6) == 0) - { - cb->nestptr[0] = ptr + 7; - ptr = sub_start_of_word; - goto REDO_LOOP; - } - if (PRIV(strncmp_c8)(ptr+1, STRING_WEIRD_ENDWORD, 6) == 0) - { - cb->nestptr[0] = ptr + 7; - ptr = sub_end_of_word; - goto REDO_LOOP; - } + /* ---- Python syntax support ---- */ - /* Handle a real character class. */ + case CHAR_P: + if (++ptr >= ptrend) goto UNCLOSED_PARENTHESIS; - previous = code; + /* (?P is the same as (?, which defines a named group. */ - /* PCRE supports POSIX class stuff inside a class. Perl gives an error if - they are encountered at the top level, so we'll do that too. */ + if (*ptr == CHAR_LESS_THAN_SIGN) + { + terminator = CHAR_GREATER_THAN_SIGN; + goto DEFINE_NAME; + } - if ((ptr[1] == CHAR_COLON || ptr[1] == CHAR_DOT || - ptr[1] == CHAR_EQUALS_SIGN) && - check_posix_syntax(ptr, &tempptr)) - { - *errorcodeptr = (ptr[1] == CHAR_COLON)? ERR12 : ERR13; - goto FAILED; - } + /* (?P>name) is the same as (?&name), which is a recursion or subroutine + call. */ - /* If the first character is '^', set the negation flag and skip it. Also, - if the first few characters (either before or after ^) are \Q\E or \E we - skip them too. This makes for compatibility with Perl. */ + if (*ptr == CHAR_GREATER_THAN_SIGN) goto RECURSE_BY_NAME; - negate_class = FALSE; - for (;;) - { - c = *(++ptr); - if (c == CHAR_BACKSLASH) + /* (?P=name) is the same as \k, a back reference by name. Anything + else after (?P is an error. */ + + if (*ptr != CHAR_EQUALS_SIGN) { - if (ptr[1] == CHAR_E) - ptr++; - else if (PRIV(strncmp_c8)(ptr + 1, STR_Q STR_BACKSLASH STR_E, 3) == 0) - ptr += 3; - else - break; + errorcode = ERR41; + goto FAILED; } - else if (!negate_class && c == CHAR_CIRCUMFLEX_ACCENT) - negate_class = TRUE; - else break; - } + if (!read_name(&ptr, ptrend, CHAR_RIGHT_PARENTHESIS, &offset, &name, + &namelen, &errorcode, cb)) goto FAILED; + *parsed_pattern++ = META_BACKREF_BYNAME; + *parsed_pattern++ = namelen; + PUTOFFSET(offset, parsed_pattern); + okquantifier = TRUE; + break; /* End of (?P processing */ - /* Empty classes are allowed if PCRE2_ALLOW_EMPTY_CLASS is set. Otherwise, - an initial ']' is taken as a data character -- the code below handles - that. When empty classes are allowed, [] must always fail, so generate - OP_FAIL, whereas [^] must match any character, so generate OP_ALLANY. */ - if (c == CHAR_RIGHT_SQUARE_BRACKET && - (cb->external_options & PCRE2_ALLOW_EMPTY_CLASS) != 0) - { - *code++ = negate_class? OP_ALLANY : OP_FAIL; - if (firstcuflags == REQ_UNSET) firstcuflags = REQ_NONE; - zerofirstcu = firstcu; - zerofirstcuflags = firstcuflags; - break; - } + /* ---- Recursion/subroutine calls by number ---- */ - /* If a non-extended class contains a negative special such as \S, we need - to flip the negation flag at the end, so that support for characters > 255 - works correctly (they are all included in the class). An extended class may - need to insert specific matching or non-matching code for wide characters. - */ + case CHAR_R: + i = 0; /* (?R) == (?R0) */ + ptr++; + if (ptr >= ptrend || *ptr != CHAR_RIGHT_PARENTHESIS) + { + errorcode = ERR58; + goto FAILED; + } + goto SET_RECURSION; - should_flip_negation = match_all_or_no_wide_chars = FALSE; + /* An item starting (?- followed by a digit comes here via the "default" + case because (?- followed by a non-digit is an options setting. */ - /* Extended class (xclass) will be used when characters > 255 - might match. */ + case CHAR_PLUS: + if (ptrend - ptr < 2 || !IS_DIGIT(ptr[1])) + { + errorcode = ERR29; /* Missing number */ + goto FAILED; + } + /* Fall through */ + + case CHAR_0: case CHAR_1: case CHAR_2: case CHAR_3: case CHAR_4: + case CHAR_5: case CHAR_6: case CHAR_7: case CHAR_8: case CHAR_9: + RECURSION_BYNUMBER: + if (!read_number(&ptr, ptrend, + (IS_DIGIT(*ptr))? -1:(int)(cb->bracount), /* + and - are relative */ + MAX_GROUP_NUMBER, ERR61, + &i, &errorcode)) goto FAILED; + if (i < 0) /* NB (?0) is permitted */ + { + errorcode = ERR15; /* Unknown group */ + goto FAILED_BACK; + } + if (ptr >= ptrend || *ptr != CHAR_RIGHT_PARENTHESIS) + goto UNCLOSED_PARENTHESIS; -#ifdef SUPPORT_WIDE_CHARS - xclass = FALSE; - class_uchardata = code + LINK_SIZE + 2; /* For XCLASS items */ - class_uchardata_base = class_uchardata; /* Save the start */ -#endif + SET_RECURSION: + *parsed_pattern++ = META_RECURSE | (uint32_t)i; + offset = (PCRE2_SIZE)(ptr - cb->start_pattern); + ptr++; + PUTOFFSET(offset, parsed_pattern); + okquantifier = TRUE; + break; /* End of recursive call by number handling */ - /* For optimization purposes, we track some properties of the class: - class_has_8bitchar will be non-zero if the class contains at least one 256 - character with a code point less than 256; class_one_char will be 1 if the - class contains just one character; xclass_has_prop will be TRUE if Unicode - property checks are present in the class. */ - class_has_8bitchar = 0; - class_one_char = 0; -#ifdef SUPPORT_WIDE_CHARS - xclass_has_prop = FALSE; -#endif + /* ---- Recursion/subroutine calls by name ---- */ - /* Initialize the 256-bit (32-byte) bit map to all zeros. We build the map - in a temporary bit of memory, in case the class contains fewer than two - 8-bit characters because in that case the compiled code doesn't use the bit - map. */ + case CHAR_AMPERSAND: + RECURSE_BY_NAME: + if (!read_name(&ptr, ptrend, CHAR_RIGHT_PARENTHESIS, &offset, &name, + &namelen, &errorcode, cb)) goto FAILED; + *parsed_pattern++ = META_RECURSE_BYNAME; + *parsed_pattern++ = namelen; + PUTOFFSET(offset, parsed_pattern); + okquantifier = TRUE; + break; - memset(classbits, 0, 32 * sizeof(uint8_t)); + /* ---- Callout with numerical or string argument ---- */ - /* Process characters until ] is reached. As the test is at the end of the - loop, an initial ] is taken as a data character. At the start of the loop, - c contains the first code unit of the character. If it is zero, check for - the end of the pattern, to allow binary zero as data. */ + case CHAR_C: + if (++ptr >= ptrend) goto UNCLOSED_PARENTHESIS; - for(;;) - { - PCRE2_SPTR oldptr; -#ifdef EBCDIC - BOOL range_is_literal = TRUE; -#endif + /* If the previous item was a condition starting (?(? an assertion, + optionally preceded by a callout, is expected. This is checked later on, + during actual compilation. However we need to identify this kind of + assertion in this pass because it must not be qualified. The value of + expect_cond_assert is set to 2 after (?(? is processed. We decrement it + for a callout - still leaving a positive value that identifies the + assertion. Multiple callouts or any other items will make it zero or + less, which doesn't matter because they will cause an error later. */ - if (c == CHAR_NULL && ptr >= cb->end_pattern) - { - *errorcodeptr = ERR6; /* Missing terminating ']' */ - goto FAILED; - } + expect_cond_assert = prev_expect_cond_assert - 1; -#ifdef SUPPORT_UNICODE - if (utf && HAS_EXTRALEN(c)) - { /* Braces are required because the */ - GETCHARLEN(c, ptr, ptr); /* macro generates multiple statements */ - } -#endif + /* If previous_callout is not NULL, it means this follows a previous + callout. If it was a manual callout, do nothing; this means its "length + of next pattern item" field will remain zero. If it was an automatic + callout, abolish it. */ - /* Inside \Q...\E everything is literal except \E */ + if (previous_callout != NULL && (options & PCRE2_AUTO_CALLOUT) != 0 && + previous_callout == parsed_pattern - 4 && + parsed_pattern[-1] == 255) + parsed_pattern = previous_callout; - if (inescq) - { - if (c == CHAR_BACKSLASH && ptr[1] == CHAR_E) /* If we are at \E */ - { - inescq = FALSE; /* Reset literal state */ - ptr++; /* Skip the 'E' */ - goto CONTINUE_CLASS; /* Carry on with next char */ - } - goto CHECK_RANGE; /* Could be range if \E follows */ - } + /* Save for updating next pattern item length, and skip one item before + completing. */ - /* Handle POSIX class names. Perl allows a negation extension of the - form [:^name:]. A square bracket that doesn't match the syntax is - treated as a literal. We also recognize the POSIX constructions - [.ch.] and [=ch=] ("collating elements") and fault them, as Perl - 5.6 and 5.8 do. */ + previous_callout = parsed_pattern; + after_manual_callout = 1; - if (c == CHAR_LEFT_SQUARE_BRACKET && - (ptr[1] == CHAR_COLON || ptr[1] == CHAR_DOT || - ptr[1] == CHAR_EQUALS_SIGN) && check_posix_syntax(ptr, &tempptr)) + /* Handle a string argument; specific delimiter is required. */ + + if (*ptr != CHAR_RIGHT_PARENTHESIS && !IS_DIGIT(*ptr)) { - BOOL local_negate = FALSE; - int posix_class, taboffset, tabopt; - register const uint8_t *cbits = cb->cbits; - uint8_t pbits[32]; + PCRE2_SIZE calloutlength; + PCRE2_SPTR startptr = ptr; - if (ptr[1] != CHAR_COLON) + delimiter = 0; + for (i = 0; PRIV(callout_start_delims)[i] != 0; i++) + { + if (*ptr == PRIV(callout_start_delims)[i]) + { + delimiter = PRIV(callout_end_delims)[i]; + break; + } + } + if (delimiter == 0) { - *errorcodeptr = ERR13; + errorcode = ERR82; goto FAILED; } - ptr += 2; - if (*ptr == CHAR_CIRCUMFLEX_ACCENT) + *parsed_pattern = META_CALLOUT_STRING; + parsed_pattern += 3; /* Skip pattern info */ + + for (;;) { - local_negate = TRUE; - should_flip_negation = TRUE; /* Note negative special */ - ptr++; + if (++ptr >= ptrend) + { + errorcode = ERR81; + ptr = startptr; /* To give a more useful message */ + goto FAILED; + } + if (*ptr == delimiter && (++ptr >= ptrend || *ptr != delimiter)) + break; } - posix_class = check_posix_name(ptr, (int)(tempptr - ptr)); - if (posix_class < 0) + calloutlength = (PCRE2_SIZE)(ptr - startptr); + if (calloutlength > UINT32_MAX) { - *errorcodeptr = ERR30; + errorcode = ERR72; goto FAILED; } + *parsed_pattern++ = (uint32_t)calloutlength; + offset = (PCRE2_SIZE)(startptr - cb->start_pattern); + PUTOFFSET(offset, parsed_pattern); + } - /* If matching is caseless, upper and lower are converted to - alpha. This relies on the fact that the class table starts with - alpha, lower, upper as the first 3 entries. */ - - if ((options & PCRE2_CASELESS) != 0 && posix_class <= 2) - posix_class = 0; + /* Handle a callout with an optional numerical argument, which must be + less than or equal to 255. A missing argument gives 0. */ - /* When PCRE2_UCP is set, some of the POSIX classes are converted to - different escape sequences that use Unicode properties \p or \P. Others - that are not available via \p or \P generate XCL_PROP/XCL_NOTPROP - directly. UCP support is not available unless UTF support is.*/ - -#ifdef SUPPORT_UNICODE - if ((options & PCRE2_UCP) != 0) + else + { + int n = 0; + *parsed_pattern = META_CALLOUT_NUMBER; /* Numerical callout */ + parsed_pattern += 3; /* Skip pattern info */ + while (ptr < ptrend && IS_DIGIT(*ptr)) { - unsigned int ptype = 0; - int pc = posix_class + ((local_negate)? POSIX_SUBSIZE/2 : 0); - - /* The posix_substitutes table specifies which POSIX classes can be - converted to \p or \P items. This can only happen at top nestling - level, as there will never be a POSIX class in a string that is - substituted for something else. */ - - if (posix_substitutes[pc] != NULL) + n = n * 10 + *ptr++ - CHAR_0; + if (n > 255) { - cb->nestptr[0] = tempptr + 1; - ptr = posix_substitutes[pc] - 1; - goto CONTINUE_CLASS; - } - - /* There are three other classes that generate special property calls - that are recognized only in an XCLASS. */ - - else switch(posix_class) - { - case PC_GRAPH: - ptype = PT_PXGRAPH; - /* Fall through */ - case PC_PRINT: - if (ptype == 0) ptype = PT_PXPRINT; - /* Fall through */ - case PC_PUNCT: - if (ptype == 0) ptype = PT_PXPUNCT; - *class_uchardata++ = local_negate? XCL_NOTPROP : XCL_PROP; - *class_uchardata++ = (PCRE2_UCHAR)ptype; - *class_uchardata++ = 0; - xclass_has_prop = TRUE; - ptr = tempptr + 1; - goto CONTINUE_CLASS; - - /* For the other POSIX classes (ascii, xdigit) we are going to fall - through to the non-UCP case and build a bit map for characters with - code points less than 256. However, if we are in a negated POSIX - class, characters with code points greater than 255 must either all - match or all not match, depending on whether the whole class is not - or is negated. For example, for [[:^ascii:]... they must all match, - whereas for [^[:^xdigit:]... they must not. - - In the special case where there are no xclass items, this is - automatically handled by the use of OP_CLASS or OP_NCLASS, but an - explicit range is needed for OP_XCLASS. Setting a flag here causes - the range to be generated later when it is known that OP_XCLASS is - required. */ - - default: - match_all_or_no_wide_chars |= local_negate; - break; + errorcode = ERR38; + goto FAILED; } } -#endif /* SUPPORT_UNICODE */ + *parsed_pattern++ = n; + } - /* In the non-UCP case, or when UCP makes no difference, we build the - bit map for the POSIX class in a chunk of local store because we may be - adding and subtracting from it, and we don't want to subtract bits that - may be in the main map already. At the end we or the result into the - bit map that is being built. */ + /* Both formats must have a closing parenthesis */ - posix_class *= 3; + if (ptr >= ptrend || *ptr != CHAR_RIGHT_PARENTHESIS) + { + errorcode = ERR39; + goto FAILED; + } + ptr++; - /* Copy in the first table (always present) */ + /* Remember the offset to the next item in the pattern, and set a default + length. This should get updated after the next item is read. */ - memcpy(pbits, cbits + posix_class_maps[posix_class], - 32 * sizeof(uint8_t)); + previous_callout[1] = ptr - cb->start_pattern; + previous_callout[2] = 0; + break; /* End callout */ - /* If there is a second table, add or remove it as required. */ - taboffset = posix_class_maps[posix_class + 1]; - tabopt = posix_class_maps[posix_class + 2]; + /* ---- Conditional group ---- */ - if (taboffset >= 0) - { - if (tabopt >= 0) - for (c = 0; c < 32; c++) pbits[c] |= cbits[(int)c + taboffset]; - else - for (c = 0; c < 32; c++) pbits[c] &= ~cbits[(int)c + taboffset]; - } + /* A condition can be an assertion, a number (referring to a numbered + group's having been set), a name (referring to a named group), or 'R', + referring to overall recursion. R and R&name are also permitted + for recursion state tests. Numbers may be preceded by + or - to specify a + relative group number. - /* Now see if we need to remove any special characters. An option - value of 1 removes vertical space and 2 removes underscore. */ + There are several syntaxes for testing a named group: (?(name)) is used + by Python; Perl 5.10 onwards uses (?() or (?('name')). - if (tabopt < 0) tabopt = -tabopt; - if (tabopt == 1) pbits[1] &= ~0x3c; - else if (tabopt == 2) pbits[11] &= 0x7f; + There are two unfortunate ambiguities. 'R' can be the recursive thing or + the name 'R' (and similarly for 'R' followed by digits). 'DEFINE' can be + the Perl DEFINE feature or the Python named test. We look for a name + first; if not found, we try the other case. - /* Add the POSIX table or its complement into the main table that is - being built and we are done. */ + For compatibility with auto-callouts, we allow a callout to be specified + before a condition that is an assertion. */ - if (local_negate) - for (c = 0; c < 32; c++) classbits[c] |= ~pbits[c]; - else - for (c = 0; c < 32; c++) classbits[c] |= pbits[c]; + case CHAR_LEFT_PARENTHESIS: + if (++ptr >= ptrend) goto UNCLOSED_PARENTHESIS; + nest_depth++; - ptr = tempptr + 1; - /* Every class contains at least one < 256 character. */ - class_has_8bitchar = 1; - /* Every class contains at least two characters. */ - class_one_char = 2; - goto CONTINUE_CLASS; /* End of POSIX syntax handling */ + /* If the next character is ? there must be an assertion next (optionally + preceded by a callout). We do not check this here, but instead we set + expect_cond_assert to 2. If this is still greater than zero (callouts + decrement it) when the next assertion is read, it will be marked as a + condition that must not be repeated. A value greater than zero also + causes checking that an assertion (possibly with callout) follows. */ + + if (*ptr == CHAR_QUESTION_MARK) + { + *parsed_pattern++ = META_COND_ASSERT; + ptr--; /* Pull pointer back to the opening parenthesis. */ + expect_cond_assert = 2; + break; /* End of conditional */ } - /* Backslash may introduce a single character, or it may introduce one - of the specials, which just set a flag. The sequence \b is a special - case. Inside a class (and only there) it is treated as backspace. We - assume that other escapes have more than one character in them, so - speculatively set both class_has_8bitchar and class_one_char bigger - than one. Unrecognized escapes fall through and are faulted. */ + /* Handle (?([+-]number)... */ - if (c == CHAR_BACKSLASH) + if (read_number(&ptr, ptrend, cb->bracount, MAX_GROUP_NUMBER, ERR61, &i, + &errorcode)) { - escape = PRIV(check_escape)(&ptr, cb->end_pattern, &ec, errorcodeptr, - options, TRUE, cb); - if (*errorcodeptr != 0) goto FAILED; - if (escape == 0) /* Escaped single char */ - { - c = ec; -#ifdef EBCDIC - range_is_literal = FALSE; -#endif - } - else if (escape == ESC_b) c = CHAR_BS; /* \b is backspace in a class */ - else if (escape == ESC_N) /* \N is not supported in a class */ + if (i <= 0) { - *errorcodeptr = ERR71; + errorcode = ERR15; goto FAILED; } - else if (escape == ESC_Q) /* Handle start of quoted string */ - { - if (ptr[1] == CHAR_BACKSLASH && ptr[2] == CHAR_E) - { - ptr += 2; /* avoid empty string */ - } - else inescq = TRUE; - goto CONTINUE_CLASS; - } - else if (escape == ESC_E) goto CONTINUE_CLASS; /* Ignore orphan \E */ - - else /* Handle \d-type escapes */ - { - register const uint8_t *cbits = cb->cbits; - /* Every class contains at least two < 256 characters. */ - class_has_8bitchar++; - /* Every class contains at least two characters. */ - class_one_char += 2; - - switch (escape) - { -#ifdef SUPPORT_UNICODE - case ESC_du: /* These are the values given for \d etc */ - case ESC_DU: /* when PCRE2_UCP is set. We replace the */ - case ESC_wu: /* escape sequence with an appropriate \p */ - case ESC_WU: /* or \P to test Unicode properties instead */ - case ESC_su: /* of the default ASCII testing. This might be */ - case ESC_SU: /* a 2nd-level nesting for [[:<:]] or [[:>:]]. */ - cb->nestptr[1] = cb->nestptr[0]; - cb->nestptr[0] = ptr; - ptr = substitutes[escape - ESC_DU] - 1; /* Just before substitute */ - class_has_8bitchar--; /* Undo! */ - break; -#endif - case ESC_d: - for (c = 0; c < 32; c++) classbits[c] |= cbits[c+cbit_digit]; - break; - - case ESC_D: - should_flip_negation = TRUE; - for (c = 0; c < 32; c++) classbits[c] |= ~cbits[c+cbit_digit]; - break; - - case ESC_w: - for (c = 0; c < 32; c++) classbits[c] |= cbits[c+cbit_word]; - break; - - case ESC_W: - should_flip_negation = TRUE; - for (c = 0; c < 32; c++) classbits[c] |= ~cbits[c+cbit_word]; - break; - - /* Perl 5.004 onwards omitted VT from \s, but restored it at Perl - 5.18. Before PCRE 8.34, we had to preserve the VT bit if it was - previously set by something earlier in the character class. - Luckily, the value of CHAR_VT is 0x0b in both ASCII and EBCDIC, so - we could just adjust the appropriate bit. From PCRE 8.34 we no - longer treat \s and \S specially. */ - - case ESC_s: - for (c = 0; c < 32; c++) classbits[c] |= cbits[c+cbit_space]; - break; - - case ESC_S: - should_flip_negation = TRUE; - for (c = 0; c < 32; c++) classbits[c] |= ~cbits[c+cbit_space]; - break; + *parsed_pattern++ = META_COND_NUMBER; + offset = (PCRE2_SIZE)(ptr - cb->start_pattern - 2); + PUTOFFSET(offset, parsed_pattern); + *parsed_pattern++ = i; + } + else if (errorcode != 0) goto FAILED; /* Number too big */ - /* The rest apply in both UCP and non-UCP cases. */ + /* No number found. Handle the special case (?(VERSION[>]=n.m)... */ - case ESC_h: - (void)add_list_to_class(classbits, &class_uchardata, options, cb, - PRIV(hspace_list), NOTACHAR); - break; + else if (ptrend - ptr >= 10 && + PRIV(strncmp_c8)(ptr, STRING_VERSION, 7) == 0 && + ptr[7] != CHAR_RIGHT_PARENTHESIS) + { + uint32_t ge = 0; + int major = 0; + int minor = 0; - case ESC_H: - (void)add_not_list_to_class(classbits, &class_uchardata, options, - cb, PRIV(hspace_list)); - break; + ptr += 7; + if (*ptr == CHAR_GREATER_THAN_SIGN) + { + ge = 1; + ptr++; + } - case ESC_v: - (void)add_list_to_class(classbits, &class_uchardata, options, cb, - PRIV(vspace_list), NOTACHAR); - break; + /* NOTE: cannot write IS_DIGIT(*(++ptr)) here because IS_DIGIT + references its argument twice. */ - case ESC_V: - (void)add_not_list_to_class(classbits, &class_uchardata, options, - cb, PRIV(vspace_list)); - break; + if (*ptr != CHAR_EQUALS_SIGN || (ptr++, !IS_DIGIT(*ptr))) + goto BAD_VERSION_CONDITION; - case ESC_p: - case ESC_P: -#ifdef SUPPORT_UNICODE - { - BOOL negated; - unsigned int ptype = 0, pdata = 0; - if (!get_ucp(&ptr, &negated, &ptype, &pdata, errorcodeptr, cb)) - goto FAILED; - *class_uchardata++ = ((escape == ESC_p) != negated)? - XCL_PROP : XCL_NOTPROP; - *class_uchardata++ = ptype; - *class_uchardata++ = pdata; - xclass_has_prop = TRUE; - class_has_8bitchar--; /* Undo! */ - } - break; -#else - *errorcodeptr = ERR45; - goto FAILED; -#endif - /* Unrecognized escapes are faulted. */ + if (!read_number(&ptr, ptrend, -1, 1000, ERR79, &major, &errorcode)) + goto FAILED; - default: - *errorcodeptr = ERR7; + if (ptr >= ptrend) goto BAD_VERSION_CONDITION; + if (*ptr == CHAR_DOT) + { + if (++ptr >= ptrend || !IS_DIGIT(*ptr)) goto BAD_VERSION_CONDITION; + if (!read_number(&ptr, ptrend, -1, 99 , ERR79, &minor, &errorcode)) goto FAILED; - } - - /* Handled \d-type escape */ - - goto CONTINUE_CLASS; + if (minor < 10) minor *= 10; + if (ptr >= ptrend || *ptr != CHAR_RIGHT_PARENTHESIS) + goto BAD_VERSION_CONDITION; } - /* Control gets here if the escape just defined a single character. - This is in c and may be greater than 256. */ - - escape = 0; - } /* End of backslash handling */ - - /* A character may be followed by '-' to form a range. However, Perl does - not permit ']' to be the end of the range. A '-' character at the end is - treated as a literal. Perl ignores orphaned \E sequences entirely. The - code for handling \Q and \E is messy. */ - - CHECK_RANGE: - while (ptr[1] == CHAR_BACKSLASH && ptr[2] == CHAR_E) - { - inescq = FALSE; - ptr += 2; + *parsed_pattern++ = META_COND_VERSION; + *parsed_pattern++ = ge; + *parsed_pattern++ = major; + *parsed_pattern++ = minor; } - oldptr = ptr; - - /* Remember if \r or \n were explicitly used */ - - if (c == CHAR_CR || c == CHAR_NL) cb->external_flags |= PCRE2_HASCRORLF; - /* Check for range */ + /* All the remaining cases now require us to read a name. We cannot at + this stage distinguish ambiguous cases such as (?(R12) which might be a + recursion test by number or a name, because the named groups have not yet + all been identified. Those cases are treated as names, but given a + different META code. */ - if (!inescq && ptr[1] == CHAR_MINUS) + else { - uint32_t d; - ptr += 2; - while (*ptr == CHAR_BACKSLASH && ptr[1] == CHAR_E) ptr += 2; - - /* If we hit \Q (not followed by \E) at this point, go into escaped - mode. */ + BOOL was_r_ampersand = FALSE; - while (*ptr == CHAR_BACKSLASH && ptr[1] == CHAR_Q) + if (*ptr == CHAR_R && ptrend - ptr > 1 && ptr[1] == CHAR_AMPERSAND) { - ptr += 2; - if (*ptr == CHAR_BACKSLASH && ptr[1] == CHAR_E) - { ptr += 2; continue; } - inescq = TRUE; - break; + terminator = CHAR_RIGHT_PARENTHESIS; + was_r_ampersand = TRUE; + ptr++; } - - /* Minus (hyphen) at the end of a class is treated as a literal, so put - back the pointer and jump to handle the character that preceded it. */ - - if (*ptr == CHAR_NULL || (!inescq && *ptr == CHAR_RIGHT_SQUARE_BRACKET)) + else if (*ptr == CHAR_LESS_THAN_SIGN) + terminator = CHAR_GREATER_THAN_SIGN; + else if (*ptr == CHAR_APOSTROPHE) + terminator = CHAR_APOSTROPHE; + else { - ptr = oldptr; - goto CLASS_SINGLE_CHARACTER; + terminator = CHAR_RIGHT_PARENTHESIS; + ptr--; /* Point to char before name */ } + if (!read_name(&ptr, ptrend, terminator, &offset, &name, &namelen, + &errorcode, cb)) goto FAILED; - /* Otherwise, we have a potential range; pick up the next character */ + /* Handle (?(R&name) */ -#ifdef SUPPORT_UNICODE - if (utf) - { /* Braces are required because the */ - GETCHARLEN(d, ptr, ptr); /* macro generates multiple statements */ + if (was_r_ampersand) + { + *parsed_pattern = META_COND_RNAME; + ptr--; /* Back to closing parens */ } - else -#endif - d = *ptr; /* Not UTF mode */ - /* The second part of a range can be a single-character escape - sequence, but not any of the other escapes. Perl treats a hyphen as a - literal in such circumstances. However, in Perl's warning mode, a - warning is given, so PCRE now faults it as it is almost certainly a - mistake on the user's part. */ + /* Handle (?(name). If the name is "DEFINE" we identify it with a + special code. Likewise if the name consists of R followed only by + digits. Otherwise, handle it like a quoted name. */ - if (!inescq) + else if (terminator == CHAR_RIGHT_PARENTHESIS) { - if (d == CHAR_BACKSLASH) - { - int descape; - descape = PRIV(check_escape)(&ptr, cb->end_pattern, &d, - errorcodeptr, options, TRUE, cb); - if (*errorcodeptr != 0) goto FAILED; -#ifdef EBCDIC - range_is_literal = FALSE; -#endif - /* 0 means a character was put into d; \b is backspace; any other - special causes an error. */ - - if (descape != 0) - { - if (descape == ESC_b) d = CHAR_BS; else - { - *errorcodeptr = ERR50; - goto FAILED; - } - } - } - - /* A hyphen followed by a POSIX class is treated in the same way. */ - - else if (d == CHAR_LEFT_SQUARE_BRACKET && - (ptr[1] == CHAR_COLON || ptr[1] == CHAR_DOT || - ptr[1] == CHAR_EQUALS_SIGN) && - check_posix_syntax(ptr, &tempptr)) + if (namelen == 6 && PRIV(strncmp_c8)(name, STRING_DEFINE, 6) == 0) + *parsed_pattern = META_COND_DEFINE; + else { - *errorcodeptr = ERR50; - goto FAILED; + for (i = 1; i < (int)namelen; i++) + if (!IS_DIGIT(name[i])) break; + *parsed_pattern = (*name == CHAR_R && i >= (int)namelen)? + META_COND_RNUMBER : META_COND_NAME; } + ptr--; /* Back to closing parens */ } - /* Check that the two values are in the correct order. Optimize - one-character ranges. */ - - if (d < c) - { - *errorcodeptr = ERR8; - goto FAILED; - } - if (d == c) goto CLASS_SINGLE_CHARACTER; /* A few lines below */ - - /* We have found a character range, so single character optimizations - cannot be done anymore. Any value greater than 1 indicates that there - is more than one character. */ - - class_one_char = 2; - - /* Remember an explicit \r or \n, and add the range to the class. */ - - if (d == CHAR_CR || d == CHAR_NL) cb->external_flags |= PCRE2_HASCRORLF; - - /* In an EBCDIC environment, Perl treats alphabetic ranges specially - because there are holes in the encoding, and simply using the range A-Z - (for example) would include the characters in the holes. This applies - only to literal ranges; [\xC1-\xE9] is different to [A-Z]. */ + /* Handle (?('name') or (?() */ -#ifdef EBCDIC - if (range_is_literal && - (cb->ctypes[c] & ctype_letter) != 0 && - (cb->ctypes[d] & ctype_letter) != 0 && - (c <= CHAR_z) == (d <= CHAR_z)) - { - uint32_t uc = (c <= CHAR_z)? 0 : 64; - uint32_t C = c - uc; - uint32_t D = d - uc; + else *parsed_pattern = META_COND_NAME; - if (C <= CHAR_i) - { - class_has_8bitchar += - add_to_class(classbits, &class_uchardata, options, cb, C + uc, - ((D < CHAR_i)? D : CHAR_i) + uc); - C = CHAR_j; - } + /* All these cases except DEFINE end with the name length and offset; + DEFINE just has an offset (for the "too many branches" error). */ - if (C <= D && C <= CHAR_r) - { - class_has_8bitchar += - add_to_class(classbits, &class_uchardata, options, cb, C + uc, - ((D < CHAR_r)? D : CHAR_r) + uc); - C = CHAR_s; - } + if (*parsed_pattern++ != META_COND_DEFINE) *parsed_pattern++ = namelen; + PUTOFFSET(offset, parsed_pattern); + } /* End cases that read a name */ - if (C <= D) - { - class_has_8bitchar += - add_to_class(classbits, &class_uchardata, options, cb, C + uc, - D + uc); - } - } - else -#endif - class_has_8bitchar += - add_to_class(classbits, &class_uchardata, options, cb, c, d); - goto CONTINUE_CLASS; /* Go get the next char in the class */ - } + /* Check the closing parenthesis of the condition */ - /* Handle a single character - we can get here for a normal non-escape - char, or after \ that introduces a single character or for an apparent - range that isn't. Only the value 1 matters for class_one_char, so don't - increase it if it is already 2 or more ... just in case there's a class - with a zillion characters in it. */ - - CLASS_SINGLE_CHARACTER: - if (class_one_char < 2) class_one_char++; - - /* If class_one_char is 1 and xclass_has_prop is false, we have the first - single character in the class, and there have been no prior ranges, or - XCLASS items generated by escapes. If this is the final character in the - class, we can optimize by turning the item into a 1-character OP_CHAR[I] - if it's positive, or OP_NOT[I] if it's negative. In the positive case, it - can cause firstcu to be set. Otherwise, there can be no first char if - this item is first, whatever repeat count may follow. In the case of - reqcu, save the previous value for reinstating. */ - - if (!inescq && -#ifdef SUPPORT_UNICODE - !xclass_has_prop && -#endif - class_one_char == 1 && ptr[1] == CHAR_RIGHT_SQUARE_BRACKET) + if (ptr >= ptrend || *ptr != CHAR_RIGHT_PARENTHESIS) { - ptr++; - zeroreqcu = reqcu; - zeroreqcuflags = reqcuflags; - - if (negate_class) - { -#ifdef SUPPORT_UNICODE - int d; -#endif - if (firstcuflags == REQ_UNSET) firstcuflags = REQ_NONE; - zerofirstcu = firstcu; - zerofirstcuflags = firstcuflags; + errorcode = ERR24; + goto FAILED; + } + ptr++; + break; /* End of condition processing */ - /* For caseless UTF mode, check whether this character has more than - one other case. If so, generate a special OP_NOTPROP item instead of - OP_NOTI. */ -#ifdef SUPPORT_UNICODE - if (utf && (options & PCRE2_CASELESS) != 0 && - (d = UCD_CASESET(c)) != 0) - { - *code++ = OP_NOTPROP; - *code++ = PT_CLIST; - *code++ = d; - } - else -#endif - /* Char has only one other case, or UCP not available */ + /* ---- Atomic group ---- */ - { - *code++ = ((options & PCRE2_CASELESS) != 0)? OP_NOTI: OP_NOT; - code += PUTCHAR(c, code); - } + case CHAR_GREATER_THAN_SIGN: + *parsed_pattern++ = META_ATOMIC; + nest_depth++; + ptr++; + break; - /* We are finished with this character class */ - goto END_CLASS; - } + /* ---- Lookahead assertions ---- */ - /* For a single, positive character, get the value into mcbuffer, and - then we can handle this with the normal one-character code. */ + case CHAR_EQUALS_SIGN: + *parsed_pattern++ = META_LOOKAHEAD; + ptr++; + goto POST_ASSERTION; - mclength = PUTCHAR(c, mcbuffer); - goto ONE_CHAR; - } /* End of 1-char optimization */ + case CHAR_EXCLAMATION_MARK: + *parsed_pattern++ = META_LOOKAHEADNOT; + ptr++; + goto POST_ASSERTION; - /* There is more than one character in the class, or an XCLASS item - has been generated. Add this character to the class. */ - class_has_8bitchar += - add_to_class(classbits, &class_uchardata, options, cb, c, c); + /* ---- Lookbehind assertions ---- */ - /* Continue to the next character in the class. Closing square bracket - not within \Q..\E ends the class. A NULL character terminates a - nested substitution string, but may be a data character in the main - pattern (tested at the start of this loop). */ + /* (?< followed by = or ! is a lookbehind assertion. Otherwise (?< is the + start of the name of a capturing group. */ - CONTINUE_CLASS: - c = *(++ptr); - if (c == CHAR_NULL && cb->nestptr[0] != NULL) + case CHAR_LESS_THAN_SIGN: + if (ptrend - ptr <= 1 || + (ptr[1] != CHAR_EQUALS_SIGN && ptr[1] != CHAR_EXCLAMATION_MARK)) { - ptr = cb->nestptr[0]; - cb->nestptr[0] = cb->nestptr[1]; - cb->nestptr[1] = NULL; - c = *(++ptr); + terminator = CHAR_GREATER_THAN_SIGN; + goto DEFINE_NAME; } - -#ifdef SUPPORT_WIDE_CHARS - /* If any wide characters have been encountered, set xclass = TRUE. Then, - in the pre-compile phase, accumulate the length of the wide characters - and reset the pointer. This is so that very large classes that contain a - zillion wide characters do not overwrite the work space (which is on the - stack). */ - - if (class_uchardata > class_uchardata_base) + *parsed_pattern++ = (ptr[1] == CHAR_EQUALS_SIGN)? + META_LOOKBEHIND : META_LOOKBEHINDNOT; + *has_lookbehind = TRUE; + offset = (PCRE2_SIZE)(ptr - cb->start_pattern - 2); + PUTOFFSET(offset, parsed_pattern); + ptr += 2; + /* Fall through */ + + /* If the previous item was a condition starting (?(? an assertion, + optionally preceded by a callout, is expected. This is checked later on, + during actual compilation. However we need to identify this kind of + assertion in this pass because it must not be qualified. The value of + expect_cond_assert is set to 2 after (?(? is processed. We decrement it + for a callout - still leaving a positive value that identifies the + assertion. Multiple callouts or any other items will make it zero or + less, which doesn't matter because they will cause an error later. */ + + POST_ASSERTION: + nest_depth++; + if (prev_expect_cond_assert > 0) { - xclass = TRUE; - if (lengthptr != NULL) + if (top_nest == NULL) top_nest = (nest_save *)(cb->start_workspace); + else if (++top_nest >= end_nests) { - *lengthptr += class_uchardata - class_uchardata_base; - class_uchardata = class_uchardata_base; + errorcode = ERR84; + goto FAILED; } + top_nest->nest_depth = nest_depth; + top_nest->flags = NSF_CONDASSERT; + if ((options & PCRE2_EXTENDED) != 0) top_nest->flags |= NSF_EXTENDED; + if ((options & PCRE2_DUPNAMES) != 0) top_nest->flags |= NSF_DUPNAMES; } -#endif - /* An unescaped ] ends the class */ + break; - if (c == CHAR_RIGHT_SQUARE_BRACKET && !inescq) break; - } /* End of main class-processing loop */ - /* If this is the first thing in the branch, there can be no first char - setting, whatever the repeat count. Any reqcu setting must remain - unchanged after any kind of repeat. */ + /* ---- Define a named group ---- */ - if (firstcuflags == REQ_UNSET) firstcuflags = REQ_NONE; - zerofirstcu = firstcu; - zerofirstcuflags = firstcuflags; - zeroreqcu = reqcu; - zeroreqcuflags = reqcuflags; + /* A named group may be defined as (?'name') or (?). In the latter + case we jump to DEFINE_NAME from the disambiguation of (?< above with the + terminator set to '>'. */ - /* If there are characters with values > 255, or Unicode property settings - (\p or \P), we have to compile an extended class, with its own opcode, - unless there were no property settings and there was a negated special such - as \S in the class, and PCRE2_UCP is not set, because in that case all - characters > 255 are in or not in the class, so any that were explicitly - given as well can be ignored. + case CHAR_APOSTROPHE: + terminator = CHAR_APOSTROPHE; /* Terminator */ - In the UCP case, if certain negated POSIX classes ([:^ascii:] or - [^:xdigit:]) were present in a class, we either have to match or not match - all wide characters (depending on whether the whole class is or is not - negated). This requirement is indicated by match_all_or_no_wide_chars being - true. We do this by including an explicit range, which works in both cases. + DEFINE_NAME: + if (!read_name(&ptr, ptrend, terminator, &offset, &name, &namelen, + &errorcode, cb)) goto FAILED; - If, when generating an xclass, there are no characters < 256, we can omit - the bitmap in the actual compiled code. */ + /* We have a name for this capturing group. It is also assigned a number, + which is its primary means of identification. */ -#ifdef SUPPORT_WIDE_CHARS -#ifdef SUPPORT_UNICODE - if (xclass && (xclass_has_prop || !should_flip_negation || - (options & PCRE2_UCP) != 0)) -#elif PCRE2_CODE_UNIT_WIDTH != 8 - if (xclass && (xclass_has_prop || !should_flip_negation)) -#endif - { - if (match_all_or_no_wide_chars) - { - *class_uchardata++ = XCL_RANGE; - class_uchardata += PRIV(ord2utf)(0x100, class_uchardata); - class_uchardata += PRIV(ord2utf)(MAX_UTF_CODE_POINT, class_uchardata); - } - *class_uchardata++ = XCL_END; /* Marks the end of extra data */ - *code++ = OP_XCLASS; - code += LINK_SIZE; - *code = negate_class? XCL_NOT:0; - if (xclass_has_prop) *code |= XCL_HASPROP; + cb->bracount++; + *parsed_pattern++ = META_CAPTURE | cb->bracount; + nest_depth++; - /* If the map is required, move up the extra data to make room for it; - otherwise just move the code pointer to the end of the extra data. */ + /* Check not too many names */ - if (class_has_8bitchar > 0) + if (cb->names_found >= MAX_NAME_COUNT) { - *code++ |= XCL_MAP; - memmove(code + (32 / sizeof(PCRE2_UCHAR)), code, - CU2BYTES(class_uchardata - code)); - if (negate_class && !xclass_has_prop) - for (c = 0; c < 32; c++) classbits[c] = ~classbits[c]; - memcpy(code, classbits, 32); - code = class_uchardata + (32 / sizeof(PCRE2_UCHAR)); + errorcode = ERR49; + goto FAILED; } - else code = class_uchardata; - /* Now fill in the complete length of the item */ + /* Adjust the entry size to accommodate the longest name found. */ - PUT(previous, 1, (int)(code - previous)); - break; /* End of class handling */ - } -#endif - - /* If there are no characters > 255, or they are all to be included or - excluded, set the opcode to OP_CLASS or OP_NCLASS, depending on whether the - whole class was negated and whether there were negative specials such as \S - (non-UCP) in the class. Then copy the 32-byte map into the code vector, - negating it if necessary. */ - - *code++ = (negate_class == should_flip_negation) ? OP_CLASS : OP_NCLASS; - if (lengthptr == NULL) /* Save time in the pre-compile phase */ - { - if (negate_class) - for (c = 0; c < 32; c++) classbits[c] = ~classbits[c]; - memcpy(code, classbits, 32); - } - code += 32 / sizeof(PCRE2_UCHAR); - - END_CLASS: - break; - - - /* ===================================================================*/ - /* Various kinds of repeat; '{' is not necessarily a quantifier, but this - has been tested above. */ - - case CHAR_LEFT_CURLY_BRACKET: - if (!is_quantifier) goto NORMAL_CHAR; - ptr = read_repeat_counts(ptr+1, &repeat_min, &repeat_max, errorcodeptr); - if (*errorcodeptr != 0) goto FAILED; - goto REPEAT; + if (namelen + IMM2_SIZE + 1 > cb->name_entry_size) + cb->name_entry_size = (uint16_t)(namelen + IMM2_SIZE + 1); - case CHAR_ASTERISK: - repeat_min = 0; - repeat_max = -1; - goto REPEAT; + /* Scan the list to check for duplicates. For duplicate names, if the + number is the same, break the loop, which causes the name to be + discarded; otherwise, if DUPNAMES is not set, give an error. + If it is set, allow the name with a different number, but continue + scanning in case this is a duplicate with the same number. For + non-duplicate names, give an error if the number is duplicated. */ - case CHAR_PLUS: - repeat_min = 1; - repeat_max = -1; - goto REPEAT; + isdupname = FALSE; + ng = cb->named_groups; + for (i = 0; i < cb->names_found; i++, ng++) + { + if (namelen == ng->length && + PRIV(strncmp)(name, ng->name, (PCRE2_SIZE)namelen) == 0) + { + if (ng->number == cb->bracount) break; + if ((options & PCRE2_DUPNAMES) == 0) + { + errorcode = ERR43; + goto FAILED; + } + isdupname = ng->isdup = TRUE; /* Mark as a duplicate */ + cb->dupnames = TRUE; /* Duplicate names exist */ + } + else if (ng->number == cb->bracount) + { + errorcode = ERR65; + goto FAILED; + } + } - case CHAR_QUESTION_MARK: - repeat_min = 0; - repeat_max = 1; + if (i < cb->names_found) break; /* Ignore duplicate with same number */ - REPEAT: - if (previous == NULL) - { - *errorcodeptr = ERR9; - goto FAILED; - } + /* Increase the list size if necessary */ - if (repeat_min == 0) - { - firstcu = zerofirstcu; /* Adjust for zero repeat */ - firstcuflags = zerofirstcuflags; - reqcu = zeroreqcu; /* Ditto */ - reqcuflags = zeroreqcuflags; - } + if (cb->names_found >= cb->named_group_list_size) + { + uint32_t newsize = cb->named_group_list_size * 2; + named_group *newspace = + cb->cx->memctl.malloc(newsize * sizeof(named_group), + cb->cx->memctl.memory_data); + if (newspace == NULL) + { + errorcode = ERR21; + goto FAILED; + } - /* Remember whether this is a variable length repeat */ + memcpy(newspace, cb->named_groups, + cb->named_group_list_size * sizeof(named_group)); + if (cb->named_group_list_size > NAMED_GROUP_LIST_SIZE) + cb->cx->memctl.free((void *)cb->named_groups, + cb->cx->memctl.memory_data); + cb->named_groups = newspace; + cb->named_group_list_size = newsize; + } - reqvary = (repeat_min == repeat_max)? 0 : REQ_VARY; + /* Add this name to the list */ - op_type = 0; /* Default single-char op codes */ - possessive_quantifier = FALSE; /* Default not possessive quantifier */ + cb->named_groups[cb->names_found].name = name; + cb->named_groups[cb->names_found].length = (uint16_t)namelen; + cb->named_groups[cb->names_found].number = cb->bracount; + cb->named_groups[cb->names_found].isdup = (uint16_t)isdupname; + cb->names_found++; + break; + } /* End of (? switch */ + break; /* End of ( handling */ - /* Save start of previous item, in case we have to move it up in order to - insert something before it. */ - tempcode = previous; + /* ---- Branch terminators ---- */ - /* Before checking for a possessive quantifier, we must skip over - whitespace and comments in extended mode because Perl allows white space at - this point. */ + /* Alternation: reset the capture count if we are in a (?| group. */ - if ((options & PCRE2_EXTENDED) != 0) + case CHAR_VERTICAL_LINE: + if (top_nest != NULL && top_nest->nest_depth == nest_depth && + (top_nest->flags & NSF_RESET) != 0) { - ptr++; - for (;;) - { - while (MAX_255(*ptr) && (cb->ctypes[*ptr] & ctype_space) != 0) ptr++; - if (*ptr != CHAR_NUMBER_SIGN) break; - ptr++; - while (ptr < cb->end_pattern) - { - if (IS_NEWLINE(ptr)) /* For non-fixed-length newline cases, */ - { /* IS_NEWLINE sets cb->nllen. */ - ptr += cb->nllen; - break; - } - ptr++; -#ifdef SUPPORT_UNICODE - if (utf) FORWARDCHAR(ptr); -#endif - } /* Loop for comment characters */ - } /* Loop for multiple comments */ - ptr--; /* Last code unit of previous character. */ + if (cb->bracount > top_nest->max_group) + top_nest->max_group = (uint16_t)cb->bracount; + cb->bracount = top_nest->reset_group; } + *parsed_pattern++ = META_ALT; + break; - /* If the next character is '+', we have a possessive quantifier. This - implies greediness, whatever the setting of the PCRE2_UNGREEDY option. - If the next character is '?' this is a minimizing repeat, by default, - but if PCRE2_UNGREEDY is set, it works the other way round. We change the - repeat type to the non-default. */ + /* End of group; reset the capture count to the maximum if we are in a (?| + group and/or reset the extended and dupnames options. Disallow quantifier + for a condition that is an assertion. */ - if (ptr[1] == CHAR_PLUS) + case CHAR_RIGHT_PARENTHESIS: + okquantifier = TRUE; + if (top_nest != NULL && top_nest->nest_depth == nest_depth) { - repeat_type = 0; /* Force greedy */ - possessive_quantifier = TRUE; - ptr++; + if ((top_nest->flags & NSF_RESET) != 0 && + top_nest->max_group > cb->bracount) + cb->bracount = top_nest->max_group; + if ((top_nest->flags & NSF_EXTENDED) != 0) options |= PCRE2_EXTENDED; + else options &= ~PCRE2_EXTENDED; + if ((top_nest->flags & NSF_DUPNAMES) != 0) options |= PCRE2_DUPNAMES; + else options &= ~PCRE2_DUPNAMES; + if ((top_nest->flags & NSF_CONDASSERT) != 0) + okquantifier = FALSE; + if (top_nest == (nest_save *)(cb->start_workspace)) top_nest = NULL; + else top_nest--; } - else if (ptr[1] == CHAR_QUESTION_MARK) + if (nest_depth == 0) /* Unmatched closing parenthesis */ { - repeat_type = greedy_non_default; - ptr++; + errorcode = ERR22; + goto FAILED_BACK; } - else repeat_type = greedy_default; + nest_depth--; + *parsed_pattern++ = META_KET; + break; + } /* End of switch on pattern character */ + } /* End of main character scan loop */ - /* If the repeat is {1} we can ignore it. */ +/* End of pattern reached. Check for missing ) at the end of a verb name. */ - if (repeat_max == 1 && repeat_min == 1) goto END_REPEAT; +if (inverbname && ptr >= ptrend) + { + errorcode = ERR60; + goto FAILED; + } - /* If previous was a recursion call, wrap it in atomic brackets so that - previous becomes the atomic group. All recursions were so wrapped in the - past, but it no longer happens for non-repeated recursions. In fact, the - repeated ones could be re-implemented independently so as not to need this, - but for the moment we rely on the code for repeating groups. */ +/* Manage callout for the final item */ - if (*previous == OP_RECURSE) - { - memmove(previous + 1 + LINK_SIZE, previous, CU2BYTES(1 + LINK_SIZE)); - *previous = OP_ONCE; - PUT(previous, 1, 2 + 2*LINK_SIZE); - previous[2 + 2*LINK_SIZE] = OP_KET; - PUT(previous, 3 + 2*LINK_SIZE, 2 + 2*LINK_SIZE); - code += 2 + 2 * LINK_SIZE; - length_prevgroup = 3 + 3*LINK_SIZE; - } +parsed_pattern = manage_callouts(ptr, &previous_callout, options, + parsed_pattern, cb); - /* Now handle repetition for the different types of item. */ +/* Terminate the parsed pattern, then return success if all groups are closed. +Otherwise we have unclosed parentheses. */ - /* If previous was a character or negated character match, abolish the item - and generate a repeat item instead. If a char item has a minimum of more - than one, ensure that it is set in reqcu - it might not be if a sequence - such as x{3} is the first thing in a branch because the x will have gone - into firstcu instead. */ +if (parsed_pattern >= parsed_pattern_end) + { + errorcode = ERR63; /* Internal error (parsed pattern overflow) */ + goto FAILED; + } +*parsed_pattern = META_END; +if (nest_depth == 0) return 0; - if (*previous == OP_CHAR || *previous == OP_CHARI - || *previous == OP_NOT || *previous == OP_NOTI) - { - switch (*previous) - { - default: /* Make compiler happy. */ - case OP_CHAR: op_type = OP_STAR - OP_STAR; break; - case OP_CHARI: op_type = OP_STARI - OP_STAR; break; - case OP_NOT: op_type = OP_NOTSTAR - OP_STAR; break; - case OP_NOTI: op_type = OP_NOTSTARI - OP_STAR; break; - } +UNCLOSED_PARENTHESIS: +errorcode = ERR14; - /* Deal with UTF characters that take up more than one code unit. It's - easier to write this out separately than try to macrify it. Use c to - hold the length of the character in code units, plus UTF_LENGTH to flag - that it's a length rather than a small character. */ +/* Come here for all failures. */ -#ifdef MAYBE_UTF_MULTI - if (utf && NOT_FIRSTCU(code[-1])) - { - PCRE2_UCHAR *lastchar = code - 1; - BACKCHAR(lastchar); - c = (int)(code - lastchar); /* Length of UTF character */ - memcpy(utf_units, lastchar, CU2BYTES(c)); /* Save the char */ - c |= UTF_LENGTH; /* Flag c as a length */ - } - else -#endif /* MAYBE_UTF_MULTI */ +FAILED: +cb->erroroffset = (PCRE2_SIZE)(ptr - cb->start_pattern); +return errorcode; - /* Handle the case of a single charater - either with no UTF support, or - with UTF disabled, or for a single-code-unit UTF character. */ - { - c = code[-1]; - if (*previous <= OP_CHARI && repeat_min > 1) - { - reqcu = c; - reqcuflags = req_caseopt | cb->req_varyopt; - } - } +/* Some errors need to indicate the previous character. */ - goto OUTPUT_SINGLE_REPEAT; /* Code shared with single character types */ - } +FAILED_BACK: +ptr--; +goto FAILED; - /* If previous was a character type match (\d or similar), abolish it and - create a suitable repeat item. The code is shared with single-character - repeats by setting op_type to add a suitable offset into repeat_type. Note - the the Unicode property types will be present only when SUPPORT_UNICODE is - defined, but we don't wrap the little bits of code here because it just - makes it horribly messy. */ +/* This failure happens several times. */ - else if (*previous < OP_EODN) - { - PCRE2_UCHAR *oldcode; - int prop_type, prop_value; - op_type = OP_TYPESTAR - OP_STAR; /* Use type opcodes */ - c = *previous; /* Save previous opcode */ - if (c == OP_PROP || c == OP_NOTPROP) - { - prop_type = previous[1]; - prop_value = previous[2]; - } - else - { - /* Come here from just above with a character in c */ - OUTPUT_SINGLE_REPEAT: - prop_type = prop_value = -1; - } +BAD_VERSION_CONDITION: +errorcode = ERR79; +goto FAILED; +} - /* At this point we either have prop_type == prop_value == -1 and either - a code point or a character type that is not OP_[NOT]PROP in c, or we - have OP_[NOT]PROP in c and prop_type/prop_value not negative. */ - oldcode = code; /* Save where we were */ - code = previous; /* Usually overwrite previous item */ - /* If the maximum is zero then the minimum must also be zero; Perl allows - this case, so we do too - by simply omitting the item altogether. */ +/************************************************* +* Find first significant op code * +*************************************************/ - if (repeat_max == 0) goto END_REPEAT; +/* This is called by several functions that scan a compiled expression looking +for a fixed first character, or an anchoring op code etc. It skips over things +that do not influence this. For some calls, it makes sense to skip negative +forward and all backward assertions, and also the \b assertion; for others it +does not. - /* Combine the op_type with the repeat_type */ +Arguments: + code pointer to the start of the group + skipassert TRUE if certain assertions are to be skipped - repeat_type += op_type; +Returns: pointer to the first significant opcode +*/ - /* A minimum of zero is handled either as the special case * or ?, or as - an UPTO, with the maximum given. */ +static const PCRE2_UCHAR* +first_significant_code(PCRE2_SPTR code, BOOL skipassert) +{ +for (;;) + { + switch ((int)*code) + { + case OP_ASSERT_NOT: + case OP_ASSERTBACK: + case OP_ASSERTBACK_NOT: + if (!skipassert) return code; + do code += GET(code, 1); while (*code == OP_ALT); + code += PRIV(OP_lengths)[*code]; + break; - if (repeat_min == 0) - { - if (repeat_max == -1) *code++ = OP_STAR + repeat_type; - else if (repeat_max == 1) *code++ = OP_QUERY + repeat_type; - else - { - *code++ = OP_UPTO + repeat_type; - PUT2INC(code, 0, repeat_max); - } - } + case OP_WORD_BOUNDARY: + case OP_NOT_WORD_BOUNDARY: + if (!skipassert) return code; + /* Fall through */ - /* A repeat minimum of 1 is optimized into some special cases. If the - maximum is unlimited, we use OP_PLUS. Otherwise, the original item is - left in place and, if the maximum is greater than 1, we use OP_UPTO with - one less than the maximum. */ + case OP_CALLOUT: + case OP_CREF: + case OP_DNCREF: + case OP_RREF: + case OP_DNRREF: + case OP_FALSE: + case OP_TRUE: + code += PRIV(OP_lengths)[*code]; + break; - else if (repeat_min == 1) - { - if (repeat_max == -1) - *code++ = OP_PLUS + repeat_type; - else - { - code = oldcode; /* Leave previous item in place */ - if (repeat_max == 1) goto END_REPEAT; - *code++ = OP_UPTO + repeat_type; - PUT2INC(code, 0, repeat_max - 1); - } - } + case OP_CALLOUT_STR: + code += GET(code, 1 + 2*LINK_SIZE); + break; - /* The case {n,n} is just an EXACT, while the general case {n,m} is - handled as an EXACT followed by an UPTO or STAR or QUERY. */ + default: + return code; + } + } +/* Control never reaches here */ +} - else - { - *code++ = OP_EXACT + op_type; /* NB EXACT doesn't have repeat_type */ - PUT2INC(code, 0, repeat_min); - /* Unless repeat_max equals repeat_min, fill in the data for EXACT, and - then generate the second opcode. In UTF mode, multi-code-unit - characters have their length in c, with the UTF_LENGTH bit as a flag, - and the code units in utf_units. For a repeated Unicode property match, - there are two extra values that define the required property, and c - never has the UTF_LENGTH bit set. */ - if (repeat_max != repeat_min) - { -#ifdef MAYBE_UTF_MULTI - if (utf && (c & UTF_LENGTH) != 0) - { - memcpy(code, utf_units, CU2BYTES(c & 7)); - code += c & 7; - } - else -#endif /* MAYBE_UTF_MULTI */ - { - *code++ = c; - if (prop_type >= 0) - { - *code++ = prop_type; - *code++ = prop_value; - } - } - - /* Now set up the following opcode */ +#ifdef SUPPORT_UNICODE +/************************************************* +* Get othercase range * +*************************************************/ - if (repeat_max < 0) *code++ = OP_STAR + repeat_type; else - { - repeat_max -= repeat_min; - if (repeat_max == 1) - { - *code++ = OP_QUERY + repeat_type; - } - else - { - *code++ = OP_UPTO + repeat_type; - PUT2INC(code, 0, repeat_max); - } - } - } - } +/* This function is passed the start and end of a class range in UCP mode. It +searches up the characters, looking for ranges of characters in the "other" +case. Each call returns the next one, updating the start address. A character +with multiple other cases is returned on its own with a special return value. - /* Fill in the character or character type for the final opcode. */ +Arguments: + cptr points to starting character value; updated + d end value + ocptr where to put start of othercase range + odptr where to put end of othercase range -#ifdef MAYBE_UTF_MULTI - if (utf && (c & UTF_LENGTH) != 0) - { - memcpy(code, utf_units, CU2BYTES(c & 7)); - code += c & 7; - } - else -#endif /* MAYBEW_UTF_MULTI */ - { - *code++ = c; - if (prop_type >= 0) - { - *code++ = prop_type; - *code++ = prop_value; - } - } - } +Yield: -1 when no more + 0 when a range is returned + >0 the CASESET offset for char with multiple other cases + in this case, ocptr contains the original +*/ - /* If previous was a character class or a back reference, we put the repeat - stuff after it, but just skip the item if the repeat was {0,0}. */ +static int +get_othercase_range(uint32_t *cptr, uint32_t d, uint32_t *ocptr, + uint32_t *odptr) +{ +uint32_t c, othercase, next; +unsigned int co; - else if (*previous == OP_CLASS || *previous == OP_NCLASS || -#ifdef SUPPORT_WIDE_CHARS - *previous == OP_XCLASS || -#endif - *previous == OP_REF || *previous == OP_REFI || - *previous == OP_DNREF || *previous == OP_DNREFI) - { - if (repeat_max == 0) - { - code = previous; - goto END_REPEAT; - } +/* Find the first character that has an other case. If it has multiple other +cases, return its case offset value. */ - if (repeat_min == 0 && repeat_max == -1) - *code++ = OP_CRSTAR + repeat_type; - else if (repeat_min == 1 && repeat_max == -1) - *code++ = OP_CRPLUS + repeat_type; - else if (repeat_min == 0 && repeat_max == 1) - *code++ = OP_CRQUERY + repeat_type; - else - { - *code++ = OP_CRRANGE + repeat_type; - PUT2INC(code, 0, repeat_min); - if (repeat_max == -1) repeat_max = 0; /* 2-byte encoding for max */ - PUT2INC(code, 0, repeat_max); - } - } +for (c = *cptr; c <= d; c++) + { + if ((co = UCD_CASESET(c)) != 0) + { + *ocptr = c++; /* Character that has the set */ + *cptr = c; /* Rest of input range */ + return (int)co; + } + if ((othercase = UCD_OTHERCASE(c)) != c) break; + } - /* If previous was a bracket group, we may have to replicate it in certain - cases. Note that at this point we can encounter only the "basic" bracket - opcodes such as BRA and CBRA, as this is the place where they get converted - into the more special varieties such as BRAPOS and SBRA. A test for >= - OP_ASSERT and <= OP_COND includes ASSERT, ASSERT_NOT, ASSERTBACK, - ASSERTBACK_NOT, ONCE, ONCE_NC, BRA, BRAPOS, CBRA, CBRAPOS, and COND. - Originally, PCRE did not allow repetition of assertions, but now it does, - for Perl compatibility. */ +if (c > d) return -1; /* Reached end of range */ - else if (*previous >= OP_ASSERT && *previous <= OP_COND) - { - register int i; - int len = (int)(code - previous); - PCRE2_UCHAR *bralink = NULL; - PCRE2_UCHAR *brazeroptr = NULL; +/* Found a character that has a single other case. Search for the end of the +range, which is either the end of the input range, or a character that has zero +or more than one other cases. */ - /* Repeating a DEFINE group (or any group where the condition is always - FALSE and there is only one branch) is pointless, but Perl allows the - syntax, so we just ignore the repeat. */ +*ocptr = othercase; +next = othercase + 1; - if (*previous == OP_COND && previous[LINK_SIZE+1] == OP_FALSE && - previous[GET(previous, 1)] != OP_ALT) - goto END_REPEAT; +for (++c; c <= d; c++) + { + if ((co = UCD_CASESET(c)) != 0 || UCD_OTHERCASE(c) != next) break; + next++; + } - /* There is no sense in actually repeating assertions. The only potential - use of repetition is in cases when the assertion is optional. Therefore, - if the minimum is greater than zero, just ignore the repeat. If the - maximum is not zero or one, set it to 1. */ +*odptr = next - 1; /* End of othercase range */ +*cptr = c; /* Rest of input range */ +return 0; +} +#endif /* SUPPORT_UNICODE */ - if (*previous < OP_ONCE) /* Assertion */ - { - if (repeat_min > 0) goto END_REPEAT; - if (repeat_max < 0 || repeat_max > 1) repeat_max = 1; - } - /* The case of a zero minimum is special because of the need to stick - OP_BRAZERO in front of it, and because the group appears once in the - data, whereas in other cases it appears the minimum number of times. For - this reason, it is simplest to treat this case separately, as otherwise - the code gets far too messy. There are several special subcases when the - minimum is zero. */ - if (repeat_min == 0) - { - /* If the maximum is also zero, we used to just omit the group from the - output altogether, like this: +/************************************************* +* Add a character or range to a class (internal) * +*************************************************/ - ** if (repeat_max == 0) - ** { - ** code = previous; - ** goto END_REPEAT; - ** } +/* This function packages up the logic of adding a character or range of +characters to a class. The character values in the arguments will be within the +valid values for the current mode (8-bit, 16-bit, UTF, etc). This function is +called only from within the "add to class" group of functions, some of which +are recursive and mutually recursive. The external entry point is +add_to_class(). - However, that fails when a group or a subgroup within it is referenced - as a subroutine from elsewhere in the pattern, so now we stick in - OP_SKIPZERO in front of it so that it is skipped on execution. As we - don't have a list of which groups are referenced, we cannot do this - selectively. +Arguments: + classbits the bit map for characters < 256 + uchardptr points to the pointer for extra data + options the options word + cb compile data + start start of range character + end end of range character - If the maximum is 1 or unlimited, we just have to stick in the BRAZERO - and do no more at this point. */ +Returns: the number of < 256 characters added + the pointer to extra data is updated +*/ - if (repeat_max <= 1) /* Covers 0, 1, and unlimited */ - { - memmove(previous + 1, previous, CU2BYTES(len)); - code++; - if (repeat_max == 0) - { - *previous++ = OP_SKIPZERO; - goto END_REPEAT; - } - brazeroptr = previous; /* Save for possessive optimizing */ - *previous++ = OP_BRAZERO + repeat_type; - } +static unsigned int +add_to_class_internal(uint8_t *classbits, PCRE2_UCHAR **uchardptr, + uint32_t options, compile_block *cb, uint32_t start, uint32_t end) +{ +uint32_t c; +uint32_t classbits_end = (end <= 0xff ? end : 0xff); +unsigned int n8 = 0; - /* If the maximum is greater than 1 and limited, we have to replicate - in a nested fashion, sticking OP_BRAZERO before each set of brackets. - The first one has to be handled carefully because it's the original - copy, which has to be moved up. The remainder can be handled by code - that is common with the non-zero minimum case below. We have to - adjust the value or repeat_max, since one less copy is required. */ +/* If caseless matching is required, scan the range and process alternate +cases. In Unicode, there are 8-bit characters that have alternate cases that +are greater than 255 and vice-versa. Sometimes we can just extend the original +range. */ - else - { - int offset; - memmove(previous + 2 + LINK_SIZE, previous, CU2BYTES(len)); - code += 2 + LINK_SIZE; - *previous++ = OP_BRAZERO + repeat_type; - *previous++ = OP_BRA; - - /* We chain together the bracket offset fields that have to be - filled in later when the ends of the brackets are reached. */ - - offset = (bralink == NULL)? 0 : (int)(previous - bralink); - bralink = previous; - PUTINC(previous, 0, offset); - } +if ((options & PCRE2_CASELESS) != 0) + { +#ifdef SUPPORT_UNICODE + if ((options & PCRE2_UTF) != 0) + { + int rc; + uint32_t oc, od; - repeat_max--; - } + options &= ~PCRE2_CASELESS; /* Remove for recursive calls */ + c = start; - /* If the minimum is greater than zero, replicate the group as many - times as necessary, and adjust the maximum to the number of subsequent - copies that we need. */ + while ((rc = get_othercase_range(&c, end, &oc, &od)) >= 0) + { + /* Handle a single character that has more than one other case. */ - else - { - if (repeat_min > 1) - { - /* In the pre-compile phase, we don't actually do the replication. We - just adjust the length as if we had. Do some paranoid checks for - potential integer overflow. The INT64_OR_DOUBLE type is a 64-bit - integer type when available, otherwise double. */ + if (rc > 0) n8 += add_list_to_class_internal(classbits, uchardptr, options, cb, + PRIV(ucd_caseless_sets) + rc, oc); - if (lengthptr != NULL) - { - size_t delta = (repeat_min - 1)*length_prevgroup; - if ((INT64_OR_DOUBLE)(repeat_min - 1)* - (INT64_OR_DOUBLE)length_prevgroup > - (INT64_OR_DOUBLE)INT_MAX || - OFLOW_MAX - *lengthptr < delta) - { - *errorcodeptr = ERR20; - goto FAILED; - } - *lengthptr += delta; - } + /* Do nothing if the other case range is within the original range. */ - /* This is compiling for real. If there is a set first byte for - the group, and we have not yet set a "required byte", set it. */ + else if (oc >= cb->class_range_start && od <= cb->class_range_end) continue; - else - { - if (groupsetfirstcu && reqcuflags < 0) - { - reqcu = firstcu; - reqcuflags = firstcuflags; - } - for (i = 1; i < repeat_min; i++) - { - memcpy(code, previous, CU2BYTES(len)); - code += len; - } - } - } + /* Extend the original range if there is overlap, noting that if oc < c, we + can't have od > end because a subrange is always shorter than the basic + range. Otherwise, use a recursive call to add the additional range. */ - if (repeat_max > 0) repeat_max -= repeat_min; + else if (oc < start && od >= start - 1) start = oc; /* Extend downwards */ + else if (od > end && oc <= end + 1) + { + end = od; /* Extend upwards */ + if (end > classbits_end) classbits_end = (end <= 0xff ? end : 0xff); } + else n8 += add_to_class_internal(classbits, uchardptr, options, cb, oc, od); + } + } + else +#endif /* SUPPORT_UNICODE */ - /* This code is common to both the zero and non-zero minimum cases. If - the maximum is limited, it replicates the group in a nested fashion, - remembering the bracket starts on a stack. In the case of a zero minimum, - the first one was set up above. In all cases the repeat_max now specifies - the number of additional copies needed. Again, we must remember to - replicate entries on the forward reference list. */ + /* Not UTF mode */ - if (repeat_max >= 0) - { - /* In the pre-compile phase, we don't actually do the replication. We - just adjust the length as if we had. For each repetition we must add 1 - to the length for BRAZERO and for all but the last repetition we must - add 2 + 2*LINKSIZE to allow for the nesting that occurs. Do some - paranoid checks to avoid integer overflow. The INT64_OR_DOUBLE type is - a 64-bit integer type when available, otherwise double. */ - - if (lengthptr != NULL && repeat_max > 0) - { - size_t delta = repeat_max*(length_prevgroup + 1 + 2 + 2*LINK_SIZE) - - 2 - 2*LINK_SIZE; /* Last one doesn't nest */ - if ((INT64_OR_DOUBLE)repeat_max * - (INT64_OR_DOUBLE)(length_prevgroup + 1 + 2 + 2*LINK_SIZE) - > (INT64_OR_DOUBLE)INT_MAX || - OFLOW_MAX - *lengthptr < delta) - { - *errorcodeptr = ERR20; - goto FAILED; - } - *lengthptr += delta; - } + for (c = start; c <= classbits_end; c++) + { + SETBIT(classbits, cb->fcc[c]); + n8++; + } + } - /* This is compiling for real */ +/* Now handle the originally supplied range. Adjust the final value according +to the bit length - this means that the same lists of (e.g.) horizontal spaces +can be used in all cases. */ - else for (i = repeat_max - 1; i >= 0; i--) - { - *code++ = OP_BRAZERO + repeat_type; +if ((options & PCRE2_UTF) == 0 && end > MAX_NON_UTF_CHAR) + end = MAX_NON_UTF_CHAR; - /* All but the final copy start a new nesting, maintaining the - chain of brackets outstanding. */ +if (start > cb->class_range_start && end < cb->class_range_end) return n8; - if (i != 0) - { - int offset; - *code++ = OP_BRA; - offset = (bralink == NULL)? 0 : (int)(code - bralink); - bralink = code; - PUTINC(code, 0, offset); - } +/* Use the bitmap for characters < 256. Otherwise use extra data.*/ - memcpy(code, previous, CU2BYTES(len)); - code += len; - } +for (c = start; c <= classbits_end; c++) + { + /* Regardless of start, c will always be <= 255. */ + SETBIT(classbits, c); + n8++; + } - /* Now chain through the pending brackets, and fill in their length - fields (which are holding the chain links pro tem). */ +#ifdef SUPPORT_WIDE_CHARS +if (start <= 0xff) start = 0xff + 1; - while (bralink != NULL) - { - int oldlinkoffset; - int offset = (int)(code - bralink + 1); - PCRE2_UCHAR *bra = code - offset; - oldlinkoffset = GET(bra, 1); - bralink = (oldlinkoffset == 0)? NULL : bralink - oldlinkoffset; - *code++ = OP_KET; - PUTINC(code, 0, offset); - PUT(bra, 1, offset); - } - } +if (end >= start) + { + PCRE2_UCHAR *uchardata = *uchardptr; - /* If the maximum is unlimited, set a repeater in the final copy. For - ONCE brackets, that's all we need to do. However, possessively repeated - ONCE brackets can be converted into non-capturing brackets, as the - behaviour of (?:xx)++ is the same as (?>xx)++ and this saves having to - deal with possessive ONCEs specially. - - Otherwise, when we are doing the actual compile phase, check to see - whether this group is one that could match an empty string. If so, - convert the initial operator to the S form (e.g. OP_BRA -> OP_SBRA) so - that runtime checking can be done. [This check is also applied to ONCE - groups at runtime, but in a different way.] - - Then, if the quantifier was possessive and the bracket is not a - conditional, we convert the BRA code to the POS form, and the KET code to - KETRPOS. (It turns out to be convenient at runtime to detect this kind of - subpattern at both the start and at the end.) The use of special opcodes - makes it possible to reduce greatly the stack usage in pcre2_match(). If - the group is preceded by OP_BRAZERO, convert this to OP_BRAPOSZERO. - - Then, if the minimum number of matches is 1 or 0, cancel the possessive - flag so that the default action below, of wrapping everything inside - atomic brackets, does not happen. When the minimum is greater than 1, - there will be earlier copies of the group, and so we still have to wrap - the whole thing. */ +#ifdef SUPPORT_UNICODE + if ((options & PCRE2_UTF) != 0) + { + if (start < end) + { + *uchardata++ = XCL_RANGE; + uchardata += PRIV(ord2utf)(start, uchardata); + uchardata += PRIV(ord2utf)(end, uchardata); + } + else if (start == end) + { + *uchardata++ = XCL_SINGLE; + uchardata += PRIV(ord2utf)(start, uchardata); + } + } + else +#endif /* SUPPORT_UNICODE */ - else - { - PCRE2_UCHAR *ketcode = code - 1 - LINK_SIZE; - PCRE2_UCHAR *bracode = ketcode - GET(ketcode, 1); + /* Without UTF support, character values are constrained by the bit length, + and can only be > 256 for 16-bit and 32-bit libraries. */ - /* Convert possessive ONCE brackets to non-capturing */ +#if PCRE2_CODE_UNIT_WIDTH == 8 + {} +#else + if (start < end) + { + *uchardata++ = XCL_RANGE; + *uchardata++ = start; + *uchardata++ = end; + } + else if (start == end) + { + *uchardata++ = XCL_SINGLE; + *uchardata++ = start; + } +#endif /* PCRE2_CODE_UNIT_WIDTH == 8 */ + *uchardptr = uchardata; /* Updata extra data pointer */ + } +#else /* SUPPORT_WIDE_CHARS */ + (void)uchardptr; /* Avoid compiler warning */ +#endif /* SUPPORT_WIDE_CHARS */ - if ((*bracode == OP_ONCE || *bracode == OP_ONCE_NC) && - possessive_quantifier) *bracode = OP_BRA; +return n8; /* Number of 8-bit characters */ +} - /* For non-possessive ONCE brackets, all we need to do is to - set the KET. */ - if (*bracode == OP_ONCE || *bracode == OP_ONCE_NC) - *ketcode = OP_KETRMAX + repeat_type; - /* Handle non-ONCE brackets and possessive ONCEs (which have been - converted to non-capturing above). */ +#ifdef SUPPORT_UNICODE +/************************************************* +* Add a list of characters to a class (internal) * +*************************************************/ - else - { - /* In the compile phase, check whether the group could match an empty - string. */ +/* This function is used for adding a list of case-equivalent characters to a +class when in UTF mode. This function is called only from within +add_to_class_internal(), with which it is mutually recursive. - if (lengthptr == NULL) - { - PCRE2_UCHAR *scode = bracode; - do - { - int count = 0; - int rc = could_be_empty_branch(scode, ketcode, utf, cb, FALSE, - NULL, &count); - if (rc < 0) - { - *errorcodeptr = ERR86; - goto FAILED; - } - if (rc > 0) - { - *bracode += OP_SBRA - OP_BRA; - break; - } - scode += GET(scode, 1); - } - while (*scode == OP_ALT); +Arguments: + classbits the bit map for characters < 256 + uchardptr points to the pointer for extra data + options the options word + cb contains pointers to tables etc. + p points to row of 32-bit values, terminated by NOTACHAR + except character to omit; this is used when adding lists of + case-equivalent characters to avoid including the one we + already know about - /* A conditional group with only one branch has an implicit empty - alternative branch. */ +Returns: the number of < 256 characters added + the pointer to extra data is updated +*/ - if (*bracode == OP_COND && bracode[GET(bracode,1)] != OP_ALT) - *bracode = OP_SCOND; - } +static unsigned int +add_list_to_class_internal(uint8_t *classbits, PCRE2_UCHAR **uchardptr, + uint32_t options, compile_block *cb, const uint32_t *p, unsigned int except) +{ +unsigned int n8 = 0; +while (p[0] < NOTACHAR) + { + unsigned int n = 0; + if (p[0] != except) + { + while(p[n+1] == p[0] + n + 1) n++; + n8 += add_to_class_internal(classbits, uchardptr, options, cb, p[0], p[n]); + } + p += n + 1; + } +return n8; +} +#endif - /* Handle possessive quantifiers. */ - if (possessive_quantifier) - { - /* For COND brackets, we wrap the whole thing in a possessively - repeated non-capturing bracket, because we have not invented POS - versions of the COND opcodes. */ - if (*bracode == OP_COND || *bracode == OP_SCOND) - { - int nlen = (int)(code - bracode); - memmove(bracode + 1 + LINK_SIZE, bracode, CU2BYTES(nlen)); - code += 1 + LINK_SIZE; - nlen += 1 + LINK_SIZE; - *bracode = (*bracode == OP_COND)? OP_BRAPOS : OP_SBRAPOS; - *code++ = OP_KETRPOS; - PUTINC(code, 0, nlen); - PUT(bracode, 1, nlen); - } +/************************************************* +* External entry point for add range to class * +*************************************************/ - /* For non-COND brackets, we modify the BRA code and use KETRPOS. */ +/* This function sets the overall range so that the internal functions can try +to avoid duplication when handling case-independence. - else - { - *bracode += 1; /* Switch to xxxPOS opcodes */ - *ketcode = OP_KETRPOS; - } +Arguments: + classbits the bit map for characters < 256 + uchardptr points to the pointer for extra data + options the options word + cb compile data + start start of range character + end end of range character - /* If the minimum is zero, mark it as possessive, then unset the - possessive flag when the minimum is 0 or 1. */ +Returns: the number of < 256 characters added + the pointer to extra data is updated +*/ - if (brazeroptr != NULL) *brazeroptr = OP_BRAPOSZERO; - if (repeat_min < 2) possessive_quantifier = FALSE; - } +static unsigned int +add_to_class(uint8_t *classbits, PCRE2_UCHAR **uchardptr, uint32_t options, + compile_block *cb, uint32_t start, uint32_t end) +{ +cb->class_range_start = start; +cb->class_range_end = end; +return add_to_class_internal(classbits, uchardptr, options, cb, start, end); +} - /* Non-possessive quantifier */ - else *ketcode = OP_KETRMAX + repeat_type; - } - } - } +/************************************************* +* External entry point for add list to class * +*************************************************/ - /* If previous is OP_FAIL, it was generated by an empty class [] - (PCRE2_ALLOW_EMPTY_CLASS is set). The other ways in which OP_FAIL can be - generated, that is by (*FAIL) or (?!), set previous to NULL, which gives a - "nothing to repeat" error above. We can just ignore the repeat in empty - class case. */ +/* This function is used for adding a list of horizontal or vertical whitespace +characters to a class. The list must be in order so that ranges of characters +can be detected and handled appropriately. This function sets the overall range +so that the internal functions can try to avoid duplication when handling +case-independence. - else if (*previous == OP_FAIL) goto END_REPEAT; +Arguments: + classbits the bit map for characters < 256 + uchardptr points to the pointer for extra data + options the options word + cb contains pointers to tables etc. + p points to row of 32-bit values, terminated by NOTACHAR + except character to omit; this is used when adding lists of + case-equivalent characters to avoid including the one we + already know about - /* Else there's some kind of shambles */ +Returns: the number of < 256 characters added + the pointer to extra data is updated +*/ - else - { - *errorcodeptr = ERR10; - goto FAILED; - } +static unsigned int +add_list_to_class(uint8_t *classbits, PCRE2_UCHAR **uchardptr, uint32_t options, + compile_block *cb, const uint32_t *p, unsigned int except) +{ +unsigned int n8 = 0; +while (p[0] < NOTACHAR) + { + unsigned int n = 0; + if (p[0] != except) + { + while(p[n+1] == p[0] + n + 1) n++; + cb->class_range_start = p[0]; + cb->class_range_end = p[n]; + n8 += add_to_class_internal(classbits, uchardptr, options, cb, p[0], p[n]); + } + p += n + 1; + } +return n8; +} - /* If the character following a repeat is '+', possessive_quantifier is - TRUE. For some opcodes, there are special alternative opcodes for this - case. For anything else, we wrap the entire repeated item inside OP_ONCE - brackets. Logically, the '+' notation is just syntactic sugar, taken from - Sun's Java package, but the special opcodes can optimize it. - Some (but not all) possessively repeated subpatterns have already been - completely handled in the code just above. For them, possessive_quantifier - is always FALSE at this stage. Note that the repeated item starts at - tempcode, not at previous, which might be the first part of a string whose - (former) last char we repeated. */ - if (possessive_quantifier) - { - int len; +/************************************************* +* Add characters not in a list to a class * +*************************************************/ - /* Possessifying an EXACT quantifier has no effect, so we can ignore it. - However, QUERY, STAR, or UPTO may follow (for quantifiers such as {5,6}, - {5,}, or {5,10}). We skip over an EXACT item; if the length of what - remains is greater than zero, there's a further opcode that can be - handled. If not, do nothing, leaving the EXACT alone. */ +/* This function is used for adding the complement of a list of horizontal or +vertical whitespace to a class. The list must be in order. - switch(*tempcode) - { - case OP_TYPEEXACT: - tempcode += PRIV(OP_lengths)[*tempcode] + - ((tempcode[1 + IMM2_SIZE] == OP_PROP - || tempcode[1 + IMM2_SIZE] == OP_NOTPROP)? 2 : 0); - break; +Arguments: + classbits the bit map for characters < 256 + uchardptr points to the pointer for extra data + options the options word + cb contains pointers to tables etc. + p points to row of 32-bit values, terminated by NOTACHAR - /* CHAR opcodes are used for exacts whose count is 1. */ +Returns: the number of < 256 characters added + the pointer to extra data is updated +*/ - case OP_CHAR: - case OP_CHARI: - case OP_NOT: - case OP_NOTI: - case OP_EXACT: - case OP_EXACTI: - case OP_NOTEXACT: - case OP_NOTEXACTI: - tempcode += PRIV(OP_lengths)[*tempcode]; -#ifdef SUPPORT_UNICODE - if (utf && HAS_EXTRALEN(tempcode[-1])) - tempcode += GET_EXTRALEN(tempcode[-1]); -#endif - break; +static unsigned int +add_not_list_to_class(uint8_t *classbits, PCRE2_UCHAR **uchardptr, + uint32_t options, compile_block *cb, const uint32_t *p) +{ +BOOL utf = (options & PCRE2_UTF) != 0; +unsigned int n8 = 0; +if (p[0] > 0) + n8 += add_to_class(classbits, uchardptr, options, cb, 0, p[0] - 1); +while (p[0] < NOTACHAR) + { + while (p[1] == p[0] + 1) p++; + n8 += add_to_class(classbits, uchardptr, options, cb, p[0] + 1, + (p[1] == NOTACHAR) ? (utf ? 0x10ffffu : 0xffffffffu) : p[1] - 1); + p++; + } +return n8; +} - /* For the class opcodes, the repeat operator appears at the end; - adjust tempcode to point to it. */ - case OP_CLASS: - case OP_NCLASS: - tempcode += 1 + 32/sizeof(PCRE2_UCHAR); - break; -#ifdef SUPPORT_WIDE_CHARS - case OP_XCLASS: - tempcode += GET(tempcode, 1); - break; -#endif - } +/************************************************* +* Find details of duplicate group names * +*************************************************/ - /* If tempcode is equal to code (which points to the end of the repeated - item), it means we have skipped an EXACT item but there is no following - QUERY, STAR, or UPTO; the value of len will be 0, and we do nothing. In - all other cases, tempcode will be pointing to the repeat opcode, and will - be less than code, so the value of len will be greater than 0. */ +/* This is called from compile_branch() when it needs to know the index and +count of duplicates in the names table when processing named backreferences, +either directly, or as conditions. - len = (int)(code - tempcode); - if (len > 0) - { - unsigned int repcode = *tempcode; +Arguments: + name points to the name + length the length of the name + indexptr where to put the index + countptr where to put the count of duplicates + errorcodeptr where to put an error code + cb the compile block + +Returns: TRUE if OK, FALSE if not, error code set +*/ - /* There is a table for possessifying opcodes, all of which are less - than OP_CALLOUT. A zero entry means there is no possessified version. - */ +static BOOL +find_dupname_details(PCRE2_SPTR name, uint32_t length, int *indexptr, + int *countptr, int *errorcodeptr, compile_block *cb) +{ +uint32_t i, groupnumber; +int count; +PCRE2_UCHAR *slot = cb->name_table; - if (repcode < OP_CALLOUT && opcode_possessify[repcode] > 0) - *tempcode = opcode_possessify[repcode]; +/* Find the first entry in the table */ - /* For opcode without a special possessified version, wrap the item in - ONCE brackets. */ +for (i = 0; i < cb->names_found; i++) + { + if (PRIV(strncmp)(name, slot+IMM2_SIZE, length) == 0 && + slot[IMM2_SIZE+length] == 0) break; + slot += cb->name_entry_size; + } - else - { - memmove(tempcode + 1 + LINK_SIZE, tempcode, CU2BYTES(len)); - code += 1 + LINK_SIZE; - len += 1 + LINK_SIZE; - tempcode[0] = OP_ONCE; - *code++ = OP_KET; - PUTINC(code, 0, len); - PUT(tempcode, 1, len); - } - } - } +/* This should not occur, because this function is called only when we know we +have duplicate names. Give an internal error. */ - /* In all case we no longer have a previous item. We also set the - "follows varying string" flag for subsequently encountered reqcus if - it isn't already set and we have just passed a varying length item. */ +if (i >= cb->names_found) + { + *errorcodeptr = ERR53; + cb->erroroffset = name - cb->start_pattern; + return FALSE; + } - END_REPEAT: - previous = NULL; - cb->req_varyopt |= reqvary; - break; +/* Record the index and then see how many duplicates there are, updating the +backref map and maximum back reference as we do. */ +*indexptr = i; +count = 0; - /* ===================================================================*/ - /* Start of nested parenthesized sub-expression, or lookahead or lookbehind - or option setting or condition or all the other extended parenthesis forms. - We must save the current high-water-mark for the forward reference list so - that we know where they start for this group. However, because the list may - be extended when there are very many forward references (usually the result - of a replicated inner group), we must use an offset rather than an absolute - address. Note that (?# comments are dealt with at the top of the loop; - they do not get this far. */ +for (;;) + { + count++; + groupnumber = GET2(slot,0); + cb->backref_map |= (groupnumber < 32)? (1u << groupnumber) : 1; + if (groupnumber > cb->top_backref) cb->top_backref = groupnumber; + if (++i >= cb->names_found) break; + slot += cb->name_entry_size; + if (PRIV(strncmp)(name, slot+IMM2_SIZE, length) != 0 || + (slot+IMM2_SIZE)[length] != 0) break; + } - case CHAR_LEFT_PARENTHESIS: - ptr++; +*countptr = count; +return TRUE; +} - /* Deal with various "verbs" that can be introduced by '*'. */ - if (ptr[0] == CHAR_ASTERISK && (ptr[1] == ':' - || (MAX_255(ptr[1]) && ((cb->ctypes[ptr[1]] & ctype_letter) != 0)))) - { - int i, namelen; - int arglen = 0; - const char *vn = verbnames; - PCRE2_SPTR name = ptr + 1; - PCRE2_SPTR arg = NULL; - previous = NULL; - ptr++; - /* Increment ptr, set namelen, check length */ +/************************************************* +* Compile one branch * +*************************************************/ - READ_NAME(ctype_letter, ERR60, *errorcodeptr); +/* Scan the parsed pattern, compiling it into the a vector of PCRE2_UCHAR. If +the options are changed during the branch, the pointer is used to change the +external options bits. This function is used during the pre-compile phase when +we are trying to find out the amount of memory needed, as well as during the +real compile phase. The value of lengthptr distinguishes the two phases. - /* It appears that Perl allows any characters whatsoever, other than - a closing parenthesis, to appear in arguments, so we no longer insist on - letters, digits, and underscores. Perl does not, however, do any - interpretation within arguments, and has no means of including a closing - parenthesis. PCRE supports escape processing but only when it is - requested by an option. Note that check_escape() will not return values - greater than the code unit maximum when not in UTF mode. */ +Arguments: + optionsptr pointer to the option bits + codeptr points to the pointer to the current code point + pptrptr points to the current parsed pattern pointer + errorcodeptr points to error code variable + firstcuptr place to put the first required code unit + firstcuflagsptr place to put the first code unit flags, or a negative number + reqcuptr place to put the last required code unit + reqcuflagsptr place to put the last required code unit flags, or a negative number + bcptr points to current branch chain + cb contains pointers to tables etc. + lengthptr NULL during the real compile phase + points to length accumulator during pre-compile phase - if (*ptr == CHAR_COLON) - { - arg = ++ptr; +Returns: 0 There's been an error, *errorcodeptr is non-zero + +1 Success, this branch must match at least one character + -1 Success, this branch may match an empty string +*/ - if ((options & PCRE2_ALT_VERBNAMES) == 0) - { - arglen = 0; - while (ptr < cb->end_pattern && *ptr != CHAR_RIGHT_PARENTHESIS) - { - ptr++; /* Check length as we go */ - arglen++; /* along, to avoid the */ - if ((unsigned int)arglen > MAX_MARK) /* possibility of overflow. */ - { - *errorcodeptr = ERR76; - goto FAILED; - } - } - } - else - { - /* The length check is in process_verb_names() */ - arglen = process_verb_name(&ptr, NULL, errorcodeptr, options, - utf, cb); - if (arglen < 0) goto FAILED; - } - } - - if (*ptr != CHAR_RIGHT_PARENTHESIS) - { - *errorcodeptr = ERR60; - goto FAILED; - } - - /* Scan the table of verb names */ +static int +compile_branch(uint32_t *optionsptr, PCRE2_UCHAR **codeptr, uint32_t **pptrptr, + int *errorcodeptr, uint32_t *firstcuptr, int32_t *firstcuflagsptr, + uint32_t *reqcuptr, int32_t *reqcuflagsptr, branch_chain *bcptr, + compile_block *cb, PCRE2_SIZE *lengthptr) +{ +int bravalue = 0; +int okreturn = -1; +int group_return = 0; +uint32_t repeat_min = 0, repeat_max = 0; /* To please picky compilers */ +uint32_t greedy_default, greedy_non_default; +uint32_t repeat_type, op_type; +uint32_t options = *optionsptr; /* May change dynamically */ +uint32_t firstcu, reqcu; +uint32_t zeroreqcu, zerofirstcu; +uint32_t escape; +uint32_t *pptr = *pptrptr; +uint32_t meta, meta_arg; +int32_t firstcuflags, reqcuflags; +int32_t zeroreqcuflags, zerofirstcuflags; +int32_t req_caseopt, reqvary, tempreqvary; +PCRE2_SIZE offset = 0; +PCRE2_SIZE length_prevgroup = 0; +PCRE2_UCHAR *code = *codeptr; +PCRE2_UCHAR *last_code = code; +PCRE2_UCHAR *orig_code = code; +PCRE2_UCHAR *tempcode; +PCRE2_UCHAR *previous = NULL; +PCRE2_UCHAR op_previous; +BOOL groupsetfirstcu = FALSE; +BOOL matched_char = FALSE; +BOOL previous_matched_char = FALSE; +const uint8_t *cbits = cb->cbits; +uint8_t classbits[32]; - for (i = 0; i < verbcount; i++) - { - if (namelen == verbs[i].len && - PRIV(strncmp_c8)(name, vn, namelen) == 0) - { - int setverb; +/* We can fish out the UTF setting once and for all into a BOOL, but we must +not do this for other options (e.g. PCRE2_EXTENDED) because they may change +dynamically as we process the pattern. */ - /* Check for open captures before ACCEPT and convert it to - ASSERT_ACCEPT if in an assertion. */ +#ifdef SUPPORT_UNICODE +BOOL utf = (options & PCRE2_UTF) != 0; +#else /* No UTF support */ +BOOL utf = FALSE; +#endif - if (verbs[i].op == OP_ACCEPT) - { - open_capitem *oc; - if (arglen != 0) - { - *errorcodeptr = ERR59; - goto FAILED; - } - cb->had_accept = TRUE; +/* Helper variables for OP_XCLASS opcode (for characters > 255). We define +class_uchardata always so that it can be passed to add_to_class() always, +though it will not be used in non-UTF 8-bit cases. This avoids having to supply +alternative calls for the different cases. */ - /* In the first pass, just accumulate the length required; - otherwise hitting (*ACCEPT) inside many nested parentheses can - cause workspace overflow. */ +PCRE2_UCHAR *class_uchardata; +#ifdef SUPPORT_WIDE_CHARS +BOOL xclass; +PCRE2_UCHAR *class_uchardata_base; +#endif - for (oc = cb->open_caps; oc != NULL; oc = oc->next) - { - if (lengthptr != NULL) - { - *lengthptr += CU2BYTES(1) + IMM2_SIZE; - } - else - { - *code++ = OP_CLOSE; - PUT2INC(code, 0, oc->number); - } - } - setverb = *code++ = - (cb->assert_depth > 0)? OP_ASSERT_ACCEPT : OP_ACCEPT; +/* Set up the default and non-default settings for greediness */ - /* Do not set firstcu after *ACCEPT */ - if (firstcuflags == REQ_UNSET) firstcuflags = REQ_NONE; - } +greedy_default = ((options & PCRE2_UNGREEDY) != 0); +greedy_non_default = greedy_default ^ 1; - /* Handle other cases with/without an argument */ +/* Initialize no first unit, no required unit. REQ_UNSET means "no char +matching encountered yet". It gets changed to REQ_NONE if we hit something that +matches a non-fixed first unit; reqcu just remains unset if we never find one. - else if (arglen == 0) /* There is no argument */ - { - if (verbs[i].op < 0) /* Argument is mandatory */ - { - *errorcodeptr = ERR66; - goto FAILED; - } - setverb = *code++ = verbs[i].op; - } +When we hit a repeat whose minimum is zero, we may have to adjust these values +to take the zero repeat into account. This is implemented by setting them to +zerofirstcu and zeroreqcu when such a repeat is encountered. The individual +item types that can be repeated set these backoff variables appropriately. */ - else /* An argument is present */ - { - if (verbs[i].op_arg < 0) /* Argument is forbidden */ - { - *errorcodeptr = ERR59; - goto FAILED; - } - setverb = *code++ = verbs[i].op_arg; +firstcu = reqcu = zerofirstcu = zeroreqcu = 0; +firstcuflags = reqcuflags = zerofirstcuflags = zeroreqcuflags = REQ_UNSET; - /* Arguments can be very long, especially in 16- and 32-bit modes, - and can overflow the workspace in the first pass. Instead of - putting the argument into memory, we just update the length counter - and set up an empty argument. */ +/* The variable req_caseopt contains either the REQ_CASELESS value or zero, +according to the current setting of the caseless flag. The REQ_CASELESS value +leaves the lower 28 bit empty. It is added into the firstcu or reqcu variables +to record the case status of the value. This is used only for ASCII characters. +*/ - if (lengthptr != NULL) - { - *lengthptr += arglen; - *code++ = 0; - } - else - { - *code++ = arglen; - if ((options & PCRE2_ALT_VERBNAMES) != 0) - { - PCRE2_UCHAR *memcode = code; /* code is "register" */ - (void)process_verb_name(&arg, &memcode, errorcodeptr, options, - utf, cb); - code = memcode; - } - else /* No argument processing */ - { - memcpy(code, arg, CU2BYTES(arglen)); - code += arglen; - } - } +req_caseopt = ((options & PCRE2_CASELESS) != 0)? REQ_CASELESS:0; - *code++ = 0; - } +/* Switch on next META item until the end of the branch */ - switch (setverb) - { - case OP_THEN: - case OP_THEN_ARG: - cb->external_flags |= PCRE2_HASTHEN; - break; +for (;; pptr++) + { +#ifdef SUPPORT_WIDE_CHARS + BOOL xclass_has_prop; +#endif + BOOL negate_class; + BOOL should_flip_negation; + BOOL match_all_or_no_wide_chars; + BOOL possessive_quantifier; + BOOL note_group_empty; + int class_has_8bitchar; + int i; + uint32_t mclength; + uint32_t templastcapture; + uint32_t skipunits; + uint32_t subreqcu, subfirstcu; + uint32_t groupnumber; + uint32_t verbarglen, verbculen; + int32_t subreqcuflags, subfirstcuflags; /* Must be signed */ + open_capitem *oc; + PCRE2_UCHAR mcbuffer[8]; - case OP_PRUNE: - case OP_PRUNE_ARG: - case OP_SKIP: - case OP_SKIP_ARG: - cb->had_pruneorskip = TRUE; - break; - } + /* Get next META item in the pattern and its potential argument. */ - break; /* Found verb, exit loop */ - } + meta = META_CODE(*pptr); + meta_arg = META_DATA(*pptr); - vn += verbs[i].len + 1; - } + /* If we are in the pre-compile phase, accumulate the length used for the + previous cycle of this loop, unless the next item is a quantifier. */ - if (i < verbcount) continue; /* Successfully handled a verb */ - *errorcodeptr = ERR60; /* Verb not recognized */ - goto FAILED; + if (lengthptr != NULL) + { + if (code > cb->start_workspace + cb->workspace_size - + WORK_SIZE_SAFETY_MARGIN) /* Check for overrun */ + { + *errorcodeptr = (code >= cb->start_workspace + cb->workspace_size)? + ERR52 : ERR86; + return 0; } - /* Initialization for "real" parentheses */ + /* There is at least one situation where code goes backwards: this is the + case of a zero quantifier after a class (e.g. [ab]{0}). When the quantifier + is processed, the whole class is eliminated. However, it is created first, + so we have to allow memory for it. Therefore, don't ever reduce the length + at this point. */ - newoptions = options; - skipunits = 0; - bravalue = OP_CBRA; - reset_bracount = FALSE; + if (code < last_code) code = last_code; - /* Deal with the extended parentheses; all are introduced by '?', and the - appearance of any of them means that this is not a capturing group. */ + /* If the next thing is not a quantifier, we add the length of the previous + item into the total, and reset the code pointer to the start of the + workspace. Otherwise leave the previous item available to be quantified. */ - if (*ptr == CHAR_QUESTION_MARK) + if (meta < META_ASTERISK || meta > META_MINMAX_QUERY) { - int i, count; - int namelen; /* Must be signed */ - uint32_t index; - uint32_t set, unset, *optset; - named_group *ng; - PCRE2_SPTR name; - PCRE2_UCHAR *slot; - - switch (*(++ptr)) + if (OFLOW_MAX - *lengthptr < (PCRE2_SIZE)(code - orig_code)) { - /* ------------------------------------------------------------ */ - case CHAR_VERTICAL_LINE: /* Reset capture count for each branch */ - reset_bracount = TRUE; - /* Fall through */ - - /* ------------------------------------------------------------ */ - case CHAR_COLON: /* Non-capturing bracket */ - bravalue = OP_BRA; - ptr++; - break; + *errorcodeptr = ERR20; /* Integer overflow */ + return 0; + } + *lengthptr += (PCRE2_SIZE)(code - orig_code); + if (*lengthptr > MAX_PATTERN_SIZE) + { + *errorcodeptr = ERR20; /* Pattern is too large */ + return 0; + } + code = orig_code; + } - /* ------------------------------------------------------------ */ - case CHAR_LEFT_PARENTHESIS: - bravalue = OP_COND; /* Conditional group */ - tempptr = ptr; + /* Remember where this code item starts so we can catch the "backwards" + case above next time round. */ - /* A condition can be an assertion, a number (referring to a numbered - group's having been set), a name (referring to a named group), or 'R', - referring to recursion. R and R&name are also permitted for - recursion tests. + last_code = code; + } - There are ways of testing a named group: (?(name)) is used by Python; - Perl 5.10 onwards uses (?() or (?('name')). + /* Process the next parsed pattern item. If it is not a quantifier, remember + where it starts so that it can be quantified when a quantifier follows. + Checking for the legality of quantifiers happens in parse_regex(), except for + a quantifier after an assertion that is a condition. */ - There is one unfortunate ambiguity, caused by history. 'R' can be the - recursive thing or the name 'R' (and similarly for 'R' followed by - digits). We look for a name first; if not found, we try the other case. + if (meta < META_ASTERISK || meta > META_MINMAX_QUERY) + { + previous = code; + if (matched_char) okreturn = 1; + } - For compatibility with auto-callouts, we allow a callout to be - specified before a condition that is an assertion. First, check for the - syntax of a callout; if found, adjust the temporary pointer that is - used to check for an assertion condition. That's all that is needed! */ + previous_matched_char = matched_char; + matched_char = FALSE; + note_group_empty = FALSE; + skipunits = 0; /* Default value for most subgroups */ - if (ptr[1] == CHAR_QUESTION_MARK && ptr[2] == CHAR_C) - { - if (IS_DIGIT(ptr[3]) || ptr[3] == CHAR_RIGHT_PARENTHESIS) - { - for (i = 3;; i++) if (!IS_DIGIT(ptr[i])) break; - if (ptr[i] == CHAR_RIGHT_PARENTHESIS) - tempptr += i + 1; - } - else - { - uint32_t delimiter = 0; - for (i = 0; PRIV(callout_start_delims)[i] != 0; i++) - { - if (ptr[3] == PRIV(callout_start_delims)[i]) - { - delimiter = PRIV(callout_end_delims)[i]; - break; - } - } - if (delimiter != 0) - { - for (i = 4; ptr + i < cb->end_pattern; i++) - { - if (ptr[i] == delimiter) - { - if (ptr[i+1] == delimiter) i++; - else - { - if (ptr[i+1] == CHAR_RIGHT_PARENTHESIS) tempptr += i + 2; - break; - } - } - } - } - } + switch(meta) + { + /* ===================================================================*/ + /* The branch terminates at pattern end or | or ) */ - /* tempptr should now be pointing to the opening parenthesis of the - assertion condition. */ + case META_END: + case META_ALT: + case META_KET: + *firstcuptr = firstcu; + *firstcuflagsptr = firstcuflags; + *reqcuptr = reqcu; + *reqcuflagsptr = reqcuflags; + *codeptr = code; + *pptrptr = pptr; + return okreturn; - if (*tempptr != CHAR_LEFT_PARENTHESIS) - { - *errorcodeptr = ERR28; - goto FAILED; - } - } - /* For conditions that are assertions, check the syntax, and then exit - the switch. This will take control down to where bracketed groups - are processed. The assertion will be handled as part of the group, - but we need to identify this case because the conditional assertion may - not be quantifier. */ - - if (tempptr[1] == CHAR_QUESTION_MARK && - (tempptr[2] == CHAR_EQUALS_SIGN || - tempptr[2] == CHAR_EXCLAMATION_MARK || - (tempptr[2] == CHAR_LESS_THAN_SIGN && - (tempptr[3] == CHAR_EQUALS_SIGN || - tempptr[3] == CHAR_EXCLAMATION_MARK)))) - { - cb->iscondassert = TRUE; - break; - } + /* ===================================================================*/ + /* Handle single-character metacharacters. In multiline mode, ^ disables + the setting of any following char as a first character. */ - /* Other conditions use OP_CREF/OP_DNCREF/OP_RREF/OP_DNRREF, and all - need to skip at least 1+IMM2_SIZE bytes at the start of the group. */ + case META_CIRCUMFLEX: + if ((options & PCRE2_MULTILINE) != 0) + { + if (firstcuflags == REQ_UNSET) + zerofirstcuflags = firstcuflags = REQ_NONE; + *code++ = OP_CIRCM; + } + else *code++ = OP_CIRC; + break; - code[1+LINK_SIZE] = OP_CREF; - skipunits = 1+IMM2_SIZE; - refsign = -1; /* => not a number */ - namelen = -1; /* => not a name; must set to avoid warning */ - name = NULL; /* Always set to avoid warning */ - recno = 0; /* Always set to avoid warning */ + case META_DOLLAR: + *code++ = ((options & PCRE2_MULTILINE) != 0)? OP_DOLLM : OP_DOLL; + break; - /* Point at character after (?( */ + /* There can never be a first char if '.' is first, whatever happens about + repeats. The value of reqcu doesn't change either. */ - ptr++; + case META_DOT: + matched_char = TRUE; + if (firstcuflags == REQ_UNSET) firstcuflags = REQ_NONE; + zerofirstcu = firstcu; + zerofirstcuflags = firstcuflags; + zeroreqcu = reqcu; + zeroreqcuflags = reqcuflags; + *code++ = ((options & PCRE2_DOTALL) != 0)? OP_ALLANY: OP_ANY; + break; - /* Check for (?(VERSION[>]=n.m), which is a facility whereby indirect - users of PCRE2 via an application can discover which release of PCRE2 - is being used. */ - if (PRIV(strncmp_c8)(ptr, STRING_VERSION, 7) == 0 && - ptr[7] != CHAR_RIGHT_PARENTHESIS) - { - BOOL ge = FALSE; - int major = 0; - int minor = 0; + /* ===================================================================*/ + /* Empty character classes are allowed if PCRE2_ALLOW_EMPTY_CLASS is set. + Otherwise, an initial ']' is taken as a data character. When empty classes + are allowed, [] must always fail, so generate OP_FAIL, whereas [^] must + match any character, so generate OP_ALLANY. */ + + case META_CLASS_EMPTY: + case META_CLASS_EMPTY_NOT: + matched_char = TRUE; + *code++ = (meta == META_CLASS_EMPTY_NOT)? OP_ALLANY : OP_FAIL; + if (firstcuflags == REQ_UNSET) firstcuflags = REQ_NONE; + zerofirstcu = firstcu; + zerofirstcuflags = firstcuflags; + break; - ptr += 7; - if (*ptr == CHAR_GREATER_THAN_SIGN) - { - ge = TRUE; - ptr++; - } - /* NOTE: cannot write IS_DIGIT(*(++ptr)) here because IS_DIGIT - references its argument twice. */ + /* ===================================================================*/ + /* Non-empty character class. If the included characters are all < 256, we + build a 32-byte bitmap of the permitted characters, except in the special + case where there is only one such character. For negated classes, we build + the map as usual, then invert it at the end. However, we use a different + opcode so that data characters > 255 can be handled correctly. - if (*ptr != CHAR_EQUALS_SIGN || (ptr++, !IS_DIGIT(*ptr))) - { - *errorcodeptr = ERR79; - goto FAILED; - } + If the class contains characters outside the 0-255 range, a different + opcode is compiled. It may optionally have a bit map for characters < 256, + but those above are are explicitly listed afterwards. A flag code unit + tells whether the bitmap is present, and whether this is a negated class or + not. */ - while (IS_DIGIT(*ptr)) major = major * 10 + *ptr++ - '0'; - if (*ptr == CHAR_DOT) - { - ptr++; - while (IS_DIGIT(*ptr)) minor = minor * 10 + *ptr++ - '0'; - if (minor < 10) minor *= 10; - } + case META_CLASS_NOT: + case META_CLASS: + matched_char = TRUE; + negate_class = meta == META_CLASS_NOT; - if (*ptr != CHAR_RIGHT_PARENTHESIS || minor > 99) - { - *errorcodeptr = ERR79; - goto FAILED; - } + /* We can optimize the case of a single character in a class by generating + OP_CHAR or OP_CHARI if it's positive, or OP_NOT or OP_NOTI if it's + negative. In the negative case there can be no first char if this item is + first, whatever repeat count may follow. In the case of reqcu, save the + previous value for reinstating. */ - if (ge) - code[1+LINK_SIZE] = ((PCRE2_MAJOR > major) || - (PCRE2_MAJOR == major && PCRE2_MINOR >= minor))? - OP_TRUE : OP_FALSE; - else - code[1+LINK_SIZE] = (PCRE2_MAJOR == major && PCRE2_MINOR == minor)? - OP_TRUE : OP_FALSE; + /* NOTE: at present this optimization is not effective if the only + character in a class in 32-bit, non-UCP mode has its top bit set. */ - ptr++; - skipunits = 1; - break; /* End of condition processing */ - } + if (pptr[1] < META_END && pptr[2] == META_CLASS_END) + { +#ifdef SUPPORT_UNICODE + uint32_t d; +#endif + uint32_t c = pptr[1]; - /* Check for a test for recursion in a named group. */ + pptr += 2; /* Move on to class end */ + if (meta == META_CLASS) /* A positive one-char class can be */ + { /* handled as a normal literal character. */ + meta = c; /* Set up the character */ + goto NORMAL_CHAR_SET; + } - if (*ptr == CHAR_R && ptr[1] == CHAR_AMPERSAND) - { - terminator = -1; - ptr += 2; - code[1+LINK_SIZE] = OP_RREF; /* Change the type of test */ - } + /* Handle a negative one-character class */ - /* Check for a test for a named group's having been set, using the Perl - syntax (?() or (?('name'), and also allow for the original PCRE - syntax of (?(name) or for (?(+n), (?(-n), and just (?(n). */ + zeroreqcu = reqcu; + zeroreqcuflags = reqcuflags; + if (firstcuflags == REQ_UNSET) firstcuflags = REQ_NONE; + zerofirstcu = firstcu; + zerofirstcuflags = firstcuflags; - else if (*ptr == CHAR_LESS_THAN_SIGN) - { - terminator = CHAR_GREATER_THAN_SIGN; - ptr++; - } - else if (*ptr == CHAR_APOSTROPHE) - { - terminator = CHAR_APOSTROPHE; - ptr++; - } - else - { - terminator = CHAR_NULL; - if (*ptr == CHAR_MINUS || *ptr == CHAR_PLUS) refsign = *ptr++; - else if (IS_DIGIT(*ptr)) refsign = 0; - } + /* For caseless UTF mode, check whether this character has more than + one other case. If so, generate a special OP_NOTPROP item instead of + OP_NOTI. */ - /* Handle a number */ +#ifdef SUPPORT_UNICODE + if (utf && (options & PCRE2_CASELESS) != 0 && + (d = UCD_CASESET(c)) != 0) + { + *code++ = OP_NOTPROP; + *code++ = PT_CLIST; + *code++ = d; + break; /* We are finished with this class */ + } +#endif + /* Char has only one other case, or UCP not available */ - if (refsign >= 0) - { - while (IS_DIGIT(*ptr)) - { - if (recno > INT_MAX / 10 - 1) /* Integer overflow */ - { - while (IS_DIGIT(*ptr)) ptr++; - *errorcodeptr = ERR61; - goto FAILED; - } - recno = recno * 10 + (int)(*ptr - CHAR_0); - ptr++; - } - } + *code++ = ((options & PCRE2_CASELESS) != 0)? OP_NOTI: OP_NOT; + code += PUTCHAR(c, code); + break; /* We are finished with this class */ + } /* End of 1-char optimization */ - /* Otherwise we expect to read a name; anything else is an error. When - the referenced name is one of a number of duplicates, a different - opcode is used and it needs more memory. Unfortunately we cannot tell - whether this is the case in the first pass, so we have to allow for - more memory always. In the second pass, the additional to skipunits - happens later. */ - - else - { - if (IS_DIGIT(*ptr)) - { - *errorcodeptr = ERR44; /* Group name must start with non-digit */ - goto FAILED; - } - if (!MAX_255(*ptr) || (cb->ctypes[*ptr] & ctype_word) == 0) - { - *errorcodeptr = ERR28; /* Assertion expected */ - goto FAILED; - } - name = ptr; - /* Increment ptr, set namelen, check length */ - READ_NAME(ctype_word, ERR48, *errorcodeptr); - if (lengthptr != NULL) skipunits += IMM2_SIZE; - } + /* Handle character classes that contain more than just one literal + character. */ - /* Check the terminator */ + /* If a non-extended class contains a negative special such as \S, we need + to flip the negation flag at the end, so that support for characters > 255 + works correctly (they are all included in the class). An extended class may + need to insert specific matching or non-matching code for wide characters. + */ - if ((terminator > 0 && *ptr++ != (PCRE2_UCHAR)terminator) || - *ptr++ != CHAR_RIGHT_PARENTHESIS) - { - ptr--; /* Error offset */ - *errorcodeptr = ERR26; /* Malformed number or name */ - goto FAILED; - } + should_flip_negation = match_all_or_no_wide_chars = FALSE; - /* Do no further checking in the pre-compile phase. */ + /* Extended class (xclass) will be used when characters > 255 + might match. */ - if (lengthptr != NULL) break; +#ifdef SUPPORT_WIDE_CHARS + xclass = FALSE; + class_uchardata = code + LINK_SIZE + 2; /* For XCLASS items */ + class_uchardata_base = class_uchardata; /* Save the start */ +#endif - /* In the real compile we do the work of looking for the actual - reference. If refsign is not negative, it means we have a number in - recno. */ + /* For optimization purposes, we track some properties of the class: + class_has_8bitchar will be non-zero if the class contains at least one + character with a code point less than 256; xclass_has_prop will be TRUE if + Unicode property checks are present in the class. */ - if (refsign >= 0) - { - if (recno <= 0) - { - *errorcodeptr = ERR35; - goto FAILED; - } - if (refsign != 0) recno = (refsign == CHAR_MINUS)? - (cb->bracount + 1) - recno : recno + cb->bracount; - if (recno <= 0 || (uint32_t)recno > cb->final_bracount) - { - *errorcodeptr = ERR15; - goto FAILED; - } - PUT2(code, 2+LINK_SIZE, recno); - if ((uint32_t)recno > cb->top_backref) cb->top_backref = recno; - break; - } + class_has_8bitchar = 0; +#ifdef SUPPORT_WIDE_CHARS + xclass_has_prop = FALSE; +#endif - /* Otherwise look for the name. */ + /* Initialize the 256-bit (32-byte) bit map to all zeros. We build the map + in a temporary bit of memory, in case the class contains fewer than two + 8-bit characters because in that case the compiled code doesn't use the bit + map. */ - slot = cb->name_table; - for (i = 0; i < cb->names_found; i++) - { - if (PRIV(strncmp)(name, slot+IMM2_SIZE, namelen) == 0) break; - slot += cb->name_entry_size; - } + memset(classbits, 0, 32 * sizeof(uint8_t)); - /* Found the named subpattern. If the name is duplicated, add one to - the opcode to change CREF/RREF into DNCREF/DNRREF and insert - appropriate data values. Otherwise, just insert the unique subpattern - number. */ + /* Process items until META_CLASS_END is reached. */ - if (i < cb->names_found) - { - int offset = i; /* Offset of first name found */ + while ((meta = *(++pptr)) != META_CLASS_END) + { + /* Handle POSIX classes such as [:alpha:] etc. */ - count = 0; - for (;;) - { - recno = GET2(slot, 0); /* Number for last found */ - if ((uint32_t)recno > cb->top_backref) cb->top_backref = recno; - count++; - if (++i >= cb->names_found) break; - slot += cb->name_entry_size; - if (PRIV(strncmp)(name, slot+IMM2_SIZE, namelen) != 0 || - (slot+IMM2_SIZE)[namelen] != 0) break; - } + if (meta == META_POSIX || meta == META_POSIX_NEG) + { + BOOL local_negate = (meta == META_POSIX_NEG); + int posix_class = *(++pptr); + int taboffset, tabopt; + uint8_t pbits[32]; - if (count > 1) - { - PUT2(code, 2+LINK_SIZE, offset); - PUT2(code, 2+LINK_SIZE+IMM2_SIZE, count); - skipunits += IMM2_SIZE; - code[1+LINK_SIZE]++; - } - else /* Not a duplicated name */ - { - PUT2(code, 2+LINK_SIZE, recno); - } - } + should_flip_negation = local_negate; /* Note negative special */ - /* If terminator == CHAR_NULL it means that the name followed directly - after the opening parenthesis [e.g. (?(abc)...] and in this case there - are some further alternatives to try. For the cases where terminator != - CHAR_NULL [things like (?(... or (?('name')... or (?(R&name)... ] - we have now checked all the possibilities, so give an error. */ + /* If matching is caseless, upper and lower are converted to alpha. + This relies on the fact that the class table starts with alpha, + lower, upper as the first 3 entries. */ - else if (terminator != CHAR_NULL) - { - *errorcodeptr = ERR15; - goto FAILED; - } + if ((options & PCRE2_CASELESS) != 0 && posix_class <= 2) + posix_class = 0; - /* Check for (?(R) for recursion. Allow digits after R to specify a - specific group number. */ + /* When PCRE2_UCP is set, some of the POSIX classes are converted to + different escape sequences that use Unicode properties \p or \P. + Others that are not available via \p or \P have to generate + XCL_PROP/XCL_NOTPROP directly, which is done here. */ - else if (*name == CHAR_R) +#ifdef SUPPORT_UNICODE + if ((options & PCRE2_UCP) != 0) switch(posix_class) { - recno = 0; - for (i = 1; i < namelen; i++) - { - if (!IS_DIGIT(name[i])) - { - *errorcodeptr = ERR15; /* Non-existent subpattern */ - goto FAILED; - } - if (recno > INT_MAX / 10 - 1) /* Integer overflow */ - { - *errorcodeptr = ERR61; - goto FAILED; - } - recno = recno * 10 + name[i] - CHAR_0; - } - if (recno == 0) recno = RREF_ANY; - code[1+LINK_SIZE] = OP_RREF; /* Change test type */ - PUT2(code, 2+LINK_SIZE, recno); - } + case PC_GRAPH: + case PC_PRINT: + case PC_PUNCT: + *class_uchardata++ = local_negate? XCL_NOTPROP : XCL_PROP; + *class_uchardata++ = (PCRE2_UCHAR) + ((posix_class == PC_GRAPH)? PT_PXGRAPH : + (posix_class == PC_PRINT)? PT_PXPRINT : PT_PXPUNCT); + *class_uchardata++ = 0; + xclass_has_prop = TRUE; + goto CONTINUE_CLASS; - /* Similarly, check for the (?(DEFINE) "condition", which is always - false. During compilation we set OP_DEFINE to distinguish this from - other OP_FALSE conditions so that it can be checked for having only one - branch, but after that the opcode is changed to OP_FALSE. */ + /* For the other POSIX classes (ascii, xdigit) we are going to + fall through to the non-UCP case and build a bit map for + characters with code points less than 256. However, if we are in + a negated POSIX class, characters with code points greater than + 255 must either all match or all not match, depending on whether + the whole class is not or is negated. For example, for + [[:^ascii:]... they must all match, whereas for [^[:^xdigit:]... + they must not. + + In the special case where there are no xclass items, this is + automatically handled by the use of OP_CLASS or OP_NCLASS, but an + explicit range is needed for OP_XCLASS. Setting a flag here + causes the range to be generated later when it is known that + OP_XCLASS is required. In the 8-bit library this is relevant only in + utf mode, since no wide characters can exist otherwise. */ - else if (namelen == 6 && PRIV(strncmp_c8)(name, STRING_DEFINE, 6) == 0) - { - code[1+LINK_SIZE] = OP_DEFINE; - skipunits = 1; + default: +#if PCRE2_CODE_UNIT_WIDTH == 8 + if (utf) +#endif + match_all_or_no_wide_chars |= local_negate; + break; } +#endif /* SUPPORT_UNICODE */ - /* Reference to an unidentified subpattern. */ + /* In the non-UCP case, or when UCP makes no difference, we build the + bit map for the POSIX class in a chunk of local store because we may + be adding and subtracting from it, and we don't want to subtract bits + that may be in the main map already. At the end we or the result into + the bit map that is being built. */ - else - { - *errorcodeptr = ERR15; - goto FAILED; - } - break; + posix_class *= 3; + /* Copy in the first table (always present) */ - /* ------------------------------------------------------------ */ - case CHAR_EQUALS_SIGN: /* Positive lookahead */ - bravalue = OP_ASSERT; - cb->assert_depth += 1; - ptr++; - break; + memcpy(pbits, cbits + posix_class_maps[posix_class], + 32 * sizeof(uint8_t)); - /* Optimize (?!) to (*FAIL) unless it is quantified - which is a weird - thing to do, but Perl allows all assertions to be quantified, and when - they contain capturing parentheses there may be a potential use for - this feature. Not that that applies to a quantified (?!) but we allow - it for uniformity. */ + /* If there is a second table, add or remove it as required. */ - /* ------------------------------------------------------------ */ - case CHAR_EXCLAMATION_MARK: /* Negative lookahead */ - ptr++; - if (*ptr == CHAR_RIGHT_PARENTHESIS && ptr[1] != CHAR_ASTERISK && - ptr[1] != CHAR_PLUS && ptr[1] != CHAR_QUESTION_MARK && - (ptr[1] != CHAR_LEFT_CURLY_BRACKET || !is_counted_repeat(ptr+2))) + taboffset = posix_class_maps[posix_class + 1]; + tabopt = posix_class_maps[posix_class + 2]; + + if (taboffset >= 0) { - *code++ = OP_FAIL; - previous = NULL; - continue; + if (tabopt >= 0) + for (i = 0; i < 32; i++) pbits[i] |= cbits[(int)i + taboffset]; + else + for (i = 0; i < 32; i++) pbits[i] &= ~cbits[(int)i + taboffset]; } - bravalue = OP_ASSERT_NOT; - cb->assert_depth += 1; - break; - - /* ------------------------------------------------------------ */ - case CHAR_LESS_THAN_SIGN: /* Lookbehind or named define */ - switch (ptr[1]) - { - case CHAR_EQUALS_SIGN: /* Positive lookbehind */ - bravalue = OP_ASSERTBACK; - cb->assert_depth += 1; - ptr += 2; - break; + /* Now see if we need to remove any special characters. An option + value of 1 removes vertical space and 2 removes underscore. */ - case CHAR_EXCLAMATION_MARK: /* Negative lookbehind */ - bravalue = OP_ASSERTBACK_NOT; - cb->assert_depth += 1; - ptr += 2; - break; + if (tabopt < 0) tabopt = -tabopt; + if (tabopt == 1) pbits[1] &= ~0x3c; + else if (tabopt == 2) pbits[11] &= 0x7f; - /* Must be a name definition - as the syntax was checked in the - pre-pass, we can assume here that it is valid. Skip over the name - and go to handle the numbered group. */ + /* Add the POSIX table or its complement into the main table that is + being built and we are done. */ - default: - while (*(++ptr) != CHAR_GREATER_THAN_SIGN); - ptr++; - goto NUMBERED_GROUP; - } - break; + if (local_negate) + for (i = 0; i < 32; i++) classbits[i] |= ~pbits[i]; + else + for (i = 0; i < 32; i++) classbits[i] |= pbits[i]; + /* Every class contains at least one < 256 character. */ - /* ------------------------------------------------------------ */ - case CHAR_GREATER_THAN_SIGN: /* One-time brackets */ - bravalue = OP_ONCE; - ptr++; - break; + class_has_8bitchar = 1; + goto CONTINUE_CLASS; /* End of POSIX handling */ + } + /* Other than POSIX classes, the only items we should encounter are + \d-type escapes and literal characters (possibly as ranges). */ - /* ------------------------------------------------------------ */ - case CHAR_C: /* Callout */ - previous_callout = code; /* Save for later completion */ - after_manual_callout = 1; /* Skip one item before completing */ - ptr++; /* Character after (?C */ + if (meta == META_BIGVALUE) + { + meta = *(++pptr); + goto CLASS_LITERAL; + } - /* A callout may have a string argument, delimited by one of a fixed - number of characters, or an undelimited numerical argument, or no - argument, which is the same as (?C0). Different opcodes are used for - the two cases. */ + /* Any other non-literal must be an escape */ - if (*ptr != CHAR_RIGHT_PARENTHESIS && !IS_DIGIT(*ptr)) + if (meta >= META_END) + { + if (META_CODE(meta) != META_ESCAPE) { - uint32_t delimiter = 0; - - for (i = 0; PRIV(callout_start_delims)[i] != 0; i++) - { - if (*ptr == PRIV(callout_start_delims)[i]) - { - delimiter = PRIV(callout_end_delims)[i]; - break; - } - } - - if (delimiter == 0) - { - *errorcodeptr = ERR82; - goto FAILED; - } - - /* During the pre-compile phase, we parse the string and update the - length. There is no need to generate any code. (In fact, the string - has already been parsed in the pre-pass that looks for named - parentheses, but it does no harm to leave this code in.) */ +#ifdef DEBUG_SHOW_PARSED + fprintf(stderr, "** Unrecognized parsed pattern item 0x%.8x " + "in character class\n", meta); +#endif + *errorcodeptr = ERR89; /* Internal error - unrecognized. */ + return 0; + } + escape = META_DATA(meta); - if (lengthptr != NULL) /* Only check the string */ - { - PCRE2_SPTR start = ptr; - do - { - if (++ptr >= cb->end_pattern) - { - *errorcodeptr = ERR81; - ptr = start; /* To give a more useful message */ - goto FAILED; - } - if (ptr[0] == delimiter && ptr[1] == delimiter) ptr += 2; - } - while (ptr[0] != delimiter); + /* Every class contains at least one < 256 character. */ - /* Start points to the opening delimiter, ptr points to the - closing delimiter. We must allow for including the delimiter and - for the terminating zero. Any doubled delimiters within the string - make this an overestimate, but it is not worth bothering about. */ + class_has_8bitchar++; - (*lengthptr) += (ptr - start) + 2 + (1 + 4*LINK_SIZE); - } + switch(escape) + { + case ESC_d: + for (i = 0; i < 32; i++) classbits[i] |= cbits[i+cbit_digit]; + break; - /* In the real compile we can copy the string, knowing that it is - syntactically OK. The starting delimiter is included so that the - client can discover it if they want. We also pass the start offset to - help a script language give better error messages. */ + case ESC_D: + should_flip_negation = TRUE; + for (i = 0; i < 32; i++) classbits[i] |= ~cbits[i+cbit_digit]; + break; - else - { - PCRE2_UCHAR *callout_string = code + (1 + 4*LINK_SIZE); - *callout_string++ = *ptr++; - PUT(code, 1 + 3*LINK_SIZE, (int)(ptr - cb->start_pattern)); /* Start offset */ - for(;;) - { - if (*ptr == delimiter) - { - if (ptr[1] == delimiter) ptr++; else break; - } - *callout_string++ = *ptr++; - } - *callout_string++ = CHAR_NULL; - code[0] = OP_CALLOUT_STR; - PUT(code, 1, (int)(ptr + 2 - cb->start_pattern)); /* Next offset */ - PUT(code, 1 + LINK_SIZE, 0); /* Default length */ - PUT(code, 1 + 2*LINK_SIZE, /* Compute size */ - (int)(callout_string - code)); - code = callout_string; - } + case ESC_w: + for (i = 0; i < 32; i++) classbits[i] |= cbits[i+cbit_word]; + break; - /* Advance to what should be the closing parenthesis, which is - checked below. */ + case ESC_W: + should_flip_negation = TRUE; + for (i = 0; i < 32; i++) classbits[i] |= ~cbits[i+cbit_word]; + break; - ptr++; - } + /* Perl 5.004 onwards omitted VT from \s, but restored it at Perl + 5.18. Before PCRE 8.34, we had to preserve the VT bit if it was + previously set by something earlier in the character class. + Luckily, the value of CHAR_VT is 0x0b in both ASCII and EBCDIC, so + we could just adjust the appropriate bit. From PCRE 8.34 we no + longer treat \s and \S specially. */ - /* Handle a callout with an optional numerical argument, which must be - less than or equal to 255. A missing argument gives 0. */ + case ESC_s: + for (i = 0; i < 32; i++) classbits[i] |= cbits[i+cbit_space]; + break; - else - { - int n = 0; - code[0] = OP_CALLOUT; /* Numerical callout */ - while (IS_DIGIT(*ptr)) - { - n = n * 10 + *ptr++ - CHAR_0; - if (n > 255) - { - *errorcodeptr = ERR38; - goto FAILED; - } - } - PUT(code, 1, (int)(ptr - cb->start_pattern + 1)); /* Next offset */ - PUT(code, 1 + LINK_SIZE, 0); /* Default length */ - code[1 + 2*LINK_SIZE] = n; /* Callout number */ - code += PRIV(OP_lengths)[OP_CALLOUT]; - } + case ESC_S: + should_flip_negation = TRUE; + for (i = 0; i < 32; i++) classbits[i] |= ~cbits[i+cbit_space]; + break; - /* Both formats must have a closing parenthesis */ + /* When adding the horizontal or vertical space lists to a class, or + their complements, disable PCRE2_CASELESS, because it justs wastes + time, and in the "not-x" UTF cases can create unwanted duplicates in + the XCLASS list (provoked by characters that have more than one other + case and by both cases being in the same "not-x" sublist). */ - if (*ptr != CHAR_RIGHT_PARENTHESIS) - { - *errorcodeptr = ERR39; - goto FAILED; - } + case ESC_h: + (void)add_list_to_class(classbits, &class_uchardata, + options & ~PCRE2_CASELESS, cb, PRIV(hspace_list), NOTACHAR); + break; - /* Callouts cannot be quantified. */ + case ESC_H: + (void)add_not_list_to_class(classbits, &class_uchardata, + options & ~PCRE2_CASELESS, cb, PRIV(hspace_list)); + break; - previous = NULL; - continue; + case ESC_v: + (void)add_list_to_class(classbits, &class_uchardata, + options & ~PCRE2_CASELESS, cb, PRIV(vspace_list), NOTACHAR); + break; + case ESC_V: + (void)add_not_list_to_class(classbits, &class_uchardata, + options & ~PCRE2_CASELESS, cb, PRIV(vspace_list)); + break; - /* ------------------------------------------------------------ */ - case CHAR_P: /* Python-style named subpattern handling */ - if (*(++ptr) == CHAR_EQUALS_SIGN || - *ptr == CHAR_GREATER_THAN_SIGN) /* Reference or recursion */ - { - is_recurse = *ptr == CHAR_GREATER_THAN_SIGN; - terminator = CHAR_RIGHT_PARENTHESIS; - goto NAMED_REF_OR_RECURSE; - } - else if (*ptr != CHAR_LESS_THAN_SIGN) /* Test for Python-style defn */ - { - *errorcodeptr = ERR41; - goto FAILED; + case ESC_p: + case ESC_P: + { + uint32_t ptype = *(++pptr) >> 16; + uint32_t pdata = *pptr & 0xffff; + *class_uchardata++ = (escape == ESC_p)? XCL_PROP : XCL_NOTPROP; + *class_uchardata++ = ptype; + *class_uchardata++ = pdata; +#ifdef SUPPORT_WIDE_CHARS + xclass_has_prop = TRUE; +#endif + class_has_8bitchar--; /* Undo! */ + } + break; } - /* Fall through to handle (?P< as (?< is handled */ + goto CONTINUE_CLASS; + } /* End handling \d-type escapes */ - /* ------------------------------------------------------------ */ - case CHAR_APOSTROPHE: /* Define a name - note fall through above */ + /* A literal character may be followed by a range meta. At parse time + there are checks for out-of-order characters, for ranges where the two + characters are equal, and for hyphens that cannot indicate a range. At + this point, therefore, no checking is needed. */ - /* The syntax was checked and the list of names was set up in the - pre-pass, so there is nothing to be done now except to skip over the - name. */ + else + { + uint32_t c, d; - terminator = (*ptr == CHAR_LESS_THAN_SIGN)? - CHAR_GREATER_THAN_SIGN : CHAR_APOSTROPHE; - while (*(++ptr) != (unsigned int)terminator); - ptr++; - goto NUMBERED_GROUP; /* Set up numbered group */ + CLASS_LITERAL: + c = d = meta; + /* Remember if \r or \n were explicitly used */ - /* ------------------------------------------------------------ */ - case CHAR_AMPERSAND: /* Perl recursion/subroutine syntax */ - terminator = CHAR_RIGHT_PARENTHESIS; - is_recurse = TRUE; - /* Fall through */ + if (c == CHAR_CR || c == CHAR_NL) cb->external_flags |= PCRE2_HASCRORLF; - /* We come here from the Python syntax above that handles both - references (?P=name) and recursion (?P>name), as well as falling - through from the Perl recursion syntax (?&name). We also come here from - the Perl \k or \k'name' back reference syntax and the \k{name} - .NET syntax, and the Oniguruma \g<...> and \g'...' subroutine syntax. */ + /* Process a character range */ - NAMED_REF_OR_RECURSE: - name = ++ptr; - if (IS_DIGIT(*ptr)) + if (pptr[1] == META_RANGE_LITERAL || pptr[1] == META_RANGE_ESCAPED) { - *errorcodeptr = ERR44; /* Group name must start with non-digit */ - goto FAILED; - } - /* Increment ptr, set namelen, check length */ - READ_NAME(ctype_word, ERR48, *errorcodeptr); - - /* In the pre-compile phase, do a syntax check. */ +#ifdef EBCDIC + BOOL range_is_literal = (pptr[1] == META_RANGE_LITERAL); +#endif + pptr += 2; + d = *pptr; + if (d == META_BIGVALUE) d = *(++pptr); - if (lengthptr != NULL) - { - if (namelen == 0) - { - *errorcodeptr = ERR62; - goto FAILED; - } - if (*ptr != (PCRE2_UCHAR)terminator) - { - *errorcodeptr = ERR42; - goto FAILED; - } - } + /* Remember an explicit \r or \n, and add the range to the class. */ - /* Scan the list of names generated in the pre-pass in order to get - a number and whether or not this name is duplicated. */ + if (d == CHAR_CR || d == CHAR_NL) cb->external_flags |= PCRE2_HASCRORLF; - recno = 0; - is_dupname = FALSE; - ng = cb->named_groups; + /* In an EBCDIC environment, Perl treats alphabetic ranges specially + because there are holes in the encoding, and simply using the range + A-Z (for example) would include the characters in the holes. This + applies only to literal ranges; [\xC1-\xE9] is different to [A-Z]. */ - for (i = 0; i < cb->names_found; i++, ng++) - { - if (namelen == ng->length && - PRIV(strncmp)(name, ng->name, namelen) == 0) +#ifdef EBCDIC + if (range_is_literal && + (cb->ctypes[c] & ctype_letter) != 0 && + (cb->ctypes[d] & ctype_letter) != 0 && + (d <= CHAR_z) == (d <= CHAR_z)) { - open_capitem *oc; - is_dupname = ng->isdup; - recno = ng->number; - - /* For a recursion, that's all that is needed. We can now go to the - code that handles numerical recursion. */ + uint32_t uc = (d <= CHAR_z)? 0 : 64; + uint32_t C = d - uc; + uint32_t D = d - uc; - if (is_recurse) goto HANDLE_RECURSION; - - /* For a back reference, update the back reference map and the - maximum back reference. Then for each group we must check to see if - it is recursive, that is, it is inside the group that it - references. A flag is set so that the group can be made atomic. */ + if (C <= CHAR_i) + { + class_has_8bitchar += + add_to_class(classbits, &class_uchardata, options, cb, C + uc, + ((D < CHAR_i)? D : CHAR_i) + uc); + C = CHAR_j; + } - cb->backref_map |= (recno < 32)? (1u << recno) : 1; - if ((uint32_t)recno > cb->top_backref) cb->top_backref = recno; + if (C <= D && C <= CHAR_r) + { + class_has_8bitchar += + add_to_class(classbits, &class_uchardata, options, cb, C + uc, + ((D < CHAR_r)? D : CHAR_r) + uc); + C = CHAR_s; + } - for (oc = cb->open_caps; oc != NULL; oc = oc->next) + if (C <= D) { - if (oc->number == recno) - { - oc->flag = TRUE; - break; - } + class_has_8bitchar += + add_to_class(classbits, &class_uchardata, options, cb, C + uc, + D + uc); } } - } - - /* If the name was not found we have a bad reference. */ - - if (recno == 0) - { - *errorcodeptr = ERR15; - goto FAILED; - } - - /* If a back reference name is not duplicated, we can handle it as a - numerical reference. */ + else +#endif + /* Not an EBCDIC special range */ - if (!is_dupname) goto HANDLE_REFERENCE; + class_has_8bitchar += + add_to_class(classbits, &class_uchardata, options, cb, c, d); + goto CONTINUE_CLASS; /* Go get the next char in the class */ + } /* End of range handling */ - /* If a back reference name is duplicated, we generate a different - opcode to a numerical back reference. In the second pass we must search - for the index and count in the final name table. */ - count = 0; - index = 0; + /* Handle a single character. */ - if (lengthptr == NULL) - { - slot = cb->name_table; - for (i = 0; i < cb->names_found; i++) - { - if (PRIV(strncmp)(name, slot+IMM2_SIZE, namelen) == 0 && - slot[IMM2_SIZE+namelen] == 0) - { - if (count == 0) index = i; - count++; - } - slot += cb->name_entry_size; - } + class_has_8bitchar += + add_to_class(classbits, &class_uchardata, options, cb, meta, meta); + } - if (count == 0) - { - *errorcodeptr = ERR15; - goto FAILED; - } - } + /* Continue to the next item in the class. */ - if (firstcuflags == REQ_UNSET) firstcuflags = REQ_NONE; - previous = code; - *code++ = ((options & PCRE2_CASELESS) != 0)? OP_DNREFI : OP_DNREF; - PUT2INC(code, 0, index); - PUT2INC(code, 0, count); - continue; /* End of back ref handling */ + CONTINUE_CLASS: +#ifdef SUPPORT_WIDE_CHARS + /* If any wide characters or Unicode properties have been encountered, + set xclass = TRUE. Then, in the pre-compile phase, accumulate the length + of the extra data and reset the pointer. This is so that very large + classes that contain a zillion wide characters or Unicode property tests + do not overwrite the work space (which is on the stack). */ - /* ------------------------------------------------------------ */ - case CHAR_R: /* Recursion, same as (?0) */ - recno = 0; - if (*(++ptr) != CHAR_RIGHT_PARENTHESIS) + if (class_uchardata > class_uchardata_base) + { + xclass = TRUE; + if (lengthptr != NULL) { - *errorcodeptr = ERR29; - goto FAILED; + *lengthptr += class_uchardata - class_uchardata_base; + class_uchardata = class_uchardata_base; } - goto HANDLE_RECURSION; + } +#endif + continue; /* Needed to avoid error when not supporting wide chars */ + } /* End of main class-processing loop */ - /* ------------------------------------------------------------ */ - case CHAR_MINUS: case CHAR_PLUS: /* Recursion or subroutine */ - case CHAR_0: case CHAR_1: case CHAR_2: case CHAR_3: case CHAR_4: - case CHAR_5: case CHAR_6: case CHAR_7: case CHAR_8: case CHAR_9: + /* If this class is the first thing in the branch, there can be no first + char setting, whatever the repeat count. Any reqcu setting must remain + unchanged after any kind of repeat. */ + + if (firstcuflags == REQ_UNSET) firstcuflags = REQ_NONE; + zerofirstcu = firstcu; + zerofirstcuflags = firstcuflags; + zeroreqcu = reqcu; + zeroreqcuflags = reqcuflags; + + /* If there are characters with values > 255, or Unicode property settings + (\p or \P), we have to compile an extended class, with its own opcode, + unless there were no property settings and there was a negated special such + as \S in the class, and PCRE2_UCP is not set, because in that case all + characters > 255 are in or not in the class, so any that were explicitly + given as well can be ignored. + + In the UCP case, if certain negated POSIX classes ([:^ascii:] or + [^:xdigit:]) were present in a class, we either have to match or not match + all wide characters (depending on whether the whole class is or is not + negated). This requirement is indicated by match_all_or_no_wide_chars being + true. We do this by including an explicit range, which works in both cases. + This applies only in UTF and 16-bit and 32-bit non-UTF modes, since there + cannot be any wide characters in 8-bit non-UTF mode. + + When there *are* properties in a positive UTF-8 or any 16-bit or 32_bit + class where \S etc is present without PCRE2_UCP, causing an extended class + to be compiled, we make sure that all characters > 255 are included by + forcing match_all_or_no_wide_chars to be true. + + If, when generating an xclass, there are no characters < 256, we can omit + the bitmap in the actual compiled code. */ + +#ifdef SUPPORT_WIDE_CHARS /* Defined for 16/32 bits, or 8-bit with Unicode */ + if (xclass && ( +#ifdef SUPPORT_UNICODE + (options & PCRE2_UCP) != 0 || +#endif + xclass_has_prop || !should_flip_negation)) + { + if (match_all_or_no_wide_chars || ( +#if PCRE2_CODE_UNIT_WIDTH == 8 + utf && +#endif + should_flip_negation && !negate_class && (options & PCRE2_UCP) == 0)) + { + *class_uchardata++ = XCL_RANGE; + if (utf) /* Will always be utf in the 8-bit library */ { - terminator = CHAR_RIGHT_PARENTHESIS; + class_uchardata += PRIV(ord2utf)(0x100, class_uchardata); + class_uchardata += PRIV(ord2utf)(MAX_UTF_CODE_POINT, class_uchardata); + } + else /* Can only happen for the 16-bit & 32-bit libraries */ + { +#if PCRE2_CODE_UNIT_WIDTH == 16 + *class_uchardata++ = 0x100; + *class_uchardata++ = 0xffffu; +#elif PCRE2_CODE_UNIT_WIDTH == 32 + *class_uchardata++ = 0x100; + *class_uchardata++ = 0xffffffffu; +#endif + } + } + *class_uchardata++ = XCL_END; /* Marks the end of extra data */ + *code++ = OP_XCLASS; + code += LINK_SIZE; + *code = negate_class? XCL_NOT:0; + if (xclass_has_prop) *code |= XCL_HASPROP; - /* Come here from the \g<...> and \g'...' code (Oniguruma - compatibility). However, the syntax has been checked to ensure that - the ... are a (signed) number, so that neither ERR63 nor ERR29 will - be called on this path, nor with the jump to OTHER_CHAR_AFTER_QUERY - ever be taken. */ + /* If the map is required, move up the extra data to make room for it; + otherwise just move the code pointer to the end of the extra data. */ - HANDLE_NUMERICAL_RECURSION: + if (class_has_8bitchar > 0) + { + *code++ |= XCL_MAP; + memmove(code + (32 / sizeof(PCRE2_UCHAR)), code, + CU2BYTES(class_uchardata - code)); + if (negate_class && !xclass_has_prop) + for (i = 0; i < 32; i++) classbits[i] = ~classbits[i]; + memcpy(code, classbits, 32); + code = class_uchardata + (32 / sizeof(PCRE2_UCHAR)); + } + else code = class_uchardata; - if ((refsign = *ptr) == CHAR_PLUS) - { - ptr++; - if (!IS_DIGIT(*ptr)) - { - *errorcodeptr = ERR63; - goto FAILED; - } - } - else if (refsign == CHAR_MINUS) - { - if (!IS_DIGIT(ptr[1])) - goto OTHER_CHAR_AFTER_QUERY; - ptr++; - } + /* Now fill in the complete length of the item */ - recno = 0; - while (IS_DIGIT(*ptr)) - { - if (recno > INT_MAX / 10 - 1) /* Integer overflow */ - { - while (IS_DIGIT(*ptr)) ptr++; - *errorcodeptr = ERR61; - goto FAILED; - } - recno = recno * 10 + *ptr++ - CHAR_0; - } + PUT(previous, 1, (int)(code - previous)); + break; /* End of class handling */ + } +#endif /* SUPPORT_WIDE_CHARS */ - if (*ptr != (PCRE2_UCHAR)terminator) - { - *errorcodeptr = ERR29; - goto FAILED; - } + /* If there are no characters > 255, or they are all to be included or + excluded, set the opcode to OP_CLASS or OP_NCLASS, depending on whether the + whole class was negated and whether there were negative specials such as \S + (non-UCP) in the class. Then copy the 32-byte map into the code vector, + negating it if necessary. */ - if (refsign == CHAR_MINUS) - { - if (recno == 0) - { - *errorcodeptr = ERR58; - goto FAILED; - } - recno = (int)(cb->bracount + 1) - recno; - if (recno <= 0) - { - *errorcodeptr = ERR15; - goto FAILED; - } - } - else if (refsign == CHAR_PLUS) - { - if (recno == 0) - { - *errorcodeptr = ERR58; - goto FAILED; - } - recno += cb->bracount; - } + *code++ = (negate_class == should_flip_negation) ? OP_CLASS : OP_NCLASS; + if (lengthptr == NULL) /* Save time in the pre-compile phase */ + { + if (negate_class) + for (i = 0; i < 32; i++) classbits[i] = ~classbits[i]; + memcpy(code, classbits, 32); + } + code += 32 / sizeof(PCRE2_UCHAR); + break; /* End of class processing */ - if ((uint32_t)recno > cb->final_bracount) - { - *errorcodeptr = ERR15; - goto FAILED; - } - /* Come here from code above that handles a named recursion. - We insert the number of the called group after OP_RECURSE. At the - end of compiling the pattern is scanned and these numbers are - replaced by offsets within the pattern. It is done like this to avoid - problems with forward references and adjusting offsets when groups - are duplicated and moved (as discovered in previous implementations). - Note that a recursion does not have a set first character (relevant - if it is repeated, because it will then be wrapped with ONCE - brackets). */ - - HANDLE_RECURSION: - previous = code; - *code = OP_RECURSE; - PUT(code, 1, recno); - code += 1 + LINK_SIZE; - groupsetfirstcu = FALSE; - cb->had_recurse = TRUE; - } + /* ===================================================================*/ + /* Deal with (*VERB)s. */ - /* Can't determine a first byte now */ + /* Check for open captures before ACCEPT and convert it to ASSERT_ACCEPT if + in an assertion. In the first pass, just accumulate the length required; + otherwise hitting (*ACCEPT) inside many nested parentheses can cause + workspace overflow. Do not set firstcu after *ACCEPT. */ - if (firstcuflags == REQ_UNSET) firstcuflags = REQ_NONE; - continue; + case META_ACCEPT: + cb->had_accept = TRUE; + for (oc = cb->open_caps; oc != NULL; oc = oc->next) + { + if (lengthptr != NULL) + { + *lengthptr += CU2BYTES(1) + IMM2_SIZE; + } + else + { + *code++ = OP_CLOSE; + PUT2INC(code, 0, oc->number); + } + } + *code++ = (cb->assert_depth > 0)? OP_ASSERT_ACCEPT : OP_ACCEPT; + if (firstcuflags == REQ_UNSET) firstcuflags = REQ_NONE; + break; + case META_PRUNE: + case META_SKIP: + cb->had_pruneorskip = TRUE; + /* Fall through */ + case META_COMMIT: + case META_FAIL: + *code++ = verbops[(meta - META_MARK) >> 16]; + break; - /* ------------------------------------------------------------ */ - default: /* Other characters: check option setting */ - OTHER_CHAR_AFTER_QUERY: - set = unset = 0; - optset = &set; + case META_THEN: + cb->external_flags |= PCRE2_HASTHEN; + *code++ = OP_THEN; + break; - while (*ptr != CHAR_RIGHT_PARENTHESIS && *ptr != CHAR_COLON) - { - switch (*ptr++) - { - case CHAR_MINUS: optset = &unset; break; + /* Handle verbs with arguments. Arguments can be very long, especially in + 16- and 32-bit modes, and can overflow the workspace in the first pass. + However, the argument length is constrained to be small enough to fit in + one code unit. This check happens in parse_regex(). In the first pass, + instead of putting the argument into memory, we just update the length + counter and set up an empty argument. */ - case CHAR_J: /* Record that it changed in the external options */ - *optset |= PCRE2_DUPNAMES; - cb->external_flags |= PCRE2_JCHANGED; - break; + case META_THEN_ARG: + cb->external_flags |= PCRE2_HASTHEN; + goto VERB_ARG; - case CHAR_i: *optset |= PCRE2_CASELESS; break; - case CHAR_m: *optset |= PCRE2_MULTILINE; break; - case CHAR_s: *optset |= PCRE2_DOTALL; break; - case CHAR_x: *optset |= PCRE2_EXTENDED; break; - case CHAR_U: *optset |= PCRE2_UNGREEDY; break; + case META_PRUNE_ARG: + case META_SKIP_ARG: + cb->had_pruneorskip = TRUE; + /* Fall through */ + case META_MARK: + VERB_ARG: + *code++ = verbops[(meta - META_MARK) >> 16]; + /* The length is in characters. */ + verbarglen = *(++pptr); + verbculen = 0; + tempcode = code++; + for (i = 0; i < (int)verbarglen; i++) + { + meta = *(++pptr); +#ifdef SUPPORT_UNICODE + if (utf) mclength = PRIV(ord2utf)(meta, mcbuffer); else +#endif + { + mclength = 1; + mcbuffer[0] = meta; + } + if (lengthptr != NULL) *lengthptr += mclength; else + { + memcpy(code, mcbuffer, CU2BYTES(mclength)); + code += mclength; + verbculen += mclength; + } + } + + *tempcode = verbculen; /* Fill in the code unit length */ + *code++ = 0; /* Terminating zero */ + break; + + + /* ===================================================================*/ + /* Handle options change. The new setting must be passed back for use in + subsequent branches. Reset the greedy defaults and the case value for + firstcu and reqcu. */ + + case META_OPTIONS: + *optionsptr = options = *(++pptr); + greedy_default = ((options & PCRE2_UNGREEDY) != 0); + greedy_non_default = greedy_default ^ 1; + req_caseopt = ((options & PCRE2_CASELESS) != 0)? REQ_CASELESS : 0; + break; + + + /* ===================================================================*/ + /* Handle conditional subpatterns. The case of (?(Rdigits) is ambiguous + because it could be a numerical check on recursion, or a name check on a + group's being set. The pre-pass sets up META_COND_RNUMBER as a name so that + we can handle it either way. We first try for a name; if not found, process + the number. */ + + case META_COND_RNUMBER: /* (?(Rdigits) */ + case META_COND_NAME: /* (?(name) or (?'name') or ?() */ + case META_COND_RNAME: /* (?(R&name) - test for recursion */ + bravalue = OP_COND; + { + int count, index; + PCRE2_SPTR name; + named_group *ng = cb->named_groups; + uint32_t length = *(++pptr); + + GETPLUSOFFSET(offset, pptr); + name = cb->start_pattern + offset; + + /* In the first pass, the names generated in the pre-pass are available, + but the main name table has not yet been created. Scan the list of names + generated in the pre-pass in order to get a number and whether or not + this name is duplicated. If it is not duplicated, we can handle it as a + numerical group. */ - default: *errorcodeptr = ERR11; - ptr--; /* Correct the offset */ - goto FAILED; + for (i = 0; i < cb->names_found; i++, ng++) + { + if (length == ng->length && + PRIV(strncmp)(name, ng->name, length) == 0) + { + if (!ng->isdup) + { + code[1+LINK_SIZE] = (meta == META_COND_RNAME)? OP_RREF : OP_CREF; + PUT2(code, 2+LINK_SIZE, ng->number); + if (ng->number > cb->top_backref) cb->top_backref = ng->number; + skipunits = 1+IMM2_SIZE; + goto GROUP_PROCESS_NOTE_EMPTY; } + break; /* Found a duplicated name */ } + } - /* Set up the changed option bits, but don't change anything yet. */ - - newoptions = (options | set) & (~unset); + /* If the name was not found we have a bad reference, unless we are + dealing with R, which is treated as a recursion test by number. + */ - /* If the options ended with ')' this is not the start of a nested - group with option changes, so the options change at this level. They - must also be passed back for use in subsequent branches. Reset the - greedy defaults and the case value for firstcu and reqcu. */ + if (i >= cb->names_found) + { + groupnumber = 0; + if (meta == META_COND_RNUMBER) + { + for (i = 1; i < (int)length; i++) + { + groupnumber = groupnumber * 10 + name[i] - CHAR_0; + if (groupnumber > MAX_GROUP_NUMBER) + { + *errorcodeptr = ERR61; + cb->erroroffset = offset + i; + return 0; + } + } + } - if (*ptr == CHAR_RIGHT_PARENTHESIS) + if (meta != META_COND_RNUMBER || groupnumber > cb->bracount) { - *optionsptr = options = newoptions; - greedy_default = ((newoptions & PCRE2_UNGREEDY) != 0); - greedy_non_default = greedy_default ^ 1; - req_caseopt = ((newoptions & PCRE2_CASELESS) != 0)? REQ_CASELESS:0; - previous = NULL; /* This item can't be repeated */ - continue; /* It is complete */ + *errorcodeptr = ERR15; + cb->erroroffset = offset; + return 0; } - /* If the options ended with ':' we are heading into a nested group - with possible change of options. Such groups are non-capturing and are - not assertions of any kind. All we need to do is skip over the ':'; - the newoptions value is handled below. */ + /* (?Rdigits) treated as a recursion reference by number. A value of + zero (which is the result of both (?R) and (?R0)) means "any", and is + translated into RREF_ANY (which is 0xffff). */ - bravalue = OP_BRA; - ptr++; - } /* End of switch for character following (? */ - } /* End of (? handling */ + if (groupnumber == 0) groupnumber = RREF_ANY; + code[1+LINK_SIZE] = OP_RREF; + PUT2(code, 2+LINK_SIZE, groupnumber); + skipunits = 1+IMM2_SIZE; + goto GROUP_PROCESS_NOTE_EMPTY; + } - /* Opening parenthesis not followed by '*' or '?'. If PCRE2_NO_AUTO_CAPTURE - is set, all unadorned brackets become non-capturing and behave like (?:...) - brackets. */ + /* A duplicated name was found. Note that if an R name is found + (META_COND_RNUMBER), it is a reference test, not a recursion test. */ - else if ((options & PCRE2_NO_AUTO_CAPTURE) != 0) - { - bravalue = OP_BRA; - } + code[1+LINK_SIZE] = (meta == META_COND_RNAME)? OP_RREF : OP_CREF; - /* Else we have a capturing group. */ + /* We have a duplicated name. In the compile pass we have to search the + main table in order to get the index and count values. */ - else - { - NUMBERED_GROUP: - cb->bracount += 1; - PUT2(code, 1+LINK_SIZE, cb->bracount); - skipunits = IMM2_SIZE; - } + count = 0; /* Values for first pass (avoids compiler warning) */ + index = 0; + if (lengthptr == NULL && !find_dupname_details(name, length, &index, + &count, errorcodeptr, cb)) return 0; - /* Process nested bracketed regex. First check for parentheses nested too - deeply. */ + /* Add one to the opcode to change CREF/RREF into DNCREF/DNRREF and + insert appropriate data values. */ - if ((cb->parens_depth += 1) > (int)(cb->cx->parens_nest_limit)) + code[1+LINK_SIZE]++; + skipunits = 1+2*IMM2_SIZE; + PUT2(code, 2+LINK_SIZE, index); + PUT2(code, 2+LINK_SIZE+IMM2_SIZE, count); + } + goto GROUP_PROCESS_NOTE_EMPTY; + + /* The DEFINE condition is always false. It's internal groups may never + be called, so matched_char must remain false, hence the jump to + GROUP_PROCESS rather than GROUP_PROCESS_NOTE_EMPTY. */ + + case META_COND_DEFINE: + bravalue = OP_COND; + GETPLUSOFFSET(offset, pptr); + code[1+LINK_SIZE] = OP_DEFINE; + skipunits = 1; + goto GROUP_PROCESS; + + /* Conditional test of a group's being set. */ + + case META_COND_NUMBER: + bravalue = OP_COND; + GETPLUSOFFSET(offset, pptr); + groupnumber = *(++pptr); + if (groupnumber > cb->bracount) { - *errorcodeptr = ERR19; - goto FAILED; + *errorcodeptr = ERR15; + cb->erroroffset = offset; + return 0; } + if (groupnumber > cb->top_backref) cb->top_backref = groupnumber; + offset -= 2; /* Point at initial ( for too many branches error */ + code[1+LINK_SIZE] = OP_CREF; + skipunits = 1+IMM2_SIZE; + PUT2(code, 2+LINK_SIZE, groupnumber); + goto GROUP_PROCESS_NOTE_EMPTY; + + /* Test for the PCRE2 version. */ + + case META_COND_VERSION: + bravalue = OP_COND; + if (pptr[1] > 0) + code[1+LINK_SIZE] = ((PCRE2_MAJOR > pptr[2]) || + (PCRE2_MAJOR == pptr[2] && PCRE2_MINOR >= pptr[3]))? + OP_TRUE : OP_FALSE; + else + code[1+LINK_SIZE] = (PCRE2_MAJOR == pptr[2] && PCRE2_MINOR == pptr[3])? + OP_TRUE : OP_FALSE; + skipunits = 1; + pptr += 3; + goto GROUP_PROCESS_NOTE_EMPTY; + + /* The condition is an assertion, possibly preceded by a callout. */ - /* All assertions used not to be repeatable, but this was changed for Perl - compatibility. All kinds can now be repeated except for assertions that are - conditions (Perl also forbids these to be repeated). We copy code into a - non-register variable (tempcode) in order to be able to pass its address - because some compilers complain otherwise. At the start of a conditional - group whose condition is an assertion, cb->iscondassert is set. We unset it - here so as to allow assertions later in the group to be quantified. */ + case META_COND_ASSERT: + bravalue = OP_COND; + goto GROUP_PROCESS_NOTE_EMPTY; - if (bravalue >= OP_ASSERT && bravalue <= OP_ASSERTBACK_NOT && - cb->iscondassert) + + /* ===================================================================*/ + /* Handle all kinds of nested bracketed groups. The non-capturing, + non-conditional cases are here; others come to GROUP_PROCESS via goto. */ + + case META_LOOKAHEAD: + bravalue = OP_ASSERT; + cb->assert_depth += 1; + goto GROUP_PROCESS; + + /* Optimize (?!) to (*FAIL) unless it is quantified - which is a weird + thing to do, but Perl allows all assertions to be quantified, and when + they contain capturing parentheses there may be a potential use for + this feature. Not that that applies to a quantified (?!) but we allow + it for uniformity. */ + + case META_LOOKAHEADNOT: + if (pptr[1] == META_KET && + (pptr[2] < META_ASTERISK || pptr[2] > META_MINMAX_QUERY)) { - previous = NULL; - cb->iscondassert = FALSE; + *code++ = OP_FAIL; + pptr++; } else { - previous = code; + bravalue = OP_ASSERT_NOT; + cb->assert_depth += 1; + goto GROUP_PROCESS; } + break; + + case META_LOOKBEHIND: + bravalue = OP_ASSERTBACK; + cb->assert_depth += 1; + goto GROUP_PROCESS; + + case META_LOOKBEHINDNOT: + bravalue = OP_ASSERTBACK_NOT; + cb->assert_depth += 1; + goto GROUP_PROCESS; + + case META_ATOMIC: + bravalue = OP_ONCE; + goto GROUP_PROCESS_NOTE_EMPTY; + + case META_NOCAPTURE: + bravalue = OP_BRA; + /* Fall through */ + /* Process nested bracketed regex. The nesting depth is maintained for the + benefit of the stackguard function. The test for too deep nesting is now + done in parse_regex(). Assertion and DEFINE groups come to GROUP_PROCESS; + others come to GROUP_PROCESS_NOTE_EMPTY, to indicate that we need to take + note of whether or not they may match an empty string. */ + + GROUP_PROCESS_NOTE_EMPTY: + note_group_empty = TRUE; + + GROUP_PROCESS: + cb->parens_depth += 1; *code = bravalue; + pptr++; tempcode = code; - tempreqvary = cb->req_varyopt; /* Save value before bracket */ - tempbracount = cb->bracount; /* Save value before bracket */ + tempreqvary = cb->req_varyopt; /* Save value before group */ + templastcapture = cb->lastcapture; /* Save value before group */ length_prevgroup = 0; /* Initialize for pre-compile phase */ - if (!compile_regex( - newoptions, /* The complete new option state */ + if ((group_return = + compile_regex( + options, /* The option state */ &tempcode, /* Where to put code (updated) */ - &ptr, /* Input pointer (updated) */ + &pptr, /* Input pointer (updated) */ errorcodeptr, /* Where to put an error message */ - (bravalue == OP_ASSERTBACK || - bravalue == OP_ASSERTBACK_NOT), /* TRUE if back assert */ - reset_bracount, /* True if (?| group */ skipunits, /* Skip over bracket number */ - cond_depth + - ((bravalue == OP_COND)?1:0), /* Depth of condition subpatterns */ &subfirstcu, /* For possible first char */ &subfirstcuflags, &subreqcu, /* For possible last char */ @@ -7051,23 +5775,32 @@ for (;; ptr++) cb, /* Compile data block */ (lengthptr == NULL)? NULL : /* Actual compile phase */ &length_prevgroup /* Pre-compile phase */ - )) - goto FAILED; + )) == 0) + return 0; /* Error */ cb->parens_depth -= 1; - /* If this was an atomic group and there are no capturing groups within it, + /* If that was a non-conditional significant group (not an assertion, not a + DEFINE) that matches at least one character, then the current item matches + a character. Conditionals are handled below. */ + + if (note_group_empty && bravalue != OP_COND && group_return > 0) + matched_char = TRUE; + + /* If that was an atomic group and there are no capturing groups within it, generate OP_ONCE_NC instead of OP_ONCE. */ - if (bravalue == OP_ONCE && cb->bracount <= tempbracount) + if (bravalue == OP_ONCE && cb->lastcapture <= templastcapture) *code = OP_ONCE_NC; + /* If we've just compiled an assertion, pop the assert depth. */ + if (bravalue >= OP_ASSERT && bravalue <= OP_ASSERTBACK_NOT) cb->assert_depth -= 1; /* At the end of compiling, code is still pointing to the start of the group, while tempcode has been updated to point past the end of the group. - The pattern pointer (ptr) is on the bracket. + The parsed pattern pointer (pptr) is on the closing META_KET. If this is a conditional bracket, check that there are no more than two branches in the group, or just one if it's a DEFINE group. We do this @@ -7093,38 +5826,32 @@ for (;; ptr++) { if (condcount > 1) { + cb->erroroffset = offset; *errorcodeptr = ERR54; - goto FAILED; + return 0; } code[LINK_SIZE+1] = OP_FALSE; - bravalue = OP_DEFINE; /* Just a flag to suppress char handling below */ + bravalue = OP_DEFINE; /* A flag to suppress char handling below */ } /* A "normal" conditional group. If there is just one branch, we must not make use of its firstcu or reqcu, because this is equivalent to an - empty second branch. */ + empty second branch. Also, it may match an empty string. If there are two + branches, this item must match a character if the group must. */ else { if (condcount > 2) { + cb->erroroffset = offset; *errorcodeptr = ERR27; - goto FAILED; + return 0; } if (condcount == 1) subfirstcuflags = subreqcuflags = REQ_NONE; + else if (group_return > 0) matched_char = TRUE; } } - /* At the end of a group, it's an error if we hit end of pattern or - any non-closing parenthesis. This check also happens in the pre-scan, - so should not trigger here, but leave this code as an insurance. */ - - if (*ptr != CHAR_RIGHT_PARENTHESIS) - { - *errorcodeptr = ERR14; - goto FAILED; - } - /* In the pre-compile phase, update the length by the length of the group, less the brackets at either end. Then reduce the compiled code to just a set of non-capturing brackets so that it doesn't use much memory if it is @@ -7135,7 +5862,7 @@ for (;; ptr++) if (OFLOW_MAX - *lengthptr < length_prevgroup - 2 - 2*LINK_SIZE) { *errorcodeptr = ERR20; - goto FAILED; + return 0; } *lengthptr += length_prevgroup - 2 - 2*LINK_SIZE; code++; /* This already contains bravalue */ @@ -7154,12 +5881,12 @@ for (;; ptr++) if (bravalue == OP_DEFINE) break; - /* Handle updating of the required and first characters for other types of + /* Handle updating of the required and first code units for other types of group. Update for normal brackets of all kinds, and conditions with two branches (see code above). If the bracket is followed by a quantifier with zero repeat, we have to back off. Hence the definition of zeroreqcu and - zerofirstcu outside the main loop so that they can be accessed for the - back off. */ + zerofirstcu outside the main loop so that they can be accessed for the back + off. */ zeroreqcu = reqcu; zeroreqcuflags = reqcuflags; @@ -7167,7 +5894,7 @@ for (;; ptr++) zerofirstcuflags = firstcuflags; groupsetfirstcu = FALSE; - if (bravalue >= OP_ONCE) + if (bravalue >= OP_ONCE) /* Not an assertion */ { /* If we have not yet set a firstcu in this branch, take it from the subpattern, remembering that it was set here so that a repeat of more @@ -7197,8 +5924,8 @@ for (;; ptr++) subreqcuflags = subfirstcuflags | tempreqvary; } - /* If the subpattern set a required byte (or set a first byte that isn't - really the first byte - see above), set it. */ + /* If the subpattern set a required code unit (or set a first code unit + that isn't really the first code unit - see above), set it. */ if (subreqcuflags >= 0) { @@ -7207,1088 +5934,2808 @@ for (;; ptr++) } } - /* For a forward assertion, we take the reqcu, if set. This can be - helpful if the pattern that follows the assertion doesn't set a different - char. For example, it's useful for /(?=abcde).+/. We can't set firstcu - for an assertion, however because it leads to incorrect effect for patterns - such as /(?=a)a.+/ when the "real" "a" would then become a reqcu instead - of a firstcu. This is overcome by a scan at the end if there's no - firstcu, looking for an asserted first char. */ - - else if (bravalue == OP_ASSERT && subreqcuflags >= 0) + /* For a forward assertion, we take the reqcu, if set, provided that the + group has also set a firstcu. This can be helpful if the pattern that + follows the assertion doesn't set a different char. For example, it's + useful for /(?=abcde).+/. We can't set firstcu for an assertion, however + because it leads to incorrect effect for patterns such as /(?=a)a.+/ when + the "real" "a" would then become a reqcu instead of a firstcu. This is + overcome by a scan at the end if there's no firstcu, looking for an + asserted first char. A similar effect for patterns like /(?=.*X)X$/ means + we must only take the reqcu when the group also set a firstcu. Otherwise, + in that example, 'X' ends up set for both. */ + + else if (bravalue == OP_ASSERT && subreqcuflags >= 0 && + subfirstcuflags >= 0) { reqcu = subreqcu; reqcuflags = subreqcuflags; } - break; /* End of processing '(' */ - - /* ===================================================================*/ - /* Handle metasequences introduced by \. For ones like \d, the ESC_ values - are arranged to be the negation of the corresponding OP_values in the - default case when PCRE2_UCP is not set. For the back references, the values - are negative the reference number. Only back references and those types - that consume a character may be repeated. We can test for values between - ESC_b and ESC_Z for the latter; this may have to change if any new ones are - ever created. + break; /* End of nested group handling */ - Note: \Q and \E are handled at the start of the character-processing loop, - not here. */ - case CHAR_BACKSLASH: - tempptr = ptr; - escape = PRIV(check_escape)(&ptr, cb->end_pattern, &ec, errorcodeptr, - options, FALSE, cb); - if (*errorcodeptr != 0) goto FAILED; + /* ===================================================================*/ + /* Handle named backreferences and recursions. */ - if (escape == 0) /* The escape coded a single character */ - c = ec; - else + case META_BACKREF_BYNAME: + case META_RECURSE_BYNAME: { - /* For metasequences that actually match a character, we disable the - setting of a first character if it hasn't already been set. */ - - if (firstcuflags == REQ_UNSET && escape > ESC_b && escape < ESC_Z) - firstcuflags = REQ_NONE; - - /* Set values to reset to if this is followed by a zero repeat. */ + int count, index; + PCRE2_SPTR name; + BOOL is_dupname = FALSE; + named_group *ng = cb->named_groups; + uint32_t length = *(++pptr); - zerofirstcu = firstcu; - zerofirstcuflags = firstcuflags; - zeroreqcu = reqcu; - zeroreqcuflags = reqcuflags; + GETPLUSOFFSET(offset, pptr); + name = cb->start_pattern + offset; - /* \g or \g'name' is a subroutine call by name and \g or \g'n' - is a subroutine call by number (Oniguruma syntax). In fact, the value - ESC_g is returned only for these cases. So we don't need to check for < - or ' if the value is ESC_g. For the Perl syntax \g{n} the value is - -n, and for the Perl syntax \g{name} the result is ESC_k (as - that is a synonym for a named back reference). */ + /* In the first pass, the names generated in the pre-pass are available, + but the main name table has not yet been created. Scan the list of names + generated in the pre-pass in order to get a number and whether or not + this name is duplicated. */ - if (escape == ESC_g) + groupnumber = 0; + for (i = 0; i < cb->names_found; i++, ng++) { - PCRE2_SPTR p; - uint32_t cf; + if (length == ng->length && + PRIV(strncmp)(name, ng->name, length) == 0) + { + is_dupname = ng->isdup; + groupnumber = ng->number; - terminator = (*(++ptr) == CHAR_LESS_THAN_SIGN)? - CHAR_GREATER_THAN_SIGN : CHAR_APOSTROPHE; + /* For a recursion, that's all that is needed. We can now go to + the code above that handles numerical recursion, applying it to + the first group with the given name. */ - /* These two statements stop the compiler for warning about possibly - unset variables caused by the jump to HANDLE_NUMERICAL_RECURSION. In - fact, because we do the check for a number below, the paths that - would actually be in error are never taken. */ + if (meta == META_RECURSE_BYNAME) + { + meta_arg = groupnumber; + goto HANDLE_NUMERICAL_RECURSION; + } - skipunits = 0; - reset_bracount = FALSE; + /* For a back reference, update the back reference map and the + maximum back reference. Then, for each group, we must check to + see if it is recursive, that is, it is inside the group that it + references. A flag is set so that the group can be made atomic. + */ - /* If it's not a signed or unsigned number, treat it as a name. */ + cb->backref_map |= (groupnumber < 32)? (1u << groupnumber) : 1; + if (groupnumber > cb->top_backref) + cb->top_backref = groupnumber; - cf = ptr[1]; - if (cf != CHAR_PLUS && cf != CHAR_MINUS && !IS_DIGIT(cf)) - { - is_recurse = TRUE; - goto NAMED_REF_OR_RECURSE; + for (oc = cb->open_caps; oc != NULL; oc = oc->next) + { + if (oc->number == groupnumber) + { + oc->flag = TRUE; + break; + } + } } + } - /* Signed or unsigned number (cf = ptr[1]) is known to be plus or minus - or a digit. */ + /* If the name was not found we have a bad reference. */ - p = ptr + 2; - while (IS_DIGIT(*p)) p++; - if (*p != (PCRE2_UCHAR)terminator) - { - *errorcodeptr = ERR57; - goto FAILED; - } - ptr++; - goto HANDLE_NUMERICAL_RECURSION; + if (groupnumber == 0) + { + *errorcodeptr = ERR15; + cb->erroroffset = offset; + return 0; } - /* \k or \k'name' is a back reference by name (Perl syntax). - We also support \k{name} (.NET syntax). */ + /* If a back reference name is not duplicated, we can handle it as + a numerical reference. */ - if (escape == ESC_k) + if (!is_dupname) { - if ((ptr[1] != CHAR_LESS_THAN_SIGN && - ptr[1] != CHAR_APOSTROPHE && ptr[1] != CHAR_LEFT_CURLY_BRACKET)) - { - *errorcodeptr = ERR69; - goto FAILED; - } - is_recurse = FALSE; - terminator = (*(++ptr) == CHAR_LESS_THAN_SIGN)? - CHAR_GREATER_THAN_SIGN : (*ptr == CHAR_APOSTROPHE)? - CHAR_APOSTROPHE : CHAR_RIGHT_CURLY_BRACKET; - goto NAMED_REF_OR_RECURSE; + meta_arg = groupnumber; + goto HANDLE_SINGLE_REFERENCE; } - /* Back references are handled specially; must disable firstcu if - not set to cope with cases like (?=(\w+))\1: which would otherwise set - ':' later. */ + /* If a back reference name is duplicated, we generate a different + opcode to a numerical back reference. In the second pass we must + search for the index and count in the final name table. */ - if (escape < 0) - { - open_capitem *oc; - recno = -escape; + count = 0; /* Values for first pass (avoids compiler warning) */ + index = 0; + if (lengthptr == NULL && !find_dupname_details(name, length, &index, + &count, errorcodeptr, cb)) return 0; - /* Come here from named backref handling when the reference is to a - single group (i.e. not to a duplicated name). */ + if (firstcuflags == REQ_UNSET) firstcuflags = REQ_NONE; + *code++ = ((options & PCRE2_CASELESS) != 0)? OP_DNREFI : OP_DNREF; + PUT2INC(code, 0, index); + PUT2INC(code, 0, count); + } + break; - HANDLE_REFERENCE: - if (recno > (int)cb->final_bracount) - { - *errorcodeptr = ERR15; - goto FAILED; - } - if (firstcuflags == REQ_UNSET) firstcuflags = REQ_NONE; - previous = code; - *code++ = ((options & PCRE2_CASELESS) != 0)? OP_REFI : OP_REF; - PUT2INC(code, 0, recno); - cb->backref_map |= (recno < 32)? (1u << recno) : 1; - if ((uint32_t)recno > cb->top_backref) cb->top_backref = recno; - - /* Check to see if this back reference is recursive, that it, it - is inside the group that it references. A flag is set so that the - group can be made atomic. */ - - for (oc = cb->open_caps; oc != NULL; oc = oc->next) - { - if (oc->number == recno) - { - oc->flag = TRUE; - break; - } - } - } - /* So are Unicode property matches, if supported. */ + /* ===================================================================*/ + /* Handle a numerical callout. */ + + case META_CALLOUT_NUMBER: + code[0] = OP_CALLOUT; + PUT(code, 1, pptr[1]); /* Offset to next pattern item */ + PUT(code, 1 + LINK_SIZE, pptr[2]); /* Length of next pattern item */ + code[1 + 2*LINK_SIZE] = pptr[3]; + pptr += 3; + code += PRIV(OP_lengths)[OP_CALLOUT]; + break; -#ifdef SUPPORT_UNICODE - else if (escape == ESC_P || escape == ESC_p) - { - BOOL negated; - unsigned int ptype = 0, pdata = 0; - if (!get_ucp(&ptr, &negated, &ptype, &pdata, errorcodeptr, cb)) - goto FAILED; - previous = code; - *code++ = ((escape == ESC_p) != negated)? OP_PROP : OP_NOTPROP; - *code++ = ptype; - *code++ = pdata; - } -#else - - /* If Unicode properties are not supported, \X, \P, and \p are not - allowed. */ - - else if (escape == ESC_X || escape == ESC_P || escape == ESC_p) - { - *errorcodeptr = ERR45; - goto FAILED; - } -#endif - /* The use of \C can be locked out. */ + /* ===================================================================*/ + /* Handle a callout with a string argument. In the pre-pass we just compute + the length without generating anything. The length in pptr[3] includes both + delimiters; in the actual compile only the first one is copied, but a + terminating zero is added. Any doubled delimiters within the string make + this an overestimate, but it is not worth bothering about. */ -#ifdef NEVER_BACKSLASH_C - else if (escape == ESC_C) - { - *errorcodeptr = ERR85; - goto FAILED; - } -#else - else if (escape == ESC_C && (options & PCRE2_NEVER_BACKSLASH_C) != 0) - { - *errorcodeptr = ERR83; - goto FAILED; - } -#endif + case META_CALLOUT_STRING: + if (lengthptr != NULL) + { + *lengthptr += pptr[3] + (1 + 4*LINK_SIZE); + pptr += 3; + SKIPOFFSET(pptr); + } - /* For the rest (including \X when Unicode properties are supported), we - can obtain the OP value by negating the escape value in the default - situation when PCRE2_UCP is not set. When it *is* set, we substitute - Unicode property tests. Note that \b and \B do a one-character - lookbehind, and \A also behaves as if it does. */ + /* In the real compile we can copy the string. The starting delimiter is + included so that the client can discover it if they want. We also pass the + start offset to help a script language give better error messages. */ - else + else + { + PCRE2_SPTR pp; + uint32_t delimiter; + uint32_t length = pptr[3]; + PCRE2_UCHAR *callout_string = code + (1 + 4*LINK_SIZE); + + code[0] = OP_CALLOUT_STR; + PUT(code, 1, pptr[1]); /* Offset to next pattern item */ + PUT(code, 1 + LINK_SIZE, pptr[2]); /* Length of next pattern item */ + + pptr += 3; + GETPLUSOFFSET(offset, pptr); /* Offset to string in pattern */ + pp = cb->start_pattern + offset; + delimiter = *callout_string++ = *pp++; + if (delimiter == CHAR_LEFT_CURLY_BRACKET) + delimiter = CHAR_RIGHT_CURLY_BRACKET; + PUT(code, 1 + 3*LINK_SIZE, (int)(offset + 1)); /* One after delimiter */ + + /* The syntax of the pattern was checked in the parsing scan. The length + includes both delimiters, but we have passed the opening one just above, + so we reduce length before testing it. The test is for > 1 because we do + not want to copy the final delimiter. This also ensures that pp[1] is + accessible. */ + + while (--length > 1) { - if (escape == ESC_C) cb->external_flags |= PCRE2_HASBKC; /* Record */ - if ((escape == ESC_b || escape == ESC_B || escape == ESC_A) && - cb->max_lookbehind == 0) - cb->max_lookbehind = 1; -#ifdef SUPPORT_UNICODE - if (escape >= ESC_DU && escape <= ESC_wu) - { - cb->nestptr[1] = cb->nestptr[0]; /* Back up if at 2nd level */ - cb->nestptr[0] = ptr + 1; /* Where to resume */ - ptr = substitutes[escape - ESC_DU] - 1; /* Just before substitute */ - } - else -#endif - /* In non-UTF mode, and for both 32-bit modes, we turn \C into - OP_ALLANY instead of OP_ANYBYTE so that it works in DFA mode and in - lookbehinds. */ - + if (*pp == delimiter && pp[1] == delimiter) { - previous = (escape > ESC_b && escape < ESC_Z)? code : NULL; -#if PCRE2_CODE_UNIT_WIDTH == 32 - *code++ = (escape == ESC_C)? OP_ALLANY : escape; -#else - *code++ = (!utf && escape == ESC_C)? OP_ALLANY : escape; -#endif + *callout_string++ = delimiter; + pp += 2; + length--; } + else *callout_string++ = *pp++; } - continue; - } + *callout_string++ = CHAR_NULL; - /* We have a data character whose value is in c. In UTF-8 mode it may have - a value > 127. We set its representation in the length/buffer, and then - handle it as a data character. */ + /* Set the length of the entire item, the advance to its end. */ - mclength = PUTCHAR(c, mcbuffer); - goto ONE_CHAR; + PUT(code, 1 + 2*LINK_SIZE, (int)(callout_string - code)); + code = callout_string; + } + break; /* ===================================================================*/ - /* Handle a literal character. It is guaranteed not to be whitespace or # - when the extended flag is set. If we are in a UTF mode, it may be a - multi-unit literal character. */ + /* Handle repetition. The different types are all sorted out in the parsing + pass. */ + + case META_MINMAX_PLUS: + case META_MINMAX_QUERY: + case META_MINMAX: + repeat_min = *(++pptr); + repeat_max = *(++pptr); + goto REPEAT; - default: - NORMAL_CHAR: - mclength = 1; - mcbuffer[0] = c; + case META_ASTERISK: + case META_ASTERISK_PLUS: + case META_ASTERISK_QUERY: + repeat_min = 0; + repeat_max = REPEAT_UNLIMITED; + goto REPEAT; -#ifdef SUPPORT_UNICODE - if (utf && HAS_EXTRALEN(c)) - ACROSSCHAR(TRUE, ptr[1], mcbuffer[mclength++] = *(++ptr)); -#endif + case META_PLUS: + case META_PLUS_PLUS: + case META_PLUS_QUERY: + repeat_min = 1; + repeat_max = REPEAT_UNLIMITED; + goto REPEAT; - /* At this point we have the character's bytes in mcbuffer, and the length - in mclength. When not in UTF mode, the length is always 1. */ + case META_QUERY: + case META_QUERY_PLUS: + case META_QUERY_QUERY: + repeat_min = 0; + repeat_max = 1; - ONE_CHAR: - previous = code; + REPEAT: + if (previous_matched_char && repeat_min > 0) matched_char = TRUE; - /* For caseless UTF mode, check whether this character has more than one - other case. If so, generate a special OP_PROP item instead of OP_CHARI. */ + /* Remember whether this is a variable length repeat, and default to + single-char opcodes. */ -#ifdef SUPPORT_UNICODE - if (utf && (options & PCRE2_CASELESS) != 0) - { - GETCHAR(c, mcbuffer); - if ((c = UCD_CASESET(c)) != 0) - { - *code++ = OP_PROP; - *code++ = PT_CLIST; - *code++ = c; - if (firstcuflags == REQ_UNSET) - firstcuflags = zerofirstcuflags = REQ_NONE; - break; - } - } -#endif + reqvary = (repeat_min == repeat_max)? 0 : REQ_VARY; + op_type = 0; - /* Caseful matches, or not one of the multicase characters. */ + /* If the repeat is {1} we can ignore it. */ - *code++ = ((options & PCRE2_CASELESS) != 0)? OP_CHARI : OP_CHAR; - for (c = 0; c < mclength; c++) *code++ = mcbuffer[c]; + if (repeat_max == 1 && repeat_min == 1) goto END_REPEAT; - /* Remember if \r or \n were seen */ + /* Adjust first and required code units for a zero repeat. */ - if (mcbuffer[0] == CHAR_CR || mcbuffer[0] == CHAR_NL) - cb->external_flags |= PCRE2_HASCRORLF; + if (repeat_min == 0) + { + firstcu = zerofirstcu; + firstcuflags = zerofirstcuflags; + reqcu = zeroreqcu; + reqcuflags = zeroreqcuflags; + } - /* Set the first and required bytes appropriately. If no previous first - byte, set it from this character, but revert to none on a zero repeat. - Otherwise, leave the firstcu value alone, and don't change it on a zero - repeat. */ + /* Note the greediness and possessiveness. */ - if (firstcuflags == REQ_UNSET) + switch (meta) { - zerofirstcuflags = REQ_NONE; - zeroreqcu = reqcu; - zeroreqcuflags = reqcuflags; - - /* If the character is more than one byte long, we can set firstcu - only if it is not to be matched caselessly. */ + case META_MINMAX_PLUS: + case META_ASTERISK_PLUS: + case META_PLUS_PLUS: + case META_QUERY_PLUS: + repeat_type = 0; /* Force greedy */ + possessive_quantifier = TRUE; + break; - if (mclength == 1 || req_caseopt == 0) - { - firstcu = mcbuffer[0] | req_caseopt; - firstcu = mcbuffer[0]; - firstcuflags = req_caseopt; + case META_MINMAX_QUERY: + case META_ASTERISK_QUERY: + case META_PLUS_QUERY: + case META_QUERY_QUERY: + repeat_type = greedy_non_default; + possessive_quantifier = FALSE; + break; - if (mclength != 1) - { - reqcu = code[-1]; - reqcuflags = cb->req_varyopt; - } - } - else firstcuflags = reqcuflags = REQ_NONE; + default: + repeat_type = greedy_default; + possessive_quantifier = FALSE; + break; } - /* firstcu was previously set; we can set reqcu only if the length is - 1 or the matching is caseful. */ + /* Save start of previous item, in case we have to move it up in order to + insert something before it, and remember what it was. */ - else + tempcode = previous; + op_previous = *previous; + + /* If previous was a recursion call, wrap it in atomic brackets so that + previous becomes the atomic group. All recursions were so wrapped in the + past, but it no longer happens for non-repeated recursions. In fact, the + repeated ones could be re-implemented independently so as not to need this, + but for the moment we rely on the code for repeating groups. */ + + if (op_previous == OP_RECURSE) { - zerofirstcu = firstcu; - zerofirstcuflags = firstcuflags; - zeroreqcu = reqcu; - zeroreqcuflags = reqcuflags; - if (mclength == 1 || req_caseopt == 0) - { - reqcu = code[-1]; - reqcuflags = req_caseopt | cb->req_varyopt; - } + memmove(previous + 1 + LINK_SIZE, previous, CU2BYTES(1 + LINK_SIZE)); + op_previous = *previous = OP_ONCE; + PUT(previous, 1, 2 + 2*LINK_SIZE); + previous[2 + 2*LINK_SIZE] = OP_KET; + PUT(previous, 3 + 2*LINK_SIZE, 2 + 2*LINK_SIZE); + code += 2 + 2 * LINK_SIZE; + length_prevgroup = 3 + 3*LINK_SIZE; + group_return = -1; /* Set "may match empty string" */ } - break; /* End of literal character handling */ - } - } /* end of big loop */ - -/* Control never reaches here by falling through, only by a goto for all the -error states. Pass back the position in the pattern so that it can be displayed -to the user for diagnosing the error. */ + /* Now handle repetition for the different types of item. */ -FAILED: -*ptrptr = ptr; -return FALSE; -} + switch (op_previous) + { + /* If previous was a character or negated character match, abolish the + item and generate a repeat item instead. If a char item has a minimum of + more than one, ensure that it is set in reqcu - it might not be if a + sequence such as x{3} is the first thing in a branch because the x will + have gone into firstcu instead. */ + case OP_CHAR: + case OP_CHARI: + case OP_NOT: + case OP_NOTI: + op_type = chartypeoffset[op_previous - OP_CHAR]; + /* Deal with UTF characters that take up more than one code unit. */ -/************************************************* -* Compile regex: a sequence of alternatives * -*************************************************/ +#ifdef MAYBE_UTF_MULTI + if (utf && NOT_FIRSTCU(code[-1])) + { + PCRE2_UCHAR *lastchar = code - 1; + BACKCHAR(lastchar); + mclength = (uint32_t)(code - lastchar); /* Length of UTF character */ + memcpy(mcbuffer, lastchar, CU2BYTES(mclength)); /* Save the char */ + } + else +#endif /* MAYBE_UTF_MULTI */ -/* On entry, ptr is pointing past the bracket character, but on return it -points to the closing bracket, or vertical bar, or end of string. The code -variable is pointing at the byte into which the BRA operator has been stored. -This function is used during the pre-compile phase when we are trying to find -out the amount of memory needed, as well as during the real compile phase. The -value of lengthptr distinguishes the two phases. + /* Handle the case of a single code unit - either with no UTF support, or + with UTF disabled, or for a single-code-unit UTF character. */ + { + mcbuffer[0] = code[-1]; + mclength = 1; + if (op_previous <= OP_CHARI && repeat_min > 1) + { + reqcu = mcbuffer[0]; + reqcuflags = req_caseopt | cb->req_varyopt; + } + } + goto OUTPUT_SINGLE_REPEAT; /* Code shared with single character types */ -Arguments: - options option bits, including any changes for this subpattern - codeptr -> the address of the current code pointer - ptrptr -> the address of the current pattern pointer - errorcodeptr -> pointer to error code variable - lookbehind TRUE if this is a lookbehind assertion - reset_bracount TRUE to reset the count for each branch - skipunits skip this many code units at start (for brackets and OP_COND) - cond_depth depth of nesting for conditional subpatterns - firstcuptr place to put the first required code unit - firstcuflagsptr place to put the first code unit flags, or a negative number - reqcuptr place to put the last required code unit - reqcuflagsptr place to put the last required code unit flags, or a negative number - bcptr pointer to the chain of currently open branches - cb points to the data block with tables pointers etc. - lengthptr NULL during the real compile phase - points to length accumulator during pre-compile phase + /* If previous was a character class or a back reference, we put the + repeat stuff after it, but just skip the item if the repeat was {0,0}. */ -Returns: TRUE on success -*/ +#ifdef SUPPORT_WIDE_CHARS + case OP_XCLASS: +#endif + case OP_CLASS: + case OP_NCLASS: + case OP_REF: + case OP_REFI: + case OP_DNREF: + case OP_DNREFI: -static BOOL -compile_regex(uint32_t options, PCRE2_UCHAR **codeptr, PCRE2_SPTR *ptrptr, - int *errorcodeptr, BOOL lookbehind, BOOL reset_bracount, uint32_t skipunits, - int cond_depth, uint32_t *firstcuptr, int32_t *firstcuflagsptr, - uint32_t *reqcuptr, int32_t *reqcuflagsptr, branch_chain *bcptr, - compile_block *cb, size_t *lengthptr) -{ -PCRE2_SPTR ptr = *ptrptr; -PCRE2_UCHAR *code = *codeptr; -PCRE2_UCHAR *last_branch = code; -PCRE2_UCHAR *start_bracket = code; -PCRE2_UCHAR *reverse_count = NULL; -open_capitem capitem; -int capnumber = 0; -uint32_t firstcu, reqcu; -int32_t firstcuflags, reqcuflags; -uint32_t branchfirstcu, branchreqcu; -int32_t branchfirstcuflags, branchreqcuflags; -size_t length; -unsigned int orig_bracount; -unsigned int max_bracount; -branch_chain bc; + if (repeat_max == 0) + { + code = previous; + goto END_REPEAT; + } -/* If set, call the external function that checks for stack availability. */ + if (repeat_min == 0 && repeat_max == REPEAT_UNLIMITED) + *code++ = OP_CRSTAR + repeat_type; + else if (repeat_min == 1 && repeat_max == REPEAT_UNLIMITED) + *code++ = OP_CRPLUS + repeat_type; + else if (repeat_min == 0 && repeat_max == 1) + *code++ = OP_CRQUERY + repeat_type; + else + { + *code++ = OP_CRRANGE + repeat_type; + PUT2INC(code, 0, repeat_min); + if (repeat_max == REPEAT_UNLIMITED) repeat_max = 0; /* 2-byte encoding for max */ + PUT2INC(code, 0, repeat_max); + } + break; -if (cb->cx->stack_guard != NULL && - cb->cx->stack_guard(cb->parens_depth, cb->cx->stack_guard_data)) - { - *errorcodeptr= ERR33; - return FALSE; - } + /* If previous is OP_FAIL, it was generated by an empty class [] + (PCRE2_ALLOW_EMPTY_CLASS is set). The other ways in which OP_FAIL can be + generated, that is by (*FAIL) or (?!), disallow a quantifier at parse + time. We can just ignore this repeat. */ + + case OP_FAIL: + goto END_REPEAT; + + /* If previous was a bracket group, we may have to replicate it in + certain cases. Note that at this point we can encounter only the "basic" + bracket opcodes such as BRA and CBRA, as this is the place where they get + converted into the more special varieties such as BRAPOS and SBRA. + Originally, PCRE did not allow repetition of assertions, but now it does, + for Perl compatibility. */ + + case OP_ASSERT: + case OP_ASSERT_NOT: + case OP_ASSERTBACK: + case OP_ASSERTBACK_NOT: + case OP_ONCE: + case OP_ONCE_NC: + case OP_BRA: + case OP_CBRA: + case OP_COND: + { + int len = (int)(code - previous); + PCRE2_UCHAR *bralink = NULL; + PCRE2_UCHAR *brazeroptr = NULL; -/* Miscellaneous initialization */ + /* Repeating a DEFINE group (or any group where the condition is always + FALSE and there is only one branch) is pointless, but Perl allows the + syntax, so we just ignore the repeat. */ -bc.outer = bcptr; -bc.current_branch = code; + if (op_previous == OP_COND && previous[LINK_SIZE+1] == OP_FALSE && + previous[GET(previous, 1)] != OP_ALT) + goto END_REPEAT; -firstcu = reqcu = 0; -firstcuflags = reqcuflags = REQ_UNSET; + /* There is no sense in actually repeating assertions. The only potential + use of repetition is in cases when the assertion is optional. Therefore, + if the minimum is greater than zero, just ignore the repeat. If the + maximum is not zero or one, set it to 1. */ -/* Accumulate the length for use in the pre-compile phase. Start with the -length of the BRA and KET and any extra code units that are required at the -beginning. We accumulate in a local variable to save frequent testing of -lengthptr for NULL. We cannot do this by looking at the value of 'code' at the -start and end of each alternative, because compiled items are discarded during -the pre-compile phase so that the work space is not exceeded. */ + if (op_previous < OP_ONCE) /* Assertion */ + { + if (repeat_min > 0) goto END_REPEAT; + if (repeat_max > 1) repeat_max = 1; + } -length = 2 + 2*LINK_SIZE + skipunits; + /* The case of a zero minimum is special because of the need to stick + OP_BRAZERO in front of it, and because the group appears once in the + data, whereas in other cases it appears the minimum number of times. For + this reason, it is simplest to treat this case separately, as otherwise + the code gets far too messy. There are several special subcases when the + minimum is zero. */ -/* WARNING: If the above line is changed for any reason, you must also change -the code that abstracts option settings at the start of the pattern and makes -them global. It tests the value of length for (2 + 2*LINK_SIZE) in the -pre-compile phase to find out whether or not anything has yet been compiled. + if (repeat_min == 0) + { + /* If the maximum is also zero, we used to just omit the group from + the output altogether, like this: -If this is a capturing subpattern, add to the chain of open capturing items -so that we can detect them if (*ACCEPT) is encountered. This is also used to -detect groups that contain recursive back references to themselves. Note that -only OP_CBRA need be tested here; changing this opcode to one of its variants, -e.g. OP_SCBRAPOS, happens later, after the group has been compiled. */ + ** if (repeat_max == 0) + ** { + ** code = previous; + ** goto END_REPEAT; + ** } -if (*code == OP_CBRA) - { - capnumber = GET2(code, 1 + LINK_SIZE); - capitem.number = capnumber; - capitem.next = cb->open_caps; - capitem.flag = FALSE; - cb->open_caps = &capitem; - } + However, that fails when a group or a subgroup within it is + referenced as a subroutine from elsewhere in the pattern, so now we + stick in OP_SKIPZERO in front of it so that it is skipped on + execution. As we don't have a list of which groups are referenced, we + cannot do this selectively. -/* Offset is set zero to mark that this bracket is still open */ + If the maximum is 1 or unlimited, we just have to stick in the + BRAZERO and do no more at this point. */ -PUT(code, 1, 0); -code += 1 + LINK_SIZE + skipunits; + if (repeat_max <= 1 || repeat_max == REPEAT_UNLIMITED) + { + memmove(previous + 1, previous, CU2BYTES(len)); + code++; + if (repeat_max == 0) + { + *previous++ = OP_SKIPZERO; + goto END_REPEAT; + } + brazeroptr = previous; /* Save for possessive optimizing */ + *previous++ = OP_BRAZERO + repeat_type; + } -/* Loop for each alternative branch */ + /* If the maximum is greater than 1 and limited, we have to replicate + in a nested fashion, sticking OP_BRAZERO before each set of brackets. + The first one has to be handled carefully because it's the original + copy, which has to be moved up. The remainder can be handled by code + that is common with the non-zero minimum case below. We have to + adjust the value or repeat_max, since one less copy is required. */ -orig_bracount = max_bracount = cb->bracount; + else + { + int linkoffset; + memmove(previous + 2 + LINK_SIZE, previous, CU2BYTES(len)); + code += 2 + LINK_SIZE; + *previous++ = OP_BRAZERO + repeat_type; + *previous++ = OP_BRA; + + /* We chain together the bracket link offset fields that have to be + filled in later when the ends of the brackets are reached. */ + + linkoffset = (bralink == NULL)? 0 : (int)(previous - bralink); + bralink = previous; + PUTINC(previous, 0, linkoffset); + } -for (;;) - { - /* For a (?| group, reset the capturing bracket count so that each branch - uses the same numbers. */ + if (repeat_max != REPEAT_UNLIMITED) repeat_max--; + } - if (reset_bracount) cb->bracount = orig_bracount; + /* If the minimum is greater than zero, replicate the group as many + times as necessary, and adjust the maximum to the number of subsequent + copies that we need. */ - /* Set up dummy OP_REVERSE if lookbehind assertion */ + else + { + if (repeat_min > 1) + { + /* In the pre-compile phase, we don't actually do the replication. + We just adjust the length as if we had. Do some paranoid checks for + potential integer overflow. The INT64_OR_DOUBLE type is a 64-bit + integer type when available, otherwise double. */ - if (lookbehind) - { - *code++ = OP_REVERSE; - reverse_count = code; - PUTINC(code, 0, 0); - length += 1 + LINK_SIZE; - } + if (lengthptr != NULL) + { + PCRE2_SIZE delta = (repeat_min - 1)*length_prevgroup; + if ((INT64_OR_DOUBLE)(repeat_min - 1)* + (INT64_OR_DOUBLE)length_prevgroup > + (INT64_OR_DOUBLE)INT_MAX || + OFLOW_MAX - *lengthptr < delta) + { + *errorcodeptr = ERR20; + return 0; + } + *lengthptr += delta; + } - /* Now compile the branch; in the pre-compile phase its length gets added - into the length. */ + /* This is compiling for real. If there is a set first code unit + for the group, and we have not yet set a "required code unit", set + it. */ - if (!compile_branch(&options, &code, &ptr, errorcodeptr, &branchfirstcu, - &branchfirstcuflags, &branchreqcu, &branchreqcuflags, &bc, - cond_depth, cb, (lengthptr == NULL)? NULL : &length)) - { - *ptrptr = ptr; - return FALSE; - } + else + { + if (groupsetfirstcu && reqcuflags < 0) + { + reqcu = firstcu; + reqcuflags = firstcuflags; + } + for (i = 1; (uint32_t)i < repeat_min; i++) + { + memcpy(code, previous, CU2BYTES(len)); + code += len; + } + } + } - /* Keep the highest bracket count in case (?| was used and some branch - has fewer than the rest. */ + if (repeat_max != REPEAT_UNLIMITED) repeat_max -= repeat_min; + } - if (cb->bracount > max_bracount) max_bracount = cb->bracount; + /* This code is common to both the zero and non-zero minimum cases. If + the maximum is limited, it replicates the group in a nested fashion, + remembering the bracket starts on a stack. In the case of a zero + minimum, the first one was set up above. In all cases the repeat_max + now specifies the number of additional copies needed. Again, we must + remember to replicate entries on the forward reference list. */ - /* In the real compile phase, there is some post-processing to be done. */ + if (repeat_max != REPEAT_UNLIMITED) + { + /* In the pre-compile phase, we don't actually do the replication. We + just adjust the length as if we had. For each repetition we must add + 1 to the length for BRAZERO and for all but the last repetition we + must add 2 + 2*LINKSIZE to allow for the nesting that occurs. Do some + paranoid checks to avoid integer overflow. The INT64_OR_DOUBLE type + is a 64-bit integer type when available, otherwise double. */ - if (lengthptr == NULL) - { - /* If this is the first branch, the firstcu and reqcu values for the - branch become the values for the regex. */ + if (lengthptr != NULL && repeat_max > 0) + { + PCRE2_SIZE delta = repeat_max*(length_prevgroup + 1 + 2 + 2*LINK_SIZE) - + 2 - 2*LINK_SIZE; /* Last one doesn't nest */ + if ((INT64_OR_DOUBLE)repeat_max * + (INT64_OR_DOUBLE)(length_prevgroup + 1 + 2 + 2*LINK_SIZE) + > (INT64_OR_DOUBLE)INT_MAX || + OFLOW_MAX - *lengthptr < delta) + { + *errorcodeptr = ERR20; + return 0; + } + *lengthptr += delta; + } - if (*last_branch != OP_ALT) - { - firstcu = branchfirstcu; - firstcuflags = branchfirstcuflags; - reqcu = branchreqcu; - reqcuflags = branchreqcuflags; - } + /* This is compiling for real */ - /* If this is not the first branch, the first char and reqcu have to - match the values from all the previous branches, except that if the - previous value for reqcu didn't have REQ_VARY set, it can still match, - and we set REQ_VARY for the regex. */ + else for (i = repeat_max - 1; i >= 0; i--) + { + *code++ = OP_BRAZERO + repeat_type; - else - { - /* If we previously had a firstcu, but it doesn't match the new branch, - we have to abandon the firstcu for the regex, but if there was - previously no reqcu, it takes on the value of the old firstcu. */ + /* All but the final copy start a new nesting, maintaining the + chain of brackets outstanding. */ - if (firstcuflags != branchfirstcuflags || firstcu != branchfirstcu) - { - if (firstcuflags >= 0) - { - if (reqcuflags < 0) + if (i != 0) + { + int linkoffset; + *code++ = OP_BRA; + linkoffset = (bralink == NULL)? 0 : (int)(code - bralink); + bralink = code; + PUTINC(code, 0, linkoffset); + } + + memcpy(code, previous, CU2BYTES(len)); + code += len; + } + + /* Now chain through the pending brackets, and fill in their length + fields (which are holding the chain links pro tem). */ + + while (bralink != NULL) { - reqcu = firstcu; - reqcuflags = firstcuflags; + int oldlinkoffset; + int linkoffset = (int)(code - bralink + 1); + PCRE2_UCHAR *bra = code - linkoffset; + oldlinkoffset = GET(bra, 1); + bralink = (oldlinkoffset == 0)? NULL : bralink - oldlinkoffset; + *code++ = OP_KET; + PUTINC(code, 0, linkoffset); + PUT(bra, 1, linkoffset); } } - firstcuflags = REQ_NONE; - } - /* If we (now or from before) have no firstcu, a firstcu from the - branch becomes a reqcu if there isn't a branch reqcu. */ + /* If the maximum is unlimited, set a repeater in the final copy. For + ONCE brackets, that's all we need to do. However, possessively repeated + ONCE brackets can be converted into non-capturing brackets, as the + behaviour of (?:xx)++ is the same as (?>xx)++ and this saves having to + deal with possessive ONCEs specially. + + Otherwise, when we are doing the actual compile phase, check to see + whether this group is one that could match an empty string. If so, + convert the initial operator to the S form (e.g. OP_BRA -> OP_SBRA) so + that runtime checking can be done. [This check is also applied to ONCE + groups at runtime, but in a different way.] + + Then, if the quantifier was possessive and the bracket is not a + conditional, we convert the BRA code to the POS form, and the KET code to + KETRPOS. (It turns out to be convenient at runtime to detect this kind of + subpattern at both the start and at the end.) The use of special opcodes + makes it possible to reduce greatly the stack usage in pcre2_match(). If + the group is preceded by OP_BRAZERO, convert this to OP_BRAPOSZERO. + + Then, if the minimum number of matches is 1 or 0, cancel the possessive + flag so that the default action below, of wrapping everything inside + atomic brackets, does not happen. When the minimum is greater than 1, + there will be earlier copies of the group, and so we still have to wrap + the whole thing. */ - if (firstcuflags < 0 && branchfirstcuflags >= 0 && - branchreqcuflags < 0) - { - branchreqcu = branchfirstcu; - branchreqcuflags = branchfirstcuflags; - } + else + { + PCRE2_UCHAR *ketcode = code - 1 - LINK_SIZE; + PCRE2_UCHAR *bracode = ketcode - GET(ketcode, 1); - /* Now ensure that the reqcus match */ + /* Convert possessive ONCE brackets to non-capturing */ - if (((reqcuflags & ~REQ_VARY) != (branchreqcuflags & ~REQ_VARY)) || - reqcu != branchreqcu) - reqcuflags = REQ_NONE; - else - { - reqcu = branchreqcu; - reqcuflags |= branchreqcuflags; /* To "or" REQ_VARY */ - } - } + if ((*bracode == OP_ONCE || *bracode == OP_ONCE_NC) && + possessive_quantifier) *bracode = OP_BRA; - /* If lookbehind, check that this branch matches a fixed-length string, and - put the length into the OP_REVERSE item. Temporarily mark the end of the - branch with OP_END. If the branch contains OP_RECURSE, the result is - FFL_LATER (a negative value) because there may be forward references that - we can't check here. Set a flag to cause another lookbehind check at the - end. Why not do it all at the end? Because common errors can be picked up - here and the offset of the problem can be shown. */ + /* For non-possessive ONCE brackets, all we need to do is to + set the KET. */ - if (lookbehind) - { - int fixed_length; - int count = 0; - *code = OP_END; - fixed_length = find_fixedlength(last_branch, (options & PCRE2_UTF) != 0, - FALSE, cb, NULL, &count); - if (fixed_length == FFL_LATER) - { - cb->check_lookbehind = TRUE; - } - else if (fixed_length < 0) - { - *errorcodeptr = fixed_length_errors[-fixed_length]; - *ptrptr = ptr; - return FALSE; - } - else - { - if (fixed_length > cb->max_lookbehind) - cb->max_lookbehind = fixed_length; - PUT(reverse_count, 0, fixed_length); - } - } - } + if (*bracode == OP_ONCE || *bracode == OP_ONCE_NC) + *ketcode = OP_KETRMAX + repeat_type; - /* Reached end of expression, either ')' or end of pattern. In the real - compile phase, go back through the alternative branches and reverse the chain - of offsets, with the field in the BRA item now becoming an offset to the - first alternative. If there are no alternatives, it points to the end of the - group. The length in the terminating ket is always the length of the whole - bracketed item. Return leaving the pointer at the terminating char. */ + /* Handle non-ONCE brackets and possessive ONCEs (which have been + converted to non-capturing above). */ - if (*ptr != CHAR_VERTICAL_LINE) - { - if (lengthptr == NULL) - { - size_t branch_length = code - last_branch; - do - { - size_t prev_length = GET(last_branch, 1); - PUT(last_branch, 1, branch_length); - branch_length = prev_length; - last_branch -= branch_length; - } - while (branch_length > 0); - } + else + { + /* In the compile phase, adjust the opcode if the group can match + an empty string. For a conditional group with only one branch, the + value of group_return will not show "could be empty", so we must + check that separately. */ - /* Fill in the ket */ + if (lengthptr == NULL) + { + if (group_return < 0) *bracode += OP_SBRA - OP_BRA; + if (*bracode == OP_COND && bracode[GET(bracode,1)] != OP_ALT) + *bracode = OP_SCOND; + } - *code = OP_KET; - PUT(code, 1, (int)(code - start_bracket)); - code += 1 + LINK_SIZE; + /* Handle possessive quantifiers. */ - /* If it was a capturing subpattern, check to see if it contained any - recursive back references. If so, we must wrap it in atomic brackets. In - any event, remove the block from the chain. */ + if (possessive_quantifier) + { + /* For COND brackets, we wrap the whole thing in a possessively + repeated non-capturing bracket, because we have not invented POS + versions of the COND opcodes. */ - if (capnumber > 0) - { - if (cb->open_caps->flag) - { - memmove(start_bracket + 1 + LINK_SIZE, start_bracket, - CU2BYTES(code - start_bracket)); - *start_bracket = OP_ONCE; - code += 1 + LINK_SIZE; - PUT(start_bracket, 1, (int)(code - start_bracket)); - *code = OP_KET; - PUT(code, 1, (int)(code - start_bracket)); - code += 1 + LINK_SIZE; - length += 2 + 2*LINK_SIZE; - } - cb->open_caps = cb->open_caps->next; - } + if (*bracode == OP_COND || *bracode == OP_SCOND) + { + int nlen = (int)(code - bracode); + memmove(bracode + 1 + LINK_SIZE, bracode, CU2BYTES(nlen)); + code += 1 + LINK_SIZE; + nlen += 1 + LINK_SIZE; + *bracode = (*bracode == OP_COND)? OP_BRAPOS : OP_SBRAPOS; + *code++ = OP_KETRPOS; + PUTINC(code, 0, nlen); + PUT(bracode, 1, nlen); + } - /* Retain the highest bracket number, in case resetting was used. */ + /* For non-COND brackets, we modify the BRA code and use KETRPOS. */ - cb->bracount = max_bracount; + else + { + *bracode += 1; /* Switch to xxxPOS opcodes */ + *ketcode = OP_KETRPOS; + } - /* Set values to pass back */ + /* If the minimum is zero, mark it as possessive, then unset the + possessive flag when the minimum is 0 or 1. */ - *codeptr = code; - *ptrptr = ptr; - *firstcuptr = firstcu; - *firstcuflagsptr = firstcuflags; - *reqcuptr = reqcu; - *reqcuflagsptr = reqcuflags; - if (lengthptr != NULL) - { - if (OFLOW_MAX - *lengthptr < length) + if (brazeroptr != NULL) *brazeroptr = OP_BRAPOSZERO; + if (repeat_min < 2) possessive_quantifier = FALSE; + } + + /* Non-possessive quantifier */ + + else *ketcode = OP_KETRMAX + repeat_type; + } + } + } + break; + + /* If previous was a character type match (\d or similar), abolish it and + create a suitable repeat item. The code is shared with single-character + repeats by setting op_type to add a suitable offset into repeat_type. + Note the the Unicode property types will be present only when + SUPPORT_UNICODE is defined, but we don't wrap the little bits of code + here because it just makes it horribly messy. */ + + default: + if (op_previous >= OP_EODN) /* Not a character type - internal error */ { - *errorcodeptr = ERR20; - return FALSE; + *errorcodeptr = ERR10; + return 0; } - *lengthptr += length; - } - return TRUE; - } + else + { + int prop_type, prop_value; + PCRE2_UCHAR *oldcode; - /* Another branch follows. In the pre-compile phase, we can move the code - pointer back to where it was for the start of the first branch. (That is, - pretend that each branch is the only one.) + op_type = OP_TYPESTAR - OP_STAR; /* Use type opcodes */ + mclength = 0; /* Not a character */ - In the real compile phase, insert an ALT node. Its length field points back - to the previous branch while the bracket remains open. At the end the chain - is reversed. It's done like this so that the start of the bracket has a - zero offset until it is closed, making it possible to detect recursion. */ + if (op_previous == OP_PROP || op_previous == OP_NOTPROP) + { + prop_type = previous[1]; + prop_value = previous[2]; + } + else + { + /* Come here from just above with a character in mcbuffer/mclength. */ + OUTPUT_SINGLE_REPEAT: + prop_type = prop_value = -1; + } - if (lengthptr != NULL) - { - code = *codeptr + 1 + LINK_SIZE + skipunits; - length += 1 + LINK_SIZE; - } - else - { - *code = OP_ALT; - PUT(code, 1, (int)(code - last_branch)); - bc.current_branch = last_branch = code; - code += 1 + LINK_SIZE; - } + /* At this point, if prop_type == prop_value == -1 we either have a + character in mcbuffer when mclength is greater than zero, or we have + mclength zero, in which case there is a non-property character type in + op_previous. If prop_type/value are not negative, we have a property + character type in op_previous. */ - /* Advance past the vertical bar */ + oldcode = code; /* Save where we were */ + code = previous; /* Usually overwrite previous item */ - ptr++; - } -/* Control never reaches here */ -} + /* If the maximum is zero then the minimum must also be zero; Perl allows + this case, so we do too - by simply omitting the item altogether. */ + if (repeat_max == 0) goto END_REPEAT; + /* Combine the op_type with the repeat_type */ -/************************************************* -* Check for anchored pattern * -*************************************************/ + repeat_type += op_type; -/* Try to find out if this is an anchored regular expression. Consider each -alternative branch. If they all start with OP_SOD or OP_CIRC, or with a bracket -all of whose alternatives start with OP_SOD or OP_CIRC (recurse ad lib), then -it's anchored. However, if this is a multiline pattern, then only OP_SOD will -be found, because ^ generates OP_CIRCM in that mode. + /* A minimum of zero is handled either as the special case * or ?, or as + an UPTO, with the maximum given. */ -We can also consider a regex to be anchored if OP_SOM starts all its branches. -This is the code for \G, which means "match at start of match position, taking -into account the match offset". + if (repeat_min == 0) + { + if (repeat_max == REPEAT_UNLIMITED) *code++ = OP_STAR + repeat_type; + else if (repeat_max == 1) *code++ = OP_QUERY + repeat_type; + else + { + *code++ = OP_UPTO + repeat_type; + PUT2INC(code, 0, repeat_max); + } + } -A branch is also implicitly anchored if it starts with .* and DOTALL is set, -because that will try the rest of the pattern at all possible matching points, -so there is no point trying again.... er .... + /* A repeat minimum of 1 is optimized into some special cases. If the + maximum is unlimited, we use OP_PLUS. Otherwise, the original item is + left in place and, if the maximum is greater than 1, we use OP_UPTO with + one less than the maximum. */ -.... except when the .* appears inside capturing parentheses, and there is a -subsequent back reference to those parentheses. We haven't enough information -to catch that case precisely. + else if (repeat_min == 1) + { + if (repeat_max == REPEAT_UNLIMITED) + *code++ = OP_PLUS + repeat_type; + else + { + code = oldcode; /* Leave previous item in place */ + if (repeat_max == 1) goto END_REPEAT; + *code++ = OP_UPTO + repeat_type; + PUT2INC(code, 0, repeat_max - 1); + } + } -At first, the best we could do was to detect when .* was in capturing brackets -and the highest back reference was greater than or equal to that level. -However, by keeping a bitmap of the first 31 back references, we can catch some -of the more common cases more precisely. + /* The case {n,n} is just an EXACT, while the general case {n,m} is + handled as an EXACT followed by an UPTO or STAR or QUERY. */ -... A second exception is when the .* appears inside an atomic group, because -this prevents the number of characters it matches from being adjusted. + else + { + *code++ = OP_EXACT + op_type; /* NB EXACT doesn't have repeat_type */ + PUT2INC(code, 0, repeat_min); -Arguments: - code points to start of the compiled pattern - bracket_map a bitmap of which brackets we are inside while testing; this - handles up to substring 31; after that we just have to take - the less precise approach - cb points to the compile data block - atomcount atomic group level + /* Unless repeat_max equals repeat_min, fill in the data for EXACT, + and then generate the second opcode. For a repeated Unicode property + match, there are two extra values that define the required property, + and mclength is set zero to indicate this. */ + + if (repeat_max != repeat_min) + { + if (mclength > 0) + { + memcpy(code, mcbuffer, CU2BYTES(mclength)); + code += mclength; + } + else + { + *code++ = op_previous; + if (prop_type >= 0) + { + *code++ = prop_type; + *code++ = prop_value; + } + } + + /* Now set up the following opcode */ + + if (repeat_max == REPEAT_UNLIMITED) + *code++ = OP_STAR + repeat_type; + else + { + repeat_max -= repeat_min; + if (repeat_max == 1) + { + *code++ = OP_QUERY + repeat_type; + } + else + { + *code++ = OP_UPTO + repeat_type; + PUT2INC(code, 0, repeat_max); + } + } + } + } + + /* Fill in the character or character type for the final opcode. */ + + if (mclength > 0) + { + memcpy(code, mcbuffer, CU2BYTES(mclength)); + code += mclength; + } + else + { + *code++ = op_previous; + if (prop_type >= 0) + { + *code++ = prop_type; + *code++ = prop_value; + } + } + } + break; + } /* End of switch on different op_previous values */ + + + /* If the character following a repeat is '+', possessive_quantifier is + TRUE. For some opcodes, there are special alternative opcodes for this + case. For anything else, we wrap the entire repeated item inside OP_ONCE + brackets. Logically, the '+' notation is just syntactic sugar, taken from + Sun's Java package, but the special opcodes can optimize it. + + Some (but not all) possessively repeated subpatterns have already been + completely handled in the code just above. For them, possessive_quantifier + is always FALSE at this stage. Note that the repeated item starts at + tempcode, not at previous, which might be the first part of a string whose + (former) last char we repeated. */ + + if (possessive_quantifier) + { + int len; + + /* Possessifying an EXACT quantifier has no effect, so we can ignore it. + However, QUERY, STAR, or UPTO may follow (for quantifiers such as {5,6}, + {5,}, or {5,10}). We skip over an EXACT item; if the length of what + remains is greater than zero, there's a further opcode that can be + handled. If not, do nothing, leaving the EXACT alone. */ + + switch(*tempcode) + { + case OP_TYPEEXACT: + tempcode += PRIV(OP_lengths)[*tempcode] + + ((tempcode[1 + IMM2_SIZE] == OP_PROP + || tempcode[1 + IMM2_SIZE] == OP_NOTPROP)? 2 : 0); + break; + + /* CHAR opcodes are used for exacts whose count is 1. */ + + case OP_CHAR: + case OP_CHARI: + case OP_NOT: + case OP_NOTI: + case OP_EXACT: + case OP_EXACTI: + case OP_NOTEXACT: + case OP_NOTEXACTI: + tempcode += PRIV(OP_lengths)[*tempcode]; +#ifdef SUPPORT_UNICODE + if (utf && HAS_EXTRALEN(tempcode[-1])) + tempcode += GET_EXTRALEN(tempcode[-1]); +#endif + break; + + /* For the class opcodes, the repeat operator appears at the end; + adjust tempcode to point to it. */ + + case OP_CLASS: + case OP_NCLASS: + tempcode += 1 + 32/sizeof(PCRE2_UCHAR); + break; + +#ifdef SUPPORT_WIDE_CHARS + case OP_XCLASS: + tempcode += GET(tempcode, 1); + break; +#endif + } + + /* If tempcode is equal to code (which points to the end of the repeated + item), it means we have skipped an EXACT item but there is no following + QUERY, STAR, or UPTO; the value of len will be 0, and we do nothing. In + all other cases, tempcode will be pointing to the repeat opcode, and will + be less than code, so the value of len will be greater than 0. */ + + len = (int)(code - tempcode); + if (len > 0) + { + unsigned int repcode = *tempcode; + + /* There is a table for possessifying opcodes, all of which are less + than OP_CALLOUT. A zero entry means there is no possessified version. + */ + + if (repcode < OP_CALLOUT && opcode_possessify[repcode] > 0) + *tempcode = opcode_possessify[repcode]; + + /* For opcode without a special possessified version, wrap the item in + ONCE brackets. */ + + else + { + memmove(tempcode + 1 + LINK_SIZE, tempcode, CU2BYTES(len)); + code += 1 + LINK_SIZE; + len += 1 + LINK_SIZE; + tempcode[0] = OP_ONCE; + *code++ = OP_KET; + PUTINC(code, 0, len); + PUT(tempcode, 1, len); + } + } + } + + /* We set the "follows varying string" flag for subsequently encountered + reqcus if it isn't already set and we have just passed a varying length + item. */ + + END_REPEAT: + cb->req_varyopt |= reqvary; + break; + + + /* ===================================================================*/ + /* Handle a 32-bit data character with a value greater than META_END. */ + + case META_BIGVALUE: + pptr++; + goto NORMAL_CHAR; + + + /* ===============================================================*/ + /* Handle a back reference by number, which is the meta argument. The + pattern offsets for back references to group numbers less than 10 are held + in a special vector, to avoid using more than two parsed pattern elements + in 64-bit environments. We only need the offset to the first occurrence, + because if that doesn't fail, subsequent ones will also be OK. */ + + case META_BACKREF: + if (meta_arg < 10) offset = cb->small_ref_offset[meta_arg]; + else GETPLUSOFFSET(offset, pptr); + + if (meta_arg > cb->bracount) + { + cb->erroroffset = offset; + *errorcodeptr = ERR15; /* Non-existent subpattern */ + return 0; + } + + /* Come here from named backref handling when the reference is to a + single group (that is, not to a duplicated name). The back reference + data will have already been updated. We must disable firstcu if not + set, to cope with cases like (?=(\w+))\1: which would otherwise set ':' + later. */ + + HANDLE_SINGLE_REFERENCE: + if (firstcuflags == REQ_UNSET) firstcuflags = REQ_NONE; + *code++ = ((options & PCRE2_CASELESS) != 0)? OP_REFI : OP_REF; + PUT2INC(code, 0, meta_arg); + + /* Update the map of back references, and keep the highest one. We + could do this in parse_regex() for numerical back references, but not + for named back references, because we don't know the numbers to which + named back references refer. So we do it all in this function. */ + + cb->backref_map |= (meta_arg < 32)? (1u << meta_arg) : 1; + if (meta_arg > cb->top_backref) cb->top_backref = meta_arg; + + /* Check to see if this back reference is recursive, that it, it + is inside the group that it references. A flag is set so that the + group can be made atomic. */ + + for (oc = cb->open_caps; oc != NULL; oc = oc->next) + { + if (oc->number == meta_arg) + { + oc->flag = TRUE; + break; + } + } + break; + + + /* ===============================================================*/ + /* Handle recursion by inserting the number of the called group (which is + the meta argument) after OP_RECURSE. At the end of compiling the pattern is + scanned and these numbers are replaced by offsets within the pattern. It is + done like this to avoid problems with forward references and adjusting + offsets when groups are duplicated and moved (as discovered in previous + implementations). Note that a recursion does not have a set first character + (relevant if it is repeated, because it will then be wrapped with ONCE + brackets). */ + + case META_RECURSE: + GETPLUSOFFSET(offset, pptr); + if (meta_arg > cb->bracount) + { + cb->erroroffset = offset; + *errorcodeptr = ERR15; /* Non-existent subpattern */ + return 0; + } + HANDLE_NUMERICAL_RECURSION: + *code = OP_RECURSE; + PUT(code, 1, meta_arg); + code += 1 + LINK_SIZE; + groupsetfirstcu = FALSE; + cb->had_recurse = TRUE; + if (firstcuflags == REQ_UNSET) firstcuflags = REQ_NONE; + break; + + + /* ===============================================================*/ + /* Handle capturing parentheses; the number is the meta argument. */ + + case META_CAPTURE: + bravalue = OP_CBRA; + skipunits = IMM2_SIZE; + PUT2(code, 1+LINK_SIZE, meta_arg); + cb->lastcapture = meta_arg; + goto GROUP_PROCESS_NOTE_EMPTY; + + + /* ===============================================================*/ + /* Handle escape sequence items. For ones like \d, the ESC_values are + arranged to be the same as the corresponding OP_values in the default case + when PCRE2_UCP is not set (which is the only case in which they will appear + here). + + Note: \Q and \E are never seen here, as they were dealt with in + parse_pattern(). Neither are numerical back references or recursions, which + were turned into META_BACKREF or META_RECURSE items, respectively. \k and + \g, when followed by names, are turned into META_BACKREF_BYNAME or + META_RECURSE_BYNAME. */ + + case META_ESCAPE: + + /* We can test for escape sequences that consume a character because their + values lie between ESC_b and ESC_Z; this may have to change if any new ones + are ever created. For these sequences, we disable the setting of a first + character if it hasn't already been set. */ + + if (meta_arg > ESC_b && meta_arg < ESC_Z) + { + matched_char = TRUE; + if (firstcuflags == REQ_UNSET) firstcuflags = REQ_NONE; + } + + /* Set values to reset to if this is followed by a zero repeat. */ + + zerofirstcu = firstcu; + zerofirstcuflags = firstcuflags; + zeroreqcu = reqcu; + zeroreqcuflags = reqcuflags; + + /* If Unicode is not supported, \P and \p are not allowed and are + faulted at parse time, so will never appear here. */ + +#ifdef SUPPORT_UNICODE + if (meta_arg == ESC_P || meta_arg == ESC_p) + { + uint32_t ptype = *(++pptr) >> 16; + uint32_t pdata = *pptr & 0xffff; + *code++ = (meta_arg == ESC_p)? OP_PROP : OP_NOTPROP; + *code++ = ptype; + *code++ = pdata; + break; /* End META_ESCAPE */ + } +#endif + + /* For the rest (including \X when Unicode is supported - if not it's + faulted at parse time), the OP value is the escape value when PCRE2_UCP is + not set; if it is set, these escapes do not show up here because they are + converted into Unicode property tests in parse_regex(). Note that \b and \B + do a one-character lookbehind, and \A also behaves as if it does. */ + + if (meta_arg == ESC_C) cb->external_flags |= PCRE2_HASBKC; /* Record */ + if ((meta_arg == ESC_b || meta_arg == ESC_B || meta_arg == ESC_A) && + cb->max_lookbehind == 0) + cb->max_lookbehind = 1; + + /* In non-UTF mode, and for both 32-bit modes, we turn \C into OP_ALLANY + instead of OP_ANYBYTE so that it works in DFA mode and in lookbehinds. */ + +#if PCRE2_CODE_UNIT_WIDTH == 32 + *code++ = (meta_arg == ESC_C)? OP_ALLANY : meta_arg; +#else + *code++ = (!utf && meta_arg == ESC_C)? OP_ALLANY : meta_arg; +#endif + break; /* End META_ESCAPE */ + + + /* ===================================================================*/ + /* Handle an unrecognized meta value. A parsed pattern value less than + META_END is a literal. Otherwise we have a problem. */ + + default: + if (meta >= META_END) + { +#ifdef DEBUG_SHOW_PARSED + fprintf(stderr, "** Unrecognized parsed pattern item 0x%.8x\n", *pptr); +#endif + *errorcodeptr = ERR89; /* Internal error - unrecognized. */ + return 0; + } + + /* Handle a literal character. We come here by goto in the case of a + 32-bit, non-UTF character whose value is greater than META_END. */ + + NORMAL_CHAR: + meta = *pptr; /* Get the full 32 bits */ + NORMAL_CHAR_SET: /* Character is already in meta */ + matched_char = TRUE; + + /* For caseless UTF mode, check whether this character has more than one + other case. If so, generate a special OP_PROP item instead of OP_CHARI. */ + +#ifdef SUPPORT_UNICODE + if (utf && (options & PCRE2_CASELESS) != 0) + { + uint32_t caseset = UCD_CASESET(meta); + if (caseset != 0) + { + *code++ = OP_PROP; + *code++ = PT_CLIST; + *code++ = caseset; + if (firstcuflags == REQ_UNSET) + firstcuflags = zerofirstcuflags = REQ_NONE; + break; /* End handling this meta item */ + } + } +#endif + + /* Caseful matches, or not one of the multicase characters. Get the + character's code units into mcbuffer, with the length in mclength. When not + in UTF mode, the length is always 1. */ + +#ifdef SUPPORT_UNICODE + if (utf) mclength = PRIV(ord2utf)(meta, mcbuffer); else +#endif + { + mclength = 1; + mcbuffer[0] = meta; + } + + /* Generate the appropriate code */ + + *code++ = ((options & PCRE2_CASELESS) != 0)? OP_CHARI : OP_CHAR; + memcpy(code, mcbuffer, CU2BYTES(mclength)); + code += mclength; + + /* Remember if \r or \n were seen */ + + if (mcbuffer[0] == CHAR_CR || mcbuffer[0] == CHAR_NL) + cb->external_flags |= PCRE2_HASCRORLF; + + /* Set the first and required code units appropriately. If no previous + first code unit, set it from this character, but revert to none on a zero + repeat. Otherwise, leave the firstcu value alone, and don't change it on + a zero repeat. */ + + if (firstcuflags == REQ_UNSET) + { + zerofirstcuflags = REQ_NONE; + zeroreqcu = reqcu; + zeroreqcuflags = reqcuflags; + + /* If the character is more than one code unit long, we can set firstcu + only if it is not to be matched caselessly. */ + + if (mclength == 1 || req_caseopt == 0) + { + firstcu = mcbuffer[0] | req_caseopt; + firstcu = mcbuffer[0]; + firstcuflags = req_caseopt; + if (mclength != 1) + { + reqcu = code[-1]; + reqcuflags = cb->req_varyopt; + } + } + else firstcuflags = reqcuflags = REQ_NONE; + } + + /* firstcu was previously set; we can set reqcu only if the length is + 1 or the matching is caseful. */ + + else + { + zerofirstcu = firstcu; + zerofirstcuflags = firstcuflags; + zeroreqcu = reqcu; + zeroreqcuflags = reqcuflags; + if (mclength == 1 || req_caseopt == 0) + { + reqcu = code[-1]; + reqcuflags = req_caseopt | cb->req_varyopt; + } + } + break; /* End default meta handling */ + } /* End of big switch */ + } /* End of big loop */ + +/* Control never reaches here. */ +} + + + +/************************************************* +* Compile regex: a sequence of alternatives * +*************************************************/ + +/* On entry, pptr is pointing past the bracket meta, but on return it points to +the closing bracket or META_END. The code variable is pointing at the code unit +into which the BRA operator has been stored. This function is used during the +pre-compile phase when we are trying to find out the amount of memory needed, +as well as during the real compile phase. The value of lengthptr distinguishes +the two phases. + +Arguments: + options option bits, including any changes for this subpattern + codeptr -> the address of the current code pointer + pptrptr -> the address of the current parsed pattern pointer + errorcodeptr -> pointer to error code variable + skipunits skip this many code units at start (for brackets and OP_COND) + firstcuptr place to put the first required code unit + firstcuflagsptr place to put the first code unit flags, or a negative number + reqcuptr place to put the last required code unit + reqcuflagsptr place to put the last required code unit flags, or a negative number + bcptr pointer to the chain of currently open branches + cb points to the data block with tables pointers etc. + lengthptr NULL during the real compile phase + points to length accumulator during pre-compile phase + +Returns: 0 There has been an error + +1 Success, this group must match at least one character + -1 Success, this group may match an empty string +*/ + +static int +compile_regex(uint32_t options, PCRE2_UCHAR **codeptr, uint32_t **pptrptr, + int *errorcodeptr, uint32_t skipunits, uint32_t *firstcuptr, + int32_t *firstcuflagsptr, uint32_t *reqcuptr,int32_t *reqcuflagsptr, + branch_chain *bcptr, compile_block *cb, PCRE2_SIZE *lengthptr) +{ +PCRE2_UCHAR *code = *codeptr; +PCRE2_UCHAR *last_branch = code; +PCRE2_UCHAR *start_bracket = code; +BOOL lookbehind; +open_capitem capitem; +int capnumber = 0; +int okreturn = 1; +uint32_t *pptr = *pptrptr; +uint32_t firstcu, reqcu; +uint32_t lookbehindlength; +int32_t firstcuflags, reqcuflags; +uint32_t branchfirstcu, branchreqcu; +int32_t branchfirstcuflags, branchreqcuflags; +PCRE2_SIZE length; +branch_chain bc; + +/* If set, call the external function that checks for stack availability. */ + +if (cb->cx->stack_guard != NULL && + cb->cx->stack_guard(cb->parens_depth, cb->cx->stack_guard_data)) + { + *errorcodeptr= ERR33; + return 0; + } + +/* Miscellaneous initialization */ + +bc.outer = bcptr; +bc.current_branch = code; + +firstcu = reqcu = 0; +firstcuflags = reqcuflags = REQ_UNSET; + +/* Accumulate the length for use in the pre-compile phase. Start with the +length of the BRA and KET and any extra code units that are required at the +beginning. We accumulate in a local variable to save frequent testing of +lengthptr for NULL. We cannot do this by looking at the value of 'code' at the +start and end of each alternative, because compiled items are discarded during +the pre-compile phase so that the work space is not exceeded. */ + +length = 2 + 2*LINK_SIZE + skipunits; + +/* Remember if this is a lookbehind assertion, and if it is, save its length +and skip over the pattern offset. */ + +lookbehind = *code == OP_ASSERTBACK || *code == OP_ASSERTBACK_NOT; +if (lookbehind) + { + lookbehindlength = META_DATA(pptr[-1]); + pptr += SIZEOFFSET; + } +else lookbehindlength = 0; + +/* If this is a capturing subpattern, add to the chain of open capturing items +so that we can detect them if (*ACCEPT) is encountered. Note that only OP_CBRA +need be tested here; changing this opcode to one of its variants, e.g. +OP_SCBRAPOS, happens later, after the group has been compiled. */ + +if (*code == OP_CBRA) + { + capnumber = GET2(code, 1 + LINK_SIZE); + capitem.number = capnumber; + capitem.next = cb->open_caps; + capitem.flag = FALSE; + cb->open_caps = &capitem; + } + +/* Offset is set zero to mark that this bracket is still open */ + +PUT(code, 1, 0); +code += 1 + LINK_SIZE + skipunits; + +/* Loop for each alternative branch */ + +for (;;) + { + int branch_return; + + /* Insert OP_REVERSE if this is as lookbehind assertion. */ + + if (lookbehind && lookbehindlength > 0) + { + *code++ = OP_REVERSE; + PUTINC(code, 0, lookbehindlength); + length += 1 + LINK_SIZE; + } + + /* Now compile the branch; in the pre-compile phase its length gets added + into the length. */ + + if ((branch_return = + compile_branch(&options, &code, &pptr, errorcodeptr, &branchfirstcu, + &branchfirstcuflags, &branchreqcu, &branchreqcuflags, &bc, + cb, (lengthptr == NULL)? NULL : &length)) == 0) + return 0; + + /* If a branch can match an empty string, so can the whole group. */ + + if (branch_return < 0) okreturn = -1; + + /* In the real compile phase, there is some post-processing to be done. */ + + if (lengthptr == NULL) + { + /* If this is the first branch, the firstcu and reqcu values for the + branch become the values for the regex. */ + + if (*last_branch != OP_ALT) + { + firstcu = branchfirstcu; + firstcuflags = branchfirstcuflags; + reqcu = branchreqcu; + reqcuflags = branchreqcuflags; + } + + /* If this is not the first branch, the first char and reqcu have to + match the values from all the previous branches, except that if the + previous value for reqcu didn't have REQ_VARY set, it can still match, + and we set REQ_VARY for the regex. */ + + else + { + /* If we previously had a firstcu, but it doesn't match the new branch, + we have to abandon the firstcu for the regex, but if there was + previously no reqcu, it takes on the value of the old firstcu. */ + + if (firstcuflags != branchfirstcuflags || firstcu != branchfirstcu) + { + if (firstcuflags >= 0) + { + if (reqcuflags < 0) + { + reqcu = firstcu; + reqcuflags = firstcuflags; + } + } + firstcuflags = REQ_NONE; + } + + /* If we (now or from before) have no firstcu, a firstcu from the + branch becomes a reqcu if there isn't a branch reqcu. */ + + if (firstcuflags < 0 && branchfirstcuflags >= 0 && + branchreqcuflags < 0) + { + branchreqcu = branchfirstcu; + branchreqcuflags = branchfirstcuflags; + } + + /* Now ensure that the reqcus match */ + + if (((reqcuflags & ~REQ_VARY) != (branchreqcuflags & ~REQ_VARY)) || + reqcu != branchreqcu) + reqcuflags = REQ_NONE; + else + { + reqcu = branchreqcu; + reqcuflags |= branchreqcuflags; /* To "or" REQ_VARY */ + } + } + } + + /* Handle reaching the end of the expression, either ')' or end of pattern. + In the real compile phase, go back through the alternative branches and + reverse the chain of offsets, with the field in the BRA item now becoming an + offset to the first alternative. If there are no alternatives, it points to + the end of the group. The length in the terminating ket is always the length + of the whole bracketed item. Return leaving the pointer at the terminating + char. */ + + if (META_CODE(*pptr) != META_ALT) + { + if (lengthptr == NULL) + { + PCRE2_SIZE branch_length = code - last_branch; + do + { + PCRE2_SIZE prev_length = GET(last_branch, 1); + PUT(last_branch, 1, branch_length); + branch_length = prev_length; + last_branch -= branch_length; + } + while (branch_length > 0); + } + + /* Fill in the ket */ + + *code = OP_KET; + PUT(code, 1, (int)(code - start_bracket)); + code += 1 + LINK_SIZE; + + /* If it was a capturing subpattern, check to see if it contained any + recursive back references. If so, we must wrap it in atomic brackets. In + any event, remove the block from the chain. */ + + if (capnumber > 0) + { + if (cb->open_caps->flag) + { + memmove(start_bracket + 1 + LINK_SIZE, start_bracket, + CU2BYTES(code - start_bracket)); + *start_bracket = OP_ONCE; + code += 1 + LINK_SIZE; + PUT(start_bracket, 1, (int)(code - start_bracket)); + *code = OP_KET; + PUT(code, 1, (int)(code - start_bracket)); + code += 1 + LINK_SIZE; + length += 2 + 2*LINK_SIZE; + } + cb->open_caps = cb->open_caps->next; + } + + /* Set values to pass back */ + + *codeptr = code; + *pptrptr = pptr; + *firstcuptr = firstcu; + *firstcuflagsptr = firstcuflags; + *reqcuptr = reqcu; + *reqcuflagsptr = reqcuflags; + if (lengthptr != NULL) + { + if (OFLOW_MAX - *lengthptr < length) + { + *errorcodeptr = ERR20; + return 0; + } + *lengthptr += length; + } + return okreturn; + } + + /* Another branch follows. In the pre-compile phase, we can move the code + pointer back to where it was for the start of the first branch. (That is, + pretend that each branch is the only one.) + + In the real compile phase, insert an ALT node. Its length field points back + to the previous branch while the bracket remains open. At the end the chain + is reversed. It's done like this so that the start of the bracket has a + zero offset until it is closed, making it possible to detect recursion. */ + + if (lengthptr != NULL) + { + code = *codeptr + 1 + LINK_SIZE + skipunits; + length += 1 + LINK_SIZE; + } + else + { + *code = OP_ALT; + PUT(code, 1, (int)(code - last_branch)); + bc.current_branch = last_branch = code; + code += 1 + LINK_SIZE; + } + + /* Set the lookbehind length (if not in a lookbehind the value will be zero) + and then advance past the vertical bar. */ + + lookbehindlength = META_DATA(*pptr); + pptr++; + } +/* Control never reaches here */ +} + + + +/************************************************* +* Check for anchored pattern * +*************************************************/ + +/* Try to find out if this is an anchored regular expression. Consider each +alternative branch. If they all start with OP_SOD or OP_CIRC, or with a bracket +all of whose alternatives start with OP_SOD or OP_CIRC (recurse ad lib), then +it's anchored. However, if this is a multiline pattern, then only OP_SOD will +be found, because ^ generates OP_CIRCM in that mode. + +We can also consider a regex to be anchored if OP_SOM starts all its branches. +This is the code for \G, which means "match at start of match position, taking +into account the match offset". + +A branch is also implicitly anchored if it starts with .* and DOTALL is set, +because that will try the rest of the pattern at all possible matching points, +so there is no point trying again.... er .... + +.... except when the .* appears inside capturing parentheses, and there is a +subsequent back reference to those parentheses. We haven't enough information +to catch that case precisely. + +At first, the best we could do was to detect when .* was in capturing brackets +and the highest back reference was greater than or equal to that level. +However, by keeping a bitmap of the first 31 back references, we can catch some +of the more common cases more precisely. + +... A second exception is when the .* appears inside an atomic group, because +this prevents the number of characters it matches from being adjusted. + +Arguments: + code points to start of the compiled pattern + bracket_map a bitmap of which brackets we are inside while testing; this + handles up to substring 31; after that we just have to take + the less precise approach + cb points to the compile data block + atomcount atomic group level + inassert TRUE if in an assertion + +Returns: TRUE or FALSE +*/ + +static BOOL +is_anchored(PCRE2_SPTR code, unsigned int bracket_map, compile_block *cb, + int atomcount, BOOL inassert) +{ +do { + PCRE2_SPTR scode = first_significant_code( + code + PRIV(OP_lengths)[*code], FALSE); + int op = *scode; + + /* Non-capturing brackets */ + + if (op == OP_BRA || op == OP_BRAPOS || + op == OP_SBRA || op == OP_SBRAPOS) + { + if (!is_anchored(scode, bracket_map, cb, atomcount, inassert)) + return FALSE; + } + + /* Capturing brackets */ + + else if (op == OP_CBRA || op == OP_CBRAPOS || + op == OP_SCBRA || op == OP_SCBRAPOS) + { + int n = GET2(scode, 1+LINK_SIZE); + int new_map = bracket_map | ((n < 32)? (1u << n) : 1); + if (!is_anchored(scode, new_map, cb, atomcount, inassert)) return FALSE; + } + + /* Positive forward assertion */ + + else if (op == OP_ASSERT) + { + if (!is_anchored(scode, bracket_map, cb, atomcount, TRUE)) return FALSE; + } + + /* Condition */ + + else if (op == OP_COND) + { + if (!is_anchored(scode, bracket_map, cb, atomcount, inassert)) + return FALSE; + } + + /* Atomic groups */ + + else if (op == OP_ONCE || op == OP_ONCE_NC) + { + if (!is_anchored(scode, bracket_map, cb, atomcount + 1, inassert)) + return FALSE; + } + + /* .* is not anchored unless DOTALL is set (which generates OP_ALLANY) and + it isn't in brackets that are or may be referenced or inside an atomic + group or an assertion. Also the pattern must not contain *PRUNE or *SKIP, + because these break the feature. Consider, for example, /(?s).*?(*PRUNE)b/ + with the subject "aab", which matches "b", i.e. not at the start of a line. + There is also an option that disables auto-anchoring. */ + + else if ((op == OP_TYPESTAR || op == OP_TYPEMINSTAR || + op == OP_TYPEPOSSTAR)) + { + if (scode[1] != OP_ALLANY || (bracket_map & cb->backref_map) != 0 || + atomcount > 0 || cb->had_pruneorskip || inassert || + (cb->external_options & PCRE2_NO_DOTSTAR_ANCHOR) != 0) + return FALSE; + } + + /* Check for explicit anchoring */ + + else if (op != OP_SOD && op != OP_SOM && op != OP_CIRC) return FALSE; + + code += GET(code, 1); + } +while (*code == OP_ALT); /* Loop for each alternative */ +return TRUE; +} + + + +/************************************************* +* Check for starting with ^ or .* * +*************************************************/ + +/* This is called to find out if every branch starts with ^ or .* so that +"first char" processing can be done to speed things up in multiline +matching and for non-DOTALL patterns that start with .* (which must start at +the beginning or after \n). As in the case of is_anchored() (see above), we +have to take account of back references to capturing brackets that contain .* +because in that case we can't make the assumption. Also, the appearance of .* +inside atomic brackets or in an assertion, or in a pattern that contains *PRUNE +or *SKIP does not count, because once again the assumption no longer holds. + +Arguments: + code points to start of the compiled pattern or a group + bracket_map a bitmap of which brackets we are inside while testing; this + handles up to substring 31; after that we just have to take + the less precise approach + cb points to the compile data + atomcount atomic group level + inassert TRUE if in an assertion + +Returns: TRUE or FALSE +*/ + +static BOOL +is_startline(PCRE2_SPTR code, unsigned int bracket_map, compile_block *cb, + int atomcount, BOOL inassert) +{ +do { + PCRE2_SPTR scode = first_significant_code( + code + PRIV(OP_lengths)[*code], FALSE); + int op = *scode; + + /* If we are at the start of a conditional assertion group, *both* the + conditional assertion *and* what follows the condition must satisfy the test + for start of line. Other kinds of condition fail. Note that there may be an + auto-callout at the start of a condition. */ + + if (op == OP_COND) + { + scode += 1 + LINK_SIZE; + + if (*scode == OP_CALLOUT) scode += PRIV(OP_lengths)[OP_CALLOUT]; + else if (*scode == OP_CALLOUT_STR) scode += GET(scode, 1 + 2*LINK_SIZE); + + switch (*scode) + { + case OP_CREF: + case OP_DNCREF: + case OP_RREF: + case OP_DNRREF: + case OP_FAIL: + case OP_FALSE: + case OP_TRUE: + return FALSE; + + default: /* Assertion */ + if (!is_startline(scode, bracket_map, cb, atomcount, TRUE)) return FALSE; + do scode += GET(scode, 1); while (*scode == OP_ALT); + scode += 1 + LINK_SIZE; + break; + } + scode = first_significant_code(scode, FALSE); + op = *scode; + } + + /* Non-capturing brackets */ + + if (op == OP_BRA || op == OP_BRAPOS || + op == OP_SBRA || op == OP_SBRAPOS) + { + if (!is_startline(scode, bracket_map, cb, atomcount, inassert)) + return FALSE; + } + + /* Capturing brackets */ + + else if (op == OP_CBRA || op == OP_CBRAPOS || + op == OP_SCBRA || op == OP_SCBRAPOS) + { + int n = GET2(scode, 1+LINK_SIZE); + int new_map = bracket_map | ((n < 32)? (1u << n) : 1); + if (!is_startline(scode, new_map, cb, atomcount, inassert)) return FALSE; + } + + /* Positive forward assertions */ + + else if (op == OP_ASSERT) + { + if (!is_startline(scode, bracket_map, cb, atomcount, TRUE)) + return FALSE; + } + + /* Atomic brackets */ + + else if (op == OP_ONCE || op == OP_ONCE_NC) + { + if (!is_startline(scode, bracket_map, cb, atomcount + 1, inassert)) + return FALSE; + } + + /* .* means "start at start or after \n" if it isn't in atomic brackets or + brackets that may be referenced or an assertion, and as long as the pattern + does not contain *PRUNE or *SKIP, because these break the feature. Consider, + for example, /.*?a(*PRUNE)b/ with the subject "aab", which matches "ab", + i.e. not at the start of a line. There is also an option that disables this + optimization. */ + + else if (op == OP_TYPESTAR || op == OP_TYPEMINSTAR || op == OP_TYPEPOSSTAR) + { + if (scode[1] != OP_ANY || (bracket_map & cb->backref_map) != 0 || + atomcount > 0 || cb->had_pruneorskip || inassert || + (cb->external_options & PCRE2_NO_DOTSTAR_ANCHOR) != 0) + return FALSE; + } + + /* Check for explicit circumflex; anything else gives a FALSE result. Note + in particular that this includes atomic brackets OP_ONCE and OP_ONCE_NC + because the number of characters matched by .* cannot be adjusted inside + them. */ + + else if (op != OP_CIRC && op != OP_CIRCM) return FALSE; + + /* Move on to the next alternative */ + + code += GET(code, 1); + } +while (*code == OP_ALT); /* Loop for each alternative */ +return TRUE; +} + + + +/************************************************* +* Scan compiled regex for recursion reference * +*************************************************/ + +/* This function scans through a compiled pattern until it finds an instance of +OP_RECURSE. + +Arguments: + code points to start of expression + utf TRUE in UTF mode + +Returns: pointer to the opcode for OP_RECURSE, or NULL if not found +*/ + +static PCRE2_SPTR +find_recurse(PCRE2_SPTR code, BOOL utf) +{ +for (;;) + { + PCRE2_UCHAR c = *code; + if (c == OP_END) return NULL; + if (c == OP_RECURSE) return code; + + /* XCLASS is used for classes that cannot be represented just by a bit map. + This includes negated single high-valued characters. CALLOUT_STR is used for + callouts with string arguments. In both cases the length in the table is + zero; the actual length is stored in the compiled code. */ + + if (c == OP_XCLASS) code += GET(code, 1); + else if (c == OP_CALLOUT_STR) code += GET(code, 1 + 2*LINK_SIZE); + + /* Otherwise, we can get the item's length from the table, except that for + repeated character types, we have to test for \p and \P, which have an extra + two code units of parameters, and for MARK/PRUNE/SKIP/THEN with an argument, + we must add in its length. */ + + else + { + switch(c) + { + case OP_TYPESTAR: + case OP_TYPEMINSTAR: + case OP_TYPEPLUS: + case OP_TYPEMINPLUS: + case OP_TYPEQUERY: + case OP_TYPEMINQUERY: + case OP_TYPEPOSSTAR: + case OP_TYPEPOSPLUS: + case OP_TYPEPOSQUERY: + if (code[1] == OP_PROP || code[1] == OP_NOTPROP) code += 2; + break; + + case OP_TYPEPOSUPTO: + case OP_TYPEUPTO: + case OP_TYPEMINUPTO: + case OP_TYPEEXACT: + if (code[1 + IMM2_SIZE] == OP_PROP || code[1 + IMM2_SIZE] == OP_NOTPROP) + code += 2; + break; + + case OP_MARK: + case OP_PRUNE_ARG: + case OP_SKIP_ARG: + case OP_THEN_ARG: + code += code[1]; + break; + } + + /* Add in the fixed length from the table */ + + code += PRIV(OP_lengths)[c]; + + /* In UTF-8 and UTF-16 modes, opcodes that are followed by a character may + be followed by a multi-unit character. The length in the table is a + minimum, so we have to arrange to skip the extra units. */ + +#ifdef MAYBE_UTF_MULTI + if (utf) switch(c) + { + case OP_CHAR: + case OP_CHARI: + case OP_NOT: + case OP_NOTI: + case OP_EXACT: + case OP_EXACTI: + case OP_NOTEXACT: + case OP_NOTEXACTI: + case OP_UPTO: + case OP_UPTOI: + case OP_NOTUPTO: + case OP_NOTUPTOI: + case OP_MINUPTO: + case OP_MINUPTOI: + case OP_NOTMINUPTO: + case OP_NOTMINUPTOI: + case OP_POSUPTO: + case OP_POSUPTOI: + case OP_NOTPOSUPTO: + case OP_NOTPOSUPTOI: + case OP_STAR: + case OP_STARI: + case OP_NOTSTAR: + case OP_NOTSTARI: + case OP_MINSTAR: + case OP_MINSTARI: + case OP_NOTMINSTAR: + case OP_NOTMINSTARI: + case OP_POSSTAR: + case OP_POSSTARI: + case OP_NOTPOSSTAR: + case OP_NOTPOSSTARI: + case OP_PLUS: + case OP_PLUSI: + case OP_NOTPLUS: + case OP_NOTPLUSI: + case OP_MINPLUS: + case OP_MINPLUSI: + case OP_NOTMINPLUS: + case OP_NOTMINPLUSI: + case OP_POSPLUS: + case OP_POSPLUSI: + case OP_NOTPOSPLUS: + case OP_NOTPOSPLUSI: + case OP_QUERY: + case OP_QUERYI: + case OP_NOTQUERY: + case OP_NOTQUERYI: + case OP_MINQUERY: + case OP_MINQUERYI: + case OP_NOTMINQUERY: + case OP_NOTMINQUERYI: + case OP_POSQUERY: + case OP_POSQUERYI: + case OP_NOTPOSQUERY: + case OP_NOTPOSQUERYI: + if (HAS_EXTRALEN(code[-1])) code += GET_EXTRALEN(code[-1]); + break; + } +#else + (void)(utf); /* Keep compiler happy by referencing function argument */ +#endif /* MAYBE_UTF_MULTI */ + } + } +} + + + +/************************************************* +* Check for asserted fixed first code unit * +*************************************************/ + +/* During compilation, the "first code unit" settings from forward assertions +are discarded, because they can cause conflicts with actual literals that +follow. However, if we end up without a first code unit setting for an +unanchored pattern, it is worth scanning the regex to see if there is an +initial asserted first code unit. If all branches start with the same asserted +code unit, or with a non-conditional bracket all of whose alternatives start +with the same asserted code unit (recurse ad lib), then we return that code +unit, with the flags set to zero or REQ_CASELESS; otherwise return zero with +REQ_NONE in the flags. + +Arguments: + code points to start of compiled pattern + flags points to the first code unit flags + inassert TRUE if in an assertion + +Returns: the fixed first code unit, or 0 with REQ_NONE in flags +*/ + +static uint32_t +find_firstassertedcu(PCRE2_SPTR code, int32_t *flags, BOOL inassert) +{ +uint32_t c = 0; +int cflags = REQ_NONE; + +*flags = REQ_NONE; +do { + uint32_t d; + int dflags; + int xl = (*code == OP_CBRA || *code == OP_SCBRA || + *code == OP_CBRAPOS || *code == OP_SCBRAPOS)? IMM2_SIZE:0; + PCRE2_SPTR scode = first_significant_code(code + 1+LINK_SIZE + xl, TRUE); + PCRE2_UCHAR op = *scode; + + switch(op) + { + default: + return 0; + + case OP_BRA: + case OP_BRAPOS: + case OP_CBRA: + case OP_SCBRA: + case OP_CBRAPOS: + case OP_SCBRAPOS: + case OP_ASSERT: + case OP_ONCE: + case OP_ONCE_NC: + d = find_firstassertedcu(scode, &dflags, op == OP_ASSERT); + if (dflags < 0) + return 0; + if (cflags < 0) { c = d; cflags = dflags; } + else if (c != d || cflags != dflags) return 0; + break; + + case OP_EXACT: + scode += IMM2_SIZE; + /* Fall through */ + + case OP_CHAR: + case OP_PLUS: + case OP_MINPLUS: + case OP_POSPLUS: + if (!inassert) return 0; + if (cflags < 0) { c = scode[1]; cflags = 0; } + else if (c != scode[1]) return 0; + break; + + case OP_EXACTI: + scode += IMM2_SIZE; + /* Fall through */ + + case OP_CHARI: + case OP_PLUSI: + case OP_MINPLUSI: + case OP_POSPLUSI: + if (!inassert) return 0; + if (cflags < 0) { c = scode[1]; cflags = REQ_CASELESS; } + else if (c != scode[1]) return 0; + break; + } + + code += GET(code, 1); + } +while (*code == OP_ALT); + +*flags = cflags; +return c; +} + + + +/************************************************* +* Add an entry to the name/number table * +*************************************************/ + +/* This function is called between compiling passes to add an entry to the +name/number table, maintaining alphabetical order. Checking for permitted +and forbidden duplicates has already been done. + +Arguments: + cb the compile data block + name the name to add + length the length of the name + groupno the group number + tablecount the count of names in the table so far + +Returns: nothing +*/ + +static void +add_name_to_table(compile_block *cb, PCRE2_SPTR name, int length, + unsigned int groupno, uint32_t tablecount) +{ +uint32_t i; +PCRE2_UCHAR *slot = cb->name_table; + +for (i = 0; i < tablecount; i++) + { + int crc = memcmp(name, slot+IMM2_SIZE, CU2BYTES(length)); + if (crc == 0 && slot[IMM2_SIZE+length] != 0) + crc = -1; /* Current name is a substring */ + + /* Make space in the table and break the loop for an earlier name. For a + duplicate or later name, carry on. We do this for duplicates so that in the + simple case (when ?(| is not used) they are in order of their numbers. In all + cases they are in the order in which they appear in the pattern. */ + + if (crc < 0) + { + memmove(slot + cb->name_entry_size, slot, + CU2BYTES((tablecount - i) * cb->name_entry_size)); + break; + } + + /* Continue the loop for a later or duplicate name */ + + slot += cb->name_entry_size; + } + +PUT2(slot, 0, groupno); +memcpy(slot + IMM2_SIZE, name, CU2BYTES(length)); + +/* Add a terminating zero and fill the rest of the slot with zeroes so that +the memory is all initialized. Otherwise valgrind moans about uninitialized +memory when saving serialized compiled patterns. */ + +memset(slot + IMM2_SIZE + length, 0, + CU2BYTES(cb->name_entry_size - length - IMM2_SIZE)); +} + + + +/************************************************* +* Skip in parsed pattern * +*************************************************/ + +/* This function is called to skip parts of the parsed pattern when finding the +length of a lookbehind branch. It is called after (*ACCEPT) and (*FAIL) to find +the end of the branch, it is called to skip over an internal lookaround, and it +is also called to skip to the end of a class, during which it will never +encounter nested groups (but there's no need to have special code for that). + +Arguments: + pptr current pointer to skip from + skiptype PSKIP_CLASS when skipping to end of class + PSKIP_ALT when META_ALT ends the skip + PSKIP_KET when only META_KET ends the skip + +Returns: new value of pptr + NULL if META_END is reached - should never occur + or for an unknown meta value - likewise +*/ + +static uint32_t * +parsed_skip(uint32_t *pptr, uint32_t skiptype) +{ +uint32_t nestlevel = 0; + +for (pptr += 1;; pptr++) + { + uint32_t meta = META_CODE(*pptr); + + switch(meta) + { + default: /* Just skip over most items */ + if (meta < META_END) continue; /* Literal */ + break; + + /* This should never occur. */ + + case META_END: + return NULL; + + /* The data for these items is variable in length. */ + + case META_BACKREF: /* Offset is present only if group >= 10 */ + if (META_DATA(*pptr) >= 10) pptr += SIZEOFFSET; + break; + + case META_ESCAPE: /* A few escapes are followed by data items. */ + switch (META_DATA(*pptr)) + { + case ESC_P: + case ESC_p: + pptr += 1; + break; + + case ESC_g: + case ESC_k: + pptr += 1 + SIZEOFFSET; + break; + } + break; + + case META_MARK: /* Add the length of the name. */ + case META_PRUNE_ARG: + case META_SKIP_ARG: + case META_THEN_ARG: + pptr += pptr[1]; + break; + + /* These are the "active" items in this loop. */ + + case META_CLASS_END: + if (skiptype == PSKIP_CLASS) return pptr; + break; + + case META_ATOMIC: + case META_CAPTURE: + case META_COND_ASSERT: + case META_COND_DEFINE: + case META_COND_NAME: + case META_COND_NUMBER: + case META_COND_RNAME: + case META_COND_RNUMBER: + case META_COND_VERSION: + case META_LOOKAHEAD: + case META_LOOKAHEADNOT: + case META_LOOKBEHIND: + case META_LOOKBEHINDNOT: + case META_NOCAPTURE: + nestlevel++; + break; + + case META_ALT: + if (nestlevel == 0 && skiptype == PSKIP_ALT) return pptr; + break; + + case META_KET: + if (nestlevel == 0) return pptr; + nestlevel--; + break; + } -Returns: TRUE or FALSE -*/ + /* The extra data item length for each meta is in a table. */ -static BOOL -is_anchored(register PCRE2_SPTR code, unsigned int bracket_map, - compile_block *cb, int atomcount) -{ -do { - PCRE2_SPTR scode = first_significant_code( - code + PRIV(OP_lengths)[*code], FALSE); - register int op = *scode; + meta = (meta >> 16) & 0x7fff; + if (meta >= sizeof(meta_extra_lengths)) return NULL; + pptr += meta_extra_lengths[meta]; + } +/* Control never reaches here */ +return pptr; +} - /* Non-capturing brackets */ - if (op == OP_BRA || op == OP_BRAPOS || - op == OP_SBRA || op == OP_SBRAPOS) - { - if (!is_anchored(scode, bracket_map, cb, atomcount)) return FALSE; - } - /* Capturing brackets */ +/************************************************* +* Find length of a parsed group * +*************************************************/ - else if (op == OP_CBRA || op == OP_CBRAPOS || - op == OP_SCBRA || op == OP_SCBRAPOS) - { - int n = GET2(scode, 1+LINK_SIZE); - int new_map = bracket_map | ((n < 32)? (1u << n) : 1); - if (!is_anchored(scode, new_map, cb, atomcount)) return FALSE; - } +/* This is called for nested groups within a branch of a lookbehind whose +length is being computed. If all the branches in the nested group have the same +length, that is OK. On entry, the pointer must be at the first element after +the group initializing code. Caching is used to improve processing speed when +the same capturing group occurs many times. - /* Positive forward assertions and conditions */ +Arguments: + pptrptr pointer to pointer in the parsed pattern + errcodeptr pointer to the errorcode + lcptr pointer to the loop counter + group number of captured group or -1 for a non-capturing group + recurses chain of recurse_check to catch mutual recursion + cb pointer to the compile data - else if (op == OP_ASSERT || op == OP_COND) - { - if (!is_anchored(scode, bracket_map, cb, atomcount)) return FALSE; - } +Returns: the group length or a negative number +*/ - /* Atomic groups */ +static int +get_grouplength(uint32_t **pptrptr, int *errcodeptr, int *lcptr, + int group, parsed_recurse_check *recurses, compile_block *cb) +{ +int branchlength; +int grouplength = -1; - else if (op == OP_ONCE || op == OP_ONCE_NC) - { - if (!is_anchored(scode, bracket_map, cb, atomcount + 1)) - return FALSE; - } +/* The cache can be used only if there is no possibility of there being two +groups with the same number. */ - /* .* is not anchored unless DOTALL is set (which generates OP_ALLANY) and - it isn't in brackets that are or may be referenced or inside an atomic - group. There is also an option that disables auto-anchoring. */ +if (group > 0) + { + uint32_t groupinfo = cb->groupinfo[group]; + if ((cb->external_flags & PCRE2_DUPCAPUSED) == 0) + { + if ((groupinfo & GI_NOT_FIXED_LENGTH) != 0) return -1; + if ((groupinfo & GI_SET_FIXED_LENGTH) != 0) + return groupinfo & GI_FIXED_LENGTH_MASK; + } + } - else if ((op == OP_TYPESTAR || op == OP_TYPEMINSTAR || - op == OP_TYPEPOSSTAR)) - { - if (scode[1] != OP_ALLANY || (bracket_map & cb->backref_map) != 0 || - atomcount > 0 || cb->had_pruneorskip || - (cb->external_options & PCRE2_NO_DOTSTAR_ANCHOR) != 0) - return FALSE; - } +/* Scan the group */ - /* Check for explicit anchoring */ +for(;;) + { + branchlength = get_branchlength(pptrptr, errcodeptr, lcptr, recurses, cb); + if (branchlength < 0) goto ISNOTFIXED; + if (grouplength == -1) grouplength = branchlength; + else if (grouplength != branchlength) goto ISNOTFIXED; + if (**pptrptr == META_KET) break; + *pptrptr += 1; /* Skip META_ALT */ + } - else if (op != OP_SOD && op != OP_SOM && op != OP_CIRC) return FALSE; +if (group > 0) + cb->groupinfo[group] |= (uint32_t)(GI_SET_FIXED_LENGTH | grouplength); +return grouplength; - code += GET(code, 1); - } -while (*code == OP_ALT); /* Loop for each alternative */ -return TRUE; +ISNOTFIXED: +if (group > 0) cb->groupinfo[group] |= GI_NOT_FIXED_LENGTH; +return -1; } /************************************************* -* Check for starting with ^ or .* * +* Find length of a parsed branch * *************************************************/ -/* This is called to find out if every branch starts with ^ or .* so that -"first char" processing can be done to speed things up in multiline -matching and for non-DOTALL patterns that start with .* (which must start at -the beginning or after \n). As in the case of is_anchored() (see above), we -have to take account of back references to capturing brackets that contain .* -because in that case we can't make the assumption. Also, the appearance of .* -inside atomic brackets or in a pattern that contains *PRUNE or *SKIP does not -count, because once again the assumption no longer holds. +/* Return a fixed length for a branch in a lookbehind, giving an error if the +length is not fixed. If any lookbehinds are encountered on the way, they get +their length set. On entry, *pptrptr points to the first element inside the +branch. On exit it is set to point to the ALT or KET. Arguments: - code points to start of the compiled pattern or a group - bracket_map a bitmap of which brackets we are inside while testing; this - handles up to substring 31; after that we just have to take - the less precise approach - cb points to the compile data - atomcount atomic group level + pptrptr pointer to pointer in the parsed pattern + errcodeptr pointer to error code + lcptr pointer to loop counter + recurses chain of recurse_check to catch mutual recursion + cb pointer to compile block -Returns: TRUE or FALSE +Returns: the length, or a negative value on error */ -static BOOL -is_startline(PCRE2_SPTR code, unsigned int bracket_map, compile_block *cb, - int atomcount) +static int +get_branchlength(uint32_t **pptrptr, int *errcodeptr, int *lcptr, + parsed_recurse_check *recurses, compile_block *cb) { -do { - PCRE2_SPTR scode = first_significant_code( - code + PRIV(OP_lengths)[*code], FALSE); - register int op = *scode; +int branchlength = 0; +int grouplength; +uint32_t lastitemlength = 0; +uint32_t *pptr = *pptrptr; +PCRE2_SIZE offset; +parsed_recurse_check this_recurse; - /* If we are at the start of a conditional assertion group, *both* the - conditional assertion *and* what follows the condition must satisfy the test - for start of line. Other kinds of condition fail. Note that there may be an - auto-callout at the start of a condition. */ +/* A large and/or complex regex can take too long to process. This can happen +more often when (?| groups are present in the pattern because their length +cannot be cached. */ - if (op == OP_COND) - { - scode += 1 + LINK_SIZE; +if ((*lcptr)++ > 2000) + { + *errcodeptr = ERR35; /* Lookbehind is too complicated */ + return -1; + } - if (*scode == OP_CALLOUT) scode += PRIV(OP_lengths)[OP_CALLOUT]; - else if (*scode == OP_CALLOUT_STR) scode += GET(scode, 1 + 2*LINK_SIZE); +/* Scan the branch, accumulating the length. */ - switch (*scode) - { - case OP_CREF: - case OP_DNCREF: - case OP_RREF: - case OP_DNRREF: - case OP_FAIL: - case OP_FALSE: - case OP_TRUE: - return FALSE; +for (;; pptr++) + { + parsed_recurse_check *r; + uint32_t *gptr, *gptrend; + uint32_t escape; + uint32_t group = 0; + uint32_t itemlength = 0; - default: /* Assertion */ - if (!is_startline(scode, bracket_map, cb, atomcount)) return FALSE; - do scode += GET(scode, 1); while (*scode == OP_ALT); - scode += 1 + LINK_SIZE; - break; - } - scode = first_significant_code(scode, FALSE); - op = *scode; - } + if (*pptr < META_END) + { + itemlength = 1; + } - /* Non-capturing brackets */ + else switch (META_CODE(*pptr)) + { + case META_KET: + case META_ALT: + goto EXIT; + + /* (*ACCEPT) and (*FAIL) terminate the branch, but we must skip to the + actual termination. */ + + case META_ACCEPT: + case META_FAIL: + pptr = parsed_skip(pptr, PSKIP_ALT); + if (pptr == NULL) goto PARSED_SKIP_FAILED; + goto EXIT; + + case META_MARK: + case META_PRUNE_ARG: + case META_SKIP_ARG: + case META_THEN_ARG: + pptr += pptr[1] + 1; + break; - if (op == OP_BRA || op == OP_BRAPOS || - op == OP_SBRA || op == OP_SBRAPOS) - { - if (!is_startline(scode, bracket_map, cb, atomcount)) return FALSE; - } + case META_CIRCUMFLEX: + case META_COMMIT: + case META_DOLLAR: + case META_PRUNE: + case META_SKIP: + case META_THEN: + break; - /* Capturing brackets */ + case META_OPTIONS: + pptr += 1; + break; - else if (op == OP_CBRA || op == OP_CBRAPOS || - op == OP_SCBRA || op == OP_SCBRAPOS) - { - int n = GET2(scode, 1+LINK_SIZE); - int new_map = bracket_map | ((n < 32)? (1u << n) : 1); - if (!is_startline(scode, new_map, cb, atomcount)) return FALSE; - } + case META_BIGVALUE: + itemlength = 1; + pptr += 1; + break; - /* Positive forward assertions */ + case META_CLASS: + case META_CLASS_NOT: + itemlength = 1; + pptr = parsed_skip(pptr, PSKIP_CLASS); + if (pptr == NULL) goto PARSED_SKIP_FAILED; + break; - else if (op == OP_ASSERT) - { - if (!is_startline(scode, bracket_map, cb, atomcount)) return FALSE; - } + case META_CLASS_EMPTY_NOT: + case META_DOT: + itemlength = 1; + break; - /* Atomic brackets */ + case META_CALLOUT_NUMBER: + pptr += 3; + break; - else if (op == OP_ONCE || op == OP_ONCE_NC) - { - if (!is_startline(scode, bracket_map, cb, atomcount + 1)) return FALSE; - } + case META_CALLOUT_STRING: + pptr += 3 + SIZEOFFSET; + break; - /* .* means "start at start or after \n" if it isn't in atomic brackets or - brackets that may be referenced, as long as the pattern does not contain - *PRUNE or *SKIP, because these break the feature. Consider, for example, - /.*?a(*PRUNE)b/ with the subject "aab", which matches "ab", i.e. not at the - start of a line. There is also an option that disables this optimization. */ + /* Only some escapes consume a character. Of those, \R and \X are never + allowed because they might match more than character. \C is allowed only in + 32-bit and non-UTF 8/16-bit modes. */ - else if (op == OP_TYPESTAR || op == OP_TYPEMINSTAR || op == OP_TYPEPOSSTAR) - { - if (scode[1] != OP_ANY || (bracket_map & cb->backref_map) != 0 || - atomcount > 0 || cb->had_pruneorskip || - (cb->external_options & PCRE2_NO_DOTSTAR_ANCHOR) != 0) - return FALSE; - } + case META_ESCAPE: + escape = META_DATA(*pptr); + if (escape == ESC_R || escape == ESC_X) return -1; + if (escape > ESC_b && escape < ESC_Z) + { +#if PCRE2_CODE_UNIT_WIDTH != 32 + if ((cb->external_options & PCRE2_UTF) != 0 && escape == ESC_C) + { + *errcodeptr = ERR36; + return -1; + } +#endif + itemlength = 1; + if (escape == ESC_p || escape == ESC_P) pptr++; /* Skip prop data */ + } + break; - /* Check for explicit circumflex; anything else gives a FALSE result. Note - in particular that this includes atomic brackets OP_ONCE and OP_ONCE_NC - because the number of characters matched by .* cannot be adjusted inside - them. */ + /* Lookaheads can be ignored. */ - else if (op != OP_CIRC && op != OP_CIRCM) return FALSE; + case META_LOOKAHEAD: + case META_LOOKAHEADNOT: + pptr = parsed_skip(pptr, PSKIP_KET); + if (pptr == NULL) goto PARSED_SKIP_FAILED; + break; - /* Move on to the next alternative */ + /* Lookbehinds can be ignored, but must themselves be checked. */ - code += GET(code, 1); - } -while (*code == OP_ALT); /* Loop for each alternative */ -return TRUE; -} + case META_LOOKBEHIND: + case META_LOOKBEHINDNOT: + if (!set_lookbehind_lengths(&pptr, errcodeptr, lcptr, recurses, cb)) + return -1; + break; + /* Back references and recursions are handled by very similar code. At this + stage, the names generated in the parsing pass are available, but the main + name table has not yet been created. So for the named varieties, scan the + list of names in order to get the number of the first one in the pattern, + and whether or not this name is duplicated. */ + case META_BACKREF_BYNAME: + if ((cb->external_options & PCRE2_MATCH_UNSET_BACKREF) != 0) + goto ISNOTFIXED; -/************************************************* -* Check for asserted fixed first code unit * -*************************************************/ + case META_RECURSE_BYNAME: + { + int i; + PCRE2_SPTR name; + BOOL is_dupname = FALSE; + named_group *ng = cb->named_groups; + uint32_t meta_code = META_CODE(*pptr); + uint32_t length = *(++pptr); -/* During compilation, the "first code unit" settings from forward assertions -are discarded, because they can cause conflicts with actual literals that -follow. However, if we end up without a first code unit setting for an -unanchored pattern, it is worth scanning the regex to see if there is an -initial asserted first code unit. If all branches start with the same asserted -code unit, or with a non-conditional bracket all of whose alternatives start -with the same asserted code unit (recurse ad lib), then we return that code -unit, with the flags set to zero or REQ_CASELESS; otherwise return zero with -REQ_NONE in the flags. + GETPLUSOFFSET(offset, pptr); + name = cb->start_pattern + offset; + for (i = 0; i < cb->names_found; i++, ng++) + { + if (length == ng->length && PRIV(strncmp)(name, ng->name, length) == 0) + { + group = ng->number; + is_dupname = ng->isdup; + break; + } + } -Arguments: - code points to start of compiled pattern - flags points to the first code unit flags - inassert TRUE if in an assertion + if (group == 0) + { + *errcodeptr = ERR15; /* Non-existent subpattern */ + cb->erroroffset = offset; + return -1; + } -Returns: the fixed first code unit, or 0 with REQ_NONE in flags -*/ + /* A numerical back reference can be fixed length if duplicate capturing + groups are not being used. A non-duplicate named back reference can also + be handled. */ -static uint32_t -find_firstassertedcu(PCRE2_SPTR code, int32_t *flags, BOOL inassert) -{ -register uint32_t c = 0; -int cflags = REQ_NONE; + if (meta_code == META_RECURSE_BYNAME || + (!is_dupname && (cb->external_flags & PCRE2_DUPCAPUSED) == 0)) + goto RECURSE_OR_BACKREF_LENGTH; /* Handle as a numbered version. */ + } + goto ISNOTFIXED; /* Duplicate name or number */ -*flags = REQ_NONE; -do { - uint32_t d; - int dflags; - int xl = (*code == OP_CBRA || *code == OP_SCBRA || - *code == OP_CBRAPOS || *code == OP_SCBRAPOS)? IMM2_SIZE:0; - PCRE2_SPTR scode = first_significant_code(code + 1+LINK_SIZE + xl, TRUE); - register PCRE2_UCHAR op = *scode; + /* The offset values for back references < 10 are in a separate vector + because otherwise they would use more than two parsed pattern elements on + 64-bit systems. */ - switch(op) - { - default: - return 0; + case META_BACKREF: + if ((cb->external_options & PCRE2_MATCH_UNSET_BACKREF) != 0 || + (cb->external_flags & PCRE2_DUPCAPUSED) != 0) + goto ISNOTFIXED; + group = META_DATA(*pptr); + if (group < 10) + { + offset = cb->small_ref_offset[group]; + goto RECURSE_OR_BACKREF_LENGTH; + } - case OP_BRA: - case OP_BRAPOS: - case OP_CBRA: - case OP_SCBRA: - case OP_CBRAPOS: - case OP_SCBRAPOS: - case OP_ASSERT: - case OP_ONCE: - case OP_ONCE_NC: - d = find_firstassertedcu(scode, &dflags, op == OP_ASSERT); - if (dflags < 0) - return 0; - if (cflags < 0) { c = d; cflags = dflags; } - else if (c != d || cflags != dflags) return 0; - break; + /* Fall through for groups >= 10 - picking up group twice does no harm. */ + + /* A true recursion implies not fixed length, but a subroutine call may + be OK. Back reference "recursions" are also failed. */ + + case META_RECURSE: + group = META_DATA(*pptr); + GETPLUSOFFSET(offset, pptr); + + RECURSE_OR_BACKREF_LENGTH: + if (group > cb->bracount) + { + cb->erroroffset = offset; + *errcodeptr = ERR15; /* Non-existent subpattern */ + return -1; + } + if (group == 0) goto ISNOTFIXED; /* Local recursion */ + for (gptr = cb->parsed_pattern; *gptr != META_END; gptr++) + { + if (META_CODE(*gptr) == META_BIGVALUE) gptr++; + else if (*gptr == (META_CAPTURE | group)) break; + } + + gptrend = parsed_skip(gptr, PSKIP_KET); + if (gptrend == NULL) goto PARSED_SKIP_FAILED; + if (pptr > gptr && pptr < gptrend) goto ISNOTFIXED; /* Local recursion */ + for (r = recurses; r != NULL; r = r->prev) if (r->groupptr == gptr) break; + if (r != NULL) goto ISNOTFIXED; /* Mutual recursion */ + this_recurse.prev = recurses; + this_recurse.groupptr = gptr; + gptr++; + grouplength = get_grouplength(&gptr, errcodeptr, lcptr, group, + &this_recurse, cb); + if (grouplength < 0) + { + if (*errcodeptr == 0) goto ISNOTFIXED; + return -1; /* Error already set */ + } + itemlength = grouplength; + break; + + /* Check nested groups - advance past the initial data for each type and + then seek a fixed length with get_grouplength(). */ + + case META_COND_NAME: + case META_COND_NUMBER: + case META_COND_RNAME: + case META_COND_RNUMBER: + case META_COND_DEFINE: + pptr += 2 + SIZEOFFSET; + goto CHECK_GROUP; + + case META_COND_ASSERT: + pptr += 1; + goto CHECK_GROUP; - case OP_EXACT: - scode += IMM2_SIZE; - /* Fall through */ + case META_COND_VERSION: + pptr += 4; + goto CHECK_GROUP; - case OP_CHAR: - case OP_PLUS: - case OP_MINPLUS: - case OP_POSPLUS: - if (!inassert) return 0; - if (cflags < 0) { c = scode[1]; cflags = 0; } - else if (c != scode[1]) return 0; - break; + case META_CAPTURE: + group = META_DATA(*pptr); + /* Fall through */ - case OP_EXACTI: - scode += IMM2_SIZE; - /* Fall through */ + case META_ATOMIC: + case META_NOCAPTURE: + pptr++; + CHECK_GROUP: + grouplength = get_grouplength(&pptr, errcodeptr, lcptr, group, recurses, cb); + if (grouplength < 0) return -1; + itemlength = grouplength; + break; - case OP_CHARI: - case OP_PLUSI: - case OP_MINPLUSI: - case OP_POSPLUSI: - if (!inassert) return 0; - if (cflags < 0) { c = scode[1]; cflags = REQ_CASELESS; } - else if (c != scode[1]) return 0; - break; - } + /* Exact repetition is OK; variable repetition is not. A repetition of zero + must subtract the length that has already been added. */ - code += GET(code, 1); - } -while (*code == OP_ALT); + case META_MINMAX: + case META_MINMAX_PLUS: + case META_MINMAX_QUERY: + if (pptr[1] == pptr[2]) + { + if (pptr[1] == 0) branchlength -= lastitemlength; + else itemlength = (pptr[1] - 1) * lastitemlength; + pptr += 2; + break; + } + /* Fall through */ -*flags = cflags; -return c; + /* Any other item means this branch does not have a fixed length. */ + + default: + ISNOTFIXED: + *errcodeptr = ERR25; /* Not fixed length */ + return -1; + } + + /* Add the item length to the branchlength, and save it for use if the next + thing is a quantifier. */ + + branchlength += itemlength; + lastitemlength = itemlength; + + /* Ensure that the length does not overflow the limit. */ + + if (branchlength > LOOKBEHIND_MAX) + { + *errcodeptr = ERR87; + return -1; + } + } + +EXIT: +*pptrptr = pptr; +if (branchlength > cb->max_lookbehind) cb->max_lookbehind = branchlength; +return branchlength; + +PARSED_SKIP_FAILED: +*errcodeptr = ERR90; +return -1; } /************************************************* -* Add an entry to the name/number table * +* Set lengths in a lookbehind * *************************************************/ -/* This function is called between compiling passes to add an entry to the -name/number table, maintaining alphabetical order. Checking for permitted -and forbidden duplicates has already been done. +/* This function is called for each lookbehind, to set the lengths in its +branches. An error occurs if any branch does not have a fixed length that is +less than the maximum (65535). On exit, the pointer must be left on the final +ket. Arguments: - cb the compile data block - name the name to add - length the length of the name - groupno the group number + pptrptr pointer to pointer in the parsed pattern + errcodeptr pointer to error code + lcptr pointer to loop counter + recurses chain of recurse_check to catch mutual recursion + cb pointer to compile block -Returns: nothing +Returns: TRUE if all is well + FALSE otherwise, with error code and offset set */ -static void -add_name_to_table(compile_block *cb, PCRE2_SPTR name, int length, - unsigned int groupno) +static BOOL +set_lookbehind_lengths(uint32_t **pptrptr, int *errcodeptr, int *lcptr, + parsed_recurse_check *recurses, compile_block *cb) { -int i; -PCRE2_UCHAR *slot = cb->name_table; +PCRE2_SIZE offset; +int branchlength; +uint32_t *bptr = *pptrptr; -for (i = 0; i < cb->names_found; i++) +READPLUSOFFSET(offset, bptr); /* Offset for error messages */ +*pptrptr += SIZEOFFSET; + +do { - int crc = memcmp(name, slot+IMM2_SIZE, CU2BYTES(length)); - if (crc == 0 && slot[IMM2_SIZE+length] != 0) - crc = -1; /* Current name is a substring */ + *pptrptr += 1; + branchlength = get_branchlength(pptrptr, errcodeptr, lcptr, recurses, cb); + if (branchlength < 0) + { + /* The errorcode and offset may already be set from a nested lookbehind. */ + if (*errcodeptr == 0) *errcodeptr = ERR25; + if (cb->erroroffset == PCRE2_UNSET) cb->erroroffset = offset; + return FALSE; + } + *bptr |= branchlength; /* branchlength never more than 65535 */ + bptr = *pptrptr; + } +while (*bptr == META_ALT); - /* Make space in the table and break the loop for an earlier name. For a - duplicate or later name, carry on. We do this for duplicates so that in the - simple case (when ?(| is not used) they are in order of their numbers. In all - cases they are in the order in which they appear in the pattern. */ +return TRUE; +} - if (crc < 0) + + +/************************************************* +* Check parsed pattern lookbehinds * +*************************************************/ + +/* This function is called at the end of parsing a pattern if any lookbehinds +were encountered. It scans the parsed pattern for them, calling +set_lookbehind_lengths() for each one. At the start, the errorcode is zero and +the error offset is marked unset. The enables the functions above not to +override settings from deeper nestings. + +Arguments cb points to the compile block +Returns: 0 on success, or an errorcode (cb->erroroffset will be set) +*/ + +static int +check_lookbehinds(compile_block *cb) +{ +uint32_t *pptr; +int errorcode = 0; +int loopcount = 0; + +cb->erroroffset = PCRE2_UNSET; + +for (pptr = cb->parsed_pattern; *pptr != META_END; pptr++) + { + if (*pptr < META_END) continue; /* Literal */ + + switch (META_CODE(*pptr)) { - memmove(slot + cb->name_entry_size, slot, - CU2BYTES((cb->names_found - i) * cb->name_entry_size)); + default: + return ERR70; /* Unrecognized meta code */ + + case META_ESCAPE: + if (*pptr - META_ESCAPE == ESC_P || *pptr - META_ESCAPE == ESC_p) + pptr += 1; break; - } - /* Continue the loop for a later or duplicate name */ + case META_ACCEPT: + case META_ALT: + case META_ASTERISK: + case META_ASTERISK_PLUS: + case META_ASTERISK_QUERY: + case META_ATOMIC: + case META_BACKREF: + case META_CAPTURE: + case META_CIRCUMFLEX: + case META_CLASS: + case META_CLASS_EMPTY: + case META_CLASS_EMPTY_NOT: + case META_CLASS_END: + case META_CLASS_NOT: + case META_COMMIT: + case META_COND_ASSERT: + case META_DOLLAR: + case META_DOT: + case META_FAIL: + case META_KET: + case META_LOOKAHEAD: + case META_LOOKAHEADNOT: + case META_NOCAPTURE: + case META_PLUS: + case META_PLUS_PLUS: + case META_PLUS_QUERY: + case META_PRUNE: + case META_QUERY: + case META_QUERY_PLUS: + case META_QUERY_QUERY: + case META_RANGE_ESCAPED: + case META_RANGE_LITERAL: + case META_SKIP: + case META_THEN: + break; - slot += cb->name_entry_size; - } + case META_RECURSE: + pptr += SIZEOFFSET; + break; -PUT2(slot, 0, groupno); -memcpy(slot + IMM2_SIZE, name, CU2BYTES(length)); -cb->names_found++; + case META_BACKREF_BYNAME: + case META_COND_DEFINE: + case META_COND_NAME: + case META_COND_NUMBER: + case META_COND_RNAME: + case META_COND_RNUMBER: + case META_RECURSE_BYNAME: + pptr += 1 + SIZEOFFSET; + break; -/* Add a terminating zero and fill the rest of the slot with zeroes so that -the memory is all initialized. Otherwise valgrind moans about uninitialized -memory when saving serialized compiled patterns. */ + case META_CALLOUT_STRING: + pptr += 3 + SIZEOFFSET; + break; -memset(slot + IMM2_SIZE + length, 0, - CU2BYTES(cb->name_entry_size - length - IMM2_SIZE)); + case META_BIGVALUE: + case META_OPTIONS: + case META_POSIX: + case META_POSIX_NEG: + pptr += 1; + break; + + case META_MINMAX: + case META_MINMAX_QUERY: + case META_MINMAX_PLUS: + pptr += 2; + break; + + case META_CALLOUT_NUMBER: + case META_COND_VERSION: + pptr += 3; + break; + + case META_MARK: + case META_PRUNE_ARG: + case META_SKIP_ARG: + case META_THEN_ARG: + pptr += 1 + pptr[1]; + break; + + case META_LOOKBEHIND: + case META_LOOKBEHINDNOT: + if (!set_lookbehind_lengths(&pptr, &errorcode, &loopcount, NULL, cb)) + return errorcode; + break; + } + } + +return 0; } @@ -8316,43 +8763,50 @@ PCRE2_EXP_DEFN pcre2_code * PCRE2_CALL_CONVENTION pcre2_compile(PCRE2_SPTR pattern, PCRE2_SIZE patlen, uint32_t options, int *errorptr, PCRE2_SIZE *erroroffset, pcre2_compile_context *ccontext) { -BOOL utf; /* Set TRUE for UTF mode */ -pcre2_real_code *re = NULL; /* What we will return */ -compile_block cb; /* "Static" compile-time data */ -const uint8_t *tables; /* Char tables base pointer */ - -PCRE2_UCHAR *code; /* Current pointer in compiled code */ -PCRE2_SPTR codestart; /* Start of compiled code */ -PCRE2_SPTR ptr; /* Current pointer in pattern */ - -size_t length = 1; /* Allow or final END opcode */ -size_t usedlength; /* Actual length used */ -size_t re_blocksize; /* Size of memory block */ - -int32_t firstcuflags, reqcuflags; /* Type of first/req code unit */ -uint32_t firstcu, reqcu; /* Value of first/req code unit */ -uint32_t setflags = 0; /* NL and BSR set flags */ - -uint32_t skipatstart; /* When checking (*UTF) etc */ -uint32_t limit_match = UINT32_MAX; /* Unset match limits */ +BOOL utf; /* Set TRUE for UTF mode */ +BOOL has_lookbehind; /* Set TRUE if a lookbehind is found */ +BOOL zero_terminated; /* Set TRUE for zero-terminated pattern */ +pcre2_real_code *re = NULL; /* What we will return */ +compile_block cb; /* "Static" compile-time data */ +const uint8_t *tables; /* Char tables base pointer */ + +PCRE2_UCHAR *code; /* Current pointer in compiled code */ +PCRE2_SPTR codestart; /* Start of compiled code */ +PCRE2_SPTR ptr; /* Current pointer in pattern */ +uint32_t *pptr; /* Current pointer in parsed pattern */ + +PCRE2_SIZE length = 1; /* Allow for final END opcode */ +PCRE2_SIZE usedlength; /* Actual length used */ +PCRE2_SIZE re_blocksize; /* Size of memory block */ +PCRE2_SIZE big32count = 0; /* 32-bit literals >= 0x80000000 */ +PCRE2_SIZE parsed_size_needed; /* Needed for parsed pattern */ + +int32_t firstcuflags, reqcuflags; /* Type of first/req code unit */ +uint32_t firstcu, reqcu; /* Value of first/req code unit */ +uint32_t setflags = 0; /* NL and BSR set flags */ + +uint32_t skipatstart; /* When checking (*UTF) etc */ +uint32_t limit_match = UINT32_MAX; /* Unset match limits */ uint32_t limit_recursion = UINT32_MAX; -int newline = 0; /* Unset; can be set by the pattern */ -int bsr = 0; /* Unset; can be set by the pattern */ -int errorcode = 0; /* Initialize to avoid compiler warn */ +int newline = 0; /* Unset; can be set by the pattern */ +int bsr = 0; /* Unset; can be set by the pattern */ +int errorcode = 0; /* Initialize to avoid compiler warn */ +int regexrc; /* Return from compile */ + +uint32_t i; /* Local loop counter */ /* Comments at the head of this file explain about these variables. */ -PCRE2_UCHAR *copied_pattern = NULL; -PCRE2_UCHAR stack_copied_pattern[COPIED_PATTERN_SIZE]; +uint32_t stack_groupinfo[GROUPINFO_DEFAULT_SIZE]; +uint32_t stack_parsed_pattern[PARSED_PATTERN_DEFAULT_SIZE]; named_group named_groups[NAMED_GROUP_LIST_SIZE]; /* The workspace is used in different ways in the different compiling phases. -It needs to be 16-bit aligned for the preliminary group scan, and 32-bit -aligned for the group information cache. */ +It needs to be 16-bit aligned for the preliminary parsing scan. */ -uint32_t c32workspace[C32_WORK_SIZE]; -PCRE2_UCHAR *cworkspace = (PCRE2_UCHAR *)c32workspace; +uint32_t c16workspace[C16_WORK_SIZE]; +PCRE2_UCHAR *cworkspace = (PCRE2_UCHAR *)c16workspace; /* -------------- Check arguments and set up the pattern ----------------- */ @@ -8385,43 +8839,21 @@ if (ccontext == NULL) ccontext = (pcre2_compile_context *)(&PRIV(default_compile_context)); /* A zero-terminated pattern is indicated by the special length value -PCRE2_ZERO_TERMINATED. Otherwise, we make a copy of the pattern and add a zero, -to ensure that it is always possible to look one code unit beyond the end of -the pattern's characters. In both cases, check that the pattern is overlong. */ +PCRE2_ZERO_TERMINATED. Check for an overlong pattern. */ -if (patlen == PCRE2_ZERO_TERMINATED) - { +if ((zero_terminated = (patlen == PCRE2_ZERO_TERMINATED))) patlen = PRIV(strlen)(pattern); - if (patlen > ccontext->max_pattern_length) - { - *errorptr = ERR88; - return NULL; - } - } -else + +if (patlen > ccontext->max_pattern_length) { - if (patlen > ccontext->max_pattern_length) - { - *errorptr = ERR88; - return NULL; - } - if (patlen < COPIED_PATTERN_SIZE) - copied_pattern = stack_copied_pattern; - else - { - copied_pattern = ccontext->memctl.malloc(CU2BYTES(patlen + 1), - ccontext->memctl.memory_data); - if (copied_pattern == NULL) - { - *errorptr = ERR21; - return NULL; - } - } - memcpy(copied_pattern, pattern, CU2BYTES(patlen)); - copied_pattern[patlen] = 0; - pattern = copied_pattern; + *errorptr = ERR88; + return NULL; } +/* From here on, all returns from this function should end up going via the +EXIT label. */ + + /* ------------ Initialize the "static" compile data -------------- */ tables = (ccontext->tables != NULL)? ccontext->tables : PRIV(default_tables); @@ -8432,16 +8864,16 @@ cb.cbits = tables + cbits_offset; /* tables */ cb.ctypes = tables + ctypes_offset; cb.assert_depth = 0; -cb.bracount = cb.final_bracount = 0; +cb.bracount = 0; cb.cx = ccontext; cb.dupnames = FALSE; cb.end_pattern = pattern + patlen; -cb.nestptr[0] = cb.nestptr[1] = NULL; +cb.erroroffset = 0; cb.external_flags = 0; cb.external_options = options; -cb.groupinfo = c32workspace; +cb.groupinfo = stack_groupinfo; cb.had_recurse = FALSE; -cb.iscondassert = FALSE; +cb.lastcapture = 0; cb.max_lookbehind = 0; cb.name_entry_size = 0; cb.name_table = NULL; @@ -8450,6 +8882,7 @@ cb.named_group_list_size = NAMED_GROUP_LIST_SIZE; cb.names_found = 0; cb.open_caps = NULL; cb.parens_depth = 0; +cb.parsed_pattern = stack_parsed_pattern; cb.req_varyopt = 0; cb.start_code = cworkspace; cb.start_pattern = pattern; @@ -8463,23 +8896,43 @@ references to help in deciding whether (.*) can be treated as anchored or not. cb.top_backref = 0; cb.backref_map = 0; +/* Escape sequences \1 to \9 are always back references, but as they are only +two characters long, only two elements can be used in the parsed_pattern +vector. The first contains the reference, and we'd like to use the second to +record the offset in the pattern, so that forward references to non-existent +groups can be diagnosed later with an offset. However, on 64-bit systems, +PCRE2_SIZE won't fit. Instead, we have a vector of offsets for the first +occurrence of \1 to \9, indexed by the second parsed_pattern value. All other +references have enough space for the offset to be put into the parsed pattern. +*/ + +for (i = 0; i < 10; i++) cb.small_ref_offset[i] = PCRE2_UNSET; + + /* --------------- Start looking at the pattern --------------- */ /* Check for global one-time option settings at the start of the pattern, and -remember the offset to the actual regex. */ +remember the offset to the actual regex. With valgrind support, make the +terminator of a zero-terminated pattern inaccessible. This catches bugs that +would otherwise only show up for non-zero-terminated patterns. */ + +#ifdef SUPPORT_VALGRIND +if (zero_terminated) VALGRIND_MAKE_MEM_NOACCESS(pattern + patlen, CU2BYTES(1)); +#endif ptr = pattern; skipatstart = 0; -while (ptr[skipatstart] == CHAR_LEFT_PARENTHESIS && +while (patlen - skipatstart >= 2 && + ptr[skipatstart] == CHAR_LEFT_PARENTHESIS && ptr[skipatstart+1] == CHAR_ASTERISK) { - unsigned int i; for (i = 0; i < sizeof(pso_list)/sizeof(pso); i++) { pso *p = pso_list + i; - if (PRIV(strncmp_c8)(ptr+skipatstart+2, (char *)(p->name), p->length) == 0) + if (patlen - skipatstart - 2 >= p->length && + PRIV(strncmp_c8)(ptr+skipatstart+2, (char *)(p->name), p->length) == 0) { uint32_t c, pp; @@ -8512,7 +8965,7 @@ while (ptr[skipatstart] == CHAR_LEFT_PARENTHESIS && { errorcode = ERR60; ptr += pp; - goto HAD_ERROR; + goto HAD_EARLY_ERROR; } while (IS_DIGIT(ptr[pp])) { @@ -8523,7 +8976,7 @@ while (ptr[skipatstart] == CHAR_LEFT_PARENTHESIS && { errorcode = ERR60; ptr += pp; - goto HAD_ERROR; + goto HAD_EARLY_ERROR; } if (p->type == PSO_LIMM) limit_match = c; else limit_recursion = c; @@ -8546,7 +8999,7 @@ ptr += skipatstart; if ((cb.external_options & (PCRE2_UTF|PCRE2_UCP)) != 0) { errorcode = ERR32; - goto HAD_ERROR; + goto HAD_EARLY_ERROR; } #endif @@ -8559,11 +9012,11 @@ if (utf) if ((options & PCRE2_NEVER_UTF) != 0) { errorcode = ERR74; - goto HAD_ERROR; + goto HAD_EARLY_ERROR; } if ((options & PCRE2_NO_UTF_CHECK) == 0 && (errorcode = PRIV(valid_utf)(pattern, patlen, erroroffset)) != 0) - goto HAD_UTF_ERROR; + goto HAD_ERROR; /* Offset was set by valid_utf() */ } /* Check UCP lockout. */ @@ -8572,7 +9025,7 @@ if ((cb.external_options & (PCRE2_UCP|PCRE2_NEVER_UCP)) == (PCRE2_UCP|PCRE2_NEVER_UCP)) { errorcode = ERR75; - goto HAD_ERROR; + goto HAD_EARLY_ERROR; } /* Process the BSR setting. */ @@ -8611,23 +9064,102 @@ switch(newline) default: errorcode = ERR56; - goto HAD_ERROR; + goto HAD_EARLY_ERROR; + } + +/* Pre-scan the pattern to do two things: (1) Discover the named groups and +their numerical equivalents, so that this information is always available for +the remaining processing. (2) At the same time, parse the pattern and put a +processed version into the parsed_pattern vector. This has escapes interpreted +and comments removed (amongst other things). + +In all but one case, when PCRE2_AUTO_CALLOUT is not set, the number of unsigned +32-bit ints in the parsed pattern is bounded by the length of the pattern plus +one (for the terminator). The exceptional case is when running in 32-bit, +non-UTF mode, when literal characters greater than META_END (0x80000000) have +to be coded as two units. In this case, therefore, we scan the pattern to check +for such values. */ + +#if PCRE2_CODE_UNIT_WIDTH == 32 +if (!utf) + { + PCRE2_SPTR p; + for (p = ptr; p < cb.end_pattern; p++) if (*p >= META_END) big32count++; } +#endif + +/* Ensure that the parsed pattern buffer is big enough. When PCRE2_AUTO_CALLOUT +is set we have to assume a numerical callout (4 elements) for each character +plus one at the end. This is overkill, but memory is plentiful these days. For +many smaller patterns the vector on the stack (which was set up above) can be +used. */ + +parsed_size_needed = patlen - skipatstart + big32count; +if ((options & PCRE2_AUTO_CALLOUT) != 0) + parsed_size_needed = (parsed_size_needed + 1) * 5; -/* Before we do anything else, do a pre-scan of the pattern in order to -discover the named groups and their numerical equivalents, so that this -information is always available for the remaining processing. */ +if (parsed_size_needed >= PARSED_PATTERN_DEFAULT_SIZE) + { + uint32_t *heap_parsed_pattern = ccontext->memctl.malloc( + (parsed_size_needed + 1) * sizeof(uint32_t), ccontext->memctl.memory_data); + if (heap_parsed_pattern == NULL) + { + *errorptr = ERR21; + goto EXIT; + } + cb.parsed_pattern = heap_parsed_pattern; + } +cb.parsed_pattern_end = cb.parsed_pattern + parsed_size_needed + 1; -errorcode = scan_for_captures(&ptr, cb.external_options, &cb); -if (errorcode != 0) goto HAD_ERROR; +/* Do the parsing scan. */ -/* For obscure debugging this code can be enabled. */ +errorcode = parse_regex(ptr, cb.external_options, &has_lookbehind, &cb); +if (errorcode != 0) goto HAD_CB_ERROR; -#if 0 +/* Workspace is needed to remember information about numbered groups: whether a +group can match an empty string and what its fixed length is. This is done to +avoid the possibility of recursive references causing very long compile times +when checking these features. Unnumbered groups do not have this exposure since +they cannot be referenced. We use an indexed vector for this purpose. If there +are sufficiently few groups, the default vector on the stack, as set up above, +can be used. Otherwise we have to get/free a special vector. The vector must be +initialized to zero. */ + +if (cb.bracount >= GROUPINFO_DEFAULT_SIZE) + { + cb.groupinfo = ccontext->memctl.malloc( + (cb.bracount + 1)*sizeof(uint32_t), ccontext->memctl.memory_data); + if (cb.groupinfo == NULL) + { + errorcode = ERR21; + cb.erroroffset = 0; + goto HAD_CB_ERROR; + } + } +memset(cb.groupinfo, 0, (cb.bracount + 1) * sizeof(uint32_t)); + +/* If there were any lookbehinds, scan the parsed pattern to figure out their +lengths. */ + +if (has_lookbehind) + { + errorcode = check_lookbehinds(&cb); + if (errorcode != 0) goto HAD_CB_ERROR; + } + +/* For debugging, there is a function that shows the parsed data vector. */ + +#ifdef DEBUG_SHOW_PARSED +fprintf(stderr, "+++ Pre-scan complete:\n"); +show_parsed(&cb); +#endif + +/* For debugging capturing information this code can be enabled. */ + +#ifdef DEBUG_SHOW_CAPTURES { - int i; named_group *ng = cb.named_groups; - fprintf(stderr, "+++Captures: %d\n", cb.final_bracount); + fprintf(stderr, "+++Captures: %d\n", cb.bracount); for (i = 0; i < cb.names_found; i++, ng++) { fprintf(stderr, "+++%3d %.*s\n", ng->number, ng->length, ng->name); @@ -8635,12 +9167,6 @@ if (errorcode != 0) goto HAD_ERROR; } #endif -/* Reset current bracket count to zero and current pointer to the start of the -pattern. */ - -cb.bracount = 0; -ptr = pattern + skipatstart; - /* Pretend to compile the pattern while actually just accumulating the amount of memory required in the 'length' variable. This behaviour is triggered by passing a non-NULL final argument to compile_regex(). We pass a block of @@ -8649,24 +9175,26 @@ compiled code is discarded when it is no longer needed, so hopefully this workspace will never overflow, though there is a test for its doing so. On error, errorcode will be set non-zero, so we don't need to look at the -result of the function. The initial options have been put into the cb block so -that they can be changed if an option setting is found within the regex right -at the beginning. Bringing initial option settings outside can help speed up -starting point checks. We still have to pass a separate options variable (the -first argument) because that may change as the pattern is processed. */ +result of the function. The initial options have been put into the cb block, +but we still have to pass a separate options variable (the first argument) +because the options may change as the pattern is processed. */ +cb.erroroffset = patlen; /* For any subsequent errors that do not set it */ +pptr = cb.parsed_pattern; code = cworkspace; *code = OP_BRA; -(void)compile_regex(cb.external_options, &code, &ptr, &errorcode, FALSE, - FALSE, 0, 0, &firstcu, &firstcuflags, &reqcu, &reqcuflags, NULL, - &cb, &length); +(void)compile_regex(cb.external_options, &code, &pptr, &errorcode, 0, &firstcu, + &firstcuflags, &reqcu, &reqcuflags, NULL, &cb, &length); + +if (errorcode != 0) goto HAD_CB_ERROR; /* Offset is in cb.erroroffset */ + +/* This should be caught in compile_regex(), but just in case... */ -if (errorcode != 0) goto HAD_ERROR; if (length > MAX_PATTERN_SIZE) { errorcode = ERR20; - goto HAD_ERROR; + goto HAD_CB_ERROR; } /* Compute the size of, and then get and initialize, the data block for storing @@ -8681,7 +9209,7 @@ re = (pcre2_real_code *) if (re == NULL) { errorcode = ERR21; - goto HAD_ERROR; + goto HAD_CB_ERROR; } re->memctl = ccontext->memctl; @@ -8712,44 +9240,19 @@ code follows after that. */ codestart = (PCRE2_SPTR)((uint8_t *)re + sizeof(pcre2_real_code)) + re->name_entry_size * re->name_count; -/* Workspace is needed to remember information about numbered groups: whether a -group can match an empty string and what its fixed length is. This is done to -avoid the possibility of recursive references causing very long compile times -when checking these features. Unnumbered groups do not have this exposure since -they cannot be referenced. We use an indexed vector for this purpose. If there -are sufficiently few groups, it can be the c32workspace vector, as set up -above. Otherwise we have to get/free a special vector. The vector must be -initialized to zero. */ - -if (cb.final_bracount >= C32_WORK_SIZE) - { - cb.groupinfo = ccontext->memctl.malloc( - (cb.final_bracount + 1)*sizeof(uint32_t), ccontext->memctl.memory_data); - if (cb.groupinfo == NULL) - { - errorcode = ERR21; - goto HAD_ERROR; - } - } -memset(cb.groupinfo, 0, (cb.final_bracount + 1) * sizeof(uint32_t)); - /* Update the compile data block for the actual compile. The starting points of the name/number translation table and of the code are passed around in the compile data block. The start/end pattern and initial options are already set -from the pre-compile phase, as is the name_entry_size field. Reset the bracket -count and the names_found field. */ +from the pre-compile phase, as is the name_entry_size field. */ cb.parens_depth = 0; cb.assert_depth = 0; -cb.bracount = 0; -cb.max_lookbehind = 0; +cb.lastcapture = 0; cb.name_table = (PCRE2_UCHAR *)((uint8_t *)re + sizeof(pcre2_real_code)); cb.start_code = codestart; -cb.iscondassert = FALSE; cb.req_varyopt = 0; cb.had_accept = FALSE; cb.had_pruneorskip = FALSE; -cb.check_lookbehind = FALSE; cb.open_caps = NULL; /* If any named groups were found, create the name/number table from the list @@ -8757,23 +9260,21 @@ created in the pre-pass. */ if (cb.names_found > 0) { - int i = cb.names_found; named_group *ng = cb.named_groups; - cb.names_found = 0; - for (; i > 0; i--, ng++) - add_name_to_table(&cb, ng->name, ng->length, ng->number); + for (i = 0; i < cb.names_found; i++, ng++) + add_name_to_table(&cb, ng->name, ng->length, ng->number, i); } /* Set up a starting, non-extracting bracket, then compile the expression. On error, errorcode will be set non-zero, so we don't need to look at the result of the function here. */ -ptr = pattern + skipatstart; +pptr = cb.parsed_pattern; code = (PCRE2_UCHAR *)codestart; *code = OP_BRA; -(void)compile_regex(re->overall_options, &code, &ptr, &errorcode, FALSE, FALSE, - 0, 0, &firstcu, &firstcuflags, &reqcu, &reqcuflags, NULL, &cb, NULL); - +regexrc = compile_regex(re->overall_options, &code, &pptr, &errorcode, 0, + &firstcu, &firstcuflags, &reqcu, &reqcuflags, NULL, &cb, NULL); +if (regexrc < 0) re->flags |= PCRE2_MATCH_EMPTY; re->top_bracket = cb.bracount; re->top_backref = cb.top_backref; re->max_lookbehind = cb.max_lookbehind; @@ -8809,7 +9310,7 @@ if (errorcode == 0 && cb.had_recurse) { PCRE2_UCHAR *rcode; PCRE2_SPTR rgroup; - int ccount = 0; + unsigned int ccount = 0; int start = RSCAN_CACHE_SIZE; recurse_cache rc[RSCAN_CACHE_SIZE]; @@ -8817,16 +9318,16 @@ if (errorcode == 0 && cb.had_recurse) rcode != NULL; rcode = (PCRE2_UCHAR *)find_recurse(rcode + 1 + LINK_SIZE, utf)) { - int i, p, recno; + int p, groupnumber; - recno = (int)GET(rcode, 1); - if (recno == 0) rgroup = codestart; else + groupnumber = (int)GET(rcode, 1); + if (groupnumber == 0) rgroup = codestart; else { PCRE2_SPTR search_from = codestart; rgroup = NULL; for (i = 0, p = start; i < ccount; i++, p = (p + 1) & 7) { - if (recno == rc[p].recno) + if (groupnumber == rc[p].groupnumber) { rgroup = rc[p].group; break; @@ -8836,19 +9337,19 @@ if (errorcode == 0 && cb.had_recurse) search time below when the new group number is greater than any of the previously found groups. */ - if (recno > rc[p].recno) search_from = rc[p].group; + if (groupnumber > rc[p].groupnumber) search_from = rc[p].group; } if (rgroup == NULL) { - rgroup = PRIV(find_bracket)(search_from, utf, recno); + rgroup = PRIV(find_bracket)(search_from, utf, groupnumber); if (rgroup == NULL) { errorcode = ERR53; break; } if (--start < 0) start = RSCAN_CACHE_SIZE - 1; - rc[start].recno = recno; + rc[start].groupnumber = groupnumber; rc[start].group = rgroup; if (ccount < RSCAN_CACHE_SIZE) ccount++; } @@ -8861,93 +9362,27 @@ if (errorcode == 0 && cb.had_recurse) /* In rare debugging situations we sometimes need to look at the compiled code at this stage. */ -#ifdef CALL_PRINTINT +#ifdef DEBUG_CALL_PRINTINT pcre2_printint(re, stderr, TRUE); fprintf(stderr, "Length=%lu Used=%lu\n", length, usedlength); #endif -/* After a successful compile, give an error if there's back reference to a -non-existent capturing subpattern. Then, unless disabled, check whether any -single character iterators can be auto-possessified. The function overwrites -the appropriate opcode values, so the type of the pointer must be cast. NOTE: -the intermediate variable "temp" is used in this code because at least one -compiler gives a warning about loss of "const" attribute if the cast -(PCRE2_UCHAR *)codestart is used directly in the function call. */ - -if (errorcode == 0) - { - if (re->top_backref > re->top_bracket) errorcode = ERR15; - else if ((re->overall_options & PCRE2_NO_AUTO_POSSESS) == 0) - { - PCRE2_UCHAR *temp = (PCRE2_UCHAR *)codestart; - if (PRIV(auto_possessify)(temp, utf, &cb) != 0) errorcode = ERR80; - } - } - -/* If there were any lookbehind assertions that contained OP_RECURSE -(recursions or subroutine calls), a flag is set for them to be checked here, -because they may contain forward references. Actual recursions cannot be fixed -length, but subroutine calls can. It is done like this so that those without -OP_RECURSE that are not fixed length get a diagnosic with a useful offset. The -exceptional ones forgo this. We scan the pattern to check that they are fixed -length, and set their lengths. */ +/* Unless disabled, check whether any single character iterators can be +auto-possessified. The function overwrites the appropriate opcode values, so +the type of the pointer must be cast. NOTE: the intermediate variable "temp" is +used in this code because at least one compiler gives a warning about loss of +"const" attribute if the cast (PCRE2_UCHAR *)codestart is used directly in the +function call. */ -if (errorcode == 0 && cb.check_lookbehind) +if (errorcode == 0 && (re->overall_options & PCRE2_NO_AUTO_POSSESS) == 0) { - PCRE2_UCHAR *cc = (PCRE2_UCHAR *)codestart; - - /* Loop, searching for OP_REVERSE items, and process those that do not have - their length set. (Actually, it will also re-process any that have a length - of zero, but that is a pathological case, and it does no harm.) When we find - one, we temporarily terminate the branch it is in while we scan it. Note that - calling find_bracket() with a negative group number returns a pointer to the - OP_REVERSE item, not the actual lookbehind. */ - - for (cc = (PCRE2_UCHAR *)PRIV(find_bracket)(codestart, utf, -1); - cc != NULL; - cc = (PCRE2_UCHAR *)PRIV(find_bracket)(cc, utf, -1)) - { - if (GET(cc, 1) == 0) - { - int fixed_length; - int count = 0; - PCRE2_UCHAR *be = cc - 1 - LINK_SIZE + GET(cc, -LINK_SIZE); - int end_op = *be; - *be = OP_END; - fixed_length = find_fixedlength(cc, utf, TRUE, &cb, NULL, &count); - *be = end_op; - if (fixed_length < 0) - { - errorcode = fixed_length_errors[-fixed_length]; - break; - } - if (fixed_length > cb.max_lookbehind) cb.max_lookbehind = fixed_length; - PUT(cc, 1, fixed_length); - } - cc += 1 + LINK_SIZE; - } - - /* The previous value of the maximum lookbehind was transferred to the - compiled regex block above. We could have updated this value in the loop - above, but keep the two values in step, just in case some later code below - uses the cb value. */ - - re->max_lookbehind = cb.max_lookbehind; + PCRE2_UCHAR *temp = (PCRE2_UCHAR *)codestart; + if (PRIV(auto_possessify)(temp, utf, &cb) != 0) errorcode = ERR80; } -/* Failed to compile, or error while post-processing. Earlier errors get here -via the dreaded goto. */ +/* Failed to compile, or error while post-processing. */ -if (errorcode != 0) - { - HAD_ERROR: - *erroroffset = (int)(ptr - pattern); - HAD_UTF_ERROR: - *errorptr = errorcode; - pcre2_code_free(re); - re = NULL; - goto EXIT; - } +if (errorcode != 0) goto HAD_CB_ERROR; /* Successful compile. If the anchored option was not passed, set it if we can determine that the pattern is anchored by virtue of ^ characters or \A @@ -8956,7 +9391,7 @@ there are no occurrences of *PRUNE or *SKIP (though there is an option to disable this case). */ if ((re->overall_options & PCRE2_ANCHORED) == 0 && - is_anchored(codestart, 0, &cb, 0)) + is_anchored(codestart, 0, &cb, 0, FALSE)) re->overall_options |= PCRE2_ANCHORED; /* If the pattern is still not anchored and we do not have a first code unit, @@ -9005,7 +9440,8 @@ if ((re->overall_options & (PCRE2_ANCHORED|PCRE2_NO_START_OPTIMIZE)) == 0) when *PRUNE and SKIP are not present. (There is an option that disables this case.) */ - else if (is_startline(codestart, 0, &cb, 0)) re->flags |= PCRE2_STARTLINE; + else if (is_startline(codestart, 0, &cb, 0, FALSE)) + re->flags |= PCRE2_STARTLINE; } /* Handle the "required code unit", if one is set. In the case of an anchored @@ -9034,27 +9470,6 @@ if (reqcuflags >= 0 && } } -/* Check for a pattern than can match an empty string, so that this information -can be provided to applications. */ - -do - { - int count = 0; - int rc = could_be_empty_branch(codestart, code, utf, &cb, TRUE, NULL, &count); - if (rc < 0) - { - errorcode = ERR86; - goto HAD_ERROR; - } - if (rc > 0) - { - re->flags |= PCRE2_MATCH_EMPTY; - break; - } - codestart += GET(codestart, 1); - } -while (*codestart == OP_ALT); - /* Finally, unless PCRE2_NO_START_OPTIMIZE is set, study the compiled pattern to set up information such as a bitmap of starting code units and a minimum matching length. */ @@ -9063,25 +9478,46 @@ if ((re->overall_options & PCRE2_NO_START_OPTIMIZE) == 0 && PRIV(study)(re) != 0) { errorcode = ERR31; - goto HAD_ERROR; + goto HAD_CB_ERROR; } -/* Control ends up here in all cases. If memory was obtained for a -zero-terminated copy of the pattern, remember to free it before returning. Also -free the list of named groups if a larger one had to be obtained, and likewise -the group information vector. */ +/* Control ends up here in all cases. When running under valgrind, make a +pattern's terminating zero defined again. If memory was obtained for the parsed +version of the pattern, free it before returning. Also free the list of named +groups if a larger one had to be obtained, and likewise the group information +vector. */ EXIT: -if (copied_pattern != stack_copied_pattern) - ccontext->memctl.free(copied_pattern, ccontext->memctl.memory_data); +#ifdef SUPPORT_VALGRIND +if (zero_terminated) VALGRIND_MAKE_MEM_DEFINED(pattern + patlen, CU2BYTES(1)); +#endif +if (cb.parsed_pattern != stack_parsed_pattern) + ccontext->memctl.free(cb.parsed_pattern, ccontext->memctl.memory_data); if (cb.named_group_list_size > NAMED_GROUP_LIST_SIZE) ccontext->memctl.free((void *)cb.named_groups, ccontext->memctl.memory_data); -if (cb.groupinfo != c32workspace) +if (cb.groupinfo != stack_groupinfo) ccontext->memctl.free((void *)cb.groupinfo, ccontext->memctl.memory_data); - return re; /* Will be NULL after an error */ + +/* Errors discovered in parse_regex() set the offset value in the compile +block. Errors discovered before it is called must compute it from the ptr +value. After parse_regex() is called, the offset in the compile block is set to +the end of the pattern, but certain errors in compile_regex() may reset it if +an offset is available in the parsed pattern. */ + +HAD_CB_ERROR: +ptr = pattern + cb.erroroffset; + +HAD_EARLY_ERROR: +*erroroffset = ptr - pattern; + +HAD_ERROR: +*errorptr = errorcode; +pcre2_code_free(re); +re = NULL; +goto EXIT; } /* End of pcre2_compile.c */ -#pragma warning(pop) \ No newline at end of file +#pragma warning(pop) diff --git a/ProcessHacker/pcre/pcre2_dfa_match.c b/ProcessHacker/pcre/pcre2_dfa_match.c index c8ad26beef45..d0f756910bfc 100644 --- a/ProcessHacker/pcre/pcre2_dfa_match.c +++ b/ProcessHacker/pcre/pcre2_dfa_match.c @@ -72,6 +72,7 @@ Overall, I concluded that the gains in some cases did not outweigh the losses in others, so I abandoned this code. */ #define HAVE_CONFIG_H + #ifdef HAVE_CONFIG_H #include "config.h" #endif @@ -371,7 +372,7 @@ internal_dfa_match( uint32_t offsetcount, int *workspace, int wscount, - int rlevel) + uint32_t rlevel) { stateblock *active_states, *new_states, *temp_states; stateblock *next_active_state, *next_new_state; @@ -400,7 +401,7 @@ BOOL utf = FALSE; BOOL reset_could_continue = FALSE; -rlevel++; +if (rlevel++ > mb->match_limit_recursion) return PCRE2_ERROR_RECURSIONLIMIT; offsetcount &= (uint32_t)(-2); /* Round down */ wscount -= 2; @@ -2591,7 +2592,7 @@ for (;;) sizeof(local_workspace)/sizeof(int), /* size of same */ rlevel); /* function recursion level */ - if (rc == PCRE2_ERROR_DFA_UITEM) return rc; + if (rc < 0 && rc != PCRE2_ERROR_NOMATCH) return rc; if ((rc >= 0) == (codevalue == OP_ASSERT || codevalue == OP_ASSERTBACK)) { ADD_ACTIVE((int)(endasscode + LINK_SIZE + 1 - start_code), 0); } } @@ -2710,7 +2711,7 @@ for (;;) sizeof(local_workspace)/sizeof(int), /* size of same */ rlevel); /* function recursion level */ - if (rc == PCRE2_ERROR_DFA_UITEM) return rc; + if (rc < 0 && rc != PCRE2_ERROR_NOMATCH) return rc; if ((rc >= 0) == (condcode == OP_ASSERT || condcode == OP_ASSERTBACK)) { ADD_ACTIVE((int)(endasscode + LINK_SIZE + 1 - start_code), 0); } @@ -3115,7 +3116,7 @@ Returns: > 0 => number of match offset pairs placed in offsets PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION pcre2_dfa_match(const pcre2_code *code, PCRE2_SPTR subject, PCRE2_SIZE length, PCRE2_SIZE start_offset, uint32_t options, pcre2_match_data *match_data, - pcre2_match_context *mcontext, int *workspace, size_t wscount) + pcre2_match_context *mcontext, int *workspace, PCRE2_SIZE wscount) { const pcre2_real_code *re = (const pcre2_real_code *)code; @@ -3216,6 +3217,7 @@ if (mcontext == NULL) { mb->callout = NULL; mb->memctl = re->memctl; + mb->match_limit_recursion = PRIV(default_match_context).recursion_limit; } else { @@ -3228,7 +3230,10 @@ else mb->callout = mcontext->callout; mb->callout_data = mcontext->callout_data; mb->memctl = mcontext->memctl; + mb->match_limit_recursion = mcontext->recursion_limit; } +if (mb->match_limit_recursion > re->limit_recursion) + mb->match_limit_recursion = re->limit_recursion; mb->start_code = (PCRE2_UCHAR *)((uint8_t *)re + sizeof(pcre2_real_code)) + re->name_count * re->name_entry_size; @@ -3470,7 +3475,7 @@ for (;;) { while (start_match < end_subject) { - register uint32_t c = UCHAR21TEST(start_match); + uint32_t c = UCHAR21TEST(start_match); #if PCRE2_CODE_UNIT_WIDTH != 8 if (c > 255) c = 255; #endif @@ -3510,7 +3515,7 @@ for (;;) if (has_req_cu && end_subject - start_match < REQ_CU_MAX) { - register PCRE2_SPTR p = start_match + (has_first_cu? 1:0); + PCRE2_SPTR p = start_match + (has_first_cu? 1:0); /* We don't need to repeat the search if we haven't yet reached the place we found it at last time. */ @@ -3521,7 +3526,7 @@ for (;;) { while (p < end_subject) { - register uint32_t pp = UCHAR21INCTEST(p); + uint32_t pp = UCHAR21INCTEST(p); if (pp == req_cu || pp == req_cu2) { p--; break; } } } diff --git a/ProcessHacker/pcre/pcre2_error.c b/ProcessHacker/pcre/pcre2_error.c index dcb03e1fbb3c..9ef2b9cd0041 100644 --- a/ProcessHacker/pcre/pcre2_error.c +++ b/ProcessHacker/pcre/pcre2_error.c @@ -39,6 +39,7 @@ POSSIBILITY OF SUCH DAMAGE. */ #define HAVE_CONFIG_H + #ifdef HAVE_CONFIG_H #include "config.h" #endif @@ -91,13 +92,13 @@ static const unsigned char compile_error_texts[] = "failed to allocate heap memory\0" "unmatched closing parenthesis\0" "internal error: code overflow\0" - "letter or underscore expected after (?< or (?'\0" + "missing closing parenthesis for condition\0" /* 25 */ "lookbehind assertion is not fixed length\0" - "malformed number or name after (?(\0" + "a relative value of zero is not allowed\0" "conditional group contains more than two branches\0" "assertion expected after (?( or (?(?C)\0" - "(?R or (?[+-]digits must be followed by )\0" + "digit expected after (?+ or (?-\0" /* 30 */ "unknown POSIX class name\0" "internal error in pcre2_study(): should not occur\0" @@ -105,7 +106,7 @@ static const unsigned char compile_error_texts[] = "parentheses are too deeply nested (stack check)\0" "character code point value in \\x{} or \\o{} is too large\0" /* 35 */ - "invalid condition (?(0)\0" + "lookbehind is too complicated\0" "\\C is not allowed in a lookbehind assertion in UTF-" XSTRING(PCRE2_CODE_UNIT_WIDTH) " mode\0" "PCRE does not support \\L, \\l, \\N{name}, \\U, or \\u\0" "number after (?C is greater than 255\0" @@ -132,13 +133,13 @@ static const unsigned char compile_error_texts[] = "missing opening brace after \\o\0" "internal error: unknown newline setting\0" "\\g is not followed by a braced, angle-bracketed, or quoted name/number or by a plain number\0" - "a numbered reference must not be zero\0" + "(?R (recursive pattern call) must be followed by a closing parenthesis\0" "an argument is not allowed for (*ACCEPT), (*FAIL), or (*COMMIT)\0" /* 60 */ "(*VERB) not recognized or malformed\0" - "number is too big\0" + "group number is too big\0" "subpattern name expected\0" - "digit expected after (?+\0" + "internal error: parsed pattern overflow\0" "non-octal character in \\o{} (closing brace missing?)\0" /* 65 */ "different names for subpatterns of the same number are not allowed\0" @@ -151,9 +152,9 @@ static const unsigned char compile_error_texts[] = #endif "\\k is not followed by a braced, angle-bracketed, or quoted name\0" /* 70 */ - "internal error: unknown opcode in find_fixedlength()\0" + "internal error: unknown meta code in check_lookbehinds()\0" "\\N is not supported in a class\0" - "SPARE ERROR\0" + "callout string is too long\0" "disallowed Unicode code point (>= 0xd800 && <= 0xdfff)\0" "using UTF is disabled by the application\0" /* 75 */ @@ -161,7 +162,7 @@ static const unsigned char compile_error_texts[] = "name is too long in (*MARK), (*PRUNE), (*SKIP), or (*THEN)\0" "character code point value in \\u.... sequence is too large\0" "digits missing in \\x{} or \\o{}\0" - "syntax error in (?(VERSION condition\0" + "syntax error or number too big in (?(VERSION condition\0" /* 80 */ "internal error: unknown opcode in auto_possessify()\0" "missing terminating delimiter for callout with string argument\0" @@ -173,6 +174,9 @@ static const unsigned char compile_error_texts[] = "regular expression is too complicated\0" "lookbehind assertion is too long\0" "pattern string is longer than the limit set by the application\0" + "internal error: unknown code in parsed pattern\0" + /* 90 */ + "internal error: bad code value in parsed_skip()\0" ; /* Match-time and UTF error texts are in the same format. */ @@ -275,10 +279,10 @@ Returns: length of message if all is well */ PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION -pcre2_get_error_message(int enumber, PCRE2_UCHAR *buffer, size_t size) +pcre2_get_error_message(int enumber, PCRE2_UCHAR *buffer, PCRE2_SIZE size) { const unsigned char *message; -size_t i; +PCRE2_SIZE i; int n; if (size == 0) return PCRE2_ERROR_NOMEMORY; diff --git a/ProcessHacker/pcre/pcre2_find_bracket.c b/ProcessHacker/pcre/pcre2_find_bracket.c index 30d407aba5e9..1564cf96f5ff 100644 --- a/ProcessHacker/pcre/pcre2_find_bracket.c +++ b/ProcessHacker/pcre/pcre2_find_bracket.c @@ -45,7 +45,9 @@ negative, an instance of OP_REVERSE for a lookbehind. The function is called from pcre2_compile.c and also from pcre2_study.c when finding the minimum matching length. */ + #define HAVE_CONFIG_H + #ifdef HAVE_CONFIG_H #include "config.h" #endif @@ -71,7 +73,7 @@ PRIV(find_bracket)(PCRE2_SPTR code, BOOL utf, int number) { for (;;) { - register PCRE2_UCHAR c = *code; + PCRE2_UCHAR c = *code; if (c == OP_END) return NULL; diff --git a/ProcessHacker/pcre/pcre2_internal.h b/ProcessHacker/pcre/pcre2_internal.h index 56908708aa13..6a8774ce8c1f 100644 --- a/ProcessHacker/pcre/pcre2_internal.h +++ b/ProcessHacker/pcre/pcre2_internal.h @@ -142,20 +142,6 @@ pcre2_match() because of the way it backtracks. */ #define PCRE2_SPTR CUSTOM_SUBJECT_PTR #endif -/* When compiling with the MSVC compiler, it is sometimes necessary to include -a "calling convention" before exported function names. (This is secondhand -information; I know nothing about MSVC myself). For example, something like - - void __cdecl function(....) - -might be needed. In order so make this easy, all the exported functions have -PCRE2_CALL_CONVENTION just before their names. It is rarely needed; if not -set, we ensure here that it has no effect. */ - -#ifndef PCRE2_CALL_CONVENTION -#define PCRE2_CALL_CONVENTION -#endif - /* When checking for integer overflow in pcre2_compile(), we need to handle large integers. If a 64-bit integer type is available, we can use that. Otherwise we have to cast to double, which of course requires floating point @@ -1298,23 +1284,16 @@ mode rather than an escape sequence. It is also used for [^] in JavaScript compatibility mode, and for \C in non-utf mode. In non-DOTALL mode, "." behaves like \N. -The special values ESC_DU, ESC_du, etc. are used instead of ESC_D, ESC_d, etc. -when PCRE2_UCP is set and replacement of \d etc by \p sequences is required. -They must be contiguous, and remain in order so that the replacements can be -looked up from a table. - Negative numbers are used to encode a backreference (\1, \2, \3, etc.) in -check_escape(). There are two tests in the code for an escape -greater than ESC_b and less than ESC_Z to detect the types that may be -repeated. These are the types that consume characters. If any new escapes are -put in between that don't consume a character, that code will have to change. -*/ +check_escape(). There are tests in the code for an escape greater than ESC_b +and less than ESC_Z to detect the types that may be repeated. These are the +types that consume characters. If any new escapes are put in between that don't +consume a character, that code will have to change. */ enum { ESC_A = 1, ESC_G, ESC_K, ESC_B, ESC_b, ESC_D, ESC_d, ESC_S, ESC_s, ESC_W, ESC_w, ESC_N, ESC_dum, ESC_C, ESC_P, ESC_p, ESC_R, ESC_H, ESC_h, ESC_V, ESC_v, ESC_X, ESC_Z, ESC_z, - ESC_E, ESC_Q, ESC_g, ESC_k, - ESC_DU, ESC_du, ESC_SU, ESC_su, ESC_WU, ESC_wu }; + ESC_E, ESC_Q, ESC_g, ESC_k }; /********************** Opcode definitions ******************/ @@ -1380,7 +1359,8 @@ enum { OP_CIRC, /* 27 Start of line - not multiline */ OP_CIRCM, /* 28 Start of line - multiline */ - /* Single characters; caseful must precede the caseless ones */ + /* Single characters; caseful must precede the caseless ones, and these + must remain in this order, and adjacent. */ OP_CHAR, /* 29 Match one character, casefully */ OP_CHARI, /* 30 Match one character, caselessly */ diff --git a/ProcessHacker/pcre/pcre2_intmodedep.h b/ProcessHacker/pcre/pcre2_intmodedep.h index 596d62cfdcff..ebff7e30661c 100644 --- a/ProcessHacker/pcre/pcre2_intmodedep.h +++ b/ProcessHacker/pcre/pcre2_intmodedep.h @@ -140,7 +140,7 @@ values of 3 or 4 are also supported. */ #undef LINK_SIZE #define LINK_SIZE 1 #define PUT(a,n,d) \ - (a[n] = (d)) + (a[n] = (PCRE2_UCHAR)(d)) #define GET(a,n) \ (a[n]) #define MAX_PATTERN_SIZE (1 << 16) @@ -200,11 +200,11 @@ arithmetic results in a signed value. Hence the cast. */ #endif /* Other macros that are different for 8-bit mode. The MAX_255 macro checks -whether its argument is less than 256. The maximum length of a MARK name must -fit in one code unit; currently it is set to 255 or 65535. The TABLE_GET macro -is used to access elements of tables containing exactly 256 items. When code -points can be greater than 255, a check is needed before accessing these -tables. */ +whether its argument, which is assumed to be one code unit, is less than 256. +The maximum length of a MARK name must fit in one code unit; currently it is +set to 255 or 65535. The TABLE_GET macro is used to access elements of tables +containing exactly 256 items. When code points can be greater than 255, a check +is needed before accessing these tables. */ #if PCRE2_CODE_UNIT_WIDTH == 8 #define MAX_255(c) TRUE @@ -648,18 +648,24 @@ typedef struct pcre2_real_match_data { #ifndef PCRE2_PCRE2TEST -/* Structure for checking for mutual recursion when scanning compiled code. */ +/* Structures for checking for mutual recursion when scanning compiled or +parsed code. */ typedef struct recurse_check { struct recurse_check *prev; PCRE2_SPTR group; } recurse_check; +typedef struct parsed_recurse_check { + struct parsed_recurse_check *prev; + uint32_t *groupptr; +} parsed_recurse_check; + /* Structure for building a cache when filling in recursion offsets. */ typedef struct recurse_cache { PCRE2_SPTR group; - int recno; + int groupnumber; } recurse_cache; /* Structure for maintaining a chain of pointers to the currently incomplete @@ -693,9 +699,10 @@ typedef struct compile_block { PCRE2_SPTR start_code; /* The start of the compiled code */ PCRE2_SPTR start_pattern; /* The start of the pattern */ PCRE2_SPTR end_pattern; /* The end of the pattern */ - PCRE2_SPTR nestptr[2]; /* Pointer(s) saved for string substitution */ PCRE2_UCHAR *name_table; /* The name/number table */ - size_t workspace_size; /* Size of workspace */ + PCRE2_SIZE workspace_size; /* Size of workspace */ + PCRE2_SIZE small_ref_offset[10]; /* Offsets for \1 to \9 */ + PCRE2_SIZE erroroffset; /* Offset of error in pattern */ uint16_t names_found; /* Number of entries so far */ uint16_t name_entry_size; /* Size of each entry */ open_capitem *open_caps; /* Chain of open capture items */ @@ -703,13 +710,17 @@ typedef struct compile_block { uint32_t named_group_list_size; /* Number of entries in the list */ uint32_t external_options; /* External (initial) options */ uint32_t external_flags; /* External flag bits to be set */ - uint32_t bracount; /* Count of capturing parens as we compile */ - uint32_t final_bracount; /* Saved value after first pass */ + uint32_t bracount; /* Count of capturing parentheses */ + uint32_t lastcapture; /* Last capture encountered */ + uint32_t *parsed_pattern; /* Parsed pattern buffer */ + uint32_t *parsed_pattern_end; /* Parsed pattern should not get here */ uint32_t *groupinfo; /* Group info vector */ uint32_t top_backref; /* Maximum back reference */ uint32_t backref_map; /* Bitmap of low back refs */ uint32_t nltype; /* Newline type */ uint32_t nllen; /* Newline string length */ + uint32_t class_range_start; /* Overall class range start */ + uint32_t class_range_end; /* Overall class range end */ PCRE2_UCHAR nl[4]; /* Newline string when fixed length */ int max_lookbehind; /* Maximum lookbehind (characters) */ int parens_depth; /* Depth of nested parentheses */ @@ -718,9 +729,7 @@ typedef struct compile_block { BOOL had_accept; /* (*ACCEPT) encountered */ BOOL had_pruneorskip; /* (*PRUNE) or (*SKIP) encountered */ BOOL had_recurse; /* Had a recursion or subroutine call */ - BOOL check_lookbehind; /* Lookbehinds need later checking */ BOOL dupnames; /* Duplicate names exist */ - BOOL iscondassert; /* Next assert is a condition */ } compile_block; /* Structure for keeping the properties of the in-memory stack used @@ -836,6 +845,7 @@ typedef struct dfa_match_block { PCRE2_SPTR last_used_ptr; /* Latest consulted character */ const uint8_t *tables; /* Character tables */ PCRE2_SIZE start_offset; /* The start offset value */ + uint32_t match_limit_recursion; /* As it says */ uint32_t moptions; /* Match options */ uint32_t poptions; /* Pattern options */ uint32_t nltype; /* Newline type */ diff --git a/ProcessHacker/pcre/pcre2_jit_compile.c b/ProcessHacker/pcre/pcre2_jit_compile.c index 0d3baa714e4a..5a02249324b3 100644 --- a/ProcessHacker/pcre/pcre2_jit_compile.c +++ b/ProcessHacker/pcre/pcre2_jit_compile.c @@ -39,6 +39,7 @@ POSSIBILITY OF SUCH DAMAGE. */ #define HAVE_CONFIG_H + #ifdef HAVE_CONFIG_H #include "config.h" #endif diff --git a/ProcessHacker/pcre/pcre2_maketables.c b/ProcessHacker/pcre/pcre2_maketables.c index dbabdb246c30..ddfadfb00d42 100644 --- a/ProcessHacker/pcre/pcre2_maketables.c +++ b/ProcessHacker/pcre/pcre2_maketables.c @@ -45,6 +45,7 @@ own as part of the PCRE2 library. However, it is also included in the compilation of dftables.c, in which case the macro DFTABLES is defined. */ #define HAVE_CONFIG_H + #ifndef DFTABLES # ifdef HAVE_CONFIG_H # include "config.h" diff --git a/ProcessHacker/pcre/pcre2_match.c b/ProcessHacker/pcre/pcre2_match.c index bf770ab90cb0..e05dc35179eb 100644 --- a/ProcessHacker/pcre/pcre2_match.c +++ b/ProcessHacker/pcre/pcre2_match.c @@ -38,11 +38,8 @@ POSSIBILITY OF SUCH DAMAGE. ----------------------------------------------------------------------------- */ -// dmex: Disable warnings -#pragma warning(push) -#pragma warning(disable : 4267) - #define HAVE_CONFIG_H + #ifdef HAVE_CONFIG_H #include "config.h" #endif @@ -146,14 +143,14 @@ Returns: = 0 sucessful match; number of code units matched is set */ static int -match_ref(PCRE2_SIZE offset, PCRE2_SIZE offset_top, register PCRE2_SPTR eptr, +match_ref(PCRE2_SIZE offset, PCRE2_SIZE offset_top, PCRE2_SPTR eptr, match_block *mb, BOOL caseless, PCRE2_SIZE *lengthptr) { #if defined SUPPORT_UNICODE BOOL utf = (mb->poptions & PCRE2_UTF) != 0; #endif -register PCRE2_SPTR p; +PCRE2_SPTR p; PCRE2_SIZE length; PCRE2_SPTR eptr_start = eptr; @@ -300,7 +297,6 @@ enum { RM1=1, RM2, RM3, RM4, RM5, RM6, RM7, RM8, RM9, RM10, argument of RMATCH isn't actually used in this definition. */ #ifndef HEAP_MATCH_RECURSE -#define REGISTER register #define RMATCH(ra,rb,rc,rd,re,rw) \ rrc = match(ra,rb,mstart,rc,rd,re,rdepth+1) #define RRETURN(ra) return ra @@ -310,8 +306,6 @@ argument of RMATCH isn't actually used in this definition. */ the "rd" argument of RMATCH isn't actually used in this definition. It's the mb argument of match(), which never changes. */ -#define REGISTER - #define RMATCH(ra,rb,rc,rd,re,rw)\ {\ heapframe *newframe = frame->Xnextframe;\ @@ -429,7 +423,7 @@ to save the ovector while calling match() to process the pattern recursion. */ op_recurse_ovecsave(). */ static int -match(REGISTER PCRE2_SPTR eptr, REGISTER PCRE2_SPTR ecode, PCRE2_SPTR mstart, +match(PCRE2_SPTR eptr, PCRE2_SPTR ecode, PCRE2_SPTR mstart, PCRE2_SIZE offset_top, match_block *mb, eptrblock *eptrb, uint32_t rdepth); @@ -472,11 +466,11 @@ static int #if defined(__GNUC__) && !defined(__INTEL_COMPILER) __attribute__ ((noinline)) #endif -op_recurse_ovecsave(REGISTER PCRE2_SPTR eptr, PCRE2_SPTR callpat, +op_recurse_ovecsave(PCRE2_SPTR eptr, PCRE2_SPTR callpat, PCRE2_SPTR mstart, PCRE2_SIZE offset_top, match_block *mb, eptrblock *eptrb, uint32_t rdepth) { -register int rrc; +int rrc; BOOL cbegroup = *callpat >= OP_SBRA; recursion_info *new_recursive = mb->recursive; PCRE2_SIZE ovecsave[OP_RECURSE_STACK_SAVE_MAX]; @@ -580,20 +574,19 @@ Returns: MATCH_MATCH if matched ) these values are >= 0 */ static int -match(REGISTER PCRE2_SPTR eptr, REGISTER PCRE2_SPTR ecode, PCRE2_SPTR mstart, +match(PCRE2_SPTR eptr, PCRE2_SPTR ecode, PCRE2_SPTR mstart, PCRE2_SIZE offset_top, match_block *mb, eptrblock *eptrb, uint32_t rdepth) { /* These variables do not need to be preserved over recursion in this function, so they can be ordinary variables in all cases. Mark some of them with "register" because they are used a lot in loops. */ -register int rrc; /* Returns from recursive calls */ -register int i; /* Used for loops not involving calls to RMATCH() */ -register uint32_t c; /* Character values not kept over RMATCH() calls */ -register BOOL utf; /* Local copy of UTF flag for speed */ +int rrc; /* Returns from recursive calls */ +int i; /* Used for loops not involving calls to RMATCH() */ +uint32_t c; /* Character values not kept over RMATCH() calls */ +BOOL utf; /* Local copy of UTF flag for speed */ BOOL minimize, possessive; /* Quantifier options */ -BOOL caseless; int condcode; /* When recursion is not being used, all "local" variables that have to be @@ -731,6 +724,7 @@ still need to be preserved over recursive calls of match(). These macros define the alternative names that are used. */ #define allow_zero cur_is_word +#define caseless cur_is_word #define cbegroup condition #define code_offset codelink #define condassert condition @@ -1323,7 +1317,7 @@ for (;;) { pcre2_callout_block cb; cb.version = 1; - cb.capture_top = offset_top/2; + cb.capture_top = (uint32_t)offset_top/2; cb.capture_last = mb->capture_last & CAPLMASK; cb.offset_vector = mb->ovector; cb.mark = mb->nomatch_mark; @@ -1507,8 +1501,8 @@ for (;;) if (offset >= offset_top) { - register PCRE2_SIZE *iptr = mb->ovector + offset_top; - register PCRE2_SIZE *iend = mb->ovector + offset; + PCRE2_SIZE *iptr = mb->ovector + offset_top; + PCRE2_SIZE *iend = mb->ovector + offset; while (iptr < iend) *iptr++ = PCRE2_UNSET; offset_top = offset + 2; } @@ -1750,7 +1744,7 @@ for (;;) pcre2_callout_block cb; cb.version = 1; cb.callout_number = ecode[LINK_SIZE + 1]; - cb.capture_top = offset_top/2; + cb.capture_top = (uint32_t)offset_top/2; cb.capture_last = mb->capture_last & CAPLMASK; cb.offset_vector = mb->ovector; cb.mark = mb->nomatch_mark; @@ -2056,8 +2050,8 @@ for (;;) if (offset > offset_top) { - register PCRE2_SIZE *iptr = mb->ovector + offset_top; - register PCRE2_SIZE *iend = mb->ovector + offset; + PCRE2_SIZE *iptr = mb->ovector + offset_top; + PCRE2_SIZE *iend = mb->ovector + offset; while (iptr < iend) *iptr++ = PCRE2_UNSET; } @@ -2386,7 +2380,7 @@ for (;;) case OP_ANY: if (IS_NEWLINE(eptr)) RRETURN(MATCH_NOMATCH); if (mb->partial != 0 && - eptr + 1 >= mb->end_subject && + eptr == mb->end_subject - 1 && NLBLOCK->nltype == NLTYPE_FIXED && NLBLOCK->nllen == 2 && UCHAR21TEST(eptr) == NLBLOCK->nl[0]) @@ -2853,9 +2847,7 @@ for (;;) continue; } - /* First, ensure the minimum number of matches are present. We get back - the length of the reference string explicitly rather than passing the - address of eptr, so that eptr can be a register variable. */ + /* First, ensure the minimum number of matches are present. */ for (i = 1; i <= min; i++) { @@ -3766,7 +3758,7 @@ for (;;) #ifdef SUPPORT_UNICODE if (utf) { - register uint32_t ch, och; + uint32_t ch, och; ecode++; GETCHARINC(ch, ecode); @@ -3788,7 +3780,7 @@ for (;;) else #endif /* SUPPORT_UNICODE */ { - register uint32_t ch = ecode[1]; + uint32_t ch = ecode[1]; c = *eptr++; if (ch == c || (op == OP_NOTI && TABLE_GET(ch, mb->fcc, ch) == c)) RRETURN(MATCH_NOMATCH); @@ -3894,7 +3886,7 @@ for (;;) #ifdef SUPPORT_UNICODE if (utf) { - register uint32_t d; + uint32_t d; for (i = 1; i <= min; i++) { if (eptr >= mb->end_subject) @@ -3929,7 +3921,7 @@ for (;;) #ifdef SUPPORT_UNICODE if (utf) { - register uint32_t d; + uint32_t d; for (fi = min;; fi++) { RMATCH(eptr, ecode, offset_top, mb, eptrb, RM28); @@ -3974,7 +3966,7 @@ for (;;) #ifdef SUPPORT_UNICODE if (utf) { - register uint32_t d; + uint32_t d; for (i = min; i < max; i++) { int len = 1; @@ -4035,7 +4027,7 @@ for (;;) #ifdef SUPPORT_UNICODE if (utf) { - register uint32_t d; + uint32_t d; for (i = 1; i <= min; i++) { if (eptr >= mb->end_subject) @@ -4069,7 +4061,7 @@ for (;;) #ifdef SUPPORT_UNICODE if (utf) { - register uint32_t d; + uint32_t d; for (fi = min;; fi++) { RMATCH(eptr, ecode, offset_top, mb, eptrb, RM32); @@ -4113,7 +4105,7 @@ for (;;) #ifdef SUPPORT_UNICODE if (utf) { - register uint32_t d; + uint32_t d; for (i = min; i < max; i++) { int len = 1; @@ -6735,8 +6727,8 @@ in case they inspect these fields. */ if (ocount > 0) { - register PCRE2_SIZE *iptr = mb->ovector + ocount; - register PCRE2_SIZE *iend = iptr - re->top_bracket; + PCRE2_SIZE *iptr = mb->ovector + ocount; + PCRE2_SIZE *iend = iptr - re->top_bracket; if (iend < mb->ovector + 2) iend = mb->ovector + 2; while (--iptr >= iend) *iptr = PCRE2_UNSET; mb->ovector[0] = mb->ovector[1] = PCRE2_UNSET; @@ -6892,7 +6884,7 @@ for(;;) { while (start_match < end_subject) { - register uint32_t c = UCHAR21TEST(start_match); + uint32_t c = UCHAR21TEST(start_match); #if PCRE2_CODE_UNIT_WIDTH != 8 if (c > 255) c = 255; #endif @@ -6936,7 +6928,7 @@ for(;;) if (has_req_cu && end_subject - start_match < REQ_CU_MAX) { - register PCRE2_SPTR p = start_match + (has_first_cu? 1:0); + PCRE2_SPTR p = start_match + (has_first_cu? 1:0); /* We don't need to repeat the search if we haven't yet reached the place we found it at last time. */ @@ -6947,7 +6939,7 @@ for(;;) { while (p < end_subject) { - register uint32_t pp = UCHAR21INCTEST(p); + uint32_t pp = UCHAR21INCTEST(p); if (pp == req_cu || pp == req_cu2) { p--; break; } } } @@ -7166,7 +7158,7 @@ if (rc == MATCH_MATCH || rc == MATCH_ACCEPT) too many to fit into the ovector. */ match_data->rc = ((mb->capture_last & OVFLBIT) != 0)? - 0 : mb->end_offset_top/2; + 0 : (int)mb->end_offset_top/2; /* If there is space in the offset vector, set any pairs that follow the highest-numbered captured string but are less than the number of capturing @@ -7180,7 +7172,7 @@ if (rc == MATCH_MATCH || rc == MATCH_ACCEPT) if (mb->end_offset_top/2 <= re->top_bracket) { - register PCRE2_SIZE *iptr, *iend; + PCRE2_SIZE *iptr, *iend; int resetcount = re->top_bracket + 1; if (resetcount > match_data->oveccount) resetcount = match_data->oveccount; iptr = match_data->ovector + mb->end_offset_top; @@ -7245,5 +7237,3 @@ return match_data->rc; } /* End of pcre2_match.c */ - -#pragma warning(pop) \ No newline at end of file diff --git a/ProcessHacker/pcre/pcre2_match_data.c b/ProcessHacker/pcre/pcre2_match_data.c index 8b3ffcd05034..6e2e0a40c8d1 100644 --- a/ProcessHacker/pcre/pcre2_match_data.c +++ b/ProcessHacker/pcre/pcre2_match_data.c @@ -39,6 +39,7 @@ POSSIBILITY OF SUCH DAMAGE. */ #define HAVE_CONFIG_H + #ifdef HAVE_CONFIG_H #include "config.h" #endif diff --git a/ProcessHacker/pcre/pcre2_newline.c b/ProcessHacker/pcre/pcre2_newline.c index 2aab03a294fd..1d22666380bb 100644 --- a/ProcessHacker/pcre/pcre2_newline.c +++ b/ProcessHacker/pcre/pcre2_newline.c @@ -48,6 +48,7 @@ and NLTYPE_ANY. The full list of Unicode newline characters is taken from http://unicode.org/unicode/reports/tr18/. */ #define HAVE_CONFIG_H + #ifdef HAVE_CONFIG_H #include "config.h" #endif diff --git a/ProcessHacker/pcre/pcre2_ord2utf.c b/ProcessHacker/pcre/pcre2_ord2utf.c index 482e30a16b01..07ab10fda25f 100644 --- a/ProcessHacker/pcre/pcre2_ord2utf.c +++ b/ProcessHacker/pcre/pcre2_ord2utf.c @@ -39,10 +39,12 @@ POSSIBILITY OF SUCH DAMAGE. */ +#define HAVE_CONFIG_H + /* This file contains a function that converts a Unicode character code point into a UTF string. The behaviour is different for each code unit width. */ -#define HAVE_CONFIG_H + #ifdef HAVE_CONFIG_H #include "config.h" #endif @@ -83,7 +85,7 @@ PRIV(ord2utf)(uint32_t cvalue, PCRE2_UCHAR *buffer) /* Convert to UTF-8 */ #if PCRE2_CODE_UNIT_WIDTH == 8 -register int i, j; +int i, j; for (i = 0; i < PRIV(utf8_table1_size); i++) if ((int)cvalue <= PRIV(utf8_table1)[i]) break; buffer += i; diff --git a/ProcessHacker/pcre/pcre2_pattern_info.c b/ProcessHacker/pcre/pcre2_pattern_info.c index 39c1162e8ab3..fadad4b324a2 100644 --- a/ProcessHacker/pcre/pcre2_pattern_info.c +++ b/ProcessHacker/pcre/pcre2_pattern_info.c @@ -38,7 +38,9 @@ POSSIBILITY OF SUCH DAMAGE. ----------------------------------------------------------------------------- */ + #define HAVE_CONFIG_H + #ifdef HAVE_CONFIG_H #include "config.h" #endif diff --git a/ProcessHacker/pcre/pcre2_printint.c b/ProcessHacker/pcre/pcre2_printint.c index 2d30926a744e..62074976489b 100644 --- a/ProcessHacker/pcre/pcre2_printint.c +++ b/ProcessHacker/pcre/pcre2_printint.c @@ -206,7 +206,7 @@ print_custring(FILE *f, PCRE2_SPTR ptr) { while (*ptr != '\0') { - register uint32_t c = *ptr++; + uint32_t c = *ptr++; if (PRINTABLE(c)) fprintf(f, "%c", c); else fprintf(f, "\\x{%x}", c); } } @@ -216,7 +216,7 @@ print_custring_bylen(FILE *f, PCRE2_SPTR ptr, PCRE2_UCHAR len) { for (; len > 0; len--) { - register uint32_t c = *ptr++; + uint32_t c = *ptr++; if (PRINTABLE(c)) fprintf(f, "%c", c); else fprintf(f, "\\x{%x}", c); } } diff --git a/ProcessHacker/pcre/pcre2_serialize.c b/ProcessHacker/pcre/pcre2_serialize.c index 1aa3c54bd901..41d36a910c4a 100644 --- a/ProcessHacker/pcre/pcre2_serialize.c +++ b/ProcessHacker/pcre/pcre2_serialize.c @@ -42,6 +42,7 @@ POSSIBILITY OF SUCH DAMAGE. a sequence of compiled codes. */ #define HAVE_CONFIG_H + #ifdef HAVE_CONFIG_H #include "config.h" #endif diff --git a/ProcessHacker/pcre/pcre2_string_utils.c b/ProcessHacker/pcre/pcre2_string_utils.c index feaa09894c48..f3666460bd78 100644 --- a/ProcessHacker/pcre/pcre2_string_utils.c +++ b/ProcessHacker/pcre/pcre2_string_utils.c @@ -43,6 +43,7 @@ of strings. These are used instead of strcmp() etc because the standard functions work only on 8-bit data. */ #define HAVE_CONFIG_H + #ifdef HAVE_CONFIG_H #include "config.h" #endif diff --git a/ProcessHacker/pcre/pcre2_study.c b/ProcessHacker/pcre/pcre2_study.c index 9bd0667e69fc..d6403dccb0bb 100644 --- a/ProcessHacker/pcre/pcre2_study.c +++ b/ProcessHacker/pcre/pcre2_study.c @@ -41,6 +41,7 @@ POSSIBILITY OF SUCH DAMAGE. /* This module contains functions for scanning a compiled pattern and collecting data (e.g. minimum matching length). */ + #define HAVE_CONFIG_H #ifdef HAVE_CONFIG_H #include "config.h" @@ -50,6 +51,10 @@ collecting data (e.g. minimum matching length). */ #include "pcre2_internal.h" +/* The maximum remembered capturing brackets minimum. */ + +#define MAX_CACHE_BACKREF 128 + /* Set a bit in the starting code unit bit map. */ #define SET_BIT(c) re->start_bitmap[(c)/8] |= (1 << ((c)&7)) @@ -71,6 +76,12 @@ length is 16-bits long (on the grounds that anything longer than that is pathological), so we give up when we reach that amount. This also means that integer overflow for really crazy patterns cannot happen. +Backreference minimum lengths are cached to speed up multiple references. This +function is called only when the highest back reference in the pattern is less +than or equal to MAX_CACHE_BACKREF, which is one less than the size of the +caching vector. The zeroth element contains the number of the highest set +value. + Arguments: re compiled pattern block code pointer to start of group (the bracket) @@ -78,6 +89,7 @@ integer overflow for really crazy patterns cannot happen. utf UTF flag recurses chain of recurse_check to catch mutual recursion countptr pointer to call count (to catch over complexity) + backref_cache vector for caching back references. Returns: the minimum length -1 \C in UTF-8 mode @@ -90,7 +102,8 @@ Returns: the minimum length static int find_minlength(const pcre2_real_code *re, PCRE2_SPTR code, - PCRE2_SPTR startcode, BOOL utf, recurse_check *recurses, int *countptr) + PCRE2_SPTR startcode, BOOL utf, recurse_check *recurses, int *countptr, + int *backref_cache) { int length = -1; int prev_cap_recno = -1; @@ -101,8 +114,8 @@ uint32_t once_fudge = 0; BOOL had_recurse = FALSE; BOOL dupcapused = (re->flags & PCRE2_DUPCAPUSED) != 0; recurse_check this_recurse; -register int branchlength = 0; -register PCRE2_UCHAR *cc = (PCRE2_UCHAR *)code + 1 + LINK_SIZE; +int branchlength = 0; +PCRE2_UCHAR *cc = (PCRE2_UCHAR *)code + 1 + LINK_SIZE; /* If this is a "could be empty" group, its minimum length is 0. */ @@ -124,7 +137,7 @@ for (;;) { int d, min, recno; PCRE2_UCHAR *cs, *ce; - register PCRE2_UCHAR op = *cc; + PCRE2_UCHAR op = *cc; if (branchlength >= UINT16_MAX) return UINT16_MAX; @@ -166,7 +179,8 @@ for (;;) case OP_BRAPOS: case OP_SBRAPOS: PROCESS_NON_CAPTURE: - d = find_minlength(re, cc, startcode, utf, recurses, countptr); + d = find_minlength(re, cc, startcode, utf, recurses, countptr, + backref_cache); if (d < 0) return d; branchlength += d; do cc += GET(cc, 1); while (*cc == OP_ALT); @@ -182,11 +196,12 @@ for (;;) case OP_SCBRA: case OP_CBRAPOS: case OP_SCBRAPOS: - recno = dupcapused? prev_cap_recno - 1 : (int)GET2(cc, 1+LINK_SIZE); - if (recno != prev_cap_recno) + recno = (int)GET2(cc, 1+LINK_SIZE); + if (dupcapused || recno != prev_cap_recno) { prev_cap_recno = recno; - prev_cap_d = find_minlength(re, cc, startcode, utf, recurses, countptr); + prev_cap_d = find_minlength(re, cc, startcode, utf, recurses, countptr, + backref_cache); if (prev_cap_d < 0) return prev_cap_d; } branchlength += prev_cap_d; @@ -456,38 +471,52 @@ for (;;) d = INT_MAX; - /* Scan all groups with the same name */ + /* Scan all groups with the same name; find the shortest. */ while (count-- > 0) { - ce = cs = (PCRE2_UCHAR *)PRIV(find_bracket)(startcode, utf, GET2(slot, 0)); - if (cs == NULL) return -2; - do ce += GET(ce, 1); while (*ce == OP_ALT); - if (cc > cs && cc < ce) /* Simple recursion */ - { - d = 0; - had_recurse = TRUE; - break; - } + int dd, i; + recno = GET2(slot, 0); + + if (recno <= backref_cache[0] && backref_cache[recno] >= 0) + dd = backref_cache[recno]; else { - recurse_check *r = recurses; - for (r = recurses; r != NULL; r = r->prev) if (r->group == cs) break; - if (r != NULL) /* Mutual recursion */ + ce = cs = (PCRE2_UCHAR *)PRIV(find_bracket)(startcode, utf, recno); + if (cs == NULL) return -2; + do ce += GET(ce, 1); while (*ce == OP_ALT); + if (cc > cs && cc < ce) /* Simple recursion */ { - d = 0; + dd = 0; had_recurse = TRUE; - break; } else { - int dd; - this_recurse.prev = recurses; - this_recurse.group = cs; - dd = find_minlength(re, cs, startcode, utf, &this_recurse, countptr); - if (dd < d) d = dd; + recurse_check *r = recurses; + for (r = recurses; r != NULL; r = r->prev) + if (r->group == cs) break; + if (r != NULL) /* Mutual recursion */ + { + dd = 0; + had_recurse = TRUE; + } + else + { + this_recurse.prev = recurses; + this_recurse.group = cs; + dd = find_minlength(re, cs, startcode, utf, &this_recurse, + countptr, backref_cache); + if (dd < 0) return dd; + } } + + backref_cache[recno] = dd; + for (i = backref_cache[0] + 1; i < recno; i++) backref_cache[i] = -1; + backref_cache[0] = recno; } + + if (dd < d) d = dd; + if (d <= 0) break; /* No point looking at any more */ slot += re->name_entry_size; } } @@ -501,34 +530,48 @@ for (;;) case OP_REF: case OP_REFI: if (dupcapused) return -1; - if ((re->overall_options & PCRE2_MATCH_UNSET_BACKREF) == 0) + recno = GET2(cc, 1); + if (recno <= backref_cache[0] && backref_cache[recno] >= 0) + d = backref_cache[recno]; + else { - ce = cs = (PCRE2_UCHAR *)PRIV(find_bracket)(startcode, utf, GET2(cc, 1)); - if (cs == NULL) return -2; - do ce += GET(ce, 1); while (*ce == OP_ALT); - if (cc > cs && cc < ce) /* Simple recursion */ + int i; + if ((re->overall_options & PCRE2_MATCH_UNSET_BACKREF) == 0) { - d = 0; - had_recurse = TRUE; - } - else - { - recurse_check *r = recurses; - for (r = recurses; r != NULL; r = r->prev) if (r->group == cs) break; - if (r != NULL) /* Mutual recursion */ + ce = cs = (PCRE2_UCHAR *)PRIV(find_bracket)(startcode, utf, recno); + if (cs == NULL) return -2; + do ce += GET(ce, 1); while (*ce == OP_ALT); + if (cc > cs && cc < ce) /* Simple recursion */ { d = 0; had_recurse = TRUE; } else { - this_recurse.prev = recurses; - this_recurse.group = cs; - d = find_minlength(re, cs, startcode, utf, &this_recurse, countptr); + recurse_check *r = recurses; + for (r = recurses; r != NULL; r = r->prev) if (r->group == cs) break; + if (r != NULL) /* Mutual recursion */ + { + d = 0; + had_recurse = TRUE; + } + else + { + this_recurse.prev = recurses; + this_recurse.group = cs; + d = find_minlength(re, cs, startcode, utf, &this_recurse, countptr, + backref_cache); + if (d < 0) return d; + } } } + else d = 0; + + backref_cache[recno] = d; + for (i = backref_cache[0] + 1; i < recno; i++) backref_cache[i] = -1; + backref_cache[0] = recno; } - else d = 0; + cc += 1 + IMM2_SIZE; /* Handle repeated back references */ @@ -601,7 +644,7 @@ for (;;) this_recurse.prev = recurses; this_recurse.group = cs; prev_recurse_d = find_minlength(re, cs, startcode, utf, &this_recurse, - countptr); + countptr, backref_cache); if (prev_recurse_d < 0) return prev_recurse_d; prev_recurse_recno = recno; branchlength += prev_recurse_d; @@ -792,7 +835,7 @@ Returns: nothing static void set_type_bits(pcre2_real_code *re, int cbit_type, unsigned int table_limit) { -register uint32_t c; +uint32_t c; for (c = 0; c < table_limit; c++) re->start_bitmap[c] |= re->tables[c+cbits_offset+cbit_type]; #if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8 @@ -833,7 +876,7 @@ Returns: nothing static void set_nottype_bits(pcre2_real_code *re, int cbit_type, unsigned int table_limit) { -register uint32_t c; +uint32_t c; for (c = 0; c < table_limit; c++) re->start_bitmap[c] |= ~(re->tables[c+cbits_offset+cbit_type]); #if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8 @@ -873,7 +916,7 @@ Returns: SSB_FAIL => Failed to find any starting code units static int set_start_bits(pcre2_real_code *re, PCRE2_SPTR code, BOOL utf) { -register uint32_t c; +uint32_t c; int yield = SSB_DONE; #if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8 @@ -1546,12 +1589,20 @@ if ((re->overall_options & PCRE2_ANCHORED) == 0 && if (rc == SSB_DONE) re->flags |= PCRE2_FIRSTMAPSET; } -/* Find the minimum length of subject string. If it can match an empty string, -the minimum length is already known. */ +/* Find the minimum length of subject string. If the pattern can match an empty +string, the minimum length is already known. If there are more back references +than the size of the vector we are going to cache them in, do nothing. A +pattern that complicated will probably take a long time to analyze and may in +any case turn out to be too complicated. Note that back reference minima are +held as 16-bit numbers. */ -if ((re->flags & PCRE2_MATCH_EMPTY) == 0) +if ((re->flags & PCRE2_MATCH_EMPTY) == 0 && + re->top_backref <= MAX_CACHE_BACKREF) { - switch(min = find_minlength(re, code, code, utf, NULL, &count)) + int backref_cache[MAX_CACHE_BACKREF+1]; + backref_cache[0] = 0; /* Highest one that is set */ + min = find_minlength(re, code, code, utf, NULL, &count, backref_cache); + switch(min) { case -1: /* \C in UTF mode or (*ACCEPT) or over-complex regex */ break; /* Leave minlength unchanged (will be zero) */ diff --git a/ProcessHacker/pcre/pcre2_substitute.c b/ProcessHacker/pcre/pcre2_substitute.c index a5d0c84e98c4..c828e307f643 100644 --- a/ProcessHacker/pcre/pcre2_substitute.c +++ b/ProcessHacker/pcre/pcre2_substitute.c @@ -38,6 +38,7 @@ POSSIBILITY OF SUCH DAMAGE. ----------------------------------------------------------------------------- */ + #define HAVE_CONFIG_H #ifdef HAVE_CONFIG_H #include "config.h" @@ -114,7 +115,7 @@ for (; ptr < ptrend; ptr++) else if (*ptr == CHAR_BACKSLASH) { int erc; - int errorcode = 0; + int errorcode; uint32_t ch; if (ptr < ptrend - 1) switch (ptr[1]) @@ -127,8 +128,10 @@ for (; ptr < ptrend; ptr++) continue; } + ptr += 1; /* Must point after \ */ erc = PRIV(check_escape)(&ptr, ptrend, &ch, &errorcode, code->overall_options, FALSE, NULL); + ptr -= 1; /* Back to last code unit of escape */ if (errorcode != 0) { rc = errorcode; @@ -287,6 +290,12 @@ options &= ~SUBSTITUTE_OPTIONS; /* Copy up to the start offset */ +if (start_offset > length) + { + match_data->leftchar = 0; + rc = PCRE2_ERROR_BADOFFSET; + goto EXIT; + } CHECKMEMCPY(subject, start_offset); /* Loop for global substituting. */ @@ -698,7 +707,7 @@ do else if ((suboptions & PCRE2_SUBSTITUTE_EXTENDED) != 0 && *ptr == CHAR_BACKSLASH) { - int errorcode = 0; + int errorcode; if (ptr < repend - 1) switch (ptr[1]) { @@ -728,10 +737,10 @@ do break; } + ptr++; /* Point after \ */ rc = PRIV(check_escape)(&ptr, repend, &ch, &errorcode, code->overall_options, FALSE, NULL); if (errorcode != 0) goto BADESCAPE; - ptr++; switch(rc) { diff --git a/ProcessHacker/pcre/pcre2_tables.c b/ProcessHacker/pcre/pcre2_tables.c index a9e6bc01c521..be0c101bc226 100644 --- a/ProcessHacker/pcre/pcre2_tables.c +++ b/ProcessHacker/pcre/pcre2_tables.c @@ -44,8 +44,8 @@ which uses macros to change their names from _pcre2_xxx to xxxx, thereby avoiding name clashes with the library. In this case, PCRE2_PCRE2TEST is defined. */ -#ifndef PCRE2_PCRE2TEST /* We're compiling the library */ #define HAVE_CONFIG_H +#ifndef PCRE2_PCRE2TEST /* We're compiling the library */ #ifdef HAVE_CONFIG_H #include "config.h" #endif diff --git a/ProcessHacker/pcre/pcre2_ucp.h b/ProcessHacker/pcre/pcre2_ucp.h index 0b7553e5e062..02e5012c29c6 100644 --- a/ProcessHacker/pcre/pcre2_ucp.h +++ b/ProcessHacker/pcre/pcre2_ucp.h @@ -39,8 +39,8 @@ POSSIBILITY OF SUCH DAMAGE. */ -#ifndef _PCRE2_UCP_H -#define _PCRE2_UCP_H +#ifndef PCRE2_UCP_H_IDEMPOTENT_GUARD +#define PCRE2_UCP_H_IDEMPOTENT_GUARD /* This file contains definitions of the property values that are returned by the UCD access macros. New values that are added for new releases of Unicode @@ -263,6 +263,6 @@ enum { ucp_SignWriting }; -#endif +#endif /* PCRE2_UCP_H_IDEMPOTENT_GUARD */ /* End of pcre2_ucp.h */ diff --git a/ProcessHacker/pcre/pcre2_valid_utf.c b/ProcessHacker/pcre/pcre2_valid_utf.c index 86749b30efa0..ccc043a5e2ac 100644 --- a/ProcessHacker/pcre/pcre2_valid_utf.c +++ b/ProcessHacker/pcre/pcre2_valid_utf.c @@ -44,8 +44,8 @@ strings. This file is also #included by the pcre2test program, which uses macros to change names from _pcre2_xxx to xxxx, thereby avoiding name clashes with the library. In this case, PCRE2_PCRE2TEST is defined. */ -#ifndef PCRE2_PCRE2TEST /* We're compiling the library */ #define HAVE_CONFIG_H +#ifndef PCRE2_PCRE2TEST /* We're compiling the library */ #ifdef HAVE_CONFIG_H #include "config.h" #endif @@ -94,8 +94,8 @@ Returns: == 0 if the string is a valid UTF string int PRIV(valid_utf)(PCRE2_SPTR string, PCRE2_SIZE length, PCRE2_SIZE *erroroffset) { -register PCRE2_SPTR p; -register uint32_t c; +PCRE2_SPTR p; +uint32_t c; /* ----------------- Check a UTF-8 string ----------------- */ @@ -134,7 +134,7 @@ PCRE2_ERROR_UTF8_ERR21 Byte with the illegal value 0xfe or 0xff for (p = string; length > 0; p++) { - register uint32_t ab, d; + uint32_t ab, d; c = *p; length--; diff --git a/ProcessHacker/pcre/pcre2_xclass.c b/ProcessHacker/pcre/pcre2_xclass.c index ccff77056946..43d0150e7554 100644 --- a/ProcessHacker/pcre/pcre2_xclass.c +++ b/ProcessHacker/pcre/pcre2_xclass.c @@ -42,6 +42,7 @@ POSSIBILITY OF SUCH DAMAGE. class. It is used by pcre2_auto_possessify() and by both pcre2_match() and pcre2_def_match(). */ + #define HAVE_CONFIG_H #ifdef HAVE_CONFIG_H #include "config.h" diff --git a/ProcessHacker/pcre/pcre2posix.c b/ProcessHacker/pcre/pcre2posix.c index eb5926550119..343b835aa216 100644 --- a/ProcessHacker/pcre/pcre2posix.c +++ b/ProcessHacker/pcre/pcre2posix.c @@ -38,14 +38,15 @@ POSSIBILITY OF SUCH DAMAGE. ----------------------------------------------------------------------------- */ -// dmex: Disable warnings -#pragma warning(push) -#pragma warning(disable : 4267) /* This module is a wrapper that provides a POSIX API to the underlying PCRE2 functions. */ +// dmex: Disable warnings. +#pragma warning(push) +#pragma warning(disable : 4267) #define HAVE_CONFIG_H + #ifdef HAVE_CONFIG_H #include "config.h" #endif @@ -101,7 +102,7 @@ PCRE2_CALL_CONVENTION just before their names. It is rarely needed; if not set, we ensure here that it has no effect. */ #ifndef PCRE2_CALL_CONVENTION -#define PCRE2_CALL_CONVENTION +#define PCRE2_CALL_CONVENTION #endif /* Table to translate PCRE2 compile time error codes into POSIX error codes. @@ -289,8 +290,7 @@ return 0; /* A suitable match_data block, large enough to hold all possible captures, was obtained when the pattern was compiled, to save having to allocate and free it -for each match. If REG_NOSUB was specified at compile time, the -PCRE_NO_AUTO_CAPTURE flag will be set. When this is the case, the nmatch and +for each match. If REG_NOSUB was specified at compile time, the nmatch and pmatch arguments are ignored, and the only result is yes/no/error. */ PCRE2POSIX_EXP_DEFN int PCRE2_CALL_CONVENTION @@ -370,4 +370,4 @@ switch(rc) /* End of pcre2posix.c */ -#pragma warning(pop) \ No newline at end of file +#pragma warning(pop) diff --git a/ProcessHacker/pcre/pcre2posix.h b/ProcessHacker/pcre/pcre2posix.h index 5f2906a4f32c..6505976aa493 100644 --- a/ProcessHacker/pcre/pcre2posix.h +++ b/ProcessHacker/pcre/pcre2posix.h @@ -56,7 +56,7 @@ extern "C" { #define REG_NOTBOL 0x0004 /* Maps to PCRE2_NOTBOL */ #define REG_NOTEOL 0x0008 /* Maps to PCRE2_NOTEOL */ #define REG_DOTALL 0x0010 /* NOT defined by POSIX; maps to PCRE2_DOTALL */ -#define REG_NOSUB 0x0020 /* Maps to PCRE2_NO_AUTO_CAPTURE */ +#define REG_NOSUB 0x0020 /* Do not report what was matched */ #define REG_UTF 0x0040 /* NOT defined by POSIX; maps to PCRE2_UTF */ #define REG_STARTEND 0x0080 /* BSD feature: pass subject string by so,eo */ #define REG_NOTEMPTY 0x0100 /* NOT defined by POSIX; maps to PCRE2_NOTEMPTY */ From 9880e279073a2f45eaac864c500d2cf48114fb0e Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 9 Jul 2017 05:19:03 +1000 Subject: [PATCH 0265/2058] Fix launcher issue with PhGetApplicationFileName --- phlib/util.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/phlib/util.c b/phlib/util.c index 0e68f3bd2136..35e9ef167aec 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -2199,6 +2199,11 @@ PPH_STRING PhGetApplicationFileName( VOID ) { + PPH_STRING fileName; + + if (NT_SUCCESS(PhGetProcessImageFileNameWin32(NtCurrentProcess(), &fileName))) + return fileName; + return PhGetDllFileName(NtCurrentPeb()->ImageBaseAddress, NULL); } @@ -2210,13 +2215,20 @@ PPH_STRING PhGetApplicationDirectory( ) { PPH_STRING fileName; - ULONG indexOfFileName; + ULONG_PTR indexOfFileName; PPH_STRING path = NULL; - fileName = PhGetDllFileName(NtCurrentPeb()->ImageBaseAddress, &indexOfFileName); + fileName = PhGetApplicationFileName(); if (fileName) { + indexOfFileName = PhFindLastCharInString(fileName, 0, '\\'); + + if (indexOfFileName != -1) + indexOfFileName++; + else + indexOfFileName = 0; + if (indexOfFileName != 0) { // Remove the file name from the path. From 2a279d602b9ea88559e73724c99429fac5e397ff Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 9 Jul 2017 16:28:11 +1000 Subject: [PATCH 0266/2058] Convert more message dialogs to TaskDialogs --- .gitattributes | 1 + ProcessHacker/ProcessHacker.def | 3 +-- ProcessHacker/actions.c | 13 ++++++------- ProcessHacker/main.c | 9 +++++---- ProcessHacker/mdump.c | 7 ++++--- ProcessHacker/options.c | 15 +++++++++------ ProcessHacker/plugman.c | 9 +++++++-- ProcessHacker/srvprp.c | 8 +++++--- phlib/include/phutil.h | 10 ---------- phlib/util.c | 20 +++++--------------- tools/peview/settings.c | 7 ++++--- 11 files changed, 47 insertions(+), 55 deletions(-) diff --git a/.gitattributes b/.gitattributes index ba1245642f8e..8c535f62e19d 100644 --- a/.gitattributes +++ b/.gitattributes @@ -16,6 +16,7 @@ *.config eol=crlf *.cmd eol=crlf *.csproj eol=crlf +*.def eol=crlf *.h eol=crlf *.manifest eol=crlf *.resx eol=crlf diff --git a/ProcessHacker/ProcessHacker.def b/ProcessHacker/ProcessHacker.def index 9e693cb33b12..d2e5565ca064 100644 --- a/ProcessHacker/ProcessHacker.def +++ b/ProcessHacker/ProcessHacker.def @@ -381,10 +381,9 @@ EXPORTS PhShellProperties PhShowConfirmMessage PhShowContinueStatus - PhShowMessage2 PhShowFileDialog PhShowMessage - PhShowMessage_V + PhShowMessage2 PhShowStatus PhUpdateHash diff --git a/ProcessHacker/actions.c b/ProcessHacker/actions.c index b822fd9f75a8..1f60c510791f 100644 --- a/ProcessHacker/actions.c +++ b/ProcessHacker/actions.c @@ -1634,7 +1634,7 @@ BOOLEAN PhUiDetachFromDebuggerProcess( if (status == STATUS_PORT_NOT_SET) { - PhShowInformation(hWnd, L"The process is not being debugged."); + PhShowInformation2(hWnd, L"The process is not being debugged.", L""); return FALSE; } @@ -2262,13 +2262,12 @@ BOOLEAN PhUiCloseConnections( } else { - if (PhShowMessage( + if (PhShowMessage2( hWnd, - MB_ICONERROR | MB_OKCANCEL, - L"Unable to close the TCP connection (from %s:%u). " - L"Make sure Process Hacker is running with administrative privileges.", - Connections[i]->LocalAddressString, - Connections[i]->LocalEndpoint.Port + TDCBF_OK_BUTTON, + TD_ERROR_ICON, + L"Unable to close the TCP connection.", + L"Make sure Process Hacker is running with administrative privileges." ) != IDOK) break; } diff --git a/ProcessHacker/main.c b/ProcessHacker/main.c index 0923076ecf9a..dabb1af18e6f 100644 --- a/ProcessHacker/main.c +++ b/ProcessHacker/main.c @@ -667,10 +667,11 @@ VOID PhpInitializeSettings( // change anything. if (status == STATUS_FILE_CORRUPT_ERROR) { - if (PhShowMessage( - NULL, - MB_ICONWARNING | MB_YESNO, - L"Process Hacker's settings file is corrupt. Do you want to reset it?\n" + if (PhShowMessage2( + PhMainWndHandle, + TDCBF_YES_BUTTON | TDCBF_NO_BUTTON, + TD_WARNING_ICON, + L"Process Hacker's settings file is corrupt. Do you want to reset it?", L"If you select No, the settings system will not function properly." ) == IDYES) { diff --git a/ProcessHacker/mdump.c b/ProcessHacker/mdump.c index 8214941f406a..b31dc20ae7b3 100644 --- a/ProcessHacker/mdump.c +++ b/ProcessHacker/mdump.c @@ -278,10 +278,11 @@ NTSTATUS PhpProcessMiniDumpThreadStart( } else { - if (PhShowMessage( + if (PhShowMessage2( context->WindowHandle, - MB_YESNO | MB_ICONWARNING, - L"The process is 32-bit, but the 32-bit version of Process Hacker could not be located. " + TDCBF_YES_BUTTON | TDCBF_NO_BUTTON, + TD_WARNING_ICON, + L"The 32-bit version of Process Hacker could not be located.", L"A 64-bit dump will be created instead. Do you want to continue?" ) == IDNO) { diff --git a/ProcessHacker/options.c b/ProcessHacker/options.c index 21944675fa3e..9e0232f4b06f 100644 --- a/ProcessHacker/options.c +++ b/ProcessHacker/options.c @@ -207,10 +207,11 @@ VOID PhShowOptionsDialog( if (RestartRequired) { - if (PhShowMessage( + if (PhShowMessage2( PhMainWndHandle, - MB_ICONQUESTION | MB_YESNO, - L"One or more options you have changed requires a restart of Process Hacker. " + TDCBF_YES_BUTTON | TDCBF_NO_BUTTON, + TD_INFORMATION_ICON, + L"One or more options you have changed requires a restart of Process Hacker.", L"Do you want to restart Process Hacker now?" ) == IDYES) { @@ -330,10 +331,12 @@ LRESULT CALLBACK PhpOptionsWndProc( { case IDC_RESET: { - if (PhShowMessage( + if (PhShowMessage2( hwnd, - MB_ICONWARNING | MB_YESNO | MB_DEFBUTTON2, - L"Do you want to reset all settings and restart Process Hacker?" + TDCBF_YES_BUTTON | TDCBF_NO_BUTTON, + TD_WARNING_ICON, + L"Do you want to reset all settings and restart Process Hacker?", + L"" ) == IDYES) { ProcessHacker_PrepareForEarlyShutdown(PhMainWndHandle); diff --git a/ProcessHacker/plugman.c b/ProcessHacker/plugman.c index a7c4314126a5..65d84a0767ed 100644 --- a/ProcessHacker/plugman.c +++ b/ProcessHacker/plugman.c @@ -380,8 +380,13 @@ INT_PTR CALLBACK PhpPluginsDlgProc( break; case IDC_CLEANUP: { - if (PhShowMessage(hwndDlg, MB_ICONQUESTION | MB_YESNO, - L"Do you want to clean up unused plugin settings?") == IDYES) + if (PhShowMessage2( + hwndDlg, + TDCBF_YES_BUTTON | TDCBF_NO_BUTTON, + TD_INFORMATION_ICON, + L"Do you want to clean up unused plugin settings?", + L"" + ) == IDYES) { PhClearIgnoredSettings(); } diff --git a/ProcessHacker/srvprp.c b/ProcessHacker/srvprp.c index e9cc3f1ac26c..0aab0620ecae 100644 --- a/ProcessHacker/srvprp.c +++ b/ProcessHacker/srvprp.c @@ -537,10 +537,12 @@ INT_PTR CALLBACK PhpServiceGeneralDlgProc( goto Cleanup; ErrorCase: - if (PhShowMessage( + if (PhShowMessage2( hwndDlg, - MB_ICONERROR | MB_RETRYCANCEL, - L"Unable to change service configuration: %s", + TDCBF_RETRY_BUTTON | TDCBF_CANCEL_BUTTON, + TD_ERROR_ICON, + L"Unable to change service configuration.", + L"%s", PH_AUTO_T(PH_STRING, PhGetWin32Message(GetLastError()))->Buffer ) == IDRETRY) { diff --git a/phlib/include/phutil.h b/phlib/include/phutil.h index 34a020c2ba4e..d5dbdb468868 100644 --- a/phlib/include/phutil.h +++ b/phlib/include/phutil.h @@ -222,16 +222,6 @@ PhShowMessage( ... ); -PHLIBAPI -INT -NTAPI -PhShowMessage_V( - _In_ HWND hWnd, - _In_ ULONG Type, - _In_ PWSTR Format, - _In_ va_list ArgPtr - ); - #define PhShowError(hWnd, Format, ...) PhShowMessage(hWnd, MB_OK | MB_ICONERROR, Format, __VA_ARGS__) #define PhShowWarning(hWnd, Format, ...) PhShowMessage(hWnd, MB_OK | MB_ICONWARNING, Format, __VA_ARGS__) #define PhShowInformation(hWnd, Format, ...) PhShowMessage(hWnd, MB_OK | MB_ICONINFORMATION, Format, __VA_ARGS__) diff --git a/phlib/util.c b/phlib/util.c index 35e9ef167aec..e33e0e449da9 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -374,25 +374,15 @@ INT PhShowMessage( _In_ PWSTR Format, ... ) -{ - va_list argptr; - - va_start(argptr, Format); - - return PhShowMessage_V(hWnd, Type, Format, argptr); -} - -INT PhShowMessage_V( - _In_ HWND hWnd, - _In_ ULONG Type, - _In_ PWSTR Format, - _In_ va_list ArgPtr - ) { INT result; + va_list argptr; PPH_STRING message; - message = PhFormatString_V(Format, ArgPtr); + va_start(argptr, Format); + va_start(argptr, Format); + message = PhFormatString_V(Format, argptr); + va_end(argptr); if (!message) return -1; diff --git a/tools/peview/settings.c b/tools/peview/settings.c index 750ce1ace2ea..224075b64973 100644 --- a/tools/peview/settings.c +++ b/tools/peview/settings.c @@ -94,10 +94,11 @@ VOID PeInitializeSettings( // change anything. if (status == STATUS_FILE_CORRUPT_ERROR) { - if (PhShowMessage( + if (PhShowMessage2( NULL, - MB_ICONWARNING | MB_YESNO, - L"PE View's settings file is corrupt. Do you want to reset it?\n" + TDCBF_YES_BUTTON | TDCBF_NO_BUTTON, + TD_WARNING_ICON, + L"PE View's settings file is corrupt. Do you want to reset it?", L"If you select No, the settings system will not function properly." ) == IDYES) { From 6ac84c04f37a1a40b07c86ed4a2e852ed2c5861e Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 10 Jul 2017 15:02:02 +1000 Subject: [PATCH 0267/2058] Add missing error check --- ProcessHacker/main.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/ProcessHacker/main.c b/ProcessHacker/main.c index dabb1af18e6f..216a7f81a09a 100644 --- a/ProcessHacker/main.c +++ b/ProcessHacker/main.c @@ -558,7 +558,6 @@ VOID PhInitializeKph( { static PH_STRINGREF kprocesshacker = PH_STRINGREF_INIT(L"kprocesshacker.sys"); static PH_STRINGREF processhackerSig = PH_STRINGREF_INIT(L"ProcessHacker.sig"); - PPH_STRING kprocesshackerFileName; PPH_STRING processhackerSigFileName; KPH_PARAMETERS parameters; @@ -571,14 +570,16 @@ VOID PhInitializeKph( kprocesshackerFileName = PhConcatStringRef2(&PhApplicationDirectory->sr, &kprocesshacker); processhackerSigFileName = PhConcatStringRef2(&PhApplicationDirectory->sr, &processhackerSig); - parameters.SecurityLevel = KphSecurityPrivilegeCheck; + parameters.SecurityLevel = KphSecuritySignatureCheck; parameters.CreateDynamicConfiguration = TRUE; - KphConnect2Ex(KPH_DEVICE_SHORT_NAME, kprocesshackerFileName->Buffer, ¶meters); - if (signature = PhpReadSignature(processhackerSigFileName->Buffer, &signatureSize)) + if (NT_SUCCESS(KphConnect2Ex(KPH_DEVICE_SHORT_NAME, kprocesshackerFileName->Buffer, ¶meters))) { - KphVerifyClient(signature, signatureSize); - PhFree(signature); + if (signature = PhpReadSignature(processhackerSigFileName->Buffer, &signatureSize)) + { + KphVerifyClient(signature, signatureSize); + PhFree(signature); + } } PhDereferenceObject(kprocesshackerFileName); From 968c8ca640e6a2678698c5e4b0a09fff2af6bf86 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 10 Jul 2017 16:24:37 +1000 Subject: [PATCH 0268/2058] treeview: Use system colors by default (feature request) https://wj32.org/processhacker/forums/viewtopic.php?f=14&t=2694 --- phlib/treenew.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/phlib/treenew.c b/phlib/treenew.c index bd96c52cfcc6..c571a64b7b21 100644 --- a/phlib/treenew.c +++ b/phlib/treenew.c @@ -450,7 +450,7 @@ BOOLEAN PhTnpOnCreate( } if (!(Context->VScrollHandle = CreateWindow( - L"SCROLLBAR", + WC_SCROLLBAR, NULL, WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | SBS_VERT, 0, @@ -467,7 +467,7 @@ BOOLEAN PhTnpOnCreate( } if (!(Context->HScrollHandle = CreateWindow( - L"SCROLLBAR", + WC_SCROLLBAR, NULL, WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | SBS_HORZ, 0, @@ -484,7 +484,7 @@ BOOLEAN PhTnpOnCreate( } if (!(Context->FillerBoxHandle = CreateWindow( - L"STATIC", + WC_STATIC, NULL, WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE, 0, @@ -5183,8 +5183,8 @@ VOID PhTnpPrepareRowForDraw( getNodeColor.Flags = 0; getNodeColor.Node = Node; - getNodeColor.BackColor = RGB(0xff, 0xff, 0xff); - getNodeColor.ForeColor = RGB(0x00, 0x00, 0x00); + getNodeColor.BackColor = GetSysColor(COLOR_WINDOW); // RGB(0xff, 0xff, 0xff) + getNodeColor.ForeColor = GetSysColor(COLOR_WINDOWTEXT); // RGB(0x00, 0x00, 0x00) if (Context->Callback( Context->Handle, From ca73c09e6032883aa03c63afdfd25123a705606e Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 10 Jul 2017 16:37:42 +1000 Subject: [PATCH 0269/2058] treeview: Improve previous commit --- phlib/include/treenewp.h | 2 ++ phlib/treenew.c | 6 ++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/phlib/include/treenewp.h b/phlib/include/treenewp.h index 8904a3a1a7cb..997bbf8980ca 100644 --- a/phlib/include/treenewp.h +++ b/phlib/include/treenewp.h @@ -132,6 +132,8 @@ typedef struct _PH_TREENEW_CONTEXT TEXTMETRIC TextMetrics; HTHEME ThemeData; + COLORREF DefaultBackColor; + COLORREF DefaultForeColor; LONG SystemBorderX; LONG SystemBorderY; LONG SystemEdgeX; diff --git a/phlib/treenew.c b/phlib/treenew.c index c571a64b7b21..639d57cf4a17 100644 --- a/phlib/treenew.c +++ b/phlib/treenew.c @@ -340,6 +340,8 @@ VOID PhTnpCreateTreeNewContext( context->TooltipId = -1; context->TooltipColumnId = -1; context->EnableRedraw = 1; + context->DefaultBackColor = GetSysColor(COLOR_WINDOW); // RGB(0xff, 0xff, 0xff) + context->DefaultForeColor = GetSysColor(COLOR_WINDOWTEXT); // RGB(0x00, 0x00, 0x00) *Context = context; } @@ -5183,8 +5185,8 @@ VOID PhTnpPrepareRowForDraw( getNodeColor.Flags = 0; getNodeColor.Node = Node; - getNodeColor.BackColor = GetSysColor(COLOR_WINDOW); // RGB(0xff, 0xff, 0xff) - getNodeColor.ForeColor = GetSysColor(COLOR_WINDOWTEXT); // RGB(0x00, 0x00, 0x00) + getNodeColor.BackColor = Context->DefaultBackColor; + getNodeColor.ForeColor = Context->DefaultForeColor; if (Context->Callback( Context->Handle, From e140ae4a8fee01e5607cb6d99692a788e9af3d2d Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 10 Jul 2017 16:58:32 +1000 Subject: [PATCH 0270/2058] WindowExplorer: Fix regression --- plugins/WindowExplorer/main.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/plugins/WindowExplorer/main.c b/plugins/WindowExplorer/main.c index 293fddfb2e29..e0fbcffdc876 100644 --- a/plugins/WindowExplorer/main.c +++ b/plugins/WindowExplorer/main.c @@ -34,7 +34,6 @@ PH_CALLBACK_REGISTRATION MainMenuInitializingCallbackRegistration; PH_CALLBACK_REGISTRATION ProcessPropertiesInitializingCallbackRegistration; PH_CALLBACK_REGISTRATION ThreadMenuInitializingCallbackRegistration; - VOID NTAPI LoadCallback( _In_opt_ PVOID Parameter, _In_opt_ PVOID Context @@ -231,7 +230,7 @@ LOGICAL DllMain( isClient = FALSE; - if (!GetModuleHandle(L"ProcessHacker.exe") || !WeGetProcedureAddress("PhLibImageBase")) + if (!GetModuleHandle(L"ProcessHacker.exe") || !WeGetProcedureAddress("PhInstanceHandle")) { isClient = TRUE; } From 3476d5c8c3fd433e92e42947bf840b867c00ed4e Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 11 Jul 2017 11:35:14 +1000 Subject: [PATCH 0271/2058] Fix splitter GDI leak --- ProcessHacker/include/splitter.h | 4 +++ ProcessHacker/settings.c | 2 +- ProcessHacker/splitter.c | 46 ++++++++++++++++++++------------ 3 files changed, 34 insertions(+), 18 deletions(-) diff --git a/ProcessHacker/include/splitter.h b/ProcessHacker/include/splitter.h index 9be37f0023cd..75be46d7593b 100644 --- a/ProcessHacker/include/splitter.h +++ b/ProcessHacker/include/splitter.h @@ -20,6 +20,10 @@ typedef struct _PH_HSPLITTER_CONTEXT HWND ParentWindow; HWND TopWindow; HWND BottomWindow; + + HBRUSH FocusBrush; + HBRUSH HotBrush; + HBRUSH NormalBrush; } PH_HSPLITTER_CONTEXT, *PPH_HSPLITTER_CONTEXT; PPH_HSPLITTER_CONTEXT PhInitializeHSplitter( diff --git a/ProcessHacker/settings.c b/ProcessHacker/settings.c index bda87b5abf52..2948a89275c0 100644 --- a/ProcessHacker/settings.c +++ b/ProcessHacker/settings.c @@ -147,7 +147,7 @@ VOID PhAddDefaultSettings( PhpAddStringSetting(L"ThreadStackListViewColumns", L""); PhpAddScalableIntegerPairSetting(L"ThreadStackWindowSize", L"@96|420,380"); PhpAddStringSetting(L"TokenGroupsListViewColumns", L""); - PhpAddIntegerSetting(L"TokenSplitterPosition", L"250"); + PhpAddIntegerSetting(L"TokenSplitterPosition", L"150"); PhpAddStringSetting(L"TokenPrivilegesListViewColumns", L""); PhpAddIntegerSetting(L"UpdateInterval", L"3e8"); // 1000ms diff --git a/ProcessHacker/splitter.c b/ProcessHacker/splitter.c index 0516fc2cd81d..4de4d68eb34f 100644 --- a/ProcessHacker/splitter.c +++ b/ProcessHacker/splitter.c @@ -91,16 +91,16 @@ LRESULT CALLBACK HSplitterWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM GetClientRect(hwnd, &clientRect); if (context->HasFocus) - FillRect(hdc, &clientRect, CreateSolidBrush(RGB(0x0, 0x0, 0x0))); + FillRect(hdc, &clientRect, context->FocusBrush); else if (context->Hot) - FillRect(hdc, &clientRect, CreateSolidBrush(RGB(0x44, 0x44, 0x44))); + FillRect(hdc, &clientRect, context->HotBrush); else - FillRect(hdc, &clientRect, GetSysColorBrush(COLOR_WINDOW)); + FillRect(hdc, &clientRect, context->NormalBrush); EndPaint(hwnd, &paintStruct); } } - return 0; + return 1; case WM_ERASEBKGND: return 1; case WM_LBUTTONDOWN: @@ -145,6 +145,12 @@ LRESULT CALLBACK HSplitterWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM return 0; case WM_MOUSEMOVE: { + INT width; + INT height; + INT NewPos; + HDWP deferHandle; + POINT cursorPos; + if (!context->Hot) { TRACKMOUSEEVENT trackMouseEvent = { sizeof(trackMouseEvent) }; @@ -158,19 +164,17 @@ LRESULT CALLBACK HSplitterWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM if (!context->HasFocus) break; - int Width = GetClientWindowWidth(context->ParentWindow); - int NewPos; - HDWP deferHandle; - POINT cursorPos; - GetCursorPos(&cursorPos); ScreenToClient(context->ParentWindow, &cursorPos); NewPos = cursorPos.y; + width = GetClientWindowWidth(context->ParentWindow); + height = GetClientWindowHeight(context->ParentWindow); if (NewPos < 200) break; - if (NewPos > GetClientWindowHeight(context->ParentWindow) - 80) + if (NewPos > height - 80) break; + context->SplitterOffset = NewPos; deferHandle = BeginDeferWindowPos(3); @@ -180,7 +184,7 @@ LRESULT CALLBACK HSplitterWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM NULL, SPLITTER_PADDING, 90, - Width - SPLITTER_PADDING * 2, + width - SPLITTER_PADDING * 2, cursorPos.y - 90, SWP_NOZORDER | SWP_NOACTIVATE ); @@ -190,7 +194,7 @@ LRESULT CALLBACK HSplitterWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM NULL, 0, cursorPos.y, - Width, + width, SPLITTER_PADDING, SWP_NOZORDER | SWP_NOACTIVATE ); @@ -200,8 +204,8 @@ LRESULT CALLBACK HSplitterWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM NULL, SPLITTER_PADDING, cursorPos.y + SPLITTER_PADDING, - Width - SPLITTER_PADDING * 2, - GetClientWindowHeight(context->ParentWindow) - (cursorPos.y + SPLITTER_PADDING) - 65, + width - SPLITTER_PADDING * 2, + height - (cursorPos.y + SPLITTER_PADDING) - 65, SWP_NOZORDER | SWP_NOACTIVATE ); @@ -229,6 +233,9 @@ PPH_HSPLITTER_CONTEXT PhInitializeHSplitter( context->TopWindow = TopWindow; context->BottomWindow = BottomWindow; context->SplitterOffset = PhGetIntegerSetting(L"TokenSplitterPosition"); + context->FocusBrush = CreateSolidBrush(RGB(0x0, 0x0, 0x0)); + context->HotBrush = CreateSolidBrush(RGB(0x44, 0x44, 0x44)); + context->NormalBrush = GetSysColorBrush(COLOR_WINDOW); if (PhBeginInitOnce(&initOnce)) { @@ -252,14 +259,14 @@ PPH_HSPLITTER_CONTEXT PhInitializeHSplitter( } context->Window = CreateWindowEx( - WS_EX_CONTROLPARENT | WS_EX_TRANSPARENT, + WS_EX_TRANSPARENT, L"PhHSplitter", NULL, WS_CHILD | WS_VISIBLE, 5, 5, - 465, - 10, + 5, + 5, ParentWindow, NULL, PhInstanceHandle, @@ -277,6 +284,11 @@ VOID PhDeleteHSplitter( ) { PhSetIntegerSetting(L"TokenSplitterPosition", Context->SplitterOffset); + + if (Context->FocusBrush) + DeleteObject(Context->FocusBrush); + if (Context->HotBrush) + DeleteObject(Context->HotBrush); } VOID PhHSplitterHandleWmSize( From 780d49e3109ee3568c7b889a2b0a1b61b785bbb3 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 11 Jul 2017 13:31:54 +1000 Subject: [PATCH 0272/2058] NetworkTools: Fix typo --- plugins/NetworkTools/tracert.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/NetworkTools/tracert.c b/plugins/NetworkTools/tracert.c index dd98669b9af2..9e4bb57c0279 100644 --- a/plugins/NetworkTools/tracert.c +++ b/plugins/NetworkTools/tracert.c @@ -703,7 +703,7 @@ NTSTATUS TracertDialogThreadStart( if (result == -1) break; - if (!IsDialogMessage(context->WindowHandle, &message)) + if (!IsDialogMessage(windowHandle, &message)) { TranslateMessage(&message); DispatchMessage(&message); From 51d31463bf6629dc8f1d8374c83ebad0a26a1d32 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 11 Jul 2017 16:49:04 +1000 Subject: [PATCH 0273/2058] Fix issue with process starttime and timezone changes --- phlib/include/phutil.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/phlib/include/phutil.h b/phlib/include/phutil.h index d5dbdb468868..2cf2f00573e6 100644 --- a/phlib/include/phutil.h +++ b/phlib/include/phutil.h @@ -164,12 +164,11 @@ PhLargeIntegerToLocalSystemTime( ) { FILETIME fileTime; - FILETIME newFileTime; fileTime.dwLowDateTime = LargeInteger->LowPart; fileTime.dwHighDateTime = LargeInteger->HighPart; - FileTimeToLocalFileTime(&fileTime, &newFileTime); - FileTimeToSystemTime(&newFileTime, SystemTime); + FileTimeToSystemTime(&fileTime, SystemTime); + SystemTimeToTzSpecificLocalTime(NULL, SystemTime, SystemTime); } PHLIBAPI From 89d9e3ba2289e7bfc9065b2349b04e33c16fe296 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 11 Jul 2017 16:49:46 +1000 Subject: [PATCH 0274/2058] Fix typo --- ProcessHacker/syssccpu.c | 2 +- plugins/ToolStatus/graph.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ProcessHacker/syssccpu.c b/ProcessHacker/syssccpu.c index c2a6cc7d9a69..a08ab77f489a 100644 --- a/ProcessHacker/syssccpu.c +++ b/ProcessHacker/syssccpu.c @@ -768,7 +768,7 @@ PPH_PROCESS_RECORD PhSipReferenceMaxCpuRecord( // * If we call PhFindProcessRecord, it cannot find the process because it was // started at 2.5 seconds, not 2 seconds or older. // - // This mean we must add one second minus one tick (100ns) to the time, giving us + // This means we must add one second minus one tick (100ns) to the time, giving us // 2.9999999 seconds. This will then make sure we find the process. PhGetStatisticsTime(NULL, Index, &time); time.QuadPart += PH_TICKS_PER_SEC - 1; diff --git a/plugins/ToolStatus/graph.c b/plugins/ToolStatus/graph.c index c8effcd4396e..7550714f44fb 100644 --- a/plugins/ToolStatus/graph.c +++ b/plugins/ToolStatus/graph.c @@ -285,7 +285,7 @@ static PPH_PROCESS_RECORD PhSipReferenceMaxCpuRecord( // * If we call PhFindProcessRecord, it cannot find the process because it was // started at 2.5 seconds, not 2 seconds or older. // - // This mean we must add one second minus one tick (100ns) to the time, giving us + // This means we must add one second minus one tick (100ns) to the time, giving us // 2.9999999 seconds. This will then make sure we find the process. PhGetStatisticsTime(NULL, Index, &time); time.QuadPart += PH_TICKS_PER_SEC - 1; From 1c567b83e815af81bc06ff0f6c817c17af8b3d31 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 11 Jul 2017 17:18:20 +1000 Subject: [PATCH 0275/2058] Revert "Fix issue with process starttime and timezone changes" This reverts commit 51d31463bf6629dc8f1d8374c83ebad0a26a1d32. --- phlib/include/phutil.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/phlib/include/phutil.h b/phlib/include/phutil.h index 2cf2f00573e6..d5dbdb468868 100644 --- a/phlib/include/phutil.h +++ b/phlib/include/phutil.h @@ -164,11 +164,12 @@ PhLargeIntegerToLocalSystemTime( ) { FILETIME fileTime; + FILETIME newFileTime; fileTime.dwLowDateTime = LargeInteger->LowPart; fileTime.dwHighDateTime = LargeInteger->HighPart; - FileTimeToSystemTime(&fileTime, SystemTime); - SystemTimeToTzSpecificLocalTime(NULL, SystemTime, SystemTime); + FileTimeToLocalFileTime(&fileTime, &newFileTime); + FileTimeToSystemTime(&newFileTime, SystemTime); } PHLIBAPI From f0c02aaabcf3c0690311dc8a6a1b8bdb6d5f9e57 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 11 Jul 2017 19:18:43 +1000 Subject: [PATCH 0276/2058] Fix virtual device path issues --- phlib/util.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/phlib/util.c b/phlib/util.c index e33e0e449da9..2fd650b27028 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -2192,7 +2192,10 @@ PPH_STRING PhGetApplicationFileName( PPH_STRING fileName; if (NT_SUCCESS(PhGetProcessImageFileNameWin32(NtCurrentProcess(), &fileName))) + { + PhMoveReference(&fileName, PhGetFileName(fileName)); return fileName; + } return PhGetDllFileName(NtCurrentPeb()->ImageBaseAddress, NULL); } From 7b5570a25048e3618d1f1ffa30f3a86f56cb8303 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 12 Jul 2017 01:55:49 +1000 Subject: [PATCH 0277/2058] Add workaround for unknown services on RS2 --- ProcessHacker/srvprv.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/ProcessHacker/srvprv.c b/ProcessHacker/srvprv.c index fc2d8b6d1ba9..70dc41e6b684 100644 --- a/ProcessHacker/srvprv.c +++ b/ProcessHacker/srvprv.c @@ -129,6 +129,15 @@ PPH_SERVICE_ITEM PhCreateServiceItem( if (Information) { + if (WindowsVersion >= WINDOWS_10_RS2) + { + // https://github.com/processhacker2/processhacker/issues/120 + if (Information->ServiceStatusProcess.dwServiceType == SERVICE_WIN32) + Information->ServiceStatusProcess.dwServiceType = SERVICE_WIN32_SHARE_PROCESS; + if (Information->ServiceStatusProcess.dwServiceType == (SERVICE_WIN32 | SERVICE_USER_SHARE_PROCESS | SERVICE_USERSERVICE_INSTANCE)) + Information->ServiceStatusProcess.dwServiceType = SERVICE_USER_SHARE_PROCESS | SERVICE_USERSERVICE_INSTANCE; + } + serviceItem->Name = PhCreateString(Information->lpServiceName); serviceItem->Key = serviceItem->Name->sr; serviceItem->DisplayName = PhCreateString(Information->lpDisplayName); @@ -645,6 +654,15 @@ VOID PhServiceProviderUpdate( } else { + if (WindowsVersion >= WINDOWS_10_RS2) + { + // https://github.com/processhacker2/processhacker/issues/120 + if (serviceEntry->ServiceStatusProcess.dwServiceType == SERVICE_WIN32) + serviceEntry->ServiceStatusProcess.dwServiceType = SERVICE_WIN32_SHARE_PROCESS; + if (serviceEntry->ServiceStatusProcess.dwServiceType == (SERVICE_WIN32 | SERVICE_USER_SHARE_PROCESS | SERVICE_USERSERVICE_INSTANCE)) + serviceEntry->ServiceStatusProcess.dwServiceType = SERVICE_USER_SHARE_PROCESS | SERVICE_USERSERVICE_INSTANCE; + } + if ( serviceItem->Type != serviceEntry->ServiceStatusProcess.dwServiceType || serviceItem->State != serviceEntry->ServiceStatusProcess.dwCurrentState || From e5802a1235f3bc7cbdb6f46523a9739ab0df9c47 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 12 Jul 2017 19:13:44 +1000 Subject: [PATCH 0278/2058] Enable advanced ACL dialogs by default --- ProcessHacker/settings.c | 1 + phlib/secedit.c | 7 +++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/ProcessHacker/settings.c b/ProcessHacker/settings.c index 2948a89275c0..19c10e064859 100644 --- a/ProcessHacker/settings.c +++ b/ProcessHacker/settings.c @@ -47,6 +47,7 @@ VOID PhAddDefaultSettings( PhpAddIntegerSetting(L"EnableStage2", L"1"); PhpAddIntegerSetting(L"EnableWarnings", L"1"); PhpAddIntegerSetting(L"EnableWindowText", L"1"); + PhpAddIntegerSetting(L"EnableSecurityAdvancedDialog", L"1"); PhpAddStringSetting(L"EnvironmentListViewColumns", L""); PhpAddIntegerSetting(L"FindObjRegex", L"0"); PhpAddStringSetting(L"FindObjListViewColumns", L""); diff --git a/phlib/secedit.c b/phlib/secedit.c index f1c09a04cb80..9208498591f5 100644 --- a/phlib/secedit.c +++ b/phlib/secedit.c @@ -25,7 +25,7 @@ #include #include - +#include #include static ISecurityInformationVtbl PhSecurityInformation_VTable = @@ -118,7 +118,10 @@ VOID PhEditSecurity( FALSE ); - EditSecurity(hWnd, info); + if (PhGetIntegerSetting(L"EnableSecurityAdvancedDialog")) + EditSecurityAdvanced(NULL, info, COMBINE_PAGE_ACTIVATION(SI_PAGE_PERM, SI_SHOW_PERM_ACTIVATED)); + else + EditSecurity(hWnd, info); PhSecurityInformation_Release(info); } From 5e6a57048df71465bb3657d3bb05f2b902b31e0a Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 12 Jul 2017 19:46:45 +1000 Subject: [PATCH 0279/2058] Fix advanced ACL dialog parent --- phlib/secedit.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phlib/secedit.c b/phlib/secedit.c index 9208498591f5..99bdeef28d85 100644 --- a/phlib/secedit.c +++ b/phlib/secedit.c @@ -119,7 +119,7 @@ VOID PhEditSecurity( ); if (PhGetIntegerSetting(L"EnableSecurityAdvancedDialog")) - EditSecurityAdvanced(NULL, info, COMBINE_PAGE_ACTIVATION(SI_PAGE_PERM, SI_SHOW_PERM_ACTIVATED)); + EditSecurityAdvanced(hWnd, info, COMBINE_PAGE_ACTIVATION(SI_PAGE_PERM, SI_SHOW_PERM_ACTIVATED)); else EditSecurity(hWnd, info); From dca4b534e75aea99c78c70a5a631f29aacc79be8 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 12 Jul 2017 22:09:41 +1000 Subject: [PATCH 0280/2058] disable advanced security dialog on windows 7 --- phlib/secedit.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phlib/secedit.c b/phlib/secedit.c index 99bdeef28d85..65057fae144d 100644 --- a/phlib/secedit.c +++ b/phlib/secedit.c @@ -118,7 +118,7 @@ VOID PhEditSecurity( FALSE ); - if (PhGetIntegerSetting(L"EnableSecurityAdvancedDialog")) + if (WindowsVersion >= WINDOWS_8_1 && PhGetIntegerSetting(L"EnableSecurityAdvancedDialog")) EditSecurityAdvanced(hWnd, info, COMBINE_PAGE_ACTIVATION(SI_PAGE_PERM, SI_SHOW_PERM_ACTIVATED)); else EditSecurity(hWnd, info); From d7342929f1426e597b95e0c20a9b9651d406f410 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 13 Jul 2017 20:25:05 +1000 Subject: [PATCH 0281/2058] Remove debug typedef --- phnt/include/ntrtl.h | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/phnt/include/ntrtl.h b/phnt/include/ntrtl.h index 74bef7a7d37e..0cfd67a428d1 100644 --- a/phnt/include/ntrtl.h +++ b/phnt/include/ntrtl.h @@ -1376,22 +1376,12 @@ VOID NTAPI RtlInitEmptyUnicodeString( _Out_ PUNICODE_STRING DestinationString, - _In_opt_ PWCHAR Buffer, - _In_opt_ USHORT MaximumLength + _In_ PWCHAR Buffer, + _In_ USHORT MaximumLength ) { - if (Buffer) - { - DestinationString->Buffer = Buffer; - DestinationString->MaximumLength = MaximumLength; - } - else - { - PTEB currentTeb = NtCurrentTeb(); - DestinationString->Buffer = currentTeb->StaticUnicodeBuffer; - DestinationString->MaximumLength = sizeof(currentTeb->StaticUnicodeBuffer); - } - + DestinationString->Buffer = Buffer; + DestinationString->MaximumLength = MaximumLength; DestinationString->Length = 0; } From 634e9a7d6d006021189a143fca24ac7a95fcecf8 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 26 Jul 2017 06:45:12 +1000 Subject: [PATCH 0282/2058] Improve PhUndecorateName, Fix multi-thread issue (PR #139) --- phlib/include/symprv.h | 30 ++++++++-------- phlib/symprv.c | 80 ++++++++++++++++++++++-------------------- 2 files changed, 56 insertions(+), 54 deletions(-) diff --git a/phlib/include/symprv.h b/phlib/include/symprv.h index 7c747fb9b913..f0a83df00d5d 100644 --- a/phlib/include/symprv.h +++ b/phlib/include/symprv.h @@ -169,7 +169,7 @@ ULONG64 __stdcall PhGetModuleBase64( _In_ HANDLE hProcess, - _In_ DWORD64 dwAddr + _In_ ULONG64 dwAddr ); PHLIBAPI @@ -177,7 +177,7 @@ PVOID __stdcall PhFunctionTableAccess64( _In_ HANDLE hProcess, - _In_ DWORD64 AddrBase + _In_ ULONG64 AddrBase ); #ifndef _DBGHELP_ @@ -189,23 +189,23 @@ typedef struct _tagADDRESS64 *LPADDRESS64; typedef BOOL (__stdcall *PREAD_PROCESS_MEMORY_ROUTINE64)( _In_ HANDLE hProcess, - _In_ DWORD64 qwBaseAddress, + _In_ ULONG64 qwBaseAddress, _Out_writes_bytes_(nSize) PVOID lpBuffer, - _In_ DWORD nSize, - _Out_ LPDWORD lpNumberOfBytesRead + _In_ ULONG nSize, + _Out_ PULONG lpNumberOfBytesRead ); typedef PVOID (__stdcall *PFUNCTION_TABLE_ACCESS_ROUTINE64)( _In_ HANDLE ahProcess, - _In_ DWORD64 AddrBase + _In_ ULONG64 AddrBase ); -typedef DWORD64 (__stdcall *PGET_MODULE_BASE_ROUTINE64)( +typedef ULONG64 (__stdcall *PGET_MODULE_BASE_ROUTINE64)( _In_ HANDLE hProcess, - _In_ DWORD64 Address + _In_ ULONG64 Address ); -typedef DWORD64 (__stdcall *PTRANSLATE_ADDRESS_ROUTINE64)( +typedef ULONG64 (__stdcall *PTRANSLATE_ADDRESS_ROUTINE64)( _In_ HANDLE hProcess, _In_ HANDLE hThread, _In_ LPADDRESS64 lpaddr @@ -300,17 +300,17 @@ PHLIBAPI PPH_STRING NTAPI PhUndecorateName( - _In_ HANDLE ProcessHandle, - _In_ PCSTR DecoratedName -); + _In_ PPH_SYMBOL_PROVIDER SymbolProvider, + _In_ PSTR DecoratedName + ); PHLIBAPI PPH_STRING NTAPI PhUndecorateNameW( - _In_ HANDLE ProcessHandle, - _In_ PWSTR DecoratedName -); + _In_ PPH_SYMBOL_PROVIDER SymbolProvider, + _In_ PWSTR DecoratedName + ); #ifdef __cplusplus } diff --git a/phlib/symprv.c b/phlib/symprv.c index 2065b1887c1a..3be8511f4924 100644 --- a/phlib/symprv.c +++ b/phlib/symprv.c @@ -1310,7 +1310,7 @@ NTSTATUS PhAccessOutOfProcessFunctionEntry( ULONG64 __stdcall PhGetModuleBase64( _In_ HANDLE hProcess, - _In_ DWORD64 dwAddr + _In_ ULONG64 dwAddr ) { ULONG64 base; @@ -1347,7 +1347,7 @@ ULONG64 __stdcall PhGetModuleBase64( PVOID __stdcall PhFunctionTableAccess64( _In_ HANDLE hProcess, - _In_ DWORD64 AddrBase + _In_ ULONG64 AddrBase ) { #ifdef _WIN64 @@ -1763,62 +1763,64 @@ NTSTATUS PhWalkThreadStack( return status; } - PPH_STRING PhUndecorateName( - _In_ HANDLE ProcessHandle, - _In_ PCSTR DecoratedName -) + _In_ PPH_SYMBOL_PROVIDER SymbolProvider, + _In_ PSTR DecoratedName + ) { - PPH_STRING UndecoratedStr = NULL; - PSTR UndecoratedName = NULL; - DWORD CandidateSize = 512; // there is no way to know the resulting length of an undecorated name - // if there is not enough place, the function does not fail. Instead it - // return a truncated name. + PPH_STRING undecoratedStr = NULL; + PSTR undecoratedName = NULL; + + PhpRegisterSymbolProvider(SymbolProvider); - if ((!SymInitialize_I) || (!UnDecorateSymbolName_I)) + if (!UnDecorateSymbolName_I) return NULL; - - - SymInitialize_I(ProcessHandle, NULL, TRUE); - - UndecoratedName = PhAllocate(CandidateSize*sizeof(CHAR)); - - DWORD Length = UnDecorateSymbolName_I(DecoratedName, UndecoratedName, CandidateSize, UNDNAME_COMPLETE); - if (Length > 0) + + // lucasg: there is no way to know the resulting length of an undecorated name + // if there is not enough place, the function does not fail. Instead it + // return a truncated name. + + undecoratedName = PhAllocate(PAGE_SIZE * sizeof(CHAR)); + + PH_LOCK_SYMBOLS(); + if (UnDecorateSymbolName_I(DecoratedName, undecoratedName, PAGE_SIZE, UNDNAME_COMPLETE) != 0) { - UndecoratedStr = PhZeroExtendToUtf16(UndecoratedName); + undecoratedStr = PhZeroExtendToUtf16(undecoratedName); } - - PhFree(UndecoratedName); - return UndecoratedStr; + PH_UNLOCK_SYMBOLS(); + + PhFree(undecoratedName); + + return undecoratedStr; } PPH_STRING PhUndecorateNameW( - _In_ HANDLE ProcessHandle, + _In_ PPH_SYMBOL_PROVIDER SymbolProvider, _In_ PWSTR DecoratedName -) + ) { + PPH_STRING undecoratedStr = NULL; + PWSTR undecoratedName = NULL; - PPH_STRING UndecoratedStr = NULL; - PWSTR UndecoratedName = NULL; - DWORD CandidateSize = 512; // there is no way to know the resulting length of an undecorated name - // if there is not enough place, the function does not fail. Instead it - // return a truncated name. + PhpRegisterSymbolProvider(SymbolProvider); - if ((!SymInitialize_I) || (!UnDecorateSymbolNameW_I)) + if (!UnDecorateSymbolNameW_I) return NULL; + // lucasg: there is no way to know the resulting length of an undecorated name + // if there is not enough place, the function does not fail. Instead it + // return a truncated name. - SymInitialize_I(ProcessHandle, NULL, TRUE); - - UndecoratedName = PhAllocate(CandidateSize *sizeof(WCHAR)); + undecoratedName = PhAllocate(PAGE_SIZE * sizeof(WCHAR)); - if (UnDecorateSymbolNameW_I(DecoratedName, UndecoratedName, CandidateSize, UNDNAME_COMPLETE)) + PH_LOCK_SYMBOLS(); + if (UnDecorateSymbolNameW_I(DecoratedName, undecoratedName, PAGE_SIZE, UNDNAME_COMPLETE) != 0) { - UndecoratedStr = PhCreateString(UndecoratedName); + undecoratedStr = PhCreateString(undecoratedName); } + PH_UNLOCK_SYMBOLS(); - PhFree(UndecoratedName); - return UndecoratedStr; + PhFree(undecoratedName); + return undecoratedStr; } \ No newline at end of file From 4c012700faa010bd7e46dad889a32a342a27adc1 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 26 Jul 2017 09:08:37 +1000 Subject: [PATCH 0283/2058] Revert "Temporarily disable KPH by default until dynamic loading support has been merged" This reverts commit 4cca64a04c3571b9a4f81ae21d4d01ebcf6faf5c. --- ProcessHacker/settings.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ProcessHacker/settings.c b/ProcessHacker/settings.c index 19c10e064859..55528bca1a76 100644 --- a/ProcessHacker/settings.c +++ b/ProcessHacker/settings.c @@ -40,7 +40,7 @@ VOID PhAddDefaultSettings( PhpAddIntegerSetting(L"ElevationLevel", L"1"); // PromptElevateAction PhpAddIntegerSetting(L"EnableCycleCpuUsage", L"1"); PhpAddIntegerSetting(L"EnableInstantTooltips", L"0"); - PhpAddIntegerSetting(L"EnableKph", L"0"); + PhpAddIntegerSetting(L"EnableKph", L"1"); PhpAddIntegerSetting(L"EnableNetworkResolve", L"1"); PhpAddIntegerSetting(L"EnablePlugins", L"1"); PhpAddIntegerSetting(L"EnableServiceNonPoll", L"1"); From a4b40e38d61e6fbdadbe7d94bcb99ff6e7f5e8ee Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 26 Jul 2017 12:33:50 +1000 Subject: [PATCH 0284/2058] Remove remaining legacy DWORD types --- ProcessHacker/actions.c | 2 +- ProcessHacker/appsup.c | 2 +- ProcessHacker/dbgcon.c | 4 +- ProcessHacker/include/notificop.h | 4 +- ProcessHacker/netprv.c | 2 +- ProcessHacker/notifico.c | 4 +- ProcessHacker/phsvc/clapi.c | 10 ++-- ProcessHacker/phsvc/svcapi.c | 10 ++-- ProcessHacker/runas.c | 14 +++--- phlib/include/apiimport.h | 2 +- phlib/include/guisup.h | 2 +- phlib/include/phbasesup.h | 2 +- phlib/include/symprvp.h | 76 +++++++++++++++---------------- phlib/include/verifyp.h | 46 +++++++++---------- 14 files changed, 90 insertions(+), 90 deletions(-) diff --git a/ProcessHacker/actions.c b/ProcessHacker/actions.c index 1f60c510791f..d039f5ed237b 100644 --- a/ProcessHacker/actions.c +++ b/ProcessHacker/actions.c @@ -48,7 +48,7 @@ #include #include -typedef DWORD (WINAPI *_SetTcpEntry)( +typedef ULONG (WINAPI *_SetTcpEntry)( _In_ PMIB_TCPROW pTcpRow ); diff --git a/ProcessHacker/appsup.c b/ProcessHacker/appsup.c index 4928ef98b55a..8517f5c049ee 100644 --- a/ProcessHacker/appsup.c +++ b/ProcessHacker/appsup.c @@ -1461,7 +1461,7 @@ BOOLEAN PhCreateProcessIgnoreIfeoDebugger( { BOOLEAN result; BOOL (NTAPI *debugSetProcessKillOnExit)(BOOL); - BOOL (NTAPI *debugActiveProcessStop)(DWORD); + BOOL (NTAPI *debugActiveProcessStop)(ULONG); BOOLEAN originalValue; STARTUPINFO startupInfo; PROCESS_INFORMATION processInfo; diff --git a/ProcessHacker/dbgcon.c b/ProcessHacker/dbgcon.c index 2107da471b6b..c441891d4979 100644 --- a/ProcessHacker/dbgcon.c +++ b/ProcessHacker/dbgcon.c @@ -45,7 +45,7 @@ typedef struct _STRING_TABLE_ENTRY } STRING_TABLE_ENTRY, *PSTRING_TABLE_ENTRY; BOOL ConsoleHandlerRoutine( - _In_ DWORD dwCtrlType + _In_ ULONG dwCtrlType ); VOID PhpPrintHashtableStatistics( @@ -122,7 +122,7 @@ VOID PhCloseDebugConsole( } static BOOL ConsoleHandlerRoutine( - _In_ DWORD dwCtrlType + _In_ ULONG dwCtrlType ) { switch (dwCtrlType) diff --git a/ProcessHacker/include/notificop.h b/ProcessHacker/include/notificop.h index 5c512ec22400..00a993da9040 100644 --- a/ProcessHacker/include/notificop.h +++ b/ProcessHacker/include/notificop.h @@ -90,7 +90,7 @@ VOID PhNfpIconClickActivateTimerProc( _In_ HWND hwnd, _In_ UINT uMsg, _In_ UINT_PTR idEvent, - _In_ DWORD dwTime + _In_ ULONG dwTime ); VOID PhNfpDisableHover( @@ -101,7 +101,7 @@ VOID PhNfpIconRestoreHoverTimerProc( _In_ HWND hwnd, _In_ UINT uMsg, _In_ UINT_PTR idEvent, - _In_ DWORD dwTime + _In_ ULONG dwTime ); #endif diff --git a/ProcessHacker/netprv.c b/ProcessHacker/netprv.c index 48f5b77c72f9..07968e356c33 100644 --- a/ProcessHacker/netprv.c +++ b/ProcessHacker/netprv.c @@ -782,7 +782,7 @@ BOOLEAN PhGetNetworkConnections( ) { PVOID table; - DWORD tableSize; + ULONG tableSize; PMIB_TCPTABLE_OWNER_MODULE tcp4Table; PMIB_UDPTABLE_OWNER_MODULE udp4Table; PMIB_TCP6TABLE_OWNER_MODULE tcp6Table; diff --git a/ProcessHacker/notifico.c b/ProcessHacker/notifico.c index 726d858b7797..15f244a30e4c 100644 --- a/ProcessHacker/notifico.c +++ b/ProcessHacker/notifico.c @@ -1313,7 +1313,7 @@ VOID PhNfpIconClickActivateTimerProc( _In_ HWND hwnd, _In_ UINT uMsg, _In_ UINT_PTR idEvent, - _In_ DWORD dwTime + _In_ ULONG dwTime ) { PhPinMiniInformation(MiniInfoActivePinType, 1, 0, @@ -1334,7 +1334,7 @@ VOID PhNfpIconRestoreHoverTimerProc( _In_ HWND hwnd, _In_ UINT uMsg, _In_ UINT_PTR idEvent, - _In_ DWORD dwTime + _In_ ULONG dwTime ) { IconDisableHover = FALSE; diff --git a/ProcessHacker/phsvc/clapi.c b/ProcessHacker/phsvc/clapi.c index 5a5cfb5b867a..8863149b2333 100644 --- a/ProcessHacker/phsvc/clapi.c +++ b/ProcessHacker/phsvc/clapi.c @@ -895,11 +895,11 @@ NTSTATUS PhSvcCallSetTcpEntry( PHSVC_API_MSG m; struct { - DWORD dwState; - DWORD dwLocalAddr; - DWORD dwLocalPort; - DWORD dwRemoteAddr; - DWORD dwRemotePort; + ULONG dwState; + ULONG dwLocalAddr; + ULONG dwLocalPort; + ULONG dwRemoteAddr; + ULONG dwRemotePort; } *tcpRow = TcpRow; if (!PhSvcClPortHandle) diff --git a/ProcessHacker/phsvc/svcapi.c b/ProcessHacker/phsvc/svcapi.c index 20fef6efb6a2..89eee95d20cb 100644 --- a/ProcessHacker/phsvc/svcapi.c +++ b/ProcessHacker/phsvc/svcapi.c @@ -1113,11 +1113,11 @@ NTSTATUS PhSvcApiSetTcpEntry( ULONG (__stdcall *localSetTcpEntry)(PVOID TcpRow); struct { - DWORD dwState; - DWORD dwLocalAddr; - DWORD dwLocalPort; - DWORD dwRemoteAddr; - DWORD dwRemotePort; + ULONG dwState; + ULONG dwLocalAddr; + ULONG dwLocalPort; + ULONG dwRemoteAddr; + ULONG dwRemotePort; } tcpRow; ULONG result; diff --git a/ProcessHacker/runas.c b/ProcessHacker/runas.c index c7131fbb28ff..e84d047429df 100644 --- a/ProcessHacker/runas.c +++ b/ProcessHacker/runas.c @@ -1015,11 +1015,11 @@ static VOID SetRunAsServiceStatus( SetServiceStatus(RunAsServiceStatusHandle, &status); } -static DWORD WINAPI RunAsServiceHandlerEx( - _In_ DWORD dwControl, - _In_ DWORD dwEventType, - _In_ LPVOID lpEventData, - _In_ LPVOID lpContext +static ULONG WINAPI RunAsServiceHandlerEx( + _In_ ULONG dwControl, + _In_ ULONG dwEventType, + _In_ PVOID lpEventData, + _In_ PVOID lpContext ) { switch (dwControl) @@ -1035,8 +1035,8 @@ static DWORD WINAPI RunAsServiceHandlerEx( } static VOID WINAPI RunAsServiceMain( - _In_ DWORD dwArgc, - _In_ LPTSTR *lpszArgv + _In_ ULONG dwArgc, + _In_ PWSTR *lpszArgv ) { PPH_STRING portName; diff --git a/phlib/include/apiimport.h b/phlib/include/apiimport.h index 80769e38bc04..973798657c33 100644 --- a/phlib/include/apiimport.h +++ b/phlib/include/apiimport.h @@ -61,7 +61,7 @@ typedef HRESULT (WINAPI *_SHOpenFolderAndSelectItems)( _In_ const struct _ITEMIDLIST __unaligned *pidlFolder, _In_ UINT cidl, _In_reads_opt_(cidl) const struct _ITEMIDLIST __unaligned **apidl, - _In_ DWORD dwFlags + _In_ ULONG dwFlags ); typedef HRESULT (WINAPI *_SHParseDisplayName)( diff --git a/phlib/include/guisup.h b/phlib/include/guisup.h index 1a5c9beabd5b..60ac7efe1267 100644 --- a/phlib/include/guisup.h +++ b/phlib/include/guisup.h @@ -52,7 +52,7 @@ typedef BOOL (WINAPI *_RunFileDlg)( typedef HRESULT (WINAPI *_SHAutoComplete)( _In_ HWND hwndEdit, - _In_ DWORD dwFlags + _In_ ULONG dwFlags ); extern _IsImmersiveProcess IsImmersiveProcess_I; diff --git a/phlib/include/phbasesup.h b/phlib/include/phbasesup.h index b2c6a1838710..cfaad93639d0 100644 --- a/phlib/include/phbasesup.h +++ b/phlib/include/phbasesup.h @@ -112,7 +112,7 @@ PhGetModuleProcAddress( _In_ PSTR ProcName ) { - HMODULE module; + PVOID module; module = PhGetDllHandle(ModuleName); diff --git a/phlib/include/symprvp.h b/phlib/include/symprvp.h index a760e142594e..9d1f309d08f6 100644 --- a/phlib/include/symprvp.h +++ b/phlib/include/symprvp.h @@ -29,15 +29,15 @@ typedef BOOL (WINAPI *_SymEnumSymbolsW)( typedef BOOL (WINAPI *_SymFromAddr)( _In_ HANDLE hProcess, - _In_ DWORD64 Address, - _Out_opt_ PDWORD64 Displacement, + _In_ ULONG64 Address, + _Out_opt_ PULONG64 Displacement, _Inout_ PSYMBOL_INFO Symbol ); typedef BOOL (WINAPI *_SymFromAddrW)( _In_ HANDLE hProcess, - _In_ DWORD64 Address, - _Out_opt_ PDWORD64 Displacement, + _In_ ULONG64 Address, + _Out_opt_ PULONG64 Displacement, _Inout_ PSYMBOL_INFOW Symbol ); @@ -55,54 +55,54 @@ typedef BOOL (WINAPI *_SymFromNameW)( typedef BOOL (WINAPI *_SymGetLineFromAddr64)( _In_ HANDLE hProcess, - _In_ DWORD64 dwAddr, - _Out_ PDWORD pdwDisplacement, + _In_ ULONG64 dwAddr, + _Out_ PULONG pdwDisplacement, _Out_ PIMAGEHLP_LINE64 Line ); typedef BOOL (WINAPI *_SymGetLineFromAddrW64)( _In_ HANDLE hProcess, - _In_ DWORD64 dwAddr, - _Out_ PDWORD pdwDisplacement, + _In_ ULONG64 dwAddr, + _Out_ PULONG pdwDisplacement, _Out_ PIMAGEHLP_LINEW64 Line ); -typedef DWORD64 (WINAPI *_SymLoadModule64)( +typedef ULONG64 (WINAPI *_SymLoadModule64)( _In_ HANDLE hProcess, _In_opt_ HANDLE hFile, _In_opt_ PCSTR ImageName, _In_opt_ PCSTR ModuleName, - _In_ DWORD64 BaseOfDll, - _In_ DWORD SizeOfDll + _In_ ULONG64 BaseOfDll, + _In_ ULONG SizeOfDll ); -typedef DWORD64 (WINAPI *_SymLoadModuleExW)( +typedef ULONG64 (WINAPI *_SymLoadModuleExW)( _In_ HANDLE hProcess, _In_ HANDLE hFile, _In_ PCWSTR ImageName, _In_ PCWSTR ModuleName, - _In_ DWORD64 BaseOfDll, - _In_ DWORD DllSize, + _In_ ULONG64 BaseOfDll, + _In_ ULONG DllSize, _In_ PMODLOAD_DATA Data, - _In_ DWORD Flags + _In_ ULONG Flags ); -typedef DWORD (WINAPI *_SymGetOptions)(); +typedef ULONG (WINAPI *_SymGetOptions)(); -typedef DWORD (WINAPI *_SymSetOptions)( - _In_ DWORD SymOptions +typedef ULONG (WINAPI *_SymSetOptions)( + _In_ ULONG SymOptions ); typedef BOOL (WINAPI *_SymGetSearchPath)( _In_ HANDLE hProcess, _Out_ PSTR SearchPath, - _In_ DWORD SearchPathLength + _In_ ULONG SearchPathLength ); typedef BOOL (WINAPI *_SymGetSearchPathW)( _In_ HANDLE hProcess, _Out_ PWSTR SearchPath, - _In_ DWORD SearchPathLength + _In_ ULONG SearchPathLength ); typedef BOOL (WINAPI *_SymSetSearchPath)( @@ -117,17 +117,17 @@ typedef BOOL (WINAPI *_SymSetSearchPathW)( typedef BOOL (WINAPI *_SymUnloadModule64)( _In_ HANDLE hProcess, - _In_ DWORD64 BaseOfDll + _In_ ULONG64 BaseOfDll ); typedef PVOID (WINAPI *_SymFunctionTableAccess64)( _In_ HANDLE hProcess, - _In_ DWORD64 AddrBase + _In_ ULONG64 AddrBase ); -typedef DWORD64 (WINAPI *_SymGetModuleBase64)( +typedef ULONG64 (WINAPI *_SymGetModuleBase64)( _In_ HANDLE hProcess, - _In_ DWORD64 dwAddr + _In_ ULONG64 dwAddr ); typedef BOOL (WINAPI *_SymRegisterCallbackW64)( @@ -137,7 +137,7 @@ typedef BOOL (WINAPI *_SymRegisterCallbackW64)( ); typedef BOOL (WINAPI *_StackWalk64)( - _In_ DWORD MachineType, + _In_ ULONG MachineType, _In_ HANDLE hProcess, _In_ HANDLE hThread, _Inout_ LPSTACKFRAME64 StackFrame, @@ -150,7 +150,7 @@ typedef BOOL (WINAPI *_StackWalk64)( typedef BOOL (WINAPI *_MiniDumpWriteDump)( _In_ HANDLE hProcess, - _In_ DWORD ProcessId, + _In_ ULONG ProcessId, _In_ HANDLE hFile, _In_ MINIDUMP_TYPE DumpType, _In_ PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, @@ -167,18 +167,18 @@ typedef BOOL (CALLBACK *_SymbolServerSetOptions)( _In_ ULONG64 data ); -typedef DWORD(WINAPI *_UnDecorateSymbolName)( - _In_ PCSTR DecoratedName, - _Out_ PSTR UnDecoratedName, - _In_ DWORD UndecoratedLength, - _In_ DWORD Flags - ); +typedef ULONG (WINAPI *_UnDecorateSymbolName)( + _In_ PCSTR DecoratedName, + _Out_ PSTR UnDecoratedName, + _In_ ULONG UndecoratedLength, + _In_ ULONG Flags + ); -typedef DWORD(WINAPI *_UnDecorateSymbolNameW)( - _In_ PCWSTR DecoratedName, - _Out_ PWSTR UnDecoratedName, - _In_ DWORD UndecoratedLength, - _In_ DWORD Flags - ); +typedef ULONG (WINAPI *_UnDecorateSymbolNameW)( + _In_ PCWSTR DecoratedName, + _Out_ PWSTR UnDecoratedName, + _In_ ULONG UndecoratedLength, + _In_ ULONG Flags + ); #endif \ No newline at end of file diff --git a/phlib/include/verifyp.h b/phlib/include/verifyp.h index 8a9dbdca2d40..cc308d6758cb 100644 --- a/phlib/include/verifyp.h +++ b/phlib/include/verifyp.h @@ -5,44 +5,44 @@ typedef struct _CATALOG_INFO { - DWORD cbStruct; + ULONG cbStruct; WCHAR wszCatalogFile[MAX_PATH]; } CATALOG_INFO, *PCATALOG_INFO; typedef struct tagCRYPTUI_VIEWSIGNERINFO_STRUCT { - DWORD dwSize; + ULONG dwSize; HWND hwndParent; - DWORD dwFlags; + ULONG dwFlags; LPCTSTR szTitle; CMSG_SIGNER_INFO *pSignerInfo; HCRYPTMSG hMsg; LPCSTR pszOID; - DWORD_PTR dwReserved; - DWORD cStores; + ULONG_PTR dwReserved; + ULONG cStores; HCERTSTORE *rghStores; - DWORD cPropSheetPages; + ULONG cPropSheetPages; LPCPROPSHEETPAGE rgPropSheetPages; } CRYPTUI_VIEWSIGNERINFO_STRUCT, *PCRYPTUI_VIEWSIGNERINFO_STRUCT; typedef BOOL (WINAPI *_CryptCATAdminCalcHashFromFileHandle)( HANDLE hFile, - DWORD *pcbHash, + ULONG *pcbHash, BYTE *pbHash, - DWORD dwFlags + ULONG dwFlags ); typedef BOOL (WINAPI *_CryptCATAdminCalcHashFromFileHandle2)( HCATADMIN hCatAdmin, HANDLE hFile, - DWORD *pcbHash, + ULONG *pcbHash, BYTE *pbHash, - DWORD dwFlags + ULONG dwFlags ); typedef BOOL (WINAPI *_CryptCATAdminAcquireContext)( HANDLE *phCatAdmin, GUID *pgSubsystem, - DWORD dwFlags + ULONG dwFlags ); typedef BOOL (WINAPI *_CryptCATAdminAcquireContext2)( @@ -50,32 +50,32 @@ typedef BOOL (WINAPI *_CryptCATAdminAcquireContext2)( const GUID *pgSubsystem, PCWSTR pwszHashAlgorithm, PCCERT_STRONG_SIGN_PARA pStrongHashPolicy, - DWORD dwFlags + ULONG dwFlags ); typedef HANDLE (WINAPI *_CryptCATAdminEnumCatalogFromHash)( HANDLE hCatAdmin, BYTE *pbHash, - DWORD cbHash, - DWORD dwFlags, + ULONG cbHash, + ULONG dwFlags, HANDLE *phPrevCatInfo ); typedef BOOL (WINAPI *_CryptCATCatalogInfoFromContext)( HANDLE hCatInfo, CATALOG_INFO *psCatInfo, - DWORD dwFlags + ULONG dwFlags ); typedef BOOL (WINAPI *_CryptCATAdminReleaseCatalogContext)( HANDLE hCatAdmin, HANDLE hCatInfo, - DWORD dwFlags + ULONG dwFlags ); typedef BOOL (WINAPI *_CryptCATAdminReleaseContext)( HANDLE hCatAdmin, - DWORD dwFlags + ULONG dwFlags ); typedef PCRYPT_PROVIDER_DATA (WINAPI *_WTHelperProvDataFromStateData)( @@ -84,9 +84,9 @@ typedef PCRYPT_PROVIDER_DATA (WINAPI *_WTHelperProvDataFromStateData)( typedef PCRYPT_PROVIDER_SGNR (WINAPI *_WTHelperGetProvSignerFromChain)( CRYPT_PROVIDER_DATA *pProvData, - DWORD idxSigner, + ULONG idxSigner, BOOL fCounterSigner, - DWORD idxCounterSigner + ULONG idxCounterSigner ); typedef LONG (WINAPI *_WinVerifyTrust)( @@ -95,12 +95,12 @@ typedef LONG (WINAPI *_WinVerifyTrust)( LPVOID pWVTData ); -typedef DWORD (WINAPI *_CertNameToStr)( - DWORD dwCertEncodingType, +typedef ULONG (WINAPI *_CertNameToStr)( + ULONG dwCertEncodingType, PCERT_NAME_BLOB pName, - DWORD dwStrType, + ULONG dwStrType, LPTSTR psz, - DWORD csz + ULONG csz ); typedef PCCERT_CONTEXT (WINAPI *_CertDuplicateCertificateContext)( From f74e0359de7615b7f039667a97615267c03dab2a Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 26 Jul 2017 13:01:20 +1000 Subject: [PATCH 0285/2058] Add missing pointer helper macros --- phlib/include/phsup.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/phlib/include/phsup.h b/phlib/include/phsup.h index 2be65f1ddb46..f669fb940271 100644 --- a/phlib/include/phsup.h +++ b/phlib/include/phsup.h @@ -16,6 +16,10 @@ #define ALIGN_UP_POINTER_BY(Pointer, Align) ((PVOID)ALIGN_UP_BY(Pointer, Align)) #define ALIGN_UP(Address, Type) ALIGN_UP_BY(Address, sizeof(Type)) #define ALIGN_UP_POINTER(Pointer, Type) ((PVOID)ALIGN_UP(Pointer, Type)) +#define ALIGN_DOWN_BY(Address, Align) ((ULONG_PTR)(Address) & ~((ULONG_PTR)(Align) - 1)) +#define ALIGN_DOWN_POINTER_BY(Pointer, Align) ((PVOID)ALIGN_DOWN_BY(Pointer, Align)) +#define ALIGN_DOWN(Address, Type) ALIGN_DOWN_BY(Address, sizeof(Type)) +#define ALIGN_DOWN_POINTER(Pointer, Type) ((PVOID)ALIGN_DOWN(Pointer, Type)) #define PAGE_SIZE 0x1000 From b6093deda4506159957c3519de49004a74f9c3fb Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 27 Jul 2017 12:25:03 +1000 Subject: [PATCH 0286/2058] Add base address column to String search window --- ProcessHacker/include/memsrch.h | 2 ++ ProcessHacker/memrslt.c | 20 +++++++++++++++++--- ProcessHacker/memsrch.c | 3 +++ 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/ProcessHacker/include/memsrch.h b/ProcessHacker/include/memsrch.h index 5804a8f1f9d9..110d3d901f54 100644 --- a/ProcessHacker/include/memsrch.h +++ b/ProcessHacker/include/memsrch.h @@ -5,6 +5,7 @@ typedef struct _PH_MEMORY_RESULT { LONG RefCount; PVOID Address; + PVOID BaseAddress; SIZE_T Length; PH_STRINGREF Display; } PH_MEMORY_RESULT, *PPH_MEMORY_RESULT; @@ -42,6 +43,7 @@ VOID PhFreeForMemorySearch( PVOID PhCreateMemoryResult( _In_ PVOID Address, + _In_ PVOID BaseAddress, _In_ SIZE_T Length ); diff --git a/ProcessHacker/memrslt.c b/ProcessHacker/memrslt.c index cb3c8b38e367..f65c39074769 100644 --- a/ProcessHacker/memrslt.c +++ b/ProcessHacker/memrslt.c @@ -299,8 +299,9 @@ INT_PTR CALLBACK PhpMemoryResultsDlgProc( PhSetListViewStyle(lvHandle, FALSE, TRUE); PhSetControlTheme(lvHandle, L"explorer"); PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 120, L"Address"); - PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 80, L"Length"); - PhAddListViewColumn(lvHandle, 2, 2, 2, LVCFMT_LEFT, 200, L"Result"); + PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 120, L"Base Address"); + PhAddListViewColumn(lvHandle, 2, 2, 2, LVCFMT_LEFT, 80, L"Length"); + PhAddListViewColumn(lvHandle, 3, 3, 3, LVCFMT_LEFT, 200, L"Result"); PhLoadListViewColumnsFromSetting(L"MemResultsListViewColumns", lvHandle); @@ -531,6 +532,19 @@ INT_PTR CALLBACK PhpMemoryResultsDlgProc( } break; case 1: + { + WCHAR baseAddressString[PH_PTR_STR_LEN_1]; + + PhPrintPointer(baseAddressString, result->BaseAddress); + wcsncpy_s( + dispInfo->item.pszText, + dispInfo->item.cchTextMax, + baseAddressString, + _TRUNCATE + ); + } + break; + case 2: { WCHAR lengthString[PH_INT32_STR_LEN_1]; @@ -543,7 +557,7 @@ INT_PTR CALLBACK PhpMemoryResultsDlgProc( ); } break; - case 2: + case 3: wcsncpy_s( dispInfo->item.pszText, dispInfo->item.cchTextMax, diff --git a/ProcessHacker/memsrch.c b/ProcessHacker/memsrch.c index fb22ff01d98a..f558f0aa4fb8 100644 --- a/ProcessHacker/memsrch.c +++ b/ProcessHacker/memsrch.c @@ -124,6 +124,7 @@ VOID PhFreeForMemorySearch( PVOID PhCreateMemoryResult( _In_ PVOID Address, + _In_ PVOID BaseAddress, _In_ SIZE_T Length ) { @@ -136,6 +137,7 @@ PVOID PhCreateMemoryResult( result->RefCount = 1; result->Address = Address; + result->BaseAddress = BaseAddress; result->Length = Length; result->Display.Length = 0; result->Display.Buffer = NULL; @@ -429,6 +431,7 @@ VOID PhSearchMemoryString( if (!(isWide && !detectUnicode) && (result = PhCreateMemoryResult( PTR_ADD_OFFSET(baseAddress, i - bias - lengthInBytes), + baseAddress, lengthInBytes ))) { From 41d92a722d8b30c6cea6f60da8d1ec79b7d68b54 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 27 Jul 2017 15:53:14 +1000 Subject: [PATCH 0287/2058] Add entrypoint column to process module tab (feature request) https://wj32.org/processhacker/forums/viewtopic.php?f=14&t=1803 --- ProcessHacker/include/modlist.h | 3 ++- ProcessHacker/include/modprv.h | 2 ++ ProcessHacker/modlist.c | 4 ++++ ProcessHacker/modprv.c | 2 ++ 4 files changed, 10 insertions(+), 1 deletion(-) diff --git a/ProcessHacker/include/modlist.h b/ProcessHacker/include/modlist.h index 099cf56fd4e3..1e9edb4150f1 100644 --- a/ProcessHacker/include/modlist.h +++ b/ProcessHacker/include/modlist.h @@ -26,8 +26,9 @@ #define PHMOTLC_LOADREASON 15 #define PHMOTLC_FILEMODIFIEDTIME 16 #define PHMOTLC_FILESIZE 17 +#define PHMOTLC_ENTRYPOINT 18 -#define PHMOTLC_MAXIMUM 18 +#define PHMOTLC_MAXIMUM 19 // begin_phapppub typedef struct _PH_MODULE_NODE diff --git a/ProcessHacker/include/modprv.h b/ProcessHacker/include/modprv.h index b08bc9c6697f..05e36ef3b664 100644 --- a/ProcessHacker/include/modprv.h +++ b/ProcessHacker/include/modprv.h @@ -8,6 +8,7 @@ extern PPH_OBJECT_TYPE PhModuleItemType; typedef struct _PH_MODULE_ITEM { PVOID BaseAddress; + PVOID EntryPoint; ULONG Size; ULONG Flags; ULONG Type; @@ -18,6 +19,7 @@ typedef struct _PH_MODULE_ITEM PH_IMAGE_VERSION_INFO VersionInfo; WCHAR BaseAddressString[PH_PTR_STR_LEN_1]; + WCHAR EntryPointAddressString[PH_PTR_STR_LEN_1]; BOOLEAN IsFirst; BOOLEAN JustProcessed; diff --git a/ProcessHacker/modlist.c b/ProcessHacker/modlist.c index af8adadb31c9..e1c0c967b387 100644 --- a/ProcessHacker/modlist.c +++ b/ProcessHacker/modlist.c @@ -114,6 +114,7 @@ VOID PhInitializeModuleList( PhAddTreeNewColumn(hwnd, PHMOTLC_LOADREASON, FALSE, L"Load reason", 80, PH_ALIGN_LEFT, -1, 0); PhAddTreeNewColumnEx(hwnd, PHMOTLC_FILEMODIFIEDTIME, FALSE, L"File modified time", 140, PH_ALIGN_LEFT, -1, 0, TRUE); PhAddTreeNewColumnEx(hwnd, PHMOTLC_FILESIZE, FALSE, L"File size", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); + PhAddTreeNewColumnEx(hwnd, PHMOTLC_ENTRYPOINT, FALSE, L"Entry point", 70, PH_ALIGN_LEFT, -1, 0, TRUE); TreeNew_SetRedraw(hwnd, TRUE); @@ -857,6 +858,9 @@ BOOLEAN NTAPI PhpModuleTreeNewCallback( getCellText->Text = node->FileSizeText->sr; } break; + case PHMOTLC_ENTRYPOINT: + PhInitializeStringRef(&getCellText->Text, moduleItem->EntryPointAddressString); + break; default: return FALSE; } diff --git a/ProcessHacker/modprv.c b/ProcessHacker/modprv.c index de4854d285c3..b3e15418a019 100644 --- a/ProcessHacker/modprv.c +++ b/ProcessHacker/modprv.c @@ -459,6 +459,8 @@ VOID PhModuleProviderUpdate( moduleItem->BaseAddress = module->BaseAddress; PhPrintPointer(moduleItem->BaseAddressString, moduleItem->BaseAddress); + moduleItem->EntryPoint = module->EntryPoint; + PhPrintPointer(moduleItem->EntryPointAddressString, moduleItem->EntryPoint); moduleItem->Size = module->Size; moduleItem->Flags = module->Flags; moduleItem->Type = module->Type; From 05f85025295eb9e9e45389f5dba36473450b1ae3 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 27 Jul 2017 18:01:19 +1000 Subject: [PATCH 0288/2058] Add type filter to the handle search window --- ProcessHacker/ProcessHacker.rc | 13 ++-- ProcessHacker/findobj.c | 130 ++++++++++++++++++++++++++------- ProcessHacker/resource.h | 5 +- 3 files changed, 112 insertions(+), 36 deletions(-) diff --git a/ProcessHacker/ProcessHacker.rc b/ProcessHacker/ProcessHacker.rc index bcbe1bc418c3..63339037d300 100644 --- a/ProcessHacker/ProcessHacker.rc +++ b/ProcessHacker/ProcessHacker.rc @@ -724,11 +724,12 @@ STYLE DS_SETFONT | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS CAPTION "Find Handles or DLLs" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN - LTEXT "Filter:",IDC_STATIC,7,9,20,8 - EDITTEXT IDC_FILTER,32,8,224,14,ES_AUTOHSCROLL - PUSHBUTTON "Find",IDOK,300,7,50,14 - CONTROL "",IDC_RESULTS,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,2,25,353,206 - CONTROL "&Regex",IDC_REGEX,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,261,9,36,10 + LTEXT "Filter:",IDC_STATIC,7,7,19,8 + EDITTEXT IDC_FILTER,29,4,134,13,ES_AUTOHSCROLL + PUSHBUTTON "Find",IDOK,301,3,50,14 + CONTROL "",IDC_RESULTS,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,2,21,353,210 + CONTROL "&Regex",IDC_REGEX,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,263,6,34,10 + COMBOBOX IDC_FILTERTYPE,165,4,93,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP END IDD_OBJTOKEN DIALOGEX 0, 0, 260, 260 @@ -1965,7 +1966,7 @@ BEGIN BEGIN LEFTMARGIN, 2 RIGHTMARGIN, 355 - TOPMARGIN, 7 + TOPMARGIN, 4 BOTTOMMARGIN, 231 END diff --git a/ProcessHacker/findobj.c b/ProcessHacker/findobj.c index 57a673c25e03..e6adb82a4673 100644 --- a/ProcessHacker/findobj.c +++ b/ProcessHacker/findobj.c @@ -3,6 +3,7 @@ * object search * * Copyright (C) 2010-2016 wj32 + * Copyright (C) 2017 dmex * * This file is part of Process Hacker. * @@ -82,6 +83,7 @@ static RECT MinimumSize; static HANDLE SearchThreadHandle = NULL; static BOOLEAN SearchStop; static PPH_STRING SearchString; +static PPH_STRING SearchTypeString; static pcre2_code *SearchRegexCompiledExpression; static pcre2_match_data *SearchRegexMatchData; static PPH_LIST SearchResults = NULL; @@ -202,6 +204,58 @@ INT NTAPI PhpObjectHandleCompareFunction( return uintptrcmp((ULONG_PTR)item1->Handle, (ULONG_PTR)item2->Handle); } +static int __cdecl PhpStringObjectTypeCompare( + _In_ const void *elem1, + _In_ const void *elem2 + ) +{ + PWSTR entry1 = *(PWSTR *)elem1; + PWSTR entry2 = *(PWSTR *)elem2; + + return PhCompareStringZ(entry2, entry1, FALSE); +} + +static VOID PhpPopulateObjectTypes( + _In_ HWND FilterTypeCombo + ) +{ + POBJECT_TYPES_INFORMATION objectTypes; + POBJECT_TYPE_INFORMATION objectType; + PPH_LIST objectTypeList; + + objectTypeList = PhCreateList(100); + + // Add a custom object type for searching all objects. + ComboBox_AddString(FilterTypeCombo, L"Everything"); + ComboBox_SetCurSel(FilterTypeCombo, 0); + + // Enumerate the available object types. + if (NT_SUCCESS(PhEnumObjectTypes(&objectTypes))) + { + objectType = PH_FIRST_OBJECT_TYPE(objectTypes); + + for (ULONG i = 0; i < objectTypes->NumberOfTypes; i++) + { + PhAddItemList(objectTypeList, PhDuplicateStringZ(objectType->TypeName.Buffer)); + objectType = PH_NEXT_OBJECT_TYPE(objectType); + } + + PhFree(objectTypes); + } + + // Sort the object types. + qsort(objectTypeList->Items, objectTypeList->Count, sizeof(PWSTR), PhpStringObjectTypeCompare); + + // HACK: Add the object types in reverse order. + for (ULONG i = objectTypeList->Count - 1; i != 0; i--) + { + ComboBox_AddString(FilterTypeCombo, objectTypeList->Items[i]); + PhFree(objectTypeList->Items[i]); + } + + PhDereferenceObject(objectTypeList); +} + static INT_PTR CALLBACK PhpFindObjectsDlgProc( _In_ HWND hwndDlg, _In_ UINT uMsg, @@ -223,15 +277,14 @@ static INT_PTR CALLBACK PhpFindObjectsDlgProc( PhCreateSearchControl(hwndDlg, GetDlgItem(hwndDlg, IDC_FILTER), NULL); + PhpPopulateObjectTypes(GetDlgItem(hwndDlg, IDC_FILTERTYPE)); + PhInitializeLayoutManager(&WindowLayoutManager, hwndDlg); - PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDC_FILTER), - NULL, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); - PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDC_REGEX), - NULL, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); - PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDOK), - NULL, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); - PhAddLayoutItem(&WindowLayoutManager, lvHandle, - NULL, PH_ANCHOR_ALL); + PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDC_FILTER), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); + PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDC_FILTERTYPE), NULL, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); + PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDC_REGEX), NULL, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); + PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDOK), NULL, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); + PhAddLayoutItem(&WindowLayoutManager, lvHandle, NULL, PH_ANCHOR_ALL); MinimumSize.left = 0; MinimumSize.top = 0; @@ -261,13 +314,6 @@ static INT_PTR CALLBACK PhpFindObjectsDlgProc( Button_SetCheck(GetDlgItem(hwndDlg, IDC_REGEX), PhGetIntegerSetting(L"FindObjRegex") ? BST_CHECKED : BST_UNCHECKED); } break; - case WM_DESTROY: - { - PhSetIntegerSetting(L"FindObjRegex", Button_GetCheck(GetDlgItem(hwndDlg, IDC_REGEX)) == BST_CHECKED); - PhSaveWindowPlacementToSetting(L"FindObjWindowPosition", L"FindObjWindowSize", hwndDlg); - PhSaveListViewColumnsToSetting(L"FindObjListViewColumns", PhFindObjectsListViewHandle); - } - break; case WM_SHOWWINDOW: { SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hwndDlg, IDC_FILTER), TRUE); @@ -276,6 +322,10 @@ static INT_PTR CALLBACK PhpFindObjectsDlgProc( break; case WM_CLOSE: { + PhSetIntegerSetting(L"FindObjRegex", Button_GetCheck(GetDlgItem(hwndDlg, IDC_REGEX)) == BST_CHECKED); + PhSaveWindowPlacementToSetting(L"FindObjWindowPosition", L"FindObjWindowSize", hwndDlg); + PhSaveListViewColumnsToSetting(L"FindObjListViewColumns", PhFindObjectsListViewHandle); + ShowWindow(hwndDlg, SW_HIDE); // IMPORTANT // Set the result to 0 so the default dialog message @@ -309,6 +359,7 @@ static INT_PTR CALLBACK PhpFindObjectsDlgProc( ULONG i; PhMoveReference(&SearchString, PhGetWindowText(GetDlgItem(hwndDlg, IDC_FILTER))); + PhMoveReference(&SearchTypeString, PhGetWindowText(GetDlgItem(hwndDlg, IDC_FILTERTYPE))); if (SearchRegexCompiledExpression) { @@ -749,6 +800,21 @@ static BOOLEAN MatchSearchString( } } +static BOOLEAN MatchTypeString( + _In_ PPH_STRINGREF Input + ) +{ + if (SearchRegexCompiledExpression && SearchRegexMatchData) + return TRUE; + else + { + if (PhEqualString2(SearchTypeString, L"Everything", FALSE)) + return TRUE; + + return PhFindStringInStringRef(Input, &SearchTypeString->sr, TRUE) != -1; + } +} + typedef struct _SEARCH_HANDLE_CONTEXT { BOOLEAN NeedToFree; @@ -775,11 +841,15 @@ static NTSTATUS NTAPI SearchHandleFunction( ))) { PPH_STRING upperBestObjectName; + PPH_STRING upperTypeName; upperBestObjectName = PhDuplicateString(bestObjectName); _wcsupr(upperBestObjectName->Buffer); - if (MatchSearchString(&upperBestObjectName->sr) || + upperTypeName = PhDuplicateString(typeName); + _wcsupr(upperTypeName->Buffer); + + if ((MatchSearchString(&upperBestObjectName->sr) && MatchTypeString(&upperTypeName->sr)) || (UseSearchPointer && context->HandleInfo->Object == (PVOID)SearchPointer)) { PPHP_OBJECT_SEARCH_RESULT searchResult; @@ -996,22 +1066,26 @@ static NTSTATUS PhpFindObjectsThreadStart( PhFree(handles); } - if (NT_SUCCESS(PhEnumProcesses(&processes))) + if (PhEqualString2(SearchTypeString, L"File", TRUE) || + PhEqualString2(SearchTypeString, L"Everything", FALSE)) { - process = PH_FIRST_PROCESS(processes); - - do + if (NT_SUCCESS(PhEnumProcesses(&processes))) { - PhEnumGenericModules( - process->UniqueProcessId, - NULL, - PH_ENUM_GENERIC_MAPPED_FILES | PH_ENUM_GENERIC_MAPPED_IMAGES, - EnumModulesCallback, - (PVOID)process->UniqueProcessId + process = PH_FIRST_PROCESS(processes); + + do + { + PhEnumGenericModules( + process->UniqueProcessId, + NULL, + PH_ENUM_GENERIC_MAPPED_FILES | PH_ENUM_GENERIC_MAPPED_IMAGES, + EnumModulesCallback, + (PVOID)process->UniqueProcessId ); - } while (process = PH_NEXT_PROCESS(process)); + } while (process = PH_NEXT_PROCESS(process)); - PhFree(processes); + PhFree(processes); + } } Exit: diff --git a/ProcessHacker/resource.h b/ProcessHacker/resource.h index ad488eaad530..6e5d76cb8a14 100644 --- a/ProcessHacker/resource.h +++ b/ProcessHacker/resource.h @@ -533,6 +533,7 @@ #define IDC_HANDLESEARCH 1385 #define IDC_SEARCH 1387 #define IDC_FILTEROPTIONS 1389 +#define IDC_FILTERTYPE 1390 #define ID_HACKER_EXIT 40001 #define ID_PROCESS_PROPERTIES 40006 #define ID_PROCESS_TERMINATE 40007 @@ -738,9 +739,9 @@ // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 231 +#define _APS_NEXT_RESOURCE_VALUE 232 #define _APS_NEXT_COMMAND_VALUE 40297 -#define _APS_NEXT_CONTROL_VALUE 1390 +#define _APS_NEXT_CONTROL_VALUE 1391 #define _APS_NEXT_SYMED_VALUE 169 #endif #endif From ae30c233b17667a51d45d03dd5856898ad6b1ac9 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 27 Jul 2017 19:58:02 +1000 Subject: [PATCH 0289/2058] Fix handle search type filter bug in previous commit --- ProcessHacker/findobj.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ProcessHacker/findobj.c b/ProcessHacker/findobj.c index e6adb82a4673..d77d68f9d58b 100644 --- a/ProcessHacker/findobj.c +++ b/ProcessHacker/findobj.c @@ -212,7 +212,7 @@ static int __cdecl PhpStringObjectTypeCompare( PWSTR entry1 = *(PWSTR *)elem1; PWSTR entry2 = *(PWSTR *)elem2; - return PhCompareStringZ(entry2, entry1, FALSE); + return PhCompareStringZ(entry1, entry2, TRUE); } static VOID PhpPopulateObjectTypes( @@ -246,8 +246,8 @@ static VOID PhpPopulateObjectTypes( // Sort the object types. qsort(objectTypeList->Items, objectTypeList->Count, sizeof(PWSTR), PhpStringObjectTypeCompare); - // HACK: Add the object types in reverse order. - for (ULONG i = objectTypeList->Count - 1; i != 0; i--) + // Add the types to the object filter combobox. + for (ULONG i = 0; i < objectTypeList->Count; i++) { ComboBox_AddString(FilterTypeCombo, objectTypeList->Items[i]); PhFree(objectTypeList->Items[i]); From 90c8745aff88c63b44a25524c50f2b1bc6ab4ff8 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 27 Jul 2017 20:25:50 +1000 Subject: [PATCH 0290/2058] Fix single instance regression --- phlib/include/phutil.h | 36 +++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/phlib/include/phutil.h b/phlib/include/phutil.h index d5dbdb468868..270041ab4c2c 100644 --- a/phlib/include/phutil.h +++ b/phlib/include/phutil.h @@ -1062,14 +1062,46 @@ PhGetNamespaceHandle( if (PhBeginInitOnce(&initOnce)) { + static SID_IDENTIFIER_AUTHORITY ntAuthority = SECURITY_NT_AUTHORITY; OBJECT_ATTRIBUTES objectAttributes; + PSECURITY_DESCRIPTOR securityDescriptor; + ULONG sdAllocationLength; + UCHAR administratorsSidBuffer[FIELD_OFFSET(SID, SubAuthority) + sizeof(ULONG) * 2]; + PSID administratorsSid; + PACL dacl; + + // Create the default namespace DACL. + + administratorsSid = (PSID)administratorsSidBuffer; + RtlInitializeSid(administratorsSid, &ntAuthority, 2); + *RtlSubAuthoritySid(administratorsSid, 0) = SECURITY_BUILTIN_DOMAIN_RID; + *RtlSubAuthoritySid(administratorsSid, 1) = DOMAIN_ALIAS_RID_ADMINS; + + sdAllocationLength = SECURITY_DESCRIPTOR_MIN_LENGTH + + (ULONG)sizeof(ACL) + + (ULONG)sizeof(ACCESS_ALLOWED_ACE) + + RtlLengthSid(&PhSeLocalSid) + + (ULONG)sizeof(ACCESS_ALLOWED_ACE) + + RtlLengthSid(administratorsSid) + + (ULONG)sizeof(ACCESS_ALLOWED_ACE) + + RtlLengthSid(&PhSeInteractiveSid); + + securityDescriptor = PhAllocate(sdAllocationLength); + dacl = (PACL)((PCHAR)securityDescriptor + SECURITY_DESCRIPTOR_MIN_LENGTH); + + RtlCreateSecurityDescriptor(securityDescriptor, SECURITY_DESCRIPTOR_REVISION); + RtlCreateAcl(dacl, sdAllocationLength - SECURITY_DESCRIPTOR_MIN_LENGTH, ACL_REVISION); + RtlAddAccessAllowedAce(dacl, ACL_REVISION, DIRECTORY_ALL_ACCESS, &PhSeLocalSid); + RtlAddAccessAllowedAce(dacl, ACL_REVISION, DIRECTORY_ALL_ACCESS, administratorsSid); + RtlAddAccessAllowedAce(dacl, ACL_REVISION, DIRECTORY_QUERY | DIRECTORY_TRAVERSE | DIRECTORY_CREATE_OBJECT, &PhSeInteractiveSid); + RtlSetDaclSecurityDescriptor(securityDescriptor, TRUE, dacl, FALSE); InitializeObjectAttributes( &objectAttributes, &namespacePathUs, OBJ_OPENIF, NULL, - NULL + securityDescriptor ); NtCreateDirectoryObject( @@ -1078,6 +1110,8 @@ PhGetNamespaceHandle( &objectAttributes ); + PhFree(securityDescriptor); + PhEndInitOnce(&initOnce); } From ee9f6680aff1343024533c804acb0fa3bf53b3b9 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 28 Jul 2017 00:38:06 +1000 Subject: [PATCH 0291/2058] peview: Fix crash (missing files from commit 634e9a7d6d006021189a143fca24ac7a95fcecf8) --- tools/peview/expprp.c | 4 ++-- tools/peview/impprp.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/peview/expprp.c b/tools/peview/expprp.c index 0688891d8c11..9e50ec4e491e 100644 --- a/tools/peview/expprp.c +++ b/tools/peview/expprp.c @@ -77,7 +77,7 @@ INT_PTR CALLBACK PvpPeExportsDlgProc( PPH_STRING forwardName = NULL; if (exportFunction.ForwardedName[0] == '?') - forwardName = PhUndecorateName(PvSymbolProvider->ProcessHandle, exportFunction.ForwardedName); + forwardName = PhUndecorateName(PvSymbolProvider, exportFunction.ForwardedName); else forwardName = PhZeroExtendToUtf16(exportFunction.ForwardedName); @@ -98,7 +98,7 @@ INT_PTR CALLBACK PvpPeExportsDlgProc( PPH_STRING exportName = NULL; if (exportEntry.Name[0] == '?') - exportName = PhUndecorateName(PvSymbolProvider->ProcessHandle, exportEntry.Name); + exportName = PhUndecorateName(PvSymbolProvider, exportEntry.Name); else exportName = PhZeroExtendToUtf16(exportEntry.Name); diff --git a/tools/peview/impprp.c b/tools/peview/impprp.c index 9a1dd38b2256..4decdd8721f6 100644 --- a/tools/peview/impprp.c +++ b/tools/peview/impprp.c @@ -63,7 +63,7 @@ VOID PvpProcessImports( PPH_STRING importName = NULL; if (importEntry.Name[0] == '?') - importName = PhUndecorateName(PvSymbolProvider->ProcessHandle, importEntry.Name); + importName = PhUndecorateName(PvSymbolProvider, importEntry.Name); else importName = PhZeroExtendToUtf16(importEntry.Name); From 421d1bc8fca9380678df2794df11ad6227a67558 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 28 Jul 2017 08:37:52 +1000 Subject: [PATCH 0292/2058] Fix handle search filter strings --- ProcessHacker/findobj.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/ProcessHacker/findobj.c b/ProcessHacker/findobj.c index d77d68f9d58b..d8247c987479 100644 --- a/ProcessHacker/findobj.c +++ b/ProcessHacker/findobj.c @@ -209,10 +209,10 @@ static int __cdecl PhpStringObjectTypeCompare( _In_ const void *elem2 ) { - PWSTR entry1 = *(PWSTR *)elem1; - PWSTR entry2 = *(PWSTR *)elem2; + PPH_STRING entry1 = *(PPH_STRING *)elem1; + PPH_STRING entry2 = *(PPH_STRING *)elem2; - return PhCompareStringZ(entry1, entry2, TRUE); + return PhCompareString(entry1, entry2, TRUE); } static VOID PhpPopulateObjectTypes( @@ -236,7 +236,7 @@ static VOID PhpPopulateObjectTypes( for (ULONG i = 0; i < objectTypes->NumberOfTypes; i++) { - PhAddItemList(objectTypeList, PhDuplicateStringZ(objectType->TypeName.Buffer)); + PhAddItemList(objectTypeList, PhCreateStringFromUnicodeString(&objectType->TypeName)); objectType = PH_NEXT_OBJECT_TYPE(objectType); } @@ -244,13 +244,13 @@ static VOID PhpPopulateObjectTypes( } // Sort the object types. - qsort(objectTypeList->Items, objectTypeList->Count, sizeof(PWSTR), PhpStringObjectTypeCompare); + qsort(objectTypeList->Items, objectTypeList->Count, sizeof(PVOID), PhpStringObjectTypeCompare); // Add the types to the object filter combobox. for (ULONG i = 0; i < objectTypeList->Count; i++) { - ComboBox_AddString(FilterTypeCombo, objectTypeList->Items[i]); - PhFree(objectTypeList->Items[i]); + ComboBox_AddString(FilterTypeCombo, PhGetString(objectTypeList->Items[i])); + PhDereferenceObject(objectTypeList->Items[i]); } PhDereferenceObject(objectTypeList); From 4ca9317f9fc5df5b7d1eac6449d45f3b28dcc2a8 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 28 Jul 2017 12:37:49 +1000 Subject: [PATCH 0293/2058] Plugins: Fix TreeNewContextMenu bug --- plugins/DotNetTools/asmpage.c | 4 ++-- plugins/ExtendedTools/disktab.c | 4 ++-- plugins/ExtraPlugins/wndtree.c | 4 ++-- plugins/NetworkTools/tracert.c | 6 +++--- plugins/NetworkTools/tracetree.c | 4 ++-- plugins/WindowExplorer/wndtree.c | 4 ++-- 6 files changed, 13 insertions(+), 13 deletions(-) diff --git a/plugins/DotNetTools/asmpage.c b/plugins/DotNetTools/asmpage.c index f21322d1026f..fe12ba0a462d 100644 --- a/plugins/DotNetTools/asmpage.c +++ b/plugins/DotNetTools/asmpage.c @@ -560,9 +560,9 @@ BOOLEAN NTAPI DotNetAsmTreeNewCallback( return TRUE; case TreeNewContextMenu: { - PPH_TREENEW_MOUSE_EVENT mouseEvent = Parameter1; + PPH_TREENEW_CONTEXT_MENU contextMenuEvent = Parameter1; - DotNetAsmShowContextMenu(context, mouseEvent->Location); + DotNetAsmShowContextMenu(context, contextMenuEvent->Location); } return TRUE; } diff --git a/plugins/ExtendedTools/disktab.c b/plugins/ExtendedTools/disktab.c index 2ab3ad8c3cd5..20e368f64c87 100644 --- a/plugins/ExtendedTools/disktab.c +++ b/plugins/ExtendedTools/disktab.c @@ -669,9 +669,9 @@ BOOLEAN NTAPI EtpDiskTreeNewCallback( return TRUE; case TreeNewContextMenu: { - PPH_TREENEW_MOUSE_EVENT mouseEvent = Parameter1; + PPH_TREENEW_CONTEXT_MENU contextMenuEvent = Parameter1; - EtShowDiskContextMenu(mouseEvent->Location); + EtShowDiskContextMenu(contextMenuEvent->Location); } return TRUE; case TreeNewDestroying: diff --git a/plugins/ExtraPlugins/wndtree.c b/plugins/ExtraPlugins/wndtree.c index 0bdeced96e21..ce624e5b847f 100644 --- a/plugins/ExtraPlugins/wndtree.c +++ b/plugins/ExtraPlugins/wndtree.c @@ -273,9 +273,9 @@ BOOLEAN NTAPI PluginsTreeNewCallback( return TRUE; case TreeNewContextMenu: { - PPH_TREENEW_MOUSE_EVENT mouseEvent = (PPH_TREENEW_MOUSE_EVENT)Parameter1; + PPH_TREENEW_CONTEXT_MENU contextMenuEvent = Parameter1; - SendMessage(context->ParentWindowHandle, WM_COMMAND, ID_WCTSHOWCONTEXTMENU, MAKELONG(mouseEvent->Location.x, mouseEvent->Location.y)); + SendMessage(context->ParentWindowHandle, WM_COMMAND, ID_WCTSHOWCONTEXTMENU, MAKELONG(contextMenuEvent->Location.x, contextMenuEvent->Location.y)); } return TRUE; case TreeNewHeaderRightClick: diff --git a/plugins/NetworkTools/tracert.c b/plugins/NetworkTools/tracert.c index 9e4bb57c0279..f5b2c5376733 100644 --- a/plugins/NetworkTools/tracert.c +++ b/plugins/NetworkTools/tracert.c @@ -614,7 +614,7 @@ INT_PTR CALLBACK TracertDlgProc( PPH_EMENU menu; PTRACERT_ROOT_NODE selectedNode; PPH_EMENU_ITEM selectedItem; - PPH_TREENEW_MOUSE_EVENT mouseEvent = (PPH_TREENEW_MOUSE_EVENT)lParam; + PPH_TREENEW_CONTEXT_MENU contextMenuEvent = (PPH_TREENEW_CONTEXT_MENU)lParam; if (selectedNode = GetSelectedTracertNode(context)) { @@ -628,8 +628,8 @@ INT_PTR CALLBACK TracertDlgProc( hwndDlg, PH_EMENU_SHOW_LEFTRIGHT, PH_ALIGN_LEFT | PH_ALIGN_TOP, - mouseEvent->Location.x, - mouseEvent->Location.y + contextMenuEvent->Location.x, + contextMenuEvent->Location.y ); if (selectedItem && selectedItem->Id != -1) diff --git a/plugins/NetworkTools/tracetree.c b/plugins/NetworkTools/tracetree.c index 5b1a945edcc8..fb4d6f55a818 100644 --- a/plugins/NetworkTools/tracetree.c +++ b/plugins/NetworkTools/tracetree.c @@ -352,13 +352,13 @@ BOOLEAN NTAPI TracertTreeNewCallback( return TRUE; case TreeNewContextMenu: { - PPH_TREENEW_MOUSE_EVENT mouseEvent = Parameter1; + PPH_TREENEW_CONTEXT_MENU contextMenuEvent = Parameter1; SendMessage( context->WindowHandle, WM_COMMAND, TRACERT_SHOWCONTEXTMENU, - (LPARAM)mouseEvent + (LPARAM)contextMenuEvent ); } return TRUE; diff --git a/plugins/WindowExplorer/wndtree.c b/plugins/WindowExplorer/wndtree.c index a18b545b90e5..c1d9d02476da 100644 --- a/plugins/WindowExplorer/wndtree.c +++ b/plugins/WindowExplorer/wndtree.c @@ -479,9 +479,9 @@ BOOLEAN NTAPI WepWindowTreeNewCallback( return TRUE; case TreeNewContextMenu: { - PPH_TREENEW_MOUSE_EVENT mouseEvent = Parameter1; + PPH_TREENEW_CONTEXT_MENU contextMenuEvent = Parameter1; - SendMessage(context->ParentWindowHandle, WM_COMMAND, ID_SHOWCONTEXTMENU, MAKELONG(mouseEvent->Location.x, mouseEvent->Location.y)); + SendMessage(context->ParentWindowHandle, WM_COMMAND, ID_SHOWCONTEXTMENU, MAKELONG(contextMenuEvent->Location.x, contextMenuEvent->Location.y)); } return TRUE; } From 0c3cd4514cda30bb3a055814755ad9630fab59a4 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 28 Jul 2017 12:40:52 +1000 Subject: [PATCH 0294/2058] Fix treeview clipboard issue caused by PhResolveDevicePrefix and extra-null terminated strings --- phlib/native.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/phlib/native.c b/phlib/native.c index 0a6acd15f6b1..7be1079480cb 100644 --- a/phlib/native.c +++ b/phlib/native.c @@ -5028,6 +5028,8 @@ PPH_STRING PhResolveDevicePrefix( PhReleaseQueuedLockShared(&PhDeviceMupPrefixesLock); } + PhTrimToNullTerminatorString(newName); + return newName; } From a11b40ec3eeb621082f2af42cd9423f94bb630fb Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 28 Jul 2017 12:52:42 +1000 Subject: [PATCH 0295/2058] Export the PhInsertCopyCellEMenuItem and PhHandleCopyCellEMenuItem functions --- ProcessHacker/include/appsup.h | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/ProcessHacker/include/appsup.h b/ProcessHacker/include/appsup.h index 1843bae473ad..16d1762462da 100644 --- a/ProcessHacker/include/appsup.h +++ b/ProcessHacker/include/appsup.h @@ -393,7 +393,6 @@ NTAPI PhApplyTreeNewFilters( _In_ PPH_TN_FILTER_SUPPORT Support ); -// end_phapppub typedef struct _PH_COPY_CELL_CONTEXT { @@ -402,16 +401,23 @@ typedef struct _PH_COPY_CELL_CONTEXT PPH_STRING MenuItemText; } PH_COPY_CELL_CONTEXT, *PPH_COPY_CELL_CONTEXT; -BOOLEAN PhInsertCopyCellEMenuItem( +PHAPPAPI +BOOLEAN +NTAPI +PhInsertCopyCellEMenuItem( _In_ struct _PH_EMENU_ITEM *Menu, _In_ ULONG InsertAfterId, _In_ HWND TreeNewHandle, _In_ PPH_TREENEW_COLUMN Column ); -BOOLEAN PhHandleCopyCellEMenuItem( +PHAPPAPI +BOOLEAN +NTAPI +PhHandleCopyCellEMenuItem( _In_ struct _PH_EMENU_ITEM *SelectedItem ); +// end_phapppub BOOLEAN PhShellOpenKey2( _In_ HWND hWnd, From a27cfbab9f6f88c6f9256115518e1110cfc27129 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 28 Jul 2017 13:17:08 +1000 Subject: [PATCH 0296/2058] Fix crash from commit 0c3cd4514cda30bb3a055814755ad9630fab59a4 --- phlib/native.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/phlib/native.c b/phlib/native.c index 7be1079480cb..2817a8e7fb01 100644 --- a/phlib/native.c +++ b/phlib/native.c @@ -5028,7 +5028,8 @@ PPH_STRING PhResolveDevicePrefix( PhReleaseQueuedLockShared(&PhDeviceMupPrefixesLock); } - PhTrimToNullTerminatorString(newName); + if (newName) + PhTrimToNullTerminatorString(newName); return newName; } From a96187247225b391babab78ea2c2278760e39513 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 28 Jul 2017 14:56:32 +1000 Subject: [PATCH 0297/2058] Fix modules tab not showing signatures for mapped images when they're actually signed (reported by Zorkov Igor) https://wj32.org/processhacker/forums/viewtopic.php?t=2428 --- ProcessHacker/modprv.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/ProcessHacker/modprv.c b/ProcessHacker/modprv.c index b3e15418a019..9f5f1f623ba9 100644 --- a/ProcessHacker/modprv.c +++ b/ProcessHacker/modprv.c @@ -535,8 +535,6 @@ VOID PhModuleProviderUpdate( moduleItem->FileEndOfFile.QuadPart = -1; } - if (moduleItem->Type == PH_MODULE_TYPE_MODULE || moduleItem->Type == PH_MODULE_TYPE_KERNEL_MODULE || - moduleItem->Type == PH_MODULE_TYPE_WOW64_MODULE || moduleItem->Type == PH_MODULE_TYPE_MAPPED_IMAGE) { // See if the file has already been verified; if not, queue for verification. From b5d3ac21ec6d64ccf6b4809b33c9a59788e869d4 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 28 Jul 2017 15:20:22 +1000 Subject: [PATCH 0298/2058] Plugins: Add missing copy menus to the Disk, .NET, Tracert and Windows tabs, Fix remaining contextmenu issues --- plugins/DotNetTools/asmpage.c | 42 +++++++++++++++++----------- plugins/ExtendedTools/disktab.c | 17 +++++++---- plugins/ExtendedTools/disktabp.h | 3 +- plugins/ExtraPlugins/dialog.c | 8 ++---- plugins/ExtraPlugins/wndtree.c | 2 +- plugins/NetworkTools/nettools.h | 1 + plugins/NetworkTools/tracert.c | 21 +++++++++++++- plugins/WindowExplorer/wnddlg.c | 48 +++++++++++++++++++++++++------- plugins/WindowExplorer/wndtree.c | 2 +- 9 files changed, 103 insertions(+), 41 deletions(-) diff --git a/plugins/DotNetTools/asmpage.c b/plugins/DotNetTools/asmpage.c index fe12ba0a462d..df80c57ed190 100644 --- a/plugins/DotNetTools/asmpage.c +++ b/plugins/DotNetTools/asmpage.c @@ -393,7 +393,7 @@ PDNA_NODE DotNetAsmGetSelectedEntry( VOID DotNetAsmShowContextMenu( _In_ PASMPAGE_CONTEXT Context, - _In_ POINT Location + _In_ PPH_TREENEW_CONTEXT_MENU ContextMenuEvent ) { PDNA_NODE node; @@ -405,6 +405,7 @@ VOID DotNetAsmShowContextMenu( menu = PhCreateEMenu(); PhLoadResourceEMenuItem(menu, PluginInstance->DllBase, MAKEINTRESOURCE(IDR_ASSEMBLY_MENU), 0); + PhInsertCopyCellEMenuItem(menu, ID_CLR_COPY, Context->TnHandle, ContextMenuEvent->Column); if (PhIsNullOrEmptyString(node->PathText) || !RtlDoesFileExists_U(node->PathText->Buffer)) { @@ -416,31 +417,38 @@ VOID DotNetAsmShowContextMenu( Context->WindowHandle, PH_EMENU_SHOW_LEFTRIGHT, PH_ALIGN_LEFT | PH_ALIGN_TOP, - Location.x, - Location.y + ContextMenuEvent->Location.x, + ContextMenuEvent->Location.y ); if (selectedItem && selectedItem->Id != -1) { - switch (selectedItem->Id) + BOOLEAN handled = FALSE; + + handled = PhHandleCopyCellEMenuItem(selectedItem); + + if (!handled) { - case ID_CLR_OPENFILELOCATION: + switch (selectedItem->Id) { - if (!PhIsNullOrEmptyString(node->PathText) && RtlDoesFileExists_U(node->PathText->Buffer)) + case ID_CLR_OPENFILELOCATION: { - PhShellExploreFile(Context->WindowHandle, node->PathText->Buffer); + if (!PhIsNullOrEmptyString(node->PathText) && RtlDoesFileExists_U(node->PathText->Buffer)) + { + PhShellExploreFile(Context->WindowHandle, node->PathText->Buffer); + } } - } - break; - case ID_CLR_COPY: - { - PPH_STRING text; + break; + case ID_CLR_COPY: + { + PPH_STRING text; - text = PhGetTreeNewText(Context->TnHandle, 0); - PhSetClipboardString(Context->TnHandle, &text->sr); - PhDereferenceObject(text); + text = PhGetTreeNewText(Context->TnHandle, 0); + PhSetClipboardString(Context->TnHandle, &text->sr); + PhDereferenceObject(text); + } + break; } - break; } } @@ -562,7 +570,7 @@ BOOLEAN NTAPI DotNetAsmTreeNewCallback( { PPH_TREENEW_CONTEXT_MENU contextMenuEvent = Parameter1; - DotNetAsmShowContextMenu(context, contextMenuEvent->Location); + DotNetAsmShowContextMenu(context, contextMenuEvent); } return TRUE; } diff --git a/plugins/ExtendedTools/disktab.c b/plugins/ExtendedTools/disktab.c index 20e368f64c87..f669e3cc93ae 100644 --- a/plugins/ExtendedTools/disktab.c +++ b/plugins/ExtendedTools/disktab.c @@ -671,7 +671,7 @@ BOOLEAN NTAPI EtpDiskTreeNewCallback( { PPH_TREENEW_CONTEXT_MENU contextMenuEvent = Parameter1; - EtShowDiskContextMenu(contextMenuEvent->Location); + EtShowDiskContextMenu(hwnd, contextMenuEvent); } return TRUE; case TreeNewDestroying: @@ -916,7 +916,8 @@ VOID EtpInitializeDiskMenu( } VOID EtShowDiskContextMenu( - _In_ POINT Location + _In_ HWND TreeWindowHandle, + _In_ PPH_TREENEW_CONTEXT_MENU ContextMenuEvent ) { PET_DISK_ITEM *diskItems; @@ -931,6 +932,7 @@ VOID EtShowDiskContextMenu( menu = PhCreateEMenu(); PhLoadResourceEMenuItem(menu, PluginInstance->DllBase, MAKEINTRESOURCE(IDR_DISK), 0); + PhInsertCopyCellEMenuItem(menu, ID_DISK_COPY, TreeWindowHandle, ContextMenuEvent->Column); PhSetFlagsEMenuItem(menu, ID_DISK_OPENFILELOCATION, PH_EMENU_DEFAULT, PH_EMENU_DEFAULT); EtpInitializeDiskMenu(menu, diskItems, numberOfDiskItems); @@ -940,13 +942,18 @@ VOID EtShowDiskContextMenu( PhMainWndHandle, PH_EMENU_SHOW_LEFTRIGHT, PH_ALIGN_LEFT | PH_ALIGN_TOP, - Location.x, - Location.y + ContextMenuEvent->Location.x, + ContextMenuEvent->Location.y ); if (item) { - EtHandleDiskCommand(item->Id); + BOOLEAN handled = FALSE; + + handled = PhHandleCopyCellEMenuItem(item); + + if (!handled) + EtHandleDiskCommand(item->Id); } PhDestroyEMenu(menu); diff --git a/plugins/ExtendedTools/disktabp.h b/plugins/ExtendedTools/disktabp.h index 794572c90e7c..0a90f64716ef 100644 --- a/plugins/ExtendedTools/disktabp.h +++ b/plugins/ExtendedTools/disktabp.h @@ -107,7 +107,8 @@ VOID EtpInitializeDiskMenu( ); VOID EtShowDiskContextMenu( - _In_ POINT Location + _In_ HWND TreeWindowHandle, + _In_ PPH_TREENEW_CONTEXT_MENU ContextMenuEvent ); VOID NTAPI EtpDiskItemAddedHandler( diff --git a/plugins/ExtraPlugins/dialog.c b/plugins/ExtraPlugins/dialog.c index 829a96ed8c49..50ca89609f1e 100644 --- a/plugins/ExtraPlugins/dialog.c +++ b/plugins/ExtraPlugins/dialog.c @@ -371,12 +371,10 @@ INT_PTR CALLBACK CloudPluginsDlgProc( break; case ID_WCTSHOWCONTEXTMENU: { - POINT cursorPos; PPH_EMENU menu; PPH_EMENU_ITEM selectedItem; PPLUGIN_NODE selectedNode; - - GetCursorPos(&cursorPos); + PPH_TREENEW_CONTEXT_MENU contextMenuEvent = (PPH_TREENEW_CONTEXT_MENU)lParam; if (!(selectedNode = WeGetSelectedWindowNode(context))) break; @@ -448,8 +446,8 @@ INT_PTR CALLBACK CloudPluginsDlgProc( hwndDlg, PH_EMENU_SHOW_LEFTRIGHT, PH_ALIGN_LEFT | PH_ALIGN_TOP, - cursorPos.x, - cursorPos.y + contextMenuEvent->Location.x, + contextMenuEvent->Location.y ); if (selectedItem && selectedItem->Id != -1) diff --git a/plugins/ExtraPlugins/wndtree.c b/plugins/ExtraPlugins/wndtree.c index ce624e5b847f..5c9858fd1b49 100644 --- a/plugins/ExtraPlugins/wndtree.c +++ b/plugins/ExtraPlugins/wndtree.c @@ -275,7 +275,7 @@ BOOLEAN NTAPI PluginsTreeNewCallback( { PPH_TREENEW_CONTEXT_MENU contextMenuEvent = Parameter1; - SendMessage(context->ParentWindowHandle, WM_COMMAND, ID_WCTSHOWCONTEXTMENU, MAKELONG(contextMenuEvent->Location.x, contextMenuEvent->Location.y)); + SendMessage(context->ParentWindowHandle, WM_COMMAND, ID_WCTSHOWCONTEXTMENU, (LPARAM)contextMenuEvent); } return TRUE; case TreeNewHeaderRightClick: diff --git a/plugins/NetworkTools/nettools.h b/plugins/NetworkTools/nettools.h index d2ae5088edf9..106eb2849428 100644 --- a/plugins/NetworkTools/nettools.h +++ b/plugins/NetworkTools/nettools.h @@ -95,6 +95,7 @@ typedef enum _PH_NETWORK_ACTION MAINMENU_ACTION_TRACERT, MAINMENU_ACTION_WHOIS, MAINMENU_ACTION_GEOIP_UPDATE, + MENU_ACTION_COPY, } PH_NETWORK_ACTION; #define NTM_RECEIVEDTRACE (WM_APP + NETWORK_ACTION_TRACEROUTE) diff --git a/plugins/NetworkTools/tracert.c b/plugins/NetworkTools/tracert.c index f5b2c5376733..62f39daef461 100644 --- a/plugins/NetworkTools/tracert.c +++ b/plugins/NetworkTools/tracert.c @@ -518,6 +518,15 @@ VOID ShowMenu( } } break; + case MENU_ACTION_COPY: + { + PPH_STRING text; + + text = PhGetTreeNewText(Context->TreeNewHandle, 0); + PhSetClipboardString(Context->TreeNewHandle, &text->sr); + PhDereferenceObject(text); + } + break; } } @@ -622,6 +631,9 @@ INT_PTR CALLBACK TracertDlgProc( PhInsertEMenuItem(menu, PhCreateEMenuItem(0, MAINMENU_ACTION_PING, L"Ping", NULL, NULL), -1); PhInsertEMenuItem(menu, PhCreateEMenuItem(0, NETWORK_ACTION_TRACEROUTE, L"Traceroute", NULL, NULL), -1); PhInsertEMenuItem(menu, PhCreateEMenuItem(0, NETWORK_ACTION_WHOIS, L"Whois", NULL, NULL), -1); + PhInsertEMenuItem(menu, PhCreateEMenuItem(PH_EMENU_SEPARATOR, 0, NULL, NULL, NULL), -1); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, MENU_ACTION_COPY, L"Copy", NULL, NULL), -1); + PhInsertCopyCellEMenuItem(menu, MENU_ACTION_COPY, context->TreeNewHandle, contextMenuEvent->Column); selectedItem = PhShowEMenu( menu, @@ -634,7 +646,14 @@ INT_PTR CALLBACK TracertDlgProc( if (selectedItem && selectedItem->Id != -1) { - ShowMenu(context, selectedItem->Id); + BOOLEAN handled = FALSE; + + handled = PhHandleCopyCellEMenuItem(selectedItem); + + if (!handled) + { + ShowMenu(context, selectedItem->Id); + } } PhDestroyEMenu(menu); diff --git a/plugins/WindowExplorer/wnddlg.c b/plugins/WindowExplorer/wnddlg.c index ab97179b6f24..9aa47dd23c1f 100644 --- a/plugins/WindowExplorer/wnddlg.c +++ b/plugins/WindowExplorer/wnddlg.c @@ -432,13 +432,11 @@ INT_PTR CALLBACK WepWindowsDlgProc( break; case ID_SHOWCONTEXTMENU: { - POINT point; + PPH_TREENEW_CONTEXT_MENU contextMenuEvent = (PPH_TREENEW_CONTEXT_MENU)lParam; PWE_WINDOW_NODE *windows; ULONG numberOfWindows; PPH_EMENU menu; - - point.x = (SHORT)LOWORD(lParam); - point.y = (SHORT)HIWORD(lParam); + PPH_EMENU_ITEM selectedItem; WeGetSelectedWindowNodes( &context->TreeContext, @@ -450,6 +448,7 @@ INT_PTR CALLBACK WepWindowsDlgProc( { menu = PhCreateEMenu(); PhLoadResourceEMenuItem(menu, PluginInstance->DllBase, MAKEINTRESOURCE(IDR_WINDOW), 0); + PhInsertCopyCellEMenuItem(menu, ID_WINDOW_COPY, context->TreeNewHandle, contextMenuEvent->Column); PhSetFlagsEMenuItem(menu, ID_WINDOW_PROPERTIES, PH_EMENU_DEFAULT, PH_EMENU_DEFAULT); if (numberOfWindows == 1) @@ -529,7 +528,22 @@ INT_PTR CALLBACK WepWindowsDlgProc( PhSetFlagsEMenuItem(menu, ID_WINDOW_COPY, PH_EMENU_DISABLED, 0); } - PhShowEMenu(menu, hwndDlg, PH_EMENU_SHOW_SEND_COMMAND | PH_EMENU_SHOW_LEFTRIGHT, PH_ALIGN_LEFT | PH_ALIGN_TOP, point.x, point.y); + selectedItem = PhShowEMenu( + menu, + hwndDlg, + PH_EMENU_SHOW_SEND_COMMAND | PH_EMENU_SHOW_LEFTRIGHT, + PH_ALIGN_LEFT | PH_ALIGN_TOP, + contextMenuEvent->Location.x, + contextMenuEvent->Location.y + ); + + if (selectedItem && selectedItem->Id != -1) + { + BOOLEAN handled = FALSE; + + handled = PhHandleCopyCellEMenuItem(selectedItem); + } + PhDestroyEMenu(menu); } } @@ -854,13 +868,11 @@ INT_PTR CALLBACK WepWindowsPageProc( break; case ID_SHOWCONTEXTMENU: { - POINT point; + PPH_TREENEW_CONTEXT_MENU contextMenuEvent = (PPH_TREENEW_CONTEXT_MENU)lParam; PWE_WINDOW_NODE *windows; ULONG numberOfWindows; PPH_EMENU menu; - - point.x = (SHORT)LOWORD(lParam); - point.y = (SHORT)HIWORD(lParam); + PPH_EMENU selectedItem; WeGetSelectedWindowNodes( &context->TreeContext, @@ -872,6 +884,7 @@ INT_PTR CALLBACK WepWindowsPageProc( { menu = PhCreateEMenu(); PhLoadResourceEMenuItem(menu, PluginInstance->DllBase, MAKEINTRESOURCE(IDR_WINDOW), 0); + PhInsertCopyCellEMenuItem(menu, ID_WINDOW_COPY, context->TreeNewHandle, contextMenuEvent->Column); PhSetFlagsEMenuItem(menu, ID_WINDOW_PROPERTIES, PH_EMENU_DEFAULT, PH_EMENU_DEFAULT); if (numberOfWindows == 1) @@ -951,7 +964,22 @@ INT_PTR CALLBACK WepWindowsPageProc( PhSetFlagsEMenuItem(menu, ID_WINDOW_COPY, PH_EMENU_DISABLED, 0); } - PhShowEMenu(menu, hwndDlg, PH_EMENU_SHOW_SEND_COMMAND | PH_EMENU_SHOW_LEFTRIGHT, PH_ALIGN_LEFT | PH_ALIGN_TOP, point.x, point.y); + selectedItem = PhShowEMenu( + menu, + hwndDlg, + PH_EMENU_SHOW_SEND_COMMAND | PH_EMENU_SHOW_LEFTRIGHT, + PH_ALIGN_LEFT | PH_ALIGN_TOP, + contextMenuEvent->Location.x, + contextMenuEvent->Location.y + ); + + if (selectedItem && selectedItem->Id != -1) + { + BOOLEAN handled = FALSE; + + handled = PhHandleCopyCellEMenuItem(selectedItem); + } + PhDestroyEMenu(menu); } } diff --git a/plugins/WindowExplorer/wndtree.c b/plugins/WindowExplorer/wndtree.c index c1d9d02476da..8b7c3e56bd09 100644 --- a/plugins/WindowExplorer/wndtree.c +++ b/plugins/WindowExplorer/wndtree.c @@ -481,7 +481,7 @@ BOOLEAN NTAPI WepWindowTreeNewCallback( { PPH_TREENEW_CONTEXT_MENU contextMenuEvent = Parameter1; - SendMessage(context->ParentWindowHandle, WM_COMMAND, ID_SHOWCONTEXTMENU, MAKELONG(contextMenuEvent->Location.x, contextMenuEvent->Location.y)); + SendMessage(context->ParentWindowHandle, WM_COMMAND, ID_SHOWCONTEXTMENU, (LPARAM)contextMenuEvent); } return TRUE; } From e3a3f037d49e1ff63ee295d1ee8dfb4d5811ff6e Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 28 Jul 2017 15:21:05 +1000 Subject: [PATCH 0299/2058] Improve KPH error checking --- phlib/kph.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/phlib/kph.c b/phlib/kph.c index 0acd7d0baa27..85e996a0c533 100644 --- a/phlib/kph.c +++ b/phlib/kph.c @@ -25,8 +25,8 @@ #include HANDLE PhKphHandle = NULL; -BOOLEAN PhKphVerified; -KPH_KEY PhKphL1Key; +BOOLEAN PhKphVerified = FALSE; +KPH_KEY PhKphL1Key = 0; NTSTATUS KphConnect( _In_opt_ PWSTR DeviceName @@ -196,13 +196,19 @@ NTSTATUS KphConnect2Ex( if (StartService(serviceHandle, 0, NULL)) started = TRUE; + else + status = PhGetLastWin32ErrorAsNtStatus(); + } + else + { + status = PhGetLastWin32ErrorAsNtStatus(); } CloseServiceHandle(scmHandle); } } - if (started) + if (NT_SUCCESS(status) && started) { // Try to open the device again. status = KphConnect(fullDeviceName); From a2a36215170b59911d9429b9160de60089443939 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 28 Jul 2017 16:15:25 +1000 Subject: [PATCH 0300/2058] Fix previous commit --- phlib/kph.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phlib/kph.c b/phlib/kph.c index 85e996a0c533..e27f622ca57b 100644 --- a/phlib/kph.c +++ b/phlib/kph.c @@ -208,7 +208,7 @@ NTSTATUS KphConnect2Ex( } } - if (NT_SUCCESS(status) && started) + if (started) { // Try to open the device again. status = KphConnect(fullDeviceName); From 2182ff8b6bdfedc15be409d0d62bdb45d95ecd6c Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 28 Jul 2017 19:35:37 +1000 Subject: [PATCH 0301/2058] Update readme.md --- README.md | 63 ++++++++++++++++++++++++++++++++++++++++++++---------- README.txt | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 113 insertions(+), 11 deletions(-) create mode 100644 README.txt diff --git a/README.md b/README.md index 38037e452c14..051fbf9c326c 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,58 @@ -Process Hacker is a powerful free and open source process viewer. +##Process Hacker -## Getting started +A free, powerful, multi-purpose tool that helps you monitor system resources, debug software and detect malware. -Simply run ProcessHacker.exe to start Process Hacker. There are two -versions, 32-bit (x86) and 64-bit (x64). If you are not sure which -version to use, open Control Panel > System and check the "System -type". You cannot run the 32-bit version of Process Hacker on a -64-bit system and expect it to work correctly, unlike other programs. +[![Build status](https://ci.appveyor.com/api/projects/status/5einmgmy3mnsfjdn?svg=true)](https://ci.appveyor.com/project/pbatard/rufus) +[![Licence](https://img.shields.io/badge/license-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0.en.html) + +![Logo](https://raw.githubusercontent.com/processhacker2/processhacker/master/ProcessHacker/resources/ProcessHacker.png) + +* [Official Website](http://processhacker.sourceforge.net/) +* [FAQ](http://processhacker.sourceforge.net/faq.php) ## System requirements Windows 7 or higher, 32-bit or 64-bit. +## Features + + +* A detailed overview of system activity with highlighting. +* Graphs and statistics allow you quickly to track down resource hogs and runaway processes. +* Can't edit or delete a file? Discover which processes are using that file. +* See what programs have active network connections, and close them if necessary. +* Get real-time information on disk access. +* View detailed stack traces with kernel-mode, WOW64 and .NET support. +* Go beyond services.msc: create, edit and control services. +* Small, portable and no installation required. +* 100% [Free Software](http://www.gnu.org/philosophy/free-sw.en.html) ([GPL v3](http://www.gnu.org/licenses/gpl-3.0.en.html)) + + +## Building the project + + +Requires Visual Studio (2017 or later). + +Execute `build_release.cmd` located in the `build` directory to compile the project or load the `ProcessHacker.sln` and `Plugins.sln` solutions if you prefer building the project using Visual Studio. + +You can download the free [Visual Studio Community Edition](https://www.visualstudio.com/vs/community/) +to build, run or develop Process Hacker. + +## Additional information + + +You cannot run the 32-bit version of Process Hacker on a +64-bit system and expect it to work correctly, unlike other programs. + + + +## Enhancements/Bugs + + +Please use the [GitHub issue tracker](https://github.com/processhacker2/processhacker/issues) +for reporting problems or suggesting new features. + + ## Settings If you are running Process Hacker from a USB drive, you may want to @@ -32,8 +73,7 @@ Plugins can be configured from Hacker > Plugins. If you experience any crashes involving plugins, make sure they are up to date. -The ExtendedTools plugin is only available for Windows Vista and -above. Disk and Network information provided by this plugin is +Disk and Network information provided by the ExtendedTools plugin is only available when running Process Hacker with administrative rights. @@ -49,8 +89,8 @@ assist with certain functionality. This includes: * Setting handle attributes Note that by default, KProcessHacker only allows connections from -processes with SeDebugPrivilege. To allow Process Hacker to show details -for all processes when it is not running as administrator: +processes with administrative privileges (SeDebugPrivilege). To allow Process Hacker +to show details for all processes when it is not running as administrator: 1. In Registry Editor, navigate to: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\KProcessHacker3 @@ -59,3 +99,4 @@ for all processes when it is not running as administrator: not using an official build, you may need to set it to 0 instead. 4. Restart the KProcessHacker3 service (sc stop KProcessHacker3, sc start KProcessHacker3). + \ No newline at end of file diff --git a/README.txt b/README.txt new file mode 100644 index 000000000000..dc20782948e6 --- /dev/null +++ b/README.txt @@ -0,0 +1,61 @@ +Process Hacker is a powerful free and open source process viewer. + +## Getting started + +Simply run ProcessHacker.exe to start Process Hacker. There are two +versions, 32-bit (x86) and 64-bit (x64). If you are not sure which +version to use, open Control Panel > System and check the "System +type". You cannot run the 32-bit version of Process Hacker on a +64-bit system and expect it to work correctly, unlike other programs. + +## System requirements + +Windows 7 or higher, 32-bit or 64-bit. + +## Settings + +If you are running Process Hacker from a USB drive, you may want to +save Process Hacker's settings there as well. To do this, create a +blank file named "ProcessHacker.exe.settings.xml" in the same +directory as ProcessHacker.exe. You can do this using Windows Explorer: + +1. Make sure "Hide extensions for known file types" is unticked in + Tools > Folder options > View. +2. Right-click in the folder and choose New > Text Document. +3. Rename the file to ProcessHacker.exe.settings.xml (delete the ".txt" + extension). + +## Plugins + +Plugins can be configured from Hacker > Plugins. + +If you experience any crashes involving plugins, make sure they +are up to date. + +The ExtendedTools plugin is only available for Windows Vista and +above. Disk and Network information provided by this plugin is +only available when running Process Hacker with administrative +rights. + +## KProcessHacker + +Process Hacker uses a kernel-mode driver, KProcessHacker, to +assist with certain functionality. This includes: + +* Capturing kernel-mode stack traces +* More efficiently enumerating process handles +* Retrieving names for file handles +* Retrieving names for EtwRegistration objects +* Setting handle attributes + +Note that by default, KProcessHacker only allows connections from +processes with SeDebugPrivilege. To allow Process Hacker to show details +for all processes when it is not running as administrator: + +1. In Registry Editor, navigate to: + HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\KProcessHacker3 +2. Under this key, create a key named Parameters if it does not exist. +3. Create a DWORD value named SecurityLevel and set it to 2. If you are + not using an official build, you may need to set it to 0 instead. +4. Restart the KProcessHacker3 service (sc stop KProcessHacker3, + sc start KProcessHacker3). From 98810f309786f5f3b0f6e07639393560e9ebfd76 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 28 Jul 2017 19:37:07 +1000 Subject: [PATCH 0302/2058] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 051fbf9c326c..178bf550becd 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -##Process Hacker +## Process Hacker A free, powerful, multi-purpose tool that helps you monitor system resources, debug software and detect malware. @@ -99,4 +99,4 @@ to show details for all processes when it is not running as administrator: not using an official build, you may need to set it to 0 instead. 4. Restart the KProcessHacker3 service (sc stop KProcessHacker3, sc start KProcessHacker3). - \ No newline at end of file + From 0758700b4265c1845417f26b86a64cd569edd7f4 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 28 Jul 2017 19:42:04 +1000 Subject: [PATCH 0303/2058] BuildTools: Update readme location, Improve website changelog format --- tools/CustomBuildTool/Source Files/Build.cs | 6 +++--- .../bin/Release/CustomBuildTool.exe | Bin 160256 -> 160256 bytes .../bin/Release/CustomBuildTool.pdb | Bin 69120 -> 69120 bytes 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/CustomBuildTool/Source Files/Build.cs b/tools/CustomBuildTool/Source Files/Build.cs index f915c51c8408..a75528a64197 100644 --- a/tools/CustomBuildTool/Source Files/Build.cs +++ b/tools/CustomBuildTool/Source Files/Build.cs @@ -299,7 +299,7 @@ public static bool CopyTextFiles() { try { - Win32.CopyIfNewer("README.md", "bin\\README.txt"); + Win32.CopyIfNewer("README.txt", "bin\\README.txt"); Win32.CopyIfNewer("CHANGELOG.txt", "bin\\CHANGELOG.txt"); Win32.CopyIfNewer("COPYRIGHT.txt", "bin\\COPYRIGHT.txt"); Win32.CopyIfNewer("LICENSE.txt", "bin\\LICENSE.txt"); @@ -872,8 +872,8 @@ public static void WebServiceUpdateConfig() if (string.IsNullOrEmpty(BuildSetupSig)) return; - string buildChangelog = Win32.ShellExecute(GitExePath, "log -n 30 --date=format:%Y-%m-%d --pretty=format:\"[%cd] %an %s\""); - string buildSummary = Win32.ShellExecute(GitExePath, "log -n 5 --date=format:%Y-%m-%d --pretty=format:\"[%cd] %an %s\" --abbrev-commit"); + string buildChangelog = Win32.ShellExecute(GitExePath, "log -n 30 --date=format:%Y-%m-%d --pretty=format:\"[%cd] %s (%an)\""); + string buildSummary = Win32.ShellExecute(GitExePath, "log -n 5 --date=format:%Y-%m-%d --pretty=format:\"[%cd] %s (%an)\" --abbrev-commit"); string buildPostString = Json.Serialize(new BuildUpdateRequest { Updated = TimeStart.ToString("o"), diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe b/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe index ac40ae99e063999800bb18b2a9740a8b0b41da61..7ec0fe7844142e97d27ca7fde66e3e1a96e1c9df 100644 GIT binary patch delta 6361 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 delta 6386 zcmbVRdvH|M8NYW)Hv3L?H@SD;k1U&PHk&6Qh7ghvc^F7Q=^3l7O7Th5v+goJLl}ZcN3g;MrOF@_xpX{ z`OZ1tdEL9&IAGj3V0?JXu#YCOfaKXdJq|tb802K7 zQRobszM^s4j< zr7gC!mE{4uNu2gDnQokF-Gvr=cB~Kw2M0-?vC?{iDh5TlU<@QLq5`&DrGXkmuv(?> z(B`+R^pDhP%2S*tA%Z7W`Z1+-cE!r)OPOC7JZG>L{otUzRq?(|d80$2J&54EN?V*r zpT-BziX$KCT6{3t?{gY)0h~0=thz`I!wVF@8Hiw$O8Y4Nt3vzTW~}w4(?eF8{Uew> z5;JAe$7<=y@aZ96LjO2EI&Po_R#hLXL#)*Gl0TaRfhp*suD7lLE;^IG1GBEz+{!Iw z;x;nh5=qk46pLVt#29!QD|QzlWL_PKpcN*>p(^pvtC;Pfz|(brcqGUjMmCxnpYYbXk}iHR$-MHRR%I@*#*?qtajTmi7a(xdEhNXi#DU_ z47a2D9V1j#Izko(cB00!VkFPoePVzdw|lY!xTy`K(kS&f{H5a~8I8jlWV}KW5pQJa zpscTS6g2)mvkrH^rn2s{wl(8-tIH796=Uhvb+eUu-8v zr(afG`GRtDmjN=y>5{dCvu4w_cCymxsc9OHXJHctF4Ds~#N9TU*>c)kGd>j4j!ZXl z#2Ij_z1DY(rQVrm=(yyY=&#KdJq4B75~CTjCCAy0Qf#e*ZRs%#+A28T4`zBvael_W zk0SRs7vX(*DBmUCOit$CRNPXGQ$$au^lZPbaC6rlRHI3J*U5rKq@f^Qxh#gs*h*D+ z31N2*H9-jmV7Yj3h-C}eRj}N=m)hCUw3p;a5%CRDDwRq?9Ixf9j+-zw_H3ge)`|ce zWTg}pYesUja1048<%6ij1HAyJhhHy+d@0TZRy&Y zZ8O;>j}V_CN9Bq5)Vs!3|A}_e441HABaBthUVeoX^rh6q*EY>w5uU{sC?soK#pTq& zyW^a}KRqeH0N>e@${{`RvzGoxPssfqdX((9?n{_afsN9oYYryh4J1RN#+KvE2dgtoYItS} z?V_(KTE(MEOU$a1Z`E~NG*DKGXZtP4l z!n;{YuU3$9pGQ1GpSs~yq{8QxAF4_(CGO2`5%{)>Jmw3H5vp;KcC_K(%98dRFln?C zsie_GNDDPO18IU>_7$3IQS6PnkvEc{zfN?JIsWji^O?#wD_xTJaxd2Z-lzxmQm!q( zq8xRnoF7utGlIp}YLYYl!Z=G5U4|?#PJ?}Ds+Q zKTJA-D;Y2EKPn)SpH z9*f7t%@;Ts!Ka9ed z1vjkfcH&tLAEF!2IvX3kUI%?X6d5769{0d(+95YgB^42Rnofyy*_NTsdzz5pH{@g_ zjD{~Flai;DKr z{F{S3Fpi-O2JH~!zyTE;IH8Gyd}!mK0Pdh584XJC11`z1l>-;-9sa^QhiIq(9TLX+{H={tYf7Yk~$A8z9y09_meVJinAc$|YUJV${X4Hm*H zT#CRc4u-=ya=fS{`5&Ykf|yqw1ji!uQ79`Zo{UoO2Hdn+I&CQ~pd#jd6)RnkWThJ( zW2FZUu+j@JvC;=8S?Pz5SQ&tSu@cjs)56wf&;;%lHgGePabSTa4y@45fer5BAQv`p zkOzbVJ3PaI176|438y&7hjSbhz}Fl|V7-yGB|{LwB%B);jNpnBE9%MB@>VgA z6juhrS?Cq-#$S~12aX9!)cIQN2_#%4kv$aw^gmot=$@fCjoOSCw&u4S{c2duDbjt4 zPhzg-upJ!=jq}r;$|Hv=OCq~e$8w-Jb~~CAVq8)?f3T-2gkLgB>|(N^s!=>cUaopi z{DADJep81p5|?Uf7Od0Tv-X1aI#ITi2^nu&ZA{2`pJ-u1#v4Ty6B77#lzv|eF=1c= znLBbgG1j!E8zWn47IRo%t+kkFPJ3e#*=dtKFC{h?w>q3Ngz>^yVVp1(%W`3rur$@M_0f=+B&QER?jm8e5E7z7mry8(8~2gf zeVyhEjdW}-NPX6~DV+Du6>mMaI@L7(!Rk z{3FArbAm9VZCu;Lt@XFsJEo4^aUef+a{BIlXcorR&+mke70Z^~+eN{WWnEo&E?RQ; zGN>l6ox7O#wvIaSe`gWzeletT;U6h1sgDQB#YZYFKe3%ZY&$Q0vsL$1^e`r%z6h1e3Nt2hvU$wN!+N4RJRd8)nSW!!1My*D%t6i~mV5j>-R1mb_EJKNk z_|JZ)ml?%^sI@9~qvbKHwtv(W1wk32f*qAHf8eH7bdy$*HGb#yJ&mGXIDF@v@4M%n zd*0>lXj68yDP4-1cg(rC_pkI_{_ftFdcOMMq^XyV)>Oq0{dSr< z{%F5+q;FI9xfR3Ru}*Q=m2Xql*@jSgwM9wlFu9u!*p|o%Vw$kj>>J4#o==Q>=Exiw}j17vwob~X3FETOkdmV2@) zExn*huEf2vmbpxAz5F?n+r$j_p2_fOttxxl>ptNsJO$P=m#O7RS=xQBkwMn-1Xvw%TL7dW$Cx37tIVW|3lXv#jxEo)Yz-% zU;W&_y;f}u6B+jqEeUE;0mc$kt9C_*VlU&@xyRu67`)!xH@}Fe7(d}{+xdb??UFP(@ z(K5$&8mJ)3F?C)`59EfggUfmc_a`{(H@vy;pZDy0^cu&5+VKCySvT;N>GYe*DP6h3#H-JRWaeWapp?$gnX(lnCH?6HZNpk!%jSV2&P5k0^j{z=VW1r_Th zhbWB@1WU>oO0Wlkf07C+Bmx6_kk$_?x6mJ1cFycfX=H~voO8eLyXQXUavCp*jhDn8 z(UvrPsCpX%fZ|j6HL(ZF0%yA7)hFdjo0?)<920Nq=x-Yx>MKZd$9Sg>>}-1QkYBwS z=w=;KiXhfS0Pq`bCtJ#yFOjcuuf#0clgQ7x^EFK7V{X5Ot=Gr(9-dm2U7Jr;qCK*bB{J(mCvLhEeGHv!8J?mZy<7meh(3azi94+1 zf$_LtxfFXJNehC8RRjZx%n=O4wfH4zcT8*bhtPAz4~J0f;%ohp4Hs}W8CA`|IR9-n z>)z0rwHtwQJaU^I+YG_*CXCk4{dPDo4KOl>7%hW2U3K83VcR?{LEHA{Sv=cL9J z(c!2R9dKqTx&)(C>41$>DY_ie5;s$8;Z6QHE8PaM7PTyOlgtX$%f*E;rc>a6R&}&$ zhn0<}MZ20s)~OEc*=xs;bNE;UhOW9}A}d#Y^&SaFfu;olj%u6NM6vs7SMZz(!4=9i z0^eWQXl2XP+>Tx=f@9r#9SCme>!o>)etWFQa0_b6;LhX*fGQt=_6~7NbO(k}-s1-d z=)m9HIC7ik;0jX#()9^{&#RRITJRFd7%v+4s7aq9%`8t%`}T&-1Nfc}P!OiI{qUrT zPT_cnKbUY*cs1e7KOWL~P4G1n;JOY(z-;bH7Qj)R6EX7aNhhw&ODCOMjT+%&M`i=y zrx_^?qwN=HP~rv(3SM z{Lj2Evp50FeE*Nf%U@%qMYv=gdNJnz^0SDO&T!QHZY`Po_D^aB)ELIxRz9VVsO9*0 z*|fo(o({JOnGa4=OF{kl6eivBvlpzzCMM6->RgITU?o~_q2A?F+65MFNtw!LBc+aI zQC3IjjLb{Cc4gfkcF5~cMt-x@q7usPMB$0h@Qs3m{s=F?f$<1N{2hSr9<1ne)yBV} rzZZ*cLHD7~j`10~P0g|GW36T;C0xO`lZQ}Ed^lnXUwU0;_RjJPIv5YO From 6f259a37973b3747b448e4e1438bc89828248d7f Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 28 Jul 2017 19:44:12 +1000 Subject: [PATCH 0304/2058] Add support for searching handle values --- ProcessHacker/findobj.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ProcessHacker/findobj.c b/ProcessHacker/findobj.c index d8247c987479..602f39befab9 100644 --- a/ProcessHacker/findobj.c +++ b/ProcessHacker/findobj.c @@ -850,7 +850,7 @@ static NTSTATUS NTAPI SearchHandleFunction( _wcsupr(upperTypeName->Buffer); if ((MatchSearchString(&upperBestObjectName->sr) && MatchTypeString(&upperTypeName->sr)) || - (UseSearchPointer && context->HandleInfo->Object == (PVOID)SearchPointer)) + (UseSearchPointer && (context->HandleInfo->Object == (PVOID)SearchPointer || context->HandleInfo->HandleValue == SearchPointer))) { PPHP_OBJECT_SEARCH_RESULT searchResult; From 8da8e0f9ad88dec6c0c810f8e6d742951c85fe04 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 28 Jul 2017 20:10:42 +1000 Subject: [PATCH 0305/2058] Add contextmenu to memory search results window --- ProcessHacker/memrslt.c | 110 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) diff --git a/ProcessHacker/memrslt.c b/ProcessHacker/memrslt.c index f65c39074769..9f9bc09b2138 100644 --- a/ProcessHacker/memrslt.c +++ b/ProcessHacker/memrslt.c @@ -621,6 +621,116 @@ INT_PTR CALLBACK PhpMemoryResultsDlgProc( } } break; + case NM_RCLICK: + { + if (header->hwndFrom == lvHandle) + { + POINT point; + PPH_EMENU menu; + PPH_EMENU_ITEM selectedItem; + ULONG filterType = 0; + + menu = PhCreateEMenu(); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_MEMORY_READWRITEMEMORY, L"Read/Write memory", NULL, NULL), -1); + PhInsertEMenuItem(menu, PhCreateEMenuItem(PH_EMENU_SEPARATOR, 0, L"", NULL, NULL), -1); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, IDC_COPY, L"Copy", NULL, NULL), -1); + GetCursorPos(&point); + + selectedItem = PhShowEMenu( + menu, + hwndDlg, + PH_EMENU_SHOW_LEFTRIGHT, + PH_ALIGN_LEFT | PH_ALIGN_TOP, + point.x, + point.y + ); + + if (selectedItem) + { + switch (selectedItem->Id) + { + case ID_MEMORY_READWRITEMEMORY: + { + INT index; + + if ((index = ListView_GetNextItem( + lvHandle, + -1, + LVNI_SELECTED + )) != -1) + { + NTSTATUS status; + PPH_MEMORY_RESULT result = context->Results->Items[index]; + HANDLE processHandle; + MEMORY_BASIC_INFORMATION basicInfo; + PPH_SHOW_MEMORY_EDITOR showMemoryEditor; + + if (NT_SUCCESS(status = PhOpenProcess( + &processHandle, + PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, + context->ProcessId + ))) + { + if (NT_SUCCESS(status = NtQueryVirtualMemory( + processHandle, + result->Address, + MemoryBasicInformation, + &basicInfo, + sizeof(MEMORY_BASIC_INFORMATION), + NULL + ))) + { + showMemoryEditor = PhAllocate(sizeof(PH_SHOW_MEMORY_EDITOR)); + memset(showMemoryEditor, 0, sizeof(PH_SHOW_MEMORY_EDITOR)); + showMemoryEditor->ProcessId = context->ProcessId; + showMemoryEditor->BaseAddress = basicInfo.BaseAddress; + showMemoryEditor->RegionSize = basicInfo.RegionSize; + showMemoryEditor->SelectOffset = (ULONG)((ULONG_PTR)result->Address - (ULONG_PTR)basicInfo.BaseAddress); + showMemoryEditor->SelectLength = (ULONG)result->Length; + ProcessHacker_ShowMemoryEditor(PhMainWndHandle, showMemoryEditor); + } + + NtClose(processHandle); + } + + if (!NT_SUCCESS(status)) + PhShowStatus(hwndDlg, L"Unable to edit memory", status, 0); + } + } + break; + case IDC_COPY: + { + HWND lvHandle; + PPH_STRING string; + ULONG selectedCount; + + lvHandle = GetDlgItem(hwndDlg, IDC_LIST); + selectedCount = ListView_GetSelectedCount(lvHandle); + + if (selectedCount == 0) + { + // User didn't select anything, so copy all items. + string = PhpGetStringForSelectedResults(lvHandle, context->Results, TRUE); + PhSetStateAllListViewItems(lvHandle, LVIS_SELECTED, LVIS_SELECTED); + } + else + { + string = PhpGetStringForSelectedResults(lvHandle, context->Results, FALSE); + } + + PhSetClipboardString(hwndDlg, &string->sr); + PhDereferenceObject(string); + + SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)lvHandle, TRUE); + } + break; + } + } + + PhDestroyEMenu(menu); + } + } + break; } } break; From e980e6d5eb599a4b24e1f2ba726cfe4b54bcf9c4 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 28 Jul 2017 20:23:07 +1000 Subject: [PATCH 0306/2058] Update copyright --- ProcessHacker/memrslt.c | 1 + 1 file changed, 1 insertion(+) diff --git a/ProcessHacker/memrslt.c b/ProcessHacker/memrslt.c index 9f9bc09b2138..ba3b0750c547 100644 --- a/ProcessHacker/memrslt.c +++ b/ProcessHacker/memrslt.c @@ -3,6 +3,7 @@ * memory search results * * Copyright (C) 2010-2016 wj32 + * Copyright (C) 2017 dmex * * This file is part of Process Hacker. * From 0a0a1b16f5811091ed47e2202a1ea58fcf181e24 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 28 Jul 2017 21:18:42 +1000 Subject: [PATCH 0307/2058] Add paramater columns to the thread stack window --- ProcessHacker/thrdstk.c | 40 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/ProcessHacker/thrdstk.c b/ProcessHacker/thrdstk.c index 050eaf9267ff..0ca0d75d0ef3 100644 --- a/ProcessHacker/thrdstk.c +++ b/ProcessHacker/thrdstk.c @@ -3,6 +3,7 @@ * thread stack viewer * * Copyright (C) 2010-2016 wj32 + * Copyright (C) 2017 dmex * * This file is part of Process Hacker. * @@ -180,8 +181,16 @@ static INT_PTR CALLBACK PhpThreadStackDlgProc( PhDereferenceObject(title); lvHandle = GetDlgItem(hwndDlg, IDC_LIST); - PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 30, L" "); + PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 30, L"#"); PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 300, L"Name"); + PhAddListViewColumn(lvHandle, 2, 2, 2, LVCFMT_LEFT, 50, L"Stack"); + PhAddListViewColumn(lvHandle, 3, 3, 3, LVCFMT_LEFT, 50, L"Frame"); + PhAddListViewColumn(lvHandle, 4, 4, 4, LVCFMT_LEFT, 50, L"Parameter #1"); + PhAddListViewColumn(lvHandle, 5, 5, 5, LVCFMT_LEFT, 50, L"Parameter #2"); + PhAddListViewColumn(lvHandle, 6, 6, 6, LVCFMT_LEFT, 50, L"Parameter #3"); + PhAddListViewColumn(lvHandle, 7, 7, 7, LVCFMT_LEFT, 50, L"Parameter #4"); + PhAddListViewColumn(lvHandle, 8, 8, 8, LVCFMT_LEFT, 50, L"Address"); + PhAddListViewColumn(lvHandle, 9, 9, 9, LVCFMT_LEFT, 50, L"Return Address"); PhSetListViewStyle(lvHandle, FALSE, TRUE); PhSetControlTheme(lvHandle, L"explorer"); PhLoadListViewColumnsFromSetting(L"ThreadStackListViewColumns", lvHandle); @@ -461,10 +470,39 @@ static NTSTATUS PhpRefreshThreadStack( PTHREAD_STACK_ITEM item = ThreadStackContext->List->Items[i]; INT lvItemIndex; WCHAR integerString[PH_INT32_STR_LEN_1]; + WCHAR addressString[PH_PTR_STR_LEN_1]; PhPrintUInt32(integerString, item->Index); lvItemIndex = PhAddListViewItem(ThreadStackContext->ListViewHandle, MAXINT, integerString, item); PhSetListViewSubItem(ThreadStackContext->ListViewHandle, lvItemIndex, 1, PhGetStringOrDefault(item->Symbol, L"???")); + + PhPrintPointer(addressString, item->StackFrame.StackAddress); + PhSetListViewSubItem(ThreadStackContext->ListViewHandle, lvItemIndex, 2, addressString); + + PhPrintPointer(addressString, item->StackFrame.FrameAddress); + PhSetListViewSubItem(ThreadStackContext->ListViewHandle, lvItemIndex, 3, addressString); + + // There are no params for kernel-mode stack traces. + if ((ULONG_PTR)item->StackFrame.PcAddress <= PhSystemBasicInformation.MaximumUserModeAddress) + { + PhPrintPointer(addressString, item->StackFrame.Params[0]); + PhSetListViewSubItem(ThreadStackContext->ListViewHandle, lvItemIndex, 4, addressString); + + PhPrintPointer(addressString, item->StackFrame.Params[1]); + PhSetListViewSubItem(ThreadStackContext->ListViewHandle, lvItemIndex, 5, addressString); + + PhPrintPointer(addressString, item->StackFrame.Params[2]); + PhSetListViewSubItem(ThreadStackContext->ListViewHandle, lvItemIndex, 6, addressString); + + PhPrintPointer(addressString, item->StackFrame.Params[3]); + PhSetListViewSubItem(ThreadStackContext->ListViewHandle, lvItemIndex, 7, addressString); + } + + PhPrintPointer(addressString, item->StackFrame.PcAddress); + PhSetListViewSubItem(ThreadStackContext->ListViewHandle, lvItemIndex, 8, addressString); + + PhPrintPointer(addressString, item->StackFrame.ReturnAddress); + PhSetListViewSubItem(ThreadStackContext->ListViewHandle, lvItemIndex, 9, addressString); } SendMessage(ThreadStackContext->ListViewHandle, WM_SETREDRAW, TRUE, 0); From 9d3b37aaf39f2ad3b8224552f201e1432d9a50f1 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 30 Jul 2017 00:46:51 +1000 Subject: [PATCH 0308/2058] NetworkTools: Fix string usage --- plugins/NetworkTools/tracetree.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/NetworkTools/tracetree.c b/plugins/NetworkTools/tracetree.c index fb4d6f55a818..12aa70e1265c 100644 --- a/plugins/NetworkTools/tracetree.c +++ b/plugins/NetworkTools/tracetree.c @@ -223,7 +223,7 @@ VOID UpdateTracertNodePingText( PhFormatString(L"%s ms", PhaFormatUInt64(Node->PingList[Index], TRUE)->Buffer) ); - CellText->Text = Node->PingString[Index]->sr; + CellText->Text = PhGetStringRef(Node->PingString[Index]); } else { From 1bccd249695593fee3fde4383caa1b8238bea74a Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 30 Jul 2017 02:02:12 +1000 Subject: [PATCH 0309/2058] Fix missing ImageSubsystem for WSL processes, Remove extra handle for querying the window title --- ProcessHacker/proctree.c | 71 +++++++++++++++++++--------------------- 1 file changed, 34 insertions(+), 37 deletions(-) diff --git a/ProcessHacker/proctree.c b/ProcessHacker/proctree.c index e59e448ffab8..a6cd292c6846 100644 --- a/ProcessHacker/proctree.c +++ b/ProcessHacker/proctree.c @@ -1031,40 +1031,47 @@ static VOID PhpUpdateProcessNodeImage( PVOID imageBaseAddress; PH_REMOTE_MAPPED_IMAGE mappedImage; - if (NT_SUCCESS(PhOpenProcess(&processHandle, ProcessQueryAccess | PROCESS_VM_READ, ProcessNode->ProcessId))) + if (ProcessNode->ProcessItem->IsSubsystemProcess) { - if (NT_SUCCESS(PhGetProcessBasicInformation(processHandle, &basicInfo))) + ProcessNode->ImageSubsystem = IMAGE_SUBSYSTEM_POSIX_CUI; + } + else + { + if (NT_SUCCESS(PhOpenProcess(&processHandle, ProcessQueryAccess | PROCESS_VM_READ, ProcessNode->ProcessId))) { - if (NT_SUCCESS(NtReadVirtualMemory( - processHandle, - PTR_ADD_OFFSET(basicInfo.PebBaseAddress, FIELD_OFFSET(PEB, ImageBaseAddress)), - &imageBaseAddress, - sizeof(PVOID), - NULL - ))) + if (NT_SUCCESS(PhGetProcessBasicInformation(processHandle, &basicInfo)) && basicInfo.PebBaseAddress != 0) { - if (NT_SUCCESS(PhLoadRemoteMappedImage(processHandle, imageBaseAddress, &mappedImage))) + if (NT_SUCCESS(NtReadVirtualMemory( + processHandle, + PTR_ADD_OFFSET(basicInfo.PebBaseAddress, FIELD_OFFSET(PEB, ImageBaseAddress)), + &imageBaseAddress, + sizeof(PVOID), + NULL + ))) { - ProcessNode->ImageTimeDateStamp = mappedImage.NtHeaders->FileHeader.TimeDateStamp; - ProcessNode->ImageCharacteristics = mappedImage.NtHeaders->FileHeader.Characteristics; - - if (mappedImage.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) + if (NT_SUCCESS(PhLoadRemoteMappedImage(processHandle, imageBaseAddress, &mappedImage))) { - ProcessNode->ImageSubsystem = ((PIMAGE_OPTIONAL_HEADER32)&mappedImage.NtHeaders->OptionalHeader)->Subsystem; - ProcessNode->ImageDllCharacteristics = ((PIMAGE_OPTIONAL_HEADER32)&mappedImage.NtHeaders->OptionalHeader)->DllCharacteristics; + ProcessNode->ImageTimeDateStamp = mappedImage.NtHeaders->FileHeader.TimeDateStamp; + ProcessNode->ImageCharacteristics = mappedImage.NtHeaders->FileHeader.Characteristics; + + if (mappedImage.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) + { + ProcessNode->ImageSubsystem = ((PIMAGE_OPTIONAL_HEADER32)&mappedImage.NtHeaders->OptionalHeader)->Subsystem; + ProcessNode->ImageDllCharacteristics = ((PIMAGE_OPTIONAL_HEADER32)&mappedImage.NtHeaders->OptionalHeader)->DllCharacteristics; + } + else if (mappedImage.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) + { + ProcessNode->ImageSubsystem = ((PIMAGE_OPTIONAL_HEADER64)&mappedImage.NtHeaders->OptionalHeader)->Subsystem; + ProcessNode->ImageDllCharacteristics = ((PIMAGE_OPTIONAL_HEADER64)&mappedImage.NtHeaders->OptionalHeader)->DllCharacteristics; + } + + PhUnloadRemoteMappedImage(&mappedImage); } - else if (mappedImage.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) - { - ProcessNode->ImageSubsystem = ((PIMAGE_OPTIONAL_HEADER64)&mappedImage.NtHeaders->OptionalHeader)->Subsystem; - ProcessNode->ImageDllCharacteristics = ((PIMAGE_OPTIONAL_HEADER64)&mappedImage.NtHeaders->OptionalHeader)->DllCharacteristics; - } - - PhUnloadRemoteMappedImage(&mappedImage); } } - } - NtClose(processHandle); + NtClose(processHandle); + } } ProcessNode->ValidMask |= PHPN_IMAGE; @@ -1077,20 +1084,13 @@ static VOID PhpUpdateProcessNodeAppId( { if (!(ProcessNode->ValidMask & PHPN_APPID)) { - HANDLE processHandle; ULONG windowFlags; PPH_STRING windowTitle; PhClearReference(&ProcessNode->AppIdText); - if (!NT_SUCCESS(PhOpenProcess(&processHandle, ProcessQueryAccess | PROCESS_VM_READ, ProcessNode->ProcessId))) - { - if (!NT_SUCCESS(PhOpenProcess(&processHandle, ProcessQueryAccess, ProcessNode->ProcessId))) - goto Done; - } - - if (NT_SUCCESS(PhGetProcessWindowTitle( - processHandle, + if (ProcessNode->ProcessItem->QueryHandle && NT_SUCCESS(PhGetProcessWindowTitle( + ProcessNode->ProcessItem->QueryHandle, &windowFlags, &windowTitle ))) @@ -1101,9 +1101,6 @@ static VOID PhpUpdateProcessNodeAppId( PhDereferenceObject(windowTitle); } - NtClose(processHandle); - -Done: ProcessNode->ValidMask |= PHPN_APPID; } } From c68d1f3e2a7b23ba1c6cfcf668c768fc6de5ec19 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 30 Jul 2017 02:19:50 +1000 Subject: [PATCH 0310/2058] Fix module tab verification status text --- ProcessHacker/modlist.c | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/ProcessHacker/modlist.c b/ProcessHacker/modlist.c index e1c0c967b387..1e77f5273cd8 100644 --- a/ProcessHacker/modlist.c +++ b/ProcessHacker/modlist.c @@ -662,7 +662,7 @@ BOOLEAN NTAPI PhpModuleTreeNewCallback( switch (getCellText->Id) { case PHMOTLC_NAME: - getCellText->Text = moduleItem->Name->sr; + getCellText->Text = PhGetStringRef(moduleItem->Name); break; case PHMOTLC_BASEADDRESS: PhInitializeStringRefLongHint(&getCellText->Text, moduleItem->BaseAddressString); @@ -733,16 +733,8 @@ BOOLEAN NTAPI PhpModuleTreeNewCallback( } break; case PHMOTLC_VERIFICATIONSTATUS: - if (moduleItem->Type == PH_MODULE_TYPE_MODULE || moduleItem->Type == PH_MODULE_TYPE_KERNEL_MODULE || - moduleItem->Type == PH_MODULE_TYPE_WOW64_MODULE || moduleItem->Type == PH_MODULE_TYPE_MAPPED_IMAGE) - { - PhInitializeStringRef(&getCellText->Text, - moduleItem->VerifyResult == VrTrusted ? L"Trusted" : L"Not trusted"); - } - else - { - PhInitializeEmptyStringRef(&getCellText->Text); - } + PhInitializeStringRef(&getCellText->Text, + moduleItem->VerifyResult == VrTrusted ? L"Trusted" : L"Not trusted"); break; case PHMOTLC_VERIFIEDSIGNER: getCellText->Text = PhGetStringRef(moduleItem->VerifySignerName); From ce2a8fdf3f51e263e116d7fe23e212fa32e076df Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 30 Jul 2017 04:21:38 +1000 Subject: [PATCH 0311/2058] Fix Windows 7 issue with PhCreatePipe --- phlib/native.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/phlib/native.c b/phlib/native.c index 2817a8e7fb01..03c4812f065e 100644 --- a/phlib/native.c +++ b/phlib/native.c @@ -6208,7 +6208,7 @@ NTSTATUS PhCreatePipe( ) { NTSTATUS status; - PACL pipeAcl; + PACL pipeAcl = NULL; HANDLE pipeDirectoryHandle; HANDLE pipeReadHandle; HANDLE pipeWriteHandle; @@ -6253,7 +6253,6 @@ NTSTATUS PhCreatePipe( RtlCreateSecurityDescriptor(&securityDescriptor, SECURITY_DESCRIPTOR_REVISION); RtlSetDaclSecurityDescriptor(&securityDescriptor, TRUE, pipeAcl, FALSE); - RtlFreeHeap(RtlProcessHeap(), 0, pipeAcl); oa.SecurityDescriptor = &securityDescriptor; } @@ -6277,6 +6276,9 @@ NTSTATUS PhCreatePipe( if (!NT_SUCCESS(status)) { + if (pipeAcl) + RtlFreeHeap(RtlProcessHeap(), 0, pipeAcl); + NtClose(pipeDirectoryHandle); return status; } @@ -6305,6 +6307,9 @@ NTSTATUS PhCreatePipe( *PipeWriteHandle = pipeWriteHandle; } + if (pipeAcl) + RtlFreeHeap(RtlProcessHeap(), 0, pipeAcl); + NtClose(pipeDirectoryHandle); return status; } From 3bb7b67292f7b4384434414a3d87497bdc3825e1 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 30 Jul 2017 05:29:25 +1000 Subject: [PATCH 0312/2058] Fix analyzing thread wait on win7 and win8 --- ProcessHacker/anawait.c | 2 +- phnt/include/ntpsapi.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ProcessHacker/anawait.c b/ProcessHacker/anawait.c index 7f1f75b4bf1b..6e8d9f0f957b 100644 --- a/ProcessHacker/anawait.c +++ b/ProcessHacker/anawait.c @@ -222,7 +222,7 @@ VOID PhpAnalyzeWaitPassive( ))) { NtClose(threadHandle); - PhShowInformation(hWnd, L"Unable to determine whether the thread is waiting."); + PhShowStatus(hWnd, L"Unable to determine whether the thread is waiting.", status, 0); return; } diff --git a/phnt/include/ntpsapi.h b/phnt/include/ntpsapi.h index 1168592532ab..1be1843f6e1f 100644 --- a/phnt/include/ntpsapi.h +++ b/phnt/include/ntpsapi.h @@ -756,8 +756,8 @@ typedef struct _THREAD_LAST_SYSCALL_INFORMATION { PVOID FirstArgument; USHORT SystemCallNumber; - USHORT Reserved; // since REDSTONE2 - ULONG64 WaitTime; + //USHORT Reserved; // since REDSTONE2 + //ULONG64 WaitTime; } THREAD_LAST_SYSCALL_INFORMATION, *PTHREAD_LAST_SYSCALL_INFORMATION; // private From 43ec569448f56e7d0b44b937d0e2802c9bcbc5da Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 30 Jul 2017 05:37:14 +1000 Subject: [PATCH 0313/2058] Rewrite thread stack window: Add treelist control, Add column customization, Add right-click menu, Add column sorting --- ProcessHacker/ProcessHacker.rc | 18 +- ProcessHacker/resource.h | 5 +- ProcessHacker/settings.c | 4 +- ProcessHacker/thrdstk.c | 935 +++++++++++++++++++++++++-------- 4 files changed, 722 insertions(+), 240 deletions(-) diff --git a/ProcessHacker/ProcessHacker.rc b/ProcessHacker/ProcessHacker.rc index 63339037d300..2261c520d25c 100644 --- a/ProcessHacker/ProcessHacker.rc +++ b/ProcessHacker/ProcessHacker.rc @@ -618,15 +618,15 @@ BEGIN PUSHBUTTON "Delete",IDC_DELETE,203,239,50,14 END -IDD_THRDSTACK DIALOGEX 0, 0, 261, 228 +IDD_THRDSTACK DIALOGEX 0, 0, 273, 228 STYLE DS_SETFONT | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME CAPTION "Thread Stack" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN - CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,7,7,247,196 - PUSHBUTTON "Copy",IDC_COPY,96,207,50,14 - PUSHBUTTON "Refresh",IDC_REFRESH,150,207,50,14 - PUSHBUTTON "Close",IDOK,204,207,50,14 + PUSHBUTTON "Copy",IDC_COPY,111,212,50,14 + PUSHBUTTON "Refresh",IDC_REFRESH,165,212,50,14 + PUSHBUTTON "Close",IDOK,219,212,50,14 + CONTROL "",IDC_TREELIST,"PhTreeNew",WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP | 0x2,2,2,269,209,WS_EX_CLIENTEDGE END IDD_ABOUT DIALOGEX 0, 0, 270, 195 @@ -1920,10 +1920,10 @@ BEGIN IDD_THRDSTACK, DIALOG BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 254 - TOPMARGIN, 7 - BOTTOMMARGIN, 221 + LEFTMARGIN, 2 + RIGHTMARGIN, 271 + TOPMARGIN, 2 + BOTTOMMARGIN, 226 END IDD_ABOUT, DIALOG diff --git a/ProcessHacker/resource.h b/ProcessHacker/resource.h index 6e5d76cb8a14..00012e75a9d9 100644 --- a/ProcessHacker/resource.h +++ b/ProcessHacker/resource.h @@ -534,6 +534,7 @@ #define IDC_SEARCH 1387 #define IDC_FILTEROPTIONS 1389 #define IDC_FILTERTYPE 1390 +#define IDC_TREELIST 1391 #define ID_HACKER_EXIT 40001 #define ID_PROCESS_PROPERTIES 40006 #define ID_PROCESS_TERMINATE 40007 @@ -739,9 +740,9 @@ // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 232 +#define _APS_NEXT_RESOURCE_VALUE 233 #define _APS_NEXT_COMMAND_VALUE 40297 -#define _APS_NEXT_CONTROL_VALUE 1391 +#define _APS_NEXT_CONTROL_VALUE 1392 #define _APS_NEXT_SYMED_VALUE 169 #endif #endif diff --git a/ProcessHacker/settings.c b/ProcessHacker/settings.c index 55528bca1a76..9ad41d1257c8 100644 --- a/ProcessHacker/settings.c +++ b/ProcessHacker/settings.c @@ -145,8 +145,8 @@ VOID PhAddDefaultSettings( PhpAddIntegerSetting(L"ThinRows", L"0"); PhpAddStringSetting(L"ThreadTreeListColumns", L""); PhpAddStringSetting(L"ThreadTreeListSort", L"1,2"); // 1, DescendingSortOrder - PhpAddStringSetting(L"ThreadStackListViewColumns", L""); - PhpAddScalableIntegerPairSetting(L"ThreadStackWindowSize", L"@96|420,380"); + PhpAddStringSetting(L"ThreadStackTreeListColumns", L""); + PhpAddScalableIntegerPairSetting(L"ThreadStackWindowSize", L"@96|420,400"); PhpAddStringSetting(L"TokenGroupsListViewColumns", L""); PhpAddIntegerSetting(L"TokenSplitterPosition", L"150"); PhpAddStringSetting(L"TokenPrivilegesListViewColumns", L""); diff --git a/ProcessHacker/thrdstk.c b/ProcessHacker/thrdstk.c index 0ca0d75d0ef3..6406cbdad01a 100644 --- a/ProcessHacker/thrdstk.c +++ b/ProcessHacker/thrdstk.c @@ -23,23 +23,28 @@ #include +#include +#include #include #include #include +#include #include #include #include #define WM_PH_COMPLETED (WM_APP + 301) #define WM_PH_STATUS_UPDATE (WM_APP + 302) +#define WM_PH_SHOWSTACKMENU (WM_APP + 303) -typedef struct _THREAD_STACK_CONTEXT +static RECT MinimumSize = { -1, -1, -1, -1 }; + +typedef struct _PH_THREAD_STACK_CONTEXT { HANDLE ProcessId; HANDLE ThreadId; HANDLE ThreadHandle; - HWND ListViewHandle; PPH_THREAD_PROVIDER ThreadProvider; PPH_SYMBOL_PROVIDER SymbolProvider; BOOLEAN CustomWalk; @@ -51,7 +56,17 @@ typedef struct _THREAD_STACK_CONTEXT NTSTATUS WalkStatus; PPH_STRING StatusMessage; PH_QUEUED_LOCK StatusLock; -} THREAD_STACK_CONTEXT, *PTHREAD_STACK_CONTEXT; + + PH_LAYOUT_MANAGER LayoutManager; + + HWND WindowHandle; + HWND TreeNewHandle; + ULONG TreeNewSortColumn; + PH_SORT_ORDER TreeNewSortOrder; + PPH_HASHTABLE NodeHashtable; + PPH_LIST NodeList; + PPH_LIST NodeRootList; +} PH_THREAD_STACK_CONTEXT, *PPH_THREAD_STACK_CONTEXT; typedef struct _THREAD_STACK_ITEM { @@ -60,6 +75,43 @@ typedef struct _THREAD_STACK_ITEM PPH_STRING Symbol; } THREAD_STACK_ITEM, *PTHREAD_STACK_ITEM; +typedef enum _PH_STACK_TREE_COLUMN_ITEM_NAME +{ + PH_STACK_TREE_COLUMN_INDEX, + PH_STACK_TREE_COLUMN_SYMBOL, + PH_STACK_TREE_COLUMN_STACKADDRESS, + PH_STACK_TREE_COLUMN_FRAMEADDRESS, + PH_STACK_TREE_COLUMN_PARAMETER1, + PH_STACK_TREE_COLUMN_PARAMETER2, + PH_STACK_TREE_COLUMN_PARAMETER3, + PH_STACK_TREE_COLUMN_PARAMETER4, + PH_STACK_TREE_COLUMN_CONTROLADDRESS, + PH_STACK_TREE_COLUMN_RETURNADDRESS, + TREE_COLUMN_ITEM_MAXIMUM +} PH_STACK_TREE_COLUMN_ITEM_NAME; + +typedef struct _PH_STACK_TREE_ROOT_NODE +{ + PH_TREENEW_NODE Node; + + PH_THREAD_STACK_FRAME StackFrame; + + ULONG Index; + PPH_STRING TooltipText; + PPH_STRING IndexString; + PPH_STRING SymbolString; + WCHAR StackAddressString[PH_PTR_STR_LEN_1]; + WCHAR FrameAddressString[PH_PTR_STR_LEN_1]; + WCHAR Parameter1String[PH_PTR_STR_LEN_1]; + WCHAR Parameter2String[PH_PTR_STR_LEN_1]; + WCHAR Parameter3String[PH_PTR_STR_LEN_1]; + WCHAR Parameter4String[PH_PTR_STR_LEN_1]; + WCHAR PcAddressString[PH_PTR_STR_LEN_1]; + WCHAR ReturnAddressString[PH_PTR_STR_LEN_1]; + + PH_STRINGREF TextCache[TREE_COLUMN_ITEM_MAXIMUM]; +} PH_STACK_TREE_ROOT_NODE, *PPH_STACK_TREE_ROOT_NODE; + INT_PTR CALLBACK PhpThreadStackDlgProc( _In_ HWND hwndDlg, _In_ UINT uMsg, @@ -73,7 +125,7 @@ VOID PhpFreeThreadStackItem( NTSTATUS PhpRefreshThreadStack( _In_ HWND hwnd, - _In_ PTHREAD_STACK_CONTEXT ThreadStackContext + _In_ PPH_THREAD_STACK_CONTEXT ThreadStackContext ); INT_PTR CALLBACK PhpThreadStackProgressDlgProc( @@ -83,7 +135,526 @@ INT_PTR CALLBACK PhpThreadStackProgressDlgProc( _In_ LPARAM lParam ); -static RECT MinimumSize = { -1, -1, -1, -1 }; +#define SORT_FUNCTION(Column) ThreadStackTreeNewCompare##Column +#define BEGIN_SORT_FUNCTION(Column) static int __cdecl ThreadStackTreeNewCompare##Column( \ + _In_ void *_context, \ + _In_ const void *_elem1, \ + _In_ const void *_elem2 \ + ) \ +{ \ + PPH_STACK_TREE_ROOT_NODE node1 = *(PPH_STACK_TREE_ROOT_NODE*)_elem1; \ + PPH_STACK_TREE_ROOT_NODE node2 = *(PPH_STACK_TREE_ROOT_NODE*)_elem2; \ + int sortResult = 0; + +#define END_SORT_FUNCTION \ + if (sortResult == 0) \ + sortResult = uintptrcmp((ULONG_PTR)node1->Node.Index, (ULONG_PTR)node2->Node.Index); \ + \ + return PhModifySort(sortResult, ((PPH_THREAD_STACK_CONTEXT)_context)->TreeNewSortOrder); \ +} + +BEGIN_SORT_FUNCTION(Index) +{ + sortResult = uint64cmp(node1->Index, node2->Index); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(Symbol) +{ + sortResult = PhCompareString(node1->SymbolString, node2->SymbolString, TRUE); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(StackAddress) +{ + sortResult = PhCompareStringZ(node1->StackAddressString, node2->StackAddressString, TRUE); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(FrameAddress) +{ + sortResult = PhCompareStringZ(node1->FrameAddressString, node2->FrameAddressString, TRUE); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(StackParameter1) +{ + sortResult = PhCompareStringZ(node1->Parameter1String, node2->Parameter1String, TRUE); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(StackParameter2) +{ + sortResult = PhCompareStringZ(node1->Parameter2String, node2->Parameter2String, TRUE); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(StackParameter3) +{ + sortResult = PhCompareStringZ(node1->Parameter3String, node2->Parameter3String, TRUE); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(StackParameter4) +{ + sortResult = PhCompareStringZ(node1->Parameter4String, node2->Parameter4String, TRUE); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(ControlAddress) +{ + sortResult = PhCompareStringZ(node1->PcAddressString, node2->PcAddressString, TRUE); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(ReturnAddress) +{ + sortResult = PhCompareStringZ(node1->ReturnAddressString, node2->ReturnAddressString, TRUE); +} +END_SORT_FUNCTION + +VOID ThreadStackLoadSettingsTreeList( + _Inout_ PPH_THREAD_STACK_CONTEXT Context + ) +{ + PPH_STRING settings; + + settings = PhGetStringSetting(L"ThreadStackTreeListColumns"); + PhCmLoadSettings(Context->TreeNewHandle, &settings->sr); + PhDereferenceObject(settings); +} + +VOID ThreadStackSaveSettingsTreeList( + _Inout_ PPH_THREAD_STACK_CONTEXT Context + ) +{ + PPH_STRING settings; + + settings = PhCmSaveSettings(Context->TreeNewHandle); + PhSetStringSetting2(L"ThreadStackTreeListColumns", &settings->sr); + PhDereferenceObject(settings); +} + +BOOLEAN ThreadStackNodeHashtableEqualFunction( + _In_ PVOID Entry1, + _In_ PVOID Entry2 + ) +{ + PPH_STACK_TREE_ROOT_NODE node1 = *(PPH_STACK_TREE_ROOT_NODE *)Entry1; + PPH_STACK_TREE_ROOT_NODE node2 = *(PPH_STACK_TREE_ROOT_NODE *)Entry2; + + return node1->Index == node2->Index; +} + +ULONG ThreadStackNodeHashtableHashFunction( + _In_ PVOID Entry + ) +{ + return (*(PPH_STACK_TREE_ROOT_NODE*)Entry)->Index; +} + +VOID DestroyThreadStackNode( + _In_ PPH_STACK_TREE_ROOT_NODE Node + ) +{ + PhClearReference(&Node->SymbolString); + + PhDereferenceObject(Node); +} + +PPH_STACK_TREE_ROOT_NODE AddThreadStackNode( + _Inout_ PPH_THREAD_STACK_CONTEXT Context, + _In_ ULONG Index + ) +{ + PPH_STACK_TREE_ROOT_NODE threadStackNode; + + threadStackNode = PhCreateAlloc(sizeof(PH_STACK_TREE_ROOT_NODE)); + memset(threadStackNode, 0, sizeof(PH_STACK_TREE_ROOT_NODE)); + + PhInitializeTreeNewNode(&threadStackNode->Node); + + memset(threadStackNode->TextCache, 0, sizeof(PH_STRINGREF) * TREE_COLUMN_ITEM_MAXIMUM); + threadStackNode->Node.TextCache = threadStackNode->TextCache; + threadStackNode->Node.TextCacheSize = TREE_COLUMN_ITEM_MAXIMUM; + + threadStackNode->Index = Index; + + PhAddEntryHashtable(Context->NodeHashtable, &threadStackNode); + PhAddItemList(Context->NodeList, threadStackNode); + + // TreeNew_NodesStructured(Context->TreeNewHandle); + + return threadStackNode; +} + +PPH_STACK_TREE_ROOT_NODE FindThreadStackNode( + _In_ PPH_THREAD_STACK_CONTEXT Context, + _In_ ULONG Index + ) +{ + PH_STACK_TREE_ROOT_NODE lookupThreadStackNode; + PPH_STACK_TREE_ROOT_NODE lookupThreadStackNodePtr = &lookupThreadStackNode; + PPH_STACK_TREE_ROOT_NODE *threadStackNode; + + lookupThreadStackNode.Index = Index; + + threadStackNode = (PPH_STACK_TREE_ROOT_NODE*)PhFindEntryHashtable( + Context->NodeHashtable, + &lookupThreadStackNodePtr + ); + + if (threadStackNode) + return *threadStackNode; + else + return NULL; +} + +VOID RemoveThreadStackNode( + _In_ PPH_THREAD_STACK_CONTEXT Context, + _In_ PPH_STACK_TREE_ROOT_NODE Node +) +{ + ULONG index = 0; + + PhRemoveEntryHashtable(Context->NodeHashtable, &Node); + + if ((index = PhFindItemList(Context->NodeList, Node)) != -1) + { + PhRemoveItemList(Context->NodeList, index); + } + + DestroyThreadStackNode(Node); + TreeNew_NodesStructured(Context->TreeNewHandle); +} + +VOID UpdateThreadStackNode( + _In_ PPH_THREAD_STACK_CONTEXT Context, + _In_ PPH_STACK_TREE_ROOT_NODE Node + ) +{ + memset(Node->TextCache, 0, sizeof(PH_STRINGREF) * TREE_COLUMN_ITEM_MAXIMUM); + + PhInvalidateTreeNewNode(&Node->Node, TN_CACHE_COLOR); + TreeNew_NodesStructured(Context->TreeNewHandle); +} + +BOOLEAN NTAPI ThreadStackTreeNewCallback( + _In_ HWND hwnd, + _In_ PH_TREENEW_MESSAGE Message, + _In_opt_ PVOID Parameter1, + _In_opt_ PVOID Parameter2, + _In_opt_ PVOID Context + ) +{ + PPH_THREAD_STACK_CONTEXT context = Context; + PPH_STACK_TREE_ROOT_NODE node; + + switch (Message) + { + case TreeNewGetChildren: + { + PPH_TREENEW_GET_CHILDREN getChildren = Parameter1; + node = (PPH_STACK_TREE_ROOT_NODE)getChildren->Node; + + if (!getChildren->Node) + { + static PVOID sortFunctions[] = + { + SORT_FUNCTION(Index), + SORT_FUNCTION(Symbol), + SORT_FUNCTION(StackAddress), + SORT_FUNCTION(FrameAddress), + SORT_FUNCTION(StackParameter1), + SORT_FUNCTION(StackParameter2), + SORT_FUNCTION(StackParameter3), + SORT_FUNCTION(StackParameter4), + SORT_FUNCTION(ControlAddress), + SORT_FUNCTION(ReturnAddress), + }; + int (__cdecl *sortFunction)(void *, const void *, const void *); + + if (context->TreeNewSortColumn < TREE_COLUMN_ITEM_MAXIMUM) + sortFunction = sortFunctions[context->TreeNewSortColumn]; + else + sortFunction = NULL; + + if (sortFunction) + { + qsort_s(context->NodeList->Items, context->NodeList->Count, sizeof(PVOID), sortFunction, context); + } + + getChildren->Children = (PPH_TREENEW_NODE *)context->NodeList->Items; + getChildren->NumberOfChildren = context->NodeList->Count; + } + } + return TRUE; + case TreeNewIsLeaf: + { + PPH_TREENEW_IS_LEAF isLeaf = (PPH_TREENEW_IS_LEAF)Parameter1; + node = (PPH_STACK_TREE_ROOT_NODE)isLeaf->Node; + + isLeaf->IsLeaf = TRUE; + } + return TRUE; + case TreeNewGetCellText: + { + PPH_TREENEW_GET_CELL_TEXT getCellText = (PPH_TREENEW_GET_CELL_TEXT)Parameter1; + node = (PPH_STACK_TREE_ROOT_NODE)getCellText->Node; + + switch (getCellText->Id) + { + case PH_STACK_TREE_COLUMN_INDEX: + { + PhMoveReference(&node->IndexString, PhFormatUInt64(node->Index, TRUE)); + getCellText->Text = PhGetStringRef(node->IndexString); + } + break; + case PH_STACK_TREE_COLUMN_SYMBOL: + getCellText->Text = PhGetStringRef(node->SymbolString); + break; + case PH_STACK_TREE_COLUMN_STACKADDRESS: + PhInitializeStringRefLongHint(&getCellText->Text, node->StackAddressString); + break; + case PH_STACK_TREE_COLUMN_FRAMEADDRESS: + PhInitializeStringRefLongHint(&getCellText->Text, node->FrameAddressString); + break; + case PH_STACK_TREE_COLUMN_PARAMETER1: + PhInitializeStringRefLongHint(&getCellText->Text, node->Parameter1String); + break; + case PH_STACK_TREE_COLUMN_PARAMETER2: + PhInitializeStringRefLongHint(&getCellText->Text, node->Parameter2String); + break; + case PH_STACK_TREE_COLUMN_PARAMETER3: + PhInitializeStringRefLongHint(&getCellText->Text, node->Parameter3String); + break; + case PH_STACK_TREE_COLUMN_PARAMETER4: + PhInitializeStringRefLongHint(&getCellText->Text, node->Parameter4String); + break; + case PH_STACK_TREE_COLUMN_CONTROLADDRESS: + PhInitializeStringRefLongHint(&getCellText->Text, node->PcAddressString); + break; + case PH_STACK_TREE_COLUMN_RETURNADDRESS: + PhInitializeStringRefLongHint(&getCellText->Text, node->ReturnAddressString); + break; + default: + return FALSE; + } + + getCellText->Flags = TN_CACHE; + } + return TRUE; + case TreeNewGetNodeColor: + { + PPH_TREENEW_GET_NODE_COLOR getNodeColor = Parameter1; + node = (PPH_STACK_TREE_ROOT_NODE)getNodeColor->Node; + + getNodeColor->Flags = TN_CACHE | TN_AUTO_FORECOLOR; + } + return TRUE; + case TreeNewSortChanged: + { + TreeNew_GetSort(hwnd, &context->TreeNewSortColumn, &context->TreeNewSortOrder); + // Force a rebuild to sort the items. + TreeNew_NodesStructured(hwnd); + } + return TRUE; + case TreeNewContextMenu: + { + PPH_TREENEW_CONTEXT_MENU contextMenuEvent = Parameter1; + + SendMessage( + context->WindowHandle, + WM_COMMAND, + WM_PH_SHOWSTACKMENU, + (LPARAM)contextMenuEvent + ); + } + return TRUE; + case TreeNewHeaderRightClick: + { + PH_TN_COLUMN_MENU_DATA data; + + data.TreeNewHandle = hwnd; + data.MouseEvent = Parameter1; + data.DefaultSortColumn = 0; + data.DefaultSortOrder = AscendingSortOrder; + PhInitializeTreeNewColumnMenu(&data); + + data.Selection = PhShowEMenu(data.Menu, hwnd, PH_EMENU_SHOW_LEFTRIGHT, + PH_ALIGN_LEFT | PH_ALIGN_TOP, data.MouseEvent->ScreenLocation.x, data.MouseEvent->ScreenLocation.y); + PhHandleTreeNewColumnMenu(&data); + PhDeleteTreeNewColumnMenu(&data); + } + return TRUE; + case TreeNewGetCellTooltip: + { + PPH_TREENEW_GET_CELL_TOOLTIP getCellTooltip = Parameter1; + node = (PPH_STACK_TREE_ROOT_NODE)getCellTooltip->Node; + + if (getCellTooltip->Column->Id != 0) + return FALSE; + + if (!node->TooltipText) + { + PH_STRING_BUILDER stringBuilder; + PPH_STRING fileName; + PH_SYMBOL_LINE_INFORMATION lineInfo; + + PhInitializeStringBuilder(&stringBuilder, 40); + + if (PhGetLineFromAddress( + context->SymbolProvider, + (ULONG64)node->StackFrame.PcAddress, + &fileName, + NULL, + &lineInfo + )) + { + PhAppendFormatStringBuilder( + &stringBuilder, + L"File: %s: line %u\n", + fileName->Buffer, + lineInfo.LineNumber + ); + PhDereferenceObject(fileName); + } + + if (stringBuilder.String->Length != 0) + PhRemoveEndStringBuilder(&stringBuilder, 1); + + if (PhPluginsEnabled) + { + PH_PLUGIN_THREAD_STACK_CONTROL control; + + control.Type = PluginThreadStackGetTooltip; + control.UniqueKey = context; + control.u.GetTooltip.StackFrame = &node->StackFrame; + control.u.GetTooltip.StringBuilder = &stringBuilder; + PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackThreadStackControl), &control); + } + + node->TooltipText = PhFinalStringBuilderString(&stringBuilder); + } + + if (!PhIsNullOrEmptyString(node->TooltipText)) + { + getCellTooltip->Text = node->TooltipText->sr; + getCellTooltip->Unfolding = FALSE; + getCellTooltip->Font = NULL; // use default font + getCellTooltip->MaximumWidth = 550; + } + else + { + return FALSE; + } + } + return TRUE; + } + + return FALSE; +} + +VOID ClearThreadStackTree( + _In_ PPH_THREAD_STACK_CONTEXT Context + ) +{ + for (ULONG i = 0; i < Context->NodeList->Count; i++) + DestroyThreadStackNode(Context->NodeList->Items[i]); + + PhClearHashtable(Context->NodeHashtable); + PhClearList(Context->NodeList); +} + +PPH_STACK_TREE_ROOT_NODE GetSelectedThreadStackNode( + _In_ PPH_THREAD_STACK_CONTEXT Context + ) +{ + PPH_STACK_TREE_ROOT_NODE windowNode = NULL; + + for (ULONG i = 0; i < Context->NodeList->Count; i++) + { + windowNode = Context->NodeList->Items[i]; + + if (windowNode->Node.Selected) + return windowNode; + } + + return NULL; +} + +VOID GetSelectedThreadStackNodes( + _In_ PPH_THREAD_STACK_CONTEXT Context, + _Out_ PPH_STACK_TREE_ROOT_NODE **ThreadStackNodes, + _Out_ PULONG NumberOfThreadStackNodes + ) +{ + PPH_LIST list; + + list = PhCreateList(2); + + for (ULONG i = 0; i < Context->NodeList->Count; i++) + { + PPH_STACK_TREE_ROOT_NODE node = (PPH_STACK_TREE_ROOT_NODE)Context->NodeList->Items[i]; + + if (node->Node.Selected) + { + PhAddItemList(list, node); + } + } + + *ThreadStackNodes = PhAllocateCopy(list->Items, sizeof(PVOID) * list->Count); + *NumberOfThreadStackNodes = list->Count; + + PhDereferenceObject(list); +} + +VOID InitializeThreadStackTree( + _Inout_ PPH_THREAD_STACK_CONTEXT Context + ) +{ + Context->NodeList = PhCreateList(100); + Context->NodeHashtable = PhCreateHashtable( + sizeof(PPH_STACK_TREE_ROOT_NODE), + ThreadStackNodeHashtableEqualFunction, + ThreadStackNodeHashtableHashFunction, + 100 + ); + + PhSetControlTheme(Context->TreeNewHandle, L"explorer"); + + TreeNew_SetCallback(Context->TreeNewHandle, ThreadStackTreeNewCallback, Context); + + PhAddTreeNewColumn(Context->TreeNewHandle, PH_STACK_TREE_COLUMN_INDEX, TRUE, L"#", 30, PH_ALIGN_LEFT, PH_STACK_TREE_COLUMN_INDEX, 0); + PhAddTreeNewColumn(Context->TreeNewHandle, PH_STACK_TREE_COLUMN_SYMBOL, TRUE, L"Name", 250, PH_ALIGN_LEFT, PH_STACK_TREE_COLUMN_SYMBOL, 0); + PhAddTreeNewColumn(Context->TreeNewHandle, PH_STACK_TREE_COLUMN_STACKADDRESS, FALSE, L"Stack address", 100, PH_ALIGN_LEFT, PH_STACK_TREE_COLUMN_STACKADDRESS, 0); + PhAddTreeNewColumn(Context->TreeNewHandle, PH_STACK_TREE_COLUMN_FRAMEADDRESS, FALSE, L"Frame address", 100, PH_ALIGN_LEFT, PH_STACK_TREE_COLUMN_FRAMEADDRESS, 0); + PhAddTreeNewColumn(Context->TreeNewHandle, PH_STACK_TREE_COLUMN_PARAMETER1, FALSE, L"Stack parameter #1", 100, PH_ALIGN_LEFT, PH_STACK_TREE_COLUMN_PARAMETER1, 0); + PhAddTreeNewColumn(Context->TreeNewHandle, PH_STACK_TREE_COLUMN_PARAMETER2, FALSE, L"Stack parameter #2", 100, PH_ALIGN_LEFT, PH_STACK_TREE_COLUMN_PARAMETER2, 0); + PhAddTreeNewColumn(Context->TreeNewHandle, PH_STACK_TREE_COLUMN_PARAMETER3, FALSE, L"Stack parameter #3", 100, PH_ALIGN_LEFT, PH_STACK_TREE_COLUMN_PARAMETER3, 0); + PhAddTreeNewColumn(Context->TreeNewHandle, PH_STACK_TREE_COLUMN_PARAMETER4, FALSE, L"Stack parameter #4", 100, PH_ALIGN_LEFT, PH_STACK_TREE_COLUMN_PARAMETER4, 0); + PhAddTreeNewColumn(Context->TreeNewHandle, PH_STACK_TREE_COLUMN_CONTROLADDRESS, TRUE, L"Control address", 100, PH_ALIGN_LEFT, PH_STACK_TREE_COLUMN_CONTROLADDRESS, 0); + PhAddTreeNewColumn(Context->TreeNewHandle, PH_STACK_TREE_COLUMN_RETURNADDRESS, FALSE, L"Return address", 100, PH_ALIGN_LEFT, PH_STACK_TREE_COLUMN_RETURNADDRESS, 0); + + TreeNew_SetTriState(Context->TreeNewHandle, TRUE); + + ThreadStackLoadSettingsTreeList(Context); +} + +VOID DeleteThreadStackTree( + _In_ PPH_THREAD_STACK_CONTEXT Context + ) +{ + ThreadStackSaveSettingsTreeList(Context); + + for (ULONG i = 0; i < Context->NodeList->Count; i++) + { + DestroyThreadStackNode(Context->NodeList->Items[i]); + } + + PhDereferenceObject(Context->NodeHashtable); + PhDereferenceObject(Context->NodeList); +} VOID PhShowThreadStackDialog( _In_ HWND ParentWindowHandle, @@ -93,7 +664,7 @@ VOID PhShowThreadStackDialog( ) { NTSTATUS status; - THREAD_STACK_CONTEXT threadStackContext; + PH_THREAD_STACK_CONTEXT threadStackContext; HANDLE threadHandle = NULL; // If the user is trying to view a system thread stack @@ -104,7 +675,7 @@ VOID PhShowThreadStackDialog( return; } - memset(&threadStackContext, 0, sizeof(THREAD_STACK_CONTEXT)); + memset(&threadStackContext, 0, sizeof(PH_THREAD_STACK_CONTEXT)); threadStackContext.ProcessId = ProcessId; threadStackContext.ThreadId = ThreadId; threadStackContext.ThreadProvider = ThreadProvider; @@ -160,55 +731,42 @@ static INT_PTR CALLBACK PhpThreadStackDlgProc( _In_ LPARAM lParam ) { + PPH_THREAD_STACK_CONTEXT context; + + if (uMsg == WM_INITDIALOG) + { + context = (PPH_THREAD_STACK_CONTEXT)lParam; + SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)context); + } + else + { + context = (PPH_THREAD_STACK_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom()); + } + + if (!context) + return FALSE; + switch (uMsg) { case WM_INITDIALOG: { NTSTATUS status; - PTHREAD_STACK_CONTEXT threadStackContext; - PPH_STRING title; - HWND lvHandle; - PPH_LAYOUT_MANAGER layoutManager; + + context->WindowHandle = hwndDlg; + context->TreeNewHandle = GetDlgItem(hwndDlg, IDC_TREELIST); SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER))); SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER))); - threadStackContext = (PTHREAD_STACK_CONTEXT)lParam; - SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)threadStackContext); - - title = PhFormatString(L"Stack - thread %u", HandleToUlong(threadStackContext->ThreadId)); - SetWindowText(hwndDlg, title->Buffer); - PhDereferenceObject(title); - - lvHandle = GetDlgItem(hwndDlg, IDC_LIST); - PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 30, L"#"); - PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 300, L"Name"); - PhAddListViewColumn(lvHandle, 2, 2, 2, LVCFMT_LEFT, 50, L"Stack"); - PhAddListViewColumn(lvHandle, 3, 3, 3, LVCFMT_LEFT, 50, L"Frame"); - PhAddListViewColumn(lvHandle, 4, 4, 4, LVCFMT_LEFT, 50, L"Parameter #1"); - PhAddListViewColumn(lvHandle, 5, 5, 5, LVCFMT_LEFT, 50, L"Parameter #2"); - PhAddListViewColumn(lvHandle, 6, 6, 6, LVCFMT_LEFT, 50, L"Parameter #3"); - PhAddListViewColumn(lvHandle, 7, 7, 7, LVCFMT_LEFT, 50, L"Parameter #4"); - PhAddListViewColumn(lvHandle, 8, 8, 8, LVCFMT_LEFT, 50, L"Address"); - PhAddListViewColumn(lvHandle, 9, 9, 9, LVCFMT_LEFT, 50, L"Return Address"); - PhSetListViewStyle(lvHandle, FALSE, TRUE); - PhSetControlTheme(lvHandle, L"explorer"); - PhLoadListViewColumnsFromSetting(L"ThreadStackListViewColumns", lvHandle); - - threadStackContext->ListViewHandle = lvHandle; - - layoutManager = PhAllocate(sizeof(PH_LAYOUT_MANAGER)); - PhInitializeLayoutManager(layoutManager, hwndDlg); - SetProp(hwndDlg, L"LayoutManager", (HANDLE)layoutManager); - - PhAddLayoutItem(layoutManager, lvHandle, NULL, - PH_ANCHOR_ALL); - PhAddLayoutItem(layoutManager, GetDlgItem(hwndDlg, IDC_COPY), - NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); - PhAddLayoutItem(layoutManager, GetDlgItem(hwndDlg, IDC_REFRESH), - NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); - PhAddLayoutItem(layoutManager, GetDlgItem(hwndDlg, IDOK), - NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); + SetWindowText(hwndDlg, PhaFormatString(L"Stack - thread %u", HandleToUlong(context->ThreadId))->Buffer); + + InitializeThreadStackTree(context); + + PhInitializeLayoutManager(&context->LayoutManager, hwndDlg); + PhAddLayoutItem(&context->LayoutManager, context->TreeNewHandle, NULL, PH_ANCHOR_ALL); + PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_COPY), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); + PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_REFRESH), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); + PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDOK), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); if (MinimumSize.left == -1) { @@ -231,18 +789,18 @@ static INT_PTR CALLBACK PhpThreadStackDlgProc( PH_PLUGIN_THREAD_STACK_CONTROL control; control.Type = PluginThreadStackInitializing; - control.UniqueKey = threadStackContext; - control.u.Initializing.ProcessId = threadStackContext->ProcessId; - control.u.Initializing.ThreadId = threadStackContext->ThreadId; - control.u.Initializing.ThreadHandle = threadStackContext->ThreadHandle; - control.u.Initializing.SymbolProvider = threadStackContext->SymbolProvider; + control.UniqueKey = context; + control.u.Initializing.ProcessId = context->ProcessId; + control.u.Initializing.ThreadId = context->ThreadId; + control.u.Initializing.ThreadHandle = context->ThreadHandle; + control.u.Initializing.SymbolProvider = context->SymbolProvider; control.u.Initializing.CustomWalk = FALSE; PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackThreadStackControl), &control); - threadStackContext->CustomWalk = control.u.Initializing.CustomWalk; + context->CustomWalk = control.u.Initializing.CustomWalk; } - status = PhpRefreshThreadStack(hwndDlg, threadStackContext); + status = PhpRefreshThreadStack(hwndDlg, context); if (status == STATUS_ABANDONED) EndDialog(hwndDlg, IDCANCEL); @@ -252,33 +810,26 @@ static INT_PTR CALLBACK PhpThreadStackDlgProc( break; case WM_DESTROY: { - PPH_LAYOUT_MANAGER layoutManager; - PTHREAD_STACK_CONTEXT threadStackContext; - ULONG i; + context->StopWalk = TRUE; - layoutManager = (PPH_LAYOUT_MANAGER)GetProp(hwndDlg, L"LayoutManager"); - PhDeleteLayoutManager(layoutManager); - PhFree(layoutManager); + DeleteThreadStackTree(context); - threadStackContext = (PTHREAD_STACK_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom()); + PhDeleteLayoutManager(&context->LayoutManager); if (PhPluginsEnabled) { PH_PLUGIN_THREAD_STACK_CONTROL control; - control.Type = PluginThreadStackUninitializing; - control.UniqueKey = threadStackContext; + control.UniqueKey = context; PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackThreadStackControl), &control); } - for (i = 0; i < threadStackContext->List->Count; i++) - PhpFreeThreadStackItem(threadStackContext->List->Items[i]); + for (ULONG i = 0; i < context->List->Count; i++) + PhpFreeThreadStackItem(context->List->Items[i]); - PhSaveListViewColumnsToSetting(L"ThreadStackListViewColumns", GetDlgItem(hwndDlg, IDC_LIST)); PhSaveWindowPlacementToSetting(NULL, L"ThreadStackWindowSize", hwndDlg); RemoveProp(hwndDlg, PhMakeContextAtom()); - RemoveProp(hwndDlg, L"LayoutManager"); } break; case WM_COMMAND: @@ -295,10 +846,7 @@ static INT_PTR CALLBACK PhpThreadStackDlgProc( { NTSTATUS status; - if (!NT_SUCCESS(status = PhpRefreshThreadStack( - hwndDlg, - (PTHREAD_STACK_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom()) - ))) + if (!NT_SUCCESS(status = PhpRefreshThreadStack(hwndDlg, context))) { PhShowStatus(hwndDlg, L"Unable to load the stack", status, 0); } @@ -306,103 +854,43 @@ static INT_PTR CALLBACK PhpThreadStackDlgProc( break; case IDC_COPY: { - HWND lvHandle; + PPH_STRING text; - lvHandle = GetDlgItem(hwndDlg, IDC_LIST); - - if (ListView_GetSelectedCount(lvHandle) == 0) - PhSetStateAllListViewItems(lvHandle, LVIS_SELECTED, LVIS_SELECTED); - - PhCopyListView(lvHandle); - SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)lvHandle, TRUE); + text = PhGetTreeNewText(context->TreeNewHandle, 0); + PhSetClipboardString(context->TreeNewHandle, &text->sr); + PhDereferenceObject(text); } break; - } - } - break; - case WM_NOTIFY: - { - LPNMHDR header = (LPNMHDR)lParam; - - switch (header->code) - { - case LVN_GETINFOTIP: + case WM_PH_SHOWSTACKMENU: { - LPNMLVGETINFOTIP getInfoTip = (LPNMLVGETINFOTIP)header; - HWND lvHandle; - PTHREAD_STACK_CONTEXT threadStackContext; + PPH_EMENU menu; + PPH_STACK_TREE_ROOT_NODE selectedNode; + PPH_EMENU_ITEM selectedItem; + PPH_TREENEW_CONTEXT_MENU contextMenuEvent = (PPH_TREENEW_CONTEXT_MENU)lParam; - lvHandle = GetDlgItem(hwndDlg, IDC_LIST); - threadStackContext = (PTHREAD_STACK_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom()); - - if (header->hwndFrom == lvHandle) + if (selectedNode = GetSelectedThreadStackNode(context)) { - PTHREAD_STACK_ITEM stackItem; - PPH_THREAD_STACK_FRAME stackFrame; - - if (PhGetListViewItemParam(lvHandle, getInfoTip->iItem, &stackItem)) + menu = PhCreateEMenu(); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, IDC_COPY, L"Copy", NULL, NULL), -1); + PhInsertCopyCellEMenuItem(menu, IDC_COPY, context->TreeNewHandle, contextMenuEvent->Column); + + selectedItem = PhShowEMenu( + menu, + hwndDlg, + PH_EMENU_SHOW_LEFTRIGHT, + PH_ALIGN_LEFT | PH_ALIGN_TOP, + contextMenuEvent->Location.x, + contextMenuEvent->Location.y + ); + + if (selectedItem && selectedItem->Id != -1) { - PH_STRING_BUILDER stringBuilder; - PPH_STRING fileName; - PH_SYMBOL_LINE_INFORMATION lineInfo; - - stackFrame = &stackItem->StackFrame; - PhInitializeStringBuilder(&stringBuilder, 40); - - PhAppendFormatStringBuilder( - &stringBuilder, - L"Stack: 0x%Ix, Frame: 0x%Ix\n", - stackFrame->StackAddress, - stackFrame->FrameAddress - ); - - // There are no params for kernel-mode stack traces. - if ((ULONG_PTR)stackFrame->PcAddress <= PhSystemBasicInformation.MaximumUserModeAddress) - { - PhAppendFormatStringBuilder( - &stringBuilder, - L"Parameters: 0x%Ix, 0x%Ix, 0x%Ix, 0x%Ix\n", - stackFrame->Params[0], - stackFrame->Params[1], - stackFrame->Params[2], - stackFrame->Params[3] - ); - } - - if (PhGetLineFromAddress( - threadStackContext->SymbolProvider, - (ULONG64)stackFrame->PcAddress, - &fileName, - NULL, - &lineInfo - )) - { - PhAppendFormatStringBuilder( - &stringBuilder, - L"File: %s: line %u\n", - fileName->Buffer, - lineInfo.LineNumber - ); - PhDereferenceObject(fileName); - } - - if (stringBuilder.String->Length != 0) - PhRemoveEndStringBuilder(&stringBuilder, 1); - - if (PhPluginsEnabled) - { - PH_PLUGIN_THREAD_STACK_CONTROL control; - - control.Type = PluginThreadStackGetTooltip; - control.UniqueKey = threadStackContext; - control.u.GetTooltip.StackFrame = stackFrame; - control.u.GetTooltip.StringBuilder = &stringBuilder; - PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackThreadStackControl), &control); - } - - PhCopyListViewInfoTip(getInfoTip, &stringBuilder.String->sr); - PhDeleteStringBuilder(&stringBuilder); + BOOLEAN handled = FALSE; + + handled = PhHandleCopyCellEMenuItem(selectedItem); } + + PhDestroyEMenu(menu); } } break; @@ -411,10 +899,7 @@ static INT_PTR CALLBACK PhpThreadStackDlgProc( break; case WM_SIZE: { - PPH_LAYOUT_MANAGER layoutManager; - - layoutManager = (PPH_LAYOUT_MANAGER)GetProp(hwndDlg, L"LayoutManager"); - PhLayoutManagerLayout(layoutManager); + PhLayoutManagerLayout(&context->LayoutManager); } break; case WM_SIZING: @@ -437,89 +922,76 @@ static VOID PhpFreeThreadStackItem( static NTSTATUS PhpRefreshThreadStack( _In_ HWND hwnd, - _In_ PTHREAD_STACK_CONTEXT ThreadStackContext + _In_ PPH_THREAD_STACK_CONTEXT Context ) { ULONG i; - ThreadStackContext->StopWalk = FALSE; - PhMoveReference(&ThreadStackContext->StatusMessage, PhCreateString(L"Loading stack...")); + Context->StopWalk = FALSE; + PhMoveReference(&Context->StatusMessage, PhCreateString(L"Loading stack...")); DialogBoxParam( PhInstanceHandle, MAKEINTRESOURCE(IDD_PROGRESS), hwnd, PhpThreadStackProgressDlgProc, - (LPARAM)ThreadStackContext + (LPARAM)Context ); - if (!ThreadStackContext->StopWalk && NT_SUCCESS(ThreadStackContext->WalkStatus)) + if (!Context->StopWalk && NT_SUCCESS(Context->WalkStatus)) { - for (i = 0; i < ThreadStackContext->List->Count; i++) - PhpFreeThreadStackItem(ThreadStackContext->List->Items[i]); + for (i = 0; i < Context->List->Count; i++) + PhpFreeThreadStackItem(Context->List->Items[i]); - PhDereferenceObject(ThreadStackContext->List); - ThreadStackContext->List = ThreadStackContext->NewList; - ThreadStackContext->NewList = PhCreateList(10); + PhDereferenceObject(Context->List); + Context->List = Context->NewList; + Context->NewList = PhCreateList(10); - SendMessage(ThreadStackContext->ListViewHandle, WM_SETREDRAW, FALSE, 0); - ListView_DeleteAllItems(ThreadStackContext->ListViewHandle); + ClearThreadStackTree(Context); - for (i = 0; i < ThreadStackContext->List->Count; i++) + for (i = 0; i < Context->List->Count; i++) { - PTHREAD_STACK_ITEM item = ThreadStackContext->List->Items[i]; - INT lvItemIndex; - WCHAR integerString[PH_INT32_STR_LEN_1]; - WCHAR addressString[PH_PTR_STR_LEN_1]; + PTHREAD_STACK_ITEM item = Context->List->Items[i]; + PPH_STACK_TREE_ROOT_NODE stackNode; - PhPrintUInt32(integerString, item->Index); - lvItemIndex = PhAddListViewItem(ThreadStackContext->ListViewHandle, MAXINT, integerString, item); - PhSetListViewSubItem(ThreadStackContext->ListViewHandle, lvItemIndex, 1, PhGetStringOrDefault(item->Symbol, L"???")); + stackNode = AddThreadStackNode(Context, item->Index); + stackNode->StackFrame = item->StackFrame; - PhPrintPointer(addressString, item->StackFrame.StackAddress); - PhSetListViewSubItem(ThreadStackContext->ListViewHandle, lvItemIndex, 2, addressString); + if (!PhIsNullOrEmptyString(item->Symbol)) + stackNode->SymbolString = PhReferenceObject(item->Symbol); - PhPrintPointer(addressString, item->StackFrame.FrameAddress); - PhSetListViewSubItem(ThreadStackContext->ListViewHandle, lvItemIndex, 3, addressString); + PhPrintPointer(stackNode->StackAddressString, item->StackFrame.StackAddress); + PhPrintPointer(stackNode->FrameAddressString, item->StackFrame.FrameAddress); // There are no params for kernel-mode stack traces. if ((ULONG_PTR)item->StackFrame.PcAddress <= PhSystemBasicInformation.MaximumUserModeAddress) { - PhPrintPointer(addressString, item->StackFrame.Params[0]); - PhSetListViewSubItem(ThreadStackContext->ListViewHandle, lvItemIndex, 4, addressString); - - PhPrintPointer(addressString, item->StackFrame.Params[1]); - PhSetListViewSubItem(ThreadStackContext->ListViewHandle, lvItemIndex, 5, addressString); - - PhPrintPointer(addressString, item->StackFrame.Params[2]); - PhSetListViewSubItem(ThreadStackContext->ListViewHandle, lvItemIndex, 6, addressString); - - PhPrintPointer(addressString, item->StackFrame.Params[3]); - PhSetListViewSubItem(ThreadStackContext->ListViewHandle, lvItemIndex, 7, addressString); + PhPrintPointer(stackNode->Parameter1String, item->StackFrame.Params[0]); + PhPrintPointer(stackNode->Parameter2String, item->StackFrame.Params[1]); + PhPrintPointer(stackNode->Parameter3String, item->StackFrame.Params[2]); + PhPrintPointer(stackNode->Parameter4String, item->StackFrame.Params[3]); } - PhPrintPointer(addressString, item->StackFrame.PcAddress); - PhSetListViewSubItem(ThreadStackContext->ListViewHandle, lvItemIndex, 8, addressString); + PhPrintPointer(stackNode->PcAddressString, item->StackFrame.PcAddress); + PhPrintPointer(stackNode->ReturnAddressString, item->StackFrame.ReturnAddress); - PhPrintPointer(addressString, item->StackFrame.ReturnAddress); - PhSetListViewSubItem(ThreadStackContext->ListViewHandle, lvItemIndex, 9, addressString); + UpdateThreadStackNode(Context, stackNode); } - SendMessage(ThreadStackContext->ListViewHandle, WM_SETREDRAW, TRUE, 0); - InvalidateRect(ThreadStackContext->ListViewHandle, NULL, FALSE); + TreeNew_NodesStructured(Context->TreeNewHandle); } else { - for (i = 0; i < ThreadStackContext->NewList->Count; i++) - PhpFreeThreadStackItem(ThreadStackContext->NewList->Items[i]); + for (i = 0; i < Context->NewList->Count; i++) + PhpFreeThreadStackItem(Context->NewList->Items[i]); - PhClearList(ThreadStackContext->NewList); + PhClearList(Context->NewList); } - if (ThreadStackContext->StopWalk) + if (Context->StopWalk) return STATUS_ABANDONED; - return ThreadStackContext->WalkStatus; + return Context->WalkStatus; } static BOOLEAN NTAPI PhpWalkThreadStackCallback( @@ -527,7 +999,7 @@ static BOOLEAN NTAPI PhpWalkThreadStackCallback( _In_opt_ PVOID Context ) { - PTHREAD_STACK_CONTEXT threadStackContext = (PTHREAD_STACK_CONTEXT)Context; + PPH_THREAD_STACK_CONTEXT threadStackContext = (PPH_THREAD_STACK_CONTEXT)Context; PPH_STRING symbol; PTHREAD_STACK_ITEM item; @@ -585,7 +1057,7 @@ static NTSTATUS PhpRefreshThreadStackThreadStart( { PH_AUTO_POOL autoPool; NTSTATUS status; - PTHREAD_STACK_CONTEXT threadStackContext = Parameter; + PPH_THREAD_STACK_CONTEXT threadStackContext = Parameter; CLIENT_ID clientId; BOOLEAN defaultWalk; @@ -664,24 +1136,36 @@ static INT_PTR CALLBACK PhpThreadStackProgressDlgProc( _In_ LPARAM lParam ) { + PPH_THREAD_STACK_CONTEXT context; + + if (uMsg == WM_INITDIALOG) + { + context = (PPH_THREAD_STACK_CONTEXT)lParam; + SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)context); + } + else + { + context = (PPH_THREAD_STACK_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom()); + } + + if (!context) + return FALSE; + switch (uMsg) { case WM_INITDIALOG: { - PTHREAD_STACK_CONTEXT threadStackContext; HANDLE threadHandle; - threadStackContext = (PTHREAD_STACK_CONTEXT)lParam; - SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)threadStackContext); - threadStackContext->ProgressWindowHandle = hwndDlg; - - if (threadHandle = PhCreateThread(0, PhpRefreshThreadStackThreadStart, threadStackContext)) + context->ProgressWindowHandle = hwndDlg; + + if (threadHandle = PhCreateThread(0, PhpRefreshThreadStackThreadStart, context)) { NtClose(threadHandle); } else { - threadStackContext->WalkStatus = STATUS_UNSUCCESSFUL; + context->WalkStatus = STATUS_UNSUCCESSFUL; EndDialog(hwndDlg, IDOK); break; } @@ -704,10 +1188,8 @@ static INT_PTR CALLBACK PhpThreadStackProgressDlgProc( { case IDCANCEL: { - PTHREAD_STACK_CONTEXT threadStackContext = (PTHREAD_STACK_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom()); - EnableWindow(GetDlgItem(hwndDlg, IDCANCEL), FALSE); - threadStackContext->StopWalk = TRUE; + context->StopWalk = TRUE; } break; } @@ -720,13 +1202,12 @@ static INT_PTR CALLBACK PhpThreadStackProgressDlgProc( break; case WM_PH_STATUS_UPDATE: { - PTHREAD_STACK_CONTEXT threadStackContext = (PTHREAD_STACK_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom()); PPH_STRING message; - PhAcquireQueuedLockExclusive(&threadStackContext->StatusLock); - message = threadStackContext->StatusMessage; + PhAcquireQueuedLockExclusive(&context->StatusLock); + message = context->StatusMessage; PhReferenceObject(message); - PhReleaseQueuedLockExclusive(&threadStackContext->StatusLock); + PhReleaseQueuedLockExclusive(&context->StatusLock); SetDlgItemText(hwndDlg, IDC_PROGRESSTEXT, message->Buffer); PhDereferenceObject(message); @@ -734,5 +1215,5 @@ static INT_PTR CALLBACK PhpThreadStackProgressDlgProc( break; } - return 0; + return FALSE; } From 4c0c64c9ae8be3efc3faeff051fa382178eb72b6 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 30 Jul 2017 05:56:10 +1000 Subject: [PATCH 0314/2058] Fix thread stack right-click menu --- ProcessHacker/thrdstk.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ProcessHacker/thrdstk.c b/ProcessHacker/thrdstk.c index 6406cbdad01a..a86ac5b96b91 100644 --- a/ProcessHacker/thrdstk.c +++ b/ProcessHacker/thrdstk.c @@ -877,7 +877,7 @@ static INT_PTR CALLBACK PhpThreadStackDlgProc( selectedItem = PhShowEMenu( menu, hwndDlg, - PH_EMENU_SHOW_LEFTRIGHT, + PH_EMENU_SHOW_SEND_COMMAND | PH_EMENU_SHOW_LEFTRIGHT, PH_ALIGN_LEFT | PH_ALIGN_TOP, contextMenuEvent->Location.x, contextMenuEvent->Location.y From 752940005eaf82d19766a173a37a4e31910e5948 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 30 Jul 2017 16:56:57 +1000 Subject: [PATCH 0315/2058] Fix thread stack memory leak --- ProcessHacker/thrdstk.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ProcessHacker/thrdstk.c b/ProcessHacker/thrdstk.c index a86ac5b96b91..fb0142ba6a31 100644 --- a/ProcessHacker/thrdstk.c +++ b/ProcessHacker/thrdstk.c @@ -257,6 +257,8 @@ VOID DestroyThreadStackNode( _In_ PPH_STACK_TREE_ROOT_NODE Node ) { + PhClearReference(&Node->TooltipText); + PhClearReference(&Node->IndexString); PhClearReference(&Node->SymbolString); PhDereferenceObject(Node); From 0512933f407e95ef28ebe3360eed84de9f36f697 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 30 Jul 2017 18:31:41 +1000 Subject: [PATCH 0316/2058] OnlineChecks: Fix service right-click crash --- plugins/OnlineChecks/main.c | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/plugins/OnlineChecks/main.c b/plugins/OnlineChecks/main.c index a7ec2e294b99..dc1ee8297a9d 100644 --- a/plugins/OnlineChecks/main.c +++ b/plugins/OnlineChecks/main.c @@ -346,15 +346,24 @@ VOID NTAPI ServiceMenuInitializingCallback( else serviceItem = NULL; - QueryServiceFileName( - &serviceItem->Name->sr, - &serviceFileName, - &serviceBinaryPath - ); + if (serviceItem) + { + QueryServiceFileName( + &serviceItem->Name->sr, + &serviceFileName, + &serviceBinaryPath + ); + } + + if (serviceBinaryPath) + PhDereferenceObject(serviceBinaryPath); - if (serviceBinaryPath) PhDereferenceObject(serviceBinaryPath); + if (serviceFileName) + { + // TODO: memory leak or possible use-after-free bug? + PhAutoDereferenceObject(serviceFileName); + } - // TODO: Possible serviceFileName string memory leak. sendToMenu = CreateSendToMenu(menuInfo->Menu, serviceFileName ? serviceFileName : NULL); if (!serviceItem || !serviceFileName) From a948f9e98f28c1d6d68a89d572b6b0738cd3aebe Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 30 Jul 2017 18:37:07 +1000 Subject: [PATCH 0317/2058] Revert "NetworkTools: Fix string usage" This reverts commit 9d3b37aaf39f2ad3b8224552f201e1432d9a50f1. --- plugins/NetworkTools/tracetree.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/NetworkTools/tracetree.c b/plugins/NetworkTools/tracetree.c index 12aa70e1265c..fb4d6f55a818 100644 --- a/plugins/NetworkTools/tracetree.c +++ b/plugins/NetworkTools/tracetree.c @@ -223,7 +223,7 @@ VOID UpdateTracertNodePingText( PhFormatString(L"%s ms", PhaFormatUInt64(Node->PingList[Index], TRUE)->Buffer) ); - CellText->Text = PhGetStringRef(Node->PingString[Index]); + CellText->Text = Node->PingString[Index]->sr; } else { From 8c0f431c44ff7bd8a38543c19503860b2c5ba1b4 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 30 Jul 2017 18:37:53 +1000 Subject: [PATCH 0318/2058] Fix default thread stack columns --- ProcessHacker/thrdstk.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/ProcessHacker/thrdstk.c b/ProcessHacker/thrdstk.c index fb0142ba6a31..9674e6531cce 100644 --- a/ProcessHacker/thrdstk.c +++ b/ProcessHacker/thrdstk.c @@ -627,16 +627,16 @@ VOID InitializeThreadStackTree( TreeNew_SetCallback(Context->TreeNewHandle, ThreadStackTreeNewCallback, Context); - PhAddTreeNewColumn(Context->TreeNewHandle, PH_STACK_TREE_COLUMN_INDEX, TRUE, L"#", 30, PH_ALIGN_LEFT, PH_STACK_TREE_COLUMN_INDEX, 0); - PhAddTreeNewColumn(Context->TreeNewHandle, PH_STACK_TREE_COLUMN_SYMBOL, TRUE, L"Name", 250, PH_ALIGN_LEFT, PH_STACK_TREE_COLUMN_SYMBOL, 0); - PhAddTreeNewColumn(Context->TreeNewHandle, PH_STACK_TREE_COLUMN_STACKADDRESS, FALSE, L"Stack address", 100, PH_ALIGN_LEFT, PH_STACK_TREE_COLUMN_STACKADDRESS, 0); - PhAddTreeNewColumn(Context->TreeNewHandle, PH_STACK_TREE_COLUMN_FRAMEADDRESS, FALSE, L"Frame address", 100, PH_ALIGN_LEFT, PH_STACK_TREE_COLUMN_FRAMEADDRESS, 0); - PhAddTreeNewColumn(Context->TreeNewHandle, PH_STACK_TREE_COLUMN_PARAMETER1, FALSE, L"Stack parameter #1", 100, PH_ALIGN_LEFT, PH_STACK_TREE_COLUMN_PARAMETER1, 0); - PhAddTreeNewColumn(Context->TreeNewHandle, PH_STACK_TREE_COLUMN_PARAMETER2, FALSE, L"Stack parameter #2", 100, PH_ALIGN_LEFT, PH_STACK_TREE_COLUMN_PARAMETER2, 0); - PhAddTreeNewColumn(Context->TreeNewHandle, PH_STACK_TREE_COLUMN_PARAMETER3, FALSE, L"Stack parameter #3", 100, PH_ALIGN_LEFT, PH_STACK_TREE_COLUMN_PARAMETER3, 0); - PhAddTreeNewColumn(Context->TreeNewHandle, PH_STACK_TREE_COLUMN_PARAMETER4, FALSE, L"Stack parameter #4", 100, PH_ALIGN_LEFT, PH_STACK_TREE_COLUMN_PARAMETER4, 0); - PhAddTreeNewColumn(Context->TreeNewHandle, PH_STACK_TREE_COLUMN_CONTROLADDRESS, TRUE, L"Control address", 100, PH_ALIGN_LEFT, PH_STACK_TREE_COLUMN_CONTROLADDRESS, 0); - PhAddTreeNewColumn(Context->TreeNewHandle, PH_STACK_TREE_COLUMN_RETURNADDRESS, FALSE, L"Return address", 100, PH_ALIGN_LEFT, PH_STACK_TREE_COLUMN_RETURNADDRESS, 0); + PhAddTreeNewColumn(Context->TreeNewHandle, PH_STACK_TREE_COLUMN_INDEX, TRUE, L"#", 30, PH_ALIGN_LEFT, 0, 0); + PhAddTreeNewColumn(Context->TreeNewHandle, PH_STACK_TREE_COLUMN_SYMBOL, TRUE, L"Name", 250, PH_ALIGN_LEFT, 1, 0); + PhAddTreeNewColumn(Context->TreeNewHandle, PH_STACK_TREE_COLUMN_STACKADDRESS, FALSE, L"Stack address", 100, PH_ALIGN_LEFT, -1, 0); + PhAddTreeNewColumn(Context->TreeNewHandle, PH_STACK_TREE_COLUMN_FRAMEADDRESS, FALSE, L"Frame address", 100, PH_ALIGN_LEFT, -1, 0); + PhAddTreeNewColumn(Context->TreeNewHandle, PH_STACK_TREE_COLUMN_PARAMETER1, FALSE, L"Stack parameter #1", 100, PH_ALIGN_LEFT, -1, 0); + PhAddTreeNewColumn(Context->TreeNewHandle, PH_STACK_TREE_COLUMN_PARAMETER2, FALSE, L"Stack parameter #2", 100, PH_ALIGN_LEFT, -1, 0); + PhAddTreeNewColumn(Context->TreeNewHandle, PH_STACK_TREE_COLUMN_PARAMETER3, FALSE, L"Stack parameter #3", 100, PH_ALIGN_LEFT, -1, 0); + PhAddTreeNewColumn(Context->TreeNewHandle, PH_STACK_TREE_COLUMN_PARAMETER4, FALSE, L"Stack parameter #4", 100, PH_ALIGN_LEFT, -1, 0); + PhAddTreeNewColumn(Context->TreeNewHandle, PH_STACK_TREE_COLUMN_CONTROLADDRESS, FALSE, L"Control address", 100, PH_ALIGN_LEFT, -1, 0); + PhAddTreeNewColumn(Context->TreeNewHandle, PH_STACK_TREE_COLUMN_RETURNADDRESS, FALSE, L"Return address", 100, PH_ALIGN_LEFT, -1, 0); TreeNew_SetTriState(Context->TreeNewHandle, TRUE); From 62fc4d9e337e0ac13cfd66d28d03c7bb35df6cb3 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 30 Jul 2017 19:23:16 +1000 Subject: [PATCH 0319/2058] NetworkTools: Fix tracert crash --- plugins/NetworkTools/nettools.h | 3 ++- plugins/NetworkTools/tracert.c | 32 ++++++++++++++++++++++++++------ plugins/NetworkTools/tracert.h | 3 +-- plugins/NetworkTools/tracetree.c | 2 +- 4 files changed, 30 insertions(+), 10 deletions(-) diff --git a/plugins/NetworkTools/nettools.h b/plugins/NetworkTools/nettools.h index 106eb2849428..8e46673641d2 100644 --- a/plugins/NetworkTools/nettools.h +++ b/plugins/NetworkTools/nettools.h @@ -102,7 +102,8 @@ typedef enum _PH_NETWORK_ACTION #define NTM_RECEIVEDWHOIS (WM_APP + NETWORK_ACTION_WHOIS) #define NTM_RECEIVEDFINISH (WM_APP + NETWORK_ACTION_FINISH) #define WM_TRACERT_UPDATE (WM_APP + NETWORK_ACTION_TRACEROUTE + 1002) -#define WM_TRACERT_COUNTRY (WM_APP + NETWORK_ACTION_TRACEROUTE) +#define WM_TRACERT_HOSTNAME (WM_APP + NETWORK_ACTION_TRACEROUTE + 1003) +#define WM_TRACERT_COUNTRY (WM_APP + NETWORK_ACTION_TRACEROUTE + 1004) #define UPDATE_MENUITEM 1005 #define PH_UPDATEISERRORED (WM_APP + 501) diff --git a/plugins/NetworkTools/tracert.c b/plugins/NetworkTools/tracert.c index 62f39daef461..57bd18c03b4a 100644 --- a/plugins/NetworkTools/tracert.c +++ b/plugins/NetworkTools/tracert.c @@ -72,7 +72,7 @@ NTSTATUS TracertHostnameLookupCallback( NI_NAMEREQD )) { - PhMoveReference(&resolve->Node->HostnameString, PhCreateString(resolve->SocketAddressHostname)); + SendMessage(resolve->WindowHandle, WM_TRACERT_HOSTNAME, resolve->Index, (LPARAM)PhCreateString(resolve->SocketAddressHostname)); } else { @@ -100,7 +100,7 @@ NTSTATUS TracertHostnameLookupCallback( NI_NAMEREQD )) { - PhMoveReference(&resolve->Node->HostnameString, PhCreateString(resolve->SocketAddressHostname)); + SendMessage(resolve->WindowHandle, WM_TRACERT_HOSTNAME, resolve->Index, (LPARAM)PhCreateString(resolve->SocketAddressHostname)); } else { @@ -141,7 +141,7 @@ VOID TracertQueueHostLookup( if (NT_SUCCESS(RtlIpv4AddressToStringEx(&sockAddrIn, 0, addressString, &addressStringLength))) { - Node->IpAddressString = PhCreateString(addressString); + PhMoveReference(&Node->IpAddressString, PhCreateString(addressString)); } resolve = PhCreateAlloc(sizeof(TRACERT_RESOLVE_WORKITEM)); @@ -149,7 +149,7 @@ VOID TracertQueueHostLookup( resolve->Type = PH_IPV4_NETWORK_TYPE; resolve->WindowHandle = Context->WindowHandle; - resolve->Node = Node; + resolve->Index = Node->TTL; ((PSOCKADDR_IN)&resolve->SocketAddress)->sin_family = AF_INET; ((PSOCKADDR_IN)&resolve->SocketAddress)->sin_addr = sockAddrIn; @@ -176,7 +176,7 @@ VOID TracertQueueHostLookup( if (NT_SUCCESS(RtlIpv6AddressToStringEx(&sockAddrIn6, 0, 0, addressString, &addressStringLength))) { - Node->IpAddressString = PhCreateString(addressString); + PhMoveReference(&Node->IpAddressString, PhCreateString(addressString)); } resolve = PhCreateAlloc(sizeof(TRACERT_RESOLVE_WORKITEM)); @@ -184,7 +184,7 @@ VOID TracertQueueHostLookup( resolve->Type = PH_IPV6_NETWORK_TYPE; resolve->WindowHandle = Context->WindowHandle; - resolve->Node = Node; + resolve->Index = Node->TTL; ((PSOCKADDR_IN6)&resolve->SocketAddress)->sin6_family = AF_INET6; ((PSOCKADDR_IN6)&resolve->SocketAddress)->sin6_addr = sockAddrIn6; @@ -689,6 +689,26 @@ INT_PTR CALLBACK TracertDlgProc( TreeNew_NodesStructured(context->TreeNewHandle); } break; + case WM_TRACERT_HOSTNAME: + { + ULONG index = (ULONG)wParam; + PPH_STRING hostName = (PPH_STRING)lParam; + PTRACERT_ROOT_NODE traceNode; + + traceNode = FindTracertNode(context, index); + + if (traceNode) + { + PhMoveReference(&traceNode->HostnameString, hostName); + + UpdateTracertNode(context, traceNode); + } + else + { + PhDereferenceObject(hostName); + } + } + break; } return FALSE; diff --git a/plugins/NetworkTools/tracert.h b/plugins/NetworkTools/tracert.h index 27bcad79bd48..817a5f3f0c78 100644 --- a/plugins/NetworkTools/tracert.h +++ b/plugins/NetworkTools/tracert.h @@ -71,8 +71,7 @@ typedef struct _TRACERT_RESOLVE_WORKITEM SOCKADDR_STORAGE SocketAddress; HWND WindowHandle; - PTRACERT_ROOT_NODE Node; - + ULONG Index; WCHAR SocketAddressHostname[NI_MAXHOST]; } TRACERT_RESOLVE_WORKITEM, *PTRACERT_RESOLVE_WORKITEM; diff --git a/plugins/NetworkTools/tracetree.c b/plugins/NetworkTools/tracetree.c index fb4d6f55a818..12aa70e1265c 100644 --- a/plugins/NetworkTools/tracetree.c +++ b/plugins/NetworkTools/tracetree.c @@ -223,7 +223,7 @@ VOID UpdateTracertNodePingText( PhFormatString(L"%s ms", PhaFormatUInt64(Node->PingList[Index], TRUE)->Buffer) ); - CellText->Text = Node->PingString[Index]->sr; + CellText->Text = PhGetStringRef(Node->PingString[Index]); } else { From 584528246e08eb0ed347f658bf0a17dff8ce011b Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 30 Jul 2017 19:49:46 +1000 Subject: [PATCH 0320/2058] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 178bf550becd..c677a1505a6c 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ A free, powerful, multi-purpose tool that helps you monitor system resources, debug software and detect malware. -[![Build status](https://ci.appveyor.com/api/projects/status/5einmgmy3mnsfjdn?svg=true)](https://ci.appveyor.com/project/pbatard/rufus) +[![Build status](https://ci.appveyor.com/api/projects/status/5einmgmy3mnsfjdn?svg=true)](https://ci.appveyor.com/project/processhacker/processhacker2) [![Licence](https://img.shields.io/badge/license-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0.en.html) ![Logo](https://raw.githubusercontent.com/processhacker2/processhacker/master/ProcessHacker/resources/ProcessHacker.png) From b3e28b17c954b7cc1254dc504bceb4e21e4d1dec Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 30 Jul 2017 19:55:36 +1000 Subject: [PATCH 0321/2058] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index c677a1505a6c..8b33bb795fa4 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,7 @@ A free, powerful, multi-purpose tool that helps you monitor system resources, de * [Official Website](http://processhacker.sourceforge.net/) * [FAQ](http://processhacker.sourceforge.net/faq.php) +* [Nightly Builds](https://wj32.org/processhacker/nightly.php) ## System requirements From 83bb1b650319ba66f9c9a0488f604e8d894a51b9 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 31 Jul 2017 10:30:03 +1000 Subject: [PATCH 0322/2058] Enable advanced security dialog for Win8 and Srv2012 by default --- phlib/secedit.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phlib/secedit.c b/phlib/secedit.c index 65057fae144d..24bd903c867a 100644 --- a/phlib/secedit.c +++ b/phlib/secedit.c @@ -118,7 +118,7 @@ VOID PhEditSecurity( FALSE ); - if (WindowsVersion >= WINDOWS_8_1 && PhGetIntegerSetting(L"EnableSecurityAdvancedDialog")) + if (WindowsVersion >= WINDOWS_8 && PhGetIntegerSetting(L"EnableSecurityAdvancedDialog")) EditSecurityAdvanced(hWnd, info, COMBINE_PAGE_ACTIVATION(SI_PAGE_PERM, SI_SHOW_PERM_ACTIVATED)); else EditSecurity(hWnd, info); From 72d2f606ba20554a34ac241d2ae03f1b7e38e69a Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 31 Jul 2017 11:00:38 +1000 Subject: [PATCH 0323/2058] ToolStatus: Fix searching waiting/unknown network connections --- plugins/ToolStatus/filter.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/plugins/ToolStatus/filter.c b/plugins/ToolStatus/filter.c index 4a20fa9d329b..cd8a92ccd31c 100644 --- a/plugins/ToolStatus/filter.c +++ b/plugins/ToolStatus/filter.c @@ -473,16 +473,49 @@ BOOLEAN ServiceTreeFilterCallback( return FALSE; } +// copied from ProcessHacker\netlist.c.. +static PPH_STRING PhpNetworkTreeGetNetworkItemProcessName( + _In_ PPH_NETWORK_ITEM NetworkItem + ) +{ + PH_FORMAT format[4]; + + if (!NetworkItem->ProcessId) + return PhaCreateString(L"Waiting connections"); + + PhInitFormatS(&format[1], L" ("); + PhInitFormatU(&format[2], HandleToUlong(NetworkItem->ProcessId)); + PhInitFormatC(&format[3], ')'); + + if (NetworkItem->ProcessName) + PhInitFormatSR(&format[0], NetworkItem->ProcessName->sr); + else + PhInitFormatS(&format[0], L"Unknown process"); + + return PH_AUTO(PhFormat(format, 4, 96)); +} + BOOLEAN NetworkTreeFilterCallback( _In_ PPH_TREENEW_NODE Node, _In_opt_ PVOID Context ) { PPH_NETWORK_NODE networkNode = (PPH_NETWORK_NODE)Node; + PPH_STRING processNameText; if (PhIsNullOrEmptyString(SearchboxText)) return TRUE; + // TODO: We need export the PPH_NETWORK_NODE->ProcessNameText field to search + // waiting/unknown network connections... For now just replicate the data here. + processNameText = PhpNetworkTreeGetNetworkItemProcessName(networkNode->NetworkItem); + + if (!PhIsNullOrEmptyString(processNameText)) + { + if (WordMatchStringRef(&processNameText->sr)) + return TRUE; + } + if (!PhIsNullOrEmptyString(networkNode->NetworkItem->ProcessName)) { if (WordMatchStringRef(&networkNode->NetworkItem->ProcessName->sr)) From 9961e1c141dea7b0b0d52cfb77e7192c5e3cdfdf Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 31 Jul 2017 15:03:16 +1000 Subject: [PATCH 0324/2058] Add OriginalFileName to the PhEnumGenericModules callbacks --- phlib/include/phnative.h | 1 + phlib/native.c | 12 ++++++------ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/phlib/include/phnative.h b/phlib/include/phnative.h index 7b9d0baa713c..c5a60e72b0c6 100644 --- a/phlib/include/phnative.h +++ b/phlib/include/phnative.h @@ -842,6 +842,7 @@ typedef struct _PH_MODULE_INFO ULONG Flags; PPH_STRING Name; PPH_STRING FileName; + PPH_STRING OriginalFileName; USHORT LoadOrderIndex; // -1 if N/A USHORT LoadCount; // -1 if N/A diff --git a/phlib/native.c b/phlib/native.c index 03c4812f065e..a567ac5dad0e 100644 --- a/phlib/native.c +++ b/phlib/native.c @@ -5157,6 +5157,7 @@ static BOOLEAN EnumGenericProcessModulesCallback( moduleInfo.Flags = Module->Flags; moduleInfo.Name = PhCreateStringFromUnicodeString(&Module->BaseDllName); moduleInfo.FileName = PhGetFileName(fileName); + moduleInfo.OriginalFileName = fileName; moduleInfo.LoadOrderIndex = (USHORT)(context->LoadOrderIndex++); moduleInfo.LoadCount = Module->ObsoleteLoadCount; @@ -5171,12 +5172,11 @@ static BOOLEAN EnumGenericProcessModulesCallback( moduleInfo.LoadTime.QuadPart = 0; } - PhDereferenceObject(fileName); - cont = context->Callback(&moduleInfo, context->Context); PhDereferenceObject(moduleInfo.Name); PhDereferenceObject(moduleInfo.FileName); + PhDereferenceObject(moduleInfo.OriginalFileName); return cont; } @@ -5222,13 +5222,12 @@ VOID PhpRtlModulesToGenericModules( moduleInfo.Flags = module->Flags; moduleInfo.Name = PhConvertMultiByteToUtf16(&module->FullPathName[module->OffsetToFileName]); moduleInfo.FileName = PhGetFileName(fileName); // convert to DOS file name + moduleInfo.OriginalFileName = fileName; moduleInfo.LoadOrderIndex = module->LoadOrderIndex; moduleInfo.LoadCount = module->LoadCount; moduleInfo.LoadReason = -1; moduleInfo.LoadTime.QuadPart = 0; - PhDereferenceObject(fileName); - if (module->OffsetToFileName == 0) { static PH_STRINGREF driversString = PH_STRINGREF_INIT(L"\\System32\\Drivers\\"); @@ -5247,6 +5246,7 @@ VOID PhpRtlModulesToGenericModules( PhDereferenceObject(moduleInfo.Name); PhDereferenceObject(moduleInfo.FileName); + PhDereferenceObject(moduleInfo.OriginalFileName); if (!cont) break; @@ -5331,6 +5331,7 @@ BOOLEAN PhpCallbackMappedFileOrImage( moduleInfo.EntryPoint = NULL; moduleInfo.Flags = 0; moduleInfo.FileName = PhGetFileName(FileName); + moduleInfo.OriginalFileName = FileName; moduleInfo.Name = PhGetBaseName(moduleInfo.FileName); moduleInfo.LoadOrderIndex = -1; moduleInfo.LoadCount = -1; @@ -5340,6 +5341,7 @@ BOOLEAN PhpCallbackMappedFileOrImage( cont = Callback(&moduleInfo, Context); PhDereferenceObject(moduleInfo.FileName); + PhDereferenceObject(moduleInfo.OriginalFileName); PhDereferenceObject(moduleInfo.Name); return cont; @@ -5446,8 +5448,6 @@ VOID PhpEnumGenericMappedFilesAndImages( BaseAddressHashtable ); - PhDereferenceObject(fileName); - if (!cont) break; } From b0f6fb012796b911a63b470d5a219df0978ddcae Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 31 Jul 2017 15:39:47 +1000 Subject: [PATCH 0325/2058] Rewrite find handle window: Add treelist control, Add column customization, Add right-click menu, Add column sorting --- ProcessHacker/ProcessHacker.rc | 3 +- ProcessHacker/findobj.c | 1921 ++++++++++++++++++++------------ ProcessHacker/settings.c | 2 +- 3 files changed, 1213 insertions(+), 713 deletions(-) diff --git a/ProcessHacker/ProcessHacker.rc b/ProcessHacker/ProcessHacker.rc index 2261c520d25c..01037698009a 100644 --- a/ProcessHacker/ProcessHacker.rc +++ b/ProcessHacker/ProcessHacker.rc @@ -360,6 +360,7 @@ BEGIN MENUITEM SEPARATOR MENUITEM "Go to owning &process", ID_OBJECT_GOTOOWNINGPROCESS MENUITEM "Prope&rties", ID_OBJECT_PROPERTIES + MENUITEM SEPARATOR MENUITEM "&Copy\aCtrl+C", ID_OBJECT_COPY END END @@ -727,7 +728,7 @@ BEGIN LTEXT "Filter:",IDC_STATIC,7,7,19,8 EDITTEXT IDC_FILTER,29,4,134,13,ES_AUTOHSCROLL PUSHBUTTON "Find",IDOK,301,3,50,14 - CONTROL "",IDC_RESULTS,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,2,21,353,210 + CONTROL "",IDC_TREELIST,"PhTreeNew",WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP | 0x2,2,19,353,212,WS_EX_CLIENTEDGE CONTROL "&Regex",IDC_REGEX,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,263,6,34,10 COMBOBOX IDC_FILTERTYPE,165,4,93,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP END diff --git a/ProcessHacker/findobj.c b/ProcessHacker/findobj.c index 602f39befab9..c3dbb4eb6f3b 100644 --- a/ProcessHacker/findobj.c +++ b/ProcessHacker/findobj.c @@ -25,11 +25,13 @@ #include +#include #include #include #include #include +#include #include #include #include @@ -39,8 +41,42 @@ #include "pcre/pcre2.h" -#define WM_PH_SEARCH_UPDATE (WM_APP + 801) +#define WM_PH_SEARCH_SHOWDIALOG (WM_APP + 801) #define WM_PH_SEARCH_FINISHED (WM_APP + 802) +#define WM_PH_SEARCH_SHOWMENU (WM_APP + 803) + +static HANDLE PhFindObjectsThreadHandle = NULL; +static HWND PhFindObjectsWindowHandle = NULL; +static PH_EVENT PhFindObjectsInitializedEvent = PH_EVENT_INIT; + +typedef struct _PH_HANDLE_SEARCH_CONTEXT +{ + PH_LAYOUT_MANAGER LayoutManager; + RECT MinimumSize; + + HWND WindowHandle; + HWND TreeNewHandle; + ULONG TreeNewSortColumn; + PH_SORT_ORDER TreeNewSortOrder; + PPH_HASHTABLE NodeHashtable; + PPH_LIST NodeList; + PPH_LIST NodeRootList; + + HANDLE TimerQueueHandle; + HANDLE UpdateTimerHandle; + HANDLE SearchThreadHandle; + + BOOLEAN SearchStop; + PPH_STRING SearchString; + PPH_STRING SearchTypeString; + pcre2_code *SearchRegexCompiledExpression; + pcre2_match_data *SearchRegexMatchData; + PPH_LIST SearchResults; + ULONG SearchResultsAddIndex; + PH_QUEUED_LOCK SearchResultsLock; + ULONG64 SearchPointer; + BOOLEAN UseSearchPointer; +} PH_HANDLE_SEARCH_CONTEXT, *PPH_HANDLE_SEARCH_CONTEXT; typedef enum _PHP_OBJECT_RESULT_TYPE { @@ -55,153 +91,511 @@ typedef struct _PHP_OBJECT_SEARCH_RESULT PHP_OBJECT_RESULT_TYPE ResultType; HANDLE Handle; + PVOID Object; PPH_STRING TypeName; - PPH_STRING Name; - PPH_STRING ProcessName; - - WCHAR HandleString[PH_PTR_STR_LEN_1]; + PPH_STRING ObjectName; + PPH_STRING BestObjectName; SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX Info; } PHP_OBJECT_SEARCH_RESULT, *PPHP_OBJECT_SEARCH_RESULT; -INT_PTR CALLBACK PhpFindObjectsDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); +typedef enum _PH_HANDLE_OBJECT_TREE_COLUMN_ITEM_NAME +{ + PH_OBJECT_SEARCH_TREE_COLUMN_PROCESS, + PH_OBJECT_SEARCH_TREE_COLUMN_TYPE, + PH_OBJECT_SEARCH_TREE_COLUMN_NAME, + PH_OBJECT_SEARCH_TREE_COLUMN_HANDLE, + PH_OBJECT_SEARCH_TREE_COLUMN_OBJECTADDRESS, + PH_OBJECT_SEARCH_TREE_COLUMN_ORIGINALNAME, + TREE_COLUMN_ITEM_MAXIMUM +} PH_HANDLE_OBJECT_TREE_COLUMN_ITEM_NAME; + +typedef struct _PH_HANDLE_OBJECT_TREE_ROOT_NODE +{ + PH_TREENEW_NODE Node; -NTSTATUS PhpFindObjectsThreadStart( - _In_ PVOID Parameter - ); - -HWND PhFindObjectsWindowHandle = NULL; -HWND PhFindObjectsListViewHandle = NULL; -static PH_LAYOUT_MANAGER WindowLayoutManager; -static RECT MinimumSize; - -static HANDLE SearchThreadHandle = NULL; -static BOOLEAN SearchStop; -static PPH_STRING SearchString; -static PPH_STRING SearchTypeString; -static pcre2_code *SearchRegexCompiledExpression; -static pcre2_match_data *SearchRegexMatchData; -static PPH_LIST SearchResults = NULL; -static ULONG SearchResultsAddIndex; -static PH_QUEUED_LOCK SearchResultsLock = PH_QUEUED_LOCK_INIT; - -static ULONG64 SearchPointer; -static BOOLEAN UseSearchPointer; + PHP_OBJECT_RESULT_TYPE ResultType; + PVOID HandleObject; + HANDLE Handle; + HANDLE ProcessId; + PPH_STRING ClientIdName; + PPH_STRING TypeNameString; + PPH_STRING ObjectNameString; + PPH_STRING BestObjectName; + WCHAR HandleString[PH_PTR_STR_LEN_1]; + WCHAR ObjectString[PH_PTR_STR_LEN_1]; + + SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX HandleInfo; + + PH_STRINGREF TextCache[TREE_COLUMN_ITEM_MAXIMUM]; +} PH_HANDLE_OBJECT_TREE_ROOT_NODE, *PPH_HANDLE_OBJECT_TREE_ROOT_NODE; + +#define SORT_FUNCTION(Column) HandleObjectTreeNewCompare##Column +#define BEGIN_SORT_FUNCTION(Column) static int __cdecl HandleObjectTreeNewCompare##Column( \ + _In_ void *_context, \ + _In_ const void *_elem1, \ + _In_ const void *_elem2 \ + ) \ +{ \ + PPH_HANDLE_OBJECT_TREE_ROOT_NODE node1 = *(PPH_HANDLE_OBJECT_TREE_ROOT_NODE*)_elem1; \ + PPH_HANDLE_OBJECT_TREE_ROOT_NODE node2 = *(PPH_HANDLE_OBJECT_TREE_ROOT_NODE*)_elem2; \ + int sortResult = 0; + +#define END_SORT_FUNCTION \ + if (sortResult == 0) \ + sortResult = uintptrcmp((ULONG_PTR)node1->Node.Index, (ULONG_PTR)node2->Node.Index); \ + \ + return PhModifySort(sortResult, ((PPH_HANDLE_SEARCH_CONTEXT)_context)->TreeNewSortOrder); \ +} -VOID PhShowFindObjectsDialog( - VOID +BEGIN_SORT_FUNCTION(Process) +{ + sortResult = PhCompareString(node1->ClientIdName, node2->ClientIdName, TRUE); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(Type) +{ + sortResult = PhCompareString(node1->TypeNameString, node2->TypeNameString, TRUE); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(Name) +{ + sortResult = PhCompareString(node1->BestObjectName, node2->BestObjectName, TRUE); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(Handle) +{ + sortResult = uintptrcmp((ULONG_PTR)node1->Handle, (ULONG_PTR)node2->Handle); +} +END_SORT_FUNCTION + +VOID HandleObjectLoadSettingsTreeList( + _Inout_ PPH_HANDLE_SEARCH_CONTEXT Context ) { - if (!PhFindObjectsWindowHandle) - { - PhFindObjectsWindowHandle = CreateDialog( - PhInstanceHandle, - MAKEINTRESOURCE(IDD_FINDOBJECTS), - NULL, - PhpFindObjectsDlgProc - ); - } + PPH_STRING settings; + + settings = PhGetStringSetting(L"FindObjTreeListColumns"); + PhCmLoadSettings(Context->TreeNewHandle, &settings->sr); + PhDereferenceObject(settings); +} + +VOID HandleObjectSaveSettingsTreeList( + _Inout_ PPH_HANDLE_SEARCH_CONTEXT Context + ) +{ + PPH_STRING settings; + + settings = PhCmSaveSettings(Context->TreeNewHandle); + PhSetStringSetting2(L"FindObjTreeListColumns", &settings->sr); + PhDereferenceObject(settings); +} - if (!IsWindowVisible(PhFindObjectsWindowHandle)) - ShowWindow(PhFindObjectsWindowHandle, SW_SHOW); +BOOLEAN HandleObjectNodeHashtableEqualFunction( + _In_ PVOID Entry1, + _In_ PVOID Entry2 + ) +{ + PPH_HANDLE_OBJECT_TREE_ROOT_NODE node1 = *(PPH_HANDLE_OBJECT_TREE_ROOT_NODE *)Entry1; + PPH_HANDLE_OBJECT_TREE_ROOT_NODE node2 = *(PPH_HANDLE_OBJECT_TREE_ROOT_NODE *)Entry2; - SetForegroundWindow(PhFindObjectsWindowHandle); + return node1->HandleObject == node2->HandleObject; } -VOID PhpInitializeFindObjMenu( - _In_ PPH_EMENU Menu, - _In_ PPHP_OBJECT_SEARCH_RESULT *Results, - _In_ ULONG NumberOfResults +ULONG HandleObjectNodeHashtableHashFunction( + _In_ PVOID Entry ) { - BOOLEAN allCanBeClosed = TRUE; - ULONG i; + return PhHashIntPtr((ULONG_PTR)(*(PPH_HANDLE_OBJECT_TREE_ROOT_NODE*)Entry)->HandleObject); +} - if (NumberOfResults == 1) - { - PH_HANDLE_ITEM_INFO info; +VOID DestroyHandleObjectNode( + _In_ PPH_HANDLE_OBJECT_TREE_ROOT_NODE Node + ) +{ + PhClearReference(&Node->ClientIdName); + PhClearReference(&Node->TypeNameString); + PhClearReference(&Node->ObjectNameString); + PhClearReference(&Node->BestObjectName); - info.ProcessId = Results[0]->ProcessId; - info.Handle = Results[0]->Handle; - info.TypeName = Results[0]->TypeName; - info.BestObjectName = Results[0]->Name; - PhInsertHandleObjectPropertiesEMenuItems(Menu, ID_OBJECT_PROPERTIES, FALSE, &info); - } + PhDereferenceObject(Node); +} + +PPH_HANDLE_OBJECT_TREE_ROOT_NODE AddHandleObjectNode( + _Inout_ PPH_HANDLE_SEARCH_CONTEXT Context, + _In_ PVOID HandleObject, + _In_ HANDLE Handle + ) +{ + PPH_HANDLE_OBJECT_TREE_ROOT_NODE handleObjectNode; + + handleObjectNode = PhCreateAlloc(sizeof(PH_HANDLE_OBJECT_TREE_ROOT_NODE)); + memset(handleObjectNode, 0, sizeof(PH_HANDLE_OBJECT_TREE_ROOT_NODE)); + + PhInitializeTreeNewNode(&handleObjectNode->Node); + + memset(handleObjectNode->TextCache, 0, sizeof(PH_STRINGREF) * TREE_COLUMN_ITEM_MAXIMUM); + handleObjectNode->Node.TextCache = handleObjectNode->TextCache; + handleObjectNode->Node.TextCacheSize = TREE_COLUMN_ITEM_MAXIMUM; + + handleObjectNode->HandleObject = HandleObject; + handleObjectNode->Handle = Handle; + + PhAddEntryHashtable(Context->NodeHashtable, &handleObjectNode); + PhAddItemList(Context->NodeList, handleObjectNode); + + //TreeNew_NodesStructured(Context->TreeNewHandle); + + return handleObjectNode; +} + +PPH_HANDLE_OBJECT_TREE_ROOT_NODE FindHandleObjectNode( + _In_ PPH_HANDLE_SEARCH_CONTEXT Context, + _In_ PVOID HandleObject + ) +{ + PH_HANDLE_OBJECT_TREE_ROOT_NODE lookupHandleObjectNode; + PPH_HANDLE_OBJECT_TREE_ROOT_NODE lookupHandleObjectNodePtr = &lookupHandleObjectNode; + PPH_HANDLE_OBJECT_TREE_ROOT_NODE *handleObjectNode; + + lookupHandleObjectNode.HandleObject = HandleObject; + + handleObjectNode = (PPH_HANDLE_OBJECT_TREE_ROOT_NODE*)PhFindEntryHashtable( + Context->NodeHashtable, + &lookupHandleObjectNodePtr + ); + + if (handleObjectNode) + return *handleObjectNode; else + return NULL; +} + +VOID RemoveHandleObjectNode( + _In_ PPH_HANDLE_SEARCH_CONTEXT Context, + _In_ PPH_HANDLE_OBJECT_TREE_ROOT_NODE Node + ) +{ + ULONG index = 0; + + PhRemoveEntryHashtable(Context->NodeHashtable, &Node); + + if ((index = PhFindItemList(Context->NodeList, Node)) != -1) { - PhSetFlagsAllEMenuItems(Menu, PH_EMENU_DISABLED, PH_EMENU_DISABLED); - PhEnableEMenuItem(Menu, ID_OBJECT_COPY, TRUE); + PhRemoveItemList(Context->NodeList, index); } - for (i = 0; i < NumberOfResults; i++) + DestroyHandleObjectNode(Node); + TreeNew_NodesStructured(Context->TreeNewHandle); +} + +VOID UpdateHandleObjectNode( + _In_ PPH_HANDLE_SEARCH_CONTEXT Context, + _In_ PPH_HANDLE_OBJECT_TREE_ROOT_NODE Node + ) +{ + memset(Node->TextCache, 0, sizeof(PH_STRINGREF) * TREE_COLUMN_ITEM_MAXIMUM); + + PhInvalidateTreeNewNode(&Node->Node, TN_CACHE_COLOR); + TreeNew_NodesStructured(Context->TreeNewHandle); +} + +BOOLEAN NTAPI HandleObjectTreeNewCallback( + _In_ HWND hwnd, + _In_ PH_TREENEW_MESSAGE Message, + _In_opt_ PVOID Parameter1, + _In_opt_ PVOID Parameter2, + _In_opt_ PVOID Context + ) +{ + PPH_HANDLE_SEARCH_CONTEXT context = Context; + PPH_HANDLE_OBJECT_TREE_ROOT_NODE node; + + switch (Message) { - if (Results[i]->ResultType != HandleSearchResult) + case TreeNewGetChildren: { - allCanBeClosed = FALSE; - break; + PPH_TREENEW_GET_CHILDREN getChildren = Parameter1; + node = (PPH_HANDLE_OBJECT_TREE_ROOT_NODE)getChildren->Node; + + if (!getChildren->Node) + { + static PVOID sortFunctions[] = + { + SORT_FUNCTION(Process), + SORT_FUNCTION(Type), + SORT_FUNCTION(Name), + SORT_FUNCTION(Handle), + }; + int (__cdecl *sortFunction)(void *, const void *, const void *); + + if (context->TreeNewSortColumn < TREE_COLUMN_ITEM_MAXIMUM) + sortFunction = sortFunctions[context->TreeNewSortColumn]; + else + sortFunction = NULL; + + if (sortFunction) + { + qsort_s(context->NodeList->Items, context->NodeList->Count, sizeof(PVOID), sortFunction, context); + } + + getChildren->Children = (PPH_TREENEW_NODE *)context->NodeList->Items; + getChildren->NumberOfChildren = context->NodeList->Count; + } + } + return TRUE; + case TreeNewIsLeaf: + { + PPH_TREENEW_IS_LEAF isLeaf = (PPH_TREENEW_IS_LEAF)Parameter1; + node = (PPH_HANDLE_OBJECT_TREE_ROOT_NODE)isLeaf->Node; + + isLeaf->IsLeaf = TRUE; + } + return TRUE; + case TreeNewGetCellText: + { + PPH_TREENEW_GET_CELL_TEXT getCellText = (PPH_TREENEW_GET_CELL_TEXT)Parameter1; + node = (PPH_HANDLE_OBJECT_TREE_ROOT_NODE)getCellText->Node; + + switch (getCellText->Id) + { + case PH_OBJECT_SEARCH_TREE_COLUMN_PROCESS: + getCellText->Text = PhGetStringRef(node->ClientIdName); + break; + case PH_OBJECT_SEARCH_TREE_COLUMN_TYPE: + getCellText->Text = PhGetStringRef(node->TypeNameString); + break; + case PH_OBJECT_SEARCH_TREE_COLUMN_NAME: + getCellText->Text = PhGetStringRef(node->BestObjectName); + break; + case PH_OBJECT_SEARCH_TREE_COLUMN_HANDLE: + PhInitializeStringRefLongHint(&getCellText->Text, node->HandleString); + break; + case PH_OBJECT_SEARCH_TREE_COLUMN_OBJECTADDRESS: + PhInitializeStringRefLongHint(&getCellText->Text, node->ObjectString); + break; + case PH_OBJECT_SEARCH_TREE_COLUMN_ORIGINALNAME: + getCellText->Text = PhGetStringRef(node->ObjectNameString); + break; + default: + return FALSE; + } + + getCellText->Flags = TN_CACHE; + } + return TRUE; + case TreeNewGetNodeColor: + { + PPH_TREENEW_GET_NODE_COLOR getNodeColor = Parameter1; + node = (PPH_HANDLE_OBJECT_TREE_ROOT_NODE)getNodeColor->Node; + + getNodeColor->Flags = TN_CACHE | TN_AUTO_FORECOLOR; } + return TRUE; + case TreeNewSortChanged: + { + TreeNew_GetSort(hwnd, &context->TreeNewSortColumn, &context->TreeNewSortOrder); + // Force a rebuild to sort the items. + TreeNew_NodesStructured(hwnd); + } + return TRUE; + case TreeNewKeyDown: + { + PPH_TREENEW_KEY_EVENT keyEvent = Parameter1; + + switch (keyEvent->VirtualKey) + { + case 'C': + if (GetKeyState(VK_CONTROL) < 0) + SendMessage(context->WindowHandle, WM_COMMAND, ID_OBJECT_COPY, 0); + break; + case 'A': + if (GetKeyState(VK_CONTROL) < 0) + TreeNew_SelectRange(context->TreeNewHandle, 0, -1); + break; + case VK_DELETE: + SendMessage(context->WindowHandle, WM_COMMAND, ID_OBJECT_CLOSE, 0); + break; + } + } + return TRUE; + case TreeNewLeftDoubleClick: + { + SendMessage(context->WindowHandle, WM_COMMAND, ID_OBJECT_PROPERTIES, 0); + } + return TRUE; + case TreeNewContextMenu: + { + PPH_TREENEW_CONTEXT_MENU contextMenuEvent = Parameter1; + + SendMessage( + context->WindowHandle, + WM_COMMAND, + WM_PH_SEARCH_SHOWMENU, + (LPARAM)contextMenuEvent + ); + } + return TRUE; + case TreeNewHeaderRightClick: + { + PH_TN_COLUMN_MENU_DATA data; + + data.TreeNewHandle = hwnd; + data.MouseEvent = Parameter1; + data.DefaultSortColumn = 0; + data.DefaultSortOrder = AscendingSortOrder; + PhInitializeTreeNewColumnMenu(&data); + + data.Selection = PhShowEMenu(data.Menu, hwnd, PH_EMENU_SHOW_LEFTRIGHT, + PH_ALIGN_LEFT | PH_ALIGN_TOP, data.MouseEvent->ScreenLocation.x, data.MouseEvent->ScreenLocation.y); + PhHandleTreeNewColumnMenu(&data); + PhDeleteTreeNewColumnMenu(&data); + } + return TRUE; } - PhEnableEMenuItem(Menu, ID_OBJECT_CLOSE, allCanBeClosed); + return FALSE; } -INT NTAPI PhpObjectProcessCompareFunction( - _In_ PVOID Item1, - _In_ PVOID Item2, - _In_opt_ PVOID Context +VOID ClearHandleObjectTree( + _In_ PPH_HANDLE_SEARCH_CONTEXT Context ) { - PPHP_OBJECT_SEARCH_RESULT item1 = Item1; - PPHP_OBJECT_SEARCH_RESULT item2 = Item2; - INT result; + for (ULONG i = 0; i < Context->NodeList->Count; i++) + DestroyHandleObjectNode(Context->NodeList->Items[i]); - result = PhCompareStringWithNull(item1->ProcessName, item2->ProcessName, TRUE); + PhClearHashtable(Context->NodeHashtable); + PhClearList(Context->NodeList); - if (result != 0) - return result; - else - return uintptrcmp((ULONG_PTR)item1->ProcessId, (ULONG_PTR)item2->ProcessId); + TreeNew_NodesStructured(Context->TreeNewHandle); } -INT NTAPI PhpObjectTypeCompareFunction( - _In_ PVOID Item1, - _In_ PVOID Item2, - _In_opt_ PVOID Context +PPH_HANDLE_OBJECT_TREE_ROOT_NODE GetSelectedHandleObjectNode( + _In_ PPH_HANDLE_SEARCH_CONTEXT Context + ) +{ + PPH_HANDLE_OBJECT_TREE_ROOT_NODE windowNode = NULL; + + for (ULONG i = 0; i < Context->NodeList->Count; i++) + { + windowNode = Context->NodeList->Items[i]; + + if (windowNode->Node.Selected) + return windowNode; + } + + return NULL; +} + +VOID GetSelectedHandleObjectNodes( + _In_ PPH_HANDLE_SEARCH_CONTEXT Context, + _Out_ PPH_HANDLE_OBJECT_TREE_ROOT_NODE **HandleObjectNodes, + _Out_ PULONG NumberOfHandleObjectNodes ) { - PPHP_OBJECT_SEARCH_RESULT item1 = Item1; - PPHP_OBJECT_SEARCH_RESULT item2 = Item2; + PPH_LIST list; + + list = PhCreateList(2); + + for (ULONG i = 0; i < Context->NodeList->Count; i++) + { + PPH_HANDLE_OBJECT_TREE_ROOT_NODE node = (PPH_HANDLE_OBJECT_TREE_ROOT_NODE)Context->NodeList->Items[i]; - return PhCompareString(item1->TypeName, item2->TypeName, TRUE); + if (node->Node.Selected) + { + PhAddItemList(list, node); + } + } + + *HandleObjectNodes = PhAllocateCopy(list->Items, sizeof(PVOID) * list->Count); + *NumberOfHandleObjectNodes = list->Count; + + PhDereferenceObject(list); } -INT NTAPI PhpObjectNameCompareFunction( - _In_ PVOID Item1, - _In_ PVOID Item2, - _In_opt_ PVOID Context +VOID InitializeHandleObjectTree( + _Inout_ PPH_HANDLE_SEARCH_CONTEXT Context + ) +{ + Context->NodeList = PhCreateList(100); + Context->NodeHashtable = PhCreateHashtable( + sizeof(PPH_HANDLE_OBJECT_TREE_ROOT_NODE), + HandleObjectNodeHashtableEqualFunction, + HandleObjectNodeHashtableHashFunction, + 100 + ); + + PhSetControlTheme(Context->TreeNewHandle, L"explorer"); + + TreeNew_SetCallback(Context->TreeNewHandle, HandleObjectTreeNewCallback, Context); + + // Default columns + PhAddTreeNewColumn(Context->TreeNewHandle, PH_OBJECT_SEARCH_TREE_COLUMN_PROCESS, TRUE, L"Process", 100, PH_ALIGN_LEFT, 0, 0); + PhAddTreeNewColumn(Context->TreeNewHandle, PH_OBJECT_SEARCH_TREE_COLUMN_TYPE, TRUE, L"Type", 100, PH_ALIGN_LEFT, 1, 0); + PhAddTreeNewColumn(Context->TreeNewHandle, PH_OBJECT_SEARCH_TREE_COLUMN_NAME, TRUE, L"Name", 200, PH_ALIGN_LEFT, 2, 0); + PhAddTreeNewColumn(Context->TreeNewHandle, PH_OBJECT_SEARCH_TREE_COLUMN_HANDLE, TRUE, L"Handle", 80, PH_ALIGN_LEFT, 3, 0); + + PhAddTreeNewColumn(Context->TreeNewHandle, PH_OBJECT_SEARCH_TREE_COLUMN_OBJECTADDRESS, FALSE, L"Object address", 80, PH_ALIGN_LEFT, -1, 0); + PhAddTreeNewColumn(Context->TreeNewHandle, PH_OBJECT_SEARCH_TREE_COLUMN_ORIGINALNAME, FALSE, L"Original name", 200, PH_ALIGN_LEFT, -1, 0); + + TreeNew_SetTriState(Context->TreeNewHandle, TRUE); + + HandleObjectLoadSettingsTreeList(Context); +} + +VOID DeleteHandleObjectTree( + _In_ PPH_HANDLE_SEARCH_CONTEXT Context ) { - PPHP_OBJECT_SEARCH_RESULT item1 = Item1; - PPHP_OBJECT_SEARCH_RESULT item2 = Item2; + HandleObjectSaveSettingsTreeList(Context); - return PhCompareString(item1->Name, item2->Name, TRUE); + for (ULONG i = 0; i < Context->NodeList->Count; i++) + { + DestroyHandleObjectNode(Context->NodeList->Items[i]); + } + + PhDereferenceObject(Context->NodeHashtable); + PhDereferenceObject(Context->NodeList); } -INT NTAPI PhpObjectHandleCompareFunction( - _In_ PVOID Item1, - _In_ PVOID Item2, - _In_opt_ PVOID Context +VOID PhpInitializeFindObjMenu( + _In_ PPH_EMENU Menu, + _In_ PPH_HANDLE_OBJECT_TREE_ROOT_NODE *Results, + _In_ ULONG NumberOfResults ) { - PPHP_OBJECT_SEARCH_RESULT item1 = Item1; - PPHP_OBJECT_SEARCH_RESULT item2 = Item2; + BOOLEAN allCanBeClosed = TRUE; + ULONG i; + + if (NumberOfResults == 1) + { + PH_HANDLE_ITEM_INFO info; + + info.ProcessId = Results[0]->ProcessId; + info.Handle = Results[0]->Handle; + info.TypeName = Results[0]->TypeNameString; + info.BestObjectName = Results[0]->BestObjectName; + PhInsertHandleObjectPropertiesEMenuItems(Menu, ID_OBJECT_PROPERTIES, FALSE, &info); + } + else + { + PhSetFlagsAllEMenuItems(Menu, PH_EMENU_DISABLED, PH_EMENU_DISABLED); + PhEnableEMenuItem(Menu, ID_OBJECT_COPY, TRUE); + } + + for (i = 0; i < NumberOfResults; i++) + { + if (Results[i]->ResultType != HandleSearchResult) + { + allCanBeClosed = FALSE; + break; + } + } - return uintptrcmp((ULONG_PTR)item1->Handle, (ULONG_PTR)item2->Handle); + PhEnableEMenuItem(Menu, ID_OBJECT_CLOSE, allCanBeClosed); } static int __cdecl PhpStringObjectTypeCompare( @@ -215,7 +609,7 @@ static int __cdecl PhpStringObjectTypeCompare( return PhCompareString(entry1, entry2, TRUE); } -static VOID PhpPopulateObjectTypes( +VOID PhpPopulateObjectTypes( _In_ HWND FilterTypeCombo ) { @@ -256,89 +650,581 @@ static VOID PhpPopulateObjectTypes( PhDereferenceObject(objectTypeList); } -static INT_PTR CALLBACK PhpFindObjectsDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam +VOID PhpFindObjectAddResultEntries( + _In_ PPH_HANDLE_SEARCH_CONTEXT Context ) { - switch (uMsg) + ULONG i; + + TreeNew_SetRedraw(Context->TreeNewHandle, FALSE); + + PhAcquireQueuedLockExclusive(&Context->SearchResultsLock); + + for (i = Context->SearchResultsAddIndex; i < Context->SearchResults->Count; i++) { - case WM_INITDIALOG: - { - HWND lvHandle; + PPHP_OBJECT_SEARCH_RESULT searchResult = Context->SearchResults->Items[i]; + CLIENT_ID clientId; + PPH_PROCESS_ITEM processItem; + PPH_HANDLE_OBJECT_TREE_ROOT_NODE objectNode; + + clientId.UniqueProcess = searchResult->ProcessId; + clientId.UniqueThread = NULL; + + processItem = PhReferenceProcessItem(clientId.UniqueProcess); + + objectNode = AddHandleObjectNode(Context, searchResult->Object, searchResult->Handle); + objectNode->ProcessId = searchResult->ProcessId; + objectNode->ResultType = searchResult->ResultType; + objectNode->ClientIdName = PhGetClientIdNameEx(&clientId, processItem ? processItem->ProcessName : NULL); + objectNode->TypeNameString = searchResult->TypeName; + objectNode->ObjectNameString = searchResult->ObjectName; + objectNode->BestObjectName = searchResult->BestObjectName; + objectNode->HandleInfo = searchResult->Info; + PhPrintPointer(objectNode->HandleString, searchResult->Handle); + + if (searchResult->Object) + PhPrintPointer(objectNode->ObjectString, searchResult->Object); + + PhDereferenceObject(processItem); + } - SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER))); - SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER))); + Context->SearchResultsAddIndex = i; - PhCenterWindow(hwndDlg, GetParent(hwndDlg)); - PhFindObjectsListViewHandle = lvHandle = GetDlgItem(hwndDlg, IDC_RESULTS); + PhReleaseQueuedLockExclusive(&Context->SearchResultsLock); - PhCreateSearchControl(hwndDlg, GetDlgItem(hwndDlg, IDC_FILTER), NULL); + TreeNew_NodesStructured(Context->TreeNewHandle); + TreeNew_SetRedraw(Context->TreeNewHandle, TRUE); +} - PhpPopulateObjectTypes(GetDlgItem(hwndDlg, IDC_FILTERTYPE)); +VOID PhpFindObjectClearResultEntries( + _In_ PPH_HANDLE_SEARCH_CONTEXT Context + ) +{ + ClearHandleObjectTree(Context); - PhInitializeLayoutManager(&WindowLayoutManager, hwndDlg); - PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDC_FILTER), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); - PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDC_FILTERTYPE), NULL, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); - PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDC_REGEX), NULL, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); - PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDOK), NULL, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); - PhAddLayoutItem(&WindowLayoutManager, lvHandle, NULL, PH_ANCHOR_ALL); + Context->SearchResultsAddIndex = 0; - MinimumSize.left = 0; - MinimumSize.top = 0; - MinimumSize.right = 150; - MinimumSize.bottom = 100; - MapDialogRect(hwndDlg, &MinimumSize); + for (ULONG i = 0; i < Context->SearchResults->Count; i++) + PhFree(Context->SearchResults->Items[i]); - PhRegisterDialog(hwndDlg); + PhClearList(Context->SearchResults); +} - PhLoadWindowPlacementFromSetting(L"FindObjWindowPosition", L"FindObjWindowSize", hwndDlg); +VOID CALLBACK PhpFindObjectTreeUpdateCallback( + _In_ PPH_HANDLE_SEARCH_CONTEXT Context, + _In_ BOOLEAN TimerOrWaitFired + ) +{ + if (!Context->SearchThreadHandle) + { + RtlUpdateTimer(Context->TimerQueueHandle, Context->UpdateTimerHandle, 1000, INFINITE); + return; + } - PhSetListViewStyle(lvHandle, TRUE, TRUE); - PhSetControlTheme(lvHandle, L"explorer"); - PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 100, L"Process"); - PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 100, L"Type"); - PhAddListViewColumn(lvHandle, 2, 2, 2, LVCFMT_LEFT, 200, L"Name"); - PhAddListViewColumn(lvHandle, 3, 3, 3, LVCFMT_LEFT, 80, L"Handle"); - - PhSetExtendedListView(lvHandle); - ExtendedListView_SetSortFast(lvHandle, TRUE); - ExtendedListView_SetCompareFunction(lvHandle, 0, PhpObjectProcessCompareFunction); - ExtendedListView_SetCompareFunction(lvHandle, 1, PhpObjectTypeCompareFunction); - ExtendedListView_SetCompareFunction(lvHandle, 2, PhpObjectNameCompareFunction); - ExtendedListView_SetCompareFunction(lvHandle, 3, PhpObjectHandleCompareFunction); - PhLoadListViewColumnsFromSetting(L"FindObjListViewColumns", lvHandle); + // Update the search results. + PhpFindObjectAddResultEntries(Context); - Button_SetCheck(GetDlgItem(hwndDlg, IDC_REGEX), PhGetIntegerSetting(L"FindObjRegex") ? BST_CHECKED : BST_UNCHECKED); - } - break; - case WM_SHOWWINDOW: - { - SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hwndDlg, IDC_FILTER), TRUE); - Edit_SetSel(GetDlgItem(hwndDlg, IDC_FILTER), 0, -1); - } - break; - case WM_CLOSE: - { - PhSetIntegerSetting(L"FindObjRegex", Button_GetCheck(GetDlgItem(hwndDlg, IDC_REGEX)) == BST_CHECKED); - PhSaveWindowPlacementToSetting(L"FindObjWindowPosition", L"FindObjWindowSize", hwndDlg); - PhSaveListViewColumnsToSetting(L"FindObjListViewColumns", PhFindObjectsListViewHandle); - - ShowWindow(hwndDlg, SW_HIDE); - // IMPORTANT - // Set the result to 0 so the default dialog message - // handler doesn't invoke IDCANCEL, which will send - // WM_CLOSE, creating an infinite loop. - SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, 0); - } - return TRUE; - case WM_SETCURSOR: + RtlUpdateTimer(Context->TimerQueueHandle, Context->UpdateTimerHandle, 1000, INFINITE); +} + +static BOOLEAN MatchSearchString( + _In_ PPH_HANDLE_SEARCH_CONTEXT Context, + _In_ PPH_STRINGREF Input + ) +{ + if (Context->SearchRegexCompiledExpression && Context->SearchRegexMatchData) + { + return pcre2_match( + Context->SearchRegexCompiledExpression, + Input->Buffer, + Input->Length / sizeof(WCHAR), + 0, + 0, + Context->SearchRegexMatchData, + NULL + ) >= 0; + } + else + { + return PhFindStringInStringRef(Input, &Context->SearchString->sr, TRUE) != -1; + } +} + +static BOOLEAN MatchTypeString( + _In_ PPH_HANDLE_SEARCH_CONTEXT Context, + _In_ PPH_STRINGREF Input + ) +{ + if (Context->SearchRegexCompiledExpression && Context->SearchRegexMatchData) + return TRUE; + else + { + if (PhEqualString2(Context->SearchTypeString, L"Everything", FALSE)) + return TRUE; + + return PhFindStringInStringRef(Input, &Context->SearchTypeString->sr, TRUE) != -1; + } +} + +typedef struct _SEARCH_HANDLE_CONTEXT +{ + PPH_HANDLE_SEARCH_CONTEXT WindowContext; + BOOLEAN NeedToFree; + PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX HandleInfo; + HANDLE ProcessHandle; +} SEARCH_HANDLE_CONTEXT, *PSEARCH_HANDLE_CONTEXT; + +static NTSTATUS NTAPI SearchHandleFunction( + _In_ PVOID Parameter + ) +{ + PSEARCH_HANDLE_CONTEXT handleContext = Parameter; + PPH_HANDLE_SEARCH_CONTEXT context = handleContext->WindowContext; + PPH_STRING typeName; + PPH_STRING objectName; + PPH_STRING bestObjectName; + + if (NT_SUCCESS(PhGetHandleInformation( + handleContext->ProcessHandle, + (HANDLE)handleContext->HandleInfo->HandleValue, + handleContext->HandleInfo->ObjectTypeIndex, + NULL, + &typeName, + &objectName, + &bestObjectName + ))) + { + PPH_STRING upperObjectName; + PPH_STRING upperBestObjectName; + PPH_STRING upperTypeName; + + upperObjectName = PhDuplicateString(objectName); + _wcsupr(upperObjectName->Buffer); + + upperBestObjectName = PhDuplicateString(bestObjectName); + _wcsupr(upperBestObjectName->Buffer); + + upperTypeName = PhDuplicateString(typeName); + _wcsupr(upperTypeName->Buffer); + + if (((MatchSearchString(context, &upperObjectName->sr) || MatchSearchString(context, &upperBestObjectName->sr)) && MatchTypeString(context, &upperTypeName->sr)) || + (context->UseSearchPointer && (handleContext->HandleInfo->Object == (PVOID)context->SearchPointer || handleContext->HandleInfo->HandleValue == context->SearchPointer))) + { + PPHP_OBJECT_SEARCH_RESULT searchResult; + + searchResult = PhAllocate(sizeof(PHP_OBJECT_SEARCH_RESULT)); + memset(searchResult, 0, sizeof(PHP_OBJECT_SEARCH_RESULT)); + + searchResult->ProcessId = (HANDLE)handleContext->HandleInfo->UniqueProcessId; + searchResult->ResultType = HandleSearchResult; + searchResult->Object = handleContext->HandleInfo->Object; + searchResult->Handle = (HANDLE)handleContext->HandleInfo->HandleValue; + searchResult->TypeName = typeName; + searchResult->ObjectName = objectName; + searchResult->BestObjectName = bestObjectName; + searchResult->Info = *handleContext->HandleInfo; + + PhAcquireQueuedLockExclusive(&context->SearchResultsLock); + PhAddItemList(context->SearchResults, searchResult); + PhReleaseQueuedLockExclusive(&context->SearchResultsLock); + } + else + { + PhDereferenceObject(typeName); + PhDereferenceObject(objectName); + PhDereferenceObject(bestObjectName); + } + + PhDereferenceObject(upperTypeName); + PhDereferenceObject(upperBestObjectName); + PhDereferenceObject(upperObjectName); + } + + if (handleContext->NeedToFree) + PhFree(handleContext); + + return STATUS_SUCCESS; +} + +typedef struct _SEARCH_MODULE_CONTEXT +{ + PPH_HANDLE_SEARCH_CONTEXT WindowContext; + HANDLE ProcessId; +} SEARCH_MODULE_CONTEXT, *PSEARCH_MODULE_CONTEXT; + +static BOOLEAN NTAPI EnumModulesCallback( + _In_ PPH_MODULE_INFO Module, + _In_opt_ PVOID Context + ) +{ + PSEARCH_MODULE_CONTEXT moduleContext = Context; + PPH_HANDLE_SEARCH_CONTEXT context = moduleContext->WindowContext; + PPH_STRING upperFileName; + + upperFileName = PhDuplicateString(Module->FileName); + _wcsupr(upperFileName->Buffer); + + if (MatchSearchString(context, &upperFileName->sr) || + (context->UseSearchPointer && Module->BaseAddress == (PVOID)context->SearchPointer)) + { + PPHP_OBJECT_SEARCH_RESULT searchResult; + PWSTR typeName; + + switch (Module->Type) { - if (SearchThreadHandle) + case PH_MODULE_TYPE_MAPPED_FILE: + typeName = L"Mapped file"; + break; + case PH_MODULE_TYPE_MAPPED_IMAGE: + typeName = L"Mapped image"; + break; + default: + typeName = L"DLL"; + break; + } + + searchResult = PhAllocate(sizeof(PHP_OBJECT_SEARCH_RESULT)); + memset(searchResult, 0, sizeof(PHP_OBJECT_SEARCH_RESULT)); + + searchResult->ProcessId = moduleContext->ProcessId; + searchResult->ResultType = (Module->Type == PH_MODULE_TYPE_MAPPED_FILE || Module->Type == PH_MODULE_TYPE_MAPPED_IMAGE) ? MappedFileSearchResult : ModuleSearchResult; + searchResult->Handle = (HANDLE)Module->BaseAddress; + searchResult->TypeName = PhCreateString(typeName); + PhSetReference(&searchResult->BestObjectName, Module->FileName); + PhSetReference(&searchResult->ObjectName, Module->OriginalFileName); + + PhAcquireQueuedLockExclusive(&context->SearchResultsLock); + PhAddItemList(context->SearchResults, searchResult); + PhReleaseQueuedLockExclusive(&context->SearchResultsLock); + } + + PhDereferenceObject(upperFileName); + + return TRUE; +} + +NTSTATUS PhpFindObjectsThreadStart( + _In_ PVOID Parameter + ) +{ + PPH_HANDLE_SEARCH_CONTEXT context = Parameter; + NTSTATUS status = STATUS_SUCCESS; + PSYSTEM_HANDLE_INFORMATION_EX handles; + PPH_HASHTABLE processHandleHashtable; + PVOID processes; + PSYSTEM_PROCESS_INFORMATION process; + ULONG i; + + // Refuse to search with no filter. + if (context->SearchString->Length == 0) + goto Exit; + + // Try to get a search pointer from the search string. + context->UseSearchPointer = PhStringToInteger64(&context->SearchString->sr, 0, &context->SearchPointer); + + _wcsupr(context->SearchString->Buffer); + + if (NT_SUCCESS(status = PhEnumHandlesEx(&handles))) + { + static PH_INITONCE initOnce = PH_INITONCE_INIT; + static ULONG fileObjectTypeIndex = -1; + + BOOLEAN useWorkQueue = FALSE; + PH_WORK_QUEUE workQueue; + processHandleHashtable = PhCreateSimpleHashtable(8); + + if (!KphIsConnected()) + { + useWorkQueue = TRUE; + PhInitializeWorkQueue(&workQueue, 1, 20, 1000); + + if (PhBeginInitOnce(&initOnce)) { - SetCursor(LoadCursor(NULL, IDC_WAIT)); + UNICODE_STRING fileTypeName; + + RtlInitUnicodeString(&fileTypeName, L"File"); + fileObjectTypeIndex = PhGetObjectTypeNumber(&fileTypeName); + PhEndInitOnce(&initOnce); + } + } + + for (i = 0; i < handles->NumberOfHandles; i++) + { + PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX handleInfo = &handles->Handles[i]; + PVOID *processHandlePtr; + HANDLE processHandle; + + // Don't continue if the user requested cancellation. + if (context->SearchStop) + break; + + // Open a handle to the process if we don't already have one. + + processHandlePtr = PhFindItemSimpleHashtable( + processHandleHashtable, + (PVOID)handleInfo->UniqueProcessId + ); + + if (processHandlePtr) + { + processHandle = (HANDLE)*processHandlePtr; + } + else + { + if (NT_SUCCESS(PhOpenProcess( + &processHandle, + PROCESS_DUP_HANDLE, + (HANDLE)handleInfo->UniqueProcessId + ))) + { + PhAddItemSimpleHashtable( + processHandleHashtable, + (PVOID)handleInfo->UniqueProcessId, + processHandle + ); + } + else + { + continue; + } + } + + if (useWorkQueue && handleInfo->ObjectTypeIndex == (USHORT)fileObjectTypeIndex) + { + PSEARCH_HANDLE_CONTEXT searchHandleContext; + + searchHandleContext = PhAllocate(sizeof(SEARCH_HANDLE_CONTEXT)); + searchHandleContext->WindowContext = context; + searchHandleContext->NeedToFree = TRUE; + searchHandleContext->HandleInfo = handleInfo; + searchHandleContext->ProcessHandle = processHandle; + + PhQueueItemWorkQueue(&workQueue, SearchHandleFunction, searchHandleContext); + } + else + { + SEARCH_HANDLE_CONTEXT searchHandleContext; + searchHandleContext.WindowContext = context; + searchHandleContext.NeedToFree = FALSE; + searchHandleContext.HandleInfo = handleInfo; + searchHandleContext.ProcessHandle = processHandle; + + SearchHandleFunction(&searchHandleContext); + } + } + + if (useWorkQueue) + { + PhWaitForWorkQueue(&workQueue); + PhDeleteWorkQueue(&workQueue); + } + + { + PPH_KEY_VALUE_PAIR entry; + + i = 0; + + while (PhEnumHashtable(processHandleHashtable, &entry, &i)) + NtClose((HANDLE)entry->Value); + } + + PhDereferenceObject(processHandleHashtable); + PhFree(handles); + } + + if (context->SearchStop) + goto Exit; + + if (PhEqualString2(context->SearchTypeString, L"File", TRUE) || + PhEqualString2(context->SearchTypeString, L"Everything", FALSE)) + { + if (NT_SUCCESS(PhEnumProcesses(&processes))) + { + process = PH_FIRST_PROCESS(processes); + + do + { + SEARCH_MODULE_CONTEXT searchModuleContext; + + if (context->SearchStop) + break; + + searchModuleContext.WindowContext = context; + searchModuleContext.ProcessId = process->UniqueProcessId; + + PhEnumGenericModules( + process->UniqueProcessId, + NULL, + PH_ENUM_GENERIC_MAPPED_FILES | PH_ENUM_GENERIC_MAPPED_IMAGES, + EnumModulesCallback, + &searchModuleContext + ); + } while (process = PH_NEXT_PROCESS(process)); + + PhFree(processes); + } + } + +Exit: + PostMessage(context->WindowHandle, WM_PH_SEARCH_FINISHED, status, 0); + + PhDereferenceObject(context); + return STATUS_SUCCESS; +} + +INT_PTR CALLBACK PhpFindObjectsDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + PPH_HANDLE_SEARCH_CONTEXT context; + + if (uMsg == WM_INITDIALOG) + { + context = PhCreateAlloc(sizeof(PH_HANDLE_SEARCH_CONTEXT)); + memset(context, 0, sizeof(PH_HANDLE_SEARCH_CONTEXT)); + + SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)context); + } + else + { + context = (PPH_HANDLE_SEARCH_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom()); + } + + if (!context) + return FALSE; + + switch (uMsg) + { + case WM_INITDIALOG: + { + SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER))); + SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER))); + + context->WindowHandle = hwndDlg; + context->TreeNewHandle = GetDlgItem(hwndDlg, IDC_TREELIST); + + PhCreateSearchControl(hwndDlg, GetDlgItem(hwndDlg, IDC_FILTER), L"Search Handles or DLLs"); + + PhpPopulateObjectTypes(GetDlgItem(hwndDlg, IDC_FILTERTYPE)); + + InitializeHandleObjectTree(context); + + PhInitializeLayoutManager(&context->LayoutManager, hwndDlg); + PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_FILTER), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); + PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_FILTERTYPE), NULL, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); + PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_REGEX), NULL, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); + PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDOK), NULL, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); + PhAddLayoutItem(&context->LayoutManager, context->TreeNewHandle, NULL, PH_ANCHOR_ALL); + + context->MinimumSize.left = 0; + context->MinimumSize.top = 0; + context->MinimumSize.right = 300; + context->MinimumSize.bottom = 100; + MapDialogRect(hwndDlg, &context->MinimumSize); + + PhRegisterDialog(hwndDlg); + + PhCenterWindow(hwndDlg, NULL); + PhLoadWindowPlacementFromSetting(L"FindObjWindowPosition", L"FindObjWindowSize", hwndDlg); + + context->SearchResults = PhCreateList(128); + context->SearchResultsAddIndex = 0; + + if (NT_SUCCESS(RtlCreateTimerQueue(&context->TimerQueueHandle))) + { + RtlCreateTimer( + context->TimerQueueHandle, + &context->UpdateTimerHandle, + PhpFindObjectTreeUpdateCallback, + context, + 0, + 1000, + 0 + ); + } + + Button_SetCheck(GetDlgItem(hwndDlg, IDC_REGEX), PhGetIntegerSetting(L"FindObjRegex") ? BST_CHECKED : BST_UNCHECKED); + + SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hwndDlg, IDC_FILTER), TRUE); + Edit_SetSel(GetDlgItem(hwndDlg, IDC_FILTER), 0, -1); + } + break; + case WM_DESTROY: + { + context->SearchStop = TRUE; + + if (context->UpdateTimerHandle) + { + RtlDeleteTimer(context->TimerQueueHandle, context->UpdateTimerHandle, NULL); + context->TimerQueueHandle = NULL; + } + + if (context->TimerQueueHandle) + { + RtlDeleteTimerQueue(context->TimerQueueHandle); + context->TimerQueueHandle = NULL; + } + + if (context->SearchThreadHandle) + { + NtWaitForSingleObject(context->SearchThreadHandle, FALSE, NULL); + NtClose(context->SearchThreadHandle); + context->SearchThreadHandle = NULL; + } + + PhClearReference(&context->SearchString); + PhClearReference(&context->SearchTypeString); + + if (context->SearchRegexCompiledExpression) + { + pcre2_code_free(context->SearchRegexCompiledExpression); + context->SearchRegexCompiledExpression = NULL; + } + + if (context->SearchRegexMatchData) + { + pcre2_match_data_free(context->SearchRegexMatchData); + context->SearchRegexMatchData = NULL; + } + + PhSetIntegerSetting(L"FindObjRegex", Button_GetCheck(GetDlgItem(hwndDlg, IDC_REGEX)) == BST_CHECKED); + PhSaveWindowPlacementToSetting(L"FindObjWindowPosition", L"FindObjWindowSize", hwndDlg); + + PhDeleteLayoutManager(&context->LayoutManager); + + DeleteHandleObjectTree(context); + + if (context->SearchResults) + { + for (ULONG i = 0; i < context->SearchResults->Count; i++) + PhFree(context->SearchResults->Items[i]); + + PhClearList(context->SearchResults); + } + + PhDereferenceObject(context); + + PostQuitMessage(0); + } + break; + case WM_PH_SEARCH_SHOWDIALOG: + { + if (IsMinimized(hwndDlg)) + ShowWindow(hwndDlg, SW_RESTORE); + else + ShowWindow(hwndDlg, SW_SHOW); + + SetForegroundWindow(hwndDlg); + } + break; + case WM_SETCURSOR: + { + if (context->SearchThreadHandle) + { + SetCursor(LoadCursor(NULL, IDC_APPSTARTING)); SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, TRUE); return TRUE; } @@ -351,26 +1237,24 @@ static INT_PTR CALLBACK PhpFindObjectsDlgProc( case IDOK: { // Don't continue if the user requested cancellation. - if (SearchStop) + if (context->SearchStop) break; - if (!SearchThreadHandle) + if (!context->SearchThreadHandle) { - ULONG i; - - PhMoveReference(&SearchString, PhGetWindowText(GetDlgItem(hwndDlg, IDC_FILTER))); - PhMoveReference(&SearchTypeString, PhGetWindowText(GetDlgItem(hwndDlg, IDC_FILTERTYPE))); + PhMoveReference(&context->SearchString, PhGetWindowText(GetDlgItem(hwndDlg, IDC_FILTER))); + PhMoveReference(&context->SearchTypeString, PhGetWindowText(GetDlgItem(hwndDlg, IDC_FILTERTYPE))); - if (SearchRegexCompiledExpression) + if (context->SearchRegexCompiledExpression) { - pcre2_code_free(SearchRegexCompiledExpression); - SearchRegexCompiledExpression = NULL; + pcre2_code_free(context->SearchRegexCompiledExpression); + context->SearchRegexCompiledExpression = NULL; } - if (SearchRegexMatchData) + if (context->SearchRegexMatchData) { - pcre2_match_data_free(SearchRegexMatchData); - SearchRegexMatchData = NULL; + pcre2_match_data_free(context->SearchRegexMatchData); + context->SearchRegexMatchData = NULL; } if (Button_GetCheck(GetDlgItem(hwndDlg, IDC_REGEX)) == BST_CHECKED) @@ -378,16 +1262,16 @@ static INT_PTR CALLBACK PhpFindObjectsDlgProc( int errorCode; PCRE2_SIZE errorOffset; - SearchRegexCompiledExpression = pcre2_compile( - SearchString->Buffer, - SearchString->Length / sizeof(WCHAR), + context->SearchRegexCompiledExpression = pcre2_compile( + context->SearchString->Buffer, + context->SearchString->Length / sizeof(WCHAR), PCRE2_CASELESS | PCRE2_DOTALL, &errorCode, &errorOffset, NULL ); - if (!SearchRegexCompiledExpression) + if (!context->SearchRegexCompiledExpression) { PhShowError(hwndDlg, L"Unable to compile the regular expression: \"%s\" at position %zu.", PhGetStringOrDefault(PH_AUTO(PhPcre2GetErrorMessage(errorCode)), L"Unknown error"), @@ -396,97 +1280,107 @@ static INT_PTR CALLBACK PhpFindObjectsDlgProc( break; } - SearchRegexMatchData = pcre2_match_data_create_from_pattern(SearchRegexCompiledExpression, NULL); + context->SearchRegexMatchData = pcre2_match_data_create_from_pattern(context->SearchRegexCompiledExpression, NULL); } // Clean up previous results. - ListView_DeleteAllItems(PhFindObjectsListViewHandle); - - if (SearchResults) - { - for (i = 0; i < SearchResults->Count; i++) - { - PPHP_OBJECT_SEARCH_RESULT searchResult = SearchResults->Items[i]; - - PhDereferenceObject(searchResult->TypeName); - PhDereferenceObject(searchResult->Name); - - if (searchResult->ProcessName) - PhDereferenceObject(searchResult->ProcessName); - - PhFree(searchResult); - } - - PhDereferenceObject(SearchResults); - } + PhpFindObjectClearResultEntries(context); // Start the search. - SearchResults = PhCreateList(128); - SearchResultsAddIndex = 0; - - SearchThreadHandle = PhCreateThread(0, PhpFindObjectsThreadStart, NULL); + PhReferenceObject(context); + context->SearchThreadHandle = PhCreateThread(0, PhpFindObjectsThreadStart, context); - if (!SearchThreadHandle) - { - PhClearReference(&SearchResults); + if (!context->SearchThreadHandle) break; - } SetDlgItemText(hwndDlg, IDOK, L"Cancel"); - SetCursor(LoadCursor(NULL, IDC_WAIT)); + SetCursor(LoadCursor(NULL, IDC_APPSTARTING)); } else { - SearchStop = TRUE; + context->SearchStop = TRUE; EnableWindow(GetDlgItem(hwndDlg, IDOK), FALSE); } } break; case IDCANCEL: { - SendMessage(hwndDlg, WM_CLOSE, 0, 0); + DestroyWindow(hwndDlg); + } + break; + case WM_PH_SEARCH_SHOWMENU: + { + PPH_TREENEW_CONTEXT_MENU contextMenuEvent = (PPH_TREENEW_CONTEXT_MENU)lParam; + PPH_EMENU menu; + PPH_EMENU_ITEM selectedItem; + PPH_HANDLE_OBJECT_TREE_ROOT_NODE *handleObjectNodes = NULL; + ULONG numberOfHandleObjectNodes = 0; + + GetSelectedHandleObjectNodes(context, &handleObjectNodes, &numberOfHandleObjectNodes); + + if (numberOfHandleObjectNodes != 0) + { + menu = PhCreateEMenu(); + PhLoadResourceEMenuItem(menu, PhInstanceHandle, MAKEINTRESOURCE(IDR_FINDOBJ), 0); + PhInsertCopyCellEMenuItem(menu, ID_OBJECT_COPY, context->TreeNewHandle, contextMenuEvent->Column); + PhSetFlagsEMenuItem(menu, ID_OBJECT_PROPERTIES, PH_EMENU_DEFAULT, PH_EMENU_DEFAULT); + PhpInitializeFindObjMenu(menu, handleObjectNodes, numberOfHandleObjectNodes); + + selectedItem = PhShowEMenu( + menu, + hwndDlg, + PH_EMENU_SHOW_SEND_COMMAND | PH_EMENU_SHOW_LEFTRIGHT, + PH_ALIGN_LEFT | PH_ALIGN_TOP, + contextMenuEvent->Location.x, + contextMenuEvent->Location.y + ); + + if (selectedItem && selectedItem->Id != -1) + { + BOOLEAN handled = FALSE; + + handled = PhHandleCopyCellEMenuItem(selectedItem); + } + + PhDestroyEMenu(menu); + } } break; case ID_OBJECT_CLOSE: { - PPHP_OBJECT_SEARCH_RESULT *results; - ULONG numberOfResults; - ULONG i; - - PhGetSelectedListViewItemParams( - PhFindObjectsListViewHandle, - &results, - &numberOfResults - ); + PPH_HANDLE_OBJECT_TREE_ROOT_NODE *handleObjectNodes = NULL; + ULONG numberOfHandleObjectNodes = 0; - if (numberOfResults != 0 && PhShowConfirmMessage( + GetSelectedHandleObjectNodes(context, &handleObjectNodes, &numberOfHandleObjectNodes); + + if (numberOfHandleObjectNodes != 0 && PhShowConfirmMessage( hwndDlg, L"close", - numberOfResults == 1 ? L"the selected handle" : L"the selected handles", + numberOfHandleObjectNodes == 1 ? L"the selected handle" : L"the selected handles", L"Closing handles may cause system instability and data corruption.", FALSE )) { - for (i = 0; i < numberOfResults; i++) + for (ULONG i = 0; i < numberOfHandleObjectNodes; i++) { NTSTATUS status; HANDLE processHandle; - - if (results[i]->ResultType != HandleSearchResult) + + if (handleObjectNodes[i]->ResultType != HandleSearchResult) continue; - + if (NT_SUCCESS(status = PhOpenProcess( &processHandle, PROCESS_DUP_HANDLE, - results[i]->ProcessId + handleObjectNodes[i]->ProcessId ))) { if (NT_SUCCESS(status = NtDuplicateObject( processHandle, - results[i]->Handle, + handleObjectNodes[i]->Handle, NULL, NULL, 0, @@ -494,17 +1388,16 @@ static INT_PTR CALLBACK PhpFindObjectsDlgProc( DUPLICATE_CLOSE_SOURCE ))) { - PhRemoveListViewItem(PhFindObjectsListViewHandle, - PhFindListViewItemByParam(PhFindObjectsListViewHandle, 0, results[i])); + RemoveHandleObjectNode(context, handleObjectNodes[i]); } - + NtClose(processHandle); } - + if (!NT_SUCCESS(status)) { if (!PhShowContinueStatus(hwndDlg, - PhaFormatString(L"Unable to close \"%s\"", results[i]->Name->Buffer)->Buffer, + PhaFormatString(L"Unable to close \"%s\"", PhGetStringOrDefault(handleObjectNodes[i]->BestObjectName, L"??"))->Buffer, status, 0 )) @@ -512,24 +1405,21 @@ static INT_PTR CALLBACK PhpFindObjectsDlgProc( } } } - - PhFree(results); } break; case ID_HANDLE_OBJECTPROPERTIES1: case ID_HANDLE_OBJECTPROPERTIES2: { - PPHP_OBJECT_SEARCH_RESULT result = - PhGetSelectedListViewItemParam(PhFindObjectsListViewHandle); + PPH_HANDLE_OBJECT_TREE_ROOT_NODE handleObjectNode; - if (result) + if (handleObjectNode = GetSelectedHandleObjectNode(context)) { PH_HANDLE_ITEM_INFO info; - info.ProcessId = result->ProcessId; - info.Handle = result->Handle; - info.TypeName = result->TypeName; - info.BestObjectName = result->Name; + info.ProcessId = handleObjectNode->ProcessId; + info.Handle = handleObjectNode->Handle; + info.TypeName = handleObjectNode->TypeNameString; + info.BestObjectName = handleObjectNode->BestObjectName; if (GET_WM_COMMAND_ID(wParam, lParam) == ID_HANDLE_OBJECTPROPERTIES1) PhShowHandleObjectProperties1(hwndDlg, &info); @@ -540,14 +1430,13 @@ static INT_PTR CALLBACK PhpFindObjectsDlgProc( break; case ID_OBJECT_GOTOOWNINGPROCESS: { - PPHP_OBJECT_SEARCH_RESULT result = - PhGetSelectedListViewItemParam(PhFindObjectsListViewHandle); + PPH_HANDLE_OBJECT_TREE_ROOT_NODE handleObjectNode; - if (result) + if (handleObjectNode = GetSelectedHandleObjectNode(context)) { PPH_PROCESS_NODE processNode; - if (processNode = PhFindProcessNode(result->ProcessId)) + if (processNode = PhFindProcessNode(handleObjectNode->ProcessId)) { ProcessHacker_SelectTabPage(PhMainWndHandle, 0); ProcessHacker_SelectProcessNode(PhMainWndHandle, processNode); @@ -558,26 +1447,25 @@ static INT_PTR CALLBACK PhpFindObjectsDlgProc( break; case ID_OBJECT_PROPERTIES: { - PPHP_OBJECT_SEARCH_RESULT result = - PhGetSelectedListViewItemParam(PhFindObjectsListViewHandle); + PPH_HANDLE_OBJECT_TREE_ROOT_NODE handleObjectNode; - if (result) + if (handleObjectNode = GetSelectedHandleObjectNode(context)) { - if (result->ResultType == HandleSearchResult) + if (handleObjectNode->ResultType == HandleSearchResult) { PPH_HANDLE_ITEM handleItem; - - handleItem = PhCreateHandleItem(&result->Info); - - handleItem->BestObjectName = handleItem->ObjectName = result->Name; - PhReferenceObjectEx(result->Name, 2); - - handleItem->TypeName = result->TypeName; - PhReferenceObject(result->TypeName); - + + handleItem = PhCreateHandleItem(&handleObjectNode->HandleInfo); + + handleItem->BestObjectName = handleItem->ObjectName = handleObjectNode->BestObjectName; + PhReferenceObjectEx(handleObjectNode->BestObjectName, 2); + + handleItem->TypeName = handleObjectNode->TypeNameString; + PhReferenceObject(handleObjectNode->TypeNameString); + PhShowHandleProperties( hwndDlg, - result->ProcessId, + handleObjectNode->ProcessId, handleItem ); PhDereferenceObject(handleItem); @@ -585,185 +1473,49 @@ static INT_PTR CALLBACK PhpFindObjectsDlgProc( else { // DLL or Mapped File. Just show file properties. - PhShellProperties(hwndDlg, result->Name->Buffer); + PhShellProperties(hwndDlg, handleObjectNode->BestObjectName->Buffer); } } } break; case ID_OBJECT_COPY: { - PhCopyListView(PhFindObjectsListViewHandle); - } - break; - } - } - break; - case WM_NOTIFY: - { - LPNMHDR header = (LPNMHDR)lParam; + PPH_STRING text; - switch (header->code) - { - case NM_DBLCLK: - { - if (header->hwndFrom == PhFindObjectsListViewHandle) - { - SendMessage(hwndDlg, WM_COMMAND, ID_OBJECT_PROPERTIES, 0); - } + text = PhGetTreeNewText(context->TreeNewHandle, 0); + PhSetClipboardString(context->TreeNewHandle, &text->sr); + PhDereferenceObject(text); } break; - case LVN_KEYDOWN: - { - if (header->hwndFrom == PhFindObjectsListViewHandle) - { - LPNMLVKEYDOWN keyDown = (LPNMLVKEYDOWN)header; - - switch (keyDown->wVKey) - { - case 'C': - if (GetKeyState(VK_CONTROL) < 0) - SendMessage(hwndDlg, WM_COMMAND, ID_OBJECT_COPY, 0); - break; - case 'A': - if (GetKeyState(VK_CONTROL) < 0) - PhSetStateAllListViewItems(PhFindObjectsListViewHandle, LVIS_SELECTED, LVIS_SELECTED); - break; - case VK_DELETE: - SendMessage(hwndDlg, WM_COMMAND, ID_OBJECT_CLOSE, 0); - break; - } - } - } - break; - } - } - break; - case WM_CONTEXTMENU: - { - if ((HWND)wParam == PhFindObjectsListViewHandle) - { - POINT point; - PPHP_OBJECT_SEARCH_RESULT *results; - ULONG numberOfResults; - - point.x = (SHORT)LOWORD(lParam); - point.y = (SHORT)HIWORD(lParam); - - if (point.x == -1 && point.y == -1) - PhGetListViewContextMenuPoint((HWND)wParam, &point); - - PhGetSelectedListViewItemParams(PhFindObjectsListViewHandle, &results, &numberOfResults); - - if (numberOfResults != 0) - { - PPH_EMENU menu; - - menu = PhCreateEMenu(); - PhLoadResourceEMenuItem(menu, PhInstanceHandle, MAKEINTRESOURCE(IDR_FINDOBJ), 0); - PhSetFlagsEMenuItem(menu, ID_OBJECT_PROPERTIES, PH_EMENU_DEFAULT, PH_EMENU_DEFAULT); - - PhpInitializeFindObjMenu(menu, results, numberOfResults); - PhShowEMenu( - menu, - hwndDlg, - PH_EMENU_SHOW_SEND_COMMAND | PH_EMENU_SHOW_LEFTRIGHT, - PH_ALIGN_LEFT | PH_ALIGN_TOP, - point.x, - point.y - ); - PhDestroyEMenu(menu); - } - - PhFree(results); - } - } - break; - case WM_SIZE: - { - PhLayoutManagerLayout(&WindowLayoutManager); - } - break; - case WM_SIZING: - { - PhResizingMinimumSize((PRECT)lParam, wParam, MinimumSize.right, MinimumSize.bottom); - } - break; - case WM_PH_SEARCH_UPDATE: - { - HWND lvHandle; - ULONG i; - - lvHandle = GetDlgItem(hwndDlg, IDC_RESULTS); - - ExtendedListView_SetRedraw(lvHandle, FALSE); - - PhAcquireQueuedLockExclusive(&SearchResultsLock); - - for (i = SearchResultsAddIndex; i < SearchResults->Count; i++) - { - PPHP_OBJECT_SEARCH_RESULT searchResult = SearchResults->Items[i]; - CLIENT_ID clientId; - PPH_PROCESS_ITEM processItem; - PPH_STRING clientIdName; - INT lvItemIndex; - - clientId.UniqueProcess = searchResult->ProcessId; - clientId.UniqueThread = NULL; - - processItem = PhReferenceProcessItem(clientId.UniqueProcess); - clientIdName = PhGetClientIdNameEx(&clientId, processItem ? processItem->ProcessName : NULL); - - lvItemIndex = PhAddListViewItem( - lvHandle, - MAXINT, - clientIdName->Buffer, - searchResult - ); - - PhDereferenceObject(clientIdName); - - if (processItem) - { - PhSetReference(&searchResult->ProcessName, processItem->ProcessName); - PhDereferenceObject(processItem); - } - else - { - searchResult->ProcessName = NULL; - } - - PhSetListViewSubItem(lvHandle, lvItemIndex, 1, searchResult->TypeName->Buffer); - PhSetListViewSubItem(lvHandle, lvItemIndex, 2, searchResult->Name->Buffer); - PhSetListViewSubItem(lvHandle, lvItemIndex, 3, searchResult->HandleString); - } - - SearchResultsAddIndex = i; - - PhReleaseQueuedLockExclusive(&SearchResultsLock); - - ExtendedListView_SetRedraw(lvHandle, TRUE); + } + } + break; + case WM_SIZE: + { + PhLayoutManagerLayout(&context->LayoutManager); + } + break; + case WM_SIZING: + { + PhResizingMinimumSize((PRECT)lParam, wParam, context->MinimumSize.right, context->MinimumSize.bottom); } break; case WM_PH_SEARCH_FINISHED: { - NTSTATUS handleSearchStatus = (NTSTATUS)wParam; - // Add any un-added items. - SendMessage(hwndDlg, WM_PH_SEARCH_UPDATE, 0, 0); + PhpFindObjectAddResultEntries(context); - NtWaitForSingleObject(SearchThreadHandle, FALSE, NULL); - NtClose(SearchThreadHandle); - SearchThreadHandle = NULL; - SearchStop = FALSE; - - ExtendedListView_SortItems(GetDlgItem(hwndDlg, IDC_RESULTS)); + NtWaitForSingleObject(context->SearchThreadHandle, FALSE, NULL); + NtClose(context->SearchThreadHandle); + context->SearchThreadHandle = NULL; + context->SearchStop = FALSE; SetDlgItemText(hwndDlg, IDOK, L"Find"); EnableWindow(GetDlgItem(hwndDlg, IDOK), TRUE); SetCursor(LoadCursor(NULL, IDC_ARROW)); - if (handleSearchStatus == STATUS_INSUFFICIENT_RESOURCES) + if ((NTSTATUS)wParam == STATUS_INSUFFICIENT_RESOURCES) { PhShowWarning( hwndDlg, @@ -778,318 +1530,65 @@ static INT_PTR CALLBACK PhpFindObjectsDlgProc( return FALSE; } -static BOOLEAN MatchSearchString( - _In_ PPH_STRINGREF Input - ) -{ - if (SearchRegexCompiledExpression && SearchRegexMatchData) - { - return pcre2_match( - SearchRegexCompiledExpression, - Input->Buffer, - Input->Length / sizeof(WCHAR), - 0, - 0, - SearchRegexMatchData, - NULL - ) >= 0; - } - else - { - return PhFindStringInStringRef(Input, &SearchString->sr, TRUE) != -1; - } -} - -static BOOLEAN MatchTypeString( - _In_ PPH_STRINGREF Input - ) -{ - if (SearchRegexCompiledExpression && SearchRegexMatchData) - return TRUE; - else - { - if (PhEqualString2(SearchTypeString, L"Everything", FALSE)) - return TRUE; - - return PhFindStringInStringRef(Input, &SearchTypeString->sr, TRUE) != -1; - } -} - -typedef struct _SEARCH_HANDLE_CONTEXT -{ - BOOLEAN NeedToFree; - PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX HandleInfo; - HANDLE ProcessHandle; -} SEARCH_HANDLE_CONTEXT, *PSEARCH_HANDLE_CONTEXT; - -static NTSTATUS NTAPI SearchHandleFunction( +NTSTATUS PhpFindObjectsDialogThreadStart( _In_ PVOID Parameter ) { - PSEARCH_HANDLE_CONTEXT context = Parameter; - PPH_STRING typeName; - PPH_STRING bestObjectName; - - if (!SearchStop && NT_SUCCESS(PhGetHandleInformation( - context->ProcessHandle, - (HANDLE)context->HandleInfo->HandleValue, - context->HandleInfo->ObjectTypeIndex, - NULL, - &typeName, - NULL, - &bestObjectName - ))) - { - PPH_STRING upperBestObjectName; - PPH_STRING upperTypeName; - - upperBestObjectName = PhDuplicateString(bestObjectName); - _wcsupr(upperBestObjectName->Buffer); - - upperTypeName = PhDuplicateString(typeName); - _wcsupr(upperTypeName->Buffer); - - if ((MatchSearchString(&upperBestObjectName->sr) && MatchTypeString(&upperTypeName->sr)) || - (UseSearchPointer && (context->HandleInfo->Object == (PVOID)SearchPointer || context->HandleInfo->HandleValue == SearchPointer))) - { - PPHP_OBJECT_SEARCH_RESULT searchResult; + BOOL result; + MSG message; + PH_AUTO_POOL autoPool; - searchResult = PhAllocate(sizeof(PHP_OBJECT_SEARCH_RESULT)); - searchResult->ProcessId = (HANDLE)context->HandleInfo->UniqueProcessId; - searchResult->ResultType = HandleSearchResult; - searchResult->Handle = (HANDLE)context->HandleInfo->HandleValue; - searchResult->TypeName = typeName; - searchResult->Name = bestObjectName; - PhPrintPointer(searchResult->HandleString, (PVOID)searchResult->Handle); - searchResult->Info = *context->HandleInfo; + PhInitializeAutoPool(&autoPool); - PhAcquireQueuedLockExclusive(&SearchResultsLock); + PhFindObjectsWindowHandle = CreateDialog( + PhInstanceHandle, + MAKEINTRESOURCE(IDD_FINDOBJECTS), + NULL, + PhpFindObjectsDlgProc + ); - PhAddItemList(SearchResults, searchResult); + PhSetEvent(&PhFindObjectsInitializedEvent); - // Update the search results in batches of 40. - if (SearchResults->Count % 40 == 0) - PostMessage(PhFindObjectsWindowHandle, WM_PH_SEARCH_UPDATE, 0, 0); + while (result = GetMessage(&message, NULL, 0, 0)) + { + if (result == -1) + break; - PhReleaseQueuedLockExclusive(&SearchResultsLock); - } - else + if (!IsDialogMessage(PhFindObjectsWindowHandle, &message)) { - PhDereferenceObject(typeName); - PhDereferenceObject(bestObjectName); + TranslateMessage(&message); + DispatchMessage(&message); } - PhDereferenceObject(upperBestObjectName); + PhDrainAutoPool(&autoPool); } - if (context->NeedToFree) - PhFree(context); + PhDeleteAutoPool(&autoPool); + PhResetEvent(&PhFindObjectsInitializedEvent); - return STATUS_SUCCESS; -} - -static BOOLEAN NTAPI EnumModulesCallback( - _In_ PPH_MODULE_INFO Module, - _In_opt_ PVOID Context - ) -{ - PPH_STRING upperFileName; - - upperFileName = PhDuplicateString(Module->FileName); - _wcsupr(upperFileName->Buffer); - - if (MatchSearchString(&upperFileName->sr) || - (UseSearchPointer && Module->BaseAddress == (PVOID)SearchPointer)) + if (PhFindObjectsThreadHandle) { - PPHP_OBJECT_SEARCH_RESULT searchResult; - PWSTR typeName; - - switch (Module->Type) - { - case PH_MODULE_TYPE_MAPPED_FILE: - typeName = L"Mapped file"; - break; - case PH_MODULE_TYPE_MAPPED_IMAGE: - typeName = L"Mapped image"; - break; - default: - typeName = L"DLL"; - break; - } - - searchResult = PhAllocate(sizeof(PHP_OBJECT_SEARCH_RESULT)); - searchResult->ProcessId = (HANDLE)Context; - searchResult->ResultType = (Module->Type == PH_MODULE_TYPE_MAPPED_FILE || Module->Type == PH_MODULE_TYPE_MAPPED_IMAGE) ? MappedFileSearchResult : ModuleSearchResult; - searchResult->Handle = (HANDLE)Module->BaseAddress; - searchResult->TypeName = PhCreateString(typeName); - PhSetReference(&searchResult->Name, Module->FileName); - PhPrintPointer(searchResult->HandleString, Module->BaseAddress); - memset(&searchResult->Info, 0, sizeof(SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX)); - - PhAcquireQueuedLockExclusive(&SearchResultsLock); - - PhAddItemList(SearchResults, searchResult); - - // Update the search results in batches of 40. - if (SearchResults->Count % 40 == 0) - PostMessage(PhFindObjectsWindowHandle, WM_PH_SEARCH_UPDATE, 0, 0); - - PhReleaseQueuedLockExclusive(&SearchResultsLock); + NtClose(PhFindObjectsThreadHandle); + PhFindObjectsThreadHandle = NULL; } - PhDereferenceObject(upperFileName); - - return TRUE; + return STATUS_SUCCESS; } -static NTSTATUS PhpFindObjectsThreadStart( - _In_ PVOID Parameter +VOID PhShowFindObjectsDialog( + VOID ) { - NTSTATUS status = STATUS_SUCCESS; - PSYSTEM_HANDLE_INFORMATION_EX handles; - PPH_HASHTABLE processHandleHashtable; - PVOID processes; - PSYSTEM_PROCESS_INFORMATION process; - ULONG i; - - // Refuse to search with no filter. - if (SearchString->Length == 0) - goto Exit; - - // Try to get a search pointer from the search string. - UseSearchPointer = PhStringToInteger64(&SearchString->sr, 0, &SearchPointer); - - _wcsupr(SearchString->Buffer); - - if (NT_SUCCESS(status = PhEnumHandlesEx(&handles))) + if (!PhFindObjectsThreadHandle) { - static PH_INITONCE initOnce = PH_INITONCE_INIT; - static ULONG fileObjectTypeIndex = -1; - - BOOLEAN useWorkQueue = FALSE; - PH_WORK_QUEUE workQueue; - processHandleHashtable = PhCreateSimpleHashtable(8); - - if (!KphIsConnected()) - { - useWorkQueue = TRUE; - PhInitializeWorkQueue(&workQueue, 1, 20, 1000); - - if (PhBeginInitOnce(&initOnce)) - { - UNICODE_STRING fileTypeName; - - RtlInitUnicodeString(&fileTypeName, L"File"); - fileObjectTypeIndex = PhGetObjectTypeNumber(&fileTypeName); - PhEndInitOnce(&initOnce); - } - } - - for (i = 0; i < handles->NumberOfHandles; i++) - { - PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX handleInfo = &handles->Handles[i]; - PVOID *processHandlePtr; - HANDLE processHandle; - - if (SearchStop) - break; - - // Open a handle to the process if we don't already have one. - - processHandlePtr = PhFindItemSimpleHashtable( - processHandleHashtable, - (PVOID)handleInfo->UniqueProcessId - ); - - if (processHandlePtr) - { - processHandle = (HANDLE)*processHandlePtr; - } - else - { - if (NT_SUCCESS(PhOpenProcess( - &processHandle, - PROCESS_DUP_HANDLE, - (HANDLE)handleInfo->UniqueProcessId - ))) - { - PhAddItemSimpleHashtable( - processHandleHashtable, - (PVOID)handleInfo->UniqueProcessId, - processHandle - ); - } - else - { - continue; - } - } - - if (useWorkQueue && handleInfo->ObjectTypeIndex == (USHORT)fileObjectTypeIndex) - { - PSEARCH_HANDLE_CONTEXT searchHandleContext; - - searchHandleContext = PhAllocate(sizeof(SEARCH_HANDLE_CONTEXT)); - searchHandleContext->NeedToFree = TRUE; - searchHandleContext->HandleInfo = handleInfo; - searchHandleContext->ProcessHandle = processHandle; - PhQueueItemWorkQueue(&workQueue, SearchHandleFunction, searchHandleContext); - } - else - { - SEARCH_HANDLE_CONTEXT searchHandleContext; - - searchHandleContext.NeedToFree = FALSE; - searchHandleContext.HandleInfo = handleInfo; - searchHandleContext.ProcessHandle = processHandle; - SearchHandleFunction(&searchHandleContext); - } - } - - if (useWorkQueue) - { - PhWaitForWorkQueue(&workQueue); - PhDeleteWorkQueue(&workQueue); - } - + if (!(PhFindObjectsThreadHandle = PhCreateThread(0, PhpFindObjectsDialogThreadStart, NULL))) { - PPH_KEY_VALUE_PAIR entry; - - i = 0; - - while (PhEnumHashtable(processHandleHashtable, &entry, &i)) - NtClose((HANDLE)entry->Value); + PhShowStatus(PhMainWndHandle, L"Unable to create the window.", 0, GetLastError()); + return; } - PhDereferenceObject(processHandleHashtable); - PhFree(handles); - } - - if (PhEqualString2(SearchTypeString, L"File", TRUE) || - PhEqualString2(SearchTypeString, L"Everything", FALSE)) - { - if (NT_SUCCESS(PhEnumProcesses(&processes))) - { - process = PH_FIRST_PROCESS(processes); - - do - { - PhEnumGenericModules( - process->UniqueProcessId, - NULL, - PH_ENUM_GENERIC_MAPPED_FILES | PH_ENUM_GENERIC_MAPPED_IMAGES, - EnumModulesCallback, - (PVOID)process->UniqueProcessId - ); - } while (process = PH_NEXT_PROCESS(process)); - - PhFree(processes); - } + PhWaitForEvent(&PhFindObjectsInitializedEvent, NULL); } -Exit: - PostMessage(PhFindObjectsWindowHandle, WM_PH_SEARCH_FINISHED, status, 0); - - return STATUS_SUCCESS; + PostMessage(PhFindObjectsWindowHandle, WM_PH_SEARCH_SHOWDIALOG, 0, 0); } diff --git a/ProcessHacker/settings.c b/ProcessHacker/settings.c index 9ad41d1257c8..1df0dbb05dfb 100644 --- a/ProcessHacker/settings.c +++ b/ProcessHacker/settings.c @@ -50,7 +50,7 @@ VOID PhAddDefaultSettings( PhpAddIntegerSetting(L"EnableSecurityAdvancedDialog", L"1"); PhpAddStringSetting(L"EnvironmentListViewColumns", L""); PhpAddIntegerSetting(L"FindObjRegex", L"0"); - PhpAddStringSetting(L"FindObjListViewColumns", L""); + PhpAddStringSetting(L"FindObjTreeListColumns", L""); PhpAddIntegerPairSetting(L"FindObjWindowPosition", L"350,350"); PhpAddScalableIntegerPairSetting(L"FindObjWindowSize", L"@96|550,420"); PhpAddStringSetting(L"FileBrowseExecutable", L"%SystemRoot%\\explorer.exe /select,\"%s\""); From 453087165937c8776c0a014eaa7cdc39b34f7279 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 31 Jul 2017 15:42:57 +1000 Subject: [PATCH 0326/2058] Fix resource ordering --- ProcessHacker/ProcessHacker.rc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ProcessHacker/ProcessHacker.rc b/ProcessHacker/ProcessHacker.rc index 01037698009a..1e94724c23cd 100644 --- a/ProcessHacker/ProcessHacker.rc +++ b/ProcessHacker/ProcessHacker.rc @@ -728,9 +728,9 @@ BEGIN LTEXT "Filter:",IDC_STATIC,7,7,19,8 EDITTEXT IDC_FILTER,29,4,134,13,ES_AUTOHSCROLL PUSHBUTTON "Find",IDOK,301,3,50,14 - CONTROL "",IDC_TREELIST,"PhTreeNew",WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP | 0x2,2,19,353,212,WS_EX_CLIENTEDGE CONTROL "&Regex",IDC_REGEX,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,263,6,34,10 COMBOBOX IDC_FILTERTYPE,165,4,93,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + CONTROL "",IDC_TREELIST,"PhTreeNew",WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP | 0x2,2,19,353,212,WS_EX_CLIENTEDGE END IDD_OBJTOKEN DIALOGEX 0, 0, 260, 260 From 8665d68c04044d1fc507d8e959ff850344213e60 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 31 Jul 2017 16:29:31 +1000 Subject: [PATCH 0327/2058] Fix find handle window not searching module original name --- ProcessHacker/findobj.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ProcessHacker/findobj.c b/ProcessHacker/findobj.c index c3dbb4eb6f3b..f0a0bb8ee4aa 100644 --- a/ProcessHacker/findobj.c +++ b/ProcessHacker/findobj.c @@ -860,11 +860,15 @@ static BOOLEAN NTAPI EnumModulesCallback( PSEARCH_MODULE_CONTEXT moduleContext = Context; PPH_HANDLE_SEARCH_CONTEXT context = moduleContext->WindowContext; PPH_STRING upperFileName; + PPH_STRING upperOriginalFileName; upperFileName = PhDuplicateString(Module->FileName); _wcsupr(upperFileName->Buffer); - if (MatchSearchString(context, &upperFileName->sr) || + upperOriginalFileName = PhDuplicateString(Module->OriginalFileName); + _wcsupr(upperOriginalFileName->Buffer); + + if ((MatchSearchString(context, &upperFileName->sr) || MatchSearchString(context, &upperOriginalFileName->sr)) || (context->UseSearchPointer && Module->BaseAddress == (PVOID)context->SearchPointer)) { PPHP_OBJECT_SEARCH_RESULT searchResult; @@ -898,6 +902,7 @@ static BOOLEAN NTAPI EnumModulesCallback( PhReleaseQueuedLockExclusive(&context->SearchResultsLock); } + PhDereferenceObject(upperOriginalFileName); PhDereferenceObject(upperFileName); return TRUE; From b3dcb0ad8b092a30d79fbad15cbcdd74307c0ea9 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 31 Jul 2017 18:12:44 +1000 Subject: [PATCH 0328/2058] Fix find handle crash when sorting ObjectAddress or OriginalName columns --- ProcessHacker/findobj.c | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/ProcessHacker/findobj.c b/ProcessHacker/findobj.c index f0a0bb8ee4aa..5cf0ab4a92e6 100644 --- a/ProcessHacker/findobj.c +++ b/ProcessHacker/findobj.c @@ -172,6 +172,18 @@ BEGIN_SORT_FUNCTION(Handle) } END_SORT_FUNCTION +BEGIN_SORT_FUNCTION(ObjectAddress) +{ + sortResult = uintptrcmp((ULONG_PTR)node1->HandleObject, (ULONG_PTR)node2->HandleObject); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(OriginalName) +{ + sortResult = PhCompareString(node1->ObjectNameString, node2->ObjectNameString, TRUE); +} +END_SORT_FUNCTION + VOID HandleObjectLoadSettingsTreeList( _Inout_ PPH_HANDLE_SEARCH_CONTEXT Context ) @@ -209,7 +221,7 @@ ULONG HandleObjectNodeHashtableHashFunction( _In_ PVOID Entry ) { - return PhHashIntPtr((ULONG_PTR)(*(PPH_HANDLE_OBJECT_TREE_ROOT_NODE*)Entry)->HandleObject); + return PhHashIntPtr((ULONG_PTR)(*(PPH_HANDLE_OBJECT_TREE_ROOT_NODE*)Entry)->Handle); } VOID DestroyHandleObjectNode( @@ -226,7 +238,6 @@ VOID DestroyHandleObjectNode( PPH_HANDLE_OBJECT_TREE_ROOT_NODE AddHandleObjectNode( _Inout_ PPH_HANDLE_SEARCH_CONTEXT Context, - _In_ PVOID HandleObject, _In_ HANDLE Handle ) { @@ -241,7 +252,6 @@ PPH_HANDLE_OBJECT_TREE_ROOT_NODE AddHandleObjectNode( handleObjectNode->Node.TextCache = handleObjectNode->TextCache; handleObjectNode->Node.TextCacheSize = TREE_COLUMN_ITEM_MAXIMUM; - handleObjectNode->HandleObject = HandleObject; handleObjectNode->Handle = Handle; PhAddEntryHashtable(Context->NodeHashtable, &handleObjectNode); @@ -254,14 +264,14 @@ PPH_HANDLE_OBJECT_TREE_ROOT_NODE AddHandleObjectNode( PPH_HANDLE_OBJECT_TREE_ROOT_NODE FindHandleObjectNode( _In_ PPH_HANDLE_SEARCH_CONTEXT Context, - _In_ PVOID HandleObject + _In_ HANDLE Handle ) { PH_HANDLE_OBJECT_TREE_ROOT_NODE lookupHandleObjectNode; PPH_HANDLE_OBJECT_TREE_ROOT_NODE lookupHandleObjectNodePtr = &lookupHandleObjectNode; PPH_HANDLE_OBJECT_TREE_ROOT_NODE *handleObjectNode; - lookupHandleObjectNode.HandleObject = HandleObject; + lookupHandleObjectNode.Handle = Handle; handleObjectNode = (PPH_HANDLE_OBJECT_TREE_ROOT_NODE*)PhFindEntryHashtable( Context->NodeHashtable, @@ -329,6 +339,8 @@ BOOLEAN NTAPI HandleObjectTreeNewCallback( SORT_FUNCTION(Type), SORT_FUNCTION(Name), SORT_FUNCTION(Handle), + SORT_FUNCTION(ObjectAddress), + SORT_FUNCTION(OriginalName) }; int (__cdecl *sortFunction)(void *, const void *, const void *); @@ -672,7 +684,7 @@ VOID PhpFindObjectAddResultEntries( processItem = PhReferenceProcessItem(clientId.UniqueProcess); - objectNode = AddHandleObjectNode(Context, searchResult->Object, searchResult->Handle); + objectNode = AddHandleObjectNode(Context, searchResult->Handle); objectNode->ProcessId = searchResult->ProcessId; objectNode->ResultType = searchResult->ResultType; objectNode->ClientIdName = PhGetClientIdNameEx(&clientId, processItem ? processItem->ProcessName : NULL); @@ -683,7 +695,10 @@ VOID PhpFindObjectAddResultEntries( PhPrintPointer(objectNode->HandleString, searchResult->Handle); if (searchResult->Object) + { + objectNode->HandleObject = searchResult->Object; PhPrintPointer(objectNode->ObjectString, searchResult->Object); + } PhDereferenceObject(processItem); } From a0c8bef525d263cd4f2c1c6c67d18d8ca11d9a5b Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 31 Jul 2017 18:49:48 +1000 Subject: [PATCH 0329/2058] NetworkTools: Add support for multiple traceroute results for the same hop --- plugins/NetworkTools/tracert.c | 66 ++++++++++++++++++++++++++++++---- 1 file changed, 59 insertions(+), 7 deletions(-) diff --git a/plugins/NetworkTools/tracert.c b/plugins/NetworkTools/tracert.c index 57bd18c03b4a..e26d8cf6647f 100644 --- a/plugins/NetworkTools/tracert.c +++ b/plugins/NetworkTools/tracert.c @@ -141,7 +141,23 @@ VOID TracertQueueHostLookup( if (NT_SUCCESS(RtlIpv4AddressToStringEx(&sockAddrIn, 0, addressString, &addressStringLength))) { - PhMoveReference(&Node->IpAddressString, PhCreateString(addressString)); + if (!PhIsNullOrEmptyString(Node->IpAddressString)) + { + // Make sure we don't append the same address. + if (PhFindStringInString(Node->IpAddressString, 0, addressString) == -1) + { + // Some routes can return multiple addresses for the same ping or 'hop', + // so make sure we don't lose this information (as every other tracert tool does) + // and instead append the additional IP address to the node. + PhMoveReference(&Node->IpAddressString, + PhFormatString(L"%s, %s", PhGetString(Node->IpAddressString), addressString) + ); + } + } + else + { + PhMoveReference(&Node->IpAddressString, PhCreateString(addressString)); + } } resolve = PhCreateAlloc(sizeof(TRACERT_RESOLVE_WORKITEM)); @@ -176,7 +192,23 @@ VOID TracertQueueHostLookup( if (NT_SUCCESS(RtlIpv6AddressToStringEx(&sockAddrIn6, 0, 0, addressString, &addressStringLength))) { - PhMoveReference(&Node->IpAddressString, PhCreateString(addressString)); + if (!PhIsNullOrEmptyString(Node->IpAddressString)) + { + // Make sure we don't append the same address. + if (PhFindStringInString(Node->IpAddressString, 0, addressString) == -1) + { + // Some routes can return multiple addresses for the same ping or 'hop', + // so make sure we don't lose this information (as every other tracert tool does) + // and instead append the additional IP address to the node. + PhMoveReference(&Node->IpAddressString, + PhFormatString(L"%s, %s", PhGetString(Node->IpAddressString), addressString) + ); + } + } + else + { + PhMoveReference(&Node->IpAddressString, PhCreateString(addressString)); + } } resolve = PhCreateAlloc(sizeof(TRACERT_RESOLVE_WORKITEM)); @@ -695,13 +727,33 @@ INT_PTR CALLBACK TracertDlgProc( PPH_STRING hostName = (PPH_STRING)lParam; PTRACERT_ROOT_NODE traceNode; - traceNode = FindTracertNode(context, index); - - if (traceNode) + if (traceNode = FindTracertNode(context, index)) { - PhMoveReference(&traceNode->HostnameString, hostName); + if (!PhIsNullOrEmptyString(traceNode->HostnameString)) + { + // Make sure we don't append the same hostname. + if (PhFindStringInString(traceNode->HostnameString, 0, PhGetString(hostName)) == -1) + { + // Some routes can return multiple addresses for the same ping or 'hop', + // so make sure we don't lose this information (as every other tracert tool does) + // and instead append the additional hostname to the node. + PhMoveReference(&traceNode->HostnameString, + PhFormatString(L"%s, %s", PhGetString(traceNode->HostnameString), PhGetString(hostName)) + ); + + UpdateTracertNode(context, traceNode); + } + else + { + PhDereferenceObject(hostName); + } + } + else + { + PhMoveReference(&traceNode->HostnameString, hostName); - UpdateTracertNode(context, traceNode); + UpdateTracertNode(context, traceNode); + } } else { From 16636d0a1caa7d2a610adcc896276e30d6d89d41 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 31 Jul 2017 19:03:58 +1000 Subject: [PATCH 0330/2058] NetworkTools: Fix use-after-free bug , Add refresh button to tracert window --- plugins/NetworkTools/NetworkTools.rc | 1 + plugins/NetworkTools/resource.h | 3 +- plugins/NetworkTools/tracert.c | 56 ++++++++++++++++++---------- plugins/NetworkTools/tracert.h | 4 ++ 4 files changed, 43 insertions(+), 21 deletions(-) diff --git a/plugins/NetworkTools/NetworkTools.rc b/plugins/NetworkTools/NetworkTools.rc index 928883c44c71..7f639e93aebd 100644 --- a/plugins/NetworkTools/NetworkTools.rc +++ b/plugins/NetworkTools/NetworkTools.rc @@ -135,6 +135,7 @@ BEGIN LTEXT "Tracing route to xyz...",IDC_STATUS,7,5,375,12 DEFPUSHBUTTON "Close",IDCANCEL,333,191,50,14 CONTROL "",IDC_LIST_TRACERT,"PhTreeNew",WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP | 0xa,7,22,375,166,WS_EX_CLIENTEDGE + PUSHBUTTON "Refresh",IDC_REFRESH,279,191,50,14 END diff --git a/plugins/NetworkTools/resource.h b/plugins/NetworkTools/resource.h index 84bd7f5c868c..204de7750856 100644 --- a/plugins/NetworkTools/resource.h +++ b/plugins/NetworkTools/resource.h @@ -269,6 +269,7 @@ #define IDC_STATUS 1023 #define IDC_GEOIP 1028 #define IDC_LIST_TRACERT 1030 +#define IDC_REFRESH 1031 // Next default values for new objects // @@ -276,7 +277,7 @@ #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 107 #define _APS_NEXT_COMMAND_VALUE 40006 -#define _APS_NEXT_CONTROL_VALUE 1031 +#define _APS_NEXT_CONTROL_VALUE 1032 #define _APS_NEXT_SYMED_VALUE 104 #endif #endif diff --git a/plugins/NetworkTools/tracert.c b/plugins/NetworkTools/tracert.c index e26d8cf6647f..ce47aaaada97 100644 --- a/plugins/NetworkTools/tracert.c +++ b/plugins/NetworkTools/tracert.c @@ -438,9 +438,9 @@ NTSTATUS NetworkTracertThreadStart( IcmpCloseHandle(icmpHandle); } - PhDereferenceObject(context); - PostMessage(context->WindowHandle, NTM_RECEIVEDFINISH, 0, 0); + + PhDereferenceObject(context); return STATUS_SUCCESS; } @@ -630,14 +630,16 @@ INT_PTR CALLBACK TracertDlgProc( PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_STATUS), NULL, PH_ANCHOR_TOP | PH_ANCHOR_LEFT | PH_ANCHOR_RIGHT | PH_LAYOUT_FORCE_INVALIDATE); PhAddLayoutItem(&context->LayoutManager, context->TreeNewHandle, NULL, PH_ANCHOR_ALL); PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDCANCEL), NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_RIGHT); + PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_REFRESH), NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_RIGHT); if (PhGetIntegerPairSetting(SETTING_NAME_TRACERT_WINDOW_POSITION).X != 0) PhLoadWindowPlacementFromSetting(SETTING_NAME_TRACERT_WINDOW_POSITION, SETTING_NAME_TRACERT_WINDOW_SIZE, hwndDlg); else PhCenterWindow(hwndDlg, PhMainWndHandle); - PhReferenceObject(context); + EnableWindow(GetDlgItem(hwndDlg, IDC_REFRESH), FALSE); + PhReferenceObject(context); PhCreateThread2(NetworkTracertThreadStart, (PVOID)context); EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); @@ -650,6 +652,26 @@ INT_PTR CALLBACK TracertDlgProc( case IDCANCEL: DestroyWindow(hwndDlg); break; + case IDC_REFRESH: + { + Static_SetText(context->WindowHandle, PhaFormatString( + L"Tracing %s...", + context->IpAddressString + )->Buffer); + Static_SetText(GetDlgItem(hwndDlg, IDC_STATUS), PhaFormatString( + L"Tracing route to %s with %lu bytes of data....", + context->IpAddressString, + PhGetIntegerSetting(SETTING_NAME_PING_SIZE) + )->Buffer); + + EnableWindow(GetDlgItem(hwndDlg, IDC_REFRESH), FALSE); + + ClearTracertTree(context); + + PhReferenceObject(context); + PhCreateThread2(NetworkTracertThreadStart, (PVOID)context); + } + break; case TRACERT_SHOWCONTEXTMENU: { PPH_EMENU menu; @@ -700,24 +722,18 @@ INT_PTR CALLBACK TracertDlgProc( break; case NTM_RECEIVEDFINISH: { - PPH_STRING windowText; + EnableWindow(GetDlgItem(hwndDlg, IDC_REFRESH), TRUE); + + Static_SetText(context->WindowHandle, PhaFormatString( + L"Tracing %s... Complete", + context->IpAddressString + )->Buffer); + Static_SetText(GetDlgItem(hwndDlg, IDC_STATUS), PhaFormatString( + L"Tracing route to %s with %lu bytes of data... Complete.", + context->IpAddressString, + PhGetIntegerSetting(SETTING_NAME_PING_SIZE) + )->Buffer); - if (windowText = PH_AUTO(PhGetWindowText(context->WindowHandle))) - { - Static_SetText( - context->WindowHandle, - PhaFormatString(L"%s complete", windowText->Buffer)->Buffer - ); - } - - if (windowText = PH_AUTO(PhGetWindowText(GetDlgItem(hwndDlg, IDC_STATUS)))) - { - Static_SetText( - GetDlgItem(hwndDlg, IDC_STATUS), - PhaFormatString(L"%s complete", windowText->Buffer)->Buffer - ); - } - TreeNew_NodesStructured(context->TreeNewHandle); } break; diff --git a/plugins/NetworkTools/tracert.h b/plugins/NetworkTools/tracert.h index 817a5f3f0c78..843ef15ad83f 100644 --- a/plugins/NetworkTools/tracert.h +++ b/plugins/NetworkTools/tracert.h @@ -104,6 +104,10 @@ TracertGetFilterSupportTreeList( VOID ); +VOID ClearTracertTree( + _In_ PNETWORK_TRACERT_CONTEXT Context + ); + PTRACERT_ROOT_NODE GetSelectedTracertNode( _In_ PNETWORK_TRACERT_CONTEXT Context ); From b35e5243e2bbfb3f27e9a256863c8e4c688cf2c6 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 31 Jul 2017 19:05:48 +1000 Subject: [PATCH 0331/2058] NetworkTools: Fix tracert text capitalization --- plugins/NetworkTools/tracert.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/NetworkTools/tracert.c b/plugins/NetworkTools/tracert.c index ce47aaaada97..eb5d39c5a0fc 100644 --- a/plugins/NetworkTools/tracert.c +++ b/plugins/NetworkTools/tracert.c @@ -725,11 +725,11 @@ INT_PTR CALLBACK TracertDlgProc( EnableWindow(GetDlgItem(hwndDlg, IDC_REFRESH), TRUE); Static_SetText(context->WindowHandle, PhaFormatString( - L"Tracing %s... Complete", + L"Tracing %s... complete", context->IpAddressString )->Buffer); Static_SetText(GetDlgItem(hwndDlg, IDC_STATUS), PhaFormatString( - L"Tracing route to %s with %lu bytes of data... Complete.", + L"Tracing route to %s with %lu bytes of data... complete.", context->IpAddressString, PhGetIntegerSetting(SETTING_NAME_PING_SIZE) )->Buffer); From 887b0fa754140bd76f9d0d9ab0b1922376081ca1 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 31 Jul 2017 21:00:22 +1000 Subject: [PATCH 0332/2058] NetworkTools: Fix tracert refresh button not updating nodes --- plugins/NetworkTools/tracetree.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/NetworkTools/tracetree.c b/plugins/NetworkTools/tracetree.c index 12aa70e1265c..1cf94b79f2ac 100644 --- a/plugins/NetworkTools/tracetree.c +++ b/plugins/NetworkTools/tracetree.c @@ -472,6 +472,8 @@ VOID ClearTracertTree( PhClearHashtable(Context->NodeHashtable); PhClearList(Context->NodeList); + + TreeNew_NodesStructured(Context->TreeNewHandle); } PTRACERT_ROOT_NODE GetSelectedTracertNode( From 9317b9f3d6b503957182eae0943ffe70c531c0a4 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 31 Jul 2017 21:00:48 +1000 Subject: [PATCH 0333/2058] Remove unused field from find handles window --- ProcessHacker/findobj.c | 1 - 1 file changed, 1 deletion(-) diff --git a/ProcessHacker/findobj.c b/ProcessHacker/findobj.c index 5cf0ab4a92e6..1e06baf50a0d 100644 --- a/ProcessHacker/findobj.c +++ b/ProcessHacker/findobj.c @@ -60,7 +60,6 @@ typedef struct _PH_HANDLE_SEARCH_CONTEXT PH_SORT_ORDER TreeNewSortOrder; PPH_HASHTABLE NodeHashtable; PPH_LIST NodeList; - PPH_LIST NodeRootList; HANDLE TimerQueueHandle; HANDLE UpdateTimerHandle; From 5460d9f1d3c04ddbc102a8e01c9e5a87715a0421 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 1 Aug 2017 12:20:01 +1000 Subject: [PATCH 0334/2058] Add subprocess column (feature request) --- ProcessHacker/include/proctree.h | 4 +++- ProcessHacker/proctree.c | 8 ++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/ProcessHacker/include/proctree.h b/ProcessHacker/include/proctree.h index 23c30a4f3b66..4c9ab88a7ab2 100644 --- a/ProcessHacker/include/proctree.h +++ b/ProcessHacker/include/proctree.h @@ -89,8 +89,9 @@ #define PHPRTLC_TIMESTAMP 76 #define PHPRTLC_FILEMODIFIEDTIME 77 #define PHPRTLC_FILESIZE 78 +#define PHPRTLC_SUBPROCESSCOUNT 79 -#define PHPRTLC_MAXIMUM 79 +#define PHPRTLC_MAXIMUM 80 #define PHPRTLC_IOGROUP_COUNT 9 #define PHPN_WSCOUNTERS 0x1 @@ -213,6 +214,7 @@ typedef struct _PH_PROCESS_NODE PPH_STRING TimeStampText; PPH_STRING FileModifiedTimeText; PPH_STRING FileSizeText; + PPH_STRING SubprocessCountText; // Graph buffers PH_GRAPH_BUFFERS CpuGraphBuffers; diff --git a/ProcessHacker/proctree.c b/ProcessHacker/proctree.c index a6cd292c6846..a7ce40df47a1 100644 --- a/ProcessHacker/proctree.c +++ b/ProcessHacker/proctree.c @@ -207,6 +207,7 @@ VOID PhInitializeProcessTreeList( PhAddTreeNewColumnEx(hwnd, PHPRTLC_TIMESTAMP, FALSE, L"Time stamp", 140, PH_ALIGN_LEFT, -1, 0, TRUE); PhAddTreeNewColumnEx(hwnd, PHPRTLC_FILEMODIFIEDTIME, FALSE, L"File modified time", 140, PH_ALIGN_LEFT, -1, 0, TRUE); PhAddTreeNewColumnEx(hwnd, PHPRTLC_FILESIZE, FALSE, L"File size", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_SUBPROCESSCOUNT, FALSE, L"Subprocesses", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); TreeNew_SetRedraw(hwnd, TRUE); @@ -561,6 +562,7 @@ VOID PhpRemoveProcessNode( PhClearReference(&ProcessNode->TimeStampText); PhClearReference(&ProcessNode->FileModifiedTimeText); PhClearReference(&ProcessNode->FileSizeText); + PhClearReference(&ProcessNode->SubprocessCountText); PhDeleteGraphBuffers(&ProcessNode->CpuGraphBuffers); PhDeleteGraphBuffers(&ProcessNode->PrivateGraphBuffers); @@ -2572,6 +2574,12 @@ BOOLEAN NTAPI PhpProcessTreeNewCallback( getCellText->Text = node->FileSizeText->sr; } break; + case PHPRTLC_SUBPROCESSCOUNT: + { + PhMoveReference(&node->SubprocessCountText, PhFormatUInt64(node->Children->Count, -1)); + getCellText->Text = node->SubprocessCountText->sr; + } + break; default: return FALSE; } From 881f99636b96b99676624eace30f4c0f0ed200f7 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 1 Aug 2017 18:29:54 +1000 Subject: [PATCH 0335/2058] Fix subprocesses column sorting --- ProcessHacker/proctree.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/ProcessHacker/proctree.c b/ProcessHacker/proctree.c index a7ce40df47a1..f0c591107a01 100644 --- a/ProcessHacker/proctree.c +++ b/ProcessHacker/proctree.c @@ -1769,6 +1769,12 @@ BEGIN_SORT_FUNCTION(FileSize) } END_SORT_FUNCTION +BEGIN_SORT_FUNCTION(Subprocesses) +{ + sortResult = int64cmp(node1->Children->Count, node2->Children->Count); +} +END_SORT_FUNCTION + BOOLEAN NTAPI PhpProcessTreeNewCallback( _In_ HWND hwnd, _In_ PH_TREENEW_MESSAGE Message, @@ -1887,7 +1893,8 @@ BOOLEAN NTAPI PhpProcessTreeNewCallback( SORT_FUNCTION(CfGuard), SORT_FUNCTION(TimeStamp), SORT_FUNCTION(FileModifiedTime), - SORT_FUNCTION(FileSize) + SORT_FUNCTION(FileSize), + SORT_FUNCTION(Subprocesses) }; int (__cdecl *sortFunction)(const void *, const void *); From 14f52afb70235a3bf4eff6da9072ed1515b2aaf7 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 1 Aug 2017 18:33:59 +1000 Subject: [PATCH 0336/2058] Fix typo --- ProcessHacker/proctree.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ProcessHacker/proctree.c b/ProcessHacker/proctree.c index f0c591107a01..c45faf671101 100644 --- a/ProcessHacker/proctree.c +++ b/ProcessHacker/proctree.c @@ -2583,7 +2583,7 @@ BOOLEAN NTAPI PhpProcessTreeNewCallback( break; case PHPRTLC_SUBPROCESSCOUNT: { - PhMoveReference(&node->SubprocessCountText, PhFormatUInt64(node->Children->Count, -1)); + PhMoveReference(&node->SubprocessCountText, PhFormatUInt64(node->Children->Count, TRUE)); getCellText->Text = node->SubprocessCountText->sr; } break; From 829154d8dc02bf272d943f5de6ac58a4fc04ed52 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 2 Aug 2017 21:52:04 +1000 Subject: [PATCH 0337/2058] Update ntpsapi with undocumented JobObjectInformation classes --- phnt/include/ntpsapi.h | 49 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/phnt/include/ntpsapi.h b/phnt/include/ntpsapi.h index 1be1843f6e1f..286184cee8bb 100644 --- a/phnt/include/ntpsapi.h +++ b/phnt/include/ntpsapi.h @@ -1561,6 +1561,55 @@ NtCreateThreadEx( #if (PHNT_MODE != PHNT_MODE_KERNEL) +#define JobObjectBasicAccountingInformation 1 +#define JobObjectBasicLimitInformation 2 +#define JobObjectBasicProcessIdList 3 +#define JobObjectBasicUIRestrictions 4 +#define JobObjectSecurityLimitInformation 5 +#define JobObjectEndOfJobTimeInformation 6 +#define JobObjectAssociateCompletionPortInformation 7 +#define JobObjectBasicAndIoAccountingInformation 8 +#define JobObjectExtendedLimitInformation 9 +#define JobObjectJobSetInformation 10 +#define JobObjectGroupInformation 11 +#define JobObjectNotificationLimitInformation 12 +#define JobObjectLimitViolationInformation 13 +#define JobObjectGroupInformationEx 14 +#define JobObjectCpuRateControlInformation 15 +#define JobObjectCompletionFilter 16 +#define JobObjectCompletionCounter 17 +#define JobObjectFreezeInformation 18 +#define JobObjectExtendedAccountingInformation 19 +#define JobObjectWakeInformation 20 +#define JobObjectBackgroundInformation 21 +#define JobObjectSchedulingRankBiasInformation 22 +#define JobObjectTimerVirtualizationInformation 23 +#define JobObjectCycleTimeNotification 24 +#define JobObjectClearEvent 25 +#define JobObjectInterferenceInformation 26 +#define JobObjectClearPeakJobMemoryUsed 27 +#define JobObjectMemoryUsageInformation 28 +#define JobObjectSharedCommit 29 +#define JobObjectContainerId 30 +#define JobObjectIoRateControlInformation 31 +#define JobObjectNetRateControlInformation 32 +#define JobObjectNotificationLimitInformation2 33 +#define JobObjectLimitViolationInformation2 34 +#define JobObjectCreateSilo 35 +#define JobObjectSiloBasicInformation 36 +#define JobObjectSiloRootDirectory 37 +#define JobObjectServerSiloBasicInformation 38 +#define JobObjectServerSiloUserSharedData 39 +#define JobObjectServerSiloInitialize 40 +#define JobObjectServerSiloRunningState 41 +#define JobObjectIoAttribution 42 +#define JobObjectMemoryPartitionInformation 43 +#define JobObjectContainerTelemetryId 44 +#define JobObjectSiloSystemRoot 45 +#define JobObjectEnergyTrackingState 46 +#define JobObjectThreadImpersonationInformation 47 +#define MaxJobObjectInfoClass 48 + NTSYSCALLAPI NTSTATUS NTAPI From 01779e65f0197ee1490722c3db4f4093650172ae Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 2 Aug 2017 23:44:11 +1000 Subject: [PATCH 0338/2058] Update ntpsapi with undocumented JobObjectInformation structs --- phnt/include/ntpsapi.h | 104 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) diff --git a/phnt/include/ntpsapi.h b/phnt/include/ntpsapi.h index 286184cee8bb..cc957c2baf71 100644 --- a/phnt/include/ntpsapi.h +++ b/phnt/include/ntpsapi.h @@ -1561,6 +1561,7 @@ NtCreateThreadEx( #if (PHNT_MODE != PHNT_MODE_KERNEL) +// JOBOBJECTINFOCLASS #define JobObjectBasicAccountingInformation 1 #define JobObjectBasicLimitInformation 2 #define JobObjectBasicProcessIdList 3 @@ -1610,6 +1611,109 @@ NtCreateThreadEx( #define JobObjectThreadImpersonationInformation 47 #define MaxJobObjectInfoClass 48 +// private +typedef struct _JOBOBJECT_EXTENDED_ACCOUNTING_INFORMATION +{ + JOBOBJECT_BASIC_ACCOUNTING_INFORMATION BasicInfo; + IO_COUNTERS IoInfo; + PROCESS_DISK_COUNTERS DiskIoInfo; + ULONG64 ContextSwitches; + LARGE_INTEGER TotalCycleTime; + ULONG64 ReadyTime; + PROCESS_ENERGY_VALUES EnergyValues; +} JOBOBJECT_EXTENDED_ACCOUNTING_INFORMATION, *PJOBOBJECT_EXTENDED_ACCOUNTING_INFORMATION; + +// private +typedef struct _JOBOBJECT_WAKE_INFORMATION +{ + HANDLE NotificationChannel; + ULONG64 WakeCounters[7]; +} JOBOBJECT_WAKE_INFORMATION, *PJOBOBJECT_WAKE_INFORMATION; + +// private +typedef struct _JOBOBJECT_WAKE_INFORMATION_V1 +{ + HANDLE NotificationChannel; + ULONG64 WakeCounters[4]; +} JOBOBJECT_WAKE_INFORMATION_V1, *PJOBOBJECT_WAKE_INFORMATION_V1; + +// private +typedef struct _JOBOBJECT_INTERFERENCE_INFORMATION +{ + ULONG64 Count; +} JOBOBJECT_INTERFERENCE_INFORMATION, *PJOBOBJECT_INTERFERENCE_INFORMATION; + +// private +typedef struct _JOBOBJECT_WAKE_FILTER +{ + ULONG HighEdgeFilter; + ULONG LowEdgeFilter; +} JOBOBJECT_WAKE_FILTER, *PJOBOBJECT_WAKE_FILTER; + +// private +typedef struct _JOBOBJECT_FREEZE_INFORMATION +{ + union + { + ULONG Flags; + struct + { + ULONG FreezeOperation : 1; + ULONG FilterOperation : 1; + ULONG SwapOperation : 1; + ULONG Reserved : 29; + }; + }; + BOOLEAN Freeze; + BOOLEAN Swap; + UCHAR Reserved0[2]; + JOBOBJECT_WAKE_FILTER WakeFilter; +} JOBOBJECT_FREEZE_INFORMATION, *PJOBOBJECT_FREEZE_INFORMATION; + +// private +typedef struct _JOBOBJECT_MEMORY_USAGE_INFORMATION +{ + ULONG64 JobMemory; + ULONG64 PeakJobMemoryUsed; +} JOBOBJECT_MEMORY_USAGE_INFORMATION, *PJOBOBJECT_MEMORY_USAGE_INFORMATION; + +// private +typedef struct _JOBOBJECT_MEMORY_USAGE_INFORMATION_V2 +{ + JOBOBJECT_MEMORY_USAGE_INFORMATION BasicInfo; + ULONG64 JobSharedMemory; + ULONG64 Reserved[2]; +} JOBOBJECT_MEMORY_USAGE_INFORMATION_V2, *PJOBOBJECT_MEMORY_USAGE_INFORMATION_V2; + +// private +typedef struct _SILO_USER_SHARED_DATA +{ + ULONG64 ServiceSessionId; + ULONG ActiveConsoleId; + LONGLONG ConsoleSessionForegroundProcessId; + NT_PRODUCT_TYPE NtProductType; + ULONG SuiteMask; + ULONG SharedUserSessionId; + BOOLEAN IsMultiSessionSku; + WCHAR NtSystemRoot[260]; + USHORT UserModeGlobalLogger[16]; +} SILO_USER_SHARED_DATA, *PSILO_USER_SHARED_DATA; + +// private +typedef struct _SILOOBJECT_ROOT_DIRECTORY +{ + ULONG ControlFlags; + UNICODE_STRING Path; +} SILOOBJECT_ROOT_DIRECTORY, *PSILOOBJECT_ROOT_DIRECTORY; + +// private +typedef struct _JOBOBJECT_ENERGY_TRACKING_STATE +{ + ULONG64 Value; + ULONG UpdateMask; + ULONG DesiredState; +} JOBOBJECT_ENERGY_TRACKING_STATE, *PJOBOBJECT_ENERGY_TRACKING_STATE; + NTSYSCALLAPI NTSTATUS NTAPI From cf57a21a132d8577c6226d0c7fb568fa4fe42df5 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 2 Aug 2017 23:47:33 +1000 Subject: [PATCH 0339/2058] Add HiddenProcessesMenuEnabled setting, Update hidden process detection window icon --- ProcessHacker/hidnproc.c | 5 ++++- ProcessHacker/mainwnd.c | 9 +++++---- ProcessHacker/settings.c | 1 + 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/ProcessHacker/hidnproc.c b/ProcessHacker/hidnproc.c index f30b4f664328..f3b342c8c2fc 100644 --- a/ProcessHacker/hidnproc.c +++ b/ProcessHacker/hidnproc.c @@ -101,7 +101,7 @@ VOID PhShowHiddenProcessesDialog( PhHiddenProcessesWindowHandle = CreateDialog( PhInstanceHandle, MAKEINTRESOURCE(IDD_HIDDENPROCESSES), - PhMainWndHandle, + NULL, PhpHiddenProcessesDlgProc ); } @@ -125,6 +125,9 @@ static INT_PTR CALLBACK PhpHiddenProcessesDlgProc( { HWND lvHandle; + SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER))); + SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER))); + PhCenterWindow(hwndDlg, GetParent(hwndDlg)); PhHiddenProcessesListViewHandle = lvHandle = GetDlgItem(hwndDlg, IDC_PROCESSES); diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index f30c396d2eb5..184825f5cf2a 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -2761,10 +2761,11 @@ VOID PhMwpInitializeSubMenu( } else if (Index == 2) // Tools { -#ifdef _WIN64 - if (menuItem = PhFindEMenuItem(Menu, 0, NULL, ID_TOOLS_HIDDENPROCESSES)) - PhDestroyEMenuItem(menuItem); -#endif + if (!PhGetIntegerSetting(L"HiddenProcessesMenuEnabled")) + { + if (menuItem = PhFindEMenuItem(Menu, 0, NULL, ID_TOOLS_HIDDENPROCESSES)) + PhDestroyEMenuItem(menuItem); + } // Windows 8 Task Manager requires elevation. if (WindowsVersion >= WINDOWS_8 && !PhGetOwnTokenAttributes().Elevated) diff --git a/ProcessHacker/settings.c b/ProcessHacker/settings.c index 1df0dbb05dfb..94df736bbbee 100644 --- a/ProcessHacker/settings.c +++ b/ProcessHacker/settings.c @@ -59,6 +59,7 @@ VOID PhAddDefaultSettings( PhpAddIntegerSetting(L"ForceNoParent", L"0"); PhpAddStringSetting(L"HandleTreeListColumns", L""); PhpAddStringSetting(L"HandleTreeListSort", L"0,1"); // 0, AscendingSortOrder + PhpAddIntegerSetting(L"HiddenProcessesMenuEnabled", L"0"); PhpAddStringSetting(L"HiddenProcessesListViewColumns", L""); PhpAddIntegerPairSetting(L"HiddenProcessesWindowPosition", L"400,400"); PhpAddScalableIntegerPairSetting(L"HiddenProcessesWindowSize", L"@96|520,400"); From 651adee893bded681e11212c5a808653c2670989 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 3 Aug 2017 00:05:02 +1000 Subject: [PATCH 0340/2058] Tidy up class names --- ProcessHacker/ProcessHacker.rc | 2 +- ProcessHacker/options.c | 2 +- ProcessHacker/proctree.c | 10 +++++----- ProcessHacker/sysinfo.c | 6 +++--- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/ProcessHacker/ProcessHacker.rc b/ProcessHacker/ProcessHacker.rc index 1e94724c23cd..6ab929d692fc 100644 --- a/ProcessHacker/ProcessHacker.rc +++ b/ProcessHacker/ProcessHacker.rc @@ -758,7 +758,7 @@ BEGIN END IDD_HIDDENPROCESSES DIALOGEX 0, 0, 337, 221 -STYLE DS_SETFONT | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME +STYLE DS_SETFONT | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME CAPTION "Hidden Processes" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN diff --git a/ProcessHacker/options.c b/ProcessHacker/options.c index 9e0232f4b06f..0c5ea7c7f833 100644 --- a/ProcessHacker/options.c +++ b/ProcessHacker/options.c @@ -279,7 +279,7 @@ static VOID PhpPageInit( MapWindowPoints(NULL, optionsWindow, (POINT *)&rect, 2); resetButton = CreateWindowEx( WS_EX_NOPARENTNOTIFY, - L"BUTTON", + WC_BUTTON, L"Reset", WS_CHILD | WS_VISIBLE | WS_TABSTOP, clientRect.right - rect.right, diff --git a/ProcessHacker/proctree.c b/ProcessHacker/proctree.c index c45faf671101..22a3d5ad63ec 100644 --- a/ProcessHacker/proctree.c +++ b/ProcessHacker/proctree.c @@ -1028,17 +1028,17 @@ static VOID PhpUpdateProcessNodeImage( { if (!(ProcessNode->ValidMask & PHPN_IMAGE)) { - HANDLE processHandle; - PROCESS_BASIC_INFORMATION basicInfo; - PVOID imageBaseAddress; - PH_REMOTE_MAPPED_IMAGE mappedImage; - if (ProcessNode->ProcessItem->IsSubsystemProcess) { ProcessNode->ImageSubsystem = IMAGE_SUBSYSTEM_POSIX_CUI; } else { + HANDLE processHandle; + PROCESS_BASIC_INFORMATION basicInfo; + PVOID imageBaseAddress; + PH_REMOTE_MAPPED_IMAGE mappedImage; + if (NT_SUCCESS(PhOpenProcess(&processHandle, ProcessQueryAccess | PROCESS_VM_READ, ProcessNode->ProcessId))) { if (NT_SUCCESS(PhGetProcessBasicInformation(processHandle, &basicInfo)) && basicInfo.PebBaseAddress != 0) diff --git a/ProcessHacker/sysinfo.c b/ProcessHacker/sysinfo.c index 4e8f019f4ff3..55513f538b9a 100644 --- a/ProcessHacker/sysinfo.c +++ b/ProcessHacker/sysinfo.c @@ -390,7 +390,7 @@ VOID PhSipOnShowWindow( } SeparatorControl = CreateWindow( - L"STATIC", + WC_STATIC, NULL, WS_CHILD | SS_OWNERDRAW, 0, @@ -404,7 +404,7 @@ VOID PhSipOnShowWindow( ); RestoreSummaryControl = CreateWindow( - L"STATIC", + WC_STATIC, NULL, WS_CHILD | WS_TABSTOP | SS_OWNERDRAW | SS_NOTIFY, 0, @@ -1143,7 +1143,7 @@ PPH_SYSINFO_SECTION PhSipCreateSection( section->PanelId = IDDYNAMIC + SectionList->Count * 2 + 2; section->PanelHandle = CreateWindow( - L"STATIC", + WC_STATIC, NULL, WS_CHILD | SS_OWNERDRAW | SS_NOTIFY, 0, From 123be3619130b07f7c98caef8182f36fe7513547 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 3 Aug 2017 17:00:12 +1000 Subject: [PATCH 0341/2058] Fix debug menu not launching 32bit debugger for WoW64 processes --- ProcessHacker/actions.c | 55 +++++++++++++++++++++-------------------- 1 file changed, 28 insertions(+), 27 deletions(-) diff --git a/ProcessHacker/actions.c b/ProcessHacker/actions.c index d039f5ed237b..71ead0b015a2 100644 --- a/ProcessHacker/actions.c +++ b/ProcessHacker/actions.c @@ -59,7 +59,6 @@ static PWSTR DangerousProcesses[] = }; static PPH_STRING DebuggerCommand = NULL; -static PH_INITONCE DebuggerCommandInitOnce = PH_INITONCE_INIT; static ULONG PhSvcReferenceCount = 0; static PH_PHSVC_MODE PhSvcCurrentMode; static PH_QUEUED_LOCK PhSvcStartLock = PH_QUEUED_LOCK_INIT; @@ -1397,9 +1396,17 @@ BOOLEAN PhUiDebugProcess( _In_ PPH_PROCESS_ITEM Process ) { + static PH_STRINGREF aeDebugKeyName = PH_STRINGREF_INIT(L"Software\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug"); +#ifdef _WIN64 + static PH_STRINGREF aeDebugWow64KeyName = PH_STRINGREF_INIT(L"Software\\Wow6432Node\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug"); +#endif NTSTATUS status; BOOLEAN cont = FALSE; PH_STRING_BUILDER commandLineBuilder; + HANDLE keyHandle; + PPH_STRING debugger; + PH_STRINGREF commandPart; + PH_STRINGREF dummy; if (PhGetIntegerSetting(L"EnableWarnings")) { @@ -1419,39 +1426,33 @@ BOOLEAN PhUiDebugProcess( if (!cont) return FALSE; - if (PhBeginInitOnce(&DebuggerCommandInitOnce)) - { - static PH_STRINGREF aeDebugKeyName = PH_STRINGREF_INIT(L"Software\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug"); - - HANDLE keyHandle; - PPH_STRING debugger; - PH_STRINGREF commandPart; - PH_STRINGREF dummy; + status = PhOpenKey( + &keyHandle, + KEY_READ, + PH_KEY_LOCAL_MACHINE, +#ifdef _WIN64 + Process->IsWow64 ? &aeDebugWow64KeyName : &aeDebugKeyName, +#else + &aeDebugKeyName, +#endif + 0 + ); - if (NT_SUCCESS(PhOpenKey( - &keyHandle, - KEY_READ, - PH_KEY_LOCAL_MACHINE, - &aeDebugKeyName, - 0 - ))) + if (NT_SUCCESS(status)) + { + if (debugger = PH_AUTO(PhQueryRegistryString(keyHandle, L"Debugger"))) { - if (debugger = PH_AUTO(PhQueryRegistryString(keyHandle, L"Debugger"))) + if (PhSplitStringRefAtChar(&debugger->sr, '"', &dummy, &commandPart) && + PhSplitStringRefAtChar(&commandPart, '"', &commandPart, &dummy)) { - if (PhSplitStringRefAtChar(&debugger->sr, '"', &dummy, &commandPart) && - PhSplitStringRefAtChar(&commandPart, '"', &commandPart, &dummy)) - { - DebuggerCommand = PhCreateString2(&commandPart); - } + DebuggerCommand = PhCreateString2(&commandPart); } - - NtClose(keyHandle); } - PhEndInitOnce(&DebuggerCommandInitOnce); + NtClose(keyHandle); } - if (!DebuggerCommand) + if (PhIsNullOrEmptyString(DebuggerCommand)) { PhShowError(hWnd, L"Unable to locate the debugger."); return FALSE; @@ -1462,7 +1463,7 @@ BOOLEAN PhUiDebugProcess( PhAppendCharStringBuilder(&commandLineBuilder, '"'); PhAppendStringBuilder(&commandLineBuilder, &DebuggerCommand->sr); PhAppendCharStringBuilder(&commandLineBuilder, '"'); - PhAppendFormatStringBuilder(&commandLineBuilder, L" -p %u", HandleToUlong(Process->ProcessId)); + PhAppendFormatStringBuilder(&commandLineBuilder, L" -p %lu", HandleToUlong(Process->ProcessId)); status = PhCreateProcessWin32( NULL, From 581416405e399cbbae53854678b8d78e95ac36c4 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 3 Aug 2017 21:21:12 +1000 Subject: [PATCH 0342/2058] Add status message when KPH fails to load --- ProcessHacker/main.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/ProcessHacker/main.c b/ProcessHacker/main.c index 216a7f81a09a..0d1cc99b1db5 100644 --- a/ProcessHacker/main.c +++ b/ProcessHacker/main.c @@ -558,6 +558,7 @@ VOID PhInitializeKph( { static PH_STRINGREF kprocesshacker = PH_STRINGREF_INIT(L"kprocesshacker.sys"); static PH_STRINGREF processhackerSig = PH_STRINGREF_INIT(L"ProcessHacker.sig"); + NTSTATUS status; PPH_STRING kprocesshackerFileName; PPH_STRING processhackerSigFileName; KPH_PARAMETERS parameters; @@ -573,7 +574,11 @@ VOID PhInitializeKph( parameters.SecurityLevel = KphSecuritySignatureCheck; parameters.CreateDynamicConfiguration = TRUE; - if (NT_SUCCESS(KphConnect2Ex(KPH_DEVICE_SHORT_NAME, kprocesshackerFileName->Buffer, ¶meters))) + if (NT_SUCCESS(status = KphConnect2Ex( + KPH_DEVICE_SHORT_NAME, + kprocesshackerFileName->Buffer, + ¶meters + ))) { if (signature = PhpReadSignature(processhackerSigFileName->Buffer, &signatureSize)) { @@ -581,6 +586,10 @@ VOID PhInitializeKph( PhFree(signature); } } + else + { + PhShowStatus(NULL, L"Unable to load the kernel driver.", status, 0); + } PhDereferenceObject(kprocesshackerFileName); PhDereferenceObject(processhackerSigFileName); From 5eb68bb76dcacb5ff8d9f756634af9c6b12354d7 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 3 Aug 2017 21:22:00 +1000 Subject: [PATCH 0343/2058] OnlineChecks: Move sendto menu on the modules tab --- plugins/OnlineChecks/main.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/plugins/OnlineChecks/main.c b/plugins/OnlineChecks/main.c index dc1ee8297a9d..faaf6dc9c7fe 100644 --- a/plugins/OnlineChecks/main.c +++ b/plugins/OnlineChecks/main.c @@ -258,6 +258,7 @@ VOID NTAPI MainMenuInitializingCallback( } PPH_EMENU_ITEM CreateSendToMenu( + _In_ BOOLEAN ProcessesMenu, _In_ PPH_EMENU_ITEM Parent, _In_ PPH_STRING FileName ) @@ -270,7 +271,7 @@ PPH_EMENU_ITEM CreateSendToMenu( PhInsertEMenuItem(sendToMenu, PhPluginCreateEMenuItem(PluginInstance, 0, MENUITEM_VIRUSTOTAL_UPLOAD, L"virustotal.com", FileName), -1); PhInsertEMenuItem(sendToMenu, PhPluginCreateEMenuItem(PluginInstance, 0, MENUITEM_JOTTI_UPLOAD, L"virusscan.jotti.org", FileName), -1); - if (menuItem = PhFindEMenuItem(Parent, PH_EMENU_FIND_STARTSWITH, L"Search online", 0)) + if (ProcessesMenu && (menuItem = PhFindEMenuItem(Parent, PH_EMENU_FIND_STARTSWITH, L"Search online", 0))) { insertIndex = PhIndexOfEMenuItem(Parent, menuItem); PhInsertEMenuItem(Parent, sendToMenu, insertIndex + 1); @@ -299,7 +300,7 @@ VOID NTAPI ProcessMenuInitializingCallback( else processItem = NULL; - sendToMenu = CreateSendToMenu(menuInfo->Menu, processItem ? processItem->FileName : NULL); + sendToMenu = CreateSendToMenu(TRUE, menuInfo->Menu, processItem ? processItem->FileName : NULL); // Only enable the Send To menu if there is exactly one process selected and it has a file name. if (!processItem || !processItem->FileName) @@ -322,7 +323,7 @@ VOID NTAPI ModuleMenuInitializingCallback( else moduleItem = NULL; - sendToMenu = CreateSendToMenu(menuInfo->Menu, moduleItem ? moduleItem->FileName : NULL); + sendToMenu = CreateSendToMenu(FALSE, menuInfo->Menu, moduleItem ? moduleItem->FileName : NULL); if (!moduleItem) { @@ -364,7 +365,7 @@ VOID NTAPI ServiceMenuInitializingCallback( PhAutoDereferenceObject(serviceFileName); } - sendToMenu = CreateSendToMenu(menuInfo->Menu, serviceFileName ? serviceFileName : NULL); + sendToMenu = CreateSendToMenu(FALSE, menuInfo->Menu, serviceFileName ? serviceFileName : NULL); if (!serviceItem || !serviceFileName) { From 9f69ed72dfac1ed548c0e704420eb465f213fcad Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 4 Aug 2017 09:16:38 +1000 Subject: [PATCH 0344/2058] OnlineChecks: Fix use-after-free --- plugins/OnlineChecks/main.c | 34 +++++++------------- plugins/OnlineChecks/onlnchk.h | 11 +++++-- plugins/OnlineChecks/upload.c | 57 +++++++++++++++++++++++++++++++--- 3 files changed, 73 insertions(+), 29 deletions(-) diff --git a/plugins/OnlineChecks/main.c b/plugins/OnlineChecks/main.c index faaf6dc9c7fe..502d5cf853f8 100644 --- a/plugins/OnlineChecks/main.c +++ b/plugins/OnlineChecks/main.c @@ -209,6 +209,12 @@ VOID NTAPI MenuItemCallback( case MENUITEM_JOTTI_UPLOAD: UploadToOnlineService(menuItem->Context, MENUITEM_JOTTI_UPLOAD); break; + case MENUITEM_VIRUSTOTAL_UPLOAD_SERVICE: + UploadServiceToOnlineService(menuItem->Context, MENUITEM_VIRUSTOTAL_UPLOAD_SERVICE); + break; + case MENUITEM_JOTTI_UPLOAD_SERVICE: + UploadServiceToOnlineService(menuItem->Context, MENUITEM_JOTTI_UPLOAD_SERVICE); + break; case MENUITEM_VIRUSTOTAL_UPLOAD_FILE: { static PH_FILETYPE_FILTER filters[] = @@ -339,35 +345,19 @@ VOID NTAPI ServiceMenuInitializingCallback( PPH_PLUGIN_MENU_INFORMATION menuInfo = Parameter; PPH_SERVICE_ITEM serviceItem; PPH_EMENU_ITEM sendToMenu; - PPH_STRING serviceFileName = NULL; - PPH_STRING serviceBinaryPath = NULL; if (menuInfo->u.Service.NumberOfServices == 1) serviceItem = menuInfo->u.Service.Services[0]; else serviceItem = NULL; - if (serviceItem) - { - QueryServiceFileName( - &serviceItem->Name->sr, - &serviceFileName, - &serviceBinaryPath - ); - } - - if (serviceBinaryPath) - PhDereferenceObject(serviceBinaryPath); - - if (serviceFileName) - { - // TODO: memory leak or possible use-after-free bug? - PhAutoDereferenceObject(serviceFileName); - } - - sendToMenu = CreateSendToMenu(FALSE, menuInfo->Menu, serviceFileName ? serviceFileName : NULL); + sendToMenu = PhPluginCreateEMenuItem(PluginInstance, 0, 0, L"Send to", NULL); + PhInsertEMenuItem(sendToMenu, PhPluginCreateEMenuItem(PluginInstance, 0, MENUITEM_VIRUSTOTAL_UPLOAD_SERVICE, L"virustotal.com", serviceItem ? serviceItem : NULL), -1); + PhInsertEMenuItem(sendToMenu, PhPluginCreateEMenuItem(PluginInstance, 0, MENUITEM_JOTTI_UPLOAD_SERVICE, L"virusscan.jotti.org", serviceItem ? serviceItem : NULL), -1); + PhInsertEMenuItem(menuInfo->Menu, PhPluginCreateEMenuItem(PluginInstance, PH_EMENU_SEPARATOR, 0, NULL, NULL), -1); + PhInsertEMenuItem(menuInfo->Menu, sendToMenu, -1); - if (!serviceItem || !serviceFileName) + if (!serviceItem) { sendToMenu->Flags |= PH_EMENU_DISABLED; } diff --git a/plugins/OnlineChecks/onlnchk.h b/plugins/OnlineChecks/onlnchk.h index 79b1ff043651..ebd5e33898e5 100644 --- a/plugins/OnlineChecks/onlnchk.h +++ b/plugins/OnlineChecks/onlnchk.h @@ -200,14 +200,21 @@ PVIRUSTOTAL_FILE_REPORT_RESULT VirusTotalSendHttpFileReportRequest( #define ENABLE_SERVICE_VIRUSTOTAL 100 #define MENUITEM_VIRUSTOTAL_QUEUE 101 #define MENUITEM_VIRUSTOTAL_UPLOAD 102 -#define MENUITEM_VIRUSTOTAL_UPLOAD_FILE 103 -#define MENUITEM_JOTTI_UPLOAD 104 +#define MENUITEM_VIRUSTOTAL_UPLOAD_SERVICE 103 +#define MENUITEM_VIRUSTOTAL_UPLOAD_FILE 104 +#define MENUITEM_JOTTI_UPLOAD 105 +#define MENUITEM_JOTTI_UPLOAD_SERVICE 106 VOID UploadToOnlineService( _In_ PPH_STRING FileName, _In_ ULONG Service ); +VOID UploadServiceToOnlineService( + _In_ PPH_SERVICE_ITEM ServiceItem, + _In_ ULONG Service + ); + typedef enum _NETWORK_COLUMN_ID { COLUMN_ID_VIUSTOTAL_PROCESS = 1, diff --git a/plugins/OnlineChecks/upload.c b/plugins/OnlineChecks/upload.c index 11948fefec83..1e5ca87291cd 100644 --- a/plugins/OnlineChecks/upload.c +++ b/plugins/OnlineChecks/upload.c @@ -25,10 +25,13 @@ #include PPH_OBJECT_TYPE UploadContextType = NULL; +PH_INITONCE UploadContextTypeInitOnce = PH_INITONCE_INIT; SERVICE_INFO UploadServiceInfo[] = { { MENUITEM_VIRUSTOTAL_UPLOAD, L"www.virustotal.com", INTERNET_DEFAULT_HTTPS_PORT, WINHTTP_FLAG_SECURE, L"???", L"file" }, + { MENUITEM_VIRUSTOTAL_UPLOAD_SERVICE, L"www.virustotal.com", INTERNET_DEFAULT_HTTPS_PORT, WINHTTP_FLAG_SECURE, L"???", L"file" }, { MENUITEM_JOTTI_UPLOAD, L"virusscan.jotti.org", INTERNET_DEFAULT_HTTPS_PORT, WINHTTP_FLAG_SECURE, L"/en-US/submit-file?isAjax=true", L"sample-file[]" }, + { MENUITEM_JOTTI_UPLOAD_SERVICE, L"virusscan.jotti.org", INTERNET_DEFAULT_HTTPS_PORT, WINHTTP_FLAG_SECURE, L"/en-US/submit-file?isAjax=true", L"sample-file[]" }, }; BOOL ReadRequestString( @@ -794,6 +797,7 @@ NTSTATUS UploadFileThreadStart( switch (context->Service) { case MENUITEM_VIRUSTOTAL_UPLOAD: + case MENUITEM_VIRUSTOTAL_UPLOAD_SERVICE: { PSTR buffer = NULL; PSTR redirectUrl; @@ -842,6 +846,7 @@ NTSTATUS UploadFileThreadStart( } break; case MENUITEM_JOTTI_UPLOAD: + case MENUITEM_JOTTI_UPLOAD_SERVICE: { PSTR buffer = NULL; PSTR redirectUrl; @@ -958,7 +963,8 @@ NTSTATUS UploadCheckThreadStart( if (NT_SUCCESS(status = PhGetFileSize(fileHandle, &fileSize64))) { - if (context->Service == MENUITEM_VIRUSTOTAL_UPLOAD) + if (context->Service == MENUITEM_VIRUSTOTAL_UPLOAD || + context->Service == MENUITEM_VIRUSTOTAL_UPLOAD_SERVICE) { if (fileSize64.QuadPart < 32 * 1024 * 1024) { @@ -1012,6 +1018,7 @@ NTSTATUS UploadCheckThreadStart( switch (context->Service) { case MENUITEM_VIRUSTOTAL_UPLOAD: + case MENUITEM_VIRUSTOTAL_UPLOAD_SERVICE: { PSTR uploadUrl = NULL; PSTR quote = NULL; @@ -1114,6 +1121,7 @@ NTSTATUS UploadCheckThreadStart( } break; case MENUITEM_JOTTI_UPLOAD: + case MENUITEM_JOTTI_UPLOAD_SERVICE: { // Create the default upload URL context->UploadUrl = PhFormatString(L"https://virusscan.jotti.org%s", serviceInfo->UploadObjectName); @@ -1276,14 +1284,12 @@ VOID UploadToOnlineService( _In_ ULONG Service ) { - static PH_INITONCE initOnce = PH_INITONCE_INIT; - PUPLOAD_CONTEXT context; - if (PhBeginInitOnce(&initOnce)) + if (PhBeginInitOnce(&UploadContextTypeInitOnce)) { UploadContextType = PhCreateObjectType(L"OnlineChecksObjectType", 0, UploadContextDeleteProcedure); - PhEndInitOnce(&initOnce); + PhEndInitOnce(&UploadContextTypeInitOnce); } context = (PUPLOAD_CONTEXT)PhCreateObject(sizeof(UPLOAD_CONTEXT), UploadContextType); @@ -1296,3 +1302,44 @@ VOID UploadToOnlineService( PhCreateThread2(ShowUpdateDialogThread, (PVOID)context); } + +VOID UploadServiceToOnlineService( + _In_ PPH_SERVICE_ITEM ServiceItem, + _In_ ULONG Service + ) +{ + NTSTATUS status; + PPH_STRING serviceFileName; + PPH_STRING serviceBinaryPath = NULL; + + if (PhBeginInitOnce(&UploadContextTypeInitOnce)) + { + UploadContextType = PhCreateObjectType(L"OnlineChecksObjectType", 0, UploadContextDeleteProcedure); + PhEndInitOnce(&UploadContextTypeInitOnce); + } + + if (NT_SUCCESS(status = QueryServiceFileName( + &ServiceItem->Name->sr, + &serviceFileName, + &serviceBinaryPath + ))) + { + PUPLOAD_CONTEXT context; + + context = (PUPLOAD_CONTEXT)PhCreateObject(sizeof(UPLOAD_CONTEXT), UploadContextType); + memset(context, 0, sizeof(UPLOAD_CONTEXT)); + + context->Service = Service; + context->FileName = serviceFileName; + context->BaseFileName = PhGetBaseName(context->FileName); + + PhCreateThread2(ShowUpdateDialogThread, (PVOID)context); + } + else + { + PhShowStatus(PhMainWndHandle, L"Unable to query the service", status, 0); + } + + if (serviceBinaryPath) + PhDereferenceObject(serviceBinaryPath); +} \ No newline at end of file From 7f7f3d2bddbaad4604272c812a269c37b5eabf0d Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 4 Aug 2017 09:53:29 +1000 Subject: [PATCH 0345/2058] Add EnableKphWarnings setting --- ProcessHacker/main.c | 3 ++- ProcessHacker/settings.c | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/ProcessHacker/main.c b/ProcessHacker/main.c index 0d1cc99b1db5..fe24cc0c7568 100644 --- a/ProcessHacker/main.c +++ b/ProcessHacker/main.c @@ -588,7 +588,8 @@ VOID PhInitializeKph( } else { - PhShowStatus(NULL, L"Unable to load the kernel driver.", status, 0); + if (PhGetIntegerSetting(L"EnableWarnings")) + PhShowStatus(NULL, L"Unable to load the kernel driver.", status, 0); } PhDereferenceObject(kprocesshackerFileName); diff --git a/ProcessHacker/settings.c b/ProcessHacker/settings.c index 94df736bbbee..bbcfc1746789 100644 --- a/ProcessHacker/settings.c +++ b/ProcessHacker/settings.c @@ -41,6 +41,7 @@ VOID PhAddDefaultSettings( PhpAddIntegerSetting(L"EnableCycleCpuUsage", L"1"); PhpAddIntegerSetting(L"EnableInstantTooltips", L"0"); PhpAddIntegerSetting(L"EnableKph", L"1"); + PhpAddIntegerSetting(L"EnableKphWarnings", L"1"); PhpAddIntegerSetting(L"EnableNetworkResolve", L"1"); PhpAddIntegerSetting(L"EnablePlugins", L"1"); PhpAddIntegerSetting(L"EnableServiceNonPoll", L"1"); From 540eca62d06e66802b8e065a8a64f2f7e13900b3 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 4 Aug 2017 11:46:38 +1000 Subject: [PATCH 0346/2058] Fix typo --- ProcessHacker/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ProcessHacker/main.c b/ProcessHacker/main.c index fe24cc0c7568..6d2b40ec275c 100644 --- a/ProcessHacker/main.c +++ b/ProcessHacker/main.c @@ -588,7 +588,7 @@ VOID PhInitializeKph( } else { - if (PhGetIntegerSetting(L"EnableWarnings")) + if (PhGetIntegerSetting(L"EnableKphWarnings")) PhShowStatus(NULL, L"Unable to load the kernel driver.", status, 0); } From bd1b0debd3e51fe6f020763a892ddf9365bdf7f7 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 4 Aug 2017 12:14:06 +1000 Subject: [PATCH 0347/2058] Fix github file encoding --- tools/GenerateZw/GenerateZw/Program.cs | 2 +- tools/GenerateZw/GenerateZw/Properties/AssemblyInfo.cs | 2 +- tools/GenerateZw/GenerateZw/ZwGen.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/GenerateZw/GenerateZw/Program.cs b/tools/GenerateZw/GenerateZw/Program.cs index 20ba3a89ee3d..1f857a046f9c 100644 --- a/tools/GenerateZw/GenerateZw/Program.cs +++ b/tools/GenerateZw/GenerateZw/Program.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Text; diff --git a/tools/GenerateZw/GenerateZw/Properties/AssemblyInfo.cs b/tools/GenerateZw/GenerateZw/Properties/AssemblyInfo.cs index 49da97e1ccc5..418173296108 100644 --- a/tools/GenerateZw/GenerateZw/Properties/AssemblyInfo.cs +++ b/tools/GenerateZw/GenerateZw/Properties/AssemblyInfo.cs @@ -1,4 +1,4 @@ -using System.Reflection; +using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; diff --git a/tools/GenerateZw/GenerateZw/ZwGen.cs b/tools/GenerateZw/GenerateZw/ZwGen.cs index 737610f9e935..de079cd659c5 100644 --- a/tools/GenerateZw/GenerateZw/ZwGen.cs +++ b/tools/GenerateZw/GenerateZw/ZwGen.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Text; From 39270e371518b243dd50dfa67fa0efcb2d356e0a Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 4 Aug 2017 13:06:42 +1000 Subject: [PATCH 0348/2058] Add TokenSplitterEnable setting, Disable token properties splitter by default --- ProcessHacker/include/splitter.h | 38 +------------- ProcessHacker/prpgtok.c | 10 ++++ ProcessHacker/settings.c | 1 + ProcessHacker/splitter.c | 87 +++++++++++++++++++++++++++++--- ProcessHacker/tokprp.c | 21 ++++---- 5 files changed, 104 insertions(+), 53 deletions(-) diff --git a/ProcessHacker/include/splitter.h b/ProcessHacker/include/splitter.h index 75be46d7593b..9901b2ea6fcc 100644 --- a/ProcessHacker/include/splitter.h +++ b/ProcessHacker/include/splitter.h @@ -1,45 +1,11 @@ #ifndef PH_HSPLITTER_H #define PH_HSPLITTER_H -typedef struct _PH_HSPLITTER_CONTEXT -{ - union - { - ULONG Flags; - struct - { - ULONG Hot : 1; - ULONG HasFocus : 1; - ULONG Spare : 30; - }; - }; - - LONG SplitterOffset; - - HWND Window; - HWND ParentWindow; - HWND TopWindow; - HWND BottomWindow; - - HBRUSH FocusBrush; - HBRUSH HotBrush; - HBRUSH NormalBrush; -} PH_HSPLITTER_CONTEXT, *PPH_HSPLITTER_CONTEXT; - -PPH_HSPLITTER_CONTEXT PhInitializeHSplitter( +VOID PhInitializeHSplitter( + _In_ PWSTR SettingName, _In_ HWND ParentWindow, _In_ HWND TopWindow, _In_ HWND BottomWindow ); -VOID PhDeleteHSplitter( - _Inout_ PPH_HSPLITTER_CONTEXT Context - ); - -VOID PhHSplitterHandleWmSize( - _Inout_ PPH_HSPLITTER_CONTEXT Context, - _In_ INT Width, - _In_ INT Height - ); - #endif diff --git a/ProcessHacker/prpgtok.c b/ProcessHacker/prpgtok.c index d6de9b5eaf9f..d19a654673e9 100644 --- a/ProcessHacker/prpgtok.c +++ b/ProcessHacker/prpgtok.c @@ -24,6 +24,8 @@ #include #include +#include + NTSTATUS NTAPI PhpOpenProcessTokenForPage( _Out_ PHANDLE Handle, _In_ ACCESS_MASK DesiredAccess, @@ -85,6 +87,14 @@ INT_PTR CALLBACK PhpProcessTokenHookProc( PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_ADVANCED), dialogItem, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); + if (!PhGetIntegerSetting(L"TokenSplitterEnable")) + { + PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_GROUPS), + dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); + PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_PRIVILEGES), + dialogItem, PH_ANCHOR_ALL); + } + PhDoPropPageLayout(hwndDlg); SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)TRUE); diff --git a/ProcessHacker/settings.c b/ProcessHacker/settings.c index bbcfc1746789..7cd244685a9a 100644 --- a/ProcessHacker/settings.c +++ b/ProcessHacker/settings.c @@ -150,6 +150,7 @@ VOID PhAddDefaultSettings( PhpAddStringSetting(L"ThreadStackTreeListColumns", L""); PhpAddScalableIntegerPairSetting(L"ThreadStackWindowSize", L"@96|420,400"); PhpAddStringSetting(L"TokenGroupsListViewColumns", L""); + PhpAddIntegerSetting(L"TokenSplitterEnable", L"0"); PhpAddIntegerSetting(L"TokenSplitterPosition", L"150"); PhpAddStringSetting(L"TokenPrivilegesListViewColumns", L""); PhpAddIntegerSetting(L"UpdateInterval", L"3e8"); // 1000ms diff --git a/ProcessHacker/splitter.c b/ProcessHacker/splitter.c index 4de4d68eb34f..208e3c22d8e9 100644 --- a/ProcessHacker/splitter.c +++ b/ProcessHacker/splitter.c @@ -28,6 +28,43 @@ #define SPLITTER_PADDING 6 +typedef struct _PH_HSPLITTER_CONTEXT +{ + union + { + ULONG Flags; + struct + { + ULONG Hot : 1; + ULONG HasFocus : 1; + ULONG Spare : 30; + }; + }; + + LONG SplitterOffset; + + HWND Window; + HWND ParentWindow; + HWND TopWindow; + HWND BottomWindow; + + HBRUSH FocusBrush; + HBRUSH HotBrush; + HBRUSH NormalBrush; + + PPH_STRING SettingName; +} PH_HSPLITTER_CONTEXT, *PPH_HSPLITTER_CONTEXT; + +VOID PhDeleteHSplitter( + _Inout_ PPH_HSPLITTER_CONTEXT Context + ); + +VOID PhHSplitterHandleWmSize( + _Inout_ PPH_HSPLITTER_CONTEXT Context, + _In_ INT Width, + _In_ INT Height + ); + LONG GetWindowWidth(HWND hwnd) { RECT Rect; @@ -60,7 +97,12 @@ LONG GetClientWindowHeight(HWND hwnd) return (Rect.bottom - Rect.top); } -LRESULT CALLBACK HSplitterWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +LRESULT CALLBACK HSplitterWindowProc( + _In_ HWND hwnd, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) { PPH_HSPLITTER_CONTEXT context = NULL; @@ -217,7 +259,38 @@ LRESULT CALLBACK HSplitterWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM return DefWindowProc(hwnd, uMsg, wParam, lParam); } -PPH_HSPLITTER_CONTEXT PhInitializeHSplitter( +LRESULT CALLBACK HSplitterParentWindowProc( + _In_ HWND hwnd, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam, + _In_ UINT_PTR uIdSubclass, + _In_ ULONG_PTR dwRefData + ) +{ + PPH_HSPLITTER_CONTEXT context = (PPH_HSPLITTER_CONTEXT)dwRefData; + + switch (uMsg) + { + case WM_DESTROY: + { + RemoveWindowSubclass(hwnd, HSplitterParentWindowProc, uIdSubclass); + + PhDeleteHSplitter(context); + } + break; + case WM_SIZE: + { + PhHSplitterHandleWmSize(context, LOWORD(lParam), HIWORD(lParam)); + } + break; + } + + return DefSubclassProc(hwnd, uMsg, wParam, lParam); +} + +VOID PhInitializeHSplitter( + _In_ PWSTR SettingName, _In_ HWND ParentWindow, _In_ HWND TopWindow, _In_ HWND BottomWindow @@ -228,11 +301,12 @@ PPH_HSPLITTER_CONTEXT PhInitializeHSplitter( context = PhAllocate(sizeof(PH_HSPLITTER_CONTEXT)); memset(context, 0, sizeof(PH_HSPLITTER_CONTEXT)); - + + context->SettingName = PhCreateString(SettingName); context->ParentWindow = ParentWindow; context->TopWindow = TopWindow; context->BottomWindow = BottomWindow; - context->SplitterOffset = PhGetIntegerSetting(L"TokenSplitterPosition"); + context->SplitterOffset = PhGetIntegerSetting(SettingName); context->FocusBrush = CreateSolidBrush(RGB(0x0, 0x0, 0x0)); context->HotBrush = CreateSolidBrush(RGB(0x44, 0x44, 0x44)); context->NormalBrush = GetSysColorBrush(COLOR_WINDOW); @@ -276,14 +350,15 @@ PPH_HSPLITTER_CONTEXT PhInitializeHSplitter( ShowWindow(context->Window, SW_SHOW); UpdateWindow(context->Window); - return context; + SetWindowSubclass(ParentWindow, HSplitterParentWindowProc, 0, (ULONG_PTR)context); } VOID PhDeleteHSplitter( _Inout_ PPH_HSPLITTER_CONTEXT Context ) { - PhSetIntegerSetting(L"TokenSplitterPosition", Context->SplitterOffset); + PhSetIntegerSetting(PhGetString(Context->SettingName), Context->SplitterOffset); + PhDereferenceObject(Context->SettingName); if (Context->FocusBrush) DeleteObject(Context->FocusBrush); diff --git a/ProcessHacker/tokprp.c b/ProcessHacker/tokprp.c index bfbd1f002a85..24cb7c718740 100644 --- a/ProcessHacker/tokprp.c +++ b/ProcessHacker/tokprp.c @@ -52,7 +52,6 @@ typedef struct _TOKEN_PAGE_CONTEXT HWND GroupsListViewHandle; HWND PrivilegesListViewHandle; - PPH_HSPLITTER_CONTEXT HSplitterContext; PTOKEN_GROUPS Groups; PTOKEN_PRIVILEGES Privileges; @@ -428,12 +427,6 @@ INT_PTR CALLBACK PhpTokenPageProc( PhSetControlTheme(groupsLv, L"explorer"); PhSetControlTheme(privilegesLv, L"explorer"); - tokenPageContext->HSplitterContext = PhInitializeHSplitter( - hwndDlg, - tokenPageContext->GroupsListViewHandle, - tokenPageContext->PrivilegesListViewHandle - ); - PhAddListViewColumn(groupsLv, 0, 0, 0, LVCFMT_LEFT, 160, L"Name"); PhAddListViewColumn(groupsLv, 1, 1, 1, LVCFMT_LEFT, 200, L"Flags"); @@ -579,6 +572,16 @@ INT_PTR CALLBACK PhpTokenPageProc( NtClose(tokenHandle); } + + if (PhGetIntegerSetting(L"TokenSplitterEnable")) + { + PhInitializeHSplitter( + L"TokenSplitterPosition", + hwndDlg, + tokenPageContext->GroupsListViewHandle, + tokenPageContext->PrivilegesListViewHandle + ); + } } break; case WM_DESTROY: @@ -588,7 +591,6 @@ INT_PTR CALLBACK PhpTokenPageProc( if (tokenPageContext->Groups) PhFree(tokenPageContext->Groups); if (tokenPageContext->Privileges) PhFree(tokenPageContext->Privileges); - if (tokenPageContext->HSplitterContext) PhDeleteHSplitter(tokenPageContext->HSplitterContext); } break; case WM_COMMAND: @@ -922,9 +924,6 @@ INT_PTR CALLBACK PhpTokenPageProc( } } break; - case WM_SIZE: - PhHSplitterHandleWmSize(tokenPageContext->HSplitterContext, LOWORD(lParam), HIWORD(lParam)); - break; } REFLECT_MESSAGE_DLG(hwndDlg, tokenPageContext->GroupsListViewHandle, uMsg, wParam, lParam); From 98c361ec26e4b26346e5a41b7cce052d12b28b2e Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 4 Aug 2017 15:05:00 +1000 Subject: [PATCH 0349/2058] Add consistency check --- ProcessHacker/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ProcessHacker/main.c b/ProcessHacker/main.c index 6d2b40ec275c..df3481b33535 100644 --- a/ProcessHacker/main.c +++ b/ProcessHacker/main.c @@ -588,7 +588,7 @@ VOID PhInitializeKph( } else { - if (PhGetIntegerSetting(L"EnableKphWarnings")) + if (PhGetIntegerSetting(L"EnableKphWarnings") && PhGetOwnTokenAttributes().Elevated) PhShowStatus(NULL, L"Unable to load the kernel driver.", status, 0); } From ae57d1530396cf1910f2bc5bc0ed654b85438533 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 4 Aug 2017 16:07:30 +1000 Subject: [PATCH 0350/2058] Add ShowHexId setting (shows PIDs and TIDs as hexadecimal) --- ProcessHacker/include/phsettings.h | 1 + ProcessHacker/procprv.c | 8 +++++++- ProcessHacker/settings.c | 2 ++ ProcessHacker/thrdprv.c | 7 ++++++- 4 files changed, 16 insertions(+), 2 deletions(-) diff --git a/ProcessHacker/include/phsettings.h b/ProcessHacker/include/phsettings.h index d722745c8815..4f79cc7a69eb 100644 --- a/ProcessHacker/include/phsettings.h +++ b/ProcessHacker/include/phsettings.h @@ -17,6 +17,7 @@ EXT ULONG PhCsHighlightingDuration; EXT ULONG PhCsPropagateCpuUsage; EXT ULONG PhCsScrollToNewProcesses; EXT ULONG PhCsShowCpuBelow001; +EXT ULONG PhCsShowHexId; EXT ULONG PhCsUpdateInterval; EXT ULONG PhCsColorNew; diff --git a/ProcessHacker/procprv.c b/ProcessHacker/procprv.c index a6a1727ba6de..c30b5412d012 100644 --- a/ProcessHacker/procprv.c +++ b/ProcessHacker/procprv.c @@ -51,6 +51,7 @@ */ #include +#include #include #include @@ -457,7 +458,12 @@ PPH_PROCESS_ITEM PhCreateProcessItem( processItem->ProcessId = ProcessId; if (!PH_IS_FAKE_PROCESS_ID(ProcessId)) - PhPrintUInt32(processItem->ProcessIdString, HandleToUlong(ProcessId)); + { + if (PhCsShowHexId) + _ultow(HandleToUlong(ProcessId), processItem->ProcessIdString, 16); + else + PhPrintUInt32(processItem->ProcessIdString, HandleToUlong(ProcessId)); + } // Create the statistics buffers. PhInitializeCircularBuffer_FLOAT(&processItem->CpuKernelHistory, PhStatisticsSampleCount); diff --git a/ProcessHacker/settings.c b/ProcessHacker/settings.c index 7cd244685a9a..421f334f821a 100644 --- a/ProcessHacker/settings.c +++ b/ProcessHacker/settings.c @@ -137,6 +137,7 @@ VOID PhAddDefaultSettings( PhpAddIntegerPairSetting(L"SessionShadowHotkey", L"106,2"); // VK_MULTIPLY,KBDCTRL PhpAddIntegerSetting(L"ShowCommitInSummary", L"1"); PhpAddIntegerSetting(L"ShowCpuBelow001", L"0"); + PhpAddIntegerSetting(L"ShowHexId", L"1"); PhpAddIntegerSetting(L"StartHidden", L"0"); PhpAddIntegerSetting(L"SysInfoWindowAlwaysOnTop", L"0"); PhpAddIntegerSetting(L"SysInfoWindowOneGraphPerCpu", L"0"); @@ -213,6 +214,7 @@ VOID PhUpdateCachedSettings( PH_UPDATE_SETTING(PropagateCpuUsage); PH_UPDATE_SETTING(ScrollToNewProcesses); PH_UPDATE_SETTING(ShowCpuBelow001); + PH_UPDATE_SETTING(ShowHexId); PH_UPDATE_SETTING(UpdateInterval); PH_UPDATE_SETTING(ColorNew); PH_UPDATE_SETTING(ColorRemoved); diff --git a/ProcessHacker/thrdprv.c b/ProcessHacker/thrdprv.c index a0cf4bee575b..3be1e25a73e2 100644 --- a/ProcessHacker/thrdprv.c +++ b/ProcessHacker/thrdprv.c @@ -27,6 +27,7 @@ */ #include +#include #include #include @@ -387,7 +388,11 @@ PPH_THREAD_ITEM PhCreateThreadItem( ); memset(threadItem, 0, sizeof(PH_THREAD_ITEM)); threadItem->ThreadId = ThreadId; - PhPrintUInt32(threadItem->ThreadIdString, HandleToUlong(ThreadId)); + + if (PhCsShowHexId) + _ultow(HandleToUlong(ThreadId), threadItem->ThreadIdString, 16); + else + PhPrintUInt32(threadItem->ThreadIdString, HandleToUlong(ThreadId)); PhEmCallObjectOperation(EmThreadItemType, threadItem, EmObjectCreate); From 25a22fdafd39c3dc5d4190dd81d4c03e7087e5dc Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 4 Aug 2017 16:08:50 +1000 Subject: [PATCH 0351/2058] Disable ShowHexId setting by default --- ProcessHacker/settings.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ProcessHacker/settings.c b/ProcessHacker/settings.c index 421f334f821a..28994dd78cbe 100644 --- a/ProcessHacker/settings.c +++ b/ProcessHacker/settings.c @@ -137,7 +137,7 @@ VOID PhAddDefaultSettings( PhpAddIntegerPairSetting(L"SessionShadowHotkey", L"106,2"); // VK_MULTIPLY,KBDCTRL PhpAddIntegerSetting(L"ShowCommitInSummary", L"1"); PhpAddIntegerSetting(L"ShowCpuBelow001", L"0"); - PhpAddIntegerSetting(L"ShowHexId", L"1"); + PhpAddIntegerSetting(L"ShowHexId", L"0"); PhpAddIntegerSetting(L"StartHidden", L"0"); PhpAddIntegerSetting(L"SysInfoWindowAlwaysOnTop", L"0"); PhpAddIntegerSetting(L"SysInfoWindowOneGraphPerCpu", L"0"); From fee5f1b3769d605dcfa4e0e334adf895fc886609 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 6 Aug 2017 22:52:39 +1000 Subject: [PATCH 0352/2058] Update ntexapi.h with undocumented SYSDBG types --- phnt/include/ntexapi.h | 45 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/phnt/include/ntexapi.h b/phnt/include/ntexapi.h index 5a42dbf6bffa..760260980a90 100644 --- a/phnt/include/ntexapi.h +++ b/phnt/include/ntexapi.h @@ -3152,6 +3152,51 @@ typedef struct _SYSDBG_TRIAGE_DUMP PHANDLE Handles; } SYSDBG_TRIAGE_DUMP, *PSYSDBG_TRIAGE_DUMP; +// private +typedef struct _SYSDBG_LIVEDUMP_CONTROL_FLAGS +{ + union + { + struct + { + ULONG UseDumpStorageStack : 1; + ULONG CompressMemoryPagesData : 1; + ULONG IncludeUserSpaceMemoryPages : 1; + ULONG Reserved : 28; + }; + ULONG AsUlong; + }; +} SYSDBG_LIVEDUMP_CONTROL_FLAGS, *PSYSDBG_LIVEDUMP_CONTROL_FLAGS; + +// private +typedef struct _SYSDBG_LIVEDUMP_CONTROL_ADDPAGES +{ + union + { + struct + { + ULONG HypervisorPages : 1; + ULONG Reserved : 31; + }; + ULONG AsUlong; + }; +} SYSDBG_LIVEDUMP_CONTROL_ADDPAGES, *PSYSDBG_LIVEDUMP_CONTROL_ADDPAGES; + +// private +typedef struct _SYSDBG_LIVEDUMP_CONTROL +{ + ULONG Version; + ULONG BugCheckCode; + ULONG_PTR BugCheckParam1; + ULONG_PTR BugCheckParam2; + ULONG_PTR BugCheckParam3; + ULONG_PTR BugCheckParam4; + HANDLE DumpFileHandle; + HANDLE CancelEventHandle; + SYSDBG_LIVEDUMP_CONTROL_FLAGS Flags; + SYSDBG_LIVEDUMP_CONTROL_ADDPAGES AddPagesControl; +} SYSDBG_LIVEDUMP_CONTROL, *PSYSDBG_LIVEDUMP_CONTROL; + NTSYSCALLAPI NTSTATUS NTAPI From 02dda7743335a179c869774a3ae0b1815d96e63a Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 7 Aug 2017 13:20:17 +1000 Subject: [PATCH 0353/2058] ToolStatus: Hide hybrid shutdown on unsupported OS --- plugins/ToolStatus/main.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/plugins/ToolStatus/main.c b/plugins/ToolStatus/main.c index afd88f8ced2c..cbd82cbdfe67 100644 --- a/plugins/ToolStatus/main.c +++ b/plugins/ToolStatus/main.c @@ -855,6 +855,16 @@ LRESULT CALLBACK MainWndSubclassProc( PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, PHAPP_ID_COMPUTER_RESTARTBOOTOPTIONS, L"Restart to boot &options", NULL, NULL), -1); PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, PHAPP_ID_COMPUTER_SHUTDOWN, L"Shu&t down", NULL, NULL), -1); PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, PHAPP_ID_COMPUTER_SHUTDOWNHYBRID, L"H&ybrid shut down", NULL, NULL), -1); + + if (WindowsVersion < WINDOWS_8) + { + PPH_EMENU_ITEM menuItemRemove; + + if (menuItemRemove = PhFindEMenuItem(menuItem, PH_EMENU_FIND_DESCEND, NULL, PHAPP_ID_COMPUTER_RESTARTBOOTOPTIONS)) + PhDestroyEMenuItem(menuItemRemove); + if (menuItemRemove = PhFindEMenuItem(menuItem, PH_EMENU_FIND_DESCEND, NULL, PHAPP_ID_COMPUTER_SHUTDOWNHYBRID)) + PhDestroyEMenuItem(menuItemRemove); + } } break; } From 24fc6c344060a497add2fa3a225bcb33a87a61c5 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 7 Aug 2017 22:56:23 +1000 Subject: [PATCH 0354/2058] Add missing case from previous commit --- plugins/ToolStatus/main.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/plugins/ToolStatus/main.c b/plugins/ToolStatus/main.c index cbd82cbdfe67..d358c8a64d7d 100644 --- a/plugins/ToolStatus/main.c +++ b/plugins/ToolStatus/main.c @@ -983,6 +983,16 @@ LRESULT CALLBACK MainWndSubclassProc( PhInsertEMenuItem(menu, PhCreateEMenuItem(0, PHAPP_ID_COMPUTER_RESTARTBOOTOPTIONS, L"Restart to boot &options", NULL, NULL), -1); PhInsertEMenuItem(menu, PhCreateEMenuItem(0, PHAPP_ID_COMPUTER_SHUTDOWN, L"Shu&t down", NULL, NULL), -1); PhInsertEMenuItem(menu, PhCreateEMenuItem(0, PHAPP_ID_COMPUTER_SHUTDOWNHYBRID, L"H&ybrid shut down", NULL, NULL), -1); + + if (WindowsVersion < WINDOWS_8) + { + PPH_EMENU_ITEM menuItemRemove; + + if (menuItemRemove = PhFindEMenuItem(menu, PH_EMENU_FIND_DESCEND, NULL, PHAPP_ID_COMPUTER_RESTARTBOOTOPTIONS)) + PhDestroyEMenuItem(menuItemRemove); + if (menuItemRemove = PhFindEMenuItem(menu, PH_EMENU_FIND_DESCEND, NULL, PHAPP_ID_COMPUTER_SHUTDOWNHYBRID)) + PhDestroyEMenuItem(menuItemRemove); + } MapWindowPoints(ToolBarHandle, NULL, (LPPOINT)&toolbar->rcButton, 2); From 94131677af118701fe5c0019c2cb17ee56f92df6 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 8 Aug 2017 16:01:22 +1000 Subject: [PATCH 0355/2058] Improve KPH error checking, Fix issue with unoffical builds and empty handles tab --- ProcessHacker/main.c | 45 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 35 insertions(+), 10 deletions(-) diff --git a/ProcessHacker/main.c b/ProcessHacker/main.c index df3481b33535..f5aae4442a07 100644 --- a/ProcessHacker/main.c +++ b/ProcessHacker/main.c @@ -517,8 +517,9 @@ VOID PhInitializeFont( } } -PUCHAR PhpReadSignature( +NTSTATUS PhpReadSignature( _In_ PWSTR FileName, + _Out_ PUCHAR *Signature, _Out_ PULONG SignatureSize ) { @@ -528,10 +529,10 @@ PUCHAR PhpReadSignature( ULONG bufferSize; IO_STATUS_BLOCK iosb; - if (!NT_SUCCESS(PhCreateFileWin32(&fileHandle, FileName, FILE_GENERIC_READ, FILE_ATTRIBUTE_NORMAL, + if (!NT_SUCCESS(status = PhCreateFileWin32(&fileHandle, FileName, FILE_GENERIC_READ, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ, FILE_OPEN, FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT))) { - return NULL; + return status; } bufferSize = 1024; @@ -542,13 +543,14 @@ PUCHAR PhpReadSignature( if (NT_SUCCESS(status)) { + *Signature = signature; *SignatureSize = (ULONG)iosb.Information; - return signature; + return status; } else { PhFree(signature); - return NULL; + return status; } } @@ -562,8 +564,6 @@ VOID PhInitializeKph( PPH_STRING kprocesshackerFileName; PPH_STRING processhackerSigFileName; KPH_PARAMETERS parameters; - PUCHAR signature; - ULONG signatureSize; if (WindowsVersion == WINDOWS_NEW) return; @@ -571,7 +571,7 @@ VOID PhInitializeKph( kprocesshackerFileName = PhConcatStringRef2(&PhApplicationDirectory->sr, &kprocesshacker); processhackerSigFileName = PhConcatStringRef2(&PhApplicationDirectory->sr, &processhackerSig); - parameters.SecurityLevel = KphSecuritySignatureCheck; + parameters.SecurityLevel = KphSecuritySignatureAndPrivilegeCheck; parameters.CreateDynamicConfiguration = TRUE; if (NT_SUCCESS(status = KphConnect2Ex( @@ -580,11 +580,36 @@ VOID PhInitializeKph( ¶meters ))) { - if (signature = PhpReadSignature(processhackerSigFileName->Buffer, &signatureSize)) + PUCHAR signature; + ULONG signatureSize; + + status = PhpReadSignature( + processhackerSigFileName->Buffer, + &signature, + &signatureSize + ); + + if (NT_SUCCESS(status)) { - KphVerifyClient(signature, signatureSize); + status = KphVerifyClient(signature, signatureSize); + + if (!NT_SUCCESS(status)) + { + if (PhGetIntegerSetting(L"EnableKphWarnings")) + PhShowStatus(NULL, L"Unable to verify the kernel driver signature.", status, 0); + + KphDisconnect(); + } + PhFree(signature); } + else + { + if (PhGetIntegerSetting(L"EnableKphWarnings")) + PhShowStatus(NULL, L"Unable to load the kernel driver signature.", status, 0); + + KphDisconnect(); + } } else { From 62542aa2796d095a7e8963cdf4cb7047379a16c3 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 8 Aug 2017 17:26:20 +1000 Subject: [PATCH 0356/2058] Fix previous commit Fix kimbers lewd disconnect --- ProcessHacker/main.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/ProcessHacker/main.c b/ProcessHacker/main.c index f5aae4442a07..0291db3d0c94 100644 --- a/ProcessHacker/main.c +++ b/ProcessHacker/main.c @@ -597,8 +597,6 @@ VOID PhInitializeKph( { if (PhGetIntegerSetting(L"EnableKphWarnings")) PhShowStatus(NULL, L"Unable to verify the kernel driver signature.", status, 0); - - KphDisconnect(); } PhFree(signature); @@ -607,8 +605,6 @@ VOID PhInitializeKph( { if (PhGetIntegerSetting(L"EnableKphWarnings")) PhShowStatus(NULL, L"Unable to load the kernel driver signature.", status, 0); - - KphDisconnect(); } } else From 3ab28ca091f538b17f70487652e897c12a57799c Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 8 Aug 2017 23:19:04 +1000 Subject: [PATCH 0357/2058] Setup: Fix setup uninstall, Fix all users desktop shortcut, Add initial websetup support --- tools/CustomBuildTool/Source Files/Build.cs | 130 +++++++++++++--- tools/CustomBuildTool/Source Files/Program.cs | 55 +++++-- tools/CustomBuildTool/Source Files/Utils.cs | 52 +++---- .../CustomSetupTool/CustomSetupTool.vcxproj | 13 +- .../CustomSetupTool.vcxproj.filters | 35 +++-- .../CustomSetupTool/CustomSetupTool/appsup.c | 28 +++- .../CustomSetupTool/{page3.c => configpage.c} | 2 +- .../CustomSetupTool/download.c | 65 +++++--- .../{page5.c => downloadpage.c} | 8 +- .../CustomSetupTool/{error.c => errorpage.c} | 0 .../CustomSetupTool/CustomSetupTool/extract.c | 4 +- .../CustomSetupTool/include/appsup.h | 4 + .../CustomSetupTool/include/setup.h | 27 +++- .../{page4.c => installpage.c} | 5 +- .../{page2.c => licencepage.c} | 0 tools/CustomSetupTool/CustomSetupTool/main.c | 7 +- .../CustomSetupTool/resources/version.rc | 10 +- tools/CustomSetupTool/CustomSetupTool/setup.c | 146 +++++++++++------- .../CustomSetupTool/{page1.c => startpage.c} | 3 + .../CustomSetupTool/uninstall.c | 9 +- .../CustomSetupTool/updatesetup.c | 29 ++++ 21 files changed, 432 insertions(+), 200 deletions(-) rename tools/CustomSetupTool/CustomSetupTool/{page3.c => configpage.c} (98%) rename tools/CustomSetupTool/CustomSetupTool/{page5.c => downloadpage.c} (94%) rename tools/CustomSetupTool/CustomSetupTool/{error.c => errorpage.c} (100%) rename tools/CustomSetupTool/CustomSetupTool/{page4.c => installpage.c} (98%) rename tools/CustomSetupTool/CustomSetupTool/{page2.c => licencepage.c} (100%) rename tools/CustomSetupTool/CustomSetupTool/{page1.c => startpage.c} (97%) create mode 100644 tools/CustomSetupTool/CustomSetupTool/updatesetup.c diff --git a/tools/CustomBuildTool/Source Files/Build.cs b/tools/CustomBuildTool/Source Files/Build.cs index a75528a64197..23ed51105d21 100644 --- a/tools/CustomBuildTool/Source Files/Build.cs +++ b/tools/CustomBuildTool/Source Files/Build.cs @@ -33,26 +33,34 @@ namespace CustomBuildTool public static class Build { private static DateTime TimeStart; - private static bool GitExportBuild; private static bool BuildNightly; + private static bool GitExportBuild; + private static string GitExePath; + private static string MSBuildExePath; + private static string CertUtilExePath; + private static string MakeAppxExePath; + private static string CustomSignToolPath; + private static string BuildBranch; private static string BuildOutputFolder; private static string BuildCommit; private static string BuildVersion; + private static string BuildWebSetupVersion; private static string BuildLongVersion; private static string BuildCount; private static string BuildRevision; private static string BuildMessage; - private static long BuildSetupFileLength; + private static long BuildBinFileLength; - private static string BuildSetupHash; private static string BuildBinHash; + + private static long BuildSetupFileLength; + private static string BuildSetupHash; private static string BuildSetupSig; - private static string GitExePath; - private static string MSBuildExePath; - private static string CertUtilExePath; - private static string MakeAppxExePath; - private static string CustomSignToolPath; + + private static long BuildWebSetupFileLength; + private static string BuildWebSetupHash; + private static string BuildWebSetupSig; #region Build Config private static readonly string[] sdk_directories = @@ -663,11 +671,48 @@ public static bool CopyKeyFiles() return true; } + public static bool BuildWebSetupExe() + { + Program.PrintColorMessage("Building build-websetup.exe...", ConsoleColor.Cyan); + + if (!BuildSolution("tools\\CustomSetupTool\\CustomSetupTool.sln", BuildFlags.Build32bit)) + return false; + + try + { + if (File.Exists(BuildOutputFolder + "\\processhacker-build-websetup.exe")) + File.Delete(BuildOutputFolder + "\\processhacker-build-websetup.exe"); + + File.Move( + "tools\\CustomSetupTool\\CustomSetupTool\\bin\\Release32\\CustomSetupTool.exe", + BuildOutputFolder + "\\processhacker-build-websetup.exe" + ); + } + catch (Exception ex) + { + Program.PrintColorMessage("[ERROR] " + ex, ConsoleColor.Red); + return false; + } + + try + { + var webSetupVersion = System.Diagnostics.FileVersionInfo.GetVersionInfo(BuildOutputFolder + "\\processhacker-build-websetup.exe"); + BuildWebSetupVersion = webSetupVersion.FileVersion.Replace(",", "."); + } + catch (Exception ex) + { + Program.PrintColorMessage("[ERROR] " + ex, ConsoleColor.Red); + return false; + } + + return true; + } + public static bool BuildSetupExe() { Program.PrintColorMessage("Building build-setup.exe...", ConsoleColor.Cyan); - if (!BuildSolution("tools\\CustomSetupTool\\CustomSetupTool.sln", BuildFlags.Build32bit | BuildFlags.BuildVerbose)) + if (!BuildSolution("tools\\CustomSetupTool\\CustomSetupTool.sln", BuildFlags.Build32bit | BuildFlags.BuildApi)) return false; try @@ -802,16 +847,22 @@ public static bool BuildChecksumsFile() if (File.Exists(BuildOutputFolder + "\\processhacker-build-checksums.txt")) File.Delete(BuildOutputFolder + "\\processhacker-build-checksums.txt"); + if (File.Exists(BuildOutputFolder + "\\processhacker-build-websetup.exe")) + BuildWebSetupFileLength = new FileInfo(BuildOutputFolder + "\\processhacker-build-websetup.exe").Length; if (File.Exists(BuildOutputFolder + "\\processhacker-build-setup.exe")) BuildSetupFileLength = new FileInfo(BuildOutputFolder + "\\processhacker-build-setup.exe").Length; if (File.Exists(BuildOutputFolder + "\\processhacker-build-bin.zip")) BuildBinFileLength = new FileInfo(BuildOutputFolder + "\\processhacker-build-bin.zip").Length; + if (File.Exists(BuildOutputFolder + "\\processhacker-build-websetup.exe")) + BuildWebSetupHash = Verify.HashFile(BuildOutputFolder + "\\processhacker-build-websetup.exe"); if (File.Exists(BuildOutputFolder + "\\processhacker-build-setup.exe")) BuildSetupHash = Verify.HashFile(BuildOutputFolder + "\\processhacker-build-setup.exe"); if (File.Exists(BuildOutputFolder + "\\processhacker-build-bin.zip")) BuildBinHash = Verify.HashFile(BuildOutputFolder + "\\processhacker-build-bin.zip"); StringBuilder sb = new StringBuilder(); + sb.AppendLine("processhacker-build-websetup.exe"); + sb.AppendLine("SHA256: " + BuildWebSetupHash + Environment.NewLine); sb.AppendLine("processhacker-build-setup.exe"); sb.AppendLine("SHA256: " + BuildSetupHash + Environment.NewLine); sb.AppendLine("processhacker-build-bin.zip"); @@ -830,7 +881,7 @@ public static bool BuildChecksumsFile() public static bool BuildUpdateSignature() { - Program.PrintColorMessage("Building release signature...", ConsoleColor.Cyan); + Program.PrintColorMessage("Building release signatures...", ConsoleColor.Cyan); if (!File.Exists(CustomSignToolPath)) { @@ -844,14 +895,24 @@ public static bool BuildUpdateSignature() return true; } + if (!File.Exists(BuildOutputFolder + "\\processhacker-build-websetup.exe")) + { + Program.PrintColorMessage("[SKIPPED] websetup-setup.exe not found.", ConsoleColor.Yellow); + return false; + } + if (!File.Exists(BuildOutputFolder + "\\processhacker-build-setup.exe")) { Program.PrintColorMessage("[SKIPPED] build-setup.exe not found.", ConsoleColor.Yellow); return false; } - BuildSetupSig = Win32.ShellExecute( + BuildWebSetupSig = Win32.ShellExecute( CustomSignToolPath, + "sign -k build\\nightly.key " + BuildOutputFolder + "\\processhacker-build-websetup.exe -h" + ); + BuildSetupSig = Win32.ShellExecute( + CustomSignToolPath, "sign -k build\\nightly.key " + BuildOutputFolder + "\\processhacker-build-setup.exe -h" ); @@ -865,11 +926,17 @@ public static string GetBuildLogString() public static void WebServiceUpdateConfig() { + if (string.IsNullOrEmpty(BuildVersion)) + return; if (string.IsNullOrEmpty(BuildSetupHash)) return; + if (string.IsNullOrEmpty(BuildSetupSig)) + return; if (string.IsNullOrEmpty(BuildBinHash)) return; - if (string.IsNullOrEmpty(BuildSetupSig)) + if (string.IsNullOrEmpty(BuildWebSetupSig)) + return; + if (string.IsNullOrEmpty(BuildWebSetupVersion)) return; string buildChangelog = Win32.ShellExecute(GitExePath, "log -n 30 --date=format:%Y-%m-%d --pretty=format:\"[%cd] %s (%an)\""); @@ -877,14 +944,23 @@ public static void WebServiceUpdateConfig() string buildPostString = Json.Serialize(new BuildUpdateRequest { Updated = TimeStart.ToString("o"), - Version = BuildVersion, FileLength = BuildSetupFileLength.ToString(), ForumUrl = "https://wj32.org/processhacker/nightly.php", - Setupurl = "https://ci.appveyor.com/api/projects/processhacker/processhacker2/artifacts/processhacker-" + BuildVersion + "-setup.exe", - Binurl = "https://ci.appveyor.com/api/projects/processhacker/processhacker2/artifacts/processhacker-" + BuildVersion + "-bin.zip", - HashSetup = BuildSetupHash, - HashBin = BuildBinHash, - sig = BuildSetupSig, + + SetupUrl = "https://ci.appveyor.com/api/projects/processhacker/processhacker2/artifacts/processhacker-" + BuildVersion + "-setup.exe", + SetupVersion = BuildVersion, + SetupHash = BuildSetupHash, + SetupSig = BuildSetupSig, + + BinUrl = "https://ci.appveyor.com/api/projects/processhacker/processhacker2/artifacts/processhacker-" + BuildVersion + "-bin.zip", + BinHash = BuildBinHash, + //BinSig = BuildBinSig, + + WebSetupUrl = "https://ci.appveyor.com/api/projects/processhacker/processhacker2/artifacts/processhacker-" + BuildVersion + "-websetup.exe", + WebSetupHash = BuildWebSetupHash, + WebSetupVersion = BuildWebSetupVersion, + WebSetupSig = BuildWebSetupSig, + Message = buildSummary, Changelog = buildChangelog, }); @@ -930,12 +1006,14 @@ public static bool AppveyorUploadBuildFiles() { string[] buildFileArray = { + BuildOutputFolder + "\\processhacker-build-websetup.exe", BuildOutputFolder + "\\processhacker-build-setup.exe", BuildOutputFolder + "\\processhacker-build-bin.zip", BuildOutputFolder + "\\processhacker-build-checksums.txt" }; string[] releaseFileArray = { + BuildOutputFolder + "\\processhacker-" + BuildVersion + "-websetup.exe", BuildOutputFolder + "\\processhacker-" + BuildVersion + "-setup.exe", BuildOutputFolder + "\\processhacker-" + BuildVersion + "-bin.zip", BuildOutputFolder + "\\processhacker-" + BuildVersion + "-checksums.txt" @@ -1007,16 +1085,22 @@ public static bool BuildSolution(string Solution, BuildFlags Flags) { if ((Flags & BuildFlags.Build32bit) == BuildFlags.Build32bit) { + StringBuilder compilerOptions = new StringBuilder(); Program.PrintColorMessage("Building " + Path.GetFileNameWithoutExtension(Solution) + " (", ConsoleColor.Cyan, false, Flags); Program.PrintColorMessage("x32", ConsoleColor.Green, false, Flags); Program.PrintColorMessage(")...", ConsoleColor.Cyan, true, Flags); + if (Flags.HasFlag(BuildFlags.BuildApi)) + compilerOptions.Append("PH_BUILD_API;"); + compilerOptions.Append("PHAPP_VERSION_REVISION=\"" + BuildRevision + "\";"); + compilerOptions.Append("PHAPP_VERSION_BUILD=\"" + BuildCount + "\""); + string error32 = Win32.ShellExecute( MSBuildExePath, "/m /nologo /verbosity:quiet " + "/p:Configuration=" + (Flags.HasFlag(BuildFlags.BuildDebug) ? "Debug " : "Release ") + "/p:Platform=Win32 " + - "/p:ExternalCompilerOptions=\"PH_BUILD_API;PHAPP_VERSION_REVISION=\"" + BuildRevision + "\";PHAPP_VERSION_BUILD=\"" + BuildCount + "\"\" " + + "/p:ExternalCompilerOptions=\"" + compilerOptions.ToString() + "\" " + Solution ); @@ -1029,16 +1113,22 @@ public static bool BuildSolution(string Solution, BuildFlags Flags) if ((Flags & BuildFlags.Build64bit) == BuildFlags.Build64bit) { + StringBuilder compilerOptions = new StringBuilder(); Program.PrintColorMessage("Building " + Path.GetFileNameWithoutExtension(Solution) + " (", ConsoleColor.Cyan, false, Flags); Program.PrintColorMessage("x64", ConsoleColor.Green, false, Flags); Program.PrintColorMessage(")...", ConsoleColor.Cyan, true, Flags); + if (Flags.HasFlag(BuildFlags.BuildApi)) + compilerOptions.Append("PH_BUILD_API;"); + compilerOptions.Append("PHAPP_VERSION_REVISION=\"" + BuildRevision + "\";"); + compilerOptions.Append("PHAPP_VERSION_BUILD=\"" + BuildCount + "\""); + string error64 = Win32.ShellExecute( MSBuildExePath, "/m /nologo /verbosity:quiet " + "/p:Configuration=" + (Flags.HasFlag(BuildFlags.BuildDebug) ? "Debug " : "Release ") + "/p:Platform=x64 " + - "/p:ExternalCompilerOptions=\"PH_BUILD_API;PHAPP_VERSION_REVISION=\"" + BuildRevision + "\";PHAPP_VERSION_BUILD=\"" + BuildCount + "\"\" " + + "/p:ExternalCompilerOptions=\"" + compilerOptions.ToString() + "\" " + Solution ); diff --git a/tools/CustomBuildTool/Source Files/Program.cs b/tools/CustomBuildTool/Source Files/Program.cs index 18cd8d9e43b6..05eda6988b8f 100644 --- a/tools/CustomBuildTool/Source Files/Program.cs +++ b/tools/CustomBuildTool/Source Files/Program.cs @@ -108,7 +108,7 @@ public static void Main(string[] args) if (!Build.BuildSolution("ProcessHacker.sln", BuildFlags.Build32bit | BuildFlags.Build64bit | - BuildFlags.BuildVerbose + BuildFlags.BuildVerbose | BuildFlags.BuildApi )) { return; @@ -127,7 +127,9 @@ public static void Main(string[] args) Build.CopyKeyFiles(); if (!Build.BuildSolution("ProcessHacker.sln", - BuildFlags.Build32bit | BuildFlags.Build64bit | BuildFlags.BuildVerbose)) + BuildFlags.Build32bit | BuildFlags.Build64bit | + BuildFlags.BuildVerbose | BuildFlags.BuildApi + )) return; if (!Build.CopyKProcessHacker( @@ -138,7 +140,9 @@ public static void Main(string[] args) return; if (!Build.BuildSolution("plugins\\Plugins.sln", - BuildFlags.Build32bit | BuildFlags.Build64bit | BuildFlags.BuildVerbose)) + BuildFlags.Build32bit | BuildFlags.Build64bit | + BuildFlags.BuildVerbose | BuildFlags.BuildApi + )) return; if (!Build.CopyWow64Files(BuildFlags.None)) @@ -159,7 +163,9 @@ public static void Main(string[] args) if (!Build.BuildSolution("ProcessHacker.sln", BuildFlags.Build32bit | BuildFlags.Build64bit | - BuildFlags.BuildDebug | BuildFlags.BuildVerbose)) + BuildFlags.BuildDebug | BuildFlags.BuildVerbose | + BuildFlags.BuildApi + )) return; if (!Build.CopyKProcessHacker( @@ -177,7 +183,8 @@ public static void Main(string[] args) if (!Build.BuildSolution("plugins\\Plugins.sln", BuildFlags.Build32bit | BuildFlags.Build64bit | - BuildFlags.BuildDebug | BuildFlags.BuildVerbose + BuildFlags.BuildDebug | BuildFlags.BuildVerbose | + BuildFlags.BuildApi )) { return; @@ -197,7 +204,9 @@ public static void Main(string[] args) Build.CopyKeyFiles(); if (!Build.BuildSolution("ProcessHacker.sln", - BuildFlags.Build32bit | BuildFlags.Build64bit | BuildFlags.BuildVerbose)) + BuildFlags.Build32bit | BuildFlags.Build64bit | + BuildFlags.BuildVerbose | BuildFlags.BuildApi + )) return; if (!Build.CopyKProcessHacker(BuildFlags.Build32bit | BuildFlags.Build64bit | BuildFlags.BuildVerbose)) @@ -206,7 +215,10 @@ public static void Main(string[] args) if (!BuildSdk(BuildFlags.Build32bit | BuildFlags.Build64bit | BuildFlags.BuildVerbose)) return; - if (!Build.BuildSolution("plugins\\Plugins.sln", BuildFlags.Build32bit | BuildFlags.Build64bit | BuildFlags.BuildVerbose)) + if (!Build.BuildSolution("plugins\\Plugins.sln", + BuildFlags.Build32bit | BuildFlags.Build64bit | + BuildFlags.BuildVerbose | BuildFlags.BuildApi + )) return; if (!Build.CopyWow64Files(BuildFlags.None)) @@ -214,6 +226,8 @@ public static void Main(string[] args) if (!Build.BuildBinZip()) return; + if (!Build.BuildWebSetupExe()) + return; if (!Build.BuildSetupExe()) return; if (!Build.BuildChecksumsFile()) @@ -232,13 +246,19 @@ public static void Main(string[] args) Build.ShowBuildEnvironment("appx", true, true); Build.CopyKeyFiles(); - if (!Build.BuildSolution("ProcessHacker.sln", BuildFlags.Build32bit | BuildFlags.Build64bit | BuildFlags.BuildVerbose)) + if (!Build.BuildSolution("ProcessHacker.sln", + BuildFlags.Build32bit | BuildFlags.Build64bit | + BuildFlags.BuildVerbose | BuildFlags.BuildApi + )) return; if (!BuildSdk(BuildFlags.Build32bit | BuildFlags.Build64bit | BuildFlags.BuildVerbose)) return; - if (!Build.BuildSolution("plugins\\Plugins.sln", BuildFlags.Build32bit | BuildFlags.Build64bit | BuildFlags.BuildVerbose)) + if (!Build.BuildSolution("plugins\\Plugins.sln", + BuildFlags.Build32bit | BuildFlags.Build64bit | + BuildFlags.BuildVerbose | BuildFlags.BuildApi + )) return; if (!Build.CopyWow64Files(BuildFlags.None)) @@ -271,7 +291,9 @@ public static void Main(string[] args) Build.CopyKeyFiles(); if (!Build.BuildSolution("ProcessHacker.sln", - BuildFlags.Build32bit | BuildFlags.Build64bit | BuildFlags.BuildVerbose)) + BuildFlags.Build32bit | BuildFlags.Build64bit | + BuildFlags.BuildVerbose | BuildFlags.BuildApi + )) return; if (!Build.CopyKProcessHacker(BuildFlags.Build32bit | BuildFlags.Build64bit | BuildFlags.BuildVerbose)) @@ -281,7 +303,9 @@ public static void Main(string[] args) return; if (!Build.BuildSolution("plugins\\Plugins.sln", - BuildFlags.Build32bit | BuildFlags.Build64bit | BuildFlags.BuildVerbose)) + BuildFlags.Build32bit | BuildFlags.Build64bit | + BuildFlags.BuildVerbose | BuildFlags.BuildApi + )) return; if (!Build.CopyWow64Files(BuildFlags.None)) @@ -373,9 +397,10 @@ private static bool Restart(string Arguments) public enum BuildFlags { None, - Build32bit = 0x1, - Build64bit = 0x2, - BuildDebug = 0x4, - BuildVerbose = 0x8 + Build32bit = 1, + Build64bit = 2, + BuildDebug = 4, + BuildVerbose = 8, + BuildApi = 16, } } \ No newline at end of file diff --git a/tools/CustomBuildTool/Source Files/Utils.cs b/tools/CustomBuildTool/Source Files/Utils.cs index dd7677d380e8..7a9beb885330 100644 --- a/tools/CustomBuildTool/Source Files/Utils.cs +++ b/tools/CustomBuildTool/Source Files/Utils.cs @@ -335,38 +335,26 @@ public VisualStudioInstance(ISetupInstance2 FromInstance) [DataContract] public class BuildUpdateRequest { - [DataMember(Name = "updated")] - public string Updated { get; set; } - - [DataMember(Name = "version")] - public string Version { get; set; } - - [DataMember(Name = "size")] - public string FileLength { get; set; } - - [DataMember(Name = "forum_url")] - public string ForumUrl { get; set; } - - [DataMember(Name = "setup_url")] - public string Setupurl { get; set; } - - [DataMember(Name = "bin_url")] - public string Binurl { get; set; } - - [DataMember(Name = "hash_setup")] - public string HashSetup { get; set; } - - [DataMember(Name = "hash_bin")] - public string HashBin { get; set; } - - [DataMember(Name = "sig")] - public string sig { get; set; } - - [DataMember(Name = "message")] - public string Message { get; set; } - - [DataMember(Name = "changelog")] - public string Changelog { get; set; } + [DataMember(Name = "updated")] public string Updated { get; set; } + [DataMember(Name = "size")] public string FileLength { get; set; } + [DataMember(Name = "forum_url")] public string ForumUrl { get; set; } + + [DataMember(Name = "bin_url")] public string BinUrl { get; set; } + [DataMember(Name = "hash_bin")] public string BinHash { get; set; } + [DataMember(Name = "bin_sig")] public string BinSig { get; set; } + + [DataMember(Name = "setup_url")] public string SetupUrl { get; set; } + [DataMember(Name = "hash")] public string SetupHash { get; set; } + [DataMember(Name = "sig")] public string SetupSig { get; set; } + [DataMember(Name = "version")] public string SetupVersion { get; set; } + + [DataMember(Name = "websetup_url")] public string WebSetupUrl { get; set; } + [DataMember(Name = "websetup_hash")] public string WebSetupHash { get; set; } + [DataMember(Name = "websetup_sig")] public string WebSetupSig { get; set; } + [DataMember(Name = "websetup_version")] public string WebSetupVersion { get; set; } + + [DataMember(Name = "message")] public string Message { get; set; } + [DataMember(Name = "changelog")] public string Changelog { get; set; } } [Flags] diff --git a/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj b/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj index 02cea7f702b1..9cde444d6474 100644 --- a/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj +++ b/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj @@ -109,7 +109,7 @@ - + @@ -125,14 +125,15 @@ - - - - - + + + + + + diff --git a/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj.filters b/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj.filters index b2499c2417c6..fed6da63ac64 100644 --- a/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj.filters +++ b/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj.filters @@ -36,18 +36,6 @@ Source Files - - Source Files\pages - - - Source Files\pages - - - Source Files\pages - - - Source Files\pages - Source Files @@ -69,9 +57,6 @@ Source Files - - Source Files\pages - Source Files\json @@ -105,9 +90,27 @@ Source Files\json - + + Source Files\pages + + + Source Files\pages + + Source Files\pages + + Source Files\pages + + + Source Files\pages + + + Source Files\pages + + + Source Files + diff --git a/tools/CustomSetupTool/CustomSetupTool/appsup.c b/tools/CustomSetupTool/CustomSetupTool/appsup.c index e4a887d1f3c5..c94f746e94aa 100644 --- a/tools/CustomSetupTool/CustomSetupTool/appsup.c +++ b/tools/CustomSetupTool/CustomSetupTool/appsup.c @@ -376,6 +376,8 @@ VOID SetupCreateLink( // Save the shortcut to the file system... IPersistFile_Save(persistFilePtr, LinkFilePath, TRUE); + SHChangeNotify(SHCNE_UPDATEITEM, SHCNF_PATH | SHCNF_FLUSHNOWAIT, LinkFilePath, NULL); + CleanupExit: if (persistFilePtr) IPersistFile_Release(persistFilePtr); @@ -404,7 +406,9 @@ BOOLEAN DialogPromptExit( return buttonPressed == IDNO; } -BOOLEAN CheckProcessHackerRunning(VOID) +BOOLEAN CheckProcessHackerRunning( + VOID + ) { HANDLE mutantHandle; OBJECT_ATTRIBUTES oa; @@ -432,25 +436,35 @@ BOOLEAN CheckProcessHackerRunning(VOID) return FALSE; } -BOOLEAN CheckProcessHackerInstalled(VOID) +BOOLEAN CheckProcessHackerInstalled( + VOID + ) { BOOLEAN installed = FALSE; PPH_STRING installPath; - + PPH_STRING exePath; + installPath = GetProcessHackerInstallPath(); - if (!PhIsNullOrEmptyString(installPath) && PhEndsWithString2(installPath, L"ProcessHacker.exe", TRUE)) + if (!PhIsNullOrEmptyString(installPath)) { + exePath = PhConcatStrings2(installPath->Buffer, L"\\ProcessHacker.exe"); + // Check if the value has a valid file path. - installed = GetFileAttributes(installPath->Buffer) != INVALID_FILE_ATTRIBUTES; + installed = GetFileAttributes(PhGetString(exePath)) != INVALID_FILE_ATTRIBUTES; + + PhDereferenceObject(exePath); } - PhClearReference(&installPath); + if (installPath) + PhDereferenceObject(installPath); return installed; } -PPH_STRING GetProcessHackerInstallPath(VOID) +PPH_STRING GetProcessHackerInstallPath( + VOID + ) { HANDLE keyHandle; PPH_STRING installPath = NULL; diff --git a/tools/CustomSetupTool/CustomSetupTool/page3.c b/tools/CustomSetupTool/CustomSetupTool/configpage.c similarity index 98% rename from tools/CustomSetupTool/CustomSetupTool/page3.c rename to tools/CustomSetupTool/CustomSetupTool/configpage.c index b4dbe1e2adb2..f016e5902fb6 100644 --- a/tools/CustomSetupTool/CustomSetupTool/page3.c +++ b/tools/CustomSetupTool/CustomSetupTool/configpage.c @@ -72,7 +72,7 @@ INT_PTR CALLBACK SetupPropPage3_WndProc( Button_SetCheck(GetDlgItem(hwndDlg, IDC_SHORTCUT_ALL_CHECK), TRUE); //Button_SetCheck(GetDlgItem(hwndDlg, IDC_KPH_CHECK), TRUE); //Button_SetCheck(GetDlgItem(hwndDlg, IDC_DBGTOOLS_CHECK), TRUE); - Button_SetCheck(GetDlgItem(hwndDlg, IDC_PHSTART_CHECK), TRUE); + //Button_SetCheck(GetDlgItem(hwndDlg, IDC_PHSTART_CHECK), TRUE); EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); } diff --git a/tools/CustomSetupTool/CustomSetupTool/download.c b/tools/CustomSetupTool/CustomSetupTool/download.c index 9b6ee0885a3a..eeb0259e5789 100644 --- a/tools/CustomSetupTool/CustomSetupTool/download.c +++ b/tools/CustomSetupTool/CustomSetupTool/download.c @@ -81,7 +81,7 @@ BOOLEAN ParseVersionString( PH_STRINGREF remaining, majorPart, minorPart, revisionPart; ULONG64 majorInteger = 0, minorInteger = 0, revisionInteger = 0; - PhInitializeStringRef(&remaining, PhGetStringOrEmpty(Context->Version)); + PhInitializeStringRef(&remaining, PhGetStringOrEmpty(Context->SetupFileVersion)); PhSplitStringRefAtChar(&remaining, '.', &majorPart, &remaining); PhSplitStringRefAtChar(&remaining, '.', &minorPart, &remaining); @@ -161,7 +161,6 @@ json_object_ptr json_get_object( return NULL; } - BOOLEAN SetupQueryUpdateData( _Inout_ PPH_SETUP_CONTEXT Context ) @@ -175,6 +174,7 @@ BOOLEAN SetupQueryUpdateData( PVOID jsonObject = NULL; PPH_STRING versionHeader = UpdateVersionString(); PPH_STRING windowsHeader = UpdateWindowsString(); + PSTR value = NULL; if (!(httpSessionHandle = WinHttpOpen( NULL, @@ -280,34 +280,53 @@ BOOLEAN SetupQueryUpdateData( if (!(jsonObject = json_tokener_parse(stringBuffer))) goto CleanupExit; - Context->Version = PhConvertUtf8ToUtf16(json_object_get_string(json_get_object(jsonObject, "version"))); - //Context->RevVersion = PhConvertUtf8ToUtf16(json_object_get_string(json_get_object(jsonObject, "rev"))); - Context->RelDate = PhConvertUtf8ToUtf16(json_object_get_string(json_get_object(jsonObject, "updated"))); - Context->Size = PhFormatSize(json_object_get_int64(json_get_object(jsonObject, "size")), -1); - Context->Hash = PhConvertUtf8ToUtf16(json_object_get_string(json_get_object(jsonObject, "hash_setup"))); - Context->Signature = PhConvertUtf8ToUtf16(json_object_get_string(json_get_object(jsonObject, "sig"))); - Context->ReleaseNotesUrl = PhConvertUtf8ToUtf16(json_object_get_string(json_get_object(jsonObject, "forum_url"))); - Context->BinFileDownloadUrl = PhConvertUtf8ToUtf16(json_object_get_string(json_get_object(jsonObject, "bin_url"))); - //Context->SetupFileDownloadUrl = PhConvertUtf8ToUtf16(json_object_get_string(json_get_object(jsonObject, "setup_url"))); - //Context->BuildMessage = PhConvertUtf8ToUtf16(GetJsonValueAsString(jsonObject, "changelog")); - - if (PhIsNullOrEmptyString(Context->Version)) - goto CleanupExit; + if (value = json_object_get_string(json_get_object(jsonObject, "updated"))) + Context->RelDate = PhConvertUtf8ToUtf16(value); + if (value = json_object_get_string(json_get_object(jsonObject, "size"))) + Context->Size = PhConvertUtf8ToUtf16(value); + if (value = json_object_get_string(json_get_object(jsonObject, "forum_url"))) + Context->ReleaseNotesUrl = PhConvertUtf8ToUtf16(value); + + if (value = json_object_get_string(json_get_object(jsonObject, "bin_url"))) + Context->BinFileDownloadUrl = PhConvertUtf8ToUtf16(value); + if (value = json_object_get_string(json_get_object(jsonObject, "hash_bin"))) + Context->BinFileHash = PhConvertUtf8ToUtf16(value); + + if (value = json_object_get_string(json_get_object(jsonObject, "setup_url"))) + Context->SetupFileDownloadUrl = PhConvertUtf8ToUtf16(value); + if (value = json_object_get_string(json_get_object(jsonObject, "sig"))) + Context->SetupFileSignature = PhConvertUtf8ToUtf16(value); + if (value = json_object_get_string(json_get_object(jsonObject, "version"))) + Context->SetupFileVersion = PhConvertUtf8ToUtf16(value); + + if (value = json_object_get_string(json_get_object(jsonObject, "websetup_url"))) + Context->WebSetupFileDownloadUrl = PhConvertUtf8ToUtf16(value); + if (value = json_object_get_string(json_get_object(jsonObject, "websetup_sig"))) + Context->WebSetupFileSignature = PhConvertUtf8ToUtf16(value); + if (value = json_object_get_string(json_get_object(jsonObject, "websetup_version"))) + Context->WebSetupFileVersion = PhConvertUtf8ToUtf16(value); + if (!ParseVersionString(Context)) goto CleanupExit; - if (PhIsNullOrEmptyString(Context->Signature)) - goto CleanupExit; if (PhIsNullOrEmptyString(Context->RelDate)) goto CleanupExit; if (PhIsNullOrEmptyString(Context->Size)) goto CleanupExit; - if (PhIsNullOrEmptyString(Context->Hash)) - goto CleanupExit; if (PhIsNullOrEmptyString(Context->ReleaseNotesUrl)) goto CleanupExit; + if (PhIsNullOrEmptyString(Context->BinFileDownloadUrl)) goto CleanupExit; + if (PhIsNullOrEmptyString(Context->BinFileHash)) + goto CleanupExit; + + if (PhIsNullOrEmptyString(Context->SetupFileDownloadUrl)) + goto CleanupExit; + if (PhIsNullOrEmptyString(Context->SetupFileSignature)) + goto CleanupExit; + if (PhIsNullOrEmptyString(Context->SetupFileVersion)) + goto CleanupExit; success = TRUE; @@ -381,7 +400,7 @@ BOOLEAN UpdateDownloadUpdateData( ); } - Context->SetupFilePath = PhFormatString( + Context->FilePath = PhFormatString( L"%s%s\\processhacker-%lu.%lu.%lu-bin.zip", PhGetStringOrEmpty(setupTempPath), PhGetStringOrEmpty(randomGuidString), @@ -389,10 +408,10 @@ BOOLEAN UpdateDownloadUpdateData( Context->LatestMinorVersion, Context->LatestRevisionVersion ); - if (PhIsNullOrEmptyString(Context->SetupFilePath)) + if (PhIsNullOrEmptyString(Context->FilePath)) goto CleanupExit; - if (fullSetupPath = PhGetFullPath(PhGetString(Context->SetupFilePath), &indexOfFileName)) + if (fullSetupPath = PhGetFullPath(PhGetString(Context->FilePath), &indexOfFileName)) { PPH_STRING directoryPath; @@ -408,7 +427,7 @@ BOOLEAN UpdateDownloadUpdateData( if (!NT_SUCCESS(PhCreateFileWin32( &tempFileHandle, - PhGetString(Context->SetupFilePath), + PhGetString(Context->FilePath), FILE_GENERIC_READ | FILE_GENERIC_WRITE, FILE_ATTRIBUTE_NOT_CONTENT_INDEXED | FILE_ATTRIBUTE_TEMPORARY, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, diff --git a/tools/CustomSetupTool/CustomSetupTool/page5.c b/tools/CustomSetupTool/CustomSetupTool/downloadpage.c similarity index 94% rename from tools/CustomSetupTool/CustomSetupTool/page5.c rename to tools/CustomSetupTool/CustomSetupTool/downloadpage.c index b480f83c671b..ced62e004766 100644 --- a/tools/CustomSetupTool/CustomSetupTool/page5.c +++ b/tools/CustomSetupTool/CustomSetupTool/downloadpage.c @@ -29,6 +29,9 @@ NTSTATUS SetupDownloadProgressThread( if (!SetupQueryUpdateData(Context)) goto CleanupExit; + //if (SetupUpdateWebSetupBuild(Context)) + // goto CleanupExit; + if (!UpdateDownloadUpdateData(Context)) goto CleanupExit; @@ -85,8 +88,6 @@ INT_PTR CALLBACK SetupPropPage5_WndProc( { case PSN_SETACTIVE: { - HANDLE threadHandle; - context->MainHeaderHandle = GetDlgItem(hwndDlg, IDC_MAINHEADER); context->StatusHandle = GetDlgItem(hwndDlg, IDC_INSTALL_STATUS); context->SubStatusHandle = GetDlgItem(hwndDlg, IDC_INSTALL_SUBSTATUS); @@ -99,8 +100,7 @@ INT_PTR CALLBACK SetupPropPage5_WndProc( // Disable Next/Back buttons PropSheet_SetWizButtons(context->DialogHandle, 0); - if (threadHandle = PhCreateThread(0, SetupDownloadProgressThread, context)) - NtClose(threadHandle); + PhCreateThread2(SetupDownloadProgressThread, context); } break; } diff --git a/tools/CustomSetupTool/CustomSetupTool/error.c b/tools/CustomSetupTool/CustomSetupTool/errorpage.c similarity index 100% rename from tools/CustomSetupTool/CustomSetupTool/error.c rename to tools/CustomSetupTool/CustomSetupTool/errorpage.c diff --git a/tools/CustomSetupTool/CustomSetupTool/extract.c b/tools/CustomSetupTool/CustomSetupTool/extract.c index 6d7113314572..a82b278aae02 100644 --- a/tools/CustomSetupTool/CustomSetupTool/extract.c +++ b/tools/CustomSetupTool/CustomSetupTool/extract.c @@ -74,10 +74,10 @@ BOOLEAN SetupExtractBuild( #else PPH_BYTES zipPathUtf8; - if (!Context->SetupFilePath) + if (PhIsNullOrEmptyString(Context->FilePath)) goto CleanupExit; - zipPathUtf8 = PhConvertUtf16ToUtf8(PhGetString(Context->SetupFilePath)); + zipPathUtf8 = PhConvertUtf16ToUtf8(PhGetString(Context->FilePath)); if (!(status = mz_zip_reader_init_file(&zip_archive, zipPathUtf8->Buffer, 0))) goto CleanupExit; diff --git a/tools/CustomSetupTool/CustomSetupTool/include/appsup.h b/tools/CustomSetupTool/CustomSetupTool/include/appsup.h index 8b71866e1cdf..5a173e411ec9 100644 --- a/tools/CustomSetupTool/CustomSetupTool/include/appsup.h +++ b/tools/CustomSetupTool/CustomSetupTool/include/appsup.h @@ -68,6 +68,10 @@ HBITMAP LoadPngImageFromResources( _In_ PCWSTR Name ); +BOOLEAN CheckProcessHackerInstalled( + VOID + ); + PPH_STRING GetProcessHackerInstallPath( VOID ); diff --git a/tools/CustomSetupTool/CustomSetupTool/include/setup.h b/tools/CustomSetupTool/CustomSetupTool/include/setup.h index 60498e436fd2..78eccacb55ad 100644 --- a/tools/CustomSetupTool/CustomSetupTool/include/setup.h +++ b/tools/CustomSetupTool/CustomSetupTool/include/setup.h @@ -104,17 +104,22 @@ typedef struct _PH_SETUP_CONTEXT BOOLEAN SetupStartAppAfterExit; ULONG ErrorCode; - PPH_STRING Version; + PPH_STRING FilePath; PPH_STRING RevVersion; PPH_STRING RelDate; PPH_STRING Size; - PPH_STRING Hash; - PPH_STRING Signature; PPH_STRING ReleaseNotesUrl; PPH_STRING BinFileDownloadUrl; - //PPH_STRING SetupFileDownloadUrl; - PPH_STRING SetupFilePath; + PPH_STRING BinFileHash; + + PPH_STRING SetupFileDownloadUrl; + PPH_STRING SetupFileSignature; + PPH_STRING SetupFileVersion; + + PPH_STRING WebSetupFileDownloadUrl; + PPH_STRING WebSetupFileSignature; + PPH_STRING WebSetupFileVersion; HWND MainHeaderHandle; HWND StatusHandle; @@ -156,7 +161,7 @@ INT_PTR CALLBACK SetupPropPage3_WndProc( _Inout_ LPARAM lParam ); -INT_PTR CALLBACK SetupPropPage4_WndProc( +INT_PTR CALLBACK SetupInstallPropPage_WndProc( _In_ HWND hwndDlg, _In_ UINT uMsg, _Inout_ WPARAM wParam, @@ -224,6 +229,10 @@ VOID SetupUpgradeSettingsFile( VOID ); +VOID SetupCreateImageFileExecutionOptions( + VOID + ); + // download.c BOOLEAN SetupQueryUpdateData( @@ -246,6 +255,12 @@ VOID SetupShowUpdateDialog( VOID ); +// updatesetup.c + +NTSTATUS SetupUpdateWebSetupBuild( + _In_ PPH_SETUP_CONTEXT Context + ); + // uninstall.c VOID SetupShowUninstallDialog( diff --git a/tools/CustomSetupTool/CustomSetupTool/page4.c b/tools/CustomSetupTool/CustomSetupTool/installpage.c similarity index 98% rename from tools/CustomSetupTool/CustomSetupTool/page4.c rename to tools/CustomSetupTool/CustomSetupTool/installpage.c index 94d2571c126d..8211041e995e 100644 --- a/tools/CustomSetupTool/CustomSetupTool/page4.c +++ b/tools/CustomSetupTool/CustomSetupTool/installpage.c @@ -59,6 +59,9 @@ NTSTATUS SetupProgressThread( // Create autorun and shortcuts. SetupSetWindowsOptions(Context); + // Set the default image execution options. + SetupCreateImageFileExecutionOptions(); + // Setup new installation. if (!SetupExtractBuild(Context)) goto CleanupExit; @@ -76,7 +79,7 @@ NTSTATUS SetupProgressThread( return STATUS_FAIL_CHECK; } -INT_PTR CALLBACK SetupPropPage4_WndProc( +INT_PTR CALLBACK SetupInstallPropPage_WndProc( _In_ HWND hwndDlg, _In_ UINT uMsg, _Inout_ WPARAM wParam, diff --git a/tools/CustomSetupTool/CustomSetupTool/page2.c b/tools/CustomSetupTool/CustomSetupTool/licencepage.c similarity index 100% rename from tools/CustomSetupTool/CustomSetupTool/page2.c rename to tools/CustomSetupTool/CustomSetupTool/licencepage.c diff --git a/tools/CustomSetupTool/CustomSetupTool/main.c b/tools/CustomSetupTool/CustomSetupTool/main.c index 7daea4ac97a9..80ab2834b87a 100644 --- a/tools/CustomSetupTool/CustomSetupTool/main.c +++ b/tools/CustomSetupTool/CustomSetupTool/main.c @@ -157,6 +157,11 @@ INT WINAPI wWinMain( } } +#ifdef _DEBUG + if (CheckProcessHackerInstalled()) + SetupMode = SETUP_COMMAND_UNINSTALL; +#endif + switch (SetupMode) { case SETUP_COMMAND_INSTALL: @@ -219,7 +224,7 @@ INT WINAPI wWinMain( propSheetPage.pszTitle = PhApplicationName; propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_DIALOG4); propSheetPage.hInstance = PhInstanceHandle; - propSheetPage.pfnDlgProc = SetupPropPage4_WndProc; + propSheetPage.pfnDlgProc = SetupInstallPropPage_WndProc; pages[propSheetHeader.nPages++] = CreatePropertySheetPage(&propSheetPage); // error page diff --git a/tools/CustomSetupTool/CustomSetupTool/resources/version.rc b/tools/CustomSetupTool/CustomSetupTool/resources/version.rc index 780765938665..6d78a05f559e 100644 --- a/tools/CustomSetupTool/CustomSetupTool/resources/version.rc +++ b/tools/CustomSetupTool/CustomSetupTool/resources/version.rc @@ -8,7 +8,13 @@ // Generated from the TEXTINCLUDE 2 resource. // #include "winres.h" + +#if defined(PH_BUILD_API) #include "../../../../ProcessHacker/include/phappres.h" +#else +#define PHAPP_VERSION_NUMBER 1,0,0,0 +#define PHAPP_VERSION_STRING "1,0,0,0" +#endif ///////////////////////////////////////////////////////////////////////////// #undef APSTUDIO_READONLY_SYMBOLS @@ -34,7 +40,9 @@ END 2 TEXTINCLUDE BEGIN "#include ""winres.h""\r\n" +#if defined(PH_BUILD_API) "#include ""../../../../ProcessHacker/include/phappres.h""\r\n" +#endif "\0" END @@ -100,7 +108,7 @@ END // // RCDATA // -#if defined(APSTUDIO_INVOKED) || defined(PH_BUILD_API) +#if defined(PH_BUILD_API) IDR_BIN_DATA RCDATA "../../../../build/output/processhacker-build-bin.zip" diff --git a/tools/CustomSetupTool/CustomSetupTool/setup.c b/tools/CustomSetupTool/CustomSetupTool/setup.c index 31009632e79a..256dc4f4a25a 100644 --- a/tools/CustomSetupTool/CustomSetupTool/setup.c +++ b/tools/CustomSetupTool/CustomSetupTool/setup.c @@ -323,19 +323,7 @@ VOID SetupStartKph( )) { NtWaitForSingleObject(processHandle, FALSE, &timeout); - } - - SC_HANDLE serviceHandle; - BOOLEAN success = FALSE; - - serviceHandle = PhOpenService(L"KProcessHacker3", SERVICE_START); - - if (serviceHandle) - { - if (StartService(serviceHandle, 0, NULL)) - success = TRUE; - - CloseServiceHandle(serviceHandle); + NtClose(processHandle); } } @@ -389,21 +377,40 @@ VOID SetupSetWindowsOptions( { static PH_STRINGREF TaskMgrImageOptionsKeyName = PH_STRINGREF_INIT(L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\taskmgr.exe"); static PH_STRINGREF CurrentUserRunKeyName = PH_STRINGREF_INIT(L"Software\\Microsoft\\Windows\\CurrentVersion\\Run"); + HANDLE keyHandle; PPH_STRING clientPathString; PPH_STRING startmenuFolderString; clientPathString = PhConcatStrings2(PhGetString(Context->SetupInstallPath), L"\\ProcessHacker.exe"); + // Create the startmenu shortcut. if (startmenuFolderString = PhGetKnownLocation(CSIDL_COMMON_PROGRAMS, L"\\Process Hacker.lnk")) { - SetupCreateLink( - PhGetString(startmenuFolderString), - PhGetString(clientPathString), - PhGetString(Context->SetupInstallPath) - ); + SetupCreateLink(PhGetString(startmenuFolderString), PhGetString(clientPathString), PhGetString(Context->SetupInstallPath)); PhDereferenceObject(startmenuFolderString); } + // Create the desktop shortcut. + if (Context->SetupCreateDesktopShortcut) + { + if (startmenuFolderString = PhGetKnownLocation(CSIDL_DESKTOPDIRECTORY, L"\\Process Hacker.lnk")) + { + SetupCreateLink(PhGetString(startmenuFolderString), PhGetString(clientPathString), PhGetString(Context->SetupInstallPath)); + PhDereferenceObject(startmenuFolderString); + } + } + + // Create the all users shortcut. + if (Context->SetupCreateDesktopShortcutAllUsers) + { + if (startmenuFolderString = PhGetKnownLocation(CSIDL_COMMON_DESKTOPDIRECTORY, L"\\Process Hacker.lnk")) + { + SetupCreateLink(PhGetString(startmenuFolderString), PhGetString(clientPathString), PhGetString(Context->SetupInstallPath)); + PhDereferenceObject(startmenuFolderString); + } + } + + // Create the PE Viewer startmenu shortcut. if (startmenuFolderString = PhGetKnownLocation(CSIDL_COMMON_PROGRAMS, L"\\PE Viewer.lnk")) { PPH_STRING peviewPathString = PhConcatStrings2(PhGetString(Context->SetupInstallPath), L"\\peview.exe"); @@ -412,24 +419,25 @@ VOID SetupSetWindowsOptions( PhGetString(startmenuFolderString), PhGetString(peviewPathString), PhGetString(Context->SetupInstallPath) - ); + ); PhDereferenceObject(peviewPathString); PhDereferenceObject(startmenuFolderString); } + // Reset the settings file. if (Context->SetupResetSettings) { PPH_STRING settingsFileName = PhGetKnownLocation(CSIDL_APPDATA, L"\\Process Hacker\\settings.xml"); SetupDeleteDirectoryFile(settingsFileName->Buffer); + PhDereferenceObject(settingsFileName); } + // Set the Windows default Task Manager. if (Context->SetupCreateDefaultTaskManager) { - HANDLE keyHandle; - if (NT_SUCCESS(PhOpenKey( &keyHandle, KEY_WRITE, @@ -440,19 +448,20 @@ VOID SetupSetWindowsOptions( { PPH_STRING value; UNICODE_STRING valueName; - + value = PhConcatStrings(3, L"\"", PhGetString(clientPathString), L"\""); + // Configure the default Task Manager. RtlInitUnicodeString(&valueName, L"Debugger"); NtSetValueKey(keyHandle, &valueName, 0, REG_SZ, value->Buffer, (ULONG)value->Length + 2); + NtClose(keyHandle); } } + // Create the run startup key. if (Context->SetupCreateSystemStartup) - { - HANDLE keyHandle; - + { if (NT_SUCCESS(PhOpenKey( &keyHandle, KEY_WRITE, @@ -470,46 +479,18 @@ VOID SetupSetWindowsOptions( value = PhConcatStrings(3, L"\"", PhGetString(clientPathString), L"\" -hide"); else value = PhConcatStrings(3, L"\"", PhGetString(clientPathString), L"\""); - + NtSetValueKey(keyHandle, &valueName, 0, REG_SZ, value->Buffer, (ULONG)value->Length + 2); NtClose(keyHandle); } } - - if (Context->SetupCreateDesktopShortcut) - { - PPH_STRING desktopFolderString; - - if (desktopFolderString = PhGetKnownLocation(CSIDL_DESKTOPDIRECTORY, L"\\Process Hacker.lnk")); - { - SetupCreateLink( - PhGetString(desktopFolderString), - PhGetString(clientPathString), - PhGetString(Context->SetupInstallPath) - ); - PhDereferenceObject(desktopFolderString); - } - } - else if (Context->SetupCreateDesktopShortcutAllUsers) - { - PPH_STRING startmenuFolderString; - - if (startmenuFolderString = PhGetKnownLocation(CSIDL_COMMON_DESKTOPDIRECTORY, L"\\Process Hacker.lnk")) - { - SetupCreateLink( - PhGetString(startmenuFolderString), - PhGetString(clientPathString), - PhGetString(Context->SetupInstallPath) - ); - PhDereferenceObject(startmenuFolderString); - } - } } VOID SetupDeleteWindowsOptions( _In_ PPH_SETUP_CONTEXT Context ) { + static PH_STRINGREF PhImageOptionsKeyName = PH_STRINGREF_INIT(L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\ProcessHacker.exe"); static PH_STRINGREF TaskMgrImageOptionsKeyName = PH_STRINGREF_INIT(L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\taskmgr.exe"); static PH_STRINGREF CurrentUserRunKeyName = PH_STRINGREF_INIT(L"Software\\Microsoft\\Windows\\CurrentVersion\\Run"); PPH_STRING startmenuFolderString; @@ -527,7 +508,7 @@ VOID SetupDeleteWindowsOptions( PhDereferenceObject(startmenuFolderString); } - if (startmenuFolderString = PhGetKnownLocation(CSIDL_DESKTOPDIRECTORY, L"\\Process Hacker.lnk")); + if (startmenuFolderString = PhGetKnownLocation(CSIDL_DESKTOPDIRECTORY, L"\\Process Hacker.lnk")) { SetupDeleteDirectoryFile(PhGetString(startmenuFolderString)); PhDereferenceObject(startmenuFolderString); @@ -539,9 +520,17 @@ VOID SetupDeleteWindowsOptions( PhDereferenceObject(startmenuFolderString); } - //PPH_STRING settingsFileName = PhGetKnownLocation(CSIDL_APPDATA, L"\\Process Hacker\\settings.xml"); - //SetupDeleteDirectoryFile(settingsFileName->Buffer); - //PhDereferenceObject(settingsFileName); + if (NT_SUCCESS(PhOpenKey( + &keyHandle, + KEY_WRITE | DELETE, + PH_KEY_LOCAL_MACHINE, + &PhImageOptionsKeyName, + 0 + ))) + { + NtDeleteKey(keyHandle); + NtClose(keyHandle); + } if (NT_SUCCESS(PhOpenKey( &keyHandle, @@ -557,7 +546,7 @@ VOID SetupDeleteWindowsOptions( if (NT_SUCCESS(PhOpenKey( &keyHandle, - KEY_WRITE, + KEY_WRITE | DELETE, PH_KEY_CURRENT_USER, &CurrentUserRunKeyName, 0 @@ -611,4 +600,41 @@ VOID SetupUpgradeSettingsFile( PhDereferenceObject(oldSettingsFileName); PhDereferenceObject(settingsFilePath); +} + +VOID SetupCreateImageFileExecutionOptions( + VOID + ) +{ + static PH_STRINGREF PhImageOptionsKeyName = PH_STRINGREF_INIT(L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\ProcessHacker.exe"); + HANDLE keyHandle; + + // Set the default Image File Execution Options. + if (NT_SUCCESS(PhCreateKey( + &keyHandle, + KEY_WRITE | DELETE, + PH_KEY_LOCAL_MACHINE, + &PhImageOptionsKeyName, + 0, + 0, + NULL + ))) + { + static UNICODE_STRING valueName = RTL_CONSTANT_STRING(L"MitigationOptions"); + + NtSetValueKey(keyHandle, &valueName, 0, REG_QWORD, &(ULONG64) + { + PROCESS_CREATION_MITIGATION_POLICY_HEAP_TERMINATE_ALWAYS_ON | + PROCESS_CREATION_MITIGATION_POLICY_BOTTOM_UP_ASLR_ALWAYS_ON | + PROCESS_CREATION_MITIGATION_POLICY_HIGH_ENTROPY_ASLR_ALWAYS_ON | + PROCESS_CREATION_MITIGATION_POLICY_EXTENSION_POINT_DISABLE_ALWAYS_ON | + PROCESS_CREATION_MITIGATION_POLICY_PROHIBIT_DYNAMIC_CODE_ALWAYS_ON | + PROCESS_CREATION_MITIGATION_POLICY_CONTROL_FLOW_GUARD_ALWAYS_ON | + PROCESS_CREATION_MITIGATION_POLICY_FONT_DISABLE_ALWAYS_ON | + PROCESS_CREATION_MITIGATION_POLICY_IMAGE_LOAD_NO_REMOTE_ALWAYS_ON | + PROCESS_CREATION_MITIGATION_POLICY_IMAGE_LOAD_NO_LOW_LABEL_ALWAYS_ON + }, sizeof(ULONG64)); + + NtClose(keyHandle); + } } \ No newline at end of file diff --git a/tools/CustomSetupTool/CustomSetupTool/page1.c b/tools/CustomSetupTool/CustomSetupTool/startpage.c similarity index 97% rename from tools/CustomSetupTool/CustomSetupTool/page1.c rename to tools/CustomSetupTool/CustomSetupTool/startpage.c index e473cf75ecaa..17a087b8664c 100644 --- a/tools/CustomSetupTool/CustomSetupTool/page1.c +++ b/tools/CustomSetupTool/CustomSetupTool/startpage.c @@ -108,6 +108,9 @@ INT_PTR CALLBACK SetupPropPage1_WndProc( { case PSN_SETACTIVE: { +#ifdef _DEBUG + PostMessage(context->DialogHandle, PSM_SETCURSELID, 0, IDD_DIALOG3); +#endif // Reset the button state. PropSheet_SetWizButtons(context->DialogHandle, PSWIZB_NEXT); } diff --git a/tools/CustomSetupTool/CustomSetupTool/uninstall.c b/tools/CustomSetupTool/CustomSetupTool/uninstall.c index 1fe866ca7671..83d4028a1d41 100644 --- a/tools/CustomSetupTool/CustomSetupTool/uninstall.c +++ b/tools/CustomSetupTool/CustomSetupTool/uninstall.c @@ -44,7 +44,7 @@ NTSTATUS SetupUninstallBuild( _In_ PPH_SETUP_CONTEXT Context ) { - //context->SetupInstallPath = SetupFindInstallDirectory(); + Context->SetupInstallPath = SetupFindInstallDirectory(); // Stop Process Hacker. if (!ShutdownProcessHacker()) @@ -55,17 +55,16 @@ NTSTATUS SetupUninstallBuild( goto CleanupExit; // Remove autorun and shortcuts. - //SetupDeleteWindowsOptions(); + SetupDeleteWindowsOptions(Context); // Remove the uninstaller. - //SetupDeleteUninstallFile(); + SetupDeleteUninstallFile(Context); // Remove the ARP uninstall entry. SetupDeleteUninstallKey(); // Remove the previous installation. - //if (!RemoveDirectoryPath(PhGetString(SetupInstallPath))) - // goto CleanupExit; + RemoveDirectoryPath(PhGetString(Context->SetupInstallPath)); ShowUninstallCompleteDialog(Context); return STATUS_SUCCESS; diff --git a/tools/CustomSetupTool/CustomSetupTool/updatesetup.c b/tools/CustomSetupTool/CustomSetupTool/updatesetup.c new file mode 100644 index 000000000000..e892305e2f5a --- /dev/null +++ b/tools/CustomSetupTool/CustomSetupTool/updatesetup.c @@ -0,0 +1,29 @@ +/* + * Process Hacker Toolchain - + * project setup + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include +#include + +NTSTATUS SetupUpdateWebSetupBuild( + _In_ PPH_SETUP_CONTEXT Context + ) +{ + return STATUS_SUCCESS; +} From 6f996c60366757b8b652ef3f6064a992e5e684d6 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 8 Aug 2017 23:27:46 +1000 Subject: [PATCH 0358/2058] BuildTools: update binaries --- .../bin/Release/CustomBuildTool.exe | Bin 160256 -> 162304 bytes .../bin/Release/CustomBuildTool.pdb | Bin 69120 -> 73216 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe b/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe index 7ec0fe7844142e97d27ca7fde66e3e1a96e1c9df..d66268864f76598e02d1647233a2a1e887d3da19 100644 GIT binary patch delta 24811 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 delta 19795 zcmaK!34o1N|M<^yjoS<}nmfBY`wTO7#w?7`3=%COONcUAC)?PH4EIjT;^`+3fDp6BxJ4)87ySWquy zmQu>=;1Ab~t;x=RSX&&SjxCPM))r?#K+JmQv@XDtrywBY;Cb{~2A!i24H zH5vs*$}U`=H@{3yUOD%xuI&Gn6EaUr*%UA#a3S%qQvmtby*NP)S2( zKG=T|Ioky5x3k=JhoO8CC(&(!E6TYV**RnAcQI5u!sWBDy^U+ZnlACE2!W>Q|e_MvBG>oD_MBKcy~h9(STc6}S8lX3&% zH)3Z1%A)9xOfjtMx&8{hSS!_Z=!b^1Objg~Hl$^4u{BCsb$7oW zjhE}JM41bbvw4`l)GDp^QWAR!OLTK%z^;)lpa%K3gBc-X*5VS8UanLesZuSS(K^<)6H0z}BdJXTR4#BWZM6=M-$?pkG{lB< zt6w9qij8749z-(2Xh>O@*Okf=fyP8!9Mb=*WQWO!R!QAxJ#l3-y}Dkgdt(eDuH}`Q z2$3@;Lf2~J&fYGD2upMfJ>n}6OA+$c$oG*n*~tA<@K#;YCN^F)#v6@Gl{Cb{t@>n} z2i&j6O2$gPB3)`O`qKG&r0&u-A$~K7y{Jg^>-2ymOrxfv8LCV3)2&cl);2NnB6^{2 zx}JN$UfR#r(`9YK_3qnabm;8?=tbV1%HKb4kB#q24#8+I#>y&+DB3ctWYC1_F}E|U zuy+)VbnJbN-=DAa0Xg0-`F>SyF9OZOxaWxd2-|*ptQnQ;g;I}NMBM`Y8q9PwCgd?0 z$fXl86i3C=WuhUCDODxMyjWYK7!5K|9gKzyb%q%lr48=Zmooz0J>m&+9TNlQqG-;C z;&iY4gj(A%kc5gvBYL83JH0PI#&YSC`HAsYi9CnpZbZIQsSMSypGOvzLAKnI5I*>g(djvBc+uVblFSRbfj`U?t}f8M9$0v{d2pN z?A|2qii$*MmK&(%T8cb|aIZ>o|ELSo_qLCY-;72C8X0Ja1!)P%TJ{HFx}<$+^=oKXyKud{L0(D|)xaKL=ZKN(RkN`WKh<%*lA!PUpp_obp^;}1!?OlrMv|BD zt)7LFY6+|dm%Qow$THXyJ`cyjRd5Qt^y6P%4}6jEO!yL90oOyE+5lgHYv4O@ zBiyT$N4<*YT?DVe&*5fx5^ja(;T!N5xDEaWcfjg2$SxQTcf&}CQExKb3-cg0z3t$B zcn3THyTcD)Pxvt`ure9yZ#6tgqLA|ctxM?_@L(+A?Y0&z|Q4Y zC{})lcfmhkZ+IOJfq%mB@NYN=GIG3BR9TQ5Q~)H6q5E!?rLJ-VU>2cbEeofVr>_Y^5VR-{+yvz1$-deeO+z z9mp#i-bJ_*yoa!)>Sj{)fFlU^LOvPxBRn6nf0-r&cM#!Ka4=jAhr-t(t>E1bhr^wa zq2qN?hHpC;c#81Lf;b)~!^fc1=y526U?P-Gp9JrNlcBUnF&qh}z+yNR&V?TMG<*_1 z2N{muwQxFQo~Rjc7i4%&`-rN`rfeGHR6PUFK@DZ{EJg7*_#9;HsOO=q|s z3)N~}{qDJ*b%X-Zk})l#Pr_2I*I*Q+qrLGaUaBea>2MotX5`IHSgQRd@}5TippicU zwkbFj&@B~>Cb`Y`9L@YHCtKlx>ufezB+i(v&2=~Gh@Ll*ld=E-B8Hrwow0a-L zzz<+L{17sV)JO0R_z%cs&3hlK)@3`lkZvQ0Y zB)bzZ7@mT$@L#Y2{2J!MZ{Th4TPOqk4D1Te!XEHE>;*6A5AW^X`7$Bd5B&sXU|)rG z;Lorr{1wUy^Ba`b{sYQNavjRr@He~%Dm}Q%efa?nUmpg-2!uh<4Qs$SSQAR0hCs1e z3(EB2o@1~7VftE^yFKhq>>5Tx84)p1tki~LB^F9q;-O64M0hVuhW%j*91QEgNsybZ zcQULGpMnkHbFeYo0GmLWbj=_Ow?}2*`3OM^D0hoocn01Euff*vPuLc^=&0KvYm{ma z6X6|@bw}L^+rmz;BfJaBI(Ikh2W3e1hxZd^R;wNkHO*t)%_9z;`3U+Eu>d|ynAxKS z!cA}(^3AXiZh^z$0XPCOywqsOs8U6GPS;O7;|WRoO@LYOG1vu8gfe3$L0PmW!-wG% zC=10@I2v+d;C&oE31`4*a2A{apMkUB3OF0eVkXsE4WA~=0@6y&$Fm2)Gw?8606&GL z@H40(w>Y&3UW7~FCAd_(?jP!uu6eAcp5NW=Sx$tEh?P)A!YY^mCC5bgB4HU%Yhh=& zj`or@;1$Ay;Qv7x8EjSTk+BI*AzTJMa0?7keN>3@Di?cQxm>EZip058v`+7l?D(ao z-qg#TyA4$-%1$WD(k@sZ?uIfQ--a?c-+^)~eiwFt@97mi8ajCT|EP!Ca{!?j`3IC) z_c4^U><|>?PvCv0PDf;p;S#;o8?PgCY%qiKp98>aj01` z->wrbfq%ip@NX#d&8nun&qD`X4g(Yd%mUv5f>nO%5KU|na=8-F7V9ZcdLR`_57dQS zU>Y0&)8Uh_9$XFUL&~Zez)xU9cm_6tf59d&z+x?FiYJuJn!$!J1Ga$8;r%cRa(7qR za1_jeqhU)Zi+?WU&Z}C(Ij{{3QT-W?{TP=0%vuru^^Q>5xiidxcSC94d!XD2?t}ecH~1*LA4-e$ ztfr>P>d=>Ph7Jfr=gyM`yi99wf8WdWe7fn&qH+}a7 z^Mv_YldXV#N%vkf{uisM8Ept}fJ@bBv??BH3$0rLoxI`6vHpV z^YAqM9X{&64e7B!cNM8pj!*Osn91qvR32+a544#0G!(ZW~0Oj%0gX#$c za!4vAiZbDNIE4ZXhck(P&BVW9;`hMW$o~oFqF1{*%LwcaS0H~Fu7o4tDmWXihHK#( z_zrwAz{C8+vlhX5_%a64ojiuY0{ABKp->7|Xu?Hs2l7d9CzR(BiJxiW=fmB|7r?jR zLii4R8B%EP2Dlf7s9ROY)}954mgk{3-_mr9UXm*w$3w7v?GNxRO&^nl&9OQJd%;g& z0sIUOg?155xCkCYF8h(sp%>akgrYwmeifi*e*nLgPB?|<3=wkYISYS>=V^lu6yit1 z_rNPqR*s*bJh)v8P*2KC`;G8(@DKPZybfhp{smu$e?uNyl~tYj03A@4^6KzY=&Y{C z4xH-o9p72yCw<(k)gGK&!KenpT2SPnFcwOkq^%@e2Zlkpk3~S4qLEPcF%mCr76W@j z#)^Hc5esFnA6H$~vX9yl5sXKWq^AtJv+*klzHVW|Y+npn)y(H*U$35$?&!#uc>AJleyqMm7j?o0U7IT8?AEmqlBh!v!#8S&vj6t~ah2w+Qz-j&4?0aa37l z;qJi=!+CM5aocexa943LjHG6`PPj_f)+WyV*1|dgI$%hgle?62a*j?L(#iq4?E6{w z9@;^?D~IMd2as@qvot?#;jknpn^dPeTc-_6aDa}(9(685lANu#4Qt{~X0fK0_Nnbr zm_#56*2~syN5|^gg|}JH>7IqDPPVwtF4=l&VLJqS5wOE@_Q=*3Y(e8kQ=KaiJeaL} zJ=!r$vXrx68FtdJPhEE7j^cjBh2Fw`6xRVa05=i0R9_q3&^duz`(*005v_F6hycfcOg&^o zjvjz_Xr_K)M04jv6h>w0<9L}t&Iy@1Y-En}3B1Lby35E`&dGSEW$O8Oi}5~{sSn|u zg10nN*BX`MoQij8roL-bD<@A@&Q+QEDWqP!>oWEGNK5d(nyH#jyO-l$*Zs%cW_8tT z#(A7fOlRw6I&FN413YxVtp|;dbKS!@k%1_!B23by#xSAI!BRWYBTMakd{2v zsLA`b81z=-n6k<*ck6EBBXs`>(XMBVrZk`!Ox80d+*hRm2Oy;cXD1ACV7<#@Lqdkt zpvbtTxYxJtee7W?_yzKQ&rA~SIv=MyO>AVX(i0}8I$tE}%WS=JVn+mL5UfS;uWVgw zk_dWEN_D=3;5?JY7VJl`4#DMYeQ8q1Ft(vpy7Ikj{Zt>f9`Hn{1EbR3^YCJBy z(8#I!%GB8S-lPpAZFAB(GJO3iX%VSZT{b1%6=b9-NM&@V>H^P$6zGnrsrqtpfTMGU z9yK+kZfBz=y)8Q%*?dTW{PM~L3Uzg@l$G?j6eivEKqaZa0I~6bSmG&2C8PJyO$zgt zC)GKY)>)aM&w5glS5_*F>~g+jHJ6)^U+&grQ^R#@Z%oijeuH|<6h1icCIyxG)9PeT zxZdau*5{^#=>6V1s|-k~8hw{g($_(cBs}TXi%MooTO>UBLXa;TOLf!TdW7o}PZq^r zuF36$$H6+d*0>(H5xD8N<+|JCB@3q~1Pj7A2*E^;^ zECTn8zSUnR@8|p2yQX1zrteE|hL+whd;Gn{R<3;A5 z$hEaKJKc4UNfE^eq9asoojbcdhNsLbjmds{QVqSKNUtZoc|i%HITwh`#RJI`gRl%Tw|om7T`Q zA^U|HN|neiY8K%ka1NA{kEdV}oJagr$X3lO4+#sPoP?CZ*-%4XK`1h?pVyv+iwW~2 z;(ZqK6zhE%au4_NQh}F=Y;`x|;r8p@4Oc>W#9qx)yllr_B+S{nyj6ViIHY3Uf5KNN z^LLP^Gw&I=h46nMPifw(a3{PDcfmj5ThPG-dK*@Q??BG7)m{&tL_F`pB)AVYg8N}} zcz_z`!4C=N!+$`|jP19Gcf&)3IU`n|z@G33D267Op z&cZk0Irttt4?l$8!!O`P$l0VvUBbheqx~ZC8+e5<$B451@p6o)uEO8oHTXOH1#)bt zeuGZ zvg}uo55ijs7eH=^CGud$k&m|sM#4!j3O)h3vwEk&+Hg9IMSmgWgu=^_j!J}_)W~kp zySxLQ6g)4&RJaz_f&T~V!i_KuZh`4=JFEveLs1Rjd$5ttex|JULp-0yvHkILm_Mxl zekRlEs52L|FV~r9;`};u^~0r!dfS3#uG#+;^UH$!Zkp~P(&ai>hL)AOJ%(`qup$y#f_BJK&LbPvD;$Zgo0 z3j63Q3mZCE{}Qyj8*gT8BM(7IJOH{O2NCwm2mhnjU`x%AA`eF{MIHg~H|zm9)wSQh z@-jxZPrJ&EBN%gaa4m6Nal>$u#cJGk+~E*;Ad$zHMRCq?EVVyo=(I%*Tt8-1UHj|m zf<>t=M{}Pvh4r1)N7dDf7d3U|8mX+_OeCaho{iQQ7e%;6nHc~5pe~=8v}Z@rb8)J3 zJekdHuBR?;?wV`V{ClD_y?1fCKDsDEUtb&{45DQAS4P$JkwwwE!?SU&H*PSUrpG*+ z81h!7qEtsWHc0Mq(m&XIHr7hhC!ejl-@H!Tj~QFrE^$~vzH(UVkUqlQyx-DuA?IkK z;94{x?jGIkxlf#|)Xraca9frZ^ozNJv&Wbou7@p)aV6&X+DGau?bAS)E^E)W^VqUf z=LQlE%F%x9pl(4$x(J zN8M>oaL|asqlS(jCO6B1Ieb;MJjS)SQAPIB5wZI8s%U+Ec@O6!SSV|xd#z~VDl;^`*mcsxNRzTW5Rt3sKT>rUgG16VpO)5rsdF|tmvYDA! z-S_2FqS2^ajMR{HBdwBkm~@|UPWYJa zK8NF=O4Y;V;YQ%5<2K(~n*YMWbxF=AF*qShr>)DWH4SfZmanvGoNlttt!Iyjh@Fmj zx?enW@c4&&4IVqLaP%k)>#ggOV`mUQ*B?KwYW$DulASY&*I9byx)j~= z@pUQgwKAf)WR>$@vx$BoOGmw&lJd2Q4)n)C_F2vi<(cV(m)#7sBZcAh*?2k2{1H-0 z`;%(lH>uKKIp%|}-a2`Gc>TF(Z})3UnQzc;ZnPJO?Yi^O-s9I6+wBTRiDj|t*Ze^2 z7CepS0l%i$t)%HMK>%Y*uFAEZPr6V1=_H3v1>=Uu+8_LBC8u$P zLq*4KHGO46Y+H@SRlkNAxkeql&%_ZwNMv8Q}h9Y$p;H>z*6`Kv0il^gX3Un1G9 z#H-|TTfRZ$Pb9IG8-t-DjVfE2$~pOlh(D3UR?dl$A&JHyu3V=udt8}B9*LDYU8Tuo z?5xGfwHfyTtL%5U>$sRu4oGqL;0EDjAGZ{@9d{Ua85hXCvktB`t~ag-HxIWKw+Htn z?kX-gjMW^M7smJH{qT&($wS<>7kcig5FAYjJyUU*fLff+Nt2 zD9!J?a9fg-4W;veWSzDx!2x`y2U&Xgw%);s#BAoCD2uYbay49szv*&pPSI`KyV)uP zF5D4lh3jr_raJbg=vUgitzmj^dJ8K-fB0r+R8CuSyUTGUMJH^J3UQ_SY}z{< zUGnCgq?xllH8`0x?M<96xE7&5-X7}m3*=TwIaH)BTOKZ1N9v#*vHY#OBi+^Cq!J~W z_mR5)j#SrRBb6|+z*mKqr+hOl^X_Ci?>46)8n}=JA+lM=Wg#;R~VZ~q|Y5OkxP>Yw*Fs2|gElBblbRddNppo_S>P=CqD84&M>>xl;<^u+gr_0j{OdOdvoK%AARj~uuUgUKJH zI!9nIxS4!DUggwp0fwmevmZR`pk_@z+~gqFQy-pkp!@bmeG|Mi)^eQu1mY;}A}%mW zsU%#>sM7q87JeM)@iInv+r>+8U!z=O7RZPUK_;xtLLw}smcr_ce_;W)PhlVCyRbHP zgwl}03^EgT3-PfogG|CDwS2tSXWygh-|7>rFbY2~az!yD$j1-yOL(s-*cqdL&=hEc zVZJF?V^gsDreK{-!3s@*sxt?~-Wzs7I0FeWB^+rC=h8fO0Zd8nFa>$q6rh_iz?UYr z-ft#@y2j3Ltdx@enrXrPjA02kHU)jov}nG_8xhgQ7?k(GqIkq895Dv{KZKj1Hylj# z95LDMH`$yt*;uB2ZNM!VQmwC-h>aDYK=7d$4t8yQUoc*6;ld63G!9P*S>U^ zsn64fJ4}Lu#_%;`aE&Q`GRDN;9SC|glVM0)A*1Z)(!nq$|;<4@Y}WV@a%?H&&8Oy-SSNbEX){rsFb9 z^+HT_Pa1w@nqh|-0P>SIv3rs~!ak5TPB%%u6iHGIP~@Uvl$Vzwf$B-_fP90-U$nPbp* zQL=KsNRlWgrHa$7kHuK6b+=A<)VJ(kl%=q(`ADEh|=NA=C>{>8zc)`%YY`9I6`QlBX zax1E|Jy!qzZHildPFZfYpdz|=yw3S9rLFviu{`<_vFfYRZ1&xjYBF%(_|apfd;Pij zb)s(S85jLihQ1O}(7ZApH@c4+#aI zYvgD#M7KKE!fK|+o@;1j=#}T1qHyS3CYx8s`Sw?nn4${vA^tMb4Ni-eMpe29Y17JqMRRY$J%2*w5Jq1`J1Kx zLf%|Azm(aP@#dcc#WZORCC5q?$C3Uf_Qm;{xFv(opJuzAMh==x8vWL#7`@_BO(yJ^ zONs8QcDzZ)@beF#W|n^CQi22gbtx*IS0pCqj-$s;7}-;P_U_MlgwFUe+Oyu)kbM4I z!xv}rV6gei_FcKv?(%Oz*aw$>tG+msh7ssblf;TuLrFeW(%fP%1W68k=*Ot|ezuOZ zlR1j4G!*-3>vFV*AFdcH|E=MRGdT~c$eG`Im^P?5di0mp7iZEi&HSa6Z!vtOt&+x9 z+Q4dh<>jdO4z^C!V@bc=4*CeCl@IbNtoV*1{TjYFU(UH16;p9{xmDi*qhH@AH~K7f z{;7MlJddjS$o1$ekztKky?tZv-ofL>$y%ZhU5U=GG}4CI8qzao;^Iy8~9{;^d5e-t|~BG=8@ zU*r$jy(GV)IBv4@rSbh0k-U0;*zP4hc2^JDK6yOaExtCnfioObquPxIKk>z z<04%q*MNk@qpWuwzXs{4f21twVOd)|_tp3#jk8i;JpEL;&*Y09Udo%e%3UsnkxzW~ z(I9f&7$@H+P4Y$kSKJoj=r#LtG&UZA7?sbB21tPGMx!~6mK<_e?&|WI^w^Rk4lBC4 zytW+a^UABkO}5vwrU~EJ`)shg-DWE9%Ro-M*a6ztjd5~p^~_D;g4qJ{|NltWYgcO` z+L^fOs#g;}0rFjz>a|P0wDdPGk(J`)<2Am4SdtuIMe_mMl7s-u&DU!-tIOwW-R!99 z^1^?)-a8`PUSs4<_@VMpAMWJ0=)LQFaRaJ^hE@rUsuG$|B~)A`G_6YLsVbq;DxsxS zLaVBT)>R3~$GsnvmvaIu{4GnmIjMJX){-txI#phb8qr)M(iNg*M)X33XoC^SyGoOA zyAjDNMk6|4MDkA1h(0$Wd3k3x)XBt!XpvAYSg5|m#OC!gjEL14|&%pKIuZG1otFP8t@66d;l~NCku~E|H(Mn!A`+V#qr?p z;0v|AVb&}w`%wgixM8^AIQE`uByJRLG_D9Y1~(Qr4mTb*p)7xzRec)1>2JECtUs## EKLdv$1ONa4 From 443d8324595d1fc09167fdc6b422fc439b745581 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 8 Aug 2017 23:35:33 +1000 Subject: [PATCH 0359/2058] Fix previous commit --- tools/CustomBuildTool/Source Files/Utils.cs | 2 +- .../bin/Release/CustomBuildTool.exe | Bin 162304 -> 162304 bytes .../bin/Release/CustomBuildTool.pdb | Bin 73216 -> 73216 bytes 3 files changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/CustomBuildTool/Source Files/Utils.cs b/tools/CustomBuildTool/Source Files/Utils.cs index 7a9beb885330..ba180c1fc213 100644 --- a/tools/CustomBuildTool/Source Files/Utils.cs +++ b/tools/CustomBuildTool/Source Files/Utils.cs @@ -344,7 +344,7 @@ public class BuildUpdateRequest [DataMember(Name = "bin_sig")] public string BinSig { get; set; } [DataMember(Name = "setup_url")] public string SetupUrl { get; set; } - [DataMember(Name = "hash")] public string SetupHash { get; set; } + [DataMember(Name = "hash_setup")] public string SetupHash { get; set; } [DataMember(Name = "sig")] public string SetupSig { get; set; } [DataMember(Name = "version")] public string SetupVersion { get; set; } diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe b/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe index d66268864f76598e02d1647233a2a1e887d3da19..a4a1356fa0497add7d6a45e8608db4a98934ff9f 100644 GIT binary patch delta 309 zcmZqp!rAbJb3z9b*S?8ea*U@Yt_)|an9Rti&g#I$$RIQM;2WLEk&Nn$7bZ6{)-$e| z%*Z6nYqOAnfsuiMA&!B8&0w=4ld&UX!RAosbQ%90d?%R>Go0Xi2_*0EaWWrf_{yiu zyqjSyyC#s$&+p8<8OZhovNiaV!R$;R+m*kW`82~N-e%^@K-p&I$w0CbC?2_)J7H;w zfTc*xzMzSw9&66F@->P*EZKbE%0fPIF-D*pLikwx5_40zG7^h3;)_#DN(&|zJ>Icd z=ZOf14%fcUNT4Gbn1EOY=-e2fe`4M+Fa!m=1WQlc|28=Km`}&_$t5aJr|jFD^M-?w pcL6uZR}ipka^qWRpnvDS&28p;x1H}DGaTZ32_&!aaWWrfc+aQI zyqjSyyC#s$$?wd(8OZhovX%Ig!R$;R+n&Ff`82~N-e%^@K-p&I$w0CbC?33-J7H;w zfNn;I#S_amuXP)k0@cLQT{a)MvXDa#N1StjKt!M$rX=xFfwe`eDT3+i+45`yy0LJn8OY7 q5d>@lvZrs)`3RIsfPVJ^$zZ_+7RY7RTuR&&@~g6kF6di!vKAQuNfbC&cOuSbR1uO&I8-Z1}U-@BCFKFAdjUjP4cHf{pKH3wD1cHEvKfYy$T1 zd&-c32CmMK3Nqy>H3Mk|&aHHc?FK9q2khXzaxHX+Ovx>zloXdEi+LVU^4h?B-UfW< zW^X+3f+_#hj6KE&7`qB+5zK_L5g}=zorPzKg$$T)`)c5b0URcFcTNTz z%LBZE(bYzRZQ={D17bwaw&Vj>X4$rXjPD52oILc#gaTllVDy3_!6vLBrd<X=D7 zMbBlh5V)=k9iGpBDGf!yOO~k}vSe4D_uAARAviB72I7>V-f(q=mZ{TPwZj~?@#=bw z^K6%vsRu=odM>)UQRBSYt7Yn#C<;uOr8X12hN3mJ2(dYOvyouiEGL#LM)d3uG3^(m eXN~{q=_Qt`^<*zLFm06*WWzsxz?CFTCjSKyBG0`5 delta 1970 zcmaLYZAep57zgnG-R^SEY1TF|v8<5`E4`_y8D`pxh>s{s7gu8Zgl6l$F1*WRxLBZEFX}hp>zOT&LEN(1ozZncUo6i~7V!f}ZGt0OEmBIa; z_p`;y_Nn|}`nyl_WVb{G!%cu&dSV4Cv>SA-brmxw0>j!3#y*fe;MkQUe$MwYp~Ij> z#uogQ%rE$A4#jC<%w$H%syR9H?0{WovX(dF9yl#L6w zSo^aOIIIeoi5^-68MkLF=#VlN1L4y^!2%q*t#C-qnLxRkl(mOsH5^ND0WNi-kvQMJ zziGkLi5gKo2pybdDEIepmhqKrm=o7$1om>`oFY)Gnan(!V}v0M87npcDV%~^Xpc^D zY$y)c$;l~ao9WbWu!XFcWB14gI0a8yfbX0*PXh2fYKgiHc1yvZQ*#ZnL&{wOTvQJT zyU~4FK#7_l*4)w*S*dCU=IO0j3cR3gQ5tLUIlz$!!N6`w8zCLaaAN~+kk!p-z${u? zi)w1!@Rjn=PLK_8Oy02qXy9NU*_|1!zP~9K@TexDzF+OqYgFI=nd|_^Hs=B7qqaRJ zaDG?&PK>gYR z;HA#|UQtLhjCc40^t*bzBRUo+Dg@|UhnpF(R?3)vOwD68P0O>58LO|cn=yYK#Vhk^ zot~$W8LQ9ZVa)$JlBegJNjPJaZBoIi=wd9e>D~#OR6>@mW@GIjnfB+*TH}9mddRfT Xh{Z?+dw$0YR+0N9?nzG)MrZ#6;cexO From 77213a8c88f6b15bd9530dd650fb81a40fac2b15 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 8 Aug 2017 23:38:14 +1000 Subject: [PATCH 0360/2058] Fix spacing --- tools/CustomSetupTool/CustomSetupTool/setup.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tools/CustomSetupTool/CustomSetupTool/setup.c b/tools/CustomSetupTool/CustomSetupTool/setup.c index 256dc4f4a25a..e23626d0026c 100644 --- a/tools/CustomSetupTool/CustomSetupTool/setup.c +++ b/tools/CustomSetupTool/CustomSetupTool/setup.c @@ -625,14 +625,14 @@ VOID SetupCreateImageFileExecutionOptions( NtSetValueKey(keyHandle, &valueName, 0, REG_QWORD, &(ULONG64) { PROCESS_CREATION_MITIGATION_POLICY_HEAP_TERMINATE_ALWAYS_ON | - PROCESS_CREATION_MITIGATION_POLICY_BOTTOM_UP_ASLR_ALWAYS_ON | - PROCESS_CREATION_MITIGATION_POLICY_HIGH_ENTROPY_ASLR_ALWAYS_ON | - PROCESS_CREATION_MITIGATION_POLICY_EXTENSION_POINT_DISABLE_ALWAYS_ON | - PROCESS_CREATION_MITIGATION_POLICY_PROHIBIT_DYNAMIC_CODE_ALWAYS_ON | - PROCESS_CREATION_MITIGATION_POLICY_CONTROL_FLOW_GUARD_ALWAYS_ON | - PROCESS_CREATION_MITIGATION_POLICY_FONT_DISABLE_ALWAYS_ON | - PROCESS_CREATION_MITIGATION_POLICY_IMAGE_LOAD_NO_REMOTE_ALWAYS_ON | - PROCESS_CREATION_MITIGATION_POLICY_IMAGE_LOAD_NO_LOW_LABEL_ALWAYS_ON + PROCESS_CREATION_MITIGATION_POLICY_BOTTOM_UP_ASLR_ALWAYS_ON | + PROCESS_CREATION_MITIGATION_POLICY_HIGH_ENTROPY_ASLR_ALWAYS_ON | + PROCESS_CREATION_MITIGATION_POLICY_EXTENSION_POINT_DISABLE_ALWAYS_ON | + PROCESS_CREATION_MITIGATION_POLICY_PROHIBIT_DYNAMIC_CODE_ALWAYS_ON | + PROCESS_CREATION_MITIGATION_POLICY_CONTROL_FLOW_GUARD_ALWAYS_ON | + PROCESS_CREATION_MITIGATION_POLICY_FONT_DISABLE_ALWAYS_ON | + PROCESS_CREATION_MITIGATION_POLICY_IMAGE_LOAD_NO_REMOTE_ALWAYS_ON | + PROCESS_CREATION_MITIGATION_POLICY_IMAGE_LOAD_NO_LOW_LABEL_ALWAYS_ON }, sizeof(ULONG64)); NtClose(keyHandle); From 34b9d9c91ed6f55bf00faff064df98926435a896 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 9 Aug 2017 00:02:16 +1000 Subject: [PATCH 0361/2058] Updater: Fix crash --- plugins/Updater/updater.c | 39 +++++++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/plugins/Updater/updater.c b/plugins/Updater/updater.c index 9affa094d471..98956efd01df 100644 --- a/plugins/Updater/updater.c +++ b/plugins/Updater/updater.c @@ -309,11 +309,11 @@ BOOLEAN QueryUpdateData( HINTERNET httpRequestHandle = NULL; ULONG stringBufferLength = 0; PSTR stringBuffer = NULL; - PH_STRING_BUILDER sb; PVOID jsonObject = NULL; mxml_node_t* xmlNode = NULL; PPH_STRING versionHeader = UpdateVersionString(); PPH_STRING windowsHeader = UpdateWindowsString(); + PSTR tempValue = NULL; if (!(httpSessionHandle = WinHttpOpen( NULL, @@ -421,18 +421,29 @@ BOOLEAN QueryUpdateData( if (!(jsonObject = CreateJsonParser(stringBuffer))) goto CleanupExit; - Context->Version = PhConvertUtf8ToUtf16(GetJsonValueAsString(jsonObject, "version")); - Context->RevVersion = PhConvertUtf8ToUtf16(GetJsonValueAsString(jsonObject, "version")); - Context->RelDate = PhConvertUtf8ToUtf16(GetJsonValueAsString(jsonObject, "updated")); Context->Size = PhFormatSize(GetJsonValueAsUlong(jsonObject, "size"), 2); - Context->Hash = PhConvertUtf8ToUtf16(GetJsonValueAsString(jsonObject, "hash_setup")); - Context->Signature = PhConvertUtf8ToUtf16(GetJsonValueAsString(jsonObject, "sig")); - Context->ReleaseNotesUrl = PhConvertUtf8ToUtf16(GetJsonValueAsString(jsonObject, "forum_url")); - Context->SetupFileDownloadUrl = PhConvertUtf8ToUtf16(GetJsonValueAsString(jsonObject, "setup_url")); - Context->BuildMessage = PhConvertUtf8ToUtf16(GetJsonValueAsString(jsonObject, "changelog")); - - if (Context->BuildMessage) + if (tempValue = GetJsonValueAsString(jsonObject, "version")) + { + Context->Version = PhConvertUtf8ToUtf16(tempValue); + Context->RevVersion = PhConvertUtf8ToUtf16(tempValue); + } + if (tempValue = GetJsonValueAsString(jsonObject, "updated")) + Context->RelDate = PhConvertUtf8ToUtf16(tempValue); + if (tempValue = GetJsonValueAsString(jsonObject, "hash_setup")) + Context->Hash = PhConvertUtf8ToUtf16(tempValue); + if (tempValue = GetJsonValueAsString(jsonObject, "sig")) + Context->Signature = PhConvertUtf8ToUtf16(tempValue); + if (tempValue = GetJsonValueAsString(jsonObject, "forum_url")) + Context->ReleaseNotesUrl = PhConvertUtf8ToUtf16(tempValue); + if (tempValue = GetJsonValueAsString(jsonObject, "setup_url")) + Context->SetupFileDownloadUrl = PhConvertUtf8ToUtf16(tempValue); + if (tempValue = GetJsonValueAsString(jsonObject, "changelog")) + Context->BuildMessage = PhConvertUtf8ToUtf16(tempValue); + + if (!PhIsNullOrEmptyString(Context->BuildMessage)) { + PH_STRING_BUILDER sb; + PhInitializeStringBuilder(&sb, 0x100); for (SIZE_T i = 0; i < Context->BuildMessage->Length / sizeof(WCHAR); i++) @@ -450,9 +461,6 @@ BOOLEAN QueryUpdateData( if (PhIsNullOrEmptyString(Context->Version)) goto CleanupExit; - if (!ParseVersionString(Context)) - goto CleanupExit; - if (PhIsNullOrEmptyString(Context->RevVersion)) goto CleanupExit; if (PhIsNullOrEmptyString(Context->RelDate)) @@ -468,6 +476,9 @@ BOOLEAN QueryUpdateData( if (PhIsNullOrEmptyString(Context->Signature)) goto CleanupExit; + if (!ParseVersionString(Context)) + goto CleanupExit; + success = TRUE; CleanupExit: From 55991c592e0b0013b80bc6f2f7e2c3f2af9a9fc9 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 10 Aug 2017 21:40:40 +1000 Subject: [PATCH 0362/2058] Update headers, Add plugin cache exports --- ProcessHacker/ProcessHacker.def | 2 + phlib/apiimport.c | 1 - phlib/include/apiimport.h | 10 --- phlib/include/kphapi.h | 14 ++-- phlib/include/phutil.h | 14 ++++ phlib/include/symprvp.h | 34 ++++++++++ phlib/util.c | 116 +++++++++++++++++++++----------- 7 files changed, 133 insertions(+), 58 deletions(-) diff --git a/ProcessHacker/ProcessHacker.def b/ProcessHacker/ProcessHacker.def index d2e5565ca064..c0ca340aa41f 100644 --- a/ProcessHacker/ProcessHacker.def +++ b/ProcessHacker/ProcessHacker.def @@ -345,6 +345,8 @@ EXPORTS PhGetApplicationDirectory PhGetApplicationFileName PhGetBaseName + PhGetCacheDirectory + PhGetCacheFileName PhGetDllFileName PhGetFileDialogFileName PhGetFileDialogFilterIndex diff --git a/phlib/apiimport.c b/phlib/apiimport.c index 12e2bc7e52d5..a14facf43a3c 100644 --- a/phlib/apiimport.c +++ b/phlib/apiimport.c @@ -58,7 +58,6 @@ _##Name Name##_Import(VOID) \ return (_##Name)PhpImportProcedure(&cache, &cacheValid, Module, #Name); \ } -PH_DEFINE_IMPORT(L"comctl32.dll", TaskDialogIndirect); PH_DEFINE_IMPORT(L"ntdll.dll", NtQueryInformationEnlistment); PH_DEFINE_IMPORT(L"ntdll.dll", NtQueryInformationResourceManager); PH_DEFINE_IMPORT(L"ntdll.dll", NtQueryInformationTransaction); diff --git a/phlib/include/apiimport.h b/phlib/include/apiimport.h index 973798657c33..574b6d9eb86c 100644 --- a/phlib/include/apiimport.h +++ b/phlib/include/apiimport.h @@ -1,15 +1,6 @@ #ifndef _PH_APIIMPORT_H #define _PH_APIIMPORT_H -// comctl32 - -typedef HRESULT (WINAPI *_TaskDialogIndirect)( - _In_ const struct _TASKDIALOGCONFIG *pTaskConfig, - _In_ int *pnButton, - _In_ int *pnRadioButton, - _In_ BOOL *pfVerificationFlagChecked - ); - // ntdll typedef NTSTATUS (NTAPI *_NtQueryInformationEnlistment)( @@ -74,7 +65,6 @@ typedef HRESULT (WINAPI *_SHParseDisplayName)( #define PH_DECLARE_IMPORT(Name) _##Name Name##_Import(VOID) -PH_DECLARE_IMPORT(TaskDialogIndirect); PH_DECLARE_IMPORT(NtQueryInformationEnlistment); PH_DECLARE_IMPORT(NtQueryInformationResourceManager); PH_DECLARE_IMPORT(NtQueryInformationTransaction); diff --git a/phlib/include/kphapi.h b/phlib/include/kphapi.h index f905de9a09d3..a802089b7587 100644 --- a/phlib/include/kphapi.h +++ b/phlib/include/kphapi.h @@ -131,17 +131,17 @@ typedef enum _KPH_SECURITY_LEVEL typedef struct _KPH_DYN_STRUCT_DATA { - SHORT EgeGuid; - SHORT EpObjectTable; + SHORT EgeGuid; // dt nt!_ETW_GUID_ENTRY Guid + SHORT EpObjectTable; // dt nt!_EPROCESS ObjectTable SHORT Reserved0; SHORT Reserved1; SHORT Reserved2; - SHORT EreGuidEntry; - SHORT HtHandleContentionEvent; - SHORT OtName; - SHORT OtIndex; + SHORT EreGuidEntry; // dt nt!_ETW_REG_ENTRY GuidEntry + SHORT HtHandleContentionEvent; // dt nt!_HANDLE_TABLE HandleContentionEvent + SHORT OtName; // dt nt!_OBJECT_ATTRIBUTES ObjectName + SHORT OtIndex; // dt nt!_OBJECT_TYPE Index SHORT ObDecodeShift; - SHORT ObAttributesShift; + SHORT ObAttributesShift; // dt nt!_HANDLE_TABLE_ENTRY } KPH_DYN_STRUCT_DATA, *PKPH_DYN_STRUCT_DATA; typedef struct _KPH_DYN_PACKAGE diff --git a/phlib/include/phutil.h b/phlib/include/phutil.h index 270041ab4c2c..9c3722bce4aa 100644 --- a/phlib/include/phutil.h +++ b/phlib/include/phutil.h @@ -1049,6 +1049,20 @@ PhParseCommandLineFuzzy( _Out_opt_ PPH_STRING *FullFileName ); +PHLIBAPI +PPH_STRING +NTAPI +PhGetCacheDirectory( + VOID + ); + +PHLIBAPI +PPH_STRING +NTAPI +PhGetCacheFileName( + _In_ PPH_STRING FileName + ); + FORCEINLINE HANDLE NTAPI diff --git a/phlib/include/symprvp.h b/phlib/include/symprvp.h index 9d1f309d08f6..80512985ed87 100644 --- a/phlib/include/symprvp.h +++ b/phlib/include/symprvp.h @@ -53,6 +53,40 @@ typedef BOOL (WINAPI *_SymFromNameW)( _Inout_ PSYMBOL_INFOW Symbol ); +typedef BOOL (WINAPI *_SymEnumTypesW)( + _In_ HANDLE hProcess, + _In_ ULONG64 BaseOfDll, + _In_ PSYM_ENUMERATESYMBOLS_CALLBACKW EnumSymbolsCallback, + _In_opt_ PVOID UserContext + ); + +typedef BOOL (WINAPI *_SymEnumTypes)( + _In_ HANDLE hProcess, + _In_ ULONG64 BaseOfDll, + _In_ PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback, + _In_opt_ PVOID UserContext + ); + +typedef BOOL (WINAPI *_SymGetModuleInfoW64)( + _In_ HANDLE hProcess, + _In_ ULONG64 qwAddr, + _Out_ PIMAGEHLP_MODULEW64 ModuleInfo + ); + +typedef BOOL (WINAPI *_SymGetTypeFromName)( + _In_ HANDLE hProcess, + _In_ ULONG64 BaseOfDll, + _In_ PCSTR Name, + _Inout_ PSYMBOL_INFO Symbol + ); + +typedef BOOL(WINAPI *_SymGetTypeFromNameW)( + _In_ HANDLE hProcess, + _In_ ULONG64 BaseOfDll, + _In_ PCWSTR Name, + _Inout_ PSYMBOL_INFOW Symbol + ); + typedef BOOL (WINAPI *_SymGetLineFromAddr64)( _In_ HANDLE hProcess, _In_ ULONG64 dwAddr, diff --git a/phlib/util.c b/phlib/util.c index 2fd650b27028..e5f0f6d7b38a 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -586,6 +586,9 @@ BOOLEAN PhShowConfirmMessage( PPH_STRING verb; PPH_STRING verbCaps; PPH_STRING action; + TASKDIALOGCONFIG config = { sizeof(config) }; + TASKDIALOG_BUTTON buttons[2]; + INT button; // Make sure the verb is all lowercase. verb = PhaLowerString(PhaCreateString(Verb)); @@ -597,53 +600,37 @@ BOOLEAN PhShowConfirmMessage( // "terminate", "the process" -> "terminate the process" action = PhaConcatStrings(3, verb->Buffer, L" ", Object); - if (TaskDialogIndirect_Import()) - { - TASKDIALOGCONFIG config = { sizeof(config) }; - TASKDIALOG_BUTTON buttons[2]; - INT button; - - config.hwndParent = hWnd; - config.hInstance = PhInstanceHandle; - config.dwFlags = TDF_ALLOW_DIALOG_CANCELLATION | (IsWindowVisible(hWnd) ? TDF_POSITION_RELATIVE_TO_WINDOW : 0); - config.pszWindowTitle = PhApplicationName; - config.pszMainIcon = Warning ? TD_WARNING_ICON : NULL; - config.pszMainInstruction = PhaConcatStrings(3, L"Do you want to ", action->Buffer, L"?")->Buffer; + config.hwndParent = hWnd; + config.hInstance = PhInstanceHandle; + config.dwFlags = TDF_ALLOW_DIALOG_CANCELLATION | (IsWindowVisible(hWnd) ? TDF_POSITION_RELATIVE_TO_WINDOW : 0); + config.pszWindowTitle = PhApplicationName; + config.pszMainIcon = Warning ? TD_WARNING_ICON : NULL; + config.pszMainInstruction = PhaConcatStrings(3, L"Do you want to ", action->Buffer, L"?")->Buffer; - if (Message) - config.pszContent = PhaConcatStrings2(Message, L" Are you sure you want to continue?")->Buffer; + if (Message) + config.pszContent = PhaConcatStrings2(Message, L" Are you sure you want to continue?")->Buffer; - buttons[0].nButtonID = IDYES; - buttons[0].pszButtonText = verbCaps->Buffer; - buttons[1].nButtonID = IDNO; - buttons[1].pszButtonText = L"Cancel"; + buttons[0].nButtonID = IDYES; + buttons[0].pszButtonText = verbCaps->Buffer; + buttons[1].nButtonID = IDNO; + buttons[1].pszButtonText = L"Cancel"; - config.cButtons = 2; - config.pButtons = buttons; - config.nDefaultButton = IDYES; + config.cButtons = 2; + config.pButtons = buttons; + config.nDefaultButton = IDYES; - if (TaskDialogIndirect_Import()( - &config, - &button, - NULL, - NULL - ) == S_OK) - { - return button == IDYES; - } - else - { - return FALSE; - } + if (TaskDialogIndirect( + &config, + &button, + NULL, + NULL + ) == S_OK) + { + return button == IDYES; } else { - return PhShowMessage( - hWnd, - MB_YESNO | MB_ICONWARNING, - L"Are you sure you want to %s?", - action->Buffer - ) == IDYES; + return FALSE; } } @@ -5029,3 +5016,52 @@ BOOLEAN PhParseCommandLineFuzzy( return FALSE; } + +PPH_STRING PhGetCacheDirectory( + VOID + ) +{ + return PhGetKnownLocation(CSIDL_LOCAL_APPDATA, L"\\Process Hacker\\Cache\\"); +} + +PPH_STRING PhGetCacheFileName( + _In_ PPH_STRING FileName + ) +{ + PPH_STRING cacheDirectory; + PPH_STRING cacheFilePath; + PPH_STRING cacheFullFilePath = NULL; + ULONG indexOfFileName = -1; + WCHAR alphastring[16] = L""; + + cacheDirectory = PhGetCacheDirectory(); + PhGenerateRandomAlphaString(alphastring, ARRAYSIZE(alphastring)); + + cacheFilePath = PhConcatStrings( + 5, + PhGetStringOrEmpty(cacheDirectory), + L"\\", + alphastring, + L"\\", + PhGetStringOrEmpty(FileName) + ); + + if (cacheFullFilePath = PhGetFullPath(PhGetString(cacheFilePath), &indexOfFileName)) + { + PPH_STRING directoryPath; + + if (indexOfFileName != -1) + { + if (directoryPath = PhSubstring(cacheFullFilePath, 0, indexOfFileName)) + { + SHCreateDirectoryEx(NULL, directoryPath->Buffer, NULL); + PhDereferenceObject(directoryPath); + } + } + } + + PhDereferenceObject(cacheFilePath); + PhDereferenceObject(cacheDirectory); + + return cacheFullFilePath; +} From 556ce3ee3f40ea601416180434412863ad6aecd7 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 10 Aug 2017 23:07:10 +1000 Subject: [PATCH 0363/2058] Export json wrapper, Update plugin imports, Update plugin cache paths --- ProcessHacker/ProcessHacker.def | 20 +- phlib/include/json.h | 161 ++++++ {plugins/CommonUtil => phlib}/json.c | 65 +-- .../CommonUtil/json-c => phlib/jsonc}/AUTHORS | 0 .../CommonUtil/json-c => phlib/jsonc}/COPYING | 0 .../json-c => phlib/jsonc}/ChangeLog | 0 .../json-c => phlib/jsonc}/arraylist.c | 0 .../json-c => phlib/jsonc}/arraylist.h | 0 .../CommonUtil/json-c => phlib/jsonc}/bits.h | 0 .../json-c => phlib/jsonc}/config.h | 0 .../json-c => phlib/jsonc}/config.h.in | 0 .../CommonUtil/json-c => phlib/jsonc}/debug.c | 0 .../CommonUtil/json-c => phlib/jsonc}/debug.h | 0 .../CommonUtil/json-c => phlib/jsonc}/json.h | 0 .../json-c => phlib/jsonc}/json_c_version.c | 0 .../json-c => phlib/jsonc}/json_c_version.h | 0 .../json-c => phlib/jsonc}/json_config.h | 0 .../json-c => phlib/jsonc}/json_inttypes.h | 0 .../json-c => phlib/jsonc}/json_object.c | 0 .../json-c => phlib/jsonc}/json_object.h | 0 .../jsonc}/json_object_iterator.c | 0 .../jsonc}/json_object_iterator.h | 0 .../jsonc}/json_object_private.h | 0 .../json-c => phlib/jsonc}/json_tokener.c | 0 .../json-c => phlib/jsonc}/json_tokener.h | 0 .../json-c => phlib/jsonc}/json_util.c | 0 .../json-c => phlib/jsonc}/json_util.h | 0 .../json-c => phlib/jsonc}/libjson.c | 0 .../json-c => phlib/jsonc}/linkhash.c | 0 .../json-c => phlib/jsonc}/linkhash.h | 0 .../json-c => phlib/jsonc}/math_compat.h | 0 .../json-c => phlib/jsonc}/printbuf.c | 0 .../json-c => phlib/jsonc}/printbuf.h | 0 .../json-c => phlib/jsonc}/random_seed.c | 0 .../json-c => phlib/jsonc}/random_seed.h | 0 phlib/phlib.vcxproj | 32 +- phlib/phlib.vcxproj.filters | 96 ++++ plugins/CommonUtil/CommonUtil.vcxproj | 42 +- plugins/CommonUtil/CommonUtil.vcxproj.filters | 90 ---- plugins/CommonUtil/http.c | 123 ----- plugins/CommonUtil/main.c | 21 - plugins/ExtraPlugins/cloud.c | 51 +- plugins/ExtraPlugins/main.h | 1 + plugins/ExtraPlugins/setup/updater.c | 98 +--- plugins/NetworkTools/update.c | 172 +++---- plugins/OnlineChecks/onlnchk.h | 1 + plugins/OnlineChecks/upload.c | 50 +- plugins/OnlineChecks/virustotal.c | 74 +-- plugins/Updater/page3.c | 6 +- plugins/Updater/page4.c | 6 +- plugins/Updater/updater.c | 234 ++++----- plugins/Updater/updater.h | 14 +- plugins/include/commonutil.h | 457 ------------------ tools/CustomBuildTool/Source Files/Build.cs | 51 +- tools/CustomBuildTool/Source Files/Program.cs | 4 +- .../bin/Release/CustomBuildTool.exe | Bin 162304 -> 161792 bytes .../bin/Release/CustomBuildTool.pdb | Bin 73216 -> 73216 bytes 57 files changed, 652 insertions(+), 1217 deletions(-) create mode 100644 phlib/include/json.h rename {plugins/CommonUtil => phlib}/json.c (73%) rename {plugins/CommonUtil/json-c => phlib/jsonc}/AUTHORS (100%) rename {plugins/CommonUtil/json-c => phlib/jsonc}/COPYING (100%) rename {plugins/CommonUtil/json-c => phlib/jsonc}/ChangeLog (100%) rename {plugins/CommonUtil/json-c => phlib/jsonc}/arraylist.c (100%) rename {plugins/CommonUtil/json-c => phlib/jsonc}/arraylist.h (100%) rename {plugins/CommonUtil/json-c => phlib/jsonc}/bits.h (100%) rename {plugins/CommonUtil/json-c => phlib/jsonc}/config.h (100%) rename {plugins/CommonUtil/json-c => phlib/jsonc}/config.h.in (100%) rename {plugins/CommonUtil/json-c => phlib/jsonc}/debug.c (100%) rename {plugins/CommonUtil/json-c => phlib/jsonc}/debug.h (100%) rename {plugins/CommonUtil/json-c => phlib/jsonc}/json.h (100%) rename {plugins/CommonUtil/json-c => phlib/jsonc}/json_c_version.c (100%) rename {plugins/CommonUtil/json-c => phlib/jsonc}/json_c_version.h (100%) rename {plugins/CommonUtil/json-c => phlib/jsonc}/json_config.h (100%) rename {plugins/CommonUtil/json-c => phlib/jsonc}/json_inttypes.h (100%) rename {plugins/CommonUtil/json-c => phlib/jsonc}/json_object.c (100%) rename {plugins/CommonUtil/json-c => phlib/jsonc}/json_object.h (100%) rename {plugins/CommonUtil/json-c => phlib/jsonc}/json_object_iterator.c (100%) rename {plugins/CommonUtil/json-c => phlib/jsonc}/json_object_iterator.h (100%) rename {plugins/CommonUtil/json-c => phlib/jsonc}/json_object_private.h (100%) rename {plugins/CommonUtil/json-c => phlib/jsonc}/json_tokener.c (100%) rename {plugins/CommonUtil/json-c => phlib/jsonc}/json_tokener.h (100%) rename {plugins/CommonUtil/json-c => phlib/jsonc}/json_util.c (100%) rename {plugins/CommonUtil/json-c => phlib/jsonc}/json_util.h (100%) rename {plugins/CommonUtil/json-c => phlib/jsonc}/libjson.c (100%) rename {plugins/CommonUtil/json-c => phlib/jsonc}/linkhash.c (100%) rename {plugins/CommonUtil/json-c => phlib/jsonc}/linkhash.h (100%) rename {plugins/CommonUtil/json-c => phlib/jsonc}/math_compat.h (100%) rename {plugins/CommonUtil/json-c => phlib/jsonc}/printbuf.c (100%) rename {plugins/CommonUtil/json-c => phlib/jsonc}/printbuf.h (100%) rename {plugins/CommonUtil/json-c => phlib/jsonc}/random_seed.c (100%) rename {plugins/CommonUtil/json-c => phlib/jsonc}/random_seed.h (100%) delete mode 100644 plugins/CommonUtil/http.c diff --git a/ProcessHacker/ProcessHacker.def b/ProcessHacker/ProcessHacker.def index c0ca340aa41f..36df3d1a187b 100644 --- a/ProcessHacker/ProcessHacker.def +++ b/ProcessHacker/ProcessHacker.def @@ -617,4 +617,22 @@ EXPORTS mxmlNewOpaque mxmlNewElement mxmlSaveFd - mxml_opaque_cb \ No newline at end of file + mxml_opaque_cb + +; json + PhCreateJsonParser + PhFreeJsonParser + PhGetJsonValueAsString + PhGetJsonValueAsLong64 + PhCreateJsonObject + PhGetJsonObject + PhGetJsonObjectLength + PhGetJsonObjectBool + PhAddJsonObject + PhCreateJsonArray + PhAddJsonArrayObject + PhGetJsonArrayString + PhGetJsonArrayLong64 + PhGetJsonArrayLength + PhGetJsonArrayIndexObject + PhGetJsonObjectAsArrayList \ No newline at end of file diff --git a/phlib/include/json.h b/phlib/include/json.h new file mode 100644 index 000000000000..fded874784d0 --- /dev/null +++ b/phlib/include/json.h @@ -0,0 +1,161 @@ +/* + * Process Hacker - + * json wrapper + * + * Copyright (C) 2017 dmex + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#ifndef _PH_PHJSON_H +#define _PH_PHJSON_H + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct _JSON_ARRAY_LIST_OBJECT +{ + PSTR Key; + PVOID Entry; +} JSON_ARRAY_LIST_OBJECT, *PJSON_ARRAY_LIST_OBJECT; + +PHLIBAPI +PVOID +NTAPI +PhCreateJsonParser( + _In_ PSTR JsonString + ); + +PHLIBAPI +VOID +NTAPI +PhFreeJsonParser( + _In_ PVOID Object + ); + +PHLIBAPI +PSTR +NTAPI +PhGetJsonValueAsString( + _In_ PVOID Object, + _In_ PSTR Key + ); + +PHLIBAPI +INT64 +NTAPI +PhGetJsonValueAsLong64( + _In_ PVOID Object, + _In_ PSTR Key + ); + +PHLIBAPI +PVOID +NTAPI +PhCreateJsonObject( + VOID + ); + +PHLIBAPI +PVOID +NTAPI +PhGetJsonObject( + _In_ PVOID Object, + _In_ PSTR Key + ); + +PHLIBAPI +INT +NTAPI +PhGetJsonObjectLength( + _In_ PVOID Object + ); + +PHLIBAPI +BOOLEAN +NTAPI +PhGetJsonObjectBool( + _In_ PVOID Object, + _In_ PSTR Key + ); + +PHLIBAPI +VOID +NTAPI +PhAddJsonObject( + _In_ PVOID Object, + _In_ PSTR Key, + _In_ PSTR Value + ); + +PHLIBAPI +PVOID +NTAPI +PhCreateJsonArray( + VOID + ); + +PHLIBAPI +VOID +NTAPI +PhAddJsonArrayObject( + _In_ PVOID Object, + _In_ PVOID jsonEntry + ); + +PHLIBAPI +PSTR +NTAPI +PhGetJsonArrayString( + _In_ PVOID Object + ); + +PHLIBAPI +INT64 +NTAPI +PhGetJsonArrayLong64( + _In_ PVOID Object, + _In_ INT Index + ); + +PHLIBAPI +INT +NTAPI +PhGetJsonArrayLength( + _In_ PVOID Object + ); + +PHLIBAPI +PVOID +NTAPI +PhGetJsonArrayIndexObject( + _In_ PVOID Object, + _In_ INT Index + ); + +PHLIBAPI +PVOID +NTAPI +PhGetJsonObjectAsArrayList( + _In_ PVOID Object + ); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/plugins/CommonUtil/json.c b/phlib/json.c similarity index 73% rename from plugins/CommonUtil/json.c rename to phlib/json.c index 8b1d3e8f062b..d22c766033da 100644 --- a/plugins/CommonUtil/json.c +++ b/phlib/json.c @@ -1,8 +1,8 @@ /* - * Process Hacker Plugins - - * CommonUtil Plugin + * Process Hacker - + * json wrapper * - * Copyright (C) 2016 dmex + * Copyright (C) 2017 dmex * * This file is part of Process Hacker. * @@ -18,13 +18,16 @@ * * You should have received a copy of the GNU General Public License * along with Process Hacker. If not, see . - * */ -#include "main.h" -#include "json-c\json.h" +#include +#include +#include + +#include "jsonc\json.h" +#include -json_object_ptr json_get_object( +static json_object_ptr json_get_object( _In_ json_object_ptr rootObj, _In_ const PSTR key ) @@ -39,21 +42,21 @@ json_object_ptr json_get_object( return NULL; } -PVOID UtilCreateJsonParser( +PVOID PhCreateJsonParser( _In_ PSTR JsonString ) { return json_tokener_parse(JsonString); } -VOID UtilCleanupJsonParser( +VOID PhFreeJsonParser( _In_ PVOID Object ) { json_object_put(Object); } -PSTR UtilGetJsonValueAsString( +PSTR PhGetJsonValueAsString( _In_ PVOID Object, _In_ PSTR Key ) @@ -61,7 +64,7 @@ PSTR UtilGetJsonValueAsString( return json_object_get_string(json_get_object(Object, Key)); } -INT64 UtilGetJsonValueAsUlong( +INT64 PhGetJsonValueAsLong64( _In_ PVOID Object, _In_ PSTR Key ) @@ -69,14 +72,14 @@ INT64 UtilGetJsonValueAsUlong( return json_object_get_int64(json_get_object(Object, Key)); } -PVOID UtilCreateJsonObject( +PVOID PhCreateJsonObject( VOID ) { return json_object_new_object(); } -PVOID UtilGetJsonObject( +PVOID PhGetJsonObject( _In_ PVOID Object, _In_ PSTR Key ) @@ -84,22 +87,22 @@ PVOID UtilGetJsonObject( return json_get_object(Object, Key); } -INT UtilGetJsonObjectLength( +INT PhGetJsonObjectLength( _In_ PVOID Object ) { return json_object_object_length(Object); } -BOOL UtilGetJsonObjectBool( +BOOLEAN PhGetJsonObjectBool( _In_ PVOID Object, _In_ PSTR Key ) { - return json_object_get_boolean(json_get_object(Object, Key)); + return json_object_get_boolean(json_get_object(Object, Key)) == TRUE; } -VOID UtilJsonAddObject( +VOID PhAddJsonObject( _In_ PVOID Object, _In_ PSTR Key, _In_ PSTR Value @@ -108,14 +111,14 @@ VOID UtilJsonAddObject( json_object_object_add(Object, Key, json_object_new_string(Value)); } -PVOID UtilCreateJsonArray( +PVOID PhCreateJsonArray( VOID ) { return json_object_new_array(); } -VOID UtilAddJsonArray( +VOID PhAddJsonArrayObject( _In_ PVOID Object, _In_ PVOID jsonEntry ) @@ -123,14 +126,14 @@ VOID UtilAddJsonArray( json_object_array_add(Object, jsonEntry); } -PSTR UtilGetJsonArrayString( +PSTR PhGetJsonArrayString( _In_ PVOID Object ) { return _strdup( json_object_to_json_string(Object) ); // leak } -INT64 UtilGetJsonArrayUlong( +INT64 PhGetJsonArrayLong64( _In_ PVOID Object, _In_ INT Index ) @@ -138,14 +141,14 @@ INT64 UtilGetJsonArrayUlong( return json_object_get_int64(json_object_array_get_idx(Object, Index)); } -INT UtilGetArrayLength( +INT PhGetJsonArrayLength( _In_ PVOID Object ) { return json_object_array_length(Object); } -PVOID UtilGetObjectArrayIndex( +PVOID PhGetJsonArrayIndexObject( _In_ PVOID Object, _In_ INT Index ) @@ -153,25 +156,27 @@ PVOID UtilGetObjectArrayIndex( return json_object_array_get_idx(Object, Index); } -PPH_LIST UtilGetObjectArrayList( +PVOID PhGetJsonObjectAsArrayList( _In_ PVOID Object ) { - json_object_iter object_iter; PPH_LIST listArray; + json_object_iter json_array_ptr; listArray = PhCreateList(1); - json_object_object_foreachC(Object, object_iter) + json_object_object_foreachC(Object, json_array_ptr) { - PJSON_ARRAY_LIST_OBJECT object = PhAllocate(sizeof(JSON_ARRAY_LIST_OBJECT)); + PJSON_ARRAY_LIST_OBJECT object; + + object = PhAllocate(sizeof(JSON_ARRAY_LIST_OBJECT)); memset(object, 0, sizeof(JSON_ARRAY_LIST_OBJECT)); - object->Key = object_iter.key; - object->Entry = object_iter.val; + object->Key = json_array_ptr.key; + object->Entry = json_array_ptr.val; PhAddItemList(listArray, object); } return listArray; -} \ No newline at end of file +} diff --git a/plugins/CommonUtil/json-c/AUTHORS b/phlib/jsonc/AUTHORS similarity index 100% rename from plugins/CommonUtil/json-c/AUTHORS rename to phlib/jsonc/AUTHORS diff --git a/plugins/CommonUtil/json-c/COPYING b/phlib/jsonc/COPYING similarity index 100% rename from plugins/CommonUtil/json-c/COPYING rename to phlib/jsonc/COPYING diff --git a/plugins/CommonUtil/json-c/ChangeLog b/phlib/jsonc/ChangeLog similarity index 100% rename from plugins/CommonUtil/json-c/ChangeLog rename to phlib/jsonc/ChangeLog diff --git a/plugins/CommonUtil/json-c/arraylist.c b/phlib/jsonc/arraylist.c similarity index 100% rename from plugins/CommonUtil/json-c/arraylist.c rename to phlib/jsonc/arraylist.c diff --git a/plugins/CommonUtil/json-c/arraylist.h b/phlib/jsonc/arraylist.h similarity index 100% rename from plugins/CommonUtil/json-c/arraylist.h rename to phlib/jsonc/arraylist.h diff --git a/plugins/CommonUtil/json-c/bits.h b/phlib/jsonc/bits.h similarity index 100% rename from plugins/CommonUtil/json-c/bits.h rename to phlib/jsonc/bits.h diff --git a/plugins/CommonUtil/json-c/config.h b/phlib/jsonc/config.h similarity index 100% rename from plugins/CommonUtil/json-c/config.h rename to phlib/jsonc/config.h diff --git a/plugins/CommonUtil/json-c/config.h.in b/phlib/jsonc/config.h.in similarity index 100% rename from plugins/CommonUtil/json-c/config.h.in rename to phlib/jsonc/config.h.in diff --git a/plugins/CommonUtil/json-c/debug.c b/phlib/jsonc/debug.c similarity index 100% rename from plugins/CommonUtil/json-c/debug.c rename to phlib/jsonc/debug.c diff --git a/plugins/CommonUtil/json-c/debug.h b/phlib/jsonc/debug.h similarity index 100% rename from plugins/CommonUtil/json-c/debug.h rename to phlib/jsonc/debug.h diff --git a/plugins/CommonUtil/json-c/json.h b/phlib/jsonc/json.h similarity index 100% rename from plugins/CommonUtil/json-c/json.h rename to phlib/jsonc/json.h diff --git a/plugins/CommonUtil/json-c/json_c_version.c b/phlib/jsonc/json_c_version.c similarity index 100% rename from plugins/CommonUtil/json-c/json_c_version.c rename to phlib/jsonc/json_c_version.c diff --git a/plugins/CommonUtil/json-c/json_c_version.h b/phlib/jsonc/json_c_version.h similarity index 100% rename from plugins/CommonUtil/json-c/json_c_version.h rename to phlib/jsonc/json_c_version.h diff --git a/plugins/CommonUtil/json-c/json_config.h b/phlib/jsonc/json_config.h similarity index 100% rename from plugins/CommonUtil/json-c/json_config.h rename to phlib/jsonc/json_config.h diff --git a/plugins/CommonUtil/json-c/json_inttypes.h b/phlib/jsonc/json_inttypes.h similarity index 100% rename from plugins/CommonUtil/json-c/json_inttypes.h rename to phlib/jsonc/json_inttypes.h diff --git a/plugins/CommonUtil/json-c/json_object.c b/phlib/jsonc/json_object.c similarity index 100% rename from plugins/CommonUtil/json-c/json_object.c rename to phlib/jsonc/json_object.c diff --git a/plugins/CommonUtil/json-c/json_object.h b/phlib/jsonc/json_object.h similarity index 100% rename from plugins/CommonUtil/json-c/json_object.h rename to phlib/jsonc/json_object.h diff --git a/plugins/CommonUtil/json-c/json_object_iterator.c b/phlib/jsonc/json_object_iterator.c similarity index 100% rename from plugins/CommonUtil/json-c/json_object_iterator.c rename to phlib/jsonc/json_object_iterator.c diff --git a/plugins/CommonUtil/json-c/json_object_iterator.h b/phlib/jsonc/json_object_iterator.h similarity index 100% rename from plugins/CommonUtil/json-c/json_object_iterator.h rename to phlib/jsonc/json_object_iterator.h diff --git a/plugins/CommonUtil/json-c/json_object_private.h b/phlib/jsonc/json_object_private.h similarity index 100% rename from plugins/CommonUtil/json-c/json_object_private.h rename to phlib/jsonc/json_object_private.h diff --git a/plugins/CommonUtil/json-c/json_tokener.c b/phlib/jsonc/json_tokener.c similarity index 100% rename from plugins/CommonUtil/json-c/json_tokener.c rename to phlib/jsonc/json_tokener.c diff --git a/plugins/CommonUtil/json-c/json_tokener.h b/phlib/jsonc/json_tokener.h similarity index 100% rename from plugins/CommonUtil/json-c/json_tokener.h rename to phlib/jsonc/json_tokener.h diff --git a/plugins/CommonUtil/json-c/json_util.c b/phlib/jsonc/json_util.c similarity index 100% rename from plugins/CommonUtil/json-c/json_util.c rename to phlib/jsonc/json_util.c diff --git a/plugins/CommonUtil/json-c/json_util.h b/phlib/jsonc/json_util.h similarity index 100% rename from plugins/CommonUtil/json-c/json_util.h rename to phlib/jsonc/json_util.h diff --git a/plugins/CommonUtil/json-c/libjson.c b/phlib/jsonc/libjson.c similarity index 100% rename from plugins/CommonUtil/json-c/libjson.c rename to phlib/jsonc/libjson.c diff --git a/plugins/CommonUtil/json-c/linkhash.c b/phlib/jsonc/linkhash.c similarity index 100% rename from plugins/CommonUtil/json-c/linkhash.c rename to phlib/jsonc/linkhash.c diff --git a/plugins/CommonUtil/json-c/linkhash.h b/phlib/jsonc/linkhash.h similarity index 100% rename from plugins/CommonUtil/json-c/linkhash.h rename to phlib/jsonc/linkhash.h diff --git a/plugins/CommonUtil/json-c/math_compat.h b/phlib/jsonc/math_compat.h similarity index 100% rename from plugins/CommonUtil/json-c/math_compat.h rename to phlib/jsonc/math_compat.h diff --git a/plugins/CommonUtil/json-c/printbuf.c b/phlib/jsonc/printbuf.c similarity index 100% rename from plugins/CommonUtil/json-c/printbuf.c rename to phlib/jsonc/printbuf.c diff --git a/plugins/CommonUtil/json-c/printbuf.h b/phlib/jsonc/printbuf.h similarity index 100% rename from plugins/CommonUtil/json-c/printbuf.h rename to phlib/jsonc/printbuf.h diff --git a/plugins/CommonUtil/json-c/random_seed.c b/phlib/jsonc/random_seed.c similarity index 100% rename from plugins/CommonUtil/json-c/random_seed.c rename to phlib/jsonc/random_seed.c diff --git a/plugins/CommonUtil/json-c/random_seed.h b/phlib/jsonc/random_seed.h similarity index 100% rename from plugins/CommonUtil/json-c/random_seed.h rename to phlib/jsonc/random_seed.h diff --git a/phlib/phlib.vcxproj b/phlib/phlib.vcxproj index e395b2239ea8..fe378512fe80 100644 --- a/phlib/phlib.vcxproj +++ b/phlib/phlib.vcxproj @@ -1,4 +1,4 @@ - + @@ -161,6 +161,18 @@ + + + + + + + + + + + + @@ -201,6 +213,7 @@ + @@ -236,6 +249,23 @@ + + + + + + + + + + + + + + + + + diff --git a/phlib/phlib.vcxproj.filters b/phlib/phlib.vcxproj.filters index dee92e1b386b..2ebb7ab5f4b3 100644 --- a/phlib/phlib.vcxproj.filters +++ b/phlib/phlib.vcxproj.filters @@ -15,6 +15,12 @@ {874b89c3-fb60-46f3-a62c-49ac88e3026d} + + {fd6c74dc-d93e-4dd1-9a8b-5bdf525e0709} + + + {4f0e2a3e-3009-4e13-8d38-e33c46d00044} + @@ -176,6 +182,42 @@ Mini-XML + + Json-C + + + Json-C + + + Json-C + + + Json-C + + + Json-C + + + Json-C + + + Json-C + + + Json-C + + + Json-C + + + Json-C + + + Json-C + + + Json-C + @@ -364,5 +406,59 @@ Mini-XML\Headers + + Json-C\Headers + + + Json-C\Headers + + + Json-C\Headers + + + Json-C\Headers + + + Json-C\Headers + + + Json-C\Headers + + + Json-C\Headers + + + Json-C\Headers + + + Json-C\Headers + + + Json-C\Headers + + + Json-C\Headers + + + Json-C\Headers + + + Json-C\Headers + + + Json-C\Headers + + + Json-C\Headers + + + Json-C\Headers + + + Json-C\Headers + + + Header Files + \ No newline at end of file diff --git a/plugins/CommonUtil/CommonUtil.vcxproj b/plugins/CommonUtil/CommonUtil.vcxproj index c2b017b83820..aa57362d61bc 100644 --- a/plugins/CommonUtil/CommonUtil.vcxproj +++ b/plugins/CommonUtil/CommonUtil.vcxproj @@ -55,62 +55,28 @@ - windowscodecs.lib;winhttp.lib;ws2_32.lib;uxtheme.lib;%(AdditionalDependencies) - winhttp.dll;ws2_32.dll;%(DelayLoadDLLs) + windowscodecs.lib;uxtheme.lib;%(AdditionalDependencies) - windowscodecs.lib;winhttp.lib;ws2_32.lib;uxtheme.lib;%(AdditionalDependencies) - winhttp.dll;ws2_32.dll;%(DelayLoadDLLs) + windowscodecs.lib;uxtheme.lib;%(AdditionalDependencies) - windowscodecs.lib;winhttp.lib;ws2_32.lib;uxtheme.lib;%(AdditionalDependencies) - winhttp.dll;ws2_32.dll;%(DelayLoadDLLs) + windowscodecs.lib;uxtheme.lib;%(AdditionalDependencies) - windowscodecs.lib;winhttp.lib;ws2_32.lib;uxtheme.lib;%(AdditionalDependencies) - winhttp.dll;ws2_32.dll;%(DelayLoadDLLs) + windowscodecs.lib;uxtheme.lib;%(AdditionalDependencies) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/plugins/CommonUtil/CommonUtil.vcxproj.filters b/plugins/CommonUtil/CommonUtil.vcxproj.filters index 83a49f7f2074..6df6a7997e96 100644 --- a/plugins/CommonUtil/CommonUtil.vcxproj.filters +++ b/plugins/CommonUtil/CommonUtil.vcxproj.filters @@ -25,45 +25,6 @@ Source Files - - Source Files - - - Source Files\json-c - - - Source Files\json-c - - - Source Files\json-c - - - Source Files\json-c - - - Source Files\json-c - - - Source Files\json-c - - - Source Files\json-c - - - Source Files\json-c - - - Source Files\json-c - - - Source Files\json-c - - - Source Files\json-c - - - Source Files - @@ -72,57 +33,6 @@ Header Files - - Header Files\json-c - - - Header Files\json-c - - - Header Files\json-c - - - Header Files\json-c - - - Header Files\json-c - - - Header Files\json-c - - - Header Files\json-c - - - Header Files\json-c - - - Header Files\json-c - - - Header Files\json-c - - - Header Files\json-c - - - Header Files\json-c - - - Header Files\json-c - - - Header Files\json-c - - - Header Files\json-c - - - Header Files\json-c - - - Header Files\json-c - diff --git a/plugins/CommonUtil/http.c b/plugins/CommonUtil/http.c deleted file mode 100644 index c6034aed6a8e..000000000000 --- a/plugins/CommonUtil/http.c +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Process Hacker Plugins - - * CommonUtil Plugin - * - * Copyright (C) 2016 dmex - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - * - */ - -#include "main.h" -#include -#include -#include - -PPH_BYTES UtilReadSocketString( - _In_ SOCKET Handle - ) -{ - PSTR data; - ULONG allocatedLength; - ULONG dataLength; - ULONG returnLength; - BYTE buffer[PAGE_SIZE]; - - allocatedLength = sizeof(buffer); - data = (PSTR)PhAllocate(allocatedLength); - dataLength = 0; - - // Zero the buffer - memset(buffer, 0, PAGE_SIZE); - - while ((returnLength = recv(Handle, buffer, PAGE_SIZE, 0)) != SOCKET_ERROR) - { - if (returnLength == 0) - break; - - if (allocatedLength < dataLength + returnLength) - { - allocatedLength *= 2; - data = (PSTR)PhReAllocate(data, allocatedLength); - } - - // Copy the returned buffer into our pointer - memcpy(data + dataLength, buffer, returnLength); - // Zero the returned buffer for the next loop - //memset(buffer, 0, returnLength); - - dataLength += returnLength; - } - - if (allocatedLength < dataLength + 1) - { - allocatedLength++; - data = (PSTR)PhReAllocate(data, allocatedLength); - } - - // Ensure that the buffer is null-terminated - data[dataLength] = 0; - - return PhCreateBytesEx(data, dataLength); -} - -PPH_BYTES UtilReadWinHttpString( - _In_ HINTERNET Handle - ) -{ - BYTE buffer[PAGE_SIZE]; - PSTR data; - ULONG allocatedLength; - ULONG dataLength; - ULONG returnLength; - - allocatedLength = sizeof(buffer); - data = (PSTR)PhAllocate(allocatedLength); - dataLength = 0; - - // Zero the buffer - memset(buffer, 0, PAGE_SIZE); - - while (WinHttpReadData(Handle, buffer, PAGE_SIZE, &returnLength)) - { - if (returnLength == 0) - break; - - if (allocatedLength < dataLength + returnLength) - { - allocatedLength *= 2; - data = (PSTR)PhReAllocate(data, allocatedLength); - } - - // Copy the returned buffer into our pointer - memcpy(data + dataLength, buffer, returnLength); - // Zero the returned buffer for the next loop - //memset(buffer, 0, returnLength); - - dataLength += returnLength; - } - - if (allocatedLength < dataLength + 1) - { - allocatedLength++; - data = (PSTR)PhReAllocate(data, allocatedLength); - } - - // Ensure that the buffer is null-terminated - data[dataLength] = 0; - - return PhCreateBytesEx(data, dataLength); -} \ No newline at end of file diff --git a/plugins/CommonUtil/main.c b/plugins/CommonUtil/main.c index ea019c1f52aa..c5e5c664c546 100644 --- a/plugins/CommonUtil/main.c +++ b/plugins/CommonUtil/main.c @@ -24,26 +24,6 @@ #include "main.h" PPH_PLUGIN PluginInstance; -COMMONUTIL_INTERFACE PluginInterface = -{ - COMMONUTIL_INTERFACE_VERSION, - UtilCreateJsonParser, - UtilCleanupJsonParser, - UtilGetJsonValueAsString, - UtilGetJsonValueAsUlong, - UtilGetJsonObjectBool, - UtilCreateJsonObject, - UtilGetJsonObject, - UtilGetJsonObjectLength, - UtilJsonAddObject, - UtilCreateJsonArray, - UtilAddJsonArray, - UtilGetJsonArrayString, - UtilGetJsonArrayUlong, - UtilGetArrayLength, - UtilGetObjectArrayIndex, - UtilGetObjectArrayList -}; LOGICAL DllMain( _In_ HINSTANCE Instance, @@ -66,7 +46,6 @@ LOGICAL DllMain( info->Author = L"dmex"; info->Description = L"Common Plugin Extensions"; info->HasOptions = FALSE; - info->Interface = &PluginInterface; } break; } diff --git a/plugins/ExtraPlugins/cloud.c b/plugins/ExtraPlugins/cloud.c index 57509cc969c0..f8a791741008 100644 --- a/plugins/ExtraPlugins/cloud.c +++ b/plugins/ExtraPlugins/cloud.c @@ -53,7 +53,7 @@ NTSTATUS QueryPluginsCallbackThread( HINTERNET httpRequestHandle = NULL; ULONG xmlStringBufferLength = 0; PSTR xmlStringBuffer = NULL; - PVOID rootJsonObject; + PVOID rootJsonObject = NULL; PWCT_CONTEXT context = Parameter; if (!(httpSessionHandle = WinHttpOpen( @@ -109,10 +109,10 @@ NTSTATUS QueryPluginsCallbackThread( if (!ReadRequestString(httpRequestHandle, &xmlStringBuffer, &xmlStringBufferLength)) goto CleanupExit; - if (!(rootJsonObject = CreateJsonParser(xmlStringBuffer))) + if (!(rootJsonObject = PhCreateJsonParser(xmlStringBuffer))) goto CleanupExit; - for (INT i = 0; i < JsonGetArrayLength(rootJsonObject); i++) + for (INT i = 0; i < PhGetJsonArrayLength(rootJsonObject); i++) { PVOID jvalue; PPLUGIN_NODE entry; @@ -124,27 +124,27 @@ NTSTATUS QueryPluginsCallbackThread( entry = PhCreateAlloc(sizeof(PLUGIN_NODE)); memset(entry, 0, sizeof(PLUGIN_NODE)); - jvalue = JsonGetObjectArrayIndex(rootJsonObject, i); - entry->Id = PhConvertUtf8ToUtf16(GetJsonValueAsString(jvalue, "plugin_id")); - entry->InternalName = PhConvertUtf8ToUtf16(GetJsonValueAsString(jvalue, "plugin_internal_name")); - entry->Name = PhConvertUtf8ToUtf16(GetJsonValueAsString(jvalue, "plugin_name")); - entry->Version = PhConvertUtf8ToUtf16(GetJsonValueAsString(jvalue, "plugin_version")); - entry->Author = PhConvertUtf8ToUtf16(GetJsonValueAsString(jvalue, "plugin_author")); - entry->Description = PhConvertUtf8ToUtf16(GetJsonValueAsString(jvalue, "plugin_description")); - entry->IconUrl = PhConvertUtf8ToUtf16(GetJsonValueAsString(jvalue, "plugin_icon")); - entry->Requirements = PhConvertUtf8ToUtf16(GetJsonValueAsString(jvalue, "plugin_requirements")); - entry->FeedbackUrl = PhConvertUtf8ToUtf16(GetJsonValueAsString(jvalue, "plugin_feedback")); - entry->Screenshots = PhConvertUtf8ToUtf16(GetJsonValueAsString(jvalue, "plugin_screenshots")); - entry->AddedTime = PhConvertUtf8ToUtf16(GetJsonValueAsString(jvalue, "plugin_datetime_added")); - entry->UpdatedTime = PhConvertUtf8ToUtf16(GetJsonValueAsString(jvalue, "plugin_datetime_updated")); - entry->Download_count = PhConvertUtf8ToUtf16(GetJsonValueAsString(jvalue, "plugin_download_count")); - entry->Download_link_32 = PhConvertUtf8ToUtf16(GetJsonValueAsString(jvalue, "plugin_download_link_32")); - entry->Download_link_64 = PhConvertUtf8ToUtf16(GetJsonValueAsString(jvalue, "plugin_download_link_64")); - entry->SHA2_32 = PhConvertUtf8ToUtf16(GetJsonValueAsString(jvalue, "plugin_hash_32")); - entry->SHA2_64 = PhConvertUtf8ToUtf16(GetJsonValueAsString(jvalue, "plugin_hash_64")); - entry->HASH_32 = PhConvertUtf8ToUtf16(GetJsonValueAsString(jvalue, "plugin_signed_32")); - entry->HASH_64 = PhConvertUtf8ToUtf16(GetJsonValueAsString(jvalue, "plugin_signed_64")); - entry->FileName = PhConvertUtf8ToUtf16(GetJsonValueAsString(jvalue, "plugin_filename")); + jvalue = PhGetJsonArrayIndexObject(rootJsonObject, i); + entry->Id = PhConvertUtf8ToUtf16(PhGetJsonValueAsString(jvalue, "plugin_id")); + entry->InternalName = PhConvertUtf8ToUtf16(PhGetJsonValueAsString(jvalue, "plugin_internal_name")); + entry->Name = PhConvertUtf8ToUtf16(PhGetJsonValueAsString(jvalue, "plugin_name")); + entry->Version = PhConvertUtf8ToUtf16(PhGetJsonValueAsString(jvalue, "plugin_version")); + entry->Author = PhConvertUtf8ToUtf16(PhGetJsonValueAsString(jvalue, "plugin_author")); + entry->Description = PhConvertUtf8ToUtf16(PhGetJsonValueAsString(jvalue, "plugin_description")); + entry->IconUrl = PhConvertUtf8ToUtf16(PhGetJsonValueAsString(jvalue, "plugin_icon")); + entry->Requirements = PhConvertUtf8ToUtf16(PhGetJsonValueAsString(jvalue, "plugin_requirements")); + entry->FeedbackUrl = PhConvertUtf8ToUtf16(PhGetJsonValueAsString(jvalue, "plugin_feedback")); + entry->Screenshots = PhConvertUtf8ToUtf16(PhGetJsonValueAsString(jvalue, "plugin_screenshots")); + entry->AddedTime = PhConvertUtf8ToUtf16(PhGetJsonValueAsString(jvalue, "plugin_datetime_added")); + entry->UpdatedTime = PhConvertUtf8ToUtf16(PhGetJsonValueAsString(jvalue, "plugin_datetime_updated")); + entry->Download_count = PhConvertUtf8ToUtf16(PhGetJsonValueAsString(jvalue, "plugin_download_count")); + entry->Download_link_32 = PhConvertUtf8ToUtf16(PhGetJsonValueAsString(jvalue, "plugin_download_link_32")); + entry->Download_link_64 = PhConvertUtf8ToUtf16(PhGetJsonValueAsString(jvalue, "plugin_download_link_64")); + entry->SHA2_32 = PhConvertUtf8ToUtf16(PhGetJsonValueAsString(jvalue, "plugin_hash_32")); + entry->SHA2_64 = PhConvertUtf8ToUtf16(PhGetJsonValueAsString(jvalue, "plugin_hash_64")); + entry->HASH_32 = PhConvertUtf8ToUtf16(PhGetJsonValueAsString(jvalue, "plugin_signed_32")); + entry->HASH_64 = PhConvertUtf8ToUtf16(PhGetJsonValueAsString(jvalue, "plugin_signed_64")); + entry->FileName = PhConvertUtf8ToUtf16(PhGetJsonValueAsString(jvalue, "plugin_filename")); swscanf( PhGetString(entry->UpdatedTime), @@ -253,6 +253,9 @@ NTSTATUS QueryPluginsCallbackThread( CleanupExit: + if (rootJsonObject) + PhFreeJsonParser(rootJsonObject); + if (httpRequestHandle) WinHttpCloseHandle(httpRequestHandle); diff --git a/plugins/ExtraPlugins/main.h b/plugins/ExtraPlugins/main.h index 8bb75a8fb1d5..b425a322b6c3 100644 --- a/plugins/ExtraPlugins/main.h +++ b/plugins/ExtraPlugins/main.h @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include diff --git a/plugins/ExtraPlugins/setup/updater.c b/plugins/ExtraPlugins/setup/updater.c index 0dc634b825aa..d8a6d0d95c14 100644 --- a/plugins/ExtraPlugins/setup/updater.c +++ b/plugins/ExtraPlugins/setup/updater.c @@ -288,87 +288,28 @@ NTSTATUS UpdateDownloadThread( HINTERNET httpSessionHandle = NULL; HINTERNET httpConnectionHandle = NULL; HINTERNET httpRequestHandle = NULL; - PPH_STRING setupTempPath = NULL; PPH_STRING downloadHostPath = NULL; PPH_STRING downloadUrlPath = NULL; PPH_STRING userAgentString = NULL; - PPH_STRING fullSetupPath = NULL; - PPH_STRING randomGuidString = NULL; PUPDATER_HASH_CONTEXT hashContext = NULL; ULONG indexOfFileName = -1; - GUID randomGuid; - URL_COMPONENTS httpUrlComponents = { sizeof(URL_COMPONENTS) }; + URL_COMPONENTS httpParts = { sizeof(URL_COMPONENTS) }; LARGE_INTEGER timeNow; LARGE_INTEGER timeStart; ULONG64 timeTicks = 0; ULONG64 timeBitsPerSecond = 0; PPH_UPDATER_CONTEXT context = (PPH_UPDATER_CONTEXT)Parameter; - context->FileDownloadUrl = PhFormatString( - L"https://wj32.org/processhacker/plugins/download.php?id=%s&type=64", - PhGetStringOrEmpty(context->Node->Id) - ); - SendMessage(context->DialogHandle, TDM_UPDATE_ELEMENT_TEXT, TDE_MAIN_INSTRUCTION, (LPARAM)L"Initializing download request..."); - // Create a user agent string. - //userAgentString = PhFormatString( - // L"PH_%lu.%lu_%lu", - // context->CurrentMajorVersion, - // context->CurrentMinorVersion, - // context->CurrentRevisionVersion - // ); - //if (PhIsNullOrEmptyString(userAgentString)) - // goto CleanupExit; - - setupTempPath = PhCreateStringEx(NULL, GetTempPath(0, NULL) * sizeof(WCHAR)); - if (PhIsNullOrEmptyString(setupTempPath)) - goto CleanupExit; - if (GetTempPath((ULONG)setupTempPath->Length / sizeof(WCHAR), setupTempPath->Buffer) == 0) - goto CleanupExit; - if (PhIsNullOrEmptyString(setupTempPath)) - goto CleanupExit; - - // Generate random guid for our directory path. - PhGenerateGuid(&randomGuid); - - if (randomGuidString = PhFormatGuid(&randomGuid)) - { - PPH_STRING guidSubString; - - // Strip the left and right curly brackets. - guidSubString = PhSubstring(randomGuidString, 1, randomGuidString->Length / sizeof(WCHAR) - 2); - - PhMoveReference(&randomGuidString, guidSubString); - } - - // Append the tempath to our string: %TEMP%RandomString\\processhacker-%lu.%lu-setup.exe - // Example: C:\\Users\\dmex\\AppData\\Temp\\ABCD\\processhacker-2.90-setup.exe - context->SetupFilePath = PhFormatString( - L"%s%s\\%s.zip", - PhGetStringOrEmpty(setupTempPath), - PhGetStringOrEmpty(randomGuidString), + context->SetupFilePath = PhGetCacheFileName(PhaFormatString( + L"%s.zip", PhGetStringOrEmpty(context->Node->InternalName) - ); + )); + if (PhIsNullOrEmptyString(context->SetupFilePath)) goto CleanupExit; - // Create the directory if it does not exist. - if (fullSetupPath = PhGetFullPath(PhGetString(context->SetupFilePath), &indexOfFileName)) - { - PPH_STRING directoryPath; - - if (indexOfFileName == -1) - goto CleanupExit; - - if (directoryPath = PhSubstring(fullSetupPath, 0, indexOfFileName)) - { - SHCreateDirectoryEx(NULL, PhGetString(directoryPath), NULL); - PhDereferenceObject(directoryPath); - } - } - - // Create output file if (!NT_SUCCESS(PhCreateFileWin32( &tempFileHandle, PhGetStringOrEmpty(context->SetupFilePath), @@ -382,29 +323,33 @@ NTSTATUS UpdateDownloadThread( goto CleanupExit; } + context->FileDownloadUrl = PhFormatString( + L"https://wj32.org/processhacker/plugins/download.php?id=%s&type=64", + PhGetStringOrEmpty(context->Node->Id) + ); + // Set lengths to non-zero enabling these params to be cracked. - httpUrlComponents.dwSchemeLength = (ULONG)-1; - httpUrlComponents.dwHostNameLength = (ULONG)-1; - httpUrlComponents.dwUrlPathLength = (ULONG)-1; + httpParts.dwSchemeLength = (ULONG)-1; + httpParts.dwHostNameLength = (ULONG)-1; + httpParts.dwUrlPathLength = (ULONG)-1; if (!WinHttpCrackUrl( PhGetString(context->FileDownloadUrl), 0, 0, - &httpUrlComponents + &httpParts )) { goto CleanupExit; } // Create the Host string. - downloadHostPath = PhCreateStringEx(httpUrlComponents.lpszHostName, httpUrlComponents.dwHostNameLength * sizeof(WCHAR)); + downloadHostPath = PhCreateStringEx(httpParts.lpszHostName, httpParts.dwHostNameLength * sizeof(WCHAR)); // Create the Path string. - downloadUrlPath = PhCreateStringEx(httpUrlComponents.lpszUrlPath, httpUrlComponents.dwUrlPathLength * sizeof(WCHAR)); + downloadUrlPath = PhCreateStringEx(httpParts.lpszUrlPath, httpParts.dwUrlPathLength * sizeof(WCHAR)); SendMessage(context->DialogHandle, TDM_UPDATE_ELEMENT_TEXT, TDE_MAIN_INSTRUCTION, (LPARAM)L"Connecting..."); - // Open the HTTP session with the system proxy configuration if available if (!(httpSessionHandle = WinHttpOpen( PhGetString(userAgentString), WindowsVersion >= WINDOWS_8_1 ? WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY : WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, @@ -418,12 +363,10 @@ NTSTATUS UpdateDownloadThread( if (WindowsVersion >= WINDOWS_8_1) { - ULONG httpFlags = WINHTTP_DECOMPRESSION_FLAG_GZIP | WINHTTP_DECOMPRESSION_FLAG_DEFLATE; - WinHttpSetOption( httpSessionHandle, WINHTTP_OPTION_DECOMPRESSION, - &httpFlags, + &(ULONG) { WINHTTP_DECOMPRESSION_FLAG_GZIP | WINHTTP_DECOMPRESSION_FLAG_DEFLATE }, sizeof(ULONG) ); } @@ -431,7 +374,7 @@ NTSTATUS UpdateDownloadThread( if (!(httpConnectionHandle = WinHttpConnect( httpSessionHandle, PhGetString(downloadHostPath), - httpUrlComponents.nScheme == INTERNET_SCHEME_HTTP ? INTERNET_DEFAULT_HTTP_PORT : INTERNET_DEFAULT_HTTPS_PORT, + httpParts.nScheme == INTERNET_SCHEME_HTTP ? INTERNET_DEFAULT_HTTP_PORT : INTERNET_DEFAULT_HTTPS_PORT, 0 ))) { @@ -445,7 +388,7 @@ NTSTATUS UpdateDownloadThread( NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, - WINHTTP_FLAG_REFRESH | (httpUrlComponents.nScheme == INTERNET_SCHEME_HTTPS ? WINHTTP_FLAG_SECURE : 0) + WINHTTP_FLAG_REFRESH | (httpParts.nScheme == INTERNET_SCHEME_HTTPS ? WINHTTP_FLAG_SECURE : 0) ))) { goto CleanupExit; @@ -612,9 +555,6 @@ NTSTATUS UpdateDownloadThread( if (httpSessionHandle) WinHttpCloseHandle(httpSessionHandle); - PhClearReference(&randomGuidString); - PhClearReference(&fullSetupPath); - PhClearReference(&setupTempPath); PhClearReference(&downloadHostPath); PhClearReference(&downloadUrlPath); PhClearReference(&userAgentString); diff --git a/plugins/NetworkTools/update.c b/plugins/NetworkTools/update.c index f57bd05db5ba..45a2db920356 100644 --- a/plugins/NetworkTools/update.c +++ b/plugins/NetworkTools/update.c @@ -289,13 +289,9 @@ NTSTATUS GeoIPUpdateThread( HINTERNET httpConnectionHandle = NULL; HINTERNET httpRequestHandle = NULL; PPH_STRING fwLinkUrl = NULL; - PPH_STRING setupTempPath = NULL; PPH_STRING downloadHostPath = NULL; PPH_STRING downloadUrlPath = NULL; - PPH_STRING fullSetupPath = NULL; - PPH_STRING randomGuidString = NULL; - ULONG indexOfFileName = -1; - GUID randomGuid; + PPH_STRING directoryPath = NULL; URL_COMPONENTS httpUrlComponents = { sizeof(URL_COMPONENTS) }; LARGE_INTEGER timeNow; LARGE_INTEGER timeStart; @@ -309,42 +305,9 @@ NTSTATUS GeoIPUpdateThread( if (!(fwLinkUrl = QueryFwLinkUrl(context))) goto CleanupExit; - setupTempPath = PhCreateStringEx(NULL, GetTempPath(0, NULL) * sizeof(WCHAR)); - if (GetTempPath((ULONG)setupTempPath->Length / sizeof(WCHAR), setupTempPath->Buffer) == 0) + context->SetupFilePath = PhGetCacheFileName(PhaCreateString(L"GeoLite2-Country.mmdb.gz")); + if (PhIsNullOrEmptyString(context->SetupFilePath)) goto CleanupExit; - if (PhIsNullOrEmptyString(setupTempPath)) - goto CleanupExit; - - // Generate random guid for our directory path - PhGenerateGuid(&randomGuid); - - if (randomGuidString = PhFormatGuid(&randomGuid)) - { - PhMoveReference(&randomGuidString, PhSubstring(randomGuidString, 1, randomGuidString->Length / sizeof(WCHAR) - 2)); - } - - // Append the tempath to our string: %TEMP%RandomString\\GeoLite2-Country.mmdb.gz - // Example: C:\\Users\\dmex\\AppData\\Temp\\ABCD\\GeoLite2-Country.mmdb.gz - context->SetupFilePath = PhFormatString( - L"%s\\%s\\GeoLite2-Country.mmdb.gz", - PhGetStringOrEmpty(setupTempPath), - PhGetStringOrDefault(randomGuidString, L"NetworkTools") - ); - - // Create the directory if it does not exist - if (fullSetupPath = PhGetFullPath(PhGetString(context->SetupFilePath), &indexOfFileName)) - { - PPH_STRING directoryPath; - - if (indexOfFileName == -1) - goto CleanupExit; - - if (directoryPath = PhSubstring(fullSetupPath, 0, indexOfFileName)) - { - SHCreateDirectoryEx(NULL, directoryPath->Buffer, NULL); - PhDereferenceObject(directoryPath); - } - } // Create output file if (!NT_SUCCESS(PhCreateFileWin32( @@ -555,79 +518,71 @@ NTSTATUS GeoIPUpdateThread( } } - PPH_STRING path; - PPH_STRING fullSetupPath; - PPH_BYTES mmdbGzPath; - gzFile file; - - path = PH_AUTO(PhGetKnownLocation(CSIDL_APPDATA, L"\\Process Hacker\\GeoLite2-Country.mmdb")); - mmdbGzPath = PhConvertUtf16ToUtf8(PhGetString(context->SetupFilePath)); - - if (RtlDoesFileExists_U(PhGetString(path))) { - if (!NT_SUCCESS(PhDeleteFileWin32(PhGetString(path)))) - { - goto CleanupExit; - } - } + PPH_STRING gzpath; + PPH_BYTES mmdbGzPath; + gzFile gzfile; - if (fullSetupPath = PhGetFullPath(PhGetString(path), &indexOfFileName)) - { - PPH_STRING directoryPath; + gzpath = PH_AUTO(PhGetKnownLocation(CSIDL_APPDATA, L"\\Process Hacker\\GeoLite2-Country.mmdb")); + mmdbGzPath = PH_AUTO(PhConvertUtf16ToUtf8(PhGetString(context->SetupFilePath))); - if (directoryPath = PhSubstring(fullSetupPath, 0, indexOfFileName)) + if (RtlDoesFileExists_U(PhGetString(gzpath))) { - SHCreateDirectoryEx(NULL, directoryPath->Buffer, NULL); - PhDereferenceObject(directoryPath); + if (!NT_SUCCESS(PhDeleteFileWin32(PhGetString(gzpath)))) + goto CleanupExit; } - } - if (file = gzopen(mmdbGzPath->Buffer, "rb")) - { - HANDLE mmdbFileHandle; - - if (NT_SUCCESS(PhCreateFileWin32( - &mmdbFileHandle, - PhGetStringOrEmpty(path), - FILE_GENERIC_READ | FILE_GENERIC_WRITE, - FILE_ATTRIBUTE_NOT_CONTENT_INDEXED | FILE_ATTRIBUTE_TEMPORARY, - FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, - FILE_OVERWRITE_IF, - FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT - ))) + if (gzfile = gzopen(mmdbGzPath->Buffer, "rb")) { - IO_STATUS_BLOCK isb; - BYTE buffer[PAGE_SIZE]; - - while (!gzeof(file)) + HANDLE mmdbFileHandle; + + if (NT_SUCCESS(PhCreateFileWin32( + &mmdbFileHandle, + PhGetStringOrEmpty(gzpath), + FILE_GENERIC_READ | FILE_GENERIC_WRITE, + FILE_ATTRIBUTE_NOT_CONTENT_INDEXED | FILE_ATTRIBUTE_TEMPORARY, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + FILE_OVERWRITE_IF, + FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT + ))) { - int bytes = gzread(file, buffer, sizeof(buffer)); - - if (bytes == -1) - goto CleanupExit; - - if (!NT_SUCCESS(NtWriteFile( - mmdbFileHandle, - NULL, - NULL, - NULL, - &isb, - buffer, - bytes, - NULL, - NULL - ))) + IO_STATUS_BLOCK isb; + BYTE buffer[PAGE_SIZE]; + + while (!gzeof(gzfile)) { - goto CleanupExit; + INT bytes = gzread(gzfile, buffer, sizeof(buffer)); + + if (bytes == -1) + { + NtClose(mmdbFileHandle); + goto CleanupExit; + } + + if (!NT_SUCCESS(NtWriteFile( + mmdbFileHandle, + NULL, + NULL, + NULL, + &isb, + buffer, + bytes, + NULL, + NULL + ))) + { + NtClose(mmdbFileHandle); + goto CleanupExit; + } } - } - success = TRUE; + success = TRUE; - NtClose(mmdbFileHandle); - } + NtClose(mmdbFileHandle); + } - gzclose(file); + gzclose(gzfile); + } } } @@ -645,10 +600,19 @@ NTSTATUS GeoIPUpdateThread( if (httpSessionHandle) WinHttpCloseHandle(httpSessionHandle); - PhClearReference(&randomGuidString); - PhClearReference(&fullSetupPath); - PhClearReference(&setupTempPath); - PhClearReference(&userAgentString); + if (userAgentString) + PhDereferenceObject(userAgentString); + + if (RtlDoesFileExists_U(PhGetString(context->SetupFilePath))) + { + PhDeleteFileWin32(PhGetString(context->SetupFilePath)); + } + + if (directoryPath) + { + RemoveDirectory(PhGetString(directoryPath)); + PhDereferenceObject(directoryPath); + } if (success) { diff --git a/plugins/OnlineChecks/onlnchk.h b/plugins/OnlineChecks/onlnchk.h index ebd5e33898e5..c7a30d3097ad 100644 --- a/plugins/OnlineChecks/onlnchk.h +++ b/plugins/OnlineChecks/onlnchk.h @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include diff --git a/plugins/OnlineChecks/upload.c b/plugins/OnlineChecks/upload.c index 1e5ca87291cd..4d060c290ff0 100644 --- a/plugins/OnlineChecks/upload.c +++ b/plugins/OnlineChecks/upload.c @@ -810,22 +810,22 @@ NTSTATUS UploadFileThreadStart( goto CleanupExit; } - if (jsonRootObject = CreateJsonParser(buffer)) + if (jsonRootObject = PhCreateJsonParser(buffer)) { - if (!GetJsonValueAsUlong(jsonRootObject, "response_code")) + if (PhGetJsonValueAsLong64(jsonRootObject, "response_code") != 0) goto CleanupExit; - // PhZeroExtendToUtf16(GetJsonValueAsString(jsonRootObject, "resource")); - // PhZeroExtendToUtf16(GetJsonValueAsString(jsonRootObject, "scan_id")); - // PhZeroExtendToUtf16(GetJsonValueAsString(jsonRootObject, "sha256")); - // PhZeroExtendToUtf16(GetJsonValueAsString(jsonRootObject, "verbose_msg")); + // PhZeroExtendToUtf16(PhGetJsonValueAsString(jsonRootObject, "resource")); + // PhZeroExtendToUtf16(PhGetJsonValueAsString(jsonRootObject, "scan_id")); + // PhZeroExtendToUtf16(PhGetJsonValueAsString(jsonRootObject, "sha256")); + // PhZeroExtendToUtf16(PhGetJsonValueAsString(jsonRootObject, "verbose_msg")); - if (redirectUrl = GetJsonValueAsString(jsonRootObject, "permalink")) + if (redirectUrl = PhGetJsonValueAsString(jsonRootObject, "permalink")) { PhMoveReference(&context->LaunchCommand, PhZeroExtendToUtf16(redirectUrl)); } - CleanupJsonParser(jsonRootObject); + PhFreeJsonParser(jsonRootObject); } else { @@ -859,14 +859,14 @@ NTSTATUS UploadFileThreadStart( goto CleanupExit; } - if (rootJsonObject = CreateJsonParser(buffer)) + if (rootJsonObject = PhCreateJsonParser(buffer)) { - if (redirectUrl = GetJsonValueAsString(rootJsonObject, "redirecturl")) + if (redirectUrl = PhGetJsonValueAsString(rootJsonObject, "redirecturl")) { PhMoveReference(&context->LaunchCommand, PhFormatString(L"http://virusscan.jotti.org%hs", redirectUrl)); } - CleanupJsonParser(rootJsonObject); + PhFreeJsonParser(rootJsonObject); } } break; @@ -1048,28 +1048,30 @@ NTSTATUS UploadCheckThreadStart( goto CleanupExit; } - if (rootJsonObject = CreateJsonParser(subRequestBuffer->Buffer)) + if (rootJsonObject = PhCreateJsonParser(subRequestBuffer->Buffer)) { - if (context->FileExists = GetJsonValueAsBool(rootJsonObject, "file_exists")) + context->FileExists = PhGetJsonObjectBool(rootJsonObject, "file_exists"); + + if (context->FileExists) { INT64 detected = 0; INT64 detectedMax = 0; PVOID detectionRatio; - if (detectionRatio = JsonGetObject(rootJsonObject, "detection_ratio")) + if (detectionRatio = PhGetJsonObject(rootJsonObject, "detection_ratio")) { - detected = GetJsonArrayUlong(detectionRatio, 0); - detectedMax = GetJsonArrayUlong(detectionRatio, 1); + detected = PhGetJsonArrayLong64(detectionRatio, 0); + detectedMax = PhGetJsonArrayLong64(detectionRatio, 1); } context->Detected = PhFormatString(L"%I64d", detected); context->MaxDetected = PhFormatString(L"%I64d", detectedMax); - context->UploadUrl = PhZeroExtendToUtf16(GetJsonValueAsString(rootJsonObject, "upload_url")); - context->ReAnalyseUrl = PhZeroExtendToUtf16(GetJsonValueAsString(rootJsonObject, "reanalyse_url")); - context->LastAnalysisUrl = PhZeroExtendToUtf16(GetJsonValueAsString(rootJsonObject, "last_analysis_url")); - context->FirstAnalysisDate = PhZeroExtendToUtf16(GetJsonValueAsString(rootJsonObject, "first_analysis_date")); - context->LastAnalysisDate = PhZeroExtendToUtf16(GetJsonValueAsString(rootJsonObject, "last_analysis_date")); - context->LastAnalysisAgo = PhZeroExtendToUtf16(GetJsonValueAsString(rootJsonObject, "last_analysis_ago")); + context->UploadUrl = PhZeroExtendToUtf16(PhGetJsonValueAsString(rootJsonObject, "upload_url")); + context->ReAnalyseUrl = PhZeroExtendToUtf16(PhGetJsonValueAsString(rootJsonObject, "reanalyse_url")); + context->LastAnalysisUrl = PhZeroExtendToUtf16(PhGetJsonValueAsString(rootJsonObject, "last_analysis_url")); + context->FirstAnalysisDate = PhZeroExtendToUtf16(PhGetJsonValueAsString(rootJsonObject, "first_analysis_date")); + context->LastAnalysisDate = PhZeroExtendToUtf16(PhGetJsonValueAsString(rootJsonObject, "last_analysis_date")); + context->LastAnalysisAgo = PhZeroExtendToUtf16(PhGetJsonValueAsString(rootJsonObject, "last_analysis_ago")); PhMoveReference(&context->FirstAnalysisDate, VirusTotalStringToTime(context->FirstAnalysisDate)); PhMoveReference(&context->LastAnalysisDate, VirusTotalStringToTime(context->LastAnalysisDate)); @@ -1106,7 +1108,7 @@ NTSTATUS UploadCheckThreadStart( } else { - context->UploadUrl = PhZeroExtendToUtf16(GetJsonValueAsString(rootJsonObject, "upload_url")); + context->UploadUrl = PhZeroExtendToUtf16(PhGetJsonValueAsString(rootJsonObject, "upload_url")); // No file found... Start the upload. if (!PhIsNullOrEmptyString(context->UploadUrl)) @@ -1116,7 +1118,7 @@ NTSTATUS UploadCheckThreadStart( } } - CleanupJsonParser(rootJsonObject); + PhFreeJsonParser(rootJsonObject); } } break; diff --git a/plugins/OnlineChecks/virustotal.c b/plugins/OnlineChecks/virustotal.c index a32907038f96..0a93f6e81a92 100644 --- a/plugins/OnlineChecks/virustotal.c +++ b/plugins/OnlineChecks/virustotal.c @@ -211,7 +211,7 @@ PPH_LIST VirusTotalJsonToResultList( ULONG arrayLength; PPH_LIST results; - if (!(arrayLength = JsonGetArrayLength(JsonObject))) + if (!(arrayLength = PhGetJsonArrayLength(JsonObject))) return NULL; results = PhCreateList(arrayLength); @@ -222,17 +222,17 @@ PPH_LIST VirusTotalJsonToResultList( PVOID jsonArrayObject; PSTR fileHash; - if (!(jsonArrayObject = JsonGetObjectArrayIndex(JsonObject, i))) + if (!(jsonArrayObject = PhGetJsonArrayIndexObject(JsonObject, i))) continue; result = PhAllocate(sizeof(VIRUSTOTAL_API_RESULT)); memset(result, 0, sizeof(VIRUSTOTAL_API_RESULT)); - fileHash = GetJsonValueAsString(jsonArrayObject, "hash"); - result->Found = GetJsonValueAsBool(jsonArrayObject, "found") == TRUE; - result->Positives = GetJsonValueAsUlong(jsonArrayObject, "positives"); - result->Total = GetJsonValueAsUlong(jsonArrayObject, "total"); + fileHash = PhGetJsonValueAsString(jsonArrayObject, "hash"); result->FileHash = fileHash ? PhZeroExtendToUtf16(fileHash) : NULL; + result->Found = PhGetJsonObjectBool(jsonArrayObject, "found") == TRUE; + result->Positives = PhGetJsonValueAsLong64(jsonArrayObject, "positives"); + result->Total = PhGetJsonValueAsLong64(jsonArrayObject, "total"); PhAddItemList(results, result); } @@ -279,13 +279,13 @@ VOID VirusTotalBuildJsonArray( Entry->FileHash = hashString; Entry->FileHashAnsi = PhConvertUtf16ToMultiByte(Entry->FileHash->Buffer); - entry = CreateJsonObject(); - JsonAddObject(entry, "autostart_location", ""); - JsonAddObject(entry, "autostart_entry", ""); - JsonAddObject(entry, "hash", Entry->FileHashAnsi->Buffer); - JsonAddObject(entry, "image_path", Entry->FileNameAnsi->Buffer); - JsonAddObject(entry, "creation_datetime", Entry->CreationTime ? Entry->CreationTime->Buffer : ""); - JsonArrayAddObject(JsonArray, entry); + entry = PhCreateJsonObject(); + PhAddJsonObject(entry, "autostart_location", ""); + PhAddJsonObject(entry, "autostart_entry", ""); + PhAddJsonObject(entry, "hash", Entry->FileHashAnsi->Buffer); + PhAddJsonObject(entry, "image_path", Entry->FileNameAnsi->Buffer); + PhAddJsonObject(entry, "creation_datetime", Entry->CreationTime ? Entry->CreationTime->Buffer : ""); + PhAddJsonArrayObject(JsonArray, entry); } NtClose(fileHandle); @@ -585,27 +585,27 @@ PVIRUSTOTAL_FILE_REPORT_RESULT VirusTotalSendHttpFileReportRequest( //PVOID jsonScanObject; PVIRUSTOTAL_FILE_REPORT_RESULT result; - if (!(jsonRootObject = CreateJsonParser(subRequestBuffer))) + if (!(jsonRootObject = PhCreateJsonParser(subRequestBuffer))) goto CleanupExit; - if (!GetJsonValueAsUlong(jsonRootObject, "response_code")) + if (PhGetJsonValueAsLong64(jsonRootObject, "response_code") != 0) goto CleanupExit; result = PhAllocate(sizeof(VIRUSTOTAL_FILE_REPORT_RESULT)); memset(result, 0, sizeof(VIRUSTOTAL_FILE_REPORT_RESULT)); - result->Total = PhFormatUInt64(GetJsonValueAsUlong(jsonRootObject, "total"), FALSE); - result->Positives = PhFormatUInt64(GetJsonValueAsUlong(jsonRootObject, "positives"), FALSE); - result->Resource = PhZeroExtendToUtf16(GetJsonValueAsString(jsonRootObject, "resource")); - result->ScanId = PhZeroExtendToUtf16(GetJsonValueAsString(jsonRootObject, "scan_id")); - result->Md5 = PhZeroExtendToUtf16(GetJsonValueAsString(jsonRootObject, "md5")); - result->Sha1 = PhZeroExtendToUtf16(GetJsonValueAsString(jsonRootObject, "sha1")); - result->Sha256 = PhZeroExtendToUtf16(GetJsonValueAsString(jsonRootObject, "sha256")); - result->ScanDate = PhZeroExtendToUtf16(GetJsonValueAsString(jsonRootObject, "scan_date")); - result->Permalink = PhZeroExtendToUtf16(GetJsonValueAsString(jsonRootObject, "permalink")); - result->StatusMessage = PhZeroExtendToUtf16(GetJsonValueAsString(jsonRootObject, "verbose_msg")); - - //if (jsonScanObject = JsonGetObject(jsonRootObject, "scans")) + result->Total = PhFormatUInt64(PhGetJsonValueAsLong64(jsonRootObject, "total"), FALSE); + result->Positives = PhFormatUInt64(PhGetJsonValueAsLong64(jsonRootObject, "positives"), FALSE); + result->Resource = PhZeroExtendToUtf16(PhGetJsonValueAsString(jsonRootObject, "resource")); + result->ScanId = PhZeroExtendToUtf16(PhGetJsonValueAsString(jsonRootObject, "scan_id")); + result->Md5 = PhZeroExtendToUtf16(PhGetJsonValueAsString(jsonRootObject, "md5")); + result->Sha1 = PhZeroExtendToUtf16(PhGetJsonValueAsString(jsonRootObject, "sha1")); + result->Sha256 = PhZeroExtendToUtf16(PhGetJsonValueAsString(jsonRootObject, "sha256")); + result->ScanDate = PhZeroExtendToUtf16(PhGetJsonValueAsString(jsonRootObject, "scan_date")); + result->Permalink = PhZeroExtendToUtf16(PhGetJsonValueAsString(jsonRootObject, "permalink")); + result->StatusMessage = PhZeroExtendToUtf16(PhGetJsonValueAsString(jsonRootObject, "verbose_msg")); + + //if (jsonScanObject = PhGetJsonObject(jsonRootObject, "scans")) //{ // PPH_LIST jsonArrayList; // @@ -617,9 +617,9 @@ PVIRUSTOTAL_FILE_REPORT_RESULT VirusTotalSendHttpFileReportRequest( // { // PJSON_ARRAY_LIST_OBJECT object = jsonArrayList->Items[i]; // //BOOLEAN detected = GetJsonValueAsBool(object->Entry, "detected") == TRUE; - // //PSTR version = GetJsonValueAsString(object->Entry, "version"); - // //PSTR result = GetJsonValueAsString(object->Entry, "result"); - // //PSTR update = GetJsonValueAsString(object->Entry, "update"); + // //PSTR version = PhGetJsonValueAsString(object->Entry, "version"); + // //PSTR result = PhGetJsonValueAsString(object->Entry, "result"); + // //PSTR update = PhGetJsonValueAsString(object->Entry, "update"); // // PhFree(object); // } @@ -659,7 +659,7 @@ NTSTATUS NTAPI VirusTotalProcessApiThread( PPH_LIST resultTempList = NULL; PPH_LIST virusTotalResults = NULL; - jsonArray = CreateJsonArray(); + jsonArray = PhCreateJsonArray(); resultTempList = PhCreateList(30); PhAcquireQueuedLockExclusive(&ProcessListLock); @@ -692,19 +692,19 @@ NTSTATUS NTAPI VirusTotalProcessApiThread( VirusTotalBuildJsonArray(resultTempList->Items[i], jsonArray); } - if (!(jsonArrayToSendString = GetJsonArrayString(jsonArray))) + if (!(jsonArrayToSendString = PhGetJsonArrayString(jsonArray))) goto CleanupExit; if (!(jsonApiResult = VirusTotalSendHttpRequest(PhCreateBytes(jsonArrayToSendString)))) goto CleanupExit; - if (!(rootJsonObject = CreateJsonParser(jsonApiResult))) + if (!(rootJsonObject = PhCreateJsonParser(jsonApiResult))) goto CleanupExit; - if (!(dataJsonObject = JsonGetObject(rootJsonObject, "data"))) + if (!(dataJsonObject = PhGetJsonObject(rootJsonObject, "data"))) goto CleanupExit; - if (!(resultLength = GetJsonValueAsUlong(rootJsonObject, "result"))) + if (!(resultLength = PhGetJsonValueAsLong64(rootJsonObject, "result"))) goto CleanupExit; if (virusTotalResults = VirusTotalJsonToResultList(dataJsonObject)) @@ -758,12 +758,12 @@ NTSTATUS NTAPI VirusTotalProcessApiThread( if (rootJsonObject) { - CleanupJsonParser(rootJsonObject); + PhFreeJsonParser(rootJsonObject); } if (jsonArray) { - CleanupJsonParser(jsonArray); + PhFreeJsonParser(jsonArray); } if (jsonApiResult) diff --git a/plugins/Updater/page3.c b/plugins/Updater/page3.c index c5fe5c051573..40cda4253452 100644 --- a/plugins/Updater/page3.c +++ b/plugins/Updater/page3.c @@ -88,10 +88,8 @@ VOID ShowAvailableDialog( config.pszWindowTitle = L"Process Hacker - Updater"; config.pszMainInstruction = L"A newer build of Process Hacker is available."; - config.pszContent = PhaFormatString(L"Version: %lu.%lu.%lu\r\nDownload size: %s\r\n\r\nView Changelog", - Context->MajorVersion, - Context->MinorVersion, - Context->RevisionVersion, + config.pszContent = PhaFormatString(L"Version: %s\r\nDownload size: %s\r\n\r\nView Changelog", + PhGetStringOrEmpty(Context->Version), PhGetStringOrEmpty(Context->Size) )->Buffer; diff --git a/plugins/Updater/page4.c b/plugins/Updater/page4.c index a8df5182aaa4..8c29f12be712 100644 --- a/plugins/Updater/page4.c +++ b/plugins/Updater/page4.c @@ -70,11 +70,7 @@ VOID ShowProgressDialog( config.pfCallback = ShowProgressCallbackProc; config.pszWindowTitle = L"Process Hacker - Updater"; - config.pszMainInstruction = PhaFormatString(L"Downloading update %lu.%lu.%lu...", - Context->MajorVersion, - Context->MinorVersion, - Context->RevisionVersion - )->Buffer; + config.pszMainInstruction = PhaFormatString(L"Downloading update %s...", PhGetStringOrEmpty(Context->Version))->Buffer; config.pszContent = L"Downloaded: ~ of ~ (0%)\r\nSpeed: ~ KB/s"; SendMessage(Context->DialogHandle, TDM_NAVIGATE_PAGE, 0, (LPARAM)&config); diff --git a/plugins/Updater/updater.c b/plugins/Updater/updater.c index 98956efd01df..1e5c29dd70f1 100644 --- a/plugins/Updater/updater.c +++ b/plugins/Updater/updater.c @@ -227,14 +227,14 @@ PPH_STRING UpdateWindowsString( return buildLabHeader; } -BOOLEAN ParseVersionString( - _Inout_ PPH_UPDATER_CONTEXT Context +ULONG64 ParseVersionString( + _Inout_ PPH_STRING VersionString ) { PH_STRINGREF remaining, majorPart, minorPart, revisionPart; ULONG64 majorInteger = 0, minorInteger = 0, revisionInteger = 0; - PhInitializeStringRef(&remaining, PhGetStringOrEmpty(Context->Version)); + PhInitializeStringRef(&remaining, PhGetString(VersionString)); PhSplitStringRefAtChar(&remaining, '.', &majorPart, &remaining); PhSplitStringRefAtChar(&remaining, '.', &minorPart, &remaining); @@ -244,10 +244,12 @@ BOOLEAN ParseVersionString( PhStringToInteger64(&minorPart, 10, &minorInteger); PhStringToInteger64(&revisionPart, 10, &revisionInteger); - Context->MajorVersion = (ULONG)majorInteger; - Context->MinorVersion = (ULONG)minorInteger; - Context->RevisionVersion = (ULONG)revisionInteger; - return TRUE; + return MAKE_VERSION_ULONGLONG( + (ULONG)majorInteger, + (ULONG)minorInteger, + (ULONG)revisionInteger, + 0 + ); } BOOLEAN ReadRequestString( @@ -414,50 +416,32 @@ BOOLEAN QueryUpdateData( if (!ReadRequestString(httpRequestHandle, &stringBuffer, &stringBufferLength)) goto CleanupExit; - // Check the buffer for valid data if (stringBuffer == NULL || stringBuffer[0] == '\0') goto CleanupExit; - if (!(jsonObject = CreateJsonParser(stringBuffer))) + if (!(jsonObject = PhCreateJsonParser(stringBuffer))) goto CleanupExit; - Context->Size = PhFormatSize(GetJsonValueAsUlong(jsonObject, "size"), 2); - if (tempValue = GetJsonValueAsString(jsonObject, "version")) + Context->Size = PhFormatSize(PhGetJsonValueAsLong64(jsonObject, "size"), 2); + if (tempValue = PhGetJsonValueAsString(jsonObject, "version")) { Context->Version = PhConvertUtf8ToUtf16(tempValue); Context->RevVersion = PhConvertUtf8ToUtf16(tempValue); } - if (tempValue = GetJsonValueAsString(jsonObject, "updated")) + if (tempValue = PhGetJsonValueAsString(jsonObject, "updated")) Context->RelDate = PhConvertUtf8ToUtf16(tempValue); - if (tempValue = GetJsonValueAsString(jsonObject, "hash_setup")) + if (tempValue = PhGetJsonValueAsString(jsonObject, "hash_setup")) Context->Hash = PhConvertUtf8ToUtf16(tempValue); - if (tempValue = GetJsonValueAsString(jsonObject, "sig")) + if (tempValue = PhGetJsonValueAsString(jsonObject, "sig")) Context->Signature = PhConvertUtf8ToUtf16(tempValue); - if (tempValue = GetJsonValueAsString(jsonObject, "forum_url")) + if (tempValue = PhGetJsonValueAsString(jsonObject, "forum_url")) Context->ReleaseNotesUrl = PhConvertUtf8ToUtf16(tempValue); - if (tempValue = GetJsonValueAsString(jsonObject, "setup_url")) + if (tempValue = PhGetJsonValueAsString(jsonObject, "setup_url")) Context->SetupFileDownloadUrl = PhConvertUtf8ToUtf16(tempValue); - if (tempValue = GetJsonValueAsString(jsonObject, "changelog")) + if (tempValue = PhGetJsonValueAsString(jsonObject, "changelog")) Context->BuildMessage = PhConvertUtf8ToUtf16(tempValue); - if (!PhIsNullOrEmptyString(Context->BuildMessage)) - { - PH_STRING_BUILDER sb; - - PhInitializeStringBuilder(&sb, 0x100); - - for (SIZE_T i = 0; i < Context->BuildMessage->Length / sizeof(WCHAR); i++) - { - if (Context->BuildMessage->Data[i] == '\n') - PhAppendStringBuilder2(&sb, L"\r\n"); - else - PhAppendCharStringBuilder(&sb, Context->BuildMessage->Data[i]); - } - - PhMoveReference(&Context->BuildMessage, PhFinalStringBuilderString(&sb)); - } - - CleanupJsonParser(jsonObject); + PhFreeJsonParser(jsonObject); if (PhIsNullOrEmptyString(Context->Version)) goto CleanupExit; @@ -475,8 +459,7 @@ BOOLEAN QueryUpdateData( goto CleanupExit; if (PhIsNullOrEmptyString(Context->Signature)) goto CleanupExit; - - if (!ParseVersionString(Context)) + if (PhIsNullOrEmptyString(Context->BuildMessage)) goto CleanupExit; success = TRUE; @@ -501,6 +484,23 @@ BOOLEAN QueryUpdateData( PhClearReference(&versionHeader); PhClearReference(&windowsHeader); + if (!PhIsNullOrEmptyString(Context->BuildMessage)) + { + PH_STRING_BUILDER sb; + + PhInitializeStringBuilder(&sb, 0x100); + + for (SIZE_T i = 0; i < Context->BuildMessage->Length / sizeof(WCHAR); i++) + { + if (Context->BuildMessage->Data[i] == '\n') + PhAppendStringBuilder2(&sb, L"\r\n"); + else + PhAppendCharStringBuilder(&sb, Context->BuildMessage->Data[i]); + } + + PhMoveReference(&Context->BuildMessage, PhFinalStringBuilderString(&sb)); + } + return success; } @@ -536,12 +536,7 @@ NTSTATUS UpdateCheckSilentThread( 0 ); #else - latestVersion = MAKE_VERSION_ULONGLONG( - context->MajorVersion, - context->MinorVersion, - context->RevisionVersion, - 0 - ); + latestVersion = ParseVersionString(context->Version); #endif // Compare the current version against the latest available version @@ -609,12 +604,7 @@ NTSTATUS UpdateCheckThread( 0 ); #else - latestVersion = MAKE_VERSION_ULONGLONG( - context->MajorVersion, - context->MinorVersion, - context->RevisionVersion, - 0 - ); + latestVersion = ParseVersionString(context->Version); #endif if (currentVersion == latestVersion) @@ -637,6 +627,25 @@ NTSTATUS UpdateCheckThread( return STATUS_SUCCESS; } +static PPH_STRING UpdaterParseDownloadFileName( + _In_ PPH_STRING DownloadUrlPath + ) +{ + PH_STRINGREF pathPart; + PH_STRINGREF baseNamePart; + PPH_STRING filePath; + PPH_STRING downloadFileName; + + if (!PhSplitStringRefAtLastChar(&DownloadUrlPath->sr, '/', &pathPart, &baseNamePart)) + return NULL; + + downloadFileName = PhCreateString2(&baseNamePart); + filePath = PhGetCacheFileName(downloadFileName); + PhDereferenceObject(downloadFileName); + + return filePath; +} + NTSTATUS UpdateDownloadThread( _In_ PVOID Parameter ) @@ -648,16 +657,11 @@ NTSTATUS UpdateDownloadThread( HINTERNET httpSessionHandle = NULL; HINTERNET httpConnectionHandle = NULL; HINTERNET httpRequestHandle = NULL; - PPH_STRING setupTempPath = NULL; PPH_STRING downloadHostPath = NULL; PPH_STRING downloadUrlPath = NULL; PPH_STRING userAgentString = NULL; - PPH_STRING fullSetupPath = NULL; - PPH_STRING randomGuidString = NULL; PUPDATER_HASH_CONTEXT hashContext = NULL; - ULONG indexOfFileName = -1; - GUID randomGuid; - URL_COMPONENTS httpUrlComponents = { sizeof(URL_COMPONENTS) }; + URL_COMPONENTS httpParts = { sizeof(URL_COMPONENTS) }; LARGE_INTEGER timeNow; LARGE_INTEGER timeStart; ULONG64 timeTicks = 0; @@ -673,57 +677,43 @@ NTSTATUS UpdateDownloadThread( context->CurrentMinorVersion, context->CurrentRevisionVersion ); + if (PhIsNullOrEmptyString(userAgentString)) goto CleanupExit; - setupTempPath = PhCreateStringEx(NULL, GetTempPath(0, NULL) * sizeof(WCHAR)); - if (PhIsNullOrEmptyString(setupTempPath)) - goto CleanupExit; + // Set lengths to non-zero enabling these params to be cracked. + httpParts.dwSchemeLength = (ULONG)-1; + httpParts.dwHostNameLength = (ULONG)-1; + httpParts.dwUrlPathLength = (ULONG)-1; - if (GetTempPath((ULONG)setupTempPath->Length / sizeof(WCHAR), setupTempPath->Buffer) == 0) - goto CleanupExit; - if (PhIsNullOrEmptyString(setupTempPath)) + if (!WinHttpCrackUrl( + PhGetStringOrEmpty(context->SetupFileDownloadUrl), + 0, + 0, + &httpParts + )) + { + context->ErrorCode = GetLastError(); goto CleanupExit; + } - // Generate random guid for our directory path. - PhGenerateGuid(&randomGuid); - - if (randomGuidString = PhFormatGuid(&randomGuid)) - { - PPH_STRING guidSubString; + // Create the Host string. + downloadHostPath = PhCreateStringEx(httpParts.lpszHostName, httpParts.dwHostNameLength * sizeof(WCHAR)); - // Strip the left and right curly brackets. - guidSubString = PhSubstring(randomGuidString, 1, randomGuidString->Length / sizeof(WCHAR) - 2); + if (PhIsNullOrEmptyString(downloadHostPath)) + goto CleanupExit; - PhMoveReference(&randomGuidString, guidSubString); - } + // Create the remote path string. + downloadUrlPath = PhCreateStringEx(httpParts.lpszUrlPath, httpParts.dwUrlPathLength * sizeof(WCHAR)); - // Append the tempath to our string: %TEMP%RandomString\\processhacker-%lu.%lu-setup.exe - // Example: C:\\Users\\dmex\\AppData\\Temp\\ABCD\\processhacker-2.90-setup.exe - context->SetupFilePath = PhFormatString( - L"%s%s\\processhacker-%lu.%lu-setup.exe", - PhGetStringOrEmpty(setupTempPath), - PhGetStringOrEmpty(randomGuidString), - context->MajorVersion, - context->MinorVersion - ); - if (PhIsNullOrEmptyString(context->SetupFilePath)) + if (PhIsNullOrEmptyString(downloadUrlPath)) goto CleanupExit; - // Create the directory if it does not exist. - if (fullSetupPath = PhGetFullPath(PhGetString(context->SetupFilePath), &indexOfFileName)) - { - PPH_STRING directoryPath; - - if (indexOfFileName == -1) - goto CleanupExit; + // Create the local path string. + context->SetupFilePath = UpdaterParseDownloadFileName(downloadUrlPath); - if (directoryPath = PhSubstring(fullSetupPath, 0, indexOfFileName)) - { - SHCreateDirectoryEx(NULL, directoryPath->Buffer, NULL); - PhDereferenceObject(directoryPath); - } - } + if (PhIsNullOrEmptyString(context->SetupFilePath)) + goto CleanupExit; // Create output file if (!NT_SUCCESS(PhCreateFileWin32( @@ -739,38 +729,6 @@ NTSTATUS UpdateDownloadThread( goto CleanupExit; } - // Set lengths to non-zero enabling these params to be cracked. - httpUrlComponents.dwSchemeLength = (ULONG)-1; - httpUrlComponents.dwHostNameLength = (ULONG)-1; - httpUrlComponents.dwUrlPathLength = (ULONG)-1; - - if (!WinHttpCrackUrl( - PhGetStringOrEmpty(context->SetupFileDownloadUrl), - 0, - 0, - &httpUrlComponents - )) - { - context->ErrorCode = GetLastError(); - goto CleanupExit; - } - - // Create the Host string. - downloadHostPath = PhCreateStringEx( - httpUrlComponents.lpszHostName, - httpUrlComponents.dwHostNameLength * sizeof(WCHAR) - ); - if (PhIsNullOrEmptyString(downloadHostPath)) - goto CleanupExit; - - // Create the Path string. - downloadUrlPath = PhCreateStringEx( - httpUrlComponents.lpszUrlPath, - httpUrlComponents.dwUrlPathLength * sizeof(WCHAR) - ); - if (PhIsNullOrEmptyString(downloadUrlPath)) - goto CleanupExit; - SendMessage(context->DialogHandle, TDM_UPDATE_ELEMENT_TEXT, TDE_MAIN_INSTRUCTION, (LPARAM)L"Connecting..."); // Open the HTTP session with the system proxy configuration if available @@ -799,7 +757,7 @@ NTSTATUS UpdateDownloadThread( if (!(httpConnectionHandle = WinHttpConnect( httpSessionHandle, PhGetString(downloadHostPath), - httpUrlComponents.nScheme == INTERNET_SCHEME_HTTP ? INTERNET_DEFAULT_HTTP_PORT : INTERNET_DEFAULT_HTTPS_PORT, + httpParts.nScheme == INTERNET_SCHEME_HTTP ? INTERNET_DEFAULT_HTTP_PORT : INTERNET_DEFAULT_HTTPS_PORT, 0 ))) { @@ -814,7 +772,7 @@ NTSTATUS UpdateDownloadThread( NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, - WINHTTP_FLAG_REFRESH | (httpUrlComponents.nScheme == INTERNET_SCHEME_HTTPS ? WINHTTP_FLAG_SECURE : 0) + WINHTTP_FLAG_REFRESH | (httpParts.nScheme == INTERNET_SCHEME_HTTPS ? WINHTTP_FLAG_SECURE : 0) ))) { context->ErrorCode = GetLastError(); @@ -861,11 +819,7 @@ NTSTATUS UpdateDownloadThread( IO_STATUS_BLOCK isb; BYTE buffer[PAGE_SIZE]; - status = PhFormatString(L"Downloading update %lu.%lu.%lu...", - context->MajorVersion, - context->MinorVersion, - context->RevisionVersion - ); + status = PhFormatString(L"Downloading update %s...", PhGetStringOrEmpty(context->Version)); SendMessage(context->DialogHandle, TDM_SET_MARQUEE_PROGRESS_BAR, FALSE, 0); SendMessage(context->DialogHandle, TDM_UPDATE_ELEMENT_TEXT, TDE_MAIN_INSTRUCTION, (LPARAM)status->Buffer); @@ -995,12 +949,14 @@ NTSTATUS UpdateDownloadThread( if (httpSessionHandle) WinHttpCloseHandle(httpSessionHandle); - PhClearReference(&randomGuidString); - PhClearReference(&fullSetupPath); - PhClearReference(&setupTempPath); - PhClearReference(&downloadHostPath); - PhClearReference(&downloadUrlPath); - PhClearReference(&userAgentString); + if (downloadHostPath) + PhDereferenceObject(downloadHostPath); + + if (downloadUrlPath) + PhDereferenceObject(downloadUrlPath); + + if (userAgentString) + WinHttpCloseHandle(userAgentString); if (UpdateDialogThreadHandle) { diff --git a/plugins/Updater/updater.h b/plugins/Updater/updater.h index ae1d6e5e9f46..d4bf4abda0aa 100644 --- a/plugins/Updater/updater.h +++ b/plugins/Updater/updater.h @@ -2,7 +2,7 @@ * Process Hacker Plugins - * Update Checker Plugin * - * Copyright (C) 2011-2015 dmex + * Copyright (C) 2011-2017 dmex * * This file is part of Process Hacker. * @@ -28,10 +28,11 @@ #define INITGUID #include #include -#include -#include +#include #include +#include #include +#include #include #include @@ -88,9 +89,6 @@ typedef struct _PH_UPDATER_CONTEXT HWND DialogHandle; ULONG ErrorCode; - ULONG MinorVersion; - ULONG MajorVersion; - ULONG RevisionVersion; ULONG CurrentMinorVersion; ULONG CurrentMajorVersion; ULONG CurrentRevisionVersion; @@ -174,6 +172,10 @@ BOOLEAN UpdaterInstalledUsingSetup( VOID ); +ULONG64 ParseVersionString( + _Inout_ PPH_STRING VersionString + ); + // options.c VOID ShowOptionsDialog( diff --git a/plugins/include/commonutil.h b/plugins/include/commonutil.h index c5511468865c..70040158bdf9 100644 --- a/plugins/include/commonutil.h +++ b/plugins/include/commonutil.h @@ -27,468 +27,11 @@ #define COMMONUTIL_PLUGIN_NAME L"ProcessHacker.CommonUtil" #define COMMONUTIL_INTERFACE_VERSION 1 -typedef PVOID (NTAPI *PUTIL_CREATE_JSON_PARSER)( - _In_ PSTR JsonString - ); - -typedef VOID (NTAPI *PUTIL_CLEANUP_JSON_PARSER)( - _In_ PVOID Object - ); - -typedef PSTR (NTAPI *PUTIL_GET_JSON_VALUE_STRING)( - _In_ PVOID Object, - _In_ PSTR Key - ); - -typedef INT64 (NTAPI *PUTIL_GET_JSON_VALUE_INT64)( - _In_ PVOID Object, - _In_ PSTR Key - ); - -typedef PVOID (NTAPI *PUTIL_CREATE_JSON_OBJECT)( - VOID - ); - -typedef PVOID (NTAPI *PUTIL_GET_JSON_OBJECT)( - _In_ PVOID Object, - _In_ PSTR Key - ); - -typedef INT (NTAPI *PUTIL_GET_JSON_OBJECT_LENGTH)( - _In_ PVOID Object - ); - -typedef BOOL (NTAPI *PUTIL_GET_JSON_OBJECT_BOOL)( - _In_ PVOID Object, - _In_ PSTR Key - ); - -typedef VOID (NTAPI *PUTIL_ADD_JSON_OBJECT_VALUE)( - _In_ PVOID Object, - _In_ PVOID Entry - ); - -typedef PVOID (NTAPI *PUTIL_CREATE_JSON_ARRAY)( - VOID - ); - -typedef VOID (NTAPI *PUTIL_ADD_JSON_ARRAY_VALUE)( - _In_ PVOID Object, - _In_ PSTR Key, - _In_ PSTR Value - ); - -typedef PSTR (NTAPI *PUTIL_GET_JSON_ARRAY_STRING)( - _In_ PVOID Object - ); - -typedef INT64 (NTAPI *PUTIL_GET_JSON_OBJECT_ARRAY_ULONG)( - _In_ PVOID Object, - _In_ INT Index - ); - -typedef INT (NTAPI *PUTIL_GET_JSON_ARRAY_LENGTH)( - _In_ PVOID Object - ); - -typedef PVOID (NTAPI *PUTIL_GET_JSON_OBJECT_ARRAY_INDEX)( - _In_ PVOID Object, - _In_ INT Index - ); - -typedef struct _JSON_ARRAY_LIST_OBJECT -{ - PSTR Key; - PVOID Entry; -} JSON_ARRAY_LIST_OBJECT, *PJSON_ARRAY_LIST_OBJECT; - -typedef PPH_LIST (NTAPI *PUTIL_GET_JSON_OBJECT_ARRAY_LIST)( - _In_ PVOID Object - ); - typedef struct _COMMONUTIL_INTERFACE { ULONG Version; - PUTIL_CREATE_JSON_PARSER CreateJsonParser; - PUTIL_CLEANUP_JSON_PARSER CleanupJsonParser; - PUTIL_GET_JSON_VALUE_STRING GetJsonValueAsString; - PUTIL_GET_JSON_VALUE_INT64 GetJsonValueAsUlong; - PUTIL_GET_JSON_OBJECT_BOOL GetJsonValueAsBool; - PUTIL_CREATE_JSON_OBJECT CreateJsonObject; - PUTIL_GET_JSON_OBJECT GetJsonObject; - PUTIL_GET_JSON_OBJECT_LENGTH GetJsonObjectLength; - PUTIL_ADD_JSON_ARRAY_VALUE JsonAddObject; - PUTIL_CREATE_JSON_ARRAY CreateJsonArray; - PUTIL_ADD_JSON_OBJECT_VALUE JsonArrayAddObject; - PUTIL_GET_JSON_ARRAY_STRING GetJsonArrayString; - PUTIL_GET_JSON_OBJECT_ARRAY_ULONG GetJsonArrayUlong; - PUTIL_GET_JSON_ARRAY_LENGTH JsonGetArrayLength; - PUTIL_GET_JSON_OBJECT_ARRAY_INDEX JsonGetObjectArrayIndex; - PUTIL_GET_JSON_OBJECT_ARRAY_LIST JsonGetObjectArrayList; } COMMONUTIL_INTERFACE, *P_COMMONUTIL_INTERFACE; -FORCEINLINE -PVOID -CreateJsonParser( - _In_ PSTR JsonString - ) -{ - PPH_PLUGIN toolStatusPlugin; - - if (toolStatusPlugin = PhFindPlugin(COMMONUTIL_PLUGIN_NAME)) - { - P_COMMONUTIL_INTERFACE Interface; - - if (Interface = PhGetPluginInformation(toolStatusPlugin)->Interface) - { - if (Interface->Version <= COMMONUTIL_INTERFACE_VERSION) - { - return Interface->CreateJsonParser(JsonString); - } - } - } - - return NULL; -} - -FORCEINLINE -VOID -CleanupJsonParser( - _In_ PVOID Object - ) -{ - PPH_PLUGIN toolStatusPlugin; - - if (toolStatusPlugin = PhFindPlugin(COMMONUTIL_PLUGIN_NAME)) - { - P_COMMONUTIL_INTERFACE Interface; - - if (Interface = PhGetPluginInformation(toolStatusPlugin)->Interface) - { - if (Interface->Version <= COMMONUTIL_INTERFACE_VERSION) - { - Interface->CleanupJsonParser(Object); - } - } - } -} - -FORCEINLINE -PSTR -GetJsonValueAsString( - _In_ PVOID Object, - _In_ PSTR Key - ) -{ - PPH_PLUGIN toolStatusPlugin; - - if (toolStatusPlugin = PhFindPlugin(COMMONUTIL_PLUGIN_NAME)) - { - P_COMMONUTIL_INTERFACE Interface; - - if (Interface = PhGetPluginInformation(toolStatusPlugin)->Interface) - { - if (Interface->Version <= COMMONUTIL_INTERFACE_VERSION) - { - return Interface->GetJsonValueAsString(Object, Key); - } - } - } - - return NULL; -} - -FORCEINLINE -INT64 -GetJsonValueAsUlong( - _In_ PVOID Object, - _In_ PSTR Key - ) -{ - PPH_PLUGIN toolStatusPlugin; - - if (toolStatusPlugin = PhFindPlugin(COMMONUTIL_PLUGIN_NAME)) - { - P_COMMONUTIL_INTERFACE Interface; - - if (Interface = PhGetPluginInformation(toolStatusPlugin)->Interface) - { - if (Interface->Version <= COMMONUTIL_INTERFACE_VERSION) - { - return Interface->GetJsonValueAsUlong(Object, Key); - } - } - } - - return 0; -} - -FORCEINLINE -BOOL -GetJsonValueAsBool( - _In_ PVOID Object, - _In_ PSTR Key - ) -{ - PPH_PLUGIN toolStatusPlugin; - - if (toolStatusPlugin = PhFindPlugin(COMMONUTIL_PLUGIN_NAME)) - { - P_COMMONUTIL_INTERFACE Interface; - - if (Interface = PhGetPluginInformation(toolStatusPlugin)->Interface) - { - if (Interface->Version <= COMMONUTIL_INTERFACE_VERSION) - { - return Interface->GetJsonValueAsBool(Object, Key); - } - } - } - - return FALSE; -} - -FORCEINLINE -PVOID -CreateJsonArray( - VOID - ) -{ - PPH_PLUGIN toolStatusPlugin; - - if (toolStatusPlugin = PhFindPlugin(COMMONUTIL_PLUGIN_NAME)) - { - P_COMMONUTIL_INTERFACE Interface; - - if (Interface = PhGetPluginInformation(toolStatusPlugin)->Interface) - { - if (Interface->Version <= COMMONUTIL_INTERFACE_VERSION) - { - return Interface->CreateJsonArray(); - } - } - } - - return NULL; -} - -FORCEINLINE -PSTR -GetJsonArrayString( - _In_ PVOID Object - ) -{ - PPH_PLUGIN toolStatusPlugin; - - if (toolStatusPlugin = PhFindPlugin(COMMONUTIL_PLUGIN_NAME)) - { - P_COMMONUTIL_INTERFACE Interface; - - if (Interface = PhGetPluginInformation(toolStatusPlugin)->Interface) - { - if (Interface->Version <= COMMONUTIL_INTERFACE_VERSION) - { - return Interface->GetJsonArrayString(Object); - } - } - } - - return NULL; -} - -FORCEINLINE -INT64 -GetJsonArrayUlong( - _In_ PVOID Object, - _In_ INT Index - ) -{ - PPH_PLUGIN toolStatusPlugin; - - if (toolStatusPlugin = PhFindPlugin(COMMONUTIL_PLUGIN_NAME)) - { - P_COMMONUTIL_INTERFACE Interface; - - if (Interface = PhGetPluginInformation(toolStatusPlugin)->Interface) - { - if (Interface->Version <= COMMONUTIL_INTERFACE_VERSION) - { - return Interface->GetJsonArrayUlong(Object, Index); - } - } - } - - return 0; -} - -FORCEINLINE -INT -JsonGetArrayLength( - _In_ PVOID Object - ) -{ - PPH_PLUGIN toolStatusPlugin; - - if (toolStatusPlugin = PhFindPlugin(COMMONUTIL_PLUGIN_NAME)) - { - P_COMMONUTIL_INTERFACE Interface; - - if (Interface = PhGetPluginInformation(toolStatusPlugin)->Interface) - { - if (Interface->Version <= COMMONUTIL_INTERFACE_VERSION) - { - return Interface->JsonGetArrayLength(Object); - } - } - } - - return 0; -} - -FORCEINLINE -PVOID -JsonGetObjectArrayIndex( - _In_ PVOID Object, - _In_ INT Index - ) -{ - PPH_PLUGIN toolStatusPlugin; - - if (toolStatusPlugin = PhFindPlugin(COMMONUTIL_PLUGIN_NAME)) - { - P_COMMONUTIL_INTERFACE Interface; - - if (Interface = PhGetPluginInformation(toolStatusPlugin)->Interface) - { - if (Interface->Version <= COMMONUTIL_INTERFACE_VERSION) - { - return Interface->JsonGetObjectArrayIndex(Object, Index); - } - } - } - - return NULL; -} - -FORCEINLINE -PPH_LIST -JsonGetObjectArrayList( - _In_ PVOID Object - ) -{ - PPH_PLUGIN toolStatusPlugin; - - if (toolStatusPlugin = PhFindPlugin(COMMONUTIL_PLUGIN_NAME)) - { - P_COMMONUTIL_INTERFACE Interface; - - if (Interface = PhGetPluginInformation(toolStatusPlugin)->Interface) - { - if (Interface->Version <= COMMONUTIL_INTERFACE_VERSION) - { - return Interface->JsonGetObjectArrayList(Object); - } - } - } - - return NULL; -} - -FORCEINLINE -PVOID -CreateJsonObject( - VOID - ) -{ - PPH_PLUGIN toolStatusPlugin; - - if (toolStatusPlugin = PhFindPlugin(COMMONUTIL_PLUGIN_NAME)) - { - P_COMMONUTIL_INTERFACE Interface; - - if (Interface = PhGetPluginInformation(toolStatusPlugin)->Interface) - { - if (Interface->Version <= COMMONUTIL_INTERFACE_VERSION) - { - return Interface->CreateJsonObject(); - } - } - } - - return NULL; -} - -FORCEINLINE -PVOID -JsonGetObject( - _In_ PVOID Object, - _In_ PSTR Key - ) -{ - PPH_PLUGIN toolStatusPlugin; - - if (toolStatusPlugin = PhFindPlugin(COMMONUTIL_PLUGIN_NAME)) - { - P_COMMONUTIL_INTERFACE Interface; - - if (Interface = PhGetPluginInformation(toolStatusPlugin)->Interface) - { - if (Interface->Version <= COMMONUTIL_INTERFACE_VERSION) - { - return Interface->GetJsonObject(Object, Key); - } - } - } - - return NULL; -} - -FORCEINLINE -VOID -JsonArrayAddObject( - _In_ PVOID Object, - _In_ PVOID Entry - ) -{ - PPH_PLUGIN toolStatusPlugin; - - if (toolStatusPlugin = PhFindPlugin(COMMONUTIL_PLUGIN_NAME)) - { - P_COMMONUTIL_INTERFACE Interface; - - if (Interface = PhGetPluginInformation(toolStatusPlugin)->Interface) - { - if (Interface->Version <= COMMONUTIL_INTERFACE_VERSION) - { - Interface->JsonArrayAddObject(Object, Entry); - } - } - } -} - -FORCEINLINE -VOID -JsonAddObject( - _In_ PVOID Object, - _In_ PSTR Key, - _In_ PSTR Value - ) -{ - PPH_PLUGIN toolStatusPlugin; - - if (toolStatusPlugin = PhFindPlugin(COMMONUTIL_PLUGIN_NAME)) - { - P_COMMONUTIL_INTERFACE Interface; - - if (Interface = PhGetPluginInformation(toolStatusPlugin)->Interface) - { - if (Interface->Version <= COMMONUTIL_INTERFACE_VERSION) - { - Interface->JsonAddObject(Object, Key, Value); - } - } - } -} FORCEINLINE HICON diff --git a/tools/CustomBuildTool/Source Files/Build.cs b/tools/CustomBuildTool/Source Files/Build.cs index 23ed51105d21..c6a02b535668 100644 --- a/tools/CustomBuildTool/Source Files/Build.cs +++ b/tools/CustomBuildTool/Source Files/Build.cs @@ -45,7 +45,7 @@ public static class Build private static string BuildOutputFolder; private static string BuildCommit; private static string BuildVersion; - private static string BuildWebSetupVersion; + //private static string BuildWebSetupVersion; private static string BuildLongVersion; private static string BuildCount; private static string BuildRevision; @@ -58,9 +58,9 @@ public static class Build private static string BuildSetupHash; private static string BuildSetupSig; - private static long BuildWebSetupFileLength; - private static string BuildWebSetupHash; - private static string BuildWebSetupSig; + //private static long BuildWebSetupFileLength; + //private static string BuildWebSetupHash; + //private static string BuildWebSetupSig; #region Build Config private static readonly string[] sdk_directories = @@ -123,6 +123,7 @@ public static class Build "guisup.h", "hexedit.h", "hndlinfo.h", + "json.h", "kphapi.h", "kphuser.h", "lsasup.h", @@ -696,8 +697,8 @@ public static bool BuildWebSetupExe() try { - var webSetupVersion = System.Diagnostics.FileVersionInfo.GetVersionInfo(BuildOutputFolder + "\\processhacker-build-websetup.exe"); - BuildWebSetupVersion = webSetupVersion.FileVersion.Replace(",", "."); + //var webSetupVersion = System.Diagnostics.FileVersionInfo.GetVersionInfo(BuildOutputFolder + "\\processhacker-build-websetup.exe"); + //BuildWebSetupVersion = webSetupVersion.FileVersion.Replace(",", "."); } catch (Exception ex) { @@ -847,22 +848,22 @@ public static bool BuildChecksumsFile() if (File.Exists(BuildOutputFolder + "\\processhacker-build-checksums.txt")) File.Delete(BuildOutputFolder + "\\processhacker-build-checksums.txt"); - if (File.Exists(BuildOutputFolder + "\\processhacker-build-websetup.exe")) - BuildWebSetupFileLength = new FileInfo(BuildOutputFolder + "\\processhacker-build-websetup.exe").Length; + //if (File.Exists(BuildOutputFolder + "\\processhacker-build-websetup.exe")) + // BuildWebSetupFileLength = new FileInfo(BuildOutputFolder + "\\processhacker-build-websetup.exe").Length; if (File.Exists(BuildOutputFolder + "\\processhacker-build-setup.exe")) BuildSetupFileLength = new FileInfo(BuildOutputFolder + "\\processhacker-build-setup.exe").Length; if (File.Exists(BuildOutputFolder + "\\processhacker-build-bin.zip")) BuildBinFileLength = new FileInfo(BuildOutputFolder + "\\processhacker-build-bin.zip").Length; - if (File.Exists(BuildOutputFolder + "\\processhacker-build-websetup.exe")) - BuildWebSetupHash = Verify.HashFile(BuildOutputFolder + "\\processhacker-build-websetup.exe"); + //if (File.Exists(BuildOutputFolder + "\\processhacker-build-websetup.exe")) + // BuildWebSetupHash = Verify.HashFile(BuildOutputFolder + "\\processhacker-build-websetup.exe"); if (File.Exists(BuildOutputFolder + "\\processhacker-build-setup.exe")) BuildSetupHash = Verify.HashFile(BuildOutputFolder + "\\processhacker-build-setup.exe"); if (File.Exists(BuildOutputFolder + "\\processhacker-build-bin.zip")) BuildBinHash = Verify.HashFile(BuildOutputFolder + "\\processhacker-build-bin.zip"); StringBuilder sb = new StringBuilder(); - sb.AppendLine("processhacker-build-websetup.exe"); - sb.AppendLine("SHA256: " + BuildWebSetupHash + Environment.NewLine); + //sb.AppendLine("processhacker-build-websetup.exe"); + //sb.AppendLine("SHA256: " + BuildWebSetupHash + Environment.NewLine); sb.AppendLine("processhacker-build-setup.exe"); sb.AppendLine("SHA256: " + BuildSetupHash + Environment.NewLine); sb.AppendLine("processhacker-build-bin.zip"); @@ -895,22 +896,12 @@ public static bool BuildUpdateSignature() return true; } - if (!File.Exists(BuildOutputFolder + "\\processhacker-build-websetup.exe")) - { - Program.PrintColorMessage("[SKIPPED] websetup-setup.exe not found.", ConsoleColor.Yellow); - return false; - } - if (!File.Exists(BuildOutputFolder + "\\processhacker-build-setup.exe")) { Program.PrintColorMessage("[SKIPPED] build-setup.exe not found.", ConsoleColor.Yellow); return false; } - BuildWebSetupSig = Win32.ShellExecute( - CustomSignToolPath, - "sign -k build\\nightly.key " + BuildOutputFolder + "\\processhacker-build-websetup.exe -h" - ); BuildSetupSig = Win32.ShellExecute( CustomSignToolPath, "sign -k build\\nightly.key " + BuildOutputFolder + "\\processhacker-build-setup.exe -h" @@ -934,10 +925,6 @@ public static void WebServiceUpdateConfig() return; if (string.IsNullOrEmpty(BuildBinHash)) return; - if (string.IsNullOrEmpty(BuildWebSetupSig)) - return; - if (string.IsNullOrEmpty(BuildWebSetupVersion)) - return; string buildChangelog = Win32.ShellExecute(GitExePath, "log -n 30 --date=format:%Y-%m-%d --pretty=format:\"[%cd] %s (%an)\""); string buildSummary = Win32.ShellExecute(GitExePath, "log -n 5 --date=format:%Y-%m-%d --pretty=format:\"[%cd] %s (%an)\" --abbrev-commit"); @@ -956,10 +943,10 @@ public static void WebServiceUpdateConfig() BinHash = BuildBinHash, //BinSig = BuildBinSig, - WebSetupUrl = "https://ci.appveyor.com/api/projects/processhacker/processhacker2/artifacts/processhacker-" + BuildVersion + "-websetup.exe", - WebSetupHash = BuildWebSetupHash, - WebSetupVersion = BuildWebSetupVersion, - WebSetupSig = BuildWebSetupSig, + //WebSetupUrl = "https://ci.appveyor.com/api/projects/processhacker/processhacker2/artifacts/processhacker-websetup.exe", + //WebSetupHash = BuildWebSetupHash, + //WebSetupVersion = BuildWebSetupVersion, + //WebSetupSig = BuildWebSetupSig, Message = buildSummary, Changelog = buildChangelog, @@ -1006,14 +993,14 @@ public static bool AppveyorUploadBuildFiles() { string[] buildFileArray = { - BuildOutputFolder + "\\processhacker-build-websetup.exe", + //BuildOutputFolder + "\\processhacker-build-websetup.exe", BuildOutputFolder + "\\processhacker-build-setup.exe", BuildOutputFolder + "\\processhacker-build-bin.zip", BuildOutputFolder + "\\processhacker-build-checksums.txt" }; string[] releaseFileArray = { - BuildOutputFolder + "\\processhacker-" + BuildVersion + "-websetup.exe", + //BuildOutputFolder + "\\processhacker-websetup.exe", BuildOutputFolder + "\\processhacker-" + BuildVersion + "-setup.exe", BuildOutputFolder + "\\processhacker-" + BuildVersion + "-bin.zip", BuildOutputFolder + "\\processhacker-" + BuildVersion + "-checksums.txt" diff --git a/tools/CustomBuildTool/Source Files/Program.cs b/tools/CustomBuildTool/Source Files/Program.cs index 05eda6988b8f..572f1a1d682c 100644 --- a/tools/CustomBuildTool/Source Files/Program.cs +++ b/tools/CustomBuildTool/Source Files/Program.cs @@ -226,8 +226,8 @@ public static void Main(string[] args) if (!Build.BuildBinZip()) return; - if (!Build.BuildWebSetupExe()) - return; + //if (!Build.BuildWebSetupExe()) + // return; if (!Build.BuildSetupExe()) return; if (!Build.BuildChecksumsFile()) diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe b/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe index a4a1356fa0497add7d6a45e8608db4a98934ff9f..9571ac2a843046720c3a6d2246eed1203b5e0b9f 100644 GIT binary patch delta 18662 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 R{<%Vasqb_C(en4w{{SQo(8K@$ delta 19275 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 Kxz+Vos{J327W^Fm delta 14505 zcmaKz30xJ`9)M?t3vv;W%SD!pECPb!iVItcqG|3MYOX2bh8pf$sa#D>&5S%MWv(r1 zr6kg#m8NB8X=UpxGcz+Q^O?R^J-6(A|G9G!d{4*U@SXEt&VJ6EIdgTtX>-46+i44k z2-vrDpss0J)Z=gcGk5TzZc9qkw8S4*?JKVx&@eFc)YOxk`)S_=8jXfIs|9tL@%Q>O zFP7yztM7{FWQ6997(F@j_rXnz-0h)iD-TUL6J(F8>2W=x^k&U{ z&j)GR5tZ4jfnHtBuj^F9>)M7kMD{Xw6Ab@dUDKrS@mie2fJ7Z0e@&Y?YDDg+Y11e5 zA2nra!Nfw%(EPM8&Br1BKXXT7m>B5s55wO_{8gRixdTsFWti_x3L^5$v8=Ur(+ehy zG!ySIYm{cDnux(RZt?NjNp3@sJQb!p*BT8D8QaZ&r%@K)2u@j3F^$R(k7 zYp9Q!k1#rgs0%H^I-ja0+KIdv`3deqdimsm6th z{G=7BU8SKlb%a(ioWy58x76_~+E!XX>L{$C9#6@QoIn}ms@zevDAph9`SiiA6P6Z9 z#TAD3V~2{#=J*Opj62vAyHSWeDbzN%1)fZFU!h^(9Vy&5BBH`4b986;AVX{ds%_;4=jIcFQLQA3yO? zA7&;5Nvg$INE1Yas(E+0)bP6kRnz({>b28S%tU{VK*tqYsTzp zDo-c0+qr8a`MOd%%xq72RNGcW(yzR9mW% zh-?+NjJ2MYTvkF!Dp>u}DnSocHCjj261$6*T>%vn|9CYy+o^tU73wSNUa%@?eXpx& zw0LUT3(~dLMalf;M5yDfV}cqIzD`9%jVLImo$8bwT5Bxg4Hb(>^T+nilXJ$PC)W1+W=HFG|Q z1Uk+U?agCXWrn;Q5>O8G8hMRm16#)zaN!z@HO+VzyRsQWQ|<@!QY)NJzmJeI0N=cj^BWl6E}qW_|os zPWzs!ZDW5DM#VML1M@G|e%IpEf_Cu*pW}R#EJS@R&YOUbBNW*x?*5hJQb_ST)j6rnVDqgJtjq_&j_Iz6=j&T9Nh&fwvL72ET;6;kWP&_zT<% z{{#2ID-b8QudZqDKqov1Yr*$m9r!+M3qOGE;D@jS{21oKW3V6m9OmiGSuhDqK=3sz zgva4Tcmh5IDUADJ_&r<-Ppi%y-pM;iq@0BD1wAr0f62CKoP z&>tR!c1TIJKzI$-fYOMp1a4VBYr-f<*xdw%!0x)%P75V42tgPe3&WusM#AL~C-(+e z8pG8s@@mcrVO>17SP0xl_-gPQ;i~S{IlEyOCE**oSy0*q69?4Ya(5zzM|fL;fHf zNqhwyO?*9^Kzt*-A8vvS2{(gQn*?{msql3;4LY2 ziU8wSD}g`5r=U!pO&DH*o8eXX43ww9vyi^lwnDmE+om4x@<>rBF@LONOv~t#xK!&k z$b(kf1EVdyR8#cHa35@H$(vbmsrFmQWzCTEWQ>d52)G|g7l^#jicgm{;Q)%2mf{IZ zu?fC|{3Un@?t_Qnhwy!P0)7C0g-4)N^Fzqc*FJ&~@EA;npFl>R_9^TDKZA@9?Q@u~ zH!z<+?okN7L@)+^1?g0cA?>E~v=fld)4o+5y1mu=2V#C?cLvJV<}8eYKfx6EGt7kN z;9c-nCNQoD6rtsqj5G4IYIv z;YVe1ZAOE3@5@Ra3)*^7r{s1!|+k~ z7<>$_hs979GpW`lxSBW%NS3ySz!UKaFbf!drXl( z6`8>p)%kY>sa!I+uA3p27p!HNY=JT%wn77g~y1?9Qg!xhM!S6Ez5a1#7D3`sV7V)s?;mTwSr2)O$kdm0nPKr4Q@@bD@-^FI)io!A-C~ zqypN#@N+l-o`VCS4`~mAkvhxeU;@n$41t~CP?!gYL3yqXhiqiDJSeN$2)GvJ!&l%) z$irA01$pLaW8j}~Eads56~HTSJgi~RY>+35HW50FMl6S-(1tS2hG@089h?@_(&oYe za3<^zr;1#4y*J9YJ)wRo|K3z}tdp(ik6_Q*a-6!!MN~U#hFDNZS=w#}l)*C#%HWv| zrDx{AG&m1Rj}$?9JT8Dk;6gYKE`rj=OQ5vzGFS{B@zKJ}wPl5m_RuQ`RzexUC91}N zIt>R<(DB?c9F6sZW38~0xZIJl^Vg(PIm+rXz!kZUbZhW-BjQsu*%^nYZaq}$erM5U zw1H@zHm%s8!ARoILaE(zFbQsfG7h)G=5QO774&)77QO&;;EPZmyxXCSq*8bvd z27Uv-g@3^BAUhcCdlgT73XU*4$hOAT)+8fi)Cf|6CQ#$NasWNH~bhHHqVnz^8dn$ z%XqUP{{i|#nOk;v9tOY*Fc8XIt6|fM+|>z40=!3=3D$y63?eMK3)UiD7e+#vlP=f- zMnTz(M#HW!2IfNXA82tnOe8)UN%jK>JO!r2Ehb41lET`;XOK2>^=hh z5DbI)Fb~dzBj7_YA8vpn;T|}ejKZkJMB*`UGL-Q(1)~wD%#86zv1Zimn}n z55f;2%cb@aWP#E?hWp_$cmjR`FT>9u(?$CnI-nFN%!)JGwSQ26@$gg;29(+~c*Qc< z4^Jci2L6a)q%SW_Fcc}%C&4DjW%JV%x}jM#DE2F0b6;)AVc6Q2 zVRe!~8x-=;X$!By_Ei3EhD&GS-C$QJ>q|E%@4P*IwFL_y4Q;OY{ooGb{hLK9mf_LtuoZBV;k3L z#ZHZCn&;NC35z2V2ise6mnvK6R1pOuje-m{uV9=pF+-gLGcr{Fas4H+(s5~aPb#|B zNYz>7Tsgjly})$WH9ysRfK&AvA1r>Q<6LUa_}b#TcKkA}kZm+gQ==zj8R=>2 z=?Q5@cA7d4I;5$P`?HL0X{yKl*+y=fS^);7sgFQjnhGk+GRCHx*o-uF zh}hgT#2f?QIR}j*}-_O2@_|s5%L_q z*Hh~!4we$mo8(fVlY*s`5^PJ5l1gv_K}tJsQi_yTBnOdDVhLU(NU0@QdvdUpyz%4| zDY;0dO%7IxyK1XVXehpjjuNB_Co!6vRvs|LWf+0YRnoNh8i8z(q$*M}P0gPkr6x@a zcGR|{E~KKZqaL3&(df}!8Pk*M_pp@meMz25o4B(u^2)_YsvNI+Pfu_RtCWEx6|WXe zA11kZ`s1X)c4&5Md2fS*5p z&9M8lk_96C%H}59zqX|Ds>~g#?k^gq`p%0mB3r1!dGYll*{(`sNfXOcN**Lq1h2eu z5u&0wkC2_Z)*g#E%Tp{Q1u0IlBe{~)TZE`u{`l|)pw+>yv1Q>c&P=1Qg*salU%${& zNKxc@^%ajASysGqZ*SLCsqO^FbZ;_N_I1@LcLT@#iZnc*XzHrX?r^=X+T+fbo{5=1 zNZLMTflIBLzeL&~X2H|sU;g%j5xV~)H^)YVx_e=$@koa1u`XWCS=dTXQF|5+Ls0Ho z6rdY_*H=l4;{{z7ZwO&?UU9Lj_iLS^t}b>p5^-xLtG9Wjhx>AO!FZP?_tq&=o({1UW#`{tY=FGQYsQ1^*<@36J>&hLfBk?F#2@-y!%5#VPnVl>HL5aG!&Ge0hj- z6wQw~=P2e!7S2b^k1Ph{Wx#ERYy#auFbLL!yd1dWAcNQ3ZiT=`#6uxR5*jZJ?ld0` zhQbN7Ll6l&!6?`r)`mSG2bpe;0OX0|<_JKGhrF?C?3>*MkhhG7W%X z2p7P{kk?zS30w|Sv0n?>ow}dm48r^(!yBmiMMgGwStxj;G{3}bhpmX0L-`^j4~T5| zI&1@FBiI%mg6-gu@;Z-A*YzgqvEoaNxAFy#8@i02#VhC8Jp)JAhO0~6oGMNoUb!mK zc&mj%bHl;0n11ARSEV_y^~OVznYKHs}gJ2TYAQ>3_e4xUlXOyuL^Z!TT<_^ zO;V24B)x6cs9D^-o5-u|QlGTCL$!hGxKvjEgI6O7R@V_GL&T^T7AE9u-d&L!sy>r zeYzpd(ZA`|W%K$8VWs;q7oKz*OU% zrmFv@G{-x)%{1xB4EMsuGIu7#F zRoK=nV_drG1E!>_6`hl+f`jQQ7 z2qOuf9a%=B47F@Wyxu`get;i4?O-2B#doCWeN91JX|R2;SqGgDS+XOJE48U!rGa|B zsh?FEEN!!_G)13c3Xb70yNbiHQrpUx0`>W(y538{W_!Jqq8FP2_e;U{k}CGRiK?AA zY&7*>;jkrLox`Ej6g1r#Y=5PSL(`o$HGF5FzSq<**%>UYxprrYe$*74!r`+j4ySMk zE(_GZG4&Z`!P3NC%2M=mrl7bi*nX*sLvfi+?Z@GYss9-V+Wl%-inP0I65H+ywtL#% z+e&SB+0>+6fztf*cBL3G8R`W6IIfyF#^v%q=j1d z>Ja}~bv+|hUHaXroUb_?UV(RU4pn9AoGbVE>!GUmYY8{cEqa()aMjvwOII^&~65ygx$K(cQrgufUsMm^Z&LW#1E}etwnO3LlCH1m(fN%gj%~aq ziNDzTo6@CkBsiSrrpO}=Fr|A*VVotEO3GPqxccWCEMfI|T?kXN-VAlTV;RWWh+d0O z>)%Y!Bh-O6bEU_^_RceA)m3ZuF0*@@TG#rR57t)umKfEO$`9=up;Nc=l>KLQyC*H3 z15~|}v%KNkmvv)us!BSTB1 zEQRcz8ctm=Fy)^VZ2+S8!1YWAU6`=4H^+WekVy?kh_(Y=|9c`wP; zowo~5yZJa;u*9F|mTm0xW~$3Hmzwons2-;teJ_f?&%c+<-%s9~X`DcLxQkR^&EYjt z%*OARN`fcfKZ&k<-v@*E?X_*?QUCJ9lP!FV#F}c*_pZpqnvzx1w5D>6<|(Sxbx7-; zQjdNg6?v+XHkBpct6irKd>^H+Q{R3co+dvJ=EpMT&!WA*8xGUzo2htop43yRl-Ivo zh)Ox_a>;Ley_u)-+7xeP?(bChosN%|pXyeq+4^|Z*F~;&ria_T`CM0fPlp?mLe-b2 zVan z?e!0=sf~^E6mMJH>Owuka$Ehj-pL9EhHJZ-rg8-bsCn1oOZw`%3uVb9U6-(*wFb*Ys{^*=g!m&~?wmb)2~G~~VasFnMzI(faF?e!!7ic1_9prp&p z>sCj3KN>Lm6VF199p$1DZ{Wx4u|9%OD=inc`s=I zIs55n32xQNq0H@ca!S(sHh%K*CSTs=s>UEaGQn<_yyVU6BXwYc(~Q+;X{x3UZ1KdJ zR*9uoiDg%bb*K{SRwb5OB{rx^EU!vzY?au=DzO<=Vsa*WSjt%>b?Cs7NuA8gZc!jQ z+0x5nUanhpeed8WTio0E<=^xx`kzF{-NA9nO~?Q7lP&V?GMs-~KjzMoJ2)2K){(h? z2fvMX@RJvqih|xccT4Z!D0}n@M^BHKf2EuD-ofwS9sG)p-oa7!__xdOn>+ZOzJuSn zs(v@?FSU?&gxh6!rK)2^{l!n?seU^@e{{DS+%+@E|8|bycW{)KzuWmG-N8@ZQL6ay zKsPU`MaztmkL;{+@&Tn$$tQM}L-};#X9oFZ;?d4PRLd0Ak;B$pD}m}31(KK?($^}< z3DCnicQ45fAl<8o0z4vHrYYjo-NTT~l2S1#VgnRjQYKz&GE2?|=qbk5%-2Gy>;E!t t`yUHms~w~#+Ui`-F@HpA9(z1XgCFG4)0fBB1j6zS`1jZHLiCN*{|gbA#ajRX From 34b798e03ad61f24da92e69e8f315dc526de8d0a Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 10 Aug 2017 23:22:04 +1000 Subject: [PATCH 0364/2058] Setup: Update to latest phlib --- .../CustomSetupTool/CustomSetupTool.vcxproj | 30 +- .../CustomSetupTool.vcxproj.filters | 86 +- .../CustomSetupTool/download.c | 186 ++-- .../CustomSetupTool/downloadpage.c | 3 - .../CustomSetupTool/include/setup.h | 15 +- .../CustomSetupTool/installpage.c | 6 +- .../CustomSetupTool/json-c/AUTHORS | 5 - .../CustomSetupTool/json-c/COPYING | 42 - .../CustomSetupTool/json-c/ChangeLog | 214 ----- .../CustomSetupTool/json-c/arraylist.c | 101 -- .../CustomSetupTool/json-c/arraylist.h | 56 -- .../CustomSetupTool/json-c/bits.h | 28 - .../CustomSetupTool/json-c/config.h | 89 -- .../CustomSetupTool/json-c/config.h.in | 174 ---- .../CustomSetupTool/json-c/debug.c | 83 -- .../CustomSetupTool/json-c/debug.h | 71 -- .../CustomSetupTool/json-c/json.h | 34 - .../CustomSetupTool/json-c/json_c_version.c | 20 - .../CustomSetupTool/json-c/json_c_version.h | 22 - .../CustomSetupTool/json-c/json_config.h | 3 - .../CustomSetupTool/json-c/json_inttypes.h | 28 - .../CustomSetupTool/json-c/json_object.c | 860 ----------------- .../CustomSetupTool/json-c/json_object.h | 611 ------------ .../json-c/json_object_iterator.c | 168 ---- .../json-c/json_object_iterator.h | 239 ----- .../json-c/json_object_private.h | 47 - .../CustomSetupTool/json-c/json_tokener.c | 888 ------------------ .../CustomSetupTool/json-c/json_tokener.h | 208 ---- .../CustomSetupTool/json-c/json_util.c | 301 ------ .../CustomSetupTool/json-c/json_util.h | 41 - .../CustomSetupTool/json-c/libjson.c | 26 - .../CustomSetupTool/json-c/linkhash.c | 604 ------------ .../CustomSetupTool/json-c/linkhash.h | 292 ------ .../CustomSetupTool/json-c/math_compat.h | 28 - .../CustomSetupTool/json-c/printbuf.c | 194 ---- .../CustomSetupTool/json-c/printbuf.h | 81 -- .../CustomSetupTool/json-c/random_seed.c | 238 ----- .../CustomSetupTool/json-c/random_seed.h | 25 - tools/CustomSetupTool/CustomSetupTool/setup.c | 90 +- .../CustomSetupTool/updatesetup.c | 29 - .../CustomSetupTool/websetuppage.c | 136 +++ 41 files changed, 237 insertions(+), 6165 deletions(-) delete mode 100644 tools/CustomSetupTool/CustomSetupTool/json-c/AUTHORS delete mode 100644 tools/CustomSetupTool/CustomSetupTool/json-c/COPYING delete mode 100644 tools/CustomSetupTool/CustomSetupTool/json-c/ChangeLog delete mode 100644 tools/CustomSetupTool/CustomSetupTool/json-c/arraylist.c delete mode 100644 tools/CustomSetupTool/CustomSetupTool/json-c/arraylist.h delete mode 100644 tools/CustomSetupTool/CustomSetupTool/json-c/bits.h delete mode 100644 tools/CustomSetupTool/CustomSetupTool/json-c/config.h delete mode 100644 tools/CustomSetupTool/CustomSetupTool/json-c/config.h.in delete mode 100644 tools/CustomSetupTool/CustomSetupTool/json-c/debug.c delete mode 100644 tools/CustomSetupTool/CustomSetupTool/json-c/debug.h delete mode 100644 tools/CustomSetupTool/CustomSetupTool/json-c/json.h delete mode 100644 tools/CustomSetupTool/CustomSetupTool/json-c/json_c_version.c delete mode 100644 tools/CustomSetupTool/CustomSetupTool/json-c/json_c_version.h delete mode 100644 tools/CustomSetupTool/CustomSetupTool/json-c/json_config.h delete mode 100644 tools/CustomSetupTool/CustomSetupTool/json-c/json_inttypes.h delete mode 100644 tools/CustomSetupTool/CustomSetupTool/json-c/json_object.c delete mode 100644 tools/CustomSetupTool/CustomSetupTool/json-c/json_object.h delete mode 100644 tools/CustomSetupTool/CustomSetupTool/json-c/json_object_iterator.c delete mode 100644 tools/CustomSetupTool/CustomSetupTool/json-c/json_object_iterator.h delete mode 100644 tools/CustomSetupTool/CustomSetupTool/json-c/json_object_private.h delete mode 100644 tools/CustomSetupTool/CustomSetupTool/json-c/json_tokener.c delete mode 100644 tools/CustomSetupTool/CustomSetupTool/json-c/json_tokener.h delete mode 100644 tools/CustomSetupTool/CustomSetupTool/json-c/json_util.c delete mode 100644 tools/CustomSetupTool/CustomSetupTool/json-c/json_util.h delete mode 100644 tools/CustomSetupTool/CustomSetupTool/json-c/libjson.c delete mode 100644 tools/CustomSetupTool/CustomSetupTool/json-c/linkhash.c delete mode 100644 tools/CustomSetupTool/CustomSetupTool/json-c/linkhash.h delete mode 100644 tools/CustomSetupTool/CustomSetupTool/json-c/math_compat.h delete mode 100644 tools/CustomSetupTool/CustomSetupTool/json-c/printbuf.c delete mode 100644 tools/CustomSetupTool/CustomSetupTool/json-c/printbuf.h delete mode 100644 tools/CustomSetupTool/CustomSetupTool/json-c/random_seed.c delete mode 100644 tools/CustomSetupTool/CustomSetupTool/json-c/random_seed.h delete mode 100644 tools/CustomSetupTool/CustomSetupTool/updatesetup.c create mode 100644 tools/CustomSetupTool/CustomSetupTool/websetuppage.c diff --git a/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj b/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj index 9cde444d6474..e6877e29be51 100644 --- a/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj +++ b/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj @@ -112,17 +112,6 @@ - - - - - - - - - - - @@ -133,28 +122,11 @@ - + - - - - - - - - - - - - - - - - - diff --git a/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj.filters b/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj.filters index fed6da63ac64..f27d961d9b0b 100644 --- a/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj.filters +++ b/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj.filters @@ -57,39 +57,6 @@ Source Files - - Source Files\json - - - Source Files\json - - - Source Files\json - - - Source Files\json - - - Source Files\json - - - Source Files\json - - - Source Files\json - - - Source Files\json - - - Source Files\json - - - Source Files\json - - - Source Files\json - Source Files\pages @@ -108,7 +75,7 @@ Source Files\pages - + Source Files @@ -125,57 +92,6 @@ Header Files\zip - - Header Files\json - - - Header Files\json - - - Header Files\json - - - Header Files\json - - - Header Files\json - - - Header Files\json - - - Header Files\json - - - Header Files\json - - - Header Files\json - - - Header Files\json - - - Header Files\json - - - Header Files\json - - - Header Files\json - - - Header Files\json - - - Header Files\json - - - Header Files\json - - - Header Files\json - diff --git a/tools/CustomSetupTool/CustomSetupTool/download.c b/tools/CustomSetupTool/CustomSetupTool/download.c index eeb0259e5789..0fc0f7fc1aa7 100644 --- a/tools/CustomSetupTool/CustomSetupTool/download.c +++ b/tools/CustomSetupTool/CustomSetupTool/download.c @@ -3,8 +3,6 @@ #include #include -#include "json-c\json.h" - PPH_STRING SetupGetVersion( VOID ) @@ -74,14 +72,14 @@ PPH_STRING UpdateWindowsString( return buildLabHeader; } -BOOLEAN ParseVersionString( - _Inout_ PPH_SETUP_CONTEXT Context +ULONG64 ParseVersionString( + _Inout_ PPH_STRING VersionString ) { PH_STRINGREF remaining, majorPart, minorPart, revisionPart; ULONG64 majorInteger = 0, minorInteger = 0, revisionInteger = 0; - - PhInitializeStringRef(&remaining, PhGetStringOrEmpty(Context->SetupFileVersion)); + + PhInitializeStringRef(&remaining, PhGetString(VersionString)); PhSplitStringRefAtChar(&remaining, '.', &majorPart, &remaining); PhSplitStringRefAtChar(&remaining, '.', &minorPart, &remaining); @@ -91,10 +89,12 @@ BOOLEAN ParseVersionString( PhStringToInteger64(&minorPart, 10, &minorInteger); PhStringToInteger64(&revisionPart, 10, &revisionInteger); - Context->LatestMajorVersion = (ULONG)majorInteger; - Context->LatestMinorVersion = (ULONG)minorInteger; - Context->LatestRevisionVersion = (ULONG)revisionInteger; - return TRUE; + return MAKE_VERSION_ULONGLONG( + (ULONG)majorInteger, + (ULONG)minorInteger, + (ULONG)revisionInteger, + 0 + ); } BOOLEAN ReadRequestString( @@ -146,21 +146,6 @@ BOOLEAN ReadRequestString( return TRUE; } -json_object_ptr json_get_object( - _In_ json_object_ptr rootObj, - _In_ const PSTR key -) -{ - json_object_ptr returnObj; - - if (json_object_object_get_ex(rootObj, key, &returnObj)) - { - return returnObj; - } - - return NULL; -} - BOOLEAN SetupQueryUpdateData( _Inout_ PPH_SETUP_CONTEXT Context ) @@ -277,38 +262,35 @@ BOOLEAN SetupQueryUpdateData( if (stringBuffer == NULL || stringBuffer[0] == '\0') goto CleanupExit; - if (!(jsonObject = json_tokener_parse(stringBuffer))) + if (!(jsonObject = PhCreateJsonParser(stringBuffer))) goto CleanupExit; - if (value = json_object_get_string(json_get_object(jsonObject, "updated"))) + if (value = PhGetJsonValueAsString(jsonObject, "updated")) Context->RelDate = PhConvertUtf8ToUtf16(value); - if (value = json_object_get_string(json_get_object(jsonObject, "size"))) + if (value = PhGetJsonValueAsString(jsonObject, "size")) Context->Size = PhConvertUtf8ToUtf16(value); - if (value = json_object_get_string(json_get_object(jsonObject, "forum_url"))) + if (value = PhGetJsonValueAsString(jsonObject, "forum_url")) Context->ReleaseNotesUrl = PhConvertUtf8ToUtf16(value); - if (value = json_object_get_string(json_get_object(jsonObject, "bin_url"))) + if (value = PhGetJsonValueAsString(jsonObject, "bin_url")) Context->BinFileDownloadUrl = PhConvertUtf8ToUtf16(value); - if (value = json_object_get_string(json_get_object(jsonObject, "hash_bin"))) + if (value = PhGetJsonValueAsString(jsonObject, "hash_bin")) Context->BinFileHash = PhConvertUtf8ToUtf16(value); - if (value = json_object_get_string(json_get_object(jsonObject, "setup_url"))) + if (value = PhGetJsonValueAsString(jsonObject, "setup_url")) Context->SetupFileDownloadUrl = PhConvertUtf8ToUtf16(value); - if (value = json_object_get_string(json_get_object(jsonObject, "sig"))) + if (value = PhGetJsonValueAsString(jsonObject, "sig")) Context->SetupFileSignature = PhConvertUtf8ToUtf16(value); - if (value = json_object_get_string(json_get_object(jsonObject, "version"))) + if (value = PhGetJsonValueAsString(jsonObject, "version")) Context->SetupFileVersion = PhConvertUtf8ToUtf16(value); - if (value = json_object_get_string(json_get_object(jsonObject, "websetup_url"))) + if (value = PhGetJsonValueAsString(jsonObject, "websetup_url")) Context->WebSetupFileDownloadUrl = PhConvertUtf8ToUtf16(value); - if (value = json_object_get_string(json_get_object(jsonObject, "websetup_sig"))) + if (value = PhGetJsonValueAsString(jsonObject, "websetup_sig")) Context->WebSetupFileSignature = PhConvertUtf8ToUtf16(value); - if (value = json_object_get_string(json_get_object(jsonObject, "websetup_version"))) + if (value = PhGetJsonValueAsString(jsonObject, "websetup_version")) Context->WebSetupFileVersion = PhConvertUtf8ToUtf16(value); - if (!ParseVersionString(Context)) - goto CleanupExit; - if (PhIsNullOrEmptyString(Context->RelDate)) goto CleanupExit; if (PhIsNullOrEmptyString(Context->Size)) @@ -327,7 +309,14 @@ BOOLEAN SetupQueryUpdateData( goto CleanupExit; if (PhIsNullOrEmptyString(Context->SetupFileVersion)) goto CleanupExit; - + + if (PhIsNullOrEmptyString(Context->WebSetupFileDownloadUrl)) + goto CleanupExit; + if (PhIsNullOrEmptyString(Context->WebSetupFileSignature)) + goto CleanupExit; + if (PhIsNullOrEmptyString(Context->WebSetupFileVersion)) + goto CleanupExit; + success = TRUE; CleanupExit: @@ -342,7 +331,7 @@ BOOLEAN SetupQueryUpdateData( WinHttpCloseHandle(httpSessionHandle); if (jsonObject) - json_object_put(jsonObject); + PhFreeJsonParser(jsonObject); if (stringBuffer) PhFree(stringBuffer); @@ -362,14 +351,11 @@ BOOLEAN UpdateDownloadUpdateData( HINTERNET httpSessionHandle = NULL; HINTERNET httpConnectionHandle = NULL; HINTERNET httpRequestHandle = NULL; - PPH_STRING setupTempPath = NULL; + PPH_STRING downloadFileName = NULL; PPH_STRING downloadHostPath = NULL; PPH_STRING downloadUrlPath = NULL; PPH_STRING userAgentString = NULL; - PPH_STRING fullSetupPath = NULL; - PPH_STRING randomGuidString = NULL; ULONG indexOfFileName = -1; - GUID randomGuid; URL_COMPONENTS httpUrlComponents = { sizeof(URL_COMPONENTS) }; LARGE_INTEGER timeNow; LARGE_INTEGER timeStart; @@ -385,46 +371,45 @@ BOOLEAN UpdateDownloadUpdateData( Context->CurrentRevisionVersion ); - setupTempPath = PhCreateStringEx(NULL, GetTempPath(0, NULL) * sizeof(WCHAR)); - - if (GetTempPath((ULONG)setupTempPath->Length / sizeof(WCHAR), setupTempPath->Buffer) == 0) - goto CleanupExit; - - PhGenerateGuid(&randomGuid); + httpUrlComponents.dwSchemeLength = (ULONG)-1; + httpUrlComponents.dwHostNameLength = (ULONG)-1; + httpUrlComponents.dwUrlPathLength = (ULONG)-1; - if (randomGuidString = PhFormatGuid(&randomGuid)) + if (!WinHttpCrackUrl( + PhGetString(Context->BinFileDownloadUrl), + 0, + 0, + &httpUrlComponents + )) { - PhMoveReference( - &randomGuidString, - PhSubstring(randomGuidString, 1, randomGuidString->Length / sizeof(WCHAR) - 2) - ); + Context->ErrorCode = GetLastError(); + goto CleanupExit; } - Context->FilePath = PhFormatString( - L"%s%s\\processhacker-%lu.%lu.%lu-bin.zip", - PhGetStringOrEmpty(setupTempPath), - PhGetStringOrEmpty(randomGuidString), - Context->LatestMajorVersion, - Context->LatestMinorVersion, - Context->LatestRevisionVersion + downloadHostPath = PhCreateStringEx( + httpUrlComponents.lpszHostName, + httpUrlComponents.dwHostNameLength * sizeof(WCHAR) + ); + downloadUrlPath = PhCreateStringEx( + httpUrlComponents.lpszUrlPath, + httpUrlComponents.dwUrlPathLength * sizeof(WCHAR) ); - if (PhIsNullOrEmptyString(Context->FilePath)) - goto CleanupExit; - if (fullSetupPath = PhGetFullPath(PhGetString(Context->FilePath), &indexOfFileName)) { - PPH_STRING directoryPath; + PH_STRINGREF pathPart; + PH_STRINGREF baseNamePart; - if (indexOfFileName == -1) + if (!PhSplitStringRefAtLastChar(&downloadUrlPath->sr, '/', &pathPart, &baseNamePart)) goto CleanupExit; - if (directoryPath = PhSubstring(fullSetupPath, 0, indexOfFileName)) - { - SHCreateDirectoryEx(NULL, directoryPath->Buffer, NULL); - PhDereferenceObject(directoryPath); - } + downloadFileName = PhCreateString2(&baseNamePart); } + Context->FilePath = PhGetCacheFileName(downloadFileName); + + if (PhIsNullOrEmptyString(Context->FilePath)) + goto CleanupExit; + if (!NT_SUCCESS(PhCreateFileWin32( &tempFileHandle, PhGetString(Context->FilePath), @@ -438,34 +423,9 @@ BOOLEAN UpdateDownloadUpdateData( goto CleanupExit; } - httpUrlComponents.dwSchemeLength = (ULONG)-1; - httpUrlComponents.dwHostNameLength = (ULONG)-1; - httpUrlComponents.dwUrlPathLength = (ULONG)-1; - - if (!WinHttpCrackUrl( - PhGetString(Context->BinFileDownloadUrl), - 0, - 0, - &httpUrlComponents - )) - { - Context->ErrorCode = GetLastError(); - goto CleanupExit; - } - - downloadHostPath = PhCreateStringEx( - httpUrlComponents.lpszHostName, - httpUrlComponents.dwHostNameLength * sizeof(WCHAR) - ); - downloadUrlPath = PhCreateStringEx( - httpUrlComponents.lpszUrlPath, - httpUrlComponents.dwUrlPathLength * sizeof(WCHAR) - ); - - SetWindowText(Context->MainHeaderHandle, PhFormatString(L"Downloading Process Hacker %lu.%lu.%lu...", - Context->LatestMajorVersion, - Context->CurrentMinorVersion, - Context->LatestRevisionVersion + SetWindowText(Context->MainHeaderHandle, PhFormatString( + L"Downloading Process Hacker %s...", + PhGetString(Context->SetupFileVersion) )->Buffer); //SetWindowText(Context->SubHeaderHandle, L"Progress: ~ of ~ (0.0%)"); @@ -643,28 +603,10 @@ BOOLEAN UpdateDownloadUpdateData( if (httpSessionHandle) WinHttpCloseHandle(httpSessionHandle); - PhClearReference(&randomGuidString); - PhClearReference(&fullSetupPath); - PhClearReference(&setupTempPath); PhClearReference(&downloadHostPath); PhClearReference(&downloadUrlPath); PhClearReference(&userAgentString); - - //if (UpdateDialogThreadHandle) - //{ - // if (downloadSuccess && hashSuccess && signatureSuccess) - // { - // PostMessage(context->DialogHandle, PH_UPDATESUCCESS, 0, 0); - // } - // else if (downloadSuccess) - // { - // PostMessage(context->DialogHandle, PH_UPDATEFAILURE, signatureSuccess, hashSuccess); - // } - // else - // { - // PostMessage(context->DialogHandle, PH_UPDATEISERRORED, 0, 0); - // } - //} - + PhClearReference(&downloadFileName); + return downloadSuccess; } diff --git a/tools/CustomSetupTool/CustomSetupTool/downloadpage.c b/tools/CustomSetupTool/CustomSetupTool/downloadpage.c index ced62e004766..8d82b65a09a4 100644 --- a/tools/CustomSetupTool/CustomSetupTool/downloadpage.c +++ b/tools/CustomSetupTool/CustomSetupTool/downloadpage.c @@ -29,9 +29,6 @@ NTSTATUS SetupDownloadProgressThread( if (!SetupQueryUpdateData(Context)) goto CleanupExit; - //if (SetupUpdateWebSetupBuild(Context)) - // goto CleanupExit; - if (!UpdateDownloadUpdateData(Context)) goto CleanupExit; diff --git a/tools/CustomSetupTool/CustomSetupTool/include/setup.h b/tools/CustomSetupTool/CustomSetupTool/include/setup.h index 78eccacb55ad..fa8478a5403f 100644 --- a/tools/CustomSetupTool/CustomSetupTool/include/setup.h +++ b/tools/CustomSetupTool/CustomSetupTool/include/setup.h @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -105,7 +106,6 @@ typedef struct _PH_SETUP_CONTEXT ULONG ErrorCode; PPH_STRING FilePath; - PPH_STRING RevVersion; PPH_STRING RelDate; PPH_STRING Size; PPH_STRING ReleaseNotesUrl; @@ -130,9 +130,6 @@ typedef struct _PH_SETUP_CONTEXT ULONG CurrentMajorVersion; ULONG CurrentMinorVersion; ULONG CurrentRevisionVersion; - ULONG LatestMajorVersion; - ULONG LatestMinorVersion; - ULONG LatestRevisionVersion; } PH_SETUP_CONTEXT, *PPH_SETUP_CONTEXT; VOID SetupLoadImage( @@ -235,6 +232,16 @@ VOID SetupCreateImageFileExecutionOptions( // download.c +#define MAKE_VERSION_ULONGLONG(major, minor, build, revision) \ + (((ULONGLONG)(major) << 48) | \ + ((ULONGLONG)(minor) << 32) | \ + ((ULONGLONG)(build) << 16) | \ + ((ULONGLONG)(revision) << 0)) + +ULONG64 ParseVersionString( + _Inout_ PPH_STRING VersionString + ); + BOOLEAN SetupQueryUpdateData( _In_ PPH_SETUP_CONTEXT Context ); diff --git a/tools/CustomSetupTool/CustomSetupTool/installpage.c b/tools/CustomSetupTool/CustomSetupTool/installpage.c index 8211041e995e..c8372ca76d34 100644 --- a/tools/CustomSetupTool/CustomSetupTool/installpage.c +++ b/tools/CustomSetupTool/CustomSetupTool/installpage.c @@ -174,10 +174,8 @@ INT_PTR CALLBACK SetupInstallPropPage_WndProc( )->Buffer); #else SetWindowText(context->MainHeaderHandle, PhaFormatString( - L"Installing Process Hacker %lu.%lu.%lu", - context->LatestMajorVersion, - context->LatestMinorVersion, - context->LatestRevisionVersion + L"Installing Process Hacker %s", + PhGetString(context->SetupFileVersion) )->Buffer); #endif SendMessage(context->ProgressHandle, PBM_SETRANGE32, 0, (LPARAM)ExtractTotalLength); diff --git a/tools/CustomSetupTool/CustomSetupTool/json-c/AUTHORS b/tools/CustomSetupTool/CustomSetupTool/json-c/AUTHORS deleted file mode 100644 index b389989c452b..000000000000 --- a/tools/CustomSetupTool/CustomSetupTool/json-c/AUTHORS +++ /dev/null @@ -1,5 +0,0 @@ -Michael Clark -Jehiah Czebotar -Eric Haszlakiewicz -C. Watford (christopher.watford@gmail.com) - diff --git a/tools/CustomSetupTool/CustomSetupTool/json-c/COPYING b/tools/CustomSetupTool/CustomSetupTool/json-c/COPYING deleted file mode 100644 index 740d1258d425..000000000000 --- a/tools/CustomSetupTool/CustomSetupTool/json-c/COPYING +++ /dev/null @@ -1,42 +0,0 @@ - -Copyright (c) 2009-2012 Eric Haszlakiewicz - -Permission is hereby granted, free of charge, to any person obtaining a -copy of this software and associated documentation files (the "Software"), -to deal in the Software without restriction, including without limitation -the rights to use, copy, modify, merge, publish, distribute, sublicense, -and/or sell copies of the Software, and to permit persons to whom the -Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included -in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - ----------------------------------------------------------------- - -Copyright (c) 2004, 2005 Metaparadigm Pte Ltd - -Permission is hereby granted, free of charge, to any person obtaining a -copy of this software and associated documentation files (the "Software"), -to deal in the Software without restriction, including without limitation -the rights to use, copy, modify, merge, publish, distribute, sublicense, -and/or sell copies of the Software, and to permit persons to whom the -Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included -in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/tools/CustomSetupTool/CustomSetupTool/json-c/ChangeLog b/tools/CustomSetupTool/CustomSetupTool/json-c/ChangeLog deleted file mode 100644 index 451b8f68403a..000000000000 --- a/tools/CustomSetupTool/CustomSetupTool/json-c/ChangeLog +++ /dev/null @@ -1,214 +0,0 @@ - -0.12 - - * Address security issues: - * CVE-2013-6371: hash collision denial of service - * CVE-2013-6370: buffer overflow if size_t is larger than int - - * Avoid potential overflow in json_object_get_double - - * Eliminate the mc_abort() function and MC_ABORT macro. - - * Make the json_tokener_errors array local. It has been deprecated for - a while, and json_tokener_error_desc() should be used instead. - - * change the floating point output format to %.17g so values with - more than 6 digits show up in the output. - - * Remove the old libjson.so name compatibility support. The library is - only created as libjson-c.so now and headers are only installed - into the ${prefix}/json-c directory. - - * When supported by the linker, add the -Bsymbolic-functions flag. - - * Various changes to fix the build on MSVC. - - * Make strict mode more strict: - * number must not start with 0 - * no single-quote strings - * no comments - * trailing char not allowed - * only allow lowercase literals - - * Added a json_object_new_double_s() convenience function to allow - an exact string representation of a double to be specified when - creating the object and use it in json_tokener_parse_ex() so - a re-serialized object more exactly matches the input. - - * Add support NaN and Infinity - - -0.11 - - * IMPORTANT: the name of the library has changed to libjson-c.so and - the header files are now in include/json-c. - The pkgconfig name has also changed from json to json-c. - You should change your build to use appropriate -I and -l options. - A compatibility shim is in place so builds using the old name will - continue to work, but that will be removed in the next release. - * Maximum recursion depth is now a runtime option. - json_tokener_new() is provided for compatibility. - json_tokener_new_ex(depth) - * Include json_object_iterator.h in the installed headers. - * Add support for building on Android. - * Rewrite json_object_object_add to replace just the value if the key already exists so keys remain valid. - * Make it safe to delete keys while iterating with the json_object_object_foreach macro. - * Add a json_set_serializer() function to allow the string output of a json_object to be customized. - * Make float parsing locale independent. - * Add a json_tokener_set_flags() function and a JSON_TOKENER_STRICT flag. - * Enable -Werror when building. - * speed improvements to parsing 64-bit integers on systems with working sscanf - * Add a json_object_object_length function. - * Fix a bug (buffer overrun) when expanding arrays to more than 64 entries. - -0.10 - - * Add a json_object_to_json_string_ext() function to allow output to be - formatted in a more human readable form. - * Add json_object_object_get_ex(), a NULL-safe get object method, to be able - to distinguish between a key not present and the value being NULL. - * Add an alternative iterator implementation, see json_object_iterator.h - * Make json_object_iter public to enable external use of the - json_object_object_foreachC macro. - * Add a printbuf_memset() function to provide an effecient way to set and - append things like whitespace indentation. - * Adjust json_object_is_type and json_object_get_type so they return - json_type_null for NULL objects and handle NULL passed to - json_objct_object_get(). - * Rename boolean type to json_bool. - * Fix various compile issues for Visual Studio and MinGW. - * Allow json_tokener_parse_ex() to be re-used to parse multiple object. - Also, fix some parsing issues with capitalized hexadecimal numbers and - number in E notation. - * Add json_tokener_get_error() and json_tokener_error_desc() to better - encapsulate the process of retrieving errors while parsing. - * Various improvements to the documentation of many functions. - * Add new json_object_array_sort() function. - * Fix a bug in json_object_get_int(), which would incorrectly return 0 - when called on a string type object. - Eric Haszlakiewicz - * Add a json_type_to_name() function. - Eric Haszlakiewicz - * Add a json_tokener_parse_verbose() function. - Jehiah Czebotar - * Improve support for null bytes within JSON strings. - Jehiah Czebotar - * Fix file descriptor leak if memory allocation fails in json_util - Zachary Blair, zack_blair at hotmail dot com - * Add int64 support. Two new functions json_object_net_int64 and - json_object_get_int64. Binary compatibility preserved. - Eric Haszlakiewicz, EHASZLA at transunion com - Rui Miguel Silva Seabra, rms at 1407 dot org - * Fix subtle bug in linkhash where lookup could hang after all slots - were filled then successively freed. - Spotted by Jean-Marc Naud, j dash m at newtraxtech dot com - * Make json_object_from_file take const char *filename - Spotted by Vikram Raj V, vsagar at attinteractive dot com - * Add handling of surrogate pairs (json_tokener.c, test4.c, Makefile.am) - Brent Miller, bdmiller at yahoo dash inc dot com - * Correction to comment describing printbuf_memappend in printbuf.h - Brent Miller, bdmiller at yahoo dash inc dot com - -0.9 - * Add README.html README-WIN32.html config.h.win32 to Makefile.am - Michael Clark, - * Add const qualifier to the json_tokener_parse functions - Eric Haszlakiewicz, EHASZLA at transunion dot com - * Rename min and max so we can never clash with C or C++ std library - Ian Atha, thatha at yahoo dash inc dot com - * Fix any noticeable spelling or grammar errors. - * Make sure every va_start has a va_end. - * Check all pointers for validity. - Erik Hovland, erik at hovland dot org - * Fix json_object_get_boolean to return false for empty string - Spotted by Vitaly Kruglikov, Vitaly dot Kruglikov at palm dot com - * optimizations to json_tokener_parse_ex(), printbuf_memappend() - Brent Miller, bdmiller at yahoo dash inc dot com - * Disable REFCOUNT_DEBUG by default in json_object.c - * Don't use this as a variable, so we can compile with a C++ compiler - * Add casts from void* to type of assignment when using malloc - * Add #ifdef __cplusplus guards to all of the headers - * Add typedefs for json_object, json_tokener, array_list, printbuf, lh_table - Michael Clark, - * Null pointer dereference fix. Fix json_object_get_boolean strlen test - to not return TRUE for zero length string. Remove redundant includes. - Erik Hovland, erik at hovland dot org - * Fixed warning reported by adding -Wstrict-prototypes - -Wold-style-definition to the compilatin flags. - Dotan Barak, dotanba at gmail dot com - * Add const correctness to public interfaces - Gerard Krol, g dot c dot krol at student dot tudelft dot nl - -0.8 - * Add va_end for every va_start - Dotan Barak, dotanba at gmail dot com - * Add macros to enable compiling out debug code - Geoffrey Young, geoff at modperlcookbook dot org - * Fix bug with use of capital E in numbers with exponents - Mateusz Loskot, mateusz at loskot dot net - * Add stddef.h include - * Patch allows for json-c compile with -Werror and not fail due to - -Wmissing-prototypes -Wstrict-prototypes -Wmissing-declarations - Geoffrey Young, geoff at modperlcookbook dot org - -0.7 - * Add escaping of backslash to json output - * Add escaping of foward slash on tokenizing and output - * Changes to internal tokenizer from using recursion to - using a depth state structure to allow incremental parsing - -0.6 - * Fix bug in escaping of control characters - Johan Bj�rklund, johbjo09 at kth dot se - * Remove include "config.h" from headers (should only - be included from .c files) - Michael Clark - -0.5 - * Make headers C++ compatible by change *this to *obj - * Add ifdef C++ extern "C" to headers - * Use simpler definition of min and max in bits.h - Larry Lansing, llansing at fuzzynerd dot com - - * Remove automake 1.6 requirement - * Move autogen commands into autogen.sh. Update README - * Remove error pointer special case for Windows - * Change license from LGPL to MIT - Michael Clark - -0.4 - * Fix additional error case in object parsing - * Add back sign reversal in nested object parse as error pointer - value is negative, while error value is positive. - Michael Clark - -0.3 - * fix pointer arithmetic bug for error pointer check in is_error() macro - * fix type passed to printbuf_memappend in json_tokener - * update autotools bootstrap instructions in README - Michael Clark - -0.2 - * printbuf.c - C. Watford (christopher.watford@gmail.com) - Added a Win32/Win64 compliant implementation of vasprintf - * debug.c - C. Watford (christopher.watford@gmail.com) - Removed usage of vsyslog on Win32/Win64 systems, needs to be handled - by a configure script - * json_object.c - C. Watford (christopher.watford@gmail.com) - Added scope operator to wrap usage of json_object_object_foreach, this - needs to be rethought to be more ANSI C friendly - * json_object.h - C. Watford (christopher.watford@gmail.com) - Added Microsoft C friendly version of json_object_object_foreach - * json_tokener.c - C. Watford (christopher.watford@gmail.com) - Added a Win32/Win64 compliant implementation of strndup - * json_util.c - C. Watford (christopher.watford@gmail.com) - Added cast and mask to suffice size_t v. unsigned int conversion - correctness - * json_tokener.c - sign reversal issue on error info for nested object parse - spotted by Johan Bj�rklund (johbjo09 at kth.se) - * json_object.c - escape " in json_escape_str - * Change to automake and libtool to build shared and static library - Michael Clark - -0.1 - * initial release diff --git a/tools/CustomSetupTool/CustomSetupTool/json-c/arraylist.c b/tools/CustomSetupTool/CustomSetupTool/json-c/arraylist.c deleted file mode 100644 index 97f2c921711b..000000000000 --- a/tools/CustomSetupTool/CustomSetupTool/json-c/arraylist.c +++ /dev/null @@ -1,101 +0,0 @@ -/* - * $Id: arraylist.c,v 1.4 2006/01/26 02:16:28 mclark Exp $ - * - * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. - * Michael Clark - * - * This library is free software; you can redistribute it and/or modify - * it under the terms of the MIT license. See COPYING for details. - * - */ - -#include "config.h" - -#ifdef STDC_HEADERS -# include -# include -#endif /* STDC_HEADERS */ - -#if defined(HAVE_STRINGS_H) && !defined(_STRING_H) && !defined(__USE_BSD) -# include -#endif /* HAVE_STRINGS_H */ - -#include "bits.h" -#include "arraylist.h" - -struct array_list* -array_list_new(array_list_free_fn *free_fn) -{ - struct array_list *arr; - - arr = (struct array_list*)calloc(1, sizeof(struct array_list)); - if(!arr) return NULL; - arr->size = ARRAY_LIST_DEFAULT_SIZE; - arr->length = 0; - arr->free_fn = free_fn; - if(!(arr->array = (void**)calloc(sizeof(void*), arr->size))) { - free(arr); - return NULL; - } - return arr; -} - -extern void -array_list_free(struct array_list *arr) -{ - int i; - for(i = 0; i < arr->length; i++) - if(arr->array[i]) arr->free_fn(arr->array[i]); - free(arr->array); - free(arr); -} - -void* -array_list_get_idx(struct array_list *arr, int i) -{ - if(i >= arr->length) return NULL; - return arr->array[i]; -} - -static int array_list_expand_internal(struct array_list *arr, int max) -{ - void *t; - int new_size; - - if(max < arr->size) return 0; - new_size = json_max(arr->size << 1, max); - if(!(t = realloc(arr->array, new_size*sizeof(void*)))) return -1; - arr->array = (void**)t; - (void)memset(arr->array + arr->size, 0, (new_size-arr->size)*sizeof(void*)); - arr->size = new_size; - return 0; -} - -int -array_list_put_idx(struct array_list *arr, int idx, void *data) -{ - if(array_list_expand_internal(arr, idx+1)) return -1; - if(arr->array[idx]) arr->free_fn(arr->array[idx]); - arr->array[idx] = data; - if(arr->length <= idx) arr->length = idx + 1; - return 0; -} - -int -array_list_add(struct array_list *arr, void *data) -{ - return array_list_put_idx(arr, arr->length, data); -} - -void -array_list_sort(struct array_list *arr, int(__cdecl* sort_fn)(const void *, const void *)) -{ - qsort(arr->array, arr->length, sizeof(arr->array[0]), - (int (__cdecl*)(const void *, const void *))sort_fn); -} - -int -array_list_length(struct array_list *arr) -{ - return arr->length; -} diff --git a/tools/CustomSetupTool/CustomSetupTool/json-c/arraylist.h b/tools/CustomSetupTool/CustomSetupTool/json-c/arraylist.h deleted file mode 100644 index 089be0bd7215..000000000000 --- a/tools/CustomSetupTool/CustomSetupTool/json-c/arraylist.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * $Id: arraylist.h,v 1.4 2006/01/26 02:16:28 mclark Exp $ - * - * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. - * Michael Clark - * - * This library is free software; you can redistribute it and/or modify - * it under the terms of the MIT license. See COPYING for details. - * - */ - -#ifndef _arraylist_h_ -#define _arraylist_h_ - -#ifdef __cplusplus -extern "C" { -#endif - -#define ARRAY_LIST_DEFAULT_SIZE 32 - -typedef void (array_list_free_fn) (void *data); - -struct array_list -{ - void **array; - int length; - int size; - array_list_free_fn *free_fn; -}; - -extern struct array_list* -array_list_new(array_list_free_fn *free_fn); - -extern void -array_list_free(struct array_list *al); - -extern void* -array_list_get_idx(struct array_list *al, int i); - -extern int -array_list_put_idx(struct array_list *al, int i, void *data); - -extern int -array_list_add(struct array_list *al, void *data); - -extern int -array_list_length(struct array_list *al); - -extern void -array_list_sort(struct array_list *arr, int(__cdecl* compar)(const void *, const void *)); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/tools/CustomSetupTool/CustomSetupTool/json-c/bits.h b/tools/CustomSetupTool/CustomSetupTool/json-c/bits.h deleted file mode 100644 index c8cbbc820d5b..000000000000 --- a/tools/CustomSetupTool/CustomSetupTool/json-c/bits.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * $Id: bits.h,v 1.10 2006/01/30 23:07:57 mclark Exp $ - * - * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. - * Michael Clark - * - * This library is free software; you can redistribute it and/or modify - * it under the terms of the MIT license. See COPYING for details. - * - */ - -#ifndef _bits_h_ -#define _bits_h_ - -#ifndef json_min -#define json_min(a,b) ((a) < (b) ? (a) : (b)) -#endif - -#ifndef json_max -#define json_max(a,b) ((a) > (b) ? (a) : (b)) -#endif - -#define hexdigit(x) (((x) <= '9') ? (x) - '0' : ((x) & 7) + 9) -#define error_ptr(error) ((void*)error) -#define error_description(error) (json_tokener_errors[error]) -#define is_error(ptr) (ptr == NULL) - -#endif diff --git a/tools/CustomSetupTool/CustomSetupTool/json-c/config.h b/tools/CustomSetupTool/CustomSetupTool/json-c/config.h deleted file mode 100644 index df46f0a481a7..000000000000 --- a/tools/CustomSetupTool/CustomSetupTool/json-c/config.h +++ /dev/null @@ -1,89 +0,0 @@ -#define PACKAGE_STRING "JSON C Library 0.12-20140410" -#define PACKAGE_BUGREPORT "json-c@googlegroups.com" -#define PACKAGE_NAME "JSON C Library" -#define PACKAGE_TARNAME "json-c" -#define PACKAGE_VERSION "0.12-20140410" - - -#define HAVE_SETLOCALE 1 -#define HAVE_LOCALE_H 1 - -#define HAVE_DECL_NAN 1 -#define HAVE_DECL_INFINITY 1 -//#define HAVE_DECL__ISNAN 1 -//#define HAVE_DECL__FINITE 1 - -/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */ -/* #undef HAVE_DOPRNT */ - -/* Define to 1 if you have the header file. */ -#define HAVE_FCNTL_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_INTTYPES_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_LIMITS_H 1 - -/* Define to 1 if your system has a GNU libc compatible `malloc' function, and - to 0 otherwise. */ -#define HAVE_MALLOC 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_MEMORY_H 1 - -/* Define to 1 if you have the `open' function. */ -#define HAVE_OPEN 1 - -/* Define to 1 if your system has a GNU libc compatible `realloc' function, - and to 0 otherwise. */ -#define HAVE_REALLOC 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STDINT_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STDLIB_H 1 - -/* Define to 1 if you have the `strdup' function. */ -#define HAVE_STRNDUP 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STDARG_H 1 - -/* Define to 1 if you have the `strerror' function. */ -#define HAVE_STRERROR 1 - -/* Define to 1 if you have the header file. */ -#undef HAVE_STRINGS_H - -/* Define to 1 if you have the header file. */ -#define HAVE_STRING_H 1 - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYSLOG_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_PARAM_H - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_STAT_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_TYPES_H 1 - -/* Define to 1 if you have the header file. */ -#undef HAVE_UNISTD_H - -/* Define to 1 if you have the `vprintf' function. */ -#undef HAVE_VPRINTF - -/* Define to 1 if you have the `vsyslog' function. */ -#undef HAVE_VSYSLOG - -/* Define to 1 if you have the `strncasecmp' function. */ -#undef HAVE_STRNCASECMP - -/* Define to 1 if you have the ANSI C header files. */ -#define STDC_HEADERS 1 - diff --git a/tools/CustomSetupTool/CustomSetupTool/json-c/config.h.in b/tools/CustomSetupTool/CustomSetupTool/json-c/config.h.in deleted file mode 100644 index 0dcab1a30015..000000000000 --- a/tools/CustomSetupTool/CustomSetupTool/json-c/config.h.in +++ /dev/null @@ -1,174 +0,0 @@ -/* config.h.in. Generated from configure.ac by autoheader. */ - -/* Enable RDRANR Hardware RNG Hash Seed */ -#undef ENABLE_RDRAND - -/* Define if .gnu.warning accepts long strings. */ -#undef HAS_GNU_WARNING_LONG - -/* Define to 1 if you have the declaration of `INFINITY', and to 0 if you - don't. */ -#undef HAVE_DECL_INFINITY - -/* Define to 1 if you have the declaration of `isinf', and to 0 if you don't. - */ -#undef HAVE_DECL_ISINF - -/* Define to 1 if you have the declaration of `isnan', and to 0 if you don't. - */ -#undef HAVE_DECL_ISNAN - -/* Define to 1 if you have the declaration of `nan', and to 0 if you don't. */ -#undef HAVE_DECL_NAN - -/* Define to 1 if you have the declaration of `_finite', and to 0 if you - don't. */ -#undef HAVE_DECL__FINITE - -/* Define to 1 if you have the declaration of `_isnan', and to 0 if you don't. - */ -#undef HAVE_DECL__ISNAN - -/* Define to 1 if you have the header file. */ -#undef HAVE_DLFCN_H - -/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */ -#undef HAVE_DOPRNT - -/* Define to 1 if you have the header file. */ -#undef HAVE_ENDIAN_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_FCNTL_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_INTTYPES_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_LIMITS_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_LOCALE_H - -/* Define to 1 if your system has a GNU libc compatible `malloc' function, and - to 0 otherwise. */ -#undef HAVE_MALLOC - -/* Define to 1 if you have the header file. */ -#undef HAVE_MEMORY_H - -/* Define to 1 if you have the `open' function. */ -#undef HAVE_OPEN - -/* Define to 1 if your system has a GNU libc compatible `realloc' function, - and to 0 otherwise. */ -#undef HAVE_REALLOC - -/* Define to 1 if you have the `setlocale' function. */ -#undef HAVE_SETLOCALE - -/* Define to 1 if you have the `snprintf' function. */ -#undef HAVE_SNPRINTF - -/* Define to 1 if you have the header file. */ -#undef HAVE_STDARG_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_STDINT_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_STDLIB_H - -/* Define to 1 if you have the `strcasecmp' function. */ -#undef HAVE_STRCASECMP - -/* Define to 1 if you have the `strdup' function. */ -#undef HAVE_STRDUP - -/* Define to 1 if you have the `strerror' function. */ -#undef HAVE_STRERROR - -/* Define to 1 if you have the header file. */ -#undef HAVE_STRINGS_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_STRING_H - -/* Define to 1 if you have the `strncasecmp' function. */ -#undef HAVE_STRNCASECMP - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYSLOG_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_CDEFS_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_PARAM_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_STAT_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_TYPES_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_UNISTD_H - -/* Define to 1 if you have the `vasprintf' function. */ -#undef HAVE_VASPRINTF - -/* Define to 1 if you have the `vprintf' function. */ -#undef HAVE_VPRINTF - -/* Define to 1 if you have the `vsnprintf' function. */ -#undef HAVE_VSNPRINTF - -/* Define to 1 if you have the `vsyslog' function. */ -#undef HAVE_VSYSLOG - -/* Public define for json_inttypes.h */ -#undef JSON_C_HAVE_INTTYPES_H - -/* Define to the sub-directory in which libtool stores uninstalled libraries. - */ -#undef LT_OBJDIR - -/* Name of package */ -#undef PACKAGE - -/* Define to the address where bug reports for this package should be sent. */ -#undef PACKAGE_BUGREPORT - -/* Define to the full name of this package. */ -#undef PACKAGE_NAME - -/* Define to the full name and version of this package. */ -#undef PACKAGE_STRING - -/* Define to the one symbol short name of this package. */ -#undef PACKAGE_TARNAME - -/* Define to the home page for this package. */ -#undef PACKAGE_URL - -/* Define to the version of this package. */ -#undef PACKAGE_VERSION - -/* Define to 1 if you have the ANSI C header files. */ -#undef STDC_HEADERS - -/* Version number of package */ -#undef VERSION - -/* Define to empty if `const' does not conform to ANSI C. */ -#undef const - -/* Define to rpl_malloc if the replacement function should be used. */ -#undef malloc - -/* Define to rpl_realloc if the replacement function should be used. */ -#undef realloc - -/* Define to `unsigned int' if does not define. */ -#undef size_t diff --git a/tools/CustomSetupTool/CustomSetupTool/json-c/debug.c b/tools/CustomSetupTool/CustomSetupTool/json-c/debug.c deleted file mode 100644 index 9dff7818bf86..000000000000 --- a/tools/CustomSetupTool/CustomSetupTool/json-c/debug.c +++ /dev/null @@ -1,83 +0,0 @@ -/* - * $Id: debug.c,v 1.5 2006/01/26 02:16:28 mclark Exp $ - * - * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. - * Michael Clark - * - * This library is free software; you can redistribute it and/or modify - * it under the terms of the MIT license. See COPYING for details. - * - */ - -#include "config.h" - -#include -#include -#include -#include - -#if HAVE_SYSLOG_H -# include -#endif /* HAVE_SYSLOG_H */ - -#if HAVE_UNISTD_H -# include -#endif /* HAVE_UNISTD_H */ - -#if HAVE_SYS_PARAM_H -#include -#endif /* HAVE_SYS_PARAM_H */ - -#include "debug.h" - -static int _syslog = 0; -static int _debug = 0; - -void mc_set_debug(int debug) { _debug = debug; } -int mc_get_debug(void) { return _debug; } - -extern void mc_set_syslog(int syslog) -{ - _syslog = syslog; -} - -void mc_debug(const char *msg, ...) -{ - va_list ap; - if(_debug) { - va_start(ap, msg); -#if HAVE_VSYSLOG - if(_syslog) { - vsyslog(LOG_DEBUG, msg, ap); - } else -#endif - vprintf(msg, ap); - va_end(ap); - } -} - -void mc_error(const char *msg, ...) -{ - va_list ap; - va_start(ap, msg); -#if HAVE_VSYSLOG - if(_syslog) { - vsyslog(LOG_ERR, msg, ap); - } else -#endif - vfprintf(stderr, msg, ap); - va_end(ap); -} - -void mc_info(const char *msg, ...) -{ - va_list ap; - va_start(ap, msg); -#if HAVE_VSYSLOG - if(_syslog) { - vsyslog(LOG_INFO, msg, ap); - } else -#endif - vfprintf(stderr, msg, ap); - va_end(ap); -} diff --git a/tools/CustomSetupTool/CustomSetupTool/json-c/debug.h b/tools/CustomSetupTool/CustomSetupTool/json-c/debug.h deleted file mode 100644 index 80ca3e43042e..000000000000 --- a/tools/CustomSetupTool/CustomSetupTool/json-c/debug.h +++ /dev/null @@ -1,71 +0,0 @@ -/* - * $Id: debug.h,v 1.5 2006/01/30 23:07:57 mclark Exp $ - * - * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. - * Michael Clark - * Copyright (c) 2009 Hewlett-Packard Development Company, L.P. - * - * This library is free software; you can redistribute it and/or modify - * it under the terms of the MIT license. See COPYING for details. - * - */ - -#ifndef _DEBUG_H_ -#define _DEBUG_H_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -extern void mc_set_debug(int debug); -extern int mc_get_debug(void); - -extern void mc_set_syslog(int syslog); - -extern void mc_debug(const char *msg, ...); -extern void mc_error(const char *msg, ...); -extern void mc_info(const char *msg, ...); - -#ifndef __STRING -#define __STRING(x) #x -#endif - -#ifndef PARSER_BROKEN_FIXED - -#define JASSERT(cond) do {} while(0) - -#else - -#define JASSERT(cond) do { \ - if (!(cond)) { \ - mc_error("cjson assert failure %s:%d : cond \"" __STRING(cond) "failed\n", __FILE__, __LINE__); \ - *(int *)0 = 1;\ - abort(); \ - }\ - } while(0) - -#endif - -#define MC_ERROR(x, ...) mc_error(x, ##__VA_ARGS__) - -#ifdef MC_MAINTAINER_MODE -#define MC_SET_DEBUG(x) mc_set_debug(x) -#define MC_GET_DEBUG() mc_get_debug() -#define MC_SET_SYSLOG(x) mc_set_syslog(x) -#define MC_DEBUG(x, ...) mc_debug(x, ##__VA_ARGS__) -#define MC_INFO(x, ...) mc_info(x, ##__VA_ARGS__) -#else -#define MC_SET_DEBUG(x) if (0) mc_set_debug(x) -#define MC_GET_DEBUG() (0) -#define MC_SET_SYSLOG(x) if (0) mc_set_syslog(x) -#define MC_DEBUG(x, ...) if (0) mc_debug(x, ##__VA_ARGS__) -#define MC_INFO(x, ...) if (0) mc_info(x, ##__VA_ARGS__) -#endif - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/tools/CustomSetupTool/CustomSetupTool/json-c/json.h b/tools/CustomSetupTool/CustomSetupTool/json-c/json.h deleted file mode 100644 index 4339b20e9060..000000000000 --- a/tools/CustomSetupTool/CustomSetupTool/json-c/json.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * $Id: json.h,v 1.6 2006/01/26 02:16:28 mclark Exp $ - * - * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. - * Michael Clark - * Copyright (c) 2009 Hewlett-Packard Development Company, L.P. - * - * This library is free software; you can redistribute it and/or modify - * it under the terms of the MIT license. See COPYING for details. - * - */ - -#ifndef _json_h_ -#define _json_h_ - -#ifdef __cplusplus -extern "C" { -#endif - -#include "bits.h" -#include "debug.h" -#include "linkhash.h" -#include "arraylist.h" -#include "json_util.h" -#include "json_object.h" -#include "json_tokener.h" -#include "json_object_iterator.h" -#include "json_c_version.h" - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/tools/CustomSetupTool/CustomSetupTool/json-c/json_c_version.c b/tools/CustomSetupTool/CustomSetupTool/json-c/json_c_version.c deleted file mode 100644 index 13eb18855423..000000000000 --- a/tools/CustomSetupTool/CustomSetupTool/json-c/json_c_version.c +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2012 Eric Haszlakiewicz - * - * This library is free software; you can redistribute it and/or modify - * it under the terms of the MIT license. See COPYING for details. - */ -#include "config.h" - -#include "json_c_version.h" - -const char *json_c_version(void) -{ - return JSON_C_VERSION; -} - -int json_c_version_num(void) -{ - return JSON_C_VERSION_NUM; -} - diff --git a/tools/CustomSetupTool/CustomSetupTool/json-c/json_c_version.h b/tools/CustomSetupTool/CustomSetupTool/json-c/json_c_version.h deleted file mode 100644 index eed98a497501..000000000000 --- a/tools/CustomSetupTool/CustomSetupTool/json-c/json_c_version.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (c) 2012 Eric Haszlakiewicz - * - * This library is free software; you can redistribute it and/or modify - * it under the terms of the MIT license. See COPYING for details. - */ - -#ifndef _json_c_version_h_ -#define _json_c_version_h_ - -#define JSON_C_MAJOR_VERSION 0 -#define JSON_C_MINOR_VERSION 12 -#define JSON_C_MICRO_VERSION 0 -#define JSON_C_VERSION_NUM ((JSON_C_MAJOR_VERSION << 16) | \ - (JSON_C_MINOR_VERSION << 8) | \ - JSON_C_MICRO_VERSION) -#define JSON_C_VERSION "0.12" - -const char *json_c_version(void); /* Returns JSON_C_VERSION */ -int json_c_version_num(void); /* Returns JSON_C_VERSION_NUM */ - -#endif diff --git a/tools/CustomSetupTool/CustomSetupTool/json-c/json_config.h b/tools/CustomSetupTool/CustomSetupTool/json-c/json_config.h deleted file mode 100644 index 405fda20dc5b..000000000000 --- a/tools/CustomSetupTool/CustomSetupTool/json-c/json_config.h +++ /dev/null @@ -1,3 +0,0 @@ - -/* Define to 1 if you have the header file. */ -#define JSON_C_HAVE_INTTYPES_H 1 diff --git a/tools/CustomSetupTool/CustomSetupTool/json-c/json_inttypes.h b/tools/CustomSetupTool/CustomSetupTool/json-c/json_inttypes.h deleted file mode 100644 index 9de8d246d9dd..000000000000 --- a/tools/CustomSetupTool/CustomSetupTool/json-c/json_inttypes.h +++ /dev/null @@ -1,28 +0,0 @@ - -#ifndef _json_inttypes_h_ -#define _json_inttypes_h_ - -#include "json_config.h" - -#if defined(_MSC_VER) && _MSC_VER <= 1700 - -/* Anything less than Visual Studio C++ 10 is missing stdint.h and inttypes.h */ -typedef __int32 int32_t; -#define INT32_MIN ((int32_t)_I32_MIN) -#define INT32_MAX ((int32_t)_I32_MAX) -typedef __int64 int64_t; -#define INT64_MIN ((int64_t)_I64_MIN) -#define INT64_MAX ((int64_t)_I64_MAX) -#define PRId64 "I64d" -#define SCNd64 "I64d" - -#else - -#ifdef JSON_C_HAVE_INTTYPES_H -#include -#endif -/* inttypes.h includes stdint.h */ - -#endif - -#endif diff --git a/tools/CustomSetupTool/CustomSetupTool/json-c/json_object.c b/tools/CustomSetupTool/CustomSetupTool/json-c/json_object.c deleted file mode 100644 index 57f3f0d237d5..000000000000 --- a/tools/CustomSetupTool/CustomSetupTool/json-c/json_object.c +++ /dev/null @@ -1,860 +0,0 @@ -/* - * $Id: json_object.c,v 1.17 2006/07/25 03:24:50 mclark Exp $ - * - * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. - * Michael Clark - * Copyright (c) 2009 Hewlett-Packard Development Company, L.P. - * - * This library is free software; you can redistribute it and/or modify - * it under the terms of the MIT license. See COPYING for details. - * - */ - -#include "config.h" - -#include -#include -#include -#include -#include -#include - -#include "debug.h" -#include "printbuf.h" -#include "linkhash.h" -#include "arraylist.h" -#include "json_inttypes.h" -#include "json_object.h" -#include "json_object_private.h" -#include "json_util.h" -#include "math_compat.h" - -#if !defined(HAVE_STRDUP) && defined(_MSC_VER) - /* MSC has the version as _strdup */ -# define strdup _strdup -#elif !defined(HAVE_STRDUP) -# error You do not have strdup on your system. -#endif /* HAVE_STRDUP */ - -#if !defined(HAVE_SNPRINTF) && defined(_MSC_VER) - /* MSC has the version as _snprintf */ -# define snprintf _snprintf -#elif !defined(HAVE_SNPRINTF) -# error You do not have snprintf on your system. -#endif /* HAVE_SNPRINTF */ - -// Don't define this. It's not thread-safe. -/* #define REFCOUNT_DEBUG 1 */ - -const char *json_number_chars = "0123456789.+-eE"; -const char *json_hex_chars = "0123456789abcdefABCDEF"; - -static void json_object_generic_delete(struct json_object* jso); -static struct json_object* json_object_new(enum json_type o_type); - -static json_object_to_json_string_fn json_object_object_to_json_string; -static json_object_to_json_string_fn json_object_boolean_to_json_string; -static json_object_to_json_string_fn json_object_int_to_json_string; -static json_object_to_json_string_fn json_object_double_to_json_string; -static json_object_to_json_string_fn json_object_string_to_json_string; -static json_object_to_json_string_fn json_object_array_to_json_string; - - -/* ref count debugging */ - -#ifdef REFCOUNT_DEBUG - -static struct lh_table *json_object_table; - -static void json_object_init(void) __attribute__ ((constructor)); -static void json_object_init(void) { - MC_DEBUG("json_object_init: creating object table\n"); - json_object_table = lh_kptr_table_new(128, "json_object_table", NULL); -} - -static void json_object_fini(void) __attribute__ ((destructor)); -static void json_object_fini(void) { - struct lh_entry *ent; - if(MC_GET_DEBUG()) { - if (json_object_table->count) { - MC_DEBUG("json_object_fini: %d referenced objects at exit\n", - json_object_table->count); - lh_foreach(json_object_table, ent) { - struct json_object* obj = (struct json_object*)ent->v; - MC_DEBUG("\t%s:%p\n", json_type_to_name(obj->o_type), obj); - } - } - } - MC_DEBUG("json_object_fini: freeing object table\n"); - lh_table_free(json_object_table); -} -#endif /* REFCOUNT_DEBUG */ - - -/* string escaping */ - -static int json_escape_str(struct printbuf *pb, char *str, size_t len) -{ - int pos = 0, start_offset = 0; - unsigned char c; - while (len--) { - c = str[pos]; - switch(c) { - case '\b': - case '\n': - case '\r': - case '\t': - case '\f': - case '"': - case '\\': - case '/': - if(pos - start_offset > 0) - printbuf_memappend(pb, str + start_offset, pos - start_offset); - if(c == '\b') printbuf_memappend(pb, "\\b", 2); - else if(c == '\n') printbuf_memappend(pb, "\\n", 2); - else if(c == '\r') printbuf_memappend(pb, "\\r", 2); - else if(c == '\t') printbuf_memappend(pb, "\\t", 2); - else if(c == '\f') printbuf_memappend(pb, "\\f", 2); - else if(c == '"') printbuf_memappend(pb, "\\\"", 2); - else if(c == '\\') printbuf_memappend(pb, "\\\\", 2); - else if(c == '/') printbuf_memappend(pb, "\\/", 2); - start_offset = ++pos; - break; - default: - if(c < ' ') { - if(pos - start_offset > 0) - printbuf_memappend(pb, str + start_offset, pos - start_offset); - sprintbuf(pb, "\\u00%c%c", - json_hex_chars[c >> 4], - json_hex_chars[c & 0xf]); - start_offset = ++pos; - } else pos++; - } - } - if(pos - start_offset > 0) - printbuf_memappend(pb, str + start_offset, pos - start_offset); - return 0; -} - - -/* reference counting */ - -extern struct json_object* json_object_get(struct json_object *jso) -{ - if(jso) { - jso->_ref_count++; - } - return jso; -} - -int json_object_put(struct json_object *jso) -{ - if(jso) - { - jso->_ref_count--; - if(!jso->_ref_count) - { - if (jso->_user_delete) - jso->_user_delete(jso, jso->_userdata); - jso->_delete(jso); - return 1; - } - } - return 0; -} - - -/* generic object construction and destruction parts */ - -static void json_object_generic_delete(struct json_object* jso) -{ -#ifdef REFCOUNT_DEBUG - MC_DEBUG("json_object_delete_%s: %p\n", - json_type_to_name(jso->o_type), jso); - lh_table_delete(json_object_table, jso); -#endif /* REFCOUNT_DEBUG */ - printbuf_free(jso->_pb); - free(jso); -} - -static struct json_object* json_object_new(enum json_type o_type) -{ - struct json_object *jso; - - jso = (struct json_object*)calloc(sizeof(struct json_object), 1); - if(!jso) return NULL; - jso->o_type = o_type; - jso->_ref_count = 1; - jso->_delete = &json_object_generic_delete; -#ifdef REFCOUNT_DEBUG - lh_table_insert(json_object_table, jso, jso); - MC_DEBUG("json_object_new_%s: %p\n", json_type_to_name(jso->o_type), jso); -#endif /* REFCOUNT_DEBUG */ - return jso; -} - - -/* type checking functions */ - -int json_object_is_type(struct json_object *jso, enum json_type type) -{ - if (!jso) - return (type == json_type_null); - return (jso->o_type == type); -} - -enum json_type json_object_get_type(struct json_object *jso) -{ - if (!jso) - return json_type_null; - return jso->o_type; -} - -/* set a custom conversion to string */ - -void json_object_set_serializer(json_object *jso, - json_object_to_json_string_fn to_string_func, - void *userdata, - json_object_delete_fn *user_delete) -{ - // First, clean up any previously existing user info - if (jso->_user_delete) - { - jso->_user_delete(jso, jso->_userdata); - } - jso->_userdata = NULL; - jso->_user_delete = NULL; - - if (to_string_func == NULL) - { - // Reset to the standard serialization function - switch(jso->o_type) - { - case json_type_null: - jso->_to_json_string = NULL; - break; - case json_type_boolean: - jso->_to_json_string = &json_object_boolean_to_json_string; - break; - case json_type_double: - jso->_to_json_string = &json_object_double_to_json_string; - break; - case json_type_int: - jso->_to_json_string = &json_object_int_to_json_string; - break; - case json_type_object: - jso->_to_json_string = &json_object_object_to_json_string; - break; - case json_type_array: - jso->_to_json_string = &json_object_array_to_json_string; - break; - case json_type_string: - jso->_to_json_string = &json_object_string_to_json_string; - break; - } - return; - } - - jso->_to_json_string = to_string_func; - jso->_userdata = userdata; - jso->_user_delete = user_delete; -} - - -/* extended conversion to string */ - -char* json_object_to_json_string_ext(struct json_object *jso, int flags) -{ - if (!jso) - return "null"; - - if ((!jso->_pb) && !(jso->_pb = printbuf_new())) - return NULL; - - printbuf_reset(jso->_pb); - - if(jso->_to_json_string(jso, jso->_pb, 0, flags) < 0) - return NULL; - - return jso->_pb->buf; -} - -/* backwards-compatible conversion to string */ - -char* json_object_to_json_string(struct json_object *jso) -{ - return json_object_to_json_string_ext(jso, JSON_C_TO_STRING_SPACED); -} - -static void indent(struct printbuf *pb, int level, int flags) -{ - if (flags & JSON_C_TO_STRING_PRETTY) - { - printbuf_memset(pb, -1, ' ', level * 2); - } -} - -/* json_object_object */ - -static int json_object_object_to_json_string(struct json_object* jso, - struct printbuf *pb, - int level, - int flags) -{ - int had_children = 0; - struct json_object_iter iter; - - sprintbuf(pb, "{" /*}*/); - if (flags & JSON_C_TO_STRING_PRETTY) - sprintbuf(pb, "\n"); - json_object_object_foreachC(jso, iter) - { - if (had_children) - { - sprintbuf(pb, ","); - if (flags & JSON_C_TO_STRING_PRETTY) - sprintbuf(pb, "\n"); - } - had_children = 1; - if (flags & JSON_C_TO_STRING_SPACED) - sprintbuf(pb, " "); - indent(pb, level+1, flags); - sprintbuf(pb, "\""); - json_escape_str(pb, iter.key, strlen(iter.key)); - if (flags & JSON_C_TO_STRING_SPACED) - sprintbuf(pb, "\": "); - else - sprintbuf(pb, "\":"); - if(iter.val == NULL) - sprintbuf(pb, "null"); - else - iter.val->_to_json_string(iter.val, pb, level+1,flags); - } - if (flags & JSON_C_TO_STRING_PRETTY) - { - if (had_children) - sprintbuf(pb, "\n"); - indent(pb,level,flags); - } - if (flags & JSON_C_TO_STRING_SPACED) - return sprintbuf(pb, /*{*/ " }"); - else - return sprintbuf(pb, /*{*/ "}"); -} - - -static void json_object_lh_entry_free(struct lh_entry *ent) -{ - free(ent->k); - json_object_put((struct json_object*)ent->v); -} - -static void json_object_object_delete(struct json_object* jso) -{ - lh_table_free(jso->o.c_object); - json_object_generic_delete(jso); -} - -struct json_object* json_object_new_object(void) -{ - struct json_object* jso = json_object_new(json_type_object); - - if (!jso) - { - return NULL; - } - - jso->_delete = &json_object_object_delete; - jso->_to_json_string = &json_object_object_to_json_string; - jso->o.c_object = lh_kchar_table_new(JSON_OBJECT_DEF_HASH_ENTRIES, NULL, &json_object_lh_entry_free); - - return jso; -} - -struct lh_table* json_object_get_object(struct json_object *jso) -{ - if(!jso) return NULL; - switch(jso->o_type) { - case json_type_object: - return jso->o.c_object; - default: - return NULL; - } -} - -void json_object_object_add(struct json_object* jso, const char *key, - struct json_object *val) -{ - // We lookup the entry and replace the value, rather than just deleting - // and re-adding it, so the existing key remains valid. - json_object *existing_value = NULL; - struct lh_entry *existing_entry; - existing_entry = lh_table_lookup_entry(jso->o.c_object, (void*)key); - if (!existing_entry) - { - lh_table_insert(jso->o.c_object, strdup(key), val); - return; - } - existing_value = (void *)existing_entry->v; - if (existing_value) - json_object_put(existing_value); - existing_entry->v = val; -} - -int json_object_object_length(struct json_object *jso) -{ - return lh_table_length(jso->o.c_object); -} - -struct json_object* json_object_object_get(struct json_object* jso, const char *key) -{ - struct json_object *result = NULL; - json_object_object_get_ex(jso, key, &result); - return result; -} - -json_bool json_object_object_get_ex(struct json_object* jso, const char *key, struct json_object **value) -{ - if (value != NULL) - *value = NULL; - - if (NULL == jso) - return FALSE; - - switch(jso->o_type) - { - case json_type_object: - return lh_table_lookup_ex(jso->o.c_object, (void*)key, (void**)value); - default: - if (value != NULL) - *value = NULL; - return FALSE; - } -} - -void json_object_object_del(struct json_object* jso, const char *key) -{ - lh_table_delete(jso->o.c_object, key); -} - - -/* json_object_boolean */ - -static int json_object_boolean_to_json_string(struct json_object* jso, - struct printbuf *pb, - int level, - int flags) -{ - if(jso->o.c_boolean) return sprintbuf(pb, "true"); - else return sprintbuf(pb, "false"); -} - -struct json_object* json_object_new_boolean(json_bool b) -{ - struct json_object *jso = json_object_new(json_type_boolean); - if(!jso) return NULL; - jso->_to_json_string = &json_object_boolean_to_json_string; - jso->o.c_boolean = b; - return jso; -} - -json_bool json_object_get_boolean(struct json_object *jso) -{ - if(!jso) return FALSE; - switch(jso->o_type) { - case json_type_boolean: - return jso->o.c_boolean; - case json_type_int: - return (jso->o.c_int64 != 0); - case json_type_double: - return (jso->o.c_double != 0); - case json_type_string: - return (jso->o.c_string.len != 0); - default: - return FALSE; - } -} - - -/* json_object_int */ - -static int json_object_int_to_json_string(struct json_object* jso, - struct printbuf *pb, - int level, - int flags) -{ - return sprintbuf(pb, "%"PRId64, jso->o.c_int64); -} - -struct json_object* json_object_new_int(int32_t i) -{ - struct json_object *jso = json_object_new(json_type_int); - if(!jso) return NULL; - jso->_to_json_string = &json_object_int_to_json_string; - jso->o.c_int64 = i; - return jso; -} - -int32_t json_object_get_int(struct json_object *jso) -{ - int64_t cint64; - enum json_type o_type; - - if(!jso) return 0; - - o_type = jso->o_type; - cint64 = jso->o.c_int64; - - if (o_type == json_type_string) - { - /* - * Parse strings into 64-bit numbers, then use the - * 64-to-32-bit number handling below. - */ - if (json_parse_int64(jso->o.c_string.str, &cint64) != 0) - return 0; /* whoops, it didn't work. */ - o_type = json_type_int; - } - - switch(o_type) { - case json_type_int: - /* Make sure we return the correct values for out of range numbers. */ - if (cint64 <= INT32_MIN) - return INT32_MIN; - else if (cint64 >= INT32_MAX) - return INT32_MAX; - else - return (int32_t)cint64; - case json_type_double: - return (int32_t)jso->o.c_double; - case json_type_boolean: - return jso->o.c_boolean; - default: - return 0; - } -} - -struct json_object* json_object_new_int64(int64_t i) -{ - struct json_object *jso = json_object_new(json_type_int); - if(!jso) return NULL; - jso->_to_json_string = &json_object_int_to_json_string; - jso->o.c_int64 = i; - return jso; -} - -int64_t json_object_get_int64(struct json_object *jso) -{ - int64_t cint; - - if(!jso) return 0; - switch(jso->o_type) { - case json_type_int: - return jso->o.c_int64; - case json_type_double: - return (int64_t)jso->o.c_double; - case json_type_boolean: - return jso->o.c_boolean; - case json_type_string: - if (json_parse_int64(jso->o.c_string.str, &cint) == 0) return cint; - default: - return 0; - } -} - - -/* json_object_double */ - -static int json_object_double_to_json_string(struct json_object* jso, - struct printbuf *pb, - int level, - int flags) -{ - char buf[128], *p, *q; - size_t size; - /* Although JSON RFC does not support - NaN or Infinity as numeric values - ECMA 262 section 9.8.1 defines - how to handle these cases as strings */ - if(isnan(jso->o.c_double)) - size = _snprintf_s(buf, sizeof(buf), _TRUNCATE, "NaN"); - else if(isinf(jso->o.c_double)) - if(jso->o.c_double > 0) - size = _snprintf_s(buf, sizeof(buf), _TRUNCATE, "Infinity"); - else - size = _snprintf_s(buf, sizeof(buf), _TRUNCATE, "-Infinity"); - else - size = _snprintf_s(buf, sizeof(buf), _TRUNCATE, "%.17g", jso->o.c_double); - - p = strchr(buf, ','); - if (p) { - *p = '.'; - } else { - p = strchr(buf, '.'); - } - if (p && (flags & JSON_C_TO_STRING_NOZERO)) { - /* last useful digit, always keep 1 zero */ - p++; - for (q=p ; *q ; q++) { - if (*q!='0') p=q; - } - /* drop trailing zeroes */ - *(++p) = 0; - size = p-buf; - } - printbuf_memappend(pb, buf, size); - return (int)size; -} - -struct json_object* json_object_new_double(double d) -{ - struct json_object *jso = json_object_new(json_type_double); - if (!jso) - return NULL; - jso->_to_json_string = &json_object_double_to_json_string; - jso->o.c_double = d; - return jso; -} - -struct json_object* json_object_new_double_s(double d, const char *ds) -{ - struct json_object *jso = json_object_new_double(d); - if (!jso) - return NULL; - - json_object_set_serializer(jso, json_object_userdata_to_json_string, strdup(ds), json_object_free_userdata); - return jso; -} - -int json_object_userdata_to_json_string(struct json_object *jso, struct printbuf *pb, int level, int flags) -{ - size_t userdata_len = strlen(jso->_userdata); - printbuf_memappend(pb, jso->_userdata, userdata_len); - return (int)userdata_len; -} - -void json_object_free_userdata(struct json_object *jso, void *userdata) -{ - free(userdata); -} - -double json_object_get_double(struct json_object *jso) -{ - double cdouble; - char *errPtr = NULL; - - if(!jso) return 0.0; - switch(jso->o_type) { - case json_type_double: - return jso->o.c_double; - case json_type_int: - return (double)jso->o.c_int64; - case json_type_boolean: - return jso->o.c_boolean; - case json_type_string: - errno = 0; - cdouble = strtod(jso->o.c_string.str,&errPtr); - - /* if conversion stopped at the first character, return 0.0 */ - if (errPtr == jso->o.c_string.str) - return 0.0; - - /* - * Check that the conversion terminated on something sensible - * - * For example, { "pay" : 123AB } would parse as 123. - */ - if (*errPtr != '\0') - return 0.0; - - /* - * If strtod encounters a string which would exceed the - * capacity of a double, it returns +/- HUGE_VAL and sets - * errno to ERANGE. But +/- HUGE_VAL is also a valid result - * from a conversion, so we need to check errno. - * - * Underflow also sets errno to ERANGE, but it returns 0 in - * that case, which is what we will return anyway. - * - * See CERT guideline ERR30-C - */ - if ((HUGE_VAL == cdouble || -HUGE_VAL == cdouble) && - (ERANGE == errno)) - cdouble = 0.0; - return cdouble; - default: - return 0.0; - } -} - - -/* json_object_string */ - -static int json_object_string_to_json_string(struct json_object* jso, - struct printbuf *pb, - int level, - int flags) -{ - sprintbuf(pb, "\""); - json_escape_str(pb, jso->o.c_string.str, jso->o.c_string.len); - sprintbuf(pb, "\""); - return 0; -} - -static void json_object_string_delete(struct json_object* jso) -{ - free(jso->o.c_string.str); - json_object_generic_delete(jso); -} - -struct json_object* json_object_new_string(const char *s) -{ - struct json_object *jso = json_object_new(json_type_string); - if(!jso) return NULL; - jso->_delete = &json_object_string_delete; - jso->_to_json_string = &json_object_string_to_json_string; - jso->o.c_string.str = strdup(s); - jso->o.c_string.len = (int)strlen(s); - return jso; -} - -struct json_object* json_object_new_string_len(const char *s, size_t len) -{ - struct json_object *jso = json_object_new(json_type_string); - if(!jso) return NULL; - jso->_delete = &json_object_string_delete; - jso->_to_json_string = &json_object_string_to_json_string; - jso->o.c_string.str = (char*)malloc(len + 1); - memcpy(jso->o.c_string.str, (void *)s, len); - jso->o.c_string.str[len] = '\0'; - jso->o.c_string.len = len; - return jso; -} - -char* json_object_get_string(struct json_object *jso) -{ - if (!jso) - return NULL; - switch (jso->o_type) - { - case json_type_string: - return jso->o.c_string.str; - default: - return json_object_to_json_string(jso); - } -} - -int json_object_get_string_len(struct json_object *jso) { - if(!jso) return 0; - switch(jso->o_type) { - case json_type_string: - return (int)jso->o.c_string.len; - default: - return 0; - } -} - - -/* json_object_array */ - -static int json_object_array_to_json_string(struct json_object* jso, - struct printbuf *pb, - int level, - int flags) -{ - int had_children = 0; - int ii; - sprintbuf(pb, "["); - if (flags & JSON_C_TO_STRING_PRETTY) - sprintbuf(pb, "\n"); - for(ii=0; ii < json_object_array_length(jso); ii++) - { - struct json_object *val; - if (had_children) - { - sprintbuf(pb, ","); - if (flags & JSON_C_TO_STRING_PRETTY) - sprintbuf(pb, "\n"); - } - had_children = 1; - if (flags & JSON_C_TO_STRING_SPACED) - sprintbuf(pb, " "); - indent(pb, level + 1, flags); - val = json_object_array_get_idx(jso, ii); - if(val == NULL) - sprintbuf(pb, "null"); - else - val->_to_json_string(val, pb, level+1, flags); - } - if (flags & JSON_C_TO_STRING_PRETTY) - { - if (had_children) - sprintbuf(pb, "\n"); - indent(pb,level,flags); - } - - if (flags & JSON_C_TO_STRING_SPACED) - return sprintbuf(pb, " ]"); - else - return sprintbuf(pb, "]"); -} - -static void json_object_array_entry_free(void *data) -{ - json_object_put((struct json_object*)data); -} - -static void json_object_array_delete(struct json_object* jso) -{ - array_list_free(jso->o.c_array); - json_object_generic_delete(jso); -} - -struct json_object* json_object_new_array(void) -{ - struct json_object *jso = json_object_new(json_type_array); - if(!jso) return NULL; - jso->_delete = &json_object_array_delete; - jso->_to_json_string = &json_object_array_to_json_string; - jso->o.c_array = array_list_new(&json_object_array_entry_free); - return jso; -} - -struct array_list* json_object_get_array(struct json_object *jso) -{ - if(!jso) return NULL; - switch(jso->o_type) { - case json_type_array: - return jso->o.c_array; - default: - return NULL; - } -} - -void json_object_array_sort(struct json_object *jso, int(__cdecl* sort_fn)(const void *, const void *)) -{ - array_list_sort(jso->o.c_array, sort_fn); -} - -int json_object_array_length(struct json_object *jso) -{ - return array_list_length(jso->o.c_array); -} - -int json_object_array_add(struct json_object *jso,struct json_object *val) -{ - return array_list_add(jso->o.c_array, val); -} - -int json_object_array_put_idx(struct json_object *jso, int idx, - struct json_object *val) -{ - return array_list_put_idx(jso->o.c_array, idx, val); -} - -struct json_object* json_object_array_get_idx(struct json_object *jso, - int idx) -{ - return (struct json_object*)array_list_get_idx(jso->o.c_array, idx); -} - diff --git a/tools/CustomSetupTool/CustomSetupTool/json-c/json_object.h b/tools/CustomSetupTool/CustomSetupTool/json-c/json_object.h deleted file mode 100644 index c649ab7c7bfb..000000000000 --- a/tools/CustomSetupTool/CustomSetupTool/json-c/json_object.h +++ /dev/null @@ -1,611 +0,0 @@ -/* - * $Id: json_object.h,v 1.12 2006/01/30 23:07:57 mclark Exp $ - * - * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. - * Michael Clark - * Copyright (c) 2009 Hewlett-Packard Development Company, L.P. - * - * This library is free software; you can redistribute it and/or modify - * it under the terms of the MIT license. See COPYING for details. - * - */ - -#ifndef _json_object_h_ -#define _json_object_h_ - -#ifdef __GNUC__ -#define THIS_FUNCTION_IS_DEPRECATED(func) func __attribute__ ((deprecated)) -#elif defined(_MSC_VER) -#define THIS_FUNCTION_IS_DEPRECATED(func) __declspec(deprecated) func -#else -#define THIS_FUNCTION_IS_DEPRECATED(func) func -#endif - -#include "json_inttypes.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define JSON_OBJECT_DEF_HASH_ENTRIES 16 - -/** - * A flag for the json_object_to_json_string_ext() and - * json_object_to_file_ext() functions which causes the output - * to have no extra whitespace or formatting applied. - */ -#define JSON_C_TO_STRING_PLAIN 0 -/** - * A flag for the json_object_to_json_string_ext() and - * json_object_to_file_ext() functions which causes the output to have - * minimal whitespace inserted to make things slightly more readable. - */ -#define JSON_C_TO_STRING_SPACED (1<<0) -/** - * A flag for the json_object_to_json_string_ext() and - * json_object_to_file_ext() functions which causes - * the output to be formatted. - * - * See the "Two Space Tab" option at http://jsonformatter.curiousconcept.com/ - * for an example of the format. - */ -#define JSON_C_TO_STRING_PRETTY (1<<1) -/** - * A flag to drop trailing zero for float values - */ -#define JSON_C_TO_STRING_NOZERO (1<<2) - -#undef FALSE -#define FALSE ((json_bool)0) - -#undef TRUE -#define TRUE ((json_bool)1) - -extern const char *json_number_chars; -extern const char *json_hex_chars; - -/* CAW: added for ANSI C iteration correctness */ -struct json_object_iter -{ - char *key; - struct json_object *val; - struct lh_entry *entry; -}; - -/* forward structure definitions */ - -typedef int json_bool; -typedef struct printbuf printbuf; -typedef struct lh_table lh_table; -typedef struct array_list array_list; -typedef struct json_object json_object, *json_object_ptr; -typedef struct json_object_iter json_object_iter; -typedef struct json_tokener json_tokener; - -/** - * Type of custom user delete functions. See json_object_set_serializer. - */ -typedef void (json_object_delete_fn)(struct json_object *jso, void *userdata); - -/** - * Type of a custom serialization function. See json_object_set_serializer. - */ -typedef int (json_object_to_json_string_fn)(struct json_object *jso, - struct printbuf *pb, - int level, - int flags); - -/* supported object types */ - -typedef enum json_type { - /* If you change this, be sure to update json_type_to_name() too */ - json_type_null, - json_type_boolean, - json_type_double, - json_type_int, - json_type_object, - json_type_array, - json_type_string, -} json_type; - -/* reference counting functions */ - -/** - * Increment the reference count of json_object, thereby grabbing shared - * ownership of obj. - * - * @param obj the json_object instance - */ -extern struct json_object* json_object_get(struct json_object *obj); - -/** - * Decrement the reference count of json_object and free if it reaches zero. - * You must have ownership of obj prior to doing this or you will cause an - * imbalance in the reference count. - * - * @param obj the json_object instance - * @returns 1 if the object was freed. - */ -int json_object_put(struct json_object *obj); - -/** - * Check if the json_object is of a given type - * @param obj the json_object instance - * @param type one of: - json_type_null (i.e. obj == NULL), - json_type_boolean, - json_type_double, - json_type_int, - json_type_object, - json_type_array, - json_type_string, - */ -extern int json_object_is_type(struct json_object *obj, enum json_type type); - -/** - * Get the type of the json_object. See also json_type_to_name() to turn this - * into a string suitable, for instance, for logging. - * - * @param obj the json_object instance - * @returns type being one of: - json_type_null (i.e. obj == NULL), - json_type_boolean, - json_type_double, - json_type_int, - json_type_object, - json_type_array, - json_type_string, - */ -extern enum json_type json_object_get_type(struct json_object *obj); - - -/** Stringify object to json format. - * Equivalent to json_object_to_json_string_ext(obj, JSON_C_TO_STRING_SPACED) - * @param obj the json_object instance - * @returns a string in JSON format - */ -extern char* json_object_to_json_string(struct json_object *obj); - -/** Stringify object to json format - * @param obj the json_object instance - * @param flags formatting options, see JSON_C_TO_STRING_PRETTY and other constants - * @returns a string in JSON format - */ -extern char* json_object_to_json_string_ext(struct json_object *obj, int flags); - -/** - * Set a custom serialization function to be used when this particular object - * is converted to a string by json_object_to_json_string. - * - * If a custom serializer is already set on this object, any existing - * user_delete function is called before the new one is set. - * - * If to_string_func is NULL, the other parameters are ignored - * and the default behaviour is reset. - * - * The userdata parameter is optional and may be passed as NULL. If provided, - * it is passed to to_string_func as-is. This parameter may be NULL even - * if user_delete is non-NULL. - * - * The user_delete parameter is optional and may be passed as NULL, even if - * the userdata parameter is non-NULL. It will be called just before the - * json_object is deleted, after it's reference count goes to zero - * (see json_object_put()). - * If this is not provided, it is up to the caller to free the userdata at - * an appropriate time. (i.e. after the json_object is deleted) - * - * @param jso the object to customize - * @param to_string_func the custom serialization function - * @param userdata an optional opaque cookie - * @param user_delete an optional function from freeing userdata - */ -extern void json_object_set_serializer(json_object *jso, - json_object_to_json_string_fn to_string_func, - void *userdata, - json_object_delete_fn *user_delete); - -/** - * Simply call free on the userdata pointer. - * Can be used with json_object_set_serializer(). - * - * @param jso unused - * @param userdata the pointer that is passed to free(). - */ -json_object_delete_fn json_object_free_userdata; - -/** - * Copy the jso->_userdata string over to pb as-is. - * Can be used with json_object_set_serializer(). - * - * @param jso The object whose _userdata is used. - * @param pb The destination buffer. - * @param level Ignored. - * @param flags Ignored. - */ -json_object_to_json_string_fn json_object_userdata_to_json_string; - - -/* object type methods */ - -/** Create a new empty object with a reference count of 1. The caller of - * this object initially has sole ownership. Remember, when using - * json_object_object_add or json_object_array_put_idx, ownership will - * transfer to the object/array. Call json_object_get if you want to maintain - * shared ownership or also add this object as a child of multiple objects or - * arrays. Any ownerships you acquired but did not transfer must be released - * through json_object_put. - * - * @returns a json_object of type json_type_object - */ -extern struct json_object* json_object_new_object(void); - -/** Get the hashtable of a json_object of type json_type_object - * @param obj the json_object instance - * @returns a linkhash - */ -extern struct lh_table* json_object_get_object(struct json_object *obj); - -/** Get the size of an object in terms of the number of fields it has. - * @param obj the json_object whose length to return - */ -extern int json_object_object_length(struct json_object* obj); - -/** Add an object field to a json_object of type json_type_object - * - * The reference count will *not* be incremented. This is to make adding - * fields to objects in code more compact. If you want to retain a reference - * to an added object, independent of the lifetime of obj, you must wrap the - * passed object with json_object_get. - * - * Upon calling this, the ownership of val transfers to obj. Thus you must - * make sure that you do in fact have ownership over this object. For instance, - * json_object_new_object will give you ownership until you transfer it, - * whereas json_object_object_get does not. - * - * @param obj the json_object instance - * @param key the object field name (a private copy will be duplicated) - * @param val a json_object or NULL member to associate with the given field - */ -extern void json_object_object_add(struct json_object* obj, const char *key, - struct json_object *val); - -/** Get the json_object associate with a given object field - * - * *No* reference counts will be changed. There is no need to manually adjust - * reference counts through the json_object_put/json_object_get methods unless - * you need to have the child (value) reference maintain a different lifetime - * than the owning parent (obj). Ownership of the returned value is retained - * by obj (do not do json_object_put unless you have done a json_object_get). - * If you delete the value from obj (json_object_object_del) and wish to access - * the returned reference afterwards, make sure you have first gotten shared - * ownership through json_object_get (& don't forget to do a json_object_put - * or transfer ownership to prevent a memory leak). - * - * @param obj the json_object instance - * @param key the object field name - * @returns the json_object associated with the given field name - * @deprecated Please use json_object_object_get_ex - */ -THIS_FUNCTION_IS_DEPRECATED(extern struct json_object* json_object_object_get(struct json_object* obj, - const char *key)); - -/** Get the json_object associated with a given object field. - * - * This returns true if the key is found, false in all other cases (including - * if obj isn't a json_type_object). - * - * *No* reference counts will be changed. There is no need to manually adjust - * reference counts through the json_object_put/json_object_get methods unless - * you need to have the child (value) reference maintain a different lifetime - * than the owning parent (obj). Ownership of value is retained by obj. - * - * @param obj the json_object instance - * @param key the object field name - * @param value a pointer where to store a reference to the json_object - * associated with the given field name. - * - * It is safe to pass a NULL value. - * @returns whether or not the key exists - */ -extern json_bool json_object_object_get_ex(struct json_object* obj, - const char *key, - struct json_object **value); - -/** Delete the given json_object field - * - * The reference count will be decremented for the deleted object. If there - * are no more owners of the value represented by this key, then the value is - * freed. Otherwise, the reference to the value will remain in memory. - * - * @param obj the json_object instance - * @param key the object field name - */ -extern void json_object_object_del(struct json_object* obj, const char *key); - -/** - * Iterate through all keys and values of an object. - * - * Adding keys to the object while iterating is NOT allowed. - * - * Deleting an existing key, or replacing an existing key with a - * new value IS allowed. - * - * @param obj the json_object instance - * @param key the local name for the char* key variable defined in the body - * @param val the local name for the json_object* object variable defined in - * the body - */ -#if defined(__GNUC__) && !defined(__STRICT_ANSI__) && __STDC_VERSION__ >= 199901L - -# define json_object_object_foreach(obj,key,val) \ - char *key; \ - struct json_object *val __attribute__((__unused__)); \ - for(struct lh_entry *entry ## key = json_object_get_object(obj)->head, *entry_next ## key = NULL; \ - ({ if(entry ## key) { \ - key = (char*)entry ## key->k; \ - val = (struct json_object*)entry ## key->v; \ - entry_next ## key = entry ## key->next; \ - } ; entry ## key; }); \ - entry ## key = entry_next ## key ) - -#else /* ANSI C or MSC */ - -# define json_object_object_foreach(obj,key,val) \ - char *key;\ - struct json_object *val; \ - struct lh_entry *entry ## key; \ - struct lh_entry *entry_next ## key = NULL; \ - for(entry ## key = json_object_get_object(obj)->head; \ - (entry ## key ? ( \ - key = (char*)entry ## key->k, \ - val = (struct json_object*)entry ## key->v, \ - entry_next ## key = entry ## key->next, \ - entry ## key) : 0); \ - entry ## key = entry_next ## key) - -#endif /* defined(__GNUC__) && !defined(__STRICT_ANSI__) && __STDC_VERSION__ >= 199901L */ - -/** Iterate through all keys and values of an object (ANSI C Safe) - * @param obj the json_object instance - * @param iter the object iterator - */ -#define json_object_object_foreachC(obj,iter) \ - for(iter.entry = json_object_get_object(obj)->head; (iter.entry ? (iter.key = (char*)iter.entry->k, iter.val = (struct json_object*)iter.entry->v, iter.entry) : 0); iter.entry = iter.entry->next) - -/* Array type methods */ - -/** Create a new empty json_object of type json_type_array - * @returns a json_object of type json_type_array - */ -extern struct json_object* json_object_new_array(void); - -/** Get the arraylist of a json_object of type json_type_array - * @param obj the json_object instance - * @returns an arraylist - */ -extern struct array_list* json_object_get_array(struct json_object *obj); - -/** Get the length of a json_object of type json_type_array - * @param obj the json_object instance - * @returns an int - */ -extern int json_object_array_length(struct json_object *obj); - -/** Sorts the elements of jso of type json_type_array -* -* Pointers to the json_object pointers will be passed as the two arguments -* to @sort_fn -* -* @param obj the json_object instance -* @param sort_fn a sorting function -*/ -extern void json_object_array_sort(struct json_object *jso, int(__cdecl* sort_fn)(const void *, const void *)); - -/** Add an element to the end of a json_object of type json_type_array - * - * The reference count will *not* be incremented. This is to make adding - * fields to objects in code more compact. If you want to retain a reference - * to an added object you must wrap the passed object with json_object_get - * - * @param obj the json_object instance - * @param val the json_object to be added - */ -extern int json_object_array_add(struct json_object *obj, - struct json_object *val); - -/** Insert or replace an element at a specified index in an array (a json_object of type json_type_array) - * - * The reference count will *not* be incremented. This is to make adding - * fields to objects in code more compact. If you want to retain a reference - * to an added object you must wrap the passed object with json_object_get - * - * The reference count of a replaced object will be decremented. - * - * The array size will be automatically be expanded to the size of the - * index if the index is larger than the current size. - * - * @param obj the json_object instance - * @param idx the index to insert the element at - * @param val the json_object to be added - */ -extern int json_object_array_put_idx(struct json_object *obj, int idx, - struct json_object *val); - -/** Get the element at specificed index of the array (a json_object of type json_type_array) - * @param obj the json_object instance - * @param idx the index to get the element at - * @returns the json_object at the specified index (or NULL) - */ -extern struct json_object* json_object_array_get_idx(struct json_object *obj, - int idx); - -/* json_bool type methods */ - -/** Create a new empty json_object of type json_type_boolean - * @param b a json_bool TRUE or FALSE (0 or 1) - * @returns a json_object of type json_type_boolean - */ -extern struct json_object* json_object_new_boolean(json_bool b); - -/** Get the json_bool value of a json_object - * - * The type is coerced to a json_bool if the passed object is not a json_bool. - * integer and double objects will return FALSE if there value is zero - * or TRUE otherwise. If the passed object is a string it will return - * TRUE if it has a non zero length. If any other object type is passed - * TRUE will be returned if the object is not NULL. - * - * @param obj the json_object instance - * @returns a json_bool - */ -extern json_bool json_object_get_boolean(struct json_object *obj); - - -/* int type methods */ - -/** Create a new empty json_object of type json_type_int - * Note that values are stored as 64-bit values internally. - * To ensure the full range is maintained, use json_object_new_int64 instead. - * @param i the integer - * @returns a json_object of type json_type_int - */ -extern struct json_object* json_object_new_int(int32_t i); - - -/** Create a new empty json_object of type json_type_int - * @param i the integer - * @returns a json_object of type json_type_int - */ -extern struct json_object* json_object_new_int64(int64_t i); - - -/** Get the int value of a json_object - * - * The type is coerced to a int if the passed object is not a int. - * double objects will return their integer conversion. Strings will be - * parsed as an integer. If no conversion exists then 0 is returned - * and errno is set to EINVAL. null is equivalent to 0 (no error values set) - * - * Note that integers are stored internally as 64-bit values. - * If the value of too big or too small to fit into 32-bit, INT32_MAX or - * INT32_MIN are returned, respectively. - * - * @param obj the json_object instance - * @returns an int - */ -extern int32_t json_object_get_int(struct json_object *obj); - -/** Get the int value of a json_object - * - * The type is coerced to a int64 if the passed object is not a int64. - * double objects will return their int64 conversion. Strings will be - * parsed as an int64. If no conversion exists then 0 is returned. - * - * NOTE: Set errno to 0 directly before a call to this function to determine - * whether or not conversion was successful (it does not clear the value for - * you). - * - * @param obj the json_object instance - * @returns an int64 - */ -extern int64_t json_object_get_int64(struct json_object *obj); - - -/* double type methods */ - -/** Create a new empty json_object of type json_type_double - * @param d the double - * @returns a json_object of type json_type_double - */ -extern struct json_object* json_object_new_double(double d); - -/** - * Create a new json_object of type json_type_double, using - * the exact serialized representation of the value. - * - * This allows for numbers that would otherwise get displayed - * inefficiently (e.g. 12.3 => "12.300000000000001") to be - * serialized with the more convenient form. - * - * Note: this is used by json_tokener_parse_ex() to allow for - * an exact re-serialization of a parsed object. - * - * An equivalent sequence of calls is: - * @code - * jso = json_object_new_double(d); - * json_object_set_serializer(d, json_object_userdata_to_json_string, - * strdup(ds), json_object_free_userdata) - * @endcode - * - * @param d the numeric value of the double. - * @param ds the string representation of the double. This will be copied. - */ -extern struct json_object* json_object_new_double_s(double d, const char *ds); - -/** Get the double floating point value of a json_object - * - * The type is coerced to a double if the passed object is not a double. - * integer objects will return their double conversion. Strings will be - * parsed as a double. If no conversion exists then 0.0 is returned and - * errno is set to EINVAL. null is equivalent to 0 (no error values set) - * - * If the value is too big to fit in a double, then the value is set to - * the closest infinity with errno set to ERANGE. If strings cannot be - * converted to their double value, then EINVAL is set & NaN is returned. - * - * Arrays of length 0 are interpreted as 0 (with no error flags set). - * Arrays of length 1 are effectively cast to the equivalent object and - * converted using the above rules. All other arrays set the error to - * EINVAL & return NaN. - * - * NOTE: Set errno to 0 directly before a call to this function to - * determine whether or not conversion was successful (it does not clear - * the value for you). - * - * @param obj the json_object instance - * @returns a double floating point number - */ -extern double json_object_get_double(struct json_object *obj); - - -/* string type methods */ - -/** Create a new empty json_object of type json_type_string - * - * A copy of the string is made and the memory is managed by the json_object - * - * @param s the string - * @returns a json_object of type json_type_string - */ -extern struct json_object* json_object_new_string(const char *s); - -extern struct json_object* json_object_new_string_len(const char *s, size_t len); - -/** Get the string value of a json_object - * - * If the passed object is not of type json_type_string then the JSON - * representation of the object is returned. - * - * The returned string memory is managed by the json_object and will - * be freed when the reference count of the json_object drops to zero. - * - * @param obj the json_object instance - * @returns a string - */ -extern char* json_object_get_string(struct json_object *obj); - -/** Get the string length of a json_object - * - * If the passed object is not of type json_type_string then zero - * will be returned. - * - * @param obj the json_object instance - * @returns int - */ -extern int json_object_get_string_len(struct json_object *obj); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/tools/CustomSetupTool/CustomSetupTool/json-c/json_object_iterator.c b/tools/CustomSetupTool/CustomSetupTool/json-c/json_object_iterator.c deleted file mode 100644 index 7066649c3bc5..000000000000 --- a/tools/CustomSetupTool/CustomSetupTool/json-c/json_object_iterator.c +++ /dev/null @@ -1,168 +0,0 @@ -/** -******************************************************************************* -* @file json_object_iterator.c -* -* Copyright (c) 2009-2012 Hewlett-Packard Development Company, L.P. -* -* This library is free software; you can redistribute it and/or modify -* it under the terms of the MIT license. See COPYING for details. -* -* @brief json-c forces clients to use its private data -* structures for JSON Object iteration. This API -* implementation corrects that by abstracting the -* private json-c details. -* -******************************************************************************* -*/ - -#include - -#include "json.h" -#include "json_object_private.h" - -#include "json_object_iterator.h" - -/** - * How It Works - * - * For each JSON Object, json-c maintains a linked list of zero - * or more lh_entry (link-hash entry) structures inside the - * Object's link-hash table (lh_table). - * - * Each lh_entry structure on the JSON Object's linked list - * represents a single name/value pair. The "next" field of the - * last lh_entry in the list is set to NULL, which terminates - * the list. - * - * We represent a valid iterator that refers to an actual - * name/value pair via a pointer to the pair's lh_entry - * structure set as the iterator's opaque_ field. - * - * We follow json-c's current pair list representation by - * representing a valid "end" iterator (one that refers past the - * last pair) with a NULL value in the iterator's opaque_ field. - * - * A JSON Object without any pairs in it will have the "head" - * field of its lh_table structure set to NULL. For such an - * object, json_object_iter_begin will return an iterator with - * the opaque_ field set to NULL, which is equivalent to the - * "end" iterator. - * - * When iterating, we simply update the iterator's opaque_ field - * to point to the next lh_entry structure in the linked list. - * opaque_ will become NULL once we iterate past the last pair - * in the list, which makes the iterator equivalent to the "end" - * iterator. - */ - -/// Our current representation of the "end" iterator; -/// -/// @note May not always be NULL -static const void* kObjectEndIterValue = NULL; - -/** - * **************************************************************************** - */ -struct json_object_iterator -json_object_iter_begin(struct json_object* obj) -{ - struct json_object_iterator iter; - struct lh_table* pTable; - - /// @note json_object_get_object will return NULL if passed NULL - /// or a non-json_type_object instance - pTable = json_object_get_object(obj); - JASSERT(NULL != pTable); - - /// @note For a pair-less Object, head is NULL, which matches our - /// definition of the "end" iterator - iter.opaque_ = pTable->head; - return iter; -} - -/** - * **************************************************************************** - */ -struct json_object_iterator -json_object_iter_end(const struct json_object* obj) -{ - struct json_object_iterator iter; - - JASSERT(NULL != obj); - JASSERT(json_object_is_type(obj, json_type_object)); - - iter.opaque_ = kObjectEndIterValue; - - return iter; -} - -/** - * **************************************************************************** - */ -void -json_object_iter_next(struct json_object_iterator* iter) -{ - JASSERT(NULL != iter); - JASSERT(kObjectEndIterValue != iter->opaque_); - - iter->opaque_ = ((struct lh_entry *)iter->opaque_)->next; -} - - -/** - * **************************************************************************** - */ -const char* -json_object_iter_peek_name(const struct json_object_iterator* iter) -{ - JASSERT(NULL != iter); - JASSERT(kObjectEndIterValue != iter->opaque_); - - return (const char*)(((struct lh_entry *)iter->opaque_)->k); -} - - -/** - * **************************************************************************** - */ -struct json_object* -json_object_iter_peek_value(const struct json_object_iterator* iter) -{ - JASSERT(NULL != iter); - JASSERT(kObjectEndIterValue != iter->opaque_); - - return (struct json_object*)(((struct lh_entry *)iter->opaque_)->v); -} - - -/** - * **************************************************************************** - */ -json_bool -json_object_iter_equal(const struct json_object_iterator* iter1, - const struct json_object_iterator* iter2) -{ - JASSERT(NULL != iter1); - JASSERT(NULL != iter2); - - return (iter1->opaque_ == iter2->opaque_); -} - - -/** - * **************************************************************************** - */ -struct json_object_iterator -json_object_iter_init_default(void) -{ - struct json_object_iterator iter; - - /** - * @note Make this a negative, invalid value, such that - * accidental access to it would likely be trapped by the - * hardware as an invalid address. - */ - iter.opaque_ = NULL; - - return iter; -} diff --git a/tools/CustomSetupTool/CustomSetupTool/json-c/json_object_iterator.h b/tools/CustomSetupTool/CustomSetupTool/json-c/json_object_iterator.h deleted file mode 100644 index 44c9fb25b6ca..000000000000 --- a/tools/CustomSetupTool/CustomSetupTool/json-c/json_object_iterator.h +++ /dev/null @@ -1,239 +0,0 @@ -/** -******************************************************************************* -* @file json_object_iterator.h -* -* Copyright (c) 2009-2012 Hewlett-Packard Development Company, L.P. -* -* This library is free software; you can redistribute it and/or modify -* it under the terms of the MIT license. See COPYING for details. -* -* @brief json-c forces clients to use its private data -* structures for JSON Object iteration. This API -* corrects that by abstracting the private json-c -* details. -* -* API attributes:
    -* * Thread-safe: NO
    -* * Reentrant: NO -* -******************************************************************************* -*/ - - -#ifndef JSON_OBJECT_ITERATOR_H -#define JSON_OBJECT_ITERATOR_H - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * Forward declaration for the opaque iterator information. - */ -struct json_object_iter_info_; - -/** - * The opaque iterator that references a name/value pair within - * a JSON Object instance or the "end" iterator value. - */ -struct json_object_iterator { - const void* opaque_; -}; - - -/** - * forward declaration of json-c's JSON value instance structure - */ -struct json_object; - - -/** - * Initializes an iterator structure to a "default" value that - * is convenient for initializing an iterator variable to a - * default state (e.g., initialization list in a class' - * constructor). - * - * @code - * struct json_object_iterator iter = json_object_iter_init_default(); - * MyClass() : iter_(json_object_iter_init_default()) - * @endcode - * - * @note The initialized value doesn't reference any specific - * pair, is considered an invalid iterator, and MUST NOT - * be passed to any json-c API that expects a valid - * iterator. - * - * @note User and internal code MUST NOT make any assumptions - * about and dependencies on the value of the "default" - * iterator value. - * - * @return json_object_iterator - */ -struct json_object_iterator -json_object_iter_init_default(void); - -/** Retrieves an iterator to the first pair of the JSON Object. - * - * @warning Any modification of the underlying pair invalidates all - * iterators to that pair. - * - * @param obj JSON Object instance (MUST be of type json_object) - * - * @return json_object_iterator If the JSON Object has at - * least one pair, on return, the iterator refers - * to the first pair. If the JSON Object doesn't - * have any pairs, the returned iterator is - * equivalent to the "end" iterator for the same - * JSON Object instance. - * - * @code - * struct json_object_iterator it; - * struct json_object_iterator itEnd; - * struct json_object* obj; - * - * obj = json_tokener_parse("{'first':'george', 'age':100}"); - * it = json_object_iter_begin(obj); - * itEnd = json_object_iter_end(obj); - * - * while (!json_object_iter_equal(&it, &itEnd)) { - * printf("%s\n", - * json_object_iter_peek_name(&it)); - * json_object_iter_next(&it); - * } - * - * @endcode - */ -struct json_object_iterator -json_object_iter_begin(struct json_object* obj); - -/** Retrieves the iterator that represents the position beyond the - * last pair of the given JSON Object instance. - * - * @warning Do NOT write code that assumes that the "end" - * iterator value is NULL, even if it is so in a - * particular instance of the implementation. - * - * @note The reason we do not (and MUST NOT) provide - * "json_object_iter_is_end(json_object_iterator* iter)" - * type of API is because it would limit the underlying - * representation of name/value containment (or force us - * to add additional, otherwise unnecessary, fields to - * the iterator structure). The "end" iterator and the - * equality test method, on the other hand, permit us to - * cleanly abstract pretty much any reasonable underlying - * representation without burdening the iterator - * structure with unnecessary data. - * - * @note For performance reasons, memorize the "end" iterator prior - * to any loop. - * - * @param obj JSON Object instance (MUST be of type json_object) - * - * @return json_object_iterator On return, the iterator refers - * to the "end" of the Object instance's pairs - * (i.e., NOT the last pair, but "beyond the last - * pair" value) - */ -struct json_object_iterator -json_object_iter_end(const struct json_object* obj); - -/** Returns an iterator to the next pair, if any - * - * @warning Any modification of the underlying pair - * invalidates all iterators to that pair. - * - * @param iter [IN/OUT] Pointer to iterator that references a - * name/value pair; MUST be a valid, non-end iterator. - * WARNING: bad things will happen if invalid or "end" - * iterator is passed. Upon return will contain the - * reference to the next pair if there is one; if there - * are no more pairs, will contain the "end" iterator - * value, which may be compared against the return value - * of json_object_iter_end() for the same JSON Object - * instance. - */ -void -json_object_iter_next(struct json_object_iterator* iter); - - -/** Returns a const pointer to the name of the pair referenced - * by the given iterator. - * - * @param iter pointer to iterator that references a name/value - * pair; MUST be a valid, non-end iterator. - * - * @warning bad things will happen if an invalid or - * "end" iterator is passed. - * - * @return const char* Pointer to the name of the referenced - * name/value pair. The name memory belongs to the - * name/value pair, will be freed when the pair is - * deleted or modified, and MUST NOT be modified or - * freed by the user. - */ -const char* -json_object_iter_peek_name(const struct json_object_iterator* iter); - - -/** Returns a pointer to the json-c instance representing the - * value of the referenced name/value pair, without altering - * the instance's reference count. - * - * @param iter pointer to iterator that references a name/value - * pair; MUST be a valid, non-end iterator. - * - * @warning bad things will happen if invalid or - * "end" iterator is passed. - * - * @return struct json_object* Pointer to the json-c value - * instance of the referenced name/value pair; the - * value's reference count is not changed by this - * function: if you plan to hold on to this json-c node, - * take a look at json_object_get() and - * json_object_put(). IMPORTANT: json-c API represents - * the JSON Null value as a NULL json_object instance - * pointer. - */ -struct json_object* -json_object_iter_peek_value(const struct json_object_iterator* iter); - - -/** Tests two iterators for equality. Typically used to test - * for end of iteration by comparing an iterator to the - * corresponding "end" iterator (that was derived from the same - * JSON Object instance). - * - * @note The reason we do not (and MUST NOT) provide - * "json_object_iter_is_end(json_object_iterator* iter)" - * type of API is because it would limit the underlying - * representation of name/value containment (or force us - * to add additional, otherwise unnecessary, fields to - * the iterator structure). The equality test method, on - * the other hand, permits us to cleanly abstract pretty - * much any reasonable underlying representation. - * - * @param iter1 Pointer to first valid, non-NULL iterator - * @param iter2 POinter to second valid, non-NULL iterator - * - * @warning if a NULL iterator pointer or an uninitialized - * or invalid iterator, or iterators derived from - * different JSON Object instances are passed, bad things - * will happen! - * - * @return json_bool non-zero if iterators are equal (i.e., both - * reference the same name/value pair or are both at - * "end"); zero if they are not equal. - */ -json_bool -json_object_iter_equal(const struct json_object_iterator* iter1, - const struct json_object_iterator* iter2); - - -#ifdef __cplusplus -} -#endif - - -#endif /* JSON_OBJECT_ITERATOR_H */ diff --git a/tools/CustomSetupTool/CustomSetupTool/json-c/json_object_private.h b/tools/CustomSetupTool/CustomSetupTool/json-c/json_object_private.h deleted file mode 100644 index deff7e8df48f..000000000000 --- a/tools/CustomSetupTool/CustomSetupTool/json-c/json_object_private.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * $Id: json_object_private.h,v 1.4 2006/01/26 02:16:28 mclark Exp $ - * - * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. - * Michael Clark - * - * This library is free software; you can redistribute it and/or modify - * it under the terms of the MIT license. See COPYING for details. - * - */ - -#ifndef _json_object_private_h_ -#define _json_object_private_h_ - -#ifdef __cplusplus -extern "C" { -#endif - -typedef void (json_object_private_delete_fn)(struct json_object *o); - -struct json_object -{ - enum json_type o_type; - json_object_private_delete_fn *_delete; - json_object_to_json_string_fn *_to_json_string; - int _ref_count; - struct printbuf *_pb; - union data { - json_bool c_boolean; - double c_double; - int64_t c_int64; - struct lh_table *c_object; - struct array_list *c_array; - struct { - char *str; - size_t len; - } c_string; - } o; - json_object_delete_fn *_user_delete; - void *_userdata; -}; - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/tools/CustomSetupTool/CustomSetupTool/json-c/json_tokener.c b/tools/CustomSetupTool/CustomSetupTool/json-c/json_tokener.c deleted file mode 100644 index 2959cbd6aea2..000000000000 --- a/tools/CustomSetupTool/CustomSetupTool/json-c/json_tokener.c +++ /dev/null @@ -1,888 +0,0 @@ -/* - * $Id: json_tokener.c,v 1.20 2006/07/25 03:24:50 mclark Exp $ - * - * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. - * Michael Clark - * - * This library is free software; you can redistribute it and/or modify - * it under the terms of the MIT license. See COPYING for details. - * - * - * Copyright (c) 2008-2009 Yahoo! Inc. All rights reserved. - * The copyrights to the contents of this file are licensed under the MIT License - * (http://www.opensource.org/licenses/mit-license.php) - */ - -#include "config.h" - -#include -#include -#include -#include -#include -#include -#include - -#include "bits.h" -#include "debug.h" -#include "printbuf.h" -#include "arraylist.h" -#include "json_inttypes.h" -#include "json_object.h" -#include "json_tokener.h" -#include "json_util.h" - -#ifdef HAVE_LOCALE_H -#include -#endif /* HAVE_LOCALE_H */ - -#if !HAVE_STRDUP && defined(_MSC_VER) - /* MSC has the version as _strdup */ -# define strdup _strdup -#elif !HAVE_STRDUP -# error You do not have strdup on your system. -#endif /* HAVE_STRDUP */ - -#if !HAVE_STRNCASECMP && defined(_MSC_VER) - /* MSC has the version as _strnicmp */ -# define strncasecmp _strnicmp -#elif !HAVE_STRNCASECMP -# error You do not have strncasecmp on your system. -#endif /* HAVE_STRNCASECMP */ - -/* Use C99 NAN by default; if not available, nan("") should work too. */ -#ifndef NAN -#define NAN nan("") -#endif /* !NAN */ - -static const char json_null_str[] = "null"; -static const int json_null_str_len = sizeof(json_null_str) - 1; -static const char json_inf_str[] = "Infinity"; -static const int json_inf_str_len = sizeof(json_inf_str) - 1; -static const char json_nan_str[] = "NaN"; -static const int json_nan_str_len = sizeof(json_nan_str) - 1; -static const char json_true_str[] = "true"; -static const int json_true_str_len = sizeof(json_true_str) - 1; -static const char json_false_str[] = "false"; -static const int json_false_str_len = sizeof(json_false_str) - 1; - -static const char* json_tokener_errors[] = { - "success", - "continue", - "nesting too deep", - "unexpected end of data", - "unexpected character", - "null expected", - "boolean expected", - "number expected", - "array value separator ',' expected", - "quoted object property name expected", - "object property name separator ':' expected", - "object value separator ',' expected", - "invalid string sequence", - "expected comment", - "buffer size overflow" -}; - -const char *json_tokener_error_desc(enum json_tokener_error jerr) -{ - int jerr_int = (int)jerr; - if (jerr_int < 0 || jerr_int >= (int)(sizeof(json_tokener_errors) / sizeof(json_tokener_errors[0]))) - return "Unknown error, invalid json_tokener_error value passed to json_tokener_error_desc()"; - return json_tokener_errors[jerr]; -} - -enum json_tokener_error json_tokener_get_error(json_tokener *tok) -{ - return tok->err; -} - -/* Stuff for decoding unicode sequences */ -#define IS_HIGH_SURROGATE(uc) (((uc) & 0xFC00) == 0xD800) -#define IS_LOW_SURROGATE(uc) (((uc) & 0xFC00) == 0xDC00) -#define DECODE_SURROGATE_PAIR(hi,lo) ((((hi) & 0x3FF) << 10) + ((lo) & 0x3FF) + 0x10000) -static unsigned char utf8_replacement_char[3] = { 0xEF, 0xBF, 0xBD }; - -struct json_tokener* json_tokener_new_ex(int depth) -{ - struct json_tokener *tok; - - tok = (struct json_tokener*)calloc(1, sizeof(struct json_tokener)); - if (!tok) return NULL; - tok->stack = (struct json_tokener_srec *)calloc(depth, sizeof(struct json_tokener_srec)); - if (!tok->stack) { - free(tok); - return NULL; - } - tok->pb = printbuf_new(); - tok->max_depth = depth; - json_tokener_reset(tok); - return tok; -} - -struct json_tokener* json_tokener_new(void) -{ - return json_tokener_new_ex(JSON_TOKENER_DEFAULT_DEPTH); -} - -void json_tokener_free(struct json_tokener *tok) -{ - json_tokener_reset(tok); - if (tok->pb) printbuf_free(tok->pb); - if (tok->stack) free(tok->stack); - free(tok); -} - -static void json_tokener_reset_level(struct json_tokener *tok, int depth) -{ - tok->stack[depth].state = json_tokener_state_eatws; - tok->stack[depth].saved_state = json_tokener_state_start; - json_object_put(tok->stack[depth].current); - tok->stack[depth].current = NULL; - free(tok->stack[depth].obj_field_name); - tok->stack[depth].obj_field_name = NULL; -} - -void json_tokener_reset(struct json_tokener *tok) -{ - int i; - if (!tok) - return; - - for(i = tok->depth; i >= 0; i--) - json_tokener_reset_level(tok, i); - tok->depth = 0; - tok->err = json_tokener_success; -} - -struct json_object* json_tokener_parse(const char *str) -{ - enum json_tokener_error jerr_ignored; - struct json_object* obj; - obj = json_tokener_parse_verbose(str, &jerr_ignored); - return obj; -} - -struct json_object* json_tokener_parse_verbose(const char *str, enum json_tokener_error *error) -{ - struct json_tokener* tok; - struct json_object* obj; - - tok = json_tokener_new(); - if (!tok) - return NULL; - obj = json_tokener_parse_ex(tok, str, -1); - *error = tok->err; - if(tok->err != json_tokener_success) { - if (obj != NULL) - json_object_put(obj); - obj = NULL; - } - - json_tokener_free(tok); - return obj; -} - -#define state tok->stack[tok->depth].state -#define saved_state tok->stack[tok->depth].saved_state -#define current tok->stack[tok->depth].current -#define obj_field_name tok->stack[tok->depth].obj_field_name - -/* Optimization: - * json_tokener_parse_ex() consumed a lot of CPU in its main loop, - * iterating character-by character. A large performance boost is - * achieved by using tighter loops to locally handle units such as - * comments and strings. Loops that handle an entire token within - * their scope also gather entire strings and pass them to - * printbuf_memappend() in a single call, rather than calling - * printbuf_memappend() one char at a time. - * - * PEEK_CHAR() and ADVANCE_CHAR() macros are used for code that is - * common to both the main loop and the tighter loops. - */ - -/* PEEK_CHAR(dest, tok) macro: - * Peeks at the current char and stores it in dest. - * Returns 1 on success, sets tok->err and returns 0 if no more chars. - * Implicit inputs: str, len vars - */ -#define PEEK_CHAR(dest, tok) \ - (((tok)->char_offset == len) ? \ - (((tok)->depth == 0 && state == json_tokener_state_eatws && saved_state == json_tokener_state_finish) ? \ - (((tok)->err = json_tokener_success), 0) \ - : \ - (((tok)->err = json_tokener_continue), 0) \ - ) : \ - (((dest) = *str), 1) \ - ) - -/* ADVANCE_CHAR() macro: - * Incrementes str & tok->char_offset. - * For convenience of existing conditionals, returns the old value of c (0 on eof) - * Implicit inputs: c var - */ -#define ADVANCE_CHAR(str, tok) \ - ( ++(str), ((tok)->char_offset)++, c) - - -/* End optimization macro defs */ - - -struct json_object* json_tokener_parse_ex(struct json_tokener *tok, - const char *str, int len) -{ - struct json_object *obj = NULL; - char c = '\1'; -#ifdef HAVE_SETLOCALE - char *oldlocale=NULL, *tmplocale; - - tmplocale = setlocale(LC_NUMERIC, NULL); - if (tmplocale) oldlocale = strdup(tmplocale); - setlocale(LC_NUMERIC, "C"); -#endif - - tok->char_offset = 0; - tok->err = json_tokener_success; - - /* this interface is presently not 64-bit clean due to the int len argument - and the internal printbuf interface that takes 32-bit int len arguments - so the function limits the maximum string size to INT32_MAX (2GB). - If the function is called with len == -1 then strlen is called to check - the string length is less than INT32_MAX (2GB) */ - if ((len < -1) || (len == -1 && strlen(str) > INT32_MAX)) { - tok->err = json_tokener_error_size; - return NULL; - } - - while (PEEK_CHAR(c, tok)) { - - redo_char: - switch(state) { - - case json_tokener_state_eatws: - /* Advance until we change state */ - while (isspace((int)c)) { - if ((!ADVANCE_CHAR(str, tok)) || (!PEEK_CHAR(c, tok))) - goto out; - } - if(c == '/' && !(tok->flags & JSON_TOKENER_STRICT)) { - printbuf_reset(tok->pb); - printbuf_memappend_fast(tok->pb, &c, 1); - state = json_tokener_state_comment_start; - } else { - state = saved_state; - goto redo_char; - } - break; - - case json_tokener_state_start: - switch(c) { - case '{': - state = json_tokener_state_eatws; - saved_state = json_tokener_state_object_field_start; - current = json_object_new_object(); - break; - case '[': - state = json_tokener_state_eatws; - saved_state = json_tokener_state_array; - current = json_object_new_array(); - break; - case 'I': - case 'i': - state = json_tokener_state_inf; - printbuf_reset(tok->pb); - tok->st_pos = 0; - goto redo_char; - case 'N': - case 'n': - state = json_tokener_state_null; // or NaN - printbuf_reset(tok->pb); - tok->st_pos = 0; - goto redo_char; - case '\'': - if (tok->flags & JSON_TOKENER_STRICT) { - /* in STRICT mode only double-quote are allowed */ - tok->err = json_tokener_error_parse_unexpected; - goto out; - } - case '"': - state = json_tokener_state_string; - printbuf_reset(tok->pb); - tok->quote_char = c; - break; - case 'T': - case 't': - case 'F': - case 'f': - state = json_tokener_state_boolean; - printbuf_reset(tok->pb); - tok->st_pos = 0; - goto redo_char; -#if defined(__GNUC__) - case '0' ... '9': -#else - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': -#endif - case '-': - state = json_tokener_state_number; - printbuf_reset(tok->pb); - tok->is_double = 0; - goto redo_char; - default: - tok->err = json_tokener_error_parse_unexpected; - goto out; - } - break; - - case json_tokener_state_finish: - if(tok->depth == 0) goto out; - obj = json_object_get(current); - json_tokener_reset_level(tok, tok->depth); - tok->depth--; - goto redo_char; - - case json_tokener_state_inf: /* aka starts with 'i' */ - { - int size; - int size_inf; - int is_negative = 0; - - printbuf_memappend_fast(tok->pb, &c, 1); - size = json_min(tok->st_pos+1, json_null_str_len); - size_inf = json_min(tok->st_pos+1, json_inf_str_len); - char *infbuf = tok->pb->buf; - if (*infbuf == '-') - { - infbuf++; - is_negative = 1; - } - if ((!(tok->flags & JSON_TOKENER_STRICT) && - strncasecmp(json_inf_str, infbuf, size_inf) == 0) || - (strncmp(json_inf_str, infbuf, size_inf) == 0) - ) - { - if (tok->st_pos == json_inf_str_len) - { - current = json_object_new_double(is_negative ? -INFINITY : INFINITY); - saved_state = json_tokener_state_finish; - state = json_tokener_state_eatws; - goto redo_char; - } - } else { - tok->err = json_tokener_error_parse_unexpected; - goto out; - } - tok->st_pos++; - } - break; - case json_tokener_state_null: /* aka starts with 'n' */ - { - int size; - int size_nan; - printbuf_memappend_fast(tok->pb, &c, 1); - size = json_min(tok->st_pos+1, json_null_str_len); - size_nan = json_min(tok->st_pos+1, json_nan_str_len); - if((!(tok->flags & JSON_TOKENER_STRICT) && - strncasecmp(json_null_str, tok->pb->buf, size) == 0) - || (strncmp(json_null_str, tok->pb->buf, size) == 0) - ) { - if (tok->st_pos == json_null_str_len) { - current = NULL; - saved_state = json_tokener_state_finish; - state = json_tokener_state_eatws; - goto redo_char; - } - } - else if ((!(tok->flags & JSON_TOKENER_STRICT) && - strncasecmp(json_nan_str, tok->pb->buf, size_nan) == 0) || - (strncmp(json_nan_str, tok->pb->buf, size_nan) == 0) - ) - { - if (tok->st_pos == json_nan_str_len) - { - current = json_object_new_double(NAN); - saved_state = json_tokener_state_finish; - state = json_tokener_state_eatws; - goto redo_char; - } - } else { - tok->err = json_tokener_error_parse_null; - goto out; - } - tok->st_pos++; - } - break; - - case json_tokener_state_comment_start: - if(c == '*') { - state = json_tokener_state_comment; - } else if(c == '/') { - state = json_tokener_state_comment_eol; - } else { - tok->err = json_tokener_error_parse_comment; - goto out; - } - printbuf_memappend_fast(tok->pb, &c, 1); - break; - - case json_tokener_state_comment: - { - /* Advance until we change state */ - const char *case_start = str; - while(c != '*') { - if (!ADVANCE_CHAR(str, tok) || !PEEK_CHAR(c, tok)) { - printbuf_memappend_fast(tok->pb, case_start, str-case_start); - goto out; - } - } - printbuf_memappend_fast(tok->pb, case_start, 1+str-case_start); - state = json_tokener_state_comment_end; - } - break; - - case json_tokener_state_comment_eol: - { - /* Advance until we change state */ - const char *case_start = str; - while(c != '\n') { - if (!ADVANCE_CHAR(str, tok) || !PEEK_CHAR(c, tok)) { - printbuf_memappend_fast(tok->pb, case_start, str-case_start); - goto out; - } - } - printbuf_memappend_fast(tok->pb, case_start, str-case_start); - MC_DEBUG("json_tokener_comment: %s\n", tok->pb->buf); - state = json_tokener_state_eatws; - } - break; - - case json_tokener_state_comment_end: - printbuf_memappend_fast(tok->pb, &c, 1); - if(c == '/') { - MC_DEBUG("json_tokener_comment: %s\n", tok->pb->buf); - state = json_tokener_state_eatws; - } else { - state = json_tokener_state_comment; - } - break; - - case json_tokener_state_string: - { - /* Advance until we change state */ - const char *case_start = str; - while(1) { - if(c == tok->quote_char) { - printbuf_memappend_fast(tok->pb, case_start, str-case_start); - current = json_object_new_string_len(tok->pb->buf, tok->pb->bpos); - saved_state = json_tokener_state_finish; - state = json_tokener_state_eatws; - break; - } else if(c == '\\') { - printbuf_memappend_fast(tok->pb, case_start, str-case_start); - saved_state = json_tokener_state_string; - state = json_tokener_state_string_escape; - break; - } - if (!ADVANCE_CHAR(str, tok) || !PEEK_CHAR(c, tok)) { - printbuf_memappend_fast(tok->pb, case_start, str-case_start); - goto out; - } - } - } - break; - - case json_tokener_state_string_escape: - switch(c) { - case '"': - case '\\': - case '/': - printbuf_memappend_fast(tok->pb, &c, 1); - state = saved_state; - break; - case 'b': - case 'n': - case 'r': - case 't': - case 'f': - if(c == 'b') printbuf_memappend_fast(tok->pb, "\b", 1); - else if(c == 'n') printbuf_memappend_fast(tok->pb, "\n", 1); - else if(c == 'r') printbuf_memappend_fast(tok->pb, "\r", 1); - else if(c == 't') printbuf_memappend_fast(tok->pb, "\t", 1); - else if(c == 'f') printbuf_memappend_fast(tok->pb, "\f", 1); - state = saved_state; - break; - case 'u': - tok->ucs_char = 0; - tok->st_pos = 0; - state = json_tokener_state_escape_unicode; - break; - default: - tok->err = json_tokener_error_parse_string; - goto out; - } - break; - - case json_tokener_state_escape_unicode: - { - unsigned int got_hi_surrogate = 0; - - /* Handle a 4-byte sequence, or two sequences if a surrogate pair */ - while(1) { - if(strchr(json_hex_chars, c)) { - tok->ucs_char += ((unsigned int)hexdigit(c) << ((3-tok->st_pos++)*4)); - if(tok->st_pos == 4) { - unsigned char unescaped_utf[4]; - - if (got_hi_surrogate) { - if (IS_LOW_SURROGATE(tok->ucs_char)) { - /* Recalculate the ucs_char, then fall thru to process normally */ - tok->ucs_char = DECODE_SURROGATE_PAIR(got_hi_surrogate, tok->ucs_char); - } else { - /* Hi surrogate was not followed by a low surrogate */ - /* Replace the hi and process the rest normally */ - printbuf_memappend_fast(tok->pb, (char*)utf8_replacement_char, 3); - } - got_hi_surrogate = 0; - } - - if (tok->ucs_char < 0x80) { - unescaped_utf[0] = tok->ucs_char; - printbuf_memappend_fast(tok->pb, (char*)unescaped_utf, 1); - } else if (tok->ucs_char < 0x800) { - unescaped_utf[0] = 0xc0 | (tok->ucs_char >> 6); - unescaped_utf[1] = 0x80 | (tok->ucs_char & 0x3f); - printbuf_memappend_fast(tok->pb, (char*)unescaped_utf, 2); - } else if (IS_HIGH_SURROGATE(tok->ucs_char)) { - /* Got a high surrogate. Remember it and look for the - * the beginning of another sequence, which should be the - * low surrogate. - */ - got_hi_surrogate = tok->ucs_char; - /* Not at end, and the next two chars should be "\u" */ - if ((tok->char_offset+1 != len) && - (tok->char_offset+2 != len) && - (str[1] == '\\') && - (str[2] == 'u')) - { - /* Advance through the 16 bit surrogate, and move on to the - * next sequence. The next step is to process the following - * characters. - */ - if( !ADVANCE_CHAR(str, tok) || !ADVANCE_CHAR(str, tok) ) { - printbuf_memappend_fast(tok->pb, (char*)utf8_replacement_char, 3); - } - /* Advance to the first char of the next sequence and - * continue processing with the next sequence. - */ - if (!ADVANCE_CHAR(str, tok) || !PEEK_CHAR(c, tok)) { - printbuf_memappend_fast(tok->pb, (char*)utf8_replacement_char, 3); - goto out; - } - tok->ucs_char = 0; - tok->st_pos = 0; - continue; /* other json_tokener_state_escape_unicode */ - } else { - /* Got a high surrogate without another sequence following - * it. Put a replacement char in for the hi surrogate - * and pretend we finished. - */ - printbuf_memappend_fast(tok->pb, (char*)utf8_replacement_char, 3); - } - } else if (IS_LOW_SURROGATE(tok->ucs_char)) { - /* Got a low surrogate not preceded by a high */ - printbuf_memappend_fast(tok->pb, (char*)utf8_replacement_char, 3); - } else if (tok->ucs_char < 0x10000) { - unescaped_utf[0] = 0xe0 | (tok->ucs_char >> 12); - unescaped_utf[1] = 0x80 | ((tok->ucs_char >> 6) & 0x3f); - unescaped_utf[2] = 0x80 | (tok->ucs_char & 0x3f); - printbuf_memappend_fast(tok->pb, (char*)unescaped_utf, 3); - } else if (tok->ucs_char < 0x110000) { - unescaped_utf[0] = 0xf0 | ((tok->ucs_char >> 18) & 0x07); - unescaped_utf[1] = 0x80 | ((tok->ucs_char >> 12) & 0x3f); - unescaped_utf[2] = 0x80 | ((tok->ucs_char >> 6) & 0x3f); - unescaped_utf[3] = 0x80 | (tok->ucs_char & 0x3f); - printbuf_memappend_fast(tok->pb, (char*)unescaped_utf, 4); - } else { - /* Don't know what we got--insert the replacement char */ - printbuf_memappend_fast(tok->pb, (char*)utf8_replacement_char, 3); - } - state = saved_state; - break; - } - } else { - tok->err = json_tokener_error_parse_string; - goto out; - } - if (!ADVANCE_CHAR(str, tok) || !PEEK_CHAR(c, tok)) { - if (got_hi_surrogate) /* Clean up any pending chars */ - printbuf_memappend_fast(tok->pb, (char*)utf8_replacement_char, 3); - goto out; - } - } - } - break; - - case json_tokener_state_boolean: - { - int size1, size2; - printbuf_memappend_fast(tok->pb, &c, 1); - size1 = json_min(tok->st_pos+1, json_true_str_len); - size2 = json_min(tok->st_pos+1, json_false_str_len); - if((!(tok->flags & JSON_TOKENER_STRICT) && - strncasecmp(json_true_str, tok->pb->buf, size1) == 0) - || (strncmp(json_true_str, tok->pb->buf, size1) == 0) - ) { - if(tok->st_pos == json_true_str_len) { - current = json_object_new_boolean(1); - saved_state = json_tokener_state_finish; - state = json_tokener_state_eatws; - goto redo_char; - } - } else if((!(tok->flags & JSON_TOKENER_STRICT) && - strncasecmp(json_false_str, tok->pb->buf, size2) == 0) - || (strncmp(json_false_str, tok->pb->buf, size2) == 0)) { - if(tok->st_pos == json_false_str_len) { - current = json_object_new_boolean(0); - saved_state = json_tokener_state_finish; - state = json_tokener_state_eatws; - goto redo_char; - } - } else { - tok->err = json_tokener_error_parse_boolean; - goto out; - } - tok->st_pos++; - } - break; - - case json_tokener_state_number: - { - /* Advance until we change state */ - const char *case_start = str; - int case_len=0; - while(c && strchr(json_number_chars, c)) { - ++case_len; - if(c == '.' || c == 'e' || c == 'E') - tok->is_double = 1; - if (!ADVANCE_CHAR(str, tok) || !PEEK_CHAR(c, tok)) { - printbuf_memappend_fast(tok->pb, case_start, case_len); - goto out; - } - } - if (case_len>0) - printbuf_memappend_fast(tok->pb, case_start, case_len); - - // Check for -Infinity - if (tok->pb->buf[0] == '-' && case_len == 1 && - (c == 'i' || c == 'I')) - { - state = json_tokener_state_inf; - goto redo_char; - } - } - { - int64_t num64; - double numd; - if (!tok->is_double && json_parse_int64(tok->pb->buf, &num64) == 0) { - if (num64 && tok->pb->buf[0]=='0' && (tok->flags & JSON_TOKENER_STRICT)) { - /* in strict mode, number must not start with 0 */ - tok->err = json_tokener_error_parse_number; - goto out; - } - current = json_object_new_int64(num64); - } - else if(tok->is_double && json_parse_double(tok->pb->buf, &numd) == 0) - { - current = json_object_new_double_s(numd, tok->pb->buf); - } else { - tok->err = json_tokener_error_parse_number; - goto out; - } - saved_state = json_tokener_state_finish; - state = json_tokener_state_eatws; - goto redo_char; - } - break; - - case json_tokener_state_array_after_sep: - case json_tokener_state_array: - if(c == ']') { - if (state == json_tokener_state_array_after_sep && - (tok->flags & JSON_TOKENER_STRICT)) - { - tok->err = json_tokener_error_parse_unexpected; - goto out; - } - saved_state = json_tokener_state_finish; - state = json_tokener_state_eatws; - } else { - if(tok->depth >= tok->max_depth-1) { - tok->err = json_tokener_error_depth; - goto out; - } - state = json_tokener_state_array_add; - tok->depth++; - json_tokener_reset_level(tok, tok->depth); - goto redo_char; - } - break; - - case json_tokener_state_array_add: - json_object_array_add(current, obj); - saved_state = json_tokener_state_array_sep; - state = json_tokener_state_eatws; - goto redo_char; - - case json_tokener_state_array_sep: - if(c == ']') { - saved_state = json_tokener_state_finish; - state = json_tokener_state_eatws; - } else if(c == ',') { - saved_state = json_tokener_state_array_after_sep; - state = json_tokener_state_eatws; - } else { - tok->err = json_tokener_error_parse_array; - goto out; - } - break; - - case json_tokener_state_object_field_start: - case json_tokener_state_object_field_start_after_sep: - if(c == '}') { - if (state == json_tokener_state_object_field_start_after_sep && - (tok->flags & JSON_TOKENER_STRICT)) - { - tok->err = json_tokener_error_parse_unexpected; - goto out; - } - saved_state = json_tokener_state_finish; - state = json_tokener_state_eatws; - } else if (c == '"' || c == '\'') { - tok->quote_char = c; - printbuf_reset(tok->pb); - state = json_tokener_state_object_field; - } else { - tok->err = json_tokener_error_parse_object_key_name; - goto out; - } - break; - - case json_tokener_state_object_field: - { - /* Advance until we change state */ - const char *case_start = str; - while(1) { - if(c == tok->quote_char) { - printbuf_memappend_fast(tok->pb, case_start, str-case_start); - obj_field_name = strdup(tok->pb->buf); - saved_state = json_tokener_state_object_field_end; - state = json_tokener_state_eatws; - break; - } else if(c == '\\') { - printbuf_memappend_fast(tok->pb, case_start, str-case_start); - saved_state = json_tokener_state_object_field; - state = json_tokener_state_string_escape; - break; - } - if (!ADVANCE_CHAR(str, tok) || !PEEK_CHAR(c, tok)) { - printbuf_memappend_fast(tok->pb, case_start, str-case_start); - goto out; - } - } - } - break; - - case json_tokener_state_object_field_end: - if(c == ':') { - saved_state = json_tokener_state_object_value; - state = json_tokener_state_eatws; - } else { - tok->err = json_tokener_error_parse_object_key_sep; - goto out; - } - break; - - case json_tokener_state_object_value: - if(tok->depth >= tok->max_depth-1) { - tok->err = json_tokener_error_depth; - goto out; - } - state = json_tokener_state_object_value_add; - tok->depth++; - json_tokener_reset_level(tok, tok->depth); - goto redo_char; - - case json_tokener_state_object_value_add: - json_object_object_add(current, obj_field_name, obj); - free(obj_field_name); - obj_field_name = NULL; - saved_state = json_tokener_state_object_sep; - state = json_tokener_state_eatws; - goto redo_char; - - case json_tokener_state_object_sep: - if(c == '}') { - saved_state = json_tokener_state_finish; - state = json_tokener_state_eatws; - } else if(c == ',') { - saved_state = json_tokener_state_object_field_start_after_sep; - state = json_tokener_state_eatws; - } else { - tok->err = json_tokener_error_parse_object_value_sep; - goto out; - } - break; - - } - if (!ADVANCE_CHAR(str, tok)) - goto out; - } /* while(POP_CHAR) */ - - out: - if (c && - (state == json_tokener_state_finish) && - (tok->depth == 0) && - (tok->flags & JSON_TOKENER_STRICT)) { - /* unexpected char after JSON data */ - tok->err = json_tokener_error_parse_unexpected; - } - if (!c) { /* We hit an eof char (0) */ - if(state != json_tokener_state_finish && - saved_state != json_tokener_state_finish) - tok->err = json_tokener_error_parse_eof; - } - -#ifdef HAVE_SETLOCALE - setlocale(LC_NUMERIC, oldlocale); - if (oldlocale) free(oldlocale); -#endif - - if (tok->err == json_tokener_success) - { - json_object *ret = json_object_get(current); - int ii; - - /* Partially reset, so we parse additional objects on subsequent calls. */ - for(ii = tok->depth; ii >= 0; ii--) - json_tokener_reset_level(tok, ii); - return ret; - } - - MC_DEBUG("json_tokener_parse_ex: error %s at offset %d\n", - json_tokener_errors[tok->err], tok->char_offset); - return NULL; -} - -void json_tokener_set_flags(struct json_tokener *tok, int flags) -{ - tok->flags = flags; -} diff --git a/tools/CustomSetupTool/CustomSetupTool/json-c/json_tokener.h b/tools/CustomSetupTool/CustomSetupTool/json-c/json_tokener.h deleted file mode 100644 index a72d2bdefe00..000000000000 --- a/tools/CustomSetupTool/CustomSetupTool/json-c/json_tokener.h +++ /dev/null @@ -1,208 +0,0 @@ -/* - * $Id: json_tokener.h,v 1.10 2006/07/25 03:24:50 mclark Exp $ - * - * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. - * Michael Clark - * - * This library is free software; you can redistribute it and/or modify - * it under the terms of the MIT license. See COPYING for details. - * - */ - -#ifndef _json_tokener_h_ -#define _json_tokener_h_ - -#include -#include "json_object.h" - -#ifdef __cplusplus -extern "C" { -#endif - -enum json_tokener_error { - json_tokener_success, - json_tokener_continue, - json_tokener_error_depth, - json_tokener_error_parse_eof, - json_tokener_error_parse_unexpected, - json_tokener_error_parse_null, - json_tokener_error_parse_boolean, - json_tokener_error_parse_number, - json_tokener_error_parse_array, - json_tokener_error_parse_object_key_name, - json_tokener_error_parse_object_key_sep, - json_tokener_error_parse_object_value_sep, - json_tokener_error_parse_string, - json_tokener_error_parse_comment, - json_tokener_error_size -}; - -enum json_tokener_state { - json_tokener_state_eatws, - json_tokener_state_start, - json_tokener_state_finish, - json_tokener_state_null, - json_tokener_state_comment_start, - json_tokener_state_comment, - json_tokener_state_comment_eol, - json_tokener_state_comment_end, - json_tokener_state_string, - json_tokener_state_string_escape, - json_tokener_state_escape_unicode, - json_tokener_state_boolean, - json_tokener_state_number, - json_tokener_state_array, - json_tokener_state_array_add, - json_tokener_state_array_sep, - json_tokener_state_object_field_start, - json_tokener_state_object_field, - json_tokener_state_object_field_end, - json_tokener_state_object_value, - json_tokener_state_object_value_add, - json_tokener_state_object_sep, - json_tokener_state_array_after_sep, - json_tokener_state_object_field_start_after_sep, - json_tokener_state_inf -}; - -struct json_tokener_srec -{ - enum json_tokener_state state, saved_state; - struct json_object *obj; - struct json_object *current; - char *obj_field_name; -}; - -#define JSON_TOKENER_DEFAULT_DEPTH 32 - -struct json_tokener -{ - char *str; - struct printbuf *pb; - int max_depth, depth, is_double, st_pos, char_offset; - enum json_tokener_error err; - unsigned int ucs_char; - char quote_char; - struct json_tokener_srec *stack; - int flags; -}; - -/** - * Be strict when parsing JSON input. Use caution with - * this flag as what is considered valid may become more - * restrictive from one release to the next, causing your - * code to fail on previously working input. - * - * This flag is not set by default. - * - * @see json_tokener_set_flags() - */ -#define JSON_TOKENER_STRICT 0x01 - -/** - * Given an error previously returned by json_tokener_get_error(), - * return a human readable description of the error. - * - * @return a generic error message is returned if an invalid error value is provided. - */ -const char *json_tokener_error_desc(enum json_tokener_error jerr); - -/** - * Retrieve the error caused by the last call to json_tokener_parse_ex(), - * or json_tokener_success if there is no error. - * - * When parsing a JSON string in pieces, if the tokener is in the middle - * of parsing this will return json_tokener_continue. - * - * See also json_tokener_error_desc(). - */ -enum json_tokener_error json_tokener_get_error(struct json_tokener *tok); - -extern struct json_tokener* json_tokener_new(void); -extern struct json_tokener* json_tokener_new_ex(int depth); -extern void json_tokener_free(struct json_tokener *tok); -extern void json_tokener_reset(struct json_tokener *tok); -extern struct json_object* json_tokener_parse(const char *str); -extern struct json_object* json_tokener_parse_verbose(const char *str, enum json_tokener_error *error); - -/** - * Set flags that control how parsing will be done. - */ -extern void json_tokener_set_flags(struct json_tokener *tok, int flags); - -/** - * Parse a string and return a non-NULL json_object if a valid JSON value - * is found. The string does not need to be a JSON object or array; - * it can also be a string, number or boolean value. - * - * A partial JSON string can be parsed. If the parsing is incomplete, - * NULL will be returned and json_tokener_get_error() will be return - * json_tokener_continue. - * json_tokener_parse_ex() can then be called with additional bytes in str - * to continue the parsing. - * - * If json_tokener_parse_ex() returns NULL and the error anything other than - * json_tokener_continue, a fatal error has occurred and parsing must be - * halted. Then tok object must not be re-used until json_tokener_reset() is - * called. - * - * When a valid JSON value is parsed, a non-NULL json_object will be - * returned. Also, json_tokener_get_error() will return json_tokener_success. - * Be sure to check the type with json_object_is_type() or - * json_object_get_type() before using the object. - * - * @b XXX this shouldn't use internal fields: - * Trailing characters after the parsed value do not automatically cause an - * error. It is up to the caller to decide whether to treat this as an - * error or to handle the additional characters, perhaps by parsing another - * json value starting from that point. - * - * Extra characters can be detected by comparing the tok->char_offset against - * the length of the last len parameter passed in. - * - * The tokener does \b not maintain an internal buffer so the caller is - * responsible for calling json_tokener_parse_ex with an appropriate str - * parameter starting with the extra characters. - * - * This interface is presently not 64-bit clean due to the int len argument - * so the function limits the maximum string size to INT32_MAX (2GB). - * If the function is called with len == -1 then strlen is called to check - * the string length is less than INT32_MAX (2GB) - * - * Example: - * @code -json_object *jobj = NULL; -const char *mystring = NULL; -int stringlen = 0; -enum json_tokener_error jerr; -do { - mystring = ... // get JSON string, e.g. read from file, etc... - stringlen = strlen(mystring); - jobj = json_tokener_parse_ex(tok, mystring, stringlen); -} while ((jerr = json_tokener_get_error(tok)) == json_tokener_continue); -if (jerr != json_tokener_success) -{ - fprintf(stderr, "Error: %s\n", json_tokener_error_desc(jerr)); - // Handle errors, as appropriate for your application. -} -if (tok->char_offset < stringlen) // XXX shouldn't access internal fields -{ - // Handle extra characters after parsed object as desired. - // e.g. issue an error, parse another object from that point, etc... -} -// Success, use jobj here. - -@endcode - * - * @param tok a json_tokener previously allocated with json_tokener_new() - * @param str an string with any valid JSON expression, or portion of. This does not need to be null terminated. - * @param len the length of str - */ -extern struct json_object* json_tokener_parse_ex(struct json_tokener *tok, - const char *str, int len); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/tools/CustomSetupTool/CustomSetupTool/json-c/json_util.c b/tools/CustomSetupTool/CustomSetupTool/json-c/json_util.c deleted file mode 100644 index fda5d1ec00a7..000000000000 --- a/tools/CustomSetupTool/CustomSetupTool/json-c/json_util.c +++ /dev/null @@ -1,301 +0,0 @@ -/* - * $Id: json_util.c,v 1.4 2006/01/30 23:07:57 mclark Exp $ - * - * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. - * Michael Clark - * - * This library is free software; you can redistribute it and/or modify - * it under the terms of the MIT license. See COPYING for details. - * - */ - -#include "config.h" -#undef realloc - -#include -#include -#include -#include -#include -#include -#include - -#ifdef HAVE_SYS_TYPES_H -#include -#endif /* HAVE_SYS_TYPES_H */ - -#ifdef HAVE_SYS_STAT_H -#include -#endif /* HAVE_SYS_STAT_H */ - -#ifdef HAVE_FCNTL_H -#include -#endif /* HAVE_FCNTL_H */ - -#ifdef HAVE_UNISTD_H -# include -#endif /* HAVE_UNISTD_H */ - -#ifdef _WIN32 -# define WIN32_LEAN_AND_MEAN -# include -# include -#endif /* defined(_WIN32) */ - -#if !defined(HAVE_OPEN) && defined(_WIN32) -# define open _open -#endif - -#if !defined(HAVE_SNPRINTF) && defined(_MSC_VER) - /* MSC has the version as _snprintf */ -# define snprintf _snprintf -#elif !defined(HAVE_SNPRINTF) -# error You do not have snprintf on your system. -#endif /* HAVE_SNPRINTF */ - -#include "bits.h" -#include "debug.h" -#include "printbuf.h" -#include "json_inttypes.h" -#include "json_object.h" -#include "json_tokener.h" -#include "json_util.h" - -static int sscanf_is_broken = 0; -static int sscanf_is_broken_testdone = 0; -static void sscanf_is_broken_test(void); - -struct json_object* json_object_from_file(const char *filename) -{ - //struct printbuf *pb; - //struct json_object *obj; - //char buf[JSON_FILE_BUF_SIZE]; - //int fd, ret; - - //if((fd = open(filename, O_RDONLY)) < 0) { - // MC_ERROR("json_object_from_file: error opening file %s: %s\n", - // filename, strerror(errno)); - // return NULL; - //} - //if(!(pb = printbuf_new())) { - // close(fd); - // MC_ERROR("json_object_from_file: printbuf_new failed\n"); - // return NULL; - //} - //while((ret = read(fd, buf, JSON_FILE_BUF_SIZE)) > 0) { - // printbuf_memappend(pb, buf, ret); - //} - //close(fd); - //if(ret < 0) { - // MC_ERROR("json_object_from_file: error reading file %s: %s\n", - // filename, strerror(errno)); - // printbuf_free(pb); - // return NULL; - //} - //obj = json_tokener_parse(pb->buf); - //printbuf_free(pb); - return NULL;//obj; -} - -/* extended "format and write to file" function */ - -int json_object_to_file_ext(const char *filename, struct json_object *obj, int flags) -{ - //const char *json_str; - //int fd, ret; - //unsigned int wpos, wsize; - - //if(!obj) { - // MC_ERROR("json_object_to_file: object is null\n"); - // return -1; - //} - - //if((fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT, 0644)) < 0) { - // MC_ERROR("json_object_to_file: error opening file %s: %s\n", - // filename, strerror(errno)); - // return -1; - //} - - //if(!(json_str = json_object_to_json_string_ext(obj,flags))) { - // close(fd); - // return -1; - //} - - //wsize = (unsigned int)(strlen(json_str) & UINT_MAX); /* CAW: probably unnecessary, but the most 64bit safe */ - //wpos = 0; - //while(wpos < wsize) { - // if((ret = write(fd, json_str + wpos, wsize-wpos)) < 0) { - // close(fd); - // MC_ERROR("json_object_to_file: error writing file %s: %s\n", - // filename, strerror(errno)); - // return -1; - // } - - // /* because of the above check for ret < 0, we can safely cast and add */ - // wpos += (unsigned int)ret; - //} - - //close(fd); - return 0; -} - -// backwards compatible "format and write to file" function - -int json_object_to_file(const char *filename, struct json_object *obj) -{ - return json_object_to_file_ext(filename, obj, JSON_C_TO_STRING_PLAIN); -} - -int json_parse_double(const char *buf, double *retval) -{ - return (sscanf_s(buf, "%lf", retval)==1 ? 0 : 1); -} - -/* - * Not all implementations of sscanf actually work properly. - * Check whether the one we're currently using does, and if - * it's broken, enable the workaround code. - */ -static void sscanf_is_broken_test() -{ - int64_t num64; - int ret_errno, is_int64_min, ret_errno2, is_int64_max; - - sscanf_s(" -01234567890123456789012345", "%" SCNd64, &num64); - ret_errno = errno; - is_int64_min = (num64 == INT64_MIN); - - sscanf_s(" 01234567890123456789012345", "%" SCNd64, &num64); - ret_errno2 = errno; - is_int64_max = (num64 == INT64_MAX); - - if (ret_errno != ERANGE || !is_int64_min || - ret_errno2 != ERANGE || !is_int64_max) - { - MC_DEBUG("sscanf_is_broken_test failed, enabling workaround code\n"); - sscanf_is_broken = 1; - } -} - -int json_parse_int64(const char *buf, int64_t *retval) -{ - int64_t num64; - const char *buf_sig_digits; - int orig_has_neg; - int saved_errno; - - if (!sscanf_is_broken_testdone) - { - sscanf_is_broken_test(); - sscanf_is_broken_testdone = 1; - } - - // Skip leading spaces - while (isspace((int)*buf) && *buf) - buf++; - - errno = 0; // sscanf won't always set errno, so initialize - - if (sscanf_s(buf, "%" SCNd64, &num64) != 1) - { - MC_DEBUG("Failed to parse, sscanf != 1\n"); - return 1; - } - - saved_errno = errno; - buf_sig_digits = buf; - orig_has_neg = 0; - if (*buf_sig_digits == '-') - { - buf_sig_digits++; - orig_has_neg = 1; - } - - // Not all sscanf implementations actually work - if (sscanf_is_broken && saved_errno != ERANGE) - { - char buf_cmp[100]; - char *buf_cmp_start = buf_cmp; - int recheck_has_neg = 0; - int buf_cmp_len; - - // Skip leading zeros, but keep at least one digit - while (buf_sig_digits[0] == '0' && buf_sig_digits[1] != '\0') - buf_sig_digits++; - if (num64 == 0) // assume all sscanf impl's will parse -0 to 0 - orig_has_neg = 0; // "-0" is the same as just plain "0" - - _snprintf_s(buf_cmp_start, sizeof(buf_cmp), _TRUNCATE, "%" PRId64, num64); - if (*buf_cmp_start == '-') - { - recheck_has_neg = 1; - buf_cmp_start++; - } - // No need to skip leading spaces or zeros here. - - buf_cmp_len = (int)strlen(buf_cmp_start); - /** - * If the sign is different, or - * some of the digits are different, or - * there is another digit present in the original string - * then we have NOT successfully parsed the value. - */ - if (orig_has_neg != recheck_has_neg || - strncmp(buf_sig_digits, buf_cmp_start, strlen(buf_cmp_start)) != 0 || - ((int)strlen(buf_sig_digits) != buf_cmp_len && - isdigit((int)buf_sig_digits[buf_cmp_len]) - ) - ) - { - saved_errno = ERANGE; - } - } - - // Not all sscanf impl's set the value properly when out of range. - // Always do this, even for properly functioning implementations, - // since it shouldn't slow things down much. - if (saved_errno == ERANGE) - { - if (orig_has_neg) - num64 = INT64_MIN; - else - num64 = INT64_MAX; - } - *retval = num64; - return 0; -} - -#ifndef HAVE_REALLOC -void* rpl_realloc(void* p, size_t n) -{ - if (n == 0) - n = 1; - if (p == 0) - return malloc(n); - return realloc(p, n); -} -#endif - -#define NELEM(a) (sizeof(a) / sizeof(a[0])) -static const char* json_type_name[] = { - /* If you change this, be sure to update the enum json_type definition too */ - "null", - "boolean", - "double", - "int", - "object", - "array", - "string", -}; - -const char *json_type_to_name(enum json_type o_type) -{ - int o_type_int = (int)o_type; - if (o_type_int < 0 || o_type_int >= (int)NELEM(json_type_name)) - { - MC_ERROR("json_type_to_name: type %d is out of range [0,%d]\n", o_type, NELEM(json_type_name)); - return NULL; - } - return json_type_name[o_type]; -} - diff --git a/tools/CustomSetupTool/CustomSetupTool/json-c/json_util.h b/tools/CustomSetupTool/CustomSetupTool/json-c/json_util.h deleted file mode 100644 index 1005e58c5b0d..000000000000 --- a/tools/CustomSetupTool/CustomSetupTool/json-c/json_util.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * $Id: json_util.h,v 1.4 2006/01/30 23:07:57 mclark Exp $ - * - * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. - * Michael Clark - * - * This library is free software; you can redistribute it and/or modify - * it under the terms of the MIT license. See COPYING for details. - * - */ - -#ifndef _json_util_h_ -#define _json_util_h_ - -#include "json_object.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define JSON_FILE_BUF_SIZE 4096 - -/* utility functions */ -extern struct json_object* json_object_from_file(const char *filename); -extern int json_object_to_file(const char *filename, struct json_object *obj); -extern int json_object_to_file_ext(const char *filename, struct json_object *obj, int flags); -extern int json_parse_int64(const char *buf, int64_t *retval); -extern int json_parse_double(const char *buf, double *retval); - - -/** - * Return a string describing the type of the object. - * e.g. "int", or "object", etc... - */ -extern const char *json_type_to_name(enum json_type o_type); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/tools/CustomSetupTool/CustomSetupTool/json-c/libjson.c b/tools/CustomSetupTool/CustomSetupTool/json-c/libjson.c deleted file mode 100644 index 5284fd0e70b7..000000000000 --- a/tools/CustomSetupTool/CustomSetupTool/json-c/libjson.c +++ /dev/null @@ -1,26 +0,0 @@ - -/* dummy source file for compatibility purposes */ - -#if defined(HAVE_CDEFS_H) -#include -#endif - -#ifndef __warn_references - -#if defined(__GNUC__) && defined (HAS_GNU_WARNING_LONG) - -#define __warn_references(sym,msg) \ - __asm__(".section .gnu" #sym ",\n\t.ascii \"" msg "\"\n\t.text"); - -#else -#define __warn_references(sym,msg) /* nothing */ -#endif - -#endif - -#include "json_object.h" - -__warn_references(json_object_get, "Warning: please link against libjson-c instead of libjson"); - -/* __asm__(".section .gnu.warning." __STRING(sym) \ - " ; .ascii \"" msg "\" ; .text") */ diff --git a/tools/CustomSetupTool/CustomSetupTool/json-c/linkhash.c b/tools/CustomSetupTool/CustomSetupTool/json-c/linkhash.c deleted file mode 100644 index 50de485638e7..000000000000 --- a/tools/CustomSetupTool/CustomSetupTool/json-c/linkhash.c +++ /dev/null @@ -1,604 +0,0 @@ -/* - * $Id: linkhash.c,v 1.4 2006/01/26 02:16:28 mclark Exp $ - * - * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. - * Michael Clark - * Copyright (c) 2009 Hewlett-Packard Development Company, L.P. - * - * This library is free software; you can redistribute it and/or modify - * it under the terms of the MIT license. See COPYING for details. - * - */ - -#include -#include -#include -#include -#include -#include - -#include - -#ifdef HAVE_ENDIAN_H -# include /* attempt to define endianness */ -#endif - -#include "random_seed.h" -#include "linkhash.h" - -void lh_abort(const char *msg, ...) -{ - va_list ap; - va_start(ap, msg); - vprintf(msg, ap); - va_end(ap); - exit(1); -} - -unsigned long lh_ptr_hash(const void *k) -{ - /* CAW: refactored to be 64bit nice */ - return (unsigned long)((((ptrdiff_t)k * LH_PRIME) >> 4) & ULONG_MAX); -} - -int lh_ptr_equal(const void *k1, const void *k2) -{ - return (k1 == k2); -} - -/* - * hashlittle from lookup3.c, by Bob Jenkins, May 2006, Public Domain. - * http://burtleburtle.net/bob/c/lookup3.c - * minor modifications to make functions static so no symbols are exported - * minor mofifications to compile with -Werror - */ - -/* -------------------------------------------------------------------------------- -lookup3.c, by Bob Jenkins, May 2006, Public Domain. - -These are functions for producing 32-bit hashes for hash table lookup. -hashword(), hashlittle(), hashlittle2(), hashbig(), mix(), and final() -are externally useful functions. Routines to test the hash are included -if SELF_TEST is defined. You can use this free for any purpose. It's in -the public domain. It has no warranty. - -You probably want to use hashlittle(). hashlittle() and hashbig() -hash byte arrays. hashlittle() is is faster than hashbig() on -little-endian machines. Intel and AMD are little-endian machines. -On second thought, you probably want hashlittle2(), which is identical to -hashlittle() except it returns two 32-bit hashes for the price of one. -You could implement hashbig2() if you wanted but I haven't bothered here. - -If you want to find a hash of, say, exactly 7 integers, do - a = i1; b = i2; c = i3; - mix(a,b,c); - a += i4; b += i5; c += i6; - mix(a,b,c); - a += i7; - final(a,b,c); -then use c as the hash value. If you have a variable length array of -4-byte integers to hash, use hashword(). If you have a byte array (like -a character string), use hashlittle(). If you have several byte arrays, or -a mix of things, see the comments above hashlittle(). - -Why is this so big? I read 12 bytes at a time into 3 4-byte integers, -then mix those integers. This is fast (you can do a lot more thorough -mixing with 12*3 instructions on 3 integers than you can with 3 instructions -on 1 byte), but shoehorning those bytes into integers efficiently is messy. -------------------------------------------------------------------------------- -*/ - -/* - * My best guess at if you are big-endian or little-endian. This may - * need adjustment. - */ -#if (defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && \ - __BYTE_ORDER == __LITTLE_ENDIAN) || \ - (defined(i386) || defined(__i386__) || defined(__i486__) || \ - defined(__i586__) || defined(__i686__) || defined(vax) || defined(MIPSEL)) -# define HASH_LITTLE_ENDIAN 1 -# define HASH_BIG_ENDIAN 0 -#elif (defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) && \ - __BYTE_ORDER == __BIG_ENDIAN) || \ - (defined(sparc) || defined(POWERPC) || defined(mc68000) || defined(sel)) -# define HASH_LITTLE_ENDIAN 0 -# define HASH_BIG_ENDIAN 1 -#else -# define HASH_LITTLE_ENDIAN 0 -# define HASH_BIG_ENDIAN 0 -#endif - -#define hashsize(n) ((uint32_t)1<<(n)) -#define hashmask(n) (hashsize(n)-1) -#define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k)))) - -/* -------------------------------------------------------------------------------- -mix -- mix 3 32-bit values reversibly. - -This is reversible, so any information in (a,b,c) before mix() is -still in (a,b,c) after mix(). - -If four pairs of (a,b,c) inputs are run through mix(), or through -mix() in reverse, there are at least 32 bits of the output that -are sometimes the same for one pair and different for another pair. -This was tested for: -* pairs that differed by one bit, by two bits, in any combination - of top bits of (a,b,c), or in any combination of bottom bits of - (a,b,c). -* "differ" is defined as +, -, ^, or ~^. For + and -, I transformed - the output delta to a Gray code (a^(a>>1)) so a string of 1's (as - is commonly produced by subtraction) look like a single 1-bit - difference. -* the base values were pseudorandom, all zero but one bit set, or - all zero plus a counter that starts at zero. - -Some k values for my "a-=c; a^=rot(c,k); c+=b;" arrangement that -satisfy this are - 4 6 8 16 19 4 - 9 15 3 18 27 15 - 14 9 3 7 17 3 -Well, "9 15 3 18 27 15" didn't quite get 32 bits diffing -for "differ" defined as + with a one-bit base and a two-bit delta. I -used http://burtleburtle.net/bob/hash/avalanche.html to choose -the operations, constants, and arrangements of the variables. - -This does not achieve avalanche. There are input bits of (a,b,c) -that fail to affect some output bits of (a,b,c), especially of a. The -most thoroughly mixed value is c, but it doesn't really even achieve -avalanche in c. - -This allows some parallelism. Read-after-writes are good at doubling -the number of bits affected, so the goal of mixing pulls in the opposite -direction as the goal of parallelism. I did what I could. Rotates -seem to cost as much as shifts on every machine I could lay my hands -on, and rotates are much kinder to the top and bottom bits, so I used -rotates. -------------------------------------------------------------------------------- -*/ -#define mix(a,b,c) \ -{ \ - a -= c; a ^= rot(c, 4); c += b; \ - b -= a; b ^= rot(a, 6); a += c; \ - c -= b; c ^= rot(b, 8); b += a; \ - a -= c; a ^= rot(c,16); c += b; \ - b -= a; b ^= rot(a,19); a += c; \ - c -= b; c ^= rot(b, 4); b += a; \ -} - -/* -------------------------------------------------------------------------------- -final -- final mixing of 3 32-bit values (a,b,c) into c - -Pairs of (a,b,c) values differing in only a few bits will usually -produce values of c that look totally different. This was tested for -* pairs that differed by one bit, by two bits, in any combination - of top bits of (a,b,c), or in any combination of bottom bits of - (a,b,c). -* "differ" is defined as +, -, ^, or ~^. For + and -, I transformed - the output delta to a Gray code (a^(a>>1)) so a string of 1's (as - is commonly produced by subtraction) look like a single 1-bit - difference. -* the base values were pseudorandom, all zero but one bit set, or - all zero plus a counter that starts at zero. - -These constants passed: - 14 11 25 16 4 14 24 - 12 14 25 16 4 14 24 -and these came close: - 4 8 15 26 3 22 24 - 10 8 15 26 3 22 24 - 11 8 15 26 3 22 24 -------------------------------------------------------------------------------- -*/ -#define final(a,b,c) \ -{ \ - c ^= b; c -= rot(b,14); \ - a ^= c; a -= rot(c,11); \ - b ^= a; b -= rot(a,25); \ - c ^= b; c -= rot(b,16); \ - a ^= c; a -= rot(c,4); \ - b ^= a; b -= rot(a,14); \ - c ^= b; c -= rot(b,24); \ -} - - -/* -------------------------------------------------------------------------------- -hashlittle() -- hash a variable-length key into a 32-bit value - k : the key (the unaligned variable-length array of bytes) - length : the length of the key, counting by bytes - initval : can be any 4-byte value -Returns a 32-bit value. Every bit of the key affects every bit of -the return value. Two keys differing by one or two bits will have -totally different hash values. - -The best hash table sizes are powers of 2. There is no need to do -mod a prime (mod is sooo slow!). If you need less than 32 bits, -use a bitmask. For example, if you need only 10 bits, do - h = (h & hashmask(10)); -In which case, the hash table should have hashsize(10) elements. - -If you are hashing n strings (uint8_t **)k, do it like this: - for (i=0, h=0; i 12) - { - a += k[0]; - b += k[1]; - c += k[2]; - mix(a,b,c); - length -= 12; - k += 3; - } - - /*----------------------------- handle the last (probably partial) block */ - /* - * "k[2]&0xffffff" actually reads beyond the end of the string, but - * then masks off the part it's not allowed to read. Because the - * string is aligned, the masked-off tail is in the same word as the - * rest of the string. Every machine with memory protection I've seen - * does it on word boundaries, so is OK with this. But VALGRIND will - * still catch it and complain. The masking trick does make the hash - * noticably faster for short strings (like English words). - */ -#ifndef VALGRIND - - switch(length) - { - case 12: c+=k[2]; b+=k[1]; a+=k[0]; break; - case 11: c+=k[2]&0xffffff; b+=k[1]; a+=k[0]; break; - case 10: c+=k[2]&0xffff; b+=k[1]; a+=k[0]; break; - case 9 : c+=k[2]&0xff; b+=k[1]; a+=k[0]; break; - case 8 : b+=k[1]; a+=k[0]; break; - case 7 : b+=k[1]&0xffffff; a+=k[0]; break; - case 6 : b+=k[1]&0xffff; a+=k[0]; break; - case 5 : b+=k[1]&0xff; a+=k[0]; break; - case 4 : a+=k[0]; break; - case 3 : a+=k[0]&0xffffff; break; - case 2 : a+=k[0]&0xffff; break; - case 1 : a+=k[0]&0xff; break; - case 0 : return c; /* zero length strings require no mixing */ - } - -#else /* make valgrind happy */ - - const uint8_t *k8 = (const uint8_t *)k; - switch(length) - { - case 12: c+=k[2]; b+=k[1]; a+=k[0]; break; - case 11: c+=((uint32_t)k8[10])<<16; /* fall through */ - case 10: c+=((uint32_t)k8[9])<<8; /* fall through */ - case 9 : c+=k8[8]; /* fall through */ - case 8 : b+=k[1]; a+=k[0]; break; - case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */ - case 6 : b+=((uint32_t)k8[5])<<8; /* fall through */ - case 5 : b+=k8[4]; /* fall through */ - case 4 : a+=k[0]; break; - case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */ - case 2 : a+=((uint32_t)k8[1])<<8; /* fall through */ - case 1 : a+=k8[0]; break; - case 0 : return c; - } - -#endif /* !valgrind */ - - } else if (HASH_LITTLE_ENDIAN && ((u.i & 0x1) == 0)) { - const uint16_t *k = (const uint16_t *)key; /* read 16-bit chunks */ - const uint8_t *k8; - - /*--------------- all but last block: aligned reads and different mixing */ - while (length > 12) - { - a += k[0] + (((uint32_t)k[1])<<16); - b += k[2] + (((uint32_t)k[3])<<16); - c += k[4] + (((uint32_t)k[5])<<16); - mix(a,b,c); - length -= 12; - k += 6; - } - - /*----------------------------- handle the last (probably partial) block */ - k8 = (const uint8_t *)k; - switch(length) - { - case 12: c+=k[4]+(((uint32_t)k[5])<<16); - b+=k[2]+(((uint32_t)k[3])<<16); - a+=k[0]+(((uint32_t)k[1])<<16); - break; - case 11: c+=((uint32_t)k8[10])<<16; /* fall through */ - case 10: c+=k[4]; - b+=k[2]+(((uint32_t)k[3])<<16); - a+=k[0]+(((uint32_t)k[1])<<16); - break; - case 9 : c+=k8[8]; /* fall through */ - case 8 : b+=k[2]+(((uint32_t)k[3])<<16); - a+=k[0]+(((uint32_t)k[1])<<16); - break; - case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */ - case 6 : b+=k[2]; - a+=k[0]+(((uint32_t)k[1])<<16); - break; - case 5 : b+=k8[4]; /* fall through */ - case 4 : a+=k[0]+(((uint32_t)k[1])<<16); - break; - case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */ - case 2 : a+=k[0]; - break; - case 1 : a+=k8[0]; - break; - case 0 : return c; /* zero length requires no mixing */ - } - - } else { /* need to read the key one byte at a time */ - const uint8_t *k = (const uint8_t *)key; - - /*--------------- all but the last block: affect some 32 bits of (a,b,c) */ - while (length > 12) - { - a += k[0]; - a += ((uint32_t)k[1])<<8; - a += ((uint32_t)k[2])<<16; - a += ((uint32_t)k[3])<<24; - b += k[4]; - b += ((uint32_t)k[5])<<8; - b += ((uint32_t)k[6])<<16; - b += ((uint32_t)k[7])<<24; - c += k[8]; - c += ((uint32_t)k[9])<<8; - c += ((uint32_t)k[10])<<16; - c += ((uint32_t)k[11])<<24; - mix(a,b,c); - length -= 12; - k += 12; - } - - /*-------------------------------- last block: affect all 32 bits of (c) */ - switch(length) /* all the case statements fall through */ - { - case 12: c+=((uint32_t)k[11])<<24; - case 11: c+=((uint32_t)k[10])<<16; - case 10: c+=((uint32_t)k[9])<<8; - case 9 : c+=k[8]; - case 8 : b+=((uint32_t)k[7])<<24; - case 7 : b+=((uint32_t)k[6])<<16; - case 6 : b+=((uint32_t)k[5])<<8; - case 5 : b+=k[4]; - case 4 : a+=((uint32_t)k[3])<<24; - case 3 : a+=((uint32_t)k[2])<<16; - case 2 : a+=((uint32_t)k[1])<<8; - case 1 : a+=k[0]; - break; - case 0 : return c; - } - } - - final(a,b,c); - return c; -} - -unsigned long lh_char_hash(const void *k) -{ - static volatile int random_seed = -1; - - if (random_seed == -1) { - int seed; - /* we can't use -1 as it is the unitialized sentinel */ - while ((seed = json_c_get_random_seed()) == -1); -#if defined __GNUC__ - __sync_val_compare_and_swap(&random_seed, -1, seed); -#elif defined _MSC_VER - InterlockedCompareExchange(&random_seed, seed, -1); -#else -#warning "racy random seed initializtion if used by multiple threads" - random_seed = seed; /* potentially racy */ -#endif - } - - return hashlittle((const char*)k, strlen((const char*)k), random_seed); -} - -int lh_char_equal(const void *k1, const void *k2) -{ - return (strcmp((const char*)k1, (const char*)k2) == 0); -} - -struct lh_table* lh_table_new(int size, const char *name, - lh_entry_free_fn *free_fn, - lh_hash_fn *hash_fn, - lh_equal_fn *equal_fn) -{ - int i; - struct lh_table *t; - - t = (struct lh_table*)calloc(1, sizeof(struct lh_table)); - if(!t) lh_abort("lh_table_new: calloc failed\n"); - t->count = 0; - t->size = size; - t->name = name; - t->table = (struct lh_entry*)calloc(size, sizeof(struct lh_entry)); - if(!t->table) lh_abort("lh_table_new: calloc failed\n"); - t->free_fn = free_fn; - t->hash_fn = hash_fn; - t->equal_fn = equal_fn; - for(i = 0; i < size; i++) t->table[i].k = LH_EMPTY; - return t; -} - -struct lh_table* lh_kchar_table_new(int size, const char *name, - lh_entry_free_fn *free_fn) -{ - return lh_table_new(size, name, free_fn, lh_char_hash, lh_char_equal); -} - -struct lh_table* lh_kptr_table_new(int size, const char *name, - lh_entry_free_fn *free_fn) -{ - return lh_table_new(size, name, free_fn, lh_ptr_hash, lh_ptr_equal); -} - -void lh_table_resize(struct lh_table *t, int new_size) -{ - struct lh_table *new_t; - struct lh_entry *ent; - - new_t = lh_table_new(new_size, t->name, NULL, t->hash_fn, t->equal_fn); - ent = t->head; - while(ent) { - lh_table_insert(new_t, ent->k, ent->v); - ent = ent->next; - } - free(t->table); - t->table = new_t->table; - t->size = new_size; - t->head = new_t->head; - t->tail = new_t->tail; - t->resizes++; - free(new_t); -} - -void lh_table_free(struct lh_table *t) -{ - struct lh_entry *c; - for(c = t->head; c != NULL; c = c->next) { - if(t->free_fn) { - t->free_fn(c); - } - } - free(t->table); - free(t); -} - - -int lh_table_insert(struct lh_table *t, void *k, const void *v) -{ - unsigned long h, n; - - t->inserts++; - if(t->count >= t->size * LH_LOAD_FACTOR) lh_table_resize(t, t->size * 2); - - h = t->hash_fn(k); - n = h % t->size; - - while( 1 ) { - if(t->table[n].k == LH_EMPTY || t->table[n].k == LH_FREED) break; - t->collisions++; - if ((int)++n == t->size) n = 0; - } - - t->table[n].k = k; - t->table[n].v = v; - t->count++; - - if(t->head == NULL) { - t->head = t->tail = &t->table[n]; - t->table[n].next = t->table[n].prev = NULL; - } else { - t->tail->next = &t->table[n]; - t->table[n].prev = t->tail; - t->table[n].next = NULL; - t->tail = &t->table[n]; - } - - return 0; -} - - -struct lh_entry* lh_table_lookup_entry(struct lh_table *t, const void *k) -{ - unsigned long h = t->hash_fn(k); - unsigned long n = h % t->size; - int count = 0; - - t->lookups++; - while( count < t->size ) { - if(t->table[n].k == LH_EMPTY) return NULL; - if(t->table[n].k != LH_FREED && - t->equal_fn(t->table[n].k, k)) return &t->table[n]; - if ((int)++n == t->size) n = 0; - count++; - } - return NULL; -} - - -const void* lh_table_lookup(struct lh_table *t, const void *k) -{ - void *result; - lh_table_lookup_ex(t, k, &result); - return result; -} - -json_bool lh_table_lookup_ex(struct lh_table* t, const void* k, void **v) -{ - struct lh_entry *e = lh_table_lookup_entry(t, k); - if (e != NULL) { - if (v != NULL) *v = (void *)e->v; - return TRUE; /* key found */ - } - if (v != NULL) *v = NULL; - return FALSE; /* key not found */ -} - -int lh_table_delete_entry(struct lh_table *t, struct lh_entry *e) -{ - ptrdiff_t n = (ptrdiff_t)(e - t->table); /* CAW: fixed to be 64bit nice, still need the crazy negative case... */ - - /* CAW: this is bad, really bad, maybe stack goes other direction on this machine... */ - if(n < 0) { return -2; } - - if(t->table[n].k == LH_EMPTY || t->table[n].k == LH_FREED) return -1; - t->count--; - if(t->free_fn) t->free_fn(e); - t->table[n].v = NULL; - t->table[n].k = LH_FREED; - if(t->tail == &t->table[n] && t->head == &t->table[n]) { - t->head = t->tail = NULL; - } else if (t->head == &t->table[n]) { - t->head->next->prev = NULL; - t->head = t->head->next; - } else if (t->tail == &t->table[n]) { - t->tail->prev->next = NULL; - t->tail = t->tail->prev; - } else { - t->table[n].prev->next = t->table[n].next; - t->table[n].next->prev = t->table[n].prev; - } - t->table[n].next = t->table[n].prev = NULL; - return 0; -} - - -int lh_table_delete(struct lh_table *t, const void *k) -{ - struct lh_entry *e = lh_table_lookup_entry(t, k); - if(!e) return -1; - return lh_table_delete_entry(t, e); -} - -int lh_table_length(struct lh_table *t) -{ - return t->count; -} diff --git a/tools/CustomSetupTool/CustomSetupTool/json-c/linkhash.h b/tools/CustomSetupTool/CustomSetupTool/json-c/linkhash.h deleted file mode 100644 index 950d09f35d70..000000000000 --- a/tools/CustomSetupTool/CustomSetupTool/json-c/linkhash.h +++ /dev/null @@ -1,292 +0,0 @@ -/* - * $Id: linkhash.h,v 1.6 2006/01/30 23:07:57 mclark Exp $ - * - * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. - * Michael Clark - * Copyright (c) 2009 Hewlett-Packard Development Company, L.P. - * - * This library is free software; you can redistribute it and/or modify - * it under the terms of the MIT license. See COPYING for details. - * - */ - -#ifndef _linkhash_h_ -#define _linkhash_h_ - -#include "json_object.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * golden prime used in hash functions - */ -#define LH_PRIME 0x9e370001UL - -/** - * The fraction of filled hash buckets until an insert will cause the table - * to be resized. - * This can range from just above 0 up to 1.0. - */ -#define LH_LOAD_FACTOR 0.66 - -/** - * sentinel pointer value for empty slots - */ -#define LH_EMPTY (void*)-1 - -/** - * sentinel pointer value for freed slots - */ -#define LH_FREED (void*)-2 - -struct lh_entry; - -/** - * callback function prototypes - */ -typedef void (lh_entry_free_fn) (struct lh_entry *e); -/** - * callback function prototypes - */ -typedef unsigned long (lh_hash_fn) (const void *k); -/** - * callback function prototypes - */ -typedef int (lh_equal_fn) (const void *k1, const void *k2); - -/** - * An entry in the hash table - */ -struct lh_entry { - /** - * The key. - */ - void *k; - /** - * The value. - */ - const void *v; - /** - * The next entry - */ - struct lh_entry *next; - /** - * The previous entry. - */ - struct lh_entry *prev; -}; - - -/** - * The hash table structure. - */ -struct lh_table { - /** - * Size of our hash. - */ - int size; - /** - * Numbers of entries. - */ - int count; - - /** - * Number of collisions. - */ - int collisions; - - /** - * Number of resizes. - */ - int resizes; - - /** - * Number of lookups. - */ - int lookups; - - /** - * Number of inserts. - */ - int inserts; - - /** - * Number of deletes. - */ - int deletes; - - /** - * Name of the hash table. - */ - const char *name; - - /** - * The first entry. - */ - struct lh_entry *head; - - /** - * The last entry. - */ - struct lh_entry *tail; - - struct lh_entry *table; - - /** - * A pointer onto the function responsible for freeing an entry. - */ - lh_entry_free_fn *free_fn; - lh_hash_fn *hash_fn; - lh_equal_fn *equal_fn; -}; - - -/** - * Pre-defined hash and equality functions - */ -extern unsigned long lh_ptr_hash(const void *k); -extern int lh_ptr_equal(const void *k1, const void *k2); - -extern unsigned long lh_char_hash(const void *k); -extern int lh_char_equal(const void *k1, const void *k2); - - -/** - * Convenience list iterator. - */ -#define lh_foreach(table, entry) \ -for(entry = table->head; entry; entry = entry->next) - -/** - * lh_foreach_safe allows calling of deletion routine while iterating. - */ -#define lh_foreach_safe(table, entry, tmp) \ -for(entry = table->head; entry && ((tmp = entry->next) || 1); entry = tmp) - - - -/** - * Create a new linkhash table. - * @param size initial table size. The table is automatically resized - * although this incurs a performance penalty. - * @param name the table name. - * @param free_fn callback function used to free memory for entries - * when lh_table_free or lh_table_delete is called. - * If NULL is provided, then memory for keys and values - * must be freed by the caller. - * @param hash_fn function used to hash keys. 2 standard ones are defined: - * lh_ptr_hash and lh_char_hash for hashing pointer values - * and C strings respectively. - * @param equal_fn comparison function to compare keys. 2 standard ones defined: - * lh_ptr_hash and lh_char_hash for comparing pointer values - * and C strings respectively. - * @return a pointer onto the linkhash table. - */ -extern struct lh_table* lh_table_new(int size, const char *name, - lh_entry_free_fn *free_fn, - lh_hash_fn *hash_fn, - lh_equal_fn *equal_fn); - -/** - * Convenience function to create a new linkhash - * table with char keys. - * @param size initial table size. - * @param name table name. - * @param free_fn callback function used to free memory for entries. - * @return a pointer onto the linkhash table. - */ -extern struct lh_table* lh_kchar_table_new(int size, const char *name, - lh_entry_free_fn *free_fn); - - -/** - * Convenience function to create a new linkhash - * table with ptr keys. - * @param size initial table size. - * @param name table name. - * @param free_fn callback function used to free memory for entries. - * @return a pointer onto the linkhash table. - */ -extern struct lh_table* lh_kptr_table_new(int size, const char *name, - lh_entry_free_fn *free_fn); - - -/** - * Free a linkhash table. - * If a callback free function is provided then it is called for all - * entries in the table. - * @param t table to free. - */ -extern void lh_table_free(struct lh_table *t); - - -/** - * Insert a record into the table. - * @param t the table to insert into. - * @param k a pointer to the key to insert. - * @param v a pointer to the value to insert. - */ -extern int lh_table_insert(struct lh_table *t, void *k, const void *v); - - -/** - * Lookup a record into the table. - * @param t the table to lookup - * @param k a pointer to the key to lookup - * @return a pointer to the record structure of the value or NULL if it does not exist. - */ -extern struct lh_entry* lh_table_lookup_entry(struct lh_table *t, const void *k); - -/** - * Lookup a record into the table - * @param t the table to lookup - * @param k a pointer to the key to lookup - * @return a pointer to the found value or NULL if it does not exist. - * @deprecated Use lh_table_lookup_ex instead. - */ -THIS_FUNCTION_IS_DEPRECATED(extern const void* lh_table_lookup(struct lh_table *t, const void *k)); - -/** - * Lookup a record in the table - * @param t the table to lookup - * @param k a pointer to the key to lookup - * @param v a pointer to a where to store the found value (set to NULL if it doesn't exist). - * @return whether or not the key was found - */ -extern json_bool lh_table_lookup_ex(struct lh_table *t, const void *k, void **v); - -/** - * Delete a record from the table. - * If a callback free function is provided then it is called for the - * for the item being deleted. - * @param t the table to delete from. - * @param e a pointer to the entry to delete. - * @return 0 if the item was deleted. - * @return -1 if it was not found. - */ -extern int lh_table_delete_entry(struct lh_table *t, struct lh_entry *e); - - -/** - * Delete a record from the table. - * If a callback free function is provided then it is called for the - * for the item being deleted. - * @param t the table to delete from. - * @param k a pointer to the key to delete. - * @return 0 if the item was deleted. - * @return -1 if it was not found. - */ -extern int lh_table_delete(struct lh_table *t, const void *k); - -extern int lh_table_length(struct lh_table *t); - -void lh_abort(const char *msg, ...); -void lh_table_resize(struct lh_table *t, int new_size); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/tools/CustomSetupTool/CustomSetupTool/json-c/math_compat.h b/tools/CustomSetupTool/CustomSetupTool/json-c/math_compat.h deleted file mode 100644 index f40b8faf8fd4..000000000000 --- a/tools/CustomSetupTool/CustomSetupTool/json-c/math_compat.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef __math_compat_h -#define __math_compat_h - -/* Define isnan and isinf on Windows/MSVC */ - -#ifndef HAVE_DECL_ISNAN -# ifdef HAVE_DECL__ISNAN -#include -#define isnan(x) _isnan(x) -# endif -#endif - -#ifndef HAVE_DECL_ISINF -# ifdef HAVE_DECL__FINITE -#include -#define isinf(x) (!_finite(x)) -# endif -#endif - -#ifndef HAVE_DECL_NAN -#error This platform does not have nan() -#endif - -#ifndef HAVE_DECL_INFINITY -#error This platform does not have INFINITY -#endif - -#endif diff --git a/tools/CustomSetupTool/CustomSetupTool/json-c/printbuf.c b/tools/CustomSetupTool/CustomSetupTool/json-c/printbuf.c deleted file mode 100644 index 94d41b0d6a5e..000000000000 --- a/tools/CustomSetupTool/CustomSetupTool/json-c/printbuf.c +++ /dev/null @@ -1,194 +0,0 @@ -/* - * $Id: printbuf.c,v 1.5 2006/01/26 02:16:28 mclark Exp $ - * - * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. - * Michael Clark - * - * This library is free software; you can redistribute it and/or modify - * it under the terms of the MIT license. See COPYING for details. - * - * - * Copyright (c) 2008-2009 Yahoo! Inc. All rights reserved. - * The copyrights to the contents of this file are licensed under the MIT License - * (http://www.opensource.org/licenses/mit-license.php) - */ - -#include "config.h" - -#include -#include -#include - -#ifdef HAVE_STDARG_H -# include -#else /* !HAVE_STDARG_H */ -# error Not enough var arg support! -#endif /* HAVE_STDARG_H */ - -#include "bits.h" -#include "debug.h" -#include "printbuf.h" - -static int printbuf_extend(struct printbuf *p, size_t min_size); - -struct printbuf* printbuf_new(void) -{ - struct printbuf *p; - - p = (struct printbuf*)calloc(1, sizeof(struct printbuf)); - if(!p) return NULL; - p->size = 32; - p->bpos = 0; - if(!(p->buf = (char*)malloc(p->size))) { - free(p); - return NULL; - } - return p; -} - - -/** - * Extend the buffer p so it has a size of at least min_size. - * - * If the current size is large enough, nothing is changed. - * - * Note: this does not check the available space! The caller - * is responsible for performing those calculations. - */ -static int printbuf_extend(struct printbuf *p, size_t min_size) -{ - char *t; - size_t new_size; - - if (p->size >= min_size) - return 0; - - new_size = json_max(p->size * 2, min_size + 8); -#ifdef PRINTBUF_DEBUG - MC_DEBUG("printbuf_memappend: realloc " - "bpos=%d min_size=%d old_size=%d new_size=%d\n", - p->bpos, min_size, p->size, new_size); -#endif /* PRINTBUF_DEBUG */ - if(!(t = (char*)realloc(p->buf, new_size))) - return -1; - p->size = new_size; - p->buf = t; - return 0; -} - -size_t printbuf_memappend(struct printbuf *p, const char *buf, size_t size) -{ - if (p->size <= p->bpos + size + 1) { - if (printbuf_extend(p, p->bpos + size + 1) < 0) - return -1; - } - memcpy(p->buf + p->bpos, buf, size); - p->bpos += size; - p->buf[p->bpos]= '\0'; - return size; -} - -int printbuf_memset(struct printbuf *pb, size_t offset, int charvalue, size_t len) -{ - size_t size_needed; - - if (offset == -1) - offset = pb->bpos; - size_needed = offset + len; - if (pb->size < size_needed) - { - if (printbuf_extend(pb, size_needed) < 0) - return -1; - } - - memset(pb->buf + offset, charvalue, len); - if (pb->bpos < size_needed) - pb->bpos = size_needed; - - return 0; -} - -#if !defined(HAVE_VSNPRINTF) && defined(_MSC_VER) -# define vsnprintf _vsnprintf -#elif !defined(HAVE_VSNPRINTF) /* !HAVE_VSNPRINTF */ -# error Need vsnprintf! -#endif /* !HAVE_VSNPRINTF && defined(_WIN32) */ - -#if !defined(HAVE_VASPRINTF) -/* CAW: compliant version of vasprintf */ -static int vasprintf(char **buf, const char *fmt, va_list ap) -{ -#ifndef _WIN32 - static char _T_emptybuffer = '\0'; -#endif /* !defined(_WIN32) */ - int chars; - char *b; - - if(!buf) { return -1; } - -#ifdef _WIN32 - chars = _vscprintf(fmt, ap)+1; -#else /* !defined(_WIN32) */ - /* CAW: RAWR! We have to hope to god here that vsnprintf doesn't overwrite - our buffer like on some 64bit sun systems.... but hey, its time to move on */ - chars = vsnprintf(&_T_emptybuffer, 0, fmt, ap)+1; - if(chars < 0) { chars *= -1; } /* CAW: old glibc versions have this problem */ -#endif /* defined(_WIN32) */ - - b = (char*)malloc(sizeof(char) * chars); - if(!b) { return -1; } - - if ((chars = vsprintf_s(b, sizeof(char), fmt, ap)) < 0) - { - free(b); - } - else - { - *buf = b; - } - - return chars; -} -#endif /* !HAVE_VASPRINTF */ - -int sprintbuf(struct printbuf *p, const char *msg, ...) -{ - va_list ap; - char *t; - int size; - char buf[128]; - - /* user stack buffer first */ - va_start(ap, msg); - size = _vsnprintf_s(buf, sizeof(buf), _TRUNCATE, msg, ap); - va_end(ap); - /* if string is greater than stack buffer, then use dynamic string - with vasprintf. Note: some implementation of vsnprintf return -1 - if output is truncated whereas some return the number of bytes that - would have been written - this code handles both cases. */ - if(size == -1 || size > 127) { - va_start(ap, msg); - if((size = vasprintf(&t, msg, ap)) < 0) { va_end(ap); return -1; } - va_end(ap); - printbuf_memappend(p, t, size); - free(t); - return size; - } else { - printbuf_memappend(p, buf, size); - return size; - } -} - -void printbuf_reset(struct printbuf *p) -{ - p->buf[0] = '\0'; - p->bpos = 0; -} - -void printbuf_free(struct printbuf *p) -{ - if(p) { - free(p->buf); - free(p); - } -} diff --git a/tools/CustomSetupTool/CustomSetupTool/json-c/printbuf.h b/tools/CustomSetupTool/CustomSetupTool/json-c/printbuf.h deleted file mode 100644 index ed003b61f3c2..000000000000 --- a/tools/CustomSetupTool/CustomSetupTool/json-c/printbuf.h +++ /dev/null @@ -1,81 +0,0 @@ -/* - * $Id: printbuf.h,v 1.4 2006/01/26 02:16:28 mclark Exp $ - * - * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. - * Michael Clark - * - * This library is free software; you can redistribute it and/or modify - * it under the terms of the MIT license. See COPYING for details. - * - * - * Copyright (c) 2008-2009 Yahoo! Inc. All rights reserved. - * The copyrights to the contents of this file are licensed under the MIT License - * (http://www.opensource.org/licenses/mit-license.php) - */ - -#ifndef _printbuf_h_ -#define _printbuf_h_ - -#ifdef __cplusplus -extern "C" { -#endif - -struct printbuf { - char *buf; - size_t bpos; - size_t size; -}; - -extern struct printbuf* -printbuf_new(void); - -/* As an optimization, printbuf_memappend_fast is defined as a macro - * that handles copying data if the buffer is large enough; otherwise - * it invokes printbuf_memappend_real() which performs the heavy - * lifting of realloc()ing the buffer and copying data. - * Your code should not use printbuf_memappend directly--use - * printbuf_memappend_fast instead. - */ -extern size_t printbuf_memappend(struct printbuf *p, const char *buf, size_t size); - -__inline void printbuf_memappend_fast(struct printbuf *p, const char *bufptr, size_t bufsize) -{ - if ((p->size - p->bpos) > bufsize) - { - memcpy(p->buf + p->bpos, (bufptr), bufsize); - p->bpos += (int)bufsize; - p->buf[p->bpos] = '\0'; - } - else - { - printbuf_memappend(p, (bufptr), bufsize); - } -} - -#define printbuf_length(p) ((p)->bpos) - -/** - * Set len bytes of the buffer to charvalue, starting at offset offset. - * Similar to calling memset(x, charvalue, len); - * - * The memory allocated for the buffer is extended as necessary. - * - * If offset is -1, this starts at the end of the current data in the buffer. - */ -extern int -printbuf_memset(struct printbuf *pb, size_t offset, int charvalue, size_t len); - -extern int -sprintbuf(struct printbuf *p, const char *msg, ...); - -extern void -printbuf_reset(struct printbuf *p); - -extern void -printbuf_free(struct printbuf *p); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/tools/CustomSetupTool/CustomSetupTool/json-c/random_seed.c b/tools/CustomSetupTool/CustomSetupTool/json-c/random_seed.c deleted file mode 100644 index ece374e5b74e..000000000000 --- a/tools/CustomSetupTool/CustomSetupTool/json-c/random_seed.c +++ /dev/null @@ -1,238 +0,0 @@ -/* - * random_seed.c - * - * Copyright (c) 2013 Metaparadigm Pte. Ltd. - * Michael Clark - * - * This library is free software; you can redistribute it and/or modify - * it under the terms of the MIT license. See COPYING for details. - * - */ - -#include -#include "config.h" - -#define DEBUG_SEED(s) - - -#if defined ENABLE_RDRAND - -/* cpuid */ - -#if defined __GNUC__ && (defined __i386__ || defined __x86_64__) -#define HAS_X86_CPUID 1 - -static void do_cpuid(int regs[], int h) -{ - __asm__ __volatile__( -#if defined __x86_64__ - "pushq %%rbx;\n" -#else - "pushl %%ebx;\n" -#endif - "cpuid;\n" -#if defined __x86_64__ - "popq %%rbx;\n" -#else - "popl %%ebx;\n" -#endif - : "=a"(regs[0]), [ebx] "=r"(regs[1]), "=c"(regs[2]), "=d"(regs[3]) - : "a"(h)); -} - -#elif defined _MSC_VER - -#define HAS_X86_CPUID 1 -#define do_cpuid __cpuid - -#endif - -/* has_rdrand */ - -#if HAS_X86_CPUID - -static int has_rdrand() -{ - // CPUID.01H:ECX.RDRAND[bit 30] == 1 - int regs[4]; - do_cpuid(regs, 1); - return (regs[2] & (1 << 30)) != 0; -} - -#endif - -/* get_rdrand_seed - GCC x86 and X64 */ - -#if defined __GNUC__ && (defined __i386__ || defined __x86_64__) - -#define HAVE_RDRAND 1 - -static int get_rdrand_seed() -{ - DEBUG_SEED("get_rdrand_seed"); - int _eax; - // rdrand eax - __asm__ __volatile__("1: .byte 0x0F\n" - " .byte 0xC7\n" - " .byte 0xF0\n" - " jnc 1b;\n" - : "=a" (_eax)); - return _eax; -} - -#endif - -#if defined _MSC_VER - -#if _MSC_VER >= 1700 -#define HAVE_RDRAND 1 - -/* get_rdrand_seed - Visual Studio 2012 and above */ - -static int get_rdrand_seed() -{ - DEBUG_SEED("get_rdrand_seed"); - int r; - while (_rdrand32_step(&r) == 0); - return r; -} - -#elif defined _M_IX86 -#define HAVE_RDRAND 1 - -/* get_rdrand_seed - Visual Studio 2010 and below - x86 only */ - -static int get_rdrand_seed() -{ - DEBUG_SEED("get_rdrand_seed"); - int _eax; -retry: - // rdrand eax - __asm _emit 0x0F __asm _emit 0xC7 __asm _emit 0xF0 - __asm jnc retry - __asm mov _eax, eax - return _eax; -} - -#endif -#endif - -#endif /* defined ENABLE_RDRAND */ - - -/* has_dev_urandom */ - -#if defined (__APPLE__) || defined(__unix__) || defined(__linux__) - -#include -#include -#include -#include -#include -#include - -#define HAVE_DEV_RANDOM 1 - -static const char *dev_random_file = "/dev/urandom"; - -static int has_dev_urandom() -{ - struct stat buf; - if (stat(dev_random_file, &buf)) { - return 0; - } - return ((buf.st_mode & S_IFCHR) != 0); -} - - -/* get_dev_random_seed */ - -static int get_dev_random_seed() -{ - DEBUG_SEED("get_dev_random_seed"); - - int fd = open(dev_random_file, O_RDONLY); - if (fd < 0) { - fprintf(stderr, "error opening %s: %s", dev_random_file, strerror(errno)); - exit(1); - } - - int r; - ssize_t nread = read(fd, &r, sizeof(r)); - if (nread != sizeof(r)) { - fprintf(stderr, "error read %s: %s", dev_random_file, strerror(errno)); - exit(1); - } - else if (nread != sizeof(r)) { - fprintf(stderr, "error short read %s", dev_random_file); - exit(1); - } - close(fd); - return r; -} - -#endif - - -/* get_cryptgenrandom_seed */ - -#ifdef _WIN32 - -#define HAVE_CRYPTGENRANDOM 1 - -#include - -static int get_cryptgenrandom_seed() -{ - DEBUG_SEED("get_cryptgenrandom_seed"); - - HCRYPTPROV hProvider = 0; - int r; - - if (!CryptAcquireContextW(&hProvider, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) - { - fprintf(stderr, "error CryptAcquireContextW"); - exit(1); - } - - if (!CryptGenRandom(hProvider, sizeof(r), (BYTE*)&r)) - { - fprintf(stderr, "error CryptGenRandom"); - exit(1); - } - - CryptReleaseContext(hProvider, 0); - - return r; -} - -#endif - - -/* get_time_seed */ - -#include - -static int get_time_seed() -{ - DEBUG_SEED("get_time_seed"); - - return (int)time(NULL) * 433494437; -} - - -/* json_c_get_random_seed */ - -int json_c_get_random_seed() -{ -#if HAVE_RDRAND - if (has_rdrand()) return get_rdrand_seed(); -#endif -#if HAVE_DEV_RANDOM - if (has_dev_urandom()) return get_dev_random_seed(); -#endif -#if HAVE_CRYPTGENRANDOM - return get_cryptgenrandom_seed(); -#endif - return get_time_seed(); -} diff --git a/tools/CustomSetupTool/CustomSetupTool/json-c/random_seed.h b/tools/CustomSetupTool/CustomSetupTool/json-c/random_seed.h deleted file mode 100644 index 7362d67d9cd5..000000000000 --- a/tools/CustomSetupTool/CustomSetupTool/json-c/random_seed.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * random_seed.h - * - * Copyright (c) 2013 Metaparadigm Pte. Ltd. - * Michael Clark - * - * This library is free software; you can redistribute it and/or modify - * it under the terms of the MIT license. See COPYING for details. - * - */ - -#ifndef seed_h -#define seed_h - -#ifdef __cplusplus -extern "C" { -#endif - -extern int json_c_get_random_seed(); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/tools/CustomSetupTool/CustomSetupTool/setup.c b/tools/CustomSetupTool/CustomSetupTool/setup.c index e23626d0026c..39a98e1046af 100644 --- a/tools/CustomSetupTool/CustomSetupTool/setup.c +++ b/tools/CustomSetupTool/CustomSetupTool/setup.c @@ -185,30 +185,21 @@ BOOLEAN SetupCreateUninstallFile( if (RtlDoesFileExists_U(backupFilePath->Buffer)) { - GUID randomGuid; - PPH_STRING tempPath = NULL; - PPH_STRING guidString = NULL; - - tempPath = PhCreateStringEx(NULL, GetTempPath(0, NULL) * sizeof(WCHAR)); - GetTempPath((ULONG)tempPath->Length / sizeof(WCHAR), tempPath->Buffer); - - PhGenerateGuid(&randomGuid); - - if (guidString = PhFormatGuid(&randomGuid)) + if (!DeleteFile(backupFilePath->Buffer)) { - PhMoveReference(&guidString, PhSubstring(guidString, 1, guidString->Length / sizeof(WCHAR) - 2)); - } + PPH_STRING tempFileName; + PPH_STRING tempFilePath; - PhMoveReference(&guidString, PhConcatStrings( - 3, - PhGetString(tempPath), - L"\\", - PhGetString(guidString) - )); + tempFileName = PhCreateString(L"processhacker-setup.old"); + tempFilePath = PhGetCacheFileName(tempFileName); - if (!MoveFile(backupFilePath->Buffer, guidString->Buffer)) - { - Context->ErrorCode = GetLastError(); + if (!MoveFile(backupFilePath->Buffer, tempFilePath->Buffer)) + { + Context->ErrorCode = GetLastError(); + } + + PhDereferenceObject(tempFilePath); + PhDereferenceObject(tempFileName); } } @@ -239,59 +230,22 @@ VOID SetupDeleteUninstallFile( if (RtlDoesFileExists_U(uninstallFilePath->Buffer)) { - ULONG indexOfFileName = -1; - GUID randomGuid; - PPH_STRING setupTempPath = NULL; - PPH_STRING randomGuidString = NULL; - PPH_STRING fullSetupPath = NULL; - PPH_STRING tempFilePath = NULL; - - setupTempPath = PhCreateStringEx(NULL, GetTempPath(0, NULL) * sizeof(WCHAR)); - if (PhIsNullOrEmptyString(setupTempPath)) - goto CleanupExit; - if (GetTempPath((ULONG)setupTempPath->Length / sizeof(WCHAR), setupTempPath->Buffer) == 0) - goto CleanupExit; - if (PhIsNullOrEmptyString(setupTempPath)) - goto CleanupExit; + PPH_STRING tempFileName; + PPH_STRING tempFilePath; - // Generate random guid for our directory path. - PhGenerateGuid(&randomGuid); + tempFileName = PhCreateString(L"processhacker-setup.exe"); + tempFilePath = PhGetCacheFileName(tempFileName); - if (randomGuidString = PhFormatGuid(&randomGuid)) - { - PPH_STRING guidSubString; - - // Strip the left and right curly brackets. - guidSubString = PhSubstring(randomGuidString, 1, randomGuidString->Length / sizeof(WCHAR) - 2); - PhMoveReference(&randomGuidString, guidSubString); - } - - // Append the tempath to our string: %TEMP%RandomString\\processhacker-setup.exe - // Example: C:\\Users\\dmex\\AppData\\Temp\\processhacker-setup.exe - tempFilePath = PhFormatString( - L"%s%s\\processhacker-setup.exe", - PhGetStringOrEmpty(setupTempPath), - PhGetStringOrEmpty(randomGuidString) - ); if (PhIsNullOrEmptyString(tempFilePath)) - goto CleanupExit; - - // Create the directory if it does not exist. - if (fullSetupPath = PhGetFullPath(PhGetString(tempFilePath), &indexOfFileName)) { - PPH_STRING directoryPath; - - if (indexOfFileName == -1) - goto CleanupExit; - - if (directoryPath = PhSubstring(fullSetupPath, 0, indexOfFileName)) - { - SHCreateDirectoryEx(NULL, directoryPath->Buffer, NULL); - PhDereferenceObject(directoryPath); - } + PhDereferenceObject(tempFileName); + goto CleanupExit; } + + MoveFile(uninstallFilePath->Buffer, tempFilePath->Buffer); - MoveFile(uninstallFilePath->Buffer, fullSetupPath->Buffer); + PhDereferenceObject(tempFilePath); + PhDereferenceObject(tempFileName); } CleanupExit: diff --git a/tools/CustomSetupTool/CustomSetupTool/updatesetup.c b/tools/CustomSetupTool/CustomSetupTool/updatesetup.c deleted file mode 100644 index e892305e2f5a..000000000000 --- a/tools/CustomSetupTool/CustomSetupTool/updatesetup.c +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Process Hacker Toolchain - - * project setup - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include -#include - -NTSTATUS SetupUpdateWebSetupBuild( - _In_ PPH_SETUP_CONTEXT Context - ) -{ - return STATUS_SUCCESS; -} diff --git a/tools/CustomSetupTool/CustomSetupTool/websetuppage.c b/tools/CustomSetupTool/CustomSetupTool/websetuppage.c new file mode 100644 index 000000000000..30012b3fbef9 --- /dev/null +++ b/tools/CustomSetupTool/CustomSetupTool/websetuppage.c @@ -0,0 +1,136 @@ +/* + * Process Hacker Toolchain - + * project setup + * + * Copyright (C) 2017 dmex + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include + +NTSTATUS SetupDownloadWebSetupThread( + _In_ PPH_SETUP_CONTEXT Context + ) +{ + ULONGLONG currentVersion = 0; + ULONGLONG latestVersion = 0; + PPH_STRING setupFileName; + PH_IMAGE_VERSION_INFO versionInfo; + + if (!SetupQueryUpdateData(Context)) + goto CleanupExit; + + setupFileName = PhGetApplicationFileName(); + + if (!PhInitializeImageVersionInfo(&versionInfo, PhGetString(setupFileName))) + goto CleanupExit; + + currentVersion = ParseVersionString(versionInfo.FileVersion); + +#ifdef FORCE_UPDATE_CHECK + latestVersion = MAKE_VERSION_ULONGLONG( + 9999, + 9999, + 9999, + 0 + ); +#else + latestVersion = ParseVersionString(Context->WebSetupFileVersion); +#endif + + // Compare the current version against the latest available version + if (currentVersion < latestVersion) + { + if (!UpdateDownloadUpdateData(Context)) + goto CleanupExit; + } + + PostMessage(Context->DialogHandle, PSM_SETCURSELID, 0, IDD_DIALOG5); + return STATUS_SUCCESS; + +CleanupExit: + + PostMessage(Context->DialogHandle, PSM_SETCURSELID, 0, IDD_ERROR); + return STATUS_FAIL_CHECK; +} + +INT_PTR CALLBACK SetupWebSetup_WndProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _Inout_ WPARAM wParam, + _Inout_ LPARAM lParam + ) +{ + PPH_SETUP_CONTEXT context = NULL; + + if (uMsg == WM_INITDIALOG) + { + context = GetProp(GetParent(hwndDlg), L"SetupContext"); + SetProp(hwndDlg, L"Context", (HANDLE)context); + } + else + { + context = (PPH_SETUP_CONTEXT)GetProp(hwndDlg, L"Context"); + } + + if (context == NULL) + return FALSE; + + switch (uMsg) + { + case WM_INITDIALOG: + { + SetupLoadImage(GetDlgItem(hwndDlg, IDC_PROJECT_ICON), MAKEINTRESOURCE(IDB_PNG1)); + SetupInitializeFont(GetDlgItem(hwndDlg, IDC_MAINHEADER), -17, FW_SEMIBOLD); + //SetupInitializeFont(GetDlgItem(hwndDlg, IDC_SUBHEADER), -12, FW_NORMAL); + SetupInitializeFont(GetDlgItem(hwndDlg, IDC_INSTALL_STATUS), -12, FW_SEMIBOLD); + SetupInitializeFont(GetDlgItem(hwndDlg, IDC_INSTALL_SUBSTATUS), -12, FW_NORMAL); + + EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); + } + break; + case WM_NOTIFY: + { + LPNMHDR header = (LPNMHDR)lParam; + LPPSHNOTIFY pageNotify = (LPPSHNOTIFY)header; + + switch (pageNotify->hdr.code) + { + case PSN_SETACTIVE: + { + context->MainHeaderHandle = GetDlgItem(hwndDlg, IDC_MAINHEADER); + context->StatusHandle = GetDlgItem(hwndDlg, IDC_INSTALL_STATUS); + context->SubStatusHandle = GetDlgItem(hwndDlg, IDC_INSTALL_SUBSTATUS); + context->ProgressHandle = GetDlgItem(hwndDlg, IDC_INSTALL_PROGRESS); + + SetWindowText(context->MainHeaderHandle, L"Checking for newer websetup version..."); + SetWindowText(context->StatusHandle, L"Requesting latest version..."); + SetWindowText(context->SubStatusHandle, L""); + + // Disable Next/Back buttons + PropSheet_SetWizButtons(context->DialogHandle, 0); + + PhCreateThread2(SetupDownloadWebSetupThread, context); + } + break; + } + } + break; + } + + return FALSE; +} \ No newline at end of file From 0d5f77e91cf700b89d4d660f6828ba57f83f2202 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 10 Aug 2017 23:53:47 +1000 Subject: [PATCH 0365/2058] Setup: Fix default task manager option, Set mitigation options during update --- .../CustomSetupTool/CustomSetupTool.vcxproj | 2 +- .../CustomSetupTool.vcxproj.filters | 6 +- .../{installpage.c => install.c} | 0 tools/CustomSetupTool/CustomSetupTool/main.c | 189 +++++++++--------- tools/CustomSetupTool/CustomSetupTool/setup.c | 96 ++++++--- .../CustomSetupTool/CustomSetupTool/update.c | 3 + 6 files changed, 168 insertions(+), 128 deletions(-) rename tools/CustomSetupTool/CustomSetupTool/{installpage.c => install.c} (100%) diff --git a/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj b/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj index e6877e29be51..46933fea0f5e 100644 --- a/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj +++ b/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj @@ -117,7 +117,7 @@ - + diff --git a/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj.filters b/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj.filters index f27d961d9b0b..851ba8eb5075 100644 --- a/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj.filters +++ b/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj.filters @@ -69,15 +69,15 @@ Source Files\pages - - Source Files\pages - Source Files\pages Source Files + + Source Files\pages +
    diff --git a/tools/CustomSetupTool/CustomSetupTool/installpage.c b/tools/CustomSetupTool/CustomSetupTool/install.c similarity index 100% rename from tools/CustomSetupTool/CustomSetupTool/installpage.c rename to tools/CustomSetupTool/CustomSetupTool/install.c diff --git a/tools/CustomSetupTool/CustomSetupTool/main.c b/tools/CustomSetupTool/CustomSetupTool/main.c index 80ab2834b87a..01f853af8ad7 100644 --- a/tools/CustomSetupTool/CustomSetupTool/main.c +++ b/tools/CustomSetupTool/CustomSetupTool/main.c @@ -30,7 +30,7 @@ PH_COMMAND_LINE_OPTION options[] = { SETUP_COMMAND_REPAIR, L"repair", NoArgumentType }, }; -static NTSTATUS CreateSetupMutant( +NTSTATUS CreateSetupMutant( VOID ) { @@ -49,7 +49,7 @@ static NTSTATUS CreateSetupMutant( return NtCreateMutant(&MutantHandle, MUTANT_ALL_ACCESS, &oa, FALSE); } -static VOID SetupInitializeDpi( +VOID SetupInitializeDpi( VOID ) { @@ -62,7 +62,7 @@ static VOID SetupInitializeDpi( } } -static BOOLEAN NTAPI MainPropSheetCommandLineCallback( +BOOLEAN NTAPI MainPropSheetCommandLineCallback( _In_opt_ PPH_COMMAND_LINE_OPTION Option, _In_opt_ PPH_STRING Value, _In_opt_ PVOID Context @@ -121,6 +121,83 @@ INT CALLBACK MainPropSheet_Callback( return FALSE; } +VOID SetupShowInstallDialog( + VOID + ) +{ + PROPSHEETPAGE propSheetPage = { sizeof(PROPSHEETPAGE) }; + PROPSHEETHEADER propSheetHeader = { sizeof(PROPSHEETHEADER) }; + HPROPSHEETPAGE pages[6]; + + propSheetHeader.dwFlags = PSH_NOAPPLYNOW | PSH_NOCONTEXTHELP | PSH_USECALLBACK | PSH_WIZARD_LITE; + propSheetHeader.pszIcon = MAKEINTRESOURCE(IDI_ICON1); + propSheetHeader.pfnCallback = MainPropSheet_Callback; + propSheetHeader.hInstance = PhInstanceHandle; + propSheetHeader.phpage = pages; + + // welcome page + memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); + propSheetPage.dwSize = sizeof(PROPSHEETPAGE); + propSheetPage.dwFlags = PSP_USETITLE; + propSheetPage.pszTitle = PhApplicationName; + propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_DIALOG1); + propSheetPage.hInstance = PhInstanceHandle; + propSheetPage.pfnDlgProc = SetupPropPage1_WndProc; + pages[propSheetHeader.nPages++] = CreatePropertySheetPage(&propSheetPage); + + // eula page + memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); + propSheetPage.dwSize = sizeof(PROPSHEETPAGE); + propSheetPage.dwFlags = PSP_USETITLE; + propSheetPage.pszTitle = PhApplicationName; + propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_DIALOG2); + propSheetPage.hInstance = PhInstanceHandle; + propSheetPage.pfnDlgProc = SetupPropPage2_WndProc; + pages[propSheetHeader.nPages++] = CreatePropertySheetPage(&propSheetPage); + + // config page + memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); + propSheetPage.dwSize = sizeof(PROPSHEETPAGE); + propSheetPage.dwFlags = PSP_USETITLE; + propSheetPage.pszTitle = PhApplicationName; + propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_DIALOG3); + propSheetPage.hInstance = PhInstanceHandle; + propSheetPage.pfnDlgProc = SetupPropPage3_WndProc; + pages[propSheetHeader.nPages++] = CreatePropertySheetPage(&propSheetPage); + + // download page + memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); + propSheetPage.dwSize = sizeof(PROPSHEETPAGE); + propSheetPage.dwFlags = PSP_USETITLE; + propSheetPage.pszTitle = PhApplicationName; + propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_DIALOG5); + propSheetPage.hInstance = PhInstanceHandle; + propSheetPage.pfnDlgProc = SetupPropPage5_WndProc; + pages[propSheetHeader.nPages++] = CreatePropertySheetPage(&propSheetPage); + + // extract page + memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); + propSheetPage.dwSize = sizeof(PROPSHEETPAGE); + propSheetPage.dwFlags = PSP_USETITLE; + propSheetPage.pszTitle = PhApplicationName; + propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_DIALOG4); + propSheetPage.hInstance = PhInstanceHandle; + propSheetPage.pfnDlgProc = SetupInstallPropPage_WndProc; + pages[propSheetHeader.nPages++] = CreatePropertySheetPage(&propSheetPage); + + // error page + memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); + propSheetPage.dwSize = sizeof(PROPSHEETPAGE); + propSheetPage.dwFlags = PSP_USETITLE; + propSheetPage.pszTitle = PhApplicationName; + propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_ERROR); + propSheetPage.hInstance = PhInstanceHandle; + propSheetPage.pfnDlgProc = SetupErrorPage_WndProc; + pages[propSheetHeader.nPages++] = CreatePropertySheetPage(&propSheetPage); + + PhModalPropertySheet(&propSheetHeader); +} + INT WINAPI wWinMain( _In_ HINSTANCE Instance, _In_opt_ HINSTANCE PrevInstance, @@ -128,6 +205,8 @@ INT WINAPI wWinMain( _In_ INT CmdShow ) { + PH_STRINGREF commandLine; + if (!NT_SUCCESS(CreateSetupMutant())) return 1; @@ -140,105 +219,27 @@ INT WINAPI wWinMain( PhGuiSupportInitialization(); SetupInitializeDpi(); + PhUnicodeStringToStringRef(&NtCurrentPeb()->ProcessParameters->CommandLine, &commandLine); + + if (!PhParseCommandLine( + &commandLine, + options, + ARRAYSIZE(options), + PH_COMMAND_LINE_IGNORE_FIRST_PART, + MainPropSheetCommandLineCallback, + NULL + )) { - PH_STRINGREF commandLine; - - PhUnicodeStringToStringRef(&NtCurrentPeb()->ProcessParameters->CommandLine, &commandLine); - if (!PhParseCommandLine( - &commandLine, - options, - ARRAYSIZE(options), - PH_COMMAND_LINE_IGNORE_FIRST_PART, - MainPropSheetCommandLineCallback, - NULL - )) - { - return 1; - } + return 1; } -#ifdef _DEBUG - if (CheckProcessHackerInstalled()) - SetupMode = SETUP_COMMAND_UNINSTALL; -#endif + // DEBUG // if (CheckProcessHackerInstalled()) SetupMode = SETUP_COMMAND_UNINSTALL; switch (SetupMode) { case SETUP_COMMAND_INSTALL: default: - { - PROPSHEETPAGE propSheetPage = { sizeof(PROPSHEETPAGE) }; - PROPSHEETHEADER propSheetHeader = { sizeof(PROPSHEETHEADER) }; - HPROPSHEETPAGE pages[6]; - - propSheetHeader.dwFlags = PSH_NOAPPLYNOW | PSH_NOCONTEXTHELP | PSH_USECALLBACK | PSH_WIZARD_LITE; - propSheetHeader.pszIcon = MAKEINTRESOURCE(IDI_ICON1); - propSheetHeader.pfnCallback = MainPropSheet_Callback; - propSheetHeader.hInstance = PhInstanceHandle; - propSheetHeader.phpage = pages; - - // welcome page - memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); - propSheetPage.dwSize = sizeof(PROPSHEETPAGE); - propSheetPage.dwFlags = PSP_USETITLE; - propSheetPage.pszTitle = PhApplicationName; - propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_DIALOG1); - propSheetPage.hInstance = PhInstanceHandle; - propSheetPage.pfnDlgProc = SetupPropPage1_WndProc; - pages[propSheetHeader.nPages++] = CreatePropertySheetPage(&propSheetPage); - - // eula page - memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); - propSheetPage.dwSize = sizeof(PROPSHEETPAGE); - propSheetPage.dwFlags = PSP_USETITLE; - propSheetPage.pszTitle = PhApplicationName; - propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_DIALOG2); - propSheetPage.hInstance = PhInstanceHandle; - propSheetPage.pfnDlgProc = SetupPropPage2_WndProc; - pages[propSheetHeader.nPages++] = CreatePropertySheetPage(&propSheetPage); - - // config page - memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); - propSheetPage.dwSize = sizeof(PROPSHEETPAGE); - propSheetPage.dwFlags = PSP_USETITLE; - propSheetPage.pszTitle = PhApplicationName; - propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_DIALOG3); - propSheetPage.hInstance = PhInstanceHandle; - propSheetPage.pfnDlgProc = SetupPropPage3_WndProc; - pages[propSheetHeader.nPages++] = CreatePropertySheetPage(&propSheetPage); - - // download page - memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); - propSheetPage.dwSize = sizeof(PROPSHEETPAGE); - propSheetPage.dwFlags = PSP_USETITLE; - propSheetPage.pszTitle = PhApplicationName; - propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_DIALOG5); - propSheetPage.hInstance = PhInstanceHandle; - propSheetPage.pfnDlgProc = SetupPropPage5_WndProc; - pages[propSheetHeader.nPages++] = CreatePropertySheetPage(&propSheetPage); - - // extract page - memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); - propSheetPage.dwSize = sizeof(PROPSHEETPAGE); - propSheetPage.dwFlags = PSP_USETITLE; - propSheetPage.pszTitle = PhApplicationName; - propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_DIALOG4); - propSheetPage.hInstance = PhInstanceHandle; - propSheetPage.pfnDlgProc = SetupInstallPropPage_WndProc; - pages[propSheetHeader.nPages++] = CreatePropertySheetPage(&propSheetPage); - - // error page - memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); - propSheetPage.dwSize = sizeof(PROPSHEETPAGE); - propSheetPage.dwFlags = PSP_USETITLE; - propSheetPage.pszTitle = PhApplicationName; - propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_ERROR); - propSheetPage.hInstance = PhInstanceHandle; - propSheetPage.pfnDlgProc = SetupErrorPage_WndProc; - pages[propSheetHeader.nPages++] = CreatePropertySheetPage(&propSheetPage); - - PhModalPropertySheet(&propSheetHeader); - } + SetupShowInstallDialog(); break; case SETUP_COMMAND_UNINSTALL: SetupShowUninstallDialog(); diff --git a/tools/CustomSetupTool/CustomSetupTool/setup.c b/tools/CustomSetupTool/CustomSetupTool/setup.c index 39a98e1046af..aafdad667e6f 100644 --- a/tools/CustomSetupTool/CustomSetupTool/setup.c +++ b/tools/CustomSetupTool/CustomSetupTool/setup.c @@ -263,6 +263,7 @@ VOID SetupStartKph( { HANDLE processHandle; LARGE_INTEGER timeout; + ULONG retries = 0; timeout.QuadPart = -10 * PH_TIMEOUT_SEC; @@ -279,6 +280,22 @@ VOID SetupStartKph( NtWaitForSingleObject(processHandle, FALSE, &timeout); NtClose(processHandle); } + + while (retries < 5) + { + SC_HANDLE serviceHandle; + SERVICE_STATUS serviceStatus; + + if (serviceHandle = PhOpenService(L"KProcessHacker3", SERVICE_START)) + { + StartService(serviceHandle, 0, NULL); + CloseServiceHandle(serviceHandle); + break; + } + + Sleep(1000); + retries++; + } } PhDereferenceObject(clientPath); @@ -288,38 +305,42 @@ BOOLEAN SetupUninstallKph( _In_ PPH_SETUP_CONTEXT Context ) { - while (TRUE) + ULONG retries = 0; + + while (retries < 5) { SC_HANDLE serviceHandle; SERVICE_STATUS serviceStatus; - if (!(serviceHandle = PhOpenService( - L"KProcessHacker2", - SERVICE_STOP | DELETE - ))) + if (serviceHandle = PhOpenService(L"KProcessHacker2", SERVICE_STOP | DELETE)) + { + ControlService(serviceHandle, SERVICE_CONTROL_STOP, &serviceStatus); + DeleteService(serviceHandle); + CloseServiceHandle(serviceHandle); break; + } - ControlService(serviceHandle, SERVICE_CONTROL_STOP, &serviceStatus); - DeleteService(serviceHandle); - - CloseServiceHandle(serviceHandle); + Sleep(1000); + retries++; } - while (TRUE) + retries = 0; + + while (retries < 5) { SC_HANDLE serviceHandle; SERVICE_STATUS serviceStatus; - if (!(serviceHandle = PhOpenService( - L"KProcessHacker3", - SERVICE_STOP | DELETE - ))) + if (serviceHandle = PhOpenService(L"KProcessHacker3", SERVICE_STOP | DELETE)) + { + ControlService(serviceHandle, SERVICE_CONTROL_STOP, &serviceStatus); + DeleteService(serviceHandle); + CloseServiceHandle(serviceHandle); break; + } - ControlService(serviceHandle, SERVICE_CONTROL_STOP, &serviceStatus); - DeleteService(serviceHandle); - - CloseServiceHandle(serviceHandle); + Sleep(1000); + retries++; } return TRUE; @@ -331,7 +352,6 @@ VOID SetupSetWindowsOptions( { static PH_STRINGREF TaskMgrImageOptionsKeyName = PH_STRINGREF_INIT(L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\taskmgr.exe"); static PH_STRINGREF CurrentUserRunKeyName = PH_STRINGREF_INIT(L"Software\\Microsoft\\Windows\\CurrentVersion\\Run"); - HANDLE keyHandle; PPH_STRING clientPathString; PPH_STRING startmenuFolderString; @@ -373,7 +393,7 @@ VOID SetupSetWindowsOptions( PhGetString(startmenuFolderString), PhGetString(peviewPathString), PhGetString(Context->SetupInstallPath) - ); + ); PhDereferenceObject(peviewPathString); PhDereferenceObject(startmenuFolderString); @@ -392,12 +412,17 @@ VOID SetupSetWindowsOptions( // Set the Windows default Task Manager. if (Context->SetupCreateDefaultTaskManager) { - if (NT_SUCCESS(PhOpenKey( - &keyHandle, - KEY_WRITE, + NTSTATUS status; + HANDLE taskmgrKeyHandle = NULL; + + if (NT_SUCCESS(status = PhCreateKey( + &taskmgrKeyHandle, + KEY_READ | KEY_WRITE, PH_KEY_LOCAL_MACHINE, &TaskMgrImageOptionsKeyName, - 0 + 0, + 0, + NULL ))) { PPH_STRING value; @@ -407,17 +432,24 @@ VOID SetupSetWindowsOptions( // Configure the default Task Manager. RtlInitUnicodeString(&valueName, L"Debugger"); - NtSetValueKey(keyHandle, &valueName, 0, REG_SZ, value->Buffer, (ULONG)value->Length + 2); + NtSetValueKey(taskmgrKeyHandle, &valueName, 0, REG_SZ, value->Buffer, (ULONG)value->Length + 2); - NtClose(keyHandle); + NtClose(taskmgrKeyHandle); + } + else + { + PhShowStatus(NULL, L"Unable to set the Windows default Task Manager.", status, 0); } } // Create the run startup key. if (Context->SetupCreateSystemStartup) { - if (NT_SUCCESS(PhOpenKey( - &keyHandle, + NTSTATUS status; + HANDLE runKeyHandle = NULL; + + if (NT_SUCCESS(status = PhOpenKey( + &runKeyHandle, KEY_WRITE, PH_KEY_CURRENT_USER, &CurrentUserRunKeyName, @@ -434,8 +466,12 @@ VOID SetupSetWindowsOptions( else value = PhConcatStrings(3, L"\"", PhGetString(clientPathString), L"\""); - NtSetValueKey(keyHandle, &valueName, 0, REG_SZ, value->Buffer, (ULONG)value->Length + 2); - NtClose(keyHandle); + NtSetValueKey(runKeyHandle, &valueName, 0, REG_SZ, value->Buffer, (ULONG)value->Length + 2); + NtClose(runKeyHandle); + } + else + { + PhShowStatus(NULL, L"Unable to create the startup entry.", status, 0); } } } diff --git a/tools/CustomSetupTool/CustomSetupTool/update.c b/tools/CustomSetupTool/CustomSetupTool/update.c index 79a22c0e495e..6a44c237e06d 100644 --- a/tools/CustomSetupTool/CustomSetupTool/update.c +++ b/tools/CustomSetupTool/CustomSetupTool/update.c @@ -47,6 +47,9 @@ NTSTATUS SetupUpdateBuild( if (!SetupExtractBuild(Context)) goto CleanupExit; + // Set the default image execution options. + SetupCreateImageFileExecutionOptions(); + SetupStartKph(Context); if (!SetupExecuteProcessHacker(Context)) From ba0b92b3d2f563fa196b88065acf75e4f369f03b Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 10 Aug 2017 23:54:20 +1000 Subject: [PATCH 0366/2058] CustomStartTool: Update to latest sdk --- tools/CustomStartTool/main.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/tools/CustomStartTool/main.c b/tools/CustomStartTool/main.c index e967ae3f8434..a85e586a20f5 100644 --- a/tools/CustomStartTool/main.c +++ b/tools/CustomStartTool/main.c @@ -107,19 +107,28 @@ INT WINAPI wWinMain( PPH_STRING fileName; PPH_STRING currentDirectory; - if (!NT_SUCCESS(PhInitializePhLibEx(0, 0, 0))) + if (!NT_SUCCESS(PhInitializePhLib())) return 1; if (!InitializeProcThreadAttributeList(NULL, 1, 0, &attributeListLength) && GetLastError() != ERROR_INSUFFICIENT_BUFFER) + { + PhShowStatus(NULL, L"InitializeProcThreadAttributeList Error", PhGetLastWin32ErrorAsNtStatus(), 0); return 1; + } info.lpAttributeList = PhAllocate(attributeListLength); if (!InitializeProcThreadAttributeList(info.lpAttributeList, 1, 0, &attributeListLength)) + { + PhShowStatus(NULL, L"InitializeProcThreadAttributeList Error", PhGetLastWin32ErrorAsNtStatus(), 0); return 1; + } if (!UpdateProcThreadAttribute(info.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY, &PhMitigationPolicy, sizeof(ULONG64), NULL, NULL)) + { + PhShowStatus(NULL, L"UpdateProcThreadAttribute Error", PhGetLastWin32ErrorAsNtStatus(), 0); return 1; + } currentDirectory = PhGetApplicationDirectory(); fileName = PhConcatStrings2(currentDirectory->Buffer, L"\\ProcessHacker.exe"); @@ -128,7 +137,7 @@ INT WINAPI wWinMain( if (!RtlDoesFileExists_U(fileName->Buffer) && CheckProcessHackerInstalled()) PhMoveReference(&fileName, GetProcessHackerPath()); - CreateProcess( + if (!CreateProcess( NULL, fileName->Buffer, NULL, @@ -139,7 +148,10 @@ INT WINAPI wWinMain( NULL, &info.StartupInfo, &processInfo - ); + )) + { + PhShowStatus(NULL, L"CreateProcess Error", PhGetLastWin32ErrorAsNtStatus(), 0); + } PhDereferenceObject(fileName); From 8c5112dc19caf782491b75726e8e163bc45be2de Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 11 Aug 2017 00:37:20 +1000 Subject: [PATCH 0367/2058] SetupTool: Remove undocumented dependencies --- tools/CustomSetupTool/CustomSetupTool/main.c | 10 +++++++--- tools/CustomSetupTool/CustomSetupTool/setup.c | 18 +++++++++++++----- .../CustomSetupTool/uninstall.c | 4 ++-- tools/CustomSetupTool/CustomSetupTool/update.c | 4 ++-- 4 files changed, 24 insertions(+), 12 deletions(-) diff --git a/tools/CustomSetupTool/CustomSetupTool/main.c b/tools/CustomSetupTool/CustomSetupTool/main.c index 01f853af8ad7..227c2cef77d4 100644 --- a/tools/CustomSetupTool/CustomSetupTool/main.c +++ b/tools/CustomSetupTool/CustomSetupTool/main.c @@ -205,7 +205,7 @@ INT WINAPI wWinMain( _In_ INT CmdShow ) { - PH_STRINGREF commandLine; + PPH_STRING commandLine; if (!NT_SUCCESS(CreateSetupMutant())) return 1; @@ -219,10 +219,11 @@ INT WINAPI wWinMain( PhGuiSupportInitialization(); SetupInitializeDpi(); - PhUnicodeStringToStringRef(&NtCurrentPeb()->ProcessParameters->CommandLine, &commandLine); + if (!NT_SUCCESS(PhGetProcessCommandLine(NtCurrentProcess(), &commandLine))) + return 1; if (!PhParseCommandLine( - &commandLine, + &commandLine->sr, options, ARRAYSIZE(options), PH_COMMAND_LINE_IGNORE_FIRST_PART, @@ -230,9 +231,12 @@ INT WINAPI wWinMain( NULL )) { + PhDereferenceObject(commandLine); return 1; } + PhDereferenceObject(commandLine); + // DEBUG // if (CheckProcessHackerInstalled()) SetupMode = SETUP_COMMAND_UNINSTALL; switch (SetupMode) diff --git a/tools/CustomSetupTool/CustomSetupTool/setup.c b/tools/CustomSetupTool/CustomSetupTool/setup.c index aafdad667e6f..1c8e6e5906f3 100644 --- a/tools/CustomSetupTool/CustomSetupTool/setup.c +++ b/tools/CustomSetupTool/CustomSetupTool/setup.c @@ -170,15 +170,19 @@ BOOLEAN SetupCreateUninstallFile( _In_ PPH_SETUP_CONTEXT Context ) { - PH_STRINGREF currentFilePath; + PPH_STRING currentFilePath; PPH_STRING backupFilePath; PPH_STRING uninstallFilePath; - PhUnicodeStringToStringRef(&NtCurrentPeb()->ProcessParameters->ImagePathName, ¤tFilePath); + if (!NT_SUCCESS(PhGetProcessImageFileNameWin32(NtCurrentProcess(), ¤tFilePath))) + return FALSE; // Check if the user has started the setup from the installation folder. - if (PhStartsWithStringRef2(¤tFilePath, PhGetString(Context->SetupInstallPath), TRUE)) + if (PhStartsWithStringRef2(¤tFilePath->sr, PhGetString(Context->SetupInstallPath), TRUE)) + { + PhDereferenceObject(currentFilePath); return TRUE; + } backupFilePath = PhConcatStrings2(PhGetString(Context->SetupInstallPath), L"\\processhacker-setup.bak"); uninstallFilePath = PhConcatStrings2(PhGetString(Context->SetupInstallPath), L"\\processhacker-setup.exe"); @@ -211,12 +215,14 @@ BOOLEAN SetupCreateUninstallFile( } } - if (!CopyFile(currentFilePath.Buffer, uninstallFilePath->Buffer, TRUE)) + if (!CopyFile(currentFilePath->Buffer, uninstallFilePath->Buffer, TRUE)) { Context->ErrorCode = GetLastError(); } PhDereferenceObject(uninstallFilePath); + PhDereferenceObject(currentFilePath); + return TRUE; } @@ -599,7 +605,9 @@ VOID SetupCreateImageFileExecutionOptions( static PH_STRINGREF PhImageOptionsKeyName = PH_STRINGREF_INIT(L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\ProcessHacker.exe"); HANDLE keyHandle; - // Set the default Image File Execution Options. + if (WindowsVersion < WINDOWS_10) + return; + if (NT_SUCCESS(PhCreateKey( &keyHandle, KEY_WRITE | DELETE, diff --git a/tools/CustomSetupTool/CustomSetupTool/uninstall.c b/tools/CustomSetupTool/CustomSetupTool/uninstall.c index 83d4028a1d41..e9c6c8a3ccc1 100644 --- a/tools/CustomSetupTool/CustomSetupTool/uninstall.c +++ b/tools/CustomSetupTool/CustomSetupTool/uninstall.c @@ -82,14 +82,14 @@ static VOID TaskDialogCreateIcons( HICON smallIcon; largeIcon = PhLoadIcon( - NtCurrentPeb()->ImageBaseAddress, + PhInstanceHandle, MAKEINTRESOURCE(IDI_ICON1), PH_LOAD_ICON_SIZE_LARGE, GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON) ); smallIcon = PhLoadIcon( - NtCurrentPeb()->ImageBaseAddress, + PhInstanceHandle, MAKEINTRESOURCE(IDI_ICON1), PH_LOAD_ICON_SIZE_LARGE, GetSystemMetrics(SM_CXSMICON), diff --git a/tools/CustomSetupTool/CustomSetupTool/update.c b/tools/CustomSetupTool/CustomSetupTool/update.c index 6a44c237e06d..2bfaff5d7db2 100644 --- a/tools/CustomSetupTool/CustomSetupTool/update.c +++ b/tools/CustomSetupTool/CustomSetupTool/update.c @@ -86,14 +86,14 @@ VOID TaskDialogCreateIcons( HICON smallIcon; largeIcon = PhLoadIcon( - NtCurrentPeb()->ImageBaseAddress, + PhInstanceHandle, MAKEINTRESOURCE(IDI_ICON1), PH_LOAD_ICON_SIZE_LARGE, GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON) ); smallIcon = PhLoadIcon( - NtCurrentPeb()->ImageBaseAddress, + PhInstanceHandle, MAKEINTRESOURCE(IDI_ICON1), PH_LOAD_ICON_SIZE_LARGE, GetSystemMetrics(SM_CXSMICON), From adeb26589b765ccdc950ff3ac3de1b9d5083f510 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 11 Aug 2017 00:39:40 +1000 Subject: [PATCH 0368/2058] peview: Enumerate all symbol types , Enable size column --- tools/peview/main.c | 8 +++++--- tools/peview/pdb.c | 2 +- tools/peview/pdbprp.c | 2 +- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/tools/peview/main.c b/tools/peview/main.c index f3bf35f5b892..33fa3d33ab96 100644 --- a/tools/peview/main.c +++ b/tools/peview/main.c @@ -61,7 +61,7 @@ INT WINAPI wWinMain( { { 0, L"h", NoArgumentType } }; - PH_STRINGREF commandLine; + PPH_STRING commandLine; if (!NT_SUCCESS(PhInitializePhLib())) return 1; @@ -75,16 +75,18 @@ INT WINAPI wWinMain( PhApplicationName = L"PE Viewer"; - PhUnicodeStringToStringRef(&NtCurrentPeb()->ProcessParameters->CommandLine, &commandLine); + if (!NT_SUCCESS(PhGetProcessCommandLine(NtCurrentProcess(), &commandLine))) + return 1; PhParseCommandLine( - &commandLine, + &commandLine->sr, options, sizeof(options) / sizeof(PH_COMMAND_LINE_OPTION), PH_COMMAND_LINE_IGNORE_FIRST_PART, PvCommandLineCallback, NULL ); + PhDereferenceObject(commandLine); if (!PvFileName) { diff --git a/tools/peview/pdb.c b/tools/peview/pdb.c index 61e222ad8daa..78475e31ef3d 100644 --- a/tools/peview/pdb.c +++ b/tools/peview/pdb.c @@ -2369,7 +2369,7 @@ NTSTATUS PeDumpFileSymbols( // Enumerate user defined types //PrintUserDefinedTypes(Context); - //SymEnumTypesW_I(NtCurrentProcess(), Context->BaseAddress, EnumCallbackProc, Context); + SymEnumTypesW_I(NtCurrentProcess(), Context->BaseAddress, EnumCallbackProc, Context); } CleanupExit: diff --git a/tools/peview/pdbprp.c b/tools/peview/pdbprp.c index 39d66924472e..5f232ff44d79 100644 --- a/tools/peview/pdbprp.c +++ b/tools/peview/pdbprp.c @@ -763,7 +763,7 @@ VOID PvInitializeSymbolTree( PhAddTreeNewColumnEx2(TreeNewHandle, TREE_COLUMN_ITEM_VA, TRUE, L"VA", 80, PH_ALIGN_LEFT, TREE_COLUMN_ITEM_VA, 0, 0); PhAddTreeNewColumnEx2(TreeNewHandle, TREE_COLUMN_ITEM_NAME, TRUE, L"Symbol", 150, PH_ALIGN_LEFT, TREE_COLUMN_ITEM_NAME, 0, 0); PhAddTreeNewColumnEx2(TreeNewHandle, TREE_COLUMN_ITEM_SYMBOL, TRUE, L"Data", 150, PH_ALIGN_LEFT, TREE_COLUMN_ITEM_SYMBOL, 0, 0); - PhAddTreeNewColumnEx2(TreeNewHandle, TREE_COLUMN_ITEM_SIZE, FALSE, L"Size", 40, PH_ALIGN_LEFT, TREE_COLUMN_ITEM_SIZE, 0, 0); + PhAddTreeNewColumnEx2(TreeNewHandle, TREE_COLUMN_ITEM_SIZE, TRUE, L"Size", 40, PH_ALIGN_LEFT, TREE_COLUMN_ITEM_SIZE, 0, 0); TreeNew_SetSort(TreeNewHandle, 0, NoSortOrder); From 25cddab3aafcbbbd38b12f155d92930ee1ed5e7b Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 11 Aug 2017 06:32:19 +1000 Subject: [PATCH 0369/2058] Add PhCreateDirectory/PhDeleteDirectory functions, Update PhCreateCacheFile functions --- ProcessHacker/ProcessHacker.def | 12 +- phlib/include/phnative.h | 14 ++ phlib/include/phutil.h | 16 +- phlib/native.c | 215 ++++++++++++++++++ phlib/settings.c | 2 +- phlib/util.c | 50 +++- plugins/ExtraPlugins/cloud.c | 5 +- plugins/ExtraPlugins/dialog.c | 5 - plugins/ExtraPlugins/plugin.c | 5 - plugins/ExtraPlugins/setup/updater.c | 55 +---- plugins/NetworkTools/update.c | 14 +- plugins/Updater/page5.c | 12 +- plugins/Updater/updater.c | 59 ++--- plugins/Updater/updater.h | 5 +- plugins/UserNotes/db.c | 2 +- .../CustomSetupTool/CustomSetupTool/appsup.c | 172 -------------- .../CustomSetupTool/download.c | 2 +- .../CustomSetupTool/CustomSetupTool/extract.c | 2 +- .../CustomSetupTool/include/appsup.h | 15 +- .../CustomSetupTool/CustomSetupTool/install.c | 6 +- tools/CustomSetupTool/CustomSetupTool/main.c | 82 +++---- tools/CustomSetupTool/CustomSetupTool/setup.c | 203 +++++++++++------ .../CustomSetupTool/uninstall.c | 2 +- tools/peview/main.c | 3 +- 24 files changed, 526 insertions(+), 432 deletions(-) diff --git a/ProcessHacker/ProcessHacker.def b/ProcessHacker/ProcessHacker.def index 36df3d1a187b..fcec0b535446 100644 --- a/ProcessHacker/ProcessHacker.def +++ b/ProcessHacker/ProcessHacker.def @@ -227,12 +227,14 @@ EXPORTS PhZeroExtendToUtf16Ex ; phnative + PhCreateDirectory PhCreateFileWin32 PhCreateFileWin32Ex PhCreateKey PhCreateNamedPipe PhCreatePipe PhConnectPipe + PhDeleteDirectory PhDeleteFileWin32 PhDisconnectNamedPipe PhEnumDirectoryFile @@ -345,8 +347,6 @@ EXPORTS PhGetApplicationDirectory PhGetApplicationFileName PhGetBaseName - PhGetCacheDirectory - PhGetCacheFileName PhGetDllFileName PhGetFileDialogFileName PhGetFileDialogFilterIndex @@ -635,4 +635,10 @@ EXPORTS PhGetJsonArrayLong64 PhGetJsonArrayLength PhGetJsonArrayIndexObject - PhGetJsonObjectAsArrayList \ No newline at end of file + PhGetJsonObjectAsArrayList + +; cache + PhGetCacheDirectory + PhClearCacheDirectory + PhCreateCacheFile + PhDeleteCacheFile diff --git a/phlib/include/phnative.h b/phlib/include/phnative.h index c5a60e72b0c6..b9dd90ab0716 100644 --- a/phlib/include/phnative.h +++ b/phlib/include/phnative.h @@ -974,6 +974,20 @@ PhDeleteFileWin32( _In_ PWSTR FileName ); +PHLIBAPI +NTSTATUS +NTAPI +PhCreateDirectory( + _In_ PPH_STRING DirectoryPath + ); + +PHLIBAPI +NTSTATUS +NTAPI +PhDeleteDirectory( + _In_ PPH_STRING DirectoryPath + ); + PHLIBAPI NTSTATUS NTAPI diff --git a/phlib/include/phutil.h b/phlib/include/phutil.h index 9c3722bce4aa..0d551968dc7f 100644 --- a/phlib/include/phutil.h +++ b/phlib/include/phutil.h @@ -1056,10 +1056,24 @@ PhGetCacheDirectory( VOID ); +PHLIBAPI +VOID +NTAPI +PhClearCacheDirectory( + VOID + ); + PHLIBAPI PPH_STRING NTAPI -PhGetCacheFileName( +PhCreateCacheFile( + _In_ PPH_STRING FileName + ); + +PHLIBAPI +VOID +NTAPI +PhDeleteCacheFile( _In_ PPH_STRING FileName ); diff --git a/phlib/native.c b/phlib/native.c index a567ac5dad0e..435c8426825c 100644 --- a/phlib/native.c +++ b/phlib/native.c @@ -6196,6 +6196,221 @@ NTSTATUS PhDeleteFileWin32( return status; } +/** +* Creates a directory path recursively. +* +* \param DirectoryPath The Win32 directory path. +*/ +NTSTATUS PhCreateDirectory( + _In_ PPH_STRING DirectoryPath + ) +{ + static PH_STRINGREF directorySeparator = PH_STRINGREF_INIT(L"\\"); + PPH_STRING directoryPath = NULL; + PH_STRINGREF part; + PH_STRINGREF remainingPart; + + if (PhIsNullOrEmptyString(DirectoryPath)) + return STATUS_FAIL_CHECK; + + if (RtlDoesFileExists_U(PhGetString(DirectoryPath))) + return STATUS_SUCCESS; + + remainingPart = PhGetStringRef(DirectoryPath); + + while (remainingPart.Length != 0) + { + PhSplitStringRefAtChar(&remainingPart, '\\', &part, &remainingPart); + + if (part.Length != 0) + { + if (PhIsNullOrEmptyString(directoryPath)) + directoryPath = PhCreateString2(&part); + else + { + PPH_STRING tempPathString; + + tempPathString = PhConcatStringRef3( + &directoryPath->sr, + &directorySeparator, + &part + ); + + // Check if the directory already exists. + if (!RtlDoesFileExists_U(PhGetString(tempPathString))) + { + HANDLE directoryHandle; + + // Create the directory. + if (NT_SUCCESS(PhCreateFileWin32( + &directoryHandle, + PhGetString(tempPathString), + FILE_GENERIC_READ, + FILE_ATTRIBUTE_NORMAL, + FILE_SHARE_READ | FILE_SHARE_WRITE, + FILE_CREATE, + FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT + ))) + { + NtClose(directoryHandle); + } + } + + PhMoveReference(&directoryPath, tempPathString); + } + } + } + + if (directoryPath) + PhDereferenceObject(directoryPath); + + if (RtlDoesFileExists_U(PhGetString(DirectoryPath))) + return STATUS_SUCCESS; + else + return STATUS_NOT_FOUND; +} + +static BOOLEAN PhpDeleteDirectoryCallback( + _In_ PFILE_DIRECTORY_INFORMATION Information, + _In_opt_ PVOID Context + ) +{ + static PH_STRINGREF directorySeparator = PH_STRINGREF_INIT(L"\\"); + PPH_STRING parentDirectory = Context; + PPH_STRING fullName; + PH_STRINGREF baseName; + + baseName.Buffer = Information->FileName; + baseName.Length = Information->FileNameLength; + + if (PhEqualStringRef2(&baseName, L".", TRUE) || PhEqualStringRef2(&baseName, L"..", TRUE)) + return TRUE; + + fullName = PhConcatStringRef3( + &parentDirectory->sr, + &directorySeparator, + &baseName + ); + + if (Information->FileAttributes & FILE_ATTRIBUTE_DIRECTORY) + { + HANDLE directoryHandle; + + if (NT_SUCCESS(PhCreateFileWin32( + &directoryHandle, + PhGetString(fullName), + FILE_GENERIC_READ, + FILE_ATTRIBUTE_NORMAL, + FILE_SHARE_READ | FILE_SHARE_DELETE, + FILE_OPEN, + FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT + ))) + { + PhEnumDirectoryFile(directoryHandle, NULL, PhpDeleteDirectoryCallback, fullName); + + NtClose(directoryHandle); + + // Delete the directory. + RemoveDirectory(PhGetString(fullName)); + } + } + else + { + if (Information->FileAttributes & FILE_ATTRIBUTE_READONLY) + { + HANDLE fileHandle; + + if (NT_SUCCESS(PhCreateFileWin32( + &fileHandle, + PhGetString(fullName), + FILE_GENERIC_WRITE, + FILE_ATTRIBUTE_NORMAL, + FILE_SHARE_WRITE, + FILE_OPEN, + FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT + ))) + { + IO_STATUS_BLOCK isb; + FILE_BASIC_INFORMATION fileInfo; + + memset(&fileInfo, 0, sizeof(FILE_BASIC_INFORMATION)); + + // Clear the read-only flag. + fileInfo.FileAttributes = Information->FileAttributes &= ~FILE_ATTRIBUTE_READONLY; + + NtSetInformationFile( + fileHandle, + &isb, + &fileInfo, + sizeof(FILE_BASIC_INFORMATION), + FileBasicInformation + ); + + NtClose(fileHandle); + } + } + + PhDeleteFileWin32(PhGetString(fullName)); + } + + PhDereferenceObject(fullName); + return TRUE; +} + +/** +* Deletes a directory path recursively. +* +* \param DirectoryPath The Win32 directory path. +*/ +NTSTATUS PhDeleteDirectory( + _In_ PPH_STRING DirectoryPath + ) +{ + NTSTATUS status; + HANDLE directoryHandle; + + status = PhCreateFileWin32( + &directoryHandle, + PhGetString(DirectoryPath), + FILE_GENERIC_READ | DELETE, + 0, + FILE_SHARE_READ | FILE_SHARE_DELETE, + FILE_OPEN, + FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT + ); + + if (NT_SUCCESS(status)) + { + IO_STATUS_BLOCK isb; + FILE_DISPOSITION_INFORMATION fileInfo; + + // Remove any files or folders inside the directory. + status = PhEnumDirectoryFile( + directoryHandle, + NULL, + PhpDeleteDirectoryCallback, + DirectoryPath + ); + + // Remove the directory. + fileInfo.DeleteFile = TRUE; + status = NtSetInformationFile( + directoryHandle, + &isb, + &fileInfo, + sizeof(FILE_DISPOSITION_INFORMATION), + FileDispositionInformation + ); + + NtClose(directoryHandle); + } + + if (!RtlDoesFileExists_U(PhGetString(DirectoryPath))) + return STATUS_SUCCESS; + + return status; +} + /** * Creates an anonymous pipe. * diff --git a/phlib/settings.c b/phlib/settings.c index 5687b891d26b..173afb1cbe91 100644 --- a/phlib/settings.c +++ b/phlib/settings.c @@ -925,7 +925,7 @@ NTSTATUS PhSaveSettings( if (indexOfFileName != -1) { directoryName = PhSubstring(fullPath, 0, indexOfFileName); - //SHCreateDirectoryEx(NULL, directoryName->Buffer, NULL); + //PhCreateDirectory(directoryName); PhDereferenceObject(directoryName); } diff --git a/phlib/util.c b/phlib/util.c index e5f0f6d7b38a..163208755298 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -5021,10 +5021,22 @@ PPH_STRING PhGetCacheDirectory( VOID ) { - return PhGetKnownLocation(CSIDL_LOCAL_APPDATA, L"\\Process Hacker\\Cache\\"); + return PhGetKnownLocation(CSIDL_LOCAL_APPDATA, L"\\Process Hacker\\Cache"); } -PPH_STRING PhGetCacheFileName( +VOID PhClearCacheDirectory( + VOID + ) +{ + PPH_STRING cacheDirectory; + + cacheDirectory = PhGetCacheDirectory(); + PhDeleteDirectory(cacheDirectory); + + PhDereferenceObject(cacheDirectory); +} + +PPH_STRING PhCreateCacheFile( _In_ PPH_STRING FileName ) { @@ -5050,13 +5062,10 @@ PPH_STRING PhGetCacheFileName( { PPH_STRING directoryPath; - if (indexOfFileName != -1) + if (indexOfFileName != -1 && (directoryPath = PhSubstring(cacheFullFilePath, 0, indexOfFileName))) { - if (directoryPath = PhSubstring(cacheFullFilePath, 0, indexOfFileName)) - { - SHCreateDirectoryEx(NULL, directoryPath->Buffer, NULL); - PhDereferenceObject(directoryPath); - } + PhCreateDirectory(directoryPath); + PhDereferenceObject(directoryPath); } } @@ -5065,3 +5074,28 @@ PPH_STRING PhGetCacheFileName( return cacheFullFilePath; } + +VOID PhDeleteCacheFile( + _In_ PPH_STRING FileName + ) +{ + PPH_STRING cacheDirectory; + PPH_STRING cacheFullFilePath; + ULONG indexOfFileName = -1; + + if (RtlDoesFileExists_U(PhGetString(FileName))) + { + PhDeleteFileWin32(PhGetString(FileName)); + } + + if (cacheFullFilePath = PhGetFullPath(PhGetString(FileName), &indexOfFileName)) + { + if (indexOfFileName != -1 && (cacheDirectory = PhSubstring(cacheFullFilePath, 0, indexOfFileName))) + { + PhDeleteDirectory(cacheDirectory); + PhDereferenceObject(cacheDirectory); + } + + PhDereferenceObject(cacheFullFilePath); + } +} diff --git a/plugins/ExtraPlugins/cloud.c b/plugins/ExtraPlugins/cloud.c index f8a791741008..d2afea082a3f 100644 --- a/plugins/ExtraPlugins/cloud.c +++ b/plugins/ExtraPlugins/cloud.c @@ -313,7 +313,7 @@ NTSTATUS SetupExtractBuild( extractPath = PhConcatStringRef3(&directory->sr, &pluginsDirectory, &fileName->sr); fullSetupPath = PhGetFullPath(PhGetStringOrEmpty(extractPath), &indexOfFileName); - SHCreateDirectoryEx(NULL, PhGetStringOrEmpty(fullSetupPath), NULL); + PhCreateDirectory(PhGetString(fullSetupPath)); PhDereferenceObject(fullSetupPath); PhDereferenceObject(extractPath); @@ -340,7 +340,8 @@ NTSTATUS SetupExtractBuild( { if (directoryPath = PhSubstring(fullSetupPath, 0, indexOfFileName)) { - SHCreateDirectoryEx(NULL, PhGetStringOrEmpty(directoryPath), NULL); + PhCreateDirectory(PhGetString(directoryPath)); + PhDereferenceObject(directoryPath); } } diff --git a/plugins/ExtraPlugins/dialog.c b/plugins/ExtraPlugins/dialog.c index 50ca89609f1e..2a1f9708ac07 100644 --- a/plugins/ExtraPlugins/dialog.c +++ b/plugins/ExtraPlugins/dialog.c @@ -434,11 +434,6 @@ INT_PTR CALLBACK CloudPluginsDlgProc( PhInsertEMenuItem(menu, selectedItem, -1); PhInsertEMenuItem(menu, PhCreateEMenuItem(PH_EMENU_SEPARATOR, 0, NULL, NULL, NULL), -1); PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_MENU_DISABLE, L"Disable", NULL, NULL), -1); - - if (!PhGetOwnTokenAttributes().Elevated) - { - PhSetFlagsEMenuItem(menu, ID_MENU_INSTALL, PH_EMENU_DISABLED, PH_EMENU_DISABLED); - } } selectedItem = PhShowEMenu( diff --git a/plugins/ExtraPlugins/plugin.c b/plugins/ExtraPlugins/plugin.c index 2e9b5bbed56f..1bfd3d10c733 100644 --- a/plugins/ExtraPlugins/plugin.c +++ b/plugins/ExtraPlugins/plugin.c @@ -208,15 +208,10 @@ PPHAPP_PLUGIN PhCreateDisabledPlugin( return plugin; } - - - - PPH_HASHTABLE PluginHashtable = NULL; PPH_LIST PluginList = NULL; PH_QUEUED_LOCK PluginListLock = PH_QUEUED_LOCK_INIT; - PPH_STRING PluginGetVersionInfo( _In_ PPH_STRING FileName ) diff --git a/plugins/ExtraPlugins/setup/updater.c b/plugins/ExtraPlugins/setup/updater.c index d8a6d0d95c14..8a1ce61eb1d3 100644 --- a/plugins/ExtraPlugins/setup/updater.c +++ b/plugins/ExtraPlugins/setup/updater.c @@ -91,44 +91,6 @@ PPH_STRING UpdaterGetOpaqueXmlNodeText( return PhReferenceEmptyString(); } -BOOLEAN LastUpdateCheckExpired( - VOID - ) -{ -#ifdef FORCE_UPDATE_CHECK - return TRUE; -#else - ULONG64 lastUpdateTimeTicks = 0; - LARGE_INTEGER currentUpdateTimeTicks; - //PPH_STRING lastUpdateTimeString; - - // Get the last update check time - //lastUpdateTimeString = PhGetStringSetting(SETTING_NAME_LAST_CHECK); - //PhStringToInteger64(&lastUpdateTimeString->sr, 0, &lastUpdateTimeTicks); - - // Query the current time - PhQuerySystemTime(¤tUpdateTimeTicks); - - // Check if the last update check was more than 7 days ago - if (currentUpdateTimeTicks.QuadPart - lastUpdateTimeTicks >= 7 * PH_TICKS_PER_DAY) - { - PPH_STRING currentUpdateTimeString = PhFormatUInt64(currentUpdateTimeTicks.QuadPart, FALSE); - - // Save the current time - // PhSetStringSetting2(SETTING_NAME_LAST_CHECK, ¤tUpdateTimeString->sr); - - // Cleanup - PhDereferenceObject(currentUpdateTimeString); - // P//hDereferenceObject(lastUpdateTimeString); - return TRUE; - } - - // Cleanup - //PhDereferenceObject(lastUpdateTimeString); - return FALSE; -#endif -} - PPH_STRING UpdateVersionString( VOID ) @@ -284,6 +246,7 @@ NTSTATUS UpdateDownloadThread( BOOLEAN downloadSuccess = FALSE; BOOLEAN hashSuccess = FALSE; BOOLEAN signatureSuccess = FALSE; + LONG updateResult = PH_UPDATEISERRORED; HANDLE tempFileHandle = NULL; HINTERNET httpSessionHandle = NULL; HINTERNET httpConnectionHandle = NULL; @@ -302,7 +265,7 @@ NTSTATUS UpdateDownloadThread( SendMessage(context->DialogHandle, TDM_UPDATE_ELEMENT_TEXT, TDE_MAIN_INSTRUCTION, (LPARAM)L"Initializing download request..."); - context->SetupFilePath = PhGetCacheFileName(PhaFormatString( + context->SetupFilePath = PhCreateCacheFile(PhaFormatString( L"%s.zip", PhGetStringOrEmpty(context->Node->InternalName) )); @@ -563,18 +526,18 @@ NTSTATUS UpdateDownloadThread( { if (NT_SUCCESS(SetupExtractBuild(context))) { - PostMessage(context->DialogHandle, PH_UPDATESUCCESS, 0, 0); - } - else - { - PostMessage(context->DialogHandle, PH_UPDATEISERRORED, 0, 0); + updateResult = PH_UPDATESUCCESS; } } - else + + if (context->SetupFilePath) { - PostMessage(context->DialogHandle, PH_UPDATEISERRORED, 0, 0); + PhDeleteCacheFile(context->SetupFilePath); + PhDereferenceObject(context->SetupFilePath); } + PostMessage(context->DialogHandle, updateResult, 0, 0); + return STATUS_SUCCESS; } diff --git a/plugins/NetworkTools/update.c b/plugins/NetworkTools/update.c index 45a2db920356..8c8692b1b0ef 100644 --- a/plugins/NetworkTools/update.c +++ b/plugins/NetworkTools/update.c @@ -291,7 +291,6 @@ NTSTATUS GeoIPUpdateThread( PPH_STRING fwLinkUrl = NULL; PPH_STRING downloadHostPath = NULL; PPH_STRING downloadUrlPath = NULL; - PPH_STRING directoryPath = NULL; URL_COMPONENTS httpUrlComponents = { sizeof(URL_COMPONENTS) }; LARGE_INTEGER timeNow; LARGE_INTEGER timeStart; @@ -305,7 +304,7 @@ NTSTATUS GeoIPUpdateThread( if (!(fwLinkUrl = QueryFwLinkUrl(context))) goto CleanupExit; - context->SetupFilePath = PhGetCacheFileName(PhaCreateString(L"GeoLite2-Country.mmdb.gz")); + context->SetupFilePath = PhCreateCacheFile(PhaCreateString(L"GeoLite2-Country.mmdb.gz")); if (PhIsNullOrEmptyString(context->SetupFilePath)) goto CleanupExit; @@ -603,15 +602,10 @@ NTSTATUS GeoIPUpdateThread( if (userAgentString) PhDereferenceObject(userAgentString); - if (RtlDoesFileExists_U(PhGetString(context->SetupFilePath))) + if (context->SetupFilePath) { - PhDeleteFileWin32(PhGetString(context->SetupFilePath)); - } - - if (directoryPath) - { - RemoveDirectory(PhGetString(directoryPath)); - PhDereferenceObject(directoryPath); + PhDeleteCacheFile(context->SetupFilePath); + PhDereferenceObject(context->SetupFilePath); } if (success) diff --git a/plugins/Updater/page5.c b/plugins/Updater/page5.c index 0b766debcfeb..863578027588 100644 --- a/plugins/Updater/page5.c +++ b/plugins/Updater/page5.c @@ -152,10 +152,8 @@ VOID ShowLatestVersionDialog( config.pszWindowTitle = L"Process Hacker - Updater"; config.pszMainInstruction = L"You're running the latest version."; config.pszContent = PhaFormatString( - L"Version: v%lu.%lu.%lu\r\nCompiled: %s\r\n\r\nView Changelog", - Context->CurrentMajorVersion, - Context->CurrentMinorVersion, - Context->CurrentRevisionVersion, + L"Version: v%s\r\nCompiled: %s\r\n\r\nView Changelog", + PhGetStringOrEmpty(Context->CurrentVersionString), PhaFormatDateTime(&systemTime)->Buffer )->Buffer; @@ -180,10 +178,8 @@ VOID ShowNewerVersionDialog( config.pszWindowTitle = L"Process Hacker - Updater"; config.pszMainInstruction = L"You're running a pre-release build."; config.pszContent = PhaFormatString( - L"Pre-release build: v%lu.%lu.%lu\r\n", - Context->CurrentMajorVersion, - Context->CurrentMinorVersion, - Context->CurrentRevisionVersion + L"Pre-release build: v%s\r\n", + PhGetStringOrEmpty(Context->CurrentVersionString) )->Buffer; SendMessage(Context->DialogHandle, TDM_NAVIGATE_PAGE, 0, (LPARAM)&config); diff --git a/plugins/Updater/updater.c b/plugins/Updater/updater.c index 1e5c29dd70f1..16790f4ab3ad 100644 --- a/plugins/Updater/updater.c +++ b/plugins/Updater/updater.c @@ -37,12 +37,7 @@ PPH_UPDATER_CONTEXT CreateUpdateContext( context = (PPH_UPDATER_CONTEXT)PhCreateAlloc(sizeof(PH_UPDATER_CONTEXT)); memset(context, 0, sizeof(PH_UPDATER_CONTEXT)); - PhGetPhVersionNumbers( - &context->CurrentMajorVersion, - &context->CurrentMinorVersion, - NULL, - &context->CurrentRevisionVersion - ); + context->CurrentVersionString = PhGetPhVersion(); context->StartupCheck = StartupCheck; return context; @@ -62,7 +57,8 @@ VOID FreeUpdateContext( PhClearReference(&Context->SetupFilePath); PhClearReference(&Context->SetupFileDownloadUrl); PhClearReference(&Context->BuildMessage); - + PhClearReference(&Context->CurrentVersionString); + PhDereferenceObject(Context); } @@ -155,18 +151,20 @@ BOOLEAN LastUpdateCheckExpired( lastUpdateTimeString = PhGetStringSetting(SETTING_NAME_LAST_CHECK); PhStringToInteger64(&lastUpdateTimeString->sr, 0, &lastUpdateTimeTicks); - PhDereferenceObject(lastUpdateTimeString); if (currentUpdateTimeTicks.QuadPart - lastUpdateTimeTicks >= 7 * PH_TICKS_PER_DAY) { - PPH_STRING currentUpdateTimeString = PhFormatUInt64(currentUpdateTimeTicks.QuadPart, FALSE); - + PPH_STRING currentUpdateTimeString; + + currentUpdateTimeString = PhFormatUInt64(currentUpdateTimeTicks.QuadPart, FALSE); PhSetStringSetting2(SETTING_NAME_LAST_CHECK, ¤tUpdateTimeString->sr); - PhDereferenceObject(currentUpdateTimeString); + PhDereferenceObject(currentUpdateTimeString); + PhDereferenceObject(lastUpdateTimeString); return TRUE; } + PhDereferenceObject(lastUpdateTimeString); return FALSE; } @@ -521,12 +519,7 @@ NTSTATUS UpdateCheckSilentThread( if (!QueryUpdateData(context)) goto CleanupExit; - currentVersion = MAKE_VERSION_ULONGLONG( - context->CurrentMajorVersion, - context->CurrentMinorVersion, - context->CurrentRevisionVersion, - 0 - ); + currentVersion = ParseVersionString(context->CurrentVersionString); #ifdef FORCE_UPDATE_CHECK latestVersion = MAKE_VERSION_ULONGLONG( @@ -542,9 +535,6 @@ NTSTATUS UpdateCheckSilentThread( // Compare the current version against the latest available version if (currentVersion < latestVersion) { - // Don't spam the user the second they open PH, delay dialog creation for 3 seconds. - //Sleep(3000); - // Check if the user hasn't already opened the dialog. if (!UpdateDialogHandle) { @@ -589,12 +579,7 @@ NTSTATUS UpdateCheckThread( return STATUS_SUCCESS; } - currentVersion = MAKE_VERSION_ULONGLONG( - context->CurrentMajorVersion, - context->CurrentMinorVersion, - context->CurrentRevisionVersion, - 0 - ); + currentVersion = ParseVersionString(context->CurrentVersionString); #ifdef FORCE_UPDATE_CHECK latestVersion = MAKE_VERSION_ULONGLONG( @@ -640,7 +625,7 @@ static PPH_STRING UpdaterParseDownloadFileName( return NULL; downloadFileName = PhCreateString2(&baseNamePart); - filePath = PhGetCacheFileName(downloadFileName); + filePath = PhCreateCacheFile(downloadFileName); PhDereferenceObject(downloadFileName); return filePath; @@ -672,12 +657,9 @@ NTSTATUS UpdateDownloadThread( // Create a user agent string. userAgentString = PhFormatString( - L"PH_%lu.%lu_%lu", - context->CurrentMajorVersion, - context->CurrentMinorVersion, - context->CurrentRevisionVersion + L"PH_%s", + PhGetStringOrEmpty(context->CurrentVersionString) ); - if (PhIsNullOrEmptyString(userAgentString)) goto CleanupExit; @@ -715,13 +697,13 @@ NTSTATUS UpdateDownloadThread( if (PhIsNullOrEmptyString(context->SetupFilePath)) goto CleanupExit; - // Create output file + // Create temporary output file. if (!NT_SUCCESS(PhCreateFileWin32( &tempFileHandle, PhGetString(context->SetupFilePath), - FILE_GENERIC_READ | FILE_GENERIC_WRITE, - FILE_ATTRIBUTE_NOT_CONTENT_INDEXED | FILE_ATTRIBUTE_TEMPORARY, - FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + FILE_GENERIC_WRITE, + FILE_ATTRIBUTE_NORMAL, + FILE_SHARE_READ, FILE_OVERWRITE_IF, FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT ))) @@ -991,7 +973,7 @@ LRESULT CALLBACK TaskDialogSubclassProc( switch (uMsg) { - case WM_INITDIALOG: + case PH_SHOWDIALOG: { if (IsMinimized(hwndDlg)) ShowWindow(hwndDlg, SW_RESTORE); @@ -1095,6 +1077,7 @@ HRESULT CALLBACK TaskDialogBootstrapCallback( ) { PPH_UPDATER_CONTEXT context = (PPH_UPDATER_CONTEXT)dwRefData; + UpdateDialogHandle = hwndDlg; switch (uMsg) { @@ -1177,7 +1160,7 @@ VOID ShowUpdateDialog( PhWaitForEvent(&InitializedEvent, NULL); } - PostMessage(UpdateDialogHandle, WM_INITDIALOG, 0, 0); + PostMessage(UpdateDialogHandle, PH_SHOWDIALOG, 0, 0); } VOID StartInitialCheck( diff --git a/plugins/Updater/updater.h b/plugins/Updater/updater.h index d4bf4abda0aa..f0ecd291f096 100644 --- a/plugins/Updater/updater.h +++ b/plugins/Updater/updater.h @@ -45,6 +45,7 @@ #define PH_UPDATENEWER (WM_APP + 504) #define PH_UPDATESUCCESS (WM_APP + 505) #define PH_UPDATEFAILURE (WM_APP + 506) +#define PH_SHOWDIALOG (WM_APP + 507) #define PLUGIN_NAME L"ProcessHacker.UpdateChecker" #define SETTING_NAME_AUTO_CHECK (PLUGIN_NAME L".PromptStart") @@ -89,9 +90,7 @@ typedef struct _PH_UPDATER_CONTEXT HWND DialogHandle; ULONG ErrorCode; - ULONG CurrentMinorVersion; - ULONG CurrentMajorVersion; - ULONG CurrentRevisionVersion; + PPH_STRING CurrentVersionString; PPH_STRING Version; PPH_STRING RevVersion; PPH_STRING RelDate; diff --git a/plugins/UserNotes/db.c b/plugins/UserNotes/db.c index 3e96290eb91e..6a7b2b9082ac 100644 --- a/plugins/UserNotes/db.c +++ b/plugins/UserNotes/db.c @@ -417,7 +417,7 @@ NTSTATUS SaveDb( if (fullPath = PH_AUTO(PhGetFullPath(ObjectDbPath->Buffer, &indexOfFileName))) { if (indexOfFileName != -1) - SHCreateDirectoryEx(NULL, PhaSubstring(fullPath, 0, indexOfFileName)->Buffer, NULL); + PhCreateDirectory(PhaSubstring(fullPath, 0, indexOfFileName)); } } diff --git a/tools/CustomSetupTool/CustomSetupTool/appsup.c b/tools/CustomSetupTool/CustomSetupTool/appsup.c index c94f746e94aa..a4c317b4f8ee 100644 --- a/tools/CustomSetupTool/CustomSetupTool/appsup.c +++ b/tools/CustomSetupTool/CustomSetupTool/appsup.c @@ -406,36 +406,6 @@ BOOLEAN DialogPromptExit( return buttonPressed == IDNO; } -BOOLEAN CheckProcessHackerRunning( - VOID - ) -{ - HANDLE mutantHandle; - OBJECT_ATTRIBUTES oa; - UNICODE_STRING mutantName; - - RtlInitUnicodeString(&mutantName, L"\\BaseNamedObjects\\ProcessHackerMutant"); - InitializeObjectAttributes( - &oa, - &mutantName, - 0, - NULL, - NULL - ); - - if (NT_SUCCESS(NtOpenMutant( - &mutantHandle, - MUTANT_QUERY_STATE, - &oa - ))) - { - NtClose(mutantHandle); - return TRUE; - } - - return FALSE; -} - BOOLEAN CheckProcessHackerInstalled( VOID ) @@ -521,145 +491,3 @@ BOOLEAN ShutdownProcessHacker(VOID) PhEnumDirectoryObjects(PhGetNamespaceHandle(), PhpPreviousInstancesCallback, NULL); return TRUE; } - -BOOLEAN CreateDirectoryPath(_In_ PWSTR DirPath) -{ - BOOLEAN success = FALSE; - PPH_STRING dirPathString = NULL; - PWSTR dirPathDup = NULL; - - if (RtlDoesFileExists_U(DirPath)) - return TRUE; - - if ((dirPathDup = PhDuplicateStringZ(DirPath)) == NULL) - goto CleanupExit; - - for (PWSTR path = _wcstok(dirPathDup, L"\\"); path; path = _wcstok(NULL, L"\\")) - { - if (!dirPathString) - dirPathString = PhCreateString(path); - else - { - PPH_STRING tempPathString; - - tempPathString = PhConcatStrings( - 3, - dirPathString->Buffer, - L"\\", - path - ); - - if (!RtlDoesFileExists_U(PhGetString(tempPathString))) - { - if (!CreateDirectory(PhGetString(tempPathString), NULL)) - { - PhDereferenceObject(tempPathString); - goto CleanupExit; - } - } - - PhSwapReference(&dirPathString, tempPathString); - PhDereferenceObject(tempPathString); - } - } - - success = TRUE; - -CleanupExit: - - if (dirPathString) - { - PhDereferenceObject(dirPathString); - } - - if (dirPathDup) - { - PhFree(dirPathDup); - } - - return success; -} - -BOOLEAN RemoveDirectoryPath(_In_ PWSTR DirPath) -{ - HANDLE findHandle; - PPH_STRING findPath; - WIN32_FIND_DATA data = { 0 }; - - findPath = PhConcatStrings2(DirPath, L"\\*"); - - if ((findHandle = FindFirstFile(findPath->Buffer, &data)) == INVALID_HANDLE_VALUE) - { - if (GetLastError() == ERROR_FILE_NOT_FOUND) - { - PhDereferenceObject(findPath); - return TRUE; - } - - PhDereferenceObject(findPath); - return FALSE; - } - - do - { - if (PhEqualStringZ(data.cFileName, L".", TRUE) || PhEqualStringZ(data.cFileName, L"..", TRUE)) - continue; - - if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) - { - PPH_STRING dirPath = PhConcatStrings(3, DirPath, L"\\", data.cFileName); - - RemoveDirectoryPath(dirPath->Buffer); - PhDereferenceObject(dirPath); - } - else - { - PPH_STRING filePath = PhConcatStrings(3, DirPath, L"\\", data.cFileName); - - if (data.dwFileAttributes & FILE_ATTRIBUTE_READONLY) - { - _wchmod(filePath->Buffer, _S_IWRITE); - } - - SetupDeleteDirectoryFile(filePath->Buffer); - PhDereferenceObject(filePath); - } - - } while (FindNextFile(findHandle, &data)); - - FindClose(findHandle); - - // Delete the parent directory - RemoveDirectory(DirPath); - - PhDereferenceObject(findPath); - return TRUE; -} - -VOID SetupDeleteDirectoryFile(_In_ PWSTR FileName) -{ - HANDLE tempHandle; - FILE_DISPOSITION_INFORMATION dispositionInfo; - IO_STATUS_BLOCK isb; - - if (NT_SUCCESS(PhCreateFileWin32( - &tempHandle, - FileName, - FILE_GENERIC_WRITE | DELETE, - 0, - 0, - FILE_OVERWRITE_IF, - FILE_SYNCHRONOUS_IO_NONALERT - ))) - { - dispositionInfo.DeleteFile = TRUE; - NtSetInformationFile( - tempHandle, - &isb, - &dispositionInfo, - sizeof(FILE_DISPOSITION_INFORMATION), - FileDispositionInformation - ); - NtClose(tempHandle); - } -} \ No newline at end of file diff --git a/tools/CustomSetupTool/CustomSetupTool/download.c b/tools/CustomSetupTool/CustomSetupTool/download.c index 0fc0f7fc1aa7..eea47d368e65 100644 --- a/tools/CustomSetupTool/CustomSetupTool/download.c +++ b/tools/CustomSetupTool/CustomSetupTool/download.c @@ -405,7 +405,7 @@ BOOLEAN UpdateDownloadUpdateData( downloadFileName = PhCreateString2(&baseNamePart); } - Context->FilePath = PhGetCacheFileName(downloadFileName); + Context->FilePath = PhCreateCacheFile(downloadFileName); if (PhIsNullOrEmptyString(Context->FilePath)) goto CleanupExit; diff --git a/tools/CustomSetupTool/CustomSetupTool/extract.c b/tools/CustomSetupTool/CustomSetupTool/extract.c index a82b278aae02..b6da5136be6d 100644 --- a/tools/CustomSetupTool/CustomSetupTool/extract.c +++ b/tools/CustomSetupTool/CustomSetupTool/extract.c @@ -177,7 +177,7 @@ BOOLEAN SetupExtractBuild( if (directoryPath = PhSubstring(fullSetupPath, 0, indexOfFileName)) { - if (!CreateDirectoryPath(PhGetString(directoryPath))) + if (!NT_SUCCESS(PhCreateDirectory(PhGetString(directoryPath)))) { PhDereferenceObject(directoryPath); PhDereferenceObject(fullSetupPath); diff --git a/tools/CustomSetupTool/CustomSetupTool/include/appsup.h b/tools/CustomSetupTool/CustomSetupTool/include/appsup.h index 5a173e411ec9..8601e3c1cc9e 100644 --- a/tools/CustomSetupTool/CustomSetupTool/include/appsup.h +++ b/tools/CustomSetupTool/CustomSetupTool/include/appsup.h @@ -44,10 +44,6 @@ PVOID ExtractResourceToBuffer( _In_ PWSTR Resource ); -VOID SetupDeleteDirectoryFile( - _In_ PWSTR FileName - ); - VOID SetupInitializeFont( _In_ HWND ControlHandle, _In_ LONG Height, @@ -80,13 +76,4 @@ BOOLEAN ShutdownProcessHacker( VOID ); -BOOLEAN CreateDirectoryPath( - _In_ PWSTR DirectoryPath - ); - -BOOLEAN RemoveDirectoryPath( - _In_ PWSTR DirPath - ); - - -#endif \ No newline at end of file +#endif diff --git a/tools/CustomSetupTool/CustomSetupTool/install.c b/tools/CustomSetupTool/CustomSetupTool/install.c index c8372ca76d34..69826e9bc9ca 100644 --- a/tools/CustomSetupTool/CustomSetupTool/install.c +++ b/tools/CustomSetupTool/CustomSetupTool/install.c @@ -39,7 +39,7 @@ NTSTATUS SetupProgressThread( goto CleanupExit; // Create the install folder path. - if (!CreateDirectoryPath(PhGetString(Context->SetupInstallPath))) + if (!NT_SUCCESS(PhCreateDirectory(Context->SetupInstallPath))) goto CleanupExit; // Upgrade the 2.x settings file. @@ -47,7 +47,9 @@ NTSTATUS SetupProgressThread( // Remove the previous installation. if (Context->SetupResetSettings) - RemoveDirectoryPath(PhGetString(Context->SetupInstallPath)); + { + PhDeleteDirectory(Context->SetupInstallPath); + } // Create the uninstaller. if (!SetupCreateUninstallFile(Context)) diff --git a/tools/CustomSetupTool/CustomSetupTool/main.c b/tools/CustomSetupTool/CustomSetupTool/main.c index 227c2cef77d4..0ef34e6c04b7 100644 --- a/tools/CustomSetupTool/CustomSetupTool/main.c +++ b/tools/CustomSetupTool/CustomSetupTool/main.c @@ -20,34 +20,7 @@ #include -HANDLE MutantHandle = NULL; SETUP_COMMAND_TYPE SetupMode = SETUP_COMMAND_INSTALL; -PH_COMMAND_LINE_OPTION options[] = -{ - { SETUP_COMMAND_INSTALL, L"install", NoArgumentType }, - { SETUP_COMMAND_UNINSTALL, L"uninstall", NoArgumentType }, - { SETUP_COMMAND_UPDATE, L"update", NoArgumentType }, - { SETUP_COMMAND_REPAIR, L"repair", NoArgumentType }, -}; - -NTSTATUS CreateSetupMutant( - VOID - ) -{ - OBJECT_ATTRIBUTES oa; - UNICODE_STRING mutantName; - - RtlInitUnicodeString(&mutantName, L"\\BaseNamedObjects\\ProcessHackerSetup"); - InitializeObjectAttributes( - &oa, - &mutantName, - 0, - NULL, - NULL - ); - - return NtCreateMutant(&MutantHandle, MUTANT_ALL_ACCESS, &oa, FALSE); -} VOID SetupInitializeDpi( VOID @@ -205,10 +178,17 @@ INT WINAPI wWinMain( _In_ INT CmdShow ) { + static PH_COMMAND_LINE_OPTION options[] = + { + { SETUP_COMMAND_INSTALL, L"install", NoArgumentType }, + { SETUP_COMMAND_UNINSTALL, L"uninstall", NoArgumentType }, + { SETUP_COMMAND_UPDATE, L"update", NoArgumentType }, + { SETUP_COMMAND_REPAIR, L"repair", NoArgumentType }, + }; + HANDLE mutantHandle; PPH_STRING commandLine; - - if (!NT_SUCCESS(CreateSetupMutant())) - return 1; + OBJECT_ATTRIBUTES oa; + UNICODE_STRING mutantName; CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE); @@ -237,23 +217,35 @@ INT WINAPI wWinMain( PhDereferenceObject(commandLine); - // DEBUG // if (CheckProcessHackerInstalled()) SetupMode = SETUP_COMMAND_UNINSTALL; + RtlInitUnicodeString(&mutantName, L"PhSetupMutant"); + InitializeObjectAttributes( + &oa, + &mutantName, + 0, + PhGetNamespaceHandle(), + NULL + ); - switch (SetupMode) + if (NT_SUCCESS(NtCreateMutant(&mutantHandle, MUTANT_ALL_ACCESS, &oa, FALSE))) { - case SETUP_COMMAND_INSTALL: - default: - SetupShowInstallDialog(); - break; - case SETUP_COMMAND_UNINSTALL: - SetupShowUninstallDialog(); - break; - case SETUP_COMMAND_UPDATE: - SetupShowUpdateDialog(); - break; - case SETUP_COMMAND_REPAIR: - break; + switch (SetupMode) + { + case SETUP_COMMAND_INSTALL: + default: + SetupShowInstallDialog(); + break; + case SETUP_COMMAND_UNINSTALL: + SetupShowUninstallDialog(); + break; + case SETUP_COMMAND_UPDATE: + SetupShowUpdateDialog(); + break; + case SETUP_COMMAND_REPAIR: + break; + } + + NtClose(mutantHandle); } - return 0; + return ERROR_SUCCESS; } \ No newline at end of file diff --git a/tools/CustomSetupTool/CustomSetupTool/setup.c b/tools/CustomSetupTool/CustomSetupTool/setup.c index 1c8e6e5906f3..b9fbfaab07be 100644 --- a/tools/CustomSetupTool/CustomSetupTool/setup.c +++ b/tools/CustomSetupTool/CustomSetupTool/setup.c @@ -131,16 +131,17 @@ PPH_STRING SetupFindInstallDirectory( // Check if the string is valid. if (PhIsNullOrEmptyString(setupInstallPath)) { - PH_STRINGREF programW6432 = PH_STRINGREF_INIT(L"%ProgramW6432%"); - PH_STRINGREF programFiles = PH_STRINGREF_INIT(L"%ProgramFiles%"); - PH_STRINGREF defaultDirectoryName = PH_STRINGREF_INIT(L"\\Process Hacker\\"); + static PH_STRINGREF programW6432 = PH_STRINGREF_INIT(L"%ProgramW6432%"); + static PH_STRINGREF programFiles = PH_STRINGREF_INIT(L"%ProgramFiles%"); + static PH_STRINGREF defaultDirectoryName = PH_STRINGREF_INIT(L"\\Process Hacker\\"); SYSTEM_INFO info; - PPH_STRING expandedString; GetNativeSystemInfo(&info); if (info.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) { + PPH_STRING expandedString; + if (expandedString = PH_AUTO(PhExpandEnvironmentStrings(&programW6432))) { setupInstallPath = PhConcatStringRef2(&expandedString->sr, &defaultDirectoryName); @@ -148,6 +149,8 @@ PPH_STRING SetupFindInstallDirectory( } else { + PPH_STRING expandedString; + if (expandedString = PH_AUTO(PhExpandEnvironmentStrings(&programFiles))) { setupInstallPath = PhConcatStringRef2(&expandedString->sr, &defaultDirectoryName); @@ -189,13 +192,13 @@ BOOLEAN SetupCreateUninstallFile( if (RtlDoesFileExists_U(backupFilePath->Buffer)) { - if (!DeleteFile(backupFilePath->Buffer)) + if (!NT_SUCCESS(PhDeleteFileWin32(backupFilePath->Buffer))) { PPH_STRING tempFileName; PPH_STRING tempFilePath; tempFileName = PhCreateString(L"processhacker-setup.old"); - tempFilePath = PhGetCacheFileName(tempFileName); + tempFilePath = PhCreateCacheFile(tempFileName); if (!MoveFile(backupFilePath->Buffer, tempFilePath->Buffer)) { @@ -240,7 +243,7 @@ VOID SetupDeleteUninstallFile( PPH_STRING tempFilePath; tempFileName = PhCreateString(L"processhacker-setup.exe"); - tempFilePath = PhGetCacheFileName(tempFileName); + tempFilePath = PhCreateCacheFile(tempFileName); if (PhIsNullOrEmptyString(tempFilePath)) { @@ -259,6 +262,127 @@ VOID SetupDeleteUninstallFile( PhDereferenceObject(uninstallFilePath); } +VOID SetupStartService( + _In_ PWSTR ServiceName + ) +{ + SC_HANDLE serviceHandle; + + serviceHandle = PhOpenService( + ServiceName, + SERVICE_QUERY_STATUS | SERVICE_START + ); + + if (serviceHandle) + { + ULONG statusLength = 0; + SERVICE_STATUS_PROCESS status; + + memset(&status, 0, sizeof(SERVICE_STATUS_PROCESS)); + + if (QueryServiceStatusEx( + serviceHandle, + SC_STATUS_PROCESS_INFO, + (PBYTE)&status, + sizeof(SERVICE_STATUS_PROCESS), + &statusLength + )) + { + if (status.dwCurrentState != SERVICE_RUNNING) + { + ULONG attempts = 5; + + do + { + StartService(serviceHandle, 0, NULL); + + if (QueryServiceStatusEx( + serviceHandle, + SC_STATUS_PROCESS_INFO, + (PBYTE)&status, + sizeof(SERVICE_STATUS_PROCESS), + &statusLength + )) + { + if (status.dwCurrentState == SERVICE_RUNNING) + { + break; + } + } + + Sleep(1000); + + } while (--attempts != 0); + } + } + + CloseServiceHandle(serviceHandle); + } +} + +VOID SetupStopService( + _In_ PWSTR ServiceName + ) +{ + SC_HANDLE serviceHandle; + + serviceHandle = PhOpenService( + ServiceName, + SERVICE_QUERY_STATUS | SERVICE_STOP + ); + + if (serviceHandle) + { + ULONG statusLength = 0; + SERVICE_STATUS_PROCESS status; + + memset(&status, 0, sizeof(SERVICE_STATUS_PROCESS)); + + if (QueryServiceStatusEx( + serviceHandle, + SC_STATUS_PROCESS_INFO, + (PBYTE)&status, + sizeof(SERVICE_STATUS_PROCESS), + &statusLength + )) + { + if (status.dwCurrentState != SERVICE_STOPPED) + { + ULONG attempts = 5; + + do + { + SERVICE_STATUS serviceStatus; + + memset(&serviceStatus, 0, sizeof(SERVICE_STATUS)); + + ControlService(serviceHandle, SERVICE_CONTROL_STOP, &serviceStatus); + + if (QueryServiceStatusEx( + serviceHandle, + SC_STATUS_PROCESS_INFO, + (PBYTE)&status, + sizeof(SERVICE_STATUS_PROCESS), + &statusLength + )) + { + if (status.dwCurrentState == SERVICE_STOPPED) + { + break; + } + } + + Sleep(1000); + + } while (--attempts != 0); + } + } + + CloseServiceHandle(serviceHandle); + } +} + + VOID SetupStartKph( _In_ PPH_SETUP_CONTEXT Context ) @@ -287,21 +411,7 @@ VOID SetupStartKph( NtClose(processHandle); } - while (retries < 5) - { - SC_HANDLE serviceHandle; - SERVICE_STATUS serviceStatus; - - if (serviceHandle = PhOpenService(L"KProcessHacker3", SERVICE_START)) - { - StartService(serviceHandle, 0, NULL); - CloseServiceHandle(serviceHandle); - break; - } - - Sleep(1000); - retries++; - } + SetupStartService(L"KProcessHacker3"); } PhDereferenceObject(clientPath); @@ -311,43 +421,9 @@ BOOLEAN SetupUninstallKph( _In_ PPH_SETUP_CONTEXT Context ) { - ULONG retries = 0; - - while (retries < 5) - { - SC_HANDLE serviceHandle; - SERVICE_STATUS serviceStatus; - - if (serviceHandle = PhOpenService(L"KProcessHacker2", SERVICE_STOP | DELETE)) - { - ControlService(serviceHandle, SERVICE_CONTROL_STOP, &serviceStatus); - DeleteService(serviceHandle); - CloseServiceHandle(serviceHandle); - break; - } - - Sleep(1000); - retries++; - } + SetupStopService(L"KProcessHacker2"); - retries = 0; - - while (retries < 5) - { - SC_HANDLE serviceHandle; - SERVICE_STATUS serviceStatus; - - if (serviceHandle = PhOpenService(L"KProcessHacker3", SERVICE_STOP | DELETE)) - { - ControlService(serviceHandle, SERVICE_CONTROL_STOP, &serviceStatus); - DeleteService(serviceHandle); - CloseServiceHandle(serviceHandle); - break; - } - - Sleep(1000); - retries++; - } + SetupStopService(L"KProcessHacker3"); return TRUE; } @@ -410,7 +486,7 @@ VOID SetupSetWindowsOptions( { PPH_STRING settingsFileName = PhGetKnownLocation(CSIDL_APPDATA, L"\\Process Hacker\\settings.xml"); - SetupDeleteDirectoryFile(settingsFileName->Buffer); + PhDeleteFileWin32(settingsFileName->Buffer); PhDereferenceObject(settingsFileName); } @@ -494,25 +570,25 @@ VOID SetupDeleteWindowsOptions( if (startmenuFolderString = PhGetKnownLocation(CSIDL_COMMON_PROGRAMS, L"\\Process Hacker.lnk")) { - SetupDeleteDirectoryFile(PhGetString(startmenuFolderString)); + PhDeleteFileWin32(PhGetString(startmenuFolderString)); PhDereferenceObject(startmenuFolderString); } if (startmenuFolderString = PhGetKnownLocation(CSIDL_COMMON_PROGRAMS, L"\\PE Viewer.lnk")) { - SetupDeleteDirectoryFile(PhGetString(startmenuFolderString)); + PhDeleteFileWin32(PhGetString(startmenuFolderString)); PhDereferenceObject(startmenuFolderString); } if (startmenuFolderString = PhGetKnownLocation(CSIDL_DESKTOPDIRECTORY, L"\\Process Hacker.lnk")) { - SetupDeleteDirectoryFile(PhGetString(startmenuFolderString)); + PhDeleteFileWin32(PhGetString(startmenuFolderString)); PhDereferenceObject(startmenuFolderString); } if (startmenuFolderString = PhGetKnownLocation(CSIDL_COMMON_DESKTOPDIRECTORY, L"\\Process Hacker.lnk")) { - SetupDeleteDirectoryFile(PhGetString(startmenuFolderString)); + PhDeleteFileWin32(PhGetString(startmenuFolderString)); PhDereferenceObject(startmenuFolderString); } @@ -628,7 +704,6 @@ VOID SetupCreateImageFileExecutionOptions( PROCESS_CREATION_MITIGATION_POLICY_EXTENSION_POINT_DISABLE_ALWAYS_ON | PROCESS_CREATION_MITIGATION_POLICY_PROHIBIT_DYNAMIC_CODE_ALWAYS_ON | PROCESS_CREATION_MITIGATION_POLICY_CONTROL_FLOW_GUARD_ALWAYS_ON | - PROCESS_CREATION_MITIGATION_POLICY_FONT_DISABLE_ALWAYS_ON | PROCESS_CREATION_MITIGATION_POLICY_IMAGE_LOAD_NO_REMOTE_ALWAYS_ON | PROCESS_CREATION_MITIGATION_POLICY_IMAGE_LOAD_NO_LOW_LABEL_ALWAYS_ON }, sizeof(ULONG64)); diff --git a/tools/CustomSetupTool/CustomSetupTool/uninstall.c b/tools/CustomSetupTool/CustomSetupTool/uninstall.c index e9c6c8a3ccc1..697576a43c22 100644 --- a/tools/CustomSetupTool/CustomSetupTool/uninstall.c +++ b/tools/CustomSetupTool/CustomSetupTool/uninstall.c @@ -64,7 +64,7 @@ NTSTATUS SetupUninstallBuild( SetupDeleteUninstallKey(); // Remove the previous installation. - RemoveDirectoryPath(PhGetString(Context->SetupInstallPath)); + PhDeleteDirectory(Context->SetupInstallPath); ShowUninstallCompleteDialog(Context); return STATUS_SUCCESS; diff --git a/tools/peview/main.c b/tools/peview/main.c index 33fa3d33ab96..8823cf300a6f 100644 --- a/tools/peview/main.c +++ b/tools/peview/main.c @@ -63,6 +63,8 @@ INT WINAPI wWinMain( }; PPH_STRING commandLine; + CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE); + if (!NT_SUCCESS(PhInitializePhLib())) return 1; @@ -117,7 +119,6 @@ INT WINAPI wWinMain( { PPH_STRING targetFileName; - CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE); targetFileName = PvResolveShortcutTarget(PvFileName); if (targetFileName) From e253bb07ce558c801dece928d2183d1e32776508 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 11 Aug 2017 07:37:51 +1000 Subject: [PATCH 0370/2058] Add unused PhInitializeMitigationPolicy --- ProcessHacker/main.c | 62 ++++++++++++++++++++++++++++++++++++++++++ phlib/include/phutil.h | 8 ++++++ phlib/util.c | 28 +++++++++++++++++++ 3 files changed, 98 insertions(+) diff --git a/ProcessHacker/main.c b/ProcessHacker/main.c index 0291db3d0c94..498260e9c118 100644 --- a/ProcessHacker/main.c +++ b/ProcessHacker/main.c @@ -517,6 +517,68 @@ VOID PhInitializeFont( } } +VOID PhInitializeMitigationPolicy( + VOID + ) +{ + static PH_STRINGREF policyKeyName = PH_STRINGREF_INIT(L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\ProcessHacker.exe"); + static UNICODE_STRING policyKeyValue = RTL_CONSTANT_STRING(L"MitigationOptions"); + BOOLEAN policyKeyValid = FALSE; + HANDLE keyReadHandle; + HANDLE keyWriteHandle; + + if (WindowsVersion < WINDOWS_10 || !PhGetOwnTokenAttributes().Elevated) + return; + +#define DEFAULT_MITIGATION_POLICY_FLAGS \ + (PROCESS_CREATION_MITIGATION_POLICY_HEAP_TERMINATE_ALWAYS_ON | \ + PROCESS_CREATION_MITIGATION_POLICY_BOTTOM_UP_ASLR_ALWAYS_ON | \ + PROCESS_CREATION_MITIGATION_POLICY_HIGH_ENTROPY_ASLR_ALWAYS_ON | \ + PROCESS_CREATION_MITIGATION_POLICY_EXTENSION_POINT_DISABLE_ALWAYS_ON | \ + PROCESS_CREATION_MITIGATION_POLICY_PROHIBIT_DYNAMIC_CODE_ALWAYS_ON | \ + PROCESS_CREATION_MITIGATION_POLICY_CONTROL_FLOW_GUARD_ALWAYS_ON | \ + PROCESS_CREATION_MITIGATION_POLICY_IMAGE_LOAD_NO_REMOTE_ALWAYS_ON | \ + PROCESS_CREATION_MITIGATION_POLICY_IMAGE_LOAD_NO_LOW_LABEL_ALWAYS_ON) + + if (NT_SUCCESS(PhOpenKey( + &keyReadHandle, + KEY_READ, + PH_KEY_LOCAL_MACHINE, + &policyKeyName, + 0 + ))) + { + if (PhQueryRegistryUlong64(keyReadHandle, L"MitigationOptions") == DEFAULT_MITIGATION_POLICY_FLAGS) + policyKeyValid = TRUE; + + NtClose(keyReadHandle); + } + + if (policyKeyValid) + return; + + if (NT_SUCCESS(PhCreateKey( + &keyWriteHandle, + KEY_WRITE | DELETE, + PH_KEY_LOCAL_MACHINE, + &policyKeyName, + 0, + 0, + NULL + ))) + { + NtSetValueKey( + keyWriteHandle, + &policyKeyValue, + 0, + REG_QWORD, + &(ULONG64) { DEFAULT_MITIGATION_POLICY_FLAGS }, + sizeof(ULONG64) + ); + NtClose(keyWriteHandle); + } +} + NTSTATUS PhpReadSignature( _In_ PWSTR FileName, _Out_ PUCHAR *Signature, diff --git a/phlib/include/phutil.h b/phlib/include/phutil.h index 0d551968dc7f..ce202be0128b 100644 --- a/phlib/include/phutil.h +++ b/phlib/include/phutil.h @@ -812,6 +812,14 @@ PhQueryRegistryString( _In_opt_ PWSTR ValueName ); +PHLIBAPI +ULONG64 +NTAPI +PhQueryRegistryUlong64( + _In_ HANDLE KeyHandle, + _In_opt_ PWSTR ValueName + ); + typedef struct _PH_FLAG_MAPPING { ULONG Flag1; diff --git a/phlib/util.c b/phlib/util.c index 163208755298..5e20010adf6a 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -3522,6 +3522,34 @@ PPH_STRING PhQueryRegistryString( return string; } +ULONG64 PhQueryRegistryUlong64( + _In_ HANDLE KeyHandle, + _In_opt_ PWSTR ValueName + ) +{ + ULONG64 ulong64 = 0; + PH_STRINGREF valueName; + PKEY_VALUE_PARTIAL_INFORMATION buffer; + + if (ValueName) + PhInitializeStringRef(&valueName, ValueName); + else + PhInitializeEmptyStringRef(&valueName); + + if (NT_SUCCESS(PhQueryValueKey(KeyHandle, &valueName, KeyValuePartialInformation, &buffer))) + { + if (buffer->Type == REG_QWORD) + { + if (buffer->DataLength == sizeof(ULONG64)) + ulong64 = *(PULONG64)buffer->Data; + } + + PhFree(buffer); + } + + return ulong64; +} + VOID PhMapFlags1( _Inout_ PULONG Value2, _In_ ULONG Value1, From 45c458699711315c93868b2f3773fbb00650324f Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 11 Aug 2017 08:09:19 +1000 Subject: [PATCH 0371/2058] Add LocalCachePath setting, Fix build warnings --- ProcessHacker/settings.c | 1 + phlib/native.c | 21 ++++++++++++++----- phlib/util.c | 11 +++++++++- plugins/ExtraPlugins/cloud.c | 4 ++-- .../CustomSetupTool/download.c | 2 +- .../CustomSetupTool/include/setup.h | 2 -- 6 files changed, 30 insertions(+), 11 deletions(-) diff --git a/ProcessHacker/settings.c b/ProcessHacker/settings.c index 28994dd78cbe..9845dd49b0e9 100644 --- a/ProcessHacker/settings.c +++ b/ProcessHacker/settings.c @@ -80,6 +80,7 @@ VOID PhAddDefaultSettings( PhpAddIntegerSetting(L"IconTogglesVisibility", L"1"); PhpAddStringSetting(L"JobListViewColumns", L""); PhpAddIntegerSetting(L"KphUnloadOnShutdown", L"0"); + PhpAddStringSetting(L"LocalCachePath", L"%LocalAppData%\\Process Hacker\\Cache"); PhpAddIntegerSetting(L"LogEntries", L"200"); // 512 PhpAddStringSetting(L"LogListViewColumns", L""); PhpAddIntegerPairSetting(L"LogWindowPosition", L"300,300"); diff --git a/phlib/native.c b/phlib/native.c index 435c8426825c..aeb0594d69a0 100644 --- a/phlib/native.c +++ b/phlib/native.c @@ -6299,19 +6299,29 @@ static BOOLEAN PhpDeleteDirectoryCallback( if (NT_SUCCESS(PhCreateFileWin32( &directoryHandle, PhGetString(fullName), - FILE_GENERIC_READ, + FILE_GENERIC_READ | DELETE, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_DELETE, FILE_OPEN, FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT ))) { + IO_STATUS_BLOCK isb; + FILE_DISPOSITION_INFORMATION fileInfo; + PhEnumDirectoryFile(directoryHandle, NULL, PhpDeleteDirectoryCallback, fullName); - NtClose(directoryHandle); + // Delete the directory. + fileInfo.DeleteFile = TRUE; + NtSetInformationFile( + directoryHandle, + &isb, + &fileInfo, + sizeof(FILE_DISPOSITION_INFORMATION), + FileDispositionInformation + ); - // Delete the directory. - RemoveDirectory(PhGetString(fullName)); + NtClose(directoryHandle); } } else @@ -6350,6 +6360,7 @@ static BOOLEAN PhpDeleteDirectoryCallback( } } + // Delete the file. PhDeleteFileWin32(PhGetString(fullName)); } @@ -6373,7 +6384,7 @@ NTSTATUS PhDeleteDirectory( &directoryHandle, PhGetString(DirectoryPath), FILE_GENERIC_READ | DELETE, - 0, + FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_DELETE, FILE_OPEN, FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT diff --git a/phlib/util.c b/phlib/util.c index 5e20010adf6a..8f17f76f2309 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -36,6 +36,7 @@ #include #include #include +#include #include "md5.h" #include "sha.h" @@ -5049,7 +5050,15 @@ PPH_STRING PhGetCacheDirectory( VOID ) { - return PhGetKnownLocation(CSIDL_LOCAL_APPDATA, L"\\Process Hacker\\Cache"); + PPH_STRING executeString; + + // Get the default cache directory. + executeString = PhGetStringSetting(L"LocalCachePath"); + + // Expand environment strings. + PhMoveReference(&executeString, PhExpandEnvironmentStrings(&executeString->sr)); + + return executeString; } VOID PhClearCacheDirectory( diff --git a/plugins/ExtraPlugins/cloud.c b/plugins/ExtraPlugins/cloud.c index d2afea082a3f..07a94476fcc9 100644 --- a/plugins/ExtraPlugins/cloud.c +++ b/plugins/ExtraPlugins/cloud.c @@ -313,7 +313,7 @@ NTSTATUS SetupExtractBuild( extractPath = PhConcatStringRef3(&directory->sr, &pluginsDirectory, &fileName->sr); fullSetupPath = PhGetFullPath(PhGetStringOrEmpty(extractPath), &indexOfFileName); - PhCreateDirectory(PhGetString(fullSetupPath)); + PhCreateDirectory(fullSetupPath); PhDereferenceObject(fullSetupPath); PhDereferenceObject(extractPath); @@ -340,7 +340,7 @@ NTSTATUS SetupExtractBuild( { if (directoryPath = PhSubstring(fullSetupPath, 0, indexOfFileName)) { - PhCreateDirectory(PhGetString(directoryPath)); + PhCreateDirectory(directoryPath); PhDereferenceObject(directoryPath); } diff --git a/tools/CustomSetupTool/CustomSetupTool/download.c b/tools/CustomSetupTool/CustomSetupTool/download.c index eea47d368e65..3355a0fc99dc 100644 --- a/tools/CustomSetupTool/CustomSetupTool/download.c +++ b/tools/CustomSetupTool/CustomSetupTool/download.c @@ -415,7 +415,7 @@ BOOLEAN UpdateDownloadUpdateData( PhGetString(Context->FilePath), FILE_GENERIC_READ | FILE_GENERIC_WRITE, FILE_ATTRIBUTE_NOT_CONTENT_INDEXED | FILE_ATTRIBUTE_TEMPORARY, - FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_OVERWRITE_IF, FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT ))) diff --git a/tools/CustomSetupTool/CustomSetupTool/include/setup.h b/tools/CustomSetupTool/CustomSetupTool/include/setup.h index fa8478a5403f..e63de392ceca 100644 --- a/tools/CustomSetupTool/CustomSetupTool/include/setup.h +++ b/tools/CustomSetupTool/CustomSetupTool/include/setup.h @@ -64,8 +64,6 @@ #define WM_UPDATE_SETUP (WM_APP + 2) #define WM_END_SETUP (WM_APP + 3) -extern HANDLE MutantHandle; - typedef enum _SETUP_COMMAND_TYPE { SETUP_COMMAND_INSTALL, From 6f9261e3b34597d320ab5d9964921da5d4b6a40e Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 11 Aug 2017 08:58:34 +1000 Subject: [PATCH 0372/2058] Remove CommonUtil plugin, Remove LocalCachePath setting (fix linker issue), Fix build --- ProcessHacker/ProcessHacker.def | 1 + ProcessHacker/plugin.c | 18 ++- ProcessHacker/settings.c | 1 - phlib/include/phutil.h | 7 + phlib/util.c | 28 ++-- plugins/CommonUtil/CHANGELOG.txt | 3 - plugins/CommonUtil/CommonUtil.vcxproj | 87 ------------ plugins/CommonUtil/CommonUtil.vcxproj.filters | 42 ------ plugins/CommonUtil/main.c | 54 -------- plugins/CommonUtil/main.h | 126 ------------------ plugins/CommonUtil/resource.h | 19 --- plugins/CommonUtil/resource.rc | 119 ----------------- .../CommonUtil/resources/active_search.bmp | Bin 1494 -> 0 bytes .../CommonUtil/resources/active_search.png | Bin 569 -> 0 bytes .../CommonUtil/resources/inactive_search.bmp | Bin 1494 -> 0 bytes .../CommonUtil/resources/inactive_search.png | Bin 755 -> 0 bytes plugins/Plugins.sln | 12 +- plugins/include/commonutil.h | 9 -- .../CustomSetupTool/CustomSetupTool/extract.c | 2 +- 19 files changed, 45 insertions(+), 483 deletions(-) delete mode 100644 plugins/CommonUtil/CHANGELOG.txt delete mode 100644 plugins/CommonUtil/CommonUtil.vcxproj delete mode 100644 plugins/CommonUtil/CommonUtil.vcxproj.filters delete mode 100644 plugins/CommonUtil/main.c delete mode 100644 plugins/CommonUtil/main.h delete mode 100644 plugins/CommonUtil/resource.h delete mode 100644 plugins/CommonUtil/resource.rc delete mode 100644 plugins/CommonUtil/resources/active_search.bmp delete mode 100644 plugins/CommonUtil/resources/active_search.png delete mode 100644 plugins/CommonUtil/resources/inactive_search.bmp delete mode 100644 plugins/CommonUtil/resources/inactive_search.png diff --git a/ProcessHacker/ProcessHacker.def b/ProcessHacker/ProcessHacker.def index fcec0b535446..d9ec3b6a127b 100644 --- a/ProcessHacker/ProcessHacker.def +++ b/ProcessHacker/ProcessHacker.def @@ -346,6 +346,7 @@ EXPORTS PhGenerateRandomAlphaString PhGetApplicationDirectory PhGetApplicationFileName + PhGetBaseDirectory PhGetBaseName PhGetDllFileName PhGetFileDialogFileName diff --git a/ProcessHacker/plugin.c b/ProcessHacker/plugin.c index 495b5eeab934..c468ffa93131 100644 --- a/ProcessHacker/plugin.c +++ b/ProcessHacker/plugin.c @@ -206,16 +206,30 @@ static BOOLEAN EnumPluginsDirectoryCallback( if (PhEndsWithStringRef2(&baseName, L".dll", TRUE)) { - if (!PhIsPluginDisabled(&baseName)) + // Plugin blacklist + if (PhEndsWithStringRef2(&baseName, L"CommonUtil.dll", TRUE)) { fileName = PhCreateStringEx(NULL, PluginsDirectory->Length + Information->FileNameLength); memcpy(fileName->Buffer, PluginsDirectory->Buffer, PluginsDirectory->Length); memcpy(&fileName->Buffer[PluginsDirectory->Length / 2], Information->FileName, Information->FileNameLength); - PhLoadPlugin(fileName); + PhDeleteFileWin32(fileName->Buffer); PhDereferenceObject(fileName); } + else + { + if (!PhIsPluginDisabled(&baseName)) + { + fileName = PhCreateStringEx(NULL, PluginsDirectory->Length + Information->FileNameLength); + memcpy(fileName->Buffer, PluginsDirectory->Buffer, PluginsDirectory->Length); + memcpy(&fileName->Buffer[PluginsDirectory->Length / 2], Information->FileName, Information->FileNameLength); + + PhLoadPlugin(fileName); + + PhDereferenceObject(fileName); + } + } } return TRUE; diff --git a/ProcessHacker/settings.c b/ProcessHacker/settings.c index 9845dd49b0e9..28994dd78cbe 100644 --- a/ProcessHacker/settings.c +++ b/ProcessHacker/settings.c @@ -80,7 +80,6 @@ VOID PhAddDefaultSettings( PhpAddIntegerSetting(L"IconTogglesVisibility", L"1"); PhpAddStringSetting(L"JobListViewColumns", L""); PhpAddIntegerSetting(L"KphUnloadOnShutdown", L"0"); - PhpAddStringSetting(L"LocalCachePath", L"%LocalAppData%\\Process Hacker\\Cache"); PhpAddIntegerSetting(L"LogEntries", L"200"); // 512 PhpAddStringSetting(L"LogListViewColumns", L""); PhpAddIntegerPairSetting(L"LogWindowPosition", L"300,300"); diff --git a/phlib/include/phutil.h b/phlib/include/phutil.h index ce202be0128b..9eddea371402 100644 --- a/phlib/include/phutil.h +++ b/phlib/include/phutil.h @@ -576,6 +576,13 @@ PhGetBaseName( _In_ PPH_STRING FileName ); +PHLIBAPI +PPH_STRING +NTAPI +PhGetBaseDirectory( + _In_ PPH_STRING FileName + ); + PHLIBAPI PPH_STRING NTAPI diff --git a/phlib/util.c b/phlib/util.c index 8f17f76f2309..62abe668d064 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -1981,6 +1981,24 @@ PPH_STRING PhGetBaseName( return PhCreateString2(&baseNamePart); } +/** + * Gets the parent directory from a file name. + * + * \param FileName The file name. + */ +PPH_STRING PhGetBaseDirectory( + _In_ PPH_STRING FileName + ) +{ + PH_STRINGREF pathPart; + PH_STRINGREF baseNamePart; + + if (!PhSplitStringRefAtLastChar(&FileName->sr, '\\', &pathPart, &baseNamePart)) + return NULL; + + return PhCreateString2(&pathPart); +} + /** * Retrieves the system directory path. */ @@ -5050,15 +5068,7 @@ PPH_STRING PhGetCacheDirectory( VOID ) { - PPH_STRING executeString; - - // Get the default cache directory. - executeString = PhGetStringSetting(L"LocalCachePath"); - - // Expand environment strings. - PhMoveReference(&executeString, PhExpandEnvironmentStrings(&executeString->sr)); - - return executeString; + return PhGetKnownLocation(CSIDL_LOCAL_APPDATA, L"\\Process Hacker\\Cache"); } VOID PhClearCacheDirectory( diff --git a/plugins/CommonUtil/CHANGELOG.txt b/plugins/CommonUtil/CHANGELOG.txt deleted file mode 100644 index 9ccf3bfe5d94..000000000000 --- a/plugins/CommonUtil/CHANGELOG.txt +++ /dev/null @@ -1,3 +0,0 @@ - -1.0 - * Initial release \ No newline at end of file diff --git a/plugins/CommonUtil/CommonUtil.vcxproj b/plugins/CommonUtil/CommonUtil.vcxproj deleted file mode 100644 index aa57362d61bc..000000000000 --- a/plugins/CommonUtil/CommonUtil.vcxproj +++ /dev/null @@ -1,87 +0,0 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {C74D269B-3FCC-4C3E-93C7-1B4A94E7BBEE} - CommonUtil - Win32Proj - CommonUtil - 10.0.15063.0 - - - - DynamicLibrary - Unicode - true - v141 - - - DynamicLibrary - Unicode - v141 - - - DynamicLibrary - Unicode - true - v141 - - - DynamicLibrary - Unicode - v141 - - - - - - - - - windowscodecs.lib;uxtheme.lib;%(AdditionalDependencies) - - - - - windowscodecs.lib;uxtheme.lib;%(AdditionalDependencies) - - - - - windowscodecs.lib;uxtheme.lib;%(AdditionalDependencies) - - - - - windowscodecs.lib;uxtheme.lib;%(AdditionalDependencies) - - - - - - - - - - - - - - \ No newline at end of file diff --git a/plugins/CommonUtil/CommonUtil.vcxproj.filters b/plugins/CommonUtil/CommonUtil.vcxproj.filters deleted file mode 100644 index 6df6a7997e96..000000000000 --- a/plugins/CommonUtil/CommonUtil.vcxproj.filters +++ /dev/null @@ -1,42 +0,0 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {664acb18-b541-4abb-8e7f-668c4de1cdfe} - - - {8483492d-4b7d-408b-95ac-d47900bfb245} - - - {31d3c520-6bf5-4720-8800-1f420d2e41e8} - - - {3ee330a7-42a6-4544-8739-f7066d4e4d82} - - - {42e6e53a-30a0-4c7f-8c1a-b98aac45b62d} - - - - - Source Files - - - - - Header Files - - - Header Files - - - - - Resource Files - - - \ No newline at end of file diff --git a/plugins/CommonUtil/main.c b/plugins/CommonUtil/main.c deleted file mode 100644 index c5e5c664c546..000000000000 --- a/plugins/CommonUtil/main.c +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Process Hacker Plugins - - * CommonUtil Plugin - * - * Copyright (C) 2016 dmex - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - * - */ - -#include "main.h" - -PPH_PLUGIN PluginInstance; - -LOGICAL DllMain( - _In_ HINSTANCE Instance, - _In_ ULONG Reason, - _Reserved_ PVOID Reserved - ) -{ - switch (Reason) - { - case DLL_PROCESS_ATTACH: - { - PPH_PLUGIN_INFORMATION info; - - PluginInstance = PhRegisterPlugin(PLUGIN_NAME, Instance, &info); - - if (!PluginInstance) - return FALSE; - - info->DisplayName = L"Common Plugin Extensions"; - info->Author = L"dmex"; - info->Description = L"Common Plugin Extensions"; - info->HasOptions = FALSE; - } - break; - } - - return TRUE; -} diff --git a/plugins/CommonUtil/main.h b/plugins/CommonUtil/main.h deleted file mode 100644 index 22604b66963c..000000000000 --- a/plugins/CommonUtil/main.h +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Process Hacker Plugins - - * CommonUtil Plugin - * - * Copyright (C) 2016 dmex - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - * - */ - -#ifndef _WCT_H_ -#define _WCT_H_ - -#define CINTERFACE -#define COBJMACROS -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "resource.h" -#include "CommonUtil.h" - -#define PLUGIN_NAME L"ProcessHacker.CommonUtil" - -extern PPH_PLUGIN PluginInstance; - -HICON BitmapToIcon( - _In_ HBITMAP BitmapHandle, - _In_ INT Width, - _In_ INT Height - ); - -PVOID UtilCreateJsonArray( - VOID - ); - -PVOID UtilCreateJsonParser( - _In_ PSTR JsonString - ); - -VOID UtilCleanupJsonParser( - _In_ PVOID Object - ); - -PSTR UtilGetJsonValueAsString( - _In_ PVOID Object, - _In_ PSTR Key - ); - -INT64 UtilGetJsonValueAsUlong( - _In_ PVOID Object, - _In_ PSTR Key - ); - -VOID UtilAddJsonArray( - _In_ PVOID jsonArray, - _In_ PVOID jsonEntry - ); - -PVOID UtilCreateJsonObject( - VOID - ); - -PVOID UtilGetJsonObject( - _In_ PVOID Object, - _In_ PSTR Key - ); - -INT UtilGetJsonObjectLength( - _In_ PVOID Object - ); - -BOOL UtilGetJsonObjectBool( - _In_ PVOID Object, - _In_ PSTR Key - ); - -VOID UtilJsonAddObject( - _In_ PVOID Object, - _In_ PSTR Key, - _In_ PSTR Value - ); - -PSTR UtilGetJsonArrayString( - _In_ PVOID Object - ); - -INT64 UtilGetJsonArrayUlong( - _In_ PVOID Object, - _In_ INT Index - ); - -INT UtilGetArrayLength( - _In_ PVOID Object - ); - -PVOID UtilGetObjectArrayIndex( - _In_ PVOID Object, - _In_ INT Index - ); - -PPH_LIST UtilGetObjectArrayList( - _In_ PVOID Object - ); - -#endif \ No newline at end of file diff --git a/plugins/CommonUtil/resource.h b/plugins/CommonUtil/resource.h deleted file mode 100644 index 72caa7b05f55..000000000000 --- a/plugins/CommonUtil/resource.h +++ /dev/null @@ -1,19 +0,0 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by resource.rc -// -#define IDB_SEARCH_ACTIVE_BMP 101 -#define IDB_SEARCH_ACTIVE 102 -#define IDB_SEARCH_INACTIVE_BMP 103 -#define IDB_SEARCH_INACTIVE 104 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 105 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1001 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif diff --git a/plugins/CommonUtil/resource.rc b/plugins/CommonUtil/resource.rc deleted file mode 100644 index fb7b45ceabac..000000000000 --- a/plugins/CommonUtil/resource.rc +++ /dev/null @@ -1,119 +0,0 @@ -// Microsoft Visual C++ generated resource script. -// -#include "resource.h" - -#define APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// -#include "winres.h" - -///////////////////////////////////////////////////////////////////////////// -#undef APSTUDIO_READONLY_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -// English (Australia) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENA) -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_AUS - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -1 TEXTINCLUDE -BEGIN - "resource.h\0" -END - -2 TEXTINCLUDE -BEGIN - "#include ""winres.h""\r\n" - "\0" -END - -3 TEXTINCLUDE -BEGIN - "\r\n" - "\0" -END - -#endif // APSTUDIO_INVOKED - - -///////////////////////////////////////////////////////////////////////////// -// -// Version -// - -VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,0,0,0 - PRODUCTVERSION 1,0,0,0 - FILEFLAGSMASK 0x3fL -#ifdef _DEBUG - FILEFLAGS 0x1L -#else - FILEFLAGS 0x0L -#endif - FILEOS 0x40004L - FILETYPE 0x2L - FILESUBTYPE 0x0L -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "0c0904b0" - BEGIN - VALUE "CompanyName", "dmex" - VALUE "FileDescription", "Common plugin for Process Hacker" - VALUE "FileVersion", "1.0" - VALUE "InternalName", "ProcessHacker.CommonUtil" - VALUE "LegalCopyright", "Licensed under the GNU GPL, v3." - VALUE "OriginalFilename", "CommonUtil.dll" - VALUE "ProductName", "Common plugin for Process Hacker" - VALUE "ProductVersion", "1.0" - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0xc09, 1200 - END -END - - -///////////////////////////////////////////////////////////////////////////// -// -// Bitmap -// - -IDB_SEARCH_ACTIVE_BMP BITMAP "resources\\active_search.bmp" - -IDB_SEARCH_INACTIVE_BMP BITMAP "resources\\inactive_search.bmp" - - -///////////////////////////////////////////////////////////////////////////// -// -// PNG -// - -IDB_SEARCH_ACTIVE PNG "resources\\active_search.png" - -IDB_SEARCH_INACTIVE PNG "resources\\inactive_search.png" - -#endif // English (Australia) resources -///////////////////////////////////////////////////////////////////////////// - - - -#ifndef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// - - -///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED - diff --git a/plugins/CommonUtil/resources/active_search.bmp b/plugins/CommonUtil/resources/active_search.bmp deleted file mode 100644 index 61b13de9a1152694de72dd81c01c47282773298e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1494 zcmZ?ry~fG_24+A~1Bk_eSOka}8650^YlUPk4#vGuUW6N6R zWNHFQJcaSx|X%2hHw&(QFzR`wykGxlOd1cH4UFR%aZTy0vQ4UK=!p| e$uJ%|jmI2xrFi+H=HLw;0_g|8USwG+hBE*$K{!VM diff --git a/plugins/CommonUtil/resources/active_search.png b/plugins/CommonUtil/resources/active_search.png deleted file mode 100644 index 1cf29576b0b50ed5ee88c1ea8565fe2e9adb9b69..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 569 zcmV-90>=G`P)sM}kty8!R#X_B;6=p#3k05!yiVY9d zlP4*H^pRy55Oc`+@ds70n9+mE9;(NrCYe{xn9wV|9VBsU+d(|PXf{(L44hUrH>@-V-11oc);or!AQP^ zGA=1rIynoT>*g-{55qdy^B+mtM4?zjp=AgQmBSj+v@_=Xhhe3lstAxc%pz)8#;6wA zW~r4l^}SZ|wEr*+mw^5uN{4!`dE+8h9B2g+;~9Laf!o+nq2=@QC~4{5 zzNMIgKr``}1C-rcX?bp5HnP>n`l5h>$RZFnesj((%HG>#cy3wt`|HP^U*3CeUNVq- zZ5@_$h2I>YUDuXnAL}xNqidV67y?vA&>V=f-`}3|{{B)38!JhqIau`~3l2ha0LuUq A!~g&Q diff --git a/plugins/CommonUtil/resources/inactive_search.png b/plugins/CommonUtil/resources/inactive_search.png deleted file mode 100644 index 29eaa91305b3de1ce3854f19d86780a552bff734..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 755 zcmV;^k2Oj%`vu0L~h9Ndt{Z?B0N*TK5C5_$jUJj2-f3Mf; z=Q4%>h(lx3%*O9D(}M#pG|-AZmB~Y^5Kn3OGXm_qV;y8!p2Ycr{A~&Vh&eaG$uG|C z6Av0_h0HQDGp8TB=MgF`eoUj*zR2Kp69(V&kV6d|aG`-#)NJOFTW(>}f=4uY!z&#( zy!b0FYT$qi4YZzi z!U4p{@mX8WMy*7RX54w@=Gkk?VfutyFI>F1**tDmn1AarCNdTRhz$lqT^w#vqiIjf z++4ek*{XCNwS|Dwx6J)v#I?d`27J0X0K~|N-h&;@?7SR0m@dn1EiEQs_o;`$Fyb>) z{!a}>%}S)Dt6pr_b2g-Y=aI^?%}2xWn%Jm@kdeTRQJW3s_yq*>%`QLV|Bc0r1Qr_O lJMbXX`SgwQ{nsmReE`jH|7l`4W6l5o002ovPDHLkV1naFZkYf8 diff --git a/plugins/Plugins.sln b/plugins/Plugins.sln index 15c2c8271d2b..87cbceb668f5 100644 --- a/plugins/Plugins.sln +++ b/plugins/Plugins.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 -VisualStudioVersion = 15.0.26403.7 +VisualStudioVersion = 15.0.26430.16 MinimumVisualStudioVersion = 15.0.26228.4 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{53C3AE07-D96F-4F5C-B407-4195084472CF}" ProjectSection(SolutionItems) = preProject @@ -32,8 +32,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UserNotes", "UserNotes\User EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "HardwareDevices", "HardwareDevices\HardwareDevices.vcxproj", "{5F0D72C4-8319-4B61-9E13-6084B680EB90}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CommonUtil", "CommonUtil\CommonUtil.vcxproj", "{C74D269B-3FCC-4C3E-93C7-1B4A94E7BBEE}" -EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ExtraPlugins", "ExtraPlugins\ExtraPlugins.vcxproj", "{96549A3E-D1BD-470E-A5B3-A64803C4DEF5}" EndProject Global @@ -132,14 +130,6 @@ Global {5F0D72C4-8319-4B61-9E13-6084B680EB90}.Release|Win32.Build.0 = Release|Win32 {5F0D72C4-8319-4B61-9E13-6084B680EB90}.Release|x64.ActiveCfg = Release|x64 {5F0D72C4-8319-4B61-9E13-6084B680EB90}.Release|x64.Build.0 = Release|x64 - {C74D269B-3FCC-4C3E-93C7-1B4A94E7BBEE}.Debug|Win32.ActiveCfg = Debug|Win32 - {C74D269B-3FCC-4C3E-93C7-1B4A94E7BBEE}.Debug|Win32.Build.0 = Debug|Win32 - {C74D269B-3FCC-4C3E-93C7-1B4A94E7BBEE}.Debug|x64.ActiveCfg = Debug|x64 - {C74D269B-3FCC-4C3E-93C7-1B4A94E7BBEE}.Debug|x64.Build.0 = Debug|x64 - {C74D269B-3FCC-4C3E-93C7-1B4A94E7BBEE}.Release|Win32.ActiveCfg = Release|Win32 - {C74D269B-3FCC-4C3E-93C7-1B4A94E7BBEE}.Release|Win32.Build.0 = Release|Win32 - {C74D269B-3FCC-4C3E-93C7-1B4A94E7BBEE}.Release|x64.ActiveCfg = Release|x64 - {C74D269B-3FCC-4C3E-93C7-1B4A94E7BBEE}.Release|x64.Build.0 = Release|x64 {96549A3E-D1BD-470E-A5B3-A64803C4DEF5}.Debug|Win32.ActiveCfg = Debug|Win32 {96549A3E-D1BD-470E-A5B3-A64803C4DEF5}.Debug|Win32.Build.0 = Debug|Win32 {96549A3E-D1BD-470E-A5B3-A64803C4DEF5}.Debug|x64.ActiveCfg = Debug|x64 diff --git a/plugins/include/commonutil.h b/plugins/include/commonutil.h index 70040158bdf9..57d730baee46 100644 --- a/plugins/include/commonutil.h +++ b/plugins/include/commonutil.h @@ -24,15 +24,6 @@ #ifndef _COMMONUTIL_H #define _COMMONUTIL_H -#define COMMONUTIL_PLUGIN_NAME L"ProcessHacker.CommonUtil" -#define COMMONUTIL_INTERFACE_VERSION 1 - -typedef struct _COMMONUTIL_INTERFACE -{ - ULONG Version; -} COMMONUTIL_INTERFACE, *P_COMMONUTIL_INTERFACE; - - FORCEINLINE HICON CommonBitmapToIcon( diff --git a/tools/CustomSetupTool/CustomSetupTool/extract.c b/tools/CustomSetupTool/CustomSetupTool/extract.c index b6da5136be6d..14ebc3ff7ddd 100644 --- a/tools/CustomSetupTool/CustomSetupTool/extract.c +++ b/tools/CustomSetupTool/CustomSetupTool/extract.c @@ -177,7 +177,7 @@ BOOLEAN SetupExtractBuild( if (directoryPath = PhSubstring(fullSetupPath, 0, indexOfFileName)) { - if (!NT_SUCCESS(PhCreateDirectory(PhGetString(directoryPath)))) + if (!NT_SUCCESS(PhCreateDirectory(directoryPath))) { PhDereferenceObject(directoryPath); PhDereferenceObject(fullSetupPath); From eccf4de2845a03acb8ca2e2334e7091d404d4951 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 11 Aug 2017 09:25:49 +1000 Subject: [PATCH 0373/2058] Fix PhDeleteDirectory access --- phlib/native.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phlib/native.c b/phlib/native.c index aeb0594d69a0..3af7fe0f68ba 100644 --- a/phlib/native.c +++ b/phlib/native.c @@ -6333,7 +6333,7 @@ static BOOLEAN PhpDeleteDirectoryCallback( if (NT_SUCCESS(PhCreateFileWin32( &fileHandle, PhGetString(fullName), - FILE_GENERIC_WRITE, + FILE_GENERIC_READ | FILE_WRITE_ATTRIBUTES, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_WRITE, FILE_OPEN, From 6776bd6df18394a340e9d4452ffb562abb861da1 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 11 Aug 2017 10:55:40 +1000 Subject: [PATCH 0374/2058] Fix typos, Update flags, Tidy up TaskDialog code --- ProcessHacker/main.c | 2 +- ProcessHacker/mainwnd.c | 2 +- phlib/util.c | 11 +-- plugins/ExtraPlugins/plugin.c | 4 - plugins/ExtraPlugins/setup/uninstall.c | 2 +- plugins/ExtraPlugins/setup/updater.c | 129 +++---------------------- plugins/NetworkTools/nettools.h | 10 +- plugins/NetworkTools/pages.c | 13 +-- plugins/NetworkTools/update.c | 54 ++--------- plugins/Updater/page5.c | 16 ++- plugins/Updater/updater.c | 66 ++++--------- plugins/Updater/updater.h | 8 +- 12 files changed, 68 insertions(+), 249 deletions(-) diff --git a/ProcessHacker/main.c b/ProcessHacker/main.c index 498260e9c118..ca0de0fe219f 100644 --- a/ProcessHacker/main.c +++ b/ProcessHacker/main.c @@ -178,7 +178,7 @@ INT WINAPI wWinMain( if (!NT_SUCCESS(status) && !PhStartupParameters.Silent) { - PhShowStatus(NULL, L"Unable to execute the command", status, 0); + PhShowStatus(NULL, L"Unable to execute the command.", status, 0); } RtlExitUserProcess(status); diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index 184825f5cf2a..4dbb73e92430 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -1867,7 +1867,7 @@ BOOLEAN PhMwpOnNotify( } else { - PhShowStatus(PhMainWndHandle, L"Unable to execute the program", status, 0); + PhShowStatus(PhMainWndHandle, L"Unable to execute the program.", status, 0); *Result = RF_RETRY; } diff --git a/phlib/util.c b/phlib/util.c index 62abe668d064..b72bef57db02 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -3262,13 +3262,13 @@ VOID PhShellExecute( info.lpFile = FileName; info.lpParameters = Parameters; + info.fMask = SEE_MASK_FLAG_NO_UI; info.nShow = SW_SHOW; info.hwnd = hWnd; if (!ShellExecuteEx(&info)) { - // It already displays error messages by itself. - //PhShowStatus(hWnd, L"Unable to execute the program", 0, GetLastError()); + PhShowStatus(hWnd, L"Unable to execute the program.", 0, GetLastError()); } } @@ -3301,7 +3301,7 @@ BOOLEAN PhShellExecuteEx( info.lpFile = FileName; info.lpParameters = Parameters; - info.fMask = SEE_MASK_NOCLOSEPROCESS; + info.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_NO_UI; info.nShow = ShowWindowType; info.hwnd = hWnd; @@ -3388,14 +3388,13 @@ VOID PhShellProperties( info.lpFile = FileName; info.nShow = SW_SHOW; - info.fMask = SEE_MASK_INVOKEIDLIST; + info.fMask = SEE_MASK_INVOKEIDLIST | SEE_MASK_FLAG_NO_UI; info.lpVerb = L"properties"; info.hwnd = hWnd; if (!ShellExecuteEx(&info)) { - // It already displays error messages by itself. - //PhShowStatus(hWnd, L"Unable to execute the program", 0, GetLastError()); + PhShowStatus(hWnd, L"Unable to execute the program.", 0, GetLastError()); } } diff --git a/plugins/ExtraPlugins/plugin.c b/plugins/ExtraPlugins/plugin.c index 1bfd3d10c733..d1298c84297f 100644 --- a/plugins/ExtraPlugins/plugin.c +++ b/plugins/ExtraPlugins/plugin.c @@ -308,10 +308,6 @@ VOID EnumerateLoadedPlugins( pluginInstance = CONTAINING_RECORD(links, PHAPP_PLUGIN, Links); - // HACK: Hide the CommonUtil plugin since it's a required dependency for multiple plugins. - if (PhEqualStringRef2(&pluginInstance->Name, L"ProcessHacker.CommonUtil", TRUE)) - continue; - PhInitializeStringRefLongHint(&pluginBaseName, PhGetPluginBaseName(pluginInstance)); if (PhIsPluginDisabled(&pluginBaseName)) diff --git a/plugins/ExtraPlugins/setup/uninstall.c b/plugins/ExtraPlugins/setup/uninstall.c index e7f92310551d..3f6069bae2dc 100644 --- a/plugins/ExtraPlugins/setup/uninstall.c +++ b/plugins/ExtraPlugins/setup/uninstall.c @@ -47,7 +47,7 @@ HRESULT CALLBACK TaskDialogUninstallCallbackProc( PhDereferenceObject(baseNameString); PhDereferenceObject(fileNameString); - PostMessage(context->DialogHandle, PH_UPDATENEWER, 0, 0); + ShowUninstallRestartDialog(context); return S_FALSE; } } diff --git a/plugins/ExtraPlugins/setup/updater.c b/plugins/ExtraPlugins/setup/updater.c index 8a1ce61eb1d3..e6abc1fe748c 100644 --- a/plugins/ExtraPlugins/setup/updater.c +++ b/plugins/ExtraPlugins/setup/updater.c @@ -246,7 +246,7 @@ NTSTATUS UpdateDownloadThread( BOOLEAN downloadSuccess = FALSE; BOOLEAN hashSuccess = FALSE; BOOLEAN signatureSuccess = FALSE; - LONG updateResult = PH_UPDATEISERRORED; + BOOLEAN updateSuccess = FALSE; HANDLE tempFileHandle = NULL; HINTERNET httpSessionHandle = NULL; HINTERNET httpConnectionHandle = NULL; @@ -526,7 +526,7 @@ NTSTATUS UpdateDownloadThread( { if (NT_SUCCESS(SetupExtractBuild(context))) { - updateResult = PH_UPDATESUCCESS; + updateSuccess = TRUE; } } @@ -536,112 +536,16 @@ NTSTATUS UpdateDownloadThread( PhDereferenceObject(context->SetupFilePath); } - PostMessage(context->DialogHandle, updateResult, 0, 0); - - return STATUS_SUCCESS; -} - -LRESULT CALLBACK TaskDialogSubclassProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam, - _In_ UINT_PTR uIdSubclass, - _In_ ULONG_PTR dwRefData - ) -{ - PPH_UPDATER_CONTEXT context = (PPH_UPDATER_CONTEXT)dwRefData; - - switch (uMsg) + if (updateSuccess) { - case WM_NCDESTROY: - { - RemoveWindowSubclass(hwndDlg, TaskDialogSubclassProc, uIdSubclass); - } - break; - case WM_APP + 1: - { - if (IsIconic(hwndDlg)) - ShowWindow(hwndDlg, SW_RESTORE); - else - ShowWindow(hwndDlg, SW_SHOW); - - SetForegroundWindow(hwndDlg); - } - break; - case PH_UPDATEAVAILABLE: - { - ShowAvailableDialog(context); - } - break; - case PH_UPDATENEWER: - { - ShowUninstallRestartDialog(context); - } - break; - case PH_UPDATESUCCESS: - { - ShowInstallRestartDialog(context); - } - break; - case PH_UPDATEFAILURE: - { - if ((BOOLEAN)wParam) - ShowUpdateFailedDialog(context, TRUE, FALSE); - else if ((BOOLEAN)lParam) - ShowUpdateFailedDialog(context, FALSE, TRUE); - else - ShowUpdateFailedDialog(context, FALSE, FALSE); - } - break; - case PH_UPDATEISERRORED: - { - ShowUpdateFailedDialog(context, FALSE, FALSE); - } - break; - //case WM_PARENTNOTIFY: - // { - // if (wParam == WM_CREATE) - // { - // // uMsg == 49251 for expand/collapse button click - // HWND hwndEdit = CreateWindowEx( - // WS_EX_CLIENTEDGE, - // L"EDIT", - // NULL, - // WS_CHILD | WS_VISIBLE | WS_VSCROLL | ES_LEFT | ES_MULTILINE | ES_AUTOVSCROLL, - // 5, - // 5, - // 390, - // 85, - // (HWND)lParam, // parent window - // 0, - // NULL, - // NULL - // ); - // - // PhCreateCommonFont(-11, hwndEdit); - // - // // Add text to the window. - // SendMessage(hwndEdit, WM_SETTEXT, 0, (LPARAM)L"TEST"); - // } - // } - // break; - //case WM_NCACTIVATE: - // { - // if (IsWindowVisible(PhMainWndHandle) && !IsMinimized(PhMainWndHandle)) - // { - // if (!context->FixedWindowStyles) - // { - // SetWindowLongPtr(hwndDlg, GWLP_HWNDPARENT, (LONG_PTR)PhMainWndHandle); - // PhSetWindowExStyle(hwndDlg, WS_EX_APPWINDOW, WS_EX_APPWINDOW); - // context->FixedWindowStyles = TRUE; - // } - // } - // } - // break; + ShowInstallRestartDialog(context); + } + else + { + ShowUpdateFailedDialog(context, FALSE, FALSE); } - return DefSubclassProc(hwndDlg, uMsg, wParam, lParam); + return STATUS_SUCCESS; } HRESULT CALLBACK TaskDialogBootstrapCallback( @@ -659,26 +563,19 @@ HRESULT CALLBACK TaskDialogBootstrapCallback( case TDN_CREATED: { context->DialogHandle = hwndDlg; - TaskDialogCreateIcons(context); - SetWindowSubclass(hwndDlg, TaskDialogSubclassProc, 0, (ULONG_PTR)context); + TaskDialogCreateIcons(context); switch (context->Action) { case PLUGIN_ACTION_INSTALL: - { - ShowAvailableDialog(context); - } + ShowAvailableDialog(context); break; case PLUGIN_ACTION_UNINSTALL: - { - ShowPluginUninstallDialog(context); - } + ShowPluginUninstallDialog(context); break; case PLUGIN_ACTION_RESTART: - { - ShowUninstallRestartDialog(context); - } + ShowUninstallRestartDialog(context); break; } } diff --git a/plugins/NetworkTools/nettools.h b/plugins/NetworkTools/nettools.h index 8e46673641d2..48d232f8574b 100644 --- a/plugins/NetworkTools/nettools.h +++ b/plugins/NetworkTools/nettools.h @@ -106,12 +106,6 @@ typedef enum _PH_NETWORK_ACTION #define WM_TRACERT_COUNTRY (WM_APP + NETWORK_ACTION_TRACEROUTE + 1004) #define UPDATE_MENUITEM 1005 -#define PH_UPDATEISERRORED (WM_APP + 501) -#define PH_UPDATEISCURRENT (WM_APP + 503) -#define PH_UPDATENEWER (WM_APP + 504) -#define PH_UPDATESUCCESS (WM_APP + 505) -#define PH_UPDATEFAILURE (WM_APP + 506) -#define WM_SHOWDIALOG (WM_APP + 550) typedef struct _NETWORK_PING_CONTEXT { @@ -305,6 +299,10 @@ VOID ShowInstallRestartDialog( _In_ PPH_UPDATER_CONTEXT Context ); +VOID ShowUpdateFailedDialog( + _In_ PPH_UPDATER_CONTEXT Context + ); + // Copied from mstcpip.h due to PH sdk conflicts #define INADDR_ANY (ULONG)0x00000000 #define INADDR_LOOPBACK 0x7f000001 diff --git a/plugins/NetworkTools/pages.c b/plugins/NetworkTools/pages.c index f2bce861c8ca..b379a9213124 100644 --- a/plugins/NetworkTools/pages.c +++ b/plugins/NetworkTools/pages.c @@ -227,8 +227,7 @@ VOID ShowInstallRestartDialog( } VOID ShowUpdateFailedDialog( - _In_ PPH_UPDATER_CONTEXT Context, - _In_ BOOLEAN HashFailed + _In_ PPH_UPDATER_CONTEXT Context ) { TASKDIALOGCONFIG config; @@ -245,15 +244,7 @@ VOID ShowUpdateFailedDialog( config.pszWindowTitle = L"Network Tools - GeoIP Updater"; config.pszMainInstruction = L"Error downloading GeoIP database."; - - if (HashFailed) - { - config.pszContent = L"Hash check failed. Click Retry to download the database again."; - } - else - { - config.pszContent = L"Click Retry to download the database again."; - } + config.pszContent = L"Click Retry to download the database again."; SendMessage(Context->DialogHandle, TDM_NAVIGATE_PAGE, 0, (LPARAM)&config); } \ No newline at end of file diff --git a/plugins/NetworkTools/update.c b/plugins/NetworkTools/update.c index 8c8692b1b0ef..38924478c8b0 100644 --- a/plugins/NetworkTools/update.c +++ b/plugins/NetworkTools/update.c @@ -608,57 +608,20 @@ NTSTATUS GeoIPUpdateThread( PhDereferenceObject(context->SetupFilePath); } - if (success) + if (context->DialogHandle) { - if (context->DialogHandle) - PostMessage(context->DialogHandle, PH_UPDATESUCCESS, 0, 0); - } - else - { - if (context->DialogHandle) - PostMessage(context->DialogHandle, PH_UPDATEISERRORED, 0, 0); - } - - PhDereferenceObject(context); - return STATUS_SUCCESS; -} - -LRESULT CALLBACK TaskDialogSubclassProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam, - _In_ UINT_PTR uIdSubclass, - _In_ ULONG_PTR dwRefData - ) -{ - PPH_UPDATER_CONTEXT context = (PPH_UPDATER_CONTEXT)dwRefData; - - switch (uMsg) - { - case WM_NCDESTROY: + if (success) { - RemoveWindowSubclass(hwndDlg, TaskDialogSubclassProc, uIdSubclass); - } - break; - case WM_SHOWDIALOG: - { - if (IsMinimized(hwndDlg)) - ShowWindow(hwndDlg, SW_RESTORE); - else - ShowWindow(hwndDlg, SW_SHOW); - - SetForegroundWindow(hwndDlg); + ShowInstallRestartDialog(context); } - break; - case PH_UPDATESUCCESS: + else { - ShowInstallRestartDialog(context); + ShowUpdateFailedDialog(context); } - break; } - return DefSubclassProc(hwndDlg, uMsg, wParam, lParam); + PhDereferenceObject(context); + return STATUS_SUCCESS; } HRESULT CALLBACK TaskDialogBootstrapCallback( @@ -683,9 +646,6 @@ HRESULT CALLBACK TaskDialogBootstrapCallback( // Create the Taskdialog icons TaskDialogCreateIcons(context); - // Subclass the Taskdialog - SetWindowSubclass(hwndDlg, TaskDialogSubclassProc, 0, (ULONG_PTR)context); - ShowCheckForUpdatesDialog(context); } break; diff --git a/plugins/Updater/page5.c b/plugins/Updater/page5.c index 863578027588..aac9d196786f 100644 --- a/plugins/Updater/page5.c +++ b/plugins/Updater/page5.c @@ -70,6 +70,7 @@ HRESULT CALLBACK FinalTaskDialogCallbackProc( info.lpVerb = PhGetOwnTokenAttributes().Elevated ? NULL : L"runas"; info.nShow = SW_SHOW; info.hwnd = hwndDlg; + info.fMask = SEE_MASK_NOASYNC | SEE_MASK_FLAG_NO_UI; ProcessHacker_PrepareForEarlyShutdown(PhMainWndHandle); @@ -79,11 +80,22 @@ HRESULT CALLBACK FinalTaskDialogCallbackProc( } else { + ULONG errorCode = GetLastError(); + // Install failed, cancel the shutdown. ProcessHacker_CancelEarlyShutdown(PhMainWndHandle); - // Set button text for next action - //Button_SetText(GetDlgItem(hwndDlg, IDOK), L"Retry"); + // Show error dialog. + if (errorCode != ERROR_CANCELLED) // Ignore UAC decline. + { + PhShowStatus(hwndDlg, L"Unable to execute the setup.", 0, GetLastError()); + + if (context->StartupCheck) + ShowAvailableDialog(context); + else + ShowCheckForUpdatesDialog(context); + } + return S_FALSE; } } diff --git a/plugins/Updater/updater.c b/plugins/Updater/updater.c index 16790f4ab3ad..97fe59b5207a 100644 --- a/plugins/Updater/updater.c +++ b/plugins/Updater/updater.c @@ -516,6 +516,13 @@ NTSTATUS UpdateCheckSilentThread( if (!LastUpdateCheckExpired()) goto CleanupExit; #endif + + Sleep(5 * 1000); + + // Clear the application cache directory. + PhClearCacheDirectory(); + + // Query latest update information from the server. if (!QueryUpdateData(context)) goto CleanupExit; @@ -573,7 +580,7 @@ NTSTATUS UpdateCheckThread( if (!context->HaveData) { - PostMessage(context->DialogHandle, PH_UPDATEISERRORED, 0, 0); + ShowUpdateFailedDialog(context, FALSE, FALSE); PhDereferenceObject(context); return STATUS_SUCCESS; @@ -595,17 +602,17 @@ NTSTATUS UpdateCheckThread( if (currentVersion == latestVersion) { // User is running the latest version - PostMessage(context->DialogHandle, PH_UPDATEISCURRENT, 0, 0); + ShowLatestVersionDialog(context); } else if (currentVersion > latestVersion) { // User is running a newer version - PostMessage(context->DialogHandle, PH_UPDATENEWER, 0, 0); + ShowNewerVersionDialog(context); } else { // User is running an older version - PostMessage(context->DialogHandle, PH_UPDATEAVAILABLE, 0, 0); + ShowAvailableDialog(context); } PhDereferenceObject(context); @@ -944,15 +951,20 @@ NTSTATUS UpdateDownloadThread( { if (downloadSuccess && hashSuccess && signatureSuccess) { - PostMessage(context->DialogHandle, PH_UPDATESUCCESS, 0, 0); + ShowUpdateInstallDialog(context); } else if (downloadSuccess) { - PostMessage(context->DialogHandle, PH_UPDATEFAILURE, signatureSuccess, hashSuccess); + if (signatureSuccess) + ShowUpdateFailedDialog(context, TRUE, FALSE); + else if (hashSuccess) + ShowUpdateFailedDialog(context, FALSE, TRUE); + else + ShowUpdateFailedDialog(context, FALSE, FALSE); } else { - PostMessage(context->DialogHandle, PH_UPDATEISERRORED, 0, 0); + ShowUpdateFailedDialog(context, FALSE, FALSE); } } @@ -988,41 +1000,6 @@ LRESULT CALLBACK TaskDialogSubclassProc( RemoveWindowSubclass(hwndDlg, TaskDialogSubclassProc, uIdSubclass); } break; - case PH_UPDATEAVAILABLE: - { - ShowAvailableDialog(context); - } - break; - case PH_UPDATEISCURRENT: - { - ShowLatestVersionDialog(context); - } - break; - case PH_UPDATENEWER: - { - ShowNewerVersionDialog(context); - } - break; - case PH_UPDATESUCCESS: - { - ShowUpdateInstallDialog(context); - } - break; - case PH_UPDATEFAILURE: - { - if ((BOOLEAN)wParam) - ShowUpdateFailedDialog(context, TRUE, FALSE); - else if ((BOOLEAN)lParam) - ShowUpdateFailedDialog(context, FALSE, TRUE); - else - ShowUpdateFailedDialog(context, FALSE, FALSE); - } - break; - case PH_UPDATEISERRORED: - { - ShowUpdateFailedDialog(context, FALSE, FALSE); - } - break; //case WM_PARENTNOTIFY: // { // if (wParam == WM_CREATE) @@ -1077,7 +1054,6 @@ HRESULT CALLBACK TaskDialogBootstrapCallback( ) { PPH_UPDATER_CONTEXT context = (PPH_UPDATER_CONTEXT)dwRefData; - UpdateDialogHandle = hwndDlg; switch (uMsg) { @@ -1095,13 +1071,9 @@ HRESULT CALLBACK TaskDialogBootstrapCallback( SetWindowSubclass(hwndDlg, TaskDialogSubclassProc, 0, (ULONG_PTR)context); if (context->StartupCheck) - { ShowAvailableDialog(context); - } else - { ShowCheckForUpdatesDialog(context); - } } break; } diff --git a/plugins/Updater/updater.h b/plugins/Updater/updater.h index f0ecd291f096..d557abf644e9 100644 --- a/plugins/Updater/updater.h +++ b/plugins/Updater/updater.h @@ -39,13 +39,7 @@ #include "resource.h" #define UPDATE_MENUITEM 1001 -#define PH_UPDATEISERRORED (WM_APP + 501) -#define PH_UPDATEAVAILABLE (WM_APP + 502) -#define PH_UPDATEISCURRENT (WM_APP + 503) -#define PH_UPDATENEWER (WM_APP + 504) -#define PH_UPDATESUCCESS (WM_APP + 505) -#define PH_UPDATEFAILURE (WM_APP + 506) -#define PH_SHOWDIALOG (WM_APP + 507) +#define PH_SHOWDIALOG (WM_APP + 501) #define PLUGIN_NAME L"ProcessHacker.UpdateChecker" #define SETTING_NAME_AUTO_CHECK (PLUGIN_NAME L".PromptStart") From e69d31ebd96c81ea38a1f99777aa3f07bf3f9848 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 11 Aug 2017 11:58:02 +1000 Subject: [PATCH 0375/2058] ExtraPlugins: Fix crash, Fix warning dialogs --- plugins/ExtraPlugins/main.h | 21 ++----- plugins/ExtraPlugins/setup/page3.c | 2 +- plugins/ExtraPlugins/setup/page4.c | 1 + plugins/ExtraPlugins/setup/uninstall.c | 79 +++++++++++++++++++++++++- plugins/ExtraPlugins/setup/updater.c | 72 ++++++++++++++++------- 5 files changed, 136 insertions(+), 39 deletions(-) diff --git a/plugins/ExtraPlugins/main.h b/plugins/ExtraPlugins/main.h index b425a322b6c3..6ccbc8adda4b 100644 --- a/plugins/ExtraPlugins/main.h +++ b/plugins/ExtraPlugins/main.h @@ -42,13 +42,7 @@ #include "resource.h" #define IDD_WCT_MENUITEM 1000 -#define PH_UPDATEISERRORED (WM_APP + 501) -#define PH_UPDATEAVAILABLE (WM_APP + 502) -#define PH_UPDATENEWER (WM_APP + 504) -#define PH_UPDATESUCCESS (WM_APP + 505) -#define PH_UPDATEFAILURE (WM_APP + 506) -#define WM_SHOWDIALOG (WM_APP + 550) -#define WM_ACTION (WM_APP + 1550) +#define WM_ACTION (WM_APP + 601) #define ID_WCTSHOWCONTEXTMENU 19584 #define PLUGIN_NAME L"dmex.ExtraPlugins" @@ -76,7 +70,7 @@ typedef enum _TREE_PLUGIN_STATE PLUGIN_STATE_LOCAL, PLUGIN_STATE_RESTART, PLUGIN_STATE_REMOTE, - PLUGIN_STATE_UPDATE, + PLUGIN_STATE_UPDATE } TREE_PLUGIN_STATE; typedef enum _WCT_TREE_COLUMN_ITEM_NAME @@ -190,7 +184,6 @@ BOOLEAN PhIsPluginLoadedByBaseName(_In_ PPH_STRINGREF BaseName); BOOLEAN PhIsPluginDisabled(_In_ PPH_STRINGREF BaseName); VOID PhSetPluginDisabled(_In_ PPH_STRINGREF BaseName, _In_ BOOLEAN Disable); - VOID InitializePluginsTree( _In_ PWCT_CONTEXT context, _In_ HWND ParentWindowHandle, @@ -256,9 +249,6 @@ typedef struct _PH_UPDATER_CONTEXT PLUGIN_ACTION Action; PPLUGIN_NODE Node; - PPH_STRING FileDownloadUrl; - PPH_STRING RevVersion; - PPH_STRING Size; PPH_STRING SetupFilePath; } PH_UPDATER_CONTEXT, *PPH_UPDATER_CONTEXT; @@ -274,10 +264,6 @@ BOOLEAN StartInitialCheck( ); // page1.c -VOID InstallPluginDialog( - _In_ PPH_UPDATER_CONTEXT Context - ); - VOID ShowAvailableDialog(_In_ PPH_UPDATER_CONTEXT Context); VOID TaskDialogLinkClicked(_In_ PPH_UPDATER_CONTEXT Context); VOID ShowProgressDialog(_In_ PPH_UPDATER_CONTEXT Context); @@ -287,6 +273,9 @@ VOID ShowUpdateFailedDialog( _In_ BOOLEAN HashFailed, _In_ BOOLEAN SignatureFailed ); +VOID ShowPluginUninstallWithoutPrompt( + _In_ PPH_UPDATER_CONTEXT Context + ); // page6.c VOID ShowInstallRestartDialog(_In_ PPH_UPDATER_CONTEXT Context); diff --git a/plugins/ExtraPlugins/setup/page3.c b/plugins/ExtraPlugins/setup/page3.c index 5db142d81c21..d81fe0e169fe 100644 --- a/plugins/ExtraPlugins/setup/page3.c +++ b/plugins/ExtraPlugins/setup/page3.c @@ -83,4 +83,4 @@ VOID ShowAvailableDialog( config.pfCallback = ShowAvailableCallbackProc; SendMessage(Context->DialogHandle, TDM_NAVIGATE_PAGE, 0, (LPARAM)&config); -} \ No newline at end of file +} diff --git a/plugins/ExtraPlugins/setup/page4.c b/plugins/ExtraPlugins/setup/page4.c index 566019d70dec..9f163d8c62cc 100644 --- a/plugins/ExtraPlugins/setup/page4.c +++ b/plugins/ExtraPlugins/setup/page4.c @@ -39,6 +39,7 @@ HRESULT CALLBACK ShowProgressCallbackProc( SendMessage(hwndDlg, TDM_SET_MARQUEE_PROGRESS_BAR, TRUE, 0); SendMessage(hwndDlg, TDM_SET_PROGRESS_BAR_MARQUEE, TRUE, 1); + PhReferenceObject(context); PhQueueItemWorkQueue(PhGetGlobalWorkQueue(), UpdateDownloadThread, context); } break; diff --git a/plugins/ExtraPlugins/setup/uninstall.c b/plugins/ExtraPlugins/setup/uninstall.c index 3f6069bae2dc..17da99493fbd 100644 --- a/plugins/ExtraPlugins/setup/uninstall.c +++ b/plugins/ExtraPlugins/setup/uninstall.c @@ -47,7 +47,11 @@ HRESULT CALLBACK TaskDialogUninstallCallbackProc( PhDereferenceObject(baseNameString); PhDereferenceObject(fileNameString); - ShowUninstallRestartDialog(context); + if (PhGetIntegerSetting(L"EnableWarnings")) + ShowUninstallRestartDialog(context); + else + SendMessage(hwndDlg, WM_CLOSE, 0, 0); + return S_FALSE; } } @@ -77,5 +81,78 @@ VOID ShowPluginUninstallDialog( config.pButtons = TaskDialogButtonArray; config.cButtons = ARRAYSIZE(TaskDialogButtonArray); + SendMessage(Context->DialogHandle, TDM_NAVIGATE_PAGE, 0, (LPARAM)&config); +} + +HRESULT CALLBACK TaskDialogUninstallWithoutPromptCallback( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam, + _In_ LONG_PTR dwRefData + ) +{ + PPH_UPDATER_CONTEXT context = (PPH_UPDATER_CONTEXT)dwRefData; + + switch (uMsg) + { + case TDN_NAVIGATED: + { + PPH_STRING baseNameString; + PPH_STRING fileNameString; + PPH_STRING bakNameString; + + context->Node->State = PLUGIN_STATE_RESTART; + + fileNameString = PhGetFileName(context->Node->FilePath); + baseNameString = PhGetBaseName(context->Node->FilePath); + bakNameString = PhConcatStrings(2, PhGetString(fileNameString), L".bak"); + + //PhQueueItemWorkQueue(PhGetGlobalWorkQueue(), SetupExtractBuild, context); + if (RtlDoesFileExists_U(PhGetString(fileNameString))) + { + MoveFileEx(PhGetString(fileNameString), PhGetString(bakNameString), MOVEFILE_REPLACE_EXISTING); + } + + PhDereferenceObject(bakNameString); + PhDereferenceObject(baseNameString); + PhDereferenceObject(fileNameString); + + if (PhGetIntegerSetting(L"EnableWarnings")) + { + ShowUninstallRestartDialog(context); + } + { + SendMessage(hwndDlg, WM_CLOSE, 0, 0); + } + + return S_FALSE; + } + break; + } + + return S_OK; +} + +VOID ShowPluginUninstallWithoutPrompt( + _In_ PPH_UPDATER_CONTEXT Context + ) +{ + PPH_UPDATER_CONTEXT context; + TASKDIALOGCONFIG config = { sizeof(TASKDIALOGCONFIG) }; + + context = (PPH_UPDATER_CONTEXT)Context; + + config.cxWidth = 200; + config.pszWindowTitle = L"Process Hacker - Plugin Manager"; + config.pszMainInstruction = PhaFormatString(L"Uninstalling %s...", PhIsNullOrEmptyString(Context->Node->Name) ? PhGetStringOrEmpty(Context->Node->InternalName) : PhGetStringOrEmpty(Context->Node->Name))->Buffer; + config.dwFlags = TDF_USE_HICON_MAIN | TDF_CAN_BE_MINIMIZED | TDF_SHOW_MARQUEE_PROGRESS_BAR; + config.dwCommonButtons = TDCBF_CLOSE_BUTTON; + config.hMainIcon = context->IconLargeHandle; + config.pfCallback = TaskDialogUninstallWithoutPromptCallback; + config.lpCallbackData = (LONG_PTR)Context; + config.pButtons = TaskDialogButtonArray; + config.cButtons = ARRAYSIZE(TaskDialogButtonArray); + SendMessage(Context->DialogHandle, TDM_NAVIGATE_PAGE, 0, (LPARAM)&config); } \ No newline at end of file diff --git a/plugins/ExtraPlugins/setup/updater.c b/plugins/ExtraPlugins/setup/updater.c index e6abc1fe748c..25fbd3ddb1f8 100644 --- a/plugins/ExtraPlugins/setup/updater.c +++ b/plugins/ExtraPlugins/setup/updater.c @@ -43,15 +43,6 @@ VOID FreeUpdateContext( _In_ _Post_invalid_ PPH_UPDATER_CONTEXT Context ) { - //PhClearReference(&Context->Version); - PhClearReference(&Context->RevVersion); - //PhClearReference(&Context->RelDate); - PhClearReference(&Context->Size); - //PhClearReference(&Context->Signature); - //PhClearReference(&Context->ReleaseNotesUrl); - PhClearReference(&Context->SetupFilePath); - PhClearReference(&Context->FileDownloadUrl); - PhDereferenceObject(Context); } @@ -254,6 +245,7 @@ NTSTATUS UpdateDownloadThread( PPH_STRING downloadHostPath = NULL; PPH_STRING downloadUrlPath = NULL; PPH_STRING userAgentString = NULL; + PPH_STRING fileDownloadUrl = NULL; PUPDATER_HASH_CONTEXT hashContext = NULL; ULONG indexOfFileName = -1; URL_COMPONENTS httpParts = { sizeof(URL_COMPONENTS) }; @@ -286,30 +278,46 @@ NTSTATUS UpdateDownloadThread( goto CleanupExit; } - context->FileDownloadUrl = PhFormatString( + fileDownloadUrl = PhFormatString( L"https://wj32.org/processhacker/plugins/download.php?id=%s&type=64", PhGetStringOrEmpty(context->Node->Id) ); // Set lengths to non-zero enabling these params to be cracked. - httpParts.dwSchemeLength = (ULONG)-1; - httpParts.dwHostNameLength = (ULONG)-1; - httpParts.dwUrlPathLength = (ULONG)-1; + httpParts.dwSchemeLength = ULONG_MAX; + httpParts.dwHostNameLength = ULONG_MAX; + httpParts.dwUrlPathLength = ULONG_MAX; if (!WinHttpCrackUrl( - PhGetString(context->FileDownloadUrl), + PhGetString(fileDownloadUrl), 0, 0, &httpParts )) { + PhDereferenceObject(fileDownloadUrl); goto CleanupExit; } + PhDereferenceObject(fileDownloadUrl); + // Create the Host string. - downloadHostPath = PhCreateStringEx(httpParts.lpszHostName, httpParts.dwHostNameLength * sizeof(WCHAR)); - // Create the Path string. - downloadUrlPath = PhCreateStringEx(httpParts.lpszUrlPath, httpParts.dwUrlPathLength * sizeof(WCHAR)); + if (PhIsNullOrEmptyString(downloadHostPath = PhCreateStringEx( + httpParts.lpszHostName, + httpParts.dwHostNameLength * sizeof(WCHAR) + ))) + { + goto CleanupExit; + } + + // Create the remote path string. + if (PhIsNullOrEmptyString(downloadUrlPath = PhCreateStringEx( + httpParts.lpszUrlPath, + httpParts.dwUrlPathLength * sizeof(WCHAR) + ))) + { + goto CleanupExit; + } SendMessage(context->DialogHandle, TDM_UPDATE_ELEMENT_TEXT, TDE_MAIN_INSTRUCTION, (LPARAM)L"Connecting..."); @@ -538,7 +546,10 @@ NTSTATUS UpdateDownloadThread( if (updateSuccess) { - ShowInstallRestartDialog(context); + if (PhGetIntegerSetting(L"EnableWarnings")) + ShowUninstallRestartDialog(context); + else + SendMessage(context->DialogHandle, WM_CLOSE, 0, 0); } else { @@ -569,13 +580,32 @@ HRESULT CALLBACK TaskDialogBootstrapCallback( switch (context->Action) { case PLUGIN_ACTION_INSTALL: - ShowAvailableDialog(context); + { + if (PhGetIntegerSetting(L"EnableWarnings")) + ShowAvailableDialog(context); + else + ShowProgressDialog(context); + } break; case PLUGIN_ACTION_UNINSTALL: - ShowPluginUninstallDialog(context); + { + if (PhGetIntegerSetting(L"EnableWarnings")) + ShowPluginUninstallDialog(context); + else + ShowPluginUninstallWithoutPrompt(context); + } break; case PLUGIN_ACTION_RESTART: - ShowUninstallRestartDialog(context); + { + if (PhGetIntegerSetting(L"EnableWarnings")) + { + ShowUninstallRestartDialog(context); + } + else + { + SendMessage(hwndDlg, WM_CLOSE, 0, 0); + } + } break; } } From 742c2185b6897a8ea043dac0536b0cac7c498b23 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 11 Aug 2017 11:58:48 +1000 Subject: [PATCH 0376/2058] Plugins: Tidy up winhttp parsing --- plugins/NetworkTools/update.c | 38 ++++++++++++++++++----------------- plugins/OnlineChecks/upload.c | 6 +++--- plugins/Updater/updater.c | 24 +++++++++++++--------- 3 files changed, 38 insertions(+), 30 deletions(-) diff --git a/plugins/NetworkTools/update.c b/plugins/NetworkTools/update.c index 38924478c8b0..2e8762359d52 100644 --- a/plugins/NetworkTools/update.c +++ b/plugins/NetworkTools/update.c @@ -291,7 +291,7 @@ NTSTATUS GeoIPUpdateThread( PPH_STRING fwLinkUrl = NULL; PPH_STRING downloadHostPath = NULL; PPH_STRING downloadUrlPath = NULL; - URL_COMPONENTS httpUrlComponents = { sizeof(URL_COMPONENTS) }; + URL_COMPONENTS httpParts = { sizeof(URL_COMPONENTS) }; LARGE_INTEGER timeNow; LARGE_INTEGER timeStart; ULONG64 timeTicks = 0; @@ -325,35 +325,37 @@ NTSTATUS GeoIPUpdateThread( SendMessage(context->DialogHandle, TDM_UPDATE_ELEMENT_TEXT, TDE_MAIN_INSTRUCTION, (LPARAM)L"Connecting..."); // Set lengths to non-zero enabling these params to be cracked. - httpUrlComponents.dwSchemeLength = (ULONG)-1; - httpUrlComponents.dwHostNameLength = (ULONG)-1; - httpUrlComponents.dwUrlPathLength = (ULONG)-1; + httpParts.dwSchemeLength = ULONG_MAX; + httpParts.dwHostNameLength = ULONG_MAX; + httpParts.dwUrlPathLength = ULONG_MAX; if (!WinHttpCrackUrl( fwLinkUrl->Buffer, 0, 0, - &httpUrlComponents + &httpParts )) { goto CleanupExit; } // Create the Host string. - downloadHostPath = PhCreateStringEx( - httpUrlComponents.lpszHostName, - httpUrlComponents.dwHostNameLength * sizeof(WCHAR) - ); - if (PhIsNullOrEmptyString(downloadHostPath)) + if (PhIsNullOrEmptyString(downloadHostPath = PhCreateStringEx( + httpParts.lpszHostName, + httpParts.dwHostNameLength * sizeof(WCHAR) + ))) + { goto CleanupExit; + } - // Create the Path string. - downloadUrlPath = PhCreateStringEx( - httpUrlComponents.lpszUrlPath, - httpUrlComponents.dwUrlPathLength * sizeof(WCHAR) - ); - if (PhIsNullOrEmptyString(downloadUrlPath)) + // Create the remote path string. + if (PhIsNullOrEmptyString(downloadUrlPath = PhCreateStringEx( + httpParts.lpszUrlPath, + httpParts.dwUrlPathLength * sizeof(WCHAR) + ))) + { goto CleanupExit; + } if (!(httpSessionHandle = WinHttpOpen( PhGetString(userAgentString), @@ -379,7 +381,7 @@ NTSTATUS GeoIPUpdateThread( if (!(httpConnectionHandle = WinHttpConnect( httpSessionHandle, PhGetString(downloadHostPath), - httpUrlComponents.nScheme == INTERNET_SCHEME_HTTP ? INTERNET_DEFAULT_HTTP_PORT : INTERNET_DEFAULT_HTTPS_PORT, + httpParts.nScheme == INTERNET_SCHEME_HTTP ? INTERNET_DEFAULT_HTTP_PORT : INTERNET_DEFAULT_HTTPS_PORT, 0 ))) { @@ -393,7 +395,7 @@ NTSTATUS GeoIPUpdateThread( NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, - WINHTTP_FLAG_REFRESH | (httpUrlComponents.nScheme == INTERNET_SCHEME_HTTPS ? WINHTTP_FLAG_SECURE : 0) + WINHTTP_FLAG_REFRESH | (httpParts.nScheme == INTERNET_SCHEME_HTTPS ? WINHTTP_FLAG_SECURE : 0) ))) { goto CleanupExit; diff --git a/plugins/OnlineChecks/upload.c b/plugins/OnlineChecks/upload.c index 4d060c290ff0..8646b1d98eae 100644 --- a/plugins/OnlineChecks/upload.c +++ b/plugins/OnlineChecks/upload.c @@ -467,9 +467,9 @@ NTSTATUS UploadFileThreadStart( serviceInfo = GetUploadServiceInfo(context->Service); // Set lengths to non-zero enabling these params to be cracked. - httpComponents.dwSchemeLength = (ULONG)-1; - httpComponents.dwHostNameLength = (ULONG)-1; - httpComponents.dwUrlPathLength = (ULONG)-1; + httpComponents.dwSchemeLength = ULONG_MAX; + httpComponents.dwHostNameLength = ULONG_MAX; + httpComponents.dwUrlPathLength = ULONG_MAX; if (!WinHttpCrackUrl( PhGetString(context->UploadUrl), diff --git a/plugins/Updater/updater.c b/plugins/Updater/updater.c index 97fe59b5207a..abb34f2a49e7 100644 --- a/plugins/Updater/updater.c +++ b/plugins/Updater/updater.c @@ -671,9 +671,9 @@ NTSTATUS UpdateDownloadThread( goto CleanupExit; // Set lengths to non-zero enabling these params to be cracked. - httpParts.dwSchemeLength = (ULONG)-1; - httpParts.dwHostNameLength = (ULONG)-1; - httpParts.dwUrlPathLength = (ULONG)-1; + httpParts.dwSchemeLength = ULONG_MAX; + httpParts.dwHostNameLength = ULONG_MAX; + httpParts.dwUrlPathLength = ULONG_MAX; if (!WinHttpCrackUrl( PhGetStringOrEmpty(context->SetupFileDownloadUrl), @@ -687,16 +687,22 @@ NTSTATUS UpdateDownloadThread( } // Create the Host string. - downloadHostPath = PhCreateStringEx(httpParts.lpszHostName, httpParts.dwHostNameLength * sizeof(WCHAR)); - - if (PhIsNullOrEmptyString(downloadHostPath)) + if (PhIsNullOrEmptyString(downloadHostPath = PhCreateStringEx( + httpParts.lpszHostName, + httpParts.dwHostNameLength * sizeof(WCHAR) + ))) + { goto CleanupExit; + } // Create the remote path string. - downloadUrlPath = PhCreateStringEx(httpParts.lpszUrlPath, httpParts.dwUrlPathLength * sizeof(WCHAR)); - - if (PhIsNullOrEmptyString(downloadUrlPath)) + if (PhIsNullOrEmptyString(downloadUrlPath = PhCreateStringEx( + httpParts.lpszUrlPath, + httpParts.dwUrlPathLength * sizeof(WCHAR) + ))) + { goto CleanupExit; + } // Create the local path string. context->SetupFilePath = UpdaterParseDownloadFileName(downloadUrlPath); From 5985b12758561a2702829f4ccaffe03fb4a60666 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 11 Aug 2017 13:51:59 +1000 Subject: [PATCH 0377/2058] Update process module tab options, Update headers --- ProcessHacker/include/modlist.h | 12 +++++++- ProcessHacker/modlist.c | 22 +++++++++++--- ProcessHacker/modprv.c | 11 +++---- ProcessHacker/prpgmod.c | 51 ++++++++++++++++++++++++++------- phnt/include/ntwow64.h | 1 + plugins/ExtraPlugins/main.c | 2 +- 6 files changed, 77 insertions(+), 22 deletions(-) diff --git a/ProcessHacker/include/modlist.h b/ProcessHacker/include/modlist.h index 1e9edb4150f1..1faef45ef001 100644 --- a/ProcessHacker/include/modlist.h +++ b/ProcessHacker/include/modlist.h @@ -60,6 +60,12 @@ typedef struct _PH_MODULE_NODE #define PH_MODULE_FLAGS_MAPPED_OPTION 2 #define PH_MODULE_FLAGS_STATIC_OPTION 3 #define PH_MODULE_FLAGS_SIGNED_OPTION 4 +#define PH_MODULE_FLAGS_HIGHLIGHT_UNSIGNED_OPTION 5 +#define PH_MODULE_FLAGS_HIGHLIGHT_DOTNET_OPTION 6 +#define PH_MODULE_FLAGS_HIGHLIGHT_IMMERSIVE_OPTION 7 +#define PH_MODULE_FLAGS_HIGHLIGHT_RELOCATED_OPTION 8 +#define PH_MODULE_FLAGS_LOAD_MODULE_OPTION 9 +#define PH_MODULE_FLAGS_MODULE_STRINGS_OPTION 10 typedef struct _PH_MODULE_LIST_CONTEXT { @@ -80,7 +86,11 @@ typedef struct _PH_MODULE_LIST_CONTEXT ULONG HideMappedModules : 1; ULONG HideSignedModules : 1; ULONG HideStaticModules : 1; - ULONG Spare : 27; + ULONG HighlightUntrustedModules : 1; + ULONG HighlightDotNetModules : 1; + ULONG HighlightImmersiveModules : 1; + ULONG HighlightRelocatedModules : 1; + ULONG Spare : 23; }; }; diff --git a/ProcessHacker/modlist.c b/ProcessHacker/modlist.c index 1e77f5273cd8..2b4285549d63 100644 --- a/ProcessHacker/modlist.c +++ b/ProcessHacker/modlist.c @@ -219,6 +219,18 @@ VOID PhSetOptionsModuleList( case PH_MODULE_FLAGS_SIGNED_OPTION: Context->HideSignedModules = !Context->HideSignedModules; break; + case PH_MODULE_FLAGS_HIGHLIGHT_UNSIGNED_OPTION: + Context->HighlightUntrustedModules = !Context->HighlightUntrustedModules; + break; + case PH_MODULE_FLAGS_HIGHLIGHT_DOTNET_OPTION: + Context->HighlightDotNetModules = !Context->HighlightDotNetModules; + break; + case PH_MODULE_FLAGS_HIGHLIGHT_IMMERSIVE_OPTION: + Context->HighlightImmersiveModules = !Context->HighlightImmersiveModules; + break; + case PH_MODULE_FLAGS_HIGHLIGHT_RELOCATED_OPTION: + Context->HighlightRelocatedModules = !Context->HighlightRelocatedModules; + break; } } @@ -870,14 +882,16 @@ BOOLEAN NTAPI PhpModuleTreeNewCallback( if (!moduleItem) ; // Dummy - else if (PhCsUseColorDotNet && (moduleItem->Flags & LDRP_COR_IMAGE)) + else if (context->HighlightUntrustedModules && moduleItem->VerifyResult != VrTrusted) + getNodeColor->BackColor = PhCsColorPacked; + else if (context->HighlightDotNetModules && (moduleItem->Flags & LDRP_COR_IMAGE)) getNodeColor->BackColor = PhCsColorDotNet; - else if (PhCsUseColorImmersiveProcesses && (moduleItem->ImageDllCharacteristics & IMAGE_DLLCHARACTERISTICS_APPCONTAINER)) + else if (context->HighlightImmersiveModules && (moduleItem->ImageDllCharacteristics & IMAGE_DLLCHARACTERISTICS_APPCONTAINER)) getNodeColor->BackColor = PhCsColorImmersiveProcesses; - else if (PhCsUseColorRelocatedModules && (moduleItem->Flags & LDRP_IMAGE_NOT_AT_BASE)) + else if (context->HighlightRelocatedModules && (moduleItem->Flags & LDRP_IMAGE_NOT_AT_BASE)) getNodeColor->BackColor = PhCsColorRelocatedModules; - getNodeColor->Flags = TN_CACHE | TN_AUTO_FORECOLOR; + getNodeColor->Flags = TN_AUTO_FORECOLOR; } return TRUE; case TreeNewGetNodeFont: diff --git a/ProcessHacker/modprv.c b/ProcessHacker/modprv.c index 9f5f1f623ba9..659774544dbd 100644 --- a/ProcessHacker/modprv.c +++ b/ProcessHacker/modprv.c @@ -457,21 +457,22 @@ VOID PhModuleProviderUpdate( moduleItem = PhCreateModuleItem(); + PhReferenceObject(module->Name); + PhReferenceObject(module->FileName); + moduleItem->BaseAddress = module->BaseAddress; - PhPrintPointer(moduleItem->BaseAddressString, moduleItem->BaseAddress); moduleItem->EntryPoint = module->EntryPoint; - PhPrintPointer(moduleItem->EntryPointAddressString, moduleItem->EntryPoint); moduleItem->Size = module->Size; moduleItem->Flags = module->Flags; moduleItem->Type = module->Type; moduleItem->LoadReason = module->LoadReason; moduleItem->LoadCount = module->LoadCount; moduleItem->LoadTime = module->LoadTime; - moduleItem->Name = module->Name; - PhReferenceObject(moduleItem->Name); moduleItem->FileName = module->FileName; - PhReferenceObject(moduleItem->FileName); + + PhPrintPointer(moduleItem->BaseAddressString, moduleItem->BaseAddress); + PhPrintPointer(moduleItem->EntryPointAddressString, moduleItem->EntryPoint); PhInitializeImageVersionInfo(&moduleItem->VersionInfo, moduleItem->FileName->Buffer); diff --git a/ProcessHacker/prpgmod.c b/ProcessHacker/prpgmod.c index c803d20f97b7..9ab53e012387 100644 --- a/ProcessHacker/prpgmod.c +++ b/ProcessHacker/prpgmod.c @@ -670,29 +670,49 @@ INT_PTR CALLBACK PhpProcessModulesDlgProc( PPH_EMENU_ITEM mappedItem; PPH_EMENU_ITEM staticItem; PPH_EMENU_ITEM verifiedItem; + PPH_EMENU_ITEM untrustedItem; + PPH_EMENU_ITEM dotnetItem; + PPH_EMENU_ITEM immersiveItem; + PPH_EMENU_ITEM relocatedItem; + PPH_EMENU_ITEM stringsItem; PPH_EMENU_ITEM selectedItem; GetWindowRect(GetDlgItem(hwndDlg, IDC_FILTEROPTIONS), &rect); menu = PhCreateEMenu(); - PhInsertEMenuItem(menu, dynamicItem = PhCreateEMenuItem(0, PH_MODULE_FLAGS_DYNAMIC_OPTION, L"Hide dynamic", NULL, NULL), -1); PhInsertEMenuItem(menu, mappedItem = PhCreateEMenuItem(0, PH_MODULE_FLAGS_MAPPED_OPTION, L"Hide mapped", NULL, NULL), -1); PhInsertEMenuItem(menu, staticItem = PhCreateEMenuItem(0, PH_MODULE_FLAGS_STATIC_OPTION, L"Hide static", NULL, NULL), -1); PhInsertEMenuItem(menu, verifiedItem = PhCreateEMenuItem(0, PH_MODULE_FLAGS_SIGNED_OPTION, L"Hide verified", NULL, NULL), -1); - + PhInsertEMenuItem(menu, PhCreateEMenuItem(PH_EMENU_SEPARATOR, 0, NULL, NULL, NULL), -1); + PhInsertEMenuItem(menu, dotnetItem = PhCreateEMenuItem(0, PH_MODULE_FLAGS_HIGHLIGHT_DOTNET_OPTION, L"Highlight .NET modules", NULL, NULL), -1); + PhInsertEMenuItem(menu, immersiveItem = PhCreateEMenuItem(0, PH_MODULE_FLAGS_HIGHLIGHT_IMMERSIVE_OPTION, L"Highlight immersive modules", NULL, NULL), -1); + PhInsertEMenuItem(menu, relocatedItem = PhCreateEMenuItem(0, PH_MODULE_FLAGS_HIGHLIGHT_RELOCATED_OPTION, L"Highlight relocated modules", NULL, NULL), -1); + PhInsertEMenuItem(menu, untrustedItem = PhCreateEMenuItem(0, PH_MODULE_FLAGS_HIGHLIGHT_UNSIGNED_OPTION, L"Highlight untrusted modules", NULL, NULL), -1); + PhInsertEMenuItem(menu, PhCreateEMenuItem(PH_EMENU_SEPARATOR, 0, NULL, NULL, NULL), -1); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, PH_MODULE_FLAGS_LOAD_MODULE_OPTION, L"Load module", NULL, NULL), -1); + PhInsertEMenuItem(menu, PhCreateEMenuItem(PH_EMENU_SEPARATOR, 0, NULL, NULL, NULL), -1); + PhInsertEMenuItem(menu, stringsItem = PhCreateEMenuItem(0, PH_MODULE_FLAGS_MODULE_STRINGS_OPTION, L"Strings...", NULL, NULL), -1); + if (modulesContext->ListContext.HideDynamicModules) dynamicItem->Flags |= PH_EMENU_CHECKED; - if (modulesContext->ListContext.HideMappedModules) mappedItem->Flags |= PH_EMENU_CHECKED; - if (modulesContext->ListContext.HideStaticModules) staticItem->Flags |= PH_EMENU_CHECKED; - if (modulesContext->ListContext.HideSignedModules) verifiedItem->Flags |= PH_EMENU_CHECKED; - + if (modulesContext->ListContext.HighlightDotNetModules) + dotnetItem->Flags |= PH_EMENU_CHECKED; + if (modulesContext->ListContext.HighlightImmersiveModules) + immersiveItem->Flags |= PH_EMENU_CHECKED; + if (modulesContext->ListContext.HighlightRelocatedModules) + relocatedItem->Flags |= PH_EMENU_CHECKED; + if (modulesContext->ListContext.HighlightUntrustedModules) + untrustedItem->Flags |= PH_EMENU_CHECKED; + + stringsItem->Flags |= PH_EMENU_DISABLED; + selectedItem = PhShowEMenu( menu, hwndDlg, @@ -704,11 +724,20 @@ INT_PTR CALLBACK PhpProcessModulesDlgProc( if (selectedItem && selectedItem->Id) { - PhSetOptionsModuleList(&modulesContext->ListContext, selectedItem->Id); - - PhSaveSettingsModuleList(&modulesContext->ListContext); - - PhApplyTreeNewFilters(&modulesContext->ListContext.TreeFilterSupport); + if (selectedItem->Id == PH_MODULE_FLAGS_LOAD_MODULE_OPTION) + { + PhReferenceObject(processItem); + PhUiInjectDllProcess(hwndDlg, processItem); + PhDereferenceObject(processItem); + } + else + { + PhSetOptionsModuleList(&modulesContext->ListContext, selectedItem->Id); + + PhSaveSettingsModuleList(&modulesContext->ListContext); + + PhApplyTreeNewFilters(&modulesContext->ListContext.TreeFilterSupport); + } } PhDestroyEMenu(menu); diff --git a/phnt/include/ntwow64.h b/phnt/include/ntwow64.h index 16948f927aae..4317ab0fbe9a 100644 --- a/phnt/include/ntwow64.h +++ b/phnt/include/ntwow64.h @@ -167,6 +167,7 @@ typedef struct _LDR_DATA_TABLE_ENTRY32 ULONG ImplicitPathOptions; ULONG ReferenceCount; ULONG DependentLoadFlags; + UCHAR SigningLevel; // since REDSTONE2 } LDR_DATA_TABLE_ENTRY32, *PLDR_DATA_TABLE_ENTRY32; typedef struct _CURDIR32 diff --git a/plugins/ExtraPlugins/main.c b/plugins/ExtraPlugins/main.c index ed2be884c1f1..e9a8aff8c18c 100644 --- a/plugins/ExtraPlugins/main.c +++ b/plugins/ExtraPlugins/main.c @@ -91,7 +91,7 @@ BOOLEAN PluginsCleanupDirectoryCallback( FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT ))) { - UNICODE_STRING pattern = RTL_CONSTANT_STRING(L"*"); + static UNICODE_STRING pattern = RTL_CONSTANT_STRING(L"*"); PhEnumDirectoryFile(pluginsDirectoryHandle, &pattern, PluginsCleanupDirectoryCallback, PluginsDirectoryPath); NtClose(pluginsDirectoryHandle); From 4b5ee673b8d7b5e638a5732eb3e44c4a8e6f0d84 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 12 Aug 2017 18:07:56 +1000 Subject: [PATCH 0378/2058] Fix empty process handle tab when running non-official builds --- ProcessHacker/hndlprv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ProcessHacker/hndlprv.c b/ProcessHacker/hndlprv.c index 8b7707c0f154..4afd571c33c9 100644 --- a/ProcessHacker/hndlprv.c +++ b/ProcessHacker/hndlprv.c @@ -306,7 +306,7 @@ NTSTATUS PhEnumHandlesGeneric( // * Otherwise, NtQuerySystemInformation with SystemHandleInformation // can be used. - if (KphIsConnected()) + if (KphIsConnected() && KphIsVerified()) { PKPH_PROCESS_HANDLE_INFORMATION handles; PSYSTEM_HANDLE_INFORMATION_EX convertedHandles; From d356b10289791bb5472291ae2eff50baa2d3f4b4 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 12 Aug 2017 18:45:23 +1000 Subject: [PATCH 0379/2058] Convert main Users menu to emenu --- ProcessHacker/mainwnd.c | 90 ++++++++++------------------------------- 1 file changed, 21 insertions(+), 69 deletions(-) diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index 4dbb73e92430..29785212bb3c 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -89,7 +89,6 @@ static HFONT CurrentCustomFont; static HMENU SubMenuHandles[5]; static PPH_EMENU SubMenuObjects[5]; static PPH_LIST LegacyAddMenuItemList; -static BOOLEAN UsersMenuInitialized = FALSE; static PH_CALLBACK_REGISTRATION SymInitRegistration; @@ -319,11 +318,6 @@ LRESULT CALLBACK PhMwpWndProc( return result; } break; - case WM_WTSSESSION_CHANGE: - { - PhMwpOnWtsSessionChange((ULONG)wParam, (ULONG)lParam); - } - break; } if (uMsg >= WM_PH_FIRST && uMsg <= WM_PH_LAST) @@ -485,9 +479,6 @@ NTSTATUS PhMwpDelayedLoadFunction( _In_ PVOID Parameter ) { - // Register for window station notifications. - WinStationRegisterConsoleNotification(NULL, PhMainWndHandle, WNOTIFY_ALL_SESSIONS); - PhNfLoadStage2(); // Make sure we get closed late in the shutdown process. @@ -1666,18 +1657,6 @@ VOID PhMwpOnInitMenuPopup( if (!found) return; - if (Index == 3) - { - // Special case for Users menu. - if (!UsersMenuInitialized) - { - PhMwpUpdateUsersMenu(); - UsersMenuInitialized = TRUE; - } - - return; - } - // Delete all items in this submenu. while (DeleteMenu(Menu, 0, MF_BYPOSITION)) ; @@ -1693,9 +1672,16 @@ VOID PhMwpOnInitMenuPopup( SetMenuInfo(Menu, &menuInfo); menu = PhCreateEMenu(); - PhLoadResourceEMenuItem(menu, PhInstanceHandle, MAKEINTRESOURCE(IDR_MAINWND), Index); - PhMwpInitializeSubMenu(menu, Index); + if (Index == 3) // Special case for Users menu. + { + PhMwpUpdateUsersMenu(menu); + } + else + { + PhLoadResourceEMenuItem(menu, PhInstanceHandle, MAKEINTRESOURCE(IDR_MAINWND), Index); + PhMwpInitializeSubMenu(menu, Index); + } if (PhPluginsEnabled) { @@ -1878,20 +1864,6 @@ BOOLEAN PhMwpOnNotify( return FALSE; } -VOID PhMwpOnWtsSessionChange( - _In_ ULONG Reason, - _In_ ULONG SessionId - ) -{ - if (Reason == WTS_SESSION_LOGON || Reason == WTS_SESSION_LOGOFF) - { - if (UsersMenuInitialized) - { - PhMwpUpdateUsersMenu(); - } - } -} - ULONG_PTR PhMwpOnUserMessage( _In_ ULONG Message, _In_ ULONG_PTR WParam, @@ -2557,7 +2529,14 @@ VOID PhMwpDispatchMenuCommand( case ID_USER_SENDMESSAGE: case ID_USER_PROPERTIES: { - SelectedUserSessionId = (ULONG)ItemData; + PPH_EMENU_ITEM menuItem; + + menuItem = (PPH_EMENU_ITEM)ItemData; + + if (menuItem && menuItem->Parent) + { + SelectedUserSessionId = PtrToUlong(menuItem->Parent->Context); + } } break; } @@ -3561,31 +3540,22 @@ BOOLEAN PhMwpPluginNotifyEvent( } VOID PhMwpUpdateUsersMenu( - VOID + _In_ PPH_EMENU UsersMenu ) { - HMENU menu; PSESSIONIDW sessions; ULONG numberOfSessions; ULONG i; - ULONG j; - MENUITEMINFO menuItemInfo = { sizeof(MENUITEMINFO) }; - - menu = SubMenuHandles[3]; - - // Delete all items in the Users menu. - while (DeleteMenu(menu, 0, MF_BYPOSITION)) ; if (WinStationEnumerateW(NULL, &sessions, &numberOfSessions)) { for (i = 0; i < numberOfSessions; i++) { - HMENU userMenu; + PPH_EMENU_ITEM userMenu; PPH_STRING menuText; PPH_STRING escapedMenuText; WINSTATIONINFORMATION winStationInfo; ULONG returnLength; - ULONG numberOfItems; if (!WinStationQueryInformationW( NULL, @@ -3615,30 +3585,12 @@ VOID PhMwpUpdateUsersMenu( escapedMenuText = PhEscapeStringForMenuPrefix(&menuText->sr); PhDereferenceObject(menuText); - userMenu = GetSubMenu(LoadMenu(PhInstanceHandle, MAKEINTRESOURCE(IDR_USER)), 0); - AppendMenu( - menu, - MF_STRING | MF_POPUP, - (UINT_PTR)userMenu, - escapedMenuText->Buffer - ); + PhInsertEMenuItem(UsersMenu, userMenu = PhCreateEMenuItem(0, IDR_USER, escapedMenuText->Buffer, NULL, UlongToPtr(sessions[i].SessionId)), -1); + PhLoadResourceEMenuItem(userMenu, PhInstanceHandle, MAKEINTRESOURCE(IDR_USER), 0); PhDereferenceObject(escapedMenuText); - - menuItemInfo.fMask = MIIM_DATA; - menuItemInfo.dwItemData = sessions[i].SessionId; - - numberOfItems = GetMenuItemCount(userMenu); - - if (numberOfItems != -1) - { - for (j = 0; j < numberOfItems; j++) - SetMenuItemInfo(userMenu, j, TRUE, &menuItemInfo); - } } WinStationFreeMemory(sessions); } - - DrawMenuBar(PhMainWndHandle); } From 568d992142f351112d33394ddd81cf8fc99611ce Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 12 Aug 2017 18:46:55 +1000 Subject: [PATCH 0380/2058] Add missing file from previous commit --- ProcessHacker/include/mainwndp.h | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/ProcessHacker/include/mainwndp.h b/ProcessHacker/include/mainwndp.h index ef1b7c8ea106..b2a82e0a7e77 100644 --- a/ProcessHacker/include/mainwndp.h +++ b/ProcessHacker/include/mainwndp.h @@ -119,11 +119,6 @@ BOOLEAN PhMwpOnNotify( _Out_ LRESULT *Result ); -VOID PhMwpOnWtsSessionChange( - _In_ ULONG Reason, - _In_ ULONG SessionId - ); - ULONG_PTR PhMwpOnUserMessage( _In_ ULONG Message, _In_ ULONG_PTR WParam, @@ -506,7 +501,7 @@ VOID PhMwpOnNetworkItemsUpdated( // Users VOID PhMwpUpdateUsersMenu( - VOID + _In_ PPH_EMENU UsersMenu ); #endif From 8003e87b27e98ac13bc86f9ef37e989ebe14f7e4 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 12 Aug 2017 21:41:53 +1000 Subject: [PATCH 0381/2058] Fix showing thread stack window after an error --- ProcessHacker/thrdstk.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/ProcessHacker/thrdstk.c b/ProcessHacker/thrdstk.c index 9674e6531cce..b63a2f5c2619 100644 --- a/ProcessHacker/thrdstk.c +++ b/ProcessHacker/thrdstk.c @@ -807,7 +807,11 @@ static INT_PTR CALLBACK PhpThreadStackDlgProc( if (status == STATUS_ABANDONED) EndDialog(hwndDlg, IDCANCEL); else if (!NT_SUCCESS(status)) - PhShowStatus(hwndDlg, L"Unable to load the stack", status, 0); + { + // HACK: Show error dialog on the parent window. + PhShowStatus(GetParent(hwndDlg), L"Unable to load the stack.", status, 0); + EndDialog(hwndDlg, IDCANCEL); + } } break; case WM_DESTROY: @@ -850,7 +854,7 @@ static INT_PTR CALLBACK PhpThreadStackDlgProc( if (!NT_SUCCESS(status = PhpRefreshThreadStack(hwndDlg, context))) { - PhShowStatus(hwndDlg, L"Unable to load the stack", status, 0); + PhShowStatus(hwndDlg, L"Unable to refresh the stack.", status, 0); } } break; From 73adea9a09928457970deee990344d65e8230506 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 13 Aug 2017 13:38:08 +1000 Subject: [PATCH 0382/2058] Add PhGetExpandStringSetting macro --- phlib/include/settings.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/phlib/include/settings.h b/phlib/include/settings.h index 5fadd004d4b8..7cd07eb07b1d 100644 --- a/phlib/include/settings.h +++ b/phlib/include/settings.h @@ -95,6 +95,20 @@ PhGetStringSetting( _In_ PWSTR Name ); +FORCEINLINE +PPH_STRING +PhGetExpandStringSetting( + _In_ PWSTR Name + ) +{ + PPH_STRING setting; + + setting = PhGetStringSetting(Name); + PhMoveReference(&setting, PhExpandEnvironmentStrings(&setting->sr)); + + return setting; +} + _May_raise_ PHLIBAPI VOID From 1eeabea3000b0a61e12522af0dcadfa962da96bc Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 13 Aug 2017 15:32:48 +1000 Subject: [PATCH 0383/2058] NetworkTools: Add setting for the geoip database path --- plugins/NetworkTools/country.c | 11 ++++++++--- plugins/NetworkTools/main.c | 1 + plugins/NetworkTools/nettools.h | 2 +- plugins/NetworkTools/update.c | 15 ++++++++++----- 4 files changed, 20 insertions(+), 9 deletions(-) diff --git a/plugins/NetworkTools/country.c b/plugins/NetworkTools/country.c index f4d0ff2e3078..9ab6f6ea8203 100644 --- a/plugins/NetworkTools/country.c +++ b/plugins/NetworkTools/country.c @@ -31,11 +31,14 @@ VOID LoadGeoLiteDb( VOID ) { - PPH_STRING path; + PPH_STRING dbpath; - path = PH_AUTO(PhGetKnownLocation(CSIDL_APPDATA, L"\\Process Hacker\\GeoLite2-Country.mmdb")); + dbpath = PhGetExpandStringSetting(SETTING_NAME_DB_LOCATION); - if (MMDB_open(PhGetString(path), MMDB_MODE_MMAP, &GeoDb) == MMDB_SUCCESS) + if (PhIsNullOrEmptyString(dbpath)) + PhMoveReference(&dbpath, PhGetKnownLocation(CSIDL_APPDATA, L"\\Process Hacker\\GeoLite2-Country.mmdb")); + + if (MMDB_open(PhGetString(dbpath), MMDB_MODE_MMAP, &GeoDb) == MMDB_SUCCESS) { time_t systemTime; @@ -55,6 +58,8 @@ VOID LoadGeoLiteDb( GeoDbLoaded = TRUE; } + + PhDereferenceObject(dbpath); } VOID FreeGeoLiteDb( diff --git a/plugins/NetworkTools/main.c b/plugins/NetworkTools/main.c index 1542ea7612e5..4c75f6c05769 100644 --- a/plugins/NetworkTools/main.c +++ b/plugins/NetworkTools/main.c @@ -597,6 +597,7 @@ LOGICAL DllMain( { IntegerSettingType, SETTING_NAME_TRACERT_MAX_HOPS, L"30" }, { IntegerPairSettingType, SETTING_NAME_WHOIS_WINDOW_POSITION, L"0,0" }, { ScalableIntegerPairSettingType, SETTING_NAME_WHOIS_WINDOW_SIZE, L"@96|600,365" }, + { StringSettingType, SETTING_NAME_DB_LOCATION, L"%APPDATA%\\Process Hacker\\GeoLite2-Country.mmdb" }, }; PluginInstance = PhRegisterPlugin(PLUGIN_NAME, Instance, &info); diff --git a/plugins/NetworkTools/nettools.h b/plugins/NetworkTools/nettools.h index 48d232f8574b..cc52b6e22c4c 100644 --- a/plugins/NetworkTools/nettools.h +++ b/plugins/NetworkTools/nettools.h @@ -45,7 +45,7 @@ #include "resource.h" #define PLUGIN_NAME L"ProcessHacker.NetworkTools" -#define SETTING_NAME_DB_TYPE (PLUGIN_NAME L".GeoIpType") +#define SETTING_NAME_DB_LOCATION (PLUGIN_NAME L".GeoDbPath") #define SETTING_NAME_ADDRESS_HISTORY (PLUGIN_NAME L".AddressHistory") #define SETTING_NAME_PING_WINDOW_POSITION (PLUGIN_NAME L".PingWindowPosition") #define SETTING_NAME_PING_WINDOW_SIZE (PLUGIN_NAME L".PingWindowSize") diff --git a/plugins/NetworkTools/update.c b/plugins/NetworkTools/update.c index 2e8762359d52..cce08c067af9 100644 --- a/plugins/NetworkTools/update.c +++ b/plugins/NetworkTools/update.c @@ -520,16 +520,21 @@ NTSTATUS GeoIPUpdateThread( } { - PPH_STRING gzpath; + PPH_STRING dbpath; PPH_BYTES mmdbGzPath; gzFile gzfile; - gzpath = PH_AUTO(PhGetKnownLocation(CSIDL_APPDATA, L"\\Process Hacker\\GeoLite2-Country.mmdb")); + dbpath = PhGetExpandStringSetting(SETTING_NAME_DB_LOCATION); + + if (PhIsNullOrEmptyString(dbpath)) + PhMoveReference(&dbpath, PhGetKnownLocation(CSIDL_APPDATA, L"\\Process Hacker\\GeoLite2-Country.mmdb")); + + PhAutoDereferenceObject(dbpath); mmdbGzPath = PH_AUTO(PhConvertUtf16ToUtf8(PhGetString(context->SetupFilePath))); - if (RtlDoesFileExists_U(PhGetString(gzpath))) + if (RtlDoesFileExists_U(PhGetString(dbpath))) { - if (!NT_SUCCESS(PhDeleteFileWin32(PhGetString(gzpath)))) + if (!NT_SUCCESS(PhDeleteFileWin32(PhGetString(dbpath)))) goto CleanupExit; } @@ -539,7 +544,7 @@ NTSTATUS GeoIPUpdateThread( if (NT_SUCCESS(PhCreateFileWin32( &mmdbFileHandle, - PhGetStringOrEmpty(gzpath), + PhGetStringOrEmpty(dbpath), FILE_GENERIC_READ | FILE_GENERIC_WRITE, FILE_ATTRIBUTE_NOT_CONTENT_INDEXED | FILE_ATTRIBUTE_TEMPORARY, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, From f31c0d9063b206d114672d99e4537e39a6d5047f Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 13 Aug 2017 15:33:12 +1000 Subject: [PATCH 0384/2058] Remove unused export --- ProcessHacker/ProcessHacker.def | 1 - 1 file changed, 1 deletion(-) diff --git a/ProcessHacker/ProcessHacker.def b/ProcessHacker/ProcessHacker.def index d9ec3b6a127b..3cd1060436f0 100644 --- a/ProcessHacker/ProcessHacker.def +++ b/ProcessHacker/ProcessHacker.def @@ -639,7 +639,6 @@ EXPORTS PhGetJsonObjectAsArrayList ; cache - PhGetCacheDirectory PhClearCacheDirectory PhCreateCacheFile PhDeleteCacheFile From b198b9d80434a4847ec4d97c79cf8375cec7794f Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 13 Aug 2017 20:12:45 +1000 Subject: [PATCH 0385/2058] Fix network tab sorting --- ProcessHacker/netlist.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ProcessHacker/netlist.c b/ProcessHacker/netlist.c index 6c416a97f978..8845df4fcb40 100644 --- a/ProcessHacker/netlist.c +++ b/ProcessHacker/netlist.c @@ -454,15 +454,15 @@ BOOLEAN NTAPI PhpNetworkTreeNewCallback( { SORT_FUNCTION(Process), SORT_FUNCTION(LocalAddress), - SORT_FUNCTION(LocalHostname), SORT_FUNCTION(LocalPort), SORT_FUNCTION(RemoteAddress), - SORT_FUNCTION(RemoteHostname), SORT_FUNCTION(RemotePort), SORT_FUNCTION(Protocol), SORT_FUNCTION(State), SORT_FUNCTION(Owner), - SORT_FUNCTION(TimeStamp) + SORT_FUNCTION(TimeStamp), + SORT_FUNCTION(LocalHostname), + SORT_FUNCTION(RemoteHostname) }; int (__cdecl *sortFunction)(const void *, const void *); From 93ffa22de3e7364f4925ba68b33950d96d33fce9 Mon Sep 17 00:00:00 2001 From: Koby Kahane Date: Sun, 13 Aug 2017 18:08:17 +0300 Subject: [PATCH 0386/2058] Show restricting SIDs when displaying the access token property page. (#167) --- ProcessHacker/include/phapp.h | 3 +- ProcessHacker/tokprp.c | 126 +++++++++++++++++++++------------- phlib/include/phnative.h | 8 +++ phlib/native.c | 19 +++++ 4 files changed, 109 insertions(+), 47 deletions(-) diff --git a/ProcessHacker/include/phapp.h b/ProcessHacker/include/phapp.h index 82099e4e0225..aaf3ed2325b6 100644 --- a/ProcessHacker/include/phapp.h +++ b/ProcessHacker/include/phapp.h @@ -789,7 +789,8 @@ VOID PhShowThreadStackDialog( // tokprp PPH_STRING PhGetGroupAttributesString( - _In_ ULONG Attributes + _In_ ULONG Attributes, + _In_ BOOLEAN Restricted ); PWSTR PhGetPrivilegeAttributesString( diff --git a/ProcessHacker/tokprp.c b/ProcessHacker/tokprp.c index 24cb7c718740..e3a06197efca 100644 --- a/ProcessHacker/tokprp.c +++ b/ProcessHacker/tokprp.c @@ -54,6 +54,7 @@ typedef struct _TOKEN_PAGE_CONTEXT HWND PrivilegesListViewHandle; PTOKEN_GROUPS Groups; + PTOKEN_GROUPS RestrictedSids; PTOKEN_PRIVILEGES Privileges; PTOKEN_GROUPS Capabilities; @@ -204,7 +205,8 @@ INT CALLBACK PhpTokenPropPageProc( } PPH_STRING PhGetGroupAttributesString( - _In_ ULONG Attributes + _In_ ULONG Attributes, + _In_ BOOLEAN Restricted ) { PWSTR baseString; @@ -213,40 +215,51 @@ PPH_STRING PhGetGroupAttributesString( if (Attributes & SE_GROUP_INTEGRITY) { if (Attributes & SE_GROUP_INTEGRITY_ENABLED) - return PhCreateString(L"Integrity"); + string = PhCreateString(L"Integrity"); else - return PhCreateString(L"Integrity (disabled)"); + string = PhCreateString(L"Integrity (disabled)"); } - - if (Attributes & SE_GROUP_LOGON_ID) - baseString = L"Logon ID"; - else if (Attributes & SE_GROUP_MANDATORY) - baseString = L"Mandatory"; - else if (Attributes & SE_GROUP_OWNER) - baseString = L"Owner"; - else if (Attributes & SE_GROUP_RESOURCE) - baseString = L"Resource"; - else if (Attributes & SE_GROUP_USE_FOR_DENY_ONLY) - baseString = L"Use for deny only"; else - baseString = NULL; - - if (!baseString) { - if (Attributes & SE_GROUP_ENABLED_BY_DEFAULT) - return PhCreateString(L"Default enabled"); - else if (Attributes & SE_GROUP_ENABLED) - return PhReferenceEmptyString(); + if (Attributes & SE_GROUP_LOGON_ID) + baseString = L"Logon ID"; + else if (Attributes & SE_GROUP_MANDATORY) + baseString = L"Mandatory"; + else if (Attributes & SE_GROUP_OWNER) + baseString = L"Owner"; + else if (Attributes & SE_GROUP_RESOURCE) + baseString = L"Resource"; + else if (Attributes & SE_GROUP_USE_FOR_DENY_ONLY) + baseString = L"Use for deny only"; else - return PhCreateString(L"Disabled"); + baseString = NULL; + + if (!baseString) + { + if (Attributes & SE_GROUP_ENABLED_BY_DEFAULT) + string = PhCreateString(L"Default enabled"); + else if (Attributes & SE_GROUP_ENABLED) + string = PhReferenceEmptyString(); + else + string = PhCreateString(L"Disabled"); + } + else + { + if (Attributes & SE_GROUP_ENABLED_BY_DEFAULT) + string = PhConcatStrings2(baseString, L" (default enabled)"); + else if (Attributes & SE_GROUP_ENABLED) + string = PhCreateString(baseString); + else + string = PhConcatStrings2(baseString, L" (disabled)"); + } } - if (Attributes & SE_GROUP_ENABLED_BY_DEFAULT) - string = PhConcatStrings2(baseString, L" (default enabled)"); - else if (Attributes & SE_GROUP_ENABLED) - string = PhCreateString(baseString); - else - string = PhConcatStrings2(baseString, L" (disabled)"); + if (Restricted) + { + PPH_STRING prefixString = string; + string = PhConcatStrings2(prefixString->Buffer, L" (restricted)"); + PhDereferenceObject(prefixString); + } return string; } @@ -332,47 +345,68 @@ PWSTR PhGetElevationTypeString( } } -BOOLEAN PhpUpdateTokenGroups( - _In_ HWND hwndDlg, - _In_ PTOKEN_PAGE_CONTEXT TokenPageContext, +VOID PhpUpdateSidsFromTokenGroups( _In_ HWND GroupsLv, - _In_ HANDLE TokenHandle + _In_ PTOKEN_GROUPS Groups, + _In_ BOOLEAN Restricted ) { - PTOKEN_GROUPS groups; ULONG i; - if (!NT_SUCCESS(PhGetTokenGroups(TokenHandle, &groups))) - return FALSE; - - ExtendedListView_SetRedraw(GroupsLv, FALSE); - - ListView_DeleteAllItems(GroupsLv); - - for (i = 0; i < groups->GroupCount; i++) + for (i = 0; i < Groups->GroupCount; i++) { INT lvItemIndex; PPH_STRING fullName; PPH_STRING attributesString; - if (!(fullName = PhGetSidFullName(groups->Groups[i].Sid, TRUE, NULL))) - fullName = PhSidToStringSid(groups->Groups[i].Sid); + if (!(fullName = PhGetSidFullName(Groups->Groups[i].Sid, TRUE, NULL))) + fullName = PhSidToStringSid(Groups->Groups[i].Sid); if (fullName) { - lvItemIndex = PhAddListViewItem(GroupsLv, MAXINT, fullName->Buffer, &groups->Groups[i]); - attributesString = PhGetGroupAttributesString(groups->Groups[i].Attributes); + lvItemIndex = PhAddListViewItem(GroupsLv, MAXINT, fullName->Buffer, &Groups->Groups[i]); + attributesString = PhGetGroupAttributesString(Groups->Groups[i].Attributes, Restricted); PhSetListViewSubItem(GroupsLv, lvItemIndex, 1, attributesString->Buffer); PhDereferenceObject(attributesString); PhDereferenceObject(fullName); } } +} + +BOOLEAN PhpUpdateTokenGroups( + _In_ HWND hwndDlg, + _In_ PTOKEN_PAGE_CONTEXT TokenPageContext, + _In_ HWND GroupsLv, + _In_ HANDLE TokenHandle + ) +{ + PTOKEN_GROUPS groups; + PTOKEN_GROUPS restrictedSIDs = NULL; + + if (!NT_SUCCESS(PhGetTokenGroups(TokenHandle, &groups))) + return FALSE; + + ExtendedListView_SetRedraw(GroupsLv, FALSE); + + ListView_DeleteAllItems(GroupsLv); + + PhpUpdateSidsFromTokenGroups(GroupsLv, groups, FALSE); + + if (NT_SUCCESS(PhGetTokenRestrictedSids(TokenHandle, &restrictedSIDs))) + { + PhpUpdateSidsFromTokenGroups(GroupsLv, restrictedSIDs, TRUE); + } ExtendedListView_SortItems(GroupsLv); ExtendedListView_SetRedraw(GroupsLv, TRUE); + if (TokenPageContext->RestrictedSids) + PhFree(TokenPageContext->RestrictedSids); + + TokenPageContext->RestrictedSids = restrictedSIDs; + if (TokenPageContext->Groups) PhFree(TokenPageContext->Groups); @@ -1389,7 +1423,7 @@ INT_PTR CALLBACK PhpTokenCapabilitiesPageProc( lvItemIndex = PhAddListViewItem(lvHandle, MAXINT, name->Buffer, &tokenPageContext->Capabilities->Groups[i]); attributesString = PhGetGroupAttributesString( - tokenPageContext->Capabilities->Groups[i].Attributes); + tokenPageContext->Capabilities->Groups[i].Attributes, FALSE); PhSetListViewSubItem(lvHandle, lvItemIndex, 1, attributesString->Buffer); PhDereferenceObject(attributesString); diff --git a/phlib/include/phnative.h b/phlib/include/phnative.h index b9dd90ab0716..4e752ae3a347 100644 --- a/phlib/include/phnative.h +++ b/phlib/include/phnative.h @@ -347,6 +347,14 @@ PhGetTokenGroups( _Out_ PTOKEN_GROUPS *Groups ); +PHLIBAPI +NTSTATUS +NTAPI +PhGetTokenRestrictedSids( + _In_ HANDLE TokenHandle, + _Out_ PTOKEN_GROUPS* RestrictedSids + ); + PHLIBAPI NTSTATUS NTAPI diff --git a/phlib/native.c b/phlib/native.c index 3af7fe0f68ba..443d259ebf02 100644 --- a/phlib/native.c +++ b/phlib/native.c @@ -1868,6 +1868,25 @@ NTSTATUS PhGetTokenGroups( ); } +/** + * Get a token's restricted SIDs. + * + * \param TokenHandle A handle to a token. The handle must have TOKEN_QUERY access. + * \param RestrictedSids A variable which receives a pointer to a structure containing the token's restricted SIDs. + * You must free the structure using PhFree() when you no longer need it. + */ +NTSTATUS PhGetTokenRestrictedSids( + _In_ HANDLE TokenHandle, + _Out_ PTOKEN_GROUPS* RestrictedSids +) +{ + return PhpQueryTokenVariableSize( + TokenHandle, + TokenRestrictedSids, + RestrictedSids + ); +} + /** * Gets a token's privileges. * From cee832a3873f2c3e3135c335426f2fdc4490ee6e Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 14 Aug 2017 01:30:37 +1000 Subject: [PATCH 0387/2058] Fix setup error during kph update --- .../CustomSetupTool/download.c | 28 +++++++++++++------ tools/CustomSetupTool/CustomSetupTool/setup.c | 5 ++-- 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/tools/CustomSetupTool/CustomSetupTool/download.c b/tools/CustomSetupTool/CustomSetupTool/download.c index 3355a0fc99dc..d76238c99456 100644 --- a/tools/CustomSetupTool/CustomSetupTool/download.c +++ b/tools/CustomSetupTool/CustomSetupTool/download.c @@ -174,12 +174,10 @@ BOOLEAN SetupQueryUpdateData( if (WindowsVersion >= WINDOWS_8_1) { - ULONG httpFlags = WINHTTP_DECOMPRESSION_FLAG_GZIP | WINHTTP_DECOMPRESSION_FLAG_DEFLATE; - WinHttpSetOption( httpSessionHandle, WINHTTP_OPTION_DECOMPRESSION, - &httpFlags, + &(ULONG) { WINHTTP_DECOMPRESSION_FLAG_GZIP | WINHTTP_DECOMPRESSION_FLAG_DEFLATE }, sizeof(ULONG) ); } @@ -211,8 +209,12 @@ BOOLEAN SetupQueryUpdateData( if (WindowsVersion >= WINDOWS_7) { - ULONG keepAlive = WINHTTP_DISABLE_KEEP_ALIVE; - WinHttpSetOption(httpRequestHandle, WINHTTP_OPTION_DISABLE_FEATURE, &keepAlive, sizeof(ULONG)); + WinHttpSetOption( + httpRequestHandle, + WINHTTP_OPTION_DISABLE_FEATURE, + &(ULONG) { WINHTTP_DISABLE_KEEP_ALIVE }, + sizeof(ULONG) + ); } if (versionHeader) @@ -445,8 +447,12 @@ BOOLEAN UpdateDownloadUpdateData( if (WindowsVersion >= WINDOWS_8_1) { - ULONG httpFlags = WINHTTP_DECOMPRESSION_FLAG_GZIP | WINHTTP_DECOMPRESSION_FLAG_DEFLATE; - WinHttpSetOption(httpSessionHandle, WINHTTP_OPTION_DECOMPRESSION, &httpFlags, sizeof(ULONG)); + WinHttpSetOption( + httpSessionHandle, + WINHTTP_OPTION_DECOMPRESSION, + &(ULONG) { WINHTTP_DECOMPRESSION_FLAG_GZIP | WINHTTP_DECOMPRESSION_FLAG_DEFLATE }, + sizeof(ULONG) + ); } if (!(httpConnectionHandle = WinHttpConnect( @@ -476,8 +482,12 @@ BOOLEAN UpdateDownloadUpdateData( if (WindowsVersion >= WINDOWS_7) { - ULONG keepAlive = WINHTTP_DISABLE_KEEP_ALIVE; - WinHttpSetOption(httpRequestHandle, WINHTTP_OPTION_DISABLE_FEATURE, &keepAlive, sizeof(ULONG)); + WinHttpSetOption( + httpRequestHandle, + WINHTTP_OPTION_DISABLE_FEATURE, + &(ULONG) { WINHTTP_DISABLE_KEEP_ALIVE }, + sizeof(ULONG) + ); } if (!WinHttpSendRequest( diff --git a/tools/CustomSetupTool/CustomSetupTool/setup.c b/tools/CustomSetupTool/CustomSetupTool/setup.c index b9fbfaab07be..810433cc85dc 100644 --- a/tools/CustomSetupTool/CustomSetupTool/setup.c +++ b/tools/CustomSetupTool/CustomSetupTool/setup.c @@ -328,7 +328,7 @@ VOID SetupStopService( serviceHandle = PhOpenService( ServiceName, - SERVICE_QUERY_STATUS | SERVICE_STOP + SERVICE_QUERY_STATUS | SERVICE_STOP | DELETE ); if (serviceHandle) @@ -378,6 +378,8 @@ VOID SetupStopService( } } + DeleteService(serviceHandle); + CloseServiceHandle(serviceHandle); } } @@ -422,7 +424,6 @@ BOOLEAN SetupUninstallKph( ) { SetupStopService(L"KProcessHacker2"); - SetupStopService(L"KProcessHacker3"); return TRUE; From be69ab36cacba81699dc8e02c62bf0259d1b038a Mon Sep 17 00:00:00 2001 From: Koby Kahane Date: Sun, 13 Aug 2017 19:49:58 +0300 Subject: [PATCH 0388/2058] Free token restricted SIDs when destroying the token property page. (#169) --- ProcessHacker/tokprp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/ProcessHacker/tokprp.c b/ProcessHacker/tokprp.c index e3a06197efca..97852c2c9925 100644 --- a/ProcessHacker/tokprp.c +++ b/ProcessHacker/tokprp.c @@ -624,6 +624,7 @@ INT_PTR CALLBACK PhpTokenPageProc( PhSaveListViewColumnsToSetting(L"TokenPrivilegesListViewColumns", tokenPageContext->PrivilegesListViewHandle); if (tokenPageContext->Groups) PhFree(tokenPageContext->Groups); + if (tokenPageContext->RestrictedSids) PhFree(tokenPageContext->RestrictedSids); if (tokenPageContext->Privileges) PhFree(tokenPageContext->Privileges); } break; From fcd79e479ee5d7e3cfa76a8a19ba8900ccc868fe Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 15 Aug 2017 20:52:09 +1000 Subject: [PATCH 0389/2058] NetworkTools: Fix crash sorting tracert window, Fix saving tracert column and sort settings --- plugins/NetworkTools/main.c | 3 ++- plugins/NetworkTools/nettools.h | 3 ++- plugins/NetworkTools/tracetree.c | 38 +++++++++++++++++++++++++++++--- plugins/NetworkTools/update.c | 2 +- 4 files changed, 40 insertions(+), 6 deletions(-) diff --git a/plugins/NetworkTools/main.c b/plugins/NetworkTools/main.c index 4c75f6c05769..fa5dc23efcc1 100644 --- a/plugins/NetworkTools/main.c +++ b/plugins/NetworkTools/main.c @@ -593,7 +593,8 @@ LOGICAL DllMain( { IntegerSettingType, SETTING_NAME_PING_SIZE, L"20" }, // 32 byte packet { IntegerPairSettingType, SETTING_NAME_TRACERT_WINDOW_POSITION, L"0,0" }, { ScalableIntegerPairSettingType, SETTING_NAME_TRACERT_WINDOW_SIZE, L"@96|850,490" }, - { StringSettingType, SETTING_NAME_TRACERT_LIST_COLUMNS, L"" }, + { StringSettingType, SETTING_NAME_TRACERT_TREE_LIST_COLUMNS, L"" }, + { IntegerPairSettingType, SETTING_NAME_TRACERT_TREE_LIST_SORT, L"0,1" }, { IntegerSettingType, SETTING_NAME_TRACERT_MAX_HOPS, L"30" }, { IntegerPairSettingType, SETTING_NAME_WHOIS_WINDOW_POSITION, L"0,0" }, { ScalableIntegerPairSettingType, SETTING_NAME_WHOIS_WINDOW_SIZE, L"@96|600,365" }, diff --git a/plugins/NetworkTools/nettools.h b/plugins/NetworkTools/nettools.h index cc52b6e22c4c..b636a0bc7091 100644 --- a/plugins/NetworkTools/nettools.h +++ b/plugins/NetworkTools/nettools.h @@ -53,7 +53,8 @@ #define SETTING_NAME_PING_SIZE (PLUGIN_NAME L".PingSize") #define SETTING_NAME_TRACERT_WINDOW_POSITION (PLUGIN_NAME L".TracertWindowPosition") #define SETTING_NAME_TRACERT_WINDOW_SIZE (PLUGIN_NAME L".TracertWindowSize") -#define SETTING_NAME_TRACERT_LIST_COLUMNS (PLUGIN_NAME L".TracertListColumns") +#define SETTING_NAME_TRACERT_TREE_LIST_COLUMNS (PLUGIN_NAME L".TracertTreeColumns") +#define SETTING_NAME_TRACERT_TREE_LIST_SORT (PLUGIN_NAME L".TracertTreeSort") #define SETTING_NAME_TRACERT_MAX_HOPS (PLUGIN_NAME L".TracertMaxHops") #define SETTING_NAME_WHOIS_WINDOW_POSITION (PLUGIN_NAME L".WhoisWindowPosition") #define SETTING_NAME_WHOIS_WINDOW_SIZE (PLUGIN_NAME L".WhoisWindowSize") diff --git a/plugins/NetworkTools/tracetree.c b/plugins/NetworkTools/tracetree.c index 1cf94b79f2ac..9327858f7434 100644 --- a/plugins/NetworkTools/tracetree.c +++ b/plugins/NetworkTools/tracetree.c @@ -72,15 +72,37 @@ BEGIN_SORT_FUNCTION(Ping4) } END_SORT_FUNCTION +BEGIN_SORT_FUNCTION(Country) +{ + sortResult = PhCompareStringWithNull(node1->CountryString, node2->CountryString, TRUE); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(IpAddress) +{ + sortResult = PhCompareStringWithNull(node1->IpAddressString, node2->IpAddressString, TRUE); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(Hostname) +{ + sortResult = PhCompareStringWithNull(node1->HostnameString, node2->HostnameString, TRUE); +} +END_SORT_FUNCTION + VOID TracertLoadSettingsTreeList( _Inout_ PNETWORK_TRACERT_CONTEXT Context ) { PPH_STRING settings; + PH_INTEGER_PAIR sortSettings; - settings = PhGetStringSetting(SETTING_NAME_TRACERT_LIST_COLUMNS); + settings = PhGetStringSetting(SETTING_NAME_TRACERT_TREE_LIST_COLUMNS); PhCmLoadSettings(Context->TreeNewHandle, &settings->sr); PhDereferenceObject(settings); + + sortSettings = PhGetIntegerPairSetting(SETTING_NAME_TRACERT_TREE_LIST_SORT); + TreeNew_SetSort(Context->TreeNewHandle, (ULONG)sortSettings.X, (PH_SORT_ORDER)sortSettings.Y); } VOID TracertSaveSettingsTreeList( @@ -88,10 +110,18 @@ VOID TracertSaveSettingsTreeList( ) { PPH_STRING settings; + PH_INTEGER_PAIR sortSettings; + ULONG sortColumn; + PH_SORT_ORDER sortOrder; settings = PhCmSaveSettings(Context->TreeNewHandle); - PhSetStringSetting2(SETTING_NAME_TRACERT_LIST_COLUMNS, &settings->sr); + PhSetStringSetting2(SETTING_NAME_TRACERT_TREE_LIST_COLUMNS, &settings->sr); PhDereferenceObject(settings); + + TreeNew_GetSort(Context->TreeNewHandle, &sortColumn, &sortOrder); + sortSettings.X = sortColumn; + sortSettings.Y = sortOrder; + PhSetIntegerPairSetting(SETTING_NAME_TRACERT_TREE_LIST_SORT, sortSettings); } BOOLEAN TracertNodeHashtableEqualFunction( @@ -268,6 +298,9 @@ BOOLEAN NTAPI TracertTreeNewCallback( SORT_FUNCTION(Ping2), SORT_FUNCTION(Ping3), SORT_FUNCTION(Ping4), + SORT_FUNCTION(IpAddress), + SORT_FUNCTION(Hostname), + SORT_FUNCTION(Country), }; int (__cdecl *sortFunction)(void *, const void *, const void *); @@ -549,7 +582,6 @@ VOID InitializeTracertTree( //for (INT i = 0; i < MAX_PINGS; i++) // PhAddTreeNewColumn(context->TreeNewHandle, i + 1, i + 1, i + 1, LVCFMT_RIGHT, 50, L"Time"); - TreeNew_SetTriState(Context->TreeNewHandle, TRUE); TreeNew_SetSort(Context->TreeNewHandle, TREE_COLUMN_ITEM_TTL, AscendingSortOrder); TracertLoadSettingsTreeList(Context); diff --git a/plugins/NetworkTools/update.c b/plugins/NetworkTools/update.c index cce08c067af9..b88d78143f68 100644 --- a/plugins/NetworkTools/update.c +++ b/plugins/NetworkTools/update.c @@ -675,7 +675,7 @@ NTSTATUS GeoIPUpdateDialogThread( context = (PPH_UPDATER_CONTEXT)PhCreateAlloc(sizeof(PH_UPDATER_CONTEXT)); memset(context, 0, sizeof(PH_UPDATER_CONTEXT)); - config.dwFlags = TDF_ALLOW_DIALOG_CANCELLATION | TDF_CAN_BE_MINIMIZED | TDF_POSITION_RELATIVE_TO_WINDOW; + config.dwFlags = TDF_ALLOW_DIALOG_CANCELLATION | TDF_CAN_BE_MINIMIZED; config.pszContent = L"Initializing..."; config.lpCallbackData = (LONG_PTR)context; config.pfCallback = TaskDialogBootstrapCallback; From 76a4dac2e62f6e748bb95b7c3780ffc730056acb Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 15 Aug 2017 23:07:30 +1000 Subject: [PATCH 0390/2058] Add name column to process threads tab (e.g. show Chrome thread names) --- ProcessHacker/include/thrdlist.h | 3 +- ProcessHacker/include/thrdprv.h | 2 ++ ProcessHacker/thrdlist.c | 20 ++++++++++++- ProcessHacker/thrdprv.c | 50 ++++++++++++++++++++++++++++++++ 4 files changed, 73 insertions(+), 2 deletions(-) diff --git a/ProcessHacker/include/thrdlist.h b/ProcessHacker/include/thrdlist.h index f1132eb4549b..c17f97f69e73 100644 --- a/ProcessHacker/include/thrdlist.h +++ b/ProcessHacker/include/thrdlist.h @@ -12,8 +12,9 @@ #define PHTHTLC_STARTADDRESS 3 #define PHTHTLC_PRIORITY 4 #define PHTHTLC_SERVICE 5 +#define PHTHTLC_NAME 6 -#define PHTHTLC_MAXIMUM 6 +#define PHTHTLC_MAXIMUM 7 // begin_phapppub typedef struct _PH_THREAD_NODE diff --git a/ProcessHacker/include/thrdprv.h b/ProcessHacker/include/thrdprv.h index ef6fe42f6cfa..971f06779e3d 100644 --- a/ProcessHacker/include/thrdprv.h +++ b/ProcessHacker/include/thrdprv.h @@ -36,6 +36,8 @@ typedef struct _PH_THREAD_ITEM BOOLEAN JustResolved; WCHAR ThreadIdString[PH_INT32_STR_LEN_1]; + + PPH_STRING ThreadName; } PH_THREAD_ITEM, *PPH_THREAD_ITEM; typedef enum _PH_KNOWN_PROCESS_TYPE PH_KNOWN_PROCESS_TYPE; diff --git a/ProcessHacker/thrdlist.c b/ProcessHacker/thrdlist.c index 37ad2e9c7698..7d3bcd1d128e 100644 --- a/ProcessHacker/thrdlist.c +++ b/ProcessHacker/thrdlist.c @@ -101,6 +101,7 @@ VOID PhInitializeThreadList( PhAddTreeNewColumn(hwnd, PHTHTLC_STARTADDRESS, TRUE, L"Start address", 180, PH_ALIGN_LEFT, 3, 0); PhAddTreeNewColumnEx(hwnd, PHTHTLC_PRIORITY, TRUE, L"Priority", 80, PH_ALIGN_LEFT, 4, 0, TRUE); PhAddTreeNewColumn(hwnd, PHTHTLC_SERVICE, FALSE, L"Service", 100, PH_ALIGN_LEFT, -1, 0); + PhAddTreeNewColumn(hwnd, PHTHTLC_NAME, FALSE, L"Name", 100, PH_ALIGN_LEFT, -1, 0); TreeNew_SetRedraw(hwnd, TRUE); @@ -166,6 +167,13 @@ VOID PhLoadSettingsThreadList( TreeNew_SetColumn(Context->TreeNewHandle, TN_COLUMN_FLAG_VISIBLE, &column); } + if (WindowsVersion >= WINDOWS_10_RS1) + { + column.Id = PHTHTLC_NAME; + column.Visible = TRUE; + TreeNew_SetColumn(Context->TreeNewHandle, TN_COLUMN_FLAG_VISIBLE, &column); + } + settings = PhGetStringSetting(L"ThreadTreeListColumns"); sortSettings = PhGetStringSetting(L"ThreadTreeListSort"); PhCmLoadSettingsEx(Context->TreeNewHandle, &Context->Cm, PH_CM_COLUMN_WIDTHS_ONLY, &settings->sr, &sortSettings->sr); @@ -417,6 +425,12 @@ BEGIN_SORT_FUNCTION(Service) } END_SORT_FUNCTION +BEGIN_SORT_FUNCTION(Name) +{ + sortResult = PhCompareStringWithNull(threadItem1->ThreadName, threadItem2->ThreadName, TRUE); +} +END_SORT_FUNCTION + BOOLEAN NTAPI PhpThreadTreeNewCallback( _In_ HWND hwnd, _In_ PH_TREENEW_MESSAGE Message, @@ -448,7 +462,8 @@ BOOLEAN NTAPI PhpThreadTreeNewCallback( SORT_FUNCTION(CyclesDelta), SORT_FUNCTION(StartAddress), SORT_FUNCTION(Priority), - SORT_FUNCTION(Service) + SORT_FUNCTION(Service), + SORT_FUNCTION(Name) }; int (__cdecl *sortFunction)(void *, const void *, const void *); @@ -564,6 +579,9 @@ BOOLEAN NTAPI PhpThreadTreeNewCallback( case PHTHTLC_SERVICE: getCellText->Text = PhGetStringRef(threadItem->ServiceName); break; + case PHTHTLC_NAME: + getCellText->Text = PhGetStringRef(threadItem->ThreadName); + break; default: return FALSE; } diff --git a/ProcessHacker/thrdprv.c b/ProcessHacker/thrdprv.c index 3be1e25a73e2..6eb750985a73 100644 --- a/ProcessHacker/thrdprv.c +++ b/ProcessHacker/thrdprv.c @@ -49,6 +49,7 @@ typedef struct _PH_THREAD_QUERY_DATA PH_SYMBOL_RESOLVE_LEVEL StartAddressResolveLevel; PPH_STRING ServiceName; + PPH_STRING ThreadName; } PH_THREAD_QUERY_DATA, *PPH_THREAD_QUERY_DATA; typedef struct _PH_THREAD_SYMBOL_LOAD_CONTEXT @@ -198,6 +199,7 @@ VOID PhpThreadProviderDeleteProcedure( PhClearReference(&data->StartAddressString); PhClearReference(&data->ServiceName); + PhClearReference(&data->ThreadName); PhDereferenceObject(data->ThreadItem); PhFree(data); } @@ -412,6 +414,7 @@ VOID PhpThreadItemDeleteProcedure( if (threadItem->StartAddressString) PhDereferenceObject(threadItem->StartAddressString); if (threadItem->StartAddressFileName) PhDereferenceObject(threadItem->StartAddressFileName); if (threadItem->ServiceName) PhDereferenceObject(threadItem->ServiceName); + if (threadItem->ThreadName) PhDereferenceObject(threadItem->ThreadName); } BOOLEAN PhpThreadHashtableEqualFunction( @@ -577,6 +580,52 @@ NTSTATUS PhpThreadQueryWorker( } } + // Get the thread name (Windows 10 only). + + if (data->ThreadItem->ThreadHandle && WindowsVersion >= WINDOWS_10_RS1) + { + NTSTATUS status; + PVOID buffer; + ULONG bufferSize; + ULONG returnLength; + PUNICODE_STRING unicodeString; + + bufferSize = 0x100; + buffer = PhAllocate(bufferSize); + + status = NtQueryInformationThread( + data->ThreadItem->ThreadHandle, + ThreadNameInformation, + buffer, + bufferSize, + &returnLength + ); + + if (status == STATUS_BUFFER_OVERFLOW) + { + PhFree(buffer); + bufferSize = returnLength; + buffer = PhAllocate(bufferSize); + + status = NtQueryInformationThread( + data->ThreadItem->ThreadHandle, + ThreadNameInformation, + buffer, + bufferSize, + &returnLength + ); + } + + if (NT_SUCCESS(status)) + { + unicodeString = (PUNICODE_STRING)buffer; + + data->ThreadName = PhCreateStringFromUnicodeString(unicodeString); + } + + PhFree(buffer); + } + Done: RtlInterlockedPushEntrySList(&data->ThreadProvider->QueryListHead, &data->ListEntry); PhDereferenceObject(data->ThreadProvider); @@ -826,6 +875,7 @@ VOID PhpThreadProviderUpdate( } PhMoveReference(&data->ThreadItem->ServiceName, data->ServiceName); + PhMoveReference(&data->ThreadItem->ThreadName, data->ThreadName); data->ThreadItem->JustResolved = TRUE; From 9523abccf351d4ddbfd6e6972c1d0508d79bd733 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 17 Aug 2017 00:15:47 +1000 Subject: [PATCH 0391/2058] Add verification/signer columns to services tab --- ProcessHacker/srvlist.c | 30 +++++++++++- ProcessHacker/srvprv.c | 100 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 129 insertions(+), 1 deletion(-) diff --git a/ProcessHacker/srvlist.c b/ProcessHacker/srvlist.c index eb10d23e993a..4f85a62bda1d 100644 --- a/ProcessHacker/srvlist.c +++ b/ProcessHacker/srvlist.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -138,6 +139,8 @@ VOID PhInitializeServiceTreeList( PhAddTreeNewColumn(hwnd, PHSVTLC_GROUP, FALSE, L"Group", 100, PH_ALIGN_LEFT, -1, 0); PhAddTreeNewColumn(hwnd, PHSVTLC_DESCRIPTION, FALSE, L"Description", 200, PH_ALIGN_LEFT, -1, 0); PhAddTreeNewColumnEx(hwnd, PHSVTLC_KEYMODIFIEDTIME, FALSE, L"Key modified time", 140, PH_ALIGN_LEFT, -1, 0, TRUE); + PhAddTreeNewColumn(hwnd, PHSVTLC_VERIFICATIONSTATUS, FALSE, L"Verification status", 70, PH_ALIGN_LEFT, -1, 0); + PhAddTreeNewColumn(hwnd, PHSVTLC_VERIFIEDSIGNER, FALSE, L"Verified signer", 100, PH_ALIGN_LEFT, -1, 0); TreeNew_SetRedraw(hwnd, TRUE); @@ -528,6 +531,22 @@ BEGIN_SORT_FUNCTION(KeyModifiedTime) } END_SORT_FUNCTION +BEGIN_SORT_FUNCTION(VerificationStatus) +{ + sortResult = intcmp(serviceItem1->VerifyResult, serviceItem2->VerifyResult); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(VerifiedSigner) +{ + sortResult = PhCompareStringWithNull( + serviceItem1->VerifySignerName, + serviceItem2->VerifySignerName, + TRUE + ); +} +END_SORT_FUNCTION + BOOLEAN NTAPI PhpServiceTreeNewCallback( _In_ HWND hwnd, _In_ PH_TREENEW_MESSAGE Message, @@ -561,7 +580,9 @@ BOOLEAN NTAPI PhpServiceTreeNewCallback( SORT_FUNCTION(ErrorControl), SORT_FUNCTION(Group), SORT_FUNCTION(Description), - SORT_FUNCTION(KeyModifiedTime) + SORT_FUNCTION(KeyModifiedTime), + SORT_FUNCTION(VerificationStatus), + SORT_FUNCTION(VerifiedSigner) }; int (__cdecl *sortFunction)(const void *, const void *); @@ -674,6 +695,13 @@ BOOLEAN NTAPI PhpServiceTreeNewCallback( getCellText->Text = node->KeyModifiedTimeText->sr; } break; + case PHSVTLC_VERIFICATIONSTATUS: + PhInitializeStringRef(&getCellText->Text, + serviceItem->VerifyResult == VrTrusted ? L"Trusted" : L"Not trusted"); + break; + case PHSVTLC_VERIFIEDSIGNER: + getCellText->Text = PhGetStringRef(serviceItem->VerifySignerName); + break; default: return FALSE; } diff --git a/ProcessHacker/srvprv.c b/ProcessHacker/srvprv.c index 70dc41e6b684..3e638fb589d7 100644 --- a/ProcessHacker/srvprv.c +++ b/ProcessHacker/srvprv.c @@ -3,6 +3,7 @@ * service provider * * Copyright (C) 2009-2015 wj32 + * Copyright (C) 2017 dmex * * This file is part of Process Hacker. * @@ -22,6 +23,7 @@ #include #include +#include #include #include @@ -99,6 +101,16 @@ static HANDLE PhpNonPollEventHandle; static PH_QUEUED_LOCK PhpNonPollServiceListLock = PH_QUEUED_LOCK_INIT; static LIST_ENTRY PhpNonPollServiceListHead; static LIST_ENTRY PhpNonPollServicePendingListHead; +static SLIST_HEADER PhpServiceQueryListHead; + +typedef struct _PH_SERVICE_QUERY_DATA +{ + SLIST_ENTRY ListEntry; + PPH_SERVICE_ITEM ServiceItem; + + VERIFY_RESULT VerifyResult; + PPH_STRING VerifySignerName; +} PH_SERVICE_QUERY_DATA, *PPH_SERVICE_QUERY_DATA; BOOLEAN PhServiceProviderInitialization( VOID @@ -112,6 +124,8 @@ BOOLEAN PhServiceProviderInitialization( 40 ); + RtlInitializeSListHead(&PhpServiceQueryListHead); + return TRUE; } @@ -441,6 +455,60 @@ static ULONG PhpHashServiceNameEntry( return PhHashStringRef(&Value->Name, TRUE); } +NTSTATUS PhpServiceQueryWorker( + _In_ PVOID Parameter + ) +{ + PPH_SERVICE_QUERY_DATA data = (PPH_SERVICE_QUERY_DATA)Parameter; + SC_HANDLE serviceHandle; + PPH_STRING serviceFileName; + + if (serviceHandle = PhOpenService(data->ServiceItem->Name->Buffer, SERVICE_QUERY_CONFIG)) + { + serviceFileName = PhGetServiceRelevantFileName(&data->ServiceItem->Name->sr, serviceHandle); + CloseServiceHandle(serviceHandle); + } + + if (serviceFileName) + { + data->VerifyResult = PhVerifyFileCached( + serviceFileName, + NULL, + &data->VerifySignerName, + FALSE + ); + PhDereferenceObject(serviceFileName); + } + + RtlInterlockedPushEntrySList(&PhpServiceQueryListHead, &data->ListEntry); + + return STATUS_SUCCESS; +} + +VOID PhpQueueServiceQuery( + _In_ PPH_SERVICE_ITEM ServiceItem + ) +{ + PPH_SERVICE_QUERY_DATA data; + PH_WORK_QUEUE_ENVIRONMENT environment; + + if (!PhEnableProcessQueryStage2) // Reuse the same setting for convenience. + return; + + data = PhAllocate(sizeof(PH_SERVICE_QUERY_DATA)); + memset(data, 0, sizeof(PH_SERVICE_QUERY_DATA)); + data->ServiceItem = ServiceItem; + + PhReferenceObject(ServiceItem); + + PhInitializeWorkQueueEnvironment(&environment); + environment.BasePriority = THREAD_PRIORITY_BELOW_NORMAL; + environment.IoPriority = IoPriorityLow; + environment.PagePriority = MEMORY_PRIORITY_LOW; + + PhQueueItemWorkQueueEx(PhGetGlobalWorkQueue(), PhpServiceQueryWorker, data, NULL, &environment); +} + VOID PhServiceProviderUpdate( _In_ PVOID Object ) @@ -523,6 +591,27 @@ VOID PhServiceProviderUpdate( ); } + // Go through the queued services query data. + { + PSLIST_ENTRY entry; + PPH_SERVICE_QUERY_DATA data; + + entry = RtlInterlockedFlushSList(&PhpServiceQueryListHead); + + while (entry) + { + data = CONTAINING_RECORD(entry, PH_SERVICE_QUERY_DATA, ListEntry); + entry = entry->Next; + + data->ServiceItem->VerifyResult = data->VerifyResult; + data->ServiceItem->VerifySignerName = data->VerifySignerName; + data->ServiceItem->JustProcessed = TRUE; + + PhDereferenceObject(data->ServiceItem); + PhFree(data); + } + } + // Look for dead services. { PPH_LIST servicesToRemove = NULL; @@ -644,6 +733,9 @@ VOID PhServiceProviderUpdate( } } + // Queue for verification. + PhpQueueServiceQuery(serviceItem); + // Add the service item to the hashtable. PhAcquireQueuedLockExclusive(&PhServiceHashtableLock); PhAddEntryHashtable(PhServiceHashtable, &serviceItem); @@ -654,6 +746,8 @@ VOID PhServiceProviderUpdate( } else { + BOOLEAN modified = FALSE; + if (WindowsVersion >= WINDOWS_10_RS2) { // https://github.com/processhacker2/processhacker/issues/120 @@ -663,7 +757,13 @@ VOID PhServiceProviderUpdate( serviceEntry->ServiceStatusProcess.dwServiceType = SERVICE_USER_SHARE_PROCESS | SERVICE_USERSERVICE_INSTANCE; } + if (serviceItem->JustProcessed) + modified = TRUE; + + serviceItem->JustProcessed = FALSE; + if ( + modified || serviceItem->Type != serviceEntry->ServiceStatusProcess.dwServiceType || serviceItem->State != serviceEntry->ServiceStatusProcess.dwCurrentState || serviceItem->ControlsAccepted != serviceEntry->ServiceStatusProcess.dwControlsAccepted || From 7879df7be87857aa1d25a3d66e9739809b682bae Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 17 Aug 2017 00:16:42 +1000 Subject: [PATCH 0392/2058] Add missing files from previous commit --- ProcessHacker/include/srvlist.h | 4 +++- ProcessHacker/include/srvprv.h | 23 +++++++++++++++++++---- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/ProcessHacker/include/srvlist.h b/ProcessHacker/include/srvlist.h index 499823274b3b..ea73a2824be3 100644 --- a/ProcessHacker/include/srvlist.h +++ b/ProcessHacker/include/srvlist.h @@ -17,8 +17,10 @@ #define PHSVTLC_GROUP 8 #define PHSVTLC_DESCRIPTION 9 #define PHSVTLC_KEYMODIFIEDTIME 10 +#define PHSVTLC_VERIFICATIONSTATUS 11 +#define PHSVTLC_VERIFIEDSIGNER 12 -#define PHSVTLC_MAXIMUM 11 +#define PHSVTLC_MAXIMUM 13 #define PHSN_CONFIG 0x1 #define PHSN_DESCRIPTION 0x2 diff --git a/ProcessHacker/include/srvprv.h b/ProcessHacker/include/srvprv.h index a01349d8005e..a30b1b6f148f 100644 --- a/ProcessHacker/include/srvprv.h +++ b/ProcessHacker/include/srvprv.h @@ -11,6 +11,8 @@ PHAPPAPI extern PH_CALLBACK PhServicesUpdatedEvent; // phapppub extern BOOLEAN PhEnableServiceNonPoll; // begin_phapppub +typedef enum _VERIFY_RESULT VERIFY_RESULT; + typedef struct _PH_SERVICE_ITEM { PH_STRINGREF Key; // points to Name @@ -28,13 +30,26 @@ typedef struct _PH_SERVICE_ITEM ULONG StartType; ULONG ErrorControl; // end_phapppub - BOOLEAN DelayedStart; - BOOLEAN HasTriggers; - BOOLEAN PendingProcess; - BOOLEAN NeedsConfigUpdate; + union + { + BOOLEAN BitFlags; + struct + { + BOOLEAN DelayedStart : 1; + BOOLEAN HasTriggers : 1; + BOOLEAN PendingProcess : 1; + BOOLEAN NeedsConfigUpdate : 1; + BOOLEAN JustProcessed : 1; + BOOLEAN Spare : 3; + }; + }; + + VERIFY_RESULT VerifyResult; + PPH_STRING VerifySignerName; WCHAR ProcessIdString[PH_INT32_STR_LEN_1]; + // begin_phapppub } PH_SERVICE_ITEM, *PPH_SERVICE_ITEM; // end_phapppub From fb9156a70498ca228ace92cf35b0d412ad726af9 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 17 Aug 2017 00:46:51 +1000 Subject: [PATCH 0393/2058] Add winsta.dll to linker delayload --- ProcessHacker/ProcessHacker.vcxproj | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ProcessHacker/ProcessHacker.vcxproj b/ProcessHacker/ProcessHacker.vcxproj index 0be944a9791b..1b6219b26070 100644 --- a/ProcessHacker/ProcessHacker.vcxproj +++ b/ProcessHacker/ProcessHacker.vcxproj @@ -102,7 +102,7 @@ 6.01 $(SolutionDir)phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) ProcessHacker.def - aclui.dll;iphlpapi.dll;ws2_32.dll;%(DelayLoadDLLs) + aclui.dll;iphlpapi.dll;winsta.dll;ws2_32.dll;%(DelayLoadDLLs) _UNICODE;UNICODE;%(PreprocessorDefinitions);$(ExternalCompilerOptions) @@ -133,7 +133,7 @@ 6.01 $(SolutionDir)phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) ProcessHacker.def - aclui.dll;iphlpapi.dll;ws2_32.dll;%(DelayLoadDLLs) + aclui.dll;iphlpapi.dll;winsta.dll;ws2_32.dll;%(DelayLoadDLLs) _UNICODE;UNICODE;%(PreprocessorDefinitions);$(ExternalCompilerOptions) @@ -173,7 +173,7 @@ 6.01 $(SolutionDir)phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) ProcessHacker.def - aclui.dll;iphlpapi.dll;ws2_32.dll;%(DelayLoadDLLs) + aclui.dll;iphlpapi.dll;winsta.dll;ws2_32.dll;%(DelayLoadDLLs) _UNICODE;UNICODE;%(PreprocessorDefinitions);$(ExternalCompilerOptions) @@ -211,7 +211,7 @@ 6.01 $(SolutionDir)phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) ProcessHacker.def - aclui.dll;iphlpapi.dll;ws2_32.dll;%(DelayLoadDLLs) + aclui.dll;iphlpapi.dll;winsta.dll;ws2_32.dll;%(DelayLoadDLLs) _UNICODE;UNICODE;%(PreprocessorDefinitions);$(ExternalCompilerOptions) From 24855cd80a933ddf40095e3dd7d8de2e5b082b60 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 17 Aug 2017 00:54:35 +1000 Subject: [PATCH 0394/2058] NetworkTools: Patch manminddb.c and disable unused winsock functionality --- plugins/NetworkTools/maxminddb/maxminddb.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/NetworkTools/maxminddb/maxminddb.c b/plugins/NetworkTools/maxminddb/maxminddb.c index f5e8d66cb850..24979674a53f 100644 --- a/plugins/NetworkTools/maxminddb/maxminddb.c +++ b/plugins/NetworkTools/maxminddb/maxminddb.c @@ -248,8 +248,8 @@ int MMDB_open(const wchar_t* const filename, uint32_t flags, MMDB_s *const mmdb) } #ifdef _WIN32 - WSADATA wsa; - WSAStartup(MAKEWORD(2, 2), &wsa); + //WSADATA wsa; // dmex: disabled since hostname lookup is not used. + //WSAStartup(MAKEWORD(2, 2), &wsa); #endif uint32_t metadata_size = 0; @@ -1845,7 +1845,7 @@ LOCAL void free_mmdb_struct(MMDB_s *const mmdb) UnmapViewOfFile(mmdb->file_content); /* Winsock is only initialized if open was successful so we only have * to cleanup then. */ - WSACleanup(); + //WSACleanup(); // dmex: disabled since hostname lookup is not used. #else munmap((void *)mmdb->file_content, mmdb->file_size); #endif From 54e8457208ddd62047f6c324520ab1d4f45e3b4a Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 17 Aug 2017 00:55:26 +1000 Subject: [PATCH 0395/2058] Fix typo --- phlib/native.c | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/phlib/native.c b/phlib/native.c index 443d259ebf02..4b99fe5466c5 100644 --- a/phlib/native.c +++ b/phlib/native.c @@ -1108,10 +1108,7 @@ NTSTATUS PhGetProcessMappedFileName( } unicodeString = (PUNICODE_STRING)buffer; - *FileName = PhCreateStringEx( - unicodeString->Buffer, - unicodeString->Length - ); + *FileName = PhCreateStringFromUnicodeString(unicodeString); PhFree(buffer); return status; @@ -2703,10 +2700,7 @@ NTSTATUS PhGetDriverName( ))) return status; - *Name = PhCreateStringEx( - unicodeString->Buffer, - unicodeString->Length - ); + *Name = PhCreateStringFromUnicodeString(unicodeString); PhFree(unicodeString); return status; @@ -2736,10 +2730,7 @@ NTSTATUS PhGetDriverServiceKeyName( ))) return status; - *ServiceKeyName = PhCreateStringEx( - unicodeString->Buffer, - unicodeString->Length - ); + *ServiceKeyName = PhCreateStringFromUnicodeString(unicodeString); PhFree(unicodeString); return status; From 900980413e46baa4700ac7092269bcb36a7d5067 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 17 Aug 2017 01:43:03 +1000 Subject: [PATCH 0396/2058] NetworkTools: Fix tracert crash --- plugins/NetworkTools/tracert.c | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/plugins/NetworkTools/tracert.c b/plugins/NetworkTools/tracert.c index eb5d39c5a0fc..75f8e2b0d609 100644 --- a/plugins/NetworkTools/tracert.c +++ b/plugins/NetworkTools/tracert.c @@ -178,8 +178,13 @@ VOID TracertQueueHostLookup( &remoteCountryName )) { - PhMoveReference(&Node->RemoteCountryCode, remoteCountryCode); - PhMoveReference(&Node->RemoteCountryName, remoteCountryName); + if (Node->RemoteCountryCode) + PhDereferenceObject(Node->RemoteCountryCode); + if (Node->RemoteCountryName) + PhDereferenceObject(Node->RemoteCountryName); + + Node->RemoteCountryCode = remoteCountryCode; + Node->RemoteCountryName = remoteCountryName; } } else if (Context->RemoteEndpoint.Address.Type == PH_IPV6_NETWORK_TYPE) @@ -229,8 +234,13 @@ VOID TracertQueueHostLookup( &remoteCountryName )) { - PhMoveReference(&Node->RemoteCountryCode, remoteCountryCode); - PhMoveReference(&Node->RemoteCountryName, remoteCountryName); + if (Node->RemoteCountryCode) + PhDereferenceObject(Node->RemoteCountryCode); + if (Node->RemoteCountryName) + PhDereferenceObject(Node->RemoteCountryName); + + Node->RemoteCountryCode = remoteCountryCode; + Node->RemoteCountryName = remoteCountryName; } } } @@ -650,7 +660,11 @@ INT_PTR CALLBACK TracertDlgProc( switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDCANCEL: - DestroyWindow(hwndDlg); + { + context->Cancel = TRUE; + + DestroyWindow(hwndDlg); + } break; case IDC_REFRESH: { From e9355ac68493d80e46f2c66601b82ebcd082b551 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 17 Aug 2017 01:44:06 +1000 Subject: [PATCH 0397/2058] Fix service verification column crash --- ProcessHacker/srvprv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ProcessHacker/srvprv.c b/ProcessHacker/srvprv.c index 3e638fb589d7..38bb93373374 100644 --- a/ProcessHacker/srvprv.c +++ b/ProcessHacker/srvprv.c @@ -461,7 +461,7 @@ NTSTATUS PhpServiceQueryWorker( { PPH_SERVICE_QUERY_DATA data = (PPH_SERVICE_QUERY_DATA)Parameter; SC_HANDLE serviceHandle; - PPH_STRING serviceFileName; + PPH_STRING serviceFileName = NULL; if (serviceHandle = PhOpenService(data->ServiceItem->Name->Buffer, SERVICE_QUERY_CONFIG)) { From 3391c028b54dec9dc25b5772c3094e37a4b7b829 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 17 Aug 2017 01:44:42 +1000 Subject: [PATCH 0398/2058] Fix typo --- ProcessHacker/thrdprv.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ProcessHacker/thrdprv.c b/ProcessHacker/thrdprv.c index 6eb750985a73..a1eb226728a6 100644 --- a/ProcessHacker/thrdprv.c +++ b/ProcessHacker/thrdprv.c @@ -588,7 +588,7 @@ NTSTATUS PhpThreadQueryWorker( PVOID buffer; ULONG bufferSize; ULONG returnLength; - PUNICODE_STRING unicodeString; + PTHREAD_NAME_INFORMATION threadNameInfo; bufferSize = 0x100; buffer = PhAllocate(bufferSize); @@ -618,9 +618,9 @@ NTSTATUS PhpThreadQueryWorker( if (NT_SUCCESS(status)) { - unicodeString = (PUNICODE_STRING)buffer; + threadNameInfo = (PTHREAD_NAME_INFORMATION)buffer; - data->ThreadName = PhCreateStringFromUnicodeString(unicodeString); + data->ThreadName = PhCreateStringFromUnicodeString(&threadNameInfo->ThreadName); } PhFree(buffer); From 5b6a2407fa99f6436d430ed7bef345f3c72dda25 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 17 Aug 2017 04:33:10 +1000 Subject: [PATCH 0399/2058] Add MainWindowTabRestoreEnabled option --- ProcessHacker/mainwnd.c | 7 +++++++ ProcessHacker/settings.c | 2 ++ 2 files changed, 9 insertions(+) diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index 29785212bb3c..c8648aa0997e 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -227,6 +227,11 @@ BOOLEAN PhMainWndInitialization( if (page) PhMwpSelectPage(page->Index); } + else + { + if (PhGetIntegerSetting(L"MainWindowTabRestoreEnabled")) + PhMwpSelectPage(PhGetIntegerSetting(L"MainWindowTabRestoreIndex")); + } if (PhStartupParameters.SysInfo) PhShowSystemInformationDialog(PhStartupParameters.SysInfo->Buffer); @@ -536,6 +541,8 @@ VOID PhMwpOnDestroy( VOID ) { + PhSetIntegerSetting(L"MainWindowTabRestoreIndex", TabCtrl_GetCurSel(TabControlHandle)); + // Notify pages and plugins that we are shutting down. PhMwpNotifyAllPages(MainTabPageDestroy, NULL, NULL); diff --git a/ProcessHacker/settings.c b/ProcessHacker/settings.c index 28994dd78cbe..86a97ee41548 100644 --- a/ProcessHacker/settings.c +++ b/ProcessHacker/settings.c @@ -90,6 +90,8 @@ VOID PhAddDefaultSettings( PhpAddIntegerPairSetting(L"MainWindowPosition", L"100,100"); PhpAddScalableIntegerPairSetting(L"MainWindowSize", L"@96|800,600"); PhpAddIntegerSetting(L"MainWindowState", L"1"); + PhpAddIntegerSetting(L"MainWindowTabRestoreEnabled", L"0"); + PhpAddIntegerSetting(L"MainWindowTabRestoreIndex", L"0"); PhpAddIntegerSetting(L"MaxSizeUnit", L"6"); PhpAddIntegerSetting(L"MemEditBytesPerRow", L"10"); // 16 PhpAddStringSetting(L"MemEditGotoChoices", L""); From 91bd4bede0e0ed57887565183d132cf29743da1b Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 17 Aug 2017 05:23:36 +1000 Subject: [PATCH 0400/2058] Fix service verification status column not updating the verification state --- ProcessHacker/include/srvprv.h | 2 +- ProcessHacker/srvprv.c | 29 ++++++++++++++++++----------- 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/ProcessHacker/include/srvprv.h b/ProcessHacker/include/srvprv.h index a30b1b6f148f..08d55c57457c 100644 --- a/ProcessHacker/include/srvprv.h +++ b/ProcessHacker/include/srvprv.h @@ -40,7 +40,7 @@ typedef struct _PH_SERVICE_ITEM BOOLEAN HasTriggers : 1; BOOLEAN PendingProcess : 1; BOOLEAN NeedsConfigUpdate : 1; - BOOLEAN JustProcessed : 1; + BOOLEAN NeedsVerifyUpdate : 1; BOOLEAN Spare : 3; }; }; diff --git a/ProcessHacker/srvprv.c b/ProcessHacker/srvprv.c index 38bb93373374..826bdfc48796 100644 --- a/ProcessHacker/srvprv.c +++ b/ProcessHacker/srvprv.c @@ -256,6 +256,14 @@ VOID PhMarkNeedsConfigUpdateServiceItem( PhpNonPollGate = 1; } +VOID PhpResetServiceNonPollGate( + VOID + ) +{ + if (PhEnableServiceNonPoll) + PhpNonPollGate = 1; +} + VOID PhpRemoveServiceItem( _In_ PPH_SERVICE_ITEM ServiceItem ) @@ -477,9 +485,12 @@ NTSTATUS PhpServiceQueryWorker( &data->VerifySignerName, FALSE ); + PhDereferenceObject(serviceFileName); } + PhpResetServiceNonPollGate(); // HACK + RtlInterlockedPushEntrySList(&PhpServiceQueryListHead, &data->ListEntry); return STATUS_SUCCESS; @@ -492,7 +503,7 @@ VOID PhpQueueServiceQuery( PPH_SERVICE_QUERY_DATA data; PH_WORK_QUEUE_ENVIRONMENT environment; - if (!PhEnableProcessQueryStage2) // Reuse the same setting for convenience. + if (!PhEnableProcessQueryStage2) return; data = PhAllocate(sizeof(PH_SERVICE_QUERY_DATA)); @@ -605,7 +616,7 @@ VOID PhServiceProviderUpdate( data->ServiceItem->VerifyResult = data->VerifyResult; data->ServiceItem->VerifySignerName = data->VerifySignerName; - data->ServiceItem->JustProcessed = TRUE; + data->ServiceItem->NeedsVerifyUpdate = TRUE; PhDereferenceObject(data->ServiceItem); PhFree(data); @@ -746,8 +757,6 @@ VOID PhServiceProviderUpdate( } else { - BOOLEAN modified = FALSE; - if (WindowsVersion >= WINDOWS_10_RS2) { // https://github.com/processhacker2/processhacker/issues/120 @@ -757,18 +766,13 @@ VOID PhServiceProviderUpdate( serviceEntry->ServiceStatusProcess.dwServiceType = SERVICE_USER_SHARE_PROCESS | SERVICE_USERSERVICE_INSTANCE; } - if (serviceItem->JustProcessed) - modified = TRUE; - - serviceItem->JustProcessed = FALSE; - if ( - modified || serviceItem->Type != serviceEntry->ServiceStatusProcess.dwServiceType || serviceItem->State != serviceEntry->ServiceStatusProcess.dwCurrentState || serviceItem->ControlsAccepted != serviceEntry->ServiceStatusProcess.dwControlsAccepted || serviceItem->ProcessId != UlongToHandle(serviceEntry->ServiceStatusProcess.dwProcessId) || - serviceItem->NeedsConfigUpdate + serviceItem->NeedsConfigUpdate || + serviceItem->NeedsVerifyUpdate ) { PH_SERVICE_MODIFIED_DATA serviceModifiedData; @@ -862,6 +866,9 @@ VOID PhServiceProviderUpdate( serviceItem->NeedsConfigUpdate = FALSE; } + if (serviceItem->NeedsVerifyUpdate) // HACK + serviceItem->NeedsVerifyUpdate = FALSE; + // Raise the service modified event. PhInvokeCallback(&PhServiceModifiedEvent, &serviceModifiedData); } From 99be9c0401880c4147f09b1d691f4b71f794adcb Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 17 Aug 2017 05:54:53 +1000 Subject: [PATCH 0401/2058] Update begin_phapppub --- ProcessHacker/include/srvprv.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/ProcessHacker/include/srvprv.h b/ProcessHacker/include/srvprv.h index 08d55c57457c..ea4ca015cc4e 100644 --- a/ProcessHacker/include/srvprv.h +++ b/ProcessHacker/include/srvprv.h @@ -44,13 +44,11 @@ typedef struct _PH_SERVICE_ITEM BOOLEAN Spare : 3; }; }; - +// begin_phapppub VERIFY_RESULT VerifyResult; PPH_STRING VerifySignerName; WCHAR ProcessIdString[PH_INT32_STR_LEN_1]; - -// begin_phapppub } PH_SERVICE_ITEM, *PPH_SERVICE_ITEM; // end_phapppub From 398040837b840beea801099a28511ef1e0979871 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 18 Aug 2017 00:58:02 +1000 Subject: [PATCH 0402/2058] Fix log window showing incorrect exit status for linux processes --- ProcessHacker/include/phapp.h | 9 +++++++++ ProcessHacker/log.c | 19 +++++++++++++++---- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/ProcessHacker/include/phapp.h b/ProcessHacker/include/phapp.h index aaf3ed2325b6..9c050d433bad 100644 --- a/ProcessHacker/include/phapp.h +++ b/ProcessHacker/include/phapp.h @@ -198,6 +198,15 @@ typedef struct _PH_LOG_ENTRY HANDLE ParentProcessId; PPH_STRING ParentName; NTSTATUS ExitStatus; + union + { + BOOLEAN Flags; + struct + { + BOOLEAN IsSubsystemProcess : 1; + BOOLEAN Spare : 7; + }; + }; } Process; struct { diff --git a/ProcessHacker/log.c b/ProcessHacker/log.c index a57862b1c614..e6188ca145d6 100644 --- a/ProcessHacker/log.c +++ b/ProcessHacker/log.c @@ -102,11 +102,12 @@ PPH_LOG_ENTRY PhpCreateProcessLogEntry( if (QueryHandle && entry->Type == PH_LOG_ENTRY_PROCESS_DELETE) { - PROCESS_BASIC_INFORMATION basicInfo; + PROCESS_EXTENDED_BASIC_INFORMATION basicInfo; - if (NT_SUCCESS(PhGetProcessBasicInformation(QueryHandle, &basicInfo))) + if (NT_SUCCESS(PhGetProcessExtendedBasicInformation(QueryHandle, &basicInfo))) { - entry->Process.ExitStatus = basicInfo.ExitStatus; + entry->Process.ExitStatus = basicInfo.BasicInfo.ExitStatus; + entry->Process.IsSubsystemProcess = !!basicInfo.IsSubsystemProcess; } } @@ -218,7 +219,17 @@ PPH_STRING PhFormatLogEntry( HandleToUlong(Entry->Process.ParentProcessId) ); case PH_LOG_ENTRY_PROCESS_DELETE: - return PhFormatString(L"Process terminated: %s (%u); exit status 0x%x", Entry->Process.Name->Buffer, HandleToUlong(Entry->Process.ProcessId), Entry->Process.ExitStatus); + { + ULONG exitstatus = 0; + + // The exit code for Linux processes is located in the lower 8-bits. + if (Entry->Process.IsSubsystemProcess) + exitstatus = Entry->Process.ExitStatus >> 8; + else + exitstatus = Entry->Process.ExitStatus; + + return PhFormatString(L"Process terminated: %s (%u); exit status 0x%x", Entry->Process.Name->Buffer, HandleToUlong(Entry->Process.ProcessId), exitstatus); + } case PH_LOG_ENTRY_SERVICE_CREATE: return PhFormatString(L"Service created: %s (%s)", Entry->Service.Name->Buffer, Entry->Service.DisplayName->Buffer); case PH_LOG_ENTRY_SERVICE_DELETE: From de5cac49c3a5ae9643acde1d684bbe5448fe801e Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 18 Aug 2017 01:07:40 +1000 Subject: [PATCH 0403/2058] ToolStatus: Update search for service verification columns --- plugins/ToolStatus/filter.c | 56 +++++++++++++++++++++++++++++++------ 1 file changed, 47 insertions(+), 9 deletions(-) diff --git a/plugins/ToolStatus/filter.c b/plugins/ToolStatus/filter.c index cd8a92ccd31c..8e0002aa3c85 100644 --- a/plugins/ToolStatus/filter.c +++ b/plugins/ToolStatus/filter.c @@ -332,11 +332,7 @@ BOOLEAN ProcessTreeFilterCallback( if (serviceItem->ProcessId) { - WCHAR processIdString[PH_INT32_STR_LEN_1]; - - PhPrintUInt32(processIdString, HandleToUlong(serviceItem->ProcessId)); - - if (WordMatchStringZ(processIdString)) + if (WordMatchStringZ(serviceItem->ProcessIdString)) { matched = TRUE; break; @@ -423,11 +419,8 @@ BOOLEAN ServiceTreeFilterCallback( if (serviceNode->ServiceItem->ProcessId) { PPH_PROCESS_NODE processNode; - WCHAR processIdString[PH_INT32_STR_LEN_1]; - PhPrintUInt32(processIdString, HandleToUlong(serviceNode->ServiceItem->ProcessId)); - - if (WordMatchStringZ(processIdString)) + if (WordMatchStringZ(serviceNode->ServiceItem->ProcessIdString)) return TRUE; // Search the process node @@ -438,6 +431,51 @@ BOOLEAN ServiceTreeFilterCallback( } } + if (!PhIsNullOrEmptyString(serviceNode->ServiceItem->VerifySignerName)) + { + if (WordMatchStringRef(&serviceNode->ServiceItem->VerifySignerName->sr)) + return TRUE; + } + + if (serviceNode->ServiceItem->VerifyResult != VrUnknown) + { + switch (serviceNode->ServiceItem->VerifyResult) + { + case VrNoSignature: + if (WordMatchStringZ(L"NoSignature")) + return TRUE; + break; + case VrTrusted: + if (WordMatchStringZ(L"Trusted")) + return TRUE; + break; + case VrExpired: + if (WordMatchStringZ(L"Expired")) + return TRUE; + break; + case VrRevoked: + if (WordMatchStringZ(L"Revoked")) + return TRUE; + break; + case VrDistrust: + if (WordMatchStringZ(L"Distrust")) + return TRUE; + break; + case VrSecuritySettings: + if (WordMatchStringZ(L"SecuritySettings")) + return TRUE; + break; + case VrBadSignature: + if (WordMatchStringZ(L"BadSignature")) + return TRUE; + break; + default: + if (WordMatchStringZ(L"Unknown")) + return TRUE; + break; + } + } + if (NT_SUCCESS(QueryServiceFileName( &serviceNode->ServiceItem->Name->sr, &serviceFileName, From ede96965ff07a58695a2efc341e4e1142a03684f Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 18 Aug 2017 03:44:42 +1000 Subject: [PATCH 0404/2058] Setup: Fix reset settings option --- tools/CustomSetupTool/CustomSetupTool/resource.h | 4 ++-- tools/CustomSetupTool/CustomSetupTool/resource.rc | 4 ++-- tools/CustomSetupTool/CustomSetupTool/setup.c | 1 - 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/tools/CustomSetupTool/CustomSetupTool/resource.h b/tools/CustomSetupTool/CustomSetupTool/resource.h index 5a7083fb3d6e..b27ddfceb9ec 100644 --- a/tools/CustomSetupTool/CustomSetupTool/resource.h +++ b/tools/CustomSetupTool/CustomSetupTool/resource.h @@ -29,8 +29,8 @@ #define IDC_INSTALL_STATUS 1064 #define IDC_INSTALL_DIRECTORY 1065 #define IDC_INSTALL_SUBSTATUS 1065 -#define IDC_RESET_CHECK 1066 -#define IDC_RESET_CHECK2 1067 +#define IDC_LATEST_NIGHTLY_CHECK 1066 +#define IDC_RESET_CHECK 1067 #define IDC_SHORTCUT_CHECK 1068 #define IDC_STATIC1 1069 #define IDC_STATIC2 1070 diff --git a/tools/CustomSetupTool/CustomSetupTool/resource.rc b/tools/CustomSetupTool/CustomSetupTool/resource.rc index e8ea912af48c..0989de87920b 100644 --- a/tools/CustomSetupTool/CustomSetupTool/resource.rc +++ b/tools/CustomSetupTool/CustomSetupTool/resource.rc @@ -105,10 +105,10 @@ BEGIN "Button",BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,20,176,168,10 CONTROL "Install KProcessHacker as a service",IDC_KPH_CHECK, "Button",BS_AUTOCHECKBOX | WS_TABSTOP,20,190,168,10 - CONTROL "Install latest nightly build (not recommended)",IDC_RESET_CHECK, + CONTROL "Install latest nightly build (not recommended)",IDC_LATEST_NIGHTLY_CHECK, "Button",BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,201,161,173,10 GROUPBOX "Installation Folder",IDC_STATIC1,10,43,380,40 - CONTROL "Reset Process Hacker settings",IDC_RESET_CHECK2,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,201,176,173,10 + CONTROL "Reset Process Hacker settings",IDC_RESET_CHECK,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,201,176,173,10 GROUPBOX "Additional Options",IDC_STATIC3,10,148,380,59 CONTROL "Start Process Hacker after setup exits",IDC_PHSTART_CHECK, "Button",BS_AUTOCHECKBOX | WS_TABSTOP,201,190,138,10 diff --git a/tools/CustomSetupTool/CustomSetupTool/setup.c b/tools/CustomSetupTool/CustomSetupTool/setup.c index 810433cc85dc..9933ad96a515 100644 --- a/tools/CustomSetupTool/CustomSetupTool/setup.c +++ b/tools/CustomSetupTool/CustomSetupTool/setup.c @@ -384,7 +384,6 @@ VOID SetupStopService( } } - VOID SetupStartKph( _In_ PPH_SETUP_CONTEXT Context ) From a9e1af86262f51724f6c5317353020af3c3ff20b Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 18 Aug 2017 04:20:05 +1000 Subject: [PATCH 0405/2058] Improve commit 398040837b840beea801099a28511ef1e0979871 --- ProcessHacker/include/phapp.h | 9 --------- ProcessHacker/log.c | 19 ++++++------------- 2 files changed, 6 insertions(+), 22 deletions(-) diff --git a/ProcessHacker/include/phapp.h b/ProcessHacker/include/phapp.h index 9c050d433bad..aaf3ed2325b6 100644 --- a/ProcessHacker/include/phapp.h +++ b/ProcessHacker/include/phapp.h @@ -198,15 +198,6 @@ typedef struct _PH_LOG_ENTRY HANDLE ParentProcessId; PPH_STRING ParentName; NTSTATUS ExitStatus; - union - { - BOOLEAN Flags; - struct - { - BOOLEAN IsSubsystemProcess : 1; - BOOLEAN Spare : 7; - }; - }; } Process; struct { diff --git a/ProcessHacker/log.c b/ProcessHacker/log.c index e6188ca145d6..36fc243b5307 100644 --- a/ProcessHacker/log.c +++ b/ProcessHacker/log.c @@ -106,8 +106,11 @@ PPH_LOG_ENTRY PhpCreateProcessLogEntry( if (NT_SUCCESS(PhGetProcessExtendedBasicInformation(QueryHandle, &basicInfo))) { - entry->Process.ExitStatus = basicInfo.BasicInfo.ExitStatus; - entry->Process.IsSubsystemProcess = !!basicInfo.IsSubsystemProcess; + // The exit code for Linux processes is located in the lower 8-bits. + if (basicInfo.IsSubsystemProcess) + entry->Process.ExitStatus = basicInfo.BasicInfo.ExitStatus >> 8; + else + entry->Process.ExitStatus = basicInfo.BasicInfo.ExitStatus; } } @@ -219,17 +222,7 @@ PPH_STRING PhFormatLogEntry( HandleToUlong(Entry->Process.ParentProcessId) ); case PH_LOG_ENTRY_PROCESS_DELETE: - { - ULONG exitstatus = 0; - - // The exit code for Linux processes is located in the lower 8-bits. - if (Entry->Process.IsSubsystemProcess) - exitstatus = Entry->Process.ExitStatus >> 8; - else - exitstatus = Entry->Process.ExitStatus; - - return PhFormatString(L"Process terminated: %s (%u); exit status 0x%x", Entry->Process.Name->Buffer, HandleToUlong(Entry->Process.ProcessId), exitstatus); - } + return PhFormatString(L"Process terminated: %s (%u); exit status 0x%x", Entry->Process.Name->Buffer, HandleToUlong(Entry->Process.ProcessId), Entry->Process.ExitStatus); case PH_LOG_ENTRY_SERVICE_CREATE: return PhFormatString(L"Service created: %s (%s)", Entry->Service.Name->Buffer, Entry->Service.DisplayName->Buffer); case PH_LOG_ENTRY_SERVICE_DELETE: From 6d21ed170538f82f7803386708369260c8cfa10f Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 20 Aug 2017 13:53:15 +1000 Subject: [PATCH 0406/2058] Add service tab highlighting, Add UseColorServiceStop/UseColorUnknown settings for service highlighting --- ProcessHacker/include/phsettings.h | 7 +++++++ ProcessHacker/include/procprv.h | 1 - ProcessHacker/mainwnd.c | 1 - ProcessHacker/modlist.c | 4 ++-- ProcessHacker/modprv.c | 1 + ProcessHacker/procprv.c | 1 - ProcessHacker/settings.c | 19 ++++++++++++++++--- ProcessHacker/srvlist.c | 21 +++++++++++++++++++++ ProcessHacker/srvprv.c | 1 + 9 files changed, 48 insertions(+), 8 deletions(-) diff --git a/ProcessHacker/include/phsettings.h b/ProcessHacker/include/phsettings.h index 4f79cc7a69eb..653bab459e98 100644 --- a/ProcessHacker/include/phsettings.h +++ b/ProcessHacker/include/phsettings.h @@ -11,6 +11,8 @@ #define EXT extern #endif +EXT BOOLEAN PhEnableProcessQueryStage2; + EXT ULONG PhCsCollapseServicesOnStart; EXT ULONG PhCsForceNoParent; EXT ULONG PhCsHighlightingDuration; @@ -63,6 +65,11 @@ EXT ULONG PhCsColorIoWrite; EXT ULONG PhCsColorPrivate; EXT ULONG PhCsColorPhysical; +EXT ULONG PhCsUseColorUnknown; +EXT ULONG PhCsColorUnknown; +EXT ULONG PhCsUseColorServiceStop; +EXT ULONG PhCsColorServiceStop; + #define PH_SET_INTEGER_CACHED_SETTING(Name, Value) (PhSetIntegerSetting(L#Name, PhCs##Name = (Value))) #endif diff --git a/ProcessHacker/include/procprv.h b/ProcessHacker/include/procprv.h index f79546f534fd..c3d6b7dd7130 100644 --- a/ProcessHacker/include/procprv.h +++ b/ProcessHacker/include/procprv.h @@ -15,7 +15,6 @@ extern PPH_LIST PhProcessRecordList; extern PH_QUEUED_LOCK PhProcessRecordListLock; extern ULONG PhStatisticsSampleCount; -extern BOOLEAN PhEnableProcessQueryStage2; extern BOOLEAN PhEnablePurgeProcessRecords; extern BOOLEAN PhEnableCycleCpuUsage; diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index c8648aa0997e..a9469a78eeb7 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -2248,7 +2248,6 @@ VOID PhMwpLoadSettings( PhSetWindowOpacity(PhMainWndHandle, opacity); PhStatisticsSampleCount = PhGetIntegerSetting(L"SampleCount"); - PhEnableProcessQueryStage2 = !!PhGetIntegerSetting(L"EnableStage2"); PhEnablePurgeProcessRecords = !PhGetIntegerSetting(L"NoPurgeProcessRecords"); PhEnableCycleCpuUsage = !!PhGetIntegerSetting(L"EnableCycleCpuUsage"); PhEnableServiceNonPoll = !!PhGetIntegerSetting(L"EnableServiceNonPoll"); diff --git a/ProcessHacker/modlist.c b/ProcessHacker/modlist.c index 2b4285549d63..a72a167d1f60 100644 --- a/ProcessHacker/modlist.c +++ b/ProcessHacker/modlist.c @@ -882,8 +882,8 @@ BOOLEAN NTAPI PhpModuleTreeNewCallback( if (!moduleItem) ; // Dummy - else if (context->HighlightUntrustedModules && moduleItem->VerifyResult != VrTrusted) - getNodeColor->BackColor = PhCsColorPacked; + else if (PhEnableProcessQueryStage2 && context->HighlightUntrustedModules && moduleItem->VerifyResult != VrTrusted) + getNodeColor->BackColor = PhCsColorUnknown; else if (context->HighlightDotNetModules && (moduleItem->Flags & LDRP_COR_IMAGE)) getNodeColor->BackColor = PhCsColorDotNet; else if (context->HighlightImmersiveModules && (moduleItem->ImageDllCharacteristics & IMAGE_DLLCHARACTERISTICS_APPCONTAINER)) diff --git a/ProcessHacker/modprv.c b/ProcessHacker/modprv.c index 659774544dbd..0a507b872a4f 100644 --- a/ProcessHacker/modprv.c +++ b/ProcessHacker/modprv.c @@ -29,6 +29,7 @@ #include #include +#include typedef struct _PH_MODULE_QUERY_DATA { diff --git a/ProcessHacker/procprv.c b/ProcessHacker/procprv.c index c30b5412d012..e4d2bdb48893 100644 --- a/ProcessHacker/procprv.c +++ b/ProcessHacker/procprv.c @@ -189,7 +189,6 @@ PPH_LIST PhProcessRecordList; PH_QUEUED_LOCK PhProcessRecordListLock = PH_QUEUED_LOCK_INIT; ULONG PhStatisticsSampleCount = 512; -BOOLEAN PhEnableProcessQueryStage2 = FALSE; BOOLEAN PhEnablePurgeProcessRecords = TRUE; BOOLEAN PhEnableCycleCpuUsage = TRUE; diff --git a/ProcessHacker/settings.c b/ProcessHacker/settings.c index 86a97ee41548..51439a7eecf7 100644 --- a/ProcessHacker/settings.c +++ b/ProcessHacker/settings.c @@ -26,6 +26,9 @@ #define PH_SETTINGS_PRIVATE #include +#define PH_UPDATE_SETTING(Name) \ + (PhCs##Name = PhGetIntegerSetting(L#Name)) + VOID PhAddDefaultSettings( VOID ) @@ -202,14 +205,19 @@ VOID PhAddDefaultSettings( PhpAddIntegerSetting(L"ColorIoWrite", L"ff0077"); PhpAddIntegerSetting(L"ColorPrivate", L"0077ff"); PhpAddIntegerSetting(L"ColorPhysical", L"ffff00"); + + PhpAddIntegerSetting(L"UseColorServiceStop", L"1"); + PhpAddIntegerSetting(L"ColorServiceStop", L"6d6d6d"); // Dark grey + PhpAddIntegerSetting(L"UseColorUnknown", L"1"); + PhpAddIntegerSetting(L"ColorUnknown", L"507fff"); // Deep Pink } VOID PhUpdateCachedSettings( VOID ) { - #define PH_UPDATE_SETTING(Name) (PhCs##Name = PhGetIntegerSetting(L#Name)) - + PhEnableProcessQueryStage2 = !!PhGetIntegerSetting(L"EnableStage2"); + PH_UPDATE_SETTING(CollapseServicesOnStart); PH_UPDATE_SETTING(ForceNoParent); PH_UPDATE_SETTING(HighlightingDuration); @@ -260,4 +268,9 @@ VOID PhUpdateCachedSettings( PH_UPDATE_SETTING(ColorIoWrite); PH_UPDATE_SETTING(ColorPrivate); PH_UPDATE_SETTING(ColorPhysical); -} \ No newline at end of file + + PH_UPDATE_SETTING(UseColorServiceStop); + PH_UPDATE_SETTING(ColorServiceStop); + PH_UPDATE_SETTING(UseColorUnknown); + PH_UPDATE_SETTING(ColorUnknown); +} diff --git a/ProcessHacker/srvlist.c b/ProcessHacker/srvlist.c index 4f85a62bda1d..2bf336cb4a26 100644 --- a/ProcessHacker/srvlist.c +++ b/ProcessHacker/srvlist.c @@ -743,6 +743,27 @@ BOOLEAN NTAPI PhpServiceTreeNewCallback( getNodeIcon->Flags = TN_CACHE; } return TRUE; + case TreeNewGetNodeColor: + { + PPH_TREENEW_GET_NODE_COLOR getNodeColor = Parameter1; + PPH_SERVICE_ITEM serviceItem; + + node = (PPH_SERVICE_NODE)getNodeColor->Node; + serviceItem = node->ServiceItem; + + if (!serviceItem) + ; // Dummy + else if (PhEnableProcessQueryStage2 && PhCsUseColorUnknown && serviceItem->VerifyResult != VrTrusted) + { + getNodeColor->Flags = TN_AUTO_FORECOLOR; + getNodeColor->BackColor = PhCsColorUnknown; + } + else if (PhCsUseColorServiceStop && serviceItem->State == SERVICE_STOPPED) + { + getNodeColor->ForeColor = PhCsColorServiceStop; + } + } + return TRUE; case TreeNewGetCellTooltip: { PPH_TREENEW_GET_CELL_TOOLTIP getCellTooltip = Parameter1; diff --git a/ProcessHacker/srvprv.c b/ProcessHacker/srvprv.c index 826bdfc48796..c4f1238460cf 100644 --- a/ProcessHacker/srvprv.c +++ b/ProcessHacker/srvprv.c @@ -30,6 +30,7 @@ #include #include +#include typedef struct _PHP_SERVICE_NAME_ENTRY { From 0a9e0bbf770fc614dfcc397fa99f1ccbefe0f0ef Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 20 Aug 2017 14:33:28 +1000 Subject: [PATCH 0407/2058] Add filename column to process properties service tab --- ProcessHacker/srvctl.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/ProcessHacker/srvctl.c b/ProcessHacker/srvctl.c index a53d1f769498..8b122289a3ff 100644 --- a/ProcessHacker/srvctl.c +++ b/ProcessHacker/srvctl.c @@ -242,17 +242,32 @@ INT_PTR CALLBACK PhpServicesPageProc( PhSetControlTheme(lvHandle, L"explorer"); PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 120, L"Name"); PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 220, L"Display name"); + PhAddListViewColumn(lvHandle, 2, 2, 2, LVCFMT_LEFT, 220, L"File name"); PhSetExtendedListView(lvHandle); for (i = 0; i < servicesContext->NumberOfServices; i++) { + SC_HANDLE serviceHandle; PPH_SERVICE_ITEM serviceItem; INT lvItemIndex; serviceItem = servicesContext->Services[i]; lvItemIndex = PhAddListViewItem(lvHandle, MAXINT, serviceItem->Name->Buffer, serviceItem); PhSetListViewSubItem(lvHandle, lvItemIndex, 1, serviceItem->DisplayName->Buffer); + + if (serviceHandle = PhOpenService(serviceItem->Name->Buffer, SERVICE_QUERY_CONFIG)) + { + PPH_STRING fileName; + + if (fileName = PhGetServiceRelevantFileName(&serviceItem->Name->sr, serviceHandle)) + { + PhSetListViewSubItem(lvHandle, lvItemIndex, 2, PhGetStringOrEmpty(fileName)); + PhDereferenceObject(fileName); + } + + CloseServiceHandle(serviceHandle); + } } ExtendedListView_SortItems(lvHandle); From 77a2f2441bf21e6038e9ff04c999c5f449f86d1f Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 20 Aug 2017 15:14:02 +1000 Subject: [PATCH 0408/2058] Add options window callback --- ProcessHacker/include/phplug.h | 1 + ProcessHacker/options.c | 17 +++++++++- plugins/ExtendedTools/ExtendedTools.rc | 1 - plugins/ExtendedTools/exttools.h | 7 ++-- plugins/ExtendedTools/main.c | 18 +++++++++-- plugins/ExtendedTools/options.c | 44 +++----------------------- 6 files changed, 41 insertions(+), 47 deletions(-) diff --git a/ProcessHacker/include/phplug.h b/ProcessHacker/include/phplug.h index 68ea5602ede1..22746056c982 100644 --- a/ProcessHacker/include/phplug.h +++ b/ProcessHacker/include/phplug.h @@ -44,6 +44,7 @@ typedef enum _PH_GENERAL_CALLBACK GeneralCallbackMemoryItemListControl = 31, // PPH_PLUGIN_MEMORY_ITEM_LIST_CONTROL Data [properties thread] GeneralCallbackMiniInformationInitializing = 32, // PPH_PLUGIN_MINIINFO_POINTERS Data [main thread] GeneralCallbackMiListSectionMenuInitializing = 33, // PPH_PLUGIN_MENU_INFORMATION Data [main thread] + GeneralCallbackOptionsWindowInitializing, // PPH_PLUGIN_OBJECT_PROPERTIES Data [main thread] GeneralCallbackMaximum } PH_GENERAL_CALLBACK, *PPH_GENERAL_CALLBACK; diff --git a/ProcessHacker/options.c b/ProcessHacker/options.c index 0c5ea7c7f833..8eebf0135ca6 100644 --- a/ProcessHacker/options.c +++ b/ProcessHacker/options.c @@ -31,6 +31,7 @@ #include #include +#include #include #include @@ -114,7 +115,7 @@ VOID PhShowOptionsDialog( { PROPSHEETHEADER propSheetHeader = { sizeof(propSheetHeader) }; PROPSHEETPAGE propSheetPage; - HPROPSHEETPAGE pages[5]; + HPROPSHEETPAGE pages[30]; propSheetHeader.dwFlags = PSH_NOAPPLYNOW | @@ -182,6 +183,20 @@ VOID PhShowOptionsDialog( pages[propSheetHeader.nPages++] = CreatePropertySheetPage(&propSheetPage); } + if (PhPluginsEnabled) + { + PH_PLUGIN_OBJECT_PROPERTIES objectProperties; + + //objectProperties.Parameter = RestartRequired; + objectProperties.NumberOfPages = propSheetHeader.nPages; + objectProperties.MaximumNumberOfPages = sizeof(pages) / sizeof(HPROPSHEETPAGE); + objectProperties.Pages = pages; + + PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackOptionsWindowInitializing), &objectProperties); + + propSheetHeader.nPages = objectProperties.NumberOfPages; + } + PageInit = FALSE; PressedOk = FALSE; RestartRequired = FALSE; diff --git a/plugins/ExtendedTools/ExtendedTools.rc b/plugins/ExtendedTools/ExtendedTools.rc index 6535eaeda856..ca97a242e353 100644 --- a/plugins/ExtendedTools/ExtendedTools.rc +++ b/plugins/ExtendedTools/ExtendedTools.rc @@ -158,7 +158,6 @@ BEGIN CONTROL "Enable Disk and Network monitoring",IDC_ENABLEETWMONITOR, "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,20,130,10 CONTROL "Enable GPU monitoring",IDC_ENABLEGPUMONITOR,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,46,88,10 - PUSHBUTTON "Close",IDOK,158,56,50,14 CONTROL "Enable Disk and Network graphs",IDC_ENABLESYSINFOGRAPHS, "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,33,130,10 END diff --git a/plugins/ExtendedTools/exttools.h b/plugins/ExtendedTools/exttools.h index c5201b3fabc5..410615b3d068 100644 --- a/plugins/ExtendedTools/exttools.h +++ b/plugins/ExtendedTools/exttools.h @@ -524,8 +524,11 @@ VOID EtHandlePropertiesInitializing( // options -VOID EtShowOptionsDialog( - _In_ HWND ParentWindowHandle +INT_PTR CALLBACK OptionsDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam ); // thrdact diff --git a/plugins/ExtendedTools/main.c b/plugins/ExtendedTools/main.c index 22c279729158..69de3fdacb2f 100644 --- a/plugins/ExtendedTools/main.c +++ b/plugins/ExtendedTools/main.c @@ -72,7 +72,20 @@ VOID NTAPI ShowOptionsCallback( _In_opt_ PVOID Context ) { - EtShowOptionsDialog((HWND)Parameter); + PPH_PLUGIN_OBJECT_PROPERTIES objectProperties = Parameter; + PROPSHEETPAGE propSheetPage; + + if (objectProperties->NumberOfPages < objectProperties->MaximumNumberOfPages) + { + memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); + propSheetPage.dwSize = sizeof(PROPSHEETPAGE); + propSheetPage.dwFlags = PSP_USETITLE; + propSheetPage.hInstance = PluginInstance->DllBase; + propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_OPTIONS); + propSheetPage.pszTitle = L"ExtendedTools"; + propSheetPage.pfnDlgProc = OptionsDlgProc; + objectProperties->Pages[objectProperties->NumberOfPages++] = CreatePropertySheetPage(&propSheetPage); + } } VOID NTAPI MenuItemCallback( @@ -470,7 +483,6 @@ LOGICAL DllMain( info->Author = L"wj32"; info->Description = L"Extended functionality for Windows 7 and above, including ETW monitoring, GPU monitoring and a Disk tab."; info->Url = L"https://wj32.org/processhacker/forums/viewtopic.php?t=1114"; - info->HasOptions = TRUE; PhRegisterCallback( PhGetPluginCallback(PluginInstance, PluginCallbackLoad), @@ -485,7 +497,7 @@ LOGICAL DllMain( &PluginUnloadCallbackRegistration ); PhRegisterCallback( - PhGetPluginCallback(PluginInstance, PluginCallbackShowOptions), + PhGetGeneralCallback(GeneralCallbackOptionsWindowInitializing), ShowOptionsCallback, NULL, &PluginShowOptionsCallbackRegistration diff --git a/plugins/ExtendedTools/options.c b/plugins/ExtendedTools/options.c index cd4c21e63b7d..0b9c5b36b0fa 100644 --- a/plugins/ExtendedTools/options.c +++ b/plugins/ExtendedTools/options.c @@ -22,25 +22,6 @@ #include "exttools.h" -INT_PTR CALLBACK OptionsDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -VOID EtShowOptionsDialog( - _In_ HWND ParentWindowHandle - ) -{ - DialogBox( - PluginInstance->DllBase, - MAKEINTRESOURCE(IDD_OPTIONS), - ParentWindowHandle, - OptionsDlgProc - ); -} - INT_PTR CALLBACK OptionsDlgProc( _In_ HWND hwndDlg, _In_ UINT uMsg, @@ -52,33 +33,16 @@ INT_PTR CALLBACK OptionsDlgProc( { case WM_INITDIALOG: { - PhCenterWindow(hwndDlg, GetParent(hwndDlg)); - Button_SetCheck(GetDlgItem(hwndDlg, IDC_ENABLEETWMONITOR), PhGetIntegerSetting(SETTING_NAME_ENABLE_ETW_MONITOR) ? BST_CHECKED : BST_UNCHECKED); Button_SetCheck(GetDlgItem(hwndDlg, IDC_ENABLEGPUMONITOR), PhGetIntegerSetting(SETTING_NAME_ENABLE_GPU_MONITOR) ? BST_CHECKED : BST_UNCHECKED); Button_SetCheck(GetDlgItem(hwndDlg, IDC_ENABLESYSINFOGRAPHS), PhGetIntegerSetting(SETTING_NAME_ENABLE_SYSINFO_GRAPHS) ? BST_CHECKED : BST_UNCHECKED); } break; - case WM_COMMAND: + case WM_DESTROY: { - switch (GET_WM_COMMAND_ID(wParam, lParam)) - { - case IDCANCEL: - EndDialog(hwndDlg, IDCANCEL); - break; - case IDOK: - { - PhSetIntegerSetting(SETTING_NAME_ENABLE_ETW_MONITOR, - Button_GetCheck(GetDlgItem(hwndDlg, IDC_ENABLEETWMONITOR)) == BST_CHECKED); - PhSetIntegerSetting(SETTING_NAME_ENABLE_GPU_MONITOR, - Button_GetCheck(GetDlgItem(hwndDlg, IDC_ENABLEGPUMONITOR)) == BST_CHECKED); - PhSetIntegerSetting(SETTING_NAME_ENABLE_SYSINFO_GRAPHS, - Button_GetCheck(GetDlgItem(hwndDlg, IDC_ENABLESYSINFOGRAPHS)) == BST_CHECKED); - - EndDialog(hwndDlg, IDOK); - } - break; - } + PhSetIntegerSetting(SETTING_NAME_ENABLE_ETW_MONITOR, Button_GetCheck(GetDlgItem(hwndDlg, IDC_ENABLEETWMONITOR)) == BST_CHECKED); + PhSetIntegerSetting(SETTING_NAME_ENABLE_GPU_MONITOR, Button_GetCheck(GetDlgItem(hwndDlg, IDC_ENABLEGPUMONITOR)) == BST_CHECKED); + PhSetIntegerSetting(SETTING_NAME_ENABLE_SYSINFO_GRAPHS, Button_GetCheck(GetDlgItem(hwndDlg, IDC_ENABLESYSINFOGRAPHS)) == BST_CHECKED); } break; } From 464a628d086dce5783ab7195837fb9880b69cc14 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 20 Aug 2017 15:26:12 +1000 Subject: [PATCH 0409/2058] Move (some) plugin dialogs to options window (also add missing files from previous commit) --- plugins/ExtendedServices/ExtendedServices.rc | 7 ++- plugins/ExtendedServices/extsrv.h | 7 ++- plugins/ExtendedServices/main.c | 18 +++++-- plugins/ExtendedServices/options.c | 31 +---------- plugins/NetworkTools/main.c | 15 +++++- plugins/NetworkTools/nettools.h | 7 ++- plugins/NetworkTools/options.c | 32 ++--------- plugins/OnlineChecks/OnlineChecks.rc | 5 +- plugins/OnlineChecks/main.c | 18 +++++-- plugins/OnlineChecks/onlnchk.h | 9 +++- plugins/OnlineChecks/options.c | 29 ++-------- plugins/ToolStatus/ToolStatus.rc | 5 +- plugins/ToolStatus/main.c | 18 +++++-- plugins/ToolStatus/options.c | 56 ++++++-------------- plugins/ToolStatus/toolstatus.h | 7 ++- plugins/Updater/Updater.rc | 7 ++- plugins/Updater/main.c | 18 +++++-- plugins/Updater/options.c | 16 +----- plugins/Updater/updater.h | 7 ++- 19 files changed, 135 insertions(+), 177 deletions(-) diff --git a/plugins/ExtendedServices/ExtendedServices.rc b/plugins/ExtendedServices/ExtendedServices.rc index 82d6e9477509..8c2bd9083285 100644 --- a/plugins/ExtendedServices/ExtendedServices.rc +++ b/plugins/ExtendedServices/ExtendedServices.rc @@ -177,14 +177,13 @@ BEGIN PUSHBUTTON "Remove",IDC_REMOVE,225,171,50,14 END -IDD_OPTIONS DIALOGEX 0, 0, 215, 54 +IDD_OPTIONS DIALOGEX 0, 0, 167, 33 STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Options" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN CONTROL "Enable Services submenu for processes",IDC_ENABLESERVICESMENU, "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,7,142,10 - PUSHBUTTON "Close",IDOK,158,33,50,14 END IDD_SRVTRIGGER DIALOGEX 0, 0, 330, 196 @@ -290,9 +289,9 @@ BEGIN IDD_OPTIONS, DIALOG BEGIN LEFTMARGIN, 7 - RIGHTMARGIN, 208 + RIGHTMARGIN, 160 TOPMARGIN, 7 - BOTTOMMARGIN, 47 + BOTTOMMARGIN, 26 END IDD_SRVTRIGGER, DIALOG diff --git a/plugins/ExtendedServices/extsrv.h b/plugins/ExtendedServices/extsrv.h index 2a15f62d44fe..6459073e14c5 100644 --- a/plugins/ExtendedServices/extsrv.h +++ b/plugins/ExtendedServices/extsrv.h @@ -40,8 +40,11 @@ INT_PTR CALLBACK EspServiceDependentsDlgProc( // options -VOID EsShowOptionsDialog( - _In_ HWND ParentWindowHandle +INT_PTR CALLBACK OptionsDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam ); // other diff --git a/plugins/ExtendedServices/main.c b/plugins/ExtendedServices/main.c index af0e8f012988..7bac8fd61502 100644 --- a/plugins/ExtendedServices/main.c +++ b/plugins/ExtendedServices/main.c @@ -43,7 +43,20 @@ VOID NTAPI ShowOptionsCallback( _In_opt_ PVOID Context ) { - EsShowOptionsDialog((HWND)Parameter); + PPH_PLUGIN_OBJECT_PROPERTIES objectProperties = Parameter; + PROPSHEETPAGE propSheetPage; + + if (objectProperties->NumberOfPages < objectProperties->MaximumNumberOfPages) + { + memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); + propSheetPage.dwSize = sizeof(PROPSHEETPAGE); + propSheetPage.dwFlags = PSP_USETITLE; + propSheetPage.hInstance = PluginInstance->DllBase; + propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_OPTIONS); + propSheetPage.pszTitle = L"ExtendedServices"; + propSheetPage.pfnDlgProc = OptionsDlgProc; + objectProperties->Pages[objectProperties->NumberOfPages++] = CreatePropertySheetPage(&propSheetPage); + } } VOID NTAPI MenuItemCallback( @@ -432,7 +445,6 @@ LOGICAL DllMain( info->Author = L"wj32"; info->Description = L"Extends service management capabilities."; info->Url = L"https://wj32.org/processhacker/forums/viewtopic.php?t=1113"; - info->HasOptions = TRUE; PhRegisterCallback( PhGetPluginCallback(PluginInstance, PluginCallbackLoad), @@ -441,7 +453,7 @@ LOGICAL DllMain( &PluginLoadCallbackRegistration ); PhRegisterCallback( - PhGetPluginCallback(PluginInstance, PluginCallbackShowOptions), + PhGetGeneralCallback(GeneralCallbackOptionsWindowInitializing), ShowOptionsCallback, NULL, &PluginShowOptionsCallbackRegistration diff --git a/plugins/ExtendedServices/options.c b/plugins/ExtendedServices/options.c index 019bfbd32dff..c9bf6e7027cd 100644 --- a/plugins/ExtendedServices/options.c +++ b/plugins/ExtendedServices/options.c @@ -33,42 +33,15 @@ INT_PTR CALLBACK OptionsDlgProc( { case WM_INITDIALOG: { - PhCenterWindow(hwndDlg, GetParent(hwndDlg)); - Button_SetCheck(GetDlgItem(hwndDlg, IDC_ENABLESERVICESMENU), PhGetIntegerSetting(SETTING_NAME_ENABLE_SERVICES_MENU) ? BST_CHECKED : BST_UNCHECKED); } break; - case WM_COMMAND: + case WM_DESTROY: { - switch (GET_WM_COMMAND_ID(wParam, lParam)) - { - case IDCANCEL: - EndDialog(hwndDlg, IDCANCEL); - break; - case IDOK: - { - PhSetIntegerSetting(SETTING_NAME_ENABLE_SERVICES_MENU, - Button_GetCheck(GetDlgItem(hwndDlg, IDC_ENABLESERVICESMENU)) == BST_CHECKED); - - EndDialog(hwndDlg, IDOK); - } - break; - } + PhSetIntegerSetting(SETTING_NAME_ENABLE_SERVICES_MENU, Button_GetCheck(GetDlgItem(hwndDlg, IDC_ENABLESERVICESMENU)) == BST_CHECKED); } break; } return FALSE; } - -VOID EsShowOptionsDialog( - _In_ HWND ParentWindowHandle - ) -{ - DialogBox( - PluginInstance->DllBase, - MAKEINTRESOURCE(IDD_OPTIONS), - ParentWindowHandle, - OptionsDlgProc - ); -} \ No newline at end of file diff --git a/plugins/NetworkTools/main.c b/plugins/NetworkTools/main.c index fa5dc23efcc1..dbe747ba1e35 100644 --- a/plugins/NetworkTools/main.c +++ b/plugins/NetworkTools/main.c @@ -47,7 +47,20 @@ VOID NTAPI ShowOptionsCallback( _In_opt_ PVOID Context ) { - ShowOptionsDialog((HWND)Parameter); + PPH_PLUGIN_OBJECT_PROPERTIES objectProperties = Parameter; + PROPSHEETPAGE propSheetPage; + + if (objectProperties->NumberOfPages < objectProperties->MaximumNumberOfPages) + { + memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); + propSheetPage.dwSize = sizeof(PROPSHEETPAGE); + propSheetPage.dwFlags = PSP_USETITLE; + propSheetPage.hInstance = PluginInstance->DllBase; + propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_OPTIONS); + propSheetPage.pszTitle = L"NetworkTools"; + propSheetPage.pfnDlgProc = OptionsDlgProc; + objectProperties->Pages[objectProperties->NumberOfPages++] = CreatePropertySheetPage(&propSheetPage); + } } static BOOLEAN ValidAddressInfo( diff --git a/plugins/NetworkTools/nettools.h b/plugins/NetworkTools/nettools.h index b636a0bc7091..45e04b181b29 100644 --- a/plugins/NetworkTools/nettools.h +++ b/plugins/NetworkTools/nettools.h @@ -201,8 +201,11 @@ VOID ShowTracertWindowFromAddress( // options.c -VOID ShowOptionsDialog( - _In_opt_ HWND Parent +INT_PTR CALLBACK OptionsDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam ); // country.c diff --git a/plugins/NetworkTools/options.c b/plugins/NetworkTools/options.c index caa320ccf068..accb0a4ece4d 100644 --- a/plugins/NetworkTools/options.c +++ b/plugins/NetworkTools/options.c @@ -34,43 +34,17 @@ INT_PTR CALLBACK OptionsDlgProc( { case WM_INITDIALOG: { - PhCenterWindow(hwndDlg, GetParent(hwndDlg)); - SetDlgItemInt(hwndDlg, IDC_PINGPACKETLENGTH, PhGetIntegerSetting(SETTING_NAME_PING_SIZE), FALSE); SetDlgItemInt(hwndDlg, IDC_MAXHOPS, PhGetIntegerSetting(SETTING_NAME_TRACERT_MAX_HOPS), FALSE); } break; - case WM_COMMAND: + case WM_DESTROY: { - switch (GET_WM_COMMAND_ID(wParam, lParam)) - { - case IDCANCEL: - { - PhSetIntegerSetting(SETTING_NAME_PING_SIZE, GetDlgItemInt(hwndDlg, IDC_PINGPACKETLENGTH, NULL, FALSE)); - PhSetIntegerSetting(SETTING_NAME_TRACERT_MAX_HOPS, GetDlgItemInt(hwndDlg, IDC_MAXHOPS, NULL, FALSE)); - - EndDialog(hwndDlg, IDCANCEL); - } - break; - case IDC_GEOIP: - ShowGeoIPUpdateDialog(NULL); - break; - } + PhSetIntegerSetting(SETTING_NAME_PING_SIZE, GetDlgItemInt(hwndDlg, IDC_PINGPACKETLENGTH, NULL, FALSE)); + PhSetIntegerSetting(SETTING_NAME_TRACERT_MAX_HOPS, GetDlgItemInt(hwndDlg, IDC_MAXHOPS, NULL, FALSE)); } break; } return FALSE; } - -VOID ShowOptionsDialog( - _In_opt_ HWND Parent - ) -{ - DialogBox( - PluginInstance->DllBase, - MAKEINTRESOURCE(IDD_OPTIONS), - (HWND)Parent, - OptionsDlgProc - ); -} \ No newline at end of file diff --git a/plugins/OnlineChecks/OnlineChecks.rc b/plugins/OnlineChecks/OnlineChecks.rc index 650d108605a9..0cdef0b36dac 100644 --- a/plugins/OnlineChecks/OnlineChecks.rc +++ b/plugins/OnlineChecks/OnlineChecks.rc @@ -87,7 +87,7 @@ END // Dialog // -IDD_OPTIONS DIALOGEX 0, 0, 185, 103 +IDD_OPTIONS DIALOGEX 0, 0, 185, 87 STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Options" FONT 8, "MS Shell Dlg", 400, 0, 0x1 @@ -96,7 +96,6 @@ BEGIN "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,7,101,10 CONTROL "Enable VirusTotal detection highlighting",IDC_ENABLE_IDC_ENABLE_VIRUSTOTAL_HIGHLIGHT, "Button",BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,7,20,141,10 - PUSHBUTTON "Close",IDCANCEL,129,82,50,14 CONTROL "Enable detection actions",IDC_CHECK1,"Button",BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,7,34,94,10 EDITTEXT IDC_EDIT1,91,47,37,14,ES_AUTOHSCROLL | WS_DISABLED LTEXT "Minimum detection ratio:",IDC_STATIC,8,50,79,8 @@ -118,7 +117,7 @@ BEGIN LEFTMARGIN, 7 RIGHTMARGIN, 179 TOPMARGIN, 7 - BOTTOMMARGIN, 96 + BOTTOMMARGIN, 80 END END #endif // APSTUDIO_INVOKED diff --git a/plugins/OnlineChecks/main.c b/plugins/OnlineChecks/main.c index 502d5cf853f8..166785835989 100644 --- a/plugins/OnlineChecks/main.c +++ b/plugins/OnlineChecks/main.c @@ -150,7 +150,20 @@ VOID NTAPI ShowOptionsCallback( _In_opt_ PVOID Context ) { - ShowOptionsDialog((HWND)Parameter); + PPH_PLUGIN_OBJECT_PROPERTIES objectProperties = Parameter; + PROPSHEETPAGE propSheetPage; + + if (objectProperties->NumberOfPages < objectProperties->MaximumNumberOfPages) + { + memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); + propSheetPage.dwSize = sizeof(PROPSHEETPAGE); + propSheetPage.dwFlags = PSP_USETITLE; + propSheetPage.hInstance = PluginInstance->DllBase; + propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_OPTIONS); + propSheetPage.pszTitle = L"OnlineChecks"; + propSheetPage.pfnDlgProc = OptionsDlgProc; + objectProperties->Pages[objectProperties->NumberOfPages++] = CreatePropertySheetPage(&propSheetPage); + } } VOID NTAPI MenuItemCallback( @@ -724,7 +737,6 @@ LOGICAL DllMain( info->Author = L"dmex, wj32"; info->Description = L"Allows files to be checked with online services."; info->Url = L"https://wj32.org/processhacker/forums/viewtopic.php?t=1118"; - info->HasOptions = TRUE; PhRegisterCallback( PhGetPluginCallback(PluginInstance, PluginCallbackLoad), @@ -733,7 +745,7 @@ LOGICAL DllMain( &PluginLoadCallbackRegistration ); PhRegisterCallback( - PhGetPluginCallback(PluginInstance, PluginCallbackShowOptions), + PhGetGeneralCallback(GeneralCallbackOptionsWindowInitializing), ShowOptionsCallback, NULL, &PluginShowOptionsCallbackRegistration diff --git a/plugins/OnlineChecks/onlnchk.h b/plugins/OnlineChecks/onlnchk.h index c7a30d3097ad..808f1282d8b2 100644 --- a/plugins/OnlineChecks/onlnchk.h +++ b/plugins/OnlineChecks/onlnchk.h @@ -143,8 +143,13 @@ typedef struct _UPLOAD_CONTEXT PPH_STRING LastAnalysisAgo; } UPLOAD_CONTEXT, *PUPLOAD_CONTEXT; -VOID ShowOptionsDialog( - _In_opt_ HWND Parent +// options.c + +INT_PTR CALLBACK OptionsDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam ); NTSTATUS UploadFileThreadStart( diff --git a/plugins/OnlineChecks/options.c b/plugins/OnlineChecks/options.c index c7f27a4acc97..6ed1c360e532 100644 --- a/plugins/OnlineChecks/options.c +++ b/plugins/OnlineChecks/options.c @@ -33,42 +33,19 @@ INT_PTR CALLBACK OptionsDlgProc( { case WM_INITDIALOG: { - PhCenterWindow(hwndDlg, GetParent(hwndDlg)); - Button_SetCheck(GetDlgItem(hwndDlg, IDC_ENABLE_VIRUSTOTAL), PhGetIntegerSetting(SETTING_NAME_VIRUSTOTAL_SCAN_ENABLED) ? BST_CHECKED : BST_UNCHECKED); Button_SetCheck(GetDlgItem(hwndDlg, IDC_ENABLE_IDC_ENABLE_VIRUSTOTAL_HIGHLIGHT), PhGetIntegerSetting(SETTING_NAME_VIRUSTOTAL_HIGHLIGHT_DETECTIONS) ? BST_CHECKED : BST_UNCHECKED); } break; - case WM_COMMAND: + case WM_DESTROY: { - switch (GET_WM_COMMAND_ID(wParam, lParam)) - { - case IDCANCEL: - { - PhSetIntegerSetting(SETTING_NAME_VIRUSTOTAL_SCAN_ENABLED, - Button_GetCheck(GetDlgItem(hwndDlg, IDC_ENABLE_VIRUSTOTAL)) == BST_CHECKED ? 1 : 0); - - EndDialog(hwndDlg, IDCANCEL); - } - break; - } + PhSetIntegerSetting(SETTING_NAME_VIRUSTOTAL_SCAN_ENABLED, + Button_GetCheck(GetDlgItem(hwndDlg, IDC_ENABLE_VIRUSTOTAL)) == BST_CHECKED ? 1 : 0); } break; } return FALSE; } - -VOID ShowOptionsDialog( - _In_opt_ HWND Parent - ) -{ - DialogBox( - PluginInstance->DllBase, - MAKEINTRESOURCE(IDD_OPTIONS), - (HWND)Parent, - OptionsDlgProc - ); -} \ No newline at end of file diff --git a/plugins/ToolStatus/ToolStatus.rc b/plugins/ToolStatus/ToolStatus.rc index b0862532cf6f..70c45351bb40 100644 --- a/plugins/ToolStatus/ToolStatus.rc +++ b/plugins/ToolStatus/ToolStatus.rc @@ -87,7 +87,7 @@ END // Dialog // -IDD_OPTIONS DIALOGEX 0, 0, 191, 103 +IDD_OPTIONS DIALOGEX 0, 0, 191, 84 STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Options" FONT 8, "MS Shell Dlg", 400, 0, 0x1 @@ -98,7 +98,6 @@ BEGIN "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,32,152,10 CONTROL "Auto-hide main menu (Alt or F10 key toggle)",IDC_ENABLE_AUTOHIDE_MENU, "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,44,157,10 - DEFPUSHBUTTON "Close",IDOK,134,82,50,14 LTEXT "Note: Right-click the toolbar on the main window to customize the icons and graphs.",IDC_STATIC,7,59,157,18 END @@ -157,7 +156,7 @@ BEGIN LEFTMARGIN, 7 RIGHTMARGIN, 184 TOPMARGIN, 7 - BOTTOMMARGIN, 96 + BOTTOMMARGIN, 77 END IDD_CUSTOMIZE_TB, DIALOG diff --git a/plugins/ToolStatus/main.c b/plugins/ToolStatus/main.c index d358c8a64d7d..008f0979259b 100644 --- a/plugins/ToolStatus/main.c +++ b/plugins/ToolStatus/main.c @@ -1353,7 +1353,20 @@ VOID NTAPI ShowOptionsCallback( _In_opt_ PVOID Context ) { - ShowOptionsDialog(Parameter); + PPH_PLUGIN_OBJECT_PROPERTIES objectProperties = Parameter; + PROPSHEETPAGE propSheetPage; + + if (objectProperties->NumberOfPages < objectProperties->MaximumNumberOfPages) + { + memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); + propSheetPage.dwSize = sizeof(PROPSHEETPAGE); + propSheetPage.dwFlags = PSP_USETITLE; + propSheetPage.hInstance = PluginInstance->DllBase; + propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_OPTIONS); + propSheetPage.pszTitle = L"ToolStatus"; + propSheetPage.pfnDlgProc = OptionsDlgProc; + objectProperties->Pages[objectProperties->NumberOfPages++] = CreatePropertySheetPage(&propSheetPage); + } } LOGICAL DllMain( @@ -1387,7 +1400,6 @@ LOGICAL DllMain( info->Author = L"dmex, wj32"; info->Description = L"Adds a Toolbar, Status Bar and Search box.\r\n\r\nModern Toolbar icons by http://www.icons8.com"; info->Url = L"https://wj32.org/processhacker/forums/viewtopic.php?t=1119"; - info->HasOptions = TRUE; info->Interface = &PluginInterface; PhRegisterCallback( @@ -1397,7 +1409,7 @@ LOGICAL DllMain( &PluginLoadCallbackRegistration ); PhRegisterCallback( - PhGetPluginCallback(PluginInstance, PluginCallbackShowOptions), + PhGetGeneralCallback(GeneralCallbackOptionsWindowInitializing), ShowOptionsCallback, NULL, &PluginShowOptionsCallbackRegistration diff --git a/plugins/ToolStatus/options.c b/plugins/ToolStatus/options.c index f46e5b5564ac..1ab5ac891182 100644 --- a/plugins/ToolStatus/options.c +++ b/plugins/ToolStatus/options.c @@ -34,8 +34,6 @@ INT_PTR CALLBACK OptionsDlgProc( { case WM_INITDIALOG: { - PhCenterWindow(hwndDlg, GetParent(hwndDlg)); - Button_SetCheck(GetDlgItem(hwndDlg, IDC_ENABLE_TOOLBAR), ToolStatusConfig.ToolBarEnabled ? BST_CHECKED : BST_UNCHECKED); Button_SetCheck(GetDlgItem(hwndDlg, IDC_ENABLE_STATUSBAR), @@ -46,37 +44,25 @@ INT_PTR CALLBACK OptionsDlgProc( ToolStatusConfig.AutoHideMenu ? BST_CHECKED : BST_UNCHECKED); } break; - case WM_COMMAND: + case WM_DESTROY: { - switch (GET_WM_COMMAND_ID(wParam, lParam)) - { - case IDCANCEL: - EndDialog(hwndDlg, IDCANCEL); - break; - case IDOK: - { - ToolStatusConfig.ToolBarEnabled = Button_GetCheck(GetDlgItem(hwndDlg, IDC_ENABLE_TOOLBAR)) == BST_CHECKED; - ToolStatusConfig.StatusBarEnabled = Button_GetCheck(GetDlgItem(hwndDlg, IDC_ENABLE_STATUSBAR)) == BST_CHECKED; - ToolStatusConfig.ResolveGhostWindows = Button_GetCheck(GetDlgItem(hwndDlg, IDC_RESOLVEGHOSTWINDOWS)) == BST_CHECKED; - ToolStatusConfig.AutoHideMenu = Button_GetCheck(GetDlgItem(hwndDlg, IDC_ENABLE_AUTOHIDE_MENU)) == BST_CHECKED; - - PhSetIntegerSetting(SETTING_NAME_TOOLSTATUS_CONFIG, ToolStatusConfig.Flags); + ToolStatusConfig.ToolBarEnabled = Button_GetCheck(GetDlgItem(hwndDlg, IDC_ENABLE_TOOLBAR)) == BST_CHECKED; + ToolStatusConfig.StatusBarEnabled = Button_GetCheck(GetDlgItem(hwndDlg, IDC_ENABLE_STATUSBAR)) == BST_CHECKED; + ToolStatusConfig.ResolveGhostWindows = Button_GetCheck(GetDlgItem(hwndDlg, IDC_RESOLVEGHOSTWINDOWS)) == BST_CHECKED; + ToolStatusConfig.AutoHideMenu = Button_GetCheck(GetDlgItem(hwndDlg, IDC_ENABLE_AUTOHIDE_MENU)) == BST_CHECKED; - ToolbarLoadSettings(); + PhSetIntegerSetting(SETTING_NAME_TOOLSTATUS_CONFIG, ToolStatusConfig.Flags); - if (ToolStatusConfig.AutoHideMenu) - { - SetMenu(PhMainWndHandle, NULL); - } - else - { - SetMenu(PhMainWndHandle, MainMenu); - DrawMenuBar(PhMainWndHandle); - } + ToolbarLoadSettings(); - EndDialog(hwndDlg, IDOK); - } - break; + if (ToolStatusConfig.AutoHideMenu) + { + SetMenu(PhMainWndHandle, NULL); + } + else + { + SetMenu(PhMainWndHandle, MainMenu); + DrawMenuBar(PhMainWndHandle); } } break; @@ -84,15 +70,3 @@ INT_PTR CALLBACK OptionsDlgProc( return FALSE; } - -VOID ShowOptionsDialog( - _In_opt_ HWND Parent - ) -{ - DialogBox( - PluginInstance->DllBase, - MAKEINTRESOURCE(IDD_OPTIONS), - Parent, - OptionsDlgProc - ); -} \ No newline at end of file diff --git a/plugins/ToolStatus/toolstatus.h b/plugins/ToolStatus/toolstatus.h index 04751703fb12..202cc23ced73 100644 --- a/plugins/ToolStatus/toolstatus.h +++ b/plugins/ToolStatus/toolstatus.h @@ -223,8 +223,11 @@ VOID ShowCustomizeMenu( // options.c -VOID ShowOptionsDialog( - _In_opt_ HWND Parent +INT_PTR CALLBACK OptionsDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam ); // filter.c diff --git a/plugins/Updater/Updater.rc b/plugins/Updater/Updater.rc index 42c50c87d468..2f67ad44e332 100644 --- a/plugins/Updater/Updater.rc +++ b/plugins/Updater/Updater.rc @@ -89,14 +89,13 @@ END // Dialog // -IDD_OPTIONS DIALOGEX 0, 0, 215, 54 +IDD_OPTIONS DIALOGEX 0, 0, 157, 34 STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Updater Options" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN CONTROL "Check for updates automatically",IDC_AUTOCHECKBOX, "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,7,142,10 - DEFPUSHBUTTON "Close",IDCANCEL,158,33,50,14 END IDD_TEXT DIALOGEX 0, 0, 309, 176 @@ -120,9 +119,9 @@ BEGIN IDD_OPTIONS, DIALOG BEGIN LEFTMARGIN, 7 - RIGHTMARGIN, 208 + RIGHTMARGIN, 150 TOPMARGIN, 7 - BOTTOMMARGIN, 47 + BOTTOMMARGIN, 27 END IDD_TEXT, DIALOG diff --git a/plugins/Updater/main.c b/plugins/Updater/main.c index a6eb9efcde40..4f27d6b7795f 100644 --- a/plugins/Updater/main.c +++ b/plugins/Updater/main.c @@ -73,7 +73,20 @@ VOID NTAPI ShowOptionsCallback( _In_opt_ PVOID Context ) { - ShowOptionsDialog((HWND)Parameter); + PPH_PLUGIN_OBJECT_PROPERTIES objectProperties = Parameter; + PROPSHEETPAGE propSheetPage; + + if (objectProperties->NumberOfPages < objectProperties->MaximumNumberOfPages) + { + memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); + propSheetPage.dwSize = sizeof(PROPSHEETPAGE); + propSheetPage.dwFlags = PSP_USETITLE; + propSheetPage.hInstance = PluginInstance->DllBase; + propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_OPTIONS); + propSheetPage.pszTitle = L"Updater"; + propSheetPage.pfnDlgProc = OptionsDlgProc; + objectProperties->Pages[objectProperties->NumberOfPages++] = CreatePropertySheetPage(&propSheetPage); + } } LOGICAL DllMain( @@ -104,7 +117,6 @@ LOGICAL DllMain( info->Author = L"dmex"; info->Description = L"Plugin for checking new Process Hacker releases via the Help menu."; info->Url = L"https://wj32.org/processhacker/forums/viewtopic.php?t=1121"; - info->HasOptions = TRUE; PhRegisterCallback( PhGetGeneralCallback(GeneralCallbackMainWindowShowing), @@ -125,7 +137,7 @@ LOGICAL DllMain( &PluginMenuItemCallbackRegistration ); PhRegisterCallback( - PhGetPluginCallback(PluginInstance, PluginCallbackShowOptions), + PhGetGeneralCallback(GeneralCallbackOptionsWindowInitializing), ShowOptionsCallback, NULL, &PluginShowOptionsCallbackRegistration diff --git a/plugins/Updater/options.c b/plugins/Updater/options.c index de429ec1e990..94879202df92 100644 --- a/plugins/Updater/options.c +++ b/plugins/Updater/options.c @@ -43,12 +43,10 @@ INT_PTR CALLBACK OptionsDlgProc( { switch (GET_WM_COMMAND_ID(wParam, lParam)) { - case IDCANCEL: + case IDC_AUTOCHECKBOX: { PhSetIntegerSetting(SETTING_NAME_AUTO_CHECK, Button_GetCheck(GetDlgItem(hwndDlg, IDC_AUTOCHECKBOX)) == BST_CHECKED); - - EndDialog(hwndDlg, IDCANCEL); } break; } @@ -59,18 +57,6 @@ INT_PTR CALLBACK OptionsDlgProc( return FALSE; } -VOID ShowOptionsDialog( - _In_opt_ HWND Parent - ) -{ - DialogBox( - PluginInstance->DllBase, - MAKEINTRESOURCE(IDD_OPTIONS), - Parent, - OptionsDlgProc - ); -} - INT_PTR CALLBACK TextDlgProc( _In_ HWND hwndDlg, _In_ UINT uMsg, diff --git a/plugins/Updater/updater.h b/plugins/Updater/updater.h index d557abf644e9..604bf3280b79 100644 --- a/plugins/Updater/updater.h +++ b/plugins/Updater/updater.h @@ -171,8 +171,11 @@ ULONG64 ParseVersionString( // options.c -VOID ShowOptionsDialog( - _In_opt_ HWND Parent +INT_PTR CALLBACK OptionsDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam ); INT_PTR CALLBACK TextDlgProc( From b522353ee79fe9eafc7d62e78ac6bcb18c0fd8b1 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 20 Aug 2017 15:29:36 +1000 Subject: [PATCH 0410/2058] NetworkTools: Add missing file from previous commit --- plugins/NetworkTools/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/NetworkTools/main.c b/plugins/NetworkTools/main.c index dbe747ba1e35..a4ea7b2402a5 100644 --- a/plugins/NetworkTools/main.c +++ b/plugins/NetworkTools/main.c @@ -632,7 +632,7 @@ LOGICAL DllMain( &PluginLoadCallbackRegistration ); PhRegisterCallback( - PhGetPluginCallback(PluginInstance, PluginCallbackShowOptions), + PhGetGeneralCallback(GeneralCallbackOptionsWindowInitializing), ShowOptionsCallback, NULL, &PluginShowOptionsCallbackRegistration From 1f887c7a579e19032cd7edf915a22bc16faa54d2 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 20 Aug 2017 15:34:14 +1000 Subject: [PATCH 0411/2058] NetworkTools: Fix options layout --- plugins/NetworkTools/NetworkTools.rc | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/plugins/NetworkTools/NetworkTools.rc b/plugins/NetworkTools/NetworkTools.rc index 7f639e93aebd..66fdaa394f83 100644 --- a/plugins/NetworkTools/NetworkTools.rc +++ b/plugins/NetworkTools/NetworkTools.rc @@ -96,17 +96,15 @@ BEGIN CONTROL "",IDC_NETOUTPUTEDIT,"RICHEDIT50W",WS_VSCROLL | WS_TABSTOP | 0x4,2,2,385,210 END -IDD_OPTIONS DIALOGEX 0, 0, 201, 57 +IDD_OPTIONS DIALOGEX 0, 0, 201, 43 STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Options" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN LTEXT "Ping packet length:",IDC_STATIC,9,7,62,8 EDITTEXT IDC_PINGPACKETLENGTH,7,17,89,14,ES_AUTOHSCROLL | ES_NUMBER - PUSHBUTTON "Close",IDCANCEL,135,36,60,14 EDITTEXT IDC_MAXHOPS,105,17,89,14,ES_AUTOHSCROLL | ES_NUMBER LTEXT "Max Tracert Hops:",IDC_STATIC,105,7,60,8 - PUSHBUTTON "Manage GeoIP Database",IDC_GEOIP,6,36,90,14 END IDD_PING DIALOGEX 0, 0, 329, 151 @@ -660,7 +658,7 @@ BEGIN LEFTMARGIN, 7 RIGHTMARGIN, 194 TOPMARGIN, 7 - BOTTOMMARGIN, 50 + BOTTOMMARGIN, 36 END IDD_PING, DIALOG From e4394490fedc708f38577898fe99c7edcfc215ff Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 20 Aug 2017 15:38:49 +1000 Subject: [PATCH 0412/2058] NetworkTools: Add missing file --- plugins/NetworkTools/main.c | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/NetworkTools/main.c b/plugins/NetworkTools/main.c index a4ea7b2402a5..df2b30a5674f 100644 --- a/plugins/NetworkTools/main.c +++ b/plugins/NetworkTools/main.c @@ -623,7 +623,6 @@ LOGICAL DllMain( info->Author = L"dmex, wj32"; info->Description = L"Provides ping, traceroute and whois for network connections."; info->Url = L"https://wj32.org/processhacker/forums/viewtopic.php?t=1117"; - info->HasOptions = TRUE; PhRegisterCallback( PhGetPluginCallback(PluginInstance, PluginCallbackLoad), From 0c8a5726eba5508b44fea2ea5da261c835e101c8 Mon Sep 17 00:00:00 2001 From: Starsam80 Date: Fri, 25 Aug 2017 00:16:44 -0600 Subject: [PATCH 0413/2058] Minor High-DPI fix (#173) --- plugins/ToolStatus/toolbar.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/ToolStatus/toolbar.c b/plugins/ToolStatus/toolbar.c index d5521bcdce06..838032616bbc 100644 --- a/plugins/ToolStatus/toolbar.c +++ b/plugins/ToolStatus/toolbar.c @@ -109,8 +109,8 @@ VOID RebarLoadSettings( { if (ToolStatusConfig.ToolBarEnabled && !ToolBarImageList) { - ToolBarImageSize.cx = PH_SCALE_DPI(GetSystemMetrics(SM_CXSMICON)); - ToolBarImageSize.cy = PH_SCALE_DPI(GetSystemMetrics(SM_CYSMICON)); + ToolBarImageSize.cx = GetSystemMetrics(SM_CXSMICON); + ToolBarImageSize.cy = GetSystemMetrics(SM_CYSMICON); ToolBarImageList = ImageList_Create(ToolBarImageSize.cx, ToolBarImageSize.cy, ILC_COLOR32, 0, 0); } From 08c864e1e6151f0f859037d117b8e73f6d393ba9 Mon Sep 17 00:00:00 2001 From: diversenok <30962924+diversenok@users.noreply.github.com> Date: Sat, 26 Aug 2017 14:25:21 +0300 Subject: [PATCH 0414/2058] Lost *.com file extension (#174) --- tools/peview/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/peview/main.c b/tools/peview/main.c index 8823cf300a6f..87404e5258c6 100644 --- a/tools/peview/main.c +++ b/tools/peview/main.c @@ -94,7 +94,7 @@ INT WINAPI wWinMain( { static PH_FILETYPE_FILTER filters[] = { - { L"Supported files (*.exe;*.dll;*.ocx;*.sys;*.scr;*.cpl;*.ax;*.acm;*.lib;*.winmd;*.efi;*.pdb)", L"*.exe;*.dll;*.ocx;*.sys;*.scr;*.cpl;*.ax;*.acm;*.lib;*.winmd;*.efi;*.pdb" }, + { L"Supported files (*.exe;*.dll;*.com;*.ocx;*.sys;*.scr;*.cpl;*.ax;*.acm;*.lib;*.winmd;*.efi;*.pdb)", L"*.exe;*.dll;*.com;*.ocx;*.sys;*.scr;*.cpl;*.ax;*.acm;*.lib;*.winmd;*.efi;*.pdb" }, { L"All files (*.*)", L"*.*" } }; PVOID fileDialog; From fec584f19ab0be9ea64813ca930863b7a5c97f3d Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 31 Aug 2017 14:54:37 +1000 Subject: [PATCH 0415/2058] Disable service verification by default, Add EnableServiceStage2 setting --- ProcessHacker/include/phsettings.h | 1 + ProcessHacker/settings.c | 2 ++ ProcessHacker/srvlist.c | 2 +- ProcessHacker/srvprv.c | 2 +- 4 files changed, 5 insertions(+), 2 deletions(-) diff --git a/ProcessHacker/include/phsettings.h b/ProcessHacker/include/phsettings.h index 653bab459e98..c74d741f692b 100644 --- a/ProcessHacker/include/phsettings.h +++ b/ProcessHacker/include/phsettings.h @@ -12,6 +12,7 @@ #endif EXT BOOLEAN PhEnableProcessQueryStage2; +EXT BOOLEAN PhEnableServiceQueryStage2; EXT ULONG PhCsCollapseServicesOnStart; EXT ULONG PhCsForceNoParent; diff --git a/ProcessHacker/settings.c b/ProcessHacker/settings.c index 51439a7eecf7..933d27733ad9 100644 --- a/ProcessHacker/settings.c +++ b/ProcessHacker/settings.c @@ -48,6 +48,7 @@ VOID PhAddDefaultSettings( PhpAddIntegerSetting(L"EnableNetworkResolve", L"1"); PhpAddIntegerSetting(L"EnablePlugins", L"1"); PhpAddIntegerSetting(L"EnableServiceNonPoll", L"1"); + PhpAddIntegerSetting(L"EnableServiceStage2", L"0"); PhpAddIntegerSetting(L"EnableStage2", L"1"); PhpAddIntegerSetting(L"EnableWarnings", L"1"); PhpAddIntegerSetting(L"EnableWindowText", L"1"); @@ -217,6 +218,7 @@ VOID PhUpdateCachedSettings( ) { PhEnableProcessQueryStage2 = !!PhGetIntegerSetting(L"EnableStage2"); + PhEnableServiceQueryStage2 = !!PhGetIntegerSetting(L"EnableServiceStage2"); PH_UPDATE_SETTING(CollapseServicesOnStart); PH_UPDATE_SETTING(ForceNoParent); diff --git a/ProcessHacker/srvlist.c b/ProcessHacker/srvlist.c index 2bf336cb4a26..e04ff39f66f8 100644 --- a/ProcessHacker/srvlist.c +++ b/ProcessHacker/srvlist.c @@ -753,7 +753,7 @@ BOOLEAN NTAPI PhpServiceTreeNewCallback( if (!serviceItem) ; // Dummy - else if (PhEnableProcessQueryStage2 && PhCsUseColorUnknown && serviceItem->VerifyResult != VrTrusted) + else if (PhEnableServiceQueryStage2 && PhCsUseColorUnknown && serviceItem->VerifyResult != VrTrusted) { getNodeColor->Flags = TN_AUTO_FORECOLOR; getNodeColor->BackColor = PhCsColorUnknown; diff --git a/ProcessHacker/srvprv.c b/ProcessHacker/srvprv.c index c4f1238460cf..1b8ea63d5b2e 100644 --- a/ProcessHacker/srvprv.c +++ b/ProcessHacker/srvprv.c @@ -504,7 +504,7 @@ VOID PhpQueueServiceQuery( PPH_SERVICE_QUERY_DATA data; PH_WORK_QUEUE_ENVIRONMENT environment; - if (!PhEnableProcessQueryStage2) + if (!PhEnableServiceQueryStage2) return; data = PhAllocate(sizeof(PH_SERVICE_QUERY_DATA)); From 27cbc8ccbe56e88875b3b0b296788016a95154ad Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 31 Aug 2017 19:43:52 +1000 Subject: [PATCH 0416/2058] Fix issue inspecting/browsing executables running from faulty ramdisk software --- ProcessHacker/prpggen.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/ProcessHacker/prpggen.c b/ProcessHacker/prpggen.c index 925398bfa7eb..38327b0653e7 100644 --- a/ProcessHacker/prpggen.c +++ b/ProcessHacker/prpggen.c @@ -484,13 +484,20 @@ INT_PTR CALLBACK PhpProcessGeneralDlgProc( { if (processItem->FileName) { + PPH_STRING fileName; + + // Note: Workaround for buggy RamDisk software. + fileName = PhGetFileName(processItem->FileName); + PhShellExecuteUserString( hwndDlg, L"ProgramInspectExecutables", - processItem->FileName->Buffer, + fileName->Buffer, FALSE, L"Make sure the PE Viewer executable file is present." ); + + PhDereferenceObject(fileName); } } break; @@ -498,13 +505,20 @@ INT_PTR CALLBACK PhpProcessGeneralDlgProc( { if (processItem->FileName) { + PPH_STRING fileName; + + // Note: Workaround for buggy RamDisk software. + fileName = PhGetFileName(processItem->FileName); + PhShellExecuteUserString( hwndDlg, L"FileBrowseExecutable", - processItem->FileName->Buffer, + fileName->Buffer, FALSE, L"Make sure the Explorer executable file is present." ); + + PhDereferenceObject(fileName); } } break; From bd438f985b476d27894cafaf235f924ebda90892 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 31 Aug 2017 20:04:26 +1000 Subject: [PATCH 0417/2058] Revert "Fix issue inspecting/browsing executables running from faulty ramdisk software" This reverts commit 27cbc8ccbe56e88875b3b0b296788016a95154ad. --- ProcessHacker/prpggen.c | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/ProcessHacker/prpggen.c b/ProcessHacker/prpggen.c index 38327b0653e7..925398bfa7eb 100644 --- a/ProcessHacker/prpggen.c +++ b/ProcessHacker/prpggen.c @@ -484,20 +484,13 @@ INT_PTR CALLBACK PhpProcessGeneralDlgProc( { if (processItem->FileName) { - PPH_STRING fileName; - - // Note: Workaround for buggy RamDisk software. - fileName = PhGetFileName(processItem->FileName); - PhShellExecuteUserString( hwndDlg, L"ProgramInspectExecutables", - fileName->Buffer, + processItem->FileName->Buffer, FALSE, L"Make sure the PE Viewer executable file is present." ); - - PhDereferenceObject(fileName); } } break; @@ -505,20 +498,13 @@ INT_PTR CALLBACK PhpProcessGeneralDlgProc( { if (processItem->FileName) { - PPH_STRING fileName; - - // Note: Workaround for buggy RamDisk software. - fileName = PhGetFileName(processItem->FileName); - PhShellExecuteUserString( hwndDlg, L"FileBrowseExecutable", - fileName->Buffer, + processItem->FileName->Buffer, FALSE, L"Make sure the Explorer executable file is present." ); - - PhDereferenceObject(fileName); } } break; From 5248f9b232624ab7581a9d08bc7d9a90575e9b6e Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 31 Aug 2017 20:43:25 +1000 Subject: [PATCH 0418/2058] Add workaround for inspecting/browsing executables running from faulty ramdisk software --- ProcessHacker/appsup.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/ProcessHacker/appsup.c b/ProcessHacker/appsup.c index 8517f5c049ee..e72d2cf1e37c 100644 --- a/ProcessHacker/appsup.c +++ b/ProcessHacker/appsup.c @@ -945,7 +945,6 @@ VOID PhShellExecuteUserString( PPH_STRING executeString; PH_STRINGREF stringBefore; - PH_STRINGREF stringMiddle; PH_STRINGREF stringAfter; PPH_STRING ntMessage; @@ -995,8 +994,20 @@ VOID PhShellExecuteUserString( // Replace the token with the string, or use the original string if the token is not present. if (PhSplitStringRefAtString(&executeString->sr, &replacementToken, FALSE, &stringBefore, &stringAfter)) { - PhInitializeStringRef(&stringMiddle, String); - PhMoveReference(&executeString, PhConcatStringRef3(&stringBefore, &stringMiddle, &stringAfter)); + PPH_STRING stringTemp; + PPH_STRING stringMiddle; + + // Note: This code is needed to solve issues with faulty RamDisk software that doesn't use the Mount Manager API + // and instead returns \device\ FileName strings. We also can't change the way the process provider stores + // the FileName string since it'll break various features and use-cases required by developers + // who need the raw untranslated FileName string. + stringTemp = PhCreateString(String); + stringMiddle = PhGetFileName(stringTemp); + + PhMoveReference(&executeString, PhConcatStringRef3(&stringBefore, &stringMiddle->sr, &stringAfter)); + + PhDereferenceObject(stringMiddle); + PhDereferenceObject(stringTemp); } if (UseShellExecute) From 947bacf796d58cc172ae3db858a0a75931f67225 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 1 Sep 2017 11:24:41 +1000 Subject: [PATCH 0419/2058] BuildTools: Fix pinvoke signature, Fix stream dispose issues --- tools/CustomBuildTool/Source Files/Utils.cs | 23 ++++++++++-------- tools/CustomBuildTool/Source Files/Zip.cs | 6 ++--- .../bin/Release/CustomBuildTool.exe | Bin 161792 -> 161792 bytes .../bin/Release/CustomBuildTool.pdb | Bin 73216 -> 73216 bytes 4 files changed, 16 insertions(+), 13 deletions(-) diff --git a/tools/CustomBuildTool/Source Files/Utils.cs b/tools/CustomBuildTool/Source Files/Utils.cs index ba180c1fc213..7fd432512415 100644 --- a/tools/CustomBuildTool/Source Files/Utils.cs +++ b/tools/CustomBuildTool/Source Files/Utils.cs @@ -108,12 +108,12 @@ public static void CopyIfNewer(string CurrentFile, string NewFile) } public static readonly IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1); - public static readonly IntPtr STD_OUTPUT_HANDLE = new IntPtr(-11); - public static readonly IntPtr STD_INPUT_HANDLE = new IntPtr(-10); - public static readonly IntPtr STD_ERROR_HANDLE = new IntPtr(-12); + public const int STD_OUTPUT_HANDLE = -11; + public const int STD_INPUT_HANDLE = -10; + public const int STD_ERROR_HANDLE = -12; [DllImport("kernel32.dll", ExactSpelling = true)] - public static extern IntPtr GetStdHandle(IntPtr StdHandle); + public static extern IntPtr GetStdHandle(int StdHandle); [DllImport("kernel32.dll", ExactSpelling = true)] public static extern bool GetConsoleMode(IntPtr ConsoleHandle, out ConsoleMode Mode); [DllImport("kernel32.dll", ExactSpelling = true)] @@ -160,10 +160,11 @@ private static Rijndael GetRijndael(string secret) public static void Encrypt(string fileName, string outFileName, string secret) { + FileStream fileOutStream = File.Create(outFileName); + using (Rijndael rijndael = GetRijndael(secret)) using (FileStream fileStream = File.OpenRead(fileName)) - using (FileStream fileStream2 = File.Create(outFileName)) - using (CryptoStream cryptoStream = new CryptoStream(fileStream2, rijndael.CreateEncryptor(), CryptoStreamMode.Write)) + using (CryptoStream cryptoStream = new CryptoStream(fileOutStream, rijndael.CreateEncryptor(), CryptoStreamMode.Write)) { fileStream.CopyTo(cryptoStream); } @@ -171,10 +172,11 @@ public static void Encrypt(string fileName, string outFileName, string secret) public static void Decrypt(string FileName, string outFileName, string secret) { + FileStream fileOutStream = File.Create(outFileName); + using (Rijndael rijndael = GetRijndael(secret)) using (FileStream fileStream = File.OpenRead(FileName)) - using (FileStream fileStream2 = File.Create(outFileName)) - using (CryptoStream cryptoStream = new CryptoStream(fileStream2, rijndael.CreateDecryptor(), CryptoStreamMode.Write)) + using (CryptoStream cryptoStream = new CryptoStream(fileOutStream, rijndael.CreateDecryptor(), CryptoStreamMode.Write)) { fileStream.CopyTo(cryptoStream); } @@ -189,8 +191,9 @@ public static string HashFile(string FileName) // return BitConverter.ToString(hashBytes).Replace("-", String.Empty); //} - using (FileStream stream = File.OpenRead(FileName)) - using (BufferedStream bufferedStream = new BufferedStream(stream, 0x1000)) + FileStream fileInStream = File.OpenRead(FileName); + + using (BufferedStream bufferedStream = new BufferedStream(fileInStream, 0x1000)) { SHA256Managed sha = new SHA256Managed(); byte[] checksum = sha.ComputeHash(bufferedStream); diff --git a/tools/CustomBuildTool/Source Files/Zip.cs b/tools/CustomBuildTool/Source Files/Zip.cs index 826659de53f8..f239475ac93e 100644 --- a/tools/CustomBuildTool/Source Files/Zip.cs +++ b/tools/CustomBuildTool/Source Files/Zip.cs @@ -59,7 +59,7 @@ public static void CreateCompressedFolder(string sourceDirectoryName, string des File.Delete(destinationArchiveFileName); using (FileStream zipFileStream = new FileStream(destinationArchiveFileName, FileMode.Create)) - using (ZipArchive archive = new ZipArchive(zipFileStream, ZipArchiveMode.Create)) + using (ZipArchive archive = new ZipArchive(zipFileStream, ZipArchiveMode.Create, true)) { for (int i = 0; i < filesToAdd.Length; i++) { @@ -93,7 +93,7 @@ public static void CreateCompressedSdkFromFolder(string sourceDirectoryName, str File.Delete(destinationArchiveFileName); using (FileStream zipFileStream = new FileStream(destinationArchiveFileName, FileMode.Create)) - using (ZipArchive archive = new ZipArchive(zipFileStream, ZipArchiveMode.Create)) + using (ZipArchive archive = new ZipArchive(zipFileStream, ZipArchiveMode.Create, true)) { for (int i = 0; i < filesToAdd.Length; i++) { @@ -111,7 +111,7 @@ public static void CreateCompressedPdbFromFolder(string sourceDirectoryName, str File.Delete(destinationArchiveFileName); using (FileStream zipFileStream = new FileStream(destinationArchiveFileName, FileMode.Create)) - using (ZipArchive archive = new ZipArchive(zipFileStream, ZipArchiveMode.Create)) + using (ZipArchive archive = new ZipArchive(zipFileStream, ZipArchiveMode.Create, true)) { for (int i = 0; i < filesToAdd.Length; i++) { diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe b/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe index 9571ac2a843046720c3a6d2246eed1203b5e0b9f..3a5ceddc828f66058aaf9a8013e749e4dd747693 100644 GIT binary patch delta 5183 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 delta 9679 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 Date: Fri, 1 Sep 2017 11:42:55 +1000 Subject: [PATCH 0420/2058] HardwareDevices: Move plugin settings to options window making kylo singing great again --- plugins/HardwareDevices/main.c | 53 +++++++++++++++------------------- 1 file changed, 24 insertions(+), 29 deletions(-) diff --git a/plugins/HardwareDevices/main.c b/plugins/HardwareDevices/main.c index 9b2e7c4a39bd..df1e73ab889e 100644 --- a/plugins/HardwareDevices/main.c +++ b/plugins/HardwareDevices/main.c @@ -67,36 +67,32 @@ VOID NTAPI ShowOptionsCallback( _In_opt_ PVOID Context ) { - PROPSHEETHEADER propSheetHeader = { sizeof(propSheetHeader) }; + PPH_PLUGIN_OBJECT_PROPERTIES objectProperties = Parameter; PROPSHEETPAGE propSheetPage; - HPROPSHEETPAGE pages[2]; - propSheetHeader.dwFlags = - PSH_NOAPPLYNOW | - PSH_NOCONTEXTHELP; - propSheetHeader.hwndParent = (HWND)Parameter; - propSheetHeader.pszCaption = L"Hardware Devices Plugin"; - propSheetHeader.nPages = 0; - propSheetHeader.nStartPage = 0; - propSheetHeader.phpage = pages; - - // Disk Drives - memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); - propSheetPage.dwSize = sizeof(PROPSHEETPAGE); - propSheetPage.hInstance = PluginInstance->DllBase; - propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_DISKDRIVE_OPTIONS); - propSheetPage.pfnDlgProc = DiskDriveOptionsDlgProc; - pages[propSheetHeader.nPages++] = CreatePropertySheetPage(&propSheetPage); + if (objectProperties->NumberOfPages < objectProperties->MaximumNumberOfPages) + { + memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); + propSheetPage.dwSize = sizeof(PROPSHEETPAGE); + propSheetPage.dwFlags = PSP_USETITLE; + propSheetPage.hInstance = PluginInstance->DllBase; + propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_DISKDRIVE_OPTIONS); + propSheetPage.pszTitle = L"Disk Drives"; + propSheetPage.pfnDlgProc = DiskDriveOptionsDlgProc; + objectProperties->Pages[objectProperties->NumberOfPages++] = CreatePropertySheetPage(&propSheetPage); + } - // Network Adapters - memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); - propSheetPage.dwSize = sizeof(PROPSHEETPAGE); - propSheetPage.hInstance = PluginInstance->DllBase; - propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_NETADAPTER_OPTIONS); - propSheetPage.pfnDlgProc = NetworkAdapterOptionsDlgProc; - pages[propSheetHeader.nPages++] = CreatePropertySheetPage(&propSheetPage); - - PhModalPropertySheet(&propSheetHeader); + if (objectProperties->NumberOfPages < objectProperties->MaximumNumberOfPages) + { + memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); + propSheetPage.dwSize = sizeof(PROPSHEETPAGE); + propSheetPage.dwFlags = PSP_USETITLE; + propSheetPage.hInstance = PluginInstance->DllBase; + propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_NETADAPTER_OPTIONS); + propSheetPage.pszTitle = L"Network Adapters"; + propSheetPage.pfnDlgProc = NetworkAdapterOptionsDlgProc; + objectProperties->Pages[objectProperties->NumberOfPages++] = CreatePropertySheetPage(&propSheetPage); + } } VOID NTAPI MainWindowShowingCallback( @@ -336,7 +332,6 @@ LOGICAL DllMain( info->Author = L"dmex, wj32"; info->Description = L"Plugin for monitoring hardware devices like Disk drives and Network adapters via the System Information window."; info->Url = L"https://wj32.org/processhacker/forums/viewtopic.php?t=1820"; - info->HasOptions = TRUE; PhRegisterCallback( PhGetPluginCallback(PluginInstance, PluginCallbackLoad), @@ -351,7 +346,7 @@ LOGICAL DllMain( &PluginUnloadCallbackRegistration ); PhRegisterCallback( - PhGetPluginCallback(PluginInstance, PluginCallbackShowOptions), + PhGetGeneralCallback(GeneralCallbackOptionsWindowInitializing), ShowOptionsCallback, NULL, &PluginShowOptionsCallbackRegistration From baecf675a542a553ecb808b3579b335b1ab46624 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 1 Sep 2017 12:33:06 +1000 Subject: [PATCH 0421/2058] NetworkTools: Fix retry button, Fix error creating DB directory path --- plugins/NetworkTools/nettools.h | 12 +++++------- plugins/NetworkTools/pages.c | 32 ++++++++++++++++++-------------- plugins/NetworkTools/update.c | 19 ++++++++++++++++--- 3 files changed, 39 insertions(+), 24 deletions(-) diff --git a/plugins/NetworkTools/nettools.h b/plugins/NetworkTools/nettools.h index 45e04b181b29..b00ba77ec247 100644 --- a/plugins/NetworkTools/nettools.h +++ b/plugins/NetworkTools/nettools.h @@ -288,22 +288,20 @@ VOID ShowGeoIPUpdateDialog( _In_opt_ HWND Parent ); -// page1.c -VOID ShowCheckForUpdatesDialog( +// pages.c +VOID ShowDbCheckForUpdatesDialog( _In_ PPH_UPDATER_CONTEXT Context ); -// page2.c -VOID ShowCheckingForUpdatesDialog( +VOID ShowDbCheckingForUpdatesDialog( _In_ PPH_UPDATER_CONTEXT Context ); -// page5.c -VOID ShowInstallRestartDialog( +VOID ShowDbInstallRestartDialog( _In_ PPH_UPDATER_CONTEXT Context ); -VOID ShowUpdateFailedDialog( +VOID ShowDbUpdateFailedDialog( _In_ PPH_UPDATER_CONTEXT Context ); diff --git a/plugins/NetworkTools/pages.c b/plugins/NetworkTools/pages.c index b379a9213124..d5fb5a254762 100644 --- a/plugins/NetworkTools/pages.c +++ b/plugins/NetworkTools/pages.c @@ -33,7 +33,7 @@ TASKDIALOG_BUTTON DownloadButtonArray[] = { IDOK, L"Download" } }; -HRESULT CALLBACK CheckForUpdatesCallbackProc( +HRESULT CALLBACK CheckForUpdatesDbCallbackProc( _In_ HWND hwndDlg, _In_ UINT uMsg, _In_ WPARAM wParam, @@ -51,7 +51,7 @@ HRESULT CALLBACK CheckForUpdatesCallbackProc( { if ((INT)wParam == IDOK) { - ShowCheckingForUpdatesDialog(context); + ShowDbCheckingForUpdatesDialog(context); return S_FALSE; } } @@ -66,7 +66,7 @@ HRESULT CALLBACK CheckForUpdatesCallbackProc( return S_OK; } -HRESULT CALLBACK CheckingForUpdatesCallbackProc( +HRESULT CALLBACK CheckingForUpdatesDbCallbackProc( _In_ HWND hwndDlg, _In_ UINT uMsg, _In_ WPARAM wParam, @@ -91,7 +91,7 @@ HRESULT CALLBACK CheckingForUpdatesCallbackProc( return S_OK; } -HRESULT CALLBACK RestartTaskDialogCallbackProc( +HRESULT CALLBACK RestartDbTaskDialogCallbackProc( _In_ HWND hwndDlg, _In_ UINT uMsg, _In_ WPARAM wParam, @@ -126,7 +126,7 @@ HRESULT CALLBACK RestartTaskDialogCallbackProc( return S_OK; } -HRESULT CALLBACK FinalTaskDialogCallbackProc( +HRESULT CALLBACK FinalDbTaskDialogCallbackProc( _In_ HWND hwndDlg, _In_ UINT uMsg, _In_ WPARAM wParam, @@ -148,7 +148,11 @@ HRESULT CALLBACK FinalTaskDialogCallbackProc( break; case TDN_BUTTON_CLICKED: { - + if ((INT)wParam == IDRETRY) + { + ShowDbCheckForUpdatesDialog(context); + return S_FALSE; + } } break; } @@ -156,7 +160,7 @@ HRESULT CALLBACK FinalTaskDialogCallbackProc( return S_OK; } -VOID ShowCheckForUpdatesDialog( +VOID ShowDbCheckForUpdatesDialog( _In_ PPH_UPDATER_CONTEXT Context ) { @@ -170,7 +174,7 @@ VOID ShowCheckForUpdatesDialog( config.cxWidth = 200; config.pButtons = DownloadButtonArray; config.cButtons = ARRAYSIZE(DownloadButtonArray); - config.pfCallback = CheckForUpdatesCallbackProc; + config.pfCallback = CheckForUpdatesDbCallbackProc; config.lpCallbackData = (LONG_PTR)Context; config.pszWindowTitle = L"Network Tools - GeoIP Updater"; @@ -180,7 +184,7 @@ VOID ShowCheckForUpdatesDialog( SendMessage(Context->DialogHandle, TDM_NAVIGATE_PAGE, 0, (LPARAM)&config); } -VOID ShowCheckingForUpdatesDialog( +VOID ShowDbCheckingForUpdatesDialog( _In_ PPH_UPDATER_CONTEXT Context ) { @@ -192,7 +196,7 @@ VOID ShowCheckingForUpdatesDialog( config.dwCommonButtons = TDCBF_CLOSE_BUTTON; config.hMainIcon = Context->IconLargeHandle; config.cxWidth = 200; - config.pfCallback = CheckingForUpdatesCallbackProc; + config.pfCallback = CheckingForUpdatesDbCallbackProc; config.lpCallbackData = (LONG_PTR)Context; config.pszWindowTitle = L"Network Tools - GeoIP Updater"; @@ -202,7 +206,7 @@ VOID ShowCheckingForUpdatesDialog( SendMessage(Context->DialogHandle, TDM_NAVIGATE_PAGE, 0, (LPARAM)&config); } -VOID ShowInstallRestartDialog( +VOID ShowDbInstallRestartDialog( _In_ PPH_UPDATER_CONTEXT Context ) { @@ -214,7 +218,7 @@ VOID ShowInstallRestartDialog( config.dwCommonButtons = TDCBF_CLOSE_BUTTON; config.hMainIcon = Context->IconLargeHandle; config.cxWidth = 200; - config.pfCallback = RestartTaskDialogCallbackProc; + config.pfCallback = RestartDbTaskDialogCallbackProc; config.lpCallbackData = (LONG_PTR)Context; config.pButtons = RestartButtonArray; config.cButtons = ARRAYSIZE(RestartButtonArray); @@ -226,7 +230,7 @@ VOID ShowInstallRestartDialog( SendMessage(Context->DialogHandle, TDM_NAVIGATE_PAGE, 0, (LPARAM)&config); } -VOID ShowUpdateFailedDialog( +VOID ShowDbUpdateFailedDialog( _In_ PPH_UPDATER_CONTEXT Context ) { @@ -239,7 +243,7 @@ VOID ShowUpdateFailedDialog( config.dwCommonButtons = TDCBF_CLOSE_BUTTON | TDCBF_RETRY_BUTTON; config.hMainIcon = Context->IconLargeHandle; config.cxWidth = 200; - config.pfCallback = FinalTaskDialogCallbackProc; + config.pfCallback = FinalDbTaskDialogCallbackProc; config.lpCallbackData = (LONG_PTR)Context; config.pszWindowTitle = L"Network Tools - GeoIP Updater"; diff --git a/plugins/NetworkTools/update.c b/plugins/NetworkTools/update.c index b88d78143f68..e53977a5e2b8 100644 --- a/plugins/NetworkTools/update.c +++ b/plugins/NetworkTools/update.c @@ -537,6 +537,19 @@ NTSTATUS GeoIPUpdateThread( if (!NT_SUCCESS(PhDeleteFileWin32(PhGetString(dbpath)))) goto CleanupExit; } + else + { + // Create the directory if it does not exist. + + PPH_STRING fullPath; + ULONG indexOfFileName; + + if (fullPath = PH_AUTO(PhGetFullPath(dbpath->Buffer, &indexOfFileName))) + { + if (indexOfFileName != -1) + PhCreateDirectory(PhaSubstring(fullPath, 0, indexOfFileName)); + } + } if (gzfile = gzopen(mmdbGzPath->Buffer, "rb")) { @@ -619,11 +632,11 @@ NTSTATUS GeoIPUpdateThread( { if (success) { - ShowInstallRestartDialog(context); + ShowDbInstallRestartDialog(context); } else { - ShowUpdateFailedDialog(context); + ShowDbUpdateFailedDialog(context); } } @@ -653,7 +666,7 @@ HRESULT CALLBACK TaskDialogBootstrapCallback( // Create the Taskdialog icons TaskDialogCreateIcons(context); - ShowCheckForUpdatesDialog(context); + ShowDbCheckForUpdatesDialog(context); } break; } From d3679a7c7492157b468cf3826549b4280b204c5a Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 1 Sep 2017 16:06:55 +1000 Subject: [PATCH 0422/2058] Remove legacy plugin menu support --- ProcessHacker/include/mainwnd.h | 15 +------ ProcessHacker/include/mainwndp.h | 4 -- ProcessHacker/include/phplug.h | 17 ------- ProcessHacker/mainwnd.c | 76 -------------------------------- ProcessHacker/plugin.c | 54 ----------------------- 5 files changed, 1 insertion(+), 165 deletions(-) diff --git a/ProcessHacker/include/mainwnd.h b/ProcessHacker/include/mainwnd.h index 12cfb2551d49..de4d3b04f33a 100644 --- a/ProcessHacker/include/mainwnd.h +++ b/ProcessHacker/include/mainwnd.h @@ -47,7 +47,7 @@ extern BOOLEAN PhMainWndExiting; #define WM_PH_GET_FONT (WM_APP + 137) // begin_phapppub #define WM_PH_INVOKE (WM_APP + 138) -#define WM_PH_ADD_MENU_ITEM (WM_APP + 139) +// WM_PH_DEPRECATED (WM_APP + 139) #define WM_PH_CREATE_TAB_PAGE (WM_APP + 140) #define WM_PH_REFRESH (WM_APP + 141) #define WM_PH_GET_UPDATE_AUTOMATICALLY (WM_APP + 142) @@ -87,8 +87,6 @@ extern BOOLEAN PhMainWndExiting; SendMessage(hWnd, WM_PH_SELECT_NETWORK_ITEM, 0, (LPARAM)(NetworkItem)) #define ProcessHacker_Invoke(hWnd, Function, Parameter) \ PostMessage(hWnd, WM_PH_INVOKE, (WPARAM)(Parameter), (LPARAM)(Function)) -#define ProcessHacker_AddMenuItem(hWnd, AddMenuItem) \ - ((ULONG_PTR)SendMessage(hWnd, WM_PH_ADD_MENU_ITEM, 0, (LPARAM)(AddMenuItem))) #define ProcessHacker_CreateTabPage(hWnd, Template) \ ((struct _PH_MAIN_TAB_PAGE *)SendMessage(hWnd, WM_PH_CREATE_TAB_PAGE, 0, (LPARAM)(Template))) #define ProcessHacker_Refresh(hWnd) \ @@ -126,17 +124,6 @@ typedef struct _PH_LAYOUT_PADDING_DATA } PH_LAYOUT_PADDING_DATA, *PPH_LAYOUT_PADDING_DATA; // end_phapppub -typedef struct _PH_ADD_MENU_ITEM -{ - _In_ PVOID Plugin; - _In_ ULONG Location; - _In_opt_ PWSTR InsertAfter; - _In_ ULONG Flags; - _In_ ULONG Id; - _In_ PWSTR Text; - _In_opt_ PVOID Context; -} PH_ADD_MENU_ITEM, *PPH_ADD_MENU_ITEM; - // begin_phapppub typedef enum _PH_MAIN_TAB_PAGE_MESSAGE { diff --git a/ProcessHacker/include/mainwndp.h b/ProcessHacker/include/mainwndp.h index b2a82e0a7e77..70f85d4f1569 100644 --- a/ProcessHacker/include/mainwndp.h +++ b/ProcessHacker/include/mainwndp.h @@ -206,10 +206,6 @@ VOID PhMwpDispatchMenuCommand( _In_ ULONG_PTR ItemData ); -ULONG_PTR PhMwpLegacyAddPluginMenuItem( - _In_ PPH_ADD_MENU_ITEM AddMenuItem - ); - HBITMAP PhMwpGetShieldBitmap( VOID ); diff --git a/ProcessHacker/include/phplug.h b/ProcessHacker/include/phplug.h index 22746056c982..29aca4ac6cc5 100644 --- a/ProcessHacker/include/phplug.h +++ b/ProcessHacker/include/phplug.h @@ -502,23 +502,6 @@ typedef struct _PH_PLUGIN_MENU_ITEM #define PH_MENU_ITEM_LOCATION_VIEW 1 #define PH_MENU_ITEM_LOCATION_TOOLS 2 -// Id flags (non-functional) -#define PH_MENU_ITEM_SUB_MENU 0x80000000 -#define PH_MENU_ITEM_RETURN_MENU 0x40000000 -#define PH_MENU_ITEM_VALID_FLAGS 0xc0000000 - -PHAPPAPI -ULONG_PTR -NTAPI -PhPluginAddMenuItem( - _In_ PPH_PLUGIN Plugin, - _In_ ULONG_PTR Location, - _In_opt_ PWSTR InsertAfter, - _In_ ULONG Id, - _In_ PWSTR Text, - _In_opt_ PVOID Context - ); - typedef struct _PH_PLUGIN_SYSTEM_STATISTICS { PSYSTEM_PERFORMANCE_INFORMATION Performance; diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index a9469a78eeb7..415a0165d274 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -88,7 +88,6 @@ static HFONT CurrentCustomFont; static HMENU SubMenuHandles[5]; static PPH_EMENU SubMenuObjects[5]; -static PPH_LIST LegacyAddMenuItemList; static PH_CALLBACK_REGISTRATION SymInitRegistration; @@ -2072,13 +2071,6 @@ ULONG_PTR PhMwpOnUserMessage( function((PVOID)WParam); } break; - case WM_PH_ADD_MENU_ITEM: - { - PPH_ADD_MENU_ITEM addMenuItem = (PPH_ADD_MENU_ITEM)LParam; - - return PhMwpLegacyAddPluginMenuItem(addMenuItem); - } - break; case WM_PH_CREATE_TAB_PAGE: { return (ULONG_PTR)PhMwpCreatePage((PPH_MAIN_TAB_PAGE)LParam); @@ -2550,30 +2542,6 @@ VOID PhMwpDispatchMenuCommand( SendMessage(PhMainWndHandle, WM_COMMAND, ItemId, 0); } -ULONG_PTR PhMwpLegacyAddPluginMenuItem( - _In_ PPH_ADD_MENU_ITEM AddMenuItem - ) -{ - PPH_ADD_MENU_ITEM addMenuItem; - PPH_PLUGIN_MENU_ITEM pluginMenuItem; - - if (!LegacyAddMenuItemList) - LegacyAddMenuItemList = PhCreateList(8); - - addMenuItem = PhAllocateCopy(AddMenuItem, sizeof(PH_ADD_MENU_ITEM)); - PhAddItemList(LegacyAddMenuItemList, addMenuItem); - - pluginMenuItem = PhAllocate(sizeof(PH_PLUGIN_MENU_ITEM)); - memset(pluginMenuItem, 0, sizeof(PH_PLUGIN_MENU_ITEM)); - pluginMenuItem->Plugin = AddMenuItem->Plugin; - pluginMenuItem->Id = AddMenuItem->Id; - pluginMenuItem->Context = AddMenuItem->Context; - - addMenuItem->Context = pluginMenuItem; - - return TRUE; -} - HBITMAP PhMwpGetShieldBitmap( VOID ) @@ -2764,50 +2732,6 @@ VOID PhMwpInitializeSubMenu( } } } - - if (LegacyAddMenuItemList) - { - ULONG i; - PPH_ADD_MENU_ITEM addMenuItem; - - for (i = 0; i < LegacyAddMenuItemList->Count; i++) - { - addMenuItem = LegacyAddMenuItemList->Items[i]; - - if (addMenuItem->Location == Index) - { - ULONG insertIndex; - - if (addMenuItem->InsertAfter) - { - for (insertIndex = 0; insertIndex < Menu->Items->Count; insertIndex++) - { - menuItem = Menu->Items->Items[insertIndex]; - - if (!(menuItem->Flags & PH_EMENU_SEPARATOR) && (PhCompareUnicodeStringZIgnoreMenuPrefix( - addMenuItem->InsertAfter, - menuItem->Text, - TRUE, - TRUE - ) == 0)) - { - insertIndex++; - break; - } - } - } - else - { - insertIndex = 0; - } - - if (addMenuItem->Text[0] == '-' && addMenuItem->Text[1] == 0) - PhInsertEMenuItem(Menu, PhCreateEMenuItem(PH_EMENU_SEPARATOR, 0, L"", NULL, NULL), insertIndex); - else - PhInsertEMenuItem(Menu, PhCreateEMenuItem(0, ID_PLUGIN_MENU_ITEM, addMenuItem->Text, NULL, addMenuItem->Context), insertIndex); - } - } - } } PPH_EMENU_ITEM PhMwpFindTrayIconsMenuItem( diff --git a/ProcessHacker/plugin.c b/ProcessHacker/plugin.c index c468ffa93131..3fd0cf20ffb6 100644 --- a/ProcessHacker/plugin.c +++ b/ProcessHacker/plugin.c @@ -627,60 +627,6 @@ ULONG PhPluginReserveIds( return nextPluginId; } -/** - * Adds a menu item to the program's main menu. This function is - * deprecated. Use \c GeneralCallbackMainMenuInitializing instead. - * - * \param Plugin A plugin instance structure. - * \param Location A handle to the parent menu, or one of the following: - * \li \c PH_MENU_ITEM_LOCATION_VIEW The "View" menu. - * \li \c PH_MENU_ITEM_LOCATION_TOOLS The "Tools" menu. - * \param InsertAfter The text of the menu item to insert the - * new menu item after. The search is a case-insensitive prefix search - * that ignores prefix characters (ampersands). - * \param Id An identifier for the menu item. This should be unique - * within the plugin. - * \param Text The text of the menu item. - * \param Context A user-defined value for the menu item. - * - * \return TRUE if the function succeeded, otherwise FALSE. - * - * \remarks The \ref PluginCallbackMenuItem callback is invoked when - * the menu item is chosen, and the \ref PH_PLUGIN_MENU_ITEM structure - * will contain the \a Id and \a Context values passed to this function. - */ -ULONG_PTR PhPluginAddMenuItem( - _In_ PPH_PLUGIN Plugin, - _In_ ULONG_PTR Location, - _In_opt_ PWSTR InsertAfter, - _In_ ULONG Id, - _In_ PWSTR Text, - _In_opt_ PVOID Context - ) -{ - PH_ADD_MENU_ITEM addMenuItem; - - addMenuItem.Plugin = Plugin; - addMenuItem.InsertAfter = InsertAfter; - addMenuItem.Text = Text; - addMenuItem.Context = Context; - - if (Location < 0x1000) - { - addMenuItem.Location = (ULONG)Location; - } - else - { - return 0; - } - - addMenuItem.Flags = Id & PH_MENU_ITEM_VALID_FLAGS; - Id &= ~PH_MENU_ITEM_VALID_FLAGS; - addMenuItem.Id = Id; - - return ProcessHacker_AddMenuItem(PhMainWndHandle, &addMenuItem); -} - /** * Retrieves current system statistics. */ From ceddb0c7a59e896ccd02e6ece02141a5a5e7fee4 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 1 Sep 2017 16:07:26 +1000 Subject: [PATCH 0423/2058] Fix users mainmenu regression --- ProcessHacker/mainwnd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index 415a0165d274..73b7be8fccd5 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -3518,7 +3518,7 @@ VOID PhMwpUpdateUsersMenu( PhInsertEMenuItem(UsersMenu, userMenu = PhCreateEMenuItem(0, IDR_USER, escapedMenuText->Buffer, NULL, UlongToPtr(sessions[i].SessionId)), -1); PhLoadResourceEMenuItem(userMenu, PhInstanceHandle, MAKEINTRESOURCE(IDR_USER), 0); - PhDereferenceObject(escapedMenuText); + PhAutoDereferenceObject(escapedMenuText); } WinStationFreeMemory(sessions); From d74b74a5c5dada1c1ae3e4d45cd2188fe8dac897 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 9 Sep 2017 19:41:39 +1000 Subject: [PATCH 0424/2058] Add new options window UI --- ProcessHacker/ProcessHacker.rc | 20 +- ProcessHacker/include/phplug.h | 44 + ProcessHacker/options.c | 903 +++++++++++------- ProcessHacker/resource.h | 7 +- .../ExtendedNotifications.rc | 10 +- plugins/ExtendedNotifications/main.c | 250 +++-- plugins/ExtendedNotifications/resource.h | 5 +- plugins/ExtendedServices/main.c | 23 +- plugins/ExtendedTools/main.c | 23 +- plugins/HardwareDevices/devices.h | 6 +- plugins/HardwareDevices/diskoptions.c | 17 +- plugins/HardwareDevices/main.c | 41 +- plugins/HardwareDevices/netoptions.c | 11 + plugins/NetworkTools/main.c | 23 +- plugins/OnlineChecks/main.c | 23 +- plugins/ToolStatus/main.c | 23 +- plugins/Updater/main.c | 23 +- plugins/UserNotes/UserNotes.rc | 12 +- plugins/UserNotes/main.c | 46 +- 19 files changed, 878 insertions(+), 632 deletions(-) diff --git a/ProcessHacker/ProcessHacker.rc b/ProcessHacker/ProcessHacker.rc index 6ab929d692fc..a2d7926d6373 100644 --- a/ProcessHacker/ProcessHacker.rc +++ b/ProcessHacker/ProcessHacker.rc @@ -1192,7 +1192,7 @@ BEGIN LTEXT "Removed objects:",IDC_STATIC,127,25,60,8 CONTROL "Removed objects",IDC_REMOVEDOBJECTS,"PhColorBox",WS_CLIPSIBLINGS | WS_TABSTOP,193,23,33,13 CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | LVS_NOCOLUMNHEADER | WS_BORDER | WS_TABSTOP,7,41,236,107 - LTEXT "Double-click an item to change it.",IDC_STATIC,7,156,106,8 + LTEXT "Double-click an item to change it.",IDC_INFO,7,156,106,8 PUSHBUTTON "Enable all",IDC_ENABLEALL,140,153,50,14 PUSHBUTTON "Disable all",IDC_DISABLEALL,193,153,50,14 END @@ -1870,6 +1870,18 @@ BEGIN PUSHBUTTON "Cancel",IDCANCEL,254,156,50,14 END +IDD_OPTIONS DIALOGEX 0, 0, 423, 247 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME +EXSTYLE WS_EX_APPWINDOW +CAPTION "Options" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + DEFPUSHBUTTON "Close",IDOK,371,231,50,14 + CONTROL "",IDC_SECTIONTREE,"SysTreeView32",TVS_SHOWSELALWAYS | TVS_TRACKSELECT | TVS_FULLROWSELECT | WS_HSCROLL | WS_TABSTOP,2,1,103,228 + CONTROL "",IDD_CONTAINER,"#32770",0x44c,107,0,316,229,WS_EX_TOPMOST | WS_EX_TOOLWINDOW | WS_EX_CONTROLPARENT | 0xc0000800L + LTEXT "",IDC_SEPARATOR,105,0,8,229 + PUSHBUTTON "Reset",IDC_RESET,319,231,50,14 +END ///////////////////////////////////////////////////////////////////////////// // @@ -2402,6 +2414,12 @@ BEGIN TOPMARGIN, 7 BOTTOMMARGIN, 170 END + + IDD_OPTIONS, DIALOG + BEGIN + LEFTMARGIN, 2 + BOTTOMMARGIN, 245 + END END #endif // APSTUDIO_INVOKED diff --git a/ProcessHacker/include/phplug.h b/ProcessHacker/include/phplug.h index 29aca4ac6cc5..18ae65492051 100644 --- a/ProcessHacker/include/phplug.h +++ b/ProcessHacker/include/phplug.h @@ -325,7 +325,51 @@ typedef struct _PH_PLUGIN_MINIINFO_POINTERS PPH_MINIINFO_FIND_SECTION FindSection; PPH_MINIINFO_CREATE_LIST_SECTION CreateListSection; } PH_PLUGIN_MINIINFO_POINTERS, *PPH_PLUGIN_MINIINFO_POINTERS; +// end_phapppub + +// begin_phapppub +typedef struct _PH_OPTIONS_SECTION +{ + PH_STRINGREF Name; + // end_phapppub + + PVOID Instance; + PWSTR Template; + DLGPROC DialogProc; + PVOID Parameter; + + HWND DialogHandle; + // begin_phapppub +} PH_OPTIONS_SECTION, *PPH_OPTIONS_SECTION; +// end_phapppub +// begin_phapppub +typedef PPH_OPTIONS_SECTION (NTAPI *PPH_OPTIONS_CREATE_SECTION)( + _In_ PWSTR Name, + _In_ PVOID Instance, + _In_ PWSTR Template, + _In_ DLGPROC DialogProc, + _In_ PVOID Parameter + ); + +typedef PPH_OPTIONS_SECTION (NTAPI *PPH_OPTIONS_FIND_SECTION)( + _In_ PPH_STRINGREF Name + ); + +typedef VOID (NTAPI *PPH_OPTIONS_ENTER_SECTION_VIEW)( + _In_ PPH_OPTIONS_SECTION NewSection + ); + +typedef struct _PH_PLUGIN_OPTIONS_POINTERS +{ + HWND WindowHandle; + PPH_OPTIONS_CREATE_SECTION CreateSection; + PPH_OPTIONS_FIND_SECTION FindSection; + PPH_OPTIONS_ENTER_SECTION_VIEW EnterSectionView; +} PH_PLUGIN_OPTIONS_POINTERS, *PPH_PLUGIN_OPTIONS_POINTERS; +// end_phapppub + +// begin_phapppub typedef struct _PH_PLUGIN_TREENEW_MESSAGE { HWND TreeNewHandle; diff --git a/ProcessHacker/options.c b/ProcessHacker/options.c index 8eebf0135ca6..b442a115de0b 100644 --- a/ProcessHacker/options.c +++ b/ProcessHacker/options.c @@ -25,6 +25,8 @@ #include #include +#include +#include #include #include @@ -33,25 +35,9 @@ #include #include #include -#include #define WM_PH_CHILD_EXIT (WM_APP + 301) -INT CALLBACK PhpOptionsPropSheetProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ LPARAM lParam - ); - -LRESULT CALLBACK PhpOptionsWndProc( - _In_ HWND hwnd, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam, - _In_ UINT_PTR uIdSubclass, - _In_ ULONG_PTR dwRefData - ); - INT_PTR CALLBACK PhpOptionsGeneralDlgProc( _In_ HWND hwndDlg, _In_ UINT uMsg, @@ -87,10 +73,70 @@ INT_PTR CALLBACK PhpOptionsGraphsDlgProc( _In_ LPARAM lParam ); +INT_PTR CALLBACK PhOptionsDialogProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +VOID PhOptionsDestroySection( + _In_ PPH_OPTIONS_SECTION Section + ); + +VOID PhOptionsEnterSectionView( + _In_ PPH_OPTIONS_SECTION NewSection + ); + +VOID PhOptionsLayoutSectionView( + VOID + ); + +VOID PhOptionsEnterSectionViewInner( + _In_ PPH_OPTIONS_SECTION Section, + _Inout_ HDWP *DeferHandle, + _Inout_ HDWP *ContainerDeferHandle + ); + +VOID PhOptionsCreateSectionDialog( + _In_ PPH_OPTIONS_SECTION Section + ); + +PPH_OPTIONS_SECTION PhOptionsFindSection( + _In_ PPH_STRINGREF Name + ); + +VOID PhOptionsOnSize( + VOID + ); + +PPH_OPTIONS_SECTION PhOptionsCreateInternalSection( + _In_ PWSTR Name, + _In_ PVOID Instance, + _In_ PWSTR Template, + _In_ DLGPROC DialogProc, + _In_ PVOID Parameter + ); + +PPH_OPTIONS_SECTION PhOptionsCreateSection( + _In_ PWSTR Name, + _In_ PVOID Instance, + _In_ PWSTR Template, + _In_ DLGPROC DialogProc, + _In_ PVOID Parameter + ); + +static HWND PhOptionsWindowHandle = NULL; +static PPH_LIST PhOptionsDialogList = NULL; +static PH_LAYOUT_MANAGER WindowLayoutManager; + +static PPH_LIST SectionList = NULL; +static PPH_OPTIONS_SECTION CurrentSection = NULL; +static HWND OptionsTreeControl = NULL; +static HWND ContainerControl = NULL; + // All -static BOOLEAN PageInit; -static BOOLEAN PressedOk; -static BOOLEAN RestartRequired; +static BOOLEAN RestartRequired = FALSE; static POINT StartLocation; // General @@ -113,241 +159,198 @@ VOID PhShowOptionsDialog( _In_ HWND ParentWindowHandle ) { - PROPSHEETHEADER propSheetHeader = { sizeof(propSheetHeader) }; - PROPSHEETPAGE propSheetPage; - HPROPSHEETPAGE pages[30]; - - propSheetHeader.dwFlags = - PSH_NOAPPLYNOW | - PSH_NOCONTEXTHELP | - PSH_USECALLBACK | - PSH_USEPSTARTPAGE; - propSheetHeader.hInstance = PhInstanceHandle; - propSheetHeader.hwndParent = ParentWindowHandle; - propSheetHeader.pszCaption = L"Options"; - propSheetHeader.nPages = 0; - propSheetHeader.pStartPage = !PhStartupParameters.ShowOptions ? L"General" : L"Advanced"; - propSheetHeader.phpage = pages; - propSheetHeader.pfnCallback = PhpOptionsPropSheetProc; - - if (!PhStartupParameters.ShowOptions) - { - // Disable all pages other than Advanced. - // General page - memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); - propSheetPage.dwSize = sizeof(PROPSHEETPAGE); - propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_OPTGENERAL); - propSheetPage.hInstance = PhInstanceHandle; - propSheetPage.pfnDlgProc = PhpOptionsGeneralDlgProc; - pages[propSheetHeader.nPages++] = CreatePropertySheetPage(&propSheetPage); - } - - // Advanced page - memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); - propSheetPage.dwSize = sizeof(PROPSHEETPAGE); - propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_OPTADVANCED); - propSheetPage.hInstance = PhInstanceHandle; - propSheetPage.pfnDlgProc = PhpOptionsAdvancedDlgProc; - pages[propSheetHeader.nPages++] = CreatePropertySheetPage(&propSheetPage); + DialogBox( + PhInstanceHandle, + MAKEINTRESOURCE(IDD_OPTIONS), + ParentWindowHandle, + PhOptionsDialogProc + ); if (!PhStartupParameters.ShowOptions) { - // Symbols page - memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); - propSheetPage.dwSize = sizeof(PROPSHEETPAGE); - propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_OPTSYMBOLS); - propSheetPage.hInstance = PhInstanceHandle; - propSheetPage.pfnDlgProc = PhpOptionsSymbolsDlgProc; - pages[propSheetHeader.nPages++] = CreatePropertySheetPage(&propSheetPage); - } + PhUpdateCachedSettings(); + ProcessHacker_SaveAllSettings(PhMainWndHandle); + PhInvalidateAllProcessNodes(); + PhReloadSettingsProcessTreeList(); + PhSiNotifyChangeSettings(); - if (!PhStartupParameters.ShowOptions) - { - // Highlighting page - memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); - propSheetPage.dwSize = sizeof(PROPSHEETPAGE); - propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_OPTHIGHLIGHTING); - propSheetPage.hInstance = PhInstanceHandle; - propSheetPage.pfnDlgProc = PhpOptionsHighlightingDlgProc; - pages[propSheetHeader.nPages++] = CreatePropertySheetPage(&propSheetPage); + if (RestartRequired) + { + if (PhShowMessage2( + PhMainWndHandle, + TDCBF_YES_BUTTON | TDCBF_NO_BUTTON, + TD_INFORMATION_ICON, + L"One or more options you have changed requires a restart of Process Hacker.", + L"Do you want to restart Process Hacker now?" + ) == IDYES) + { + ProcessHacker_PrepareForEarlyShutdown(PhMainWndHandle); + PhShellProcessHacker( + PhMainWndHandle, + L"-v", + SW_SHOW, + 0, + PH_SHELL_APP_PROPAGATE_PARAMETERS | PH_SHELL_APP_PROPAGATE_PARAMETERS_IGNORE_VISIBILITY, + 0, + NULL + ); + ProcessHacker_Destroy(PhMainWndHandle); + } + } } - - if (!PhStartupParameters.ShowOptions) + else { - // Graphs page - memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); - propSheetPage.dwSize = sizeof(PROPSHEETPAGE); - propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_OPTGRAPHS); - propSheetPage.hInstance = PhInstanceHandle; - propSheetPage.pfnDlgProc = PhpOptionsGraphsDlgProc; - pages[propSheetHeader.nPages++] = CreatePropertySheetPage(&propSheetPage); + // Main window not available. + if (PhSettingsFileName) + PhSaveSettings(PhSettingsFileName->Buffer); } +} - if (PhPluginsEnabled) - { - PH_PLUGIN_OBJECT_PROPERTIES objectProperties; - - //objectProperties.Parameter = RestartRequired; - objectProperties.NumberOfPages = propSheetHeader.nPages; - objectProperties.MaximumNumberOfPages = sizeof(pages) / sizeof(HPROPSHEETPAGE); - objectProperties.Pages = pages; +static HTREEITEM PhOptionsTreeViewAddItem( + _In_ PWSTR Text, + _In_ PVOID Context + ) +{ + TV_INSERTSTRUCT insert; - PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackOptionsWindowInitializing), &objectProperties); + memset(&insert, 0, sizeof(TV_INSERTSTRUCT)); - propSheetHeader.nPages = objectProperties.NumberOfPages; - } + insert.item.mask = TVIF_TEXT | TVIF_PARAM; + insert.hInsertAfter = TVI_LAST; + insert.hParent = TVI_ROOT; + insert.item.pszText = Text; + insert.item.lParam = (LPARAM)Context; - PageInit = FALSE; - PressedOk = FALSE; - RestartRequired = FALSE; + return TreeView_InsertItem(OptionsTreeControl, &insert); +} - if (PhStartupParameters.ShowOptions) - StartLocation = PhStartupParameters.Point; - else - StartLocation.x = MINLONG; +static PPH_OPTIONS_SECTION GetSelectedSectionTreeView( + _In_ HTREEITEM SelectedTreeItem + ) +{ + TVITEM item; - OldTaskMgrDebugger = NULL; + if (!SelectedTreeItem) + return NULL; - PhModalPropertySheet(&propSheetHeader); + item.mask = TVIF_PARAM | TVIF_HANDLE; + item.hItem = SelectedTreeItem; - if (PressedOk) - { - if (!PhStartupParameters.ShowOptions) - { - PhUpdateCachedSettings(); - ProcessHacker_SaveAllSettings(PhMainWndHandle); - PhInvalidateAllProcessNodes(); - PhReloadSettingsProcessTreeList(); - PhSiNotifyChangeSettings(); + if (!TreeView_GetItem(OptionsTreeControl, &item)) + return NULL; - if (RestartRequired) - { - if (PhShowMessage2( - PhMainWndHandle, - TDCBF_YES_BUTTON | TDCBF_NO_BUTTON, - TD_INFORMATION_ICON, - L"One or more options you have changed requires a restart of Process Hacker.", - L"Do you want to restart Process Hacker now?" - ) == IDYES) - { - ProcessHacker_PrepareForEarlyShutdown(PhMainWndHandle); - PhShellProcessHacker( - PhMainWndHandle, - L"-v", - SW_SHOW, - 0, - PH_SHELL_APP_PROPAGATE_PARAMETERS | PH_SHELL_APP_PROPAGATE_PARAMETERS_IGNORE_VISIBILITY, - 0, - NULL - ); - ProcessHacker_Destroy(PhMainWndHandle); - } - } - } - else - { - // Main window not available. - if (PhSettingsFileName) - PhSaveSettings(PhSettingsFileName->Buffer); - } - } + return (PPH_OPTIONS_SECTION)item.lParam; } -INT CALLBACK PhpOptionsPropSheetProc( +INT_PTR CALLBACK PhOptionsDialogProc( _In_ HWND hwndDlg, _In_ UINT uMsg, + _In_ WPARAM wParam, _In_ LPARAM lParam ) { switch (uMsg) { - case PSCB_BUTTONPRESSED: + case WM_INITDIALOG: { - if (lParam == PSBTN_OK) + PhOptionsWindowHandle = hwndDlg; + + SendMessage(PhOptionsWindowHandle, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER))); + SendMessage(PhOptionsWindowHandle, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER))); + + PhCenterWindow(hwndDlg, NULL); + + OptionsTreeControl = GetDlgItem(PhOptionsWindowHandle, IDC_SECTIONTREE); + ContainerControl = GetDlgItem(PhOptionsWindowHandle, IDD_CONTAINER); + + PhSetWindowStyle(GetDlgItem(hwndDlg, IDC_SEPARATOR), SS_OWNERDRAW, SS_OWNERDRAW); + + PhSetControlTheme(OptionsTreeControl, L"explorer"); + TreeView_SetExtendedStyle(OptionsTreeControl, TVS_EX_DOUBLEBUFFER, TVS_EX_DOUBLEBUFFER); + TreeView_SetImageList(OptionsTreeControl, ImageList_Create(2, 22, ILC_COLOR32, 1, 1), TVSIL_NORMAL); // leak + TreeView_SetBkColor(OptionsTreeControl, GetSysColor(COLOR_3DFACE)); + + PhInitializeLayoutManager(&WindowLayoutManager, PhOptionsWindowHandle); + + PhAddLayoutItem(&WindowLayoutManager, OptionsTreeControl, NULL, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_BOTTOM); + PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDC_SEPARATOR), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_BOTTOM); + PhAddLayoutItem(&WindowLayoutManager, ContainerControl, NULL, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); + PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(PhOptionsWindowHandle, IDC_RESET), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); + PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(PhOptionsWindowHandle, IDOK), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); + + EnableThemeDialogTexture(ContainerControl, ETDT_ENABLETAB); + { - PressedOk = TRUE; + PPH_OPTIONS_SECTION section; + + SectionList = PhCreateList(8); + CurrentSection = NULL; + + if (PhStartupParameters.ShowOptions) + { + // Disable all pages other than Advanced. + section = PhOptionsCreateInternalSection(L"Advanced", PhInstanceHandle, MAKEINTRESOURCE(IDD_OPTADVANCED), PhpOptionsAdvancedDlgProc, NULL); + } + else + { + section = PhOptionsCreateInternalSection(L"General", PhInstanceHandle, MAKEINTRESOURCE(IDD_OPTGENERAL), PhpOptionsGeneralDlgProc, NULL); + PhOptionsCreateInternalSection(L"Advanced", PhInstanceHandle, MAKEINTRESOURCE(IDD_OPTADVANCED), PhpOptionsAdvancedDlgProc, NULL); + PhOptionsCreateInternalSection(L"Symbols", PhInstanceHandle, MAKEINTRESOURCE(IDD_OPTSYMBOLS), PhpOptionsSymbolsDlgProc, NULL); + PhOptionsCreateInternalSection(L"Highlighting", PhInstanceHandle, MAKEINTRESOURCE(IDD_OPTHIGHLIGHTING), PhpOptionsHighlightingDlgProc, NULL); + PhOptionsCreateInternalSection(L"Graphs", PhInstanceHandle, MAKEINTRESOURCE(IDD_OPTGRAPHS), PhpOptionsGraphsDlgProc, NULL); + + if (PhPluginsEnabled) + { + PH_PLUGIN_OPTIONS_POINTERS pointers; + + pointers.WindowHandle = PhOptionsWindowHandle; + pointers.CreateSection = PhOptionsCreateSection; + pointers.FindSection = PhOptionsFindSection; + pointers.EnterSectionView = PhOptionsEnterSectionView; + + PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackOptionsWindowInitializing), &pointers); + } + } + + PhOptionsEnterSectionView(section); + PhOptionsOnSize(); } } break; - } - - return 0; -} + case WM_NCDESTROY: + { + ULONG i; + PPH_OPTIONS_SECTION section; -static VOID PhpPageInit( - _In_ HWND hwndDlg - ) -{ - if (!PageInit) - { - HWND optionsWindow; - HWND resetButton; - RECT clientRect; - RECT rect; - - optionsWindow = GetParent(hwndDlg); - SetWindowSubclass(optionsWindow, PhpOptionsWndProc, 0, 0); - - // Create the Reset button. - GetClientRect(optionsWindow, &clientRect); - GetWindowRect(GetDlgItem(optionsWindow, IDCANCEL), &rect); - MapWindowPoints(NULL, optionsWindow, (POINT *)&rect, 2); - resetButton = CreateWindowEx( - WS_EX_NOPARENTNOTIFY, - WC_BUTTON, - L"Reset", - WS_CHILD | WS_VISIBLE | WS_TABSTOP, - clientRect.right - rect.right, - rect.top, - rect.right - rect.left, - rect.bottom - rect.top, - optionsWindow, - (HMENU)IDC_RESET, - PhInstanceHandle, - NULL - ); - SendMessage(resetButton, WM_SETFONT, SendMessage(GetDlgItem(optionsWindow, IDCANCEL), WM_GETFONT, 0, 0), TRUE); + for (i = 0; i < SectionList->Count; i++) + { + section = SectionList->Items[i]; + PhOptionsDestroySection(section); + } - if (PhStartupParameters.ShowOptions) - ShowWindow(resetButton, SW_HIDE); + PhDereferenceObject(SectionList); + SectionList = NULL; - // Set the location of the options window. - if (StartLocation.x == MINLONG) - { - PhCenterWindow(optionsWindow, GetParent(optionsWindow)); + PhDeleteLayoutManager(&WindowLayoutManager); } - else + break; + case WM_SIZE: { - SetWindowPos(optionsWindow, NULL, StartLocation.x, StartLocation.y, 0, 0, - SWP_NOACTIVATE | SWP_NOREDRAW | SWP_NOSIZE | SWP_NOZORDER); + PhOptionsOnSize(); } - - PageInit = TRUE; - } -} - -LRESULT CALLBACK PhpOptionsWndProc( - _In_ HWND hwnd, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam, - _In_ UINT_PTR uIdSubclass, - _In_ ULONG_PTR dwRefData - ) -{ - switch (uMsg) - { - case WM_DESTROY: - RemoveWindowSubclass(hwnd, PhpOptionsWndProc, uIdSubclass); break; case WM_COMMAND: { - switch (LOWORD(wParam)) + switch (GET_WM_COMMAND_ID(wParam, lParam)) { + case IDCANCEL: + case IDOK: + EndDialog(hwndDlg, IDOK); + break; case IDC_RESET: { if (PhShowMessage2( - hwnd, + hwndDlg, TDCBF_YES_BUTTON | TDCBF_NO_BUTTON, TD_WARNING_ICON, L"Do you want to reset all settings and restart Process Hacker?", @@ -377,9 +380,254 @@ LRESULT CALLBACK PhpOptionsWndProc( } } break; + case WM_DRAWITEM: + { + PDRAWITEMSTRUCT drawInfo = (PDRAWITEMSTRUCT)lParam; + + if (drawInfo->CtlID == IDC_SEPARATOR) + { + RECT rect; + + rect = drawInfo->rcItem; + rect.right = 2; + FillRect(drawInfo->hDC, &rect, GetSysColorBrush(COLOR_3DHIGHLIGHT)); + rect.left += 1; + FillRect(drawInfo->hDC, &rect, GetSysColorBrush(COLOR_3DSHADOW)); + return TRUE; + } + } + break; + case WM_NOTIFY: + { + LPNMHDR header = (LPNMHDR)lParam; + + switch (header->code) + { + case TVN_SELCHANGED: + { + LPNMTREEVIEW treeview = (LPNMTREEVIEW)lParam; + PPH_OPTIONS_SECTION section; + + if (section = GetSelectedSectionTreeView(treeview->itemNew.hItem)) + { + PhOptionsEnterSectionView(section); + } + } + break; + case NM_SETCURSOR: + { + if (header->hwndFrom == OptionsTreeControl) + { + HCURSOR cursor = (HCURSOR)LoadImage( + NULL, + IDC_ARROW, + IMAGE_CURSOR, + 0, + 0, + LR_SHARED + ); + + if (cursor != GetCursor()) + { + SetCursor(cursor); + } + + SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, TRUE); + return TRUE; + } + } + break; + } + } + break; } - return DefSubclassProc(hwnd, uMsg, wParam, lParam); + return FALSE; +} + +VOID PhOptionsOnSize( + VOID + ) +{ + PhLayoutManagerLayout(&WindowLayoutManager); + + if (SectionList && SectionList->Count != 0) + { + PhOptionsLayoutSectionView(); + } +} + +PPH_OPTIONS_SECTION PhOptionsCreateSection( + _In_ PWSTR Name, + _In_ PVOID Instance, + _In_ PWSTR Template, + _In_ DLGPROC DialogProc, + _In_ PVOID Parameter + ) +{ + PPH_OPTIONS_SECTION section; + + section = PhAllocate(sizeof(PH_OPTIONS_SECTION)); + memset(section, 0, sizeof(PH_OPTIONS_SECTION)); + + PhInitializeStringRefLongHint(§ion->Name, Name); + + section->Instance = Instance; + section->Template = Template; + section->DialogProc = DialogProc; + section->Parameter = Parameter; + + PhAddItemList(SectionList, section); + + PhOptionsTreeViewAddItem(Name, section); + + return section; +} + +PPH_OPTIONS_SECTION PhOptionsCreateInternalSection( + _In_ PWSTR Name, + _In_ PVOID Instance, + _In_ PWSTR Template, + _In_ DLGPROC DialogProc, + _In_ PVOID Parameter + ) +{ + PPH_OPTIONS_SECTION section; + + section = PhOptionsCreateSection( + Name, + Instance, + Template, + DialogProc, + Parameter + ); + + section->DialogHandle = PhCreateDialogFromTemplate( + ContainerControl, + DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD, + Instance, + Template, + DialogProc, + Parameter + ); + + return section; +} + +VOID PhOptionsDestroySection( + _In_ PPH_OPTIONS_SECTION Section + ) +{ + PhFree(Section); +} + +PPH_OPTIONS_SECTION PhOptionsFindSection( + _In_ PPH_STRINGREF Name + ) +{ + ULONG i; + PPH_OPTIONS_SECTION section; + + for (i = 0; i < SectionList->Count; i++) + { + section = SectionList->Items[i]; + + if (PhEqualStringRef(§ion->Name, Name, TRUE)) + return section; + } + + return NULL; +} + +VOID PhOptionsLayoutSectionView( + VOID + ) +{ + if (CurrentSection && CurrentSection->DialogHandle) + { + RECT clientRect; + + GetClientRect(ContainerControl, &clientRect); + + SetWindowPos( + CurrentSection->DialogHandle, + NULL, + 0, + 0, + clientRect.right - clientRect.left, + clientRect.bottom - clientRect.top, + SWP_NOACTIVATE | SWP_NOZORDER + ); + } +} + +VOID PhOptionsEnterSectionView( + _In_ PPH_OPTIONS_SECTION NewSection + ) +{ + ULONG i; + PPH_OPTIONS_SECTION section; + PPH_OPTIONS_SECTION oldSection; + HDWP deferHandle; + HDWP containerDeferHandle; + + if (CurrentSection == NewSection) + return; + + oldSection = CurrentSection; + CurrentSection = NewSection; + + deferHandle = BeginDeferWindowPos(SectionList->Count); + containerDeferHandle = BeginDeferWindowPos(SectionList->Count); + + PhOptionsEnterSectionViewInner(NewSection, &deferHandle, &containerDeferHandle); + PhOptionsLayoutSectionView(); + + for (i = 0; i < SectionList->Count; i++) + { + section = SectionList->Items[i]; + + if (section != NewSection) + PhOptionsEnterSectionViewInner(section, &deferHandle, &containerDeferHandle); + } + + EndDeferWindowPos(deferHandle); + EndDeferWindowPos(containerDeferHandle); + + if (NewSection->DialogHandle) + RedrawWindow(NewSection->DialogHandle, NULL, NULL, RDW_ERASE | RDW_INVALIDATE | RDW_ALLCHILDREN | RDW_UPDATENOW); +} + +VOID PhOptionsEnterSectionViewInner( + _In_ PPH_OPTIONS_SECTION Section, + _Inout_ HDWP *DeferHandle, + _Inout_ HDWP *ContainerDeferHandle + ) +{ + if (Section == CurrentSection && !Section->DialogHandle) + PhOptionsCreateSectionDialog(Section); + + if (Section->DialogHandle) + { + if (Section == CurrentSection) + *ContainerDeferHandle = DeferWindowPos(*ContainerDeferHandle, Section->DialogHandle, NULL, 0, 0, 0, 0, SWP_SHOWWINDOW_ONLY | SWP_NOREDRAW); + else + *ContainerDeferHandle = DeferWindowPos(*ContainerDeferHandle, Section->DialogHandle, NULL, 0, 0, 0, 0, SWP_HIDEWINDOW_ONLY | SWP_NOREDRAW); + } +} + +VOID PhOptionsCreateSectionDialog( + _In_ PPH_OPTIONS_SECTION Section + ) +{ + Section->DialogHandle = PhCreateDialogFromTemplate( + ContainerControl, + DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD, + Section->Instance, + Section->Template, + Section->DialogProc, + Section->Parameter + ); } #define SetDlgItemCheckForSetting(hwndDlg, Id, Name) \ @@ -394,11 +642,10 @@ LRESULT CALLBACK PhpOptionsWndProc( RestartRequired = TRUE; \ PhSetIntegerSetting(Name, __newValue); \ } while (0) -#define DialogChanged PropSheet_Changed(GetParent(hwndDlg), hwndDlg) static BOOLEAN GetCurrentFont( _Out_ PLOGFONT Font - ) +) { BOOLEAN result; PPH_STRING fontHexString; @@ -500,7 +747,6 @@ static VOID WriteCurrentUserRun( } } - INT_PTR CALLBACK PhpOptionsGeneralDlgProc( _In_ HWND hwndDlg, _In_ UINT uMsg, @@ -516,8 +762,6 @@ INT_PTR CALLBACK PhpOptionsGeneralDlgProc( ULONG i; LOGFONT font; - PhpPageInit(hwndDlg); - comboBoxHandle = GetDlgItem(hwndDlg, IDC_MAXSIZEUNIT); for (i = 0; i < sizeof(PhSizeUnitNames) / sizeof(PWSTR); i++) @@ -567,6 +811,31 @@ INT_PTR CALLBACK PhpOptionsGeneralDlgProc( break; case WM_DESTROY: { + BOOLEAN startAtLogon; + BOOLEAN startHidden; + + PhSetStringSetting2(L"SearchEngine", &(PhaGetDlgItemText(hwndDlg, IDC_SEARCHENGINE)->sr)); + PhSetStringSetting2(L"ProgramInspectExecutables", &(PhaGetDlgItemText(hwndDlg, IDC_PEVIEWER)->sr)); + PhSetIntegerSetting(L"MaxSizeUnit", PhMaxSizeUnit = ComboBox_GetCurSel(GetDlgItem(hwndDlg, IDC_MAXSIZEUNIT))); + PhSetIntegerSetting(L"IconProcesses", GetDlgItemInt(hwndDlg, IDC_ICONPROCESSES, NULL, FALSE)); + SetSettingForDlgItemCheck(hwndDlg, IDC_ALLOWONLYONEINSTANCE, L"AllowOnlyOneInstance"); + SetSettingForDlgItemCheck(hwndDlg, IDC_HIDEONCLOSE, L"HideOnClose"); + SetSettingForDlgItemCheck(hwndDlg, IDC_HIDEONMINIMIZE, L"HideOnMinimize"); + SetSettingForDlgItemCheck(hwndDlg, IDC_COLLAPSESERVICES, L"CollapseServicesOnStart"); + SetSettingForDlgItemCheck(hwndDlg, IDC_ICONSINGLECLICK, L"IconSingleClick"); + SetSettingForDlgItemCheck(hwndDlg, IDC_ICONTOGGLESVISIBILITY, L"IconTogglesVisibility"); + SetSettingForDlgItemCheckRestartRequired(hwndDlg, IDC_ENABLEPLUGINS, L"EnablePlugins"); + + startAtLogon = Button_GetCheck(GetDlgItem(hwndDlg, IDC_STARTATLOGON)) == BST_CHECKED; + startHidden = Button_GetCheck(GetDlgItem(hwndDlg, IDC_STARTHIDDEN)) == BST_CHECKED; + WriteCurrentUserRun(startAtLogon, startHidden); + + if (NewFontSelection) + { + PhSetStringSetting2(L"Font", &NewFontSelection->sr); + PostMessage(PhMainWndHandle, WM_PH_UPDATE_FONT, 0, 0); + } + if (CurrentFontInstance) DeleteObject(CurrentFontInstance); @@ -575,7 +844,7 @@ INT_PTR CALLBACK PhpOptionsGeneralDlgProc( break; case WM_COMMAND: { - switch (LOWORD(wParam)) + switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDC_STARTATLOGON: { @@ -618,45 +887,6 @@ INT_PTR CALLBACK PhpOptionsGeneralDlgProc( } } break; - case WM_NOTIFY: - { - LPNMHDR header = (LPNMHDR)lParam; - - switch (header->code) - { - case PSN_APPLY: - { - BOOLEAN startAtLogon; - BOOLEAN startHidden; - - PhSetStringSetting2(L"SearchEngine", &(PhaGetDlgItemText(hwndDlg, IDC_SEARCHENGINE)->sr)); - PhSetStringSetting2(L"ProgramInspectExecutables", &(PhaGetDlgItemText(hwndDlg, IDC_PEVIEWER)->sr)); - PhSetIntegerSetting(L"MaxSizeUnit", PhMaxSizeUnit = ComboBox_GetCurSel(GetDlgItem(hwndDlg, IDC_MAXSIZEUNIT))); - PhSetIntegerSetting(L"IconProcesses", GetDlgItemInt(hwndDlg, IDC_ICONPROCESSES, NULL, FALSE)); - SetSettingForDlgItemCheck(hwndDlg, IDC_ALLOWONLYONEINSTANCE, L"AllowOnlyOneInstance"); - SetSettingForDlgItemCheck(hwndDlg, IDC_HIDEONCLOSE, L"HideOnClose"); - SetSettingForDlgItemCheck(hwndDlg, IDC_HIDEONMINIMIZE, L"HideOnMinimize"); - SetSettingForDlgItemCheck(hwndDlg, IDC_COLLAPSESERVICES, L"CollapseServicesOnStart"); - SetSettingForDlgItemCheck(hwndDlg, IDC_ICONSINGLECLICK, L"IconSingleClick"); - SetSettingForDlgItemCheck(hwndDlg, IDC_ICONTOGGLESVISIBILITY, L"IconTogglesVisibility"); - SetSettingForDlgItemCheckRestartRequired(hwndDlg, IDC_ENABLEPLUGINS, L"EnablePlugins"); - - startAtLogon = Button_GetCheck(GetDlgItem(hwndDlg, IDC_STARTATLOGON)) == BST_CHECKED; - startHidden = Button_GetCheck(GetDlgItem(hwndDlg, IDC_STARTHIDDEN)) == BST_CHECKED; - WriteCurrentUserRun(startAtLogon, startHidden); - - if (NewFontSelection) - { - PhSetStringSetting2(L"Font", &NewFontSelection->sr); - PostMessage(PhMainWndHandle, WM_PH_UPDATE_FONT, 0, 0); - } - - SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_NOERROR); - } - return TRUE; - } - } - break; } return FALSE; @@ -876,7 +1106,6 @@ INT_PTR CALLBACK PhpOptionsAdvancedDlgProc( { case WM_INITDIALOG: { - PhpPageInit(hwndDlg); PhpAdvancedPageLoad(hwndDlg); if (PhStartupParameters.ShowOptions) @@ -898,6 +1127,8 @@ INT_PTR CALLBACK PhpOptionsAdvancedDlgProc( break; case WM_DESTROY: { + PhpAdvancedPageSave(hwndDlg); + PhClearReference(&OldTaskMgrDebugger); } break; @@ -915,7 +1146,7 @@ INT_PTR CALLBACK PhpOptionsAdvancedDlgProc( GetWindowRect(GetParent(hwndDlg), &windowRect); WindowHandleForElevate = hwndDlg; - + PhCreateThread2(PhpElevateAdvancedThreadStart, PhFormatString( L"-showoptions -hwnd %Ix -point %u,%u", (ULONG_PTR)GetParent(hwndDlg), @@ -932,21 +1163,6 @@ INT_PTR CALLBACK PhpOptionsAdvancedDlgProc( } } break; - case WM_NOTIFY: - { - LPNMHDR header = (LPNMHDR)lParam; - - switch (header->code) - { - case PSN_APPLY: - { - PhpAdvancedPageSave(hwndDlg); - SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_NOERROR); - } - return TRUE; - } - } - break; case WM_PH_CHILD_EXIT: { PhpAdvancedPageLoad(hwndDlg); @@ -964,16 +1180,21 @@ INT_PTR CALLBACK PhpOptionsSymbolsDlgProc( _In_ LPARAM lParam ) { + static PH_LAYOUT_MANAGER LayoutManager; + switch (uMsg) { case WM_INITDIALOG: { - PhpPageInit(hwndDlg); - SetDlgItemText(hwndDlg, IDC_DBGHELPPATH, PhaGetStringSetting(L"DbgHelpPath")->Buffer); SetDlgItemText(hwndDlg, IDC_DBGHELPSEARCHPATH, PhaGetStringSetting(L"DbgHelpSearchPath")->Buffer); SetDlgItemCheckForSetting(hwndDlg, IDC_UNDECORATESYMBOLS, L"DbgHelpUndecorate"); + + PhInitializeLayoutManager(&LayoutManager, hwndDlg); + PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDC_DBGHELPPATH), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); + PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDC_BROWSE), NULL, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); + PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDC_DBGHELPSEARCHPATH), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); } break; case WM_COMMAND: @@ -1008,27 +1229,23 @@ INT_PTR CALLBACK PhpOptionsSymbolsDlgProc( } } break; - case WM_NOTIFY: + case WM_SIZE: { - LPNMHDR header = (LPNMHDR)lParam; - - switch (header->code) - { - case PSN_APPLY: - { - PPH_STRING dbgHelpPath = PhaGetDlgItemText(hwndDlg, IDC_DBGHELPPATH); + PhLayoutManagerLayout(&LayoutManager); + } + break; + case WM_DESTROY: + { + PPH_STRING dbgHelpPath = PhaGetDlgItemText(hwndDlg, IDC_DBGHELPPATH); - if (!PhEqualString(dbgHelpPath, PhaGetStringSetting(L"DbgHelpPath"), TRUE)) - RestartRequired = TRUE; + if (!PhEqualString(dbgHelpPath, PhaGetStringSetting(L"DbgHelpPath"), TRUE)) + RestartRequired = TRUE; - PhSetStringSetting2(L"DbgHelpPath", &dbgHelpPath->sr); - PhSetStringSetting2(L"DbgHelpSearchPath", &(PhaGetDlgItemText(hwndDlg, IDC_DBGHELPSEARCHPATH)->sr)); - SetSettingForDlgItemCheck(hwndDlg, IDC_UNDECORATESYMBOLS, L"DbgHelpUndecorate"); + PhSetStringSetting2(L"DbgHelpPath", &dbgHelpPath->sr); + PhSetStringSetting2(L"DbgHelpSearchPath", &(PhaGetDlgItemText(hwndDlg, IDC_DBGHELPSEARCHPATH)->sr)); + SetSettingForDlgItemCheck(hwndDlg, IDC_UNDECORATESYMBOLS, L"DbgHelpUndecorate"); - SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_NOERROR); - } - return TRUE; - } + PhDeleteLayoutManager(&LayoutManager); } break; } @@ -1092,14 +1309,12 @@ INT_PTR CALLBACK PhpOptionsHighlightingDlgProc( _In_ LPARAM lParam ) { + static PH_LAYOUT_MANAGER LayoutManager; + switch (uMsg) { case WM_INITDIALOG: { - ULONG i; - - PhpPageInit(hwndDlg); - // Highlighting Duration SetDlgItemInt(hwndDlg, IDC_HIGHLIGHTINGDURATION, PhCsHighlightingDuration, FALSE); @@ -1117,7 +1332,7 @@ INT_PTR CALLBACK PhpOptionsHighlightingDlgProc( PhSetExtendedListView(HighlightingListViewHandle); ExtendedListView_SetItemColorFunction(HighlightingListViewHandle, PhpColorItemColorFunction); - for (i = 0; i < sizeof(ColorItems) / sizeof(COLOR_ITEM); i++) + for (ULONG i = 0; i < ARRAYSIZE(ColorItems); i++) { INT lvItemIndex; @@ -1126,25 +1341,50 @@ INT_PTR CALLBACK PhpOptionsHighlightingDlgProc( ColorItems[i].CurrentUse = !!PhGetIntegerSetting(ColorItems[i].UseSettingName); ListView_SetCheckState(HighlightingListViewHandle, lvItemIndex, ColorItems[i].CurrentUse); } + + PhInitializeLayoutManager(&LayoutManager, hwndDlg); + PhAddLayoutItem(&LayoutManager, HighlightingListViewHandle, NULL, PH_ANCHOR_ALL); + PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDC_INFO), NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_LEFT | PH_LAYOUT_FORCE_INVALIDATE); + PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDC_ENABLEALL), NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_RIGHT); + PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDC_DISABLEALL), NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_RIGHT); + } + break; + case WM_DESTROY: + { + PH_SET_INTEGER_CACHED_SETTING(HighlightingDuration, GetDlgItemInt(hwndDlg, IDC_HIGHLIGHTINGDURATION, NULL, FALSE)); + PH_SET_INTEGER_CACHED_SETTING(ColorNew, ColorBox_GetColor(GetDlgItem(hwndDlg, IDC_NEWOBJECTS))); + PH_SET_INTEGER_CACHED_SETTING(ColorRemoved, ColorBox_GetColor(GetDlgItem(hwndDlg, IDC_REMOVEDOBJECTS))); + + for (ULONG i = 0; i < ARRAYSIZE(ColorItems); i++) + { + ColorItems[i].CurrentUse = !!ListView_GetCheckState(HighlightingListViewHandle, i); + PhSetIntegerSetting(ColorItems[i].SettingName, ColorItems[i].CurrentColor); + PhSetIntegerSetting(ColorItems[i].UseSettingName, ColorItems[i].CurrentUse); + } + + PhDeleteLayoutManager(&LayoutManager); + } + break; + case WM_SIZE: + { + PhLayoutManagerLayout(&LayoutManager); + + ExtendedListView_SetColumnWidth(HighlightingListViewHandle, 0, ELVSCW_AUTOSIZE_REMAININGSPACE); } break; case WM_COMMAND: { - switch (LOWORD(wParam)) + switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDC_ENABLEALL: { - ULONG i; - - for (i = 0; i < sizeof(ColorItems) / sizeof(COLOR_ITEM); i++) + for (ULONG i = 0; i < ARRAYSIZE(ColorItems); i++) ListView_SetCheckState(HighlightingListViewHandle, i, TRUE); } break; case IDC_DISABLEALL: { - ULONG i; - - for (i = 0; i < sizeof(ColorItems) / sizeof(COLOR_ITEM); i++) + for (ULONG i = 0; i < ARRAYSIZE(ColorItems); i++) ListView_SetCheckState(HighlightingListViewHandle, i, FALSE); } break; @@ -1157,24 +1397,6 @@ INT_PTR CALLBACK PhpOptionsHighlightingDlgProc( switch (header->code) { - case PSN_APPLY: - { - ULONG i; - - PH_SET_INTEGER_CACHED_SETTING(HighlightingDuration, GetDlgItemInt(hwndDlg, IDC_HIGHLIGHTINGDURATION, NULL, FALSE)); - PH_SET_INTEGER_CACHED_SETTING(ColorNew, ColorBox_GetColor(GetDlgItem(hwndDlg, IDC_NEWOBJECTS))); - PH_SET_INTEGER_CACHED_SETTING(ColorRemoved, ColorBox_GetColor(GetDlgItem(hwndDlg, IDC_REMOVEDOBJECTS))); - - for (i = 0; i < sizeof(ColorItems) / sizeof(COLOR_ITEM); i++) - { - ColorItems[i].CurrentUse = !!ListView_GetCheckState(HighlightingListViewHandle, i); - PhSetIntegerSetting(ColorItems[i].SettingName, ColorItems[i].CurrentColor); - PhSetIntegerSetting(ColorItems[i].UseSettingName, ColorItems[i].CurrentUse); - } - - SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_NOERROR); - } - return TRUE; case NM_DBLCLK: { if (header->hwndFrom == HighlightingListViewHandle) @@ -1183,7 +1405,7 @@ INT_PTR CALLBACK PhpOptionsHighlightingDlgProc( if (item = PhGetSelectedListViewItemParam(HighlightingListViewHandle)) { - CHOOSECOLOR chooseColor = { sizeof(chooseColor) }; + CHOOSECOLOR chooseColor = { sizeof(CHOOSECOLOR) }; COLORREF customColors[16] = { 0 }; chooseColor.hwndOwner = hwndDlg; @@ -1233,8 +1455,6 @@ INT_PTR CALLBACK PhpOptionsGraphsDlgProc( { case WM_INITDIALOG: { - PhpPageInit(hwndDlg); - // Show Text SetDlgItemCheckForSetting(hwndDlg, IDC_SHOWTEXT, L"GraphShowText"); SetDlgItemCheckForSetting(hwndDlg, IDC_USEOLDCOLORS, L"GraphColorMode"); @@ -1248,28 +1468,17 @@ INT_PTR CALLBACK PhpOptionsGraphsDlgProc( ColorBox_SetColor(GetDlgItem(hwndDlg, IDC_PHYSICAL), PhCsColorPhysical); } break; - case WM_NOTIFY: + case WM_DESTROY: { - LPNMHDR header = (LPNMHDR)lParam; - - switch (header->code) - { - case PSN_APPLY: - { - SetSettingForDlgItemCheck(hwndDlg, IDC_SHOWTEXT, L"GraphShowText"); - SetSettingForDlgItemCheck(hwndDlg, IDC_USEOLDCOLORS, L"GraphColorMode"); - SetSettingForDlgItemCheck(hwndDlg, IDC_SHOWCOMMITINSUMMARY, L"ShowCommitInSummary"); - PH_SET_INTEGER_CACHED_SETTING(ColorCpuUser, ColorBox_GetColor(GetDlgItem(hwndDlg, IDC_CPUUSER))); - PH_SET_INTEGER_CACHED_SETTING(ColorCpuKernel, ColorBox_GetColor(GetDlgItem(hwndDlg, IDC_CPUKERNEL))); - PH_SET_INTEGER_CACHED_SETTING(ColorIoReadOther, ColorBox_GetColor(GetDlgItem(hwndDlg, IDC_IORO))); - PH_SET_INTEGER_CACHED_SETTING(ColorIoWrite, ColorBox_GetColor(GetDlgItem(hwndDlg, IDC_IOW))); - PH_SET_INTEGER_CACHED_SETTING(ColorPrivate, ColorBox_GetColor(GetDlgItem(hwndDlg, IDC_PRIVATE))); - PH_SET_INTEGER_CACHED_SETTING(ColorPhysical, ColorBox_GetColor(GetDlgItem(hwndDlg, IDC_PHYSICAL))); - - SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_NOERROR); - } - return TRUE; - } + SetSettingForDlgItemCheck(hwndDlg, IDC_SHOWTEXT, L"GraphShowText"); + SetSettingForDlgItemCheck(hwndDlg, IDC_USEOLDCOLORS, L"GraphColorMode"); + SetSettingForDlgItemCheck(hwndDlg, IDC_SHOWCOMMITINSUMMARY, L"ShowCommitInSummary"); + PH_SET_INTEGER_CACHED_SETTING(ColorCpuUser, ColorBox_GetColor(GetDlgItem(hwndDlg, IDC_CPUUSER))); + PH_SET_INTEGER_CACHED_SETTING(ColorCpuKernel, ColorBox_GetColor(GetDlgItem(hwndDlg, IDC_CPUKERNEL))); + PH_SET_INTEGER_CACHED_SETTING(ColorIoReadOther, ColorBox_GetColor(GetDlgItem(hwndDlg, IDC_IORO))); + PH_SET_INTEGER_CACHED_SETTING(ColorIoWrite, ColorBox_GetColor(GetDlgItem(hwndDlg, IDC_IOW))); + PH_SET_INTEGER_CACHED_SETTING(ColorPrivate, ColorBox_GetColor(GetDlgItem(hwndDlg, IDC_PRIVATE))); + PH_SET_INTEGER_CACHED_SETTING(ColorPhysical, ColorBox_GetColor(GetDlgItem(hwndDlg, IDC_PHYSICAL))); } break; } diff --git a/ProcessHacker/resource.h b/ProcessHacker/resource.h index 00012e75a9d9..7ab4883d8fa3 100644 --- a/ProcessHacker/resource.h +++ b/ProcessHacker/resource.h @@ -124,6 +124,7 @@ #define IDB_SEARCH_INACTIVE 224 #define IDB_SEARCH_ACTIVE_BMP 225 #define IDB_SEARCH_INACTIVE_BMP 226 +#define IDD_OPTIONS 227 #define IDC_TERMINATE 1003 #define IDC_FILEICON 1005 #define IDC_FILE 1006 @@ -535,6 +536,8 @@ #define IDC_FILTEROPTIONS 1389 #define IDC_FILTERTYPE 1390 #define IDC_TREELIST 1391 +#define IDC_SECTIONTREE 1393 +#define IDC_INFO 1396 #define ID_HACKER_EXIT 40001 #define ID_PROCESS_PROPERTIES 40006 #define ID_PROCESS_TERMINATE 40007 @@ -740,9 +743,9 @@ // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 233 +#define _APS_NEXT_RESOURCE_VALUE 238 #define _APS_NEXT_COMMAND_VALUE 40297 -#define _APS_NEXT_CONTROL_VALUE 1392 +#define _APS_NEXT_CONTROL_VALUE 1397 #define _APS_NEXT_SYMED_VALUE 169 #endif #endif diff --git a/plugins/ExtendedNotifications/ExtendedNotifications.rc b/plugins/ExtendedNotifications/ExtendedNotifications.rc index ce5be6f4bd35..0c7e73170777 100644 --- a/plugins/ExtendedNotifications/ExtendedNotifications.rc +++ b/plugins/ExtendedNotifications/ExtendedNotifications.rc @@ -101,7 +101,7 @@ BEGIN CONTROL "Exclude",IDC_EXCLUDE,"Button",BS_AUTORADIOBUTTON,207,153,41,10 PUSHBUTTON "Add/Update",IDC_ADD,145,168,50,14 PUSHBUTTON "Remove",IDC_REMOVE,198,168,50,14 - LTEXT "Examples:\nnote*.exe\nC:\\Windows\\system32\\cmd.exe\nC:\\Windows\\*",IDC_STATIC,7,186,241,36 + LTEXT "Examples:\nnote*.exe\nC:\\Windows\\system32\\cmd.exe\nC:\\Windows\\*",IDC_INFO,7,186,241,36 END IDD_SERVICES DIALOGEX 0, 0, 255, 229 @@ -118,15 +118,15 @@ BEGIN CONTROL "Exclude",IDC_EXCLUDE,"Button",BS_AUTORADIOBUTTON,207,153,41,10 PUSHBUTTON "Add/Update",IDC_ADD,145,168,50,14 PUSHBUTTON "Remove",IDC_REMOVE,198,168,50,14 - LTEXT "Examples:\nWdi*\nseclogon",IDC_STATIC,7,186,241,36 + LTEXT "Examples:\nWdi*\nseclogon",IDC_INFO,7,186,241,36 END -IDD_LOGGING DIALOGEX 0, 0, 255, 229 +IDD_LOGGING DIALOGEX 0, 0, 255, 69 STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Logging" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN - GROUPBOX "File",IDC_STATIC,7,7,241,53 + GROUPBOX "File",IDC_INFO,7,7,241,53 LTEXT "Log all events to this file (leave blank to disable this feature):",IDC_STATIC,13,18,196,8 EDITTEXT IDC_LOGFILENAME,13,29,178,12,ES_AUTOHSCROLL PUSHBUTTON "Browse...",IDC_BROWSE,194,28,50,14 @@ -173,7 +173,7 @@ BEGIN LEFTMARGIN, 7 RIGHTMARGIN, 248 TOPMARGIN, 7 - BOTTOMMARGIN, 222 + BOTTOMMARGIN, 62 END IDD_GROWL, DIALOG diff --git a/plugins/ExtendedNotifications/main.c b/plugins/ExtendedNotifications/main.c index b272d100f136..1ec31acc37d7 100644 --- a/plugins/ExtendedNotifications/main.c +++ b/plugins/ExtendedNotifications/main.c @@ -3,6 +3,7 @@ * main program * * Copyright (C) 2010-2011 wj32 + * Copyright (C) 2017 dmex * * This file is part of Process Hacker. * @@ -122,7 +123,6 @@ LOGICAL DllMain( info->Author = L"wj32"; info->Description = L"Filters notifications."; info->Url = L"https://wj32.org/processhacker/forums/viewtopic.php?t=1112"; - info->HasOptions = TRUE; PhRegisterCallback( PhGetPluginCallback(PluginInstance, PluginCallbackLoad), @@ -131,7 +131,7 @@ LOGICAL DllMain( &PluginLoadCallbackRegistration ); PhRegisterCallback( - PhGetPluginCallback(PluginInstance, PluginCallbackShowOptions), + PhGetGeneralCallback(GeneralCallbackOptionsWindowInitializing), ShowOptionsCallback, NULL, &PluginShowOptionsCallbackRegistration @@ -339,53 +339,36 @@ VOID NTAPI ShowOptionsCallback( _In_opt_ PVOID Context ) { - PROPSHEETHEADER propSheetHeader = { sizeof(propSheetHeader) }; - PROPSHEETPAGE propSheetPage; - HPROPSHEETPAGE pages[4]; - - propSheetHeader.dwFlags = - PSH_NOAPPLYNOW | - PSH_NOCONTEXTHELP | - PSH_PROPTITLE; - propSheetHeader.hwndParent = (HWND)Parameter; - propSheetHeader.pszCaption = L"Extended Notifications"; - propSheetHeader.nPages = 0; - propSheetHeader.nStartPage = 0; - propSheetHeader.phpage = pages; - - // Processes - memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); - propSheetPage.dwSize = sizeof(PROPSHEETPAGE); - propSheetPage.hInstance = PluginInstance->DllBase; - propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_PROCESSES); - propSheetPage.pfnDlgProc = ProcessesDlgProc; - pages[propSheetHeader.nPages++] = CreatePropertySheetPage(&propSheetPage); - - // Services - memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); - propSheetPage.dwSize = sizeof(PROPSHEETPAGE); - propSheetPage.hInstance = PluginInstance->DllBase; - propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_SERVICES); - propSheetPage.pfnDlgProc = ServicesDlgProc; - pages[propSheetHeader.nPages++] = CreatePropertySheetPage(&propSheetPage); - - // Logging - memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); - propSheetPage.dwSize = sizeof(PROPSHEETPAGE); - propSheetPage.hInstance = PluginInstance->DllBase; - propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_LOGGING); - propSheetPage.pfnDlgProc = LoggingDlgProc; - pages[propSheetHeader.nPages++] = CreatePropertySheetPage(&propSheetPage); - - // Growl - memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); - propSheetPage.dwSize = sizeof(PROPSHEETPAGE); - propSheetPage.hInstance = PluginInstance->DllBase; - propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_GROWL); - propSheetPage.pfnDlgProc = GrowlDlgProc; - pages[propSheetHeader.nPages++] = CreatePropertySheetPage(&propSheetPage); - - PhModalPropertySheet(&propSheetHeader); + PPH_PLUGIN_OPTIONS_POINTERS optionsEntry = (PPH_PLUGIN_OPTIONS_POINTERS)Parameter; + + optionsEntry->CreateSection( + L"Notifications - Processes", + PluginInstance->DllBase, + MAKEINTRESOURCE(IDD_PROCESSES), + ProcessesDlgProc, + NULL + ); + optionsEntry->CreateSection( + L"Notifications - Services", + PluginInstance->DllBase, + MAKEINTRESOURCE(IDD_SERVICES), + ServicesDlgProc, + NULL + ); + optionsEntry->CreateSection( + L"Notifications - Logging", + PluginInstance->DllBase, + MAKEINTRESOURCE(IDD_LOGGING), + LoggingDlgProc, + NULL + ); + optionsEntry->CreateSection( + L"Notifications - Growl", + PluginInstance->DllBase, + MAKEINTRESOURCE(IDD_GROWL), + GrowlDlgProc, + NULL + ); } BOOLEAN MatchFilterList( @@ -875,6 +858,7 @@ INT_PTR CALLBACK ProcessesDlgProc( _In_ LPARAM lParam ) { + static PH_LAYOUT_MANAGER LayoutManager; INT_PTR result; if (result = HandleCommonMessages(hwndDlg, uMsg, wParam, lParam, @@ -885,42 +869,44 @@ INT_PTR CALLBACK ProcessesDlgProc( { case WM_INITDIALOG: { - PhCenterWindow(GetParent(hwndDlg), GetParent(GetParent(hwndDlg))); - EditingProcessFilterList = PhCreateList(ProcessFilterList->Count + 10); CopyFilterList(EditingProcessFilterList, ProcessFilterList); + PhInitializeLayoutManager(&LayoutManager, hwndDlg); + PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDC_LIST), NULL, PH_ANCHOR_ALL); + PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDC_MOVEUP), NULL, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); + PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDC_MOVEDOWN), NULL, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); + PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDC_TEXT), NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_LEFT | PH_ANCHOR_RIGHT); + PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDC_INCLUDE), NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_RIGHT); + PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDC_EXCLUDE), NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_RIGHT); + PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDC_ADD), NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_RIGHT); + PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDC_REMOVE), NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_RIGHT); + PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDC_INFO), NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_LEFT); + AddEntriesToListBox(GetDlgItem(hwndDlg, IDC_LIST), EditingProcessFilterList); } break; case WM_DESTROY: { + PPH_STRING string; + + ClearFilterList(ProcessFilterList); + CopyFilterList(ProcessFilterList, EditingProcessFilterList); + + string = SaveFilterList(ProcessFilterList); + PhSetStringSetting2(SETTING_NAME_PROCESS_LIST, &string->sr); + PhDereferenceObject(string); + ClearFilterList(EditingProcessFilterList); PhDereferenceObject(EditingProcessFilterList); EditingProcessFilterList = NULL; + + PhDeleteLayoutManager(&LayoutManager); } break; - case WM_NOTIFY: + case WM_SIZE: { - LPNMHDR header = (LPNMHDR)lParam; - - switch (header->code) - { - case PSN_APPLY: - { - PPH_STRING string; - - ClearFilterList(ProcessFilterList); - CopyFilterList(ProcessFilterList, EditingProcessFilterList); - - string = SaveFilterList(ProcessFilterList); - PhSetStringSetting2(SETTING_NAME_PROCESS_LIST, &string->sr); - PhDereferenceObject(string); - - SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_NOERROR); - } - return TRUE; - } + PhLayoutManagerLayout(&LayoutManager); } break; } @@ -935,9 +921,12 @@ INT_PTR CALLBACK ServicesDlgProc( _In_ LPARAM lParam ) { - if (HandleCommonMessages(hwndDlg, uMsg, wParam, lParam, + static PH_LAYOUT_MANAGER LayoutManager; + INT_PTR result; + + if (result = HandleCommonMessages(hwndDlg, uMsg, wParam, lParam, GetDlgItem(hwndDlg, IDC_LIST), EditingServiceFilterList)) - return FALSE; + return result; switch (uMsg) { @@ -946,37 +935,41 @@ INT_PTR CALLBACK ServicesDlgProc( EditingServiceFilterList = PhCreateList(ServiceFilterList->Count + 10); CopyFilterList(EditingServiceFilterList, ServiceFilterList); + PhInitializeLayoutManager(&LayoutManager, hwndDlg); + PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDC_LIST), NULL, PH_ANCHOR_ALL); + PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDC_MOVEUP), NULL, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); + PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDC_MOVEDOWN), NULL, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); + PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDC_TEXT), NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_LEFT | PH_ANCHOR_RIGHT); + PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDC_INCLUDE), NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_RIGHT); + PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDC_EXCLUDE), NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_RIGHT); + PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDC_ADD), NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_RIGHT); + PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDC_REMOVE), NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_RIGHT); + PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDC_INFO), NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_LEFT); + AddEntriesToListBox(GetDlgItem(hwndDlg, IDC_LIST), EditingServiceFilterList); } break; case WM_DESTROY: { + PPH_STRING string; + + ClearFilterList(ServiceFilterList); + CopyFilterList(ServiceFilterList, EditingServiceFilterList); + + string = SaveFilterList(ServiceFilterList); + PhSetStringSetting2(SETTING_NAME_SERVICE_LIST, &string->sr); + PhDereferenceObject(string); + ClearFilterList(EditingServiceFilterList); PhDereferenceObject(EditingServiceFilterList); EditingServiceFilterList = NULL; + + PhDeleteLayoutManager(&LayoutManager); } break; - case WM_NOTIFY: + case WM_SIZE: { - LPNMHDR header = (LPNMHDR)lParam; - - switch (header->code) - { - case PSN_APPLY: - { - PPH_STRING string; - - ClearFilterList(ServiceFilterList); - CopyFilterList(ServiceFilterList, EditingServiceFilterList); - - string = SaveFilterList(ServiceFilterList); - PhSetStringSetting2(SETTING_NAME_SERVICE_LIST, &string->sr); - PhDereferenceObject(string); - - SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_NOERROR); - } - return TRUE; - } + PhLayoutManagerLayout(&LayoutManager); } break; } @@ -991,11 +984,30 @@ INT_PTR CALLBACK LoggingDlgProc( _In_ LPARAM lParam ) { + static PH_LAYOUT_MANAGER LayoutManager; + switch (uMsg) { case WM_INITDIALOG: { - SetDlgItemText(hwndDlg, IDC_LOGFILENAME, ((PPH_STRING)PH_AUTO(PhGetStringSetting(SETTING_NAME_LOG_FILENAME)))->Buffer); + SetDlgItemText(hwndDlg, IDC_LOGFILENAME, PhaGetStringSetting(SETTING_NAME_LOG_FILENAME)->Buffer); + + PhInitializeLayoutManager(&LayoutManager, hwndDlg); + PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDC_INFO), NULL, PH_ANCHOR_TOP | PH_ANCHOR_LEFT | PH_ANCHOR_RIGHT); + PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDC_LOGFILENAME), NULL, PH_ANCHOR_TOP | PH_ANCHOR_LEFT | PH_ANCHOR_RIGHT); + PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDC_BROWSE), NULL, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); + } + break; + case WM_DESTROY: + { + PhSetStringSetting2(SETTING_NAME_LOG_FILENAME, &PhaGetDlgItemText(hwndDlg, IDC_LOGFILENAME)->sr); + + PhDeleteLayoutManager(&LayoutManager); + } + break; + case WM_SIZE: + { + PhLayoutManagerLayout(&LayoutManager); } break; case WM_COMMAND: @@ -1030,22 +1042,6 @@ INT_PTR CALLBACK LoggingDlgProc( } } break; - case WM_NOTIFY: - { - LPNMHDR header = (LPNMHDR)lParam; - - switch (header->code) - { - case PSN_APPLY: - { - PhSetStringSetting2(SETTING_NAME_LOG_FILENAME, &PhaGetDlgItemText(hwndDlg, IDC_LOGFILENAME)->sr); - - SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_NOERROR); - } - return TRUE; - } - } - break; } return FALSE; @@ -1058,6 +1054,8 @@ INT_PTR CALLBACK GrowlDlgProc( _In_ LPARAM lParam ) { + static PH_LAYOUT_MANAGER LayoutManager; + switch (uMsg) { case WM_INITDIALOG: @@ -1065,30 +1063,24 @@ INT_PTR CALLBACK GrowlDlgProc( SetDlgItemText(hwndDlg, IDC_LICENSE, PH_AUTO_T(PH_STRING, PhConvertUtf8ToUtf16(gntp_send_license_text))->Buffer); Button_SetCheck(GetDlgItem(hwndDlg, IDC_ENABLEGROWL), PhGetIntegerSetting(SETTING_NAME_ENABLE_GROWL) ? BST_CHECKED : BST_UNCHECKED); + + PhInitializeLayoutManager(&LayoutManager, hwndDlg); + PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDC_LICENSE), NULL, PH_ANCHOR_ALL); } break; - case WM_NOTIFY: + case WM_DESTROY: { - LPNMHDR header = (LPNMHDR)lParam; - - switch (header->code) - { - case PSN_QUERYINITIALFOCUS: - { - SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, (LONG_PTR)GetDlgItem(hwndDlg, IDC_ENABLEGROWL)); - } - return TRUE; - case PSN_APPLY: - { - PhSetIntegerSetting(SETTING_NAME_ENABLE_GROWL, Button_GetCheck(GetDlgItem(hwndDlg, IDC_ENABLEGROWL)) == BST_CHECKED); + PhSetIntegerSetting(SETTING_NAME_ENABLE_GROWL, Button_GetCheck(GetDlgItem(hwndDlg, IDC_ENABLEGROWL)) == BST_CHECKED); - if (PhGetIntegerSetting(SETTING_NAME_ENABLE_GROWL)) - RegisterGrowl(FALSE); + if (PhGetIntegerSetting(SETTING_NAME_ENABLE_GROWL)) + RegisterGrowl(FALSE); - SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_NOERROR); - } - return TRUE; - } + PhDeleteLayoutManager(&LayoutManager); + } + break; + case WM_SIZE: + { + PhLayoutManagerLayout(&LayoutManager); } break; } diff --git a/plugins/ExtendedNotifications/resource.h b/plugins/ExtendedNotifications/resource.h index 7222e3a05259..10606d451840 100644 --- a/plugins/ExtendedNotifications/resource.h +++ b/plugins/ExtendedNotifications/resource.h @@ -20,14 +20,15 @@ #define IDC_LICENSE 1014 #define IDC_BROWSE 1015 #define IDC_ENABLEGROWL 1016 +#define IDC_INFO 1017 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 108 +#define _APS_NEXT_RESOURCE_VALUE 109 #define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1017 +#define _APS_NEXT_CONTROL_VALUE 1018 #define _APS_NEXT_SYMED_VALUE 102 #endif #endif diff --git a/plugins/ExtendedServices/main.c b/plugins/ExtendedServices/main.c index 7bac8fd61502..401b27a1629a 100644 --- a/plugins/ExtendedServices/main.c +++ b/plugins/ExtendedServices/main.c @@ -43,20 +43,15 @@ VOID NTAPI ShowOptionsCallback( _In_opt_ PVOID Context ) { - PPH_PLUGIN_OBJECT_PROPERTIES objectProperties = Parameter; - PROPSHEETPAGE propSheetPage; - - if (objectProperties->NumberOfPages < objectProperties->MaximumNumberOfPages) - { - memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); - propSheetPage.dwSize = sizeof(PROPSHEETPAGE); - propSheetPage.dwFlags = PSP_USETITLE; - propSheetPage.hInstance = PluginInstance->DllBase; - propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_OPTIONS); - propSheetPage.pszTitle = L"ExtendedServices"; - propSheetPage.pfnDlgProc = OptionsDlgProc; - objectProperties->Pages[objectProperties->NumberOfPages++] = CreatePropertySheetPage(&propSheetPage); - } + PPH_PLUGIN_OPTIONS_POINTERS optionsEntry = (PPH_PLUGIN_OPTIONS_POINTERS)Parameter; + + optionsEntry->CreateSection( + L"ExtendedServices", + PluginInstance->DllBase, + MAKEINTRESOURCE(IDD_OPTIONS), + OptionsDlgProc, + NULL + ); } VOID NTAPI MenuItemCallback( diff --git a/plugins/ExtendedTools/main.c b/plugins/ExtendedTools/main.c index 69de3fdacb2f..fe84e010489f 100644 --- a/plugins/ExtendedTools/main.c +++ b/plugins/ExtendedTools/main.c @@ -72,20 +72,15 @@ VOID NTAPI ShowOptionsCallback( _In_opt_ PVOID Context ) { - PPH_PLUGIN_OBJECT_PROPERTIES objectProperties = Parameter; - PROPSHEETPAGE propSheetPage; - - if (objectProperties->NumberOfPages < objectProperties->MaximumNumberOfPages) - { - memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); - propSheetPage.dwSize = sizeof(PROPSHEETPAGE); - propSheetPage.dwFlags = PSP_USETITLE; - propSheetPage.hInstance = PluginInstance->DllBase; - propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_OPTIONS); - propSheetPage.pszTitle = L"ExtendedTools"; - propSheetPage.pfnDlgProc = OptionsDlgProc; - objectProperties->Pages[objectProperties->NumberOfPages++] = CreatePropertySheetPage(&propSheetPage); - } + PPH_PLUGIN_OPTIONS_POINTERS optionsEntry = (PPH_PLUGIN_OPTIONS_POINTERS)Parameter; + + optionsEntry->CreateSection( + L"ExtendedTools", + PluginInstance->DllBase, + MAKEINTRESOURCE(IDD_OPTIONS), + OptionsDlgProc, + NULL + ); } VOID NTAPI MenuItemCallback( diff --git a/plugins/HardwareDevices/devices.h b/plugins/HardwareDevices/devices.h index e6b70f33d775..1c415a429d92 100644 --- a/plugins/HardwareDevices/devices.h +++ b/plugins/HardwareDevices/devices.h @@ -182,16 +182,13 @@ typedef struct _DV_NETADAPTER_CONTEXT //HIMAGELIST ImageList; BOOLEAN OptionsChanged; BOOLEAN UseAlternateMethod; + PH_LAYOUT_MANAGER LayoutManager; } DV_NETADAPTER_CONTEXT, *PDV_NETADAPTER_CONTEXT; VOID NetAdaptersLoadList( VOID ); -VOID ShowOptionsDialog( - _In_ HWND ParentHandle - ); - // adapter.c VOID NetAdaptersInitialize( @@ -443,6 +440,7 @@ typedef struct _DV_DISK_OPTIONS_CONTEXT HWND ListViewHandle; //HIMAGELIST ImageList; BOOLEAN OptionsChanged; + PH_LAYOUT_MANAGER LayoutManager; } DV_DISK_OPTIONS_CONTEXT, *PDV_DISK_OPTIONS_CONTEXT; VOID DiskDrivesInitialize(VOID); diff --git a/plugins/HardwareDevices/diskoptions.c b/plugins/HardwareDevices/diskoptions.c index 42a404f99c63..bd252a5171ce 100644 --- a/plugins/HardwareDevices/diskoptions.c +++ b/plugins/HardwareDevices/diskoptions.c @@ -606,6 +606,8 @@ INT_PTR CALLBACK DiskDriveOptionsDlgProc( if (uMsg == WM_DESTROY) { + PhDeleteLayoutManager(&context->LayoutManager); + if (context->OptionsChanged) DiskDrivesSaveList(); @@ -623,13 +625,6 @@ INT_PTR CALLBACK DiskDriveOptionsDlgProc( { case WM_INITDIALOG: { - // Center the property sheet. - PhCenterWindow(GetParent(hwndDlg), GetParent(GetParent(hwndDlg))); - // Hide the OK button. - ShowWindow(GetDlgItem(GetParent(hwndDlg), IDOK), SW_HIDE); - // Set the Cancel button text. - Button_SetText(GetDlgItem(GetParent(hwndDlg), IDCANCEL), L"Close"); - context->ListViewHandle = GetDlgItem(hwndDlg, IDC_DISKDRIVE_LISTVIEW); PhSetListViewStyle(context->ListViewHandle, FALSE, TRUE); ListView_SetExtendedListViewStyleEx(context->ListViewHandle, LVS_EX_CHECKBOXES, LVS_EX_CHECKBOXES); @@ -641,6 +636,9 @@ INT_PTR CALLBACK DiskDriveOptionsDlgProc( AddListViewGroup(context->ListViewHandle, 0, L"Connected"); AddListViewGroup(context->ListViewHandle, 1, L"Disconnected"); + PhInitializeLayoutManager(&context->LayoutManager, hwndDlg); + PhAddLayoutItem(&context->LayoutManager, context->ListViewHandle, NULL, PH_ANCHOR_ALL); + EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); FindDiskDrives(context); @@ -648,6 +646,11 @@ INT_PTR CALLBACK DiskDriveOptionsDlgProc( context->OptionsChanged = FALSE; } break; + case WM_SIZE: + { + PhLayoutManagerLayout(&context->LayoutManager); + } + break; case WM_NOTIFY: { LPNMHDR header = (LPNMHDR)lParam; diff --git a/plugins/HardwareDevices/main.c b/plugins/HardwareDevices/main.c index df1e73ab889e..19366f4c7515 100644 --- a/plugins/HardwareDevices/main.c +++ b/plugins/HardwareDevices/main.c @@ -67,32 +67,23 @@ VOID NTAPI ShowOptionsCallback( _In_opt_ PVOID Context ) { - PPH_PLUGIN_OBJECT_PROPERTIES objectProperties = Parameter; - PROPSHEETPAGE propSheetPage; - - if (objectProperties->NumberOfPages < objectProperties->MaximumNumberOfPages) - { - memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); - propSheetPage.dwSize = sizeof(PROPSHEETPAGE); - propSheetPage.dwFlags = PSP_USETITLE; - propSheetPage.hInstance = PluginInstance->DllBase; - propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_DISKDRIVE_OPTIONS); - propSheetPage.pszTitle = L"Disk Drives"; - propSheetPage.pfnDlgProc = DiskDriveOptionsDlgProc; - objectProperties->Pages[objectProperties->NumberOfPages++] = CreatePropertySheetPage(&propSheetPage); - } + PPH_PLUGIN_OPTIONS_POINTERS optionsEntry = (PPH_PLUGIN_OPTIONS_POINTERS)Parameter; + + optionsEntry->CreateSection( + L"Disk Drives", + PluginInstance->DllBase, + MAKEINTRESOURCE(IDD_DISKDRIVE_OPTIONS), + DiskDriveOptionsDlgProc, + NULL + ); - if (objectProperties->NumberOfPages < objectProperties->MaximumNumberOfPages) - { - memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); - propSheetPage.dwSize = sizeof(PROPSHEETPAGE); - propSheetPage.dwFlags = PSP_USETITLE; - propSheetPage.hInstance = PluginInstance->DllBase; - propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_NETADAPTER_OPTIONS); - propSheetPage.pszTitle = L"Network Adapters"; - propSheetPage.pfnDlgProc = NetworkAdapterOptionsDlgProc; - objectProperties->Pages[objectProperties->NumberOfPages++] = CreatePropertySheetPage(&propSheetPage); - } + optionsEntry->CreateSection( + L"Network Adapters", + PluginInstance->DllBase, + MAKEINTRESOURCE(IDD_NETADAPTER_OPTIONS), + NetworkAdapterOptionsDlgProc, + NULL + ); } VOID NTAPI MainWindowShowingCallback( diff --git a/plugins/HardwareDevices/netoptions.c b/plugins/HardwareDevices/netoptions.c index 0807ba9a9e3b..0d5a25d4005c 100644 --- a/plugins/HardwareDevices/netoptions.c +++ b/plugins/HardwareDevices/netoptions.c @@ -705,6 +705,8 @@ INT_PTR CALLBACK NetworkAdapterOptionsDlgProc( if (uMsg == WM_DESTROY) { + PhDeleteLayoutManager(&context->LayoutManager); + if (context->OptionsChanged) NetAdaptersSaveList(); @@ -733,11 +735,20 @@ INT_PTR CALLBACK NetworkAdapterOptionsDlgProc( AddListViewGroup(context->ListViewHandle, 0, L"Connected"); AddListViewGroup(context->ListViewHandle, 1, L"Disconnected"); + PhInitializeLayoutManager(&context->LayoutManager, hwndDlg); + PhAddLayoutItem(&context->LayoutManager, context->ListViewHandle, NULL, PH_ANCHOR_ALL); + PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_SHOW_HIDDEN_ADAPTERS), NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_LEFT); + FindNetworkAdapters(context); context->OptionsChanged = FALSE; } break; + case WM_SIZE: + { + PhLayoutManagerLayout(&context->LayoutManager); + } + break; case WM_COMMAND: { switch (GET_WM_COMMAND_ID(wParam, lParam)) diff --git a/plugins/NetworkTools/main.c b/plugins/NetworkTools/main.c index df2b30a5674f..b034b73ca90f 100644 --- a/plugins/NetworkTools/main.c +++ b/plugins/NetworkTools/main.c @@ -47,20 +47,15 @@ VOID NTAPI ShowOptionsCallback( _In_opt_ PVOID Context ) { - PPH_PLUGIN_OBJECT_PROPERTIES objectProperties = Parameter; - PROPSHEETPAGE propSheetPage; - - if (objectProperties->NumberOfPages < objectProperties->MaximumNumberOfPages) - { - memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); - propSheetPage.dwSize = sizeof(PROPSHEETPAGE); - propSheetPage.dwFlags = PSP_USETITLE; - propSheetPage.hInstance = PluginInstance->DllBase; - propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_OPTIONS); - propSheetPage.pszTitle = L"NetworkTools"; - propSheetPage.pfnDlgProc = OptionsDlgProc; - objectProperties->Pages[objectProperties->NumberOfPages++] = CreatePropertySheetPage(&propSheetPage); - } + PPH_PLUGIN_OPTIONS_POINTERS optionsEntry = (PPH_PLUGIN_OPTIONS_POINTERS)Parameter; + + optionsEntry->CreateSection( + L"NetworkTools", + PluginInstance->DllBase, + MAKEINTRESOURCE(IDD_OPTIONS), + OptionsDlgProc, + NULL + ); } static BOOLEAN ValidAddressInfo( diff --git a/plugins/OnlineChecks/main.c b/plugins/OnlineChecks/main.c index 166785835989..6f9677e1b99c 100644 --- a/plugins/OnlineChecks/main.c +++ b/plugins/OnlineChecks/main.c @@ -150,20 +150,15 @@ VOID NTAPI ShowOptionsCallback( _In_opt_ PVOID Context ) { - PPH_PLUGIN_OBJECT_PROPERTIES objectProperties = Parameter; - PROPSHEETPAGE propSheetPage; - - if (objectProperties->NumberOfPages < objectProperties->MaximumNumberOfPages) - { - memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); - propSheetPage.dwSize = sizeof(PROPSHEETPAGE); - propSheetPage.dwFlags = PSP_USETITLE; - propSheetPage.hInstance = PluginInstance->DllBase; - propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_OPTIONS); - propSheetPage.pszTitle = L"OnlineChecks"; - propSheetPage.pfnDlgProc = OptionsDlgProc; - objectProperties->Pages[objectProperties->NumberOfPages++] = CreatePropertySheetPage(&propSheetPage); - } + PPH_PLUGIN_OPTIONS_POINTERS optionsEntry = (PPH_PLUGIN_OPTIONS_POINTERS)Parameter; + + optionsEntry->CreateSection( + L"OnlineChecks", + PluginInstance->DllBase, + MAKEINTRESOURCE(IDD_OPTIONS), + OptionsDlgProc, + NULL + ); } VOID NTAPI MenuItemCallback( diff --git a/plugins/ToolStatus/main.c b/plugins/ToolStatus/main.c index 008f0979259b..ae24130f3e41 100644 --- a/plugins/ToolStatus/main.c +++ b/plugins/ToolStatus/main.c @@ -1353,20 +1353,15 @@ VOID NTAPI ShowOptionsCallback( _In_opt_ PVOID Context ) { - PPH_PLUGIN_OBJECT_PROPERTIES objectProperties = Parameter; - PROPSHEETPAGE propSheetPage; - - if (objectProperties->NumberOfPages < objectProperties->MaximumNumberOfPages) - { - memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); - propSheetPage.dwSize = sizeof(PROPSHEETPAGE); - propSheetPage.dwFlags = PSP_USETITLE; - propSheetPage.hInstance = PluginInstance->DllBase; - propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_OPTIONS); - propSheetPage.pszTitle = L"ToolStatus"; - propSheetPage.pfnDlgProc = OptionsDlgProc; - objectProperties->Pages[objectProperties->NumberOfPages++] = CreatePropertySheetPage(&propSheetPage); - } + PPH_PLUGIN_OPTIONS_POINTERS optionsEntry = (PPH_PLUGIN_OPTIONS_POINTERS)Parameter; + + optionsEntry->CreateSection( + L"ToolStatus", + PluginInstance->DllBase, + MAKEINTRESOURCE(IDD_OPTIONS), + OptionsDlgProc, + NULL + ); } LOGICAL DllMain( diff --git a/plugins/Updater/main.c b/plugins/Updater/main.c index 4f27d6b7795f..9d9e795e2607 100644 --- a/plugins/Updater/main.c +++ b/plugins/Updater/main.c @@ -73,20 +73,15 @@ VOID NTAPI ShowOptionsCallback( _In_opt_ PVOID Context ) { - PPH_PLUGIN_OBJECT_PROPERTIES objectProperties = Parameter; - PROPSHEETPAGE propSheetPage; - - if (objectProperties->NumberOfPages < objectProperties->MaximumNumberOfPages) - { - memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); - propSheetPage.dwSize = sizeof(PROPSHEETPAGE); - propSheetPage.dwFlags = PSP_USETITLE; - propSheetPage.hInstance = PluginInstance->DllBase; - propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_OPTIONS); - propSheetPage.pszTitle = L"Updater"; - propSheetPage.pfnDlgProc = OptionsDlgProc; - objectProperties->Pages[objectProperties->NumberOfPages++] = CreatePropertySheetPage(&propSheetPage); - } + PPH_PLUGIN_OPTIONS_POINTERS optionsEntry = (PPH_PLUGIN_OPTIONS_POINTERS)Parameter; + + optionsEntry->CreateSection( + L"Updater", + PluginInstance->DllBase, + MAKEINTRESOURCE(IDD_OPTIONS), + OptionsDlgProc, + NULL + ); } LOGICAL DllMain( diff --git a/plugins/UserNotes/UserNotes.rc b/plugins/UserNotes/UserNotes.rc index 5510b557d445..a1b019805eb3 100644 --- a/plugins/UserNotes/UserNotes.rc +++ b/plugins/UserNotes/UserNotes.rc @@ -48,17 +48,15 @@ END // Dialog // -IDD_OPTIONS DIALOGEX 0, 0, 316, 71 +IDD_OPTIONS DIALOGEX 0, 0, 317, 54 STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Options" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN LTEXT "Database location:",IDC_STATIC,7,9,61,8 EDITTEXT IDC_DATABASE,72,8,183,12,ES_AUTOHSCROLL - PUSHBUTTON "Browse...",IDC_BROWSE,259,7,50,14 - LTEXT "If a relative path is specified, it is relative to Process Hacker's directory. Environment variables can be used. Changes will take place after Process Hacker is restarted.",IDC_STATIC,7,26,302,19 - DEFPUSHBUTTON "OK",IDOK,205,50,50,14 - PUSHBUTTON "Cancel",IDCANCEL,259,50,50,14 + PUSHBUTTON "Browse...",IDC_BROWSE,260,7,50,14 + LTEXT "If a relative path is specified, it is relative to Process Hacker's directory. Environment variables can be used. Changes will take place after Process Hacker is restarted.",IDC_STATIC,7,26,303,19 END IDD_PROCCOMMENT DIALOGEX 0, 0, 260, 260 @@ -92,9 +90,9 @@ BEGIN IDD_OPTIONS, DIALOG BEGIN LEFTMARGIN, 7 - RIGHTMARGIN, 309 + RIGHTMARGIN, 310 TOPMARGIN, 7 - BOTTOMMARGIN, 64 + BOTTOMMARGIN, 47 END IDD_PROCCOMMENT, DIALOG diff --git a/plugins/UserNotes/main.c b/plugins/UserNotes/main.c index 6f2dde717b1c..55bfc0d4b5ff 100644 --- a/plugins/UserNotes/main.c +++ b/plugins/UserNotes/main.c @@ -3,7 +3,7 @@ * main program * * Copyright (C) 2011-2016 wj32 - * Copyright (C) 2016 dmex + * Copyright (C) 2016-2017 dmex * * This file is part of Process Hacker. * @@ -314,11 +314,14 @@ VOID NTAPI ShowOptionsCallback( _In_opt_ PVOID Context ) { - DialogBox( + PPH_PLUGIN_OPTIONS_POINTERS optionsEntry = (PPH_PLUGIN_OPTIONS_POINTERS)Parameter; + + optionsEntry->CreateSection( + L"UserNotes", PluginInstance->DllBase, MAKEINTRESOURCE(IDD_OPTIONS), - (HWND)Parameter, - OptionsDlgProc + OptionsDlgProc, + NULL ); } @@ -1344,7 +1347,6 @@ LOGICAL DllMain( info->Author = L"dmex, wj32"; info->Description = L"Allows the user to add comments for processes and services, save process priority and affinity, highlight individual processes and show processes collapsed by default."; info->Url = L"https://wj32.org/processhacker/forums/viewtopic.php?t=1120"; - info->HasOptions = TRUE; InitializeDb(); @@ -1361,7 +1363,7 @@ LOGICAL DllMain( &PluginUnloadCallbackRegistration ); PhRegisterCallback( - PhGetPluginCallback(PluginInstance, PluginCallbackShowOptions), + PhGetGeneralCallback(GeneralCallbackOptionsWindowInitializing), ShowOptionsCallback, NULL, &PluginShowOptionsCallbackRegistration @@ -1479,32 +1481,38 @@ INT_PTR CALLBACK OptionsDlgProc( _In_ LPARAM lParam ) { + static PH_LAYOUT_MANAGER LayoutManager; + switch (uMsg) { case WM_INITDIALOG: { - PhCenterWindow(hwndDlg, GetParent(hwndDlg)); - SetDlgItemText(hwndDlg, IDC_DATABASE, PhaGetStringSetting(SETTING_NAME_DATABASE_PATH)->Buffer); + PhInitializeLayoutManager(&LayoutManager, hwndDlg); + PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDC_DATABASE), NULL, PH_ANCHOR_TOP | PH_ANCHOR_LEFT | PH_ANCHOR_RIGHT); + PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDC_BROWSE), NULL, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); + SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hwndDlg, IDCANCEL), TRUE); + + } + break; + case WM_DESTROY: + { + PhSetStringSetting2(SETTING_NAME_DATABASE_PATH, &PhaGetDlgItemText(hwndDlg, IDC_DATABASE)->sr); + + PhDeleteLayoutManager(&LayoutManager); + } + break; + case WM_SIZE: + { + PhLayoutManagerLayout(&LayoutManager); } break; case WM_COMMAND: { switch (GET_WM_COMMAND_ID(wParam, lParam)) { - case IDCANCEL: - EndDialog(hwndDlg, IDCANCEL); - break; - case IDOK: - { - PhSetStringSetting2(SETTING_NAME_DATABASE_PATH, - &PhaGetDlgItemText(hwndDlg, IDC_DATABASE)->sr); - - EndDialog(hwndDlg, IDOK); - } - break; case IDC_BROWSE: { static PH_FILETYPE_FILTER filters[] = From 818bb1b7b301381d7cd4600e68a9e6000e741a96 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 9 Sep 2017 20:01:36 +1000 Subject: [PATCH 0425/2058] Fix options window start location regression from previous commit --- ProcessHacker/options.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/ProcessHacker/options.c b/ProcessHacker/options.c index b442a115de0b..17bef613611a 100644 --- a/ProcessHacker/options.c +++ b/ProcessHacker/options.c @@ -159,6 +159,11 @@ VOID PhShowOptionsDialog( _In_ HWND ParentWindowHandle ) { + if (PhStartupParameters.ShowOptions) + StartLocation = PhStartupParameters.Point; + else + StartLocation.x = MINLONG; + DialogBox( PhInstanceHandle, MAKEINTRESOURCE(IDD_OPTIONS), @@ -258,7 +263,16 @@ INT_PTR CALLBACK PhOptionsDialogProc( SendMessage(PhOptionsWindowHandle, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER))); SendMessage(PhOptionsWindowHandle, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER))); - PhCenterWindow(hwndDlg, NULL); + // Set the location of the options window. + if (StartLocation.x == MINLONG) + { + PhCenterWindow(hwndDlg, GetParent(hwndDlg)); + } + else + { + SetWindowPos(hwndDlg, NULL, StartLocation.x, StartLocation.y, 0, 0, + SWP_NOACTIVATE | SWP_NOREDRAW | SWP_NOSIZE | SWP_NOZORDER); + } OptionsTreeControl = GetDlgItem(PhOptionsWindowHandle, IDC_SECTIONTREE); ContainerControl = GetDlgItem(PhOptionsWindowHandle, IDD_CONTAINER); @@ -1144,12 +1158,12 @@ INT_PTR CALLBACK PhpOptionsAdvancedDlgProc( // WM_PH_CHILD_EXIT gets sent. PhpAdvancedPageSave(hwndDlg); - GetWindowRect(GetParent(hwndDlg), &windowRect); + GetWindowRect(GetParent(GetParent(hwndDlg)), &windowRect); WindowHandleForElevate = hwndDlg; PhCreateThread2(PhpElevateAdvancedThreadStart, PhFormatString( L"-showoptions -hwnd %Ix -point %u,%u", - (ULONG_PTR)GetParent(hwndDlg), + (ULONG_PTR)GetParent(GetParent(hwndDlg)), windowRect.left + 20, windowRect.top + 20 )); From 814450d9a752a128bab20a7dd96a31c75e8234ac Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 14 Sep 2017 16:45:20 +1000 Subject: [PATCH 0426/2058] Add cleanup button to options window, Fix options window handle leak --- ProcessHacker/ProcessHacker.rc | 11 ++-- ProcessHacker/options.c | 95 +++++++++++++--------------------- ProcessHacker/resource.h | 1 + 3 files changed, 45 insertions(+), 62 deletions(-) diff --git a/ProcessHacker/ProcessHacker.rc b/ProcessHacker/ProcessHacker.rc index a2d7926d6373..4e3105150b98 100644 --- a/ProcessHacker/ProcessHacker.rc +++ b/ProcessHacker/ProcessHacker.rc @@ -1877,12 +1877,15 @@ CAPTION "Options" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN DEFPUSHBUTTON "Close",IDOK,371,231,50,14 - CONTROL "",IDC_SECTIONTREE,"SysTreeView32",TVS_SHOWSELALWAYS | TVS_TRACKSELECT | TVS_FULLROWSELECT | WS_HSCROLL | WS_TABSTOP,2,1,103,228 + CONTROL "",IDC_SECTIONTREE,"SysTreeView32",TVS_SHOWSELALWAYS | TVS_TRACKSELECT | TVS_FULLROWSELECT | WS_HSCROLL | WS_TABSTOP,2,1,103,244 CONTROL "",IDD_CONTAINER,"#32770",0x44c,107,0,316,229,WS_EX_TOPMOST | WS_EX_TOOLWINDOW | WS_EX_CONTROLPARENT | 0xc0000800L - LTEXT "",IDC_SEPARATOR,105,0,8,229 - PUSHBUTTON "Reset",IDC_RESET,319,231,50,14 + LTEXT "",IDC_SEPARATOR,105,0,8,246 + PUSHBUTTON "Reset",IDC_RESET,113,231,50,14 + PUSHBUTTON "Apply",IDC_APPLY,319,231,50,14,NOT WS_VISIBLE + PUSHBUTTON "Cleanup",IDC_CLEANUP,165,231,50,14 END + ///////////////////////////////////////////////////////////////////////////// // // DESIGNINFO @@ -2414,7 +2417,7 @@ BEGIN TOPMARGIN, 7 BOTTOMMARGIN, 170 END - + IDD_OPTIONS, DIALOG BEGIN LEFTMARGIN, 2 diff --git a/ProcessHacker/options.c b/ProcessHacker/options.c index 17bef613611a..d57347a8497a 100644 --- a/ProcessHacker/options.c +++ b/ProcessHacker/options.c @@ -94,7 +94,6 @@ VOID PhOptionsLayoutSectionView( VOID PhOptionsEnterSectionViewInner( _In_ PPH_OPTIONS_SECTION Section, - _Inout_ HDWP *DeferHandle, _Inout_ HDWP *ContainerDeferHandle ); @@ -110,14 +109,6 @@ VOID PhOptionsOnSize( VOID ); -PPH_OPTIONS_SECTION PhOptionsCreateInternalSection( - _In_ PWSTR Name, - _In_ PVOID Instance, - _In_ PWSTR Template, - _In_ DLGPROC DialogProc, - _In_ PVOID Parameter - ); - PPH_OPTIONS_SECTION PhOptionsCreateSection( _In_ PWSTR Name, _In_ PVOID Instance, @@ -134,6 +125,7 @@ static PPH_LIST SectionList = NULL; static PPH_OPTIONS_SECTION CurrentSection = NULL; static HWND OptionsTreeControl = NULL; static HWND ContainerControl = NULL; +static HIMAGELIST OptionsTreeImageList = NULL; // All static BOOLEAN RestartRequired = FALSE; @@ -211,7 +203,7 @@ VOID PhShowOptionsDialog( } } -static HTREEITEM PhOptionsTreeViewAddItem( +static HTREEITEM PhpOptionsTreeViewAddItem( _In_ PWSTR Text, _In_ PVOID Context ) @@ -229,7 +221,7 @@ static HTREEITEM PhOptionsTreeViewAddItem( return TreeView_InsertItem(OptionsTreeControl, &insert); } -static PPH_OPTIONS_SECTION GetSelectedSectionTreeView( +static PPH_OPTIONS_SECTION PhpTreeViewGetSelectedSection( _In_ HTREEITEM SelectedTreeItem ) { @@ -274,6 +266,7 @@ INT_PTR CALLBACK PhOptionsDialogProc( SWP_NOACTIVATE | SWP_NOREDRAW | SWP_NOSIZE | SWP_NOZORDER); } + OptionsTreeImageList = ImageList_Create(2, 22, ILC_COLOR, 1, 1); OptionsTreeControl = GetDlgItem(PhOptionsWindowHandle, IDC_SECTIONTREE); ContainerControl = GetDlgItem(PhOptionsWindowHandle, IDD_CONTAINER); @@ -281,15 +274,16 @@ INT_PTR CALLBACK PhOptionsDialogProc( PhSetControlTheme(OptionsTreeControl, L"explorer"); TreeView_SetExtendedStyle(OptionsTreeControl, TVS_EX_DOUBLEBUFFER, TVS_EX_DOUBLEBUFFER); - TreeView_SetImageList(OptionsTreeControl, ImageList_Create(2, 22, ILC_COLOR32, 1, 1), TVSIL_NORMAL); // leak + TreeView_SetImageList(OptionsTreeControl, OptionsTreeImageList, TVSIL_NORMAL); TreeView_SetBkColor(OptionsTreeControl, GetSysColor(COLOR_3DFACE)); PhInitializeLayoutManager(&WindowLayoutManager, PhOptionsWindowHandle); - PhAddLayoutItem(&WindowLayoutManager, OptionsTreeControl, NULL, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_BOTTOM); PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDC_SEPARATOR), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_BOTTOM); PhAddLayoutItem(&WindowLayoutManager, ContainerControl, NULL, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); - PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(PhOptionsWindowHandle, IDC_RESET), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); + PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(PhOptionsWindowHandle, IDC_RESET), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_BOTTOM); + PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(PhOptionsWindowHandle, IDC_CLEANUP), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_BOTTOM); + //PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(PhOptionsWindowHandle, IDC_APPLY), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(PhOptionsWindowHandle, IDOK), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); EnableThemeDialogTexture(ContainerControl, ETDT_ENABLETAB); @@ -303,15 +297,15 @@ INT_PTR CALLBACK PhOptionsDialogProc( if (PhStartupParameters.ShowOptions) { // Disable all pages other than Advanced. - section = PhOptionsCreateInternalSection(L"Advanced", PhInstanceHandle, MAKEINTRESOURCE(IDD_OPTADVANCED), PhpOptionsAdvancedDlgProc, NULL); + section = PhOptionsCreateSection(L"Advanced", PhInstanceHandle, MAKEINTRESOURCE(IDD_OPTADVANCED), PhpOptionsAdvancedDlgProc, NULL); } else { - section = PhOptionsCreateInternalSection(L"General", PhInstanceHandle, MAKEINTRESOURCE(IDD_OPTGENERAL), PhpOptionsGeneralDlgProc, NULL); - PhOptionsCreateInternalSection(L"Advanced", PhInstanceHandle, MAKEINTRESOURCE(IDD_OPTADVANCED), PhpOptionsAdvancedDlgProc, NULL); - PhOptionsCreateInternalSection(L"Symbols", PhInstanceHandle, MAKEINTRESOURCE(IDD_OPTSYMBOLS), PhpOptionsSymbolsDlgProc, NULL); - PhOptionsCreateInternalSection(L"Highlighting", PhInstanceHandle, MAKEINTRESOURCE(IDD_OPTHIGHLIGHTING), PhpOptionsHighlightingDlgProc, NULL); - PhOptionsCreateInternalSection(L"Graphs", PhInstanceHandle, MAKEINTRESOURCE(IDD_OPTGRAPHS), PhpOptionsGraphsDlgProc, NULL); + section = PhOptionsCreateSection(L"General", PhInstanceHandle, MAKEINTRESOURCE(IDD_OPTGENERAL), PhpOptionsGeneralDlgProc, NULL); + PhOptionsCreateSection(L"Advanced", PhInstanceHandle, MAKEINTRESOURCE(IDD_OPTADVANCED), PhpOptionsAdvancedDlgProc, NULL); + PhOptionsCreateSection(L"Symbols", PhInstanceHandle, MAKEINTRESOURCE(IDD_OPTSYMBOLS), PhpOptionsSymbolsDlgProc, NULL); + PhOptionsCreateSection(L"Highlighting", PhInstanceHandle, MAKEINTRESOURCE(IDD_OPTHIGHLIGHTING), PhpOptionsHighlightingDlgProc, NULL); + PhOptionsCreateSection(L"Graphs", PhInstanceHandle, MAKEINTRESOURCE(IDD_OPTGRAPHS), PhpOptionsGraphsDlgProc, NULL); if (PhPluginsEnabled) { @@ -345,6 +339,8 @@ INT_PTR CALLBACK PhOptionsDialogProc( PhDereferenceObject(SectionList); SectionList = NULL; + ImageList_Destroy(OptionsTreeImageList); + PhDeleteLayoutManager(&WindowLayoutManager); } break; @@ -391,6 +387,20 @@ INT_PTR CALLBACK PhOptionsDialogProc( } } break; + case IDC_CLEANUP: + { + if (PhShowMessage2( + hwndDlg, + TDCBF_YES_BUTTON | TDCBF_NO_BUTTON, + TD_INFORMATION_ICON, + L"Do you want to clean up unused plugin settings?", + L"" + ) == IDYES) + { + PhClearIgnoredSettings(); + } + } + break; } } break; @@ -422,7 +432,7 @@ INT_PTR CALLBACK PhOptionsDialogProc( LPNMTREEVIEW treeview = (LPNMTREEVIEW)lParam; PPH_OPTIONS_SECTION section; - if (section = GetSelectedSectionTreeView(treeview->itemNew.hItem)) + if (section = PhpTreeViewGetSelectedSection(treeview->itemNew.hItem)) { PhOptionsEnterSectionView(section); } @@ -493,37 +503,7 @@ PPH_OPTIONS_SECTION PhOptionsCreateSection( PhAddItemList(SectionList, section); - PhOptionsTreeViewAddItem(Name, section); - - return section; -} - -PPH_OPTIONS_SECTION PhOptionsCreateInternalSection( - _In_ PWSTR Name, - _In_ PVOID Instance, - _In_ PWSTR Template, - _In_ DLGPROC DialogProc, - _In_ PVOID Parameter - ) -{ - PPH_OPTIONS_SECTION section; - - section = PhOptionsCreateSection( - Name, - Instance, - Template, - DialogProc, - Parameter - ); - - section->DialogHandle = PhCreateDialogFromTemplate( - ContainerControl, - DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD, - Instance, - Template, - DialogProc, - Parameter - ); + PhpOptionsTreeViewAddItem(Name, section); return section; } @@ -582,7 +562,6 @@ VOID PhOptionsEnterSectionView( ULONG i; PPH_OPTIONS_SECTION section; PPH_OPTIONS_SECTION oldSection; - HDWP deferHandle; HDWP containerDeferHandle; if (CurrentSection == NewSection) @@ -591,10 +570,9 @@ VOID PhOptionsEnterSectionView( oldSection = CurrentSection; CurrentSection = NewSection; - deferHandle = BeginDeferWindowPos(SectionList->Count); containerDeferHandle = BeginDeferWindowPos(SectionList->Count); - PhOptionsEnterSectionViewInner(NewSection, &deferHandle, &containerDeferHandle); + PhOptionsEnterSectionViewInner(NewSection, &containerDeferHandle); PhOptionsLayoutSectionView(); for (i = 0; i < SectionList->Count; i++) @@ -602,10 +580,9 @@ VOID PhOptionsEnterSectionView( section = SectionList->Items[i]; if (section != NewSection) - PhOptionsEnterSectionViewInner(section, &deferHandle, &containerDeferHandle); + PhOptionsEnterSectionViewInner(section, &containerDeferHandle); } - EndDeferWindowPos(deferHandle); EndDeferWindowPos(containerDeferHandle); if (NewSection->DialogHandle) @@ -614,7 +591,6 @@ VOID PhOptionsEnterSectionView( VOID PhOptionsEnterSectionViewInner( _In_ PPH_OPTIONS_SECTION Section, - _Inout_ HDWP *DeferHandle, _Inout_ HDWP *ContainerDeferHandle ) { @@ -1136,6 +1112,9 @@ INT_PTR CALLBACK PhpOptionsAdvancedDlgProc( EnableWindow(GetDlgItem(hwndDlg, IDC_SAMPLECOUNTLABEL), FALSE); EnableWindow(GetDlgItem(hwndDlg, IDC_SAMPLECOUNT), FALSE); EnableWindow(GetDlgItem(hwndDlg, IDC_SAMPLECOUNTAUTOMATIC), FALSE); + + EnableWindow(GetDlgItem(PhOptionsWindowHandle, IDC_RESET), FALSE); + EnableWindow(GetDlgItem(PhOptionsWindowHandle, IDC_CLEANUP), FALSE); } } break; diff --git a/ProcessHacker/resource.h b/ProcessHacker/resource.h index 7ab4883d8fa3..80b0825bde89 100644 --- a/ProcessHacker/resource.h +++ b/ProcessHacker/resource.h @@ -225,6 +225,7 @@ #define IDC_SET 1085 #define IDC_RESET 1086 #define IDC_PULSE 1087 +#define IDC_APPLY 1087 #define IDC_COUNT 1088 #define IDC_ABANDONED 1089 #define IDC_CURRENTCOUNT 1090 From 4a78a1b027bffbed9b0b1c7ee104f987b73ccbc3 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 14 Sep 2017 16:59:04 +1000 Subject: [PATCH 0427/2058] Fix format specifiers --- ProcessHacker/dbgcon.c | 18 +++++++++--------- phlib/settings.c | 4 ++-- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/ProcessHacker/dbgcon.c b/ProcessHacker/dbgcon.c index c441891d4979..d9a5c25e57d7 100644 --- a/ProcessHacker/dbgcon.c +++ b/ProcessHacker/dbgcon.c @@ -240,16 +240,16 @@ static VOID PhpDumpObjectInfo( __try { wprintf(L"Type: %s\n", objectType->Name); - wprintf(L"Reference count: %d\n", ObjectHeader->RefCount); + wprintf(L"Reference count: %ld\n", ObjectHeader->RefCount); wprintf(L"Flags: %x\n", ObjectHeader->Flags); if (objectType == PhObjectTypeObject) { wprintf(L"Name: %s\n", ((PPH_OBJECT_TYPE)object)->Name); - wprintf(L"Number of objects: %u\n", ((PPH_OBJECT_TYPE)object)->NumberOfObjects); + wprintf(L"Number of objects: %lu\n", ((PPH_OBJECT_TYPE)object)->NumberOfObjects); wprintf(L"Flags: %u\n", ((PPH_OBJECT_TYPE)object)->Flags); wprintf(L"Type index: %u\n", ((PPH_OBJECT_TYPE)object)->TypeIndex); - wprintf(L"Free list count: %u\n", ((PPH_OBJECT_TYPE)object)->FreeList.Count); + wprintf(L"Free list count: %lu\n", ((PPH_OBJECT_TYPE)object)->FreeList.Count); } else if (objectType == PhStringType) { @@ -1329,12 +1329,12 @@ NTSTATUS PhpDebugConsoleThreadStart( PLIST_ENTRY workQueueItemEntry; wprintf(L"Work queue at %s\n", PhpGetSymbolForAddress(workQueue)); - wprintf(L"Maximum threads: %u\n", workQueue->MaximumThreads); - wprintf(L"Minimum threads: %u\n", workQueue->MinimumThreads); - wprintf(L"No work timeout: %d\n", workQueue->NoWorkTimeout); + wprintf(L"Maximum threads: %lu\n", workQueue->MaximumThreads); + wprintf(L"Minimum threads: %lu\n", workQueue->MinimumThreads); + wprintf(L"No work timeout: %lu\n", workQueue->NoWorkTimeout); - wprintf(L"Current threads: %u\n", workQueue->CurrentThreads); - wprintf(L"Busy count: %u\n", workQueue->BusyCount); + wprintf(L"Current threads: %lu\n", workQueue->CurrentThreads); + wprintf(L"Busy count: %lu\n", workQueue->BusyCount); PhAcquireQueuedLockExclusive(&workQueue->QueueLock); @@ -1388,7 +1388,7 @@ NTSTATUS PhpDebugConsoleThreadStart( do { - wprintf(L"\tRecord at %Ix: %s (%u) (refs: %d)\n", (ULONG_PTR)record, record->ProcessName->Buffer, HandleToUlong(record->ProcessId), record->RefCount); + wprintf(L"\tRecord at %Ix: %s (%lu) (refs: %ld)\n", (ULONG_PTR)record, record->ProcessName->Buffer, HandleToUlong(record->ProcessId), record->RefCount); if (record->FileName) wprintf(L"\t\t%s\n", record->FileName->Buffer); diff --git a/phlib/settings.c b/phlib/settings.c index 173afb1cbe91..4f38546f7393 100644 --- a/phlib/settings.c +++ b/phlib/settings.c @@ -165,7 +165,7 @@ static PPH_STRING PhpSettingToString( { PPH_INTEGER_PAIR integerPair = &Setting->u.IntegerPair; - return PhFormatString(L"%d,%d", integerPair->X, integerPair->Y); + return PhFormatString(L"%ld,%ld", integerPair->X, integerPair->Y); } case ScalableIntegerPairSettingType: { @@ -174,7 +174,7 @@ static PPH_STRING PhpSettingToString( if (!scalableIntegerPair) return PhReferenceEmptyString(); - return PhFormatString(L"@%u|%d,%d", scalableIntegerPair->Scale, scalableIntegerPair->X, scalableIntegerPair->Y); + return PhFormatString(L"@%lu|%ld,%ld", scalableIntegerPair->Scale, scalableIntegerPair->X, scalableIntegerPair->Y); } } From 9128580e2ac275b1d4130b2565662765b1c51a29 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 24 Sep 2017 15:34:32 +1000 Subject: [PATCH 0428/2058] UserNotes: Check current directory for portable database file --- plugins/UserNotes/main.c | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/plugins/UserNotes/main.c b/plugins/UserNotes/main.c index 55bfc0d4b5ff..e3c8e0deb96f 100644 --- a/plugins/UserNotes/main.c +++ b/plugins/UserNotes/main.c @@ -273,7 +273,9 @@ VOID NTAPI LoadCallback( _In_opt_ PVOID Context ) { + static PH_STRINGREF databaseFile = PH_STRINGREF_INIT(L"usernotesdb.xml"); PPH_PLUGIN toolStatusPlugin; + PPH_STRING directory; PPH_STRING path; if (toolStatusPlugin = PhFindPlugin(TOOLSTATUS_PLUGIN_NAME)) @@ -284,21 +286,29 @@ VOID NTAPI LoadCallback( ToolStatusInterface = NULL; } - path = PhaGetStringSetting(SETTING_NAME_DATABASE_PATH); - path = PH_AUTO(PhExpandEnvironmentStrings(&path->sr)); + directory = PH_AUTO(PhGetApplicationDirectory()); + path = PH_AUTO(PhConcatStringRef2(&directory->sr, &databaseFile)); - LoadCustomColors(); - - if (RtlDetermineDosPathNameType_U(path->Buffer) == RtlPathTypeRelative) + if (RtlDoesFileExists_U(path->Buffer)) + { + SetDbPath(path); + } + else { - PPH_STRING directory; + path = PhaGetStringSetting(SETTING_NAME_DATABASE_PATH); + path = PH_AUTO(PhExpandEnvironmentStrings(&path->sr)); - directory = PH_AUTO(PhGetApplicationDirectory()); - path = PH_AUTO(PhConcatStringRef2(&directory->sr, &path->sr)); + if (RtlDetermineDosPathNameType_U(path->Buffer) == RtlPathTypeRelative) + { + directory = PH_AUTO(PhGetApplicationDirectory()); + path = PH_AUTO(PhConcatStringRef2(&directory->sr, &path->sr)); + } + + SetDbPath(path); } - SetDbPath(path); LoadDb(); + LoadCustomColors(); } VOID NTAPI UnloadCallback( From adce5c621482b71a298000e12e46741504073ba4 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 24 Sep 2017 17:26:25 +1000 Subject: [PATCH 0429/2058] SetupTool: Ignore portable config files --- tools/CustomSetupTool/CustomSetupTool/extract.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/tools/CustomSetupTool/CustomSetupTool/extract.c b/tools/CustomSetupTool/CustomSetupTool/extract.c index 14ebc3ff7ddd..af1efe92e6ae 100644 --- a/tools/CustomSetupTool/CustomSetupTool/extract.c +++ b/tools/CustomSetupTool/CustomSetupTool/extract.c @@ -96,6 +96,11 @@ BOOLEAN SetupExtractBuild( if (!mz_zip_reader_file_stat(&zip_archive, i, &zipFileStat)) continue; + if (!strstr(zipFileStat.m_filename, "ProcessHacker.exe.settings.xml")) + continue; + if (!strstr(zipFileStat.m_filename, "usernotesdb.xml")) + continue; + if (info.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) { if (!strncmp(zipFileStat.m_filename, "x32\\", 4)) @@ -130,6 +135,11 @@ BOOLEAN SetupExtractBuild( if (!mz_zip_reader_file_stat(&zip_archive, i, &zipFileStat)) continue; + if (!strstr(zipFileStat.m_filename, "ProcessHacker.exe.settings.xml")) + continue; + if (!strstr(zipFileStat.m_filename, "usernotesdb.xml")) + continue; + if (info.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) { if (!strncmp(zipFileStat.m_filename, "x32\\", 4)) @@ -166,7 +176,12 @@ BOOLEAN SetupExtractBuild( if ((zipFileCrc32 = mz_crc32(zipFileCrc32, buffer, bufferLength)) != zipFileStat.m_crc32) goto CleanupExit; - extractPath = PhConcatStrings(3, PhGetString(Context->SetupInstallPath), L"\\", PhGetString(fileName)); + extractPath = PhConcatStrings( + 3, + PhGetString(Context->SetupInstallPath), + L"\\", + PhGetString(fileName) + ); if (fullSetupPath = PhGetFullPath(extractPath->Buffer, &indexOfFileName)) { From 5f3cc85417372b5e91325103584c4f16e7e5d572 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 24 Sep 2017 17:29:17 +1000 Subject: [PATCH 0430/2058] BuildTools: Include config files for portable release --- tools/CustomBuildTool/Source Files/Build.cs | 28 ++++++++++++++++-- .../bin/Release/CustomBuildTool.exe | Bin 161792 -> 162304 bytes .../bin/Release/CustomBuildTool.pdb | Bin 73216 -> 73216 bytes 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/tools/CustomBuildTool/Source Files/Build.cs b/tools/CustomBuildTool/Source Files/Build.cs index c6a02b535668..73d01c1bc7b4 100644 --- a/tools/CustomBuildTool/Source Files/Build.cs +++ b/tools/CustomBuildTool/Source Files/Build.cs @@ -758,9 +758,30 @@ public static bool BuildBinZip() try { - if (File.Exists(BuildOutputFolder + "\\processhacker-build-bin.zip")) - File.Delete(BuildOutputFolder + "\\processhacker-build-bin.zip"); + if (File.Exists("bin\\Release32\\ProcessHacker.exe.settings.xml")) + File.Delete("bin\\Release32\\ProcessHacker.exe.settings.xml"); + if (File.Exists("bin\\Release64\\ProcessHacker.exe.settings.xml")) + File.Delete("bin\\Release64\\ProcessHacker.exe.settings.xml"); + + File.Create("bin\\Release32\\ProcessHacker.exe.settings.xml").Dispose(); + File.Create("bin\\Release64\\ProcessHacker.exe.settings.xml").Dispose(); + } + catch { } + + try + { + if (File.Exists("bin\\Release32\\usernotesdb.xml")) + File.Delete("bin\\Release32\\usernotesdb.xml"); + if (File.Exists("bin\\Release64\\usernotesdb.xml")) + File.Delete("bin\\Release64\\usernotesdb.xml"); + File.Create("bin\\Release32\\usernotesdb.xml").Dispose(); + File.Create("bin\\Release64\\usernotesdb.xml").Dispose(); + } + catch { } + + try + { if (Directory.Exists("bin\\x32")) Directory.Delete("bin\\x32", true); if (Directory.Exists("bin\\x64")) @@ -769,6 +790,9 @@ public static bool BuildBinZip() Directory.Move("bin\\Release32", "bin\\x32"); Directory.Move("bin\\Release64", "bin\\x64"); + if (File.Exists(BuildOutputFolder + "\\processhacker-build-bin.zip")) + File.Delete(BuildOutputFolder + "\\processhacker-build-bin.zip"); + Zip.CreateCompressedFolder("bin", BuildOutputFolder + "\\processhacker-build-bin.zip"); Directory.Move("bin\\x32", "bin\\Release32"); diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe b/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe index 3a5ceddc828f66058aaf9a8013e749e4dd747693..eccc44aa16cc4def7600af91ef53d0824753c23d 100644 GIT binary patch delta 11562 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 X-sjKeeJ-8dB+qDkHZW2CoAiGG%Nn|_ delta 11166 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 YYjcl3l6zeGa=m=%z(<}bmOhjI8vsptC;$Ke diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb b/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb index 6456725c97ff4e77184007b52e406f3d2a3c0e45..f3ccdd966ff702092d823ec80c0a128736eca275 100644 GIT binary patch delta 9193 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 M`EW{SajN5g0J^S^Jpcdz delta 9532 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 Date: Sun, 24 Sep 2017 18:12:25 +1000 Subject: [PATCH 0431/2058] SetupTool: Fix websetup, Fix ignored files --- tools/CustomSetupTool/CustomSetupTool/download.c | 12 ++++++------ tools/CustomSetupTool/CustomSetupTool/extract.c | 9 ++++----- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/tools/CustomSetupTool/CustomSetupTool/download.c b/tools/CustomSetupTool/CustomSetupTool/download.c index d76238c99456..227dc7e41df4 100644 --- a/tools/CustomSetupTool/CustomSetupTool/download.c +++ b/tools/CustomSetupTool/CustomSetupTool/download.c @@ -312,12 +312,12 @@ BOOLEAN SetupQueryUpdateData( if (PhIsNullOrEmptyString(Context->SetupFileVersion)) goto CleanupExit; - if (PhIsNullOrEmptyString(Context->WebSetupFileDownloadUrl)) - goto CleanupExit; - if (PhIsNullOrEmptyString(Context->WebSetupFileSignature)) - goto CleanupExit; - if (PhIsNullOrEmptyString(Context->WebSetupFileVersion)) - goto CleanupExit; + //if (PhIsNullOrEmptyString(Context->WebSetupFileDownloadUrl)) + // goto CleanupExit; + //if (PhIsNullOrEmptyString(Context->WebSetupFileSignature)) + // goto CleanupExit; + //if (PhIsNullOrEmptyString(Context->WebSetupFileVersion)) + // goto CleanupExit; success = TRUE; diff --git a/tools/CustomSetupTool/CustomSetupTool/extract.c b/tools/CustomSetupTool/CustomSetupTool/extract.c index af1efe92e6ae..a24bb20e315b 100644 --- a/tools/CustomSetupTool/CustomSetupTool/extract.c +++ b/tools/CustomSetupTool/CustomSetupTool/extract.c @@ -96,9 +96,9 @@ BOOLEAN SetupExtractBuild( if (!mz_zip_reader_file_stat(&zip_archive, i, &zipFileStat)) continue; - if (!strstr(zipFileStat.m_filename, "ProcessHacker.exe.settings.xml")) + if (strstr(zipFileStat.m_filename, "ProcessHacker.exe.settings.xml")) continue; - if (!strstr(zipFileStat.m_filename, "usernotesdb.xml")) + if (strstr(zipFileStat.m_filename, "usernotesdb.xml")) continue; if (info.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) @@ -135,9 +135,9 @@ BOOLEAN SetupExtractBuild( if (!mz_zip_reader_file_stat(&zip_archive, i, &zipFileStat)) continue; - if (!strstr(zipFileStat.m_filename, "ProcessHacker.exe.settings.xml")) + if (strstr(zipFileStat.m_filename, "ProcessHacker.exe.settings.xml")) continue; - if (!strstr(zipFileStat.m_filename, "usernotesdb.xml")) + if (strstr(zipFileStat.m_filename, "usernotesdb.xml")) continue; if (info.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) @@ -279,4 +279,3 @@ BOOLEAN SetupExtractBuild( return FALSE; } - From 5c67dcde1df084263bda334bf1a01b891a5ed2e9 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 27 Sep 2017 17:31:07 +1000 Subject: [PATCH 0432/2058] SetupTool: Remove CRT functions, Add workqueue support --- .../CustomSetupTool/configpage.c | 2 +- .../CustomSetupTool/download.c | 2 +- .../CustomSetupTool/downloadpage.c | 2 +- .../CustomSetupTool/CustomSetupTool/extract.c | 37 +++++++++---------- .../CustomSetupTool/include/setup.h | 1 + .../CustomSetupTool/CustomSetupTool/install.c | 6 +-- .../CustomSetupTool/CustomSetupTool/update.c | 1 - 7 files changed, 22 insertions(+), 29 deletions(-) diff --git a/tools/CustomSetupTool/CustomSetupTool/configpage.c b/tools/CustomSetupTool/CustomSetupTool/configpage.c index f016e5902fb6..b4dbe1e2adb2 100644 --- a/tools/CustomSetupTool/CustomSetupTool/configpage.c +++ b/tools/CustomSetupTool/CustomSetupTool/configpage.c @@ -72,7 +72,7 @@ INT_PTR CALLBACK SetupPropPage3_WndProc( Button_SetCheck(GetDlgItem(hwndDlg, IDC_SHORTCUT_ALL_CHECK), TRUE); //Button_SetCheck(GetDlgItem(hwndDlg, IDC_KPH_CHECK), TRUE); //Button_SetCheck(GetDlgItem(hwndDlg, IDC_DBGTOOLS_CHECK), TRUE); - //Button_SetCheck(GetDlgItem(hwndDlg, IDC_PHSTART_CHECK), TRUE); + Button_SetCheck(GetDlgItem(hwndDlg, IDC_PHSTART_CHECK), TRUE); EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); } diff --git a/tools/CustomSetupTool/CustomSetupTool/download.c b/tools/CustomSetupTool/CustomSetupTool/download.c index 227dc7e41df4..830e8f5939a0 100644 --- a/tools/CustomSetupTool/CustomSetupTool/download.c +++ b/tools/CustomSetupTool/CustomSetupTool/download.c @@ -591,8 +591,8 @@ BOOLEAN UpdateDownloadUpdateData( PhDereferenceObject(subMessage); PhDereferenceObject(statusMessage); PhDereferenceObject(totalSpeed); - PhDereferenceObject(totalLength); PhDereferenceObject(totalDownloaded); + PhDereferenceObject(totalLength); } } diff --git a/tools/CustomSetupTool/CustomSetupTool/downloadpage.c b/tools/CustomSetupTool/CustomSetupTool/downloadpage.c index 8d82b65a09a4..6779444751ec 100644 --- a/tools/CustomSetupTool/CustomSetupTool/downloadpage.c +++ b/tools/CustomSetupTool/CustomSetupTool/downloadpage.c @@ -97,7 +97,7 @@ INT_PTR CALLBACK SetupPropPage5_WndProc( // Disable Next/Back buttons PropSheet_SetWizButtons(context->DialogHandle, 0); - PhCreateThread2(SetupDownloadProgressThread, context); + PhQueueItemWorkQueue(PhGetGlobalWorkQueue(), SetupDownloadProgressThread, context); } break; } diff --git a/tools/CustomSetupTool/CustomSetupTool/extract.c b/tools/CustomSetupTool/CustomSetupTool/extract.c index a24bb20e315b..f5c74259fb86 100644 --- a/tools/CustomSetupTool/CustomSetupTool/extract.c +++ b/tools/CustomSetupTool/CustomSetupTool/extract.c @@ -92,28 +92,31 @@ BOOLEAN SetupExtractBuild( for (mz_uint i = 0; i < mz_zip_reader_get_num_files(&zip_archive); i++) { mz_zip_archive_file_stat zipFileStat; + PPH_STRING fileName; if (!mz_zip_reader_file_stat(&zip_archive, i, &zipFileStat)) continue; - if (strstr(zipFileStat.m_filename, "ProcessHacker.exe.settings.xml")) - continue; - if (strstr(zipFileStat.m_filename, "usernotesdb.xml")) - continue; + fileName = PhConvertUtf8ToUtf16(zipFileStat.m_filename); if (info.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) { - if (!strncmp(zipFileStat.m_filename, "x32\\", 4)) + if (PhStartsWithString2(fileName, L"x32\\", TRUE)) continue; } else { - if (!strncmp(zipFileStat.m_filename, "x64\\", 4)) + if (PhStartsWithString2(fileName, L"x64\\", TRUE)) continue; - if (!strncmp(zipFileStat.m_filename, "x86\\", 4)) + if (PhStartsWithString2(fileName, L"x86\\", TRUE)) continue; } + if (PhFindStringInString(fileName, 0, L"ProcessHacker.exe.settings.xml") != -1) + continue; + if (PhFindStringInString(fileName, 0, L"usernotesdb.xml") != -1) + continue; + totalLength += zipFileStat.m_uncomp_size; } @@ -135,30 +138,28 @@ BOOLEAN SetupExtractBuild( if (!mz_zip_reader_file_stat(&zip_archive, i, &zipFileStat)) continue; - if (strstr(zipFileStat.m_filename, "ProcessHacker.exe.settings.xml")) + fileName = PhConvertUtf8ToUtf16(zipFileStat.m_filename); + + if (PhFindStringInString(fileName, 0, L"ProcessHacker.exe.settings.xml") != -1) continue; - if (strstr(zipFileStat.m_filename, "usernotesdb.xml")) + if (PhFindStringInString(fileName, 0, L"usernotesdb.xml") != -1) continue; if (info.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) { - if (!strncmp(zipFileStat.m_filename, "x32\\", 4)) + if (PhStartsWithString2(fileName, L"x32\\", TRUE)) continue; - fileName = PhConvertUtf8ToUtf16(zipFileStat.m_filename); - if (PhFindStringInString(fileName, 0, L"x64\\") != -1) PhMoveReference(&fileName, PhSubstring(fileName, 4, (fileName->Length / 2) - 4)); } else { - if (!strncmp(zipFileStat.m_filename, "x64\\", 4)) + if (PhStartsWithString2(fileName, L"x64\\", TRUE)) continue; - if (!strncmp(zipFileStat.m_filename, "x86\\", 4)) + if (PhStartsWithString2(fileName, L"x86\\", TRUE)) continue; - fileName = PhConvertUtf8ToUtf16(zipFileStat.m_filename); - if (PhFindStringInString(fileName, 0, L"x32\\") != -1) PhMoveReference(&fileName, PhSubstring(fileName, 4, (fileName->Length / 2) - 4)); } @@ -264,18 +265,14 @@ BOOLEAN SetupExtractBuild( } mz_zip_reader_end(&zip_archive); - if (extractPath) PhDereferenceObject(extractPath); - return TRUE; CleanupExit: mz_zip_reader_end(&zip_archive); - if (extractPath) PhDereferenceObject(extractPath); - return FALSE; } diff --git a/tools/CustomSetupTool/CustomSetupTool/include/setup.h b/tools/CustomSetupTool/CustomSetupTool/include/setup.h index e63de392ceca..eef82542cdf9 100644 --- a/tools/CustomSetupTool/CustomSetupTool/include/setup.h +++ b/tools/CustomSetupTool/CustomSetupTool/include/setup.h @@ -32,6 +32,7 @@ #include #include #include +#include #include #include diff --git a/tools/CustomSetupTool/CustomSetupTool/install.c b/tools/CustomSetupTool/CustomSetupTool/install.c index 69826e9bc9ca..e54c6642ada3 100644 --- a/tools/CustomSetupTool/CustomSetupTool/install.c +++ b/tools/CustomSetupTool/CustomSetupTool/install.c @@ -76,7 +76,6 @@ NTSTATUS SetupProgressThread( return STATUS_SUCCESS; CleanupExit: - PostMessage(Context->DialogHandle, PSM_SETCURSELID, 0, IDD_ERROR); return STATUS_FAIL_CHECK; } @@ -139,8 +138,6 @@ INT_PTR CALLBACK SetupInstallPropPage_WndProc( break; case PSN_SETACTIVE: { - HANDLE threadHandle; - context->MainHeaderHandle = GetDlgItem(hwndDlg, IDC_MAINHEADER); context->StatusHandle = GetDlgItem(hwndDlg, IDC_INSTALL_STATUS); context->SubStatusHandle = GetDlgItem(hwndDlg, IDC_INSTALL_SUBSTATUS); @@ -157,8 +154,7 @@ INT_PTR CALLBACK SetupInstallPropPage_WndProc( { SetupRunning = TRUE; - if (threadHandle = PhCreateThread(0, SetupProgressThread, context)) - NtClose(threadHandle); + PhQueueItemWorkQueue(PhGetGlobalWorkQueue(), SetupProgressThread, context); } } break; diff --git a/tools/CustomSetupTool/CustomSetupTool/update.c b/tools/CustomSetupTool/CustomSetupTool/update.c index 2bfaff5d7db2..8df1ced0220b 100644 --- a/tools/CustomSetupTool/CustomSetupTool/update.c +++ b/tools/CustomSetupTool/CustomSetupTool/update.c @@ -20,7 +20,6 @@ #include #include -#include #define WM_TASKDIALOGINIT (WM_APP + 550) HWND UpdateDialogHandle = NULL; From de74d68f4bca7dad2194298eaaa2ab546f69cb76 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 28 Sep 2017 02:52:06 +1000 Subject: [PATCH 0433/2058] Add PhEnumSettings callback --- phlib/include/settings.h | 21 ++++++++++++++++----- phlib/settings.c | 21 +++++++++++++++++++++ 2 files changed, 37 insertions(+), 5 deletions(-) diff --git a/phlib/include/settings.h b/phlib/include/settings.h index 7cd07eb07b1d..b279298511b3 100644 --- a/phlib/include/settings.h +++ b/phlib/include/settings.h @@ -11,11 +11,11 @@ extern "C" { // PH_STRINGREFs at compile time, for a small speed boost. #define ADD_SETTING_WRAPPER(Type, Name, DefaultValue) \ - { \ - static PH_STRINGREF name = PH_STRINGREF_INIT(Name); \ - static PH_STRINGREF defaultValue = PH_STRINGREF_INIT(DefaultValue); \ - PhAddSetting(Type, &name, &defaultValue); \ - } +{ \ + static PH_STRINGREF name = PH_STRINGREF_INIT(Name); \ + static PH_STRINGREF defaultValue = PH_STRINGREF_INIT(DefaultValue); \ + PhAddSetting(Type, &name, &defaultValue); \ +} #define PhpAddStringSetting(A, B) ADD_SETTING_WRAPPER(StringSettingType, A, B) #define PhpAddIntegerSetting(A, B) ADD_SETTING_WRAPPER(IntegerSettingType, A, B) @@ -61,6 +61,17 @@ VOID PhUpdateCachedSettings( VOID ); +// private +typedef BOOLEAN (NTAPI *PPH_SETTINGS_ENUM_CALLBACK)( + _In_ PPH_SETTING Setting, + _In_ PVOID Context + ); + +VOID PhEnumSettings( + _In_ PPH_SETTINGS_ENUM_CALLBACK Callback, + _In_ PVOID Context + ); + // begin_phapppub _May_raise_ PHLIBAPI diff --git a/phlib/settings.c b/phlib/settings.c index 4f38546f7393..ba8c54732783 100644 --- a/phlib/settings.c +++ b/phlib/settings.c @@ -319,6 +319,27 @@ static PVOID PhpLookupSetting( return setting; } +VOID PhEnumSettings( + _In_ PPH_SETTINGS_ENUM_CALLBACK Callback, + _In_ PVOID Context + ) +{ + PH_HASHTABLE_ENUM_CONTEXT enumContext; + PPH_SETTING setting; + + PhAcquireQueuedLockExclusive(&PhSettingsLock); + + PhBeginEnumHashtable(PhSettingsHashtable, &enumContext); + + while (setting = PhNextEnumHashtable(&enumContext)) + { + if (!Callback(setting, Context)) + break; + } + + PhReleaseQueuedLockExclusive(&PhSettingsLock); +} + _May_raise_ ULONG PhGetIntegerSetting( _In_ PWSTR Name ) From 5af1f81eb4d68f6ed71f0f04861d23faf0379131 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 28 Sep 2017 03:52:40 +1000 Subject: [PATCH 0434/2058] HardwareDevices: Fix macro usage --- plugins/HardwareDevices/diskoptions.c | 5 +---- plugins/HardwareDevices/netoptions.c | 5 +---- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/plugins/HardwareDevices/diskoptions.c b/plugins/HardwareDevices/diskoptions.c index bd252a5171ce..0e7f2668b46e 100644 --- a/plugins/HardwareDevices/diskoptions.c +++ b/plugins/HardwareDevices/diskoptions.c @@ -23,9 +23,6 @@ #include "devices.h" #include -#define ITEM_CHECKED (INDEXTOSTATEIMAGEMASK(2)) -#define ITEM_UNCHECKED (INDEXTOSTATEIMAGEMASK(1)) - typedef struct _DISK_ENUM_ENTRY { ULONG DeviceIndex; @@ -210,7 +207,7 @@ VOID AddDiskDriveToListView( ); if (found) - ListView_SetItemState(Context->ListViewHandle, lvItemIndex, ITEM_CHECKED, LVIS_STATEIMAGEMASK); + ListView_SetCheckState(Context->ListViewHandle, lvItemIndex, TRUE); DeleteDiskId(&adapterId); } diff --git a/plugins/HardwareDevices/netoptions.c b/plugins/HardwareDevices/netoptions.c index 0d5a25d4005c..a23e4a440e29 100644 --- a/plugins/HardwareDevices/netoptions.c +++ b/plugins/HardwareDevices/netoptions.c @@ -26,9 +26,6 @@ #include #include -#define ITEM_CHECKED (INDEXTOSTATEIMAGEMASK(2)) -#define ITEM_UNCHECKED (INDEXTOSTATEIMAGEMASK(1)) - typedef struct _NET_ENUM_ENTRY { BOOLEAN DevicePresent; @@ -227,7 +224,7 @@ VOID AddNetworkAdapterToListView( ); if (found) - ListView_SetItemState(Context->ListViewHandle, lvItemIndex, ITEM_CHECKED, LVIS_STATEIMAGEMASK); + ListView_SetCheckState(Context->ListViewHandle, lvItemIndex, TRUE); DeleteNetAdapterId(&adapterId); } From b1f6127995f817e343f299a91736eb73dcff1e39 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 28 Sep 2017 16:43:37 +1000 Subject: [PATCH 0435/2058] Fix macro usage --- plugins/ExtraPlugins/disabled.c | 6 +++--- plugins/ExtraPlugins/main.h | 3 --- plugins/HardwareDevices/diskoptions.c | 4 ++-- plugins/HardwareDevices/netoptions.c | 4 ++-- 4 files changed, 7 insertions(+), 10 deletions(-) diff --git a/plugins/ExtraPlugins/disabled.c b/plugins/ExtraPlugins/disabled.c index ff4405df5234..9d57f680ad6a 100644 --- a/plugins/ExtraPlugins/disabled.c +++ b/plugins/ExtraPlugins/disabled.c @@ -47,7 +47,7 @@ VOID PhAddDisabledPlugins( lvItemIndex = PhAddListViewItem(Context->ListViewHandle, MAXINT, PhGetString(displayText), displayText); PhReleaseQueuedLockExclusive(&Context->ListLock); - ListView_SetItemState(Context->ListViewHandle, lvItemIndex, ITEM_CHECKED, LVIS_STATEIMAGEMASK); + ListView_SetCheckState(Context->ListViewHandle, lvItemIndex, TRUE); } } @@ -143,7 +143,7 @@ INT_PTR CALLBACK DisabledPluginsDlgProc( { switch (listView->uNewState & LVIS_STATEIMAGEMASK) { - case 0x2000: // checked + case INDEXTOSTATEIMAGEMASK(2): // checked { PPH_STRING param = (PPH_STRING)listView->lParam; @@ -163,7 +163,7 @@ INT_PTR CALLBACK DisabledPluginsDlgProc( //context->OptionsChanged = TRUE; } break; - case 0x1000: // unchecked + case INDEXTOSTATEIMAGEMASK(1): // unchecked { PPH_STRING param = (PPH_STRING)listView->lParam; diff --git a/plugins/ExtraPlugins/main.h b/plugins/ExtraPlugins/main.h index 6ccbc8adda4b..36be49543ef1 100644 --- a/plugins/ExtraPlugins/main.h +++ b/plugins/ExtraPlugins/main.h @@ -60,9 +60,6 @@ ((ULONGLONG)(build) << 16) | \ ((ULONGLONG)(revision) << 0)) -#define ITEM_CHECKED (INDEXTOSTATEIMAGEMASK(2)) -#define ITEM_UNCHECKED (INDEXTOSTATEIMAGEMASK(1)) - extern PPH_PLUGIN PluginInstance; typedef enum _TREE_PLUGIN_STATE diff --git a/plugins/HardwareDevices/diskoptions.c b/plugins/HardwareDevices/diskoptions.c index 0e7f2668b46e..01059908b1d8 100644 --- a/plugins/HardwareDevices/diskoptions.c +++ b/plugins/HardwareDevices/diskoptions.c @@ -663,7 +663,7 @@ INT_PTR CALLBACK DiskDriveOptionsDlgProc( { switch (listView->uNewState & LVIS_STATEIMAGEMASK) { - case 0x2000: // checked + case INDEXTOSTATEIMAGEMASK(2): // checked { PDV_DISK_ID param = (PDV_DISK_ID)listView->lParam; @@ -678,7 +678,7 @@ INT_PTR CALLBACK DiskDriveOptionsDlgProc( context->OptionsChanged = TRUE; } break; - case 0x1000: // unchecked + case INDEXTOSTATEIMAGEMASK(1): // unchecked { PDV_DISK_ID param = (PDV_DISK_ID)listView->lParam; diff --git a/plugins/HardwareDevices/netoptions.c b/plugins/HardwareDevices/netoptions.c index a23e4a440e29..c658ce3607fa 100644 --- a/plugins/HardwareDevices/netoptions.c +++ b/plugins/HardwareDevices/netoptions.c @@ -787,7 +787,7 @@ INT_PTR CALLBACK NetworkAdapterOptionsDlgProc( { switch (listView->uNewState & LVIS_STATEIMAGEMASK) { - case 0x2000: // checked + case INDEXTOSTATEIMAGEMASK(2): // checked { PDV_NETADAPTER_ID param = (PDV_NETADAPTER_ID)listView->lParam; @@ -802,7 +802,7 @@ INT_PTR CALLBACK NetworkAdapterOptionsDlgProc( context->OptionsChanged = TRUE; } break; - case 0x1000: // unchecked + case INDEXTOSTATEIMAGEMASK(1): // unchecked { PDV_NETADAPTER_ID param = (PDV_NETADAPTER_ID)listView->lParam; From 86cf15c228dfd185beb23fa1d9e5720c4e9d641b Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 29 Sep 2017 04:53:09 +1000 Subject: [PATCH 0436/2058] DotNetTools: Fix macro usage --- plugins/DotNetTools/counters.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/DotNetTools/counters.c b/plugins/DotNetTools/counters.c index 669831c546db..badf758550f0 100644 --- a/plugins/DotNetTools/counters.c +++ b/plugins/DotNetTools/counters.c @@ -60,7 +60,7 @@ PVOID GetLegacyBlockTableEntry( // Directory has offset in bytes of block ULONG offsetEntry = IpcBlock->FullIPCHeader.EntryTable[EntryId].Offset; - return ((PBYTE)IpcBlock) + offsetBase + offsetEntry; + return PTR_ADD_OFFSET(IpcBlock, offsetBase + offsetEntry); } else { @@ -71,7 +71,7 @@ PVOID GetLegacyBlockTableEntry( // Directory has offset in bytes of block ULONG offsetEntry = IpcBlock->FullIPCHeader.EntryTable[EntryId].Offset; - return ((PBYTE)IpcBlock) + offsetBase + offsetEntry; + return PTR_ADD_OFFSET(IpcBlock, offsetBase + offsetEntry); } } From 29d62de5116a21ac0d80893133459501314c93a9 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 29 Sep 2017 04:53:50 +1000 Subject: [PATCH 0437/2058] HardwareDevices: Fix options window text clipping --- plugins/HardwareDevices/diskoptions.c | 2 ++ plugins/HardwareDevices/netoptions.c | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/plugins/HardwareDevices/diskoptions.c b/plugins/HardwareDevices/diskoptions.c index 01059908b1d8..968ec97569f0 100644 --- a/plugins/HardwareDevices/diskoptions.c +++ b/plugins/HardwareDevices/diskoptions.c @@ -646,6 +646,8 @@ INT_PTR CALLBACK DiskDriveOptionsDlgProc( case WM_SIZE: { PhLayoutManagerLayout(&context->LayoutManager); + + ExtendedListView_SetColumnWidth(context->ListViewHandle, 0, ELVSCW_AUTOSIZE_REMAININGSPACE); } break; case WM_NOTIFY: diff --git a/plugins/HardwareDevices/netoptions.c b/plugins/HardwareDevices/netoptions.c index c658ce3607fa..e6a24711514f 100644 --- a/plugins/HardwareDevices/netoptions.c +++ b/plugins/HardwareDevices/netoptions.c @@ -744,6 +744,8 @@ INT_PTR CALLBACK NetworkAdapterOptionsDlgProc( case WM_SIZE: { PhLayoutManagerLayout(&context->LayoutManager); + + ExtendedListView_SetColumnWidth(context->ListViewHandle, 0, ELVSCW_AUTOSIZE_REMAININGSPACE); } break; case WM_COMMAND: @@ -767,6 +769,8 @@ INT_PTR CALLBACK NetworkAdapterOptionsDlgProc( ListView_DeleteAllItems(context->ListViewHandle); FindNetworkAdapters(context); + + ExtendedListView_SetColumnWidth(context->ListViewHandle, 0, ELVSCW_AUTOSIZE_REMAININGSPACE); } break; } From eaa227c0255c5a134bf59647b02e694f833be4e6 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 29 Sep 2017 18:05:11 +1000 Subject: [PATCH 0438/2058] Update settings exports --- phlib/include/settings.h | 13 +++++++++++++ phlib/settings.c | 30 +++++++++--------------------- 2 files changed, 22 insertions(+), 21 deletions(-) diff --git a/phlib/include/settings.h b/phlib/include/settings.h index b279298511b3..ba1b03718fd0 100644 --- a/phlib/include/settings.h +++ b/phlib/include/settings.h @@ -62,6 +62,19 @@ VOID PhUpdateCachedSettings( ); // private + +PPH_STRING PhSettingToString( + _In_ PH_SETTING_TYPE Type, + _In_ PPH_SETTING Setting + ); + +BOOLEAN PhSettingFromString( + _In_ PH_SETTING_TYPE Type, + _In_ PPH_STRINGREF StringRef, + _In_opt_ PPH_STRING String, + _Inout_ PPH_SETTING Setting + ); + typedef BOOLEAN (NTAPI *PPH_SETTINGS_ENUM_CALLBACK)( _In_ PPH_SETTING Setting, _In_ PVOID Context diff --git a/phlib/settings.c b/phlib/settings.c index ba8c54732783..bb78e121b21b 100644 --- a/phlib/settings.c +++ b/phlib/settings.c @@ -57,18 +57,6 @@ ULONG PhpGetCurrentScale( VOID ); -PPH_STRING PhpSettingToString( - _In_ PH_SETTING_TYPE Type, - _In_ PPH_SETTING Setting - ); - -BOOLEAN PhpSettingFromString( - _In_ PH_SETTING_TYPE Type, - _In_ PPH_STRINGREF StringRef, - _In_opt_ PPH_STRING String, - _Inout_ PPH_SETTING Setting - ); - VOID PhpFreeSettingValue( _In_ PH_SETTING_TYPE Type, _In_ PPH_SETTING Setting @@ -141,7 +129,7 @@ static ULONG PhpGetCurrentScale( return dpi; } -static PPH_STRING PhpSettingToString( +PPH_STRING PhSettingToString( _In_ PH_SETTING_TYPE Type, _In_ PPH_SETTING Setting ) @@ -181,7 +169,7 @@ static PPH_STRING PhpSettingToString( return PhReferenceEmptyString(); } -static BOOLEAN PhpSettingFromString( +BOOLEAN PhSettingFromString( _In_ PH_SETTING_TYPE Type, _In_ PPH_STRINGREF StringRef, _In_opt_ PPH_STRING String, @@ -685,14 +673,14 @@ VOID PhConvertIgnoredSettings( { PhpFreeSettingValue(setting->Type, setting); - if (!PhpSettingFromString( + if (!PhSettingFromString( setting->Type, &((PPH_STRING)ignoredSetting->u.Pointer)->sr, ignoredSetting->u.Pointer, setting )) { - PhpSettingFromString( + PhSettingFromString( setting->Type, &setting->DefaultValue, NULL, @@ -800,14 +788,14 @@ NTSTATUS PhLoadSettings( { PhpFreeSettingValue(setting->Type, setting); - if (!PhpSettingFromString( + if (!PhSettingFromString( setting->Type, &settingValue->sr, settingValue, setting )) { - PhpSettingFromString( + PhSettingFromString( setting->Type, &setting->DefaultValue, NULL, @@ -912,7 +900,7 @@ NTSTATUS PhSaveSettings( { PPH_STRING settingValue; - settingValue = PhpSettingToString(setting->Type, setting); + settingValue = PhSettingToString(setting->Type, setting); PhpCreateSettingElement(topNode, &setting->Name, &settingValue->sr); PhDereferenceObject(settingValue); } @@ -991,7 +979,7 @@ VOID PhResetSettings( while (setting = PhNextEnumHashtable(&enumContext)) { PhpFreeSettingValue(setting->Type, setting); - PhpSettingFromString(setting->Type, &setting->DefaultValue, NULL, setting); + PhSettingFromString(setting->Type, &setting->DefaultValue, NULL, setting); } PhReleaseQueuedLockExclusive(&PhSettingsLock); @@ -1010,7 +998,7 @@ VOID PhAddSetting( setting.DefaultValue = *DefaultValue; memset(&setting.u, 0, sizeof(setting.u)); - PhpSettingFromString(Type, &setting.DefaultValue, NULL, &setting); + PhSettingFromString(Type, &setting.DefaultValue, NULL, &setting); PhAddEntryHashtable(PhSettingsHashtable, &setting); } From ee6a027973c324b47fcbb0db8d9742a960a23cc1 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 29 Sep 2017 20:04:44 +1000 Subject: [PATCH 0439/2058] Update options window layout, Add advaned options editor --- ProcessHacker/ProcessHacker.rc | 57 +- ProcessHacker/options.c | 1116 ++++++++++++++++++++++---------- ProcessHacker/resource.h | 26 +- 3 files changed, 786 insertions(+), 413 deletions(-) diff --git a/ProcessHacker/ProcessHacker.rc b/ProcessHacker/ProcessHacker.rc index 4e3105150b98..47f7c8402e2b 100644 --- a/ProcessHacker/ProcessHacker.rc +++ b/ProcessHacker/ProcessHacker.rc @@ -1153,31 +1153,27 @@ BEGIN EDITTEXT IDC_CHOICESIMPLE,7,20,185,13,ES_PASSWORD | ES_AUTOHSCROLL | NOT WS_VISIBLE END -IDD_OPTGENERAL DIALOGEX 0, 0, 250, 154 +IDD_OPTGENERAL DIALOGEX 0, 0, 315, 220 STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "General" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN LTEXT "Search engine:",IDC_STATIC,7,8,49,8 - EDITTEXT IDC_SEARCHENGINE,61,7,182,12,ES_AUTOHSCROLL + EDITTEXT IDC_SEARCHENGINE,61,7,247,12,ES_AUTOHSCROLL LTEXT "PE viewer:",IDC_STATIC,7,23,35,8 - EDITTEXT IDC_PEVIEWER,61,22,182,12,ES_AUTOHSCROLL + EDITTEXT IDC_PEVIEWER,61,22,247,12,ES_AUTOHSCROLL LTEXT "Max. size unit:",IDC_STATIC,7,38,49,8 COMBOBOX IDC_MAXSIZEUNIT,61,37,39,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP LTEXT "Icon processes:",IDC_STATIC,7,55,52,8 EDITTEXT IDC_ICONPROCESSES,61,53,40,12,ES_AUTOHSCROLL | ES_NUMBER - CONTROL "Allow only one instance",IDC_ALLOWONLYONEINSTANCE, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,71,91,10 - CONTROL "Hide when closed",IDC_HIDEONCLOSE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,83,71,10 - CONTROL "Hide when minimized",IDC_HIDEONMINIMIZE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,95,81,10 - CONTROL "Start hidden",IDC_STARTHIDDEN,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,119,55,10 - CONTROL "Collapse services on start",IDC_COLLAPSESERVICES,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,122,71,98,10 - CONTROL "Single-click tray icons",IDC_ICONSINGLECLICK,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,122,83,83,10 - CONTROL "Icon click toggles visibility",IDC_ICONTOGGLESVISIBILITY, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,122,95,97,10 - CONTROL "Enable plugins",IDC_ENABLEPLUGINS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,122,107,61,10 - PUSHBUTTON "Font...",IDC_FONT,7,133,50,14 - CONTROL "Start when I log on",IDC_STARTATLOGON,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,107,77,10 + PUSHBUTTON "Font...",IDC_FONT,179,53,49,14 + PUSHBUTTON "Make default...",IDC_REPLACETASKMANAGER,179,69,72,14 + LTEXT "Graph history length:",IDC_STATIC,106,39,69,8 + EDITTEXT IDC_SAMPLECOUNT,180,38,48,12,ES_AUTOHSCROLL | ES_NUMBER + CONTROL "Automatic",IDC_SAMPLECOUNTAUTOMATIC,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,233,39,48,10 + CONTROL "",IDC_SETTINGS,"SysListView32",LVS_LIST | LVS_SINGLESEL | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,88,301,125 + LTEXT "Application font:",IDC_STATIC,121,55,54,8 + RTEXT "Process Hacker is the default Task Manager:",IDC_DEFSTATE,7,71,166,8 END IDD_OPTHIGHLIGHTING DIALOGEX 0, 0, 250, 174 @@ -1325,31 +1321,12 @@ BEGIN RTEXT "Static",IDC_ZSHAREDWS_V,78,167,42,8,SS_ENDELLIPSIS END -IDD_OPTADVANCED DIALOGEX 0, 0, 250, 150 +IDD_OPTADVANCED DIALOGEX 0, 0, 317, 225 STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Advanced" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN - CONTROL "Enable warnings",IDC_ENABLEWARNINGS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,7,68,10 - CONTROL "Enable kernel-mode driver",IDC_ENABLEKERNELMODEDRIVER, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,19,99,10 - CONTROL "Hide unnamed handles",IDC_HIDEUNNAMEDHANDLES,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,31,88,10 - CONTROL "Check images for digital signatures and packing",IDC_ENABLESTAGE2, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,43,167,10 - CONTROL "Resolve addresses for network connections",IDC_ENABLENETWORKRESOLVE, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,55,155,10 - CONTROL "Include CPU (and other) usage of children in collapsed processes",IDC_PROPAGATECPUUSAGE, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,67,223,10 - CONTROL "Show tooltips instantly",IDC_ENABLEINSTANTTOOLTIPS, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,79,88,10 - CONTROL "Enable cycle-based CPU usage",IDC_ENABLECYCLECPUUSAGE, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,91,114,10 - CONTROL "Replace Task Manager with Process Hacker",IDC_REPLACETASKMANAGER, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,105,154,10 - PUSHBUTTON "Change...",IDC_CHANGE,161,103,62,14 - LTEXT "History sample count:",IDC_SAMPLECOUNTLABEL,7,121,70,8 - EDITTEXT IDC_SAMPLECOUNT,82,120,39,12,ES_AUTOHSCROLL | ES_NUMBER - CONTROL "Automatic",IDC_SAMPLECOUNTAUTOMATIC,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,126,121,48,10 + CONTROL "",IDC_SETTINGS,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,7,303,211 END IDD_GDIHANDLES DIALOGEX 0, 0, 351, 307 @@ -2157,9 +2134,9 @@ BEGIN IDD_OPTGENERAL, DIALOG BEGIN LEFTMARGIN, 7 - RIGHTMARGIN, 243 + RIGHTMARGIN, 308 TOPMARGIN, 7 - BOTTOMMARGIN, 147 + BOTTOMMARGIN, 213 END IDD_OPTHIGHLIGHTING, DIALOG @@ -2213,9 +2190,9 @@ BEGIN IDD_OPTADVANCED, DIALOG BEGIN LEFTMARGIN, 7 - RIGHTMARGIN, 243 + RIGHTMARGIN, 310 TOPMARGIN, 7 - BOTTOMMARGIN, 143 + BOTTOMMARGIN, 218 END IDD_GDIHANDLES, DIALOG diff --git a/ProcessHacker/options.c b/ProcessHacker/options.c index d57347a8497a..e095121f8975 100644 --- a/ProcessHacker/options.c +++ b/ProcessHacker/options.c @@ -117,6 +117,22 @@ PPH_OPTIONS_SECTION PhOptionsCreateSection( _In_ PVOID Parameter ); +PPH_OPTIONS_SECTION PhOptionsCreateSectionAdvanced( + _In_ PWSTR Name, + _In_ PVOID Instance, + _In_ PWSTR Template, + _In_ DLGPROC DialogProc, + _In_ PVOID Parameter + ); + +BOOLEAN PhpIsDefaultTaskManager( + VOID + ); + +VOID PhpSetDefaultTaskManager( + _In_ HWND ParentWindowHandle + ); + static HWND PhOptionsWindowHandle = NULL; static PPH_LIST PhOptionsDialogList = NULL; static PH_LAYOUT_MANAGER WindowLayoutManager; @@ -129,7 +145,6 @@ static HIMAGELIST OptionsTreeImageList = NULL; // All static BOOLEAN RestartRequired = FALSE; -static POINT StartLocation; // General static PH_STRINGREF CurrentUserRunKeyName = PH_STRINGREF_INIT(L"Software\\Microsoft\\Windows\\CurrentVersion\\Run"); @@ -137,11 +152,11 @@ static BOOLEAN CurrentUserRunPresent; static BOOLEAN CurrentUserRunStartHidden; static HFONT CurrentFontInstance; static PPH_STRING NewFontSelection; +static HIMAGELIST GeneralListviewImageList = NULL; // Advanced static PH_STRINGREF TaskMgrImageOptionsKeyName = PH_STRINGREF_INIT(L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\taskmgr.exe"); static PPH_STRING OldTaskMgrDebugger; -static BOOLEAN OldReplaceTaskMgr; static HWND WindowHandleForElevate; // Highlighting @@ -152,19 +167,18 @@ VOID PhShowOptionsDialog( ) { if (PhStartupParameters.ShowOptions) - StartLocation = PhStartupParameters.Point; + { + PhpSetDefaultTaskManager(ParentWindowHandle); + } else - StartLocation.x = MINLONG; - - DialogBox( - PhInstanceHandle, - MAKEINTRESOURCE(IDD_OPTIONS), - ParentWindowHandle, - PhOptionsDialogProc - ); - - if (!PhStartupParameters.ShowOptions) { + DialogBox( + PhInstanceHandle, + MAKEINTRESOURCE(IDD_OPTIONS), + ParentWindowHandle, + PhOptionsDialogProc + ); + PhUpdateCachedSettings(); ProcessHacker_SaveAllSettings(PhMainWndHandle); PhInvalidateAllProcessNodes(); @@ -195,48 +209,98 @@ VOID PhShowOptionsDialog( } } } - else - { - // Main window not available. - if (PhSettingsFileName) - PhSaveSettings(PhSettingsFileName->Buffer); - } } static HTREEITEM PhpOptionsTreeViewAddItem( _In_ PWSTR Text, - _In_ PVOID Context + _In_ PVOID Context, + _In_ HTREEITEM InsertAfter ) { TV_INSERTSTRUCT insert; memset(&insert, 0, sizeof(TV_INSERTSTRUCT)); - insert.item.mask = TVIF_TEXT | TVIF_PARAM; - insert.hInsertAfter = TVI_LAST; insert.hParent = TVI_ROOT; + insert.hInsertAfter = InsertAfter; + insert.item.mask = TVIF_TEXT | TVIF_PARAM; insert.item.pszText = Text; insert.item.lParam = (LPARAM)Context; return TreeView_InsertItem(OptionsTreeControl, &insert); } +static VOID PhpOptionsShowHideTreeViewItem( + _In_ BOOLEAN Hide + ) +{ + HTREEITEM tvItemGeneral = NULL; + HTREEITEM tvItemAdvanced = NULL; + HTREEITEM tvItemCurrent; + + tvItemCurrent = TreeView_GetRoot(OptionsTreeControl); + + while (tvItemCurrent) + { + TVITEM tvItem; + WCHAR buffer[MAX_PATH]; + + tvItem.mask = TVIF_TEXT | TVIF_HANDLE; + tvItem.hItem = tvItemCurrent; + tvItem.cchTextMax = ARRAYSIZE(buffer); + tvItem.pszText = buffer; + + if (TreeView_GetItem(OptionsTreeControl, &tvItem)) + { + if (PhEqualStringZ(buffer, L"Advanced", TRUE)) + { + tvItemAdvanced = tvItemCurrent; + } + else if (PhEqualStringZ(buffer, L"General", TRUE)) + { + tvItemGeneral = tvItemCurrent; + } + } + + tvItemCurrent = TreeView_GetNextSibling(OptionsTreeControl, tvItemCurrent); + } + + if (Hide) + { + if (tvItemAdvanced) + TreeView_DeleteItem(OptionsTreeControl, tvItemAdvanced); + } + else + { + static PH_STRINGREF sectionName = PH_STRINGREF_INIT(L"Advanced"); + + if (tvItemGeneral) + { + PhpOptionsTreeViewAddItem( + sectionName.Buffer, + PhOptionsFindSection(§ionName), + tvItemGeneral + ); + } + } +} + static PPH_OPTIONS_SECTION PhpTreeViewGetSelectedSection( _In_ HTREEITEM SelectedTreeItem ) { - TVITEM item; + TVITEM tvItem; if (!SelectedTreeItem) return NULL; - item.mask = TVIF_PARAM | TVIF_HANDLE; - item.hItem = SelectedTreeItem; + tvItem.mask = TVIF_PARAM | TVIF_HANDLE; + tvItem.hItem = SelectedTreeItem; - if (!TreeView_GetItem(OptionsTreeControl, &item)) + if (!TreeView_GetItem(OptionsTreeControl, &tvItem)) return NULL; - return (PPH_OPTIONS_SECTION)item.lParam; + return (PPH_OPTIONS_SECTION)tvItem.lParam; } INT_PTR CALLBACK PhOptionsDialogProc( @@ -255,16 +319,7 @@ INT_PTR CALLBACK PhOptionsDialogProc( SendMessage(PhOptionsWindowHandle, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER))); SendMessage(PhOptionsWindowHandle, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER))); - // Set the location of the options window. - if (StartLocation.x == MINLONG) - { - PhCenterWindow(hwndDlg, GetParent(hwndDlg)); - } - else - { - SetWindowPos(hwndDlg, NULL, StartLocation.x, StartLocation.y, 0, 0, - SWP_NOACTIVATE | SWP_NOREDRAW | SWP_NOSIZE | SWP_NOZORDER); - } + PhCenterWindow(hwndDlg, GetParent(hwndDlg)); OptionsTreeImageList = ImageList_Create(2, 22, ILC_COLOR, 1, 1); OptionsTreeControl = GetDlgItem(PhOptionsWindowHandle, IDC_SECTIONTREE); @@ -294,30 +349,22 @@ INT_PTR CALLBACK PhOptionsDialogProc( SectionList = PhCreateList(8); CurrentSection = NULL; - if (PhStartupParameters.ShowOptions) - { - // Disable all pages other than Advanced. - section = PhOptionsCreateSection(L"Advanced", PhInstanceHandle, MAKEINTRESOURCE(IDD_OPTADVANCED), PhpOptionsAdvancedDlgProc, NULL); - } - else - { - section = PhOptionsCreateSection(L"General", PhInstanceHandle, MAKEINTRESOURCE(IDD_OPTGENERAL), PhpOptionsGeneralDlgProc, NULL); - PhOptionsCreateSection(L"Advanced", PhInstanceHandle, MAKEINTRESOURCE(IDD_OPTADVANCED), PhpOptionsAdvancedDlgProc, NULL); - PhOptionsCreateSection(L"Symbols", PhInstanceHandle, MAKEINTRESOURCE(IDD_OPTSYMBOLS), PhpOptionsSymbolsDlgProc, NULL); - PhOptionsCreateSection(L"Highlighting", PhInstanceHandle, MAKEINTRESOURCE(IDD_OPTHIGHLIGHTING), PhpOptionsHighlightingDlgProc, NULL); - PhOptionsCreateSection(L"Graphs", PhInstanceHandle, MAKEINTRESOURCE(IDD_OPTGRAPHS), PhpOptionsGraphsDlgProc, NULL); + section = PhOptionsCreateSection(L"General", PhInstanceHandle, MAKEINTRESOURCE(IDD_OPTGENERAL), PhpOptionsGeneralDlgProc, NULL); + PhOptionsCreateSectionAdvanced(L"Advanced", PhInstanceHandle, MAKEINTRESOURCE(IDD_OPTADVANCED), PhpOptionsAdvancedDlgProc, NULL); + PhOptionsCreateSection(L"Symbols", PhInstanceHandle, MAKEINTRESOURCE(IDD_OPTSYMBOLS), PhpOptionsSymbolsDlgProc, NULL); + PhOptionsCreateSection(L"Highlighting", PhInstanceHandle, MAKEINTRESOURCE(IDD_OPTHIGHLIGHTING), PhpOptionsHighlightingDlgProc, NULL); + PhOptionsCreateSection(L"Graphs", PhInstanceHandle, MAKEINTRESOURCE(IDD_OPTGRAPHS), PhpOptionsGraphsDlgProc, NULL); - if (PhPluginsEnabled) - { - PH_PLUGIN_OPTIONS_POINTERS pointers; + if (PhPluginsEnabled) + { + PH_PLUGIN_OPTIONS_POINTERS pointers; - pointers.WindowHandle = PhOptionsWindowHandle; - pointers.CreateSection = PhOptionsCreateSection; - pointers.FindSection = PhOptionsFindSection; - pointers.EnterSectionView = PhOptionsEnterSectionView; + pointers.WindowHandle = PhOptionsWindowHandle; + pointers.CreateSection = PhOptionsCreateSection; + pointers.FindSection = PhOptionsFindSection; + pointers.EnterSectionView = PhOptionsEnterSectionView; - PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackOptionsWindowInitializing), &pointers); - } + PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackOptionsWindowInitializing), &pointers); } PhOptionsEnterSectionView(section); @@ -503,7 +550,32 @@ PPH_OPTIONS_SECTION PhOptionsCreateSection( PhAddItemList(SectionList, section); - PhpOptionsTreeViewAddItem(Name, section); + PhpOptionsTreeViewAddItem(Name, section, TVI_LAST); + + return section; +} + +PPH_OPTIONS_SECTION PhOptionsCreateSectionAdvanced( + _In_ PWSTR Name, + _In_ PVOID Instance, + _In_ PWSTR Template, + _In_ DLGPROC DialogProc, + _In_ PVOID Parameter + ) +{ + PPH_OPTIONS_SECTION section; + + section = PhAllocate(sizeof(PH_OPTIONS_SECTION)); + memset(section, 0, sizeof(PH_OPTIONS_SECTION)); + + PhInitializeStringRefLongHint(§ion->Name, Name); + + section->Instance = Instance; + section->Template = Template; + section->DialogProc = DialogProc; + section->Parameter = Parameter; + + PhAddItemList(SectionList, section); return section; } @@ -625,17 +697,30 @@ VOID PhOptionsCreateSectionDialog( #define SetSettingForDlgItemCheck(hwndDlg, Id, Name) \ PhSetIntegerSetting(Name, Button_GetCheck(GetDlgItem(hwndDlg, Id)) == BST_CHECKED) #define SetSettingForDlgItemCheckRestartRequired(hwndDlg, Id, Name) \ - do { \ - BOOLEAN __oldValue = !!PhGetIntegerSetting(Name); \ - BOOLEAN __newValue = Button_GetCheck(GetDlgItem(hwndDlg, Id)) == BST_CHECKED; \ - if (__newValue != __oldValue) \ - RestartRequired = TRUE; \ - PhSetIntegerSetting(Name, __newValue); \ - } while (0) +{ \ + BOOLEAN __oldValue = !!PhGetIntegerSetting(Name); \ + BOOLEAN __newValue = Button_GetCheck(GetDlgItem(hwndDlg, Id)) == BST_CHECKED; \ + if (__newValue != __oldValue) \ + RestartRequired = TRUE; \ + PhSetIntegerSetting(Name, __newValue); \ +} + +#define SetLvItemCheckForSetting(ListViewHandle, Index, Name) \ + ListView_SetCheckState(ListViewHandle, Index, !!PhGetIntegerSetting(Name)); +#define SetSettingForLvItemCheck(ListViewHandle, Index, Name) \ + PhSetIntegerSetting(Name, ListView_GetCheckState(ListViewHandle, Index) == BST_CHECKED) +#define SetSettingForLvItemCheckRestartRequired(ListViewHandle, Index, Name) \ +{ \ + BOOLEAN __oldValue = !!PhGetIntegerSetting(Name); \ + BOOLEAN __newValue = ListView_GetCheckState(ListViewHandle, Index) == BST_CHECKED; \ + if (__newValue != __oldValue) \ + RestartRequired = TRUE; \ + PhSetIntegerSetting(Name, __newValue); \ +} static BOOLEAN GetCurrentFont( _Out_ PLOGFONT Font -) + ) { BOOLEAN result; PPH_STRING fontHexString; @@ -737,151 +822,6 @@ static VOID WriteCurrentUserRun( } } -INT_PTR CALLBACK PhpOptionsGeneralDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - switch (uMsg) - { - case WM_INITDIALOG: - { - HWND comboBoxHandle; - ULONG i; - LOGFONT font; - - comboBoxHandle = GetDlgItem(hwndDlg, IDC_MAXSIZEUNIT); - - for (i = 0; i < sizeof(PhSizeUnitNames) / sizeof(PWSTR); i++) - ComboBox_AddString(comboBoxHandle, PhSizeUnitNames[i]); - - SetDlgItemText(hwndDlg, IDC_SEARCHENGINE, PhaGetStringSetting(L"SearchEngine")->Buffer); - SetDlgItemText(hwndDlg, IDC_PEVIEWER, PhaGetStringSetting(L"ProgramInspectExecutables")->Buffer); - - if (PhMaxSizeUnit != -1) - ComboBox_SetCurSel(comboBoxHandle, PhMaxSizeUnit); - else - ComboBox_SetCurSel(comboBoxHandle, sizeof(PhSizeUnitNames) / sizeof(PWSTR) - 1); - - SetDlgItemInt(hwndDlg, IDC_ICONPROCESSES, PhGetIntegerSetting(L"IconProcesses"), FALSE); - - SetDlgItemCheckForSetting(hwndDlg, IDC_ALLOWONLYONEINSTANCE, L"AllowOnlyOneInstance"); - SetDlgItemCheckForSetting(hwndDlg, IDC_HIDEONCLOSE, L"HideOnClose"); - SetDlgItemCheckForSetting(hwndDlg, IDC_HIDEONMINIMIZE, L"HideOnMinimize"); - SetDlgItemCheckForSetting(hwndDlg, IDC_COLLAPSESERVICES, L"CollapseServicesOnStart"); - SetDlgItemCheckForSetting(hwndDlg, IDC_ICONSINGLECLICK, L"IconSingleClick"); - SetDlgItemCheckForSetting(hwndDlg, IDC_ICONTOGGLESVISIBILITY, L"IconTogglesVisibility"); - SetDlgItemCheckForSetting(hwndDlg, IDC_ENABLEPLUGINS, L"EnablePlugins"); - - ReadCurrentUserRun(); - - if (CurrentUserRunPresent) - { - Button_SetCheck(GetDlgItem(hwndDlg, IDC_STARTATLOGON), BST_CHECKED); - - if (CurrentUserRunStartHidden) - Button_SetCheck(GetDlgItem(hwndDlg, IDC_STARTHIDDEN), BST_CHECKED); - } - else - { - EnableWindow(GetDlgItem(hwndDlg, IDC_STARTHIDDEN), FALSE); - } - - // Set the font of the button for a nice preview. - if (GetCurrentFont(&font)) - { - CurrentFontInstance = CreateFontIndirect(&font); - - if (CurrentFontInstance) - SendMessage(GetDlgItem(hwndDlg, IDC_FONT), WM_SETFONT, (WPARAM)CurrentFontInstance, TRUE); - } - } - break; - case WM_DESTROY: - { - BOOLEAN startAtLogon; - BOOLEAN startHidden; - - PhSetStringSetting2(L"SearchEngine", &(PhaGetDlgItemText(hwndDlg, IDC_SEARCHENGINE)->sr)); - PhSetStringSetting2(L"ProgramInspectExecutables", &(PhaGetDlgItemText(hwndDlg, IDC_PEVIEWER)->sr)); - PhSetIntegerSetting(L"MaxSizeUnit", PhMaxSizeUnit = ComboBox_GetCurSel(GetDlgItem(hwndDlg, IDC_MAXSIZEUNIT))); - PhSetIntegerSetting(L"IconProcesses", GetDlgItemInt(hwndDlg, IDC_ICONPROCESSES, NULL, FALSE)); - SetSettingForDlgItemCheck(hwndDlg, IDC_ALLOWONLYONEINSTANCE, L"AllowOnlyOneInstance"); - SetSettingForDlgItemCheck(hwndDlg, IDC_HIDEONCLOSE, L"HideOnClose"); - SetSettingForDlgItemCheck(hwndDlg, IDC_HIDEONMINIMIZE, L"HideOnMinimize"); - SetSettingForDlgItemCheck(hwndDlg, IDC_COLLAPSESERVICES, L"CollapseServicesOnStart"); - SetSettingForDlgItemCheck(hwndDlg, IDC_ICONSINGLECLICK, L"IconSingleClick"); - SetSettingForDlgItemCheck(hwndDlg, IDC_ICONTOGGLESVISIBILITY, L"IconTogglesVisibility"); - SetSettingForDlgItemCheckRestartRequired(hwndDlg, IDC_ENABLEPLUGINS, L"EnablePlugins"); - - startAtLogon = Button_GetCheck(GetDlgItem(hwndDlg, IDC_STARTATLOGON)) == BST_CHECKED; - startHidden = Button_GetCheck(GetDlgItem(hwndDlg, IDC_STARTHIDDEN)) == BST_CHECKED; - WriteCurrentUserRun(startAtLogon, startHidden); - - if (NewFontSelection) - { - PhSetStringSetting2(L"Font", &NewFontSelection->sr); - PostMessage(PhMainWndHandle, WM_PH_UPDATE_FONT, 0, 0); - } - - if (CurrentFontInstance) - DeleteObject(CurrentFontInstance); - - PhClearReference(&NewFontSelection); - } - break; - case WM_COMMAND: - { - switch (GET_WM_COMMAND_ID(wParam, lParam)) - { - case IDC_STARTATLOGON: - { - EnableWindow(GetDlgItem(hwndDlg, IDC_STARTHIDDEN), Button_GetCheck(GetDlgItem(hwndDlg, IDC_STARTATLOGON)) == BST_CHECKED); - } - break; - case IDC_FONT: - { - LOGFONT font; - CHOOSEFONT chooseFont; - - if (!GetCurrentFont(&font)) - { - // Can't get LOGFONT from the existing setting, probably - // because the user hasn't ever chosen a font before. - // Set the font to something familiar. - GetObject((HFONT)SendMessage(PhMainWndHandle, WM_PH_GET_FONT, 0, 0), sizeof(LOGFONT), &font); - } - - memset(&chooseFont, 0, sizeof(CHOOSEFONT)); - chooseFont.lStructSize = sizeof(CHOOSEFONT); - chooseFont.hwndOwner = hwndDlg; - chooseFont.lpLogFont = &font; - chooseFont.Flags = CF_FORCEFONTEXIST | CF_INITTOLOGFONTSTRUCT | CF_SCREENFONTS; - - if (ChooseFont(&chooseFont)) - { - PhMoveReference(&NewFontSelection, PhBufferToHexString((PUCHAR)&font, sizeof(LOGFONT))); - - // Update the button's font. - - if (CurrentFontInstance) - DeleteObject(CurrentFontInstance); - - CurrentFontInstance = CreateFontIndirect(&font); - SendMessage(GetDlgItem(hwndDlg, IDC_FONT), WM_SETFONT, (WPARAM)CurrentFontInstance, TRUE); - } - } - break; - } - } - break; - } - - return FALSE; -} - static BOOLEAN PathMatchesPh( _In_ PPH_STRING Path ) @@ -911,158 +851,253 @@ static BOOLEAN PathMatchesPh( return match; } -VOID PhpAdvancedPageLoad( - _In_ HWND hwndDlg +BOOLEAN PhpIsDefaultTaskManager( + VOID ) { - HWND changeButton; + HANDLE taskmgrKeyHandle; + BOOLEAN alreadyReplaced = FALSE; - SetDlgItemCheckForSetting(hwndDlg, IDC_ENABLEWARNINGS, L"EnableWarnings"); - SetDlgItemCheckForSetting(hwndDlg, IDC_ENABLEKERNELMODEDRIVER, L"EnableKph"); - SetDlgItemCheckForSetting(hwndDlg, IDC_HIDEUNNAMEDHANDLES, L"HideUnnamedHandles"); - SetDlgItemCheckForSetting(hwndDlg, IDC_ENABLESTAGE2, L"EnableStage2"); - SetDlgItemCheckForSetting(hwndDlg, IDC_ENABLENETWORKRESOLVE, L"EnableNetworkResolve"); - SetDlgItemCheckForSetting(hwndDlg, IDC_PROPAGATECPUUSAGE, L"PropagateCpuUsage"); - SetDlgItemCheckForSetting(hwndDlg, IDC_ENABLEINSTANTTOOLTIPS, L"EnableInstantTooltips"); - SetDlgItemCheckForSetting(hwndDlg, IDC_ENABLECYCLECPUUSAGE, L"EnableCycleCpuUsage"); + if (NT_SUCCESS(PhOpenKey( + &taskmgrKeyHandle, + KEY_READ, + PH_KEY_LOCAL_MACHINE, + &TaskMgrImageOptionsKeyName, + 0 + ))) + { + PhClearReference(&OldTaskMgrDebugger); - SetDlgItemInt(hwndDlg, IDC_SAMPLECOUNT, PhGetIntegerSetting(L"SampleCount"), FALSE); - SetDlgItemCheckForSetting(hwndDlg, IDC_SAMPLECOUNTAUTOMATIC, L"SampleCountAutomatic"); + if (OldTaskMgrDebugger = PhQueryRegistryString(taskmgrKeyHandle, L"Debugger")) + { + alreadyReplaced = PathMatchesPh(OldTaskMgrDebugger); + } - if (PhGetIntegerSetting(L"SampleCountAutomatic")) - EnableWindow(GetDlgItem(hwndDlg, IDC_SAMPLECOUNT), FALSE); + NtClose(taskmgrKeyHandle); + } - // Replace Task Manager + return alreadyReplaced; +} - changeButton = GetDlgItem(hwndDlg, IDC_CHANGE); +VOID PhpSetDefaultTaskManager( + _In_ HWND ParentWindowHandle + ) +{ + PWSTR message; - if (PhGetOwnTokenAttributes().Elevated) - { - ShowWindow(changeButton, SW_HIDE); - } + if (PhpIsDefaultTaskManager()) + message = L"Do you want to restore the default Windows Task Manager?"; else - { - SendMessage(changeButton, BCM_SETSHIELD, 0, TRUE); - } + message = L"Do you want to make Process Hacker the default Windows Task Manager?"; + if (PhShowMessage2( + ParentWindowHandle, + TDCBF_YES_BUTTON | TDCBF_NO_BUTTON, + TD_INFORMATION_ICON, + L"", + message + ) == IDYES) { - HANDLE taskmgrKeyHandle = NULL; - ULONG disposition; - BOOLEAN success = FALSE; - BOOLEAN alreadyReplaced = FALSE; + NTSTATUS status; + HANDLE taskmgrKeyHandle; + UNICODE_STRING valueName; - // See if we can write to the key. if (NT_SUCCESS(PhCreateKey( &taskmgrKeyHandle, KEY_READ | KEY_WRITE, PH_KEY_LOCAL_MACHINE, &TaskMgrImageOptionsKeyName, + OBJ_OPENIF, 0, - 0, - &disposition - ))) - { - success = TRUE; - } - - if (taskmgrKeyHandle || NT_SUCCESS(PhOpenKey( - &taskmgrKeyHandle, - KEY_READ, - PH_KEY_LOCAL_MACHINE, - &TaskMgrImageOptionsKeyName, - 0 + NULL ))) { - PhClearReference(&OldTaskMgrDebugger); + RtlInitUnicodeString(&valueName, L"Debugger"); - if (OldTaskMgrDebugger = PhQueryRegistryString(taskmgrKeyHandle, L"Debugger")) + if (PhpIsDefaultTaskManager()) + { + status = NtDeleteValueKey(taskmgrKeyHandle, &valueName); + } + else { - alreadyReplaced = PathMatchesPh(OldTaskMgrDebugger); + PPH_STRING quotedFileName; + + quotedFileName = PH_AUTO(PhConcatStrings(3, L"\"", PhApplicationFileName->Buffer, L"\"")); + status = NtSetValueKey(taskmgrKeyHandle, &valueName, 0, REG_SZ, quotedFileName->Buffer, (ULONG)quotedFileName->Length + 2); } + if (!NT_SUCCESS(status)) + PhShowStatus(ParentWindowHandle, L"Unable to replace Task Manager", status, 0); + NtClose(taskmgrKeyHandle); } - if (!success) - EnableWindow(GetDlgItem(hwndDlg, IDC_REPLACETASKMANAGER), FALSE); - - OldReplaceTaskMgr = alreadyReplaced; - Button_SetCheck(GetDlgItem(hwndDlg, IDC_REPLACETASKMANAGER), alreadyReplaced ? BST_CHECKED : BST_UNCHECKED); + if (PhSettingsFileName) + PhSaveSettings(PhSettingsFileName->Buffer); } } -VOID PhpAdvancedPageSave( - _In_ HWND hwndDlg +VOID PhpRefreshTaskManagerState( + _In_ HWND WindowHandle ) { - ULONG sampleCount; - - SetSettingForDlgItemCheck(hwndDlg, IDC_ENABLEWARNINGS, L"EnableWarnings"); - SetSettingForDlgItemCheckRestartRequired(hwndDlg, IDC_ENABLEKERNELMODEDRIVER, L"EnableKph"); - SetSettingForDlgItemCheck(hwndDlg, IDC_HIDEUNNAMEDHANDLES, L"HideUnnamedHandles"); - SetSettingForDlgItemCheckRestartRequired(hwndDlg, IDC_ENABLESTAGE2, L"EnableStage2"); - SetSettingForDlgItemCheckRestartRequired(hwndDlg, IDC_ENABLENETWORKRESOLVE, L"EnableNetworkResolve"); - SetSettingForDlgItemCheck(hwndDlg, IDC_PROPAGATECPUUSAGE, L"PropagateCpuUsage"); - SetSettingForDlgItemCheck(hwndDlg, IDC_ENABLEINSTANTTOOLTIPS, L"EnableInstantTooltips"); - SetSettingForDlgItemCheckRestartRequired(hwndDlg, IDC_ENABLECYCLECPUUSAGE, L"EnableCycleCpuUsage"); - - sampleCount = GetDlgItemInt(hwndDlg, IDC_SAMPLECOUNT, NULL, FALSE); - SetSettingForDlgItemCheckRestartRequired(hwndDlg, IDC_SAMPLECOUNTAUTOMATIC, L"SampleCountAutomatic"); + if (!PhGetOwnTokenAttributes().Elevated) + { + SendMessage(GetDlgItem(WindowHandle, IDC_REPLACETASKMANAGER), BCM_SETSHIELD, 0, TRUE); + } - if (sampleCount == 0) - sampleCount = 1; + if (PhpIsDefaultTaskManager()) + { + Static_SetText(GetDlgItem(WindowHandle, IDC_DEFSTATE), L"Process Hacker is the default Task Manager:"); + Button_SetText(GetDlgItem(WindowHandle, IDC_REPLACETASKMANAGER), L"Restore default..."); + } + else + { + Static_SetText(GetDlgItem(WindowHandle, IDC_DEFSTATE), L"Process Hacker is not the default Task Manager:"); + Button_SetText(GetDlgItem(WindowHandle, IDC_REPLACETASKMANAGER), L"Make default..."); + } +} - if (sampleCount != PhGetIntegerSetting(L"SampleCount")) - RestartRequired = TRUE; +typedef enum _PHP_OPTIONS_INDEX +{ + PHP_OPTIONS_INDEX_SINGLE_INSTANCE, + PHP_OPTIONS_INDEX_HIDE_WHENCLOSED, + PHP_OPTIONS_INDEX_HIDE_WHENMINIMIZED, + PHP_OPTIONS_INDEX_START_ATLOGON, + PHP_OPTIONS_INDEX_START_HIDDEN, + PHP_OPTIONS_INDEX_ENABLE_MINIINFO_WINDOW, + PHP_OPTIONS_INDEX_ENABLE_DRIVER, + PHP_OPTIONS_INDEX_ENABLE_WARNINGS, + PHP_OPTIONS_INDEX_ENABLE_PLUGINS, + PHP_OPTIONS_INDEX_ENABLE_NETWORK_RESOLVE, + PHP_OPTIONS_INDEX_ENABLE_INSTANT_TOOLTIPS, + PHP_OPTIONS_INDEX_ENABLE_CYCLE_CPU_USAGE, + PHP_OPTIONS_INDEX_ENABLE_STAGE2, + PHP_OPTIONS_INDEX_COLLAPSE_SERVICES_ON_START, + PHP_OPTIONS_INDEX_ICON_SINGLE_CLICK, + PHP_OPTIONS_INDEX_ICON_TOGGLE_VISIBILITY, + PHP_OPTIONS_INDEX_PROPAGATE_CPU_USAGE, + PHP_OPTIONS_INDEX_SHOW_ADVANCED_OPTIONS, +} PHP_OPTIONS_GENERAL_INDEX; + +VOID PhpSetListViewItemState( + _In_ HWND ListViewHandle, + _In_ INT Index, + _In_ BOOLEAN Hide + ) +{ + ListView_SetItemState(ListViewHandle, Index, INDEXTOSTATEIMAGEMASK(Hide ? 0 : 1), LVIS_STATEIMAGEMASK); +} - PhSetIntegerSetting(L"SampleCount", sampleCount); +static VOID PhpAdvancedPageLoad( + _In_ HWND hwndDlg + ) +{ + HWND listViewHandle; + + listViewHandle = GetDlgItem(hwndDlg, IDC_SETTINGS); - // Replace Task Manager - if (IsWindowEnabled(GetDlgItem(hwndDlg, IDC_REPLACETASKMANAGER))) + SetDlgItemInt(hwndDlg, IDC_SAMPLECOUNT, PhGetIntegerSetting(L"SampleCount"), FALSE); + SetDlgItemCheckForSetting(hwndDlg, IDC_SAMPLECOUNTAUTOMATIC, L"SampleCountAutomatic"); + + if (PhGetIntegerSetting(L"SampleCountAutomatic")) + EnableWindow(GetDlgItem(hwndDlg, IDC_SAMPLECOUNT), FALSE); + + PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_SINGLE_INSTANCE, L"Allow only one instance", NULL); + PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_HIDE_WHENCLOSED, L"Hide when closed", NULL); + PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_HIDE_WHENMINIMIZED, L"Hide when minimized", NULL); + PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_START_ATLOGON, L"Start when I log on", NULL); + PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_START_HIDDEN, L"Start hidden", NULL); + PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_MINIINFO_WINDOW, L"Enable tray information window", NULL); + PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_DRIVER, L"Enable kernel-mode driver", NULL); + PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_WARNINGS, L"Enable warnings", NULL); + PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_PLUGINS, L"Enable plugins", NULL); + PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_NETWORK_RESOLVE, L"Resolve network addresses", NULL); + PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_INSTANT_TOOLTIPS, L"Show tooltips instantly", NULL); + PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_CYCLE_CPU_USAGE, L"Enable cycle-based CPU usage", NULL); + PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_STAGE2, L"Check images for digital signatures", NULL); + PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_COLLAPSE_SERVICES_ON_START, L"Collapse services on start", NULL); + PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_ICON_SINGLE_CLICK, L"Single-click tray icons", NULL); + PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_ICON_TOGGLE_VISIBILITY, L"Icon click toggles visibility", NULL); + PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_PROPAGATE_CPU_USAGE, L"Include usage of collapsed processes", NULL); + PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_SHOW_ADVANCED_OPTIONS, L"Show advanced options", NULL); + + SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_SINGLE_INSTANCE, L"AllowOnlyOneInstance"); + SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_HIDE_WHENCLOSED, L"HideOnClose"); + SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_HIDE_WHENMINIMIZED, L"HideOnMinimize"); + SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_WARNINGS, L"EnableWarnings"); + SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_PLUGINS, L"EnablePlugins"); + SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_MINIINFO_WINDOW, L"MiniInfoWindowEnabled"); + SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_DRIVER, L"EnableKph"); + SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_STAGE2, L"EnableStage2"); + SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_NETWORK_RESOLVE, L"EnableNetworkResolve"); + SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_PROPAGATE_CPU_USAGE, L"PropagateCpuUsage"); + SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_INSTANT_TOOLTIPS, L"EnableInstantTooltips"); + SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_CYCLE_CPU_USAGE, L"EnableCycleCpuUsage"); + SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_COLLAPSE_SERVICES_ON_START, L"CollapseServicesOnStart"); + SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_ICON_SINGLE_CLICK, L"IconSingleClick"); + SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_ICON_TOGGLE_VISIBILITY, L"IconTogglesVisibility"); + + if (CurrentUserRunPresent) { - NTSTATUS status; - HANDLE taskmgrKeyHandle; - BOOLEAN replaceTaskMgr; - UNICODE_STRING valueName; + ListView_SetCheckState(listViewHandle, PHP_OPTIONS_INDEX_START_ATLOGON, TRUE); - replaceTaskMgr = Button_GetCheck(GetDlgItem(hwndDlg, IDC_REPLACETASKMANAGER)) == BST_CHECKED; + if (CurrentUserRunStartHidden) + ListView_SetCheckState(listViewHandle, PHP_OPTIONS_INDEX_START_HIDDEN, TRUE); + } + else + { + PhpSetListViewItemState(listViewHandle, PHP_OPTIONS_INDEX_START_HIDDEN, TRUE); + } +} - if (OldReplaceTaskMgr != replaceTaskMgr) - { - // We should have created the key back in PhpAdvancedPageLoad, which is why - // we're opening the key here. - if (NT_SUCCESS(PhOpenKey( - &taskmgrKeyHandle, - KEY_WRITE, - PH_KEY_LOCAL_MACHINE, - &TaskMgrImageOptionsKeyName, - 0 - ))) - { - RtlInitUnicodeString(&valueName, L"Debugger"); +static VOID PhpAdvancedPageSave( + _In_ HWND hwndDlg + ) +{ + HWND listViewHandle; + ULONG sampleCount; - if (replaceTaskMgr) - { - PPH_STRING quotedFileName; + listViewHandle = GetDlgItem(hwndDlg, IDC_SETTINGS); + sampleCount = GetDlgItemInt(hwndDlg, IDC_SAMPLECOUNT, NULL, FALSE); - quotedFileName = PH_AUTO(PhConcatStrings(3, L"\"", PhApplicationFileName->Buffer, L"\"")); - status = NtSetValueKey(taskmgrKeyHandle, &valueName, 0, REG_SZ, quotedFileName->Buffer, (ULONG)quotedFileName->Length + 2); - } - else - { - status = NtDeleteValueKey(taskmgrKeyHandle, &valueName); - } + SetSettingForDlgItemCheckRestartRequired(hwndDlg, IDC_SAMPLECOUNTAUTOMATIC, L"SampleCountAutomatic"); + + if (sampleCount == 0) + sampleCount = 1; - if (!NT_SUCCESS(status)) - PhShowStatus(hwndDlg, L"Unable to replace Task Manager", status, 0); + if (sampleCount != PhGetIntegerSetting(L"SampleCount")) + RestartRequired = TRUE; - NtClose(taskmgrKeyHandle); - } - } - } + PhSetIntegerSetting(L"SampleCount", sampleCount); + PhSetStringSetting2(L"SearchEngine", &PhaGetDlgItemText(hwndDlg, IDC_SEARCHENGINE)->sr); + PhSetStringSetting2(L"ProgramInspectExecutables", &PhaGetDlgItemText(hwndDlg, IDC_PEVIEWER)->sr); + PhSetIntegerSetting(L"MaxSizeUnit", PhMaxSizeUnit = ComboBox_GetCurSel(GetDlgItem(hwndDlg, IDC_MAXSIZEUNIT))); + PhSetIntegerSetting(L"IconProcesses", GetDlgItemInt(hwndDlg, IDC_ICONPROCESSES, NULL, FALSE)); + + SetSettingForLvItemCheck(listViewHandle, PHP_OPTIONS_INDEX_SINGLE_INSTANCE, L"AllowOnlyOneInstance"); + SetSettingForLvItemCheck(listViewHandle, PHP_OPTIONS_INDEX_HIDE_WHENCLOSED, L"HideOnClose"); + SetSettingForLvItemCheck(listViewHandle, PHP_OPTIONS_INDEX_HIDE_WHENMINIMIZED, L"HideOnMinimize"); + SetSettingForLvItemCheckRestartRequired(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_MINIINFO_WINDOW, L"MiniInfoWindowEnabled"); + SetSettingForLvItemCheckRestartRequired(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_DRIVER, L"EnableKph"); + SetSettingForLvItemCheck(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_WARNINGS, L"EnableWarnings"); + SetSettingForLvItemCheckRestartRequired(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_PLUGINS, L"EnablePlugins"); + SetSettingForLvItemCheckRestartRequired(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_NETWORK_RESOLVE, L"EnableNetworkResolve"); + SetSettingForLvItemCheck(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_INSTANT_TOOLTIPS, L"EnableInstantTooltips"); + SetSettingForLvItemCheckRestartRequired(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_CYCLE_CPU_USAGE, L"EnableCycleCpuUsage"); + SetSettingForLvItemCheckRestartRequired(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_STAGE2, L"EnableStage2"); + SetSettingForLvItemCheck(listViewHandle, PHP_OPTIONS_INDEX_COLLAPSE_SERVICES_ON_START, L"CollapseServicesOnStart"); + SetSettingForLvItemCheck(listViewHandle, PHP_OPTIONS_INDEX_ICON_SINGLE_CLICK, L"IconSingleClick"); + SetSettingForLvItemCheck(listViewHandle, PHP_OPTIONS_INDEX_ICON_TOGGLE_VISIBILITY, L"IconTogglesVisibility"); + SetSettingForLvItemCheck(listViewHandle, PHP_OPTIONS_INDEX_PROPAGATE_CPU_USAGE, L"PropagateCpuUsage"); + + WriteCurrentUserRun( + ListView_GetCheckState(listViewHandle, PHP_OPTIONS_INDEX_START_ATLOGON) == BST_CHECKED, + ListView_GetCheckState(listViewHandle, PHP_OPTIONS_INDEX_START_HIDDEN) == BST_CHECKED + ); } -NTSTATUS PhpElevateAdvancedThreadStart( +static NTSTATUS PhpElevateAdvancedThreadStart( _In_ PVOID Parameter ) { @@ -1085,66 +1120,133 @@ NTSTATUS PhpElevateAdvancedThreadStart( return STATUS_SUCCESS; } -INT_PTR CALLBACK PhpOptionsAdvancedDlgProc( +INT_PTR CALLBACK PhpOptionsGeneralDlgProc( _In_ HWND hwndDlg, _In_ UINT uMsg, _In_ WPARAM wParam, _In_ LPARAM lParam ) { + static PH_LAYOUT_MANAGER LayoutManager; + switch (uMsg) { case WM_INITDIALOG: { - PhpAdvancedPageLoad(hwndDlg); + HWND comboBoxHandle; + HWND listviewHandle; + ULONG i; + LOGFONT font; + + GeneralListviewImageList = ImageList_Create(2, 20, ILC_COLOR, 1, 1); + comboBoxHandle = GetDlgItem(hwndDlg, IDC_MAXSIZEUNIT); + listviewHandle = GetDlgItem(hwndDlg, IDC_SETTINGS); - if (PhStartupParameters.ShowOptions) + PhInitializeLayoutManager(&LayoutManager, hwndDlg); + PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDC_SEARCHENGINE), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); + PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDC_PEVIEWER), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); + PhAddLayoutItem(&LayoutManager, listviewHandle, NULL, PH_ANCHOR_ALL); + + PhSetListViewStyle(listviewHandle, FALSE, TRUE); + ListView_SetExtendedListViewStyleEx(listviewHandle, LVS_EX_CHECKBOXES, LVS_EX_CHECKBOXES); + ListView_SetImageList(listviewHandle, GeneralListviewImageList, LVSIL_SMALL); + PhSetControlTheme(listviewHandle, L"explorer"); + PhAddListViewColumn(listviewHandle, 0, 0, 0, LVCFMT_LEFT, 250, L"Name"); + PhSetExtendedListView(listviewHandle); + + for (i = 0; i < ARRAYSIZE(PhSizeUnitNames); i++) + ComboBox_AddString(comboBoxHandle, PhSizeUnitNames[i]); + + if (PhMaxSizeUnit != -1) + ComboBox_SetCurSel(comboBoxHandle, PhMaxSizeUnit); + else + ComboBox_SetCurSel(comboBoxHandle, ARRAYSIZE(PhSizeUnitNames) - 1); + + SetDlgItemText(hwndDlg, IDC_SEARCHENGINE, PhaGetStringSetting(L"SearchEngine")->Buffer); + SetDlgItemText(hwndDlg, IDC_PEVIEWER, PhaGetStringSetting(L"ProgramInspectExecutables")->Buffer); + + SetDlgItemInt(hwndDlg, IDC_ICONPROCESSES, PhGetIntegerSetting(L"IconProcesses"), FALSE); + + ReadCurrentUserRun(); + + // Set the font of the button for a nice preview. + if (GetCurrentFont(&font)) { - // Disable all controls except for Replace Task Manager. - EnableWindow(GetDlgItem(hwndDlg, IDC_ENABLEWARNINGS), FALSE); - EnableWindow(GetDlgItem(hwndDlg, IDC_ENABLEKERNELMODEDRIVER), FALSE); - EnableWindow(GetDlgItem(hwndDlg, IDC_HIDEUNNAMEDHANDLES), FALSE); - EnableWindow(GetDlgItem(hwndDlg, IDC_ENABLESTAGE2), FALSE); - EnableWindow(GetDlgItem(hwndDlg, IDC_ENABLENETWORKRESOLVE), FALSE); - EnableWindow(GetDlgItem(hwndDlg, IDC_PROPAGATECPUUSAGE), FALSE); - EnableWindow(GetDlgItem(hwndDlg, IDC_ENABLEINSTANTTOOLTIPS), FALSE); - EnableWindow(GetDlgItem(hwndDlg, IDC_ENABLECYCLECPUUSAGE), FALSE); - EnableWindow(GetDlgItem(hwndDlg, IDC_SAMPLECOUNTLABEL), FALSE); - EnableWindow(GetDlgItem(hwndDlg, IDC_SAMPLECOUNT), FALSE); - EnableWindow(GetDlgItem(hwndDlg, IDC_SAMPLECOUNTAUTOMATIC), FALSE); - - EnableWindow(GetDlgItem(PhOptionsWindowHandle, IDC_RESET), FALSE); - EnableWindow(GetDlgItem(PhOptionsWindowHandle, IDC_CLEANUP), FALSE); + CurrentFontInstance = CreateFontIndirect(&font); + + if (CurrentFontInstance) + SendMessage(GetDlgItem(hwndDlg, IDC_FONT), WM_SETFONT, (WPARAM)CurrentFontInstance, TRUE); } + + PhpAdvancedPageLoad(hwndDlg); + PhpRefreshTaskManagerState(hwndDlg); } break; case WM_DESTROY: { + if (NewFontSelection) + { + PhSetStringSetting2(L"Font", &NewFontSelection->sr); + PostMessage(PhMainWndHandle, WM_PH_UPDATE_FONT, 0, 0); + } + PhpAdvancedPageSave(hwndDlg); + if (CurrentFontInstance) + DeleteObject(CurrentFontInstance); + + PhClearReference(&NewFontSelection); PhClearReference(&OldTaskMgrDebugger); + + ImageList_Destroy(GeneralListviewImageList); + + PhDeleteLayoutManager(&LayoutManager); } break; case WM_COMMAND: { - switch (LOWORD(wParam)) + switch (GET_WM_COMMAND_ID(wParam, lParam)) { - case IDC_CHANGE: + case IDC_FONT: { - RECT windowRect; + LOGFONT font; + CHOOSEFONT chooseFont; - // Save the options so they don't get "overwritten" when - // WM_PH_CHILD_EXIT gets sent. - PhpAdvancedPageSave(hwndDlg); + if (!GetCurrentFont(&font)) + { + // Can't get LOGFONT from the existing setting, probably + // because the user hasn't ever chosen a font before. + // Set the font to something familiar. + GetObject((HFONT)SendMessage(PhMainWndHandle, WM_PH_GET_FONT, 0, 0), sizeof(LOGFONT), &font); + } + + memset(&chooseFont, 0, sizeof(CHOOSEFONT)); + chooseFont.lStructSize = sizeof(CHOOSEFONT); + chooseFont.hwndOwner = hwndDlg; + chooseFont.lpLogFont = &font; + chooseFont.Flags = CF_FORCEFONTEXIST | CF_INITTOLOGFONTSTRUCT | CF_SCREENFONTS; + + if (ChooseFont(&chooseFont)) + { + PhMoveReference(&NewFontSelection, PhBufferToHexString((PUCHAR)&font, sizeof(LOGFONT))); + + // Update the button's font. + + if (CurrentFontInstance) + DeleteObject(CurrentFontInstance); - GetWindowRect(GetParent(GetParent(hwndDlg)), &windowRect); + CurrentFontInstance = CreateFontIndirect(&font); + SendMessage(GetDlgItem(hwndDlg, IDC_FONT), WM_SETFONT, (WPARAM)CurrentFontInstance, TRUE); + } + } + break; + case IDC_REPLACETASKMANAGER: + { WindowHandleForElevate = hwndDlg; PhCreateThread2(PhpElevateAdvancedThreadStart, PhFormatString( - L"-showoptions -hwnd %Ix -point %u,%u", - (ULONG_PTR)GetParent(GetParent(hwndDlg)), - windowRect.left + 20, - windowRect.top + 20 + L"-showoptions -hwnd %Ix", + (ULONG_PTR)GetParent(GetParent(hwndDlg)) )); } break; @@ -1158,7 +1260,320 @@ INT_PTR CALLBACK PhpOptionsAdvancedDlgProc( break; case WM_PH_CHILD_EXIT: { - PhpAdvancedPageLoad(hwndDlg); + PhpRefreshTaskManagerState(hwndDlg); + } + break; + case WM_SIZE: + { + PhLayoutManagerLayout(&LayoutManager); + } + break; + case WM_NOTIFY: + { + LPNMHDR header = (LPNMHDR)lParam; + + //if (header->code == LVN_ITEMCHANGING) + //{ + // LPNM_LISTVIEW listView = (LPNM_LISTVIEW)lParam; + // + // if (listView->uChanged & LVIF_STATE) + // { + // switch (listView->uNewState & LVIS_STATEIMAGEMASK) + // { + // case INDEXTOSTATEIMAGEMASK(2): // checked + // { + // switch (listView->iItem) + // { + // case PHP_OPTIONS_INDEX_SHOW_ADVANCED_OPTIONS: + // { + // if (PhShowMessage2( + // PhOptionsWindowHandle, + // TDCBF_OK_BUTTON | TDCBF_CANCEL_BUTTON, + // TD_WARNING_ICON, + // L"WARNING", + // L"DO NOT change advanced settings unless you know what you're doing..." + // ) == IDOK) + // { + // SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, FALSE); + // return FALSE; + // } + // else + // { + // SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, TRUE); + // return TRUE; + // } + // } + // break; + // } + // } + // break; + // } + // } + //} + + if (header->code == LVN_ITEMCHANGED) + { + LPNM_LISTVIEW listView = (LPNM_LISTVIEW)lParam; + + if (listView->uChanged & LVIF_STATE) + { + switch (listView->uNewState & LVIS_STATEIMAGEMASK) + { + case INDEXTOSTATEIMAGEMASK(2): // checked + { + switch (listView->iItem) + { + case PHP_OPTIONS_INDEX_START_ATLOGON: + { + PhpSetListViewItemState(listView->hdr.hwndFrom, PHP_OPTIONS_INDEX_START_HIDDEN, FALSE); + } + break; + case PHP_OPTIONS_INDEX_SHOW_ADVANCED_OPTIONS: + { + PhpOptionsShowHideTreeViewItem(FALSE); + } + break; + } + } + break; + case INDEXTOSTATEIMAGEMASK(1): // unchecked + { + switch (listView->iItem) + { + case PHP_OPTIONS_INDEX_START_ATLOGON: + { + PhpSetListViewItemState(listView->hdr.hwndFrom, PHP_OPTIONS_INDEX_START_HIDDEN, TRUE); + } + break; + case PHP_OPTIONS_INDEX_SHOW_ADVANCED_OPTIONS: + { + PhpOptionsShowHideTreeViewItem(TRUE); + } + break; + } + } + break; + } + } + } + } + break; + //case WM_CTLCOLORSTATIC: + // { + // static HFONT BoldFont = NULL; // leak + // HWND control = (HWND)lParam; + // HDC hdc = (HDC)wParam; + // + // if (GetDlgCtrlID(control) == IDC_DEFSTATE) + // { + // if (!BoldFont) + // BoldFont = PhDuplicateFontWithNewWeight((HFONT)SendMessage(control, WM_GETFONT, 0, 0), FW_BOLD); + // + // SetBkMode(hdc, TRANSPARENT); + // + // if (!PhpIsDefaultTaskManager()) + // { + // SelectObject(hdc, BoldFont); + // } + // } + // } + // break; + } + + return FALSE; +} + +static BOOLEAN PhpOptionsSettingsCallback( + _In_ PPH_SETTING Setting, + _In_ PVOID Context + ) +{ + INT lvItemIndex; + + lvItemIndex = PhAddListViewItem(Context, MAXINT, Setting->Name.Buffer, Setting); + + switch (Setting->Type) + { + case StringSettingType: + PhSetListViewSubItem(Context, lvItemIndex, 1, L"String"); + break; + case IntegerSettingType: + PhSetListViewSubItem(Context, lvItemIndex, 1, L"Integer"); + break; + case IntegerPairSettingType: + PhSetListViewSubItem(Context, lvItemIndex, 1, L"IntegerPair"); + break; + case ScalableIntegerPairSettingType: + PhSetListViewSubItem(Context, lvItemIndex, 1, L"ScalableIntegerPair"); + break; + } + + PhSetListViewSubItem(Context, lvItemIndex, 2, PH_AUTO_T(PH_STRING, PhSettingToString(Setting->Type, Setting))->Buffer); + PhSetListViewSubItem(Context, lvItemIndex, 3, Setting->DefaultValue.Buffer); + + return TRUE; +} + +static INT_PTR CALLBACK PhpOptionsAdvancedEditDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + static PH_LAYOUT_MANAGER LayoutManager; + + switch (uMsg) + { + case WM_INITDIALOG: + { + PPH_SETTING setting = (PPH_SETTING)lParam; + + SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER))); + SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER))); + + SetWindowText(hwndDlg, L"Setting Editor"); + PhCenterWindow(hwndDlg, GetParent(hwndDlg)); + + SetProp(hwndDlg, PhMakeContextAtom(), setting); + + PhInitializeLayoutManager(&LayoutManager, hwndDlg); + PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDC_NAME), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); + PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDC_VALUE), NULL, PH_ANCHOR_ALL); + PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDOK), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); + PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDCANCEL), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); + + SetDlgItemText(hwndDlg, IDC_NAME, setting->Name.Buffer); + SetDlgItemText(hwndDlg, IDC_VALUE, PH_AUTO_T(PH_STRING, PhSettingToString(setting->Type, setting))->Buffer); + + EnableWindow(GetDlgItem(hwndDlg, IDC_NAME), FALSE); + + SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hwndDlg, IDCANCEL), TRUE); + } + break; + case WM_DESTROY: + { + RemoveProp(hwndDlg, PhMakeContextAtom()); + + PhDeleteLayoutManager(&LayoutManager); + } + break; + case WM_SIZE: + { + PhLayoutManagerLayout(&LayoutManager); + } + break; + case WM_COMMAND: + { + switch (GET_WM_COMMAND_ID(wParam, lParam)) + { + case IDCANCEL: + EndDialog(hwndDlg, IDCANCEL); + break; + case IDOK: + { + PPH_SETTING setting = (PPH_SETTING)GetProp(hwndDlg, PhMakeContextAtom()); + PPH_STRING settingValue = PH_AUTO(PhGetWindowText(GetDlgItem(hwndDlg, IDC_VALUE))); + + if (!PhSettingFromString( + setting->Type, + &settingValue->sr, + settingValue, + setting + )) + { + PhSettingFromString( + setting->Type, + &setting->DefaultValue, + NULL, + setting + ); + } + + EndDialog(hwndDlg, IDOK); + } + break; + } + } + break; + } + + return FALSE; +} + +INT_PTR CALLBACK PhpOptionsAdvancedDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + static PH_LAYOUT_MANAGER LayoutManager; + + switch (uMsg) + { + case WM_INITDIALOG: + { + HWND listviewHandle; + + listviewHandle = GetDlgItem(hwndDlg, IDC_SETTINGS); + + PhInitializeLayoutManager(&LayoutManager, hwndDlg); + PhAddLayoutItem(&LayoutManager, listviewHandle, NULL, PH_ANCHOR_ALL); + + PhSetListViewStyle(listviewHandle, FALSE, TRUE); + PhSetControlTheme(listviewHandle, L"explorer"); + PhAddListViewColumn(listviewHandle, 0, 0, 0, LVCFMT_LEFT, 180, L"Name"); + PhAddListViewColumn(listviewHandle, 1, 1, 1, LVCFMT_LEFT, 80, L"Type"); + PhAddListViewColumn(listviewHandle, 2, 2, 2, LVCFMT_LEFT, 80, L"Value"); + PhAddListViewColumn(listviewHandle, 3, 3, 3, LVCFMT_LEFT, 80, L"Default"); + PhSetExtendedListView(listviewHandle); + + PhEnumSettings(PhpOptionsSettingsCallback, listviewHandle); + } + break; + case WM_DESTROY: + { + PhDeleteLayoutManager(&LayoutManager); + } + break; + case WM_SIZE: + { + PhLayoutManagerLayout(&LayoutManager); + } + break; + case WM_NOTIFY: + { + LPNMHDR header = (LPNMHDR)lParam; + + switch (header->code) + { + case NM_DBLCLK: + { + if (header->idFrom == IDC_SETTINGS) + { + PPH_SETTING setting; + INT index; + + if (setting = PhGetSelectedListViewItemParam(header->hwndFrom)) + { + DialogBoxParam( + PhInstanceHandle, + MAKEINTRESOURCE(IDD_EDITENV), + hwndDlg, + PhpOptionsAdvancedEditDlgProc, + (LPARAM)setting + ); + + if ((index = PhFindListViewItemByFlags(header->hwndFrom, -1, LVNI_SELECTED)) != -1) + { + PhSetListViewSubItem(header->hwndFrom, index, 2, PH_AUTO_T(PH_STRING, PhSettingToString(setting->Type, setting))->Buffer); + } + } + } + } + break; + } } break; } @@ -1246,9 +1661,6 @@ INT_PTR CALLBACK PhpOptionsSymbolsDlgProc( return FALSE; } -#define CROSS_INDEX 0 -#define TICK_INDEX 1 - typedef struct _COLOR_ITEM { PWSTR SettingName; diff --git a/ProcessHacker/resource.h b/ProcessHacker/resource.h index 80b0825bde89..cb5262a4eadc 100644 --- a/ProcessHacker/resource.h +++ b/ProcessHacker/resource.h @@ -208,7 +208,6 @@ #define IDC_LINKEDTOKEN 1079 #define IDC_DISABLEALL 1079 #define IDC_MOVEUP 1079 -#define IDC_CHANGE 1079 #define IDC_CLEAR 1079 #define IDC_GOTO 1079 #define IDC_OPTIONS 1079 @@ -218,6 +217,7 @@ #define IDC_INTEGRITY 1079 #define IDC_MORE 1079 #define IDC_VIEWMITIGATION 1080 +#define IDC_REPLACETASKMANAGER 1080 #define IDC_VIEWPARENTPROCESS 1081 #define IDC_OPENFILENAME 1082 #define IDC_LIMITS 1083 @@ -318,16 +318,10 @@ #define IDC_CPU44 1143 #define IDC_MAXSIZEUNIT 1144 #define IDC_CPU45 1144 -#define IDC_ALLOWONLYONEINSTANCE 1145 #define IDC_CPU46 1145 -#define IDC_HIDEONCLOSE 1146 #define IDC_CPU47 1146 -#define IDC_ENABLEWARNINGS 1147 -#define IDC_HIDEONMINIMIZE 1147 #define IDC_CPU48 1147 -#define IDC_STARTHIDDEN 1148 #define IDC_CPU49 1148 -#define IDC_ENABLEKERNELMODEDRIVER 1149 #define IDC_CPU50 1149 #define IDC_CPU51 1150 #define IDC_PEVIEWER 1151 @@ -389,13 +383,10 @@ #define IDC_ACTIVE 1208 #define IDC_SHOW 1209 #define IDC_HIDE 1210 -#define IDC_REPLACETASKMANAGER 1211 #define IDC_AUTOSCROLL 1215 #define IDC_UNDECORATESYMBOLS 1216 #define IDC_DBGHELPPATH 1217 #define IDC_DBGHELPSEARCHPATH 1218 -#define IDC_COLLAPSESERVICES 1219 -#define IDC_ICONSINGLECLICK 1220 #define IDC_DESKTOP 1221 #define IDC_REREAD 1224 #define IDC_WRITE 1225 @@ -409,21 +400,16 @@ #define IDC_SHOWTEXT 1245 #define IDC_ICONPROCESSES 1248 #define IDC_CLEANUP 1251 -#define IDC_ENABLESTAGE2 1253 #define IDC_TOGGLEELEVATION 1254 -#define IDC_ENABLEPLUGINS 1258 #define IDC_PARENT 1263 #define IDC_PROCESSNAME 1264 #define IDC_SERVICES_LAYOUT 1266 #define IDC_LINK_SF 1267 #define IDC_CREDITS 1270 -#define IDC_ENABLENETWORKRESOLVE 1271 #define IDC_LOGONTIME 1272 #define IDC_ZPEAKHANDLES_V 1273 -#define IDC_PROPAGATECPUUSAGE 1274 #define IDC_SHIFT 1274 #define IDC_USEOLDCOLORS 1274 -#define IDC_ICONTOGGLESVISIBILITY 1274 #define IDC_OPENURL 1279 #define IDC_COMPANYNAME_LINK 1279 #define IDC_SAMPLECOUNT 1280 @@ -438,8 +424,6 @@ #define IDC_ZPRIVATEWS_V 1289 #define IDC_ZSHAREABLEWS_V 1290 #define IDC_ZSHAREDWS_V 1291 -#define IDC_ENABLEINSTANTTOOLTIPS 1292 -#define IDC_ENABLECYCLECPUUSAGE 1293 #define IDC_IDEALPROCESSOR 1294 #define IDC_STATICBL12 1295 #define IDC_BASICINFORMATION 1296 @@ -517,7 +501,6 @@ #define IDC_ZLISTSTANDBY7_V 1367 #define IDC_INSPECT 1367 #define IDC_ZPAGINGPAGEFAULTSDELTA_V 1368 -#define IDC_HIDEFREEREGIONS 1368 #define IDC_ZPAGINGPAGEREADSDELTA_V 1369 #define IDC_BYTESPERROW 1369 #define IDC_ZPAGINGPAGEFILEWRITESDELTA_V 1370 @@ -527,7 +510,6 @@ #define IDC_SECTION 1375 #define IDC_REGEX 1377 #define IDC_DESCRIPTIONLABEL 1378 -#define IDC_STARTATLOGON 1380 #define IDC_VIEWCOMMANDLINE 1381 #define IDC_DELETE 1382 #define IDC_EDIT 1383 @@ -539,6 +521,8 @@ #define IDC_TREELIST 1391 #define IDC_SECTIONTREE 1393 #define IDC_INFO 1396 +#define IDC_DEFSTATE 1398 +#define IDC_SETTINGS 1399 #define ID_HACKER_EXIT 40001 #define ID_PROCESS_PROPERTIES 40006 #define ID_PROCESS_TERMINATE 40007 @@ -744,9 +728,9 @@ // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 238 +#define _APS_NEXT_RESOURCE_VALUE 239 #define _APS_NEXT_COMMAND_VALUE 40297 -#define _APS_NEXT_CONTROL_VALUE 1397 +#define _APS_NEXT_CONTROL_VALUE 1400 #define _APS_NEXT_SYMED_VALUE 169 #endif #endif From d995e2e7dd4b04a18ed917e9be47033996980c27 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 29 Sep 2017 20:51:45 +1000 Subject: [PATCH 0440/2058] Fix json file functions --- phlib/include/json.h | 17 +++- phlib/json.c | 17 +++- phlib/jsonc/json_util.c | 177 +++++++++++++++++++++++++--------------- phlib/jsonc/json_util.h | 6 +- 4 files changed, 144 insertions(+), 73 deletions(-) diff --git a/phlib/include/json.h b/phlib/include/json.h index fded874784d0..a8d43b25acba 100644 --- a/phlib/include/json.h +++ b/phlib/include/json.h @@ -148,12 +148,27 @@ PhGetJsonArrayIndexObject( ); PHLIBAPI -PVOID +PPH_LIST NTAPI PhGetJsonObjectAsArrayList( _In_ PVOID Object ); +PHLIBAPI +PVOID +NTAPI +PhLoadJsonObjectFromFile( + _In_ PWSTR FileName + ); + +PHLIBAPI +VOID +NTAPI +PhSaveJsonObjectToFile( + _In_ PWSTR FileName, + _In_ PVOID Object + ); + #ifdef __cplusplus } #endif diff --git a/phlib/json.c b/phlib/json.c index d22c766033da..fa889476750e 100644 --- a/phlib/json.c +++ b/phlib/json.c @@ -156,7 +156,7 @@ PVOID PhGetJsonArrayIndexObject( return json_object_array_get_idx(Object, Index); } -PVOID PhGetJsonObjectAsArrayList( +PPH_LIST PhGetJsonObjectAsArrayList( _In_ PVOID Object ) { @@ -180,3 +180,18 @@ PVOID PhGetJsonObjectAsArrayList( return listArray; } + +PVOID PhLoadJsonObjectFromFile( + _In_ PWSTR FileName + ) +{ + return json_object_from_file(FileName); +} + +VOID PhSaveJsonObjectToFile( + _In_ PWSTR FileName, + _In_ PVOID Object + ) +{ + json_object_to_file(FileName, Object); +} \ No newline at end of file diff --git a/phlib/jsonc/json_util.c b/phlib/jsonc/json_util.c index fda5d1ec00a7..077777afe9e9 100644 --- a/phlib/jsonc/json_util.c +++ b/phlib/jsonc/json_util.c @@ -9,6 +9,9 @@ * */ +#include "..\include\phbase.h" +#include "..\include\phnative.h" + #include "config.h" #undef realloc @@ -65,85 +68,123 @@ static int sscanf_is_broken = 0; static int sscanf_is_broken_testdone = 0; static void sscanf_is_broken_test(void); -struct json_object* json_object_from_file(const char *filename) +struct json_object* json_object_from_file(wchar_t *filename) { - //struct printbuf *pb; - //struct json_object *obj; - //char buf[JSON_FILE_BUF_SIZE]; - //int fd, ret; - - //if((fd = open(filename, O_RDONLY)) < 0) { - // MC_ERROR("json_object_from_file: error opening file %s: %s\n", - // filename, strerror(errno)); - // return NULL; - //} - //if(!(pb = printbuf_new())) { - // close(fd); - // MC_ERROR("json_object_from_file: printbuf_new failed\n"); - // return NULL; - //} - //while((ret = read(fd, buf, JSON_FILE_BUF_SIZE)) > 0) { - // printbuf_memappend(pb, buf, ret); - //} - //close(fd); - //if(ret < 0) { - // MC_ERROR("json_object_from_file: error reading file %s: %s\n", - // filename, strerror(errno)); - // printbuf_free(pb); - // return NULL; - //} - //obj = json_tokener_parse(pb->buf); - //printbuf_free(pb); - return NULL;//obj; + NTSTATUS status; + HANDLE fileHandle; + IO_STATUS_BLOCK isb; + struct json_object *obj = NULL; + + status = PhCreateFileWin32( + &fileHandle, + filename, + FILE_GENERIC_WRITE, + FILE_ATTRIBUTE_NORMAL, + FILE_SHARE_READ, + FILE_OPEN, + FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT + ); + + if (NT_SUCCESS(status)) + { + PSTR data; + ULONG allocatedLength; + ULONG dataLength; + ULONG returnLength; + BYTE buffer[PAGE_SIZE]; + + allocatedLength = sizeof(buffer); + data = (PSTR)PhAllocate(allocatedLength); + dataLength = 0; + + memset(data, 0, allocatedLength); + + while (NT_SUCCESS(NtReadFile(fileHandle, NULL, NULL, NULL, &isb, buffer, PAGE_SIZE, NULL, NULL))) + { + returnLength = (ULONG)isb.Information; + + if (returnLength == 0) + break; + + if (allocatedLength < dataLength + returnLength) + { + allocatedLength *= 2; + data = (PSTR)PhReAllocate(data, allocatedLength); + } + + memcpy(data + dataLength, buffer, returnLength); + + dataLength += returnLength; + } + + if (allocatedLength < dataLength + 1) + { + allocatedLength++; + data = (PSTR)PhReAllocate(data, allocatedLength); + } + + data[dataLength] = 0; + + obj = json_tokener_parse(data); + + PhFree(data); + } + + return obj; } /* extended "format and write to file" function */ -int json_object_to_file_ext(const char *filename, struct json_object *obj, int flags) +int json_object_to_file_ext(wchar_t *filename, struct json_object *obj, int flags) { - //const char *json_str; - //int fd, ret; - //unsigned int wpos, wsize; - - //if(!obj) { - // MC_ERROR("json_object_to_file: object is null\n"); - // return -1; - //} - - //if((fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT, 0644)) < 0) { - // MC_ERROR("json_object_to_file: error opening file %s: %s\n", - // filename, strerror(errno)); - // return -1; - //} - - //if(!(json_str = json_object_to_json_string_ext(obj,flags))) { - // close(fd); - // return -1; - //} - - //wsize = (unsigned int)(strlen(json_str) & UINT_MAX); /* CAW: probably unnecessary, but the most 64bit safe */ - //wpos = 0; - //while(wpos < wsize) { - // if((ret = write(fd, json_str + wpos, wsize-wpos)) < 0) { - // close(fd); - // MC_ERROR("json_object_to_file: error writing file %s: %s\n", - // filename, strerror(errno)); - // return -1; - // } - - // /* because of the above check for ret < 0, we can safely cast and add */ - // wpos += (unsigned int)ret; - //} - - //close(fd); - return 0; + NTSTATUS status; + HANDLE fileHandle; + IO_STATUS_BLOCK isb; + PSTR json_str; + + if (!(json_str = json_object_to_json_string_ext(obj, flags))) + return -1; + + status = PhCreateFileWin32( + &fileHandle, + filename, + FILE_GENERIC_WRITE, + FILE_ATTRIBUTE_NORMAL, + FILE_SHARE_READ, + FILE_OVERWRITE_IF, + FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT + ); + + if (!NT_SUCCESS(status)) + return -1; + + status = NtWriteFile( + fileHandle, + NULL, + NULL, + NULL, + &isb, + json_str, + (ULONG)strlen(json_str), + NULL, + NULL + ); + + if (!NT_SUCCESS(status)) + { + NtClose(fileHandle); + return -1; + } + + NtClose(fileHandle); + return 0; } // backwards compatible "format and write to file" function -int json_object_to_file(const char *filename, struct json_object *obj) +int json_object_to_file(wchar_t *FileName, struct json_object *obj) { - return json_object_to_file_ext(filename, obj, JSON_C_TO_STRING_PLAIN); + return json_object_to_file_ext(FileName, obj, JSON_C_TO_STRING_PRETTY); } int json_parse_double(const char *buf, double *retval) diff --git a/phlib/jsonc/json_util.h b/phlib/jsonc/json_util.h index 1005e58c5b0d..e9aea4876a66 100644 --- a/phlib/jsonc/json_util.h +++ b/phlib/jsonc/json_util.h @@ -21,9 +21,9 @@ extern "C" { #define JSON_FILE_BUF_SIZE 4096 /* utility functions */ -extern struct json_object* json_object_from_file(const char *filename); -extern int json_object_to_file(const char *filename, struct json_object *obj); -extern int json_object_to_file_ext(const char *filename, struct json_object *obj, int flags); +extern struct json_object* json_object_from_file(wchar_t *filename); +extern int json_object_to_file(wchar_t *FileName, struct json_object *obj); +extern int json_object_to_file_ext(wchar_t *FileName, struct json_object *obj, int flags); extern int json_parse_int64(const char *buf, int64_t *retval); extern int json_parse_double(const char *buf, double *retval); From 1a1a53b70243c094df1991039f249b15d3b08429 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 29 Sep 2017 21:33:20 +1000 Subject: [PATCH 0441/2058] Add inital RS3 types --- phnt/include/ntexapi.h | 3 +++ phnt/include/ntioapi.h | 1 + phnt/include/ntmmapi.h | 4 +++- phnt/include/ntpsapi.h | 9 +++++++++ phnt/include/ntregapi.h | 1 + 5 files changed, 17 insertions(+), 1 deletion(-) diff --git a/phnt/include/ntexapi.h b/phnt/include/ntexapi.h index 760260980a90..6d2e8ac48ce7 100644 --- a/phnt/include/ntexapi.h +++ b/phnt/include/ntexapi.h @@ -1390,6 +1390,9 @@ typedef enum _SYSTEM_INFORMATION_CLASS SystemCodeIntegrityUnlockInformation, // SYSTEM_CODEINTEGRITY_UNLOCK_INFORMATION // 190 SystemIntegrityQuotaInformation, SystemFlushInformation, // q: SYSTEM_FLUSH_INFORMATION + SystemProcessorIdleMaskInformation, // since REDSTONE3 + SystemSecureDumpEncryptionInformation, + SystemWriteConstraintInformation, MaxSystemInfoClass } SYSTEM_INFORMATION_CLASS; diff --git a/phnt/include/ntioapi.h b/phnt/include/ntioapi.h index c13aa19c3721..6bbcc5652ef9 100644 --- a/phnt/include/ntioapi.h +++ b/phnt/include/ntioapi.h @@ -242,6 +242,7 @@ typedef enum _FILE_INFORMATION_CLASS FileRenameInformationExBypassAccessCheck, FileDesiredStorageClassInformation, // FILE_DESIRED_STORAGE_CLASS_INFORMATION // since REDSTONE2 FileStatInformation, // FILE_STAT_INFORMATION + FileMemoryPartitionInformation, // since REDSTONE3 FileMaximumInformation } FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS; diff --git a/phnt/include/ntmmapi.h b/phnt/include/ntmmapi.h index 9499ee236911..9f282024dfe5 100644 --- a/phnt/include/ntmmapi.h +++ b/phnt/include/ntmmapi.h @@ -66,7 +66,9 @@ typedef enum _MEMORY_INFORMATION_CLASS MemorySharedCommitInformation, // MEMORY_SHARED_COMMIT_INFORMATION MemoryImageInformation, // MEMORY_IMAGE_INFORMATION MemoryRegionInformationEx, - MemoryPrivilegedBasicInformation + MemoryPrivilegedBasicInformation, + MemoryEnclaveImageInformation, // since REDSTONE3 + MemoryBasicInformationCapped } MEMORY_INFORMATION_CLASS; #if (PHNT_MODE == PHNT_MODE_KERNEL) diff --git a/phnt/include/ntpsapi.h b/phnt/include/ntpsapi.h index cc957c2baf71..0816befb2b34 100644 --- a/phnt/include/ntpsapi.h +++ b/phnt/include/ntpsapi.h @@ -180,6 +180,13 @@ typedef enum _PROCESSINFOCLASS ProcessDisableSystemAllowedCpuSets, ProcessWakeInformation, // PROCESS_WAKE_INFORMATION ProcessEnergyTrackingState, // PROCESS_ENERGY_TRACKING_STATE + ProcessManageWritesToExecutableMemory, // since REDSTONE3 + ProcessCaptureTrustletLiveDump, + ProcessTelemetryCoverage, + ProcessEnclaveInformation, + ProcessEnableReadWriteVmLogging, + ProcessUptimeInformation, + ProcessImageSection, MaxProcessInfoClass } PROCESSINFOCLASS; #endif @@ -235,6 +242,8 @@ typedef enum _THREADINFOCLASS ThreadSubsystemInformation, // q: SUBSYSTEM_INFORMATION_TYPE // since REDSTONE2 ThreadDbgkWerReportActive, ThreadAttachContainer, + ThreadManageWritesToExecutableMemory, // since REDSTONE3 + ThreadPowerThrottlingState, MaxThreadInfoClass } THREADINFOCLASS; #endif diff --git a/phnt/include/ntregapi.h b/phnt/include/ntregapi.h index d5d874173322..0a3a4c8be773 100644 --- a/phnt/include/ntregapi.h +++ b/phnt/include/ntregapi.h @@ -120,6 +120,7 @@ typedef enum _KEY_SET_INFORMATION_CLASS KeySetVirtualizationInformation, // KEY_SET_VIRTUALIZATION_INFORMATION KeySetDebugInformation, KeySetHandleTagsInformation, // KEY_HANDLE_TAGS_INFORMATION + KeySetLayerInformation, MaxKeySetInfoClass } KEY_SET_INFORMATION_CLASS; From 5464c0cae5907ec5dcb0f619b8db2a9c3640fca0 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 30 Sep 2017 22:50:12 +1000 Subject: [PATCH 0442/2058] Fix incorrect SYSDBG types --- phnt/include/ntexapi.h | 35 ++++++++++++++++------------------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/phnt/include/ntexapi.h b/phnt/include/ntexapi.h index 6d2e8ac48ce7..70e2310acc32 100644 --- a/phnt/include/ntexapi.h +++ b/phnt/include/ntexapi.h @@ -3156,35 +3156,31 @@ typedef struct _SYSDBG_TRIAGE_DUMP } SYSDBG_TRIAGE_DUMP, *PSYSDBG_TRIAGE_DUMP; // private -typedef struct _SYSDBG_LIVEDUMP_CONTROL_FLAGS +typedef union _SYSDBG_LIVEDUMP_CONTROL_FLAGS { - union + struct { - struct - { - ULONG UseDumpStorageStack : 1; - ULONG CompressMemoryPagesData : 1; - ULONG IncludeUserSpaceMemoryPages : 1; - ULONG Reserved : 28; - }; - ULONG AsUlong; + ULONG UseDumpStorageStack : 1; + ULONG CompressMemoryPagesData : 1; + ULONG IncludeUserSpaceMemoryPages : 1; + ULONG Reserved : 29; }; + ULONG AsUlong; } SYSDBG_LIVEDUMP_CONTROL_FLAGS, *PSYSDBG_LIVEDUMP_CONTROL_FLAGS; // private -typedef struct _SYSDBG_LIVEDUMP_CONTROL_ADDPAGES +typedef union _SYSDBG_LIVEDUMP_CONTROL_ADDPAGES { - union + struct { - struct - { - ULONG HypervisorPages : 1; - ULONG Reserved : 31; - }; - ULONG AsUlong; + ULONG HypervisorPages : 1; + ULONG Reserved : 31; }; + ULONG AsUlong; } SYSDBG_LIVEDUMP_CONTROL_ADDPAGES, *PSYSDBG_LIVEDUMP_CONTROL_ADDPAGES; +#define SYSDBG_LIVEDUMP_CONTROL_VERSION 1 + // private typedef struct _SYSDBG_LIVEDUMP_CONTROL { @@ -3367,7 +3363,8 @@ typedef struct _KUSER_SHARED_DATA ULONG DbgSecureBootEnabled : 1; ULONG DbgMultiSessionSku : 1; ULONG DbgMultiUsersInSessionSku : 1; - ULONG SpareBits : 22; + ULONG DbgStateSeparationEnabled : 1; + ULONG SpareBits : 21; }; }; ULONG DataFlagsPad[1]; From d5338e96fa5a918161b0ca9ca655274bc7ff37b7 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 1 Oct 2017 03:18:29 +1100 Subject: [PATCH 0443/2058] SetupTool: Fix creating ifeo key --- tools/CustomSetupTool/CustomSetupTool/setup.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/CustomSetupTool/CustomSetupTool/setup.c b/tools/CustomSetupTool/CustomSetupTool/setup.c index 9933ad96a515..48d5f8a41d72 100644 --- a/tools/CustomSetupTool/CustomSetupTool/setup.c +++ b/tools/CustomSetupTool/CustomSetupTool/setup.c @@ -686,10 +686,10 @@ VOID SetupCreateImageFileExecutionOptions( if (NT_SUCCESS(PhCreateKey( &keyHandle, - KEY_WRITE | DELETE, + KEY_WRITE, PH_KEY_LOCAL_MACHINE, &PhImageOptionsKeyName, - 0, + OBJ_OPENIF, 0, NULL ))) From 4df29b79242263d89bf79eb836cc0d7854db8ab6 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 1 Oct 2017 04:08:26 +1100 Subject: [PATCH 0444/2058] Add undocumented RunFileDlg flags (Vista+) --- phlib/include/guisup.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/phlib/include/guisup.h b/phlib/include/guisup.h index 60ac7efe1267..f7d7abb6d655 100644 --- a/phlib/include/guisup.h +++ b/phlib/include/guisup.h @@ -20,8 +20,10 @@ typedef BOOL (WINAPI *_IsImmersiveProcess)( #define RFF_CALCDIRECTORY 0x0004 #define RFF_NOLABEL 0x0008 #define RFF_NOSEPARATEMEM 0x0020 +#define RFF_OPTRUNAS 0x0040 #define RFN_VALIDATE (-510) +#define RFN_LIMITEDRUNAS (-511) typedef struct _NMRUNFILEDLGW { From 85a1bde535dc01de088948527abbe6c47def8ec3 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 1 Oct 2017 05:14:20 +1100 Subject: [PATCH 0445/2058] Reduce 0-byte string allocations (experimental) orang? --- phlib/include/phbasesup.h | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/phlib/include/phbasesup.h b/phlib/include/phbasesup.h index cfaad93639d0..7dd9bb837a28 100644 --- a/phlib/include/phbasesup.h +++ b/phlib/include/phbasesup.h @@ -1131,12 +1131,22 @@ PhCreateStringEx( _In_ SIZE_T Length ); +PHLIBAPI +PPH_STRING +NTAPI +PhReferenceEmptyString( + VOID + ); + FORCEINLINE PPH_STRING PhCreateString2( _In_ PPH_STRINGREF String ) { + if (String->Length == 0) + return PhReferenceEmptyString(); + return PhCreateStringEx(String->Buffer, String->Length); } @@ -1146,16 +1156,12 @@ PhCreateStringFromUnicodeString( _In_ PUNICODE_STRING UnicodeString ) { + if (UnicodeString->Length == 0) + return PhReferenceEmptyString(); + return PhCreateStringEx(UnicodeString->Buffer, UnicodeString->Length); } -PHLIBAPI -PPH_STRING -NTAPI -PhReferenceEmptyString( - VOID - ); - PHLIBAPI PPH_STRING NTAPI From 03afda7eb8af18258cbcb5cb2e7e0a58fd31f57c Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 4 Oct 2017 11:55:37 +1100 Subject: [PATCH 0446/2058] NetworkTools: Fix ping dialog focus --- plugins/NetworkTools/ping.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/NetworkTools/ping.c b/plugins/NetworkTools/ping.c index 0d94de17499a..4fd646f6e450 100644 --- a/plugins/NetworkTools/ping.c +++ b/plugins/NetworkTools/ping.c @@ -350,7 +350,7 @@ INT_PTR CALLBACK NetworkPingWndProc( EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); } - return TRUE; + break; case WM_COMMAND: { switch (GET_WM_COMMAND_ID(wParam, lParam)) From 77b3cb7e39a1daad02239537477051457e5d0a64 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 4 Oct 2017 11:57:36 +1100 Subject: [PATCH 0447/2058] ToolStatus: Fix toolbar/statusbar customize dialog focus --- plugins/ToolStatus/customizesb.c | 14 +++++++++++++- plugins/ToolStatus/customizetb.c | 20 +++++++++++++++++++- 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/plugins/ToolStatus/customizesb.c b/plugins/ToolStatus/customizesb.c index e8ce99115092..edb1929a8caf 100644 --- a/plugins/ToolStatus/customizesb.c +++ b/plugins/ToolStatus/customizesb.c @@ -328,7 +328,7 @@ INT_PTR CALLBACK CustomizeStatusBarDialogProc( SendMessage(context->DialogHandle, WM_NEXTDLGCTL, (WPARAM)context->CurrentListHandle, TRUE); } - return TRUE; + break; case WM_DESTROY: { StatusBarSaveSettings(); @@ -394,6 +394,11 @@ INT_PTR CALLBACK CustomizeStatusBarDialogProc( CustomizeAddStatusBarItem(context, index, indexto); } break; + case LBN_KILLFOCUS: + { + Button_Enable(context->AddButtonHandle, FALSE); + } + break; } } break; @@ -470,6 +475,13 @@ INT_PTR CALLBACK CustomizeStatusBarDialogProc( CustomizeRemoveStatusBarItem(context, index); } break; + case LBN_KILLFOCUS: + { + Button_Enable(context->MoveUpButtonHandle, FALSE); + Button_Enable(context->MoveDownButtonHandle, FALSE); + Button_Enable(context->RemoveButtonHandle, FALSE); + } + break; } } break; diff --git a/plugins/ToolStatus/customizetb.c b/plugins/ToolStatus/customizetb.c index 27330c0c74ba..7e6e8eb74f28 100644 --- a/plugins/ToolStatus/customizetb.c +++ b/plugins/ToolStatus/customizetb.c @@ -365,6 +365,7 @@ VOID CustomizeLoadToolbarItems( // Disable buttons Button_Enable(Context->MoveUpButtonHandle, FALSE); Button_Enable(Context->MoveDownButtonHandle, FALSE); + Button_Enable(Context->AddButtonHandle, FALSE); Button_Enable(Context->RemoveButtonHandle, FALSE); } @@ -533,7 +534,7 @@ INT_PTR CALLBACK CustomizeToolbarDialogProc( SendMessage(context->DialogHandle, WM_NEXTDLGCTL, (WPARAM)context->CurrentListHandle, TRUE); } - return TRUE; + break; case WM_DESTROY: { ToolbarSaveButtonSettings(); @@ -558,6 +559,11 @@ INT_PTR CALLBACK CustomizeToolbarDialogProc( { switch (GET_WM_COMMAND_CMD(wParam, lParam)) { + case LBN_SELCHANGE: + { + Button_Enable(context->AddButtonHandle, TRUE); + } + break; case LBN_DBLCLK: { INT index; @@ -575,6 +581,11 @@ INT_PTR CALLBACK CustomizeToolbarDialogProc( CustomizeAddToolbarItem(context, index, indexto); } break; + case LBN_KILLFOCUS: + { + Button_Enable(context->AddButtonHandle, FALSE); + } + break; } } break; @@ -650,6 +661,13 @@ INT_PTR CALLBACK CustomizeToolbarDialogProc( CustomizeRemoveToolbarItem(context, index); } break; + case LBN_KILLFOCUS: + { + Button_Enable(context->MoveUpButtonHandle, FALSE); + Button_Enable(context->MoveDownButtonHandle, FALSE); + Button_Enable(context->RemoveButtonHandle, FALSE); + } + break; } } break; From 222cc32ed44cce1768eb816d162d25373a77436a Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 4 Oct 2017 12:35:55 +1100 Subject: [PATCH 0448/2058] NetworkTools: Fix tracert crash --- plugins/NetworkTools/tracert.c | 6 ++- plugins/NetworkTools/tracetree.c | 66 +++++++++++++++++++++++++------- 2 files changed, 57 insertions(+), 15 deletions(-) diff --git a/plugins/NetworkTools/tracert.c b/plugins/NetworkTools/tracert.c index 75f8e2b0d609..311dfe47787f 100644 --- a/plugins/NetworkTools/tracert.c +++ b/plugins/NetworkTools/tracert.c @@ -301,13 +301,15 @@ NTSTATUS NetworkTracertThreadStart( for (ULONG i = 0; i < DEFAULT_MAXIMUM_HOPS; i++) { + PTRACERT_ROOT_NODE node; IN_ADDR last4ReplyAddress = in4addr_any; IN6_ADDR last6ReplyAddress = in6addr_any; if (context->Cancel) break; - PTRACERT_ROOT_NODE node = AddTracertNode(context, pingOptions.Ttl); + node = AddTracertNode(context, pingOptions.Ttl); + PhReferenceObject(node); for (ULONG ii = 0; ii < DEFAULT_MAXIMUM_PINGS; ii++) { @@ -427,6 +429,8 @@ NTSTATUS NetworkTracertThreadStart( } } + PhDereferenceObject(node); + if (context->RemoteEndpoint.Address.Type == PH_IPV4_NETWORK_TYPE) { if (!memcmp(&last4ReplyAddress, &((PSOCKADDR_IN)&destinationAddress)->sin_addr, sizeof(IN_ADDR))) diff --git a/plugins/NetworkTools/tracetree.c b/plugins/NetworkTools/tracetree.c index 9327858f7434..0423c418332e 100644 --- a/plugins/NetworkTools/tracetree.c +++ b/plugins/NetworkTools/tracetree.c @@ -24,6 +24,49 @@ #include "tracert.h" #include +PPH_OBJECT_TYPE TracertTreeNodeItemType; + +VOID NTAPI TracertTreeNodeItemDeleteProcedure( + _In_ PVOID Object, + _In_ ULONG Flags + ) +{ + PTRACERT_ROOT_NODE tracertNode = Object; + + if (tracertNode->TtlString) + PhDereferenceObject(tracertNode->TtlString); + if (tracertNode->CountryString) + PhDereferenceObject(tracertNode->CountryString); + if (tracertNode->HostnameString) + PhDereferenceObject(tracertNode->HostnameString); + if (tracertNode->IpAddressString) + PhDereferenceObject(tracertNode->IpAddressString); + if (tracertNode->RemoteCountryCode) + PhDereferenceObject(tracertNode->RemoteCountryCode); + if (tracertNode->RemoteCountryName) + PhDereferenceObject(tracertNode->RemoteCountryName); + + for (ULONG i = 0; i < DEFAULT_MAXIMUM_PINGS; i++) + { + if (tracertNode->PingString[i]) + PhDereferenceObject(tracertNode->PingString[i]); + } +} + +PTRACERT_ROOT_NODE TracertTreeCreateNode( + VOID + ) +{ + PTRACERT_ROOT_NODE tracertNode; + + tracertNode = PhCreateObject(sizeof(TRACERT_ROOT_NODE), TracertTreeNodeItemType); + memset(tracertNode, 0, sizeof(TRACERT_ROOT_NODE)); + + PhInitializeTreeNewNode(&tracertNode->Node); + + return tracertNode; +} + #define SORT_FUNCTION(Column) TracertTreeNewCompare##Column #define BEGIN_SORT_FUNCTION(Column) static int __cdecl TracertTreeNewCompare##Column( \ _In_ void *_context, \ @@ -146,16 +189,6 @@ VOID DestroyTracertNode( _In_ PTRACERT_ROOT_NODE Node ) { - PhClearReference(&Node->TtlString); - PhClearReference(&Node->CountryString); - PhClearReference(&Node->HostnameString); - PhClearReference(&Node->IpAddressString); - PhClearReference(&Node->RemoteCountryCode); - PhClearReference(&Node->RemoteCountryName); - - for (ULONG i = 0; i < DEFAULT_MAXIMUM_PINGS; i++) - PhClearReference(&Node->PingString[i]); - PhDereferenceObject(Node); } @@ -166,10 +199,7 @@ PTRACERT_ROOT_NODE AddTracertNode( { PTRACERT_ROOT_NODE tracertNode; - tracertNode = PhCreateAlloc(sizeof(TRACERT_ROOT_NODE)); - memset(tracertNode, 0, sizeof(TRACERT_ROOT_NODE)); - - PhInitializeTreeNewNode(&tracertNode->Node); + tracertNode = TracertTreeCreateNode(); tracertNode->TTL = TTL; memset(tracertNode->PingStatus, STATUS_FAIL_CHECK, sizeof(tracertNode->PingStatus)); @@ -558,6 +588,14 @@ VOID InitializeTracertTree( _Inout_ PNETWORK_TRACERT_CONTEXT Context ) { + static PH_INITONCE initOnce = PH_INITONCE_INIT; + + if (PhBeginInitOnce(&initOnce)) + { + TracertTreeNodeItemType = PhCreateObjectType(L"TracertTreeNodeItem", 0, TracertTreeNodeItemDeleteProcedure); + PhEndInitOnce(&initOnce); + } + Context->NodeList = PhCreateList(100); Context->NodeHashtable = PhCreateHashtable( sizeof(PTRACERT_ROOT_NODE), From 2ee8055ebd71053e7cfe4a3f8f6e69f8554c643a Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 5 Oct 2017 12:18:45 +1100 Subject: [PATCH 0449/2058] Fix RS3 sdk conflict --- ProcessHacker/ProcessHacker.rc | 2 +- ProcessHacker/miniinfo.c | 14 +++++++------- ProcessHacker/resource.h | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/ProcessHacker/ProcessHacker.rc b/ProcessHacker/ProcessHacker.rc index 47f7c8402e2b..ffb1f8741c04 100644 --- a/ProcessHacker/ProcessHacker.rc +++ b/ProcessHacker/ProcessHacker.rc @@ -1812,7 +1812,7 @@ BEGIN LTEXT "Content layout",IDC_LAYOUT,4,3,210,128,NOT WS_VISIBLE CONTROL "Section",IDC_SECTION,"Static",SS_LEFTNOWORDWRAP | SS_NOTIFY | SS_ENDELLIPSIS | WS_GROUP,4,134,177,13 PUSHBUTTON "Options",IDC_OPTIONS,183,133,15,14,BS_ICON - CONTROL "Pin",IDC_PIN,"Button",BS_AUTOCHECKBOX | BS_ICON | BS_PUSHLIKE | WS_TABSTOP,199,133,15,14 + CONTROL "Pin",IDC_PINWINDOW,"Button",BS_AUTOCHECKBOX | BS_ICON | BS_PUSHLIKE | WS_TABSTOP,199,133,15,14 END IDD_MINIINFO_LIST DIALOGEX 0, 0, 217, 141 diff --git a/ProcessHacker/miniinfo.c b/ProcessHacker/miniinfo.c index a6695a217eb1..e1d3489d7296 100644 --- a/ProcessHacker/miniinfo.c +++ b/ProcessHacker/miniinfo.c @@ -352,7 +352,7 @@ VOID PhMipContainerOnShowWindow( for (i = 0; i < MaxMiniInfoPinType; i++) PhMipPinCounts[i] = 0; - Button_SetCheck(GetDlgItem(PhMipWindow, IDC_PIN), BST_UNCHECKED); + Button_SetCheck(GetDlgItem(PhMipWindow, IDC_PINWINDOW), BST_UNCHECKED); PhMipSetPinned(FALSE); PhSetIntegerSetting(L"MiniInfoWindowPinned", FALSE); @@ -452,7 +452,7 @@ VOID PhMipOnInitDialog( SET_BUTTON_ICON(PhMipWindow, IDC_OPTIONS, cog); pin = PH_LOAD_SHARED_ICON_SMALL(PhInstanceHandle, MAKEINTRESOURCE(IDI_PIN)); - SET_BUTTON_ICON(PhMipWindow, IDC_PIN, pin); + SET_BUTTON_ICON(PhMipWindow, IDC_PINWINDOW, pin); PhInitializeLayoutManager(&PhMipLayoutManager, PhMipWindow); PhAddLayoutItem(&PhMipLayoutManager, GetDlgItem(PhMipWindow, IDC_LAYOUT), NULL, @@ -461,12 +461,12 @@ VOID PhMipOnInitDialog( PH_ANCHOR_LEFT | PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM | PH_LAYOUT_FORCE_INVALIDATE); PhAddLayoutItem(&PhMipLayoutManager, GetDlgItem(PhMipWindow, IDC_OPTIONS), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); - PhAddLayoutItem(&PhMipLayoutManager, GetDlgItem(PhMipWindow, IDC_PIN), NULL, + PhAddLayoutItem(&PhMipLayoutManager, GetDlgItem(PhMipWindow, IDC_PINWINDOW), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); SetWindowSubclass(GetDlgItem(PhMipWindow, IDC_SECTION), PhMipSectionControlHookWndProc, 0, 0); - Button_SetCheck(GetDlgItem(PhMipWindow, IDC_PIN), !!PhGetIntegerSetting(L"MiniInfoWindowPinned")); + Button_SetCheck(GetDlgItem(PhMipWindow, IDC_PINWINDOW), !!PhGetIntegerSetting(L"MiniInfoWindowPinned")); } VOID PhMipOnShowWindow( @@ -519,11 +519,11 @@ VOID PhMipOnCommand( case IDC_OPTIONS: PhMipShowOptionsMenu(); break; - case IDC_PIN: + case IDC_PINWINDOW: { BOOLEAN pinned; - pinned = Button_GetCheck(GetDlgItem(PhMipWindow, IDC_PIN)) == BST_CHECKED; + pinned = Button_GetCheck(GetDlgItem(PhMipWindow, IDC_PINWINDOW)) == BST_CHECKED; PhPinMiniInformation(MiniInfoManualPinType, pinned ? 1 : -1, 0, 0, NULL, NULL); PhMipSetPinned(pinned); PhSetIntegerSetting(L"MiniInfoWindowPinned", pinned); @@ -987,7 +987,7 @@ VOID PhMipLayout( ); } - GetWindowRect(GetDlgItem(PhMipWindow, IDC_PIN), &rect); + GetWindowRect(GetDlgItem(PhMipWindow, IDC_PINWINDOW), &rect); MapWindowPoints(NULL, PhMipWindow, (POINT *)&rect, 2); } diff --git a/ProcessHacker/resource.h b/ProcessHacker/resource.h index cb5262a4eadc..ffec44e7675d 100644 --- a/ProcessHacker/resource.h +++ b/ProcessHacker/resource.h @@ -504,7 +504,7 @@ #define IDC_ZPAGINGPAGEREADSDELTA_V 1369 #define IDC_BYTESPERROW 1369 #define IDC_ZPAGINGPAGEFILEWRITESDELTA_V 1370 -#define IDC_PIN 1370 +#define IDC_PINWINDOW 1370 #define IDC_ZPAGINGMAPPEDWRITESDELTA_V 1371 #define IDC_ZLISTMODIFIEDPAGEFILE_V 1373 #define IDC_SECTION 1375 From a147a5c8afc9062e71994fa922303dd854e14331 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 5 Oct 2017 12:35:53 +1100 Subject: [PATCH 0450/2058] Update ForceNoParent default setting --- ProcessHacker/settings.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ProcessHacker/settings.c b/ProcessHacker/settings.c index 933d27733ad9..5eaf3964eeda 100644 --- a/ProcessHacker/settings.c +++ b/ProcessHacker/settings.c @@ -61,7 +61,7 @@ VOID PhAddDefaultSettings( PhpAddStringSetting(L"FileBrowseExecutable", L"%SystemRoot%\\explorer.exe /select,\"%s\""); PhpAddIntegerSetting(L"FirstRun", L"1"); PhpAddStringSetting(L"Font", L""); // null - PhpAddIntegerSetting(L"ForceNoParent", L"0"); + PhpAddIntegerSetting(L"ForceNoParent", L"1"); PhpAddStringSetting(L"HandleTreeListColumns", L""); PhpAddStringSetting(L"HandleTreeListSort", L"0,1"); // 0, AscendingSortOrder PhpAddIntegerSetting(L"HiddenProcessesMenuEnabled", L"0"); From f7c60b4bfa15d252d2cd1b8d4cfe9d255d5c9b92 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 5 Oct 2017 18:04:26 +1100 Subject: [PATCH 0451/2058] Fix AppId column for store apps --- ProcessHacker/proctree.c | 69 ++++++++++++++++++++++++++++++++++------ 1 file changed, 60 insertions(+), 9 deletions(-) diff --git a/ProcessHacker/proctree.c b/ProcessHacker/proctree.c index 22a3d5ad63ec..6b1da367e78d 100644 --- a/ProcessHacker/proctree.c +++ b/ProcessHacker/proctree.c @@ -608,7 +608,7 @@ VOID PhTickProcessNodes( // The name and PID never change, so we don't invalidate that. memset(&node->TextCache[2], 0, sizeof(PH_STRINGREF) * (PHPRTLC_MAXIMUM - 2)); - node->ValidMask &= PHPN_OSCONTEXT | PHPN_IMAGE | PHPN_DPIAWARENESS; // Items that always remain valid + node->ValidMask &= PHPN_OSCONTEXT | PHPN_IMAGE | PHPN_DPIAWARENESS | PHPN_APPID; // Items that always remain valid // Invalidate graph buffers. node->CpuGraphBuffers.Valid = FALSE; @@ -1091,16 +1091,67 @@ static VOID PhpUpdateProcessNodeAppId( PhClearReference(&ProcessNode->AppIdText); - if (ProcessNode->ProcessItem->QueryHandle && NT_SUCCESS(PhGetProcessWindowTitle( - ProcessNode->ProcessItem->QueryHandle, - &windowFlags, - &windowTitle - ))) + if (ProcessNode->ProcessItem->QueryHandle) { - if (windowFlags & STARTF_TITLEISAPPID) - ProcessNode->AppIdText = windowTitle; + if (WindowsVersion >= WINDOWS_8 && ProcessNode->ProcessItem->IsImmersive) + { + HANDLE tokenHandle; + PTOKEN_SECURITY_ATTRIBUTES_INFORMATION info; + + if (NT_SUCCESS(PhOpenProcessToken( + ProcessNode->ProcessItem->QueryHandle, + TOKEN_QUERY, + &tokenHandle + ))) + { + // rev from GetApplicationUserModelId + if (NT_SUCCESS(PhQueryTokenVariableSize(tokenHandle, TokenSecurityAttributes, &info))) + { + for (ULONG i = 0; i < info->AttributeCount; i++) + { + static UNICODE_STRING attributeNameUs = RTL_CONSTANT_STRING(L"WIN://SYSAPPID"); + PTOKEN_SECURITY_ATTRIBUTE_V1 attribute = &info->Attribute.pAttributeV1[i]; + + if (RtlEqualUnicodeString(&attribute->Name, &attributeNameUs, FALSE)) + { + if (attribute->ValueType == TOKEN_SECURITY_ATTRIBUTE_TYPE_STRING) + { + PPH_STRING attributeValue1; + PPH_STRING attributeValue2; + + attributeValue1 = PH_AUTO(PhCreateStringFromUnicodeString(&attribute->Values.pString[1])); + attributeValue2 = PH_AUTO(PhCreateStringFromUnicodeString(&attribute->Values.pString[2])); + + ProcessNode->AppIdText = PhConcatStrings( + 3, + attributeValue2->Buffer, + L"!", + attributeValue1->Buffer + ); + } + } + } + + PhFree(info); + } + + NtClose(tokenHandle); + } + } else - PhDereferenceObject(windowTitle); + { + if (NT_SUCCESS(PhGetProcessWindowTitle( + ProcessNode->ProcessItem->QueryHandle, + &windowFlags, + &windowTitle + ))) + { + if (windowFlags & STARTF_TITLEISAPPID) + ProcessNode->AppIdText = windowTitle; + else + PhDereferenceObject(windowTitle); + } + } } ProcessNode->ValidMask |= PHPN_APPID; From 820ba59146b157e50b59b803561d7f6c9b95895d Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 5 Oct 2017 18:34:08 +1100 Subject: [PATCH 0452/2058] Add missing break from previous commit --- ProcessHacker/proctree.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ProcessHacker/proctree.c b/ProcessHacker/proctree.c index 6b1da367e78d..3e6e6d445f9b 100644 --- a/ProcessHacker/proctree.c +++ b/ProcessHacker/proctree.c @@ -1128,6 +1128,8 @@ static VOID PhpUpdateProcessNodeAppId( L"!", attributeValue1->Buffer ); + + break; } } } From 624d8c30a6bcf057a67e45197d641f148962f4b9 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 5 Oct 2017 18:47:46 +1100 Subject: [PATCH 0453/2058] Improve store package lookup performance (experimental) --- ProcessHacker/appsup.c | 163 +++++++++----------------------- ProcessHacker/include/appsup.h | 8 +- ProcessHacker/include/procprv.h | 4 +- ProcessHacker/modprv.c | 2 +- ProcessHacker/procprv.c | 18 ++-- ProcessHacker/prpggen.c | 2 +- 6 files changed, 58 insertions(+), 139 deletions(-) diff --git a/ProcessHacker/appsup.c b/ProcessHacker/appsup.c index e72d2cf1e37c..d8a109c3d3d2 100644 --- a/ProcessHacker/appsup.c +++ b/ProcessHacker/appsup.c @@ -41,26 +41,6 @@ #include "pcre/pcre2.h" -typedef LONG (WINAPI *_GetPackageFullName)( - _In_ HANDLE hProcess, - _Inout_ UINT32 *packageFullNameLength, - _Out_opt_ PWSTR packageFullName - ); - -typedef LONG (WINAPI *_GetPackagePath)( - _In_ PACKAGE_ID *packageId, - _Reserved_ UINT32 reserved, - _Inout_ UINT32 *pathLength, - _Out_opt_ PWSTR path - ); - -typedef LONG (WINAPI *_PackageIdFromFullName)( - _In_ PCWSTR packageFullName, - _In_ UINT32 flags, - _Inout_ UINT32 *bufferLength, - _Out_opt_ BYTE *buffer - ); - GUID XP_CONTEXT_GUID = { 0xbeb1b341, 0x6837, 0x4c83, { 0x83, 0x66, 0x2b, 0x45, 0x1e, 0x7c, 0xe6, 0x9b } }; GUID VISTA_CONTEXT_GUID = { 0xe2011457, 0x1546, 0x43c5, { 0xa5, 0xfe, 0x00, 0x8d, 0xee, 0xe3, 0xd3, 0xf0 } }; GUID WIN7_CONTEXT_GUID = { 0x35138b9a, 0x5d96, 0x4fbd, { 0x8e, 0x2d, 0xa2, 0x44, 0x02, 0x25, 0xf9, 0x3a } }; @@ -242,119 +222,70 @@ PPH_STRING PhGetProcessPackageFullName( _In_ HANDLE ProcessHandle ) { - static _GetPackageFullName getPackageFullName = NULL; - - LONG result; - PPH_STRING name; - ULONG nameLength; - - if (!getPackageFullName) - getPackageFullName = PhGetModuleProcAddress(L"kernel32.dll", "GetPackageFullName"); - if (!getPackageFullName) - return NULL; - - nameLength = 101; - name = PhCreateStringEx(NULL, (nameLength - 1) * 2); - - result = getPackageFullName(ProcessHandle, &nameLength, name->Buffer); - - if (result == ERROR_INSUFFICIENT_BUFFER) - { - PhDereferenceObject(name); - name = PhCreateStringEx(NULL, (nameLength - 1) * 2); - - result = getPackageFullName(ProcessHandle, &nameLength, name->Buffer); - } + HANDLE tokenHandle; + PTOKEN_SECURITY_ATTRIBUTES_INFORMATION info; + PPH_STRING name = NULL; - if (result == ERROR_SUCCESS) - { - PhTrimToNullTerminatorString(name); - return name; - } - else + if (NT_SUCCESS(PhOpenProcessToken( + ProcessHandle, + TOKEN_QUERY, + &tokenHandle + ))) { - PhDereferenceObject(name); - return NULL; - } -} - -PACKAGE_ID *PhPackageIdFromFullName( - _In_ PWSTR PackageFullName - ) -{ - static _PackageIdFromFullName packageIdFromFullName = NULL; - - LONG result; - PVOID packageIdBuffer; - ULONG packageIdBufferSize; - - if (!packageIdFromFullName) - packageIdFromFullName = PhGetModuleProcAddress(L"kernel32.dll", "PackageIdFromFullName"); - if (!packageIdFromFullName) - return NULL; - - packageIdBufferSize = 100; - packageIdBuffer = PhAllocate(packageIdBufferSize); + // rev from PackageIdFromFullName + if (NT_SUCCESS(PhQueryTokenVariableSize(tokenHandle, TokenSecurityAttributes, &info))) + { + for (ULONG i = 0; i < info->AttributeCount; i++) + { + static UNICODE_STRING attributeNameUs = RTL_CONSTANT_STRING(L"WIN://SYSAPPID"); + PTOKEN_SECURITY_ATTRIBUTE_V1 attribute = &info->Attribute.pAttributeV1[i]; - result = packageIdFromFullName(PackageFullName, PACKAGE_INFORMATION_BASIC, &packageIdBufferSize, (PBYTE)packageIdBuffer); + if (RtlEqualUnicodeString(&attribute->Name, &attributeNameUs, FALSE)) + { + if (attribute->ValueType == TOKEN_SECURITY_ATTRIBUTE_TYPE_STRING) + { + name = PhCreateStringFromUnicodeString(&attribute->Values.pString[0]); + break; + } + } + } - if (result == ERROR_INSUFFICIENT_BUFFER) - { - PhFree(packageIdBuffer); - packageIdBuffer = PhAllocate(packageIdBufferSize); + PhFree(info); + } - result = packageIdFromFullName(PackageFullName, PACKAGE_INFORMATION_BASIC, &packageIdBufferSize, (PBYTE)packageIdBuffer); + NtClose(tokenHandle); } - if (result == ERROR_SUCCESS) - { - return packageIdBuffer; - } - else - { - PhFree(packageIdBuffer); - return NULL; - } + return name; } PPH_STRING PhGetPackagePath( - _In_ PACKAGE_ID *PackageId + _In_ PPH_STRING PackageFullName ) { - static _GetPackagePath getPackagePath = NULL; + static PH_STRINGREF storeAppPackages = PH_STRINGREF_INIT(L"Software\\Classes\\Local Settings\\Software\\Microsoft\\Windows\\CurrentVersion\\AppModel\\Repository\\Packages\\"); + HANDLE keyHandle; + PPH_STRING keyPath; + PPH_STRING packagePath = NULL; - LONG result; - PPH_STRING path; - ULONG pathLength; + keyPath = PhConcatStringRef2(&storeAppPackages, &PackageFullName->sr); - if (!getPackagePath) - getPackagePath = PhGetModuleProcAddress(L"kernel32.dll", "GetPackagePath"); - if (!getPackagePath) - return NULL; - - pathLength = 101; - path = PhCreateStringEx(NULL, (pathLength - 1) * 2); - - result = getPackagePath(PackageId, 0, &pathLength, path->Buffer); - - if (result == ERROR_INSUFFICIENT_BUFFER) + // rev from GetPackagePath + if (NT_SUCCESS(PhOpenKey( + &keyHandle, + KEY_READ, + PH_KEY_CURRENT_USER, + &keyPath->sr, + 0 + ))) { - PhDereferenceObject(path); - path = PhCreateStringEx(NULL, (pathLength - 1) * 2); - - result = getPackagePath(PackageId, 0, &pathLength, path->Buffer); + packagePath = PhQueryRegistryString(keyHandle, L"PackageRootFolder"); + NtClose(keyHandle); } - if (result == ERROR_SUCCESS) - { - PhTrimToNullTerminatorString(path); - return path; - } - else - { - PhDereferenceObject(path); - return NULL; - } + PhDereferenceObject(keyPath); + + return packagePath; } /** diff --git a/ProcessHacker/include/appsup.h b/ProcessHacker/include/appsup.h index 16d1762462da..3ae868ceb48e 100644 --- a/ProcessHacker/include/appsup.h +++ b/ProcessHacker/include/appsup.h @@ -8,8 +8,6 @@ extern GUID WIN8_CONTEXT_GUID; extern GUID WINBLUE_CONTEXT_GUID; extern GUID WINTHRESHOLD_CONTEXT_GUID; -typedef struct PACKAGE_ID PACKAGE_ID; - // begin_phapppub PHAPPAPI BOOLEAN @@ -28,12 +26,8 @@ PPH_STRING PhGetProcessPackageFullName( _In_ HANDLE ProcessHandle ); -PACKAGE_ID *PhPackageIdFromFullName( - _In_ PWSTR PackageFullName - ); - PPH_STRING PhGetPackagePath( - _In_ PACKAGE_ID *PackageId + _In_ PPH_STRING PackageFullName ); // begin_phapppub diff --git a/ProcessHacker/include/procprv.h b/ProcessHacker/include/procprv.h index c3d6b7dd7130..3e433d740952 100644 --- a/ProcessHacker/include/procprv.h +++ b/ProcessHacker/include/procprv.h @@ -311,13 +311,13 @@ typedef struct _PH_VERIFY_FILE_INFO *PPH_VERIFY_FILE_INFO; VERIFY_RESULT PhVerifyFileWithAdditionalCatalog( _In_ PPH_VERIFY_FILE_INFO Information, - _In_opt_ PWSTR PackageFullName, + _In_opt_ PPH_STRING PackageFullName, _Out_opt_ PPH_STRING *SignerName ); VERIFY_RESULT PhVerifyFileCached( _In_ PPH_STRING FileName, - _In_opt_ PWSTR PackageFullName, + _In_opt_ PPH_STRING PackageFullName, _Out_opt_ PPH_STRING *SignerName, _In_ BOOLEAN CachedOnly ); diff --git a/ProcessHacker/modprv.c b/ProcessHacker/modprv.c index 0a507b872a4f..7a39345db8aa 100644 --- a/ProcessHacker/modprv.c +++ b/ProcessHacker/modprv.c @@ -292,7 +292,7 @@ NTSTATUS PhpModuleQueryWorker( data->VerifyResult = PhVerifyFileCached( data->ModuleItem->FileName, - PhGetString(data->ModuleProvider->PackageFullName), + data->ModuleProvider->PackageFullName, &data->VerifySignerName, FALSE ); diff --git a/ProcessHacker/procprv.c b/ProcessHacker/procprv.c index e4d2bdb48893..296ba8fbdc6a 100644 --- a/ProcessHacker/procprv.c +++ b/ProcessHacker/procprv.c @@ -680,7 +680,7 @@ INT NTAPI PhpVerifyCacheCompareFunction( VERIFY_RESULT PhVerifyFileWithAdditionalCatalog( _In_ PPH_VERIFY_FILE_INFO Information, - _In_opt_ PWSTR PackageFullName, + _In_opt_ PPH_STRING PackageFullName, _Out_opt_ PPH_STRING *SignerName ) { @@ -693,18 +693,12 @@ VERIFY_RESULT PhVerifyFileWithAdditionalCatalog( if (PackageFullName) { - PACKAGE_ID *packageId; PPH_STRING packagePath; - if (packageId = PhPackageIdFromFullName(PackageFullName)) + if (packagePath = PhGetPackagePath(PackageFullName)) { - if (packagePath = PhGetPackagePath(packageId)) - { - additionalCatalogFileName = PhConcatStringRef2(&packagePath->sr, &codeIntegrityFileName); - PhDereferenceObject(packagePath); - } - - PhFree(packageId); + additionalCatalogFileName = PhConcatStringRef2(&packagePath->sr, &codeIntegrityFileName); + PhDereferenceObject(packagePath); } } @@ -751,7 +745,7 @@ VERIFY_RESULT PhVerifyFileWithAdditionalCatalog( */ VERIFY_RESULT PhVerifyFileCached( _In_ PPH_STRING FileName, - _In_opt_ PWSTR PackageFullName, + _In_opt_ PPH_STRING PackageFullName, _Out_opt_ PPH_STRING *SignerName, _In_ BOOLEAN CachedOnly ) @@ -1184,7 +1178,7 @@ VOID PhpProcessQueryStage2( Data->VerifyResult = PhVerifyFileCached( processItem->FileName, - PhGetString(packageFullName), + packageFullName, &Data->VerifySignerName, FALSE ); diff --git a/ProcessHacker/prpggen.c b/ProcessHacker/prpggen.c index 925398bfa7eb..aa061e46e478 100644 --- a/ProcessHacker/prpggen.c +++ b/ProcessHacker/prpggen.c @@ -613,7 +613,7 @@ INT_PTR CALLBACK PhpProcessGeneralDlgProc( info.hWnd = hwndDlg; PhVerifyFileWithAdditionalCatalog( &info, - PhGetString(processItem->PackageFullName), + processItem->PackageFullName, NULL ); } From 962fbd62ba644ad01aeda304956830626d94f9d8 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 5 Oct 2017 18:49:16 +1100 Subject: [PATCH 0454/2058] Update sdk --- ProcessHacker/include/sysinfop.h | 6 ------ phnt/include/ntexapi.h | 12 +++++++++--- phnt/include/phnt.h | 1 + 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/ProcessHacker/include/sysinfop.h b/ProcessHacker/include/sysinfop.h index 261c23151325..ccd8b02fd1df 100644 --- a/ProcessHacker/include/sysinfop.h +++ b/ProcessHacker/include/sysinfop.h @@ -233,12 +233,6 @@ PPH_STRING PhSipFormatSizeWithPrecision( // CPU section -typedef struct _SYSTEM_PROCESSOR_PERFORMANCE_HITCOUNT_WIN8 -{ - ULONG Hits; - UCHAR PercentFrequency; -} SYSTEM_PROCESSOR_PERFORMANCE_HITCOUNT_WIN8, *PSYSTEM_PROCESSOR_PERFORMANCE_HITCOUNT_WIN8; - BOOLEAN PhSipCpuSectionCallback( _In_ PPH_SYSINFO_SECTION Section, _In_ PH_SYSINFO_SECTION_MESSAGE Message, diff --git a/phnt/include/ntexapi.h b/phnt/include/ntexapi.h index 70e2310acc32..5a13354ad539 100644 --- a/phnt/include/ntexapi.h +++ b/phnt/include/ntexapi.h @@ -1194,7 +1194,6 @@ NtAllocateUuids( // rev // private -// source:http://www.microsoft.com/whdc/system/Sysinternals/MoreThan64proc.mspx typedef enum _SYSTEM_INFORMATION_CLASS { SystemBasicInformation, // q: SYSTEM_BASIC_INFORMATION @@ -2276,13 +2275,20 @@ typedef struct _SYSTEM_SYSTEM_DISK_INFORMATION UNICODE_STRING SystemDisk; } SYSTEM_SYSTEM_DISK_INFORMATION, *PSYSTEM_SYSTEM_DISK_INFORMATION; -// private +// private (Windows 8.1 and above) typedef struct _SYSTEM_PROCESSOR_PERFORMANCE_HITCOUNT { - ULONGLONG Hits; // ULONG in WIN8 + ULONGLONG Hits; UCHAR PercentFrequency; } SYSTEM_PROCESSOR_PERFORMANCE_HITCOUNT, *PSYSTEM_PROCESSOR_PERFORMANCE_HITCOUNT; +// private (Windows 7 and Windows 8) +typedef struct _SYSTEM_PROCESSOR_PERFORMANCE_HITCOUNT_WIN8 +{ + ULONG Hits; + UCHAR PercentFrequency; +} SYSTEM_PROCESSOR_PERFORMANCE_HITCOUNT_WIN8, *PSYSTEM_PROCESSOR_PERFORMANCE_HITCOUNT_WIN8; + // private typedef struct _SYSTEM_PROCESSOR_PERFORMANCE_STATE_DISTRIBUTION { diff --git a/phnt/include/phnt.h b/phnt/include/phnt.h index 42bf2a9d8007..924b09b6f2fc 100644 --- a/phnt/include/phnt.h +++ b/phnt/include/phnt.h @@ -35,6 +35,7 @@ #define PHNT_THRESHOLD2 101 #define PHNT_REDSTONE 102 #define PHNT_REDSTONE2 103 +#define PHNT_REDSTONE3 104 #ifndef PHNT_MODE #define PHNT_MODE PHNT_MODE_USER From cbd7281ad8f51a15fb785f12b681c2b173c6500a Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 6 Oct 2017 06:44:14 +1100 Subject: [PATCH 0455/2058] Fix format specifier --- ProcessHacker/thrdprv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ProcessHacker/thrdprv.c b/ProcessHacker/thrdprv.c index a1eb226728a6..42c41e2f78fd 100644 --- a/ProcessHacker/thrdprv.c +++ b/ProcessHacker/thrdprv.c @@ -743,7 +743,7 @@ PPH_STRING PhGetBasePriorityIncrementString( case THREAD_PRIORITY_ERROR_RETURN: return NULL; default: - return PhFormatString(L"%d", Increment); + return PhFormatString(L"%ld", Increment); } } From 7db125defb581af4bede5ca29cbee483a724b1cc Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 6 Oct 2017 06:54:20 +1100 Subject: [PATCH 0456/2058] Move DbgHelp code into appsup, Improve phsvc linking --- ProcessHacker/appsup.c | 40 +++++++++++++++++++++++++++++++ ProcessHacker/include/appsup.h | 7 ++++++ ProcessHacker/include/mainwnd.h | 4 ---- ProcessHacker/mainwnd.c | 42 +-------------------------------- ProcessHacker/phsvc/svcapi.c | 3 +-- 5 files changed, 49 insertions(+), 47 deletions(-) diff --git a/ProcessHacker/appsup.c b/ProcessHacker/appsup.c index d8a109c3d3d2..e5f004d5265f 100644 --- a/ProcessHacker/appsup.c +++ b/ProcessHacker/appsup.c @@ -969,6 +969,46 @@ VOID PhShellExecuteUserString( PhDereferenceObject(executeString); } +VOID PhLoadSymbolProviderDbgHelpFromPath( + _In_ PWSTR DbgHelpPath + ) +{ + HMODULE dbghelpModule; + + if (dbghelpModule = LoadLibrary(DbgHelpPath)) + { + PPH_STRING fullDbghelpPath; + ULONG indexOfFileName; + PH_STRINGREF dbghelpFolder; + PPH_STRING symsrvPath; + + fullDbghelpPath = PhGetDllFileName(dbghelpModule, &indexOfFileName); + + if (fullDbghelpPath) + { + if (indexOfFileName != 0) + { + static PH_STRINGREF symsrvString = PH_STRINGREF_INIT(L"\\symsrv.dll"); + + dbghelpFolder.Buffer = fullDbghelpPath->Buffer; + dbghelpFolder.Length = indexOfFileName * sizeof(WCHAR); + + symsrvPath = PhConcatStringRef2(&dbghelpFolder, &symsrvString); + LoadLibrary(symsrvPath->Buffer); + PhDereferenceObject(symsrvPath); + } + + PhDereferenceObject(fullDbghelpPath); + } + } + else + { + dbghelpModule = LoadLibrary(L"dbghelp.dll"); + } + + PhSymbolProviderCompleteInitialization(dbghelpModule); +} + VOID PhLoadSymbolProviderOptions( _Inout_ PPH_SYMBOL_PROVIDER SymbolProvider ) diff --git a/ProcessHacker/include/appsup.h b/ProcessHacker/include/appsup.h index 3ae868ceb48e..294d41140ab4 100644 --- a/ProcessHacker/include/appsup.h +++ b/ProcessHacker/include/appsup.h @@ -149,6 +149,13 @@ PhShellExecuteUserString( _In_opt_ PWSTR ErrorMessage ); +PHAPPAPI +VOID +NTAPI +PhLoadSymbolProviderDbgHelpFromPath( + _In_ PWSTR DbgHelpPath + ); + PHAPPAPI VOID NTAPI diff --git a/ProcessHacker/include/mainwnd.h b/ProcessHacker/include/mainwnd.h index de4d3b04f33a..f1d96ac8c202 100644 --- a/ProcessHacker/include/mainwnd.h +++ b/ProcessHacker/include/mainwnd.h @@ -207,10 +207,6 @@ BOOLEAN PhMainWndInitialization( _In_ INT ShowCommand ); -VOID PhLoadDbgHelpFromPath( - _In_ PWSTR DbgHelpPath - ); - VOID PhAddMiniProcessMenuItems( _Inout_ struct _PH_EMENU_ITEM *Menu, _In_ HANDLE ProcessId diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index 73b7be8fccd5..8d1e89befcd3 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -2286,46 +2286,6 @@ VOID PhMwpSaveWindowState( PhSetIntegerSetting(L"MainWindowState", SW_MAXIMIZE); } -VOID PhLoadDbgHelpFromPath( - _In_ PWSTR DbgHelpPath - ) -{ - HMODULE dbghelpModule; - - if (dbghelpModule = LoadLibrary(DbgHelpPath)) - { - PPH_STRING fullDbghelpPath; - ULONG indexOfFileName; - PH_STRINGREF dbghelpFolder; - PPH_STRING symsrvPath; - - fullDbghelpPath = PhGetDllFileName(dbghelpModule, &indexOfFileName); - - if (fullDbghelpPath) - { - if (indexOfFileName != 0) - { - static PH_STRINGREF symsrvString = PH_STRINGREF_INIT(L"\\symsrv.dll"); - - dbghelpFolder.Buffer = fullDbghelpPath->Buffer; - dbghelpFolder.Length = indexOfFileName * sizeof(WCHAR); - - symsrvPath = PhConcatStringRef2(&dbghelpFolder, &symsrvString); - LoadLibrary(symsrvPath->Buffer); - PhDereferenceObject(symsrvPath); - } - - PhDereferenceObject(fullDbghelpPath); - } - } - else - { - dbghelpModule = LoadLibrary(L"dbghelp.dll"); - } - - PhSymbolProviderCompleteInitialization(dbghelpModule); -} - VOID PhMwpSymInitHandler( _In_opt_ PVOID Parameter, _In_opt_ PVOID Context @@ -2334,7 +2294,7 @@ VOID PhMwpSymInitHandler( PPH_STRING dbghelpPath; dbghelpPath = PhGetStringSetting(L"DbgHelpPath"); - PhLoadDbgHelpFromPath(dbghelpPath->Buffer); + PhLoadSymbolProviderDbgHelpFromPath(dbghelpPath->Buffer); PhDereferenceObject(dbghelpPath); } diff --git a/ProcessHacker/phsvc/svcapi.c b/ProcessHacker/phsvc/svcapi.c index 89eee95d20cb..e9e614c84c91 100644 --- a/ProcessHacker/phsvc/svcapi.c +++ b/ProcessHacker/phsvc/svcapi.c @@ -31,7 +31,6 @@ #include #include -#include #include typedef struct _PHSVCP_CAPTURED_RUNAS_SERVICE_PARAMETERS @@ -1408,7 +1407,7 @@ NTSTATUS PhSvcApiLoadDbgHelp( if (NT_SUCCESS(status = PhSvcCaptureString(&Payload->u.LoadDbgHelp.i.DbgHelpPath, FALSE, &dbgHelpPath))) { PH_AUTO(dbgHelpPath); - PhLoadDbgHelpFromPath(dbgHelpPath->Buffer); + PhLoadSymbolProviderDbgHelpFromPath(dbgHelpPath->Buffer); alreadyLoaded = TRUE; } From b16c4521fbb5361d04e59a7ab211b534d01ca3cf Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 6 Oct 2017 06:54:59 +1100 Subject: [PATCH 0457/2058] Improve handle enumeration error fallback --- ProcessHacker/hndlprv.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ProcessHacker/hndlprv.c b/ProcessHacker/hndlprv.c index 4afd571c33c9..cd1dd54c34c9 100644 --- a/ProcessHacker/hndlprv.c +++ b/ProcessHacker/hndlprv.c @@ -306,7 +306,7 @@ NTSTATUS PhEnumHandlesGeneric( // * Otherwise, NtQuerySystemInformation with SystemHandleInformation // can be used. - if (KphIsConnected() && KphIsVerified()) + if (KphIsConnected()) { PKPH_PROCESS_HANDLE_INFORMATION handles; PSYSTEM_HANDLE_INFORMATION_EX convertedHandles; @@ -316,7 +316,7 @@ NTSTATUS PhEnumHandlesGeneric( // this only enumerates handles for a single process and saves a lot of processing. if (!NT_SUCCESS(status = KphEnumerateProcessHandles2(ProcessHandle, &handles))) - return status; + goto FAILED; convertedHandles = PhAllocate( FIELD_OFFSET(SYSTEM_HANDLE_INFORMATION_EX, Handles) + @@ -344,7 +344,7 @@ NTSTATUS PhEnumHandlesGeneric( else { PSYSTEM_HANDLE_INFORMATION_EX handles; - +FAILED: if (!NT_SUCCESS(status = PhEnumHandlesEx(&handles))) return status; From ea6f64dd030012621cb8d726e53493703650eb80 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 6 Oct 2017 06:58:21 +1100 Subject: [PATCH 0458/2058] Improve KPH error messsages --- ProcessHacker/main.c | 54 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 51 insertions(+), 3 deletions(-) diff --git a/ProcessHacker/main.c b/ProcessHacker/main.c index ca0de0fe219f..b0ed3931001f 100644 --- a/ProcessHacker/main.c +++ b/ProcessHacker/main.c @@ -616,6 +616,47 @@ NTSTATUS PhpReadSignature( } } +VOID PhpShowKphError( + _In_ PWSTR Message, + _In_opt_ NTSTATUS Status + ) +{ + if (Status == STATUS_NO_SUCH_FILE) + { + PhShowError2( + NULL, + Message, + L"You will be unable to use more advanced features, view details about system processes or terminate malicious software." + ); + } + else + { + PPH_STRING errorMessage; + PPH_STRING statusMessage; + + if (errorMessage = PhGetStatusMessage(Status, 0)) + { + statusMessage = PhConcatStrings( + 3, + errorMessage->Buffer, + L"\r\n\r\n", + L"You will be unable to use more advanced features, view details about system processes or terminate malicious software." + ); + PhShowError2(NULL, Message, statusMessage->Buffer); + PhDereferenceObject(statusMessage); + PhDereferenceObject(errorMessage); + } + else + { + PhShowError2( + NULL, + Message, + L"You will be unable to use more advanced features, view details about system processes or terminate malicious software." + ); + } + } +} + VOID PhInitializeKph( VOID ) @@ -633,6 +674,13 @@ VOID PhInitializeKph( kprocesshackerFileName = PhConcatStringRef2(&PhApplicationDirectory->sr, &kprocesshacker); processhackerSigFileName = PhConcatStringRef2(&PhApplicationDirectory->sr, &processhackerSig); + if (!RtlDoesFileExists_U(kprocesshackerFileName->Buffer)) + { + if (PhGetIntegerSetting(L"EnableKphWarnings")) + PhpShowKphError(L"The Process Hacker kernel driver 'kprocesshacker.sys' was not found in the application directory.", STATUS_NO_SUCH_FILE); + return; + } + parameters.SecurityLevel = KphSecuritySignatureAndPrivilegeCheck; parameters.CreateDynamicConfiguration = TRUE; @@ -658,7 +706,7 @@ VOID PhInitializeKph( if (!NT_SUCCESS(status)) { if (PhGetIntegerSetting(L"EnableKphWarnings")) - PhShowStatus(NULL, L"Unable to verify the kernel driver signature.", status, 0); + PhpShowKphError(L"Unable to verify the kernel driver signature.", status); } PhFree(signature); @@ -666,13 +714,13 @@ VOID PhInitializeKph( else { if (PhGetIntegerSetting(L"EnableKphWarnings")) - PhShowStatus(NULL, L"Unable to load the kernel driver signature.", status, 0); + PhpShowKphError(L"Unable to load the kernel driver signature.", status); } } else { if (PhGetIntegerSetting(L"EnableKphWarnings") && PhGetOwnTokenAttributes().Elevated) - PhShowStatus(NULL, L"Unable to load the kernel driver.", status, 0); + PhpShowKphError(L"Unable to load the kernel driver.", status); } PhDereferenceObject(kprocesshackerFileName); From 5d2e02b48ae31d229b35e8f672a79a67cf7dafd2 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 6 Oct 2017 07:23:24 +1100 Subject: [PATCH 0459/2058] Move DbgHelp code into appsup, Improve mainwnd linking --- ProcessHacker/appsup.c | 43 ++++++++++++++++++++++++++++++ ProcessHacker/include/appsup.h | 7 +++++ ProcessHacker/include/mainwndp.h | 4 --- ProcessHacker/mainwnd.c | 45 +------------------------------- 4 files changed, 51 insertions(+), 48 deletions(-) diff --git a/ProcessHacker/appsup.c b/ProcessHacker/appsup.c index e5f004d5265f..3fe2ad206c8e 100644 --- a/ProcessHacker/appsup.c +++ b/ProcessHacker/appsup.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -969,6 +970,48 @@ VOID PhShellExecuteUserString( PhDereferenceObject(executeString); } +PPH_STRING PhFindDbghelpPath( + VOID + ) +{ + static struct + { + ULONG Folder; + PWSTR AppendPath; + } locations[] = + { +#ifdef _WIN64 + { CSIDL_PROGRAM_FILESX86, L"\\Windows Kits\\10\\Debuggers\\x64\\dbghelp.dll" }, + { CSIDL_PROGRAM_FILESX86, L"\\Windows Kits\\8.1\\Debuggers\\x64\\dbghelp.dll" }, + { CSIDL_PROGRAM_FILESX86, L"\\Windows Kits\\8.0\\Debuggers\\x64\\dbghelp.dll" }, + { CSIDL_PROGRAM_FILES, L"\\Debugging Tools for Windows (x64)\\dbghelp.dll" } +#else + { CSIDL_PROGRAM_FILES, L"\\Windows Kits\\10\\Debuggers\\x86\\dbghelp.dll" }, + { CSIDL_PROGRAM_FILES, L"\\Windows Kits\\8.1\\Debuggers\\x86\\dbghelp.dll" }, + { CSIDL_PROGRAM_FILES, L"\\Windows Kits\\8.0\\Debuggers\\x86\\dbghelp.dll" }, + { CSIDL_PROGRAM_FILES, L"\\Debugging Tools for Windows (x86)\\dbghelp.dll" } +#endif + }; + + PPH_STRING path; + ULONG i; + + for (i = 0; i < sizeof(locations) / sizeof(locations[0]); i++) + { + path = PhGetKnownLocation(locations[i].Folder, locations[i].AppendPath); + + if (path) + { + if (RtlDoesFileExists_U(path->Buffer)) + return path; + + PhDereferenceObject(path); + } + } + + return NULL; +} + VOID PhLoadSymbolProviderDbgHelpFromPath( _In_ PWSTR DbgHelpPath ) diff --git a/ProcessHacker/include/appsup.h b/ProcessHacker/include/appsup.h index 294d41140ab4..d82339461152 100644 --- a/ProcessHacker/include/appsup.h +++ b/ProcessHacker/include/appsup.h @@ -149,6 +149,13 @@ PhShellExecuteUserString( _In_opt_ PWSTR ErrorMessage ); +PHAPPAPI +PPH_STRING +NTAPI +PhFindDbghelpPath( + VOID + ); + PHAPPAPI VOID NTAPI diff --git a/ProcessHacker/include/mainwndp.h b/ProcessHacker/include/mainwndp.h index 70f85d4f1569..29fea32a3fc7 100644 --- a/ProcessHacker/include/mainwndp.h +++ b/ProcessHacker/include/mainwndp.h @@ -53,10 +53,6 @@ NTSTATUS PhMwpDelayedLoadFunction( _In_ PVOID Parameter ); -PPH_STRING PhMwpFindDbghelpPath( - VOID - ); - // Event handlers VOID PhMwpOnDestroy( diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index 8d1e89befcd3..fa80643d7f64 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -24,7 +24,6 @@ #include #include -#include #include #include @@ -107,7 +106,7 @@ BOOLEAN PhMainWndInitialization( PPH_STRING autoDbghelpPath; // Try to set up the dbghelp path automatically if this is the first run. - if (autoDbghelpPath = PH_AUTO(PhMwpFindDbghelpPath())) + if (autoDbghelpPath = PH_AUTO(PhFindDbghelpPath())) PhSetStringSetting2(L"DbgHelpPath", &autoDbghelpPath->sr); PhSetIntegerSetting(L"FirstRun", FALSE); @@ -494,48 +493,6 @@ NTSTATUS PhMwpDelayedLoadFunction( return STATUS_SUCCESS; } -PPH_STRING PhMwpFindDbghelpPath( - VOID - ) -{ - static struct - { - ULONG Folder; - PWSTR AppendPath; - } locations[] = - { -#ifdef _WIN64 - { CSIDL_PROGRAM_FILESX86, L"\\Windows Kits\\10\\Debuggers\\x64\\dbghelp.dll" }, - { CSIDL_PROGRAM_FILESX86, L"\\Windows Kits\\8.1\\Debuggers\\x64\\dbghelp.dll" }, - { CSIDL_PROGRAM_FILESX86, L"\\Windows Kits\\8.0\\Debuggers\\x64\\dbghelp.dll" }, - { CSIDL_PROGRAM_FILES, L"\\Debugging Tools for Windows (x64)\\dbghelp.dll" } -#else - { CSIDL_PROGRAM_FILES, L"\\Windows Kits\\10\\Debuggers\\x86\\dbghelp.dll" }, - { CSIDL_PROGRAM_FILES, L"\\Windows Kits\\8.1\\Debuggers\\x86\\dbghelp.dll" }, - { CSIDL_PROGRAM_FILES, L"\\Windows Kits\\8.0\\Debuggers\\x86\\dbghelp.dll" }, - { CSIDL_PROGRAM_FILES, L"\\Debugging Tools for Windows (x86)\\dbghelp.dll" } -#endif - }; - - PPH_STRING path; - ULONG i; - - for (i = 0; i < sizeof(locations) / sizeof(locations[0]); i++) - { - path = PhGetKnownLocation(locations[i].Folder, locations[i].AppendPath); - - if (path) - { - if (RtlDoesFileExists_U(path->Buffer)) - return path; - - PhDereferenceObject(path); - } - } - - return NULL; -} - VOID PhMwpOnDestroy( VOID ) From 6110e0b758ec44cac461fda8e65aa12aa75801a4 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 6 Oct 2017 07:23:56 +1100 Subject: [PATCH 0460/2058] Enable KPH for Win10 insider previews --- ProcessHacker/main.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/ProcessHacker/main.c b/ProcessHacker/main.c index b0ed3931001f..2f42307995e5 100644 --- a/ProcessHacker/main.c +++ b/ProcessHacker/main.c @@ -668,9 +668,6 @@ VOID PhInitializeKph( PPH_STRING processhackerSigFileName; KPH_PARAMETERS parameters; - if (WindowsVersion == WINDOWS_NEW) - return; - kprocesshackerFileName = PhConcatStringRef2(&PhApplicationDirectory->sr, &kprocesshacker); processhackerSigFileName = PhConcatStringRef2(&PhApplicationDirectory->sr, &processhackerSig); From 7f806cb2737936d50e17434d2c55f8824f26057c Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 6 Oct 2017 08:49:52 +1100 Subject: [PATCH 0461/2058] partial revert 'Fix AppId column for store apps' --- ProcessHacker/proctree.c | 119 +++++++++++++++++++-------------------- 1 file changed, 59 insertions(+), 60 deletions(-) diff --git a/ProcessHacker/proctree.c b/ProcessHacker/proctree.c index 3e6e6d445f9b..22bf759f5d1c 100644 --- a/ProcessHacker/proctree.c +++ b/ProcessHacker/proctree.c @@ -608,7 +608,7 @@ VOID PhTickProcessNodes( // The name and PID never change, so we don't invalidate that. memset(&node->TextCache[2], 0, sizeof(PH_STRINGREF) * (PHPRTLC_MAXIMUM - 2)); - node->ValidMask &= PHPN_OSCONTEXT | PHPN_IMAGE | PHPN_DPIAWARENESS | PHPN_APPID; // Items that always remain valid + node->ValidMask &= PHPN_OSCONTEXT | PHPN_IMAGE | PHPN_DPIAWARENESS; // Items that always remain valid // Invalidate graph buffers. node->CpuGraphBuffers.Valid = FALSE; @@ -1093,66 +1093,65 @@ static VOID PhpUpdateProcessNodeAppId( if (ProcessNode->ProcessItem->QueryHandle) { - if (WindowsVersion >= WINDOWS_8 && ProcessNode->ProcessItem->IsImmersive) - { - HANDLE tokenHandle; - PTOKEN_SECURITY_ATTRIBUTES_INFORMATION info; - - if (NT_SUCCESS(PhOpenProcessToken( - ProcessNode->ProcessItem->QueryHandle, - TOKEN_QUERY, - &tokenHandle - ))) - { - // rev from GetApplicationUserModelId - if (NT_SUCCESS(PhQueryTokenVariableSize(tokenHandle, TokenSecurityAttributes, &info))) - { - for (ULONG i = 0; i < info->AttributeCount; i++) - { - static UNICODE_STRING attributeNameUs = RTL_CONSTANT_STRING(L"WIN://SYSAPPID"); - PTOKEN_SECURITY_ATTRIBUTE_V1 attribute = &info->Attribute.pAttributeV1[i]; - - if (RtlEqualUnicodeString(&attribute->Name, &attributeNameUs, FALSE)) - { - if (attribute->ValueType == TOKEN_SECURITY_ATTRIBUTE_TYPE_STRING) - { - PPH_STRING attributeValue1; - PPH_STRING attributeValue2; - - attributeValue1 = PH_AUTO(PhCreateStringFromUnicodeString(&attribute->Values.pString[1])); - attributeValue2 = PH_AUTO(PhCreateStringFromUnicodeString(&attribute->Values.pString[2])); - - ProcessNode->AppIdText = PhConcatStrings( - 3, - attributeValue2->Buffer, - L"!", - attributeValue1->Buffer - ); - - break; - } - } - } - - PhFree(info); - } - - NtClose(tokenHandle); - } - } - else + //if (WindowsVersion >= WINDOWS_8 && ProcessNode->ProcessItem->IsImmersive) + //{ + // HANDLE tokenHandle; + // PTOKEN_SECURITY_ATTRIBUTES_INFORMATION info; + // + // if (NT_SUCCESS(PhOpenProcessToken( + // ProcessNode->ProcessItem->QueryHandle, + // TOKEN_QUERY, + // &tokenHandle + // ))) + // { + // // rev from GetApplicationUserModelId + // if (NT_SUCCESS(PhQueryTokenVariableSize(tokenHandle, TokenSecurityAttributes, &info))) + // { + // for (ULONG i = 0; i < info->AttributeCount; i++) + // { + // static UNICODE_STRING attributeNameUs = RTL_CONSTANT_STRING(L"WIN://SYSAPPID"); + // PTOKEN_SECURITY_ATTRIBUTE_V1 attribute = &info->Attribute.pAttributeV1[i]; + // + // if (RtlEqualUnicodeString(&attribute->Name, &attributeNameUs, FALSE)) + // { + // if (attribute->ValueType == TOKEN_SECURITY_ATTRIBUTE_TYPE_STRING) + // { + // PPH_STRING attributeValue1; + // PPH_STRING attributeValue2; + // + // attributeValue1 = PH_AUTO(PhCreateStringFromUnicodeString(&attribute->Values.pString[1])); + // attributeValue2 = PH_AUTO(PhCreateStringFromUnicodeString(&attribute->Values.pString[2])); + // + // ProcessNode->AppIdText = PhConcatStrings( + // 3, + // attributeValue2->Buffer, + // L"!", + // attributeValue1->Buffer + // ); + // + // break; + // } + // } + // } + // + // PhFree(info); + // } + // + // NtClose(tokenHandle); + // } + //} + //else + + if (NT_SUCCESS(PhGetProcessWindowTitle( + ProcessNode->ProcessItem->QueryHandle, + &windowFlags, + &windowTitle + ))) { - if (NT_SUCCESS(PhGetProcessWindowTitle( - ProcessNode->ProcessItem->QueryHandle, - &windowFlags, - &windowTitle - ))) - { - if (windowFlags & STARTF_TITLEISAPPID) - ProcessNode->AppIdText = windowTitle; - else - PhDereferenceObject(windowTitle); - } + if (windowFlags & STARTF_TITLEISAPPID) + ProcessNode->AppIdText = windowTitle; + else + PhDereferenceObject(windowTitle); } } From ea538b4241f67955ca35ea88031c24399931f0ce Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 6 Oct 2017 09:16:08 +1100 Subject: [PATCH 0462/2058] Fix sdk conflicts with DDK --- phnt/include/ntexapi.h | 12 ++---------- phnt/include/ntmmapi.h | 26 +++++++++++--------------- 2 files changed, 13 insertions(+), 25 deletions(-) diff --git a/phnt/include/ntexapi.h b/phnt/include/ntexapi.h index 5a13354ad539..682d10db59f7 100644 --- a/phnt/include/ntexapi.h +++ b/phnt/include/ntexapi.h @@ -2151,6 +2151,7 @@ typedef struct _SYSTEM_SESSION_MAPPED_VIEW_INFORMATION SIZE_T NumberOfBytesAvailableContiguous; } SYSTEM_SESSION_MAPPED_VIEW_INFORMATION, *PSYSTEM_SESSION_MAPPED_VIEW_INFORMATION; +#if (PHNT_MODE != PHNT_MODE_KERNEL) // private typedef enum _SYSTEM_FIRMWARE_TABLE_ACTION { @@ -2168,6 +2169,7 @@ typedef struct _SYSTEM_FIRMWARE_TABLE_INFORMATION ULONG TableBufferLength; UCHAR TableBuffer[1]; } SYSTEM_FIRMWARE_TABLE_INFORMATION, *PSYSTEM_FIRMWARE_TABLE_INFORMATION; +#endif // private typedef struct _SYSTEM_MEMORY_LIST_INFORMATION @@ -2223,16 +2225,6 @@ typedef struct _SYSTEM_PROCESS_ID_INFORMATION UNICODE_STRING ImageName; } SYSTEM_PROCESS_ID_INFORMATION, *PSYSTEM_PROCESS_ID_INFORMATION; -#if (PHNT_MODE == PHNT_MODE_KERNEL) -typedef enum _FIRMWARE_TYPE -{ - FirmwareTypeUnknown, - FirmwareTypeBios, - FirmwareTypeUefi, - FirmwareTypeMax -} FIRMWARE_TYPE, *PFIRMWARE_TYPE; -#endif - // private typedef struct _SYSTEM_BOOT_ENVIRONMENT_INFORMATION { diff --git a/phnt/include/ntmmapi.h b/phnt/include/ntmmapi.h index 9f282024dfe5..9da77a7a4e87 100644 --- a/phnt/include/ntmmapi.h +++ b/phnt/include/ntmmapi.h @@ -24,7 +24,7 @@ #define PAGE_ENCLAVE_UNVALIDATED 0x20000000 // Region and section constants - +#if (PHNT_MODE != PHNT_MODE_KERNEL) #define MEM_COMMIT 0x1000 #define MEM_RESERVE 0x2000 #define MEM_DECOMMIT 0x4000 @@ -34,19 +34,26 @@ #define MEM_MAPPED 0x40000 #define MEM_RESET 0x80000 #define MEM_TOP_DOWN 0x100000 +#endif #define MEM_WRITE_WATCH 0x200000 #define MEM_PHYSICAL 0x400000 #define MEM_ROTATE 0x800000 #define MEM_DIFFERENT_IMAGE_BASE_OK 0x800000 +#if (PHNT_MODE != PHNT_MODE_KERNEL) #define MEM_RESET_UNDO 0x1000000 +#endif #define MEM_LARGE_PAGES 0x20000000 #define MEM_4MB_PAGES 0x80000000 +#if (PHNT_MODE != PHNT_MODE_KERNEL) #define SEC_FILE 0x800000 +#endif #define SEC_IMAGE 0x1000000 #define SEC_PROTECTED_IMAGE 0x2000000 +#if (PHNT_MODE != PHNT_MODE_KERNEL) #define SEC_RESERVE 0x4000000 #define SEC_COMMIT 0x8000000 +#endif #define SEC_NOCACHE 0x10000000 #define SEC_WRITECOMBINE 0x40000000 #define SEC_LARGE_PAGES 0x80000000 @@ -55,6 +62,7 @@ #endif +#if (PHNT_MODE != PHNT_MODE_KERNEL) // private typedef enum _MEMORY_INFORMATION_CLASS { @@ -70,19 +78,6 @@ typedef enum _MEMORY_INFORMATION_CLASS MemoryEnclaveImageInformation, // since REDSTONE3 MemoryBasicInformationCapped } MEMORY_INFORMATION_CLASS; - -#if (PHNT_MODE == PHNT_MODE_KERNEL) - -typedef struct _MEMORY_BASIC_INFORMATION -{ - PVOID BaseAddress; - PVOID AllocationBase; - ULONG AllocationProtect; - SIZE_T RegionSize; - ULONG State; - ULONG Protect; - ULONG Type; -} MEMORY_BASIC_INFORMATION, *PMEMORY_BASIC_INFORMATION; #endif typedef struct _MEMORY_WORKING_SET_BLOCK @@ -474,6 +469,7 @@ NtQueryVirtualMemory( // begin_private +#if (PHNT_MODE != PHNT_MODE_KERNEL) typedef enum _VIRTUAL_MEMORY_INFORMATION_CLASS { VmPrefetchInformation, @@ -486,7 +482,7 @@ typedef struct _MEMORY_RANGE_ENTRY PVOID VirtualAddress; SIZE_T NumberOfBytes; } MEMORY_RANGE_ENTRY, *PMEMORY_RANGE_ENTRY; - +#endif // end_private #if (PHNT_MODE != PHNT_MODE_KERNEL) From 8d475729fcf9f7f6f664eb643ec03f0cf00a2aec Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 6 Oct 2017 12:46:50 +1100 Subject: [PATCH 0463/2058] Fix build error, Fix DDK conflicts --- phnt/include/ntmmapi.h | 12 ++++++++++++ phnt/include/ntzwapi.h | 10 ++++++++++ 2 files changed, 22 insertions(+) diff --git a/phnt/include/ntmmapi.h b/phnt/include/ntmmapi.h index 9da77a7a4e87..8446e6f5568d 100644 --- a/phnt/include/ntmmapi.h +++ b/phnt/include/ntmmapi.h @@ -78,6 +78,18 @@ typedef enum _MEMORY_INFORMATION_CLASS MemoryEnclaveImageInformation, // since REDSTONE3 MemoryBasicInformationCapped } MEMORY_INFORMATION_CLASS; +#else +#define MemoryBasicInformation 0x0 +#define MemoryWorkingSetInformation 0x1 +#define MemoryMappedFilenameInformation 0x2 +#define MemoryRegionInformation 0x3 +#define MemoryWorkingSetExInformation 0x4 +#define MemorySharedCommitInformation 0x5 +#define MemoryImageInformation 0x6 +#define MemoryRegionInformationEx 0x7 +#define MemoryPrivilegedBasicInformation 0x8 +#define MemoryEnclaveImageInformation 0x9 +#define MemoryBasicInformationCapped 0xA #endif typedef struct _MEMORY_WORKING_SET_BLOCK diff --git a/phnt/include/ntzwapi.h b/phnt/include/ntzwapi.h index d8c445aba8ae..92def73473ca 100644 --- a/phnt/include/ntzwapi.h +++ b/phnt/include/ntzwapi.h @@ -1537,6 +1537,16 @@ ZwExtendSection( _Inout_ PLARGE_INTEGER NewSectionSize ); +#ifndef FILTER_BOOT_OPTION_OPERATION +typedef enum _FILTER_BOOT_OPTION_OPERATION +{ + FilterBootOptionOperationOpenSystemStore, + FilterBootOptionOperationSetElement, + FilterBootOptionOperationDeleteElement, + FilterBootOptionOperationMax +} FILTER_BOOT_OPTION_OPERATION; +#endif + NTSYSCALLAPI NTSTATUS NTAPI From 00d2e6b8f2c053e8ae8a2aa6b95fa392d3406124 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 6 Oct 2017 12:51:25 +1100 Subject: [PATCH 0464/2058] Remove duplicate SDK definition --- phnt/include/ntzwapi.h | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/phnt/include/ntzwapi.h b/phnt/include/ntzwapi.h index 92def73473ca..48eb7f841507 100644 --- a/phnt/include/ntzwapi.h +++ b/phnt/include/ntzwapi.h @@ -1537,27 +1537,6 @@ ZwExtendSection( _Inout_ PLARGE_INTEGER NewSectionSize ); -#ifndef FILTER_BOOT_OPTION_OPERATION -typedef enum _FILTER_BOOT_OPTION_OPERATION -{ - FilterBootOptionOperationOpenSystemStore, - FilterBootOptionOperationSetElement, - FilterBootOptionOperationDeleteElement, - FilterBootOptionOperationMax -} FILTER_BOOT_OPTION_OPERATION; -#endif - -NTSYSCALLAPI -NTSTATUS -NTAPI -ZwFilterBootOption( - _In_ FILTER_BOOT_OPTION_OPERATION FilterOperation, - _In_ ULONG ObjectType, - _In_ ULONG ElementType, - _In_reads_bytes_opt_(DataSize) PVOID Data, - _In_ ULONG DataSize - ); - NTSYSCALLAPI NTSTATUS NTAPI From 5961b14364b926a647a0e8bd82509caacaa5a3ac Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 6 Oct 2017 13:59:34 +1100 Subject: [PATCH 0465/2058] ExtendedServices: Remove unused options tab --- .../ExtendedServices/ExtendedServices.vcxproj | 1 - .../ExtendedServices.vcxproj.filters | 3 -- plugins/ExtendedServices/extsrv.h | 9 ---- plugins/ExtendedServices/main.c | 46 ++---------------- plugins/ExtendedServices/options.c | 47 ------------------- 5 files changed, 4 insertions(+), 102 deletions(-) delete mode 100644 plugins/ExtendedServices/options.c diff --git a/plugins/ExtendedServices/ExtendedServices.vcxproj b/plugins/ExtendedServices/ExtendedServices.vcxproj index 55fd13d45770..f257f184c66c 100644 --- a/plugins/ExtendedServices/ExtendedServices.vcxproj +++ b/plugins/ExtendedServices/ExtendedServices.vcxproj @@ -54,7 +54,6 @@ - diff --git a/plugins/ExtendedServices/ExtendedServices.vcxproj.filters b/plugins/ExtendedServices/ExtendedServices.vcxproj.filters index 5b0693c97f97..836add93a586 100644 --- a/plugins/ExtendedServices/ExtendedServices.vcxproj.filters +++ b/plugins/ExtendedServices/ExtendedServices.vcxproj.filters @@ -27,9 +27,6 @@ Source Files - - Source Files - Source Files diff --git a/plugins/ExtendedServices/extsrv.h b/plugins/ExtendedServices/extsrv.h index 6459073e14c5..45ee3d50f048 100644 --- a/plugins/ExtendedServices/extsrv.h +++ b/plugins/ExtendedServices/extsrv.h @@ -38,15 +38,6 @@ INT_PTR CALLBACK EspServiceDependentsDlgProc( _In_ LPARAM lParam ); -// options - -INT_PTR CALLBACK OptionsDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - // other typedef NTSTATUS (NTAPI *_RtlCreateServiceSid)( diff --git a/plugins/ExtendedServices/main.c b/plugins/ExtendedServices/main.c index 401b27a1629a..a84cdc669ae4 100644 --- a/plugins/ExtendedServices/main.c +++ b/plugins/ExtendedServices/main.c @@ -23,36 +23,10 @@ #include "extsrv.h" PPH_PLUGIN PluginInstance; -static PH_CALLBACK_REGISTRATION PluginLoadCallbackRegistration; -static PH_CALLBACK_REGISTRATION PluginShowOptionsCallbackRegistration; -static PH_CALLBACK_REGISTRATION PluginMenuItemCallbackRegistration; -static PH_CALLBACK_REGISTRATION ProcessMenuInitializingCallbackRegistration; -static PH_CALLBACK_REGISTRATION ServicePropertiesInitializingCallbackRegistration; -static PH_CALLBACK_REGISTRATION ServiceMenuInitializingCallbackRegistration; - -VOID NTAPI LoadCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - // Nothing -} - -VOID NTAPI ShowOptionsCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - PPH_PLUGIN_OPTIONS_POINTERS optionsEntry = (PPH_PLUGIN_OPTIONS_POINTERS)Parameter; - - optionsEntry->CreateSection( - L"ExtendedServices", - PluginInstance->DllBase, - MAKEINTRESOURCE(IDD_OPTIONS), - OptionsDlgProc, - NULL - ); -} +PH_CALLBACK_REGISTRATION PluginMenuItemCallbackRegistration; +PH_CALLBACK_REGISTRATION ProcessMenuInitializingCallbackRegistration; +PH_CALLBACK_REGISTRATION ServicePropertiesInitializingCallbackRegistration; +PH_CALLBACK_REGISTRATION ServiceMenuInitializingCallbackRegistration; VOID NTAPI MenuItemCallback( _In_opt_ PVOID Parameter, @@ -441,18 +415,6 @@ LOGICAL DllMain( info->Description = L"Extends service management capabilities."; info->Url = L"https://wj32.org/processhacker/forums/viewtopic.php?t=1113"; - PhRegisterCallback( - PhGetPluginCallback(PluginInstance, PluginCallbackLoad), - LoadCallback, - NULL, - &PluginLoadCallbackRegistration - ); - PhRegisterCallback( - PhGetGeneralCallback(GeneralCallbackOptionsWindowInitializing), - ShowOptionsCallback, - NULL, - &PluginShowOptionsCallbackRegistration - ); PhRegisterCallback( PhGetPluginCallback(PluginInstance, PluginCallbackMenuItem), MenuItemCallback, diff --git a/plugins/ExtendedServices/options.c b/plugins/ExtendedServices/options.c deleted file mode 100644 index c9bf6e7027cd..000000000000 --- a/plugins/ExtendedServices/options.c +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Process Hacker Extended Services - - * options dialog - * - * Copyright (C) 2011 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include "extsrv.h" - -INT_PTR CALLBACK OptionsDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - switch (uMsg) - { - case WM_INITDIALOG: - { - Button_SetCheck(GetDlgItem(hwndDlg, IDC_ENABLESERVICESMENU), PhGetIntegerSetting(SETTING_NAME_ENABLE_SERVICES_MENU) ? BST_CHECKED : BST_UNCHECKED); - } - break; - case WM_DESTROY: - { - PhSetIntegerSetting(SETTING_NAME_ENABLE_SERVICES_MENU, Button_GetCheck(GetDlgItem(hwndDlg, IDC_ENABLESERVICESMENU)) == BST_CHECKED); - } - break; - } - - return FALSE; -} From defaac11ba612711209abcd5bc4ba14e3abb9745 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 6 Oct 2017 14:07:16 +1100 Subject: [PATCH 0466/2058] Update gitignore paths for KPH --- .gitignore | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index 53afad1c8da7..346a563a6704 100644 --- a/.gitignore +++ b/.gitignore @@ -78,11 +78,12 @@ build/output/ plugins-extra/ sdk/ -KProcessHacker/*.log -KProcessHacker/*.err -KProcessHacker/*.wrn -KProcessHacker/*/objchk_* -KProcessHacker/*/objfre_* +!KProcessHacker/bin/ +KProcessHacker/bin/Debug32/ +KProcessHacker/bin/Debug64/ +KProcessHacker/bin/Release32/ +KProcessHacker/bin/Release64/ +KProcessHacker/bin/* !plugins/SamplePlugin/bin/ plugins/SamplePlugin/bin/Debug32/ From 10bc7c724f43e823634c0d8745284daa79ef17b0 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 6 Oct 2017 14:12:50 +1100 Subject: [PATCH 0467/2058] Update KPH for VS17 --- KProcessHacker/KProcessHacker.sln | 35 ++ KProcessHacker/KProcessHacker.vcxproj | 112 ++++-- KProcessHacker/KProcessHacker.vcxproj.filters | 6 + KProcessHacker/bin/amd64/kprocesshacker.pdb | Bin 314368 -> 0 bytes KProcessHacker/bin/amd64/kprocesshacker.sys | Bin 27648 -> 0 bytes KProcessHacker/bin/i386/kprocesshacker.pdb | Bin 363520 -> 0 bytes KProcessHacker/bin/i386/kprocesshacker.sys | Bin 24064 -> 0 bytes KProcessHacker/clean/makefile | 1 - KProcessHacker/clean/sources | 7 - KProcessHacker/devctrl.c | 4 +- KProcessHacker/dirs | 1 - KProcessHacker/dyndata.c | 14 +- KProcessHacker/dynimp.c | 2 +- KProcessHacker/include/dyndata.h | 2 +- KProcessHacker/include/kph.h | 338 +++++++++--------- KProcessHacker/include/ntfill.h | 220 ++++++------ KProcessHacker/main.c | 40 ++- KProcessHacker/object.c | 100 +++--- KProcessHacker/process.c | 168 ++++----- KProcessHacker/qrydrv.c | 28 +- KProcessHacker/sign.cmd | 7 - KProcessHacker/sources.inc | 28 -- KProcessHacker/thread.c | 102 +++--- KProcessHacker/util.c | 18 +- KProcessHacker/verify.c | 48 +-- KProcessHacker/vm.c | 42 +-- 26 files changed, 670 insertions(+), 653 deletions(-) create mode 100644 KProcessHacker/KProcessHacker.sln delete mode 100644 KProcessHacker/bin/amd64/kprocesshacker.pdb delete mode 100644 KProcessHacker/bin/amd64/kprocesshacker.sys delete mode 100644 KProcessHacker/bin/i386/kprocesshacker.pdb delete mode 100644 KProcessHacker/bin/i386/kprocesshacker.sys delete mode 100644 KProcessHacker/clean/makefile delete mode 100644 KProcessHacker/clean/sources delete mode 100644 KProcessHacker/dirs delete mode 100644 KProcessHacker/sign.cmd delete mode 100644 KProcessHacker/sources.inc diff --git a/KProcessHacker/KProcessHacker.sln b/KProcessHacker/KProcessHacker.sln new file mode 100644 index 000000000000..f10b7a09a817 --- /dev/null +++ b/KProcessHacker/KProcessHacker.sln @@ -0,0 +1,35 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.26730.16 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "KProcessHacker", "KProcessHacker.vcxproj", "{F4853009-C5D2-4A25-BE4D-BB0D9F84E2FF}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {F4853009-C5D2-4A25-BE4D-BB0D9F84E2FF}.Debug|Win32.ActiveCfg = Debug|Win32 + {F4853009-C5D2-4A25-BE4D-BB0D9F84E2FF}.Debug|Win32.Build.0 = Debug|Win32 + {F4853009-C5D2-4A25-BE4D-BB0D9F84E2FF}.Debug|Win32.Deploy.0 = Debug|Win32 + {F4853009-C5D2-4A25-BE4D-BB0D9F84E2FF}.Debug|x64.ActiveCfg = Debug|x64 + {F4853009-C5D2-4A25-BE4D-BB0D9F84E2FF}.Debug|x64.Build.0 = Debug|x64 + {F4853009-C5D2-4A25-BE4D-BB0D9F84E2FF}.Debug|x64.Deploy.0 = Debug|x64 + {F4853009-C5D2-4A25-BE4D-BB0D9F84E2FF}.Release|Win32.ActiveCfg = Release|Win32 + {F4853009-C5D2-4A25-BE4D-BB0D9F84E2FF}.Release|Win32.Build.0 = Release|Win32 + {F4853009-C5D2-4A25-BE4D-BB0D9F84E2FF}.Release|Win32.Deploy.0 = Release|Win32 + {F4853009-C5D2-4A25-BE4D-BB0D9F84E2FF}.Release|x64.ActiveCfg = Release|x64 + {F4853009-C5D2-4A25-BE4D-BB0D9F84E2FF}.Release|x64.Build.0 = Release|x64 + {F4853009-C5D2-4A25-BE4D-BB0D9F84E2FF}.Release|x64.Deploy.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {4989C8A8-DCF1-48A9-9012-23369AB01403} + EndGlobalSection +EndGlobal diff --git a/KProcessHacker/KProcessHacker.vcxproj b/KProcessHacker/KProcessHacker.vcxproj index 87fb632baad2..3f18628eba62 100644 --- a/KProcessHacker/KProcessHacker.vcxproj +++ b/KProcessHacker/KProcessHacker.vcxproj @@ -1,27 +1,26 @@  - + - - Win8 Debug + + Debug Win32 - - Win8 Release + + Release Win32 - - Win8 Debug + + Debug x64 - - Win8 Release + + Release x64 {F4853009-C5D2-4A25-BE4D-BB0D9F84E2FF} {dd38f7fc-d7bd-488b-9242-7d8754cde80d} - v4.5 11.0 Win8 Debug Win32 @@ -29,28 +28,33 @@ KProcessHacker $(VCTargetsPath11) + $(LatestTargetPlatformVersion) - WindowsKernelModeDriver8.0 + WindowsKernelModeDriver10.0 Driver WDM - - Windows8 + + Windows7 true + Unicode - - Windows8 + + Windows7 false + Unicode - - Windows8 + + Windows7 true + Unicode - - Windows8 + + Windows7 false + Unicode @@ -62,53 +66,81 @@ DbgengKernelDebugger - - $(ProjectDir)bin\$(Configuration) $(PlatformArchitecture)\ - $(ProjectDir)obj\$(Configuration) $(PlatformArchitecture)\ + + $(SolutionDir)bin\$(Configuration)$(PlatformArchitecture)\ + $(ProjectDir)obj\$(Configuration)$(PlatformArchitecture)\ + false kprocesshacker - - $(ProjectDir)bin\$(Configuration) $(PlatformArchitecture)\ - $(ProjectDir)obj\$(Configuration) $(PlatformArchitecture)\ + + $(SolutionDir)bin\$(Configuration)$(PlatformArchitecture)\ + $(ProjectDir)obj\$(Configuration)$(PlatformArchitecture)\ + false kprocesshacker - - $(ProjectDir)bin\$(Configuration) $(PlatformArchitecture)\ - $(ProjectDir)obj\$(Configuration) $(PlatformArchitecture)\ + + $(SolutionDir)bin\$(Configuration)$(PlatformArchitecture)\ + $(ProjectDir)obj\$(Configuration)$(PlatformArchitecture)\ + false kprocesshacker - - $(ProjectDir)bin\$(Configuration) $(PlatformArchitecture)\ - $(ProjectDir)obj\$(Configuration) $(PlatformArchitecture)\ + + $(SolutionDir)bin\$(Configuration)$(PlatformArchitecture)\ + $(ProjectDir)obj\$(Configuration)$(PlatformArchitecture)\ + false kprocesshacker - + ../phnt/include;../phlib/include;include;$(IntDir);%(AdditionalIncludeDirectories) - KPH_CONFIG_CLEAN;_X86_=1;i386=1;STD_CALL;%(PreprocessorDefinitions) + KPH_CONFIG_CLEAN;POOL_NX_OPTIN;_X86_=1;i386=1;STD_CALL;%(PreprocessorDefinitions) Level3 + true + true + + ksecdd.lib;%(AdditionalDependencies) + true + - + ../phnt/include;../phlib/include;include;$(IntDir);%(AdditionalIncludeDirectories) - KPH_CONFIG_CLEAN;_X86_=1;i386=1;STD_CALL;%(PreprocessorDefinitions) + KPH_CONFIG_CLEAN;POOL_NX_OPTIN;_X86_=1;i386=1;STD_CALL;%(PreprocessorDefinitions) Level3 + true + true + + ksecdd.lib;%(AdditionalDependencies) + true + - + ../phnt/include;../phlib/include;include;$(IntDir);%(AdditionalIncludeDirectories) - KPH_CONFIG_CLEAN;_WIN64;_AMD64_;AMD64;%(PreprocessorDefinitions) + KPH_CONFIG_CLEAN;POOL_NX_OPTIN;_WIN64;_AMD64_;AMD64;%(PreprocessorDefinitions) Level3 + true + true + + ksecdd.lib;%(AdditionalDependencies) + true + - + ../phnt/include;../phlib/include;include;$(IntDir);%(AdditionalIncludeDirectories) - KPH_CONFIG_CLEAN;_WIN64;_AMD64_;AMD64;%(PreprocessorDefinitions) + KPH_CONFIG_CLEAN;POOL_NX_OPTIN;_WIN64;_AMD64_;AMD64;%(PreprocessorDefinitions) Level3 + true + true + + ksecdd.lib;%(AdditionalDependencies) + true + @@ -123,6 +155,8 @@ + + diff --git a/KProcessHacker/KProcessHacker.vcxproj.filters b/KProcessHacker/KProcessHacker.vcxproj.filters index 1ff8bd09f11c..87b584444426 100644 --- a/KProcessHacker/KProcessHacker.vcxproj.filters +++ b/KProcessHacker/KProcessHacker.vcxproj.filters @@ -46,6 +46,12 @@ Source Files + + Source Files + + + Source Files + diff --git a/KProcessHacker/bin/amd64/kprocesshacker.pdb b/KProcessHacker/bin/amd64/kprocesshacker.pdb deleted file mode 100644 index 93dbdc215621ddfdc319505af53842701ffccc47..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 314368 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 S$$_05*vWyN9QgO;!2bsxG=SLv diff --git a/KProcessHacker/bin/amd64/kprocesshacker.sys b/KProcessHacker/bin/amd64/kprocesshacker.sys deleted file mode 100644 index f6a94ff33aa26fc54554baa610c71102de06c990..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 27648 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 aLoSVL6Z)0B!-8+KrF~A~^sgT{@IL{P_`l@< diff --git a/KProcessHacker/bin/i386/kprocesshacker.pdb b/KProcessHacker/bin/i386/kprocesshacker.pdb deleted file mode 100644 index b82fe335059d3b99358418a3b44030479fdfca75..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 363520 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%0A~cJj_!BflYX{Nmk(PyOVy(@x&_;X^;cpJ5~a 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 diff --git a/KProcessHacker/bin/i386/kprocesshacker.sys b/KProcessHacker/bin/i386/kprocesshacker.sys deleted file mode 100644 index 4f8f329cc11feb776ff36a3a36a6030a79924640..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 24064 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 T#& NTSTATUS KphDispatchDeviceControl( - __in PDEVICE_OBJECT DeviceObject, - __in PIRP Irp + _In_ PDEVICE_OBJECT DeviceObject, + _Inout_ PIRP Irp ) { NTSTATUS status; diff --git a/KProcessHacker/dirs b/KProcessHacker/dirs deleted file mode 100644 index 1caf7fa5b055..000000000000 --- a/KProcessHacker/dirs +++ /dev/null @@ -1 +0,0 @@ -DIRS=clean diff --git a/KProcessHacker/dyndata.c b/KProcessHacker/dyndata.c index 40d4cfe5d470..ff685369570b 100644 --- a/KProcessHacker/dyndata.c +++ b/KProcessHacker/dyndata.c @@ -26,8 +26,8 @@ #define C_2sTo4(x) ((unsigned int)(signed short)(x)) NTSTATUS KphpLoadDynamicConfiguration( - __in PVOID Buffer, - __in ULONG Length + _In_ PVOID Buffer, + _In_ ULONG Length ); #ifdef ALLOC_PRAGMA @@ -53,7 +53,7 @@ NTSTATUS KphDynamicDataInitialization( } NTSTATUS KphReadDynamicDataParameters( - __in_opt HANDLE KeyHandle + _In_opt_ HANDLE KeyHandle ) { NTSTATUS status; @@ -114,8 +114,8 @@ NTSTATUS KphReadDynamicDataParameters( } NTSTATUS KphpLoadDynamicConfiguration( - __in PVOID Buffer, - __in ULONG Length + _In_ PVOID Buffer, + _In_ ULONG Length ) { PKPH_DYN_CONFIGURATION config; @@ -126,13 +126,13 @@ NTSTATUS KphpLoadDynamicConfiguration( config = Buffer; - if (Length < FIELD_OFFSET(KPH_DYN_CONFIGURATION, Packages)) + if (Length < (ULONG)FIELD_OFFSET(KPH_DYN_CONFIGURATION, Packages)) return STATUS_INVALID_PARAMETER; if (config->Version != KPH_DYN_CONFIGURATION_VERSION) return STATUS_INVALID_PARAMETER; if (config->NumberOfPackages > KPH_DYN_MAXIMUM_PACKAGES) return STATUS_INVALID_PARAMETER; - if (Length < FIELD_OFFSET(KPH_DYN_CONFIGURATION, Packages) + config->NumberOfPackages * sizeof(KPH_DYN_PACKAGE)) + if (Length < (ULONG)FIELD_OFFSET(KPH_DYN_CONFIGURATION, Packages) + config->NumberOfPackages * sizeof(KPH_DYN_PACKAGE)) return STATUS_INVALID_PARAMETER; dprintf("Loading dynamic configuration with %u package(s)\n", config->NumberOfPackages); diff --git a/KProcessHacker/dynimp.c b/KProcessHacker/dynimp.c index d432611a3ca8..7b02b5b1841f 100644 --- a/KProcessHacker/dynimp.c +++ b/KProcessHacker/dynimp.c @@ -47,7 +47,7 @@ VOID KphDynamicImport( * not be found. */ PVOID KphGetSystemRoutineAddress( - __in PWSTR SystemRoutineName + _In_ PWSTR SystemRoutineName ) { UNICODE_STRING systemRoutineName; diff --git a/KProcessHacker/include/dyndata.h b/KProcessHacker/include/dyndata.h index d31f0f0e10e7..ab36182a3fd9 100644 --- a/KProcessHacker/include/dyndata.h +++ b/KProcessHacker/include/dyndata.h @@ -41,7 +41,7 @@ NTSTATUS KphDynamicDataInitialization( ); NTSTATUS KphReadDynamicDataParameters( - __in_opt HANDLE KeyHandle + _In_opt_ HANDLE KeyHandle ); #endif diff --git a/KProcessHacker/include/kph.h b/KProcessHacker/include/kph.h index 8ee115f9b7ab..4c5032411cf1 100644 --- a/KProcessHacker/include/kph.h +++ b/KProcessHacker/include/kph.h @@ -48,17 +48,17 @@ extern ULONG KphFeatures; extern KPH_PARAMETERS KphParameters; NTSTATUS KpiGetFeatures( - __out PULONG Features, - __in KPROCESSOR_MODE AccessMode + _Out_ PULONG Features, + _In_ KPROCESSOR_MODE AccessMode ); // devctrl -__drv_dispatchType(IRP_MJ_DEVICE_CONTROL) DRIVER_DISPATCH KphDispatchDeviceControl; +_Dispatch_type_(IRP_MJ_DEVICE_CONTROL) DRIVER_DISPATCH KphDispatchDeviceControl; NTSTATUS KphDispatchDeviceControl( - __in PDEVICE_OBJECT DeviceObject, - __in PIRP Irp + _In_ PDEVICE_OBJECT DeviceObject, + _Inout_ PIRP Irp ); // dynimp @@ -68,298 +68,298 @@ VOID KphDynamicImport( ); PVOID KphGetSystemRoutineAddress( - __in PWSTR SystemRoutineName + _In_ PWSTR SystemRoutineName ); // object PHANDLE_TABLE KphReferenceProcessHandleTable( - __in PEPROCESS Process + _In_ PEPROCESS Process ); VOID KphDereferenceProcessHandleTable( - __in PEPROCESS Process + _In_ PEPROCESS Process ); VOID KphUnlockHandleTableEntry( - __in PHANDLE_TABLE HandleTable, - __in PHANDLE_TABLE_ENTRY HandleTableEntry + _In_ PHANDLE_TABLE HandleTable, + _In_ PHANDLE_TABLE_ENTRY HandleTableEntry ); NTSTATUS KpiEnumerateProcessHandles( - __in HANDLE ProcessHandle, - __out_bcount(BufferLength) PVOID Buffer, - __in_opt ULONG BufferLength, - __out_opt PULONG ReturnLength, - __in KPROCESSOR_MODE AccessMode + _In_ HANDLE ProcessHandle, + _Out_writes_bytes_(BufferLength) PVOID Buffer, + _In_opt_ ULONG BufferLength, + _Out_opt_ PULONG ReturnLength, + _In_ KPROCESSOR_MODE AccessMode ); NTSTATUS KphQueryNameObject( - __in PVOID Object, - __out_bcount(BufferLength) POBJECT_NAME_INFORMATION Buffer, - __in ULONG BufferLength, - __out PULONG ReturnLength + _In_ PVOID Object, + _Out_writes_bytes_(BufferLength) POBJECT_NAME_INFORMATION Buffer, + _In_ ULONG BufferLength, + _Out_ PULONG ReturnLength ); NTSTATUS KphQueryNameFileObject( - __in PFILE_OBJECT FileObject, - __out_bcount(BufferLength) POBJECT_NAME_INFORMATION Buffer, - __in ULONG BufferLength, - __out PULONG ReturnLength + _In_ PFILE_OBJECT FileObject, + _Out_writes_bytes_(BufferLength) POBJECT_NAME_INFORMATION Buffer, + _In_ ULONG BufferLength, + _Out_ PULONG ReturnLength ); NTSTATUS KpiQueryInformationObject( - __in HANDLE ProcessHandle, - __in HANDLE Handle, - __in KPH_OBJECT_INFORMATION_CLASS ObjectInformationClass, - __out_bcount(ObjectInformationLength) PVOID ObjectInformation, - __in ULONG ObjectInformationLength, - __out_opt PULONG ReturnLength, - __in KPROCESSOR_MODE AccessMode + _In_ HANDLE ProcessHandle, + _In_ HANDLE Handle, + _In_ KPH_OBJECT_INFORMATION_CLASS ObjectInformationClass, + _Out_writes_bytes_(ObjectInformationLength) PVOID ObjectInformation, + _In_ ULONG ObjectInformationLength, + _Out_opt_ PULONG ReturnLength, + _In_ KPROCESSOR_MODE AccessMode ); NTSTATUS KpiSetInformationObject( - __in HANDLE ProcessHandle, - __in HANDLE Handle, - __in KPH_OBJECT_INFORMATION_CLASS ObjectInformationClass, - __in_bcount(ObjectInformationLength) PVOID ObjectInformation, - __in ULONG ObjectInformationLength, - __in KPROCESSOR_MODE AccessMode + _In_ HANDLE ProcessHandle, + _In_ HANDLE Handle, + _In_ KPH_OBJECT_INFORMATION_CLASS ObjectInformationClass, + _In_reads_bytes_(ObjectInformationLength) PVOID ObjectInformation, + _In_ ULONG ObjectInformationLength, + _In_ KPROCESSOR_MODE AccessMode ); NTSTATUS KphOpenNamedObject( - __out PHANDLE ObjectHandle, - __in ACCESS_MASK DesiredAccess, - __in POBJECT_ATTRIBUTES ObjectAttributes, - __in POBJECT_TYPE ObjectType, - __in KPROCESSOR_MODE AccessMode + _Out_ PHANDLE ObjectHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_ POBJECT_TYPE ObjectType, + _In_ KPROCESSOR_MODE AccessMode ); // process NTSTATUS KpiOpenProcess( - __out PHANDLE ProcessHandle, - __in ACCESS_MASK DesiredAccess, - __in PCLIENT_ID ClientId, - __in_opt KPH_KEY Key, - __in PKPH_CLIENT Client, - __in KPROCESSOR_MODE AccessMode + _Out_ PHANDLE ProcessHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ PCLIENT_ID ClientId, + _In_opt_ KPH_KEY Key, + _In_ PKPH_CLIENT Client, + _In_ KPROCESSOR_MODE AccessMode ); NTSTATUS KpiOpenProcessToken( - __in HANDLE ProcessHandle, - __in ACCESS_MASK DesiredAccess, - __out PHANDLE TokenHandle, - __in_opt KPH_KEY Key, - __in PKPH_CLIENT Client, - __in KPROCESSOR_MODE AccessMode + _In_ HANDLE ProcessHandle, + _In_ ACCESS_MASK DesiredAccess, + _Out_ PHANDLE TokenHandle, + _In_opt_ KPH_KEY Key, + _In_ PKPH_CLIENT Client, + _In_ KPROCESSOR_MODE AccessMode ); NTSTATUS KpiOpenProcessJob( - __in HANDLE ProcessHandle, - __in ACCESS_MASK DesiredAccess, - __out PHANDLE JobHandle, - __in KPROCESSOR_MODE AccessMode + _In_ HANDLE ProcessHandle, + _In_ ACCESS_MASK DesiredAccess, + _Out_ PHANDLE JobHandle, + _In_ KPROCESSOR_MODE AccessMode ); NTSTATUS KpiTerminateProcess( - __in HANDLE ProcessHandle, - __in NTSTATUS ExitStatus, - __in_opt KPH_KEY Key, - __in PKPH_CLIENT Client, - __in KPROCESSOR_MODE AccessMode + _In_ HANDLE ProcessHandle, + _In_ NTSTATUS ExitStatus, + _In_opt_ KPH_KEY Key, + _In_ PKPH_CLIENT Client, + _In_ KPROCESSOR_MODE AccessMode ); NTSTATUS KpiQueryInformationProcess( - __in HANDLE ProcessHandle, - __in KPH_PROCESS_INFORMATION_CLASS ProcessInformationClass, - __out_bcount(ProcessInformationLength) PVOID ProcessInformation, - __in ULONG ProcessInformationLength, - __out_opt PULONG ReturnLength, - __in KPROCESSOR_MODE AccessMode + _In_ HANDLE ProcessHandle, + _In_ KPH_PROCESS_INFORMATION_CLASS ProcessInformationClass, + _Out_writes_bytes_(ProcessInformationLength) PVOID ProcessInformation, + _In_ ULONG ProcessInformationLength, + _Out_opt_ PULONG ReturnLength, + _In_ KPROCESSOR_MODE AccessMode ); NTSTATUS KpiSetInformationProcess( - __in HANDLE ProcessHandle, - __in KPH_PROCESS_INFORMATION_CLASS ProcessInformationClass, - __in_bcount(ProcessInformationLength) PVOID ProcessInformation, - __in ULONG ProcessInformationLength, - __in KPROCESSOR_MODE AccessMode + _In_ HANDLE ProcessHandle, + _In_ KPH_PROCESS_INFORMATION_CLASS ProcessInformationClass, + _In_reads_bytes_(ProcessInformationLength) PVOID ProcessInformation, + _In_ ULONG ProcessInformationLength, + _In_ KPROCESSOR_MODE AccessMode ); // qrydrv NTSTATUS KpiOpenDriver( - __out PHANDLE DriverHandle, - __in ACCESS_MASK DesiredAccess, - __in POBJECT_ATTRIBUTES ObjectAttributes, - __in KPROCESSOR_MODE AccessMode + _Out_ PHANDLE DriverHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_ KPROCESSOR_MODE AccessMode ); NTSTATUS KpiQueryInformationDriver( - __in HANDLE DriverHandle, - __in DRIVER_INFORMATION_CLASS DriverInformationClass, - __out_bcount(DriverInformationLength) PVOID DriverInformation, - __in ULONG DriverInformationLength, - __out_opt PULONG ReturnLength, - __in KPROCESSOR_MODE AccessMode + _In_ HANDLE DriverHandle, + _In_ DRIVER_INFORMATION_CLASS DriverInformationClass, + _Out_writes_bytes_(DriverInformationLength) PVOID DriverInformation, + _In_ ULONG DriverInformationLength, + _Out_opt_ PULONG ReturnLength, + _In_ KPROCESSOR_MODE AccessMode ); // thread NTSTATUS KpiOpenThread( - __out PHANDLE ThreadHandle, - __in ACCESS_MASK DesiredAccess, - __in PCLIENT_ID ClientId, - __in_opt KPH_KEY Key, - __in PKPH_CLIENT Client, - __in KPROCESSOR_MODE AccessMode + _Out_ PHANDLE ThreadHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ PCLIENT_ID ClientId, + _In_opt_ KPH_KEY Key, + _In_ PKPH_CLIENT Client, + _In_ KPROCESSOR_MODE AccessMode ); NTSTATUS KpiOpenThreadProcess( - __in HANDLE ThreadHandle, - __in ACCESS_MASK DesiredAccess, - __out PHANDLE ProcessHandle, - __in KPROCESSOR_MODE AccessMode + _In_ HANDLE ThreadHandle, + _In_ ACCESS_MASK DesiredAccess, + _Out_ PHANDLE ProcessHandle, + _In_ KPROCESSOR_MODE AccessMode ); ULONG KphCaptureStackBackTrace( - __in ULONG FramesToSkip, - __in ULONG FramesToCapture, - __in_opt ULONG Flags, - __out_ecount(FramesToCapture) PVOID *BackTrace, - __out_opt PULONG BackTraceHash + _In_ ULONG FramesToSkip, + _In_ ULONG FramesToCapture, + _In_opt_ ULONG Flags, + _Out_writes_(FramesToCapture) PVOID *BackTrace, + _Out_opt_ PULONG BackTraceHash ); NTSTATUS KphCaptureStackBackTraceThread( - __in PETHREAD Thread, - __in ULONG FramesToSkip, - __in ULONG FramesToCapture, - __out_ecount(FramesToCapture) PVOID *BackTrace, - __out_opt PULONG CapturedFrames, - __out_opt PULONG BackTraceHash, - __in KPROCESSOR_MODE AccessMode + _In_ PETHREAD Thread, + _In_ ULONG FramesToSkip, + _In_ ULONG FramesToCapture, + _Out_writes_(FramesToCapture) PVOID *BackTrace, + _Out_opt_ PULONG CapturedFrames, + _Out_opt_ PULONG BackTraceHash, + _In_ KPROCESSOR_MODE AccessMode ); NTSTATUS KpiCaptureStackBackTraceThread( - __in HANDLE ThreadHandle, - __in ULONG FramesToSkip, - __in ULONG FramesToCapture, - __out_ecount(FramesToCapture) PVOID *BackTrace, - __out_opt PULONG CapturedFrames, - __out_opt PULONG BackTraceHash, - __in KPROCESSOR_MODE AccessMode + _In_ HANDLE ThreadHandle, + _In_ ULONG FramesToSkip, + _In_ ULONG FramesToCapture, + _Out_writes_(FramesToCapture) PVOID *BackTrace, + _Out_opt_ PULONG CapturedFrames, + _Out_opt_ PULONG BackTraceHash, + _In_ KPROCESSOR_MODE AccessMode ); NTSTATUS KpiQueryInformationThread( - __in HANDLE ThreadHandle, - __in KPH_THREAD_INFORMATION_CLASS ThreadInformationClass, - __out_bcount(ProcessInformationLength) PVOID ThreadInformation, - __in ULONG ThreadInformationLength, - __out_opt PULONG ReturnLength, - __in KPROCESSOR_MODE AccessMode + _In_ HANDLE ThreadHandle, + _In_ KPH_THREAD_INFORMATION_CLASS ThreadInformationClass, + _Out_writes_bytes_(ThreadInformationLength) PVOID ThreadInformation, + _In_ ULONG ThreadInformationLength, + _Out_opt_ PULONG ReturnLength, + _In_ KPROCESSOR_MODE AccessMode ); NTSTATUS KpiSetInformationThread( - __in HANDLE ThreadHandle, - __in KPH_THREAD_INFORMATION_CLASS ThreadInformationClass, - __in_bcount(ThreadInformationLength) PVOID ThreadInformation, - __in ULONG ThreadInformationLength, - __in KPROCESSOR_MODE AccessMode + _In_ HANDLE ThreadHandle, + _In_ KPH_THREAD_INFORMATION_CLASS ThreadInformationClass, + _In_reads_bytes_(ThreadInformationLength) PVOID ThreadInformation, + _In_ ULONG ThreadInformationLength, + _In_ KPROCESSOR_MODE AccessMode ); // util VOID KphFreeCapturedUnicodeString( - __in PUNICODE_STRING CapturedUnicodeString + _In_ PUNICODE_STRING CapturedUnicodeString ); NTSTATUS KphCaptureUnicodeString( - __in PUNICODE_STRING UnicodeString, - __out PUNICODE_STRING CapturedUnicodeString + _In_ PUNICODE_STRING UnicodeString, + _Out_ PUNICODE_STRING CapturedUnicodeString ); NTSTATUS KphEnumerateSystemModules( - __out PRTL_PROCESS_MODULES *Modules + _Out_ PRTL_PROCESS_MODULES *Modules ); NTSTATUS KphValidateAddressForSystemModules( - __in PVOID Address, - __in SIZE_T Length + _In_ PVOID Address, + _In_ SIZE_T Length ); NTSTATUS KphGetProcessMappedFileName( - __in HANDLE ProcessHandle, - __in PVOID BaseAddress, - __out PUNICODE_STRING *FileName + _In_ HANDLE ProcessHandle, + _In_ PVOID BaseAddress, + _Out_ PUNICODE_STRING *FileName ); // verify NTSTATUS KphHashFile( - __in PUNICODE_STRING FileName, - __out PVOID *Hash, - __out PULONG HashSize + _In_ PUNICODE_STRING FileName, + _Out_ PVOID *Hash, + _Out_ PULONG HashSize ); NTSTATUS KphVerifyFile( - __in PUNICODE_STRING FileName, - __in_bcount(SignatureSize) PUCHAR Signature, - __in ULONG SignatureSize + _In_ PUNICODE_STRING FileName, + _In_reads_bytes_(SignatureSize) PUCHAR Signature, + _In_ ULONG SignatureSize ); VOID KphVerifyClient( - __inout PKPH_CLIENT Client, - __in PVOID CodeAddress, - __in_bcount(SignatureSize) PUCHAR Signature, - __in ULONG SignatureSize + _Inout_ PKPH_CLIENT Client, + _In_ PVOID CodeAddress, + _In_reads_bytes_(SignatureSize) PUCHAR Signature, + _In_ ULONG SignatureSize ); NTSTATUS KpiVerifyClient( - __in PVOID CodeAddress, - __in_bcount(SignatureSize) PUCHAR Signature, - __in ULONG SignatureSize, - __in PKPH_CLIENT Client + _In_ PVOID CodeAddress, + _In_reads_bytes_(SignatureSize) PUCHAR Signature, + _In_ ULONG SignatureSize, + _In_ PKPH_CLIENT Client ); VOID KphGenerateKeysClient( - __inout PKPH_CLIENT Client + _Inout_ PKPH_CLIENT Client ); NTSTATUS KphRetrieveKeyViaApc( - __inout PKPH_CLIENT Client, - __in KPH_KEY_LEVEL KeyLevel, - __inout PIRP Irp + _Inout_ PKPH_CLIENT Client, + _In_ KPH_KEY_LEVEL KeyLevel, + _Inout_ PIRP Irp ); NTSTATUS KphValidateKey( - __in KPH_KEY_LEVEL RequiredKeyLevel, - __in_opt KPH_KEY Key, - __in PKPH_CLIENT Client, - __in KPROCESSOR_MODE AccessMode + _In_ KPH_KEY_LEVEL RequiredKeyLevel, + _In_opt_ KPH_KEY Key, + _In_ PKPH_CLIENT Client, + _In_ KPROCESSOR_MODE AccessMode ); // vm NTSTATUS KphCopyVirtualMemory( - __in PEPROCESS FromProcess, - __in PVOID FromAddress, - __in PEPROCESS ToProcess, - __in PVOID ToAddress, - __in SIZE_T BufferLength, - __in KPROCESSOR_MODE AccessMode, - __out PSIZE_T ReturnLength + _In_ PEPROCESS FromProcess, + _In_ PVOID FromAddress, + _In_ PEPROCESS ToProcess, + _In_ PVOID ToAddress, + _In_ SIZE_T BufferLength, + _In_ KPROCESSOR_MODE AccessMode, + _Out_ PSIZE_T ReturnLength ); NTSTATUS KpiReadVirtualMemoryUnsafe( - __in_opt HANDLE ProcessHandle, - __in PVOID BaseAddress, - __out_bcount(BufferSize) PVOID Buffer, - __in SIZE_T BufferSize, - __out_opt PSIZE_T NumberOfBytesRead, - __in_opt KPH_KEY Key, - __in PKPH_CLIENT Client, - __in KPROCESSOR_MODE AccessMode + _In_opt_ HANDLE ProcessHandle, + _In_ PVOID BaseAddress, + _Out_writes_bytes_(BufferSize) PVOID Buffer, + _In_ SIZE_T BufferSize, + _Out_opt_ PSIZE_T NumberOfBytesRead, + _In_opt_ KPH_KEY Key, + _In_ PKPH_CLIENT Client, + _In_ KPROCESSOR_MODE AccessMode ); #endif diff --git a/KProcessHacker/include/ntfill.h b/KProcessHacker/include/ntfill.h index 865bbe877cb1..0cf0bcdc300c 100644 --- a/KProcessHacker/include/ntfill.h +++ b/KProcessHacker/include/ntfill.h @@ -13,8 +13,8 @@ NTKERNELAPI VOID FASTCALL ExfUnblockPushLock( - __inout PEX_PUSH_LOCK PushLock, - __inout_opt PEX_PUSH_LOCK_WAIT_BLOCK WaitBlock + _Inout_ PEX_PUSH_LOCK PushLock, + _Inout_opt_ PEX_PUSH_LOCK_WAIT_BLOCK WaitBlock ); typedef struct _HANDLE_TABLE_ENTRY @@ -35,37 +35,37 @@ typedef struct _HANDLE_TABLE_ENTRY typedef struct _HANDLE_TABLE HANDLE_TABLE, *PHANDLE_TABLE; typedef BOOLEAN (NTAPI *PEX_ENUM_HANDLE_CALLBACK_61)( - __inout PHANDLE_TABLE_ENTRY HandleTableEntry, - __in HANDLE Handle, - __in PVOID Context + _Inout_ PHANDLE_TABLE_ENTRY HandleTableEntry, + _In_ HANDLE Handle, + _In_ PVOID Context ); // since WIN8 typedef BOOLEAN (NTAPI *PEX_ENUM_HANDLE_CALLBACK)( - __in PHANDLE_TABLE HandleTable, - __inout PHANDLE_TABLE_ENTRY HandleTableEntry, - __in HANDLE Handle, - __in PVOID Context + _In_ PHANDLE_TABLE HandleTable, + _Inout_ PHANDLE_TABLE_ENTRY HandleTableEntry, + _In_ HANDLE Handle, + _In_ PVOID Context ); NTKERNELAPI BOOLEAN NTAPI ExEnumHandleTable( - __in PHANDLE_TABLE HandleTable, - __in PEX_ENUM_HANDLE_CALLBACK EnumHandleProcedure, - __inout PVOID Context, - __out_opt PHANDLE Handle + _In_ PHANDLE_TABLE HandleTable, + _In_ PEX_ENUM_HANDLE_CALLBACK EnumHandleProcedure, + _Inout_ PVOID Context, + _Out_opt_ PHANDLE Handle ); NTSYSCALLAPI NTSTATUS NTAPI ZwQuerySystemInformation( - __in SYSTEM_INFORMATION_CLASS SystemInformationClass, - __out_bcount_opt(SystemInformationLength) PVOID SystemInformation, - __in ULONG SystemInformationLength, - __out_opt PULONG ReturnLength + _In_ SYSTEM_INFORMATION_CLASS SystemInformationClass, + _Out_writes_bytes_opt_(SystemInformationLength) PVOID SystemInformation, + _In_ ULONG SystemInformationLength, + _Out_opt_ PULONG ReturnLength ); // IO @@ -83,61 +83,47 @@ typedef enum _KAPC_ENVIRONMENT } KAPC_ENVIRONMENT, *PKAPC_ENVIRONMENT; typedef VOID (NTAPI *PKNORMAL_ROUTINE)( - __in PVOID NormalContext, - __in PVOID SystemArgument1, - __in PVOID SystemArgument2 + _In_ PVOID NormalContext, + _In_ PVOID SystemArgument1, + _In_ PVOID SystemArgument2 ); typedef VOID KKERNEL_ROUTINE( - __in PRKAPC Apc, - __inout PKNORMAL_ROUTINE *NormalRoutine, - __inout PVOID *NormalContext, - __inout PVOID *SystemArgument1, - __inout PVOID *SystemArgument2 + _In_ PRKAPC Apc, + _Inout_ PKNORMAL_ROUTINE *NormalRoutine, + _Inout_ PVOID *NormalContext, + _Inout_ PVOID *SystemArgument1, + _Inout_ PVOID *SystemArgument2 ); typedef KKERNEL_ROUTINE (NTAPI *PKKERNEL_ROUTINE); typedef VOID (NTAPI *PKRUNDOWN_ROUTINE)( - __in PRKAPC Apc + _In_ PRKAPC Apc ); NTKERNELAPI VOID NTAPI KeInitializeApc( - __out PRKAPC Apc, - __in PRKTHREAD Thread, - __in KAPC_ENVIRONMENT Environment, - __in PKKERNEL_ROUTINE KernelRoutine, - __in_opt PKRUNDOWN_ROUTINE RundownRoutine, - __in_opt PKNORMAL_ROUTINE NormalRoutine, - __in_opt KPROCESSOR_MODE ProcessorMode, - __in_opt PVOID NormalContext + _Out_ PRKAPC Apc, + _In_ PRKTHREAD Thread, + _In_ KAPC_ENVIRONMENT Environment, + _In_ PKKERNEL_ROUTINE KernelRoutine, + _In_opt_ PKRUNDOWN_ROUTINE RundownRoutine, + _In_opt_ PKNORMAL_ROUTINE NormalRoutine, + _In_opt_ KPROCESSOR_MODE ProcessorMode, + _In_opt_ PVOID NormalContext ); NTKERNELAPI BOOLEAN NTAPI KeInsertQueueApc( - __inout PRKAPC Apc, - __in_opt PVOID SystemArgument1, - __in_opt PVOID SystemArgument2, - __in KPRIORITY Increment - ); - -// MM - -NTSYSCALLAPI -NTSTATUS -NTAPI -ZwQueryVirtualMemory( - __in HANDLE ProcessHandle, - __in PVOID BaseAddress, - __in MEMORY_INFORMATION_CLASS MemoryInformationClass, - __out_bcount(MemoryInformationLength) PVOID MemoryInformation, - __in SIZE_T MemoryInformationLength, - __out_opt PSIZE_T ReturnLength + _Inout_ PRKAPC Apc, + _In_opt_ PVOID SystemArgument1, + _In_opt_ PVOID SystemArgument2, + _In_ KPRIORITY Increment ); // OB @@ -195,7 +181,7 @@ FORCEINLINE ULONG ObpGetHandleAttributes(PHANDLE_TABLE_ENTRY HandleTableEntry) typedef struct _OBJECT_CREATE_INFORMATION OBJECT_CREATE_INFORMATION, *POBJECT_CREATE_INFORMATION; -// This is incorrect as of Windows 8.1, but the size of the structure is still correct. +// This structure is not correct on Windows 7, but the offsets we need are still correct. typedef struct _OBJECT_HEADER { LONG PointerCount; @@ -204,11 +190,34 @@ typedef struct _OBJECT_HEADER LONG HandleCount; PVOID NextToFree; }; - POBJECT_TYPE Type; - UCHAR NameInfoOffset; - UCHAR HandleInfoOffset; - UCHAR QuotaInfoOffset; - UCHAR Flags; + EX_PUSH_LOCK Lock; + UCHAR TypeIndex; + union + { + UCHAR TraceFlags; + struct + { + UCHAR DbgRefTrace : 1; + UCHAR DbgTracePermanent : 1; + UCHAR Reserved : 6; + }; + }; + UCHAR InfoMask; + union + { + UCHAR Flags; + struct + { + UCHAR NewObject : 1; + UCHAR KernelObject : 1; + UCHAR KernelOnlyAccess : 1; + UCHAR ExclusiveObject : 1; + UCHAR PermanentObject : 1; + UCHAR DefaultSecurityQuota : 1; + UCHAR SingleHandleEntry : 1; + UCHAR DeletedInline : 1; + }; + }; union { POBJECT_CREATE_INFORMATION ObjectCreateInfo; @@ -218,42 +227,43 @@ typedef struct _OBJECT_HEADER QUAD Body; } OBJECT_HEADER, *POBJECT_HEADER; +#ifdef _M_X64 +C_ASSERT(FIELD_OFFSET(OBJECT_HEADER, Body) == 0x030); +C_ASSERT(sizeof(OBJECT_HEADER) == 0x038); +#else +C_ASSERT(FIELD_OFFSET(OBJECT_HEADER, Body) == 0x018); +C_ASSERT(sizeof(OBJECT_HEADER) == 0x020); +#endif + #define OBJECT_TO_OBJECT_HEADER(Object) CONTAINING_RECORD((Object), OBJECT_HEADER, Body) NTKERNELAPI POBJECT_TYPE NTAPI ObGetObjectType( - __in PVOID Object + _In_ PVOID Object ); NTKERNELAPI NTSTATUS NTAPI ObOpenObjectByName( - __in POBJECT_ATTRIBUTES ObjectAttributes, - __in POBJECT_TYPE ObjectType, - __in KPROCESSOR_MODE PreviousMode, - __in_opt PACCESS_STATE AccessState, - __in_opt ACCESS_MASK DesiredAccess, - __in PVOID ParseContext, - __out PHANDLE Handle + _In_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_ POBJECT_TYPE ObjectType, + _In_ KPROCESSOR_MODE PreviousMode, + _In_opt_ PACCESS_STATE AccessState, + _In_opt_ ACCESS_MASK DesiredAccess, + _In_opt_ PVOID ParseContext, + _Out_ PHANDLE Handle ); NTKERNELAPI NTSTATUS NTAPI ObSetHandleAttributes( - __in HANDLE Handle, - __in POBJECT_HANDLE_FLAG_INFORMATION HandleFlags, - __in KPROCESSOR_MODE PreviousMode - ); - -NTKERNELAPI -NTSTATUS -ObCloseHandle( - __in HANDLE Handle, - __in KPROCESSOR_MODE PreviousMode + _In_ HANDLE Handle, + _In_ POBJECT_HANDLE_FLAG_INFORMATION HandleFlags, + _In_ KPROCESSOR_MODE PreviousMode ); // PS @@ -262,48 +272,31 @@ NTSYSCALLAPI NTSTATUS NTAPI ZwQueryInformationProcess( - __in HANDLE ProcessHandle, - __in PROCESSINFOCLASS ProcessInformationClass, - __out_bcount(ProcessInformationLength) PVOID ProcessInformation, - __in ULONG ProcessInformationLength, - __out_opt PULONG ReturnLength - ); - -NTSYSCALLAPI -NTSTATUS -NTAPI -ZwSetInformationProcess( - __in HANDLE ProcessHandle, - __in PROCESSINFOCLASS ProcessInformationClass, - __in_bcount(ProcessInformationLength) PVOID ProcessInformation, - __in ULONG ProcessInformationLength + _In_ HANDLE ProcessHandle, + _In_ PROCESSINFOCLASS ProcessInformationClass, + _Out_writes_bytes_(ProcessInformationLength) PVOID ProcessInformation, + _In_ ULONG ProcessInformationLength, + _Out_opt_ PULONG ReturnLength ); NTSYSCALLAPI NTSTATUS NTAPI ZwQueryInformationThread( - __in HANDLE ThreadHandle, - __in THREADINFOCLASS ThreadInformationClass, - __out_bcount(ThreadInformationLength) PVOID ThreadInformation, - __in ULONG ThreadInformationLength, - __out_opt PULONG ReturnLength + _In_ HANDLE ThreadHandle, + _In_ THREADINFOCLASS ThreadInformationClass, + _Out_writes_bytes_(ThreadInformationLength) PVOID ThreadInformation, + _In_ ULONG ThreadInformationLength, + _Out_opt_ PULONG ReturnLength ); NTKERNELAPI NTSTATUS NTAPI PsLookupProcessThreadByCid( - __in PCLIENT_ID ClientId, - __out_opt PEPROCESS *Process, - __out PETHREAD *Thread - ); - -NTKERNELAPI -PVOID -NTAPI -PsGetThreadWin32Thread( - __in PETHREAD Thread + _In_ PCLIENT_ID ClientId, + _Out_opt_ PEPROCESS *Process, + _Out_ PETHREAD *Thread ); typedef struct _EJOB *PEJOB; @@ -314,21 +307,21 @@ NTKERNELAPI PEJOB NTAPI PsGetProcessJob( - __in PEPROCESS Process + _In_ PEPROCESS Process ); NTKERNELAPI NTSTATUS NTAPI PsAcquireProcessExitSynchronization( - __in PEPROCESS Process + _In_ PEPROCESS Process ); NTKERNELAPI VOID NTAPI PsReleaseProcessExitSynchronization( - __in PEPROCESS Process + _In_ PEPROCESS Process ); // RTL @@ -339,13 +332,4 @@ PsReleaseProcessExitSynchronization( #define RTL_WALK_USER_MODE_STACK 0x00000001 #define RTL_WALK_VALID_FLAGS 0x00000001 -NTSYSAPI -ULONG -NTAPI -RtlWalkFrameChain( - __out PVOID *Callers, - __in ULONG Count, - __in ULONG Flags - ); - #endif diff --git a/KProcessHacker/main.c b/KProcessHacker/main.c index 31623234b278..c2696cdee21f 100644 --- a/KProcessHacker/main.c +++ b/KProcessHacker/main.c @@ -24,17 +24,17 @@ DRIVER_INITIALIZE DriverEntry; DRIVER_UNLOAD DriverUnload; -__drv_dispatchType(IRP_MJ_CREATE) DRIVER_DISPATCH KphDispatchCreate; -__drv_dispatchType(IRP_MJ_CLOSE) DRIVER_DISPATCH KphDispatchClose; +_Dispatch_type_(IRP_MJ_CREATE) DRIVER_DISPATCH KphDispatchCreate; +_Dispatch_type_(IRP_MJ_CLOSE) DRIVER_DISPATCH KphDispatchClose; ULONG KphpReadIntegerParameter( - __in_opt HANDLE KeyHandle, - __in PUNICODE_STRING ValueName, - __in ULONG DefaultValue + _In_opt_ HANDLE KeyHandle, + _In_ PUNICODE_STRING ValueName, + _In_ ULONG DefaultValue ); NTSTATUS KphpReadDriverParameters( - __in PUNICODE_STRING RegistryPath + _In_ PUNICODE_STRING RegistryPath ); #ifdef ALLOC_PRAGMA @@ -51,8 +51,8 @@ ULONG KphFeatures; KPH_PARAMETERS KphParameters; NTSTATUS DriverEntry( - __in PDRIVER_OBJECT DriverObject, - __in PUNICODE_STRING RegistryPath + _In_ PDRIVER_OBJECT DriverObject, + _In_ PUNICODE_STRING RegistryPath ) { NTSTATUS status; @@ -61,6 +61,8 @@ NTSTATUS DriverEntry( PAGED_CODE(); + ExInitializeDriverRuntime(DrvRtPoolNxOptIn); + KphDriverObject = DriverObject; if (!NT_SUCCESS(status = KphDynamicDataInitialization())) @@ -105,7 +107,7 @@ NTSTATUS DriverEntry( } VOID DriverUnload( - __in PDRIVER_OBJECT DriverObject + _In_ PDRIVER_OBJECT DriverObject ) { PAGED_CODE(); @@ -116,8 +118,8 @@ VOID DriverUnload( } NTSTATUS KphDispatchCreate( - __in PDEVICE_OBJECT DeviceObject, - __in PIRP Irp + _In_ PDEVICE_OBJECT DeviceObject, + _Inout_ PIRP Irp ) { NTSTATUS status = STATUS_SUCCESS; @@ -186,8 +188,8 @@ NTSTATUS KphDispatchCreate( } NTSTATUS KphDispatchClose( - __in PDEVICE_OBJECT DeviceObject, - __in PIRP Irp + _In_ PDEVICE_OBJECT DeviceObject, + _Inout_ PIRP Irp ) { NTSTATUS status = STATUS_SUCCESS; @@ -223,9 +225,9 @@ NTSTATUS KphDispatchClose( * \return The parameter value, or \a DefaultValue if the function failed. */ ULONG KphpReadIntegerParameter( - __in_opt HANDLE KeyHandle, - __in PUNICODE_STRING ValueName, - __in ULONG DefaultValue + _In_opt_ HANDLE KeyHandle, + _In_ PUNICODE_STRING ValueName, + _In_ ULONG DefaultValue ) { NTSTATUS status; @@ -267,7 +269,7 @@ ULONG KphpReadIntegerParameter( * \param RegistryPath The registry path of the driver. */ NTSTATUS KphpReadDriverParameters( - __in PUNICODE_STRING RegistryPath + _In_ PUNICODE_STRING RegistryPath ) { NTSTATUS status; @@ -329,8 +331,8 @@ NTSTATUS KphpReadDriverParameters( } NTSTATUS KpiGetFeatures( - __out PULONG Features, - __in KPROCESSOR_MODE AccessMode + _Out_ PULONG Features, + _In_ KPROCESSOR_MODE AccessMode ) { PAGED_CODE(); diff --git a/KProcessHacker/object.c b/KProcessHacker/object.c index f272a16f9826..134a4d36e6db 100644 --- a/KProcessHacker/object.c +++ b/KProcessHacker/object.c @@ -41,16 +41,16 @@ typedef struct _KPHP_ENUMERATE_PROCESS_HANDLES_CONTEXT } KPHP_ENUMERATE_PROCESS_HANDLES_CONTEXT, *PKPHP_ENUMERATE_PROCESS_HANDLES_CONTEXT; BOOLEAN KphpEnumerateProcessHandlesEnumCallback61( - __inout PHANDLE_TABLE_ENTRY HandleTableEntry, - __in HANDLE Handle, - __in PVOID Context + _Inout_ PHANDLE_TABLE_ENTRY HandleTableEntry, + _In_ HANDLE Handle, + _In_ PVOID Context ); BOOLEAN KphpEnumerateProcessHandlesEnumCallback( - __in PHANDLE_TABLE HandleTable, - __inout PHANDLE_TABLE_ENTRY HandleTableEntry, - __in HANDLE Handle, - __in PVOID Context + _In_ PHANDLE_TABLE HandleTable, + _Inout_ PHANDLE_TABLE_ENTRY HandleTableEntry, + _In_ HANDLE Handle, + _In_ PVOID Context ); #ifdef ALLOC_PRAGMA @@ -77,7 +77,7 @@ BOOLEAN KphpEnumerateProcessHandlesEnumCallback( * longer needed. */ PHANDLE_TABLE KphReferenceProcessHandleTable( - __in PEPROCESS Process + _In_ PEPROCESS Process ) { PHANDLE_TABLE handleTable = NULL; @@ -106,7 +106,7 @@ PHANDLE_TABLE KphReferenceProcessHandleTable( * \param Process A process object. */ VOID KphDereferenceProcessHandleTable( - __in PEPROCESS Process + _In_ PEPROCESS Process ) { PAGED_CODE(); @@ -115,8 +115,8 @@ VOID KphDereferenceProcessHandleTable( } VOID KphUnlockHandleTableEntry( - __in PHANDLE_TABLE HandleTable, - __in PHANDLE_TABLE_ENTRY HandleTableEntry + _In_ PHANDLE_TABLE HandleTable, + _In_ PHANDLE_TABLE_ENTRY HandleTableEntry ) { PEX_PUSH_LOCK handleContentionEvent; @@ -140,9 +140,9 @@ VOID KphUnlockHandleTableEntry( } BOOLEAN KphpEnumerateProcessHandlesEnumCallback61( - __inout PHANDLE_TABLE_ENTRY HandleTableEntry, - __in HANDLE Handle, - __in PVOID Context + _Inout_ PHANDLE_TABLE_ENTRY HandleTableEntry, + _In_ HANDLE Handle, + _In_ PVOID Context ) { PKPHP_ENUMERATE_PROCESS_HANDLES_CONTEXT context = Context; @@ -205,10 +205,10 @@ BOOLEAN KphpEnumerateProcessHandlesEnumCallback61( } BOOLEAN KphpEnumerateProcessHandlesEnumCallback( - __in PHANDLE_TABLE HandleTable, - __inout PHANDLE_TABLE_ENTRY HandleTableEntry, - __in HANDLE Handle, - __in PVOID Context + _In_ PHANDLE_TABLE HandleTable, + _Inout_ PHANDLE_TABLE_ENTRY HandleTableEntry, + _In_ HANDLE Handle, + _In_ PVOID Context ) { BOOLEAN result; @@ -232,11 +232,11 @@ BOOLEAN KphpEnumerateProcessHandlesEnumCallback( * \param AccessMode The mode in which to perform access checks. */ NTSTATUS KpiEnumerateProcessHandles( - __in HANDLE ProcessHandle, - __out_bcount(BufferLength) PVOID Buffer, - __in_opt ULONG BufferLength, - __out_opt PULONG ReturnLength, - __in KPROCESSOR_MODE AccessMode + _In_ HANDLE ProcessHandle, + _Out_writes_bytes_(BufferLength) PVOID Buffer, + _In_opt_ ULONG BufferLength, + _Out_opt_ PULONG ReturnLength, + _In_ KPROCESSOR_MODE AccessMode ) { NTSTATUS status; @@ -321,7 +321,7 @@ NTSTATUS KpiEnumerateProcessHandles( ObDereferenceObject(process); // Write the number of handles if we can. - if (BufferLength >= FIELD_OFFSET(KPH_PROCESS_HANDLE_INFORMATION, Handles)) + if (BufferLength >= (ULONG)FIELD_OFFSET(KPH_PROCESS_HANDLE_INFORMATION, Handles)) { if (AccessMode != KernelMode) { @@ -378,10 +378,10 @@ NTSTATUS KpiEnumerateProcessHandles( * \a Buffer. */ NTSTATUS KphQueryNameObject( - __in PVOID Object, - __out_bcount(BufferLength) POBJECT_NAME_INFORMATION Buffer, - __in ULONG BufferLength, - __out PULONG ReturnLength + _In_ PVOID Object, + _Out_writes_bytes_(BufferLength) POBJECT_NAME_INFORMATION Buffer, + _In_ ULONG BufferLength, + _Out_ PULONG ReturnLength ) { NTSTATUS status; @@ -429,10 +429,10 @@ NTSTATUS KphQueryNameObject( * \a Buffer. */ NTSTATUS KphQueryNameFileObject( - __in PFILE_OBJECT FileObject, - __out_bcount(BufferLength) POBJECT_NAME_INFORMATION Buffer, - __in ULONG BufferLength, - __out PULONG ReturnLength + _In_ PFILE_OBJECT FileObject, + _Out_writes_bytes_(BufferLength) POBJECT_NAME_INFORMATION Buffer, + _In_ ULONG BufferLength, + _Out_ PULONG ReturnLength ) { NTSTATUS status = STATUS_SUCCESS; @@ -568,13 +568,13 @@ NTSTATUS KphQueryNameFileObject( * \param AccessMode The mode in which to perform access checks. */ NTSTATUS KpiQueryInformationObject( - __in HANDLE ProcessHandle, - __in HANDLE Handle, - __in KPH_OBJECT_INFORMATION_CLASS ObjectInformationClass, - __out_bcount(ObjectInformationLength) PVOID ObjectInformation, - __in ULONG ObjectInformationLength, - __out_opt PULONG ReturnLength, - __in KPROCESSOR_MODE AccessMode + _In_ HANDLE ProcessHandle, + _In_ HANDLE Handle, + _In_ KPH_OBJECT_INFORMATION_CLASS ObjectInformationClass, + _Out_writes_bytes_(ObjectInformationLength) PVOID ObjectInformation, + _In_ ULONG ObjectInformationLength, + _Out_opt_ PULONG ReturnLength, + _In_ KPROCESSOR_MODE AccessMode ) { NTSTATUS status; @@ -1145,12 +1145,12 @@ NTSTATUS KpiQueryInformationObject( * \param AccessMode The mode in which to perform access checks. */ NTSTATUS KpiSetInformationObject( - __in HANDLE ProcessHandle, - __in HANDLE Handle, - __in KPH_OBJECT_INFORMATION_CLASS ObjectInformationClass, - __in_bcount(ObjectInformationLength) PVOID ObjectInformation, - __in ULONG ObjectInformationLength, - __in KPROCESSOR_MODE AccessMode + _In_ HANDLE ProcessHandle, + _In_ HANDLE Handle, + _In_ KPH_OBJECT_INFORMATION_CLASS ObjectInformationClass, + _In_reads_bytes_(ObjectInformationLength) PVOID ObjectInformation, + _In_ ULONG ObjectInformationLength, + _In_ KPROCESSOR_MODE AccessMode ) { NTSTATUS status; @@ -1249,11 +1249,11 @@ NTSTATUS KpiSetInformationObject( } NTSTATUS KphOpenNamedObject( - __out PHANDLE ObjectHandle, - __in ACCESS_MASK DesiredAccess, - __in POBJECT_ATTRIBUTES ObjectAttributes, - __in POBJECT_TYPE ObjectType, - __in KPROCESSOR_MODE AccessMode + _Out_ PHANDLE ObjectHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_ POBJECT_TYPE ObjectType, + _In_ KPROCESSOR_MODE AccessMode ) { NTSTATUS status; diff --git a/KProcessHacker/process.c b/KProcessHacker/process.c index c0aa6d1b63d2..17532e91dd5c 100644 --- a/KProcessHacker/process.c +++ b/KProcessHacker/process.c @@ -48,12 +48,12 @@ * \param AccessMode The mode in which to perform access checks. */ NTSTATUS KpiOpenProcess( - __out PHANDLE ProcessHandle, - __in ACCESS_MASK DesiredAccess, - __in PCLIENT_ID ClientId, - __in_opt KPH_KEY Key, - __in PKPH_CLIENT Client, - __in KPROCESSOR_MODE AccessMode + _Out_ PHANDLE ProcessHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ PCLIENT_ID ClientId, + _In_opt_ KPH_KEY Key, + _In_ PKPH_CLIENT Client, + _In_ KPROCESSOR_MODE AccessMode ) { NTSTATUS status; @@ -119,29 +119,29 @@ NTSTATUS KpiOpenProcess( KernelMode, &processHandle ); - } - - ObDereferenceObject(process); - if (NT_SUCCESS(status)) - { - if (AccessMode != KernelMode) + if (NT_SUCCESS(status)) { - __try + if (AccessMode != KernelMode) { - *ProcessHandle = processHandle; + __try + { + *ProcessHandle = processHandle; + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + status = GetExceptionCode(); + } } - __except (EXCEPTION_EXECUTE_HANDLER) + else { - status = GetExceptionCode(); + *ProcessHandle = processHandle; } } - else - { - *ProcessHandle = processHandle; - } } + ObDereferenceObject(process); + return status; } @@ -160,12 +160,12 @@ NTSTATUS KpiOpenProcess( * \param AccessMode The mode in which to perform access checks. */ NTSTATUS KpiOpenProcessToken( - __in HANDLE ProcessHandle, - __in ACCESS_MASK DesiredAccess, - __out PHANDLE TokenHandle, - __in_opt KPH_KEY Key, - __in PKPH_CLIENT Client, - __in KPROCESSOR_MODE AccessMode + _In_ HANDLE ProcessHandle, + _In_ ACCESS_MASK DesiredAccess, + _Out_ PHANDLE TokenHandle, + _In_opt_ KPH_KEY Key, + _In_ PKPH_CLIENT Client, + _In_ KPROCESSOR_MODE AccessMode ) { NTSTATUS status; @@ -218,6 +218,25 @@ NTSTATUS KpiOpenProcessToken( KernelMode, &tokenHandle ); + + if (NT_SUCCESS(status)) + { + if (AccessMode != KernelMode) + { + __try + { + *TokenHandle = tokenHandle; + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + status = GetExceptionCode(); + } + } + else + { + *TokenHandle = tokenHandle; + } + } } PsDereferencePrimaryToken(primaryToken); @@ -229,25 +248,6 @@ NTSTATUS KpiOpenProcessToken( ObDereferenceObject(process); - if (NT_SUCCESS(status)) - { - if (AccessMode != KernelMode) - { - __try - { - *TokenHandle = tokenHandle; - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - status = GetExceptionCode(); - } - } - else - { - *TokenHandle = tokenHandle; - } - } - return status; } @@ -260,16 +260,16 @@ NTSTATUS KpiOpenProcessToken( * \param AccessMode The mode in which to perform access checks. */ NTSTATUS KpiOpenProcessJob( - __in HANDLE ProcessHandle, - __in ACCESS_MASK DesiredAccess, - __out PHANDLE JobHandle, - __in KPROCESSOR_MODE AccessMode + _In_ HANDLE ProcessHandle, + _In_ ACCESS_MASK DesiredAccess, + _Out_ PHANDLE JobHandle, + _In_ KPROCESSOR_MODE AccessMode ) { NTSTATUS status; PEPROCESS process; PEJOB job; - HANDLE jobHandle = NULL; + HANDLE jobHandle; PAGED_CODE(); @@ -310,32 +310,32 @@ NTSTATUS KpiOpenProcessJob( AccessMode, &jobHandle ); - } - else - { - status = STATUS_NOT_FOUND; - } - ObDereferenceObject(process); - - if (NT_SUCCESS(status)) - { - if (AccessMode != KernelMode) + if (NT_SUCCESS(status)) { - __try + if (AccessMode != KernelMode) { - *JobHandle = jobHandle; + __try + { + *JobHandle = jobHandle; + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + status = GetExceptionCode(); + } } - __except (EXCEPTION_EXECUTE_HANDLER) + else { - status = GetExceptionCode(); + *JobHandle = jobHandle; } } - else - { - *JobHandle = jobHandle; - } } + else + { + status = STATUS_NOT_FOUND; + } + + ObDereferenceObject(process); return status; } @@ -352,11 +352,11 @@ NTSTATUS KpiOpenProcessJob( * \param AccessMode The mode in which to perform access checks. */ NTSTATUS KpiTerminateProcess( - __in HANDLE ProcessHandle, - __in NTSTATUS ExitStatus, - __in_opt KPH_KEY Key, - __in PKPH_CLIENT Client, - __in KPROCESSOR_MODE AccessMode + _In_ HANDLE ProcessHandle, + _In_ NTSTATUS ExitStatus, + _In_opt_ KPH_KEY Key, + _In_ PKPH_CLIENT Client, + _In_ KPROCESSOR_MODE AccessMode ) { NTSTATUS status; @@ -420,12 +420,12 @@ NTSTATUS KpiTerminateProcess( * \param AccessMode The mode in which to perform access checks. */ NTSTATUS KpiQueryInformationProcess( - __in HANDLE ProcessHandle, - __in KPH_PROCESS_INFORMATION_CLASS ProcessInformationClass, - __out_bcount(ProcessInformationLength) PVOID ProcessInformation, - __in ULONG ProcessInformationLength, - __out_opt PULONG ReturnLength, - __in KPROCESSOR_MODE AccessMode + _In_ HANDLE ProcessHandle, + _In_ KPH_PROCESS_INFORMATION_CLASS ProcessInformationClass, + _Out_writes_bytes_(ProcessInformationLength) PVOID ProcessInformation, + _In_ ULONG ProcessInformationLength, + _Out_opt_ PULONG ReturnLength, + _In_ KPROCESSOR_MODE AccessMode ) { NTSTATUS status; @@ -512,11 +512,11 @@ NTSTATUS KpiQueryInformationProcess( * \param AccessMode The mode in which to perform access checks. */ NTSTATUS KpiSetInformationProcess( - __in HANDLE ProcessHandle, - __in KPH_PROCESS_INFORMATION_CLASS ProcessInformationClass, - __in_bcount(ProcessInformationLength) PVOID ProcessInformation, - __in ULONG ProcessInformationLength, - __in KPROCESSOR_MODE AccessMode + _In_ HANDLE ProcessHandle, + _In_ KPH_PROCESS_INFORMATION_CLASS ProcessInformationClass, + _In_reads_bytes_(ProcessInformationLength) PVOID ProcessInformation, + _In_ ULONG ProcessInformationLength, + _In_ KPROCESSOR_MODE AccessMode ) { NTSTATUS status; diff --git a/KProcessHacker/qrydrv.c b/KProcessHacker/qrydrv.c index d2cb31b8ba18..641779fa0a52 100644 --- a/KProcessHacker/qrydrv.c +++ b/KProcessHacker/qrydrv.c @@ -22,8 +22,8 @@ #include VOID KphpCopyInfoUnicodeString( - __out PVOID Information, - __in_opt PUNICODE_STRING UnicodeString + _Out_ PVOID Information, + _In_opt_ PUNICODE_STRING UnicodeString ); #ifdef ALLOC_PRAGMA @@ -33,10 +33,10 @@ VOID KphpCopyInfoUnicodeString( #endif NTSTATUS KpiOpenDriver( - __out PHANDLE DriverHandle, - __in ACCESS_MASK DesiredAccess, - __in POBJECT_ATTRIBUTES ObjectAttributes, - __in KPROCESSOR_MODE AccessMode + _Out_ PHANDLE DriverHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_ KPROCESSOR_MODE AccessMode ) { PAGED_CODE(); @@ -51,12 +51,12 @@ NTSTATUS KpiOpenDriver( } NTSTATUS KpiQueryInformationDriver( - __in HANDLE DriverHandle, - __in DRIVER_INFORMATION_CLASS DriverInformationClass, - __out_bcount(DriverInformationLength) PVOID DriverInformation, - __in ULONG DriverInformationLength, - __out_opt PULONG ReturnLength, - __in KPROCESSOR_MODE AccessMode + _In_ HANDLE DriverHandle, + _In_ DRIVER_INFORMATION_CLASS DriverInformationClass, + _Out_writes_bytes_(DriverInformationLength) PVOID DriverInformation, + _In_ ULONG DriverInformationLength, + _Out_opt_ PULONG ReturnLength, + _In_ KPROCESSOR_MODE AccessMode ) { NTSTATUS status = STATUS_SUCCESS; @@ -211,8 +211,8 @@ NTSTATUS KpiQueryInformationDriver( } VOID KphpCopyInfoUnicodeString( - __out PVOID Information, - __in_opt PUNICODE_STRING UnicodeString + _Out_ PVOID Information, + _In_opt_ PUNICODE_STRING UnicodeString ) { PUNICODE_STRING targetUnicodeString = Information; diff --git a/KProcessHacker/sign.cmd b/KProcessHacker/sign.cmd deleted file mode 100644 index 90e2927feed0..000000000000 --- a/KProcessHacker/sign.cmd +++ /dev/null @@ -1,7 +0,0 @@ -@echo off -set PHBASE=.. -set SIGN_TIMESTAMP=1 -copy bin\i386\kprocesshacker.sys bin-signed\i386\kprocesshacker.sys -copy bin\amd64\kprocesshacker.sys bin-signed\amd64\kprocesshacker.sys -call ..\build\internal\sign.cmd bin-signed\i386\kprocesshacker.sys kmcs -call ..\build\internal\sign.cmd bin-signed\amd64\kprocesshacker.sys kmcs diff --git a/KProcessHacker/sources.inc b/KProcessHacker/sources.inc deleted file mode 100644 index d50fe7368fa1..000000000000 --- a/KProcessHacker/sources.inc +++ /dev/null @@ -1,28 +0,0 @@ -TARGETTYPE=DRIVER - -!IF !DEFINED(TARGETNAME) -TARGETNAME=kprocesshacker -!ENDIF - -!IF !DEFINED(TARGETPATH) -TARGETPATH=..\bin -!ENDIF - -TARGETLIBS=$(TARGETLIBS) $(DDK_LIB_PATH)\ksecdd.lib - -INCLUDES=$(DDK_INC_PATH);..\include;..\..\phnt\include;..\..\phlib\include -LIBS=%BUILD%\lib - -SOURCES= \ - ..\main.c \ - ..\devctrl.c \ - ..\dyndata.c \ - ..\dynimp.c \ - ..\object.c \ - ..\process.c \ - ..\qrydrv.c \ - ..\thread.c \ - ..\util.c \ - ..\verify.c \ - ..\vm.c \ - ..\resource.rc diff --git a/KProcessHacker/thread.c b/KProcessHacker/thread.c index da8154c0c5d0..15ccd26705b8 100644 --- a/KProcessHacker/thread.c +++ b/KProcessHacker/thread.c @@ -37,11 +37,11 @@ typedef struct _CAPTURE_BACKTRACE_THREAD_CONTEXT KKERNEL_ROUTINE KphpCaptureStackBackTraceThreadSpecialApc; VOID KphpCaptureStackBackTraceThreadSpecialApc( - __in PRKAPC Apc, - __inout PKNORMAL_ROUTINE *NormalRoutine, - __inout PVOID *NormalContext, - __inout PVOID *SystemArgument1, - __inout PVOID *SystemArgument2 + _In_ PRKAPC Apc, + _Inout_opt_ PKNORMAL_ROUTINE *NormalRoutine, + _Inout_opt_ PVOID *NormalContext, + _Inout_ PVOID *SystemArgument1, + _Inout_ PVOID *SystemArgument2 ); #ifdef ALLOC_PRAGMA @@ -70,19 +70,19 @@ VOID KphpCaptureStackBackTraceThreadSpecialApc( * \param AccessMode The mode in which to perform access checks. */ NTSTATUS KpiOpenThread( - __out PHANDLE ThreadHandle, - __in ACCESS_MASK DesiredAccess, - __in PCLIENT_ID ClientId, - __in_opt KPH_KEY Key, - __in PKPH_CLIENT Client, - __in KPROCESSOR_MODE AccessMode + _Out_ PHANDLE ThreadHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ PCLIENT_ID ClientId, + _In_opt_ KPH_KEY Key, + _In_ PKPH_CLIENT Client, + _In_ KPROCESSOR_MODE AccessMode ) { NTSTATUS status; CLIENT_ID clientId; PETHREAD thread; KPH_KEY_LEVEL requiredKeyLevel; - HANDLE threadHandle; + HANDLE threadHandle = NULL; PAGED_CODE(); @@ -170,10 +170,10 @@ NTSTATUS KpiOpenThread( * \param AccessMode The mode in which to perform access checks. */ NTSTATUS KpiOpenThreadProcess( - __in HANDLE ThreadHandle, - __in ACCESS_MASK DesiredAccess, - __out PHANDLE ProcessHandle, - __in KPROCESSOR_MODE AccessMode + _In_ HANDLE ThreadHandle, + _In_ ACCESS_MASK DesiredAccess, + _Out_ PHANDLE ProcessHandle, + _In_ KPROCESSOR_MODE AccessMode ) { NTSTATUS status; @@ -257,11 +257,11 @@ NTSTATUS KpiOpenThreadProcess( * \return The number of frames captured. */ ULONG KphCaptureStackBackTrace( - __in ULONG FramesToSkip, - __in ULONG FramesToCapture, - __in_opt ULONG Flags, - __out_ecount(FramesToCapture) PVOID *BackTrace, - __out_opt PULONG BackTraceHash + _In_ ULONG FramesToSkip, + _In_ ULONG FramesToCapture, + _In_opt_ ULONG Flags, + _Out_writes_(FramesToCapture) PVOID *BackTrace, + _Out_opt_ PULONG BackTraceHash ) { PVOID backTrace[MAX_STACK_DEPTH]; @@ -320,13 +320,13 @@ ULONG KphCaptureStackBackTrace( * \return The number of frames captured. */ NTSTATUS KphCaptureStackBackTraceThread( - __in PETHREAD Thread, - __in ULONG FramesToSkip, - __in ULONG FramesToCapture, - __out_ecount(FramesToCapture) PVOID *BackTrace, - __out_opt PULONG CapturedFrames, - __out_opt PULONG BackTraceHash, - __in KPROCESSOR_MODE AccessMode + _In_ PETHREAD Thread, + _In_ ULONG FramesToSkip, + _In_ ULONG FramesToCapture, + _Out_writes_(FramesToCapture) PVOID *BackTrace, + _Out_opt_ PULONG CapturedFrames, + _Out_opt_ PULONG BackTraceHash, + _In_ KPROCESSOR_MODE AccessMode ) { NTSTATUS status = STATUS_SUCCESS; @@ -490,11 +490,11 @@ NTSTATUS KphCaptureStackBackTraceThread( } VOID KphpCaptureStackBackTraceThreadSpecialApc( - __in PRKAPC Apc, - __inout PKNORMAL_ROUTINE *NormalRoutine, - __inout PVOID *NormalContext, - __inout PVOID *SystemArgument1, - __inout PVOID *SystemArgument2 + _In_ PRKAPC Apc, + _Inout_opt_ PKNORMAL_ROUTINE *NormalRoutine, + _Inout_opt_ PVOID *NormalContext, + _Inout_ PVOID *SystemArgument1, + _Inout_ PVOID *SystemArgument2 ) { PCAPTURE_BACKTRACE_THREAD_CONTEXT context = *SystemArgument1; @@ -530,13 +530,13 @@ VOID KphpCaptureStackBackTraceThreadSpecialApc( * \return The number of frames captured. */ NTSTATUS KpiCaptureStackBackTraceThread( - __in HANDLE ThreadHandle, - __in ULONG FramesToSkip, - __in ULONG FramesToCapture, - __out_ecount(FramesToCapture) PVOID *BackTrace, - __out_opt PULONG CapturedFrames, - __out_opt PULONG BackTraceHash, - __in KPROCESSOR_MODE AccessMode + _In_ HANDLE ThreadHandle, + _In_ ULONG FramesToSkip, + _In_ ULONG FramesToCapture, + _Out_writes_(FramesToCapture) PVOID *BackTrace, + _Out_opt_ PULONG CapturedFrames, + _Out_opt_ PULONG BackTraceHash, + _In_ KPROCESSOR_MODE AccessMode ) { NTSTATUS status = STATUS_SUCCESS; @@ -582,12 +582,12 @@ NTSTATUS KpiCaptureStackBackTraceThread( * \param AccessMode The mode in which to perform access checks. */ NTSTATUS KpiQueryInformationThread( - __in HANDLE ThreadHandle, - __in KPH_THREAD_INFORMATION_CLASS ThreadInformationClass, - __out_bcount(ProcessInformationLength) PVOID ThreadInformation, - __in ULONG ThreadInformationLength, - __out_opt PULONG ReturnLength, - __in KPROCESSOR_MODE AccessMode + _In_ HANDLE ThreadHandle, + _In_ KPH_THREAD_INFORMATION_CLASS ThreadInformationClass, + _Out_writes_bytes_(ThreadInformationLength) PVOID ThreadInformation, + _In_ ULONG ThreadInformationLength, + _Out_opt_ PULONG ReturnLength, + _In_ KPROCESSOR_MODE AccessMode ) { NTSTATUS status; @@ -665,11 +665,11 @@ NTSTATUS KpiQueryInformationThread( * \param AccessMode The mode in which to perform access checks. */ NTSTATUS KpiSetInformationThread( - __in HANDLE ThreadHandle, - __in KPH_THREAD_INFORMATION_CLASS ThreadInformationClass, - __in_bcount(ThreadInformationLength) PVOID ThreadInformation, - __in ULONG ThreadInformationLength, - __in KPROCESSOR_MODE AccessMode + _In_ HANDLE ThreadHandle, + _In_ KPH_THREAD_INFORMATION_CLASS ThreadInformationClass, + _In_reads_bytes_(ThreadInformationLength) PVOID ThreadInformation, + _In_ ULONG ThreadInformationLength, + _In_ KPROCESSOR_MODE AccessMode ) { NTSTATUS status; diff --git a/KProcessHacker/util.c b/KProcessHacker/util.c index b30ae7e6bcd6..d372284bda48 100644 --- a/KProcessHacker/util.c +++ b/KProcessHacker/util.c @@ -30,7 +30,7 @@ #endif VOID KphFreeCapturedUnicodeString( - __in PUNICODE_STRING CapturedUnicodeString + _In_ PUNICODE_STRING CapturedUnicodeString ) { PAGED_CODE(); @@ -40,8 +40,8 @@ VOID KphFreeCapturedUnicodeString( } NTSTATUS KphCaptureUnicodeString( - __in PUNICODE_STRING UnicodeString, - __out PUNICODE_STRING CapturedUnicodeString + _In_ PUNICODE_STRING UnicodeString, + _Out_ PUNICODE_STRING CapturedUnicodeString ) { UNICODE_STRING unicodeString; @@ -107,7 +107,7 @@ NTSTATUS KphCaptureUnicodeString( * the kernel modules. The structure must be freed with the tag 'ThpK'. */ NTSTATUS KphEnumerateSystemModules( - __out PRTL_PROCESS_MODULES *Modules + _Out_ PRTL_PROCESS_MODULES *Modules ) { NTSTATUS status; @@ -162,8 +162,8 @@ NTSTATUS KphEnumerateSystemModules( * \param Length The number of bytes in the address range. */ NTSTATUS KphValidateAddressForSystemModules( - __in PVOID Address, - __in SIZE_T Length + _In_ PVOID Address, + _In_ SIZE_T Length ) { NTSTATUS status; @@ -214,9 +214,9 @@ NTSTATUS KphValidateAddressForSystemModules( * section. The structure must be freed with the tag 'ThpK'. */ NTSTATUS KphGetProcessMappedFileName( - __in HANDLE ProcessHandle, - __in PVOID BaseAddress, - __out PUNICODE_STRING *FileName + _In_ HANDLE ProcessHandle, + _In_ PVOID BaseAddress, + _Out_ PUNICODE_STRING *FileName ) { NTSTATUS status; diff --git a/KProcessHacker/verify.c b/KProcessHacker/verify.c index 08ccbf15d82f..3d097c62128d 100644 --- a/KProcessHacker/verify.c +++ b/KProcessHacker/verify.c @@ -25,7 +25,7 @@ #define FILE_MAX_SIZE (32 * 1024 * 1024) // 32 MB VOID KphpBackoffKey( - __in PKPH_CLIENT Client + _In_ PKPH_CLIENT Client ); static UCHAR KphpTrustedPublicKey[] = @@ -49,9 +49,9 @@ static UCHAR KphpTrustedPublicKey[] = #endif NTSTATUS KphHashFile( - __in PUNICODE_STRING FileName, - __out PVOID *Hash, - __out PULONG HashSize + _In_ PUNICODE_STRING FileName, + _Out_ PVOID *Hash, + _Out_ PULONG HashSize ) { NTSTATUS status; @@ -192,9 +192,9 @@ NTSTATUS KphHashFile( } NTSTATUS KphVerifyFile( - __in PUNICODE_STRING FileName, - __in_bcount(SignatureSize) PUCHAR Signature, - __in ULONG SignatureSize + _In_ PUNICODE_STRING FileName, + _In_reads_bytes_(SignatureSize) PUCHAR Signature, + _In_ ULONG SignatureSize ) { NTSTATUS status; @@ -240,10 +240,10 @@ NTSTATUS KphVerifyFile( } VOID KphVerifyClient( - __inout PKPH_CLIENT Client, - __in PVOID CodeAddress, - __in_bcount(SignatureSize) PUCHAR Signature, - __in ULONG SignatureSize + _Inout_ PKPH_CLIENT Client, + _In_ PVOID CodeAddress, + _In_reads_bytes_(SignatureSize) PUCHAR Signature, + _In_ ULONG SignatureSize ) { NTSTATUS status; @@ -311,10 +311,10 @@ VOID KphVerifyClient( } NTSTATUS KpiVerifyClient( - __in PVOID CodeAddress, - __in_bcount(SignatureSize) PUCHAR Signature, - __in ULONG SignatureSize, - __in PKPH_CLIENT Client + _In_ PVOID CodeAddress, + _In_reads_bytes_(SignatureSize) PUCHAR Signature, + _In_ ULONG SignatureSize, + _In_ PKPH_CLIENT Client ) { PUCHAR signature; @@ -354,7 +354,7 @@ NTSTATUS KpiVerifyClient( } VOID KphGenerateKeysClient( - __inout PKPH_CLIENT Client + _Inout_ PKPH_CLIENT Client ) { ULONGLONG interruptTime; @@ -389,9 +389,9 @@ VOID KphGenerateKeysClient( } NTSTATUS KphRetrieveKeyViaApc( - __inout PKPH_CLIENT Client, - __in KPH_KEY_LEVEL KeyLevel, - __inout PIRP Irp + _Inout_ PKPH_CLIENT Client, + _In_ KPH_KEY_LEVEL KeyLevel, + _Inout_ PIRP Irp ) { PIO_APC_ROUTINE userApcRoutine; @@ -440,10 +440,10 @@ NTSTATUS KphRetrieveKeyViaApc( } NTSTATUS KphValidateKey( - __in KPH_KEY_LEVEL RequiredKeyLevel, - __in_opt KPH_KEY Key, - __in PKPH_CLIENT Client, - __in KPROCESSOR_MODE AccessMode + _In_ KPH_KEY_LEVEL RequiredKeyLevel, + _In_opt_ KPH_KEY Key, + _In_ PKPH_CLIENT Client, + _In_ KPROCESSOR_MODE AccessMode ) { PAGED_CODE(); @@ -478,7 +478,7 @@ NTSTATUS KphValidateKey( } VOID KphpBackoffKey( - __in PKPH_CLIENT Client + _In_ PKPH_CLIENT Client ) { LARGE_INTEGER backoffTime; diff --git a/KProcessHacker/vm.c b/KProcessHacker/vm.c index 41dc7ef8a85f..63e4e2d0657c 100644 --- a/KProcessHacker/vm.c +++ b/KProcessHacker/vm.c @@ -22,9 +22,9 @@ #include ULONG KphpGetCopyExceptionInfo( - __in PEXCEPTION_POINTERS ExceptionInfo, - __out PBOOLEAN HaveBadAddress, - __out PULONG_PTR BadAddress + _In_ PEXCEPTION_POINTERS ExceptionInfo, + _Out_ PBOOLEAN HaveBadAddress, + _Out_ PULONG_PTR BadAddress ); #ifdef ALLOC_PRAGMA @@ -38,9 +38,9 @@ ULONG KphpGetCopyExceptionInfo( #define KPH_POOL_COPY_THRESHOLD 0x3ff ULONG KphpGetCopyExceptionInfo( - __in PEXCEPTION_POINTERS ExceptionInfo, - __out PBOOLEAN HaveBadAddress, - __out PULONG_PTR BadAddress + _In_ PEXCEPTION_POINTERS ExceptionInfo, + _Out_ PBOOLEAN HaveBadAddress, + _Out_ PULONG_PTR BadAddress ) { PEXCEPTION_RECORD exceptionRecord; @@ -75,13 +75,13 @@ ULONG KphpGetCopyExceptionInfo( * \param ReturnLength A variable which receives the number of bytes copied. */ NTSTATUS KphCopyVirtualMemory( - __in PEPROCESS FromProcess, - __in PVOID FromAddress, - __in PEPROCESS ToProcess, - __in PVOID ToAddress, - __in SIZE_T BufferLength, - __in KPROCESSOR_MODE AccessMode, - __out PSIZE_T ReturnLength + _In_ PEPROCESS FromProcess, + _In_ PVOID FromAddress, + _In_ PEPROCESS ToProcess, + _In_ PVOID ToAddress, + _In_ SIZE_T BufferLength, + _In_ KPROCESSOR_MODE AccessMode, + _Out_ PSIZE_T ReturnLength ) { UCHAR stackBuffer[KPH_STACK_COPY_BYTES]; @@ -311,14 +311,14 @@ NTSTATUS KphCopyVirtualMemory( * \param AccessMode The mode in which to perform access checks. */ NTSTATUS KpiReadVirtualMemoryUnsafe( - __in_opt HANDLE ProcessHandle, - __in PVOID BaseAddress, - __out_bcount(BufferSize) PVOID Buffer, - __in SIZE_T BufferSize, - __out_opt PSIZE_T NumberOfBytesRead, - __in_opt KPH_KEY Key, - __in PKPH_CLIENT Client, - __in KPROCESSOR_MODE AccessMode + _In_opt_ HANDLE ProcessHandle, + _In_ PVOID BaseAddress, + _Out_writes_bytes_(BufferSize) PVOID Buffer, + _In_ SIZE_T BufferSize, + _Out_opt_ PSIZE_T NumberOfBytesRead, + _In_opt_ KPH_KEY Key, + _In_ PKPH_CLIENT Client, + _In_ KPROCESSOR_MODE AccessMode ) { NTSTATUS status; From c68a3fc2de37ef39bc445fbae42130c82c717079 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 6 Oct 2017 18:04:29 +1100 Subject: [PATCH 0468/2058] UserNotes: Fix affinity type on 64bit --- plugins/UserNotes/db.c | 2 +- plugins/UserNotes/db.h | 2 +- plugins/UserNotes/main.c | 10 +++++----- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/plugins/UserNotes/db.c b/plugins/UserNotes/db.c index 6a7b2b9082ac..76de395f4e98 100644 --- a/plugins/UserNotes/db.c +++ b/plugins/UserNotes/db.c @@ -307,7 +307,7 @@ NTSTATUS LoadDb( PhStringToInteger64(&affinityMask->sr, 10, &affinityInteger); - object->AffinityMask = (ULONG)affinityInteger; + object->AffinityMask = (ULONG_PTR)affinityInteger; } PhClearReference(&tag); diff --git a/plugins/UserNotes/db.h b/plugins/UserNotes/db.h index bf8018c4b9f2..4c88fe239df5 100644 --- a/plugins/UserNotes/db.h +++ b/plugins/UserNotes/db.h @@ -43,7 +43,7 @@ typedef struct _DB_OBJECT ULONG IoPriorityPlusOne; COLORREF BackColor; BOOLEAN Collapse; - ULONG AffinityMask; + ULONG_PTR AffinityMask; } DB_OBJECT, *PDB_OBJECT; VOID InitializeDb( diff --git a/plugins/UserNotes/main.c b/plugins/UserNotes/main.c index e3c8e0deb96f..409f92957f66 100644 --- a/plugins/UserNotes/main.c +++ b/plugins/UserNotes/main.c @@ -171,12 +171,12 @@ PPH_STRING SaveCustomColors( return PhFinalStringBuilderString(&stringBuilder); } -ULONG GetProcessAffinity( +ULONG_PTR GetProcessAffinity( _In_ HANDLE ProcessId ) { HANDLE processHandle; - ULONG affinityMask = 0; + ULONG_PTR affinityMask = 0; PROCESS_BASIC_INFORMATION basicInfo; if (NT_SUCCESS(PhOpenProcess( @@ -190,7 +190,7 @@ ULONG GetProcessAffinity( &basicInfo ))) { - affinityMask = (ULONG)basicInfo.AffinityMask; + affinityMask = basicInfo.AffinityMask; } NtClose(processHandle); @@ -646,9 +646,9 @@ VOID NTAPI MenuHookCallback( if (object = FindDbObjectForProcess(processItem, INTENT_PROCESS_AFFINITY)) { // Update the process affinity in our database (if the database values are different). - if (object->AffinityMask != (ULONG)newAffinityMask) + if (object->AffinityMask != newAffinityMask) { - object->AffinityMask = (ULONG)newAffinityMask; + object->AffinityMask = newAffinityMask; changed = TRUE; } } From 3f9e8efe6ae62db6e9ed6cd3e424cd1df826893b Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 8 Oct 2017 16:08:39 +1100 Subject: [PATCH 0469/2058] peview: Fix searching pdb tab RVA --- tools/peview/pdbprp.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tools/peview/pdbprp.c b/tools/peview/pdbprp.c index 5f232ff44d79..438436d75740 100644 --- a/tools/peview/pdbprp.c +++ b/tools/peview/pdbprp.c @@ -883,6 +883,12 @@ BOOLEAN PvSymbolTreeFilterCallback( return TRUE; } + if (node->Pointer[0]) + { + if (WordMatchStringZ(context, node->Pointer)) + return TRUE; + } + return FALSE; } From 485ff5b6888cb84ffd6127ce551c56a1bde92de7 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 8 Oct 2017 16:09:34 +1100 Subject: [PATCH 0470/2058] Setup: FIx multiple desktop icons --- .../CustomSetupTool/CustomSetupTool/appsup.c | 25 ++++++- .../CustomSetupTool/include/appsup.h | 3 +- tools/CustomSetupTool/CustomSetupTool/setup.c | 68 +++++++++++++------ 3 files changed, 74 insertions(+), 22 deletions(-) diff --git a/tools/CustomSetupTool/CustomSetupTool/appsup.c b/tools/CustomSetupTool/CustomSetupTool/appsup.c index a4c317b4f8ee..51e3eb7de171 100644 --- a/tools/CustomSetupTool/CustomSetupTool/appsup.c +++ b/tools/CustomSetupTool/CustomSetupTool/appsup.c @@ -21,6 +21,8 @@ #include #include #include +#include +#include VOID ExtractResourceToFile( _In_ PWSTR Resource, @@ -349,13 +351,15 @@ BOOLEAN ConnectionAvailable(VOID) } VOID SetupCreateLink( - _In_ PWSTR LinkFilePath, + _In_ PWSTR AppUserModelId, + _In_ PWSTR LinkFilePath, _In_ PWSTR FilePath, _In_ PWSTR FileParentDir ) { IShellLink* shellLinkPtr = NULL; IPersistFile* persistFilePtr = NULL; + IPropertyStore* propertyStorePtr; if (FAILED(CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, &IID_IShellLink, &shellLinkPtr))) goto CleanupExit; @@ -363,9 +367,28 @@ VOID SetupCreateLink( if (FAILED(IShellLinkW_QueryInterface(shellLinkPtr, &IID_IPersistFile, &persistFilePtr))) goto CleanupExit; + if (SUCCEEDED(IShellLinkW_QueryInterface(shellLinkPtr, &IID_IPropertyStore, &propertyStorePtr))) + { + PROPVARIANT appIdPropVar; + + PropVariantInit(&appIdPropVar); + + appIdPropVar.vt = VT_BSTR; + appIdPropVar.bstrVal = SysAllocString(AppUserModelId); + + if (SUCCEEDED(IPropertyStore_SetValue(propertyStorePtr, &PKEY_AppUserModel_ID, &appIdPropVar))) + { + IPropertyStore_Commit(propertyStorePtr); + } + + PropVariantClear(&appIdPropVar); + IPropertyStore_Release(propertyStorePtr); + } + // Load existing shell item if it exists... //IPersistFile_Load(persistFilePtr, LinkFilePath, STGM_READ) //IShellLinkW_SetDescription(shellLinkPtr, FileComment); + //IShellLinkW_SetHotkey(shellLinkPtr, MAKEWORD(VK_END, HOTKEYF_CONTROL | HOTKEYF_ALT)); IShellLinkW_SetWorkingDirectory(shellLinkPtr, FileParentDir); IShellLinkW_SetIconLocation(shellLinkPtr, FilePath, 0); diff --git a/tools/CustomSetupTool/CustomSetupTool/include/appsup.h b/tools/CustomSetupTool/CustomSetupTool/include/appsup.h index 8601e3c1cc9e..3f0c27bb759e 100644 --- a/tools/CustomSetupTool/CustomSetupTool/include/appsup.h +++ b/tools/CustomSetupTool/CustomSetupTool/include/appsup.h @@ -51,7 +51,8 @@ VOID SetupInitializeFont( ); VOID SetupCreateLink( - _In_ PWSTR DestFilePath, + _In_ PWSTR AppUserModelId, + _In_ PWSTR LinkFilePath, _In_ PWSTR FilePath, _In_ PWSTR FileParentDir ); diff --git a/tools/CustomSetupTool/CustomSetupTool/setup.c b/tools/CustomSetupTool/CustomSetupTool/setup.c index 48d5f8a41d72..2050d7bddf58 100644 --- a/tools/CustomSetupTool/CustomSetupTool/setup.c +++ b/tools/CustomSetupTool/CustomSetupTool/setup.c @@ -442,27 +442,44 @@ VOID SetupSetWindowsOptions( // Create the startmenu shortcut. if (startmenuFolderString = PhGetKnownLocation(CSIDL_COMMON_PROGRAMS, L"\\Process Hacker.lnk")) { - SetupCreateLink(PhGetString(startmenuFolderString), PhGetString(clientPathString), PhGetString(Context->SetupInstallPath)); + SetupCreateLink( + L"ProcessHacker.Desktop.App", + PhGetString(startmenuFolderString), + PhGetString(clientPathString), + PhGetString(Context->SetupInstallPath) + ); PhDereferenceObject(startmenuFolderString); } - // Create the desktop shortcut. - if (Context->SetupCreateDesktopShortcut) + // Create the all users shortcut. + if (Context->SetupCreateDesktopShortcutAllUsers) { - if (startmenuFolderString = PhGetKnownLocation(CSIDL_DESKTOPDIRECTORY, L"\\Process Hacker.lnk")) + if (startmenuFolderString = PhGetKnownLocation(CSIDL_COMMON_DESKTOPDIRECTORY, L"\\Process Hacker.lnk")) { - SetupCreateLink(PhGetString(startmenuFolderString), PhGetString(clientPathString), PhGetString(Context->SetupInstallPath)); + SetupCreateLink( + L"ProcessHacker.Desktop.App", + PhGetString(startmenuFolderString), + PhGetString(clientPathString), + PhGetString(Context->SetupInstallPath) + ); PhDereferenceObject(startmenuFolderString); } } - - // Create the all users shortcut. - if (Context->SetupCreateDesktopShortcutAllUsers) + else { - if (startmenuFolderString = PhGetKnownLocation(CSIDL_COMMON_DESKTOPDIRECTORY, L"\\Process Hacker.lnk")) + // Create the desktop shortcut. + if (Context->SetupCreateDesktopShortcut) { - SetupCreateLink(PhGetString(startmenuFolderString), PhGetString(clientPathString), PhGetString(Context->SetupInstallPath)); - PhDereferenceObject(startmenuFolderString); + if (startmenuFolderString = PhGetKnownLocation(CSIDL_DESKTOPDIRECTORY, L"\\Process Hacker.lnk")) + { + SetupCreateLink( + L"ProcessHacker.Desktop.App", + PhGetString(startmenuFolderString), + PhGetString(clientPathString), + PhGetString(Context->SetupInstallPath) + ); + PhDereferenceObject(startmenuFolderString); + } } } @@ -472,6 +489,7 @@ VOID SetupSetWindowsOptions( PPH_STRING peviewPathString = PhConcatStrings2(PhGetString(Context->SetupInstallPath), L"\\peview.exe"); SetupCreateLink( + L"PeViewer.Desktop.App", PhGetString(startmenuFolderString), PhGetString(peviewPathString), PhGetString(Context->SetupInstallPath) @@ -495,30 +513,40 @@ VOID SetupSetWindowsOptions( if (Context->SetupCreateDefaultTaskManager) { NTSTATUS status; - HANDLE taskmgrKeyHandle = NULL; + HANDLE taskmgrKeyHandle; - if (NT_SUCCESS(status = PhCreateKey( + status = PhCreateKey( &taskmgrKeyHandle, KEY_READ | KEY_WRITE, PH_KEY_LOCAL_MACHINE, &TaskMgrImageOptionsKeyName, - 0, + OBJ_OPENIF, 0, NULL - ))) + ); + + if (NT_SUCCESS(status)) { PPH_STRING value; UNICODE_STRING valueName; - value = PhConcatStrings(3, L"\"", PhGetString(clientPathString), L"\""); - - // Configure the default Task Manager. RtlInitUnicodeString(&valueName, L"Debugger"); - NtSetValueKey(taskmgrKeyHandle, &valueName, 0, REG_SZ, value->Buffer, (ULONG)value->Length + 2); + value = PhConcatStrings(3, L"\"", PhGetString(clientPathString), L"\""); + status = NtSetValueKey( + taskmgrKeyHandle, + &valueName, + 0, + REG_SZ, + value->Buffer, + (ULONG)value->Length + sizeof(UNICODE_NULL) + ); + + PhDereferenceObject(value); NtClose(taskmgrKeyHandle); } - else + + if (!NT_SUCCESS(status)) { PhShowStatus(NULL, L"Unable to set the Windows default Task Manager.", status, 0); } From 45828459a283fce31c97d62e0f24661f0e6047a8 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 8 Oct 2017 22:38:20 +1100 Subject: [PATCH 0471/2058] Improve security dialog AppContainer SID<>Name mappings (#179) * Add fixes for security editor showing unknown SIDS for store app packages * Fix missing security dialog integrity labels --- phlib/include/secedit.h | 32 +++- phlib/include/seceditp.h | 112 +++++++++++++ phlib/secedit.c | 344 ++++++++++++++++++++++++++++++++++++++- 3 files changed, 481 insertions(+), 7 deletions(-) diff --git a/phlib/include/secedit.h b/phlib/include/secedit.h index 50090d4452b1..cde07e7702d4 100644 --- a/phlib/include/secedit.h +++ b/phlib/include/secedit.h @@ -59,7 +59,10 @@ FORCEINLINE ACCESS_MASK PhGetAccessForGetSecurity( if ( (SecurityInformation & OWNER_SECURITY_INFORMATION) || (SecurityInformation & GROUP_SECURITY_INFORMATION) || - (SecurityInformation & DACL_SECURITY_INFORMATION) + (SecurityInformation & DACL_SECURITY_INFORMATION) || + (SecurityInformation & LABEL_SECURITY_INFORMATION) || + (SecurityInformation & ATTRIBUTE_SECURITY_INFORMATION) || + (SecurityInformation & SCOPE_SECURITY_INFORMATION) ) { access |= READ_CONTROL; @@ -70,6 +73,11 @@ FORCEINLINE ACCESS_MASK PhGetAccessForGetSecurity( access |= ACCESS_SYSTEM_SECURITY; } + if (SecurityInformation & BACKUP_SECURITY_INFORMATION) + { + access |= READ_CONTROL | ACCESS_SYSTEM_SECURITY; + } + return access; } @@ -81,22 +89,38 @@ FORCEINLINE ACCESS_MASK PhGetAccessForSetSecurity( if ( (SecurityInformation & OWNER_SECURITY_INFORMATION) || - (SecurityInformation & GROUP_SECURITY_INFORMATION) + (SecurityInformation & GROUP_SECURITY_INFORMATION) || + (SecurityInformation & LABEL_SECURITY_INFORMATION) ) { access |= WRITE_OWNER; } - if (SecurityInformation & DACL_SECURITY_INFORMATION) + if ( + (SecurityInformation & DACL_SECURITY_INFORMATION) || + (SecurityInformation & ATTRIBUTE_SECURITY_INFORMATION) || + (SecurityInformation & PROTECTED_DACL_SECURITY_INFORMATION) || + (SecurityInformation & UNPROTECTED_DACL_SECURITY_INFORMATION) + ) { access |= WRITE_DAC; } - if (SecurityInformation & SACL_SECURITY_INFORMATION) + if ( + (SecurityInformation & SACL_SECURITY_INFORMATION) || + (SecurityInformation & SCOPE_SECURITY_INFORMATION) || + (SecurityInformation & PROTECTED_SACL_SECURITY_INFORMATION) || + (SecurityInformation & UNPROTECTED_SACL_SECURITY_INFORMATION) + ) { access |= ACCESS_SYSTEM_SECURITY; } + if (SecurityInformation & BACKUP_SECURITY_INFORMATION) + { + access |= WRITE_DAC | WRITE_OWNER | ACCESS_SYSTEM_SECURITY; + } + return access; } diff --git a/phlib/include/seceditp.h b/phlib/include/seceditp.h index d90cfd43d76c..3bd325245600 100644 --- a/phlib/include/seceditp.h +++ b/phlib/include/seceditp.h @@ -19,6 +19,25 @@ typedef struct BOOLEAN IsPage; } PhSecurityInformation; +typedef struct +{ + ISecurityInformation2Vtbl *VTable; + + ULONG RefCount; +} PhSecurityInformation2; + +typedef struct +{ + IDataObjectVtbl *VTable; + + ULONG RefCount; + + ULONG SidCount; + PSID *Sids; + + PPH_LIST NameCache; +} PhSecurityIDataObject; + ISecurityInformation *PhSecurityInformation_Create( _In_ PWSTR ObjectName, _In_ PPH_GET_OBJECT_SECURITY GetObjectSecurity, @@ -90,4 +109,97 @@ HRESULT STDMETHODCALLTYPE PhSecurityInformation_PropertySheetPageCallback( _In_ SI_PAGE_TYPE uPage ); +HRESULT STDMETHODCALLTYPE PhSecurityInformation2_QueryInterface( + _In_ ISecurityInformation2 *This, + _In_ REFIID Riid, + _Out_ PVOID *Object + ); + +ULONG STDMETHODCALLTYPE PhSecurityInformation2_AddRef( + _In_ ISecurityInformation2 *This + ); + +ULONG STDMETHODCALLTYPE PhSecurityInformation2_Release( + _In_ ISecurityInformation2 *This + ); + +BOOL STDMETHODCALLTYPE PhSecurityInformation2_IsDaclCanonical( + _In_ ISecurityInformation2 *This, + _In_ PACL pDacl + ); + +HRESULT STDMETHODCALLTYPE PhSecurityInformation2_LookupSids( + _In_ ISecurityInformation2 *This, + _In_ ULONG cSids, + _In_ PSID *rgpSids, + _Out_ LPDATAOBJECT *ppdo + ); + +HRESULT STDMETHODCALLTYPE PhSecurityDataObject_QueryInterface( + _In_ IDataObject *This, + _In_ REFIID Riid, + _Out_ PVOID *Object + ); + +ULONG STDMETHODCALLTYPE PhSecurityDataObject_AddRef( + _In_ IDataObject *This + ); + +ULONG STDMETHODCALLTYPE PhSecurityDataObject_Release( + _In_ IDataObject *This + ); + +HRESULT STDMETHODCALLTYPE PhSecurityDataObject_GetData( + _In_ IDataObject *This, + _In_ FORMATETC *pformatetcIn, + _Out_ STGMEDIUM *pmedium); + +HRESULT STDMETHODCALLTYPE PhSecurityDataObject_GetDataHere( + IDataObject *This, + _In_ FORMATETC *pformatetc, + _Inout_ STGMEDIUM *pmedium + ); + +HRESULT STDMETHODCALLTYPE PhSecurityDataObject_QueryGetData( + _In_ IDataObject *This, + _In_opt_ FORMATETC *pformatetc + ); + +HRESULT STDMETHODCALLTYPE PhSecurityDataObject_GetCanonicalFormatEtc( + _In_ IDataObject *This, + _In_opt_ FORMATETC *pformatectIn, + _Out_ FORMATETC *pformatetcOut + ); + +HRESULT STDMETHODCALLTYPE PhSecurityDataObject_SetData( + _In_ IDataObject *This, + _In_ FORMATETC *pformatetc, + _In_ STGMEDIUM *pmedium, + _In_ BOOL fRelease + ); + +HRESULT STDMETHODCALLTYPE PhSecurityDataObject_EnumFormatEtc( + _In_ IDataObject *This, + _In_ ULONG dwDirection, + _Out_opt_ IEnumFORMATETC **ppenumFormatEtc + ); + +HRESULT STDMETHODCALLTYPE PhSecurityDataObject_DAdvise( + _In_ IDataObject *This, + _In_ FORMATETC *pformatetc, + _In_ ULONG advf, + _In_opt_ IAdviseSink *pAdvSink, + _Out_ ULONG *pdwConnection + ); + +HRESULT STDMETHODCALLTYPE PhSecurityDataObject_DUnadvise( + _In_ IDataObject *This, + _In_ ULONG dwConnection + ); + +HRESULT STDMETHODCALLTYPE PhSecurityDataObject_EnumDAdvise( + _In_ IDataObject *This, + _Out_opt_ IEnumSTATDATA **ppenumAdvise + ); + #endif diff --git a/phlib/secedit.c b/phlib/secedit.c index 24bd903c867a..98e6df3ee5ab 100644 --- a/phlib/secedit.c +++ b/phlib/secedit.c @@ -3,6 +3,7 @@ * object security editor * * Copyright (C) 2010-2016 wj32 + * Copyright (C) 2017 dmex * * This file is part of Process Hacker. * @@ -22,6 +23,7 @@ #include #include +#include #include #include @@ -42,6 +44,31 @@ static ISecurityInformationVtbl PhSecurityInformation_VTable = PhSecurityInformation_PropertySheetPageCallback }; +static ISecurityInformation2Vtbl PhSecurityInformation_VTable2 = +{ + PhSecurityInformation2_QueryInterface, + PhSecurityInformation2_AddRef, + PhSecurityInformation2_Release, + PhSecurityInformation2_IsDaclCanonical, + PhSecurityInformation2_LookupSids +}; + +static IDataObjectVtbl PhDataObject_VTable = +{ + PhSecurityDataObject_QueryInterface, + PhSecurityDataObject_AddRef, + PhSecurityDataObject_Release, + PhSecurityDataObject_GetData, + PhSecurityDataObject_GetDataHere, + PhSecurityDataObject_QueryGetData, + PhSecurityDataObject_GetCanonicalFormatEtc, + PhSecurityDataObject_SetData, + PhSecurityDataObject_EnumFormatEtc, + PhSecurityDataObject_DAdvise, + PhSecurityDataObject_DUnadvise, + PhSecurityDataObject_EnumDAdvise +}; + /** * Creates a security editor page. * @@ -172,6 +199,8 @@ HRESULT STDMETHODCALLTYPE PhSecurityInformation_QueryInterface( _Out_ PVOID *Object ) { + PhSecurityInformation *this = (PhSecurityInformation *)This; + if ( IsEqualIID(Riid, &IID_IUnknown) || IsEqualIID(Riid, &IID_ISecurityInformation) @@ -181,6 +210,20 @@ HRESULT STDMETHODCALLTYPE PhSecurityInformation_QueryInterface( *Object = This; return S_OK; } + else if (IsEqualGUID(Riid, &IID_ISecurityInformation2)) + { + if (WindowsVersion >= WINDOWS_8) + { + PhSecurityInformation2 *info; + + info = PhAllocate(sizeof(PhSecurityInformation2)); + info->VTable = &PhSecurityInformation_VTable2; + info->RefCount = 1; + + *Object = info; + return S_OK; + } + } *Object = NULL; return E_NOINTERFACE; @@ -230,9 +273,9 @@ HRESULT STDMETHODCALLTYPE PhSecurityInformation_GetObjectInformation( SI_EDIT_AUDITS | SI_EDIT_OWNER | SI_EDIT_PERMS | - SI_ADVANCED | - SI_NO_ACL_PROTECT | - SI_NO_TREE_APPLY; + SI_ADVANCED; + //SI_NO_ACL_PROTECT | + //SI_NO_TREE_APPLY; ObjectInfo->hInstance = NULL; ObjectInfo->pszObjectName = this->ObjectName->Buffer; @@ -347,6 +390,301 @@ HRESULT STDMETHODCALLTYPE PhSecurityInformation_PropertySheetPageCallback( return E_NOTIMPL; } +HRESULT STDMETHODCALLTYPE PhSecurityInformation2_QueryInterface( + _In_ ISecurityInformation2 *This, + _In_ REFIID Riid, + _Out_ PVOID *Object + ) +{ + if ( + IsEqualIID(Riid, &IID_IUnknown) || + IsEqualIID(Riid, &IID_ISecurityInformation2) + ) + { + PhSecurityInformation2_AddRef(This); + *Object = This; + return S_OK; + } + + *Object = NULL; + return E_NOINTERFACE; +} + +ULONG STDMETHODCALLTYPE PhSecurityInformation2_AddRef( + _In_ ISecurityInformation2 *This + ) +{ + PhSecurityInformation2 *this = (PhSecurityInformation2 *)This; + + this->RefCount++; + + return this->RefCount; +} + +ULONG STDMETHODCALLTYPE PhSecurityInformation2_Release( + _In_ ISecurityInformation2 *This + ) +{ + PhSecurityInformation2 *this = (PhSecurityInformation2 *)This; + + this->RefCount--; + + if (this->RefCount == 0) + { + PhFree(this); + return 0; + } + + return this->RefCount; +} + +BOOL STDMETHODCALLTYPE PhSecurityInformation2_IsDaclCanonical( + _In_ ISecurityInformation2 *This, + _In_ PACL pDacl + ) +{ + return TRUE; +} + +HRESULT STDMETHODCALLTYPE PhSecurityInformation2_LookupSids( + _In_ ISecurityInformation2 *This, + _In_ ULONG cSids, + _In_ PSID *rgpSids, + _Out_ LPDATAOBJECT *ppdo + ) +{ + PhSecurityIDataObject *dataObject; + + dataObject = PhAllocate(sizeof(PhSecurityInformation)); + dataObject->VTable = &PhDataObject_VTable; + dataObject->RefCount = 1; + + dataObject->SidCount = cSids; + dataObject->Sids = rgpSids; + dataObject->NameCache = PhCreateList(1); + + *ppdo = (LPDATAOBJECT)dataObject; + + return S_OK; +} + +HRESULT STDMETHODCALLTYPE PhSecurityDataObject_QueryInterface( + _In_ IDataObject *This, + _In_ REFIID Riid, + _COM_Outptr_ PVOID *Object + ) +{ + if ( + IsEqualIID(Riid, &IID_IUnknown) || + IsEqualIID(Riid, &IID_IDataObject) + ) + { + PhSecurityDataObject_AddRef(This); + *Object = This; + return S_OK; + } + + *Object = NULL; + return E_NOINTERFACE; +} + +ULONG STDMETHODCALLTYPE PhSecurityDataObject_AddRef( + _In_ IDataObject *This + ) +{ + PhSecurityIDataObject *this = (PhSecurityIDataObject *)This; + + this->RefCount++; + + return this->RefCount; +} + +ULONG STDMETHODCALLTYPE PhSecurityDataObject_Release( + _In_ IDataObject *This + ) +{ + PhSecurityIDataObject *this = (PhSecurityIDataObject *)This; + + this->RefCount--; + + if (this->RefCount == 0) + { + for (ULONG i = 0; i < this->NameCache->Count; i++) + PhDereferenceObject(this->NameCache->Items[i]); + PhDereferenceObject(this->NameCache); + + PhFree(this); + return 0; + } + + return this->RefCount; +} + +HRESULT STDMETHODCALLTYPE PhSecurityDataObject_GetData( + _In_ IDataObject *This, + _In_ FORMATETC *pformatetcIn, + _Out_ STGMEDIUM *pmedium + ) +{ + PhSecurityIDataObject *this = (PhSecurityIDataObject *)This; + PSID_INFO_LIST sidInfoList; + + sidInfoList = (PSID_INFO_LIST)GlobalAlloc(GMEM_ZEROINIT, sizeof(SID_INFO_LIST) + (sizeof(SID_INFO) * this->SidCount)); + sidInfoList->cItems = this->SidCount; + + for (ULONG i = 0; i < this->SidCount; i++) + { + SID_INFO sidInfo; + PPH_STRING sidString; + SID_NAME_USE sidUse; + + memset(&sidInfo, 0, sizeof(SID_INFO)); + + sidInfo.pSid = this->Sids[i]; + + if (sidString = PhGetSidFullName(sidInfo.pSid, FALSE, &sidUse)) + { + switch (sidUse) + { + case SidTypeUser: + case SidTypeLogonSession: + sidInfo.pwzClass = L"User"; + break; + case SidTypeAlias: + case SidTypeGroup: + sidInfo.pwzClass = L"Group"; + break; + case SidTypeComputer: + sidInfo.pwzClass = L"Computer"; + break; + } + + sidInfo.pwzCommonName = PhGetString(sidString); + PhAddItemList(this->NameCache, sidString); + } + else if (sidString = PhSidToStringSid(sidInfo.pSid)) + { + static PH_STRINGREF appcontainerMappings = PH_STRINGREF_INIT(L"Software\\Classes\\Local Settings\\Software\\Microsoft\\Windows\\CurrentVersion\\AppContainer\\Mappings\\"); + HANDLE keyHandle; + PPH_STRING keyPath; + PPH_STRING packageName = NULL; + + if (PhEqualString2(sidString, L"S-1-15-3-4096", FALSE)) + { + // Special case for Edge and Internet Explorer objects. + packageName = PhCreateString(L"InternetExplorer (APP_PACKAGE)"); + sidInfo.pwzCommonName = PhGetString(packageName);; + PhAddItemList(this->NameCache, packageName); + sidInfoList->aSidInfo[i] = sidInfo; + continue; + } + + keyPath = PhConcatStringRef2(&appcontainerMappings, &sidString->sr); + + if (NT_SUCCESS(PhOpenKey( + &keyHandle, + KEY_READ, + PH_KEY_CURRENT_USER, + &keyPath->sr, + 0 + ))) + { + packageName = PhQueryRegistryString(keyHandle, L"Moniker"); + NtClose(keyHandle); + } + + if (packageName) + { + PhMoveReference(&packageName, PhFormatString(L"%s (APP_PACKAGE)", PhGetString(packageName))); + sidInfo.pwzCommonName = PhGetString(packageName); + PhAddItemList(this->NameCache, packageName); + } + + PhDereferenceObject(keyPath); + PhDereferenceObject(sidString); + } + + sidInfoList->aSidInfo[i] = sidInfo; + } + + pmedium->tymed = TYMED_HGLOBAL; + pmedium->hGlobal = (HGLOBAL)sidInfoList; + + return S_OK; +} + +HRESULT STDMETHODCALLTYPE PhSecurityDataObject_GetDataHere( + _In_ IDataObject *This, + _In_ FORMATETC *pformatetc, + _Inout_ STGMEDIUM *pmedium + ) +{ + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE PhSecurityDataObject_QueryGetData( + _In_ IDataObject *This, + _In_opt_ FORMATETC *pformatetc + ) +{ + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE PhSecurityDataObject_GetCanonicalFormatEtc( + _In_ IDataObject * This, + _In_opt_ FORMATETC *pformatectIn, + _Out_ FORMATETC *pformatetcOut + ) +{ + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE PhSecurityDataObject_SetData( + _In_ IDataObject *This, + _In_ FORMATETC *pformatetc, + _In_ STGMEDIUM *pmedium, + _In_ BOOL fRelease + ) +{ + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE PhSecurityDataObject_EnumFormatEtc( + _In_ IDataObject *This, + _In_ ULONG dwDirection, + _Out_opt_ IEnumFORMATETC **ppenumFormatEtc + ) +{ + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE PhSecurityDataObject_DAdvise( + _In_ IDataObject *This, + _In_ FORMATETC *pformatetc, + _In_ ULONG advf, + _In_opt_ IAdviseSink *pAdvSink, + _Out_ ULONG *pdwConnection + ) +{ + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE PhSecurityDataObject_DUnadvise( + _In_ IDataObject *This, + _In_ ULONG dwConnection + ) +{ + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE PhSecurityDataObject_EnumDAdvise( + _In_ IDataObject *This, + _Out_opt_ IEnumSTATDATA **ppenumAdvise + ) +{ + return E_NOTIMPL; +} + NTSTATUS PhpGetObjectSecurityWithTimeout( _In_ HANDLE Handle, _In_ SECURITY_INFORMATION SecurityInformation, From 7e51171ad4885d9af22da938f611f950c46bcd8d Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 8 Oct 2017 22:41:37 +1100 Subject: [PATCH 0472/2058] Remove unused line --- phlib/secedit.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/phlib/secedit.c b/phlib/secedit.c index 98e6df3ee5ab..83e5611e9502 100644 --- a/phlib/secedit.c +++ b/phlib/secedit.c @@ -199,8 +199,6 @@ HRESULT STDMETHODCALLTYPE PhSecurityInformation_QueryInterface( _Out_ PVOID *Object ) { - PhSecurityInformation *this = (PhSecurityInformation *)This; - if ( IsEqualIID(Riid, &IID_IUnknown) || IsEqualIID(Riid, &IID_ISecurityInformation) From 1bbddde5523a7b9807ba62f6d5e08035cb5d13b5 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 8 Oct 2017 22:42:10 +1100 Subject: [PATCH 0473/2058] Add binary setting wrappers (unused) --- phlib/settings.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/phlib/settings.c b/phlib/settings.c index bb78e121b21b..a068218c07b2 100644 --- a/phlib/settings.c +++ b/phlib/settings.c @@ -479,6 +479,21 @@ _May_raise_ PPH_STRING PhGetStringSetting( return value; } +_May_raise_ BOOLEAN PhGetBinarySetting( + _In_ PWSTR Name, + _Out_ PVOID Buffer + ) +{ + PPH_STRING setting; + BOOLEAN result; + + setting = PhGetStringSetting(Name); + result = PhHexStringToBuffer(&setting->sr, (PUCHAR)Buffer); + PhDereferenceObject(setting); + + return result; +} + _May_raise_ VOID PhSetIntegerSetting( _In_ PWSTR Name, _In_ ULONG Value @@ -619,6 +634,19 @@ _May_raise_ VOID PhSetStringSetting2( PhRaiseStatus(STATUS_NOT_FOUND); } +_May_raise_ VOID PhSetBinarySetting( + _In_ PWSTR Name, + _In_ PVOID Buffer, + _In_ ULONG Length + ) +{ + PPH_STRING binaryString; + + binaryString = PhBufferToHexString((PUCHAR)Buffer, Length); + PhSetStringSetting(Name, binaryString->Buffer); + PhDereferenceObject(binaryString); +} + VOID PhpFreeIgnoredSetting( _In_ PPH_SETTING Setting ) From 565298402f276abf3c637b089863802d5b4ebd96 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 9 Oct 2017 11:55:05 +1100 Subject: [PATCH 0474/2058] Fix macro usage --- phlib/lsasup.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/phlib/lsasup.c b/phlib/lsasup.c index c81051484571..b4ea741e4cea 100644 --- a/phlib/lsasup.c +++ b/phlib/lsasup.c @@ -38,11 +38,13 @@ NTSTATUS PhOpenLsaPolicy( _In_opt_ PUNICODE_STRING SystemName ) { - OBJECT_ATTRIBUTES oa = { 0 }; + OBJECT_ATTRIBUTES objectAttributes; + + InitializeObjectAttributes(&objectAttributes, NULL, 0, NULL, NULL); return LsaOpenPolicy( SystemName, - &oa, + &objectAttributes, DesiredAccess, PolicyHandle ); From ce3ea92cf5338196ca8c2f3db474c6fb612e3ca5 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 9 Oct 2017 12:22:51 +1100 Subject: [PATCH 0475/2058] Fix disabling token menu --- ProcessHacker/tokprp.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/ProcessHacker/tokprp.c b/ProcessHacker/tokprp.c index 97852c2c9925..ec8401daba6a 100644 --- a/ProcessHacker/tokprp.c +++ b/ProcessHacker/tokprp.c @@ -818,25 +818,23 @@ INT_PTR CALLBACK PhpTokenPageProc( // Put a radio check on the menu item that corresponds with the current integrity level. // Also disable menu items which correspond to higher integrity levels since // NtSetInformationToken doesn't allow integrity levels to be raised. - if (NT_SUCCESS(tokenPageContext->OpenObject( + if (NT_SUCCESS(status = tokenPageContext->OpenObject( &tokenHandle, TOKEN_QUERY, tokenPageContext->Context ))) { - if (NT_SUCCESS(PhGetTokenIntegrityLevel( + if (NT_SUCCESS(status = PhGetTokenIntegrityLevel( tokenHandle, &integrityLevel, NULL ))) { - ULONG i; - - for (i = 0; i < menu->Items->Count; i++) + for (ULONG i = 0; i < menu->Items->Count; i++) { PPH_EMENU_ITEM menuItem = menu->Items->Items[i]; - if (menuItem->Id == integrityLevel) + if (menuItem->Id == (ULONG)integrityLevel) { menuItem->Flags |= PH_EMENU_CHECKED | PH_EMENU_RADIOCHECK; } @@ -850,6 +848,15 @@ INT_PTR CALLBACK PhpTokenPageProc( NtClose(tokenHandle); } + if (!NT_SUCCESS(status)) + { + for (ULONG i = 0; i < menu->Items->Count; i++) + { + PPH_EMENU_ITEM menuItem = menu->Items->Items[i]; + menuItem->Flags |= PH_EMENU_DISABLED; + } + } + selectedItem = PhShowEMenu( menu, hwndDlg, From a8553b4a6d5dfa29027338eceea41e4f53823e63 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 9 Oct 2017 12:23:41 +1100 Subject: [PATCH 0476/2058] Remove unused export --- ProcessHacker/ProcessHacker.def | 1 - 1 file changed, 1 deletion(-) diff --git a/ProcessHacker/ProcessHacker.def b/ProcessHacker/ProcessHacker.def index 3cd1060436f0..51007a4e1896 100644 --- a/ProcessHacker/ProcessHacker.def +++ b/ProcessHacker/ProcessHacker.def @@ -636,7 +636,6 @@ EXPORTS PhGetJsonArrayLong64 PhGetJsonArrayLength PhGetJsonArrayIndexObject - PhGetJsonObjectAsArrayList ; cache PhClearCacheDirectory From ce910c82f22558902a6ab4129f81dda2be88bbcb Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 9 Oct 2017 12:25:57 +1100 Subject: [PATCH 0477/2058] Improve default task manager error checking, Fix color dialog window position --- ProcessHacker/options.c | 36 ++++++++++++++++++++++++++++++------ 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/ProcessHacker/options.c b/ProcessHacker/options.c index e095121f8975..31ef37cd061c 100644 --- a/ProcessHacker/options.c +++ b/ProcessHacker/options.c @@ -902,7 +902,7 @@ VOID PhpSetDefaultTaskManager( HANDLE taskmgrKeyHandle; UNICODE_STRING valueName; - if (NT_SUCCESS(PhCreateKey( + status = PhCreateKey( &taskmgrKeyHandle, KEY_READ | KEY_WRITE, PH_KEY_LOCAL_MACHINE, @@ -910,7 +910,9 @@ VOID PhpSetDefaultTaskManager( OBJ_OPENIF, 0, NULL - ))) + ); + + if (NT_SUCCESS(status)) { RtlInitUnicodeString(&valueName, L"Debugger"); @@ -926,12 +928,12 @@ VOID PhpSetDefaultTaskManager( status = NtSetValueKey(taskmgrKeyHandle, &valueName, 0, REG_SZ, quotedFileName->Buffer, (ULONG)quotedFileName->Length + 2); } - if (!NT_SUCCESS(status)) - PhShowStatus(ParentWindowHandle, L"Unable to replace Task Manager", status, 0); - NtClose(taskmgrKeyHandle); } + if (!NT_SUCCESS(status)) + PhShowStatus(ParentWindowHandle, L"Unable to replace Task Manager", status, 0); + if (PhSettingsFileName) PhSaveSettings(PhSettingsFileName->Buffer); } @@ -1707,6 +1709,27 @@ COLORREF NTAPI PhpColorItemColorFunction( return item->CurrentColor; } +UINT_PTR CALLBACK PhpColorDlgHookProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + switch (uMsg) + { + case WM_INITDIALOG: + { + PhCenterWindow(hwndDlg, PhOptionsWindowHandle); + + EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); + } + break; + } + + return FALSE; +} + INT_PTR CALLBACK PhpOptionsHighlightingDlgProc( _In_ HWND hwndDlg, _In_ UINT uMsg, @@ -1816,7 +1839,8 @@ INT_PTR CALLBACK PhpOptionsHighlightingDlgProc( chooseColor.hwndOwner = hwndDlg; chooseColor.rgbResult = item->CurrentColor; chooseColor.lpCustColors = customColors; - chooseColor.Flags = CC_ANYCOLOR | CC_FULLOPEN | CC_RGBINIT; + chooseColor.lpfnHook = PhpColorDlgHookProc; + chooseColor.Flags = CC_ANYCOLOR | CC_FULLOPEN | CC_SOLIDCOLOR | CC_ENABLEHOOK | CC_RGBINIT; if (ChooseColor(&chooseColor)) { From 5c1dddd6982070f78166188951fd8478a26c9312 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 9 Oct 2017 16:53:30 +1100 Subject: [PATCH 0478/2058] ToolStatus: Fix extra statusbar memory allocations, Fix regression customizing toolbar/statusbar items --- plugins/ToolStatus/customizesb.c | 39 ++++++++++++-------------------- plugins/ToolStatus/customizetb.c | 24 ++++++++++---------- plugins/ToolStatus/statusbar.c | 32 ++++---------------------- plugins/ToolStatus/toolstatus.h | 5 ---- 4 files changed, 30 insertions(+), 70 deletions(-) diff --git a/plugins/ToolStatus/customizesb.c b/plugins/ToolStatus/customizesb.c index edb1929a8caf..d823a35a3339 100644 --- a/plugins/ToolStatus/customizesb.c +++ b/plugins/ToolStatus/customizesb.c @@ -52,14 +52,7 @@ VOID CustomizeInsertStatusBarItem( _In_ PBUTTON_CONTEXT Button ) { - PSTATUSBAR_ITEM item; - - item = PhAllocate(sizeof(STATUSBAR_ITEM)); - memset(item, 0, sizeof(STATUSBAR_ITEM)); - - item->Id = Button->IdCommand; - - PhInsertItemList(StatusBarItemList, Index, item); + PhInsertItemList(StatusBarItemList, Index, UlongToPtr(Button->IdCommand)); StatusBarUpdate(TRUE); } @@ -224,14 +217,10 @@ VOID CustomizeLoadStatusBarItems( for (index = 0; index < StatusBarItemList->Count; index++) { - PSTATUSBAR_ITEM item; - - item = StatusBarItemList->Items[index]; - button = PhAllocate(sizeof(BUTTON_CONTEXT)); memset(button, 0, sizeof(BUTTON_CONTEXT)); - button->IdCommand = item->Id; + button->IdCommand = PtrToUlong(StatusBarItemList->Items[index]); ListBox_AddItemData(Context->CurrentListHandle, button); } @@ -394,11 +383,11 @@ INT_PTR CALLBACK CustomizeStatusBarDialogProc( CustomizeAddStatusBarItem(context, index, indexto); } break; - case LBN_KILLFOCUS: - { - Button_Enable(context->AddButtonHandle, FALSE); - } - break; + //case LBN_KILLFOCUS: + // { + // Button_Enable(context->AddButtonHandle, FALSE); + // } + // break; } } break; @@ -475,13 +464,13 @@ INT_PTR CALLBACK CustomizeStatusBarDialogProc( CustomizeRemoveStatusBarItem(context, index); } break; - case LBN_KILLFOCUS: - { - Button_Enable(context->MoveUpButtonHandle, FALSE); - Button_Enable(context->MoveDownButtonHandle, FALSE); - Button_Enable(context->RemoveButtonHandle, FALSE); - } - break; + //case LBN_KILLFOCUS: + // { + // Button_Enable(context->MoveUpButtonHandle, FALSE); + // Button_Enable(context->MoveDownButtonHandle, FALSE); + // Button_Enable(context->RemoveButtonHandle, FALSE); + // } + // break; } } break; diff --git a/plugins/ToolStatus/customizetb.c b/plugins/ToolStatus/customizetb.c index 7e6e8eb74f28..c103c01b4d18 100644 --- a/plugins/ToolStatus/customizetb.c +++ b/plugins/ToolStatus/customizetb.c @@ -581,11 +581,11 @@ INT_PTR CALLBACK CustomizeToolbarDialogProc( CustomizeAddToolbarItem(context, index, indexto); } break; - case LBN_KILLFOCUS: - { - Button_Enable(context->AddButtonHandle, FALSE); - } - break; + //case LBN_KILLFOCUS: + // { + // Button_Enable(context->AddButtonHandle, FALSE); + // } + // break; } } break; @@ -661,13 +661,13 @@ INT_PTR CALLBACK CustomizeToolbarDialogProc( CustomizeRemoveToolbarItem(context, index); } break; - case LBN_KILLFOCUS: - { - Button_Enable(context->MoveUpButtonHandle, FALSE); - Button_Enable(context->MoveDownButtonHandle, FALSE); - Button_Enable(context->RemoveButtonHandle, FALSE); - } - break; + //case LBN_KILLFOCUS: + // { + // Button_Enable(context->MoveUpButtonHandle, FALSE); + // Button_Enable(context->MoveDownButtonHandle, FALSE); + // Button_Enable(context->RemoveButtonHandle, FALSE); + // } + // break; } } break; diff --git a/plugins/ToolStatus/statusbar.c b/plugins/ToolStatus/statusbar.c index 92a8515eb812..fa5df12ed8c8 100644 --- a/plugins/ToolStatus/statusbar.c +++ b/plugins/ToolStatus/statusbar.c @@ -57,14 +57,7 @@ VOID StatusBarLoadDefault( for (ULONG i = 0; i < MAX_DEFAULT_STATUSBAR_ITEMS; i++) { - PSTATUSBAR_ITEM item; - - item = PhAllocate(sizeof(STATUSBAR_ITEM)); - memset(item, 0, sizeof(STATUSBAR_ITEM)); - - item->Id = StatusBarItems[i]; - - PhAddItemList(StatusBarItemList, item); + PhAddItemList(StatusBarItemList, UlongToPtr(StatusBarItems[i])); } } @@ -116,14 +109,7 @@ VOID StatusBarLoadSettings( if (PhStringToInteger64(&idPart, 10, &idInteger)) { - PSTATUSBAR_ITEM item; - - item = PhAllocate(sizeof(STATUSBAR_ITEM)); - memset(item, 0, sizeof(STATUSBAR_ITEM)); - - item->Id = (ULONG)idInteger; - - PhInsertItemList(StatusBarItemList, i, item); + PhInsertItemList(StatusBarItemList, i, UlongToPtr((ULONG)idInteger)); } } } @@ -145,12 +131,10 @@ VOID StatusBarSaveSettings( for (ULONG i = 0; i < StatusBarItemList->Count; i++) { - PSTATUSBAR_ITEM item = StatusBarItemList->Items[i]; - PhAppendFormatStringBuilder( &stringBuilder, L"%lu|", - item->Id + PtrToUlong(StatusBarItemList->Items[i]) ); } @@ -165,11 +149,6 @@ VOID StatusBarResetSettings( VOID ) { - for (ULONG i = 0; i < StatusBarItemList->Count; i++) - { - PhFree(StatusBarItemList->Items[i]); - } - PhClearList(StatusBarItemList); StatusBarLoadDefault(); @@ -296,11 +275,8 @@ VOID StatusBarUpdate( { SIZE size; ULONG width; - PSTATUSBAR_ITEM item; - - item = StatusBarItemList->Items[i]; - switch (item->Id) + switch (PtrToUlong(StatusBarItemList->Items[i])) { case ID_STATUS_CPUUSAGE: { diff --git a/plugins/ToolStatus/toolstatus.h b/plugins/ToolStatus/toolstatus.h index 202cc23ced73..b905a915f8ff 100644 --- a/plugins/ToolStatus/toolstatus.h +++ b/plugins/ToolStatus/toolstatus.h @@ -268,11 +268,6 @@ VOID ToolbarUpdateGraphsInfo(LPNMHDR Header); // statusbar.c -typedef struct _STATUSBAR_ITEM -{ - ULONG Id; -} STATUSBAR_ITEM, *PSTATUSBAR_ITEM; - extern ULONG ProcessesUpdatedCount; extern HWND StatusBarHandle; extern PPH_LIST StatusBarItemList; From 4b6f35f5c2eb3c00a7c166bd855b532728ab506b Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 10 Oct 2017 16:23:10 +1100 Subject: [PATCH 0479/2058] Fix resource leak --- phlib/guisup.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/phlib/guisup.c b/phlib/guisup.c index b9667e8d2509..d952d7971cae 100644 --- a/phlib/guisup.c +++ b/phlib/guisup.c @@ -862,9 +862,13 @@ HWND PhCreateDialogFromTemplate( dialog = LockResource(resourceHandle); if (!dialog) + { + FreeResource(resourceHandle); return NULL; + } dialogCopy = PhAllocateCopy(dialog, resourceSize); + FreeResource(resourceHandle); if (dialogCopy->signature == 0xffff) { From 06cc8aa9c1e88490f3cfba01a5d2fb3423a21042 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 10 Oct 2017 18:52:59 +1100 Subject: [PATCH 0480/2058] Improve FileVersionInfo lookup performance --- phlib/util.c | 58 +++++++++++++++++++++++++++++++--------------------- 1 file changed, 35 insertions(+), 23 deletions(-) diff --git a/phlib/util.c b/phlib/util.c index b72bef57db02..100662c2e2e8 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -1530,37 +1530,49 @@ PVOID PhGetFileVersionInfo( _In_ PWSTR FileName ) { - ULONG versionInfoSize; - ULONG dummy; + HMODULE resourceInstance; + HRSRC resourceInfo; + ULONG resourceSize; + HGLOBAL resourceHandle; PVOID versionInfo; + PVOID versionInfoCopy = NULL; - versionInfoSize = GetFileVersionInfoSize( - FileName, - &dummy - ); + resourceInstance = LoadLibraryEx(FileName, 0, LOAD_LIBRARY_AS_DATAFILE); - if (versionInfoSize) - { - versionInfo = PhAllocate(versionInfoSize); + if (!resourceInstance) + return NULL; - if (!GetFileVersionInfo( - FileName, - 0, - versionInfoSize, - versionInfo - )) - { - PhFree(versionInfo); + resourceInfo = FindResource(resourceInstance, MAKEINTRESOURCE(VS_VERSION_INFO), VS_FILE_INFO); - return NULL; - } - } - else + if (!resourceInfo) + goto CleanupExit; + + resourceSize = SizeofResource(resourceInstance, resourceInfo); + + if (resourceSize == 0) + goto CleanupExit; + + resourceHandle = LoadResource(resourceInstance, resourceInfo); + + if (!resourceHandle) + goto CleanupExit; + + versionInfo = LockResource(resourceHandle); + + if (!versionInfo) { - return NULL; + FreeResource(resourceHandle); + goto CleanupExit; } - return versionInfo; + versionInfoCopy = PhAllocateCopy(versionInfo, resourceSize); + FreeResource(resourceHandle); + +CleanupExit: + + FreeLibrary(resourceInstance); + + return versionInfoCopy; } /** From d70896be4adf7e9d5b1e15d9fbb41c6812cc68b9 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 10 Oct 2017 19:47:59 +1100 Subject: [PATCH 0481/2058] Revert "Fix resource leak" This reverts commit 4b6f35f5c2eb3c00a7c166bd855b532728ab506b. --- phlib/guisup.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/phlib/guisup.c b/phlib/guisup.c index d952d7971cae..b9667e8d2509 100644 --- a/phlib/guisup.c +++ b/phlib/guisup.c @@ -862,13 +862,9 @@ HWND PhCreateDialogFromTemplate( dialog = LockResource(resourceHandle); if (!dialog) - { - FreeResource(resourceHandle); return NULL; - } dialogCopy = PhAllocateCopy(dialog, resourceSize); - FreeResource(resourceHandle); if (dialogCopy->signature == 0xffff) { From 49d857fc34262dbfa9282c3922d7c61795d8d3e0 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 10 Oct 2017 21:42:09 +1100 Subject: [PATCH 0482/2058] Add PhLoadResource function (removes 600 unnecessary calls on startup) --- phlib/guisup.c | 43 +++++++--------------- phlib/include/phutil.h | 10 ++++++ phlib/util.c | 82 ++++++++++++++++++++++++------------------ phnt/include/ntldr.h | 12 +++++++ 4 files changed, 82 insertions(+), 65 deletions(-) diff --git a/phlib/guisup.c b/phlib/guisup.c index b9667e8d2509..4871ac46d1ec 100644 --- a/phlib/guisup.c +++ b/phlib/guisup.c @@ -837,47 +837,30 @@ HWND PhCreateDialogFromTemplate( _In_ PVOID Parameter ) { - HRSRC resourceInfo; - ULONG resourceSize; - HGLOBAL resourceHandle; - PDLGTEMPLATEEX dialog; - PDLGTEMPLATEEX dialogCopy; + PDLGTEMPLATEEX dialogTemplate; HWND dialogHandle; - resourceInfo = FindResource(Instance, Template, MAKEINTRESOURCE(RT_DIALOG)); - - if (!resourceInfo) - return NULL; - - resourceSize = SizeofResource(Instance, resourceInfo); - - if (resourceSize == 0) - return NULL; - - resourceHandle = LoadResource(Instance, resourceInfo); - - if (!resourceHandle) - return NULL; - - dialog = LockResource(resourceHandle); - - if (!dialog) + if (!PhLoadResource(Instance, Template, RT_DIALOG, NULL, &dialogTemplate)) return NULL; - dialogCopy = PhAllocateCopy(dialog, resourceSize); - - if (dialogCopy->signature == 0xffff) + if (dialogTemplate->signature == USHRT_MAX) { - dialogCopy->style = Style; + dialogTemplate->style = Style; } else { - ((DLGTEMPLATE *)dialogCopy)->style = Style; + ((DLGTEMPLATE *)dialogTemplate)->style = Style; } - dialogHandle = CreateDialogIndirectParam(Instance, (DLGTEMPLATE *)dialogCopy, Parent, DialogProc, (LPARAM)Parameter); + dialogHandle = CreateDialogIndirectParam( + Instance, + (DLGTEMPLATE *)dialogTemplate, + Parent, + DialogProc, + (LPARAM)Parameter + ); - PhFree(dialogCopy); + PhFree(dialogTemplate); return dialogHandle; } diff --git a/phlib/include/phutil.h b/phlib/include/phutil.h index 9eddea371402..a5588c4a143d 100644 --- a/phlib/include/phutil.h +++ b/phlib/include/phutil.h @@ -1160,6 +1160,16 @@ PhGetNamespaceHandle( return directory; } +PHLIBAPI +BOOLEAN +NTAPI +PhLoadResource( + _In_ PVOID DllBase, + _In_ PCWSTR Name, + _In_ PCWSTR Type, + _Out_opt_ ULONG *ResourceLength, + _Out_ PVOID *ResourceBuffer + ); #ifdef __cplusplus } diff --git a/phlib/util.c b/phlib/util.c index 100662c2e2e8..d0502830b9de 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -1530,49 +1530,28 @@ PVOID PhGetFileVersionInfo( _In_ PWSTR FileName ) { - HMODULE resourceInstance; - HRSRC resourceInfo; - ULONG resourceSize; - HGLOBAL resourceHandle; + PVOID libraryModule; PVOID versionInfo; - PVOID versionInfoCopy = NULL; - resourceInstance = LoadLibraryEx(FileName, 0, LOAD_LIBRARY_AS_DATAFILE); + libraryModule = LoadLibraryEx(FileName, NULL, LOAD_LIBRARY_AS_DATAFILE); - if (!resourceInstance) + if (!libraryModule) return NULL; - resourceInfo = FindResource(resourceInstance, MAKEINTRESOURCE(VS_VERSION_INFO), VS_FILE_INFO); - - if (!resourceInfo) - goto CleanupExit; - - resourceSize = SizeofResource(resourceInstance, resourceInfo); - - if (resourceSize == 0) - goto CleanupExit; - - resourceHandle = LoadResource(resourceInstance, resourceInfo); - - if (!resourceHandle) - goto CleanupExit; - - versionInfo = LockResource(resourceHandle); - - if (!versionInfo) + if (PhLoadResource( + libraryModule, + MAKEINTRESOURCE(VS_VERSION_INFO), + VS_FILE_INFO, + NULL, + &versionInfo + )) { - FreeResource(resourceHandle); - goto CleanupExit; + FreeLibrary(libraryModule); + return versionInfo; } - versionInfoCopy = PhAllocateCopy(versionInfo, resourceSize); - FreeResource(resourceHandle); - -CleanupExit: - - FreeLibrary(resourceInstance); - - return versionInfoCopy; + FreeLibrary(libraryModule); + return NULL; } /** @@ -5157,3 +5136,36 @@ VOID PhDeleteCacheFile( PhDereferenceObject(cacheFullFilePath); } } + +BOOLEAN PhLoadResource( + _In_ PVOID DllBase, + _In_ PCWSTR Name, + _In_ PCWSTR Type, + _Out_opt_ ULONG *ResourceLength, + _Out_ PVOID *ResourceBuffer + ) +{ + ULONG resourceLength; + PVOID resourceInfo; + PVOID resourceBuffer; + + resourceInfo = FindResource(DllBase, Name, Type); + + if (!resourceInfo) + return FALSE; + + if (!NT_SUCCESS(LdrAccessResource(DllBase, resourceInfo, &resourceBuffer, &resourceLength))) + return FALSE; + + if (!resourceBuffer) + return FALSE; + + if (resourceLength == 0) + return FALSE; + + if (ResourceLength) + *ResourceLength = resourceLength; + *ResourceBuffer = PhAllocateCopy(resourceBuffer, resourceLength); + + return TRUE; +} diff --git a/phnt/include/ntldr.h b/phnt/include/ntldr.h index 6ec947c0f407..f89b5f2360b0 100644 --- a/phnt/include/ntldr.h +++ b/phnt/include/ntldr.h @@ -586,4 +586,16 @@ typedef struct _RTL_PROCESS_MODULE_INFORMATION_EX PVOID DefaultBase; } RTL_PROCESS_MODULE_INFORMATION_EX, *PRTL_PROCESS_MODULE_INFORMATION_EX; +// Resources + +NTSYSAPI +NTSTATUS +NTAPI +LdrAccessResource( + _In_ PVOID BaseAddress, + _In_ PIMAGE_RESOURCE_DATA_ENTRY ResourceDataEntry, + _Out_opt_ PVOID *ResourceBuffer, + _Out_opt_ ULONG *ResourceLength + ); + #endif From 275bfe85ff53efc764fa78ea38f8a3a12be48946 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 10 Oct 2017 21:42:54 +1100 Subject: [PATCH 0483/2058] Convert macro to function --- phlib/include/phutil.h | 67 ++---------------------------------------- phlib/util.c | 66 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 64 deletions(-) diff --git a/phlib/include/phutil.h b/phlib/include/phutil.h index a5588c4a143d..cdfbbdbdba2b 100644 --- a/phlib/include/phutil.h +++ b/phlib/include/phutil.h @@ -1092,74 +1092,13 @@ PhDeleteCacheFile( _In_ PPH_STRING FileName ); -FORCEINLINE -HANDLE +PHLIBAPI +HANDLE NTAPI PhGetNamespaceHandle( VOID - ) -{ - static PH_INITONCE initOnce = PH_INITONCE_INIT; - static UNICODE_STRING namespacePathUs = RTL_CONSTANT_STRING(L"\\BaseNamedObjects\\ProcessHacker"); - static HANDLE directory = NULL; + ); - if (PhBeginInitOnce(&initOnce)) - { - static SID_IDENTIFIER_AUTHORITY ntAuthority = SECURITY_NT_AUTHORITY; - OBJECT_ATTRIBUTES objectAttributes; - PSECURITY_DESCRIPTOR securityDescriptor; - ULONG sdAllocationLength; - UCHAR administratorsSidBuffer[FIELD_OFFSET(SID, SubAuthority) + sizeof(ULONG) * 2]; - PSID administratorsSid; - PACL dacl; - - // Create the default namespace DACL. - - administratorsSid = (PSID)administratorsSidBuffer; - RtlInitializeSid(administratorsSid, &ntAuthority, 2); - *RtlSubAuthoritySid(administratorsSid, 0) = SECURITY_BUILTIN_DOMAIN_RID; - *RtlSubAuthoritySid(administratorsSid, 1) = DOMAIN_ALIAS_RID_ADMINS; - - sdAllocationLength = SECURITY_DESCRIPTOR_MIN_LENGTH + - (ULONG)sizeof(ACL) + - (ULONG)sizeof(ACCESS_ALLOWED_ACE) + - RtlLengthSid(&PhSeLocalSid) + - (ULONG)sizeof(ACCESS_ALLOWED_ACE) + - RtlLengthSid(administratorsSid) + - (ULONG)sizeof(ACCESS_ALLOWED_ACE) + - RtlLengthSid(&PhSeInteractiveSid); - - securityDescriptor = PhAllocate(sdAllocationLength); - dacl = (PACL)((PCHAR)securityDescriptor + SECURITY_DESCRIPTOR_MIN_LENGTH); - - RtlCreateSecurityDescriptor(securityDescriptor, SECURITY_DESCRIPTOR_REVISION); - RtlCreateAcl(dacl, sdAllocationLength - SECURITY_DESCRIPTOR_MIN_LENGTH, ACL_REVISION); - RtlAddAccessAllowedAce(dacl, ACL_REVISION, DIRECTORY_ALL_ACCESS, &PhSeLocalSid); - RtlAddAccessAllowedAce(dacl, ACL_REVISION, DIRECTORY_ALL_ACCESS, administratorsSid); - RtlAddAccessAllowedAce(dacl, ACL_REVISION, DIRECTORY_QUERY | DIRECTORY_TRAVERSE | DIRECTORY_CREATE_OBJECT, &PhSeInteractiveSid); - RtlSetDaclSecurityDescriptor(securityDescriptor, TRUE, dacl, FALSE); - - InitializeObjectAttributes( - &objectAttributes, - &namespacePathUs, - OBJ_OPENIF, - NULL, - securityDescriptor - ); - - NtCreateDirectoryObject( - &directory, - MAXIMUM_ALLOWED, - &objectAttributes - ); - - PhFree(securityDescriptor); - - PhEndInitOnce(&initOnce); - } - - return directory; -} PHLIBAPI BOOLEAN NTAPI diff --git a/phlib/util.c b/phlib/util.c index d0502830b9de..5a4089afec2d 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -5137,6 +5137,72 @@ VOID PhDeleteCacheFile( } } +HANDLE PhGetNamespaceHandle( + VOID + ) +{ + static PH_INITONCE initOnce = PH_INITONCE_INIT; + static UNICODE_STRING namespacePathUs = RTL_CONSTANT_STRING(L"\\BaseNamedObjects\\ProcessHacker"); + static HANDLE directory = NULL; + + if (PhBeginInitOnce(&initOnce)) + { + static SID_IDENTIFIER_AUTHORITY ntAuthority = SECURITY_NT_AUTHORITY; + OBJECT_ATTRIBUTES objectAttributes; + PSECURITY_DESCRIPTOR securityDescriptor; + ULONG sdAllocationLength; + UCHAR administratorsSidBuffer[FIELD_OFFSET(SID, SubAuthority) + sizeof(ULONG) * 2]; + PSID administratorsSid; + PACL dacl; + + // Create the default namespace DACL. + + administratorsSid = (PSID)administratorsSidBuffer; + RtlInitializeSid(administratorsSid, &ntAuthority, 2); + *RtlSubAuthoritySid(administratorsSid, 0) = SECURITY_BUILTIN_DOMAIN_RID; + *RtlSubAuthoritySid(administratorsSid, 1) = DOMAIN_ALIAS_RID_ADMINS; + + sdAllocationLength = SECURITY_DESCRIPTOR_MIN_LENGTH + + (ULONG)sizeof(ACL) + + (ULONG)sizeof(ACCESS_ALLOWED_ACE) + + RtlLengthSid(&PhSeLocalSid) + + (ULONG)sizeof(ACCESS_ALLOWED_ACE) + + RtlLengthSid(administratorsSid) + + (ULONG)sizeof(ACCESS_ALLOWED_ACE) + + RtlLengthSid(&PhSeInteractiveSid); + + securityDescriptor = PhAllocate(sdAllocationLength); + dacl = (PACL)((PCHAR)securityDescriptor + SECURITY_DESCRIPTOR_MIN_LENGTH); + + RtlCreateSecurityDescriptor(securityDescriptor, SECURITY_DESCRIPTOR_REVISION); + RtlCreateAcl(dacl, sdAllocationLength - SECURITY_DESCRIPTOR_MIN_LENGTH, ACL_REVISION); + RtlAddAccessAllowedAce(dacl, ACL_REVISION, DIRECTORY_ALL_ACCESS, &PhSeLocalSid); + RtlAddAccessAllowedAce(dacl, ACL_REVISION, DIRECTORY_ALL_ACCESS, administratorsSid); + RtlAddAccessAllowedAce(dacl, ACL_REVISION, DIRECTORY_QUERY | DIRECTORY_TRAVERSE | DIRECTORY_CREATE_OBJECT, &PhSeInteractiveSid); + RtlSetDaclSecurityDescriptor(securityDescriptor, TRUE, dacl, FALSE); + + InitializeObjectAttributes( + &objectAttributes, + &namespacePathUs, + OBJ_OPENIF, + NULL, + securityDescriptor + ); + + NtCreateDirectoryObject( + &directory, + MAXIMUM_ALLOWED, + &objectAttributes + ); + + PhFree(securityDescriptor); + + PhEndInitOnce(&initOnce); + } + + return directory; +} + BOOLEAN PhLoadResource( _In_ PVOID DllBase, _In_ PCWSTR Name, From 0be81cc138e902fe22aa9acec1296d68f4469687 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 10 Oct 2017 21:43:54 +1100 Subject: [PATCH 0484/2058] Searchbox: Use PhLoadResource function --- ProcessHacker/searchbox.c | 20 +++----------------- tools/peview/searchbox.c | 18 +++--------------- 2 files changed, 6 insertions(+), 32 deletions(-) diff --git a/ProcessHacker/searchbox.c b/ProcessHacker/searchbox.c index 8581d2d15cfd..c60f2d6780f0 100644 --- a/ProcessHacker/searchbox.c +++ b/ProcessHacker/searchbox.c @@ -552,8 +552,6 @@ HBITMAP PhLoadPngImageFromResource( BOOLEAN success = FALSE; UINT frameCount = 0; ULONG resourceLength = 0; - HGLOBAL resourceHandle = NULL; - HRSRC resourceHandleSource = NULL; WICInProcPointer resourceBuffer = NULL; HDC screenHdc = NULL; HDC bufferDc = NULL; @@ -573,18 +571,8 @@ HBITMAP PhLoadPngImageFromResource( if (FAILED(CoCreateInstance(&CLSID_WICImagingFactory1, NULL, CLSCTX_INPROC_SERVER, &IID_IWICImagingFactory, &wicFactory))) goto CleanupExit; - // Find the resource - if ((resourceHandleSource = FindResource(DllBase, Name, L"PNG")) == NULL) - goto CleanupExit; - - // Get the resource length - resourceLength = SizeofResource(DllBase, resourceHandleSource); - // Load the resource - if ((resourceHandle = LoadResource(DllBase, resourceHandleSource)) == NULL) - goto CleanupExit; - - if ((resourceBuffer = (WICInProcPointer)LockResource(resourceHandle)) == NULL) + if (!PhLoadResource(DllBase, Name, L"PNG", &resourceLength, &resourceBuffer)) goto CleanupExit; // Create the Stream @@ -694,13 +682,11 @@ HBITMAP PhLoadPngImageFromResource( if (wicFactory) IWICImagingFactory_Release(wicFactory); - if (resourceHandle) - FreeResource(resourceHandle); + if (resourceBuffer) + PhFree(resourceBuffer); if (success) - { return bitmapHandle; - } DeleteObject(bitmapHandle); return NULL; diff --git a/tools/peview/searchbox.c b/tools/peview/searchbox.c index a758b0e2816b..e7774bb44573 100644 --- a/tools/peview/searchbox.c +++ b/tools/peview/searchbox.c @@ -160,8 +160,6 @@ HBITMAP PhLoadPngImageFromResource( BOOLEAN success = FALSE; UINT frameCount = 0; ULONG resourceLength = 0; - HGLOBAL resourceHandle = NULL; - HRSRC resourceHandleSource = NULL; WICInProcPointer resourceBuffer = NULL; HDC screenHdc = NULL; HDC bufferDc = NULL; @@ -181,18 +179,8 @@ HBITMAP PhLoadPngImageFromResource( if (FAILED(CoCreateInstance(&CLSID_WICImagingFactory1, NULL, CLSCTX_INPROC_SERVER, &IID_IWICImagingFactory, &wicFactory))) goto CleanupExit; - // Find the resource - if ((resourceHandleSource = FindResource(DllBase, Name, L"PNG")) == NULL) - goto CleanupExit; - - // Get the resource length - resourceLength = SizeofResource(DllBase, resourceHandleSource); - // Load the resource - if ((resourceHandle = LoadResource(DllBase, resourceHandleSource)) == NULL) - goto CleanupExit; - - if ((resourceBuffer = (WICInProcPointer)LockResource(resourceHandle)) == NULL) + if (!PhLoadResource(DllBase, Name, L"PNG", &resourceLength, &resourceBuffer)) goto CleanupExit; // Create the Stream @@ -302,8 +290,8 @@ HBITMAP PhLoadPngImageFromResource( if (wicFactory) IWICImagingFactory_Release(wicFactory); - if (resourceHandle) - FreeResource(resourceHandle); + if (resourceBuffer) + PhFree(resourceBuffer); if (success) { From 172d4330950d1e9ccd36ea618f5a9071a7ddb314 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 10 Oct 2017 21:46:52 +1100 Subject: [PATCH 0485/2058] KPH: Fix issue deleting service after exit --- phlib/include/kphuser.h | 7 ++++++ phlib/kph.c | 54 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 60 insertions(+), 1 deletion(-) diff --git a/phlib/include/kphuser.h b/phlib/include/kphuser.h index 102534b55a62..e58b99f9de10 100644 --- a/phlib/include/kphuser.h +++ b/phlib/include/kphuser.h @@ -66,6 +66,13 @@ KphSetParameters( _In_ PKPH_PARAMETERS Parameters ); +PHLIBAPI +VOID +NTAPI +KphSetServiceSecurity( + _In_ SC_HANDLE ServiceHandle + ); + PHLIBAPI NTSTATUS NTAPI diff --git a/phlib/kph.c b/phlib/kph.c index e27f622ca57b..43935b3f7d28 100644 --- a/phlib/kph.c +++ b/phlib/kph.c @@ -180,6 +180,8 @@ NTSTATUS KphConnect2Ex( { created = TRUE; + KphSetServiceSecurity(serviceHandle); + // Set parameters if the caller supplied them. Note that we fail the entire function // if this fails, because failing to set parameters like SecurityLevel may result in // security vulnerabilities. @@ -215,7 +217,7 @@ NTSTATUS KphConnect2Ex( } CreateAndConnectEnd: - if (created) + if (created && serviceHandle) { // "Delete" the service. Since we (may) have a handle to the device, the SCM will delete the // service automatically when it is stopped (upon reboot). If we don't have a handle to the @@ -344,6 +346,54 @@ NTSTATUS KphSetParameters( return status; } +VOID KphSetServiceSecurity( + _In_ SC_HANDLE ServiceHandle + ) +{ + static SID_IDENTIFIER_AUTHORITY ntAuthority = SECURITY_NT_AUTHORITY; + PSECURITY_DESCRIPTOR securityDescriptor; + ULONG sdAllocationLength; + UCHAR administratorsSidBuffer[FIELD_OFFSET(SID, SubAuthority) + sizeof(ULONG) * 2]; + PSID administratorsSid; + PACL dacl; + + administratorsSid = (PSID)administratorsSidBuffer; + RtlInitializeSid(administratorsSid, &ntAuthority, 2); + *RtlSubAuthoritySid(administratorsSid, 0) = SECURITY_BUILTIN_DOMAIN_RID; + *RtlSubAuthoritySid(administratorsSid, 1) = DOMAIN_ALIAS_RID_ADMINS; + + sdAllocationLength = SECURITY_DESCRIPTOR_MIN_LENGTH + + (ULONG)sizeof(ACL) + + (ULONG)sizeof(ACCESS_ALLOWED_ACE) + + RtlLengthSid(&PhSeServiceSid) + + (ULONG)sizeof(ACCESS_ALLOWED_ACE) + + RtlLengthSid(administratorsSid) + + (ULONG)sizeof(ACCESS_ALLOWED_ACE) + + RtlLengthSid(&PhSeInteractiveSid); + + securityDescriptor = PhAllocate(sdAllocationLength); + dacl = (PACL)((PCHAR)securityDescriptor + SECURITY_DESCRIPTOR_MIN_LENGTH); + + RtlCreateSecurityDescriptor(securityDescriptor, SECURITY_DESCRIPTOR_REVISION); + RtlCreateAcl(dacl, sdAllocationLength - SECURITY_DESCRIPTOR_MIN_LENGTH, ACL_REVISION); + RtlAddAccessAllowedAce(dacl, ACL_REVISION, SERVICE_ALL_ACCESS, &PhSeServiceSid); + RtlAddAccessAllowedAce(dacl, ACL_REVISION, SERVICE_ALL_ACCESS, administratorsSid); + RtlAddAccessAllowedAce(dacl, ACL_REVISION, + SERVICE_QUERY_CONFIG | + SERVICE_QUERY_STATUS | + SERVICE_START | + SERVICE_STOP | + SERVICE_INTERROGATE | + DELETE, + &PhSeInteractiveSid + ); + RtlSetDaclSecurityDescriptor(securityDescriptor, TRUE, dacl, FALSE); + + SetServiceObjectSecurity(ServiceHandle, DACL_SECURITY_INFORMATION, securityDescriptor); + + PhFree(securityDescriptor); +} + NTSTATUS KphInstall( _In_opt_ PWSTR DeviceName, _In_ PWSTR FileName @@ -388,6 +438,8 @@ NTSTATUS KphInstallEx( if (serviceHandle) { + KphSetServiceSecurity(serviceHandle); + // See KphConnect2Ex for more details. if (Parameters) { From 2450843721887cd096ccd5996aae4c6a3870a69f Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 10 Oct 2017 22:57:53 +1100 Subject: [PATCH 0486/2058] Fix options window seperator drawing issues (experimental) --- ProcessHacker/ProcessHacker.rc | 11 +-- ProcessHacker/options.c | 174 +++++++++++++++++++++++++++++---- 2 files changed, 159 insertions(+), 26 deletions(-) diff --git a/ProcessHacker/ProcessHacker.rc b/ProcessHacker/ProcessHacker.rc index ffb1f8741c04..19a03b36c7da 100644 --- a/ProcessHacker/ProcessHacker.rc +++ b/ProcessHacker/ProcessHacker.rc @@ -1854,12 +1854,11 @@ CAPTION "Options" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN DEFPUSHBUTTON "Close",IDOK,371,231,50,14 - CONTROL "",IDC_SECTIONTREE,"SysTreeView32",TVS_SHOWSELALWAYS | TVS_TRACKSELECT | TVS_FULLROWSELECT | WS_HSCROLL | WS_TABSTOP,2,1,103,244 - CONTROL "",IDD_CONTAINER,"#32770",0x44c,107,0,316,229,WS_EX_TOPMOST | WS_EX_TOOLWINDOW | WS_EX_CONTROLPARENT | 0xc0000800L - LTEXT "",IDC_SEPARATOR,105,0,8,246 - PUSHBUTTON "Reset",IDC_RESET,113,231,50,14 + CONTROL "",IDC_SECTIONTREE,"SysTreeView32",TVS_SHOWSELALWAYS | TVS_TRACKSELECT | TVS_FULLROWSELECT | WS_BORDER | WS_HSCROLL | WS_TABSTOP,2,0,103,246 + CONTROL "",IDD_CONTAINER,"#32770",0x44c,105,0,318,229,WS_EX_TOPMOST | WS_EX_TOOLWINDOW | WS_EX_CONTROLPARENT | 0xc0000800L + PUSHBUTTON "Reset",IDC_RESET,107,231,50,14 PUSHBUTTON "Apply",IDC_APPLY,319,231,50,14,NOT WS_VISIBLE - PUSHBUTTON "Cleanup",IDC_CLEANUP,165,231,50,14 + PUSHBUTTON "Cleanup",IDC_CLEANUP,159,231,50,14 END @@ -2398,7 +2397,7 @@ BEGIN IDD_OPTIONS, DIALOG BEGIN LEFTMARGIN, 2 - BOTTOMMARGIN, 245 + BOTTOMMARGIN, 246 END END #endif // APSTUDIO_INVOKED diff --git a/ProcessHacker/options.c b/ProcessHacker/options.c index 31ef37cd061c..ff991452817b 100644 --- a/ProcessHacker/options.c +++ b/ProcessHacker/options.c @@ -80,6 +80,15 @@ INT_PTR CALLBACK PhOptionsDialogProc( _In_ LPARAM lParam ); +LRESULT CALLBACK PhpSelectionTreeSubclassProc( + _In_ HWND hWnd, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam, + _In_ UINT_PTR uIdSubclass, + _In_ ULONG_PTR dwRefData + ); + VOID PhOptionsDestroySection( _In_ PPH_OPTIONS_SECTION Section ); @@ -325,8 +334,6 @@ INT_PTR CALLBACK PhOptionsDialogProc( OptionsTreeControl = GetDlgItem(PhOptionsWindowHandle, IDC_SECTIONTREE); ContainerControl = GetDlgItem(PhOptionsWindowHandle, IDD_CONTAINER); - PhSetWindowStyle(GetDlgItem(hwndDlg, IDC_SEPARATOR), SS_OWNERDRAW, SS_OWNERDRAW); - PhSetControlTheme(OptionsTreeControl, L"explorer"); TreeView_SetExtendedStyle(OptionsTreeControl, TVS_EX_DOUBLEBUFFER, TVS_EX_DOUBLEBUFFER); TreeView_SetImageList(OptionsTreeControl, OptionsTreeImageList, TVSIL_NORMAL); @@ -334,13 +341,15 @@ INT_PTR CALLBACK PhOptionsDialogProc( PhInitializeLayoutManager(&WindowLayoutManager, PhOptionsWindowHandle); PhAddLayoutItem(&WindowLayoutManager, OptionsTreeControl, NULL, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_BOTTOM); - PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDC_SEPARATOR), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_BOTTOM); PhAddLayoutItem(&WindowLayoutManager, ContainerControl, NULL, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(PhOptionsWindowHandle, IDC_RESET), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_BOTTOM); PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(PhOptionsWindowHandle, IDC_CLEANUP), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_BOTTOM); //PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(PhOptionsWindowHandle, IDC_APPLY), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(PhOptionsWindowHandle, IDOK), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); + SetWindowSubclass(OptionsTreeControl, PhpSelectionTreeSubclassProc, 0, 0); + SendMessage(OptionsTreeControl, WM_THEMECHANGED, 0, 0); + EnableThemeDialogTexture(ContainerControl, ETDT_ENABLETAB); { @@ -451,23 +460,6 @@ INT_PTR CALLBACK PhOptionsDialogProc( } } break; - case WM_DRAWITEM: - { - PDRAWITEMSTRUCT drawInfo = (PDRAWITEMSTRUCT)lParam; - - if (drawInfo->CtlID == IDC_SEPARATOR) - { - RECT rect; - - rect = drawInfo->rcItem; - rect.right = 2; - FillRect(drawInfo->hDC, &rect, GetSysColorBrush(COLOR_3DHIGHLIGHT)); - rect.left += 1; - FillRect(drawInfo->hDC, &rect, GetSysColorBrush(COLOR_3DSHADOW)); - return TRUE; - } - } - break; case WM_NOTIFY: { LPNMHDR header = (LPNMHDR)lParam; @@ -1914,3 +1906,145 @@ INT_PTR CALLBACK PhpOptionsGraphsDlgProc( return FALSE; } + +VOID PhpSelectionTreeDrawThemedFrame( + _In_ HWND hWnd, + _In_ HRGN UpdateRegion, + _In_ HTHEME ThemeData + ) +{ + INT systemEdgeX; + INT systemEdgeY; + HDC hdc; + ULONG flags; + + systemEdgeX = GetSystemMetrics(SM_CXEDGE); + systemEdgeY = GetSystemMetrics(SM_CYEDGE); + + if (UpdateRegion == (HRGN)1) + UpdateRegion = NULL; + + // Note the use of undocumented flags below. GetDCEx doesn't work without these. + + flags = DCX_WINDOW | DCX_LOCKWINDOWUPDATE | 0x10000; + + if (UpdateRegion) + flags |= DCX_INTERSECTRGN | 0x40000; + + if (hdc = GetDCEx(hWnd, UpdateRegion, flags)) + { + RECT windowRect; + RECT clientRect; + RECT tempRect; + LONG sizingBorderWidth; + LONG borderX; + LONG borderY; + + GetWindowRect(hWnd, &windowRect); + windowRect.right -= windowRect.left; + windowRect.bottom -= windowRect.top; + windowRect.left = 0; + windowRect.top = 0; + + clientRect.left = windowRect.left + systemEdgeX; + clientRect.top = windowRect.top + systemEdgeY; + clientRect.right = windowRect.right - systemEdgeX; + clientRect.bottom = windowRect.bottom - systemEdgeY; + + // Make sure we don't paint in the client area. + ExcludeClipRect(hdc, clientRect.left, clientRect.top, clientRect.right, clientRect.bottom); + + // Draw the themed border. + tempRect = windowRect; + tempRect.left = tempRect.right - 2; + FillRect(hdc, &tempRect, GetSysColorBrush(COLOR_3DHIGHLIGHT)); + tempRect.left = tempRect.right - 1; + FillRect(hdc, &tempRect, GetSysColorBrush(COLOR_3DSHADOW)); + + // Calculate the size of the border we just drew, and fill in the rest of the space if we didn't + // fully paint the region. + + if (SUCCEEDED(GetThemeInt(ThemeData, 0, 0, TMT_SIZINGBORDERWIDTH, &sizingBorderWidth))) + { + borderX = sizingBorderWidth; + borderY = sizingBorderWidth; + } + else + { + borderX = GetSystemMetrics(SM_CXBORDER); + borderY = GetSystemMetrics(SM_CYBORDER); + } + + if (borderX < systemEdgeX || borderY < systemEdgeY) + { + windowRect.left += systemEdgeX - borderX; + windowRect.top += systemEdgeY - borderY; + windowRect.right -= systemEdgeX - borderX; + windowRect.bottom -= systemEdgeY - borderY; + + FillRect(hdc, &windowRect, GetSysColorBrush(COLOR_3DFACE)); + } + + ReleaseDC(hWnd, hdc); + } +} + +LRESULT CALLBACK PhpSelectionTreeSubclassProc( + _In_ HWND hWnd, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam, + _In_ UINT_PTR uIdSubclass, + _In_ ULONG_PTR dwRefData + ) +{ + HTHEME treeThemeData = (HTHEME)GetWindowLongPtr(hWnd, GWLP_USERDATA); + + switch (uMsg) + { + case WM_DESTROY: + { + RemoveWindowSubclass(hWnd, PhpSelectionTreeSubclassProc, uIdSubclass); + + CloseThemeData(treeThemeData); + SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)NULL); + } + break; + case WM_SYSCOLORCHANGE: + case WM_SETFOCUS: + case WM_KILLFOCUS: + case WM_ENABLE: + { + if (treeThemeData) + { + PhpSelectionTreeDrawThemedFrame(hWnd, NULL, treeThemeData); + } + } + break; + case WM_THEMECHANGED: + { + if (treeThemeData) + { + CloseThemeData(treeThemeData); + treeThemeData = NULL; + } + + treeThemeData = OpenThemeData(hWnd, VSCLASS_TREEVIEW); + SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)treeThemeData); + InvalidateRect(hWnd, NULL, TRUE); + } + break; + case WM_NCPAINT: + { + if (treeThemeData) + { + PhpSelectionTreeDrawThemedFrame(hWnd, (HRGN)wParam, treeThemeData); + return TRUE; + } + } + break; + } + + return DefSubclassProc(hWnd, uMsg, wParam, lParam); +} + From 349a98c723d34997087161f5e96c06e4dc282be1 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 11 Oct 2017 00:31:22 +1100 Subject: [PATCH 0487/2058] Revert "Fix options window seperator drawing issues (experimental)" This reverts commit 2450843721887cd096ccd5996aae4c6a3870a69f. --- ProcessHacker/ProcessHacker.rc | 11 ++- ProcessHacker/options.c | 174 ++++----------------------------- 2 files changed, 26 insertions(+), 159 deletions(-) diff --git a/ProcessHacker/ProcessHacker.rc b/ProcessHacker/ProcessHacker.rc index 19a03b36c7da..ffb1f8741c04 100644 --- a/ProcessHacker/ProcessHacker.rc +++ b/ProcessHacker/ProcessHacker.rc @@ -1854,11 +1854,12 @@ CAPTION "Options" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN DEFPUSHBUTTON "Close",IDOK,371,231,50,14 - CONTROL "",IDC_SECTIONTREE,"SysTreeView32",TVS_SHOWSELALWAYS | TVS_TRACKSELECT | TVS_FULLROWSELECT | WS_BORDER | WS_HSCROLL | WS_TABSTOP,2,0,103,246 - CONTROL "",IDD_CONTAINER,"#32770",0x44c,105,0,318,229,WS_EX_TOPMOST | WS_EX_TOOLWINDOW | WS_EX_CONTROLPARENT | 0xc0000800L - PUSHBUTTON "Reset",IDC_RESET,107,231,50,14 + CONTROL "",IDC_SECTIONTREE,"SysTreeView32",TVS_SHOWSELALWAYS | TVS_TRACKSELECT | TVS_FULLROWSELECT | WS_HSCROLL | WS_TABSTOP,2,1,103,244 + CONTROL "",IDD_CONTAINER,"#32770",0x44c,107,0,316,229,WS_EX_TOPMOST | WS_EX_TOOLWINDOW | WS_EX_CONTROLPARENT | 0xc0000800L + LTEXT "",IDC_SEPARATOR,105,0,8,246 + PUSHBUTTON "Reset",IDC_RESET,113,231,50,14 PUSHBUTTON "Apply",IDC_APPLY,319,231,50,14,NOT WS_VISIBLE - PUSHBUTTON "Cleanup",IDC_CLEANUP,159,231,50,14 + PUSHBUTTON "Cleanup",IDC_CLEANUP,165,231,50,14 END @@ -2397,7 +2398,7 @@ BEGIN IDD_OPTIONS, DIALOG BEGIN LEFTMARGIN, 2 - BOTTOMMARGIN, 246 + BOTTOMMARGIN, 245 END END #endif // APSTUDIO_INVOKED diff --git a/ProcessHacker/options.c b/ProcessHacker/options.c index ff991452817b..31ef37cd061c 100644 --- a/ProcessHacker/options.c +++ b/ProcessHacker/options.c @@ -80,15 +80,6 @@ INT_PTR CALLBACK PhOptionsDialogProc( _In_ LPARAM lParam ); -LRESULT CALLBACK PhpSelectionTreeSubclassProc( - _In_ HWND hWnd, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam, - _In_ UINT_PTR uIdSubclass, - _In_ ULONG_PTR dwRefData - ); - VOID PhOptionsDestroySection( _In_ PPH_OPTIONS_SECTION Section ); @@ -334,6 +325,8 @@ INT_PTR CALLBACK PhOptionsDialogProc( OptionsTreeControl = GetDlgItem(PhOptionsWindowHandle, IDC_SECTIONTREE); ContainerControl = GetDlgItem(PhOptionsWindowHandle, IDD_CONTAINER); + PhSetWindowStyle(GetDlgItem(hwndDlg, IDC_SEPARATOR), SS_OWNERDRAW, SS_OWNERDRAW); + PhSetControlTheme(OptionsTreeControl, L"explorer"); TreeView_SetExtendedStyle(OptionsTreeControl, TVS_EX_DOUBLEBUFFER, TVS_EX_DOUBLEBUFFER); TreeView_SetImageList(OptionsTreeControl, OptionsTreeImageList, TVSIL_NORMAL); @@ -341,15 +334,13 @@ INT_PTR CALLBACK PhOptionsDialogProc( PhInitializeLayoutManager(&WindowLayoutManager, PhOptionsWindowHandle); PhAddLayoutItem(&WindowLayoutManager, OptionsTreeControl, NULL, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_BOTTOM); + PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDC_SEPARATOR), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_BOTTOM); PhAddLayoutItem(&WindowLayoutManager, ContainerControl, NULL, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(PhOptionsWindowHandle, IDC_RESET), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_BOTTOM); PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(PhOptionsWindowHandle, IDC_CLEANUP), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_BOTTOM); //PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(PhOptionsWindowHandle, IDC_APPLY), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(PhOptionsWindowHandle, IDOK), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); - SetWindowSubclass(OptionsTreeControl, PhpSelectionTreeSubclassProc, 0, 0); - SendMessage(OptionsTreeControl, WM_THEMECHANGED, 0, 0); - EnableThemeDialogTexture(ContainerControl, ETDT_ENABLETAB); { @@ -460,6 +451,23 @@ INT_PTR CALLBACK PhOptionsDialogProc( } } break; + case WM_DRAWITEM: + { + PDRAWITEMSTRUCT drawInfo = (PDRAWITEMSTRUCT)lParam; + + if (drawInfo->CtlID == IDC_SEPARATOR) + { + RECT rect; + + rect = drawInfo->rcItem; + rect.right = 2; + FillRect(drawInfo->hDC, &rect, GetSysColorBrush(COLOR_3DHIGHLIGHT)); + rect.left += 1; + FillRect(drawInfo->hDC, &rect, GetSysColorBrush(COLOR_3DSHADOW)); + return TRUE; + } + } + break; case WM_NOTIFY: { LPNMHDR header = (LPNMHDR)lParam; @@ -1906,145 +1914,3 @@ INT_PTR CALLBACK PhpOptionsGraphsDlgProc( return FALSE; } - -VOID PhpSelectionTreeDrawThemedFrame( - _In_ HWND hWnd, - _In_ HRGN UpdateRegion, - _In_ HTHEME ThemeData - ) -{ - INT systemEdgeX; - INT systemEdgeY; - HDC hdc; - ULONG flags; - - systemEdgeX = GetSystemMetrics(SM_CXEDGE); - systemEdgeY = GetSystemMetrics(SM_CYEDGE); - - if (UpdateRegion == (HRGN)1) - UpdateRegion = NULL; - - // Note the use of undocumented flags below. GetDCEx doesn't work without these. - - flags = DCX_WINDOW | DCX_LOCKWINDOWUPDATE | 0x10000; - - if (UpdateRegion) - flags |= DCX_INTERSECTRGN | 0x40000; - - if (hdc = GetDCEx(hWnd, UpdateRegion, flags)) - { - RECT windowRect; - RECT clientRect; - RECT tempRect; - LONG sizingBorderWidth; - LONG borderX; - LONG borderY; - - GetWindowRect(hWnd, &windowRect); - windowRect.right -= windowRect.left; - windowRect.bottom -= windowRect.top; - windowRect.left = 0; - windowRect.top = 0; - - clientRect.left = windowRect.left + systemEdgeX; - clientRect.top = windowRect.top + systemEdgeY; - clientRect.right = windowRect.right - systemEdgeX; - clientRect.bottom = windowRect.bottom - systemEdgeY; - - // Make sure we don't paint in the client area. - ExcludeClipRect(hdc, clientRect.left, clientRect.top, clientRect.right, clientRect.bottom); - - // Draw the themed border. - tempRect = windowRect; - tempRect.left = tempRect.right - 2; - FillRect(hdc, &tempRect, GetSysColorBrush(COLOR_3DHIGHLIGHT)); - tempRect.left = tempRect.right - 1; - FillRect(hdc, &tempRect, GetSysColorBrush(COLOR_3DSHADOW)); - - // Calculate the size of the border we just drew, and fill in the rest of the space if we didn't - // fully paint the region. - - if (SUCCEEDED(GetThemeInt(ThemeData, 0, 0, TMT_SIZINGBORDERWIDTH, &sizingBorderWidth))) - { - borderX = sizingBorderWidth; - borderY = sizingBorderWidth; - } - else - { - borderX = GetSystemMetrics(SM_CXBORDER); - borderY = GetSystemMetrics(SM_CYBORDER); - } - - if (borderX < systemEdgeX || borderY < systemEdgeY) - { - windowRect.left += systemEdgeX - borderX; - windowRect.top += systemEdgeY - borderY; - windowRect.right -= systemEdgeX - borderX; - windowRect.bottom -= systemEdgeY - borderY; - - FillRect(hdc, &windowRect, GetSysColorBrush(COLOR_3DFACE)); - } - - ReleaseDC(hWnd, hdc); - } -} - -LRESULT CALLBACK PhpSelectionTreeSubclassProc( - _In_ HWND hWnd, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam, - _In_ UINT_PTR uIdSubclass, - _In_ ULONG_PTR dwRefData - ) -{ - HTHEME treeThemeData = (HTHEME)GetWindowLongPtr(hWnd, GWLP_USERDATA); - - switch (uMsg) - { - case WM_DESTROY: - { - RemoveWindowSubclass(hWnd, PhpSelectionTreeSubclassProc, uIdSubclass); - - CloseThemeData(treeThemeData); - SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)NULL); - } - break; - case WM_SYSCOLORCHANGE: - case WM_SETFOCUS: - case WM_KILLFOCUS: - case WM_ENABLE: - { - if (treeThemeData) - { - PhpSelectionTreeDrawThemedFrame(hWnd, NULL, treeThemeData); - } - } - break; - case WM_THEMECHANGED: - { - if (treeThemeData) - { - CloseThemeData(treeThemeData); - treeThemeData = NULL; - } - - treeThemeData = OpenThemeData(hWnd, VSCLASS_TREEVIEW); - SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)treeThemeData); - InvalidateRect(hWnd, NULL, TRUE); - } - break; - case WM_NCPAINT: - { - if (treeThemeData) - { - PhpSelectionTreeDrawThemedFrame(hWnd, (HRGN)wParam, treeThemeData); - return TRUE; - } - } - break; - } - - return DefSubclassProc(hWnd, uMsg, wParam, lParam); -} - From 5bd68c4357f311b4c70ffda680938f35315ac42b Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 14 Oct 2017 17:03:49 +1100 Subject: [PATCH 0488/2058] Remove GetTickCount --- ProcessHacker/include/phapp.h | 2 +- ProcessHacker/include/phuisup.h | 8 ++++---- ProcessHacker/include/proctree.h | 2 +- ProcessHacker/itemtips.c | 4 ++-- ProcessHacker/mdump.c | 8 ++++---- ProcessHacker/miniinfo.c | 3 --- ProcessHacker/proctree.c | 6 +++--- phlib/hndlinfo.c | 6 +++--- phlib/include/phsup.h | 6 +++--- phlib/util.c | 12 ++++++------ 10 files changed, 27 insertions(+), 30 deletions(-) diff --git a/ProcessHacker/include/phapp.h b/ProcessHacker/include/phapp.h index aaf3ed2325b6..a23878fd7ae5 100644 --- a/ProcessHacker/include/phapp.h +++ b/ProcessHacker/include/phapp.h @@ -262,7 +262,7 @@ VOID PhShowDebugConsole( PPH_STRING PhGetProcessTooltipText( _In_ PPH_PROCESS_ITEM Process, - _Out_opt_ PULONG ValidToTickCount + _Out_opt_ PULONG64 ValidToTickCount ); PPH_STRING PhGetServiceTooltipText( diff --git a/ProcessHacker/include/phuisup.h b/ProcessHacker/include/phuisup.h index b7160daaf5b3..23f439a4cff8 100644 --- a/ProcessHacker/include/phuisup.h +++ b/ProcessHacker/include/phuisup.h @@ -8,7 +8,7 @@ typedef struct _PH_SH_STATE { PH_ITEM_STATE State; HANDLE StateListHandle; - ULONG TickCount; + ULONG64 TickCount; } PH_SH_STATE, *PPH_SH_STATE; // end_phapppub @@ -27,7 +27,7 @@ FORCEINLINE VOID PhChangeShStateTn( if (ShState->State == NormalItemState) ShState->StateListHandle = PhAddItemPointerList(*StateList, Node); - ShState->TickCount = GetTickCount(); + ShState->TickCount = NtGetTickCount64(); ShState->State = NewState; Node->UseTempBackColor = TRUE; @@ -41,7 +41,7 @@ FORCEINLINE VOID PhChangeShStateTn( do { \ NodeType *node; \ ULONG enumerationKey = 0; \ - ULONG tickCount; \ + ULONG64 tickCount; \ BOOLEAN preferFullInvalidate; \ HANDLE stateListHandle; \ BOOLEAN redrawDisabled = FALSE; \ @@ -50,7 +50,7 @@ FORCEINLINE VOID PhChangeShStateTn( if (!StateList || StateList->Count == 0) \ break; \ \ - tickCount = GetTickCount(); \ + tickCount = NtGetTickCount64(); \ preferFullInvalidate = StateList->Count > 8; \ \ while (PhEnumPointerList(StateList, &enumerationKey, &node)) \ diff --git a/ProcessHacker/include/proctree.h b/ProcessHacker/include/proctree.h index 4c9ab88a7ab2..3535bfbd605e 100644 --- a/ProcessHacker/include/proctree.h +++ b/ProcessHacker/include/proctree.h @@ -169,7 +169,7 @@ typedef struct _PH_PROCESS_NODE LARGE_INTEGER FileEndOfFile; PPH_STRING TooltipText; - ULONG TooltipTextValidToTickCount; + ULONG64 TooltipTextValidToTickCount; // Text buffers WCHAR CpuUsageText[PH_INT32_STR_LEN_1]; diff --git a/ProcessHacker/itemtips.c b/ProcessHacker/itemtips.c index 318592248aaf..b022e2dbb036 100644 --- a/ProcessHacker/itemtips.c +++ b/ProcessHacker/itemtips.c @@ -95,7 +95,7 @@ static int __cdecl ServiceForTooltipCompare( PPH_STRING PhGetProcessTooltipText( _In_ PPH_PROCESS_ITEM Process, - _Out_opt_ PULONG ValidToTickCount + _Out_opt_ PULONG64 ValidToTickCount ) { PH_STRING_BUILDER stringBuilder; @@ -422,7 +422,7 @@ PPH_STRING PhGetProcessTooltipText( } if (ValidToTickCount) - *ValidToTickCount = GetTickCount() + validForMs; + *ValidToTickCount = NtGetTickCount64() + validForMs; // Remove the trailing newline. if (stringBuilder.String->Length != 0) diff --git a/ProcessHacker/mdump.c b/ProcessHacker/mdump.c index b31dc20ae7b3..e4bf2a239f32 100644 --- a/ProcessHacker/mdump.c +++ b/ProcessHacker/mdump.c @@ -51,7 +51,7 @@ typedef struct _PROCESS_MINIDUMP_CONTEXT BOOLEAN Stop; BOOLEAN Succeeded; - ULONG LastTickCount; + ULONG64 LastTickCount; } PROCESS_MINIDUMP_CONTEXT, *PPROCESS_MINIDUMP_CONTEXT; BOOLEAN PhpCreateProcessMiniDumpWithProgress( @@ -410,9 +410,9 @@ INT_PTR CALLBACK PhpProcessMiniDumpDlgProc( { PPROCESS_MINIDUMP_CONTEXT context = (PPROCESS_MINIDUMP_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom()); - ULONG currentTickCount; + ULONG64 currentTickCount; - currentTickCount = GetTickCount(); + currentTickCount = NtGetTickCount64(); if (currentTickCount - context->LastTickCount >= 2000) { @@ -438,7 +438,7 @@ INT_PTR CALLBACK PhpProcessMiniDumpDlgProc( case PH_MINIDUMP_STATUS_UPDATE: SetDlgItemText(hwndDlg, IDC_PROGRESSTEXT, (PWSTR)lParam); InvalidateRect(GetDlgItem(hwndDlg, IDC_PROGRESSTEXT), NULL, FALSE); - context->LastTickCount = GetTickCount(); + context->LastTickCount = NtGetTickCount64(); break; case PH_MINIDUMP_ERROR: PhShowStatus(hwndDlg, L"Unable to create the minidump", 0, (ULONG)lParam); diff --git a/ProcessHacker/miniinfo.c b/ProcessHacker/miniinfo.c index e1d3489d7296..ccef3ad0b9c1 100644 --- a/ProcessHacker/miniinfo.c +++ b/ProcessHacker/miniinfo.c @@ -1634,9 +1634,6 @@ BOOLEAN PhMipListSectionTreeNewCallback( { PPH_TREENEW_GET_CELL_TOOLTIP getCellTooltip = Parameter1; PPH_MIP_GROUP_NODE node = (PPH_MIP_GROUP_NODE)getCellTooltip->Node; - ULONG tickCount; - - tickCount = GetTickCount(); // This is useless most of the time because the tooltip doesn't display unless the window is active. // TODO: Find a way to make the tooltip display all the time. diff --git a/ProcessHacker/proctree.c b/ProcessHacker/proctree.c index 22bf759f5d1c..3d1ba2b22158 100644 --- a/ProcessHacker/proctree.c +++ b/ProcessHacker/proctree.c @@ -2737,16 +2737,16 @@ BOOLEAN NTAPI PhpProcessTreeNewCallback( case TreeNewGetCellTooltip: { PPH_TREENEW_GET_CELL_TOOLTIP getCellTooltip = Parameter1; - ULONG tickCount; + ULONG64 tickCount; node = (PPH_PROCESS_NODE)getCellTooltip->Node; if (getCellTooltip->Column->Id != 0) return FALSE; - tickCount = GetTickCount(); + tickCount = NtGetTickCount64(); - if ((LONG)(node->TooltipTextValidToTickCount - tickCount) < 0) + if ((LONG64)(node->TooltipTextValidToTickCount - tickCount) < 0) PhClearReference(&node->TooltipText); if (!node->TooltipText) node->TooltipText = PhGetProcessTooltipText(node->ProcessItem, &node->TooltipTextValidToTickCount); diff --git a/phlib/hndlinfo.c b/phlib/hndlinfo.c index 58c22e8b8bbf..877b530f9fd5 100644 --- a/phlib/hndlinfo.c +++ b/phlib/hndlinfo.c @@ -480,15 +480,15 @@ _Callback_ PPH_STRING PhStdGetClientIdName( { static PH_QUEUED_LOCK cachedProcessesLock = PH_QUEUED_LOCK_INIT; static PVOID processes = NULL; - static ULONG lastProcessesTickCount = 0; + static ULONG64 lastProcessesTickCount = 0; PPH_STRING name; - ULONG tickCount; + ULONG64 tickCount; PSYSTEM_PROCESS_INFORMATION processInfo; // Get a new process list only if 2 seconds have passed since the last update. - tickCount = GetTickCount(); + tickCount = NtGetTickCount64(); if (tickCount - lastProcessesTickCount >= 2000) { diff --git a/phlib/include/phsup.h b/phlib/include/phsup.h index f669fb940271..006955251e85 100644 --- a/phlib/include/phsup.h +++ b/phlib/include/phsup.h @@ -458,9 +458,9 @@ FORCEINLINE ULONG PhCountBits( return count; } -FORCEINLINE ULONG PhRoundNumber( - _In_ ULONG Value, - _In_ ULONG Granularity +FORCEINLINE ULONG64 PhRoundNumber( + _In_ ULONG64 Value, + _In_ ULONG64 Granularity ) { return (Value + Granularity / 2) / Granularity * Granularity; diff --git a/phlib/util.c b/phlib/util.c index 5a4089afec2d..67fd7a565518 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -2296,11 +2296,11 @@ NTSTATUS PhWaitForMultipleObjectsAndPump( ) { NTSTATUS status; - ULONG startTickCount; - ULONG currentTickCount; - LONG currentTimeout; + ULONG64 startTickCount; + ULONG64 currentTickCount; + ULONG64 currentTimeout; - startTickCount = GetTickCount(); + startTickCount = NtGetTickCount64(); currentTimeout = Timeout; while (TRUE) @@ -2338,10 +2338,10 @@ NTSTATUS PhWaitForMultipleObjectsAndPump( if (Timeout != INFINITE) { - currentTickCount = GetTickCount(); + currentTickCount = NtGetTickCount64(); currentTimeout = Timeout - (currentTickCount - startTickCount); - if (currentTimeout < 0) + if ((LONG64)currentTimeout < 0) return STATUS_TIMEOUT; } } From f3a58abf51342e164bc7987d552c4d71f1b8b4cd Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 14 Oct 2017 17:04:29 +1100 Subject: [PATCH 0489/2058] Fix PhCreateNamedPipe error on Win7 --- phlib/native.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/phlib/native.c b/phlib/native.c index 4b99fe5466c5..7f3c630d2d9a 100644 --- a/phlib/native.c +++ b/phlib/native.c @@ -6562,7 +6562,7 @@ NTSTATUS PhCreateNamedPipe( ) { NTSTATUS status; - PACL pipeAcl; + PACL pipeAcl = NULL; HANDLE pipeHandle; PPH_STRING pipeName; LARGE_INTEGER pipeTimeout; @@ -6588,7 +6588,6 @@ NTSTATUS PhCreateNamedPipe( RtlCreateSecurityDescriptor(&securityDescriptor, SECURITY_DESCRIPTOR_REVISION); RtlSetDaclSecurityDescriptor(&securityDescriptor, TRUE, pipeAcl, FALSE); - RtlFreeHeap(RtlProcessHeap(), 0, pipeAcl); oa.SecurityDescriptor = &securityDescriptor; } @@ -6615,6 +6614,9 @@ NTSTATUS PhCreateNamedPipe( *PipeHandle = pipeHandle; } + if (pipeAcl) + RtlFreeHeap(RtlProcessHeap(), 0, pipeAcl); + PhDereferenceObject(pipeName); return status; } From fe71733eb00b151bcac9435cb5b25277475c6bb7 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 14 Oct 2017 17:05:53 +1100 Subject: [PATCH 0490/2058] Update headers --- phnt/include/ntexapi.h | 2 +- phnt/include/ntldr.h | 32 ++++++++++++++++++++------------ 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/phnt/include/ntexapi.h b/phnt/include/ntexapi.h index 682d10db59f7..01452aa249b8 100644 --- a/phnt/include/ntexapi.h +++ b/phnt/include/ntexapi.h @@ -3457,7 +3457,7 @@ C_ASSERT(FIELD_OFFSET(KUSER_SHARED_DATA, SystemCallPad) == 0x310); C_ASSERT(FIELD_OFFSET(KUSER_SHARED_DATA, TickCount) == 0x320); C_ASSERT(FIELD_OFFSET(KUSER_SHARED_DATA, TickCountQuad) == 0x320); C_ASSERT(FIELD_OFFSET(KUSER_SHARED_DATA, XState) == 0x3d8); -//C_ASSERT(sizeof(KUSER_SHARED_DATA) == 0x708); // Visual Studio has a problem with this +//C_ASSERT(sizeof(KUSER_SHARED_DATA) == 0x704); // Visual Studio has a problem with this #define USER_SHARED_DATA ((KUSER_SHARED_DATA * const)0x7ffe0000) diff --git a/phnt/include/ntldr.h b/phnt/include/ntldr.h index f89b5f2360b0..84e8428ad7a8 100644 --- a/phnt/include/ntldr.h +++ b/phnt/include/ntldr.h @@ -552,6 +552,26 @@ LdrDisableThreadCalloutsForDll( _In_ PVOID DllImageBase ); +// Resources + +NTSYSAPI +NTSTATUS +NTAPI +LdrAccessResource( + _In_ PVOID BaseAddress, + _In_ PIMAGE_RESOURCE_DATA_ENTRY ResourceDataEntry, + _Out_opt_ PVOID *ResourceBuffer, + _Out_opt_ ULONG *ResourceLength + ); + +NTSYSAPI +NTSTATUS +NTAPI +LdrFindEntryForAddress( + _In_ PVOID BaseAddress, + _Out_ PLDR_DATA_TABLE_ENTRY *Entry + ); + #endif // (PHNT_MODE != PHNT_MODE_KERNEL) // Module information @@ -586,16 +606,4 @@ typedef struct _RTL_PROCESS_MODULE_INFORMATION_EX PVOID DefaultBase; } RTL_PROCESS_MODULE_INFORMATION_EX, *PRTL_PROCESS_MODULE_INFORMATION_EX; -// Resources - -NTSYSAPI -NTSTATUS -NTAPI -LdrAccessResource( - _In_ PVOID BaseAddress, - _In_ PIMAGE_RESOURCE_DATA_ENTRY ResourceDataEntry, - _Out_opt_ PVOID *ResourceBuffer, - _Out_opt_ ULONG *ResourceLength - ); - #endif From d83e887285e9a32433c4b82cadbc69e1325dc186 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 14 Oct 2017 17:06:30 +1100 Subject: [PATCH 0491/2058] Remove log window parent --- ProcessHacker/logwnd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ProcessHacker/logwnd.c b/ProcessHacker/logwnd.c index 74d7e4fe7289..61f3df459a57 100644 --- a/ProcessHacker/logwnd.c +++ b/ProcessHacker/logwnd.c @@ -52,7 +52,7 @@ VOID PhShowLogDialog( PhLogWindowHandle = CreateDialog( PhInstanceHandle, MAKEINTRESOURCE(IDD_LOG), - PhMainWndHandle, + NULL, PhpLogDlgProc ); PhRegisterDialog(PhLogWindowHandle); From 567ce0b75319dd89d69069ae236f6a77dc7721bf Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 14 Oct 2017 17:06:40 +1100 Subject: [PATCH 0492/2058] Remove unused cast --- ProcessHacker/hndlprv.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ProcessHacker/hndlprv.c b/ProcessHacker/hndlprv.c index cd1dd54c34c9..75d548132531 100644 --- a/ProcessHacker/hndlprv.c +++ b/ProcessHacker/hndlprv.c @@ -447,7 +447,7 @@ VOID PhHandleProviderUpdate( // Make a list of the relevant handles. if (filterNeeded) { - for (i = 0; i < (ULONG)numberOfHandles; i++) + for (i = 0; i < numberOfHandles; i++) { PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX handle = &handles[i]; @@ -463,7 +463,7 @@ VOID PhHandleProviderUpdate( } else { - for (i = 0; i < (ULONG)numberOfHandles; i++) + for (i = 0; i < numberOfHandles; i++) { PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX handle = &handles[i]; From 7b07f3638d94b7e3cbd4acac7228cf5ddf740d9f Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 14 Oct 2017 17:07:26 +1100 Subject: [PATCH 0493/2058] Improve PhCommandModeStart error checking --- ProcessHacker/cmdmode.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/ProcessHacker/cmdmode.c b/ProcessHacker/cmdmode.c index 481e03937358..6dcd32625fbe 100644 --- a/ProcessHacker/cmdmode.c +++ b/ProcessHacker/cmdmode.c @@ -64,19 +64,21 @@ NTSTATUS PhCommandModeStart( { { PH_COMMAND_OPTION_HWND, L"hwnd", MandatoryArgumentType } }; - NTSTATUS status = STATUS_SUCCESS; - PH_STRINGREF commandLine; + NTSTATUS status; + PPH_STRING commandLine; - PhUnicodeStringToStringRef(&NtCurrentPeb()->ProcessParameters->CommandLine, &commandLine); + if (!NT_SUCCESS(status = PhGetProcessCommandLine(NtCurrentProcess(), &commandLine))) + return status; PhParseCommandLine( - &commandLine, + &commandLine->sr, options, sizeof(options) / sizeof(PH_COMMAND_LINE_OPTION), PH_COMMAND_LINE_IGNORE_UNKNOWN_OPTIONS, PhpCommandModeOptionCallback, NULL ); + PhDereferenceObject(commandLine); if (PhEqualString2(PhStartupParameters.CommandType, L"process", TRUE)) { From 786b6c55197293d99df75474c776b1146b78ddcb Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 14 Oct 2017 17:07:54 +1100 Subject: [PATCH 0494/2058] ToolStatus: Fix statusbar issue with timezones --- plugins/ToolStatus/statusbar.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/ToolStatus/statusbar.c b/plugins/ToolStatus/statusbar.c index fa5df12ed8c8..7e18a6c56622 100644 --- a/plugins/ToolStatus/statusbar.c +++ b/plugins/ToolStatus/statusbar.c @@ -258,14 +258,14 @@ VOID StatusBarUpdate( // Reset max. widths for Max. CPU Process and Max. I/O Process parts once in a while. { - LARGE_INTEGER tickCount; + ULONG64 tickCount; - PhQuerySystemTime(&tickCount); + tickCount = NtGetTickCount64(); - if (tickCount.QuadPart - lastTickCount >= 10 * PH_TICKS_PER_SEC) + if (tickCount - lastTickCount >= 10 * 1000) { resetMaxWidths = TRUE; - lastTickCount = tickCount.QuadPart; + lastTickCount = tickCount; } } From 72a8fc818d6c4d1e72e16a845d432830907a6b0f Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 14 Oct 2017 17:09:06 +1100 Subject: [PATCH 0495/2058] CustomSetupTool: Clear download cache after updates --- tools/CustomSetupTool/CustomSetupTool/install.c | 2 ++ tools/CustomSetupTool/CustomSetupTool/setup.c | 5 ++++- tools/CustomSetupTool/CustomSetupTool/update.c | 2 ++ 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/tools/CustomSetupTool/CustomSetupTool/install.c b/tools/CustomSetupTool/CustomSetupTool/install.c index e54c6642ada3..18794635fbaf 100644 --- a/tools/CustomSetupTool/CustomSetupTool/install.c +++ b/tools/CustomSetupTool/CustomSetupTool/install.c @@ -72,6 +72,8 @@ NTSTATUS SetupProgressThread( if (Context->SetupInstallKphService) SetupStartKph(Context); + PhClearCacheDirectory(); + PostMessage(Context->ExtractPageHandle, WM_END_SETUP, 0, 0); return STATUS_SUCCESS; diff --git a/tools/CustomSetupTool/CustomSetupTool/setup.c b/tools/CustomSetupTool/CustomSetupTool/setup.c index 2050d7bddf58..d914e1d90444 100644 --- a/tools/CustomSetupTool/CustomSetupTool/setup.c +++ b/tools/CustomSetupTool/CustomSetupTool/setup.c @@ -197,12 +197,13 @@ BOOLEAN SetupCreateUninstallFile( PPH_STRING tempFileName; PPH_STRING tempFilePath; - tempFileName = PhCreateString(L"processhacker-setup.old"); + tempFileName = PhCreateString(L"processhacker-setup.bak"); tempFilePath = PhCreateCacheFile(tempFileName); if (!MoveFile(backupFilePath->Buffer, tempFilePath->Buffer)) { Context->ErrorCode = GetLastError(); + return FALSE; } PhDereferenceObject(tempFilePath); @@ -215,12 +216,14 @@ BOOLEAN SetupCreateUninstallFile( if (!MoveFile(uninstallFilePath->Buffer, backupFilePath->Buffer)) { Context->ErrorCode = GetLastError(); + return FALSE; } } if (!CopyFile(currentFilePath->Buffer, uninstallFilePath->Buffer, TRUE)) { Context->ErrorCode = GetLastError(); + return FALSE; } PhDereferenceObject(uninstallFilePath); diff --git a/tools/CustomSetupTool/CustomSetupTool/update.c b/tools/CustomSetupTool/CustomSetupTool/update.c index 8df1ced0220b..43ea2e386524 100644 --- a/tools/CustomSetupTool/CustomSetupTool/update.c +++ b/tools/CustomSetupTool/CustomSetupTool/update.c @@ -54,6 +54,8 @@ NTSTATUS SetupUpdateBuild( if (!SetupExecuteProcessHacker(Context)) goto CleanupExit; + PhClearCacheDirectory(); + PostMessage(Context->DialogHandle, WM_QUIT, 0, 0); PhDereferenceObject(Context); return STATUS_SUCCESS; From cd1c173df6d85c737a8a1768951fc188e1a7f664 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 14 Oct 2017 17:09:21 +1100 Subject: [PATCH 0496/2058] Update DelayLoadedDLLs --- ProcessHacker/ProcessHacker.vcxproj | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/ProcessHacker/ProcessHacker.vcxproj b/ProcessHacker/ProcessHacker.vcxproj index 1b6219b26070..99d582dc11ed 100644 --- a/ProcessHacker/ProcessHacker.vcxproj +++ b/ProcessHacker/ProcessHacker.vcxproj @@ -93,6 +93,7 @@ StdCall true true + true aclui.lib;comctl32.lib;iphlpapi.lib;noarg.obj;noenv.obj;ntdll.lib;phlib.lib;uxtheme.lib;version.lib;windowscodecs.lib;winsta.lib;ws2_32.lib;%(AdditionalDependencies) @@ -102,7 +103,7 @@ 6.01 $(SolutionDir)phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) ProcessHacker.def - aclui.dll;iphlpapi.dll;winsta.dll;ws2_32.dll;%(DelayLoadDLLs) + aclui.dll;comdlg32.dll;iphlpapi.dll;winsta.dll;ws2_32.dll;%(DelayLoadDLLs) _UNICODE;UNICODE;%(PreprocessorDefinitions);$(ExternalCompilerOptions) @@ -124,6 +125,7 @@ StdCall true true + true aclui.lib;comctl32.lib;iphlpapi.lib;noarg.obj;noenv.obj;ntdll.lib;phlib.lib;uxtheme.lib;version.lib;windowscodecs.lib;winsta.lib;ws2_32.lib;%(AdditionalDependencies) @@ -133,7 +135,7 @@ 6.01 $(SolutionDir)phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) ProcessHacker.def - aclui.dll;iphlpapi.dll;winsta.dll;ws2_32.dll;%(DelayLoadDLLs) + aclui.dll;comdlg32.dll;iphlpapi.dll;winsta.dll;ws2_32.dll;%(DelayLoadDLLs) _UNICODE;UNICODE;%(PreprocessorDefinitions);$(ExternalCompilerOptions) @@ -173,7 +175,7 @@ 6.01 $(SolutionDir)phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) ProcessHacker.def - aclui.dll;iphlpapi.dll;winsta.dll;ws2_32.dll;%(DelayLoadDLLs) + aclui.dll;comdlg32.dll;iphlpapi.dll;winsta.dll;ws2_32.dll;%(DelayLoadDLLs) _UNICODE;UNICODE;%(PreprocessorDefinitions);$(ExternalCompilerOptions) @@ -211,7 +213,7 @@ 6.01 $(SolutionDir)phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) ProcessHacker.def - aclui.dll;iphlpapi.dll;winsta.dll;ws2_32.dll;%(DelayLoadDLLs) + aclui.dll;comdlg32.dll;iphlpapi.dll;winsta.dll;ws2_32.dll;%(DelayLoadDLLs) _UNICODE;UNICODE;%(PreprocessorDefinitions);$(ExternalCompilerOptions) From 6f221ae34bbe7b8300766bb8a76f0f0294d87231 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 14 Oct 2017 17:09:47 +1100 Subject: [PATCH 0497/2058] Update ProtectedSignerStrings for RS3 --- ProcessHacker/prpggen.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ProcessHacker/prpggen.c b/ProcessHacker/prpggen.c index aa061e46e478..4d4ffca566eb 100644 --- a/ProcessHacker/prpggen.c +++ b/ProcessHacker/prpggen.c @@ -36,7 +36,7 @@ #include static PWSTR ProtectedSignerStrings[] = - { L"", L" (Authenticode)", L" (CodeGen)", L" (Antimalware)", L" (Lsa)", L" (Windows)", L" (WinTcb)", L" (WinSystem)" }; + { L"", L" (Authenticode)", L" (CodeGen)", L" (Antimalware)", L" (Lsa)", L" (Windows)", L" (WinTcb)", L" (WinSystem)", L" (StoreApp)" }; NTSTATUS PhpProcessGeneralOpenProcess( _Out_ PHANDLE Handle, From 7775c8af021a5eadf5acb909c51fdd7a51b71931 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 14 Oct 2017 19:52:29 +1100 Subject: [PATCH 0498/2058] Update string search progress dialog --- ProcessHacker/memsrch.c | 193 ++++++++++++++++++++++++---------------- 1 file changed, 118 insertions(+), 75 deletions(-) diff --git a/ProcessHacker/memsrch.c b/ProcessHacker/memsrch.c index f558f0aa4fb8..1d38f573cf66 100644 --- a/ProcessHacker/memsrch.c +++ b/ProcessHacker/memsrch.c @@ -3,6 +3,7 @@ * memory searchers * * Copyright (C) 2010 wj32 + * Copyright (C) 2017 dmex * * This file is part of Process Hacker. * @@ -38,11 +39,22 @@ typedef struct _MEMORY_STRING_CONTEXT HANDLE ProcessId; HANDLE ProcessHandle; ULONG MinimumLength; - BOOLEAN DetectUnicode; - BOOLEAN Private; - BOOLEAN Image; - BOOLEAN Mapped; + union + { + BOOLEAN Flags; + struct + { + BOOLEAN DetectUnicode : 1; + BOOLEAN Private : 1; + BOOLEAN Image : 1; + BOOLEAN Mapped : 1; + BOOLEAN EnableCloseDialog : 1; + BOOLEAN Spare : 3; + }; + }; + + HWND ParentWindowHandle; HWND WindowHandle; PH_MEMORY_STRING_OPTIONS Options; PPH_LIST Results; @@ -55,11 +67,8 @@ INT_PTR CALLBACK PhpMemoryStringDlgProc( _In_ LPARAM lParam ); -INT_PTR CALLBACK PhpMemoryStringProgressDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam +BOOLEAN PhpShowMemoryStringProgressDialog( + _In_ PMEMORY_STRING_CONTEXT Context ); PVOID PhMemorySearchHeap = NULL; @@ -170,9 +179,7 @@ VOID PhDereferenceMemoryResults( _In_ ULONG NumberOfResults ) { - ULONG i; - - for (i = 0; i < NumberOfResults; i++) + for (ULONG i = 0; i < NumberOfResults; i++) PhDereferenceMemoryResult(Results[i]); } @@ -477,7 +484,6 @@ VOID PhShowMemoryStringDialog( NTSTATUS status; HANDLE processHandle; MEMORY_STRING_CONTEXT context; - PPH_SHOW_MEMORY_RESULTS showMemoryResults; if (!NT_SUCCESS(status = PhOpenProcess( &processHandle, @@ -490,6 +496,7 @@ VOID PhShowMemoryStringDialog( } memset(&context, 0, sizeof(MEMORY_STRING_CONTEXT)); + context.ParentWindowHandle = ParentWindowHandle; context.ProcessId = ProcessItem->ProcessId; context.ProcessHandle = processHandle; @@ -507,14 +514,10 @@ VOID PhShowMemoryStringDialog( context.Results = PhCreateList(1024); - if (DialogBoxParam( - PhInstanceHandle, - MAKEINTRESOURCE(IDD_PROGRESS), - ParentWindowHandle, - PhpMemoryStringProgressDlgProc, - (LPARAM)&context - ) == IDOK) + if (PhpShowMemoryStringProgressDialog(&context)) { + PPH_SHOW_MEMORY_RESULTS showMemoryResults; + showMemoryResults = PhAllocate(sizeof(PH_SHOW_MEMORY_RESULTS)); showMemoryResults->ProcessId = ProcessItem->ProcessId; showMemoryResults->Results = context.Results; @@ -633,88 +636,128 @@ NTSTATUS PhpMemoryStringThreadStart( return STATUS_SUCCESS; } -INT_PTR CALLBACK PhpMemoryStringProgressDlgProc( +LRESULT CALLBACK PhpMemoryStringTaskDialogSubclassProc( _In_ HWND hwndDlg, _In_ UINT uMsg, _In_ WPARAM wParam, - _In_ LPARAM lParam + _In_ LPARAM lParam, + _In_ UINT_PTR uIdSubclass, + _In_ ULONG_PTR dwRefData ) { + PMEMORY_STRING_CONTEXT context = (PMEMORY_STRING_CONTEXT)dwRefData; + switch (uMsg) { - case WM_INITDIALOG: + case WM_NCDESTROY: + RemoveWindowSubclass(hwndDlg, PhpMemoryStringTaskDialogSubclassProc, uIdSubclass); + break; + case WM_PH_MEMORY_STATUS_UPDATE: { - PMEMORY_STRING_CONTEXT context = (PMEMORY_STRING_CONTEXT)lParam; + switch (wParam) + { + case PH_SEARCH_COMPLETED: + { + context->EnableCloseDialog = TRUE; + SendMessage(hwndDlg, TDM_CLICK_BUTTON, IDOK, 0); + } + break; + } + } + break; + } - PhCenterWindow(hwndDlg, GetParent(hwndDlg)); - SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)context); + return DefSubclassProc(hwndDlg, uMsg, wParam, lParam); +} - SetDlgItemText(hwndDlg, IDC_PROGRESSTEXT, L"Searching..."); +HRESULT CALLBACK PhpMemoryStringTaskDialogCallback( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam, + _In_ LONG_PTR dwRefData + ) +{ + PMEMORY_STRING_CONTEXT context = (PMEMORY_STRING_CONTEXT)dwRefData; - PhSetWindowStyle(GetDlgItem(hwndDlg, IDC_PROGRESS), PBS_MARQUEE, PBS_MARQUEE); - SendMessage(GetDlgItem(hwndDlg, IDC_PROGRESS), PBM_SETMARQUEE, TRUE, 75); + switch (uMsg) + { + case TDN_CREATED: + { + HICON iconSmall; + HICON iconLarge; context->WindowHandle = hwndDlg; - PhCreateThread2(PhpMemoryStringThreadStart, context); + // Create the Taskdialog icons. + iconSmall = PH_LOAD_SHARED_ICON_SMALL(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER)); + iconLarge = PH_LOAD_SHARED_ICON_LARGE(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER)); + SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)iconSmall); + SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)iconLarge); + SendMessage(hwndDlg, TDM_UPDATE_ICON, TDIE_ICON_MAIN, (LPARAM)iconLarge); - SetTimer(hwndDlg, 1, 500, NULL); - } - break; - case WM_DESTROY: - { - RemoveProp(hwndDlg, PhMakeContextAtom()); - } - break; - case WM_COMMAND: - { - switch (GET_WM_COMMAND_ID(wParam, lParam)) - { - case IDCANCEL: - { - PMEMORY_STRING_CONTEXT context = - (PMEMORY_STRING_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom()); + // Set the progress state. + SendMessage(hwndDlg, TDM_SET_MARQUEE_PROGRESS_BAR, TRUE, 0); + SendMessage(hwndDlg, TDM_SET_PROGRESS_BAR_MARQUEE, TRUE, 1); - EnableWindow(GetDlgItem(hwndDlg, IDCANCEL), FALSE); - context->Options.Header.Cancel = TRUE; - } - break; - } + // Subclass the Taskdialog. + SetWindowSubclass(hwndDlg, PhpMemoryStringTaskDialogSubclassProc, 0, (ULONG_PTR)context); + + // Create the search thread. + PhCreateThread2(PhpMemoryStringThreadStart, context); } break; - case WM_TIMER: + case TDN_BUTTON_CLICKED: { - if (wParam == 1) - { - PMEMORY_STRING_CONTEXT context = - (PMEMORY_STRING_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom()); - PPH_STRING progressText; - PPH_STRING numberText; - - numberText = PhFormatUInt64(context->Results->Count, TRUE); - progressText = PhFormatString(L"%s strings found...", numberText->Buffer); - PhDereferenceObject(numberText); - SetDlgItemText(hwndDlg, IDC_PROGRESSTEXT, progressText->Buffer); - PhDereferenceObject(progressText); - InvalidateRect(GetDlgItem(hwndDlg, IDC_PROGRESSTEXT), NULL, FALSE); - } + if ((INT)wParam == IDCANCEL) + context->Options.Header.Cancel = TRUE; + + if (!context->EnableCloseDialog) + return S_FALSE; } break; - case WM_PH_MEMORY_STATUS_UPDATE: + case TDN_TIMER: { - PMEMORY_STRING_CONTEXT context; + PPH_STRING numberText; + PPH_STRING progressText; - context = (PMEMORY_STRING_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom()); + numberText = PhFormatUInt64(context->Results->Count, TRUE); + progressText = PhFormatString(L"%s strings found...", numberText->Buffer); - switch (wParam) - { - case PH_SEARCH_COMPLETED: - EndDialog(hwndDlg, IDOK); - break; - } + SendMessage(hwndDlg, TDM_SET_ELEMENT_TEXT, TDE_CONTENT, (LPARAM)progressText->Buffer); + + PhDereferenceObject(progressText); + PhDereferenceObject(numberText); } break; } + return S_OK; +} + +BOOLEAN PhpShowMemoryStringProgressDialog( + _In_ PMEMORY_STRING_CONTEXT Context + ) +{ + TASKDIALOGCONFIG config; + INT result = 0; + + memset(&config, 0, sizeof(TASKDIALOGCONFIG)); + config.cbSize = sizeof(TASKDIALOGCONFIG); + config.dwFlags = TDF_USE_HICON_MAIN | TDF_ALLOW_DIALOG_CANCELLATION | TDF_POSITION_RELATIVE_TO_WINDOW | TDF_SHOW_MARQUEE_PROGRESS_BAR | TDF_CALLBACK_TIMER; + config.dwCommonButtons = TDCBF_CANCEL_BUTTON; + config.pfCallback = PhpMemoryStringTaskDialogCallback; + config.lpCallbackData = (LONG_PTR)Context; + config.hwndParent = Context->ParentWindowHandle; + config.pszWindowTitle = PhApplicationName; + config.pszMainInstruction = L"Searching memory strings..."; + config.pszContent = L" "; + config.cxWidth = 200; + + if (SUCCEEDED(TaskDialogIndirect(&config, &result, NULL, NULL)) && result == IDOK) + { + return TRUE; + } + return FALSE; } From 55060a57e92fc354f9ee77897fcd94f90c98ae27 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 14 Oct 2017 20:10:52 +1100 Subject: [PATCH 0499/2058] Improve handle menu error checking --- ProcessHacker/hndlmenu.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/ProcessHacker/hndlmenu.c b/ProcessHacker/hndlmenu.c index 802e41c26ff1..8b86873713e0 100644 --- a/ProcessHacker/hndlmenu.c +++ b/ProcessHacker/hndlmenu.c @@ -206,17 +206,18 @@ VOID PhShowHandleObjectProperties1( } else if (PhEqualString2(Info->TypeName, L"Section", TRUE)) { + NTSTATUS status; HANDLE handle = NULL; BOOLEAN readOnly = FALSE; - if (!NT_SUCCESS(PhpDuplicateHandleFromProcessItem( + if (!NT_SUCCESS(status = PhpDuplicateHandleFromProcessItem( &handle, SECTION_QUERY | SECTION_MAP_READ | SECTION_MAP_WRITE, Info->ProcessId, Info->Handle ))) { - PhpDuplicateHandleFromProcessItem( + status = PhpDuplicateHandleFromProcessItem( &handle, SECTION_QUERY | SECTION_MAP_READ, Info->ProcessId, @@ -227,7 +228,6 @@ VOID PhShowHandleObjectProperties1( if (handle) { - NTSTATUS status; PPH_STRING sectionName = NULL; SECTION_BASIC_INFORMATION basicInfo; SIZE_T viewSize = PH_MAX_SECTION_EDIT_SIZE; @@ -236,7 +236,7 @@ VOID PhShowHandleObjectProperties1( PhGetHandleInformation(NtCurrentProcess(), handle, -1, NULL, NULL, NULL, §ionName); - if (NT_SUCCESS(PhGetSectionBasicInformation(handle, &basicInfo))) + if (NT_SUCCESS(status = PhGetSectionBasicInformation(handle, &basicInfo))) { if (basicInfo.MaximumSize.QuadPart <= PH_MAX_SECTION_EDIT_SIZE) viewSize = (SIZE_T)basicInfo.MaximumSize.QuadPart; @@ -291,7 +291,7 @@ VOID PhShowHandleObjectProperties1( } else { - PhShowStatus(hWnd, L"Unable to map a view of the section", status, 0); + PhShowStatus(hWnd, L"Unable to map a view of the section.", status, 0); } } @@ -299,6 +299,11 @@ VOID PhShowHandleObjectProperties1( NtClose(handle); } + + if (!NT_SUCCESS(status)) + { + PhShowStatus(hWnd, L"Unable to query the section.", status, 0); + } } else if (PhEqualString2(Info->TypeName, L"Thread", TRUE)) { From 9192d42b87ac39553aecc988fa67a2064942e76f Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 15 Oct 2017 07:06:13 +1100 Subject: [PATCH 0500/2058] Fix json wrapper memory leak --- phlib/include/json.h | 4 ++-- phlib/json.c | 18 ++++++++++++++---- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/phlib/include/json.h b/phlib/include/json.h index a8d43b25acba..74ed35752f23 100644 --- a/phlib/include/json.h +++ b/phlib/include/json.h @@ -48,7 +48,7 @@ PhFreeJsonParser( ); PHLIBAPI -PSTR +PPH_STRING NTAPI PhGetJsonValueAsString( _In_ PVOID Object, @@ -118,7 +118,7 @@ PhAddJsonArrayObject( ); PHLIBAPI -PSTR +PPH_STRING NTAPI PhGetJsonArrayString( _In_ PVOID Object diff --git a/phlib/json.c b/phlib/json.c index fa889476750e..0eba2c3682a5 100644 --- a/phlib/json.c +++ b/phlib/json.c @@ -56,12 +56,17 @@ VOID PhFreeJsonParser( json_object_put(Object); } -PSTR PhGetJsonValueAsString( +PPH_STRING PhGetJsonValueAsString( _In_ PVOID Object, _In_ PSTR Key ) { - return json_object_get_string(json_get_object(Object, Key)); + PSTR value; + + if (value = json_object_get_string(json_get_object(Object, Key))) + return PhConvertUtf8ToUtf16(value); + else + return NULL; } INT64 PhGetJsonValueAsLong64( @@ -126,11 +131,16 @@ VOID PhAddJsonArrayObject( json_object_array_add(Object, jsonEntry); } -PSTR PhGetJsonArrayString( +PPH_STRING PhGetJsonArrayString( _In_ PVOID Object ) { - return _strdup( json_object_to_json_string(Object) ); // leak + PSTR value; + + if (value = json_object_to_json_string(Object)) + return PhConvertUtf8ToUtf16(value); + else + return NULL; } INT64 PhGetJsonArrayLong64( From c82312a7677d526aa4a39fe08c686b55ffe3bae0 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 15 Oct 2017 07:07:40 +1100 Subject: [PATCH 0501/2058] BuildTools: Update appveyor format --- tools/CustomBuildTool/Source Files/Build.cs | 36 +++++++++++++++------ tools/CustomBuildTool/Source Files/Utils.cs | 21 ++++++++---- 2 files changed, 41 insertions(+), 16 deletions(-) diff --git a/tools/CustomBuildTool/Source Files/Build.cs b/tools/CustomBuildTool/Source Files/Build.cs index 73d01c1bc7b4..2c0a63c2d5aa 100644 --- a/tools/CustomBuildTool/Source Files/Build.cs +++ b/tools/CustomBuildTool/Source Files/Build.cs @@ -53,6 +53,7 @@ public static class Build private static long BuildBinFileLength; private static string BuildBinHash; + private static string BuildBinSig; private static long BuildSetupFileLength; private static string BuildSetupHash; @@ -259,7 +260,7 @@ public static void ShowBuildEnvironment(string Platform, bool ShowBuildInfo, boo Program.PrintColorMessage("Branch: ", ConsoleColor.Cyan, false); Program.PrintColorMessage(BuildBranch, ConsoleColor.White); Program.PrintColorMessage("Commit: ", ConsoleColor.Cyan, false); - Program.PrintColorMessage(BuildCommit, ConsoleColor.White); + Program.PrintColorMessage(BuildCommit.Substring(0, 8), ConsoleColor.White); string currentGitTag = Win32.ShellExecute(GitExePath, "describe --abbrev=0 --tags --always").Trim(); BuildRevision = Win32.ShellExecute(GitExePath, "rev-list --count \"" + currentGitTag + ".." + BuildBranch + "\"").Trim(); @@ -920,12 +921,21 @@ public static bool BuildUpdateSignature() return true; } + if (!File.Exists(BuildOutputFolder + "\\processhacker-build-bin.zip")) + { + Program.PrintColorMessage("[SKIPPED] build-bin.zip not found.", ConsoleColor.Yellow); + return false; + } if (!File.Exists(BuildOutputFolder + "\\processhacker-build-setup.exe")) { Program.PrintColorMessage("[SKIPPED] build-setup.exe not found.", ConsoleColor.Yellow); return false; } + BuildBinSig = Win32.ShellExecute( + CustomSignToolPath, + "sign -k build\\nightly.key " + BuildOutputFolder + "\\processhacker-build-bin.zip -h" + ); BuildSetupSig = Win32.ShellExecute( CustomSignToolPath, "sign -k build\\nightly.key " + BuildOutputFolder + "\\processhacker-build-setup.exe -h" @@ -949,24 +959,27 @@ public static void WebServiceUpdateConfig() return; if (string.IsNullOrEmpty(BuildBinHash)) return; + if (string.IsNullOrEmpty(BuildBinSig)) + return; string buildChangelog = Win32.ShellExecute(GitExePath, "log -n 30 --date=format:%Y-%m-%d --pretty=format:\"[%cd] %s (%an)\""); string buildSummary = Win32.ShellExecute(GitExePath, "log -n 5 --date=format:%Y-%m-%d --pretty=format:\"[%cd] %s (%an)\" --abbrev-commit"); string buildPostString = Json.Serialize(new BuildUpdateRequest { + Version = BuildVersion, + Commit = BuildCommit, Updated = TimeStart.ToString("o"), - FileLength = BuildSetupFileLength.ToString(), - ForumUrl = "https://wj32.org/processhacker/nightly.php", + + BinUrl = "https://ci.appveyor.com/api/projects/processhacker/processhacker2/artifacts/processhacker-" + BuildVersion + "-bin.zip", + BinLength = BuildBinFileLength.ToString(), + BinHash = BuildBinHash, + BinSig = BuildBinSig, SetupUrl = "https://ci.appveyor.com/api/projects/processhacker/processhacker2/artifacts/processhacker-" + BuildVersion + "-setup.exe", - SetupVersion = BuildVersion, + SetupLength = BuildSetupFileLength.ToString(), SetupHash = BuildSetupHash, SetupSig = BuildSetupSig, - BinUrl = "https://ci.appveyor.com/api/projects/processhacker/processhacker2/artifacts/processhacker-" + BuildVersion + "-bin.zip", - BinHash = BuildBinHash, - //BinSig = BuildBinSig, - //WebSetupUrl = "https://ci.appveyor.com/api/projects/processhacker/processhacker2/artifacts/processhacker-websetup.exe", //WebSetupHash = BuildWebSetupHash, //WebSetupVersion = BuildWebSetupVersion, @@ -974,6 +987,11 @@ public static void WebServiceUpdateConfig() Message = buildSummary, Changelog = buildChangelog, + + FileLengthDeprecated = BuildSetupFileLength.ToString(), // TODO: Remove after most users have updated. + ForumUrlDeprecated = "https://wj32.org/processhacker/", // TODO: Remove after most users have updated. + SetupSigDeprecated = BuildSetupSig, // TODO: Remove after most users have updated. + BinHashDeprecated = BuildBinHash // TODO: Remove after most users have updated. }); if (string.IsNullOrEmpty(buildPostString)) @@ -1087,7 +1105,7 @@ public static bool AppveyorUploadBuildFiles() } // Update Appveyor build version string. - Win32.ShellExecute("appveyor", "UpdateBuild -Version \"" + BuildLongVersion + " (" + BuildCommit + ")\" "); + Win32.ShellExecute("appveyor", "UpdateBuild -Version \"" + BuildLongVersion + "\" "); return true; } diff --git a/tools/CustomBuildTool/Source Files/Utils.cs b/tools/CustomBuildTool/Source Files/Utils.cs index 7fd432512415..088112be4cac 100644 --- a/tools/CustomBuildTool/Source Files/Utils.cs +++ b/tools/CustomBuildTool/Source Files/Utils.cs @@ -338,26 +338,33 @@ public VisualStudioInstance(ISetupInstance2 FromInstance) [DataContract] public class BuildUpdateRequest { + [DataMember(Name = "version")] public string Version { get; set; } + [DataMember(Name = "commit")] public string Commit { get; set; } [DataMember(Name = "updated")] public string Updated { get; set; } - [DataMember(Name = "size")] public string FileLength { get; set; } - [DataMember(Name = "forum_url")] public string ForumUrl { get; set; } [DataMember(Name = "bin_url")] public string BinUrl { get; set; } - [DataMember(Name = "hash_bin")] public string BinHash { get; set; } + [DataMember(Name = "bin_length")] public string BinLength { get; set; } + [DataMember(Name = "bin_hash")] public string BinHash { get; set; } [DataMember(Name = "bin_sig")] public string BinSig { get; set; } [DataMember(Name = "setup_url")] public string SetupUrl { get; set; } - [DataMember(Name = "hash_setup")] public string SetupHash { get; set; } - [DataMember(Name = "sig")] public string SetupSig { get; set; } - [DataMember(Name = "version")] public string SetupVersion { get; set; } + [DataMember(Name = "setup_length")] public string SetupLength { get; set; } + [DataMember(Name = "setup_hash")] public string SetupHash { get; set; } + [DataMember(Name = "setup_sig")] public string SetupSig { get; set; } [DataMember(Name = "websetup_url")] public string WebSetupUrl { get; set; } + [DataMember(Name = "websetup_version")] public string WebSetupVersion { get; set; } + [DataMember(Name = "websetup_length")] public string WebSetupLength { get; set; } [DataMember(Name = "websetup_hash")] public string WebSetupHash { get; set; } [DataMember(Name = "websetup_sig")] public string WebSetupSig { get; set; } - [DataMember(Name = "websetup_version")] public string WebSetupVersion { get; set; } [DataMember(Name = "message")] public string Message { get; set; } [DataMember(Name = "changelog")] public string Changelog { get; set; } + + [DataMember(Name = "size")] public string FileLengthDeprecated { get; set; } // TODO: Remove after most users have updated. + [DataMember(Name = "forum_url")] public string ForumUrlDeprecated { get; set; } // TODO: Remove after most users have updated. + [DataMember(Name = "hash_bin")] public string BinHashDeprecated { get; set; } // TODO: Remove after most users have updated. + [DataMember(Name = "sig")] public string SetupSigDeprecated { get; set; } // TODO: Remove after most users have updated. } [Flags] From 4920387ace1c980e33879353b170b60a241453ad Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 15 Oct 2017 07:10:39 +1100 Subject: [PATCH 0502/2058] Plugins: Update to latest json format --- plugins/ExtraPlugins/cloud.c | 40 +++++++++++----------- plugins/OnlineChecks/upload.c | 26 +++++++------- plugins/OnlineChecks/virustotal.c | 27 ++++++++------- plugins/Updater/page3.c | 2 +- plugins/Updater/updater.c | 57 +++++++++++-------------------- plugins/Updater/updater.h | 13 ++++--- 6 files changed, 73 insertions(+), 92 deletions(-) diff --git a/plugins/ExtraPlugins/cloud.c b/plugins/ExtraPlugins/cloud.c index 07a94476fcc9..7a7d72bfec24 100644 --- a/plugins/ExtraPlugins/cloud.c +++ b/plugins/ExtraPlugins/cloud.c @@ -125,26 +125,26 @@ NTSTATUS QueryPluginsCallbackThread( memset(entry, 0, sizeof(PLUGIN_NODE)); jvalue = PhGetJsonArrayIndexObject(rootJsonObject, i); - entry->Id = PhConvertUtf8ToUtf16(PhGetJsonValueAsString(jvalue, "plugin_id")); - entry->InternalName = PhConvertUtf8ToUtf16(PhGetJsonValueAsString(jvalue, "plugin_internal_name")); - entry->Name = PhConvertUtf8ToUtf16(PhGetJsonValueAsString(jvalue, "plugin_name")); - entry->Version = PhConvertUtf8ToUtf16(PhGetJsonValueAsString(jvalue, "plugin_version")); - entry->Author = PhConvertUtf8ToUtf16(PhGetJsonValueAsString(jvalue, "plugin_author")); - entry->Description = PhConvertUtf8ToUtf16(PhGetJsonValueAsString(jvalue, "plugin_description")); - entry->IconUrl = PhConvertUtf8ToUtf16(PhGetJsonValueAsString(jvalue, "plugin_icon")); - entry->Requirements = PhConvertUtf8ToUtf16(PhGetJsonValueAsString(jvalue, "plugin_requirements")); - entry->FeedbackUrl = PhConvertUtf8ToUtf16(PhGetJsonValueAsString(jvalue, "plugin_feedback")); - entry->Screenshots = PhConvertUtf8ToUtf16(PhGetJsonValueAsString(jvalue, "plugin_screenshots")); - entry->AddedTime = PhConvertUtf8ToUtf16(PhGetJsonValueAsString(jvalue, "plugin_datetime_added")); - entry->UpdatedTime = PhConvertUtf8ToUtf16(PhGetJsonValueAsString(jvalue, "plugin_datetime_updated")); - entry->Download_count = PhConvertUtf8ToUtf16(PhGetJsonValueAsString(jvalue, "plugin_download_count")); - entry->Download_link_32 = PhConvertUtf8ToUtf16(PhGetJsonValueAsString(jvalue, "plugin_download_link_32")); - entry->Download_link_64 = PhConvertUtf8ToUtf16(PhGetJsonValueAsString(jvalue, "plugin_download_link_64")); - entry->SHA2_32 = PhConvertUtf8ToUtf16(PhGetJsonValueAsString(jvalue, "plugin_hash_32")); - entry->SHA2_64 = PhConvertUtf8ToUtf16(PhGetJsonValueAsString(jvalue, "plugin_hash_64")); - entry->HASH_32 = PhConvertUtf8ToUtf16(PhGetJsonValueAsString(jvalue, "plugin_signed_32")); - entry->HASH_64 = PhConvertUtf8ToUtf16(PhGetJsonValueAsString(jvalue, "plugin_signed_64")); - entry->FileName = PhConvertUtf8ToUtf16(PhGetJsonValueAsString(jvalue, "plugin_filename")); + entry->Id = PhGetJsonValueAsString(jvalue, "plugin_id"); + entry->InternalName = PhGetJsonValueAsString(jvalue, "plugin_internal_name"); + entry->Name = PhGetJsonValueAsString(jvalue, "plugin_name"); + entry->Version = PhGetJsonValueAsString(jvalue, "plugin_version"); + entry->Author = PhGetJsonValueAsString(jvalue, "plugin_author"); + entry->Description = PhGetJsonValueAsString(jvalue, "plugin_description"); + entry->IconUrl = PhGetJsonValueAsString(jvalue, "plugin_icon"); + entry->Requirements = PhGetJsonValueAsString(jvalue, "plugin_requirements"); + entry->FeedbackUrl = PhGetJsonValueAsString(jvalue, "plugin_feedback"); + entry->Screenshots = PhGetJsonValueAsString(jvalue, "plugin_screenshots"); + entry->AddedTime = PhGetJsonValueAsString(jvalue, "plugin_datetime_added"); + entry->UpdatedTime = PhGetJsonValueAsString(jvalue, "plugin_datetime_updated"); + entry->Download_count = PhGetJsonValueAsString(jvalue, "plugin_download_count"); + entry->Download_link_32 = PhGetJsonValueAsString(jvalue, "plugin_download_link_32"); + entry->Download_link_64 = PhGetJsonValueAsString(jvalue, "plugin_download_link_64"); + entry->SHA2_32 = PhGetJsonValueAsString(jvalue, "plugin_hash_32"); + entry->SHA2_64 = PhGetJsonValueAsString(jvalue, "plugin_hash_64"); + entry->HASH_32 = PhGetJsonValueAsString(jvalue, "plugin_signed_32"); + entry->HASH_64 = PhGetJsonValueAsString(jvalue, "plugin_signed_64"); + entry->FileName = PhGetJsonValueAsString(jvalue, "plugin_filename"); swscanf( PhGetString(entry->UpdatedTime), diff --git a/plugins/OnlineChecks/upload.c b/plugins/OnlineChecks/upload.c index 8646b1d98eae..77a6f619f96c 100644 --- a/plugins/OnlineChecks/upload.c +++ b/plugins/OnlineChecks/upload.c @@ -800,7 +800,6 @@ NTSTATUS UploadFileThreadStart( case MENUITEM_VIRUSTOTAL_UPLOAD_SERVICE: { PSTR buffer = NULL; - PSTR redirectUrl; ULONG bufferLength; PVOID jsonRootObject; @@ -820,10 +819,7 @@ NTSTATUS UploadFileThreadStart( // PhZeroExtendToUtf16(PhGetJsonValueAsString(jsonRootObject, "sha256")); // PhZeroExtendToUtf16(PhGetJsonValueAsString(jsonRootObject, "verbose_msg")); - if (redirectUrl = PhGetJsonValueAsString(jsonRootObject, "permalink")) - { - PhMoveReference(&context->LaunchCommand, PhZeroExtendToUtf16(redirectUrl)); - } + PhMoveReference(&context->LaunchCommand, PhGetJsonValueAsString(jsonRootObject, "permalink")); PhFreeJsonParser(jsonRootObject); } @@ -849,7 +845,6 @@ NTSTATUS UploadFileThreadStart( case MENUITEM_JOTTI_UPLOAD_SERVICE: { PSTR buffer = NULL; - PSTR redirectUrl; ULONG bufferLength; PVOID rootJsonObject; @@ -861,9 +856,12 @@ NTSTATUS UploadFileThreadStart( if (rootJsonObject = PhCreateJsonParser(buffer)) { + PPH_STRING redirectUrl; + if (redirectUrl = PhGetJsonValueAsString(rootJsonObject, "redirecturl")) { - PhMoveReference(&context->LaunchCommand, PhFormatString(L"http://virusscan.jotti.org%hs", redirectUrl)); + PhMoveReference(&context->LaunchCommand, PhFormatString(L"http://virusscan.jotti.org%s", redirectUrl->Buffer)); + PhDereferenceObject(redirectUrl); } PhFreeJsonParser(rootJsonObject); @@ -1066,12 +1064,12 @@ NTSTATUS UploadCheckThreadStart( context->Detected = PhFormatString(L"%I64d", detected); context->MaxDetected = PhFormatString(L"%I64d", detectedMax); - context->UploadUrl = PhZeroExtendToUtf16(PhGetJsonValueAsString(rootJsonObject, "upload_url")); - context->ReAnalyseUrl = PhZeroExtendToUtf16(PhGetJsonValueAsString(rootJsonObject, "reanalyse_url")); - context->LastAnalysisUrl = PhZeroExtendToUtf16(PhGetJsonValueAsString(rootJsonObject, "last_analysis_url")); - context->FirstAnalysisDate = PhZeroExtendToUtf16(PhGetJsonValueAsString(rootJsonObject, "first_analysis_date")); - context->LastAnalysisDate = PhZeroExtendToUtf16(PhGetJsonValueAsString(rootJsonObject, "last_analysis_date")); - context->LastAnalysisAgo = PhZeroExtendToUtf16(PhGetJsonValueAsString(rootJsonObject, "last_analysis_ago")); + context->UploadUrl = PhGetJsonValueAsString(rootJsonObject, "upload_url"); + context->ReAnalyseUrl = PhGetJsonValueAsString(rootJsonObject, "reanalyse_url"); + context->LastAnalysisUrl = PhGetJsonValueAsString(rootJsonObject, "last_analysis_url"); + context->FirstAnalysisDate = PhGetJsonValueAsString(rootJsonObject, "first_analysis_date"); + context->LastAnalysisDate = PhGetJsonValueAsString(rootJsonObject, "last_analysis_date"); + context->LastAnalysisAgo = PhGetJsonValueAsString(rootJsonObject, "last_analysis_ago"); PhMoveReference(&context->FirstAnalysisDate, VirusTotalStringToTime(context->FirstAnalysisDate)); PhMoveReference(&context->LastAnalysisDate, VirusTotalStringToTime(context->LastAnalysisDate)); @@ -1108,7 +1106,7 @@ NTSTATUS UploadCheckThreadStart( } else { - context->UploadUrl = PhZeroExtendToUtf16(PhGetJsonValueAsString(rootJsonObject, "upload_url")); + context->UploadUrl = PhGetJsonValueAsString(rootJsonObject, "upload_url"); // No file found... Start the upload. if (!PhIsNullOrEmptyString(context->UploadUrl)) diff --git a/plugins/OnlineChecks/virustotal.c b/plugins/OnlineChecks/virustotal.c index 0a93f6e81a92..3d2f2d5e80fb 100644 --- a/plugins/OnlineChecks/virustotal.c +++ b/plugins/OnlineChecks/virustotal.c @@ -220,7 +220,6 @@ PPH_LIST VirusTotalJsonToResultList( { PVIRUSTOTAL_API_RESULT result; PVOID jsonArrayObject; - PSTR fileHash; if (!(jsonArrayObject = PhGetJsonArrayIndexObject(JsonObject, i))) continue; @@ -228,8 +227,7 @@ PPH_LIST VirusTotalJsonToResultList( result = PhAllocate(sizeof(VIRUSTOTAL_API_RESULT)); memset(result, 0, sizeof(VIRUSTOTAL_API_RESULT)); - fileHash = PhGetJsonValueAsString(jsonArrayObject, "hash"); - result->FileHash = fileHash ? PhZeroExtendToUtf16(fileHash) : NULL; + result->FileHash = PhGetJsonValueAsString(jsonArrayObject, "hash"); result->Found = PhGetJsonObjectBool(jsonArrayObject, "found") == TRUE; result->Positives = PhGetJsonValueAsLong64(jsonArrayObject, "positives"); result->Total = PhGetJsonValueAsLong64(jsonArrayObject, "total"); @@ -596,14 +594,14 @@ PVIRUSTOTAL_FILE_REPORT_RESULT VirusTotalSendHttpFileReportRequest( result->Total = PhFormatUInt64(PhGetJsonValueAsLong64(jsonRootObject, "total"), FALSE); result->Positives = PhFormatUInt64(PhGetJsonValueAsLong64(jsonRootObject, "positives"), FALSE); - result->Resource = PhZeroExtendToUtf16(PhGetJsonValueAsString(jsonRootObject, "resource")); - result->ScanId = PhZeroExtendToUtf16(PhGetJsonValueAsString(jsonRootObject, "scan_id")); - result->Md5 = PhZeroExtendToUtf16(PhGetJsonValueAsString(jsonRootObject, "md5")); - result->Sha1 = PhZeroExtendToUtf16(PhGetJsonValueAsString(jsonRootObject, "sha1")); - result->Sha256 = PhZeroExtendToUtf16(PhGetJsonValueAsString(jsonRootObject, "sha256")); - result->ScanDate = PhZeroExtendToUtf16(PhGetJsonValueAsString(jsonRootObject, "scan_date")); - result->Permalink = PhZeroExtendToUtf16(PhGetJsonValueAsString(jsonRootObject, "permalink")); - result->StatusMessage = PhZeroExtendToUtf16(PhGetJsonValueAsString(jsonRootObject, "verbose_msg")); + result->Resource = PhGetJsonValueAsString(jsonRootObject, "resource"); + result->ScanId = PhGetJsonValueAsString(jsonRootObject, "scan_id"); + result->Md5 = PhGetJsonValueAsString(jsonRootObject, "md5"); + result->Sha1 = PhGetJsonValueAsString(jsonRootObject, "sha1"); + result->Sha256 = PhGetJsonValueAsString(jsonRootObject, "sha256"); + result->ScanDate = PhGetJsonValueAsString(jsonRootObject, "scan_date"); + result->Permalink = PhGetJsonValueAsString(jsonRootObject, "permalink"); + result->StatusMessage = PhGetJsonValueAsString(jsonRootObject, "verbose_msg"); //if (jsonScanObject = PhGetJsonObject(jsonRootObject, "scans")) //{ @@ -651,11 +649,11 @@ NTSTATUS NTAPI VirusTotalProcessApiThread( { ULONG i; INT64 resultLength; - PSTR jsonArrayToSendString; PSTR jsonApiResult = NULL; PVOID jsonArray; PVOID rootJsonObject = NULL; PVOID dataJsonObject; + PPH_STRING jsonArrayToSendString = NULL; PPH_LIST resultTempList = NULL; PPH_LIST virusTotalResults = NULL; @@ -695,7 +693,7 @@ NTSTATUS NTAPI VirusTotalProcessApiThread( if (!(jsonArrayToSendString = PhGetJsonArrayString(jsonArray))) goto CleanupExit; - if (!(jsonApiResult = VirusTotalSendHttpRequest(PhCreateBytes(jsonArrayToSendString)))) + if (!(jsonApiResult = VirusTotalSendHttpRequest(PhConvertUtf16ToUtf8(jsonArrayToSendString->Buffer)))) goto CleanupExit; if (!(rootJsonObject = PhCreateJsonParser(jsonApiResult))) @@ -761,6 +759,9 @@ NTSTATUS NTAPI VirusTotalProcessApiThread( PhFreeJsonParser(rootJsonObject); } + if (jsonArrayToSendString) + PhDereferenceObject(jsonArrayToSendString); + if (jsonArray) { PhFreeJsonParser(jsonArray); diff --git a/plugins/Updater/page3.c b/plugins/Updater/page3.c index 40cda4253452..ced2fcffb38a 100644 --- a/plugins/Updater/page3.c +++ b/plugins/Updater/page3.c @@ -90,7 +90,7 @@ VOID ShowAvailableDialog( config.pszMainInstruction = L"A newer build of Process Hacker is available."; config.pszContent = PhaFormatString(L"Version: %s\r\nDownload size: %s\r\n\r\nView Changelog", PhGetStringOrEmpty(Context->Version), - PhGetStringOrEmpty(Context->Size) + PhGetStringOrEmpty(Context->SetupFileLength) )->Buffer; SendMessage(Context->DialogHandle, TDM_NAVIGATE_PAGE, 0, (LPARAM)&config); diff --git a/plugins/Updater/updater.c b/plugins/Updater/updater.c index abb34f2a49e7..ea940d5b0030 100644 --- a/plugins/Updater/updater.c +++ b/plugins/Updater/updater.c @@ -47,18 +47,16 @@ VOID FreeUpdateContext( _In_ _Post_invalid_ PPH_UPDATER_CONTEXT Context ) { + PhClearReference(&Context->CurrentVersionString); + PhClearReference(&Context->Version); - PhClearReference(&Context->RevVersion); PhClearReference(&Context->RelDate); - PhClearReference(&Context->Size); - PhClearReference(&Context->Hash); - PhClearReference(&Context->Signature); - PhClearReference(&Context->ReleaseNotesUrl); - PhClearReference(&Context->SetupFilePath); PhClearReference(&Context->SetupFileDownloadUrl); + PhClearReference(&Context->SetupFileLength); + PhClearReference(&Context->SetupFileHash); + PhClearReference(&Context->SetupFileSignature); PhClearReference(&Context->BuildMessage); - PhClearReference(&Context->CurrentVersionString); - + PhDereferenceObject(Context); } @@ -77,7 +75,7 @@ VOID TaskDialogLinkClicked( _In_ PPH_UPDATER_CONTEXT Context ) { - if (!PhIsNullOrEmptyString(Context->ReleaseNotesUrl)) + if (!PhIsNullOrEmptyString(Context->BuildMessage)) { DialogBoxParam( PluginInstance->DllBase, @@ -420,42 +418,27 @@ BOOLEAN QueryUpdateData( if (!(jsonObject = PhCreateJsonParser(stringBuffer))) goto CleanupExit; - Context->Size = PhFormatSize(PhGetJsonValueAsLong64(jsonObject, "size"), 2); - if (tempValue = PhGetJsonValueAsString(jsonObject, "version")) - { - Context->Version = PhConvertUtf8ToUtf16(tempValue); - Context->RevVersion = PhConvertUtf8ToUtf16(tempValue); - } - if (tempValue = PhGetJsonValueAsString(jsonObject, "updated")) - Context->RelDate = PhConvertUtf8ToUtf16(tempValue); - if (tempValue = PhGetJsonValueAsString(jsonObject, "hash_setup")) - Context->Hash = PhConvertUtf8ToUtf16(tempValue); - if (tempValue = PhGetJsonValueAsString(jsonObject, "sig")) - Context->Signature = PhConvertUtf8ToUtf16(tempValue); - if (tempValue = PhGetJsonValueAsString(jsonObject, "forum_url")) - Context->ReleaseNotesUrl = PhConvertUtf8ToUtf16(tempValue); - if (tempValue = PhGetJsonValueAsString(jsonObject, "setup_url")) - Context->SetupFileDownloadUrl = PhConvertUtf8ToUtf16(tempValue); - if (tempValue = PhGetJsonValueAsString(jsonObject, "changelog")) - Context->BuildMessage = PhConvertUtf8ToUtf16(tempValue); + Context->Version = PhGetJsonValueAsString(jsonObject, "version"); + Context->RelDate = PhGetJsonValueAsString(jsonObject, "updated"); + Context->SetupFileDownloadUrl = PhGetJsonValueAsString(jsonObject, "setup_url"); + Context->SetupFileLength = PhFormatSize(PhGetJsonValueAsLong64(jsonObject, "setup_length"), 2); + Context->SetupFileHash = PhGetJsonValueAsString(jsonObject, "setup_hash"); + Context->SetupFileSignature = PhGetJsonValueAsString(jsonObject, "setup_sig"); + Context->BuildMessage = PhGetJsonValueAsString(jsonObject, "changelog"); PhFreeJsonParser(jsonObject); if (PhIsNullOrEmptyString(Context->Version)) goto CleanupExit; - if (PhIsNullOrEmptyString(Context->RevVersion)) - goto CleanupExit; if (PhIsNullOrEmptyString(Context->RelDate)) goto CleanupExit; - if (PhIsNullOrEmptyString(Context->Size)) - goto CleanupExit; - if (PhIsNullOrEmptyString(Context->Hash)) + if (PhIsNullOrEmptyString(Context->SetupFileDownloadUrl)) goto CleanupExit; - if (PhIsNullOrEmptyString(Context->ReleaseNotesUrl)) + if (PhIsNullOrEmptyString(Context->SetupFileLength)) goto CleanupExit; - if (PhIsNullOrEmptyString(Context->SetupFileDownloadUrl)) + if (PhIsNullOrEmptyString(Context->SetupFileHash)) goto CleanupExit; - if (PhIsNullOrEmptyString(Context->Signature)) + if (PhIsNullOrEmptyString(Context->SetupFileSignature)) goto CleanupExit; if (PhIsNullOrEmptyString(Context->BuildMessage)) goto CleanupExit; @@ -911,12 +894,12 @@ NTSTATUS UpdateDownloadThread( } } - if (UpdaterVerifyHash(hashContext, context->Hash)) + if (UpdaterVerifyHash(hashContext, context->SetupFileHash)) { hashSuccess = TRUE; } - if (UpdaterVerifySignature(hashContext, context->Signature)) + if (UpdaterVerifySignature(hashContext, context->SetupFileSignature)) { signatureSuccess = TRUE; } diff --git a/plugins/Updater/updater.h b/plugins/Updater/updater.h index 604bf3280b79..b207301f2ab2 100644 --- a/plugins/Updater/updater.h +++ b/plugins/Updater/updater.h @@ -84,17 +84,16 @@ typedef struct _PH_UPDATER_CONTEXT HWND DialogHandle; ULONG ErrorCode; + PPH_STRING SetupFilePath; PPH_STRING CurrentVersionString; PPH_STRING Version; - PPH_STRING RevVersion; PPH_STRING RelDate; - PPH_STRING Size; - PPH_STRING Hash; - PPH_STRING Signature; - PPH_STRING ReleaseNotesUrl; - PPH_STRING SetupFileDownloadUrl; - PPH_STRING SetupFilePath; + PPH_STRING SetupFileLength; + PPH_STRING SetupFileDownloadUrl; + PPH_STRING SetupFileHash; + PPH_STRING SetupFileSignature; + // Nightly builds only PPH_STRING BuildMessage; } PH_UPDATER_CONTEXT, *PPH_UPDATER_CONTEXT; From 439388b1f352718346497fffa48beb3346e865a5 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 15 Oct 2017 07:11:15 +1100 Subject: [PATCH 0503/2058] SetupTool: Update to latest json format --- .../CustomSetupTool/download.c | 57 ++++++++----------- .../CustomSetupTool/include/setup.h | 13 +++-- .../CustomSetupTool/CustomSetupTool/install.c | 2 +- 3 files changed, 33 insertions(+), 39 deletions(-) diff --git a/tools/CustomSetupTool/CustomSetupTool/download.c b/tools/CustomSetupTool/CustomSetupTool/download.c index 830e8f5939a0..51f76385dc58 100644 --- a/tools/CustomSetupTool/CustomSetupTool/download.c +++ b/tools/CustomSetupTool/CustomSetupTool/download.c @@ -267,50 +267,39 @@ BOOLEAN SetupQueryUpdateData( if (!(jsonObject = PhCreateJsonParser(stringBuffer))) goto CleanupExit; - if (value = PhGetJsonValueAsString(jsonObject, "updated")) - Context->RelDate = PhConvertUtf8ToUtf16(value); - if (value = PhGetJsonValueAsString(jsonObject, "size")) - Context->Size = PhConvertUtf8ToUtf16(value); - if (value = PhGetJsonValueAsString(jsonObject, "forum_url")) - Context->ReleaseNotesUrl = PhConvertUtf8ToUtf16(value); - - if (value = PhGetJsonValueAsString(jsonObject, "bin_url")) - Context->BinFileDownloadUrl = PhConvertUtf8ToUtf16(value); - if (value = PhGetJsonValueAsString(jsonObject, "hash_bin")) - Context->BinFileHash = PhConvertUtf8ToUtf16(value); - - if (value = PhGetJsonValueAsString(jsonObject, "setup_url")) - Context->SetupFileDownloadUrl = PhConvertUtf8ToUtf16(value); - if (value = PhGetJsonValueAsString(jsonObject, "sig")) - Context->SetupFileSignature = PhConvertUtf8ToUtf16(value); - if (value = PhGetJsonValueAsString(jsonObject, "version")) - Context->SetupFileVersion = PhConvertUtf8ToUtf16(value); - - if (value = PhGetJsonValueAsString(jsonObject, "websetup_url")) - Context->WebSetupFileDownloadUrl = PhConvertUtf8ToUtf16(value); - if (value = PhGetJsonValueAsString(jsonObject, "websetup_sig")) - Context->WebSetupFileSignature = PhConvertUtf8ToUtf16(value); - if (value = PhGetJsonValueAsString(jsonObject, "websetup_version")) - Context->WebSetupFileVersion = PhConvertUtf8ToUtf16(value); - - if (PhIsNullOrEmptyString(Context->RelDate)) - goto CleanupExit; - if (PhIsNullOrEmptyString(Context->Size)) + Context->RelVersion = PhGetJsonValueAsString(jsonObject, "version"); + Context->RelDate = PhGetJsonValueAsString(jsonObject, "updated"); + + Context->BinFileDownloadUrl = PhGetJsonValueAsString(jsonObject, "bin_url"); + Context->BinFileLength = PhGetJsonValueAsString(jsonObject, "bin_length"); + Context->BinFileHash = PhGetJsonValueAsString(jsonObject, "bin_hash"); + Context->BinFileSignature = PhGetJsonValueAsString(jsonObject, "bin_sig"); + + Context->SetupFileDownloadUrl = PhGetJsonValueAsString(jsonObject, "setup_url"); + Context->SetupFileLength = PhGetJsonValueAsString(jsonObject, "setup_length"); + Context->SetupFileHash = PhGetJsonValueAsString(jsonObject, "setup_hash"); + Context->SetupFileSignature = PhGetJsonValueAsString(jsonObject, "setup_sig"); + + Context->WebSetupFileDownloadUrl = PhGetJsonValueAsString(jsonObject, "websetup_url"); + Context->WebSetupFileVersion = PhGetJsonValueAsString(jsonObject, "websetup_version"); + Context->WebSetupFileLength = PhGetJsonValueAsString(jsonObject, "websetup_length"); + Context->WebSetupFileHash = PhGetJsonValueAsString(jsonObject, "websetup_hash"); + Context->WebSetupFileSignature = PhGetJsonValueAsString(jsonObject, "websetup_sig"); + + if (PhIsNullOrEmptyString(Context->RelVersion)) goto CleanupExit; - if (PhIsNullOrEmptyString(Context->ReleaseNotesUrl)) + if (PhIsNullOrEmptyString(Context->RelDate)) goto CleanupExit; if (PhIsNullOrEmptyString(Context->BinFileDownloadUrl)) goto CleanupExit; - if (PhIsNullOrEmptyString(Context->BinFileHash)) + if (PhIsNullOrEmptyString(Context->BinFileSignature)) goto CleanupExit; if (PhIsNullOrEmptyString(Context->SetupFileDownloadUrl)) goto CleanupExit; if (PhIsNullOrEmptyString(Context->SetupFileSignature)) goto CleanupExit; - if (PhIsNullOrEmptyString(Context->SetupFileVersion)) - goto CleanupExit; //if (PhIsNullOrEmptyString(Context->WebSetupFileDownloadUrl)) // goto CleanupExit; @@ -427,7 +416,7 @@ BOOLEAN UpdateDownloadUpdateData( SetWindowText(Context->MainHeaderHandle, PhFormatString( L"Downloading Process Hacker %s...", - PhGetString(Context->SetupFileVersion) + PhGetString(Context->RelVersion) )->Buffer); //SetWindowText(Context->SubHeaderHandle, L"Progress: ~ of ~ (0.0%)"); diff --git a/tools/CustomSetupTool/CustomSetupTool/include/setup.h b/tools/CustomSetupTool/CustomSetupTool/include/setup.h index eef82542cdf9..204e4eaff6cf 100644 --- a/tools/CustomSetupTool/CustomSetupTool/include/setup.h +++ b/tools/CustomSetupTool/CustomSetupTool/include/setup.h @@ -105,20 +105,25 @@ typedef struct _PH_SETUP_CONTEXT ULONG ErrorCode; PPH_STRING FilePath; + PPH_STRING RelDate; - PPH_STRING Size; - PPH_STRING ReleaseNotesUrl; + PPH_STRING RelVersion; PPH_STRING BinFileDownloadUrl; + PPH_STRING BinFileLength; PPH_STRING BinFileHash; + PPH_STRING BinFileSignature; PPH_STRING SetupFileDownloadUrl; + PPH_STRING SetupFileLength; + PPH_STRING SetupFileHash; PPH_STRING SetupFileSignature; - PPH_STRING SetupFileVersion; PPH_STRING WebSetupFileDownloadUrl; - PPH_STRING WebSetupFileSignature; PPH_STRING WebSetupFileVersion; + PPH_STRING WebSetupFileLength; + PPH_STRING WebSetupFileHash; + PPH_STRING WebSetupFileSignature; HWND MainHeaderHandle; HWND StatusHandle; diff --git a/tools/CustomSetupTool/CustomSetupTool/install.c b/tools/CustomSetupTool/CustomSetupTool/install.c index 18794635fbaf..28e57eda6da7 100644 --- a/tools/CustomSetupTool/CustomSetupTool/install.c +++ b/tools/CustomSetupTool/CustomSetupTool/install.c @@ -175,7 +175,7 @@ INT_PTR CALLBACK SetupInstallPropPage_WndProc( #else SetWindowText(context->MainHeaderHandle, PhaFormatString( L"Installing Process Hacker %s", - PhGetString(context->SetupFileVersion) + PhGetString(context->RelVersion) )->Buffer); #endif SendMessage(context->ProgressHandle, PBM_SETRANGE32, 0, (LPARAM)ExtractTotalLength); From 6befd020b0e7c2a8feff5896b607c50a6789adee Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 15 Oct 2017 07:20:15 +1100 Subject: [PATCH 0504/2058] BuildTools: Update binaries --- .../bin/Release/CustomBuildTool.exe | Bin 162304 -> 163328 bytes .../bin/Release/CustomBuildTool.pdb | Bin 73216 -> 75264 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe b/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe index eccc44aa16cc4def7600af91ef53d0824753c23d..5007bee5757ffc76010dffbf1e2a9721f0f42ddc 100644 GIT binary patch delta 18570 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 delta 17352 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 XRq(f61%H#iT_aB(xNA>Z`bPS{t0t-2 diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb b/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb index f3ccdd966ff702092d823ec80c0a128736eca275..c1fefa50203825176a1fd5a6879b0487bf090184 100644 GIT binary patch delta 18564 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 delta 15801 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 From 22dc344005ca7fcf1ed23761dee0049b406e8250 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 15 Oct 2017 07:57:56 +1100 Subject: [PATCH 0505/2058] BuildTools: Fix commit hash --- tools/CustomBuildTool/Source Files/Build.cs | 2 +- .../bin/Release/CustomBuildTool.exe | Bin 163328 -> 163328 bytes .../bin/Release/CustomBuildTool.pdb | Bin 75264 -> 75264 bytes 3 files changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/CustomBuildTool/Source Files/Build.cs b/tools/CustomBuildTool/Source Files/Build.cs index 2c0a63c2d5aa..4b58ebfece6e 100644 --- a/tools/CustomBuildTool/Source Files/Build.cs +++ b/tools/CustomBuildTool/Source Files/Build.cs @@ -255,7 +255,7 @@ public static void ShowBuildEnvironment(string Platform, bool ShowBuildInfo, boo if (!GitExportBuild) { BuildBranch = Win32.ShellExecute(GitExePath, "rev-parse --abbrev-ref HEAD").Trim(); - BuildCommit = Win32.ShellExecute(GitExePath, "rev-parse --short HEAD").Trim(); + BuildCommit = Win32.ShellExecute(GitExePath, "rev-parse HEAD").Trim(); Program.PrintColorMessage("Branch: ", ConsoleColor.Cyan, false); Program.PrintColorMessage(BuildBranch, ConsoleColor.White); diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe b/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe index 5007bee5757ffc76010dffbf1e2a9721f0f42ddc..9e9a9cd51082919cb782ba4c5b1a9f4c65341c94 100644 GIT binary patch delta 7129 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 diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb b/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb index c1fefa50203825176a1fd5a6879b0487bf090184..b2f8f7a0dd82ae675d6ced25eae4f43ee35488cc 100644 GIT binary patch delta 1374 zcmZ|PT}TvB6bJDC9cNc}+|?~MS9A%>MF=z{Ovznh*9w?_v*?oOSY z6%Pv{UeA1@Do||(_U8$8>GRTz8LGS$73WRkRR6dZpQ4-)J@F|svi+r8uebO18T=F1 z{6MR|tz(5Y+hthdjQZ7{Ze2Ae`fAwAZNuHhtWT8X4|hMNm_{Sz6XDob`q|)w odod{+g;i!>Ezp)_Mo<%F%4C-j+j*u>Yht00{c5HoCE`=@Z{bd@sQ>@~ delta 1369 zcmZ{kO=uHQ5Xb*7*~Dg>v=P!ok|3?grBJI@s2Yl-h#wdb=}D0qZ}uR92d!G^2GIys z6scuFsh3{-2->=6dMFW5DS=WDX%7lL)T-!7!Jgx6voFoA&RpKdZ{|OuzCNP%1=m!qS z4cJ+U*k!YnHM6tbO~AB7j<{dMIL&UY85m(i-vohAjOc@nKnueriS@Z8v={0M0kd`a zH0fr3eVG)ynZQZ}c;c1bcG1V1frUCz>1ApTw*rH5!_k@5Rs`^>E}?O&vZQEZY15zU zin)K15&S{yGgHVrH;`rG5(;oaGR;xtFu@rK9W3Pm!c4-W)U7LL7)`CS0XV|I zE5!CN>?N@eOv1bh{AS_?8-d(93)H6O|119Sh{G;ACL`^@UJJSK^Sbmh6PAgUsK2H; z*^RBhr7HS|p%X|lEJ^H?WST9ZfBYK3Aq%>(>yb5ufPcI~Y>{CL+kmqS+qWHf{$B>@ zJwDMSpl5s{wtkl>9WcKGxMPLUNvWC1`nv#nHP+0@^ny=B=@>jEpB{b6Ct9fP@3cr+ n0kz9UYg4RkCy=RQdQcTnx;%PEbu1oI#Y`jnU>4(HvC{k(UF55( From cbeecc7f15dc23dfd5c2dbcbc897fd0357f03c80 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 15 Oct 2017 08:01:17 +1100 Subject: [PATCH 0506/2058] BuildTools: Fix appveyor version --- tools/CustomBuildTool/Source Files/Build.cs | 2 +- .../bin/Release/CustomBuildTool.exe | Bin 163328 -> 163328 bytes .../bin/Release/CustomBuildTool.pdb | Bin 75264 -> 75264 bytes 3 files changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/CustomBuildTool/Source Files/Build.cs b/tools/CustomBuildTool/Source Files/Build.cs index 4b58ebfece6e..088571bb97a0 100644 --- a/tools/CustomBuildTool/Source Files/Build.cs +++ b/tools/CustomBuildTool/Source Files/Build.cs @@ -273,7 +273,7 @@ public static void ShowBuildEnvironment(string Platform, bool ShowBuildInfo, boo BuildCount = "0"; BuildVersion = "3.0." + BuildRevision; - BuildLongVersion = "3.0." + BuildRevision + "." + BuildCount; + BuildLongVersion = "3.0." + BuildCount + "." + BuildRevision; if (ShowBuildInfo && !GitExportBuild) { diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe b/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe index 9e9a9cd51082919cb782ba4c5b1a9f4c65341c94..75b114bc7dbdf48d404d2a57782ce2527e4c2191 100644 GIT binary patch delta 108 zcmZqp!`bkMb3zBx(W;GIcC6fd3=Awq%NZF8>i9QbX0^N|kXN2_`@Bu4!?rh@_N1(g zJib}xhKPjD(W*z03_!pH#4?Nw3?6)p3?3gC7=nUbfC$T6Wwai>8&nOQ9 zPgt_+A*+WnN;&j`LJ*1&Br4E{q6~>5=t1N9^VId*b@#j-8|UHJ+0V>(W@l&ix~HY? zX=y~V=fCKfKgs|c+8L@pR&mWYzIfW_?D^0d_1ZV)xaa=dF7LZKWc6cTziY5->fW!n zEu(c0*_{lp%{u7$)L0gEZLlzD?sC@esJrOzgxw#YFw~{{15xk%mjXEyQR`}92u030 zf%>H?{hDoptV5lOR?JqF1w1i`>$gBA%B+;Lfj&X#WDf975PCBg$P?HISwotE=82}c zftM-c$wo8v>8B{MQqVE67I+E5ZrtEj=4T;X7*8268cKYW z^j9KU74`l}LEtyC_kxK$w*ZZTenk>++%TD&Wf$Qy139a)0v^GD2WYi=1vZ-w91 zr5V6}0d|sA3v7(+jbOlDJFqC|*X{tim(6855wWSkFZwE bR)R9JT-~xz8uP7TlNRBBXUywipR@k~HpKq= delta 1890 zcmaKtYe-a45Xb*#z3XEiy2+*sE@3G_R9cC;Nth*66oeFn5tT$lLgfd+EiE?|i@+9gPNEYkdByuB-lH?Rn{gBiG;b4rf>Aw|>kV z+;X4YNew1DhpSe4S4X`ol9)E~d89Au&-)X1g?dN~tUlBe4NiZ_(M!#<>4PV7+5>Fk z2h;2a0dy!tM}5Fsh3JhXz)}SpAhyRLpuHJ~A9$Hi zPZwc~Za+qfC5pt^Y@jb$MB7DsmjROrq9TfGHs=Ci;gBZtI~QI&PAC}doc*Bbo(PXu zO@;dpDFnX}d#7mRMG|mWk(Z|d2L#ilE}IEH6HsDhP9RHBu!^SDreISkK(#_sFGvM; zD_|3`jS4nI?6sm`n+y1%$P2rHmU-s2{UTz&oNT8<@2==r1(aJ+4&0iHXXvgNBNnIm za+BGmwZNHwXaPe3kgs6*#A*c7Z3Tf=f@dvg)iqE2_OryM6l}5(IHh2f>wrfJrvD_^ zU_lKuOv`w|&q+h;=F0!3_ZI6w~Z^?RB-pwpxtdnDI1?xl`Kf`pLb?7))c? zN59g?GAkk(x5cf%J6c`@>{753i?A56?Fo6t4j0?YVBB=EocUMBD>M`X^oC8NXE$e@ zos*a`L+PaAamy-~rAQ&eRjx_QsG)RHXM`c8IqVWVXDNwyV(UNEx&MRevgXp zg6H!NI*Exp%Ipd;@d{)XStRdnBHJfAwF>qVJZbs75)07$X$6}mvqECD^G! Date: Sun, 15 Oct 2017 09:33:23 +1100 Subject: [PATCH 0507/2058] BuildTools: Fix updating from older builds --- tools/CustomBuildTool/Source Files/Build.cs | 1 + tools/CustomBuildTool/Source Files/Utils.cs | 1 + .../bin/Release/CustomBuildTool.exe | Bin 163328 -> 163840 bytes .../bin/Release/CustomBuildTool.pdb | Bin 75264 -> 75264 bytes 4 files changed, 2 insertions(+) diff --git a/tools/CustomBuildTool/Source Files/Build.cs b/tools/CustomBuildTool/Source Files/Build.cs index 088571bb97a0..0307f39ce004 100644 --- a/tools/CustomBuildTool/Source Files/Build.cs +++ b/tools/CustomBuildTool/Source Files/Build.cs @@ -990,6 +990,7 @@ public static void WebServiceUpdateConfig() FileLengthDeprecated = BuildSetupFileLength.ToString(), // TODO: Remove after most users have updated. ForumUrlDeprecated = "https://wj32.org/processhacker/", // TODO: Remove after most users have updated. + SetupHashDeprecated = BuildSetupHash, // TODO: Remove after most users have updated. SetupSigDeprecated = BuildSetupSig, // TODO: Remove after most users have updated. BinHashDeprecated = BuildBinHash // TODO: Remove after most users have updated. }); diff --git a/tools/CustomBuildTool/Source Files/Utils.cs b/tools/CustomBuildTool/Source Files/Utils.cs index 088112be4cac..39727e0272cb 100644 --- a/tools/CustomBuildTool/Source Files/Utils.cs +++ b/tools/CustomBuildTool/Source Files/Utils.cs @@ -364,6 +364,7 @@ public class BuildUpdateRequest [DataMember(Name = "size")] public string FileLengthDeprecated { get; set; } // TODO: Remove after most users have updated. [DataMember(Name = "forum_url")] public string ForumUrlDeprecated { get; set; } // TODO: Remove after most users have updated. [DataMember(Name = "hash_bin")] public string BinHashDeprecated { get; set; } // TODO: Remove after most users have updated. + [DataMember(Name = "hash_setup")] public string SetupHashDeprecated { get; set; } // TODO: Remove after most users have updated. [DataMember(Name = "sig")] public string SetupSigDeprecated { get; set; } // TODO: Remove after most users have updated. } diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe b/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe index 75b114bc7dbdf48d404d2a57782ce2527e4c2191..c47c6a0ee102e9e4af0762e2f4cd1e2d4a64a7c9 100644 GIT binary patch delta 8530 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 LZhM-7;(PHglgNPA delta 8258 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 wBdn;b?MPe5VK(Bk5E2pQ Date: Sun, 15 Oct 2017 20:44:30 +1100 Subject: [PATCH 0508/2058] Update PhGetPhVersionNumbers --- ProcessHacker/appsup.c | 4 +++- ProcessHacker/include/appsup.h | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/ProcessHacker/appsup.c b/ProcessHacker/appsup.c index 3fe2ad206c8e..4736a7a02e33 100644 --- a/ProcessHacker/appsup.c +++ b/ProcessHacker/appsup.c @@ -1255,7 +1255,7 @@ PPH_STRING PhGetPhVersion( VOID PhGetPhVersionNumbers( _Out_opt_ PULONG MajorVersion, _Out_opt_ PULONG MinorVersion, - _Reserved_ PULONG Reserved, + _Out_opt_ PULONG BuildNumber, _Out_opt_ PULONG RevisionNumber ) { @@ -1263,6 +1263,8 @@ VOID PhGetPhVersionNumbers( *MajorVersion = PHAPP_VERSION_MAJOR; if (MinorVersion) *MinorVersion = PHAPP_VERSION_MINOR; + if (BuildNumber) + *BuildNumber = PHAPP_VERSION_BUILD; if (RevisionNumber) *RevisionNumber = PHAPP_VERSION_REVISION; } diff --git a/ProcessHacker/include/appsup.h b/ProcessHacker/include/appsup.h index d82339461152..bd3c04e42099 100644 --- a/ProcessHacker/include/appsup.h +++ b/ProcessHacker/include/appsup.h @@ -242,7 +242,7 @@ NTAPI PhGetPhVersionNumbers( _Out_opt_ PULONG MajorVersion, _Out_opt_ PULONG MinorVersion, - _Reserved_ PULONG Reserved, + _Out_opt_ PULONG BuildNumber, _Out_opt_ PULONG RevisionNumber ); From 77f43a80bb4c0fb10b32f24e174ed64fe4c76442 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 16 Oct 2017 00:43:01 +1100 Subject: [PATCH 0509/2058] Add KPH fixes for RS4 --- phlib/kphdata.c | 129 ++++++++++++++++++------------------------------ 1 file changed, 48 insertions(+), 81 deletions(-) diff --git a/phlib/kphdata.c b/phlib/kphdata.c index 1ec3c206008b..ba09f5928584 100644 --- a/phlib/kphdata.c +++ b/phlib/kphdata.c @@ -125,52 +125,31 @@ NTSTATUS KphInitializeDynamicPackage( Package->StructData.ObAttributesShift = 17; } // Windows 10 - else if (majorVersion == 10 && minorVersion == 0 && buildNumber == 10240) + else if (majorVersion == 10 && minorVersion == 0) { - Package->BuildNumber = 10240; - Package->ResultingNtVersion = PHNT_THRESHOLD; - - Package->StructData.EgeGuid = 0x18; - Package->StructData.EpObjectTable = 0x418; - Package->StructData.EreGuidEntry = 0x20; - Package->StructData.HtHandleContentionEvent = 0x30; - Package->StructData.OtName = 0x10; - Package->StructData.OtIndex = 0x28; - Package->StructData.ObDecodeShift = 16; - Package->StructData.ObAttributesShift = 17; - } - else if (majorVersion == 10 && minorVersion == 0 && buildNumber == 10586) - { - Package->BuildNumber = 10586; - Package->ResultingNtVersion = PHNT_THRESHOLD2; - - Package->StructData.EgeGuid = 0x18; - Package->StructData.EpObjectTable = 0x418; - Package->StructData.EreGuidEntry = 0x20; - Package->StructData.HtHandleContentionEvent = 0x30; - Package->StructData.OtName = 0x10; - Package->StructData.OtIndex = 0x28; - Package->StructData.ObDecodeShift = 16; - Package->StructData.ObAttributesShift = 17; - } - else if (majorVersion == 10 && minorVersion == 0 && buildNumber == 14393) - { - Package->BuildNumber = 14393; - Package->ResultingNtVersion = PHNT_REDSTONE; - - Package->StructData.EgeGuid = 0x18; - Package->StructData.EpObjectTable = 0x418; - Package->StructData.EreGuidEntry = 0x20; - Package->StructData.HtHandleContentionEvent = 0x30; - Package->StructData.OtName = 0x10; - Package->StructData.OtIndex = 0x28; - Package->StructData.ObDecodeShift = 16; - Package->StructData.ObAttributesShift = 17; - } - else if (majorVersion == 10 && minorVersion == 0 && buildNumber == 15063) - { - Package->BuildNumber = 15063; - Package->ResultingNtVersion = PHNT_REDSTONE2; + switch (buildNumber) + { + case 10240: + Package->BuildNumber = 10240; + Package->ResultingNtVersion = PHNT_THRESHOLD; + break; + case 10586: + Package->BuildNumber = 10586; + Package->ResultingNtVersion = PHNT_THRESHOLD2; + break; + case 14393: + Package->BuildNumber = 14393; + Package->ResultingNtVersion = PHNT_REDSTONE; + break; + case 15063: + Package->BuildNumber = 15063; + Package->ResultingNtVersion = PHNT_REDSTONE2; + break; + default: + Package->BuildNumber = USHRT_MAX; + Package->ResultingNtVersion = PHNT_THRESHOLD; + break; + } Package->StructData.EgeGuid = 0x18; Package->StructData.EpObjectTable = 0x418; @@ -274,43 +253,31 @@ NTSTATUS KphInitializeDynamicPackage( Package->StructData.OtIndex = 0x14; } // Windows 10 - else if (majorVersion == 10 && minorVersion == 0 && buildNumber == 10240) - { - Package->BuildNumber = 10240; - Package->ResultingNtVersion = PHNT_THRESHOLD; - - Package->StructData.EgeGuid = 0xc; - Package->StructData.EpObjectTable = 0x154; - Package->StructData.EreGuidEntry = 0x10; - Package->StructData.OtName = 0x8; - Package->StructData.OtIndex = 0x14; - } - else if (majorVersion == 10 && minorVersion == 0 && buildNumber == 10586) - { - Package->BuildNumber = 10586; - Package->ResultingNtVersion = PHNT_THRESHOLD2; - - Package->StructData.EgeGuid = 0xc; - Package->StructData.EpObjectTable = 0x154; - Package->StructData.EreGuidEntry = 0x10; - Package->StructData.OtName = 0x8; - Package->StructData.OtIndex = 0x14; - } - else if (majorVersion == 10 && minorVersion == 0 && buildNumber == 14393) + else if (majorVersion == 10 && minorVersion == 0) { - Package->BuildNumber = 14393; - Package->ResultingNtVersion = PHNT_REDSTONE; - - Package->StructData.EgeGuid = 0xc; - Package->StructData.EpObjectTable = 0x154; - Package->StructData.EreGuidEntry = 0x10; - Package->StructData.OtName = 0x8; - Package->StructData.OtIndex = 0x14; - } - else if (majorVersion == 10 && minorVersion == 0 && buildNumber == 15063) - { - Package->BuildNumber = 15063; - Package->ResultingNtVersion = PHNT_REDSTONE2; + switch (buildNumber) + { + case 10240: + Package->BuildNumber = 10240; + Package->ResultingNtVersion = PHNT_THRESHOLD; + break; + case 10586: + Package->BuildNumber = 10586; + Package->ResultingNtVersion = PHNT_THRESHOLD2; + break; + case 14393: + Package->BuildNumber = 14393; + Package->ResultingNtVersion = PHNT_REDSTONE; + break; + case 15063: + Package->BuildNumber = 15063; + Package->ResultingNtVersion = PHNT_REDSTONE2; + break; + default: + Package->BuildNumber = USHRT_MAX; + Package->ResultingNtVersion = PHNT_THRESHOLD; + break; + } Package->StructData.EgeGuid = 0xc; Package->StructData.EpObjectTable = 0x154; From b21eb234669e24781be116415886213389fdad8c Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 18 Oct 2017 04:40:48 +1100 Subject: [PATCH 0510/2058] NetworkTools: Fix hostname lookup not always working properly, Fix memory leak --- plugins/NetworkTools/tracert.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/plugins/NetworkTools/tracert.c b/plugins/NetworkTools/tracert.c index 311dfe47787f..c69ccd659198 100644 --- a/plugins/NetworkTools/tracert.c +++ b/plugins/NetworkTools/tracert.c @@ -264,6 +264,11 @@ NTSTATUS NetworkTracertThreadStart( IP_FLAG_DF, 0 }; + WSADATA winsockStartup; + + // WSAStartup required by GetNameInfo. + if (WSAStartup(WINSOCK_VERSION, &winsockStartup) != ERROR_SUCCESS) + goto CleanupExit; if (icmpRandString = PhCreateStringEx(NULL, PhGetIntegerSetting(SETTING_NAME_PING_SIZE) * 2 + 2)) { @@ -448,13 +453,15 @@ NTSTATUS NetworkTracertThreadStart( CleanupExit: if (icmpHandle != INVALID_HANDLE_VALUE) - { IcmpCloseHandle(icmpHandle); - } PostMessage(context->WindowHandle, NTM_RECEIVEDFINISH, 0, 0); - PhDereferenceObject(context); + + if (icmpEchoBuffer) + PhDereferenceObject(icmpEchoBuffer); + + WSACleanup(); return STATUS_SUCCESS; } From b4614ff45e4e9527645cdc949260a8ad9b9fdef8 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 18 Oct 2017 21:41:35 +1100 Subject: [PATCH 0511/2058] Update to latest Windows SDK --- KProcessHacker/KProcessHacker.vcxproj | 2 +- ProcessHacker/ProcessHacker.vcxproj | 2 +- phlib/phlib.vcxproj | 2 +- phnt/include/ntmmapi.h | 8 ++++++++ plugins/DotNetTools/DotNetTools.vcxproj | 2 +- .../ExtendedNotifications/ExtendedNotifications.vcxproj | 2 +- plugins/ExtendedServices/ExtendedServices.vcxproj | 2 +- plugins/ExtendedTools/ExtendedTools.vcxproj | 2 +- plugins/ExtraPlugins/ExtraPlugins.vcxproj | 2 +- plugins/HardwareDevices/HardwareDevices.vcxproj | 2 +- plugins/NetworkTools/NetworkTools.vcxproj | 2 +- plugins/OnlineChecks/OnlineChecks.vcxproj | 2 +- plugins/ToolStatus/ToolStatus.vcxproj | 2 +- plugins/Updater/Updater.vcxproj | 2 +- plugins/UserNotes/UserNotes.vcxproj | 2 +- plugins/WindowExplorer/WindowExplorer.vcxproj | 2 +- .../CustomSetupTool/CustomSetupTool.vcxproj | 2 +- tools/peview/peview.vcxproj | 2 +- 18 files changed, 25 insertions(+), 17 deletions(-) diff --git a/KProcessHacker/KProcessHacker.vcxproj b/KProcessHacker/KProcessHacker.vcxproj index 3f18628eba62..b19957e7dee6 100644 --- a/KProcessHacker/KProcessHacker.vcxproj +++ b/KProcessHacker/KProcessHacker.vcxproj @@ -28,7 +28,7 @@ KProcessHacker $(VCTargetsPath11) - $(LatestTargetPlatformVersion) + 10.0.16299.0 WindowsKernelModeDriver10.0 diff --git a/ProcessHacker/ProcessHacker.vcxproj b/ProcessHacker/ProcessHacker.vcxproj index 99d582dc11ed..b998678db459 100644 --- a/ProcessHacker/ProcessHacker.vcxproj +++ b/ProcessHacker/ProcessHacker.vcxproj @@ -22,7 +22,7 @@ {0271DD27-6707-4290-8DFE-285702B7115D} ProcessHacker Win32Proj - 10.0.15063.0 + 10.0.16299.0 diff --git a/phlib/phlib.vcxproj b/phlib/phlib.vcxproj index fe378512fe80..8582f9290f38 100644 --- a/phlib/phlib.vcxproj +++ b/phlib/phlib.vcxproj @@ -22,7 +22,7 @@ {477D0215-F252-41A1-874B-F27E3EA1ED17} phlib Win32Proj - 10.0.15063.0 + 10.0.16299.0 diff --git a/phnt/include/ntmmapi.h b/phnt/include/ntmmapi.h index 8446e6f5568d..4f22eb67380e 100644 --- a/phnt/include/ntmmapi.h +++ b/phnt/include/ntmmapi.h @@ -629,6 +629,14 @@ NtAreMappedFilesTheSame( // Partitions +#ifndef MEMORY_PARTITION_QUERY_ACCESS +#define MEMORY_PARTITION_QUERY_ACCESS 0x0001 +#define MEMORY_PARTITION_MODIFY_ACCESS 0x0002 +#define MEMORY_PARTITION_ALL_ACCESS \ + (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | \ + MEMORY_PARTITION_QUERY_ACCESS | MEMORY_PARTITION_MODIFY_ACCESS) +#endif + // private typedef enum _MEMORY_PARTITION_INFORMATION_CLASS { diff --git a/plugins/DotNetTools/DotNetTools.vcxproj b/plugins/DotNetTools/DotNetTools.vcxproj index f0b912ea36de..60fe4cddde3e 100644 --- a/plugins/DotNetTools/DotNetTools.vcxproj +++ b/plugins/DotNetTools/DotNetTools.vcxproj @@ -23,7 +23,7 @@ DotNetTools Win32Proj DotNetTools - 10.0.15063.0 + 10.0.16299.0 diff --git a/plugins/ExtendedNotifications/ExtendedNotifications.vcxproj b/plugins/ExtendedNotifications/ExtendedNotifications.vcxproj index 348d996c5ca4..4c13d33c0dc2 100644 --- a/plugins/ExtendedNotifications/ExtendedNotifications.vcxproj +++ b/plugins/ExtendedNotifications/ExtendedNotifications.vcxproj @@ -23,7 +23,7 @@ ExtendedNotifications Win32Proj ExtendedNotifications - 10.0.15063.0 + 10.0.16299.0 diff --git a/plugins/ExtendedServices/ExtendedServices.vcxproj b/plugins/ExtendedServices/ExtendedServices.vcxproj index f257f184c66c..4c2f84f3736b 100644 --- a/plugins/ExtendedServices/ExtendedServices.vcxproj +++ b/plugins/ExtendedServices/ExtendedServices.vcxproj @@ -23,7 +23,7 @@ ExtendedServices Win32Proj ExtendedServices - 10.0.15063.0 + 10.0.16299.0 diff --git a/plugins/ExtendedTools/ExtendedTools.vcxproj b/plugins/ExtendedTools/ExtendedTools.vcxproj index ea3f79282e4e..4dee2ca5e0ec 100644 --- a/plugins/ExtendedTools/ExtendedTools.vcxproj +++ b/plugins/ExtendedTools/ExtendedTools.vcxproj @@ -23,7 +23,7 @@ ExtendedTools Win32Proj ExtendedTools - 10.0.15063.0 + 10.0.16299.0 diff --git a/plugins/ExtraPlugins/ExtraPlugins.vcxproj b/plugins/ExtraPlugins/ExtraPlugins.vcxproj index d42305f9cc4d..15bbc0c42f1f 100644 --- a/plugins/ExtraPlugins/ExtraPlugins.vcxproj +++ b/plugins/ExtraPlugins/ExtraPlugins.vcxproj @@ -23,7 +23,7 @@ ExtraPlugins Win32Proj ExtraPlugins - 10.0.15063.0 + 10.0.16299.0 diff --git a/plugins/HardwareDevices/HardwareDevices.vcxproj b/plugins/HardwareDevices/HardwareDevices.vcxproj index e61a3c53b8db..754c8b7765ab 100644 --- a/plugins/HardwareDevices/HardwareDevices.vcxproj +++ b/plugins/HardwareDevices/HardwareDevices.vcxproj @@ -23,7 +23,7 @@ HardwareDevices Win32Proj HardwareDevices - 10.0.15063.0 + 10.0.16299.0 diff --git a/plugins/NetworkTools/NetworkTools.vcxproj b/plugins/NetworkTools/NetworkTools.vcxproj index 3f96a14ded81..64ed76316c01 100644 --- a/plugins/NetworkTools/NetworkTools.vcxproj +++ b/plugins/NetworkTools/NetworkTools.vcxproj @@ -23,7 +23,7 @@ NetworkTools Win32Proj NetworkTools - 10.0.15063.0 + 10.0.16299.0 diff --git a/plugins/OnlineChecks/OnlineChecks.vcxproj b/plugins/OnlineChecks/OnlineChecks.vcxproj index 9683eec73393..f6a7ecd4e1b2 100644 --- a/plugins/OnlineChecks/OnlineChecks.vcxproj +++ b/plugins/OnlineChecks/OnlineChecks.vcxproj @@ -23,7 +23,7 @@ OnlineChecks Win32Proj OnlineChecks - 10.0.15063.0 + 10.0.16299.0 diff --git a/plugins/ToolStatus/ToolStatus.vcxproj b/plugins/ToolStatus/ToolStatus.vcxproj index b92b848af210..2931e6480717 100644 --- a/plugins/ToolStatus/ToolStatus.vcxproj +++ b/plugins/ToolStatus/ToolStatus.vcxproj @@ -23,7 +23,7 @@ ToolStatus Win32Proj ToolStatus - 10.0.15063.0 + 10.0.16299.0 diff --git a/plugins/Updater/Updater.vcxproj b/plugins/Updater/Updater.vcxproj index 0cacd9bc1f76..1bb143343361 100644 --- a/plugins/Updater/Updater.vcxproj +++ b/plugins/Updater/Updater.vcxproj @@ -23,7 +23,7 @@ Updater Win32Proj Updater - 10.0.15063.0 + 10.0.16299.0 diff --git a/plugins/UserNotes/UserNotes.vcxproj b/plugins/UserNotes/UserNotes.vcxproj index 45cec0ecac59..891f9462e957 100644 --- a/plugins/UserNotes/UserNotes.vcxproj +++ b/plugins/UserNotes/UserNotes.vcxproj @@ -23,7 +23,7 @@ UserNotes Win32Proj UserNotes - 10.0.15063.0 + 10.0.16299.0 diff --git a/plugins/WindowExplorer/WindowExplorer.vcxproj b/plugins/WindowExplorer/WindowExplorer.vcxproj index f61d6d998529..3bd826bcf330 100644 --- a/plugins/WindowExplorer/WindowExplorer.vcxproj +++ b/plugins/WindowExplorer/WindowExplorer.vcxproj @@ -23,7 +23,7 @@ WindowExplorer Win32Proj WindowExplorer - 10.0.15063.0 + 10.0.16299.0 diff --git a/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj b/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj index 46933fea0f5e..3f43de47288d 100644 --- a/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj +++ b/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj @@ -13,7 +13,7 @@ {5C00734F-F50A-49FC-9D2A-F6EE51ECB00F} CustomSetupTool - 10.0.15063.0 + 10.0.16299.0 CustomSetupTool diff --git a/tools/peview/peview.vcxproj b/tools/peview/peview.vcxproj index a5a6ae577e12..9ea3c2dce967 100644 --- a/tools/peview/peview.vcxproj +++ b/tools/peview/peview.vcxproj @@ -22,7 +22,7 @@ {72C124A2-3C80-41C6-ABA1-C4948B713204} peview Win32Proj - 10.0.15063.0 + 10.0.16299.0 From c8749bf759dd94f889df9c9fe54f17bf47ca36e9 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 18 Oct 2017 21:57:48 +1100 Subject: [PATCH 0512/2058] BuildTools: Fix build error while using Build Tools for Visual Studio 2017 --- tools/CustomBuildTool/Source Files/Build.cs | 7 +++---- tools/CustomBuildTool/Source Files/Utils.cs | 1 + .../bin/Release/CustomBuildTool.exe | Bin 163840 -> 163840 bytes .../bin/Release/CustomBuildTool.pdb | Bin 75264 -> 75264 bytes 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tools/CustomBuildTool/Source Files/Build.cs b/tools/CustomBuildTool/Source Files/Build.cs index 0307f39ce004..ac7a3f1f6170 100644 --- a/tools/CustomBuildTool/Source Files/Build.cs +++ b/tools/CustomBuildTool/Source Files/Build.cs @@ -206,8 +206,7 @@ public static bool InitializeBuildEnvironment(bool CheckDependencies) { if (CheckDependencies) { - Program.PrintColorMessage("Git not installed... Exiting.", ConsoleColor.Red); - return false; + Program.PrintColorMessage("[Warning] Git not installed...", ConsoleColor.Yellow); } } @@ -252,7 +251,7 @@ public static void CleanupBuildEnvironment() public static void ShowBuildEnvironment(string Platform, bool ShowBuildInfo, bool ShowLogInfo) { - if (!GitExportBuild) + if (!GitExportBuild && File.Exists(GitExePath)) { BuildBranch = Win32.ShellExecute(GitExePath, "rev-parse --abbrev-ref HEAD").Trim(); BuildCommit = Win32.ShellExecute(GitExePath, "rev-parse HEAD").Trim(); @@ -280,7 +279,7 @@ public static void ShowBuildEnvironment(string Platform, bool ShowBuildInfo, boo Program.PrintColorMessage("Version: ", ConsoleColor.Cyan, false); Program.PrintColorMessage(BuildVersion + Environment.NewLine, ConsoleColor.White); - if (!BuildNightly && ShowLogInfo) + if (!BuildNightly && ShowLogInfo && File.Exists(GitExePath)) { Win32.GetConsoleMode(Win32.GetStdHandle(Win32.STD_OUTPUT_HANDLE), out ConsoleMode mode); Win32.SetConsoleMode(Win32.GetStdHandle(Win32.STD_OUTPUT_HANDLE), mode | ConsoleMode.ENABLE_VIRTUAL_TERMINAL_PROCESSING); diff --git a/tools/CustomBuildTool/Source Files/Utils.cs b/tools/CustomBuildTool/Source Files/Utils.cs index 39727e0272cb..39cfc47bb98f 100644 --- a/tools/CustomBuildTool/Source Files/Utils.cs +++ b/tools/CustomBuildTool/Source Files/Utils.cs @@ -214,6 +214,7 @@ public static string GetMsbuildFilePath() { string vswhereResult = Win32.ShellExecute(vswhere, "-latest " + + "-products * " + "-requires Microsoft.Component.MSBuild " + "-property installationPath " ); diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe b/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe index c47c6a0ee102e9e4af0762e2f4cd1e2d4a64a7c9..6d4f94ed7598186a47d75359070eba401bea087f 100644 GIT binary patch delta 9363 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 delta 9299 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 diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb b/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb index bd969a28c9e155179474e75a8c3859d44792fdd3..596e48415e9b89b3d78904c08a570cc77e4b95ca 100644 GIT binary patch delta 11806 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 BQX2pO From 1f050dcb6b070ba6e03995073f91839ee45bf313 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 18 Oct 2017 22:13:57 +1100 Subject: [PATCH 0513/2058] Update versions for RS3 --- phlib/global.c | 3 +++ phlib/include/phconfig.h | 1 + phlib/kphdata.c | 8 ++++++++ 3 files changed, 12 insertions(+) diff --git a/phlib/global.c b/phlib/global.c index 26c69aa8a4a8..325b13764b8f 100644 --- a/phlib/global.c +++ b/phlib/global.c @@ -214,6 +214,9 @@ static VOID PhInitializeWindowsVersion( case 15063: WindowsVersion = WINDOWS_10_RS2; break; + case 16299: + WindowsVersion = WINDOWS_10_RS3; + break; default: WindowsVersion = WINDOWS_NEW; break; diff --git a/phlib/include/phconfig.h b/phlib/include/phconfig.h index 482921a90007..dcff8133381b 100644 --- a/phlib/include/phconfig.h +++ b/phlib/include/phconfig.h @@ -31,6 +31,7 @@ PHLIBAPI extern ACCESS_MASK ThreadAllAccess; #define WINDOWS_10_TH2 101 #define WINDOWS_10_RS1 102 #define WINDOWS_10_RS2 103 +#define WINDOWS_10_RS3 104 #define WINDOWS_NEW MAXLONG #define WINDOWS_HAS_IMMERSIVE (WindowsVersion >= WINDOWS_8) diff --git a/phlib/kphdata.c b/phlib/kphdata.c index ba09f5928584..472c7800d2c2 100644 --- a/phlib/kphdata.c +++ b/phlib/kphdata.c @@ -145,6 +145,10 @@ NTSTATUS KphInitializeDynamicPackage( Package->BuildNumber = 15063; Package->ResultingNtVersion = PHNT_REDSTONE2; break; + case 16299: + Package->BuildNumber = 16299; + Package->ResultingNtVersion = PHNT_REDSTONE3; + break; default: Package->BuildNumber = USHRT_MAX; Package->ResultingNtVersion = PHNT_THRESHOLD; @@ -273,6 +277,10 @@ NTSTATUS KphInitializeDynamicPackage( Package->BuildNumber = 15063; Package->ResultingNtVersion = PHNT_REDSTONE2; break; + case 16299: + Package->BuildNumber = 16299; + Package->ResultingNtVersion = PHNT_REDSTONE3; + break; default: Package->BuildNumber = USHRT_MAX; Package->ResultingNtVersion = PHNT_THRESHOLD; From 4c5b9185a0e95a57c3baec1929fde25ee5573e49 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 21 Oct 2017 03:53:27 +1100 Subject: [PATCH 0514/2058] PHNT: Update types for RS3 --- phnt/include/ntexapi.h | 99 +++++++++++++++++++++++++++++++++++------ phnt/include/ntioapi.h | 18 +++++++- phnt/include/ntldr.h | 21 ++++++++- phnt/include/ntmmapi.h | 40 ++++++++++++----- phnt/include/ntpebteb.h | 30 ++++++++++--- phnt/include/ntpsapi.h | 67 +++++++++++++++++++++++++--- phnt/include/ntregapi.h | 11 ++++- 7 files changed, 246 insertions(+), 40 deletions(-) diff --git a/phnt/include/ntexapi.h b/phnt/include/ntexapi.h index 01452aa249b8..dcdad9fc1ba5 100644 --- a/phnt/include/ntexapi.h +++ b/phnt/include/ntexapi.h @@ -833,7 +833,8 @@ typedef enum _WNF_DATA_SCOPE WnfDataScopeSystem, WnfDataScopeSession, WnfDataScopeUser, - WnfDataScopeProcess + WnfDataScopeProcess, + WnfDataScopeMachine // REDSTONE3 } WNF_DATA_SCOPE; typedef struct _WNF_TYPE_ID @@ -1240,12 +1241,12 @@ typedef enum _SYSTEM_INFORMATION_CLASS SystemVerifierRemoveDriverInformation, // s (requires SeDebugPrivilege) SystemProcessorIdleInformation, // q: SYSTEM_PROCESSOR_IDLE_INFORMATION SystemLegacyDriverInformation, // q: SYSTEM_LEGACY_DRIVER_INFORMATION - SystemCurrentTimeZoneInformation, // q + SystemCurrentTimeZoneInformation, // q; s: RTL_TIME_ZONE_INFORMATION SystemLookasideInformation, // q: SYSTEM_LOOKASIDE_INFORMATION SystemTimeSlipNotification, // s (requires SeSystemtimePrivilege) SystemSessionCreate, // not implemented SystemSessionDetach, // not implemented - SystemSessionInformation, // not implemented + SystemSessionInformation, // not implemented (SYSTEM_SESSION_INFORMATION) SystemRangeStartInformation, // q: SYSTEM_RANGE_START_INFORMATION // 50 SystemVerifierInformation, // q: SYSTEM_VERIFIER_INFORMATION; s (requires SeDebugPrivilege) SystemVerifierThunkExtend, // s (kernel-mode only) @@ -1265,8 +1266,8 @@ typedef enum _SYSTEM_INFORMATION_CLASS SystemBigPoolInformation, // q: SYSTEM_BIGPOOL_INFORMATION SystemSessionPoolTagInformation, // q: SYSTEM_SESSION_POOLTAG_INFORMATION SystemSessionMappedViewInformation, // q: SYSTEM_SESSION_MAPPED_VIEW_INFORMATION - SystemHotpatchInformation, // q; s - SystemObjectSecurityMode, // q // 70 + SystemHotpatchInformation, // q; s: SYSTEM_HOTPATCH_CODE_INFORMATION + SystemObjectSecurityMode, // q: ULONG // 70 SystemWatchdogTimerHandler, // s (kernel-mode only) SystemWatchdogTimerInformation, // q (kernel-mode only); s (kernel-mode only) SystemLogicalProcessorInformation, // q: SYSTEM_LOGICAL_PROCESSOR_INFORMATION @@ -1391,7 +1392,7 @@ typedef enum _SYSTEM_INFORMATION_CLASS SystemFlushInformation, // q: SYSTEM_FLUSH_INFORMATION SystemProcessorIdleMaskInformation, // since REDSTONE3 SystemSecureDumpEncryptionInformation, - SystemWriteConstraintInformation, + SystemWriteConstraintInformation, // SYSTEM_WRITE_CONSTRAINT_INFORMATION MaxSystemInfoClass } SYSTEM_INFORMATION_CLASS; @@ -1578,7 +1579,9 @@ typedef struct _SYSTEM_PROCESS_INFORMATION LARGE_INTEGER ReadTransferCount; LARGE_INTEGER WriteTransferCount; LARGE_INTEGER OtherTransferCount; - SYSTEM_THREAD_INFORMATION Threads[1]; + SYSTEM_THREAD_INFORMATION Threads[1]; // SystemProcessInformation + // SYSTEM_EXTENDED_THREAD_INFORMATION Threads[1]; // SystemExtendedProcessinformation + // SYSTEM_EXTENDED_THREAD_INFORMATION + SYSTEM_PROCESS_INFORMATION_EXTENSION // SystemFullProcessInformation } SYSTEM_PROCESS_INFORMATION, *PSYSTEM_PROCESS_INFORMATION; typedef struct _SYSTEM_CALL_COUNT_INFORMATION @@ -1792,12 +1795,25 @@ typedef struct _SYSTEM_QUERY_TIME_ADJUST_INFORMATION BOOLEAN Enable; } SYSTEM_QUERY_TIME_ADJUST_INFORMATION, *PSYSTEM_QUERY_TIME_ADJUST_INFORMATION; +typedef struct _SYSTEM_QUERY_TIME_ADJUST_INFORMATION_PRECISE +{ + ULONGLONG TimeAdjustment; + ULONGLONG TimeIncrement; + BOOLEAN Enable; +} SYSTEM_QUERY_TIME_ADJUST_INFORMATION_PRECISE, *PSYSTEM_QUERY_TIME_ADJUST_INFORMATION_PRECISE; + typedef struct _SYSTEM_SET_TIME_ADJUST_INFORMATION { ULONG TimeAdjustment; BOOLEAN Enable; } SYSTEM_SET_TIME_ADJUST_INFORMATION, *PSYSTEM_SET_TIME_ADJUST_INFORMATION; +typedef struct _SYSTEM_SET_TIME_ADJUST_INFORMATION_PRECISE +{ + ULONGLONG TimeAdjustment; + BOOLEAN Enable; +} SYSTEM_SET_TIME_ADJUST_INFORMATION_PRECISE, *PSYSTEM_SET_TIME_ADJUST_INFORMATION_PRECISE; + typedef enum _EVENT_TRACE_INFORMATION_CLASS { EventTraceKernelVersionInformation, // EVENT_TRACE_VERSION_INFORMATION @@ -1819,6 +1835,8 @@ typedef enum _EVENT_TRACE_INFORMATION_CLASS EventTraceStackCachingInformation, // EVENT_TRACE_STACK_CACHING_INFORMATION EventTraceObjectTypeFilterInformation, // EVENT_TRACE_TAG_FILTER_INFORMATION EventTraceSoftRestartInformation, // EVENT_TRACE_SOFT_RESTART_INFORMATION + EventTraceLastBranchConfigurationInformation, // REDSTONE3 + EventTraceLastBranchEventListInformation, MaxEventTraceInfoClass } EVENT_TRACE_INFORMATION_CLASS; @@ -2712,7 +2730,7 @@ typedef struct _PROCESS_ENERGY_VALUES_EXTENSION { union { - TIMELINE_BITMAP Timelines[9]; + TIMELINE_BITMAP Timelines[14]; // 9 for REDSTONE2, 14 for REDSTONE3 struct { TIMELINE_BITMAP CpuTimeline; @@ -2724,8 +2742,29 @@ typedef struct _PROCESS_ENERGY_VALUES_EXTENSION TIMELINE_BITMAP CompositionRenderedTimeline; TIMELINE_BITMAP CompositionDirtyGeneratedTimeline; TIMELINE_BITMAP CompositionDirtyPropagatedTimeline; + TIMELINE_BITMAP InputTimeline; // REDSTONE3 + TIMELINE_BITMAP AudioInTimeline; + TIMELINE_BITMAP AudioOutTimeline; + TIMELINE_BITMAP DisplayRequiredTimeline; + TIMELINE_BITMAP KeyboardInputTimeline; }; }; + + union // REDSTONE3 + { + ENERGY_STATE_DURATION Durations[5]; + struct + { + ENERGY_STATE_DURATION InputDuration; + ENERGY_STATE_DURATION AudioInDuration; + ENERGY_STATE_DURATION AudioOutDuration; + ENERGY_STATE_DURATION DisplayRequiredDuration; + ENERGY_STATE_DURATION PSMBackgroundDuration; + }; + }; + + ULONG KeyboardInput; + ULONG MouseInput; } PROCESS_ENERGY_VALUES_EXTENSION, *PPROCESS_ENERGY_VALUES_EXTENSION; typedef struct _PROCESS_EXTENDED_ENERGY_VALUES @@ -2734,6 +2773,16 @@ typedef struct _PROCESS_EXTENDED_ENERGY_VALUES PROCESS_ENERGY_VALUES_EXTENSION Extension; } PROCESS_EXTENDED_ENERGY_VALUES, *PPROCESS_EXTENDED_ENERGY_VALUES; +// private +typedef enum _SYSTEM_PROCESS_CLASSIFICATION +{ + SystemProcessClassificationNormal, + SystemProcessClassificationSystem, + SystemProcessClassificationSecureSystem, + SystemProcessClassificationMemCompression, + SystemProcessClassificationMaximum +} SYSTEM_PROCESS_CLASSIFICATION; + // private typedef struct _SYSTEM_PROCESS_INFORMATION_EXTENSION { @@ -2745,7 +2794,7 @@ typedef struct _SYSTEM_PROCESS_INFORMATION_EXTENSION struct { ULONG HasStrongId : 1; - ULONG Classification : 4; + ULONG Classification : 4; // SYSTEM_PROCESS_CLASSIFICATION ULONG BackgroundActivityModerated : 1; ULONG Spare : 26; }; @@ -2969,13 +3018,28 @@ typedef enum _SYSTEM_ACTIVITY_MODERATION_STATE MaxSystemActivityModerationState } SYSTEM_ACTIVITY_MODERATION_STATE; -// private -typedef struct _SYSTEM_ACTIVITY_MODERATION_EXE_STATE +// private - REDSTONE2 +typedef struct _SYSTEM_ACTIVITY_MODERATION_EXE_STATE // REDSTONE3: Renamed SYSTEM_ACTIVITY_MODERATION_INFO { UNICODE_STRING ExePathNt; SYSTEM_ACTIVITY_MODERATION_STATE ModerationState; } SYSTEM_ACTIVITY_MODERATION_EXE_STATE, *PSYSTEM_ACTIVITY_MODERATION_EXE_STATE; +typedef enum _SYSTEM_ACTIVITY_MODERATION_APP_TYPE +{ + SystemActivityModerationAppTypeClassic, + SystemActivityModerationAppTypePackaged, + MaxSystemActivityModerationAppType +} SYSTEM_ACTIVITY_MODERATION_APP_TYPE; + +// private - REDSTONE3 +typedef struct _SYSTEM_ACTIVITY_MODERATION_INFO +{ + UNICODE_STRING Identifier; + SYSTEM_ACTIVITY_MODERATION_STATE ModerationState; + SYSTEM_ACTIVITY_MODERATION_APP_TYPE AppType; +} SYSTEM_ACTIVITY_MODERATION_INFO, *PSYSTEM_ACTIVITY_MODERATION_INFO; + // private typedef struct _SYSTEM_ACTIVITY_MODERATION_USER_SETTINGS { @@ -3007,6 +3071,13 @@ typedef struct _SYSTEM_FLUSH_INFORMATION ULONGLONG Reserved[2]; } SYSTEM_FLUSH_INFORMATION, *PSYSTEM_FLUSH_INFORMATION; +// private +typedef struct _SYSTEM_WRITE_CONSTRAINT_INFORMATION +{ + ULONG WriteConstraintPolicy; + ULONG Reserved; +} SYSTEM_WRITE_CONSTRAINT_INFORMATION, *PSYSTEM_WRITE_CONSTRAINT_INFORMATION; + #if (PHNT_MODE != PHNT_MODE_KERNEL) NTSYSCALLAPI @@ -3296,7 +3367,7 @@ typedef struct _KUSER_SHARED_DATA LONG TimeZoneBiasStamp; ULONG NtBuildNumber; - ULONG NtProductType; + NT_PRODUCT_TYPE NtProductType; BOOLEAN ProductTypeIsValid; UCHAR Reserved0[1]; USHORT NativeProcessorArchitecture; @@ -3395,7 +3466,9 @@ typedef struct _KUSER_SHARED_DATA USHORT UnparkedProcessorCount; ULONG EnclaveFeatureMask[4]; - ULONG Reserved8; + + ULONG TelemetryCoverageRound; + USHORT UserModeGlobalLogger[16]; ULONG ImageFileExecutionOptions; diff --git a/phnt/include/ntioapi.h b/phnt/include/ntioapi.h index 6bbcc5652ef9..158e3b091840 100644 --- a/phnt/include/ntioapi.h +++ b/phnt/include/ntioapi.h @@ -242,7 +242,7 @@ typedef enum _FILE_INFORMATION_CLASS FileRenameInformationExBypassAccessCheck, FileDesiredStorageClassInformation, // FILE_DESIRED_STORAGE_CLASS_INFORMATION // since REDSTONE2 FileStatInformation, // FILE_STAT_INFORMATION - FileMemoryPartitionInformation, // since REDSTONE3 + FileMemoryPartitionInformation, // FILE_MEMORY_PARTITION_INFORMATION // since REDSTONE3 FileMaximumInformation } FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS; @@ -680,6 +680,7 @@ typedef struct _FILE_ID_EXTD_BOTH_DIR_INFORMATION WCHAR FileName[1]; } FILE_ID_EXTD_BOTH_DIR_INFORMATION, *PFILE_ID_EXTD_BOTH_DIR_INFORMATION; +// private typedef struct _FILE_STAT_INFORMATION { LARGE_INTEGER FileId; @@ -695,6 +696,21 @@ typedef struct _FILE_STAT_INFORMATION ULONG EffectiveAccess; } FILE_STAT_INFORMATION, *PFILE_STAT_INFORMATION; +// private +typedef struct _FILE_MEMORY_PARTITION_INFORMATION +{ + HANDLE OwnerPartitionHandle; + union + { + struct + { + UCHAR NoCrossPartitionAccess; + UCHAR Spare[3]; + }; + ULONG AllFlags; + } Flags; +} FILE_MEMORY_PARTITION_INFORMATION, *PFILE_MEMORY_PARTITION_INFORMATION; + // NtQueryDirectoryFile types typedef struct _FILE_DIRECTORY_INFORMATION diff --git a/phnt/include/ntldr.h b/phnt/include/ntldr.h index 84e8428ad7a8..09c2f1299805 100644 --- a/phnt/include/ntldr.h +++ b/phnt/include/ntldr.h @@ -76,6 +76,8 @@ typedef enum _LDR_DLL_LOAD_REASON LoadReasonDynamicLoad, LoadReasonAsImageLoad, LoadReasonAsDataLoad, + LoadReasonEnclavePrimary, // REDSTONE3 + LoadReasonEnclaveDependency, LoadReasonUnknown = -1 } LDR_DLL_LOAD_REASON, *PLDR_DLL_LOAD_REASON; @@ -471,9 +473,25 @@ LdrUnregisterDllNotification( // private typedef struct _PS_MITIGATION_OPTIONS_MAP { - ULONG_PTR Map[2]; + union + { + ULONG_PTR Map[2]; // REDSTONE2 + struct + { + ULONG_PTR Depth : 16; // REDSTONE3 + ULONG_PTR Sequence : 48; + ULONG_PTR Reserved : 4; + ULONG_PTR NextEntry : 60; + }; + }; } PS_MITIGATION_OPTIONS_MAP, *PPS_MITIGATION_OPTIONS_MAP; +// private +typedef struct _PS_MITIGATION_AUDIT_OPTIONS_MAP +{ + ULONG_PTR Map[2]; +} PS_MITIGATION_AUDIT_OPTIONS_MAP, *PPS_MITIGATION_AUDIT_OPTIONS_MAP; + // private typedef struct _PS_SYSTEM_DLL_INIT_BLOCK { @@ -496,6 +514,7 @@ typedef struct _PS_SYSTEM_DLL_INIT_BLOCK ULONG_PTR CfgBitMapSize; ULONG_PTR Wow64CfgBitMap; ULONG_PTR Wow64CfgBitMapSize; + PS_MITIGATION_AUDIT_OPTIONS_MAP MitigationAuditOptionsMap; // REDSTONE3 } PS_SYSTEM_DLL_INIT_BLOCK, *PPS_SYSTEM_DLL_INIT_BLOCK; #if (PHNT_VERSION >= PHNT_THRESHOLD) diff --git a/phnt/include/ntmmapi.h b/phnt/include/ntmmapi.h index 4f22eb67380e..02a3e19e74b4 100644 --- a/phnt/include/ntmmapi.h +++ b/phnt/include/ntmmapi.h @@ -127,7 +127,9 @@ typedef struct _MEMORY_REGION_INFORMATION ULONG MappedPageFile : 1; ULONG MappedPhysical : 1; ULONG DirectMapped : 1; - ULONG Reserved : 26; + ULONG SoftwareEnclave : 1; //REDSTONE3 + ULONG PageSize64K : 1; + ULONG Reserved : 24; }; }; SIZE_T RegionSize; @@ -205,6 +207,7 @@ typedef struct _MEMORY_IMAGE_INFORMATION { ULONG ImagePartialMap : 1; ULONG ImageNotExecutable : 1; + ULONG ImageSigningLevel : 1; // REDSTONE3 ULONG Reserved : 30; }; }; @@ -378,10 +381,8 @@ typedef struct _SECTION_INTERNAL_IMAGE_INFORMATION ULONG ExtendedFlags; struct { - ULONG ImageReturnFlowGuardEnabled : 1; - ULONG ImageReturnFlowGuardStrict : 1; ULONG ImageExportSuppressionEnabled : 1; - ULONG Reserved : 29; + ULONG Reserved : 31; }; }; } SECTION_INTERNAL_IMAGE_INFORMATION, *PSECTION_INTERNAL_IMAGE_INFORMATION; @@ -480,13 +481,13 @@ NtQueryVirtualMemory( #endif // begin_private - #if (PHNT_MODE != PHNT_MODE_KERNEL) typedef enum _VIRTUAL_MEMORY_INFORMATION_CLASS { - VmPrefetchInformation, + VmPrefetchInformation, // ULONG VmPagePriorityInformation, - VmCfgCallTargetInformation + VmCfgCallTargetInformation, // CFG_CALL_TARGET_LIST_INFORMATION // REDSTONE2 + VmPageDirtyStateInformation // REDSTONE3 } VIRTUAL_MEMORY_INFORMATION_CLASS; typedef struct _MEMORY_RANGE_ENTRY @@ -494,6 +495,14 @@ typedef struct _MEMORY_RANGE_ENTRY PVOID VirtualAddress; SIZE_T NumberOfBytes; } MEMORY_RANGE_ENTRY, *PMEMORY_RANGE_ENTRY; + +typedef struct _CFG_CALL_TARGET_LIST_INFORMATION +{ + ULONG NumberOfEntries; + ULONG Reserved; + PULONG NumberOfEntriesProcessed; + PCFG_CALL_TARGET_INFO CallTargetInfo; +} CFG_CALL_TARGET_LIST_INFORMATION, *PCFG_CALL_TARGET_LIST_INFORMATION; #endif // end_private @@ -664,10 +673,11 @@ typedef struct _MEMORY_PARTITION_CONFIGURATION_INFORMATION ULONG_PTR ZeroPages; ULONG_PTR FreePages; ULONG_PTR StandbyPages; - ULONG StandbyPageCountByPriority[8]; // since REDSTONE2 - ULONG RepurposedPagesByPriority[8]; - ULONG MaximumCommitLimit; - ULONG DonatedPagesToPartitions; + ULONG_PTR StandbyPageCountByPriority[8]; // since REDSTONE2 + ULONG_PTR RepurposedPagesByPriority[8]; + ULONG_PTR MaximumCommitLimit; + ULONG_PTR DonatedPagesToPartitions; + ULONG PartitionId; // since REDSTONE3 } MEMORY_PARTITION_CONFIGURATION_INFORMATION, *PMEMORY_PARTITION_CONFIGURATION_INFORMATION; // private @@ -722,7 +732,13 @@ typedef struct _MEMORY_PARTITION_MEMORY_EVENTS_INFORMATION ULONG Spare : 31; }; ULONG AllFlags; - }; + } Flags; + + ULONG HandleAttributes; + ULONG DesiredAccess; + HANDLE LowCommitCondition; // \KernelObjects\LowCommitCondition + HANDLE HighCommitCondition; // \KernelObjects\HighCommitCondition + HANDLE MaximumCommitCondition; // \KernelObjects\MaximumCommitCondition } MEMORY_PARTITION_MEMORY_EVENTS_INFORMATION, *PMEMORY_PARTITION_MEMORY_EVENTS_INFORMATION; #if (PHNT_MODE != PHNT_MODE_KERNEL) diff --git a/phnt/include/ntpebteb.h b/phnt/include/ntpebteb.h index 6169a18d4f44..37d4fbb43a55 100644 --- a/phnt/include/ntpebteb.h +++ b/phnt/include/ntpebteb.h @@ -4,6 +4,16 @@ typedef struct _RTL_USER_PROCESS_PARAMETERS *PRTL_USER_PROCESS_PARAMETERS; typedef struct _RTL_CRITICAL_SECTION *PRTL_CRITICAL_SECTION; +// private +typedef struct _ACTIVATION_CONTEXT_STACK +{ + struct _RTL_ACTIVATION_CONTEXT_STACK_FRAME* ActiveFrame; + LIST_ENTRY FrameListCache; + ULONG Flags; + ULONG NextCookieSequenceNumber; + ULONG StackId; +} ACTIVATION_CONTEXT_STACK, *PACTIVATION_CONTEXT_STACK; + // symbols typedef struct _PEB { @@ -62,9 +72,11 @@ typedef struct _PEB ULONG TlsExpansionCounter; PVOID TlsBitmap; ULONG TlsBitmapBits[2]; - PVOID ReadOnlySharedMemoryBase; - PVOID HotpatchInformation; + + PVOID ReadOnlySharedMemoryBase; + PVOID SharedData; // HotpatchInformation PVOID *ReadOnlyStaticServerData; + PVOID AnsiCodePageData; // PCPTABLEINFO PVOID OemCodePageData; // PCPTABLEINFO PVOID UnicodeCaseTableData; // PNLSTABLEINFO @@ -127,7 +139,7 @@ typedef struct _PEB PVOID WerRegistrationData; PVOID WerShipAssertPtr; - PVOID pContextData; + PVOID pUnused; // pContextData PVOID pImageHeaderHash; union { @@ -144,6 +156,8 @@ typedef struct _PEB PVOID TppWorkerpListLock; LIST_ENTRY TppWorkerpList; PVOID WaitOnAddressHashTable[128]; + PVOID TelemetryCoverageHeader; // REDSTONE3 + ULONG CloudFileFlags; } PEB, *PPEB; #define GDI_BATCH_BUFFER_SIZE 310 @@ -188,11 +202,17 @@ typedef struct _TEB LCID CurrentLocale; ULONG FpSoftwareStatusRegister; PVOID ReservedForDebuggerInstrumentation[16]; - PVOID SystemReserved1[37]; + PVOID SystemReserved1[30]; + + CHAR PlaceholderCompatibilityMode; + CHAR PlaceholderReserved[11]; + ULONG ProxiedProcessId; + ACTIVATION_CONTEXT_STACK ActivationStack; + UCHAR WorkingOnBehalfTicket[8]; NTSTATUS ExceptionCode; - PVOID ActivationContextStackPointer; + PACTIVATION_CONTEXT_STACK ActivationContextStackPointer; ULONG_PTR InstrumentationCallbackSp; ULONG_PTR InstrumentationCallbackPreviousPc; ULONG_PTR InstrumentationCallbackPreviousSp; diff --git a/phnt/include/ntpsapi.h b/phnt/include/ntpsapi.h index 0816befb2b34..205d892c7f7a 100644 --- a/phnt/include/ntpsapi.h +++ b/phnt/include/ntpsapi.h @@ -180,12 +180,12 @@ typedef enum _PROCESSINFOCLASS ProcessDisableSystemAllowedCpuSets, ProcessWakeInformation, // PROCESS_WAKE_INFORMATION ProcessEnergyTrackingState, // PROCESS_ENERGY_TRACKING_STATE - ProcessManageWritesToExecutableMemory, // since REDSTONE3 + ProcessManageWritesToExecutableMemory, // MANAGE_WRITES_TO_EXECUTABLE_MEMORY // since REDSTONE3 ProcessCaptureTrustletLiveDump, ProcessTelemetryCoverage, ProcessEnclaveInformation, - ProcessEnableReadWriteVmLogging, - ProcessUptimeInformation, + ProcessEnableReadWriteVmLogging, // PROCESS_READWRITEVM_LOGGING_INFORMATION + ProcessUptimeInformation, // PROCESS_UPTIME_INFORMATION ProcessImageSection, MaxProcessInfoClass } PROCESSINFOCLASS; @@ -242,8 +242,8 @@ typedef enum _THREADINFOCLASS ThreadSubsystemInformation, // q: SUBSYSTEM_INFORMATION_TYPE // since REDSTONE2 ThreadDbgkWerReportActive, ThreadAttachContainer, - ThreadManageWritesToExecutableMemory, // since REDSTONE3 - ThreadPowerThrottlingState, + ThreadManageWritesToExecutableMemory, // MANAGE_WRITES_TO_EXECUTABLE_MEMORY // since REDSTONE3 + ThreadPowerThrottlingState, // THREAD_POWER_THROTTLING_STATE MaxThreadInfoClass } THREADINFOCLASS; #endif @@ -587,6 +587,9 @@ typedef struct _PROCESS_MITIGATION_POLICY_INFORMATION PROCESS_MITIGATION_BINARY_SIGNATURE_POLICY SignaturePolicy; PROCESS_MITIGATION_FONT_DISABLE_POLICY FontDisablePolicy; PROCESS_MITIGATION_IMAGE_LOAD_POLICY ImageLoadPolicy; + PROCESS_MITIGATION_SYSTEM_CALL_FILTER_POLICY SystemCallFilterPolicy; + PROCESS_MITIGATION_PAYLOAD_RESTRICTION_POLICY PayloadRestrictionPolicy; + PROCESS_MITIGATION_CHILD_PROCESS_POLICY ChildProcessPolicy; }; } PROCESS_MITIGATION_POLICY_INFORMATION, *PPROCESS_MITIGATION_POLICY_INFORMATION; @@ -725,7 +728,9 @@ typedef struct _PROCESS_JOB_MEMORY_INFO typedef struct _PROCESS_CHILD_PROCESS_INFORMATION { BOOLEAN ProhibitChildProcesses; - BOOLEAN EnableAutomaticOverride; + //BOOLEAN EnableAutomaticOverride; // REDSTONE2 + BOOLEAN AlwaysAllowSecureChildProcess; // REDSTONE3 + BOOLEAN AuditProhibitChildProcesses; } PROCESS_CHILD_PROCESS_INFORMATION, *PPROCESS_CHILD_PROCESS_INFORMATION; typedef struct _PROCESS_WAKE_INFORMATION @@ -744,6 +749,45 @@ typedef struct _PROCESS_ENERGY_TRACKING_STATE WCHAR Tag[64]; } PROCESS_ENERGY_TRACKING_STATE, *PPROCESS_ENERGY_TRACKING_STATE; +typedef struct _MANAGE_WRITES_TO_EXECUTABLE_MEMORY +{ + ULONG Version : 8; + ULONG ProcessEnableWriteExceptions : 1; + ULONG ThreadAllowWrites : 1; + ULONG Spare : 22; +} MANAGE_WRITES_TO_EXECUTABLE_MEMORY, *PMANAGE_WRITES_TO_EXECUTABLE_MEMORY; + +typedef struct _PROCESS_READWRITEVM_LOGGING_INFORMATION +{ + union + { + BOOLEAN Flags; + struct + { + BOOLEAN EnableReadVmLogging : 1; + BOOLEAN EnableWriteVmLogging : 1; + BOOLEAN Unused : 6; + }; + }; +} PROCESS_READWRITEVM_LOGGING_INFORMATION, *PPROCESS_READWRITEVM_LOGGING_INFORMATION; + +typedef struct _PROCESS_UPTIME_INFORMATION +{ + ULONGLONG QueryInterruptTime; + ULONGLONG QueryUnbiasedTime; + ULONGLONG EndInterruptTime; + ULONGLONG TimeSinceCreation; + ULONGLONG Uptime; + ULONGLONG SuspendedTime; + union + { + ULONG HangCount : 4; + ULONG GhostCount : 4; + ULONG Crashed : 1; + ULONG Terminated : 1; + }; +} PROCESS_UPTIME_INFORMATION, *PPROCESS_UPTIME_INFORMATION; + // end_private #endif @@ -1258,6 +1302,7 @@ typedef enum _PS_ATTRIBUTE_NUM PsAttributeSafeOpenPromptOriginClaim, PsAttributeBnoIsolation, // PS_BNO_ISOLATION_PARAMETERS PsAttributeDesktopAppPolicy, // in ULONG + PsAttributeChpe, // since REDSTONE3 PsAttributeMax } PS_ATTRIBUTE_NUM; @@ -1409,7 +1454,15 @@ typedef enum _PS_MITIGATION_OPTION PS_MITIGATION_OPTION_RETURN_FLOW_GUARD, PS_MITIGATION_OPTION_LOADER_INTEGRITY_CONTINUITY, PS_MITIGATION_OPTION_STRICT_CONTROL_FLOW_GUARD, - PS_MITIGATION_OPTION_RESTRICT_SET_THREAD_CONTEXT + PS_MITIGATION_OPTION_RESTRICT_SET_THREAD_CONTEXT, + PS_MITIGATION_OPTION_ROP_STACKPIVOT, // since REDSTONE3 + PS_MITIGATION_OPTION_ROP_CALLER_CHECK, + PS_MITIGATION_OPTION_ROP_SIMEXEC, + PS_MITIGATION_OPTION_EXPORT_ADDRESS_FILTER, + PS_MITIGATION_OPTION_EXPORT_ADDRESS_FILTER_PLUS, + PS_MITIGATION_OPTION_RESTRICT_CHILD_PROCESS_CREATION, + PS_MITIGATION_OPTION_IMPORT_ADDRESS_FILTER, + PS_MITIGATION_OPTION_MODULE_TAMPERING_PROTECTION } PS_MITIGATION_OPTION; // windows-internals-book:"Chapter 5" diff --git a/phnt/include/ntregapi.h b/phnt/include/ntregapi.h index 0a3a4c8be773..da9bc244de3a 100644 --- a/phnt/include/ntregapi.h +++ b/phnt/include/ntregapi.h @@ -120,7 +120,7 @@ typedef enum _KEY_SET_INFORMATION_CLASS KeySetVirtualizationInformation, // KEY_SET_VIRTUALIZATION_INFORMATION KeySetDebugInformation, KeySetHandleTagsInformation, // KEY_HANDLE_TAGS_INFORMATION - KeySetLayerInformation, + KeySetLayerInformation, // KEY_SET_LAYER_INFORMATION MaxKeySetInfoClass } KEY_SET_INFORMATION_CLASS; @@ -139,6 +139,15 @@ typedef struct _KEY_HANDLE_TAGS_INFORMATION ULONG HandleTags; } KEY_HANDLE_TAGS_INFORMATION, *PKEY_HANDLE_TAGS_INFORMATION; +typedef struct _KEY_SET_LAYER_INFORMATION +{ + ULONG IsTombstone : 1; + ULONG IsSupersedeLocal : 1; + ULONG IsSupersedeTree : 1; + ULONG ClassIsInherited : 1; + ULONG Reserved : 28; +} KEY_SET_LAYER_INFORMATION, *PKEY_SET_LAYER_INFORMATION; + typedef struct _KEY_CONTROL_FLAGS_INFORMATION { ULONG ControlFlags; From c741c5963ff012cc7160d9cbc5dc83fdbca12edd Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 21 Oct 2017 03:53:57 +1100 Subject: [PATCH 0515/2058] Update type name --- ProcessHacker/appsup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ProcessHacker/appsup.c b/ProcessHacker/appsup.c index 4736a7a02e33..233b59ec909c 100644 --- a/ProcessHacker/appsup.c +++ b/ProcessHacker/appsup.c @@ -146,7 +146,7 @@ NTSTATUS PhGetProcessSwitchContext( { if (!NT_SUCCESS(status = NtReadVirtualMemory( ProcessHandle, - PTR_ADD_OFFSET(basicInfo.PebBaseAddress, FIELD_OFFSET(PEB, pContextData)), + PTR_ADD_OFFSET(basicInfo.PebBaseAddress, FIELD_OFFSET(PEB, pUnused)), &data, sizeof(PVOID), NULL From 78f06aa426b4db13cde5eca81ab83339ae4db44e Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 21 Oct 2017 04:02:17 +1100 Subject: [PATCH 0516/2058] Add initial RS3 mitigation options --- ProcessHacker/include/procmtgn.h | 24 +++++---- ProcessHacker/mtgndlg.c | 1 + ProcessHacker/procmtgn.c | 87 ++++++++++++++++++++++++++++++++ 3 files changed, 102 insertions(+), 10 deletions(-) diff --git a/ProcessHacker/include/procmtgn.h b/ProcessHacker/include/procmtgn.h index 480e4d1c6415..20522d78764b 100644 --- a/ProcessHacker/include/procmtgn.h +++ b/ProcessHacker/include/procmtgn.h @@ -4,16 +4,20 @@ typedef struct _PH_PROCESS_MITIGATION_POLICY_ALL_INFORMATION { PVOID Pointers[MaxProcessMitigationPolicy]; - PROCESS_MITIGATION_DEP_POLICY DEPPolicy; - PROCESS_MITIGATION_ASLR_POLICY ASLRPolicy; - PROCESS_MITIGATION_STRICT_HANDLE_CHECK_POLICY StrictHandleCheckPolicy; - PROCESS_MITIGATION_SYSTEM_CALL_DISABLE_POLICY SystemCallDisablePolicy; - PROCESS_MITIGATION_EXTENSION_POINT_DISABLE_POLICY ExtensionPointDisablePolicy; - PROCESS_MITIGATION_DYNAMIC_CODE_POLICY DynamicCodePolicy; - PROCESS_MITIGATION_CONTROL_FLOW_GUARD_POLICY ControlFlowGuardPolicy; - PROCESS_MITIGATION_BINARY_SIGNATURE_POLICY SignaturePolicy; - PROCESS_MITIGATION_FONT_DISABLE_POLICY FontDisablePolicy; - PROCESS_MITIGATION_IMAGE_LOAD_POLICY ImageLoadPolicy; + PROCESS_MITIGATION_DEP_POLICY DEPPolicy; // ProcessDEPPolicy + PROCESS_MITIGATION_ASLR_POLICY ASLRPolicy; // ProcessASLRPolicy + PROCESS_MITIGATION_DYNAMIC_CODE_POLICY DynamicCodePolicy; // ProcessDynamicCodePolicy + PROCESS_MITIGATION_STRICT_HANDLE_CHECK_POLICY StrictHandleCheckPolicy; // ProcessStrictHandleCheckPolicy + PROCESS_MITIGATION_SYSTEM_CALL_DISABLE_POLICY SystemCallDisablePolicy; // ProcessSystemCallDisablePolicy + // ProcessMitigationOptionsMask + PROCESS_MITIGATION_EXTENSION_POINT_DISABLE_POLICY ExtensionPointDisablePolicy; // ProcessExtensionPointDisablePolicy + PROCESS_MITIGATION_CONTROL_FLOW_GUARD_POLICY ControlFlowGuardPolicy; // ProcessControlFlowGuardPolicy + PROCESS_MITIGATION_BINARY_SIGNATURE_POLICY SignaturePolicy; // ProcessSignaturePolicy + PROCESS_MITIGATION_FONT_DISABLE_POLICY FontDisablePolicy; // ProcessFontDisablePolicy + PROCESS_MITIGATION_IMAGE_LOAD_POLICY ImageLoadPolicy; // ProcessImageLoadPolicy + PROCESS_MITIGATION_SYSTEM_CALL_FILTER_POLICY SystemCallFilterPolicy; // ProcessSystemCallFilterPolicy + PROCESS_MITIGATION_PAYLOAD_RESTRICTION_POLICY PayloadRestrictionPolicy; // ProcessPayloadRestrictionPolicy + PROCESS_MITIGATION_CHILD_PROCESS_POLICY ChildProcessPolicy; // ProcessChildProcessPolicy } PH_PROCESS_MITIGATION_POLICY_ALL_INFORMATION, *PPH_PROCESS_MITIGATION_POLICY_ALL_INFORMATION; NTSTATUS PhGetProcessMitigationPolicy( diff --git a/ProcessHacker/mtgndlg.c b/ProcessHacker/mtgndlg.c index cd864ba0eba6..164152b0f52f 100644 --- a/ProcessHacker/mtgndlg.c +++ b/ProcessHacker/mtgndlg.c @@ -116,6 +116,7 @@ INT_PTR CALLBACK PhpProcessMitigationPolicyDlgProc( } ExtendedListView_SortItems(lvHandle); + ExtendedListView_SetColumnWidth(lvHandle, 0, ELVSCW_AUTOSIZE_REMAININGSPACE); ListView_SetItemState(lvHandle, 0, LVIS_FOCUSED | LVIS_SELECTED, LVIS_FOCUSED | LVIS_SELECTED); SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)lvHandle, TRUE); } diff --git a/ProcessHacker/procmtgn.c b/ProcessHacker/procmtgn.c index 4a2c99011157..e002fe1beba4 100644 --- a/ProcessHacker/procmtgn.c +++ b/ProcessHacker/procmtgn.c @@ -3,6 +3,7 @@ * process mitigation information * * Copyright (C) 2016 wj32 + * Copyright (C) 2017 dmex * * This file is part of Process Hacker. * @@ -115,6 +116,9 @@ NTSTATUS PhGetProcessMitigationPolicy( COPY_PROCESS_MITIGATION_POLICY(Signature, PROCESS_MITIGATION_BINARY_SIGNATURE_POLICY); COPY_PROCESS_MITIGATION_POLICY(FontDisable, PROCESS_MITIGATION_FONT_DISABLE_POLICY); COPY_PROCESS_MITIGATION_POLICY(ImageLoad, PROCESS_MITIGATION_IMAGE_LOAD_POLICY); + COPY_PROCESS_MITIGATION_POLICY(SystemCallFilter, PROCESS_MITIGATION_SYSTEM_CALL_FILTER_POLICY); // REDSTONE3 + COPY_PROCESS_MITIGATION_POLICY(PayloadRestriction, PROCESS_MITIGATION_PAYLOAD_RESTRICTION_POLICY); + COPY_PROCESS_MITIGATION_POLICY(ChildProcess, PROCESS_MITIGATION_CHILD_PROCESS_POLICY); return status; } @@ -219,6 +223,17 @@ BOOLEAN PhDescribeProcessMitigationPolicy( result = TRUE; } + + if (data->AllowRemoteDowngrade) + { + if (ShortDescription) + *ShortDescription = PhCreateString(L"Dynamic code downgradable"); + + if (LongDescription) + *LongDescription = PhCreateString(L"Allow non-AppContainer processes to modify all of the dynamic code settings for the calling process, including relaxing dynamic code restrictions after they have been set.\r\n"); + + result = TRUE; + } } break; case ProcessStrictHandleCheckPolicy: @@ -251,6 +266,17 @@ BOOLEAN PhDescribeProcessMitigationPolicy( result = TRUE; } + + if (data->AuditDisallowWin32kSystemCalls) + { + if (ShortDescription) + *ShortDescription = PhCreateString(L"Win32k system calls (Audit)"); + + if (LongDescription) + *LongDescription = PhCreateString(L"Win32k (GDI/USER) system calls will trigger an ETW event.\r\n"); + + result = TRUE; + } } break; case ProcessExtensionPointDisablePolicy: @@ -391,6 +417,67 @@ BOOLEAN PhDescribeProcessMitigationPolicy( } } break; + case ProcessSystemCallFilterPolicy: + { + PPROCESS_MITIGATION_SYSTEM_CALL_FILTER_POLICY data = Data; + + if (data->FilterId) + { + if (ShortDescription) + *ShortDescription = PhCreateString(L"System call filtering"); + + if (LongDescription) + *LongDescription = PhCreateString(L"System call filtering is active.\r\n"); + + result = TRUE; + } + } + break; + + case ProcessPayloadRestrictionPolicy: + { + PPROCESS_MITIGATION_PAYLOAD_RESTRICTION_POLICY data = Data; + + if (data->EnableExportAddressFilter || data->EnableExportAddressFilterPlus || + data->EnableImportAddressFilter || data->EnableRopStackPivot || + data->EnableRopCallerCheck || data->EnableRopSimExec) + { + if (ShortDescription) + *ShortDescription = PhCreateString(L"Payload restrictions"); + + if (LongDescription) + { + PhInitializeStringBuilder(&sb, 100); + PhAppendStringBuilder2(&sb, L"Payload restrictions are enabled for this process.\r\n"); + if (data->EnableExportAddressFilter) PhAppendStringBuilder2(&sb, L"Export Address Filtering is enabled.\r\n"); + if (data->EnableExportAddressFilterPlus) PhAppendStringBuilder2(&sb, L"Export Address Filtering (Plus) is enabled.\r\n"); + if (data->EnableImportAddressFilter) PhAppendStringBuilder2(&sb, L"Import Address Filtering is enabled.\r\n"); + if (data->EnableRopStackPivot) PhAppendStringBuilder2(&sb, L"StackPivot is enabled.\r\n"); + if (data->EnableRopCallerCheck) PhAppendStringBuilder2(&sb, L"CallerCheck is enabled.\r\n"); + if (data->EnableRopSimExec) PhAppendStringBuilder2(&sb, L"SimExec is enabled.\r\n"); + *LongDescription = PhFinalStringBuilderString(&sb); + } + + result = TRUE; + } + } + break; + case ProcessChildProcessPolicy: + { + PPROCESS_MITIGATION_CHILD_PROCESS_POLICY data = Data; + + if (data->NoChildProcessCreation) + { + if (ShortDescription) + *ShortDescription = PhCreateString(L"Child process creation disabled"); + + if (LongDescription) + *LongDescription = PhCreateString(L"Child processes cannot be created by this process.\r\n"); + + result = TRUE; + } + } + break; default: result = FALSE; } From a0943b8e42214ab4cdae43f9939b9ad6639652a5 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 21 Oct 2017 04:02:39 +1100 Subject: [PATCH 0517/2058] Remove mitigation dialog column header --- ProcessHacker/ProcessHacker.rc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ProcessHacker/ProcessHacker.rc b/ProcessHacker/ProcessHacker.rc index ffb1f8741c04..e37738d8f2f0 100644 --- a/ProcessHacker/ProcessHacker.rc +++ b/ProcessHacker/ProcessHacker.rc @@ -1828,7 +1828,7 @@ STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSM CAPTION "Mitigation Policies" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN - CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,7,263,108 + CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | LVS_NOCOLUMNHEADER | WS_BORDER | WS_TABSTOP,7,7,263,108 LTEXT "Description:",IDC_DESCRIPTIONLABEL,7,118,38,8 EDITTEXT IDC_DESCRIPTION,7,129,263,62,ES_MULTILINE | ES_READONLY | WS_VSCROLL DEFPUSHBUTTON "OK",IDOK,220,196,50,14 From 25d4882497ded0f36a633c458eea69c60e76c3b6 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 21 Oct 2017 04:03:30 +1100 Subject: [PATCH 0518/2058] Rename Win10 context guid --- ProcessHacker/appsup.c | 2 +- ProcessHacker/include/appsup.h | 2 +- ProcessHacker/proctree.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ProcessHacker/appsup.c b/ProcessHacker/appsup.c index 233b59ec909c..8ac68a44e908 100644 --- a/ProcessHacker/appsup.c +++ b/ProcessHacker/appsup.c @@ -47,7 +47,7 @@ GUID VISTA_CONTEXT_GUID = { 0xe2011457, 0x1546, 0x43c5, { 0xa5, 0xfe, 0x00, 0x8d GUID WIN7_CONTEXT_GUID = { 0x35138b9a, 0x5d96, 0x4fbd, { 0x8e, 0x2d, 0xa2, 0x44, 0x02, 0x25, 0xf9, 0x3a } }; GUID WIN8_CONTEXT_GUID = { 0x4a2f28e3, 0x53b9, 0x4441, { 0xba, 0x9c, 0xd6, 0x9d, 0x4a, 0x4a, 0x6e, 0x38 } }; GUID WINBLUE_CONTEXT_GUID = { 0x1f676c76, 0x80e1, 0x4239, { 0x95, 0xbb, 0x83, 0xd0, 0xf6, 0xd0, 0xda, 0x78 } }; -GUID WINTHRESHOLD_CONTEXT_GUID = { 0x8e0f7a12, 0xbfb3, 0x4fe8, { 0xb9, 0xa5, 0x48, 0xfd, 0x50, 0xa1, 0x5a, 0x9a } }; +GUID WIN10_CONTEXT_GUID = { 0x8e0f7a12, 0xbfb3, 0x4fe8, { 0xb9, 0xa5, 0x48, 0xfd, 0x50, 0xa1, 0x5a, 0x9a } }; /** * Determines whether a process is suspended. diff --git a/ProcessHacker/include/appsup.h b/ProcessHacker/include/appsup.h index bd3c04e42099..9df859d7fc9a 100644 --- a/ProcessHacker/include/appsup.h +++ b/ProcessHacker/include/appsup.h @@ -6,7 +6,7 @@ extern GUID VISTA_CONTEXT_GUID; extern GUID WIN7_CONTEXT_GUID; extern GUID WIN8_CONTEXT_GUID; extern GUID WINBLUE_CONTEXT_GUID; -extern GUID WINTHRESHOLD_CONTEXT_GUID; +extern GUID WIN10_CONTEXT_GUID; // begin_phapppub PHAPPAPI diff --git a/ProcessHacker/proctree.c b/ProcessHacker/proctree.c index 3d1ba2b22158..fcebcb953846 100644 --- a/ProcessHacker/proctree.c +++ b/ProcessHacker/proctree.c @@ -972,7 +972,7 @@ static VOID PhpUpdateProcessOsContext( { if (NT_SUCCESS(PhGetProcessSwitchContext(processHandle, &ProcessNode->OsContextGuid))) { - if (IsEqualGUID(&ProcessNode->OsContextGuid, &WINTHRESHOLD_CONTEXT_GUID)) + if (IsEqualGUID(&ProcessNode->OsContextGuid, &WIN10_CONTEXT_GUID)) ProcessNode->OsContextVersion = WINDOWS_10; else if (IsEqualGUID(&ProcessNode->OsContextGuid, &WINBLUE_CONTEXT_GUID)) ProcessNode->OsContextVersion = WINDOWS_8_1; From 66677fced0386dc0b213a5d94a9727e292391590 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 21 Oct 2017 04:25:36 +1100 Subject: [PATCH 0519/2058] Remove RS3 type --- phnt/include/ntldr.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/phnt/include/ntldr.h b/phnt/include/ntldr.h index 09c2f1299805..37ed1d78536b 100644 --- a/phnt/include/ntldr.h +++ b/phnt/include/ntldr.h @@ -476,13 +476,13 @@ typedef struct _PS_MITIGATION_OPTIONS_MAP union { ULONG_PTR Map[2]; // REDSTONE2 - struct - { - ULONG_PTR Depth : 16; // REDSTONE3 - ULONG_PTR Sequence : 48; - ULONG_PTR Reserved : 4; - ULONG_PTR NextEntry : 60; - }; + //struct + //{ + // ULONG_PTR Depth : 16; // REDSTONE3 + // ULONG_PTR Sequence : 48; + // ULONG_PTR Reserved : 4; + // ULONG_PTR NextEntry : 60; + //}; }; } PS_MITIGATION_OPTIONS_MAP, *PPS_MITIGATION_OPTIONS_MAP; From 56b208f13187e67c73275eb593a94e687258da46 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 21 Oct 2017 10:09:15 +1100 Subject: [PATCH 0520/2058] Fix process module highlighting regression --- ProcessHacker/modlist.c | 4 ++-- ProcessHacker/settings.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ProcessHacker/modlist.c b/ProcessHacker/modlist.c index a72a167d1f60..b6a24c56edd8 100644 --- a/ProcessHacker/modlist.c +++ b/ProcessHacker/modlist.c @@ -172,7 +172,7 @@ VOID PhLoadSettingsModuleList( PPH_STRING settings; PPH_STRING sortSettings; - flags = PhGetIntegerSetting(L"ModuleListFlags"); + flags = PhGetIntegerSetting(L"ModuleTreeListFlags"); settings = PhGetStringSetting(L"ModuleTreeListColumns"); sortSettings = PhGetStringSetting(L"ModuleTreeListSort"); @@ -192,7 +192,7 @@ VOID PhSaveSettingsModuleList( settings = PhCmSaveSettingsEx(Context->TreeNewHandle, &Context->Cm, 0, &sortSettings); - PhSetIntegerSetting(L"ModuleListFlags", Context->Flags); + PhSetIntegerSetting(L"ModuleTreeListFlags", Context->Flags); PhSetStringSetting2(L"ModuleTreeListColumns", &settings->sr); PhSetStringSetting2(L"ModuleTreeListSort", &sortSettings->sr); diff --git a/ProcessHacker/settings.c b/ProcessHacker/settings.c index 5eaf3964eeda..a9609843c868 100644 --- a/ProcessHacker/settings.c +++ b/ProcessHacker/settings.c @@ -116,7 +116,7 @@ VOID PhAddDefaultSettings( PhpAddIntegerPairSetting(L"MiniInfoWindowPosition", L"200,200"); PhpAddIntegerSetting(L"MiniInfoWindowRefreshAutomatically", L"1"); PhpAddScalableIntegerPairSetting(L"MiniInfoWindowSize", L"@96|10,200"); - PhpAddIntegerSetting(L"ModuleListFlags", L"0"); + PhpAddIntegerSetting(L"ModuleTreeListFlags", L"1"); PhpAddStringSetting(L"ModuleTreeListColumns", L""); PhpAddStringSetting(L"ModuleTreeListSort", L"0,0"); // 0, NoSortOrder PhpAddStringSetting(L"NetworkTreeListColumns", L""); From dc7bed9ac18e086e2123fc2beecd99ac3b849e1c Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 23 Oct 2017 21:17:12 +1100 Subject: [PATCH 0521/2058] Remove PhHeapHandle export --- ProcessHacker/ProcessHacker.def | 1 - 1 file changed, 1 deletion(-) diff --git a/ProcessHacker/ProcessHacker.def b/ProcessHacker/ProcessHacker.def index 51007a4e1896..b0fbedefeb2e 100644 --- a/ProcessHacker/ProcessHacker.def +++ b/ProcessHacker/ProcessHacker.def @@ -38,7 +38,6 @@ EXPORTS ; phconfig PhGlobalDpi DATA - PhHeapHandle DATA PhIsExecutingInWow64 PhInstanceHandle DATA PhOsVersion DATA From 95e6f3773eee5cd2b1cd97d6b22ad505f2a7ec99 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 23 Oct 2017 21:20:56 +1100 Subject: [PATCH 0522/2058] SetupTool: Add support for legacy commandline options --- .../CustomSetupTool/include/setup.h | 37 ++++-- tools/CustomSetupTool/CustomSetupTool/main.c | 122 +++++++++++------- .../CustomSetupTool/CustomSetupTool/update.c | 35 +++-- 3 files changed, 121 insertions(+), 73 deletions(-) diff --git a/tools/CustomSetupTool/CustomSetupTool/include/setup.h b/tools/CustomSetupTool/CustomSetupTool/include/setup.h index 204e4eaff6cf..5e025039333f 100644 --- a/tools/CustomSetupTool/CustomSetupTool/include/setup.h +++ b/tools/CustomSetupTool/CustomSetupTool/include/setup.h @@ -71,10 +71,13 @@ typedef enum _SETUP_COMMAND_TYPE SETUP_COMMAND_UNINSTALL, SETUP_COMMAND_UPDATE, SETUP_COMMAND_REPAIR, + SETUP_COMMAND_SILENTINSTALL, } SETUP_COMMAND_TYPE; typedef struct _PH_SETUP_CONTEXT { + SETUP_COMMAND_TYPE SetupMode; + HWND DialogHandle; HWND PropSheetBackHandle; HWND PropSheetForwardHandle; @@ -91,19 +94,29 @@ typedef struct _PH_SETUP_CONTEXT HICON IconSmallHandle; HICON IconLargeHandle; - PPH_STRING SetupInstallPath; - BOOLEAN SetupCreateDesktopShortcut; - BOOLEAN SetupCreateDesktopShortcutAllUsers; - BOOLEAN SetupCreateDefaultTaskManager; - BOOLEAN SetupCreateSystemStartup; - BOOLEAN SetupCreateMinimizedSystemStartup; - BOOLEAN SetupInstallDebuggingTools; - BOOLEAN SetupInstallPeViewAssociations; - BOOLEAN SetupInstallKphService; - BOOLEAN SetupResetSettings; - BOOLEAN SetupStartAppAfterExit; + union + { + ULONG Flags; + struct + { + ULONG SetupCreateDesktopShortcut : 1; + ULONG SetupCreateDesktopShortcutAllUsers : 1; + ULONG SetupCreateDefaultTaskManager : 1; + ULONG SetupCreateSystemStartup : 1; + ULONG SetupCreateMinimizedSystemStartup : 1; + ULONG SetupInstallDebuggingTools : 1; + ULONG SetupInstallPeViewAssociations : 1; + ULONG SetupInstallKphService : 1; + ULONG SetupResetSettings : 1; + ULONG SetupStartAppAfterExit : 1; + ULONG Spare : 22; + }; + }; ULONG ErrorCode; + + PPH_STRING SetupInstallPath; + PPH_STRING FilePath; PPH_STRING RelDate; @@ -263,7 +276,7 @@ BOOLEAN SetupExtractBuild( // update.c VOID SetupShowUpdateDialog( - VOID + _In_ SETUP_COMMAND_TYPE SetupMode ); // updatesetup.c diff --git a/tools/CustomSetupTool/CustomSetupTool/main.c b/tools/CustomSetupTool/CustomSetupTool/main.c index 0ef34e6c04b7..b1327e184520 100644 --- a/tools/CustomSetupTool/CustomSetupTool/main.c +++ b/tools/CustomSetupTool/CustomSetupTool/main.c @@ -43,6 +43,19 @@ BOOLEAN NTAPI MainPropSheetCommandLineCallback( { if (Option) SetupMode = Option->Id; + else + { + // HACK: PhParseCommandLine requires the - symbol for commandline parameters + // and we already support the -silent parameter however we need to maintain + // compatibility with the legacy Inno Setup. + if (!PhIsNullOrEmptyString(Value)) + { + if (PhEqualString2(Value, L"/silent", TRUE)) + { + SetupMode = SETUP_COMMAND_SILENTINSTALL; + } + } + } return TRUE; } @@ -70,7 +83,7 @@ INT CALLBACK MainPropSheet_Callback( { PPH_SETUP_CONTEXT context; - context = PhAllocate(sizeof(PH_SETUP_CONTEXT)); + context = PhCreateAlloc(sizeof(PH_SETUP_CONTEXT)); memset(context, 0, sizeof(PH_SETUP_CONTEXT)); context->CurrentMajorVersion = PHAPP_VERSION_MAJOR; @@ -171,11 +184,8 @@ VOID SetupShowInstallDialog( PhModalPropertySheet(&propSheetHeader); } -INT WINAPI wWinMain( - _In_ HINSTANCE Instance, - _In_opt_ HINSTANCE PrevInstance, - _In_ PWSTR CmdLine, - _In_ INT CmdShow +VOID SetupParseCommandLine( + VOID ) { static PH_COMMAND_LINE_OPTION options[] = @@ -184,67 +194,79 @@ INT WINAPI wWinMain( { SETUP_COMMAND_UNINSTALL, L"uninstall", NoArgumentType }, { SETUP_COMMAND_UPDATE, L"update", NoArgumentType }, { SETUP_COMMAND_REPAIR, L"repair", NoArgumentType }, + { SETUP_COMMAND_SILENTINSTALL, L"silent", NoArgumentType }, }; - HANDLE mutantHandle; PPH_STRING commandLine; - OBJECT_ATTRIBUTES oa; - UNICODE_STRING mutantName; - CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE); - - if (!NT_SUCCESS(PhInitializePhLibEx(ULONG_MAX, Instance, 0, 0))) - return 1; - - PhApplicationName = L"Process Hacker - Setup"; - PhGuiSupportInitialization(); - SetupInitializeDpi(); - - if (!NT_SUCCESS(PhGetProcessCommandLine(NtCurrentProcess(), &commandLine))) - return 1; - - if (!PhParseCommandLine( - &commandLine->sr, - options, - ARRAYSIZE(options), - PH_COMMAND_LINE_IGNORE_FIRST_PART, - MainPropSheetCommandLineCallback, - NULL - )) + if (NT_SUCCESS(PhGetProcessCommandLine(NtCurrentProcess(), &commandLine))) { + PhParseCommandLine( + &commandLine->sr, + options, + ARRAYSIZE(options), + PH_COMMAND_LINE_IGNORE_UNKNOWN_OPTIONS | PH_COMMAND_LINE_IGNORE_FIRST_PART, + MainPropSheetCommandLineCallback, + NULL + ); + PhDereferenceObject(commandLine); - return 1; } +} - PhDereferenceObject(commandLine); +VOID SetupInitializeMutant( + VOID + ) +{ + HANDLE mutantHandle; + OBJECT_ATTRIBUTES oa; + UNICODE_STRING mutantName; RtlInitUnicodeString(&mutantName, L"PhSetupMutant"); InitializeObjectAttributes( &oa, &mutantName, - 0, + OBJ_CASE_INSENSITIVE, PhGetNamespaceHandle(), NULL ); - if (NT_SUCCESS(NtCreateMutant(&mutantHandle, MUTANT_ALL_ACCESS, &oa, FALSE))) - { - switch (SetupMode) - { - case SETUP_COMMAND_INSTALL: - default: - SetupShowInstallDialog(); - break; - case SETUP_COMMAND_UNINSTALL: - SetupShowUninstallDialog(); - break; - case SETUP_COMMAND_UPDATE: - SetupShowUpdateDialog(); - break; - case SETUP_COMMAND_REPAIR: - break; - } + NtCreateMutant(&mutantHandle, MUTANT_ALL_ACCESS, &oa, FALSE); +} - NtClose(mutantHandle); +INT WINAPI wWinMain( + _In_ HINSTANCE Instance, + _In_opt_ HINSTANCE PrevInstance, + _In_ PWSTR CmdLine, + _In_ INT CmdShow + ) +{ + CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE); + + if (!NT_SUCCESS(PhInitializePhLibEx(ULONG_MAX, Instance, 0, 0))) + return 1; + + PhApplicationName = L"Process Hacker - Setup"; + PhGuiSupportInitialization(); + SetupInitializeDpi(); + + SetupInitializeMutant(); + SetupParseCommandLine(); + + switch (SetupMode) + { + case SETUP_COMMAND_INSTALL: + default: + SetupShowInstallDialog(); + break; + case SETUP_COMMAND_UNINSTALL: + SetupShowUninstallDialog(); + break; + case SETUP_COMMAND_UPDATE: + case SETUP_COMMAND_SILENTINSTALL: + SetupShowUpdateDialog(SetupMode); + break; + case SETUP_COMMAND_REPAIR: + break; } return ERROR_SUCCESS; diff --git a/tools/CustomSetupTool/CustomSetupTool/update.c b/tools/CustomSetupTool/CustomSetupTool/update.c index 43ea2e386524..47f46f81e0ce 100644 --- a/tools/CustomSetupTool/CustomSetupTool/update.c +++ b/tools/CustomSetupTool/CustomSetupTool/update.c @@ -68,7 +68,7 @@ NTSTATUS SetupUpdateBuild( } PPH_SETUP_CONTEXT CreateUpdateContext( - VOID + _In_ SETUP_COMMAND_TYPE SetupMode ) { PPH_SETUP_CONTEXT context; @@ -76,6 +76,8 @@ PPH_SETUP_CONTEXT CreateUpdateContext( context = (PPH_SETUP_CONTEXT)PhCreateAlloc(sizeof(PH_SETUP_CONTEXT)); memset(context, 0, sizeof(PH_SETUP_CONTEXT)); + context->SetupMode = SetupMode; + return context; } @@ -236,12 +238,25 @@ VOID SetupShowUpdatingDialog( config.pfCallback = SetupUpdatingTaskDialogCallbackProc; config.lpCallbackData = (LONG_PTR)Context; config.pszWindowTitle = PhApplicationName; - config.pszMainInstruction = PhaFormatString( - L"Updating to version %lu.%lu.%lu...", - PHAPP_VERSION_MAJOR, - PHAPP_VERSION_MINOR, - PHAPP_VERSION_REVISION - )->Buffer; + + if (Context->SetupMode = SETUP_COMMAND_SILENTINSTALL) + { + config.pszMainInstruction = PhaFormatString( + L"Installing Process Hacker %lu.%lu.%lu...", + PHAPP_VERSION_MAJOR, + PHAPP_VERSION_MINOR, + PHAPP_VERSION_REVISION + )->Buffer; + } + else + { + config.pszMainInstruction = PhaFormatString( + L"Updating to version %lu.%lu.%lu...", + PHAPP_VERSION_MAJOR, + PHAPP_VERSION_MINOR, + PHAPP_VERSION_REVISION + )->Buffer; + } SendMessage(Context->DialogHandle, TDM_NAVIGATE_PAGE, 0, (LPARAM)&config); } @@ -280,10 +295,9 @@ HRESULT CALLBACK TaskDialogBootstrapCallback( } VOID SetupShowUpdateDialog( - VOID + _In_ SETUP_COMMAND_TYPE SetupMode ) { - PVOID context; TASKDIALOGCONFIG config; PH_AUTO_POOL autoPool; @@ -291,13 +305,12 @@ VOID SetupShowUpdateDialog( PhInitializeAutoPool(&autoPool); - context = CreateUpdateContext(); config.cbSize = sizeof(TASKDIALOGCONFIG); config.dwFlags = TDF_POSITION_RELATIVE_TO_WINDOW; config.dwCommonButtons = TDCBF_CANCEL_BUTTON; config.pszWindowTitle = PhApplicationName; config.pfCallback = TaskDialogBootstrapCallback; - config.lpCallbackData = (LONG_PTR)context; + config.lpCallbackData = (LONG_PTR)CreateUpdateContext(SetupMode); TaskDialogIndirect(&config, NULL, NULL, NULL); From c759e7d2cd2690dc6be572e0f50876b32978eb7d Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 23 Oct 2017 21:21:17 +1100 Subject: [PATCH 0523/2058] StartTool: Update SDK --- tools/CustomStartTool/CustomStartTool.vcxproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/CustomStartTool/CustomStartTool.vcxproj b/tools/CustomStartTool/CustomStartTool.vcxproj index 787cb050f1df..202dc4bc4471 100644 --- a/tools/CustomStartTool/CustomStartTool.vcxproj +++ b/tools/CustomStartTool/CustomStartTool.vcxproj @@ -22,7 +22,7 @@ {E8CD0A41-1537-4EA6-98AC-E80CD59C478E} CustomStartTool Win32Proj - 10.0.15063.0 + 10.0.16299.0 From 9dd7e4291a8fd35920ae82da5849b70571eb3fdc Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 23 Oct 2017 21:24:21 +1100 Subject: [PATCH 0524/2058] Improve SDK gui support initialization --- ProcessHacker/include/phapp.h | 2 +- ProcessHacker/main.c | 18 ++---------------- ProcessHacker/mainwnd.c | 2 +- phlib/guisup.c | 11 +++++++++-- 4 files changed, 13 insertions(+), 20 deletions(-) diff --git a/ProcessHacker/include/phapp.h b/ProcessHacker/include/phapp.h index a23878fd7ae5..ab2ee920e15f 100644 --- a/ProcessHacker/include/phapp.h +++ b/ProcessHacker/include/phapp.h @@ -131,7 +131,7 @@ PhUnregisterMessageLoopFilter( // end_phapppub VOID PhInitializeFont( - _In_ HWND hWnd + VOID ); // plugin diff --git a/ProcessHacker/main.c b/ProcessHacker/main.c index 2f42307995e5..3381dfd1f705 100644 --- a/ProcessHacker/main.c +++ b/ProcessHacker/main.c @@ -486,31 +486,17 @@ VOID PhInitializeCommonControls( } VOID PhInitializeFont( - _In_ HWND hWnd + VOID ) { NONCLIENTMETRICS metrics = { sizeof(metrics) }; - BOOLEAN success; - HDC hdc; - - if (hdc = GetDC(hWnd)) - { - PhGlobalDpi = GetDeviceCaps(hdc, LOGPIXELSY); - ReleaseDC(hWnd, hdc); - } - else - { - PhGlobalDpi = 96; - } - - success = !!SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, &metrics, 0); if ( !(PhApplicationFont = PhCreateFont(L"Microsoft Sans Serif", 8, FW_NORMAL)) && !(PhApplicationFont = PhCreateFont(L"Tahoma", 8, FW_NORMAL)) ) { - if (success) + if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, &metrics, 0)) PhApplicationFont = CreateFontIndirect(&metrics.lfMessageFont); else PhApplicationFont = NULL; diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index fa80643d7f64..d53367b77ed8 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -528,7 +528,7 @@ VOID PhMwpOnSettingChange( if (PhApplicationFont) DeleteObject(PhApplicationFont); - PhInitializeFont(PhMainWndHandle); + PhInitializeFont(); SendMessage(TabControlHandle, WM_SETFONT, (WPARAM)PhApplicationFont, FALSE); } diff --git a/phlib/guisup.c b/phlib/guisup.c index 4871ac46d1ec..c27f2bce0957 100644 --- a/phlib/guisup.c +++ b/phlib/guisup.c @@ -43,8 +43,15 @@ VOID PhGuiSupportInitialization( VOID ) { - HMODULE shell32Handle; - HMODULE shlwapiHandle; + HDC hdc; + PVOID shell32Handle; + PVOID shlwapiHandle; + + if (hdc = CreateIC(L"DISPLAY", NULL, NULL, NULL)) + { + PhGlobalDpi = GetDeviceCaps(hdc, LOGPIXELSY); + DeleteDC(hdc); + } shell32Handle = LoadLibrary(L"shell32.dll"); shlwapiHandle = LoadLibrary(L"shlwapi.dll"); From 60293b2cfd3498dcb9ea450ee5a9cb5bcba29cf7 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 23 Oct 2017 21:26:12 +1100 Subject: [PATCH 0525/2058] HardwareDevices: Remove unused code --- plugins/HardwareDevices/disknotify.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/plugins/HardwareDevices/disknotify.c b/plugins/HardwareDevices/disknotify.c index f212a04d456a..f4025a6cc345 100644 --- a/plugins/HardwareDevices/disknotify.c +++ b/plugins/HardwareDevices/disknotify.c @@ -77,16 +77,11 @@ LRESULT CALLBACK MainWndDevicesSubclassProc( } } } - - goto DefaultWndProc; } break; } return DefSubclassProc(hWnd, uMsg, wParam, lParam); - -DefaultWndProc: - return DefWindowProc(hWnd, uMsg, wParam, lParam); } VOID AddRemoveDeviceChangeCallback( From a6ad02b4b96759c31777e7e0805251c83af7cdb2 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 23 Oct 2017 21:26:55 +1100 Subject: [PATCH 0526/2058] peview: Remove duplicate SDK gui support initialization --- tools/peview/main.c | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/tools/peview/main.c b/tools/peview/main.c index 87404e5258c6..2338bf6d2a59 100644 --- a/tools/peview/main.c +++ b/tools/peview/main.c @@ -37,19 +37,6 @@ static BOOLEAN NTAPI PvCommandLineCallback( return TRUE; } -static VOID PvpInitializeDpi( - VOID - ) -{ - HDC hdc; - - if (hdc = CreateIC(L"DISPLAY", NULL, NULL, NULL)) - { - PhGlobalDpi = GetDeviceCaps(hdc, LOGPIXELSY); - DeleteDC(hdc); - } -} - INT WINAPI wWinMain( _In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, @@ -69,7 +56,6 @@ INT WINAPI wWinMain( return 1; PhGuiSupportInitialization(); - PvpInitializeDpi(); PhSettingsInitialization(); PeInitializeSettings(); PvPropInitialization(); From 4d62221d6ab34d4bc029b44eb08049c5a4533145 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 26 Oct 2017 14:11:46 +1100 Subject: [PATCH 0527/2058] Fix RS3 type, Add JobObject comments --- phnt/include/ntexapi.h | 2 +- phnt/include/ntpsapi.h | 57 +++++++++++++++++++++--------------------- 2 files changed, 30 insertions(+), 29 deletions(-) diff --git a/phnt/include/ntexapi.h b/phnt/include/ntexapi.h index dcdad9fc1ba5..595381753cec 100644 --- a/phnt/include/ntexapi.h +++ b/phnt/include/ntexapi.h @@ -2937,7 +2937,7 @@ typedef struct _SYSTEM_SECUREBOOT_POLICY_FULL_INFORMATION typedef struct _SYSTEM_ROOT_SILO_INFORMATION { ULONG NumberOfSilos; - HANDLE SiloIdList[1]; + ULONG SiloIdList[1]; } SYSTEM_ROOT_SILO_INFORMATION, *PSYSTEM_ROOT_SILO_INFORMATION; // private diff --git a/phnt/include/ntpsapi.h b/phnt/include/ntpsapi.h index 205d892c7f7a..513505172b0b 100644 --- a/phnt/include/ntpsapi.h +++ b/phnt/include/ntpsapi.h @@ -1624,52 +1624,53 @@ NtCreateThreadEx( #if (PHNT_MODE != PHNT_MODE_KERNEL) // JOBOBJECTINFOCLASS -#define JobObjectBasicAccountingInformation 1 -#define JobObjectBasicLimitInformation 2 -#define JobObjectBasicProcessIdList 3 -#define JobObjectBasicUIRestrictions 4 -#define JobObjectSecurityLimitInformation 5 -#define JobObjectEndOfJobTimeInformation 6 -#define JobObjectAssociateCompletionPortInformation 7 -#define JobObjectBasicAndIoAccountingInformation 8 -#define JobObjectExtendedLimitInformation 9 -#define JobObjectJobSetInformation 10 -#define JobObjectGroupInformation 11 -#define JobObjectNotificationLimitInformation 12 -#define JobObjectLimitViolationInformation 13 -#define JobObjectGroupInformationEx 14 -#define JobObjectCpuRateControlInformation 15 +// Note: We don't use an enum since it conflicts with the Windows SDK. +#define JobObjectBasicAccountingInformation 1 // JOBOBJECT_BASIC_ACCOUNTING_INFORMATION +#define JobObjectBasicLimitInformation 2 // JOBOBJECT_BASIC_LIMIT_INFORMATION +#define JobObjectBasicProcessIdList 3 // JOBOBJECT_BASIC_PROCESS_ID_LIST +#define JobObjectBasicUIRestrictions 4 // JOBOBJECT_BASIC_UI_RESTRICTIONS +#define JobObjectSecurityLimitInformation 5 // JOBOBJECT_SECURITY_LIMIT_INFORMATION +#define JobObjectEndOfJobTimeInformation 6 // JOBOBJECT_END_OF_JOB_TIME_INFORMATION +#define JobObjectAssociateCompletionPortInformation 7 // JOBOBJECT_ASSOCIATE_COMPLETION_PORT +#define JobObjectBasicAndIoAccountingInformation 8 // JOBOBJECT_BASIC_AND_IO_ACCOUNTING_INFORMATION +#define JobObjectExtendedLimitInformation 9 // JOBOBJECT_EXTENDED_LIMIT_INFORMATION +#define JobObjectJobSetInformation 10 // JOBOBJECT_JOBSET_INFORMATION +#define JobObjectGroupInformation 11 // USHORT +#define JobObjectNotificationLimitInformation 12 // JOBOBJECT_NOTIFICATION_LIMIT_INFORMATION +#define JobObjectLimitViolationInformation 13 // JOBOBJECT_LIMIT_VIOLATION_INFORMATION +#define JobObjectGroupInformationEx 14 // GROUP_AFFINITY (ARRAY) +#define JobObjectCpuRateControlInformation 15 // JOBOBJECT_CPU_RATE_CONTROL_INFORMATION #define JobObjectCompletionFilter 16 #define JobObjectCompletionCounter 17 -#define JobObjectFreezeInformation 18 -#define JobObjectExtendedAccountingInformation 19 -#define JobObjectWakeInformation 20 +#define JobObjectFreezeInformation 18 // JOBOBJECT_FREEZE_INFORMATION +#define JobObjectExtendedAccountingInformation 19 // JOBOBJECT_EXTENDED_ACCOUNTING_INFORMATION +#define JobObjectWakeInformation 20 // JOBOBJECT_WAKE_INFORMATION #define JobObjectBackgroundInformation 21 #define JobObjectSchedulingRankBiasInformation 22 #define JobObjectTimerVirtualizationInformation 23 #define JobObjectCycleTimeNotification 24 #define JobObjectClearEvent 25 -#define JobObjectInterferenceInformation 26 +#define JobObjectInterferenceInformation 26 // JOBOBJECT_INTERFERENCE_INFORMATION #define JobObjectClearPeakJobMemoryUsed 27 -#define JobObjectMemoryUsageInformation 28 +#define JobObjectMemoryUsageInformation 28 // JOBOBJECT_MEMORY_USAGE_INFORMATION // JOBOBJECT_MEMORY_USAGE_INFORMATION_V2 #define JobObjectSharedCommit 29 #define JobObjectContainerId 30 #define JobObjectIoRateControlInformation 31 -#define JobObjectNetRateControlInformation 32 -#define JobObjectNotificationLimitInformation2 33 -#define JobObjectLimitViolationInformation2 34 +#define JobObjectNetRateControlInformation 32 // JOBOBJECT_NET_RATE_CONTROL_INFORMATION +#define JobObjectNotificationLimitInformation2 33 // JOBOBJECT_NOTIFICATION_LIMIT_INFORMATION_2 +#define JobObjectLimitViolationInformation2 34 // JOBOBJECT_LIMIT_VIOLATION_INFORMATION_2 #define JobObjectCreateSilo 35 -#define JobObjectSiloBasicInformation 36 -#define JobObjectSiloRootDirectory 37 -#define JobObjectServerSiloBasicInformation 38 -#define JobObjectServerSiloUserSharedData 39 +#define JobObjectSiloBasicInformation 36 // SILOOBJECT_BASIC_INFORMATION +#define JobObjectSiloRootDirectory 37 // SILOOBJECT_ROOT_DIRECTORY +#define JobObjectServerSiloBasicInformation 38 // SERVERSILO_BASIC_INFORMATION +#define JobObjectServerSiloUserSharedData 39 // SILO_USER_SHARED_DATA #define JobObjectServerSiloInitialize 40 #define JobObjectServerSiloRunningState 41 #define JobObjectIoAttribution 42 #define JobObjectMemoryPartitionInformation 43 #define JobObjectContainerTelemetryId 44 #define JobObjectSiloSystemRoot 45 -#define JobObjectEnergyTrackingState 46 +#define JobObjectEnergyTrackingState 46 // JOBOBJECT_ENERGY_TRACKING_STATE #define JobObjectThreadImpersonationInformation 47 #define MaxJobObjectInfoClass 48 From f05b831d5ba769ad209bf4dbe05e754644d99267 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 26 Oct 2017 14:16:33 +1100 Subject: [PATCH 0528/2058] Adjust sysinfo graph padding, Fix sysinfo fullscreen (F11) bleeding through multiple-monitors --- ProcessHacker/include/sysinfop.h | 4 ++-- ProcessHacker/sysinfo.c | 9 ++++----- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/ProcessHacker/include/sysinfop.h b/ProcessHacker/include/sysinfop.h index ccd8b02fd1df..2428889df949 100644 --- a/ProcessHacker/include/sysinfop.h +++ b/ProcessHacker/include/sysinfop.h @@ -5,8 +5,8 @@ #define PH_SYSINFO_FADE_ADD 50 #define PH_SYSINFO_PANEL_PADDING 3 -#define PH_SYSINFO_WINDOW_PADDING 13 -#define PH_SYSINFO_GRAPH_PADDING 9 +#define PH_SYSINFO_WINDOW_PADDING 7 +#define PH_SYSINFO_GRAPH_PADDING 4 #define PH_SYSINFO_SMALL_GRAPH_WIDTH 48 #define PH_SYSINFO_SMALL_GRAPH_PADDING 5 #define PH_SYSINFO_SEPARATOR_WIDTH 2 diff --git a/ProcessHacker/sysinfo.c b/ProcessHacker/sysinfo.c index 55513f538b9a..d756db5111b8 100644 --- a/ProcessHacker/sysinfo.c +++ b/ProcessHacker/sysinfo.c @@ -580,15 +580,14 @@ VOID PhSipOnCommand( GetMonitorInfo(MonitorFromWindow(PhSipWindow, MONITOR_DEFAULTTOPRIMARY), &info) ) { - ULONG padding = CurrentParameters.WindowPadding / 2; PhSetWindowStyle(PhSipWindow, WS_OVERLAPPEDWINDOW, 0); SetWindowPos( PhSipWindow, HWND_TOPMOST, - info.rcMonitor.left - padding, - info.rcMonitor.top - padding, - (info.rcMonitor.right - info.rcMonitor.left) + padding * 2, - (info.rcMonitor.bottom - info.rcMonitor.top) + padding * 2, + info.rcMonitor.left, + info.rcMonitor.top, + (info.rcMonitor.right - info.rcMonitor.left), + (info.rcMonitor.bottom - info.rcMonitor.top), SWP_NOOWNERZORDER | SWP_FRAMECHANGED ); } From ffb626cf0c5569590dc9dcafc4af75184b12c8aa Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 26 Oct 2017 16:36:44 +1100 Subject: [PATCH 0529/2058] Fix sysinfo fullscreen topmost bug --- ProcessHacker/sysinfo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ProcessHacker/sysinfo.c b/ProcessHacker/sysinfo.c index d756db5111b8..509a4b75a5ec 100644 --- a/ProcessHacker/sysinfo.c +++ b/ProcessHacker/sysinfo.c @@ -596,7 +596,7 @@ VOID PhSipOnCommand( { PhSetWindowStyle(PhSipWindow, WS_OVERLAPPEDWINDOW, WS_OVERLAPPEDWINDOW); SetWindowPlacement(PhSipWindow, &windowLayout); - SetWindowPos(PhSipWindow, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_FRAMECHANGED); + SetWindowPos(PhSipWindow, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOOWNERZORDER | SWP_FRAMECHANGED); } } break; From f525b448d9289b5c64173326c142611651d386dc Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 30 Oct 2017 00:39:15 +1100 Subject: [PATCH 0530/2058] KPH: Fix macro usage --- KProcessHacker/dyndata.c | 6 ++---- KProcessHacker/include/kph.h | 9 +++++++++ KProcessHacker/object.c | 20 ++++++++++---------- KProcessHacker/qrydrv.c | 2 +- 4 files changed, 22 insertions(+), 15 deletions(-) diff --git a/KProcessHacker/dyndata.c b/KProcessHacker/dyndata.c index ff685369570b..be90cda839b0 100644 --- a/KProcessHacker/dyndata.c +++ b/KProcessHacker/dyndata.c @@ -23,8 +23,6 @@ #define _DYNDATA_PRIVATE #include -#define C_2sTo4(x) ((unsigned int)(signed short)(x)) - NTSTATUS KphpLoadDynamicConfiguration( _In_ PVOID Buffer, _In_ ULONG Length @@ -126,13 +124,13 @@ NTSTATUS KphpLoadDynamicConfiguration( config = Buffer; - if (Length < (ULONG)FIELD_OFFSET(KPH_DYN_CONFIGURATION, Packages)) + if (Length < UFIELD_OFFSET(KPH_DYN_CONFIGURATION, Packages)) return STATUS_INVALID_PARAMETER; if (config->Version != KPH_DYN_CONFIGURATION_VERSION) return STATUS_INVALID_PARAMETER; if (config->NumberOfPackages > KPH_DYN_MAXIMUM_PACKAGES) return STATUS_INVALID_PARAMETER; - if (Length < (ULONG)FIELD_OFFSET(KPH_DYN_CONFIGURATION, Packages) + config->NumberOfPackages * sizeof(KPH_DYN_PACKAGE)) + if (Length < UFIELD_OFFSET(KPH_DYN_CONFIGURATION, Packages) + config->NumberOfPackages * sizeof(KPH_DYN_PACKAGE)) return STATUS_INVALID_PARAMETER; dprintf("Loading dynamic configuration with %u package(s)\n", config->NumberOfPackages); diff --git a/KProcessHacker/include/kph.h b/KProcessHacker/include/kph.h index 4c5032411cf1..2afa4a4fc84a 100644 --- a/KProcessHacker/include/kph.h +++ b/KProcessHacker/include/kph.h @@ -8,6 +8,15 @@ #include #include +// Memory + +#define PTR_ADD_OFFSET(Pointer, Offset) ((PVOID)((ULONG_PTR)(Pointer) + (ULONG_PTR)(Offset))) +#define PTR_SUB_OFFSET(Pointer, Offset) ((PVOID)((ULONG_PTR)(Pointer) - (ULONG_PTR)(Offset))) + +// Zero extension and sign extension macros + +#define C_2sTo4(x) ((unsigned int)(signed short)(x)) + // Debugging #ifdef DBG diff --git a/KProcessHacker/object.c b/KProcessHacker/object.c index 134a4d36e6db..704fd90dea58 100644 --- a/KProcessHacker/object.c +++ b/KProcessHacker/object.c @@ -91,7 +91,7 @@ PHANDLE_TABLE KphReferenceProcessHandleTable( // Prevent the process from terminating and get its handle table. if (NT_SUCCESS(PsAcquireProcessExitSynchronization(Process))) { - handleTable = *(PHANDLE_TABLE *)((ULONG_PTR)Process + KphDynEpObjectTable); + handleTable = *(PHANDLE_TABLE *)PTR_ADD_OFFSET(Process, KphDynEpObjectTable); if (!handleTable) PsReleaseProcessExitSynchronization(Process); @@ -133,7 +133,7 @@ VOID KphUnlockHandleTableEntry( // Allow waiters to wake up. - handleContentionEvent = (PEX_PUSH_LOCK)((ULONG_PTR)HandleTable + KphDynHtHandleContentionEvent); + handleContentionEvent = (PEX_PUSH_LOCK)PTR_ADD_OFFSET(HandleTable, KphDynHtHandleContentionEvent); if (*(PULONG_PTR)handleContentionEvent != 0) ExfUnblockPushLock(handleContentionEvent, NULL); @@ -167,13 +167,13 @@ BOOLEAN KphpEnumerateProcessHandlesEnumCallback61( objectType = ObGetObjectType(handleInfo.Object); if (objectType && KphDynOtIndex != -1) - handleInfo.ObjectTypeIndex = (USHORT)*(PUCHAR)((ULONG_PTR)objectType + KphDynOtIndex); + handleInfo.ObjectTypeIndex = (USHORT)*(PUCHAR)PTR_ADD_OFFSET(objectType, KphDynOtIndex); } // Advance the current entry pointer regardless of whether the information will be written; this // will allow the parent function to report the correct return length. entryInBuffer = context->CurrentEntry; - context->CurrentEntry = (PVOID)((ULONG_PTR)context->CurrentEntry + sizeof(KPH_PROCESS_HANDLE)); + context->CurrentEntry = PTR_ADD_OFFSET(context->CurrentEntry, sizeof(KPH_PROCESS_HANDLE)); context->Count++; // Only write if we have not exceeded the buffer length. Also check for a potential overflow (if @@ -291,7 +291,7 @@ NTSTATUS KpiEnumerateProcessHandles( // Initialize the enumeration context. context.Buffer = Buffer; - context.BufferLimit = (PVOID)((ULONG_PTR)Buffer + BufferLength); + context.BufferLimit = PTR_ADD_OFFSET(Buffer, BufferLength); context.CurrentEntry = ((PKPH_PROCESS_HANDLE_INFORMATION)Buffer)->Handles; context.Count = 0; context.Status = STATUS_SUCCESS; @@ -321,7 +321,7 @@ NTSTATUS KpiEnumerateProcessHandles( ObDereferenceObject(process); // Write the number of handles if we can. - if (BufferLength >= (ULONG)FIELD_OFFSET(KPH_PROCESS_HANDLE_INFORMATION, Handles)) + if (BufferLength >= UFIELD_OFFSET(KPH_PROCESS_HANDLE_INFORMATION, Handles)) { if (AccessMode != KernelMode) { @@ -455,7 +455,7 @@ NTSTATUS KphQueryNameFileObject( // Assume failure. Buffer->Name.Length = 0; // We will place the object name directly after the UNICODE_STRING structure in the buffer. - Buffer->Name.Buffer = (PWSTR)((ULONG_PTR)Buffer + sizeof(OBJECT_NAME_INFORMATION)); + Buffer->Name.Buffer = (PWSTR)PTR_ADD_OFFSET(Buffer, sizeof(OBJECT_NAME_INFORMATION)); // Retain a local pointer to the object name so we can manipulate the pointer. objectName = (PCHAR)Buffer->Name.Buffer; // A variable that keeps track of how much space we have used. @@ -943,7 +943,7 @@ NTSTATUS KpiQueryInformationObject( if (objectType) { - objectTypeName = (PUNICODE_STRING)((ULONG_PTR)objectType + KphDynOtName); + objectTypeName = (PUNICODE_STRING)PTR_ADD_OFFSET(objectType, KphDynOtName); RtlInitUnicodeString(&etwRegistrationName, L"EtwRegistration"); if (!RtlEqualUnicodeString(objectTypeName, &etwRegistrationName, FALSE)) @@ -958,10 +958,10 @@ NTSTATUS KpiQueryInformationObject( if (NT_SUCCESS(status)) { - guidEntry = *(PVOID *)((ULONG_PTR)etwReg + KphDynEreGuidEntry); + guidEntry = *(PVOID *)PTR_ADD_OFFSET(etwReg, KphDynEreGuidEntry); if (guidEntry) - basicInfo.Guid = *(GUID *)((ULONG_PTR)guidEntry + KphDynEgeGuid); + basicInfo.Guid = *(GUID *)PTR_ADD_OFFSET(guidEntry, KphDynEgeGuid); else memset(&basicInfo.Guid, 0, sizeof(GUID)); diff --git a/KProcessHacker/qrydrv.c b/KProcessHacker/qrydrv.c index 641779fa0a52..cc3879e0e3fb 100644 --- a/KProcessHacker/qrydrv.c +++ b/KProcessHacker/qrydrv.c @@ -222,7 +222,7 @@ VOID KphpCopyInfoUnicodeString( if (UnicodeString) { - targetBuffer = (PWCHAR)((PCHAR)Information + sizeof(UNICODE_STRING)); + targetBuffer = (PWCHAR)PTR_ADD_OFFSET(Information, sizeof(UNICODE_STRING)); targetUnicodeString->Length = UnicodeString->Length; targetUnicodeString->MaximumLength = UnicodeString->Length; From 1e60fa3d87bf8c5df39aad276d2e58a93ba51b3c Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 31 Oct 2017 06:07:17 +1100 Subject: [PATCH 0531/2058] Fix hexedit control scrolling bug (If one line of text is off the screen you cannot scroll down to it - Raymond Lee) --- phlib/hexedit.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/phlib/hexedit.c b/phlib/hexedit.c index 82c1d614d83f..8e6fb97cff83 100644 --- a/phlib/hexedit.c +++ b/phlib/hexedit.c @@ -3,6 +3,7 @@ * hex editor control * * Copyright (C) 2010-2015 wj32 + * Copyright (C) 2017 dmex * * This file is part of Process Hacker. * @@ -1289,12 +1290,12 @@ VOID PhpHexEditUpdateScrollbars( si.fMask = SIF_ALL; si.nMin = 0; - si.nMax = (Context->Length / Context->BytesPerRow) - 1; + si.nMax = Context->Length / Context->BytesPerRow; si.nPage = Context->LinesPerPage; si.nPos = Context->TopIndex / Context->BytesPerRow; SetScrollInfo(hwnd, SB_VERT, &si, TRUE); - if (si.nMax > (LONG)si.nPage) + if (si.nMax > (LONG)si.nPage - 1) EnableScrollBar(hwnd, SB_VERT, ESB_ENABLE_BOTH); // No horizontal scrollbar please. From 8d296ddfdec5d0f34299bc3f2415586e93c1f490 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 31 Oct 2017 06:36:35 +1100 Subject: [PATCH 0532/2058] Fix hexedit control pagedown scrolling bug, Add missing hexedit scrolbar right-click options --- phlib/hexedit.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/phlib/hexedit.c b/phlib/hexedit.c index 8e6fb97cff83..909e020d8c55 100644 --- a/phlib/hexedit.c +++ b/phlib/hexedit.c @@ -211,10 +211,15 @@ LRESULT CALLBACK PhpHexEditWndProc( case SB_PAGEDOWN: if (context->TopIndex < context->Length - mult) { + LONG pageEnd = 0; + + while (pageEnd < context->Length - mult) + pageEnd += context->BytesPerRow; + context->TopIndex += mult; - if (context->TopIndex > context->Length - mult) - context->TopIndex = context->Length - mult; + if (context->TopIndex > pageEnd) + context->TopIndex = pageEnd; REDRAW_WINDOW(hwnd); } @@ -234,6 +239,15 @@ LRESULT CALLBACK PhpHexEditWndProc( context->TopIndex = currentPosition * context->BytesPerRow; REDRAW_WINDOW(hwnd); break; + case SB_TOP: + context->TopIndex = 0; + REDRAW_WINDOW(hwnd); + break; + case SB_BOTTOM: + while (context->TopIndex < context->Length - mult) + context->TopIndex += context->BytesPerRow; + REDRAW_WINDOW(hwnd); + break; } SetScrollPos(hwnd, SB_VERT, context->TopIndex / context->BytesPerRow, TRUE); From 6a7c7dcb33c5b1a93592bcf615b8c3248e1f7b65 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 31 Oct 2017 08:10:07 +1100 Subject: [PATCH 0533/2058] Fix macro usage --- phlib/include/mapimg.h | 2 +- phlib/mapimg.c | 21 +++++++-------------- 2 files changed, 8 insertions(+), 15 deletions(-) diff --git a/phlib/include/mapimg.h b/phlib/include/mapimg.h index ba179e8ca83d..8590b1b50f67 100644 --- a/phlib/include/mapimg.h +++ b/phlib/include/mapimg.h @@ -79,7 +79,7 @@ BOOLEAN NTAPI PhGetMappedImageSectionName( _In_ PIMAGE_SECTION_HEADER Section, - _Out_writes_opt_z_(Count) PSTR Buffer, + _Out_writes_opt_z_(Count) PWSTR Buffer, _In_ ULONG Count, _Out_opt_ PULONG ReturnCount ); diff --git a/phlib/mapimg.c b/phlib/mapimg.c index 9210e2e351c9..aa000600495b 100644 --- a/phlib/mapimg.c +++ b/phlib/mapimg.c @@ -117,11 +117,7 @@ NTSTATUS PhInitializeMappedImage( // Get a pointer to the first section. MappedImage->NumberOfSections = MappedImage->NtHeaders->FileHeader.NumberOfSections; - - MappedImage->Sections = (PIMAGE_SECTION_HEADER)( - ((PCHAR)&MappedImage->NtHeaders->OptionalHeader) + - MappedImage->NtHeaders->FileHeader.SizeOfOptionalHeader - ); + MappedImage->Sections = IMAGE_FIRST_SECTION(MappedImage->NtHeaders); return STATUS_SUCCESS; } @@ -153,7 +149,7 @@ NTSTATUS PhLoadMappedImage( if (!NT_SUCCESS(status)) { - NtUnmapViewOfSection(NtCurrentProcess(), MappedImage->ViewBase); + PhUnloadMappedImage(MappedImage); } } @@ -307,8 +303,8 @@ PVOID PhMappedImageRvaToVa( if (Section) *Section = section; - return (PVOID)( - (ULONG_PTR)MappedImage->ViewBase + + return PTR_ADD_OFFSET( + MappedImage->ViewBase, (Rva - section->VirtualAddress) + section->PointerToRawData ); @@ -316,7 +312,7 @@ PVOID PhMappedImageRvaToVa( BOOLEAN PhGetMappedImageSectionName( _In_ PIMAGE_SECTION_HEADER Section, - _Out_writes_opt_z_(Count) PSTR Buffer, + _Out_writes_opt_z_(Count) PWSTR Buffer, _In_ ULONG Count, _Out_opt_ PULONG ReturnCount ) @@ -324,7 +320,7 @@ BOOLEAN PhGetMappedImageSectionName( BOOLEAN result; SIZE_T returnCount; - result = PhCopyBytesZ( + result = PhCopyStringZFromBytes( Section->Name, IMAGE_SIZEOF_SHORT_NAME, Buffer, @@ -525,10 +521,7 @@ NTSTATUS PhLoadRemoteMappedImage( return status; } - RemoteMappedImage->Sections = (PIMAGE_SECTION_HEADER)( - (PCHAR)RemoteMappedImage->NtHeaders + - FIELD_OFFSET(IMAGE_NT_HEADERS, OptionalHeader) + ntHeaders.FileHeader.SizeOfOptionalHeader - ); + RemoteMappedImage->Sections = IMAGE_FIRST_SECTION(RemoteMappedImage->NtHeaders); return STATUS_SUCCESS; } From 89b0f55f35d88c544afeab5172b6f4dc15886067 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 2 Nov 2017 10:06:56 +1100 Subject: [PATCH 0534/2058] Remove casts, Fix macro usage --- ProcessHacker/memprv.c | 2 +- ProcessHacker/phsvc/svcapi.c | 2 +- phlib/mapimg.c | 16 ++++++++-------- tools/peview/ldprp.c | 6 +++--- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/ProcessHacker/memprv.c b/ProcessHacker/memprv.c index 881a5d2500e7..0b38809c1d1e 100644 --- a/ProcessHacker/memprv.c +++ b/ProcessHacker/memprv.c @@ -494,7 +494,7 @@ NTSTATUS PhpUpdateMemoryRegionTypes( PVOID cfgBitmapAddress = NULL; PVOID cfgBitmapWow64Address = NULL; - if (ldrInitBlock.Size >= (ULONG)FIELD_OFFSET(PS_SYSTEM_DLL_INIT_BLOCK, Wow64CfgBitMap)) + if (ldrInitBlock.Size >= UFIELD_OFFSET(PS_SYSTEM_DLL_INIT_BLOCK, Wow64CfgBitMap)) { cfgBitmapAddress = (PVOID)ldrInitBlock.CfgBitMap; cfgBitmapWow64Address = (PVOID)ldrInitBlock.Wow64CfgBitMap; diff --git a/ProcessHacker/phsvc/svcapi.c b/ProcessHacker/phsvc/svcapi.c index e9e614c84c91..be7a728ce830 100644 --- a/ProcessHacker/phsvc/svcapi.c +++ b/ProcessHacker/phsvc/svcapi.c @@ -239,7 +239,7 @@ NTSTATUS PhSvcCaptureSid( if (sid) { - if (String->Length < (ULONG)FIELD_OFFSET(struct _SID, IdentifierAuthority) || + if (String->Length < UFIELD_OFFSET(struct _SID, IdentifierAuthority) || String->Length < RtlLengthRequiredSid(((struct _SID *)sid)->SubAuthorityCount) || !RtlValidSid(sid)) { diff --git a/phlib/mapimg.c b/phlib/mapimg.c index aa000600495b..fbee31dec399 100644 --- a/phlib/mapimg.c +++ b/phlib/mapimg.c @@ -1045,7 +1045,7 @@ NTSTATUS PhGetMappedImageImportEntry( if (IMAGE_SNAP_BY_ORDINAL32(entry.u1.Ordinal)) { Entry->Name = NULL; - Entry->Ordinal = (USHORT)IMAGE_ORDINAL32(entry.u1.Ordinal); + Entry->Ordinal = IMAGE_ORDINAL32(entry.u1.Ordinal); return STATUS_SUCCESS; } @@ -1068,7 +1068,7 @@ NTSTATUS PhGetMappedImageImportEntry( if (IMAGE_SNAP_BY_ORDINAL64(entry.u1.Ordinal)) { Entry->Name = NULL; - Entry->Ordinal = (USHORT)IMAGE_ORDINAL64(entry.u1.Ordinal); + Entry->Ordinal = IMAGE_ORDINAL64(entry.u1.Ordinal); return STATUS_SUCCESS; } @@ -1219,7 +1219,7 @@ NTSTATUS PhGetMappedImageCfg64( return status; // Not every load configuration defines CFG characteristics - if (config64->Size < (ULONG)FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY64, GuardFlags)) + if (config64->Size < UFIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY64, GuardFlags)) return STATUS_INVALID_VIEW_SIZE; CfgConfig->MappedImage = MappedImage; @@ -1262,7 +1262,7 @@ NTSTATUS PhGetMappedImageCfg64( CfgConfig->GuardAdressIatTable = 0; if ( - config64->Size >= (ULONG)FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY64, GuardAddressTakenIatEntryTable) + + config64->Size >= UFIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY64, GuardAddressTakenIatEntryTable) + sizeof(config64->GuardAddressTakenIatEntryTable) + sizeof(config64->GuardAddressTakenIatEntryCount) ) @@ -1295,7 +1295,7 @@ NTSTATUS PhGetMappedImageCfg64( CfgConfig->GuardLongJumpTable = 0; if ( - config64->Size >= (ULONG)FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY64, GuardLongJumpTargetTable) + + config64->Size >= UFIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY64, GuardLongJumpTargetTable) + sizeof(config64->GuardLongJumpTargetTable) + sizeof(config64->GuardLongJumpTargetCount) ) @@ -1339,7 +1339,7 @@ NTSTATUS PhGetMappedImageCfg32( return status; // Not every load configuration defines CFG characteristics - if (config32->Size < (ULONG)FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY32, GuardFlags)) + if (config32->Size < UFIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY32, GuardFlags)) return STATUS_INVALID_VIEW_SIZE; CfgConfig->MappedImage = MappedImage; @@ -1382,7 +1382,7 @@ NTSTATUS PhGetMappedImageCfg32( CfgConfig->GuardAdressIatTable = 0; if ( - config32->Size >= (ULONG)FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY32, GuardAddressTakenIatEntryTable) + + config32->Size >= UFIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY32, GuardAddressTakenIatEntryTable) + sizeof(config32->GuardAddressTakenIatEntryTable) + sizeof(config32->GuardAddressTakenIatEntryCount) ) @@ -1415,7 +1415,7 @@ NTSTATUS PhGetMappedImageCfg32( CfgConfig->GuardLongJumpTable = 0; if ( - config32->Size >= (ULONG)FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY32, GuardLongJumpTargetTable) + + config32->Size >= UFIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY32, GuardLongJumpTargetTable) + sizeof(config32->GuardLongJumpTargetTable) + sizeof(config32->GuardLongJumpTargetCount) ) diff --git a/tools/peview/ldprp.c b/tools/peview/ldprp.c index 826ec0d6a711..d19cb649d83b 100644 --- a/tools/peview/ldprp.c +++ b/tools/peview/ldprp.c @@ -85,21 +85,21 @@ INT_PTR CALLBACK PvpPeLoadConfigDlgProc( ADD_VALUE(L"SEH handler table", PhaFormatString(L"0x%Ix", (Config)->SEHandlerTable)->Buffer); \ ADD_VALUE(L"SEH handler count", PhaFormatUInt64((Config)->SEHandlerCount, TRUE)->Buffer); \ \ - if ((Config)->Size >= (ULONG)FIELD_OFFSET(Type, GuardCFCheckFunctionPointer)) \ + if ((Config)->Size >= UFIELD_OFFSET(Type, GuardCFCheckFunctionPointer)) \ { \ ADD_VALUE(L"CFG GuardFlags", PhaFormatString(L"0x%Ix", (Config)->GuardFlags)->Buffer); \ ADD_VALUE(L"CFG Check Function pointer", PhaFormatString(L"0x%Ix", (Config)->GuardCFCheckFunctionPointer)->Buffer); \ ADD_VALUE(L"CFG Check Dispatch pointer", PhaFormatString(L"0x%Ix", (Config)->GuardCFDispatchFunctionPointer)->Buffer); \ ADD_VALUE(L"CFG Function table", PhaFormatString(L"0x%Ix", (Config)->GuardCFFunctionTable)->Buffer); \ ADD_VALUE(L"CFG Function table entry count", PhaFormatUInt64((Config)->GuardCFFunctionCount, TRUE)->Buffer); \ - if ((Config)->Size >= (ULONG)FIELD_OFFSET(Type, GuardAddressTakenIatEntryTable) \ + if ((Config)->Size >= UFIELD_OFFSET(Type, GuardAddressTakenIatEntryTable) \ + sizeof((Config)->GuardAddressTakenIatEntryTable) \ + sizeof((Config)->GuardAddressTakenIatEntryCount)) \ { \ ADD_VALUE(L"CFG IatEntry table", PhaFormatString(L"0x%Ix", (Config)->GuardAddressTakenIatEntryTable)->Buffer); \ ADD_VALUE(L"CFG IatEntry table entry count", PhaFormatUInt64((Config)->GuardAddressTakenIatEntryCount, TRUE)->Buffer); \ } \ - if ((Config)->Size >= (ULONG)FIELD_OFFSET(Type, GuardLongJumpTargetTable) \ + if ((Config)->Size >= UFIELD_OFFSET(Type, GuardLongJumpTargetTable) \ + sizeof((Config)->GuardLongJumpTargetTable) \ + sizeof((Config)->GuardLongJumpTargetCount)) \ { \ From 2b8e69e0ac594718585fc3ef7aa809040eb99d00 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 2 Nov 2017 10:07:38 +1100 Subject: [PATCH 0535/2058] Fix typo --- plugins/ToolStatus/toolstatus.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/ToolStatus/toolstatus.h b/plugins/ToolStatus/toolstatus.h index b905a915f8ff..fee12ad7a937 100644 --- a/plugins/ToolStatus/toolstatus.h +++ b/plugins/ToolStatus/toolstatus.h @@ -2,8 +2,8 @@ * Process Hacker ToolStatus - * toolstatus header * - * Copyright (C) 2011-2016 dmex * Copyright (C) 2010-2013 wj32 + * Copyright (C) 2011-2016 dmex * * This file is part of Process Hacker. * From 374cec4c0ff8ed06ba9a7e4aa2e839223dec99a5 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 2 Nov 2017 10:08:53 +1100 Subject: [PATCH 0536/2058] peview: query section names using builtin function --- tools/peview/peprp.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tools/peview/peprp.c b/tools/peview/peprp.c index b2d8d744382f..bce767f5c460 100644 --- a/tools/peview/peprp.c +++ b/tools/peview/peprp.c @@ -531,11 +531,10 @@ INT_PTR CALLBACK PvpPeGeneralDlgProc( for (i = 0; i < PvMappedImage.NumberOfSections; i++) { INT lvItemIndex; - WCHAR sectionName[9]; + WCHAR sectionName[IMAGE_SIZEOF_SHORT_NAME + 1]; WCHAR pointer[PH_PTR_STR_LEN_1]; - if (PhCopyStringZFromBytes(PvMappedImage.Sections[i].Name, - IMAGE_SIZEOF_SHORT_NAME, sectionName, 9, NULL)) + if (PhGetMappedImageSectionName(&PvMappedImage.Sections[i], sectionName, ARRAYSIZE(sectionName), NULL)) { lvItemIndex = PhAddListViewItem(lvHandle, MAXINT, sectionName, NULL); From c63ad12d63ef4c162d2146894bdf43e4a97c05bc Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 2 Nov 2017 10:09:45 +1100 Subject: [PATCH 0537/2058] Remove duplicate ProcessPackage query --- ProcessHacker/procprv.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/ProcessHacker/procprv.c b/ProcessHacker/procprv.c index 296ba8fbdc6a..a55eefbc3460 100644 --- a/ProcessHacker/procprv.c +++ b/ProcessHacker/procprv.c @@ -1171,21 +1171,13 @@ VOID PhpProcessQueryStage2( if (PhEnableProcessQueryStage2 && processItem->FileName) { - PPH_STRING packageFullName = NULL; - - if (processItem->QueryHandle) - packageFullName = PhGetProcessPackageFullName(processItem->QueryHandle); - Data->VerifyResult = PhVerifyFileCached( processItem->FileName, - packageFullName, + processItem->PackageFullName, &Data->VerifySignerName, FALSE ); - if (packageFullName) - PhDereferenceObject(packageFullName); - status = PhIsExecutablePacked( processItem->FileName->Buffer, &Data->IsPacked, From 15c68b93022efc8d7e6f3bb29f713d1fc80ee89d Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 2 Nov 2017 11:16:51 +1100 Subject: [PATCH 0538/2058] Fix typo --- phlib/util.c | 1 - 1 file changed, 1 deletion(-) diff --git a/phlib/util.c b/phlib/util.c index 67fd7a565518..7d7f4950e9a0 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -380,7 +380,6 @@ INT PhShowMessage( va_list argptr; PPH_STRING message; - va_start(argptr, Format); va_start(argptr, Format); message = PhFormatString_V(Format, argptr); va_end(argptr); From 84f88facc554eb69e2390e4adaab1167c929d4ce Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 2 Nov 2017 12:18:07 +1100 Subject: [PATCH 0539/2058] Fix memory tab address filtering --- ProcessHacker/include/procprpp.h | 2 ++ ProcessHacker/prpgmem.c | 12 ++++++++++++ 2 files changed, 14 insertions(+) diff --git a/ProcessHacker/include/procprpp.h b/ProcessHacker/include/procprpp.h index 500573f100f7..2e315c4db325 100644 --- a/ProcessHacker/include/procprpp.h +++ b/ProcessHacker/include/procprpp.h @@ -305,6 +305,8 @@ typedef struct _PH_MEMORY_CONTEXT NTSTATUS LastRunStatus; PPH_STRING ErrorMessage; + BOOLEAN UseSearchPointer; + ULONG64 SearchPointer; PPH_STRING SearchboxText; PPH_TN_FILTER_ENTRY AllocationFilterEntry; PPH_TN_FILTER_ENTRY FilterEntry; diff --git a/ProcessHacker/prpgmem.c b/ProcessHacker/prpgmem.c index adb9146f7418..b835125aca20 100644 --- a/ProcessHacker/prpgmem.c +++ b/ProcessHacker/prpgmem.c @@ -256,6 +256,15 @@ BOOLEAN PhpMemoryTreeFilterCallback( if (PhIsNullOrEmptyString(memoryContext->SearchboxText)) return TRUE; + if ( + memoryContext->UseSearchPointer && + (memoryNode->MemoryItem->BaseAddress == (PVOID)memoryContext->SearchPointer || + memoryNode->MemoryItem->AllocationBase == (PVOID)memoryContext->SearchPointer) + ) + { + return TRUE; + } + if (memoryNode->BaseAddressText[0]) { if (PhpWordMatchHandleStringZ(memoryContext->SearchboxText, memoryNode->BaseAddressText)) @@ -408,6 +417,9 @@ INT_PTR CALLBACK PhpProcessMemoryDlgProc( if (!PhEqualString(memoryContext->SearchboxText, newSearchboxText, FALSE)) { + // Try to get a search pointer from the search string. + memoryContext->UseSearchPointer = PhStringToInteger64(&newSearchboxText->sr, 0, &memoryContext->SearchPointer); + // Cache the current search text for our callback. PhMoveReference(&memoryContext->SearchboxText, newSearchboxText); From 817bbecc7b766e3ea71491a4cba2876f656f0b0c Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 2 Nov 2017 23:40:22 +1100 Subject: [PATCH 0540/2058] Remove ExtraPlugins --- plugins/ExtraPlugins/CHANGELOG.txt | 4 - plugins/ExtraPlugins/ExtraPlugins.rc | 170 - plugins/ExtraPlugins/ExtraPlugins.vcxproj | 108 - .../ExtraPlugins/ExtraPlugins.vcxproj.filters | 97 - plugins/ExtraPlugins/cloud.c | 373 -- plugins/ExtraPlugins/dialog.c | 709 --- plugins/ExtraPlugins/disabled.c | 195 - plugins/ExtraPlugins/main.c | 351 -- plugins/ExtraPlugins/main.h | 327 -- plugins/ExtraPlugins/miniz/miniz.c | 4190 ----------------- plugins/ExtraPlugins/miniz/miniz.h | 785 --- plugins/ExtraPlugins/plugin.c | 371 -- plugins/ExtraPlugins/resource.h | 38 - .../resources/cog_edit_modern.png | Bin 341 -> 0 bytes plugins/ExtraPlugins/setup/page3.c | 86 - plugins/ExtraPlugins/setup/page4.c | 78 - plugins/ExtraPlugins/setup/page5.c | 198 - plugins/ExtraPlugins/setup/uninstall.c | 158 - plugins/ExtraPlugins/setup/updater.c | 678 --- plugins/ExtraPlugins/setup/verify.c | 204 - plugins/ExtraPlugins/wndtree.c | 461 -- 21 files changed, 9581 deletions(-) delete mode 100644 plugins/ExtraPlugins/CHANGELOG.txt delete mode 100644 plugins/ExtraPlugins/ExtraPlugins.rc delete mode 100644 plugins/ExtraPlugins/ExtraPlugins.vcxproj delete mode 100644 plugins/ExtraPlugins/ExtraPlugins.vcxproj.filters delete mode 100644 plugins/ExtraPlugins/cloud.c delete mode 100644 plugins/ExtraPlugins/dialog.c delete mode 100644 plugins/ExtraPlugins/disabled.c delete mode 100644 plugins/ExtraPlugins/main.c delete mode 100644 plugins/ExtraPlugins/main.h delete mode 100644 plugins/ExtraPlugins/miniz/miniz.c delete mode 100644 plugins/ExtraPlugins/miniz/miniz.h delete mode 100644 plugins/ExtraPlugins/plugin.c delete mode 100644 plugins/ExtraPlugins/resource.h delete mode 100644 plugins/ExtraPlugins/resources/cog_edit_modern.png delete mode 100644 plugins/ExtraPlugins/setup/page3.c delete mode 100644 plugins/ExtraPlugins/setup/page4.c delete mode 100644 plugins/ExtraPlugins/setup/page5.c delete mode 100644 plugins/ExtraPlugins/setup/uninstall.c delete mode 100644 plugins/ExtraPlugins/setup/updater.c delete mode 100644 plugins/ExtraPlugins/setup/verify.c delete mode 100644 plugins/ExtraPlugins/wndtree.c diff --git a/plugins/ExtraPlugins/CHANGELOG.txt b/plugins/ExtraPlugins/CHANGELOG.txt deleted file mode 100644 index 18d7d7804f0c..000000000000 --- a/plugins/ExtraPlugins/CHANGELOG.txt +++ /dev/null @@ -1,4 +0,0 @@ -1.0 - * Initial release - - diff --git a/plugins/ExtraPlugins/ExtraPlugins.rc b/plugins/ExtraPlugins/ExtraPlugins.rc deleted file mode 100644 index 1a87df91cf08..000000000000 --- a/plugins/ExtraPlugins/ExtraPlugins.rc +++ /dev/null @@ -1,170 +0,0 @@ -// Microsoft Visual C++ generated resource script. -// -#include "resource.h" - -#define APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// -#include "winres.h" -///////////////////////////////////////////////////////////////////////////// -#undef APSTUDIO_READONLY_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -// English (Australia) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENA) -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_AUS -#pragma code_page(1252) - -///////////////////////////////////////////////////////////////////////////// -// -// Version -// - -VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,0,0,0 - PRODUCTVERSION 1,0,0,0 - FILEFLAGSMASK 0x17L -#ifdef _DEBUG - FILEFLAGS 0x1L -#else - FILEFLAGS 0x0L -#endif - FILEOS 0x4L - FILETYPE 0x2L - FILESUBTYPE 0x0L -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "000904b0" - BEGIN - VALUE "CompanyName", "dmex" - VALUE "FileDescription", "Extra plugins for Process Hacker" - VALUE "FileVersion", "1.0.0.0" - VALUE "InternalName", "dmex.ExtraPlugins" - VALUE "LegalCopyright", "Licensed under the GNU GPL, v3." - VALUE "OriginalFilename", "ExtraPlugins.dll" - VALUE "ProductName", "Extra plugins for Process Hacker" - VALUE "ProductVersion", "1.0.0.0" - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x9, 1200 - END -END - - -///////////////////////////////////////////////////////////////////////////// -// -// DESIGNINFO -// - -#ifdef APSTUDIO_INVOKED -GUIDELINES DESIGNINFO -BEGIN - IDD_PLUGINS_DIALOG, DIALOG - BEGIN - LEFTMARGIN, 2 - RIGHTMARGIN, 637 - TOPMARGIN, 2 - BOTTOMMARGIN, 309 - END - - IDD_DISABLED_DIALOG, DIALOG - BEGIN - LEFTMARGIN, 2 - RIGHTMARGIN, 307 - TOPMARGIN, 2 - BOTTOMMARGIN, 176 - HORZGUIDE, 2 - END -END -#endif // APSTUDIO_INVOKED - - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -1 TEXTINCLUDE -BEGIN - "resource.h\0" -END - -2 TEXTINCLUDE -BEGIN - "#include ""winres.h""\0" -END - -3 TEXTINCLUDE -BEGIN - "\0" -END - -#endif // APSTUDIO_INVOKED - - -///////////////////////////////////////////////////////////////////////////// -// -// AFX_DIALOG_LAYOUT -// - -IDD_PLUGINS_DIALOG AFX_DIALOG_LAYOUT -BEGIN - 0 -END - -IDD_DISABLED_DIALOG AFX_DIALOG_LAYOUT -BEGIN - 0 -END - - -///////////////////////////////////////////////////////////////////////////// -// -// Dialog -// - -IDD_PLUGINS_DIALOG DIALOGEX 0, 0, 639, 313 -STYLE DS_SETFONT | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME -EXSTYLE WS_EX_APPWINDOW -CAPTION "Plugin Manager" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - PUSHBUTTON "Installed",IDC_INSTALLED,2,2,65,14,NOT WS_TABSTOP - PUSHBUTTON "Browse",IDC_BROWSE,73,2,64,14,NOT WS_TABSTOP - PUSHBUTTON "Updates (0)",IDC_UPDATES,143,2,65,14,NOT WS_TABSTOP - EDITTEXT IDC_SEARCHBOX,483,2,153,14,ES_AUTOHSCROLL,WS_EX_CLIENTEDGE - CONTROL "",IDC_PLUGINTREE,"PhTreeNew",WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP | 0xa,2,18,635,275,WS_EX_CLIENTEDGE - PUSHBUTTON "Close",IDOK,587,295,50,14 - PUSHBUTTON "Disabled Plugins (0)",IDC_DISABLED,2,295,75,14,NOT WS_TABSTOP - PUSHBUTTON "Clean up",IDC_CLEANUP,81,295,75,14,NOT WS_VISIBLE -END - -IDD_DISABLED_DIALOG DIALOGEX 0, 0, 309, 178 -STYLE DS_SETFONT | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME -CAPTION "Disabled Plugins" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - PUSHBUTTON "OK",IDOK,257,162,50,14 - CONTROL "",IDC_LIST_DISABLED,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_ALIGNLEFT | LVS_NOCOLUMNHEADER | WS_BORDER | WS_TABSTOP,2,15,305,145 - LTEXT "Changes may require a restart to take effect.",IDC_INSTRUCTION,3,3,154,8 -END - - -///////////////////////////////////////////////////////////////////////////// -// -// PNG -// - -IDB_SETTINGS_PNG PNG "resources\\cog_edit_modern.png" - -#endif // English (Australia) resources -///////////////////////////////////////////////////////////////////////////// - - diff --git a/plugins/ExtraPlugins/ExtraPlugins.vcxproj b/plugins/ExtraPlugins/ExtraPlugins.vcxproj deleted file mode 100644 index 15bbc0c42f1f..000000000000 --- a/plugins/ExtraPlugins/ExtraPlugins.vcxproj +++ /dev/null @@ -1,108 +0,0 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {96549A3E-D1BD-470E-A5B3-A64803C4DEF5} - ExtraPlugins - Win32Proj - ExtraPlugins - 10.0.16299.0 - - - - DynamicLibrary - Unicode - v141 - - - DynamicLibrary - Unicode - v141 - - - DynamicLibrary - Unicode - v141 - - - DynamicLibrary - Unicode - v141 - - - - - - - - - windowscodecs.lib;bcrypt.lib;winhttp.lib;uxtheme.lib;%(AdditionalDependencies) - bcrypt.dll;winhttp.dll;%(DelayLoadDLLs) - - - - - windowscodecs.lib;bcrypt.lib;winhttp.lib;uxtheme.lib;%(AdditionalDependencies) - bcrypt.dll;winhttp.dll;%(DelayLoadDLLs) - - - - - windowscodecs.lib;bcrypt.lib;winhttp.lib;uxtheme.lib;%(AdditionalDependencies) - bcrypt.dll;winhttp.dll;%(DelayLoadDLLs) - - - - - windowscodecs.lib;bcrypt.lib;winhttp.lib;uxtheme.lib;%(AdditionalDependencies) - bcrypt.dll;winhttp.dll;%(DelayLoadDLLs) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/plugins/ExtraPlugins/ExtraPlugins.vcxproj.filters b/plugins/ExtraPlugins/ExtraPlugins.vcxproj.filters deleted file mode 100644 index 8cd8cd03c4e7..000000000000 --- a/plugins/ExtraPlugins/ExtraPlugins.vcxproj.filters +++ /dev/null @@ -1,97 +0,0 @@ - - - - - {802108be-ae96-47c3-8d93-884ed6dd096a} - - - {3e65ffb8-3f3e-40d7-b3ca-d55cae8edb16} - - - {b98dd849-bbfe-4b41-8c48-f65680da5c00} - - - {d13aeaca-3136-44f8-8525-ac088e4170ad} - - - {297fc08d-cce6-41c6-8e77-63411ddd185b} - - - {59006979-4faf-455c-b58c-3f81e8ff9272} - - - {2ff6c860-c958-4bcc-8147-4093cad157e5} - - - {77191a45-2eba-438a-8ad2-853e25615850} - - - {50861cd8-df66-4551-a743-f08b54011d1e} - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files\zip - - - Source Files - - - Source Files\pages - - - Source Files\pages - - - Source Files\pages - - - Source Files\pages - - - Source Files - - - Source Files - - - Source Files - - - Source Files\pages - - - - - Header Files - - - Header Files - - - Header Files\zip - - - - - Resource Files - - - - - Resource Files\Images - - - - - - \ No newline at end of file diff --git a/plugins/ExtraPlugins/cloud.c b/plugins/ExtraPlugins/cloud.c deleted file mode 100644 index 7a7d72bfec24..000000000000 --- a/plugins/ExtraPlugins/cloud.c +++ /dev/null @@ -1,373 +0,0 @@ -/* -* Process Hacker Extra Plugins - -* Plugin Manager -* -* Copyright (C) 2016-2017 dmex -* -* This file is part of Process Hacker. -* -* Process Hacker is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* Process Hacker is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with Process Hacker. If not, see . -*/ - -#include "main.h" -#include "miniz\miniz.h" - -ULONGLONG ParseVersionString( - _In_ PPH_STRING Version - ) -{ - PH_STRINGREF remainingPart, majorPart, minorPart, revisionPart, reservedPart; - ULONG64 majorInteger = 0, minorInteger = 0, revisionInteger = 0, reservedInteger = 0; - - PhInitializeStringRef(&remainingPart, PhGetString(Version)); - PhSplitStringRefAtChar(&remainingPart, '.', &majorPart, &remainingPart); - PhSplitStringRefAtChar(&remainingPart, '.', &minorPart, &remainingPart); - PhSplitStringRefAtChar(&remainingPart, '.', &revisionPart, &remainingPart); - PhSplitStringRefAtChar(&remainingPart, '.', &reservedPart, &remainingPart); - - PhStringToInteger64(&majorPart, 10, &majorInteger); - PhStringToInteger64(&minorPart, 10, &minorInteger); - PhStringToInteger64(&revisionPart, 10, &revisionInteger); - PhStringToInteger64(&reservedPart, 10, &reservedInteger); - - return MAKE_VERSION_ULONGLONG(majorInteger, minorInteger, reservedInteger, revisionInteger); -} - -NTSTATUS QueryPluginsCallbackThread( - _In_ PVOID Parameter - ) -{ - HINTERNET httpSessionHandle = NULL; - HINTERNET httpConnectionHandle = NULL; - HINTERNET httpRequestHandle = NULL; - ULONG xmlStringBufferLength = 0; - PSTR xmlStringBuffer = NULL; - PVOID rootJsonObject = NULL; - PWCT_CONTEXT context = Parameter; - - if (!(httpSessionHandle = WinHttpOpen( - L"ExtraPlugins_1.0", - WindowsVersion >= WINDOWS_8_1 ? WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY : WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, - WINHTTP_NO_PROXY_NAME, - WINHTTP_NO_PROXY_BYPASS, - 0 - ))) - { - goto CleanupExit; - } - - if (!(httpConnectionHandle = WinHttpConnect( - httpSessionHandle, - L"wj32.org", - INTERNET_DEFAULT_HTTP_PORT, - 0 - ))) - { - goto CleanupExit; - } - - if (!(httpRequestHandle = WinHttpOpenRequest( - httpConnectionHandle, - NULL, - L"/processhacker/plugins/list.php", - NULL, - WINHTTP_NO_REFERER, - WINHTTP_DEFAULT_ACCEPT_TYPES, - WINHTTP_FLAG_REFRESH - ))) - { - goto CleanupExit; - } - - if (!WinHttpSendRequest( - httpRequestHandle, - WINHTTP_NO_ADDITIONAL_HEADERS, - 0, - WINHTTP_NO_REQUEST_DATA, - 0, - WINHTTP_IGNORE_REQUEST_TOTAL_LENGTH, - 0 - )) - { - goto CleanupExit; - } - - if (!WinHttpReceiveResponse(httpRequestHandle, NULL)) - goto CleanupExit; - - if (!ReadRequestString(httpRequestHandle, &xmlStringBuffer, &xmlStringBufferLength)) - goto CleanupExit; - - if (!(rootJsonObject = PhCreateJsonParser(xmlStringBuffer))) - goto CleanupExit; - - for (INT i = 0; i < PhGetJsonArrayLength(rootJsonObject); i++) - { - PVOID jvalue; - PPLUGIN_NODE entry; - SYSTEMTIME time = { 0 }; - SYSTEMTIME localTime = { 0 }; - PH_STRINGREF pluginBaseName; - PPH_STRING pluginDllPath; - - entry = PhCreateAlloc(sizeof(PLUGIN_NODE)); - memset(entry, 0, sizeof(PLUGIN_NODE)); - - jvalue = PhGetJsonArrayIndexObject(rootJsonObject, i); - entry->Id = PhGetJsonValueAsString(jvalue, "plugin_id"); - entry->InternalName = PhGetJsonValueAsString(jvalue, "plugin_internal_name"); - entry->Name = PhGetJsonValueAsString(jvalue, "plugin_name"); - entry->Version = PhGetJsonValueAsString(jvalue, "plugin_version"); - entry->Author = PhGetJsonValueAsString(jvalue, "plugin_author"); - entry->Description = PhGetJsonValueAsString(jvalue, "plugin_description"); - entry->IconUrl = PhGetJsonValueAsString(jvalue, "plugin_icon"); - entry->Requirements = PhGetJsonValueAsString(jvalue, "plugin_requirements"); - entry->FeedbackUrl = PhGetJsonValueAsString(jvalue, "plugin_feedback"); - entry->Screenshots = PhGetJsonValueAsString(jvalue, "plugin_screenshots"); - entry->AddedTime = PhGetJsonValueAsString(jvalue, "plugin_datetime_added"); - entry->UpdatedTime = PhGetJsonValueAsString(jvalue, "plugin_datetime_updated"); - entry->Download_count = PhGetJsonValueAsString(jvalue, "plugin_download_count"); - entry->Download_link_32 = PhGetJsonValueAsString(jvalue, "plugin_download_link_32"); - entry->Download_link_64 = PhGetJsonValueAsString(jvalue, "plugin_download_link_64"); - entry->SHA2_32 = PhGetJsonValueAsString(jvalue, "plugin_hash_32"); - entry->SHA2_64 = PhGetJsonValueAsString(jvalue, "plugin_hash_64"); - entry->HASH_32 = PhGetJsonValueAsString(jvalue, "plugin_signed_32"); - entry->HASH_64 = PhGetJsonValueAsString(jvalue, "plugin_signed_64"); - entry->FileName = PhGetJsonValueAsString(jvalue, "plugin_filename"); - - swscanf( - PhGetString(entry->UpdatedTime), - L"%hu-%hu-%hu %hu:%hu:%hu", - &time.wYear, - &time.wMonth, - &time.wDay, - &time.wHour, - &time.wMinute, - &time.wSecond - ); - - if (SystemTimeToTzSpecificLocalTime(NULL, &time, &localTime)) - { - entry->UpdatedTime = PhFormatDateTime(&localTime); - } - - PPH_STRING directory = PhGetApplicationDirectory(); - pluginDllPath = PhConcatStrings(3, PhGetString(directory), L"Plugins\\", PhGetString(entry->FileName)); - PhDereferenceObject(directory); - - PhInitializeStringRefLongHint(&pluginBaseName, PhGetString(entry->FileName)); - - if (PhIsPluginDisabled(&pluginBaseName)) - goto CleanupExit; - - if (RtlDoesFileExists_U(PhGetString(pluginDllPath))) - { - ULONG versionSize; - PVOID versionInfo; - PUSHORT languageInfo; - UINT language; - UINT bufferSize = 0; - PWSTR buffer = NULL; - PPH_STRING internalName = NULL; - PPH_STRING version = NULL; - - entry->FilePath = PhCreateString2(&pluginDllPath->sr); - - versionSize = GetFileVersionInfoSize(PhGetString(entry->FilePath), NULL); - versionInfo = PhAllocate(versionSize); - memset(versionInfo, 0, versionSize); - - if (GetFileVersionInfo(PhGetString(entry->FilePath), 0, versionSize, versionInfo)) - { - if (VerQueryValue(versionInfo, L"\\", &buffer, &bufferSize)) - { - VS_FIXEDFILEINFO* info = (VS_FIXEDFILEINFO*)buffer; - - if (info->dwSignature == 0xfeef04bd) - { - version = PhFormatString( - L"%lu.%lu.%lu.%lu", - (info->dwFileVersionMS >> 16) & 0xffff, - (info->dwFileVersionMS >> 0) & 0xffff, - (info->dwFileVersionLS >> 16) & 0xffff, - (info->dwFileVersionLS >> 0) & 0xffff - ); - } - } - - if (VerQueryValue(versionInfo, L"\\VarFileInfo\\Translation", &languageInfo, &language)) - { - PPH_STRING internalNameString = PhFormatString( - L"\\StringFileInfo\\%04x%04x\\InternalName", - languageInfo[0], - languageInfo[1] - ); - - if (VerQueryValue(versionInfo, PhGetStringOrEmpty(internalNameString), &buffer, &bufferSize)) - { - internalName = PhCreateStringEx(buffer, bufferSize * sizeof(WCHAR)); - } - - PhDereferenceObject(internalNameString); - } - } - - PhFree(versionInfo); - - if (entry->PluginInstance = (PPHAPP_PLUGIN)PhFindPlugin(PhGetString(entry->InternalName))) - { - ULONGLONG currentVersion = ParseVersionString(version); - ULONGLONG latestVersion = ParseVersionString(entry->Version); - - entry->PluginOptions = entry->PluginInstance->Information.HasOptions; - - if (currentVersion < latestVersion) - { - entry->State = PLUGIN_STATE_UPDATE; - PostMessage(context->DialogHandle, ID_UPDATE_ADD, 0, (LPARAM)entry); - } - } - else - { - entry->State = PLUGIN_STATE_RESTART; - PostMessage(context->DialogHandle, ID_UPDATE_ADD, 0, (LPARAM)entry); - } - } - else - { - entry->State = PLUGIN_STATE_REMOTE; - PostMessage(context->DialogHandle, ID_UPDATE_ADD, 0, (LPARAM)entry); - } - } - -CleanupExit: - - if (rootJsonObject) - PhFreeJsonParser(rootJsonObject); - - if (httpRequestHandle) - WinHttpCloseHandle(httpRequestHandle); - - if (httpConnectionHandle) - WinHttpCloseHandle(httpConnectionHandle); - - if (httpSessionHandle) - WinHttpCloseHandle(httpSessionHandle); - - if (xmlStringBuffer) - PhFree(xmlStringBuffer); - - PostMessage(context->DialogHandle, ID_UPDATE_COUNT, 0, 0); - - return STATUS_SUCCESS; -} - -NTSTATUS SetupExtractBuild( - _In_ PVOID Parameter - ) -{ - static PH_STRINGREF pluginsDirectory = PH_STRINGREF_INIT(L"plugins\\"); - mz_bool status = MZ_FALSE; - mz_zip_archive zip_archive; - PPH_UPDATER_CONTEXT context = (PPH_UPDATER_CONTEXT)Parameter; - - memset(&zip_archive, 0, sizeof(zip_archive)); - - // TODO: Move existing folder items. - - if (!(status = mz_zip_reader_init_file(&zip_archive, PhGetStringOrEmpty(context->SetupFilePath), 0))) - { - goto error; - } - - for (ULONG i = 0; i < mz_zip_reader_get_num_files(&zip_archive); i++) - { - mz_zip_archive_file_stat stat; - - if (!mz_zip_reader_file_stat(&zip_archive, i, &stat)) - { - continue; - } - - if (mz_zip_reader_is_file_a_directory(&zip_archive, i)) - { - PPH_STRING directory; - PPH_STRING fileName; - PPH_STRING fullSetupPath; - PPH_STRING extractPath; - ULONG indexOfFileName = -1; - - fileName = PhConvertUtf8ToUtf16(stat.m_filename); - directory = PhGetApplicationDirectory(); - extractPath = PhConcatStringRef3(&directory->sr, &pluginsDirectory, &fileName->sr); - fullSetupPath = PhGetFullPath(PhGetStringOrEmpty(extractPath), &indexOfFileName); - - PhCreateDirectory(fullSetupPath); - - PhDereferenceObject(fullSetupPath); - PhDereferenceObject(extractPath); - PhDereferenceObject(directory); - PhDereferenceObject(fileName); - } - else - { - PPH_STRING directory; - PPH_STRING fileName; - PPH_STRING fullSetupPath; - PPH_STRING extractPath; - PPH_STRING directoryPath; - PPH_STRING fileNameString; - ULONG indexOfFileName = -1; - - fileName = PhConvertUtf8ToUtf16(stat.m_filename); - directory = PhGetApplicationDirectory(); - extractPath = PhConcatStringRef3(&directory->sr, &pluginsDirectory, &fileName->sr); - fullSetupPath = PhGetFullPath(PhGetStringOrEmpty(extractPath), &indexOfFileName); - fileNameString = PhConcatStrings(2, fullSetupPath->Buffer, L".bak"); - - if (indexOfFileName != -1) - { - if (directoryPath = PhSubstring(fullSetupPath, 0, indexOfFileName)) - { - PhCreateDirectory(directoryPath); - - PhDereferenceObject(directoryPath); - } - } - - if (RtlDoesFileExists_U(PhGetStringOrEmpty(fullSetupPath))) - { - MoveFileEx(PhGetString(fullSetupPath), PhGetString(fileNameString), MOVEFILE_REPLACE_EXISTING); - } - - if (!mz_zip_reader_extract_to_file(&zip_archive, i, PhGetString(fullSetupPath), 0)) - { - goto error; - } - - PhDereferenceObject(fileNameString); - PhDereferenceObject(fullSetupPath); - PhDereferenceObject(extractPath); - PhDereferenceObject(directory); - PhDereferenceObject(fileName); - } - } - - mz_zip_reader_end(&zip_archive); - return STATUS_SUCCESS; - -error: - mz_zip_reader_end(&zip_archive); - return STATUS_FAIL_CHECK; -} \ No newline at end of file diff --git a/plugins/ExtraPlugins/dialog.c b/plugins/ExtraPlugins/dialog.c deleted file mode 100644 index 2a1f9708ac07..000000000000 --- a/plugins/ExtraPlugins/dialog.c +++ /dev/null @@ -1,709 +0,0 @@ -/* - * Process Hacker Extra Plugins - - * Plugin Manager - * - * Copyright (C) 2016 dmex - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include "main.h" - -BOOLEAN WordMatchStringRef( - _In_ PWCT_CONTEXT Context, - _In_ PPH_STRINGREF Text - ) -{ - PH_STRINGREF part; - PH_STRINGREF remainingPart; - - remainingPart = Context->SearchboxText->sr; - - while (remainingPart.Length) - { - PhSplitStringRefAtChar(&remainingPart, '|', &part, &remainingPart); - - if (part.Length) - { - if (PhFindStringInStringRef(Text, &part, TRUE) != -1) - return TRUE; - } - } - - return FALSE; -} - -BOOLEAN WordMatchStringZ( - _In_ PWCT_CONTEXT Context, - _In_ PWSTR Text - ) -{ - PH_STRINGREF text; - - PhInitializeStringRef(&text, Text); - return WordMatchStringRef(Context, &text); -} - -VOID UpdateTreeView( - _In_ PWCT_CONTEXT Context - ) -{ - //PhMoveReference(&Context->TreeText, PhCreateString(L"Loading Plugins...")); - //TreeNew_SetEmptyText(Context->TreeNewHandle, &Context->TreeText->sr, 0); - - PhApplyTreeNewFilters(GetPluginListFilterSupport(Context)); - TreeNew_AutoSizeColumn(Context->TreeNewHandle, TREE_COLUMN_ITEM_NAME, TN_AUTOSIZE_REMAINING_SPACE); -} - -VOID UpdateMenuView(_In_ PWCT_CONTEXT Context, UINT Id) -{ - HWND active = Context->PluginMenuActive; - Context->PluginMenuActiveId = Id; - Context->PluginMenuActive = GetDlgItem(Context->DialogHandle, Id); - RedrawWindow(active, NULL, NULL, RDW_ERASENOW | RDW_INVALIDATE | RDW_FRAME); -} - -LRESULT DrawButton( - _In_ PWCT_CONTEXT Context, - _In_ LPARAM lParam - ) -{ - LPNMTVCUSTOMDRAW drawInfo = (LPNMTVCUSTOMDRAW)lParam; - BOOLEAN isGrayed = (drawInfo->nmcd.uItemState & CDIS_GRAYED) == CDIS_GRAYED; - BOOLEAN isChecked = (drawInfo->nmcd.uItemState & CDIS_CHECKED) == CDIS_CHECKED; - BOOLEAN isDisabled = (drawInfo->nmcd.uItemState & CDIS_DISABLED) == CDIS_DISABLED; - BOOLEAN isSelected = (drawInfo->nmcd.uItemState & CDIS_SELECTED) == CDIS_SELECTED; - BOOLEAN isHighlighted = (drawInfo->nmcd.uItemState & CDIS_HOT) == CDIS_HOT; - BOOLEAN isFocused = (drawInfo->nmcd.uItemState & CDIS_FOCUS) == CDIS_FOCUS; - - if (drawInfo->nmcd.dwDrawStage == CDDS_PREPAINT) - { - HPEN PenActive = CreatePen(PS_SOLID, 2, RGB(0, 0, 0)); - //HPEN PenNormal = CreatePen(PS_SOLID, 1, RGB(0, 0xff, 0)); - HBRUSH BrushNormal = GetSysColorBrush(COLOR_3DFACE); - //HBRUSH BrushSelected = CreateSolidBrush(RGB(0xff, 0xff, 0xff)); - HBRUSH BrushPushed = CreateSolidBrush(RGB(153, 209, 255)); - PPH_STRING windowText = PH_AUTO(PhGetWindowText(drawInfo->nmcd.hdr.hwndFrom)); - - SetBkMode(drawInfo->nmcd.hdc, TRANSPARENT); - - if (isHighlighted || Context->PluginMenuActiveId == drawInfo->nmcd.hdr.idFrom) - { - FillRect(drawInfo->nmcd.hdc, &drawInfo->nmcd.rc, BrushNormal); - - SelectObject(drawInfo->nmcd.hdc, PenActive); - SelectObject(drawInfo->nmcd.hdc, Context->BoldFontHandle); - } - else if (isSelected) - { - FillRect(drawInfo->nmcd.hdc, &drawInfo->nmcd.rc, BrushPushed); - - SelectObject(drawInfo->nmcd.hdc, PenActive); - SelectObject(drawInfo->nmcd.hdc, Context->BoldFontHandle); - } - else - { - FillRect(drawInfo->nmcd.hdc, &drawInfo->nmcd.rc, BrushNormal); - } - - DrawText( - drawInfo->nmcd.hdc, - windowText->Buffer, - (ULONG)windowText->Length / 2, - &drawInfo->nmcd.rc, - DT_CENTER | DT_VCENTER | DT_END_ELLIPSIS | DT_SINGLELINE - ); - - MoveToEx(drawInfo->nmcd.hdc, drawInfo->nmcd.rc.left, drawInfo->nmcd.rc.bottom, 0); - LineTo(drawInfo->nmcd.hdc, drawInfo->nmcd.rc.right, drawInfo->nmcd.rc.bottom); - - DeletePen(PenActive); - DeleteBrush(BrushNormal); - DeleteBrush(BrushPushed); - return CDRF_SKIPDEFAULT; - } - - return CDRF_DODEFAULT; -} - -BOOLEAN ProcessTreeFilterCallback( - _In_ PPH_TREENEW_NODE Node, - _In_opt_ PVOID Context - ) -{ - PWCT_CONTEXT context = Context; - PPLUGIN_NODE node = (PPLUGIN_NODE)Node; - - // Hide plugins from different tabs - if (node->State != context->Type) - return FALSE; - - if (PhIsNullOrEmptyString(context->SearchboxText)) - return TRUE; - - if (!PhIsNullOrEmptyString(node->InternalName)) - { - if (WordMatchStringRef(context, &node->InternalName->sr)) - return TRUE; - } - - if (!PhIsNullOrEmptyString(node->Id)) - { - if (WordMatchStringRef(context, &node->Id->sr)) - return TRUE; - } - - if (!PhIsNullOrEmptyString(node->Name)) - { - if (WordMatchStringRef(context, &node->Name->sr)) - return TRUE; - } - - if (!PhIsNullOrEmptyString(node->Version)) - { - if (WordMatchStringRef(context, &node->Version->sr)) - return TRUE; - } - - if (!PhIsNullOrEmptyString(node->Author)) - { - if (WordMatchStringRef(context, &node->Author->sr)) - return TRUE; - } - - if (!PhIsNullOrEmptyString(node->Description)) - { - if (WordMatchStringRef(context, &node->Description->sr)) - return TRUE; - } - - return FALSE; -} - -INT_PTR CALLBACK CloudPluginsDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - PWCT_CONTEXT context = NULL; - - if (uMsg == WM_INITDIALOG) - { - context = (PWCT_CONTEXT)PhAllocate(sizeof(WCT_CONTEXT)); - memset(context, 0, sizeof(WCT_CONTEXT)); - - SetProp(hwndDlg, L"Context", (HANDLE)context); - } - else - { - context = (PWCT_CONTEXT)GetProp(hwndDlg, L"Context"); - - if (uMsg == WM_DESTROY) - { - PhSaveWindowPlacementToSetting(SETTING_NAME_WINDOW_POSITION, SETTING_NAME_WINDOW_SIZE, hwndDlg); - PhDeleteLayoutManager(&context->LayoutManager); - PhUnregisterDialog(hwndDlg); - RemoveProp(hwndDlg, L"Context"); - PhFree(context); - - PostQuitMessage(0); - } - } - - if (context == NULL) - return FALSE; - - switch (uMsg) - { - case WM_INITDIALOG: - { - SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhInstanceHandle, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); - SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhInstanceHandle, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); - - context->DialogHandle = hwndDlg; - context->PluginMenuActiveId = IDC_INSTALLED; - context->PluginMenuActive = GetDlgItem(hwndDlg, IDC_INSTALLED); - context->TreeNewHandle = GetDlgItem(hwndDlg, IDC_PLUGINTREE); - context->SearchHandle = GetDlgItem(hwndDlg, IDC_SEARCHBOX); - context->SearchboxText = PhReferenceEmptyString(); - - PhCreateSearchControl(hwndDlg, context->SearchHandle, L"Search Plugins (Ctrl+K)"); - context->NormalFontHandle = PhCreateCommonFont(-14, FW_NORMAL, NULL); - context->BoldFontHandle = PhCreateCommonFont(-16, FW_BOLD, NULL); - - PhCenterWindow(hwndDlg, PhMainWndHandle); - InitializePluginsTree(context, hwndDlg, context->TreeNewHandle); - PhAddTreeNewFilter(GetPluginListFilterSupport(context), ProcessTreeFilterCallback, context); - - PhInitializeLayoutManager(&context->LayoutManager, hwndDlg); - PhAddLayoutItem(&context->LayoutManager, context->TreeNewHandle, NULL, PH_ANCHOR_ALL); - PhAddLayoutItem(&context->LayoutManager, context->SearchHandle, NULL, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); - PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_CLEANUP), NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_LEFT); - PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_DISABLED), NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_LEFT); - PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDOK), NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_RIGHT); - PhLoadWindowPlacementFromSetting(SETTING_NAME_WINDOW_POSITION, SETTING_NAME_WINDOW_SIZE, hwndDlg); - - EnumerateLoadedPlugins(context); - SetWindowText(GetDlgItem(hwndDlg, IDC_DISABLED), PhaFormatString(L"Disabled Plugins (%lu)", PhDisabledPluginsCount())->Buffer); - PhQueueItemWorkQueue(PhGetGlobalWorkQueue(), QueryPluginsCallbackThread, context); - UpdateTreeView(context); - - SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hwndDlg, IDC_INSTALLED), TRUE); - } - break; - case WM_SIZE: - PhLayoutManagerLayout(&context->LayoutManager); - TreeNew_AutoSizeColumn(context->TreeNewHandle, TREE_COLUMN_ITEM_NAME, TN_AUTOSIZE_REMAINING_SPACE); - break; - case WM_COMMAND: - { - switch (GET_WM_COMMAND_CMD(wParam, lParam)) - { - case EN_CHANGE: - { - PPH_STRING newSearchboxText; - - newSearchboxText = PH_AUTO(PhGetWindowText(context->SearchHandle)); - - if (!PhEqualString(context->SearchboxText, newSearchboxText, FALSE)) - { - // Cache the current search text for our callback. - PhSwapReference(&context->SearchboxText, newSearchboxText); - - if (!PhIsNullOrEmptyString(context->SearchboxText)) - { - // Expand the nodes to ensure that they will be visible to the user. - } - - PhApplyTreeNewFilters(GetPluginListFilterSupport(context)); - } - } - break; - } - - switch (GET_WM_COMMAND_ID(wParam, lParam)) - { - //case ID_SEARCH_CLEAR: - // { - // if (context->SearchHandle) - // { - // SetFocus(context->SearchHandle); - // Static_SetText(context->SearchHandle, L""); - - // UpdateTreeView(context); - // } - // } - // break; - case IDC_INSTALLED: - { - context->Type = PLUGIN_STATE_LOCAL; - - UpdateMenuView(context, IDC_INSTALLED); - UpdateTreeView(context); - } - break; - case IDC_BROWSE: - { - context->Type = PLUGIN_STATE_REMOTE; - - UpdateMenuView(context, IDC_BROWSE); - UpdateTreeView(context); - } - break; - case IDC_UPDATES: - { - context->Type = PLUGIN_STATE_UPDATE; - - UpdateMenuView(context, IDC_UPDATES); - UpdateTreeView(context); - } - break; - case WM_ACTION: - { - PPLUGIN_NODE selectedNode; - - if (selectedNode = WeGetSelectedWindowNode(context)) - { - if (selectedNode->State == PLUGIN_STATE_LOCAL) - { - if (selectedNode->PluginInstance && selectedNode->PluginInstance->Information.HasOptions) - { - PhInvokeCallback(PhGetPluginCallback((PPH_PLUGIN)selectedNode->PluginInstance, PluginCallbackShowOptions), hwndDlg); - } - } - else if (selectedNode->State == PLUGIN_STATE_REMOTE) - { - if (PhGetOwnTokenAttributes().Elevated) - { - if (StartInitialCheck(hwndDlg, selectedNode, PLUGIN_ACTION_INSTALL)) - { - - } - } - } - else if (selectedNode->State == PLUGIN_STATE_UPDATE) - { - if (PhGetOwnTokenAttributes().Elevated) - { - if (StartInitialCheck(hwndDlg, selectedNode, PLUGIN_ACTION_INSTALL)) - { - - } - } - } - } - } - break; - case ID_WCTSHOWCONTEXTMENU: - { - PPH_EMENU menu; - PPH_EMENU_ITEM selectedItem; - PPLUGIN_NODE selectedNode; - PPH_TREENEW_CONTEXT_MENU contextMenuEvent = (PPH_TREENEW_CONTEXT_MENU)lParam; - - if (!(selectedNode = WeGetSelectedWindowNode(context))) - break; - - menu = PhCreateEMenu(); - - if (selectedNode->State == PLUGIN_STATE_LOCAL) - { - HICON shieldIcon; - - shieldIcon = PhLoadIcon(NULL, IDI_SHIELD, PH_LOAD_ICON_SIZE_SMALL | PH_LOAD_ICON_STRICT, 0, 0); - selectedItem = PhCreateEMenuItem(0, ID_MENU_UNINSTALL, L"Uninstall", NULL, NULL); - - if (shieldIcon) - { - selectedItem->Bitmap = PhIconToBitmap( - shieldIcon, - GetSystemMetrics(SM_CXSMICON), - GetSystemMetrics(SM_CYSMICON) - ); - DestroyIcon(shieldIcon); - } - - PhInsertEMenuItem(menu, selectedItem, -1); - PhInsertEMenuItem(menu, PhCreateEMenuItem(PH_EMENU_SEPARATOR, 0, NULL, NULL, NULL), -1); - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_MENU_DISABLE, L"Disable", NULL, NULL), -1); - PhInsertEMenuItem(menu, PhCreateEMenuItem(PH_EMENU_SEPARATOR, 0, NULL, NULL, NULL), -1); - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_MENU_PROPERTIES, L"Options", NULL, NULL), -1); - - if (!selectedNode->PluginInstance || !selectedNode->PluginInstance->Information.HasOptions) - { - PhSetFlagsEMenuItem(menu, ID_MENU_PROPERTIES, PH_EMENU_DISABLED, PH_EMENU_DISABLED); - } - - if (!PhGetOwnTokenAttributes().Elevated) - { - PhSetFlagsEMenuItem(menu, ID_MENU_UNINSTALL, PH_EMENU_DISABLED, PH_EMENU_DISABLED); - } - } - else - { - HICON shieldIcon; - - shieldIcon = PhLoadIcon(NULL, IDI_SHIELD, PH_LOAD_ICON_SIZE_SMALL | PH_LOAD_ICON_STRICT, 0, 0); - selectedItem = PhCreateEMenuItem(0, ID_MENU_INSTALL, PhaFormatString(L"Install %s plugin", PhGetStringOrEmpty(selectedNode->Name))->Buffer, NULL, NULL); - - if (shieldIcon) - { - selectedItem->Bitmap = PhIconToBitmap( - shieldIcon, - GetSystemMetrics(SM_CXSMICON), - GetSystemMetrics(SM_CYSMICON) - ); - DestroyIcon(shieldIcon); - } - - PhInsertEMenuItem(menu, selectedItem, -1); - PhInsertEMenuItem(menu, PhCreateEMenuItem(PH_EMENU_SEPARATOR, 0, NULL, NULL, NULL), -1); - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_MENU_DISABLE, L"Disable", NULL, NULL), -1); - } - - selectedItem = PhShowEMenu( - menu, - hwndDlg, - PH_EMENU_SHOW_LEFTRIGHT, - PH_ALIGN_LEFT | PH_ALIGN_TOP, - contextMenuEvent->Location.x, - contextMenuEvent->Location.y - ); - - if (selectedItem && selectedItem->Id != -1) - { - switch (selectedItem->Id) - { - case ID_MENU_INSTALL: - { - if (!PhGetOwnTokenAttributes().Elevated) - { - //SHELLEXECUTEINFO info = { sizeof(SHELLEXECUTEINFO) }; - //info.lpFile = L"ProcessHacker.exe"; - //info.lpParameters = L"-plugin dmex.ExtraPlugins:INSTALL -plugin dmex.ExtraPlugins:hex64value"; - //info.lpVerb = L"runas"; - //info.nShow = SW_SHOW; - //info.hwnd = hwndDlg; - - //if (!ShellExecuteEx(&info)) - //{ - - //} - } - else - { - PPLUGIN_NODE existingNode; - - if (selectedNode->State == PLUGIN_STATE_LOCAL) - { - if (existingNode = FindTreeNode( - context, - PLUGIN_STATE_REMOTE, - selectedNode->InternalName - )) - { - if (StartInitialCheck(hwndDlg, existingNode, PLUGIN_ACTION_INSTALL)) - { - - } - } - - UpdateTreeView(context); - } - else - { - if (StartInitialCheck(hwndDlg, selectedNode, PLUGIN_ACTION_INSTALL)) - { - - } - - if (existingNode = FindTreeNode( - context, - PLUGIN_STATE_REMOTE, - selectedNode->InternalName - )) - { - selectedNode->State = PLUGIN_STATE_RESTART; - } - - UpdateTreeView(context); - } - } - } - break; - case ID_MENU_UNINSTALL: - { - if (!PhGetOwnTokenAttributes().Elevated) - { - //SHELLEXECUTEINFO info = { sizeof(SHELLEXECUTEINFO) }; - //info.lpFile = L"ProcessHacker.exe"; - //info.lpParameters = L"-plugin dmex.ExtraPlugins:UNINSTALL -plugin dmex.ExtraPlugins:hex64value"; - //info.lpVerb = L"runas"; - //info.nShow = SW_SHOW; - //info.hwnd = hwndDlg; - // - //if (!ShellExecuteEx(&info)) - //{ - // - //} - } - else - { - PPLUGIN_NODE selectedNode; - PPLUGIN_NODE existingNode; - - if (selectedNode = WeGetSelectedWindowNode(context)) - { - if (StartInitialCheck(hwndDlg, selectedNode, PLUGIN_ACTION_UNINSTALL)) - { - if (existingNode = FindTreeNode( - context, - PLUGIN_STATE_LOCAL, - selectedNode->InternalName - )) - { - existingNode->State = PLUGIN_STATE_RESTART; - } - } - - UpdateTreeView(context); - } - } - } - break; - case ID_MENU_DISABLE: - { - PPH_STRING baseName; - - baseName = PhGetBaseName(selectedNode->FileName); - - PhSetPluginDisabled(&baseName->sr, TRUE); - - selectedNode->State = PLUGIN_STATE_RESTART; - UpdateTreeView(context); - - SetWindowText(GetDlgItem(hwndDlg, IDC_DISABLED), - PhGetString(PhaFormatString(L"Disabled Plugins (%lu)", PhDisabledPluginsCount())) - ); - } - break; - case ID_MENU_PROPERTIES: - { - if (selectedNode->PluginInstance) - { - PhInvokeCallback(PhGetPluginCallback((PPH_PLUGIN)selectedNode->PluginInstance, PluginCallbackShowOptions), hwndDlg); - } - } - break; - } - } - } - break; - case IDCANCEL: - case IDOK: - { - //ShowUpdateDialog(hwndDlg, PLUGIN_ACTION_RESTART); - DestroyWindow(hwndDlg); - } - break; - case IDC_DISABLED: - { - ShowDisabledPluginsDialog(hwndDlg); - - PluginsClearTree(context); - EnumerateLoadedPlugins(context); - SetWindowText(GetDlgItem(hwndDlg, IDC_DISABLED), PhGetString(PhaFormatString(L"Disabled Plugins (%lu)", PhDisabledPluginsCount()))); - PhQueueItemWorkQueue(PhGetGlobalWorkQueue(), QueryPluginsCallbackThread, context); - UpdateTreeView(context); - - SetWindowText(GetDlgItem(hwndDlg, IDC_DISABLED), - PhGetString(PhaFormatString(L"Disabled Plugins (%lu)", PhDisabledPluginsCount())) - ); - } - break; - } - } - break; - case WM_NOTIFY: - { - LPNMHDR header = (LPNMHDR)lParam; - - switch (header->code) - { - case NM_CUSTOMDRAW: - { - if (header->idFrom == IDC_INSTALLED || header->idFrom == IDC_BROWSE || header->idFrom == IDC_UPDATES) - { - SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, DrawButton(context, lParam)); - return TRUE; - } - } - break; - } - } - break; - case ID_UPDATE_ADD: - { - PPLUGIN_NODE entry = (PPLUGIN_NODE)lParam; - - TreeNew_SetRedraw(context->TreeNewHandle, FALSE); - - PluginsAddTreeNode(context, entry); - UpdateTreeView(context); - - TreeNew_SetRedraw(context->TreeNewHandle, TRUE); - } - break; - case ID_UPDATE_COUNT: - { - //ULONG count = 0; - // - //for (ULONG i = 0; i < context->TreeContext.NodeList->Count; i++) - //{ - // PPLUGIN_NODE windowNode = context->TreeContext.NodeList->Items[i]; - // - // if (windowNode->State == PLUGIN_STATE_UPDATE) - // { - // count++; - // } - //} - // - //SetWindowText(GetDlgItem(hwndDlg, IDC_UPDATES), PhGetString(PhaFormatString(L"Updates (%lu)", count))); - } - break; - } - - return FALSE; -} - -NTSTATUS CloudDialogThread( - _In_ PVOID Parameter - ) -{ - BOOL result; - MSG message; - HWND cloudDialogHandle; - PH_AUTO_POOL autoPool; - - PhInitializeAutoPool(&autoPool); - - cloudDialogHandle = CreateDialog( - PluginInstance->DllBase, - MAKEINTRESOURCE(IDD_PLUGINS_DIALOG), - NULL, - CloudPluginsDlgProc - ); - - if (IsIconic(cloudDialogHandle)) - ShowWindow(cloudDialogHandle, SW_RESTORE); - else - ShowWindow(cloudDialogHandle, SW_SHOW); - - SetForegroundWindow(cloudDialogHandle); - - while (result = GetMessage(&message, NULL, 0, 0)) - { - if (result == -1) - break; - - if (!IsDialogMessage(cloudDialogHandle, &message)) - { - TranslateMessage(&message); - DispatchMessage(&message); - } - - PhDrainAutoPool(&autoPool); - } - - PhDeleteAutoPool(&autoPool); - - return STATUS_SUCCESS; -} - - -VOID ShowPluginManagerDialog( - VOID - ) -{ - HANDLE threadHandle; - - if (threadHandle = PhCreateThread(0, CloudDialogThread, NULL)) - { - NtClose(threadHandle); - } -} \ No newline at end of file diff --git a/plugins/ExtraPlugins/disabled.c b/plugins/ExtraPlugins/disabled.c deleted file mode 100644 index 9d57f680ad6a..000000000000 --- a/plugins/ExtraPlugins/disabled.c +++ /dev/null @@ -1,195 +0,0 @@ -/* - * Process Hacker Extra Plugins - - * Plugin Manager - * - * Copyright (C) 2016 dmex - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include "main.h" - -VOID PhAddDisabledPlugins( - _In_ PPLUGIN_DISABLED_CONTEXT Context - ) -{ - PPH_STRING disabled; - PH_STRINGREF remainingPart; - PH_STRINGREF part; - PPH_STRING displayText; - INT lvItemIndex; - - disabled = PhGetStringSetting(L"DisabledPlugins"); - remainingPart = disabled->sr; - - while (remainingPart.Length) - { - PhSplitStringRefAtChar(&remainingPart, '|', &part, &remainingPart); - - if (part.Length) - { - displayText = PhCreateString2(&part); - - PhAcquireQueuedLockExclusive(&Context->ListLock); - lvItemIndex = PhAddListViewItem(Context->ListViewHandle, MAXINT, PhGetString(displayText), displayText); - PhReleaseQueuedLockExclusive(&Context->ListLock); - - ListView_SetCheckState(Context->ListViewHandle, lvItemIndex, TRUE); - } - } - - PhDereferenceObject(disabled); -} - -INT_PTR CALLBACK DisabledPluginsDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - PPLUGIN_DISABLED_CONTEXT context = NULL; - - if (uMsg == WM_INITDIALOG) - { - context = (PPLUGIN_DISABLED_CONTEXT)PhAllocate(sizeof(PLUGIN_DISABLED_CONTEXT)); - memset(context, 0, sizeof(PLUGIN_DISABLED_CONTEXT)); - - SetProp(hwndDlg, L"Context", (HANDLE)context); - } - else - { - context = (PPLUGIN_DISABLED_CONTEXT)GetProp(hwndDlg, L"Context"); - - if (uMsg == WM_DESTROY) - { - PhDeleteLayoutManager(&context->LayoutManager); - PhUnregisterDialog(hwndDlg); - RemoveProp(hwndDlg, L"Context"); - PhFree(context); - } - } - - if (context == NULL) - return FALSE; - - switch (uMsg) - { - case WM_INITDIALOG: - { - context->DialogHandle = hwndDlg; - context->ListViewHandle = GetDlgItem(hwndDlg, IDC_LIST_DISABLED); - - PhCenterWindow(hwndDlg, GetParent(hwndDlg)); - - PhSetListViewStyle(context->ListViewHandle, FALSE, TRUE); - ListView_SetExtendedListViewStyleEx(context->ListViewHandle, - LVS_EX_CHECKBOXES | LVS_EX_FULLROWSELECT | LVS_EX_DOUBLEBUFFER, - LVS_EX_CHECKBOXES | LVS_EX_FULLROWSELECT | LVS_EX_DOUBLEBUFFER); - PhSetControlTheme(context->ListViewHandle, L"explorer"); - PhAddListViewColumn(context->ListViewHandle, 0, 0, 0, LVCFMT_LEFT, 400, L"Property"); - PhSetExtendedListView(context->ListViewHandle); - - PhInitializeLayoutManager(&context->LayoutManager, hwndDlg); - PhAddLayoutItem(&context->LayoutManager, context->ListViewHandle, NULL, PH_ANCHOR_ALL); - PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDOK), NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_RIGHT); - - PhAddDisabledPlugins(context); - - SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hwndDlg, IDOK), TRUE); - } - break; - case WM_SIZE: - PhLayoutManagerLayout(&context->LayoutManager); - break; - case WM_COMMAND: - { - switch (GET_WM_COMMAND_ID(wParam, lParam)) - { - case IDCANCEL: - case IDOK: - { - EndDialog(hwndDlg, IDOK); - } - break; - } - } - break; - case WM_NOTIFY: - { - LPNMHDR header = (LPNMHDR)lParam; - - if (header->code == LVN_ITEMCHANGED) - { - LPNM_LISTVIEW listView = (LPNM_LISTVIEW)lParam; - - if (!PhTryAcquireReleaseQueuedLockExclusive(&context->ListLock)) - break; - - if (listView->uChanged & LVIF_STATE) - { - switch (listView->uNewState & LVIS_STATEIMAGEMASK) - { - case INDEXTOSTATEIMAGEMASK(2): // checked - { - PPH_STRING param = (PPH_STRING)listView->lParam; - - PhSetPluginDisabled(¶m->sr, TRUE); - - /*if (existingNode = FindTreeNode( - &context->TreeContext, - PLUGIN_STATE_LOCAL, - selectedNode->InternalName - )) - { - existingNode->State = PLUGIN_STATE_RESTART; - }*/ - - //entry->State = PLUGIN_STATE_LOCAL; - - //context->OptionsChanged = TRUE; - } - break; - case INDEXTOSTATEIMAGEMASK(1): // unchecked - { - PPH_STRING param = (PPH_STRING)listView->lParam; - - PhSetPluginDisabled(¶m->sr, FALSE); - - //context->OptionsChanged = TRUE; - } - break; - } - } - } - } - break; - } - - return FALSE; -} - -VOID ShowDisabledPluginsDialog( - _In_ HWND Parent - ) -{ - DialogBox( - PluginInstance->DllBase, - MAKEINTRESOURCE(IDD_DIALOG1), - Parent, - DisabledPluginsDlgProc - ); -} \ No newline at end of file diff --git a/plugins/ExtraPlugins/main.c b/plugins/ExtraPlugins/main.c deleted file mode 100644 index e9a8aff8c18c..000000000000 --- a/plugins/ExtraPlugins/main.c +++ /dev/null @@ -1,351 +0,0 @@ -/* - * Process Hacker Extra Plugins - - * Plugin Manager - * - * Copyright (C) 2016 dmex - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include "main.h" - -PPH_PLUGIN PluginInstance; -PH_CALLBACK_REGISTRATION PluginLoadCallbackRegistration; -PH_CALLBACK_REGISTRATION PluginUnloadCallbackRegistration; -PH_CALLBACK_REGISTRATION PluginShowOptionsCallbackRegistration; -PH_CALLBACK_REGISTRATION MainMenuInitializingCallbackRegistration; -PH_CALLBACK_REGISTRATION PluginMenuItemCallbackRegistration; - -BOOLEAN LastCleanupExpired( - VOID - ) -{ - ULONG64 lastUpdateTimeTicks = 0; - LARGE_INTEGER currentUpdateTimeTicks; - PPH_STRING lastUpdateTimeString; - - PhQuerySystemTime(¤tUpdateTimeTicks); - - lastUpdateTimeString = PhGetStringSetting(SETTING_NAME_LAST_CLEANUP); - PhStringToInteger64(&lastUpdateTimeString->sr, 0, &lastUpdateTimeTicks); - PhDereferenceObject(lastUpdateTimeString); - - if (currentUpdateTimeTicks.QuadPart - lastUpdateTimeTicks >= 25 * PH_TICKS_PER_DAY) - { - PPH_STRING currentUpdateTimeString = PhFormatUInt64(currentUpdateTimeTicks.QuadPart, FALSE); - - PhSetStringSetting2(SETTING_NAME_LAST_CLEANUP, ¤tUpdateTimeString->sr); - - PhDereferenceObject(currentUpdateTimeString); - return TRUE; - } - - return FALSE; -} - -BOOLEAN PluginsCleanupDirectoryCallback( - _In_ PFILE_DIRECTORY_INFORMATION Information, - _In_opt_ PVOID Context - ) -{ - PH_STRINGREF baseName; - PPH_STRING fileName; - PPH_STRING rootDirectoryPath; - - rootDirectoryPath = Context; - baseName.Buffer = Information->FileName; - baseName.Length = Information->FileNameLength; - - if (PhEqualStringRef2(&baseName, L".", TRUE) || PhEqualStringRef2(&baseName, L"..", TRUE)) - return TRUE; - - if (Information->FileAttributes & FILE_ATTRIBUTE_DIRECTORY) - { - HANDLE pluginsDirectoryHandle; - PPH_STRING directoryPath; - PPH_STRING PluginsDirectoryPath; - - directoryPath = PhCreateString2(&baseName); - PluginsDirectoryPath = PhConcatStrings(4, rootDirectoryPath->Buffer, L"\\", directoryPath->Buffer, L"\\"); - - if (NT_SUCCESS(PhCreateFileWin32( - &pluginsDirectoryHandle, - PluginsDirectoryPath->Buffer, - FILE_GENERIC_READ, - 0, - FILE_SHARE_READ, - FILE_OPEN, - FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT - ))) - { - static UNICODE_STRING pattern = RTL_CONSTANT_STRING(L"*"); - - PhEnumDirectoryFile(pluginsDirectoryHandle, &pattern, PluginsCleanupDirectoryCallback, PluginsDirectoryPath); - NtClose(pluginsDirectoryHandle); - } - } - else if (PhEndsWithStringRef2(&baseName, L".bak", TRUE)) - { - NTSTATUS status; - HANDLE fileHandle; - FILE_DISPOSITION_INFORMATION dispositionInfo; - IO_STATUS_BLOCK isb; - - fileName = PhCreateStringEx(NULL, rootDirectoryPath->Length + Information->FileNameLength); - memcpy(fileName->Buffer, rootDirectoryPath->Buffer, rootDirectoryPath->Length); - memcpy(&fileName->Buffer[rootDirectoryPath->Length / 2], Information->FileName, Information->FileNameLength); - - if (NT_SUCCESS(status = PhCreateFileWin32( - &fileHandle, - fileName->Buffer, - FILE_GENERIC_WRITE | DELETE, - 0, - 0, - FILE_OVERWRITE_IF, - FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT - ))) - { - dispositionInfo.DeleteFile = TRUE; - - NtSetInformationFile( - fileHandle, - &isb, - &dispositionInfo, - sizeof(FILE_DISPOSITION_INFORMATION), - FileDispositionInformation - ); - - NtClose(fileHandle); - } - - PhDereferenceObject(fileName); - } - - return TRUE; -} - -VOID PluginsCleanup( - VOID - ) -{ - static UNICODE_STRING pluginsPattern = RTL_CONSTANT_STRING(L"*"); - HANDLE pluginsDirectoryHandle; - PPH_STRING pluginsDirectory; - PPH_STRING PluginsDirectoryPath; - - pluginsDirectory = PhGetStringSetting(L"PluginsDirectory"); - - if (RtlDetermineDosPathNameType_U(PhGetString(pluginsDirectory)) == RtlPathTypeRelative) - { - PluginsDirectoryPath = PhConcatStrings( - 4, - PhGetString(PhGetApplicationDirectory()), - L"\\", - PhGetStringOrEmpty(pluginsDirectory), - L"\\" - ); - PhDereferenceObject(pluginsDirectory); - } - else - { - PluginsDirectoryPath = pluginsDirectory; - } - - if (NT_SUCCESS(PhCreateFileWin32( - &pluginsDirectoryHandle, - PhGetStringOrEmpty(PluginsDirectoryPath), - FILE_GENERIC_READ, - 0, - FILE_SHARE_READ, - FILE_OPEN, - FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT - ))) - { - PhEnumDirectoryFile( - pluginsDirectoryHandle, - &pluginsPattern, - PluginsCleanupDirectoryCallback, - PluginsDirectoryPath - ); - - NtClose(pluginsDirectoryHandle); - } -} - -VOID NTAPI LoadCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - PPH_LIST pluginArgvList = Parameter; - - if (pluginArgvList) - { - for (ULONG i = 0; i < pluginArgvList->Count; i++) - { - PPH_STRING pluginCommandParam = pluginArgvList->Items[i]; - - if (PhEqualString2(pluginCommandParam, L"INSTALL", TRUE)) - { - //PPH_STRING directory; - //PPH_STRING path; - // - //directory = PH_AUTO(PhGetApplicationDirectory()); - //path = PhaCreateString(L"\\plugins"); - //path = PH_AUTO(PhConcatStringRef2(&directory->sr, &path->sr)); - // - //if (MoveFileWithProgress( - // L"new.plugin", - // path->Buffer, - // NULL, - // NULL, - // MOVEFILE_WRITE_THROUGH | MOVEFILE_REPLACE_EXISTING - // )) - //{ - // - //} - - //NtTerminateProcess(NtCurrentProcess(), EXIT_SUCCESS); - } - else if (PhEqualString2(pluginCommandParam, L"UNINSTALL", TRUE)) - { - //NtTerminateProcess(NtCurrentProcess(), EXIT_SUCCESS); - } - } - } - else - { - PluginsCleanup(); - } -} - -VOID NTAPI UnloadCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - NOTHING; -} - -VOID NTAPI MainMenuInitializingCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - PPH_PLUGIN_MENU_INFORMATION menuInfo = Parameter; - PPH_EMENU_ITEM pluginMenu; - - if (menuInfo->u.MainMenu.SubMenuIndex != 0) - return; - - if (pluginMenu = PhFindEMenuItem(menuInfo->Menu, PH_EMENU_FIND_DESCEND, NULL, PHAPP_ID_HACKER_PLUGINS)) - { - PhInsertEMenuItem(menuInfo->Menu, PhPluginCreateEMenuItem(PluginInstance, 0, pluginMenu->Id, L"&Plugins... (Beta)", NULL), PhIndexOfEMenuItem(menuInfo->Menu, pluginMenu)); - PhRemoveEMenuItem(menuInfo->Menu, pluginMenu, 0); - } -} - -VOID NTAPI MenuItemCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - PPH_PLUGIN_MENU_ITEM menuItem = Parameter; - - switch (menuItem->Id) - { - case PHAPP_ID_HACKER_PLUGINS: - ShowPluginManagerDialog(); - break; - } -} - -VOID NTAPI ShowOptionsCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - //ShowOptionsDialog((HWND)Parameter); -} - -LOGICAL DllMain( - _In_ HINSTANCE Instance, - _In_ ULONG Reason, - _Reserved_ PVOID Reserved - ) -{ - switch (Reason) - { - case DLL_PROCESS_ATTACH: - { - PPH_PLUGIN_INFORMATION info; - PH_SETTING_CREATE settings[] = - { - { StringSettingType, SETTING_NAME_TREE_LIST_COLUMNS, L"" }, - { StringSettingType, SETTING_NAME_LAST_CLEANUP, L"" }, - { IntegerPairSettingType, SETTING_NAME_WINDOW_POSITION, L"100,100" }, - { ScalableIntegerPairSettingType, SETTING_NAME_WINDOW_SIZE, L"@96|690,540" } - }; - - PluginInstance = PhRegisterPlugin(PLUGIN_NAME, Instance, &info); - - if (!PluginInstance) - return FALSE; - - info->DisplayName = L"Extra Plugins Manager"; - info->Author = L"dmex"; - info->Description = L"Process Hacker plugins from the community."; - info->HasOptions = FALSE; - - PhRegisterCallback( - PhGetPluginCallback(PluginInstance, PluginCallbackLoad), - LoadCallback, - NULL, - &PluginLoadCallbackRegistration - ); - PhRegisterCallback( - PhGetPluginCallback(PluginInstance, PluginCallbackUnload), - UnloadCallback, - NULL, - &PluginUnloadCallbackRegistration - ); - PhRegisterCallback( - PhGetPluginCallback(PluginInstance, PluginCallbackShowOptions), - ShowOptionsCallback, - NULL, - &PluginShowOptionsCallbackRegistration - ); - PhRegisterCallback( - PhGetGeneralCallback(GeneralCallbackMainMenuInitializing), - MainMenuInitializingCallback, - NULL, - &MainMenuInitializingCallbackRegistration - ); - - PhRegisterCallback( - PhGetPluginCallback(PluginInstance, PluginCallbackMenuItem), - MenuItemCallback, - NULL, - &PluginMenuItemCallbackRegistration - ); - - PhAddSettings(settings, ARRAYSIZE(settings)); - } - break; - } - - return TRUE; -} diff --git a/plugins/ExtraPlugins/main.h b/plugins/ExtraPlugins/main.h deleted file mode 100644 index 36be49543ef1..000000000000 --- a/plugins/ExtraPlugins/main.h +++ /dev/null @@ -1,327 +0,0 @@ -/* - * Process Hacker Extra Plugins - - * Plugin Manager - * - * Copyright (C) 2013 dmex - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#ifndef _WCT_H_ -#define _WCT_H_ - -#define CINTERFACE -#define COBJMACROS -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "resource.h" - -#define IDD_WCT_MENUITEM 1000 -#define WM_ACTION (WM_APP + 601) -#define ID_WCTSHOWCONTEXTMENU 19584 - -#define PLUGIN_NAME L"dmex.ExtraPlugins" -#define SETTING_NAME_TREE_LIST_COLUMNS (PLUGIN_NAME L".TreeListColumns") -#define SETTING_NAME_WINDOW_POSITION (PLUGIN_NAME L".WindowPosition") -#define SETTING_NAME_WINDOW_SIZE (PLUGIN_NAME L".WindowSize") -#define SETTING_NAME_LAST_CLEANUP (PLUGIN_NAME L".LastCleanupCheckTime") - -#define ID_UPDATE_ADD (WM_APP + 8002) -#define ID_UPDATE_COUNT (WM_APP + 8003) - -#define MAKE_VERSION_ULONGLONG(major, minor, build, revision) \ - (((ULONGLONG)(major) << 48) | \ - ((ULONGLONG)(minor) << 32) | \ - ((ULONGLONG)(build) << 16) | \ - ((ULONGLONG)(revision) << 0)) - -extern PPH_PLUGIN PluginInstance; - -typedef enum _TREE_PLUGIN_STATE -{ - PLUGIN_STATE_LOCAL, - PLUGIN_STATE_RESTART, - PLUGIN_STATE_REMOTE, - PLUGIN_STATE_UPDATE -} TREE_PLUGIN_STATE; - -typedef enum _WCT_TREE_COLUMN_ITEM_NAME -{ - TREE_COLUMN_ITEM_NAME, - TREE_COLUMN_ITEM_AUTHOR, - TREE_COLUMN_ITEM_VERSION, - TREE_COLUMN_ITEM_MAXIMUM -} WCT_TREE_COLUMN_ITEM_NAME; - -typedef struct _PHAPP_PLUGIN -{ - // Public - PH_AVL_LINKS Links; - PVOID Reserved; - PVOID DllBase; - // end - - // Private - PPH_STRING FileName; - ULONG Flags; - PH_STRINGREF Name; - PH_PLUGIN_INFORMATION Information; - - PH_CALLBACK Callbacks[PluginCallbackMaximum]; -} PHAPP_PLUGIN, *PPHAPP_PLUGIN; - -typedef struct _PLUGIN_NODE -{ - PH_TREENEW_NODE Node; - - HICON Icon; - TREE_PLUGIN_STATE State; - - BOOLEAN PluginOptions; - PPHAPP_PLUGIN PluginInstance; - - // Local - PPH_STRING FilePath; - PPH_STRING InternalName; - - // Remote - PPH_STRING Id; - PPH_STRING Name; - PPH_STRING Version; - PPH_STRING Author; - PPH_STRING Description; - PPH_STRING IconUrl; - PPH_STRING Requirements; - PPH_STRING FeedbackUrl; - PPH_STRING Screenshots; - PPH_STRING AddedTime; - PPH_STRING UpdatedTime; - PPH_STRING Download_count; - PPH_STRING Download_link_32; - PPH_STRING Download_link_64; - PPH_STRING SHA2_32; - PPH_STRING SHA2_64; - PPH_STRING HASH_32; - PPH_STRING HASH_64; - PPH_STRING FileName; - - PH_STRINGREF TextCache[TREE_COLUMN_ITEM_MAXIMUM]; -} PLUGIN_NODE, *PPLUGIN_NODE; - -typedef struct _WCT_CONTEXT -{ - HWND DialogHandle; - HWND SearchHandle; - HWND TreeNewHandle; - HWND ParentWindowHandle; - - PPH_STRING SearchboxText; - PPH_STRING TreeText; - HFONT NormalFontHandle; - HFONT BoldFontHandle; - HFONT TitleFontHandle; - - TREE_PLUGIN_STATE Type; - HWND PluginMenuActive; - UINT PluginMenuActiveId; - - PH_LAYOUT_MANAGER LayoutManager; - - ULONG TreeNewSortColumn; - PH_SORT_ORDER TreeNewSortOrder; - PH_TN_FILTER_SUPPORT FilterSupport; - PPH_HASHTABLE NodeHashtable; - PPH_LIST NodeList; -} WCT_CONTEXT, *PWCT_CONTEXT; - -// dialog.c -VOID ShowPluginManagerDialog(VOID); - -// disabled.c -VOID ShowDisabledPluginsDialog(_In_ HWND Parent); - -typedef struct _PLUGIN_DISABLED_CONTEXT -{ - PH_QUEUED_LOCK ListLock; - HWND DialogHandle; - HWND ListViewHandle; - PH_LAYOUT_MANAGER LayoutManager; -} PLUGIN_DISABLED_CONTEXT, *PPLUGIN_DISABLED_CONTEXT; - -ULONG PhDisabledPluginsCount(VOID); - -// plugin.c -PWSTR PhGetPluginBaseName(_In_ PPHAPP_PLUGIN Plugin); -BOOLEAN PhIsPluginLoadedByBaseName(_In_ PPH_STRINGREF BaseName); -BOOLEAN PhIsPluginDisabled(_In_ PPH_STRINGREF BaseName); -VOID PhSetPluginDisabled(_In_ PPH_STRINGREF BaseName, _In_ BOOLEAN Disable); - -VOID InitializePluginsTree( - _In_ PWCT_CONTEXT context, - _In_ HWND ParentWindowHandle, - _In_ HWND TreeNewHandle - ); - -VOID DeletePluginsTree( - _In_ PWCT_CONTEXT Context - ); - -struct _PH_TN_FILTER_SUPPORT* GetPluginListFilterSupport( - _In_ PWCT_CONTEXT Context - ); - -VOID PluginsAddTreeNode( - _In_ PWCT_CONTEXT Context, - _In_ PPLUGIN_NODE Entry - ); - -PPLUGIN_NODE FindTreeNode( - _In_ PWCT_CONTEXT Context, - _In_ TREE_PLUGIN_STATE Type, - _In_ PPH_STRING InternalName - ); - -VOID WeRemoveWindowNode( - _In_ PWCT_CONTEXT Context, - _In_ PPLUGIN_NODE WindowNode - ); - -VOID PluginsClearTree( - _In_ PWCT_CONTEXT Context - ); - -PPLUGIN_NODE WeGetSelectedWindowNode( - _In_ PWCT_CONTEXT Context - ); - -VOID WeGetSelectedWindowNodes( - _In_ PWCT_CONTEXT Context, - _Out_ PPLUGIN_NODE **Windows, - _Out_ PULONG NumberOfWindows - ); - -NTSTATUS QueryPluginsCallbackThread(_In_ PVOID Parameter); -VOID EnumerateLoadedPlugins(_In_ PWCT_CONTEXT Context); - -typedef enum _PLUGIN_ACTION -{ - PLUGIN_ACTION_RESTORE, - PLUGIN_ACTION_INSTALL, - PLUGIN_ACTION_UNINSTALL, - PLUGIN_ACTION_RESTART -} PLUGIN_ACTION; - -typedef struct _PH_UPDATER_CONTEXT -{ - BOOLEAN FixedWindowStyles; - HWND DialogHandle; - HICON IconSmallHandle; - HICON IconLargeHandle; - - PLUGIN_ACTION Action; - PPLUGIN_NODE Node; - - PPH_STRING SetupFilePath; -} PH_UPDATER_CONTEXT, *PPH_UPDATER_CONTEXT; - -BOOLEAN ShowUpdateDialog( - _In_ HWND Parent, - _In_ PLUGIN_ACTION Action - ); - -BOOLEAN StartInitialCheck( - _In_ HWND Parent, - _In_ PPLUGIN_NODE Node, - _In_ PLUGIN_ACTION Action - ); - -// page1.c -VOID ShowAvailableDialog(_In_ PPH_UPDATER_CONTEXT Context); -VOID TaskDialogLinkClicked(_In_ PPH_UPDATER_CONTEXT Context); -VOID ShowProgressDialog(_In_ PPH_UPDATER_CONTEXT Context); -VOID ShowPluginUninstallDialog(_In_ PPH_UPDATER_CONTEXT Context); -VOID ShowUpdateFailedDialog( - _In_ PPH_UPDATER_CONTEXT Context, - _In_ BOOLEAN HashFailed, - _In_ BOOLEAN SignatureFailed - ); -VOID ShowPluginUninstallWithoutPrompt( - _In_ PPH_UPDATER_CONTEXT Context - ); - -// page6.c -VOID ShowInstallRestartDialog(_In_ PPH_UPDATER_CONTEXT Context); -VOID ShowUninstallRestartDialog(_In_ PPH_UPDATER_CONTEXT Context); - -NTSTATUS UpdateDownloadThread(_In_ PVOID Parameter); -NTSTATUS SetupExtractBuild(_In_ PVOID Parameter); - -BOOLEAN ReadRequestString( - _In_ HINTERNET Handle, - _Out_ _Deref_post_z_cap_(*DataLength) PSTR *Data, - _Out_ ULONG *DataLength - ); - -// verify.c -typedef struct _UPDATER_HASH_CONTEXT -{ - BCRYPT_ALG_HANDLE SignAlgHandle; - BCRYPT_ALG_HANDLE HashAlgHandle; - BCRYPT_KEY_HANDLE KeyHandle; - BCRYPT_HASH_HANDLE HashHandle; - ULONG HashObjectSize; - ULONG HashSize; - PVOID HashObject; - PVOID Hash; -} UPDATER_HASH_CONTEXT, *PUPDATER_HASH_CONTEXT; - -BOOLEAN UpdaterInitializeHash( - _Out_ PUPDATER_HASH_CONTEXT *Context - ); - -BOOLEAN UpdaterUpdateHash( - _Inout_ PUPDATER_HASH_CONTEXT Context, - _In_reads_bytes_(Length) PVOID Buffer, - _In_ ULONG Length - ); - -BOOLEAN UpdaterVerifyHash( - _Inout_ PUPDATER_HASH_CONTEXT Context, - _In_ PPH_STRING Sha2Hash - ); - -BOOLEAN UpdaterVerifySignature( - _Inout_ PUPDATER_HASH_CONTEXT Context, - _In_ PPH_STRING HexSignature - ); - -VOID UpdaterDestroyHash( - _Inout_ PUPDATER_HASH_CONTEXT Context - ); - -#endif \ No newline at end of file diff --git a/plugins/ExtraPlugins/miniz/miniz.c b/plugins/ExtraPlugins/miniz/miniz.c deleted file mode 100644 index 95830af8f120..000000000000 --- a/plugins/ExtraPlugins/miniz/miniz.c +++ /dev/null @@ -1,4190 +0,0 @@ -/* miniz.c v1.15 - public domain deflate/inflate, zlib-subset, ZIP reading/writing/appending, PNG writing - See "unlicense" statement at the end of this file. - Rich Geldreich , last updated Oct. 13, 2013 - Implements RFC 1950: http://www.ietf.org/rfc/rfc1950.txt and RFC 1951: http://www.ietf.org/rfc/rfc1951.txt - - Most API's defined in miniz.c are optional. For example, to disable the archive related functions just define - MINIZ_NO_ARCHIVE_APIS, or to get rid of all stdio usage define MINIZ_NO_STDIO (see the list below for more macros). - - * Change History - 10/13/13 v1.15 r4 - Interim bugfix release while I work on the next major release with Zip64 support (almost there!): - - Critical fix for the MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY bug (thanks kahmyong.moon@hp.com) which could cause locate files to not find files. This bug - would only have occured in earlier versions if you explicitly used this flag, OR if you used mz_zip_extract_archive_file_to_heap() or mz_zip_add_mem_to_archive_file_in_place() - (which used this flag). If you can't switch to v1.15 but want to fix this bug, just remove the uses of this flag from both helper funcs (and of course don't use the flag). - - Bugfix in mz_zip_reader_extract_to_mem_no_alloc() from kymoon when pUser_read_buf is not NULL and compressed size is > uncompressed size - - Fixing mz_zip_reader_extract_*() funcs so they don't try to extract compressed data from directory entries, to account for weird zipfiles which contain zero-size compressed data on dir entries. - Hopefully this fix won't cause any issues on weird zip archives, because it assumes the low 16-bits of zip external attributes are DOS attributes (which I believe they always are in practice). - - Fixing mz_zip_reader_is_file_a_directory() so it doesn't check the internal attributes, just the filename and external attributes - - mz_zip_reader_init_file() - missing MZ_FCLOSE() call if the seek failed - - Added cmake support for Linux builds which builds all the examples, tested with clang v3.3 and gcc v4.6. - - Clang fix for tdefl_write_image_to_png_file_in_memory() from toffaletti - - Merged MZ_FORCEINLINE fix from hdeanclark - - Fix include before config #ifdef, thanks emil.brink - - Added tdefl_write_image_to_png_file_in_memory_ex(): supports Y flipping (super useful for OpenGL apps), and explicit control over the compression level (so you can - set it to 1 for real-time compression). - - Merged in some compiler fixes from paulharris's github repro. - - Retested this build under Windows (VS 2010, including static analysis), tcc 0.9.26, gcc v4.6 and clang v3.3. - - Added example6.c, which dumps an image of the mandelbrot set to a PNG file. - - Modified example2 to help test the MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY flag more. - - In r3: Bugfix to mz_zip_writer_add_file() found during merge: Fix possible src file fclose() leak if alignment bytes+local header file write faiiled - - In r4: Minor bugfix to mz_zip_writer_add_from_zip_reader(): Was pushing the wrong central dir header offset, appears harmless in this release, but it became a problem in the zip64 branch - 5/20/12 v1.14 - MinGW32/64 GCC 4.6.1 compiler fixes: added MZ_FORCEINLINE, #include (thanks fermtect). - 5/19/12 v1.13 - From jason@cornsyrup.org and kelwert@mtu.edu - Fix mz_crc32() so it doesn't compute the wrong CRC-32's when mz_ulong is 64-bit. - - Temporarily/locally slammed in "typedef unsigned long mz_ulong" and re-ran a randomized regression test on ~500k files. - - Eliminated a bunch of warnings when compiling with GCC 32-bit/64. - - Ran all examples, miniz.c, and tinfl.c through MSVC 2008's /analyze (static analysis) option and fixed all warnings (except for the silly - "Use of the comma-operator in a tested expression.." analysis warning, which I purposely use to work around a MSVC compiler warning). - - Created 32-bit and 64-bit Codeblocks projects/workspace. Built and tested Linux executables. The codeblocks workspace is compatible with Linux+Win32/x64. - - Added miniz_tester solution/project, which is a useful little app derived from LZHAM's tester app that I use as part of the regression test. - - Ran miniz.c and tinfl.c through another series of regression testing on ~500,000 files and archives. - - Modified example5.c so it purposely disables a bunch of high-level functionality (MINIZ_NO_STDIO, etc.). (Thanks to corysama for the MINIZ_NO_STDIO bug report.) - - Fix ftell() usage in examples so they exit with an error on files which are too large (a limitation of the examples, not miniz itself). - 4/12/12 v1.12 - More comments, added low-level example5.c, fixed a couple minor level_and_flags issues in the archive API's. - level_and_flags can now be set to MZ_DEFAULT_COMPRESSION. Thanks to Bruce Dawson for the feedback/bug report. - 5/28/11 v1.11 - Added statement from unlicense.org - 5/27/11 v1.10 - Substantial compressor optimizations: - - Level 1 is now ~4x faster than before. The L1 compressor's throughput now varies between 70-110MB/sec. on a - - Core i7 (actual throughput varies depending on the type of data, and x64 vs. x86). - - Improved baseline L2-L9 compression perf. Also, greatly improved compression perf. issues on some file types. - - Refactored the compression code for better readability and maintainability. - - Added level 10 compression level (L10 has slightly better ratio than level 9, but could have a potentially large - drop in throughput on some files). - 5/15/11 v1.09 - Initial stable release. - - * Low-level Deflate/Inflate implementation notes: - - Compression: Use the "tdefl" API's. The compressor supports raw, static, and dynamic blocks, lazy or - greedy parsing, match length filtering, RLE-only, and Huffman-only streams. It performs and compresses - approximately as well as zlib. - - Decompression: Use the "tinfl" API's. The entire decompressor is implemented as a single function - coroutine: see tinfl_decompress(). It supports decompression into a 32KB (or larger power of 2) wrapping buffer, or into a memory - block large enough to hold the entire file. - - The low-level tdefl/tinfl API's do not make any use of dynamic memory allocation. - - * zlib-style API notes: - - miniz.c implements a fairly large subset of zlib. There's enough functionality present for it to be a drop-in - zlib replacement in many apps: - The z_stream struct, optional memory allocation callbacks - deflateInit/deflateInit2/deflate/deflateReset/deflateEnd/deflateBound - inflateInit/inflateInit2/inflate/inflateEnd - compress, compress2, compressBound, uncompress - CRC-32, Adler-32 - Using modern, minimal code size, CPU cache friendly routines. - Supports raw deflate streams or standard zlib streams with adler-32 checking. - - Limitations: - The callback API's are not implemented yet. No support for gzip headers or zlib static dictionaries. - I've tried to closely emulate zlib's various flavors of stream flushing and return status codes, but - there are no guarantees that miniz.c pulls this off perfectly. - - * PNG writing: See the tdefl_write_image_to_png_file_in_memory() function, originally written by - Alex Evans. Supports 1-4 bytes/pixel images. - - * ZIP archive API notes: - - The ZIP archive API's where designed with simplicity and efficiency in mind, with just enough abstraction to - get the job done with minimal fuss. There are simple API's to retrieve file information, read files from - existing archives, create new archives, append new files to existing archives, or clone archive data from - one archive to another. It supports archives located in memory or the heap, on disk (using stdio.h), - or you can specify custom file read/write callbacks. - - - Archive reading: Just call this function to read a single file from a disk archive: - - void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, - size_t *pSize, mz_uint zip_flags); - - For more complex cases, use the "mz_zip_reader" functions. Upon opening an archive, the entire central - directory is located and read as-is into memory, and subsequent file access only occurs when reading individual files. - - - Archives file scanning: The simple way is to use this function to scan a loaded archive for a specific file: - - int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags); - - The locate operation can optionally check file comments too, which (as one example) can be used to identify - multiple versions of the same file in an archive. This function uses a simple linear search through the central - directory, so it's not very fast. - - Alternately, you can iterate through all the files in an archive (using mz_zip_reader_get_num_files()) and - retrieve detailed info on each file by calling mz_zip_reader_file_stat(). - - - Archive creation: Use the "mz_zip_writer" functions. The ZIP writer immediately writes compressed file data - to disk and builds an exact image of the central directory in memory. The central directory image is written - all at once at the end of the archive file when the archive is finalized. - - The archive writer can optionally align each file's local header and file data to any power of 2 alignment, - which can be useful when the archive will be read from optical media. Also, the writer supports placing - arbitrary data blobs at the very beginning of ZIP archives. Archives written using either feature are still - readable by any ZIP tool. - - - Archive appending: The simple way to add a single file to an archive is to call this function: - - mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const char *pArchive_name, - const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags); - - The archive will be created if it doesn't already exist, otherwise it'll be appended to. - Note the appending is done in-place and is not an atomic operation, so if something goes wrong - during the operation it's possible the archive could be left without a central directory (although the local - file headers and file data will be fine, so the archive will be recoverable). - - For more complex archive modification scenarios: - 1. The safest way is to use a mz_zip_reader to read the existing archive, cloning only those bits you want to - preserve into a new archive using using the mz_zip_writer_add_from_zip_reader() function (which compiles the - compressed file data as-is). When you're done, delete the old archive and rename the newly written archive, and - you're done. This is safe but requires a bunch of temporary disk space or heap memory. - - 2. Or, you can convert an mz_zip_reader in-place to an mz_zip_writer using mz_zip_writer_init_from_reader(), - append new files as needed, then finalize the archive which will write an updated central directory to the - original archive. (This is basically what mz_zip_add_mem_to_archive_file_in_place() does.) There's a - possibility that the archive's central directory could be lost with this method if anything goes wrong, though. - - - ZIP archive support limitations: - No zip64 or spanning support. Extraction functions can only handle unencrypted, stored or deflated files. - Requires streams capable of seeking. - - * This is a header file library, like stb_image.c. To get only a header file, either cut and paste the - below header, or create miniz.h, #define MINIZ_HEADER_FILE_ONLY, and then include miniz.c from it. - - * Important: For best perf. be sure to customize the below macros for your target platform: - #define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1 - #define MINIZ_LITTLE_ENDIAN 1 - #define MINIZ_HAS_64BIT_REGISTERS 1 - - * On platforms using glibc, Be sure to "#define _LARGEFILE64_SOURCE 1" before including miniz.c to ensure miniz - uses the 64-bit variants: fopen64(), stat64(), etc. Otherwise you won't be able to process large files - (i.e. 32-bit stat() fails for me on files > 0x7FFFFFFF bytes). -*/ - -#include "miniz.h" -#include -#include - -typedef unsigned char mz_validate_uint16[sizeof(mz_uint16) == 2 ? 1 : -1]; -typedef unsigned char mz_validate_uint32[sizeof(mz_uint32) == 4 ? 1 : -1]; -typedef unsigned char mz_validate_uint64[sizeof(mz_uint64) == 8 ? 1 : -1]; - -#define MZ_ASSERT(x) assert(x) - -#ifdef MINIZ_NO_MALLOC -#define MZ_MALLOC(x) NULL -#define MZ_FREE(x) (void)x, ((void)0) -#define MZ_REALLOC(p, x) NULL -#else -#define MZ_MALLOC(x) malloc(x) -#define MZ_FREE(x) free(x) -#define MZ_REALLOC(p, x) realloc(p, x) -#endif - -#define MZ_MAX(a,b) (((a)>(b))?(a):(b)) -#define MZ_MIN(a,b) (((a)<(b))?(a):(b)) -#define MZ_CLEAR_OBJ(obj) memset(&(obj), 0, sizeof(obj)) - -#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN -#define MZ_READ_LE16(p) *((const mz_uint16 *)(p)) -#define MZ_READ_LE32(p) *((const mz_uint32 *)(p)) -#else -#define MZ_READ_LE16(p) ((mz_uint32)(((const mz_uint8 *)(p))[0]) | ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U)) -#define MZ_READ_LE32(p) ((mz_uint32)(((const mz_uint8 *)(p))[0]) | ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U) | ((mz_uint32)(((const mz_uint8 *)(p))[2]) << 16U) | ((mz_uint32)(((const mz_uint8 *)(p))[3]) << 24U)) -#endif - -#ifdef _MSC_VER -#define MZ_FORCEINLINE __forceinline -#elif defined(__GNUC__) -#define MZ_FORCEINLINE inline __attribute__((__always_inline__)) -#else -#define MZ_FORCEINLINE inline -#endif - - -// ------------------- zlib-style API's - -mz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len) -{ - mz_uint32 i, s1 = (mz_uint32)(adler & 0xffff), s2 = (mz_uint32)(adler >> 16); size_t block_len = buf_len % 5552; - if (!ptr) return MZ_ADLER32_INIT; - while (buf_len) { - for (i = 0; i + 7 < block_len; i += 8, ptr += 8) { - s1 += ptr[0], s2 += s1; s1 += ptr[1], s2 += s1; s1 += ptr[2], s2 += s1; s1 += ptr[3], s2 += s1; - s1 += ptr[4], s2 += s1; s1 += ptr[5], s2 += s1; s1 += ptr[6], s2 += s1; s1 += ptr[7], s2 += s1; - } - for (; i < block_len; ++i) s1 += *ptr++, s2 += s1; - s1 %= 65521U, s2 %= 65521U; buf_len -= block_len; block_len = 5552; - } - return (s2 << 16) + s1; -} - -// Karl Malbrain's compact CRC-32. See "A compact CCITT crc16 and crc32 C implementation that balances processor cache usage against speed": http://www.geocities.com/malbrain/ -mz_ulong mz_crc32(mz_ulong crc, const unsigned char *ptr, size_t buf_len) -{ - static const mz_uint32 s_crc32[16] = { 0, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, - 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c }; - mz_uint32 crcu32 = (mz_uint32)crc; - if (!ptr) return MZ_CRC32_INIT; - crcu32 = ~crcu32; while (buf_len--) { mz_uint8 b = *ptr++; crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b & 0xF)]; crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b >> 4)]; } - return ~crcu32; -} - -void mz_free(void *p) -{ - MZ_FREE(p); -} - -#ifndef MINIZ_NO_ZLIB_APIS - -static void *def_alloc_func(void *opaque, size_t items, size_t size) { (void)opaque, (void)items, (void)size; return MZ_MALLOC(items * size); } -static void def_free_func(void *opaque, void *address) { (void)opaque, (void)address; MZ_FREE(address); } -static void *def_realloc_func(void *opaque, void *address, size_t items, size_t size) { (void)opaque, (void)address, (void)items, (void)size; return MZ_REALLOC(address, items * size); } - -const char *mz_version(void) -{ - return MZ_VERSION; -} - -int mz_deflateInit(mz_streamp pStream, int level) -{ - return mz_deflateInit2(pStream, level, MZ_DEFLATED, MZ_DEFAULT_WINDOW_BITS, 9, MZ_DEFAULT_STRATEGY); -} - -int mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits, int mem_level, int strategy) -{ - tdefl_compressor *pComp; - mz_uint comp_flags = TDEFL_COMPUTE_ADLER32 | tdefl_create_comp_flags_from_zip_params(level, window_bits, strategy); - - if (!pStream) return MZ_STREAM_ERROR; - if ((method != MZ_DEFLATED) || ((mem_level < 1) || (mem_level > 9)) || ((window_bits != MZ_DEFAULT_WINDOW_BITS) && (-window_bits != MZ_DEFAULT_WINDOW_BITS))) return MZ_PARAM_ERROR; - - pStream->data_type = 0; - pStream->adler = MZ_ADLER32_INIT; - pStream->msg = NULL; - pStream->reserved = 0; - pStream->total_in = 0; - pStream->total_out = 0; - if (!pStream->zalloc) pStream->zalloc = def_alloc_func; - if (!pStream->zfree) pStream->zfree = def_free_func; - - pComp = (tdefl_compressor *)pStream->zalloc(pStream->opaque, 1, sizeof(tdefl_compressor)); - if (!pComp) - return MZ_MEM_ERROR; - - pStream->state = (struct mz_internal_state *)pComp; - - if (tdefl_init(pComp, NULL, NULL, comp_flags) != TDEFL_STATUS_OKAY) - { - mz_deflateEnd(pStream); - return MZ_PARAM_ERROR; - } - - return MZ_OK; -} - -int mz_deflateReset(mz_streamp pStream) -{ - if ((!pStream) || (!pStream->state) || (!pStream->zalloc) || (!pStream->zfree)) return MZ_STREAM_ERROR; - pStream->total_in = pStream->total_out = 0; - tdefl_init((tdefl_compressor*)pStream->state, NULL, NULL, ((tdefl_compressor*)pStream->state)->m_flags); - return MZ_OK; -} - -int mz_deflate(mz_streamp pStream, int flush) -{ - size_t in_bytes, out_bytes; - mz_ulong orig_total_in, orig_total_out; - int mz_status = MZ_OK; - - if ((!pStream) || (!pStream->state) || (flush < 0) || (flush > MZ_FINISH) || (!pStream->next_out)) return MZ_STREAM_ERROR; - if (!pStream->avail_out) return MZ_BUF_ERROR; - - if (flush == MZ_PARTIAL_FLUSH) flush = MZ_SYNC_FLUSH; - - if (((tdefl_compressor*)pStream->state)->m_prev_return_status == TDEFL_STATUS_DONE) - return (flush == MZ_FINISH) ? MZ_STREAM_END : MZ_BUF_ERROR; - - orig_total_in = pStream->total_in; orig_total_out = pStream->total_out; - for (; ; ) - { - tdefl_status defl_status; - in_bytes = pStream->avail_in; out_bytes = pStream->avail_out; - - defl_status = tdefl_compress((tdefl_compressor*)pStream->state, pStream->next_in, &in_bytes, pStream->next_out, &out_bytes, (tdefl_flush)flush); - pStream->next_in += (mz_uint)in_bytes; pStream->avail_in -= (mz_uint)in_bytes; - pStream->total_in += (mz_uint)in_bytes; pStream->adler = tdefl_get_adler32((tdefl_compressor*)pStream->state); - - pStream->next_out += (mz_uint)out_bytes; pStream->avail_out -= (mz_uint)out_bytes; - pStream->total_out += (mz_uint)out_bytes; - - if (defl_status < 0) - { - mz_status = MZ_STREAM_ERROR; - break; - } - else if (defl_status == TDEFL_STATUS_DONE) - { - mz_status = MZ_STREAM_END; - break; - } - else if (!pStream->avail_out) - break; - else if ((!pStream->avail_in) && (flush != MZ_FINISH)) - { - if ((flush) || (pStream->total_in != orig_total_in) || (pStream->total_out != orig_total_out)) - break; - return MZ_BUF_ERROR; // Can't make forward progress without some input. - } - } - return mz_status; -} - -int mz_deflateEnd(mz_streamp pStream) -{ - if (!pStream) return MZ_STREAM_ERROR; - if (pStream->state) - { - pStream->zfree(pStream->opaque, pStream->state); - pStream->state = NULL; - } - return MZ_OK; -} - -mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len) -{ - (void)pStream; - // This is really over conservative. (And lame, but it's actually pretty tricky to compute a true upper bound given the way tdefl's blocking works.) - return MZ_MAX(128 + (source_len * 110) / 100, 128 + source_len + ((source_len / (31 * 1024)) + 1) * 5); -} - -int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len, int level) -{ - int status; - mz_stream stream; - memset(&stream, 0, sizeof(stream)); - - // In case mz_ulong is 64-bits (argh I hate longs). - if ((source_len | *pDest_len) > 0xFFFFFFFFU) return MZ_PARAM_ERROR; - - stream.next_in = pSource; - stream.avail_in = (mz_uint32)source_len; - stream.next_out = pDest; - stream.avail_out = (mz_uint32)*pDest_len; - - status = mz_deflateInit(&stream, level); - if (status != MZ_OK) return status; - - status = mz_deflate(&stream, MZ_FINISH); - if (status != MZ_STREAM_END) - { - mz_deflateEnd(&stream); - return (status == MZ_OK) ? MZ_BUF_ERROR : status; - } - - *pDest_len = stream.total_out; - return mz_deflateEnd(&stream); -} - -int mz_compress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len) -{ - return mz_compress2(pDest, pDest_len, pSource, source_len, MZ_DEFAULT_COMPRESSION); -} - -mz_ulong mz_compressBound(mz_ulong source_len) -{ - return mz_deflateBound(NULL, source_len); -} - -typedef struct -{ - tinfl_decompressor m_decomp; - mz_uint m_dict_ofs, m_dict_avail, m_first_call, m_has_flushed; int m_window_bits; - mz_uint8 m_dict[TINFL_LZ_DICT_SIZE]; - tinfl_status m_last_status; -} inflate_state; - -int mz_inflateInit2(mz_streamp pStream, int window_bits) -{ - inflate_state *pDecomp; - if (!pStream) return MZ_STREAM_ERROR; - if ((window_bits != MZ_DEFAULT_WINDOW_BITS) && (-window_bits != MZ_DEFAULT_WINDOW_BITS)) return MZ_PARAM_ERROR; - - pStream->data_type = 0; - pStream->adler = 0; - pStream->msg = NULL; - pStream->total_in = 0; - pStream->total_out = 0; - pStream->reserved = 0; - if (!pStream->zalloc) pStream->zalloc = def_alloc_func; - if (!pStream->zfree) pStream->zfree = def_free_func; - - pDecomp = (inflate_state*)pStream->zalloc(pStream->opaque, 1, sizeof(inflate_state)); - if (!pDecomp) return MZ_MEM_ERROR; - - pStream->state = (struct mz_internal_state *)pDecomp; - - tinfl_init(&pDecomp->m_decomp); - pDecomp->m_dict_ofs = 0; - pDecomp->m_dict_avail = 0; - pDecomp->m_last_status = TINFL_STATUS_NEEDS_MORE_INPUT; - pDecomp->m_first_call = 1; - pDecomp->m_has_flushed = 0; - pDecomp->m_window_bits = window_bits; - - return MZ_OK; -} - -int mz_inflateInit(mz_streamp pStream) -{ - return mz_inflateInit2(pStream, MZ_DEFAULT_WINDOW_BITS); -} - -int mz_inflate(mz_streamp pStream, int flush) -{ - inflate_state* pState; - mz_uint n, first_call, decomp_flags = TINFL_FLAG_COMPUTE_ADLER32; - size_t in_bytes, out_bytes, orig_avail_in; - tinfl_status status; - - if ((!pStream) || (!pStream->state)) return MZ_STREAM_ERROR; - if (flush == MZ_PARTIAL_FLUSH) flush = MZ_SYNC_FLUSH; - if ((flush) && (flush != MZ_SYNC_FLUSH) && (flush != MZ_FINISH)) return MZ_STREAM_ERROR; - - pState = (inflate_state*)pStream->state; - if (pState->m_window_bits > 0) decomp_flags |= TINFL_FLAG_PARSE_ZLIB_HEADER; - orig_avail_in = pStream->avail_in; - - first_call = pState->m_first_call; pState->m_first_call = 0; - if (pState->m_last_status < 0) return MZ_DATA_ERROR; - - if (pState->m_has_flushed && (flush != MZ_FINISH)) return MZ_STREAM_ERROR; - pState->m_has_flushed |= (flush == MZ_FINISH); - - if ((flush == MZ_FINISH) && (first_call)) - { - // MZ_FINISH on the first call implies that the input and output buffers are large enough to hold the entire compressed/decompressed file. - decomp_flags |= TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF; - in_bytes = pStream->avail_in; out_bytes = pStream->avail_out; - status = tinfl_decompress(&pState->m_decomp, pStream->next_in, &in_bytes, pStream->next_out, pStream->next_out, &out_bytes, decomp_flags); - pState->m_last_status = status; - pStream->next_in += (mz_uint)in_bytes; pStream->avail_in -= (mz_uint)in_bytes; pStream->total_in += (mz_uint)in_bytes; - pStream->adler = tinfl_get_adler32(&pState->m_decomp); - pStream->next_out += (mz_uint)out_bytes; pStream->avail_out -= (mz_uint)out_bytes; pStream->total_out += (mz_uint)out_bytes; - - if (status < 0) - return MZ_DATA_ERROR; - else if (status != TINFL_STATUS_DONE) - { - pState->m_last_status = TINFL_STATUS_FAILED; - return MZ_BUF_ERROR; - } - return MZ_STREAM_END; - } - // flush != MZ_FINISH then we must assume there's more input. - if (flush != MZ_FINISH) decomp_flags |= TINFL_FLAG_HAS_MORE_INPUT; - - if (pState->m_dict_avail) - { - n = MZ_MIN(pState->m_dict_avail, pStream->avail_out); - memcpy(pStream->next_out, pState->m_dict + pState->m_dict_ofs, n); - pStream->next_out += n; pStream->avail_out -= n; pStream->total_out += n; - pState->m_dict_avail -= n; pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1); - return ((pState->m_last_status == TINFL_STATUS_DONE) && (!pState->m_dict_avail)) ? MZ_STREAM_END : MZ_OK; - } - - for (; ; ) - { - in_bytes = pStream->avail_in; - out_bytes = TINFL_LZ_DICT_SIZE - pState->m_dict_ofs; - - status = tinfl_decompress(&pState->m_decomp, pStream->next_in, &in_bytes, pState->m_dict, pState->m_dict + pState->m_dict_ofs, &out_bytes, decomp_flags); - pState->m_last_status = status; - - pStream->next_in += (mz_uint)in_bytes; pStream->avail_in -= (mz_uint)in_bytes; - pStream->total_in += (mz_uint)in_bytes; pStream->adler = tinfl_get_adler32(&pState->m_decomp); - - pState->m_dict_avail = (mz_uint)out_bytes; - - n = MZ_MIN(pState->m_dict_avail, pStream->avail_out); - memcpy(pStream->next_out, pState->m_dict + pState->m_dict_ofs, n); - pStream->next_out += n; pStream->avail_out -= n; pStream->total_out += n; - pState->m_dict_avail -= n; pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1); - - if (status < 0) - return MZ_DATA_ERROR; // Stream is corrupted (there could be some uncompressed data left in the output dictionary - oh well). - else if ((status == TINFL_STATUS_NEEDS_MORE_INPUT) && (!orig_avail_in)) - return MZ_BUF_ERROR; // Signal caller that we can't make forward progress without supplying more input or by setting flush to MZ_FINISH. - else if (flush == MZ_FINISH) - { - // The output buffer MUST be large to hold the remaining uncompressed data when flush==MZ_FINISH. - if (status == TINFL_STATUS_DONE) - return pState->m_dict_avail ? MZ_BUF_ERROR : MZ_STREAM_END; - // status here must be TINFL_STATUS_HAS_MORE_OUTPUT, which means there's at least 1 more byte on the way. If there's no more room left in the output buffer then something is wrong. - else if (!pStream->avail_out) - return MZ_BUF_ERROR; - } - else if ((status == TINFL_STATUS_DONE) || (!pStream->avail_in) || (!pStream->avail_out) || (pState->m_dict_avail)) - break; - } - - return ((status == TINFL_STATUS_DONE) && (!pState->m_dict_avail)) ? MZ_STREAM_END : MZ_OK; -} - -int mz_inflateEnd(mz_streamp pStream) -{ - if (!pStream) - return MZ_STREAM_ERROR; - if (pStream->state) - { - pStream->zfree(pStream->opaque, pStream->state); - pStream->state = NULL; - } - return MZ_OK; -} - -int mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len) -{ - mz_stream stream; - int status; - memset(&stream, 0, sizeof(stream)); - - // In case mz_ulong is 64-bits (argh I hate longs). - if ((source_len | *pDest_len) > 0xFFFFFFFFU) return MZ_PARAM_ERROR; - - stream.next_in = pSource; - stream.avail_in = (mz_uint32)source_len; - stream.next_out = pDest; - stream.avail_out = (mz_uint32)*pDest_len; - - status = mz_inflateInit(&stream); - if (status != MZ_OK) - return status; - - status = mz_inflate(&stream, MZ_FINISH); - if (status != MZ_STREAM_END) - { - mz_inflateEnd(&stream); - return ((status == MZ_BUF_ERROR) && (!stream.avail_in)) ? MZ_DATA_ERROR : status; - } - *pDest_len = stream.total_out; - - return mz_inflateEnd(&stream); -} - -const char *mz_error(int err) -{ - static struct { int m_err; const char *m_pDesc; } s_error_descs[] = - { - { MZ_OK, "" }, { MZ_STREAM_END, "stream end" }, { MZ_NEED_DICT, "need dictionary" }, { MZ_ERRNO, "file error" }, { MZ_STREAM_ERROR, "stream error" }, - { MZ_DATA_ERROR, "data error" }, { MZ_MEM_ERROR, "out of memory" }, { MZ_BUF_ERROR, "buf error" }, { MZ_VERSION_ERROR, "version error" }, { MZ_PARAM_ERROR, "parameter error" } - }; - mz_uint i; for (i = 0; i < sizeof(s_error_descs) / sizeof(s_error_descs[0]); ++i) if (s_error_descs[i].m_err == err) return s_error_descs[i].m_pDesc; - return NULL; -} - -#endif //MINIZ_NO_ZLIB_APIS - -// ------------------- Low-level Decompression (completely independent from all compression API's) - -#define TINFL_MEMCPY(d, s, l) memcpy(d, s, l) -#define TINFL_MEMSET(p, c, l) memset(p, c, l) - -#define TINFL_CR_BEGIN switch(r->m_state) { case 0: -#define TINFL_CR_RETURN(state_index, result) do { status = result; r->m_state = state_index; goto common_exit; case state_index:; } MZ_MACRO_END -#define TINFL_CR_RETURN_FOREVER(state_index, result) do { for ( ; ; ) { TINFL_CR_RETURN(state_index, result); } } MZ_MACRO_END -#define TINFL_CR_FINISH } - -// TODO: If the caller has indicated that there's no more input, and we attempt to read beyond the input buf, then something is wrong with the input because the inflator never -// reads ahead more than it needs to. Currently TINFL_GET_BYTE() pads the end of the stream with 0's in this scenario. -#define TINFL_GET_BYTE(state_index, c) do { \ - if (pIn_buf_cur >= pIn_buf_end) { \ - for ( ; ; ) { \ - if (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) { \ - TINFL_CR_RETURN(state_index, TINFL_STATUS_NEEDS_MORE_INPUT); \ - if (pIn_buf_cur < pIn_buf_end) { \ - c = *pIn_buf_cur++; \ - break; \ - } \ - } else { \ - c = 0; \ - break; \ - } \ - } \ - } else c = *pIn_buf_cur++; } MZ_MACRO_END - -#define TINFL_NEED_BITS(state_index, n) do { mz_uint c; TINFL_GET_BYTE(state_index, c); bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); num_bits += 8; } while (num_bits < (mz_uint)(n)) -#define TINFL_SKIP_BITS(state_index, n) do { if (num_bits < (mz_uint)(n)) { TINFL_NEED_BITS(state_index, n); } bit_buf >>= (n); num_bits -= (n); } MZ_MACRO_END -#define TINFL_GET_BITS(state_index, b, n) do { if (num_bits < (mz_uint)(n)) { TINFL_NEED_BITS(state_index, n); } b = bit_buf & ((1 << (n)) - 1); bit_buf >>= (n); num_bits -= (n); } MZ_MACRO_END - -// TINFL_HUFF_BITBUF_FILL() is only used rarely, when the number of bytes remaining in the input buffer falls below 2. -// It reads just enough bytes from the input stream that are needed to decode the next Huffman code (and absolutely no more). It works by trying to fully decode a -// Huffman code by using whatever bits are currently present in the bit buffer. If this fails, it reads another byte, and tries again until it succeeds or until the -// bit buffer contains >=15 bits (deflate's max. Huffman code size). -#define TINFL_HUFF_BITBUF_FILL(state_index, pHuff) \ - do { \ - temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]; \ - if (temp >= 0) { \ - code_len = temp >> 9; \ - if ((code_len) && (num_bits >= code_len)) \ - break; \ - } else if (num_bits > TINFL_FAST_LOOKUP_BITS) { \ - code_len = TINFL_FAST_LOOKUP_BITS; \ - do { \ - temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; \ - } while ((temp < 0) && (num_bits >= (code_len + 1))); if (temp >= 0) break; \ - } TINFL_GET_BYTE(state_index, c); bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); num_bits += 8; \ - } while (num_bits < 15); - -// TINFL_HUFF_DECODE() decodes the next Huffman coded symbol. It's more complex than you would initially expect because the zlib API expects the decompressor to never read -// beyond the final byte of the deflate stream. (In other words, when this macro wants to read another byte from the input, it REALLY needs another byte in order to fully -// decode the next Huffman code.) Handling this properly is particularly important on raw deflate (non-zlib) streams, which aren't followed by a byte aligned adler-32. -// The slow path is only executed at the very end of the input buffer. -#define TINFL_HUFF_DECODE(state_index, sym, pHuff) do { \ - int temp; mz_uint code_len, c; \ - if (num_bits < 15) { \ - if ((pIn_buf_end - pIn_buf_cur) < 2) { \ - TINFL_HUFF_BITBUF_FILL(state_index, pHuff); \ - } else { \ - bit_buf |= (((tinfl_bit_buf_t)pIn_buf_cur[0]) << num_bits) | (((tinfl_bit_buf_t)pIn_buf_cur[1]) << (num_bits + 8)); pIn_buf_cur += 2; num_bits += 16; \ - } \ - } \ - if ((temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) \ - code_len = temp >> 9, temp &= 511; \ - else { \ - code_len = TINFL_FAST_LOOKUP_BITS; do { temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; } while (temp < 0); \ - } sym = temp; bit_buf >>= code_len; num_bits -= code_len; } MZ_MACRO_END - -tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_next, size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, const mz_uint32 decomp_flags) -{ - static const int s_length_base[31] = { 3,4,5,6,7,8,9,10,11,13, 15,17,19,23,27,31,35,43,51,59, 67,83,99,115,131,163,195,227,258,0,0 }; - static const int s_length_extra[31] = { 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0 }; - static const int s_dist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193, 257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0 }; - static const int s_dist_extra[32] = { 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13 }; - static const mz_uint8 s_length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 }; - static const int s_min_table_sizes[3] = { 257, 1, 4 }; - - tinfl_status status = TINFL_STATUS_FAILED; mz_uint32 num_bits, dist, counter, num_extra; tinfl_bit_buf_t bit_buf; - const mz_uint8 *pIn_buf_cur = pIn_buf_next, *const pIn_buf_end = pIn_buf_next + *pIn_buf_size; - mz_uint8 *pOut_buf_cur = pOut_buf_next, *const pOut_buf_end = pOut_buf_next + *pOut_buf_size; - size_t out_buf_size_mask = (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF) ? (size_t)-1 : ((pOut_buf_next - pOut_buf_start) + *pOut_buf_size) - 1, dist_from_out_buf_start; - - // Ensure the output buffer's size is a power of 2, unless the output buffer is large enough to hold the entire output file (in which case it doesn't matter). - if (((out_buf_size_mask + 1) & out_buf_size_mask) || (pOut_buf_next < pOut_buf_start)) { *pIn_buf_size = *pOut_buf_size = 0; return TINFL_STATUS_BAD_PARAM; } - - num_bits = r->m_num_bits; bit_buf = r->m_bit_buf; dist = r->m_dist; counter = r->m_counter; num_extra = r->m_num_extra; dist_from_out_buf_start = r->m_dist_from_out_buf_start; - TINFL_CR_BEGIN - - bit_buf = num_bits = dist = counter = num_extra = r->m_zhdr0 = r->m_zhdr1 = 0; r->m_z_adler32 = r->m_check_adler32 = 1; - if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) - { - TINFL_GET_BYTE(1, r->m_zhdr0); TINFL_GET_BYTE(2, r->m_zhdr1); - counter = (((r->m_zhdr0 * 256 + r->m_zhdr1) % 31 != 0) || (r->m_zhdr1 & 32) || ((r->m_zhdr0 & 15) != 8)); - if (!(decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)) counter |= (((1U << (8U + (r->m_zhdr0 >> 4))) > 32768U) || ((out_buf_size_mask + 1) < (size_t)(1U << (8U + (r->m_zhdr0 >> 4))))); - if (counter) { TINFL_CR_RETURN_FOREVER(36, TINFL_STATUS_FAILED); } - } - - do - { - TINFL_GET_BITS(3, r->m_final, 3); r->m_type = r->m_final >> 1; - if (r->m_type == 0) - { - TINFL_SKIP_BITS(5, num_bits & 7); - for (counter = 0; counter < 4; ++counter) { if (num_bits) TINFL_GET_BITS(6, r->m_raw_header[counter], 8); else TINFL_GET_BYTE(7, r->m_raw_header[counter]); } - if ((counter = (r->m_raw_header[0] | (r->m_raw_header[1] << 8))) != (mz_uint)(0xFFFF ^ (r->m_raw_header[2] | (r->m_raw_header[3] << 8)))) { TINFL_CR_RETURN_FOREVER(39, TINFL_STATUS_FAILED); } - while ((counter) && (num_bits)) - { - TINFL_GET_BITS(51, dist, 8); - while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(52, TINFL_STATUS_HAS_MORE_OUTPUT); } - *pOut_buf_cur++ = (mz_uint8)dist; - counter--; - } - while (counter) - { - size_t n; while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(9, TINFL_STATUS_HAS_MORE_OUTPUT); } - while (pIn_buf_cur >= pIn_buf_end) - { - if (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) - { - TINFL_CR_RETURN(38, TINFL_STATUS_NEEDS_MORE_INPUT); - } - else - { - TINFL_CR_RETURN_FOREVER(40, TINFL_STATUS_FAILED); - } - } - n = MZ_MIN(MZ_MIN((size_t)(pOut_buf_end - pOut_buf_cur), (size_t)(pIn_buf_end - pIn_buf_cur)), counter); - TINFL_MEMCPY(pOut_buf_cur, pIn_buf_cur, n); pIn_buf_cur += n; pOut_buf_cur += n; counter -= (mz_uint)n; - } - } - else if (r->m_type == 3) - { - TINFL_CR_RETURN_FOREVER(10, TINFL_STATUS_FAILED); - } - else - { - if (r->m_type == 1) - { - mz_uint8 *p = r->m_tables[0].m_code_size; mz_uint i; - r->m_table_sizes[0] = 288; r->m_table_sizes[1] = 32; TINFL_MEMSET(r->m_tables[1].m_code_size, 5, 32); - for (i = 0; i <= 143; ++i) *p++ = 8; for (; i <= 255; ++i) *p++ = 9; for (; i <= 279; ++i) *p++ = 7; for (; i <= 287; ++i) *p++ = 8; - } - else - { - for (counter = 0; counter < 3; counter++) { TINFL_GET_BITS(11, r->m_table_sizes[counter], "\05\05\04"[counter]); r->m_table_sizes[counter] += s_min_table_sizes[counter]; } - MZ_CLEAR_OBJ(r->m_tables[2].m_code_size); for (counter = 0; counter < r->m_table_sizes[2]; counter++) { mz_uint s; TINFL_GET_BITS(14, s, 3); r->m_tables[2].m_code_size[s_length_dezigzag[counter]] = (mz_uint8)s; } - r->m_table_sizes[2] = 19; - } - for (; (int)r->m_type >= 0; r->m_type--) - { - int tree_next, tree_cur; tinfl_huff_table *pTable; - mz_uint i, j, used_syms, total, sym_index, next_code[17], total_syms[16]; pTable = &r->m_tables[r->m_type]; MZ_CLEAR_OBJ(total_syms); MZ_CLEAR_OBJ(pTable->m_look_up); MZ_CLEAR_OBJ(pTable->m_tree); - for (i = 0; i < r->m_table_sizes[r->m_type]; ++i) total_syms[pTable->m_code_size[i]]++; - used_syms = 0, total = 0; next_code[0] = next_code[1] = 0; - for (i = 1; i <= 15; ++i) { used_syms += total_syms[i]; next_code[i + 1] = (total = ((total + total_syms[i]) << 1)); } - if ((65536 != total) && (used_syms > 1)) - { - TINFL_CR_RETURN_FOREVER(35, TINFL_STATUS_FAILED); - } - for (tree_next = -1, sym_index = 0; sym_index < r->m_table_sizes[r->m_type]; ++sym_index) - { - mz_uint rev_code = 0, l, cur_code, code_size = pTable->m_code_size[sym_index]; if (!code_size) continue; - cur_code = next_code[code_size]++; for (l = code_size; l > 0; l--, cur_code >>= 1) rev_code = (rev_code << 1) | (cur_code & 1); - if (code_size <= TINFL_FAST_LOOKUP_BITS) { mz_int16 k = (mz_int16)((code_size << 9) | sym_index); while (rev_code < TINFL_FAST_LOOKUP_SIZE) { pTable->m_look_up[rev_code] = k; rev_code += (1 << code_size); } continue; } - if (0 == (tree_cur = pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)])) { pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)] = (mz_int16)tree_next; tree_cur = tree_next; tree_next -= 2; } - rev_code >>= (TINFL_FAST_LOOKUP_BITS - 1); - for (j = code_size; j > (TINFL_FAST_LOOKUP_BITS + 1); j--) - { - tree_cur -= ((rev_code >>= 1) & 1); - if (!pTable->m_tree[-tree_cur - 1]) { pTable->m_tree[-tree_cur - 1] = (mz_int16)tree_next; tree_cur = tree_next; tree_next -= 2; } - else tree_cur = pTable->m_tree[-tree_cur - 1]; - } - tree_cur -= ((rev_code >>= 1) & 1); pTable->m_tree[-tree_cur - 1] = (mz_int16)sym_index; - } - if (r->m_type == 2) - { - for (counter = 0; counter < (r->m_table_sizes[0] + r->m_table_sizes[1]); ) - { - mz_uint s; TINFL_HUFF_DECODE(16, dist, &r->m_tables[2]); if (dist < 16) { r->m_len_codes[counter++] = (mz_uint8)dist; continue; } - if ((dist == 16) && (!counter)) - { - TINFL_CR_RETURN_FOREVER(17, TINFL_STATUS_FAILED); - } - num_extra = "\02\03\07"[dist - 16]; TINFL_GET_BITS(18, s, num_extra); s += "\03\03\013"[dist - 16]; - TINFL_MEMSET(r->m_len_codes + counter, (dist == 16) ? r->m_len_codes[counter - 1] : 0, s); counter += s; - } - if ((r->m_table_sizes[0] + r->m_table_sizes[1]) != counter) - { - TINFL_CR_RETURN_FOREVER(21, TINFL_STATUS_FAILED); - } - TINFL_MEMCPY(r->m_tables[0].m_code_size, r->m_len_codes, r->m_table_sizes[0]); TINFL_MEMCPY(r->m_tables[1].m_code_size, r->m_len_codes + r->m_table_sizes[0], r->m_table_sizes[1]); - } - } - for (; ; ) - { - mz_uint8 *pSrc; - for (; ; ) - { - if (((pIn_buf_end - pIn_buf_cur) < 4) || ((pOut_buf_end - pOut_buf_cur) < 2)) - { - TINFL_HUFF_DECODE(23, counter, &r->m_tables[0]); - if (counter >= 256) - break; - while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(24, TINFL_STATUS_HAS_MORE_OUTPUT); } - *pOut_buf_cur++ = (mz_uint8)counter; - } - else - { - int sym2; mz_uint code_len; -#if TINFL_USE_64BIT_BITBUF - if (num_bits < 30) { bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE32(pIn_buf_cur)) << num_bits); pIn_buf_cur += 4; num_bits += 32; } -#else - if (num_bits < 15) { bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits); pIn_buf_cur += 2; num_bits += 16; } -#endif - if ((sym2 = r->m_tables[0].m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) - code_len = sym2 >> 9; - else - { - code_len = TINFL_FAST_LOOKUP_BITS; do { sym2 = r->m_tables[0].m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; } while (sym2 < 0); - } - counter = sym2; bit_buf >>= code_len; num_bits -= code_len; - if (counter & 256) - break; - -#if !TINFL_USE_64BIT_BITBUF - if (num_bits < 15) { bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits); pIn_buf_cur += 2; num_bits += 16; } -#endif - if ((sym2 = r->m_tables[0].m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) - code_len = sym2 >> 9; - else - { - code_len = TINFL_FAST_LOOKUP_BITS; do { sym2 = r->m_tables[0].m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; } while (sym2 < 0); - } - bit_buf >>= code_len; num_bits -= code_len; - - pOut_buf_cur[0] = (mz_uint8)counter; - if (sym2 & 256) - { - pOut_buf_cur++; - counter = sym2; - break; - } - pOut_buf_cur[1] = (mz_uint8)sym2; - pOut_buf_cur += 2; - } - } - if ((counter &= 511) == 256) break; - - num_extra = s_length_extra[counter - 257]; counter = s_length_base[counter - 257]; - if (num_extra) { mz_uint extra_bits; TINFL_GET_BITS(25, extra_bits, num_extra); counter += extra_bits; } - - TINFL_HUFF_DECODE(26, dist, &r->m_tables[1]); - num_extra = s_dist_extra[dist]; dist = s_dist_base[dist]; - if (num_extra) { mz_uint extra_bits; TINFL_GET_BITS(27, extra_bits, num_extra); dist += extra_bits; } - - dist_from_out_buf_start = pOut_buf_cur - pOut_buf_start; - if ((dist > dist_from_out_buf_start) && (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)) - { - TINFL_CR_RETURN_FOREVER(37, TINFL_STATUS_FAILED); - } - - pSrc = pOut_buf_start + ((dist_from_out_buf_start - dist) & out_buf_size_mask); - - if ((MZ_MAX(pOut_buf_cur, pSrc) + counter) > pOut_buf_end) - { - while (counter--) - { - while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(53, TINFL_STATUS_HAS_MORE_OUTPUT); } - *pOut_buf_cur++ = pOut_buf_start[(dist_from_out_buf_start++ - dist) & out_buf_size_mask]; - } - continue; - } -#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES - else if ((counter >= 9) && (counter <= dist)) - { - const mz_uint8 *pSrc_end = pSrc + (counter & ~7); - do - { - ((mz_uint32 *)pOut_buf_cur)[0] = ((const mz_uint32 *)pSrc)[0]; - ((mz_uint32 *)pOut_buf_cur)[1] = ((const mz_uint32 *)pSrc)[1]; - pOut_buf_cur += 8; - } while ((pSrc += 8) < pSrc_end); - if ((counter &= 7) < 3) - { - if (counter) - { - pOut_buf_cur[0] = pSrc[0]; - if (counter > 1) - pOut_buf_cur[1] = pSrc[1]; - pOut_buf_cur += counter; - } - continue; - } - } -#endif - do - { - pOut_buf_cur[0] = pSrc[0]; - pOut_buf_cur[1] = pSrc[1]; - pOut_buf_cur[2] = pSrc[2]; - pOut_buf_cur += 3; pSrc += 3; - } while ((int)(counter -= 3) > 2); - if ((int)counter > 0) - { - pOut_buf_cur[0] = pSrc[0]; - if ((int)counter > 1) - pOut_buf_cur[1] = pSrc[1]; - pOut_buf_cur += counter; - } - } - } - } while (!(r->m_final & 1)); - if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) - { - TINFL_SKIP_BITS(32, num_bits & 7); for (counter = 0; counter < 4; ++counter) { mz_uint s; if (num_bits) TINFL_GET_BITS(41, s, 8); else TINFL_GET_BYTE(42, s); r->m_z_adler32 = (r->m_z_adler32 << 8) | s; } - } - TINFL_CR_RETURN_FOREVER(34, TINFL_STATUS_DONE); - TINFL_CR_FINISH - - common_exit : - r->m_num_bits = num_bits; r->m_bit_buf = bit_buf; r->m_dist = dist; r->m_counter = counter; r->m_num_extra = num_extra; r->m_dist_from_out_buf_start = dist_from_out_buf_start; - *pIn_buf_size = pIn_buf_cur - pIn_buf_next; *pOut_buf_size = pOut_buf_cur - pOut_buf_next; - if ((decomp_flags & (TINFL_FLAG_PARSE_ZLIB_HEADER | TINFL_FLAG_COMPUTE_ADLER32)) && (status >= 0)) - { - const mz_uint8 *ptr = pOut_buf_next; size_t buf_len = *pOut_buf_size; - mz_uint32 i, s1 = r->m_check_adler32 & 0xffff, s2 = r->m_check_adler32 >> 16; size_t block_len = buf_len % 5552; - while (buf_len) - { - for (i = 0; i + 7 < block_len; i += 8, ptr += 8) - { - s1 += ptr[0], s2 += s1; s1 += ptr[1], s2 += s1; s1 += ptr[2], s2 += s1; s1 += ptr[3], s2 += s1; - s1 += ptr[4], s2 += s1; s1 += ptr[5], s2 += s1; s1 += ptr[6], s2 += s1; s1 += ptr[7], s2 += s1; - } - for (; i < block_len; ++i) s1 += *ptr++, s2 += s1; - s1 %= 65521U, s2 %= 65521U; buf_len -= block_len; block_len = 5552; - } - r->m_check_adler32 = (s2 << 16) + s1; if ((status == TINFL_STATUS_DONE) && (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) && (r->m_check_adler32 != r->m_z_adler32)) status = TINFL_STATUS_ADLER32_MISMATCH; - } - return status; -} - -// Higher level helper functions. -void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags) -{ - tinfl_decompressor decomp; void *pBuf = NULL, *pNew_buf; size_t src_buf_ofs = 0, out_buf_capacity = 0; - *pOut_len = 0; - tinfl_init(&decomp); - for (; ; ) - { - size_t src_buf_size = src_buf_len - src_buf_ofs, dst_buf_size = out_buf_capacity - *pOut_len, new_out_buf_capacity; - tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8*)pSrc_buf + src_buf_ofs, &src_buf_size, (mz_uint8*)pBuf, pBuf ? (mz_uint8*)pBuf + *pOut_len : NULL, &dst_buf_size, - (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF); - if ((status < 0) || (status == TINFL_STATUS_NEEDS_MORE_INPUT)) - { - MZ_FREE(pBuf); *pOut_len = 0; return NULL; - } - src_buf_ofs += src_buf_size; - *pOut_len += dst_buf_size; - if (status == TINFL_STATUS_DONE) break; - new_out_buf_capacity = out_buf_capacity * 2; if (new_out_buf_capacity < 128) new_out_buf_capacity = 128; - pNew_buf = MZ_REALLOC(pBuf, new_out_buf_capacity); - if (!pNew_buf) - { - MZ_FREE(pBuf); *pOut_len = 0; return NULL; - } - pBuf = pNew_buf; out_buf_capacity = new_out_buf_capacity; - } - return pBuf; -} - -size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags) -{ - tinfl_decompressor decomp; tinfl_status status; tinfl_init(&decomp); - status = tinfl_decompress(&decomp, (const mz_uint8*)pSrc_buf, &src_buf_len, (mz_uint8*)pOut_buf, (mz_uint8*)pOut_buf, &out_buf_len, (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF); - return (status != TINFL_STATUS_DONE) ? TINFL_DECOMPRESS_MEM_TO_MEM_FAILED : out_buf_len; -} - -int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags) -{ - int result = 0; - tinfl_decompressor decomp; - mz_uint8 *pDict = (mz_uint8*)MZ_MALLOC(TINFL_LZ_DICT_SIZE); size_t in_buf_ofs = 0, dict_ofs = 0; - if (!pDict) - return TINFL_STATUS_FAILED; - tinfl_init(&decomp); - for (; ; ) - { - size_t in_buf_size = *pIn_buf_size - in_buf_ofs, dst_buf_size = TINFL_LZ_DICT_SIZE - dict_ofs; - tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8*)pIn_buf + in_buf_ofs, &in_buf_size, pDict, pDict + dict_ofs, &dst_buf_size, - (flags & ~(TINFL_FLAG_HAS_MORE_INPUT | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF))); - in_buf_ofs += in_buf_size; - if ((dst_buf_size) && (!(*pPut_buf_func)(pDict + dict_ofs, (int)dst_buf_size, pPut_buf_user))) - break; - if (status != TINFL_STATUS_HAS_MORE_OUTPUT) - { - result = (status == TINFL_STATUS_DONE); - break; - } - dict_ofs = (dict_ofs + dst_buf_size) & (TINFL_LZ_DICT_SIZE - 1); - } - MZ_FREE(pDict); - *pIn_buf_size = in_buf_ofs; - return result; -} - -// ------------------- Low-level Compression (independent from all decompression API's) - -// Purposely making these tables static for faster init and thread safety. -static const mz_uint16 s_tdefl_len_sym[256] = { - 257,258,259,260,261,262,263,264,265,265,266,266,267,267,268,268,269,269,269,269,270,270,270,270,271,271,271,271,272,272,272,272, - 273,273,273,273,273,273,273,273,274,274,274,274,274,274,274,274,275,275,275,275,275,275,275,275,276,276,276,276,276,276,276,276, - 277,277,277,277,277,277,277,277,277,277,277,277,277,277,277,277,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278, - 279,279,279,279,279,279,279,279,279,279,279,279,279,279,279,279,280,280,280,280,280,280,280,280,280,280,280,280,280,280,280,280, - 281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281, - 282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282, - 283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283, - 284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,285 }; - -static const mz_uint8 s_tdefl_len_extra[256] = { - 0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0 }; - -static const mz_uint8 s_tdefl_small_dist_sym[512] = { - 0,1,2,3,4,4,5,5,6,6,6,6,7,7,7,7,8,8,8,8,8,8,8,8,9,9,9,9,9,9,9,9,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,11,11,11,11,11,11, - 11,11,11,11,11,11,11,11,11,11,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,13, - 13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,14,14,14,14,14,14,14,14,14,14,14,14, - 14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14, - 14,14,14,14,14,14,14,14,14,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15, - 15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,16,16,16,16,16,16,16,16,16,16,16,16,16, - 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, - 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, - 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,17,17,17,17,17,17,17,17,17,17,17,17,17,17, - 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, - 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, - 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17 }; - -static const mz_uint8 s_tdefl_small_dist_extra[512] = { - 0,0,0,0,1,1,1,1,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, - 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, - 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, - 7,7,7,7,7,7,7,7 }; - -static const mz_uint8 s_tdefl_large_dist_sym[128] = { - 0,0,18,19,20,20,21,21,22,22,22,22,23,23,23,23,24,24,24,24,24,24,24,24,25,25,25,25,25,25,25,25,26,26,26,26,26,26,26,26,26,26,26,26, - 26,26,26,26,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28, - 28,28,28,28,28,28,28,28,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29 }; - -static const mz_uint8 s_tdefl_large_dist_extra[128] = { - 0,0,8,8,9,9,9,9,10,10,10,10,10,10,10,10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12, - 12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13, - 13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13 }; - -// Radix sorts tdefl_sym_freq[] array by 16-bit key m_key. Returns ptr to sorted values. -typedef struct { mz_uint16 m_key, m_sym_index; } tdefl_sym_freq; -static tdefl_sym_freq* tdefl_radix_sort_syms(mz_uint num_syms, tdefl_sym_freq* pSyms0, tdefl_sym_freq* pSyms1) -{ - mz_uint32 total_passes = 2, pass_shift, pass, i, hist[256 * 2]; tdefl_sym_freq* pCur_syms = pSyms0, *pNew_syms = pSyms1; MZ_CLEAR_OBJ(hist); - for (i = 0; i < num_syms; i++) { mz_uint freq = pSyms0[i].m_key; hist[freq & 0xFF]++; hist[256 + ((freq >> 8) & 0xFF)]++; } - while ((total_passes > 1) && (num_syms == hist[(total_passes - 1) * 256])) total_passes--; - for (pass_shift = 0, pass = 0; pass < total_passes; pass++, pass_shift += 8) - { - const mz_uint32* pHist = &hist[pass << 8]; - mz_uint offsets[256], cur_ofs = 0; - for (i = 0; i < 256; i++) { offsets[i] = cur_ofs; cur_ofs += pHist[i]; } - for (i = 0; i < num_syms; i++) pNew_syms[offsets[(pCur_syms[i].m_key >> pass_shift) & 0xFF]++] = pCur_syms[i]; - { tdefl_sym_freq* t = pCur_syms; pCur_syms = pNew_syms; pNew_syms = t; } - } - return pCur_syms; -} - -// tdefl_calculate_minimum_redundancy() originally written by: Alistair Moffat, alistair@cs.mu.oz.au, Jyrki Katajainen, jyrki@diku.dk, November 1996. -static void tdefl_calculate_minimum_redundancy(tdefl_sym_freq *A, int n) -{ - int root, leaf, next, avbl, used, dpth; - if (n == 0) return; else if (n == 1) { A[0].m_key = 1; return; } - A[0].m_key += A[1].m_key; root = 0; leaf = 2; - for (next = 1; next < n - 1; next++) - { - if (leaf >= n || A[root].m_key < A[leaf].m_key) { A[next].m_key = A[root].m_key; A[root++].m_key = (mz_uint16)next; } - else A[next].m_key = A[leaf++].m_key; - if (leaf >= n || (root < next && A[root].m_key < A[leaf].m_key)) { A[next].m_key = (mz_uint16)(A[next].m_key + A[root].m_key); A[root++].m_key = (mz_uint16)next; } - else A[next].m_key = (mz_uint16)(A[next].m_key + A[leaf++].m_key); - } - A[n - 2].m_key = 0; for (next = n - 3; next >= 0; next--) A[next].m_key = A[A[next].m_key].m_key + 1; - avbl = 1; used = dpth = 0; root = n - 2; next = n - 1; - while (avbl > 0) - { - while (root >= 0 && (int)A[root].m_key == dpth) { used++; root--; } - while (avbl > used) { A[next--].m_key = (mz_uint16)(dpth); avbl--; } - avbl = 2 * used; dpth++; used = 0; - } -} - -// Limits canonical Huffman code table's max code size. -enum { TDEFL_MAX_SUPPORTED_HUFF_CODESIZE = 32 }; -static void tdefl_huffman_enforce_max_code_size(int *pNum_codes, int code_list_len, int max_code_size) -{ - int i; mz_uint32 total = 0; if (code_list_len <= 1) return; - for (i = max_code_size + 1; i <= TDEFL_MAX_SUPPORTED_HUFF_CODESIZE; i++) pNum_codes[max_code_size] += pNum_codes[i]; - for (i = max_code_size; i > 0; i--) total += (((mz_uint32)pNum_codes[i]) << (max_code_size - i)); - while (total != (1UL << max_code_size)) - { - pNum_codes[max_code_size]--; - for (i = max_code_size - 1; i > 0; i--) if (pNum_codes[i]) { pNum_codes[i]--; pNum_codes[i + 1] += 2; break; } - total--; - } -} - -static void tdefl_optimize_huffman_table(tdefl_compressor *d, int table_num, int table_len, int code_size_limit, int static_table) -{ - int i, j, l, num_codes[1 + TDEFL_MAX_SUPPORTED_HUFF_CODESIZE]; mz_uint next_code[TDEFL_MAX_SUPPORTED_HUFF_CODESIZE + 1]; MZ_CLEAR_OBJ(num_codes); - if (static_table) - { - for (i = 0; i < table_len; i++) num_codes[d->m_huff_code_sizes[table_num][i]]++; - } - else - { - tdefl_sym_freq syms0[TDEFL_MAX_HUFF_SYMBOLS], syms1[TDEFL_MAX_HUFF_SYMBOLS], *pSyms; - int num_used_syms = 0; - const mz_uint16 *pSym_count = &d->m_huff_count[table_num][0]; - for (i = 0; i < table_len; i++) if (pSym_count[i]) { syms0[num_used_syms].m_key = (mz_uint16)pSym_count[i]; syms0[num_used_syms++].m_sym_index = (mz_uint16)i; } - - pSyms = tdefl_radix_sort_syms(num_used_syms, syms0, syms1); tdefl_calculate_minimum_redundancy(pSyms, num_used_syms); - - for (i = 0; i < num_used_syms; i++) num_codes[pSyms[i].m_key]++; - - tdefl_huffman_enforce_max_code_size(num_codes, num_used_syms, code_size_limit); - - MZ_CLEAR_OBJ(d->m_huff_code_sizes[table_num]); MZ_CLEAR_OBJ(d->m_huff_codes[table_num]); - for (i = 1, j = num_used_syms; i <= code_size_limit; i++) - for (l = num_codes[i]; l > 0; l--) d->m_huff_code_sizes[table_num][pSyms[--j].m_sym_index] = (mz_uint8)(i); - } - - next_code[1] = 0; for (j = 0, i = 2; i <= code_size_limit; i++) next_code[i] = j = ((j + num_codes[i - 1]) << 1); - - for (i = 0; i < table_len; i++) - { - mz_uint rev_code = 0, code, code_size; if ((code_size = d->m_huff_code_sizes[table_num][i]) == 0) continue; - code = next_code[code_size]++; for (l = code_size; l > 0; l--, code >>= 1) rev_code = (rev_code << 1) | (code & 1); - d->m_huff_codes[table_num][i] = (mz_uint16)rev_code; - } -} - -#define TDEFL_PUT_BITS(b, l) do { \ - mz_uint bits = b; mz_uint len = l; MZ_ASSERT(bits <= ((1U << len) - 1U)); \ - d->m_bit_buffer |= (bits << d->m_bits_in); d->m_bits_in += len; \ - while (d->m_bits_in >= 8) { \ - if (d->m_pOutput_buf < d->m_pOutput_buf_end) \ - *d->m_pOutput_buf++ = (mz_uint8)(d->m_bit_buffer); \ - d->m_bit_buffer >>= 8; \ - d->m_bits_in -= 8; \ - } \ -} MZ_MACRO_END - -#define TDEFL_RLE_PREV_CODE_SIZE() { if (rle_repeat_count) { \ - if (rle_repeat_count < 3) { \ - d->m_huff_count[2][prev_code_size] = (mz_uint16)(d->m_huff_count[2][prev_code_size] + rle_repeat_count); \ - while (rle_repeat_count--) packed_code_sizes[num_packed_code_sizes++] = prev_code_size; \ - } else { \ - d->m_huff_count[2][16] = (mz_uint16)(d->m_huff_count[2][16] + 1); packed_code_sizes[num_packed_code_sizes++] = 16; packed_code_sizes[num_packed_code_sizes++] = (mz_uint8)(rle_repeat_count - 3); \ -} rle_repeat_count = 0; } } - -#define TDEFL_RLE_ZERO_CODE_SIZE() { if (rle_z_count) { \ - if (rle_z_count < 3) { \ - d->m_huff_count[2][0] = (mz_uint16)(d->m_huff_count[2][0] + rle_z_count); while (rle_z_count--) packed_code_sizes[num_packed_code_sizes++] = 0; \ - } else if (rle_z_count <= 10) { \ - d->m_huff_count[2][17] = (mz_uint16)(d->m_huff_count[2][17] + 1); packed_code_sizes[num_packed_code_sizes++] = 17; packed_code_sizes[num_packed_code_sizes++] = (mz_uint8)(rle_z_count - 3); \ - } else { \ - d->m_huff_count[2][18] = (mz_uint16)(d->m_huff_count[2][18] + 1); packed_code_sizes[num_packed_code_sizes++] = 18; packed_code_sizes[num_packed_code_sizes++] = (mz_uint8)(rle_z_count - 11); \ -} rle_z_count = 0; } } - -static mz_uint8 s_tdefl_packed_code_size_syms_swizzle[] = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 }; - -static void tdefl_start_dynamic_block(tdefl_compressor *d) -{ - int num_lit_codes, num_dist_codes, num_bit_lengths; mz_uint i, total_code_sizes_to_pack, num_packed_code_sizes, rle_z_count, rle_repeat_count, packed_code_sizes_index; - mz_uint8 code_sizes_to_pack[TDEFL_MAX_HUFF_SYMBOLS_0 + TDEFL_MAX_HUFF_SYMBOLS_1], packed_code_sizes[TDEFL_MAX_HUFF_SYMBOLS_0 + TDEFL_MAX_HUFF_SYMBOLS_1], prev_code_size = 0xFF; - - d->m_huff_count[0][256] = 1; - - tdefl_optimize_huffman_table(d, 0, TDEFL_MAX_HUFF_SYMBOLS_0, 15, MZ_FALSE); - tdefl_optimize_huffman_table(d, 1, TDEFL_MAX_HUFF_SYMBOLS_1, 15, MZ_FALSE); - - for (num_lit_codes = 286; num_lit_codes > 257; num_lit_codes--) if (d->m_huff_code_sizes[0][num_lit_codes - 1]) break; - for (num_dist_codes = 30; num_dist_codes > 1; num_dist_codes--) if (d->m_huff_code_sizes[1][num_dist_codes - 1]) break; - - memcpy(code_sizes_to_pack, &d->m_huff_code_sizes[0][0], num_lit_codes); - memcpy(code_sizes_to_pack + num_lit_codes, &d->m_huff_code_sizes[1][0], num_dist_codes); - total_code_sizes_to_pack = num_lit_codes + num_dist_codes; num_packed_code_sizes = 0; rle_z_count = 0; rle_repeat_count = 0; - - memset(&d->m_huff_count[2][0], 0, sizeof(d->m_huff_count[2][0]) * TDEFL_MAX_HUFF_SYMBOLS_2); - for (i = 0; i < total_code_sizes_to_pack; i++) - { - mz_uint8 code_size = code_sizes_to_pack[i]; - if (!code_size) - { - TDEFL_RLE_PREV_CODE_SIZE(); - if (++rle_z_count == 138) { TDEFL_RLE_ZERO_CODE_SIZE(); } - } - else - { - TDEFL_RLE_ZERO_CODE_SIZE(); - if (code_size != prev_code_size) - { - TDEFL_RLE_PREV_CODE_SIZE(); - d->m_huff_count[2][code_size] = (mz_uint16)(d->m_huff_count[2][code_size] + 1); packed_code_sizes[num_packed_code_sizes++] = code_size; - } - else if (++rle_repeat_count == 6) - { - TDEFL_RLE_PREV_CODE_SIZE(); - } - } - prev_code_size = code_size; - } - if (rle_repeat_count) { TDEFL_RLE_PREV_CODE_SIZE(); } - else { TDEFL_RLE_ZERO_CODE_SIZE(); } - - tdefl_optimize_huffman_table(d, 2, TDEFL_MAX_HUFF_SYMBOLS_2, 7, MZ_FALSE); - - TDEFL_PUT_BITS(2, 2); - - TDEFL_PUT_BITS(num_lit_codes - 257, 5); - TDEFL_PUT_BITS(num_dist_codes - 1, 5); - - for (num_bit_lengths = 18; num_bit_lengths >= 0; num_bit_lengths--) if (d->m_huff_code_sizes[2][s_tdefl_packed_code_size_syms_swizzle[num_bit_lengths]]) break; - num_bit_lengths = MZ_MAX(4, (num_bit_lengths + 1)); TDEFL_PUT_BITS(num_bit_lengths - 4, 4); - for (i = 0; (int)i < num_bit_lengths; i++) TDEFL_PUT_BITS(d->m_huff_code_sizes[2][s_tdefl_packed_code_size_syms_swizzle[i]], 3); - - for (packed_code_sizes_index = 0; packed_code_sizes_index < num_packed_code_sizes; ) - { - mz_uint code = packed_code_sizes[packed_code_sizes_index++]; MZ_ASSERT(code < TDEFL_MAX_HUFF_SYMBOLS_2); - TDEFL_PUT_BITS(d->m_huff_codes[2][code], d->m_huff_code_sizes[2][code]); - if (code >= 16) TDEFL_PUT_BITS(packed_code_sizes[packed_code_sizes_index++], "\02\03\07"[code - 16]); - } -} - -static void tdefl_start_static_block(tdefl_compressor *d) -{ - mz_uint i; - mz_uint8 *p = &d->m_huff_code_sizes[0][0]; - - for (i = 0; i <= 143; ++i) *p++ = 8; - for (; i <= 255; ++i) *p++ = 9; - for (; i <= 279; ++i) *p++ = 7; - for (; i <= 287; ++i) *p++ = 8; - - memset(d->m_huff_code_sizes[1], 5, 32); - - tdefl_optimize_huffman_table(d, 0, 288, 15, MZ_TRUE); - tdefl_optimize_huffman_table(d, 1, 32, 15, MZ_TRUE); - - TDEFL_PUT_BITS(1, 2); -} - -static const mz_uint mz_bitmasks[17] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F, 0x007F, 0x00FF, 0x01FF, 0x03FF, 0x07FF, 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF }; - -#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN && MINIZ_HAS_64BIT_REGISTERS -static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d) -{ - mz_uint flags; - mz_uint8 *pLZ_codes; - mz_uint8 *pOutput_buf = d->m_pOutput_buf; - mz_uint8 *pLZ_code_buf_end = d->m_pLZ_code_buf; - mz_uint64 bit_buffer = d->m_bit_buffer; - mz_uint bits_in = d->m_bits_in; - -#define TDEFL_PUT_BITS_FAST(b, l) { bit_buffer |= (((mz_uint64)(b)) << bits_in); bits_in += (l); } - - flags = 1; - for (pLZ_codes = d->m_lz_code_buf; pLZ_codes < pLZ_code_buf_end; flags >>= 1) - { - if (flags == 1) - flags = *pLZ_codes++ | 0x100; - - if (flags & 1) - { - mz_uint s0, s1, n0, n1, sym, num_extra_bits; - mz_uint match_len = pLZ_codes[0], match_dist = *(const mz_uint16 *)(pLZ_codes + 1); pLZ_codes += 3; - - MZ_ASSERT(d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); - TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][s_tdefl_len_sym[match_len]], d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); - TDEFL_PUT_BITS_FAST(match_len & mz_bitmasks[s_tdefl_len_extra[match_len]], s_tdefl_len_extra[match_len]); - - // This sequence coaxes MSVC into using cmov's vs. jmp's. - s0 = s_tdefl_small_dist_sym[match_dist & 511]; - n0 = s_tdefl_small_dist_extra[match_dist & 511]; - s1 = s_tdefl_large_dist_sym[match_dist >> 8]; - n1 = s_tdefl_large_dist_extra[match_dist >> 8]; - sym = (match_dist < 512) ? s0 : s1; - num_extra_bits = (match_dist < 512) ? n0 : n1; - - MZ_ASSERT(d->m_huff_code_sizes[1][sym]); - TDEFL_PUT_BITS_FAST(d->m_huff_codes[1][sym], d->m_huff_code_sizes[1][sym]); - TDEFL_PUT_BITS_FAST(match_dist & mz_bitmasks[num_extra_bits], num_extra_bits); - } - else - { - mz_uint lit = *pLZ_codes++; - MZ_ASSERT(d->m_huff_code_sizes[0][lit]); - TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); - - if (((flags & 2) == 0) && (pLZ_codes < pLZ_code_buf_end)) - { - flags >>= 1; - lit = *pLZ_codes++; - MZ_ASSERT(d->m_huff_code_sizes[0][lit]); - TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); - - if (((flags & 2) == 0) && (pLZ_codes < pLZ_code_buf_end)) - { - flags >>= 1; - lit = *pLZ_codes++; - MZ_ASSERT(d->m_huff_code_sizes[0][lit]); - TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); - } - } - } - - if (pOutput_buf >= d->m_pOutput_buf_end) - return MZ_FALSE; - - *(mz_uint64*)pOutput_buf = bit_buffer; - pOutput_buf += (bits_in >> 3); - bit_buffer >>= (bits_in & ~7); - bits_in &= 7; - } - -#undef TDEFL_PUT_BITS_FAST - - d->m_pOutput_buf = pOutput_buf; - d->m_bits_in = 0; - d->m_bit_buffer = 0; - - while (bits_in) - { - mz_uint32 n = MZ_MIN(bits_in, 16); - TDEFL_PUT_BITS((mz_uint)bit_buffer & mz_bitmasks[n], n); - bit_buffer >>= n; - bits_in -= n; - } - - TDEFL_PUT_BITS(d->m_huff_codes[0][256], d->m_huff_code_sizes[0][256]); - - return (d->m_pOutput_buf < d->m_pOutput_buf_end); -} -#else -static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d) -{ - mz_uint flags; - mz_uint8 *pLZ_codes; - - flags = 1; - for (pLZ_codes = d->m_lz_code_buf; pLZ_codes < d->m_pLZ_code_buf; flags >>= 1) - { - if (flags == 1) - flags = *pLZ_codes++ | 0x100; - if (flags & 1) - { - mz_uint sym, num_extra_bits; - mz_uint match_len = pLZ_codes[0], match_dist = (pLZ_codes[1] | (pLZ_codes[2] << 8)); pLZ_codes += 3; - - MZ_ASSERT(d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); - TDEFL_PUT_BITS(d->m_huff_codes[0][s_tdefl_len_sym[match_len]], d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); - TDEFL_PUT_BITS(match_len & mz_bitmasks[s_tdefl_len_extra[match_len]], s_tdefl_len_extra[match_len]); - - if (match_dist < 512) - { - sym = s_tdefl_small_dist_sym[match_dist]; num_extra_bits = s_tdefl_small_dist_extra[match_dist]; - } - else - { - sym = s_tdefl_large_dist_sym[match_dist >> 8]; num_extra_bits = s_tdefl_large_dist_extra[match_dist >> 8]; - } - MZ_ASSERT(d->m_huff_code_sizes[1][sym]); - TDEFL_PUT_BITS(d->m_huff_codes[1][sym], d->m_huff_code_sizes[1][sym]); - TDEFL_PUT_BITS(match_dist & mz_bitmasks[num_extra_bits], num_extra_bits); - } - else - { - mz_uint lit = *pLZ_codes++; - MZ_ASSERT(d->m_huff_code_sizes[0][lit]); - TDEFL_PUT_BITS(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); - } - } - - TDEFL_PUT_BITS(d->m_huff_codes[0][256], d->m_huff_code_sizes[0][256]); - - return (d->m_pOutput_buf < d->m_pOutput_buf_end); -} -#endif // MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN && MINIZ_HAS_64BIT_REGISTERS - -static mz_bool tdefl_compress_block(tdefl_compressor *d, mz_bool static_block) -{ - if (static_block) - tdefl_start_static_block(d); - else - tdefl_start_dynamic_block(d); - return tdefl_compress_lz_codes(d); -} - -static int tdefl_flush_block(tdefl_compressor *d, int flush) -{ - mz_uint saved_bit_buf, saved_bits_in; - mz_uint8 *pSaved_output_buf; - mz_bool comp_block_succeeded = MZ_FALSE; - int n, use_raw_block = ((d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS) != 0) && (d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size; - mz_uint8 *pOutput_buf_start = ((d->m_pPut_buf_func == NULL) && ((*d->m_pOut_buf_size - d->m_out_buf_ofs) >= TDEFL_OUT_BUF_SIZE)) ? ((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs) : d->m_output_buf; - - d->m_pOutput_buf = pOutput_buf_start; - d->m_pOutput_buf_end = d->m_pOutput_buf + TDEFL_OUT_BUF_SIZE - 16; - - MZ_ASSERT(!d->m_output_flush_remaining); - d->m_output_flush_ofs = 0; - d->m_output_flush_remaining = 0; - - *d->m_pLZ_flags = (mz_uint8)(*d->m_pLZ_flags >> d->m_num_flags_left); - d->m_pLZ_code_buf -= (d->m_num_flags_left == 8); - - if ((d->m_flags & TDEFL_WRITE_ZLIB_HEADER) && (!d->m_block_index)) - { - TDEFL_PUT_BITS(0x78, 8); TDEFL_PUT_BITS(0x01, 8); - } - - TDEFL_PUT_BITS(flush == TDEFL_FINISH, 1); - - pSaved_output_buf = d->m_pOutput_buf; saved_bit_buf = d->m_bit_buffer; saved_bits_in = d->m_bits_in; - - if (!use_raw_block) - comp_block_succeeded = tdefl_compress_block(d, (d->m_flags & TDEFL_FORCE_ALL_STATIC_BLOCKS) || (d->m_total_lz_bytes < 48)); - - // If the block gets expanded, forget the current contents of the output buffer and send a raw block instead. - if (((use_raw_block) || ((d->m_total_lz_bytes) && ((d->m_pOutput_buf - pSaved_output_buf + 1U) >= d->m_total_lz_bytes))) && - ((d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size)) - { - mz_uint i; d->m_pOutput_buf = pSaved_output_buf; d->m_bit_buffer = saved_bit_buf, d->m_bits_in = saved_bits_in; - TDEFL_PUT_BITS(0, 2); - if (d->m_bits_in) { TDEFL_PUT_BITS(0, 8 - d->m_bits_in); } - for (i = 2; i; --i, d->m_total_lz_bytes ^= 0xFFFF) - { - TDEFL_PUT_BITS(d->m_total_lz_bytes & 0xFFFF, 16); - } - for (i = 0; i < d->m_total_lz_bytes; ++i) - { - TDEFL_PUT_BITS(d->m_dict[(d->m_lz_code_buf_dict_pos + i) & TDEFL_LZ_DICT_SIZE_MASK], 8); - } - } - // Check for the extremely unlikely (if not impossible) case of the compressed block not fitting into the output buffer when using dynamic codes. - else if (!comp_block_succeeded) - { - d->m_pOutput_buf = pSaved_output_buf; d->m_bit_buffer = saved_bit_buf, d->m_bits_in = saved_bits_in; - tdefl_compress_block(d, MZ_TRUE); - } - - if (flush) - { - if (flush == TDEFL_FINISH) - { - if (d->m_bits_in) { TDEFL_PUT_BITS(0, 8 - d->m_bits_in); } - if (d->m_flags & TDEFL_WRITE_ZLIB_HEADER) { mz_uint i, a = d->m_adler32; for (i = 0; i < 4; i++) { TDEFL_PUT_BITS((a >> 24) & 0xFF, 8); a <<= 8; } } - } - else - { - mz_uint i, z = 0; TDEFL_PUT_BITS(0, 3); if (d->m_bits_in) { TDEFL_PUT_BITS(0, 8 - d->m_bits_in); } for (i = 2; i; --i, z ^= 0xFFFF) { TDEFL_PUT_BITS(z & 0xFFFF, 16); } - } - } - - MZ_ASSERT(d->m_pOutput_buf < d->m_pOutput_buf_end); - - memset(&d->m_huff_count[0][0], 0, sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0); - memset(&d->m_huff_count[1][0], 0, sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1); - - d->m_pLZ_code_buf = d->m_lz_code_buf + 1; d->m_pLZ_flags = d->m_lz_code_buf; d->m_num_flags_left = 8; d->m_lz_code_buf_dict_pos += d->m_total_lz_bytes; d->m_total_lz_bytes = 0; d->m_block_index++; - - if ((n = (int)(d->m_pOutput_buf - pOutput_buf_start)) != 0) - { - if (d->m_pPut_buf_func) - { - *d->m_pIn_buf_size = d->m_pSrc - (const mz_uint8 *)d->m_pIn_buf; - if (!(*d->m_pPut_buf_func)(d->m_output_buf, n, d->m_pPut_buf_user)) - return (d->m_prev_return_status = TDEFL_STATUS_PUT_BUF_FAILED); - } - else if (pOutput_buf_start == d->m_output_buf) - { - int bytes_to_copy = (int)MZ_MIN((size_t)n, (size_t)(*d->m_pOut_buf_size - d->m_out_buf_ofs)); - memcpy((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs, d->m_output_buf, bytes_to_copy); - d->m_out_buf_ofs += bytes_to_copy; - if ((n -= bytes_to_copy) != 0) - { - d->m_output_flush_ofs = bytes_to_copy; - d->m_output_flush_remaining = n; - } - } - else - { - d->m_out_buf_ofs += n; - } - } - - return d->m_output_flush_remaining; -} - -#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES -#define TDEFL_READ_UNALIGNED_WORD(p) *(const mz_uint16*)(p) -static MZ_FORCEINLINE void tdefl_find_match(tdefl_compressor *d, mz_uint lookahead_pos, mz_uint max_dist, mz_uint max_match_len, mz_uint *pMatch_dist, mz_uint *pMatch_len) -{ - mz_uint dist, pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK, match_len = *pMatch_len, probe_pos = pos, next_probe_pos, probe_len; - mz_uint num_probes_left = d->m_max_probes[match_len >= 32]; - const mz_uint16 *s = (const mz_uint16*)(d->m_dict + pos), *p, *q; - mz_uint16 c01 = TDEFL_READ_UNALIGNED_WORD(&d->m_dict[pos + match_len - 1]), s01 = TDEFL_READ_UNALIGNED_WORD(s); - MZ_ASSERT(max_match_len <= TDEFL_MAX_MATCH_LEN); if (max_match_len <= match_len) return; - for (; ; ) - { - for (; ; ) - { - if (--num_probes_left == 0) return; -#define TDEFL_PROBE \ - next_probe_pos = d->m_next[probe_pos]; \ - if ((!next_probe_pos) || ((dist = (mz_uint16)(lookahead_pos - next_probe_pos)) > max_dist)) return; \ - probe_pos = next_probe_pos & TDEFL_LZ_DICT_SIZE_MASK; \ - if (TDEFL_READ_UNALIGNED_WORD(&d->m_dict[probe_pos + match_len - 1]) == c01) break; - TDEFL_PROBE; TDEFL_PROBE; TDEFL_PROBE; - } - if (!dist) break; q = (const mz_uint16*)(d->m_dict + probe_pos); if (TDEFL_READ_UNALIGNED_WORD(q) != s01) continue; p = s; probe_len = 32; - do {} while ((TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && - (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (--probe_len > 0)); - if (!probe_len) - { - *pMatch_dist = dist; *pMatch_len = MZ_MIN(max_match_len, TDEFL_MAX_MATCH_LEN); break; - } - else if ((probe_len = ((mz_uint)(p - s) * 2) + (mz_uint)(*(const mz_uint8*)p == *(const mz_uint8*)q)) > match_len) - { - *pMatch_dist = dist; if ((*pMatch_len = match_len = MZ_MIN(max_match_len, probe_len)) == max_match_len) break; - c01 = TDEFL_READ_UNALIGNED_WORD(&d->m_dict[pos + match_len - 1]); - } - } -} -#else -static MZ_FORCEINLINE void tdefl_find_match(tdefl_compressor *d, mz_uint lookahead_pos, mz_uint max_dist, mz_uint max_match_len, mz_uint *pMatch_dist, mz_uint *pMatch_len) -{ - mz_uint dist, pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK, match_len = *pMatch_len, probe_pos = pos, next_probe_pos, probe_len; - mz_uint num_probes_left = d->m_max_probes[match_len >= 32]; - const mz_uint8 *s = d->m_dict + pos, *p, *q; - mz_uint8 c0 = d->m_dict[pos + match_len], c1 = d->m_dict[pos + match_len - 1]; - MZ_ASSERT(max_match_len <= TDEFL_MAX_MATCH_LEN); if (max_match_len <= match_len) return; - for (; ; ) - { - for (; ; ) - { - if (--num_probes_left == 0) return; -#define TDEFL_PROBE \ - next_probe_pos = d->m_next[probe_pos]; \ - if ((!next_probe_pos) || ((dist = (mz_uint16)(lookahead_pos - next_probe_pos)) > max_dist)) return; \ - probe_pos = next_probe_pos & TDEFL_LZ_DICT_SIZE_MASK; \ - if ((d->m_dict[probe_pos + match_len] == c0) && (d->m_dict[probe_pos + match_len - 1] == c1)) break; - TDEFL_PROBE; TDEFL_PROBE; TDEFL_PROBE; - } - if (!dist) break; p = s; q = d->m_dict + probe_pos; for (probe_len = 0; probe_len < max_match_len; probe_len++) if (*p++ != *q++) break; - if (probe_len > match_len) - { - *pMatch_dist = dist; if ((*pMatch_len = match_len = probe_len) == max_match_len) return; - c0 = d->m_dict[pos + match_len]; c1 = d->m_dict[pos + match_len - 1]; - } - } -} -#endif // #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES - -#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN -static mz_bool tdefl_compress_fast(tdefl_compressor *d) -{ - // Faster, minimally featured LZRW1-style match+parse loop with better register utilization. Intended for applications where raw throughput is valued more highly than ratio. - mz_uint lookahead_pos = d->m_lookahead_pos, lookahead_size = d->m_lookahead_size, dict_size = d->m_dict_size, total_lz_bytes = d->m_total_lz_bytes, num_flags_left = d->m_num_flags_left; - mz_uint8 *pLZ_code_buf = d->m_pLZ_code_buf, *pLZ_flags = d->m_pLZ_flags; - mz_uint cur_pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK; - - while ((d->m_src_buf_left) || ((d->m_flush) && (lookahead_size))) - { - const mz_uint TDEFL_COMP_FAST_LOOKAHEAD_SIZE = 4096; - mz_uint dst_pos = (lookahead_pos + lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK; - mz_uint num_bytes_to_process = (mz_uint)MZ_MIN(d->m_src_buf_left, TDEFL_COMP_FAST_LOOKAHEAD_SIZE - lookahead_size); - d->m_src_buf_left -= num_bytes_to_process; - lookahead_size += num_bytes_to_process; - - while (num_bytes_to_process) - { - mz_uint32 n = MZ_MIN(TDEFL_LZ_DICT_SIZE - dst_pos, num_bytes_to_process); - memcpy(d->m_dict + dst_pos, d->m_pSrc, n); - if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) - memcpy(d->m_dict + TDEFL_LZ_DICT_SIZE + dst_pos, d->m_pSrc, MZ_MIN(n, (TDEFL_MAX_MATCH_LEN - 1) - dst_pos)); - d->m_pSrc += n; - dst_pos = (dst_pos + n) & TDEFL_LZ_DICT_SIZE_MASK; - num_bytes_to_process -= n; - } - - dict_size = MZ_MIN(TDEFL_LZ_DICT_SIZE - lookahead_size, dict_size); - if ((!d->m_flush) && (lookahead_size < TDEFL_COMP_FAST_LOOKAHEAD_SIZE)) break; - - while (lookahead_size >= 4) - { - mz_uint cur_match_dist, cur_match_len = 1; - mz_uint8 *pCur_dict = d->m_dict + cur_pos; - mz_uint first_trigram = (*(const mz_uint32 *)pCur_dict) & 0xFFFFFF; - mz_uint hash = (first_trigram ^ (first_trigram >> (24 - (TDEFL_LZ_HASH_BITS - 8)))) & TDEFL_LEVEL1_HASH_SIZE_MASK; - mz_uint probe_pos = d->m_hash[hash]; - d->m_hash[hash] = (mz_uint16)lookahead_pos; - - if (((cur_match_dist = (mz_uint16)(lookahead_pos - probe_pos)) <= dict_size) && ((*(const mz_uint32 *)(d->m_dict + (probe_pos &= TDEFL_LZ_DICT_SIZE_MASK)) & 0xFFFFFF) == first_trigram)) - { - const mz_uint16 *p = (const mz_uint16 *)pCur_dict; - const mz_uint16 *q = (const mz_uint16 *)(d->m_dict + probe_pos); - mz_uint32 probe_len = 32; - do {} while ((TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && - (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (--probe_len > 0)); - cur_match_len = ((mz_uint)(p - (const mz_uint16 *)pCur_dict) * 2) + (mz_uint)(*(const mz_uint8 *)p == *(const mz_uint8 *)q); - if (!probe_len) - cur_match_len = cur_match_dist ? TDEFL_MAX_MATCH_LEN : 0; - - if ((cur_match_len < TDEFL_MIN_MATCH_LEN) || ((cur_match_len == TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 8U * 1024U))) - { - cur_match_len = 1; - *pLZ_code_buf++ = (mz_uint8)first_trigram; - *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); - d->m_huff_count[0][(mz_uint8)first_trigram]++; - } - else - { - mz_uint32 s0, s1; - cur_match_len = MZ_MIN(cur_match_len, lookahead_size); - - MZ_ASSERT((cur_match_len >= TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 1) && (cur_match_dist <= TDEFL_LZ_DICT_SIZE)); - - cur_match_dist--; - - pLZ_code_buf[0] = (mz_uint8)(cur_match_len - TDEFL_MIN_MATCH_LEN); - *(mz_uint16 *)(&pLZ_code_buf[1]) = (mz_uint16)cur_match_dist; - pLZ_code_buf += 3; - *pLZ_flags = (mz_uint8)((*pLZ_flags >> 1) | 0x80); - - s0 = s_tdefl_small_dist_sym[cur_match_dist & 511]; - s1 = s_tdefl_large_dist_sym[cur_match_dist >> 8]; - d->m_huff_count[1][(cur_match_dist < 512) ? s0 : s1]++; - - d->m_huff_count[0][s_tdefl_len_sym[cur_match_len - TDEFL_MIN_MATCH_LEN]]++; - } - } - else - { - *pLZ_code_buf++ = (mz_uint8)first_trigram; - *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); - d->m_huff_count[0][(mz_uint8)first_trigram]++; - } - - if (--num_flags_left == 0) { num_flags_left = 8; pLZ_flags = pLZ_code_buf++; } - - total_lz_bytes += cur_match_len; - lookahead_pos += cur_match_len; - dict_size = MZ_MIN(dict_size + cur_match_len, TDEFL_LZ_DICT_SIZE); - cur_pos = (cur_pos + cur_match_len) & TDEFL_LZ_DICT_SIZE_MASK; - MZ_ASSERT(lookahead_size >= cur_match_len); - lookahead_size -= cur_match_len; - - if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) - { - int n; - d->m_lookahead_pos = lookahead_pos; d->m_lookahead_size = lookahead_size; d->m_dict_size = dict_size; - d->m_total_lz_bytes = total_lz_bytes; d->m_pLZ_code_buf = pLZ_code_buf; d->m_pLZ_flags = pLZ_flags; d->m_num_flags_left = num_flags_left; - if ((n = tdefl_flush_block(d, 0)) != 0) - return (n < 0) ? MZ_FALSE : MZ_TRUE; - total_lz_bytes = d->m_total_lz_bytes; pLZ_code_buf = d->m_pLZ_code_buf; pLZ_flags = d->m_pLZ_flags; num_flags_left = d->m_num_flags_left; - } - } - - while (lookahead_size) - { - mz_uint8 lit = d->m_dict[cur_pos]; - - total_lz_bytes++; - *pLZ_code_buf++ = lit; - *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); - if (--num_flags_left == 0) { num_flags_left = 8; pLZ_flags = pLZ_code_buf++; } - - d->m_huff_count[0][lit]++; - - lookahead_pos++; - dict_size = MZ_MIN(dict_size + 1, TDEFL_LZ_DICT_SIZE); - cur_pos = (cur_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK; - lookahead_size--; - - if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) - { - int n; - d->m_lookahead_pos = lookahead_pos; d->m_lookahead_size = lookahead_size; d->m_dict_size = dict_size; - d->m_total_lz_bytes = total_lz_bytes; d->m_pLZ_code_buf = pLZ_code_buf; d->m_pLZ_flags = pLZ_flags; d->m_num_flags_left = num_flags_left; - if ((n = tdefl_flush_block(d, 0)) != 0) - return (n < 0) ? MZ_FALSE : MZ_TRUE; - total_lz_bytes = d->m_total_lz_bytes; pLZ_code_buf = d->m_pLZ_code_buf; pLZ_flags = d->m_pLZ_flags; num_flags_left = d->m_num_flags_left; - } - } - } - - d->m_lookahead_pos = lookahead_pos; d->m_lookahead_size = lookahead_size; d->m_dict_size = dict_size; - d->m_total_lz_bytes = total_lz_bytes; d->m_pLZ_code_buf = pLZ_code_buf; d->m_pLZ_flags = pLZ_flags; d->m_num_flags_left = num_flags_left; - return MZ_TRUE; -} -#endif // MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN - -static MZ_FORCEINLINE void tdefl_record_literal(tdefl_compressor *d, mz_uint8 lit) -{ - d->m_total_lz_bytes++; - *d->m_pLZ_code_buf++ = lit; - *d->m_pLZ_flags = (mz_uint8)(*d->m_pLZ_flags >> 1); if (--d->m_num_flags_left == 0) { d->m_num_flags_left = 8; d->m_pLZ_flags = d->m_pLZ_code_buf++; } - d->m_huff_count[0][lit]++; -} - -static MZ_FORCEINLINE void tdefl_record_match(tdefl_compressor *d, mz_uint match_len, mz_uint match_dist) -{ - mz_uint32 s0, s1; - - MZ_ASSERT((match_len >= TDEFL_MIN_MATCH_LEN) && (match_dist >= 1) && (match_dist <= TDEFL_LZ_DICT_SIZE)); - - d->m_total_lz_bytes += match_len; - - d->m_pLZ_code_buf[0] = (mz_uint8)(match_len - TDEFL_MIN_MATCH_LEN); - - match_dist -= 1; - d->m_pLZ_code_buf[1] = (mz_uint8)(match_dist & 0xFF); - d->m_pLZ_code_buf[2] = (mz_uint8)(match_dist >> 8); d->m_pLZ_code_buf += 3; - - *d->m_pLZ_flags = (mz_uint8)((*d->m_pLZ_flags >> 1) | 0x80); if (--d->m_num_flags_left == 0) { d->m_num_flags_left = 8; d->m_pLZ_flags = d->m_pLZ_code_buf++; } - - s0 = s_tdefl_small_dist_sym[match_dist & 511]; s1 = s_tdefl_large_dist_sym[(match_dist >> 8) & 127]; - d->m_huff_count[1][(match_dist < 512) ? s0 : s1]++; - - if (match_len >= TDEFL_MIN_MATCH_LEN) d->m_huff_count[0][s_tdefl_len_sym[match_len - TDEFL_MIN_MATCH_LEN]]++; -} - -static mz_bool tdefl_compress_normal(tdefl_compressor *d) -{ - const mz_uint8 *pSrc = d->m_pSrc; size_t src_buf_left = d->m_src_buf_left; - tdefl_flush flush = d->m_flush; - - while ((src_buf_left) || ((flush) && (d->m_lookahead_size))) - { - mz_uint len_to_move, cur_match_dist, cur_match_len, cur_pos; - // Update dictionary and hash chains. Keeps the lookahead size equal to TDEFL_MAX_MATCH_LEN. - if ((d->m_lookahead_size + d->m_dict_size) >= (TDEFL_MIN_MATCH_LEN - 1)) - { - mz_uint dst_pos = (d->m_lookahead_pos + d->m_lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK, ins_pos = d->m_lookahead_pos + d->m_lookahead_size - 2; - mz_uint hash = (d->m_dict[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] << TDEFL_LZ_HASH_SHIFT) ^ d->m_dict[(ins_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK]; - mz_uint num_bytes_to_process = (mz_uint)MZ_MIN(src_buf_left, TDEFL_MAX_MATCH_LEN - d->m_lookahead_size); - const mz_uint8 *pSrc_end = pSrc + num_bytes_to_process; - src_buf_left -= num_bytes_to_process; - d->m_lookahead_size += num_bytes_to_process; - while (pSrc != pSrc_end) - { - mz_uint8 c = *pSrc++; d->m_dict[dst_pos] = c; if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) d->m_dict[TDEFL_LZ_DICT_SIZE + dst_pos] = c; - hash = ((hash << TDEFL_LZ_HASH_SHIFT) ^ c) & (TDEFL_LZ_HASH_SIZE - 1); - d->m_next[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] = d->m_hash[hash]; d->m_hash[hash] = (mz_uint16)(ins_pos); - dst_pos = (dst_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK; ins_pos++; - } - } - else - { - while ((src_buf_left) && (d->m_lookahead_size < TDEFL_MAX_MATCH_LEN)) - { - mz_uint8 c = *pSrc++; - mz_uint dst_pos = (d->m_lookahead_pos + d->m_lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK; - src_buf_left--; - d->m_dict[dst_pos] = c; - if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) - d->m_dict[TDEFL_LZ_DICT_SIZE + dst_pos] = c; - if ((++d->m_lookahead_size + d->m_dict_size) >= TDEFL_MIN_MATCH_LEN) - { - mz_uint ins_pos = d->m_lookahead_pos + (d->m_lookahead_size - 1) - 2; - mz_uint hash = ((d->m_dict[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] << (TDEFL_LZ_HASH_SHIFT * 2)) ^ (d->m_dict[(ins_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK] << TDEFL_LZ_HASH_SHIFT) ^ c) & (TDEFL_LZ_HASH_SIZE - 1); - d->m_next[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] = d->m_hash[hash]; d->m_hash[hash] = (mz_uint16)(ins_pos); - } - } - } - d->m_dict_size = MZ_MIN(TDEFL_LZ_DICT_SIZE - d->m_lookahead_size, d->m_dict_size); - if ((!flush) && (d->m_lookahead_size < TDEFL_MAX_MATCH_LEN)) - break; - - // Simple lazy/greedy parsing state machine. - len_to_move = 1; cur_match_dist = 0; cur_match_len = d->m_saved_match_len ? d->m_saved_match_len : (TDEFL_MIN_MATCH_LEN - 1); cur_pos = d->m_lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK; - if (d->m_flags & (TDEFL_RLE_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS)) - { - if ((d->m_dict_size) && (!(d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS))) - { - mz_uint8 c = d->m_dict[(cur_pos - 1) & TDEFL_LZ_DICT_SIZE_MASK]; - cur_match_len = 0; while (cur_match_len < d->m_lookahead_size) { if (d->m_dict[cur_pos + cur_match_len] != c) break; cur_match_len++; } - if (cur_match_len < TDEFL_MIN_MATCH_LEN) cur_match_len = 0; else cur_match_dist = 1; - } - } - else - { - tdefl_find_match(d, d->m_lookahead_pos, d->m_dict_size, d->m_lookahead_size, &cur_match_dist, &cur_match_len); - } - if (((cur_match_len == TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 8U * 1024U)) || (cur_pos == cur_match_dist) || ((d->m_flags & TDEFL_FILTER_MATCHES) && (cur_match_len <= 5))) - { - cur_match_dist = cur_match_len = 0; - } - if (d->m_saved_match_len) - { - if (cur_match_len > d->m_saved_match_len) - { - tdefl_record_literal(d, (mz_uint8)d->m_saved_lit); - if (cur_match_len >= 128) - { - tdefl_record_match(d, cur_match_len, cur_match_dist); - d->m_saved_match_len = 0; len_to_move = cur_match_len; - } - else - { - d->m_saved_lit = d->m_dict[cur_pos]; d->m_saved_match_dist = cur_match_dist; d->m_saved_match_len = cur_match_len; - } - } - else - { - tdefl_record_match(d, d->m_saved_match_len, d->m_saved_match_dist); - len_to_move = d->m_saved_match_len - 1; d->m_saved_match_len = 0; - } - } - else if (!cur_match_dist) - tdefl_record_literal(d, d->m_dict[MZ_MIN(cur_pos, sizeof(d->m_dict) - 1)]); - else if ((d->m_greedy_parsing) || (d->m_flags & TDEFL_RLE_MATCHES) || (cur_match_len >= 128)) - { - tdefl_record_match(d, cur_match_len, cur_match_dist); - len_to_move = cur_match_len; - } - else - { - d->m_saved_lit = d->m_dict[MZ_MIN(cur_pos, sizeof(d->m_dict) - 1)]; d->m_saved_match_dist = cur_match_dist; d->m_saved_match_len = cur_match_len; - } - // Move the lookahead forward by len_to_move bytes. - d->m_lookahead_pos += len_to_move; - MZ_ASSERT(d->m_lookahead_size >= len_to_move); - d->m_lookahead_size -= len_to_move; - d->m_dict_size = MZ_MIN(d->m_dict_size + len_to_move, TDEFL_LZ_DICT_SIZE); - // Check if it's time to flush the current LZ codes to the internal output buffer. - if ((d->m_pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) || - ((d->m_total_lz_bytes > 31 * 1024) && (((((mz_uint)(d->m_pLZ_code_buf - d->m_lz_code_buf) * 115) >> 7) >= d->m_total_lz_bytes) || (d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS)))) - { - int n; - d->m_pSrc = pSrc; d->m_src_buf_left = src_buf_left; - if ((n = tdefl_flush_block(d, 0)) != 0) - return (n < 0) ? MZ_FALSE : MZ_TRUE; - } - } - - d->m_pSrc = pSrc; d->m_src_buf_left = src_buf_left; - return MZ_TRUE; -} - -static tdefl_status tdefl_flush_output_buffer(tdefl_compressor *d) -{ - if (d->m_pIn_buf_size) - { - *d->m_pIn_buf_size = d->m_pSrc - (const mz_uint8 *)d->m_pIn_buf; - } - - if (d->m_pOut_buf_size) - { - size_t n = MZ_MIN(*d->m_pOut_buf_size - d->m_out_buf_ofs, d->m_output_flush_remaining); - memcpy((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs, d->m_output_buf + d->m_output_flush_ofs, n); - d->m_output_flush_ofs += (mz_uint)n; - d->m_output_flush_remaining -= (mz_uint)n; - d->m_out_buf_ofs += n; - - *d->m_pOut_buf_size = d->m_out_buf_ofs; - } - - return (d->m_finished && !d->m_output_flush_remaining) ? TDEFL_STATUS_DONE : TDEFL_STATUS_OKAY; -} - -tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf, size_t *pIn_buf_size, void *pOut_buf, size_t *pOut_buf_size, tdefl_flush flush) -{ - if (!d) - { - if (pIn_buf_size) *pIn_buf_size = 0; - if (pOut_buf_size) *pOut_buf_size = 0; - return TDEFL_STATUS_BAD_PARAM; - } - - d->m_pIn_buf = pIn_buf; d->m_pIn_buf_size = pIn_buf_size; - d->m_pOut_buf = pOut_buf; d->m_pOut_buf_size = pOut_buf_size; - d->m_pSrc = (const mz_uint8 *)(pIn_buf); d->m_src_buf_left = pIn_buf_size ? *pIn_buf_size : 0; - d->m_out_buf_ofs = 0; - d->m_flush = flush; - - if (((d->m_pPut_buf_func != NULL) == ((pOut_buf != NULL) || (pOut_buf_size != NULL))) || (d->m_prev_return_status != TDEFL_STATUS_OKAY) || - (d->m_wants_to_finish && (flush != TDEFL_FINISH)) || (pIn_buf_size && *pIn_buf_size && !pIn_buf) || (pOut_buf_size && *pOut_buf_size && !pOut_buf)) - { - if (pIn_buf_size) *pIn_buf_size = 0; - if (pOut_buf_size) *pOut_buf_size = 0; - return (d->m_prev_return_status = TDEFL_STATUS_BAD_PARAM); - } - d->m_wants_to_finish |= (flush == TDEFL_FINISH); - - if ((d->m_output_flush_remaining) || (d->m_finished)) - return (d->m_prev_return_status = tdefl_flush_output_buffer(d)); - -#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN - if (((d->m_flags & TDEFL_MAX_PROBES_MASK) == 1) && - ((d->m_flags & TDEFL_GREEDY_PARSING_FLAG) != 0) && - ((d->m_flags & (TDEFL_FILTER_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS | TDEFL_RLE_MATCHES)) == 0)) - { - if (!tdefl_compress_fast(d)) - return d->m_prev_return_status; - } - else -#endif // #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN - { - if (!tdefl_compress_normal(d)) - return d->m_prev_return_status; - } - - if ((d->m_flags & (TDEFL_WRITE_ZLIB_HEADER | TDEFL_COMPUTE_ADLER32)) && (pIn_buf)) - d->m_adler32 = (mz_uint32)mz_adler32(d->m_adler32, (const mz_uint8 *)pIn_buf, d->m_pSrc - (const mz_uint8 *)pIn_buf); - - if ((flush) && (!d->m_lookahead_size) && (!d->m_src_buf_left) && (!d->m_output_flush_remaining)) - { - if (tdefl_flush_block(d, flush) < 0) - return d->m_prev_return_status; - d->m_finished = (flush == TDEFL_FINISH); - if (flush == TDEFL_FULL_FLUSH) { MZ_CLEAR_OBJ(d->m_hash); MZ_CLEAR_OBJ(d->m_next); d->m_dict_size = 0; } - } - - return (d->m_prev_return_status = tdefl_flush_output_buffer(d)); -} - -tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf, size_t in_buf_size, tdefl_flush flush) -{ - MZ_ASSERT(d->m_pPut_buf_func); return tdefl_compress(d, pIn_buf, &in_buf_size, NULL, NULL, flush); -} - -tdefl_status tdefl_init(tdefl_compressor *d, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags) -{ - d->m_pPut_buf_func = pPut_buf_func; d->m_pPut_buf_user = pPut_buf_user; - d->m_flags = (mz_uint)(flags); d->m_max_probes[0] = 1 + ((flags & 0xFFF) + 2) / 3; d->m_greedy_parsing = (flags & TDEFL_GREEDY_PARSING_FLAG) != 0; - d->m_max_probes[1] = 1 + (((flags & 0xFFF) >> 2) + 2) / 3; - if (!(flags & TDEFL_NONDETERMINISTIC_PARSING_FLAG)) MZ_CLEAR_OBJ(d->m_hash); - d->m_lookahead_pos = d->m_lookahead_size = d->m_dict_size = d->m_total_lz_bytes = d->m_lz_code_buf_dict_pos = d->m_bits_in = 0; - d->m_output_flush_ofs = d->m_output_flush_remaining = d->m_finished = d->m_block_index = d->m_bit_buffer = d->m_wants_to_finish = 0; - d->m_pLZ_code_buf = d->m_lz_code_buf + 1; d->m_pLZ_flags = d->m_lz_code_buf; d->m_num_flags_left = 8; - d->m_pOutput_buf = d->m_output_buf; d->m_pOutput_buf_end = d->m_output_buf; d->m_prev_return_status = TDEFL_STATUS_OKAY; - d->m_saved_match_dist = d->m_saved_match_len = d->m_saved_lit = 0; d->m_adler32 = 1; - d->m_pIn_buf = NULL; d->m_pOut_buf = NULL; - d->m_pIn_buf_size = NULL; d->m_pOut_buf_size = NULL; - d->m_flush = TDEFL_NO_FLUSH; d->m_pSrc = NULL; d->m_src_buf_left = 0; d->m_out_buf_ofs = 0; - memset(&d->m_huff_count[0][0], 0, sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0); - memset(&d->m_huff_count[1][0], 0, sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1); - return TDEFL_STATUS_OKAY; -} - -tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d) -{ - return d->m_prev_return_status; -} - -mz_uint32 tdefl_get_adler32(tdefl_compressor *d) -{ - return d->m_adler32; -} - -mz_bool tdefl_compress_mem_to_output(const void *pBuf, size_t buf_len, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags) -{ - tdefl_compressor *pComp; mz_bool succeeded; if (((buf_len) && (!pBuf)) || (!pPut_buf_func)) return MZ_FALSE; - pComp = (tdefl_compressor*)MZ_MALLOC(sizeof(tdefl_compressor)); if (!pComp) return MZ_FALSE; - succeeded = (tdefl_init(pComp, pPut_buf_func, pPut_buf_user, flags) == TDEFL_STATUS_OKAY); - succeeded = succeeded && (tdefl_compress_buffer(pComp, pBuf, buf_len, TDEFL_FINISH) == TDEFL_STATUS_DONE); - MZ_FREE(pComp); return succeeded; -} - -typedef struct -{ - size_t m_size, m_capacity; - mz_uint8 *m_pBuf; - mz_bool m_expandable; -} tdefl_output_buffer; - -static mz_bool tdefl_output_buffer_putter(const void *pBuf, int len, void *pUser) -{ - tdefl_output_buffer *p = (tdefl_output_buffer *)pUser; - size_t new_size = p->m_size + len; - if (new_size > p->m_capacity) - { - size_t new_capacity = p->m_capacity; mz_uint8 *pNew_buf; if (!p->m_expandable) return MZ_FALSE; - do { new_capacity = MZ_MAX(128U, new_capacity << 1U); } while (new_size > new_capacity); - pNew_buf = (mz_uint8*)MZ_REALLOC(p->m_pBuf, new_capacity); if (!pNew_buf) return MZ_FALSE; - p->m_pBuf = pNew_buf; p->m_capacity = new_capacity; - } - memcpy((mz_uint8*)p->m_pBuf + p->m_size, pBuf, len); p->m_size = new_size; - return MZ_TRUE; -} - -void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags) -{ - tdefl_output_buffer out_buf; MZ_CLEAR_OBJ(out_buf); - if (!pOut_len) return MZ_FALSE; else *pOut_len = 0; - out_buf.m_expandable = MZ_TRUE; - if (!tdefl_compress_mem_to_output(pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags)) return NULL; - *pOut_len = out_buf.m_size; return out_buf.m_pBuf; -} - -size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags) -{ - tdefl_output_buffer out_buf; MZ_CLEAR_OBJ(out_buf); - if (!pOut_buf) return 0; - out_buf.m_pBuf = (mz_uint8*)pOut_buf; out_buf.m_capacity = out_buf_len; - if (!tdefl_compress_mem_to_output(pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags)) return 0; - return out_buf.m_size; -} - -#ifndef MINIZ_NO_ZLIB_APIS -static const mz_uint s_tdefl_num_probes[11] = { 0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500 }; - -// level may actually range from [0,10] (10 is a "hidden" max level, where we want a bit more compression and it's fine if throughput to fall off a cliff on some files). -mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, int strategy) -{ - mz_uint comp_flags = s_tdefl_num_probes[(level >= 0) ? MZ_MIN(10, level) : MZ_DEFAULT_LEVEL] | ((level <= 3) ? TDEFL_GREEDY_PARSING_FLAG : 0); - if (window_bits > 0) comp_flags |= TDEFL_WRITE_ZLIB_HEADER; - - if (!level) comp_flags |= TDEFL_FORCE_ALL_RAW_BLOCKS; - else if (strategy == MZ_FILTERED) comp_flags |= TDEFL_FILTER_MATCHES; - else if (strategy == MZ_HUFFMAN_ONLY) comp_flags &= ~TDEFL_MAX_PROBES_MASK; - else if (strategy == MZ_FIXED) comp_flags |= TDEFL_FORCE_ALL_STATIC_BLOCKS; - else if (strategy == MZ_RLE) comp_flags |= TDEFL_RLE_MATCHES; - - return comp_flags; -} -#endif //MINIZ_NO_ZLIB_APIS - -#ifdef _MSC_VER -#pragma warning (push) -#pragma warning (disable:4204) // nonstandard extension used : non-constant aggregate initializer (also supported by GNU C and C99, so no big deal) -#endif - -// Simple PNG writer function by Alex Evans, 2011. Released into the public domain: https://gist.github.com/908299, more context at -// http://altdevblogaday.org/2011/04/06/a-smaller-jpg-encoder/. -// This is actually a modification of Alex's original code so PNG files generated by this function pass pngcheck. -void *tdefl_write_image_to_png_file_in_memory_ex(const void *pImage, int w, int h, int num_chans, size_t *pLen_out, mz_uint level, mz_bool flip) -{ - // Using a local copy of this array here in case MINIZ_NO_ZLIB_APIS was defined. - static const mz_uint s_tdefl_png_num_probes[11] = { 0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500 }; - tdefl_compressor *pComp = (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor)); tdefl_output_buffer out_buf; int i, bpl = w * num_chans, y, z; mz_uint32 c; *pLen_out = 0; - if (!pComp) return NULL; - MZ_CLEAR_OBJ(out_buf); out_buf.m_expandable = MZ_TRUE; out_buf.m_capacity = 57 + MZ_MAX(64, (1 + bpl)*h); if (NULL == (out_buf.m_pBuf = (mz_uint8*)MZ_MALLOC(out_buf.m_capacity))) { MZ_FREE(pComp); return NULL; } - // write dummy header - for (z = 41; z; --z) tdefl_output_buffer_putter(&z, 1, &out_buf); - // compress image data - tdefl_init(pComp, tdefl_output_buffer_putter, &out_buf, s_tdefl_png_num_probes[MZ_MIN(10, level)] | TDEFL_WRITE_ZLIB_HEADER); - for (y = 0; y < h; ++y) { tdefl_compress_buffer(pComp, &z, 1, TDEFL_NO_FLUSH); tdefl_compress_buffer(pComp, (mz_uint8*)pImage + (flip ? (h - 1 - y) : y) * bpl, bpl, TDEFL_NO_FLUSH); } - if (tdefl_compress_buffer(pComp, NULL, 0, TDEFL_FINISH) != TDEFL_STATUS_DONE) { MZ_FREE(pComp); MZ_FREE(out_buf.m_pBuf); return NULL; } - // write real header - *pLen_out = out_buf.m_size - 41; - { - static const mz_uint8 chans[] = { 0x00, 0x00, 0x04, 0x02, 0x06 }; - mz_uint8 pnghdr[41] = { 0x89,0x50,0x4e,0x47,0x0d,0x0a,0x1a,0x0a,0x00,0x00,0x00,0x0d,0x49,0x48,0x44,0x52, - 0,0,(mz_uint8)(w >> 8),(mz_uint8)w,0,0,(mz_uint8)(h >> 8),(mz_uint8)h,8,chans[num_chans],0,0,0,0,0,0,0, - (mz_uint8)(*pLen_out >> 24),(mz_uint8)(*pLen_out >> 16),(mz_uint8)(*pLen_out >> 8),(mz_uint8)*pLen_out,0x49,0x44,0x41,0x54 }; - c = (mz_uint32)mz_crc32(MZ_CRC32_INIT, pnghdr + 12, 17); for (i = 0; i < 4; ++i, c <<= 8) ((mz_uint8*)(pnghdr + 29))[i] = (mz_uint8)(c >> 24); - memcpy(out_buf.m_pBuf, pnghdr, 41); - } - // write footer (IDAT CRC-32, followed by IEND chunk) - if (!tdefl_output_buffer_putter("\0\0\0\0\0\0\0\0\x49\x45\x4e\x44\xae\x42\x60\x82", 16, &out_buf)) { *pLen_out = 0; MZ_FREE(pComp); MZ_FREE(out_buf.m_pBuf); return NULL; } - c = (mz_uint32)mz_crc32(MZ_CRC32_INIT, out_buf.m_pBuf + 41 - 4, *pLen_out + 4); for (i = 0; i < 4; ++i, c <<= 8) (out_buf.m_pBuf + out_buf.m_size - 16)[i] = (mz_uint8)(c >> 24); - // compute final size of file, grab compressed data buffer and return - *pLen_out += 57; MZ_FREE(pComp); return out_buf.m_pBuf; -} -void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, int num_chans, size_t *pLen_out) -{ - // Level 6 corresponds to TDEFL_DEFAULT_MAX_PROBES or MZ_DEFAULT_LEVEL (but we can't depend on MZ_DEFAULT_LEVEL being available in case the zlib API's where #defined out) - return tdefl_write_image_to_png_file_in_memory_ex(pImage, w, h, num_chans, pLen_out, 6, MZ_FALSE); -} - -#ifdef _MSC_VER -#pragma warning (pop) -#endif - -// ------------------- .ZIP archive reading - -#ifndef MINIZ_NO_ARCHIVE_APIS - -#ifdef MINIZ_NO_STDIO -#define MZ_FILE void * -#else -#include -#include -#include - -#if defined(_MSC_VER) || defined(__MINGW64__) -static FILE *mz_fopen(const wchar_t *pFilename, const wchar_t *pMode) -{ - FILE* pFile = NULL; - - errno_t err = _wfopen_s(&pFile, pFilename, pMode); - - return pFile; -} -static FILE *mz_freopen(const wchar_t *pPath, const wchar_t *pMode, FILE *pStream) -{ - FILE* pFile; - - if (_wfreopen_s(&pFile, pPath, pMode, pStream)) - return NULL; - - return pFile; -} -#ifndef MINIZ_NO_TIME -#include -#endif -#define MZ_FILE FILE -#define MZ_FOPEN mz_fopen -#define MZ_FCLOSE fclose -#define MZ_FREAD fread -#define MZ_FWRITE fwrite -#define MZ_FTELL64 _ftelli64 -#define MZ_FSEEK64 _fseeki64 -#define MZ_FILE_STAT_STRUCT _stat -#define MZ_FILE_STAT _wstat -#define MZ_FFLUSH fflush -#define MZ_FREOPEN mz_freopen -#define MZ_DELETE_FILE _wremove -#elif defined(__MINGW32__) -#ifndef MINIZ_NO_TIME -#include -#endif -#define MZ_FILE FILE -#define MZ_FOPEN(f, m) fopen(f, m) -#define MZ_FCLOSE fclose -#define MZ_FREAD fread -#define MZ_FWRITE fwrite -#define MZ_FTELL64 ftello64 -#define MZ_FSEEK64 fseeko64 -#define MZ_FILE_STAT_STRUCT _stat -#define MZ_FILE_STAT _stat -#define MZ_FFLUSH fflush -#define MZ_FREOPEN(f, m, s) freopen(f, m, s) -#define MZ_DELETE_FILE remove -#elif defined(__TINYC__) -#ifndef MINIZ_NO_TIME -#include -#endif -#define MZ_FILE FILE -#define MZ_FOPEN(f, m) fopen(f, m) -#define MZ_FCLOSE fclose -#define MZ_FREAD fread -#define MZ_FWRITE fwrite -#define MZ_FTELL64 ftell -#define MZ_FSEEK64 fseek -#define MZ_FILE_STAT_STRUCT stat -#define MZ_FILE_STAT stat -#define MZ_FFLUSH fflush -#define MZ_FREOPEN(f, m, s) freopen(f, m, s) -#define MZ_DELETE_FILE remove -#elif defined(__GNUC__) && _LARGEFILE64_SOURCE -#ifndef MINIZ_NO_TIME -#include -#endif -#define MZ_FILE FILE -#define MZ_FOPEN(f, m) fopen64(f, m) -#define MZ_FCLOSE fclose -#define MZ_FREAD fread -#define MZ_FWRITE fwrite -#define MZ_FTELL64 ftello64 -#define MZ_FSEEK64 fseeko64 -#define MZ_FILE_STAT_STRUCT stat64 -#define MZ_FILE_STAT stat64 -#define MZ_FFLUSH fflush -#define MZ_FREOPEN(p, m, s) freopen64(p, m, s) -#define MZ_DELETE_FILE remove -#else -#ifndef MINIZ_NO_TIME -#include -#endif -#define MZ_FILE FILE -#define MZ_FOPEN(f, m) fopen(f, m) -#define MZ_FCLOSE fclose -#define MZ_FREAD fread -#define MZ_FWRITE fwrite -#define MZ_FTELL64 ftello -#define MZ_FSEEK64 fseeko -#define MZ_FILE_STAT_STRUCT stat -#define MZ_FILE_STAT stat -#define MZ_FFLUSH fflush -#define MZ_FREOPEN(f, m, s) freopen(f, m, s) -#define MZ_DELETE_FILE remove -#endif // #ifdef _MSC_VER -#endif // #ifdef MINIZ_NO_STDIO - -#define MZ_TOLOWER(c) ((((c) >= 'A') && ((c) <= 'Z')) ? ((c) - 'A' + 'a') : (c)) - -// Various ZIP archive enums. To completely avoid cross platform compiler alignment and platform endian issues, miniz.c doesn't use structs for any of this stuff. -enum -{ - // ZIP archive identifiers and record sizes - MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG = 0x06054b50, MZ_ZIP_CENTRAL_DIR_HEADER_SIG = 0x02014b50, MZ_ZIP_LOCAL_DIR_HEADER_SIG = 0x04034b50, - MZ_ZIP_LOCAL_DIR_HEADER_SIZE = 30, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE = 46, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE = 22, - // Central directory header record offsets - MZ_ZIP_CDH_SIG_OFS = 0, MZ_ZIP_CDH_VERSION_MADE_BY_OFS = 4, MZ_ZIP_CDH_VERSION_NEEDED_OFS = 6, MZ_ZIP_CDH_BIT_FLAG_OFS = 8, - MZ_ZIP_CDH_METHOD_OFS = 10, MZ_ZIP_CDH_FILE_TIME_OFS = 12, MZ_ZIP_CDH_FILE_DATE_OFS = 14, MZ_ZIP_CDH_CRC32_OFS = 16, - MZ_ZIP_CDH_COMPRESSED_SIZE_OFS = 20, MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS = 24, MZ_ZIP_CDH_FILENAME_LEN_OFS = 28, MZ_ZIP_CDH_EXTRA_LEN_OFS = 30, - MZ_ZIP_CDH_COMMENT_LEN_OFS = 32, MZ_ZIP_CDH_DISK_START_OFS = 34, MZ_ZIP_CDH_INTERNAL_ATTR_OFS = 36, MZ_ZIP_CDH_EXTERNAL_ATTR_OFS = 38, MZ_ZIP_CDH_LOCAL_HEADER_OFS = 42, - // Local directory header offsets - MZ_ZIP_LDH_SIG_OFS = 0, MZ_ZIP_LDH_VERSION_NEEDED_OFS = 4, MZ_ZIP_LDH_BIT_FLAG_OFS = 6, MZ_ZIP_LDH_METHOD_OFS = 8, MZ_ZIP_LDH_FILE_TIME_OFS = 10, - MZ_ZIP_LDH_FILE_DATE_OFS = 12, MZ_ZIP_LDH_CRC32_OFS = 14, MZ_ZIP_LDH_COMPRESSED_SIZE_OFS = 18, MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS = 22, - MZ_ZIP_LDH_FILENAME_LEN_OFS = 26, MZ_ZIP_LDH_EXTRA_LEN_OFS = 28, - // End of central directory offsets - MZ_ZIP_ECDH_SIG_OFS = 0, MZ_ZIP_ECDH_NUM_THIS_DISK_OFS = 4, MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS = 6, MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS = 8, - MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS = 10, MZ_ZIP_ECDH_CDIR_SIZE_OFS = 12, MZ_ZIP_ECDH_CDIR_OFS_OFS = 16, MZ_ZIP_ECDH_COMMENT_SIZE_OFS = 20, -}; - -typedef struct _mz_zip_array -{ - void *m_p; - size_t m_size, m_capacity; - mz_uint m_element_size; -} mz_zip_array; - -struct mz_zip_internal_state_tag -{ - mz_zip_array m_central_dir; - mz_zip_array m_central_dir_offsets; - mz_zip_array m_sorted_central_dir_offsets; - MZ_FILE *m_pFile; - void *m_pMem; - size_t m_mem_size; - size_t m_mem_capacity; -}; - -#define MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(array_ptr, element_size) (array_ptr)->m_element_size = element_size -#define MZ_ZIP_ARRAY_ELEMENT(array_ptr, element_type, index) ((element_type *)((array_ptr)->m_p))[index] - -static MZ_FORCEINLINE void mz_zip_array_clear(mz_zip_archive *pZip, mz_zip_array *pArray) -{ - pZip->m_pFree(pZip->m_pAlloc_opaque, pArray->m_p); - memset(pArray, 0, sizeof(mz_zip_array)); -} - -static mz_bool mz_zip_array_ensure_capacity(mz_zip_archive *pZip, mz_zip_array *pArray, size_t min_new_capacity, mz_uint growing) -{ - void *pNew_p; size_t new_capacity = min_new_capacity; MZ_ASSERT(pArray->m_element_size); if (pArray->m_capacity >= min_new_capacity) return MZ_TRUE; - if (growing) { new_capacity = MZ_MAX(1, pArray->m_capacity); while (new_capacity < min_new_capacity) new_capacity *= 2; } - if (NULL == (pNew_p = pZip->m_pRealloc(pZip->m_pAlloc_opaque, pArray->m_p, pArray->m_element_size, new_capacity))) return MZ_FALSE; - pArray->m_p = pNew_p; pArray->m_capacity = new_capacity; - return MZ_TRUE; -} - -static MZ_FORCEINLINE mz_bool mz_zip_array_reserve(mz_zip_archive *pZip, mz_zip_array *pArray, size_t new_capacity, mz_uint growing) -{ - if (new_capacity > pArray->m_capacity) { if (!mz_zip_array_ensure_capacity(pZip, pArray, new_capacity, growing)) return MZ_FALSE; } - return MZ_TRUE; -} - -static MZ_FORCEINLINE mz_bool mz_zip_array_resize(mz_zip_archive *pZip, mz_zip_array *pArray, size_t new_size, mz_uint growing) -{ - if (new_size > pArray->m_capacity) { if (!mz_zip_array_ensure_capacity(pZip, pArray, new_size, growing)) return MZ_FALSE; } - pArray->m_size = new_size; - return MZ_TRUE; -} - -static MZ_FORCEINLINE mz_bool mz_zip_array_ensure_room(mz_zip_archive *pZip, mz_zip_array *pArray, size_t n) -{ - return mz_zip_array_reserve(pZip, pArray, pArray->m_size + n, MZ_TRUE); -} - -static MZ_FORCEINLINE mz_bool mz_zip_array_push_back(mz_zip_archive *pZip, mz_zip_array *pArray, const void *pElements, size_t n) -{ - size_t orig_size = pArray->m_size; if (!mz_zip_array_resize(pZip, pArray, orig_size + n, MZ_TRUE)) return MZ_FALSE; - memcpy((mz_uint8*)pArray->m_p + orig_size * pArray->m_element_size, pElements, n * pArray->m_element_size); - return MZ_TRUE; -} - -#ifndef MINIZ_NO_TIME -static time_t mz_zip_dos_to_time_t(int dos_time, int dos_date) -{ - struct tm tm; - memset(&tm, 0, sizeof(tm)); tm.tm_isdst = -1; - tm.tm_year = ((dos_date >> 9) & 127) + 1980 - 1900; tm.tm_mon = ((dos_date >> 5) & 15) - 1; tm.tm_mday = dos_date & 31; - tm.tm_hour = (dos_time >> 11) & 31; tm.tm_min = (dos_time >> 5) & 63; tm.tm_sec = (dos_time << 1) & 62; - return mktime(&tm); -} - -static void mz_zip_time_to_dos_time(time_t time, mz_uint16 *pDOS_time, mz_uint16 *pDOS_date) -{ -#ifdef _MSC_VER - struct tm tm_struct; - struct tm *tm = &tm_struct; - errno_t err = localtime_s(tm, &time); - if (err) - { - *pDOS_date = 0; *pDOS_time = 0; - return; - } -#else - struct tm *tm = localtime(&time); -#endif - *pDOS_time = (mz_uint16)(((tm->tm_hour) << 11) + ((tm->tm_min) << 5) + ((tm->tm_sec) >> 1)); - *pDOS_date = (mz_uint16)(((tm->tm_year + 1900 - 1980) << 9) + ((tm->tm_mon + 1) << 5) + tm->tm_mday); -} -#endif - -#ifndef MINIZ_NO_STDIO -static mz_bool mz_zip_get_file_modified_time(const wchar_t *pFilename, mz_uint16 *pDOS_time, mz_uint16 *pDOS_date) -{ -#ifdef MINIZ_NO_TIME - (void)pFilename; *pDOS_date = *pDOS_time = 0; -#else - struct MZ_FILE_STAT_STRUCT file_stat; - // On Linux with x86 glibc, this call will fail on large files (>= 0x80000000 bytes) unless you compiled with _LARGEFILE64_SOURCE. Argh. - if (MZ_FILE_STAT(pFilename, &file_stat) != 0) - return MZ_FALSE; - mz_zip_time_to_dos_time(file_stat.st_mtime, pDOS_time, pDOS_date); -#endif // #ifdef MINIZ_NO_TIME - return MZ_TRUE; -} - -#ifndef MINIZ_NO_TIME - -static mz_bool mz_zip_set_file_times(const wchar_t *pFilename, time_t access_time, time_t modified_time) -{ - struct _utimbuf t; - t.actime = access_time; - t.modtime = modified_time; - - return !_wutime(pFilename, &t); -} -#endif // #ifndef MINIZ_NO_TIME -#endif // #ifndef MINIZ_NO_STDIO - -static mz_bool mz_zip_reader_init_internal(mz_zip_archive *pZip, mz_uint32 flags) -{ - (void)flags; - if ((!pZip) || (pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID)) - return MZ_FALSE; - - if (!pZip->m_pAlloc) pZip->m_pAlloc = def_alloc_func; - if (!pZip->m_pFree) pZip->m_pFree = def_free_func; - if (!pZip->m_pRealloc) pZip->m_pRealloc = def_realloc_func; - - pZip->m_zip_mode = MZ_ZIP_MODE_READING; - pZip->m_archive_size = 0; - pZip->m_central_directory_file_ofs = 0; - pZip->m_total_files = 0; - - if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state)))) - return MZ_FALSE; - memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state)); - MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir, sizeof(mz_uint8)); - MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets, sizeof(mz_uint32)); - MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets, sizeof(mz_uint32)); - return MZ_TRUE; -} - -static MZ_FORCEINLINE mz_bool mz_zip_reader_filename_less(const mz_zip_array *pCentral_dir_array, const mz_zip_array *pCentral_dir_offsets, mz_uint l_index, mz_uint r_index) -{ - const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, l_index)), *pE; - const mz_uint8 *pR = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, r_index)); - mz_uint l_len = MZ_READ_LE16(pL + MZ_ZIP_CDH_FILENAME_LEN_OFS), r_len = MZ_READ_LE16(pR + MZ_ZIP_CDH_FILENAME_LEN_OFS); - mz_uint8 l = 0, r = 0; - pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; pR += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; - pE = pL + MZ_MIN(l_len, r_len); - while (pL < pE) - { - if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR))) - break; - pL++; pR++; - } - return (pL == pE) ? (l_len < r_len) : (l < r); -} - -#define MZ_SWAP_UINT32(a, b) do { mz_uint32 t = a; a = b; b = t; } MZ_MACRO_END - -// Heap sort of lowercased filenames, used to help accelerate plain central directory searches by mz_zip_reader_locate_file(). (Could also use qsort(), but it could allocate memory.) -static void mz_zip_reader_sort_central_dir_offsets_by_filename(mz_zip_archive *pZip) -{ - mz_zip_internal_state *pState = pZip->m_pState; - const mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets; - const mz_zip_array *pCentral_dir = &pState->m_central_dir; - mz_uint32 *pIndices = &MZ_ZIP_ARRAY_ELEMENT(&pState->m_sorted_central_dir_offsets, mz_uint32, 0); - const int size = pZip->m_total_files; - int start = (size - 2) >> 1, end; - while (start >= 0) - { - int child, root = start; - for (; ; ) - { - if ((child = (root << 1) + 1) >= size) - break; - child += (((child + 1) < size) && (mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[child], pIndices[child + 1]))); - if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[root], pIndices[child])) - break; - MZ_SWAP_UINT32(pIndices[root], pIndices[child]); root = child; - } - start--; - } - - end = size - 1; - while (end > 0) - { - int child, root = 0; - MZ_SWAP_UINT32(pIndices[end], pIndices[0]); - for (; ; ) - { - if ((child = (root << 1) + 1) >= end) - break; - child += (((child + 1) < end) && mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[child], pIndices[child + 1])); - if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[root], pIndices[child])) - break; - MZ_SWAP_UINT32(pIndices[root], pIndices[child]); root = child; - } - end--; - } -} - -static mz_bool mz_zip_reader_read_central_dir(mz_zip_archive *pZip, mz_uint32 flags) -{ - mz_uint cdir_size, num_this_disk, cdir_disk_index; - mz_uint64 cdir_ofs; - mz_int64 cur_file_ofs; - const mz_uint8 *p; - mz_uint32 buf_u32[4096 / sizeof(mz_uint32)]; mz_uint8 *pBuf = (mz_uint8 *)buf_u32; - mz_bool sort_central_dir = ((flags & MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY) == 0); - // Basic sanity checks - reject files which are too small, and check the first 4 bytes of the file to make sure a local header is there. - if (pZip->m_archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) - return MZ_FALSE; - // Find the end of central directory record by scanning the file from the end towards the beginning. - cur_file_ofs = MZ_MAX((mz_int64)pZip->m_archive_size - (mz_int64)sizeof(buf_u32), 0); - for (; ; ) - { - int i, n = (int)MZ_MIN(sizeof(buf_u32), pZip->m_archive_size - cur_file_ofs); - if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, n) != (mz_uint)n) - return MZ_FALSE; - for (i = n - 4; i >= 0; --i) - if (MZ_READ_LE32(pBuf + i) == MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG) - break; - if (i >= 0) - { - cur_file_ofs += i; - break; - } - if ((!cur_file_ofs) || ((pZip->m_archive_size - cur_file_ofs) >= (0xFFFF + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE))) - return MZ_FALSE; - cur_file_ofs = MZ_MAX(cur_file_ofs - (sizeof(buf_u32) - 3), 0); - } - // Read and verify the end of central directory record. - if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) - return MZ_FALSE; - if ((MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_SIG_OFS) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG) || - ((pZip->m_total_files = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS)) != MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS))) - return MZ_FALSE; - - num_this_disk = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_THIS_DISK_OFS); - cdir_disk_index = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS); - if (((num_this_disk | cdir_disk_index) != 0) && ((num_this_disk != 1) || (cdir_disk_index != 1))) - return MZ_FALSE; - - if ((cdir_size = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_SIZE_OFS)) < pZip->m_total_files * MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) - return MZ_FALSE; - - cdir_ofs = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_OFS_OFS); - if ((cdir_ofs + (mz_uint64)cdir_size) > pZip->m_archive_size) - return MZ_FALSE; - - pZip->m_central_directory_file_ofs = cdir_ofs; - - if (pZip->m_total_files) - { - mz_uint i, n; - - // Read the entire central directory into a heap block, and allocate another heap block to hold the unsorted central dir file record offsets, and another to hold the sorted indices. - if ((!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir, cdir_size, MZ_FALSE)) || - (!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir_offsets, pZip->m_total_files, MZ_FALSE))) - return MZ_FALSE; - - if (sort_central_dir) - { - if (!mz_zip_array_resize(pZip, &pZip->m_pState->m_sorted_central_dir_offsets, pZip->m_total_files, MZ_FALSE)) - return MZ_FALSE; - } - - if (pZip->m_pRead(pZip->m_pIO_opaque, cdir_ofs, pZip->m_pState->m_central_dir.m_p, cdir_size) != cdir_size) - return MZ_FALSE; - - // Now create an index into the central directory file records, do some basic sanity checking on each record, and check for zip64 entries (which are not yet supported). - p = (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p; - for (n = cdir_size, i = 0; i < pZip->m_total_files; ++i) - { - mz_uint total_header_size, comp_size, decomp_size, disk_index; - if ((n < MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) || (MZ_READ_LE32(p) != MZ_ZIP_CENTRAL_DIR_HEADER_SIG)) - return MZ_FALSE; - MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, i) = (mz_uint32)(p - (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p); - if (sort_central_dir) - MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_sorted_central_dir_offsets, mz_uint32, i) = i; - comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); - decomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); - if (((!MZ_READ_LE32(p + MZ_ZIP_CDH_METHOD_OFS)) && (decomp_size != comp_size)) || (decomp_size && !comp_size) || (decomp_size == 0xFFFFFFFF) || (comp_size == 0xFFFFFFFF)) - return MZ_FALSE; - disk_index = MZ_READ_LE16(p + MZ_ZIP_CDH_DISK_START_OFS); - if ((disk_index != num_this_disk) && (disk_index != 1)) - return MZ_FALSE; - if (((mz_uint64)MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS) + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + comp_size) > pZip->m_archive_size) - return MZ_FALSE; - if ((total_header_size = MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS)) > n) - return MZ_FALSE; - n -= total_header_size; p += total_header_size; - } - } - - if (sort_central_dir) - mz_zip_reader_sort_central_dir_offsets_by_filename(pZip); - - return MZ_TRUE; -} - -mz_bool mz_zip_reader_init(mz_zip_archive *pZip, mz_uint64 size, mz_uint32 flags) -{ - if ((!pZip) || (!pZip->m_pRead)) - return MZ_FALSE; - if (!mz_zip_reader_init_internal(pZip, flags)) - return MZ_FALSE; - pZip->m_archive_size = size; - if (!mz_zip_reader_read_central_dir(pZip, flags)) - { - mz_zip_reader_end(pZip); - return MZ_FALSE; - } - return MZ_TRUE; -} - -static size_t mz_zip_mem_read_func(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n) -{ - mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; - size_t s = (file_ofs >= pZip->m_archive_size) ? 0 : (size_t)MZ_MIN(pZip->m_archive_size - file_ofs, n); - memcpy(pBuf, (const mz_uint8 *)pZip->m_pState->m_pMem + file_ofs, s); - return s; -} - -mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem, size_t size, mz_uint32 flags) -{ - if (!mz_zip_reader_init_internal(pZip, flags)) - return MZ_FALSE; - pZip->m_archive_size = size; - pZip->m_pRead = mz_zip_mem_read_func; - pZip->m_pIO_opaque = pZip; -#ifdef __cplusplus - pZip->m_pState->m_pMem = const_cast(pMem); -#else - pZip->m_pState->m_pMem = (void *)pMem; -#endif - pZip->m_pState->m_mem_size = size; - if (!mz_zip_reader_read_central_dir(pZip, flags)) - { - mz_zip_reader_end(pZip); - return MZ_FALSE; - } - return MZ_TRUE; -} - -#ifndef MINIZ_NO_STDIO -static size_t mz_zip_file_read_func(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n) -{ - mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; - mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile); - - if (((mz_int64)file_ofs < 0) || (((cur_ofs != (mz_int64)file_ofs)) && (MZ_FSEEK64(pZip->m_pState->m_pFile, (mz_int64)file_ofs, SEEK_SET)))) - return 0; - - return MZ_FREAD(pBuf, 1, n, pZip->m_pState->m_pFile); -} - -mz_bool mz_zip_reader_init_file(mz_zip_archive *pZip, const wchar_t *pFilename, mz_uint32 flags) -{ - mz_uint64 file_size; - MZ_FILE* pFile = MZ_FOPEN(pFilename, L"rb"); - - if (!pFile) - return MZ_FALSE; - - if (MZ_FSEEK64(pFile, 0, SEEK_END)) - { - MZ_FCLOSE(pFile); - return MZ_FALSE; - } - - file_size = MZ_FTELL64(pFile); - - if (!mz_zip_reader_init_internal(pZip, flags)) - { - MZ_FCLOSE(pFile); - return MZ_FALSE; - } - - pZip->m_pRead = mz_zip_file_read_func; - pZip->m_pIO_opaque = pZip; - pZip->m_pState->m_pFile = pFile; - pZip->m_archive_size = file_size; - - if (!mz_zip_reader_read_central_dir(pZip, flags)) - { - mz_zip_reader_end(pZip); - return MZ_FALSE; - } - return MZ_TRUE; -} -#endif // #ifndef MINIZ_NO_STDIO - -mz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip) -{ - return pZip ? pZip->m_total_files : 0; -} - -static MZ_FORCEINLINE const mz_uint8 *mz_zip_reader_get_cdh(mz_zip_archive *pZip, mz_uint file_index) -{ - if ((!pZip) || (!pZip->m_pState) || (file_index >= pZip->m_total_files) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) - return NULL; - return &MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index)); -} - -mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip, mz_uint file_index) -{ - mz_uint m_bit_flag; - const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index); - if (!p) - return MZ_FALSE; - m_bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); - return (m_bit_flag & 1); -} - -mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip, mz_uint file_index) -{ - mz_uint filename_len, external_attr; - const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index); - if (!p) - return MZ_FALSE; - - // First see if the filename ends with a '/' character. - filename_len = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); - if (filename_len) - { - if (*(p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_len - 1) == '/') - return MZ_TRUE; - } - - // Bugfix: This code was also checking if the internal attribute was non-zero, which wasn't correct. - // Most/all zip writers (hopefully) set DOS file/directory attributes in the low 16-bits, so check for the DOS directory flag and ignore the source OS ID in the created by field. - // FIXME: Remove this check? Is it necessary - we already check the filename. - external_attr = MZ_READ_LE32(p + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS); - if ((external_attr & 0x10) != 0) - return MZ_TRUE; - - return MZ_FALSE; -} - -mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index, mz_zip_archive_file_stat *pStat) -{ - mz_uint n; - const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index); - if ((!p) || (!pStat)) - return MZ_FALSE; - - // Unpack the central directory record. - pStat->m_file_index = file_index; - pStat->m_central_dir_ofs = MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index); - pStat->m_version_made_by = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_MADE_BY_OFS); - pStat->m_version_needed = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_NEEDED_OFS); - pStat->m_bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); - pStat->m_method = MZ_READ_LE16(p + MZ_ZIP_CDH_METHOD_OFS); -#ifndef MINIZ_NO_TIME - pStat->m_time = mz_zip_dos_to_time_t(MZ_READ_LE16(p + MZ_ZIP_CDH_FILE_TIME_OFS), MZ_READ_LE16(p + MZ_ZIP_CDH_FILE_DATE_OFS)); -#endif - pStat->m_crc32 = MZ_READ_LE32(p + MZ_ZIP_CDH_CRC32_OFS); - pStat->m_comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); - pStat->m_uncomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); - pStat->m_internal_attr = MZ_READ_LE16(p + MZ_ZIP_CDH_INTERNAL_ATTR_OFS); - pStat->m_external_attr = MZ_READ_LE32(p + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS); - pStat->m_local_header_ofs = MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS); - - // Copy as much of the filename and comment as possible. - n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE - 1); - memcpy(pStat->m_filename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n); pStat->m_filename[n] = '\0'; - - n = MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS); n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE - 1); - pStat->m_comment_size = n; - memcpy(pStat->m_comment, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS), n); pStat->m_comment[n] = '\0'; - - return MZ_TRUE; -} - -mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index, char *pFilename, mz_uint filename_buf_size) -{ - mz_uint n; - const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index); - if (!p) { if (filename_buf_size) pFilename[0] = '\0'; return 0; } - n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); - if (filename_buf_size) - { - n = MZ_MIN(n, filename_buf_size - 1); - memcpy(pFilename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n); - pFilename[n] = '\0'; - } - return n + 1; -} - -static MZ_FORCEINLINE mz_bool mz_zip_reader_string_equal(const char *pA, const char *pB, mz_uint len, mz_uint flags) -{ - mz_uint i; - if (flags & MZ_ZIP_FLAG_CASE_SENSITIVE) - return 0 == memcmp(pA, pB, len); - for (i = 0; i < len; ++i) - if (MZ_TOLOWER(pA[i]) != MZ_TOLOWER(pB[i])) - return MZ_FALSE; - return MZ_TRUE; -} - -static MZ_FORCEINLINE int mz_zip_reader_filename_compare(const mz_zip_array *pCentral_dir_array, const mz_zip_array *pCentral_dir_offsets, mz_uint l_index, const char *pR, mz_uint r_len) -{ - const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, l_index)), *pE; - mz_uint l_len = MZ_READ_LE16(pL + MZ_ZIP_CDH_FILENAME_LEN_OFS); - mz_uint8 l = 0, r = 0; - pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; - pE = pL + MZ_MIN(l_len, r_len); - while (pL < pE) - { - if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR))) - break; - pL++; pR++; - } - return (pL == pE) ? (int)(l_len - r_len) : (l - r); -} - -static int mz_zip_reader_locate_file_binary_search(mz_zip_archive *pZip, const char *pFilename) -{ - mz_zip_internal_state *pState = pZip->m_pState; - const mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets; - const mz_zip_array *pCentral_dir = &pState->m_central_dir; - mz_uint32 *pIndices = &MZ_ZIP_ARRAY_ELEMENT(&pState->m_sorted_central_dir_offsets, mz_uint32, 0); - const int size = pZip->m_total_files; - const mz_uint filename_len = (mz_uint)strlen(pFilename); - int l = 0, h = size - 1; - while (l <= h) - { - int m = (l + h) >> 1, file_index = pIndices[m], comp = mz_zip_reader_filename_compare(pCentral_dir, pCentral_dir_offsets, file_index, pFilename, filename_len); - if (!comp) - return file_index; - else if (comp < 0) - l = m + 1; - else - h = m - 1; - } - return -1; -} - -int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags) -{ - mz_uint file_index; size_t name_len, comment_len; - - if ((!pZip) || (!pZip->m_pState) || (!pName) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) - return -1; - - if (((flags & (MZ_ZIP_FLAG_IGNORE_PATH | MZ_ZIP_FLAG_CASE_SENSITIVE)) == 0) && (!pComment) && (pZip->m_pState->m_sorted_central_dir_offsets.m_size)) - return mz_zip_reader_locate_file_binary_search(pZip, pName); - - name_len = strlen(pName); - - if (name_len > 0xFFFF) - return -1; - - comment_len = pComment ? strlen(pComment) : 0; - - if (comment_len > 0xFFFF) - return -1; - - for (file_index = 0; file_index < pZip->m_total_files; file_index++) - { - const mz_uint8 *pHeader = &MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index)); - mz_uint filename_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_FILENAME_LEN_OFS); - const char *pFilename = (const char *)pHeader + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; - - if (filename_len < name_len) - continue; - - if (comment_len) - { - mz_uint file_extra_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_EXTRA_LEN_OFS), file_comment_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_COMMENT_LEN_OFS); - - const char *pFile_comment = pFilename + filename_len + file_extra_len; - - if ((file_comment_len != comment_len) || (!mz_zip_reader_string_equal(pComment, pFile_comment, file_comment_len, flags))) - continue; - } - - if ((flags & MZ_ZIP_FLAG_IGNORE_PATH) && (filename_len)) - { - int ofs = filename_len - 1; - do - { - if ((pFilename[ofs] == '/') || (pFilename[ofs] == '\\') || (pFilename[ofs] == ':')) - break; - } while (--ofs >= 0); - ofs++; - pFilename += ofs; filename_len -= ofs; - } - - if ((filename_len == name_len) && (mz_zip_reader_string_equal(pName, pFilename, filename_len, flags))) - return file_index; - } - - return -1; -} - -mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size) -{ - int status = TINFL_STATUS_DONE; - mz_uint64 needed_size, cur_file_ofs, comp_remaining, out_buf_ofs = 0, read_buf_size, read_buf_ofs = 0, read_buf_avail; - mz_zip_archive_file_stat file_stat; - void *pRead_buf; - mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; - tinfl_decompressor inflator; - - if ((buf_size) && (!pBuf)) - return MZ_FALSE; - - if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) - return MZ_FALSE; - - // Empty file, or a directory (but not always a directory - I've seen odd zips with directories that have compressed data which inflates to 0 bytes) - if (!file_stat.m_comp_size) - return MZ_TRUE; - - // Entry is a subdirectory (I've seen old zips with dir entries which have compressed deflate data which inflates to 0 bytes, but these entries claim to uncompress to 512 bytes in the headers). - // I'm torn how to handle this case - should it fail instead? - if (mz_zip_reader_is_file_a_directory(pZip, file_index)) - return MZ_TRUE; - - // Encryption and patch files are not supported. - if (file_stat.m_bit_flag & (1 | 32)) - return MZ_FALSE; - - // This function only supports stored and deflate. - if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) && (file_stat.m_method != MZ_DEFLATED)) - return MZ_FALSE; - - // Ensure supplied output buffer is large enough. - needed_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? file_stat.m_comp_size : file_stat.m_uncomp_size; - if (buf_size < needed_size) - return MZ_FALSE; - - // Read and parse the local directory entry. - cur_file_ofs = file_stat.m_local_header_ofs; - if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) - return MZ_FALSE; - - if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) - return MZ_FALSE; - - cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); - if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size) - return MZ_FALSE; - - if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method)) - { - // The file is stored or the caller has requested the compressed data. - if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, (size_t)needed_size) != needed_size) - return MZ_FALSE; - return ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) != 0) || (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, (size_t)file_stat.m_uncomp_size) == file_stat.m_crc32); - } - - // Decompress the file either directly from memory or from a file input buffer. - tinfl_init(&inflator); - - if (pZip->m_pState->m_pMem) - { - // Read directly from the archive in memory. - pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs; - read_buf_size = read_buf_avail = file_stat.m_comp_size; - comp_remaining = 0; - } - else if (pUser_read_buf) - { - // Use a user provided read buffer. - if (!user_read_buf_size) - return MZ_FALSE; - - pRead_buf = (mz_uint8 *)pUser_read_buf; - read_buf_size = user_read_buf_size; - read_buf_avail = 0; - comp_remaining = file_stat.m_comp_size; - } - else - { - // Temporarily allocate a read buffer. - read_buf_size = MZ_MIN(file_stat.m_comp_size, MZ_ZIP_MAX_IO_BUF_SIZE); -#ifdef _MSC_VER - if (((0, sizeof(size_t) == sizeof(mz_uint32))) && (read_buf_size > 0x7FFFFFFF)) -#else - if (((sizeof(size_t) == sizeof(mz_uint32))) && (read_buf_size > 0x7FFFFFFF)) -#endif - return MZ_FALSE; - if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)read_buf_size))) - return MZ_FALSE; - read_buf_avail = 0; - comp_remaining = file_stat.m_comp_size; - } - - do - { - size_t in_buf_size, out_buf_size = (size_t)(file_stat.m_uncomp_size - out_buf_ofs); - if ((!read_buf_avail) && (!pZip->m_pState->m_pMem)) - { - read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); - if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) - { - status = TINFL_STATUS_FAILED; - break; - } - cur_file_ofs += read_buf_avail; - comp_remaining -= read_buf_avail; - read_buf_ofs = 0; - } - in_buf_size = (size_t)read_buf_avail; - status = tinfl_decompress(&inflator, (mz_uint8 *)pRead_buf + read_buf_ofs, &in_buf_size, (mz_uint8 *)pBuf, (mz_uint8 *)pBuf + out_buf_ofs, &out_buf_size, TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF | (comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0)); - read_buf_avail -= in_buf_size; - read_buf_ofs += in_buf_size; - out_buf_ofs += out_buf_size; - } while (status == TINFL_STATUS_NEEDS_MORE_INPUT); - - if (status == TINFL_STATUS_DONE) - { - // Make sure the entire file was decompressed, and check its CRC. - if ((out_buf_ofs != file_stat.m_uncomp_size) || (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, (size_t)file_stat.m_uncomp_size) != file_stat.m_crc32)) - status = TINFL_STATUS_FAILED; - } - - if ((!pZip->m_pState->m_pMem) && (!pUser_read_buf)) - pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); - - return status == TINFL_STATUS_DONE; -} - -mz_bool mz_zip_reader_extract_file_to_mem_no_alloc(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size) -{ - int file_index = mz_zip_reader_locate_file(pZip, pFilename, NULL, flags); - if (file_index < 0) - return MZ_FALSE; - return mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size, flags, pUser_read_buf, user_read_buf_size); -} - -mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags) -{ - return mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size, flags, NULL, 0); -} - -mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags) -{ - return mz_zip_reader_extract_file_to_mem_no_alloc(pZip, pFilename, pBuf, buf_size, flags, NULL, 0); -} - -void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index, size_t *pSize, mz_uint flags) -{ - mz_uint64 comp_size, uncomp_size, alloc_size; - const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index); - void *pBuf; - - if (pSize) - *pSize = 0; - if (!p) - return NULL; - - comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); - uncomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); - - alloc_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? comp_size : uncomp_size; -#ifdef _MSC_VER - if (((0, sizeof(size_t) == sizeof(mz_uint32))) && (alloc_size > 0x7FFFFFFF)) -#else - if (((sizeof(size_t) == sizeof(mz_uint32))) && (alloc_size > 0x7FFFFFFF)) -#endif - return NULL; - - if (NULL == (pBuf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)alloc_size))) - return NULL; - - if (!mz_zip_reader_extract_to_mem(pZip, file_index, pBuf, (size_t)alloc_size, flags)) - { - pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); - return NULL; - } - - if (pSize) - *pSize = (size_t)alloc_size; - - return pBuf; -} - -void *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip, const char *pFilename, size_t *pSize, mz_uint flags) -{ - int file_index = mz_zip_reader_locate_file(pZip, pFilename, NULL, flags); - if (file_index < 0) - { - if (pSize) *pSize = 0; - return MZ_FALSE; - } - return mz_zip_reader_extract_to_heap(pZip, file_index, pSize, flags); -} - -mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip, mz_uint file_index, mz_file_write_func pCallback, void *pOpaque, mz_uint flags) -{ - int status = TINFL_STATUS_DONE; mz_uint file_crc32 = MZ_CRC32_INIT; - mz_uint64 read_buf_size, read_buf_ofs = 0, read_buf_avail, comp_remaining, out_buf_ofs = 0, cur_file_ofs; - mz_zip_archive_file_stat file_stat; - void *pRead_buf = NULL; void *pWrite_buf = NULL; - mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; - - if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) - return MZ_FALSE; - - // Empty file, or a directory (but not always a directory - I've seen odd zips with directories that have compressed data which inflates to 0 bytes) - if (!file_stat.m_comp_size) - return MZ_TRUE; - - // Entry is a subdirectory (I've seen old zips with dir entries which have compressed deflate data which inflates to 0 bytes, but these entries claim to uncompress to 512 bytes in the headers). - // I'm torn how to handle this case - should it fail instead? - if (mz_zip_reader_is_file_a_directory(pZip, file_index)) - return MZ_TRUE; - - // Encryption and patch files are not supported. - if (file_stat.m_bit_flag & (1 | 32)) - return MZ_FALSE; - - // This function only supports stored and deflate. - if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) && (file_stat.m_method != MZ_DEFLATED)) - return MZ_FALSE; - - // Read and parse the local directory entry. - cur_file_ofs = file_stat.m_local_header_ofs; - if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) - return MZ_FALSE; - if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) - return MZ_FALSE; - - cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); - if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size) - return MZ_FALSE; - - // Decompress the file either directly from memory or from a file input buffer. - if (pZip->m_pState->m_pMem) - { - pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs; - read_buf_size = read_buf_avail = file_stat.m_comp_size; - comp_remaining = 0; - } - else - { - read_buf_size = MZ_MIN(file_stat.m_comp_size, MZ_ZIP_MAX_IO_BUF_SIZE); - if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)read_buf_size))) - return MZ_FALSE; - read_buf_avail = 0; - comp_remaining = file_stat.m_comp_size; - } - - if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method)) - { - // The file is stored or the caller has requested the compressed data. - if (pZip->m_pState->m_pMem) - { -#ifdef _MSC_VER - if (((0, sizeof(size_t) == sizeof(mz_uint32))) && (file_stat.m_comp_size > 0xFFFFFFFF)) -#else - if (((sizeof(size_t) == sizeof(mz_uint32))) && (file_stat.m_comp_size > 0xFFFFFFFF)) -#endif - return MZ_FALSE; - - if (pCallback(pOpaque, out_buf_ofs, pRead_buf, (size_t)file_stat.m_comp_size) != file_stat.m_comp_size) - status = TINFL_STATUS_FAILED; - else if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) - file_crc32 = (mz_uint32)mz_crc32(file_crc32, (const mz_uint8 *)pRead_buf, (size_t)file_stat.m_comp_size); - - cur_file_ofs += file_stat.m_comp_size; - out_buf_ofs += file_stat.m_comp_size; - comp_remaining = 0; - } - else - { - while (comp_remaining) - { - read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); - - if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) - { - status = TINFL_STATUS_FAILED; - break; - } - - if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) - file_crc32 = (mz_uint32)mz_crc32(file_crc32, (const mz_uint8 *)pRead_buf, (size_t)read_buf_avail); - - if (pCallback(pOpaque, out_buf_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) - { - status = TINFL_STATUS_FAILED; - break; - } - cur_file_ofs += read_buf_avail; - out_buf_ofs += read_buf_avail; - comp_remaining -= read_buf_avail; - } - } - } - else - { - tinfl_decompressor inflator; - tinfl_init(&inflator); - - if (NULL == (pWrite_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, TINFL_LZ_DICT_SIZE))) - status = TINFL_STATUS_FAILED; - else - { - do - { - mz_uint8 *pWrite_buf_cur = (mz_uint8 *)pWrite_buf + (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); - size_t in_buf_size, out_buf_size = TINFL_LZ_DICT_SIZE - (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); - if ((!read_buf_avail) && (!pZip->m_pState->m_pMem)) - { - read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); - if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) - { - status = TINFL_STATUS_FAILED; - break; - } - cur_file_ofs += read_buf_avail; - comp_remaining -= read_buf_avail; - read_buf_ofs = 0; - } - - in_buf_size = (size_t)read_buf_avail; - status = tinfl_decompress(&inflator, (const mz_uint8 *)pRead_buf + read_buf_ofs, &in_buf_size, (mz_uint8 *)pWrite_buf, pWrite_buf_cur, &out_buf_size, comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0); - read_buf_avail -= in_buf_size; - read_buf_ofs += in_buf_size; - - if (out_buf_size) - { - if (pCallback(pOpaque, out_buf_ofs, pWrite_buf_cur, out_buf_size) != out_buf_size) - { - status = TINFL_STATUS_FAILED; - break; - } - file_crc32 = (mz_uint32)mz_crc32(file_crc32, pWrite_buf_cur, out_buf_size); - if ((out_buf_ofs += out_buf_size) > file_stat.m_uncomp_size) - { - status = TINFL_STATUS_FAILED; - break; - } - } - } while ((status == TINFL_STATUS_NEEDS_MORE_INPUT) || (status == TINFL_STATUS_HAS_MORE_OUTPUT)); - } - } - - if ((status == TINFL_STATUS_DONE) && (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA))) - { - // Make sure the entire file was decompressed, and check its CRC. - if ((out_buf_ofs != file_stat.m_uncomp_size) || (file_crc32 != file_stat.m_crc32)) - status = TINFL_STATUS_FAILED; - } - - if (!pZip->m_pState->m_pMem) - pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); - if (pWrite_buf) - pZip->m_pFree(pZip->m_pAlloc_opaque, pWrite_buf); - - return status == TINFL_STATUS_DONE; -} - -mz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive *pZip, const char *pFilename, mz_file_write_func pCallback, void *pOpaque, mz_uint flags) -{ - int file_index = mz_zip_reader_locate_file(pZip, pFilename, NULL, flags); - if (file_index < 0) - return MZ_FALSE; - return mz_zip_reader_extract_to_callback(pZip, file_index, pCallback, pOpaque, flags); -} - -#ifndef MINIZ_NO_STDIO -static size_t mz_zip_file_write_callback(void *pOpaque, mz_uint64 ofs, const void *pBuf, size_t n) -{ - (void)ofs; return MZ_FWRITE(pBuf, 1, n, (MZ_FILE*)pOpaque); -} - -mz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip, mz_uint file_index, const wchar_t *pDst_filename, mz_uint flags) -{ - mz_bool status; - mz_zip_archive_file_stat file_stat; - MZ_FILE *pFile; - - if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) - return MZ_FALSE; - - pFile = MZ_FOPEN(pDst_filename, L"wb"); - - if (!pFile) - return MZ_FALSE; - - status = mz_zip_reader_extract_to_callback(pZip, file_index, mz_zip_file_write_callback, pFile, flags); - - if (MZ_FCLOSE(pFile) == EOF) - return MZ_FALSE; - -#ifndef MINIZ_NO_TIME - if (status) - mz_zip_set_file_times(pDst_filename, file_stat.m_time, file_stat.m_time); -#endif - return status; -} -#endif // #ifndef MINIZ_NO_STDIO - -mz_bool mz_zip_reader_end(mz_zip_archive *pZip) -{ - if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) - return MZ_FALSE; - - if (pZip->m_pState) - { - mz_zip_internal_state *pState = pZip->m_pState; pZip->m_pState = NULL; - mz_zip_array_clear(pZip, &pState->m_central_dir); - mz_zip_array_clear(pZip, &pState->m_central_dir_offsets); - mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets); - -#ifndef MINIZ_NO_STDIO - if (pState->m_pFile) - { - MZ_FCLOSE(pState->m_pFile); - pState->m_pFile = NULL; - } -#endif // #ifndef MINIZ_NO_STDIO - - pZip->m_pFree(pZip->m_pAlloc_opaque, pState); - } - - pZip->m_zip_mode = MZ_ZIP_MODE_INVALID; - - return MZ_TRUE; -} - -#ifndef MINIZ_NO_STDIO -mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip, const char *pArchive_filename, const wchar_t *pDst_filename, mz_uint flags) -{ - int file_index = mz_zip_reader_locate_file(pZip, pArchive_filename, NULL, flags); - if (file_index < 0) - return MZ_FALSE; - return mz_zip_reader_extract_to_file(pZip, file_index, pDst_filename, flags); -} -#endif - -// ------------------- .ZIP archive writing - -#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS - -static void mz_write_le16(mz_uint8 *p, mz_uint16 v) { p[0] = (mz_uint8)v; p[1] = (mz_uint8)(v >> 8); } -static void mz_write_le32(mz_uint8 *p, mz_uint32 v) { p[0] = (mz_uint8)v; p[1] = (mz_uint8)(v >> 8); p[2] = (mz_uint8)(v >> 16); p[3] = (mz_uint8)(v >> 24); } -#define MZ_WRITE_LE16(p, v) mz_write_le16((mz_uint8 *)(p), (mz_uint16)(v)) -#define MZ_WRITE_LE32(p, v) mz_write_le32((mz_uint8 *)(p), (mz_uint32)(v)) - -mz_bool mz_zip_writer_init(mz_zip_archive *pZip, mz_uint64 existing_size) -{ - if ((!pZip) || (pZip->m_pState) || (!pZip->m_pWrite) || (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID)) - return MZ_FALSE; - - if (pZip->m_file_offset_alignment) - { - // Ensure user specified file offset alignment is a power of 2. - if (pZip->m_file_offset_alignment & (pZip->m_file_offset_alignment - 1)) - return MZ_FALSE; - } - - if (!pZip->m_pAlloc) pZip->m_pAlloc = def_alloc_func; - if (!pZip->m_pFree) pZip->m_pFree = def_free_func; - if (!pZip->m_pRealloc) pZip->m_pRealloc = def_realloc_func; - - pZip->m_zip_mode = MZ_ZIP_MODE_WRITING; - pZip->m_archive_size = existing_size; - pZip->m_central_directory_file_ofs = 0; - pZip->m_total_files = 0; - - if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state)))) - return MZ_FALSE; - memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state)); - MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir, sizeof(mz_uint8)); - MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets, sizeof(mz_uint32)); - MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets, sizeof(mz_uint32)); - return MZ_TRUE; -} - -static size_t mz_zip_heap_write_func(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n) -{ - mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; - mz_zip_internal_state *pState = pZip->m_pState; - mz_uint64 new_size = MZ_MAX(file_ofs + n, pState->m_mem_size); -#ifdef _MSC_VER - if ((!n) || ((0, sizeof(size_t) == sizeof(mz_uint32)) && (new_size > 0x7FFFFFFF))) -#else - if ((!n) || ((sizeof(size_t) == sizeof(mz_uint32)) && (new_size > 0x7FFFFFFF))) -#endif - return 0; - if (new_size > pState->m_mem_capacity) - { - void *pNew_block; - size_t new_capacity = MZ_MAX(64, pState->m_mem_capacity); while (new_capacity < new_size) new_capacity *= 2; - if (NULL == (pNew_block = pZip->m_pRealloc(pZip->m_pAlloc_opaque, pState->m_pMem, 1, new_capacity))) - return 0; - pState->m_pMem = pNew_block; pState->m_mem_capacity = new_capacity; - } - memcpy((mz_uint8 *)pState->m_pMem + file_ofs, pBuf, n); - pState->m_mem_size = (size_t)new_size; - return n; -} - -mz_bool mz_zip_writer_init_heap(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size) -{ - pZip->m_pWrite = mz_zip_heap_write_func; - pZip->m_pIO_opaque = pZip; - if (!mz_zip_writer_init(pZip, size_to_reserve_at_beginning)) - return MZ_FALSE; - if (0 != (initial_allocation_size = MZ_MAX(initial_allocation_size, size_to_reserve_at_beginning))) - { - if (NULL == (pZip->m_pState->m_pMem = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, initial_allocation_size))) - { - mz_zip_writer_end(pZip); - return MZ_FALSE; - } - pZip->m_pState->m_mem_capacity = initial_allocation_size; - } - return MZ_TRUE; -} - -#ifndef MINIZ_NO_STDIO -static size_t mz_zip_file_write_func(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n) -{ - mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; - mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile); - if (((mz_int64)file_ofs < 0) || (((cur_ofs != (mz_int64)file_ofs)) && (MZ_FSEEK64(pZip->m_pState->m_pFile, (mz_int64)file_ofs, SEEK_SET)))) - return 0; - return MZ_FWRITE(pBuf, 1, n, pZip->m_pState->m_pFile); -} - -mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const wchar_t *pFilename, mz_uint64 size_to_reserve_at_beginning) -{ - MZ_FILE *pFile; - pZip->m_pWrite = mz_zip_file_write_func; - pZip->m_pIO_opaque = pZip; - if (!mz_zip_writer_init(pZip, size_to_reserve_at_beginning)) - return MZ_FALSE; - if (NULL == (pFile = MZ_FOPEN(pFilename, L"wb"))) - { - mz_zip_writer_end(pZip); - return MZ_FALSE; - } - pZip->m_pState->m_pFile = pFile; - if (size_to_reserve_at_beginning) - { - mz_uint64 cur_ofs = 0; char buf[4096]; MZ_CLEAR_OBJ(buf); - do - { - size_t n = (size_t)MZ_MIN(sizeof(buf), size_to_reserve_at_beginning); - if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_ofs, buf, n) != n) - { - mz_zip_writer_end(pZip); - return MZ_FALSE; - } - cur_ofs += n; size_to_reserve_at_beginning -= n; - } while (size_to_reserve_at_beginning); - } - return MZ_TRUE; -} -#endif // #ifndef MINIZ_NO_STDIO - -mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip, const wchar_t *pFilename) -{ - mz_zip_internal_state *pState; - if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) - return MZ_FALSE; - // No sense in trying to write to an archive that's already at the support max size - if ((pZip->m_total_files == 0xFFFF) || ((pZip->m_archive_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_ZIP_LOCAL_DIR_HEADER_SIZE) > 0xFFFFFFFF)) - return MZ_FALSE; - - pState = pZip->m_pState; - - if (pState->m_pFile) - { -#ifdef MINIZ_NO_STDIO - pFilename; return MZ_FALSE; -#else - // Archive is being read from stdio - try to reopen as writable. - if (pZip->m_pIO_opaque != pZip) - return MZ_FALSE; - if (!pFilename) - return MZ_FALSE; - pZip->m_pWrite = mz_zip_file_write_func; - if (NULL == (pState->m_pFile = MZ_FREOPEN(pFilename, L"r+b", pState->m_pFile))) - { - // The mz_zip_archive is now in a bogus state because pState->m_pFile is NULL, so just close it. - mz_zip_reader_end(pZip); - return MZ_FALSE; - } -#endif // #ifdef MINIZ_NO_STDIO - } - else if (pState->m_pMem) - { - // Archive lives in a memory block. Assume it's from the heap that we can resize using the realloc callback. - if (pZip->m_pIO_opaque != pZip) - return MZ_FALSE; - pState->m_mem_capacity = pState->m_mem_size; - pZip->m_pWrite = mz_zip_heap_write_func; - } - // Archive is being read via a user provided read function - make sure the user has specified a write function too. - else if (!pZip->m_pWrite) - return MZ_FALSE; - - // Start writing new files at the archive's current central directory location. - pZip->m_archive_size = pZip->m_central_directory_file_ofs; - pZip->m_zip_mode = MZ_ZIP_MODE_WRITING; - pZip->m_central_directory_file_ofs = 0; - - return MZ_TRUE; -} - -mz_bool mz_zip_writer_add_mem(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, mz_uint level_and_flags) -{ - return mz_zip_writer_add_mem_ex(pZip, pArchive_name, pBuf, buf_size, NULL, 0, level_and_flags, 0, 0); -} - -typedef struct -{ - mz_zip_archive *m_pZip; - mz_uint64 m_cur_archive_file_ofs; - mz_uint64 m_comp_size; -} mz_zip_writer_add_state; - -static mz_bool mz_zip_writer_add_put_buf_callback(const void* pBuf, int len, void *pUser) -{ - mz_zip_writer_add_state *pState = (mz_zip_writer_add_state *)pUser; - if ((int)pState->m_pZip->m_pWrite(pState->m_pZip->m_pIO_opaque, pState->m_cur_archive_file_ofs, pBuf, len) != len) - return MZ_FALSE; - pState->m_cur_archive_file_ofs += len; - pState->m_comp_size += len; - return MZ_TRUE; -} - -static mz_bool mz_zip_writer_create_local_dir_header(mz_zip_archive *pZip, mz_uint8 *pDst, mz_uint16 filename_size, mz_uint16 extra_size, mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date) -{ - (void)pZip; - memset(pDst, 0, MZ_ZIP_LOCAL_DIR_HEADER_SIZE); - MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_SIG_OFS, MZ_ZIP_LOCAL_DIR_HEADER_SIG); - MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_VERSION_NEEDED_OFS, method ? 20 : 0); - MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_BIT_FLAG_OFS, bit_flags); - MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_METHOD_OFS, method); - MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_TIME_OFS, dos_time); - MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_DATE_OFS, dos_date); - MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_CRC32_OFS, uncomp_crc32); - MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS, comp_size); - MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS, uncomp_size); - MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILENAME_LEN_OFS, filename_size); - MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_EXTRA_LEN_OFS, extra_size); - return MZ_TRUE; -} - -static mz_bool mz_zip_writer_create_central_dir_header(mz_zip_archive *pZip, mz_uint8 *pDst, mz_uint16 filename_size, mz_uint16 extra_size, mz_uint16 comment_size, mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date, mz_uint64 local_header_ofs, mz_uint32 ext_attributes) -{ - (void)pZip; - memset(pDst, 0, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE); - MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_SIG_OFS, MZ_ZIP_CENTRAL_DIR_HEADER_SIG); - MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_VERSION_NEEDED_OFS, method ? 20 : 0); - MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_BIT_FLAG_OFS, bit_flags); - MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_METHOD_OFS, method); - MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILE_TIME_OFS, dos_time); - MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILE_DATE_OFS, dos_date); - MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_CRC32_OFS, uncomp_crc32); - MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS, comp_size); - MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS, uncomp_size); - MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILENAME_LEN_OFS, filename_size); - MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_EXTRA_LEN_OFS, extra_size); - MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_COMMENT_LEN_OFS, comment_size); - MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS, ext_attributes); - MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_LOCAL_HEADER_OFS, local_header_ofs); - return MZ_TRUE; -} - -static mz_bool mz_zip_writer_add_to_central_dir(mz_zip_archive *pZip, const char *pFilename, mz_uint16 filename_size, const void *pExtra, mz_uint16 extra_size, const void *pComment, mz_uint16 comment_size, mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date, mz_uint64 local_header_ofs, mz_uint32 ext_attributes) -{ - mz_zip_internal_state *pState = pZip->m_pState; - mz_uint32 central_dir_ofs = (mz_uint32)pState->m_central_dir.m_size; - size_t orig_central_dir_size = pState->m_central_dir.m_size; - mz_uint8 central_dir_header[MZ_ZIP_CENTRAL_DIR_HEADER_SIZE]; - - // No zip64 support yet - if ((local_header_ofs > 0xFFFFFFFF) || (((mz_uint64)pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size + extra_size + comment_size) > 0xFFFFFFFF)) - return MZ_FALSE; - - if (!mz_zip_writer_create_central_dir_header(pZip, central_dir_header, filename_size, extra_size, comment_size, uncomp_size, comp_size, uncomp_crc32, method, bit_flags, dos_time, dos_date, local_header_ofs, ext_attributes)) - return MZ_FALSE; - - if ((!mz_zip_array_push_back(pZip, &pState->m_central_dir, central_dir_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)) || - (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pFilename, filename_size)) || - (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pExtra, extra_size)) || - (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pComment, comment_size)) || - (!mz_zip_array_push_back(pZip, &pState->m_central_dir_offsets, ¢ral_dir_ofs, 1))) - { - // Try to push the central directory array back into its original state. - mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); - return MZ_FALSE; - } - - return MZ_TRUE; -} - -static mz_bool mz_zip_writer_validate_archive_name(const char *pArchive_name) -{ - // Basic ZIP archive filename validity checks: Valid filenames cannot start with a forward slash, cannot contain a drive letter, and cannot use DOS-style backward slashes. - if (*pArchive_name == '/') - return MZ_FALSE; - while (*pArchive_name) - { - if ((*pArchive_name == '\\') || (*pArchive_name == ':')) - return MZ_FALSE; - pArchive_name++; - } - return MZ_TRUE; -} - -static mz_uint mz_zip_writer_compute_padding_needed_for_file_alignment(mz_zip_archive *pZip) -{ - mz_uint32 n; - if (!pZip->m_file_offset_alignment) - return 0; - n = (mz_uint32)(pZip->m_archive_size & (pZip->m_file_offset_alignment - 1)); - return (pZip->m_file_offset_alignment - n) & (pZip->m_file_offset_alignment - 1); -} - -static mz_bool mz_zip_writer_write_zeros(mz_zip_archive *pZip, mz_uint64 cur_file_ofs, mz_uint32 n) -{ - char buf[4096]; - memset(buf, 0, MZ_MIN(sizeof(buf), n)); - while (n) - { - mz_uint32 s = MZ_MIN(sizeof(buf), n); - if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_file_ofs, buf, s) != s) - return MZ_FALSE; - cur_file_ofs += s; n -= s; - } - return MZ_TRUE; -} - -mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, mz_uint64 uncomp_size, mz_uint32 uncomp_crc32) -{ - mz_uint16 method = 0, dos_time = 0, dos_date = 0; - mz_uint level, ext_attributes = 0, num_alignment_padding_bytes; - mz_uint64 local_dir_header_ofs = pZip->m_archive_size, cur_archive_file_ofs = pZip->m_archive_size, comp_size = 0; - size_t archive_name_size; - mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE]; - tdefl_compressor *pComp = NULL; - mz_bool store_data_uncompressed; - mz_zip_internal_state *pState; - - if ((int)level_and_flags < 0) - level_and_flags = MZ_DEFAULT_LEVEL; - level = level_and_flags & 0xF; - store_data_uncompressed = ((!level) || (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)); - - if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || ((buf_size) && (!pBuf)) || (!pArchive_name) || ((comment_size) && (!pComment)) || (pZip->m_total_files == 0xFFFF) || (level > MZ_UBER_COMPRESSION)) - return MZ_FALSE; - - pState = pZip->m_pState; - - if ((!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (uncomp_size)) - return MZ_FALSE; - // No zip64 support yet - if ((buf_size > 0xFFFFFFFF) || (uncomp_size > 0xFFFFFFFF)) - return MZ_FALSE; - if (!mz_zip_writer_validate_archive_name(pArchive_name)) - return MZ_FALSE; - -#ifndef MINIZ_NO_TIME - { - time_t cur_time; time(&cur_time); - mz_zip_time_to_dos_time(cur_time, &dos_time, &dos_date); - } -#endif // #ifndef MINIZ_NO_TIME - - archive_name_size = strlen(pArchive_name); - if (archive_name_size > 0xFFFF) - return MZ_FALSE; - - num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); - - // no zip64 support yet - if ((pZip->m_total_files == 0xFFFF) || ((pZip->m_archive_size + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + comment_size + archive_name_size) > 0xFFFFFFFF)) - return MZ_FALSE; - - if ((archive_name_size) && (pArchive_name[archive_name_size - 1] == '/')) - { - // Set DOS Subdirectory attribute bit. - ext_attributes |= 0x10; - // Subdirectories cannot contain data. - if ((buf_size) || (uncomp_size)) - return MZ_FALSE; - } - - // Try to do any allocations before writing to the archive, so if an allocation fails the file remains unmodified. (A good idea if we're doing an in-place modification.) - if ((!mz_zip_array_ensure_room(pZip, &pState->m_central_dir, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + comment_size)) || (!mz_zip_array_ensure_room(pZip, &pState->m_central_dir_offsets, 1))) - return MZ_FALSE; - - if ((!store_data_uncompressed) && (buf_size)) - { - if (NULL == (pComp = (tdefl_compressor *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor)))) - return MZ_FALSE; - } - - if (!mz_zip_writer_write_zeros(pZip, cur_archive_file_ofs, num_alignment_padding_bytes + sizeof(local_dir_header))) - { - pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); - return MZ_FALSE; - } - local_dir_header_ofs += num_alignment_padding_bytes; - if (pZip->m_file_offset_alignment) { MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == 0); } - cur_archive_file_ofs += num_alignment_padding_bytes + sizeof(local_dir_header); - - MZ_CLEAR_OBJ(local_dir_header); - if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) - { - pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); - return MZ_FALSE; - } - cur_archive_file_ofs += archive_name_size; - - if (!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) - { - uncomp_crc32 = (mz_uint32)mz_crc32(MZ_CRC32_INIT, (const mz_uint8*)pBuf, buf_size); - uncomp_size = buf_size; - if (uncomp_size <= 3) - { - level = 0; - store_data_uncompressed = MZ_TRUE; - } - } - - if (store_data_uncompressed) - { - if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pBuf, buf_size) != buf_size) - { - pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); - return MZ_FALSE; - } - - cur_archive_file_ofs += buf_size; - comp_size = buf_size; - - if (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA) - method = MZ_DEFLATED; - } - else if (buf_size) - { - mz_zip_writer_add_state state; - - state.m_pZip = pZip; - state.m_cur_archive_file_ofs = cur_archive_file_ofs; - state.m_comp_size = 0; - - if ((tdefl_init(pComp, mz_zip_writer_add_put_buf_callback, &state, tdefl_create_comp_flags_from_zip_params(level, -15, MZ_DEFAULT_STRATEGY)) != TDEFL_STATUS_OKAY) || - (tdefl_compress_buffer(pComp, pBuf, buf_size, TDEFL_FINISH) != TDEFL_STATUS_DONE)) - { - pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); - return MZ_FALSE; - } - - comp_size = state.m_comp_size; - cur_archive_file_ofs = state.m_cur_archive_file_ofs; - - method = MZ_DEFLATED; - } - - pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); - pComp = NULL; - - // no zip64 support yet - if ((comp_size > 0xFFFFFFFF) || (cur_archive_file_ofs > 0xFFFFFFFF)) - return MZ_FALSE; - - if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, 0, uncomp_size, comp_size, uncomp_crc32, method, 0, dos_time, dos_date)) - return MZ_FALSE; - - if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) - return MZ_FALSE; - - if (!mz_zip_writer_add_to_central_dir(pZip, pArchive_name, (mz_uint16)archive_name_size, NULL, 0, pComment, comment_size, uncomp_size, comp_size, uncomp_crc32, method, 0, dos_time, dos_date, local_dir_header_ofs, ext_attributes)) - return MZ_FALSE; - - pZip->m_total_files++; - pZip->m_archive_size = cur_archive_file_ofs; - - return MZ_TRUE; -} - -#ifndef MINIZ_NO_STDIO -mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, const wchar_t *pSrc_filename, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags) -{ - mz_uint uncomp_crc32 = MZ_CRC32_INIT, level, num_alignment_padding_bytes; - mz_uint16 method = 0, dos_time = 0, dos_date = 0, ext_attributes = 0; - mz_uint64 local_dir_header_ofs = pZip->m_archive_size, cur_archive_file_ofs = pZip->m_archive_size, uncomp_size = 0, comp_size = 0; - size_t archive_name_size; - mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE]; - MZ_FILE *pSrc_file = NULL; - - if ((int)level_and_flags < 0) - level_and_flags = MZ_DEFAULT_LEVEL; - level = level_and_flags & 0xF; - - if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || (!pArchive_name) || ((comment_size) && (!pComment)) || (level > MZ_UBER_COMPRESSION)) - return MZ_FALSE; - if (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA) - return MZ_FALSE; - if (!mz_zip_writer_validate_archive_name(pArchive_name)) - return MZ_FALSE; - - archive_name_size = strlen(pArchive_name); - if (archive_name_size > 0xFFFF) - return MZ_FALSE; - - num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); - - // no zip64 support yet - if ((pZip->m_total_files == 0xFFFF) || ((pZip->m_archive_size + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + comment_size + archive_name_size) > 0xFFFFFFFF)) - return MZ_FALSE; - - if (!mz_zip_get_file_modified_time(pSrc_filename, &dos_time, &dos_date)) - return MZ_FALSE; - - pSrc_file = MZ_FOPEN(pSrc_filename, L"rb"); - if (!pSrc_file) - return MZ_FALSE; - MZ_FSEEK64(pSrc_file, 0, SEEK_END); - uncomp_size = MZ_FTELL64(pSrc_file); - MZ_FSEEK64(pSrc_file, 0, SEEK_SET); - - if (uncomp_size > 0xFFFFFFFF) - { - // No zip64 support yet - MZ_FCLOSE(pSrc_file); - return MZ_FALSE; - } - if (uncomp_size <= 3) - level = 0; - - if (!mz_zip_writer_write_zeros(pZip, cur_archive_file_ofs, num_alignment_padding_bytes + sizeof(local_dir_header))) - { - MZ_FCLOSE(pSrc_file); - return MZ_FALSE; - } - local_dir_header_ofs += num_alignment_padding_bytes; - if (pZip->m_file_offset_alignment) { MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == 0); } - cur_archive_file_ofs += num_alignment_padding_bytes + sizeof(local_dir_header); - - MZ_CLEAR_OBJ(local_dir_header); - if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) - { - MZ_FCLOSE(pSrc_file); - return MZ_FALSE; - } - cur_archive_file_ofs += archive_name_size; - - if (uncomp_size) - { - mz_uint64 uncomp_remaining = uncomp_size; - void *pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, MZ_ZIP_MAX_IO_BUF_SIZE); - if (!pRead_buf) - { - MZ_FCLOSE(pSrc_file); - return MZ_FALSE; - } - - if (!level) - { - while (uncomp_remaining) - { - mz_uint n = (mz_uint)MZ_MIN(MZ_ZIP_MAX_IO_BUF_SIZE, uncomp_remaining); - if ((MZ_FREAD(pRead_buf, 1, n, pSrc_file) != n) || (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pRead_buf, n) != n)) - { - pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); - MZ_FCLOSE(pSrc_file); - return MZ_FALSE; - } - uncomp_crc32 = (mz_uint32)mz_crc32(uncomp_crc32, (const mz_uint8 *)pRead_buf, n); - uncomp_remaining -= n; - cur_archive_file_ofs += n; - } - comp_size = uncomp_size; - } - else - { - mz_bool result = MZ_FALSE; - mz_zip_writer_add_state state; - tdefl_compressor *pComp = (tdefl_compressor *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor)); - if (!pComp) - { - pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); - MZ_FCLOSE(pSrc_file); - return MZ_FALSE; - } - - state.m_pZip = pZip; - state.m_cur_archive_file_ofs = cur_archive_file_ofs; - state.m_comp_size = 0; - - if (tdefl_init(pComp, mz_zip_writer_add_put_buf_callback, &state, tdefl_create_comp_flags_from_zip_params(level, -15, MZ_DEFAULT_STRATEGY)) != TDEFL_STATUS_OKAY) - { - pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); - pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); - MZ_FCLOSE(pSrc_file); - return MZ_FALSE; - } - - for (; ; ) - { - size_t in_buf_size = (mz_uint32)MZ_MIN(uncomp_remaining, MZ_ZIP_MAX_IO_BUF_SIZE); - tdefl_status status; - - if (MZ_FREAD(pRead_buf, 1, in_buf_size, pSrc_file) != in_buf_size) - break; - - uncomp_crc32 = (mz_uint32)mz_crc32(uncomp_crc32, (const mz_uint8 *)pRead_buf, in_buf_size); - uncomp_remaining -= in_buf_size; - - status = tdefl_compress_buffer(pComp, pRead_buf, in_buf_size, uncomp_remaining ? TDEFL_NO_FLUSH : TDEFL_FINISH); - if (status == TDEFL_STATUS_DONE) - { - result = MZ_TRUE; - break; - } - else if (status != TDEFL_STATUS_OKAY) - break; - } - - pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); - - if (!result) - { - pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); - MZ_FCLOSE(pSrc_file); - return MZ_FALSE; - } - - comp_size = state.m_comp_size; - cur_archive_file_ofs = state.m_cur_archive_file_ofs; - - method = MZ_DEFLATED; - } - - pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); - } - - MZ_FCLOSE(pSrc_file); pSrc_file = NULL; - - // no zip64 support yet - if ((comp_size > 0xFFFFFFFF) || (cur_archive_file_ofs > 0xFFFFFFFF)) - return MZ_FALSE; - - if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, 0, uncomp_size, comp_size, uncomp_crc32, method, 0, dos_time, dos_date)) - return MZ_FALSE; - - if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) - return MZ_FALSE; - - if (!mz_zip_writer_add_to_central_dir(pZip, pArchive_name, (mz_uint16)archive_name_size, NULL, 0, pComment, comment_size, uncomp_size, comp_size, uncomp_crc32, method, 0, dos_time, dos_date, local_dir_header_ofs, ext_attributes)) - return MZ_FALSE; - - pZip->m_total_files++; - pZip->m_archive_size = cur_archive_file_ofs; - - return MZ_TRUE; -} -#endif // #ifndef MINIZ_NO_STDIO - -mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip, mz_zip_archive *pSource_zip, mz_uint file_index) -{ - mz_uint n, bit_flags, num_alignment_padding_bytes; - mz_uint64 comp_bytes_remaining, local_dir_header_ofs; - mz_uint64 cur_src_file_ofs, cur_dst_file_ofs; - mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; - mz_uint8 central_header[MZ_ZIP_CENTRAL_DIR_HEADER_SIZE]; - size_t orig_central_dir_size; - mz_zip_internal_state *pState; - void *pBuf; const mz_uint8 *pSrc_central_header; - - if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING)) - return MZ_FALSE; - if (NULL == (pSrc_central_header = mz_zip_reader_get_cdh(pSource_zip, file_index))) - return MZ_FALSE; - pState = pZip->m_pState; - - num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); - - // no zip64 support yet - if ((pZip->m_total_files == 0xFFFF) || ((pZip->m_archive_size + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) > 0xFFFFFFFF)) - return MZ_FALSE; - - cur_src_file_ofs = MZ_READ_LE32(pSrc_central_header + MZ_ZIP_CDH_LOCAL_HEADER_OFS); - cur_dst_file_ofs = pZip->m_archive_size; - - if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) - return MZ_FALSE; - if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) - return MZ_FALSE; - cur_src_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE; - - if (!mz_zip_writer_write_zeros(pZip, cur_dst_file_ofs, num_alignment_padding_bytes)) - return MZ_FALSE; - cur_dst_file_ofs += num_alignment_padding_bytes; - local_dir_header_ofs = cur_dst_file_ofs; - if (pZip->m_file_offset_alignment) { MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == 0); } - - if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) - return MZ_FALSE; - cur_dst_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE; - - n = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); - comp_bytes_remaining = n + MZ_READ_LE32(pSrc_central_header + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); - - if (NULL == (pBuf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)MZ_MAX(sizeof(mz_uint32) * 4, MZ_MIN(MZ_ZIP_MAX_IO_BUF_SIZE, comp_bytes_remaining))))) - return MZ_FALSE; - - while (comp_bytes_remaining) - { - n = (mz_uint)MZ_MIN(MZ_ZIP_MAX_IO_BUF_SIZE, comp_bytes_remaining); - if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf, n) != n) - { - pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); - return MZ_FALSE; - } - cur_src_file_ofs += n; - - if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pBuf, n) != n) - { - pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); - return MZ_FALSE; - } - cur_dst_file_ofs += n; - - comp_bytes_remaining -= n; - } - - bit_flags = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_BIT_FLAG_OFS); - if (bit_flags & 8) - { - // Copy data descriptor - if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf, sizeof(mz_uint32) * 4) != sizeof(mz_uint32) * 4) - { - pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); - return MZ_FALSE; - } - - n = sizeof(mz_uint32) * ((MZ_READ_LE32(pBuf) == 0x08074b50) ? 4 : 3); - if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pBuf, n) != n) - { - pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); - return MZ_FALSE; - } - - cur_src_file_ofs += n; - cur_dst_file_ofs += n; - } - pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); - - // no zip64 support yet - if (cur_dst_file_ofs > 0xFFFFFFFF) - return MZ_FALSE; - - orig_central_dir_size = pState->m_central_dir.m_size; - - memcpy(central_header, pSrc_central_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE); - MZ_WRITE_LE32(central_header + MZ_ZIP_CDH_LOCAL_HEADER_OFS, local_dir_header_ofs); - if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, central_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)) - return MZ_FALSE; - - n = MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_EXTRA_LEN_OFS) + MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_COMMENT_LEN_OFS); - if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pSrc_central_header + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n)) - { - mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); - return MZ_FALSE; - } - - if (pState->m_central_dir.m_size > 0xFFFFFFFF) - return MZ_FALSE; - n = (mz_uint32)orig_central_dir_size; - if (!mz_zip_array_push_back(pZip, &pState->m_central_dir_offsets, &n, 1)) - { - mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); - return MZ_FALSE; - } - - pZip->m_total_files++; - pZip->m_archive_size = cur_dst_file_ofs; - - return MZ_TRUE; -} - -mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip) -{ - mz_zip_internal_state *pState; - mz_uint64 central_dir_ofs, central_dir_size; - mz_uint8 hdr[MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE]; - - if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING)) - return MZ_FALSE; - - pState = pZip->m_pState; - - // no zip64 support yet - if ((pZip->m_total_files > 0xFFFF) || ((pZip->m_archive_size + pState->m_central_dir.m_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) > 0xFFFFFFFF)) - return MZ_FALSE; - - central_dir_ofs = 0; - central_dir_size = 0; - if (pZip->m_total_files) - { - // Write central directory - central_dir_ofs = pZip->m_archive_size; - central_dir_size = pState->m_central_dir.m_size; - pZip->m_central_directory_file_ofs = central_dir_ofs; - if (pZip->m_pWrite(pZip->m_pIO_opaque, central_dir_ofs, pState->m_central_dir.m_p, (size_t)central_dir_size) != central_dir_size) - return MZ_FALSE; - pZip->m_archive_size += central_dir_size; - } - - // Write end of central directory record - MZ_CLEAR_OBJ(hdr); - MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_SIG_OFS, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG); - MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS, pZip->m_total_files); - MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS, pZip->m_total_files); - MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_SIZE_OFS, central_dir_size); - MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_OFS_OFS, central_dir_ofs); - - if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr, sizeof(hdr)) != sizeof(hdr)) - return MZ_FALSE; -#ifndef MINIZ_NO_STDIO - if ((pState->m_pFile) && (MZ_FFLUSH(pState->m_pFile) == EOF)) - return MZ_FALSE; -#endif // #ifndef MINIZ_NO_STDIO - - pZip->m_archive_size += sizeof(hdr); - - pZip->m_zip_mode = MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED; - return MZ_TRUE; -} - -mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **pBuf, size_t *pSize) -{ - if ((!pZip) || (!pZip->m_pState) || (!pBuf) || (!pSize)) - return MZ_FALSE; - if (pZip->m_pWrite != mz_zip_heap_write_func) - return MZ_FALSE; - if (!mz_zip_writer_finalize_archive(pZip)) - return MZ_FALSE; - - *pBuf = pZip->m_pState->m_pMem; - *pSize = pZip->m_pState->m_mem_size; - pZip->m_pState->m_pMem = NULL; - pZip->m_pState->m_mem_size = pZip->m_pState->m_mem_capacity = 0; - return MZ_TRUE; -} - -mz_bool mz_zip_writer_end(mz_zip_archive *pZip) -{ - mz_zip_internal_state *pState; - mz_bool status = MZ_TRUE; - if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || ((pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) && (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED))) - return MZ_FALSE; - - pState = pZip->m_pState; - pZip->m_pState = NULL; - mz_zip_array_clear(pZip, &pState->m_central_dir); - mz_zip_array_clear(pZip, &pState->m_central_dir_offsets); - mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets); - -#ifndef MINIZ_NO_STDIO - if (pState->m_pFile) - { - MZ_FCLOSE(pState->m_pFile); - pState->m_pFile = NULL; - } -#endif // #ifndef MINIZ_NO_STDIO - - if ((pZip->m_pWrite == mz_zip_heap_write_func) && (pState->m_pMem)) - { - pZip->m_pFree(pZip->m_pAlloc_opaque, pState->m_pMem); - pState->m_pMem = NULL; - } - - pZip->m_pFree(pZip->m_pAlloc_opaque, pState); - pZip->m_zip_mode = MZ_ZIP_MODE_INVALID; - return status; -} - -#ifndef MINIZ_NO_STDIO -mz_bool mz_zip_add_mem_to_archive_file_in_place(const wchar_t *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags) -{ - mz_bool status, created_new_archive = MZ_FALSE; - mz_zip_archive zip_archive; - struct MZ_FILE_STAT_STRUCT file_stat; - MZ_CLEAR_OBJ(zip_archive); - if ((int)level_and_flags < 0) - level_and_flags = MZ_DEFAULT_LEVEL; - if ((!pZip_filename) || (!pArchive_name) || ((buf_size) && (!pBuf)) || ((comment_size) && (!pComment)) || ((level_and_flags & 0xF) > MZ_UBER_COMPRESSION)) - return MZ_FALSE; - if (!mz_zip_writer_validate_archive_name(pArchive_name)) - return MZ_FALSE; - if (MZ_FILE_STAT(pZip_filename, &file_stat) != 0) - { - // Create a new archive. - if (!mz_zip_writer_init_file(&zip_archive, pZip_filename, 0)) - return MZ_FALSE; - created_new_archive = MZ_TRUE; - } - else - { - // Append to an existing archive. - if (!mz_zip_reader_init_file(&zip_archive, pZip_filename, level_and_flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY)) - return MZ_FALSE; - if (!mz_zip_writer_init_from_reader(&zip_archive, pZip_filename)) - { - mz_zip_reader_end(&zip_archive); - return MZ_FALSE; - } - } - status = mz_zip_writer_add_mem_ex(&zip_archive, pArchive_name, pBuf, buf_size, pComment, comment_size, level_and_flags, 0, 0); - // Always finalize, even if adding failed for some reason, so we have a valid central directory. (This may not always succeed, but we can try.) - if (!mz_zip_writer_finalize_archive(&zip_archive)) - status = MZ_FALSE; - if (!mz_zip_writer_end(&zip_archive)) - status = MZ_FALSE; - if ((!status) && (created_new_archive)) - { - // It's a new archive and something went wrong, so just delete it. - int ignoredStatus = MZ_DELETE_FILE(pZip_filename); - (void)ignoredStatus; - } - return status; -} - -void *mz_zip_extract_archive_file_to_heap(const wchar_t *pZip_filename, const char *pArchive_name, size_t *pSize, mz_uint flags) -{ - int file_index; - mz_zip_archive zip_archive; - void *p = NULL; - - if (pSize) - *pSize = 0; - - if ((!pZip_filename) || (!pArchive_name)) - return NULL; - - MZ_CLEAR_OBJ(zip_archive); - if (!mz_zip_reader_init_file(&zip_archive, pZip_filename, flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY)) - return NULL; - - if ((file_index = mz_zip_reader_locate_file(&zip_archive, pArchive_name, NULL, flags)) >= 0) - p = mz_zip_reader_extract_to_heap(&zip_archive, file_index, pSize, flags); - - mz_zip_reader_end(&zip_archive); - return p; -} - -#endif // #ifndef MINIZ_NO_STDIO - -#endif // #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS - -#endif // #ifndef MINIZ_NO_ARCHIVE_APIS - - -/* - This is free and unencumbered software released into the public domain. - - Anyone is free to copy, modify, publish, use, compile, sell, or - distribute this software, either in source code form or as a compiled - binary, for any purpose, commercial or non-commercial, and by any - means. - - In jurisdictions that recognize copyright laws, the author or authors - of this software dedicate any and all copyright interest in the - software to the public domain. We make this dedication for the benefit - of the public at large and to the detriment of our heirs and - successors. We intend this dedication to be an overt act of - relinquishment in perpetuity of all present and future rights to this - software under copyright law. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR - OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - OTHER DEALINGS IN THE SOFTWARE. - - For more information, please refer to -*/ diff --git a/plugins/ExtraPlugins/miniz/miniz.h b/plugins/ExtraPlugins/miniz/miniz.h deleted file mode 100644 index 261ac5a6dbac..000000000000 --- a/plugins/ExtraPlugins/miniz/miniz.h +++ /dev/null @@ -1,785 +0,0 @@ -#ifndef MINIZ_HEADER_INCLUDED -#define MINIZ_HEADER_INCLUDED - -#include - -// Defines to completely disable specific portions of miniz.c: -// If all macros here are defined the only functionality remaining will be CRC-32, adler-32, tinfl, and tdefl. - -// Define MINIZ_NO_STDIO to disable all usage and any functions which rely on stdio for file I/O. -//#define MINIZ_NO_STDIO - -// If MINIZ_NO_TIME is specified then the ZIP archive functions will not be able to get the current time, or -// get/set file times, and the C run-time funcs that get/set times won't be called. -// The current downside is the times written to your archives will be from 1979. -//#define MINIZ_NO_TIME - -// Define MINIZ_NO_ARCHIVE_APIS to disable all ZIP archive API's. -//#define MINIZ_NO_ARCHIVE_APIS - -// Define MINIZ_NO_ARCHIVE_APIS to disable all writing related ZIP archive API's. -//#define MINIZ_NO_ARCHIVE_WRITING_APIS - -// Define MINIZ_NO_ZLIB_APIS to remove all ZLIB-style compression/decompression API's. -//#define MINIZ_NO_ZLIB_APIS - -// Define MINIZ_NO_ZLIB_COMPATIBLE_NAME to disable zlib names, to prevent conflicts against stock zlib. -#define MINIZ_NO_ZLIB_COMPATIBLE_NAMES - -// Define MINIZ_NO_MALLOC to disable all calls to malloc, free, and realloc. -// Note if MINIZ_NO_MALLOC is defined then the user must always provide custom user alloc/free/realloc -// callbacks to the zlib and archive API's, and a few stand-alone helper API's which don't provide custom user -// functions (such as tdefl_compress_mem_to_heap() and tinfl_decompress_mem_to_heap()) won't work. -//#define MINIZ_NO_MALLOC - -#if !defined(MINIZ_NO_TIME) && !defined(MINIZ_NO_ARCHIVE_APIS) -#include -#endif - -#if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || defined(__i386) || defined(__i486__) || defined(__i486) || defined(i386) || defined(__ia64__) || defined(__x86_64__) -// MINIZ_X86_OR_X64_CPU is only used to help set the below macros. -#define MINIZ_X86_OR_X64_CPU 1 -#endif - -#if (__BYTE_ORDER__==__ORDER_LITTLE_ENDIAN__) || MINIZ_X86_OR_X64_CPU -// Set MINIZ_LITTLE_ENDIAN to 1 if the processor is little endian. -#define MINIZ_LITTLE_ENDIAN 1 -#endif - -#if MINIZ_X86_OR_X64_CPU -// Set MINIZ_USE_UNALIGNED_LOADS_AND_STORES to 1 on CPU's that permit efficient integer loads and stores from unaligned addresses. -#define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1 -#endif - -#if defined(_M_X64) || defined(_WIN64) || defined(__MINGW64__) || defined(_LP64) || defined(__LP64__) || defined(__ia64__) || defined(__x86_64__) -// Set MINIZ_HAS_64BIT_REGISTERS to 1 if operations on 64-bit integers are reasonably fast (and don't involve compiler generated calls to helper functions). -#define MINIZ_HAS_64BIT_REGISTERS 1 -#endif - -// ------------------- Types and macros - -typedef unsigned char mz_uint8; -typedef signed short mz_int16; -typedef unsigned short mz_uint16; -typedef unsigned int mz_uint32; -typedef unsigned int mz_uint; -typedef long long mz_int64; -typedef unsigned long long mz_uint64; -typedef int mz_bool; - -#define MZ_FALSE (0) -#define MZ_TRUE (1) - -// An attempt to work around MSVC's spammy "warning C4127: conditional expression is constant" message. -#ifdef _MSC_VER -#define MZ_MACRO_END while (0, 0) -#else -#define MZ_MACRO_END while (0) -#endif - -// ------------------- zlib-style API Definitions. - -// For more compatibility with zlib, miniz.c uses unsigned long for some parameters/struct members. Beware: mz_ulong can be either 32 or 64-bits! -typedef unsigned long mz_ulong; - -// mz_free() internally uses the MZ_FREE() macro (which by default calls free() unless you've modified the MZ_MALLOC macro) to release a block allocated from the heap. -void mz_free(void *p); - -#define MZ_ADLER32_INIT (1) -// mz_adler32() returns the initial adler-32 value to use when called with ptr==NULL. -mz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len); - -#define MZ_CRC32_INIT (0) -// mz_crc32() returns the initial CRC-32 value to use when called with ptr==NULL. -mz_ulong mz_crc32(mz_ulong crc, const unsigned char *ptr, size_t buf_len); - -// Compression strategies. -enum { MZ_DEFAULT_STRATEGY = 0, MZ_FILTERED = 1, MZ_HUFFMAN_ONLY = 2, MZ_RLE = 3, MZ_FIXED = 4 }; - -// Method -#define MZ_DEFLATED 8 - -#ifndef MINIZ_NO_ZLIB_APIS - -// Heap allocation callbacks. -// Note that mz_alloc_func parameter types purpsosely differ from zlib's: items/size is size_t, not unsigned long. -typedef void *(*mz_alloc_func)(void *opaque, size_t items, size_t size); -typedef void(*mz_free_func)(void *opaque, void *address); -typedef void *(*mz_realloc_func)(void *opaque, void *address, size_t items, size_t size); - -#define MZ_VERSION "9.1.15" -#define MZ_VERNUM 0x91F0 -#define MZ_VER_MAJOR 9 -#define MZ_VER_MINOR 1 -#define MZ_VER_REVISION 15 -#define MZ_VER_SUBREVISION 0 - -// Flush values. For typical usage you only need MZ_NO_FLUSH and MZ_FINISH. The other values are for advanced use (refer to the zlib docs). -enum -{ - MZ_NO_FLUSH = 0, - MZ_PARTIAL_FLUSH = 1, - MZ_SYNC_FLUSH = 2, - MZ_FULL_FLUSH = 3, - MZ_FINISH = 4, - MZ_BLOCK = 5 -}; - -// Return status codes. MZ_PARAM_ERROR is non-standard. -enum -{ - MZ_OK = 0, - MZ_STREAM_END = 1, - MZ_NEED_DICT = 2, - MZ_ERRNO = -1, - MZ_STREAM_ERROR = -2, - MZ_DATA_ERROR = -3, - MZ_MEM_ERROR = -4, - MZ_BUF_ERROR = -5, - MZ_VERSION_ERROR = -6, - MZ_PARAM_ERROR = -10000 -}; - -// Compression levels: 0-9 are the standard zlib-style levels, 10 is best possible compression (not zlib compatible, and may be very slow), MZ_DEFAULT_COMPRESSION=MZ_DEFAULT_LEVEL. -enum -{ - MZ_NO_COMPRESSION = 0, - MZ_BEST_SPEED = 1, - MZ_BEST_COMPRESSION = 9, - MZ_UBER_COMPRESSION = 10, - MZ_DEFAULT_LEVEL = 6, - MZ_DEFAULT_COMPRESSION = -1 -}; - -// Window bits -#define MZ_DEFAULT_WINDOW_BITS 15 - -struct mz_internal_state; - -// Compression/decompression stream struct. -typedef struct mz_stream_s -{ - const unsigned char *next_in; // pointer to next byte to read - unsigned int avail_in; // number of bytes available at next_in - mz_ulong total_in; // total number of bytes consumed so far - - unsigned char *next_out; // pointer to next byte to write - unsigned int avail_out; // number of bytes that can be written to next_out - mz_ulong total_out; // total number of bytes produced so far - - char *msg; // error msg (unused) - struct mz_internal_state *state; // internal state, allocated by zalloc/zfree - - mz_alloc_func zalloc; // optional heap allocation function (defaults to malloc) - mz_free_func zfree; // optional heap free function (defaults to free) - void *opaque; // heap alloc function user pointer - - int data_type; // data_type (unused) - mz_ulong adler; // adler32 of the source or uncompressed data - mz_ulong reserved; // not used -} mz_stream; - -typedef mz_stream *mz_streamp; - -// Returns the version string of miniz.c. -const char *mz_version(void); - -// mz_deflateInit() initializes a compressor with default options: -// Parameters: -// pStream must point to an initialized mz_stream struct. -// level must be between [MZ_NO_COMPRESSION, MZ_BEST_COMPRESSION]. -// level 1 enables a specially optimized compression function that's been optimized purely for performance, not ratio. -// (This special func. is currently only enabled when MINIZ_USE_UNALIGNED_LOADS_AND_STORES and MINIZ_LITTLE_ENDIAN are defined.) -// Return values: -// MZ_OK on success. -// MZ_STREAM_ERROR if the stream is bogus. -// MZ_PARAM_ERROR if the input parameters are bogus. -// MZ_MEM_ERROR on out of memory. -int mz_deflateInit(mz_streamp pStream, int level); - -// mz_deflateInit2() is like mz_deflate(), except with more control: -// Additional parameters: -// method must be MZ_DEFLATED -// window_bits must be MZ_DEFAULT_WINDOW_BITS (to wrap the deflate stream with zlib header/adler-32 footer) or -MZ_DEFAULT_WINDOW_BITS (raw deflate/no header or footer) -// mem_level must be between [1, 9] (it's checked but ignored by miniz.c) -int mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits, int mem_level, int strategy); - -// Quickly resets a compressor without having to reallocate anything. Same as calling mz_deflateEnd() followed by mz_deflateInit()/mz_deflateInit2(). -int mz_deflateReset(mz_streamp pStream); - -// mz_deflate() compresses the input to output, consuming as much of the input and producing as much output as possible. -// Parameters: -// pStream is the stream to read from and write to. You must initialize/update the next_in, avail_in, next_out, and avail_out members. -// flush may be MZ_NO_FLUSH, MZ_PARTIAL_FLUSH/MZ_SYNC_FLUSH, MZ_FULL_FLUSH, or MZ_FINISH. -// Return values: -// MZ_OK on success (when flushing, or if more input is needed but not available, and/or there's more output to be written but the output buffer is full). -// MZ_STREAM_END if all input has been consumed and all output bytes have been written. Don't call mz_deflate() on the stream anymore. -// MZ_STREAM_ERROR if the stream is bogus. -// MZ_PARAM_ERROR if one of the parameters is invalid. -// MZ_BUF_ERROR if no forward progress is possible because the input and/or output buffers are empty. (Fill up the input buffer or free up some output space and try again.) -int mz_deflate(mz_streamp pStream, int flush); - -// mz_deflateEnd() deinitializes a compressor: -// Return values: -// MZ_OK on success. -// MZ_STREAM_ERROR if the stream is bogus. -int mz_deflateEnd(mz_streamp pStream); - -// mz_deflateBound() returns a (very) conservative upper bound on the amount of data that could be generated by deflate(), assuming flush is set to only MZ_NO_FLUSH or MZ_FINISH. -mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len); - -// Single-call compression functions mz_compress() and mz_compress2(): -// Returns MZ_OK on success, or one of the error codes from mz_deflate() on failure. -int mz_compress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len); -int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len, int level); - -// mz_compressBound() returns a (very) conservative upper bound on the amount of data that could be generated by calling mz_compress(). -mz_ulong mz_compressBound(mz_ulong source_len); - -// Initializes a decompressor. -int mz_inflateInit(mz_streamp pStream); - -// mz_inflateInit2() is like mz_inflateInit() with an additional option that controls the window size and whether or not the stream has been wrapped with a zlib header/footer: -// window_bits must be MZ_DEFAULT_WINDOW_BITS (to parse zlib header/footer) or -MZ_DEFAULT_WINDOW_BITS (raw deflate). -int mz_inflateInit2(mz_streamp pStream, int window_bits); - -// Decompresses the input stream to the output, consuming only as much of the input as needed, and writing as much to the output as possible. -// Parameters: -// pStream is the stream to read from and write to. You must initialize/update the next_in, avail_in, next_out, and avail_out members. -// flush may be MZ_NO_FLUSH, MZ_SYNC_FLUSH, or MZ_FINISH. -// On the first call, if flush is MZ_FINISH it's assumed the input and output buffers are both sized large enough to decompress the entire stream in a single call (this is slightly faster). -// MZ_FINISH implies that there are no more source bytes available beside what's already in the input buffer, and that the output buffer is large enough to hold the rest of the decompressed data. -// Return values: -// MZ_OK on success. Either more input is needed but not available, and/or there's more output to be written but the output buffer is full. -// MZ_STREAM_END if all needed input has been consumed and all output bytes have been written. For zlib streams, the adler-32 of the decompressed data has also been verified. -// MZ_STREAM_ERROR if the stream is bogus. -// MZ_DATA_ERROR if the deflate stream is invalid. -// MZ_PARAM_ERROR if one of the parameters is invalid. -// MZ_BUF_ERROR if no forward progress is possible because the input buffer is empty but the inflater needs more input to continue, or if the output buffer is not large enough. Call mz_inflate() again -// with more input data, or with more room in the output buffer (except when using single call decompression, described above). -int mz_inflate(mz_streamp pStream, int flush); - -// Deinitializes a decompressor. -int mz_inflateEnd(mz_streamp pStream); - -// Single-call decompression. -// Returns MZ_OK on success, or one of the error codes from mz_inflate() on failure. -int mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len); - -// Returns a string description of the specified error code, or NULL if the error code is invalid. -const char *mz_error(int err); - -// Redefine zlib-compatible names to miniz equivalents, so miniz.c can be used as a drop-in replacement for the subset of zlib that miniz.c supports. -// Define MINIZ_NO_ZLIB_COMPATIBLE_NAMES to disable zlib-compatibility if you use zlib in the same project. -#ifndef MINIZ_NO_ZLIB_COMPATIBLE_NAMES -typedef unsigned char Byte; -typedef unsigned int uInt; -typedef mz_ulong uLong; -typedef Byte Bytef; -typedef uInt uIntf; -typedef char charf; -typedef int intf; -typedef void *voidpf; -typedef uLong uLongf; -typedef void *voidp; -typedef void *const voidpc; -#define Z_NULL 0 -#define Z_NO_FLUSH MZ_NO_FLUSH -#define Z_PARTIAL_FLUSH MZ_PARTIAL_FLUSH -#define Z_SYNC_FLUSH MZ_SYNC_FLUSH -#define Z_FULL_FLUSH MZ_FULL_FLUSH -#define Z_FINISH MZ_FINISH -#define Z_BLOCK MZ_BLOCK -#define Z_OK MZ_OK -#define Z_STREAM_END MZ_STREAM_END -#define Z_NEED_DICT MZ_NEED_DICT -#define Z_ERRNO MZ_ERRNO -#define Z_STREAM_ERROR MZ_STREAM_ERROR -#define Z_DATA_ERROR MZ_DATA_ERROR -#define Z_MEM_ERROR MZ_MEM_ERROR -#define Z_BUF_ERROR MZ_BUF_ERROR -#define Z_VERSION_ERROR MZ_VERSION_ERROR -#define Z_PARAM_ERROR MZ_PARAM_ERROR -#define Z_NO_COMPRESSION MZ_NO_COMPRESSION -#define Z_BEST_SPEED MZ_BEST_SPEED -#define Z_BEST_COMPRESSION MZ_BEST_COMPRESSION -#define Z_DEFAULT_COMPRESSION MZ_DEFAULT_COMPRESSION -#define Z_DEFAULT_STRATEGY MZ_DEFAULT_STRATEGY -#define Z_FILTERED MZ_FILTERED -#define Z_HUFFMAN_ONLY MZ_HUFFMAN_ONLY -#define Z_RLE MZ_RLE -#define Z_FIXED MZ_FIXED -#define Z_DEFLATED MZ_DEFLATED -#define Z_DEFAULT_WINDOW_BITS MZ_DEFAULT_WINDOW_BITS -#define alloc_func mz_alloc_func -#define free_func mz_free_func -#define internal_state mz_internal_state -#define z_stream mz_stream -#define deflateInit mz_deflateInit -#define deflateInit2 mz_deflateInit2 -#define deflateReset mz_deflateReset -#define deflate mz_deflate -#define deflateEnd mz_deflateEnd -#define deflateBound mz_deflateBound -#define compress mz_compress -#define compress2 mz_compress2 -#define compressBound mz_compressBound -#define inflateInit mz_inflateInit -#define inflateInit2 mz_inflateInit2 -#define inflate mz_inflate -#define inflateEnd mz_inflateEnd -#define uncompress mz_uncompress -#define crc32 mz_crc32 -#define adler32 mz_adler32 -#define MAX_WBITS 15 -#define MAX_MEM_LEVEL 9 -#define zError mz_error -#define ZLIB_VERSION MZ_VERSION -#define ZLIB_VERNUM MZ_VERNUM -#define ZLIB_VER_MAJOR MZ_VER_MAJOR -#define ZLIB_VER_MINOR MZ_VER_MINOR -#define ZLIB_VER_REVISION MZ_VER_REVISION -#define ZLIB_VER_SUBREVISION MZ_VER_SUBREVISION -#define zlibVersion mz_version -#define zlib_version mz_version() -#endif // #ifndef MINIZ_NO_ZLIB_COMPATIBLE_NAMES - -#endif // MINIZ_NO_ZLIB_APIS - - - - // ------------------- ZIP archive reading/writing - -#ifndef MINIZ_NO_ARCHIVE_APIS - -enum -{ - MZ_ZIP_MAX_IO_BUF_SIZE = 64 * 1024, - MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE = 260, - MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE = 256 -}; - -typedef struct _mz_zip_archive_file_stat -{ - mz_uint32 m_file_index; - mz_uint32 m_central_dir_ofs; - mz_uint16 m_version_made_by; - mz_uint16 m_version_needed; - mz_uint16 m_bit_flag; - mz_uint16 m_method; -#ifndef MINIZ_NO_TIME - time_t m_time; -#endif - mz_uint32 m_crc32; - mz_uint64 m_comp_size; - mz_uint64 m_uncomp_size; - mz_uint16 m_internal_attr; - mz_uint32 m_external_attr; - mz_uint64 m_local_header_ofs; - mz_uint32 m_comment_size; - char m_filename[MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE]; - char m_comment[MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE]; -} mz_zip_archive_file_stat; - -typedef size_t(*mz_file_read_func)(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n); -typedef size_t(*mz_file_write_func)(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n); - -struct mz_zip_internal_state_tag; -typedef struct mz_zip_internal_state_tag mz_zip_internal_state; - -typedef enum _mz_zip_mode -{ - MZ_ZIP_MODE_INVALID = 0, - MZ_ZIP_MODE_READING = 1, - MZ_ZIP_MODE_WRITING = 2, - MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED = 3 -} mz_zip_mode; - -typedef struct _mz_zip_archive -{ - mz_uint64 m_archive_size; - mz_uint64 m_central_directory_file_ofs; - mz_uint m_total_files; - mz_zip_mode m_zip_mode; - - mz_uint m_file_offset_alignment; - - mz_alloc_func m_pAlloc; - mz_free_func m_pFree; - mz_realloc_func m_pRealloc; - void *m_pAlloc_opaque; - - mz_file_read_func m_pRead; - mz_file_write_func m_pWrite; - void *m_pIO_opaque; - - mz_zip_internal_state *m_pState; - -} mz_zip_archive; - -typedef enum _mz_zip_flags -{ - MZ_ZIP_FLAG_CASE_SENSITIVE = 0x0100, - MZ_ZIP_FLAG_IGNORE_PATH = 0x0200, - MZ_ZIP_FLAG_COMPRESSED_DATA = 0x0400, - MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY = 0x0800 -} mz_zip_flags; - -// ZIP archive reading - -// Inits a ZIP archive reader. -// These functions read and validate the archive's central directory. -mz_bool mz_zip_reader_init(mz_zip_archive *pZip, mz_uint64 size, mz_uint32 flags); -mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem, size_t size, mz_uint32 flags); - -#ifndef MINIZ_NO_STDIO -mz_bool mz_zip_reader_init_file(mz_zip_archive *pZip, const wchar_t *pFilename, mz_uint32 flags); -#endif - -// Returns the total number of files in the archive. -mz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip); - -// Returns detailed information about an archive file entry. -mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index, mz_zip_archive_file_stat *pStat); - -// Determines if an archive file entry is a directory entry. -mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip, mz_uint file_index); -mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip, mz_uint file_index); - -// Retrieves the filename of an archive file entry. -// Returns the number of bytes written to pFilename, or if filename_buf_size is 0 this function returns the number of bytes needed to fully store the filename. -mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index, char *pFilename, mz_uint filename_buf_size); - -// Attempts to locates a file in the archive's central directory. -// Valid flags: MZ_ZIP_FLAG_CASE_SENSITIVE, MZ_ZIP_FLAG_IGNORE_PATH -// Returns -1 if the file cannot be found. -int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags); - -// Extracts a archive file to a memory buffer using no memory allocation. -mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size); -mz_bool mz_zip_reader_extract_file_to_mem_no_alloc(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size); - -// Extracts a archive file to a memory buffer. -mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags); -mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags); - -// Extracts a archive file to a dynamically allocated heap buffer. -void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index, size_t *pSize, mz_uint flags); -void *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip, const char *pFilename, size_t *pSize, mz_uint flags); - -// Extracts a archive file using a callback function to output the file's data. -mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip, mz_uint file_index, mz_file_write_func pCallback, void *pOpaque, mz_uint flags); -mz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive *pZip, const char *pFilename, mz_file_write_func pCallback, void *pOpaque, mz_uint flags); - -#ifndef MINIZ_NO_STDIO -// Extracts a archive file to a disk file and sets its last accessed and modified times. -// This function only extracts files, not archive directory records. -mz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip, mz_uint file_index, const wchar_t *pDst_filename, mz_uint flags); -mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip, const char *pArchive_filename, const wchar_t *pDst_filename, mz_uint flags); -#endif - -// Ends archive reading, freeing all allocations, and closing the input archive file if mz_zip_reader_init_file() was used. -mz_bool mz_zip_reader_end(mz_zip_archive *pZip); - -// ZIP archive writing - -#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS - - // Inits a ZIP archive writer. -mz_bool mz_zip_writer_init(mz_zip_archive *pZip, mz_uint64 existing_size); -mz_bool mz_zip_writer_init_heap(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size); - -#ifndef MINIZ_NO_STDIO -mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const wchar_t *pFilename, mz_uint64 size_to_reserve_at_beginning); -#endif - -// Converts a ZIP archive reader object into a writer object, to allow efficient in-place file appends to occur on an existing archive. -// For archives opened using mz_zip_reader_init_file, pFilename must be the archive's filename so it can be reopened for writing. If the file can't be reopened, mz_zip_reader_end() will be called. -// For archives opened using mz_zip_reader_init_mem, the memory block must be growable using the realloc callback (which defaults to realloc unless you've overridden it). -// Finally, for archives opened using mz_zip_reader_init, the mz_zip_archive's user provided m_pWrite function cannot be NULL. -// Note: In-place archive modification is not recommended unless you know what you're doing, because if execution stops or something goes wrong before -// the archive is finalized the file's central directory will be hosed. -mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip, const wchar_t *pFilename); - -// Adds the contents of a memory buffer to an archive. These functions record the current local time into the archive. -// To add a directory entry, call this method with an archive name ending in a forwardslash with empty buffer. -// level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION. -mz_bool mz_zip_writer_add_mem(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, mz_uint level_and_flags); -mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, mz_uint64 uncomp_size, mz_uint32 uncomp_crc32); - -#ifndef MINIZ_NO_STDIO -// Adds the contents of a disk file to an archive. This function also records the disk file's modified time into the archive. -// level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION. -mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, const wchar_t *pSrc_filename, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags); -#endif - -// Adds a file to an archive by fully cloning the data from another archive. -// This function fully clones the source file's compressed data (no recompression), along with its full filename, extra data, and comment fields. -mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip, mz_zip_archive *pSource_zip, mz_uint file_index); - -// Finalizes the archive by writing the central directory records followed by the end of central directory record. -// After an archive is finalized, the only valid call on the mz_zip_archive struct is mz_zip_writer_end(). -// An archive must be manually finalized by calling this function for it to be valid. -mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip); -mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **pBuf, size_t *pSize); - -// Ends archive writing, freeing all allocations, and closing the output file if mz_zip_writer_init_file() was used. -// Note for the archive to be valid, it must have been finalized before ending. -mz_bool mz_zip_writer_end(mz_zip_archive *pZip); - -// Misc. high-level helper functions: - -// mz_zip_add_mem_to_archive_file_in_place() efficiently (but not atomically) appends a memory blob to a ZIP archive. -// level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION. -mz_bool mz_zip_add_mem_to_archive_file_in_place(const wchar_t *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags); - -// Reads a single file from an archive into a heap block. -// Returns NULL on failure. -void *mz_zip_extract_archive_file_to_heap(const wchar_t *pZip_filename, const char *pArchive_name, size_t *pSize, mz_uint zip_flags); - -#endif // #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS - -#endif // #ifndef MINIZ_NO_ARCHIVE_APIS - -// ------------------- Low-level Decompression API Definitions - -// Decompression flags used by tinfl_decompress(). -// TINFL_FLAG_PARSE_ZLIB_HEADER: If set, the input has a valid zlib header and ends with an adler32 checksum (it's a valid zlib stream). Otherwise, the input is a raw deflate stream. -// TINFL_FLAG_HAS_MORE_INPUT: If set, there are more input bytes available beyond the end of the supplied input buffer. If clear, the input buffer contains all remaining input. -// TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF: If set, the output buffer is large enough to hold the entire decompressed stream. If clear, the output buffer is at least the size of the dictionary (typically 32KB). -// TINFL_FLAG_COMPUTE_ADLER32: Force adler-32 checksum computation of the decompressed bytes. -enum -{ - TINFL_FLAG_PARSE_ZLIB_HEADER = 1, - TINFL_FLAG_HAS_MORE_INPUT = 2, - TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF = 4, - TINFL_FLAG_COMPUTE_ADLER32 = 8 -}; - -// High level decompression functions: -// tinfl_decompress_mem_to_heap() decompresses a block in memory to a heap block allocated via malloc(). -// On entry: -// pSrc_buf, src_buf_len: Pointer and size of the Deflate or zlib source data to decompress. -// On return: -// Function returns a pointer to the decompressed data, or NULL on failure. -// *pOut_len will be set to the decompressed data's size, which could be larger than src_buf_len on uncompressible data. -// The caller must call mz_free() on the returned block when it's no longer needed. -void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags); - -// tinfl_decompress_mem_to_mem() decompresses a block in memory to another block in memory. -// Returns TINFL_DECOMPRESS_MEM_TO_MEM_FAILED on failure, or the number of bytes written on success. -#define TINFL_DECOMPRESS_MEM_TO_MEM_FAILED ((size_t)(-1)) -size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags); - -// tinfl_decompress_mem_to_callback() decompresses a block in memory to an internal 32KB buffer, and a user provided callback function will be called to flush the buffer. -// Returns 1 on success or 0 on failure. -typedef int(*tinfl_put_buf_func_ptr)(const void* pBuf, int len, void *pUser); -int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags); - -struct tinfl_decompressor_tag; typedef struct tinfl_decompressor_tag tinfl_decompressor; - -// Max size of LZ dictionary. -#define TINFL_LZ_DICT_SIZE 32768 - - // Return status. -typedef enum -{ - TINFL_STATUS_BAD_PARAM = -3, - TINFL_STATUS_ADLER32_MISMATCH = -2, - TINFL_STATUS_FAILED = -1, - TINFL_STATUS_DONE = 0, - TINFL_STATUS_NEEDS_MORE_INPUT = 1, - TINFL_STATUS_HAS_MORE_OUTPUT = 2 -} tinfl_status; - -// Initializes the decompressor to its initial state. -#define tinfl_init(r) do { (r)->m_state = 0; } MZ_MACRO_END -#define tinfl_get_adler32(r) (r)->m_check_adler32 - - // Main low-level decompressor coroutine function. This is the only function actually needed for decompression. All the other functions are just high-level helpers for improved usability. - // This is a universal API, i.e. it can be used as a building block to build any desired higher level decompression API. In the limit case, it can be called once per every byte input or output. -tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_next, size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, const mz_uint32 decomp_flags); - -// Internal/private bits follow. -enum -{ - TINFL_MAX_HUFF_TABLES = 3, TINFL_MAX_HUFF_SYMBOLS_0 = 288, TINFL_MAX_HUFF_SYMBOLS_1 = 32, TINFL_MAX_HUFF_SYMBOLS_2 = 19, - TINFL_FAST_LOOKUP_BITS = 10, TINFL_FAST_LOOKUP_SIZE = 1 << TINFL_FAST_LOOKUP_BITS -}; - -typedef struct -{ - mz_uint8 m_code_size[TINFL_MAX_HUFF_SYMBOLS_0]; - mz_int16 m_look_up[TINFL_FAST_LOOKUP_SIZE], m_tree[TINFL_MAX_HUFF_SYMBOLS_0 * 2]; -} tinfl_huff_table; - -#if MINIZ_HAS_64BIT_REGISTERS -#define TINFL_USE_64BIT_BITBUF 1 -#endif - -#if TINFL_USE_64BIT_BITBUF -typedef mz_uint64 tinfl_bit_buf_t; -#define TINFL_BITBUF_SIZE (64) -#else -typedef mz_uint32 tinfl_bit_buf_t; -#define TINFL_BITBUF_SIZE (32) -#endif - -struct tinfl_decompressor_tag -{ - mz_uint32 m_state, m_num_bits, m_zhdr0, m_zhdr1, m_z_adler32, m_final, m_type, m_check_adler32, m_dist, m_counter, m_num_extra, m_table_sizes[TINFL_MAX_HUFF_TABLES]; - tinfl_bit_buf_t m_bit_buf; - size_t m_dist_from_out_buf_start; - tinfl_huff_table m_tables[TINFL_MAX_HUFF_TABLES]; - mz_uint8 m_raw_header[4], m_len_codes[TINFL_MAX_HUFF_SYMBOLS_0 + TINFL_MAX_HUFF_SYMBOLS_1 + 137]; -}; - -// ------------------- Low-level Compression API Definitions - -// Set TDEFL_LESS_MEMORY to 1 to use less memory (compression will be slightly slower, and raw/dynamic blocks will be output more frequently). -#define TDEFL_LESS_MEMORY 0 - - // tdefl_init() compression flags logically OR'd together (low 12 bits contain the max. number of probes per dictionary search): - // TDEFL_DEFAULT_MAX_PROBES: The compressor defaults to 128 dictionary probes per dictionary search. 0=Huffman only, 1=Huffman+LZ (fastest/crap compression), 4095=Huffman+LZ (slowest/best compression). -enum -{ - TDEFL_HUFFMAN_ONLY = 0, TDEFL_DEFAULT_MAX_PROBES = 128, TDEFL_MAX_PROBES_MASK = 0xFFF -}; - -// TDEFL_WRITE_ZLIB_HEADER: If set, the compressor outputs a zlib header before the deflate data, and the Adler-32 of the source data at the end. Otherwise, you'll get raw deflate data. -// TDEFL_COMPUTE_ADLER32: Always compute the adler-32 of the input data (even when not writing zlib headers). -// TDEFL_GREEDY_PARSING_FLAG: Set to use faster greedy parsing, instead of more efficient lazy parsing. -// TDEFL_NONDETERMINISTIC_PARSING_FLAG: Enable to decrease the compressor's initialization time to the minimum, but the output may vary from run to run given the same input (depending on the contents of memory). -// TDEFL_RLE_MATCHES: Only look for RLE matches (matches with a distance of 1) -// TDEFL_FILTER_MATCHES: Discards matches <= 5 chars if enabled. -// TDEFL_FORCE_ALL_STATIC_BLOCKS: Disable usage of optimized Huffman tables. -// TDEFL_FORCE_ALL_RAW_BLOCKS: Only use raw (uncompressed) deflate blocks. -// The low 12 bits are reserved to control the max # of hash probes per dictionary lookup (see TDEFL_MAX_PROBES_MASK). -enum -{ - TDEFL_WRITE_ZLIB_HEADER = 0x01000, - TDEFL_COMPUTE_ADLER32 = 0x02000, - TDEFL_GREEDY_PARSING_FLAG = 0x04000, - TDEFL_NONDETERMINISTIC_PARSING_FLAG = 0x08000, - TDEFL_RLE_MATCHES = 0x10000, - TDEFL_FILTER_MATCHES = 0x20000, - TDEFL_FORCE_ALL_STATIC_BLOCKS = 0x40000, - TDEFL_FORCE_ALL_RAW_BLOCKS = 0x80000 -}; - -// High level compression functions: -// tdefl_compress_mem_to_heap() compresses a block in memory to a heap block allocated via malloc(). -// On entry: -// pSrc_buf, src_buf_len: Pointer and size of source block to compress. -// flags: The max match finder probes (default is 128) logically OR'd against the above flags. Higher probes are slower but improve compression. -// On return: -// Function returns a pointer to the compressed data, or NULL on failure. -// *pOut_len will be set to the compressed data's size, which could be larger than src_buf_len on uncompressible data. -// The caller must free() the returned block when it's no longer needed. -void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags); - -// tdefl_compress_mem_to_mem() compresses a block in memory to another block in memory. -// Returns 0 on failure. -size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags); - -// Compresses an image to a compressed PNG file in memory. -// On entry: -// pImage, w, h, and num_chans describe the image to compress. num_chans may be 1, 2, 3, or 4. -// The image pitch in bytes per scanline will be w*num_chans. The leftmost pixel on the top scanline is stored first in memory. -// level may range from [0,10], use MZ_NO_COMPRESSION, MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc. or a decent default is MZ_DEFAULT_LEVEL -// If flip is true, the image will be flipped on the Y axis (useful for OpenGL apps). -// On return: -// Function returns a pointer to the compressed data, or NULL on failure. -// *pLen_out will be set to the size of the PNG image file. -// The caller must mz_free() the returned heap block (which will typically be larger than *pLen_out) when it's no longer needed. -void *tdefl_write_image_to_png_file_in_memory_ex(const void *pImage, int w, int h, int num_chans, size_t *pLen_out, mz_uint level, mz_bool flip); -void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, int num_chans, size_t *pLen_out); - -// Output stream interface. The compressor uses this interface to write compressed data. It'll typically be called TDEFL_OUT_BUF_SIZE at a time. -typedef mz_bool(*tdefl_put_buf_func_ptr)(const void* pBuf, int len, void *pUser); - -// tdefl_compress_mem_to_output() compresses a block to an output stream. The above helpers use this function internally. -mz_bool tdefl_compress_mem_to_output(const void *pBuf, size_t buf_len, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags); - -enum { TDEFL_MAX_HUFF_TABLES = 3, TDEFL_MAX_HUFF_SYMBOLS_0 = 288, TDEFL_MAX_HUFF_SYMBOLS_1 = 32, TDEFL_MAX_HUFF_SYMBOLS_2 = 19, TDEFL_LZ_DICT_SIZE = 32768, TDEFL_LZ_DICT_SIZE_MASK = TDEFL_LZ_DICT_SIZE - 1, TDEFL_MIN_MATCH_LEN = 3, TDEFL_MAX_MATCH_LEN = 258 }; - -// TDEFL_OUT_BUF_SIZE MUST be large enough to hold a single entire compressed output block (using static/fixed Huffman codes). -#if TDEFL_LESS_MEMORY -enum { TDEFL_LZ_CODE_BUF_SIZE = 24 * 1024, TDEFL_OUT_BUF_SIZE = (TDEFL_LZ_CODE_BUF_SIZE * 13) / 10, TDEFL_MAX_HUFF_SYMBOLS = 288, TDEFL_LZ_HASH_BITS = 12, TDEFL_LEVEL1_HASH_SIZE_MASK = 4095, TDEFL_LZ_HASH_SHIFT = (TDEFL_LZ_HASH_BITS + 2) / 3, TDEFL_LZ_HASH_SIZE = 1 << TDEFL_LZ_HASH_BITS }; -#else -enum { TDEFL_LZ_CODE_BUF_SIZE = 64 * 1024, TDEFL_OUT_BUF_SIZE = (TDEFL_LZ_CODE_BUF_SIZE * 13) / 10, TDEFL_MAX_HUFF_SYMBOLS = 288, TDEFL_LZ_HASH_BITS = 15, TDEFL_LEVEL1_HASH_SIZE_MASK = 4095, TDEFL_LZ_HASH_SHIFT = (TDEFL_LZ_HASH_BITS + 2) / 3, TDEFL_LZ_HASH_SIZE = 1 << TDEFL_LZ_HASH_BITS }; -#endif - -// The low-level tdefl functions below may be used directly if the above helper functions aren't flexible enough. The low-level functions don't make any heap allocations, unlike the above helper functions. -typedef enum -{ - TDEFL_STATUS_BAD_PARAM = -2, - TDEFL_STATUS_PUT_BUF_FAILED = -1, - TDEFL_STATUS_OKAY = 0, - TDEFL_STATUS_DONE = 1, -} tdefl_status; - -// Must map to MZ_NO_FLUSH, MZ_SYNC_FLUSH, etc. enums -typedef enum -{ - TDEFL_NO_FLUSH = 0, - TDEFL_SYNC_FLUSH = 2, - TDEFL_FULL_FLUSH = 3, - TDEFL_FINISH = 4 -} tdefl_flush; - -// tdefl's compression state structure. -typedef struct -{ - tdefl_put_buf_func_ptr m_pPut_buf_func; - void *m_pPut_buf_user; - mz_uint m_flags, m_max_probes[2]; - int m_greedy_parsing; - mz_uint m_adler32, m_lookahead_pos, m_lookahead_size, m_dict_size; - mz_uint8 *m_pLZ_code_buf, *m_pLZ_flags, *m_pOutput_buf, *m_pOutput_buf_end; - mz_uint m_num_flags_left, m_total_lz_bytes, m_lz_code_buf_dict_pos, m_bits_in, m_bit_buffer; - mz_uint m_saved_match_dist, m_saved_match_len, m_saved_lit, m_output_flush_ofs, m_output_flush_remaining, m_finished, m_block_index, m_wants_to_finish; - tdefl_status m_prev_return_status; - const void *m_pIn_buf; - void *m_pOut_buf; - size_t *m_pIn_buf_size, *m_pOut_buf_size; - tdefl_flush m_flush; - const mz_uint8 *m_pSrc; - size_t m_src_buf_left, m_out_buf_ofs; - mz_uint8 m_dict[TDEFL_LZ_DICT_SIZE + TDEFL_MAX_MATCH_LEN - 1]; - mz_uint16 m_huff_count[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS]; - mz_uint16 m_huff_codes[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS]; - mz_uint8 m_huff_code_sizes[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS]; - mz_uint8 m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE]; - mz_uint16 m_next[TDEFL_LZ_DICT_SIZE]; - mz_uint16 m_hash[TDEFL_LZ_HASH_SIZE]; - mz_uint8 m_output_buf[TDEFL_OUT_BUF_SIZE]; -} tdefl_compressor; - -// Initializes the compressor. -// There is no corresponding deinit() function because the tdefl API's do not dynamically allocate memory. -// pBut_buf_func: If NULL, output data will be supplied to the specified callback. In this case, the user should call the tdefl_compress_buffer() API for compression. -// If pBut_buf_func is NULL the user should always call the tdefl_compress() API. -// flags: See the above enums (TDEFL_HUFFMAN_ONLY, TDEFL_WRITE_ZLIB_HEADER, etc.) -tdefl_status tdefl_init(tdefl_compressor *d, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags); - -// Compresses a block of data, consuming as much of the specified input buffer as possible, and writing as much compressed data to the specified output buffer as possible. -tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf, size_t *pIn_buf_size, void *pOut_buf, size_t *pOut_buf_size, tdefl_flush flush); - -// tdefl_compress_buffer() is only usable when the tdefl_init() is called with a non-NULL tdefl_put_buf_func_ptr. -// tdefl_compress_buffer() always consumes the entire input buffer. -tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf, size_t in_buf_size, tdefl_flush flush); - -tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d); -mz_uint32 tdefl_get_adler32(tdefl_compressor *d); - -// Can't use tdefl_create_comp_flags_from_zip_params if MINIZ_NO_ZLIB_APIS isn't defined, because it uses some of its macros. -#ifndef MINIZ_NO_ZLIB_APIS - // Create tdefl_compress() flags given zlib-style compression parameters. - // level may range from [0,10] (where 10 is absolute max compression, but may be much slower on some files) - // window_bits may be -15 (raw deflate) or 15 (zlib) - // strategy may be either MZ_DEFAULT_STRATEGY, MZ_FILTERED, MZ_HUFFMAN_ONLY, MZ_RLE, or MZ_FIXED -mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, int strategy); -#endif // #ifndef MINIZ_NO_ZLIB_APIS - -#endif // MINIZ_HEADER_INCLUDED \ No newline at end of file diff --git a/plugins/ExtraPlugins/plugin.c b/plugins/ExtraPlugins/plugin.c deleted file mode 100644 index d1298c84297f..000000000000 --- a/plugins/ExtraPlugins/plugin.c +++ /dev/null @@ -1,371 +0,0 @@ -#include "main.h" - -ULONG PhDisabledPluginsCount( - VOID - ) -{ - PPH_STRING disabled; - PH_STRINGREF remainingPart; - PH_STRINGREF part; - ULONG count = 0; - - disabled = PhGetStringSetting(L"DisabledPlugins"); - remainingPart = disabled->sr; - - while (remainingPart.Length) - { - PhSplitStringRefAtChar(&remainingPart, '|', &part, &remainingPart); - - if (part.Length) - { - count++; - } - } - - PhDereferenceObject(disabled); - - return count; -} - -// Copied from Process Hacker, plugin.c - -PWSTR PhGetPluginBaseName( - _In_ PPHAPP_PLUGIN Plugin - ) -{ - if (Plugin->FileName) - { - PH_STRINGREF pathNamePart; - PH_STRINGREF baseNamePart; - - if (PhSplitStringRefAtLastChar(&Plugin->FileName->sr, '\\', &pathNamePart, &baseNamePart)) - return baseNamePart.Buffer; - else - return Plugin->FileName->Buffer; - } - else - { - // Fake disabled plugin. - return Plugin->Name.Buffer; - } -} - -BOOLEAN PhIsPluginLoadedByBaseName( - _In_ PPH_STRINGREF BaseName - ) -{ - PPH_AVL_LINKS root; - PPH_AVL_LINKS links; - - root = PluginInstance->Links.Parent; - - while (root) - { - if (!root->Parent) - break; - - root = root->Parent; - } - - for ( - links = PhMinimumElementAvlTree((PPH_AVL_TREE)root); - links; - links = PhSuccessorElementAvlTree(links) - ) - { - PPHAPP_PLUGIN plugin = CONTAINING_RECORD(links, PHAPP_PLUGIN, Links); - PH_STRINGREF pluginBaseName; - - PhInitializeStringRefLongHint(&pluginBaseName, PhGetPluginBaseName(plugin)); - - if (PhEqualStringRef(&pluginBaseName, BaseName, TRUE)) - return TRUE; - } - - return FALSE; -} - -BOOLEAN PhpLocateDisabledPlugin( - _In_ PPH_STRING List, - _In_ PPH_STRINGREF BaseName, - _Out_opt_ PULONG FoundIndex - ) -{ - PH_STRINGREF namePart; - PH_STRINGREF remainingPart; - - remainingPart = List->sr; - - while (remainingPart.Length != 0) - { - PhSplitStringRefAtChar(&remainingPart, '|', &namePart, &remainingPart); - - if (PhEqualStringRef(&namePart, BaseName, TRUE)) - { - if (FoundIndex) - *FoundIndex = (ULONG)(namePart.Buffer - List->Buffer); - - return TRUE; - } - } - - return FALSE; -} - -BOOLEAN PhIsPluginDisabled( - _In_ PPH_STRINGREF BaseName - ) -{ - BOOLEAN found; - PPH_STRING disabled; - - disabled = PhGetStringSetting(L"DisabledPlugins"); - found = PhpLocateDisabledPlugin(disabled, BaseName, NULL); - PhDereferenceObject(disabled); - - return found; -} - -VOID PhSetPluginDisabled( - _In_ PPH_STRINGREF BaseName, - _In_ BOOLEAN Disable - ) -{ - BOOLEAN found; - PPH_STRING disabled; - ULONG foundIndex; - PPH_STRING newDisabled; - - disabled = PhGetStringSetting(L"DisabledPlugins"); - - found = PhpLocateDisabledPlugin(disabled, BaseName, &foundIndex); - - if (Disable && !found) - { - // We need to add the plugin to the disabled list. - - if (disabled->Length != 0) - { - // We have other disabled plugins. Append a pipe character followed by the plugin name. - newDisabled = PhCreateStringEx(NULL, disabled->Length + sizeof(WCHAR) + BaseName->Length); - memcpy(newDisabled->Buffer, disabled->Buffer, disabled->Length); - newDisabled->Buffer[disabled->Length / 2] = '|'; - memcpy(&newDisabled->Buffer[disabled->Length / 2 + 1], BaseName->Buffer, BaseName->Length); - PhSetStringSetting2(L"DisabledPlugins", &newDisabled->sr); - PhDereferenceObject(newDisabled); - } - else - { - // This is the first disabled plugin. - PhSetStringSetting2(L"DisabledPlugins", BaseName); - } - } - else if (!Disable && found) - { - ULONG removeCount; - - // We need to remove the plugin from the disabled list. - - removeCount = (ULONG)BaseName->Length / 2; - - if (foundIndex + (ULONG)BaseName->Length / 2 < (ULONG)disabled->Length / 2) - { - // Remove the following pipe character as well. - removeCount++; - } - else if (foundIndex != 0) - { - // Remove the preceding pipe character as well. - foundIndex--; - removeCount++; - } - - newDisabled = PhCreateStringEx(NULL, disabled->Length - removeCount * sizeof(WCHAR)); - memcpy(newDisabled->Buffer, disabled->Buffer, foundIndex * sizeof(WCHAR)); - memcpy(&newDisabled->Buffer[foundIndex], &disabled->Buffer[foundIndex + removeCount], - disabled->Length - removeCount * sizeof(WCHAR) - foundIndex * sizeof(WCHAR)); - PhSetStringSetting2(L"DisabledPlugins", &newDisabled->sr); - PhDereferenceObject(newDisabled); - } - - PhDereferenceObject(disabled); -} - -PPHAPP_PLUGIN PhCreateDisabledPlugin( - _In_ PPH_STRINGREF BaseName - ) -{ - PPHAPP_PLUGIN plugin; - - plugin = PhAllocate(sizeof(PHAPP_PLUGIN)); - memset(plugin, 0, sizeof(PHAPP_PLUGIN)); - - plugin->Name.Length = BaseName->Length; - plugin->Name.Buffer = PhAllocate(BaseName->Length + sizeof(WCHAR)); - memcpy(plugin->Name.Buffer, BaseName->Buffer, BaseName->Length); - plugin->Name.Buffer[BaseName->Length / 2] = 0; - - return plugin; -} - -PPH_HASHTABLE PluginHashtable = NULL; -PPH_LIST PluginList = NULL; -PH_QUEUED_LOCK PluginListLock = PH_QUEUED_LOCK_INIT; - -PPH_STRING PluginGetVersionInfo( - _In_ PPH_STRING FileName - ) -{ - ULONG versionSize; - PVOID versionInfo; - PUSHORT languageInfo; - UINT language; - UINT bufferSize = 0; - PWSTR buffer; - PPH_STRING internalName = NULL; - PPH_STRING version = NULL; - - versionSize = GetFileVersionInfoSize(PhGetStringOrEmpty(FileName), NULL); - versionInfo = PhAllocate(versionSize); - memset(versionInfo, 0, versionSize); - - if (GetFileVersionInfo(PhGetStringOrEmpty(FileName), 0, versionSize, versionInfo)) - { - if (VerQueryValue(versionInfo, L"\\", &buffer, &bufferSize)) - { - VS_FIXEDFILEINFO* info = (VS_FIXEDFILEINFO*)buffer; - - if (info->dwSignature == 0xfeef04bd) - { - PH_FORMAT fileVersionFormat[7]; - - PhInitFormatU(&fileVersionFormat[0], info->dwFileVersionMS >> 16); - PhInitFormatC(&fileVersionFormat[1], '.'); - PhInitFormatU(&fileVersionFormat[2], info->dwFileVersionMS & 0xffff); - PhInitFormatC(&fileVersionFormat[3], '.'); - PhInitFormatU(&fileVersionFormat[4], info->dwFileVersionLS >> 16); - PhInitFormatC(&fileVersionFormat[5], '.'); - PhInitFormatU(&fileVersionFormat[6], info->dwFileVersionLS & 0xffff); - - version = PhFormat(fileVersionFormat, 7, 30); - } - } - - if (VerQueryValue(versionInfo, L"\\VarFileInfo\\Translation", &languageInfo, &language)) - { - PPH_STRING internalNameString = PhFormatString( - L"\\StringFileInfo\\%04x%04x\\InternalName", - languageInfo[0], - languageInfo[1] - ); - - if (VerQueryValue(versionInfo, PhGetStringOrEmpty(internalNameString), &buffer, &bufferSize)) - { - internalName = PhCreateStringEx(buffer, bufferSize * sizeof(WCHAR)); - } - - PhDereferenceObject(internalNameString); - } - } - - PhFree(versionInfo); - - return version; -} - - -VOID EnumerateLoadedPlugins( - _In_ PWCT_CONTEXT Context - ) -{ - PPH_AVL_LINKS root; - PPH_AVL_LINKS links; - - root = PluginInstance->Links.Parent; - - while (root) - { - if (!root->Parent) - break; - - root = root->Parent; - } - - for ( - links = PhMinimumElementAvlTree((PPH_AVL_TREE)root); - links; - links = PhSuccessorElementAvlTree(links) - ) - { - HANDLE handle; - IO_STATUS_BLOCK isb; - FILE_BASIC_INFORMATION basic; - PPHAPP_PLUGIN pluginInstance; - PH_STRINGREF pluginBaseName; - PPH_STRING pluginVersion; - SYSTEMTIME utcTime, localTime; - PPLUGIN_NODE entry; - - pluginInstance = CONTAINING_RECORD(links, PHAPP_PLUGIN, Links); - - PhInitializeStringRefLongHint(&pluginBaseName, PhGetPluginBaseName(pluginInstance)); - - if (PhIsPluginDisabled(&pluginBaseName)) - { - continue; - } - - if (!RtlDoesFileExists_U(PhGetString(pluginInstance->FileName))) - { - continue; - } - - entry = PhCreateAlloc(sizeof(PLUGIN_NODE)); - memset(entry, 0, sizeof(PLUGIN_NODE)); - memset(&basic, 0, sizeof(FILE_BASIC_INFORMATION)); - - if (NT_SUCCESS(PhCreateFileWin32( - &handle, - PhGetString(pluginInstance->FileName), - FILE_GENERIC_READ, - FILE_ATTRIBUTE_NORMAL, - FILE_SHARE_READ, - FILE_OPEN, - FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT - ))) - { - NtQueryInformationFile( - handle, - &isb, - &basic, - sizeof(FILE_BASIC_INFORMATION), - FileBasicInformation - ); - - NtClose(handle); - } - - pluginVersion = PluginGetVersionInfo(pluginInstance->FileName); - - entry->State = PLUGIN_STATE_LOCAL; - entry->PluginInstance = pluginInstance; - entry->InternalName = PhCreateString2(&pluginInstance->Name); - entry->Version = PhSubstring(pluginVersion, 0, pluginVersion->Length / sizeof(WCHAR) - 4); - entry->Name = PhCreateString(pluginInstance->Information.DisplayName); - entry->Author = PhCreateString(pluginInstance->Information.Author); - entry->Description = PhCreateString(pluginInstance->Information.Description); - entry->PluginOptions = pluginInstance->Information.HasOptions; - entry->FilePath = PhCreateString2(&pluginInstance->FileName->sr); - entry->FileName = PhGetBaseName(entry->FilePath); - - PhLargeIntegerToSystemTime(&utcTime, &basic.LastWriteTime); - SystemTimeToTzSpecificLocalTime(NULL, &utcTime, &localTime); - entry->UpdatedTime = PhFormatDateTime(&localTime); - - PhLargeIntegerToSystemTime(&utcTime, &basic.CreationTime); - SystemTimeToTzSpecificLocalTime(NULL, &utcTime, &localTime); - entry->AddedTime = PhFormatDateTime(&localTime); - - PluginsAddTreeNode(Context, entry); - } -} \ No newline at end of file diff --git a/plugins/ExtraPlugins/resource.h b/plugins/ExtraPlugins/resource.h deleted file mode 100644 index 301cf1ec38d5..000000000000 --- a/plugins/ExtraPlugins/resource.h +++ /dev/null @@ -1,38 +0,0 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by ExtraPlugins.rc -// -#define IDD_PLUGINS_DIALOG 102 -#define IDB_SEARCH_ACTIVE_BMP 105 -#define IDB_SEARCH_ACTIVE 106 -#define IDB_SEARCH_INACTIVE_BMP 107 -#define IDB_SEARCH_INACTIVE 108 -#define IDD_DIALOG1 111 -#define IDD_DISABLED_DIALOG 111 -#define IDB_SETTINGS 113 -#define IDB_SETTINGS_PNG 113 -#define IDC_PLUGINTREE 1001 -#define IDC_INSTALLED 1036 -#define IDC_BROWSE 1037 -#define IDC_UPDATES 1038 -#define IDC_DISABLED 1039 -#define IDC_LIST_DISABLED 1046 -#define IDC_CLEANUP 1057 -#define ID_MENU_INSTALL 4059 -#define ID_MENU_UNINSTALL 40011 -#define ID_MENU_DISABLE 40012 -#define ID_MENU_PROPERTIES 40013 -#define ID_MENU_UNLOAD 40014 -#define IDC_INSTRUCTION 40025 -#define IDC_SEARCHBOX 40026 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 114 -#define _APS_NEXT_COMMAND_VALUE 40028 -#define _APS_NEXT_CONTROL_VALUE 1047 -#define _APS_NEXT_SYMED_VALUE 104 -#endif -#endif diff --git a/plugins/ExtraPlugins/resources/cog_edit_modern.png b/plugins/ExtraPlugins/resources/cog_edit_modern.png deleted file mode 100644 index 8cf8e4dcdd3a042f4cb9950a9efd00fe9ce8f5cf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 341 zcmeAS@N?(olHy`uVBq!ia0vp^k|4~%3?x6Bmj(hUrvRT2S0Jrz6`wnSbH*^{ST+n&$gjr7NpKz9dug=. - */ - -#include "..\main.h" - -static TASKDIALOG_BUTTON TaskDialogButtonArray[] = -{ - { IDOK, L"Download" } -}; - -HRESULT CALLBACK ShowAvailableCallbackProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam, - _In_ LONG_PTR dwRefData - ) -{ - PPH_UPDATER_CONTEXT context = (PPH_UPDATER_CONTEXT)dwRefData; - - switch (uMsg) - { - case TDN_BUTTON_CLICKED: - { - if ((INT)wParam == IDOK) - { - ShowProgressDialog(context); - return S_FALSE; - } - } - break; - } - - return S_OK; -} - -VOID ShowAvailableDialog( - _In_ PPH_UPDATER_CONTEXT Context - ) -{ - TASKDIALOGCONFIG config; - - memset(&config, 0, sizeof(TASKDIALOGCONFIG)); - config.cbSize = sizeof(TASKDIALOGCONFIG); - config.dwFlags = TDF_USE_HICON_MAIN | TDF_ALLOW_DIALOG_CANCELLATION | TDF_CAN_BE_MINIMIZED | TDF_ENABLE_HYPERLINKS; - config.dwCommonButtons = TDCBF_CANCEL_BUTTON; - config.hMainIcon = Context->IconLargeHandle; - - config.pszWindowTitle = L"Process Hacker - Plugin Manager"; - config.pszMainInstruction = PhIsNullOrEmptyString(Context->Node->Name) ? PhGetStringOrEmpty(Context->Node->InternalName) : PhGetStringOrEmpty(Context->Node->Name); - config.pszContent = PhaFormatString(L"%s\r\n\r\nAuthor: %s\r\nVersion: %s\r\nUpdated: %s", - PhGetStringOrEmpty(Context->Node->Description), - PhGetStringOrEmpty(Context->Node->Author), - PhGetStringOrEmpty(Context->Node->Version), - PhGetStringOrEmpty(Context->Node->UpdatedTime) - )->Buffer; - //config.pszExpandedInformation = L"View Changelog"; - - config.cxWidth = 200; - config.pButtons = TaskDialogButtonArray; - config.cButtons = ARRAYSIZE(TaskDialogButtonArray); - - config.lpCallbackData = (LONG_PTR)Context; - config.pfCallback = ShowAvailableCallbackProc; - - SendMessage(Context->DialogHandle, TDM_NAVIGATE_PAGE, 0, (LPARAM)&config); -} diff --git a/plugins/ExtraPlugins/setup/page4.c b/plugins/ExtraPlugins/setup/page4.c deleted file mode 100644 index 9f163d8c62cc..000000000000 --- a/plugins/ExtraPlugins/setup/page4.c +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Process Hacker Plugins - - * Update Checker Plugin - * - * Copyright (C) 2016 dmex - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include "..\main.h" - -HRESULT CALLBACK ShowProgressCallbackProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam, - _In_ LONG_PTR dwRefData - ) -{ - PPH_UPDATER_CONTEXT context = (PPH_UPDATER_CONTEXT)dwRefData; - - switch (uMsg) - { - case TDN_NAVIGATED: - { - SendMessage(hwndDlg, TDM_SET_MARQUEE_PROGRESS_BAR, TRUE, 0); - SendMessage(hwndDlg, TDM_SET_PROGRESS_BAR_MARQUEE, TRUE, 1); - - PhReferenceObject(context); - PhQueueItemWorkQueue(PhGetGlobalWorkQueue(), UpdateDownloadThread, context); - } - break; - case TDN_HYPERLINK_CLICKED: - { - TaskDialogLinkClicked(context); - } - break; - } - - return S_OK; -} - -VOID ShowProgressDialog( - _In_ PPH_UPDATER_CONTEXT Context - ) -{ - TASKDIALOGCONFIG config; - - memset(&config, 0, sizeof(TASKDIALOGCONFIG)); - config.cbSize = sizeof(TASKDIALOGCONFIG); - config.dwFlags = TDF_USE_HICON_MAIN | TDF_ALLOW_DIALOG_CANCELLATION | TDF_CAN_BE_MINIMIZED | TDF_ENABLE_HYPERLINKS | TDF_SHOW_PROGRESS_BAR; - config.dwCommonButtons = TDCBF_CANCEL_BUTTON; - config.hMainIcon = Context->IconLargeHandle; - - config.pszWindowTitle = L"Process Hacker - Plugin Manager"; - config.pszMainInstruction = L"Downloading 0.0.0.0..."; - config.pszContent = L"Downloaded: ~ of ~ (0%)\r\nSpeed: ~ KB/s"; - //config.pszExpandedInformation = L"View Changelog"; - - config.cxWidth = 200; - config.lpCallbackData = (LONG_PTR)Context; - config.pfCallback = ShowProgressCallbackProc; - - SendMessage(Context->DialogHandle, TDM_NAVIGATE_PAGE, 0, (LPARAM)&config); -} \ No newline at end of file diff --git a/plugins/ExtraPlugins/setup/page5.c b/plugins/ExtraPlugins/setup/page5.c deleted file mode 100644 index e703258e37b6..000000000000 --- a/plugins/ExtraPlugins/setup/page5.c +++ /dev/null @@ -1,198 +0,0 @@ -/* - * Process Hacker Plugins - - * Update Checker Plugin - * - * Copyright (C) 2016 dmex - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include "..\main.h" -#include -#include - -static TASKDIALOG_BUTTON TaskDialogButtonArray[] = -{ - { IDYES, L"Restart" } -}; - -HRESULT CALLBACK RestartTaskDialogCallbackProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam, - _In_ LONG_PTR dwRefData - ) -{ - PPH_UPDATER_CONTEXT context = (PPH_UPDATER_CONTEXT)dwRefData; - - switch (uMsg) - { - case TDN_BUTTON_CLICKED: - { - if ((INT)wParam == IDYES) - { - ProcessHacker_PrepareForEarlyShutdown(PhMainWndHandle); - PhShellProcessHacker( - PhMainWndHandle, - L"-v", - SW_SHOW, - 0, - PH_SHELL_APP_PROPAGATE_PARAMETERS | PH_SHELL_APP_PROPAGATE_PARAMETERS_IGNORE_VISIBILITY, - 0, - NULL - ); - //PhShellProcessHacker( - // PhMainWndHandle, - // L"-plugin " PLUGIN_NAME L":INSTALL -plugin " PLUGIN_NAME L":hex64value", - // SW_SHOW, - // 0, - // PH_SHELL_APP_PROPAGATE_PARAMETERS | PH_SHELL_APP_PROPAGATE_PARAMETERS_IGNORE_VISIBILITY, - // 0, - // NULL - // ); - ProcessHacker_Destroy(PhMainWndHandle); - } - } - break; - } - - return S_OK; -} - -HRESULT CALLBACK FinalTaskDialogCallbackProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam, - _In_ LONG_PTR dwRefData - ) -{ - PPH_UPDATER_CONTEXT context = (PPH_UPDATER_CONTEXT)dwRefData; - - switch (uMsg) - { - case TDN_NAVIGATED: - { - if (!PhGetOwnTokenAttributes().Elevated) - { - SendMessage(hwndDlg, TDM_SET_BUTTON_ELEVATION_REQUIRED_STATE, IDYES, TRUE); - } - } - break; - case TDN_BUTTON_CLICKED: - { - if ((INT)wParam == IDRETRY) - { - ShowAvailableDialog(context); - return S_FALSE; - } - } - break; - } - - return S_OK; -} - -VOID ShowInstallRestartDialog( - _In_ PPH_UPDATER_CONTEXT Context - ) -{ - TASKDIALOGCONFIG config; - - memset(&config, 0, sizeof(TASKDIALOGCONFIG)); - config.cbSize = sizeof(TASKDIALOGCONFIG); - config.dwFlags = TDF_USE_HICON_MAIN | TDF_ALLOW_DIALOG_CANCELLATION | TDF_CAN_BE_MINIMIZED; - config.dwCommonButtons = TDCBF_CLOSE_BUTTON; - config.hMainIcon = Context->IconLargeHandle; - - config.pszWindowTitle = L"Process Hacker - Plugin Manager"; - config.pszMainInstruction = L"Process Hacker needs to restart"; - config.pszContent = L"Changes may require a restart to take effect..."; - - config.pButtons = TaskDialogButtonArray; - config.cButtons = ARRAYSIZE(TaskDialogButtonArray); - - config.cxWidth = 200; - config.pfCallback = RestartTaskDialogCallbackProc; - config.lpCallbackData = (LONG_PTR)Context; - - SendMessage(Context->DialogHandle, TDM_NAVIGATE_PAGE, 0, (LPARAM)&config); -} - -VOID ShowUninstallRestartDialog( - _In_ PPH_UPDATER_CONTEXT Context - ) -{ - TASKDIALOGCONFIG config; - - memset(&config, 0, sizeof(TASKDIALOGCONFIG)); - config.cbSize = sizeof(TASKDIALOGCONFIG); - config.dwFlags = TDF_USE_HICON_MAIN | TDF_ALLOW_DIALOG_CANCELLATION | TDF_CAN_BE_MINIMIZED; - config.dwCommonButtons = TDCBF_CLOSE_BUTTON; - config.hMainIcon = Context->IconLargeHandle; - - config.pszWindowTitle = L"Process Hacker - Plugin Manager"; - config.pszMainInstruction = L"Process Hacker needs to restart"; - config.pszContent = L"Changes may require a restart to take effect..."; - - config.pButtons = TaskDialogButtonArray; - config.cButtons = ARRAYSIZE(TaskDialogButtonArray); - - config.cxWidth = 200; - config.pfCallback = RestartTaskDialogCallbackProc; - config.lpCallbackData = (LONG_PTR)Context; - - SendMessage(Context->DialogHandle, TDM_NAVIGATE_PAGE, 0, (LPARAM)&config); -} - -VOID ShowUpdateFailedDialog( - _In_ PPH_UPDATER_CONTEXT Context, - _In_ BOOLEAN HashFailed, - _In_ BOOLEAN SignatureFailed - ) -{ - TASKDIALOGCONFIG config; - - memset(&config, 0, sizeof(TASKDIALOGCONFIG)); - config.cbSize = sizeof(TASKDIALOGCONFIG); - //config.pszMainIcon = MAKEINTRESOURCE(65529); - config.dwFlags = TDF_USE_HICON_MAIN | TDF_ALLOW_DIALOG_CANCELLATION | TDF_CAN_BE_MINIMIZED; - config.dwCommonButtons = TDCBF_CLOSE_BUTTON | TDCBF_RETRY_BUTTON; - config.hMainIcon = Context->IconLargeHandle; - - config.pszWindowTitle = L"Process Hacker - Plugin Manager"; - config.pszMainInstruction = L"Error downloading plugin files."; - - if (SignatureFailed) - { - config.pszContent = L"Signature check failed. Click Retry to download the plugin again."; - } - else if (HashFailed) - { - config.pszContent = L"Hash check failed. Click Retry to download the plugin again."; - } - else - { - config.pszContent = L"Click Retry to download the plugin again."; - } - - config.cxWidth = 200; - config.pfCallback = FinalTaskDialogCallbackProc; - config.lpCallbackData = (LONG_PTR)Context; - - SendMessage(Context->DialogHandle, TDM_NAVIGATE_PAGE, 0, (LPARAM)&config); -} \ No newline at end of file diff --git a/plugins/ExtraPlugins/setup/uninstall.c b/plugins/ExtraPlugins/setup/uninstall.c deleted file mode 100644 index 17da99493fbd..000000000000 --- a/plugins/ExtraPlugins/setup/uninstall.c +++ /dev/null @@ -1,158 +0,0 @@ -#include "..\main.h" -#include -#include - -static TASKDIALOG_BUTTON TaskDialogButtonArray[] = -{ - { IDYES, L"Uninstall" } -}; - -HRESULT CALLBACK TaskDialogUninstallCallbackProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam, - _In_ LONG_PTR dwRefData - ) -{ - PPH_UPDATER_CONTEXT context = (PPH_UPDATER_CONTEXT)dwRefData; - - switch (uMsg) - { - case TDN_NAVIGATED: - { - //PhQueueItemWorkQueue(PhGetGlobalWorkQueue(), SetupExtractBuild, context); - } - break; - case TDN_BUTTON_CLICKED: - { - if ((INT)wParam == IDYES) - { - PPH_STRING baseNameString; - PPH_STRING fileNameString; - PPH_STRING bakNameString; - - context->Node->State = PLUGIN_STATE_RESTART; - - fileNameString = PhGetFileName(context->Node->FilePath); - baseNameString = PhGetBaseName(context->Node->FilePath); - bakNameString = PhConcatStrings(2, PhGetString(fileNameString), L".bak"); - - if (RtlDoesFileExists_U(PhGetString(fileNameString))) - { - MoveFileEx(PhGetString(fileNameString), PhGetString(bakNameString), MOVEFILE_REPLACE_EXISTING); - } - - PhDereferenceObject(bakNameString); - PhDereferenceObject(baseNameString); - PhDereferenceObject(fileNameString); - - if (PhGetIntegerSetting(L"EnableWarnings")) - ShowUninstallRestartDialog(context); - else - SendMessage(hwndDlg, WM_CLOSE, 0, 0); - - return S_FALSE; - } - } - break; - } - - return S_OK; -} - -VOID ShowPluginUninstallDialog( - _In_ PPH_UPDATER_CONTEXT Context - ) -{ - PPH_UPDATER_CONTEXT context; - TASKDIALOGCONFIG config = { sizeof(TASKDIALOGCONFIG) }; - - context = (PPH_UPDATER_CONTEXT)Context; - - config.cxWidth = 200; - config.pszWindowTitle = L"Process Hacker - Plugin Manager"; - config.pszMainInstruction = PhaFormatString(L"Uninstall %s?", PhIsNullOrEmptyString(Context->Node->Name) ? PhGetStringOrEmpty(Context->Node->InternalName) : PhGetStringOrEmpty(Context->Node->Name))->Buffer; - config.dwFlags = TDF_USE_HICON_MAIN | TDF_ALLOW_DIALOG_CANCELLATION | TDF_CAN_BE_MINIMIZED; - config.dwCommonButtons = TDCBF_CLOSE_BUTTON; - config.hMainIcon = context->IconLargeHandle; - config.pfCallback = TaskDialogUninstallCallbackProc; - config.lpCallbackData = (LONG_PTR)Context; - config.pButtons = TaskDialogButtonArray; - config.cButtons = ARRAYSIZE(TaskDialogButtonArray); - - SendMessage(Context->DialogHandle, TDM_NAVIGATE_PAGE, 0, (LPARAM)&config); -} - -HRESULT CALLBACK TaskDialogUninstallWithoutPromptCallback( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam, - _In_ LONG_PTR dwRefData - ) -{ - PPH_UPDATER_CONTEXT context = (PPH_UPDATER_CONTEXT)dwRefData; - - switch (uMsg) - { - case TDN_NAVIGATED: - { - PPH_STRING baseNameString; - PPH_STRING fileNameString; - PPH_STRING bakNameString; - - context->Node->State = PLUGIN_STATE_RESTART; - - fileNameString = PhGetFileName(context->Node->FilePath); - baseNameString = PhGetBaseName(context->Node->FilePath); - bakNameString = PhConcatStrings(2, PhGetString(fileNameString), L".bak"); - - //PhQueueItemWorkQueue(PhGetGlobalWorkQueue(), SetupExtractBuild, context); - if (RtlDoesFileExists_U(PhGetString(fileNameString))) - { - MoveFileEx(PhGetString(fileNameString), PhGetString(bakNameString), MOVEFILE_REPLACE_EXISTING); - } - - PhDereferenceObject(bakNameString); - PhDereferenceObject(baseNameString); - PhDereferenceObject(fileNameString); - - if (PhGetIntegerSetting(L"EnableWarnings")) - { - ShowUninstallRestartDialog(context); - } - { - SendMessage(hwndDlg, WM_CLOSE, 0, 0); - } - - return S_FALSE; - } - break; - } - - return S_OK; -} - -VOID ShowPluginUninstallWithoutPrompt( - _In_ PPH_UPDATER_CONTEXT Context - ) -{ - PPH_UPDATER_CONTEXT context; - TASKDIALOGCONFIG config = { sizeof(TASKDIALOGCONFIG) }; - - context = (PPH_UPDATER_CONTEXT)Context; - - config.cxWidth = 200; - config.pszWindowTitle = L"Process Hacker - Plugin Manager"; - config.pszMainInstruction = PhaFormatString(L"Uninstalling %s...", PhIsNullOrEmptyString(Context->Node->Name) ? PhGetStringOrEmpty(Context->Node->InternalName) : PhGetStringOrEmpty(Context->Node->Name))->Buffer; - config.dwFlags = TDF_USE_HICON_MAIN | TDF_CAN_BE_MINIMIZED | TDF_SHOW_MARQUEE_PROGRESS_BAR; - config.dwCommonButtons = TDCBF_CLOSE_BUTTON; - config.hMainIcon = context->IconLargeHandle; - config.pfCallback = TaskDialogUninstallWithoutPromptCallback; - config.lpCallbackData = (LONG_PTR)Context; - config.pButtons = TaskDialogButtonArray; - config.cButtons = ARRAYSIZE(TaskDialogButtonArray); - - SendMessage(Context->DialogHandle, TDM_NAVIGATE_PAGE, 0, (LPARAM)&config); -} \ No newline at end of file diff --git a/plugins/ExtraPlugins/setup/updater.c b/plugins/ExtraPlugins/setup/updater.c deleted file mode 100644 index 25fbd3ddb1f8..000000000000 --- a/plugins/ExtraPlugins/setup/updater.c +++ /dev/null @@ -1,678 +0,0 @@ -/* - * Process Hacker Plugins - - * Update Checker Plugin - * - * Copyright (C) 2011-2016 dmex - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include "..\main.h" -#include - -PPH_UPDATER_CONTEXT CreateUpdateContext( - _In_ PPLUGIN_NODE Node, - _In_ PLUGIN_ACTION Action - ) -{ - PPH_UPDATER_CONTEXT context; - - context = (PPH_UPDATER_CONTEXT)PhCreateAlloc(sizeof(PH_UPDATER_CONTEXT)); - memset(context, 0, sizeof(PH_UPDATER_CONTEXT)); - - context->Action = Action; - context->Node = Node; - - return context; -} - -VOID FreeUpdateContext( - _In_ _Post_invalid_ PPH_UPDATER_CONTEXT Context - ) -{ - PhDereferenceObject(Context); -} - -VOID TaskDialogCreateIcons( - _In_ PPH_UPDATER_CONTEXT Context - ) -{ - // Load the Process Hacker window icon - Context->IconLargeHandle = PH_LOAD_SHARED_ICON_LARGE(PhInstanceHandle, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER)); - Context->IconSmallHandle = PH_LOAD_SHARED_ICON_SMALL(PhInstanceHandle, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER)); - - // Set the TaskDialog window icons - SendMessage(Context->DialogHandle, WM_SETICON, ICON_SMALL, (LPARAM)Context->IconSmallHandle); - SendMessage(Context->DialogHandle, WM_SETICON, ICON_BIG, (LPARAM)Context->IconLargeHandle); -} - -VOID TaskDialogLinkClicked( - _In_ PPH_UPDATER_CONTEXT Context - ) -{ - //if (!PhIsNullOrEmptyString(Context->ReleaseNotesUrl)) - { - // Launch the ReleaseNotes URL (if it exists) with the default browser - //PhShellExecute(Context->DialogHandle, Context->ReleaseNotesUrl->Buffer, NULL); - } -} - -PPH_STRING UpdaterGetOpaqueXmlNodeText( - _In_ mxml_node_t *xmlNode - ) -{ - if (xmlNode && xmlNode->child && xmlNode->child->type == MXML_OPAQUE && xmlNode->child->value.opaque) - { - return PhConvertUtf8ToUtf16(xmlNode->child->value.opaque); - } - - return PhReferenceEmptyString(); -} - -PPH_STRING UpdateVersionString( - VOID - ) -{ - ULONG majorVersion; - ULONG minorVersion; - ULONG revisionVersion; - PPH_STRING currentVersion = NULL; - PPH_STRING versionHeader = NULL; - - PhGetPhVersionNumbers( - &majorVersion, - &minorVersion, - NULL, - &revisionVersion - ); - - currentVersion = PhFormatString( - L"%lu.%lu.%lu", - majorVersion, - minorVersion, - revisionVersion - ); - - if (currentVersion) - { - versionHeader = PhConcatStrings2(L"ProcessHacker-Build: ", currentVersion->Buffer); - PhDereferenceObject(currentVersion); - } - - return versionHeader; -} - -PPH_STRING UpdateWindowsString( - VOID - ) -{ - static PH_STRINGREF keyName = PH_STRINGREF_INIT(L"Software\\Microsoft\\Windows NT\\CurrentVersion"); - - HANDLE keyHandle = NULL; - PPH_STRING buildLabHeader = NULL; - - if (NT_SUCCESS(PhOpenKey( - &keyHandle, - KEY_READ, - PH_KEY_LOCAL_MACHINE, - &keyName, - 0 - ))) - { - PPH_STRING buildLabString; - - if (buildLabString = PhQueryRegistryString(keyHandle, L"BuildLabEx")) - { - buildLabHeader = PhConcatStrings2(L"ProcessHacker-OsBuild: ", buildLabString->Buffer); - PhDereferenceObject(buildLabString); - } - else if (buildLabString = PhQueryRegistryString(keyHandle, L"BuildLab")) - { - buildLabHeader = PhConcatStrings2(L"ProcessHacker-OsBuild: ", buildLabString->Buffer); - PhDereferenceObject(buildLabString); - } - - NtClose(keyHandle); - } - - return buildLabHeader; -} - -//BOOLEAN ParseVersionString( -// _Inout_ PPH_UPDATER_CONTEXT Context -// ) -//{ -// PH_STRINGREF sr, majorPart, minorPart, revisionPart; -// ULONG64 majorInteger = 0, minorInteger = 0, revisionInteger = 0; -// -// //PhInitializeStringRef(&sr, Context->VersionString->Buffer); -// PhInitializeStringRef(&revisionPart, Context->RevVersion->Buffer); -// -// if (PhSplitStringRefAtChar(&sr, '.', &majorPart, &minorPart)) -// { -// PhStringToInteger64(&majorPart, 10, &majorInteger); -// PhStringToInteger64(&minorPart, 10, &minorInteger); -// PhStringToInteger64(&revisionPart, 10, &revisionInteger); -// -// //Context->MajorVersion = (ULONG)majorInteger; -// //Context->MinorVersion = (ULONG)minorInteger; -// //Context->RevisionVersion = (ULONG)revisionInteger; -// -// return TRUE; -// } -// -// return FALSE; -//} - -BOOLEAN ReadRequestString( - _In_ HINTERNET Handle, - _Out_ _Deref_post_z_cap_(*DataLength) PSTR *Data, - _Out_ ULONG *DataLength - ) -{ - PSTR data; - ULONG allocatedLength; - ULONG dataLength; - ULONG returnLength; - BYTE buffer[PAGE_SIZE]; - - allocatedLength = sizeof(buffer); - data = (PSTR)PhAllocate(allocatedLength); - dataLength = 0; - - // Zero the buffer - memset(buffer, 0, PAGE_SIZE); - - while (WinHttpReadData(Handle, buffer, PAGE_SIZE, &returnLength)) - { - if (returnLength == 0) - break; - - if (allocatedLength < dataLength + returnLength) - { - allocatedLength *= 2; - data = (PSTR)PhReAllocate(data, allocatedLength); - } - - // Copy the returned buffer into our pointer - memcpy(data + dataLength, buffer, returnLength); - // Zero the returned buffer for the next loop - //memset(buffer, 0, returnLength); - - dataLength += returnLength; - } - - if (allocatedLength < dataLength + 1) - { - allocatedLength++; - data = (PSTR)PhReAllocate(data, allocatedLength); - } - - // Ensure that the buffer is null-terminated. - data[dataLength] = 0; - - *DataLength = dataLength; - *Data = data; - - return TRUE; -} - -NTSTATUS UpdateDownloadThread( - _In_ PVOID Parameter - ) -{ - BOOLEAN downloadSuccess = FALSE; - BOOLEAN hashSuccess = FALSE; - BOOLEAN signatureSuccess = FALSE; - BOOLEAN updateSuccess = FALSE; - HANDLE tempFileHandle = NULL; - HINTERNET httpSessionHandle = NULL; - HINTERNET httpConnectionHandle = NULL; - HINTERNET httpRequestHandle = NULL; - PPH_STRING downloadHostPath = NULL; - PPH_STRING downloadUrlPath = NULL; - PPH_STRING userAgentString = NULL; - PPH_STRING fileDownloadUrl = NULL; - PUPDATER_HASH_CONTEXT hashContext = NULL; - ULONG indexOfFileName = -1; - URL_COMPONENTS httpParts = { sizeof(URL_COMPONENTS) }; - LARGE_INTEGER timeNow; - LARGE_INTEGER timeStart; - ULONG64 timeTicks = 0; - ULONG64 timeBitsPerSecond = 0; - PPH_UPDATER_CONTEXT context = (PPH_UPDATER_CONTEXT)Parameter; - - SendMessage(context->DialogHandle, TDM_UPDATE_ELEMENT_TEXT, TDE_MAIN_INSTRUCTION, (LPARAM)L"Initializing download request..."); - - context->SetupFilePath = PhCreateCacheFile(PhaFormatString( - L"%s.zip", - PhGetStringOrEmpty(context->Node->InternalName) - )); - - if (PhIsNullOrEmptyString(context->SetupFilePath)) - goto CleanupExit; - - if (!NT_SUCCESS(PhCreateFileWin32( - &tempFileHandle, - PhGetStringOrEmpty(context->SetupFilePath), - FILE_GENERIC_READ | FILE_GENERIC_WRITE, - FILE_ATTRIBUTE_NOT_CONTENT_INDEXED | FILE_ATTRIBUTE_TEMPORARY, - FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, - FILE_OVERWRITE_IF, - FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT - ))) - { - goto CleanupExit; - } - - fileDownloadUrl = PhFormatString( - L"https://wj32.org/processhacker/plugins/download.php?id=%s&type=64", - PhGetStringOrEmpty(context->Node->Id) - ); - - // Set lengths to non-zero enabling these params to be cracked. - httpParts.dwSchemeLength = ULONG_MAX; - httpParts.dwHostNameLength = ULONG_MAX; - httpParts.dwUrlPathLength = ULONG_MAX; - - if (!WinHttpCrackUrl( - PhGetString(fileDownloadUrl), - 0, - 0, - &httpParts - )) - { - PhDereferenceObject(fileDownloadUrl); - goto CleanupExit; - } - - PhDereferenceObject(fileDownloadUrl); - - // Create the Host string. - if (PhIsNullOrEmptyString(downloadHostPath = PhCreateStringEx( - httpParts.lpszHostName, - httpParts.dwHostNameLength * sizeof(WCHAR) - ))) - { - goto CleanupExit; - } - - // Create the remote path string. - if (PhIsNullOrEmptyString(downloadUrlPath = PhCreateStringEx( - httpParts.lpszUrlPath, - httpParts.dwUrlPathLength * sizeof(WCHAR) - ))) - { - goto CleanupExit; - } - - SendMessage(context->DialogHandle, TDM_UPDATE_ELEMENT_TEXT, TDE_MAIN_INSTRUCTION, (LPARAM)L"Connecting..."); - - if (!(httpSessionHandle = WinHttpOpen( - PhGetString(userAgentString), - WindowsVersion >= WINDOWS_8_1 ? WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY : WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, - WINHTTP_NO_PROXY_NAME, - WINHTTP_NO_PROXY_BYPASS, - 0 - ))) - { - goto CleanupExit; - } - - if (WindowsVersion >= WINDOWS_8_1) - { - WinHttpSetOption( - httpSessionHandle, - WINHTTP_OPTION_DECOMPRESSION, - &(ULONG) { WINHTTP_DECOMPRESSION_FLAG_GZIP | WINHTTP_DECOMPRESSION_FLAG_DEFLATE }, - sizeof(ULONG) - ); - } - - if (!(httpConnectionHandle = WinHttpConnect( - httpSessionHandle, - PhGetString(downloadHostPath), - httpParts.nScheme == INTERNET_SCHEME_HTTP ? INTERNET_DEFAULT_HTTP_PORT : INTERNET_DEFAULT_HTTPS_PORT, - 0 - ))) - { - goto CleanupExit; - } - - if (!(httpRequestHandle = WinHttpOpenRequest( - httpConnectionHandle, - NULL, - PhGetString(downloadUrlPath), - NULL, - WINHTTP_NO_REFERER, - WINHTTP_DEFAULT_ACCEPT_TYPES, - WINHTTP_FLAG_REFRESH | (httpParts.nScheme == INTERNET_SCHEME_HTTPS ? WINHTTP_FLAG_SECURE : 0) - ))) - { - goto CleanupExit; - } - - WinHttpSetOption( - httpRequestHandle, - WINHTTP_OPTION_DISABLE_FEATURE, - &(ULONG){ WINHTTP_DISABLE_KEEP_ALIVE }, - sizeof(ULONG) - ); - - SendMessage(context->DialogHandle, TDM_UPDATE_ELEMENT_TEXT, TDE_MAIN_INSTRUCTION, (LPARAM)L"Sending download request..."); - - if (!WinHttpSendRequest( - httpRequestHandle, - WINHTTP_NO_ADDITIONAL_HEADERS, - 0, - WINHTTP_NO_REQUEST_DATA, - 0, - WINHTTP_IGNORE_REQUEST_TOTAL_LENGTH, - 0 - )) - { - goto CleanupExit; - } - - SendMessage(context->DialogHandle, TDM_UPDATE_ELEMENT_TEXT, TDE_MAIN_INSTRUCTION, (LPARAM)L"Waiting for response..."); - - if (WinHttpReceiveResponse(httpRequestHandle, NULL)) - { - ULONG bytesDownloaded = 0; - ULONG downloadedBytes = 0; - ULONG contentLengthSize = sizeof(ULONG); - ULONG contentLength = 0; - PPH_STRING status; - IO_STATUS_BLOCK isb; - BYTE buffer[PAGE_SIZE]; - - status = PhFormatString(L"Downloading %s...", PhGetString(context->Node->Name)); - - SendMessage(context->DialogHandle, TDM_SET_MARQUEE_PROGRESS_BAR, FALSE, 0); - SendMessage(context->DialogHandle, TDM_UPDATE_ELEMENT_TEXT, TDE_MAIN_INSTRUCTION, (LPARAM)PhGetString(status)); - - PhDereferenceObject(status); - - // Start the clock. - PhQuerySystemTime(&timeStart); - - if (!WinHttpQueryHeaders( - httpRequestHandle, - WINHTTP_QUERY_CONTENT_LENGTH | WINHTTP_QUERY_FLAG_NUMBER, - WINHTTP_HEADER_NAME_BY_INDEX, - &contentLength, - &contentLengthSize, - 0 - )) - { - goto CleanupExit; - } - - // Initialize hash algorithm. - if (!UpdaterInitializeHash(&hashContext)) - goto CleanupExit; - - // Zero the buffer. - memset(buffer, 0, PAGE_SIZE); - - // Download the data. - while (WinHttpReadData(httpRequestHandle, buffer, PAGE_SIZE, &bytesDownloaded)) - { - // If we get zero bytes, the file was uploaded or there was an error - if (bytesDownloaded == 0) - break; - - // If the dialog was closed, just cleanup and exit - //if (!UpdateDialogThreadHandle) - // __leave; - - // Update the hash of bytes we downloaded. - UpdaterUpdateHash(hashContext, buffer, bytesDownloaded); - - // Write the downloaded bytes to disk. - if (!NT_SUCCESS(NtWriteFile( - tempFileHandle, - NULL, - NULL, - NULL, - &isb, - buffer, - bytesDownloaded, - NULL, - NULL - ))) - { - goto CleanupExit; - } - - downloadedBytes += (DWORD)isb.Information; - - // Check the number of bytes written are the same we downloaded. - if (bytesDownloaded != isb.Information) - goto CleanupExit; - - // Query the current time - PhQuerySystemTime(&timeNow); - - // Calculate the number of ticks - timeTicks = (timeNow.QuadPart - timeStart.QuadPart) / PH_TICKS_PER_SEC; - timeBitsPerSecond = downloadedBytes / __max(timeTicks, 1); - - // TODO: Update on timer callback. - { - FLOAT percent = ((FLOAT)downloadedBytes / contentLength * 100); - PPH_STRING totalLength = PhFormatSize(contentLength, -1); - PPH_STRING totalDownloaded = PhFormatSize(downloadedBytes, -1); - PPH_STRING totalSpeed = PhFormatSize(timeBitsPerSecond, -1); - - PPH_STRING statusMessage = PhFormatString( - L"Downloaded: %s of %s (%.0f%%)\r\nSpeed: %s/s", - totalDownloaded->Buffer, - totalLength->Buffer, - percent, - totalSpeed->Buffer - ); - - SendMessage(context->DialogHandle, TDM_SET_PROGRESS_BAR_POS, (WPARAM)percent, 0); - SendMessage(context->DialogHandle, TDM_UPDATE_ELEMENT_TEXT, TDE_CONTENT, (LPARAM)statusMessage->Buffer); - - PhDereferenceObject(statusMessage); - PhDereferenceObject(totalSpeed); - PhDereferenceObject(totalLength); - PhDereferenceObject(totalDownloaded); - } - } - - downloadSuccess = TRUE; - - if (UpdaterVerifyHash(hashContext, context->Node->SHA2_64)) - { - hashSuccess = TRUE; - } - - if (UpdaterVerifySignature(hashContext, context->Node->HASH_64)) - { - signatureSuccess = TRUE; - } - } - -CleanupExit: - - if (hashContext) - UpdaterDestroyHash(hashContext); - - if (tempFileHandle) - NtClose(tempFileHandle); - - if (httpRequestHandle) - WinHttpCloseHandle(httpRequestHandle); - - if (httpConnectionHandle) - WinHttpCloseHandle(httpConnectionHandle); - - if (httpSessionHandle) - WinHttpCloseHandle(httpSessionHandle); - - PhClearReference(&downloadHostPath); - PhClearReference(&downloadUrlPath); - PhClearReference(&userAgentString); - - if (downloadSuccess && hashSuccess && signatureSuccess) - { - if (NT_SUCCESS(SetupExtractBuild(context))) - { - updateSuccess = TRUE; - } - } - - if (context->SetupFilePath) - { - PhDeleteCacheFile(context->SetupFilePath); - PhDereferenceObject(context->SetupFilePath); - } - - if (updateSuccess) - { - if (PhGetIntegerSetting(L"EnableWarnings")) - ShowUninstallRestartDialog(context); - else - SendMessage(context->DialogHandle, WM_CLOSE, 0, 0); - } - else - { - ShowUpdateFailedDialog(context, FALSE, FALSE); - } - - return STATUS_SUCCESS; -} - -HRESULT CALLBACK TaskDialogBootstrapCallback( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam, - _In_ LONG_PTR dwRefData - ) -{ - PPH_UPDATER_CONTEXT context = (PPH_UPDATER_CONTEXT)dwRefData; - - switch (uMsg) - { - case TDN_CREATED: - { - context->DialogHandle = hwndDlg; - - TaskDialogCreateIcons(context); - - switch (context->Action) - { - case PLUGIN_ACTION_INSTALL: - { - if (PhGetIntegerSetting(L"EnableWarnings")) - ShowAvailableDialog(context); - else - ShowProgressDialog(context); - } - break; - case PLUGIN_ACTION_UNINSTALL: - { - if (PhGetIntegerSetting(L"EnableWarnings")) - ShowPluginUninstallDialog(context); - else - ShowPluginUninstallWithoutPrompt(context); - } - break; - case PLUGIN_ACTION_RESTART: - { - if (PhGetIntegerSetting(L"EnableWarnings")) - { - ShowUninstallRestartDialog(context); - } - else - { - SendMessage(hwndDlg, WM_CLOSE, 0, 0); - } - } - break; - } - } - break; - } - - return S_OK; -} - -BOOLEAN ShowInitialDialog( - _In_ HWND Parent, - _In_ PVOID Context - ) -{ - INT result = 0; - TASKDIALOGCONFIG config = { sizeof(TASKDIALOGCONFIG) }; - config.dwFlags = TDF_ALLOW_DIALOG_CANCELLATION | TDF_CAN_BE_MINIMIZED | TDF_POSITION_RELATIVE_TO_WINDOW; - config.pszContent = L"Initializing..."; - config.lpCallbackData = (LONG_PTR)Context; - config.pfCallback = TaskDialogBootstrapCallback; - config.hwndParent = Parent; - - // Start the TaskDialog bootstrap - TaskDialogIndirect(&config, &result, NULL, NULL); - - return result == IDOK; -} - -BOOLEAN ShowUpdateDialog( - _In_ HWND Parent, - _In_ PLUGIN_ACTION Action - ) -{ - BOOLEAN result; - PH_AUTO_POOL autoPool; - PPH_UPDATER_CONTEXT context; - - context = CreateUpdateContext(NULL, Action); - - PhInitializeAutoPool(&autoPool); - - result = ShowInitialDialog(Parent, context); - - FreeUpdateContext(context); - PhDeleteAutoPool(&autoPool); - - return result; -} - -BOOLEAN StartInitialCheck( - _In_ HWND Parent, - _In_ PPLUGIN_NODE Node, - _In_ PLUGIN_ACTION Action - ) -{ - BOOLEAN result; - PH_AUTO_POOL autoPool; - PPH_UPDATER_CONTEXT context; - - context = CreateUpdateContext(Node, Action); - - PhInitializeAutoPool(&autoPool); - - result = ShowInitialDialog(Parent, context); - - FreeUpdateContext(context); - PhDeleteAutoPool(&autoPool); - - return result; -} \ No newline at end of file diff --git a/plugins/ExtraPlugins/setup/verify.c b/plugins/ExtraPlugins/setup/verify.c deleted file mode 100644 index 25b01fa492e5..000000000000 --- a/plugins/ExtraPlugins/setup/verify.c +++ /dev/null @@ -1,204 +0,0 @@ -#include "..\main.h" - -static UCHAR ExtraPluginsPublicKey[] = -{ - 0x45, 0x43, 0x53, 0x31, 0x20, 0x00, 0x00, 0x00, 0x63, 0x35, 0x3E, 0x56, 0x42, - 0x64, 0xB3, 0x2F, 0xEE, 0x07, 0x85, 0x8A, 0x3D, 0x6E, 0x11, 0x98, 0x78, 0xE2, - 0xC7, 0x25, 0xD4, 0x15, 0x75, 0xD1, 0xDB, 0x63, 0x69, 0x56, 0x71, 0xCD, 0x86, - 0x05, 0xFD, 0xDE, 0xD8, 0x95, 0x89, 0xC4, 0xBC, 0x9B, 0x9E, 0x73, 0xE9, 0x74, - 0x7D, 0xB7, 0xAF, 0x07, 0x34, 0x57, 0x62, 0x72, 0x1A, 0x31, 0x46, 0x3E, 0x91, - 0x8A, 0x0B, 0x29, 0x8C, 0x97, 0xA4, 0x29 -}; - -BOOLEAN UpdaterInitializeHash( - _Out_ PUPDATER_HASH_CONTEXT *Context - ) -{ - ULONG querySize; - PUPDATER_HASH_CONTEXT hashContext; - - hashContext = PhAllocate(sizeof(UPDATER_HASH_CONTEXT)); - memset(hashContext, 0, sizeof(UPDATER_HASH_CONTEXT)); - - if (!NT_SUCCESS(BCryptOpenAlgorithmProvider( - &hashContext->SignAlgHandle, - BCRYPT_ECDSA_P256_ALGORITHM, - NULL, - 0 - ))) - { - goto error; - } - - if (!NT_SUCCESS(BCryptImportKeyPair( - hashContext->SignAlgHandle, - NULL, - BCRYPT_ECCPUBLIC_BLOB, - &hashContext->KeyHandle, - ExtraPluginsPublicKey, - sizeof(ExtraPluginsPublicKey), - 0 - ))) - { - goto error; - } - - if (!NT_SUCCESS(BCryptOpenAlgorithmProvider( - &hashContext->HashAlgHandle, - BCRYPT_SHA256_ALGORITHM, - NULL, - 0 - ))) - { - goto error; - } - - if (!NT_SUCCESS(BCryptGetProperty( - hashContext->HashAlgHandle, - BCRYPT_OBJECT_LENGTH, - (PUCHAR)&hashContext->HashObjectSize, - sizeof(ULONG), - &querySize, - 0 - ))) - { - goto error; - } - - if (!NT_SUCCESS(BCryptGetProperty( - hashContext->HashAlgHandle, - BCRYPT_HASH_LENGTH, - (PUCHAR)&hashContext->HashSize, - sizeof(ULONG), - &querySize, - 0 - ))) - { - goto error; - } - - if (!(hashContext->HashObject = PhAllocate(hashContext->HashObjectSize))) - goto error; - if (!(hashContext->Hash = PhAllocate(hashContext->HashSize))) - goto error; - - if (!NT_SUCCESS(BCryptCreateHash( - hashContext->HashAlgHandle, - &hashContext->HashHandle, - hashContext->HashObject, - hashContext->HashObjectSize, - NULL, - 0, - 0 - ))) - { - goto error; - } - - *Context = hashContext; - return TRUE; - -error: - UpdaterDestroyHash(hashContext); - return FALSE; -} - -BOOLEAN UpdaterUpdateHash( - _Inout_ PUPDATER_HASH_CONTEXT Context, - _In_reads_bytes_(Length) PVOID Buffer, - _In_ ULONG Length - ) -{ - return NT_SUCCESS(BCryptHashData(Context->HashHandle, Buffer, Length, 0)); -} - -BOOLEAN UpdaterVerifyHash( - _Inout_ PUPDATER_HASH_CONTEXT Context, - _In_ PPH_STRING Sha2Hash - ) -{ - PPH_STRING sha2HexString; - - // Compute the final hash. - if (!NT_SUCCESS(BCryptFinishHash( - Context->HashHandle, - Context->Hash, - Context->HashSize, - 0 - ))) - { - return FALSE; - } - - if (!(sha2HexString = PhBufferToHexString(Context->Hash, Context->HashSize))) - return FALSE; - - if (!PhEqualString2(sha2HexString, PhGetStringOrEmpty(Sha2Hash), TRUE)) - { - PhDereferenceObject(sha2HexString); - return FALSE; - } - - PhDereferenceObject(sha2HexString); - return TRUE; -} - -BOOLEAN UpdaterVerifySignature( - _Inout_ PUPDATER_HASH_CONTEXT Context, - _In_ PPH_STRING HexSignature - ) -{ - ULONG signatureLength; - PUCHAR signatureBuffer; - - signatureLength = (ULONG)HexSignature->Length / sizeof(WCHAR) / 2; - signatureBuffer = PhAllocate(signatureLength); - - if (!PhHexStringToBuffer(&HexSignature->sr, signatureBuffer)) - { - PhFree(signatureBuffer); - return FALSE; - } - - if (!NT_SUCCESS(BCryptVerifySignature( - Context->KeyHandle, - NULL, - Context->Hash, - Context->HashSize, - signatureBuffer, - signatureLength, - 0 - ))) - { - PhFree(signatureBuffer); - return FALSE; - } - - PhFree(signatureBuffer); - return TRUE; -} - -VOID UpdaterDestroyHash( - _Inout_ PUPDATER_HASH_CONTEXT Context - ) -{ - if (Context->HashAlgHandle) - BCryptCloseAlgorithmProvider(Context->HashAlgHandle, 0); - - if (Context->SignAlgHandle) - BCryptCloseAlgorithmProvider(Context->SignAlgHandle, 0); - - if (Context->HashHandle) - BCryptDestroyHash(Context->HashHandle); - - if (Context->KeyHandle) - BCryptDestroyKey(Context->KeyHandle); - - if (Context->HashObject) - PhFree(Context->HashObject); - - if (Context->Hash) - PhFree(Context->Hash); - - PhFree(Context); -} \ No newline at end of file diff --git a/plugins/ExtraPlugins/wndtree.c b/plugins/ExtraPlugins/wndtree.c deleted file mode 100644 index 5c9858fd1b49..000000000000 --- a/plugins/ExtraPlugins/wndtree.c +++ /dev/null @@ -1,461 +0,0 @@ -/* - * Process Hacker Extra Plugins - - * Plugin Manager - * - * Copyright (C) 2016-2017 dmex - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include "main.h" - -BOOLEAN PluginsNodeHashtableCompareFunction( - _In_ PVOID Entry1, - _In_ PVOID Entry2 - ); -ULONG PluginsNodeHashtableHashFunction( - _In_ PVOID Entry - ); -VOID DestroyPluginsNode( - _In_ PPLUGIN_NODE Node - ); - -VOID DeletePluginsTree( - _In_ PWCT_CONTEXT Context - ) -{ - PPH_STRING settings = PhCmSaveSettings(Context->TreeNewHandle); - PhSetStringSetting2(SETTING_NAME_TREE_LIST_COLUMNS, &settings->sr); - PhDereferenceObject(settings); - - for (ULONG i = 0; i < Context->NodeList->Count; i++) - { - DestroyPluginsNode(Context->NodeList->Items[i]); - } - - PhDereferenceObject(Context->NodeHashtable); - PhDereferenceObject(Context->NodeList); -} - -struct _PH_TN_FILTER_SUPPORT* GetPluginListFilterSupport( - _In_ PWCT_CONTEXT Context - ) -{ - return &Context->FilterSupport; -} - -BOOLEAN PluginsNodeHashtableCompareFunction( - _In_ PVOID Entry1, - _In_ PVOID Entry2 - ) -{ - PPLUGIN_NODE windowNode1 = *(PPLUGIN_NODE *)Entry1; - PPLUGIN_NODE windowNode2 = *(PPLUGIN_NODE *)Entry2; - - return PhEqualString(windowNode1->InternalName, windowNode2->InternalName, TRUE); -} - -ULONG PluginsNodeHashtableHashFunction( - _In_ PVOID Entry - ) -{ - return PhHashStringRef(&(*(PPLUGIN_NODE*)Entry)->InternalName->sr, TRUE); -} - -VOID PluginsAddTreeNode( - _In_ PWCT_CONTEXT Context, - _In_ PPLUGIN_NODE Entry - ) -{ - PhInitializeTreeNewNode(&Entry->Node); - - memset(Entry->TextCache, 0, sizeof(PH_STRINGREF) * TREE_COLUMN_ITEM_MAXIMUM); - Entry->Node.TextCache = Entry->TextCache; - Entry->Node.TextCacheSize = TREE_COLUMN_ITEM_MAXIMUM; - - PhAddEntryHashtable(Context->NodeHashtable, &Entry); - PhAddItemList(Context->NodeList, Entry); - - if (Context->FilterSupport.NodeList) - { - Entry->Node.Visible = PhApplyTreeNewFiltersToNode(&Context->FilterSupport, &Entry->Node); - } -} - -PPLUGIN_NODE FindTreeNode( - _In_ PWCT_CONTEXT Context, - _In_ TREE_PLUGIN_STATE State, - _In_ PPH_STRING InternalName - ) -{ - for (ULONG i = 0; i < Context->NodeList->Count; i++) - { - PPLUGIN_NODE entry = Context->NodeList->Items[i]; - - if (entry->State == State && PhEqualString(entry->InternalName, InternalName, TRUE)) - return entry; - } - - return NULL; -} - -VOID WeRemoveWindowNode( - _In_ PWCT_CONTEXT Context, - _In_ PPLUGIN_NODE WindowNode - ) -{ - ULONG index = 0; - - // Remove from hashtable/list and cleanup. - PhRemoveEntryHashtable(Context->NodeHashtable, &WindowNode); - - if ((index = PhFindItemList(Context->NodeList, WindowNode)) != -1) - { - PhRemoveItemList(Context->NodeList, index); - } - - DestroyPluginsNode(WindowNode); -} - -VOID DestroyPluginsNode( - _In_ PPLUGIN_NODE WindowNode - ) -{ - PhDereferenceObject(WindowNode); -} - -#define SORT_FUNCTION(Column) PmPoolTreeNewCompare##Column -#define BEGIN_SORT_FUNCTION(Column) static int __cdecl PmPoolTreeNewCompare##Column( \ - _In_ void *_context, \ - _In_ const void *_elem1, \ - _In_ const void *_elem2 \ - ) \ -{ \ - PPLUGIN_NODE node1 = *(PPLUGIN_NODE *)_elem1; \ - PPLUGIN_NODE node2 = *(PPLUGIN_NODE *)_elem2; \ - int sortResult = 0; - -#define END_SORT_FUNCTION \ - if (sortResult == 0) \ - sortResult = uintptrcmp((ULONG_PTR)node1->Node.Index, (ULONG_PTR)node2->Node.Index); \ - \ - return PhModifySort(sortResult, ((PWCT_CONTEXT)_context)->TreeNewSortOrder); \ -} - -BEGIN_SORT_FUNCTION(Name) -{ - sortResult = PhCompareString(node1->Name, node2->Name, FALSE); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(Author) -{ - sortResult = PhCompareString(node1->Author, node2->Author, FALSE); -} -END_SORT_FUNCTION - -BEGIN_SORT_FUNCTION(Version) -{ - sortResult = PhCompareString(node1->Version, node2->Version, FALSE); -} -END_SORT_FUNCTION - -BOOLEAN NTAPI PluginsTreeNewCallback( - _In_ HWND hwnd, - _In_ PH_TREENEW_MESSAGE Message, - __in_opt PVOID Parameter1, - __in_opt PVOID Parameter2, - __in_opt PVOID Context - ) -{ - PWCT_CONTEXT context; - PPLUGIN_NODE node; - - context = Context; - - switch (Message) - { - case TreeNewGetChildren: - { - PPH_TREENEW_GET_CHILDREN getChildren = Parameter1; - node = (PPLUGIN_NODE)getChildren->Node; - - if (!getChildren->Node) - { - static PVOID sortFunctions[] = - { - SORT_FUNCTION(Name), - SORT_FUNCTION(Author), - SORT_FUNCTION(Version) - }; - int (__cdecl *sortFunction)(void *, const void *, const void *); - - if (context->TreeNewSortColumn < TREE_COLUMN_ITEM_MAXIMUM) - sortFunction = sortFunctions[context->TreeNewSortColumn]; - else - sortFunction = NULL; - - if (sortFunction) - { - qsort_s(context->NodeList->Items, context->NodeList->Count, sizeof(PVOID), sortFunction, context); - } - - getChildren->Children = (PPH_TREENEW_NODE *)context->NodeList->Items; - getChildren->NumberOfChildren = context->NodeList->Count; - } - } - return TRUE; - case TreeNewIsLeaf: - { - PPH_TREENEW_IS_LEAF isLeaf = (PPH_TREENEW_IS_LEAF)Parameter1; - node = (PPLUGIN_NODE)isLeaf->Node; - - isLeaf->IsLeaf = TRUE; - } - return TRUE; - case TreeNewGetCellText: - { - PPH_TREENEW_GET_CELL_TEXT getCellText = (PPH_TREENEW_GET_CELL_TEXT)Parameter1; - node = (PPLUGIN_NODE)getCellText->Node; - - switch (getCellText->Id) - { - case TREE_COLUMN_ITEM_NAME: - getCellText->Text = PhGetStringRef(node->Name); - break; - case TREE_COLUMN_ITEM_AUTHOR: - getCellText->Text = PhGetStringRef(node->Author); - break; - case TREE_COLUMN_ITEM_VERSION: - getCellText->Text = PhGetStringRef(node->Version); - break; - default: - return FALSE; - } - - getCellText->Flags = TN_CACHE; - } - return TRUE; - case TreeNewGetNodeColor: - { - PPH_TREENEW_GET_NODE_COLOR getNodeColor = (PPH_TREENEW_GET_NODE_COLOR)Parameter1; - node = (PPLUGIN_NODE)getNodeColor->Node; - - getNodeColor->Flags = TN_CACHE | TN_AUTO_FORECOLOR; - } - return TRUE; - case TreeNewSortChanged: - { - TreeNew_GetSort(hwnd, &context->TreeNewSortColumn, &context->TreeNewSortOrder); - TreeNew_NodesStructured(hwnd); - } - return TRUE; - case TreeNewKeyDown: - case TreeNewNodeExpanding: - return TRUE; - case TreeNewLeftDoubleClick: - { - SendMessage(context->ParentWindowHandle, WM_COMMAND, WM_ACTION, (LPARAM)context); - } - return TRUE; - case TreeNewContextMenu: - { - PPH_TREENEW_CONTEXT_MENU contextMenuEvent = Parameter1; - - SendMessage(context->ParentWindowHandle, WM_COMMAND, ID_WCTSHOWCONTEXTMENU, (LPARAM)contextMenuEvent); - } - return TRUE; - case TreeNewHeaderRightClick: - { - PH_TN_COLUMN_MENU_DATA data; - - data.TreeNewHandle = hwnd; - data.MouseEvent = Parameter1; - data.DefaultSortColumn = 0; - data.DefaultSortOrder = AscendingSortOrder; - PhInitializeTreeNewColumnMenu(&data); - - data.Selection = PhShowEMenu(data.Menu, hwnd, PH_EMENU_SHOW_LEFTRIGHT, - PH_ALIGN_LEFT | PH_ALIGN_TOP, data.MouseEvent->ScreenLocation.x, data.MouseEvent->ScreenLocation.y); - PhHandleTreeNewColumnMenu(&data); - PhDeleteTreeNewColumnMenu(&data); - } - return TRUE; - case TreeNewCustomDraw: - { - PPH_TREENEW_CUSTOM_DRAW customDraw = Parameter1; - RECT rect = customDraw->CellRect; - node = (PPLUGIN_NODE)customDraw->Node; - - switch (customDraw->Column->Id) - { - case TREE_COLUMN_ITEM_NAME: - { - PH_STRINGREF text; - SIZE nameSize; - SIZE textSize; - SIZE imageSize; - - imageSize.cx = PH_SCALE_DPI(17); - imageSize.cy = PH_SCALE_DPI(17); - - if (node->PluginOptions) - { - if (!node->Icon) - { - HBITMAP bitmapActive; - - if (bitmapActive = PhLoadPngImageFromResource(PluginInstance->DllBase, imageSize.cx, imageSize.cy, MAKEINTRESOURCE(IDB_SETTINGS_PNG), TRUE)) - { - node->Icon = CommonBitmapToIcon(bitmapActive, imageSize.cx, imageSize.cy); - DeleteObject(bitmapActive); - } - } - - if (node->Icon) - { - DrawIconEx( - customDraw->Dc, - rect.left + PH_SCALE_DPI(5), - rect.top + ((rect.bottom - rect.top) - imageSize.cy) / 2, - node->Icon, - imageSize.cx, - imageSize.cy, - 0, - NULL, - DI_NORMAL - ); - } - } - - rect.left += PH_SCALE_DPI(27); - rect.top += PH_SCALE_DPI(5); - rect.right -= PH_SCALE_DPI(5); - rect.bottom -= PH_SCALE_DPI(8); - - // top - SetTextColor(customDraw->Dc, RGB(0x0, 0x0, 0x0)); - SelectObject(customDraw->Dc, context->TitleFontHandle); - text = PhIsNullOrEmptyString(node->Name) ? PhGetStringRef(node->InternalName) : PhGetStringRef(node->Name); - GetTextExtentPoint32(customDraw->Dc, text.Buffer, (ULONG)text.Length / 2, &nameSize); - DrawText(customDraw->Dc, text.Buffer, (ULONG)text.Length / 2, &rect, DT_TOP | DT_LEFT | DT_END_ELLIPSIS | DT_SINGLELINE); - - // bottom - SetTextColor(customDraw->Dc, RGB(0x64, 0x64, 0x64)); - SelectObject(customDraw->Dc, context->NormalFontHandle); - text = PhGetStringRef(node->Description); - GetTextExtentPoint32(customDraw->Dc, text.Buffer, (ULONG)text.Length / 2, &textSize); - DrawText( - customDraw->Dc, - text.Buffer, - (ULONG)text.Length / 2, - &rect, - DT_BOTTOM | DT_LEFT | DT_END_ELLIPSIS | DT_SINGLELINE - ); - } - break; - } - } - return TRUE; - } - - return FALSE; -} - -VOID PluginsClearTree( - _In_ PWCT_CONTEXT Context - ) -{ - for (ULONG i = 0; i < Context->NodeList->Count; i++) - DestroyPluginsNode(Context->NodeList->Items[i]); - - PhClearHashtable(Context->NodeHashtable); - PhClearList(Context->NodeList); -} - -PPLUGIN_NODE WeGetSelectedWindowNode( - _In_ PWCT_CONTEXT Context - ) -{ - for (ULONG i = 0; i < Context->NodeList->Count; i++) - { - PPLUGIN_NODE windowNode = Context->NodeList->Items[i]; - - if (windowNode->Node.Selected) - return windowNode; - } - - return NULL; -} - -VOID WeGetSelectedWindowNodes( - _In_ PWCT_CONTEXT Context, - __out PPLUGIN_NODE **Windows, - __out PULONG NumberOfWindows - ) -{ - PPH_LIST list = PhCreateList(2); - - for (ULONG i = 0; i < Context->NodeList->Count; i++) - { - PPLUGIN_NODE node = (PPLUGIN_NODE)Context->NodeList->Items[i]; - - if (node->Node.Selected) - PhAddItemList(list, node); - } - - *Windows = PhAllocateCopy(list->Items, sizeof(PVOID) * list->Count); - *NumberOfWindows = list->Count; - - PhDereferenceObject(list); -} - -VOID InitializePluginsTree( - _In_ PWCT_CONTEXT Context, - _In_ HWND ParentWindowHandle, - _In_ HWND TreeNewHandle - ) -{ - Context->NodeHashtable = PhCreateHashtable( - sizeof(PPLUGIN_NODE), - PluginsNodeHashtableCompareFunction, - PluginsNodeHashtableHashFunction, - 100 - ); - Context->NodeList = PhCreateList(100); - - Context->ParentWindowHandle = ParentWindowHandle; - Context->TreeNewHandle = TreeNewHandle; - PhSetControlTheme(TreeNewHandle, L"explorer"); - - Context->NormalFontHandle = PhCreateCommonFont(-10, FW_NORMAL, NULL); - Context->TitleFontHandle = PhCreateCommonFont(-14, FW_BOLD, NULL); - - TreeNew_SetCallback(TreeNewHandle, PluginsTreeNewCallback, Context); - TreeNew_SetRowHeight(TreeNewHandle, PH_SCALE_DPI(48)); - - PhAddTreeNewColumnEx2(TreeNewHandle, TREE_COLUMN_ITEM_NAME, TRUE, L"Plugin", 80, PH_ALIGN_LEFT, TREE_COLUMN_ITEM_NAME, 0, TN_COLUMN_FLAG_CUSTOMDRAW); - PhAddTreeNewColumnEx2(TreeNewHandle, TREE_COLUMN_ITEM_AUTHOR, TRUE, L"Author", 80, PH_ALIGN_LEFT, TREE_COLUMN_ITEM_AUTHOR, 0, 0); - PhAddTreeNewColumnEx2(TreeNewHandle, TREE_COLUMN_ITEM_VERSION, TRUE, L"Version", 80, PH_ALIGN_CENTER, TREE_COLUMN_ITEM_VERSION, DT_CENTER, 0); - - TreeNew_SetSort(TreeNewHandle, 0, NoSortOrder); - - PPH_STRING settings = PhGetStringSetting(SETTING_NAME_TREE_LIST_COLUMNS); - PhCmLoadSettings(TreeNewHandle, &settings->sr); - PhDereferenceObject(settings); - - PhInitializeTreeNewFilterSupport(&Context->FilterSupport, TreeNewHandle, Context->NodeList); -} \ No newline at end of file From cd68b46a757a3260410d81e1835a4ceaba726a9a Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 2 Nov 2017 23:44:00 +1100 Subject: [PATCH 0541/2058] Add CommonUtil --- plugins/CommonUtil/CommonUtil.vcxitems | 23 ++ plugins/CommonUtil/http.c | 495 +++++++++++++++++++++++++ plugins/CommonUtil/http.h | 167 +++++++++ plugins/Plugins.sln | 21 +- 4 files changed, 696 insertions(+), 10 deletions(-) create mode 100644 plugins/CommonUtil/CommonUtil.vcxitems create mode 100644 plugins/CommonUtil/http.c create mode 100644 plugins/CommonUtil/http.h diff --git a/plugins/CommonUtil/CommonUtil.vcxitems b/plugins/CommonUtil/CommonUtil.vcxitems new file mode 100644 index 000000000000..9ff58474fb3e --- /dev/null +++ b/plugins/CommonUtil/CommonUtil.vcxitems @@ -0,0 +1,23 @@ + + + + $(MSBuildAllProjects);$(MSBuildThisFileFullPath) + true + {bfaabf4a-4b1b-4b28-b6cb-b55ab6c1109f} + CommonUtil + + + + %(AdditionalIncludeDirectories);$(MSBuildThisFileDirectory) + + + + + + + + + + + + \ No newline at end of file diff --git a/plugins/CommonUtil/http.c b/plugins/CommonUtil/http.c new file mode 100644 index 000000000000..e909ae5605c1 --- /dev/null +++ b/plugins/CommonUtil/http.c @@ -0,0 +1,495 @@ +/* + * Process Hacker - + * http socket wrapper + * + * Copyright (C) 2017 dmex + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +// dmex: This wrapper is utilizing a shared project until stable enough for inclusion with the base program. + +#include +#include +#include +#include + +static const PH_FLAG_MAPPING PhpHttpRequestFlagMappings[] = +{ + { PH_HTTP_FLAG_SECURE, WINHTTP_FLAG_SECURE }, + { PH_HTTP_FLAG_REFRESH, WINHTTP_FLAG_REFRESH } +}; + +static const PH_FLAG_MAPPING PhpHttpHeaderQueryMappings[] = +{ + { PH_HTTP_QUERY_CONTENT_LENGTH, WINHTTP_QUERY_CONTENT_LENGTH }, + { PH_HTTP_QUERY_STATUS_CODE, WINHTTP_QUERY_STATUS_CODE }, +}; + +static const PH_FLAG_MAPPING PhpHttpFeatureMappings[] = +{ + { PH_HTTP_FEATURE_REDIRECTS, WINHTTP_DISABLE_REDIRECTS }, + { PH_HTTP_FEATURE_KEEP_ALIVE, WINHTTP_DISABLE_KEEP_ALIVE }, +}; + +BOOLEAN PhHttpSocketCreate( + _Out_ PPH_HTTP_CONTEXT *HttpContext, + _In_opt_ PWSTR HttpUserAgent + ) +{ + PPH_HTTP_CONTEXT httpContext; + + httpContext = PhAllocate(sizeof(PH_HTTP_CONTEXT)); + memset(httpContext, 0, sizeof(PH_HTTP_CONTEXT)); + + httpContext->SessionHandle = WinHttpOpen( + HttpUserAgent, + WindowsVersion >= WINDOWS_8_1 ? WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY : WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, + WINHTTP_NO_PROXY_NAME, + WINHTTP_NO_PROXY_BYPASS, + 0 + ); + + if (!httpContext->SessionHandle) + { + PhFree(httpContext); + return FALSE; + } + + if (WindowsVersion >= WINDOWS_8_1) + { + WinHttpSetOption( + httpContext->SessionHandle, + WINHTTP_OPTION_DECOMPRESSION, + &(ULONG){ WINHTTP_DECOMPRESSION_FLAG_GZIP | WINHTTP_DECOMPRESSION_FLAG_DEFLATE }, + sizeof(ULONG) + ); + } + + *HttpContext = httpContext; + + return TRUE; +} + +VOID PhHttpSocketDestroy( + _Frees_ptr_opt_ PPH_HTTP_CONTEXT HttpContext + ) +{ + if (HttpContext->RequestHandle) + WinHttpCloseHandle(HttpContext->RequestHandle); + + if (HttpContext->ConnectionHandle) + WinHttpCloseHandle(HttpContext->ConnectionHandle); + + if (HttpContext->SessionHandle) + WinHttpCloseHandle(HttpContext->SessionHandle); + + PhFree(HttpContext); +} + +BOOLEAN PhHttpSocketConnect( + _In_ PPH_HTTP_CONTEXT HttpContext, + _In_ PWSTR ServerName, + _In_ USHORT ServerPort + ) +{ + HttpContext->ConnectionHandle = WinHttpConnect( + HttpContext->SessionHandle, + ServerName, + ServerPort, + 0 + ); + + if (HttpContext->ConnectionHandle) + return TRUE; + else + return FALSE; +} + +BOOLEAN PhHttpSocketBeginRequest( + _In_ PPH_HTTP_CONTEXT HttpContext, + _In_ PWSTR Method, + _In_ PWSTR UrlPath, + _In_ ULONG Flags + ) +{ + ULONG httpFlags = 0; + + PhMapFlags1( + &httpFlags, + Flags, + PhpHttpRequestFlagMappings, + ARRAYSIZE(PhpHttpRequestFlagMappings) + ); + + HttpContext->RequestHandle = WinHttpOpenRequest( + HttpContext->ConnectionHandle, + Method, + UrlPath, + NULL, + WINHTTP_NO_REFERER, + WINHTTP_DEFAULT_ACCEPT_TYPES, + httpFlags + ); + + if (!HttpContext->RequestHandle) + return FALSE; + + WinHttpSetOption( + HttpContext->RequestHandle, + WINHTTP_OPTION_DISABLE_FEATURE, + &(ULONG){ WINHTTP_DISABLE_KEEP_ALIVE }, + sizeof(ULONG) + ); + + return TRUE; +} + +BOOLEAN PhHttpSocketSendRequest( + _In_ PPH_HTTP_CONTEXT HttpContext, + _In_ PVOID RequestData, + _In_ ULONG RequestDataLength + ) +{ + return !!WinHttpSendRequest( + HttpContext->RequestHandle, + WINHTTP_NO_ADDITIONAL_HEADERS, + 0, + RequestData, + RequestDataLength, + RequestDataLength, + 0 + ); +} + +BOOLEAN PhHttpSocketEndRequest( + _In_ PPH_HTTP_CONTEXT HttpContext + ) +{ + return !!WinHttpReceiveResponse(HttpContext->RequestHandle, NULL); +} + +BOOLEAN PhHttpSocketReadData( + _In_ PPH_HTTP_CONTEXT HttpContext, + _In_ PVOID Buffer, + _In_ ULONG BufferLength, + _Out_ PULONG BytesCopied + ) +{ + return !!WinHttpReadData(HttpContext->RequestHandle, Buffer, BufferLength, BytesCopied); +} + +BOOLEAN PhHttpSocketWriteData( + _In_ PPH_HTTP_CONTEXT HttpContext, + _In_ PVOID Buffer, + _In_ ULONG BufferLength, + _Out_ PULONG BytesCopied + ) +{ + return !!WinHttpWriteData(HttpContext->RequestHandle, Buffer, BufferLength, BytesCopied); +} + +BOOLEAN PhHttpSocketAddRequestHeaders( + _In_ PPH_HTTP_CONTEXT HttpContext, + _In_ PWSTR Headers, + _In_opt_ ULONG HeadersLength + ) +{ + return !!WinHttpAddRequestHeaders( + HttpContext->RequestHandle, + Headers, + HeadersLength ? HeadersLength : -1L, + WINHTTP_ADDREQ_FLAG_ADD | WINHTTP_ADDREQ_FLAG_REPLACE + ); +} + +_Check_return_ +_Ret_maybenull_ +PPH_STRING PhHttpSocketQueryHeaderString( + _In_ PPH_HTTP_CONTEXT HttpContext, + _In_ PWSTR HeaderString + ) +{ + ULONG bufferLength = 0; + PPH_STRING stringBuffer; + + if (!WinHttpQueryHeaders( + HttpContext->RequestHandle, + WINHTTP_QUERY_CUSTOM, + HeaderString, + WINHTTP_NO_OUTPUT_BUFFER, + &bufferLength, + WINHTTP_NO_HEADER_INDEX + )) + { + if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) + return NULL; + } + + stringBuffer = PhCreateStringEx(NULL, bufferLength); + + if (!WinHttpQueryHeaders( + HttpContext->RequestHandle, + WINHTTP_QUERY_CUSTOM, + HeaderString, + stringBuffer->Buffer, + &bufferLength, + WINHTTP_NO_HEADER_INDEX + )) + { + PhDereferenceObject(stringBuffer); + return NULL; + } + + return stringBuffer; +} + +BOOLEAN PhHttpSocketQueryHeaderUlong( + _In_ PPH_HTTP_CONTEXT HttpContext, + _In_ ULONG QueryValue, + _Out_ PULONG HeaderValue + ) +{ + ULONG queryFlags = 0; + ULONG headerValue = 0; + ULONG valueLength = sizeof(ULONG); + + PhMapFlags1( + &queryFlags, + QueryValue, + PhpHttpHeaderQueryMappings, + ARRAYSIZE(PhpHttpHeaderQueryMappings) + ); + + if (WinHttpQueryHeaders( + HttpContext->RequestHandle, + queryFlags | WINHTTP_QUERY_FLAG_NUMBER, + WINHTTP_HEADER_NAME_BY_INDEX, + &headerValue, + &valueLength, + WINHTTP_NO_HEADER_INDEX + )) + { + *HeaderValue = headerValue; + return TRUE; + } + + return FALSE; +} + +PVOID PhHttpSocketQueryOption( + _In_ PPH_HTTP_CONTEXT HttpContext, + _In_ BOOLEAN SessionOption, + _In_ ULONG QueryOption + ) +{ + HINTERNET queryHandle; + ULONG bufferLength = 0; + PVOID optionBuffer; + + if (SessionOption) + queryHandle = HttpContext->SessionHandle; + else + queryHandle = HttpContext->RequestHandle; + + if (!WinHttpQueryOption( + queryHandle, + QueryOption, + NULL, + &bufferLength + )) + { + if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) + return NULL; + } + + optionBuffer = PhAllocate(bufferLength); + memset(optionBuffer, 0, bufferLength); + + if (!WinHttpQueryOption( + queryHandle, + QueryOption, + optionBuffer, + &bufferLength + )) + { + PhFree(optionBuffer); + return NULL; + } + + return optionBuffer; +} + +_Check_return_ +_Ret_maybenull_ +PPH_STRING PhHttpSocketQueryOptionString( + _In_ PPH_HTTP_CONTEXT HttpContext, + _In_ BOOLEAN SessionOption, + _In_ ULONG QueryOption + ) +{ + PVOID optionBuffer; + PPH_STRING stringBuffer = NULL; + + optionBuffer = PhHttpSocketQueryOption( + HttpContext, + SessionOption, + QueryOption + ); + + if (optionBuffer) + { + stringBuffer = PhCreateString(optionBuffer); // FIXME + PhFree(optionBuffer); + } + + return stringBuffer; +} + +PVOID PhHttpSocketDownloadString( + _In_ PPH_HTTP_CONTEXT HttpContext, + _In_ BOOLEAN Unicode + ) +{ + PSTR data = NULL; + PVOID result = NULL; + ULONG allocatedLength; + ULONG dataLength; + ULONG returnLength; + BYTE buffer[PAGE_SIZE]; + + allocatedLength = sizeof(buffer); + data = (PSTR)PhAllocate(allocatedLength); + dataLength = 0; + + while (WinHttpReadData(HttpContext->RequestHandle, buffer, PAGE_SIZE, &returnLength)) + { + if (returnLength == 0) + break; + + if (allocatedLength < dataLength + returnLength) + { + allocatedLength *= 2; + data = (PSTR)PhReAllocate(data, allocatedLength); + } + + memcpy(data + dataLength, buffer, returnLength); + + dataLength += returnLength; + } + + if (allocatedLength < dataLength + 1) + { + allocatedLength++; + data = (PSTR)PhReAllocate(data, allocatedLength); + } + + // Ensure that the buffer is null-terminated. + data[dataLength] = 0; + + if (Unicode) + result = PhConvertUtf8ToUtf16Ex(data, dataLength); + else + result = PhCreateBytesEx(data, dataLength); + + PhFree(data); + + return result; +} + +BOOLEAN PhHttpSocketSetFeature( + _In_ PPH_HTTP_CONTEXT HttpContext, + _In_ ULONG Feature, + _In_ BOOLEAN Enable + ) +{ + ULONG featureValue = 0; + + PhMapFlags1( + &featureValue, + Feature, + PhpHttpFeatureMappings, + ARRAYSIZE(PhpHttpFeatureMappings) + ); + + return !!WinHttpSetOption( + HttpContext->RequestHandle, + Enable ? WINHTTP_OPTION_ENABLE_FEATURE : WINHTTP_OPTION_DISABLE_FEATURE, + &featureValue, + sizeof(ULONG) + ); +} + + +BOOLEAN PhHttpSocketParseUrl( + _In_ PPH_STRING Url, + _Out_opt_ PPH_STRING *HostPart, + _Out_opt_ PPH_STRING *PathPart, + _Out_opt_ PUSHORT PortPart + ) +{ + URL_COMPONENTS httpParts; + + memset(&httpParts, 0, sizeof(URL_COMPONENTS)); + httpParts.dwStructSize = sizeof(URL_COMPONENTS); + httpParts.dwHostNameLength = ULONG_MAX; + httpParts.dwUrlPathLength = ULONG_MAX; + + if (!WinHttpCrackUrl( + Url->Buffer, + (ULONG)Url->Length / sizeof(WCHAR), + 0, + &httpParts + )) + { + return FALSE; + } + + if (HostPart && httpParts.dwHostNameLength) + *HostPart = PhCreateStringEx(httpParts.lpszHostName, httpParts.dwHostNameLength * sizeof(WCHAR)); + + if (PathPart && httpParts.dwUrlPathLength) + *PathPart = PhCreateStringEx(httpParts.lpszUrlPath, httpParts.dwUrlPathLength * sizeof(WCHAR)); + + if (PortPart) + *PortPart = httpParts.nPort; + + return TRUE; +} + +_Check_return_ +_Ret_maybenull_ +PPH_STRING PhHttpSocketGetErrorMessage( + _In_ ULONG ErrorCode + ) +{ + PPH_STRING message = NULL; + + if (message = PhGetMessage(PhGetDllHandle(L"winhttp.dll"), 0xb, GetUserDefaultLangID(), ErrorCode)) + { + PhTrimToNullTerminatorString(message); + } + + // Remove any trailing newline + if (message && message->Length >= 2 * sizeof(WCHAR) && + message->Buffer[message->Length / sizeof(WCHAR) - 2] == '\r' && + message->Buffer[message->Length / sizeof(WCHAR) - 1] == '\n') + { + PhMoveReference(&message, PhCreateStringEx(message->Buffer, message->Length - 2 * sizeof(WCHAR))); + } + + return message; +} \ No newline at end of file diff --git a/plugins/CommonUtil/http.h b/plugins/CommonUtil/http.h new file mode 100644 index 000000000000..5636f4f1523d --- /dev/null +++ b/plugins/CommonUtil/http.h @@ -0,0 +1,167 @@ +#ifndef _PH_NETIO_H +#define _PH_NETIO_H + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct _PH_HTTP_CONTEXT +{ + PVOID SessionHandle; + PVOID ConnectionHandle; + PVOID RequestHandle; +} PH_HTTP_CONTEXT, *PPH_HTTP_CONTEXT; + +BOOLEAN +NTAPI +PhHttpSocketCreate( + _Out_ PPH_HTTP_CONTEXT *HttpContext, + _In_opt_ PWSTR HttpUserAgent + ); + +VOID +NTAPI +PhHttpSocketDestroy( + _Frees_ptr_opt_ PPH_HTTP_CONTEXT HttpContext + ); + +#define PH_HTTP_DEFAULT_PORT 0 // use the protocol-specific default +#define PH_HTTP_DEFAULT_HTTP_PORT 80 +#define PH_HTTP_DEFAULT_HTTPS_PORT 443 + +BOOLEAN +NTAPI +PhHttpSocketConnect( + _In_ PPH_HTTP_CONTEXT HttpContext, + _In_ PWSTR ServerName, + _In_ USHORT ServerPort + ); + +#define PH_HTTP_FLAG_SECURE 0x1 +#define PH_HTTP_FLAG_REFRESH 0x2 + +BOOLEAN +NTAPI +PhHttpSocketBeginRequest( + _In_ PPH_HTTP_CONTEXT HttpContext, + _In_ PWSTR Method, + _In_ PWSTR UrlPath, + _In_ ULONG Flags + ); + +BOOLEAN +NTAPI +PhHttpSocketSendRequest( + _In_ PPH_HTTP_CONTEXT HttpContext, + _In_ PVOID RequestData, + _In_ ULONG RequestDataLength + ); + +BOOLEAN +NTAPI +PhHttpSocketEndRequest( + _In_ PPH_HTTP_CONTEXT HttpContext + ); + +BOOLEAN +NTAPI +PhHttpSocketReadData( + _In_ PPH_HTTP_CONTEXT HttpContext, + _In_ PVOID Buffer, + _In_ ULONG BufferLength, + _Out_ PULONG BytesCopied + ); + +BOOLEAN +NTAPI +PhHttpSocketWriteData( + _In_ PPH_HTTP_CONTEXT HttpContext, + _In_ PVOID Buffer, + _In_ ULONG BufferLength, + _Out_ PULONG BytesCopied + ); + +BOOLEAN +NTAPI +PhHttpSocketAddRequestHeaders( + _In_ PPH_HTTP_CONTEXT HttpContext, + _In_ PWSTR Headers, + _In_opt_ ULONG HeadersLength + ); + +_Check_return_ +_Ret_maybenull_ +PPH_STRING +NTAPI +PhHttpSocketQueryHeaderString( + _In_ PPH_HTTP_CONTEXT HttpContext, + _In_ PWSTR HeaderString + ); + +// status codes +#define PH_HTTP_STATUS_OK 200 // request completed +#define PH_HTTP_STATUS_REDIRECT_METHOD 303 // redirection w/ new access method +#define PH_HTTP_STATUS_REDIRECT 302 // object temporarily moved + +// header query flags +#define PH_HTTP_QUERY_CONTENT_LENGTH 0x1 +#define PH_HTTP_QUERY_STATUS_CODE 0x2 + +BOOLEAN +NTAPI +PhHttpSocketQueryHeaderUlong( + _In_ PPH_HTTP_CONTEXT HttpContext, + _In_ ULONG QueryValue, + _Out_ PULONG HeaderValue + ); + +_Check_return_ +_Ret_maybenull_ +PPH_STRING +NTAPI +PhHttpSocketQueryOptionString( + _In_ PPH_HTTP_CONTEXT HttpContext, + _In_ BOOLEAN SessionOption, + _In_ ULONG QueryOption + ); + +PVOID +NTAPI +PhHttpSocketDownloadString( + _In_ PPH_HTTP_CONTEXT HttpContext, + _In_ BOOLEAN Unicode + ); + +#define PH_HTTP_FEATURE_REDIRECTS 0x1 +#define PH_HTTP_FEATURE_KEEP_ALIVE 0x2 + +BOOLEAN +NTAPI +PhHttpSocketSetFeature( + _In_ PPH_HTTP_CONTEXT HttpContext, + _In_ ULONG Feature, + _In_ BOOLEAN Enable + ); + +BOOLEAN +NTAPI +PhHttpSocketParseUrl( + _In_ PPH_STRING Url, + _Out_opt_ PPH_STRING *Host, + _Out_opt_ PPH_STRING *Path, + _Out_opt_ PUSHORT Port + ); + +_Check_return_ +_Ret_maybenull_ +PPH_STRING +NTAPI +PhHttpSocketGetErrorMessage( + _In_ ULONG ErrorCode + ); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/plugins/Plugins.sln b/plugins/Plugins.sln index 87cbceb668f5..6dd3d8b25eff 100644 --- a/plugins/Plugins.sln +++ b/plugins/Plugins.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 -VisualStudioVersion = 15.0.26430.16 +VisualStudioVersion = 15.0.27004.2006 MinimumVisualStudioVersion = 15.0.26228.4 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{53C3AE07-D96F-4F5C-B407-4195084472CF}" ProjectSection(SolutionItems) = preProject @@ -32,9 +32,15 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UserNotes", "UserNotes\User EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "HardwareDevices", "HardwareDevices\HardwareDevices.vcxproj", "{5F0D72C4-8319-4B61-9E13-6084B680EB90}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ExtraPlugins", "ExtraPlugins\ExtraPlugins.vcxproj", "{96549A3E-D1BD-470E-A5B3-A64803C4DEF5}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CommonUtil", "CommonUtil\CommonUtil.vcxitems", "{BFAABF4A-4B1B-4B28-B6CB-B55AB6C1109F}" EndProject Global + GlobalSection(SharedMSBuildProjectFiles) = preSolution + CommonUtil\CommonUtil.vcxitems*{79d24223-1122-40a9-bc8f-46a2089fe089}*SharedItemsImports = 4 + CommonUtil\CommonUtil.vcxitems*{a0c1595c-fa3e-4b7a-936c-306bc6294c5e}*SharedItemsImports = 4 + CommonUtil\CommonUtil.vcxitems*{b5e0da09-ea01-4d5a-a9d6-5b22db0c306e}*SharedItemsImports = 4 + CommonUtil\CommonUtil.vcxitems*{bfaabf4a-4b1b-4b28-b6cb-b55ab6c1109f}*SharedItemsImports = 9 + EndGlobalSection GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 Debug|x64 = Debug|x64 @@ -130,16 +136,11 @@ Global {5F0D72C4-8319-4B61-9E13-6084B680EB90}.Release|Win32.Build.0 = Release|Win32 {5F0D72C4-8319-4B61-9E13-6084B680EB90}.Release|x64.ActiveCfg = Release|x64 {5F0D72C4-8319-4B61-9E13-6084B680EB90}.Release|x64.Build.0 = Release|x64 - {96549A3E-D1BD-470E-A5B3-A64803C4DEF5}.Debug|Win32.ActiveCfg = Debug|Win32 - {96549A3E-D1BD-470E-A5B3-A64803C4DEF5}.Debug|Win32.Build.0 = Debug|Win32 - {96549A3E-D1BD-470E-A5B3-A64803C4DEF5}.Debug|x64.ActiveCfg = Debug|x64 - {96549A3E-D1BD-470E-A5B3-A64803C4DEF5}.Debug|x64.Build.0 = Debug|x64 - {96549A3E-D1BD-470E-A5B3-A64803C4DEF5}.Release|Win32.ActiveCfg = Release|Win32 - {96549A3E-D1BD-470E-A5B3-A64803C4DEF5}.Release|Win32.Build.0 = Release|Win32 - {96549A3E-D1BD-470E-A5B3-A64803C4DEF5}.Release|x64.ActiveCfg = Release|x64 - {96549A3E-D1BD-470E-A5B3-A64803C4DEF5}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {F936C56D-6A19-47EB-973F-535DF252210E} + EndGlobalSection EndGlobal From 7c92c16d9e93686e3d07fffd62157ff7d9daf316 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 3 Nov 2017 01:59:53 +1100 Subject: [PATCH 0542/2058] Updater: Use http wrapper --- plugins/Updater/Updater.vcxproj | 3 + plugins/Updater/page5.c | 24 +-- plugins/Updater/updater.c | 354 +++++++------------------------- plugins/Updater/updater.h | 7 +- 4 files changed, 89 insertions(+), 299 deletions(-) diff --git a/plugins/Updater/Updater.vcxproj b/plugins/Updater/Updater.vcxproj index 1bb143343361..a906bc3ca17c 100644 --- a/plugins/Updater/Updater.vcxproj +++ b/plugins/Updater/Updater.vcxproj @@ -47,6 +47,9 @@ v141 + + + diff --git a/plugins/Updater/page5.c b/plugins/Updater/page5.c index aac9d196786f..3cf00b67ff49 100644 --- a/plugins/Updater/page5.c +++ b/plugins/Updater/page5.c @@ -213,7 +213,7 @@ VOID ShowUpdateFailedDialog( config.hMainIcon = Context->IconLargeHandle; config.pszWindowTitle = L"Process Hacker - Updater"; - config.pszMainInstruction = L"Error downloading the update"; + config.pszMainInstruction = L"Error downloading the update."; if (SignatureFailed) { @@ -227,22 +227,12 @@ VOID ShowUpdateFailedDialog( { if (Context->ErrorCode) { - PPH_STRING message; - - message = PhGetMessage( - GetModuleHandle(L"winhttp.dll"), - 0xb, - GetUserDefaultLangID(), - Context->ErrorCode - ); - - //if (PhIsNullOrEmptyString(message)) - // PhMoveReference(&message, PhGetNtMessage(Context->ErrorCode)); - - if (message) - { - config.pszContent = PhaFormatString(L"[%lu] %s", Context->ErrorCode, message->Buffer)->Buffer; - PhDereferenceObject(message); + PPH_STRING errorMessage; + + if (errorMessage = PhHttpSocketGetErrorMessage(Context->ErrorCode)) + { + config.pszContent = PhaFormatString(L"[%lu] %s", Context->ErrorCode, errorMessage->Buffer)->Buffer; + PhDereferenceObject(errorMessage); } else { diff --git a/plugins/Updater/updater.c b/plugins/Updater/updater.c index ea940d5b0030..6e593160c14f 100644 --- a/plugins/Updater/updater.c +++ b/plugins/Updater/updater.c @@ -2,7 +2,7 @@ * Process Hacker Plugins - * Update Checker Plugin * - * Copyright (C) 2011-2016 dmex + * Copyright (C) 2011-2017 dmex * * This file is part of Process Hacker. * @@ -21,8 +21,6 @@ */ #include "updater.h" -#include -#include HWND UpdateDialogHandle = NULL; HANDLE UpdateDialogThreadHandle = NULL; @@ -87,18 +85,6 @@ VOID TaskDialogLinkClicked( } } -PPH_STRING UpdaterGetOpaqueXmlNodeText( - _In_ mxml_node_t *xmlNode - ) -{ - if (xmlNode && xmlNode->child && xmlNode->child->type == MXML_OPAQUE && xmlNode->child->value.opaque) - { - return PhConvertUtf8ToUtf16(xmlNode->child->value.opaque); - } - - return PhReferenceEmptyString(); -} - BOOLEAN UpdaterInstalledUsingSetup( VOID ) @@ -248,174 +234,78 @@ ULONG64 ParseVersionString( ); } -BOOLEAN ReadRequestString( - _In_ HINTERNET Handle, - _Out_ _Deref_post_z_cap_(*DataLength) PSTR *Data, - _Out_ ULONG *DataLength - ) -{ - PSTR data; - ULONG allocatedLength; - ULONG dataLength; - ULONG returnLength; - BYTE buffer[PAGE_SIZE]; - - allocatedLength = sizeof(buffer); - data = (PSTR)PhAllocate(allocatedLength); - dataLength = 0; - - memset(buffer, 0, PAGE_SIZE); - memset(data, 0, allocatedLength); - - while (WinHttpReadData(Handle, buffer, PAGE_SIZE, &returnLength)) - { - if (returnLength == 0) - break; - - if (allocatedLength < dataLength + returnLength) - { - allocatedLength *= 2; - data = (PSTR)PhReAllocate(data, allocatedLength); - } - - memcpy(data + dataLength, buffer, returnLength); - - dataLength += returnLength; - } - - if (allocatedLength < dataLength + 1) - { - allocatedLength++; - data = (PSTR)PhReAllocate(data, allocatedLength); - } - - data[dataLength] = 0; - - *DataLength = dataLength; - *Data = data; - - return TRUE; -} - BOOLEAN QueryUpdateData( _Inout_ PPH_UPDATER_CONTEXT Context ) { BOOLEAN success = FALSE; - HINTERNET httpSessionHandle = NULL; - HINTERNET httpConnectionHandle = NULL; - HINTERNET httpRequestHandle = NULL; - ULONG stringBufferLength = 0; - PSTR stringBuffer = NULL; + PPH_HTTP_CONTEXT httpContext = NULL; + PPH_BYTES jsonString = NULL; PVOID jsonObject = NULL; - mxml_node_t* xmlNode = NULL; - PPH_STRING versionHeader = UpdateVersionString(); - PPH_STRING windowsHeader = UpdateWindowsString(); - PSTR tempValue = NULL; - - if (!(httpSessionHandle = WinHttpOpen( - NULL, - WindowsVersion >= WINDOWS_8_1 ? WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY : WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, - WINHTTP_NO_PROXY_NAME, - WINHTTP_NO_PROXY_BYPASS, - 0 - ))) + + if (!PhHttpSocketCreate(&httpContext, NULL)) { Context->ErrorCode = GetLastError(); goto CleanupExit; } - if (WindowsVersion >= WINDOWS_8_1) - { - ULONG httpFlags = WINHTTP_DECOMPRESSION_FLAG_GZIP | WINHTTP_DECOMPRESSION_FLAG_DEFLATE; - - WinHttpSetOption( - httpSessionHandle, - WINHTTP_OPTION_DECOMPRESSION, - &httpFlags, - sizeof(ULONG) - ); - } - - if (!(httpConnectionHandle = WinHttpConnect( - httpSessionHandle, - L"wj32.org", - INTERNET_DEFAULT_HTTPS_PORT, - 0 - ))) + if (!PhHttpSocketConnect( + httpContext, + L"wj32.org", + PH_HTTP_DEFAULT_HTTPS_PORT + )) { Context->ErrorCode = GetLastError(); goto CleanupExit; } - if (!(httpRequestHandle = WinHttpOpenRequest( - httpConnectionHandle, - NULL, - L"/processhacker/nightly.php?phupdater", - NULL, - WINHTTP_NO_REFERER, - WINHTTP_DEFAULT_ACCEPT_TYPES, - WINHTTP_FLAG_REFRESH | WINHTTP_FLAG_SECURE - ))) + if (!PhHttpSocketBeginRequest( + httpContext, + NULL, + L"/processhacker/nightly.php?phupdater", + PH_HTTP_FLAG_REFRESH | PH_HTTP_FLAG_SECURE + )) { Context->ErrorCode = GetLastError(); goto CleanupExit; } - - WinHttpSetOption( - httpRequestHandle, - WINHTTP_OPTION_DISABLE_FEATURE, - &(ULONG){ WINHTTP_DISABLE_KEEP_ALIVE }, - sizeof(ULONG) - ); - - if (versionHeader) + { - WinHttpAddRequestHeaders( - httpRequestHandle, - versionHeader->Buffer, - (ULONG)versionHeader->Length / sizeof(WCHAR), - WINHTTP_ADDREQ_FLAG_ADD - ); - } + PPH_STRING versionHeader; + PPH_STRING windowsHeader; - if (windowsHeader) - { - WinHttpAddRequestHeaders( - httpRequestHandle, - windowsHeader->Buffer, - (ULONG)windowsHeader->Length / sizeof(WCHAR), - WINHTTP_ADDREQ_FLAG_ADD - ); + if (versionHeader = UpdateVersionString()) + { + PhHttpSocketAddRequestHeaders(httpContext, versionHeader->Buffer, (ULONG)versionHeader->Length / sizeof(WCHAR)); + PhDereferenceObject(versionHeader); + } + + if (windowsHeader = UpdateWindowsString()) + { + PhHttpSocketAddRequestHeaders(httpContext, windowsHeader->Buffer, (ULONG)windowsHeader->Length / sizeof(WCHAR)); + PhDereferenceObject(windowsHeader); + } } - if (!WinHttpSendRequest( - httpRequestHandle, - WINHTTP_NO_ADDITIONAL_HEADERS, - 0, - WINHTTP_NO_REQUEST_DATA, - 0, - WINHTTP_IGNORE_REQUEST_TOTAL_LENGTH, - 0 - )) + if (!PhHttpSocketSendRequest(httpContext, NULL, 0)) { Context->ErrorCode = GetLastError(); goto CleanupExit; } - if (!WinHttpReceiveResponse(httpRequestHandle, NULL)) + if (!PhHttpSocketEndRequest(httpContext)) { Context->ErrorCode = GetLastError(); goto CleanupExit; } - if (!ReadRequestString(httpRequestHandle, &stringBuffer, &stringBufferLength)) - goto CleanupExit; - - if (stringBuffer == NULL || stringBuffer[0] == '\0') + if (!(jsonString = PhHttpSocketDownloadString(httpContext, FALSE))) + { + Context->ErrorCode = GetLastError(); goto CleanupExit; + } - if (!(jsonObject = PhCreateJsonParser(stringBuffer))) + if (!(jsonObject = PhCreateJsonParser(jsonString->Buffer))) goto CleanupExit; Context->Version = PhGetJsonValueAsString(jsonObject, "version"); @@ -447,25 +337,13 @@ BOOLEAN QueryUpdateData( CleanupExit: - if (httpRequestHandle) - WinHttpCloseHandle(httpRequestHandle); - - if (httpConnectionHandle) - WinHttpCloseHandle(httpConnectionHandle); + if (httpContext) + PhHttpSocketDestroy(httpContext); - if (httpSessionHandle) - WinHttpCloseHandle(httpSessionHandle); + if (jsonString) + PhDereferenceObject(jsonString); - if (xmlNode) - mxmlDelete(xmlNode); - - if (stringBuffer) - PhFree(stringBuffer); - - PhClearReference(&versionHeader); - PhClearReference(&windowsHeader); - - if (!PhIsNullOrEmptyString(Context->BuildMessage)) + if (success && !PhIsNullOrEmptyString(Context->BuildMessage)) { PH_STRING_BUILDER sb; @@ -629,14 +507,11 @@ NTSTATUS UpdateDownloadThread( BOOLEAN hashSuccess = FALSE; BOOLEAN signatureSuccess = FALSE; HANDLE tempFileHandle = NULL; - HINTERNET httpSessionHandle = NULL; - HINTERNET httpConnectionHandle = NULL; - HINTERNET httpRequestHandle = NULL; + PPH_HTTP_CONTEXT httpContext = NULL; PPH_STRING downloadHostPath = NULL; PPH_STRING downloadUrlPath = NULL; - PPH_STRING userAgentString = NULL; PUPDATER_HASH_CONTEXT hashContext = NULL; - URL_COMPONENTS httpParts = { sizeof(URL_COMPONENTS) }; + USHORT httpPort = 0; LARGE_INTEGER timeNow; LARGE_INTEGER timeStart; ULONG64 timeTicks = 0; @@ -645,51 +520,19 @@ NTSTATUS UpdateDownloadThread( SendMessage(context->DialogHandle, TDM_UPDATE_ELEMENT_TEXT, TDE_MAIN_INSTRUCTION, (LPARAM)L"Initializing download request..."); - // Create a user agent string. - userAgentString = PhFormatString( - L"PH_%s", - PhGetStringOrEmpty(context->CurrentVersionString) - ); - if (PhIsNullOrEmptyString(userAgentString)) - goto CleanupExit; - - // Set lengths to non-zero enabling these params to be cracked. - httpParts.dwSchemeLength = ULONG_MAX; - httpParts.dwHostNameLength = ULONG_MAX; - httpParts.dwUrlPathLength = ULONG_MAX; - - if (!WinHttpCrackUrl( - PhGetStringOrEmpty(context->SetupFileDownloadUrl), - 0, - 0, - &httpParts + if (!PhHttpSocketParseUrl( + context->SetupFileDownloadUrl, + &downloadHostPath, + &downloadUrlPath, + &httpPort )) { context->ErrorCode = GetLastError(); goto CleanupExit; } - // Create the Host string. - if (PhIsNullOrEmptyString(downloadHostPath = PhCreateStringEx( - httpParts.lpszHostName, - httpParts.dwHostNameLength * sizeof(WCHAR) - ))) - { - goto CleanupExit; - } - - // Create the remote path string. - if (PhIsNullOrEmptyString(downloadUrlPath = PhCreateStringEx( - httpParts.lpszUrlPath, - httpParts.dwUrlPathLength * sizeof(WCHAR) - ))) - { - goto CleanupExit; - } - // Create the local path string. context->SetupFilePath = UpdaterParseDownloadFileName(downloadUrlPath); - if (PhIsNullOrEmptyString(context->SetupFilePath)) goto CleanupExit; @@ -709,72 +552,36 @@ NTSTATUS UpdateDownloadThread( SendMessage(context->DialogHandle, TDM_UPDATE_ELEMENT_TEXT, TDE_MAIN_INSTRUCTION, (LPARAM)L"Connecting..."); - // Open the HTTP session with the system proxy configuration if available - if (!(httpSessionHandle = WinHttpOpen( - PhGetString(userAgentString), - WindowsVersion >= WINDOWS_8_1 ? WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY : WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, - WINHTTP_NO_PROXY_NAME, - WINHTTP_NO_PROXY_BYPASS, - 0 - ))) + if (!PhHttpSocketCreate(&httpContext, NULL)) { context->ErrorCode = GetLastError(); goto CleanupExit; } - if (WindowsVersion >= WINDOWS_8_1) - { - WinHttpSetOption( - httpSessionHandle, - WINHTTP_OPTION_DECOMPRESSION, - &(ULONG){ WINHTTP_DECOMPRESSION_FLAG_GZIP | WINHTTP_DECOMPRESSION_FLAG_DEFLATE }, - sizeof(ULONG) - ); - } - - if (!(httpConnectionHandle = WinHttpConnect( - httpSessionHandle, - PhGetString(downloadHostPath), - httpParts.nScheme == INTERNET_SCHEME_HTTP ? INTERNET_DEFAULT_HTTP_PORT : INTERNET_DEFAULT_HTTPS_PORT, - 0 - ))) + if (!PhHttpSocketConnect( + httpContext, + PhGetString(downloadHostPath), + httpPort + )) { context->ErrorCode = GetLastError(); goto CleanupExit; } - if (!(httpRequestHandle = WinHttpOpenRequest( - httpConnectionHandle, - NULL, - PhGetString(downloadUrlPath), - NULL, - WINHTTP_NO_REFERER, - WINHTTP_DEFAULT_ACCEPT_TYPES, - WINHTTP_FLAG_REFRESH | (httpParts.nScheme == INTERNET_SCHEME_HTTPS ? WINHTTP_FLAG_SECURE : 0) - ))) + if (!PhHttpSocketBeginRequest( + httpContext, + NULL, + PhGetString(downloadUrlPath), + PH_HTTP_FLAG_REFRESH | (httpPort == PH_HTTP_DEFAULT_HTTPS_PORT ? PH_HTTP_FLAG_SECURE : 0) + )) { context->ErrorCode = GetLastError(); goto CleanupExit; } - WinHttpSetOption( - httpRequestHandle, - WINHTTP_OPTION_DISABLE_FEATURE, - &(ULONG){ WINHTTP_DISABLE_KEEP_ALIVE }, - sizeof(ULONG) - ); - SendMessage(context->DialogHandle, TDM_UPDATE_ELEMENT_TEXT, TDE_MAIN_INSTRUCTION, (LPARAM)L"Sending download request..."); - if (!WinHttpSendRequest( - httpRequestHandle, - WINHTTP_NO_ADDITIONAL_HEADERS, - 0, - WINHTTP_NO_REQUEST_DATA, - 0, - WINHTTP_IGNORE_REQUEST_TOTAL_LENGTH, - 0 - )) + if (!PhHttpSocketSendRequest(httpContext, NULL, 0)) { context->ErrorCode = GetLastError(); goto CleanupExit; @@ -782,7 +589,7 @@ NTSTATUS UpdateDownloadThread( SendMessage(context->DialogHandle, TDM_UPDATE_ELEMENT_TEXT, TDE_MAIN_INSTRUCTION, (LPARAM)L"Waiting for response..."); - if (!WinHttpReceiveResponse(httpRequestHandle, NULL)) + if (!PhHttpSocketEndRequest(httpContext)) { context->ErrorCode = GetLastError(); goto CleanupExit; @@ -791,7 +598,6 @@ NTSTATUS UpdateDownloadThread( { ULONG bytesDownloaded = 0; ULONG downloadedBytes = 0; - ULONG contentLengthSize = sizeof(ULONG); ULONG contentLength = 0; PPH_STRING status; IO_STATUS_BLOCK isb; @@ -803,16 +609,10 @@ NTSTATUS UpdateDownloadThread( SendMessage(context->DialogHandle, TDM_UPDATE_ELEMENT_TEXT, TDE_MAIN_INSTRUCTION, (LPARAM)status->Buffer); PhDereferenceObject(status); - // Start the clock. - PhQuerySystemTime(&timeStart); - - if (!WinHttpQueryHeaders( - httpRequestHandle, - WINHTTP_QUERY_CONTENT_LENGTH | WINHTTP_QUERY_FLAG_NUMBER, - WINHTTP_HEADER_NAME_BY_INDEX, - &contentLength, - &contentLengthSize, - 0 + if (!PhHttpSocketQueryHeaderUlong( + httpContext, + PH_HTTP_QUERY_CONTENT_LENGTH, + &contentLength )) { context->ErrorCode = GetLastError(); @@ -826,8 +626,11 @@ NTSTATUS UpdateDownloadThread( // Zero the buffer. memset(buffer, 0, PAGE_SIZE); + // Start the clock. + PhQuerySystemTime(&timeStart); + // Download the data. - while (WinHttpReadData(httpRequestHandle, buffer, PAGE_SIZE, &bytesDownloaded)) + while (PhHttpSocketReadData(httpContext, buffer, PAGE_SIZE, &bytesDownloaded)) { // If we get zero bytes, the file was uploaded or there was an error if (bytesDownloaded == 0) @@ -912,30 +715,21 @@ NTSTATUS UpdateDownloadThread( CleanupExit: + if (httpContext) + PhHttpSocketDestroy(httpContext); + if (hashContext) UpdaterDestroyHash(hashContext); if (tempFileHandle) NtClose(tempFileHandle); - if (httpRequestHandle) - WinHttpCloseHandle(httpRequestHandle); - - if (httpConnectionHandle) - WinHttpCloseHandle(httpConnectionHandle); - - if (httpSessionHandle) - WinHttpCloseHandle(httpSessionHandle); - if (downloadHostPath) PhDereferenceObject(downloadHostPath); if (downloadUrlPath) PhDereferenceObject(downloadUrlPath); - if (userAgentString) - WinHttpCloseHandle(userAgentString); - if (UpdateDialogThreadHandle) { if (downloadSuccess && hashSuccess && signatureSuccess) diff --git a/plugins/Updater/updater.h b/plugins/Updater/updater.h index b207301f2ab2..ebc867f041a1 100644 --- a/plugins/Updater/updater.h +++ b/plugins/Updater/updater.h @@ -29,12 +29,15 @@ #include #include #include -#include #include #include #include + #include -#include +#include + +#include +#include #include "resource.h" From 4b266416d5add7a4552fefed0e21ad60c092e2ce Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 3 Nov 2017 02:00:24 +1100 Subject: [PATCH 0543/2058] Update exports --- ProcessHacker/ProcessHacker.def | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ProcessHacker/ProcessHacker.def b/ProcessHacker/ProcessHacker.def index b0fbedefeb2e..f36b044488fa 100644 --- a/ProcessHacker/ProcessHacker.def +++ b/ProcessHacker/ProcessHacker.def @@ -359,6 +359,7 @@ EXPORTS PhGetKnownLocation PhGetMessage PhGetNtMessage + PhGetStatusMessage PhGetSystemDirectory PhGetSystemRoot PhGetWin32Message @@ -629,6 +630,7 @@ EXPORTS PhGetJsonObjectLength PhGetJsonObjectBool PhAddJsonObject + PhGetJsonObjectAsArrayList PhCreateJsonArray PhAddJsonArrayObject PhGetJsonArrayString From 5bc8e1400175214c4b372d96bb0a1eaeaa5fffe9 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 3 Nov 2017 02:03:22 +1100 Subject: [PATCH 0544/2058] NetworkTools: Use http wrapper --- plugins/NetworkTools/NetworkTools.rc | 4 +- plugins/NetworkTools/NetworkTools.vcxproj | 3 + plugins/NetworkTools/nettools.h | 5 +- plugins/NetworkTools/update.c | 325 ++++++---------------- 4 files changed, 93 insertions(+), 244 deletions(-) diff --git a/plugins/NetworkTools/NetworkTools.rc b/plugins/NetworkTools/NetworkTools.rc index 66fdaa394f83..ba5d9ab2068c 100644 --- a/plugins/NetworkTools/NetworkTools.rc +++ b/plugins/NetworkTools/NetworkTools.rc @@ -93,7 +93,7 @@ EXSTYLE WS_EX_APPWINDOW CAPTION "Network Tools" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN - CONTROL "",IDC_NETOUTPUTEDIT,"RICHEDIT50W",WS_VSCROLL | WS_TABSTOP | 0x4,2,2,385,210 + CONTROL "",IDC_NETOUTPUTEDIT,"RICHEDIT50W",WS_VSCROLL | WS_TABSTOP | 0x4,2,2,387,212 END IDD_OPTIONS DIALOGEX 0, 0, 201, 43 @@ -648,9 +648,7 @@ BEGIN IDD_WHOIS, DIALOG BEGIN LEFTMARGIN, 2 - RIGHTMARGIN, 387 TOPMARGIN, 2 - BOTTOMMARGIN, 212 END IDD_OPTIONS, DIALOG diff --git a/plugins/NetworkTools/NetworkTools.vcxproj b/plugins/NetworkTools/NetworkTools.vcxproj index 64ed76316c01..2df98cd00960 100644 --- a/plugins/NetworkTools/NetworkTools.vcxproj +++ b/plugins/NetworkTools/NetworkTools.vcxproj @@ -47,6 +47,9 @@ v141 + + + diff --git a/plugins/NetworkTools/nettools.h b/plugins/NetworkTools/nettools.h index b00ba77ec247..4255eaa3d2f9 100644 --- a/plugins/NetworkTools/nettools.h +++ b/plugins/NetworkTools/nettools.h @@ -26,22 +26,23 @@ #define CINTERFACE #define COBJMACROS -#include #include #include #include #include #include + #include #include #include #include #include #include -#include #include #include +#include + #include "resource.h" #define PLUGIN_NAME L"ProcessHacker.NetworkTools" diff --git a/plugins/NetworkTools/update.c b/plugins/NetworkTools/update.c index e53977a5e2b8..e30b76700eb9 100644 --- a/plugins/NetworkTools/update.c +++ b/plugins/NetworkTools/update.c @@ -34,16 +34,19 @@ VOID FreeUpdateContext( _In_ _Post_invalid_ PPH_UPDATER_CONTEXT Context ) { - //PhClearReference(&Context->Version); - //PhClearReference(&Context->RevVersion); - //PhClearReference(&Context->RelDate); - //PhClearReference(&Context->Size); - //PhClearReference(&Context->Hash); - //PhClearReference(&Context->Signature); - //PhClearReference(&Context->ReleaseNotesUrl); - //PhClearReference(&Context->SetupFilePath); - //PhClearReference(&Context->SetupFileDownloadUrl); - //PhClearReference(&Context); + if (Context->FileDownloadUrl) + PhDereferenceObject(Context->FileDownloadUrl); + + if (Context->FileDownloadUrl) + PhDereferenceObject(Context->FileDownloadUrl); + + if (Context->FileDownloadUrl) + PhDereferenceObject(Context->FileDownloadUrl); + + if (Context->FileDownloadUrl) + PhDereferenceObject(Context->FileDownloadUrl); + + PhDereferenceObject(Context); } VOID TaskDialogCreateIcons( @@ -65,7 +68,7 @@ VOID TaskDialogLinkClicked( } PPH_STRING UpdateVersionString( - _In_ PWSTR UserAgent + VOID ) { ULONG majorVersion; @@ -78,7 +81,7 @@ PPH_STRING UpdateVersionString( if (currentVersion = PhFormatString(L"%lu.%lu.%lu", majorVersion, minorVersion, revisionVersion)) { - versionHeader = PhConcatStrings2(UserAgent, currentVersion->Buffer); + versionHeader = PhConcatStrings2(L"ProcessHacker-Build: ", currentVersion->Buffer); PhDereferenceObject(currentVersion); } @@ -126,155 +129,61 @@ PPH_STRING QueryFwLinkUrl( ) { PPH_STRING redirectUrl = NULL; - HINTERNET httpSessionHandle = NULL; - HINTERNET httpConnectionHandle = NULL; - HINTERNET httpRequestHandle = NULL; - PPH_STRING versionHeader = UpdateVersionString(L"ProcessHacker_Build: "); - PPH_STRING windowsHeader = UpdateWindowsString(); + PPH_HTTP_CONTEXT httpContext = NULL; + PPH_STRING versionString = NULL; + PPH_STRING userAgentString = NULL; + PPH_STRING versionHeader; + PPH_STRING windowsHeader; - if (!(httpSessionHandle = WinHttpOpen( - NULL, - WindowsVersion >= WINDOWS_8_1 ? WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY : WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, - WINHTTP_NO_PROXY_NAME, - WINHTTP_NO_PROXY_BYPASS, - 0 - ))) - { - goto CleanupExit; - } + versionString = PhGetPhVersion(); + userAgentString = PhConcatStrings2(L"ProcessHacker_", versionString->Buffer); - if (WindowsVersion >= WINDOWS_8_1) - { - ULONG httpFlags = WINHTTP_DECOMPRESSION_FLAG_GZIP | WINHTTP_DECOMPRESSION_FLAG_DEFLATE; - - WinHttpSetOption( - httpSessionHandle, - WINHTTP_OPTION_DECOMPRESSION, - &httpFlags, - sizeof(ULONG) - ); - } + if (!PhHttpSocketCreate(&httpContext, PhGetString(userAgentString))) + goto CleanupExit; - if (!(httpConnectionHandle = WinHttpConnect( - httpSessionHandle, - L"wj32.org", - INTERNET_DEFAULT_HTTPS_PORT, - 0 - ))) - { + if (!PhHttpSocketConnect(httpContext, L"wj32.org", PH_HTTP_DEFAULT_HTTPS_PORT)) goto CleanupExit; - } - if (!(httpRequestHandle = WinHttpOpenRequest( - httpConnectionHandle, + if (!PhHttpSocketBeginRequest( + httpContext, NULL, L"/processhacker/fwlink/maxminddb.php", - NULL, - WINHTTP_NO_REFERER, - WINHTTP_DEFAULT_ACCEPT_TYPES, - WINHTTP_FLAG_REFRESH | WINHTTP_FLAG_SECURE - ))) + PH_HTTP_FLAG_REFRESH | PH_HTTP_FLAG_SECURE + )) { goto CleanupExit; } - if (versionHeader) + if (versionHeader = UpdateVersionString()) { - WinHttpAddRequestHeaders( - httpRequestHandle, - versionHeader->Buffer, - (ULONG)versionHeader->Length / sizeof(WCHAR), - WINHTTP_ADDREQ_FLAG_ADD - ); + PhHttpSocketAddRequestHeaders(httpContext, versionHeader->Buffer, (ULONG)versionHeader->Length / sizeof(WCHAR)); + PhDereferenceObject(versionHeader); } - if (windowsHeader) + if (windowsHeader = UpdateWindowsString()) { - WinHttpAddRequestHeaders( - httpRequestHandle, - windowsHeader->Buffer, - (ULONG)windowsHeader->Length / sizeof(WCHAR), - WINHTTP_ADDREQ_FLAG_ADD - ); + PhHttpSocketAddRequestHeaders(httpContext, windowsHeader->Buffer, (ULONG)windowsHeader->Length / sizeof(WCHAR)); + PhDereferenceObject(windowsHeader); } - WinHttpSetOption( - httpRequestHandle, - WINHTTP_OPTION_DISABLE_FEATURE, - &(ULONG){ WINHTTP_DISABLE_REDIRECTS }, - sizeof(ULONG) - ); - - WinHttpSetOption( - httpRequestHandle, - WINHTTP_OPTION_DISABLE_FEATURE, - &(ULONG){ WINHTTP_DISABLE_KEEP_ALIVE }, - sizeof(ULONG) - ); - - if (!WinHttpSendRequest( - httpRequestHandle, - WINHTTP_NO_ADDITIONAL_HEADERS, - 0, - WINHTTP_NO_REQUEST_DATA, - 0, - WINHTTP_IGNORE_REQUEST_TOTAL_LENGTH, - 0 - )) - { + if (!PhHttpSocketSetFeature(httpContext, PH_HTTP_FEATURE_REDIRECTS, FALSE)) goto CleanupExit; - } - if (WinHttpReceiveResponse(httpRequestHandle, NULL)) - { - ULONG redirectLength = 0; - - if (WinHttpQueryHeaders( - httpRequestHandle, - WINHTTP_QUERY_LOCATION, - WINHTTP_HEADER_NAME_BY_INDEX, - NULL, - &redirectLength, - 0 - )) - { - goto CleanupExit; - } + if (!PhHttpSocketSendRequest(httpContext, NULL, 0)) + goto CleanupExit; - if (redirectLength) - { - redirectUrl = PhCreateStringEx(NULL, redirectLength); - - if (!WinHttpQueryHeaders( - httpRequestHandle, - WINHTTP_QUERY_LOCATION, - WINHTTP_HEADER_NAME_BY_INDEX, - redirectUrl->Buffer, - &redirectLength, - 0 - )) - { - PhClearReference(&redirectUrl); - } - } - } + if (!PhHttpSocketEndRequest(httpContext)) + goto CleanupExit; + + redirectUrl = PhHttpSocketQueryHeaderString(httpContext, L"Location"); // WINHTTP_QUERY_LOCATION CleanupExit: - if (httpRequestHandle) - WinHttpCloseHandle(httpRequestHandle); - - if (httpConnectionHandle) - WinHttpCloseHandle(httpConnectionHandle); - - if (httpSessionHandle) - WinHttpCloseHandle(httpSessionHandle); + if (httpContext) + PhHttpSocketDestroy(httpContext); - if (versionHeader) - PhDereferenceObject(versionHeader); - - if (windowsHeader) - PhDereferenceObject(windowsHeader); + PhClearReference(&versionString); + PhClearReference(&userAgentString); return redirectUrl; } @@ -285,19 +194,18 @@ NTSTATUS GeoIPUpdateThread( { BOOLEAN success = FALSE; HANDLE tempFileHandle = NULL; - HINTERNET httpSessionHandle = NULL; - HINTERNET httpConnectionHandle = NULL; - HINTERNET httpRequestHandle = NULL; PPH_STRING fwLinkUrl = NULL; - PPH_STRING downloadHostPath = NULL; - PPH_STRING downloadUrlPath = NULL; - URL_COMPONENTS httpParts = { sizeof(URL_COMPONENTS) }; + PPH_HTTP_CONTEXT httpContext = NULL; + PPH_STRING versionString = NULL; + PPH_STRING userAgentString = NULL; + PPH_STRING httpHostName = NULL; + PPH_STRING httpHostPath = NULL; + USHORT httpHostPort = 0; LARGE_INTEGER timeNow; LARGE_INTEGER timeStart; ULONG64 timeTicks = 0; ULONG64 timeBitsPerSecond = 0; PPH_UPDATER_CONTEXT context = (PPH_UPDATER_CONTEXT)Parameter; - PPH_STRING userAgentString = UpdateVersionString(L"ProcessHacker_"); SendMessage(context->DialogHandle, TDM_UPDATE_ELEMENT_TEXT, TDE_MAIN_INSTRUCTION, (LPARAM)L"Initializing download request..."); @@ -305,10 +213,10 @@ NTSTATUS GeoIPUpdateThread( goto CleanupExit; context->SetupFilePath = PhCreateCacheFile(PhaCreateString(L"GeoLite2-Country.mmdb.gz")); + if (PhIsNullOrEmptyString(context->SetupFilePath)) goto CleanupExit; - // Create output file if (!NT_SUCCESS(PhCreateFileWin32( &tempFileHandle, PhGetString(context->SetupFilePath), @@ -324,112 +232,57 @@ NTSTATUS GeoIPUpdateThread( SendMessage(context->DialogHandle, TDM_UPDATE_ELEMENT_TEXT, TDE_MAIN_INSTRUCTION, (LPARAM)L"Connecting..."); - // Set lengths to non-zero enabling these params to be cracked. - httpParts.dwSchemeLength = ULONG_MAX; - httpParts.dwHostNameLength = ULONG_MAX; - httpParts.dwUrlPathLength = ULONG_MAX; - - if (!WinHttpCrackUrl( - fwLinkUrl->Buffer, - 0, - 0, - &httpParts + if (!PhHttpSocketParseUrl( + fwLinkUrl, + &httpHostName, + &httpHostPath, + &httpHostPort )) { goto CleanupExit; } - // Create the Host string. - if (PhIsNullOrEmptyString(downloadHostPath = PhCreateStringEx( - httpParts.lpszHostName, - httpParts.dwHostNameLength * sizeof(WCHAR) - ))) - { - goto CleanupExit; - } + versionString = PhGetPhVersion(); + userAgentString = PhConcatStrings2(L"ProcessHacker_", versionString->Buffer); - // Create the remote path string. - if (PhIsNullOrEmptyString(downloadUrlPath = PhCreateStringEx( - httpParts.lpszUrlPath, - httpParts.dwUrlPathLength * sizeof(WCHAR) - ))) - { - goto CleanupExit; - } - - if (!(httpSessionHandle = WinHttpOpen( - PhGetString(userAgentString), - WindowsVersion >= WINDOWS_8_1 ? WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY : WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, - WINHTTP_NO_PROXY_NAME, - WINHTTP_NO_PROXY_BYPASS, - 0 - ))) + if (!PhHttpSocketCreate( + &httpContext, + PhGetString(userAgentString) + )) { goto CleanupExit; } - if (WindowsVersion >= WINDOWS_8_1) - { - WinHttpSetOption( - httpSessionHandle, - WINHTTP_OPTION_DECOMPRESSION, - &(ULONG){ WINHTTP_DECOMPRESSION_FLAG_GZIP | WINHTTP_DECOMPRESSION_FLAG_DEFLATE }, - sizeof(ULONG) - ); - } - - if (!(httpConnectionHandle = WinHttpConnect( - httpSessionHandle, - PhGetString(downloadHostPath), - httpParts.nScheme == INTERNET_SCHEME_HTTP ? INTERNET_DEFAULT_HTTP_PORT : INTERNET_DEFAULT_HTTPS_PORT, - 0 - ))) + if (!PhHttpSocketConnect( + httpContext, + PhGetString(httpHostName), + httpHostPort + )) { goto CleanupExit; } - if (!(httpRequestHandle = WinHttpOpenRequest( - httpConnectionHandle, - NULL, - PhGetString(downloadUrlPath), + if (!PhHttpSocketBeginRequest( + httpContext, NULL, - WINHTTP_NO_REFERER, - WINHTTP_DEFAULT_ACCEPT_TYPES, - WINHTTP_FLAG_REFRESH | (httpParts.nScheme == INTERNET_SCHEME_HTTPS ? WINHTTP_FLAG_SECURE : 0) - ))) + PhGetString(httpHostPath), + PH_HTTP_FLAG_REFRESH | (httpHostPort == PH_HTTP_DEFAULT_HTTPS_PORT ? PH_HTTP_FLAG_SECURE : 0) + )) { goto CleanupExit; } - WinHttpSetOption( - httpRequestHandle, - WINHTTP_OPTION_DISABLE_FEATURE, - &(ULONG){ WINHTTP_DISABLE_KEEP_ALIVE }, - sizeof(ULONG) - ); - SendMessage(context->DialogHandle, TDM_UPDATE_ELEMENT_TEXT, TDE_MAIN_INSTRUCTION, (LPARAM)L"Sending download request..."); - if (!WinHttpSendRequest( - httpRequestHandle, - WINHTTP_NO_ADDITIONAL_HEADERS, - 0, - WINHTTP_NO_REQUEST_DATA, - 0, - WINHTTP_IGNORE_REQUEST_TOTAL_LENGTH, - 0 - )) - { + if (!PhHttpSocketSendRequest(httpContext, NULL, 0)) goto CleanupExit; - } SendMessage(context->DialogHandle, TDM_UPDATE_ELEMENT_TEXT, TDE_MAIN_INSTRUCTION, (LPARAM)L"Waiting for response..."); - if (WinHttpReceiveResponse(httpRequestHandle, NULL)) + if (PhHttpSocketEndRequest(httpContext)) { ULONG bytesDownloaded = 0; ULONG downloadedBytes = 0; - ULONG contentLengthSize = sizeof(ULONG); ULONG contentLength = 0; PPH_STRING status; IO_STATUS_BLOCK isb; @@ -442,21 +295,19 @@ NTSTATUS GeoIPUpdateThread( SendMessage(context->DialogHandle, TDM_UPDATE_ELEMENT_TEXT, TDE_MAIN_INSTRUCTION, (LPARAM)status->Buffer); PhDereferenceObject(status); - if (!WinHttpQueryHeaders( - httpRequestHandle, - WINHTTP_QUERY_CONTENT_LENGTH | WINHTTP_QUERY_FLAG_NUMBER, - WINHTTP_HEADER_NAME_BY_INDEX, - &contentLength, - &contentLengthSize, - 0 + if (!PhHttpSocketQueryHeaderUlong( + httpContext, + PH_HTTP_QUERY_CONTENT_LENGTH, + &contentLength )) { + //context->ErrorCode = GetLastError(); goto CleanupExit; } PhQuerySystemTime(&timeStart); - while (WinHttpReadData(httpRequestHandle, buffer, PAGE_SIZE, &bytesDownloaded)) + while (PhHttpSocketReadData(httpContext, buffer, PAGE_SIZE, &bytesDownloaded)) { // If we get zero bytes, the file was uploaded or there was an error. if (bytesDownloaded == 0) @@ -610,17 +461,13 @@ NTSTATUS GeoIPUpdateThread( if (tempFileHandle) NtClose(tempFileHandle); - if (httpRequestHandle) - WinHttpCloseHandle(httpRequestHandle); - - if (httpConnectionHandle) - WinHttpCloseHandle(httpConnectionHandle); - - if (httpSessionHandle) - WinHttpCloseHandle(httpSessionHandle); + if (httpContext) + PhHttpSocketDestroy(httpContext); if (userAgentString) PhDereferenceObject(userAgentString); + if (versionString) + PhDereferenceObject(versionString); if (context->SetupFilePath) { From 732a141a1f0d3734aeb616669f04d6d35c52db17 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 3 Nov 2017 04:10:26 +1100 Subject: [PATCH 0545/2058] Add workaround for PhGetMessage and insert sequences --- phlib/util.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/phlib/util.c b/phlib/util.c index 7d7f4950e9a0..379d835d2620 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -280,6 +280,10 @@ PPH_STRING PhGetMessage( if (!NT_SUCCESS(status)) return NULL; + // dmex: We don't support parsing insert sequences. + if (messageEntry->Text[0] == '%') + return NULL; + if (messageEntry->Flags & MESSAGE_RESOURCE_UNICODE) { return PhCreateStringEx((PWCHAR)messageEntry->Text, messageEntry->Length); From b2ed625dea4072e7db6004898e451a673274990e Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 3 Nov 2017 04:11:49 +1100 Subject: [PATCH 0546/2058] NetworkTools: Add missing file --- plugins/NetworkTools/update.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/plugins/NetworkTools/update.c b/plugins/NetworkTools/update.c index e30b76700eb9..774069ad8e55 100644 --- a/plugins/NetworkTools/update.c +++ b/plugins/NetworkTools/update.c @@ -37,14 +37,14 @@ VOID FreeUpdateContext( if (Context->FileDownloadUrl) PhDereferenceObject(Context->FileDownloadUrl); - if (Context->FileDownloadUrl) - PhDereferenceObject(Context->FileDownloadUrl); + if (Context->RevVersion) + PhDereferenceObject(Context->RevVersion); - if (Context->FileDownloadUrl) - PhDereferenceObject(Context->FileDownloadUrl); + if (Context->Size) + PhDereferenceObject(Context->Size); - if (Context->FileDownloadUrl) - PhDereferenceObject(Context->FileDownloadUrl); + if (Context->SetupFilePath) + PhDereferenceObject(Context->SetupFilePath); PhDereferenceObject(Context); } From 60a10900b917e9a03c98b762dbc708df1a2037a3 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 3 Nov 2017 13:10:55 +1100 Subject: [PATCH 0547/2058] OnlineChecks: Use http wrapper --- plugins/OnlineChecks/OnlineChecks.rc | 22 + plugins/OnlineChecks/OnlineChecks.vcxproj | 3 + plugins/OnlineChecks/main.c | 3 +- plugins/OnlineChecks/onlnchk.h | 105 ++-- plugins/OnlineChecks/page2.c | 4 +- plugins/OnlineChecks/resource.h | 8 +- plugins/OnlineChecks/upload.c | 527 ++++++++------------ plugins/OnlineChecks/virustotal.c | 563 ++++++++++++---------- 8 files changed, 631 insertions(+), 604 deletions(-) diff --git a/plugins/OnlineChecks/OnlineChecks.rc b/plugins/OnlineChecks/OnlineChecks.rc index 0cdef0b36dac..e5f2b6e780c4 100644 --- a/plugins/OnlineChecks/OnlineChecks.rc +++ b/plugins/OnlineChecks/OnlineChecks.rc @@ -103,6 +103,15 @@ BEGIN LTEXT "Minimum detection action:",IDC_STATIC,7,67,84,8 END +IDD_VIRUSTOTAL DIALOGEX 0, 0, 259, 261 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "VirusTotal" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + PUSHBUTTON "Refresh",IDC_REFRESH,207,245,50,14 + CONTROL "",IDC_SCANRESULTS,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,2,2,255,241 +END + ///////////////////////////////////////////////////////////////////////////// // @@ -119,6 +128,14 @@ BEGIN TOPMARGIN, 7 BOTTOMMARGIN, 80 END + + IDD_VIRUSTOTAL, DIALOG + BEGIN + LEFTMARGIN, 2 + RIGHTMARGIN, 257 + TOPMARGIN, 2 + BOTTOMMARGIN, 259 + END END #endif // APSTUDIO_INVOKED @@ -133,6 +150,11 @@ BEGIN 0 END +IDD_VIRUSTOTAL AFX_DIALOG_LAYOUT +BEGIN + 0 +END + #endif // English (Australia) resources ///////////////////////////////////////////////////////////////////////////// diff --git a/plugins/OnlineChecks/OnlineChecks.vcxproj b/plugins/OnlineChecks/OnlineChecks.vcxproj index f6a7ecd4e1b2..a041a2316bb4 100644 --- a/plugins/OnlineChecks/OnlineChecks.vcxproj +++ b/plugins/OnlineChecks/OnlineChecks.vcxproj @@ -47,6 +47,9 @@ v141 + + + diff --git a/plugins/OnlineChecks/main.c b/plugins/OnlineChecks/main.c index 6f9677e1b99c..cbc39b076775 100644 --- a/plugins/OnlineChecks/main.c +++ b/plugins/OnlineChecks/main.c @@ -720,7 +720,8 @@ LOGICAL DllMain( PH_SETTING_CREATE settings[] = { { IntegerSettingType, SETTING_NAME_VIRUSTOTAL_SCAN_ENABLED, L"0" }, - { IntegerSettingType, SETTING_NAME_VIRUSTOTAL_HIGHLIGHT_DETECTIONS, L"0" } + { IntegerSettingType, SETTING_NAME_VIRUSTOTAL_HIGHLIGHT_DETECTIONS, L"0" }, + { IntegerSettingType, SETTING_NAME_VIRUSTOTAL_DEFAULT_ACTION, L"0" } }; PluginInstance = PhRegisterPlugin(PLUGIN_NAME, Instance, &info); diff --git a/plugins/OnlineChecks/onlnchk.h b/plugins/OnlineChecks/onlnchk.h index 808f1282d8b2..1940fc053220 100644 --- a/plugins/OnlineChecks/onlnchk.h +++ b/plugins/OnlineChecks/onlnchk.h @@ -29,19 +29,21 @@ #include #include #include -#include +#include #include #include #include + #include #include -#include + #include "resource.h" #include "db.h" #define PLUGIN_NAME L"ProcessHacker.OnlineChecks" #define SETTING_NAME_VIRUSTOTAL_SCAN_ENABLED (PLUGIN_NAME L".EnableVirusTotalScanning") #define SETTING_NAME_VIRUSTOTAL_HIGHLIGHT_DETECTIONS (PLUGIN_NAME L".VirusTotalHighlightDetection") +#define SETTING_NAME_VIRUSTOTAL_DEFAULT_ACTION (PLUGIN_NAME L".VirusTotalDefautAction") #define UM_UPLOAD (WM_APP + 1) #define UM_EXISTS (WM_APP + 2) @@ -55,7 +57,7 @@ typedef struct _SERVICE_INFO { ULONG Id; PWSTR HostName; - INTERNET_PORT HostPort; + USHORT HostPort; ULONG HostFlags; PWSTR UploadObjectName; PWSTR FileNameFieldName; @@ -124,7 +126,7 @@ typedef struct _UPLOAD_CONTEXT HANDLE UploadThreadHandle; HICON IconLargeHandle; HICON IconSmallHandle; - HINTERNET HttpHandle; + ITaskbarList3* TaskbarListClass; PPH_STRING FileSize; @@ -141,6 +143,9 @@ typedef struct _UPLOAD_CONTEXT PPH_STRING LastAnalysisDate; PPH_STRING LastAnalysisUrl; PPH_STRING LastAnalysisAgo; + + PPH_STRING FileHash; + } UPLOAD_CONTEXT, *PUPLOAD_CONTEXT; // options.c @@ -160,6 +165,10 @@ NTSTATUS UploadCheckThreadStart( _In_ PVOID Parameter ); +NTSTATUS UploadRecheckThreadStart( + _In_ PVOID Parameter + ); + VOID ShowVirusTotalUploadDialog( _In_ PUPLOAD_CONTEXT Context ); @@ -176,32 +185,6 @@ VOID VirusTotalShowErrorDialog( _In_ PUPLOAD_CONTEXT Context ); -typedef struct _VIRUSTOTAL_FILE_REPORT_RESULT -{ - PPH_STRING FileName; - PPH_STRING BaseFileName; - - PPH_STRING Total; - PPH_STRING Positives; - PPH_STRING Resource; - PPH_STRING ScanId; - PPH_STRING Md5; - PPH_STRING Sha1; - PPH_STRING Sha256; - PPH_STRING ScanDate; - PPH_STRING Permalink; - PPH_STRING StatusMessage; - PPH_LIST ScanResults; -} VIRUSTOTAL_FILE_REPORT_RESULT, *PVIRUSTOTAL_FILE_REPORT_RESULT; - -PPH_STRING VirusTotalStringToTime( - _In_ PPH_STRING Time - ); - -PVIRUSTOTAL_FILE_REPORT_RESULT VirusTotalSendHttpFileReportRequest( - _In_ PPH_STRING FileHash - ); - // upload #define ENABLE_SERVICE_VIRUSTOTAL 100 #define MENUITEM_VIRUSTOTAL_QUEUE 101 @@ -259,6 +242,68 @@ PPH_BYTES VirusTotalGetCachedDbHash( VOID ); +typedef struct _VT_SYSINT_FILE_REPORT_RESULT +{ + PPH_STRING FileName; + PPH_STRING BaseFileName; + + PPH_STRING Total; + PPH_STRING Positives; + PPH_STRING Resource; + PPH_STRING ScanId; + PPH_STRING Md5; + PPH_STRING Sha1; + PPH_STRING Sha256; + PPH_STRING ScanDate; + PPH_STRING Permalink; + PPH_STRING StatusMessage; + PPH_LIST ScanResults; +} VT_SYSINT_FILE_REPORT_RESULT, *PVT_SYSINT_FILE_REPORT_RESULT; + +PPH_STRING VirusTotalStringToTime( + _In_ PPH_STRING Time +); + +typedef struct _VIRUSTOTAL_API_RESPONSE +{ + INT64 ResponseCode; + PPH_STRING StatusMessage; + PPH_STRING PermaLink; + PPH_STRING ScanId; +} VIRUSTOTAL_API_RESPONSE, *PVIRUSTOTAL_API_RESPONSE; + +typedef struct _VIRUSTOTAL_FILE_REPORT +{ + INT64 ResponseCode; + PPH_STRING StatusMessage; + PPH_STRING PermaLink; + PPH_STRING ScanId; + + PPH_STRING ScanDate; + PPH_STRING Positives; + PPH_STRING Total; + PPH_LIST ScanResults; +} VIRUSTOTAL_FILE_REPORT, *PVIRUSTOTAL_FILE_REPORT; + +typedef struct _VIRUSTOTAL_FILE_REPORT_RESULT +{ + BOOLEAN Detected; + + PPH_STRING Vendor; + PPH_STRING DetectionName; + PPH_STRING EngineVersion; + PPH_STRING DatabaseDate; +} VIRUSTOTAL_FILE_REPORT_RESULT, *PVIRUSTOTAL_FILE_REPORT_RESULT; + +PVIRUSTOTAL_FILE_REPORT VirusTotalRequestFileReport( + _In_ PPH_STRING FileHash + ); + +PVIRUSTOTAL_API_RESPONSE VirusTotalRequestFileReScan( + _In_ PPH_STRING FileHash + ); + + VOID InitializeVirusTotalProcessMonitor( VOID ); diff --git a/plugins/OnlineChecks/page2.c b/plugins/OnlineChecks/page2.c index aff040808c29..dbee6f4d88b5 100644 --- a/plugins/OnlineChecks/page2.c +++ b/plugins/OnlineChecks/page2.c @@ -46,11 +46,11 @@ HRESULT CALLBACK TaskDialogResultFoundProc( if (context->TaskbarListClass) { ITaskbarList3_SetProgressState(context->TaskbarListClass, PhMainWndHandle, TBPF_NOPROGRESS); - } + } } break; case TDN_BUTTON_CLICKED: - { + { INT buttonID = (INT)wParam; if (buttonID == IDOK) diff --git a/plugins/OnlineChecks/resource.h b/plugins/OnlineChecks/resource.h index 6b43b8c86cbf..bc4a9fd77e37 100644 --- a/plugins/OnlineChecks/resource.h +++ b/plugins/OnlineChecks/resource.h @@ -3,19 +3,23 @@ // Used by OnlineChecks.rc // #define IDD_OPTIONS 102 +#define IDD_VIRUSTOTAL 103 #define IDC_ENABLE_VIRUSTOTAL 1001 #define IDC_ENABLE_IDC_ENABLE_VIRUSTOTAL_HIGHLIGHT 1002 #define IDC_CHECK1 1010 #define IDC_EDIT1 1011 #define IDC_COMBO1 1012 +#define IDC_REFRESH 1013 +#define IDC_LIST1 1014 +#define IDC_SCANRESULTS 1014 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 103 +#define _APS_NEXT_RESOURCE_VALUE 105 #define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1013 +#define _APS_NEXT_CONTROL_VALUE 1015 #define _APS_NEXT_SYMED_VALUE 103 #endif #endif diff --git a/plugins/OnlineChecks/upload.c b/plugins/OnlineChecks/upload.c index 77a6f619f96c..4c6309239c69 100644 --- a/plugins/OnlineChecks/upload.c +++ b/plugins/OnlineChecks/upload.c @@ -21,98 +21,30 @@ */ #include "onlnchk.h" -#include #include PPH_OBJECT_TYPE UploadContextType = NULL; PH_INITONCE UploadContextTypeInitOnce = PH_INITONCE_INIT; SERVICE_INFO UploadServiceInfo[] = { - { MENUITEM_VIRUSTOTAL_UPLOAD, L"www.virustotal.com", INTERNET_DEFAULT_HTTPS_PORT, WINHTTP_FLAG_SECURE, L"???", L"file" }, - { MENUITEM_VIRUSTOTAL_UPLOAD_SERVICE, L"www.virustotal.com", INTERNET_DEFAULT_HTTPS_PORT, WINHTTP_FLAG_SECURE, L"???", L"file" }, - { MENUITEM_JOTTI_UPLOAD, L"virusscan.jotti.org", INTERNET_DEFAULT_HTTPS_PORT, WINHTTP_FLAG_SECURE, L"/en-US/submit-file?isAjax=true", L"sample-file[]" }, - { MENUITEM_JOTTI_UPLOAD_SERVICE, L"virusscan.jotti.org", INTERNET_DEFAULT_HTTPS_PORT, WINHTTP_FLAG_SECURE, L"/en-US/submit-file?isAjax=true", L"sample-file[]" }, + { MENUITEM_VIRUSTOTAL_UPLOAD, L"www.virustotal.com", PH_HTTP_DEFAULT_HTTPS_PORT, PH_HTTP_FLAG_SECURE, L"???", L"file" }, + { MENUITEM_VIRUSTOTAL_UPLOAD_SERVICE, L"www.virustotal.com", PH_HTTP_DEFAULT_HTTPS_PORT, PH_HTTP_FLAG_SECURE, L"???", L"file" }, + { MENUITEM_JOTTI_UPLOAD, L"virusscan.jotti.org", PH_HTTP_DEFAULT_HTTPS_PORT, PH_HTTP_FLAG_SECURE, L"/en-US/submit-file?isAjax=true", L"sample-file[]" }, + { MENUITEM_JOTTI_UPLOAD_SERVICE, L"virusscan.jotti.org", PH_HTTP_DEFAULT_HTTPS_PORT, PH_HTTP_FLAG_SECURE, L"/en-US/submit-file?isAjax=true", L"sample-file[]" }, }; -BOOL ReadRequestString( - _In_ HINTERNET Handle, - _Out_ _Deref_post_z_cap_(*DataLength) PSTR *Data, - _Out_ ULONG *DataLength - ) -{ - BYTE buffer[PAGE_SIZE]; - PSTR data; - ULONG allocatedLength; - ULONG dataLength; - ULONG returnLength; - - allocatedLength = sizeof(buffer); - data = (PSTR)PhAllocate(allocatedLength); - dataLength = 0; - - // Zero the buffer - memset(buffer, 0, PAGE_SIZE); - - while (WinHttpReadData(Handle, buffer, PAGE_SIZE, &returnLength)) - { - if (returnLength == 0) - break; - - if (allocatedLength < dataLength + returnLength) - { - allocatedLength *= 2; - data = (PSTR)PhReAllocate(data, allocatedLength); - } - - // Copy the returned buffer into our pointer - memcpy(data + dataLength, buffer, returnLength); - // Zero the returned buffer for the next loop - //memset(buffer, 0, returnLength); - - dataLength += returnLength; - } - - if (allocatedLength < dataLength + 1) - { - allocatedLength++; - data = (PSTR)PhReAllocate(data, allocatedLength); - } - - // Ensure that the buffer is null-terminated. - data[dataLength] = 0; - - *DataLength = dataLength; - *Data = data; - - return TRUE; -} - VOID RaiseUploadError( _In_ PUPLOAD_CONTEXT Context, _In_ PWSTR Error, _In_ ULONG ErrorCode ) { - PWSTR errorMessage = NULL; PPH_STRING message; if (!Context->DialogHandle) return; - if (message = PhGetMessage(PhGetDllHandle(L"winhttp.dll"), 0xb, GetUserDefaultLangID(), ErrorCode)) - { - PhTrimToNullTerminatorString(message); - } - - // Remove any trailing newline - if (message && message->Length >= 2 * sizeof(WCHAR) && - message->Buffer[message->Length / sizeof(WCHAR) - 2] == '\r' && - message->Buffer[message->Length / sizeof(WCHAR) - 1] == '\n') - { - PhMoveReference(&message, PhCreateStringEx(message->Buffer, message->Length - 2 * sizeof(WCHAR))); - } - - if (message) + if (message = PhHttpSocketGetErrorMessage(ErrorCode)) { PhMoveReference(&Context->ErrorString, PhFormatString( L"[%lu] %s", @@ -132,7 +64,6 @@ VOID RaiseUploadError( } PostMessage(Context->DialogHandle, UM_ERROR, 0, 0); - } PSERVICE_INFO GetUploadServiceInfo( @@ -169,12 +100,6 @@ VOID UploadContextDeleteProcedure( context->UploadThreadHandle = NULL; } - if (context->HttpHandle) - { - WinHttpCloseHandle(context->HttpHandle); - context->HttpHandle = NULL; - } - PhClearReference(&context->ErrorString); PhClearReference(&context->FileName); PhClearReference(&context->BaseFileName); @@ -329,104 +254,75 @@ NTSTATUS HashFileAndResetPosition( PPH_BYTES PerformSubRequest( _In_ PUPLOAD_CONTEXT Context, _In_ PWSTR HostName, - _In_ INTERNET_PORT HostPort, + _In_ USHORT HostPort, _In_ ULONG HostFlags, _In_ PWSTR ObjectName ) { PPH_BYTES result = NULL; - HINTERNET connectHandle = NULL; - HINTERNET requestHandle = NULL; + PPH_HTTP_CONTEXT httpContext = NULL; + PPH_STRING phVersion = NULL; + PPH_STRING userAgent = NULL; + + // Create a user agent string. + phVersion = PhGetPhVersion(); + userAgent = PhConcatStrings2(L"ProcessHacker_", phVersion->Buffer); - if (!(connectHandle = WinHttpConnect( - Context->HttpHandle, + if (!PhHttpSocketCreate( + &httpContext, + PhGetString(userAgent) + )) + { + RaiseUploadError(Context, L"Unable to create the http socket.", GetLastError()); + goto CleanupExit; + } + + if (!PhHttpSocketConnect( + httpContext, HostName, - HostPort, - 0 - ))) + HostPort + )) { - RaiseUploadError(Context, L"Unable to connect to the service", GetLastError()); + RaiseUploadError(Context, L"Unable to connect to the service.", GetLastError()); goto CleanupExit; } - if (!(requestHandle = WinHttpOpenRequest( - connectHandle, + if (!PhHttpSocketBeginRequest( + httpContext, NULL, ObjectName, - NULL, - WINHTTP_NO_REFERER, - WINHTTP_DEFAULT_ACCEPT_TYPES, - WINHTTP_FLAG_REFRESH | HostFlags - ))) + PH_HTTP_FLAG_REFRESH | HostFlags + )) { - RaiseUploadError(Context, L"Unable to create the request", GetLastError()); + RaiseUploadError(Context, L"Unable to create the request.", GetLastError()); goto CleanupExit; } - if (!WinHttpSendRequest( - requestHandle, - WINHTTP_NO_ADDITIONAL_HEADERS, - 0, - WINHTTP_NO_REQUEST_DATA, - 0, - WINHTTP_IGNORE_REQUEST_TOTAL_LENGTH, - 0 - )) + if (!PhHttpSocketSendRequest(httpContext, NULL, 0)) { - RaiseUploadError(Context, L"Unable to send the request", GetLastError()); + RaiseUploadError(Context, L"Unable to send the request.", GetLastError()); goto CleanupExit; } - if (WinHttpReceiveResponse(requestHandle, NULL)) + if (!PhHttpSocketEndRequest(httpContext)) { - PSTR data; - ULONG allocatedLength; - ULONG dataLength; - ULONG returnLength; - BYTE buffer[PAGE_SIZE]; - - allocatedLength = sizeof(buffer); - data = PhAllocate(allocatedLength); - dataLength = 0; - - while (WinHttpReadData(requestHandle, buffer, PAGE_SIZE, &returnLength)) - { - if (returnLength == 0) - break; - - if (allocatedLength < dataLength + returnLength) - { - allocatedLength *= 2; - data = PhReAllocate(data, allocatedLength); - } - - memcpy(data + dataLength, buffer, returnLength); - dataLength += returnLength; - } - - if (allocatedLength < dataLength + 1) - { - allocatedLength++; - data = PhReAllocate(data, allocatedLength); - } - - data[dataLength] = 0; - - result = PhCreateBytesEx(data, dataLength); + RaiseUploadError(Context, L"Unable to receive the request.", GetLastError()); + goto CleanupExit; } - else + + if (!(result = PhHttpSocketDownloadString(httpContext, FALSE))) { - RaiseUploadError(Context, L"Unable to receive the response", GetLastError()); + RaiseUploadError(Context, L"Unable to download the response.", GetLastError()); goto CleanupExit; } CleanupExit: - if (requestHandle) - WinHttpCloseHandle(requestHandle); + if (httpContext) + PhHttpSocketDestroy(httpContext); - if (connectHandle) - WinHttpCloseHandle(connectHandle); + PhClearReference(&phVersion); + PhClearReference(&userAgent); return result; } @@ -437,7 +333,6 @@ NTSTATUS UploadFileThreadStart( { NTSTATUS status = STATUS_SUCCESS; ULONG httpStatus = 0; - ULONG httpStatusLength = sizeof(ULONG); ULONG httpPostSeed = 0; ULONG totalUploadLength = 0; ULONG totalUploadedLength = 0; @@ -449,12 +344,13 @@ NTSTATUS UploadFileThreadStart( ULONG64 timeTicks = 0; ULONG64 timeBitsPerSecond = 0; HANDLE fileHandle = NULL; - HINTERNET connectHandle = NULL; - HINTERNET requestHandle = NULL; IO_STATUS_BLOCK isb; - URL_COMPONENTS httpComponents = { sizeof(URL_COMPONENTS) }; + PPH_HTTP_CONTEXT httpContext = NULL; + PPH_STRING phVersion = NULL; + PPH_STRING userAgent = NULL; PPH_STRING httpHostName = NULL; PPH_STRING httpHostPath = NULL; + USHORT httpHostPort = 0; PSERVICE_INFO serviceInfo = NULL; PPH_STRING postBoundary = NULL; PPH_BYTES asciiPostData = NULL; @@ -466,39 +362,6 @@ NTSTATUS UploadFileThreadStart( serviceInfo = GetUploadServiceInfo(context->Service); - // Set lengths to non-zero enabling these params to be cracked. - httpComponents.dwSchemeLength = ULONG_MAX; - httpComponents.dwHostNameLength = ULONG_MAX; - httpComponents.dwUrlPathLength = ULONG_MAX; - - if (!WinHttpCrackUrl( - PhGetString(context->UploadUrl), - 0, - 0, - &httpComponents - )) - { - goto CleanupExit; - } - - // Create the Host string. - if (PhIsNullOrEmptyString(httpHostName = PhCreateStringEx( - httpComponents.lpszHostName, - httpComponents.dwHostNameLength * sizeof(WCHAR) - ))) - { - goto CleanupExit; - } - - // Create the Path string. - if (PhIsNullOrEmptyString(httpHostPath = PhCreateStringEx( - httpComponents.lpszUrlPath, - httpComponents.dwUrlPathLength * sizeof(WCHAR) - ))) - { - goto CleanupExit; - } - if (!NT_SUCCESS(status = PhCreateFileWin32( &fileHandle, PhGetString(context->FileName), @@ -513,26 +376,47 @@ NTSTATUS UploadFileThreadStart( goto CleanupExit; } - if (!(connectHandle = WinHttpConnect( - context->HttpHandle, - serviceInfo->HostName, - serviceInfo->HostPort, - 0 - ))) + // Create a user agent string. + phVersion = PhGetPhVersion(); + userAgent = PhConcatStrings2(L"ProcessHacker_", phVersion->Buffer); + + if (!PhHttpSocketCreate(&httpContext, userAgent->Buffer)) + { + PhClearReference(&phVersion); + PhClearReference(&userAgent); + goto CleanupExit; + } + + PhClearReference(&phVersion); + PhClearReference(&userAgent); + + if (!PhHttpSocketParseUrl( + context->UploadUrl, + &httpHostName, + &httpHostPath, + &httpHostPort + )) + { + context->ErrorCode = GetLastError(); + goto CleanupExit; + } + + if (!PhHttpSocketConnect( + httpContext, + PhGetString(httpHostName), + httpHostPort + )) { RaiseUploadError(context, L"Unable to connect to the service", GetLastError()); goto CleanupExit; } - if (!(requestHandle = WinHttpOpenRequest( - connectHandle, + if (!PhHttpSocketBeginRequest( + httpContext, L"POST", PhGetString(httpHostPath), - NULL, - WINHTTP_NO_REFERER, - WINHTTP_DEFAULT_ACCEPT_TYPES, - WINHTTP_FLAG_REFRESH | serviceInfo->HostFlags - ))) + PH_HTTP_FLAG_REFRESH | (httpHostPort == PH_HTTP_DEFAULT_HTTPS_PORT ? PH_HTTP_FLAG_SECURE : 0) + )) { RaiseUploadError(context, L"Unable to create the request", GetLastError()); goto CleanupExit; @@ -618,11 +502,10 @@ NTSTATUS UploadFileThreadStart( } // add headers - if (!WinHttpAddRequestHeaders( - requestHandle, + if (!PhHttpSocketAddRequestHeaders( + httpContext, httpRequestHeaders.String->Buffer, - -1L, - WINHTTP_ADDREQ_FLAG_REPLACE | WINHTTP_ADDREQ_FLAG_ADD + (ULONG)httpRequestHeaders.String->Length / sizeof(WCHAR) )) { RaiseUploadError(context, L"Unable to add request headers", GetLastError()); @@ -633,11 +516,10 @@ NTSTATUS UploadFileThreadStart( { PPH_STRING ajaxHeader = PhCreateString(L"X-Requested-With: XMLHttpRequest"); - WinHttpAddRequestHeaders( - requestHandle, + PhHttpSocketAddRequestHeaders( + httpContext, ajaxHeader->Buffer, - (ULONG)ajaxHeader->Length / sizeof(WCHAR), - WINHTTP_ADDREQ_FLAG_ADD + (ULONG)ajaxHeader->Length / sizeof(WCHAR) ); PhDereferenceObject(ajaxHeader); @@ -647,15 +529,7 @@ NTSTATUS UploadFileThreadStart( totalUploadLength = (ULONG)httpPostHeader.String->Length / sizeof(WCHAR) + context->TotalFileLength + (ULONG)httpPostFooter.String->Length / sizeof(WCHAR); // Send the request. - if (!WinHttpSendRequest( - requestHandle, - WINHTTP_NO_ADDITIONAL_HEADERS, - 0, - WINHTTP_NO_REQUEST_DATA, - 0, - totalUploadLength, - 0 - )) + if (!PhHttpSocketSendRequest(httpContext, NULL, totalUploadLength)) { RaiseUploadError(context, L"Unable to send the request", GetLastError()); goto CleanupExit; @@ -669,8 +543,8 @@ NTSTATUS UploadFileThreadStart( PhQuerySystemTime(&timeStart); // Write the header - if (!WinHttpWriteData( - requestHandle, + if (!PhHttpSocketWriteData( + httpContext, asciiPostData->Buffer, (ULONG)asciiPostData->Length, &totalPostHeaderWritten @@ -716,7 +590,7 @@ NTSTATUS UploadFileThreadStart( break; } - if (!WinHttpWriteData(requestHandle, buffer, (ULONG)isb.Information, &totalWriteLength)) + if (!PhHttpSocketWriteData(httpContext, buffer, (ULONG)isb.Information, &totalWriteLength)) { RaiseUploadError(context, L"Unable to upload the file data", GetLastError()); goto CleanupExit; @@ -762,8 +636,8 @@ NTSTATUS UploadFileThreadStart( } // Write the footer bytes - if (!WinHttpWriteData( - requestHandle, + if (!PhHttpSocketWriteData( + httpContext, asciiFooterData->Buffer, (ULONG)asciiFooterData->Length, &totalPostFooterWritten @@ -773,99 +647,92 @@ NTSTATUS UploadFileThreadStart( goto CleanupExit; } - if (!WinHttpReceiveResponse(requestHandle, NULL)) + if (!PhHttpSocketEndRequest(httpContext)) { RaiseUploadError(context, L"Unable to receive the response", GetLastError()); goto CleanupExit; } - if (!WinHttpQueryHeaders( - requestHandle, - WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, - NULL, - &httpStatus, - &httpStatusLength, - NULL + if (!PhHttpSocketQueryHeaderUlong( + httpContext, + PH_HTTP_QUERY_STATUS_CODE, + &httpStatus )) { RaiseUploadError(context, L"Unable to query http headers", GetLastError()); goto CleanupExit; } - if (httpStatus == HTTP_STATUS_OK || httpStatus == HTTP_STATUS_REDIRECT_METHOD || httpStatus == HTTP_STATUS_REDIRECT) + if (httpStatus == PH_HTTP_STATUS_OK || httpStatus == PH_HTTP_STATUS_REDIRECT_METHOD || httpStatus == PH_HTTP_STATUS_REDIRECT) { switch (context->Service) { case MENUITEM_VIRUSTOTAL_UPLOAD: case MENUITEM_VIRUSTOTAL_UPLOAD_SERVICE: { - PSTR buffer = NULL; - ULONG bufferLength; + PPH_BYTES jsonString; PVOID jsonRootObject; - if (!ReadRequestString(requestHandle, &buffer, &bufferLength)) + if (!(jsonString = PhHttpSocketDownloadString(httpContext, FALSE))) { RaiseUploadError(context, L"Unable to complete the request", GetLastError()); goto CleanupExit; } - if (jsonRootObject = PhCreateJsonParser(buffer)) + if (jsonRootObject = PhCreateJsonParser(jsonString->Buffer)) { - if (PhGetJsonValueAsLong64(jsonRootObject, "response_code") != 0) - goto CleanupExit; - - // PhZeroExtendToUtf16(PhGetJsonValueAsString(jsonRootObject, "resource")); - // PhZeroExtendToUtf16(PhGetJsonValueAsString(jsonRootObject, "scan_id")); - // PhZeroExtendToUtf16(PhGetJsonValueAsString(jsonRootObject, "sha256")); - // PhZeroExtendToUtf16(PhGetJsonValueAsString(jsonRootObject, "verbose_msg")); + INT64 errorCode = PhGetJsonValueAsLong64(jsonRootObject, "response_code"); + //PhGetJsonValueAsString(jsonRootObject, "scan_id"); + //PhGetJsonValueAsString(jsonRootObject, "verbose_msg"); - PhMoveReference(&context->LaunchCommand, PhGetJsonValueAsString(jsonRootObject, "permalink")); + if (errorCode != 1) + { + RaiseUploadError(context, L"VirusTotal API error", (ULONG)errorCode); + PhDereferenceObject(jsonString); + goto CleanupExit; + } + else + { + PhMoveReference(&context->LaunchCommand, PhGetJsonValueAsString(jsonRootObject, "permalink")); + } PhFreeJsonParser(jsonRootObject); } else { - ULONG httpUrlLength = 0; - - if (!WinHttpQueryOption(requestHandle, WINHTTP_OPTION_URL, NULL, &httpUrlLength)) - { - PPH_STRING httpUrlString = PhCreateStringEx(NULL, httpUrlLength); - - if (WinHttpQueryOption(requestHandle, WINHTTP_OPTION_URL, httpUrlString->Buffer, &httpUrlLength)) - { - PhSwapReference(&context->LaunchCommand, httpUrlString); - } - - PhDereferenceObject(httpUrlString); - } + RaiseUploadError(context, L"Unable to complete the request", RtlNtStatusToDosError(STATUS_FAIL_CHECK)); + goto CleanupExit; } + + PhDereferenceObject(jsonString); } break; case MENUITEM_JOTTI_UPLOAD: case MENUITEM_JOTTI_UPLOAD_SERVICE: { - PSTR buffer = NULL; - ULONG bufferLength; - PVOID rootJsonObject; + PPH_BYTES jsonString; + PVOID jsonRootObject; - if (!ReadRequestString(requestHandle, &buffer, &bufferLength)) + if (!(jsonString = PhHttpSocketDownloadString(httpContext, FALSE))) { RaiseUploadError(context, L"Unable to complete the request", GetLastError()); goto CleanupExit; } - if (rootJsonObject = PhCreateJsonParser(buffer)) + if (jsonRootObject = PhCreateJsonParser(jsonString->Buffer)) { PPH_STRING redirectUrl; - if (redirectUrl = PhGetJsonValueAsString(rootJsonObject, "redirecturl")) + if (redirectUrl = PhGetJsonValueAsString(jsonRootObject, "redirecturl")) { PhMoveReference(&context->LaunchCommand, PhFormatString(L"http://virusscan.jotti.org%s", redirectUrl->Buffer)); PhDereferenceObject(redirectUrl); } - PhFreeJsonParser(rootJsonObject); + PhFreeJsonParser(jsonRootObject); } + + PhDereferenceObject(jsonString); } break; } @@ -929,17 +796,11 @@ NTSTATUS UploadCheckThreadStart( { NTSTATUS status = STATUS_SUCCESS; BOOLEAN fileExists = FALSE; - BOOLEAN success = FALSE; LARGE_INTEGER fileSize64; PPH_BYTES subRequestBuffer = NULL; - HINTERNET connectHandle = NULL; - HINTERNET requestHandle = NULL; PSERVICE_INFO serviceInfo = NULL; - PPH_STRING hashString = NULL; PPH_STRING subObjectName = NULL; HANDLE fileHandle = NULL; - PPH_STRING phVersion = NULL; - PPH_STRING userAgent = NULL; PUPLOAD_CONTEXT context = (PUPLOAD_CONTEXT)Parameter; //context->Extension = VirusTotalGetCachedResult(context->FileName); @@ -988,51 +849,28 @@ NTSTATUS UploadCheckThreadStart( context->TotalFileLength = fileSize64.LowPart; } - // Create a user agent string. - phVersion = PhGetPhVersion(); - userAgent = PhConcatStrings2(L"ProcessHacker_", phVersion->Buffer); - - if (!(context->HttpHandle = WinHttpOpen( - userAgent->Buffer, - WindowsVersion >= WINDOWS_8_1 ? WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY : WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, - WINHTTP_NO_PROXY_NAME, - WINHTTP_NO_PROXY_BYPASS, - 0 - ))) - { - goto CleanupExit; - } - - if (WindowsVersion >= WINDOWS_8_1) - { - WinHttpSetOption( - context->HttpHandle, - WINHTTP_OPTION_DECOMPRESSION, - &(ULONG){ WINHTTP_DECOMPRESSION_FLAG_ALL }, - sizeof(ULONG) - ); - } - switch (context->Service) { case MENUITEM_VIRUSTOTAL_UPLOAD: case MENUITEM_VIRUSTOTAL_UPLOAD_SERVICE: { + PPH_STRING tempHashString = NULL; PSTR uploadUrl = NULL; PSTR quote = NULL; PVOID rootJsonObject; - if (!NT_SUCCESS(status = HashFileAndResetPosition(fileHandle, &fileSize64, Sha256HashAlgorithm, &hashString))) + if (!NT_SUCCESS(status = HashFileAndResetPosition(fileHandle, &fileSize64, Sha256HashAlgorithm, &tempHashString))) { RaiseUploadError(context, L"Unable to hash the file", RtlNtStatusToDosError(status)); goto CleanupExit; } - subObjectName = PhConcatStrings2(L"/file/upload/?sha256=", hashString->Buffer); + context->FileHash = tempHashString; + subObjectName = PhConcatStrings2(L"/file/upload/?sha256=", PhGetString(context->FileHash)); PhMoveReference(&context->LaunchCommand, PhFormatString( L"https://www.virustotal.com/file/%s/analysis/", - PhGetString(hashString) + PhGetString(context->FileHash) )); if (!(subRequestBuffer = PerformSubRequest( @@ -1048,9 +886,7 @@ NTSTATUS UploadCheckThreadStart( if (rootJsonObject = PhCreateJsonParser(subRequestBuffer->Buffer)) { - context->FileExists = PhGetJsonObjectBool(rootJsonObject, "file_exists"); - - if (context->FileExists) + if (context->FileExists = PhGetJsonObjectBool(rootJsonObject, "file_exists")) { INT64 detected = 0; INT64 detectedMax = 0; @@ -1088,11 +924,11 @@ NTSTATUS UploadCheckThreadStart( PPH_BYTES resource = VirusTotalGetCachedDbHash(); PhMoveReference(&context->UploadUrl, PhFormatString( - L"%s%s?apikey=%S&resource=%s", + L"%s%s?\x0061\x0070\x0069\x006B\x0065\x0079=%S&resource=%s", L"https://www.virustotal.com/", L"/vtapi/v2/file/scan", resource->Buffer, - PhGetString(hashString) + PhGetString(context->FileHash) )); PhClearReference(&resource); @@ -1100,9 +936,12 @@ NTSTATUS UploadCheckThreadStart( if (!PhIsNullOrEmptyString(context->UploadUrl)) { - success = TRUE; PostMessage(context->DialogHandle, UM_EXISTS, 0, 0); } + else + { + RaiseUploadError(context, L"Unable to parse the UploadUrl.", RtlNtStatusToDosError(STATUS_FAIL_CHECK)); + } } else { @@ -1111,13 +950,20 @@ NTSTATUS UploadCheckThreadStart( // No file found... Start the upload. if (!PhIsNullOrEmptyString(context->UploadUrl)) { - success = TRUE; PostMessage(context->DialogHandle, UM_UPLOAD, 0, 0); } + else + { + RaiseUploadError(context, L"Received invalid response.", RtlNtStatusToDosError(STATUS_FAIL_CHECK)); + } } PhFreeJsonParser(rootJsonObject); } + else + { + RaiseUploadError(context, L"Unable to parse the response.", RtlNtStatusToDosError(STATUS_FAIL_CHECK)); + } } break; case MENUITEM_JOTTI_UPLOAD: @@ -1129,31 +975,20 @@ NTSTATUS UploadCheckThreadStart( // No file found... Start the upload. if (!PhIsNullOrEmptyString(context->UploadUrl)) { - success = TRUE; PostMessage(context->DialogHandle, UM_UPLOAD, 0, 0); } + else + { + RaiseUploadError(context, L"Unable to parse the response.", RtlNtStatusToDosError(STATUS_FAIL_CHECK)); + } } break; } CleanupExit: - if (context->DialogHandle && !success) - { - PostMessage(context->DialogHandle, UM_ERROR, 0, 0); - } - - PhClearReference(&phVersion); - PhClearReference(&userAgent); - PhClearReference(&hashString); PhClearReference(&subObjectName); - PhClearReference(&subRequestBuffer); - - if (requestHandle) - WinHttpCloseHandle(requestHandle); - - if (connectHandle) - WinHttpCloseHandle(connectHandle); + PhClearReference(&subRequestBuffer); if (fileHandle) NtClose(fileHandle); @@ -1163,6 +998,34 @@ NTSTATUS UploadCheckThreadStart( return status; } +NTSTATUS UploadRecheckThreadStart( + _In_ PVOID Parameter + ) +{ + PUPLOAD_CONTEXT context = (PUPLOAD_CONTEXT)Parameter; + PVIRUSTOTAL_API_RESPONSE response; + + response = VirusTotalRequestFileReScan(context->FileHash); + + if (response->ResponseCode == 1) + PhMoveReference(&context->ReAnalyseUrl, response->PermaLink); + else + RaiseUploadError(context, L"VirusTotal API error", (ULONG)response->ResponseCode); + + if (!PhIsNullOrEmptyString(context->ReAnalyseUrl)) + { + PhShellExecute(NULL, PhGetString(context->ReAnalyseUrl), NULL); + //PostMessage(context->DialogHandle, UM_LAUNCH, 0, 0); + } + else + { + RaiseUploadError(context, L"Unable to complete the ReAnalyse request (please try again after a few minutes)", ERROR_INVALID_DATA); + } + + return STATUS_SUCCESS; +} + + LRESULT CALLBACK TaskDialogSubclassProc( _In_ HWND hwndDlg, _In_ UINT uMsg, @@ -1190,7 +1053,33 @@ LRESULT CALLBACK TaskDialogSubclassProc( break; case UM_EXISTS: { - ShowFileFoundDialog(context); + switch (PhGetIntegerSetting(SETTING_NAME_VIRUSTOTAL_DEFAULT_ACTION)) + { + //default: + case 1: + { + ShowVirusTotalProgressDialog(context); + } + break; + case 2: + { + if (!PhIsNullOrEmptyString(context->ReAnalyseUrl)) + PhShellExecute(hwndDlg, PhGetString(context->ReAnalyseUrl), NULL); + } + break; + case 3: + { + if (!PhIsNullOrEmptyString(context->LaunchCommand)) + { + PhShellExecute(hwndDlg, PhGetString(context->LaunchCommand), NULL); + } + } + break; + default: + { + ShowFileFoundDialog(context); + } + } } break; case UM_LAUNCH: diff --git a/plugins/OnlineChecks/virustotal.c b/plugins/OnlineChecks/virustotal.c index 3d2f2d5e80fb..630575214429 100644 --- a/plugins/OnlineChecks/virustotal.c +++ b/plugins/OnlineChecks/virustotal.c @@ -290,341 +290,404 @@ VOID VirusTotalBuildJsonArray( } } -PSTR VirusTotalSendHttpRequest( +PPH_BYTES VirusTotalSendHttpRequest( _In_ PPH_BYTES JsonArray ) { - HANDLE fileHandle = INVALID_HANDLE_VALUE; - HINTERNET httpSessionHandle = NULL; - HINTERNET connectHandle = NULL; - HINTERNET requestHandle = NULL; - PSTR subRequestBuffer = NULL; - PPH_STRING phVersion = NULL; - PPH_STRING userAgent = NULL; - PPH_STRING urlString = NULL; - - phVersion = PhGetPhVersion(); - userAgent = PhConcatStrings2(L"ProcessHacker_", phVersion->Buffer); - - if (!(httpSessionHandle = WinHttpOpen( - userAgent->Buffer, - WindowsVersion >= WINDOWS_8_1 ? WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY : WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, - WINHTTP_NO_PROXY_NAME, - WINHTTP_NO_PROXY_BYPASS, - 0 - ))) - { + PPH_BYTES subRequestBuffer = NULL; + PPH_HTTP_CONTEXT httpContext = NULL; + PPH_STRING versionString = NULL; + PPH_STRING userAgentString = NULL; + PPH_STRING urlPathString = NULL; + + versionString = PhGetPhVersion(); + userAgentString = PhConcatStrings2(L"ProcessHacker_", versionString->Buffer); + + if (!PhHttpSocketCreate(&httpContext, PhGetString(userAgentString))) + goto CleanupExit; + + if (!PhHttpSocketConnect(httpContext, L"www.virustotal.com", PH_HTTP_DEFAULT_HTTPS_PORT)) goto CleanupExit; - } - if (WindowsVersion >= WINDOWS_8_1) { - WinHttpSetOption( - httpSessionHandle, - WINHTTP_OPTION_DECOMPRESSION, - &(ULONG){ WINHTTP_DECOMPRESSION_FLAG_GZIP | WINHTTP_DECOMPRESSION_FLAG_DEFLATE }, - sizeof(ULONG) + PPH_BYTES resourceString = VirusTotalGetCachedDbHash(); + + urlPathString = PhFormatString( + L"%s%s%s%s%S", + L"/partners", + L"/sysinternals", + L"/file-reports", + L"?\x0061\x0070\x0069\x006B\x0065\x0079=", + resourceString->Buffer ); + + PhClearReference(&resourceString); } - if (!(connectHandle = WinHttpConnect( - httpSessionHandle, - L"www.virustotal.com", - INTERNET_DEFAULT_HTTPS_PORT, - 0 - ))) + if (!PhHttpSocketBeginRequest( + httpContext, + L"POST", + urlPathString->Buffer, + PH_HTTP_FLAG_REFRESH | PH_HTTP_FLAG_SECURE + )) { goto CleanupExit; } - PPH_BYTES resourceString = VirusTotalGetCachedDbHash(); + if (!PhHttpSocketAddRequestHeaders(httpContext, L"Content-Type: application/json", 0)) + goto CleanupExit; - urlString = PhFormatString( - L"%s%s%s%s%S", - L"/partners", - L"/sysinternals", - L"/file-reports", - L"?apikey=", - resourceString->Buffer - ); + if (!PhHttpSocketSendRequest(httpContext, JsonArray->Buffer, (ULONG)JsonArray->Length)) + goto CleanupExit; - PhClearReference(&resourceString); + if (!PhHttpSocketEndRequest(httpContext)) + goto CleanupExit; - if (!(requestHandle = WinHttpOpenRequest( - connectHandle, - L"POST", - PhGetString(urlString), - NULL, - WINHTTP_NO_REFERER, - WINHTTP_DEFAULT_ACCEPT_TYPES, - WINHTTP_FLAG_SECURE - ))) - { - PhClearReference(&urlString); + if (!(subRequestBuffer = PhHttpSocketDownloadString(httpContext, FALSE))) goto CleanupExit; - } - PhClearReference(&urlString); +CleanupExit: + + if (httpContext) + PhHttpSocketDestroy(httpContext); + + PhClearReference(&urlPathString); + PhClearReference(&versionString); + PhClearReference(&userAgentString); - if (!WinHttpAddRequestHeaders(requestHandle, L"Content-Type: application/json", -1L, 0)) + if (JsonArray) + PhDereferenceObject(JsonArray); + + return subRequestBuffer; +} + +PVIRUSTOTAL_FILE_REPORT VirusTotalRequestFileReport( + _In_ PPH_STRING FileHash + ) +{ + PVIRUSTOTAL_FILE_REPORT result = NULL; + PPH_BYTES jsonString = NULL; + PPH_HTTP_CONTEXT httpContext = NULL; + PPH_STRING versionString = NULL; + PPH_STRING userAgentString = NULL; + PPH_STRING urlPathString = NULL; + PVOID jsonRootObject = NULL; + PVOID jsonScanObject; + + versionString = PhGetPhVersion(); + userAgentString = PhConcatStrings2(L"ProcessHacker_", versionString->Buffer); + + if (!PhHttpSocketCreate( + &httpContext, + PhGetString(userAgentString) + )) { goto CleanupExit; } - if (!WinHttpSendRequest( - requestHandle, - WINHTTP_NO_ADDITIONAL_HEADERS, - 0, - JsonArray->Buffer, - (ULONG)JsonArray->Length, - (ULONG)JsonArray->Length, - 0 + if (!PhHttpSocketConnect( + httpContext, + L"www.virustotal.com", + PH_HTTP_DEFAULT_HTTPS_PORT )) { goto CleanupExit; } - if (WinHttpReceiveResponse(requestHandle, NULL)) { - BYTE buffer[PAGE_SIZE]; - ULONG allocatedLength; - ULONG dataLength; - ULONG returnLength; + PPH_BYTES resourceString = VirusTotalGetCachedDbHash(); + + urlPathString = PhFormatString( + L"%s%s%s%s%s%S%s%s", + L"/vtapi", + L"/v2", + L"/file", + L"/report", + L"?\x0061\x0070\x0069\x006B\x0065\x0079=", + resourceString->Buffer, + L"&resource=", + FileHash->Buffer + ); - allocatedLength = sizeof(buffer); - subRequestBuffer = PhAllocate(allocatedLength); - dataLength = 0; + PhClearReference(&resourceString); + } - while (WinHttpReadData(requestHandle, buffer, PAGE_SIZE, &returnLength)) + if (!PhHttpSocketBeginRequest( + httpContext, + L"POST", + PhGetString(urlPathString), + PH_HTTP_FLAG_REFRESH | PH_HTTP_FLAG_SECURE + )) + { + goto CleanupExit; + } + + if (!PhHttpSocketAddRequestHeaders(httpContext, L"Content-Type: application/json", 0)) + goto CleanupExit; + + if (!PhHttpSocketSendRequest(httpContext, NULL, 0)) + goto CleanupExit; + + if (!PhHttpSocketEndRequest(httpContext)) + goto CleanupExit; + + if (!(jsonString = PhHttpSocketDownloadString(httpContext, FALSE))) + goto CleanupExit; + + if (!(jsonRootObject = PhCreateJsonParser(jsonString->Buffer))) + goto CleanupExit; + + result = PhAllocate(sizeof(VIRUSTOTAL_FILE_REPORT)); + memset(result, 0, sizeof(VIRUSTOTAL_FILE_REPORT)); + + result->ResponseCode = PhGetJsonValueAsLong64(jsonRootObject, "response_code"); + result->StatusMessage = PhGetJsonValueAsString(jsonRootObject, "verbose_msg"); + result->PermaLink = PhGetJsonValueAsString(jsonRootObject, "permalink"); + result->ScanDate = PhGetJsonValueAsString(jsonRootObject, "scan_date"); + result->ScanId = PhGetJsonValueAsString(jsonRootObject, "scan_id"); + result->Total = PhFormatUInt64(PhGetJsonValueAsLong64(jsonRootObject, "total"), FALSE); + result->Positives = PhFormatUInt64(PhGetJsonValueAsLong64(jsonRootObject, "positives"), FALSE); + //result->Md5 = PhGetJsonValueAsString(jsonRootObject, "md5"); + //result->Sha1 = PhGetJsonValueAsString(jsonRootObject, "sha1"); + //result->Sha256 = PhGetJsonValueAsString(jsonRootObject, "sha256"); + + if (jsonScanObject = PhGetJsonObject(jsonRootObject, "scans")) + { + PPH_LIST jsonArrayList; + + if (jsonArrayList = PhGetJsonObjectAsArrayList(jsonScanObject)) { - if (returnLength == 0) - break; + result->ScanResults = PhCreateList(jsonArrayList->Count); - if (allocatedLength < dataLength + returnLength) + for (ULONG i = 0; i < jsonArrayList->Count; i++) { - allocatedLength *= 2; - subRequestBuffer = PhReAllocate(subRequestBuffer, allocatedLength); - } + PVIRUSTOTAL_FILE_REPORT_RESULT entry; + PJSON_ARRAY_LIST_OBJECT object = jsonArrayList->Items[i]; - memcpy(subRequestBuffer + dataLength, buffer, returnLength); - dataLength += returnLength; - } + entry = PhAllocate(sizeof(VIRUSTOTAL_FILE_REPORT_RESULT)); + memset(entry, 0, sizeof(VIRUSTOTAL_FILE_REPORT_RESULT)); - if (allocatedLength < dataLength + 1) - { - allocatedLength++; - subRequestBuffer = PhReAllocate(subRequestBuffer, allocatedLength); - } + entry->Vendor = PhConvertUtf8ToUtf16(object->Key); + entry->Detected = PhGetJsonObjectBool(object->Entry, "detected"); + entry->EngineVersion = PhGetJsonValueAsString(object->Entry, "version"); + entry->DetectionName = PhGetJsonValueAsString(object->Entry, "result"); + entry->DatabaseDate = PhGetJsonValueAsString(object->Entry, "update"); + PhAddItemList(result->ScanResults, entry); + + PhFree(object); + } - // Ensure that the buffer is null-terminated. - subRequestBuffer[dataLength] = 0; + PhDereferenceObject(jsonArrayList); + } } CleanupExit: - if (requestHandle) - WinHttpCloseHandle(requestHandle); + if (httpContext) + PhHttpSocketDestroy(httpContext); - if (connectHandle) - WinHttpCloseHandle(connectHandle); + if (jsonRootObject) + PhFreeJsonParser(jsonRootObject); - if (httpSessionHandle) - WinHttpCloseHandle(httpSessionHandle); + PhClearReference(&jsonString); + PhClearReference(&versionString); + PhClearReference(&userAgentString); - if (JsonArray) - PhDereferenceObject(JsonArray); - - return subRequestBuffer; + return result; } -PVIRUSTOTAL_FILE_REPORT_RESULT VirusTotalSendHttpFileReportRequest( +PVIRUSTOTAL_API_RESPONSE VirusTotalRequestFileReScan( _In_ PPH_STRING FileHash ) { - NTSTATUS status = STATUS_SUCCESS; - HANDLE fileHandle = INVALID_HANDLE_VALUE; - HINTERNET httpSessionHandle = NULL; - HINTERNET connectHandle = NULL; - HINTERNET requestHandle = NULL; - PSTR subRequestBuffer = NULL; - PPH_STRING phVersion = NULL; - PPH_STRING userAgent = NULL; - PPH_STRING urlString = NULL; - - phVersion = PhGetPhVersion(); - userAgent = PhConcatStrings2(L"ProcessHacker_", phVersion->Buffer); - - if (!(httpSessionHandle = WinHttpOpen( - userAgent->Buffer, - WindowsVersion >= WINDOWS_8_1 ? WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY : WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, - WINHTTP_NO_PROXY_NAME, - WINHTTP_NO_PROXY_BYPASS, - 0 - ))) + PVIRUSTOTAL_API_RESPONSE result = NULL; + PPH_BYTES jsonString = NULL; + PPH_HTTP_CONTEXT httpContext = NULL; + PPH_STRING versionString = NULL; + PPH_STRING userAgentString = NULL; + PPH_STRING urlPathString = NULL; + PVOID jsonRootObject = NULL; + + versionString = PhGetPhVersion(); + userAgentString = PhConcatStrings2(L"ProcessHacker_", versionString->Buffer); + + if (!PhHttpSocketCreate( + &httpContext, + PhGetString(userAgentString) + )) { goto CleanupExit; } - if (WindowsVersion >= WINDOWS_8_1) - { - WinHttpSetOption( - httpSessionHandle, - WINHTTP_OPTION_DECOMPRESSION, - &(ULONG){ WINHTTP_DECOMPRESSION_FLAG_GZIP | WINHTTP_DECOMPRESSION_FLAG_DEFLATE }, - sizeof(ULONG) - ); - } - - if (!(connectHandle = WinHttpConnect( - httpSessionHandle, + if (!PhHttpSocketConnect( + httpContext, L"www.virustotal.com", - INTERNET_DEFAULT_HTTPS_PORT, - 0 - ))) + PH_HTTP_DEFAULT_HTTPS_PORT + )) { goto CleanupExit; } - PPH_BYTES resourceString = VirusTotalGetCachedDbHash(); - - urlString = PhFormatString( - L"%s%s%s%s%S%s%s", - L"/vtapi", - L"/v2", - L"/file", - L"/report", - L"?apikey=", - resourceString->Buffer, - L"&resource=", - PhGetString(FileHash) - ); + { + PPH_BYTES resourceString = VirusTotalGetCachedDbHash(); + + urlPathString = PhFormatString( + L"%s%s%s%s%s%S%s%s", + L"/vtapi", + L"/v2", + L"/file", + L"/rescan", + L"?\x0061\x0070\x0069\x006B\x0065\x0079=", + resourceString->Buffer, + L"&resource=", + FileHash->Buffer + ); - PhClearReference(&resourceString); + PhClearReference(&resourceString); + } - if (!(requestHandle = WinHttpOpenRequest( - connectHandle, + if (!PhHttpSocketBeginRequest( + httpContext, L"POST", - PhGetString(urlString), - NULL, - WINHTTP_NO_REFERER, - WINHTTP_DEFAULT_ACCEPT_TYPES, - WINHTTP_FLAG_SECURE - ))) + PhGetString(urlPathString), + PH_HTTP_FLAG_REFRESH | PH_HTTP_FLAG_SECURE + )) { goto CleanupExit; } - if (!WinHttpAddRequestHeaders(requestHandle, L"Content-Type: application/json", -1L, 0)) + if (!PhHttpSocketAddRequestHeaders(httpContext, L"Content-Type: application/json", 0)) goto CleanupExit; - if (!WinHttpSendRequest( - requestHandle, - WINHTTP_NO_ADDITIONAL_HEADERS, - 0, - WINHTTP_NO_REQUEST_DATA, - 0, - WINHTTP_IGNORE_REQUEST_TOTAL_LENGTH, - 0 - )) - { + if (!PhHttpSocketSendRequest(httpContext, NULL, 0)) goto CleanupExit; - } - if (WinHttpReceiveResponse(requestHandle, NULL)) - { - BYTE buffer[PAGE_SIZE]; - ULONG allocatedLength; - ULONG dataLength; - ULONG returnLength; + if (!PhHttpSocketEndRequest(httpContext)) + goto CleanupExit; + + if (!(jsonString = PhHttpSocketDownloadString(httpContext, FALSE))) + goto CleanupExit; - allocatedLength = sizeof(buffer); - subRequestBuffer = PhAllocate(allocatedLength); - dataLength = 0; + if (!(jsonRootObject = PhCreateJsonParser(jsonString->Buffer))) + goto CleanupExit; - while (WinHttpReadData(requestHandle, buffer, PAGE_SIZE, &returnLength)) - { - if (returnLength == 0) - break; + result = PhAllocate(sizeof(VIRUSTOTAL_API_RESPONSE)); + memset(result, 0, sizeof(VIRUSTOTAL_API_RESPONSE)); - if (allocatedLength < dataLength + returnLength) - { - allocatedLength *= 2; - subRequestBuffer = PhReAllocate(subRequestBuffer, allocatedLength); - } + result->ResponseCode = PhGetJsonValueAsLong64(jsonRootObject, "response_code"); + result->StatusMessage = PhGetJsonValueAsString(jsonRootObject, "verbose_msg"); + result->PermaLink = PhGetJsonValueAsString(jsonRootObject, "permalink"); + result->ScanId = PhGetJsonValueAsString(jsonRootObject, "scan_id"); - memcpy(subRequestBuffer + dataLength, buffer, returnLength); - dataLength += returnLength; - } +CleanupExit: - if (allocatedLength < dataLength + 1) - { - allocatedLength++; - subRequestBuffer = PhReAllocate(subRequestBuffer, allocatedLength); - } + if (httpContext) + PhHttpSocketDestroy(httpContext); - subRequestBuffer[dataLength] = 0; - } + if (jsonRootObject) + PhFreeJsonParser(jsonRootObject); -CleanupExit: + PhClearReference(&jsonString); + PhClearReference(&versionString); + PhClearReference(&userAgentString); - PhClearReference(&urlString); + return result; +} - if (requestHandle) - WinHttpCloseHandle(requestHandle); +PVIRUSTOTAL_API_RESPONSE VirusTotalRequestIpAddressReport( + _In_ PPH_STRING IpAddress + ) +{ + PVIRUSTOTAL_API_RESPONSE result = NULL; + PPH_BYTES jsonString = NULL; + PPH_HTTP_CONTEXT httpContext = NULL; + PPH_STRING versionString = NULL; + PPH_STRING userAgentString = NULL; + PPH_STRING urlPathString = NULL; + PVOID jsonRootObject = NULL; + + versionString = PhGetPhVersion(); + userAgentString = PhConcatStrings2(L"ProcessHacker_", versionString->Buffer); + + if (!PhHttpSocketCreate( + &httpContext, + PhGetString(userAgentString) + )) + { + goto CleanupExit; + } - if (connectHandle) - WinHttpCloseHandle(connectHandle); + if (!PhHttpSocketConnect( + httpContext, + L"www.virustotal.com", + PH_HTTP_DEFAULT_HTTPS_PORT + )) + { + goto CleanupExit; + } - if (httpSessionHandle) - WinHttpCloseHandle(httpSessionHandle); + { + PPH_BYTES resourceString = VirusTotalGetCachedDbHash(); + + urlPathString = PhFormatString( + L"%s%s%s%s%s%S%s%s", + L"/vtapi", + L"/v2", + L"/ip-address", + L"/report", + L"?\x0061\x0070\x0069\x006B\x0065\x0079=", + resourceString->Buffer, + L"&ip=", + IpAddress->Buffer + ); + + PhClearReference(&resourceString); + } + + if (!PhHttpSocketBeginRequest( + httpContext, + L"POST", + PhGetString(urlPathString), + PH_HTTP_FLAG_REFRESH | PH_HTTP_FLAG_SECURE + )) + { + goto CleanupExit; + } + if (!PhHttpSocketAddRequestHeaders(httpContext, L"Content-Type: application/json", 0)) + goto CleanupExit; - PVOID jsonRootObject; - //PVOID jsonScanObject; - PVIRUSTOTAL_FILE_REPORT_RESULT result; + if (!PhHttpSocketSendRequest(httpContext, NULL, 0)) + goto CleanupExit; - if (!(jsonRootObject = PhCreateJsonParser(subRequestBuffer))) + if (!PhHttpSocketEndRequest(httpContext)) + goto CleanupExit; + + if (!(jsonString = PhHttpSocketDownloadString(httpContext, FALSE))) goto CleanupExit; - if (PhGetJsonValueAsLong64(jsonRootObject, "response_code") != 0) + if (!(jsonRootObject = PhCreateJsonParser(jsonString->Buffer))) goto CleanupExit; - result = PhAllocate(sizeof(VIRUSTOTAL_FILE_REPORT_RESULT)); - memset(result, 0, sizeof(VIRUSTOTAL_FILE_REPORT_RESULT)); + result = PhAllocate(sizeof(VIRUSTOTAL_API_RESPONSE)); + memset(result, 0, sizeof(VIRUSTOTAL_API_RESPONSE)); - result->Total = PhFormatUInt64(PhGetJsonValueAsLong64(jsonRootObject, "total"), FALSE); - result->Positives = PhFormatUInt64(PhGetJsonValueAsLong64(jsonRootObject, "positives"), FALSE); - result->Resource = PhGetJsonValueAsString(jsonRootObject, "resource"); - result->ScanId = PhGetJsonValueAsString(jsonRootObject, "scan_id"); - result->Md5 = PhGetJsonValueAsString(jsonRootObject, "md5"); - result->Sha1 = PhGetJsonValueAsString(jsonRootObject, "sha1"); - result->Sha256 = PhGetJsonValueAsString(jsonRootObject, "sha256"); - result->ScanDate = PhGetJsonValueAsString(jsonRootObject, "scan_date"); - result->Permalink = PhGetJsonValueAsString(jsonRootObject, "permalink"); - result->StatusMessage = PhGetJsonValueAsString(jsonRootObject, "verbose_msg"); + //result->ResponseCode = PhGetJsonValueAsLong64(jsonRootObject, "response_code"); + //result->StatusMessage = PhGetJsonValueAsString(jsonRootObject, "verbose_msg"); + //result->PermaLink = PhGetJsonValueAsString(jsonRootObject, "permalink"); + //result->ScanId = PhGetJsonValueAsString(jsonRootObject, "scan_id"); + +CleanupExit: - //if (jsonScanObject = PhGetJsonObject(jsonRootObject, "scans")) - //{ - // PPH_LIST jsonArrayList; - // - // if (jsonArrayList = JsonGetObjectArrayList(jsonScanObject)) - // { - // result->ScanResults = PhCreateList(jsonArrayList->Count); - // - // for (ULONG i = 0; i < jsonArrayList->Count; i++) - // { - // PJSON_ARRAY_LIST_OBJECT object = jsonArrayList->Items[i]; - // //BOOLEAN detected = GetJsonValueAsBool(object->Entry, "detected") == TRUE; - // //PSTR version = PhGetJsonValueAsString(object->Entry, "version"); - // //PSTR result = PhGetJsonValueAsString(object->Entry, "result"); - // //PSTR update = PhGetJsonValueAsString(object->Entry, "update"); - // - // PhFree(object); - // } - // - // PhDereferenceObject(jsonArrayList); - // } - //} + if (httpContext) + PhHttpSocketDestroy(httpContext); + + if (jsonRootObject) + PhFreeJsonParser(jsonRootObject); + + PhClearReference(&jsonString); + PhClearReference(&versionString); + PhClearReference(&userAgentString); return result; } @@ -649,7 +712,7 @@ NTSTATUS NTAPI VirusTotalProcessApiThread( { ULONG i; INT64 resultLength; - PSTR jsonApiResult = NULL; + PPH_BYTES jsonApiResult = NULL; PVOID jsonArray; PVOID rootJsonObject = NULL; PVOID dataJsonObject; @@ -696,7 +759,7 @@ NTSTATUS NTAPI VirusTotalProcessApiThread( if (!(jsonApiResult = VirusTotalSendHttpRequest(PhConvertUtf16ToUtf8(jsonArrayToSendString->Buffer)))) goto CleanupExit; - if (!(rootJsonObject = PhCreateJsonParser(jsonApiResult))) + if (!(rootJsonObject = PhCreateJsonParser(jsonApiResult->Buffer))) goto CleanupExit; if (!(dataJsonObject = PhGetJsonObject(rootJsonObject, "data"))) @@ -747,7 +810,7 @@ NTSTATUS NTAPI VirusTotalProcessApiThread( // PhClearReference(&result->Permalink); // PhClearReference(&result->FileHash); // PhClearReference(&result->DetectionRatio); - // + PhFree(result); } @@ -769,7 +832,7 @@ NTSTATUS NTAPI VirusTotalProcessApiThread( if (jsonApiResult) { - PhFree(jsonApiResult); + PhDereferenceObject(jsonApiResult); } if (resultTempList) From 0297b865a3ed838b0413b9af5aa81ec249dbbdeb Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 3 Nov 2017 13:18:41 +1100 Subject: [PATCH 0548/2058] Update plugin manager window --- ProcessHacker/plugman.c | 1250 +++++++++++++++++++++++++++++++-------- 1 file changed, 994 insertions(+), 256 deletions(-) diff --git a/ProcessHacker/plugman.c b/ProcessHacker/plugman.c index 65d84a0767ed..b05852f3bb21 100644 --- a/ProcessHacker/plugman.c +++ b/ProcessHacker/plugman.c @@ -3,6 +3,7 @@ * plugins * * Copyright (C) 2010-2011 wj32 + * Copyright (C) 2017 dmex * * This file is part of Process Hacker. * @@ -21,265 +22,596 @@ */ #include - +#include +#include #include +#include #include -#include +#include -#define IS_PLUGIN_LOADED(Plugin) (!!(Plugin)->AppContext.AppName.Buffer) -#define STR_OR_DEFAULT(String, Default) ((String) ? (String) : (Default)) +#define WM_PH_PLUGINS_SHOWDIALOG (WM_APP + 401) +#define WM_PH_PLUGINS_SHOWPROPERTIES (WM_APP + 402) -static HWND PluginsLv; -static PPH_PLUGIN SelectedPlugin; -static PPH_LIST DisabledPluginInstances; // fake PH_PLUGIN structures for disabled plugins -static PPH_HASHTABLE DisabledPluginLookup; // list of all disabled plugins (including fake structures) by PH_PLUGIN address +static HANDLE PhPluginsThreadHandle = NULL; +static HWND PhPluginsWindowHandle = NULL; +static PH_EVENT PhPluginsInitializedEvent = PH_EVENT_INIT; -INT_PTR CALLBACK PhpPluginsDlgProc( +typedef struct _PH_PLUGMAN_CONTEXT +{ + PH_LAYOUT_MANAGER LayoutManager; + RECT MinimumSize; + + HFONT NormalFontHandle; + HFONT TitleFontHandle; + + HWND WindowHandle; + HWND TreeNewHandle; + ULONG TreeNewSortColumn; + PH_SORT_ORDER TreeNewSortOrder; + PPH_HASHTABLE NodeHashtable; + PPH_LIST NodeList; +} PH_PLUGMAN_CONTEXT, *PPH_PLUGMAN_CONTEXT; + +typedef enum _PH_PLUGIN_TREE_ITEM_MENU +{ + PH_PLUGIN_TREE_ITEM_MENU_UNINSTALL, + PH_PLUGIN_TREE_ITEM_MENU_DISABLE, + PH_PLUGIN_TREE_ITEM_MENU_PROPERTIES +} PH_PLUGIN_TREE_ITEM_MENU; + +typedef enum _PH_PLUGIN_TREE_COLUMN_ITEM +{ + PH_PLUGIN_TREE_COLUMN_ITEM_NAME, + PH_PLUGIN_TREE_COLUMN_ITEM_AUTHOR, + PH_PLUGIN_TREE_COLUMN_ITEM_VERSION, + PH_PLUGIN_TREE_COLUMN_ITEM_MAXIMUM +} PH_PLUGIN_TREE_COLUMN_ITEM; + +typedef struct _PH_PLUGIN_TREE_ROOT_NODE +{ + PH_TREENEW_NODE Node; + + BOOLEAN PluginOptions; + PPH_PLUGIN PluginInstance; + + PPH_STRING InternalName; + PPH_STRING Name; + PPH_STRING Version; + PPH_STRING Author; + PPH_STRING Description; + + PH_STRINGREF TextCache[PH_PLUGIN_TREE_COLUMN_ITEM_MAXIMUM]; +} PH_PLUGIN_TREE_ROOT_NODE, *PPH_PLUGIN_TREE_ROOT_NODE; + +INT_PTR CALLBACK PhpPluginPropertiesDlgProc( _In_ HWND hwndDlg, _In_ UINT uMsg, _In_ WPARAM wParam, _In_ LPARAM lParam ); -VOID PhShowPluginsDialog( - _In_ HWND ParentWindowHandle +ULONG PhpDisabledPluginsCount( + VOID + ); + +INT_PTR CALLBACK PhpPluginsDisabledDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +#pragma region Plugin TreeList + +#define SORT_FUNCTION(Column) PluginsTreeNewCompare##Column +#define BEGIN_SORT_FUNCTION(Column) static int __cdecl PluginsTreeNewCompare##Column( \ + _In_ void *_context, \ + _In_ const void *_elem1, \ + _In_ const void *_elem2 \ + ) \ +{ \ + PPH_PLUGIN_TREE_ROOT_NODE node1 = *(PPH_PLUGIN_TREE_ROOT_NODE*)_elem1; \ + PPH_PLUGIN_TREE_ROOT_NODE node2 = *(PPH_PLUGIN_TREE_ROOT_NODE*)_elem2; \ + int sortResult = 0; + +#define END_SORT_FUNCTION \ + if (sortResult == 0) \ + sortResult = uintptrcmp((ULONG_PTR)node1->Node.Index, (ULONG_PTR)node2->Node.Index); \ + \ + return PhModifySort(sortResult, ((PPH_PLUGMAN_CONTEXT)_context)->TreeNewSortOrder); \ +} + +BEGIN_SORT_FUNCTION(Name) +{ + sortResult = PhCompareString(node1->Name, node2->Name, TRUE); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(Author) +{ + sortResult = PhCompareString(node1->Author, node2->Author, TRUE); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(Version) +{ + sortResult = PhCompareString(node1->Version, node2->Version, TRUE); +} +END_SORT_FUNCTION + +VOID PluginsLoadSettingsTreeList( + _Inout_ PPH_PLUGMAN_CONTEXT Context ) { - if (PhPluginsEnabled) - { - DialogBox( - PhInstanceHandle, - MAKEINTRESOURCE(IDD_PLUGINS), - ParentWindowHandle, - PhpPluginsDlgProc - ); - } - else - { - PhShowInformation(ParentWindowHandle, - L"Plugins are not enabled. To use plugins enable them in Options and restart Process Hacker."); - } + PPH_STRING settings; + + settings = PhGetStringSetting(L"PluginManagerTreeListColumns"); + PhCmLoadSettings(Context->TreeNewHandle, &settings->sr); + PhDereferenceObject(settings); } -PWSTR PhpGetPluginBaseName( +VOID PluginsSaveSettingsTreeList( + _Inout_ PPH_PLUGMAN_CONTEXT Context + ) +{ + PPH_STRING settings; + + settings = PhCmSaveSettings(Context->TreeNewHandle); + PhSetStringSetting2(L"PluginManagerTreeListColumns", &settings->sr); + PhDereferenceObject(settings); +} + +BOOLEAN PluginsNodeHashtableEqualFunction( + _In_ PVOID Entry1, + _In_ PVOID Entry2 + ) +{ + PPH_PLUGIN_TREE_ROOT_NODE node1 = *(PPH_PLUGIN_TREE_ROOT_NODE *)Entry1; + PPH_PLUGIN_TREE_ROOT_NODE node2 = *(PPH_PLUGIN_TREE_ROOT_NODE *)Entry2; + + return PhEqualString(node1->InternalName, node2->InternalName, TRUE); +} + +ULONG PluginsNodeHashtableHashFunction( + _In_ PVOID Entry + ) +{ + return PhHashStringRef(&(*(PPH_PLUGIN_TREE_ROOT_NODE*)Entry)->InternalName->sr, TRUE); +} + +VOID DestroyPluginsNode( + _In_ PPH_PLUGIN_TREE_ROOT_NODE Node + ) +{ + PhClearReference(&Node->InternalName); + PhClearReference(&Node->Name); + PhClearReference(&Node->Version); + PhClearReference(&Node->Author); + PhClearReference(&Node->Description); + + PhFree(Node); +} + +PPH_PLUGIN_TREE_ROOT_NODE AddPluginsNode( + _Inout_ PPH_PLUGMAN_CONTEXT Context, _In_ PPH_PLUGIN Plugin ) { - if (Plugin->FileName) - { - PH_STRINGREF pathNamePart; - PH_STRINGREF baseNamePart; + PPH_PLUGIN_TREE_ROOT_NODE pluginNode; + PH_IMAGE_VERSION_INFO versionInfo; - if (PhSplitStringRefAtLastChar(&Plugin->FileName->sr, '\\', &pathNamePart, &baseNamePart)) - return baseNamePart.Buffer; - else - return Plugin->FileName->Buffer; - } - else + pluginNode = PhAllocate(sizeof(PH_PLUGIN_TREE_ROOT_NODE)); + memset(pluginNode, 0, sizeof(PH_PLUGIN_TREE_ROOT_NODE)); + + PhInitializeTreeNewNode(&pluginNode->Node); + + memset(pluginNode->TextCache, 0, sizeof(PH_STRINGREF) * PH_PLUGIN_TREE_COLUMN_ITEM_MAXIMUM); + pluginNode->Node.TextCache = pluginNode->TextCache; + pluginNode->Node.TextCacheSize = PH_PLUGIN_TREE_COLUMN_ITEM_MAXIMUM; + + pluginNode->PluginInstance = Plugin; + pluginNode->PluginOptions = Plugin->Information.HasOptions; + pluginNode->InternalName = PhCreateString2(&Plugin->Name); + pluginNode->Name = PhCreateString(Plugin->Information.DisplayName); + pluginNode->Author = PhCreateString(Plugin->Information.Author); + pluginNode->Description = PhCreateString(Plugin->Information.Description); + + if (PhInitializeImageVersionInfo(&versionInfo, Plugin->FileName->Buffer)) { - // Fake disabled plugin. - return Plugin->Name.Buffer; + pluginNode->Version = PhReferenceObject(versionInfo.FileVersion); + PhDeleteImageVersionInfo(&versionInfo); } + + PhAddEntryHashtable(Context->NodeHashtable, &pluginNode); + PhAddItemList(Context->NodeList, pluginNode); + + TreeNew_NodesStructured(Context->TreeNewHandle); + + return pluginNode; } -PWSTR PhpGetPluginDisableButtonText( - _In_ PWSTR BaseName +PPH_PLUGIN_TREE_ROOT_NODE FindPluginsNode( + _In_ PPH_PLUGMAN_CONTEXT Context, + _In_ PPH_STRING InternalName ) { - PH_STRINGREF baseName; + PH_PLUGIN_TREE_ROOT_NODE lookupPluginsNode; + PPH_PLUGIN_TREE_ROOT_NODE lookupPluginsNodePtr = &lookupPluginsNode; + PPH_PLUGIN_TREE_ROOT_NODE *pluginsNode; + + lookupPluginsNode.InternalName = InternalName; - PhInitializeStringRefLongHint(&baseName, BaseName); + pluginsNode = (PPH_PLUGIN_TREE_ROOT_NODE*)PhFindEntryHashtable( + Context->NodeHashtable, + &lookupPluginsNodePtr + ); - if (PhIsPluginDisabled(&baseName)) - return L"Enable"; + if (pluginsNode) + return *pluginsNode; else - return L"Disable"; + return NULL; } -VOID PhpRefreshPluginDetails( - _In_ HWND hwndDlg +VOID RemovePluginsNode( + _In_ PPH_PLUGMAN_CONTEXT Context, + _In_ PPH_PLUGIN_TREE_ROOT_NODE Node ) { - PPH_STRING fileName; - PH_IMAGE_VERSION_INFO versionInfo; + ULONG index = 0; - if (SelectedPlugin && SelectedPlugin->FileName) // if there's no FileName, then it's a fake disabled plugin instance + PhRemoveEntryHashtable(Context->NodeHashtable, &Node); + + if ((index = PhFindItemList(Context->NodeList, Node)) != -1) { - fileName = SelectedPlugin->FileName; + PhRemoveItemList(Context->NodeList, index); + } - SetDlgItemText(hwndDlg, IDC_NAME, SelectedPlugin->Information.DisplayName ? SelectedPlugin->Information.DisplayName : L"(unnamed)"); - SetDlgItemText(hwndDlg, IDC_INTERNALNAME, SelectedPlugin->Name.Buffer); - SetDlgItemText(hwndDlg, IDC_AUTHOR, SelectedPlugin->Information.Author); - SetDlgItemText(hwndDlg, IDC_FILENAME, fileName->Buffer); - SetDlgItemText(hwndDlg, IDC_DESCRIPTION, SelectedPlugin->Information.Description); - SetDlgItemText(hwndDlg, IDC_URL, SelectedPlugin->Information.Url); + DestroyPluginsNode(Node); + TreeNew_NodesStructured(Context->TreeNewHandle); +} + +VOID UpdatePluginsNode( + _In_ PPH_PLUGMAN_CONTEXT Context, + _In_ PPH_PLUGIN_TREE_ROOT_NODE Node + ) +{ + memset(Node->TextCache, 0, sizeof(PH_STRINGREF) * PH_PLUGIN_TREE_COLUMN_ITEM_MAXIMUM); - if (PhInitializeImageVersionInfo(&versionInfo, fileName->Buffer)) + PhInvalidateTreeNewNode(&Node->Node, TN_CACHE_COLOR); + TreeNew_NodesStructured(Context->TreeNewHandle); +} + +BOOLEAN NTAPI PluginsTreeNewCallback( + _In_ HWND hwnd, + _In_ PH_TREENEW_MESSAGE Message, + _In_opt_ PVOID Parameter1, + _In_opt_ PVOID Parameter2, + _In_opt_ PVOID Context + ) +{ + PPH_PLUGMAN_CONTEXT context = Context; + PPH_PLUGIN_TREE_ROOT_NODE node; + + switch (Message) + { + case TreeNewGetChildren: { - SetDlgItemText(hwndDlg, IDC_VERSION, PhGetStringOrDefault(versionInfo.FileVersion, L"Unknown")); - PhDeleteImageVersionInfo(&versionInfo); + PPH_TREENEW_GET_CHILDREN getChildren = Parameter1; + node = (PPH_PLUGIN_TREE_ROOT_NODE)getChildren->Node; + + if (!getChildren->Node) + { + static PVOID sortFunctions[] = + { + SORT_FUNCTION(Name), + SORT_FUNCTION(Author), + SORT_FUNCTION(Version) + }; + int (__cdecl *sortFunction)(void *, const void *, const void *); + + if (context->TreeNewSortColumn < PH_PLUGIN_TREE_COLUMN_ITEM_MAXIMUM) + sortFunction = sortFunctions[context->TreeNewSortColumn]; + else + sortFunction = NULL; + + if (sortFunction) + { + qsort_s(context->NodeList->Items, context->NodeList->Count, sizeof(PVOID), sortFunction, context); + } + + getChildren->Children = (PPH_TREENEW_NODE *)context->NodeList->Items; + getChildren->NumberOfChildren = context->NodeList->Count; + } } - else + return TRUE; + case TreeNewIsLeaf: { - SetDlgItemText(hwndDlg, IDC_VERSION, L"Unknown"); + PPH_TREENEW_IS_LEAF isLeaf = (PPH_TREENEW_IS_LEAF)Parameter1; + node = (PPH_PLUGIN_TREE_ROOT_NODE)isLeaf->Node; + + isLeaf->IsLeaf = TRUE; } + return TRUE; + case TreeNewGetCellText: + { + PPH_TREENEW_GET_CELL_TEXT getCellText = (PPH_TREENEW_GET_CELL_TEXT)Parameter1; + node = (PPH_PLUGIN_TREE_ROOT_NODE)getCellText->Node; - ShowWindow(GetDlgItem(hwndDlg, IDC_OPENURL), SelectedPlugin->Information.Url ? SW_SHOW : SW_HIDE); - EnableWindow(GetDlgItem(hwndDlg, IDC_DISABLE), TRUE); - SetDlgItemText(hwndDlg, IDC_DISABLE, PhpGetPluginDisableButtonText(PhpGetPluginBaseName(SelectedPlugin))); - EnableWindow(GetDlgItem(hwndDlg, IDC_OPTIONS), SelectedPlugin->Information.HasOptions); - } - else - { - SetDlgItemText(hwndDlg, IDC_NAME, L"N/A"); - SetDlgItemText(hwndDlg, IDC_VERSION, L"N/A"); - SetDlgItemText(hwndDlg, IDC_INTERNALNAME, L"N/A"); - SetDlgItemText(hwndDlg, IDC_AUTHOR, L"N/A"); - SetDlgItemText(hwndDlg, IDC_URL, L"N/A"); - SetDlgItemText(hwndDlg, IDC_FILENAME, L"N/A"); - SetDlgItemText(hwndDlg, IDC_DESCRIPTION, L"N/A"); + switch (getCellText->Id) + { + case PH_PLUGIN_TREE_COLUMN_ITEM_NAME: + getCellText->Text = PhGetStringRef(node->Name); + break; + case PH_PLUGIN_TREE_COLUMN_ITEM_AUTHOR: + getCellText->Text = PhGetStringRef(node->Author); + break; + case PH_PLUGIN_TREE_COLUMN_ITEM_VERSION: + getCellText->Text = PhGetStringRef(node->Version); + break; + default: + return FALSE; + } - ShowWindow(GetDlgItem(hwndDlg, IDC_OPENURL), SW_HIDE); + getCellText->Flags = TN_CACHE; + } + return TRUE; + case TreeNewGetNodeColor: + { + PPH_TREENEW_GET_NODE_COLOR getNodeColor = Parameter1; + node = (PPH_PLUGIN_TREE_ROOT_NODE)getNodeColor->Node; - if (SelectedPlugin) + getNodeColor->Flags = TN_CACHE | TN_AUTO_FORECOLOR; + } + return TRUE; + case TreeNewSortChanged: { - // This is a disabled plugin. - EnableWindow(GetDlgItem(hwndDlg, IDC_DISABLE), TRUE); - SetDlgItemText(hwndDlg, IDC_DISABLE, PhpGetPluginDisableButtonText(SelectedPlugin->Name.Buffer)); + TreeNew_GetSort(hwnd, &context->TreeNewSortColumn, &context->TreeNewSortOrder); + // Force a rebuild to sort the items. + TreeNew_NodesStructured(hwnd); } - else + return TRUE; + case TreeNewKeyDown: + { + PPH_TREENEW_KEY_EVENT keyEvent = Parameter1; + + switch (keyEvent->VirtualKey) + { + case 'C': + if (GetKeyState(VK_CONTROL) < 0) + SendMessage(context->WindowHandle, WM_COMMAND, ID_OBJECT_COPY, 0); + break; + case 'A': + if (GetKeyState(VK_CONTROL) < 0) + TreeNew_SelectRange(context->TreeNewHandle, 0, -1); + break; + case VK_DELETE: + SendMessage(context->WindowHandle, WM_COMMAND, ID_OBJECT_CLOSE, 0); + break; + } + } + return TRUE; + case TreeNewLeftDoubleClick: + { + PPH_TREENEW_MOUSE_EVENT mouseEvent = Parameter1; + + SendMessage(context->WindowHandle, WM_COMMAND, WM_PH_PLUGINS_SHOWPROPERTIES, (LPARAM)mouseEvent); + } + return TRUE; + case TreeNewContextMenu: { - EnableWindow(GetDlgItem(hwndDlg, IDC_DISABLE), FALSE); - SetDlgItemText(hwndDlg, IDC_DISABLE, L"Disable"); + PPH_TREENEW_CONTEXT_MENU contextMenuEvent = Parameter1; + + SendMessage(context->WindowHandle, WM_COMMAND, ID_SHOWCONTEXTMENU, (LPARAM)contextMenuEvent); } + return TRUE; + //case TreeNewHeaderRightClick: + // { + // PH_TN_COLUMN_MENU_DATA data; + // + // data.TreeNewHandle = hwnd; + // data.MouseEvent = Parameter1; + // data.DefaultSortColumn = 0; + // data.DefaultSortOrder = AscendingSortOrder; + // PhInitializeTreeNewColumnMenu(&data); + // + // data.Selection = PhShowEMenu(data.Menu, hwnd, PH_EMENU_SHOW_LEFTRIGHT, + // PH_ALIGN_LEFT | PH_ALIGN_TOP, data.MouseEvent->ScreenLocation.x, data.MouseEvent->ScreenLocation.y); + // PhHandleTreeNewColumnMenu(&data); + // PhDeleteTreeNewColumnMenu(&data); + // } + // return TRUE; + case TreeNewCustomDraw: + { + PPH_TREENEW_CUSTOM_DRAW customDraw = Parameter1; + RECT rect = customDraw->CellRect; + node = (PPH_PLUGIN_TREE_ROOT_NODE)customDraw->Node; - EnableWindow(GetDlgItem(hwndDlg, IDC_OPTIONS), FALSE); + switch (customDraw->Column->Id) + { + case PH_PLUGIN_TREE_COLUMN_ITEM_NAME: + { + PH_STRINGREF text; + SIZE nameSize; + SIZE textSize; + + rect.left += PH_SCALE_DPI(15); + rect.top += PH_SCALE_DPI(5); + rect.right -= PH_SCALE_DPI(5); + rect.bottom -= PH_SCALE_DPI(8); + + // top + SetTextColor(customDraw->Dc, RGB(0x0, 0x0, 0x0)); + SelectObject(customDraw->Dc, context->TitleFontHandle); + text = PhIsNullOrEmptyString(node->Name) ? PhGetStringRef(node->InternalName) : PhGetStringRef(node->Name); + GetTextExtentPoint32(customDraw->Dc, text.Buffer, (ULONG)text.Length / 2, &nameSize); + DrawText(customDraw->Dc, text.Buffer, (ULONG)text.Length / 2, &rect, DT_TOP | DT_LEFT | DT_END_ELLIPSIS | DT_SINGLELINE); + + // bottom + SetTextColor(customDraw->Dc, RGB(0x64, 0x64, 0x64)); + SelectObject(customDraw->Dc, context->NormalFontHandle); + text = PhGetStringRef(node->Description); + GetTextExtentPoint32(customDraw->Dc, text.Buffer, (ULONG)text.Length / 2, &textSize); + DrawText( + customDraw->Dc, + text.Buffer, + (ULONG)text.Length / 2, + &rect, + DT_BOTTOM | DT_LEFT | DT_END_ELLIPSIS | DT_SINGLELINE + ); + } + break; + } + } + return TRUE; } + + return FALSE; } -BOOLEAN PhpIsPluginLoadedByBaseName( - _In_ PPH_STRINGREF BaseName +VOID ClearPluginsTree( + _In_ PPH_PLUGMAN_CONTEXT Context ) { - PPH_AVL_LINKS links; + for (ULONG i = 0; i < Context->NodeList->Count; i++) + DestroyPluginsNode(Context->NodeList->Items[i]); - // Extremely inefficient code follows. - // TODO: Make this better. + PhClearHashtable(Context->NodeHashtable); + PhClearList(Context->NodeList); - for (links = PhMinimumElementAvlTree(&PhPluginsByName); links; links = PhSuccessorElementAvlTree(links)) - { - PPH_PLUGIN plugin = CONTAINING_RECORD(links, PH_PLUGIN, Links); - PH_STRINGREF pluginBaseName; + TreeNew_NodesStructured(Context->TreeNewHandle); +} - PhInitializeStringRefLongHint(&pluginBaseName, PhpGetPluginBaseName(plugin)); +PPH_PLUGIN_TREE_ROOT_NODE GetSelectedPluginsNode( + _In_ PPH_PLUGMAN_CONTEXT Context + ) +{ + PPH_PLUGIN_TREE_ROOT_NODE windowNode = NULL; + + for (ULONG i = 0; i < Context->NodeList->Count; i++) + { + windowNode = Context->NodeList->Items[i]; - if (PhEqualStringRef(&pluginBaseName, BaseName, TRUE)) - return TRUE; + if (windowNode->Node.Selected) + return windowNode; } - return FALSE; + return NULL; } -PPH_PLUGIN PhpCreateDisabledPlugin( - _In_ PPH_STRINGREF BaseName +VOID GetSelectedPluginsNodes( + _In_ PPH_PLUGMAN_CONTEXT Context, + _Out_ PPH_PLUGIN_TREE_ROOT_NODE **PluginsNodes, + _Out_ PULONG NumberOfPluginsNodes ) { - PPH_PLUGIN plugin; + PPH_LIST list; + + list = PhCreateList(2); + + for (ULONG i = 0; i < Context->NodeList->Count; i++) + { + PPH_PLUGIN_TREE_ROOT_NODE node = (PPH_PLUGIN_TREE_ROOT_NODE)Context->NodeList->Items[i]; - plugin = PhAllocate(sizeof(PH_PLUGIN)); - memset(plugin, 0, sizeof(PH_PLUGIN)); + if (node->Node.Selected) + { + PhAddItemList(list, node); + } + } - plugin->Name.Length = BaseName->Length; - plugin->Name.Buffer = PhAllocate(BaseName->Length + sizeof(WCHAR)); - memcpy(plugin->Name.Buffer, BaseName->Buffer, BaseName->Length); - plugin->Name.Buffer[BaseName->Length / 2] = 0; + *PluginsNodes = PhAllocateCopy(list->Items, sizeof(PVOID) * list->Count); + *NumberOfPluginsNodes = list->Count; - return plugin; + PhDereferenceObject(list); } -VOID PhpFreeDisabledPlugin( - _In_ PPH_PLUGIN Plugin +VOID InitializePluginsTree( + _Inout_ PPH_PLUGMAN_CONTEXT Context ) { - PhFree(Plugin->Name.Buffer); - PhFree(Plugin); + Context->NodeList = PhCreateList(100); + Context->NodeHashtable = PhCreateHashtable( + sizeof(PPH_PLUGIN_TREE_ROOT_NODE), + PluginsNodeHashtableEqualFunction, + PluginsNodeHashtableHashFunction, + 100 + ); + + Context->NormalFontHandle = PhCreateCommonFont(-10, FW_NORMAL, NULL); + Context->TitleFontHandle = PhCreateCommonFont(-14, FW_BOLD, NULL); + + PhSetControlTheme(Context->TreeNewHandle, L"explorer"); + + TreeNew_SetCallback(Context->TreeNewHandle, PluginsTreeNewCallback, Context); + TreeNew_SetRowHeight(Context->TreeNewHandle, PH_SCALE_DPI(48)); + + PhAddTreeNewColumnEx2(Context->TreeNewHandle, PH_PLUGIN_TREE_COLUMN_ITEM_NAME, TRUE, L"Plugin", 80, PH_ALIGN_LEFT, 0, 0, TN_COLUMN_FLAG_CUSTOMDRAW); + PhAddTreeNewColumnEx2(Context->TreeNewHandle, PH_PLUGIN_TREE_COLUMN_ITEM_AUTHOR, TRUE, L"Author", 80, PH_ALIGN_LEFT, 1, 0, 0); + PhAddTreeNewColumnEx2(Context->TreeNewHandle, PH_PLUGIN_TREE_COLUMN_ITEM_VERSION, TRUE, L"Version", 80, PH_ALIGN_CENTER, 2, DT_CENTER, 0); + + TreeNew_SetTriState(Context->TreeNewHandle, TRUE); + + PluginsLoadSettingsTreeList(Context); } -VOID PhpAddDisabledPlugins( - VOID +VOID DeletePluginsTree( + _In_ PPH_PLUGMAN_CONTEXT Context ) { - PPH_STRING disabled; - PH_STRINGREF remainingPart; - PH_STRINGREF part; - PPH_PLUGIN disabledPlugin; - PPH_STRING displayText; - INT lvItemIndex; + if (Context->TitleFontHandle) + DeleteObject(Context->TitleFontHandle); + if (Context->NormalFontHandle) + DeleteObject(Context->NormalFontHandle); - disabled = PhGetStringSetting(L"DisabledPlugins"); - remainingPart = disabled->sr; + PluginsSaveSettingsTreeList(Context); - while (remainingPart.Length != 0) - { - PhSplitStringRefAtChar(&remainingPart, '|', &part, &remainingPart); + for (ULONG i = 0; i < Context->NodeList->Count; i++) + DestroyPluginsNode(Context->NodeList->Items[i]); - if (part.Length != 0) - { - if (!PhpIsPluginLoadedByBaseName(&part)) - { - disabledPlugin = PhpCreateDisabledPlugin(&part); - PhAddItemList(DisabledPluginInstances, disabledPlugin); - PhAddItemSimpleHashtable(DisabledPluginLookup, disabledPlugin, NULL); - - displayText = PhCreateString2(&part); - lvItemIndex = PhAddListViewItem(PluginsLv, MAXINT, displayText->Buffer, disabledPlugin); - PhDereferenceObject(displayText); - } - } - } - - PhDereferenceObject(disabled); + PhDereferenceObject(Context->NodeHashtable); + PhDereferenceObject(Context->NodeList); } -VOID PhpUpdateDisabledPlugin( - _In_ HWND hwndDlg, - _In_ INT ItemIndex, - _In_ PPH_PLUGIN Plugin, - _In_ BOOLEAN NewDisabledState +#pragma endregion + +PWSTR PhpGetPluginBaseName( + _In_ PPH_PLUGIN Plugin ) { - if (NewDisabledState) + if (Plugin->FileName) { - PhAddItemSimpleHashtable(DisabledPluginLookup, Plugin, NULL); + PH_STRINGREF pathNamePart; + PH_STRINGREF baseNamePart; + + if (PhSplitStringRefAtLastChar(&Plugin->FileName->sr, '\\', &pathNamePart, &baseNamePart)) + return baseNamePart.Buffer; + else + return Plugin->FileName->Buffer; } else { - PhRemoveItemSimpleHashtable(DisabledPluginLookup, Plugin); - } - - if (!IS_PLUGIN_LOADED(Plugin)) - { - assert(!NewDisabledState); - ListView_DeleteItem(PluginsLv, ItemIndex); + // Fake disabled plugin. + return Plugin->Name.Buffer; } - - InvalidateRect(PluginsLv, NULL, TRUE); - - ShowWindow(GetDlgItem(hwndDlg, IDC_INSTRUCTION), SW_SHOW); } -static COLORREF PhpPluginColorFunction( - _In_ INT Index, - _In_ PVOID Param, - _In_opt_ PVOID Context +VOID PhpEnumerateLoadedPlugins( + _In_ PPH_PLUGMAN_CONTEXT Context ) { - PPH_PLUGIN plugin = Param; + PPH_AVL_LINKS links; - if (PhFindItemSimpleHashtable(DisabledPluginLookup, plugin)) - return RGB(0x77, 0x77, 0x77); // fake disabled plugin + for (links = PhMinimumElementAvlTree(&PhPluginsByName); links; links = PhSuccessorElementAvlTree(links)) + { + PPH_PLUGIN plugin = CONTAINING_RECORD(links, PH_PLUGIN, Links); + PH_STRINGREF pluginBaseName; + + PhInitializeStringRefLongHint(&pluginBaseName, PhpGetPluginBaseName(plugin)); - return GetSysColor(COLOR_WINDOW); + if (PhIsPluginDisabled(&pluginBaseName)) + continue; + + AddPluginsNode(Context, plugin); + } } INT_PTR CALLBACK PhpPluginsDlgProc( @@ -289,112 +621,378 @@ INT_PTR CALLBACK PhpPluginsDlgProc( _In_ LPARAM lParam ) { + PPH_PLUGMAN_CONTEXT context; + + if (uMsg == WM_INITDIALOG) + { + context = PhAllocate(sizeof(PH_PLUGMAN_CONTEXT)); + memset(context, 0, sizeof(PH_PLUGMAN_CONTEXT)); + + SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)context); + } + else + { + context = (PPH_PLUGMAN_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom()); + } + + if (!context) + return FALSE; + switch (uMsg) { case WM_INITDIALOG: { - PPH_AVL_LINKS links; + SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER))); + SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER))); - PhCenterWindow(hwndDlg, PhMainWndHandle); + context->WindowHandle = hwndDlg; + context->TreeNewHandle = GetDlgItem(hwndDlg, IDC_PLUGINTREE); - PluginsLv = GetDlgItem(hwndDlg, IDC_LIST); - PhSetListViewStyle(PluginsLv, FALSE, TRUE); - PhSetControlTheme(PluginsLv, L"explorer"); - PhAddListViewColumn(PluginsLv, 0, 0, 0, LVCFMT_LEFT, 280, L"Name"); - PhAddListViewColumn(PluginsLv, 1, 1, 1, LVCFMT_LEFT, 100, L"Author"); - PhSetExtendedListView(PluginsLv); - ExtendedListView_SetItemColorFunction(PluginsLv, PhpPluginColorFunction); + InitializePluginsTree(context); - DisabledPluginLookup = PhCreateSimpleHashtable(10); + PhInitializeLayoutManager(&context->LayoutManager, hwndDlg); + PhAddLayoutItem(&context->LayoutManager, context->TreeNewHandle, NULL, PH_ANCHOR_ALL); + PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_DISABLED), NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_LEFT); + PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDOK), NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_RIGHT); - for (links = PhMinimumElementAvlTree(&PhPluginsByName); links; links = PhSuccessorElementAvlTree(links)) - { - PPH_PLUGIN plugin = CONTAINING_RECORD(links, PH_PLUGIN, Links); - INT lvItemIndex; - PH_STRINGREF baseNameSr; - - lvItemIndex = PhAddListViewItem(PluginsLv, MAXINT, plugin->Information.DisplayName ? plugin->Information.DisplayName : plugin->Name.Buffer, plugin); + if (PhGetIntegerPairSetting(L"PluginManagerWindowPosition").X != 0) + PhLoadWindowPlacementFromSetting(L"PluginManagerWindowPosition", L"PluginManagerWindowSize", hwndDlg); + else + PhCenterWindow(hwndDlg, PhMainWndHandle); - if (plugin->Information.Author) - PhSetListViewSubItem(PluginsLv, lvItemIndex, 1, plugin->Information.Author); + context->MinimumSize.left = 0; + context->MinimumSize.top = 0; + context->MinimumSize.right = 300; + context->MinimumSize.bottom = 100; + MapDialogRect(hwndDlg, &context->MinimumSize); - PhInitializeStringRefLongHint(&baseNameSr, PhpGetPluginBaseName(plugin)); + PhpEnumerateLoadedPlugins(context); + TreeNew_AutoSizeColumn(context->TreeNewHandle, PH_PLUGIN_TREE_COLUMN_ITEM_NAME, TN_AUTOSIZE_REMAINING_SPACE); + SetWindowText(GetDlgItem(hwndDlg, IDC_DISABLED), PhaFormatString(L"Disabled Plugins (%lu)", PhpDisabledPluginsCount())->Buffer); + } + break; + case WM_DESTROY: + { + PhSaveWindowPlacementToSetting(L"PluginManagerWindowPosition", L"PluginManagerWindowSize", hwndDlg); - if (PhIsPluginDisabled(&baseNameSr)) - PhAddItemSimpleHashtable(DisabledPluginLookup, plugin, NULL); - } + PhDeleteLayoutManager(&context->LayoutManager); - DisabledPluginInstances = PhCreateList(10); - PhpAddDisabledPlugins(); + DeletePluginsTree(context); - ExtendedListView_SortItems(PluginsLv); + PhFree(context); - SelectedPlugin = NULL; - PhpRefreshPluginDetails(hwndDlg); + PostQuitMessage(0); } break; - case WM_DESTROY: + case WM_PH_PLUGINS_SHOWDIALOG: { - ULONG i; - - for (i = 0; i < DisabledPluginInstances->Count; i++) - PhpFreeDisabledPlugin(DisabledPluginInstances->Items[i]); + if (IsMinimized(hwndDlg)) + ShowWindow(hwndDlg, SW_RESTORE); + else + ShowWindow(hwndDlg, SW_SHOW); - PhDereferenceObject(DisabledPluginInstances); - PhDereferenceObject(DisabledPluginLookup); + SetForegroundWindow(hwndDlg); } break; case WM_COMMAND: { - switch (LOWORD(wParam)) + switch (GET_WM_COMMAND_ID(wParam, lParam)) { - case IDCANCEL: case IDOK: - EndDialog(hwndDlg, IDOK); + case IDCANCEL: + { + DestroyWindow(hwndDlg); + } break; - case IDC_DISABLE: + case IDC_DISABLED: { - if (SelectedPlugin) - { - PWSTR baseName; - PH_STRINGREF baseNameRef; - BOOLEAN newDisabledState; - - baseName = PhpGetPluginBaseName(SelectedPlugin); - PhInitializeStringRef(&baseNameRef, baseName); - newDisabledState = !PhIsPluginDisabled(&baseNameRef); - PhSetPluginDisabled(&baseNameRef, newDisabledState); - PhpUpdateDisabledPlugin(hwndDlg, PhFindListViewItemByFlags(PluginsLv, -1, LVNI_SELECTED), SelectedPlugin, newDisabledState); + DialogBox( + PhInstanceHandle, + MAKEINTRESOURCE(IDD_PLUGINSDISABLED), + hwndDlg, + PhpPluginsDisabledDlgProc + ); - SetDlgItemText(hwndDlg, IDC_DISABLE, PhpGetPluginDisableButtonText(baseName)); - } + ClearPluginsTree(context); + PhpEnumerateLoadedPlugins(context); + TreeNew_AutoSizeColumn(context->TreeNewHandle, PH_PLUGIN_TREE_COLUMN_ITEM_NAME, TN_AUTOSIZE_REMAINING_SPACE); + SetWindowText(GetDlgItem(hwndDlg, IDC_DISABLED), PhaFormatString(L"Disabled Plugins (%lu)", PhpDisabledPluginsCount())->Buffer); } break; - case IDC_OPTIONS: + case ID_SHOWCONTEXTMENU: { - if (SelectedPlugin && IS_PLUGIN_LOADED(SelectedPlugin)) + PPH_EMENU menu; + PPH_EMENU_ITEM selectedItem; + //PPH_EMENU_ITEM uninstallItem; + PPH_TREENEW_CONTEXT_MENU contextMenuEvent = (PPH_TREENEW_CONTEXT_MENU)lParam; + PPH_PLUGIN_TREE_ROOT_NODE selectedNode = (PPH_PLUGIN_TREE_ROOT_NODE)contextMenuEvent->Node; + + if (!selectedNode) + break; + + menu = PhCreateEMenu(); + //PhInsertEMenuItem(menu, uninstallItem = PhCreateEMenuItem(0, PH_PLUGIN_TREE_ITEM_MENU_UNINSTALL, L"Uninstall", NULL, NULL), -1); + //PhInsertEMenuItem(menu, PhCreateEMenuItem(PH_EMENU_SEPARATOR, 0, NULL, NULL, NULL), -1); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, PH_PLUGIN_TREE_ITEM_MENU_DISABLE, L"Disable", NULL, NULL), -1); + PhInsertEMenuItem(menu, PhCreateEMenuItem(PH_EMENU_SEPARATOR, 0, NULL, NULL, NULL), -1); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, PH_PLUGIN_TREE_ITEM_MENU_PROPERTIES, L"Properties", NULL, NULL), -1); + + //if (!PhGetOwnTokenAttributes().Elevated) + //{ + // HBITMAP shieldBitmap; + // + // if (shieldBitmap = PhGetShieldBitmap()) + // uninstallItem->Bitmap = shieldBitmap; + //} + + selectedItem = PhShowEMenu( + menu, + hwndDlg, + PH_EMENU_SHOW_LEFTRIGHT, + PH_ALIGN_LEFT | PH_ALIGN_TOP, + contextMenuEvent->Location.x, + contextMenuEvent->Location.y + ); + + if (selectedItem && selectedItem->Id != -1) { - PhInvokeCallback(PhGetPluginCallback(SelectedPlugin, PluginCallbackShowOptions), hwndDlg); + switch (selectedItem->Id) + { + case PH_PLUGIN_TREE_ITEM_MENU_UNINSTALL: + { + //if (PhShowConfirmMessage( + // hwndDlg, + // L"Uninstall", + // PhGetString(selectedNode->Name), + // L"Changes may require a restart to take effect...", + // TRUE + // )) + //{ + // + //} + } + break; + case PH_PLUGIN_TREE_ITEM_MENU_DISABLE: + { + PWSTR baseName; + PH_STRINGREF baseNameRef; + + baseName = PhpGetPluginBaseName(selectedNode->PluginInstance); + PhInitializeStringRef(&baseNameRef, baseName); + + PhSetPluginDisabled(&baseNameRef, TRUE); + + ClearPluginsTree(context); + PhpEnumerateLoadedPlugins(context); + TreeNew_AutoSizeColumn(context->TreeNewHandle, PH_PLUGIN_TREE_COLUMN_ITEM_NAME, TN_AUTOSIZE_REMAINING_SPACE); + SetWindowText(GetDlgItem(hwndDlg, IDC_DISABLED), PhaFormatString(L"Disabled Plugins (%lu)", PhpDisabledPluginsCount())->Buffer); + } + break; + case PH_PLUGIN_TREE_ITEM_MENU_PROPERTIES: + { + DialogBoxParam( + PhInstanceHandle, + MAKEINTRESOURCE(IDD_PLUGINPROPERTIES), + hwndDlg, + PhpPluginPropertiesDlgProc, + (LPARAM)selectedNode->PluginInstance + ); + } + break; + } } } break; - case IDC_CLEANUP: + case WM_PH_PLUGINS_SHOWPROPERTIES: { - if (PhShowMessage2( + PPH_TREENEW_MOUSE_EVENT mouseEvent = (PPH_TREENEW_MOUSE_EVENT)lParam; + PPH_PLUGIN_TREE_ROOT_NODE selectedNode = (PPH_PLUGIN_TREE_ROOT_NODE)mouseEvent->Node; + + if (!selectedNode) + break; + + DialogBoxParam( + PhInstanceHandle, + MAKEINTRESOURCE(IDD_PLUGINPROPERTIES), hwndDlg, - TDCBF_YES_BUTTON | TDCBF_NO_BUTTON, - TD_INFORMATION_ICON, - L"Do you want to clean up unused plugin settings?", - L"" - ) == IDYES) - { - PhClearIgnoredSettings(); - } + PhpPluginPropertiesDlgProc, + (LPARAM)selectedNode->PluginInstance + ); } break; - case IDC_OPENURL: + } + } + break; + case WM_SIZE: + { + PhLayoutManagerLayout(&context->LayoutManager); + TreeNew_AutoSizeColumn(context->TreeNewHandle, PH_PLUGIN_TREE_COLUMN_ITEM_NAME, TN_AUTOSIZE_REMAINING_SPACE); + } + break; + case WM_SIZING: + { + PhResizingMinimumSize((PRECT)lParam, wParam, context->MinimumSize.right, context->MinimumSize.bottom); + } + break; + } + + return FALSE; +} + +NTSTATUS PhpPluginsDialogThreadStart( + _In_ PVOID Parameter + ) +{ + BOOL result; + MSG message; + PH_AUTO_POOL autoPool; + + PhInitializeAutoPool(&autoPool); + + PhPluginsWindowHandle = CreateDialog( + PhInstanceHandle, + MAKEINTRESOURCE(IDD_PLUGINS), + NULL, + PhpPluginsDlgProc + ); + + PhSetEvent(&PhPluginsInitializedEvent); + + while (result = GetMessage(&message, NULL, 0, 0)) + { + if (result == -1) + break; + + if (!IsDialogMessage(PhPluginsWindowHandle, &message)) + { + TranslateMessage(&message); + DispatchMessage(&message); + } + + PhDrainAutoPool(&autoPool); + } + + PhDeleteAutoPool(&autoPool); + PhResetEvent(&PhPluginsInitializedEvent); + + if (PhPluginsThreadHandle) + { + NtClose(PhPluginsThreadHandle); + PhPluginsThreadHandle = NULL; + } + + return STATUS_SUCCESS; +} + +VOID PhShowPluginsDialog( + _In_ HWND ParentWindowHandle + ) +{ + if (PhPluginsEnabled) + { + if (!PhPluginsThreadHandle) + { + if (!(PhPluginsThreadHandle = PhCreateThread(0, PhpPluginsDialogThreadStart, NULL))) + { + PhShowStatus(PhMainWndHandle, L"Unable to create the window.", 0, GetLastError()); + return; + } + + PhWaitForEvent(&PhPluginsInitializedEvent, NULL); + } + + PostMessage(PhPluginsWindowHandle, WM_PH_PLUGINS_SHOWDIALOG, 0, 0); + } + else + { + PhShowInformation2( + ParentWindowHandle, + L"Plugins are not enabled.", + L"To use plugins enable them in Options and restart Process Hacker." + ); + } +} + +VOID PhpRefreshPluginDetails( + _In_ HWND hwndDlg, + _In_ PPH_PLUGIN SelectedPlugin + ) +{ + PPH_STRING fileName; + PH_IMAGE_VERSION_INFO versionInfo; + + fileName = SelectedPlugin->FileName; + + SetDlgItemText(hwndDlg, IDC_NAME, SelectedPlugin->Information.DisplayName ? SelectedPlugin->Information.DisplayName : L"(unnamed)"); + SetDlgItemText(hwndDlg, IDC_INTERNALNAME, SelectedPlugin->Name.Buffer); + SetDlgItemText(hwndDlg, IDC_AUTHOR, SelectedPlugin->Information.Author); + SetDlgItemText(hwndDlg, IDC_FILENAME, PH_AUTO_T(PH_STRING, PhGetBaseName(fileName))->Buffer); + SetDlgItemText(hwndDlg, IDC_DESCRIPTION, SelectedPlugin->Information.Description); + SetDlgItemText(hwndDlg, IDC_URL, SelectedPlugin->Information.Url); + + if (PhInitializeImageVersionInfo(&versionInfo, fileName->Buffer)) + { + SetDlgItemText(hwndDlg, IDC_VERSION, PhGetStringOrDefault(versionInfo.FileVersion, L"Unknown")); + PhDeleteImageVersionInfo(&versionInfo); + } + else + { + SetDlgItemText(hwndDlg, IDC_VERSION, L"Unknown"); + } + + ShowWindow(GetDlgItem(hwndDlg, IDC_OPENURL), SelectedPlugin->Information.Url ? SW_SHOW : SW_HIDE); + EnableWindow(GetDlgItem(hwndDlg, IDC_OPTIONS), SelectedPlugin->Information.HasOptions); +} + +INT_PTR CALLBACK PhpPluginPropertiesDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + PPH_PLUGIN selectedPlugin = NULL; + + if (uMsg == WM_INITDIALOG) + { + selectedPlugin = (PPH_PLUGIN)lParam; + SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)selectedPlugin); + } + else + { + selectedPlugin = (PPH_PLUGIN)GetProp(hwndDlg, PhMakeContextAtom()); + + if (uMsg == WM_DESTROY) + { + RemoveProp(hwndDlg, PhMakeContextAtom()); + } + } + + if (selectedPlugin == NULL) + return FALSE; + + switch (uMsg) + { + case WM_INITDIALOG: + { + PhCenterWindow(hwndDlg, GetParent(hwndDlg)); + + PhpRefreshPluginDetails(hwndDlg, selectedPlugin); + + SendMessage(hwndDlg, WM_NEXTDLGCTL, (LPARAM)GetDlgItem(hwndDlg, IDOK), TRUE); + } + break; + case WM_COMMAND: + { + switch (GET_WM_COMMAND_ID(wParam, lParam)) + { + case IDCANCEL: + case IDOK: + EndDialog(hwndDlg, IDOK); + break; + case IDC_OPTIONS: { - NOTHING; + PhInvokeCallback(PhGetPluginCallback(selectedPlugin, PluginCallbackShowOptions), hwndDlg); } break; } @@ -406,45 +1004,185 @@ INT_PTR CALLBACK PhpPluginsDlgProc( switch (header->code) { - case LVN_ITEMCHANGED: - { - if (header->hwndFrom == PluginsLv) - { - if (ListView_GetSelectedCount(PluginsLv) == 1) - SelectedPlugin = PhGetSelectedListViewItemParam(PluginsLv); - else - SelectedPlugin = NULL; - - PhpRefreshPluginDetails(hwndDlg); - } - } - break; case NM_CLICK: { if (header->hwndFrom == GetDlgItem(hwndDlg, IDC_OPENURL)) { - if (SelectedPlugin && IS_PLUGIN_LOADED(SelectedPlugin)) - PhShellExecute(hwndDlg, SelectedPlugin->Information.Url, NULL); + PhShellExecute(hwndDlg, selectedPlugin->Information.Url, NULL); } } break; - case NM_DBLCLK: + } + } + break; + } + + return FALSE; +} + +typedef struct _PLUGIN_DISABLED_CONTEXT +{ + PH_QUEUED_LOCK ListLock; + HWND DialogHandle; + HWND ListViewHandle; +} PLUGIN_DISABLED_CONTEXT, *PPLUGIN_DISABLED_CONTEXT; + +VOID PhpAddDisabledPlugins( + _In_ PPLUGIN_DISABLED_CONTEXT Context + ) +{ + PPH_STRING disabled; + PH_STRINGREF remainingPart; + PH_STRINGREF part; + PPH_STRING displayText; + INT lvItemIndex; + + disabled = PhGetStringSetting(L"DisabledPlugins"); + remainingPart = disabled->sr; + + while (remainingPart.Length) + { + PhSplitStringRefAtChar(&remainingPart, '|', &part, &remainingPart); + + if (part.Length) + { + displayText = PhCreateString2(&part); + + PhAcquireQueuedLockExclusive(&Context->ListLock); + lvItemIndex = PhAddListViewItem(Context->ListViewHandle, MAXINT, PhGetString(displayText), displayText); + PhReleaseQueuedLockExclusive(&Context->ListLock); + + ListView_SetCheckState(Context->ListViewHandle, lvItemIndex, TRUE); + } + } + + PhDereferenceObject(disabled); +} + +ULONG PhpDisabledPluginsCount( + VOID + ) +{ + PPH_STRING disabled; + PH_STRINGREF remainingPart; + PH_STRINGREF part; + ULONG count = 0; + + disabled = PhGetStringSetting(L"DisabledPlugins"); + remainingPart = disabled->sr; + + while (remainingPart.Length) + { + PhSplitStringRefAtChar(&remainingPart, '|', &part, &remainingPart); + + if (part.Length) + count++; + } + + PhDereferenceObject(disabled); + + return count; +} + +INT_PTR CALLBACK PhpPluginsDisabledDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + PPLUGIN_DISABLED_CONTEXT context = NULL; + + if (uMsg == WM_INITDIALOG) + { + context = PhAllocate(sizeof(PLUGIN_DISABLED_CONTEXT)); + memset(context, 0, sizeof(PLUGIN_DISABLED_CONTEXT)); + + SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)context); + } + else + { + context = (PPLUGIN_DISABLED_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom()); + + if (uMsg == WM_DESTROY) + { + RemoveProp(hwndDlg, PhMakeContextAtom()); + PhFree(context); + } + } + + if (context == NULL) + return FALSE; + + switch (uMsg) + { + case WM_INITDIALOG: + { + context->DialogHandle = hwndDlg; + context->ListViewHandle = GetDlgItem(hwndDlg, IDC_LIST_DISABLED); + + PhCenterWindow(hwndDlg, GetParent(hwndDlg)); + + PhSetListViewStyle(context->ListViewHandle, FALSE, TRUE); + ListView_SetExtendedListViewStyleEx(context->ListViewHandle, + LVS_EX_CHECKBOXES | LVS_EX_FULLROWSELECT | LVS_EX_DOUBLEBUFFER, + LVS_EX_CHECKBOXES | LVS_EX_FULLROWSELECT | LVS_EX_DOUBLEBUFFER); + PhSetControlTheme(context->ListViewHandle, L"explorer"); + PhAddListViewColumn(context->ListViewHandle, 0, 0, 0, LVCFMT_LEFT, 400, L"Property"); + PhSetExtendedListView(context->ListViewHandle); + + PhpAddDisabledPlugins(context); + ExtendedListView_SetColumnWidth(context->ListViewHandle, 0, ELVSCW_AUTOSIZE_REMAININGSPACE); + + SendMessage(hwndDlg, WM_NEXTDLGCTL, (LPARAM)GetDlgItem(hwndDlg, IDOK), TRUE); + } + break; + case WM_COMMAND: + { + switch (GET_WM_COMMAND_ID(wParam, lParam)) + { + case IDCANCEL: + case IDOK: + EndDialog(hwndDlg, IDOK); + break; + } + } + break; + case WM_NOTIFY: + { + LPNMHDR header = (LPNMHDR)lParam; + + if (header->code == LVN_ITEMCHANGED) + { + LPNM_LISTVIEW listView = (LPNM_LISTVIEW)lParam; + + if (!PhTryAcquireReleaseQueuedLockExclusive(&context->ListLock)) + break; + + if (listView->uChanged & LVIF_STATE) { - if (header->hwndFrom == PluginsLv) + switch (listView->uNewState & LVIS_STATEIMAGEMASK) { - if (SelectedPlugin && IS_PLUGIN_LOADED(SelectedPlugin)) + case INDEXTOSTATEIMAGEMASK(2): // checked { - PhInvokeCallback(PhGetPluginCallback(SelectedPlugin, PluginCallbackShowOptions), hwndDlg); + PPH_STRING param = (PPH_STRING)listView->lParam; + + PhSetPluginDisabled(¶m->sr, TRUE); } + break; + case INDEXTOSTATEIMAGEMASK(1): // unchecked + { + PPH_STRING param = (PPH_STRING)listView->lParam; + + PhSetPluginDisabled(¶m->sr, FALSE); + } + break; } } - break; } } break; } - REFLECT_MESSAGE_DLG(hwndDlg, PluginsLv, uMsg, wParam, lParam); - return FALSE; } From 13d553a33b557bd3117e160abcea501263c4480c Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 3 Nov 2017 13:23:10 +1100 Subject: [PATCH 0549/2058] Add deprecated ExtraPlugins plugin to blocklist --- ProcessHacker/plugin.c | 44 +++++++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/ProcessHacker/plugin.c b/ProcessHacker/plugin.c index 3fd0cf20ffb6..788f5557b4dd 100644 --- a/ProcessHacker/plugin.c +++ b/ProcessHacker/plugin.c @@ -198,38 +198,42 @@ static BOOLEAN EnumPluginsDirectoryCallback( _In_opt_ PVOID Context ) { + static PCWSTR PhpPluginBlocklist[] = + { + L"CommonUtil.dll", + L"ExtraPlugins.dll" + }; + BOOLEAN blacklistedPlugin = FALSE; PH_STRINGREF baseName; PPH_STRING fileName; baseName.Buffer = Information->FileName; baseName.Length = Information->FileNameLength; - if (PhEndsWithStringRef2(&baseName, L".dll", TRUE)) + for (ULONG i = 0; i < ARRAYSIZE(PhpPluginBlocklist); i++) { - // Plugin blacklist - if (PhEndsWithStringRef2(&baseName, L"CommonUtil.dll", TRUE)) + if (PhEndsWithStringRef2(&baseName, PhpPluginBlocklist[i], TRUE)) { - fileName = PhCreateStringEx(NULL, PluginsDirectory->Length + Information->FileNameLength); - memcpy(fileName->Buffer, PluginsDirectory->Buffer, PluginsDirectory->Length); - memcpy(&fileName->Buffer[PluginsDirectory->Length / 2], Information->FileName, Information->FileNameLength); + blacklistedPlugin = TRUE; + break; + } + } - PhDeleteFileWin32(fileName->Buffer); + if (blacklistedPlugin) + { + fileName = PhConcatStringRef2(&PluginsDirectory->sr, &baseName); - PhDereferenceObject(fileName); - } - else - { - if (!PhIsPluginDisabled(&baseName)) - { - fileName = PhCreateStringEx(NULL, PluginsDirectory->Length + Information->FileNameLength); - memcpy(fileName->Buffer, PluginsDirectory->Buffer, PluginsDirectory->Length); - memcpy(&fileName->Buffer[PluginsDirectory->Length / 2], Information->FileName, Information->FileNameLength); + PhDeleteFileWin32(fileName->Buffer); - PhLoadPlugin(fileName); + PhDereferenceObject(fileName); + } + else if (!PhIsPluginDisabled(&baseName)) + { + fileName = PhConcatStringRef2(&PluginsDirectory->sr, &baseName); - PhDereferenceObject(fileName); - } - } + PhLoadPlugin(fileName); + + PhDereferenceObject(fileName); } return TRUE; From 203c557c243e7cf9f4d925677af9c34d0901d194 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 3 Nov 2017 14:27:08 +1100 Subject: [PATCH 0550/2058] Update plugin window layout --- ProcessHacker/ProcessHacker.rc | 91 +++++++++++++++++++++++----------- 1 file changed, 62 insertions(+), 29 deletions(-) diff --git a/ProcessHacker/ProcessHacker.rc b/ProcessHacker/ProcessHacker.rc index e37738d8f2f0..e44cfe89d3de 100644 --- a/ProcessHacker/ProcessHacker.rc +++ b/ProcessHacker/ProcessHacker.rc @@ -1446,33 +1446,15 @@ BEGIN CONTROL "Physical memory",IDC_PHYSICAL,"PhColorBox",WS_CLIPSIBLINGS | WS_TABSTOP,73,129,33,13 END -IDD_PLUGINS DIALOGEX 0, 0, 291, 272 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +IDD_PLUGINMANAGER DIALOGEX 0, 0, 501, 272 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME CAPTION "Plugins" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN - CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,7,277,119 - GROUPBOX "Plugin",IDC_STATIC,7,129,277,118 - LTEXT "Name:",IDC_STATIC,15,141,22,8 - EDITTEXT IDC_NAME,71,141,104,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER - LTEXT "Internal name:",IDC_STATIC,15,152,49,8 - EDITTEXT IDC_INTERNALNAME,71,152,203,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER - LTEXT "Author:",IDC_STATIC,15,163,26,8 - EDITTEXT IDC_AUTHOR,71,163,203,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER - LTEXT "URL:",IDC_STATIC,15,174,16,8 - EDITTEXT IDC_URL,71,174,174,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER - CONTROL "Open",IDC_OPENURL,"SysLink",WS_TABSTOP,250,174,26,10 - LTEXT "File name:",IDC_STATIC,15,185,34,8 - EDITTEXT IDC_FILENAME,71,185,203,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER - LTEXT "Version:",IDC_STATIC,183,141,27,8 - EDITTEXT IDC_VERSION,215,141,59,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER - LTEXT "Description:",IDC_STATIC,15,196,39,8 - EDITTEXT IDC_DESCRIPTION,14,208,211,34,ES_MULTILINE | ES_READONLY - PUSHBUTTON "Disable",IDC_DISABLE,230,211,50,14 - PUSHBUTTON "Options...",IDC_OPTIONS,230,228,50,14 - PUSHBUTTON "Clean up",IDC_CLEANUP,7,251,50,14 - LTEXT "Changes may require a restart to take effect.",IDC_INSTRUCTION,82,254,148,8,NOT WS_VISIBLE - DEFPUSHBUTTON "Close",IDOK,234,251,50,14 + LTEXT "Changes may require a restart to take effect.",IDC_INSTRUCTION,187,262,148,8,NOT WS_VISIBLE + DEFPUSHBUTTON "Close",IDOK,449,256,50,14 + CONTROL "",IDC_PLUGINTREE,"PhTreeNew",WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP | 0xa,2,2,497,253,WS_EX_CLIENTEDGE + PUSHBUTTON "Disabled plugins (0)",IDC_DISABLED,2,256,72,14 END IDD_HANDLESTATS DIALOGEX 0, 0, 219, 175 @@ -1862,6 +1844,41 @@ BEGIN PUSHBUTTON "Cleanup",IDC_CLEANUP,165,231,50,14 END +IDD_PLUGINPROPERTIES DIALOGEX 0, 0, 291, 152 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Plugin Properties" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + GROUPBOX "Plugin",IDC_STATIC,7,7,277,122 + LTEXT "Name:",IDC_STATIC,15,18,22,8 + EDITTEXT IDC_NAME,71,18,104,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + LTEXT "Internal name:",IDC_STATIC,15,30,49,8 + EDITTEXT IDC_INTERNALNAME,71,30,203,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + LTEXT "Author:",IDC_STATIC,15,41,26,8 + EDITTEXT IDC_AUTHOR,71,41,203,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + LTEXT "URL:",IDC_STATIC,15,52,16,8 + EDITTEXT IDC_URL,71,52,174,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + CONTROL "Open",IDC_OPENURL,"SysLink",WS_TABSTOP,250,52,26,10 + LTEXT "File name:",IDC_STATIC,15,63,34,8 + EDITTEXT IDC_FILENAME,71,63,203,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + LTEXT "Version:",IDC_STATIC,183,18,27,8 + EDITTEXT IDC_VERSION,215,18,59,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + LTEXT "Description:",IDC_STATIC,15,74,39,8 + EDITTEXT IDC_DESCRIPTION,14,86,263,37,ES_MULTILINE | ES_READONLY + PUSHBUTTON "Options...",IDC_OPTIONS,7,131,50,14 + DEFPUSHBUTTON "Close",IDOK,234,131,50,14 +END + +IDD_PLUGINSDISABLED DIALOGEX 0, 0, 309, 176 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Disabled Plugins" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + DEFPUSHBUTTON "OK",IDOK,257,160,50,14 + CONTROL "",IDC_LIST_DISABLED,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_ALIGNLEFT | LVS_NOCOLUMNHEADER | WS_BORDER | WS_TABSTOP,2,2,305,157 + LTEXT "Changes may require a restart to take effect.",IDC_INSTRUCTION,2,163,148,8,NOT WS_VISIBLE +END + ///////////////////////////////////////////////////////////////////////////// // @@ -2259,12 +2276,12 @@ BEGIN BOTTOMMARGIN, 149 END - IDD_PLUGINS, DIALOG + IDD_PLUGINMANAGER, DIALOG BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 284 - TOPMARGIN, 7 - BOTTOMMARGIN, 265 + LEFTMARGIN, 2 + RIGHTMARGIN, 499 + TOPMARGIN, 2 + BOTTOMMARGIN, 270 END IDD_HANDLESTATS, DIALOG @@ -2400,6 +2417,22 @@ BEGIN LEFTMARGIN, 2 BOTTOMMARGIN, 245 END + + IDD_PLUGINPROPERTIES, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 284 + TOPMARGIN, 7 + BOTTOMMARGIN, 145 + END + + IDD_PLUGINSDISABLED, DIALOG + BEGIN + LEFTMARGIN, 2 + RIGHTMARGIN, 307 + TOPMARGIN, 2 + BOTTOMMARGIN, 174 + END END #endif // APSTUDIO_INVOKED From ed96e48367fa759a22a05efd2b4fb0b59acbfa9b Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 3 Nov 2017 14:27:33 +1100 Subject: [PATCH 0551/2058] Add missing file from previous commit --- ProcessHacker/resource.h | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/ProcessHacker/resource.h b/ProcessHacker/resource.h index ffec44e7675d..5fe76c517a48 100644 --- a/ProcessHacker/resource.h +++ b/ProcessHacker/resource.h @@ -39,11 +39,9 @@ #define IDD_FINDOBJECTS 130 #define IDD_OBJTOKEN 131 #define ID_PLUGIN_MENU_ITEM 131 -#define ID_SHOWCONTEXTMENU 132 #define IDR_PRIVILEGE 133 #define IDC_SEPARATOR 133 #define IDR_FINDOBJ 134 -#define IDC_COMMIT 134 #define IDD_HIDDENPROCESSES 135 #define ID_TRAYICONS_REGISTERED 135 #define IDD_RUNAS 136 @@ -74,6 +72,7 @@ #define IDD_NETSTACK 167 #define IDD_CREATESERVICE 168 #define IDD_PROCPERFORMANCE 169 +#define ID_SHOWCONTEXTMENU 169 #define IDD_PROCSTATISTICS 170 #define IDD_OPTADVANCED 171 #define IDR_ICON 173 @@ -88,6 +87,7 @@ #define IDD_MEMSTRING 185 #define IDD_OPTGRAPHS 186 #define IDD_PLUGINS 187 +#define IDD_PLUGINMANAGER 187 #define IDD_HANDLESTATS 188 #define IDD_PROCRECORD 189 #define IDD_CHOOSEPROCESS 190 @@ -125,6 +125,8 @@ #define IDB_SEARCH_ACTIVE_BMP 225 #define IDB_SEARCH_INACTIVE_BMP 226 #define IDD_OPTIONS 227 +#define IDD_PLUGINPROPERTIES 228 +#define IDD_PLUGINSDISABLED 241 #define IDC_TERMINATE 1003 #define IDC_FILEICON 1005 #define IDC_FILE 1006 @@ -414,7 +416,6 @@ #define IDC_COMPANYNAME_LINK 1279 #define IDC_SAMPLECOUNT 1280 #define IDC_SAMPLECOUNTLABEL 1281 -#define IDC_DISABLE 1282 #define IDC_VIRTUALKEY 1283 #define IDC_CTRL 1284 #define IDC_ALT 1285 @@ -523,6 +524,9 @@ #define IDC_INFO 1396 #define IDC_DEFSTATE 1398 #define IDC_SETTINGS 1399 +#define IDC_PLUGINTREE 1400 +#define IDC_DISABLED 1401 +#define IDC_LIST_DISABLED 1402 #define ID_HACKER_EXIT 40001 #define ID_PROCESS_PROPERTIES 40006 #define ID_PROCESS_TERMINATE 40007 @@ -551,7 +555,6 @@ #define ID_PROCESS_AFFINITY 40035 #define ID_PROCESS_CREATEDUMPFILE 40036 #define ID_MISCELLANEOUS_DETACHFROMDEBUGGER 40039 -#define ID_MISCELLANEOUS_HEAPS 40040 #define ID_MISCELLANEOUS_INJECTDLL 40041 #define ID_PRIORITY_REALTIME 40048 #define ID_PRIORITY_HIGH 40049 @@ -728,9 +731,9 @@ // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 239 +#define _APS_NEXT_RESOURCE_VALUE 243 #define _APS_NEXT_COMMAND_VALUE 40297 -#define _APS_NEXT_CONTROL_VALUE 1400 -#define _APS_NEXT_SYMED_VALUE 169 +#define _APS_NEXT_CONTROL_VALUE 1403 +#define _APS_NEXT_SYMED_VALUE 170 #endif #endif From fa21e5132c8d345633cd247d7aaacb102d93c9d4 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 3 Nov 2017 20:24:50 +1100 Subject: [PATCH 0552/2058] Remove unused resources --- ProcessHacker/sysscmem.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ProcessHacker/sysscmem.c b/ProcessHacker/sysscmem.c index f17d5ad36e05..2b7a9c4833cd 100644 --- a/ProcessHacker/sysscmem.c +++ b/ProcessHacker/sysscmem.c @@ -336,7 +336,7 @@ INT_PTR CALLBACK PhSipMemoryDialogProc( 3, 3, MemoryDialog, - (HMENU)IDC_COMMIT, + NULL, PhInstanceHandle, NULL ); @@ -351,7 +351,7 @@ INT_PTR CALLBACK PhSipMemoryDialogProc( 3, 3, MemoryDialog, - (HMENU)IDC_PHYSICAL, + NULL, PhInstanceHandle, NULL ); From 028128616fe5b6e6226a685da6079f253fd3817e Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 3 Nov 2017 20:37:28 +1100 Subject: [PATCH 0553/2058] Move PhGetShieldBitmap, Fix bitmap flags --- ProcessHacker/appsup.c | 20 ++++++++++++++++++++ ProcessHacker/include/appsup.h | 4 ++++ ProcessHacker/mainwnd.c | 24 ++---------------------- 3 files changed, 26 insertions(+), 22 deletions(-) diff --git a/ProcessHacker/appsup.c b/ProcessHacker/appsup.c index 8ac68a44e908..5cf37bc85463 100644 --- a/ProcessHacker/appsup.c +++ b/ProcessHacker/appsup.c @@ -2152,3 +2152,23 @@ PPH_STRING PhPcre2GetErrorMessage( buffer->Length = returnLength * sizeof(WCHAR); return buffer; } + +HBITMAP PhGetShieldBitmap( + VOID + ) +{ + static HBITMAP shieldBitmap = NULL; + + if (!shieldBitmap) + { + HICON shieldIcon; + + if (shieldIcon = PhLoadIcon(NULL, IDI_SHIELD, PH_LOAD_ICON_SHARED | PH_LOAD_ICON_SIZE_SMALL | PH_LOAD_ICON_STRICT, 0, 0)) + { + shieldBitmap = PhIconToBitmap(shieldIcon, PhSmallIconSize.X, PhSmallIconSize.Y); + DestroyIcon(shieldIcon); + } + } + + return shieldBitmap; +} diff --git a/ProcessHacker/include/appsup.h b/ProcessHacker/include/appsup.h index 9df859d7fc9a..172c4ab55626 100644 --- a/ProcessHacker/include/appsup.h +++ b/ProcessHacker/include/appsup.h @@ -436,6 +436,10 @@ PPH_STRING PhPcre2GetErrorMessage( _In_ INT ErrorCode ); +HBITMAP PhGetShieldBitmap( + VOID + ); + #define PH_LOAD_SHARED_ICON_SMALL(BaseAddress, Name) PhLoadIcon(BaseAddress, (Name), PH_LOAD_ICON_SHARED | PH_LOAD_ICON_SIZE_SMALL, 0, 0) // phapppub #define PH_LOAD_SHARED_ICON_LARGE(BaseAddress, Name) PhLoadIcon(BaseAddress, (Name), PH_LOAD_ICON_SHARED | PH_LOAD_ICON_SIZE_LARGE, 0, 0) // phapppub diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index d53367b77ed8..46186dfe4219 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -2459,26 +2459,6 @@ VOID PhMwpDispatchMenuCommand( SendMessage(PhMainWndHandle, WM_COMMAND, ItemId, 0); } -HBITMAP PhMwpGetShieldBitmap( - VOID - ) -{ - static HBITMAP shieldBitmap = NULL; - - if (!shieldBitmap) - { - HICON shieldIcon; - - if (shieldIcon = PhLoadIcon(NULL, IDI_SHIELD, PH_LOAD_ICON_SIZE_SMALL | PH_LOAD_ICON_STRICT, 0, 0)) - { - shieldBitmap = PhIconToBitmap(shieldIcon, PhSmallIconSize.X, PhSmallIconSize.Y); - DestroyIcon(shieldIcon); - } - } - - return shieldBitmap; -} - VOID PhMwpInitializeSubMenu( _In_ PPH_EMENU Menu, _In_ ULONG Index @@ -2500,7 +2480,7 @@ VOID PhMwpInitializeSubMenu( { HBITMAP shieldBitmap; - if (shieldBitmap = PhMwpGetShieldBitmap()) + if (shieldBitmap = PhGetShieldBitmap()) { if (menuItem = PhFindEMenuItem(Menu, 0, NULL, ID_HACKER_SHOWDETAILSFORALLPROCESSES)) menuItem->Bitmap = shieldBitmap; @@ -2642,7 +2622,7 @@ VOID PhMwpInitializeSubMenu( { HBITMAP shieldBitmap; - if (shieldBitmap = PhMwpGetShieldBitmap()) + if (shieldBitmap = PhGetShieldBitmap()) { if (menuItem = PhFindEMenuItem(Menu, 0, NULL, ID_TOOLS_STARTTASKMANAGER)) menuItem->Bitmap = shieldBitmap; From 044a1f30d02d99c79d7ebbbd4ea66072889a1fa2 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 3 Nov 2017 20:37:58 +1100 Subject: [PATCH 0554/2058] Add file from previous commit --- ProcessHacker/include/mainwndp.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/ProcessHacker/include/mainwndp.h b/ProcessHacker/include/mainwndp.h index 29fea32a3fc7..1f69c58882fb 100644 --- a/ProcessHacker/include/mainwndp.h +++ b/ProcessHacker/include/mainwndp.h @@ -202,10 +202,6 @@ VOID PhMwpDispatchMenuCommand( _In_ ULONG_PTR ItemData ); -HBITMAP PhMwpGetShieldBitmap( - VOID - ); - VOID PhMwpInitializeSubMenu( _In_ PPH_EMENU Menu, _In_ ULONG Index From e68b51dc15deb61b4e435637ad28477d4b8529b5 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 4 Nov 2017 03:14:20 +1100 Subject: [PATCH 0555/2058] Fix warning --- ProcessHacker/plugin.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ProcessHacker/plugin.c b/ProcessHacker/plugin.c index 788f5557b4dd..a62dd703b31e 100644 --- a/ProcessHacker/plugin.c +++ b/ProcessHacker/plugin.c @@ -198,7 +198,7 @@ static BOOLEAN EnumPluginsDirectoryCallback( _In_opt_ PVOID Context ) { - static PCWSTR PhpPluginBlocklist[] = + static const PWSTR PhpPluginBlocklist[] = { L"CommonUtil.dll", L"ExtraPlugins.dll" From 9002b87e401dfddf58f5ca76a24fe931cfb71142 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 4 Nov 2017 04:39:49 +1100 Subject: [PATCH 0556/2058] CustomSignTool: Update to latest SDK --- tools/CustomSignTool/CustomSignTool.sln | 31 ++++++++++++++++++ tools/CustomSignTool/CustomSignTool.vcxproj | 2 +- .../bin/Release32/CustomSignTool.exe | Bin 118784 -> 119808 bytes .../bin/Release64/CustomSignTool.exe | Bin 137728 -> 140288 bytes tools/CustomSignTool/main.c | 2 +- 5 files changed, 33 insertions(+), 2 deletions(-) create mode 100644 tools/CustomSignTool/CustomSignTool.sln diff --git a/tools/CustomSignTool/CustomSignTool.sln b/tools/CustomSignTool/CustomSignTool.sln new file mode 100644 index 000000000000..89743a203c9d --- /dev/null +++ b/tools/CustomSignTool/CustomSignTool.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.27004.2006 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CustomSignTool", "CustomSignTool.vcxproj", "{E8CD0A41-1537-4EA6-98AC-E80CD59C478E}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {E8CD0A41-1537-4EA6-98AC-E80CD59C478E}.Debug|x64.ActiveCfg = Debug|x64 + {E8CD0A41-1537-4EA6-98AC-E80CD59C478E}.Debug|x64.Build.0 = Debug|x64 + {E8CD0A41-1537-4EA6-98AC-E80CD59C478E}.Debug|x86.ActiveCfg = Debug|Win32 + {E8CD0A41-1537-4EA6-98AC-E80CD59C478E}.Debug|x86.Build.0 = Debug|Win32 + {E8CD0A41-1537-4EA6-98AC-E80CD59C478E}.Release|x64.ActiveCfg = Release|x64 + {E8CD0A41-1537-4EA6-98AC-E80CD59C478E}.Release|x64.Build.0 = Release|x64 + {E8CD0A41-1537-4EA6-98AC-E80CD59C478E}.Release|x86.ActiveCfg = Release|Win32 + {E8CD0A41-1537-4EA6-98AC-E80CD59C478E}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {67C12566-2845-498A-B9B9-C4472F50BD19} + EndGlobalSection +EndGlobal diff --git a/tools/CustomSignTool/CustomSignTool.vcxproj b/tools/CustomSignTool/CustomSignTool.vcxproj index c8a08527627b..24f83c05f5de 100644 --- a/tools/CustomSignTool/CustomSignTool.vcxproj +++ b/tools/CustomSignTool/CustomSignTool.vcxproj @@ -22,7 +22,7 @@ {E8CD0A41-1537-4EA6-98AC-E80CD59C478E} CustomSignTool Win32Proj - 10.0.15063.0 + 10.0.16299.0 diff --git a/tools/CustomSignTool/bin/Release32/CustomSignTool.exe b/tools/CustomSignTool/bin/Release32/CustomSignTool.exe index 7af31bf7ba69b82c30b783f257113ac5fdd89724..d78fbf12720dccf665f26805a7d0e29709fe95cc 100644 GIT binary patch delta 54129 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%0ABrj}IL!8vCW0y+?~<$5Iig@01{Yy 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 diff --git a/tools/CustomSignTool/main.c b/tools/CustomSignTool/main.c index 32b8a4051a31..c860769fb5f5 100644 --- a/tools/CustomSignTool/main.c +++ b/tools/CustomSignTool/main.c @@ -234,7 +234,7 @@ int __cdecl wmain(int argc, wchar_t *argv[]) NTSTATUS status; PH_STRINGREF commandLine; - if (!NT_SUCCESS(PhInitializePhLibEx(0, 0, 0))) + if (!NT_SUCCESS(PhInitializePhLib())) return 1; PhUnicodeStringToStringRef(&NtCurrentPeb()->ProcessParameters->CommandLine, &commandLine); From 997de755cacc01583ae2a4056dd74ef0fa37a8b8 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 4 Nov 2017 06:09:16 +1100 Subject: [PATCH 0557/2058] Add plugin manager settings --- ProcessHacker/settings.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ProcessHacker/settings.c b/ProcessHacker/settings.c index a9609843c868..33fc77524159 100644 --- a/ProcessHacker/settings.c +++ b/ProcessHacker/settings.c @@ -122,6 +122,9 @@ VOID PhAddDefaultSettings( PhpAddStringSetting(L"NetworkTreeListColumns", L""); PhpAddStringSetting(L"NetworkTreeListSort", L"0,1"); // 0, AscendingSortOrder PhpAddIntegerSetting(L"NoPurgeProcessRecords", L"0"); + PhpAddIntegerPairSetting(L"PluginManagerWindowPosition", L"0,0"); + PhpAddScalableIntegerPairSetting(L"PluginManagerWindowSize", L"@96|900,590"); + PhpAddStringSetting(L"PluginManagerTreeListColumns", L""); PhpAddStringSetting(L"PluginsDirectory", L"plugins"); PhpAddStringSetting(L"ProcessServiceListViewColumns", L""); PhpAddStringSetting(L"ProcessTreeListColumns", L""); From 703e929b6de51a972ec13d6d1a855a3b8094fc86 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 5 Nov 2017 21:26:27 +1100 Subject: [PATCH 0558/2058] Remove duplicate MAKEINTRESOURCE macro --- phlib/guisup.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/phlib/guisup.c b/phlib/guisup.c index c27f2bce0957..7b83f1571132 100644 --- a/phlib/guisup.c +++ b/phlib/guisup.c @@ -710,9 +710,9 @@ VOID PhGetStockApplicationIcon( // Fallback icons if (!smallIcon) - smallIcon = PhLoadIcon(NULL, MAKEINTRESOURCE(IDI_APPLICATION), PH_LOAD_ICON_SIZE_SMALL, 0, 0); + smallIcon = PhLoadIcon(NULL, IDI_APPLICATION, PH_LOAD_ICON_SIZE_SMALL, 0, 0); if (!largeIcon) - largeIcon = PhLoadIcon(NULL, MAKEINTRESOURCE(IDI_APPLICATION), PH_LOAD_ICON_SIZE_LARGE, 0, 0); + largeIcon = PhLoadIcon(NULL, IDI_APPLICATION, PH_LOAD_ICON_SIZE_LARGE, 0, 0); PhEndInitOnce(&initOnce); } From ed493e3f4d17373213c35e418b558e6b716b80cd Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 5 Nov 2017 22:32:53 +1100 Subject: [PATCH 0559/2058] Improve Win10 application icons --- phlib/guisup.c | 36 +++++++++++++++--------------------- 1 file changed, 15 insertions(+), 21 deletions(-) diff --git a/phlib/guisup.c b/phlib/guisup.c index 7b83f1571132..0578d65e8de2 100644 --- a/phlib/guisup.c +++ b/phlib/guisup.c @@ -678,34 +678,28 @@ VOID PhGetStockApplicationIcon( if (PhBeginInitOnce(&initOnce)) { - PPH_STRING systemDirectory; - PPH_STRING dllFileName; - - // imageres,11 (Windows 10 and above), user32,0 (Vista and above) or shell32,2 (XP) contains - // the default application icon. - - if (systemDirectory = PhGetSystemDirectory()) + if (WindowsVersion < WINDOWS_10) { - PH_STRINGREF dllBaseName; - ULONG index; + PPH_STRING systemDirectory; + PPH_STRING dllFileName; - // TODO: Find a better solution. - if (WindowsVersion >= WINDOWS_10) - { - PhInitializeStringRef(&dllBaseName, L"\\imageres.dll"); - index = 11; - } - else + // imageres,11 (Windows 10 and above), user32,0 (Vista and above) or shell32,2 (XP) contains + // the default application icon. + + if (systemDirectory = PhGetSystemDirectory()) { + PH_STRINGREF dllBaseName; + ULONG index; + PhInitializeStringRef(&dllBaseName, L"\\user32.dll"); index = 0; - } - dllFileName = PhConcatStringRef2(&systemDirectory->sr, &dllBaseName); - PhDereferenceObject(systemDirectory); + dllFileName = PhConcatStringRef2(&systemDirectory->sr, &dllBaseName); + PhDereferenceObject(systemDirectory); - ExtractIconEx(dllFileName->Buffer, index, &largeIcon, &smallIcon, 1); - PhDereferenceObject(dllFileName); + ExtractIconEx(dllFileName->Buffer, index, &largeIcon, &smallIcon, 1); + PhDereferenceObject(dllFileName); + } } // Fallback icons From 01e76274a7414adb689047def02987d8d4970f1d Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 6 Nov 2017 08:46:23 +1100 Subject: [PATCH 0560/2058] Update PhGetSystemDirectory --- phlib/util.c | 34 ++++++---------------------------- 1 file changed, 6 insertions(+), 28 deletions(-) diff --git a/phlib/util.c b/phlib/util.c index 379d835d2620..76903763b2bb 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -2000,40 +2000,18 @@ PPH_STRING PhGetSystemDirectory( VOID ) { + static PH_STRINGREF system32String = PH_STRINGREF_INIT(L"\\System32"); static PPH_STRING cachedSystemDirectory = NULL; - PPH_STRING systemDirectory; - ULONG bufferSize; - ULONG returnLength; + PH_STRINGREF systemRootString; // Use the cached value if possible. - systemDirectory = cachedSystemDirectory; - - if (systemDirectory) - return PhReferenceObject(systemDirectory); - - bufferSize = 0x40; - systemDirectory = PhCreateStringEx(NULL, bufferSize * 2); - - returnLength = GetSystemDirectory(systemDirectory->Buffer, bufferSize); - - if (returnLength > bufferSize) - { - PhDereferenceObject(systemDirectory); - bufferSize = returnLength; - systemDirectory = PhCreateStringEx(NULL, bufferSize * 2); - - returnLength = GetSystemDirectory(systemDirectory->Buffer, bufferSize); - } - - if (returnLength == 0) - { - PhDereferenceObject(systemDirectory); - return NULL; - } + if (cachedSystemDirectory) + return PhReferenceObject(cachedSystemDirectory); - PhTrimToNullTerminatorString(systemDirectory); + PhGetSystemRoot(&systemRootString); + systemDirectory = PhConcatStringRef2(&systemRootString, &system32String); // Try to cache the value. if (_InterlockedCompareExchangePointer( From 3b393029fb093e0349c3450805635e27351c743d Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 6 Nov 2017 19:11:31 +1100 Subject: [PATCH 0561/2058] Update macro usage --- ProcessHacker/extmgr.c | 4 ++-- ProcessHacker/phsvc/svcapi.c | 2 +- ProcessHacker/phsvc/svcapiport.c | 6 ++--- ProcessHacker/procmtgn.c | 2 +- ProcessHacker/runas.c | 2 +- phlib/basesup.c | 39 ++++++++++++++++---------------- phlib/filepool.c | 10 ++++---- phlib/filestream.c | 8 +++---- phlib/guisup.c | 2 +- phlib/include/hndlinfo.h | 4 ++-- phlib/include/phbasesup.h | 6 ++--- phlib/include/phnative.h | 4 ++-- phlib/kph.c | 2 +- phlib/maplib.c | 6 ++--- phlib/native.c | 8 +++---- phlib/util.c | 2 +- 16 files changed, 54 insertions(+), 53 deletions(-) diff --git a/ProcessHacker/extmgr.c b/ProcessHacker/extmgr.c index d86051f0bb61..950d483b095d 100644 --- a/ProcessHacker/extmgr.c +++ b/ProcessHacker/extmgr.c @@ -126,7 +126,7 @@ PVOID PhEmGetObjectExtension( if (!objectExtension) return NULL; - return (PCHAR)Object + PhEmObjectTypeState[ObjectType].InitialSize + objectExtension->ExtensionOffset; + return PTR_ADD_OFFSET(Object, PhEmObjectTypeState[ObjectType].InitialSize + objectExtension->ExtensionOffset); } /** @@ -178,7 +178,7 @@ VOID PhEmCallObjectOperation( objectExtension->Callbacks[Operation]( Object, ObjectType, - (PCHAR)Object + objectTypeState->InitialSize + objectExtension->ExtensionOffset + PTR_ADD_OFFSET(Object, objectTypeState->InitialSize + objectExtension->ExtensionOffset) ); } diff --git a/ProcessHacker/phsvc/svcapi.c b/ProcessHacker/phsvc/svcapi.c index be7a728ce830..9aba65bd33e3 100644 --- a/ProcessHacker/phsvc/svcapi.c +++ b/ProcessHacker/phsvc/svcapi.c @@ -108,7 +108,7 @@ PVOID PhSvcValidateString( PPHSVC_CLIENT client = PhSvcGetCurrentClient(); PVOID address; - address = (PCHAR)client->ClientViewBase + String->Offset; + address = PTR_ADD_OFFSET(client->ClientViewBase, String->Offset); if ((ULONG_PTR)address + String->Length < (ULONG_PTR)address || (ULONG_PTR)address < (ULONG_PTR)client->ClientViewBase || diff --git a/ProcessHacker/phsvc/svcapiport.c b/ProcessHacker/phsvc/svcapiport.c index 7bfb8ebf49b8..62278ed630cf 100644 --- a/ProcessHacker/phsvc/svcapiport.c +++ b/ProcessHacker/phsvc/svcapiport.c @@ -64,7 +64,7 @@ NTSTATUS PhSvcApiPortInitialization( RtlLengthSid(&PhSeEveryoneSid); securityDescriptor = PhAllocate(sdAllocationLength); - dacl = (PACL)((PCHAR)securityDescriptor + SECURITY_DESCRIPTOR_MIN_LENGTH); + dacl = (PACL)PTR_ADD_OFFSET(securityDescriptor, SECURITY_DESCRIPTOR_MIN_LENGTH); RtlCreateSecurityDescriptor(securityDescriptor, SECURITY_DESCRIPTOR_REVISION); RtlCreateAcl(dacl, sdAllocationLength - SECURITY_DESCRIPTOR_MIN_LENGTH, ACL_REVISION); @@ -296,12 +296,12 @@ VOID PhSvcHandleConnectionRequest( if (PhIsExecutingInWow64()) { client->ClientViewBase = (PVOID)clientView64.ViewBase; - client->ClientViewLimit = (PCHAR)clientView64.ViewBase + (ULONG)clientView64.ViewSize; + client->ClientViewLimit = PTR_ADD_OFFSET(clientView64.ViewBase, clientView64.ViewSize); } else { client->ClientViewBase = clientView.ViewBase; - client->ClientViewLimit = (PCHAR)clientView.ViewBase + clientView.ViewSize; + client->ClientViewLimit = PTR_ADD_OFFSET(clientView.ViewBase, clientView.ViewSize); } NtCompleteConnectPort(portHandle); diff --git a/ProcessHacker/procmtgn.c b/ProcessHacker/procmtgn.c index e002fe1beba4..cf72c479d837 100644 --- a/ProcessHacker/procmtgn.c +++ b/ProcessHacker/procmtgn.c @@ -52,7 +52,7 @@ NTSTATUS PhpCopyProcessMitigationPolicy( return status; } - memcpy(Destination, (PCHAR)&policyInfo + Offset, Size); + memcpy(Destination, PTR_ADD_OFFSET(&policyInfo, Offset), Size); *Status = STATUS_SUCCESS; return status; diff --git a/ProcessHacker/runas.c b/ProcessHacker/runas.c index e84d047429df..954f4fb811eb 100644 --- a/ProcessHacker/runas.c +++ b/ProcessHacker/runas.c @@ -741,7 +741,7 @@ VOID PhSetDesktopWinStaAccess( (ULONG)sizeof(ACCESS_ALLOWED_ACE) + RtlLengthSid(allAppPackagesSid); securityDescriptor = PhAllocate(allocationLength); - dacl = (PACL)((PCHAR)securityDescriptor + SECURITY_DESCRIPTOR_MIN_LENGTH); + dacl = (PACL)PTR_ADD_OFFSET(securityDescriptor, SECURITY_DESCRIPTOR_MIN_LENGTH); RtlCreateSecurityDescriptor(securityDescriptor, SECURITY_DESCRIPTOR_REVISION); diff --git a/phlib/basesup.c b/phlib/basesup.c index 358bcbb9fe07..fd8eb7c8d92d 100644 --- a/phlib/basesup.c +++ b/phlib/basesup.c @@ -922,7 +922,7 @@ BOOLEAN PhCopyStringZFromMultiByte( if (NT_SUCCESS(status)) { // RtlMultiByteToUnicodeN doesn't null terminate the string. - *(PWCHAR)((PCHAR)OutputBuffer + unicodeBytes) = 0; + *(PWCHAR)PTR_ADD_OFFSET(OutputBuffer, unicodeBytes) = 0; copied = TRUE; } else @@ -1151,7 +1151,7 @@ LONG PhCompareStringRef( s1 = String1->Buffer; s2 = String2->Buffer; - end = (PWCHAR)((PCHAR)s1 + (l1 <= l2 ? l1 : l2)); + end = (PWCHAR)PTR_ADD_OFFSET(s1, l1 <= l2 ? l1 : l2); if (!IgnoreCase) { @@ -1440,7 +1440,7 @@ ULONG_PTR PhFindLastCharInStringRef( PWCHAR buffer; SIZE_T length; - buffer = (PWCHAR)((PCHAR)String->Buffer + String->Length); + buffer = (PWCHAR)PTR_ADD_OFFSET(String->Buffer, String->Length); length = String->Length / sizeof(WCHAR); if (!IgnoreCase) @@ -1622,7 +1622,7 @@ BOOLEAN PhSplitStringRefAtChar( FirstPart->Buffer = input.Buffer; FirstPart->Length = index * sizeof(WCHAR); - SecondPart->Buffer = (PWCHAR)((PCHAR)input.Buffer + index * sizeof(WCHAR) + sizeof(WCHAR)); + SecondPart->Buffer = (PWCHAR)PTR_ADD_OFFSET(input.Buffer, index * sizeof(WCHAR) + sizeof(WCHAR)); SecondPart->Length = input.Length - index * sizeof(WCHAR) - sizeof(WCHAR); return TRUE; @@ -1669,7 +1669,7 @@ BOOLEAN PhSplitStringRefAtLastChar( FirstPart->Buffer = input.Buffer; FirstPart->Length = index * sizeof(WCHAR); - SecondPart->Buffer = (PWCHAR)((PCHAR)input.Buffer + index * sizeof(WCHAR) + sizeof(WCHAR)); + SecondPart->Buffer = (PWCHAR)PTR_ADD_OFFSET(input.Buffer, index * sizeof(WCHAR) + sizeof(WCHAR)); SecondPart->Length = input.Length - index * sizeof(WCHAR) - sizeof(WCHAR); return TRUE; @@ -1718,7 +1718,7 @@ BOOLEAN PhSplitStringRefAtString( FirstPart->Buffer = input.Buffer; FirstPart->Length = index * sizeof(WCHAR); - SecondPart->Buffer = (PWCHAR)((PCHAR)input.Buffer + index * sizeof(WCHAR) + Separator->Length); + SecondPart->Buffer = (PWCHAR)PTR_ADD_OFFSET(input.Buffer, index * sizeof(WCHAR) + Separator->Length); SecondPart->Length = input.Length - index * sizeof(WCHAR) - Separator->Length; return TRUE; @@ -1855,7 +1855,7 @@ BOOLEAN PhSplitStringRefEx( } else { - s = (PWCHAR)((PCHAR)input.Buffer + input.Length - sizeof(WCHAR)); + s = (PWCHAR)PTR_ADD_OFFSET(input.Buffer, input.Length - sizeof(WCHAR)); direction = -1; } @@ -1945,7 +1945,7 @@ BOOLEAN PhSplitStringRefEx( SeparatorFound: FirstPart->Buffer = input.Buffer; FirstPart->Length = separatorIndex * sizeof(WCHAR); - SecondPart->Buffer = (PWCHAR)((PCHAR)input.Buffer + separatorIndex * sizeof(WCHAR) + separatorLength); + SecondPart->Buffer = (PWCHAR)PTR_ADD_OFFSET(input.Buffer, separatorIndex * sizeof(WCHAR) + separatorLength); SecondPart->Length = input.Length - separatorIndex * sizeof(WCHAR) - separatorLength; if (SeparatorPart) @@ -2016,7 +2016,7 @@ VOID PhTrimStringRef( { trimCount = 0; count = String->Length / sizeof(WCHAR); - s = (PWCHAR)((PCHAR)String->Buffer + String->Length - sizeof(WCHAR)); + s = (PWCHAR)PTR_ADD_OFFSET(String->Buffer, String->Length - sizeof(WCHAR)); while (count-- != 0) { @@ -2085,7 +2085,7 @@ VOID PhTrimStringRef( { trimCount = 0; count = String->Length / sizeof(WCHAR); - s = (PWCHAR)((PCHAR)String->Buffer + String->Length - sizeof(WCHAR)); + s = (PWCHAR)PTR_ADD_OFFSET(String->Buffer, String->Length - sizeof(WCHAR)); while (count-- != 0) { @@ -2146,7 +2146,7 @@ PPH_STRING PhCreateStringEx( assert(!(Length & 1)); string->Length = Length; string->Buffer = string->Data; - *(PWCHAR)((PCHAR)string->Buffer + Length) = 0; + *(PWCHAR)PTR_ADD_OFFSET(string->Buffer, Length) = 0; if (Buffer) { @@ -2260,7 +2260,7 @@ PPH_STRING PhConcatStrings_V( stringLength = PhCountStringZ(arg) * sizeof(WCHAR); memcpy( - (PCHAR)string->Buffer + totalLength, + PTR_ADD_OFFSET(string->Buffer, totalLength), arg, stringLength ); @@ -2294,7 +2294,7 @@ PPH_STRING PhConcatStrings2( length1 ); memcpy( - (PCHAR)string->Buffer + length1, + PTR_ADD_OFFSET(string->Buffer, length1), String2, length2 ); @@ -2320,7 +2320,7 @@ PPH_STRING PhConcatStringRef2( string = PhCreateStringEx(NULL, String1->Length + String2->Length); memcpy(string->Buffer, String1->Buffer, String1->Length); - memcpy((PCHAR)string->Buffer + String1->Length, String2->Buffer, String2->Length); + memcpy(PTR_ADD_OFFSET(string->Buffer, String1->Length), String2->Buffer, String2->Length); return string; } @@ -3474,7 +3474,7 @@ FORCEINLINE VOID PhpWriteNullTerminatorStringBuilder( ) { assert(!(StringBuilder->String->Length & 1)); - *(PWCHAR)((PCHAR)StringBuilder->String->Buffer + StringBuilder->String->Length) = 0; + *(PWCHAR)PTR_ADD_OFFSET(StringBuilder->String->Buffer, StringBuilder->String->Length) = 0; } /** @@ -3540,7 +3540,7 @@ VOID PhAppendStringBuilderEx( if (String) { memcpy( - (PCHAR)StringBuilder->String->Buffer + StringBuilder->String->Length, + PTR_ADD_OFFSET(StringBuilder->String->Buffer, StringBuilder->String->Length), String, Length ); @@ -3566,7 +3566,7 @@ VOID PhAppendCharStringBuilder( PhpResizeStringBuilder(StringBuilder, StringBuilder->String->Length + sizeof(WCHAR)); } - *(PWCHAR)((PCHAR)StringBuilder->String->Buffer + StringBuilder->String->Length) = Character; + *(PWCHAR)PTR_ADD_OFFSET(StringBuilder->String->Buffer, StringBuilder->String->Length) = Character; StringBuilder->String->Length += sizeof(WCHAR); PhpWriteNullTerminatorStringBuilder(StringBuilder); } @@ -3594,7 +3594,7 @@ VOID PhAppendCharStringBuilder2( } wmemset( - (PWCHAR)((PCHAR)StringBuilder->String->Buffer + StringBuilder->String->Length), + PTR_ADD_OFFSET(StringBuilder->String->Buffer, StringBuilder->String->Length), Character, Count ); @@ -3619,6 +3619,7 @@ VOID PhAppendFormatStringBuilder( va_start(argptr, Format); PhAppendFormatStringBuilder_V(StringBuilder, Format, argptr); + va_end(argptr); } VOID PhAppendFormatStringBuilder_V( @@ -3641,7 +3642,7 @@ VOID PhAppendFormatStringBuilder_V( PhpResizeStringBuilder(StringBuilder, StringBuilder->String->Length + lengthInBytes); _vsnwprintf( - (PWCHAR)((PCHAR)StringBuilder->String->Buffer + StringBuilder->String->Length), + PTR_ADD_OFFSET(StringBuilder->String->Buffer, StringBuilder->String->Length), length, Format, ArgPtr diff --git a/phlib/filepool.c b/phlib/filepool.c index 9b76e6fa44a2..58790ae17f55 100644 --- a/phlib/filepool.c +++ b/phlib/filepool.c @@ -223,7 +223,7 @@ NTSTATUS PhCreateFilePool( // Set up the first segment properly. pool->FirstBlockOfFirstSegment->Span = pool->FileHeaderBlockSpan; - segmentHeaderBlock = (PPH_FP_BLOCK_HEADER)((PCHAR)pool->FirstBlockOfFirstSegment + (pool->FileHeaderBlockSpan << pool->BlockShift)); + segmentHeaderBlock = (PPH_FP_BLOCK_HEADER)PTR_ADD_OFFSET(pool->FirstBlockOfFirstSegment, (pool->FileHeaderBlockSpan << pool->BlockShift)); PhFppInitializeSegment(pool, segmentHeaderBlock, pool->FileHeaderBlockSpan); pool->Header->FreeLists[1] = 0; @@ -576,7 +576,7 @@ BOOLEAN PhFreeFilePoolByRva( if (!firstBlock) return FALSE; - PhpFreeFilePool(Pool, segmentIndex, firstBlock, (PCHAR)firstBlock + offset); + PhpFreeFilePool(Pool, segmentIndex, firstBlock, PTR_ADD_OFFSET(firstBlock, offset)); PhFppDereferenceSegment(Pool, segmentIndex); return TRUE; @@ -639,7 +639,7 @@ PVOID PhReferenceFilePoolByRva( if (!firstBlock) return NULL; - return (PCHAR)firstBlock + offset; + return PTR_ADD_OFFSET(firstBlock, offset); } /** @@ -877,7 +877,7 @@ PPH_FP_SEGMENT_HEADER PhFppGetHeaderSegment( else { // In the first segment, the segment header is after the file header. - return (PPH_FP_SEGMENT_HEADER)&((PPH_FP_BLOCK_HEADER)((PCHAR)FirstBlock + (Pool->FileHeaderBlockSpan << Pool->BlockShift)))->Body; + return (PPH_FP_SEGMENT_HEADER)&((PPH_FP_BLOCK_HEADER)PTR_ADD_OFFSET(FirstBlock, (Pool->FileHeaderBlockSpan << Pool->BlockShift)))->Body; } } @@ -1248,7 +1248,7 @@ PPH_FP_BLOCK_HEADER PhFppAllocateBlocks( SegmentHeader->FreeBlocks -= NumberOfBlocks; - blockHeader = (PPH_FP_BLOCK_HEADER)((PCHAR)FirstBlock + (foundIndex << Pool->BlockShift)); + blockHeader = (PPH_FP_BLOCK_HEADER)PTR_ADD_OFFSET(FirstBlock, (foundIndex << Pool->BlockShift)); blockHeader->Flags = 0; blockHeader->Span = NumberOfBlocks; diff --git a/phlib/filestream.c b/phlib/filestream.c index 3e7552d40ce5..d38da05ec6a0 100644 --- a/phlib/filestream.c +++ b/phlib/filestream.c @@ -332,7 +332,7 @@ NTSTATUS PhReadFileStream( // Try to satisfy the request from the buffer. memcpy( Buffer, - (PCHAR)FileStream->Buffer + FileStream->ReadPosition, + PTR_ADD_OFFSET(FileStream->Buffer, FileStream->ReadPosition), readLength ); FileStream->ReadPosition += readLength; @@ -348,7 +348,7 @@ NTSTATUS PhReadFileStream( if (NT_SUCCESS(status = PhpReadFileStream( FileStream, - (PCHAR)Buffer + readLength, + PTR_ADD_OFFSET(Buffer, readLength), Length - readLength, &readLength2 ))) @@ -454,7 +454,7 @@ NTSTATUS PhWriteFileStream( writtenLength = Length; memcpy( - (PCHAR)FileStream->Buffer + FileStream->WritePosition, + PTR_ADD_OFFSET(FileStream->Buffer, FileStream->WritePosition), Buffer, writtenLength ); @@ -466,7 +466,7 @@ NTSTATUS PhWriteFileStream( return status; } - Buffer = (PCHAR)Buffer + writtenLength; + Buffer = PTR_ADD_OFFSET(Buffer, writtenLength); Length -= writtenLength; } diff --git a/phlib/guisup.c b/phlib/guisup.c index 0578d65e8de2..a2d3f18aa4b3 100644 --- a/phlib/guisup.c +++ b/phlib/guisup.c @@ -822,7 +822,7 @@ VOID PhSetClipboardString( memory = GlobalLock(data); memcpy(memory, String->Buffer, String->Length); - *(PWCHAR)((PCHAR)memory + String->Length) = 0; + *(PWCHAR)PTR_ADD_OFFSET(memory, String->Length) = 0; GlobalUnlock(memory); diff --git a/phlib/include/hndlinfo.h b/phlib/include/hndlinfo.h index c92bd4b8de57..9a79c013d6c1 100644 --- a/phlib/include/hndlinfo.h +++ b/phlib/include/hndlinfo.h @@ -70,10 +70,10 @@ PhGetHandleInformationEx( ); #define PH_FIRST_OBJECT_TYPE(ObjectTypes) \ - (POBJECT_TYPE_INFORMATION)((PCHAR)(ObjectTypes) + ALIGN_UP(sizeof(OBJECT_TYPES_INFORMATION), ULONG_PTR)) + (POBJECT_TYPE_INFORMATION)PTR_ADD_OFFSET(ObjectTypes, ALIGN_UP(sizeof(OBJECT_TYPES_INFORMATION), ULONG_PTR)) #define PH_NEXT_OBJECT_TYPE(ObjectType) \ - (POBJECT_TYPE_INFORMATION)((PCHAR)(ObjectType) + sizeof(OBJECT_TYPE_INFORMATION) + \ + (POBJECT_TYPE_INFORMATION)PTR_ADD_OFFSET(ObjectType, sizeof(OBJECT_TYPE_INFORMATION) + \ ALIGN_UP(ObjectType->TypeName.MaximumLength, ULONG_PTR)) PHLIBAPI diff --git a/phlib/include/phbasesup.h b/phlib/include/phbasesup.h index 7dd9bb837a28..5fc24b13821a 100644 --- a/phlib/include/phbasesup.h +++ b/phlib/include/phbasesup.h @@ -1028,7 +1028,7 @@ PhEndsWithStringRef( if (Suffix->Length > String->Length) return FALSE; - sr.Buffer = (PWCHAR)((PCHAR)String->Buffer + String->Length - Suffix->Length); + sr.Buffer = (PWCHAR)PTR_ADD_OFFSET(String->Buffer, String->Length - Suffix->Length); sr.Length = Suffix->Length; return PhEqualStringRef(&sr, Suffix, IgnoreCase); @@ -1056,7 +1056,7 @@ PhSkipStringRef( _In_ LONG_PTR Length ) { - String->Buffer = (PWCH)((PCHAR)String->Buffer + Length); + String->Buffer = (PWCH)PTR_ADD_OFFSET(String->Buffer, Length); String->Length -= Length; } @@ -2242,7 +2242,7 @@ PhItemArray( _In_ SIZE_T Index ) { - return (PCHAR)Array->Items + Index * Array->ItemSize; + return PTR_ADD_OFFSET(Array->Items, Index * Array->ItemSize); } PHLIBAPI diff --git a/phlib/include/phnative.h b/phlib/include/phnative.h index 4e752ae3a347..a0c4e45bfed2 100644 --- a/phlib/include/phnative.h +++ b/phlib/include/phnative.h @@ -633,7 +633,7 @@ PhGetKernelFileName( */ #define PH_NEXT_PROCESS(Process) ( \ ((PSYSTEM_PROCESS_INFORMATION)(Process))->NextEntryOffset ? \ - (PSYSTEM_PROCESS_INFORMATION)((PCHAR)(Process) + \ + (PSYSTEM_PROCESS_INFORMATION)PTR_ADD_OFFSET((Process), \ ((PSYSTEM_PROCESS_INFORMATION)(Process))->NextEntryOffset) : \ NULL \ ) @@ -700,7 +700,7 @@ PhEnumHandlesEx( ) #define PH_NEXT_PAGEFILE(Pagefile) ( \ ((PSYSTEM_PAGEFILE_INFORMATION)(Pagefile))->NextEntryOffset ? \ - (PSYSTEM_PAGEFILE_INFORMATION)((PCHAR)(Pagefile) + \ + (PSYSTEM_PAGEFILE_INFORMATION)PTR_ADD_OFFSET((Pagefile), \ ((PSYSTEM_PAGEFILE_INFORMATION)(Pagefile))->NextEntryOffset) : \ NULL \ ) diff --git a/phlib/kph.c b/phlib/kph.c index 43935b3f7d28..75ccd9d2c3b2 100644 --- a/phlib/kph.c +++ b/phlib/kph.c @@ -372,7 +372,7 @@ VOID KphSetServiceSecurity( RtlLengthSid(&PhSeInteractiveSid); securityDescriptor = PhAllocate(sdAllocationLength); - dacl = (PACL)((PCHAR)securityDescriptor + SECURITY_DESCRIPTOR_MIN_LENGTH); + dacl = (PACL)PTR_ADD_OFFSET(securityDescriptor, SECURITY_DESCRIPTOR_MIN_LENGTH); RtlCreateSecurityDescriptor(securityDescriptor, SECURITY_DESCRIPTOR_REVISION); RtlCreateAcl(dacl, sdAllocationLength - SECURITY_DESCRIPTOR_MIN_LENGTH, ACL_REVISION); diff --git a/phlib/maplib.c b/phlib/maplib.c index 4600b375909f..c46477a3a5aa 100644 --- a/phlib/maplib.c +++ b/phlib/maplib.c @@ -49,9 +49,9 @@ NTSTATUS PhInitializeMappedArchive( ) { NTSTATUS status; - PCHAR start; + PVOID start; - start = (PCHAR)ViewBase; + start = ViewBase; memset(MappedArchive, 0, sizeof(PH_MAPPED_ARCHIVE)); MappedArchive->ViewBase = ViewBase; @@ -78,7 +78,7 @@ NTSTATUS PhInitializeMappedArchive( status = PhpGetMappedArchiveMemberFromHeader( MappedArchive, - (PIMAGE_ARCHIVE_MEMBER_HEADER)(start + IMAGE_ARCHIVE_START_SIZE), + PTR_ADD_OFFSET(start, IMAGE_ARCHIVE_START_SIZE), &MappedArchive->FirstLinkerMember ); diff --git a/phlib/native.c b/phlib/native.c index 7f3c630d2d9a..260c2c4313b7 100644 --- a/phlib/native.c +++ b/phlib/native.c @@ -4307,12 +4307,12 @@ BOOLEAN NTAPI PhpIsDotNetEnumProcessModulesCallback( if (RtlPrefixUnicodeString(&systemRoot, &fileName, TRUE)) { - fileName.Buffer = (PWCHAR)((PCHAR)fileName.Buffer + systemRoot.Length); + fileName.Buffer = (PWCHAR)PTR_ADD_OFFSET(fileName.Buffer, systemRoot.Length); fileName.Length -= systemRoot.Length; if (RtlPrefixUnicodeString(frameworkPart, &fileName, TRUE)) { - fileName.Buffer = (PWCHAR)((PCHAR)fileName.Buffer + frameworkPart->Length); + fileName.Buffer = (PWCHAR)PTR_ADD_OFFSET(fileName.Buffer, frameworkPart->Length); fileName.Length -= frameworkPart->Length; if (fileName.Length >= 4 * sizeof(WCHAR)) // vx.x @@ -5077,7 +5077,7 @@ PPH_STRING PhGetFileName( PhGetSystemRoot(&systemRoot); newFileName = PhCreateStringEx(NULL, systemRoot.Length + FileName->Length - 11 * 2); memcpy(newFileName->Buffer, systemRoot.Buffer, systemRoot.Length); - memcpy((PCHAR)newFileName->Buffer + systemRoot.Length, &FileName->Buffer[11], FileName->Length - 11 * 2); + memcpy(PTR_ADD_OFFSET(newFileName->Buffer, systemRoot.Length), &FileName->Buffer[11], FileName->Length - 11 * 2); } // "system32\" means "C:\Windows\system32\". else if (PhStartsWithString2(FileName, L"system32\\", TRUE)) @@ -5088,7 +5088,7 @@ PPH_STRING PhGetFileName( newFileName = PhCreateStringEx(NULL, systemRoot.Length + 2 + FileName->Length); memcpy(newFileName->Buffer, systemRoot.Buffer, systemRoot.Length); newFileName->Buffer[systemRoot.Length / 2] = '\\'; - memcpy((PCHAR)newFileName->Buffer + systemRoot.Length + 2, FileName->Buffer, FileName->Length); + memcpy(PTR_ADD_OFFSET(newFileName->Buffer, systemRoot.Length + 2), FileName->Buffer, FileName->Length); } else if (FileName->Length != 0 && FileName->Buffer[0] == '\\') { diff --git a/phlib/util.c b/phlib/util.c index 76903763b2bb..979a6a5ca74f 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -5153,7 +5153,7 @@ HANDLE PhGetNamespaceHandle( RtlLengthSid(&PhSeInteractiveSid); securityDescriptor = PhAllocate(sdAllocationLength); - dacl = (PACL)((PCHAR)securityDescriptor + SECURITY_DESCRIPTOR_MIN_LENGTH); + dacl = (PACL)PTR_ADD_OFFSET(securityDescriptor, SECURITY_DESCRIPTOR_MIN_LENGTH); RtlCreateSecurityDescriptor(securityDescriptor, SECURITY_DESCRIPTOR_REVISION); RtlCreateAcl(dacl, sdAllocationLength - SECURITY_DESCRIPTOR_MIN_LENGTH, ACL_REVISION); From cb4f919ddfabd52ba69d231ca5a5bc79657b00e5 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 7 Nov 2017 20:24:21 +1100 Subject: [PATCH 0562/2058] Return PhCreateThread2 ntstatus --- phlib/basesup.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/phlib/basesup.c b/phlib/basesup.c index fd8eb7c8d92d..93a08cfe4c43 100644 --- a/phlib/basesup.c +++ b/phlib/basesup.c @@ -267,11 +267,12 @@ HANDLE PhCreateThread( } } -VOID PhCreateThread2( +NTSTATUS PhCreateThread2( _In_ PUSER_THREAD_START_ROUTINE StartAddress, _In_opt_ PVOID Parameter ) { + NTSTATUS status; HANDLE threadHandle; PPHP_BASE_THREAD_CONTEXT context; @@ -279,7 +280,7 @@ VOID PhCreateThread2( context->StartAddress = StartAddress; context->Parameter = Parameter; - if (NT_SUCCESS(RtlCreateUserThread( + status = RtlCreateUserThread( NtCurrentProcess(), NULL, FALSE, @@ -290,7 +291,9 @@ VOID PhCreateThread2( context, &threadHandle, NULL - ))) + ); + + if (NT_SUCCESS(status)) { PHLIB_INC_STATISTIC(BaseThreadsCreated); NtClose(threadHandle); @@ -300,6 +303,8 @@ VOID PhCreateThread2( PHLIB_INC_STATISTIC(BaseThreadsCreateFailed); PhFreeToFreeList(&PhpBaseThreadContextFreeList, context); } + + return status; } /** From ee79647fcdbb4b27299ae01e1bc55f9094c79d57 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 7 Nov 2017 20:24:36 +1100 Subject: [PATCH 0563/2058] Add missing type --- phlib/include/phbasesup.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phlib/include/phbasesup.h b/phlib/include/phbasesup.h index 5fc24b13821a..9b2c871b6ae2 100644 --- a/phlib/include/phbasesup.h +++ b/phlib/include/phbasesup.h @@ -41,7 +41,7 @@ PhCreateThread( ); PHLIBAPI -VOID +NTSTATUS NTAPI PhCreateThread2( _In_ PUSER_THREAD_START_ROUTINE StartAddress, From 9cffba8eaa18cd5ec8f261815386d942cf6ea4fc Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 9 Nov 2017 14:07:36 +1100 Subject: [PATCH 0564/2058] Remove unused code --- plugins/DotNetTools/main.c | 15 --------------- plugins/OnlineChecks/main.c | 2 +- plugins/WindowExplorer/main.c | 15 --------------- 3 files changed, 1 insertion(+), 31 deletions(-) diff --git a/plugins/DotNetTools/main.c b/plugins/DotNetTools/main.c index 759559574503..c54131347ba7 100644 --- a/plugins/DotNetTools/main.c +++ b/plugins/DotNetTools/main.c @@ -26,7 +26,6 @@ PPH_PLUGIN PluginInstance; static PH_CALLBACK_REGISTRATION PluginLoadCallbackRegistration; static PH_CALLBACK_REGISTRATION PluginUnloadCallbackRegistration; -static PH_CALLBACK_REGISTRATION PluginShowOptionsCallbackRegistration; static PH_CALLBACK_REGISTRATION PluginMenuItemCallbackRegistration; static PH_CALLBACK_REGISTRATION PluginTreeNewMessageCallbackRegistration; static PH_CALLBACK_REGISTRATION PluginPhSvcRequestCallbackRegistration; @@ -56,14 +55,6 @@ VOID NTAPI UnloadCallback( NOTHING; } -VOID NTAPI ShowOptionsCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - NOTHING; -} - VOID NTAPI MenuItemCallback( _In_opt_ PVOID Parameter, _In_opt_ PVOID Context @@ -237,12 +228,6 @@ LOGICAL DllMain( NULL, &PluginUnloadCallbackRegistration ); - PhRegisterCallback( - PhGetPluginCallback(PluginInstance, PluginCallbackShowOptions), - ShowOptionsCallback, - NULL, - &PluginShowOptionsCallbackRegistration - ); //PhRegisterCallback( // PhGetPluginCallback(PluginInstance, PluginCallbackMenuItem), // MenuItemCallback, diff --git a/plugins/OnlineChecks/main.c b/plugins/OnlineChecks/main.c index cbc39b076775..c199c8070458 100644 --- a/plugins/OnlineChecks/main.c +++ b/plugins/OnlineChecks/main.c @@ -264,7 +264,7 @@ VOID NTAPI MainMenuInitializingCallback( PhInsertEMenuItem(onlineMenuItem, enableMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, ENABLE_SERVICE_VIRUSTOTAL, L"Enable VirusTotal scanning", NULL), -1); PhInsertEMenuItem(onlineMenuItem, PhPluginCreateEMenuItem(PluginInstance, PH_EMENU_SEPARATOR, 0, NULL, NULL), -1); PhInsertEMenuItem(onlineMenuItem, PhPluginCreateEMenuItem(PluginInstance, 0, MENUITEM_VIRUSTOTAL_UPLOAD_FILE, L"Upload file to VirusTotal...", NULL), -1); - PhInsertEMenuItem(onlineMenuItem, PhPluginCreateEMenuItem(PluginInstance, 0, MENUITEM_VIRUSTOTAL_QUEUE, L"Upload unknown files to VirusTotal...", NULL), -1); + //PhInsertEMenuItem(onlineMenuItem, PhPluginCreateEMenuItem(PluginInstance, 0, MENUITEM_VIRUSTOTAL_QUEUE, L"Upload unknown files to VirusTotal...", NULL), -1); PhInsertEMenuItem(menuInfo->Menu, onlineMenuItem, -1); if (VirusTotalScanningEnabled) diff --git a/plugins/WindowExplorer/main.c b/plugins/WindowExplorer/main.c index e0fbcffdc876..e6a4aadfa86f 100644 --- a/plugins/WindowExplorer/main.c +++ b/plugins/WindowExplorer/main.c @@ -28,7 +28,6 @@ BOOLEAN IsHookClient; PPH_PLUGIN PluginInstance; PH_CALLBACK_REGISTRATION PluginLoadCallbackRegistration; PH_CALLBACK_REGISTRATION PluginUnloadCallbackRegistration; -PH_CALLBACK_REGISTRATION PluginShowOptionsCallbackRegistration; PH_CALLBACK_REGISTRATION PluginMenuItemCallbackRegistration; PH_CALLBACK_REGISTRATION MainMenuInitializingCallbackRegistration; PH_CALLBACK_REGISTRATION ProcessPropertiesInitializingCallbackRegistration; @@ -50,14 +49,6 @@ VOID NTAPI UnloadCallback( WeHookServerUninitialization(); } -VOID NTAPI ShowOptionsCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - NOTHING; -} - BOOL CALLBACK WepEnumDesktopProc( _In_ LPTSTR lpszDesktop, _In_ LPARAM lParam @@ -276,12 +267,6 @@ LOGICAL DllMain( NULL, &PluginUnloadCallbackRegistration ); - //PhRegisterCallback( - // PhGetPluginCallback(PluginInstance, PluginCallbackShowOptions), - // ShowOptionsCallback, - // NULL, - // &PluginShowOptionsCallbackRegistration - // ); PhRegisterCallback( PhGetPluginCallback(PluginInstance, PluginCallbackMenuItem), MenuItemCallback, From da3c18b7bdc7d26cc194d433247394fff9d5aab9 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 9 Nov 2017 14:08:50 +1100 Subject: [PATCH 0565/2058] Enable assert, Remove cast --- phlib/include/hndlinfo.h | 4 ++-- phnt/include/ntexapi.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/phlib/include/hndlinfo.h b/phlib/include/hndlinfo.h index 9a79c013d6c1..fb0849f524b9 100644 --- a/phlib/include/hndlinfo.h +++ b/phlib/include/hndlinfo.h @@ -70,10 +70,10 @@ PhGetHandleInformationEx( ); #define PH_FIRST_OBJECT_TYPE(ObjectTypes) \ - (POBJECT_TYPE_INFORMATION)PTR_ADD_OFFSET(ObjectTypes, ALIGN_UP(sizeof(OBJECT_TYPES_INFORMATION), ULONG_PTR)) + PTR_ADD_OFFSET(ObjectTypes, ALIGN_UP(sizeof(OBJECT_TYPES_INFORMATION), ULONG_PTR)) #define PH_NEXT_OBJECT_TYPE(ObjectType) \ - (POBJECT_TYPE_INFORMATION)PTR_ADD_OFFSET(ObjectType, sizeof(OBJECT_TYPE_INFORMATION) + \ + PTR_ADD_OFFSET(ObjectType, sizeof(OBJECT_TYPE_INFORMATION) + \ ALIGN_UP(ObjectType->TypeName.MaximumLength, ULONG_PTR)) PHLIBAPI diff --git a/phnt/include/ntexapi.h b/phnt/include/ntexapi.h index 595381753cec..f7bea46bf049 100644 --- a/phnt/include/ntexapi.h +++ b/phnt/include/ntexapi.h @@ -3530,7 +3530,7 @@ C_ASSERT(FIELD_OFFSET(KUSER_SHARED_DATA, SystemCallPad) == 0x310); C_ASSERT(FIELD_OFFSET(KUSER_SHARED_DATA, TickCount) == 0x320); C_ASSERT(FIELD_OFFSET(KUSER_SHARED_DATA, TickCountQuad) == 0x320); C_ASSERT(FIELD_OFFSET(KUSER_SHARED_DATA, XState) == 0x3d8); -//C_ASSERT(sizeof(KUSER_SHARED_DATA) == 0x704); // Visual Studio has a problem with this +C_ASSERT(sizeof(KUSER_SHARED_DATA) == 0x708); #define USER_SHARED_DATA ((KUSER_SHARED_DATA * const)0x7ffe0000) From a24dffdccf9094a5e14c5a3eed39723ce6301c1c Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 12 Nov 2017 02:05:58 +1100 Subject: [PATCH 0566/2058] NetworkTools: Fix tracert handle leak --- plugins/NetworkTools/tracetree.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/plugins/NetworkTools/tracetree.c b/plugins/NetworkTools/tracetree.c index 0423c418332e..919e7074f906 100644 --- a/plugins/NetworkTools/tracetree.c +++ b/plugins/NetworkTools/tracetree.c @@ -51,6 +51,9 @@ VOID NTAPI TracertTreeNodeItemDeleteProcedure( if (tracertNode->PingString[i]) PhDereferenceObject(tracertNode->PingString[i]); } + + if (tracertNode->CountryIcon) + DestroyIcon(tracertNode->CountryIcon); } PTRACERT_ROOT_NODE TracertTreeCreateNode( From a19360b645e495242b6be5992e9554107ab117a4 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 12 Nov 2017 19:14:05 +1100 Subject: [PATCH 0567/2058] Update help text --- ProcessHacker/mwpgproc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ProcessHacker/mwpgproc.c b/ProcessHacker/mwpgproc.c index 619dbe6c12ee..142240387119 100644 --- a/ProcessHacker/mwpgproc.c +++ b/ProcessHacker/mwpgproc.c @@ -243,7 +243,7 @@ VOID PhMwpToggleSignedProcessTreeFilter( PhShowInformation( PhMainWndHandle, L"This filter cannot function because digital signature checking is not enabled. " - L"Enable it in Options > Advanced and restart Process Hacker." + L"Enable it in Options > General and restart Process Hacker." ); } From 8be9996c91b9a49ce461714098da8b4a2f2760be Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 12 Nov 2017 19:16:56 +1100 Subject: [PATCH 0568/2058] Improve consistency, Tidy up comments --- ProcessHacker/include/netprv.h | 2 +- ProcessHacker/netprv.c | 58 +++++++++++++++++++--------------- ProcessHacker/ntobjprp.c | 2 +- ProcessHacker/procprv.c | 6 ++-- phnt/include/ntmmapi.h | 4 +-- 5 files changed, 40 insertions(+), 32 deletions(-) diff --git a/ProcessHacker/include/netprv.h b/ProcessHacker/include/netprv.h index beaecea2b4a1..7b26038ed53f 100644 --- a/ProcessHacker/include/netprv.h +++ b/ProcessHacker/include/netprv.h @@ -25,7 +25,7 @@ typedef struct _PH_NETWORK_ITEM BOOLEAN ProcessIconValid; PPH_STRING OwnerName; - BOOLEAN JustResolved; + ULONG JustResolved; WCHAR LocalAddressString[65]; WCHAR LocalPortString[PH_INT32_STR_LEN_1]; diff --git a/ProcessHacker/netprv.c b/ProcessHacker/netprv.c index 07968e356c33..8930c1ec20fb 100644 --- a/ProcessHacker/netprv.c +++ b/ProcessHacker/netprv.c @@ -456,6 +456,35 @@ VOID PhpUpdateNetworkItemOwner( } } +VOID PhFlushNetworkQueryData( + VOID + ) +{ + PSLIST_ENTRY entry; + PPH_NETWORK_ITEM_QUERY_DATA data; + + if (RtlQueryDepthSList(&PhNetworkItemQueryListHead) == 0) + return; + + entry = RtlInterlockedFlushSList(&PhNetworkItemQueryListHead); + + while (entry) + { + data = CONTAINING_RECORD(entry, PH_NETWORK_ITEM_QUERY_DATA, ListEntry); + entry = entry->Next; + + if (data->Remote) + PhMoveReference(&data->NetworkItem->RemoteHostString, data->HostString); + else + PhMoveReference(&data->NetworkItem->LocalHostString, data->HostString); + + data->NetworkItem->JustResolved = TRUE; + + PhDereferenceObject(data->NetworkItem); + PhFree(data); + } +} + VOID PhNetworkProviderUpdate( _In_ PVOID Object ) @@ -476,6 +505,7 @@ VOID PhNetworkProviderUpdate( if (!PhGetNetworkConnections(&connections, &numberOfConnections)) return; + // Look for closed connections. { PPH_LIST connectionsToRemove = NULL; PH_HASHTABLE_ENUM_CONTEXT enumContext; @@ -527,29 +557,9 @@ VOID PhNetworkProviderUpdate( } // Go through the queued network item query data. - { - PSLIST_ENTRY entry; - PPH_NETWORK_ITEM_QUERY_DATA data; - - entry = RtlInterlockedFlushSList(&PhNetworkItemQueryListHead); - - while (entry) - { - data = CONTAINING_RECORD(entry, PH_NETWORK_ITEM_QUERY_DATA, ListEntry); - entry = entry->Next; - - if (data->Remote) - PhMoveReference(&data->NetworkItem->RemoteHostString, data->HostString); - else - PhMoveReference(&data->NetworkItem->LocalHostString, data->HostString); - - data->NetworkItem->JustResolved = TRUE; - - PhDereferenceObject(data->NetworkItem); - PhFree(data); - } - } + PhFlushNetworkQueryData(); + // Look for new network connections and update existing ones. for (i = 0; i < numberOfConnections; i++) { PPH_NETWORK_ITEM networkItem; @@ -673,7 +683,7 @@ VOID PhNetworkProviderUpdate( BOOLEAN modified = FALSE; PPH_PROCESS_ITEM processItem; - if (networkItem->JustResolved) + if (InterlockedExchange(&networkItem->JustResolved, 0) != 0) modified = TRUE; if (networkItem->State != connections[i].State) @@ -705,8 +715,6 @@ VOID PhNetworkProviderUpdate( } } - networkItem->JustResolved = FALSE; - if (modified) { // Raise the network item modified event. diff --git a/ProcessHacker/ntobjprp.c b/ProcessHacker/ntobjprp.c index b2e892f6550f..e7aa709fa6e8 100644 --- a/ProcessHacker/ntobjprp.c +++ b/ProcessHacker/ntobjprp.c @@ -393,7 +393,7 @@ static VOID PhpRefreshMutantPageInfo( { PPH_STRING name; - if (ownerInfo.ClientId.UniqueProcess != NULL) + if (ownerInfo.ClientId.UniqueProcess) { name = PhGetClientIdName(&ownerInfo.ClientId); SetDlgItemText(hwndDlg, IDC_OWNER, name->Buffer); diff --git a/ProcessHacker/procprv.c b/ProcessHacker/procprv.c index a55eefbc3460..dc516afedcd9 100644 --- a/ProcessHacker/procprv.c +++ b/ProcessHacker/procprv.c @@ -1808,7 +1808,7 @@ VOID PhFlushProcessQueryData( PPH_PROCESS_QUERY_DATA data; BOOLEAN processed; - if (!RtlFirstEntrySList(&PhProcessQueryDataListHead)) + if (RtlQueryDepthSList(&PhProcessQueryDataListHead) == 0) return; entry = RtlInterlockedFlushSList(&PhProcessQueryDataListHead); @@ -1847,7 +1847,7 @@ VOID PhFlushProcessQueryData( } else { - data->ProcessItem->JustProcessed = 1; + data->ProcessItem->JustProcessed = TRUE; } } @@ -2323,7 +2323,7 @@ VOID PhProcessProviderUpdate( // Max. values - if (processItem->ProcessId != NULL) + if (processItem->ProcessId) { if (maxCpuValue < newCpuUsage) { diff --git a/phnt/include/ntmmapi.h b/phnt/include/ntmmapi.h index 02a3e19e74b4..2ae1234f5551 100644 --- a/phnt/include/ntmmapi.h +++ b/phnt/include/ntmmapi.h @@ -308,8 +308,8 @@ typedef struct _MMPFN_MEMSNAP_INFORMATION typedef enum _SECTION_INFORMATION_CLASS { - SectionBasicInformation, - SectionImageInformation, + SectionBasicInformation, // q; SECTION_BASIC_INFORMATION + SectionImageInformation, // q; SECTION_IMAGE_INFORMATION SectionRelocationInformation, // name:wow64:whNtQuerySection_SectionRelocationInformation SectionOriginalBaseInformation, // PVOID BaseAddress SectionInternalImageInformation, // SECTION_INTERNAL_IMAGE_INFORMATION // since REDSTONE2 From bcfb0c6a30744b04a50ad70e2aff97320e8a66c3 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 12 Nov 2017 19:27:25 +1100 Subject: [PATCH 0569/2058] Fix typo --- ProcessHacker/main.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/ProcessHacker/main.c b/ProcessHacker/main.c index 3381dfd1f705..74c1e506236b 100644 --- a/ProcessHacker/main.c +++ b/ProcessHacker/main.c @@ -233,6 +233,19 @@ INT WINAPI wWinMain( PhLoadPlugins(); } + if (WindowsVersion >= WINDOWS_10) + { + PROCESS_MITIGATION_POLICY_INFORMATION policyInfo; + + // Note: The PhInitializeMitigationPolicy function enables the other mitigation policies. + // However, we can only enable the ProcessSignaturePolicy after loading plugins. + policyInfo.Policy = ProcessSignaturePolicy; + policyInfo.SignaturePolicy.Flags = 0; + policyInfo.SignaturePolicy.MicrosoftSignedOnly = TRUE; + + NtSetInformationProcess(NtCurrentProcess(), ProcessMitigationPolicy, &policyInfo, sizeof(PROCESS_MITIGATION_POLICY_INFORMATION)); + } + if (PhStartupParameters.PhSvc) { MSG message; @@ -548,7 +561,7 @@ VOID PhInitializeMitigationPolicy( KEY_WRITE | DELETE, PH_KEY_LOCAL_MACHINE, &policyKeyName, - 0, + OBJ_OPENIF, 0, NULL ))) From d3cd9ddafb128e0786d086870bda0ec31f493bcf Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 12 Nov 2017 19:40:54 +1100 Subject: [PATCH 0570/2058] Partial revert commit 6e38952c --- ProcessHacker/notifico.c | 4 ++-- ProcessHacker/searchbox.c | 8 ++++---- phlib/guisup.c | 4 ++-- phlib/icotobmp.c | 4 ++-- phlib/settings.c | 4 ++-- tools/peview/searchbox.c | 8 ++++---- 6 files changed, 16 insertions(+), 16 deletions(-) diff --git a/ProcessHacker/notifico.c b/ProcessHacker/notifico.c index 15f244a30e4c..4b72394b0adf 100644 --- a/ProcessHacker/notifico.c +++ b/ProcessHacker/notifico.c @@ -754,7 +754,7 @@ VOID PhNfpBeginBitmap2( { HDC screenHdc; - screenHdc = CreateIC(L"DISPLAY", NULL, NULL, NULL); + screenHdc = GetDC(NULL); Context->Hdc = CreateCompatibleDC(screenHdc); memset(&Context->Header, 0, sizeof(BITMAPINFOHEADER)); @@ -765,7 +765,7 @@ VOID PhNfpBeginBitmap2( Context->Header.biBitCount = 32; Context->Bitmap = CreateDIBSection(screenHdc, (BITMAPINFO *)&Context->Header, DIB_RGB_COLORS, &Context->Bits, NULL, 0); - DeleteDC(screenHdc); + ReleaseDC(NULL, screenHdc); Context->Initialized = TRUE; } diff --git a/ProcessHacker/searchbox.c b/ProcessHacker/searchbox.c index c60f2d6780f0..6fd37ed6c719 100644 --- a/ProcessHacker/searchbox.c +++ b/ProcessHacker/searchbox.c @@ -496,7 +496,7 @@ HICON PhpSearchBitmapToIcon( HBITMAP screenBitmap; ICONINFO iconInfo = { 0 }; - screenDc = CreateIC(L"DISPLAY", NULL, NULL, NULL); + screenDc = GetDC(NULL); screenBitmap = CreateCompatibleBitmap(screenDc, Width, Height); iconInfo.fIcon = TRUE; @@ -506,7 +506,7 @@ HICON PhpSearchBitmapToIcon( icon = CreateIconIndirect(&iconInfo); DeleteObject(screenBitmap); - DeleteDC(screenDc); + ReleaseDC(NULL, screenDc); return icon; } @@ -644,7 +644,7 @@ HBITMAP PhLoadPngImageFromResource( bitmapInfo.bmiHeader.biBitCount = 32; bitmapInfo.bmiHeader.biCompression = BI_RGB; - screenHdc = CreateIC(L"DISPLAY", NULL, NULL, NULL); + screenHdc = GetDC(NULL); bufferDc = CreateCompatibleDC(screenHdc); bitmapHandle = CreateDIBSection(screenHdc, &bitmapInfo, DIB_RGB_COLORS, &bitmapBuffer, NULL, 0); @@ -668,7 +668,7 @@ HBITMAP PhLoadPngImageFromResource( DeleteDC(bufferDc); if (screenHdc) - DeleteDC(screenHdc); + ReleaseDC(NULL, screenHdc); if (wicBitmapSource) IWICBitmapSource_Release(wicBitmapSource); diff --git a/phlib/guisup.c b/phlib/guisup.c index a2d3f18aa4b3..e223e14d9d43 100644 --- a/phlib/guisup.c +++ b/phlib/guisup.c @@ -47,10 +47,10 @@ VOID PhGuiSupportInitialization( PVOID shell32Handle; PVOID shlwapiHandle; - if (hdc = CreateIC(L"DISPLAY", NULL, NULL, NULL)) + if (hdc = GetDC(NULL)) { PhGlobalDpi = GetDeviceCaps(hdc, LOGPIXELSY); - DeleteDC(hdc); + ReleaseDC(NULL, hdc); } shell32Handle = LoadLibrary(L"shell32.dll"); diff --git a/phlib/icotobmp.c b/phlib/icotobmp.c index b70d72c5b1af..9d4ce2878c84 100644 --- a/phlib/icotobmp.c +++ b/phlib/icotobmp.c @@ -160,10 +160,10 @@ HBITMAP PhIconToBitmap( iconRectangle.right = Width; iconRectangle.bottom = Height; - screenHdc = CreateIC(L"DISPLAY", NULL, NULL, NULL); + screenHdc = GetDC(NULL); hdc = CreateCompatibleDC(screenHdc); bitmap = PhpCreateBitmap32(screenHdc, Width, Height, NULL); - DeleteDC(screenHdc); + ReleaseDC(NULL, screenHdc); oldBitmap = SelectObject(hdc, bitmap); paintParams.dwFlags = BPPF_ERASE; diff --git a/phlib/settings.c b/phlib/settings.c index a068218c07b2..fd5ce5fd3e2f 100644 --- a/phlib/settings.c +++ b/phlib/settings.c @@ -117,10 +117,10 @@ static ULONG PhpGetCurrentScale( { HDC hdc; - if (hdc = CreateIC(L"DISPLAY", NULL, NULL, NULL)) + if (hdc = GetDC(NULL)) { dpi = GetDeviceCaps(hdc, LOGPIXELSY); - DeleteDC(hdc); + ReleaseDC(NULL, hdc); } PhEndInitOnce(&initOnce); diff --git a/tools/peview/searchbox.c b/tools/peview/searchbox.c index e7774bb44573..1d51bf7c061b 100644 --- a/tools/peview/searchbox.c +++ b/tools/peview/searchbox.c @@ -252,7 +252,7 @@ HBITMAP PhLoadPngImageFromResource( bitmapInfo.bmiHeader.biBitCount = 32; bitmapInfo.bmiHeader.biCompression = BI_RGB; - screenHdc = CreateIC(L"DISPLAY", NULL, NULL, NULL); + screenHdc = GetDC(NULL); bufferDc = CreateCompatibleDC(screenHdc); bitmapHandle = CreateDIBSection(screenHdc, &bitmapInfo, DIB_RGB_COLORS, &bitmapBuffer, NULL, 0); @@ -276,7 +276,7 @@ HBITMAP PhLoadPngImageFromResource( DeleteDC(bufferDc); if (screenHdc) - DeleteDC(screenHdc); + ReleaseDC(NULL, screenHdc); if (wicBitmapSource) IWICBitmapSource_Release(wicBitmapSource); @@ -671,7 +671,7 @@ HICON PhpSearchBitmapToIcon( HBITMAP screenBitmap; ICONINFO iconInfo = { 0 }; - screenDc = CreateIC(L"DISPLAY", NULL, NULL, NULL); + screenDc = GetDC(NULL); screenBitmap = CreateCompatibleBitmap(screenDc, Width, Height); iconInfo.fIcon = TRUE; @@ -681,7 +681,7 @@ HICON PhpSearchBitmapToIcon( icon = CreateIconIndirect(&iconInfo); DeleteObject(screenBitmap); - DeleteDC(screenDc); + ReleaseDC(NULL, screenDc); return icon; } From 442945d7ec65979937f3a1a2cca5a19886ec4008 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 13 Nov 2017 03:39:17 +1100 Subject: [PATCH 0571/2058] Update handle enumeration, Add PhEnumHandlesEx2 --- ProcessHacker/hndlprv.c | 56 +++++++++++++++++++-------------- ProcessHacker/include/hndlprv.h | 1 + phlib/include/phnative.h | 8 +++++ phlib/native.c | 53 +++++++++++++++++++++++++++++++ 4 files changed, 94 insertions(+), 24 deletions(-) diff --git a/ProcessHacker/hndlprv.c b/ProcessHacker/hndlprv.c index 75d548132531..d831817461b9 100644 --- a/ProcessHacker/hndlprv.c +++ b/ProcessHacker/hndlprv.c @@ -3,6 +3,7 @@ * handle provider * * Copyright (C) 2010-2015 wj32 + * Copyright (C) 2017 dmex * * This file is part of Process Hacker. * @@ -84,7 +85,7 @@ PPH_HANDLE_PROVIDER PhCreateHandleProvider( handleProvider->RunStatus = PhOpenProcess( &handleProvider->ProcessHandle, - PROCESS_DUP_HANDLE, + PROCESS_QUERY_INFORMATION | PROCESS_DUP_HANDLE, ProcessId ); @@ -133,11 +134,13 @@ PPH_HANDLE_ITEM PhCreateHandleItem( if (Handle) { handleItem->Handle = (HANDLE)Handle->HandleValue; - PhPrintPointer(handleItem->HandleString, (PVOID)handleItem->Handle); handleItem->Object = Handle->Object; - PhPrintPointer(handleItem->ObjectString, handleItem->Object); handleItem->Attributes = Handle->HandleAttributes; handleItem->GrantedAccess = (ACCESS_MASK)Handle->GrantedAccess; + handleItem->TypeIndex = Handle->ObjectTypeIndex; + + PhPrintPointer(handleItem->HandleString, (PVOID)handleItem->Handle); + PhPrintPointer(handleItem->ObjectString, handleItem->Object); PhPrintPointer(handleItem->GrantedAccessString, UlongToPtr(handleItem->GrantedAccess)); } @@ -299,40 +302,34 @@ NTSTATUS PhEnumHandlesGeneric( NTSTATUS status; // There are three ways of enumerating handles: - // * When KProcessHacker is available, using KphEnumerateProcessHandles - // is the most efficient method. - // * On Windows XP and later, NtQuerySystemInformation with - // SystemExtendedHandleInformation can be used. - // * Otherwise, NtQuerySystemInformation with SystemHandleInformation - // can be used. - - if (KphIsConnected()) + // * On Windows 8 and later, NtQueryInformationProcess with ProcessHandleInformation is the most efficient method. + // * On Windows XP and later, NtQuerySystemInformation with SystemExtendedHandleInformation. + // * Otherwise, NtQuerySystemInformation with SystemHandleInformation can be used. + + if (WindowsVersion >= WINDOWS_8) { - PKPH_PROCESS_HANDLE_INFORMATION handles; + PPROCESS_HANDLE_SNAPSHOT_INFORMATION handles; PSYSTEM_HANDLE_INFORMATION_EX convertedHandles; ULONG i; - // Enumerate handles using KProcessHacker. Unlike with NtQuerySystemInformation, - // this only enumerates handles for a single process and saves a lot of processing. - - if (!NT_SUCCESS(status = KphEnumerateProcessHandles2(ProcessHandle, &handles))) + if (!NT_SUCCESS(status = PhEnumHandlesEx2(ProcessHandle, &handles))) goto FAILED; convertedHandles = PhAllocate( FIELD_OFFSET(SYSTEM_HANDLE_INFORMATION_EX, Handles) + - sizeof(SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX) * handles->HandleCount + sizeof(SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX) * handles->NumberOfHandles ); - convertedHandles->NumberOfHandles = handles->HandleCount; + convertedHandles->NumberOfHandles = handles->NumberOfHandles; - for (i = 0; i < handles->HandleCount; i++) + for (i = 0; i < handles->NumberOfHandles; i++) { - convertedHandles->Handles[i].Object = handles->Handles[i].Object; + convertedHandles->Handles[i].Object = 0; convertedHandles->Handles[i].UniqueProcessId = (ULONG_PTR)ProcessId; - convertedHandles->Handles[i].HandleValue = (ULONG_PTR)handles->Handles[i].Handle; - convertedHandles->Handles[i].GrantedAccess = (ULONG)handles->Handles[i].GrantedAccess; + convertedHandles->Handles[i].HandleValue = (ULONG_PTR)handles->Handles[i].HandleValue; + convertedHandles->Handles[i].GrantedAccess = handles->Handles[i].GrantedAccess; convertedHandles->Handles[i].CreatorBackTraceIndex = 0; - convertedHandles->Handles[i].ObjectTypeIndex = handles->Handles[i].ObjectTypeIndex; + convertedHandles->Handles[i].ObjectTypeIndex = (USHORT)handles->Handles[i].ObjectTypeIndex; convertedHandles->Handles[i].HandleAttributes = handles->Handles[i].HandleAttributes; } @@ -503,10 +500,21 @@ VOID PhHandleProviderUpdate( // different object wasn't re-opened with the same // handle value. This isn't 100% accurate as pool // addresses may be re-used, but it works well. - if (handleItem->Object == (*tempHashtableValue)->Object) + if (handleItem->Object && handleItem->Object == (*tempHashtableValue)->Object) { found = TRUE; } + else + { + if ( + handleItem->Handle == (HANDLE)(*tempHashtableValue)->HandleValue && + handleItem->GrantedAccess == (*tempHashtableValue)->GrantedAccess && + handleItem->TypeIndex == (*tempHashtableValue)->ObjectTypeIndex + ) + { + found = TRUE; + } + } } if (!found) diff --git a/ProcessHacker/include/hndlprv.h b/ProcessHacker/include/hndlprv.h index 7238239efc06..d2bb0afd9677 100644 --- a/ProcessHacker/include/hndlprv.h +++ b/ProcessHacker/include/hndlprv.h @@ -18,6 +18,7 @@ typedef struct _PH_HANDLE_ITEM PVOID Object; ULONG Attributes; ACCESS_MASK GrantedAccess; + ULONG TypeIndex; ULONG FileFlags; PPH_STRING TypeName; diff --git a/phlib/include/phnative.h b/phlib/include/phnative.h index a0c4e45bfed2..a3773c94dfeb 100644 --- a/phlib/include/phnative.h +++ b/phlib/include/phnative.h @@ -691,6 +691,14 @@ PhEnumHandlesEx( _Out_ PSYSTEM_HANDLE_INFORMATION_EX *Handles ); +PHLIBAPI +NTSTATUS +NTAPI +PhEnumHandlesEx2( + _In_ HANDLE ProcessHandle, + _Out_ PPROCESS_HANDLE_SNAPSHOT_INFORMATION *Handles + ); + #define PH_FIRST_PAGEFILE(Pagefiles) ( \ /* The size of a pagefile can never be 0. A TotalSize of 0 * is used to indicate that there are no pagefiles. diff --git a/phlib/native.c b/phlib/native.c index 260c2c4313b7..3a332dcd5bd5 100644 --- a/phlib/native.c +++ b/phlib/native.c @@ -4141,6 +4141,59 @@ NTSTATUS PhEnumHandlesEx( return status; } +/** + * Enumerates all open handles. + * + * \param ProcessHandle A handle to the process. The handle must have PROCESS_LIMITED_INFORMATION access. + * \param Handles A variable which receives a pointer to a structure containing information about + * handles opened by the process. You must free the structure using PhFree() when you no longer need it. + * + * \retval STATUS_INSUFFICIENT_RESOURCES The handle information returned by the kernel is too large. + * + * \remarks This function is only available starting with Windows 8. + */ +NTSTATUS PhEnumHandlesEx2( + _In_ HANDLE ProcessHandle, + _Out_ PPROCESS_HANDLE_SNAPSHOT_INFORMATION *Handles + ) +{ + NTSTATUS status; + PVOID buffer; + ULONG bufferSize = 0x1000; + ULONG returnLength = 0; + + buffer = PhAllocate(bufferSize); + + while ((status = NtQueryInformationProcess( + ProcessHandle, + ProcessHandleInformation, + buffer, + bufferSize, + &returnLength + )) == STATUS_INFO_LENGTH_MISMATCH) + { + PhFree(buffer); + bufferSize *= 2; + + // Fail if we're resizing the buffer to something very large. + if (bufferSize > PH_LARGE_BUFFER_SIZE) + return STATUS_INSUFFICIENT_RESOURCES; + + buffer = PhAllocate(bufferSize); + } + + if (NT_SUCCESS(status)) + { + *Handles = buffer; + } + else + { + PhFree(buffer); + } + + return status; +} + /** * Enumerates all pagefiles. * From aaacd0f7f69d6f18faac220a561c7bc57d07f464 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 13 Nov 2017 03:50:33 +1100 Subject: [PATCH 0572/2058] Fix typo, Improve PhEnumHandlesEx2 performance --- phlib/native.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/phlib/native.c b/phlib/native.c index 3a332dcd5bd5..f3796615e83e 100644 --- a/phlib/native.c +++ b/phlib/native.c @@ -4144,7 +4144,7 @@ NTSTATUS PhEnumHandlesEx( /** * Enumerates all open handles. * - * \param ProcessHandle A handle to the process. The handle must have PROCESS_LIMITED_INFORMATION access. + * \param ProcessHandle A handle to the process. The handle must have PROCESS_QUERY_INFORMATION access. * \param Handles A variable which receives a pointer to a structure containing information about * handles opened by the process. You must free the structure using PhFree() when you no longer need it. * @@ -4159,7 +4159,7 @@ NTSTATUS PhEnumHandlesEx2( { NTSTATUS status; PVOID buffer; - ULONG bufferSize = 0x1000; + ULONG bufferSize = 0x8000; ULONG returnLength = 0; buffer = PhAllocate(bufferSize); From 4b8f8b44152ff3756f3938c79e256f993ec785b6 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 13 Nov 2017 11:33:37 +1100 Subject: [PATCH 0573/2058] NetworkTools: Fix memory leak --- plugins/NetworkTools/nettools.h | 1 - plugins/NetworkTools/pages.c | 1 + plugins/NetworkTools/update.c | 40 +++++++++++++++++++-------------- 3 files changed, 24 insertions(+), 18 deletions(-) diff --git a/plugins/NetworkTools/nettools.h b/plugins/NetworkTools/nettools.h index 4255eaa3d2f9..ff6aaa2f3427 100644 --- a/plugins/NetworkTools/nettools.h +++ b/plugins/NetworkTools/nettools.h @@ -274,7 +274,6 @@ typedef struct _PH_UPDATER_CONTEXT PPH_STRING FileDownloadUrl; PPH_STRING RevVersion; PPH_STRING Size; - PPH_STRING SetupFilePath; } PH_UPDATER_CONTEXT, *PPH_UPDATER_CONTEXT; VOID TaskDialogLinkClicked( diff --git a/plugins/NetworkTools/pages.c b/plugins/NetworkTools/pages.c index d5fb5a254762..8479aa9886ff 100644 --- a/plugins/NetworkTools/pages.c +++ b/plugins/NetworkTools/pages.c @@ -83,6 +83,7 @@ HRESULT CALLBACK CheckingForUpdatesDbCallbackProc( SendMessage(hwndDlg, TDM_SET_MARQUEE_PROGRESS_BAR, TRUE, 0); SendMessage(hwndDlg, TDM_SET_PROGRESS_BAR_MARQUEE, TRUE, 1); + PhReferenceObject(context); PhQueueItemWorkQueue(PhGetGlobalWorkQueue(), GeoIPUpdateThread, context); } break; diff --git a/plugins/NetworkTools/update.c b/plugins/NetworkTools/update.c index 774069ad8e55..39c0ee32a5b5 100644 --- a/plugins/NetworkTools/update.c +++ b/plugins/NetworkTools/update.c @@ -43,9 +43,6 @@ VOID FreeUpdateContext( if (Context->Size) PhDereferenceObject(Context->Size); - if (Context->SetupFilePath) - PhDereferenceObject(Context->SetupFilePath); - PhDereferenceObject(Context); } @@ -196,10 +193,14 @@ NTSTATUS GeoIPUpdateThread( HANDLE tempFileHandle = NULL; PPH_STRING fwLinkUrl = NULL; PPH_HTTP_CONTEXT httpContext = NULL; + PPH_STRING zipFilePath = NULL; PPH_STRING versionString = NULL; PPH_STRING userAgentString = NULL; PPH_STRING httpHostName = NULL; PPH_STRING httpHostPath = NULL; + PPH_STRING dbpath = NULL; + PPH_BYTES mmdbGzPath = NULL; + gzFile gzfile = NULL; USHORT httpHostPort = 0; LARGE_INTEGER timeNow; LARGE_INTEGER timeStart; @@ -212,14 +213,14 @@ NTSTATUS GeoIPUpdateThread( if (!(fwLinkUrl = QueryFwLinkUrl(context))) goto CleanupExit; - context->SetupFilePath = PhCreateCacheFile(PhaCreateString(L"GeoLite2-Country.mmdb.gz")); + zipFilePath = PhCreateCacheFile(PhaCreateString(L"GeoLite2-Country.mmdb.gz")); - if (PhIsNullOrEmptyString(context->SetupFilePath)) + if (PhIsNullOrEmptyString(zipFilePath)) goto CleanupExit; if (!NT_SUCCESS(PhCreateFileWin32( &tempFileHandle, - PhGetString(context->SetupFilePath), + PhGetString(zipFilePath), FILE_GENERIC_READ | FILE_GENERIC_WRITE, FILE_ATTRIBUTE_NOT_CONTENT_INDEXED | FILE_ATTRIBUTE_TEMPORARY, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, @@ -371,18 +372,11 @@ NTSTATUS GeoIPUpdateThread( } { - PPH_STRING dbpath; - PPH_BYTES mmdbGzPath; - gzFile gzfile; - dbpath = PhGetExpandStringSetting(SETTING_NAME_DB_LOCATION); if (PhIsNullOrEmptyString(dbpath)) PhMoveReference(&dbpath, PhGetKnownLocation(CSIDL_APPDATA, L"\\Process Hacker\\GeoLite2-Country.mmdb")); - PhAutoDereferenceObject(dbpath); - mmdbGzPath = PH_AUTO(PhConvertUtf16ToUtf8(PhGetString(context->SetupFilePath))); - if (RtlDoesFileExists_U(PhGetString(dbpath))) { if (!NT_SUCCESS(PhDeleteFileWin32(PhGetString(dbpath)))) @@ -395,13 +389,17 @@ NTSTATUS GeoIPUpdateThread( PPH_STRING fullPath; ULONG indexOfFileName; - if (fullPath = PH_AUTO(PhGetFullPath(dbpath->Buffer, &indexOfFileName))) + if (fullPath = PhGetFullPath(dbpath->Buffer, &indexOfFileName)) { if (indexOfFileName != -1) PhCreateDirectory(PhaSubstring(fullPath, 0, indexOfFileName)); + + PhDereferenceObject(fullPath); } } + mmdbGzPath = PhConvertUtf16ToUtf8(PhGetString(zipFilePath)); + if (gzfile = gzopen(mmdbGzPath->Buffer, "rb")) { HANDLE mmdbFileHandle; @@ -452,12 +450,20 @@ NTSTATUS GeoIPUpdateThread( } gzclose(gzfile); + gzfile = NULL; } } } CleanupExit: + if (gzfile) + gzclose(gzfile); + if (mmdbGzPath) + PhDereferenceObject(mmdbGzPath); + if (dbpath) + PhDereferenceObject(dbpath); + if (tempFileHandle) NtClose(tempFileHandle); @@ -469,10 +475,10 @@ NTSTATUS GeoIPUpdateThread( if (versionString) PhDereferenceObject(versionString); - if (context->SetupFilePath) + if (zipFilePath) { - PhDeleteCacheFile(context->SetupFilePath); - PhDereferenceObject(context->SetupFilePath); + PhDeleteCacheFile(zipFilePath); + PhDereferenceObject(zipFilePath); } if (context->DialogHandle) From 1f39694e5a79ea18e6c8f5a8ed56e9fd45042f17 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 13 Nov 2017 20:21:00 +1100 Subject: [PATCH 0574/2058] Add (experimental) EventQueue support, Improve process/service/network tab performance, Remove legacy process/service providor hacks --- ProcessHacker/hidnproc.c | 4 +- ProcessHacker/include/mainwnd.h | 18 ++-- ProcessHacker/include/mainwndp.h | 78 +++++------------ ProcessHacker/include/phuisup.h | 15 +--- ProcessHacker/include/procprv.h | 4 +- ProcessHacker/mainwnd.c | 121 ++------------------------ ProcessHacker/mwpgnet.c | 93 +++++++++++++------- ProcessHacker/mwpgproc.c | 70 +++++++++------ ProcessHacker/mwpgsrv.c | 142 +++++++++++-------------------- ProcessHacker/netprv.c | 2 +- ProcessHacker/procprv.c | 35 ++------ ProcessHacker/srvctl.c | 6 +- ProcessHacker/srvprv.c | 47 +++++----- 13 files changed, 236 insertions(+), 399 deletions(-) diff --git a/ProcessHacker/hidnproc.c b/ProcessHacker/hidnproc.c index f3b342c8c2fc..81745a5528fb 100644 --- a/ProcessHacker/hidnproc.c +++ b/ProcessHacker/hidnproc.c @@ -565,8 +565,8 @@ static PPH_PROCESS_ITEM PhpCreateProcessItemForHiddenProcess( processItem = PhCreateProcessItem(Entry->ProcessId); // Mark the process as terminated if necessary. - if (Entry->Type == TerminatedProcess) - processItem->State |= PH_PROCESS_ITEM_REMOVED; + //if (Entry->Type == TerminatedProcess) + // processItem->State |= PH_PROCESS_ITEM_REMOVED; // We need a process record. Just use the record of System Idle Process. if (idleProcessItem = PhReferenceProcessItem(SYSTEM_IDLE_PROCESS_ID)) diff --git a/ProcessHacker/include/mainwnd.h b/ProcessHacker/include/mainwnd.h index f1d96ac8c202..8c24ec999766 100644 --- a/ProcessHacker/include/mainwnd.h +++ b/ProcessHacker/include/mainwnd.h @@ -8,19 +8,19 @@ extern BOOLEAN PhMainWndExiting; #define WM_PH_ACTIVATE (WM_APP + 99) #define PH_ACTIVATE_REPLY 0x1119 -#define WM_PH_PROCESS_ADDED (WM_APP + 101) -#define WM_PH_PROCESS_MODIFIED (WM_APP + 102) -#define WM_PH_PROCESS_REMOVED (WM_APP + 103) +//#define WM_PH_PROCESS_ADDED_DEPRECATED (WM_APP + 101) +//#define WM_PH_PROCESS_MODIFIED_DEPRECATED (WM_APP + 102) +//#define WM_PH_PROCESS_REMOVED_DEPRECATED (WM_APP + 103) #define WM_PH_PROCESSES_UPDATED (WM_APP + 104) -#define WM_PH_SERVICE_ADDED (WM_APP + 105) -#define WM_PH_SERVICE_MODIFIED (WM_APP + 106) -#define WM_PH_SERVICE_REMOVED (WM_APP + 107) +//#define WM_PH_SERVICE_ADDED_DEPRECATED (WM_APP + 105) +//#define WM_PH_SERVICE_MODIFIED_DEPRECATED (WM_APP + 106) +//#define WM_PH_SERVICE_REMOVED_DEPRECATED (WM_APP + 107) #define WM_PH_SERVICES_UPDATED (WM_APP + 108) -#define WM_PH_NETWORK_ITEM_ADDED (WM_APP + 109) -#define WM_PH_NETWORK_ITEM_MODIFIED (WM_APP + 110) -#define WM_PH_NETWORK_ITEM_REMOVED (WM_APP + 111) +//#define WM_PH_NETWORK_ITEM_ADDED_DEPRECATED (WM_APP + 109) +//#define WM_PH_NETWORK_ITEM_MODIFIED_DEPRECATED (WM_APP + 110) +//#define WM_PH_NETWORK_ITEM_REMOVED_DEPRECATED (WM_APP + 111) #define WM_PH_NETWORK_ITEMS_UPDATED (WM_APP + 112) // begin_phapppub diff --git a/ProcessHacker/include/mainwndp.h b/ProcessHacker/include/mainwndp.h index 1f69c58882fb..13d25a772259 100644 --- a/ProcessHacker/include/mainwndp.h +++ b/ProcessHacker/include/mainwndp.h @@ -121,28 +121,6 @@ ULONG_PTR PhMwpOnUserMessage( _In_ ULONG_PTR LParam ); -// Callbacks - -VOID NTAPI PhMwpNetworkItemAddedHandler( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ); - -VOID NTAPI PhMwpNetworkItemModifiedHandler( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ); - -VOID NTAPI PhMwpNetworkItemRemovedHandler( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ); - -VOID NTAPI PhMwpNetworkItemsUpdatedHandler( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ); - // Settings VOID PhMwpLoadSettings( @@ -276,6 +254,7 @@ extern PPH_MAIN_TAB_PAGE PhMwpProcessesPage; extern HWND PhMwpProcessTreeNewHandle; extern HWND PhMwpSelectedProcessWindowHandle; extern BOOLEAN PhMwpSelectedProcessVirtualizationEnabled; +extern struct _PH_PROVIDER_EVENT_QUEUE PhMwpProcessEventQueue; BOOLEAN PhMwpProcessesPageCallback( _In_ struct _PH_MAIN_TAB_PAGE *Page, @@ -352,27 +331,15 @@ VOID NTAPI PhMwpProcessesUpdatedHandler( _In_opt_ PVOID Context ); -VOID PhMwpOnProcessAdded( - _In_ _Assume_refs_(1) PPH_PROCESS_ITEM ProcessItem, - _In_ ULONG RunId - ); - -VOID PhMwpOnProcessModified( - _In_ PPH_PROCESS_ITEM ProcessItem - ); - -VOID PhMwpOnProcessRemoved( - _In_ PPH_PROCESS_ITEM ProcessItem - ); - VOID PhMwpOnProcessesUpdated( - VOID + _In_ ULONG RunId ); // Services extern PPH_MAIN_TAB_PAGE PhMwpServicesPage; extern HWND PhMwpServiceTreeNewHandle; +extern struct _PH_PROVIDER_EVENT_QUEUE PhMwpServiceEventQueue; BOOLEAN PhMwpServicesPageCallback( _In_ struct _PH_MAIN_TAB_PAGE *Page, @@ -420,27 +387,15 @@ VOID NTAPI PhMwpServicesUpdatedHandler( _In_opt_ PVOID Context ); -VOID PhMwpOnServiceAdded( - _In_ _Assume_refs_(1) PPH_SERVICE_ITEM ServiceItem, - _In_ ULONG RunId - ); - -VOID PhMwpOnServiceModified( - _In_ struct _PH_SERVICE_MODIFIED_DATA *ServiceModifiedData - ); - -VOID PhMwpOnServiceRemoved( - _In_ PPH_SERVICE_ITEM ServiceItem - ); - VOID PhMwpOnServicesUpdated( - VOID + _In_ ULONG RunId ); // Network extern PPH_MAIN_TAB_PAGE PhMwpNetworkPage; extern HWND PhMwpNetworkTreeNewHandle; +extern struct _PH_PROVIDER_EVENT_QUEUE PhMwpNetworkEventQueue; BOOLEAN PhMwpNetworkPageCallback( _In_ struct _PH_MAIN_TAB_PAGE *Page, @@ -469,21 +424,28 @@ VOID PhMwpInitializeNetworkMenu( _In_ ULONG NumberOfNetworkItems ); -VOID PhMwpOnNetworkItemAdded( - _In_ ULONG RunId, - _In_ _Assume_refs_(1) PPH_NETWORK_ITEM NetworkItem +VOID PhMwpNetworkItemAddedHandler( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ); + +VOID PhMwpNetworkItemModifiedHandler( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context ); -VOID PhMwpOnNetworkItemModified( - _In_ PPH_NETWORK_ITEM NetworkItem +VOID PhMwpNetworkItemRemovedHandler( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context ); -VOID PhMwpOnNetworkItemRemoved( - _In_ PPH_NETWORK_ITEM NetworkItem +VOID PhMwpNetworkItemsUpdatedHandler( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context ); VOID PhMwpOnNetworkItemsUpdated( - VOID + _In_ ULONG RunId ); // Users diff --git a/ProcessHacker/include/phuisup.h b/ProcessHacker/include/phuisup.h index 23f439a4cff8..d1860f1f49fa 100644 --- a/ProcessHacker/include/phuisup.h +++ b/ProcessHacker/include/phuisup.h @@ -44,7 +44,6 @@ FORCEINLINE VOID PhChangeShStateTn( ULONG64 tickCount; \ BOOLEAN preferFullInvalidate; \ HANDLE stateListHandle; \ - BOOLEAN redrawDisabled = FALSE; \ BOOLEAN needsFullInvalidate = FALSE; \ \ if (!StateList || StateList->Count == 0) \ @@ -72,21 +71,13 @@ FORCEINLINE VOID PhChangeShStateTn( } \ else \ { \ - TreeNew_InvalidateNode(TreeNewHandleForUpdate, node); \ + if (TreeNewHandleForUpdate) \ + TreeNew_InvalidateNode((TreeNewHandleForUpdate), node); \ } \ } \ } \ else if (node->ShStateFieldName.State == RemovingItemState) \ { \ - if (TreeNewHandleForUpdate) \ - { \ - if (!redrawDisabled) \ - { \ - TreeNew_SetRedraw((TreeNewHandleForUpdate), FALSE); \ - redrawDisabled = TRUE; \ - } \ - } \ -\ RemoveFunction(node, __VA_ARGS__); \ needsFullInvalidate = TRUE; \ } \ @@ -96,8 +87,6 @@ FORCEINLINE VOID PhChangeShStateTn( \ if (TreeNewHandleForUpdate) \ { \ - if (redrawDisabled) \ - TreeNew_SetRedraw((TreeNewHandleForUpdate), TRUE); \ if (needsFullInvalidate) \ { \ InvalidateRect((TreeNewHandleForUpdate), NULL, FALSE); \ diff --git a/ProcessHacker/include/procprv.h b/ProcessHacker/include/procprv.h index 3e433d740952..7f82eabee7de 100644 --- a/ProcessHacker/include/procprv.h +++ b/ProcessHacker/include/procprv.h @@ -164,7 +164,7 @@ typedef struct _PH_PROCESS_ITEM ULONG IsImmersive : 1; ULONG IsWow64Valid : 1; ULONG IsPartiallySuspended : 1; - ULONG AddedEventSent : 1; + ULONG Unused : 1; ULONG IsProtectedProcess : 1; ULONG IsSecureProcess : 1; ULONG IsSubsystemProcess : 1; @@ -342,7 +342,7 @@ PhGetStatisticsTimeString( // end_phapppub VOID PhFlushProcessQueryData( - _In_ BOOLEAN SendModifiedEvent + VOID ); VOID PhProcessProviderUpdate( diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index 46186dfe4219..9b039b2c7dc8 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -385,11 +385,6 @@ VOID PhMwpApplyUpdateInterval( { PhSetIntervalProviderThread(&PhPrimaryProviderThread, Interval); PhSetIntervalProviderThread(&PhSecondaryProviderThread, Interval); - - if (Interval > PH_FLUSH_PROCESS_QUERY_DATA_INTERVAL_LONG_TERM) - SetTimer(PhMainWndHandle, TIMER_FLUSH_PROCESS_QUERY_DATA, PH_FLUSH_PROCESS_QUERY_DATA_INTERVAL_LONG_TERM, NULL); - else - KillTimer(PhMainWndHandle, TIMER_FLUSH_PROCESS_QUERY_DATA); // Might not exist } VOID PhMwpInitializeControls( @@ -1722,12 +1717,15 @@ VOID PhMwpOnTimer( KillTimer(PhMainWndHandle, TIMER_FLUSH_PROCESS_QUERY_DATA); break; - default: - NOTHING; + case 3: + { + KillTimer(PhMainWndHandle, TIMER_FLUSH_PROCESS_QUERY_DATA); + } break; } - PhFlushProcessQueryData(TRUE); + PhBoostProvider(&PhMwpProcessProviderRegistration, NULL); + PhBoostProvider(&PhMwpServiceProviderRegistration, NULL); } } @@ -2056,76 +2054,19 @@ ULONG_PTR PhMwpOnUserMessage( PhMwpActivateWindow(!!PhGetIntegerSetting(L"IconTogglesVisibility")); } break; - case WM_PH_PROCESS_ADDED: - { - ULONG runId = (ULONG)WParam; - PPH_PROCESS_ITEM processItem = (PPH_PROCESS_ITEM)LParam; - - PhMwpOnProcessAdded(processItem, runId); - } - break; - case WM_PH_PROCESS_MODIFIED: - { - PhMwpOnProcessModified((PPH_PROCESS_ITEM)LParam); - } - break; - case WM_PH_PROCESS_REMOVED: - { - PhMwpOnProcessRemoved((PPH_PROCESS_ITEM)LParam); - } - break; case WM_PH_PROCESSES_UPDATED: { - PhMwpOnProcessesUpdated(); - } - break; - case WM_PH_SERVICE_ADDED: - { - ULONG runId = (ULONG)WParam; - PPH_SERVICE_ITEM serviceItem = (PPH_SERVICE_ITEM)LParam; - - PhMwpOnServiceAdded(serviceItem, runId); - } - break; - case WM_PH_SERVICE_MODIFIED: - { - PPH_SERVICE_MODIFIED_DATA serviceModifiedData = (PPH_SERVICE_MODIFIED_DATA)LParam; - - PhMwpOnServiceModified(serviceModifiedData); - PhFree(serviceModifiedData); - } - break; - case WM_PH_SERVICE_REMOVED: - { - PhMwpOnServiceRemoved((PPH_SERVICE_ITEM)LParam); + PhMwpOnProcessesUpdated((ULONG)WParam); } break; case WM_PH_SERVICES_UPDATED: { - PhMwpOnServicesUpdated(); - } - break; - case WM_PH_NETWORK_ITEM_ADDED: - { - ULONG runId = (ULONG)WParam; - PPH_NETWORK_ITEM networkItem = (PPH_NETWORK_ITEM)LParam; - - PhMwpOnNetworkItemAdded(runId, networkItem); - } - break; - case WM_PH_NETWORK_ITEM_MODIFIED: - { - PhMwpOnNetworkItemModified((PPH_NETWORK_ITEM)LParam); - } - break; - case WM_PH_NETWORK_ITEM_REMOVED: - { - PhMwpOnNetworkItemRemoved((PPH_NETWORK_ITEM)LParam); + PhMwpOnServicesUpdated((ULONG)WParam); } break; case WM_PH_NETWORK_ITEMS_UPDATED: { - PhMwpOnNetworkItemsUpdated(); + PhMwpOnNetworkItemsUpdated((ULONG)WParam); } break; } @@ -2133,50 +2074,6 @@ ULONG_PTR PhMwpOnUserMessage( return 0; } -VOID NTAPI PhMwpNetworkItemAddedHandler( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - PPH_NETWORK_ITEM networkItem = (PPH_NETWORK_ITEM)Parameter; - - PhReferenceObject(networkItem); - PostMessage( - PhMainWndHandle, - WM_PH_NETWORK_ITEM_ADDED, - PhGetRunIdProvider(&PhMwpNetworkProviderRegistration), - (LPARAM)networkItem - ); -} - -VOID NTAPI PhMwpNetworkItemModifiedHandler( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - PPH_NETWORK_ITEM networkItem = (PPH_NETWORK_ITEM)Parameter; - - PostMessage(PhMainWndHandle, WM_PH_NETWORK_ITEM_MODIFIED, 0, (LPARAM)networkItem); -} - -VOID NTAPI PhMwpNetworkItemRemovedHandler( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - PPH_NETWORK_ITEM networkItem = (PPH_NETWORK_ITEM)Parameter; - - PostMessage(PhMainWndHandle, WM_PH_NETWORK_ITEM_REMOVED, 0, (LPARAM)networkItem); -} - -VOID NTAPI PhMwpNetworkItemsUpdatedHandler( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - PostMessage(PhMainWndHandle, WM_PH_NETWORK_ITEMS_UPDATED, 0, 0); -} - VOID PhMwpLoadSettings( VOID ) diff --git a/ProcessHacker/mwpgnet.c b/ProcessHacker/mwpgnet.c index 68832d0a5438..e87dd26a01c9 100644 --- a/ProcessHacker/mwpgnet.c +++ b/ProcessHacker/mwpgnet.c @@ -3,6 +3,7 @@ * Main window: Network tab * * Copyright (C) 2009-2016 wj32 + * Copyright (C) 2017 dmex * * This file is part of Process Hacker. * @@ -38,6 +39,7 @@ PPH_MAIN_TAB_PAGE PhMwpNetworkPage; HWND PhMwpNetworkTreeNewHandle; +PH_PROVIDER_EVENT_QUEUE PhMwpNetworkEventQueue; static PH_CALLBACK_REGISTRATION NetworkItemAddedRegistration; static PH_CALLBACK_REGISTRATION NetworkItemModifiedRegistration; @@ -46,7 +48,6 @@ static PH_CALLBACK_REGISTRATION NetworkItemsUpdatedRegistration; static BOOLEAN NetworkFirstTime = TRUE; static BOOLEAN NetworkTreeListLoaded = FALSE; -static BOOLEAN NetworkNeedsRedraw = FALSE; BOOLEAN PhMwpNetworkPageCallback( _In_ struct _PH_MAIN_TAB_PAGE *Page, @@ -61,6 +62,8 @@ BOOLEAN PhMwpNetworkPageCallback( { PhMwpNetworkPage = Page; + PhInitializeProviderEventQueue(&PhMwpNetworkEventQueue, 100); + PhRegisterCallback( &PhNetworkItemAddedEvent, PhMwpNetworkItemAddedHandler, @@ -309,52 +312,84 @@ VOID PhShowNetworkContextMenu( PhFree(networkItems); } -VOID PhMwpOnNetworkItemAdded( - _In_ ULONG RunId, - _In_ _Assume_refs_(1) PPH_NETWORK_ITEM NetworkItem +VOID NTAPI PhMwpNetworkItemAddedHandler( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context ) { - PPH_NETWORK_NODE networkNode; - - if (!NetworkNeedsRedraw) - { - TreeNew_SetRedraw(PhMwpNetworkTreeNewHandle, FALSE); - NetworkNeedsRedraw = TRUE; - } + PPH_NETWORK_ITEM networkItem = (PPH_NETWORK_ITEM)Parameter; - networkNode = PhAddNetworkNode(NetworkItem, RunId); - PhDereferenceObject(NetworkItem); + PhReferenceObject(networkItem); + PhPushProviderEventQueue(&PhMwpNetworkEventQueue, ProviderAddedEvent, Parameter, PhGetRunIdProvider(&PhMwpNetworkProviderRegistration)); } -VOID PhMwpOnNetworkItemModified( - _In_ PPH_NETWORK_ITEM NetworkItem +VOID NTAPI PhMwpNetworkItemModifiedHandler( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context ) { - PhUpdateNetworkNode(PhFindNetworkNode(NetworkItem)); + PPH_NETWORK_ITEM networkItem = (PPH_NETWORK_ITEM)Parameter; + + PhPushProviderEventQueue(&PhMwpNetworkEventQueue, ProviderModifiedEvent, Parameter, PhGetRunIdProvider(&PhMwpNetworkProviderRegistration)); } -VOID PhMwpOnNetworkItemRemoved( - _In_ PPH_NETWORK_ITEM NetworkItem +VOID NTAPI PhMwpNetworkItemRemovedHandler( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context ) { - if (!NetworkNeedsRedraw) - { - TreeNew_SetRedraw(PhMwpNetworkTreeNewHandle, FALSE); - NetworkNeedsRedraw = TRUE; - } + PPH_NETWORK_ITEM networkItem = (PPH_NETWORK_ITEM)Parameter; - PhRemoveNetworkNode(PhFindNetworkNode(NetworkItem)); + PhPushProviderEventQueue(&PhMwpNetworkEventQueue, ProviderRemovedEvent, Parameter, PhGetRunIdProvider(&PhMwpNetworkProviderRegistration)); +} + +VOID NTAPI PhMwpNetworkItemsUpdatedHandler( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + PostMessage(PhMainWndHandle, WM_PH_NETWORK_ITEMS_UPDATED, PhGetRunIdProvider(&PhMwpNetworkProviderRegistration), 0); } VOID PhMwpOnNetworkItemsUpdated( - VOID + _In_ ULONG RunId ) { - PhTickNetworkNodes(); + PPH_PROVIDER_EVENT events; + ULONG count; + ULONG i; + + events = PhFlushProviderEventQueue(&PhMwpNetworkEventQueue, RunId, &count); - if (NetworkNeedsRedraw) + if (events) { - TreeNew_SetRedraw(PhMwpNetworkTreeNewHandle, TRUE); - NetworkNeedsRedraw = FALSE; + TreeNew_SetRedraw(PhMwpNetworkTreeNewHandle, FALSE); + + for (i = 0; i < count; i++) + { + PH_PROVIDER_EVENT_TYPE type = PH_PROVIDER_EVENT_TYPE(events[i]); + PPH_NETWORK_ITEM networkItem = PH_PROVIDER_EVENT_OBJECT(events[i]); + + switch (type) + { + case ProviderAddedEvent: + PhAddNetworkNode(networkItem, events[i].RunId); + PhDereferenceObject(networkItem); + break; + case ProviderModifiedEvent: + PhUpdateNetworkNode(PhFindNetworkNode(networkItem)); + break; + case ProviderRemovedEvent: + PhRemoveNetworkNode(PhFindNetworkNode(networkItem)); + break; + } + } + + PhFree(events); } + + PhTickNetworkNodes(); + + if (count != 0) + TreeNew_SetRedraw(PhMwpNetworkTreeNewHandle, TRUE); } diff --git a/ProcessHacker/mwpgproc.c b/ProcessHacker/mwpgproc.c index 142240387119..2d12dada4116 100644 --- a/ProcessHacker/mwpgproc.c +++ b/ProcessHacker/mwpgproc.c @@ -3,6 +3,7 @@ * Main window: Processes tab * * Copyright (C) 2009-2016 wj32 + * Copyright (C) 2017 dmex * * This file is part of Process Hacker. * @@ -43,6 +44,7 @@ PPH_MAIN_TAB_PAGE PhMwpProcessesPage; HWND PhMwpProcessTreeNewHandle; HWND PhMwpSelectedProcessWindowHandle; BOOLEAN PhMwpSelectedProcessVirtualizationEnabled; +PH_PROVIDER_EVENT_QUEUE PhMwpProcessEventQueue; static PH_CALLBACK_REGISTRATION ProcessAddedRegistration; static PH_CALLBACK_REGISTRATION ProcessModifiedRegistration; @@ -50,9 +52,7 @@ static PH_CALLBACK_REGISTRATION ProcessRemovedRegistration; static PH_CALLBACK_REGISTRATION ProcessesUpdatedRegistration; static ULONG NeedsSelectPid = 0; -static BOOLEAN ProcessesNeedsRedraw = FALSE; static PPH_PROCESS_NODE ProcessToScrollTo = NULL; - static PPH_TN_FILTER_ENTRY CurrentUserFilterEntry = NULL; static PPH_TN_FILTER_ENTRY SignedFilterEntry = NULL; @@ -69,6 +69,8 @@ BOOLEAN PhMwpProcessesPageCallback( { PhMwpProcessesPage = Page; + PhInitializeProviderEventQueue(&PhMwpProcessEventQueue, 100); + PhRegisterCallback( &PhProcessAddedEvent, PhMwpProcessAddedHandler, @@ -709,12 +711,7 @@ VOID NTAPI PhMwpProcessAddedHandler( // Reference the process item so it doesn't get deleted before // we handle the event in the main thread. PhReferenceObject(processItem); - PostMessage( - PhMainWndHandle, - WM_PH_PROCESS_ADDED, - (WPARAM)PhGetRunIdProvider(&PhMwpProcessProviderRegistration), - (LPARAM)processItem - ); + PhPushProviderEventQueue(&PhMwpProcessEventQueue, ProviderAddedEvent, Parameter, PhGetRunIdProvider(&PhMwpProcessProviderRegistration)); } VOID NTAPI PhMwpProcessModifiedHandler( @@ -724,7 +721,7 @@ VOID NTAPI PhMwpProcessModifiedHandler( { PPH_PROCESS_ITEM processItem = (PPH_PROCESS_ITEM)Parameter; - PostMessage(PhMainWndHandle, WM_PH_PROCESS_MODIFIED, 0, (LPARAM)processItem); + PhPushProviderEventQueue(&PhMwpProcessEventQueue, ProviderModifiedEvent, Parameter, PhGetRunIdProvider(&PhMwpProcessProviderRegistration)); } VOID NTAPI PhMwpProcessRemovedHandler( @@ -736,7 +733,7 @@ VOID NTAPI PhMwpProcessRemovedHandler( // We already have a reference to the process item, so we don't need to // reference it here. - PostMessage(PhMainWndHandle, WM_PH_PROCESS_REMOVED, 0, (LPARAM)processItem); + PhPushProviderEventQueue(&PhMwpProcessEventQueue, ProviderRemovedEvent, Parameter, PhGetRunIdProvider(&PhMwpProcessProviderRegistration)); } VOID NTAPI PhMwpProcessesUpdatedHandler( @@ -744,7 +741,7 @@ VOID NTAPI PhMwpProcessesUpdatedHandler( _In_opt_ PVOID Context ) { - PostMessage(PhMainWndHandle, WM_PH_PROCESSES_UPDATED, 0, 0); + PostMessage(PhMainWndHandle, WM_PH_PROCESSES_UPDATED, PhGetRunIdProvider(&PhMwpProcessProviderRegistration), 0); } VOID PhMwpOnProcessAdded( @@ -754,12 +751,6 @@ VOID PhMwpOnProcessAdded( { PPH_PROCESS_NODE processNode; - if (!ProcessesNeedsRedraw) - { - TreeNew_SetRedraw(PhMwpProcessTreeNewHandle, FALSE); - ProcessesNeedsRedraw = TRUE; - } - processNode = PhAddProcessNode(ProcessItem, RunId); if (RunId != 1) @@ -840,12 +831,6 @@ VOID PhMwpOnProcessRemoved( { PPH_PROCESS_NODE processNode; - if (!ProcessesNeedsRedraw) - { - TreeNew_SetRedraw(PhMwpProcessTreeNewHandle, FALSE); - ProcessesNeedsRedraw = TRUE; - } - PhLogProcessEntry(PH_LOG_ENTRY_PROCESS_DELETE, ProcessItem->ProcessId, ProcessItem->QueryHandle, ProcessItem->ProcessName, NULL, NULL); if (PhMwpNotifyIconNotifyMask & PH_NOTIFY_PROCESS_DELETE) @@ -872,9 +857,41 @@ VOID PhMwpOnProcessRemoved( } VOID PhMwpOnProcessesUpdated( - VOID + _In_ ULONG RunId ) { + PPH_PROVIDER_EVENT events; + ULONG count; + ULONG i; + + events = PhFlushProviderEventQueue(&PhMwpProcessEventQueue, RunId, &count); + + if (events) + { + TreeNew_SetRedraw(PhMwpProcessTreeNewHandle, FALSE); + + for (i = 0; i < count; i++) + { + PH_PROVIDER_EVENT_TYPE type = PH_PROVIDER_EVENT_TYPE(events[i]); + PPH_PROCESS_ITEM processItem = PH_PROVIDER_EVENT_OBJECT(events[i]); + + switch (type) + { + case ProviderAddedEvent: + PhMwpOnProcessAdded(processItem, events[i].RunId); + break; + case ProviderModifiedEvent: + PhMwpOnProcessModified(processItem); + break; + case ProviderRemovedEvent: + PhMwpOnProcessRemoved(processItem); + break; + } + } + + PhFree(events); + } + // The modified notification is only sent for special cases. // We have to invalidate the text on each update. PhTickProcessNodes(); @@ -884,11 +901,8 @@ VOID PhMwpOnProcessesUpdated( PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackProcessesUpdated), NULL); } - if (ProcessesNeedsRedraw) - { + if (count != 0) TreeNew_SetRedraw(PhMwpProcessTreeNewHandle, TRUE); - ProcessesNeedsRedraw = FALSE; - } if (NeedsSelectPid != 0) { diff --git a/ProcessHacker/mwpgsrv.c b/ProcessHacker/mwpgsrv.c index 8862e02ded39..c5ac2d0119f9 100644 --- a/ProcessHacker/mwpgsrv.c +++ b/ProcessHacker/mwpgsrv.c @@ -3,6 +3,7 @@ * Main window: Services tab * * Copyright (C) 2009-2016 wj32 + * Copyright (C) 2017 dmex * * This file is part of Process Hacker. * @@ -37,16 +38,14 @@ PPH_MAIN_TAB_PAGE PhMwpServicesPage; HWND PhMwpServiceTreeNewHandle; +PH_PROVIDER_EVENT_QUEUE PhMwpServiceEventQueue; static PH_CALLBACK_REGISTRATION ServiceAddedRegistration; static PH_CALLBACK_REGISTRATION ServiceModifiedRegistration; static PH_CALLBACK_REGISTRATION ServiceRemovedRegistration; static PH_CALLBACK_REGISTRATION ServicesUpdatedRegistration; -static PPH_POINTER_LIST ServicesPendingList; static BOOLEAN ServiceTreeListLoaded = FALSE; -static BOOLEAN ServicesNeedsRedraw = FALSE; - static PPH_TN_FILTER_ENTRY DriverFilterEntry = NULL; BOOLEAN PhMwpServicesPageCallback( @@ -62,6 +61,8 @@ BOOLEAN PhMwpServicesPageCallback( { PhMwpServicesPage = Page; + PhInitializeProviderEventQueue(&PhMwpServiceEventQueue, 100); + PhRegisterCallback( &PhServiceAddedEvent, PhMwpServiceAddedHandler, @@ -163,22 +164,6 @@ VOID PhMwpNeedServiceTreeList( if (PhGetIntegerSetting(L"HideDriverServices")) DriverFilterEntry = PhAddTreeNewFilter(PhGetFilterSupportServiceTreeList(), PhMwpDriverServiceTreeFilter, NULL); - - if (ServicesPendingList) - { - PPH_SERVICE_ITEM serviceItem; - ULONG enumerationKey = 0; - - while (PhEnumPointerList(ServicesPendingList, &enumerationKey, (PVOID *)&serviceItem)) - { - PhMwpOnServiceAdded(serviceItem, 1); - } - - // Force a re-draw. - PhMwpOnServicesUpdated(); - - PhClearReference(&ServicesPendingList); - } } } @@ -358,12 +343,7 @@ VOID NTAPI PhMwpServiceAddedHandler( PPH_SERVICE_ITEM serviceItem = (PPH_SERVICE_ITEM)Parameter; PhReferenceObject(serviceItem); - PostMessage( - PhMainWndHandle, - WM_PH_SERVICE_ADDED, - PhGetRunIdProvider(&PhMwpServiceProviderRegistration), - (LPARAM)serviceItem - ); + PhPushProviderEventQueue(&PhMwpServiceEventQueue, ProviderAddedEvent, Parameter, PhGetRunIdProvider(&PhMwpServiceProviderRegistration)); } VOID NTAPI PhMwpServiceModifiedHandler( @@ -376,7 +356,7 @@ VOID NTAPI PhMwpServiceModifiedHandler( copy = PhAllocateCopy(serviceModifiedData, sizeof(PH_SERVICE_MODIFIED_DATA)); - PostMessage(PhMainWndHandle, WM_PH_SERVICE_MODIFIED, 0, (LPARAM)copy); + PhPushProviderEventQueue(&PhMwpServiceEventQueue, ProviderModifiedEvent, copy, PhGetRunIdProvider(&PhMwpServiceProviderRegistration)); } VOID NTAPI PhMwpServiceRemovedHandler( @@ -386,7 +366,7 @@ VOID NTAPI PhMwpServiceRemovedHandler( { PPH_SERVICE_ITEM serviceItem = (PPH_SERVICE_ITEM)Parameter; - PostMessage(PhMainWndHandle, WM_PH_SERVICE_REMOVED, 0, (LPARAM)serviceItem); + PhPushProviderEventQueue(&PhMwpServiceEventQueue, ProviderRemovedEvent, Parameter, PhGetRunIdProvider(&PhMwpServiceProviderRegistration)); } VOID NTAPI PhMwpServicesUpdatedHandler( @@ -394,7 +374,7 @@ VOID NTAPI PhMwpServicesUpdatedHandler( _In_opt_ PVOID Context ) { - PostMessage(PhMainWndHandle, WM_PH_SERVICES_UPDATED, 0, 0); + PostMessage(PhMainWndHandle, WM_PH_SERVICES_UPDATED, PhGetRunIdProvider(&PhMwpServiceProviderRegistration), 0); } VOID PhMwpOnServiceAdded( @@ -404,24 +384,8 @@ VOID PhMwpOnServiceAdded( { PPH_SERVICE_NODE serviceNode; - if (ServiceTreeListLoaded) - { - if (!ServicesNeedsRedraw) - { - TreeNew_SetRedraw(PhMwpServiceTreeNewHandle, FALSE); - ServicesNeedsRedraw = TRUE; - } - - serviceNode = PhAddServiceNode(ServiceItem, RunId); - // ServiceItem dereferenced below - } - else - { - if (!ServicesPendingList) - ServicesPendingList = PhCreatePointerList(100); - - PhAddItemPointerList(ServicesPendingList, ServiceItem); - } + serviceNode = PhAddServiceNode(ServiceItem, RunId); + // ServiceItem dereferenced below if (RunId != 1) { @@ -444,30 +408,20 @@ VOID PhMwpOnServiceAdded( } } - if (ServiceTreeListLoaded) - PhDereferenceObject(ServiceItem); + PhDereferenceObject(ServiceItem); } VOID PhMwpOnServiceModified( - _In_ struct _PH_SERVICE_MODIFIED_DATA *ServiceModifiedData + _In_ PPH_SERVICE_MODIFIED_DATA ServiceModifiedData ) { PH_SERVICE_CHANGE serviceChange; UCHAR logEntryType; - if (ServiceTreeListLoaded) - { - //if (!ServicesNeedsRedraw) - //{ - // TreeNew_SetRedraw(PhMwpServiceTreeNewHandle, FALSE); - // ServicesNeedsRedraw = TRUE; - //} - - PhUpdateServiceNode(PhFindServiceNode(ServiceModifiedData->Service)); + PhUpdateServiceNode(PhFindServiceNode(ServiceModifiedData->Service)); - if (DriverFilterEntry) - PhApplyTreeNewFilters(PhGetFilterSupportServiceTreeList()); - } + if (DriverFilterEntry) + PhApplyTreeNewFilters(PhGetFilterSupportServiceTreeList()); serviceChange = PhGetServiceChange(ServiceModifiedData); @@ -536,15 +490,6 @@ VOID PhMwpOnServiceRemoved( _In_ PPH_SERVICE_ITEM ServiceItem ) { - if (ServiceTreeListLoaded) - { - if (!ServicesNeedsRedraw) - { - TreeNew_SetRedraw(PhMwpServiceTreeNewHandle, FALSE); - ServicesNeedsRedraw = TRUE; - } - } - PhLogServiceEntry(PH_LOG_ENTRY_SERVICE_DELETE, ServiceItem->Name, ServiceItem->DisplayName); if (PhMwpNotifyIconNotifyMask & PH_NOTIFY_SERVICE_CREATE) @@ -563,38 +508,47 @@ VOID PhMwpOnServiceRemoved( } } - if (ServiceTreeListLoaded) - { - PhRemoveServiceNode(PhFindServiceNode(ServiceItem)); - } - else - { - if (ServicesPendingList) - { - HANDLE pointerHandle; - - // Remove the service from the pending list so we don't try to add it later. - - if (pointerHandle = PhFindItemPointerList(ServicesPendingList, ServiceItem)) - PhRemoveItemPointerList(ServicesPendingList, pointerHandle); - - PhDereferenceObject(ServiceItem); - } - } + PhRemoveServiceNode(PhFindServiceNode(ServiceItem)); } VOID PhMwpOnServicesUpdated( - VOID + _In_ ULONG RunId ) { - if (ServiceTreeListLoaded) + PPH_PROVIDER_EVENT events; + ULONG count; + ULONG i; + + events = PhFlushProviderEventQueue(&PhMwpServiceEventQueue, RunId, &count); + + if (events) { - PhTickServiceNodes(); + TreeNew_SetRedraw(PhMwpServiceTreeNewHandle, FALSE); - if (ServicesNeedsRedraw) + for (i = 0; i < count; i++) { - TreeNew_SetRedraw(PhMwpServiceTreeNewHandle, TRUE); - ServicesNeedsRedraw = FALSE; + PH_PROVIDER_EVENT_TYPE type = PH_PROVIDER_EVENT_TYPE(events[i]); + PPH_SERVICE_ITEM serviceItem = PH_PROVIDER_EVENT_OBJECT(events[i]); + + switch (type) + { + case ProviderAddedEvent: + PhMwpOnServiceAdded(serviceItem, events[i].RunId); + break; + case ProviderModifiedEvent: + PhMwpOnServiceModified((PPH_SERVICE_MODIFIED_DATA)serviceItem); + break; + case ProviderRemovedEvent: + PhMwpOnServiceRemoved(serviceItem); + break; + } } + + PhFree(events); } + + PhTickServiceNodes(); + + if (count != 0) + TreeNew_SetRedraw(PhMwpServiceTreeNewHandle, TRUE); } diff --git a/ProcessHacker/netprv.c b/ProcessHacker/netprv.c index 8930c1ec20fb..a096ec281b85 100644 --- a/ProcessHacker/netprv.c +++ b/ProcessHacker/netprv.c @@ -463,7 +463,7 @@ VOID PhFlushNetworkQueryData( PSLIST_ENTRY entry; PPH_NETWORK_ITEM_QUERY_DATA data; - if (RtlQueryDepthSList(&PhNetworkItemQueryListHead) == 0) + if (!RtlFirstEntrySList(&PhNetworkItemQueryListHead)) return; entry = RtlInterlockedFlushSList(&PhNetworkItemQueryListHead); diff --git a/ProcessHacker/procprv.c b/ProcessHacker/procprv.c index dc516afedcd9..cf5b07e43b64 100644 --- a/ProcessHacker/procprv.c +++ b/ProcessHacker/procprv.c @@ -3,6 +3,7 @@ * process provider * * Copyright (C) 2009-2016 wj32 + * Copyright (C) 2017 dmex * * This file is part of Process Hacker. * @@ -1801,14 +1802,13 @@ PPH_STRING PhGetStatisticsTimeString( } VOID PhFlushProcessQueryData( - _In_ BOOLEAN SendModifiedEvent + VOID ) { PSLIST_ENTRY entry; PPH_PROCESS_QUERY_DATA data; - BOOLEAN processed; - if (RtlQueryDepthSList(&PhProcessQueryDataListHead) == 0) + if (!RtlFirstEntrySList(&PhProcessQueryDataListHead)) return; entry = RtlInterlockedFlushSList(&PhProcessQueryDataListHead); @@ -1817,39 +1817,18 @@ VOID PhFlushProcessQueryData( { data = CONTAINING_RECORD(entry, PH_PROCESS_QUERY_DATA, ListEntry); entry = entry->Next; - processed = FALSE; if (data->Stage == 1) { PhpFillProcessItemStage1((PPH_PROCESS_QUERY_S1_DATA)data); PhSetEvent(&data->ProcessItem->Stage1Event); - processed = TRUE; } else if (data->Stage == 2) { PhpFillProcessItemStage2((PPH_PROCESS_QUERY_S2_DATA)data); - processed = TRUE; } - if (processed) - { - // Invoke the modified event only if the main provider has sent the added event already. - if (SendModifiedEvent && data->ProcessItem->AddedEventSent) - { - // Since this may be executing on a thread other than the main provider thread, we - // need to check whether the process has been removed already. If we don't do this - // then users may get a modified event after a removed event for the same process, - // which will lead to very bad things happening. - PhAcquireQueuedLockExclusive(&data->ProcessItem->RemoveLock); - if (!(data->ProcessItem->State & PH_PROCESS_ITEM_REMOVED)) - PhInvokeCallback(&PhProcessModifiedEvent, data->ProcessItem); - PhReleaseQueuedLockExclusive(&data->ProcessItem->RemoveLock); - } - else - { - data->ProcessItem->JustProcessed = TRUE; - } - } + data->ProcessItem->JustProcessed = TRUE; PhDereferenceObject(data->ProcessItem); PhFree(data); @@ -2106,10 +2085,7 @@ VOID PhProcessProviderUpdate( processItem->Record->ExitTime = exitTime; // Raise the process removed event. - // See PhFlushProcessQueryData for why we need to lock here. - PhAcquireQueuedLockExclusive(&processItem->RemoveLock); PhInvokeCallback(&PhProcessRemovedEvent, processItem); - PhReleaseQueuedLockExclusive(&processItem->RemoveLock); if (!processesToRemove) processesToRemove = PhCreateList(2); @@ -2135,7 +2111,7 @@ VOID PhProcessProviderUpdate( } // Go through the queued process query data. - PhFlushProcessQueryData(FALSE); + PhFlushProcessQueryData(); if (sysTotalTime == 0) sysTotalTime = -1; // max. value @@ -2231,7 +2207,6 @@ VOID PhProcessProviderUpdate( // Raise the process added event. PhInvokeCallback(&PhProcessAddedEvent, processItem); - processItem->AddedEventSent = TRUE; // (Ref: for the process item being in the hashtable.) // Instead of referencing then dereferencing we simply don't do anything. diff --git a/ProcessHacker/srvctl.c b/ProcessHacker/srvctl.c index 8b122289a3ff..4992df84a96e 100644 --- a/ProcessHacker/srvctl.c +++ b/ProcessHacker/srvctl.c @@ -41,6 +41,8 @@ typedef struct _PH_SERVICES_CONTEXT HWND WindowHandle; } PH_SERVICES_CONTEXT, *PPH_SERVICES_CONTEXT; +#define WM_PH_SERVICE_PAGE_MODIFIED (WM_APP + 106) + VOID NTAPI ServiceModifiedHandler( _In_opt_ PVOID Parameter, _In_opt_ PVOID Context @@ -108,7 +110,7 @@ static VOID NTAPI ServiceModifiedHandler( copy = PhAllocateCopy(serviceModifiedData, sizeof(PH_SERVICE_MODIFIED_DATA)); - PostMessage(servicesContext->WindowHandle, WM_PH_SERVICE_MODIFIED, 0, (LPARAM)copy); + PostMessage(servicesContext->WindowHandle, WM_PH_SERVICE_PAGE_MODIFIED, 0, (LPARAM)copy); } VOID PhpFixProcessServicesControls( @@ -398,7 +400,7 @@ INT_PTR CALLBACK PhpServicesPageProc( PhLayoutManagerLayout(&servicesContext->LayoutManager); } break; - case WM_PH_SERVICE_MODIFIED: + case WM_PH_SERVICE_PAGE_MODIFIED: { PPH_SERVICE_MODIFIED_DATA serviceModifiedData = (PPH_SERVICE_MODIFIED_DATA)lParam; PPH_SERVICE_ITEM serviceItem = NULL; diff --git a/ProcessHacker/srvprv.c b/ProcessHacker/srvprv.c index 1b8ea63d5b2e..137c1f58a4a8 100644 --- a/ProcessHacker/srvprv.c +++ b/ProcessHacker/srvprv.c @@ -521,6 +521,33 @@ VOID PhpQueueServiceQuery( PhQueueItemWorkQueueEx(PhGetGlobalWorkQueue(), PhpServiceQueryWorker, data, NULL, &environment); } +VOID PhFlushServiceQueryData( + VOID + ) +{ + PSLIST_ENTRY entry; + PPH_SERVICE_QUERY_DATA data; + + if (!RtlFirstEntrySList(&PhpServiceQueryListHead)) + return; + + entry = RtlInterlockedFlushSList(&PhpServiceQueryListHead); + + while (entry) + { + data = CONTAINING_RECORD(entry, PH_SERVICE_QUERY_DATA, ListEntry); + entry = entry->Next; + + data->ServiceItem->VerifyResult = data->VerifyResult; + data->ServiceItem->VerifySignerName = data->VerifySignerName; + + data->ServiceItem->NeedsVerifyUpdate = TRUE; + + PhDereferenceObject(data->ServiceItem); + PhFree(data); + } +} + VOID PhServiceProviderUpdate( _In_ PVOID Object ) @@ -604,25 +631,7 @@ VOID PhServiceProviderUpdate( } // Go through the queued services query data. - { - PSLIST_ENTRY entry; - PPH_SERVICE_QUERY_DATA data; - - entry = RtlInterlockedFlushSList(&PhpServiceQueryListHead); - - while (entry) - { - data = CONTAINING_RECORD(entry, PH_SERVICE_QUERY_DATA, ListEntry); - entry = entry->Next; - - data->ServiceItem->VerifyResult = data->VerifyResult; - data->ServiceItem->VerifySignerName = data->VerifySignerName; - data->ServiceItem->NeedsVerifyUpdate = TRUE; - - PhDereferenceObject(data->ServiceItem); - PhFree(data); - } - } + PhFlushServiceQueryData(); // Look for dead services. { From 9f6d17ddd3d43011c195821d9ea3c5df537d6056 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 14 Nov 2017 05:14:11 +1100 Subject: [PATCH 0575/2058] Fix crash --- phlib/native.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/phlib/native.c b/phlib/native.c index f3796615e83e..aa40f5acbe95 100644 --- a/phlib/native.c +++ b/phlib/native.c @@ -4163,6 +4163,7 @@ NTSTATUS PhEnumHandlesEx2( ULONG returnLength = 0; buffer = PhAllocate(bufferSize); + memset(buffer, 0, bufferSize); while ((status = NtQueryInformationProcess( ProcessHandle, @@ -4180,6 +4181,7 @@ NTSTATUS PhEnumHandlesEx2( return STATUS_INSUFFICIENT_RESOURCES; buffer = PhAllocate(bufferSize); + memset(buffer, 0, bufferSize); } if (NT_SUCCESS(status)) From 889f317c35b0e1fb28a967b7be0517ff8964bc2a Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 14 Nov 2017 06:56:12 +1100 Subject: [PATCH 0576/2058] Fix incorrect extension layout --- phnt/include/ntexapi.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/phnt/include/ntexapi.h b/phnt/include/ntexapi.h index f7bea46bf049..033d7963f31a 100644 --- a/phnt/include/ntexapi.h +++ b/phnt/include/ntexapi.h @@ -2681,7 +2681,7 @@ typedef struct _PROCESS_DISK_COUNTERS } PROCESS_DISK_COUNTERS, *PPROCESS_DISK_COUNTERS; // private -typedef struct _ENERGY_STATE_DURATION +typedef union _ENERGY_STATE_DURATION { union { @@ -2715,8 +2715,8 @@ typedef struct _PROCESS_ENERGY_VALUES ULONG CompositionDirtyGenerated; ULONG CompositionDirtyPropagated; ULONG Reserved1; - ULONGLONG AttributedCycles[2][4]; - ULONGLONG WorkOnBehalfCycles[2][4]; + ULONGLONG AttributedCycles[4][2]; + ULONGLONG WorkOnBehalfCycles[4][2]; } PROCESS_ENERGY_VALUES, *PPROCESS_ENERGY_VALUES; typedef struct _TIMELINE_BITMAP From f5cef286069664cf1a26aeb5b398e53532b64e7e Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 14 Nov 2017 19:29:39 +1100 Subject: [PATCH 0577/2058] Update PhEnumHandlesEx2 --- phlib/native.c | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/phlib/native.c b/phlib/native.c index aa40f5acbe95..a1dbfb769808 100644 --- a/phlib/native.c +++ b/phlib/native.c @@ -4159,39 +4159,43 @@ NTSTATUS PhEnumHandlesEx2( { NTSTATUS status; PVOID buffer; - ULONG bufferSize = 0x8000; + ULONG bufferSize; ULONG returnLength = 0; + ULONG attempts = 0; + bufferSize = 0x8000; buffer = PhAllocate(bufferSize); memset(buffer, 0, bufferSize); - while ((status = NtQueryInformationProcess( + status = NtQueryInformationProcess( ProcessHandle, ProcessHandleInformation, buffer, bufferSize, &returnLength - )) == STATUS_INFO_LENGTH_MISMATCH) + ); + + while (status == STATUS_INFO_LENGTH_MISMATCH && attempts < 8) { PhFree(buffer); - bufferSize *= 2; - - // Fail if we're resizing the buffer to something very large. - if (bufferSize > PH_LARGE_BUFFER_SIZE) - return STATUS_INSUFFICIENT_RESOURCES; - + bufferSize = returnLength; buffer = PhAllocate(bufferSize); memset(buffer, 0, bufferSize); + + status = NtQueryInformationProcess( + ProcessHandle, + ProcessHandleInformation, + buffer, + bufferSize, + &returnLength + ); + attempts++; } if (NT_SUCCESS(status)) - { *Handles = buffer; - } else - { PhFree(buffer); - } return status; } From 03e2c805eb8e241c6a8cb68d06c136cd0b6e056f Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 16 Nov 2017 08:00:12 +1100 Subject: [PATCH 0578/2058] Add macro --- phlib/include/phnative.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/phlib/include/phnative.h b/phlib/include/phnative.h index a3773c94dfeb..1ab3c6574068 100644 --- a/phlib/include/phnative.h +++ b/phlib/include/phnative.h @@ -638,6 +638,12 @@ PhGetKernelFileName( NULL \ ) +#define PH_PROCESS_EXTENSION(Process) \ + ((PSYSTEM_PROCESS_INFORMATION_EXTENSION)PTR_ADD_OFFSET((Process), \ + FIELD_OFFSET(SYSTEM_PROCESS_INFORMATION, Threads) + \ + sizeof(SYSTEM_THREAD_INFORMATION) * \ + ((PSYSTEM_PROCESS_INFORMATION)(Process))->NumberOfThreads)) + PHLIBAPI NTSTATUS NTAPI From 8b448663671e59eba240f37e0ea6ebb620fbbb7d Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 16 Nov 2017 08:13:29 +1100 Subject: [PATCH 0579/2058] Remove deprecated symsrv flags --- phlib/symprv.c | 9 ++++++++- tools/peview/pdb.c | 7 ++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/phlib/symprv.c b/phlib/symprv.c index 3be8511f4924..ac3a4da3045e 100644 --- a/phlib/symprv.c +++ b/phlib/symprv.c @@ -156,7 +156,14 @@ VOID PhSymbolProviderCompleteInitialization( UnDecorateSymbolNameW_I = PhGetProcedureAddress(dbghelpHandle, "UnDecorateSymbolNameW", 0); if (SymGetOptions_I && SymSetOptions_I) - SymSetOptions_I(SymGetOptions_I() | SYMOPT_DEFERRED_LOADS | SYMOPT_FAVOR_COMPRESSED | SYMOPT_UNDNAME); + { + SymSetOptions_I( + SymGetOptions_I() | + SYMOPT_AUTO_PUBLICS | SYMOPT_CASE_INSENSITIVE | SYMOPT_DEFERRED_LOADS | + SYMOPT_FAIL_CRITICAL_ERRORS | SYMOPT_INCLUDE_32BIT_MODULES | + SYMOPT_LOAD_LINES | SYMOPT_OMAP_FIND_NEAREST | SYMOPT_UNDNAME + ); + } } PPH_SYMBOL_PROVIDER PhCreateSymbolProvider( diff --git a/tools/peview/pdb.c b/tools/peview/pdb.c index 78475e31ef3d..53239934e5f2 100644 --- a/tools/peview/pdb.c +++ b/tools/peview/pdb.c @@ -2328,7 +2328,12 @@ NTSTATUS PeDumpFileSymbols( SymGetTypeInfo_I = PhGetProcedureAddress(dbghelpHandle, "SymGetTypeInfo", 0); SymSetContext_I = PhGetProcedureAddress(dbghelpHandle, "SymSetContext", 0); - SymSetOptions_I(SymGetOptions_I() | SYMOPT_DEBUG | SYMOPT_UNDNAME); + SymSetOptions_I( + SymGetOptions_I() | + SYMOPT_AUTO_PUBLICS | SYMOPT_CASE_INSENSITIVE | + SYMOPT_DEFERRED_LOADS | SYMOPT_FAIL_CRITICAL_ERRORS | SYMOPT_INCLUDE_32BIT_MODULES | + SYMOPT_LOAD_LINES | SYMOPT_OMAP_FIND_NEAREST | SYMOPT_UNDNAME // SYMOPT_DEBUG + ); if (!SymInitialize_I(NtCurrentProcess(), NULL, FALSE)) return 1; From 3dd162d92cbced563d7153b3fe899c6df1032c08 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 16 Nov 2017 08:17:07 +1100 Subject: [PATCH 0580/2058] Add JobObjectId column to processes tab, Add ProcessSequenceNumber support, Fix timezone changes breaking process' parenting --- ProcessHacker/actions.c | 25 ++++-- ProcessHacker/hidnproc.c | 4 +- ProcessHacker/include/procprv.h | 11 +-- ProcessHacker/include/proctree.h | 4 +- ProcessHacker/mwpgproc.c | 6 +- ProcessHacker/procprv.c | 114 +++++++++++++++++++++------ ProcessHacker/procrec.c | 6 +- ProcessHacker/proctree.c | 28 ++++++- ProcessHacker/prpggen.c | 6 +- plugins/ExtendedNotifications/main.c | 6 +- 10 files changed, 151 insertions(+), 59 deletions(-) diff --git a/ProcessHacker/actions.c b/ProcessHacker/actions.c index 71ead0b015a2..868753e1df70 100644 --- a/ProcessHacker/actions.c +++ b/ProcessHacker/actions.c @@ -1082,13 +1082,28 @@ BOOLEAN PhpUiTerminateTreeProcess( { if (processItem = PhReferenceProcessItem(process->UniqueProcessId)) { - // Check the creation time to make sure it is a descendant. - if (processItem->CreateTime.QuadPart >= Process->CreateTime.QuadPart) + if (WindowsVersion >= WINDOWS_10_RS3) { - if (!PhpUiTerminateTreeProcess(hWnd, processItem, Processes, Success)) + // Check the sequence number to make sure it is a descendant. + if (processItem->ProcessSequenceNumber >= Process->ProcessSequenceNumber) { - PhDereferenceObject(processItem); - return FALSE; + if (!PhpUiTerminateTreeProcess(hWnd, processItem, Processes, Success)) + { + PhDereferenceObject(processItem); + return FALSE; + } + } + } + else + { + // Check the creation time to make sure it is a descendant. + if (processItem->CreateTime.QuadPart >= Process->CreateTime.QuadPart) + { + if (!PhpUiTerminateTreeProcess(hWnd, processItem, Processes, Success)) + { + PhDereferenceObject(processItem); + return FALSE; + } } } diff --git a/ProcessHacker/hidnproc.c b/ProcessHacker/hidnproc.c index 81745a5528fb..f3b342c8c2fc 100644 --- a/ProcessHacker/hidnproc.c +++ b/ProcessHacker/hidnproc.c @@ -565,8 +565,8 @@ static PPH_PROCESS_ITEM PhpCreateProcessItemForHiddenProcess( processItem = PhCreateProcessItem(Entry->ProcessId); // Mark the process as terminated if necessary. - //if (Entry->Type == TerminatedProcess) - // processItem->State |= PH_PROCESS_ITEM_REMOVED; + if (Entry->Type == TerminatedProcess) + processItem->State |= PH_PROCESS_ITEM_REMOVED; // We need a process record. Just use the record of System Idle Process. if (idleProcessItem = PhReferenceProcessItem(SYSTEM_IDLE_PROCESS_ID)) diff --git a/ProcessHacker/include/procprv.h b/ProcessHacker/include/procprv.h index 7f82eabee7de..1237d1c8995a 100644 --- a/ProcessHacker/include/procprv.h +++ b/ProcessHacker/include/procprv.h @@ -216,7 +216,7 @@ typedef struct _PH_PROCESS_ITEM ULONG PeakNumberOfThreads; // since WIN7 ULONG HardFaultCount; // since WIN7 - ULONG SequenceNumber; + ULONG TimeSequenceNumber; PH_CIRCULAR_BUFFER_FLOAT CpuKernelHistory; PH_CIRCULAR_BUFFER_FLOAT CpuUserHistory; PH_CIRCULAR_BUFFER_ULONG64 IoReadHistory; @@ -229,7 +229,9 @@ typedef struct _PH_PROCESS_ITEM PH_UINTPTR_DELTA PrivateBytesDelta; PPH_STRING PackageFullName; - PH_QUEUED_LOCK RemoveLock; + ULONGLONG ProcessSequenceNumber; + PH_KNOWN_PROCESS_TYPE KnownProcessType; + ULONG JobObjectId; } PH_PROCESS_ITEM, *PPH_PROCESS_ITEM; // end_phapppub @@ -248,6 +250,7 @@ typedef struct _PH_PROCESS_RECORD HANDLE ProcessId; HANDLE ParentProcessId; ULONG SessionId; + ULONGLONG ProcessSequenceNumber; LARGE_INTEGER CreateTime; LARGE_INTEGER ExitTime; @@ -396,9 +399,7 @@ PHAPPAPI PPH_PROCESS_ITEM NTAPI PhReferenceProcessItemForParent( - _In_ HANDLE ParentProcessId, - _In_ HANDLE ProcessId, - _In_ PLARGE_INTEGER CreateTime + _In_ PPH_PROCESS_ITEM ProcessItem ); PHAPPAPI diff --git a/ProcessHacker/include/proctree.h b/ProcessHacker/include/proctree.h index 3535bfbd605e..5ddd6ef7b0b5 100644 --- a/ProcessHacker/include/proctree.h +++ b/ProcessHacker/include/proctree.h @@ -90,8 +90,9 @@ #define PHPRTLC_FILEMODIFIEDTIME 77 #define PHPRTLC_FILESIZE 78 #define PHPRTLC_SUBPROCESSCOUNT 79 +#define PHPRTLC_JOBOBJECTID 80 -#define PHPRTLC_MAXIMUM 80 +#define PHPRTLC_MAXIMUM 81 #define PHPRTLC_IOGROUP_COUNT 9 #define PHPN_WSCOUNTERS 0x1 @@ -215,6 +216,7 @@ typedef struct _PH_PROCESS_NODE PPH_STRING FileModifiedTimeText; PPH_STRING FileSizeText; PPH_STRING SubprocessCountText; + WCHAR JobObjectIdText[PH_INT32_STR_LEN_1]; // Graph buffers PH_GRAPH_BUFFERS CpuGraphBuffers; diff --git a/ProcessHacker/mwpgproc.c b/ProcessHacker/mwpgproc.c index 2d12dada4116..f0b222193d3d 100644 --- a/ProcessHacker/mwpgproc.c +++ b/ProcessHacker/mwpgproc.c @@ -759,11 +759,7 @@ VOID PhMwpOnProcessAdded( HANDLE parentProcessId = NULL; PPH_STRING parentName = NULL; - if (parentProcess = PhReferenceProcessItemForParent( - ProcessItem->ParentProcessId, - ProcessItem->ProcessId, - &ProcessItem->CreateTime - )) + if (parentProcess = PhReferenceProcessItemForParent(ProcessItem)) { parentProcessId = parentProcess->ProcessId; parentName = parentProcess->ProcessName; diff --git a/ProcessHacker/procprv.c b/ProcessHacker/procprv.c index cf5b07e43b64..c7033fd3c584 100644 --- a/ProcessHacker/procprv.c +++ b/ProcessHacker/procprv.c @@ -1316,6 +1316,22 @@ VOID PhpFillProcessItemStage2( processItem->ImportModules = Data->ImportModules; } +VOID PhpFillProcessItemExtension( + _Inout_ PPH_PROCESS_ITEM ProcessItem, + _In_ PSYSTEM_PROCESS_INFORMATION Process + ) +{ + PSYSTEM_PROCESS_INFORMATION_EXTENSION processExtension; + + if (WindowsVersion < WINDOWS_10_RS3) + return; + + processExtension = PH_PROCESS_EXTENSION(Process); + + ProcessItem->JobObjectId = processExtension->JobObjectId; + ProcessItem->ProcessSequenceNumber = processExtension->ProcessSequenceNumber; +} + VOID PhpFillProcessItem( _Inout_ PPH_PROCESS_ITEM ProcessItem, _In_ PSYSTEM_PROCESS_INFORMATION Process @@ -1413,6 +1429,14 @@ VOID PhpFillProcessItem( } } + // Known Process Type + { + ProcessItem->KnownProcessType = PhGetProcessKnownTypeEx( + ProcessItem->ProcessId, + ProcessItem->FileName + ); + } + NtClose(processHandle); } @@ -1759,7 +1783,7 @@ BOOLEAN PhGetStatisticsTime( { // The sequence number is used to synchronize statistics when a process exits, since that // process' history is not updated anymore. - index = PhTimeSequenceNumber - ProcessItem->SequenceNumber + Index; + index = PhTimeSequenceNumber - ProcessItem->TimeSequenceNumber + Index; if (index >= PhTimeHistory.Count) { @@ -1987,10 +2011,20 @@ VOID PhProcessProviderUpdate( { PPH_PROCESS_ITEM processItem; - if ((processItem = PhpLookupProcessItem(process->UniqueProcessId)) && processItem->CreateTime.QuadPart == process->CreateTime.QuadPart) - sysTotalCycleTime += process->CycleTime - processItem->CycleTimeDelta.Value; // existing process + if (WindowsVersion >= WINDOWS_10_RS3) + { + if ((processItem = PhpLookupProcessItem(process->UniqueProcessId)) && processItem->ProcessSequenceNumber == PH_PROCESS_EXTENSION(process)->ProcessSequenceNumber) + sysTotalCycleTime += process->CycleTime - processItem->CycleTimeDelta.Value; // existing process + else + sysTotalCycleTime += process->CycleTime; // new process + } else - sysTotalCycleTime += process->CycleTime; // new process + { + if ((processItem = PhpLookupProcessItem(process->UniqueProcessId)) && processItem->CreateTime.QuadPart == process->CreateTime.QuadPart) + sysTotalCycleTime += process->CycleTime - processItem->CycleTimeDelta.Value; // existing process + else + sysTotalCycleTime += process->CycleTime; // new process + } } } while (process = PH_NEXT_PROCESS(process)); @@ -2023,6 +2057,8 @@ VOID PhProcessProviderUpdate( { for (entry = PhProcessHashSet[i]; entry; entry = entry->Next) { + BOOLEAN processRemoved = FALSE; + processItem = CONTAINING_RECORD(entry, PH_PROCESS_ITEM, HashEntry); // Check if the process still exists. Note that we take into account PID re-use by @@ -2044,7 +2080,18 @@ VOID PhProcessProviderUpdate( processEntry = (PSYSTEM_PROCESS_INFORMATION)processEntry->UniqueProcessKey; } - if (!processEntry || processEntry->CreateTime.QuadPart != processItem->CreateTime.QuadPart) + if (WindowsVersion >= WINDOWS_10_RS3) + { + if (!processEntry || PH_PROCESS_EXTENSION(processEntry)->ProcessSequenceNumber != processItem->ProcessSequenceNumber) + processRemoved = TRUE; + } + else + { + if (!processEntry || processEntry->CreateTime.QuadPart != processItem->CreateTime.QuadPart) + processRemoved = TRUE; + } + + if (processRemoved) { LARGE_INTEGER exitTime; @@ -2139,7 +2186,8 @@ VOID PhProcessProviderUpdate( // Create the process item and fill in basic information. processItem = PhCreateProcessItem(process->UniqueProcessId); PhpFillProcessItem(processItem, process); - processItem->SequenceNumber = PhTimeSequenceNumber; + PhpFillProcessItemExtension(processItem, process); + processItem->TimeSequenceNumber = PhTimeSequenceNumber; processRecord = PhpCreateProcessRecord(processItem); PhpAddProcessRecord(processRecord); @@ -2224,6 +2272,7 @@ VOID PhProcessProviderUpdate( PhpGetProcessThreadInformation(process, &isSuspended, &isPartiallySuspended, &contextSwitches); PhpUpdateDynamicInfoProcessItem(processItem, process); + PhpFillProcessItemExtension(processItem, process); // Update the deltas. PhUpdateDelta(&processItem->CpuKernelDelta, process->KernelTime.QuadPart); @@ -2239,7 +2288,7 @@ VOID PhProcessProviderUpdate( PhUpdateDelta(&processItem->CycleTimeDelta, process->CycleTime); PhUpdateDelta(&processItem->PrivateBytesDelta, process->PagefileUsage); - processItem->SequenceNumber++; + processItem->TimeSequenceNumber++; PhAddItemCircularBuffer_ULONG64(&processItem->IoReadHistory, processItem->IoReadDelta.Delta); PhAddItemCircularBuffer_ULONG64(&processItem->IoWriteHistory, processItem->IoWriteDelta.Delta); PhAddItemCircularBuffer_ULONG64(&processItem->IoOtherHistory, processItem->IoOtherDelta.Delta); @@ -2488,6 +2537,7 @@ PPH_PROCESS_RECORD PhpCreateProcessRecord( processRecord->ProcessId = ProcessItem->ProcessId; processRecord->ParentProcessId = ProcessItem->ParentProcessId; processRecord->SessionId = ProcessItem->SessionId; + processRecord->ProcessSequenceNumber = ProcessItem->ProcessSequenceNumber; processRecord->CreateTime = ProcessItem->CreateTime; PhSetReference(&processRecord->ProcessName, ProcessItem->ProcessName); @@ -2839,30 +2889,40 @@ VOID PhPurgeProcessRecords( } PPH_PROCESS_ITEM PhReferenceProcessItemForParent( - _In_ HANDLE ParentProcessId, - _In_ HANDLE ProcessId, - _In_ PLARGE_INTEGER CreateTime + _In_ PPH_PROCESS_ITEM ProcessItem ) { - PPH_PROCESS_ITEM processItem; + PPH_PROCESS_ITEM parentProcessItem; - if (ParentProcessId == ProcessId) // for cases where the parent PID = PID (e.g. System Idle Process) + if (ProcessItem->ParentProcessId == ProcessItem->ProcessId) // for cases where the parent PID = PID (e.g. System Idle Process) return NULL; PhAcquireQueuedLockShared(&PhProcessHashSetLock); - processItem = PhpLookupProcessItem(ParentProcessId); + parentProcessItem = PhpLookupProcessItem(ProcessItem->ParentProcessId); - // We make sure that the process item we found is actually the parent process - its start time - // must not be larger than the supplied time. - if (processItem && processItem->CreateTime.QuadPart <= CreateTime->QuadPart) - PhReferenceObject(processItem); + if (WindowsVersion >= WINDOWS_10_RS3) + { + // We make sure that the process item we found is actually the parent process - its start time + // must not be larger than the supplied time. + if (parentProcessItem && parentProcessItem->ProcessSequenceNumber <= ProcessItem->ProcessSequenceNumber) + PhReferenceObject(parentProcessItem); + else + parentProcessItem = NULL; + } else - processItem = NULL; + { + // We make sure that the process item we found is actually the parent process - its start time + // must not be larger than the supplied time. + if (parentProcessItem && parentProcessItem->CreateTime.QuadPart <= ProcessItem->CreateTime.QuadPart) + PhReferenceObject(parentProcessItem); + else + parentProcessItem = NULL; + } PhReleaseQueuedLockShared(&PhProcessHashSetLock); - return processItem; + return parentProcessItem; } PPH_PROCESS_ITEM PhReferenceProcessItemForRecord( @@ -2875,10 +2935,20 @@ PPH_PROCESS_ITEM PhReferenceProcessItemForRecord( processItem = PhpLookupProcessItem(Record->ProcessId); - if (processItem && processItem->CreateTime.QuadPart == Record->CreateTime.QuadPart) - PhReferenceObject(processItem); + if (WindowsVersion >= WINDOWS_10_RS3) + { + if (processItem && processItem->ProcessSequenceNumber == Record->ProcessSequenceNumber) + PhReferenceObject(processItem); + else + processItem = NULL; + } else - processItem = NULL; + { + if (processItem && processItem->CreateTime.QuadPart == Record->CreateTime.QuadPart) + PhReferenceObject(processItem); + else + processItem = NULL; + } PhReleaseQueuedLockShared(&PhProcessHashSetLock); diff --git a/ProcessHacker/procrec.c b/ProcessHacker/procrec.c index 8332a7180d2d..fb654e1aa669 100644 --- a/ProcessHacker/procrec.c +++ b/ProcessHacker/procrec.c @@ -142,11 +142,7 @@ INT_PTR CALLBACK PhpProcessRecordDlgProc( { PPH_PROCESS_ITEM parentProcess; - if (parentProcess = PhReferenceProcessItemForParent( - processItem->ParentProcessId, - processItem->ProcessId, - &processItem->CreateTime - )) + if (parentProcess = PhReferenceProcessItemForParent(processItem)) { CLIENT_ID clientId; diff --git a/ProcessHacker/proctree.c b/ProcessHacker/proctree.c index fcebcb953846..0d4e674de3ca 100644 --- a/ProcessHacker/proctree.c +++ b/ProcessHacker/proctree.c @@ -208,6 +208,7 @@ VOID PhInitializeProcessTreeList( PhAddTreeNewColumnEx(hwnd, PHPRTLC_FILEMODIFIEDTIME, FALSE, L"File modified time", 140, PH_ALIGN_LEFT, -1, 0, TRUE); PhAddTreeNewColumnEx(hwnd, PHPRTLC_FILESIZE, FALSE, L"File size", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); PhAddTreeNewColumnEx(hwnd, PHPRTLC_SUBPROCESSCOUNT, FALSE, L"Subprocesses", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_JOBOBJECTID, FALSE, L"Job Object ID", 50, PH_ALIGN_LEFT, -1, 0, TRUE); TreeNew_SetRedraw(hwnd, TRUE); @@ -296,9 +297,16 @@ FORCEINLINE BOOLEAN PhpValidateParentCreateTime( _In_ PPH_PROCESS_NODE Parent ) { - return - PH_IS_FAKE_PROCESS_ID(Child->ProcessId) || - Parent->ProcessItem->CreateTime.QuadPart <= Child->ProcessItem->CreateTime.QuadPart; + if (WindowsVersion >= WINDOWS_10_RS3) + { + return PH_IS_FAKE_PROCESS_ID(Child->ProcessId) || + Parent->ProcessItem->ProcessSequenceNumber <= Child->ProcessItem->ProcessSequenceNumber; + } + else + { + return PH_IS_FAKE_PROCESS_ID(Child->ProcessId) || + Parent->ProcessItem->CreateTime.QuadPart <= Child->ProcessItem->CreateTime.QuadPart; + } } PPH_PROCESS_NODE PhAddProcessNode( @@ -1827,6 +1835,12 @@ BEGIN_SORT_FUNCTION(Subprocesses) } END_SORT_FUNCTION +BEGIN_SORT_FUNCTION(JobObjectId) +{ + sortResult = int64cmp(processItem1->JobObjectId, processItem2->JobObjectId); +} +END_SORT_FUNCTION + BOOLEAN NTAPI PhpProcessTreeNewCallback( _In_ HWND hwnd, _In_ PH_TREENEW_MESSAGE Message, @@ -1946,7 +1960,8 @@ BOOLEAN NTAPI PhpProcessTreeNewCallback( SORT_FUNCTION(TimeStamp), SORT_FUNCTION(FileModifiedTime), SORT_FUNCTION(FileSize), - SORT_FUNCTION(Subprocesses) + SORT_FUNCTION(Subprocesses), + SORT_FUNCTION(JobObjectId) }; int (__cdecl *sortFunction)(const void *, const void *); @@ -2639,6 +2654,11 @@ BOOLEAN NTAPI PhpProcessTreeNewCallback( getCellText->Text = node->SubprocessCountText->sr; } break; + case PHPRTLC_JOBOBJECTID: + { + PhpFormatInt32GroupDigits(processItem->JobObjectId, node->JobObjectIdText, sizeof(node->JobObjectIdText), &getCellText->Text); + } + break; default: return FALSE; } diff --git a/ProcessHacker/prpggen.c b/ProcessHacker/prpggen.c index 4d4ffca566eb..a6d288b7c7d9 100644 --- a/ProcessHacker/prpggen.c +++ b/ProcessHacker/prpggen.c @@ -284,11 +284,7 @@ INT_PTR CALLBACK PhpProcessGeneralDlgProc( // Parent - if (parentProcess = PhReferenceProcessItemForParent( - processItem->ParentProcessId, - processItem->ProcessId, - &processItem->CreateTime - )) + if (parentProcess = PhReferenceProcessItemForParent(processItem)) { clientId.UniqueProcess = parentProcess->ProcessId; clientId.UniqueThread = NULL; diff --git a/plugins/ExtendedNotifications/main.c b/plugins/ExtendedNotifications/main.c index 1ec31acc37d7..d8940a4879d5 100644 --- a/plugins/ExtendedNotifications/main.c +++ b/plugins/ExtendedNotifications/main.c @@ -487,11 +487,7 @@ VOID NotifyGrowl( notification = GrowlNotifications[0]; title = processItem->ProcessName; - parentProcessItem = PhReferenceProcessItemForParent( - processItem->ParentProcessId, - processItem->ProcessId, - &processItem->CreateTime - ); + parentProcessItem = PhReferenceProcessItemForParent(processItem); message = PhaFormatString( L"The process %s (%lu) was started by %s.", From 70bed5c0debfff516ec9d9d8be8e68792abaa245 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 16 Nov 2017 08:19:42 +1100 Subject: [PATCH 0581/2058] Add WMI Provider Host process properties page for WmiPrvSE.exe processes --- ProcessHacker/ProcessHacker.rc | 16 + ProcessHacker/ProcessHacker.vcxproj | 9 +- ProcessHacker/ProcessHacker.vcxproj.filters | 3 + ProcessHacker/include/procprpp.h | 7 + ProcessHacker/procprp.c | 11 + ProcessHacker/prpgwmi.c | 755 ++++++++++++++++++++ ProcessHacker/resource.h | 1 + ProcessHacker/settings.c | 2 + 8 files changed, 800 insertions(+), 4 deletions(-) create mode 100644 ProcessHacker/prpgwmi.c diff --git a/ProcessHacker/ProcessHacker.rc b/ProcessHacker/ProcessHacker.rc index e44cfe89d3de..02976aa4cd90 100644 --- a/ProcessHacker/ProcessHacker.rc +++ b/ProcessHacker/ProcessHacker.rc @@ -1879,6 +1879,14 @@ BEGIN LTEXT "Changes may require a restart to take effect.",IDC_INSTRUCTION,2,163,148,8,NOT WS_VISIBLE END +IDD_PROCWMIPROVIDERS DIALOGEX 0, 0, 260, 260 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "WMI Providers" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,2,2,256,256 +END + ///////////////////////////////////////////////////////////////////////////// // @@ -2433,6 +2441,14 @@ BEGIN TOPMARGIN, 2 BOTTOMMARGIN, 174 END + + IDD_PROCWMIPROVIDERS, DIALOG + BEGIN + LEFTMARGIN, 2 + RIGHTMARGIN, 258 + TOPMARGIN, 2 + BOTTOMMARGIN, 258 + END END #endif // APSTUDIO_INVOKED diff --git a/ProcessHacker/ProcessHacker.vcxproj b/ProcessHacker/ProcessHacker.vcxproj index b998678db459..9b4c0047495c 100644 --- a/ProcessHacker/ProcessHacker.vcxproj +++ b/ProcessHacker/ProcessHacker.vcxproj @@ -96,7 +96,7 @@ true - aclui.lib;comctl32.lib;iphlpapi.lib;noarg.obj;noenv.obj;ntdll.lib;phlib.lib;uxtheme.lib;version.lib;windowscodecs.lib;winsta.lib;ws2_32.lib;%(AdditionalDependencies) + aclui.lib;comctl32.lib;iphlpapi.lib;noarg.obj;noenv.obj;ntdll.lib;phlib.lib;uxtheme.lib;version.lib;wbemuuid.lib;windowscodecs.lib;winsta.lib;ws2_32.lib;%(AdditionalDependencies) true Windows MachineX86 @@ -128,7 +128,7 @@ true - aclui.lib;comctl32.lib;iphlpapi.lib;noarg.obj;noenv.obj;ntdll.lib;phlib.lib;uxtheme.lib;version.lib;windowscodecs.lib;winsta.lib;ws2_32.lib;%(AdditionalDependencies) + aclui.lib;comctl32.lib;iphlpapi.lib;noarg.obj;noenv.obj;ntdll.lib;phlib.lib;uxtheme.lib;version.lib;wbemuuid.lib;windowscodecs.lib;winsta.lib;ws2_32.lib;%(AdditionalDependencies) true Windows MachineX64 @@ -165,7 +165,7 @@ Guard - aclui.lib;comctl32.lib;iphlpapi.lib;noarg.obj;noenv.obj;ntdll.lib;phlib.lib;uxtheme.lib;version.lib;windowscodecs.lib;winsta.lib;ws2_32.lib;%(AdditionalDependencies) + aclui.lib;comctl32.lib;iphlpapi.lib;noarg.obj;noenv.obj;ntdll.lib;phlib.lib;uxtheme.lib;version.lib;wbemuuid.lib;windowscodecs.lib;winsta.lib;ws2_32.lib;%(AdditionalDependencies) true Windows true @@ -203,7 +203,7 @@ Guard - aclui.lib;comctl32.lib;iphlpapi.lib;noarg.obj;noenv.obj;ntdll.lib;phlib.lib;uxtheme.lib;version.lib;windowscodecs.lib;winsta.lib;ws2_32.lib;%(AdditionalDependencies) + aclui.lib;comctl32.lib;iphlpapi.lib;noarg.obj;noenv.obj;ntdll.lib;phlib.lib;uxtheme.lib;version.lib;wbemuuid.lib;windowscodecs.lib;winsta.lib;ws2_32.lib;%(AdditionalDependencies) true Windows true @@ -322,6 +322,7 @@ + diff --git a/ProcessHacker/ProcessHacker.vcxproj.filters b/ProcessHacker/ProcessHacker.vcxproj.filters index f93d2a3fb8b1..b969ed3f7d8f 100644 --- a/ProcessHacker/ProcessHacker.vcxproj.filters +++ b/ProcessHacker/ProcessHacker.vcxproj.filters @@ -381,6 +381,9 @@ Process Hacker + + Process Hacker + diff --git a/ProcessHacker/include/procprpp.h b/ProcessHacker/include/procprpp.h index 2e315c4db325..b38f340a7a58 100644 --- a/ProcessHacker/include/procprpp.h +++ b/ProcessHacker/include/procprpp.h @@ -178,6 +178,13 @@ INT_PTR CALLBACK PhpProcessServicesDlgProc( _In_ LPARAM lParam ); +INT_PTR CALLBACK PhpProcessWmiProvidersDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + extern PH_STRINGREF PhpLoadingText; #define WM_PH_THREADS_UPDATED (WM_APP + 200) diff --git a/ProcessHacker/procprp.c b/ProcessHacker/procprp.c index 2380d83ec95b..a9909f48b557 100644 --- a/ProcessHacker/procprp.c +++ b/ProcessHacker/procprp.c @@ -650,6 +650,17 @@ NTSTATUS PhpProcessPropertiesThreadStart( PhAddProcessPropPage(PropContext, newPage); } + // WMI Provider Host + if ((PropContext->ProcessItem->KnownProcessType & KnownProcessTypeMask) == WmiProviderHostType) + { + newPage = PhCreateProcessPropPageContext( + MAKEINTRESOURCE(IDD_PROCWMIPROVIDERS), + PhpProcessWmiProvidersDlgProc, + NULL + ); + PhAddProcessPropPage(PropContext, newPage); + } + // Plugin-supplied pages if (PhPluginsEnabled) { diff --git a/ProcessHacker/prpgwmi.c b/ProcessHacker/prpgwmi.c new file mode 100644 index 000000000000..d24f7c4d63ca --- /dev/null +++ b/ProcessHacker/prpgwmi.c @@ -0,0 +1,755 @@ +/* + * Process Hacker - + * Process properties: WMI Providor page + * + * Copyright (C) 2017 dmex + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include +#include +#include +#include +#include +#include + +#define CINTERFACE +#define COBJMACROS +#include +#include +#include + +#define WM_PH_WMI_UPDATE (WM_APP + 251) + +typedef struct _PH_WMI_CONTEXT +{ + PH_CALLBACK_REGISTRATION ProcessesUpdatedRegistration; + HWND WindowHandle; + HWND ListViewHandle; + BOOLEAN Enabled; + PPH_LIST WmiProviderList; +} PH_WMI_CONTEXT, *PPH_WMI_CONTEXT; + +typedef struct _PH_WMI_ENTRY +{ + PPH_STRING ProviderName; + PPH_STRING NamespacePath; + PPH_STRING FileName; + PPH_STRING UserName; +} PH_WMI_ENTRY, *PPH_WMI_ENTRY; + +HRESULT PhpWmiProviderExecMethod( + _In_ PWSTR Method, + _In_ PWSTR ProcessIdString, + _In_ PPH_WMI_ENTRY Entry + ) +{ + HRESULT status; + PPH_STRING queryString = NULL; + IWbemLocator* wbemLocator = NULL; + IWbemServices* wbemServices = NULL; + IEnumWbemClassObject* wbemEnumerator = NULL; + IWbemClassObject *wbemClassObject; + + if (FAILED(status = CoCreateInstance( + &CLSID_WbemLocator, + 0, + CLSCTX_INPROC_SERVER, + &IID_IWbemLocator, + &wbemLocator + ))) + { + goto CleanupExit; + } + + if (FAILED(status = IWbemLocator_ConnectServer( + wbemLocator, + L"root\\CIMV2", + NULL, + NULL, + NULL, + 0, + 0, + NULL, + &wbemServices + ))) + { + goto CleanupExit; + } + + queryString = PhConcatStrings2(L"SELECT Namespace,Provider,User,__PATH FROM Msft_Providers WHERE HostProcessIdentifier = ", ProcessIdString); + + if (FAILED(status = IWbemServices_ExecQuery( + wbemServices, + L"WQL", + queryString->Buffer, + WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, + NULL, + &wbemEnumerator + ))) + { + goto CleanupExit; + } + + while (TRUE) + { + PPH_STRING namespacePath = NULL; + PPH_STRING providerName = NULL; + PPH_STRING userName = NULL; + PPH_STRING instancePath = NULL; + ULONG count = 0; + VARIANT variant; + + if (FAILED(IEnumWbemClassObject_Next(wbemEnumerator, WBEM_INFINITE, 1, &wbemClassObject, &count))) + break; + + if (count == 0) + break; + + if (SUCCEEDED(IWbemClassObject_Get(wbemClassObject, L"Namespace", 0, &variant, 0, 0))) + { + namespacePath = PhCreateString(variant.bstrVal); + VariantClear(&variant); + } + + if (SUCCEEDED(IWbemClassObject_Get(wbemClassObject, L"Provider", 0, &variant, 0, 0))) + { + providerName = PhCreateString(variant.bstrVal); + VariantClear(&variant); + } + + if (SUCCEEDED(IWbemClassObject_Get(wbemClassObject, L"User", 0, &variant, 0, 0))) + { + userName = PhCreateString(variant.bstrVal); + VariantClear(&variant); + } + + if (SUCCEEDED(IWbemClassObject_Get(wbemClassObject, L"__PATH", 0, &variant, 0, 0))) + { + instancePath = PhCreateString(variant.bstrVal); + VariantClear(&variant); + } + + if ( + PhEqualString(Entry->NamespacePath, namespacePath, FALSE) && + PhEqualString(Entry->ProviderName, providerName, FALSE) && + PhEqualString(Entry->UserName, userName, FALSE) + ) + { + status = IWbemServices_ExecMethod( + wbemServices, + instancePath->Buffer, + Method, + 0, + NULL, + wbemClassObject, + NULL, + NULL + ); + } + + if (instancePath) + PhDereferenceObject(instancePath); + if (userName) + PhDereferenceObject(userName); + if (providerName) + PhDereferenceObject(providerName); + if (namespacePath) + PhDereferenceObject(namespacePath); + + IWbemClassObject_Release(wbemClassObject); + } + +CleanupExit: + if (queryString) + PhDereferenceObject(queryString); + if (wbemEnumerator) + IEnumWbemClassObject_Release(wbemEnumerator); + if (wbemServices) + IWbemServices_Release(wbemServices); + if (wbemLocator) + IWbemLocator_Release(wbemLocator); + + return status; +} + +HRESULT PhpQueryWmiProviderFileName( + _In_ PPH_STRING ProviderNameSpace, + _In_ PPH_STRING ProviderName, + _Out_ PPH_STRING *FileName + ) +{ + HRESULT status; + PPH_STRING fileName = NULL; + PPH_STRING queryString = NULL; + PPH_STRING clsidString = NULL; + IWbemLocator* wbemLocator = NULL; + IWbemServices* wbemServices = NULL; + IEnumWbemClassObject* wbemEnumerator = NULL; + IWbemClassObject *wbemClassObject = NULL; + ULONG count = 0; + + if (FAILED(status = CoCreateInstance( + &CLSID_WbemLocator, + 0, + CLSCTX_INPROC_SERVER, + &IID_IWbemLocator, + &wbemLocator + ))) + { + goto CleanupExit; + } + + if (FAILED(status = IWbemLocator_ConnectServer( + wbemLocator, + ProviderNameSpace->Buffer, + NULL, + NULL, + NULL, + 0, + 0, + NULL, + &wbemServices + ))) + { + goto CleanupExit; + } + + queryString = PhFormatString(L"SELECT clsid FROM __Win32Provider WHERE Name = '%s'", ProviderName->Buffer); + + if (FAILED(status = IWbemServices_ExecQuery( + wbemServices, + L"WQL", + queryString->Buffer, + WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, + NULL, + &wbemEnumerator + ))) + { + goto CleanupExit; + } + + if (SUCCEEDED(status = IEnumWbemClassObject_Next( + wbemEnumerator, + WBEM_INFINITE, + 1, + &wbemClassObject, + &count + ))) + { + VARIANT variant; + + if (SUCCEEDED(IWbemClassObject_Get(wbemClassObject, L"CLSID", 0, &variant, 0, 0))) + { + clsidString = PhCreateString(variant.bstrVal); + VariantClear(&variant); + } + + IWbemClassObject_Release(wbemClassObject); + } + + // Lookup the GUID in the registry to determine the name and file name. + + if (!PhIsNullOrEmptyString(clsidString)) + { + HANDLE keyHandle; + PPH_STRING keyPath; + + // Note: String pooling optimization. + keyPath = PhConcatStrings( + 4, + L"CLSID\\", + clsidString->Buffer, + L"\\", + L"InprocServer32" + ); + + if (SUCCEEDED(status = HRESULT_FROM_NT(PhOpenKey( + &keyHandle, + KEY_READ, + PH_KEY_CLASSES_ROOT, + &keyPath->sr, + 0 + )))) + { + if (fileName = PhQueryRegistryString(keyHandle, NULL)) + { + PPH_STRING expandedString; + + if (expandedString = PhExpandEnvironmentStrings(&fileName->sr)) + { + PhMoveReference(&fileName, expandedString); + } + } + + NtClose(keyHandle); + } + + PhDereferenceObject(keyPath); + } + +CleanupExit: + if (clsidString) + PhDereferenceObject(clsidString); + if (queryString) + PhDereferenceObject(queryString); + if (wbemEnumerator) + IEnumWbemClassObject_Release(wbemEnumerator); + if (wbemServices) + IWbemServices_Release(wbemServices); + if (wbemLocator) + IWbemLocator_Release(wbemLocator); + + if (SUCCEEDED(status)) + *FileName = fileName; + + return status; +} + +PPH_LIST PhpQueryWmiProviderHostProcess( + _In_ PPH_PROCESS_ITEM ProcessItem + ) +{ + HRESULT status; + PPH_LIST providerList; + PPH_STRING queryString = NULL; + IWbemLocator* wbemLocator = NULL; + IWbemServices* wbemServices = NULL; + IEnumWbemClassObject* wbemEnumerator = NULL; + IWbemClassObject *wbemClassObject; + + if (FAILED(status = CoCreateInstance( + &CLSID_WbemLocator, + 0, + CLSCTX_INPROC_SERVER, + &IID_IWbemLocator, + &wbemLocator + ))) + { + goto CleanupExit; + } + + if (FAILED(status = IWbemLocator_ConnectServer( + wbemLocator, + L"root\\CIMV2", + NULL, + NULL, + NULL, + 0, + 0, + NULL, + &wbemServices + ))) + { + goto CleanupExit; + } + + queryString = PhConcatStrings2(L"SELECT Namespace,Provider,User FROM Msft_Providers WHERE HostProcessIdentifier = ", ProcessItem->ProcessIdString); + + if (FAILED(status = IWbemServices_ExecQuery( + wbemServices, + L"WQL", + queryString->Buffer, + WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, + NULL, + &wbemEnumerator + ))) + { + goto CleanupExit; + } + + providerList = PhCreateList(1); + + while (TRUE) + { + ULONG count = 0; + VARIANT variant; + PPH_WMI_ENTRY entry; + + if (FAILED(IEnumWbemClassObject_Next(wbemEnumerator, WBEM_INFINITE, 1, &wbemClassObject, &count))) + break; + + if (count == 0) + break; + + entry = PhAllocate(sizeof(PH_WMI_ENTRY)); + memset(entry, 0, sizeof(PH_WMI_ENTRY)); + + if (SUCCEEDED(IWbemClassObject_Get(wbemClassObject, L"Namespace", 0, &variant, 0, 0))) + { + entry->NamespacePath = PhCreateString(variant.bstrVal); + VariantClear(&variant); + } + + if (SUCCEEDED(IWbemClassObject_Get(wbemClassObject, L"Provider", 0, &variant, 0, 0))) + { + entry->ProviderName = PhCreateString(variant.bstrVal); + VariantClear(&variant); + } + + if (SUCCEEDED(IWbemClassObject_Get(wbemClassObject, L"User", 0, &variant, 0, 0))) + { + entry->UserName = PhCreateString(variant.bstrVal); + VariantClear(&variant); + } + + IWbemClassObject_Release(wbemClassObject); + + if (entry->NamespacePath && entry->ProviderName) + { + PPH_STRING fileName; + + if (SUCCEEDED(PhpQueryWmiProviderFileName(entry->NamespacePath, entry->ProviderName, &fileName))) + { + entry->FileName = fileName; + } + } + + PhAddItemList(providerList, entry); + } + +CleanupExit: + if (queryString) + PhDereferenceObject(queryString); + if (wbemEnumerator) + IEnumWbemClassObject_Release(wbemEnumerator); + if (wbemServices) + IWbemServices_Release(wbemServices); + if (wbemLocator) + IWbemLocator_Release(wbemLocator); + + return providerList; +} + +// HACK: Move to itemtips.c +VOID PhQueryWmiHostProcessString( + _In_ PPH_PROCESS_ITEM ProcessItem, + _Inout_ PPH_STRING_BUILDER Providers + ) +{ + PPH_LIST providerList; + + if (providerList = PhpQueryWmiProviderHostProcess(ProcessItem)) + { + for (ULONG i = 0; i < providerList->Count; i++) + { + PPH_WMI_ENTRY entry = providerList->Items[i]; + + PhAppendFormatStringBuilder( + Providers, + L" %s (%s)\n", + PhGetStringOrEmpty(entry->ProviderName), + PhGetStringOrEmpty(entry->FileName) + ); + + if (entry->NamespacePath) + PhDereferenceObject(entry->NamespacePath); + if (entry->ProviderName) + PhDereferenceObject(entry->ProviderName); + if (entry->FileName) + PhDereferenceObject(entry->FileName); + if (entry->UserName) + PhDereferenceObject(entry->UserName); + + PhFree(entry); + } + + PhDereferenceObject(providerList); + } +} + +static VOID NTAPI PhpWmiProviderUpdateHandler( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + PPH_WMI_CONTEXT context = (PPH_WMI_CONTEXT)Context; + + PostMessage(context->WindowHandle, WM_PH_WMI_UPDATE, 0, 0); +} + +VOID PhpClearWmiProviderItems( + _Inout_ PPH_WMI_CONTEXT Context + ) +{ + ULONG i; + PPH_WMI_ENTRY entry; + + for (i = 0; i < Context->WmiProviderList->Count; i++) + { + entry = Context->WmiProviderList->Items[i]; + + if (entry->NamespacePath) + PhDereferenceObject(entry->NamespacePath); + if (entry->ProviderName) + PhDereferenceObject(entry->ProviderName); + if (entry->FileName) + PhDereferenceObject(entry->FileName); + if (entry->UserName) + PhDereferenceObject(entry->UserName); + + PhFree(entry); + } + + PhClearList(Context->WmiProviderList); +} + +VOID PhpRefreshWmiProviders( + _In_ HWND hwndDlg, + _Inout_ PPH_WMI_CONTEXT Context, + _In_ PPH_PROCESS_ITEM ProcessItem + ) +{ + PVOID selectedIndex; + PPH_LIST providerList; + + ExtendedListView_SetRedraw(Context->ListViewHandle, FALSE); + + selectedIndex = PhGetSelectedListViewItemParam(Context->ListViewHandle); + ListView_DeleteAllItems(Context->ListViewHandle); + PhpClearWmiProviderItems(Context); + + if (providerList = PhpQueryWmiProviderHostProcess(ProcessItem)) + { + for (ULONG i = 0; i < providerList->Count; i++) + { + PPH_WMI_ENTRY entry = providerList->Items[i]; + INT lvItemIndex; + + lvItemIndex = PhAddListViewItem( + Context->ListViewHandle, + MAXINT, + PhGetStringOrEmpty(entry->ProviderName), + UlongToPtr(Context->WmiProviderList->Count + 1) + ); + PhSetListViewSubItem(Context->ListViewHandle, lvItemIndex, 1, PhGetStringOrEmpty(entry->NamespacePath)); + PhSetListViewSubItem(Context->ListViewHandle, lvItemIndex, 2, PhGetStringOrEmpty(entry->FileName)); + PhSetListViewSubItem(Context->ListViewHandle, lvItemIndex, 3, PhGetStringOrEmpty(entry->UserName)); + + PhAddItemList(Context->WmiProviderList, entry); + } + + PhDereferenceObject(providerList); + } + + if (selectedIndex) + { + ListView_SetItemState(Context->ListViewHandle, PtrToUlong(selectedIndex) - 1, + LVIS_FOCUSED | LVIS_SELECTED, LVIS_FOCUSED | LVIS_SELECTED); + ListView_EnsureVisible(Context->ListViewHandle, PtrToUlong(selectedIndex) - 1, FALSE); + } + + ExtendedListView_SetRedraw(Context->ListViewHandle, TRUE); +} + +INT_PTR CALLBACK PhpProcessWmiProvidersDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + LPPROPSHEETPAGE propSheetPage; + PPH_PROCESS_PROPPAGECONTEXT propPageContext; + PPH_PROCESS_ITEM processItem; + PPH_WMI_CONTEXT context; + + if (PhpPropPageDlgProcHeader(hwndDlg, uMsg, lParam, &propSheetPage, &propPageContext, &processItem)) + { + context = (PPH_WMI_CONTEXT)propPageContext->Context; + } + else + { + return FALSE; + } + + switch (uMsg) + { + case WM_INITDIALOG: + { + context = propPageContext->Context = PhAllocate(sizeof(PH_WMI_CONTEXT)); + memset(context, 0, sizeof(PH_WMI_CONTEXT)); + + context->WindowHandle = hwndDlg; + context->ListViewHandle = GetDlgItem(hwndDlg, IDC_LIST); + context->Enabled = TRUE; + context->WmiProviderList = PhCreateList(1); + + PhSetListViewStyle(context->ListViewHandle, FALSE, TRUE); + PhSetControlTheme(context->ListViewHandle, L"explorer"); + PhAddListViewColumn(context->ListViewHandle, 0, 0, 0, LVCFMT_LEFT, 140, L"Provider"); + PhAddListViewColumn(context->ListViewHandle, 1, 1, 1, LVCFMT_LEFT, 180, L"Namespace"); + PhAddListViewColumn(context->ListViewHandle, 2, 2, 2, LVCFMT_LEFT, 260, L"File name"); + PhAddListViewColumn(context->ListViewHandle, 3, 3, 3, LVCFMT_LEFT, 80, L"User"); + PhSetExtendedListView(context->ListViewHandle); + PhLoadListViewColumnsFromSetting(L"WmiProviderListViewColumns", context->ListViewHandle); + + EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); + + PhpRefreshWmiProviders(hwndDlg, context, processItem); + + PhRegisterCallback( + &PhProcessesUpdatedEvent, + PhpWmiProviderUpdateHandler, + context, + &context->ProcessesUpdatedRegistration + ); + } + break; + case WM_DESTROY: + { + PhUnregisterCallback(&PhProcessesUpdatedEvent, &context->ProcessesUpdatedRegistration); + + PhSaveListViewColumnsToSetting(L"WmiProviderListViewColumns", context->ListViewHandle); + + PhpClearWmiProviderItems(context); + PhDereferenceObject(context->WmiProviderList); + + PhFree(context); + + PhpPropPageDlgProcDestroy(hwndDlg); + } + break; + case WM_SHOWWINDOW: + { + if (!propPageContext->LayoutInitialized) + { + PPH_LAYOUT_ITEM dialogItem; + + dialogItem = PhAddPropPageLayoutItem(hwndDlg, hwndDlg, PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL); + PhAddPropPageLayoutItem(hwndDlg, context->ListViewHandle, dialogItem, PH_ANCHOR_ALL); + + PhDoPropPageLayout(hwndDlg); + + propPageContext->LayoutInitialized = TRUE; + } + } + break; + case WM_NOTIFY: + { + LPNMHDR header = (LPNMHDR)lParam; + + switch (header->code) + { + case PSN_SETACTIVE: + context->Enabled = TRUE; + break; + case PSN_KILLACTIVE: + context->Enabled = FALSE; + break; + } + + PhHandleListViewNotifyForCopy(lParam, context->ListViewHandle); + } + break; + case WM_CONTEXTMENU: + { + if ((HWND)wParam == context->ListViewHandle) + { + POINT point; + PVOID index; + PPH_EMENU_ITEM selectedItem; + + point.x = GET_X_LPARAM(lParam); + point.y = GET_Y_LPARAM(lParam); + + if (point.x == -1 && point.y == -1) + PhGetListViewContextMenuPoint((HWND)wParam, &point); + + if (index = PhGetSelectedListViewItemParam(context->ListViewHandle)) + { + PPH_EMENU menu; + + menu = PhCreateEMenu(); + if (PhGetIntegerSetting(L"WmiProviderEnableHiddenMenu")) + { + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, 1, L"Suspend", NULL, NULL), -1); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, 2, L"Resume", NULL, NULL), -1); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, 3, L"Unload", NULL, NULL), -1); + PhInsertEMenuItem(menu, PhCreateEMenuItem(PH_EMENU_SEPARATOR, 0, NULL, NULL, NULL), -1); + } + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, 4, L"Open &file location", NULL, NULL), -1); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, 5, L"&Copy", NULL, NULL), -1); + + selectedItem = PhShowEMenu( + menu, + hwndDlg, + PH_EMENU_SHOW_LEFTRIGHT, + PH_ALIGN_LEFT | PH_ALIGN_TOP, + point.x, + point.y + ); + PhDestroyEMenu(menu); + + if (selectedItem && selectedItem->Id != -1) + { + PPH_WMI_ENTRY entry; + + entry = context->WmiProviderList->Items[PtrToUlong(index) - 1]; + + switch (selectedItem->Id) + { + case 1: + PhpWmiProviderExecMethod(L"Suspend", processItem->ProcessIdString, entry); + break; + case 2: + PhpWmiProviderExecMethod(L"Resume", processItem->ProcessIdString, entry); + break; + case 3: + PhpWmiProviderExecMethod(L"Unload", processItem->ProcessIdString, entry); + break; + case 4: + { + if (!PhIsNullOrEmptyString(entry->FileName) && RtlDoesFileExists_U(entry->FileName->Buffer)) + { + PhShellExploreFile(hwndDlg, entry->FileName->Buffer); + } + } + break; + case 5: + { + PPH_STRING string; + + string = PhFormatString( + L"%s, %s, %s, %s", + PhGetStringOrDefault(entry->ProviderName, L"N/A"), + PhGetStringOrDefault(entry->NamespacePath, L"N/A"), + PhGetStringOrDefault(entry->FileName, L"N/A"), + PhGetStringOrDefault(entry->UserName, L"N/A") + ); + + PhSetClipboardString(hwndDlg, &string->sr); + PhDereferenceObject(string); + + SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)context->ListViewHandle, TRUE); + } + break; + } + } + } + } + } + break; + case WM_PH_WMI_UPDATE: + { + PhpRefreshWmiProviders(hwndDlg, context, processItem); + } + break; + } + + return FALSE; +} diff --git a/ProcessHacker/resource.h b/ProcessHacker/resource.h index 5fe76c517a48..b53551cec92b 100644 --- a/ProcessHacker/resource.h +++ b/ProcessHacker/resource.h @@ -127,6 +127,7 @@ #define IDD_OPTIONS 227 #define IDD_PLUGINPROPERTIES 228 #define IDD_PLUGINSDISABLED 241 +#define IDD_PROCWMIPROVIDERS 242 #define IDC_TERMINATE 1003 #define IDC_FILEICON 1005 #define IDC_FILE 1006 diff --git a/ProcessHacker/settings.c b/ProcessHacker/settings.c index 33fc77524159..dad506a77231 100644 --- a/ProcessHacker/settings.c +++ b/ProcessHacker/settings.c @@ -164,6 +164,8 @@ VOID PhAddDefaultSettings( PhpAddIntegerSetting(L"TokenSplitterPosition", L"150"); PhpAddStringSetting(L"TokenPrivilegesListViewColumns", L""); PhpAddIntegerSetting(L"UpdateInterval", L"3e8"); // 1000ms + PhpAddIntegerSetting(L"WmiProviderEnableHiddenMenu", L"0"); + PhpAddStringSetting(L"WmiProviderListViewColumns", L""); // Colors are specified with R in the lowest byte, then G, then B. So: bbggrr. PhpAddIntegerSetting(L"ColorNew", L"00ff7f"); // Chartreuse From 0ac2199644f5fcf30655d1f6b2ae0fc8ed3c2f0f Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 16 Nov 2017 08:21:43 +1100 Subject: [PATCH 0582/2058] Update process tooltips with Microsoft Edge container names and WMI provider host process information --- ProcessHacker/appsup.c | 63 +++++++++++---- ProcessHacker/include/appsup.h | 10 +++ ProcessHacker/itemtips.c | 136 +++++++++++++++++++++++++++++++-- 3 files changed, 188 insertions(+), 21 deletions(-) diff --git a/ProcessHacker/appsup.c b/ProcessHacker/appsup.c index 5cf37bc85463..dcf264aca322 100644 --- a/ProcessHacker/appsup.c +++ b/ProcessHacker/appsup.c @@ -302,15 +302,9 @@ NTSTATUS PhGetProcessKnownType( ) { NTSTATUS status; - PH_KNOWN_PROCESS_TYPE knownProcessType; PROCESS_BASIC_INFORMATION basicInfo; - PH_STRINGREF systemRootPrefix; PPH_STRING fileName; PPH_STRING newFileName; - PH_STRINGREF name; -#ifdef _WIN64 - BOOLEAN isWow64 = FALSE; -#endif if (!NT_SUCCESS(status = PhGetProcessBasicInformation( ProcessHandle, @@ -324,8 +318,6 @@ NTSTATUS PhGetProcessKnownType( return STATUS_SUCCESS; } - PhGetSystemRoot(&systemRootPrefix); - if (!NT_SUCCESS(status = PhGetProcessImageFileName( ProcessHandle, &fileName @@ -336,7 +328,40 @@ NTSTATUS PhGetProcessKnownType( newFileName = PhGetFileName(fileName); PhDereferenceObject(fileName); - name = newFileName->sr; + + *KnownProcessType = PhGetProcessKnownTypeEx( + basicInfo.UniqueProcessId, + newFileName + ); + + PhDereferenceObject(newFileName); + + return status; +} + +PH_KNOWN_PROCESS_TYPE PhGetProcessKnownTypeEx( + _In_ HANDLE ProcessId, + _In_ PPH_STRING FileName + ) +{ + PH_KNOWN_PROCESS_TYPE knownProcessType; + PH_STRINGREF systemRootPrefix; + PPH_STRING fileName; + PH_STRINGREF name; +#ifdef _WIN64 + BOOLEAN isWow64 = FALSE; +#endif + + if (ProcessId == SYSTEM_PROCESS_ID) + return SystemProcessType; + + if (PhIsNullOrEmptyString(FileName)) + return UnknownProcessType; + + PhGetSystemRoot(&systemRootPrefix); + + fileName = PhDuplicateString(FileName); + name = fileName->sr; knownProcessType = UnknownProcessType; @@ -394,19 +419,31 @@ NTSTATUS PhGetProcessKnownType( knownProcessType = TaskHostProcessType; else if (PhEqualStringRef2(&name, L"\\wudfhost.exe", TRUE)) knownProcessType = UmdfHostProcessType; + else if (PhEqualStringRef2(&name, L"\\wbem\\WmiPrvSE.exe", TRUE)) + knownProcessType = WmiProviderHostType; + } + else + { + // Microsoft Edge + if (PhEndsWithStringRef2(&name, L"\\MicrosoftEdgeCP.exe", TRUE)) + knownProcessType = EdgeProcessType; + else if (PhEndsWithStringRef2(&name, L"\\MicrosoftEdge.exe", TRUE)) + knownProcessType = EdgeProcessType; + else if (PhEndsWithStringRef2(&name, L"\\ServiceWorkerHost.exe", TRUE)) + knownProcessType = EdgeProcessType; + else if (PhEndsWithStringRef2(&name, L"\\Windows.WARP.JITService.exe", TRUE)) + knownProcessType = EdgeProcessType; } } - PhDereferenceObject(newFileName); + PhDereferenceObject(fileName); #ifdef _WIN64 if (isWow64) knownProcessType |= KnownProcessWow64; #endif - *KnownProcessType = knownProcessType; - - return status; + return knownProcessType; } static BOOLEAN NTAPI PhpSvchostCommandLineCallback( diff --git a/ProcessHacker/include/appsup.h b/ProcessHacker/include/appsup.h index 172c4ab55626..fd79e97e2bd3 100644 --- a/ProcessHacker/include/appsup.h +++ b/ProcessHacker/include/appsup.h @@ -48,6 +48,8 @@ typedef enum _PH_KNOWN_PROCESS_TYPE TaskHostProcessType, // taskeng, taskhost, taskhostex ExplorerProcessType, // explorer UmdfHostProcessType, // wudfhost + EdgeProcessType, // Microsoft Edge + WmiProviderHostType, MaximumProcessType, KnownProcessTypeMask = 0xffff, @@ -62,6 +64,14 @@ PhGetProcessKnownType( _Out_ PH_KNOWN_PROCESS_TYPE *KnownProcessType ); +PHAPPAPI +PH_KNOWN_PROCESS_TYPE +NTAPI +PhGetProcessKnownTypeEx( + _In_ HANDLE ProcessId, + _In_ PPH_STRING FileName + ); + typedef union _PH_KNOWN_PROCESS_COMMAND_LINE { struct diff --git a/ProcessHacker/itemtips.c b/ProcessHacker/itemtips.c index b022e2dbb036..6c7e536de13e 100644 --- a/ProcessHacker/itemtips.c +++ b/ProcessHacker/itemtips.c @@ -28,6 +28,7 @@ #include #include +#include #include #include @@ -43,6 +44,22 @@ VOID PhpFillRunningTasks( _Inout_ PPH_STRING_BUILDER Tasks ); +VOID PhpFillMicrosoftEdge( + _In_ PPH_PROCESS_ITEM Process, + _Inout_ PPH_STRING_BUILDER Tasks + ); + +VOID PhpFillWmiProviderHost( + _In_ PPH_PROCESS_ITEM Process, + _Inout_ PPH_STRING_BUILDER Providers + ); + +// HACK +PPH_STRING PhQueryWmiHostProcessString( + _In_ PPH_PROCESS_ITEM ProcessItem, + _Inout_ PPH_STRING_BUILDER Providers + ); + static PH_STRINGREF StandardIndent = PH_STRINGREF_INIT(L" "); VOID PhpAppendStringWithLineBreaks( @@ -101,7 +118,6 @@ PPH_STRING PhGetProcessTooltipText( PH_STRING_BUILDER stringBuilder; ULONG validForMs = 60 * 60 * 1000; // 1 hour PPH_STRING tempString; - PH_KNOWN_PROCESS_TYPE knownProcessType = UnknownProcessType; PhInitializeStringBuilder(&stringBuilder, 200); @@ -140,20 +156,17 @@ PPH_STRING PhGetProcessTooltipText( // Known command line information - if (Process->QueryHandle) - PhGetProcessKnownType(Process->QueryHandle, &knownProcessType); - if (Process->CommandLine && Process->QueryHandle) { PH_KNOWN_PROCESS_COMMAND_LINE knownCommandLine; - if (knownProcessType != UnknownProcessType && PhaGetProcessKnownCommandLine( + if (Process->KnownProcessType != UnknownProcessType && PhaGetProcessKnownCommandLine( Process->CommandLine, - knownProcessType, + Process->KnownProcessType, &knownCommandLine )) { - switch (knownProcessType & KnownProcessTypeMask) + switch (Process->KnownProcessType & KnownProcessTypeMask) { case ServiceHostProcessType: PhAppendStringBuilder2(&stringBuilder, L"Service group name:\n "); @@ -290,7 +303,7 @@ PPH_STRING PhGetProcessTooltipText( } // Tasks, Drivers - switch (knownProcessType & KnownProcessTypeMask) + switch (Process->KnownProcessType & KnownProcessTypeMask) { case TaskHostProcessType: { @@ -328,6 +341,42 @@ PPH_STRING PhGetProcessTooltipText( validForMs = 10 * 1000; // 10 seconds } break; + case EdgeProcessType: + { + PH_STRING_BUILDER container; + + PhInitializeStringBuilder(&container, 40); + + PhpFillMicrosoftEdge(Process, &container); + + if (container.String->Length != 0) + { + PhAppendStringBuilder2(&stringBuilder, L"Edge:\n"); + PhAppendStringBuilder(&stringBuilder, &container.String->sr); + } + + PhDeleteStringBuilder(&container); + } + break; + case WmiProviderHostType: + { + PH_STRING_BUILDER provider; + + PhInitializeStringBuilder(&provider, 40); + + PhpFillWmiProviderHost(Process, &provider); + + if (provider.String->Length != 0) + { + PhAppendStringBuilder2(&stringBuilder, L"WMI Providers:\n"); + PhAppendStringBuilder(&stringBuilder, &provider.String->sr); + } + + PhDeleteStringBuilder(&provider); + + validForMs = 10 * 1000; // 10 seconds + } + break; } // Plugin @@ -636,6 +685,77 @@ VOID PhpFillRunningTasks( } } +VOID PhpFillMicrosoftEdge( + _In_ PPH_PROCESS_ITEM Process, + _Inout_ PPH_STRING_BUILDER Containers + ) +{ + HANDLE tokenHandle; + PTOKEN_APPCONTAINER_INFORMATION appContainerInfo; + PPH_STRING appContainerSid = NULL; + + if (NT_SUCCESS(PhOpenProcessToken( + Process->QueryHandle, + TOKEN_QUERY, + &tokenHandle + ))) + { + if (NT_SUCCESS(PhQueryTokenVariableSize(tokenHandle, TokenAppContainerSid, &appContainerInfo))) + { + if (appContainerInfo->TokenAppContainer) + appContainerSid = PhSidToStringSid(appContainerInfo->TokenAppContainer); + + PhFree(appContainerInfo); + } + } + + if (appContainerSid) + { + static PH_STRINGREF extensionsSid = PH_STRINGREF_INIT(L"S-1-15-2-3624051433-2125758914-1423191267-1740899205-1073925389-3782572162-737981194-1206159417-1570029349-2913729690-1184509225"); + static PH_STRINGREF serviceUiSid = PH_STRINGREF_INIT(L"S-1-15-2-3624051433-2125758914-1423191267-1740899205-1073925389-3782572162-737981194-3513710562-3729412521-1863153555-1462103995"); + static PH_STRINGREF chakraJitSid = PH_STRINGREF_INIT(L"S-1-15-2-3624051433-2125758914-1423191267-1740899205-1073925389-3782572162-737981194-1821068571-1793888307-623627345-1529106238"); + static PH_STRINGREF flashSid = PH_STRINGREF_INIT(L"S-1-15-2-3624051433-2125758914-1423191267-1740899205-1073925389-3782572162-737981194-3859068477-1314311106-1651661491-1685393560"); + static PH_STRINGREF backgroundTabPool1Sid = PH_STRINGREF_INIT(L"S-1-15-2-3624051433-2125758914-1423191267-1740899205-1073925389-3782572162-737981194-4256926629-1688279915-2739229046-3928706915"); + static PH_STRINGREF backgroundTabPool2Sid = PH_STRINGREF_INIT(L"S-1-15-2-3624051433-2125758914-1423191267-1740899205-1073925389-3782572162-737981194-2385269614-3243675-834220592-3047885450"); + static PH_STRINGREF backgroundTabPool3Sid = PH_STRINGREF_INIT(L"S-1-15-2-3624051433-2125758914-1423191267-1740899205-1073925389-3782572162-737981194-355265979-2879959831-980936148-1241729999"); + + if (PhEqualStringRef(&appContainerSid->sr, &extensionsSid, FALSE)) + { + PhAppendStringBuilder2(Containers, L" Browser Extensions\n"); + } + else if (PhEqualStringRef(&appContainerSid->sr, &serviceUiSid, FALSE)) + { + PhAppendStringBuilder2(Containers, L" User Interface Service\n"); + } + else if (PhEqualStringRef(&appContainerSid->sr, &chakraJitSid, FALSE)) + { + PhAppendStringBuilder2(Containers, L" Chakra Jit Compiler\n"); + } + else if (PhEqualStringRef(&appContainerSid->sr, &flashSid, FALSE)) + { + PhAppendStringBuilder2(Containers, L" Adobe Flash Player\n"); + } + else if ( + PhEqualStringRef(&appContainerSid->sr, &backgroundTabPool1Sid, FALSE) || + PhEqualStringRef(&appContainerSid->sr, &backgroundTabPool2Sid, FALSE) || + PhEqualStringRef(&appContainerSid->sr, &backgroundTabPool3Sid, FALSE) + ) + { + PhAppendStringBuilder2(Containers, L" Background Tab Pool\n"); + } + + PhDereferenceObject(appContainerSid); + } +} + +VOID PhpFillWmiProviderHost( + _In_ PPH_PROCESS_ITEM Process, + _Inout_ PPH_STRING_BUILDER Providers + ) +{ + PhQueryWmiHostProcessString(Process, Providers); +} + PPH_STRING PhGetServiceTooltipText( _In_ PPH_SERVICE_ITEM Service ) From 574e8571eab866ccc121cb4460ac27fd4e5d9c2f Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 16 Nov 2017 22:34:47 +1100 Subject: [PATCH 0583/2058] Make JobObjectId column formatting the same as Task Manager --- ProcessHacker/proctree.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ProcessHacker/proctree.c b/ProcessHacker/proctree.c index 0d4e674de3ca..a57c7792c777 100644 --- a/ProcessHacker/proctree.c +++ b/ProcessHacker/proctree.c @@ -3,6 +3,7 @@ * process tree list * * Copyright (C) 2010-2016 wj32 + * Copyright (C) 2016-2017 dmex * * This file is part of Process Hacker. * @@ -2656,7 +2657,11 @@ BOOLEAN NTAPI PhpProcessTreeNewCallback( break; case PHPRTLC_JOBOBJECTID: { - PhpFormatInt32GroupDigits(processItem->JobObjectId, node->JobObjectIdText, sizeof(node->JobObjectIdText), &getCellText->Text); + if (processItem->JobObjectId != 0) + { + PhPrintInt32(node->JobObjectIdText, processItem->JobObjectId); + PhInitializeStringRefLongHint(&getCellText->Text, node->JobObjectIdText); + } } break; default: From 76447c5f2c798d42f64a499157aa8c364eb9c15b Mon Sep 17 00:00:00 2001 From: Matthijs Lavrijsen Date: Thu, 16 Nov 2017 13:11:22 +0100 Subject: [PATCH 0584/2058] Fix some TEB field offsets on 32 bit (#189) --- phnt/include/ntpebteb.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/phnt/include/ntpebteb.h b/phnt/include/ntpebteb.h index 37d4fbb43a55..7114a1bb7bb9 100644 --- a/phnt/include/ntpebteb.h +++ b/phnt/include/ntpebteb.h @@ -202,7 +202,11 @@ typedef struct _TEB LCID CurrentLocale; ULONG FpSoftwareStatusRegister; PVOID ReservedForDebuggerInstrumentation[16]; +#ifdef _WIN64 PVOID SystemReserved1[30]; +#else + PVOID SystemReserved1[26]; +#endif CHAR PlaceholderCompatibilityMode; CHAR PlaceholderReserved[11]; @@ -216,9 +220,15 @@ typedef struct _TEB ULONG_PTR InstrumentationCallbackSp; ULONG_PTR InstrumentationCallbackPreviousPc; ULONG_PTR InstrumentationCallbackPreviousSp; +#ifdef _WIN64 ULONG TxFsContext; +#endif BOOLEAN InstrumentationCallbackDisabled; +#ifndef _WIN64 + UCHAR SpareBytes[23]; + ULONG TxFsContext; +#endif GDI_TEB_BATCH GdiTebBatch; CLIENT_ID RealClientId; HANDLE GdiCachedProcessHandle; From 6674e5254773bfa1b342bbfac732be5170ad4048 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 17 Nov 2017 01:06:24 +1100 Subject: [PATCH 0585/2058] Improve service description query performance, Fix service state highlighting, Fix showing username for driver services --- ProcessHacker/srvlist.c | 69 ++++++++++++++++++++++++++++++++++++++--- ProcessHacker/srvprp.c | 15 +++++++++ 2 files changed, 79 insertions(+), 5 deletions(-) diff --git a/ProcessHacker/srvlist.c b/ProcessHacker/srvlist.c index e04ff39f66f8..c1ee3fd12dfe 100644 --- a/ProcessHacker/srvlist.c +++ b/ProcessHacker/srvlist.c @@ -3,6 +3,7 @@ * service list * * Copyright (C) 2010-2015 wj32 + * Copyright (C) 2017 dmex * * This file is part of Process Hacker. * @@ -371,17 +372,75 @@ static VOID PhpUpdateServiceNodeDescription( { if (!(ServiceNode->ValidMask & PHSN_DESCRIPTION)) { - SC_HANDLE serviceHandle; + static PH_STRINGREF servicesKeyName = PH_STRINGREF_INIT(L"System\\CurrentControlSet\\Services\\"); + HANDLE keyHandle; + PPH_STRING keyName; - if (serviceHandle = PhOpenService(ServiceNode->ServiceItem->Name->Buffer, SERVICE_QUERY_CONFIG)) + keyName = PhConcatStringRef2(&servicesKeyName, &ServiceNode->ServiceItem->Name->sr); + + if (NT_SUCCESS(PhOpenKey( + &keyHandle, + KEY_QUERY_VALUE, + PH_KEY_LOCAL_MACHINE, + &keyName->sr, + 0 + ))) { - PhMoveReference(&ServiceNode->Description, PhGetServiceDescription(serviceHandle)); + LSTATUS result; + PWSTR buffer; + ULONG bufferSize; + ULONG returnLength = 0; + + bufferSize = 0x100; + buffer = PhAllocate(bufferSize); + + if ((result = RegLoadMUIString( + keyHandle, + L"Description", + buffer, + bufferSize, + &returnLength, + 0, + NULL + )) == ERROR_MORE_DATA) + { + PhFree(buffer); + bufferSize = returnLength; + buffer = PhAllocate(bufferSize); + + result = RegLoadMUIString( + keyHandle, + L"Description", + buffer, + bufferSize, + &returnLength, + 0, + NULL + ); + } - CloseServiceHandle(serviceHandle); + if (result == ERROR_SUCCESS) + { + PhMoveReference(&ServiceNode->Description, PhCreateStringEx(buffer, returnLength)); + } + + PhFree(buffer); + NtClose(keyHandle); } + PhDereferenceObject(keyName); + ServiceNode->ValidMask |= PHSN_DESCRIPTION; } + + // NOTE: Querying the service description via RPC is extremely slow. + //SC_HANDLE serviceHandle; + // + //if (serviceHandle = PhOpenService(ServiceNode->ServiceItem->Name->Buffer, SERVICE_QUERY_CONFIG)) + //{ + // PhMoveReference(&ServiceNode->Description, PhGetServiceDescription(serviceHandle)); + // CloseServiceHandle(serviceHandle); + //} } static VOID PhpUpdateServiceNodeKey( @@ -758,7 +817,7 @@ BOOLEAN NTAPI PhpServiceTreeNewCallback( getNodeColor->Flags = TN_AUTO_FORECOLOR; getNodeColor->BackColor = PhCsColorUnknown; } - else if (PhCsUseColorServiceStop && serviceItem->State == SERVICE_STOPPED) + else if (PhCsUseColorServiceStop && serviceItem->StartType == SERVICE_DISABLED) { getNodeColor->ForeColor = PhCsColorServiceStop; } diff --git a/ProcessHacker/srvprp.c b/ProcessHacker/srvprp.c index 0aab0620ecae..c3edcfdb001f 100644 --- a/ProcessHacker/srvprp.c +++ b/ProcessHacker/srvprp.c @@ -184,6 +184,21 @@ static VOID PhpRefreshControls( { EnableWindow(GetDlgItem(hwndDlg, IDC_DELAYEDSTART), FALSE); } + + if (PhEqualString2(PhaGetDlgItemText(hwndDlg, IDC_TYPE), L"Driver", FALSE)) + { + EnableWindow(GetDlgItem(hwndDlg, IDC_USERACCOUNT), FALSE); + EnableWindow(GetDlgItem(hwndDlg, IDC_PASSWORD), FALSE); + EnableWindow(GetDlgItem(hwndDlg, IDC_PASSWORDCHECK), FALSE); + EnableWindow(GetDlgItem(hwndDlg, IDC_SERVICEDLL), FALSE); + } + else + { + EnableWindow(GetDlgItem(hwndDlg, IDC_DELAYEDSTART), TRUE); + EnableWindow(GetDlgItem(hwndDlg, IDC_PASSWORD), TRUE); + EnableWindow(GetDlgItem(hwndDlg, IDC_PASSWORDCHECK), TRUE); + EnableWindow(GetDlgItem(hwndDlg, IDC_SERVICEDLL), TRUE); + } } INT_PTR CALLBACK PhpServiceGeneralDlgProc( From 2e645e3b1814a8e54664ce400cebfd4720bf1cf2 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 17 Nov 2017 01:08:04 +1100 Subject: [PATCH 0586/2058] peview: Query name for 'unnamed' DLL exports from symbols --- tools/peview/expprp.c | 39 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/tools/peview/expprp.c b/tools/peview/expprp.c index 9e50ec4e491e..1b521fb12754 100644 --- a/tools/peview/expprp.c +++ b/tools/peview/expprp.c @@ -110,7 +110,44 @@ INT_PTR CALLBACK PvpPeExportsDlgProc( } else { - PhSetListViewSubItem(lvHandle, lvItemIndex, 2, L"(unnamed)"); + if (exportFunction.Function) + { + PPH_STRING exportName; + + // Try find the export name using symbols. + exportName = PhGetSymbolFromAddress( + PvSymbolProvider, + (ULONG64)PTR_ADD_OFFSET(PvMappedImage.NtHeaders->OptionalHeader.ImageBase, exportFunction.Function), + NULL, + NULL, + NULL, + NULL + ); + + if (exportName) + { + static PH_STRINGREF unnamedText = PH_STRINGREF_INIT(L" (unnamed)"); + PH_STRINGREF exportNameText; + PH_STRINGREF firstPart; + PH_STRINGREF secondPart; + + if (PhSplitStringRefAtLastChar(&exportName->sr, L'!', &firstPart, &secondPart)) + exportNameText = secondPart; + else + exportNameText = exportName->sr; + + PhSetListViewSubItem(lvHandle, lvItemIndex, 2, PH_AUTO_T(PH_STRING, PhConcatStringRef2(&exportNameText, &unnamedText))->Buffer); + PhDereferenceObject(exportName); + } + else + { + PhSetListViewSubItem(lvHandle, lvItemIndex, 2, L"(unnamed)"); + } + } + else + { + PhSetListViewSubItem(lvHandle, lvItemIndex, 2, L"(unnamed)"); + } } PhPrintUInt32(number, exportEntry.Ordinal); From 02973e2d6212abec1f22bed8ac1994e848f2f795 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 17 Nov 2017 11:01:58 +1100 Subject: [PATCH 0587/2058] Tidy up code --- ProcessHacker/procprv.c | 4 +- ProcessHacker/prpgenv.c | 14 +++--- ProcessHacker/searchbox.c | 8 +--- ProcessHacker/tokprp.c | 5 +- phlib/graph.c | 5 +- phlib/hexedit.c | 11 +++-- phlib/lsasup.c | 2 +- phlib/native.c | 2 +- plugins/ToolStatus/ToolStatus.vcxproj | 1 - plugins/ToolStatus/ToolStatus.vcxproj.filters | 3 -- plugins/ToolStatus/searchbox.c | 48 ------------------- plugins/ToolStatus/toolbar.c | 21 ++++++-- tools/peview/searchbox.c | 8 +--- 13 files changed, 42 insertions(+), 90 deletions(-) delete mode 100644 plugins/ToolStatus/searchbox.c diff --git a/ProcessHacker/procprv.c b/ProcessHacker/procprv.c index c7033fd3c584..55d048fdd1ab 100644 --- a/ProcessHacker/procprv.c +++ b/ProcessHacker/procprv.c @@ -2903,8 +2903,8 @@ PPH_PROCESS_ITEM PhReferenceProcessItemForParent( if (WindowsVersion >= WINDOWS_10_RS3) { - // We make sure that the process item we found is actually the parent process - its start time - // must not be larger than the supplied time. + // We make sure that the process item we found is actually the parent process - its sequence number + // must not be higher than the supplied sequence. if (parentProcessItem && parentProcessItem->ProcessSequenceNumber <= ProcessItem->ProcessSequenceNumber) PhReferenceObject(parentProcessItem); else diff --git a/ProcessHacker/prpgenv.c b/ProcessHacker/prpgenv.c index cb16b9606a21..d81c73a68264 100644 --- a/ProcessHacker/prpgenv.c +++ b/ProcessHacker/prpgenv.c @@ -27,6 +27,7 @@ #include #include #include + #include #include @@ -165,8 +166,7 @@ INT_PTR CALLBACK PhpProcessEnvironmentDlgProc( PPH_ENVIRONMENT_CONTEXT environmentContext; HWND lvHandle; - if (PhpPropPageDlgProcHeader(hwndDlg, uMsg, lParam, - &propSheetPage, &propPageContext, &processItem)) + if (PhpPropPageDlgProcHeader(hwndDlg, uMsg, lParam, &propSheetPage, &propPageContext, &processItem)) { environmentContext = propPageContext->Context; @@ -184,8 +184,8 @@ INT_PTR CALLBACK PhpProcessEnvironmentDlgProc( { environmentContext = propPageContext->Context = PhAllocate(sizeof(PH_ENVIRONMENT_CONTEXT)); memset(environmentContext, 0, sizeof(PH_ENVIRONMENT_CONTEXT)); - lvHandle = GetDlgItem(hwndDlg, IDC_LIST); - environmentContext->ListViewHandle = lvHandle; + + environmentContext->ListViewHandle = lvHandle = GetDlgItem(hwndDlg, IDC_LIST); PhInitializeArray(&environmentContext->Items, sizeof(PH_ENVIRONMENT_ITEM), 100); PhSetListViewStyle(lvHandle, TRUE, TRUE); @@ -206,7 +206,7 @@ INT_PTR CALLBACK PhpProcessEnvironmentDlgProc( break; case WM_DESTROY: { - PhSaveListViewColumnsToSetting(L"EnvironmentListViewColumns", GetDlgItem(hwndDlg, IDC_LIST)); + PhSaveListViewColumnsToSetting(L"EnvironmentListViewColumns", lvHandle); PhpClearEnvironmentItems(environmentContext); PhDeleteArray(&environmentContext->Items); @@ -382,8 +382,8 @@ INT_PTR CALLBACK PhpProcessEnvironmentDlgProc( PVOID *indices; ULONG numberOfIndices; - point.x = (SHORT)LOWORD(lParam); - point.y = (SHORT)HIWORD(lParam); + point.x = GET_X_LPARAM(lParam); + point.y = GET_Y_LPARAM(lParam); if (point.x == -1 && point.y == -1) PhGetListViewContextMenuPoint((HWND)wParam, &point); diff --git a/ProcessHacker/searchbox.c b/ProcessHacker/searchbox.c index 6fd37ed6c719..b6ec86880b23 100644 --- a/ProcessHacker/searchbox.c +++ b/ProcessHacker/searchbox.c @@ -254,9 +254,7 @@ LRESULT CALLBACK PhpSearchWndSubclassProc( _In_ ULONG_PTR dwRefData ) { - PEDIT_CONTEXT context; - - context = (PEDIT_CONTEXT)GetProp(hWnd, L"SearchBoxContext"); + PEDIT_CONTEXT context = (PEDIT_CONTEXT)dwRefData; switch (uMsg) { @@ -268,7 +266,6 @@ LRESULT CALLBACK PhpSearchWndSubclassProc( DeleteObject(context->WindowFont); RemoveWindowSubclass(hWnd, PhpSearchWndSubclassProc, uIdSubclass); - RemoveProp(hWnd, L"SearchBoxContext"); PhFree(context); } break; @@ -531,9 +528,6 @@ VOID PhCreateSearchControl( if (BannerText) Edit_SetCueBannerText(context->WindowHandle, BannerText); - // Set our window context data. - SetProp(context->WindowHandle, L"SearchBoxContext", (HANDLE)context); - // Subclass the Edit control window procedure. SetWindowSubclass(context->WindowHandle, PhpSearchWndSubclassProc, 0, (ULONG_PTR)context); diff --git a/ProcessHacker/tokprp.c b/ProcessHacker/tokprp.c index ec8401daba6a..3e6596d6b7f4 100644 --- a/ProcessHacker/tokprp.c +++ b/ProcessHacker/tokprp.c @@ -29,6 +29,7 @@ #include #include +#include #include typedef struct _ATTRIBUTE_NODE @@ -947,8 +948,8 @@ INT_PTR CALLBACK PhpTokenPageProc( { POINT point; - point.x = (SHORT)LOWORD(lParam); - point.y = (SHORT)HIWORD(lParam); + point.x = GET_X_LPARAM(lParam); + point.y = GET_Y_LPARAM(lParam); if (point.x == -1 && point.y == -1) PhGetListViewContextMenuPoint((HWND)wParam, &point); diff --git a/phlib/graph.c b/phlib/graph.c index b74eeab067c1..6bcc69ab67aa 100644 --- a/phlib/graph.c +++ b/phlib/graph.c @@ -22,6 +22,7 @@ #include +#include #include #include @@ -1129,8 +1130,8 @@ LRESULT CALLBACK PhpGraphWndProc( mouseEvent.Header.code = GCN_MOUSEEVENT; mouseEvent.Message = uMsg; mouseEvent.Keys = (ULONG)wParam; - mouseEvent.Point.x = LOWORD(lParam); - mouseEvent.Point.y = HIWORD(lParam); + mouseEvent.Point.x = GET_X_LPARAM(lParam); + mouseEvent.Point.y = GET_Y_LPARAM(lParam); mouseEvent.Index = (clientRect.right - mouseEvent.Point.x - 1) / context->DrawInfo.Step; mouseEvent.TotalCount = context->DrawInfo.LineDataCount; diff --git a/phlib/hexedit.c b/phlib/hexedit.c index 909e020d8c55..5fce14a1c383 100644 --- a/phlib/hexedit.c +++ b/phlib/hexedit.c @@ -23,11 +23,12 @@ #include #include - #include #include +#include + // Code originally from http://www.codeguru.com/Cpp/controls/editctrl/article.php/c539 BOOLEAN PhHexEditInitialization( @@ -300,8 +301,8 @@ LRESULT CALLBACK PhpHexEditWndProc( ULONG flags = (ULONG)wParam; POINT cursorPos; - cursorPos.x = (LONG)(SHORT)LOWORD(lParam); - cursorPos.y = (LONG)(SHORT)HIWORD(lParam); + cursorPos.x = GET_X_LPARAM(lParam); + cursorPos.y = GET_Y_LPARAM(lParam); SetFocus(hwnd); @@ -379,8 +380,8 @@ LRESULT CALLBACK PhpHexEditWndProc( ULONG flags = (ULONG)wParam; POINT cursorPos; - cursorPos.x = (LONG)(SHORT)LOWORD(lParam); - cursorPos.y = (LONG)(SHORT)HIWORD(lParam); + cursorPos.x = GET_X_LPARAM(lParam); + cursorPos.y = GET_Y_LPARAM(lParam); if ( context->Data && diff --git a/phlib/lsasup.c b/phlib/lsasup.c index b4ea741e4cea..d526ca2ffc67 100644 --- a/phlib/lsasup.c +++ b/phlib/lsasup.c @@ -461,7 +461,7 @@ PPH_STRING PhSidToStringSid( PPH_STRING string; UNICODE_STRING us; - string = PhCreateStringEx(NULL, MAX_UNICODE_STACK_BUFFER_LENGTH * sizeof(WCHAR)); + string = PhCreateStringEx(NULL, SECURITY_MAX_SID_STRING_CHARACTERS * sizeof(WCHAR)); PhStringRefToUnicodeString(&string->sr, &us); if (NT_SUCCESS(RtlConvertSidToUnicodeString( diff --git a/phlib/native.c b/phlib/native.c index a1dbfb769808..1ffe2d2a675b 100644 --- a/phlib/native.c +++ b/phlib/native.c @@ -5705,7 +5705,7 @@ VOID PhpInitializePredefineKeys( HANDLE tokenHandle; PTOKEN_USER tokenUser; UNICODE_STRING stringSid; - WCHAR stringSidBuffer[MAX_UNICODE_STACK_BUFFER_LENGTH]; + WCHAR stringSidBuffer[SECURITY_MAX_SID_STRING_CHARACTERS]; PUNICODE_STRING currentUserKeyName; // Get the string SID of the current user. diff --git a/plugins/ToolStatus/ToolStatus.vcxproj b/plugins/ToolStatus/ToolStatus.vcxproj index 2931e6480717..17a8c126440c 100644 --- a/plugins/ToolStatus/ToolStatus.vcxproj +++ b/plugins/ToolStatus/ToolStatus.vcxproj @@ -78,7 +78,6 @@ - diff --git a/plugins/ToolStatus/ToolStatus.vcxproj.filters b/plugins/ToolStatus/ToolStatus.vcxproj.filters index 6d32c767dcd8..ed6e324e7fcc 100644 --- a/plugins/ToolStatus/ToolStatus.vcxproj.filters +++ b/plugins/ToolStatus/ToolStatus.vcxproj.filters @@ -45,9 +45,6 @@ Source Files - - Source Files - diff --git a/plugins/ToolStatus/searchbox.c b/plugins/ToolStatus/searchbox.c deleted file mode 100644 index 1c62529daddf..000000000000 --- a/plugins/ToolStatus/searchbox.c +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Process Hacker - - * Search control stub - * - * Copyright (C) 2016 dmex - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - * - */ - -#include "toolstatus.h" -#include "commonutil.h" - -BOOLEAN CreateSearchboxControl( - VOID - ) -{ - if (SearchboxHandle = CreateWindowEx( - WS_EX_CLIENTEDGE, - WC_EDIT, - NULL, - WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | ES_LEFT | ES_AUTOHSCROLL | WS_VISIBLE, - CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, - RebarHandle, - NULL, - NULL, - NULL - )) - { - PhCreateSearchControl(RebarHandle, SearchboxHandle, L"Search Processes (Ctrl+K)"); - return TRUE; - } - - return FALSE; -} \ No newline at end of file diff --git a/plugins/ToolStatus/toolbar.c b/plugins/ToolStatus/toolbar.c index 838032616bbc..10c86c351482 100644 --- a/plugins/ToolStatus/toolbar.c +++ b/plugins/ToolStatus/toolbar.c @@ -161,11 +161,24 @@ VOID RebarLoadSettings( if (ToolStatusConfig.SearchBoxEnabled && !SearchboxHandle) { SearchboxText = PhReferenceEmptyString(); - ProcessTreeFilterEntry = PhAddTreeNewFilter(PhGetFilterSupportProcessTreeList(), (PPH_TN_FILTER_FUNCTION)ProcessTreeFilterCallback, NULL); - ServiceTreeFilterEntry = PhAddTreeNewFilter(PhGetFilterSupportServiceTreeList(), (PPH_TN_FILTER_FUNCTION)ServiceTreeFilterCallback, NULL); - NetworkTreeFilterEntry = PhAddTreeNewFilter(PhGetFilterSupportNetworkTreeList(), (PPH_TN_FILTER_FUNCTION)NetworkTreeFilterCallback, NULL); + ProcessTreeFilterEntry = PhAddTreeNewFilter(PhGetFilterSupportProcessTreeList(), ProcessTreeFilterCallback, NULL); + ServiceTreeFilterEntry = PhAddTreeNewFilter(PhGetFilterSupportServiceTreeList(), ServiceTreeFilterCallback, NULL); + NetworkTreeFilterEntry = PhAddTreeNewFilter(PhGetFilterSupportNetworkTreeList(), NetworkTreeFilterCallback, NULL); - CreateSearchboxControl(); + if (SearchboxHandle = CreateWindowEx( + WS_EX_CLIENTEDGE, + WC_EDIT, + NULL, + WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | ES_LEFT | ES_AUTOHSCROLL | WS_VISIBLE, + CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, + RebarHandle, + NULL, + NULL, + NULL + )) + { + PhCreateSearchControl(RebarHandle, SearchboxHandle, L"Search Processes (Ctrl+K)"); + } } if (ToolStatusConfig.StatusBarEnabled && !StatusBarHandle) diff --git a/tools/peview/searchbox.c b/tools/peview/searchbox.c index 1d51bf7c061b..c3e78f5ba471 100644 --- a/tools/peview/searchbox.c +++ b/tools/peview/searchbox.c @@ -429,9 +429,7 @@ LRESULT CALLBACK PhpSearchWndSubclassProc( _In_ ULONG_PTR dwRefData ) { - PEDIT_CONTEXT context; - - context = (PEDIT_CONTEXT)GetProp(hWnd, L"SearchBoxContext"); + PEDIT_CONTEXT context = (PEDIT_CONTEXT)dwRefData; switch (uMsg) { @@ -443,7 +441,6 @@ LRESULT CALLBACK PhpSearchWndSubclassProc( DeleteObject(context->WindowFont); RemoveWindowSubclass(hWnd, PhpSearchWndSubclassProc, uIdSubclass); - RemoveProp(hWnd, L"SearchBoxContext"); PhFree(context); } break; @@ -705,9 +702,6 @@ VOID PvCreateSearchControl( if (BannerText) Edit_SetCueBannerText(context->WindowHandle, BannerText); - // Set our window context data. - SetProp(context->WindowHandle, L"SearchBoxContext", (HANDLE)context); - // Subclass the Edit control window procedure. SetWindowSubclass(context->WindowHandle, PhpSearchWndSubclassProc, 0, (ULONG_PTR)context); From d9f733bf6ff50380d09c6399d2e57f9448e1256a Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 18 Nov 2017 13:51:55 +1100 Subject: [PATCH 0588/2058] Fix WinVerifyTrust flags, Reuse existing file handle for catalog verification --- phlib/verify.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/phlib/verify.c b/phlib/verify.c index 1118bc495bf8..72e0213787cc 100644 --- a/phlib/verify.c +++ b/phlib/verify.c @@ -189,7 +189,6 @@ VOID PhpViewSignerInfo( VERIFY_RESULT PhpVerifyFile( _In_ PPH_VERIFY_FILE_INFO Information, - _In_ HANDLE FileHandle, _In_ ULONG UnionChoice, _In_ PVOID UnionData, _In_ PGUID ActionId, @@ -220,7 +219,7 @@ VERIFY_RESULT PhpVerifyFile( trustData.dwProvFlags |= WTD_CACHE_ONLY_URL_RETRIEVAL; } - status = WinVerifyTrust_I(NULL, ActionId, &trustData); + status = WinVerifyTrust_I(INVALID_HANDLE_VALUE, ActionId, &trustData); PhpGetSignaturesFromStateData(trustData.hWVTStateData, Signatures, NumberOfSignatures); if (status == 0 && (Information->Flags & PH_VERIFY_VIEW_PROPERTIES)) @@ -228,7 +227,7 @@ VERIFY_RESULT PhpVerifyFile( // Close the state data. trustData.dwStateAction = WTD_STATEACTION_CLOSE; - WinVerifyTrust_I(NULL, ActionId, &trustData); + WinVerifyTrust_I(INVALID_HANDLE_VALUE, ActionId, &trustData); return PhpStatusToVerifyResult(status); } @@ -365,11 +364,12 @@ VERIFY_RESULT PhpVerifyFileFromCatalog( catalogInfo.cbStruct = sizeof(catalogInfo); catalogInfo.pcwszCatalogFilePath = ci.wszCatalogFile; catalogInfo.pcwszMemberFilePath = Information->FileName; + catalogInfo.hMemberFile = FileHandle; catalogInfo.pcwszMemberTag = fileHashTag->Buffer; catalogInfo.pbCalculatedFileHash = fileHash; catalogInfo.cbCalculatedFileHash = fileHashLength; catalogInfo.hCatAdmin = catAdminHandle; - verifyResult = PhpVerifyFile(Information, FileHandle, WTD_CHOICE_CATALOG, &catalogInfo, &DriverActionVerify, &verInfo, &signatures, &numberOfSignatures); + verifyResult = PhpVerifyFile(Information, WTD_CHOICE_CATALOG, &catalogInfo, &DriverActionVerify, &verInfo, &signatures, &numberOfSignatures); if (verInfo.pcSignerCertContext) CertFreeCertificateContext_I(verInfo.pcSignerCertContext); @@ -388,11 +388,12 @@ VERIFY_RESULT PhpVerifyFileFromCatalog( catalogInfo.cbStruct = sizeof(catalogInfo); catalogInfo.pcwszCatalogFilePath = Information->CatalogFileNames[i]; catalogInfo.pcwszMemberFilePath = Information->FileName; + catalogInfo.hMemberFile = FileHandle; catalogInfo.pcwszMemberTag = fileHashTag->Buffer; catalogInfo.pbCalculatedFileHash = fileHash; catalogInfo.cbCalculatedFileHash = fileHashLength; catalogInfo.hCatAdmin = catAdminHandle; - verifyResult = PhpVerifyFile(Information, FileHandle, WTD_CHOICE_CATALOG, &catalogInfo, &WinTrustActionGenericVerifyV2, NULL, &signatures, &numberOfSignatures); + verifyResult = PhpVerifyFile(Information, WTD_CHOICE_CATALOG, &catalogInfo, &WinTrustActionGenericVerifyV2, NULL, &signatures, &numberOfSignatures); if (verifyResult == VrTrusted) break; @@ -451,7 +452,7 @@ NTSTATUS PhVerifyFileEx( &fileHandle, Information->FileName, FILE_GENERIC_READ, - 0, + FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_DELETE, FILE_OPEN, FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT @@ -462,7 +463,7 @@ NTSTATUS PhVerifyFileEx( fileInfo.pcwszFilePath = Information->FileName; fileInfo.hFile = fileHandle; - verifyResult = PhpVerifyFile(Information, fileHandle, WTD_CHOICE_FILE, &fileInfo, &WinTrustActionGenericVerifyV2, NULL, &signatures, &numberOfSignatures); + verifyResult = PhpVerifyFile(Information, WTD_CHOICE_FILE, &fileInfo, &WinTrustActionGenericVerifyV2, NULL, &signatures, &numberOfSignatures); if (verifyResult == VrNoSignature) { From f3442d7b54a34dd0dbb424b0278a487b4e2e91e7 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 18 Nov 2017 14:11:00 +1100 Subject: [PATCH 0589/2058] Remove extra handle from process provider --- ProcessHacker/procprv.c | 65 +++++++++++++++++++---------------------- 1 file changed, 30 insertions(+), 35 deletions(-) diff --git a/ProcessHacker/procprv.c b/ProcessHacker/procprv.c index 55d048fdd1ab..5307bdfdd948 100644 --- a/ProcessHacker/procprv.c +++ b/ProcessHacker/procprv.c @@ -1154,8 +1154,14 @@ VOID PhpProcessQueryStage1( PhGetProcessConsoleHostProcessId(processHandleLimited, &Data->ConsoleHostProcessId); } + // Immersive + if (processHandleLimited && IsImmersiveProcess_I) + { + processItem->IsImmersive = !!IsImmersiveProcess_I(processHandleLimited); + } + // Package full name - if (processHandleLimited && WINDOWS_HAS_IMMERSIVE) + if (processHandleLimited && WINDOWS_HAS_IMMERSIVE && processItem->IsImmersive) { Data->PackageFullName = PhGetProcessPackageFullName(processHandleLimited); } @@ -1337,9 +1343,6 @@ VOID PhpFillProcessItem( _In_ PSYSTEM_PROCESS_INFORMATION Process ) { - NTSTATUS status; - HANDLE processHandle = NULL; - ProcessItem->ParentProcessId = Process->InheritedFromUniqueProcessId; ProcessItem->SessionId = Process->SessionId; ProcessItem->CreateTime = Process->CreateTime; @@ -1352,7 +1355,13 @@ VOID PhpFillProcessItem( PhPrintUInt32(ProcessItem->ParentProcessIdString, HandleToUlong(ProcessItem->ParentProcessId)); PhPrintUInt32(ProcessItem->SessionIdString, ProcessItem->SessionId); - PhOpenProcess(&processHandle, ProcessQueryAccess, ProcessItem->ProcessId); + // Open a handle to the process for later usage. + { + PhOpenProcess(&ProcessItem->QueryHandle, PROCESS_QUERY_INFORMATION, ProcessItem->ProcessId); + + if (!ProcessItem->QueryHandle) + PhOpenProcess(&ProcessItem->QueryHandle, PROCESS_QUERY_LIMITED_INFORMATION, ProcessItem->ProcessId); + } // Process information { @@ -1363,9 +1372,9 @@ VOID PhpFillProcessItem( { PPH_STRING fileName; - if (processHandle) + if (ProcessItem->QueryHandle) { - PhGetProcessImageFileNameWin32(processHandle, &ProcessItem->FileName); + PhGetProcessImageFileNameWin32(ProcessItem->QueryHandle, &ProcessItem->FileName); } else { @@ -1392,27 +1401,20 @@ VOID PhpFillProcessItem( // Token-related information if ( - processHandle && + ProcessItem->QueryHandle && ProcessItem->ProcessId != SYSTEM_PROCESS_ID // Token of System process can't be opened sometimes ) { HANDLE tokenHandle; - status = PhOpenProcessToken(processHandle, TOKEN_QUERY, &tokenHandle); - - if (NT_SUCCESS(status)) + if (NT_SUCCESS(PhOpenProcessToken(ProcessItem->QueryHandle, TOKEN_QUERY, &tokenHandle))) { - // User name - { - PTOKEN_USER user; + PTOKEN_USER user; - status = PhGetTokenUser(tokenHandle, &user); - - if (NT_SUCCESS(status)) - { - ProcessItem->UserName = PhpGetSidFullNameCached(user->User.Sid); - PhFree(user); - } + if (NT_SUCCESS(PhGetTokenUser(tokenHandle, &user))) + { + ProcessItem->UserName = PhpGetSidFullNameCached(user->User.Sid); + PhFree(user); } NtClose(tokenHandle); @@ -1437,7 +1439,13 @@ VOID PhpFillProcessItem( ); } - NtClose(processHandle); + // On Windows 8.1 and above, processes without threads are reflected processes + // which will not terminate if we have a handle open. + if (Process->NumberOfThreads == 0) + { + NtClose(ProcessItem->QueryHandle); + ProcessItem->QueryHandle = NULL; + } } FORCEINLINE VOID PhpUpdateDynamicInfoProcessItem( @@ -2193,19 +2201,6 @@ VOID PhProcessProviderUpdate( PhpAddProcessRecord(processRecord); processItem->Record = processRecord; - // Open a handle to the process for later usage. - // - // Don't try to do this if the process has no threads. On Windows 8.1, processes without - // threads are probably reflected processes which will not terminate if we have a handle - // open. - if (process->NumberOfThreads != 0) - { - PhOpenProcess(&processItem->QueryHandle, PROCESS_QUERY_INFORMATION, processItem->ProcessId); - - if (!processItem->QueryHandle) - PhOpenProcess(&processItem->QueryHandle, PROCESS_QUERY_LIMITED_INFORMATION, processItem->ProcessId); - } - PhpGetProcessThreadInformation(process, &isSuspended, &isPartiallySuspended, &contextSwitches); PhpUpdateDynamicInfoProcessItem(processItem, process); From 06189bbebce366c870332b192848f0da7ea4fe70 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 22 Nov 2017 13:43:12 +1100 Subject: [PATCH 0590/2058] Update ntrtl.h types --- phnt/include/ntrtl.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/phnt/include/ntrtl.h b/phnt/include/ntrtl.h index 0cfd67a428d1..4d505b1f7602 100644 --- a/phnt/include/ntrtl.h +++ b/phnt/include/ntrtl.h @@ -4562,6 +4562,12 @@ typedef struct _RTL_BITMAP PULONG Buffer; } RTL_BITMAP, *PRTL_BITMAP; +typedef struct _RTL_BITMAP_EX +{ + ULONG64 SizeOfBitMap; + PULONG64 Buffer; +} RTL_BITMAP_EX, *PRTL_BITMAP_EX; + NTSYSAPI VOID NTAPI From bc7a9a29c903822cc7c7c95c7be045a124372a2d Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 23 Nov 2017 07:24:36 +1100 Subject: [PATCH 0591/2058] peview: Fix symbol path --- tools/peview/peprp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/peview/peprp.c b/tools/peview/peprp.c index bce767f5c460..2e91afed8563 100644 --- a/tools/peview/peprp.c +++ b/tools/peview/peprp.c @@ -726,11 +726,11 @@ BOOLEAN PvpLoadDbgHelp( // Load symbol path from _NT_SYMBOL_PATH if configured by the user. if (NT_SUCCESS(RtlQueryEnvironmentVariable_U(NULL, &symbolPathVarName, &symbolPathUs))) { - symbolSearchPath = PhFormatString(L"SRV*%s*http://msdl.microsoft.com/download/symbols", symbolPathUs.Buffer); + symbolSearchPath = PhCreateStringFromUnicodeString(&symbolPathUs); } else { - symbolSearchPath = PhCreateString(L"SRV**http://msdl.microsoft.com/download/symbols"); + symbolSearchPath = PhCreateString(L"SRV*C:\\Symbols*http://msdl.microsoft.com/download/symbols"); } PhSetSearchPathSymbolProvider(symbolProvider, symbolSearchPath->Buffer); From 5818ba54e074d1d51ed1ac1aec557b43ca0a1712 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 23 Nov 2017 07:33:40 +1100 Subject: [PATCH 0592/2058] Fix #193 --- ProcessHacker/procprv.c | 50 ++++++++++++++++++++--------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/ProcessHacker/procprv.c b/ProcessHacker/procprv.c index 5307bdfdd948..7adacbcb2237 100644 --- a/ProcessHacker/procprv.c +++ b/ProcessHacker/procprv.c @@ -201,8 +201,8 @@ ULONG PhTotalProcesses; ULONG PhTotalThreads; ULONG PhTotalHandles; -SYSTEM_PROCESS_INFORMATION PhDpcsProcessInformation; -SYSTEM_PROCESS_INFORMATION PhInterruptsProcessInformation; +PSYSTEM_PROCESS_INFORMATION PhDpcsProcessInformation; +PSYSTEM_PROCESS_INFORMATION PhInterruptsProcessInformation; ULONG64 PhCpuTotalCycleDelta; // real cycle time delta for this period PLARGE_INTEGER PhCpuIdleCycleTime; // cycle time for Idle @@ -279,19 +279,19 @@ BOOLEAN PhProcessProviderInitialization( PhProcessRecordList = PhCreateList(40); - RtlInitUnicodeString( - &PhDpcsProcessInformation.ImageName, - L"DPCs" - ); - PhDpcsProcessInformation.UniqueProcessId = DPCS_PROCESS_ID; - PhDpcsProcessInformation.InheritedFromUniqueProcessId = SYSTEM_IDLE_PROCESS_ID; + PhDpcsProcessInformation = PhAllocate(sizeof(SYSTEM_PROCESS_INFORMATION) + sizeof(SYSTEM_PROCESS_INFORMATION_EXTENSION)); + memset(PhDpcsProcessInformation, 0, sizeof(SYSTEM_PROCESS_INFORMATION) + sizeof(SYSTEM_PROCESS_INFORMATION_EXTENSION)); - RtlInitUnicodeString( - &PhInterruptsProcessInformation.ImageName, - L"Interrupts" - ); - PhInterruptsProcessInformation.UniqueProcessId = INTERRUPTS_PROCESS_ID; - PhInterruptsProcessInformation.InheritedFromUniqueProcessId = SYSTEM_IDLE_PROCESS_ID; + PhInterruptsProcessInformation = PhAllocate(sizeof(SYSTEM_PROCESS_INFORMATION) + sizeof(SYSTEM_PROCESS_INFORMATION_EXTENSION)); + memset(PhInterruptsProcessInformation, 0, sizeof(SYSTEM_PROCESS_INFORMATION) + sizeof(SYSTEM_PROCESS_INFORMATION_EXTENSION)); + + RtlInitUnicodeString(&PhDpcsProcessInformation->ImageName, L"DPCs"); + PhDpcsProcessInformation->UniqueProcessId = DPCS_PROCESS_ID; + PhDpcsProcessInformation->InheritedFromUniqueProcessId = SYSTEM_IDLE_PROCESS_ID; + + RtlInitUnicodeString(&PhInterruptsProcessInformation->ImageName, L"Interrupts"); + PhInterruptsProcessInformation->UniqueProcessId = INTERRUPTS_PROCESS_ID; + PhInterruptsProcessInformation->InheritedFromUniqueProcessId = SYSTEM_IDLE_PROCESS_ID; PhCpuInformation = PhAllocate( sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION) * @@ -2043,14 +2043,14 @@ VOID PhProcessProviderUpdate( if (PhEnableCycleCpuUsage) { - PhInterruptsProcessInformation.KernelTime.QuadPart = PhCpuTotals.DpcTime.QuadPart + PhCpuTotals.InterruptTime.QuadPart; - PhInterruptsProcessInformation.CycleTime = PhCpuSystemCycleDelta.Value; + PhInterruptsProcessInformation->KernelTime.QuadPart = PhCpuTotals.DpcTime.QuadPart + PhCpuTotals.InterruptTime.QuadPart; + PhInterruptsProcessInformation->CycleTime = PhCpuSystemCycleDelta.Value; sysTotalCycleTime += PhCpuSystemCycleDelta.Delta; } else { - PhDpcsProcessInformation.KernelTime = PhCpuTotals.DpcTime; - PhInterruptsProcessInformation.KernelTime = PhCpuTotals.InterruptTime; + PhDpcsProcessInformation->KernelTime = PhCpuTotals.DpcTime; + PhInterruptsProcessInformation->KernelTime = PhCpuTotals.InterruptTime; } // Look for dead processes. @@ -2074,11 +2074,11 @@ VOID PhProcessProviderUpdate( if (processItem->ProcessId == DPCS_PROCESS_ID) { - processEntry = &PhDpcsProcessInformation; + processEntry = PhDpcsProcessInformation; } else if (processItem->ProcessId == INTERRUPTS_PROCESS_ID) { - processEntry = &PhInterruptsProcessInformation; + processEntry = PhInterruptsProcessInformation; } else { @@ -2420,13 +2420,13 @@ VOID PhProcessProviderUpdate( // Trick ourselves into thinking that the fake processes // are on the list. - if (process == &PhInterruptsProcessInformation) + if (process == PhInterruptsProcessInformation) { process = NULL; } - else if (process == &PhDpcsProcessInformation) + else if (process == PhDpcsProcessInformation) { - process = &PhInterruptsProcessInformation; + process = PhInterruptsProcessInformation; } else { @@ -2435,9 +2435,9 @@ VOID PhProcessProviderUpdate( if (process == NULL) { if (PhEnableCycleCpuUsage) - process = &PhInterruptsProcessInformation; + process = PhInterruptsProcessInformation; else - process = &PhDpcsProcessInformation; + process = PhDpcsProcessInformation; } } } From 70676131234825ab2efcab48646722efd40b14d1 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 25 Nov 2017 02:53:07 +1100 Subject: [PATCH 0593/2058] Update macro, Fix dbghelp path --- ProcessHacker/dbgcon.c | 3 +- tools/peview/peprp.c | 64 ++++++++++++++++++++++++++++++++++++------ 2 files changed, 56 insertions(+), 11 deletions(-) diff --git a/ProcessHacker/dbgcon.c b/ProcessHacker/dbgcon.c index d9a5c25e57d7..bcd6cab3ae10 100644 --- a/ProcessHacker/dbgcon.c +++ b/ProcessHacker/dbgcon.c @@ -677,8 +677,7 @@ NTSTATUS PhpDebugConsoleThreadStart( UNICODE_STRING var; PPH_STRING newSearchPath; - var.Buffer = buffer; - var.MaximumLength = sizeof(buffer); + RtlInitEmptyUnicodeString(&var, buffer, sizeof(buffer)); if (!NT_SUCCESS(RtlQueryEnvironmentVariable_U(NULL, &name, &var))) buffer[0] = 0; diff --git a/tools/peview/peprp.c b/tools/peview/peprp.c index 2e91afed8563..22ec46ba10f2 100644 --- a/tools/peview/peprp.c +++ b/tools/peview/peprp.c @@ -666,7 +666,7 @@ VOID PvpLoadDbgHelpFromPath( { HMODULE dbghelpModule; - if (dbghelpModule = LoadLibrary(DbgHelpPath)) + if (DbgHelpPath && (dbghelpModule = LoadLibrary(DbgHelpPath))) { PPH_STRING fullDbghelpPath; ULONG indexOfFileName; @@ -702,25 +702,67 @@ VOID PvpLoadDbgHelpFromPath( PhSymbolProviderCompleteInitialization(dbghelpModule); } +PPH_STRING PhFindDbghelpPath( + VOID + ) +{ + static struct + { + ULONG Folder; + PWSTR AppendPath; + } locations[] = + { +#ifdef _WIN64 + { CSIDL_PROGRAM_FILESX86, L"\\Windows Kits\\10\\Debuggers\\x64\\dbghelp.dll" }, + { CSIDL_PROGRAM_FILESX86, L"\\Windows Kits\\8.1\\Debuggers\\x64\\dbghelp.dll" }, + { CSIDL_PROGRAM_FILESX86, L"\\Windows Kits\\8.0\\Debuggers\\x64\\dbghelp.dll" }, + { CSIDL_PROGRAM_FILES, L"\\Debugging Tools for Windows (x64)\\dbghelp.dll" } +#else + { CSIDL_PROGRAM_FILES, L"\\Windows Kits\\10\\Debuggers\\x86\\dbghelp.dll" }, + { CSIDL_PROGRAM_FILES, L"\\Windows Kits\\8.1\\Debuggers\\x86\\dbghelp.dll" }, + { CSIDL_PROGRAM_FILES, L"\\Windows Kits\\8.0\\Debuggers\\x86\\dbghelp.dll" }, + { CSIDL_PROGRAM_FILES, L"\\Debugging Tools for Windows (x86)\\dbghelp.dll" } +#endif + }; + + PPH_STRING path; + ULONG i; + + for (i = 0; i < sizeof(locations) / sizeof(locations[0]); i++) + { + path = PhGetKnownLocation(locations[i].Folder, locations[i].AppendPath); + + if (path) + { + if (RtlDoesFileExists_U(path->Buffer)) + return path; + + PhDereferenceObject(path); + } + } + + return NULL; +} + + BOOLEAN PvpLoadDbgHelp( _Inout_ PPH_SYMBOL_PROVIDER *SymbolProvider ) { static UNICODE_STRING symbolPathVarName = RTL_CONSTANT_STRING(L"_NT_SYMBOL_PATH"); PPH_STRING symbolSearchPath; + PPH_STRING dbgHelpPath; PPH_SYMBOL_PROVIDER symbolProvider; - WCHAR buffer[512] = L""; - UNICODE_STRING symbolPathUs = - { - .Buffer = buffer, - .Length = sizeof(buffer) - sizeof(UNICODE_NULL), - .MaximumLength = sizeof(buffer) - }; + UNICODE_STRING symbolPathUs; + WCHAR buffer[512]; + RtlInitEmptyUnicodeString(&symbolPathUs, buffer, sizeof(buffer)); + if (!PhSymbolProviderInitialization()) return FALSE; - PvpLoadDbgHelpFromPath(L"C:\\Program Files (x86)\\Windows Kits\\10\\Debuggers\\x64\\dbghelp.dll"); + dbgHelpPath = PhFindDbghelpPath(); + PvpLoadDbgHelpFromPath(PhGetString(dbgHelpPath)); symbolProvider = PhCreateSymbolProvider(NULL); // Load symbol path from _NT_SYMBOL_PATH if configured by the user. @@ -730,12 +772,16 @@ BOOLEAN PvpLoadDbgHelp( } else { + // Set the default path (C:\\Symbols is the default hard-coded path for livekd). symbolSearchPath = PhCreateString(L"SRV*C:\\Symbols*http://msdl.microsoft.com/download/symbols"); } PhSetSearchPathSymbolProvider(symbolProvider, symbolSearchPath->Buffer); PhDereferenceObject(symbolSearchPath); + if (dbgHelpPath) + PhDereferenceObject(dbgHelpPath); + *SymbolProvider = symbolProvider; return TRUE; } \ No newline at end of file From f5d19dbaba56f66f303daa89d90edf07662352eb Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 25 Nov 2017 02:53:48 +1100 Subject: [PATCH 0594/2058] Fix typo --- ProcessHacker/procprv.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/ProcessHacker/procprv.c b/ProcessHacker/procprv.c index 7adacbcb2237..e65e512f4b8b 100644 --- a/ProcessHacker/procprv.c +++ b/ProcessHacker/procprv.c @@ -111,7 +111,10 @@ typedef struct _PH_PROCESS_QUERY_S1_DATA ULONG IsSecureProcess : 1; ULONG IsSubsystemProcess : 1; - ULONG Spare : 23; + ULONG IsBeingDebugged : 1; + ULONG IsImmersive : 1; + + ULONG Spare : 21; }; }; } PH_PROCESS_QUERY_S1_DATA, *PPH_PROCESS_QUERY_S1_DATA; @@ -1006,6 +1009,17 @@ VOID PhpProcessQueryStage1( } } + // Debugged + if (processHandleLimited) + { + BOOLEAN isBeingDebugged; + + if (NT_SUCCESS(PhGetProcessIsBeingDebugged(processHandleLimited, &isBeingDebugged))) + { + Data->IsBeingDebugged = isBeingDebugged; + } + } + // Command line, .NET if (processHandleLimited) { @@ -1157,11 +1171,11 @@ VOID PhpProcessQueryStage1( // Immersive if (processHandleLimited && IsImmersiveProcess_I) { - processItem->IsImmersive = !!IsImmersiveProcess_I(processHandleLimited); + Data->IsImmersive = !!IsImmersiveProcess_I(processHandleLimited); } // Package full name - if (processHandleLimited && WINDOWS_HAS_IMMERSIVE && processItem->IsImmersive) + if (processHandleLimited && WINDOWS_HAS_IMMERSIVE && Data->IsImmersive) { Data->PackageFullName = PhGetProcessPackageFullName(processHandleLimited); } @@ -1305,6 +1319,8 @@ VOID PhpFillProcessItemStage1( processItem->IsProtectedProcess = Data->IsProtectedProcess; processItem->IsSecureProcess = Data->IsSecureProcess; processItem->IsSubsystemProcess = Data->IsSubsystemProcess; + processItem->IsBeingDebugged = Data->IsBeingDebugged; + processItem->IsImmersive = Data->IsImmersive; PhSwapReference(&processItem->Record->CommandLine, processItem->CommandLine); } From 47a7a891d3cfce5796ba8962e80e0dba407618af Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 27 Nov 2017 07:42:58 +1100 Subject: [PATCH 0595/2058] NetworkTools: Add packet loss, latency, bytes in/out columns to the network tab --- plugins/NetworkTools/NetworkTools.rc | 7 +- plugins/NetworkTools/main.c | 321 ++++++++++++++++++++++++++- plugins/NetworkTools/nettools.h | 28 ++- plugins/NetworkTools/options.c | 2 + plugins/NetworkTools/resource.h | 3 +- 5 files changed, 347 insertions(+), 14 deletions(-) diff --git a/plugins/NetworkTools/NetworkTools.rc b/plugins/NetworkTools/NetworkTools.rc index ba5d9ab2068c..434e4122d907 100644 --- a/plugins/NetworkTools/NetworkTools.rc +++ b/plugins/NetworkTools/NetworkTools.rc @@ -96,7 +96,7 @@ BEGIN CONTROL "",IDC_NETOUTPUTEDIT,"RICHEDIT50W",WS_VSCROLL | WS_TABSTOP | 0x4,2,2,387,212 END -IDD_OPTIONS DIALOGEX 0, 0, 201, 43 +IDD_OPTIONS DIALOGEX 0, 0, 201, 69 STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Options" FONT 8, "MS Shell Dlg", 400, 0, 0x1 @@ -105,6 +105,9 @@ BEGIN EDITTEXT IDC_PINGPACKETLENGTH,7,17,89,14,ES_AUTOHSCROLL | ES_NUMBER EDITTEXT IDC_MAXHOPS,105,17,89,14,ES_AUTOHSCROLL | ES_NUMBER LTEXT "Max Tracert Hops:",IDC_STATIC,105,7,60,8 + CONTROL "Enable extended TCP statistics",IDC_ENABLE_EXTENDED_TCP, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,39,115,10 + LTEXT "Note: Changes may require an application restart.",IDC_STATIC,7,54,162,8 END IDD_PING DIALOGEX 0, 0, 329, 151 @@ -656,7 +659,7 @@ BEGIN LEFTMARGIN, 7 RIGHTMARGIN, 194 TOPMARGIN, 7 - BOTTOMMARGIN, 36 + BOTTOMMARGIN, 62 END IDD_PING, DIALOG diff --git a/plugins/NetworkTools/main.c b/plugins/NetworkTools/main.c index b034b73ca90f..1ff9eaa5d195 100644 --- a/plugins/NetworkTools/main.c +++ b/plugins/NetworkTools/main.c @@ -32,13 +32,25 @@ PH_CALLBACK_REGISTRATION MainMenuInitializingCallbackRegistration; PH_CALLBACK_REGISTRATION NetworkMenuInitializingCallbackRegistration; PH_CALLBACK_REGISTRATION NetworkTreeNewInitializingCallbackRegistration; PH_CALLBACK_REGISTRATION TreeNewMessageCallbackRegistration; +PH_CALLBACK_REGISTRATION ProcessesUpdatedCallbackRegistration; + HWND NetworkTreeNewHandle = NULL; +BOOLEAN NetworkExtensionEnabled = FALSE; +LIST_ENTRY NetworkExtensionListHead = { &NetworkExtensionListHead, &NetworkExtensionListHead }; +PH_QUEUED_LOCK NetworkExtensionListLock = PH_QUEUED_LOCK_INIT; VOID NTAPI LoadCallback( _In_opt_ PVOID Parameter, _In_opt_ PVOID Context ) { + // HACK: The GetPerTcpConnectionEStats function requires administrative privileges + // but returns success instead of access denied. + if (PhGetOwnTokenAttributes().Elevated) + { + NetworkExtensionEnabled = !!PhGetIntegerSetting(SETTING_NAME_EXTENDED_TCP_STATS); + } + LoadGeoLiteDb(); } @@ -329,6 +341,18 @@ LONG NTAPI NetworkServiceSortFunction( { case NETWORK_COLUMN_ID_REMOTE_COUNTRY: return PhCompareStringWithNull(extension1->RemoteCountryCode, extension2->RemoteCountryCode, TRUE); + case NETWORK_COLUMN_ID_LOCAL_SERVICE: + return PhCompareStringWithNull(extension1->LocalServiceName, extension2->LocalServiceName, TRUE); + case NETWORK_COLUMN_ID_REMOTE_SERVICE: + return PhCompareStringWithNull(extension1->RemoteServiceName, extension2->RemoteServiceName, TRUE); + case NETWORK_COLUMN_ID_BYTES_IN: + return uint64cmp(extension1->NumberOfBytesIn, extension2->NumberOfBytesIn); + case NETWORK_COLUMN_ID_BYTES_OUT: + return uint64cmp(extension1->NumberOfBytesOut, extension2->NumberOfBytesOut); + case NETWORK_COLUMN_ID_PACKETLOSS: + return uint64cmp(extension1->NumberOfLostPackets, extension2->NumberOfLostPackets); + case NETWORK_COLUMN_ID_LATENCY: + return uint64cmp(extension1->SampleRtt, extension2->SampleRtt); } return 0; @@ -362,18 +386,51 @@ VOID NTAPI NetworkTreeNewInitializingCallback( column.Width = 140; column.Alignment = PH_ALIGN_LEFT; PhPluginAddTreeNewColumn(PluginInstance, info->CmData, &column, NETWORK_COLUMN_ID_REMOTE_SERVICE, NULL, NetworkServiceSortFunction); + + memset(&column, 0, sizeof(PH_TREENEW_COLUMN)); + column.Text = L"Total bytes in"; + column.Width = 80; + column.Alignment = PH_ALIGN_LEFT; + PhPluginAddTreeNewColumn(PluginInstance, info->CmData, &column, NETWORK_COLUMN_ID_BYTES_IN, NULL, NetworkServiceSortFunction); + + memset(&column, 0, sizeof(PH_TREENEW_COLUMN)); + column.Text = L"Total bytes out"; + column.Width = 80; + column.Alignment = PH_ALIGN_LEFT; + PhPluginAddTreeNewColumn(PluginInstance, info->CmData, &column, NETWORK_COLUMN_ID_BYTES_OUT, NULL, NetworkServiceSortFunction); + + memset(&column, 0, sizeof(PH_TREENEW_COLUMN)); + column.Text = L"Packet loss"; + column.Width = 80; + column.Alignment = PH_ALIGN_LEFT; + PhPluginAddTreeNewColumn(PluginInstance, info->CmData, &column, NETWORK_COLUMN_ID_PACKETLOSS, NULL, NetworkServiceSortFunction); + + memset(&column, 0, sizeof(PH_TREENEW_COLUMN)); + column.Text = L"Latency (ms)"; + column.Width = 80; + column.Alignment = PH_ALIGN_LEFT; + PhPluginAddTreeNewColumn(PluginInstance, info->CmData, &column, NETWORK_COLUMN_ID_LATENCY, NULL, NetworkServiceSortFunction); } VOID NTAPI NetworkItemCreateCallback( _In_ PVOID Object, _In_ PH_EM_OBJECT_TYPE ObjectType, _In_ PVOID Extension - ) +) { - //PPH_NETWORK_ITEM networkItem = Object; + PPH_NETWORK_ITEM networkItem = Object; PNETWORK_EXTENSION extension = Extension; memset(extension, 0, sizeof(NETWORK_EXTENSION)); + + extension->NetworkItem = networkItem; + + if (NetworkExtensionEnabled) + { + PhAcquireQueuedLockExclusive(&NetworkExtensionListLock); + InsertTailList(&NetworkExtensionListHead, &extension->ListEntry); + PhReleaseQueuedLockExclusive(&NetworkExtensionListLock); + } } VOID NTAPI NetworkItemDeleteCallback( @@ -385,13 +442,60 @@ VOID NTAPI NetworkItemDeleteCallback( //PPH_NETWORK_ITEM networkItem = Object; PNETWORK_EXTENSION extension = Extension; - PhClearReference(&extension->RemoteCountryCode); - PhClearReference(&extension->RemoteCountryName); + if (NetworkExtensionEnabled) + { + PhAcquireQueuedLockExclusive(&NetworkExtensionListLock); + RemoveEntryList(&extension->ListEntry); + PhReleaseQueuedLockExclusive(&NetworkExtensionListLock); + } + + if (extension->LocalServiceName) + PhDereferenceObject(extension->LocalServiceName); + if (extension->RemoteServiceName) + PhDereferenceObject(extension->RemoteServiceName); + if (extension->RemoteCountryCode) + PhDereferenceObject(extension->RemoteCountryCode); + if (extension->RemoteCountryName) + PhDereferenceObject(extension->RemoteCountryName); + if (extension->BytesIn) + PhDereferenceObject(extension->BytesIn); + if (extension->BytesOut) + PhDereferenceObject(extension->BytesOut); + if (extension->PacketLossText) + PhDereferenceObject(extension->PacketLossText); + if (extension->LatencyText) + PhDereferenceObject(extension->LatencyText); if (extension->CountryIcon) DestroyIcon(extension->CountryIcon); } +FORCEINLINE VOID PhpNetworkItemToRow( + _Out_ PMIB_TCPROW Row, + _In_ PPH_NETWORK_ITEM NetworkItem + ) +{ + Row->dwState = NetworkItem->State; + Row->dwLocalAddr = NetworkItem->LocalEndpoint.Address.Ipv4; + Row->dwLocalPort = _byteswap_ushort((USHORT)NetworkItem->LocalEndpoint.Port); + Row->dwRemoteAddr = NetworkItem->RemoteEndpoint.Address.Ipv4; + Row->dwRemotePort = _byteswap_ushort((USHORT)NetworkItem->RemoteEndpoint.Port); +} + +FORCEINLINE VOID PhpNetworkItemToRow6( + _Out_ PMIB_TCP6ROW Row, + _In_ PPH_NETWORK_ITEM NetworkItem + ) +{ + Row->State = NetworkItem->State; + memcpy(Row->LocalAddr.u.Byte, NetworkItem->LocalEndpoint.Address.Ipv6, 16); + Row->dwLocalScopeId = NetworkItem->LocalScopeId; + Row->dwLocalPort = _byteswap_ushort((USHORT)NetworkItem->LocalEndpoint.Port); + memcpy(Row->RemoteAddr.u.Byte, NetworkItem->RemoteEndpoint.Address.Ipv6, 16); + Row->dwRemoteScopeId = NetworkItem->RemoteScopeId; + Row->dwRemotePort = _byteswap_ushort((USHORT)NetworkItem->RemoteEndpoint.Port); +} + VOID NTAPI NetworkNodeCreateCallback( _In_ PVOID Object, _In_ PH_EM_OBJECT_TYPE ObjectType, @@ -418,6 +522,43 @@ VOID NTAPI NetworkNodeCreateCallback( extension->CountryValid = TRUE; } + + if (!extension->StatsEnabled) + { + if (NetworkExtensionEnabled) + { + if (networkNode->NetworkItem->ProtocolType == PH_TCP4_NETWORK_PROTOCOL) + { + MIB_TCPROW tcpRow; + TCP_ESTATS_DATA_RW_v0 dataRw; + TCP_ESTATS_PATH_RW_v0 pathRw; + + dataRw.EnableCollection = TRUE; + pathRw.EnableCollection = TRUE; + + PhpNetworkItemToRow(&tcpRow, networkNode->NetworkItem); + + SetPerTcpConnectionEStats(&tcpRow, TcpConnectionEstatsData, (PUCHAR)&dataRw, 0, sizeof(TCP_ESTATS_DATA_RW_v0), 0); + SetPerTcpConnectionEStats(&tcpRow, TcpConnectionEstatsPath, (PUCHAR)&pathRw, 0, sizeof(TCP_ESTATS_PATH_RW_v0), 0); + } + else if (networkNode->NetworkItem->ProtocolType == PH_TCP6_NETWORK_PROTOCOL) + { + MIB_TCP6ROW tcp6Row; + TCP_ESTATS_DATA_RW_v0 dataRw; + TCP_ESTATS_PATH_RW_v0 pathRw; + + dataRw.EnableCollection = TRUE; + pathRw.EnableCollection = TRUE; + + PhpNetworkItemToRow6(&tcp6Row, networkNode->NetworkItem); + + SetPerTcp6ConnectionEStats(&tcp6Row, TcpConnectionEstatsData, (PUCHAR)&dataRw, 0, sizeof(TCP_ESTATS_DATA_RW_v0), 0); + SetPerTcp6ConnectionEStats(&tcp6Row, TcpConnectionEstatsPath, (PUCHAR)&pathRw, 0, sizeof(TCP_ESTATS_PATH_RW_v0), 0); + } + } + + extension->StatsEnabled = TRUE; + } } VOID UpdateNetworkNode( @@ -464,6 +605,30 @@ VOID UpdateNetworkNode( } } break; + case NETWORK_COLUMN_ID_BYTES_IN: + { + if (Extension->NumberOfBytesIn) + PhMoveReference(&Extension->BytesIn, PhFormatSize(Extension->NumberOfBytesIn, -1)); + } + break; + case NETWORK_COLUMN_ID_BYTES_OUT: + { + if (Extension->NumberOfBytesOut) + PhMoveReference(&Extension->BytesOut, PhFormatSize(Extension->NumberOfBytesOut, -1)); + } + break; + case NETWORK_COLUMN_ID_PACKETLOSS: + { + if (Extension->NumberOfLostPackets) + PhMoveReference(&Extension->PacketLossText, PhFormatUInt64(Extension->NumberOfLostPackets, TRUE)); + } + break; + case NETWORK_COLUMN_ID_LATENCY: + { + if (Extension->SampleRtt) + PhMoveReference(&Extension->LatencyText, PhFormatUInt64(Extension->SampleRtt, TRUE)); + } + break; } } @@ -497,6 +662,18 @@ VOID NTAPI TreeNewMessageCallback( case NETWORK_COLUMN_ID_REMOTE_SERVICE: getCellText->Text = PhGetStringRef(extension->RemoteServiceName); break; + case NETWORK_COLUMN_ID_BYTES_IN: + getCellText->Text = PhGetStringRef(extension->BytesIn); + break; + case NETWORK_COLUMN_ID_BYTES_OUT: + getCellText->Text = PhGetStringRef(extension->BytesOut); + break; + case NETWORK_COLUMN_ID_PACKETLOSS: + getCellText->Text = PhGetStringRef(extension->PacketLossText); + break; + case NETWORK_COLUMN_ID_LATENCY: + getCellText->Text = PhGetStringRef(extension->LatencyText); + break; } } } @@ -563,24 +740,146 @@ VOID NTAPI TreeNewMessageCallback( extension->RemoteCountryName->Buffer, (INT)extension->RemoteCountryName->Length / 2, &rect, - DT_LEFT | DT_VCENTER | DT_SINGLELINE + DT_LEFT | DT_VCENTER | DT_END_ELLIPSIS | DT_SINGLELINE ); } if (GeoDbExpired && !extension->CountryIcon) { - DrawText(hdc, L"Geoip database expired.", -1, &rect, DT_LEFT | DT_VCENTER | DT_SINGLELINE); + DrawText(hdc, L"Geoip database expired.", -1, &rect, DT_LEFT | DT_VCENTER | DT_END_ELLIPSIS | DT_SINGLELINE); } if (!GeoDbLoaded) { - DrawText(hdc, L"Geoip database not found.", -1, &rect, DT_LEFT | DT_VCENTER | DT_SINGLELINE); + DrawText(hdc, L"Geoip database not found.", -1, &rect, DT_LEFT | DT_VCENTER | DT_END_ELLIPSIS | DT_SINGLELINE); } } break; } } +VOID ProcessesUpdatedCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + static ULONG ProcessesUpdatedCount = 0; + PLIST_ENTRY listEntry; + + if (!NetworkExtensionEnabled) + return; + + if (ProcessesUpdatedCount < 2) + { + ProcessesUpdatedCount++; + return; + } + + for ( + listEntry = NetworkExtensionListHead.Flink; + listEntry != &NetworkExtensionListHead; + listEntry = listEntry->Flink + ) + { + PNETWORK_EXTENSION extension = CONTAINING_RECORD(listEntry, NETWORK_EXTENSION, ListEntry); + + if (!extension || !extension->StatsEnabled) + continue; + + if (extension->NetworkItem->ProtocolType == PH_TCP4_NETWORK_PROTOCOL) + { + MIB_TCPROW tcpRow; + TCP_ESTATS_DATA_ROD_v0 dataRod; + TCP_ESTATS_PATH_ROD_v0 pathRod; + + PhpNetworkItemToRow(&tcpRow, extension->NetworkItem); + + if (GetPerTcpConnectionEStats( + &tcpRow, + TcpConnectionEstatsData, + NULL, + 0, + 0, + NULL, + 0, + 0, + (PUCHAR)&dataRod, + 0, + sizeof(TCP_ESTATS_DATA_ROD_v0) + ) == ERROR_SUCCESS) + { + extension->NumberOfBytesIn = dataRod.DataBytesIn; + extension->NumberOfBytesOut = dataRod.DataBytesOut; + } + + if (GetPerTcpConnectionEStats( + &tcpRow, + TcpConnectionEstatsPath, + NULL, + 0, + 0, + NULL, + 0, + 0, + (PUCHAR)&pathRod, + 0, + sizeof(TCP_ESTATS_PATH_ROD_v0) + ) == ERROR_SUCCESS) + { + extension->NumberOfLostPackets = pathRod.FastRetran + pathRod.PktsRetrans; + extension->SampleRtt = pathRod.SampleRtt; + + if (extension->SampleRtt == ULONG_MAX) // HACK + extension->SampleRtt = 0; + } + } + else if (extension->NetworkItem->ProtocolType == PH_TCP6_NETWORK_PROTOCOL) + { + MIB_TCP6ROW tcp6Row; + TCP_ESTATS_DATA_ROD_v0 dataRod; + TCP_ESTATS_PATH_ROD_v0 pathRod; + + PhpNetworkItemToRow6(&tcp6Row, extension->NetworkItem); + + if (GetPerTcp6ConnectionEStats( + &tcp6Row, + TcpConnectionEstatsData, + NULL, + 0, + 0, + NULL, + 0, + 0, + (PUCHAR)&dataRod, + 0, + sizeof(TCP_ESTATS_DATA_ROD_v0) + ) == ERROR_SUCCESS) + { + extension->NumberOfBytesIn = dataRod.DataBytesIn; + extension->NumberOfBytesOut = dataRod.DataBytesOut; + } + + if (GetPerTcp6ConnectionEStats( + &tcp6Row, + TcpConnectionEstatsPath, + NULL, + 0, + 0, + NULL, + 0, + 0, + (PUCHAR)&pathRod, + 0, + sizeof(TCP_ESTATS_PATH_ROD_v0) + ) == ERROR_SUCCESS) + { + extension->NumberOfLostPackets = pathRod.FastRetran + pathRod.PktsRetrans; + extension->SampleRtt = pathRod.SampleRtt; + } + } + } +} + LOGICAL DllMain( _In_ HINSTANCE Instance, _In_ ULONG Reason, @@ -607,6 +906,7 @@ LOGICAL DllMain( { IntegerPairSettingType, SETTING_NAME_WHOIS_WINDOW_POSITION, L"0,0" }, { ScalableIntegerPairSettingType, SETTING_NAME_WHOIS_WINDOW_SIZE, L"@96|600,365" }, { StringSettingType, SETTING_NAME_DB_LOCATION, L"%APPDATA%\\Process Hacker\\GeoLite2-Country.mmdb" }, + { IntegerSettingType, SETTING_NAME_EXTENDED_TCP_STATS, L"0" } }; PluginInstance = PhRegisterPlugin(PLUGIN_NAME, Instance, &info); @@ -663,6 +963,13 @@ LOGICAL DllMain( &TreeNewMessageCallbackRegistration ); + PhRegisterCallback( + PhGetGeneralCallback(GeneralCallbackProcessesUpdated), + ProcessesUpdatedCallback, + NULL, + &ProcessesUpdatedCallbackRegistration + ); + PhPluginSetObjectExtension( PluginInstance, EmNetworkItemType, diff --git a/plugins/NetworkTools/nettools.h b/plugins/NetworkTools/nettools.h index ff6aaa2f3427..eda0819c7553 100644 --- a/plugins/NetworkTools/nettools.h +++ b/plugins/NetworkTools/nettools.h @@ -59,6 +59,7 @@ #define SETTING_NAME_TRACERT_MAX_HOPS (PLUGIN_NAME L".TracertMaxHops") #define SETTING_NAME_WHOIS_WINDOW_POSITION (PLUGIN_NAME L".WhoisWindowPosition") #define SETTING_NAME_WHOIS_WINDOW_SIZE (PLUGIN_NAME L".WhoisWindowSize") +#define SETTING_NAME_EXTENDED_TCP_STATS (PLUGIN_NAME L".EnableExtendedTcpStats") extern PPH_PLUGIN PluginInstance; extern BOOLEAN GeoDbLoaded; @@ -212,6 +213,9 @@ INT_PTR CALLBACK OptionsDlgProc( // country.c typedef struct _NETWORK_EXTENSION { + LIST_ENTRY ListEntry; + PPH_NETWORK_ITEM NetworkItem; + union { BOOLEAN Flags; @@ -220,7 +224,8 @@ typedef struct _NETWORK_EXTENSION BOOLEAN CountryValid : 1; BOOLEAN LocalValid : 1; BOOLEAN RemoteValid : 1; - BOOLEAN Spare : 5; + BOOLEAN StatsEnabled : 1; + BOOLEAN Spare : 4; }; }; @@ -229,13 +234,28 @@ typedef struct _NETWORK_EXTENSION PPH_STRING RemoteServiceName; PPH_STRING RemoteCountryCode; PPH_STRING RemoteCountryName; + + ULONG64 NumberOfBytesOut; + ULONG64 NumberOfBytesIn; + ULONG64 NumberOfLostPackets; + ULONG SampleRtt; + + PPH_STRING BytesIn; + PPH_STRING BytesOut; + PPH_STRING PacketLossText; + PPH_STRING LatencyText; } NETWORK_EXTENSION, *PNETWORK_EXTENSION; typedef enum _NETWORK_COLUMN_ID { - NETWORK_COLUMN_ID_REMOTE_COUNTRY = 1, - NETWORK_COLUMN_ID_LOCAL_SERVICE = 2, - NETWORK_COLUMN_ID_REMOTE_SERVICE = 3, + NETWORK_COLUMN_ID_NONE, + NETWORK_COLUMN_ID_REMOTE_COUNTRY, + NETWORK_COLUMN_ID_LOCAL_SERVICE, + NETWORK_COLUMN_ID_REMOTE_SERVICE, + NETWORK_COLUMN_ID_BYTES_IN, + NETWORK_COLUMN_ID_BYTES_OUT, + NETWORK_COLUMN_ID_PACKETLOSS, + NETWORK_COLUMN_ID_LATENCY } NETWORK_COLUMN_ID; // country.c diff --git a/plugins/NetworkTools/options.c b/plugins/NetworkTools/options.c index accb0a4ece4d..abe24349106e 100644 --- a/plugins/NetworkTools/options.c +++ b/plugins/NetworkTools/options.c @@ -36,12 +36,14 @@ INT_PTR CALLBACK OptionsDlgProc( { SetDlgItemInt(hwndDlg, IDC_PINGPACKETLENGTH, PhGetIntegerSetting(SETTING_NAME_PING_SIZE), FALSE); SetDlgItemInt(hwndDlg, IDC_MAXHOPS, PhGetIntegerSetting(SETTING_NAME_TRACERT_MAX_HOPS), FALSE); + Button_SetCheck(GetDlgItem(hwndDlg, IDC_ENABLE_EXTENDED_TCP), PhGetIntegerSetting(SETTING_NAME_EXTENDED_TCP_STATS) ? BST_CHECKED : BST_UNCHECKED); } break; case WM_DESTROY: { PhSetIntegerSetting(SETTING_NAME_PING_SIZE, GetDlgItemInt(hwndDlg, IDC_PINGPACKETLENGTH, NULL, FALSE)); PhSetIntegerSetting(SETTING_NAME_TRACERT_MAX_HOPS, GetDlgItemInt(hwndDlg, IDC_MAXHOPS, NULL, FALSE)); + PhSetIntegerSetting(SETTING_NAME_EXTENDED_TCP_STATS, Button_GetCheck(GetDlgItem(hwndDlg, IDC_ENABLE_EXTENDED_TCP)) == BST_CHECKED); } break; } diff --git a/plugins/NetworkTools/resource.h b/plugins/NetworkTools/resource.h index 204de7750856..4c00392ba362 100644 --- a/plugins/NetworkTools/resource.h +++ b/plugins/NetworkTools/resource.h @@ -270,6 +270,7 @@ #define IDC_GEOIP 1028 #define IDC_LIST_TRACERT 1030 #define IDC_REFRESH 1031 +#define IDC_ENABLE_EXTENDED_TCP 1032 // Next default values for new objects // @@ -277,7 +278,7 @@ #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 107 #define _APS_NEXT_COMMAND_VALUE 40006 -#define _APS_NEXT_CONTROL_VALUE 1032 +#define _APS_NEXT_CONTROL_VALUE 1033 #define _APS_NEXT_SYMED_VALUE 104 #endif #endif From 5232ef00acd82c159e48217f8968d70cc4fa402f Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 27 Nov 2017 07:51:49 +1100 Subject: [PATCH 0596/2058] Export Ipv6 ScopeId for plugins --- ProcessHacker/include/netprv.h | 2 ++ ProcessHacker/netprv.c | 7 +++++++ 2 files changed, 9 insertions(+) diff --git a/ProcessHacker/include/netprv.h b/ProcessHacker/include/netprv.h index 7b26038ed53f..06398f6d988e 100644 --- a/ProcessHacker/include/netprv.h +++ b/ProcessHacker/include/netprv.h @@ -36,6 +36,8 @@ typedef struct _PH_NETWORK_ITEM LARGE_INTEGER CreateTime; ULONGLONG OwnerInfo[PH_NETWORK_OWNER_INFO_SIZE]; + ULONG LocalScopeId; + ULONG RemoteScopeId; } PH_NETWORK_ITEM, *PPH_NETWORK_ITEM; // end_phapppub diff --git a/ProcessHacker/netprv.c b/ProcessHacker/netprv.c index a096ec281b85..7df386b212c1 100644 --- a/ProcessHacker/netprv.c +++ b/ProcessHacker/netprv.c @@ -43,6 +43,8 @@ typedef struct _PH_NETWORK_CONNECTION HANDLE ProcessId; LARGE_INTEGER CreateTime; ULONGLONG OwnerInfo[PH_NETWORK_OWNER_INFO_SIZE]; + ULONG LocalScopeId; // Ipv6 + ULONG RemoteScopeId; // Ipv6 } PH_NETWORK_CONNECTION, *PPH_NETWORK_CONNECTION; typedef struct _PH_NETWORK_ITEM_QUERY_DATA @@ -589,6 +591,8 @@ VOID PhNetworkProviderUpdate( networkItem->ProcessId = connections[i].ProcessId; networkItem->CreateTime = connections[i].CreateTime; memcpy(networkItem->OwnerInfo, connections[i].OwnerInfo, sizeof(ULONGLONG) * PH_NETWORK_OWNER_INFO_SIZE); + networkItem->LocalScopeId = connections[i].LocalScopeId; + networkItem->RemoteScopeId = connections[i].RemoteScopeId; // Format various strings. @@ -924,6 +928,9 @@ BOOLEAN PhGetNetworkConnections( sizeof(ULONGLONG) * min(PH_NETWORK_OWNER_INFO_SIZE, TCPIP_OWNING_MODULE_SIZE) ); + connections[index].LocalScopeId = tcp6Table->table[i].dwLocalScopeId; + connections[index].RemoteScopeId = tcp6Table->table[i].dwRemoteScopeId; + index++; } From d40f25e4730055d530ce26222322d5d4acb71df2 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 28 Nov 2017 17:06:10 +1100 Subject: [PATCH 0597/2058] Increase column order limiting (https://wj32.org/processhacker/forums/viewtopic.php?t=2798) --- ProcessHacker/chcol.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ProcessHacker/chcol.c b/ProcessHacker/chcol.c index 68c16754a6c7..75e453219617 100644 --- a/ProcessHacker/chcol.c +++ b/ProcessHacker/chcol.c @@ -214,7 +214,7 @@ INT_PTR CALLBACK PhpColumnsDlgProc( break; case IDOK: { -#define ORDER_LIMIT 100 +#define ORDER_LIMIT 200 PPH_LIST activeList; ULONG activeCount; ULONG i; From f6e1662b94a9e99ba1288a675f0bbe25c7027445 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 29 Nov 2017 19:19:12 +1100 Subject: [PATCH 0598/2058] Fix emenu crash from commit d356b10289791bb5472291ae2eff50baa2d3f4b4 --- ProcessHacker/mainwnd.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index 9b039b2c7dc8..01e864229ad7 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -3309,10 +3309,11 @@ VOID PhMwpUpdateUsersMenu( escapedMenuText = PhEscapeStringForMenuPrefix(&menuText->sr); PhDereferenceObject(menuText); - PhInsertEMenuItem(UsersMenu, userMenu = PhCreateEMenuItem(0, IDR_USER, escapedMenuText->Buffer, NULL, UlongToPtr(sessions[i].SessionId)), -1); + userMenu = PhCreateEMenuItem(PH_EMENU_TEXT_OWNED, IDR_USER, PhAllocateCopy(escapedMenuText->Buffer, escapedMenuText->Length + sizeof(WCHAR)), NULL, UlongToPtr(sessions[i].SessionId)); PhLoadResourceEMenuItem(userMenu, PhInstanceHandle, MAKEINTRESOURCE(IDR_USER), 0); + PhInsertEMenuItem(UsersMenu, userMenu, -1); - PhAutoDereferenceObject(escapedMenuText); + PhDereferenceObject(escapedMenuText); } WinStationFreeMemory(sessions); From 2dd3232cb70808fedeb5e7269ac52eb1f9d9273e Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 30 Nov 2017 15:05:23 +1100 Subject: [PATCH 0599/2058] Add column set support, Add View menu > Column set options #180 --- ProcessHacker/ProcessHacker.rc | 21 + ProcessHacker/ProcessHacker.vcxproj | 2 + ProcessHacker/ProcessHacker.vcxproj.filters | 6 + ProcessHacker/colsetmgr.c | 651 ++++++++++++++++++++ ProcessHacker/include/colsetmgr.h | 40 ++ ProcessHacker/include/phplug.h | 1 + ProcessHacker/include/proctree.h | 10 + ProcessHacker/mainwnd.c | 82 ++- ProcessHacker/mwpgproc.c | 34 + ProcessHacker/proctree.c | 27 + ProcessHacker/resource.h | 11 +- ProcessHacker/settings.c | 1 + 12 files changed, 880 insertions(+), 6 deletions(-) create mode 100644 ProcessHacker/colsetmgr.c create mode 100644 ProcessHacker/include/colsetmgr.h diff --git a/ProcessHacker/ProcessHacker.rc b/ProcessHacker/ProcessHacker.rc index 02976aa4cd90..793a20ab1c10 100644 --- a/ProcessHacker/ProcessHacker.rc +++ b/ProcessHacker/ProcessHacker.rc @@ -1887,6 +1887,19 @@ BEGIN CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,2,2,256,256 END +IDD_COLUMNSETS DIALOGEX 0, 0, 231, 188 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Organize Column Sets" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + PUSHBUTTON "Move up",IDC_MOVEUP,177,42,50,14 + PUSHBUTTON "Move down",IDC_MOVEDOWN,177,59,50,14 + PUSHBUTTON "OK",IDOK,177,171,50,14 + PUSHBUTTON "Rename",IDC_RENAME,177,4,50,14 + PUSHBUTTON "Delete",IDC_REMOVE,177,94,50,14 + CONTROL "",IDC_COLUMNSETLIST,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_EDITLABELS | LVS_ALIGNLEFT | LVS_NOCOLUMNHEADER | WS_BORDER | WS_TABSTOP,4,4,170,180 +END + ///////////////////////////////////////////////////////////////////////////// // @@ -2449,6 +2462,14 @@ BEGIN TOPMARGIN, 2 BOTTOMMARGIN, 258 END + + IDD_COLUMNSETS, DIALOG + BEGIN + LEFTMARGIN, 4 + RIGHTMARGIN, 227 + TOPMARGIN, 4 + BOTTOMMARGIN, 184 + END END #endif // APSTUDIO_INVOKED diff --git a/ProcessHacker/ProcessHacker.vcxproj b/ProcessHacker/ProcessHacker.vcxproj index 9b4c0047495c..45896e808026 100644 --- a/ProcessHacker/ProcessHacker.vcxproj +++ b/ProcessHacker/ProcessHacker.vcxproj @@ -234,6 +234,7 @@ + @@ -348,6 +349,7 @@ + diff --git a/ProcessHacker/ProcessHacker.vcxproj.filters b/ProcessHacker/ProcessHacker.vcxproj.filters index b969ed3f7d8f..3a8cdc58efd6 100644 --- a/ProcessHacker/ProcessHacker.vcxproj.filters +++ b/ProcessHacker/ProcessHacker.vcxproj.filters @@ -384,6 +384,9 @@ Process Hacker + + Process Hacker + @@ -545,6 +548,9 @@ Headers + + Headers + diff --git a/ProcessHacker/colsetmgr.c b/ProcessHacker/colsetmgr.c new file mode 100644 index 000000000000..63c0617b6c55 --- /dev/null +++ b/ProcessHacker/colsetmgr.c @@ -0,0 +1,651 @@ +/* + * Process Hacker - + * tree new column set manager + * + * Copyright (C) 2017 dmex + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include +#include +#include +#include +#include + +PPH_LIST PhInitializeColumnSetList( + _In_ PWSTR SettingName + ) +{ + PPH_LIST columnSetList; + PPH_STRING settingsString; + ULONG64 count; + ULONG64 index; + PH_STRINGREF remaining; + PH_STRINGREF part; + + columnSetList = PhCreateList(10); + settingsString = PhaGetStringSetting(SettingName); + remaining = settingsString->sr; + + if (remaining.Length == 0) + goto CleanupExit; + if (!PhSplitStringRefAtChar(&remaining, '-', &part, &remaining)) + goto CleanupExit; + if (!PhStringToInteger64(&part, 10, &count)) + goto CleanupExit; + + for (index = 0; index < count; index++) + { + PH_STRINGREF columnSetNamePart; + PH_STRINGREF columnSetSettingPart; + PH_STRINGREF columnSetSortPart; + + if (remaining.Length == 0) + break; + + PhSplitStringRefAtChar(&remaining, '-', &columnSetNamePart, &remaining); + PhSplitStringRefAtChar(&remaining, '-', &columnSetSettingPart, &remaining); + PhSplitStringRefAtChar(&remaining, '-', &columnSetSortPart, &remaining); + + { + PPH_COLUMN_SET_ENTRY entry; + + entry = PhAllocate(sizeof(PH_COLUMN_SET_ENTRY)); + entry->Name = PhCreateString2(&columnSetNamePart); + entry->Setting = PhCreateString2(&columnSetSettingPart); + entry->Sorting = PhCreateString2(&columnSetSortPart); + + PhAddItemList(columnSetList, entry); + } + } + +CleanupExit: + return columnSetList; +} + +VOID PhSaveSettingsColumnList( + _In_ PWSTR SettingName, + _In_ PPH_LIST ColumnSetList + ) +{ + ULONG index; + PPH_STRING settingsString; + PH_STRING_BUILDER stringBuilder; + + PhInitializeStringBuilder(&stringBuilder, 100); + PhAppendFormatStringBuilder( + &stringBuilder, + L"%lu-", + ColumnSetList->Count + ); + + for (index = 0; index < ColumnSetList->Count; index++) + { + PPH_COLUMN_SET_ENTRY entry = ColumnSetList->Items[index]; + + if (PhIsNullOrEmptyString(entry->Name)) + continue; + + PhAppendFormatStringBuilder( + &stringBuilder, + L"%s-%s-%s-", + entry->Name->Buffer, + PhGetStringOrEmpty(entry->Setting), + PhGetStringOrEmpty(entry->Sorting) + ); + } + + if (stringBuilder.String->Length != 0) + PhRemoveEndStringBuilder(&stringBuilder, 1); + + settingsString = PH_AUTO(PhFinalStringBuilderString(&stringBuilder)); + PhSetStringSetting2(L"ProcessTreeColumnSetConfig", &settingsString->sr); +} + +VOID PhDeleteColumnSetList( + _In_ PPH_LIST ColumnSetList + ) +{ + for (ULONG i = 0; i < ColumnSetList->Count; i++) + { + PPH_COLUMN_SET_ENTRY entry = ColumnSetList->Items[i]; + + //PhRemoveItemList(ColumnSetList, PhFindItemList(ColumnSetList, entry)); + + PhClearReference(&entry->Name); + PhClearReference(&entry->Setting); + PhClearReference(&entry->Sorting); + + PhFree(entry); + } + + PhDereferenceObject(ColumnSetList); +} + +BOOLEAN PhLoadSettingsColumnSet( + _In_ PWSTR SettingName, + _In_ PPH_STRING ColumnSetName, + _Out_ PPH_STRING *TreeListSettings, + _Out_ PPH_STRING *TreeSortSettings + ) +{ + PPH_STRING treeSettings = NULL; + PPH_STRING sortSettings = NULL; + PPH_STRING settingsString; + ULONG64 count; + ULONG64 index; + PH_STRINGREF remaining; + PH_STRINGREF part; + + settingsString = PhaGetStringSetting(L"ProcessTreeColumnSetConfig"); + remaining = settingsString->sr; + + if (remaining.Length == 0) + return FALSE; + + if (!PhSplitStringRefAtChar(&remaining, '-', &part, &remaining)) + return FALSE; + if (!PhStringToInteger64(&part, 10, &count)) + return FALSE; + + for (index = 0; index < count; index++) + { + PH_STRINGREF columnSetNamePart; + PH_STRINGREF columnSetSettingPart; + PH_STRINGREF columnSetSortPart; + + if (remaining.Length == 0) + break; + + PhSplitStringRefAtChar(&remaining, '-', &columnSetNamePart, &remaining); + PhSplitStringRefAtChar(&remaining, '-', &columnSetSettingPart, &remaining); + PhSplitStringRefAtChar(&remaining, '-', &columnSetSortPart, &remaining); + + if (PhEqualStringRef(&columnSetNamePart, &ColumnSetName->sr, FALSE)) + { + treeSettings = PhCreateString2(&columnSetSettingPart); + sortSettings = PhCreateString2(&columnSetSortPart); + break; + } + } + + if (!PhIsNullOrEmptyString(treeSettings) && !PhIsNullOrEmptyString(sortSettings)) + { + *TreeListSettings = treeSettings; + *TreeSortSettings = sortSettings; + return TRUE; + } + else + { + if (treeSettings) + PhDereferenceObject(treeSettings); + if (sortSettings) + PhDereferenceObject(sortSettings); + return FALSE; + } +} + +VOID PhSaveSettingsColumnSet( + _In_ PWSTR SettingName, + _In_ PPH_STRING ColumnSetName, + _In_ PPH_STRING TreeListSettings, + _In_ PPH_STRING TreeSortSettings + ) +{ + ULONG index; + BOOLEAN found = FALSE; + PPH_LIST columnSetList; + + columnSetList = PhInitializeColumnSetList(SettingName); + + for (index = 0; index < columnSetList->Count; index++) + { + PPH_COLUMN_SET_ENTRY entry = columnSetList->Items[index]; + + if (PhEqualString(entry->Name, ColumnSetName, FALSE)) + { + PhReferenceObject(TreeListSettings); + PhReferenceObject(TreeSortSettings); + + PhMoveReference(&entry->Setting, TreeListSettings); + PhMoveReference(&entry->Sorting, TreeSortSettings); + + found = TRUE; + break; + } + } + + if (!found) + { + PPH_COLUMN_SET_ENTRY entry; + + PhReferenceObject(ColumnSetName); + PhReferenceObject(TreeListSettings); + PhReferenceObject(TreeSortSettings); + + entry = PhAllocate(sizeof(PH_COLUMN_SET_ENTRY)); + entry->Name = ColumnSetName; + entry->Setting = TreeListSettings; + entry->Sorting = TreeSortSettings; + + PhAddItemList(columnSetList, entry); + } + + PhSaveSettingsColumnList(SettingName, columnSetList); + + PhDeleteColumnSetList(columnSetList); +} + +// Column Set Editor Dialog + +typedef struct _COLUMNSET_DIALOG_CONTEXT +{ + HWND DialogHandle; + HWND ListViewHandle; + HWND RenameButtonHandle; + HWND MoveUpButtonHandle; + HWND MoveDownButtonHandle; + HWND RemoveButtonHandle; + PPH_STRING SettingName; + PPH_LIST ColumnSetList; + BOOLEAN LabelEditActive; +} COLUMNSET_DIALOG_CONTEXT, *PCOLUMNSET_DIALOG_CONTEXT; + +INT_PTR CALLBACK PhpColumnSetEditorDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +VOID PhShowColumnSetEditorDialog( + _In_ HWND ParentWindowHandle, + _In_ PWSTR SettingName + ) +{ + DialogBoxParam( + PhInstanceHandle, + MAKEINTRESOURCE(IDD_COLUMNSETS), + ParentWindowHandle, + PhpColumnSetEditorDlgProc, + (LPARAM)SettingName + ); +} + +VOID PhpMoveListViewItem( + _In_ HWND ListViewHandle, + _In_ INT ItemIndex1, + _In_ INT ItemIndex2 + ) +{ + LVITEM item1; + LVITEM item2; + WCHAR buffer1[MAX_PATH]; + WCHAR buffer2[MAX_PATH]; + + item1.mask = LVIF_TEXT | LVIF_PARAM | LVIF_STATE; + item1.stateMask = (UINT)-1; + item1.iItem = ItemIndex1; + item1.iSubItem = 0; + item1.cchTextMax = sizeof(buffer1); + item1.pszText = buffer1; + + item2.mask = LVIF_TEXT | LVIF_PARAM | LVIF_STATE; + item2.stateMask = (UINT)-1; + item2.iItem = ItemIndex2; + item2.iSubItem = 0; + item2.cchTextMax = sizeof(buffer2); + item2.pszText = buffer2; + + if ( + ListView_GetItem(ListViewHandle, &item1) && + ListView_GetItem(ListViewHandle, &item2) + ) + { + item1.iItem = ItemIndex2; + item2.iItem = ItemIndex1; + + ListView_SetItem(ListViewHandle, &item1); + ListView_SetItem(ListViewHandle, &item2); + } +} + +VOID PhpMoveSelectedListViewItemUp( + _In_ HWND ListViewHandle + ) +{ + INT lvItemIndex; + + lvItemIndex = ListView_GetNextItem(ListViewHandle, -1, LVNI_SELECTED); + + if (lvItemIndex != -1) + { + PhpMoveListViewItem(ListViewHandle, lvItemIndex, lvItemIndex - 1); + } + + SetFocus(ListViewHandle); + ListView_SetItemState(ListViewHandle, lvItemIndex - 1, LVNI_SELECTED, LVNI_SELECTED); + //ListView_EnsureVisible(ListViewHandle, lvItemIndex - 1, FALSE); +} + +VOID PhpMoveSelectedListViewItemDown( + _In_ HWND ListViewHandle + ) +{ + INT lvItemIndex; + + lvItemIndex = ListView_GetNextItem(ListViewHandle, -1, LVNI_SELECTED); + + if (lvItemIndex != -1) + { + PhpMoveListViewItem(ListViewHandle, lvItemIndex, lvItemIndex + 1); + } + + SetFocus(ListViewHandle); + ListView_SetItemState(ListViewHandle, lvItemIndex + 1, LVNI_SELECTED, LVNI_SELECTED); + //ListView_EnsureVisible(ListViewHandle, lvItemIndex + 1, FALSE); +} + +INT_PTR CALLBACK PhpColumnSetEditorDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + PCOLUMNSET_DIALOG_CONTEXT context = NULL; + + if (uMsg == WM_INITDIALOG) + { + context = PhAllocate(sizeof(COLUMNSET_DIALOG_CONTEXT)); + memset(context, 0, sizeof(COLUMNSET_DIALOG_CONTEXT)); + + context->SettingName = PhCreateString((PWSTR)lParam); + + SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)context); + } + else + { + context = (PCOLUMNSET_DIALOG_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom()); + } + + if (!context) + return FALSE; + + switch (uMsg) + { + case WM_INITDIALOG: + { + context->DialogHandle = hwndDlg; + context->ListViewHandle = GetDlgItem(hwndDlg, IDC_COLUMNSETLIST); + context->RenameButtonHandle = GetDlgItem(hwndDlg, IDC_RENAME); + context->MoveUpButtonHandle = GetDlgItem(hwndDlg, IDC_MOVEUP); + context->MoveDownButtonHandle = GetDlgItem(hwndDlg, IDC_MOVEDOWN); + context->RemoveButtonHandle = GetDlgItem(hwndDlg, IDC_REMOVE); + + PhCenterWindow(hwndDlg, GetParent(hwndDlg)); + + PhSetListViewStyle(context->ListViewHandle, FALSE, TRUE); + PhSetControlTheme(context->ListViewHandle, L"explorer"); + PhAddListViewColumn(context->ListViewHandle, 0, 0, 0, LVCFMT_LEFT, 250, L"Name"); + PhSetExtendedListView(context->ListViewHandle); + + context->ColumnSetList = PhInitializeColumnSetList(PhGetString(context->SettingName)); + + for (ULONG i = 0; i < context->ColumnSetList->Count; i++) + { + PPH_COLUMN_SET_ENTRY entry = context->ColumnSetList->Items[i]; + + PhAddListViewItem(context->ListViewHandle, MAXINT, entry->Name->Buffer, entry); + } + + Button_Enable(context->RenameButtonHandle, FALSE); + Button_Enable(context->MoveUpButtonHandle, FALSE); + Button_Enable(context->MoveDownButtonHandle, FALSE); + Button_Enable(context->RemoveButtonHandle, FALSE); + } + break; + case WM_DESTROY: + { + PhDeleteColumnSetList(context->ColumnSetList); + + RemoveProp(hwndDlg, PhMakeContextAtom()); + PhFree(context); + } + break; + case WM_COMMAND: + { + switch (GET_WM_COMMAND_ID(wParam, lParam)) + { + case IDCANCEL: + EndDialog(hwndDlg, IDCANCEL); + break; + case IDOK: + { + if (context->LabelEditActive) + break; + + PhSaveSettingsColumnList(PhGetString(context->SettingName), context->ColumnSetList); + + EndDialog(hwndDlg, IDOK); + } + break; + case IDC_RENAME: + { + INT lvItemIndex; + + lvItemIndex = ListView_GetNextItem(context->ListViewHandle, -1, LVNI_SELECTED); + + if (lvItemIndex != -1) + { + SetFocus(context->ListViewHandle); + ListView_EditLabel(context->ListViewHandle, lvItemIndex); + } + } + break; + case IDC_MOVEUP: + { + INT lvItemIndex; + PPH_COLUMN_SET_ENTRY entry; + ULONG index; + + PhpMoveSelectedListViewItemUp(context->ListViewHandle); + + lvItemIndex = ListView_GetNextItem(context->ListViewHandle, -1, LVNI_SELECTED); + + if (lvItemIndex != -1 && PhGetListViewItemParam(context->ListViewHandle, lvItemIndex, (PVOID *)&entry)) + { + index = PhFindItemList(context->ColumnSetList, entry); + + if (index != -1) + { + PhRemoveItemList(context->ColumnSetList, index); + PhInsertItemList(context->ColumnSetList, lvItemIndex, entry); + } + } + } + break; + case IDC_MOVEDOWN: + { + INT lvItemIndex; + PPH_COLUMN_SET_ENTRY entry; + ULONG index; + + PhpMoveSelectedListViewItemDown(context->ListViewHandle); + + lvItemIndex = ListView_GetNextItem(context->ListViewHandle, -1, LVNI_SELECTED); + + if (lvItemIndex != -1 && PhGetListViewItemParam(context->ListViewHandle, lvItemIndex, (PVOID *)&entry)) + { + index = PhFindItemList(context->ColumnSetList, entry); + + if (index != -1) + { + PhRemoveItemList(context->ColumnSetList, index); + PhInsertItemList(context->ColumnSetList, lvItemIndex, entry); + } + } + } + break; + case IDC_REMOVE: + { + INT lvItemIndex; + PPH_COLUMN_SET_ENTRY entry; + ULONG index; + + lvItemIndex = ListView_GetNextItem(context->ListViewHandle, -1, LVNI_SELECTED); + + if (lvItemIndex != -1 && PhGetListViewItemParam(context->ListViewHandle, lvItemIndex, (PVOID *)&entry)) + { + index = PhFindItemList(context->ColumnSetList, entry); + + if (index != -1) + { + PhRemoveItemList(context->ColumnSetList, index); + PhRemoveListViewItem(context->ListViewHandle, lvItemIndex); + + PhClearReference(&entry->Name); + PhClearReference(&entry->Setting); + PhClearReference(&entry->Sorting); + PhFree(entry); + } + + SetFocus(context->ListViewHandle); + ListView_SetItemState(context->ListViewHandle, 0, LVNI_SELECTED, LVNI_SELECTED); + //ListView_EnsureVisible(context->ListViewHandle, 0, FALSE); + } + } + break; + } + } + break; + case WM_NOTIFY: + { + LPNMHDR header = (LPNMHDR)lParam; + + switch (header->code) + { + case NM_DBLCLK: + { + INT lvItemIndex; + + lvItemIndex = ListView_GetNextItem(context->ListViewHandle, -1, LVNI_SELECTED); + + if (lvItemIndex != -1) + { + SetFocus(context->ListViewHandle); + ListView_EditLabel(context->ListViewHandle, lvItemIndex); + } + } + break; + case LVN_ITEMCHANGED: + { + LPNMLISTVIEW listview = (LPNMLISTVIEW)lParam; + INT index; + INT lvItemIndex; + INT count; + + index = listview->iItem; + lvItemIndex = ListView_GetNextItem(context->ListViewHandle, -1, LVNI_SELECTED); + count = ListView_GetItemCount(context->ListViewHandle); + + if (count == 0 || index == -1 || lvItemIndex == -1) + { + Button_Enable(context->RenameButtonHandle, FALSE); + Button_Enable(context->MoveUpButtonHandle, FALSE); + Button_Enable(context->MoveDownButtonHandle, FALSE); + Button_Enable(context->RemoveButtonHandle, FALSE); + break; + } + + if (index != lvItemIndex) + break; + + if (index == 0 && count == 1) + { + // First and last item + Button_Enable(context->MoveUpButtonHandle, FALSE); + Button_Enable(context->MoveDownButtonHandle, FALSE); + } + else if (index == (count - 1)) + { + // Last item + Button_Enable(context->MoveUpButtonHandle, TRUE); + Button_Enable(context->MoveDownButtonHandle, FALSE); + } + else if (index == 0) + { + // First item + Button_Enable(context->MoveUpButtonHandle, FALSE); + Button_Enable(context->MoveDownButtonHandle, TRUE); + } + else + { + Button_Enable(context->MoveUpButtonHandle, TRUE); + Button_Enable(context->MoveDownButtonHandle, TRUE); + } + + Button_Enable(context->RenameButtonHandle, TRUE); + Button_Enable(context->RemoveButtonHandle, TRUE); + } + break; + case LVN_BEGINLABELEDIT: + context->LabelEditActive = TRUE; + break; + case LVN_ENDLABELEDIT: + { + LV_DISPINFO* lvinfo = (LV_DISPINFO*)lParam; + + if (lvinfo->item.iItem != -1 && lvinfo->item.pszText) + { + BOOLEAN found = FALSE; + PPH_COLUMN_SET_ENTRY entry; + ULONG index; + + for (ULONG i = 0; i < context->ColumnSetList->Count; i++) + { + entry = context->ColumnSetList->Items[i]; + + if (PhEqualStringRef2(&entry->Name->sr, lvinfo->item.pszText, FALSE)) + { + found = TRUE; + break; + } + } + + if (!found && PhGetListViewItemParam(context->ListViewHandle, lvinfo->item.iItem, (PVOID *)&entry)) + { + index = PhFindItemList(context->ColumnSetList, entry); + + if (index != -1) + { + PhMoveReference(&entry->Name, PhCreateString(lvinfo->item.pszText)); + ListView_SetItemText(context->ListViewHandle, lvinfo->item.iItem, 0, lvinfo->item.pszText); + } + } + } + + context->LabelEditActive = FALSE; + } + break; + } + } + break; + } + + return FALSE; +} diff --git a/ProcessHacker/include/colsetmgr.h b/ProcessHacker/include/colsetmgr.h new file mode 100644 index 000000000000..4b39d58f2342 --- /dev/null +++ b/ProcessHacker/include/colsetmgr.h @@ -0,0 +1,40 @@ +#ifndef PH_COLSETMGR_H +#define PH_COLSETMGR_H + +typedef struct _PH_COLUMN_SET_ENTRY +{ + PPH_STRING Name; + PPH_STRING Setting; + PPH_STRING Sorting; +} PH_COLUMN_SET_ENTRY, *PPH_COLUMN_SET_ENTRY; + +PPH_LIST PhInitializeColumnSetList( + _In_ PWSTR SettingName + ); + +VOID PhDeleteColumnSetList( + _In_ PPH_LIST ColumnSetList + ); + +BOOLEAN PhLoadSettingsColumnSet( + _In_ PWSTR SettingName, + _In_ PPH_STRING ColumnSetName, + _Out_ PPH_STRING *TreeListSettings, + _Out_ PPH_STRING *TreeSortSettings + ); + +VOID PhSaveSettingsColumnSet( + _In_ PWSTR SettingName, + _In_ PPH_STRING ColumnSetName, + _In_ PPH_STRING TreeListSettings, + _In_ PPH_STRING TreeSortSettings + ); + +// Column Set Editor Dialog + +VOID PhShowColumnSetEditorDialog( + _In_ HWND ParentWindowHandle, + _In_ PWSTR SettingName + ); + +#endif diff --git a/ProcessHacker/include/phplug.h b/ProcessHacker/include/phplug.h index 18ae65492051..2be5efb9d36c 100644 --- a/ProcessHacker/include/phplug.h +++ b/ProcessHacker/include/phplug.h @@ -543,6 +543,7 @@ typedef struct _PH_PLUGIN_MENU_ITEM } PH_PLUGIN_MENU_ITEM, *PPH_PLUGIN_MENU_ITEM; // Location +#define PH_MENU_ITEM_LOCATION_HACKER 0 #define PH_MENU_ITEM_LOCATION_VIEW 1 #define PH_MENU_ITEM_LOCATION_TOOLS 2 diff --git a/ProcessHacker/include/proctree.h b/ProcessHacker/include/proctree.h index 5ddd6ef7b0b5..65dba46ed220 100644 --- a/ProcessHacker/include/proctree.h +++ b/ProcessHacker/include/proctree.h @@ -242,6 +242,16 @@ VOID PhSaveSettingsProcessTreeList( VOID ); +VOID PhLoadSettingsProcessTreeListEx( + _In_ PPH_STRING TreeListSettings, + _In_ PPH_STRING TreeSortSettings + ); + +VOID PhSaveSettingsProcessTreeListEx( + _Out_ PPH_STRING *TreeListSettings, + _Out_ PPH_STRING *TreeSortSettings + ); + VOID PhReloadSettingsProcessTreeList( VOID ); diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index 01e864229ad7..ad2de4ecbda7 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -37,6 +37,7 @@ #include #include +#include #include #include #include @@ -2351,6 +2352,73 @@ VOID PhMwpDispatchMenuCommand( } } break; + case ID_VIEW_ORGANIZECOLUMNSETS: + { + PhShowColumnSetEditorDialog(PhMainWndHandle, L"ProcessTreeColumnSetConfig"); + } + return; + case ID_VIEW_SAVECOLUMNSET: + { + PPH_EMENU_ITEM menuItem; + PPH_STRING columnSetName = NULL; + + menuItem = (PPH_EMENU_ITEM)ItemData; + + while (PhaChoiceDialog( + PhMainWndHandle, + L"Column Set Name", + L"Enter a name for this column set:", + NULL, + 0, + NULL, + PH_CHOICE_DIALOG_USER_CHOICE, + &columnSetName, + NULL, + NULL + )) + { + if (!PhIsNullOrEmptyString(columnSetName)) + break; + } + + if (!PhIsNullOrEmptyString(columnSetName)) + { + PPH_STRING treeSettings; + PPH_STRING sortSettings; + + // Query the current column configuration. + PhSaveSettingsProcessTreeListEx(&treeSettings, &sortSettings); + // Create the column set for this column configuration. + PhSaveSettingsColumnSet(L"ProcessTreeColumnSetConfig", columnSetName, treeSettings, sortSettings); + + PhDereferenceObject(treeSettings); + PhDereferenceObject(sortSettings); + } + } + return; + case ID_VIEW_LOADCOLUMNSET: + { + PPH_EMENU_ITEM menuItem; + PPH_STRING columnSetName; + PPH_STRING treeSettings; + PPH_STRING sortSettings; + + menuItem = (PPH_EMENU_ITEM)ItemData; + columnSetName = PhCreateString(menuItem->Text); + + // Query the selected column set. + if (PhLoadSettingsColumnSet(L"ProcessTreeColumnSetConfig", columnSetName, &treeSettings, &sortSettings)) + { + // Load the column configuration from the selected column set. + PhLoadSettingsProcessTreeListEx(treeSettings, sortSettings); + + PhDereferenceObject(treeSettings); + PhDereferenceObject(sortSettings); + } + + PhDereferenceObject(columnSetName); + } + return; } SendMessage(PhMainWndHandle, WM_COMMAND, ItemId, 0); @@ -2363,7 +2431,7 @@ VOID PhMwpInitializeSubMenu( { PPH_EMENU_ITEM menuItem; - if (Index == 0) // Hacker + if (Index == PH_MENU_ITEM_LOCATION_HACKER) // Hacker { // Fix some menu items. if (PhGetOwnTokenAttributes().Elevated) @@ -2387,7 +2455,7 @@ VOID PhMwpInitializeSubMenu( // Fix up the Computer menu. PhMwpSetupComputerMenu(Menu); } - else if (Index == 1) // View + else if (Index == PH_MENU_ITEM_LOCATION_VIEW) // View { PPH_EMENU_ITEM trayIconsMenuItem; ULONG i; @@ -2506,7 +2574,7 @@ VOID PhMwpInitializeSubMenu( if (PhMwpUpdateAutomatically && (menuItem = PhFindEMenuItem(Menu, 0, NULL, ID_VIEW_UPDATEAUTOMATICALLY))) menuItem->Flags |= PH_EMENU_CHECKED; } - else if (Index == 2) // Tools + else if (Index == PH_MENU_ITEM_LOCATION_TOOLS) // Tools { if (!PhGetIntegerSetting(L"HiddenProcessesMenuEnabled")) { @@ -3309,7 +3377,13 @@ VOID PhMwpUpdateUsersMenu( escapedMenuText = PhEscapeStringForMenuPrefix(&menuText->sr); PhDereferenceObject(menuText); - userMenu = PhCreateEMenuItem(PH_EMENU_TEXT_OWNED, IDR_USER, PhAllocateCopy(escapedMenuText->Buffer, escapedMenuText->Length + sizeof(WCHAR)), NULL, UlongToPtr(sessions[i].SessionId)); + userMenu = PhCreateEMenuItem( + PH_EMENU_TEXT_OWNED, + IDR_USER, + PhAllocateCopy(escapedMenuText->Buffer, escapedMenuText->Length + sizeof(WCHAR)), + NULL, + UlongToPtr(sessions[i].SessionId) + ); PhLoadResourceEMenuItem(userMenu, PhInstanceHandle, MAKEINTRESOURCE(IDR_USER), 0); PhInsertEMenuItem(UsersMenu, userMenu, -1); diff --git a/ProcessHacker/mwpgproc.c b/ProcessHacker/mwpgproc.c index f0b222193d3d..bc88c3fd8fda 100644 --- a/ProcessHacker/mwpgproc.c +++ b/ProcessHacker/mwpgproc.c @@ -32,6 +32,7 @@ #include #include +#include #include #include #include @@ -110,6 +111,7 @@ BOOLEAN PhMwpProcessesPageCallback( PPH_EMENU menu = menuInfo->Menu; ULONG startIndex = menuInfo->StartIndex; PPH_EMENU_ITEM menuItem; + PPH_EMENU_ITEM columnSetMenuItem; PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_VIEW_HIDEPROCESSESFROMOTHERUSERS, L"Hide processes from other users", NULL, NULL), startIndex); PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_VIEW_HIDESIGNEDPROCESSES, L"Hide signed processes", NULL, NULL), startIndex + 1); @@ -135,6 +137,38 @@ BOOLEAN PhMwpProcessesPageCallback( menuItem->Flags |= PH_EMENU_DISABLED; } } + + PhInsertEMenuItem(menu, PhCreateEMenuItem(PH_EMENU_SEPARATOR, 0, NULL, NULL, NULL), startIndex + 4); + PhInsertEMenuItem(menu, menuItem = PhCreateEMenuItem(0, ID_VIEW_ORGANIZECOLUMNSETS, L"Organize column sets...", NULL, NULL), startIndex + 5); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_VIEW_SAVECOLUMNSET, L"Save column set...", NULL, NULL), startIndex + 6); + PhInsertEMenuItem(menu, columnSetMenuItem = PhCreateEMenuItem(0, 0, L"&Load column set", NULL, NULL), startIndex + 7); + + // Add column set sub menu entries. + { + ULONG index; + PPH_LIST columnSetList; + + columnSetList = PhInitializeColumnSetList(L"ProcessTreeColumnSetConfig"); + + if (!columnSetList->Count) + { + menuItem->Flags |= PH_EMENU_DISABLED; + columnSetMenuItem->Flags |= PH_EMENU_DISABLED; + } + else + { + for (index = 0; index < columnSetList->Count; index++) + { + PPH_COLUMN_SET_ENTRY entry = columnSetList->Items[index]; + + menuItem = PhCreateEMenuItem(PH_EMENU_TEXT_OWNED, ID_VIEW_LOADCOLUMNSET, + PhAllocateCopy(entry->Name->Buffer, entry->Name->Length + sizeof(WCHAR)), NULL, NULL); + PhInsertEMenuItem(columnSetMenuItem, menuItem, -1); + } + } + + PhDeleteColumnSetList(columnSetList); + } } return TRUE; case MainTabPageLoadSettings: diff --git a/ProcessHacker/proctree.c b/ProcessHacker/proctree.c index a57c7792c777..7dadc864a055 100644 --- a/ProcessHacker/proctree.c +++ b/ProcessHacker/proctree.c @@ -263,6 +263,33 @@ VOID PhSaveSettingsProcessTreeList( PhDereferenceObject(sortSettings); } +VOID PhLoadSettingsProcessTreeListEx( + _In_ PPH_STRING TreeListSettings, + _In_ PPH_STRING TreeSortSettings + ) +{ + PhCmLoadSettingsEx(ProcessTreeListHandle, &ProcessTreeListCm, 0, &TreeListSettings->sr, &TreeSortSettings->sr); + + if (PhGetIntegerSetting(L"EnableInstantTooltips")) + { + SendMessage(TreeNew_GetTooltips(ProcessTreeListHandle), TTM_SETDELAYTIME, TTDT_INITIAL, 0); + } +} + +VOID PhSaveSettingsProcessTreeListEx( + _Out_ PPH_STRING *TreeListSettings, + _Out_ PPH_STRING *TreeSortSettings + ) +{ + PPH_STRING settings; + PPH_STRING sortSettings; + + settings = PhCmSaveSettingsEx(ProcessTreeListHandle, &ProcessTreeListCm, 0, &sortSettings); + + *TreeListSettings = settings; + *TreeSortSettings = sortSettings; +} + VOID PhReloadSettingsProcessTreeList( VOID ) diff --git a/ProcessHacker/resource.h b/ProcessHacker/resource.h index b53551cec92b..82c94b02a94a 100644 --- a/ProcessHacker/resource.h +++ b/ProcessHacker/resource.h @@ -128,6 +128,7 @@ #define IDD_PLUGINPROPERTIES 228 #define IDD_PLUGINSDISABLED 241 #define IDD_PROCWMIPROVIDERS 242 +#define IDD_COLUMNSETS 243 #define IDC_TERMINATE 1003 #define IDC_FILEICON 1005 #define IDC_FILE 1006 @@ -221,6 +222,7 @@ #define IDC_MORE 1079 #define IDC_VIEWMITIGATION 1080 #define IDC_REPLACETASKMANAGER 1080 +#define IDC_RENAME 1080 #define IDC_VIEWPARENTPROCESS 1081 #define IDC_OPENFILENAME 1082 #define IDC_LIMITS 1083 @@ -359,6 +361,7 @@ #define IDC_ZIOOTHER_V 1172 #define IDC_ZIOOTHERBYTES_V 1173 #define IDC_MOVEDOWN 1176 +#define IDC_REMOVE 1177 #define IDC_DISPLAYNAME 1179 #define IDC_ZPRIORITY_V 1181 #define IDC_ZCYCLES_V 1182 @@ -528,6 +531,7 @@ #define IDC_PLUGINTREE 1400 #define IDC_DISABLED 1401 #define IDC_LIST_DISABLED 1402 +#define IDC_COLUMNSETLIST 1403 #define ID_HACKER_EXIT 40001 #define ID_PROCESS_PROPERTIES 40006 #define ID_PROCESS_TERMINATE 40007 @@ -697,6 +701,9 @@ #define ID_EMPTY_EMPTYSTANDBYLIST 40252 #define ID_EMPTY_EMPTYPRIORITY0STANDBYLIST 40253 #define IDC_BACK 40255 +#define ID_VIEW_ORGANIZECOLUMNSETS 40256 +#define ID_VIEW_SAVECOLUMNSET 40257 +#define ID_VIEW_LOADCOLUMNSET 40258 #define ID_DIGIT1 40263 #define ID_DIGIT2 40264 #define ID_DIGIT3 40265 @@ -732,9 +739,9 @@ // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 243 +#define _APS_NEXT_RESOURCE_VALUE 244 #define _APS_NEXT_COMMAND_VALUE 40297 -#define _APS_NEXT_CONTROL_VALUE 1403 +#define _APS_NEXT_CONTROL_VALUE 1404 #define _APS_NEXT_SYMED_VALUE 170 #endif #endif diff --git a/ProcessHacker/settings.c b/ProcessHacker/settings.c index dad506a77231..6df4cc013175 100644 --- a/ProcessHacker/settings.c +++ b/ProcessHacker/settings.c @@ -127,6 +127,7 @@ VOID PhAddDefaultSettings( PhpAddStringSetting(L"PluginManagerTreeListColumns", L""); PhpAddStringSetting(L"PluginsDirectory", L"plugins"); PhpAddStringSetting(L"ProcessServiceListViewColumns", L""); + PhpAddStringSetting(L"ProcessTreeColumnSetConfig", L""); PhpAddStringSetting(L"ProcessTreeListColumns", L""); PhpAddStringSetting(L"ProcessTreeListSort", L"0,0"); // 0, NoSortOrder PhpAddStringSetting(L"ProcPropPage", L"General"); From d238cba0e166857a507ee475093096fde941cbf7 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 1 Dec 2017 22:07:14 +1100 Subject: [PATCH 0600/2058] Fix toolbar regression updating from 2.39 to 3.0 --- plugins/ToolStatus/toolstatus.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/ToolStatus/toolstatus.h b/plugins/ToolStatus/toolstatus.h index fee12ad7a937..b5e370dcf73f 100644 --- a/plugins/ToolStatus/toolstatus.h +++ b/plugins/ToolStatus/toolstatus.h @@ -41,7 +41,7 @@ #define PLUGIN_NAME TOOLSTATUS_PLUGIN_NAME #define SETTING_NAME_TOOLSTATUS_CONFIG (PLUGIN_NAME L".Config") #define SETTING_NAME_REBAR_CONFIG (PLUGIN_NAME L".RebarConfig") -#define SETTING_NAME_TOOLBAR_CONFIG (PLUGIN_NAME L".ToolbarConfig") +#define SETTING_NAME_TOOLBAR_CONFIG (PLUGIN_NAME L".ToolbarButtonConfig") #define SETTING_NAME_STATUSBAR_CONFIG (PLUGIN_NAME L".StatusbarConfig") #define SETTING_NAME_TOOLBAR_THEME (PLUGIN_NAME L".ToolbarTheme") #define SETTING_NAME_TOOLBARDISPLAYSTYLE (PLUGIN_NAME L".ToolbarDisplayStyle") From 9b431bd69ee8d1ef4a425074eaf91ab1cf74a395 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 3 Dec 2017 11:53:29 +1100 Subject: [PATCH 0601/2058] Add missing description for DisallowStrippedImages --- ProcessHacker/procmtgn.c | 1 + 1 file changed, 1 insertion(+) diff --git a/ProcessHacker/procmtgn.c b/ProcessHacker/procmtgn.c index cf72c479d837..1f07687c9bea 100644 --- a/ProcessHacker/procmtgn.c +++ b/ProcessHacker/procmtgn.c @@ -177,6 +177,7 @@ BOOLEAN PhDescribeProcessMitigationPolicy( PhAppendStringBuilder2(&sb, L" ("); if (data->EnableHighEntropy) PhAppendStringBuilder2(&sb, L"high entropy, "); if (data->EnableForceRelocateImages) PhAppendStringBuilder2(&sb, L"force relocate, "); + if (data->DisallowStrippedImages) PhAppendStringBuilder2(&sb, L"disallow stripped, "); if (PhEndsWithStringRef2(&sb.String->sr, L", ", FALSE)) PhRemoveEndStringBuilder(&sb, 2); PhAppendCharStringBuilder(&sb, ')'); } From bfca80bd7f365241e6d919fba209650fbe186451 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 3 Dec 2017 11:57:47 +1100 Subject: [PATCH 0602/2058] Fix column set leak #180 --- ProcessHacker/mainwnd.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index ad2de4ecbda7..c803890aa2ef 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -2381,7 +2381,7 @@ VOID PhMwpDispatchMenuCommand( break; } - if (!PhIsNullOrEmptyString(columnSetName)) + if (columnSetName) { PPH_STRING treeSettings; PPH_STRING sortSettings; @@ -2393,6 +2393,7 @@ VOID PhMwpDispatchMenuCommand( PhDereferenceObject(treeSettings); PhDereferenceObject(sortSettings); + PhDereferenceObject(columnSetName); } } return; From 2b3180c117e75b1d8e49dcbe9fbb8aced41927ff Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 3 Dec 2017 12:01:08 +1100 Subject: [PATCH 0603/2058] Update PCRE to 10.30 (https://www.pcre.org/changelog.txt) --- ProcessHacker/ProcessHacker.vcxproj | 8 +- ProcessHacker/pcre/config.h | 105 +- ProcessHacker/pcre/pcre2.h | 283 +- ProcessHacker/pcre/pcre2_auto_possess.c | 12 +- ProcessHacker/pcre/pcre2_chartables.c | 1 - ProcessHacker/pcre/pcre2_compile.c | 764 +- ProcessHacker/pcre/pcre2_config.c | 25 +- ProcessHacker/pcre/pcre2_context.c | 125 +- ProcessHacker/pcre/pcre2_dfa_match.c | 434 +- ProcessHacker/pcre/pcre2_error.c | 15 +- ProcessHacker/pcre/pcre2_find_bracket.c | 2 - ProcessHacker/pcre/pcre2_internal.h | 124 +- ProcessHacker/pcre/pcre2_intmodedep.h | 152 +- ProcessHacker/pcre/pcre2_jit_compile.c | 3330 +++++--- ProcessHacker/pcre/pcre2_jit_match.c | 8 +- ProcessHacker/pcre/pcre2_jit_test.c | 30 +- ProcessHacker/pcre/pcre2_maketables.c | 2 - ProcessHacker/pcre/pcre2_match.c | 9950 +++++++++++------------ ProcessHacker/pcre/pcre2_match_data.c | 7 +- ProcessHacker/pcre/pcre2_newline.c | 1 - ProcessHacker/pcre/pcre2_ord2utf.c | 2 - ProcessHacker/pcre/pcre2_pattern_info.c | 34 +- ProcessHacker/pcre/pcre2_printint.c | 5 +- ProcessHacker/pcre/pcre2_serialize.c | 6 +- ProcessHacker/pcre/pcre2_string_utils.c | 1 - ProcessHacker/pcre/pcre2_study.c | 39 +- ProcessHacker/pcre/pcre2_substitute.c | 1 - ProcessHacker/pcre/pcre2_substring.c | 2 +- ProcessHacker/pcre/pcre2_tables.c | 449 +- ProcessHacker/pcre/pcre2_ucd.c | 5448 +++++++------ ProcessHacker/pcre/pcre2_ucp.h | 38 +- ProcessHacker/pcre/pcre2_valid_utf.c | 9 +- ProcessHacker/pcre/pcre2_xclass.c | 1 - ProcessHacker/pcre/pcre2posix.c | 21 +- ProcessHacker/pcre/pcre2posix.h | 6 +- 35 files changed, 11625 insertions(+), 9815 deletions(-) diff --git a/ProcessHacker/ProcessHacker.vcxproj b/ProcessHacker/ProcessHacker.vcxproj index 45896e808026..f5b99fe1b1a1 100644 --- a/ProcessHacker/ProcessHacker.vcxproj +++ b/ProcessHacker/ProcessHacker.vcxproj @@ -85,7 +85,7 @@ Disabled $(SolutionDir)phnt\include;$(SolutionDir)phlib\include;include;%(AdditionalIncludeDirectories) - _PHLIB_;_PHAPP_;_WINDOWS;WIN32;DEBUG;%(PreprocessorDefinitions);$(ExternalCompilerOptions) + _PHLIB_;_PHAPP_;_WINDOWS;HAVE_CONFIG_H;WIN32;DEBUG;%(PreprocessorDefinitions);$(ExternalCompilerOptions) EnableFastChecks MultiThreadedDebug Level3 @@ -117,7 +117,7 @@ Disabled $(SolutionDir)phnt\include;$(SolutionDir)phlib\include;include;%(AdditionalIncludeDirectories) - _PHLIB_;_PHAPP_;_WINDOWS;WIN64;DEBUG;%(PreprocessorDefinitions);$(ExternalCompilerOptions) + _PHLIB_;_PHAPP_;_WINDOWS;HAVE_CONFIG_H;WIN64;DEBUG;%(PreprocessorDefinitions);$(ExternalCompilerOptions) EnableFastChecks MultiThreadedDebug Level3 @@ -151,7 +151,7 @@ MaxSpeed true $(SolutionDir)phnt\include;$(SolutionDir)phlib\include;include;%(AdditionalIncludeDirectories) - _PHLIB_;_PHAPP_;_WINDOWS;WIN32;NDEBUG;%(PreprocessorDefinitions);$(ExternalCompilerOptions) + _PHLIB_;_PHAPP_;_WINDOWS;HAVE_CONFIG_H;WIN32;NDEBUG;%(PreprocessorDefinitions);$(ExternalCompilerOptions) true MultiThreaded false @@ -190,7 +190,7 @@ MaxSpeed true $(SolutionDir)phnt\include;$(SolutionDir)phlib\include;include;%(AdditionalIncludeDirectories) - _PHLIB_;_PHAPP_;_WINDOWS;WIN64;NDEBUG;%(PreprocessorDefinitions);$(ExternalCompilerOptions) + _PHLIB_;_PHAPP_;_WINDOWS;HAVE_CONFIG_H;WIN64;NDEBUG;%(PreprocessorDefinitions);$(ExternalCompilerOptions) true MultiThreaded false diff --git a/ProcessHacker/pcre/config.h b/ProcessHacker/pcre/config.h index b71d730d3561..2843be569595 100644 --- a/ProcessHacker/pcre/config.h +++ b/ProcessHacker/pcre/config.h @@ -1,6 +1,6 @@ +/* src/config.h. Generated from config.h.in by configure. */ /* src/config.h.in. Generated from configure.ac by autoheader. */ - /* PCRE2 is written in Standard C, but there are a few non-standard things it can cope with, allowing it to run on SunOS4 and other "close to standard" systems. @@ -154,13 +154,11 @@ sure both macros are undefined; an emulation function will then be used. */ /* Define to 1 if you have the header file. */ #undef HAVE_ZLIB_H -/* PCRE2 uses recursive function calls to handle backtracking while matching. - This can sometimes be a problem on systems that have stacks of limited - size. Define HEAP_MATCH_RECURSE to any value to get a version that doesn't - use recursion in the match() function; instead it creates its own stack by - steam using memory from the heap. For more detail, see the comments and - other stuff just above the match() function. */ -#undef HEAP_MATCH_RECURSE +/* This limits the amount of memory that pcre2_match() may use while matching + a pattern. The value is in kilobytes. */ +#ifndef HEAP_LIMIT +#define HEAP_LIMIT 20000000 +#endif /* The value of LINK_SIZE determines the number of bytes used to store links as offsets within the compiled regex. The default is 2, which allows for @@ -172,28 +170,31 @@ sure both macros are undefined; an emulation function will then be used. */ #endif /* Define to the sub-directory where libtool stores uninstalled libraries. */ -#undef LT_OBJDIR +/* This is ignored unless you are using libtool. */ +#ifndef LT_OBJDIR +#define LT_OBJDIR ".libs/" +#endif /* The value of MATCH_LIMIT determines the default number of times the - internal match() function can be called during a single execution of - pcre2_match(). There is a runtime interface for setting a different limit. - The limit exists in order to catch runaway regular expressions that take - for ever to determine that they do not match. The default is set very large - so that it does not accidentally catch legitimate cases. */ + pcre2_match() function can record a backtrack position during a single + matching attempt. There is a runtime interface for setting a different + limit. The limit exists in order to catch runaway regular expressions that + take for ever to determine that they do not match. The default is set very + large so that it does not accidentally catch legitimate cases. */ #ifndef MATCH_LIMIT #define MATCH_LIMIT 10000000 #endif -/* The above limit applies to all calls of match(), whether or not they - increase the recursion depth. In some environments it is desirable to limit - the depth of recursive calls of match() more strictly, in order to restrict - the maximum amount of stack (or heap, if HEAP_MATCH_RECURSE is defined) - that is used. The value of MATCH_LIMIT_RECURSION applies only to recursive - calls of match(). To have any useful effect, it must be less than the value - of MATCH_LIMIT. The default is to use the same value as MATCH_LIMIT. There - is a runtime method for setting a different limit. */ -#ifndef MATCH_LIMIT_RECURSION -#define MATCH_LIMIT_RECURSION MATCH_LIMIT +/* The above limit applies to all backtracks, whether or not they are nested. + In some environments it is desirable to limit the nesting of backtracking + (that is, the depth of tree that is searched) more strictly, in order to + restrict the maximum amount of heap memory that is used. The value of + MATCH_LIMIT_DEPTH provides this facility. To have any useful effect, it + must be less than the value of MATCH_LIMIT. The default is to use the same + value as MATCH_LIMIT. There is a runtime method for setting a different + limit. */ +#ifndef MATCH_LIMIT_DEPTH +#define MATCH_LIMIT_DEPTH MATCH_LIMIT #endif /* This limit is parameterized just in case anybody ever wants to change it. @@ -215,32 +216,32 @@ sure both macros are undefined; an emulation function will then be used. */ /* The value of NEWLINE_DEFAULT determines the default newline character sequence. PCRE2 client programs can override this by selecting other values - at run time. The valid values are 1 (CR), 2 (LF), 3 (CRLF), 4 (ANY), and 5 - (ANYCRLF). */ + at run time. The valid values are 1 (CR), 2 (LF), 3 (CRLF), 4 (ANY), 5 + (ANYCRLF), and 6 (NUL). */ #ifndef NEWLINE_DEFAULT #define NEWLINE_DEFAULT 4 #endif /* Name of package */ -#undef PACKAGE +#define PACKAGE "pcre2" /* Define to the address where bug reports for this package should be sent. */ -#undef PACKAGE_BUGREPORT +#define PACKAGE_BUGREPORT "" /* Define to the full name of this package. */ -#undef PACKAGE_NAME +#define PACKAGE_NAME "PCRE2" /* Define to the full name and version of this package. */ -#undef PACKAGE_STRING +#define PACKAGE_STRING "PCRE2 10.30" /* Define to the one symbol short name of this package. */ -#undef PACKAGE_TARNAME +#define PACKAGE_TARNAME "pcre2" /* Define to the home page for this package. */ -#undef PACKAGE_URL +#define PACKAGE_URL "" /* Define to the version of this package. */ -#undef PACKAGE_VERSION +#define PACKAGE_VERSION "10.30" /* The value of PARENS_NEST_LIMIT specifies the maximum depth of nested parentheses (of any kind) in a pattern. This limits the amount of system @@ -267,19 +268,9 @@ sure both macros are undefined; an emulation function will then be used. */ #define PCRE2GREP_MAX_BUFSIZE 1048576 #endif -/* to make a symbol visible */ -#undef PCRE2POSIX_EXP_DECL - -/* to make a symbol visible */ -#undef PCRE2POSIX_EXP_DEFN - /* Define to any value to include debugging code. */ #undef PCRE2_DEBUG -/* to make a symbol visible */ -#undef PCRE2_EXP_DECL - - /* If you are compiling for a system other than a Unix-like system or Win32, and it needs some magic to be inserted before the definition of a function that is exported by the library, define this macro to @@ -300,6 +291,11 @@ sure both macros are undefined; an emulation function will then be used. */ your system. */ #undef PTHREAD_CREATE_JOINABLE +/* Define to any non-zero number to enable support for SELinux compatible + executable memory allocator in JIT. Note that this will have no effect + unless SUPPORT_JIT is also defined. */ +/* #undef SLJIT_PROT_EXECUTABLE_ALLOCATOR */ + /* Define to 1 if you have the ANSI C header files. */ #ifndef STDC_HEADERS #define STDC_HEADERS 1 @@ -335,10 +331,10 @@ sure both macros are undefined; an emulation function will then be used. */ #endif /* Define to any value to enable the 32 bit PCRE2 library. */ -//#undef SUPPORT_PCRE2_32 +#undef SUPPORT_PCRE2_32 /* Define to any value to enable the 8 bit PCRE2 library. */ -//#undef SUPPORT_PCRE2_8 +#undef SUPPORT_PCRE2_8 /* Define to any value to enable support for Unicode and UTF encoding. This will work even in an EBCDIC environment, but it is incompatible with the @@ -353,28 +349,27 @@ sure both macros are undefined; an emulation function will then be used. */ /* Enable extensions on AIX 3, Interix. */ #ifndef _ALL_SOURCE -# undef _ALL_SOURCE +# define _ALL_SOURCE 1 #endif /* Enable GNU extensions on systems that have them. */ #ifndef _GNU_SOURCE -# undef _GNU_SOURCE +# define _GNU_SOURCE 1 #endif /* Enable threading extensions on Solaris. */ #ifndef _POSIX_PTHREAD_SEMANTICS -# undef _POSIX_PTHREAD_SEMANTICS +# define _POSIX_PTHREAD_SEMANTICS 1 #endif /* Enable extensions on HP NonStop. */ #ifndef _TANDEM_SOURCE -# undef _TANDEM_SOURCE +# define _TANDEM_SOURCE 1 #endif /* Enable general extensions on Solaris. */ #ifndef __EXTENSIONS__ -# undef __EXTENSIONS__ +# define __EXTENSIONS__ 1 #endif - /* Version number of package */ -#undef VERSION +#define VERSION "10.30" /* Define to 1 if on MINIX. */ #undef _MINIX @@ -387,11 +382,11 @@ sure both macros are undefined; an emulation function will then be used. */ #undef _POSIX_SOURCE /* Define to empty if `const' does not conform to ANSI C. */ -#undef const +/* #undef const */ /* Define to the type of a signed integer type of width exactly 64 bits if such a type exists and the standard includes do not define it. */ -#undef int64_t +/* #undef int64_t */ /* Define to `unsigned int' if does not define. */ -#undef size_t +/* #undef size_t */ diff --git a/ProcessHacker/pcre/pcre2.h b/ProcessHacker/pcre/pcre2.h index 550a2b93d81f..2cceb5cb79ba 100644 --- a/ProcessHacker/pcre/pcre2.h +++ b/ProcessHacker/pcre/pcre2.h @@ -5,22 +5,22 @@ /* This is the public header file for the PCRE library, second API, to be #included by applications that call PCRE2 functions. -Copyright (c) 2016 University of Cambridge + Copyright (c) 2016-2017 University of Cambridge ----------------------------------------------------------------------------- Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: -* Redistributions of source code must retain the above copyright notice, -this list of conditions and the following disclaimer. + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. -* Redistributions in binary form must reproduce the above copyright -notice, this list of conditions and the following disclaimer in the -documentation and/or other materials provided with the distribution. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. -* Neither the name of the University of Cambridge nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. + * Neither the name of the University of Cambridge nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE @@ -48,9 +48,9 @@ POSSIBILITY OF SUCH DAMAGE. /* The current PCRE version information. */ #define PCRE2_MAJOR 10 -#define PCRE2_MINOR 23 +#define PCRE2_MINOR 30 #define PCRE2_PRERELEASE -#define PCRE2_DATE 2017-02-14 +#define PCRE2_DATE 2017-08-14 /* When an application links to a PCRE DLL in Windows, the symbols that are imported have to be identified as such. When building PCRE2, the appropriate @@ -77,7 +77,7 @@ don't change existing definitions of PCRE2_EXP_DECL. */ a "calling convention" before exported function names. (This is secondhand information; I know nothing about MSVC myself). For example, something like -void __cdecl function(....) + void __cdecl function(....) might be needed. In order so make this easy, all the exported functions have PCRE2_CALL_CONVENTION just before their names. It is rarely needed; if not @@ -100,23 +100,24 @@ uint8_t, UCHAR_MAX, etc are defined. */ extern "C" { #endif - /* The following option bits can be passed to pcre2_compile(), pcre2_match(), - or pcre2_dfa_match(). PCRE2_NO_UTF_CHECK affects only the function to which it - is passed. Put these bits at the most significant end of the options word so - others can be added next to them */ +/* The following option bits can be passed to pcre2_compile(), pcre2_match(), +or pcre2_dfa_match(). PCRE2_NO_UTF_CHECK affects only the function to which it +is passed. Put these bits at the most significant end of the options word so +others can be added next to them */ #define PCRE2_ANCHORED 0x80000000u #define PCRE2_NO_UTF_CHECK 0x40000000u +#define PCRE2_ENDANCHORED 0x20000000u - /* The following option bits can be passed only to pcre2_compile(). However, - they may affect compilation, JIT compilation, and/or interpretive execution. - The following tags indicate which: +/* The following option bits can be passed only to pcre2_compile(). However, +they may affect compilation, JIT compilation, and/or interpretive execution. +The following tags indicate which: - C alters what is compiled by pcre2_compile() - J alters what is compiled by pcre2_jit_compile() - M is inspected during pcre2_match() execution - D is inspected during pcre2_dfa_match() execution - */ +C alters what is compiled by pcre2_compile() +J alters what is compiled by pcre2_jit_compile() +M is inspected during pcre2_match() execution +D is inspected during pcre2_dfa_match() execution +*/ #define PCRE2_ALLOW_EMPTY_CLASS 0x00000001u /* C */ #define PCRE2_ALT_BSUX 0x00000002u /* C */ @@ -142,17 +143,26 @@ extern "C" { #define PCRE2_ALT_CIRCUMFLEX 0x00200000u /* J M D */ #define PCRE2_ALT_VERBNAMES 0x00400000u /* C */ #define PCRE2_USE_OFFSET_LIMIT 0x00800000u /* J M D */ +#define PCRE2_EXTENDED_MORE 0x01000000u /* C */ +#define PCRE2_LITERAL 0x02000000u /* C */ + +/* An additional compile options word is available in the compile context. */ + +#define PCRE2_EXTRA_ALLOW_SURROGATE_ESCAPES 0x00000001u /* C */ +#define PCRE2_EXTRA_BAD_ESCAPE_IS_LITERAL 0x00000002u /* C */ +#define PCRE2_EXTRA_MATCH_WORD 0x00000004u /* C */ +#define PCRE2_EXTRA_MATCH_LINE 0x00000008u /* C */ - /* These are for pcre2_jit_compile(). */ +/* These are for pcre2_jit_compile(). */ #define PCRE2_JIT_COMPLETE 0x00000001u /* For full matching */ #define PCRE2_JIT_PARTIAL_SOFT 0x00000002u #define PCRE2_JIT_PARTIAL_HARD 0x00000004u - /* These are for pcre2_match(), pcre2_dfa_match(), and pcre2_jit_match(). Note - that PCRE2_ANCHORED and PCRE2_NO_UTF_CHECK can also be passed to these - functions (though pcre2_jit_match() ignores the latter since it bypasses all - sanity checks). */ +/* These are for pcre2_match(), pcre2_dfa_match(), and pcre2_jit_match(). Note +that PCRE2_ANCHORED and PCRE2_NO_UTF_CHECK can also be passed to these +functions (though pcre2_jit_match() ignores the latter since it bypasses all +sanity checks). */ #define PCRE2_NOTBOL 0x00000001u #define PCRE2_NOTEOL 0x00000002u @@ -161,13 +171,13 @@ extern "C" { #define PCRE2_PARTIAL_SOFT 0x00000010u #define PCRE2_PARTIAL_HARD 0x00000020u - /* These are additional options for pcre2_dfa_match(). */ +/* These are additional options for pcre2_dfa_match(). */ #define PCRE2_DFA_RESTART 0x00000040u #define PCRE2_DFA_SHORTEST 0x00000080u - /* These are additional options for pcre2_substitute(), which passes any others - through to pcre2_match(). */ +/* These are additional options for pcre2_substitute(), which passes any others +through to pcre2_match(). */ #define PCRE2_SUBSTITUTE_GLOBAL 0x00000100u #define PCRE2_SUBSTITUTE_EXTENDED 0x00000200u @@ -175,30 +185,41 @@ extern "C" { #define PCRE2_SUBSTITUTE_UNKNOWN_UNSET 0x00000800u #define PCRE2_SUBSTITUTE_OVERFLOW_LENGTH 0x00001000u - /* A further option for pcre2_match(), not allowed for pcre2_dfa_match(), - ignored for pcre2_jit_match(). */ +/* A further option for pcre2_match(), not allowed for pcre2_dfa_match(), +ignored for pcre2_jit_match(). */ #define PCRE2_NO_JIT 0x00002000u - /* Newline and \R settings, for use in compile contexts. The newline values - must be kept in step with values set in config.h and both sets must all be - greater than zero. */ +/* Options for pcre2_pattern_convert(). */ + +#define PCRE2_CONVERT_UTF 0x00000001u +#define PCRE2_CONVERT_NO_UTF_CHECK 0x00000002u +#define PCRE2_CONVERT_POSIX_BASIC 0x00000004u +#define PCRE2_CONVERT_POSIX_EXTENDED 0x00000008u +#define PCRE2_CONVERT_GLOB 0x00000010u +#define PCRE2_CONVERT_GLOB_NO_WILD_SEPARATOR 0x00000030u +#define PCRE2_CONVERT_GLOB_NO_STARSTAR 0x00000050u + +/* Newline and \R settings, for use in compile contexts. The newline values +must be kept in step with values set in config.h and both sets must all be +greater than zero. */ #define PCRE2_NEWLINE_CR 1 #define PCRE2_NEWLINE_LF 2 #define PCRE2_NEWLINE_CRLF 3 #define PCRE2_NEWLINE_ANY 4 #define PCRE2_NEWLINE_ANYCRLF 5 +#define PCRE2_NEWLINE_NUL 6 #define PCRE2_BSR_UNICODE 1 #define PCRE2_BSR_ANYCRLF 2 - /* Error codes: no match and partial match are "expected" errors. */ +/* Error codes: no match and partial match are "expected" errors. */ #define PCRE2_ERROR_NOMATCH (-1) #define PCRE2_ERROR_PARTIAL (-2) - /* Error codes for UTF-8 validity checks */ +/* Error codes for UTF-8 validity checks */ #define PCRE2_ERROR_UTF8_ERR1 (-3) #define PCRE2_ERROR_UTF8_ERR2 (-4) @@ -222,21 +243,21 @@ extern "C" { #define PCRE2_ERROR_UTF8_ERR20 (-22) #define PCRE2_ERROR_UTF8_ERR21 (-23) - /* Error codes for UTF-16 validity checks */ +/* Error codes for UTF-16 validity checks */ #define PCRE2_ERROR_UTF16_ERR1 (-24) #define PCRE2_ERROR_UTF16_ERR2 (-25) #define PCRE2_ERROR_UTF16_ERR3 (-26) - /* Error codes for UTF-32 validity checks */ +/* Error codes for UTF-32 validity checks */ #define PCRE2_ERROR_UTF32_ERR1 (-27) #define PCRE2_ERROR_UTF32_ERR2 (-28) - /* Error codes for pcre2[_dfa]_match(), substring extraction functions, context - functions, and serializing functions. They are in numerical order. Originally - they were in alphabetical order too, but now that PCRE2 is released, the - numbers must not be changed. */ +/* Error codes for pcre2[_dfa]_match(), substring extraction functions, context +functions, and serializing functions. They are in numerical order. Originally +they were in alphabetical order too, but now that PCRE2 is released, the +numbers must not be changed. */ #define PCRE2_ERROR_BADDATA (-29) #define PCRE2_ERROR_MIXEDTABLES (-30) /* Name was changed */ @@ -262,7 +283,8 @@ extern "C" { #define PCRE2_ERROR_NOUNIQUESUBSTRING (-50) #define PCRE2_ERROR_NULL (-51) #define PCRE2_ERROR_RECURSELOOP (-52) -#define PCRE2_ERROR_RECURSIONLIMIT (-53) +#define PCRE2_ERROR_DEPTHLIMIT (-53) +#define PCRE2_ERROR_RECURSIONLIMIT (-53) /* Obsolete synonym */ #define PCRE2_ERROR_UNAVAILABLE (-54) #define PCRE2_ERROR_UNSET (-55) #define PCRE2_ERROR_BADOFFSETLIMIT (-56) @@ -272,8 +294,11 @@ extern "C" { #define PCRE2_ERROR_BADSUBSPATTERN (-60) #define PCRE2_ERROR_TOOMANYREPLACE (-61) #define PCRE2_ERROR_BADSERIALIZEDDATA (-62) +#define PCRE2_ERROR_HEAPLIMIT (-63) +#define PCRE2_ERROR_CONVERT_SYNTAX (-64) + - /* Request types for pcre2_pattern_info() */ +/* Request types for pcre2_pattern_info() */ #define PCRE2_INFO_ALLOPTIONS 0 #define PCRE2_INFO_ARGOPTIONS 1 @@ -296,11 +321,14 @@ extern "C" { #define PCRE2_INFO_NAMEENTRYSIZE 18 #define PCRE2_INFO_NAMETABLE 19 #define PCRE2_INFO_NEWLINE 20 -#define PCRE2_INFO_RECURSIONLIMIT 21 +#define PCRE2_INFO_DEPTHLIMIT 21 +#define PCRE2_INFO_RECURSIONLIMIT 21 /* Obsolete synonym */ #define PCRE2_INFO_SIZE 22 #define PCRE2_INFO_HASBACKSLASHC 23 +#define PCRE2_INFO_FRAMESIZE 24 +#define PCRE2_INFO_HEAPLIMIT 25 - /* Request types for pcre2_config(). */ +/* Request types for pcre2_config(). */ #define PCRE2_CONFIG_BSR 0 #define PCRE2_CONFIG_JIT 1 @@ -309,34 +337,36 @@ extern "C" { #define PCRE2_CONFIG_MATCHLIMIT 4 #define PCRE2_CONFIG_NEWLINE 5 #define PCRE2_CONFIG_PARENSLIMIT 6 -#define PCRE2_CONFIG_RECURSIONLIMIT 7 -#define PCRE2_CONFIG_STACKRECURSE 8 +#define PCRE2_CONFIG_DEPTHLIMIT 7 +#define PCRE2_CONFIG_RECURSIONLIMIT 7 /* Obsolete synonym */ +#define PCRE2_CONFIG_STACKRECURSE 8 /* Obsolete */ #define PCRE2_CONFIG_UNICODE 9 #define PCRE2_CONFIG_UNICODE_VERSION 10 #define PCRE2_CONFIG_VERSION 11 +#define PCRE2_CONFIG_HEAPLIMIT 12 - /* Types for code units in patterns and subject strings. */ +/* Types for code units in patterns and subject strings. */ - typedef uint8_t PCRE2_UCHAR8; - typedef uint16_t PCRE2_UCHAR16; - typedef uint32_t PCRE2_UCHAR32; +typedef uint8_t PCRE2_UCHAR8; +typedef uint16_t PCRE2_UCHAR16; +typedef uint32_t PCRE2_UCHAR32; - typedef const PCRE2_UCHAR8 *PCRE2_SPTR8; - typedef const PCRE2_UCHAR16 *PCRE2_SPTR16; - typedef const PCRE2_UCHAR32 *PCRE2_SPTR32; +typedef const PCRE2_UCHAR8 *PCRE2_SPTR8; +typedef const PCRE2_UCHAR16 *PCRE2_SPTR16; +typedef const PCRE2_UCHAR32 *PCRE2_SPTR32; - /* The PCRE2_SIZE type is used for all string lengths and offsets in PCRE2, - including pattern offsets for errors and subject offsets after a match. We - define special values to indicate zero-terminated strings and unset offsets in - the offset vector (ovector). */ +/* The PCRE2_SIZE type is used for all string lengths and offsets in PCRE2, +including pattern offsets for errors and subject offsets after a match. We +define special values to indicate zero-terminated strings and unset offsets in +the offset vector (ovector). */ #define PCRE2_SIZE size_t #define PCRE2_SIZE_MAX SIZE_MAX #define PCRE2_ZERO_TERMINATED (~(PCRE2_SIZE)0) #define PCRE2_UNSET (~(PCRE2_SIZE)0) - /* Generic types for opaque structures and JIT callback functions. These - declarations are defined in a macro that is expanded for each width later. */ +/* Generic types for opaque structures and JIT callback functions. These +declarations are defined in a macro that is expanded for each width later. */ #define PCRE2_TYPES_LIST \ struct pcre2_real_general_context; \ @@ -348,6 +378,9 @@ typedef struct pcre2_real_compile_context pcre2_compile_context; \ struct pcre2_real_match_context; \ typedef struct pcre2_real_match_context pcre2_match_context; \ \ +struct pcre2_real_convert_context; \ +typedef struct pcre2_real_convert_context pcre2_convert_context; \ +\ struct pcre2_real_code; \ typedef struct pcre2_real_code pcre2_code; \ \ @@ -360,11 +393,11 @@ typedef struct pcre2_real_jit_stack pcre2_jit_stack; \ typedef pcre2_jit_stack *(*pcre2_jit_callback)(void *); - /* The structure for passing out data via the pcre_callout_function. We use a - structure so that new fields can be added on the end in future versions, - without changing the API of the function, thereby allowing old clients to work - without modification. Define the generic version in a macro; the width-specific - versions are generated from this macro below. */ +/* The structure for passing out data via the pcre_callout_function. We use a +structure so that new fields can be added on the end in future versions, +without changing the API of the function, thereby allowing old clients to work +without modification. Define the generic version in a macro; the width-specific +versions are generated from this macro below. */ #define PCRE2_STRUCTURE_LIST \ typedef struct pcre2_callout_block { \ @@ -401,15 +434,15 @@ typedef struct pcre2_callout_enumerate_block { \ } pcre2_callout_enumerate_block; - /* List the generic forms of all other functions in macros, which will be - expanded for each width below. Start with functions that give general - information. */ +/* List the generic forms of all other functions in macros, which will be +expanded for each width below. Start with functions that give general +information. */ #define PCRE2_GENERAL_INFO_FUNCTIONS \ PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION pcre2_config(uint32_t, void *); - /* Functions for manipulating contexts. */ +/* Functions for manipulating contexts. */ #define PCRE2_GENERAL_CONTEXT_FUNCTIONS \ PCRE2_EXP_DECL pcre2_general_context PCRE2_CALL_CONVENTION \ @@ -431,6 +464,8 @@ PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \ pcre2_set_bsr(pcre2_compile_context *, uint32_t); \ PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \ pcre2_set_character_tables(pcre2_compile_context *, const unsigned char *); \ +PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \ + pcre2_set_compile_extra_options(pcre2_compile_context *, uint32_t); \ PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \ pcre2_set_max_pattern_length(pcre2_compile_context *, PCRE2_SIZE); \ PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \ @@ -451,6 +486,10 @@ PCRE2_EXP_DECL void PCRE2_CALL_CONVENTION \ PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \ pcre2_set_callout(pcre2_match_context *, \ int (*)(pcre2_callout_block *, void *), void *); \ +PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \ + pcre2_set_depth_limit(pcre2_match_context *, uint32_t); \ +PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \ + pcre2_set_heap_limit(pcre2_match_context *, uint32_t); \ PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \ pcre2_set_match_limit(pcre2_match_context *, uint32_t); \ PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \ @@ -461,8 +500,20 @@ PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \ pcre2_set_recursion_memory_management(pcre2_match_context *, \ void *(*)(PCRE2_SIZE, void *), void (*)(void *, void *), void *); +#define PCRE2_CONVERT_CONTEXT_FUNCTIONS \ +PCRE2_EXP_DECL pcre2_convert_context PCRE2_CALL_CONVENTION \ + *pcre2_convert_context_copy(pcre2_convert_context *); \ +PCRE2_EXP_DECL pcre2_convert_context PCRE2_CALL_CONVENTION \ + *pcre2_convert_context_create(pcre2_general_context *); \ +PCRE2_EXP_DECL void PCRE2_CALL_CONVENTION \ + pcre2_convert_context_free(pcre2_convert_context *); \ +PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \ + pcre2_set_glob_escape(pcre2_convert_context *, uint32_t); \ +PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \ + pcre2_set_glob_separator(pcre2_convert_context *, uint32_t); + - /* Functions concerned with compiling a pattern to PCRE internal code. */ +/* Functions concerned with compiling a pattern to PCRE internal code. */ #define PCRE2_COMPILE_FUNCTIONS \ PCRE2_EXP_DECL pcre2_code PCRE2_CALL_CONVENTION \ @@ -476,7 +527,7 @@ PCRE2_EXP_DECL pcre2_code PCRE2_CALL_CONVENTION \ *pcre2_code_copy_with_tables(const pcre2_code *); - /* Functions that give information about a compiled pattern. */ +/* Functions that give information about a compiled pattern. */ #define PCRE2_PATTERN_INFO_FUNCTIONS \ PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \ @@ -486,7 +537,7 @@ PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \ int (*)(pcre2_callout_enumerate_block *, void *), void *); - /* Functions for running a match and inspecting the result. */ +/* Functions for running a match and inspecting the result. */ #define PCRE2_MATCH_FUNCTIONS \ PCRE2_EXP_DECL pcre2_match_data PCRE2_CALL_CONVENTION \ @@ -512,7 +563,7 @@ PCRE2_EXP_DECL PCRE2_SIZE PCRE2_CALL_CONVENTION \ pcre2_get_startchar(pcre2_match_data *); - /* Convenience functions for handling matched substrings. */ +/* Convenience functions for handling matched substrings. */ #define PCRE2_SUBSTRING_FUNCTIONS \ PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \ @@ -543,7 +594,7 @@ PCRE2_EXP_DECL void PCRE2_CALL_CONVENTION \ PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \ pcre2_substring_list_get(pcre2_match_data *, PCRE2_UCHAR ***, PCRE2_SIZE **); - /* Functions for serializing / deserializing compiled patterns. */ +/* Functions for serializing / deserializing compiled patterns. */ #define PCRE2_SERIALIZE_FUNCTIONS \ PCRE2_EXP_DECL int32_t PCRE2_CALL_CONVENTION \ @@ -558,7 +609,7 @@ PCRE2_EXP_DECL void PCRE2_CALL_CONVENTION \ pcre2_serialize_free(uint8_t *); - /* Convenience function for match + substitute. */ +/* Convenience function for match + substitute. */ #define PCRE2_SUBSTITUTE_FUNCTION \ PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \ @@ -567,7 +618,17 @@ PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \ PCRE2_SIZE, PCRE2_UCHAR *, PCRE2_SIZE *); - /* Functions for JIT processing */ +/* Functions for converting pattern source strings. */ + +#define PCRE2_CONVERT_FUNCTIONS \ +PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \ + pcre2_pattern_convert(PCRE2_SPTR, PCRE2_SIZE, uint32_t, PCRE2_UCHAR **, \ + PCRE2_SIZE *, pcre2_convert_context *); \ +PCRE2_EXP_DECL void PCRE2_CALL_CONVENTION \ + pcre2_converted_pattern_free(PCRE2_UCHAR *); + + +/* Functions for JIT processing */ #define PCRE2_JIT_FUNCTIONS \ PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \ @@ -585,7 +646,7 @@ PCRE2_EXP_DECL void PCRE2_CALL_CONVENTION \ pcre2_jit_stack_free(pcre2_jit_stack *); - /* Other miscellaneous functions. */ +/* Other miscellaneous functions. */ #define PCRE2_OTHER_FUNCTIONS \ PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \ @@ -594,19 +655,19 @@ PCRE2_EXP_DECL const uint8_t PCRE2_CALL_CONVENTION \ *pcre2_maketables(pcre2_general_context *); \ - /* Define macros that generate width-specific names from generic versions. The - three-level macro scheme is necessary to get the macros expanded when we want - them to be. First we get the width from PCRE2_LOCAL_WIDTH, which is used for - generating three versions of everything below. After that, PCRE2_SUFFIX will be - re-defined to use PCRE2_CODE_UNIT_WIDTH, for use when macros such as - pcre2_compile are called by application code. */ +/* Define macros that generate width-specific names from generic versions. The +three-level macro scheme is necessary to get the macros expanded when we want +them to be. First we get the width from PCRE2_LOCAL_WIDTH, which is used for +generating three versions of everything below. After that, PCRE2_SUFFIX will be +re-defined to use PCRE2_CODE_UNIT_WIDTH, for use when macros such as +pcre2_compile are called by application code. */ #define PCRE2_JOIN(a,b) a ## b #define PCRE2_GLUE(a,b) PCRE2_JOIN(a,b) #define PCRE2_SUFFIX(a) PCRE2_GLUE(a,PCRE2_LOCAL_WIDTH) - /* Data types */ +/* Data types */ #define PCRE2_UCHAR PCRE2_SUFFIX(PCRE2_UCHAR) #define PCRE2_SPTR PCRE2_SUFFIX(PCRE2_SPTR) @@ -618,22 +679,24 @@ PCRE2_EXP_DECL const uint8_t PCRE2_CALL_CONVENTION \ #define pcre2_real_code PCRE2_SUFFIX(pcre2_real_code_) #define pcre2_real_general_context PCRE2_SUFFIX(pcre2_real_general_context_) #define pcre2_real_compile_context PCRE2_SUFFIX(pcre2_real_compile_context_) +#define pcre2_real_convert_context PCRE2_SUFFIX(pcre2_real_convert_context_) #define pcre2_real_match_context PCRE2_SUFFIX(pcre2_real_match_context_) #define pcre2_real_jit_stack PCRE2_SUFFIX(pcre2_real_jit_stack_) #define pcre2_real_match_data PCRE2_SUFFIX(pcre2_real_match_data_) - /* Data blocks */ +/* Data blocks */ #define pcre2_callout_block PCRE2_SUFFIX(pcre2_callout_block_) #define pcre2_callout_enumerate_block PCRE2_SUFFIX(pcre2_callout_enumerate_block_) #define pcre2_general_context PCRE2_SUFFIX(pcre2_general_context_) #define pcre2_compile_context PCRE2_SUFFIX(pcre2_compile_context_) +#define pcre2_convert_context PCRE2_SUFFIX(pcre2_convert_context_) #define pcre2_match_context PCRE2_SUFFIX(pcre2_match_context_) #define pcre2_match_data PCRE2_SUFFIX(pcre2_match_data_) - /* Functions: the complete list in alphabetical order */ +/* Functions: the complete list in alphabetical order */ #define pcre2_callout_enumerate PCRE2_SUFFIX(pcre2_callout_enumerate_) #define pcre2_code_copy PCRE2_SUFFIX(pcre2_code_copy_) @@ -644,6 +707,10 @@ PCRE2_EXP_DECL const uint8_t PCRE2_CALL_CONVENTION \ #define pcre2_compile_context_create PCRE2_SUFFIX(pcre2_compile_context_create_) #define pcre2_compile_context_free PCRE2_SUFFIX(pcre2_compile_context_free_) #define pcre2_config PCRE2_SUFFIX(pcre2_config_) +#define pcre2_convert_context_copy PCRE2_SUFFIX(pcre2_convert_context_copy_) +#define pcre2_convert_context_create PCRE2_SUFFIX(pcre2_convert_context_create_) +#define pcre2_convert_context_free PCRE2_SUFFIX(pcre2_convert_context_free_) +#define pcre2_converted_pattern_free PCRE2_SUFFIX(pcre2_converted_pattern_free_) #define pcre2_dfa_match PCRE2_SUFFIX(pcre2_dfa_match_) #define pcre2_general_context_copy PCRE2_SUFFIX(pcre2_general_context_copy_) #define pcre2_general_context_create PCRE2_SUFFIX(pcre2_general_context_create_) @@ -667,6 +734,7 @@ PCRE2_EXP_DECL const uint8_t PCRE2_CALL_CONVENTION \ #define pcre2_match_data_create PCRE2_SUFFIX(pcre2_match_data_create_) #define pcre2_match_data_create_from_pattern PCRE2_SUFFIX(pcre2_match_data_create_from_pattern_) #define pcre2_match_data_free PCRE2_SUFFIX(pcre2_match_data_free_) +#define pcre2_pattern_convert PCRE2_SUFFIX(pcre2_pattern_convert_) #define pcre2_pattern_info PCRE2_SUFFIX(pcre2_pattern_info_) #define pcre2_serialize_decode PCRE2_SUFFIX(pcre2_serialize_decode_) #define pcre2_serialize_encode PCRE2_SUFFIX(pcre2_serialize_encode_) @@ -675,14 +743,17 @@ PCRE2_EXP_DECL const uint8_t PCRE2_CALL_CONVENTION \ #define pcre2_set_bsr PCRE2_SUFFIX(pcre2_set_bsr_) #define pcre2_set_callout PCRE2_SUFFIX(pcre2_set_callout_) #define pcre2_set_character_tables PCRE2_SUFFIX(pcre2_set_character_tables_) +#define pcre2_set_compile_extra_options PCRE2_SUFFIX(pcre2_set_compile_extra_options_) #define pcre2_set_compile_recursion_guard PCRE2_SUFFIX(pcre2_set_compile_recursion_guard_) +#define pcre2_set_depth_limit PCRE2_SUFFIX(pcre2_set_depth_limit_) +#define pcre2_set_glob_escape PCRE2_SUFFIX(pcre2_set_glob_escape_) +#define pcre2_set_glob_separator PCRE2_SUFFIX(pcre2_set_glob_separator_) +#define pcre2_set_heap_limit PCRE2_SUFFIX(pcre2_set_heap_limit_) #define pcre2_set_match_limit PCRE2_SUFFIX(pcre2_set_match_limit_) #define pcre2_set_max_pattern_length PCRE2_SUFFIX(pcre2_set_max_pattern_length_) #define pcre2_set_newline PCRE2_SUFFIX(pcre2_set_newline_) #define pcre2_set_parens_nest_limit PCRE2_SUFFIX(pcre2_set_parens_nest_limit_) #define pcre2_set_offset_limit PCRE2_SUFFIX(pcre2_set_offset_limit_) -#define pcre2_set_recursion_limit PCRE2_SUFFIX(pcre2_set_recursion_limit_) -#define pcre2_set_recursion_memory_management PCRE2_SUFFIX(pcre2_set_recursion_memory_management_) #define pcre2_substitute PCRE2_SUFFIX(pcre2_substitute_) #define pcre2_substring_copy_byname PCRE2_SUFFIX(pcre2_substring_copy_byname_) #define pcre2_substring_copy_bynumber PCRE2_SUFFIX(pcre2_substring_copy_bynumber_) @@ -696,9 +767,14 @@ PCRE2_EXP_DECL const uint8_t PCRE2_CALL_CONVENTION \ #define pcre2_substring_nametable_scan PCRE2_SUFFIX(pcre2_substring_nametable_scan_) #define pcre2_substring_number_from_name PCRE2_SUFFIX(pcre2_substring_number_from_name_) +/* Keep this old function name for backwards compatibility */ +#define pcre2_set_recursion_limit PCRE2_SUFFIX(pcre2_set_recursion_limit_) + +/* Keep this obsolete function for backwards compatibility: it is now a noop. */ +#define pcre2_set_recursion_memory_management PCRE2_SUFFIX(pcre2_set_recursion_memory_management_) - /* Now generate all three sets of width-specific structures and function - prototypes. */ +/* Now generate all three sets of width-specific structures and function +prototypes. */ #define PCRE2_TYPES_STRUCTURES_AND_FUNCTIONS \ PCRE2_TYPES_LIST \ @@ -706,6 +782,8 @@ PCRE2_STRUCTURE_LIST \ PCRE2_GENERAL_INFO_FUNCTIONS \ PCRE2_GENERAL_CONTEXT_FUNCTIONS \ PCRE2_COMPILE_CONTEXT_FUNCTIONS \ +PCRE2_CONVERT_CONTEXT_FUNCTIONS \ +PCRE2_CONVERT_FUNCTIONS \ PCRE2_MATCH_CONTEXT_FUNCTIONS \ PCRE2_COMPILE_FUNCTIONS \ PCRE2_PATTERN_INFO_FUNCTIONS \ @@ -717,24 +795,25 @@ PCRE2_JIT_FUNCTIONS \ PCRE2_OTHER_FUNCTIONS #define PCRE2_LOCAL_WIDTH 8 - PCRE2_TYPES_STRUCTURES_AND_FUNCTIONS +PCRE2_TYPES_STRUCTURES_AND_FUNCTIONS #undef PCRE2_LOCAL_WIDTH #define PCRE2_LOCAL_WIDTH 16 - PCRE2_TYPES_STRUCTURES_AND_FUNCTIONS +PCRE2_TYPES_STRUCTURES_AND_FUNCTIONS #undef PCRE2_LOCAL_WIDTH #define PCRE2_LOCAL_WIDTH 32 - PCRE2_TYPES_STRUCTURES_AND_FUNCTIONS +PCRE2_TYPES_STRUCTURES_AND_FUNCTIONS #undef PCRE2_LOCAL_WIDTH - /* Undefine the list macros; they are no longer needed. */ +/* Undefine the list macros; they are no longer needed. */ #undef PCRE2_TYPES_LIST #undef PCRE2_STRUCTURE_LIST #undef PCRE2_GENERAL_INFO_FUNCTIONS #undef PCRE2_GENERAL_CONTEXT_FUNCTIONS #undef PCRE2_COMPILE_CONTEXT_FUNCTIONS +#undef PCRE2_CONVERT_CONTEXT_FUNCTIONS #undef PCRE2_MATCH_CONTEXT_FUNCTIONS #undef PCRE2_COMPILE_FUNCTIONS #undef PCRE2_PATTERN_INFO_FUNCTIONS @@ -746,9 +825,9 @@ PCRE2_OTHER_FUNCTIONS #undef PCRE2_OTHER_FUNCTIONS #undef PCRE2_TYPES_STRUCTURES_AND_FUNCTIONS - /* PCRE2_CODE_UNIT_WIDTH must be defined. If it is 8, 16, or 32, redefine - PCRE2_SUFFIX to use it. If it is 0, undefine the other macros and make - PCRE2_SUFFIX a no-op. Otherwise, generate an error. */ +/* PCRE2_CODE_UNIT_WIDTH must be defined. If it is 8, 16, or 32, redefine +PCRE2_SUFFIX to use it. If it is 0, undefine the other macros and make +PCRE2_SUFFIX a no-op. Otherwise, generate an error. */ #undef PCRE2_SUFFIX #ifndef PCRE2_CODE_UNIT_WIDTH @@ -774,4 +853,4 @@ PCRE2_OTHER_FUNCTIONS #endif /* PCRE2_H_IDEMPOTENT_GUARD */ - /* End of pcre2.h */ +/* End of pcre2.h */ diff --git a/ProcessHacker/pcre/pcre2_auto_possess.c b/ProcessHacker/pcre/pcre2_auto_possess.c index 2c987bbf5b76..ad3543f62737 100644 --- a/ProcessHacker/pcre/pcre2_auto_possess.c +++ b/ProcessHacker/pcre/pcre2_auto_possess.c @@ -7,7 +7,7 @@ and semantics are as close as possible to those of the Perl 5 language. Written by Philip Hazel Original API code Copyright (c) 1997-2012 University of Cambridge - New API code Copyright (c) 2016 University of Cambridge + New API code Copyright (c) 2016-2017 University of Cambridge ----------------------------------------------------------------------------- Redistribution and use in source and binary forms, with or without @@ -42,8 +42,6 @@ POSSIBILITY OF SUCH DAMAGE. repeats into possessive repeats where possible. */ -#define HAVE_CONFIG_H - #ifdef HAVE_CONFIG_H #include "config.h" #endif @@ -590,7 +588,6 @@ for(;;) case OP_ASSERTBACK: case OP_ASSERTBACK_NOT: case OP_ONCE: - case OP_ONCE_NC: /* Atomic sub-patterns and assertions can always auto-possessify their last iterator. However, if the group was entered as a result of checking @@ -603,7 +600,6 @@ for(;;) continue; case OP_ONCE: - case OP_ONCE_NC: case OP_BRA: case OP_CBRA: next_code = code + GET(code, 1); @@ -627,8 +623,8 @@ for(;;) case OP_BRAMINZERO: next_code = code + 1; - if (*next_code != OP_BRA && *next_code != OP_CBRA - && *next_code != OP_ONCE && *next_code != OP_ONCE_NC) return FALSE; + if (*next_code != OP_BRA && *next_code != OP_CBRA && + *next_code != OP_ONCE) return FALSE; do next_code += GET(next_code, 1); while (*next_code == OP_ALT); @@ -1079,7 +1075,7 @@ for (;;) { c = *code; - if (c > OP_TABLE_LENGTH) return -1; /* Something gone wrong */ + if (c >= OP_TABLE_LENGTH) return -1; /* Something gone wrong */ if (c >= OP_STAR && c <= OP_TYPEPOSUPTO) { diff --git a/ProcessHacker/pcre/pcre2_chartables.c b/ProcessHacker/pcre/pcre2_chartables.c index 23578d8932b0..203cb1a4ab04 100644 --- a/ProcessHacker/pcre/pcre2_chartables.c +++ b/ProcessHacker/pcre/pcre2_chartables.c @@ -20,7 +20,6 @@ and dead code stripping is activated. This leads to link errors. Pulling in the header ensures that the array gets flagged as "someone outside this compilation unit might reference this" and so it will always be supplied to the linker. */ -#define HAVE_CONFIG_H #ifdef HAVE_CONFIG_H #include "config.h" #endif diff --git a/ProcessHacker/pcre/pcre2_compile.c b/ProcessHacker/pcre/pcre2_compile.c index 0e8199ff4123..e8de8dabbce4 100644 --- a/ProcessHacker/pcre/pcre2_compile.c +++ b/ProcessHacker/pcre/pcre2_compile.c @@ -7,7 +7,7 @@ and semantics are as close as possible to those of the Perl 5 language. Written by Philip Hazel Original API code Copyright (c) 1997-2012 University of Cambridge - New API code Copyright (c) 2016 University of Cambridge + New API code Copyright (c) 2016-2017 University of Cambridge ----------------------------------------------------------------------------- Redistribution and use in source and binary forms, with or without @@ -41,7 +41,6 @@ POSSIBILITY OF SUCH DAMAGE. // dmex: Disable warnings. #pragma warning(push) #pragma warning(disable : 4244 4267) -#define HAVE_CONFIG_H #ifdef HAVE_CONFIG_H #include "config.h" @@ -164,7 +163,7 @@ the length of compiled items varies with this. In the real compile phase, this workspace is not currently used. */ -#define COMPILE_WORK_SIZE (2048*LINK_SIZE) /* Size in code units */ +#define COMPILE_WORK_SIZE (3000*LINK_SIZE) /* Size in code units */ #define C16_WORK_SIZE \ ((COMPILE_WORK_SIZE * sizeof(PCRE2_UCHAR))/sizeof(uint16_t)) @@ -694,17 +693,29 @@ static int posix_substitutes[] = { #define POSIX_SUBSIZE (sizeof(posix_substitutes) / (2*sizeof(uint32_t))) #endif /* SUPPORT_UNICODE */ -/* Masks for checking option settings. */ +/* Masks for checking option settings. When PCRE2_LITERAL is set, only a subset +are allowed. */ + +#define PUBLIC_LITERAL_COMPILE_OPTIONS \ + (PCRE2_ANCHORED|PCRE2_AUTO_CALLOUT|PCRE2_CASELESS|PCRE2_ENDANCHORED| \ + PCRE2_FIRSTLINE|PCRE2_LITERAL|PCRE2_NO_START_OPTIMIZE| \ + PCRE2_NO_UTF_CHECK|PCRE2_USE_OFFSET_LIMIT|PCRE2_UTF) #define PUBLIC_COMPILE_OPTIONS \ - (PCRE2_ANCHORED|PCRE2_ALLOW_EMPTY_CLASS|PCRE2_ALT_BSUX|PCRE2_ALT_CIRCUMFLEX| \ - PCRE2_ALT_VERBNAMES|PCRE2_AUTO_CALLOUT|PCRE2_CASELESS|PCRE2_DOLLAR_ENDONLY| \ - PCRE2_DOTALL|PCRE2_DUPNAMES|PCRE2_EXTENDED|PCRE2_FIRSTLINE| \ - PCRE2_MATCH_UNSET_BACKREF|PCRE2_MULTILINE|PCRE2_NEVER_BACKSLASH_C| \ - PCRE2_NEVER_UCP|PCRE2_NEVER_UTF|PCRE2_NO_AUTO_CAPTURE| \ - PCRE2_NO_AUTO_POSSESS|PCRE2_NO_DOTSTAR_ANCHOR|PCRE2_NO_START_OPTIMIZE| \ - PCRE2_NO_UTF_CHECK|PCRE2_UCP|PCRE2_UNGREEDY|PCRE2_USE_OFFSET_LIMIT| \ - PCRE2_UTF) + (PUBLIC_LITERAL_COMPILE_OPTIONS| \ + PCRE2_ALLOW_EMPTY_CLASS|PCRE2_ALT_BSUX|PCRE2_ALT_CIRCUMFLEX| \ + PCRE2_ALT_VERBNAMES|PCRE2_DOLLAR_ENDONLY|PCRE2_DOTALL|PCRE2_DUPNAMES| \ + PCRE2_EXTENDED|PCRE2_EXTENDED_MORE|PCRE2_MATCH_UNSET_BACKREF| \ + PCRE2_MULTILINE|PCRE2_NEVER_BACKSLASH_C|PCRE2_NEVER_UCP| \ + PCRE2_NEVER_UTF|PCRE2_NO_AUTO_CAPTURE|PCRE2_NO_AUTO_POSSESS| \ + PCRE2_NO_DOTSTAR_ANCHOR|PCRE2_UCP|PCRE2_UNGREEDY) + +#define PUBLIC_LITERAL_COMPILE_EXTRA_OPTIONS \ + (PCRE2_EXTRA_MATCH_LINE|PCRE2_EXTRA_MATCH_WORD) + +#define PUBLIC_COMPILE_EXTRA_OPTIONS \ + (PUBLIC_LITERAL_COMPILE_EXTRA_OPTIONS| \ + PCRE2_EXTRA_ALLOW_SURROGATE_ESCAPES|PCRE2_EXTRA_BAD_ESCAPE_IS_LITERAL) /* Compile time error code numbers. They are given names so that they can more easily be tracked. When a new number is added, the tables called eint1 and @@ -720,7 +731,8 @@ enum { ERR0 = COMPILE_ERROR_BASE, ERR51, ERR52, ERR53, ERR54, ERR55, ERR56, ERR57, ERR58, ERR59, ERR60, ERR61, ERR62, ERR63, ERR64, ERR65, ERR66, ERR67, ERR68, ERR69, ERR70, ERR71, ERR72, ERR73, ERR74, ERR75, ERR76, ERR77, ERR78, ERR79, ERR80, - ERR81, ERR82, ERR83, ERR84, ERR85, ERR86, ERR87, ERR88, ERR89, ERR90 }; + ERR81, ERR82, ERR83, ERR84, ERR85, ERR86, ERR87, ERR88, ERR89, ERR90, + ERR91, ERR92}; /* This is a table of start-of-pattern options such as (*UTF) and settings such as (*LIMIT_MATCH=nnnn) and (*CRLF). For completeness and backward @@ -731,8 +743,9 @@ enum { PSO_OPT, /* Value is an option bit */ PSO_FLG, /* Value is a flag bit */ PSO_NL, /* Value is a newline type */ PSO_BSR, /* Value is a \R type */ + PSO_LIMH, /* Read integer value for heap limit */ PSO_LIMM, /* Read integer value for match limit */ - PSO_LIMR }; /* Read integer value for recursion limit */ + PSO_LIMD }; /* Read integer value for depth limit */ typedef struct pso { const uint8_t *name; @@ -753,12 +766,15 @@ static pso pso_list[] = { { (uint8_t *)STRING_NO_DOTSTAR_ANCHOR_RIGHTPAR, 18, PSO_OPT, PCRE2_NO_DOTSTAR_ANCHOR }, { (uint8_t *)STRING_NO_JIT_RIGHTPAR, 7, PSO_FLG, PCRE2_NOJIT }, { (uint8_t *)STRING_NO_START_OPT_RIGHTPAR, 13, PSO_OPT, PCRE2_NO_START_OPTIMIZE }, + { (uint8_t *)STRING_LIMIT_HEAP_EQ, 11, PSO_LIMH, 0 }, { (uint8_t *)STRING_LIMIT_MATCH_EQ, 12, PSO_LIMM, 0 }, - { (uint8_t *)STRING_LIMIT_RECURSION_EQ, 16, PSO_LIMR, 0 }, + { (uint8_t *)STRING_LIMIT_DEPTH_EQ, 12, PSO_LIMD, 0 }, + { (uint8_t *)STRING_LIMIT_RECURSION_EQ, 16, PSO_LIMD, 0 }, { (uint8_t *)STRING_CR_RIGHTPAR, 3, PSO_NL, PCRE2_NEWLINE_CR }, { (uint8_t *)STRING_LF_RIGHTPAR, 3, PSO_NL, PCRE2_NEWLINE_LF }, { (uint8_t *)STRING_CRLF_RIGHTPAR, 5, PSO_NL, PCRE2_NEWLINE_CRLF }, { (uint8_t *)STRING_ANY_RIGHTPAR, 4, PSO_NL, PCRE2_NEWLINE_ANY }, + { (uint8_t *)STRING_NUL_RIGHTPAR, 4, PSO_NL, PCRE2_NEWLINE_NUL }, { (uint8_t *)STRING_ANYCRLF_RIGHTPAR, 8, PSO_NL, PCRE2_NEWLINE_ANYCRLF }, { (uint8_t *)STRING_BSR_ANYCRLF_RIGHTPAR, 12, PSO_BSR, PCRE2_BSR_ANYCRLF }, { (uint8_t *)STRING_BSR_UNICODE_RIGHTPAR, 12, PSO_BSR, PCRE2_BSR_UNICODE } @@ -1474,7 +1490,10 @@ else if (utf) { if (c > 0x10ffffU) *errorcodeptr = ERR77; - else if (c >= 0xd800 && c <= 0xdfff) *errorcodeptr = ERR73; + else + if (c >= 0xd800 && c <= 0xdfff && + (cb->cx->extra_options & PCRE2_EXTRA_ALLOW_SURROGATE_ESCAPES) == 0) + *errorcodeptr = ERR73; } else if (c > MAX_NON_UTF_CHAR) *errorcodeptr = ERR77; } @@ -1608,7 +1627,7 @@ else if (c >= CHAR_8) break; - /* Fall through with a digit less than 8 */ + /* Fall through */ /* \0 always starts an octal number, but we may drop through to here with a larger first octal digit. The original code used just to take the least @@ -1663,7 +1682,8 @@ else } else if (ptr < ptrend && *ptr++ == CHAR_RIGHT_CURLY_BRACKET) { - if (utf && c >= 0xd800 && c <= 0xdfff) + if (utf && c >= 0xd800 && c <= 0xdfff && (cb == NULL || + (cb->cx->extra_options & PCRE2_EXTRA_ALLOW_SURROGATE_ESCAPES) == 0)) { ptr--; *errorcodeptr = ERR73; @@ -1732,7 +1752,8 @@ else } else if (ptr < ptrend && *ptr++ == CHAR_RIGHT_CURLY_BRACKET) { - if (utf && c >= 0xd800 && c <= 0xdfff) + if (utf && c >= 0xd800 && c <= 0xdfff && (cb == NULL || + (cb->cx->extra_options & PCRE2_EXTRA_ALLOW_SURROGATE_ESCAPES) == 0)) { ptr--; *errorcodeptr = ERR73; @@ -1905,7 +1926,7 @@ if (c == CHAR_LEFT_CURLY_BRACKET) { if (ptr >= cb->end_pattern) goto ERROR_RETURN; c = *ptr++; - if (c == CHAR_NULL) goto ERROR_RETURN; + if (c == CHAR_NUL) goto ERROR_RETURN; if (c == CHAR_RIGHT_CURLY_BRACKET) break; name[i] = c; } @@ -2163,7 +2184,7 @@ the parsed pattern. Arguments: ptr current pattern pointer pcalloutptr points to a pointer to previous callout, or NULL - options the compiling options + auto_callout TRUE if auto_callouts are enabled parsed_pattern the parsed pattern pointer cb compile block @@ -2171,7 +2192,7 @@ Returns: possibly updated parsed_pattern pointer. */ static uint32_t * -manage_callouts(PCRE2_SPTR ptr, uint32_t **pcalloutptr, uint32_t options, +manage_callouts(PCRE2_SPTR ptr, uint32_t **pcalloutptr, BOOL auto_callout, uint32_t *parsed_pattern, compile_block *cb) { uint32_t *previous_callout = *pcalloutptr; @@ -2179,7 +2200,7 @@ uint32_t *previous_callout = *pcalloutptr; if (previous_callout != NULL) previous_callout[2] = ptr - cb->start_pattern - (PCRE2_SIZE)previous_callout[1]; -if ((options & PCRE2_AUTO_CALLOUT) == 0) previous_callout = NULL; else +if (!auto_callout) previous_callout = NULL; else { if (previous_callout == NULL || previous_callout != parsed_pattern - 4 || @@ -2227,12 +2248,17 @@ typedef struct nest_save { uint16_t reset_group; uint16_t max_group; uint16_t flags; + uint32_t options; } nest_save; -#define NSF_RESET 0x0001u -#define NSF_EXTENDED 0x0002u -#define NSF_DUPNAMES 0x0004u -#define NSF_CONDASSERT 0x0008u +#define NSF_RESET 0x0001u +#define NSF_CONDASSERT 0x0002u + +/* Of the options that are changeable within the pattern, these are tracked +during parsing. The rest are used from META_OPTIONS items when compiling. */ + +#define PARSE_TRACKED_OPTIONS \ + (PCRE2_DUPNAMES|PCRE2_EXTENDED|PCRE2_EXTENDED_MORE|PCRE2_NO_AUTO_CAPTURE) /* States used for analyzing ranges in character classes. The two OK values must be last. */ @@ -2276,15 +2302,57 @@ int i; BOOL inescq = FALSE; BOOL inverbname = FALSE; BOOL utf = (options & PCRE2_UTF) != 0; +BOOL auto_callout = (options & PCRE2_AUTO_CALLOUT) != 0; BOOL isdupname; BOOL negate_class; BOOL okquantifier = FALSE; +PCRE2_SPTR thisptr; PCRE2_SPTR name; PCRE2_SPTR ptrend = cb->end_pattern; PCRE2_SPTR verbnamestart = NULL; /* Value avoids compiler warning */ named_group *ng; -nest_save *top_nest = NULL; -nest_save *end_nests = (nest_save *)(cb->start_workspace + cb->workspace_size); +nest_save *top_nest, *end_nests; + +/* Insert leading items for word and line matching (features provided for the +benefit of pcre2grep). */ + +if ((cb->cx->extra_options & PCRE2_EXTRA_MATCH_LINE) != 0) + { + *parsed_pattern++ = META_CIRCUMFLEX; + *parsed_pattern++ = META_NOCAPTURE; + } +else if ((cb->cx->extra_options & PCRE2_EXTRA_MATCH_WORD) != 0) + { + *parsed_pattern++ = META_ESCAPE + ESC_b; + *parsed_pattern++ = META_NOCAPTURE; + } + +/* If the pattern is actually a literal string, process it separately to avoid +cluttering up the main loop. */ + +if ((options & PCRE2_LITERAL) != 0) + { + while (ptr < ptrend) + { + if (parsed_pattern >= parsed_pattern_end) + { + errorcode = ERR63; /* Internal error (parsed pattern overflow) */ + goto FAILED; + } + thisptr = ptr; + GETCHARINCTEST(c, ptr); + if (auto_callout) + parsed_pattern = manage_callouts(thisptr, &previous_callout, + auto_callout, parsed_pattern, cb); + PARSED_LITERAL(c, parsed_pattern); + } + goto PARSED_END; + } + +/* Process a real regex which may contain meta-characters. */ + +top_nest = NULL; +end_nests = (nest_save *)(cb->start_workspace + cb->workspace_size); /* The size of the nest_save structure might not be a factor of the size of the workspace. Therefore we must round down end_nests so as to correctly avoid @@ -2293,9 +2361,11 @@ creating a nest_save that spans the end of the workspace. */ end_nests = (nest_save *)((char *)end_nests - ((cb->workspace_size * sizeof(PCRE2_UCHAR)) % sizeof(nest_save))); -/* Now scan the pattern */ +/* PCRE2_EXTENDED_MORE implies PCRE2_EXTENDED */ -*has_lookbehind = FALSE; +if ((options & PCRE2_EXTENDED_MORE) != 0) options |= PCRE2_EXTENDED; + +/* Now scan the pattern */ while (ptr < ptrend) { @@ -2306,7 +2376,6 @@ while (ptr < ptrend) uint32_t prev_meta_quantifier; BOOL prev_okquantifier; PCRE2_SPTR tempptr; - PCRE2_SPTR thisptr; PCRE2_SIZE offset; if (parsed_pattern >= parsed_pattern_end) @@ -2318,7 +2387,7 @@ while (ptr < ptrend) if (nest_depth > cb->cx->parens_nest_limit) { errorcode = ERR19; - goto FAILED; + goto FAILED; /* Parentheses too deeply nested */ } /* Get next input character, save its position for callout handling. */ @@ -2345,8 +2414,8 @@ while (ptr < ptrend) goto FAILED; } if (!inverbname && after_manual_callout-- <= 0) - parsed_pattern = manage_callouts(thisptr, &previous_callout, options, - parsed_pattern, cb); + parsed_pattern = manage_callouts(thisptr, &previous_callout, + auto_callout, parsed_pattern, cb); PARSED_LITERAL(c, parsed_pattern); meta_quantifier = 0; } @@ -2491,7 +2560,7 @@ while (ptr < ptrend) !read_repeat_counts(&tempptr, ptrend, NULL, NULL, &errorcode)))) { if (after_manual_callout-- <= 0) - parsed_pattern = manage_callouts(thisptr, &previous_callout, options, + parsed_pattern = manage_callouts(thisptr, &previous_callout, auto_callout, parsed_pattern, cb); } @@ -2575,11 +2644,23 @@ while (ptr < ptrend) /* ---- Escape sequence ---- */ case CHAR_BACKSLASH: + tempptr = ptr; escape = PRIV(check_escape)(&ptr, ptrend, &c, &errorcode, options, FALSE, cb); - if (errorcode != 0) goto FAILED; + if (errorcode != 0) + { + ESCAPE_FAILED: + if ((cb->cx->extra_options & PCRE2_EXTRA_BAD_ESCAPE_IS_LITERAL) == 0) + goto FAILED; + ptr = tempptr; + if (ptr >= ptrend) c = CHAR_BACKSLASH; else + { + GETCHARINCTEST(c, ptr); /* Get character value, increment pointer */ + } + escape = 0; /* Treat as literal character */ + } - /* The escape was a data character. */ + /* The escape was a data escape or literal character. */ if (escape == 0) { @@ -2631,12 +2712,12 @@ while (ptr < ptrend) case ESC_C: #ifdef NEVER_BACKSLASH_C errorcode = ERR85; - goto FAILED; + goto ESCAPE_FAILED; #else if ((options & PCRE2_NEVER_BACKSLASH_C) != 0) { errorcode = ERR83; - goto FAILED; + goto ESCAPE_FAILED; } #endif okquantifier = TRUE; @@ -2646,7 +2727,7 @@ while (ptr < ptrend) case ESC_X: #ifndef SUPPORT_UNICODE errorcode = ERR45; /* Supported only with Unicode support */ - goto FAILED; + goto ESCAPE_FAILED; #endif case ESC_H: case ESC_h: @@ -2711,7 +2792,7 @@ while (ptr < ptrend) BOOL negated; uint16_t ptype = 0, pdata = 0; if (!get_ucp(&ptr, &negated, &ptype, &pdata, &errorcode, cb)) - goto FAILED; + goto ESCAPE_FAILED; if (negated) escape = (escape == ESC_P)? ESC_p : ESC_P; *parsed_pattern++ = META_ESCAPE + escape; *parsed_pattern++ = (ptype << 16) | pdata; @@ -2719,7 +2800,7 @@ while (ptr < ptrend) } #else errorcode = ERR45; - goto FAILED; + goto ESCAPE_FAILED; #endif break; /* End \P and \p */ @@ -2735,7 +2816,7 @@ while (ptr < ptrend) *ptr != CHAR_LESS_THAN_SIGN && *ptr != CHAR_APOSTROPHE)) { errorcode = (escape == ESC_g)? ERR57 : ERR69; - goto FAILED; + goto ESCAPE_FAILED; } terminator = (*ptr == CHAR_LESS_THAN_SIGN)? CHAR_GREATER_THAN_SIGN : (*ptr == CHAR_APOSTROPHE)? @@ -2753,18 +2834,18 @@ while (ptr < ptrend) if (p >= ptrend || *p != terminator) { errorcode = ERR57; - goto FAILED; + goto ESCAPE_FAILED; } ptr = p; goto SET_RECURSION; } - if (errorcode != 0) goto FAILED; + if (errorcode != 0) goto ESCAPE_FAILED; } /* Not a numerical recursion */ if (!read_name(&ptr, ptrend, terminator, &offset, &name, &namelen, - &errorcode, cb)) goto FAILED; + &errorcode, cb)) goto ESCAPE_FAILED; /* \k and \g when used with braces are back references, whereas \g used with quotes or angle brackets is a recursion */ @@ -2776,7 +2857,7 @@ while (ptr < ptrend) PUTOFFSET(offset, parsed_pattern); okquantifier = TRUE; - break; + break; /* End special escape processing */ } break; /* End escape sequence processing */ @@ -2908,7 +2989,8 @@ while (ptr < ptrend) /* Process a regular character class. If the first character is '^', set the negation flag. If the first few characters (either before or after ^) - are \Q\E or \E we skip them too. This makes for compatibility with Perl. */ + are \Q\E or \E or space or tab in extended-more mode, we skip them too. + This makes for compatibility with Perl. */ negate_class = FALSE; while (ptr < ptrend) @@ -2923,6 +3005,9 @@ while (ptr < ptrend) else break; } + else if ((options & PCRE2_EXTENDED_MORE) != 0 && + (c == CHAR_SPACE || c == CHAR_HT)) /* Note: just these two */ + continue; else if (!negate_class && c == CHAR_CIRCUMFLEX_ACCENT) negate_class = TRUE; else break; @@ -2970,6 +3055,12 @@ while (ptr < ptrend) goto CLASS_LITERAL; } + /* Skip over space and tab (only) in extended-more mode. */ + + if ((options & PCRE2_EXTENDED_MORE) != 0 && + (c == CHAR_SPACE || c == CHAR_HT)) + goto CLASS_CONTINUE; + /* Handle POSIX class names. Perl allows a negation extension of the form [:^name:]. A square bracket that doesn't match the syntax is treated as a literal. We also recognize the POSIX constructions @@ -3017,21 +3108,23 @@ while (ptr < ptrend) ptr = tempptr + 2; /* Perl treats a hyphen after a POSIX class as a literal, not the - start of a range. However, it gives a warning in its warning mode. PCRE - does not have a warning mode, so we give an error, because this is - likely an error on the user's part. */ + start of a range. However, it gives a warning in its warning mode + unless the hyphen is the last character in the class. PCRE does not + have a warning mode, so we give an error, because this is likely an + error on the user's part. */ - if (ptr < ptrend && *ptr == CHAR_MINUS) + if (ptr < ptrend - 1 && *ptr == CHAR_MINUS && + ptr[1] != CHAR_RIGHT_SQUARE_BRACKET) { errorcode = ERR50; goto FAILED; } - /* Set "a hyphen is not the start of a range" just in case the POSIX - class is followed by \E or \Q\E (possibly repeated - fuzzers do that - kind of thing) and *then* a hyphen. This causes that hyphen to be - treated as a literal. I don't think it's worth setting up special - apparatus to do otherwise. */ + /* Set "a hyphen is not the start of a range" for the -] case, and also + in case the POSIX class is followed by \E or \Q\E (possibly repeated - + fuzzers do that kind of thing) and *then* a hyphen. This causes that + hyphen to be treated as a literal. I don't think it's worth setting up + special apparatus to do otherwise. */ class_range_state = RANGE_NO; @@ -3113,10 +3206,23 @@ while (ptr < ptrend) else { + tempptr = ptr; escape = PRIV(check_escape)(&ptr, ptrend, &c, &errorcode, options, TRUE, cb); - if (errorcode != 0) goto FAILED; + if (errorcode != 0) + { + CLASS_ESCAPE_FAILED: + if ((cb->cx->extra_options & PCRE2_EXTRA_BAD_ESCAPE_IS_LITERAL) == 0) + goto FAILED; + ptr = tempptr; + if (ptr >= ptrend) c = CHAR_BACKSLASH; else + { + GETCHARINCTEST(c, ptr); /* Get character value, increment pointer */ + } + escape = 0; /* Treat as literal character */ + } + if (escape == 0) /* Escaped character code point is in c */ { char_is_literal = FALSE; @@ -3150,7 +3256,7 @@ while (ptr < ptrend) if (class_range_state == RANGE_STARTED) { errorcode = ERR50; - goto FAILED; + goto CLASS_ESCAPE_FAILED; } /* Of the remaining escapes, only those that define characters are @@ -3161,7 +3267,7 @@ while (ptr < ptrend) { case ESC_N: errorcode = ERR71; /* Not supported in a class */ - goto FAILED; + goto CLASS_ESCAPE_FAILED; case ESC_H: case ESC_h: @@ -3224,13 +3330,24 @@ while (ptr < ptrend) } #else errorcode = ERR45; - goto FAILED; + goto CLASS_ESCAPE_FAILED; #endif break; /* End \P and \p */ default: /* All others are not allowed in a class */ errorcode = ERR7; - goto FAILED_BACK; + ptr--; + goto CLASS_ESCAPE_FAILED; + } + + /* Perl gives a warning unless a following hyphen is the last character + in the class. PCRE throws an error. */ + + if (ptr < ptrend - 1 && *ptr == CHAR_MINUS && + ptr[1] != CHAR_RIGHT_SQUARE_BRACKET) + { + errorcode = ERR50; + goto FAILED; } } @@ -3388,8 +3505,7 @@ while (ptr < ptrend) } top_nest->nest_depth = nest_depth; top_nest->flags = 0; - if ((options & PCRE2_EXTENDED) != 0) top_nest->flags |= NSF_EXTENDED; - if ((options & PCRE2_DUPNAMES) != 0) top_nest->flags |= NSF_DUPNAMES; + top_nest->options = options & PARSE_TRACKED_OPTIONS; /* Start of non-capturing group that resets the capture count for each branch. */ @@ -3404,9 +3520,7 @@ while (ptr < ptrend) ptr++; } - /* Scan for options imsxJU. We need to keep track of (?x) and (?J) for - use while scanning. The other options are used during the compiling - phases. */ + /* Scan for options imnsxJU to be set or unset. */ else { @@ -3429,16 +3543,36 @@ while (ptr < ptrend) case CHAR_i: *optset |= PCRE2_CASELESS; break; case CHAR_m: *optset |= PCRE2_MULTILINE; break; + case CHAR_n: *optset |= PCRE2_NO_AUTO_CAPTURE; break; case CHAR_s: *optset |= PCRE2_DOTALL; break; - case CHAR_x: *optset |= PCRE2_EXTENDED; break; case CHAR_U: *optset |= PCRE2_UNGREEDY; break; + /* If x appears twice it sets the extended extended option. */ + + case CHAR_x: + *optset |= PCRE2_EXTENDED; + if (ptr < ptrend && *ptr == CHAR_x) + { + *optset |= PCRE2_EXTENDED_MORE; + ptr++; + } + break; + default: errorcode = ERR11; ptr--; /* Correct the offset */ goto FAILED; } } + + /* If we are setting extended without extended-more, ensure that any + existing extended-more gets unset. Also, unsetting extended must also + unset extended-more. */ + + if ((set & (PCRE2_EXTENDED|PCRE2_EXTENDED_MORE)) == PCRE2_EXTENDED || + (unset & PCRE2_EXTENDED) != 0) + unset |= PCRE2_EXTENDED_MORE; + options = (options | set) & (~unset); /* If the options ended with ')' this is not the start of a nested @@ -3917,8 +4051,7 @@ while (ptr < ptrend) } top_nest->nest_depth = nest_depth; top_nest->flags = NSF_CONDASSERT; - if ((options & PCRE2_EXTENDED) != 0) top_nest->flags |= NSF_EXTENDED; - if ((options & PCRE2_DUPNAMES) != 0) top_nest->flags |= NSF_DUPNAMES; + top_nest->options = options & PARSE_TRACKED_OPTIONS; } break; @@ -4039,20 +4172,17 @@ while (ptr < ptrend) break; /* End of group; reset the capture count to the maximum if we are in a (?| - group and/or reset the extended and dupnames options. Disallow quantifier - for a condition that is an assertion. */ + group and/or reset the options that are tracked during parsing. Disallow + quantifier for a condition that is an assertion. */ case CHAR_RIGHT_PARENTHESIS: okquantifier = TRUE; if (top_nest != NULL && top_nest->nest_depth == nest_depth) { + options = (options & ~PARSE_TRACKED_OPTIONS) | top_nest->options; if ((top_nest->flags & NSF_RESET) != 0 && top_nest->max_group > cb->bracount) cb->bracount = top_nest->max_group; - if ((top_nest->flags & NSF_EXTENDED) != 0) options |= PCRE2_EXTENDED; - else options &= ~PCRE2_EXTENDED; - if ((top_nest->flags & NSF_DUPNAMES) != 0) options |= PCRE2_DUPNAMES; - else options &= ~PCRE2_DUPNAMES; if ((top_nest->flags & NSF_CONDASSERT) != 0) okquantifier = FALSE; if (top_nest == (nest_save *)(cb->start_workspace)) top_nest = NULL; @@ -4079,9 +4209,24 @@ if (inverbname && ptr >= ptrend) /* Manage callout for the final item */ -parsed_pattern = manage_callouts(ptr, &previous_callout, options, +PARSED_END: +parsed_pattern = manage_callouts(ptr, &previous_callout, auto_callout, parsed_pattern, cb); +/* Insert trailing items for word and line matching (features provided for the +benefit of pcre2grep). */ + +if ((cb->cx->extra_options & PCRE2_EXTRA_MATCH_LINE) != 0) + { + *parsed_pattern++ = META_KET; + *parsed_pattern++ = META_DOLLAR; + } +else if ((cb->cx->extra_options & PCRE2_EXTRA_MATCH_WORD) != 0) + { + *parsed_pattern++ = META_KET; + *parsed_pattern++ = META_ESCAPE + ESC_b; + } + /* Terminate the parsed pattern, then return success if all groups are closed. Otherwise we have unclosed parentheses. */ @@ -4090,6 +4235,7 @@ if (parsed_pattern >= parsed_pattern_end) errorcode = ERR63; /* Internal error (parsed pattern overflow) */ goto FAILED; } + *parsed_pattern = META_END; if (nest_depth == 0) return 0; @@ -4168,6 +4314,18 @@ for (;;) code += GET(code, 1 + 2*LINK_SIZE); break; + case OP_SKIPZERO: + code += 2 + GET(code, 2) + LINK_SIZE; + break; + + case OP_COND: + case OP_SCOND: + if (code[1+LINK_SIZE] != OP_FALSE || /* Not DEFINE */ + code[GET(code, 1)] != OP_KET) /* More than one branch */ + return code; + code += GET(code, 1) + 1 + LINK_SIZE; + break; + default: return code; } @@ -4750,7 +4908,6 @@ for (;; pptr++) int class_has_8bitchar; int i; uint32_t mclength; - uint32_t templastcapture; uint32_t skipunits; uint32_t subreqcu, subfirstcu; uint32_t groupnumber; @@ -5202,6 +5359,10 @@ for (;; pptr++) options & ~PCRE2_CASELESS, cb, PRIV(vspace_list)); break; + /* If Unicode is not supported, \P and \p are not allowed and are + faulted at parse time, so will never appear here. */ + +#ifdef SUPPORT_UNICODE case ESC_p: case ESC_P: { @@ -5210,12 +5371,11 @@ for (;; pptr++) *class_uchardata++ = (escape == ESC_p)? XCL_PROP : XCL_NOTPROP; *class_uchardata++ = ptype; *class_uchardata++ = pdata; -#ifdef SUPPORT_WIDE_CHARS xclass_has_prop = TRUE; -#endif class_has_8bitchar--; /* Undo! */ } break; +#endif } goto CONTINUE_CLASS; @@ -5757,7 +5917,6 @@ for (;; pptr++) pptr++; tempcode = code; tempreqvary = cb->req_varyopt; /* Save value before group */ - templastcapture = cb->lastcapture; /* Save value before group */ length_prevgroup = 0; /* Initialize for pre-compile phase */ if ((group_return = @@ -5787,12 +5946,6 @@ for (;; pptr++) if (note_group_empty && bravalue != OP_COND && group_return > 0) matched_char = TRUE; - /* If that was an atomic group and there are no capturing groups within it, - generate OP_ONCE_NC instead of OP_ONCE. */ - - if (bravalue == OP_ONCE && cb->lastcapture <= templastcapture) - *code = OP_ONCE_NC; - /* If we've just compiled an assertion, pop the assert depth. */ if (bravalue >= OP_ASSERT && bravalue <= OP_ASSERTBACK_NOT) @@ -6117,7 +6270,7 @@ for (;; pptr++) } else *callout_string++ = *pp++; } - *callout_string++ = CHAR_NULL; + *callout_string++ = CHAR_NUL; /* Set the length of the entire item, the advance to its end. */ @@ -6213,24 +6366,6 @@ for (;; pptr++) tempcode = previous; op_previous = *previous; - /* If previous was a recursion call, wrap it in atomic brackets so that - previous becomes the atomic group. All recursions were so wrapped in the - past, but it no longer happens for non-repeated recursions. In fact, the - repeated ones could be re-implemented independently so as not to need this, - but for the moment we rely on the code for repeating groups. */ - - if (op_previous == OP_RECURSE) - { - memmove(previous + 1 + LINK_SIZE, previous, CU2BYTES(1 + LINK_SIZE)); - op_previous = *previous = OP_ONCE; - PUT(previous, 1, 2 + 2*LINK_SIZE); - previous[2 + 2*LINK_SIZE] = OP_KET; - PUT(previous, 3 + 2*LINK_SIZE, 2 + 2*LINK_SIZE); - code += 2 + 2 * LINK_SIZE; - length_prevgroup = 3 + 3*LINK_SIZE; - group_return = -1; /* Set "may match empty string" */ - } - /* Now handle repetition for the different types of item. */ switch (op_previous) @@ -6315,6 +6450,77 @@ for (;; pptr++) case OP_FAIL: goto END_REPEAT; + /* Prior to 10.30, repeated recursions were wrapped in OP_ONCE brackets + because pcre2_match() could not handle backtracking into recursively + called groups. Now that this backtracking is available, we no longer need + to do this. However, we still need to replicate recursions as we do for + groups so as to have independent backtracking points. We can replicate + for the minimum number of repeats directly. For optional repeats we now + wrap the recursion in OP_BRA brackets and make use of the bracket + repetition. */ + + case OP_RECURSE: + + /* Generate unwrapped repeats for a non-zero minimum, except when the + minimum is 1 and the maximum unlimited, because that can be handled with + OP_BRA terminated by OP_KETRMAX/MIN. When the maximum is equal to the + minimum, we just need to generate the appropriate additional copies. + Otherwise we need to generate one more, to simulate the situation when + the minimum is zero. */ + + if (repeat_min > 0 && (repeat_min != 1 || repeat_max != REPEAT_UNLIMITED)) + { + int replicate = repeat_min; + if (repeat_min == repeat_max) replicate--; + + /* In the pre-compile phase, we don't actually do the replication. We + just adjust the length as if we had. Do some paranoid checks for + potential integer overflow. The INT64_OR_DOUBLE type is a 64-bit + integer type when available, otherwise double. */ + + if (lengthptr != NULL) + { + PCRE2_SIZE delta = replicate*(1 + LINK_SIZE); + if ((INT64_OR_DOUBLE)replicate* + (INT64_OR_DOUBLE)(1 + LINK_SIZE) > + (INT64_OR_DOUBLE)INT_MAX || + OFLOW_MAX - *lengthptr < delta) + { + *errorcodeptr = ERR20; + return 0; + } + *lengthptr += delta; + } + + else for (i = 0; i < replicate; i++) + { + memcpy(code, previous, CU2BYTES(1 + LINK_SIZE)); + previous = code; + code += 1 + LINK_SIZE; + } + + /* If the number of repeats is fixed, we are done. Otherwise, adjust + the counts and fall through. */ + + if (repeat_min == repeat_max) break; + if (repeat_max != REPEAT_UNLIMITED) repeat_max -= repeat_min; + repeat_min = 0; + } + + /* Wrap the recursion call in OP_BRA brackets. */ + + memmove(previous + 1 + LINK_SIZE, previous, CU2BYTES(1 + LINK_SIZE)); + op_previous = *previous = OP_BRA; + PUT(previous, 1, 2 + 2*LINK_SIZE); + previous[2 + 2*LINK_SIZE] = OP_KET; + PUT(previous, 3 + 2*LINK_SIZE, 2 + 2*LINK_SIZE); + code += 2 + 2 * LINK_SIZE; + length_prevgroup = 3 + 3*LINK_SIZE; + group_return = -1; /* Set "may match empty string" */ + + /* Now treat as a repeated OP_BRA. */ + /* Fall through */ + /* If previous was a bracket group, we may have to replicate it in certain cases. Note that at this point we can encounter only the "basic" bracket opcodes such as BRA and CBRA, as this is the place where they get @@ -6327,7 +6533,6 @@ for (;; pptr++) case OP_ASSERTBACK: case OP_ASSERTBACK_NOT: case OP_ONCE: - case OP_ONCE_NC: case OP_BRA: case OP_CBRA: case OP_COND: @@ -6344,10 +6549,10 @@ for (;; pptr++) previous[GET(previous, 1)] != OP_ALT) goto END_REPEAT; - /* There is no sense in actually repeating assertions. The only potential - use of repetition is in cases when the assertion is optional. Therefore, - if the minimum is greater than zero, just ignore the repeat. If the - maximum is not zero or one, set it to 1. */ + /* There is no sense in actually repeating assertions. The only + potential use of repetition is in cases when the assertion is optional. + Therefore, if the minimum is greater than zero, just ignore the repeat. + If the maximum is not zero or one, set it to 1. */ if (op_previous < OP_ONCE) /* Assertion */ { @@ -6571,14 +6776,12 @@ for (;; pptr++) /* Convert possessive ONCE brackets to non-capturing */ - if ((*bracode == OP_ONCE || *bracode == OP_ONCE_NC) && - possessive_quantifier) *bracode = OP_BRA; + if (*bracode == OP_ONCE && possessive_quantifier) *bracode = OP_BRA; /* For non-possessive ONCE brackets, all we need to do is to set the KET. */ - if (*bracode == OP_ONCE || *bracode == OP_ONCE_NC) - *ketcode = OP_KETRMAX + repeat_type; + if (*bracode == OP_ONCE) *ketcode = OP_KETRMAX + repeat_type; /* Handle non-ONCE brackets and possessive ONCEs (which have been converted to non-capturing above). */ @@ -7147,7 +7350,6 @@ for (;; pptr++) if (mclength == 1 || req_caseopt == 0) { - firstcu = mcbuffer[0] | req_caseopt; firstcu = mcbuffer[0]; firstcuflags = req_caseopt; if (mclength != 1) @@ -7572,7 +7774,7 @@ do { /* Atomic groups */ - else if (op == OP_ONCE || op == OP_ONCE_NC) + else if (op == OP_ONCE) { if (!is_anchored(scode, bracket_map, cb, atomcount + 1, inassert)) return FALSE; @@ -7702,7 +7904,7 @@ do { /* Atomic brackets */ - else if (op == OP_ONCE || op == OP_ONCE_NC) + else if (op == OP_ONCE) { if (!is_startline(scode, bracket_map, cb, atomcount + 1, inassert)) return FALSE; @@ -7724,9 +7926,8 @@ do { } /* Check for explicit circumflex; anything else gives a FALSE result. Note - in particular that this includes atomic brackets OP_ONCE and OP_ONCE_NC - because the number of characters matched by .* cannot be adjusted inside - them. */ + in particular that this includes atomic brackets OP_ONCE because the number + of characters matched by .* cannot be adjusted inside them. */ else if (op != OP_CIRC && op != OP_CIRCM) return FALSE; @@ -7937,7 +8138,6 @@ do { case OP_SCBRAPOS: case OP_ASSERT: case OP_ONCE: - case OP_ONCE_NC: d = find_firstassertedcu(scode, &dflags, op == OP_ASSERT); if (dflags < 0) return 0; @@ -8053,6 +8253,10 @@ the end of the branch, it is called to skip over an internal lookaround, and it is also called to skip to the end of a class, during which it will never encounter nested groups (but there's no need to have special code for that). +When called to find the end of a branch or group, pptr must point to the first +meta code inside the branch, not the branch-starting code. In other cases it +can point to the item that causes the function to be called. + Arguments: pptr current pointer to skip from skiptype PSKIP_CLASS when skipping to end of class @@ -8069,7 +8273,7 @@ parsed_skip(uint32_t *pptr, uint32_t skiptype) { uint32_t nestlevel = 0; -for (pptr += 1;; pptr++) +for (;; pptr++) { uint32_t meta = META_CODE(*pptr); @@ -8164,11 +8368,12 @@ return pptr; /* This is called for nested groups within a branch of a lookbehind whose length is being computed. If all the branches in the nested group have the same length, that is OK. On entry, the pointer must be at the first element after -the group initializing code. Caching is used to improve processing speed when -the same capturing group occurs many times. +the group initializing code. On exit it points to OP_KET. Caching is used to +improve processing speed when the same capturing group occurs many times. Arguments: pptrptr pointer to pointer in the parsed pattern + isinline FALSE if a reference or recursion; TRUE for inline group errcodeptr pointer to the errorcode lcptr pointer to the loop counter group number of captured group or -1 for a non-capturing group @@ -8179,27 +8384,29 @@ Returns: the group length or a negative number */ static int -get_grouplength(uint32_t **pptrptr, int *errcodeptr, int *lcptr, +get_grouplength(uint32_t **pptrptr, BOOL isinline, int *errcodeptr, int *lcptr, int group, parsed_recurse_check *recurses, compile_block *cb) { int branchlength; int grouplength = -1; /* The cache can be used only if there is no possibility of there being two -groups with the same number. */ +groups with the same number. We do not need to set the end pointer for a group +that is being processed as a back reference or recursion, but we must do so for +an inline group. */ -if (group > 0) +if (group > 0 && (cb->external_flags & PCRE2_DUPCAPUSED) == 0) { uint32_t groupinfo = cb->groupinfo[group]; - if ((cb->external_flags & PCRE2_DUPCAPUSED) == 0) + if ((groupinfo & GI_NOT_FIXED_LENGTH) != 0) return -1; + if ((groupinfo & GI_SET_FIXED_LENGTH) != 0) { - if ((groupinfo & GI_NOT_FIXED_LENGTH) != 0) return -1; - if ((groupinfo & GI_SET_FIXED_LENGTH) != 0) - return groupinfo & GI_FIXED_LENGTH_MASK; + if (isinline) *pptrptr = parsed_skip(*pptrptr, PSKIP_KET); + return groupinfo & GI_FIXED_LENGTH_MASK; } } -/* Scan the group */ +/* Scan the group. In this case we find the end pointer of necessity. */ for(;;) { @@ -8357,11 +8564,12 @@ for (;; pptr++) } break; - /* Lookaheads can be ignored. */ + /* Lookaheads can be ignored, but we must start the skip inside the group + so that it isn't treated as a group within the branch. */ case META_LOOKAHEAD: case META_LOOKAHEADNOT: - pptr = parsed_skip(pptr, PSKIP_KET); + pptr = parsed_skip(pptr + 1, PSKIP_KET); if (pptr == NULL) goto PARSED_SKIP_FAILED; break; @@ -8382,6 +8590,7 @@ for (;; pptr++) case META_BACKREF_BYNAME: if ((cb->external_options & PCRE2_MATCH_UNSET_BACKREF) != 0) goto ISNOTFIXED; + /* Fall through */ case META_RECURSE_BYNAME: { @@ -8436,7 +8645,8 @@ for (;; pptr++) goto RECURSE_OR_BACKREF_LENGTH; } - /* Fall through for groups >= 10 - picking up group twice does no harm. */ + /* Fall through */ + /* For groups >= 10 - picking up group twice does no harm. */ /* A true recursion implies not fixed length, but a subroutine call may be OK. Back reference "recursions" are also failed. */ @@ -8459,15 +8669,24 @@ for (;; pptr++) else if (*gptr == (META_CAPTURE | group)) break; } - gptrend = parsed_skip(gptr, PSKIP_KET); + /* We must start the search for the end of the group at the first meta code + inside the group. Otherwise it will be treated as an enclosed group. */ + + gptrend = parsed_skip(gptr + 1, PSKIP_KET); if (gptrend == NULL) goto PARSED_SKIP_FAILED; if (pptr > gptr && pptr < gptrend) goto ISNOTFIXED; /* Local recursion */ for (r = recurses; r != NULL; r = r->prev) if (r->groupptr == gptr) break; if (r != NULL) goto ISNOTFIXED; /* Mutual recursion */ this_recurse.prev = recurses; this_recurse.groupptr = gptr; + + /* We do not need to know the position of the end of the group, that is, + gptr is not used after the call to get_grouplength(). Setting the second + argument FALSE stops it scanning for the end when the length can be found + in the cache. */ + gptr++; - grouplength = get_grouplength(&gptr, errcodeptr, lcptr, group, + grouplength = get_grouplength(&gptr, FALSE, errcodeptr, lcptr, group, &this_recurse, cb); if (grouplength < 0) { @@ -8504,7 +8723,8 @@ for (;; pptr++) case META_NOCAPTURE: pptr++; CHECK_GROUP: - grouplength = get_grouplength(&pptr, errcodeptr, lcptr, group, recurses, cb); + grouplength = get_grouplength(&pptr, TRUE, errcodeptr, lcptr, group, + recurses, cb); if (grouplength < 0) return -1; itemlength = grouplength; break; @@ -8764,7 +8984,7 @@ pcre2_compile(PCRE2_SPTR pattern, PCRE2_SIZE patlen, uint32_t options, int *errorptr, PCRE2_SIZE *erroroffset, pcre2_compile_context *ccontext) { BOOL utf; /* Set TRUE for UTF mode */ -BOOL has_lookbehind; /* Set TRUE if a lookbehind is found */ +BOOL has_lookbehind = FALSE; /* Set TRUE if a lookbehind is found */ BOOL zero_terminated; /* Set TRUE for zero-terminated pattern */ pcre2_real_code *re = NULL; /* What we will return */ compile_block cb; /* "Static" compile-time data */ @@ -8786,8 +9006,9 @@ uint32_t firstcu, reqcu; /* Value of first/req code unit */ uint32_t setflags = 0; /* NL and BSR set flags */ uint32_t skipatstart; /* When checking (*UTF) etc */ +uint32_t limit_heap = UINT32_MAX; uint32_t limit_match = UINT32_MAX; /* Unset match limits */ -uint32_t limit_recursion = UINT32_MAX; +uint32_t limit_depth = UINT32_MAX; int newline = 0; /* Unset; can be set by the pattern */ int bsr = 0; /* Unset; can be set by the pattern */ @@ -8825,18 +9046,27 @@ if (pattern == NULL) return NULL; } +/* A NULL compile context means "use a default context" */ + +if (ccontext == NULL) + ccontext = (pcre2_compile_context *)(&PRIV(default_compile_context)); + /* Check that all undefined public option bits are zero. */ -if ((options & ~PUBLIC_COMPILE_OPTIONS) != 0) +if ((options & ~PUBLIC_COMPILE_OPTIONS) != 0 || + (ccontext->extra_options & ~PUBLIC_COMPILE_EXTRA_OPTIONS) != 0) { *errorptr = ERR17; return NULL; } -/* A NULL compile context means "use a default context" */ - -if (ccontext == NULL) - ccontext = (pcre2_compile_context *)(&PRIV(default_compile_context)); +if ((options & PCRE2_LITERAL) != 0 && + ((options & ~PUBLIC_LITERAL_COMPILE_OPTIONS) != 0 || + (ccontext->extra_options & ~PUBLIC_LITERAL_COMPILE_EXTRA_OPTIONS) != 0)) + { + *errorptr = ERR92; + return NULL; + } /* A zero-terminated pattern is indicated by the special length value PCRE2_ZERO_TERMINATED. Check for an overlong pattern. */ @@ -8911,10 +9141,11 @@ for (i = 0; i < 10; i++) cb.small_ref_offset[i] = PCRE2_UNSET; /* --------------- Start looking at the pattern --------------- */ -/* Check for global one-time option settings at the start of the pattern, and -remember the offset to the actual regex. With valgrind support, make the -terminator of a zero-terminated pattern inaccessible. This catches bugs that -would otherwise only show up for non-zero-terminated patterns. */ +/* Unless PCRE2_LITERAL is set, check for global one-time option settings at +the start of the pattern, and remember the offset to the actual regex. With +valgrind support, make the terminator of a zero-terminated pattern +inaccessible. This catches bugs that would otherwise only show up for +non-zero-terminated patterns. */ #ifdef SUPPORT_VALGRIND if (zero_terminated) VALGRIND_MAKE_MEM_NOACCESS(pattern + patlen, CU2BYTES(1)); @@ -8923,70 +9154,75 @@ if (zero_terminated) VALGRIND_MAKE_MEM_NOACCESS(pattern + patlen, CU2BYTES(1)); ptr = pattern; skipatstart = 0; -while (patlen - skipatstart >= 2 && - ptr[skipatstart] == CHAR_LEFT_PARENTHESIS && - ptr[skipatstart+1] == CHAR_ASTERISK) +if ((options & PCRE2_LITERAL) == 0) { - for (i = 0; i < sizeof(pso_list)/sizeof(pso); i++) + while (patlen - skipatstart >= 2 && + ptr[skipatstart] == CHAR_LEFT_PARENTHESIS && + ptr[skipatstart+1] == CHAR_ASTERISK) { - pso *p = pso_list + i; - - if (patlen - skipatstart - 2 >= p->length && - PRIV(strncmp_c8)(ptr+skipatstart+2, (char *)(p->name), p->length) == 0) + for (i = 0; i < sizeof(pso_list)/sizeof(pso); i++) { uint32_t c, pp; + pso *p = pso_list + i; - skipatstart += p->length + 2; - switch(p->type) + if (patlen - skipatstart - 2 >= p->length && + PRIV(strncmp_c8)(ptr + skipatstart + 2, (char *)(p->name), + p->length) == 0) { - case PSO_OPT: - cb.external_options |= p->value; - break; + skipatstart += p->length + 2; + switch(p->type) + { + case PSO_OPT: + cb.external_options |= p->value; + break; - case PSO_FLG: - setflags |= p->value; - break; + case PSO_FLG: + setflags |= p->value; + break; - case PSO_NL: - newline = p->value; - setflags |= PCRE2_NL_SET; - break; + case PSO_NL: + newline = p->value; + setflags |= PCRE2_NL_SET; + break; - case PSO_BSR: - bsr = p->value; - setflags |= PCRE2_BSR_SET; - break; + case PSO_BSR: + bsr = p->value; + setflags |= PCRE2_BSR_SET; + break; - case PSO_LIMM: - case PSO_LIMR: - c = 0; - pp = skipatstart; - if (!IS_DIGIT(ptr[pp])) - { - errorcode = ERR60; - ptr += pp; - goto HAD_EARLY_ERROR; - } - while (IS_DIGIT(ptr[pp])) - { - if (c > UINT32_MAX / 10 - 1) break; /* Integer overflow */ - c = c*10 + (ptr[pp++] - CHAR_0); - } - if (ptr[pp++] != CHAR_RIGHT_PARENTHESIS) - { - errorcode = ERR60; - ptr += pp; - goto HAD_EARLY_ERROR; + case PSO_LIMM: + case PSO_LIMD: + case PSO_LIMH: + c = 0; + pp = skipatstart; + if (!IS_DIGIT(ptr[pp])) + { + errorcode = ERR60; + ptr += pp; + goto HAD_EARLY_ERROR; + } + while (IS_DIGIT(ptr[pp])) + { + if (c > UINT32_MAX / 10 - 1) break; /* Integer overflow */ + c = c*10 + (ptr[pp++] - CHAR_0); + } + if (ptr[pp++] != CHAR_RIGHT_PARENTHESIS) + { + errorcode = ERR60; + ptr += pp; + goto HAD_EARLY_ERROR; + } + if (p->type == PSO_LIMH) limit_heap = c; + else if (p->type == PSO_LIMM) limit_match = c; + else limit_depth = c; + skipatstart += pp - skipatstart; + break; } - if (p->type == PSO_LIMM) limit_match = c; - else limit_recursion = c; - skipatstart += pp - skipatstart; - break; + break; /* Out of the table scan loop */ } - break; /* Out of the table scan loop */ } + if (i >= sizeof(pso_list)/sizeof(pso)) break; /* Out of pso loop */ } - if (i >= sizeof(pso_list)/sizeof(pso)) break; /* Out of pso loop */ } /* End of pattern-start options; advance to start of real regex. */ @@ -9004,7 +9240,9 @@ if ((cb.external_options & (PCRE2_UTF|PCRE2_UCP)) != 0) #endif /* Check UTF. We have the original options in 'options', with that value as -modified by (*UTF) etc in cb->external_options. */ +modified by (*UTF) etc in cb->external_options. The extra option +PCRE2_EXTRA_ALLOW_SURROGATE_ESCAPES is not permitted in UTF-16 mode because the +surrogate code points cannot be represented in UTF-16. */ utf = (cb.external_options & PCRE2_UTF) != 0; if (utf) @@ -9017,6 +9255,14 @@ if (utf) if ((options & PCRE2_NO_UTF_CHECK) == 0 && (errorcode = PRIV(valid_utf)(pattern, patlen, erroroffset)) != 0) goto HAD_ERROR; /* Offset was set by valid_utf() */ + +#if PCRE2_CODE_UNIT_WIDTH == 16 + if ((ccontext->extra_options & PCRE2_EXTRA_ALLOW_SURROGATE_ESCAPES) != 0) + { + errorcode = ERR91; + goto HAD_EARLY_ERROR; + } +#endif } /* Check UCP lockout. */ @@ -9048,6 +9294,11 @@ switch(newline) cb.nl[0] = CHAR_NL; break; + case PCRE2_NEWLINE_NUL: + cb.nllen = 1; + cb.nl[0] = CHAR_NUL; + break; + case PCRE2_NEWLINE_CRLF: cb.nllen = 2; cb.nl[0] = CHAR_CR; @@ -9075,10 +9326,10 @@ and comments removed (amongst other things). In all but one case, when PCRE2_AUTO_CALLOUT is not set, the number of unsigned 32-bit ints in the parsed pattern is bounded by the length of the pattern plus -one (for the terminator). The exceptional case is when running in 32-bit, -non-UTF mode, when literal characters greater than META_END (0x80000000) have -to be coded as two units. In this case, therefore, we scan the pattern to check -for such values. */ +one (for the terminator) plus four if PCRE2_EXTRA_WORD or PCRE2_EXTRA_LINE is +set. The exceptional case is when running in 32-bit, non-UTF mode, when literal +characters greater than META_END (0x80000000) have to be coded as two units. In +this case, therefore, we scan the pattern to check for such values. */ #if PCRE2_CODE_UNIT_WIDTH == 32 if (!utf) @@ -9095,6 +9346,11 @@ many smaller patterns the vector on the stack (which was set up above) can be used. */ parsed_size_needed = patlen - skipatstart + big32count; + +if ((ccontext->extra_options & + (PCRE2_EXTRA_MATCH_WORD|PCRE2_EXTRA_MATCH_LINE)) != 0) + parsed_size_needed += 4; + if ((options & PCRE2_AUTO_CALLOUT) != 0) parsed_size_needed = (parsed_size_needed + 1) * 5; @@ -9203,7 +9459,8 @@ possible because nowadays we limit the maximum value of cb.names_found and cb.name_entry_size. */ re_blocksize = sizeof(pcre2_real_code) + - CU2BYTES(length + cb.names_found * cb.name_entry_size); + CU2BYTES(length + + (PCRE2_SIZE)cb.names_found * (PCRE2_SIZE)cb.name_entry_size); re = (pcre2_real_code *) ccontext->memctl.malloc(re_blocksize, ccontext->memctl.memory_data); if (re == NULL) @@ -9212,6 +9469,13 @@ if (re == NULL) goto HAD_CB_ERROR; } +/* The compiler may put padding at the end of the pcre2_real_code structure in +order to round it up to a multiple of 4 or 8 bytes. This means that when a +compiled pattern is copied (for example, when serialized) undefined bytes are +read, and this annoys debuggers such as valgrind. To avoid this, we explicitly +write to the last 8 bytes of the structure before setting the fields. */ + +memset((char *)re + sizeof(pcre2_real_code) - 8, 0, 8); re->memctl = ccontext->memctl; re->tables = tables; re->executable_jit = NULL; @@ -9221,8 +9485,9 @@ re->magic_number = MAGIC_NUMBER; re->compile_options = options; re->overall_options = cb.external_options; re->flags = PCRE2_CODE_UNIT_WIDTH/8 | cb.external_flags | setflags; +re->limit_heap = limit_heap; re->limit_match = limit_match; -re->limit_recursion = limit_recursion; +re->limit_depth = limit_depth; re->first_codeunit = 0; re->last_codeunit = 0; re->bsr_convention = bsr; @@ -9394,14 +9659,19 @@ if ((re->overall_options & PCRE2_ANCHORED) == 0 && is_anchored(codestart, 0, &cb, 0, FALSE)) re->overall_options |= PCRE2_ANCHORED; -/* If the pattern is still not anchored and we do not have a first code unit, -see if there is one that is asserted (these are not saved during the compile -because they can cause conflicts with actual literals that follow). This code -need not be obeyed if PCRE2_NO_START_OPTIMIZE is set, as the data it would -create will not be used. */ +/* Set up the first code unit or startline flag, the required code unit, and +then study the pattern. This code need not be obeyed if PCRE2_NO_START_OPTIMIZE +is set, as the data it would create will not be used. Note that a first code +unit (but not the startline flag) is useful for anchored patterns because it +can still give a quick "no match" and also avoid searching for a last code +unit. */ -if ((re->overall_options & (PCRE2_ANCHORED|PCRE2_NO_START_OPTIMIZE)) == 0) +if ((re->overall_options & PCRE2_NO_START_OPTIMIZE) == 0) { + /* If we do not have a first code unit, see if there is one that is asserted + (these are not saved during the compile because they can cause conflicts with + actual literals that follow). */ + if (firstcuflags < 0) firstcu = find_firstassertedcu(codestart, &firstcuflags, FALSE); @@ -9434,52 +9704,50 @@ if ((re->overall_options & (PCRE2_ANCHORED|PCRE2_NO_START_OPTIMIZE)) == 0) } } - /* When there is no first code unit, see if we can set the PCRE2_STARTLINE - flag. This is helpful for multiline matches when all branches start with ^ - and also when all branches start with non-atomic .* for non-DOTALL matches - when *PRUNE and SKIP are not present. (There is an option that disables this - case.) */ + /* When there is no first code unit, for non-anchored patterns, see if we can + set the PCRE2_STARTLINE flag. This is helpful for multiline matches when all + branches start with ^ and also when all branches start with non-atomic .* for + non-DOTALL matches when *PRUNE and SKIP are not present. (There is an option + that disables this case.) */ - else if (is_startline(codestart, 0, &cb, 0, FALSE)) + else if ((re->overall_options & PCRE2_ANCHORED) == 0 && + is_startline(codestart, 0, &cb, 0, FALSE)) re->flags |= PCRE2_STARTLINE; - } -/* Handle the "required code unit", if one is set. In the case of an anchored -pattern, do this only if it follows a variable length item in the pattern. -Again, skip this if PCRE2_NO_START_OPTIMIZE is set. */ + /* Handle the "required code unit", if one is set. In the case of an anchored + pattern, do this only if it follows a variable length item in the pattern. */ -if (reqcuflags >= 0 && - ((re->overall_options & (PCRE2_ANCHORED|PCRE2_NO_START_OPTIMIZE)) == 0 || - (reqcuflags & REQ_VARY) != 0)) - { - re->last_codeunit = reqcu; - re->flags |= PCRE2_LASTSET; + if (reqcuflags >= 0 && + ((re->overall_options & PCRE2_ANCHORED) == 0 || + (reqcuflags & REQ_VARY) != 0)) + { + re->last_codeunit = reqcu; + re->flags |= PCRE2_LASTSET; - /* Handle caseless required code units as for first code units (above). */ + /* Handle caseless required code units as for first code units (above). */ - if ((reqcuflags & REQ_CASELESS) != 0) - { - if (reqcu < 128 || (!utf && reqcu < 255)) + if ((reqcuflags & REQ_CASELESS) != 0) { - if (cb.fcc[reqcu] != reqcu) re->flags |= PCRE2_LASTCASELESS; - } + if (reqcu < 128 || (!utf && reqcu < 255)) + { + if (cb.fcc[reqcu] != reqcu) re->flags |= PCRE2_LASTCASELESS; + } #if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 8 - else if (reqcu <= MAX_UTF_CODE_POINT && UCD_OTHERCASE(reqcu) != reqcu) - re->flags |= PCRE2_LASTCASELESS; + else if (reqcu <= MAX_UTF_CODE_POINT && UCD_OTHERCASE(reqcu) != reqcu) + re->flags |= PCRE2_LASTCASELESS; #endif + } } - } -/* Finally, unless PCRE2_NO_START_OPTIMIZE is set, study the compiled pattern -to set up information such as a bitmap of starting code units and a minimum -matching length. */ + /* Finally, study the compiled pattern to set up information such as a bitmap + of starting code units and a minimum matching length. */ -if ((re->overall_options & PCRE2_NO_START_OPTIMIZE) == 0 && - PRIV(study)(re) != 0) - { - errorcode = ERR31; - goto HAD_CB_ERROR; - } + if (PRIV(study)(re) != 0) + { + errorcode = ERR31; + goto HAD_CB_ERROR; + } + } /* End of start-of-match optimizations. */ /* Control ends up here in all cases. When running under valgrind, make a pattern's terminating zero defined again. If memory was obtained for the parsed diff --git a/ProcessHacker/pcre/pcre2_config.c b/ProcessHacker/pcre/pcre2_config.c index 89223ae957bc..d009c0a676a5 100644 --- a/ProcessHacker/pcre/pcre2_config.c +++ b/ProcessHacker/pcre/pcre2_config.c @@ -7,7 +7,7 @@ and semantics are as close as possible to those of the Perl 5 language. Written by Philip Hazel Original API code Copyright (c) 1997-2012 University of Cambridge - New API code Copyright (c) 2016 University of Cambridge + New API code Copyright (c) 2016-2017 University of Cambridge ----------------------------------------------------------------------------- Redistribution and use in source and binary forms, with or without @@ -38,7 +38,6 @@ POSSIBILITY OF SUCH DAMAGE. ----------------------------------------------------------------------------- */ -#define HAVE_CONFIG_H #ifdef HAVE_CONFIG_H #include "config.h" #endif @@ -85,13 +84,14 @@ if (where == NULL) /* Requests a length */ return PCRE2_ERROR_BADOPTION; case PCRE2_CONFIG_BSR: + case PCRE2_CONFIG_HEAPLIMIT: case PCRE2_CONFIG_JIT: case PCRE2_CONFIG_LINKSIZE: case PCRE2_CONFIG_MATCHLIMIT: + case PCRE2_CONFIG_DEPTHLIMIT: case PCRE2_CONFIG_NEWLINE: case PCRE2_CONFIG_PARENSLIMIT: - case PCRE2_CONFIG_RECURSIONLIMIT: - case PCRE2_CONFIG_STACKRECURSE: + case PCRE2_CONFIG_STACKRECURSE: /* Obsolete */ case PCRE2_CONFIG_UNICODE: return sizeof(uint32_t); @@ -117,6 +117,10 @@ switch (what) #endif break; + case PCRE2_CONFIG_HEAPLIMIT: + *((uint32_t *)where) = HEAP_LIMIT; + break; + case PCRE2_CONFIG_JIT: #ifdef SUPPORT_JIT *((uint32_t *)where) = 1; @@ -144,6 +148,10 @@ switch (what) *((uint32_t *)where) = MATCH_LIMIT; break; + case PCRE2_CONFIG_DEPTHLIMIT: + *((uint32_t *)where) = MATCH_LIMIT_DEPTH; + break; + case PCRE2_CONFIG_NEWLINE: *((uint32_t *)where) = NEWLINE_DEFAULT; break; @@ -152,16 +160,11 @@ switch (what) *((uint32_t *)where) = PARENS_NEST_LIMIT; break; - case PCRE2_CONFIG_RECURSIONLIMIT: - *((uint32_t *)where) = MATCH_LIMIT_RECURSION; - break; + /* This is now obsolete. The stack is no longer used via recursion for + handling backtracking in pcre2_match(). */ case PCRE2_CONFIG_STACKRECURSE: -#ifdef HEAP_MATCH_RECURSE *((uint32_t *)where) = 0; -#else - *((uint32_t *)where) = 1; -#endif break; case PCRE2_CONFIG_UNICODE_VERSION: diff --git a/ProcessHacker/pcre/pcre2_context.c b/ProcessHacker/pcre/pcre2_context.c index 096e8ee2f725..2c14df00805b 100644 --- a/ProcessHacker/pcre/pcre2_context.c +++ b/ProcessHacker/pcre/pcre2_context.c @@ -7,7 +7,7 @@ and semantics are as close as possible to those of the Perl 5 language. Written by Philip Hazel Original API code Copyright (c) 1997-2012 University of Cambridge - New API code Copyright (c) 2016 University of Cambridge + New API code Copyright (c) 2016-2017 University of Cambridge ----------------------------------------------------------------------------- Redistribution and use in source and binary forms, with or without @@ -38,9 +38,7 @@ POSSIBILITY OF SUCH DAMAGE. ----------------------------------------------------------------------------- */ -#include -#define HAVE_CONFIG_H #ifdef HAVE_CONFIG_H #include "config.h" #endif @@ -58,14 +56,14 @@ POSSIBILITY OF SUCH DAMAGE. static void *default_malloc(size_t size, void *data) { (void)data; -return PhAllocateSafe(size); +return malloc(size); } static void default_free(void *block, void *data) { (void)data; -PhFree(block); +free(block); } @@ -140,7 +138,8 @@ const pcre2_compile_context PRIV(default_compile_context) = { PCRE2_UNSET, /* Max pattern length */ BSR_DEFAULT, /* Backslash R default */ NEWLINE_DEFAULT, /* Newline convention */ - PARENS_NEST_LIMIT }; /* As it says */ + PARENS_NEST_LIMIT, /* As it says */ + 0 }; /* Extra options */ /* The create function copies the default into the new memory, but must override the default memory handling functions if a gcontext was provided. */ @@ -163,9 +162,6 @@ when no context is supplied to a match function. */ const pcre2_match_context PRIV(default_match_context) = { { default_malloc, default_free, NULL }, -#ifdef HEAP_MATCH_RECURSE - { default_malloc, default_free, NULL }, -#endif #ifdef SUPPORT_JIT NULL, NULL, @@ -173,8 +169,9 @@ const pcre2_match_context PRIV(default_match_context) = { NULL, NULL, PCRE2_UNSET, /* Offset limit */ + HEAP_LIMIT, MATCH_LIMIT, - MATCH_LIMIT_RECURSION }; + MATCH_LIMIT_DEPTH }; /* The create function copies the default into the new memory, but must override the default memory handling functions if a gcontext was provided. */ @@ -192,6 +189,36 @@ return mcontext; } +/* A default convert context is set up to save having to initialize at run time +when no context is supplied to the convert function. */ + +const pcre2_convert_context PRIV(default_convert_context) = { + { default_malloc, default_free, NULL }, /* Default memory handling */ +#ifdef _WIN32 + CHAR_BACKSLASH, /* Default path separator */ + CHAR_GRAVE_ACCENT /* Default escape character */ +#else /* Not Windows */ + CHAR_SLASH, /* Default path separator */ + CHAR_BACKSLASH /* Default escape character */ +#endif + }; + +/* The create function copies the default into the new memory, but must +override the default memory handling functions if a gcontext was provided. */ + +PCRE2_EXP_DEFN pcre2_convert_context * PCRE2_CALL_CONVENTION +pcre2_convert_context_create(pcre2_general_context *gcontext) +{ +pcre2_convert_context *ccontext = PRIV(memctl_malloc)( + sizeof(pcre2_real_convert_context), (pcre2_memctl *)gcontext); +if (ccontext == NULL) return NULL; +*ccontext = PRIV(default_convert_context); +if (gcontext != NULL) + *((pcre2_memctl *)ccontext) = *((pcre2_memctl *)gcontext); +return ccontext; +} + + /************************************************* * Context copy functions * *************************************************/ @@ -233,11 +260,22 @@ return new; +PCRE2_EXP_DEFN pcre2_convert_context * PCRE2_CALL_CONVENTION +pcre2_convert_context_copy(pcre2_convert_context *ccontext) +{ +pcre2_convert_context *new = + ccontext->memctl.malloc(sizeof(pcre2_real_convert_context), + ccontext->memctl.memory_data); +if (new == NULL) return NULL; +memcpy(new, ccontext, sizeof(pcre2_real_convert_context)); +return new; +} + + /************************************************* * Context free functions * *************************************************/ - PCRE2_EXP_DEFN void PCRE2_CALL_CONVENTION pcre2_general_context_free(pcre2_general_context *gcontext) { @@ -262,6 +300,12 @@ if (mcontext != NULL) } +PCRE2_EXP_DEFN void PCRE2_CALL_CONVENTION +pcre2_convert_context_free(pcre2_convert_context *ccontext) +{ +if (ccontext != NULL) + ccontext->memctl.free(ccontext, ccontext->memctl.memory_data); +} /************************************************* @@ -273,7 +317,7 @@ data is given. Only some of the functions are able to test the validity of the data. */ -/* ------------ Compile contexts ------------ */ +/* ------------ Compile context ------------ */ PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION pcre2_set_character_tables(pcre2_compile_context *ccontext, @@ -315,6 +359,7 @@ switch(newline) case PCRE2_NEWLINE_CRLF: case PCRE2_NEWLINE_ANY: case PCRE2_NEWLINE_ANYCRLF: + case PCRE2_NEWLINE_NUL: ccontext->newline_convention = newline; return 0; @@ -330,6 +375,13 @@ ccontext->parens_nest_limit = limit; return 0; } +PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION +pcre2_set_compile_extra_options(pcre2_compile_context *ccontext, uint32_t options) +{ +ccontext->extra_options = options; +return 0; +} + PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION pcre2_set_compile_recursion_guard(pcre2_compile_context *ccontext, int (*guard)(uint32_t, void *), void *user_data) @@ -340,7 +392,7 @@ return 0; } -/* ------------ Match contexts ------------ */ +/* ------------ Match context ------------ */ PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION pcre2_set_callout(pcre2_match_context *mcontext, @@ -351,6 +403,13 @@ mcontext->callout_data = callout_data; return 0; } +PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION +pcre2_set_heap_limit(pcre2_match_context *mcontext, uint32_t limit) +{ +mcontext->heap_limit = limit; +return 0; +} + PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION pcre2_set_match_limit(pcre2_match_context *mcontext, uint32_t limit) { @@ -358,6 +417,13 @@ mcontext->match_limit = limit; return 0; } +PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION +pcre2_set_depth_limit(pcre2_match_context *mcontext, uint32_t limit) +{ +mcontext->depth_limit = limit; +return 0; +} + PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION pcre2_set_offset_limit(pcre2_match_context *mcontext, PCRE2_SIZE limit) { @@ -365,11 +431,13 @@ mcontext->offset_limit = limit; return 0; } +/* This function became obsolete at release 10.30. It is kept as a synonym for +backwards compatibility. */ + PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION pcre2_set_recursion_limit(pcre2_match_context *mcontext, uint32_t limit) { -mcontext->recursion_limit = limit; -return 0; +return pcre2_set_depth_limit(mcontext, limit); } PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION @@ -377,17 +445,32 @@ pcre2_set_recursion_memory_management(pcre2_match_context *mcontext, void *(*mymalloc)(size_t, void *), void (*myfree)(void *, void *), void *mydata) { -#ifdef HEAP_MATCH_RECURSE -mcontext->stack_memctl.malloc = mymalloc; -mcontext->stack_memctl.free = myfree; -mcontext->stack_memctl.memory_data = mydata; -#else (void)mcontext; (void)mymalloc; (void)myfree; (void)mydata; -#endif +return 0; +} + +/* ------------ Convert context ------------ */ + +PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION +pcre2_set_glob_separator(pcre2_convert_context *ccontext, uint32_t separator) +{ +if (separator != CHAR_SLASH && separator != CHAR_BACKSLASH && + separator != CHAR_DOT) return PCRE2_ERROR_BADDATA; +ccontext->glob_separator = separator; +return 0; +} + +PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION +pcre2_set_glob_escape(pcre2_convert_context *ccontext, uint32_t escape) +{ +if (escape > 255 || (escape != 0 && !ispunct(escape))) + return PCRE2_ERROR_BADDATA; +ccontext->glob_escape = escape; return 0; } /* End of pcre2_context.c */ + diff --git a/ProcessHacker/pcre/pcre2_dfa_match.c b/ProcessHacker/pcre/pcre2_dfa_match.c index d0f756910bfc..5ae13944c72b 100644 --- a/ProcessHacker/pcre/pcre2_dfa_match.c +++ b/ProcessHacker/pcre/pcre2_dfa_match.c @@ -7,7 +7,7 @@ and semantics are as close as possible to those of the Perl 5 language. Written by Philip Hazel Original API code Copyright (c) 1997-2012 University of Cambridge - New API code Copyright (c) 2016 University of Cambridge + New API code Copyright (c) 2016-2017 University of Cambridge ----------------------------------------------------------------------------- Redistribution and use in source and binary forms, with or without @@ -71,7 +71,6 @@ only once - I suspect this was the cause of the problems with the tests.) Overall, I concluded that the gains in some cases did not outweigh the losses in others, so I abandoned this code. */ -#define HAVE_CONFIG_H #ifdef HAVE_CONFIG_H #include "config.h" @@ -84,7 +83,7 @@ in others, so I abandoned this code. */ #include "pcre2_internal.h" #define PUBLIC_DFA_MATCH_OPTIONS \ - (PCRE2_ANCHORED|PCRE2_NOTBOL|PCRE2_NOTEOL|PCRE2_NOTEMPTY| \ + (PCRE2_ANCHORED|PCRE2_ENDANCHORED|PCRE2_NOTBOL|PCRE2_NOTEOL|PCRE2_NOTEMPTY| \ PCRE2_NOTEMPTY_ATSTART|PCRE2_NO_UTF_CHECK|PCRE2_PARTIAL_HARD| \ PCRE2_PARTIAL_SOFT|PCRE2_DFA_SHORTEST|PCRE2_DFA_RESTART) @@ -173,7 +172,7 @@ static const uint8_t coptable[] = { 0, /* Assert not */ 0, /* Assert behind */ 0, /* Assert behind not */ - 0, 0, /* ONCE, ONCE_NC */ + 0, /* ONCE */ 0, 0, 0, 0, 0, /* BRA, BRAPOS, CBRA, CBRAPOS, COND */ 0, 0, 0, 0, 0, /* SBRA, SBRAPOS, SCBRA, SCBRAPOS, SCOND */ 0, 0, /* CREF, DNCREF */ @@ -246,7 +245,7 @@ static const uint8_t poptable[] = { 0, /* Assert not */ 0, /* Assert behind */ 0, /* Assert behind not */ - 0, 0, /* ONCE, ONCE_NC */ + 0, /* ONCE */ 0, 0, 0, 0, 0, /* BRA, BRAPOS, CBRA, CBRAPOS, COND */ 0, 0, 0, 0, 0, /* SBRA, SBRAPOS, SCBRA, SCBRAPOS, SCOND */ 0, 0, /* CREF, DNCREF */ @@ -376,14 +375,10 @@ internal_dfa_match( { stateblock *active_states, *new_states, *temp_states; stateblock *next_active_state, *next_new_state; - const uint8_t *ctypes, *lcc, *fcc; PCRE2_SPTR ptr; PCRE2_SPTR end_code; -PCRE2_SPTR first_op; - dfa_recursion_info new_recursive; - int active_count, new_count, match_count; /* Some fields in the mb block are frequently referenced, so we load them into @@ -401,7 +396,8 @@ BOOL utf = FALSE; BOOL reset_could_continue = FALSE; -if (rlevel++ > mb->match_limit_recursion) return PCRE2_ERROR_RECURSIONLIMIT; +if (mb->match_call_count++ >= mb->match_limit) return PCRE2_ERROR_MATCHLIMIT; +if (rlevel++ > mb->match_limit_depth) return PCRE2_ERROR_DEPTHLIMIT; offsetcount &= (uint32_t)(-2); /* Round down */ wscount -= 2; @@ -418,21 +414,15 @@ active_states = (stateblock *)(workspace + 2); next_new_state = new_states = active_states + wscount; new_count = 0; -first_op = this_start_code + 1 + LINK_SIZE + - ((*this_start_code == OP_CBRA || *this_start_code == OP_SCBRA || - *this_start_code == OP_CBRAPOS || *this_start_code == OP_SCBRAPOS) - ? IMM2_SIZE:0); - /* The first thing in any (sub) pattern is a bracket of some sort. Push all the alternative states onto the list, and find out where the end is. This makes is possible to use this function recursively, when we want to stop at a matching internal ket rather than at the end. -If the first opcode in the first alternative is OP_REVERSE, we are dealing with -a backward assertion. In that case, we have to find out the maximum amount to -move back, and set up each alternative appropriately. */ +If we are dealing with a backward assertion we have to find out the maximum +amount to move back, and set up each alternative appropriately. */ -if (*first_op == OP_REVERSE) +if (*this_start_code == OP_ASSERTBACK || *this_start_code == OP_ASSERTBACK_NOT) { size_t max_back = 0; size_t gone_back; @@ -477,15 +467,17 @@ if (*first_op == OP_REVERSE) if (current_subject < mb->start_used_ptr) mb->start_used_ptr = current_subject; - /* Now we can process the individual branches. */ + /* Now we can process the individual branches. There will be an OP_REVERSE at + the start of each branch, except when the length of the branch is zero. */ end_code = this_start_code; do { - size_t back = (size_t)GET(end_code, 2+LINK_SIZE); + uint32_t revlen = (end_code[1+LINK_SIZE] == OP_REVERSE)? 1 + LINK_SIZE : 0; + size_t back = (revlen == 0)? 0 : (size_t)GET(end_code, 2+LINK_SIZE); if (back <= gone_back) { - int bstate = (int)(end_code - start_code + 2 + 2*LINK_SIZE); + int bstate = (int)(end_code - start_code + 1 + LINK_SIZE + revlen); ADD_NEW_DATA(-bstate, 0, (int)(gone_back - back)); } end_code += GET(end_code, 1); @@ -698,7 +690,7 @@ for (;;) case OP_TABLE_LENGTH + ((sizeof(coptable) == OP_TABLE_LENGTH) && (sizeof(poptable) == OP_TABLE_LENGTH)): - break; + return 0; /* ========================================================================== */ /* Reached a closing bracket. If not at the end of the pattern, carry @@ -1387,8 +1379,46 @@ for (;;) if (!utf) d = *nptr; else { GETCHARLEN(d, nptr, dlen); } rgb = UCD_GRAPHBREAK(d); if ((PRIV(ucp_gbtable)[lgb] & (1u << rgb)) == 0) break; + + /* Not breaking between Regional Indicators is allowed only if + there are an even number of preceding RIs. */ + + if (lgb == ucp_gbRegionalIndicator && + rgb == ucp_gbRegionalIndicator) + { + int ricount = 0; + PCRE2_SPTR bptr = nptr - 1; +#ifdef SUPPORT_UNICODE + if (utf) BACKCHAR(bptr); +#endif + /* bptr is pointing to the left-hand character */ + + while (bptr > mb->start_subject) + { + bptr--; +#ifdef SUPPORT_UNICODE + if (utf) + { + BACKCHAR(bptr); + GETCHAR(d, bptr); + } + else +#endif + d = *bptr; + if (UCD_GRAPHBREAK(d) != ucp_gbRegionalIndicator) break; + ricount++; + } + if ((ricount & 1) != 0) break; /* Grapheme break required */ + } + + /* If Extend follows E_Base[_GAZ] do not update lgb; this allows + any number of Extend before a following E_Modifier. */ + + if (rgb != ucp_gbExtend || + (lgb != ucp_gbE_Base && lgb != ucp_gbE_Base_GAZ)) + lgb = rgb; + ncount++; - lgb = rgb; nptr += dlen; } count++; @@ -1649,8 +1679,46 @@ for (;;) if (!utf) d = *nptr; else { GETCHARLEN(d, nptr, dlen); } rgb = UCD_GRAPHBREAK(d); if ((PRIV(ucp_gbtable)[lgb] & (1u << rgb)) == 0) break; + + /* Not breaking between Regional Indicators is allowed only if + there are an even number of preceding RIs. */ + + if (lgb == ucp_gbRegionalIndicator && + rgb == ucp_gbRegionalIndicator) + { + int ricount = 0; + PCRE2_SPTR bptr = nptr - 1; +#ifdef SUPPORT_UNICODE + if (utf) BACKCHAR(bptr); +#endif + /* bptr is pointing to the left-hand character */ + + while (bptr > mb->start_subject) + { + bptr--; +#ifdef SUPPORT_UNICODE + if (utf) + { + BACKCHAR(bptr); + GETCHAR(d, bptr); + } + else +#endif + d = *bptr; + if (UCD_GRAPHBREAK(d) != ucp_gbRegionalIndicator) break; + ricount++; + } + if ((ricount & 1) != 0) break; /* Grapheme break required */ + } + + /* If Extend follows E_Base[_GAZ] do not update lgb; this allows + any number of Extend before a following E_Modifier. */ + + if (rgb != ucp_gbExtend || + (lgb != ucp_gbE_Base && lgb != ucp_gbE_Base_GAZ)) + lgb = rgb; + ncount++; - lgb = rgb; nptr += dlen; } ADD_NEW_DATA(-(state_offset + count), 0, ncount); @@ -1920,8 +1988,46 @@ for (;;) if (!utf) d = *nptr; else { GETCHARLEN(d, nptr, dlen); } rgb = UCD_GRAPHBREAK(d); if ((PRIV(ucp_gbtable)[lgb] & (1u << rgb)) == 0) break; + + /* Not breaking between Regional Indicators is allowed only if + there are an even number of preceding RIs. */ + + if (lgb == ucp_gbRegionalIndicator && + rgb == ucp_gbRegionalIndicator) + { + int ricount = 0; + PCRE2_SPTR bptr = nptr - 1; +#ifdef SUPPORT_UNICODE + if (utf) BACKCHAR(bptr); +#endif + /* bptr is pointing to the left-hand character */ + + while (bptr > mb->start_subject) + { + bptr--; +#ifdef SUPPORT_UNICODE + if (utf) + { + BACKCHAR(bptr); + GETCHAR(d, bptr); + } + else +#endif + d = *bptr; + if (UCD_GRAPHBREAK(d) != ucp_gbRegionalIndicator) break; + ricount++; + } + if ((ricount & 1) != 0) break; /* Grapheme break required */ + } + + /* If Extend follows E_Base[_GAZ] do not update lgb; this allows + any number of Extend before a following E_Modifier. */ + + if (rgb != ucp_gbExtend || + (lgb != ucp_gbE_Base && lgb != ucp_gbE_Base_GAZ)) + lgb = rgb; + ncount++; - lgb = rgb; nptr += dlen; } if (nptr >= end_subject && (mb->moptions & PCRE2_PARTIAL_HARD) != 0) @@ -2110,8 +2216,46 @@ for (;;) if (!utf) d = *nptr; else { GETCHARLEN(d, nptr, dlen); } rgb = UCD_GRAPHBREAK(d); if ((PRIV(ucp_gbtable)[lgb] & (1u << rgb)) == 0) break; + + /* Not breaking between Regional Indicators is allowed only if + there are an even number of preceding RIs. */ + + if (lgb == ucp_gbRegionalIndicator && + rgb == ucp_gbRegionalIndicator) + { + int ricount = 0; + PCRE2_SPTR bptr = nptr - 1; +#ifdef SUPPORT_UNICODE + if (utf) BACKCHAR(bptr); +#endif + /* bptr is pointing to the left-hand character */ + + while (bptr > mb->start_subject) + { + bptr--; +#ifdef SUPPORT_UNICODE + if (utf) + { + BACKCHAR(bptr); + GETCHAR(d, bptr); + } + else +#endif + d = *bptr; + if (UCD_GRAPHBREAK(d) != ucp_gbRegionalIndicator) break; + ricount++; + } + if ((ricount & 1) != 0) break; /* Grapheme break required */ + } + + /* If Extend follows E_Base[_GAZ] do not update lgb; this allows + any number of Extend before a following E_Modifier. */ + + if (rgb != ucp_gbExtend || + (lgb != ucp_gbE_Base && lgb != ucp_gbE_Base_GAZ)) + lgb = rgb; + ncount++; - lgb = rgb; nptr += dlen; } if (nptr >= end_subject && (mb->moptions & PCRE2_PARTIAL_HARD) != 0) @@ -2137,6 +2281,7 @@ for (;;) case 0x2029: #endif /* Not EBCDIC */ if (mb->bsr_convention == PCRE2_BSR_ANYCRLF) break; + /* Fall through */ case CHAR_LF: ADD_NEW(state_offset + 1, 0); @@ -2540,11 +2685,13 @@ for (;;) if (isinclass) { int max = (int)GET2(ecode, 1 + IMM2_SIZE); - if (*ecode == OP_CRPOSRANGE) + + if (*ecode == OP_CRPOSRANGE && count >= (int)GET2(ecode, 1)) { active_count--; /* Remove non-match possibility */ next_active_state--; } + if (++count >= max && max != 0) /* Max 0 => no limit */ { ADD_NEW(next_state_offset + 1 + 2 * IMM2_SIZE, 0); } else @@ -2890,7 +3037,6 @@ for (;;) /*-----------------------------------------------------------------*/ case OP_ONCE: - case OP_ONCE_NC: { PCRE2_SIZE local_offsets[2]; int local_workspace[1000]; @@ -3070,7 +3216,7 @@ for (;;) ) ) match_count = PCRE2_ERROR_PARTIAL; - break; /* In effect, "return", but see the comment below */ + break; /* Exit from loop along the subject string */ } /* One or more states are active for the next character. */ @@ -3078,11 +3224,13 @@ for (;;) ptr += clen; /* Advance to next subject character */ } /* Loop to move along the subject string */ -/* Control gets here from "break" a few lines above. We do it this way because -if we use "return" above, we have compiler trouble. Some compilers warn if -there's nothing here because they think the function doesn't return a value. On -the other hand, if we put a dummy statement here, some more clever compilers -complain that it can't be reached. Sigh. */ +/* Control gets here from "break" a few lines above. If we have a match and +PCRE2_ENDANCHORED is set, the match fails. */ + +if (match_count >= 0 && + ((mb->moptions | mb->poptions) & PCRE2_ENDANCHORED) != 0 && + ptr < end_subject) + match_count = PCRE2_ERROR_NOMATCH; return match_count; } @@ -3155,6 +3303,13 @@ if (re == NULL || subject == NULL || workspace == NULL || match_data == NULL) if (wscount < 20) return PCRE2_ERROR_DFA_WSSIZE; if (start_offset > length) return PCRE2_ERROR_BADOFFSET; +/* Partial matching and PCRE2_ENDANCHORED are currently not allowed at the same +time. */ + +if ((options & (PCRE2_PARTIAL_HARD|PCRE2_PARTIAL_SOFT)) != 0 && + ((re->overall_options | options) & PCRE2_ENDANCHORED) != 0) + return PCRE2_ERROR_BADOPTION; + /* Check that the first field in the block is the magic number. If it is not, return with PCRE2_ERROR_BADMAGIC. */ @@ -3217,7 +3372,8 @@ if (mcontext == NULL) { mb->callout = NULL; mb->memctl = re->memctl; - mb->match_limit_recursion = PRIV(default_match_context).recursion_limit; + mb->match_limit = PRIV(default_match_context).match_limit; + mb->match_limit_depth = PRIV(default_match_context).depth_limit; } else { @@ -3230,10 +3386,15 @@ else mb->callout = mcontext->callout; mb->callout_data = mcontext->callout_data; mb->memctl = mcontext->memctl; - mb->match_limit_recursion = mcontext->recursion_limit; + mb->match_limit = mcontext->match_limit; + mb->match_limit_depth = mcontext->depth_limit; } -if (mb->match_limit_recursion > re->limit_recursion) - mb->match_limit_recursion = re->limit_recursion; + +if (mb->match_limit > re->limit_match) + mb->match_limit = re->limit_match; + +if (mb->match_limit_depth > re->limit_depth) + mb->match_limit_depth = re->limit_depth; mb->start_code = (PCRE2_UCHAR *)((uint8_t *)re + sizeof(pcre2_real_code)) + re->name_count * re->name_entry_size; @@ -3243,6 +3404,7 @@ mb->end_subject = end_subject; mb->start_offset = start_offset; mb->moptions = options; mb->poptions = re->overall_options; +mb->match_call_count = 0; /* Process the \R and newline settings. */ @@ -3260,6 +3422,11 @@ switch(re->newline_convention) mb->nl[0] = CHAR_NL; break; + case PCRE2_NEWLINE_NUL: + mb->nllen = 1; + mb->nl[0] = CHAR_NUL; + break; + case PCRE2_NEWLINE_CRLF: mb->nllen = 2; mb->nl[0] = CHAR_CR; @@ -3326,34 +3493,27 @@ if (utf && (options & PCRE2_NO_UTF_CHECK) == 0) } #endif /* SUPPORT_UNICODE */ -/* Set up the first code unit to match, if available. The first_codeunit value -is never set for an anchored regular expression, but the anchoring may be -forced at run time, so we have to test for anchoring. The first code unit may -be unset for an unanchored pattern, of course. If there's no first code unit -there may be a bitmap of possible first characters. */ +/* Set up the first code unit to match, if available. If there's no first code +unit there may be a bitmap of possible first characters. */ -if (!anchored) +if ((re->flags & PCRE2_FIRSTSET) != 0) { - if ((re->flags & PCRE2_FIRSTSET) != 0) + has_first_cu = TRUE; + first_cu = first_cu2 = (PCRE2_UCHAR)(re->first_codeunit); + if ((re->flags & PCRE2_FIRSTCASELESS) != 0) { - has_first_cu = TRUE; - first_cu = first_cu2 = (PCRE2_UCHAR)(re->first_codeunit); - if ((re->flags & PCRE2_FIRSTCASELESS) != 0) - { - first_cu2 = TABLE_GET(first_cu, mb->tables + fcc_offset, first_cu); + first_cu2 = TABLE_GET(first_cu, mb->tables + fcc_offset, first_cu); #if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 8 - if (utf && first_cu > 127) - first_cu2 = (PCRE2_UCHAR)UCD_OTHERCASE(first_cu); + if (utf && first_cu > 127) + first_cu2 = (PCRE2_UCHAR)UCD_OTHERCASE(first_cu); #endif - } } - else - if (!startline && (re->flags & PCRE2_FIRSTMAPSET) != 0) - start_bits = re->start_bitmap; } +else + if (!startline && (re->flags & PCRE2_FIRSTMAPSET) != 0) + start_bits = re->start_bitmap; -/* For anchored or unanchored matches, there may be a "last known required -character" set. */ +/* There may be a "last known required code unit" set. */ if ((re->flags & PCRE2_LASTSET) != 0) { @@ -3399,8 +3559,8 @@ for (;;) /* If firstline is TRUE, the start of the match is constrained to the first line of a multiline string. That is, the match must be before or at the first newline. Implement this by temporarily adjusting end_subject so that - we stop the optimization scans at a newline. If the match fails at the - newline, later code breaks this loop. */ + we stop the optimization scans for a first code unit at a newline. If the + match fails at the newline, later code breaks this loop. */ if (firstline) { @@ -3420,69 +3580,137 @@ for (;;) end_subject = t; } - /* Advance to a unique first code unit if there is one. */ + /* Anchored: check the first code unit if one is recorded. This may seem + pointless but it can help in detecting a no match case without scanning for + the required code unit. */ - if (has_first_cu) + if (anchored) { - PCRE2_UCHAR smc; - if (first_cu != first_cu2) - while (start_match < end_subject && - (smc = UCHAR21TEST(start_match)) != first_cu && smc != first_cu2) - start_match++; - else - while (start_match < end_subject && UCHAR21TEST(start_match) != first_cu) - start_match++; + if (has_first_cu || start_bits != NULL) + { + BOOL ok = start_match < end_subject; + if (ok) + { + PCRE2_UCHAR c = UCHAR21TEST(start_match); + ok = has_first_cu && (c == first_cu || c == first_cu2); + if (!ok && start_bits != NULL) + { +#if PCRE2_CODE_UNIT_WIDTH != 8 + if (c > 255) c = 255; +#endif + ok = (start_bits[c/8] & (1 << (c&7))) != 0; + } + } + if (!ok) break; + } } - /* Or to just after a linebreak for a multiline match */ + /* Not anchored. Advance to a unique first code unit if there is one. In + 8-bit mode, the use of memchr() gives a big speed up, even though we have + to call it twice in caseless mode, in order to find the earliest occurrence + of the character in either of its cases. */ - else if (startline) + else { - if (start_match > mb->start_subject + start_offset) + if (has_first_cu) { -#ifdef SUPPORT_UNICODE - if (utf) + if (first_cu != first_cu2) /* Caseless */ { - while (start_match < end_subject && !WAS_NEWLINE(start_match)) - { +#if PCRE2_CODE_UNIT_WIDTH != 8 + PCRE2_UCHAR smc; + while (start_match < end_subject && + (smc = UCHAR21TEST(start_match)) != first_cu && + smc != first_cu2) start_match++; - ACROSSCHAR(start_match < end_subject, *start_match, - start_match++); - } +#else /* 8-bit code units */ + PCRE2_SPTR pp1 = + memchr(start_match, first_cu, end_subject-start_match); + PCRE2_SPTR pp2 = + memchr(start_match, first_cu2, end_subject-start_match); + if (pp1 == NULL) + start_match = (pp2 == NULL)? end_subject : pp2; + else + start_match = (pp2 == NULL || pp1 < pp2)? pp1 : pp2; +#endif } + + /* The caseful case */ + else + { +#if PCRE2_CODE_UNIT_WIDTH != 8 + while (start_match < end_subject && UCHAR21TEST(start_match) != + first_cu) + start_match++; +#else + start_match = memchr(start_match, first_cu, end_subject - start_match); + if (start_match == NULL) start_match = end_subject; #endif - while (start_match < end_subject && !WAS_NEWLINE(start_match)) - start_match++; + } - /* If we have just passed a CR and the newline option is ANY or - ANYCRLF, and we are now at a LF, advance the match position by one more - code unit. */ + /* If we can't find the required code unit, break the bumpalong loop, + to force a match failure, except when doing partial matching, when we + let the next cycle run at the end of the subject. To see why, consider + the pattern /(?<=abc)def/, which partially matches "abc", even though + the string does not contain the starting character "d". */ - if (start_match[-1] == CHAR_CR && - (mb->nltype == NLTYPE_ANY || mb->nltype == NLTYPE_ANYCRLF) && - start_match < end_subject && - UCHAR21TEST(start_match) == CHAR_NL) - start_match++; + if ((mb->moptions & (PCRE2_PARTIAL_HARD|PCRE2_PARTIAL_SOFT)) == 0 && + start_match >= end_subject) + break; } - } - /* Or to a non-unique first code unit if any have been identified. The - bitmap contains only 256 bits. When code units are 16 or 32 bits wide, all - code units greater than 254 set the 255 bit. */ + /* If there's no first code unit, advance to just after a linebreak for a + multiline match if required. */ - else if (start_bits != NULL) - { - while (start_match < end_subject) + else if (startline) + { + if (start_match > mb->start_subject + start_offset) + { +#ifdef SUPPORT_UNICODE + if (utf) + { + while (start_match < end_subject && !WAS_NEWLINE(start_match)) + { + start_match++; + ACROSSCHAR(start_match < end_subject, *start_match, + start_match++); + } + } + else +#endif + while (start_match < end_subject && !WAS_NEWLINE(start_match)) + start_match++; + + /* If we have just passed a CR and the newline option is ANY or + ANYCRLF, and we are now at a LF, advance the match position by one + more code unit. */ + + if (start_match[-1] == CHAR_CR && + (mb->nltype == NLTYPE_ANY || mb->nltype == NLTYPE_ANYCRLF) && + start_match < end_subject && + UCHAR21TEST(start_match) == CHAR_NL) + start_match++; + } + } + + /* If there's no first code unit or a requirement for a multiline line + start, advance to a non-unique first code unit if any have been + identified. The bitmap contains only 256 bits. When code units are 16 or + 32 bits wide, all code units greater than 254 set the 255 bit. */ + + else if (start_bits != NULL) { - uint32_t c = UCHAR21TEST(start_match); + while (start_match < end_subject) + { + uint32_t c = UCHAR21TEST(start_match); #if PCRE2_CODE_UNIT_WIDTH != 8 - if (c > 255) c = 255; + if (c > 255) c = 255; #endif - if ((start_bits[c/8] & (1 << (c&7))) != 0) break; - start_match++; + if ((start_bits[c/8] & (1 << (c&7))) != 0) break; + start_match++; + } } - } + } /* End of first code unit handling */ /* Restore fudged end_subject */ diff --git a/ProcessHacker/pcre/pcre2_error.c b/ProcessHacker/pcre/pcre2_error.c index 9ef2b9cd0041..d98cae99636a 100644 --- a/ProcessHacker/pcre/pcre2_error.c +++ b/ProcessHacker/pcre/pcre2_error.c @@ -7,7 +7,7 @@ and semantics are as close as possible to those of the Perl 5 language. Written by Philip Hazel Original API code Copyright (c) 1997-2012 University of Cambridge - New API code Copyright (c) 2016 University of Cambridge + New API code Copyright (c) 2016-2017 University of Cambridge ----------------------------------------------------------------------------- Redistribution and use in source and binary forms, with or without @@ -38,7 +38,6 @@ POSSIBILITY OF SUCH DAMAGE. ----------------------------------------------------------------------------- */ -#define HAVE_CONFIG_H #ifdef HAVE_CONFIG_H #include "config.h" @@ -177,6 +176,8 @@ static const unsigned char compile_error_texts[] = "internal error: unknown code in parsed pattern\0" /* 90 */ "internal error: bad code value in parsed_skip()\0" + "PCRE2_EXTRA_ALLOW_SURROGATE_ESCAPES is not allowed in UTF-16 mode\0" + "invalid option bits with PCRE2_LITERAL\0" ; /* Match-time and UTF error texts are in the same format. */ @@ -245,7 +246,7 @@ static const unsigned char match_error_texts[] = "non-unique substring name\0" "NULL argument passed\0" "nested recursion at the same subject position\0" - "recursion limit exceeded\0" + "matching depth limit exceeded\0" "requested value is not available\0" /* 55 */ "requested value is not set\0" @@ -257,6 +258,8 @@ static const unsigned char match_error_texts[] = "match with end before start is not supported\0" "too many replacements (more than INT_MAX)\0" "bad serialized data\0" + "heap limit exceeded\0" + "invalid syntax\0" ; @@ -272,7 +275,7 @@ distinct. Arguments: enumber error number buffer where to put the message (zero terminated) - size size of the buffer + size size of the buffer in code units Returns: length of message if all is well negative on error @@ -305,8 +308,8 @@ else /* Invalid error number */ for (; n > 0; n--) { - while (*message++ != CHAR_NULL) {}; - if (*message == CHAR_NULL) return PCRE2_ERROR_BADDATA; + while (*message++ != CHAR_NUL) {}; + if (*message == CHAR_NUL) return PCRE2_ERROR_BADDATA; } for (i = 0; *message != 0; i++) diff --git a/ProcessHacker/pcre/pcre2_find_bracket.c b/ProcessHacker/pcre/pcre2_find_bracket.c index 1564cf96f5ff..357385a11ccc 100644 --- a/ProcessHacker/pcre/pcre2_find_bracket.c +++ b/ProcessHacker/pcre/pcre2_find_bracket.c @@ -46,8 +46,6 @@ from pcre2_compile.c and also from pcre2_study.c when finding the minimum matching length. */ -#define HAVE_CONFIG_H - #ifdef HAVE_CONFIG_H #include "config.h" #endif diff --git a/ProcessHacker/pcre/pcre2_internal.h b/ProcessHacker/pcre/pcre2_internal.h index 6a8774ce8c1f..9ccce25d4712 100644 --- a/ProcessHacker/pcre/pcre2_internal.h +++ b/ProcessHacker/pcre/pcre2_internal.h @@ -7,7 +7,7 @@ and semantics are as close as possible to those of the Perl 5 language. Written by Philip Hazel Original API code Copyright (c) 1997-2012 University of Cambridge - New API code Copyright (c) 2016 University of Cambridge + New API code Copyright (c) 2016-2017 University of Cambridge ----------------------------------------------------------------------------- Redistribution and use in source and binary forms, with or without @@ -240,6 +240,16 @@ not rely on this. */ #define COMPILE_ERROR_BASE 100 +/* The initial frames vector for remembering backtracking points in +pcre2_match() is allocated on the system stack, of this size (bytes). The size +must be a multiple of sizeof(PCRE2_SPTR) in all environments, so making it a +multiple of 8 is best. Typical frame sizes are a few hundred bytes (it depends +on the number of capturing parentheses) so 20K handles quite a few frames. A +larger vector on the heap is obtained for patterns that need more frames. The +maximum size of this can be limited. */ + +#define START_FRAMES_SIZE 20480 + /* Define the default BSR convention. */ #ifdef BSR_ANYCRLF @@ -547,9 +557,14 @@ enum { PCRE2_MATCHEDBY_INTERPRETER, /* pcre2_match() */ #define MAGIC_NUMBER 0x50435245UL /* 'PCRE' */ /* The maximum remaining length of subject we are prepared to search for a -req_unit match. */ +req_unit match. In 8-bit mode, memchr() is used and is much faster than the +search loop that has to be used in 16-bit and 32-bit modes. */ +#if PCRE2_CODE_UNIT_WIDTH == 8 +#define REQ_CU_MAX 2000 +#else #define REQ_CU_MAX 1000 +#endif /* Offsets for the bitmap tables in the cbits set of tables. Each table contains a set of bits for a class map. Some classes are built by combining @@ -668,7 +683,7 @@ a positive value. */ /* The remaining definitions work in both environments. */ -#define CHAR_NULL '\0' +#define CHAR_NUL '\0' #define CHAR_HT '\t' #define CHAR_VT '\v' #define CHAR_FF '\f' @@ -909,6 +924,7 @@ a positive value. */ #define STRING_CRLF_RIGHTPAR "CRLF)" #define STRING_ANY_RIGHTPAR "ANY)" #define STRING_ANYCRLF_RIGHTPAR "ANYCRLF)" +#define STRING_NUL_RIGHTPAR "NUL)" #define STRING_BSR_ANYCRLF_RIGHTPAR "BSR_ANYCRLF)" #define STRING_BSR_UNICODE_RIGHTPAR "BSR_UNICODE)" #define STRING_UTF8_RIGHTPAR "UTF8)" @@ -922,7 +938,9 @@ a positive value. */ #define STRING_NO_START_OPT_RIGHTPAR "NO_START_OPT)" #define STRING_NOTEMPTY_RIGHTPAR "NOTEMPTY)" #define STRING_NOTEMPTY_ATSTART_RIGHTPAR "NOTEMPTY_ATSTART)" +#define STRING_LIMIT_HEAP_EQ "LIMIT_HEAP=" #define STRING_LIMIT_MATCH_EQ "LIMIT_MATCH=" +#define STRING_LIMIT_DEPTH_EQ "LIMIT_DEPTH=" #define STRING_LIMIT_RECURSION_EQ "LIMIT_RECURSION=" #define STRING_MARK "MARK" @@ -944,7 +962,7 @@ only. */ #define CHAR_ESC '\033' #define CHAR_DEL '\177' -#define CHAR_NULL '\0' +#define CHAR_NUL '\0' #define CHAR_SPACE '\040' #define CHAR_EXCLAMATION_MARK '\041' #define CHAR_QUOTATION_MARK '\042' @@ -1182,6 +1200,7 @@ only. */ #define STRING_CRLF_RIGHTPAR STR_C STR_R STR_L STR_F STR_RIGHT_PARENTHESIS #define STRING_ANY_RIGHTPAR STR_A STR_N STR_Y STR_RIGHT_PARENTHESIS #define STRING_ANYCRLF_RIGHTPAR STR_A STR_N STR_Y STR_C STR_R STR_L STR_F STR_RIGHT_PARENTHESIS +#define STRING_NUL_RIGHTPAR STR_N STR_U STR_L STR_RIGHT_PARENTHESIS #define STRING_BSR_ANYCRLF_RIGHTPAR STR_B STR_S STR_R STR_UNDERSCORE STR_A STR_N STR_Y STR_C STR_R STR_L STR_F STR_RIGHT_PARENTHESIS #define STRING_BSR_UNICODE_RIGHTPAR STR_B STR_S STR_R STR_UNDERSCORE STR_U STR_N STR_I STR_C STR_O STR_D STR_E STR_RIGHT_PARENTHESIS #define STRING_UTF8_RIGHTPAR STR_U STR_T STR_F STR_8 STR_RIGHT_PARENTHESIS @@ -1195,7 +1214,9 @@ only. */ #define STRING_NO_START_OPT_RIGHTPAR STR_N STR_O STR_UNDERSCORE STR_S STR_T STR_A STR_R STR_T STR_UNDERSCORE STR_O STR_P STR_T STR_RIGHT_PARENTHESIS #define STRING_NOTEMPTY_RIGHTPAR STR_N STR_O STR_T STR_E STR_M STR_P STR_T STR_Y STR_RIGHT_PARENTHESIS #define STRING_NOTEMPTY_ATSTART_RIGHTPAR STR_N STR_O STR_T STR_E STR_M STR_P STR_T STR_Y STR_UNDERSCORE STR_A STR_T STR_S STR_T STR_A STR_R STR_T STR_RIGHT_PARENTHESIS +#define STRING_LIMIT_HEAP_EQ STR_L STR_I STR_M STR_I STR_T STR_UNDERSCORE STR_H STR_E STR_A STR_P STR_EQUALS_SIGN #define STRING_LIMIT_MATCH_EQ STR_L STR_I STR_M STR_I STR_T STR_UNDERSCORE STR_M STR_A STR_T STR_C STR_H STR_EQUALS_SIGN +#define STRING_LIMIT_DEPTH_EQ STR_L STR_I STR_M STR_I STR_T STR_UNDERSCORE STR_D STR_E STR_P STR_T STR_H STR_EQUALS_SIGN #define STRING_LIMIT_RECURSION_EQ STR_L STR_I STR_M STR_I STR_T STR_UNDERSCORE STR_R STR_E STR_C STR_U STR_R STR_S STR_I STR_O STR_N STR_EQUALS_SIGN #define STRING_MARK STR_M STR_A STR_R STR_K @@ -1510,68 +1531,67 @@ enum { OP_ASSERTBACK, /* 128 Positive lookbehind */ OP_ASSERTBACK_NOT, /* 129 Negative lookbehind */ - /* ONCE, ONCE_NC, BRA, BRAPOS, CBRA, CBRAPOS, and COND must come immediately - after the assertions, with ONCE first, as there's a test for >= ONCE for a - subpattern that isn't an assertion. The POS versions must immediately follow - the non-POS versions in each case. */ + /* ONCE, BRA, BRAPOS, CBRA, CBRAPOS, and COND must come immediately after the + assertions, with ONCE first, as there's a test for >= ONCE for a subpattern + that isn't an assertion. The POS versions must immediately follow the non-POS + versions in each case. */ OP_ONCE, /* 130 Atomic group, contains captures */ - OP_ONCE_NC, /* 131 Atomic group containing no captures */ - OP_BRA, /* 132 Start of non-capturing bracket */ - OP_BRAPOS, /* 133 Ditto, with unlimited, possessive repeat */ - OP_CBRA, /* 134 Start of capturing bracket */ - OP_CBRAPOS, /* 135 Ditto, with unlimited, possessive repeat */ - OP_COND, /* 136 Conditional group */ + OP_BRA, /* 131 Start of non-capturing bracket */ + OP_BRAPOS, /* 132 Ditto, with unlimited, possessive repeat */ + OP_CBRA, /* 133 Start of capturing bracket */ + OP_CBRAPOS, /* 134 Ditto, with unlimited, possessive repeat */ + OP_COND, /* 135 Conditional group */ /* These five must follow the previous five, in the same order. There's a check for >= SBRA to distinguish the two sets. */ - OP_SBRA, /* 137 Start of non-capturing bracket, check empty */ - OP_SBRAPOS, /* 138 Ditto, with unlimited, possessive repeat */ - OP_SCBRA, /* 139 Start of capturing bracket, check empty */ - OP_SCBRAPOS, /* 140 Ditto, with unlimited, possessive repeat */ - OP_SCOND, /* 141 Conditional group, check empty */ + OP_SBRA, /* 136 Start of non-capturing bracket, check empty */ + OP_SBRAPOS, /* 137 Ditto, with unlimited, possessive repeat */ + OP_SCBRA, /* 138 Start of capturing bracket, check empty */ + OP_SCBRAPOS, /* 139 Ditto, with unlimited, possessive repeat */ + OP_SCOND, /* 140 Conditional group, check empty */ /* The next two pairs must (respectively) be kept together. */ - OP_CREF, /* 142 Used to hold a capture number as condition */ - OP_DNCREF, /* 143 Used to point to duplicate names as a condition */ - OP_RREF, /* 144 Used to hold a recursion number as condition */ - OP_DNRREF, /* 145 Used to point to duplicate names as a condition */ - OP_FALSE, /* 146 Always false (used by DEFINE and VERSION) */ - OP_TRUE, /* 147 Always true (used by VERSION) */ + OP_CREF, /* 141 Used to hold a capture number as condition */ + OP_DNCREF, /* 142 Used to point to duplicate names as a condition */ + OP_RREF, /* 143 Used to hold a recursion number as condition */ + OP_DNRREF, /* 144 Used to point to duplicate names as a condition */ + OP_FALSE, /* 145 Always false (used by DEFINE and VERSION) */ + OP_TRUE, /* 146 Always true (used by VERSION) */ - OP_BRAZERO, /* 148 These two must remain together and in this */ - OP_BRAMINZERO, /* 149 order. */ - OP_BRAPOSZERO, /* 150 */ + OP_BRAZERO, /* 147 These two must remain together and in this */ + OP_BRAMINZERO, /* 148 order. */ + OP_BRAPOSZERO, /* 149 */ /* These are backtracking control verbs */ - OP_MARK, /* 151 always has an argument */ - OP_PRUNE, /* 152 */ - OP_PRUNE_ARG, /* 153 same, but with argument */ - OP_SKIP, /* 154 */ - OP_SKIP_ARG, /* 155 same, but with argument */ - OP_THEN, /* 156 */ - OP_THEN_ARG, /* 157 same, but with argument */ - OP_COMMIT, /* 158 */ + OP_MARK, /* 150 always has an argument */ + OP_PRUNE, /* 151 */ + OP_PRUNE_ARG, /* 152 same, but with argument */ + OP_SKIP, /* 153 */ + OP_SKIP_ARG, /* 154 same, but with argument */ + OP_THEN, /* 155 */ + OP_THEN_ARG, /* 156 same, but with argument */ + OP_COMMIT, /* 157 */ /* These are forced failure and success verbs */ - OP_FAIL, /* 159 */ - OP_ACCEPT, /* 160 */ - OP_ASSERT_ACCEPT, /* 161 Used inside assertions */ - OP_CLOSE, /* 162 Used before OP_ACCEPT to close open captures */ + OP_FAIL, /* 158 */ + OP_ACCEPT, /* 159 */ + OP_ASSERT_ACCEPT, /* 160 Used inside assertions */ + OP_CLOSE, /* 161 Used before OP_ACCEPT to close open captures */ /* This is used to skip a subpattern with a {0} quantifier */ - OP_SKIPZERO, /* 163 */ + OP_SKIPZERO, /* 162 */ /* This is used to identify a DEFINE group during compilation so that it can be checked for having only one branch. It is changed to OP_FALSE before compilation finishes. */ - OP_DEFINE, /* 164 */ + OP_DEFINE, /* 163 */ /* This is not an opcode, but is used to check that tables indexed by opcode are the correct length, in order to catch updating errors - there have been @@ -1618,7 +1638,7 @@ some cases doesn't actually use these names at all). */ "Recurse", "Callout", "CalloutStr", \ "Alt", "Ket", "KetRmax", "KetRmin", "KetRpos", \ "Reverse", "Assert", "Assert not", "AssertB", "AssertB not", \ - "Once", "Once_NC", \ + "Once", \ "Bra", "BraPos", "CBra", "CBraPos", \ "Cond", \ "SBra", "SBraPos", "SCBra", "SCBraPos", \ @@ -1702,7 +1722,6 @@ in UTF-8 mode. The code that uses this table must know about such things. */ 1+LINK_SIZE, /* Assert behind */ \ 1+LINK_SIZE, /* Assert behind not */ \ 1+LINK_SIZE, /* ONCE */ \ - 1+LINK_SIZE, /* ONCE_NC */ \ 1+LINK_SIZE, /* BRA */ \ 1+LINK_SIZE, /* BRAPOS */ \ 1+LINK_SIZE+IMM2_SIZE, /* CBRA */ \ @@ -1774,10 +1793,17 @@ typedef struct { /* UCD access macros */ #define UCD_BLOCK_SIZE 128 -#define GET_UCD(ch) (PRIV(ucd_records) + \ +#define REAL_GET_UCD(ch) (PRIV(ucd_records) + \ PRIV(ucd_stage2)[PRIV(ucd_stage1)[(int)(ch) / UCD_BLOCK_SIZE] * \ UCD_BLOCK_SIZE + (int)(ch) % UCD_BLOCK_SIZE]) +#if PCRE2_CODE_UNIT_WIDTH == 32 +#define GET_UCD(ch) ((ch > MAX_UTF_CODE_POINT)? \ + PRIV(dummy_ucd_record) : REAL_GET_UCD(ch)) +#else +#define GET_UCD(ch) REAL_GET_UCD(ch) +#endif + #define UCD_CHARTYPE(ch) GET_UCD(ch)->chartype #define UCD_SCRIPT(ch) GET_UCD(ch)->script #define UCD_CATEGORY(ch) PRIV(ucp_gentype)[UCD_CHARTYPE(ch)] @@ -1832,8 +1858,12 @@ extern const uint8_t PRIV(utf8_table4)[]; #define _pcre2_callout_end_delims PCRE2_SUFFIX(_pcre2_callout_end_delims_) #define _pcre2_callout_start_delims PCRE2_SUFFIX(_pcre2_callout_start_delims_) #define _pcre2_default_compile_context PCRE2_SUFFIX(_pcre2_default_compile_context_) +#define _pcre2_default_convert_context PCRE2_SUFFIX(_pcre2_default_convert_context_) #define _pcre2_default_match_context PCRE2_SUFFIX(_pcre2_default_match_context_) #define _pcre2_default_tables PCRE2_SUFFIX(_pcre2_default_tables_) +#if PCRE2_CODE_UNIT_WIDTH == 32 +#define _pcre2_dummy_ucd_record PCRE2_SUFFIX(_pcre2_dummy_ucd_record_) +#endif #define _pcre2_hspace_list PCRE2_SUFFIX(_pcre2_hspace_list_) #define _pcre2_vspace_list PCRE2_SUFFIX(_pcre2_vspace_list_) #define _pcre2_ucd_caseless_sets PCRE2_SUFFIX(_pcre2_ucd_caseless_sets_) @@ -1852,12 +1882,16 @@ extern const uint8_t PRIV(OP_lengths)[]; extern const uint32_t PRIV(callout_end_delims)[]; extern const uint32_t PRIV(callout_start_delims)[]; extern const pcre2_compile_context PRIV(default_compile_context); +extern const pcre2_convert_context PRIV(default_convert_context); extern const pcre2_match_context PRIV(default_match_context); extern const uint8_t PRIV(default_tables)[]; extern const uint32_t PRIV(hspace_list)[]; extern const uint32_t PRIV(vspace_list)[]; extern const uint32_t PRIV(ucd_caseless_sets)[]; extern const ucd_record PRIV(ucd_records)[]; +#if PCRE2_CODE_UNIT_WIDTH == 32 +extern const ucd_record PRIV(dummy_ucd_record)[]; +#endif extern const uint8_t PRIV(ucd_stage1)[]; extern const uint16_t PRIV(ucd_stage2)[]; extern const uint32_t PRIV(ucp_gbtable)[]; diff --git a/ProcessHacker/pcre/pcre2_intmodedep.h b/ProcessHacker/pcre/pcre2_intmodedep.h index ebff7e30661c..387f65eb08a9 100644 --- a/ProcessHacker/pcre/pcre2_intmodedep.h +++ b/ProcessHacker/pcre/pcre2_intmodedep.h @@ -7,7 +7,7 @@ and semantics are as close as possible to those of the Perl 5 language. Written by Philip Hazel Original API code Copyright (c) 1997-2012 University of Cambridge - New API code Copyright (c) 2016 University of Cambridge + New API code Copyright (c) 2016-2017 University of Cambridge ----------------------------------------------------------------------------- Redistribution and use in source and binary forms, with or without @@ -54,6 +54,7 @@ just to undefine them all. */ #undef ACROSSCHAR #undef BACKCHAR #undef BYTES2CU +#undef CHMAX_255 #undef CU2BYTES #undef FORWARDCHAR #undef FORWARDCHARTEST @@ -201,20 +202,25 @@ arithmetic results in a signed value. Hence the cast. */ /* Other macros that are different for 8-bit mode. The MAX_255 macro checks whether its argument, which is assumed to be one code unit, is less than 256. -The maximum length of a MARK name must fit in one code unit; currently it is -set to 255 or 65535. The TABLE_GET macro is used to access elements of tables -containing exactly 256 items. When code points can be greater than 255, a check -is needed before accessing these tables. */ +The CHMAX_255 macro does not assume one code unit. The maximum length of a MARK +name must fit in one code unit; currently it is set to 255 or 65535. The +TABLE_GET macro is used to access elements of tables containing exactly 256 +items. When code points can be greater than 255, a check is needed before +accessing these tables. */ #if PCRE2_CODE_UNIT_WIDTH == 8 #define MAX_255(c) TRUE #define MAX_MARK ((1u << 8) - 1) #ifdef SUPPORT_UNICODE #define SUPPORT_WIDE_CHARS +#define CHMAX_255(c) ((c) <= 255u) +#else +#define CHMAX_255(c) TRUE #endif /* SUPPORT_UNICODE */ #define TABLE_GET(c, table, default) ((table)[c]) #else /* Code units are 16 or 32 bits */ +#define CHMAX_255(c) ((c) <= 255u) #define MAX_255(c) ((c) <= 255u) #define MAX_MARK ((1u << 16) - 1) #define SUPPORT_WIDE_CHARS @@ -566,15 +572,13 @@ typedef struct pcre2_real_compile_context { uint16_t bsr_convention; uint16_t newline_convention; uint32_t parens_nest_limit; + uint32_t extra_options; } pcre2_real_compile_context; /* The real match context structure. */ typedef struct pcre2_real_match_context { pcre2_memctl memctl; -#ifdef HEAP_MATCH_RECURSE - pcre2_memctl stack_memctl; -#endif #ifdef SUPPORT_JIT pcre2_jit_callback jit_callback; void *jit_callback_data; @@ -582,10 +586,19 @@ typedef struct pcre2_real_match_context { int (*callout)(pcre2_callout_block *, void *); void *callout_data; PCRE2_SIZE offset_limit; + uint32_t heap_limit; uint32_t match_limit; - uint32_t recursion_limit; + uint32_t depth_limit; } pcre2_real_match_context; +/* The real convert context structure. */ + +typedef struct pcre2_real_convert_context { + pcre2_memctl memctl; + uint32_t glob_separator; + uint32_t glob_escape; +} pcre2_real_convert_context; + /* The real compiled code structure. The type for the blocksize field is defined specially because it is required in pcre2_serialize_decode() when copying the size from possibly unaligned memory into a variable of the same @@ -611,8 +624,9 @@ typedef struct pcre2_real_code { uint32_t compile_options; /* Options passed to pcre2_compile() */ uint32_t overall_options; /* Options after processing the pattern */ uint32_t flags; /* Various state flags */ + uint32_t limit_heap; /* Limit set in the pattern */ uint32_t limit_match; /* Limit set in the pattern */ - uint32_t limit_recursion; /* Limit set in the pattern */ + uint32_t limit_depth; /* Limit set in the pattern */ uint32_t first_codeunit; /* Starting code unit */ uint32_t last_codeunit; /* This codeunit must be seen */ uint16_t bsr_convention; /* What \R matches */ @@ -625,7 +639,11 @@ typedef struct pcre2_real_code { uint16_t name_count; /* Number of name entries in the table */ } pcre2_real_code; -/* The real match data structure. */ +/* The real match data structure. Define ovector large so that array bound +checkers don't grumble. Memory for this structure is obtained by calling +pcre2_match_data_create(), which sets the size as the offset of ovector plus +pairs of elements for each capturing group. (See also the heapframe structure +below.) */ typedef struct pcre2_real_match_data { pcre2_memctl memctl; @@ -638,7 +656,7 @@ typedef struct pcre2_real_match_data { uint16_t matchedby; /* Type of match (normal, JIT, DFA) */ uint16_t oveccount; /* Number of pairs */ int rc; /* The return code from the match */ - PCRE2_SIZE ovector[1]; /* The first field */ + PCRE2_SIZE ovector[10000];/* The first field */ } pcre2_real_match_data; @@ -740,27 +758,8 @@ typedef struct pcre2_real_jit_stack { void* stack; } pcre2_real_jit_stack; -/* Structure for keeping a chain of heap blocks used for saving ovectors -during pattern recursion when the ovector is larger than can be saved on -the system stack. */ - -typedef struct ovecsave_frame { - struct ovecsave_frame *next; /* Next frame on free chain */ - PCRE2_SIZE saved_ovec[1]; /* First vector element */ -} ovecsave_frame; - /* Structure for items in a linked list that represents an explicit recursive -call within the pattern; used by pcre_match(). */ - -typedef struct recursion_info { - struct recursion_info *prevrec; /* Previous recursion record (or NULL) */ - unsigned int group_num; /* Number of group that was called */ - PCRE2_SIZE *ovec_save; /* Pointer to saved ovector frame */ - uint32_t saved_capture_last; /* Last capture number */ - PCRE2_SPTR subject_position; /* Position at start of recursion */ -} recursion_info; - -/* A similar structure for pcre_dfa_match(). */ +call within the pattern when running pcre_dfa_match(). */ typedef struct dfa_recursion_info { struct dfa_recursion_info *prevrec; @@ -768,35 +767,75 @@ typedef struct dfa_recursion_info { uint32_t group_num; } dfa_recursion_info; -/* Structure for building a chain of data for holding the values of the subject -pointer at the start of each subpattern, so as to detect when an empty string -has been matched by a subpattern - to break infinite loops; used by -pcre2_match(). */ +/* Structure for "stack" frames that are used for remembering backtracking +positions during matching. As these are used in a vector, with the ovector item +being extended, the size of the structure must be a multiple of PCRE2_SIZE. The +only way to check this at compile time is to force an error by generating an +array with a negative size. By putting this in a typedef (which is never used), +we don't generate any code when all is well. */ + +typedef struct heapframe { + + /* The first set of fields are variables that have to be preserved over calls + to RRMATCH(), but which do not need to be copied to new frames. */ + + PCRE2_SPTR ecode; /* The current position in the pattern */ + PCRE2_SPTR temp_sptr[2]; /* Used for short-term PCRE_SPTR values */ + PCRE2_SIZE length; /* Used for character, string, or code lengths */ + PCRE2_SIZE back_frame; /* Amount to subtract on RRETURN */ + PCRE2_SIZE temp_size; /* Used for short-term PCRE2_SIZE values */ + uint32_t rdepth; /* "Recursion" depth */ + uint32_t group_frame_type; /* Type information for group frames */ + uint32_t temp_32[4]; /* Used for short-term 32-bit or BOOL values */ + uint8_t return_id; /* Where to go on in internal "return" */ + uint8_t op; /* Processing opcode */ -typedef struct eptrblock { - struct eptrblock *epb_prev; - PCRE2_SPTR epb_saved_eptr; -} eptrblock; +#if PCRE2_CODE_UNIT_WIDTH == 8 + PCRE2_UCHAR occu[6]; /* Used for other case code units */ +#elif PCRE2_CODE_UNIT_WIDTH == 16 + PCRE2_UCHAR occu[2]; /* Used for other case code units */ +#else + PCRE2_UCHAR occu[1]; /* Used for other case code units */ +#endif + + /* The rest have to be copied from the previous frame whenever a new frame + becomes current. The final field is specified as a large vector so that + runtime array bound checks don't catch references to it. However, for any + specific call to pcre2_match() the memory allocated for each frame structure + allows for exactly the right size ovector for the number of capturing + parentheses. */ + + PCRE2_SPTR eptr; /* MUST BE FIRST */ + PCRE2_SPTR start_match; /* Can be adjusted by \K */ + PCRE2_SPTR mark; /* Most recent mark on the success path */ + uint32_t current_recurse; /* Current (deepest) recursion number */ + uint32_t capture_last; /* Most recent capture */ + PCRE2_SIZE last_group_offset; /* Saved offset to most recent group frame */ + PCRE2_SIZE offset_top; /* Offset after highest capture */ + PCRE2_SIZE ovector[10000]; /* Must be last in the structure */ +} heapframe; + +typedef char check_heapframe_size[ + ((sizeof(heapframe) % sizeof(PCRE2_SIZE)) == 0)? (+1):(-1)]; /* Structure for passing "static" information around between the functions doing traditional NFA matching (pcre2_match() and friends). */ typedef struct match_block { pcre2_memctl memctl; /* For general use */ -#ifdef HEAP_MATCH_RECURSE - pcre2_memctl stack_memctl; /* For "stack" frames */ -#endif - uint32_t match_call_count; /* As it says */ + PCRE2_SIZE frame_vector_size; /* Size of a backtracking frame */ + heapframe *match_frames; /* Points to vector of frames */ + heapframe *match_frames_top; /* Points after the end of the vector */ + heapframe *stack_frames; /* The original vector on the stack */ + PCRE2_SIZE heap_limit; /* As it says */ uint32_t match_limit; /* As it says */ - uint32_t match_limit_recursion; /* As it says */ + uint32_t match_limit_depth; /* As it says */ + uint32_t match_call_count; /* Number of times a new frame is created */ BOOL hitend; /* Hit the end of the subject at some point */ BOOL hasthen; /* Pattern contains (*THEN) */ const uint8_t *lcc; /* Points to lower casing table */ const uint8_t *fcc; /* Points to case-flipping table */ const uint8_t *ctypes; /* Points to table of type maps */ - PCRE2_SIZE *ovector; /* Pointer to the offset vector */ - PCRE2_SIZE offset_end; /* One past the end */ - PCRE2_SIZE offset_max; /* The maximum usable for return data */ PCRE2_SIZE start_offset; /* The start offset value */ PCRE2_SIZE end_offset_top; /* Highwater mark at end of match */ uint16_t partial; /* PARTIAL options */ @@ -807,30 +846,23 @@ typedef struct match_block { PCRE2_SPTR start_code; /* For use when recursing */ PCRE2_SPTR start_subject; /* Start of the subject string */ PCRE2_SPTR end_subject; /* End of the subject string */ - PCRE2_SPTR start_match_ptr; /* Start of matched string */ PCRE2_SPTR end_match_ptr; /* Subject position at end match */ PCRE2_SPTR start_used_ptr; /* Earliest consulted character */ PCRE2_SPTR last_used_ptr; /* Latest consulted character */ PCRE2_SPTR mark; /* Mark pointer to pass back on success */ PCRE2_SPTR nomatch_mark; /* Mark pointer to pass back on failure */ - PCRE2_SPTR once_target; /* Where to back up to for atomic groups */ + PCRE2_SPTR verb_ecode_ptr; /* For passing back info */ + PCRE2_SPTR verb_skip_ptr; /* For passing back a (*SKIP) name */ + uint32_t verb_current_recurse; /* Current recurse when (*VERB) happens */ uint32_t moptions; /* Match options */ uint32_t poptions; /* Pattern options */ - uint32_t capture_last; /* Most recent capture number + overflow flag */ uint32_t skip_arg_count; /* For counting SKIP_ARGs */ uint32_t ignore_skip_arg; /* For re-run when SKIP arg name not found */ - uint32_t match_function_type; /* Set for certain special calls of match() */ uint32_t nltype; /* Newline type */ uint32_t nllen; /* Newline string length */ PCRE2_UCHAR nl[4]; /* Newline string when fixed */ - eptrblock *eptrchain; /* Chain of eptrblocks for tail recursions */ - recursion_info *recursive; /* Linked list of recursion data */ - ovecsave_frame *ovecsave_chain; /* Linked list of free ovecsave blocks */ void *callout_data; /* To pass back to callouts */ int (*callout)(pcre2_callout_block *,void *); /* Callout function or NULL */ -#ifdef HEAP_MATCH_RECURSE - void *match_frames_base; /* For remembering malloc'd frames */ -#endif } match_block; /* A similar structure is used for the same purpose by the DFA matching @@ -845,7 +877,9 @@ typedef struct dfa_match_block { PCRE2_SPTR last_used_ptr; /* Latest consulted character */ const uint8_t *tables; /* Character tables */ PCRE2_SIZE start_offset; /* The start offset value */ - uint32_t match_limit_recursion; /* As it says */ + uint32_t match_limit; /* As it says */ + uint32_t match_limit_depth; /* As it says */ + uint32_t match_call_count; /* Number of calls of internal function */ uint32_t moptions; /* Match options */ uint32_t poptions; /* Pattern options */ uint32_t nltype; /* Newline type */ diff --git a/ProcessHacker/pcre/pcre2_jit_compile.c b/ProcessHacker/pcre/pcre2_jit_compile.c index 5a02249324b3..c7bf0b2c3e02 100644 --- a/ProcessHacker/pcre/pcre2_jit_compile.c +++ b/ProcessHacker/pcre/pcre2_jit_compile.c @@ -7,7 +7,7 @@ and semantics are as close as possible to those of the Perl 5 language. Written by Philip Hazel Original API code Copyright (c) 1997-2012 University of Cambridge - New API code Copyright (c) 2016 University of Cambridge + New API code Copyright (c) 2016-2017 University of Cambridge ----------------------------------------------------------------------------- Redistribution and use in source and binary forms, with or without @@ -38,8 +38,6 @@ POSSIBILITY OF SUCH DAMAGE. ----------------------------------------------------------------------------- */ -#define HAVE_CONFIG_H - #ifdef HAVE_CONFIG_H #include "config.h" #endif @@ -315,16 +313,25 @@ typedef struct ref_iterator_backtrack { typedef struct recurse_entry { struct recurse_entry *next; - /* Contains the function entry. */ - struct sljit_label *entry; - /* Collects the calls until the function is not created. */ - jump_list *calls; + /* Contains the function entry label. */ + struct sljit_label *entry_label; + /* Contains the function entry label. */ + struct sljit_label *backtrack_label; + /* Collects the entry calls until the function is not created. */ + jump_list *entry_calls; + /* Collects the backtrack calls until the function is not created. */ + jump_list *backtrack_calls; /* Points to the starting opcode. */ sljit_sw start; } recurse_entry; typedef struct recurse_backtrack { backtrack_common common; + /* Return to the matching path. */ + struct sljit_label *matchingpath; + /* Recursive pattern. */ + recurse_entry *entry; + /* Pattern is inlined. */ BOOL inlined_pattern; } recurse_backtrack; @@ -343,11 +350,26 @@ typedef struct then_trap_backtrack { int framesize; } then_trap_backtrack; -#define MAX_RANGE_SIZE 4 +#define MAX_N_CHARS 12 +#define MAX_DIFF_CHARS 5 + +typedef struct fast_forward_char_data { + /* Number of characters in the chars array, 255 for any character. */ + sljit_u8 count; + /* Number of last UTF-8 characters in the chars array. */ + sljit_u8 last_count; + /* Available characters in the current position. */ + PCRE2_UCHAR chars[MAX_DIFF_CHARS]; +} fast_forward_char_data; + +#define MAX_CLASS_RANGE_SIZE 4 +#define MAX_CLASS_CHARS_SIZE 3 typedef struct compiler_common { /* The sljit ceneric compiler. */ struct sljit_compiler *compiler; + /* Compiled regular expression. */ + pcre2_real_code *re; /* First byte code. */ PCRE2_SPTR start; /* Maps private data offset to each opcode. */ @@ -404,10 +426,10 @@ typedef struct compiler_common { BOOL has_then; /* (*SKIP) or (*SKIP:arg) is found in lookbehind assertion. */ BOOL has_skip_in_assert_back; - /* Currently in recurse or negative assert. */ - BOOL local_exit; - /* Currently in a positive assert. */ - BOOL positive_assert; + /* Quit is redirected by recurse, negative assertion, or positive assertion in conditional block. */ + BOOL local_quit_available; + /* Currently in a positive assertion. */ + BOOL in_positive_assertion; /* Newline control. */ int nltype; sljit_u32 nlmax; @@ -428,7 +450,7 @@ typedef struct compiler_common { /* Labels and jump lists. */ struct sljit_label *partialmatchlabel; struct sljit_label *quit_label; - struct sljit_label *forced_quit_label; + struct sljit_label *abort_label; struct sljit_label *accept_label; struct sljit_label *ff_newline_shortcut; stub_list *stubs; @@ -437,8 +459,9 @@ typedef struct compiler_common { recurse_entry *currententry; jump_list *partialmatch; jump_list *quit; - jump_list *positive_assert_quit; - jump_list *forced_quit; + jump_list *positive_assertion_quit; + jump_list *abort; + jump_list *failed_match; jump_list *accept; jump_list *calllimit; jump_list *stackalloc; @@ -502,7 +525,7 @@ typedef struct compare_context { #undef CMP /* Used for accessing the elements of the stack. */ -#define STACK(i) ((-(i) - 1) * (int)sizeof(sljit_sw)) +#define STACK(i) ((i) * (int)sizeof(sljit_sw)) #define TMP1 SLJIT_R0 #define TMP2 SLJIT_R2 @@ -572,13 +595,17 @@ the start pointers when the end of the capturing group has not yet reached. */ sljit_emit_cmp(compiler, (type), (src1), (src1w), (src2), (src2w)) #define CMPTO(type, src1, src1w, src2, src2w, label) \ sljit_set_label(sljit_emit_cmp(compiler, (type), (src1), (src1w), (src2), (src2w)), (label)) -#define OP_FLAGS(op, dst, dstw, src, srcw, type) \ - sljit_emit_op_flags(compiler, (op), (dst), (dstw), (src), (srcw), (type)) +#define OP_FLAGS(op, dst, dstw, type) \ + sljit_emit_op_flags(compiler, (op), (dst), (dstw), (type)) +#define CMOV(type, dst_reg, src, srcw) \ + sljit_emit_cmov(compiler, (type), (dst_reg), (src), (srcw)) #define GET_LOCAL_BASE(dst, dstw, offset) \ sljit_get_local_base(compiler, (dst), (dstw), (offset)) #define READ_CHAR_MAX 0x7fffffff +#define INVALID_UTF_CHAR 888 + static PCRE2_SPTR bracketend(PCRE2_SPTR cc) { SLJIT_ASSERT((*cc >= OP_ASSERT && *cc <= OP_ASSERTBACK_NOT) || (*cc >= OP_ONCE && *cc <= OP_SCOND)); @@ -608,8 +635,8 @@ return count; set_private_data_ptrs get_framesize init_frame - get_private_data_copy_length - copy_private_data + get_recurse_data_length + copy_recurse_data compile_matchingpath compile_backtrackingpath */ @@ -677,7 +704,6 @@ switch(*cc) case OP_ASSERTBACK: case OP_ASSERTBACK_NOT: case OP_ONCE: - case OP_ONCE_NC: case OP_BRA: case OP_BRAPOS: case OP_CBRA: @@ -808,7 +834,7 @@ switch(*cc) default: /* All opcodes are supported now! */ - SLJIT_ASSERT_STOP(); + SLJIT_UNREACHABLE(); return NULL; } } @@ -1306,7 +1332,7 @@ while (cc < ccend) if (private_data_ptr > SLJIT_MAX_LOCAL_SIZE) break; - if (repeat_check && (*cc == OP_ONCE || *cc == OP_ONCE_NC || *cc == OP_BRA || *cc == OP_CBRA || *cc == OP_COND)) + if (repeat_check && (*cc == OP_ONCE || *cc == OP_BRA || *cc == OP_CBRA || *cc == OP_COND)) { if (detect_repeat(common, cc)) { @@ -1335,7 +1361,6 @@ while (cc < ccend) case OP_ASSERTBACK: case OP_ASSERTBACK_NOT: case OP_ONCE: - case OP_ONCE_NC: case OP_BRAPOS: case OP_SBRA: case OP_SBRAPOS: @@ -1656,11 +1681,11 @@ if (length > 0) return stack_restore ? no_frame : no_stack; } -static void init_frame(compiler_common *common, PCRE2_SPTR cc, PCRE2_SPTR ccend, int stackpos, int stacktop, BOOL recursive) +static void init_frame(compiler_common *common, PCRE2_SPTR cc, PCRE2_SPTR ccend, int stackpos, int stacktop) { DEFINE_COMPILER; -BOOL setsom_found = recursive; -BOOL setmark_found = recursive; +BOOL setsom_found = FALSE; +BOOL setmark_found = FALSE; /* The last capture is a local variable even for recursions. */ BOOL capture_last_found = FALSE; int offset; @@ -1673,7 +1698,7 @@ stackpos = STACK(stackpos); if (ccend == NULL) { ccend = bracketend(cc) - (1 + LINK_SIZE); - if (recursive || (*cc != OP_CBRAPOS && *cc != OP_SCBRAPOS)) + if (*cc != OP_CBRAPOS && *cc != OP_SCBRAPOS) cc = next_opcode(common, cc); } @@ -1687,9 +1712,9 @@ while (cc < ccend) { OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(0)); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, SLJIT_IMM, -OVECTOR(0)); - stackpos += (int)sizeof(sljit_sw); + stackpos -= (int)sizeof(sljit_sw); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, TMP1, 0); - stackpos += (int)sizeof(sljit_sw); + stackpos -= (int)sizeof(sljit_sw); setsom_found = TRUE; } cc += 1; @@ -1703,9 +1728,9 @@ while (cc < ccend) { OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->mark_ptr); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, SLJIT_IMM, -common->mark_ptr); - stackpos += (int)sizeof(sljit_sw); + stackpos -= (int)sizeof(sljit_sw); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, TMP1, 0); - stackpos += (int)sizeof(sljit_sw); + stackpos -= (int)sizeof(sljit_sw); setmark_found = TRUE; } cc += 1 + 2 + cc[1]; @@ -1716,27 +1741,27 @@ while (cc < ccend) { OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(0)); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, SLJIT_IMM, -OVECTOR(0)); - stackpos += (int)sizeof(sljit_sw); + stackpos -= (int)sizeof(sljit_sw); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, TMP1, 0); - stackpos += (int)sizeof(sljit_sw); + stackpos -= (int)sizeof(sljit_sw); setsom_found = TRUE; } if (common->mark_ptr != 0 && !setmark_found) { OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->mark_ptr); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, SLJIT_IMM, -common->mark_ptr); - stackpos += (int)sizeof(sljit_sw); + stackpos -= (int)sizeof(sljit_sw); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, TMP1, 0); - stackpos += (int)sizeof(sljit_sw); + stackpos -= (int)sizeof(sljit_sw); setmark_found = TRUE; } if (common->capture_last_ptr != 0 && !capture_last_found) { OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->capture_last_ptr); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, SLJIT_IMM, -common->capture_last_ptr); - stackpos += (int)sizeof(sljit_sw); + stackpos -= (int)sizeof(sljit_sw); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, TMP1, 0); - stackpos += (int)sizeof(sljit_sw); + stackpos -= (int)sizeof(sljit_sw); capture_last_found = TRUE; } cc += 1 + LINK_SIZE; @@ -1750,20 +1775,20 @@ while (cc < ccend) { OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->capture_last_ptr); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, SLJIT_IMM, -common->capture_last_ptr); - stackpos += (int)sizeof(sljit_sw); + stackpos -= (int)sizeof(sljit_sw); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, TMP1, 0); - stackpos += (int)sizeof(sljit_sw); + stackpos -= (int)sizeof(sljit_sw); capture_last_found = TRUE; } offset = (GET2(cc, 1 + LINK_SIZE)) << 1; OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, SLJIT_IMM, OVECTOR(offset)); - stackpos += (int)sizeof(sljit_sw); + stackpos -= (int)sizeof(sljit_sw); OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset)); OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset + 1)); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, TMP1, 0); - stackpos += (int)sizeof(sljit_sw); + stackpos -= (int)sizeof(sljit_sw); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, TMP2, 0); - stackpos += (int)sizeof(sljit_sw); + stackpos -= (int)sizeof(sljit_sw); cc += 1 + LINK_SIZE + IMM2_SIZE; break; @@ -1778,21 +1803,127 @@ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, SLJIT_IMM, 0); SLJIT_ASSERT(stackpos == STACK(stacktop)); } -static SLJIT_INLINE int get_private_data_copy_length(compiler_common *common, PCRE2_SPTR cc, PCRE2_SPTR ccend, BOOL needs_control_head) +#define RECURSE_TMP_REG_COUNT 3 + +typedef struct delayed_mem_copy_status { + struct sljit_compiler *compiler; + int store_bases[RECURSE_TMP_REG_COUNT]; + int store_offsets[RECURSE_TMP_REG_COUNT]; + int tmp_regs[RECURSE_TMP_REG_COUNT]; + int saved_tmp_regs[RECURSE_TMP_REG_COUNT]; + int next_tmp_reg; +} delayed_mem_copy_status; + +static void delayed_mem_copy_init(delayed_mem_copy_status *status, compiler_common *common) +{ +int i; + +for (i = 0; i < RECURSE_TMP_REG_COUNT; i++) + { + SLJIT_ASSERT(status->tmp_regs[i] >= 0); + SLJIT_ASSERT(sljit_get_register_index(status->saved_tmp_regs[i]) < 0 || status->tmp_regs[i] == status->saved_tmp_regs[i]); + + status->store_bases[i] = -1; + } +status->next_tmp_reg = 0; +status->compiler = common->compiler; +} + +static void delayed_mem_copy_move(delayed_mem_copy_status *status, int load_base, sljit_sw load_offset, + int store_base, sljit_sw store_offset) +{ +struct sljit_compiler *compiler = status->compiler; +int next_tmp_reg = status->next_tmp_reg; +int tmp_reg = status->tmp_regs[next_tmp_reg]; + +SLJIT_ASSERT(load_base > 0 && store_base > 0); + +if (status->store_bases[next_tmp_reg] == -1) + { + /* Preserve virtual registers. */ + if (sljit_get_register_index(status->saved_tmp_regs[next_tmp_reg]) < 0) + OP1(SLJIT_MOV, status->saved_tmp_regs[next_tmp_reg], 0, tmp_reg, 0); + } +else + OP1(SLJIT_MOV, SLJIT_MEM1(status->store_bases[next_tmp_reg]), status->store_offsets[next_tmp_reg], tmp_reg, 0); + +OP1(SLJIT_MOV, tmp_reg, 0, SLJIT_MEM1(load_base), load_offset); +status->store_bases[next_tmp_reg] = store_base; +status->store_offsets[next_tmp_reg] = store_offset; + +status->next_tmp_reg = (next_tmp_reg + 1) % RECURSE_TMP_REG_COUNT; +} + +static void delayed_mem_copy_finish(delayed_mem_copy_status *status) +{ +struct sljit_compiler *compiler = status->compiler; +int next_tmp_reg = status->next_tmp_reg; +int tmp_reg, saved_tmp_reg, i; + +for (i = 0; i < RECURSE_TMP_REG_COUNT; i++) + { + if (status->store_bases[next_tmp_reg] != -1) + { + tmp_reg = status->tmp_regs[next_tmp_reg]; + saved_tmp_reg = status->saved_tmp_regs[next_tmp_reg]; + + OP1(SLJIT_MOV, SLJIT_MEM1(status->store_bases[next_tmp_reg]), status->store_offsets[next_tmp_reg], tmp_reg, 0); + + /* Restore virtual registers. */ + if (sljit_get_register_index(saved_tmp_reg) < 0) + OP1(SLJIT_MOV, tmp_reg, 0, saved_tmp_reg, 0); + } + + next_tmp_reg = (next_tmp_reg + 1) % RECURSE_TMP_REG_COUNT; + } +} + +#undef RECURSE_TMP_REG_COUNT + +static int get_recurse_data_length(compiler_common *common, PCRE2_SPTR cc, PCRE2_SPTR ccend, + BOOL *needs_control_head, BOOL *has_quit, BOOL *has_accept) { -int private_data_length = needs_control_head ? 3 : 2; +int length = 1; int size; PCRE2_SPTR alternative; +BOOL quit_found = FALSE; +BOOL accept_found = FALSE; +BOOL setsom_found = FALSE; +BOOL setmark_found = FALSE; +BOOL capture_last_found = FALSE; +BOOL control_head_found = FALSE; + +#if defined DEBUG_FORCE_CONTROL_HEAD && DEBUG_FORCE_CONTROL_HEAD +SLJIT_ASSERT(common->control_head_ptr != 0); +control_head_found = TRUE; +#endif + /* Calculate the sum of the private machine words. */ while (cc < ccend) { size = 0; switch(*cc) { + case OP_SET_SOM: + SLJIT_ASSERT(common->has_set_som); + setsom_found = TRUE; + cc += 1; + break; + + case OP_RECURSE: + if (common->has_set_som) + setsom_found = TRUE; + if (common->mark_ptr != 0) + setmark_found = TRUE; + if (common->capture_last_ptr != 0) + capture_last_found = TRUE; + cc += 1 + LINK_SIZE; + break; + case OP_KET: if (PRIVATE_DATA(cc) != 0) { - private_data_length++; + length++; SLJIT_ASSERT(PRIVATE_DATA(cc + 1) != 0); cc += PRIVATE_DATA(cc + 1); } @@ -1804,26 +1935,30 @@ while (cc < ccend) case OP_ASSERTBACK: case OP_ASSERTBACK_NOT: case OP_ONCE: - case OP_ONCE_NC: case OP_BRAPOS: case OP_SBRA: case OP_SBRAPOS: case OP_SCOND: - private_data_length++; + length++; SLJIT_ASSERT(PRIVATE_DATA(cc) != 0); cc += 1 + LINK_SIZE; break; case OP_CBRA: case OP_SCBRA: + length += 2; + if (common->capture_last_ptr != 0) + capture_last_found = TRUE; if (common->optimized_cbracket[GET2(cc, 1 + LINK_SIZE)] == 0) - private_data_length++; + length++; cc += 1 + LINK_SIZE + IMM2_SIZE; break; case OP_CBRAPOS: case OP_SCBRAPOS: - private_data_length += 2; + length += 2 + 2; + if (common->capture_last_ptr != 0) + capture_last_found = TRUE; cc += 1 + LINK_SIZE + IMM2_SIZE; break; @@ -1831,13 +1966,13 @@ while (cc < ccend) /* Might be a hidden SCOND. */ alternative = cc + GET(cc, 1); if (*alternative == OP_KETRMAX || *alternative == OP_KETRMIN) - private_data_length++; + length++; cc += 1 + LINK_SIZE; break; CASE_ITERATOR_PRIVATE_DATA_1 - if (PRIVATE_DATA(cc)) - private_data_length++; + if (PRIVATE_DATA(cc) != 0) + length++; cc += 2; #ifdef SUPPORT_UNICODE if (common->utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]); @@ -1845,8 +1980,8 @@ while (cc < ccend) break; CASE_ITERATOR_PRIVATE_DATA_2A - if (PRIVATE_DATA(cc)) - private_data_length += 2; + if (PRIVATE_DATA(cc) != 0) + length += 2; cc += 2; #ifdef SUPPORT_UNICODE if (common->utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]); @@ -1854,8 +1989,8 @@ while (cc < ccend) break; CASE_ITERATOR_PRIVATE_DATA_2B - if (PRIVATE_DATA(cc)) - private_data_length += 2; + if (PRIVATE_DATA(cc) != 0) + length += 2; cc += 2 + IMM2_SIZE; #ifdef SUPPORT_UNICODE if (common->utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]); @@ -1863,20 +1998,20 @@ while (cc < ccend) break; CASE_ITERATOR_TYPE_PRIVATE_DATA_1 - if (PRIVATE_DATA(cc)) - private_data_length++; + if (PRIVATE_DATA(cc) != 0) + length++; cc += 1; break; CASE_ITERATOR_TYPE_PRIVATE_DATA_2A - if (PRIVATE_DATA(cc)) - private_data_length += 2; + if (PRIVATE_DATA(cc) != 0) + length += 2; cc += 1; break; CASE_ITERATOR_TYPE_PRIVATE_DATA_2B - if (PRIVATE_DATA(cc)) - private_data_length += 2; + if (PRIVATE_DATA(cc) != 0) + length += 2; cc += 1 + IMM2_SIZE; break; @@ -1888,11 +2023,51 @@ while (cc < ccend) #else size = 1 + 32 / (int)sizeof(PCRE2_UCHAR); #endif - if (PRIVATE_DATA(cc)) - private_data_length += get_class_iterator_size(cc + size); + if (PRIVATE_DATA(cc) != 0) + length += get_class_iterator_size(cc + size); cc += size; break; + case OP_MARK: + case OP_PRUNE_ARG: + case OP_THEN_ARG: + SLJIT_ASSERT(common->mark_ptr != 0); + if (!setmark_found) + setmark_found = TRUE; + if (common->control_head_ptr != 0) + control_head_found = TRUE; + if (*cc != OP_MARK) + quit_found = TRUE; + + cc += 1 + 2 + cc[1]; + break; + + case OP_PRUNE: + case OP_SKIP: + case OP_COMMIT: + quit_found = TRUE; + cc++; + break; + + case OP_SKIP_ARG: + quit_found = TRUE; + cc += 1 + 2 + cc[1]; + break; + + case OP_THEN: + SLJIT_ASSERT(common->control_head_ptr != 0); + quit_found = TRUE; + if (!control_head_found) + control_head_found = TRUE; + cc++; + break; + + case OP_ACCEPT: + case OP_ASSERT_ACCEPT: + accept_found = TRUE; + cc++; + break; + default: cc = next_opcode(common, cc); SLJIT_ASSERT(cc != NULL); @@ -1900,329 +2075,446 @@ while (cc < ccend) } } SLJIT_ASSERT(cc == ccend); -return private_data_length; + +if (control_head_found) + length++; +if (capture_last_found) + length++; +if (quit_found) + { + if (setsom_found) + length++; + if (setmark_found) + length++; + } + +*needs_control_head = control_head_found; +*has_quit = quit_found; +*has_accept = accept_found; +return length; } -static void copy_private_data(compiler_common *common, PCRE2_SPTR cc, PCRE2_SPTR ccend, - BOOL save, int stackptr, int stacktop, BOOL needs_control_head) +enum copy_recurse_data_types { + recurse_copy_from_global, + recurse_copy_private_to_global, + recurse_copy_shared_to_global, + recurse_copy_kept_shared_to_global, + recurse_swap_global +}; + +static void copy_recurse_data(compiler_common *common, PCRE2_SPTR cc, PCRE2_SPTR ccend, + int type, int stackptr, int stacktop, BOOL has_quit) { -DEFINE_COMPILER; -int srcw[2]; -int count, size; -BOOL tmp1next = TRUE; -BOOL tmp1empty = TRUE; -BOOL tmp2empty = TRUE; +delayed_mem_copy_status status; PCRE2_SPTR alternative; -enum { - start, - loop, - end -} status; +sljit_sw private_srcw[2]; +sljit_sw shared_srcw[3]; +sljit_sw kept_shared_srcw[2]; +int private_count, shared_count, kept_shared_count; +int from_sp, base_reg, offset, i; +BOOL setsom_found = FALSE; +BOOL setmark_found = FALSE; +BOOL capture_last_found = FALSE; +BOOL control_head_found = FALSE; -status = save ? start : loop; -stackptr = STACK(stackptr - 2); -stacktop = STACK(stacktop - 1); +#if defined DEBUG_FORCE_CONTROL_HEAD && DEBUG_FORCE_CONTROL_HEAD +SLJIT_ASSERT(common->control_head_ptr != 0); +control_head_found = TRUE; +#endif -if (!save) +switch (type) { - stackptr += (needs_control_head ? 2 : 1) * sizeof(sljit_sw); - if (stackptr < stacktop) - { - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), stackptr); - stackptr += sizeof(sljit_sw); - tmp1empty = FALSE; - } - if (stackptr < stacktop) - { - OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), stackptr); - stackptr += sizeof(sljit_sw); - tmp2empty = FALSE; - } - /* The tmp1next must be TRUE in either way. */ - } + case recurse_copy_from_global: + from_sp = TRUE; + base_reg = STACK_TOP; + break; -do - { - count = 0; - switch(status) - { - case start: - SLJIT_ASSERT(save && common->recursive_head_ptr != 0); - count = 1; - srcw[0] = common->recursive_head_ptr; - if (needs_control_head) - { - SLJIT_ASSERT(common->control_head_ptr != 0); - count = 2; - srcw[1] = common->control_head_ptr; - } - status = loop; - break; + case recurse_copy_private_to_global: + case recurse_copy_shared_to_global: + case recurse_copy_kept_shared_to_global: + from_sp = FALSE; + base_reg = STACK_TOP; + break; - case loop: - if (cc >= ccend) - { - status = end; - break; - } + default: + SLJIT_ASSERT(type == recurse_swap_global); + from_sp = FALSE; + base_reg = TMP2; + break; + } - switch(*cc) - { - case OP_KET: - if (PRIVATE_DATA(cc) != 0) - { - count = 1; - srcw[0] = PRIVATE_DATA(cc); - SLJIT_ASSERT(PRIVATE_DATA(cc + 1) != 0); - cc += PRIVATE_DATA(cc + 1); - } - cc += 1 + LINK_SIZE; - break; +stackptr = STACK(stackptr); +stacktop = STACK(stacktop); - case OP_ASSERT: - case OP_ASSERT_NOT: - case OP_ASSERTBACK: - case OP_ASSERTBACK_NOT: - case OP_ONCE: - case OP_ONCE_NC: - case OP_BRAPOS: - case OP_SBRA: - case OP_SBRAPOS: - case OP_SCOND: - count = 1; - srcw[0] = PRIVATE_DATA(cc); - SLJIT_ASSERT(srcw[0] != 0); - cc += 1 + LINK_SIZE; - break; +status.tmp_regs[0] = TMP1; +status.saved_tmp_regs[0] = TMP1; - case OP_CBRA: - case OP_SCBRA: - if (common->optimized_cbracket[GET2(cc, 1 + LINK_SIZE)] == 0) - { - count = 1; - srcw[0] = OVECTOR_PRIV(GET2(cc, 1 + LINK_SIZE)); - } - cc += 1 + LINK_SIZE + IMM2_SIZE; - break; +if (base_reg != TMP2) + { + status.tmp_regs[1] = TMP2; + status.saved_tmp_regs[1] = TMP2; + } +else + { + status.saved_tmp_regs[1] = RETURN_ADDR; + if (sljit_get_register_index (RETURN_ADDR) == -1) + status.tmp_regs[1] = STR_PTR; + else + status.tmp_regs[1] = RETURN_ADDR; + } - case OP_CBRAPOS: - case OP_SCBRAPOS: - count = 2; - srcw[0] = PRIVATE_DATA(cc); - srcw[1] = OVECTOR_PRIV(GET2(cc, 1 + LINK_SIZE)); - SLJIT_ASSERT(srcw[0] != 0 && srcw[1] != 0); - cc += 1 + LINK_SIZE + IMM2_SIZE; - break; +status.saved_tmp_regs[2] = TMP3; +if (sljit_get_register_index (TMP3) == -1) + status.tmp_regs[2] = STR_END; +else + status.tmp_regs[2] = TMP3; - case OP_COND: - /* Might be a hidden SCOND. */ - alternative = cc + GET(cc, 1); - if (*alternative == OP_KETRMAX || *alternative == OP_KETRMIN) - { - count = 1; - srcw[0] = PRIVATE_DATA(cc); - SLJIT_ASSERT(srcw[0] != 0); - } - cc += 1 + LINK_SIZE; - break; +delayed_mem_copy_init(&status, common); - CASE_ITERATOR_PRIVATE_DATA_1 - if (PRIVATE_DATA(cc)) - { - count = 1; - srcw[0] = PRIVATE_DATA(cc); - } - cc += 2; -#ifdef SUPPORT_UNICODE - if (common->utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]); -#endif - break; +if (type != recurse_copy_shared_to_global && type != recurse_copy_kept_shared_to_global) + { + SLJIT_ASSERT(type == recurse_copy_from_global || type == recurse_copy_private_to_global || type == recurse_swap_global); - CASE_ITERATOR_PRIVATE_DATA_2A - if (PRIVATE_DATA(cc)) - { - count = 2; - srcw[0] = PRIVATE_DATA(cc); - srcw[1] = PRIVATE_DATA(cc) + sizeof(sljit_sw); - } - cc += 2; -#ifdef SUPPORT_UNICODE - if (common->utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]); -#endif - break; + if (!from_sp) + delayed_mem_copy_move(&status, base_reg, stackptr, SLJIT_SP, common->recursive_head_ptr); - CASE_ITERATOR_PRIVATE_DATA_2B - if (PRIVATE_DATA(cc)) - { - count = 2; - srcw[0] = PRIVATE_DATA(cc); - srcw[1] = PRIVATE_DATA(cc) + sizeof(sljit_sw); - } - cc += 2 + IMM2_SIZE; -#ifdef SUPPORT_UNICODE - if (common->utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]); -#endif - break; + if (from_sp || type == recurse_swap_global) + delayed_mem_copy_move(&status, SLJIT_SP, common->recursive_head_ptr, base_reg, stackptr); + } - CASE_ITERATOR_TYPE_PRIVATE_DATA_1 - if (PRIVATE_DATA(cc)) - { - count = 1; - srcw[0] = PRIVATE_DATA(cc); - } - cc += 1; - break; +stackptr += sizeof(sljit_sw); - CASE_ITERATOR_TYPE_PRIVATE_DATA_2A - if (PRIVATE_DATA(cc)) - { - count = 2; - srcw[0] = PRIVATE_DATA(cc); - srcw[1] = srcw[0] + sizeof(sljit_sw); - } - cc += 1; - break; +#if defined DEBUG_FORCE_CONTROL_HEAD && DEBUG_FORCE_CONTROL_HEAD +if (type != recurse_copy_shared_to_global) + { + if (!from_sp) + delayed_mem_copy_move(&status, base_reg, stackptr, SLJIT_SP, common->control_head_ptr); - CASE_ITERATOR_TYPE_PRIVATE_DATA_2B - if (PRIVATE_DATA(cc)) - { - count = 2; - srcw[0] = PRIVATE_DATA(cc); - srcw[1] = srcw[0] + sizeof(sljit_sw); - } - cc += 1 + IMM2_SIZE; - break; + if (from_sp || type == recurse_swap_global) + delayed_mem_copy_move(&status, SLJIT_SP, common->control_head_ptr, base_reg, stackptr); + } - case OP_CLASS: - case OP_NCLASS: -#if defined SUPPORT_UNICODE || PCRE2_CODE_UNIT_WIDTH != 8 - case OP_XCLASS: - size = (*cc == OP_XCLASS) ? GET(cc, 1) : 1 + 32 / (int)sizeof(PCRE2_UCHAR); -#else - size = 1 + 32 / (int)sizeof(PCRE2_UCHAR); +stackptr += sizeof(sljit_sw); #endif - if (PRIVATE_DATA(cc)) - switch(get_class_iterator_size(cc + size)) - { - case 1: - count = 1; - srcw[0] = PRIVATE_DATA(cc); - break; - - case 2: - count = 2; - srcw[0] = PRIVATE_DATA(cc); - srcw[1] = srcw[0] + sizeof(sljit_sw); - break; - default: - SLJIT_ASSERT_STOP(); - break; - } - cc += size; - break; +while (cc < ccend) + { + private_count = 0; + shared_count = 0; + kept_shared_count = 0; - default: - cc = next_opcode(common, cc); - SLJIT_ASSERT(cc != NULL); - break; + switch(*cc) + { + case OP_SET_SOM: + SLJIT_ASSERT(common->has_set_som); + if (has_quit && !setsom_found) + { + kept_shared_srcw[0] = OVECTOR(0); + kept_shared_count = 1; + setsom_found = TRUE; } + cc += 1; break; - case end: - SLJIT_ASSERT_STOP(); - break; - } - - while (count > 0) - { - count--; - if (save) + case OP_RECURSE: + if (has_quit) { - if (tmp1next) + if (common->has_set_som && !setsom_found) { - if (!tmp1empty) - { - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackptr, TMP1, 0); - stackptr += sizeof(sljit_sw); - } - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), srcw[count]); - tmp1empty = FALSE; - tmp1next = FALSE; + kept_shared_srcw[0] = OVECTOR(0); + kept_shared_count = 1; + setsom_found = TRUE; } - else + if (common->mark_ptr != 0 && !setmark_found) { - if (!tmp2empty) - { - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackptr, TMP2, 0); - stackptr += sizeof(sljit_sw); - } - OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), srcw[count]); - tmp2empty = FALSE; - tmp1next = TRUE; + kept_shared_srcw[kept_shared_count] = common->mark_ptr; + kept_shared_count++; + setmark_found = TRUE; } } - else + if (common->capture_last_ptr != 0 && !capture_last_found) { - if (tmp1next) - { - SLJIT_ASSERT(!tmp1empty); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), srcw[count], TMP1, 0); - tmp1empty = stackptr >= stacktop; - if (!tmp1empty) - { - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), stackptr); - stackptr += sizeof(sljit_sw); - } - tmp1next = FALSE; - } - else - { - SLJIT_ASSERT(!tmp2empty); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), srcw[count], TMP2, 0); - tmp2empty = stackptr >= stacktop; - if (!tmp2empty) - { - OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), stackptr); - stackptr += sizeof(sljit_sw); - } - tmp1next = TRUE; - } + shared_srcw[0] = common->capture_last_ptr; + shared_count = 1; + capture_last_found = TRUE; } - } - } -while (status != end); + cc += 1 + LINK_SIZE; + break; -if (save) - { - if (tmp1next) - { - if (!tmp1empty) + case OP_KET: + if (PRIVATE_DATA(cc) != 0) { - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackptr, TMP1, 0); - stackptr += sizeof(sljit_sw); + private_count = 1; + private_srcw[0] = PRIVATE_DATA(cc); + SLJIT_ASSERT(PRIVATE_DATA(cc + 1) != 0); + cc += PRIVATE_DATA(cc + 1); } - if (!tmp2empty) + cc += 1 + LINK_SIZE; + break; + + case OP_ASSERT: + case OP_ASSERT_NOT: + case OP_ASSERTBACK: + case OP_ASSERTBACK_NOT: + case OP_ONCE: + case OP_BRAPOS: + case OP_SBRA: + case OP_SBRAPOS: + case OP_SCOND: + private_count = 1; + private_srcw[0] = PRIVATE_DATA(cc); + cc += 1 + LINK_SIZE; + break; + + case OP_CBRA: + case OP_SCBRA: + offset = (GET2(cc, 1 + LINK_SIZE)) << 1; + shared_srcw[0] = OVECTOR(offset); + shared_srcw[1] = OVECTOR(offset + 1); + shared_count = 2; + + if (common->capture_last_ptr != 0 && !capture_last_found) + { + shared_srcw[2] = common->capture_last_ptr; + shared_count = 3; + capture_last_found = TRUE; + } + + if (common->optimized_cbracket[GET2(cc, 1 + LINK_SIZE)] == 0) + { + private_count = 1; + private_srcw[0] = OVECTOR_PRIV(GET2(cc, 1 + LINK_SIZE)); + } + cc += 1 + LINK_SIZE + IMM2_SIZE; + break; + + case OP_CBRAPOS: + case OP_SCBRAPOS: + offset = (GET2(cc, 1 + LINK_SIZE)) << 1; + shared_srcw[0] = OVECTOR(offset); + shared_srcw[1] = OVECTOR(offset + 1); + shared_count = 2; + + if (common->capture_last_ptr != 0 && !capture_last_found) + { + shared_srcw[2] = common->capture_last_ptr; + shared_count = 3; + capture_last_found = TRUE; + } + + private_count = 2; + private_srcw[0] = PRIVATE_DATA(cc); + private_srcw[1] = OVECTOR_PRIV(GET2(cc, 1 + LINK_SIZE)); + cc += 1 + LINK_SIZE + IMM2_SIZE; + break; + + case OP_COND: + /* Might be a hidden SCOND. */ + alternative = cc + GET(cc, 1); + if (*alternative == OP_KETRMAX || *alternative == OP_KETRMIN) + { + private_count = 1; + private_srcw[0] = PRIVATE_DATA(cc); + } + cc += 1 + LINK_SIZE; + break; + + CASE_ITERATOR_PRIVATE_DATA_1 + if (PRIVATE_DATA(cc)) + { + private_count = 1; + private_srcw[0] = PRIVATE_DATA(cc); + } + cc += 2; +#ifdef SUPPORT_UNICODE + if (common->utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]); +#endif + break; + + CASE_ITERATOR_PRIVATE_DATA_2A + if (PRIVATE_DATA(cc)) + { + private_count = 2; + private_srcw[0] = PRIVATE_DATA(cc); + private_srcw[1] = PRIVATE_DATA(cc) + sizeof(sljit_sw); + } + cc += 2; +#ifdef SUPPORT_UNICODE + if (common->utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]); +#endif + break; + + CASE_ITERATOR_PRIVATE_DATA_2B + if (PRIVATE_DATA(cc)) + { + private_count = 2; + private_srcw[0] = PRIVATE_DATA(cc); + private_srcw[1] = PRIVATE_DATA(cc) + sizeof(sljit_sw); + } + cc += 2 + IMM2_SIZE; +#ifdef SUPPORT_UNICODE + if (common->utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]); +#endif + break; + + CASE_ITERATOR_TYPE_PRIVATE_DATA_1 + if (PRIVATE_DATA(cc)) + { + private_count = 1; + private_srcw[0] = PRIVATE_DATA(cc); + } + cc += 1; + break; + + CASE_ITERATOR_TYPE_PRIVATE_DATA_2A + if (PRIVATE_DATA(cc)) + { + private_count = 2; + private_srcw[0] = PRIVATE_DATA(cc); + private_srcw[1] = private_srcw[0] + sizeof(sljit_sw); + } + cc += 1; + break; + + CASE_ITERATOR_TYPE_PRIVATE_DATA_2B + if (PRIVATE_DATA(cc)) + { + private_count = 2; + private_srcw[0] = PRIVATE_DATA(cc); + private_srcw[1] = private_srcw[0] + sizeof(sljit_sw); + } + cc += 1 + IMM2_SIZE; + break; + + case OP_CLASS: + case OP_NCLASS: +#if defined SUPPORT_UNICODE || PCRE2_CODE_UNIT_WIDTH != 8 + case OP_XCLASS: + i = (*cc == OP_XCLASS) ? GET(cc, 1) : 1 + 32 / (int)sizeof(PCRE2_UCHAR); +#else + i = 1 + 32 / (int)sizeof(PCRE2_UCHAR); +#endif + if (PRIVATE_DATA(cc) != 0) + switch(get_class_iterator_size(cc + i)) + { + case 1: + private_count = 1; + private_srcw[0] = PRIVATE_DATA(cc); + break; + + case 2: + private_count = 2; + private_srcw[0] = PRIVATE_DATA(cc); + private_srcw[1] = private_srcw[0] + sizeof(sljit_sw); + break; + + default: + SLJIT_UNREACHABLE(); + break; + } + cc += i; + break; + + case OP_MARK: + case OP_PRUNE_ARG: + case OP_THEN_ARG: + SLJIT_ASSERT(common->mark_ptr != 0); + if (has_quit && !setmark_found) + { + kept_shared_srcw[0] = common->mark_ptr; + kept_shared_count = 1; + setmark_found = TRUE; + } + if (common->control_head_ptr != 0 && !control_head_found) + { + shared_srcw[0] = common->control_head_ptr; + shared_count = 1; + control_head_found = TRUE; + } + cc += 1 + 2 + cc[1]; + break; + + case OP_THEN: + SLJIT_ASSERT(common->control_head_ptr != 0); + if (!control_head_found) + { + shared_srcw[0] = common->control_head_ptr; + shared_count = 1; + control_head_found = TRUE; + } + cc++; + break; + + default: + cc = next_opcode(common, cc); + SLJIT_ASSERT(cc != NULL); + break; + } + + if (type != recurse_copy_shared_to_global && type != recurse_copy_kept_shared_to_global) + { + SLJIT_ASSERT(type == recurse_copy_from_global || type == recurse_copy_private_to_global || type == recurse_swap_global); + + for (i = 0; i < private_count; i++) { - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackptr, TMP2, 0); + SLJIT_ASSERT(private_srcw[i] != 0); + + if (!from_sp) + delayed_mem_copy_move(&status, base_reg, stackptr, SLJIT_SP, private_srcw[i]); + + if (from_sp || type == recurse_swap_global) + delayed_mem_copy_move(&status, SLJIT_SP, private_srcw[i], base_reg, stackptr); + stackptr += sizeof(sljit_sw); } } else + stackptr += sizeof(sljit_sw) * private_count; + + if (type != recurse_copy_private_to_global && type != recurse_copy_kept_shared_to_global) { - if (!tmp2empty) + SLJIT_ASSERT(type == recurse_copy_from_global || type == recurse_copy_shared_to_global || type == recurse_swap_global); + + for (i = 0; i < shared_count; i++) { - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackptr, TMP2, 0); + SLJIT_ASSERT(shared_srcw[i] != 0); + + if (!from_sp) + delayed_mem_copy_move(&status, base_reg, stackptr, SLJIT_SP, shared_srcw[i]); + + if (from_sp || type == recurse_swap_global) + delayed_mem_copy_move(&status, SLJIT_SP, shared_srcw[i], base_reg, stackptr); + stackptr += sizeof(sljit_sw); } - if (!tmp1empty) + } + else + stackptr += sizeof(sljit_sw) * shared_count; + + if (type != recurse_copy_private_to_global && type != recurse_swap_global) + { + SLJIT_ASSERT(type == recurse_copy_from_global || type == recurse_copy_shared_to_global || type == recurse_copy_kept_shared_to_global); + + for (i = 0; i < kept_shared_count; i++) { - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackptr, TMP1, 0); + SLJIT_ASSERT(kept_shared_srcw[i] != 0); + + if (!from_sp) + delayed_mem_copy_move(&status, base_reg, stackptr, SLJIT_SP, kept_shared_srcw[i]); + + if (from_sp || type == recurse_swap_global) + delayed_mem_copy_move(&status, SLJIT_SP, kept_shared_srcw[i], base_reg, stackptr); + stackptr += sizeof(sljit_sw); } } + else + stackptr += sizeof(sljit_sw) * kept_shared_count; } -SLJIT_ASSERT(cc == ccend && stackptr == stacktop && (save || (tmp1empty && tmp2empty))); + +SLJIT_ASSERT(cc == ccend && stackptr == stacktop); + +delayed_mem_copy_finish(&status); } static SLJIT_INLINE PCRE2_SPTR set_then_offsets(compiler_common *common, PCRE2_SPTR cc, sljit_u8 *current_offset) @@ -2339,7 +2631,7 @@ static SLJIT_INLINE void count_match(compiler_common *common) { DEFINE_COMPILER; -OP2(SLJIT_SUB | SLJIT_SET_E, COUNT_MATCH, 0, COUNT_MATCH, 0, SLJIT_IMM, 1); +OP2(SLJIT_SUB | SLJIT_SET_Z, COUNT_MATCH, 0, COUNT_MATCH, 0, SLJIT_IMM, 1); add_jump(compiler, &common->calllimit, JUMP(SLJIT_ZERO)); } @@ -2349,7 +2641,7 @@ static SLJIT_INLINE void allocate_stack(compiler_common *common, int size) DEFINE_COMPILER; SLJIT_ASSERT(size > 0); -OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, size * sizeof(sljit_sw)); +OP2(SLJIT_SUB, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, size * sizeof(sljit_sw)); #ifdef DESTROY_REGISTERS OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, 12345); OP1(SLJIT_MOV, TMP3, 0, TMP1, 0); @@ -2357,7 +2649,7 @@ OP1(SLJIT_MOV, RETURN_ADDR, 0, TMP1, 0); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LOCALS0, TMP1, 0); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LOCALS1, TMP1, 0); #endif -add_stub(common, CMP(SLJIT_GREATER, STACK_TOP, 0, STACK_LIMIT, 0)); +add_stub(common, CMP(SLJIT_LESS, STACK_TOP, 0, STACK_LIMIT, 0)); } static SLJIT_INLINE void free_stack(compiler_common *common, int size) @@ -2365,7 +2657,7 @@ static SLJIT_INLINE void free_stack(compiler_common *common, int size) DEFINE_COMPILER; SLJIT_ASSERT(size > 0); -OP2(SLJIT_SUB, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, size * sizeof(sljit_sw)); +OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, size * sizeof(sljit_sw)); } static sljit_uw * allocate_read_only_data(compiler_common *common, sljit_uw size) @@ -2409,7 +2701,7 @@ else OP1(SLJIT_MOV, SLJIT_R2, 0, SLJIT_IMM, length - 1); loop = LABEL(); OP1(SLJIT_MOVU, SLJIT_MEM1(SLJIT_R1), sizeof(sljit_sw), SLJIT_R0, 0); - OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_R2, 0, SLJIT_R2, 0, SLJIT_IMM, 1); + OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_R2, 0, SLJIT_R2, 0, SLJIT_IMM, 1); JUMPTO(SLJIT_NOT_ZERO, loop); } } @@ -2447,7 +2739,7 @@ else OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_IMM, length - 2); loop = LABEL(); OP1(SLJIT_MOVU, SLJIT_MEM1(TMP2), sizeof(sljit_sw), TMP1, 0); - OP2(SLJIT_SUB | SLJIT_SET_E, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, 1); + OP2(SLJIT_SUB | SLJIT_SET_Z, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, 1); JUMPTO(SLJIT_NOT_ZERO, loop); } @@ -2465,22 +2757,22 @@ static sljit_sw SLJIT_CALL do_search_mark(sljit_sw *current, PCRE2_SPTR skip_arg { while (current != NULL) { - switch (current[-2]) + switch (current[1]) { case type_then_trap: break; case type_mark: - if (PRIV(strcmp)(skip_arg, (PCRE2_SPTR)current[-3]) == 0) - return current[-4]; + if (PRIV(strcmp)(skip_arg, (PCRE2_SPTR)current[2]) == 0) + return current[3]; break; default: - SLJIT_ASSERT_STOP(); + SLJIT_UNREACHABLE(); break; } - SLJIT_ASSERT(current > (sljit_sw*)current[-1]); - current = (sljit_sw*)current[-1]; + SLJIT_ASSERT(current[0] == 0 || current < (sljit_sw*)current[0]); + current = (sljit_sw*)current[0]; } return -1; } @@ -2520,7 +2812,7 @@ if (sizeof(PCRE2_SIZE) == 4) OP1(SLJIT_MOVU_U32, SLJIT_MEM1(SLJIT_R2), sizeof(PCRE2_SIZE), SLJIT_S1, 0); else OP1(SLJIT_MOVU, SLJIT_MEM1(SLJIT_R2), sizeof(PCRE2_SIZE), SLJIT_S1, 0); -OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_R1, 0, SLJIT_R1, 0, SLJIT_IMM, 1); +OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_R1, 0, SLJIT_R1, 0, SLJIT_IMM, 1); JUMPTO(SLJIT_NOT_ZERO, loop); /* Calculate the return value, which is the maximum ovector value. */ @@ -3106,8 +3398,8 @@ if (common->utf) OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); /* Skip low surrogate if necessary. */ OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xfc00); - OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0xdc00); - OP_FLAGS(SLJIT_MOV, TMP1, 0, SLJIT_UNUSED, 0, SLJIT_EQUAL); + OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0xdc00); + OP_FLAGS(SLJIT_MOV, TMP1, 0, SLJIT_EQUAL); OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, 1); OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, TMP1, 0); return; @@ -3126,6 +3418,7 @@ struct sljit_jump *jump; if (nltype == NLTYPE_ANY) { add_jump(compiler, &common->anynewline, JUMP(SLJIT_FAST_CALL)); + sljit_set_current_flags(compiler, SLJIT_SET_Z); add_jump(compiler, backtracks, JUMP(jumpifmatch ? SLJIT_NOT_ZERO : SLJIT_ZERO)); } else if (nltype == NLTYPE_ANYCRLF) @@ -3167,7 +3460,7 @@ OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, 0x3f); OP2(SLJIT_OR, TMP1, 0, TMP1, 0, TMP2, 0); /* Searching for the first zero. */ -OP2(SLJIT_AND | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x800); +OP2(SLJIT_AND | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x800); jump = JUMP(SLJIT_NOT_ZERO); /* Two byte sequence. */ OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); @@ -3181,7 +3474,7 @@ OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, 6); OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, 0x3f); OP2(SLJIT_OR, TMP1, 0, TMP1, 0, TMP2, 0); -OP2(SLJIT_AND | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x10000); +OP2(SLJIT_AND | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x10000); jump = JUMP(SLJIT_NOT_ZERO); /* Three byte sequence. */ OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(2)); @@ -3215,15 +3508,15 @@ OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, 0x3f); OP2(SLJIT_OR, TMP1, 0, TMP1, 0, TMP2, 0); /* Searching for the first zero. */ -OP2(SLJIT_AND | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x800); +OP2(SLJIT_AND | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x800); jump = JUMP(SLJIT_NOT_ZERO); /* Two byte sequence. */ OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); sljit_emit_fast_return(compiler, RETURN_ADDR, 0); JUMPHERE(jump); -OP2(SLJIT_AND | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x400); -OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_UNUSED, 0, SLJIT_NOT_ZERO); +OP2(SLJIT_AND | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x400); +OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_NOT_ZERO); /* This code runs only in 8 bit mode. No need to shift the value. */ OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP2, 0); OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(1)); @@ -3246,7 +3539,7 @@ struct sljit_jump *compare; sljit_emit_fast_enter(compiler, RETURN_ADDR, 0); -OP2(SLJIT_AND | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP2, 0, SLJIT_IMM, 0x20); +OP2(SLJIT_AND | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP2, 0, SLJIT_IMM, 0x20); jump = JUMP(SLJIT_NOT_ZERO); /* Two byte sequence. */ OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0)); @@ -3283,10 +3576,30 @@ static void do_getucd(compiler_common *common) /* Search the UCD record for the character comes in TMP1. Returns chartype in TMP1 and UCD offset in TMP2. */ DEFINE_COMPILER; +#if PCRE2_CODE_UNIT_WIDTH == 32 +struct sljit_jump *jump; +#endif + +#if defined SLJIT_DEBUG && SLJIT_DEBUG +/* dummy_ucd_record */ +const ucd_record *record = GET_UCD(INVALID_UTF_CHAR); +SLJIT_ASSERT(record->script == ucp_Common && record->chartype == ucp_Cn && record->gbprop == ucp_gbOther); +SLJIT_ASSERT(record->caseset == 0 && record->other_case == 0); +#endif SLJIT_ASSERT(UCD_BLOCK_SIZE == 128 && sizeof(ucd_record) == 8); sljit_emit_fast_enter(compiler, RETURN_ADDR, 0); + +#if PCRE2_CODE_UNIT_WIDTH == 32 +if (!common->utf) + { + jump = CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, MAX_UTF_CODE_POINT + 1); + OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, INVALID_UTF_CHAR); + JUMPHERE(jump); + } +#endif + OP2(SLJIT_LSHR, TMP2, 0, TMP1, 0, SLJIT_IMM, UCD_BLOCK_SHIFT); OP1(SLJIT_MOV_U8, TMP2, 0, SLJIT_MEM1(TMP2), (sljit_sw)PRIV(ucd_stage1)); OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, UCD_BLOCK_MASK); @@ -3301,7 +3614,7 @@ sljit_emit_fast_return(compiler, RETURN_ADDR, 0); #endif /* SUPPORT_UNICODE */ -static SLJIT_INLINE struct sljit_label *mainloop_entry(compiler_common *common, BOOL hascrorlf, sljit_u32 overall_options) +static SLJIT_INLINE struct sljit_label *mainloop_entry(compiler_common *common) { DEFINE_COMPILER; struct sljit_label *mainloop; @@ -3313,6 +3626,8 @@ struct sljit_jump *end2 = NULL; struct sljit_jump *singlechar; #endif jump_list *newline = NULL; +sljit_u32 overall_options = common->re->overall_options; +BOOL hascrorlf = (common->re->flags & PCRE2_HASCRORLF) != 0; BOOL newlinecheck = FALSE; BOOL readuchar = FALSE; @@ -3320,7 +3635,7 @@ if (!(hascrorlf || (overall_options & PCRE2_FIRSTLINE) != 0) && (common->nltype == NLTYPE_ANY || common->nltype == NLTYPE_ANYCRLF || common->newline > 255)) newlinecheck = TRUE; -SLJIT_ASSERT(common->forced_quit_label == NULL); +SLJIT_ASSERT(common->abort_label == NULL); if ((overall_options & PCRE2_FIRSTLINE) != 0) { @@ -3377,7 +3692,7 @@ else if ((overall_options & PCRE2_USE_OFFSET_LIMIT) != 0) OP1(SLJIT_MOV, TMP2, 0, STR_END, 0); JUMPHERE(end2); OP1(SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_IMM, PCRE2_ERROR_NOMATCH); - add_jump(compiler, &common->forced_quit, CMP(SLJIT_LESS, TMP2, 0, STR_PTR, 0)); + add_jump(compiler, &common->abort, CMP(SLJIT_LESS, TMP2, 0, STR_PTR, 0)); JUMPHERE(end); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->match_end_ptr, TMP2, 0); } @@ -3390,8 +3705,8 @@ if (newlinecheck) OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); end = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0); OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), 0); - OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, common->newline & 0xff); - OP_FLAGS(SLJIT_MOV, TMP1, 0, SLJIT_UNUSED, 0, SLJIT_EQUAL); + OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, common->newline & 0xff); + OP_FLAGS(SLJIT_MOV, TMP1, 0, SLJIT_EQUAL); #if PCRE2_CODE_UNIT_WIDTH == 16 || PCRE2_CODE_UNIT_WIDTH == 32 OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, UCHAR_SHIFT); #endif @@ -3428,8 +3743,8 @@ if (common->utf) { singlechar = CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, 0xd800); OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xfc00); - OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0xd800); - OP_FLAGS(SLJIT_MOV, TMP1, 0, SLJIT_UNUSED, 0, SLJIT_EQUAL); + OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0xd800); + OP_FLAGS(SLJIT_MOV, TMP1, 0, SLJIT_EQUAL); OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, 1); OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0); JUMPHERE(singlechar); @@ -3447,40 +3762,42 @@ if (newlinecheck) return mainloop; } -#define MAX_N_CHARS 16 -#define MAX_DIFF_CHARS 6 -static SLJIT_INLINE void add_prefix_char(PCRE2_UCHAR chr, PCRE2_UCHAR *chars) +static SLJIT_INLINE void add_prefix_char(PCRE2_UCHAR chr, fast_forward_char_data *chars, BOOL last) { -PCRE2_UCHAR i, len; +sljit_u32 i, count = chars->count; -len = chars[0]; -if (len == 255) +if (count == 255) return; -if (len == 0) +if (count == 0) { - chars[0] = 1; - chars[1] = chr; + chars->count = 1; + chars->chars[0] = chr; + + if (last) + chars->last_count = 1; return; } -for (i = len; i > 0; i--) - if (chars[i] == chr) +for (i = 0; i < count; i++) + if (chars->chars[i] == chr) return; -if (len >= MAX_DIFF_CHARS - 1) +if (count >= MAX_DIFF_CHARS) { - chars[0] = 255; + chars->count = 255; return; } -len++; -chars[len] = chr; -chars[0] = len; +chars->chars[count] = chr; +chars->count = count + 1; + +if (last) + chars->last_count++; } -static int scan_prefix(compiler_common *common, PCRE2_SPTR cc, PCRE2_UCHAR *chars, int max_chars, sljit_u32 *rec_count) +static int scan_prefix(compiler_common *common, PCRE2_SPTR cc, fast_forward_char_data *chars, int max_chars, sljit_u32 *rec_count) { /* Recursive function, which scans prefix literals. */ BOOL last, any, class, caseless; @@ -3489,7 +3806,7 @@ sljit_u32 chr; /* Any unicode character. */ sljit_u8 *bytes, *bytes_end, byte; PCRE2_SPTR alternative, cc_save, oc; #if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8 -PCRE2_UCHAR othercase[8]; +PCRE2_UCHAR othercase[4]; #elif defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 16 PCRE2_UCHAR othercase[2]; #else @@ -3512,6 +3829,7 @@ while (TRUE) { case OP_CHARI: caseless = TRUE; + /* Fall through */ case OP_CHAR: last = FALSE; cc++; @@ -3543,6 +3861,7 @@ while (TRUE) case OP_MINPLUSI: case OP_POSPLUSI: caseless = TRUE; + /* Fall through */ case OP_PLUS: case OP_MINPLUS: case OP_POSPLUS: @@ -3551,6 +3870,7 @@ while (TRUE) case OP_EXACTI: caseless = TRUE; + /* Fall through */ case OP_EXACT: repeat = GET2(cc, 1); last = FALSE; @@ -3561,6 +3881,7 @@ while (TRUE) case OP_MINQUERYI: case OP_POSQUERYI: caseless = TRUE; + /* Fall through */ case OP_QUERY: case OP_MINQUERY: case OP_POSQUERY: @@ -3584,7 +3905,6 @@ while (TRUE) continue; case OP_ONCE: - case OP_ONCE_NC: case OP_BRA: case OP_BRAPOS: case OP_CBRA: @@ -3705,12 +4025,12 @@ while (TRUE) { do { - chars[0] = 255; + chars->count = 255; consumed++; if (--max_chars == 0) return consumed; - chars += MAX_DIFF_CHARS; + chars++; } while (--repeat > 0); @@ -3754,8 +4074,8 @@ while (TRUE) do { if (bytes[31] & 0x80) - chars[0] = 255; - else if (chars[0] != 255) + chars->count = 255; + else if (chars->count != 255) { bytes_end = bytes + 32; chr = 0; @@ -3770,7 +4090,7 @@ while (TRUE) do { if ((byte & 0x1) != 0) - add_prefix_char(chr, chars); + add_prefix_char(chr, chars, TRUE); byte >>= 1; chr++; } @@ -3778,14 +4098,14 @@ while (TRUE) chr = (chr + 7) & ~7; } } - while (chars[0] != 255 && bytes < bytes_end); + while (chars->count != 255 && bytes < bytes_end); bytes = bytes_end - 32; } consumed++; if (--max_chars == 0) return consumed; - chars += MAX_DIFF_CHARS; + chars++; } while (--repeat > 0); @@ -3849,17 +4169,18 @@ while (TRUE) oc = othercase; do { + len--; + consumed++; + chr = *cc; - add_prefix_char(*cc, chars); + add_prefix_char(*cc, chars, len == 0); if (caseless) - add_prefix_char(*oc, chars); + add_prefix_char(*oc, chars, len == 0); - len--; - consumed++; if (--max_chars == 0) return consumed; - chars += MAX_DIFF_CHARS; + chars++; cc++; oc++; } @@ -3878,7 +4199,37 @@ while (TRUE) } } -#if (defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86) +#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32 +static void jumpto_if_not_utf_char_start(struct sljit_compiler *compiler, sljit_s32 reg, struct sljit_label *label) +{ +#if PCRE2_CODE_UNIT_WIDTH == 8 +OP2(SLJIT_AND, reg, 0, reg, 0, SLJIT_IMM, 0xc0); +CMPTO(SLJIT_EQUAL, reg, 0, SLJIT_IMM, 0x80, label); +#elif PCRE2_CODE_UNIT_WIDTH == 16 +OP2(SLJIT_AND, reg, 0, reg, 0, SLJIT_IMM, 0xfc00); +CMPTO(SLJIT_EQUAL, reg, 0, SLJIT_IMM, 0xdc00, label); +#else +#error "Unknown code width" +#endif +} +#endif + +#if (defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86) && !(defined SUPPORT_VALGRIND) + +#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32 +static struct sljit_jump *jump_if_utf_char_start(struct sljit_compiler *compiler, sljit_s32 reg) +{ +#if PCRE2_CODE_UNIT_WIDTH == 8 +OP2(SLJIT_AND, reg, 0, reg, 0, SLJIT_IMM, 0xc0); +return CMP(SLJIT_NOT_EQUAL, reg, 0, SLJIT_IMM, 0x80); +#elif PCRE2_CODE_UNIT_WIDTH == 16 +OP2(SLJIT_AND, reg, 0, reg, 0, SLJIT_IMM, 0xfc00); +return CMP(SLJIT_NOT_EQUAL, reg, 0, SLJIT_IMM, 0xdc00); +#else +#error "Unknown code width" +#endif +} +#endif static sljit_s32 character_to_int32(PCRE2_UCHAR chr) { @@ -3897,264 +4248,665 @@ return value; #endif } -static SLJIT_INLINE void fast_forward_first_char2_sse2(compiler_common *common, PCRE2_UCHAR char1, PCRE2_UCHAR char2) +static void load_from_mem_sse2(struct sljit_compiler *compiler, sljit_s32 dst_xmm_reg, sljit_s32 src_general_reg) { -DEFINE_COMPILER; -struct sljit_label *start; -struct sljit_jump *quit[3]; -struct sljit_jump *nomatch; -sljit_u8 instruction[8]; -sljit_s32 tmp1_ind = sljit_get_register_index(TMP1); -sljit_s32 tmp2_ind = sljit_get_register_index(TMP2); -sljit_s32 str_ptr_ind = sljit_get_register_index(STR_PTR); -BOOL load_twice = FALSE; -PCRE2_UCHAR bit; - -bit = char1 ^ char2; -if (!is_powerof2(bit)) - bit = 0; - -if ((char1 != char2) && bit == 0) - load_twice = TRUE; - -quit[0] = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0); - -/* First part (unaligned start) */ - -OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, character_to_int32(char1 | bit)); - -SLJIT_ASSERT(tmp1_ind < 8 && tmp2_ind == 1); - -/* MOVD xmm, r/m32 */ -instruction[0] = 0x66; -instruction[1] = 0x0f; -instruction[2] = 0x6e; -instruction[3] = 0xc0 | (2 << 3) | tmp1_ind; -sljit_emit_op_custom(compiler, instruction, 4); - -if (char1 != char2) - { - OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, character_to_int32(bit != 0 ? bit : char2)); - - /* MOVD xmm, r/m32 */ - instruction[3] = 0xc0 | (3 << 3) | tmp1_ind; - sljit_emit_op_custom(compiler, instruction, 4); - } - -/* PSHUFD xmm1, xmm2/m128, imm8 */ -instruction[2] = 0x70; -instruction[3] = 0xc0 | (2 << 3) | 2; -instruction[4] = 0; -sljit_emit_op_custom(compiler, instruction, 5); - -if (char1 != char2) - { - /* PSHUFD xmm1, xmm2/m128, imm8 */ - instruction[3] = 0xc0 | (3 << 3) | 3; - instruction[4] = 0; - sljit_emit_op_custom(compiler, instruction, 5); - } +#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) +sljit_u8 instruction[5]; +#else +sljit_u8 instruction[4]; +#endif -OP2(SLJIT_AND, TMP2, 0, STR_PTR, 0, SLJIT_IMM, 0xf); -OP2(SLJIT_AND, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, ~0xf); +SLJIT_ASSERT(dst_xmm_reg < 8); /* MOVDQA xmm1, xmm2/m128 */ #if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) - -if (str_ptr_ind < 8) +if (src_general_reg < 8) { + instruction[0] = 0x66; + instruction[1] = 0x0f; instruction[2] = 0x6f; - instruction[3] = (0 << 3) | str_ptr_ind; + instruction[3] = (dst_xmm_reg << 3) | src_general_reg; sljit_emit_op_custom(compiler, instruction, 4); - - if (load_twice) - { - instruction[3] = (1 << 3) | str_ptr_ind; - sljit_emit_op_custom(compiler, instruction, 4); - } } else { + instruction[0] = 0x66; instruction[1] = 0x41; instruction[2] = 0x0f; instruction[3] = 0x6f; - instruction[4] = (0 << 3) | (str_ptr_ind & 0x7); - sljit_emit_op_custom(compiler, instruction, 5); - - if (load_twice) - { - instruction[4] = (1 << 3) | str_ptr_ind; - sljit_emit_op_custom(compiler, instruction, 5); - } - instruction[1] = 0x0f; + instruction[4] = (dst_xmm_reg << 3) | (src_general_reg & 0x7); + sljit_emit_op_custom(compiler, instruction, 4); } - #else - +instruction[0] = 0x66; +instruction[1] = 0x0f; instruction[2] = 0x6f; -instruction[3] = (0 << 3) | str_ptr_ind; +instruction[3] = (dst_xmm_reg << 3) | src_general_reg; sljit_emit_op_custom(compiler, instruction, 4); +#endif +} -if (load_twice) +static void fast_forward_char_pair_sse2_compare(struct sljit_compiler *compiler, PCRE2_UCHAR char1, PCRE2_UCHAR char2, + sljit_u32 bit, sljit_s32 dst_ind, sljit_s32 cmp1_ind, sljit_s32 cmp2_ind, sljit_s32 tmp_ind) +{ +sljit_u8 instruction[4]; +instruction[0] = 0x66; +instruction[1] = 0x0f; + +if (char1 == char2 || bit != 0) { - instruction[3] = (1 << 3) | str_ptr_ind; + if (bit != 0) + { + /* POR xmm1, xmm2/m128 */ + /* instruction[0] = 0x66; */ + /* instruction[1] = 0x0f; */ + instruction[2] = 0xeb; + instruction[3] = 0xc0 | (dst_ind << 3) | cmp2_ind; + sljit_emit_op_custom(compiler, instruction, 4); + } + + /* PCMPEQB/W/D xmm1, xmm2/m128 */ + /* instruction[0] = 0x66; */ + /* instruction[1] = 0x0f; */ + instruction[2] = 0x74 + SSE2_COMPARE_TYPE_INDEX; + instruction[3] = 0xc0 | (dst_ind << 3) | cmp1_ind; sljit_emit_op_custom(compiler, instruction, 4); } +else + { + /* MOVDQA xmm1, xmm2/m128 */ + /* instruction[0] = 0x66; */ + /* instruction[1] = 0x0f; */ + instruction[2] = 0x6f; + instruction[3] = 0xc0 | (tmp_ind << 3) | dst_ind; + sljit_emit_op_custom(compiler, instruction, 4); -#endif + /* PCMPEQB/W/D xmm1, xmm2/m128 */ + /* instruction[0] = 0x66; */ + /* instruction[1] = 0x0f; */ + instruction[2] = 0x74 + SSE2_COMPARE_TYPE_INDEX; + instruction[3] = 0xc0 | (dst_ind << 3) | cmp1_ind; + sljit_emit_op_custom(compiler, instruction, 4); + + instruction[3] = 0xc0 | (tmp_ind << 3) | cmp2_ind; + sljit_emit_op_custom(compiler, instruction, 4); -if (bit != 0) - { /* POR xmm1, xmm2/m128 */ + /* instruction[0] = 0x66; */ + /* instruction[1] = 0x0f; */ instruction[2] = 0xeb; - instruction[3] = 0xc0 | (0 << 3) | 3; + instruction[3] = 0xc0 | (dst_ind << 3) | tmp_ind; sljit_emit_op_custom(compiler, instruction, 4); } +} -/* PCMPEQB/W/D xmm1, xmm2/m128 */ -instruction[2] = 0x74 + SSE2_COMPARE_TYPE_INDEX; -instruction[3] = 0xc0 | (0 << 3) | 2; -sljit_emit_op_custom(compiler, instruction, 4); +static void fast_forward_first_char2_sse2(compiler_common *common, PCRE2_UCHAR char1, PCRE2_UCHAR char2, sljit_s32 offset) +{ +DEFINE_COMPILER; +struct sljit_label *start; +#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32 +struct sljit_label *restart; +#endif +struct sljit_jump *quit; +struct sljit_jump *partial_quit[2]; +sljit_u8 instruction[8]; +sljit_s32 tmp1_ind = sljit_get_register_index(TMP1); +// sljit_s32 tmp2_ind = sljit_get_register_index(TMP2); +sljit_s32 str_ptr_ind = sljit_get_register_index(STR_PTR); +sljit_s32 data_ind = 0; +sljit_s32 tmp_ind = 1; +sljit_s32 cmp1_ind = 2; +sljit_s32 cmp2_ind = 3; +sljit_u32 bit = 0; + +SLJIT_UNUSED_ARG(offset); -if (load_twice) +if (char1 != char2) { - instruction[3] = 0xc0 | (1 << 3) | 3; - sljit_emit_op_custom(compiler, instruction, 4); + bit = char1 ^ char2; + if (!is_powerof2(bit)) + bit = 0; } -/* PMOVMSKB reg, xmm */ -instruction[2] = 0xd7; -instruction[3] = 0xc0 | (tmp1_ind << 3) | 0; +partial_quit[0] = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0); +if (common->mode == PCRE2_JIT_COMPLETE) + add_jump(compiler, &common->failed_match, partial_quit[0]); + +/* First part (unaligned start) */ + +OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, character_to_int32(char1 | bit)); + +// SLJIT_ASSERT(tmp1_ind < 8 && tmp2_ind == 1); + +SLJIT_ASSERT(tmp1_ind < 8); + +/* MOVD xmm, r/m32 */ +instruction[0] = 0x66; +instruction[1] = 0x0f; +instruction[2] = 0x6e; +instruction[3] = 0xc0 | (cmp1_ind << 3) | tmp1_ind; sljit_emit_op_custom(compiler, instruction, 4); -if (load_twice) +if (char1 != char2) { - OP1(SLJIT_MOV, RETURN_ADDR, 0, TMP2, 0); - instruction[3] = 0xc0 | (tmp2_ind << 3) | 1; + OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, character_to_int32(bit != 0 ? bit : char2)); + + /* MOVD xmm, r/m32 */ + instruction[3] = 0xc0 | (cmp2_ind << 3) | tmp1_ind; sljit_emit_op_custom(compiler, instruction, 4); + } - OP2(SLJIT_OR, TMP1, 0, TMP1, 0, TMP2, 0); - OP1(SLJIT_MOV, TMP2, 0, RETURN_ADDR, 0); +OP1(SLJIT_MOV, TMP2, 0, STR_PTR, 0); + +/* PSHUFD xmm1, xmm2/m128, imm8 */ +/* instruction[0] = 0x66; */ +/* instruction[1] = 0x0f; */ +instruction[2] = 0x70; +instruction[3] = 0xc0 | (cmp1_ind << 3) | 2; +instruction[4] = 0; +sljit_emit_op_custom(compiler, instruction, 5); + +if (char1 != char2) + { + /* PSHUFD xmm1, xmm2/m128, imm8 */ + instruction[3] = 0xc0 | (cmp2_ind << 3) | 3; + sljit_emit_op_custom(compiler, instruction, 5); } -OP2(SLJIT_ASHR, TMP1, 0, TMP1, 0, TMP2, 0); +#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32 +restart = LABEL(); +#endif +OP2(SLJIT_AND, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, ~0xf); +OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, 0xf); + +load_from_mem_sse2(compiler, data_ind, str_ptr_ind); +fast_forward_char_pair_sse2_compare(compiler, char1, char2, bit, data_ind, cmp1_ind, cmp2_ind, tmp_ind); + +/* PMOVMSKB reg, xmm */ +/* instruction[0] = 0x66; */ +/* instruction[1] = 0x0f; */ +instruction[2] = 0xd7; +instruction[3] = 0xc0 | (tmp1_ind << 3) | 0; +sljit_emit_op_custom(compiler, instruction, 4); + +OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP2, 0); +OP2(SLJIT_LSHR, TMP1, 0, TMP1, 0, TMP2, 0); /* BSF r32, r/m32 */ instruction[0] = 0x0f; instruction[1] = 0xbc; instruction[2] = 0xc0 | (tmp1_ind << 3) | tmp1_ind; sljit_emit_op_custom(compiler, instruction, 3); +sljit_set_current_flags(compiler, SLJIT_SET_Z); -nomatch = JUMP(SLJIT_ZERO); - -OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP2, 0); -OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0); -quit[1] = JUMP(SLJIT_JUMP); +quit = JUMP(SLJIT_NOT_ZERO); -JUMPHERE(nomatch); +OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, TMP2, 0); start = LABEL(); OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, 16); -quit[2] = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0); + +partial_quit[1] = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0); +if (common->mode == PCRE2_JIT_COMPLETE) + add_jump(compiler, &common->failed_match, partial_quit[1]); /* Second part (aligned) */ +load_from_mem_sse2(compiler, 0, str_ptr_ind); +fast_forward_char_pair_sse2_compare(compiler, char1, char2, bit, data_ind, cmp1_ind, cmp2_ind, tmp_ind); + +/* PMOVMSKB reg, xmm */ instruction[0] = 0x66; instruction[1] = 0x0f; +instruction[2] = 0xd7; +instruction[3] = 0xc0 | (tmp1_ind << 3) | 0; +sljit_emit_op_custom(compiler, instruction, 4); -/* MOVDQA xmm1, xmm2/m128 */ -#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) +/* BSF r32, r/m32 */ +instruction[0] = 0x0f; +instruction[1] = 0xbc; +instruction[2] = 0xc0 | (tmp1_ind << 3) | tmp1_ind; +sljit_emit_op_custom(compiler, instruction, 3); +sljit_set_current_flags(compiler, SLJIT_SET_Z); + +JUMPTO(SLJIT_ZERO, start); + +JUMPHERE(quit); +OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0); -if (str_ptr_ind < 8) +if (common->mode != PCRE2_JIT_COMPLETE) { - instruction[2] = 0x6f; - instruction[3] = (0 << 3) | str_ptr_ind; - sljit_emit_op_custom(compiler, instruction, 4); + JUMPHERE(partial_quit[0]); + JUMPHERE(partial_quit[1]); + OP2(SLJIT_SUB | SLJIT_SET_GREATER, SLJIT_UNUSED, 0, STR_PTR, 0, STR_END, 0); + CMOV(SLJIT_GREATER, STR_PTR, STR_END, 0); + } +else + add_jump(compiler, &common->failed_match, CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0)); + +#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32 +if (common->utf && offset > 0) + { + SLJIT_ASSERT(common->mode == PCRE2_JIT_COMPLETE); + + OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-offset)); + + quit = jump_if_utf_char_start(compiler, TMP1); + + OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); + add_jump(compiler, &common->failed_match, CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0)); + OP1(SLJIT_MOV, TMP2, 0, STR_PTR, 0); + JUMPTO(SLJIT_JUMP, restart); + + JUMPHERE(quit); + } +#endif +} + +#ifndef _WIN64 + +static SLJIT_INLINE sljit_u32 max_fast_forward_char_pair_sse2_offset(void) +{ +#if PCRE2_CODE_UNIT_WIDTH == 8 +return 15; +#elif PCRE2_CODE_UNIT_WIDTH == 16 +return 7; +#elif PCRE2_CODE_UNIT_WIDTH == 32 +return 3; +#else +#error "Unsupported unit width" +#endif +} + +static void fast_forward_char_pair_sse2(compiler_common *common, sljit_s32 offs1, + PCRE2_UCHAR char1a, PCRE2_UCHAR char1b, sljit_s32 offs2, PCRE2_UCHAR char2a, PCRE2_UCHAR char2b) +{ +DEFINE_COMPILER; +sljit_u32 bit1 = 0; +sljit_u32 bit2 = 0; +sljit_u32 diff = IN_UCHARS(offs1 - offs2); +sljit_s32 tmp1_ind = sljit_get_register_index(TMP1); +sljit_s32 tmp2_ind = sljit_get_register_index(TMP2); +sljit_s32 str_ptr_ind = sljit_get_register_index(STR_PTR); +sljit_s32 data1_ind = 0; +sljit_s32 data2_ind = 1; +sljit_s32 tmp_ind = 2; +sljit_s32 cmp1a_ind = 3; +sljit_s32 cmp1b_ind = 4; +sljit_s32 cmp2a_ind = 5; +sljit_s32 cmp2b_ind = 6; +struct sljit_label *start; +#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32 +struct sljit_label *restart; +#endif +struct sljit_jump *jump[2]; + +sljit_u8 instruction[8]; + +SLJIT_ASSERT(common->mode == PCRE2_JIT_COMPLETE && offs1 > offs2); +SLJIT_ASSERT(diff <= IN_UCHARS(max_fast_forward_char_pair_sse2_offset())); +SLJIT_ASSERT(tmp1_ind < 8 && tmp2_ind == 1); + +/* Initialize. */ +if (common->match_end_ptr != 0) + { + OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->match_end_ptr); + OP1(SLJIT_MOV, TMP3, 0, STR_END, 0); + OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, IN_UCHARS(offs1 + 1)); + + OP2(SLJIT_SUB | SLJIT_SET_LESS, SLJIT_UNUSED, 0, TMP1, 0, STR_END, 0); + CMOV(SLJIT_LESS, STR_END, TMP1, 0); + } - if (load_twice) +OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(offs1)); +add_jump(compiler, &common->failed_match, CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0)); + +/* MOVD xmm, r/m32 */ +instruction[0] = 0x66; +instruction[1] = 0x0f; +instruction[2] = 0x6e; + +if (char1a == char1b) + OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, character_to_int32(char1a)); +else + { + bit1 = char1a ^ char1b; + if (is_powerof2(bit1)) { - instruction[3] = (1 << 3) | str_ptr_ind; - sljit_emit_op_custom(compiler, instruction, 4); + OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, character_to_int32(char1a | bit1)); + OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, character_to_int32(bit1)); + } + else + { + bit1 = 0; + OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, character_to_int32(char1a)); + OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, character_to_int32(char1b)); } } -else + +instruction[3] = 0xc0 | (cmp1a_ind << 3) | tmp1_ind; +sljit_emit_op_custom(compiler, instruction, 4); + +if (char1a != char1b) { - instruction[1] = 0x41; - instruction[2] = 0x0f; - instruction[3] = 0x6f; - instruction[4] = (0 << 3) | (str_ptr_ind & 0x7); - sljit_emit_op_custom(compiler, instruction, 5); + instruction[3] = 0xc0 | (cmp1b_ind << 3) | tmp2_ind; + sljit_emit_op_custom(compiler, instruction, 4); + } - if (load_twice) +if (char2a == char2b) + OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, character_to_int32(char2a)); +else + { + bit2 = char2a ^ char2b; + if (is_powerof2(bit2)) { - instruction[4] = (1 << 3) | str_ptr_ind; - sljit_emit_op_custom(compiler, instruction, 5); + OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, character_to_int32(char2a | bit2)); + OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, character_to_int32(bit2)); + } + else + { + bit2 = 0; + OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, character_to_int32(char2a)); + OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, character_to_int32(char2b)); } - instruction[1] = 0x0f; } -#else - -instruction[2] = 0x6f; -instruction[3] = (0 << 3) | str_ptr_ind; +instruction[3] = 0xc0 | (cmp2a_ind << 3) | tmp1_ind; sljit_emit_op_custom(compiler, instruction, 4); -if (load_twice) +if (char2a != char2b) { - instruction[3] = (1 << 3) | str_ptr_ind; + instruction[3] = 0xc0 | (cmp2b_ind << 3) | tmp2_ind; sljit_emit_op_custom(compiler, instruction, 4); } -#endif +/* PSHUFD xmm1, xmm2/m128, imm8 */ +/* instruction[0] = 0x66; */ +/* instruction[1] = 0x0f; */ +instruction[2] = 0x70; +instruction[4] = 0; -if (bit != 0) +instruction[3] = 0xc0 | (cmp1a_ind << 3) | cmp1a_ind; +sljit_emit_op_custom(compiler, instruction, 5); + +if (char1a != char1b) { - /* POR xmm1, xmm2/m128 */ - instruction[2] = 0xeb; - instruction[3] = 0xc0 | (0 << 3) | 3; - sljit_emit_op_custom(compiler, instruction, 4); + instruction[3] = 0xc0 | (cmp1b_ind << 3) | cmp1b_ind; + sljit_emit_op_custom(compiler, instruction, 5); } -/* PCMPEQB/W/D xmm1, xmm2/m128 */ -instruction[2] = 0x74 + SSE2_COMPARE_TYPE_INDEX; -instruction[3] = 0xc0 | (0 << 3) | 2; -sljit_emit_op_custom(compiler, instruction, 4); +instruction[3] = 0xc0 | (cmp2a_ind << 3) | cmp2a_ind; +sljit_emit_op_custom(compiler, instruction, 5); -if (load_twice) +if (char2a != char2b) { - instruction[3] = 0xc0 | (1 << 3) | 3; - sljit_emit_op_custom(compiler, instruction, 4); + instruction[3] = 0xc0 | (cmp2b_ind << 3) | cmp2b_ind; + sljit_emit_op_custom(compiler, instruction, 5); } +#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32 +restart = LABEL(); +#endif + +OP2(SLJIT_SUB, TMP1, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(offs1 - offs2)); +OP1(SLJIT_MOV, TMP2, 0, STR_PTR, 0); +OP2(SLJIT_AND, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, ~0xf); +OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, ~0xf); + +load_from_mem_sse2(compiler, data1_ind, str_ptr_ind); + +jump[0] = CMP(SLJIT_EQUAL, STR_PTR, 0, TMP1, 0); + +load_from_mem_sse2(compiler, data2_ind, tmp1_ind); + +/* MOVDQA xmm1, xmm2/m128 */ +/* instruction[0] = 0x66; */ +/* instruction[1] = 0x0f; */ +instruction[2] = 0x6f; +instruction[3] = 0xc0 | (tmp_ind << 3) | data1_ind; +sljit_emit_op_custom(compiler, instruction, 4); + +/* PSLLDQ xmm1, xmm2/m128, imm8 */ +/* instruction[0] = 0x66; */ +/* instruction[1] = 0x0f; */ +instruction[2] = 0x73; +instruction[3] = 0xc0 | (7 << 3) | tmp_ind; +instruction[4] = diff; +sljit_emit_op_custom(compiler, instruction, 5); + +/* PSRLDQ xmm1, xmm2/m128, imm8 */ +/* instruction[0] = 0x66; */ +/* instruction[1] = 0x0f; */ +/* instruction[2] = 0x73; */ +instruction[3] = 0xc0 | (3 << 3) | data2_ind; +instruction[4] = 16 - diff; +sljit_emit_op_custom(compiler, instruction, 5); + +/* POR xmm1, xmm2/m128 */ +/* instruction[0] = 0x66; */ +/* instruction[1] = 0x0f; */ +instruction[2] = 0xeb; +instruction[3] = 0xc0 | (data2_ind << 3) | tmp_ind; +sljit_emit_op_custom(compiler, instruction, 4); + +jump[1] = JUMP(SLJIT_JUMP); + +JUMPHERE(jump[0]); + +/* MOVDQA xmm1, xmm2/m128 */ +/* instruction[0] = 0x66; */ +/* instruction[1] = 0x0f; */ +instruction[2] = 0x6f; +instruction[3] = 0xc0 | (data2_ind << 3) | data1_ind; +sljit_emit_op_custom(compiler, instruction, 4); + +/* PSLLDQ xmm1, xmm2/m128, imm8 */ +/* instruction[0] = 0x66; */ +/* instruction[1] = 0x0f; */ +instruction[2] = 0x73; +instruction[3] = 0xc0 | (7 << 3) | data2_ind; +instruction[4] = diff; +sljit_emit_op_custom(compiler, instruction, 5); + +JUMPHERE(jump[1]); + +OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, 0xf); + +fast_forward_char_pair_sse2_compare(compiler, char2a, char2b, bit2, data2_ind, cmp2a_ind, cmp2b_ind, tmp_ind); +fast_forward_char_pair_sse2_compare(compiler, char1a, char1b, bit1, data1_ind, cmp1a_ind, cmp1b_ind, tmp_ind); + +/* PAND xmm1, xmm2/m128 */ +/* instruction[0] = 0x66; */ +/* instruction[1] = 0x0f; */ +instruction[2] = 0xdb; +instruction[3] = 0xc0 | (data1_ind << 3) | data2_ind; +sljit_emit_op_custom(compiler, instruction, 4); + /* PMOVMSKB reg, xmm */ +/* instruction[0] = 0x66; */ +/* instruction[1] = 0x0f; */ instruction[2] = 0xd7; instruction[3] = 0xc0 | (tmp1_ind << 3) | 0; sljit_emit_op_custom(compiler, instruction, 4); -if (load_twice) - { - instruction[3] = 0xc0 | (tmp2_ind << 3) | 1; - sljit_emit_op_custom(compiler, instruction, 4); +/* Ignore matches before the first STR_PTR. */ +OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP2, 0); +OP2(SLJIT_LSHR, TMP1, 0, TMP1, 0, TMP2, 0); - OP2(SLJIT_OR, TMP1, 0, TMP1, 0, TMP2, 0); - } +/* BSF r32, r/m32 */ +instruction[0] = 0x0f; +instruction[1] = 0xbc; +instruction[2] = 0xc0 | (tmp1_ind << 3) | tmp1_ind; +sljit_emit_op_custom(compiler, instruction, 3); +sljit_set_current_flags(compiler, SLJIT_SET_Z); + +jump[0] = JUMP(SLJIT_NOT_ZERO); + +OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, TMP2, 0); + +/* Main loop. */ +instruction[0] = 0x66; +instruction[1] = 0x0f; + +start = LABEL(); + +load_from_mem_sse2(compiler, data2_ind, str_ptr_ind); + +OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, 16); +add_jump(compiler, &common->failed_match, CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0)); + +load_from_mem_sse2(compiler, data1_ind, str_ptr_ind); + +/* PSRLDQ xmm1, xmm2/m128, imm8 */ +/* instruction[0] = 0x66; */ +/* instruction[1] = 0x0f; */ +instruction[2] = 0x73; +instruction[3] = 0xc0 | (3 << 3) | data2_ind; +instruction[4] = 16 - diff; +sljit_emit_op_custom(compiler, instruction, 5); + +/* MOVDQA xmm1, xmm2/m128 */ +/* instruction[0] = 0x66; */ +/* instruction[1] = 0x0f; */ +instruction[2] = 0x6f; +instruction[3] = 0xc0 | (tmp_ind << 3) | data1_ind; +sljit_emit_op_custom(compiler, instruction, 4); + +/* PSLLDQ xmm1, xmm2/m128, imm8 */ +/* instruction[0] = 0x66; */ +/* instruction[1] = 0x0f; */ +instruction[2] = 0x73; +instruction[3] = 0xc0 | (7 << 3) | tmp_ind; +instruction[4] = diff; +sljit_emit_op_custom(compiler, instruction, 5); + +/* POR xmm1, xmm2/m128 */ +/* instruction[0] = 0x66; */ +/* instruction[1] = 0x0f; */ +instruction[2] = 0xeb; +instruction[3] = 0xc0 | (data2_ind << 3) | tmp_ind; +sljit_emit_op_custom(compiler, instruction, 4); + +fast_forward_char_pair_sse2_compare(compiler, char1a, char1b, bit1, data1_ind, cmp1a_ind, cmp1b_ind, tmp_ind); +fast_forward_char_pair_sse2_compare(compiler, char2a, char2b, bit2, data2_ind, cmp2a_ind, cmp2b_ind, tmp_ind); + +/* PAND xmm1, xmm2/m128 */ +/* instruction[0] = 0x66; */ +/* instruction[1] = 0x0f; */ +instruction[2] = 0xdb; +instruction[3] = 0xc0 | (data1_ind << 3) | data2_ind; +sljit_emit_op_custom(compiler, instruction, 4); + +/* PMOVMSKB reg, xmm */ +/* instruction[0] = 0x66; */ +/* instruction[1] = 0x0f; */ +instruction[2] = 0xd7; +instruction[3] = 0xc0 | (tmp1_ind << 3) | 0; +sljit_emit_op_custom(compiler, instruction, 4); /* BSF r32, r/m32 */ instruction[0] = 0x0f; instruction[1] = 0xbc; instruction[2] = 0xc0 | (tmp1_ind << 3) | tmp1_ind; sljit_emit_op_custom(compiler, instruction, 3); +sljit_set_current_flags(compiler, SLJIT_SET_Z); JUMPTO(SLJIT_ZERO, start); +JUMPHERE(jump[0]); + OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0); -start = LABEL(); -SET_LABEL(quit[0], start); -SET_LABEL(quit[1], start); -SET_LABEL(quit[2], start); +add_jump(compiler, &common->failed_match, CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0)); + +if (common->match_end_ptr != 0) + OP1(SLJIT_MOV, STR_END, 0, SLJIT_MEM1(SLJIT_SP), common->match_end_ptr); + +#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32 +if (common->utf) + { + OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-offs1)); + + jump[0] = jump_if_utf_char_start(compiler, TMP1); + + OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); + CMPTO(SLJIT_LESS, STR_PTR, 0, STR_END, 0, restart); + + add_jump(compiler, &common->failed_match, JUMP(SLJIT_JUMP)); + + JUMPHERE(jump[0]); + } +#endif + +OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(offs1)); + +if (common->match_end_ptr != 0) + OP1(SLJIT_MOV, STR_END, 0, TMP3, 0); +} + +static BOOL check_fast_forward_char_pair_sse2(compiler_common *common, fast_forward_char_data *chars, int max) +{ +sljit_s32 i, j, priority, count; +sljit_u32 priorities; +PCRE2_UCHAR a1, a2, b1, b2; + +priorities = 0; + +count = 0; +for (i = 0; i < max; i++) + { + if (chars[i].last_count > 2) + { + SLJIT_ASSERT(chars[i].last_count <= 7); + + priorities |= (1 << chars[i].last_count); + count++; + } + } + +if (count < 2) + return FALSE; + +for (priority = 7; priority > 2; priority--) + { + if ((priorities & (1 << priority)) == 0) + continue; + + for (i = max - 1; i >= 1; i--) + if (chars[i].last_count >= priority) + { + SLJIT_ASSERT(chars[i].count <= 2 && chars[i].count >= 1); + + a1 = chars[i].chars[0]; + a2 = chars[i].chars[1]; + + j = i - max_fast_forward_char_pair_sse2_offset(); + if (j < 0) + j = 0; + + while (j < i) + { + if (chars[j].last_count >= priority) + { + b1 = chars[j].chars[0]; + b2 = chars[j].chars[1]; + + if (a1 != b1 && a1 != b2 && a2 != b1 && a2 != b2) + { + fast_forward_char_pair_sse2(common, i, a1, a2, j, b1, b2); + return TRUE; + } + } + j++; + } + } + } + +return FALSE; } +#endif + #undef SSE2_COMPARE_TYPE_INDEX #endif @@ -4163,15 +4915,16 @@ static void fast_forward_first_char2(compiler_common *common, PCRE2_UCHAR char1, { DEFINE_COMPILER; struct sljit_label *start; -struct sljit_jump *quit; -struct sljit_jump *found; +struct sljit_jump *match; +struct sljit_jump *partial_quit; PCRE2_UCHAR mask; -#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32 -struct sljit_label *utf_start = NULL; -struct sljit_jump *utf_quit = NULL; -#endif BOOL has_match_end = (common->match_end_ptr != 0); +SLJIT_ASSERT(common->mode == PCRE2_JIT_COMPLETE || offset == 0); + +if (has_match_end) + OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->match_end_ptr); + if (offset > 0) OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(offset)); @@ -4179,76 +4932,21 @@ if (has_match_end) { OP1(SLJIT_MOV, TMP3, 0, STR_END, 0); - OP2(SLJIT_ADD, STR_END, 0, SLJIT_MEM1(SLJIT_SP), common->match_end_ptr, SLJIT_IMM, IN_UCHARS(offset + 1)); -#if (defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86) - if (sljit_x86_is_cmov_available()) - { - OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, STR_END, 0, TMP3, 0); - sljit_x86_emit_cmov(compiler, SLJIT_GREATER, STR_END, TMP3, 0); - } -#endif - { - quit = CMP(SLJIT_LESS_EQUAL, STR_END, 0, TMP3, 0); - OP1(SLJIT_MOV, STR_END, 0, TMP3, 0); - JUMPHERE(quit); - } + OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, IN_UCHARS(offset + 1)); + OP2(SLJIT_SUB | SLJIT_SET_GREATER, SLJIT_UNUSED, 0, STR_END, 0, TMP1, 0); + CMOV(SLJIT_GREATER, STR_END, TMP1, 0); } -#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32 -if (common->utf && offset > 0) - utf_start = LABEL(); -#endif - -#if (defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86) +#if (defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86) && !(defined SUPPORT_VALGRIND) /* SSE2 accelerated first character search. */ -if (sljit_x86_is_sse2_available()) +if (sljit_has_cpu_feature(SLJIT_HAS_SSE2)) { - fast_forward_first_char2_sse2(common, char1, char2); - - SLJIT_ASSERT(common->mode == PCRE2_JIT_COMPLETE || offset == 0); - if (common->mode == PCRE2_JIT_COMPLETE) - { - /* In complete mode, we don't need to run a match when STR_PTR == STR_END. */ - SLJIT_ASSERT(common->forced_quit_label == NULL); - OP1(SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_IMM, PCRE2_ERROR_NOMATCH); - add_jump(compiler, &common->forced_quit, CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0)); - -#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32 - if (common->utf && offset > 0) - { - SLJIT_ASSERT(common->mode == PCRE2_JIT_COMPLETE); + fast_forward_first_char2_sse2(common, char1, char2, offset); - OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-offset)); - OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); -#if PCRE2_CODE_UNIT_WIDTH == 8 - OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xc0); - CMPTO(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, 0x80, utf_start); -#elif PCRE2_CODE_UNIT_WIDTH == 16 - OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xfc00); - CMPTO(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, 0xdc00, utf_start); -#else -#error "Unknown code width" -#endif - OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); - } -#endif - - if (offset > 0) - OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(offset)); - } - else if (sljit_x86_is_cmov_available()) - { - OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, STR_PTR, 0, STR_END, 0); - sljit_x86_emit_cmov(compiler, SLJIT_GREATER_EQUAL, STR_PTR, has_match_end ? SLJIT_MEM1(SLJIT_SP) : STR_END, has_match_end ? common->match_end_ptr : 0); - } - else - { - quit = CMP(SLJIT_LESS, STR_PTR, 0, STR_END, 0); - OP1(SLJIT_MOV, STR_PTR, 0, has_match_end ? SLJIT_MEM1(SLJIT_SP) : STR_END, has_match_end ? common->match_end_ptr : 0); - JUMPHERE(quit); - } + if (offset > 0) + OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(offset)); if (has_match_end) OP1(SLJIT_MOV, STR_END, 0, TMP3, 0); @@ -4257,85 +4955,56 @@ if (sljit_x86_is_sse2_available()) #endif -quit = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0); - start = LABEL(); + +partial_quit = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0); +if (common->mode == PCRE2_JIT_COMPLETE) + add_jump(compiler, &common->failed_match, partial_quit); + OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), 0); +OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); if (char1 == char2) - found = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, char1); + CMPTO(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, char1, start); else { mask = char1 ^ char2; if (is_powerof2(mask)) { OP2(SLJIT_OR, TMP1, 0, TMP1, 0, SLJIT_IMM, mask); - found = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, char1 | mask); + CMPTO(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, char1 | mask, start); } else { - OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, char1); - OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_UNUSED, 0, SLJIT_EQUAL); - OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, char2); - OP_FLAGS(SLJIT_OR | SLJIT_SET_E, TMP2, 0, TMP2, 0, SLJIT_EQUAL); - found = JUMP(SLJIT_NOT_ZERO); + match = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, char1); + CMPTO(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, char2, start); + JUMPHERE(match); } } -OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); -CMPTO(SLJIT_LESS, STR_PTR, 0, STR_END, 0, start); - -#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32 -if (common->utf && offset > 0) - utf_quit = JUMP(SLJIT_JUMP); -#endif - -JUMPHERE(found); - #if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32 if (common->utf && offset > 0) { - OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-offset)); - OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); -#if PCRE2_CODE_UNIT_WIDTH == 8 - OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xc0); - CMPTO(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, 0x80, utf_start); -#elif PCRE2_CODE_UNIT_WIDTH == 16 - OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xfc00); - CMPTO(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, 0xdc00, utf_start); -#else -#error "Unknown code width" -#endif - OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); - JUMPHERE(utf_quit); + OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-(offset + 1))); + jumpto_if_not_utf_char_start(compiler, TMP1, start); } #endif -JUMPHERE(quit); +OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(offset + 1)); + +if (common->mode != PCRE2_JIT_COMPLETE) + JUMPHERE(partial_quit); if (has_match_end) - { - quit = CMP(SLJIT_LESS, STR_PTR, 0, STR_END, 0); - OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(SLJIT_SP), common->match_end_ptr); - if (offset > 0) - OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(offset)); - JUMPHERE(quit); OP1(SLJIT_MOV, STR_END, 0, TMP3, 0); - } - -if (offset > 0) - OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(offset)); } static SLJIT_INLINE BOOL fast_forward_first_n_chars(compiler_common *common) { DEFINE_COMPILER; struct sljit_label *start; -struct sljit_jump *quit; struct sljit_jump *match; -/* bytes[0] represent the number of characters between 0 -and MAX_N_BYTES - 1, 255 represents any character. */ -PCRE2_UCHAR chars[MAX_N_CHARS * MAX_DIFF_CHARS]; +fast_forward_char_data chars[MAX_N_CHARS]; sljit_s32 offset; PCRE2_UCHAR mask; PCRE2_UCHAR *char_set, *char_set_end; @@ -4346,7 +5015,10 @@ BOOL in_range; sljit_u32 rec_count; for (i = 0; i < MAX_N_CHARS; i++) - chars[i * MAX_DIFF_CHARS] = 0; + { + chars[i].count = 0; + chars[i].last_count = 0; + } rec_count = 10000; max = scan_prefix(common, common->start, chars, MAX_N_CHARS, &rec_count); @@ -4354,21 +5026,50 @@ max = scan_prefix(common, common->start, chars, MAX_N_CHARS, &rec_count); if (max < 1) return FALSE; +/* Convert last_count to priority. */ +for (i = 0; i < max; i++) + { + SLJIT_ASSERT(chars[i].count > 0 && chars[i].last_count <= chars[i].count); + + if (chars[i].count == 1) + { + chars[i].last_count = (chars[i].last_count == 1) ? 7 : 5; + /* Simplifies algorithms later. */ + chars[i].chars[1] = chars[i].chars[0]; + } + else if (chars[i].count == 2) + { + SLJIT_ASSERT(chars[i].chars[0] != chars[i].chars[1]); + + if (is_powerof2(chars[i].chars[0] ^ chars[i].chars[1])) + chars[i].last_count = (chars[i].last_count == 2) ? 6 : 4; + else + chars[i].last_count = (chars[i].last_count == 2) ? 3 : 2; + } + else + chars[i].last_count = (chars[i].count == 255) ? 0 : 1; + } + +#if (defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86) && !(defined SUPPORT_VALGRIND) && !(defined _WIN64) +if (check_fast_forward_char_pair_sse2(common, chars, max)) + return TRUE; +#endif + in_range = FALSE; /* Prevent compiler "uninitialized" warning */ from = 0; range_len = 4 /* minimum length */ - 1; for (i = 0; i <= max; i++) { - if (in_range && (i - from) > range_len && (chars[(i - 1) * MAX_DIFF_CHARS] < 255)) + if (in_range && (i - from) > range_len && (chars[i - 1].count < 255)) { range_len = i - from; range_right = i - 1; } - if (i < max && chars[i * MAX_DIFF_CHARS] < 255) + if (i < max && chars[i].count < 255) { - SLJIT_ASSERT(chars[i * MAX_DIFF_CHARS] > 0); + SLJIT_ASSERT(chars[i].count > 0); if (!in_range) { in_range = TRUE; @@ -4388,16 +5089,17 @@ if (range_right >= 0) for (i = 0; i < range_len; i++) { - char_set = chars + ((range_right - i) * MAX_DIFF_CHARS); - SLJIT_ASSERT(char_set[0] > 0 && char_set[0] < 255); - char_set_end = char_set + char_set[0]; - char_set++; - while (char_set <= char_set_end) + SLJIT_ASSERT(chars[range_right - i].count > 0 && chars[range_right - i].count < 255); + + char_set = chars[range_right - i].chars; + char_set_end = char_set + chars[range_right - i].count; + do { if (update_table[(*char_set) & 0xff] > IN_UCHARS(i)) update_table[(*char_set) & 0xff] = IN_UCHARS(i); char_set++; } + while (char_set < char_set_end); } } @@ -4405,54 +5107,38 @@ offset = -1; /* Scan forward. */ for (i = 0; i < max; i++) { + if (range_right == i) + continue; + if (offset == -1) { - if (chars[i * MAX_DIFF_CHARS] <= 2) + if (chars[i].last_count >= 2) offset = i; } - else if (chars[offset * MAX_DIFF_CHARS] == 2 && chars[i * MAX_DIFF_CHARS] <= 2) - { - if (chars[i * MAX_DIFF_CHARS] == 1) - offset = i; - else - { - mask = chars[offset * MAX_DIFF_CHARS + 1] ^ chars[offset * MAX_DIFF_CHARS + 2]; - if (!is_powerof2(mask)) - { - mask = chars[i * MAX_DIFF_CHARS + 1] ^ chars[i * MAX_DIFF_CHARS + 2]; - if (is_powerof2(mask)) - offset = i; - } - } - } + else if (chars[offset].last_count < chars[i].last_count) + offset = i; } +SLJIT_ASSERT(offset == -1 || (chars[offset].count >= 1 && chars[offset].count <= 2)); + if (range_right < 0) { if (offset < 0) return FALSE; - SLJIT_ASSERT(chars[offset * MAX_DIFF_CHARS] >= 1 && chars[offset * MAX_DIFF_CHARS] <= 2); /* Works regardless the value is 1 or 2. */ - mask = chars[offset * MAX_DIFF_CHARS + chars[offset * MAX_DIFF_CHARS]]; - fast_forward_first_char2(common, chars[offset * MAX_DIFF_CHARS + 1], mask, offset); + fast_forward_first_char2(common, chars[offset].chars[0], chars[offset].chars[1], offset); return TRUE; } -if (range_right == offset) - offset = -1; +SLJIT_ASSERT(range_right != offset); -SLJIT_ASSERT(offset == -1 || (chars[offset * MAX_DIFF_CHARS] >= 1 && chars[offset * MAX_DIFF_CHARS] <= 2)); - -max -= 1; -SLJIT_ASSERT(max > 0); if (common->match_end_ptr != 0) { OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->match_end_ptr); OP1(SLJIT_MOV, TMP3, 0, STR_END, 0); OP2(SLJIT_SUB, STR_END, 0, STR_END, 0, SLJIT_IMM, IN_UCHARS(max)); - quit = CMP(SLJIT_LESS_EQUAL, STR_END, 0, TMP1, 0); - OP1(SLJIT_MOV, STR_END, 0, TMP1, 0); - JUMPHERE(quit); + OP2(SLJIT_SUB | SLJIT_SET_GREATER, SLJIT_UNUSED, 0, STR_END, 0, TMP1, 0); + CMOV(SLJIT_GREATER, STR_END, TMP1, 0); } else OP2(SLJIT_SUB, STR_END, 0, STR_END, 0, SLJIT_IMM, IN_UCHARS(max)); @@ -4464,7 +5150,7 @@ OP1(SLJIT_MOV, RETURN_ADDR, 0, SLJIT_IMM, (sljit_sw)update_table); #endif start = LABEL(); -quit = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0); +add_jump(compiler, &common->failed_match, CMP(SLJIT_GREATER, STR_PTR, 0, STR_END, 0)); #if PCRE2_CODE_UNIT_WIDTH == 8 || (defined SLJIT_LITTLE_ENDIAN && SLJIT_LITTLE_ENDIAN) OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(range_right)); @@ -4485,20 +5171,20 @@ if (offset >= 0) OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(offset)); OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); - if (chars[offset * MAX_DIFF_CHARS] == 1) - CMPTO(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, chars[offset * MAX_DIFF_CHARS + 1], start); + if (chars[offset].count == 1) + CMPTO(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, chars[offset].chars[0], start); else { - mask = chars[offset * MAX_DIFF_CHARS + 1] ^ chars[offset * MAX_DIFF_CHARS + 2]; + mask = chars[offset].chars[0] ^ chars[offset].chars[1]; if (is_powerof2(mask)) { OP2(SLJIT_OR, TMP1, 0, TMP1, 0, SLJIT_IMM, mask); - CMPTO(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, chars[offset * MAX_DIFF_CHARS + 1] | mask, start); + CMPTO(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, chars[offset].chars[0] | mask, start); } else { - match = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, chars[offset * MAX_DIFF_CHARS + 1]); - CMPTO(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, chars[offset * MAX_DIFF_CHARS + 2], start); + match = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, chars[offset].chars[0]); + CMPTO(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, chars[offset].chars[1], start); JUMPHERE(match); } } @@ -4514,15 +5200,9 @@ if (common->utf && offset != 0) } else OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-1)); -#if PCRE2_CODE_UNIT_WIDTH == 8 - OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xc0); - CMPTO(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, 0x80, start); -#elif PCRE2_CODE_UNIT_WIDTH == 16 - OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xfc00); - CMPTO(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, 0xdc00, start); -#else -#error "Unknown code width" -#endif + + jumpto_if_not_utf_char_start(compiler, TMP1, start); + if (offset < 0) OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); } @@ -4531,33 +5211,20 @@ if (common->utf && offset != 0) if (offset >= 0) OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); -JUMPHERE(quit); - if (common->match_end_ptr != 0) - { - if (range_right >= 0) - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->match_end_ptr); - OP1(SLJIT_MOV, STR_END, 0, TMP3, 0); - if (range_right >= 0) - { - quit = CMP(SLJIT_LESS_EQUAL, STR_PTR, 0, TMP1, 0); - OP1(SLJIT_MOV, STR_PTR, 0, TMP1, 0); - JUMPHERE(quit); - } - } + OP1(SLJIT_MOV, STR_END, 0, TMP3, 0); else OP2(SLJIT_ADD, STR_END, 0, STR_END, 0, SLJIT_IMM, IN_UCHARS(max)); return TRUE; } -#undef MAX_N_CHARS - -static SLJIT_INLINE void fast_forward_first_char(compiler_common *common, PCRE2_UCHAR first_char, BOOL caseless) +static SLJIT_INLINE void fast_forward_first_char(compiler_common *common) { +PCRE2_UCHAR first_char = (PCRE2_UCHAR)(common->re->first_codeunit); PCRE2_UCHAR oc; oc = first_char; -if (caseless) +if ((common->re->flags & PCRE2_FIRSTCASELESS) != 0) { oc = TABLE_GET(first_char, common->fcc, first_char); #if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 8 @@ -4595,8 +5262,8 @@ if (common->nltype == NLTYPE_FIXED && common->newline > 255) firstchar = CMP(SLJIT_LESS_EQUAL, STR_PTR, 0, TMP2, 0); OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, IN_UCHARS(2)); - OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, STR_PTR, 0, TMP1, 0); - OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_UNUSED, 0, SLJIT_GREATER_EQUAL); + OP2(SLJIT_SUB | SLJIT_SET_GREATER_EQUAL, SLJIT_UNUSED, 0, STR_PTR, 0, TMP1, 0); + OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_GREATER_EQUAL); #if PCRE2_CODE_UNIT_WIDTH == 16 || PCRE2_CODE_UNIT_WIDTH == 32 OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, UCHAR_SHIFT); #endif @@ -4640,8 +5307,8 @@ if (common->nltype == NLTYPE_ANY || common->nltype == NLTYPE_ANYCRLF) JUMPHERE(foundcr); notfoundnl = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0); OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), 0); - OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, CHAR_NL); - OP_FLAGS(SLJIT_MOV, TMP1, 0, SLJIT_UNUSED, 0, SLJIT_EQUAL); + OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, CHAR_NL); + OP_FLAGS(SLJIT_MOV, TMP1, 0, SLJIT_EQUAL); #if PCRE2_CODE_UNIT_WIDTH == 16 || PCRE2_CODE_UNIT_WIDTH == 32 OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, UCHAR_SHIFT); #endif @@ -4656,79 +5323,75 @@ if (common->match_end_ptr != 0) OP1(SLJIT_MOV, STR_END, 0, TMP3, 0); } -static BOOL check_class_ranges(compiler_common *common, const sljit_u8 *bits, BOOL nclass, BOOL invert, jump_list **backtracks); +static BOOL optimize_class(compiler_common *common, const sljit_u8 *bits, BOOL nclass, BOOL invert, jump_list **backtracks); -static SLJIT_INLINE void fast_forward_start_bits(compiler_common *common, const sljit_u8 *start_bits) +static SLJIT_INLINE void fast_forward_start_bits(compiler_common *common) { DEFINE_COMPILER; +const sljit_u8 *start_bits = common->re->start_bitmap; struct sljit_label *start; -struct sljit_jump *quit; -struct sljit_jump *found = NULL; -jump_list *matches = NULL; +struct sljit_jump *partial_quit; #if PCRE2_CODE_UNIT_WIDTH != 8 -struct sljit_jump *jump; +struct sljit_jump *found = NULL; #endif +jump_list *matches = NULL; if (common->match_end_ptr != 0) { + OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->match_end_ptr); OP1(SLJIT_MOV, RETURN_ADDR, 0, STR_END, 0); - OP1(SLJIT_MOV, STR_END, 0, SLJIT_MEM1(SLJIT_SP), common->match_end_ptr); + OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, IN_UCHARS(1)); + OP2(SLJIT_SUB | SLJIT_SET_GREATER, SLJIT_UNUSED, 0, STR_END, 0, TMP1, 0); + CMOV(SLJIT_GREATER, STR_END, TMP1, 0); } start = LABEL(); -quit = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0); + +partial_quit = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0); +if (common->mode == PCRE2_JIT_COMPLETE) + add_jump(compiler, &common->failed_match, partial_quit); + OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), 0); -#ifdef SUPPORT_UNICODE -if (common->utf) - OP1(SLJIT_MOV, TMP3, 0, TMP1, 0); -#endif +OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); -if (!check_class_ranges(common, start_bits, (start_bits[31] & 0x80) != 0, TRUE, &matches)) +if (!optimize_class(common, start_bits, (start_bits[31] & 0x80) != 0, FALSE, &matches)) { #if PCRE2_CODE_UNIT_WIDTH != 8 - jump = CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, 255); - OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, 255); - JUMPHERE(jump); + if ((start_bits[31] & 0x80) != 0) + found = CMP(SLJIT_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, 255); + else + CMPTO(SLJIT_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, 255, start); +#elif defined SUPPORT_UNICODE + if (common->utf && is_char7_bitset(start_bits, FALSE)) + CMPTO(SLJIT_GREATER, TMP1, 0, SLJIT_IMM, 127, start); #endif OP2(SLJIT_AND, TMP2, 0, TMP1, 0, SLJIT_IMM, 0x7); OP2(SLJIT_LSHR, TMP1, 0, TMP1, 0, SLJIT_IMM, 3); OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(TMP1), (sljit_sw)start_bits); - OP2(SLJIT_SHL, TMP2, 0, SLJIT_IMM, 1, TMP2, 0); - OP2(SLJIT_AND | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, TMP2, 0); - found = JUMP(SLJIT_NOT_ZERO); + if (sljit_get_register_index(TMP3) >= 0) + { + OP2(SLJIT_SHL, TMP3, 0, SLJIT_IMM, 1, TMP2, 0); + OP2(SLJIT_AND | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, TMP3, 0); + } + else + { + OP2(SLJIT_SHL, TMP2, 0, SLJIT_IMM, 1, TMP2, 0); + OP2(SLJIT_AND | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, TMP2, 0); + } + JUMPTO(SLJIT_ZERO, start); } +else + set_jumps(matches, start); -#ifdef SUPPORT_UNICODE -if (common->utf) - OP1(SLJIT_MOV, TMP1, 0, TMP3, 0); -#endif -OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); -#ifdef SUPPORT_UNICODE -#if PCRE2_CODE_UNIT_WIDTH == 8 -if (common->utf) - { - CMPTO(SLJIT_LESS, TMP1, 0, SLJIT_IMM, 0xc0, start); - OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(TMP1), (sljit_sw)PRIV(utf8_table4) - 0xc0); - OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0); - } -#elif PCRE2_CODE_UNIT_WIDTH == 16 -if (common->utf) - { - CMPTO(SLJIT_LESS, TMP1, 0, SLJIT_IMM, 0xd800, start); - OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xfc00); - OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0xd800); - OP_FLAGS(SLJIT_MOV, TMP1, 0, SLJIT_UNUSED, 0, SLJIT_EQUAL); - OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, 1); - OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0); - } -#endif /* PCRE2_CODE_UNIT_WIDTH == [8|16] */ -#endif /* SUPPORT_UNICODE */ -JUMPTO(SLJIT_JUMP, start); +#if PCRE2_CODE_UNIT_WIDTH != 8 if (found != NULL) JUMPHERE(found); -if (matches != NULL) - set_jumps(matches, LABEL()); -JUMPHERE(quit); +#endif + +OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); + +if (common->mode != PCRE2_JIT_COMPLETE) + JUMPHERE(partial_quit); if (common->match_end_ptr != 0) OP1(SLJIT_MOV, STR_END, 0, RETURN_ADDR, 0); @@ -4804,31 +5467,50 @@ struct sljit_jump *jump; struct sljit_label *mainloop; sljit_emit_fast_enter(compiler, RETURN_ADDR, 0); -OP1(SLJIT_MOV, TMP1, 0, STACK_TOP, 0); -GET_LOCAL_BASE(TMP3, 0, 0); +GET_LOCAL_BASE(TMP1, 0, 0); /* Drop frames until we reach STACK_TOP. */ mainloop = LABEL(); -OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(TMP1), 0); -OP2(SLJIT_SUB | SLJIT_SET_S, SLJIT_UNUSED, 0, TMP2, 0, SLJIT_IMM, 0); -jump = JUMP(SLJIT_SIG_LESS_EQUAL); - -OP2(SLJIT_ADD, TMP2, 0, TMP2, 0, TMP3, 0); -OP1(SLJIT_MOV, SLJIT_MEM1(TMP2), 0, SLJIT_MEM1(TMP1), sizeof(sljit_sw)); -OP1(SLJIT_MOV, SLJIT_MEM1(TMP2), sizeof(sljit_sw), SLJIT_MEM1(TMP1), 2 * sizeof(sljit_sw)); -OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, 3 * sizeof(sljit_sw)); +OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), -sizeof(sljit_sw)); +jump = CMP(SLJIT_SIG_LESS_EQUAL, TMP2, 0, SLJIT_IMM, 0); + +OP2(SLJIT_ADD, TMP2, 0, TMP2, 0, TMP1, 0); +if (sljit_get_register_index (TMP3) < 0) + { + OP1(SLJIT_MOV, SLJIT_MEM1(TMP2), 0, SLJIT_MEM1(STACK_TOP), -(2 * sizeof(sljit_sw))); + OP1(SLJIT_MOV, SLJIT_MEM1(TMP2), sizeof(sljit_sw), SLJIT_MEM1(STACK_TOP), -(3 * sizeof(sljit_sw))); + OP2(SLJIT_SUB, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, 3 * sizeof(sljit_sw)); + } +else + { + OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), -(2 * sizeof(sljit_sw))); + OP1(SLJIT_MOV, TMP3, 0, SLJIT_MEM1(STACK_TOP), -(3 * sizeof(sljit_sw))); + OP2(SLJIT_SUB, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, 3 * sizeof(sljit_sw)); + OP1(SLJIT_MOV, SLJIT_MEM1(TMP2), 0, TMP1, 0); + GET_LOCAL_BASE(TMP1, 0, 0); + OP1(SLJIT_MOV, SLJIT_MEM1(TMP2), sizeof(sljit_sw), TMP3, 0); + } JUMPTO(SLJIT_JUMP, mainloop); JUMPHERE(jump); -jump = JUMP(SLJIT_SIG_LESS); -/* End of dropping frames. */ +jump = CMP(SLJIT_NOT_ZERO /* SIG_LESS */, TMP2, 0, SLJIT_IMM, 0); +/* End of reverting values. */ sljit_emit_fast_return(compiler, RETURN_ADDR, 0); JUMPHERE(jump); OP1(SLJIT_NEG, TMP2, 0, TMP2, 0); -OP2(SLJIT_ADD, TMP2, 0, TMP2, 0, TMP3, 0); -OP1(SLJIT_MOV, SLJIT_MEM1(TMP2), 0, SLJIT_MEM1(TMP1), sizeof(sljit_sw)); -OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, 2 * sizeof(sljit_sw)); +OP2(SLJIT_ADD, TMP2, 0, TMP2, 0, TMP1, 0); +if (sljit_get_register_index (TMP3) < 0) + { + OP1(SLJIT_MOV, SLJIT_MEM1(TMP2), 0, SLJIT_MEM1(STACK_TOP), -(2 * sizeof(sljit_sw))); + OP2(SLJIT_SUB, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, 2 * sizeof(sljit_sw)); + } +else + { + OP1(SLJIT_MOV, TMP3, 0, SLJIT_MEM1(STACK_TOP), -(2 * sizeof(sljit_sw))); + OP2(SLJIT_SUB, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, 2 * sizeof(sljit_sw)); + OP1(SLJIT_MOV, SLJIT_MEM1(TMP2), 0, TMP3, 0); + } JUMPTO(SLJIT_JUMP, mainloop); } @@ -4861,11 +5543,11 @@ if (common->use_ucp) jump = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, CHAR_UNDERSCORE); add_jump(compiler, &common->getucd, JUMP(SLJIT_FAST_CALL)); OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, ucp_Ll); - OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, ucp_Lu - ucp_Ll); - OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_UNUSED, 0, SLJIT_LESS_EQUAL); + OP2(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, ucp_Lu - ucp_Ll); + OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_LESS_EQUAL); OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, ucp_Nd - ucp_Ll); - OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, ucp_No - ucp_Nd); - OP_FLAGS(SLJIT_OR, TMP2, 0, TMP2, 0, SLJIT_LESS_EQUAL); + OP2(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, ucp_No - ucp_Nd); + OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_LESS_EQUAL); JUMPHERE(jump); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LOCALS1, TMP2, 0); } @@ -4905,11 +5587,11 @@ if (common->use_ucp) jump = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, CHAR_UNDERSCORE); add_jump(compiler, &common->getucd, JUMP(SLJIT_FAST_CALL)); OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, ucp_Ll); - OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, ucp_Lu - ucp_Ll); - OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_UNUSED, 0, SLJIT_LESS_EQUAL); + OP2(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, ucp_Lu - ucp_Ll); + OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_LESS_EQUAL); OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, ucp_Nd - ucp_Ll); - OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, ucp_No - ucp_Nd); - OP_FLAGS(SLJIT_OR, TMP2, 0, TMP2, 0, SLJIT_LESS_EQUAL); + OP2(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, ucp_No - ucp_Nd); + OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_LESS_EQUAL); JUMPHERE(jump); } else @@ -4937,15 +5619,15 @@ else } set_jumps(skipread_list, LABEL()); -OP2(SLJIT_XOR | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP2, 0, SLJIT_MEM1(SLJIT_SP), LOCALS1); +OP2(SLJIT_XOR | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP2, 0, SLJIT_MEM1(SLJIT_SP), LOCALS1); sljit_emit_fast_return(compiler, SLJIT_MEM1(SLJIT_SP), LOCALS0); } -static BOOL check_class_ranges(compiler_common *common, const sljit_u8 *bits, BOOL nclass, BOOL invert, jump_list **backtracks) +static BOOL optimize_class_ranges(compiler_common *common, const sljit_u8 *bits, BOOL nclass, BOOL invert, jump_list **backtracks) { /* May destroy TMP1. */ DEFINE_COMPILER; -int ranges[MAX_RANGE_SIZE]; +int ranges[MAX_CLASS_RANGE_SIZE]; sljit_u8 bit, cbit, all; int i, byte, length = 0; @@ -4963,7 +5645,7 @@ for (i = 0; i < 256; ) cbit = (bits[byte] >> (i & 0x7)) & 0x1; if (cbit != bit) { - if (length >= MAX_RANGE_SIZE) + if (length >= MAX_CLASS_RANGE_SIZE) return FALSE; ranges[length] = i; length++; @@ -4976,7 +5658,7 @@ for (i = 0; i < 256; ) if (((bit == 0) && nclass) || ((bit == 1) && !nclass)) { - if (length >= MAX_RANGE_SIZE) + if (length >= MAX_CLASS_RANGE_SIZE) return FALSE; ranges[length] = 256; length++; @@ -5088,9 +5770,116 @@ switch(length) return TRUE; default: - SLJIT_ASSERT_STOP(); + SLJIT_UNREACHABLE(); + return FALSE; + } +} + +static BOOL optimize_class_chars(compiler_common *common, const sljit_u8 *bits, BOOL nclass, BOOL invert, jump_list **backtracks) +{ +/* May destroy TMP1. */ +DEFINE_COMPILER; +uint16_t char_list[MAX_CLASS_CHARS_SIZE]; +uint8_t byte; +sljit_s32 type; +int i, j, k, len, c; + +if (!sljit_has_cpu_feature(SLJIT_HAS_CMOV)) return FALSE; + +if (invert) + nclass = !nclass; + +len = 0; + +for (i = 0; i < 32; i++) + { + byte = bits[i]; + + if (nclass) + byte = ~byte; + + j = 0; + while (byte != 0) + { + if (byte & 0x1) + { + c = i * 8 + j; + + k = len; + + if ((c & 0x20) != 0) + { + for (k = 0; k < len; k++) + if (char_list[k] == c - 0x20) + { + char_list[k] |= 0x120; + break; + } + } + + if (k == len) + { + if (len >= MAX_CLASS_CHARS_SIZE) + return FALSE; + + char_list[len++] = (uint16_t) c; + } + } + + byte >>= 1; + j++; + } } + +i = 0; +j = 0; + +if (char_list[0] == 0) + { + i++; + OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0); + OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_ZERO); + } +else + OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, 0); + +while (i < len) + { + if ((char_list[i] & 0x100) != 0) + j++; + else + { + OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, char_list[i]); + CMOV(SLJIT_ZERO, TMP2, TMP1, 0); + } + i++; + } + +if (j != 0) + { + OP2(SLJIT_OR, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x20); + + for (i = 0; i < len; i++) + if ((char_list[i] & 0x100) != 0) + { + j--; + OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, char_list[i] & 0xff); + CMOV(SLJIT_ZERO, TMP2, TMP1, 0); + } + } + +type = nclass ? SLJIT_NOT_EQUAL : SLJIT_EQUAL; +add_jump(compiler, backtracks, CMP(type, TMP2, 0, SLJIT_IMM, 0)); +return TRUE; +} + +static BOOL optimize_class(compiler_common *common, const sljit_u8 *bits, BOOL nclass, BOOL invert, jump_list **backtracks) +{ +/* May destroy TMP1. */ +if (optimize_class_ranges(common, bits, nclass, invert, backtracks)) + return TRUE; +return optimize_class_chars(common, bits, nclass, invert, backtracks); } static void check_anynewline(compiler_common *common) @@ -5101,22 +5890,22 @@ DEFINE_COMPILER; sljit_emit_fast_enter(compiler, RETURN_ADDR, 0); OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x0a); -OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x0d - 0x0a); -OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_UNUSED, 0, SLJIT_LESS_EQUAL); -OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x85 - 0x0a); +OP2(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x0d - 0x0a); +OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_LESS_EQUAL); +OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x85 - 0x0a); #if defined SUPPORT_UNICODE || PCRE2_CODE_UNIT_WIDTH == 16 || PCRE2_CODE_UNIT_WIDTH == 32 #if PCRE2_CODE_UNIT_WIDTH == 8 if (common->utf) { #endif - OP_FLAGS(SLJIT_OR, TMP2, 0, TMP2, 0, SLJIT_EQUAL); + OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL); OP2(SLJIT_OR, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x1); - OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x2029 - 0x0a); + OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x2029 - 0x0a); #if PCRE2_CODE_UNIT_WIDTH == 8 } #endif #endif /* SUPPORT_UNICODE || PCRE2_CODE_UNIT_WIDTH == [16|32] */ -OP_FLAGS(SLJIT_OR | SLJIT_SET_E, TMP2, 0, TMP2, 0, SLJIT_EQUAL); +OP_FLAGS(SLJIT_OR | SLJIT_SET_Z, TMP2, 0, SLJIT_EQUAL); sljit_emit_fast_return(compiler, RETURN_ADDR, 0); } @@ -5127,34 +5916,34 @@ DEFINE_COMPILER; sljit_emit_fast_enter(compiler, RETURN_ADDR, 0); -OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x09); -OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_UNUSED, 0, SLJIT_EQUAL); -OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x20); -OP_FLAGS(SLJIT_OR, TMP2, 0, TMP2, 0, SLJIT_EQUAL); -OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0xa0); +OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x09); +OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_EQUAL); +OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x20); +OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL); +OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0xa0); #if defined SUPPORT_UNICODE || PCRE2_CODE_UNIT_WIDTH == 16 || PCRE2_CODE_UNIT_WIDTH == 32 #if PCRE2_CODE_UNIT_WIDTH == 8 if (common->utf) { #endif - OP_FLAGS(SLJIT_OR, TMP2, 0, TMP2, 0, SLJIT_EQUAL); - OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x1680); - OP_FLAGS(SLJIT_OR, TMP2, 0, TMP2, 0, SLJIT_EQUAL); - OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x180e); - OP_FLAGS(SLJIT_OR, TMP2, 0, TMP2, 0, SLJIT_EQUAL); + OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL); + OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x1680); + OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL); + OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x180e); + OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL); OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x2000); - OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x200A - 0x2000); - OP_FLAGS(SLJIT_OR, TMP2, 0, TMP2, 0, SLJIT_LESS_EQUAL); - OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x202f - 0x2000); - OP_FLAGS(SLJIT_OR, TMP2, 0, TMP2, 0, SLJIT_EQUAL); - OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x205f - 0x2000); - OP_FLAGS(SLJIT_OR, TMP2, 0, TMP2, 0, SLJIT_EQUAL); - OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x3000 - 0x2000); + OP2(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x200A - 0x2000); + OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_LESS_EQUAL); + OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x202f - 0x2000); + OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL); + OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x205f - 0x2000); + OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL); + OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x3000 - 0x2000); #if PCRE2_CODE_UNIT_WIDTH == 8 } #endif #endif /* SUPPORT_UNICODE || PCRE2_CODE_UNIT_WIDTH == [16|32] */ -OP_FLAGS(SLJIT_OR | SLJIT_SET_E, TMP2, 0, TMP2, 0, SLJIT_EQUAL); +OP_FLAGS(SLJIT_OR | SLJIT_SET_Z, TMP2, 0, SLJIT_EQUAL); sljit_emit_fast_return(compiler, RETURN_ADDR, 0); } @@ -5167,22 +5956,22 @@ DEFINE_COMPILER; sljit_emit_fast_enter(compiler, RETURN_ADDR, 0); OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x0a); -OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x0d - 0x0a); -OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_UNUSED, 0, SLJIT_LESS_EQUAL); -OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x85 - 0x0a); +OP2(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x0d - 0x0a); +OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_LESS_EQUAL); +OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x85 - 0x0a); #if defined SUPPORT_UNICODE || PCRE2_CODE_UNIT_WIDTH == 16 || PCRE2_CODE_UNIT_WIDTH == 32 #if PCRE2_CODE_UNIT_WIDTH == 8 if (common->utf) { #endif - OP_FLAGS(SLJIT_OR | SLJIT_SET_E, TMP2, 0, TMP2, 0, SLJIT_EQUAL); + OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL); OP2(SLJIT_OR, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x1); - OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x2029 - 0x0a); + OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x2029 - 0x0a); #if PCRE2_CODE_UNIT_WIDTH == 8 } #endif #endif /* SUPPORT_UNICODE || PCRE2_CODE_UNIT_WIDTH == [16|32] */ -OP_FLAGS(SLJIT_OR | SLJIT_SET_E, TMP2, 0, TMP2, 0, SLJIT_EQUAL); +OP_FLAGS(SLJIT_OR | SLJIT_SET_Z, TMP2, 0, SLJIT_EQUAL); sljit_emit_fast_return(compiler, RETURN_ADDR, 0); } @@ -5207,7 +5996,7 @@ label = LABEL(); OP1(MOVU_UCHAR, CHAR1, 0, SLJIT_MEM1(TMP1), IN_UCHARS(1)); OP1(MOVU_UCHAR, CHAR2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(1)); jump = CMP(SLJIT_NOT_EQUAL, CHAR1, 0, CHAR2, 0); -OP2(SLJIT_SUB | SLJIT_SET_E, TMP2, 0, TMP2, 0, SLJIT_IMM, IN_UCHARS(1)); +OP2(SLJIT_SUB | SLJIT_SET_Z, TMP2, 0, TMP2, 0, SLJIT_IMM, IN_UCHARS(1)); JUMPTO(SLJIT_NOT_ZERO, label); JUMPHERE(jump); @@ -5251,7 +6040,7 @@ OP1(SLJIT_MOV_U8, CHAR2, 0, SLJIT_MEM2(LCC_TABLE, CHAR2), 0); JUMPHERE(jump); #endif jump = CMP(SLJIT_NOT_EQUAL, CHAR1, 0, CHAR2, 0); -OP2(SLJIT_SUB | SLJIT_SET_E, TMP2, 0, TMP2, 0, SLJIT_IMM, IN_UCHARS(1)); +OP2(SLJIT_SUB | SLJIT_SET_Z, TMP2, 0, TMP2, 0, SLJIT_IMM, IN_UCHARS(1)); JUMPTO(SLJIT_NOT_ZERO, label); JUMPHERE(jump); @@ -5418,7 +6207,7 @@ do #endif default: - SLJIT_ASSERT_STOP(); + SLJIT_UNREACHABLE(); break; } context->ucharptr = 0; @@ -5593,7 +6382,7 @@ while (*cc != XCL_END) break; default: - SLJIT_ASSERT_STOP(); + SLJIT_UNREACHABLE(); break; } cc += 2; @@ -5611,13 +6400,13 @@ if ((cc[-1] & XCL_HASPROP) == 0) if ((cc[-1] & XCL_MAP) != 0) { jump = CMP(SLJIT_GREATER, TMP1, 0, SLJIT_IMM, 255); - if (!check_class_ranges(common, (const sljit_u8 *)cc, (((const sljit_u8 *)cc)[31] & 0x80) != 0, TRUE, &found)) + if (!optimize_class(common, (const sljit_u8 *)cc, (((const sljit_u8 *)cc)[31] & 0x80) != 0, TRUE, &found)) { OP2(SLJIT_AND, TMP2, 0, TMP1, 0, SLJIT_IMM, 0x7); OP2(SLJIT_LSHR, TMP1, 0, TMP1, 0, SLJIT_IMM, 3); OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(TMP1), (sljit_sw)cc); OP2(SLJIT_SHL, TMP2, 0, SLJIT_IMM, 1, TMP2, 0); - OP2(SLJIT_AND | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, TMP2, 0); + OP2(SLJIT_AND | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, TMP2, 0); add_jump(compiler, &found, JUMP(SLJIT_NOT_ZERO)); } @@ -5638,7 +6427,7 @@ else if ((cc[-1] & XCL_MAP) != 0) #ifdef SUPPORT_UNICODE charsaved = TRUE; #endif - if (!check_class_ranges(common, (const sljit_u8 *)cc, FALSE, TRUE, list)) + if (!optimize_class(common, (const sljit_u8 *)cc, FALSE, TRUE, list)) { #if PCRE2_CODE_UNIT_WIDTH == 8 jump = NULL; @@ -5650,7 +6439,7 @@ else if ((cc[-1] & XCL_MAP) != 0) OP2(SLJIT_LSHR, TMP1, 0, TMP1, 0, SLJIT_IMM, 3); OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(TMP1), (sljit_sw)cc); OP2(SLJIT_SHL, TMP2, 0, SLJIT_IMM, 1, TMP2, 0); - OP2(SLJIT_AND | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, TMP2, 0); + OP2(SLJIT_AND | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, TMP2, 0); add_jump(compiler, list, JUMP(SLJIT_NOT_ZERO)); #if PCRE2_CODE_UNIT_WIDTH == 8 @@ -5669,6 +6458,15 @@ if (needstype || needsscript) if (needschar && !charsaved) OP1(SLJIT_MOV, RETURN_ADDR, 0, TMP1, 0); +#if PCRE2_CODE_UNIT_WIDTH == 32 + if (!common->utf) + { + jump = CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, MAX_UTF_CODE_POINT + 1); + OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, INVALID_UTF_CHAR); + JUMPHERE(jump); + } +#endif + OP2(SLJIT_LSHR, TMP2, 0, TMP1, 0, SLJIT_IMM, UCD_BLOCK_SHIFT); OP1(SLJIT_MOV_U8, TMP2, 0, SLJIT_MEM1(TMP2), (sljit_sw)PRIV(ucd_stage1)); OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, UCD_BLOCK_MASK); @@ -5760,14 +6558,14 @@ while (*cc != XCL_END) if (numberofcmps < 3 && (*cc == XCL_SINGLE || *cc == XCL_RANGE)) { - OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)(c - charoffset)); - OP_FLAGS(numberofcmps == 0 ? SLJIT_MOV : SLJIT_OR, TMP2, 0, numberofcmps == 0 ? SLJIT_UNUSED : TMP2, 0, SLJIT_EQUAL); + OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)(c - charoffset)); + OP_FLAGS(numberofcmps == 0 ? SLJIT_MOV : SLJIT_OR, TMP2, 0, SLJIT_EQUAL); numberofcmps++; } else if (numberofcmps > 0) { - OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)(c - charoffset)); - OP_FLAGS(SLJIT_OR | SLJIT_SET_E, TMP2, 0, TMP2, 0, SLJIT_EQUAL); + OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)(c - charoffset)); + OP_FLAGS(SLJIT_OR | SLJIT_SET_Z, TMP2, 0, SLJIT_EQUAL); jump = JUMP(SLJIT_NOT_ZERO ^ invertcmp); numberofcmps = 0; } @@ -5786,14 +6584,14 @@ while (*cc != XCL_END) if (numberofcmps < 3 && (*cc == XCL_SINGLE || *cc == XCL_RANGE)) { - OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)(c - charoffset)); - OP_FLAGS(numberofcmps == 0 ? SLJIT_MOV : SLJIT_OR, TMP2, 0, numberofcmps == 0 ? SLJIT_UNUSED : TMP2, 0, SLJIT_LESS_EQUAL); + OP2(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)(c - charoffset)); + OP_FLAGS(numberofcmps == 0 ? SLJIT_MOV : SLJIT_OR, TMP2, 0, SLJIT_LESS_EQUAL); numberofcmps++; } else if (numberofcmps > 0) { - OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)(c - charoffset)); - OP_FLAGS(SLJIT_OR | SLJIT_SET_E, TMP2, 0, TMP2, 0, SLJIT_LESS_EQUAL); + OP2(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)(c - charoffset)); + OP_FLAGS(SLJIT_OR | SLJIT_SET_Z, TMP2, 0, SLJIT_LESS_EQUAL); jump = JUMP(SLJIT_NOT_ZERO ^ invertcmp); numberofcmps = 0; } @@ -5818,12 +6616,12 @@ while (*cc != XCL_END) break; case PT_LAMP: - OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, typereg, 0, SLJIT_IMM, ucp_Lu - typeoffset); - OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_UNUSED, 0, SLJIT_EQUAL); - OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, typereg, 0, SLJIT_IMM, ucp_Ll - typeoffset); - OP_FLAGS(SLJIT_OR, TMP2, 0, TMP2, 0, SLJIT_EQUAL); - OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, typereg, 0, SLJIT_IMM, ucp_Lt - typeoffset); - OP_FLAGS(SLJIT_OR | SLJIT_SET_E, TMP2, 0, TMP2, 0, SLJIT_EQUAL); + OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, typereg, 0, SLJIT_IMM, ucp_Lu - typeoffset); + OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_EQUAL); + OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, typereg, 0, SLJIT_IMM, ucp_Ll - typeoffset); + OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL); + OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, typereg, 0, SLJIT_IMM, ucp_Lt - typeoffset); + OP_FLAGS(SLJIT_OR | SLJIT_SET_Z, TMP2, 0, SLJIT_EQUAL); jump = JUMP(SLJIT_NOT_ZERO ^ invertcmp); break; @@ -5845,33 +6643,33 @@ while (*cc != XCL_END) case PT_SPACE: case PT_PXSPACE: SET_CHAR_OFFSET(9); - OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0xd - 0x9); - OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_UNUSED, 0, SLJIT_LESS_EQUAL); + OP2(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0xd - 0x9); + OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_LESS_EQUAL); - OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x85 - 0x9); - OP_FLAGS(SLJIT_OR | SLJIT_SET_E, TMP2, 0, TMP2, 0, SLJIT_EQUAL); + OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x85 - 0x9); + OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL); - OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x180e - 0x9); - OP_FLAGS(SLJIT_OR | SLJIT_SET_E, TMP2, 0, TMP2, 0, SLJIT_EQUAL); + OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x180e - 0x9); + OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL); SET_TYPE_OFFSET(ucp_Zl); - OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, typereg, 0, SLJIT_IMM, ucp_Zs - ucp_Zl); - OP_FLAGS(SLJIT_OR | SLJIT_SET_E, TMP2, 0, TMP2, 0, SLJIT_LESS_EQUAL); + OP2(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, SLJIT_UNUSED, 0, typereg, 0, SLJIT_IMM, ucp_Zs - ucp_Zl); + OP_FLAGS(SLJIT_OR | SLJIT_SET_Z, TMP2, 0, SLJIT_LESS_EQUAL); jump = JUMP(SLJIT_NOT_ZERO ^ invertcmp); break; case PT_WORD: - OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)(CHAR_UNDERSCORE - charoffset)); - OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_UNUSED, 0, SLJIT_EQUAL); + OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)(CHAR_UNDERSCORE - charoffset)); + OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_EQUAL); /* Fall through. */ case PT_ALNUM: SET_TYPE_OFFSET(ucp_Ll); - OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, typereg, 0, SLJIT_IMM, ucp_Lu - ucp_Ll); - OP_FLAGS((*cc == PT_ALNUM) ? SLJIT_MOV : SLJIT_OR, TMP2, 0, (*cc == PT_ALNUM) ? SLJIT_UNUSED : TMP2, 0, SLJIT_LESS_EQUAL); + OP2(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, SLJIT_UNUSED, 0, typereg, 0, SLJIT_IMM, ucp_Lu - ucp_Ll); + OP_FLAGS((*cc == PT_ALNUM) ? SLJIT_MOV : SLJIT_OR, TMP2, 0, SLJIT_LESS_EQUAL); SET_TYPE_OFFSET(ucp_Nd); - OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, typereg, 0, SLJIT_IMM, ucp_No - ucp_Nd); - OP_FLAGS(SLJIT_OR | SLJIT_SET_E, TMP2, 0, TMP2, 0, SLJIT_LESS_EQUAL); + OP2(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, SLJIT_UNUSED, 0, typereg, 0, SLJIT_IMM, ucp_No - ucp_Nd); + OP_FLAGS(SLJIT_OR | SLJIT_SET_Z, TMP2, 0, SLJIT_LESS_EQUAL); jump = JUMP(SLJIT_NOT_ZERO ^ invertcmp); break; @@ -5893,8 +6691,8 @@ while (*cc != XCL_END) OP2(SLJIT_ADD, TMP2, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)charoffset); OP2(SLJIT_OR, TMP2, 0, TMP2, 0, SLJIT_IMM, other_cases[1] ^ other_cases[0]); } - OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP2, 0, SLJIT_IMM, other_cases[1]); - OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_UNUSED, 0, SLJIT_EQUAL); + OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP2, 0, SLJIT_IMM, other_cases[1]); + OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_EQUAL); other_cases += 2; } else if (is_powerof2(other_cases[2] ^ other_cases[1])) @@ -5906,63 +6704,63 @@ while (*cc != XCL_END) OP2(SLJIT_ADD, TMP2, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)charoffset); OP2(SLJIT_OR, TMP2, 0, TMP2, 0, SLJIT_IMM, other_cases[1] ^ other_cases[0]); } - OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP2, 0, SLJIT_IMM, other_cases[2]); - OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_UNUSED, 0, SLJIT_EQUAL); + OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP2, 0, SLJIT_IMM, other_cases[2]); + OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_EQUAL); - OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)(other_cases[0] - charoffset)); - OP_FLAGS(SLJIT_OR | ((other_cases[3] == NOTACHAR) ? SLJIT_SET_E : 0), TMP2, 0, TMP2, 0, SLJIT_EQUAL); + OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)(other_cases[0] - charoffset)); + OP_FLAGS(SLJIT_OR | ((other_cases[3] == NOTACHAR) ? SLJIT_SET_Z : 0), TMP2, 0, SLJIT_EQUAL); other_cases += 3; } else { - OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)(*other_cases++ - charoffset)); - OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_UNUSED, 0, SLJIT_EQUAL); + OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)(*other_cases++ - charoffset)); + OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_EQUAL); } while (*other_cases != NOTACHAR) { - OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)(*other_cases++ - charoffset)); - OP_FLAGS(SLJIT_OR | ((*other_cases == NOTACHAR) ? SLJIT_SET_E : 0), TMP2, 0, TMP2, 0, SLJIT_EQUAL); + OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)(*other_cases++ - charoffset)); + OP_FLAGS(SLJIT_OR | ((*other_cases == NOTACHAR) ? SLJIT_SET_Z : 0), TMP2, 0, SLJIT_EQUAL); } jump = JUMP(SLJIT_NOT_ZERO ^ invertcmp); break; case PT_UCNC: - OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)(CHAR_DOLLAR_SIGN - charoffset)); - OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_UNUSED, 0, SLJIT_EQUAL); - OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)(CHAR_COMMERCIAL_AT - charoffset)); - OP_FLAGS(SLJIT_OR, TMP2, 0, TMP2, 0, SLJIT_EQUAL); - OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)(CHAR_GRAVE_ACCENT - charoffset)); - OP_FLAGS(SLJIT_OR, TMP2, 0, TMP2, 0, SLJIT_EQUAL); + OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)(CHAR_DOLLAR_SIGN - charoffset)); + OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_EQUAL); + OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)(CHAR_COMMERCIAL_AT - charoffset)); + OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL); + OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)(CHAR_GRAVE_ACCENT - charoffset)); + OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL); SET_CHAR_OFFSET(0xa0); - OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)(0xd7ff - charoffset)); - OP_FLAGS(SLJIT_OR, TMP2, 0, TMP2, 0, SLJIT_LESS_EQUAL); + OP2(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)(0xd7ff - charoffset)); + OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_LESS_EQUAL); SET_CHAR_OFFSET(0); - OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0xe000 - 0); - OP_FLAGS(SLJIT_OR | SLJIT_SET_E, TMP2, 0, TMP2, 0, SLJIT_GREATER_EQUAL); + OP2(SLJIT_SUB | SLJIT_SET_GREATER_EQUAL, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0xe000 - 0); + OP_FLAGS(SLJIT_OR | SLJIT_SET_Z, TMP2, 0, SLJIT_GREATER_EQUAL); jump = JUMP(SLJIT_NOT_ZERO ^ invertcmp); break; case PT_PXGRAPH: /* C and Z groups are the farthest two groups. */ SET_TYPE_OFFSET(ucp_Ll); - OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, typereg, 0, SLJIT_IMM, ucp_So - ucp_Ll); - OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_UNUSED, 0, SLJIT_GREATER); + OP2(SLJIT_SUB | SLJIT_SET_GREATER, SLJIT_UNUSED, 0, typereg, 0, SLJIT_IMM, ucp_So - ucp_Ll); + OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_GREATER); jump = CMP(SLJIT_NOT_EQUAL, typereg, 0, SLJIT_IMM, ucp_Cf - ucp_Ll); /* In case of ucp_Cf, we overwrite the result. */ SET_CHAR_OFFSET(0x2066); - OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x2069 - 0x2066); - OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_UNUSED, 0, SLJIT_LESS_EQUAL); + OP2(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x2069 - 0x2066); + OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_LESS_EQUAL); - OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x061c - 0x2066); - OP_FLAGS(SLJIT_OR, TMP2, 0, TMP2, 0, SLJIT_EQUAL); + OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x061c - 0x2066); + OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL); - OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x180e - 0x2066); - OP_FLAGS(SLJIT_OR, TMP2, 0, TMP2, 0, SLJIT_EQUAL); + OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x180e - 0x2066); + OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL); JUMPHERE(jump); jump = CMP(SLJIT_ZERO ^ invertcmp, TMP2, 0, SLJIT_IMM, 0); @@ -5971,21 +6769,21 @@ while (*cc != XCL_END) case PT_PXPRINT: /* C and Z groups are the farthest two groups. */ SET_TYPE_OFFSET(ucp_Ll); - OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, typereg, 0, SLJIT_IMM, ucp_So - ucp_Ll); - OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_UNUSED, 0, SLJIT_GREATER); + OP2(SLJIT_SUB | SLJIT_SET_GREATER, SLJIT_UNUSED, 0, typereg, 0, SLJIT_IMM, ucp_So - ucp_Ll); + OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_GREATER); - OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, typereg, 0, SLJIT_IMM, ucp_Zs - ucp_Ll); - OP_FLAGS(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_NOT_EQUAL); + OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, typereg, 0, SLJIT_IMM, ucp_Zs - ucp_Ll); + OP_FLAGS(SLJIT_AND, TMP2, 0, SLJIT_NOT_EQUAL); jump = CMP(SLJIT_NOT_EQUAL, typereg, 0, SLJIT_IMM, ucp_Cf - ucp_Ll); /* In case of ucp_Cf, we overwrite the result. */ SET_CHAR_OFFSET(0x2066); - OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x2069 - 0x2066); - OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_UNUSED, 0, SLJIT_LESS_EQUAL); + OP2(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x2069 - 0x2066); + OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_LESS_EQUAL); - OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x061c - 0x2066); - OP_FLAGS(SLJIT_OR, TMP2, 0, TMP2, 0, SLJIT_EQUAL); + OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x061c - 0x2066); + OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL); JUMPHERE(jump); jump = CMP(SLJIT_ZERO ^ invertcmp, TMP2, 0, SLJIT_IMM, 0); @@ -5993,21 +6791,21 @@ while (*cc != XCL_END) case PT_PXPUNCT: SET_TYPE_OFFSET(ucp_Sc); - OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, typereg, 0, SLJIT_IMM, ucp_So - ucp_Sc); - OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_UNUSED, 0, SLJIT_LESS_EQUAL); + OP2(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, SLJIT_UNUSED, 0, typereg, 0, SLJIT_IMM, ucp_So - ucp_Sc); + OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_LESS_EQUAL); SET_CHAR_OFFSET(0); - OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x7f); - OP_FLAGS(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_LESS_EQUAL); + OP2(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x7f); + OP_FLAGS(SLJIT_AND, TMP2, 0, SLJIT_LESS_EQUAL); SET_TYPE_OFFSET(ucp_Pc); - OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, typereg, 0, SLJIT_IMM, ucp_Ps - ucp_Pc); - OP_FLAGS(SLJIT_OR | SLJIT_SET_E, TMP2, 0, TMP2, 0, SLJIT_LESS_EQUAL); + OP2(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, SLJIT_UNUSED, 0, typereg, 0, SLJIT_IMM, ucp_Ps - ucp_Pc); + OP_FLAGS(SLJIT_OR | SLJIT_SET_Z, TMP2, 0, SLJIT_LESS_EQUAL); jump = JUMP(SLJIT_NOT_ZERO ^ invertcmp); break; default: - SLJIT_ASSERT_STOP(); + SLJIT_UNREACHABLE(); break; } cc += 2; @@ -6053,6 +6851,7 @@ switch(type) case OP_NOT_WORD_BOUNDARY: case OP_WORD_BOUNDARY: add_jump(compiler, &common->wordboundary, JUMP(SLJIT_FAST_CALL)); + sljit_set_current_flags(compiler, SLJIT_SET_Z); add_jump(compiler, backtracks, JUMP(type == OP_NOT_WORD_BOUNDARY ? SLJIT_NOT_ZERO : SLJIT_ZERO)); return cc; @@ -6068,10 +6867,10 @@ switch(type) else { jump[1] = CMP(SLJIT_EQUAL, TMP2, 0, STR_END, 0); - OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, TMP2, 0, STR_END, 0); - OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_UNUSED, 0, SLJIT_LESS); - OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, (common->newline >> 8) & 0xff); - OP_FLAGS(SLJIT_OR | SLJIT_SET_E, TMP2, 0, TMP2, 0, SLJIT_NOT_EQUAL); + OP2(SLJIT_SUB | SLJIT_SET_LESS, SLJIT_UNUSED, 0, TMP2, 0, STR_END, 0); + OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_LESS); + OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, (common->newline >> 8) & 0xff); + OP_FLAGS(SLJIT_OR | SLJIT_SET_Z, TMP2, 0, SLJIT_NOT_EQUAL); add_jump(compiler, backtracks, JUMP(SLJIT_NOT_EQUAL)); check_partial(common, TRUE); add_jump(compiler, backtracks, JUMP(SLJIT_JUMP)); @@ -6093,9 +6892,9 @@ switch(type) OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0)); jump[1] = CMP(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, CHAR_CR); OP2(SLJIT_ADD, TMP2, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(2)); - OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, TMP2, 0, STR_END, 0); + OP2(SLJIT_SUB | SLJIT_SET_Z | SLJIT_SET_GREATER, SLJIT_UNUSED, 0, TMP2, 0, STR_END, 0); jump[2] = JUMP(SLJIT_GREATER); - add_jump(compiler, backtracks, JUMP(SLJIT_LESS)); + add_jump(compiler, backtracks, JUMP(SLJIT_NOT_EQUAL) /* LESS */); /* Equal. */ OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(1)); jump[3] = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, CHAR_NL); @@ -6114,6 +6913,7 @@ switch(type) read_char_range(common, common->nlmin, common->nlmax, TRUE); add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, STR_PTR, 0, STR_END, 0)); add_jump(compiler, &common->anynewline, JUMP(SLJIT_FAST_CALL)); + sljit_set_current_flags(compiler, SLJIT_SET_Z); add_jump(compiler, backtracks, JUMP(SLJIT_ZERO)); OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(SLJIT_SP), LOCALS1); } @@ -6131,8 +6931,8 @@ switch(type) case OP_DOLL: OP1(SLJIT_MOV, TMP2, 0, ARGUMENTS, 0); - OP2(SLJIT_AND32 | SLJIT_SET_E, SLJIT_UNUSED, 0, SLJIT_MEM1(TMP2), SLJIT_OFFSETOF(jit_arguments, options), SLJIT_IMM, PCRE2_NOTEOL); - add_jump(compiler, backtracks, JUMP(SLJIT_NOT_ZERO)); + OP2(SLJIT_AND32 | SLJIT_SET_Z, SLJIT_UNUSED, 0, SLJIT_MEM1(TMP2), SLJIT_OFFSETOF(jit_arguments, options), SLJIT_IMM, PCRE2_NOTEOL); + add_jump(compiler, backtracks, JUMP(SLJIT_NOT_ZERO32)); if (!common->endonly) compile_simple_assertion_matchingpath(common, OP_EODN, cc, backtracks); @@ -6146,8 +6946,8 @@ switch(type) case OP_DOLLM: jump[1] = CMP(SLJIT_LESS, STR_PTR, 0, STR_END, 0); OP1(SLJIT_MOV, TMP2, 0, ARGUMENTS, 0); - OP2(SLJIT_AND32 | SLJIT_SET_E, SLJIT_UNUSED, 0, SLJIT_MEM1(TMP2), SLJIT_OFFSETOF(jit_arguments, options), SLJIT_IMM, PCRE2_NOTEOL); - add_jump(compiler, backtracks, JUMP(SLJIT_NOT_ZERO)); + OP2(SLJIT_AND32 | SLJIT_SET_Z, SLJIT_UNUSED, 0, SLJIT_MEM1(TMP2), SLJIT_OFFSETOF(jit_arguments, options), SLJIT_IMM, PCRE2_NOTEOL); + add_jump(compiler, backtracks, JUMP(SLJIT_NOT_ZERO32)); check_partial(common, FALSE); jump[0] = JUMP(SLJIT_JUMP); JUMPHERE(jump[1]); @@ -6184,16 +6984,16 @@ switch(type) OP1(SLJIT_MOV, TMP2, 0, ARGUMENTS, 0); OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP2), SLJIT_OFFSETOF(jit_arguments, begin)); add_jump(compiler, backtracks, CMP(SLJIT_GREATER, STR_PTR, 0, TMP1, 0)); - OP2(SLJIT_AND32 | SLJIT_SET_E, SLJIT_UNUSED, 0, SLJIT_MEM1(TMP2), SLJIT_OFFSETOF(jit_arguments, options), SLJIT_IMM, PCRE2_NOTBOL); - add_jump(compiler, backtracks, JUMP(SLJIT_NOT_ZERO)); + OP2(SLJIT_AND32 | SLJIT_SET_Z, SLJIT_UNUSED, 0, SLJIT_MEM1(TMP2), SLJIT_OFFSETOF(jit_arguments, options), SLJIT_IMM, PCRE2_NOTBOL); + add_jump(compiler, backtracks, JUMP(SLJIT_NOT_ZERO32)); return cc; case OP_CIRCM: OP1(SLJIT_MOV, TMP2, 0, ARGUMENTS, 0); OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP2), SLJIT_OFFSETOF(jit_arguments, begin)); jump[1] = CMP(SLJIT_GREATER, STR_PTR, 0, TMP1, 0); - OP2(SLJIT_AND32 | SLJIT_SET_E, SLJIT_UNUSED, 0, SLJIT_MEM1(TMP2), SLJIT_OFFSETOF(jit_arguments, options), SLJIT_IMM, PCRE2_NOTBOL); - add_jump(compiler, backtracks, JUMP(SLJIT_NOT_ZERO)); + OP2(SLJIT_AND32 | SLJIT_SET_Z, SLJIT_UNUSED, 0, SLJIT_MEM1(TMP2), SLJIT_OFFSETOF(jit_arguments, options), SLJIT_IMM, PCRE2_NOTBOL); + add_jump(compiler, backtracks, JUMP(SLJIT_NOT_ZERO32)); jump[0] = JUMP(SLJIT_JUMP); JUMPHERE(jump[1]); @@ -6231,7 +7031,7 @@ switch(type) label = LABEL(); add_jump(compiler, backtracks, CMP(SLJIT_LESS_EQUAL, STR_PTR, 0, TMP3, 0)); skip_char_back(common); - OP2(SLJIT_SUB | SLJIT_SET_E, TMP2, 0, TMP2, 0, SLJIT_IMM, 1); + OP2(SLJIT_SUB | SLJIT_SET_Z, TMP2, 0, TMP2, 0, SLJIT_IMM, 1); JUMPTO(SLJIT_NOT_ZERO, label); } else @@ -6244,7 +7044,7 @@ switch(type) check_start_used_ptr(common); return cc + LINK_SIZE; } -SLJIT_ASSERT_STOP(); +SLJIT_UNREACHABLE(); return cc; } @@ -6275,7 +7075,7 @@ switch(type) #endif read_char8_type(common, type == OP_NOT_DIGIT); /* Flip the starting bit in the negative case. */ - OP2(SLJIT_AND | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, ctype_digit); + OP2(SLJIT_AND | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, ctype_digit); add_jump(compiler, backtracks, JUMP(type == OP_DIGIT ? SLJIT_ZERO : SLJIT_NOT_ZERO)); return cc; @@ -6289,7 +7089,7 @@ switch(type) else #endif read_char8_type(common, type == OP_NOT_WHITESPACE); - OP2(SLJIT_AND | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, ctype_space); + OP2(SLJIT_AND | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, ctype_space); add_jump(compiler, backtracks, JUMP(type == OP_WHITESPACE ? SLJIT_ZERO : SLJIT_NOT_ZERO)); return cc; @@ -6303,7 +7103,7 @@ switch(type) else #endif read_char8_type(common, type == OP_NOT_WORDCHAR); - OP2(SLJIT_AND | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, ctype_word); + OP2(SLJIT_AND | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, ctype_word); add_jump(compiler, backtracks, JUMP(type == OP_WORDCHAR ? SLJIT_ZERO : SLJIT_NOT_ZERO)); return cc; @@ -6345,8 +7145,8 @@ switch(type) #elif PCRE2_CODE_UNIT_WIDTH == 16 jump[0] = CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, 0xd800); OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xfc00); - OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0xd800); - OP_FLAGS(SLJIT_MOV, TMP1, 0, SLJIT_UNUSED, 0, SLJIT_EQUAL); + OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0xd800); + OP_FLAGS(SLJIT_MOV, TMP1, 0, SLJIT_EQUAL); OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, 1); OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0); #endif @@ -6406,6 +7206,7 @@ switch(type) detect_partial_match(common, backtracks); read_char_range(common, 0x9, 0x3000, type == OP_NOT_HSPACE); add_jump(compiler, &common->hspace, JUMP(SLJIT_FAST_CALL)); + sljit_set_current_flags(compiler, SLJIT_SET_Z); add_jump(compiler, backtracks, JUMP(type == OP_NOT_HSPACE ? SLJIT_NOT_ZERO : SLJIT_ZERO)); return cc; @@ -6415,6 +7216,7 @@ switch(type) detect_partial_match(common, backtracks); read_char_range(common, 0xa, 0x2029, type == OP_NOT_VSPACE); add_jump(compiler, &common->vspace, JUMP(SLJIT_FAST_CALL)); + sljit_set_current_flags(compiler, SLJIT_SET_Z); add_jump(compiler, backtracks, JUMP(type == OP_NOT_VSPACE ? SLJIT_NOT_ZERO : SLJIT_ZERO)); return cc; @@ -6441,7 +7243,7 @@ switch(type) OP1(SLJIT_MOV_U32, TMP1, 0, SLJIT_MEM1(STACK_TOP), (sljit_sw)PRIV(ucp_gbtable)); OP1(SLJIT_MOV, STACK_TOP, 0, TMP2, 0); OP2(SLJIT_SHL, TMP2, 0, SLJIT_IMM, 1, TMP2, 0); - OP2(SLJIT_AND | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, TMP2, 0); + OP2(SLJIT_AND | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, TMP2, 0); JUMPTO(SLJIT_NOT_ZERO, label); OP1(SLJIT_MOV, STR_PTR, 0, TMP3, 0); @@ -6584,7 +7386,7 @@ switch(type) read_char_range(common, 0, 255, type == OP_NCLASS); #endif - if (check_class_ranges(common, (const sljit_u8 *)cc, type == OP_NCLASS, FALSE, backtracks)) + if (optimize_class(common, (const sljit_u8 *)cc, type == OP_NCLASS, FALSE, backtracks)) return cc + 32 / sizeof(PCRE2_UCHAR); #if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8 @@ -6611,7 +7413,7 @@ switch(type) OP2(SLJIT_LSHR, TMP1, 0, TMP1, 0, SLJIT_IMM, 3); OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(TMP1), (sljit_sw)cc); OP2(SLJIT_SHL, TMP2, 0, SLJIT_IMM, 1, TMP2, 0); - OP2(SLJIT_AND | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, TMP2, 0); + OP2(SLJIT_AND | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, TMP2, 0); add_jump(compiler, backtracks, JUMP(SLJIT_ZERO)); #if defined SUPPORT_UNICODE || PCRE2_CODE_UNIT_WIDTH != 8 @@ -6628,7 +7430,7 @@ switch(type) return cc + GET(cc, 0) - 1; #endif } -SLJIT_ASSERT_STOP(); +SLJIT_UNREACHABLE(); return cc; } @@ -6814,9 +7616,9 @@ else #endif /* SUPPORT_UNICODE */ { if (ref) - OP2(SLJIT_SUB | SLJIT_SET_E, TMP2, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset + 1), TMP1, 0); + OP2(SLJIT_SUB | SLJIT_SET_Z, TMP2, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset + 1), TMP1, 0); else - OP2(SLJIT_SUB | SLJIT_SET_E, TMP2, 0, SLJIT_MEM1(TMP2), sizeof(sljit_sw), TMP1, 0); + OP2(SLJIT_SUB | SLJIT_SET_Z, TMP2, 0, SLJIT_MEM1(TMP2), sizeof(sljit_sw), TMP1, 0); if (withchecks) jump = JUMP(SLJIT_ZERO); @@ -6907,7 +7709,7 @@ switch(type) cc += 1 + IMM2_SIZE + 1 + 2 * IMM2_SIZE; break; default: - SLJIT_ASSERT_STOP(); + SLJIT_UNREACHABLE(); break; } @@ -6921,7 +7723,7 @@ if (!minimize) OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), SLJIT_IMM, 0); /* Temporary release of STR_PTR. */ - OP2(SLJIT_SUB, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, sizeof(sljit_sw)); + OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, sizeof(sljit_sw)); /* Handles both invalid and empty cases. Since the minimum repeat, is zero the invalid case is basically the same as an empty case. */ if (ref) @@ -6934,7 +7736,7 @@ if (!minimize) zerolength = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_MEM1(TMP2), sizeof(sljit_sw)); } /* Restore if not zero length. */ - OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, sizeof(sljit_sw)); + OP2(SLJIT_SUB, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, sizeof(sljit_sw)); } else { @@ -7098,8 +7900,10 @@ if (entry == NULL) if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler))) return NULL; entry->next = NULL; - entry->entry = NULL; - entry->calls = NULL; + entry->entry_label = NULL; + entry->backtrack_label = NULL; + entry->entry_calls = NULL; + entry->backtrack_calls = NULL; entry->start = start; if (prev != NULL) @@ -7108,71 +7912,73 @@ if (entry == NULL) common->entries = entry; } -if (common->has_set_som && common->mark_ptr != 0) - { - OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(0)); - allocate_stack(common, 2); - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->mark_ptr); - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), TMP2, 0); - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), TMP1, 0); - } -else if (common->has_set_som || common->mark_ptr != 0) - { - OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), common->has_set_som ? (int)(OVECTOR(0)) : common->mark_ptr); - allocate_stack(common, 1); - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), TMP2, 0); - } +BACKTRACK_AS(recurse_backtrack)->entry = entry; -if (entry->entry == NULL) - add_jump(compiler, &entry->calls, JUMP(SLJIT_FAST_CALL)); +if (entry->entry_label == NULL) + add_jump(compiler, &entry->entry_calls, JUMP(SLJIT_FAST_CALL)); else - JUMPTO(SLJIT_FAST_CALL, entry->entry); + JUMPTO(SLJIT_FAST_CALL, entry->entry_label); /* Leave if the match is failed. */ add_jump(compiler, &backtrack->topbacktracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, 0)); +BACKTRACK_AS(recurse_backtrack)->matchingpath = LABEL(); return cc + 1 + LINK_SIZE; } static int SLJIT_CALL do_callout(struct jit_arguments *arguments, pcre2_callout_block *callout_block, PCRE2_SPTR *jit_ovector) { -PCRE2_SPTR begin = arguments->begin; -PCRE2_SIZE *ovector = arguments->match_data->ovector; -sljit_u32 oveccount = arguments->oveccount; -sljit_u32 i; +PCRE2_SPTR begin; +PCRE2_SIZE *ovector; +sljit_u32 oveccount, capture_top; if (arguments->callout == NULL) return 0; +SLJIT_COMPILE_ASSERT(sizeof (PCRE2_SIZE) <= sizeof (sljit_sw), pcre2_size_must_be_lower_than_sljit_sw_size); + +begin = arguments->begin; +ovector = (PCRE2_SIZE*)(callout_block + 1); +oveccount = callout_block->capture_top; + +SLJIT_ASSERT(oveccount >= 1); + callout_block->version = 1; /* Offsets in subject. */ callout_block->subject_length = arguments->end - arguments->begin; -callout_block->start_match = (PCRE2_SPTR)callout_block->subject - arguments->begin; -callout_block->current_position = (PCRE2_SPTR)callout_block->offset_vector - arguments->begin; +callout_block->start_match = jit_ovector[0] - begin; +callout_block->current_position = (PCRE2_SPTR)callout_block->offset_vector - begin; callout_block->subject = begin; /* Convert and copy the JIT offset vector to the ovector array. */ -callout_block->capture_top = 0; +callout_block->capture_top = 1; callout_block->offset_vector = ovector; -for (i = 2; i < oveccount; i += 2) - { - ovector[i] = jit_ovector[i] - begin; - ovector[i + 1] = jit_ovector[i + 1] - begin; - if (jit_ovector[i] >= begin) - callout_block->capture_top = i; - } -callout_block->capture_top = (callout_block->capture_top >> 1) + 1; ovector[0] = PCRE2_UNSET; ovector[1] = PCRE2_UNSET; +ovector += 2; +jit_ovector += 2; +capture_top = 1; + +/* Convert pointers to sizes. */ +while (--oveccount != 0) + { + capture_top++; + + ovector[0] = (PCRE2_SIZE)(jit_ovector[0] - begin); + ovector[1] = (PCRE2_SIZE)(jit_ovector[1] - begin); + + if (ovector[0] != PCRE2_UNSET) + callout_block->capture_top = capture_top; + + ovector += 2; + jit_ovector += 2; + } + return (arguments->callout)(callout_block, arguments->callout_data); } -/* Aligning to 8 byte. */ -#define CALLOUT_ARG_SIZE \ - (((int)sizeof(pcre2_callout_block) + 7) & ~7) - #define CALLOUT_ARG_OFFSET(arg) \ - (-CALLOUT_ARG_SIZE + SLJIT_OFFSETOF(pcre2_callout_block, arg)) + SLJIT_OFFSETOF(pcre2_callout_block, arg) static SLJIT_INLINE PCRE2_SPTR compile_callout_matchingpath(compiler_common *common, PCRE2_SPTR cc, backtrack_common *parent) { @@ -7184,10 +7990,13 @@ unsigned int callout_length = (*cc == OP_CALLOUT) sljit_sw value1; sljit_sw value2; sljit_sw value3; +sljit_uw callout_arg_size = (common->re->top_bracket + 1) * 2 * sizeof(sljit_sw); PUSH_BACKTRACK(sizeof(backtrack_common), cc, NULL); -allocate_stack(common, CALLOUT_ARG_SIZE / sizeof(sljit_sw)); +callout_arg_size = (sizeof(pcre2_callout_block) + callout_arg_size + sizeof(sljit_sw) - 1) / sizeof(sljit_sw); + +allocate_stack(common, callout_arg_size); SLJIT_ASSERT(common->capture_last_ptr != 0); OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), common->capture_last_ptr); @@ -7195,11 +8004,10 @@ OP1(SLJIT_MOV, TMP1, 0, ARGUMENTS, 0); value1 = (*cc == OP_CALLOUT) ? cc[1 + 2 * LINK_SIZE] : 0; OP1(SLJIT_MOV_U32, SLJIT_MEM1(STACK_TOP), CALLOUT_ARG_OFFSET(callout_number), SLJIT_IMM, value1); OP1(SLJIT_MOV_U32, SLJIT_MEM1(STACK_TOP), CALLOUT_ARG_OFFSET(capture_last), TMP2, 0); +OP1(SLJIT_MOV_U32, SLJIT_MEM1(STACK_TOP), CALLOUT_ARG_OFFSET(capture_top), SLJIT_IMM, common->re->top_bracket + 1); /* These pointer sized fields temporarly stores internal variables. */ -OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(0)); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), CALLOUT_ARG_OFFSET(offset_vector), STR_PTR, 0); -OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), CALLOUT_ARG_OFFSET(subject), TMP2, 0); if (common->mark_ptr != 0) OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, mark_ptr)); @@ -7227,20 +8035,21 @@ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), CALLOUT_ARG_OFFSET(mark), (common->mark_pt /* Needed to save important temporary registers. */ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LOCALS0, STACK_TOP, 0); -OP2(SLJIT_SUB, SLJIT_R1, 0, STACK_TOP, 0, SLJIT_IMM, CALLOUT_ARG_SIZE); +/* SLJIT_R0 = arguments */ +OP1(SLJIT_MOV, SLJIT_R1, 0, STACK_TOP, 0); GET_LOCAL_BASE(SLJIT_R2, 0, OVECTOR_START); sljit_emit_ijump(compiler, SLJIT_CALL3, SLJIT_IMM, SLJIT_FUNC_OFFSET(do_callout)); OP1(SLJIT_MOV_S32, SLJIT_RETURN_REG, 0, SLJIT_RETURN_REG, 0); OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), LOCALS0); -free_stack(common, CALLOUT_ARG_SIZE / sizeof(sljit_sw)); +free_stack(common, callout_arg_size); /* Check return value. */ -OP2(SLJIT_SUB | SLJIT_SET_S, SLJIT_UNUSED, 0, SLJIT_RETURN_REG, 0, SLJIT_IMM, 0); +OP2(SLJIT_SUB | SLJIT_SET_Z | SLJIT_SET_SIG_GREATER, SLJIT_UNUSED, 0, SLJIT_RETURN_REG, 0, SLJIT_IMM, 0); add_jump(compiler, &backtrack->topbacktracks, JUMP(SLJIT_SIG_GREATER)); -if (common->forced_quit_label == NULL) - add_jump(compiler, &common->forced_quit, JUMP(SLJIT_SIG_LESS)); +if (common->abort_label == NULL) + add_jump(compiler, &common->abort, JUMP(SLJIT_NOT_EQUAL) /* SIG_LESS */); else - JUMPTO(SLJIT_SIG_LESS, common->forced_quit_label); + JUMPTO(SLJIT_NOT_EQUAL /* SIG_LESS */, common->abort_label); return cc + callout_length; } @@ -7282,6 +8091,7 @@ static PCRE2_SPTR compile_assert_matchingpath(compiler_common *common, PCRE2_SPT DEFINE_COMPILER; int framesize; int extrasize; +BOOL local_quit_available = FALSE; BOOL needs_control_head; int private_data_ptr; backtrack_common altbacktrack; @@ -7292,13 +8102,13 @@ jump_list *tmp = NULL; jump_list **target = (conditional) ? &backtrack->condfailed : &backtrack->common.topbacktracks; jump_list **found; /* Saving previous accept variables. */ -BOOL save_local_exit = common->local_exit; -BOOL save_positive_assert = common->positive_assert; +BOOL save_local_quit_available = common->local_quit_available; +BOOL save_in_positive_assertion = common->in_positive_assertion; then_trap_backtrack *save_then_trap = common->then_trap; struct sljit_label *save_quit_label = common->quit_label; struct sljit_label *save_accept_label = common->accept_label; jump_list *save_quit = common->quit; -jump_list *save_positive_assert_quit = common->positive_assert_quit; +jump_list *save_positive_assertion_quit = common->positive_assertion_quit; jump_list *save_accept = common->accept; struct sljit_jump *jump; struct sljit_jump *brajump = NULL; @@ -7365,7 +8175,7 @@ else allocate_stack(common, framesize + extrasize); OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr); - OP2(SLJIT_SUB, TMP2, 0, STACK_TOP, 0, SLJIT_IMM, (framesize + extrasize) * sizeof(sljit_sw)); + OP2(SLJIT_ADD, TMP2, 0, STACK_TOP, 0, SLJIT_IMM, (framesize + extrasize) * sizeof(sljit_sw)); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, TMP2, 0); if (needs_control_head) OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr); @@ -7380,21 +8190,21 @@ else else OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), TMP1, 0); - init_frame(common, ccbegin, NULL, framesize + extrasize - 1, extrasize, FALSE); + init_frame(common, ccbegin, NULL, framesize + extrasize - 1, extrasize); } memset(&altbacktrack, 0, sizeof(backtrack_common)); -if (opcode == OP_ASSERT_NOT || opcode == OP_ASSERTBACK_NOT) +if (conditional || (opcode == OP_ASSERT_NOT || opcode == OP_ASSERTBACK_NOT)) { - /* Negative assert is stronger than positive assert. */ - common->local_exit = TRUE; + /* Control verbs cannot escape from these asserts. */ + local_quit_available = TRUE; + common->local_quit_available = TRUE; common->quit_label = NULL; common->quit = NULL; - common->positive_assert = FALSE; } -else - common->positive_assert = TRUE; -common->positive_assert_quit = NULL; + +common->in_positive_assertion = (opcode == OP_ASSERT || opcode == OP_ASSERTBACK); +common->positive_assertion_quit = NULL; while (1) { @@ -7410,16 +8220,16 @@ while (1) compile_matchingpath(common, ccbegin + 1 + LINK_SIZE, cc, &altbacktrack); if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler))) { - if (opcode == OP_ASSERT_NOT || opcode == OP_ASSERTBACK_NOT) + if (local_quit_available) { - common->local_exit = save_local_exit; + common->local_quit_available = save_local_quit_available; common->quit_label = save_quit_label; common->quit = save_quit; } - common->positive_assert = save_positive_assert; + common->in_positive_assertion = save_in_positive_assertion; common->then_trap = save_then_trap; common->accept_label = save_accept_label; - common->positive_assert_quit = save_positive_assert_quit; + common->positive_assertion_quit = save_positive_assertion_quit; common->accept = save_accept; return NULL; } @@ -7436,23 +8246,24 @@ while (1) free_stack(common, extrasize); if (needs_control_head) - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, SLJIT_MEM1(STACK_TOP), 0); + OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, SLJIT_MEM1(STACK_TOP), STACK(-1)); } else { if ((opcode != OP_ASSERT_NOT && opcode != OP_ASSERTBACK_NOT) || conditional) { /* We don't need to keep the STR_PTR, only the previous private_data_ptr. */ - OP2(SLJIT_ADD, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr, SLJIT_IMM, (framesize + 1) * sizeof(sljit_sw)); + OP2(SLJIT_SUB, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr, SLJIT_IMM, (framesize + 1) * sizeof(sljit_sw)); if (needs_control_head) - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, SLJIT_MEM1(STACK_TOP), 0); + OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, SLJIT_MEM1(STACK_TOP), STACK(-1)); } else { OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr); if (needs_control_head) - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, SLJIT_MEM1(STACK_TOP), (framesize + 1) * sizeof(sljit_sw)); + OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, SLJIT_MEM1(STACK_TOP), STACK(-framesize - 2)); add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL)); + OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, (framesize - 1) * sizeof(sljit_sw)); } } @@ -7462,25 +8273,25 @@ while (1) if (conditional) { if (extrasize > 0) - OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), needs_control_head ? sizeof(sljit_sw) : 0); + OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), needs_control_head ? STACK(-2) : STACK(-1)); } else if (bra == OP_BRAZERO) { if (framesize < 0) - OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), (extrasize - 1) * sizeof(sljit_sw)); + OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(-extrasize)); else { - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), framesize * sizeof(sljit_sw)); - OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), (framesize + extrasize - 1) * sizeof(sljit_sw)); + OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(-framesize - 1)); + OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(-framesize - extrasize)); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, TMP1, 0); } - OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, sizeof(sljit_sw)); + OP2(SLJIT_SUB, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, sizeof(sljit_sw)); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0); } else if (framesize >= 0) { /* For OP_BRA and OP_BRAMINZERO. */ - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, SLJIT_MEM1(STACK_TOP), framesize * sizeof(sljit_sw)); + OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, SLJIT_MEM1(STACK_TOP), STACK(-framesize - 1)); } } add_jump(compiler, found, JUMP(SLJIT_JUMP)); @@ -7488,16 +8299,16 @@ while (1) compile_backtrackingpath(common, altbacktrack.top); if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler))) { - if (opcode == OP_ASSERT_NOT || opcode == OP_ASSERTBACK_NOT) + if (local_quit_available) { - common->local_exit = save_local_exit; + common->local_quit_available = save_local_quit_available; common->quit_label = save_quit_label; common->quit = save_quit; } - common->positive_assert = save_positive_assert; + common->in_positive_assertion = save_in_positive_assertion; common->then_trap = save_then_trap; common->accept_label = save_accept_label; - common->positive_assert_quit = save_positive_assert_quit; + common->positive_assertion_quit = save_positive_assertion_quit; common->accept = save_accept; return NULL; } @@ -7510,26 +8321,26 @@ while (1) cc += GET(cc, 1); } -if (opcode == OP_ASSERT_NOT || opcode == OP_ASSERTBACK_NOT) +if (local_quit_available) { - SLJIT_ASSERT(common->positive_assert_quit == NULL); + SLJIT_ASSERT(common->positive_assertion_quit == NULL); /* Makes the check less complicated below. */ - common->positive_assert_quit = common->quit; + common->positive_assertion_quit = common->quit; } /* None of them matched. */ -if (common->positive_assert_quit != NULL) +if (common->positive_assertion_quit != NULL) { jump = JUMP(SLJIT_JUMP); - set_jumps(common->positive_assert_quit, LABEL()); + set_jumps(common->positive_assertion_quit, LABEL()); SLJIT_ASSERT(framesize != no_stack); if (framesize < 0) - OP2(SLJIT_ADD, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr, SLJIT_IMM, extrasize * sizeof(sljit_sw)); + OP2(SLJIT_SUB, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr, SLJIT_IMM, extrasize * sizeof(sljit_sw)); else { OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr); add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL)); - OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, (framesize + extrasize) * sizeof(sljit_sw)); + OP2(SLJIT_SUB, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, (extrasize + 1) * sizeof(sljit_sw)); } JUMPHERE(jump); } @@ -7578,18 +8389,18 @@ if (opcode == OP_ASSERT || opcode == OP_ASSERTBACK) { /* We know that STR_PTR was stored on the top of the stack. */ if (extrasize > 0) - OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), (extrasize - 1) * sizeof(sljit_sw)); + OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(-extrasize)); /* Keep the STR_PTR on the top of the stack. */ if (bra == OP_BRAZERO) { - OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, sizeof(sljit_sw)); + OP2(SLJIT_SUB, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, sizeof(sljit_sw)); if (extrasize == 2) OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0); } else if (bra == OP_BRAMINZERO) { - OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, sizeof(sljit_sw)); + OP2(SLJIT_SUB, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, sizeof(sljit_sw)); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0); } } @@ -7598,13 +8409,13 @@ if (opcode == OP_ASSERT || opcode == OP_ASSERTBACK) if (bra == OP_BRA) { /* We don't need to keep the STR_PTR, only the previous private_data_ptr. */ - OP2(SLJIT_ADD, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr, SLJIT_IMM, (framesize + 1) * sizeof(sljit_sw)); - OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), (extrasize - 2) * sizeof(sljit_sw)); + OP2(SLJIT_SUB, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr, SLJIT_IMM, (framesize + 1) * sizeof(sljit_sw)); + OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(-extrasize + 1)); } else { /* We don't need to keep the STR_PTR, only the previous private_data_ptr. */ - OP2(SLJIT_ADD, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr, SLJIT_IMM, (framesize + 2) * sizeof(sljit_sw)); + OP2(SLJIT_SUB, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr, SLJIT_IMM, (framesize + 2) * sizeof(sljit_sw)); if (extrasize == 2) { OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); @@ -7632,7 +8443,9 @@ if (opcode == OP_ASSERT || opcode == OP_ASSERTBACK) { OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr); add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL)); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, SLJIT_MEM1(STACK_TOP), framesize * sizeof(sljit_sw)); + OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(-2)); + OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, (framesize - 1) * sizeof(sljit_sw)); + OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, TMP1, 0); } set_jumps(backtrack->common.topbacktracks, LABEL()); } @@ -7685,16 +8498,16 @@ else } } -if (opcode == OP_ASSERT_NOT || opcode == OP_ASSERTBACK_NOT) +if (local_quit_available) { - common->local_exit = save_local_exit; + common->local_quit_available = save_local_quit_available; common->quit_label = save_quit_label; common->quit = save_quit; } -common->positive_assert = save_positive_assert; +common->in_positive_assertion = save_in_positive_assertion; common->then_trap = save_then_trap; common->accept_label = save_accept_label; -common->positive_assert_quit = save_positive_assert_quit; +common->positive_assertion_quit = save_positive_assertion_quit; common->accept = save_accept; return cc + 1 + LINK_SIZE; } @@ -7719,23 +8532,23 @@ if (framesize < 0) } if (needs_control_head) - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), (ket != OP_KET || has_alternatives) ? sizeof(sljit_sw) : 0); + OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), (ket != OP_KET || has_alternatives) ? STACK(-2) : STACK(-1)); /* TMP2 which is set here used by OP_KETRMAX below. */ if (ket == OP_KETRMAX) - OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), 0); + OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), STACK(-1)); else if (ket == OP_KETRMIN) { /* Move the STR_PTR to the private_data_ptr. */ - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, SLJIT_MEM1(STACK_TOP), 0); + OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, SLJIT_MEM1(STACK_TOP), STACK(-1)); } } else { stacksize = (ket != OP_KET || has_alternatives) ? 2 : 1; - OP2(SLJIT_ADD, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr, SLJIT_IMM, (framesize + stacksize) * sizeof(sljit_sw)); + OP2(SLJIT_SUB, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr, SLJIT_IMM, (framesize + stacksize) * sizeof(sljit_sw)); if (needs_control_head) - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), 0); + OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(-1)); if (ket == OP_KETRMAX) { @@ -7822,7 +8635,6 @@ return stacksize; (|) OP_*BRA | OP_ALT ... M A (?()|) OP_*COND | OP_ALT M A (?>|) OP_ONCE | OP_ALT ... [stack trace] M A - (?>|) OP_ONCE_NC | OP_ALT ... [stack trace] M A Or nothing, if trace is unnecessary */ @@ -7890,8 +8702,6 @@ if (SLJIT_UNLIKELY(opcode == OP_COND || opcode == OP_SCOND)) if (SLJIT_UNLIKELY(opcode == OP_COND) && (*cc == OP_KETRMAX || *cc == OP_KETRMIN)) opcode = OP_SCOND; -if (SLJIT_UNLIKELY(opcode == OP_ONCE_NC)) - opcode = OP_ONCE; if (opcode == OP_CBRA || opcode == OP_SCBRA) { @@ -7968,7 +8778,7 @@ if (bra == OP_BRAMINZERO) { /* Except when the whole stack frame must be saved. */ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr); - braminzero = CMP(SLJIT_EQUAL, STR_PTR, 0, SLJIT_MEM1(TMP1), (BACKTRACK_AS(bracket_backtrack)->u.framesize + 1) * sizeof(sljit_sw)); + braminzero = CMP(SLJIT_EQUAL, STR_PTR, 0, SLJIT_MEM1(TMP1), STACK(-BACKTRACK_AS(bracket_backtrack)->u.framesize - 2)); } JUMPHERE(skip); } @@ -8041,7 +8851,7 @@ if (opcode == OP_ONCE) OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize), STR_PTR, 0); if (BACKTRACK_AS(bracket_backtrack)->u.framesize == no_frame) - OP2(SLJIT_SUB, SLJIT_MEM1(SLJIT_SP), private_data_ptr, STACK_TOP, 0, SLJIT_IMM, needs_control_head ? (2 * sizeof(sljit_sw)) : sizeof(sljit_sw)); + OP2(SLJIT_ADD, SLJIT_MEM1(SLJIT_SP), private_data_ptr, STACK_TOP, 0, SLJIT_IMM, needs_control_head ? (2 * sizeof(sljit_sw)) : sizeof(sljit_sw)); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize + 1), TMP2, 0); } else if (ket == OP_KETRMAX || has_alternatives) @@ -8059,7 +8869,7 @@ if (opcode == OP_ONCE) OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), TMP2, 0); OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr); - OP2(SLJIT_SUB, TMP2, 0, STACK_TOP, 0, SLJIT_IMM, stacksize * sizeof(sljit_sw)); + OP2(SLJIT_ADD, TMP2, 0, STACK_TOP, 0, SLJIT_IMM, stacksize * sizeof(sljit_sw)); stacksize = needs_control_head ? 1 : 0; if (ket != OP_KET || has_alternatives) @@ -8074,7 +8884,7 @@ if (opcode == OP_ONCE) OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, TMP2, 0); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize), TMP1, 0); } - init_frame(common, ccbegin, NULL, BACKTRACK_AS(bracket_backtrack)->u.framesize + stacksize, stacksize + 1, FALSE); + init_frame(common, ccbegin, NULL, BACKTRACK_AS(bracket_backtrack)->u.framesize + stacksize, stacksize + 1); } } else if (opcode == OP_CBRA || opcode == OP_SCBRA) @@ -8131,13 +8941,13 @@ if (opcode == OP_COND || opcode == OP_SCOND) slot = common->name_table + GET2(matchingpath, 1) * common->name_entry_size; OP1(SLJIT_MOV, TMP3, 0, STR_PTR, 0); OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(1)); - OP2(SLJIT_SUB | SLJIT_SET_E, TMP2, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(GET2(slot, 0) << 1), TMP1, 0); + OP2(SLJIT_SUB | SLJIT_SET_Z, TMP2, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(GET2(slot, 0) << 1), TMP1, 0); slot += common->name_entry_size; i--; while (i-- > 0) { OP2(SLJIT_SUB, STR_PTR, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(GET2(slot, 0) << 1), TMP1, 0); - OP2(SLJIT_OR | SLJIT_SET_E, TMP2, 0, TMP2, 0, STR_PTR, 0); + OP2(SLJIT_OR | SLJIT_SET_Z, TMP2, 0, TMP2, 0, STR_PTR, 0); slot += common->name_entry_size; } OP1(SLJIT_MOV, STR_PTR, 0, TMP3, 0); @@ -8290,7 +9100,7 @@ if (ket == OP_KETRMAX) { if (has_alternatives) BACKTRACK_AS(bracket_backtrack)->alternative_matchingpath = LABEL(); - OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_MEM1(SLJIT_SP), repeat_ptr, SLJIT_MEM1(SLJIT_SP), repeat_ptr, SLJIT_IMM, 1); + OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_MEM1(SLJIT_SP), repeat_ptr, SLJIT_MEM1(SLJIT_SP), repeat_ptr, SLJIT_IMM, 1); JUMPTO(SLJIT_NOT_ZERO, rmax_label); /* Drop STR_PTR for greedy plus quantifier. */ if (opcode != OP_ONCE) @@ -8320,7 +9130,7 @@ if (ket == OP_KETRMAX) if (repeat_type == OP_EXACT) { count_match(common); - OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_MEM1(SLJIT_SP), repeat_ptr, SLJIT_MEM1(SLJIT_SP), repeat_ptr, SLJIT_IMM, 1); + OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_MEM1(SLJIT_SP), repeat_ptr, SLJIT_MEM1(SLJIT_SP), repeat_ptr, SLJIT_IMM, 1); JUMPTO(SLJIT_NOT_ZERO, rmax_label); } else if (repeat_type == OP_UPTO) @@ -8348,6 +9158,7 @@ if (bra == OP_BRAMINZERO) { OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr); add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL)); + OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, (BACKTRACK_AS(bracket_backtrack)->u.framesize - 1) * sizeof(sljit_sw)); } else if (ket == OP_KETRMIN && opcode != OP_ONCE) free_stack(common, 1); @@ -8420,7 +9231,7 @@ switch(opcode) break; default: - SLJIT_ASSERT_STOP(); + SLJIT_UNREACHABLE(); break; } @@ -8498,7 +9309,7 @@ else OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr); if (needs_control_head) OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr); - OP2(SLJIT_SUB, SLJIT_MEM1(SLJIT_SP), private_data_ptr, STACK_TOP, 0, SLJIT_IMM, -STACK(stacksize - 1)); + OP2(SLJIT_ADD, SLJIT_MEM1(SLJIT_SP), private_data_ptr, STACK_TOP, 0, SLJIT_IMM, stacksize * sizeof(sljit_sw)); stack = 0; if (!zero) @@ -8517,7 +9328,7 @@ else stack++; } OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stack), TMP1, 0); - init_frame(common, cc, NULL, stacksize - 1, stacksize - framesize, FALSE); + init_frame(common, cc, NULL, stacksize - 1, stacksize - framesize); stack -= 1 + (offset == 0); } @@ -8570,7 +9381,7 @@ while (*cc != OP_KETRPOS) { if (offset != 0) { - OP2(SLJIT_ADD, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr, SLJIT_IMM, stacksize * sizeof(sljit_sw)); + OP2(SLJIT_SUB, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr, SLJIT_IMM, stacksize * sizeof(sljit_sw)); OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), cbraprivptr); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset + 1), STR_PTR, 0); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), cbraprivptr, STR_PTR, 0); @@ -8581,10 +9392,10 @@ while (*cc != OP_KETRPOS) else { OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr); - OP2(SLJIT_ADD, STACK_TOP, 0, TMP2, 0, SLJIT_IMM, stacksize * sizeof(sljit_sw)); + OP2(SLJIT_SUB, STACK_TOP, 0, TMP2, 0, SLJIT_IMM, stacksize * sizeof(sljit_sw)); if (opcode == OP_SBRAPOS) - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP2), (framesize + 1) * sizeof(sljit_sw)); - OP1(SLJIT_MOV, SLJIT_MEM1(TMP2), (framesize + 1) * sizeof(sljit_sw), STR_PTR, 0); + OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP2), STACK(-framesize - 2)); + OP1(SLJIT_MOV, SLJIT_MEM1(TMP2), STACK(-framesize - 2), STR_PTR, 0); } /* Even if the match is empty, we need to reset the control head. */ @@ -8630,7 +9441,7 @@ while (*cc != OP_KETRPOS) else { OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr); - OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(TMP2), (framesize + 1) * sizeof(sljit_sw)); + OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(TMP2), STACK(-framesize - 2)); } } @@ -8647,7 +9458,7 @@ if (!zero) if (framesize < 0) add_jump(compiler, &backtrack->topbacktracks, CMP(SLJIT_NOT_EQUAL, SLJIT_MEM1(STACK_TOP), STACK(stacksize - 1), SLJIT_IMM, 0)); else /* TMP2 is set to [private_data_ptr] above. */ - add_jump(compiler, &backtrack->topbacktracks, CMP(SLJIT_NOT_EQUAL, SLJIT_MEM1(TMP2), (stacksize - 1) * sizeof(sljit_sw), SLJIT_IMM, 0)); + add_jump(compiler, &backtrack->topbacktracks, CMP(SLJIT_NOT_EQUAL, SLJIT_MEM1(TMP2), STACK(-stacksize), SLJIT_IMM, 0)); } /* None of them matched. */ @@ -8870,7 +9681,7 @@ if (exact > 1) OP1(SLJIT_MOV, tmp_base, tmp_offset, SLJIT_IMM, exact); label = LABEL(); compile_char1_matchingpath(common, type, cc, &backtrack->topbacktracks, FALSE); - OP2(SLJIT_SUB | SLJIT_SET_E, tmp_base, tmp_offset, tmp_base, tmp_offset, SLJIT_IMM, 1); + OP2(SLJIT_SUB | SLJIT_SET_Z, tmp_base, tmp_offset, tmp_base, tmp_offset, SLJIT_IMM, 1); JUMPTO(SLJIT_NOT_ZERO, label); } else @@ -8878,7 +9689,7 @@ if (exact > 1) OP1(SLJIT_MOV, tmp_base, tmp_offset, SLJIT_IMM, exact); label = LABEL(); compile_char1_matchingpath(common, type, cc, &backtrack->topbacktracks, TRUE); - OP2(SLJIT_SUB | SLJIT_SET_E, tmp_base, tmp_offset, tmp_base, tmp_offset, SLJIT_IMM, 1); + OP2(SLJIT_SUB | SLJIT_SET_Z, tmp_base, tmp_offset, tmp_base, tmp_offset, SLJIT_IMM, 1); JUMPTO(SLJIT_NOT_ZERO, label); } } @@ -8908,7 +9719,7 @@ switch(opcode) if (opcode == OP_UPTO) { OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), POSSESSIVE0); - OP2(SLJIT_SUB | SLJIT_SET_E, TMP1, 0, TMP1, 0, SLJIT_IMM, 1); + OP2(SLJIT_SUB | SLJIT_SET_Z, TMP1, 0, TMP1, 0, SLJIT_IMM, 1); jump = JUMP(SLJIT_ZERO); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), POSSESSIVE0, TMP1, 0); } @@ -8970,7 +9781,7 @@ switch(opcode) label = LABEL(); if (opcode == OP_UPTO) { - OP2(SLJIT_SUB | SLJIT_SET_E, tmp_base, tmp_offset, tmp_base, tmp_offset, SLJIT_IMM, 1); + OP2(SLJIT_SUB | SLJIT_SET_Z, tmp_base, tmp_offset, tmp_base, tmp_offset, SLJIT_IMM, 1); add_jump(compiler, &backtrack->topbacktracks, JUMP(SLJIT_ZERO)); } compile_char1_matchingpath(common, type, cc, &backtrack->topbacktracks, FALSE); @@ -8990,7 +9801,7 @@ switch(opcode) OP1(SLJIT_MOV, base, offset1, STR_PTR, 0); if (opcode == OP_UPTO) { - OP2(SLJIT_SUB | SLJIT_SET_E, tmp_base, tmp_offset, tmp_base, tmp_offset, SLJIT_IMM, 1); + OP2(SLJIT_SUB | SLJIT_SET_Z, tmp_base, tmp_offset, tmp_base, tmp_offset, SLJIT_IMM, 1); add_jump(compiler, &no_match, JUMP(SLJIT_ZERO)); } @@ -9017,7 +9828,7 @@ switch(opcode) if (opcode == OP_UPTO) { - OP2(SLJIT_SUB | SLJIT_SET_E, tmp_base, tmp_offset, tmp_base, tmp_offset, SLJIT_IMM, 1); + OP2(SLJIT_SUB | SLJIT_SET_Z, tmp_base, tmp_offset, tmp_base, tmp_offset, SLJIT_IMM, 1); JUMPTO(SLJIT_NOT_ZERO, label); } else @@ -9046,7 +9857,7 @@ switch(opcode) if (opcode == OP_UPTO) { - OP2(SLJIT_SUB | SLJIT_SET_E, tmp_base, tmp_offset, tmp_base, tmp_offset, SLJIT_IMM, 1); + OP2(SLJIT_SUB | SLJIT_SET_Z, tmp_base, tmp_offset, tmp_base, tmp_offset, SLJIT_IMM, 1); JUMPTO(SLJIT_NOT_ZERO, label); } else @@ -9072,7 +9883,7 @@ switch(opcode) compile_char1_matchingpath(common, type, cc, &no_char1_match, FALSE); if (opcode == OP_UPTO) { - OP2(SLJIT_SUB | SLJIT_SET_E, tmp_base, tmp_offset, tmp_base, tmp_offset, SLJIT_IMM, 1); + OP2(SLJIT_SUB | SLJIT_SET_Z, tmp_base, tmp_offset, tmp_base, tmp_offset, SLJIT_IMM, 1); JUMPTO(SLJIT_NOT_ZERO, label); OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); } @@ -9159,7 +9970,7 @@ switch(opcode) label = LABEL(); compile_char1_matchingpath(common, type, cc, &no_match, TRUE); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), POSSESSIVE1, STR_PTR, 0); - OP2(SLJIT_SUB | SLJIT_SET_E, tmp_base, tmp_offset, tmp_base, tmp_offset, SLJIT_IMM, 1); + OP2(SLJIT_SUB | SLJIT_SET_Z, tmp_base, tmp_offset, tmp_base, tmp_offset, SLJIT_IMM, 1); JUMPTO(SLJIT_NOT_ZERO, label); set_jumps(no_match, LABEL()); OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(SLJIT_SP), POSSESSIVE1); @@ -9170,7 +9981,7 @@ switch(opcode) label = LABEL(); detect_partial_match(common, &no_match); compile_char1_matchingpath(common, type, cc, &no_char1_match, FALSE); - OP2(SLJIT_SUB | SLJIT_SET_E, tmp_base, tmp_offset, tmp_base, tmp_offset, SLJIT_IMM, 1); + OP2(SLJIT_SUB | SLJIT_SET_Z, tmp_base, tmp_offset, tmp_base, tmp_offset, SLJIT_IMM, 1); JUMPTO(SLJIT_NOT_ZERO, label); OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); set_jumps(no_char1_match, LABEL()); @@ -9188,7 +9999,7 @@ switch(opcode) break; default: - SLJIT_ASSERT_STOP(); + SLJIT_UNREACHABLE(); break; } @@ -9209,6 +10020,9 @@ if (*cc == OP_FAIL) return cc + 1; } +if (*cc == OP_ACCEPT && common->currententry == NULL && (common->re->overall_options & PCRE2_ENDANCHORED) != 0) + add_jump(compiler, &common->reset_match, CMP(SLJIT_NOT_EQUAL, STR_PTR, 0, STR_END, 0)); + if (*cc == OP_ASSERT_ACCEPT || common->currententry != NULL || !common->might_be_empty) { /* No need to check notempty conditions. */ @@ -9225,9 +10039,9 @@ else CMPTO(SLJIT_NOT_EQUAL, STR_PTR, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(0), common->accept_label); OP1(SLJIT_MOV, TMP1, 0, ARGUMENTS, 0); OP1(SLJIT_MOV_U32, TMP2, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, options)); -OP2(SLJIT_AND | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP2, 0, SLJIT_IMM, PCRE2_NOTEMPTY); +OP2(SLJIT_AND | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP2, 0, SLJIT_IMM, PCRE2_NOTEMPTY); add_jump(compiler, &backtrack->topbacktracks, JUMP(SLJIT_NOT_ZERO)); -OP2(SLJIT_AND | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP2, 0, SLJIT_IMM, PCRE2_NOTEMPTY_ATSTART); +OP2(SLJIT_AND | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP2, 0, SLJIT_IMM, PCRE2_NOTEMPTY_ATSTART); if (common->accept_label == NULL) add_jump(compiler, &common->accept, JUMP(SLJIT_ZERO)); else @@ -9311,7 +10125,7 @@ size = 3 + (size < 0 ? 0 : size); OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr); allocate_stack(common, size); if (size > 3) - OP2(SLJIT_SUB, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, STACK_TOP, 0, SLJIT_IMM, (size - 3) * sizeof(sljit_sw)); + OP2(SLJIT_ADD, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, STACK_TOP, 0, SLJIT_IMM, (size - 3) * sizeof(sljit_sw)); else OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, STACK_TOP, 0); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(size - 1), SLJIT_IMM, BACKTRACK_AS(then_trap_backtrack)->start); @@ -9320,7 +10134,7 @@ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(size - 3), TMP2, 0); size = BACKTRACK_AS(then_trap_backtrack)->framesize; if (size >= 0) - init_frame(common, cc, ccend, size - 1, 0, FALSE); + init_frame(common, cc, ccend, size - 1, 0); } static void compile_matchingpath(compiler_common *common, PCRE2_SPTR cc, PCRE2_SPTR ccend, backtrack_common *parent) @@ -9542,7 +10356,6 @@ while (cc < ccend) break; case OP_ONCE: - case OP_ONCE_NC: case OP_BRA: case OP_CBRA: case OP_COND: @@ -9617,7 +10430,7 @@ while (cc < ccend) break; default: - SLJIT_ASSERT_STOP(); + SLJIT_UNREACHABLE(); return; } if (cc == NULL) @@ -9725,7 +10538,7 @@ switch(opcode) case OP_MINUPTO: OP1(SLJIT_MOV, TMP1, 0, base, offset1); OP1(SLJIT_MOV, STR_PTR, 0, base, offset0); - OP2(SLJIT_SUB | SLJIT_SET_E, TMP1, 0, TMP1, 0, SLJIT_IMM, 1); + OP2(SLJIT_SUB | SLJIT_SET_Z, TMP1, 0, TMP1, 0, SLJIT_IMM, 1); add_jump(compiler, &jumplist, JUMP(SLJIT_ZERO)); OP1(SLJIT_MOV, base, offset1, TMP1, 0); @@ -9771,7 +10584,7 @@ switch(opcode) break; default: - SLJIT_ASSERT_STOP(); + SLJIT_UNREACHABLE(); break; } @@ -9806,27 +10619,21 @@ free_stack(common, ref ? 2 : 3); static SLJIT_INLINE void compile_recurse_backtrackingpath(compiler_common *common, struct backtrack_common *current) { DEFINE_COMPILER; +recurse_entry *entry; -if (CURRENT_AS(recurse_backtrack)->inlined_pattern) - compile_backtrackingpath(common, current->top); -set_jumps(current->topbacktracks, LABEL()); -if (CURRENT_AS(recurse_backtrack)->inlined_pattern) - return; - -if (common->has_set_som && common->mark_ptr != 0) +if (!CURRENT_AS(recurse_backtrack)->inlined_pattern) { - OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(1)); - free_stack(common, 2); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(0), TMP2, 0); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->mark_ptr, TMP1, 0); - } -else if (common->has_set_som || common->mark_ptr != 0) - { - OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); - free_stack(common, 1); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->has_set_som ? (int)(OVECTOR(0)) : common->mark_ptr, TMP2, 0); + entry = CURRENT_AS(recurse_backtrack)->entry; + if (entry->backtrack_label == NULL) + add_jump(compiler, &entry->backtrack_calls, JUMP(SLJIT_FAST_CALL)); + else + JUMPTO(SLJIT_FAST_CALL, entry->backtrack_label); + CMPTO(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, 0, CURRENT_AS(recurse_backtrack)->matchingpath); } +else + compile_backtrackingpath(common, current->top); + +set_jumps(current->topbacktracks, LABEL()); } static void compile_assert_backtrackingpath(compiler_common *common, struct backtrack_common *current) @@ -9879,7 +10686,9 @@ if (*cc == OP_ASSERT || *cc == OP_ASSERTBACK) { OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), CURRENT_AS(assert_backtrack)->private_data_ptr); add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL)); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), CURRENT_AS(assert_backtrack)->private_data_ptr, SLJIT_MEM1(STACK_TOP), CURRENT_AS(assert_backtrack)->framesize * sizeof(sljit_sw)); + OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(-2)); + OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, (CURRENT_AS(assert_backtrack)->framesize - 1) * sizeof(sljit_sw)); + OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), CURRENT_AS(assert_backtrack)->private_data_ptr, TMP1, 0); set_jumps(current->topbacktracks, LABEL()); } @@ -9889,7 +10698,7 @@ else if (bra == OP_BRAZERO) { /* We know there is enough place on the stack. */ - OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, sizeof(sljit_sw)); + OP2(SLJIT_SUB, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, sizeof(sljit_sw)); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0); JUMPTO(SLJIT_JUMP, CURRENT_AS(assert_backtrack)->matchingpath); JUMPHERE(brajump); @@ -9949,8 +10758,6 @@ if (opcode == OP_CBRA || opcode == OP_SCBRA) offset = (GET2(ccbegin, 1 + LINK_SIZE)) << 1; if (SLJIT_UNLIKELY(opcode == OP_COND) && (*cc == OP_KETRMAX || *cc == OP_KETRMIN)) opcode = OP_SCOND; -if (SLJIT_UNLIKELY(opcode == OP_ONCE_NC)) - opcode = OP_ONCE; alt_max = has_alternatives ? no_alternatives(ccbegin) : 0; @@ -10002,7 +10809,7 @@ else if (ket == OP_KETRMIN) else { OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr); - CMPTO(SLJIT_NOT_EQUAL, STR_PTR, 0, SLJIT_MEM1(TMP1), (CURRENT_AS(bracket_backtrack)->u.framesize + 1) * sizeof(sljit_sw), CURRENT_AS(bracket_backtrack)->recursive_matchingpath); + CMPTO(SLJIT_NOT_EQUAL, STR_PTR, 0, SLJIT_MEM1(TMP1), STACK(-CURRENT_AS(bracket_backtrack)->u.framesize - 2), CURRENT_AS(bracket_backtrack)->recursive_matchingpath); } /* Drop STR_PTR for non-greedy plus quantifier. */ if (opcode != OP_ONCE) @@ -10056,6 +10863,7 @@ if (SLJIT_UNLIKELY(opcode == OP_ONCE)) { OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr); add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL)); + OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, (CURRENT_AS(bracket_backtrack)->u.framesize - 1) * sizeof(sljit_sw)); } once = JUMP(SLJIT_JUMP); } @@ -10108,7 +10916,9 @@ if (SLJIT_UNLIKELY(opcode == OP_COND) || SLJIT_UNLIKELY(opcode == OP_SCOND)) { OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), assert->private_data_ptr); add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL)); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), assert->private_data_ptr, SLJIT_MEM1(STACK_TOP), assert->framesize * sizeof(sljit_sw)); + OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(-2)); + OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, (assert->framesize - 1) * sizeof(sljit_sw)); + OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), assert->private_data_ptr, TMP1, 0); } cond = JUMP(SLJIT_JUMP); set_jumps(CURRENT_AS(bracket_backtrack)->u.assert->condfailed, LABEL()); @@ -10249,7 +11059,9 @@ if (has_alternatives) { OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), assert->private_data_ptr); add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL)); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), assert->private_data_ptr, SLJIT_MEM1(STACK_TOP), assert->framesize * sizeof(sljit_sw)); + OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(-2)); + OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, (assert->framesize - 1) * sizeof(sljit_sw)); + OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), assert->private_data_ptr, TMP1, 0); } JUMPHERE(cond); } @@ -10304,7 +11116,7 @@ else if (opcode == OP_ONCE) JUMPHERE(once); /* Restore previous private_data_ptr */ if (CURRENT_AS(bracket_backtrack)->u.framesize >= 0) - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, SLJIT_MEM1(STACK_TOP), CURRENT_AS(bracket_backtrack)->u.framesize * sizeof(sljit_sw)); + OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, SLJIT_MEM1(STACK_TOP), STACK(-CURRENT_AS(bracket_backtrack)->u.framesize - 1)); else if (ket == OP_KETRMIN) { OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(1)); @@ -10385,6 +11197,7 @@ if (CURRENT_AS(bracketpos_backtrack)->framesize < 0) OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), CURRENT_AS(bracketpos_backtrack)->private_data_ptr); add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL)); +OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, (CURRENT_AS(bracketpos_backtrack)->framesize - 1) * sizeof(sljit_sw)); if (current->topbacktracks) { @@ -10394,7 +11207,7 @@ if (current->topbacktracks) free_stack(common, CURRENT_AS(bracketpos_backtrack)->stacksize); JUMPHERE(jump); } -OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), CURRENT_AS(bracketpos_backtrack)->private_data_ptr, SLJIT_MEM1(STACK_TOP), CURRENT_AS(bracketpos_backtrack)->framesize * sizeof(sljit_sw)); +OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), CURRENT_AS(bracketpos_backtrack)->private_data_ptr, SLJIT_MEM1(STACK_TOP), STACK(-CURRENT_AS(bracketpos_backtrack)->framesize - 1)); } static SLJIT_INLINE void compile_braminzero_backtrackingpath(compiler_common *common, struct backtrack_common *current) @@ -10440,22 +11253,23 @@ if (opcode == OP_THEN || opcode == OP_THEN_ARG) jump = JUMP(SLJIT_JUMP); loop = LABEL(); - OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(STACK_TOP), -(int)sizeof(sljit_sw)); + OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); JUMPHERE(jump); - CMPTO(SLJIT_NOT_EQUAL, SLJIT_MEM1(STACK_TOP), -(int)(2 * sizeof(sljit_sw)), TMP1, 0, loop); - CMPTO(SLJIT_NOT_EQUAL, SLJIT_MEM1(STACK_TOP), -(int)(3 * sizeof(sljit_sw)), TMP2, 0, loop); + CMPTO(SLJIT_NOT_EQUAL, SLJIT_MEM1(STACK_TOP), STACK(1), TMP1, 0, loop); + CMPTO(SLJIT_NOT_EQUAL, SLJIT_MEM1(STACK_TOP), STACK(2), TMP2, 0, loop); add_jump(compiler, &common->then_trap->quit, JUMP(SLJIT_JUMP)); return; } - else if (common->positive_assert) + else if (!common->local_quit_available && common->in_positive_assertion) { - add_jump(compiler, &common->positive_assert_quit, JUMP(SLJIT_JUMP)); + add_jump(compiler, &common->positive_assertion_quit, JUMP(SLJIT_JUMP)); return; } } -if (common->local_exit) +if (common->local_quit_available) { + /* Abort match with a fail. */ if (common->quit_label == NULL) add_jump(compiler, &common->quit, JUMP(SLJIT_JUMP)); else @@ -10506,7 +11320,10 @@ jump = JUMP(SLJIT_JUMP); set_jumps(CURRENT_AS(then_trap_backtrack)->quit, LABEL()); /* STACK_TOP is set by THEN. */ if (CURRENT_AS(then_trap_backtrack)->framesize >= 0) + { add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL)); + OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, (CURRENT_AS(then_trap_backtrack)->framesize - 1) * sizeof(sljit_sw)); + } OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); free_stack(common, 3); @@ -10623,7 +11440,6 @@ while (current) break; case OP_ONCE: - case OP_ONCE_NC: case OP_BRA: case OP_CBRA: case OP_COND: @@ -10672,7 +11488,7 @@ while (current) break; case OP_COMMIT: - if (!common->local_exit) + if (!common->local_quit_available) OP1(SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_IMM, PCRE2_ERROR_NOMATCH); if (common->quit_label == NULL) add_jump(compiler, &common->quit, JUMP(SLJIT_JUMP)); @@ -10694,7 +11510,7 @@ while (current) break; default: - SLJIT_ASSERT_STOP(); + SLJIT_UNREACHABLE(); break; } current = current->prev; @@ -10709,38 +11525,52 @@ PCRE2_SPTR cc = common->start + common->currententry->start; PCRE2_SPTR ccbegin = cc + 1 + LINK_SIZE + (*cc == OP_BRA ? 0 : IMM2_SIZE); PCRE2_SPTR ccend = bracketend(cc) - (1 + LINK_SIZE); BOOL needs_control_head; -int framesize = get_framesize(common, cc, NULL, TRUE, &needs_control_head); -int private_data_size = get_private_data_copy_length(common, ccbegin, ccend, needs_control_head); -int alternativesize; -BOOL needs_frame; +BOOL has_quit; +BOOL has_accept; +int private_data_size = get_recurse_data_length(common, ccbegin, ccend, &needs_control_head, &has_quit, &has_accept); +int alt_count, alt_max, local_size; backtrack_common altbacktrack; -struct sljit_jump *jump; +jump_list *match = NULL; +sljit_uw *next_update_addr = NULL; +struct sljit_jump *alt1 = NULL; +struct sljit_jump *alt2 = NULL; +struct sljit_jump *accept_exit = NULL; +struct sljit_label *quit; /* Recurse captures then. */ common->then_trap = NULL; SLJIT_ASSERT(*cc == OP_BRA || *cc == OP_CBRA || *cc == OP_CBRAPOS || *cc == OP_SCBRA || *cc == OP_SCBRAPOS); -needs_frame = framesize >= 0; -if (!needs_frame) - framesize = 0; -alternativesize = *(cc + GET(cc, 1)) == OP_ALT ? 1 : 0; -SLJIT_ASSERT(common->currententry->entry == NULL && common->recursive_head_ptr != 0); -common->currententry->entry = LABEL(); -set_jumps(common->currententry->calls, common->currententry->entry); +alt_max = no_alternatives(cc); +alt_count = 0; + +/* Matching path. */ +SLJIT_ASSERT(common->currententry->entry_label == NULL && common->recursive_head_ptr != 0); +common->currententry->entry_label = LABEL(); +set_jumps(common->currententry->entry_calls, common->currententry->entry_label); sljit_emit_fast_enter(compiler, TMP2, 0); count_match(common); -allocate_stack(common, private_data_size + framesize + alternativesize); -OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(private_data_size + framesize + alternativesize - 1), TMP2, 0); -copy_private_data(common, ccbegin, ccend, TRUE, private_data_size + framesize + alternativesize, framesize + alternativesize, needs_control_head); + +local_size = (alt_max > 1) ? 2 : 1; + +/* (Reversed) stack layout: + [private data][return address][optional: str ptr] ... [optional: alternative index][recursive_head_ptr] */ + +allocate_stack(common, private_data_size + local_size); +/* Save return address. */ +OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(local_size - 1), TMP2, 0); + +copy_recurse_data(common, ccbegin, ccend, recurse_copy_from_global, local_size, private_data_size + local_size, has_quit); + +/* This variable is saved and restored all time when we enter or exit from a recursive context. */ +OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->recursive_head_ptr, STACK_TOP, 0); + if (needs_control_head) OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, SLJIT_IMM, 0); -OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->recursive_head_ptr, STACK_TOP, 0); -if (needs_frame) - init_frame(common, cc, NULL, framesize + alternativesize - 1, alternativesize, TRUE); -if (alternativesize > 0) +if (alt_max > 1) OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0); memset(&altbacktrack, 0, sizeof(backtrack_common)); @@ -10762,7 +11592,75 @@ while (1) if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler))) return; - add_jump(compiler, &common->accept, JUMP(SLJIT_JUMP)); + allocate_stack(common, (alt_max > 1 || has_accept) ? 2 : 1); + OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), common->recursive_head_ptr); + + if (alt_max > 1 || has_accept) + OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), SLJIT_IMM, alt_count); + + add_jump(compiler, &match, JUMP(SLJIT_JUMP)); + + if (alt_count == 0) + { + /* Backtracking path entry. */ + SLJIT_ASSERT(common->currententry->backtrack_label == NULL); + common->currententry->backtrack_label = LABEL(); + set_jumps(common->currententry->backtrack_calls, common->currententry->backtrack_label); + + sljit_emit_fast_enter(compiler, TMP1, 0); + + if (has_accept) + accept_exit = CMP(SLJIT_EQUAL, SLJIT_MEM1(STACK_TOP), STACK(1), SLJIT_IMM, alt_max * sizeof (sljit_sw)); + + OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); + /* Save return address. */ + OP1(SLJIT_MOV, SLJIT_MEM1(TMP2), STACK(local_size - 1), TMP1, 0); + + copy_recurse_data(common, ccbegin, ccend, recurse_swap_global, local_size, private_data_size + local_size, has_quit); + + if (alt_max > 1) + { + OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(1)); + free_stack(common, 2); + + if (alt_max > 4) + { + /* Table jump if alt_max is greater than 4. */ + next_update_addr = allocate_read_only_data(common, alt_max * sizeof(sljit_uw)); + if (SLJIT_UNLIKELY(next_update_addr == NULL)) + return; + sljit_emit_ijump(compiler, SLJIT_JUMP, SLJIT_MEM1(TMP1), (sljit_sw)next_update_addr); + add_label_addr(common, next_update_addr++); + } + else + { + if (alt_max == 4) + alt2 = CMP(SLJIT_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, 2 * sizeof(sljit_uw)); + alt1 = CMP(SLJIT_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, sizeof(sljit_uw)); + } + } + else + free_stack(common, has_accept ? 2 : 1); + } + else if (alt_max > 4) + add_label_addr(common, next_update_addr++); + else + { + if (alt_count != 2 * sizeof(sljit_uw)) + { + JUMPHERE(alt1); + if (alt_max == 3 && alt_count == sizeof(sljit_uw)) + alt2 = CMP(SLJIT_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, 2 * sizeof(sljit_uw)); + } + else + { + JUMPHERE(alt2); + if (alt_max == 4) + alt1 = CMP(SLJIT_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, 3 * sizeof(sljit_uw)); + } + } + + alt_count += sizeof(sljit_uw); compile_backtrackingpath(common, altbacktrack.top); if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler))) @@ -10776,55 +11674,65 @@ while (1) cc += GET(cc, 1); } -/* None of them matched. */ -OP1(SLJIT_MOV, TMP3, 0, SLJIT_IMM, 0); -jump = JUMP(SLJIT_JUMP); +/* No alternative is matched. */ + +quit = LABEL(); + +copy_recurse_data(common, ccbegin, ccend, recurse_copy_private_to_global, local_size, private_data_size + local_size, has_quit); + +OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), STACK(local_size - 1)); +free_stack(common, private_data_size + local_size); +OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, 0); +sljit_emit_fast_return(compiler, TMP2, 0); if (common->quit != NULL) { + SLJIT_ASSERT(has_quit); + set_jumps(common->quit, LABEL()); OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), common->recursive_head_ptr); - if (needs_frame) - { - OP2(SLJIT_SUB, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, (framesize + alternativesize) * sizeof(sljit_sw)); - add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL)); - OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, (framesize + alternativesize) * sizeof(sljit_sw)); - } - OP1(SLJIT_MOV, TMP3, 0, SLJIT_IMM, 0); - common->quit = NULL; - add_jump(compiler, &common->quit, JUMP(SLJIT_JUMP)); + copy_recurse_data(common, ccbegin, ccend, recurse_copy_shared_to_global, local_size, private_data_size + local_size, has_quit); + JUMPTO(SLJIT_JUMP, quit); } -set_jumps(common->accept, LABEL()); -OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), common->recursive_head_ptr); -if (needs_frame) +if (has_accept) { - OP2(SLJIT_SUB, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, (framesize + alternativesize) * sizeof(sljit_sw)); - add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL)); - OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, (framesize + alternativesize) * sizeof(sljit_sw)); - } -OP1(SLJIT_MOV, TMP3, 0, SLJIT_IMM, 1); + JUMPHERE(accept_exit); + free_stack(common, 2); -JUMPHERE(jump); -if (common->quit != NULL) - set_jumps(common->quit, LABEL()); -copy_private_data(common, ccbegin, ccend, FALSE, private_data_size + framesize + alternativesize, framesize + alternativesize, needs_control_head); -free_stack(common, private_data_size + framesize + alternativesize); -if (needs_control_head) - { - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), 2 * sizeof(sljit_sw)); - OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), sizeof(sljit_sw)); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->recursive_head_ptr, TMP1, 0); - OP1(SLJIT_MOV, TMP1, 0, TMP3, 0); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, TMP2, 0); + /* Save return address. */ + OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(local_size - 1), TMP1, 0); + + copy_recurse_data(common, ccbegin, ccend, recurse_copy_kept_shared_to_global, local_size, private_data_size + local_size, has_quit); + + OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), STACK(local_size - 1)); + free_stack(common, private_data_size + local_size); + OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, 0); + sljit_emit_fast_return(compiler, TMP2, 0); } -else + +if (common->accept != NULL) { - OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), sizeof(sljit_sw)); - OP1(SLJIT_MOV, TMP1, 0, TMP3, 0); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->recursive_head_ptr, TMP2, 0); + SLJIT_ASSERT(has_accept); + + set_jumps(common->accept, LABEL()); + + OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), common->recursive_head_ptr); + OP1(SLJIT_MOV, TMP2, 0, STACK_TOP, 0); + + allocate_stack(common, 2); + OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), SLJIT_IMM, alt_count); } -sljit_emit_fast_return(compiler, SLJIT_MEM1(STACK_TOP), 0); + +set_jumps(match, LABEL()); + +OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), TMP2, 0); + +copy_recurse_data(common, ccbegin, ccend, recurse_swap_global, local_size, private_data_size + local_size, has_quit); + +OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(TMP2), STACK(local_size - 1)); +OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, 1); +sljit_emit_fast_return(compiler, TMP2, 0); } #undef COMPILE_BACKTRACKINGPATH @@ -10856,11 +11764,13 @@ struct sljit_jump *jump; struct sljit_jump *minlength_check_failed = NULL; struct sljit_jump *reqbyte_notfound = NULL; struct sljit_jump *empty_match = NULL; +struct sljit_jump *end_anchor_failed = NULL; SLJIT_ASSERT(tables); memset(&rootbacktrack, 0, sizeof(backtrack_common)); memset(common, 0, sizeof(compiler_common)); +common->re = re; common->name_table = (PCRE2_SPTR)((uint8_t *)re + sizeof(pcre2_real_code)); rootbacktrack.cc = common->name_table + re->name_count * re->name_entry_size; @@ -11078,7 +11988,7 @@ if (common->control_head_ptr != 0) /* Main part of the matching */ if ((re->overall_options & PCRE2_ANCHORED) == 0) { - mainloop_label = mainloop_entry(common, (re->flags & PCRE2_HASCRORLF) != 0, re->overall_options); + mainloop_label = mainloop_entry(common); continue_match_label = LABEL(); /* Forward search if possible. */ if ((re->overall_options & PCRE2_NO_START_OPTIMIZE) == 0) @@ -11086,11 +11996,11 @@ if ((re->overall_options & PCRE2_ANCHORED) == 0) if (mode == PCRE2_JIT_COMPLETE && fast_forward_first_n_chars(common)) ; else if ((re->flags & PCRE2_FIRSTSET) != 0) - fast_forward_first_char(common, (PCRE2_UCHAR)(re->first_codeunit), (re->flags & PCRE2_FIRSTCASELESS) != 0); + fast_forward_first_char(common); else if ((re->flags & PCRE2_STARTLINE) != 0) fast_forward_newline(common); else if ((re->flags & PCRE2_FIRSTMAPSET) != 0) - fast_forward_start_bits(common, re->start_bitmap); + fast_forward_start_bits(common); } } else @@ -11137,6 +12047,9 @@ if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler))) return PCRE2_ERROR_NOMEMORY; } +if ((re->overall_options & PCRE2_ENDANCHORED) != 0) + end_anchor_failed = CMP(SLJIT_NOT_EQUAL, STR_PTR, 0, STR_END, 0); + if (common->might_be_empty) { empty_match = CMP(SLJIT_EQUAL, STR_PTR, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(0)); @@ -11149,15 +12062,26 @@ if (common->accept != NULL) /* This means we have a match. Update the ovector. */ copy_ovector(common, re->top_bracket + 1); -common->quit_label = common->forced_quit_label = LABEL(); +common->quit_label = common->abort_label = LABEL(); if (common->quit != NULL) set_jumps(common->quit, common->quit_label); -if (common->forced_quit != NULL) - set_jumps(common->forced_quit, common->forced_quit_label); +if (common->abort != NULL) + set_jumps(common->abort, common->abort_label); if (minlength_check_failed != NULL) - SET_LABEL(minlength_check_failed, common->forced_quit_label); + SET_LABEL(minlength_check_failed, common->abort_label); sljit_emit_return(compiler, SLJIT_MOV, SLJIT_RETURN_REG, 0); +if (common->failed_match != NULL) + { + SLJIT_ASSERT(common->mode == PCRE2_JIT_COMPLETE); + set_jumps(common->failed_match, LABEL()); + OP1(SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_IMM, PCRE2_ERROR_NOMATCH); + JUMPTO(SLJIT_JUMP, common->abort_label); + } + +if ((re->overall_options & PCRE2_ENDANCHORED) != 0) + JUMPHERE(end_anchor_failed); + if (mode != PCRE2_JIT_COMPLETE) { common->partialmatchlabel = LABEL(); @@ -11238,9 +12162,9 @@ if (common->might_be_empty) JUMPHERE(empty_match); OP1(SLJIT_MOV, TMP1, 0, ARGUMENTS, 0); OP1(SLJIT_MOV_U32, TMP2, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, options)); - OP2(SLJIT_AND | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP2, 0, SLJIT_IMM, PCRE2_NOTEMPTY); + OP2(SLJIT_AND | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP2, 0, SLJIT_IMM, PCRE2_NOTEMPTY); JUMPTO(SLJIT_NOT_ZERO, empty_match_backtrack_label); - OP2(SLJIT_AND | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP2, 0, SLJIT_IMM, PCRE2_NOTEMPTY_ATSTART); + OP2(SLJIT_AND | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP2, 0, SLJIT_IMM, PCRE2_NOTEMPTY_ATSTART); JUMPTO(SLJIT_ZERO, empty_match_found_label); OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, str)); CMPTO(SLJIT_NOT_EQUAL, TMP2, 0, STR_PTR, 0, empty_match_found_label); @@ -11251,7 +12175,7 @@ common->fast_forward_bc_ptr = NULL; common->fast_fail_start_ptr = 0; common->fast_fail_end_ptr = 0; common->currententry = common->entries; -common->local_exit = TRUE; +common->local_quit_available = TRUE; quit_label = common->quit_label; while (common->currententry != NULL) { @@ -11268,7 +12192,7 @@ while (common->currententry != NULL) flush_stubs(common); common->currententry = common->currententry->next; } -common->local_exit = FALSE; +common->local_quit_available = FALSE; common->quit_label = quit_label; /* Allocating stack, returns with PCRE_ERROR_JIT_STACKLIMIT if fails. */ @@ -11280,7 +12204,7 @@ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LOCALS1, TMP2, 0); OP1(SLJIT_MOV, TMP1, 0, ARGUMENTS, 0); OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, stack)); OP1(SLJIT_MOV, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(struct sljit_stack, top), STACK_TOP, 0); -OP2(SLJIT_ADD, TMP2, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(struct sljit_stack, limit), SLJIT_IMM, STACK_GROWTH_RATE); +OP2(SLJIT_SUB, TMP2, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(struct sljit_stack, limit), SLJIT_IMM, STACK_GROWTH_RATE); sljit_emit_ijump(compiler, SLJIT_CALL2, SLJIT_IMM, SLJIT_FUNC_OFFSET(sljit_stack_resize)); jump = CMP(SLJIT_NOT_EQUAL, SLJIT_RETURN_REG, 0, SLJIT_IMM, 0); diff --git a/ProcessHacker/pcre/pcre2_jit_match.c b/ProcessHacker/pcre/pcre2_jit_match.c index a323971ff3ea..4cad754c759e 100644 --- a/ProcessHacker/pcre/pcre2_jit_match.c +++ b/ProcessHacker/pcre/pcre2_jit_match.c @@ -49,10 +49,10 @@ static SLJIT_NOINLINE int jit_machine_stack_exec(jit_arguments *arguments, jit_f sljit_u8 local_space[MACHINE_STACK_SIZE]; struct sljit_stack local_stack; -local_stack.top = (sljit_sw)&local_space; -local_stack.base = local_stack.top; -local_stack.limit = local_stack.base + MACHINE_STACK_SIZE; -local_stack.max_limit = local_stack.limit; +local_stack.max_limit = local_space; +local_stack.limit = local_space; +local_stack.base = local_space + MACHINE_STACK_SIZE; +local_stack.top = local_space + MACHINE_STACK_SIZE; arguments->stack = &local_stack; return executable_func(arguments); } diff --git a/ProcessHacker/pcre/pcre2_jit_test.c b/ProcessHacker/pcre/pcre2_jit_test.c index 705ba181eb3c..96280b71680f 100644 --- a/ProcessHacker/pcre/pcre2_jit_test.c +++ b/ProcessHacker/pcre/pcre2_jit_test.c @@ -258,6 +258,8 @@ static struct regression_test_case regression_test_cases[] = { { MU, A, 0, 0, "=\xc7\x82|#\xc6\x82", "\xf1\x83\x82\x82=\xc7\x82\xc7\x83" }, { MU, A, 0, 0, "\xc7\x82\xc7\x83|\xc6\x82\xc6\x82", "\xf1\x83\x82\x82\xc7\x82\xc7\x83" }, { MU, A, 0, 0, "\xc6\x82\xc6\x82|\xc7\x83\xc7\x83|\xc8\x84\xc8\x84", "\xf1\x83\x82\x82\xc8\x84\xc8\x84" }, + { U, A, 0, 0, "\xe1\x81\x80|\xe2\x82\x80|\xe4\x84\x80", "\xdf\xbf\xc2\x80\xe4\x84\x80" }, + { U, A, 0, 0, "(?:\xe1\x81\x80|\xe2\x82\x80|\xe4\x84\x80)#", "\xdf\xbf\xc2\x80#\xe4\x84\x80#" }, /* Greedy and non-greedy ? operators. */ { MU, A, 0, 0, "(?:a)?a", "laab" }, @@ -707,7 +709,7 @@ static struct regression_test_case regression_test_cases[] = { { MU, A, 0, 0, "(?1)(((a(*ACCEPT)))b)", "axaa" }, { MU, A, 0, 0, "(?1)(?(DEFINE) (((ac(*ACCEPT)))b) )", "akaac" }, { MU, A, 0, 0, "(a+)b(?1)b\\1", "abaaabaaaaa" }, - { MU, A, 0, 0 | F_NOMATCH, "(?(DEFINE)(aa|a))(?1)ab", "aab" }, + { MU, A, 0, 0, "(?(DEFINE)(aa|a))(?1)ab", "aab" }, { MU, A, 0, 0, "(?(DEFINE)(a\\Kb))(?1)+ababc", "abababxabababc" }, { MU, A, 0, 0, "(a\\Kb)(?1)+ababc", "abababxababababc" }, { MU, A, 0, 0 | F_NOMATCH, "(a\\Kb)(?1)+ababc", "abababxababababxc" }, @@ -724,6 +726,8 @@ static struct regression_test_case regression_test_cases[] = { { MU, A, 0, 0, "((?:(?(R)a|(?1))){3})", "XaaaaaaaaaX" }, { MU, A, 0, 0, "((?(R)a|(?1)){1,3})aaaaaa", "aaaaaaaaXaaaaaaaaa" }, { MU, A, 0, 0, "((?(R)a|(?1)){1,3}?)M", "aaaM" }, + { MU, A, 0, 0, "((.)(?:.|\\2(?1))){0}#(?1)#", "#aabbccdde# #aabbccddee#" }, + { MU, A, 0, 0, "((.)(?:\\2|\\2{4}b)){0}#(?:(?1))+#", "#aaaab# #aaaaab#" }, /* 16 bit specific tests. */ { CM, A, 0, 0 | F_FORCECONV, "\xc3\xa1", "\xc3\x81\xc3\xa1" }, @@ -842,13 +846,23 @@ static struct regression_test_case regression_test_cases[] = { { MU, A, 0, 0 | F_NOMATCH, "(?(?=a)a(*THEN)b|ad)", "ad" }, { MU, A, 0, 0, "(?!(?(?=a)ab|b(*THEN)d))bn|bnn", "bnn" }, + /* Recurse and control verbs. */ + { MU, A, 0, 0, "(a(*ACCEPT)b){0}a(?1)b", "aacaabb" }, + { MU, A, 0, 0, "((a)\\2(*ACCEPT)b){0}a(?1)b", "aaacaaabb" }, + { MU, A, 0, 0, "((ab|a(*ACCEPT)x)+|ababababax){0}_(?1)_", "_ababababax_ _ababababa_" }, + { MU, A, 0, 0, "((.)(?:A(*ACCEPT)|(?1)\\2)){0}_(?1)_", "_bcdaAdcb_bcdaAdcb_" }, + { MU, A, 0, 0, "((*MARK:m)(?:a|a(*COMMIT)b|aa)){0}_(?1)_", "_ab_" }, + { MU, A, 0, 0, "((*MARK:m)(?:a|a(*COMMIT)b|aa)){0}_(?1)_|(_aa_)", "_aa_" }, + { MU, A, 0, 0, "(a(*COMMIT)(?:b|bb)|c(*ACCEPT)d|dd){0}_(?1)+_", "_ax_ _cd_ _abbb_ _abcd_ _abbcdd_" }, + { MU, A, 0, 0, "((.)(?:.|(*COMMIT)\\2{3}(*ACCEPT).*|.*)){0}_(?1){0,4}_", "_aaaabbbbccccddd_ _aaaabbbbccccdddd_" }, + /* Deep recursion. */ { MU, A, 0, 0, "((((?:(?:(?:\\w)+)?)*|(?>\\w)+?)+|(?>\\w)?\?)*)?\\s", "aaaaa+ " }, { MU, A, 0, 0, "(?:((?:(?:(?:\\w*?)+)??|(?>\\w)?|\\w*+)*)+)+?\\s", "aa+ " }, { MU, A, 0, 0, "((a?)+)+b", "aaaaaaaaaaaa b" }, /* Deep recursion: Stack limit reached. */ - { M, A, 0, 0 | F_NOMATCH, "a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaaaaaaaaa", "aaaaaaaaaaaaaaaaaaaaaaa" }, + { M, A, 0, 0 | F_NOMATCH, "a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaaaaaaaaa", "aaaaaaaaaaaaaaaaaaaaaaa" }, { M, A, 0, 0 | F_NOMATCH, "(?:a+)+b", "aaaaaaaaaaaaaaaaaaaaaaaa b" }, { M, A, 0, 0 | F_NOMATCH, "(?:a+?)+?b", "aaaaaaaaaaaaaaaaaaaaaaaa b" }, { M, A, 0, 0 | F_NOMATCH, "(?:a*)*b", "aaaaaaaaaaaaaaaaaaaaaaaa b" }, @@ -1309,9 +1323,9 @@ static int regression_tests(void) } else { ovector8_1 = pcre2_get_ovector_pointer_8(mdata8_1); ovector8_2 = pcre2_get_ovector_pointer_8(mdata8_2); - for (i = 0; i < OVECTOR_SIZE * 3; ++i) + for (i = 0; i < OVECTOR_SIZE * 2; ++i) ovector8_1[i] = -2; - for (i = 0; i < OVECTOR_SIZE * 3; ++i) + for (i = 0; i < OVECTOR_SIZE * 2; ++i) ovector8_2[i] = -2; } if (re8) { @@ -1348,9 +1362,9 @@ static int regression_tests(void) } else { ovector16_1 = pcre2_get_ovector_pointer_16(mdata16_1); ovector16_2 = pcre2_get_ovector_pointer_16(mdata16_2); - for (i = 0; i < OVECTOR_SIZE * 3; ++i) + for (i = 0; i < OVECTOR_SIZE * 2; ++i) ovector16_1[i] = -2; - for (i = 0; i < OVECTOR_SIZE * 3; ++i) + for (i = 0; i < OVECTOR_SIZE * 2; ++i) ovector16_2[i] = -2; } if (re16) { @@ -1392,9 +1406,9 @@ static int regression_tests(void) } else { ovector32_1 = pcre2_get_ovector_pointer_32(mdata32_1); ovector32_2 = pcre2_get_ovector_pointer_32(mdata32_2); - for (i = 0; i < OVECTOR_SIZE * 3; ++i) + for (i = 0; i < OVECTOR_SIZE * 2; ++i) ovector32_1[i] = -2; - for (i = 0; i < OVECTOR_SIZE * 3; ++i) + for (i = 0; i < OVECTOR_SIZE * 2; ++i) ovector32_2[i] = -2; } if (re32) { diff --git a/ProcessHacker/pcre/pcre2_maketables.c b/ProcessHacker/pcre/pcre2_maketables.c index ddfadfb00d42..2c7ae84d864d 100644 --- a/ProcessHacker/pcre/pcre2_maketables.c +++ b/ProcessHacker/pcre/pcre2_maketables.c @@ -44,8 +44,6 @@ character tables for PCRE2 in the current locale. The file is compiled on its own as part of the PCRE2 library. However, it is also included in the compilation of dftables.c, in which case the macro DFTABLES is defined. */ -#define HAVE_CONFIG_H - #ifndef DFTABLES # ifdef HAVE_CONFIG_H # include "config.h" diff --git a/ProcessHacker/pcre/pcre2_match.c b/ProcessHacker/pcre/pcre2_match.c index e05dc35179eb..689169e837d1 100644 --- a/ProcessHacker/pcre/pcre2_match.c +++ b/ProcessHacker/pcre/pcre2_match.c @@ -7,7 +7,7 @@ and semantics are as close as possible to those of the Perl 5 language. Written by Philip Hazel Original API code Copyright (c) 1997-2012 University of Cambridge - New API code Copyright (c) 2016 University of Cambridge + New API code Copyright (c) 2015-2017 University of Cambridge ----------------------------------------------------------------------------- Redistribution and use in source and binary forms, with or without @@ -38,23 +38,39 @@ POSSIBILITY OF SUCH DAMAGE. ----------------------------------------------------------------------------- */ -#define HAVE_CONFIG_H +// dmex: Disable warnings. +#pragma warning(push) +#pragma warning(disable : 4244) #ifdef HAVE_CONFIG_H #include "config.h" #endif -#define NLBLOCK mb /* Block containing newline information */ -#define PSSTART start_subject /* Field containing processed string start */ -#define PSEND end_subject /* Field containing processed string end */ +/* These defines enables debugging code */ + +//#define DEBUG_FRAMES_DISPLAY +//#define DEBUG_SHOW_OPS +//#define DEBUG_SHOW_RMATCH + +#ifdef DEBUG_FRAME_DISPLAY +#include +#endif + +/* These defines identify the name of the block containing "static" +information, and fields within it. */ + +#define NLBLOCK mb /* Block containing newline information */ +#define PSSTART start_subject /* Field containing processed string start */ +#define PSEND end_subject /* Field containing processed string end */ #include "pcre2_internal.h" -/* Masks for identifying the public options that are permitted at match time. -*/ +#define RECURSE_UNSET 0xffffffffu /* Bigger than max group number */ + +/* Masks for identifying the public options that are permitted at match time. */ #define PUBLIC_MATCH_OPTIONS \ - (PCRE2_ANCHORED|PCRE2_NOTBOL|PCRE2_NOTEOL|PCRE2_NOTEMPTY| \ + (PCRE2_ANCHORED|PCRE2_ENDANCHORED|PCRE2_NOTBOL|PCRE2_NOTEOL|PCRE2_NOTEMPTY| \ PCRE2_NOTEMPTY_ATSTART|PCRE2_NO_UTF_CHECK|PCRE2_PARTIAL_HARD| \ PCRE2_PARTIAL_SOFT|PCRE2_NO_JIT) @@ -62,60 +78,252 @@ POSSIBILITY OF SUCH DAMAGE. (PCRE2_NO_UTF_CHECK|PCRE2_NOTBOL|PCRE2_NOTEOL|PCRE2_NOTEMPTY|\ PCRE2_NOTEMPTY_ATSTART|PCRE2_PARTIAL_SOFT|PCRE2_PARTIAL_HARD) -/* The mb->capture_last field uses the lower 16 bits for the last captured -substring (which can never be greater than 65535) and a bit in the top half -to mean "capture vector overflowed". This odd way of doing things was -implemented when it was realized that preserving and restoring the overflow bit -whenever the last capture number was saved/restored made for a neater -interface, and doing it this way saved on (a) another variable, which would -have increased the stack frame size (a big NO-NO in PCRE) and (b) another -separate set of save/restore instructions. The following defines are used in -implementing this. */ - -#define CAPLMASK 0x0000ffff /* The bits used for last_capture */ -#define OVFLMASK 0xffff0000 /* The bits used for the overflow flag */ -#define OVFLBIT 0x00010000 /* The bit that is set for overflow */ - -/* Bits for setting in mb->match_function_type to indicate two special types -of call to match(). We do it this way to save on using another stack variable, -as stack usage is to be discouraged. */ - -#define MATCH_CONDASSERT 1 /* Called to check a condition assertion */ -#define MATCH_CBEGROUP 2 /* Could-be-empty unlimited repeat group */ - -/* Non-error returns from the match() function. Error returns are externally -defined PCRE2_ERROR_xxx codes, which are all negative. */ +/* Non-error returns from and within the match() function. Error returns are +externally defined PCRE2_ERROR_xxx codes, which are all negative. */ #define MATCH_MATCH 1 #define MATCH_NOMATCH 0 -/* Special internal returns from the match() function. Make them sufficiently -negative to avoid the external error codes. */ +/* Special internal returns used in the match() function. Make them +sufficiently negative to avoid the external error codes. */ #define MATCH_ACCEPT (-999) #define MATCH_KETRPOS (-998) -#define MATCH_ONCE (-997) /* The next 5 must be kept together and in sequence so that a test that checks for any one of them can use a range. */ -#define MATCH_COMMIT (-996) -#define MATCH_PRUNE (-995) -#define MATCH_SKIP (-994) -#define MATCH_SKIP_ARG (-993) -#define MATCH_THEN (-992) +#define MATCH_COMMIT (-997) +#define MATCH_PRUNE (-996) +#define MATCH_SKIP (-995) +#define MATCH_SKIP_ARG (-994) +#define MATCH_THEN (-993) #define MATCH_BACKTRACK_MAX MATCH_THEN #define MATCH_BACKTRACK_MIN MATCH_COMMIT -/* Min and max values for the common repeats; for the maxima, 0 => infinity */ +/* Group frame type values. Zero means the frame is not a group frame. The +lower 16 bits are used for data (e.g. the capture number). Group frames are +used for most groups so that information about the start is easily available at +the end without having to scan back through intermediate frames (backtrack +points). */ + +#define GF_CAPTURE 0x00010000u +#define GF_NOCAPTURE 0x00020000u +#define GF_CONDASSERT 0x00030000u +#define GF_RECURSE 0x00040000u + +/* Masks for the identity and data parts of the group frame type. */ + +#define GF_IDMASK(a) ((a) & 0xffff0000u) +#define GF_DATAMASK(a) ((a) & 0x0000ffffu) + +/* Repetition types */ + +enum { REPTYPE_MIN, REPTYPE_MAX, REPTYPE_POS }; + +/* Min and max values for the common repeats; a maximum of UINT32_MAX => +infinity. */ + +static const uint32_t rep_min[] = { + 0, 0, /* * and *? */ + 1, 1, /* + and +? */ + 0, 0, /* ? and ?? */ + 0, 0, /* dummy placefillers for OP_CR[MIN]RANGE */ + 0, 1, 0 }; /* OP_CRPOS{STAR, PLUS, QUERY} */ + +static const uint32_t rep_max[] = { + UINT32_MAX, UINT32_MAX, /* * and *? */ + UINT32_MAX, UINT32_MAX, /* + and +? */ + 1, 1, /* ? and ?? */ + 0, 0, /* dummy placefillers for OP_CR[MIN]RANGE */ + UINT32_MAX, UINT32_MAX, 1 }; /* OP_CRPOS{STAR, PLUS, QUERY} */ + +/* Repetition types - must include OP_CRPOSRANGE (not needed above) */ + +static const uint32_t rep_typ[] = { + REPTYPE_MAX, REPTYPE_MIN, /* * and *? */ + REPTYPE_MAX, REPTYPE_MIN, /* + and +? */ + REPTYPE_MAX, REPTYPE_MIN, /* ? and ?? */ + REPTYPE_MAX, REPTYPE_MIN, /* OP_CRRANGE and OP_CRMINRANGE */ + REPTYPE_POS, REPTYPE_POS, /* OP_CRPOSSTAR, OP_CRPOSPLUS */ + REPTYPE_POS, REPTYPE_POS }; /* OP_CRPOSQUERY, OP_CRPOSRANGE */ + +/* Numbers for RMATCH calls at backtracking points. When these lists are +changed, the code at RETURN_SWITCH below must be updated in sync. */ + +enum { RM1=1, RM2, RM3, RM4, RM5, RM6, RM7, RM8, RM9, RM10, + RM11, RM12, RM13, RM14, RM15, RM16, RM17, RM18, RM19, RM20, + RM21, RM22, RM23, RM24, RM25, RM26, RM27, RM28, RM29, RM30, + RM31, RM32, RM33, RM34, RM35 }; + +#ifdef SUPPORT_WIDE_CHARS +enum { RM100=100, RM101 }; +#endif + +#ifdef SUPPORT_UNICODE +enum { RM200=200, RM201, RM202, RM203, RM204, RM205, RM206, RM207, + RM208, RM209, RM210, RM211, RM212, RM213, RM214, RM215, + RM216, RM217, RM218, RM219, RM220, RM221, RM222 }; +#endif + +/* Define short names for general fields in the current backtrack frame, which +is always pointed to by the F variable. Occasional references to fields in +other frames are written out explicitly. There are also some fields in the +current frame whose names start with "temp" that are used for short-term, +localised backtracking memory. These are #defined with Lxxx names at the point +of use and undefined afterwards. */ + +#define Fback_frame F->back_frame +#define Fcapture_last F->capture_last +#define Fcurrent_recurse F->current_recurse +#define Fecode F->ecode +#define Feptr F->eptr +#define Fgroup_frame_type F->group_frame_type +#define Flast_group_offset F->last_group_offset +#define Flength F->length +#define Fmark F->mark +#define Frdepth F->rdepth +#define Fstart_match F->start_match +#define Foffset_top F->offset_top +#define Foccu F->occu +#define Fop F->op +#define Fovector F->ovector +#define Freturn_id F->return_id + + +#ifdef DEBUG_FRAMES_DISPLAY +/************************************************* +* Display current frames and contents * +*************************************************/ + +/* This debugging function displays the current set of frames and their +contents. It is not called automatically from anywhere, the intention being +that calls can be inserted where necessary when debugging frame-related +problems. + +Arguments: + f the file to write to + F the current top frame + P a previous frame of interest + frame_size the frame size + mb points to the match block + s identification text + +Returns: nothing +*/ + +static void +display_frames(FILE *f, heapframe *F, heapframe *P, PCRE2_SIZE frame_size, + match_block *mb, const char *s, ...) +{ +uint32_t i; +heapframe *Q; +va_list ap; +va_start(ap, s); + +fprintf(f, "FRAMES "); +vfprintf(f, s, ap); +va_end(ap); + +if (P != NULL) fprintf(f, " P=%lu", + ((char *)P - (char *)(mb->match_frames))/frame_size); +fprintf(f, "\n"); + +for (i = 0, Q = mb->match_frames; + Q <= F; + i++, Q = (heapframe *)((char *)Q + frame_size)) + { + fprintf(f, "Frame %d type=%x subj=%lu code=%d back=%lu id=%d", + i, Q->group_frame_type, Q->eptr - mb->start_subject, *(Q->ecode), + Q->back_frame, Q->return_id); + + if (Q->last_group_offset == PCRE2_UNSET) + fprintf(f, " lgoffset=unset\n"); + else + fprintf(f, " lgoffset=%lu\n", Q->last_group_offset/frame_size); + } +} + +#endif + + + +/************************************************* +* Process a callout * +*************************************************/ + +/* This function is called for all callouts, whether "standalone" or at the +start of a conditional group. Feptr will be pointing to either OP_CALLOUT or +OP_CALLOUT_STR. + +Arguments: + F points to the current backtracking frame + mb points to the match block + lengthptr where to return the length of the callout item -static const char rep_min[] = { 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, }; -static const char rep_max[] = { 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, }; +Returns: the return from the callout + or 0 if no callout function exists +*/ -/* Maximum number of ovector elements that can be saved on the system stack -when processing OP_RECURSE in non-HEAP_MATCH_RECURSE mode. If the ovector is -bigger, malloc() is used. This value should be a multiple of 3, because the -ovector length is always a multiple of 3. */ +static int +do_callout(heapframe *F, match_block *mb, PCRE2_SIZE *lengthptr) +{ +int rc; +PCRE2_SIZE save0, save1; +PCRE2_SIZE *callout_ovector; +pcre2_callout_block cb; + +*lengthptr = (*Fecode == OP_CALLOUT)? + PRIV(OP_lengths)[OP_CALLOUT] : GET(Fecode, 1 + 2*LINK_SIZE); + +if (mb->callout == NULL) return 0; /* No callout function provided */ + +/* The original matching code (pre 10.30) worked directly with the ovector +passed by the user, and this was passed to callouts. Now that the working +ovector is in the backtracking frame, it no longer needs to reserve space for +the overall match offsets (which would waste space in the frame). For backward +compatibility, however, we pass capture_top and offset_vector to the callout as +if for the extended ovector, and we ensure that the first two slots are unset +by preserving and restoring their current contents. Picky compilers complain if +references such as Fovector[-2] are use directly, so we set up a separate +pointer. */ + +callout_ovector = (PCRE2_SIZE *)(Fovector) - 2; + +cb.version = 1; +cb.capture_top = (uint32_t)Foffset_top/2 + 1; +cb.capture_last = Fcapture_last; +cb.offset_vector = callout_ovector; +cb.mark = mb->nomatch_mark; +cb.subject = mb->start_subject; +cb.subject_length = (PCRE2_SIZE)(mb->end_subject - mb->start_subject); +cb.start_match = (PCRE2_SIZE)(Fstart_match - mb->start_subject); +cb.current_position = (PCRE2_SIZE)(Feptr - mb->start_subject); +cb.pattern_position = GET(Fecode, 1); +cb.next_item_length = GET(Fecode, 1 + LINK_SIZE); + +if (*Fecode == OP_CALLOUT) /* Numerical callout */ + { + cb.callout_number = Fecode[1 + 2*LINK_SIZE]; + cb.callout_string_offset = 0; + cb.callout_string = NULL; + cb.callout_string_length = 0; + } +else /* String callout */ + { + cb.callout_number = 0; + cb.callout_string_offset = GET(Fecode, 1 + 3*LINK_SIZE); + cb.callout_string = Fecode + (1 + 4*LINK_SIZE) + 1; + cb.callout_string_length = + *lengthptr - (1 + 4*LINK_SIZE) - 2; + } -#define OP_RECURSE_STACK_SAVE_MAX 45 +save0 = callout_ovector[0]; +save1 = callout_ovector[1]; +callout_ovector[0] = callout_ovector[1] = PCRE2_UNSET; +rc = mb->callout(&cb, mb->callout_data); +callout_ovector[0] = save0; +callout_ovector[1] = save1; +return rc; +} @@ -131,10 +339,9 @@ seems unlikely.) Arguments: offset index into the offset vector - offset_top top of the used offset vector - eptr pointer into the subject - mb points to match block caseless TRUE if caseless + F the current backtracking frame pointer + mb points to match block lengthptr pointer for returning the length matched Returns: = 0 sucessful match; number of code units matched is set @@ -143,21 +350,18 @@ Returns: = 0 sucessful match; number of code units matched is set */ static int -match_ref(PCRE2_SIZE offset, PCRE2_SIZE offset_top, PCRE2_SPTR eptr, - match_block *mb, BOOL caseless, PCRE2_SIZE *lengthptr) +match_ref(PCRE2_SIZE offset, BOOL caseless, heapframe *F, match_block *mb, + PCRE2_SIZE *lengthptr) { -#if defined SUPPORT_UNICODE -BOOL utf = (mb->poptions & PCRE2_UTF) != 0; -#endif - PCRE2_SPTR p; PCRE2_SIZE length; -PCRE2_SPTR eptr_start = eptr; +PCRE2_SPTR eptr; +PCRE2_SPTR eptr_start; /* Deal with an unset group. The default is no match, but there is an option to match an empty string. */ -if (offset >= offset_top || mb->ovector[offset] == PCRE2_UNSET) +if (offset >= Foffset_top || Fovector[offset] == PCRE2_UNSET) { if ((mb->poptions & PCRE2_MATCH_UNSET_BACKREF) != 0) { @@ -169,19 +373,20 @@ if (offset >= offset_top || mb->ovector[offset] == PCRE2_UNSET) /* Separate the caseless and UTF cases for speed. */ -p = mb->start_subject + mb->ovector[offset]; -length = mb->ovector[offset+1] - mb->ovector[offset]; +eptr = eptr_start = Feptr; +p = mb->start_subject + Fovector[offset]; +length = Fovector[offset+1] - Fovector[offset]; if (caseless) { #if defined SUPPORT_UNICODE - if (utf) + if ((mb->poptions & PCRE2_UTF) != 0) { /* Match characters up to the end of the reference. NOTE: the number of code units matched may differ, because in UTF-8 there are some characters - whose upper and lower case versions code have different numbers of bytes. - For example, U+023A (2 bytes in UTF-8) is the upper case version of U+2C65 - (3 bytes in UTF-8); a sequence of 3 of the former uses 6 bytes, as does a + whose upper and lower case codes have different numbers of bytes. For + example, U+023A (2 bytes in UTF-8) is the upper case version of U+2C65 (3 + bytes in UTF-8); a sequence of 3 of the former uses 6 bytes, as does a sequence of two of the latter. It is important, therefore, to check the length along the reference, not along the subject (earlier code did this wrong). */ @@ -227,14 +432,26 @@ if (caseless) } /* In the caseful case, we can just compare the code units, whether or not we -are in UTF mode. */ +are in UTF mode. When partial matching, we have to do this unit-by-unit. */ else { - for (; length > 0; length--) + if (mb->partial != 0) + { + for (; length > 0; length--) + { + if (eptr >= mb->end_subject) return 1; /* Partial match */ + if (UCHAR21INCTEST(p) != UCHAR21INCTEST(eptr)) return -1; /* No match */ + } + } + + /* Not partial matching */ + + else { - if (eptr >= mb->end_subject) return 1; /* Partial match */ - if (UCHAR21INCTEST(p) != UCHAR21INCTEST(eptr)) return -1; /*No match */ + if ((PCRE2_SIZE)(mb->end_subject - eptr) < length) return 1; /* Partial */ + if (memcmp(p, eptr, CU2BYTES(length)) != 0) return -1; /* No match */ + eptr += length; } } @@ -244,278 +461,73 @@ return 0; /* Match */ -/*************************************************************************** -**************************************************************************** - RECURSION IN THE match() FUNCTION - -The match() function is highly recursive, though not every recursive call -increases the recursion depth. Nevertheless, some regular expressions can cause -it to recurse to a great depth. I was writing for Unix, so I just let it call -itself recursively. This uses the stack for saving everything that has to be -saved for a recursive call. On Unix, the stack can be large, and this works -fine. - -It turns out that on some non-Unix-like systems there are problems with -programs that use a lot of stack. (This despite the fact that every last chip -has oodles of memory these days, and techniques for extending the stack have -been known for decades.) So.... - -There is a fudge, triggered by defining HEAP_MATCH_RECURSE, which avoids -recursive calls by keeping local variables that need to be preserved in blocks -of memory on the heap instead instead of on the stack. Macros are used to -achieve this so that the actual code doesn't look very different to what it -always used to. - -The original heap-recursive code used longjmp(). However, it seems that this -can be very slow on some operating systems. Following a suggestion from Stan -Switzer, the use of longjmp() has been abolished, at the cost of having to -provide a unique number for each call to RMATCH. There is no way of generating -a sequence of numbers at compile time in C. I have given them names, to make -them stand out more clearly. - -Crude tests on x86 Linux show a small speedup of around 5-8%. However, on -FreeBSD, avoiding longjmp() more than halves the time taken to run the standard -tests. Furthermore, not using longjmp() means that local dynamic variables -don't have indeterminate values; this has meant that the frame size can be -reduced because the result can be "passed back" by straight setting of the -variable instead of being passed in the frame. -**************************************************************************** -***************************************************************************/ - -/* Numbers for RMATCH calls. When this list is changed, the code at HEAP_RETURN -below must be updated in sync. */ - -enum { RM1=1, RM2, RM3, RM4, RM5, RM6, RM7, RM8, RM9, RM10, - RM11, RM12, RM13, RM14, RM15, RM16, RM17, RM18, RM19, RM20, - RM21, RM22, RM23, RM24, RM25, RM26, RM27, RM28, RM29, RM30, - RM31, RM32, RM33, RM34, RM35, RM36, RM37, RM38, RM39, RM40, - RM41, RM42, RM43, RM44, RM45, RM46, RM47, RM48, RM49, RM50, - RM51, RM52, RM53, RM54, RM55, RM56, RM57, RM58, RM59, RM60, - RM61, RM62, RM63, RM64, RM65, RM66, RM67, RM68 }; - -/* These versions of the macros use the stack, as normal. Note that the "rw" -argument of RMATCH isn't actually used in this definition. */ - -#ifndef HEAP_MATCH_RECURSE -#define RMATCH(ra,rb,rc,rd,re,rw) \ - rrc = match(ra,rb,mstart,rc,rd,re,rdepth+1) -#define RRETURN(ra) return ra -#else - -/* These versions of the macros manage a private stack on the heap. Note that -the "rd" argument of RMATCH isn't actually used in this definition. It's the mb -argument of match(), which never changes. */ - -#define RMATCH(ra,rb,rc,rd,re,rw)\ - {\ - heapframe *newframe = frame->Xnextframe;\ - if (newframe == NULL)\ - {\ - newframe = (heapframe *)(mb->stack_memctl.malloc)\ - (sizeof(heapframe), mb->stack_memctl.memory_data);\ - if (newframe == NULL) RRETURN(PCRE2_ERROR_NOMEMORY);\ - newframe->Xnextframe = NULL;\ - frame->Xnextframe = newframe;\ - }\ - frame->Xwhere = rw;\ - newframe->Xeptr = ra;\ - newframe->Xecode = rb;\ - newframe->Xmstart = mstart;\ - newframe->Xoffset_top = rc;\ - newframe->Xeptrb = re;\ - newframe->Xrdepth = frame->Xrdepth + 1;\ - newframe->Xprevframe = frame;\ - frame = newframe;\ - goto HEAP_RECURSE;\ - L_##rw:;\ - } - -#define RRETURN(ra)\ - {\ - heapframe *oldframe = frame;\ - frame = oldframe->Xprevframe;\ - if (frame != NULL)\ - {\ - rrc = ra;\ - goto HEAP_RETURN;\ - }\ - return ra;\ - } - - -/* Structure for remembering the local variables in a private frame. Arrange it -so as to minimize the number of holes. */ - -typedef struct heapframe { - struct heapframe *Xprevframe; - struct heapframe *Xnextframe; - -#ifdef SUPPORT_UNICODE - PCRE2_SPTR Xcharptr; -#endif - PCRE2_SPTR Xeptr; - PCRE2_SPTR Xecode; - PCRE2_SPTR Xmstart; - PCRE2_SPTR Xcallpat; - PCRE2_SPTR Xdata; - PCRE2_SPTR Xnext_ecode; - PCRE2_SPTR Xpp; - PCRE2_SPTR Xprev; - PCRE2_SPTR Xsaved_eptr; - - eptrblock *Xeptrb; - - PCRE2_SIZE Xlength; - PCRE2_SIZE Xoffset; - PCRE2_SIZE Xoffset_top; - PCRE2_SIZE Xsave_offset1, Xsave_offset2, Xsave_offset3; - - uint32_t Xfc; - uint32_t Xnumber; - uint32_t Xrdepth; - uint32_t Xop; - uint32_t Xsave_capture_last; - -#ifdef SUPPORT_UNICODE - uint32_t Xprop_value; - int Xprop_type; - int Xprop_fail_result; - int Xoclength; -#endif - - int Xcodelink; - int Xctype; - int Xfi; - int Xmax; - int Xmin; - int Xwhere; /* Where to jump back to */ - - BOOL Xcondition; - BOOL Xcur_is_word; - BOOL Xprev_is_word; - - eptrblock Xnewptrb; - recursion_info Xnew_recursive; - -#ifdef SUPPORT_UNICODE - PCRE2_UCHAR Xocchars[6]; -#endif -} heapframe; - -#endif - - -/*************************************************************************** -***************************************************************************/ +/****************************************************************************** +******************************************************************************* + "Recursion" in the match() function +The original match() function was highly recursive, but this proved to be the +source of a number of problems over the years, mostly because of the relatively +small system stacks that are commonly found. As new features were added to +patterns, various kludges were invented to reduce the amount of stack used, +making the code hard to understand in places. -/* When HEAP_MATCH_RECURSE is not defined, the match() function implements -backtrack points by calling itself recursively in all but one case. The one -special case is when processing OP_RECURSE, which specifies recursion in the -pattern. The entire ovector must be saved and restored while processing -OP_RECURSE. If the ovector is small enough, instead of calling match() -directly, op_recurse_ovecsave() is called. This function uses the system stack -to save the ovector while calling match() to process the pattern recursion. */ +A version did exist that used individual frames on the heap instead of calling +match() recursively, but this ran substantially slower. The current version is +a refactoring that uses a vector of frames to remember backtracking points. +This runs no slower, and possibly even a bit faster than the original recursive +implementation. An initial vector of size START_FRAMES_SIZE (enough for maybe +50 frames) is allocated on the system stack. If this is not big enough, the +heap is used for a larger vector. -#ifndef HEAP_MATCH_RECURSE +******************************************************************************* +******************************************************************************/ -/* We need a prototype for match() because it is mutually recursive with -op_recurse_ovecsave(). */ -static int -match(PCRE2_SPTR eptr, PCRE2_SPTR ecode, PCRE2_SPTR mstart, - PCRE2_SIZE offset_top, match_block *mb, eptrblock *eptrb, uint32_t rdepth); /************************************************* -* Process OP_RECURSE, stacking ovector * +* Macros for the match() function * *************************************************/ -/* When this function is called, mb->recursive has already been updated to -point to a new recursion data block, and all its fields other than ovec_save -have been set. - -This function exists so that the local vector variable ovecsave is no longer -defined in the match() function, as it was in PCRE1. It is used only when there -is recursion in the pattern, so it wastes a lot of stack to have it defined for -every call of match(). We now use this function as an indirect way of calling -match() only in the case when ovecsave is needed. (David Wheeler used to say -"All problems in computer science can be solved by another level of -indirection.") - -HOWEVER: when this file is compiled by gcc in an optimizing mode, because this -function is called only once, and only from within match(), gcc will "inline" -it - that is, move it inside match() - and this completely negates its reason -for existence. Therefore, we mark it as non-inline when gcc is in use. - -Arguments: - eptr pointer to current character in subject - callpat the recursion point in the pattern - mstart pointer to the current match start position (can be modified - by encountering \K) - offset_top current top pointer (highest ovector offset used + 1) - mb pointer to "static" info block for the match - eptrb pointer to chain of blocks containing eptr at start of - brackets - for testing for empty matches - rdepth the recursion depth - -Returns: a match() return code -*/ - -static int -#if defined(__GNUC__) && !defined(__INTEL_COMPILER) -__attribute__ ((noinline)) -#endif -op_recurse_ovecsave(PCRE2_SPTR eptr, PCRE2_SPTR callpat, - PCRE2_SPTR mstart, PCRE2_SIZE offset_top, match_block *mb, eptrblock *eptrb, - uint32_t rdepth) -{ -int rrc; -BOOL cbegroup = *callpat >= OP_SBRA; -recursion_info *new_recursive = mb->recursive; -PCRE2_SIZE ovecsave[OP_RECURSE_STACK_SAVE_MAX]; +/* These macros pack up tests that are used for partial matching several times +in the code. We set the "hit end" flag if the pointer is at the end of the +subject and also past the earliest inspected character (i.e. something has been +matched, even if not part of the actual matched string). For hard partial +matching, we then return immediately. The second one is used when we already +know we are past the end of the subject. */ -/* Save the ovector */ +#define CHECK_PARTIAL()\ + if (mb->partial != 0 && Feptr >= mb->end_subject && \ + Feptr > mb->start_used_ptr) \ + { \ + mb->hitend = TRUE; \ + if (mb->partial > 1) return PCRE2_ERROR_PARTIAL; \ + } -new_recursive->ovec_save = ovecsave; -memcpy(ovecsave, mb->ovector, mb->offset_end * sizeof(PCRE2_SIZE)); +#define SCHECK_PARTIAL()\ + if (mb->partial != 0 && Feptr > mb->start_used_ptr) \ + { \ + mb->hitend = TRUE; \ + if (mb->partial > 1) return PCRE2_ERROR_PARTIAL; \ + } -/* Do the recursion. After processing each alternative, restore the ovector -data and the last captured value. */ +/* These macros are used to implement backtracking. They simulate a recursive +call to the match() function by means of a local vector of frames which +remember the backtracking points. */ -do - { - if (cbegroup) mb->match_function_type |= MATCH_CBEGROUP; - rrc = match(eptr, callpat + PRIV(OP_lengths)[*callpat], mstart, offset_top, - mb, eptrb, rdepth + 1); - memcpy(mb->ovector, new_recursive->ovec_save, - mb->offset_end * sizeof(PCRE2_SIZE)); - mb->capture_last = new_recursive->saved_capture_last; - if (rrc == MATCH_MATCH || rrc == MATCH_ACCEPT) return rrc; - - /* PCRE does not allow THEN, SKIP, PRUNE or COMMIT to escape beyond a - recursion; they cause a NOMATCH for the entire recursion. These codes - are defined in a range that can be tested for. */ - - if (rrc >= MATCH_BACKTRACK_MIN && rrc <= MATCH_BACKTRACK_MAX) - return MATCH_NOMATCH; - - /* Any return code other than NOMATCH is an error. Otherwise, advance to the - next alternative or to the end of the recursing subpattern. If there were - nested recursions, mb->recursive might be changed, so reset it before - looping. */ - - if (rrc != MATCH_NOMATCH) return rrc; - mb->recursive = new_recursive; - callpat += GET(callpat, 1); +#define RMATCH(ra,rb)\ + {\ + start_ecode = ra;\ + Freturn_id = rb;\ + goto MATCH_RECURSE;\ + L_##rb:;\ } -while (*callpat == OP_ALT); /* Loop for the alternatives */ - -/* None of the alternatives matched. */ -return MATCH_NOMATCH; -} -#endif /* HEAP_MATCH_RECURSE */ +#define RRETURN(ra)\ + {\ + rrc = ra;\ + goto RETURN_SWITCH;\ + } @@ -523,2022 +535,1713 @@ return MATCH_NOMATCH; * Match from current position * *************************************************/ -/* This function is called recursively in many circumstances. Whenever it -returns a negative (error) response, the outer incarnation must also return the -same response. */ - -/* These macros pack up tests that are used for partial matching, and which -appear several times in the code. We set the "hit end" flag if the pointer is -at the end of the subject and also past the earliest inspected character (i.e. -something has been matched, even if not part of the actual matched string). For -hard partial matching, we then return immediately. The second one is used when -we already know we are past the end of the subject. */ - -#define CHECK_PARTIAL()\ - if (mb->partial != 0 && eptr >= mb->end_subject && \ - eptr > mb->start_used_ptr) \ - { \ - mb->hitend = TRUE; \ - if (mb->partial > 1) RRETURN(PCRE2_ERROR_PARTIAL); \ - } - -#define SCHECK_PARTIAL()\ - if (mb->partial != 0 && eptr > mb->start_used_ptr) \ - { \ - mb->hitend = TRUE; \ - if (mb->partial > 1) RRETURN(PCRE2_ERROR_PARTIAL); \ - } - +/* This function is called to run one match attempt at a single starting point +in the subject. -/* Performance note: It might be tempting to extract commonly used fields from -the mb structure (e.g. utf, end_subject) into individual variables to improve +Performance note: It might be tempting to extract commonly used fields from the +mb structure (e.g. end_subject) into individual variables to improve performance. Tests using gcc on a SPARC disproved this; in the first case, it made performance worse. Arguments: - eptr pointer to current character in subject - ecode pointer to current position in compiled code - mstart pointer to the current match start position (can be modified - by encountering \K) - offset_top current top pointer (highest ovector offset used + 1) - mb pointer to "static" info block for the match - eptrb pointer to chain of blocks containing eptr at start of - brackets - for testing for empty matches - rdepth the recursion depth - -Returns: MATCH_MATCH if matched ) these values are >= 0 - MATCH_NOMATCH if failed to match ) - a negative MATCH_xxx value for PRUNE, SKIP, etc - a negative PCRE2_ERROR_xxx value if aborted by an error condition - (e.g. stopped by repeated call or recursion limit) + start_eptr starting character in subject + start_ecode starting position in compiled code + ovector pointer to the final output vector + oveccount number of pairs in ovector + top_bracket number of capturing parentheses in the pattern + frame_size size of each backtracking frame + mb pointer to "static" variables block + +Returns: MATCH_MATCH if matched ) these values are >= 0 + MATCH_NOMATCH if failed to match ) + negative MATCH_xxx value for PRUNE, SKIP, etc + negative PCRE2_ERROR_xxx value if aborted by an error condition + (e.g. stopped by repeated call or depth limit) */ static int -match(PCRE2_SPTR eptr, PCRE2_SPTR ecode, PCRE2_SPTR mstart, - PCRE2_SIZE offset_top, match_block *mb, eptrblock *eptrb, uint32_t rdepth) +match(PCRE2_SPTR start_eptr, PCRE2_SPTR start_ecode, PCRE2_SIZE *ovector, + uint16_t oveccount, uint16_t top_bracket, PCRE2_SIZE frame_size, + match_block *mb) { -/* These variables do not need to be preserved over recursion in this function, -so they can be ordinary variables in all cases. Mark some of them with -"register" because they are used a lot in loops. */ - -int rrc; /* Returns from recursive calls */ -int i; /* Used for loops not involving calls to RMATCH() */ -uint32_t c; /* Character values not kept over RMATCH() calls */ -BOOL utf; /* Local copy of UTF flag for speed */ - -BOOL minimize, possessive; /* Quantifier options */ -int condcode; +/* Frame-handling variables */ -/* When recursion is not being used, all "local" variables that have to be -preserved over calls to RMATCH() are part of a "frame". We set up the top-level -frame on the stack here; subsequent instantiations are obtained from the heap -whenever RMATCH() does a "recursion". See the macro definitions above. Putting -the top-level on the stack rather than malloc-ing them all gives a performance -boost in many cases where there is not much "recursion". */ +heapframe *F; /* Current frame pointer */ +heapframe *N = NULL; /* Temporary frame pointers */ +heapframe *P = NULL; +heapframe *assert_accept_frame; /* For passing back the frame with captures */ +PCRE2_SIZE frame_copy_size; /* Amount to copy when creating a new frame */ -#ifdef HEAP_MATCH_RECURSE -heapframe *frame = (heapframe *)mb->match_frames_base; +/* Local variables that do not need to be preserved over calls to RRMATCH(). */ -/* Copy in the original argument variables */ +PCRE2_SPTR bracode; /* Temp pointer to start of group */ +PCRE2_SIZE offset; /* Used for group offsets */ +PCRE2_SIZE length; /* Used for various length calculations */ -frame->Xeptr = eptr; -frame->Xecode = ecode; -frame->Xmstart = mstart; -frame->Xoffset_top = offset_top; -frame->Xeptrb = eptrb; -frame->Xrdepth = rdepth; - -/* This is where control jumps back to to effect "recursion" */ - -HEAP_RECURSE: +int rrc; /* Return from functions & backtracking "recursions" */ +#ifdef SUPPORT_UNICODE +int proptype; /* Type of character property */ +#endif -/* Macros make the argument variables come from the current frame */ +uint32_t i; /* Used for local loops */ +uint32_t fc; /* Character values */ +uint32_t number; /* Used for group and other numbers */ +uint32_t reptype = 0; /* Type of repetition (0 to avoid compiler warning) */ +uint32_t group_frame_type; /* Specifies type for new group frames */ -#define eptr frame->Xeptr -#define ecode frame->Xecode -#define mstart frame->Xmstart -#define offset_top frame->Xoffset_top -#define eptrb frame->Xeptrb -#define rdepth frame->Xrdepth +BOOL condition; /* Used in conditional groups */ +BOOL cur_is_word; /* Used in "word" tests */ +BOOL prev_is_word; /* Used in "word" tests */ -/* Ditto for the local variables */ +/* UTF flag */ #ifdef SUPPORT_UNICODE -#define charptr frame->Xcharptr -#define prop_value frame->Xprop_value -#define prop_type frame->Xprop_type -#define prop_fail_result frame->Xprop_fail_result -#define oclength frame->Xoclength -#define occhars frame->Xocchars +BOOL utf = (mb->poptions & PCRE2_UTF) != 0; +#else +BOOL utf = FALSE; #endif +/* This is the length of the last part of a backtracking frame that must be +copied when a new frame is created. */ -#define callpat frame->Xcallpat -#define codelink frame->Xcodelink -#define data frame->Xdata -#define next_ecode frame->Xnext_ecode -#define pp frame->Xpp -#define prev frame->Xprev -#define saved_eptr frame->Xsaved_eptr - -#define new_recursive frame->Xnew_recursive - -#define ctype frame->Xctype -#define fc frame->Xfc -#define fi frame->Xfi -#define length frame->Xlength -#define max frame->Xmax -#define min frame->Xmin -#define number frame->Xnumber -#define offset frame->Xoffset -#define op frame->Xop -#define save_capture_last frame->Xsave_capture_last -#define save_offset1 frame->Xsave_offset1 -#define save_offset2 frame->Xsave_offset2 -#define save_offset3 frame->Xsave_offset3 - -#define condition frame->Xcondition -#define cur_is_word frame->Xcur_is_word -#define prev_is_word frame->Xprev_is_word - -#define newptrb frame->Xnewptrb - -/* When normal stack-based recursion is being used for match(), local variables -are allocated on the stack and get preserved during recursion in the usual way. -In this environment, fi and i, and fc and c, can be the same variables. */ - -#else /* HEAP_MATCH_RECURSE not defined */ -#define fi i -#define fc c - -/* Many of the following variables are used only in small blocks of the code. -My normal style of coding would have declared them within each of those blocks. -However, in order to accommodate the version of this code that uses an external -"stack" implemented on the heap, it is easier to declare them all here, so the -declarations can be cut out in a block. The only declarations within blocks -below are for variables that do not have to be preserved over a recursive call -to RMATCH(). */ - -#ifdef SUPPORT_UNICODE -PCRE2_SPTR charptr; -#endif -PCRE2_SPTR callpat; -PCRE2_SPTR data; -PCRE2_SPTR next_ecode; -PCRE2_SPTR pp; -PCRE2_SPTR prev; -PCRE2_SPTR saved_eptr; +frame_copy_size = frame_size - offsetof(heapframe, eptr); -PCRE2_SIZE length; -PCRE2_SIZE offset; -PCRE2_SIZE save_offset1, save_offset2, save_offset3; +/* Set up the first current frame at the start of the vector, and initialize +fields that are not reset for new frames. */ -uint32_t number; -uint32_t op; -uint32_t save_capture_last; +F = mb->match_frames; +Frdepth = 0; /* "Recursion" depth */ +Fcapture_last = 0; /* Number of most recent capture */ +Fcurrent_recurse = RECURSE_UNSET; /* Not pattern recursing. */ +Fstart_match = Feptr = start_eptr; /* Current data pointer and start match */ +Fmark = NULL; /* Most recent mark */ +Foffset_top = 0; /* End of captures within the frame */ +Flast_group_offset = PCRE2_UNSET; /* Saved frame of most recent group */ +group_frame_type = 0; /* Not a start of group frame */ +goto NEW_FRAME; /* Start processing with this frame */ -#ifdef SUPPORT_UNICODE -uint32_t prop_value; -int prop_type; -int prop_fail_result; -int oclength; -PCRE2_UCHAR occhars[6]; -#endif +/* Come back here when we want to create a new frame for remembering a +backtracking point. */ -int codelink; -int ctype; -int max; -int min; +MATCH_RECURSE: -BOOL condition; -BOOL cur_is_word; -BOOL prev_is_word; +/* Set up a new backtracking frame. If the vector is full, get a new one +on the heap, doubling the size, but constrained by the heap limit. */ -eptrblock newptrb; -recursion_info new_recursive; -#endif /* HEAP_MATCH_RECURSE not defined */ +N = (heapframe *)((char *)F + frame_size); +if (N >= mb->match_frames_top) + { + PCRE2_SIZE newsize = mb->frame_vector_size * 2; + heapframe *new; -/* To save space on the stack and in the heap frame, I have doubled up on some -of the local variables that are used only in localised parts of the code, but -still need to be preserved over recursive calls of match(). These macros define -the alternative names that are used. */ + if ((newsize / 1024) > mb->heap_limit) + { + PCRE2_SIZE maxsize = ((mb->heap_limit * 1024)/frame_size) * frame_size; + if (mb->frame_vector_size >= maxsize) return PCRE2_ERROR_HEAPLIMIT; + newsize = maxsize; + } -#define allow_zero cur_is_word -#define caseless cur_is_word -#define cbegroup condition -#define code_offset codelink -#define condassert condition -#define foc number -#define matched_once prev_is_word -#define save_mark data + new = mb->memctl.malloc(newsize, mb->memctl.memory_data); + if (new == NULL) return PCRE2_ERROR_NOMEMORY; + memcpy(new, mb->match_frames, mb->frame_vector_size); -/* These statements are here to stop the compiler complaining about unitialized -variables. */ + F = (heapframe *)((char *)new + ((char *)F - (char *)mb->match_frames)); + N = (heapframe *)((char *)F + frame_size); -#ifdef SUPPORT_UNICODE -prop_value = 0; -prop_fail_result = 0; -#endif + if (mb->match_frames != mb->stack_frames) + mb->memctl.free(mb->match_frames, mb->memctl.memory_data); + mb->match_frames = new; + mb->match_frames_top = (heapframe *)((char *)mb->match_frames + newsize); + mb->frame_vector_size = newsize; + } +#ifdef DEBUG_SHOW_RMATCH +fprintf(stderr, "++ RMATCH %2d frame=%d", Freturn_id, Frdepth + 1); +if (group_frame_type != 0) + { + fprintf(stderr, " type=%x ", group_frame_type); + switch (GF_IDMASK(group_frame_type)) + { + case GF_CAPTURE: + fprintf(stderr, "capture=%d", GF_DATAMASK(group_frame_type)); + break; -/* This label is used for tail recursion, which is used in a few cases even -when HEAP_MATCH_RECURSE is not defined, in order to reduce the amount of stack -that is used. Thanks to Ian Taylor for noticing this possibility and sending -the original patch. */ + case GF_NOCAPTURE: + fprintf(stderr, "nocapture op=%d", GF_DATAMASK(group_frame_type)); + break; -TAIL_RECURSE: + case GF_CONDASSERT: + fprintf(stderr, "condassert op=%d", GF_DATAMASK(group_frame_type)); + break; -/* OK, now we can get on with the real code of the function. Recursive calls -are specified by the macro RMATCH and RRETURN is used to return. When -HEAP_MATCH_RECURSE is *not* defined, these just turn into a recursive call to -match() and a "return", respectively. However, RMATCH isn't like a function -call because it's quite a complicated macro. It has to be used in one -particular way. This shouldn't, however, impact performance when true recursion -is being used. */ + case GF_RECURSE: + fprintf(stderr, "recurse=%d", GF_DATAMASK(group_frame_type)); + break; -#ifdef SUPPORT_UNICODE -utf = (mb->poptions & PCRE2_UTF) != 0; -#else -utf = FALSE; + default: + fprintf(stderr, "*** unknown ***"); + break; + } + } +fprintf(stderr, "\n"); #endif -/* First check that we haven't called match() too many times, or that we -haven't exceeded the recursive call limit. */ +/* Copy those fields that must be copied into the new frame, increase the +"recursion" depth (i.e. the new frame's index) and then make the new frame +current. */ + +memcpy((char *)N + offsetof(heapframe, eptr), + (char *)F + offsetof(heapframe, eptr), + frame_copy_size); + +N->rdepth = Frdepth + 1; +F = N; -if (mb->match_call_count++ >= mb->match_limit) RRETURN(PCRE2_ERROR_MATCHLIMIT); -if (rdepth >= mb->match_limit_recursion) RRETURN(PCRE2_ERROR_RECURSIONLIMIT); +/* Carry on processing with a new frame. */ -/* At the start of a group with an unlimited repeat that may match an empty -string, the variable mb->match_function_type contains the MATCH_CBEGROUP bit. -It is done this way to save having to use another function argument, which -would take up space on the stack. See also MATCH_CONDASSERT below. +NEW_FRAME: +Fgroup_frame_type = group_frame_type; +Fecode = start_ecode; /* Starting code pointer */ +Fback_frame = frame_size; /* Default is go back one frame */ -When MATCH_CBEGROUP is set, add the current subject pointer to the chain of -such remembered pointers, to be checked when we hit the closing ket, in order -to break infinite loops that match no characters. When match() is called in -other circumstances, don't add to the chain. The MATCH_CBEGROUP feature must -NOT be used with tail recursion, because the memory block that is used is on -the stack, so a new one may be required for each match(). */ +/* If this is a special type of group frame, remember its offset for quick +access at the end of the group. If this is a recursion, set a new current +recursion value. */ -if ((mb->match_function_type & MATCH_CBEGROUP) != 0) +if (group_frame_type != 0) { - newptrb.epb_saved_eptr = eptr; - newptrb.epb_prev = eptrb; - eptrb = &newptrb; - mb->match_function_type &= ~MATCH_CBEGROUP; + Flast_group_offset = (char *)F - (char *)mb->match_frames; + if (GF_IDMASK(group_frame_type) == GF_RECURSE) + Fcurrent_recurse = GF_DATAMASK(group_frame_type); + group_frame_type = 0; } -/* Now, at last, we can start processing the opcodes. */ + +/* ========================================================================= */ +/* This is the main processing loop. First check that we haven't recorded too +many backtracks (search tree is too large), or that we haven't exceeded the +recursive depth limit (used too many backtracking frames). If not, process the +opcodes. */ + +if (mb->match_call_count++ >= mb->match_limit) return PCRE2_ERROR_MATCHLIMIT; +if (Frdepth >= mb->match_limit_depth) return PCRE2_ERROR_DEPTHLIMIT; for (;;) { - minimize = possessive = FALSE; - op = *ecode; +#ifdef DEBUG_SHOW_OPS +fprintf(stderr, "++ op=%d\n", *Fecode); +#endif - switch(op) + Fop = *Fecode; + switch(Fop) { - case OP_MARK: - mb->nomatch_mark = ecode + 2; - mb->mark = NULL; /* In case previously set by assertion */ - RMATCH(eptr, ecode + PRIV(OP_lengths)[*ecode] + ecode[1], offset_top, mb, - eptrb, RM55); - if ((rrc == MATCH_MATCH || rrc == MATCH_ACCEPT) && - mb->mark == NULL) mb->mark = ecode + 2; + /* ===================================================================== */ + /* Before OP_ACCEPT there may be any number of OP_CLOSE opcodes, to close + any currently open capturing brackets. Unlike reaching the end of a group, + where we know the starting frame is at the top of the chained frames, in + this case we have to search back for the relevant frame in case other types + of group that use chained frames have intervened. Multiple OP_CLOSEs always + come innermost first, which matches the chain order. We can ignore this in + a recursion, because captures are not passed out of recursions. */ - /* A return of MATCH_SKIP_ARG means that matching failed at SKIP with an - argument, and we must check whether that argument matches this MARK's - argument. It is passed back in mb->start_match_ptr (an overloading of that - variable). If it does match, we reset that variable to the current subject - position and return MATCH_SKIP. Otherwise, pass back the return code - unaltered. */ - - else if (rrc == MATCH_SKIP_ARG && - PRIV(strcmp)(ecode + 2, mb->start_match_ptr) == 0) + case OP_CLOSE: + if (Fcurrent_recurse == RECURSE_UNSET) { - mb->start_match_ptr = eptr; - RRETURN(MATCH_SKIP); + number = GET2(Fecode, 1); + offset = Flast_group_offset; + for(;;) + { + if (offset == PCRE2_UNSET) return PCRE2_ERROR_INTERNAL; + N = (heapframe *)((char *)mb->match_frames + offset); + P = (heapframe *)((char *)N - frame_size); + if (N->group_frame_type == (GF_CAPTURE | number)) break; + offset = P->last_group_offset; + } + offset = (number << 1) - 2; + Fcapture_last = number; + Fovector[offset] = P->eptr - mb->start_subject; + Fovector[offset+1] = Feptr - mb->start_subject; + if (offset >= Foffset_top) Foffset_top = offset + 2; } - RRETURN(rrc); + Fecode += PRIV(OP_lengths)[*Fecode]; + break; - case OP_FAIL: - RRETURN(MATCH_NOMATCH); - case OP_COMMIT: - RMATCH(eptr, ecode + PRIV(OP_lengths)[*ecode], offset_top, mb, - eptrb, RM52); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - RRETURN(MATCH_COMMIT); + /* ===================================================================== */ + /* Real or forced end of the pattern, assertion, or recursion. In an + assertion ACCEPT, update the last used pointer and remember the current + frame so that the captures can be fished out of it. */ - case OP_PRUNE: - RMATCH(eptr, ecode + PRIV(OP_lengths)[*ecode], offset_top, mb, - eptrb, RM51); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - RRETURN(MATCH_PRUNE); + case OP_ASSERT_ACCEPT: + if (Feptr > mb->last_used_ptr) mb->last_used_ptr = Feptr; + assert_accept_frame = F; + RRETURN(MATCH_ACCEPT); - case OP_PRUNE_ARG: - mb->nomatch_mark = ecode + 2; - mb->mark = NULL; /* In case previously set by assertion */ - RMATCH(eptr, ecode + PRIV(OP_lengths)[*ecode] + ecode[1], offset_top, mb, - eptrb, RM56); - if ((rrc == MATCH_MATCH || rrc == MATCH_ACCEPT) && - mb->mark == NULL) mb->mark = ecode + 2; - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - RRETURN(MATCH_PRUNE); + /* If recursing, we have to find the most recent recursion. */ - case OP_SKIP: - RMATCH(eptr, ecode + PRIV(OP_lengths)[*ecode], offset_top, mb, - eptrb, RM53); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - mb->start_match_ptr = eptr; /* Pass back current position */ - RRETURN(MATCH_SKIP); + case OP_ACCEPT: + case OP_END: - /* Note that, for Perl compatibility, SKIP with an argument does NOT set - nomatch_mark. When a pattern match ends with a SKIP_ARG for which there was - not a matching mark, we have to re-run the match, ignoring the SKIP_ARG - that failed and any that precede it (either they also failed, or were not - triggered). To do this, we maintain a count of executed SKIP_ARGs. If a - SKIP_ARG gets to top level, the match is re-run with mb->ignore_skip_arg - set to the count of the one that failed. */ + /* Handle end of a recursion. */ - case OP_SKIP_ARG: - mb->skip_arg_count++; - if (mb->skip_arg_count <= mb->ignore_skip_arg) + if (Fcurrent_recurse != RECURSE_UNSET) { - ecode += PRIV(OP_lengths)[*ecode] + ecode[1]; - break; - } - RMATCH(eptr, ecode + PRIV(OP_lengths)[*ecode] + ecode[1], offset_top, mb, - eptrb, RM57); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); + offset = Flast_group_offset; + for(;;) + { + if (offset == PCRE2_UNSET) return PCRE2_ERROR_INTERNAL; + N = (heapframe *)((char *)mb->match_frames + offset); + P = (heapframe *)((char *)N - frame_size); + if (GF_IDMASK(N->group_frame_type) == GF_RECURSE) break; + offset = P->last_group_offset; + } - /* Pass back the current skip name by overloading mb->start_match_ptr and - returning the special MATCH_SKIP_ARG return code. This will either be - caught by a matching MARK, or get to the top, where it causes a rematch - with mb->ignore_skip_arg set to the value of mb->skip_arg_count. */ + /* N is now the frame of the recursion; the previous frame is at the + OP_RECURSE position. Go back there, copying the current subject position + and mark, and move on past the OP_RECURSE. */ - mb->start_match_ptr = ecode + 2; - RRETURN(MATCH_SKIP_ARG); + P->eptr = Feptr; + P->mark = Fmark; + F = P; + Fecode += 1 + LINK_SIZE; + continue; + } - /* For THEN (and THEN_ARG) we pass back the address of the opcode, so that - the branch in which it occurs can be determined. Overload the start of - match pointer to do this. */ + /* Not a recursion. Fail for an empty string match if either PCRE2_NOTEMPTY + is set, or if PCRE2_NOTEMPTY_ATSTART is set and we have matched at the + start of the subject. In both cases, backtracking will then try other + alternatives, if any. */ - case OP_THEN: - RMATCH(eptr, ecode + PRIV(OP_lengths)[*ecode], offset_top, mb, - eptrb, RM54); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - mb->start_match_ptr = ecode; - RRETURN(MATCH_THEN); + if (Feptr == Fstart_match && + ((mb->moptions & PCRE2_NOTEMPTY) != 0 || + ((mb->moptions & PCRE2_NOTEMPTY_ATSTART) != 0 && + Fstart_match == mb->start_subject + mb->start_offset))) + RRETURN(MATCH_NOMATCH); - case OP_THEN_ARG: - mb->nomatch_mark = ecode + 2; - mb->mark = NULL; /* In case previously set by assertion */ - RMATCH(eptr, ecode + PRIV(OP_lengths)[*ecode] + ecode[1], offset_top, - mb, eptrb, RM58); - if ((rrc == MATCH_MATCH || rrc == MATCH_ACCEPT) && - mb->mark == NULL) mb->mark = ecode + 2; - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - mb->start_match_ptr = ecode; - RRETURN(MATCH_THEN); + /* Also fail if PCRE2_ENDANCHORED is set and the end of the match is not + the end of the subject. After (*ACCEPT) we fail the entire match (at this + position) but backtrack on reaching the end of the pattern. */ - /* Handle an atomic group that does not contain any capturing parentheses. - This can be handled like an assertion. Prior to 8.13, all atomic groups - were handled this way. In 8.13, the code was changed as below for ONCE, so - that backups pass through the group and thereby reset captured values. - However, this uses a lot more stack, so in 8.20, atomic groups that do not - contain any captures generate OP_ONCE_NC, which can be handled in the old, - less stack intensive way. - - Check the alternative branches in turn - the matching won't pass the KET - for this kind of subpattern. If any one branch matches, we carry on as at - the end of a normal bracket, leaving the subject pointer, but resetting - the start-of-match value in case it was changed by \K. */ - - case OP_ONCE_NC: - prev = ecode; - saved_eptr = eptr; - save_mark = mb->mark; - do + if (Feptr < mb->end_subject && + ((mb->moptions | mb->poptions) & PCRE2_ENDANCHORED) != 0) { - RMATCH(eptr, ecode + 1 + LINK_SIZE, offset_top, mb, eptrb, RM64); - if (rrc == MATCH_MATCH) /* Note: _not_ MATCH_ACCEPT */ - { - mstart = mb->start_match_ptr; - break; - } - if (rrc == MATCH_THEN) - { - next_ecode = ecode + GET(ecode,1); - if (mb->start_match_ptr < next_ecode && - (*ecode == OP_ALT || *next_ecode == OP_ALT)) - rrc = MATCH_NOMATCH; - } - - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - ecode += GET(ecode,1); - mb->mark = save_mark; + if (Fop == OP_END) RRETURN(MATCH_NOMATCH); + return MATCH_NOMATCH; } - while (*ecode == OP_ALT); - /* If hit the end of the group (which could be repeated), fail */ + /* We have a successful match of the whole pattern. Record the result and + then do a direct return from the function. If there is space in the offset + vector, set any pairs that follow the highest-numbered captured string but + are less than the number of capturing groups in the pattern to PCRE2_UNSET. + It is documented that this happens. "Gaps" are set to PCRE2_UNSET + dynamically. It is only those at the end that need setting here. */ - if (*ecode != OP_ONCE_NC && *ecode != OP_ALT) RRETURN(MATCH_NOMATCH); + mb->end_match_ptr = Feptr; /* Record where we ended */ + mb->end_offset_top = Foffset_top; /* and how many extracts were taken */ + mb->mark = Fmark; /* and the last success mark */ + if (Feptr > mb->last_used_ptr) mb->last_used_ptr = Feptr; - /* Continue as from after the group, updating the offsets high water - mark, since extracts may have been taken. */ + ovector[0] = Fstart_match - mb->start_subject; + ovector[1] = Feptr - mb->start_subject; - do ecode += GET(ecode, 1); while (*ecode == OP_ALT); + /* Set i to the smaller of the sizes of the external and frame ovectors. */ - offset_top = mb->end_offset_top; - eptr = mb->end_match_ptr; + i = 2 * ((top_bracket + 1 > oveccount)? oveccount : top_bracket + 1); + memcpy(ovector + 2, Fovector, (i - 2) * sizeof(PCRE2_SIZE)); + while (--i >= Foffset_top + 2) ovector[i] = PCRE2_UNSET; + return MATCH_MATCH; /* Note: NOT RRETURN */ - /* For a non-repeating ket, just continue at this level. This also - happens for a repeating ket if no characters were matched in the group. - This is the forcible breaking of infinite loops as implemented in Perl - 5.005. */ - - if (*ecode == OP_KET || eptr == saved_eptr) - { - ecode += 1+LINK_SIZE; - break; - } - /* The repeating kets try the rest of the pattern or restart from the - preceding bracket, in the appropriate order. The second "call" of match() - uses tail recursion, to avoid using another stack frame. */ + /*===================================================================== */ + /* Match any single character type except newline; have to take care with + CRLF newlines and partial matching. */ - if (*ecode == OP_KETRMIN) - { - RMATCH(eptr, ecode + 1 + LINK_SIZE, offset_top, mb, eptrb, RM65); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - ecode = prev; - goto TAIL_RECURSE; - } - else /* OP_KETRMAX */ + case OP_ANY: + if (IS_NEWLINE(Feptr)) RRETURN(MATCH_NOMATCH); + if (mb->partial != 0 && + Feptr == mb->end_subject - 1 && + NLBLOCK->nltype == NLTYPE_FIXED && + NLBLOCK->nllen == 2 && + UCHAR21TEST(Feptr) == NLBLOCK->nl[0]) { - RMATCH(eptr, prev, offset_top, mb, eptrb, RM66); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - ecode += 1 + LINK_SIZE; - goto TAIL_RECURSE; + mb->hitend = TRUE; + if (mb->partial > 1) return PCRE2_ERROR_PARTIAL; } - /* Control never gets here */ - - /* Handle a capturing bracket, other than those that are possessive with an - unlimited repeat. If there is space in the offset vector, save the current - subject position in the working slot at the top of the vector. We mustn't - change the current values of the data slot, because they may be set from a - previous iteration of this group, and be referred to by a reference inside - the group. A failure to match might occur after the group has succeeded, - if something later on doesn't match. For this reason, we need to restore - the working value and also the values of the final offsets, in case they - were set by a previous iteration of the same bracket. - - If there isn't enough space in the offset vector, treat this as if it were - a non-capturing bracket. Don't worry about setting the flag for the error - case here; that is handled in the code for KET. */ - - case OP_CBRA: - case OP_SCBRA: - number = GET2(ecode, 1+LINK_SIZE); - offset = number << 1; - - if (offset < mb->offset_max) - { - save_offset1 = mb->ovector[offset]; - save_offset2 = mb->ovector[offset+1]; - save_offset3 = mb->ovector[mb->offset_end - number]; - save_capture_last = mb->capture_last; - save_mark = mb->mark; - - mb->ovector[mb->offset_end - number] = eptr - mb->start_subject; - - for (;;) - { - if (op >= OP_SBRA) mb->match_function_type |= MATCH_CBEGROUP; - RMATCH(eptr, ecode + PRIV(OP_lengths)[*ecode], offset_top, mb, - eptrb, RM1); - if (rrc == MATCH_ONCE) break; /* Backing up through an atomic group */ - - /* If we backed up to a THEN, check whether it is within the current - branch by comparing the address of the THEN that is passed back with - the end of the branch. If it is within the current branch, and the - branch is one of two or more alternatives (it either starts or ends - with OP_ALT), we have reached the limit of THEN's action, so convert - the return code to NOMATCH, which will cause normal backtracking to - happen from now on. Otherwise, THEN is passed back to an outer - alternative. This implements Perl's treatment of parenthesized groups, - where a group not containing | does not affect the current alternative, - that is, (X) is NOT the same as (X|(*F)). */ - - if (rrc == MATCH_THEN) - { - next_ecode = ecode + GET(ecode,1); - if (mb->start_match_ptr < next_ecode && - (*ecode == OP_ALT || *next_ecode == OP_ALT)) - rrc = MATCH_NOMATCH; - } - - /* Anything other than NOMATCH is passed back. */ - - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - mb->capture_last = save_capture_last; - ecode += GET(ecode, 1); - mb->mark = save_mark; - if (*ecode != OP_ALT) break; - } - - mb->ovector[offset] = save_offset1; - mb->ovector[offset+1] = save_offset2; - mb->ovector[mb->offset_end - number] = save_offset3; + /* Fall through */ - /* At this point, rrc will be one of MATCH_ONCE or MATCH_NOMATCH. */ + /* Match any single character whatsoever. */ - RRETURN(rrc); + case OP_ALLANY: + if (Feptr >= mb->end_subject) /* DO NOT merge the Feptr++ here; it must */ + { /* not be updated before SCHECK_PARTIAL. */ + SCHECK_PARTIAL(); + RRETURN(MATCH_NOMATCH); } + Feptr++; +#ifdef SUPPORT_UNICODE + if (utf) ACROSSCHAR(Feptr < mb->end_subject, *Feptr, Feptr++); +#endif + Fecode++; + break; - /* FALL THROUGH ... Insufficient room for saving captured contents. Treat - as a non-capturing bracket. */ - - /* VVVVVVVVVVVVVVVVVVVVVVVVV */ - /* VVVVVVVVVVVVVVVVVVVVVVVVV */ - - /* Non-capturing or atomic group, except for possessive with unlimited - repeat and ONCE group with no captures. Loop for all the alternatives. - When we get to the final alternative within the brackets, we used to return - the result of a recursive call to match() whatever happened so it was - possible to reduce stack usage by turning this into a tail recursion, - except in the case of a possibly empty group. However, now that there is - the possiblity of (*THEN) occurring in the final alternative, this - optimization is no longer always possible. + /* ===================================================================== */ + /* Match a single code unit, even in UTF mode. This opcode really does + match any code unit, even newline. (It really should be called ANYCODEUNIT, + of course - the byte name is from pre-16 bit days.) */ - We can optimize if we know there are no (*THEN)s in the pattern; at present - this is the best that can be done. + case OP_ANYBYTE: + if (Feptr >= mb->end_subject) /* DO NOT merge the Feptr++ here; it must */ + { /* not be updated before SCHECK_PARTIAL. */ + SCHECK_PARTIAL(); + RRETURN(MATCH_NOMATCH); + } + Feptr++; + Fecode++; + break; - MATCH_ONCE is returned when the end of an atomic group is successfully - reached, but subsequent matching fails. It passes back up the tree (causing - captured values to be reset) until the original atomic group level is - reached. This is tested by comparing mb->once_target with the start of the - group. At this point, the return is converted into MATCH_NOMATCH so that - previous backup points can be taken. */ - case OP_ONCE: - case OP_BRA: - case OP_SBRA: + /* ===================================================================== */ + /* Match a single character, casefully */ - for (;;) + case OP_CHAR: +#ifdef SUPPORT_UNICODE + if (utf) { - if (op >= OP_SBRA || op == OP_ONCE) - mb->match_function_type |= MATCH_CBEGROUP; - - /* If this is not a possibly empty group, and there are no (*THEN)s in - the pattern, and this is the final alternative, optimize as described - above. */ - - else if (!mb->hasthen && ecode[GET(ecode, 1)] != OP_ALT) + Flength = 1; + Fecode++; + GETCHARLEN(fc, Fecode, Flength); + if (Flength > (PCRE2_SIZE)(mb->end_subject - Feptr)) { - ecode += PRIV(OP_lengths)[*ecode]; - goto TAIL_RECURSE; + CHECK_PARTIAL(); /* Not SCHECK_PARTIAL() */ + RRETURN(MATCH_NOMATCH); } - - /* In all other cases, we have to make another call to match(). */ - - save_mark = mb->mark; - save_capture_last = mb->capture_last; - RMATCH(eptr, ecode + PRIV(OP_lengths)[*ecode], offset_top, mb, eptrb, - RM2); - - /* See comment in the code for capturing groups above about handling - THEN. */ - - if (rrc == MATCH_THEN) + for (; Flength > 0; Flength--) { - next_ecode = ecode + GET(ecode,1); - if (mb->start_match_ptr < next_ecode && - (*ecode == OP_ALT || *next_ecode == OP_ALT)) - rrc = MATCH_NOMATCH; + if (*Fecode++ != UCHAR21INC(Feptr)) RRETURN(MATCH_NOMATCH); } - - if (rrc != MATCH_NOMATCH) + } + else +#endif + /* Not UTF mode */ + { + if (mb->end_subject - Feptr < 1) { - if (rrc == MATCH_ONCE) - { - PCRE2_SPTR scode = ecode; - if (*scode != OP_ONCE) /* If not at start, find it */ - { - while (*scode == OP_ALT) scode += GET(scode, 1); - scode -= GET(scode, 1); - } - if (mb->once_target == scode) rrc = MATCH_NOMATCH; - } - RRETURN(rrc); + SCHECK_PARTIAL(); /* This one can use SCHECK_PARTIAL() */ + RRETURN(MATCH_NOMATCH); } - ecode += GET(ecode, 1); - mb->mark = save_mark; - if (*ecode != OP_ALT) break; - mb->capture_last = save_capture_last; + if (Fecode[1] != *Feptr++) RRETURN(MATCH_NOMATCH); + Fecode += 2; } + break; - RRETURN(MATCH_NOMATCH); - - /* Handle possessive capturing brackets with an unlimited repeat. We come - here from BRAZERO with allow_zero set TRUE. The ovector values are - handled similarly to the normal case above. However, the matching is - different. The end of these brackets will always be OP_KETRPOS, which - returns MATCH_KETRPOS without going further in the pattern. By this means - we can handle the group by iteration rather than recursion, thereby - reducing the amount of stack needed. If the ovector is too small for - capturing, treat as non-capturing. */ - case OP_CBRAPOS: - case OP_SCBRAPOS: - allow_zero = FALSE; + /* ===================================================================== */ + /* Match a single character, caselessly. If we are at the end of the + subject, give up immediately. We get here only when the pattern character + has at most one other case. Characters with more than two cases are coded + as OP_PROP with the pseudo-property PT_CLIST. */ - POSSESSIVE_CAPTURE: - number = GET2(ecode, 1+LINK_SIZE); - offset = number << 1; - if (offset >= mb->offset_max) goto POSSESSIVE_NON_CAPTURE; - - matched_once = FALSE; - code_offset = (int)(ecode - mb->start_code); - - save_offset1 = mb->ovector[offset]; - save_offset2 = mb->ovector[offset+1]; - save_offset3 = mb->ovector[mb->offset_end - number]; - save_capture_last = mb->capture_last; - - /* Each time round the loop, save the current subject position for use - when the group matches. For MATCH_MATCH, the group has matched, so we - restart it with a new subject starting position, remembering that we had - at least one match. For MATCH_NOMATCH, carry on with the alternatives, as - usual. If we haven't matched any alternatives in any iteration, check to - see if a previous iteration matched. If so, the group has matched; - continue from afterwards. Otherwise it has failed; restore the previous - capture values before returning NOMATCH. */ + case OP_CHARI: + if (Feptr >= mb->end_subject) + { + SCHECK_PARTIAL(); + RRETURN(MATCH_NOMATCH); + } - for (;;) +#ifdef SUPPORT_UNICODE + if (utf) { - mb->ovector[mb->offset_end - number] = eptr - mb->start_subject; - if (op >= OP_SBRA) mb->match_function_type |= MATCH_CBEGROUP; - RMATCH(eptr, ecode + PRIV(OP_lengths)[*ecode], offset_top, mb, - eptrb, RM63); - if (rrc == MATCH_KETRPOS) - { - offset_top = mb->end_offset_top; - ecode = mb->start_code + code_offset; - save_capture_last = mb->capture_last; - matched_once = TRUE; - mstart = mb->start_match_ptr; /* In case \K changed it */ - if (eptr == mb->end_match_ptr) /* Matched an empty string */ - { - do ecode += GET(ecode, 1); while (*ecode == OP_ALT); - break; - } - eptr = mb->end_match_ptr; - continue; - } + Flength = 1; + Fecode++; + GETCHARLEN(fc, Fecode, Flength); - /* See comment in the code for capturing groups above about handling - THEN. */ + /* If the pattern character's value is < 128, we know that its other case + (if any) is also < 128 (and therefore only one code unit long in all + code-unit widths), so we can use the fast lookup table. We checked above + that there is at least one character left in the subject. */ - if (rrc == MATCH_THEN) + if (fc < 128) { - next_ecode = ecode + GET(ecode,1); - if (mb->start_match_ptr < next_ecode && - (*ecode == OP_ALT || *next_ecode == OP_ALT)) - rrc = MATCH_NOMATCH; + uint32_t cc = UCHAR21(Feptr); + if (mb->lcc[fc] != TABLE_GET(cc, mb->lcc, cc)) RRETURN(MATCH_NOMATCH); + Fecode++; + Feptr++; } - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - mb->capture_last = save_capture_last; - ecode += GET(ecode, 1); - if (*ecode != OP_ALT) break; - } + /* Otherwise we must pick up the subject character and use Unicode + property support to test its other case. Note that we cannot use the + value of "Flength" to check for sufficient bytes left, because the other + case of the character may have more or fewer code units. */ - if (!matched_once) - { - mb->ovector[offset] = save_offset1; - mb->ovector[offset+1] = save_offset2; - mb->ovector[mb->offset_end - number] = save_offset3; + else + { + uint32_t dc; + GETCHARINC(dc, Feptr); + Fecode += Flength; + if (dc != fc && dc != UCD_OTHERCASE(fc)) RRETURN(MATCH_NOMATCH); + } } + else +#endif /* SUPPORT_UNICODE */ - if (allow_zero || matched_once) + /* Not UTF mode; use the table for characters < 256. */ { - ecode += 1 + LINK_SIZE; - break; + if (TABLE_GET(Fecode[1], mb->lcc, Fecode[1]) + != TABLE_GET(*Feptr, mb->lcc, *Feptr)) RRETURN(MATCH_NOMATCH); + Feptr++; + Fecode += 2; } - RRETURN(MATCH_NOMATCH); - - /* Non-capturing possessive bracket with unlimited repeat. We come here - from BRAZERO with allow_zero = TRUE. The code is similar to the above, - without the capturing complication. It is written out separately for speed - and cleanliness. */ + break; - case OP_BRAPOS: - case OP_SBRAPOS: - allow_zero = FALSE; - POSSESSIVE_NON_CAPTURE: - matched_once = FALSE; - code_offset = (int)(ecode - mb->start_code); - save_capture_last = mb->capture_last; + /* ===================================================================== */ + /* Match not a single character. */ - for (;;) + case OP_NOT: + case OP_NOTI: + if (Feptr >= mb->end_subject) { - if (op >= OP_SBRA) mb->match_function_type |= MATCH_CBEGROUP; - RMATCH(eptr, ecode + PRIV(OP_lengths)[*ecode], offset_top, mb, - eptrb, RM48); - if (rrc == MATCH_KETRPOS) + SCHECK_PARTIAL(); + RRETURN(MATCH_NOMATCH); + } +#ifdef SUPPORT_UNICODE + if (utf) + { + uint32_t ch; + Fecode++; + GETCHARINC(ch, Fecode); + GETCHARINC(fc, Feptr); + if (ch == fc) { - offset_top = mb->end_offset_top; - ecode = mb->start_code + code_offset; - matched_once = TRUE; - mstart = mb->start_match_ptr; /* In case \K reset it */ - if (eptr == mb->end_match_ptr) /* Matched an empty string */ - { - do ecode += GET(ecode, 1); while (*ecode == OP_ALT); - break; - } - eptr = mb->end_match_ptr; - continue; + RRETURN(MATCH_NOMATCH); /* Caseful match */ } - - /* See comment in the code for capturing groups above about handling - THEN. */ - - if (rrc == MATCH_THEN) + else if (Fop == OP_NOTI) /* If caseless */ { - next_ecode = ecode + GET(ecode,1); - if (mb->start_match_ptr < next_ecode && - (*ecode == OP_ALT || *next_ecode == OP_ALT)) - rrc = MATCH_NOMATCH; + if (ch > 127) + ch = UCD_OTHERCASE(ch); + else + ch = TABLE_GET(ch, mb->fcc, ch); + if (ch == fc) RRETURN(MATCH_NOMATCH); } - - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - ecode += GET(ecode, 1); - if (*ecode != OP_ALT) break; - mb->capture_last = save_capture_last; } - - if (matched_once || allow_zero) + else +#endif /* SUPPORT_UNICODE */ { - ecode += 1 + LINK_SIZE; - break; + uint32_t ch = Fecode[1]; + fc = *Feptr++; + if (ch == fc || (Fop == OP_NOTI && TABLE_GET(ch, mb->fcc, ch) == fc)) + RRETURN(MATCH_NOMATCH); + Fecode += 2; } - RRETURN(MATCH_NOMATCH); + break; - /* Control never reaches here. */ - /* Conditional group: compilation checked that there are no more than two - branches. If the condition is false, skipping the first branch takes us - past the end of the item if there is only one branch, but that's exactly - what we want. */ + /* ===================================================================== */ + /* Match a single character repeatedly. */ - case OP_COND: - case OP_SCOND: +#define Loclength F->temp_size +#define Lstart_eptr F->temp_sptr[0] +#define Lcharptr F->temp_sptr[1] +#define Lmin F->temp_32[0] +#define Lmax F->temp_32[1] +#define Lc F->temp_32[2] +#define Loc F->temp_32[3] - /* The variable codelink will be added to ecode when the condition is - false, to get to the second branch. Setting it to the offset to the ALT - or KET, then incrementing ecode achieves this effect. We now have ecode - pointing to the condition or callout. */ + case OP_EXACT: + case OP_EXACTI: + Lmin = Lmax = GET2(Fecode, 1); + Fecode += 1 + IMM2_SIZE; + goto REPEATCHAR; - codelink = GET(ecode, 1); /* Offset to the second branch */ - ecode += 1 + LINK_SIZE; /* From this opcode */ + case OP_POSUPTO: + case OP_POSUPTOI: + reptype = REPTYPE_POS; + Lmin = 0; + Lmax = GET2(Fecode, 1); + Fecode += 1 + IMM2_SIZE; + goto REPEATCHAR; - /* Because of the way auto-callout works during compile, a callout item is - inserted between OP_COND and an assertion condition. */ + case OP_UPTO: + case OP_UPTOI: + reptype = REPTYPE_MAX; + Lmin = 0; + Lmax = GET2(Fecode, 1); + Fecode += 1 + IMM2_SIZE; + goto REPEATCHAR; - if (*ecode == OP_CALLOUT || *ecode == OP_CALLOUT_STR) - { - unsigned int callout_length = (*ecode == OP_CALLOUT) - ? PRIV(OP_lengths)[OP_CALLOUT] : GET(ecode, 1 + 2*LINK_SIZE); + case OP_MINUPTO: + case OP_MINUPTOI: + reptype = REPTYPE_MIN; + Lmin = 0; + Lmax = GET2(Fecode, 1); + Fecode += 1 + IMM2_SIZE; + goto REPEATCHAR; - if (mb->callout != NULL) - { - pcre2_callout_block cb; - cb.version = 1; - cb.capture_top = (uint32_t)offset_top/2; - cb.capture_last = mb->capture_last & CAPLMASK; - cb.offset_vector = mb->ovector; - cb.mark = mb->nomatch_mark; - cb.subject = mb->start_subject; - cb.subject_length = (PCRE2_SIZE)(mb->end_subject - mb->start_subject); - cb.start_match = (PCRE2_SIZE)(mstart - mb->start_subject); - cb.current_position = (PCRE2_SIZE)(eptr - mb->start_subject); - cb.pattern_position = GET(ecode, 1); - cb.next_item_length = GET(ecode, 1 + LINK_SIZE); - - if (*ecode == OP_CALLOUT) - { - cb.callout_number = ecode[1 + 2*LINK_SIZE]; - cb.callout_string_offset = 0; - cb.callout_string = NULL; - cb.callout_string_length = 0; - } - else - { - cb.callout_number = 0; - cb.callout_string_offset = GET(ecode, 1 + 3*LINK_SIZE); - cb.callout_string = ecode + (1 + 4*LINK_SIZE) + 1; - cb.callout_string_length = - callout_length - (1 + 4*LINK_SIZE) - 2; - } + case OP_POSSTAR: + case OP_POSSTARI: + reptype = REPTYPE_POS; + Lmin = 0; + Lmax = UINT32_MAX; + Fecode++; + goto REPEATCHAR; - if ((rrc = mb->callout(&cb, mb->callout_data)) > 0) - RRETURN(MATCH_NOMATCH); - if (rrc < 0) RRETURN(rrc); - } + case OP_POSPLUS: + case OP_POSPLUSI: + reptype = REPTYPE_POS; + Lmin = 1; + Lmax = UINT32_MAX; + Fecode++; + goto REPEATCHAR; - /* Advance ecode past the callout, so it now points to the condition. We - must adjust codelink so that the value of ecode+codelink is unchanged. */ + case OP_POSQUERY: + case OP_POSQUERYI: + reptype = REPTYPE_POS; + Lmin = 0; + Lmax = 1; + Fecode++; + goto REPEATCHAR; - ecode += callout_length; - codelink -= callout_length; - } + case OP_STAR: + case OP_STARI: + case OP_MINSTAR: + case OP_MINSTARI: + case OP_PLUS: + case OP_PLUSI: + case OP_MINPLUS: + case OP_MINPLUSI: + case OP_QUERY: + case OP_QUERYI: + case OP_MINQUERY: + case OP_MINQUERYI: + fc = *Fecode++ - ((Fop < OP_STARI)? OP_STAR : OP_STARI); + Lmin = rep_min[fc]; + Lmax = rep_max[fc]; + reptype = rep_typ[fc]; - /* Test the various possible conditions */ + /* Common code for all repeated single-character matches. We first check + for the minimum number of characters. If the minimum equals the maximum, we + are done. Otherwise, if minimizing, check the rest of the pattern for a + match; if there isn't one, advance up to the maximum, one character at a + time. - condition = FALSE; - switch(condcode = *ecode) + If maximizing, advance up to the maximum number of matching characters, + until Feptr is past the end of the maximum run. If possessive, we are + then done (no backing up). Otherwise, match at this position; anything + other than no match is immediately returned. For nomatch, back up one + character, unless we are matching \R and the last thing matched was + \r\n, in which case, back up two code units until we reach the first + optional character position. + + The various UTF/non-UTF and caseful/caseless cases are handled separately, + for speed. */ + + REPEATCHAR: +#ifdef SUPPORT_UNICODE + if (utf) { - case OP_RREF: /* Numbered group recursion test */ - if (mb->recursive != NULL) /* Not recursing => FALSE */ - { - uint32_t recno = GET2(ecode, 1); /* Recursion group number*/ - condition = (recno == RREF_ANY || recno == mb->recursive->group_num); - } - break; + Flength = 1; + Lcharptr = Fecode; + GETCHARLEN(fc, Fecode, Flength); + Fecode += Flength; - case OP_DNRREF: /* Duplicate named group recursion test */ - if (mb->recursive != NULL) + /* Handle multi-code-unit character matching, caseful and caseless. */ + + if (Flength > 1) { - int count = GET2(ecode, 1 + IMM2_SIZE); - PCRE2_SPTR slot = mb->name_table + GET2(ecode, 1) * mb->name_entry_size; - while (count-- > 0) - { - uint32_t recno = GET2(slot, 0); - condition = recno == mb->recursive->group_num; - if (condition) break; - slot += mb->name_entry_size; - } - } - break; + uint32_t othercase; - case OP_CREF: /* Numbered group used test */ - offset = GET2(ecode, 1) << 1; /* Doubled ref number */ - condition = offset < offset_top && - mb->ovector[offset] != PCRE2_UNSET; - break; + if (Fop >= OP_STARI && /* Caseless */ + (othercase = UCD_OTHERCASE(fc)) != fc) + Loclength = PRIV(ord2utf)(othercase, Foccu); + else Loclength = 0; - case OP_DNCREF: /* Duplicate named group used test */ - { - int count = GET2(ecode, 1 + IMM2_SIZE); - PCRE2_SPTR slot = mb->name_table + GET2(ecode, 1) * mb->name_entry_size; - while (count-- > 0) + for (i = 1; i <= Lmin; i++) { - offset = GET2(slot, 0) << 1; - condition = offset < offset_top && - mb->ovector[offset] != PCRE2_UNSET; - if (condition) break; - slot += mb->name_entry_size; + if (Feptr <= mb->end_subject - Flength && + memcmp(Feptr, Lcharptr, CU2BYTES(Flength)) == 0) Feptr += Flength; + else if (Loclength > 0 && + Feptr <= mb->end_subject - Loclength && + memcmp(Feptr, Foccu, CU2BYTES(Loclength)) == 0) + Feptr += Loclength; + else + { + CHECK_PARTIAL(); + RRETURN(MATCH_NOMATCH); + } } - } - break; - - case OP_FALSE: - case OP_FAIL: /* The assertion (?!) becomes OP_FAIL */ - break; - - case OP_TRUE: - condition = TRUE; - break; - /* The condition is an assertion. Call match() to evaluate it - setting - the MATCH_CONDASSERT bit in mb->match_function_type causes it to stop at - the end of an assertion. */ + if (Lmin == Lmax) continue; - default: - mb->match_function_type |= MATCH_CONDASSERT; - RMATCH(eptr, ecode, offset_top, mb, NULL, RM3); - if (rrc == MATCH_MATCH) - { - if (mb->end_offset_top > offset_top) - offset_top = mb->end_offset_top; /* Captures may have happened */ - condition = TRUE; - - /* Advance ecode past the assertion to the start of the first branch, - but adjust it so that the general choosing code below works. If the - assertion has a quantifier that allows zero repeats we must skip over - the BRAZERO. This is a lunatic thing to do, but somebody did! */ - - if (*ecode == OP_BRAZERO) ecode++; - ecode += GET(ecode, 1); - while (*ecode == OP_ALT) ecode += GET(ecode, 1); - ecode += 1 + LINK_SIZE - PRIV(OP_lengths)[condcode]; - } + if (reptype == REPTYPE_MIN) + { + for (;;) + { + RMATCH(Fecode, RM202); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH); + if (Feptr <= mb->end_subject - Flength && + memcmp(Feptr, Lcharptr, CU2BYTES(Flength)) == 0) Feptr += Flength; + else if (Loclength > 0 && + Feptr <= mb->end_subject - Loclength && + memcmp(Feptr, Foccu, CU2BYTES(Loclength)) == 0) + Feptr += Loclength; + else + { + CHECK_PARTIAL(); + RRETURN(MATCH_NOMATCH); + } + } + /* Control never gets here */ + } + + else /* Maximize */ + { + Lstart_eptr = Feptr; + for (i = Lmin; i < Lmax; i++) + { + if (Feptr <= mb->end_subject - Flength && + memcmp(Feptr, Lcharptr, CU2BYTES(Flength)) == 0) + Feptr += Flength; + else if (Loclength > 0 && + Feptr <= mb->end_subject - Loclength && + memcmp(Feptr, Foccu, CU2BYTES(Loclength)) == 0) + Feptr += Loclength; + else + { + CHECK_PARTIAL(); + break; + } + } - /* PCRE doesn't allow the effect of (*THEN) to escape beyond an - assertion; it is therefore treated as NOMATCH. Any other return is an - error. */ + /* After \C in UTF mode, Lstart_eptr might be in the middle of a + Unicode character. Use <= Lstart_eptr to ensure backtracking doesn't + go too far. */ - else if (rrc != MATCH_NOMATCH && rrc != MATCH_THEN) - { - RRETURN(rrc); /* Need braces because of following else */ + if (reptype != REPTYPE_POS) for(;;) + { + if (Feptr <= Lstart_eptr) break; + RMATCH(Fecode, RM203); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + Feptr--; + BACKCHAR(Feptr); + } + } + break; /* End of repeated wide character handling */ } - break; + + /* Length of UTF character is 1. Put it into the preserved variable and + fall through to the non-UTF code. */ + + Lc = fc; } + else +#endif /* SUPPORT_UNICODE */ - /* Choose branch according to the condition */ + /* When not in UTF mode, load a single-code-unit character. Then proceed as + above. */ - ecode += condition? PRIV(OP_lengths)[condcode] : codelink; + Lc = *Fecode++; - /* We are now at the branch that is to be obeyed. As there is only one, we - can use tail recursion to avoid using another stack frame, except when - there is unlimited repeat of a possibly empty group. In the latter case, a - recursive call to match() is always required, unless the second alternative - doesn't exist, in which case we can just plough on. Note that, for - compatibility with Perl, the | in a conditional group is NOT treated as - creating two alternatives. If a THEN is encountered in the branch, it - propagates out to the enclosing alternative (unless nested in a deeper set - of alternatives, of course). */ + /* Caseless comparison */ - if (condition || ecode[-(1+LINK_SIZE)] == OP_ALT) + if (Fop >= OP_STARI) { - if (op != OP_SCOND) +#if PCRE2_CODE_UNIT_WIDTH == 8 + /* Lc must be < 128 in UTF-8 mode. */ + Loc = mb->fcc[Lc]; +#else /* 16-bit & 32-bit */ +#ifdef SUPPORT_UNICODE + if (utf && Lc > 127) Loc = UCD_OTHERCASE(Lc); + else +#endif /* SUPPORT_UNICODE */ + Loc = TABLE_GET(Lc, mb->fcc, Lc); +#endif /* PCRE2_CODE_UNIT_WIDTH == 8 */ + + for (i = 1; i <= Lmin; i++) { - goto TAIL_RECURSE; + uint32_t cc; /* Faster than PCRE2_UCHAR */ + if (Feptr >= mb->end_subject) + { + SCHECK_PARTIAL(); + RRETURN(MATCH_NOMATCH); + } + cc = UCHAR21TEST(Feptr); + if (Lc != cc && Loc != cc) RRETURN(MATCH_NOMATCH); + Feptr++; } + if (Lmin == Lmax) continue; - mb->match_function_type |= MATCH_CBEGROUP; - RMATCH(eptr, ecode, offset_top, mb, eptrb, RM49); - RRETURN(rrc); + if (reptype == REPTYPE_MIN) + { + for (;;) + { + uint32_t cc; /* Faster than PCRE2_UCHAR */ + RMATCH(Fecode, RM25); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH); + if (Feptr >= mb->end_subject) + { + SCHECK_PARTIAL(); + RRETURN(MATCH_NOMATCH); + } + cc = UCHAR21TEST(Feptr); + if (Lc != cc && Loc != cc) RRETURN(MATCH_NOMATCH); + Feptr++; + } + /* Control never gets here */ + } + + else /* Maximize */ + { + Lstart_eptr = Feptr; + for (i = Lmin; i < Lmax; i++) + { + uint32_t cc; /* Faster than PCRE2_UCHAR */ + if (Feptr >= mb->end_subject) + { + SCHECK_PARTIAL(); + break; + } + cc = UCHAR21TEST(Feptr); + if (Lc != cc && Loc != cc) break; + Feptr++; + } + if (reptype != REPTYPE_POS) for (;;) + { + if (Feptr == Lstart_eptr) break; + RMATCH(Fecode, RM26); + Feptr--; + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + } + } } - /* Condition false & no alternative; continue after the group. */ + /* Caseful comparisons (includes all multi-byte characters) */ else { - } - break; - + for (i = 1; i <= Lmin; i++) + { + if (Feptr >= mb->end_subject) + { + SCHECK_PARTIAL(); + RRETURN(MATCH_NOMATCH); + } + if (Lc != UCHAR21INCTEST(Feptr)) RRETURN(MATCH_NOMATCH); + } - /* Before OP_ACCEPT there may be any number of OP_CLOSE opcodes, - to close any currently open capturing brackets. */ + if (Lmin == Lmax) continue; - case OP_CLOSE: - number = GET2(ecode, 1); /* Must be less than 65536 */ - offset = number << 1; - mb->capture_last = (mb->capture_last & OVFLMASK) | number; - if (offset >= mb->offset_max) mb->capture_last |= OVFLBIT; else - { - mb->ovector[offset] = - mb->ovector[mb->offset_end - number]; - mb->ovector[offset+1] = eptr - mb->start_subject; + if (reptype == REPTYPE_MIN) + { + for (;;) + { + RMATCH(Fecode, RM27); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH); + if (Feptr >= mb->end_subject) + { + SCHECK_PARTIAL(); + RRETURN(MATCH_NOMATCH); + } + if (Lc != UCHAR21INCTEST(Feptr)) RRETURN(MATCH_NOMATCH); + } + /* Control never gets here */ + } + else /* Maximize */ + { + Lstart_eptr = Feptr; + for (i = Lmin; i < Lmax; i++) + { + if (Feptr >= mb->end_subject) + { + SCHECK_PARTIAL(); + break; + } - /* If this group is at or above the current highwater mark, ensure that - any groups between the current high water mark and this group are marked - unset and then update the high water mark. */ + if (Lc != UCHAR21TEST(Feptr)) break; + Feptr++; + } - if (offset >= offset_top) - { - PCRE2_SIZE *iptr = mb->ovector + offset_top; - PCRE2_SIZE *iend = mb->ovector + offset; - while (iptr < iend) *iptr++ = PCRE2_UNSET; - offset_top = offset + 2; + if (reptype != REPTYPE_POS) for (;;) + { + if (Feptr <= Lstart_eptr) break; + RMATCH(Fecode, RM28); + Feptr--; + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + } } } - ecode += 1 + IMM2_SIZE; break; +#undef Loclength +#undef Lstart_eptr +#undef Lcharptr +#undef Lmin +#undef Lmax +#undef Lc +#undef Loc - /* End of the pattern, either real or forced. In an assertion ACCEPT, - update the last used pointer. */ - case OP_ASSERT_ACCEPT: - if (eptr > mb->last_used_ptr) mb->last_used_ptr = eptr; + /* ===================================================================== */ + /* Match a negated single one-byte character repeatedly. This is almost a + repeat of the code for a repeated single character, but I haven't found a + nice way of commoning these up that doesn't require a test of the + positive/negative option for each character match. Maybe that wouldn't add + very much to the time taken, but character matching *is* what this is all + about... */ - case OP_ACCEPT: - case OP_END: +#define Lstart_eptr F->temp_sptr[0] +#define Lmin F->temp_32[0] +#define Lmax F->temp_32[1] +#define Lc F->temp_32[2] +#define Loc F->temp_32[3] - /* If we have matched an empty string, fail if not in an assertion and not - in a recursion if either PCRE2_NOTEMPTY is set, or if PCRE2_NOTEMPTY_ATSTART - is set and we have matched at the start of the subject. In both cases, - backtracking will then try other alternatives, if any. */ + case OP_NOTEXACT: + case OP_NOTEXACTI: + Lmin = Lmax = GET2(Fecode, 1); + Fecode += 1 + IMM2_SIZE; + goto REPEATNOTCHAR; - if (eptr == mstart && op != OP_ASSERT_ACCEPT && - mb->recursive == NULL && - ((mb->moptions & PCRE2_NOTEMPTY) != 0 || - ((mb->moptions & PCRE2_NOTEMPTY_ATSTART) != 0 && - mstart == mb->start_subject + mb->start_offset))) - RRETURN(MATCH_NOMATCH); + case OP_NOTUPTO: + case OP_NOTUPTOI: + Lmin = 0; + Lmax = GET2(Fecode, 1); + reptype = REPTYPE_MAX; + Fecode += 1 + IMM2_SIZE; + goto REPEATNOTCHAR; + + case OP_NOTMINUPTO: + case OP_NOTMINUPTOI: + Lmin = 0; + Lmax = GET2(Fecode, 1); + reptype = REPTYPE_MIN; + Fecode += 1 + IMM2_SIZE; + goto REPEATNOTCHAR; + + case OP_NOTPOSSTAR: + case OP_NOTPOSSTARI: + reptype = REPTYPE_POS; + Lmin = 0; + Lmax = UINT32_MAX; + Fecode++; + goto REPEATNOTCHAR; - /* Otherwise, we have a match. */ + case OP_NOTPOSPLUS: + case OP_NOTPOSPLUSI: + reptype = REPTYPE_POS; + Lmin = 1; + Lmax = UINT32_MAX; + Fecode++; + goto REPEATNOTCHAR; - mb->end_match_ptr = eptr; /* Record where we ended */ - mb->end_offset_top = offset_top; /* and how many extracts were taken */ - mb->start_match_ptr = mstart; /* and the start (\K can modify) */ + case OP_NOTPOSQUERY: + case OP_NOTPOSQUERYI: + reptype = REPTYPE_POS; + Lmin = 0; + Lmax = 1; + Fecode++; + goto REPEATNOTCHAR; - /* For some reason, the macros don't work properly if an expression is - given as the argument to RRETURN when the heap is in use. */ + case OP_NOTPOSUPTO: + case OP_NOTPOSUPTOI: + reptype = REPTYPE_POS; + Lmin = 0; + Lmax = GET2(Fecode, 1); + Fecode += 1 + IMM2_SIZE; + goto REPEATNOTCHAR; - rrc = (op == OP_END)? MATCH_MATCH : MATCH_ACCEPT; - RRETURN(rrc); + case OP_NOTSTAR: + case OP_NOTSTARI: + case OP_NOTMINSTAR: + case OP_NOTMINSTARI: + case OP_NOTPLUS: + case OP_NOTPLUSI: + case OP_NOTMINPLUS: + case OP_NOTMINPLUSI: + case OP_NOTQUERY: + case OP_NOTQUERYI: + case OP_NOTMINQUERY: + case OP_NOTMINQUERYI: + fc = *Fecode++ - ((Fop >= OP_NOTSTARI)? OP_NOTSTARI: OP_NOTSTAR); + Lmin = rep_min[fc]; + Lmax = rep_max[fc]; + reptype = rep_typ[fc]; - /* Assertion brackets. Check the alternative branches in turn - the - matching won't pass the KET for an assertion. If any one branch matches, - the assertion is true. Lookbehind assertions have an OP_REVERSE item at the - start of each branch to move the current point backwards, so the code at - this level is identical to the lookahead case. When the assertion is part - of a condition, we want to return immediately afterwards. The caller of - this incarnation of the match() function will have set MATCH_CONDASSERT in - mb->match_function type, and one of these opcodes will be the first opcode - that is processed. We use a local variable that is preserved over calls to - match() to remember this case. */ + /* Common code for all repeated single-character non-matches. */ - case OP_ASSERT: - case OP_ASSERTBACK: - save_mark = mb->mark; - if ((mb->match_function_type & MATCH_CONDASSERT) != 0) - { - condassert = TRUE; - mb->match_function_type &= ~MATCH_CONDASSERT; - } - else condassert = FALSE; + REPEATNOTCHAR: + GETCHARINCTEST(Lc, Fecode); - /* Loop for each branch */ + /* The code is duplicated for the caseless and caseful cases, for speed, + since matching characters is likely to be quite common. First, ensure the + minimum number of matches are present. If Lmin = Lmax, we are done. + Otherwise, if minimizing, keep trying the rest of the expression and + advancing one matching character if failing, up to the maximum. + Alternatively, if maximizing, find the maximum number of characters and + work backwards. */ - do + if (Fop >= OP_NOTSTARI) /* Caseless */ { - RMATCH(eptr, ecode + 1 + LINK_SIZE, offset_top, mb, NULL, RM4); +#ifdef SUPPORT_UNICODE + if (utf && Lc > 127) + Loc = UCD_OTHERCASE(Lc); + else +#endif /* SUPPORT_UNICODE */ - /* A match means that the assertion is true; break out of the loop - that matches its alternatives. */ + Loc = TABLE_GET(Lc, mb->fcc, Lc); /* Other case from table */ - if (rrc == MATCH_MATCH || rrc == MATCH_ACCEPT) +#ifdef SUPPORT_UNICODE + if (utf) { - mstart = mb->start_match_ptr; /* In case \K reset it */ - break; + uint32_t d; + for (i = 1; i <= Lmin; i++) + { + if (Feptr >= mb->end_subject) + { + SCHECK_PARTIAL(); + RRETURN(MATCH_NOMATCH); + } + GETCHARINC(d, Feptr); + if (Lc == d || Loc == d) RRETURN(MATCH_NOMATCH); + } } + else +#endif /* SUPPORT_UNICODE */ - /* If not matched, restore the previous mark setting. */ - - mb->mark = save_mark; - - /* See comment in the code for capturing groups above about handling - THEN. */ - - if (rrc == MATCH_THEN) + /* Not UTF mode */ { - next_ecode = ecode + GET(ecode,1); - if (mb->start_match_ptr < next_ecode && - (*ecode == OP_ALT || *next_ecode == OP_ALT)) - rrc = MATCH_NOMATCH; + for (i = 1; i <= Lmin; i++) + { + if (Feptr >= mb->end_subject) + { + SCHECK_PARTIAL(); + RRETURN(MATCH_NOMATCH); + } + if (Lc == *Feptr || Loc == *Feptr) RRETURN(MATCH_NOMATCH); + Feptr++; + } } - /* Anything other than NOMATCH causes the entire assertion to fail, - passing back the return code. This includes COMMIT, SKIP, PRUNE and an - uncaptured THEN, which means they take their normal effect. This - consistent approach does not always have exactly the same effect as in - Perl. */ - - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - ecode += GET(ecode, 1); - } - while (*ecode == OP_ALT); /* Continue for next alternative */ + if (Lmin == Lmax) continue; /* Finished for exact count */ - /* If we have tried all the alternative branches, the assertion has - failed. If not, we broke out after a match. */ + if (reptype == REPTYPE_MIN) + { +#ifdef SUPPORT_UNICODE + if (utf) + { + uint32_t d; + for (;;) + { + RMATCH(Fecode, RM204); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH); + if (Feptr >= mb->end_subject) + { + SCHECK_PARTIAL(); + RRETURN(MATCH_NOMATCH); + } + GETCHARINC(d, Feptr); + if (Lc == d || Loc == d) RRETURN(MATCH_NOMATCH); + } + } + else +#endif /*SUPPORT_UNICODE */ - if (*ecode == OP_KET) RRETURN(MATCH_NOMATCH); + /* Not UTF mode */ + { + for (;;) + { + RMATCH(Fecode, RM29); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH); + if (Feptr >= mb->end_subject) + { + SCHECK_PARTIAL(); + RRETURN(MATCH_NOMATCH); + } + if (Lc == *Feptr || Loc == *Feptr) RRETURN(MATCH_NOMATCH); + Feptr++; + } + } + /* Control never gets here */ + } - /* If checking an assertion for a condition, return MATCH_MATCH. */ + /* Maximize case */ - if (condassert) RRETURN(MATCH_MATCH); + else + { + Lstart_eptr = Feptr; - /* Continue from after a successful assertion, updating the offsets high - water mark, since extracts may have been taken during the assertion. */ +#ifdef SUPPORT_UNICODE + if (utf) + { + uint32_t d; + for (i = Lmin; i < Lmax; i++) + { + int len = 1; + if (Feptr >= mb->end_subject) + { + SCHECK_PARTIAL(); + break; + } + GETCHARLEN(d, Feptr, len); + if (Lc == d || Loc == d) break; + Feptr += len; + } - do ecode += GET(ecode,1); while (*ecode == OP_ALT); - ecode += 1 + LINK_SIZE; - offset_top = mb->end_offset_top; - continue; + /* After \C in UTF mode, Lstart_eptr might be in the middle of a + Unicode character. Use <= Lstart_eptr to ensure backtracking doesn't + go too far. */ - /* Negative assertion: all branches must fail to match for the assertion to - succeed. */ + if (reptype != REPTYPE_POS) for(;;) + { + if (Feptr <= Lstart_eptr) break; + RMATCH(Fecode, RM205); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + Feptr--; + BACKCHAR(Feptr); + } + } + else +#endif /* SUPPORT_UNICODE */ - case OP_ASSERT_NOT: - case OP_ASSERTBACK_NOT: - save_mark = mb->mark; - if ((mb->match_function_type & MATCH_CONDASSERT) != 0) - { - condassert = TRUE; - mb->match_function_type &= ~MATCH_CONDASSERT; + /* Not UTF mode */ + { + for (i = Lmin; i < Lmax; i++) + { + if (Feptr >= mb->end_subject) + { + SCHECK_PARTIAL(); + break; + } + if (Lc == *Feptr || Loc == *Feptr) break; + Feptr++; + } + if (reptype != REPTYPE_POS) for (;;) + { + if (Feptr == Lstart_eptr) break; + RMATCH(Fecode, RM30); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + Feptr--; + } + } + } } - else condassert = FALSE; - /* Loop for each alternative branch. */ + /* Caseful comparisons */ - do + else { - RMATCH(eptr, ecode + 1 + LINK_SIZE, offset_top, mb, NULL, RM5); - mb->mark = save_mark; /* Always restore the mark setting */ - - switch(rrc) +#ifdef SUPPORT_UNICODE + if (utf) { - case MATCH_MATCH: /* A successful match means */ - case MATCH_ACCEPT: /* the assertion has failed. */ - RRETURN(MATCH_NOMATCH); - - case MATCH_NOMATCH: /* Carry on with next branch */ - break; - - /* See comment in the code for capturing groups above about handling - THEN. */ - - case MATCH_THEN: - next_ecode = ecode + GET(ecode,1); - if (mb->start_match_ptr < next_ecode && - (*ecode == OP_ALT || *next_ecode == OP_ALT)) + uint32_t d; + for (i = 1; i <= Lmin; i++) { - rrc = MATCH_NOMATCH; - break; + if (Feptr >= mb->end_subject) + { + SCHECK_PARTIAL(); + RRETURN(MATCH_NOMATCH); + } + GETCHARINC(d, Feptr); + if (Lc == d) RRETURN(MATCH_NOMATCH); } - /* Otherwise fall through. */ - - /* COMMIT, SKIP, PRUNE, and an uncaptured THEN cause the whole - assertion to fail to match, without considering any more alternatives. - Failing to match means the assertion is true. This is a consistent - approach, but does not always have the same effect as in Perl. */ - - case MATCH_COMMIT: - case MATCH_SKIP: - case MATCH_SKIP_ARG: - case MATCH_PRUNE: - do ecode += GET(ecode,1); while (*ecode == OP_ALT); - goto NEG_ASSERT_TRUE; /* Break out of alternation loop */ - - /* Anything else is an error */ - - default: - RRETURN(rrc); } - - /* Continue with next branch */ - - ecode += GET(ecode,1); - } - while (*ecode == OP_ALT); - - /* All branches in the assertion failed to match. */ - - NEG_ASSERT_TRUE: - if (condassert) RRETURN(MATCH_MATCH); /* Condition assertion */ - ecode += 1 + LINK_SIZE; /* Continue with current branch */ - continue; - - /* Move the subject pointer back. This occurs only at the start of - each branch of a lookbehind assertion. If we are too close to the start to - move back, this match function fails. When working with UTF-8 we move - back a number of characters, not bytes. */ - - case OP_REVERSE: - i = GET(ecode, 1); -#ifdef SUPPORT_UNICODE - if (utf) - { - while (i-- > 0) + else +#endif + /* Not UTF mode */ { - if (eptr <= mb->start_subject) RRETURN(MATCH_NOMATCH); - eptr--; - BACKCHAR(eptr); + for (i = 1; i <= Lmin; i++) + { + if (Feptr >= mb->end_subject) + { + SCHECK_PARTIAL(); + RRETURN(MATCH_NOMATCH); + } + if (Lc == *Feptr++) RRETURN(MATCH_NOMATCH); + } } - } - else -#endif - - /* No UTF-8 support, or not in UTF-8 mode: count is byte count */ - - { - if (i > eptr - mb->start_subject) RRETURN(MATCH_NOMATCH); - eptr -= i; - } - - /* Save the earliest consulted character, then skip to next op code */ - if (eptr < mb->start_used_ptr) mb->start_used_ptr = eptr; - ecode += 1 + LINK_SIZE; - break; - - /* The callout item calls an external function, if one is provided, passing - details of the match so far. This is mainly for debugging, though the - function is able to force a failure. */ - - case OP_CALLOUT: - case OP_CALLOUT_STR: - { - unsigned int callout_length = (*ecode == OP_CALLOUT) - ? PRIV(OP_lengths)[OP_CALLOUT] : GET(ecode, 1 + 2*LINK_SIZE); + if (Lmin == Lmax) continue; - if (mb->callout != NULL) + if (reptype == REPTYPE_MIN) { - pcre2_callout_block cb; - cb.version = 1; - cb.callout_number = ecode[LINK_SIZE + 1]; - cb.capture_top = (uint32_t)offset_top/2; - cb.capture_last = mb->capture_last & CAPLMASK; - cb.offset_vector = mb->ovector; - cb.mark = mb->nomatch_mark; - cb.subject = mb->start_subject; - cb.subject_length = (PCRE2_SIZE)(mb->end_subject - mb->start_subject); - cb.start_match = (PCRE2_SIZE)(mstart - mb->start_subject); - cb.current_position = (PCRE2_SIZE)(eptr - mb->start_subject); - cb.pattern_position = GET(ecode, 1); - cb.next_item_length = GET(ecode, 1 + LINK_SIZE); - - if (*ecode == OP_CALLOUT) +#ifdef SUPPORT_UNICODE + if (utf) { - cb.callout_number = ecode[1 + 2*LINK_SIZE]; - cb.callout_string_offset = 0; - cb.callout_string = NULL; - cb.callout_string_length = 0; + uint32_t d; + for (;;) + { + RMATCH(Fecode, RM206); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH); + if (Feptr >= mb->end_subject) + { + SCHECK_PARTIAL(); + RRETURN(MATCH_NOMATCH); + } + GETCHARINC(d, Feptr); + if (Lc == d) RRETURN(MATCH_NOMATCH); + } } else +#endif + /* Not UTF mode */ { - cb.callout_number = 0; - cb.callout_string_offset = GET(ecode, 1 + 3*LINK_SIZE); - cb.callout_string = ecode + (1 + 4*LINK_SIZE) + 1; - cb.callout_string_length = - callout_length - (1 + 4*LINK_SIZE) - 2; + for (;;) + { + RMATCH(Fecode, RM31); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH); + if (Feptr >= mb->end_subject) + { + SCHECK_PARTIAL(); + RRETURN(MATCH_NOMATCH); + } + if (Lc == *Feptr++) RRETURN(MATCH_NOMATCH); + } } - - if ((rrc = mb->callout(&cb, mb->callout_data)) > 0) - RRETURN(MATCH_NOMATCH); - if (rrc < 0) RRETURN(rrc); + /* Control never gets here */ } - ecode += callout_length; - } - break; - - /* Recursion either matches the current regex, or some subexpression. The - offset data is the offset to the starting bracket from the start of the - whole pattern. (This is so that it works from duplicated subpatterns.) - - The state of the capturing groups is preserved over recursion, and - re-instated afterwards. We don't know how many are started and not yet - finished (offset_top records the completed total) so we just have to save - all the potential data. There may be up to 65535 such values, which is too - large to put on the stack, but using malloc for small numbers seems - expensive. As a compromise, the stack is used when there are no more than - OP_RECURSE_STACK_SAVE_MAX values to store; otherwise malloc is used. - - There are also other values that have to be saved. We use a chained - sequence of blocks that actually live on the stack. Thanks to Robin Houston - for the original version of this logic. It has, however, been hacked around - a lot, so he is not to blame for the current way it works. */ - case OP_RECURSE: - { - ovecsave_frame *fr; - recursion_info *ri; - uint32_t recno; - - callpat = mb->start_code + GET(ecode, 1); - recno = (callpat == mb->start_code)? 0 : GET2(callpat, 1 + LINK_SIZE); - - /* Check for repeating a pattern recursion without advancing the subject - pointer. This should catch convoluted mutual recursions. (Some simple - cases are caught at compile time.) */ - - for (ri = mb->recursive; ri != NULL; ri = ri->prevrec) - if (recno == ri->group_num && eptr == ri->subject_position) - RRETURN(PCRE2_ERROR_RECURSELOOP); - - /* Add to "recursing stack" */ - - new_recursive.group_num = recno; - new_recursive.saved_capture_last = mb->capture_last; - new_recursive.subject_position = eptr; - new_recursive.prevrec = mb->recursive; - mb->recursive = &new_recursive; - - /* Where to continue from afterwards */ - - ecode += 1 + LINK_SIZE; - - /* When we are using the system stack for match() recursion we can call a - function that uses the system stack for preserving the ovector while - processing the pattern recursion, but only if the ovector is small - enough. */ - -#ifndef HEAP_MATCH_RECURSE - if (mb->offset_end <= OP_RECURSE_STACK_SAVE_MAX) - { - rrc = op_recurse_ovecsave(eptr, callpat, mstart, offset_top, mb, - eptrb, rdepth); - mb->recursive = new_recursive.prevrec; - if (rrc != MATCH_MATCH && rrc != MATCH_ACCEPT) RRETURN(rrc); - - /* Set where we got to in the subject, and reset the start, in case - it was changed by \K. This *is* propagated back out of a recursion, - for Perl compatibility. */ - - eptr = mb->end_match_ptr; - mstart = mb->start_match_ptr; - break; /* End of processing OP_RECURSE */ - } -#endif - /* If the ovector is too big, or if we are using the heap for match() - recursion, we have to use the heap for saving the ovector. Used ovecsave - frames are kept on a chain and re-used. This makes a small improvement in - execution time on Linux. */ + /* Maximize case */ - if (mb->ovecsave_chain != NULL) - { - new_recursive.ovec_save = mb->ovecsave_chain->saved_ovec; - mb->ovecsave_chain = mb->ovecsave_chain->next; - } else { - fr = (ovecsave_frame *)(mb->memctl.malloc(sizeof(ovecsave_frame *) + - mb->offset_end * sizeof(PCRE2_SIZE), mb->memctl.memory_data)); - if (fr == NULL) RRETURN(PCRE2_ERROR_NOMEMORY); - new_recursive.ovec_save = fr->saved_ovec; - } - - memcpy(new_recursive.ovec_save, mb->ovector, - mb->offset_end * sizeof(PCRE2_SIZE)); - - /* Do the recursion. After processing each alternative, restore the - ovector data and the last captured value. This code has the same overall - logic as the code in the op_recurse_ovecsave() function, but is adapted - to use RMATCH/RRETURN and to release the heap block containing the saved - ovector. */ + Lstart_eptr = Feptr; - cbegroup = (*callpat >= OP_SBRA); - do - { - if (cbegroup) mb->match_function_type |= MATCH_CBEGROUP; - RMATCH(eptr, callpat + PRIV(OP_lengths)[*callpat], offset_top, - mb, eptrb, RM6); - memcpy(mb->ovector, new_recursive.ovec_save, - mb->offset_end * sizeof(PCRE2_SIZE)); - mb->capture_last = new_recursive.saved_capture_last; - mb->recursive = new_recursive.prevrec; - - if (rrc == MATCH_MATCH || rrc == MATCH_ACCEPT) +#ifdef SUPPORT_UNICODE + if (utf) { - fr = (ovecsave_frame *) - ((uint8_t *)new_recursive.ovec_save - sizeof(ovecsave_frame *)); - fr->next = mb->ovecsave_chain; - mb->ovecsave_chain = fr; - - /* Set where we got to in the subject, and reset the start, in case - it was changed by \K. This *is* propagated back out of a recursion, - for Perl compatibility. */ - - eptr = mb->end_match_ptr; - mstart = mb->start_match_ptr; - goto RECURSION_MATCHED; /* Exit loop; end processing */ - } + uint32_t d; + for (i = Lmin; i < Lmax; i++) + { + int len = 1; + if (Feptr >= mb->end_subject) + { + SCHECK_PARTIAL(); + break; + } + GETCHARLEN(d, Feptr, len); + if (Lc == d) break; + Feptr += len; + } - /* PCRE does not allow THEN, SKIP, PRUNE or COMMIT to escape beyond a - recursion; they cause a NOMATCH for the entire recursion. These codes - are defined in a range that can be tested for. */ + /* After \C in UTF mode, Lstart_eptr might be in the middle of a + Unicode character. Use <= Lstart_eptr to ensure backtracking doesn't + go too far. */ - if (rrc >= MATCH_BACKTRACK_MIN && rrc <= MATCH_BACKTRACK_MAX) + if (reptype != REPTYPE_POS) for(;;) + { + if (Feptr <= Lstart_eptr) break; + RMATCH(Fecode, RM207); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + Feptr--; + BACKCHAR(Feptr); + } + } + else +#endif + /* Not UTF mode */ { - rrc = MATCH_NOMATCH; - goto RECURSION_RETURN; + for (i = Lmin; i < Lmax; i++) + { + if (Feptr >= mb->end_subject) + { + SCHECK_PARTIAL(); + break; + } + if (Lc == *Feptr) break; + Feptr++; + } + if (reptype != REPTYPE_POS) for (;;) + { + if (Feptr == Lstart_eptr) break; + RMATCH(Fecode, RM32); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + Feptr--; + } } - - /* Any return code other than NOMATCH is an error. */ - - if (rrc != MATCH_NOMATCH) goto RECURSION_RETURN; - mb->recursive = &new_recursive; - callpat += GET(callpat, 1); } - while (*callpat == OP_ALT); - - RECURSION_RETURN: - mb->recursive = new_recursive.prevrec; - fr = (ovecsave_frame *) - ((uint8_t *)new_recursive.ovec_save - sizeof(ovecsave_frame *)); - fr->next = mb->ovecsave_chain; - mb->ovecsave_chain = fr; - RRETURN(rrc); } - - RECURSION_MATCHED: - break; - - /* An alternation is the end of a branch; scan along to find the end of the - bracketed group and go to there. */ - - case OP_ALT: - do ecode += GET(ecode,1); while (*ecode == OP_ALT); - break; - - /* BRAZERO, BRAMINZERO and SKIPZERO occur just before a bracket group, - indicating that it may occur zero times. It may repeat infinitely, or not - at all - i.e. it could be ()* or ()? or even (){0} in the pattern. Brackets - with fixed upper repeat limits are compiled as a number of copies, with the - optional ones preceded by BRAZERO or BRAMINZERO. */ - - case OP_BRAZERO: - next_ecode = ecode + 1; - RMATCH(eptr, next_ecode, offset_top, mb, eptrb, RM10); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - do next_ecode += GET(next_ecode, 1); while (*next_ecode == OP_ALT); - ecode = next_ecode + 1 + LINK_SIZE; - break; - - case OP_BRAMINZERO: - next_ecode = ecode + 1; - do next_ecode += GET(next_ecode, 1); while (*next_ecode == OP_ALT); - RMATCH(eptr, next_ecode + 1+LINK_SIZE, offset_top, mb, eptrb, RM11); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - ecode++; - break; - - case OP_SKIPZERO: - next_ecode = ecode+1; - do next_ecode += GET(next_ecode,1); while (*next_ecode == OP_ALT); - ecode = next_ecode + 1 + LINK_SIZE; break; - /* BRAPOSZERO occurs before a possessive bracket group. Don't do anything - here; just jump to the group, with allow_zero set TRUE. */ - - case OP_BRAPOSZERO: - op = *(++ecode); - allow_zero = TRUE; - if (op == OP_CBRAPOS || op == OP_SCBRAPOS) goto POSSESSIVE_CAPTURE; - goto POSSESSIVE_NON_CAPTURE; +#undef Lstart_eptr +#undef Lmin +#undef Lmax +#undef Lc +#undef Loc - /* End of a group, repeated or non-repeating. */ - case OP_KET: - case OP_KETRMIN: - case OP_KETRMAX: - case OP_KETRPOS: - prev = ecode - GET(ecode, 1); + /* ===================================================================== */ + /* Match a bit-mapped character class, possibly repeatedly. These op codes + are used when all the characters in the class have values in the range + 0-255, and either the matching is caseful, or the characters are in the + range 0-127 when UTF processing is enabled. The only difference between + OP_CLASS and OP_NCLASS occurs when a data character outside the range is + encountered. */ - /* If this was a group that remembered the subject start, in order to break - infinite repeats of empty string matches, retrieve the subject start from - the chain. Otherwise, set it NULL. */ +#define Lmin F->temp_32[0] +#define Lmax F->temp_32[1] +#define Lstart_eptr F->temp_sptr[0] +#define Lbyte_map_address F->temp_sptr[1] +#define Lbyte_map ((unsigned char *)Lbyte_map_address) - if (*prev >= OP_SBRA || *prev == OP_ONCE) + case OP_NCLASS: + case OP_CLASS: { - saved_eptr = eptrb->epb_saved_eptr; /* Value at start of group */ - eptrb = eptrb->epb_prev; /* Backup to previous group */ - } - else saved_eptr = NULL; + Lbyte_map_address = Fecode + 1; /* Save for matching */ + Fecode += 1 + (32 / sizeof(PCRE2_UCHAR)); /* Advance past the item */ - /* If we are at the end of an assertion group or a non-capturing atomic - group, stop matching and return MATCH_MATCH, but record the current high - water mark for use by positive assertions. We also need to record the match - start in case it was changed by \K. */ + /* Look past the end of the item to see if there is repeat information + following. Then obey similar code to character type repeats. */ - if ((*prev >= OP_ASSERT && *prev <= OP_ASSERTBACK_NOT) || - *prev == OP_ONCE_NC) - { - mb->end_match_ptr = eptr; /* For ONCE_NC */ - mb->end_offset_top = offset_top; - mb->start_match_ptr = mstart; - if (eptr > mb->last_used_ptr) mb->last_used_ptr = eptr; - RRETURN(MATCH_MATCH); /* Sets mb->mark */ - } + switch (*Fecode) + { + case OP_CRSTAR: + case OP_CRMINSTAR: + case OP_CRPLUS: + case OP_CRMINPLUS: + case OP_CRQUERY: + case OP_CRMINQUERY: + case OP_CRPOSSTAR: + case OP_CRPOSPLUS: + case OP_CRPOSQUERY: + fc = *Fecode++ - OP_CRSTAR; + Lmin = rep_min[fc]; + Lmax = rep_max[fc]; + reptype = rep_typ[fc]; + break; - /* For capturing groups we have to check the group number back at the start - and if necessary complete handling an extraction by setting the offsets and - bumping the high water mark. Whole-pattern recursion is coded as a recurse - into group 0, so it won't be picked up here. Instead, we catch it when the - OP_END is reached. Other recursion is handled here. We just have to record - the current subject position and start match pointer and give a MATCH - return. */ + case OP_CRRANGE: + case OP_CRMINRANGE: + case OP_CRPOSRANGE: + Lmin = GET2(Fecode, 1); + Lmax = GET2(Fecode, 1 + IMM2_SIZE); + if (Lmax == 0) Lmax = UINT32_MAX; /* Max 0 => infinity */ + reptype = rep_typ[*Fecode - OP_CRSTAR]; + Fecode += 1 + 2 * IMM2_SIZE; + break; - if (*prev == OP_CBRA || *prev == OP_SCBRA || - *prev == OP_CBRAPOS || *prev == OP_SCBRAPOS) - { - number = GET2(prev, 1+LINK_SIZE); - offset = number << 1; + default: /* No repeat follows */ + Lmin = Lmax = 1; + break; + } - /* Handle a recursively called group. */ + /* First, ensure the minimum number of matches are present. */ - if (mb->recursive != NULL && mb->recursive->group_num == number) +#ifdef SUPPORT_UNICODE + if (utf) { - mb->end_match_ptr = eptr; - mb->start_match_ptr = mstart; - if (eptr > mb->last_used_ptr) mb->last_used_ptr = eptr; - RRETURN(MATCH_MATCH); + for (i = 1; i <= Lmin; i++) + { + if (Feptr >= mb->end_subject) + { + SCHECK_PARTIAL(); + RRETURN(MATCH_NOMATCH); + } + GETCHARINC(fc, Feptr); + if (fc > 255) + { + if (Fop == OP_CLASS) RRETURN(MATCH_NOMATCH); + } + else + if ((Lbyte_map[fc/8] & (1 << (fc&7))) == 0) RRETURN(MATCH_NOMATCH); + } } - - /* Deal with capturing */ - - mb->capture_last = (mb->capture_last & OVFLMASK) | number; - if (offset >= mb->offset_max) mb->capture_last |= OVFLBIT; else + else +#endif + /* Not UTF mode */ { - /* If offset is greater than offset_top, it means that we are - "skipping" a capturing group, and that group's offsets must be marked - unset. In earlier versions of PCRE, all the offsets were unset at the - start of matching, but this doesn't work because atomic groups and - assertions can cause a value to be set that should later be unset. - Example: matching /(?>(a))b|(a)c/ against "ac". This sets group 1 as - part of the atomic group, but this is not on the final matching path, - so must be unset when 2 is set. (If there is no group 2, there is no - problem, because offset_top will then be 2, indicating no capture.) */ - - if (offset > offset_top) + for (i = 1; i <= Lmin; i++) { - PCRE2_SIZE *iptr = mb->ovector + offset_top; - PCRE2_SIZE *iend = mb->ovector + offset; - while (iptr < iend) *iptr++ = PCRE2_UNSET; + if (Feptr >= mb->end_subject) + { + SCHECK_PARTIAL(); + RRETURN(MATCH_NOMATCH); + } + fc = *Feptr++; +#if PCRE2_CODE_UNIT_WIDTH != 8 + if (fc > 255) + { + if (Fop == OP_CLASS) RRETURN(MATCH_NOMATCH); + } + else +#endif + if ((Lbyte_map[fc/8] & (1 << (fc&7))) == 0) RRETURN(MATCH_NOMATCH); } - - /* Now make the extraction */ - - mb->ovector[offset] = mb->ovector[mb->offset_end - number]; - mb->ovector[offset+1] = eptr - mb->start_subject; - if (offset_top <= offset) offset_top = offset + 2; } - } - - /* OP_KETRPOS is a possessive repeating ket. Remember the current position, - and return the MATCH_KETRPOS. This makes it possible to do the repeats one - at a time from the outer level, thus saving stack. This must precede the - empty string test - in this case that test is done at the outer level. */ - - if (*ecode == OP_KETRPOS) - { - mb->start_match_ptr = mstart; /* In case \K reset it */ - mb->end_match_ptr = eptr; - mb->end_offset_top = offset_top; - if (eptr > mb->last_used_ptr) mb->last_used_ptr = eptr; - RRETURN(MATCH_KETRPOS); - } - /* For an ordinary non-repeating ket, just continue at this level. This - also happens for a repeating ket if no characters were matched in the - group. This is the forcible breaking of infinite loops as implemented in - Perl 5.005. For a non-repeating atomic group that includes captures, - establish a backup point by processing the rest of the pattern at a lower - level. If this results in a NOMATCH return, pass MATCH_ONCE back to the - original OP_ONCE level, thereby bypassing intermediate backup points, but - resetting any captures that happened along the way. */ + /* If Lmax == Lmin we are done. Continue with main loop. */ - if (*ecode == OP_KET || eptr == saved_eptr) - { - if (*prev == OP_ONCE) - { - RMATCH(eptr, ecode + 1 + LINK_SIZE, offset_top, mb, eptrb, RM12); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - mb->once_target = prev; /* Level at which to change to MATCH_NOMATCH */ - RRETURN(MATCH_ONCE); - } - ecode += 1 + LINK_SIZE; /* Carry on at this level */ - break; - } + if (Lmin == Lmax) continue; - /* The normal repeating kets try the rest of the pattern or restart from - the preceding bracket, in the appropriate order. In the second case, we can - use tail recursion to avoid using another stack frame, unless we have an - an atomic group or an unlimited repeat of a group that can match an empty - string. */ + /* If minimizing, keep testing the rest of the expression and advancing + the pointer while it matches the class. */ - if (*ecode == OP_KETRMIN) - { - RMATCH(eptr, ecode + 1 + LINK_SIZE, offset_top, mb, eptrb, RM7); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - if (*prev == OP_ONCE) - { - RMATCH(eptr, prev, offset_top, mb, eptrb, RM8); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - mb->once_target = prev; /* Level at which to change to MATCH_NOMATCH */ - RRETURN(MATCH_ONCE); - } - if (*prev >= OP_SBRA) /* Could match an empty string */ - { - RMATCH(eptr, prev, offset_top, mb, eptrb, RM50); - RRETURN(rrc); - } - ecode = prev; - goto TAIL_RECURSE; - } - else /* OP_KETRMAX */ - { - RMATCH(eptr, prev, offset_top, mb, eptrb, RM13); - if (rrc == MATCH_ONCE && mb->once_target == prev) rrc = MATCH_NOMATCH; - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - if (*prev == OP_ONCE) + if (reptype == REPTYPE_MIN) { - RMATCH(eptr, ecode + 1 + LINK_SIZE, offset_top, mb, eptrb, RM9); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - mb->once_target = prev; - RRETURN(MATCH_ONCE); - } - ecode += 1 + LINK_SIZE; - goto TAIL_RECURSE; - } - /* Control never gets here */ - - /* Not multiline mode: start of subject assertion, unless notbol. */ - - case OP_CIRC: - if ((mb->moptions & PCRE2_NOTBOL) != 0 && eptr == mb->start_subject) - RRETURN(MATCH_NOMATCH); - - /* Start of subject assertion */ - - case OP_SOD: - if (eptr != mb->start_subject) RRETURN(MATCH_NOMATCH); - ecode++; - break; - - /* Multiline mode: start of subject unless notbol, or after any newline - except for one at the very end, unless PCRE2_ALT_CIRCUMFLEX is set. */ +#ifdef SUPPORT_UNICODE + if (utf) + { + for (;;) + { + RMATCH(Fecode, RM200); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH); + if (Feptr >= mb->end_subject) + { + SCHECK_PARTIAL(); + RRETURN(MATCH_NOMATCH); + } + GETCHARINC(fc, Feptr); + if (fc > 255) + { + if (Fop == OP_CLASS) RRETURN(MATCH_NOMATCH); + } + else + if ((Lbyte_map[fc/8] & (1 << (fc&7))) == 0) RRETURN(MATCH_NOMATCH); + } + } + else +#endif + /* Not UTF mode */ + { + for (;;) + { + RMATCH(Fecode, RM23); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH); + if (Feptr >= mb->end_subject) + { + SCHECK_PARTIAL(); + RRETURN(MATCH_NOMATCH); + } + fc = *Feptr++; +#if PCRE2_CODE_UNIT_WIDTH != 8 + if (fc > 255) + { + if (Fop == OP_CLASS) RRETURN(MATCH_NOMATCH); + } + else +#endif + if ((Lbyte_map[fc/8] & (1 << (fc&7))) == 0) RRETURN(MATCH_NOMATCH); + } + } + /* Control never gets here */ + } - case OP_CIRCM: - if ((mb->moptions & PCRE2_NOTBOL) != 0 && eptr == mb->start_subject) - RRETURN(MATCH_NOMATCH); - if (eptr != mb->start_subject && - ((eptr == mb->end_subject && - (mb->poptions & PCRE2_ALT_CIRCUMFLEX) == 0) || - !WAS_NEWLINE(eptr))) - RRETURN(MATCH_NOMATCH); - ecode++; - break; + /* If maximizing, find the longest possible run, then work backwards. */ - /* Start of match assertion */ + else + { + Lstart_eptr = Feptr; - case OP_SOM: - if (eptr != mb->start_subject + mb->start_offset) RRETURN(MATCH_NOMATCH); - ecode++; - break; +#ifdef SUPPORT_UNICODE + if (utf) + { + for (i = Lmin; i < Lmax; i++) + { + int len = 1; + if (Feptr >= mb->end_subject) + { + SCHECK_PARTIAL(); + break; + } + GETCHARLEN(fc, Feptr, len); + if (fc > 255) + { + if (Fop == OP_CLASS) break; + } + else + if ((Lbyte_map[fc/8] & (1 << (fc&7))) == 0) break; + Feptr += len; + } - /* Reset the start of match point */ + if (reptype == REPTYPE_POS) continue; /* No backtracking */ - case OP_SET_SOM: - mstart = eptr; - ecode++; - break; + for (;;) + { + RMATCH(Fecode, RM201); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + if (Feptr-- == Lstart_eptr) break; /* Tried at original position */ + BACKCHAR(Feptr); + } + } + else +#endif + /* Not UTF mode */ + { + for (i = Lmin; i < Lmax; i++) + { + if (Feptr >= mb->end_subject) + { + SCHECK_PARTIAL(); + break; + } + fc = *Feptr; +#if PCRE2_CODE_UNIT_WIDTH != 8 + if (fc > 255) + { + if (Fop == OP_CLASS) break; + } + else +#endif + if ((Lbyte_map[fc/8] & (1 << (fc&7))) == 0) break; + Feptr++; + } - /* Multiline mode: assert before any newline, or before end of subject - unless noteol is set. */ + if (reptype == REPTYPE_POS) continue; /* No backtracking */ - case OP_DOLLM: - if (eptr < mb->end_subject) - { - if (!IS_NEWLINE(eptr)) - { - if (mb->partial != 0 && - eptr + 1 >= mb->end_subject && - NLBLOCK->nltype == NLTYPE_FIXED && - NLBLOCK->nllen == 2 && - UCHAR21TEST(eptr) == NLBLOCK->nl[0]) - { - mb->hitend = TRUE; - if (mb->partial > 1) RRETURN(PCRE2_ERROR_PARTIAL); + while (Feptr >= Lstart_eptr) + { + RMATCH(Fecode, RM24); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + Feptr--; + } } + RRETURN(MATCH_NOMATCH); } } - else - { - if ((mb->moptions & PCRE2_NOTEOL) != 0) RRETURN(MATCH_NOMATCH); - SCHECK_PARTIAL(); - } - ecode++; - break; - - /* Not multiline mode: assert before a terminating newline or before end of - subject unless noteol is set. */ - - case OP_DOLL: - if ((mb->moptions & PCRE2_NOTEOL) != 0) RRETURN(MATCH_NOMATCH); - if ((mb->poptions & PCRE2_DOLLAR_ENDONLY) == 0) goto ASSERT_NL_OR_EOS; + /* Control never gets here */ - /* ... else fall through for endonly */ +#undef Lbyte_map_address +#undef Lbyte_map +#undef Lstart_eptr +#undef Lmin +#undef Lmax - /* End of subject assertion (\z) */ - case OP_EOD: - if (eptr < mb->end_subject) RRETURN(MATCH_NOMATCH); - SCHECK_PARTIAL(); - ecode++; - break; + /* ===================================================================== */ + /* Match an extended character class. In the 8-bit library, this opcode is + encountered only when UTF-8 mode mode is supported. In the 16-bit and + 32-bit libraries, codepoints greater than 255 may be encountered even when + UTF is not supported. */ - /* End of subject or ending \n assertion (\Z) */ +#define Lstart_eptr F->temp_sptr[0] +#define Lxclass_data F->temp_sptr[1] +#define Lmin F->temp_32[0] +#define Lmax F->temp_32[1] - case OP_EODN: - ASSERT_NL_OR_EOS: - if (eptr < mb->end_subject && - (!IS_NEWLINE(eptr) || eptr != mb->end_subject - mb->nllen)) +#ifdef SUPPORT_WIDE_CHARS + case OP_XCLASS: { - if (mb->partial != 0 && - eptr + 1 >= mb->end_subject && - NLBLOCK->nltype == NLTYPE_FIXED && - NLBLOCK->nllen == 2 && - UCHAR21TEST(eptr) == NLBLOCK->nl[0]) - { - mb->hitend = TRUE; - if (mb->partial > 1) RRETURN(PCRE2_ERROR_PARTIAL); - } - RRETURN(MATCH_NOMATCH); - } - - /* Either at end of string or \n before end. */ + Lxclass_data = Fecode + 1 + LINK_SIZE; /* Save for matching */ + Fecode += GET(Fecode, 1); /* Advance past the item */ - SCHECK_PARTIAL(); - ecode++; - break; + switch (*Fecode) + { + case OP_CRSTAR: + case OP_CRMINSTAR: + case OP_CRPLUS: + case OP_CRMINPLUS: + case OP_CRQUERY: + case OP_CRMINQUERY: + case OP_CRPOSSTAR: + case OP_CRPOSPLUS: + case OP_CRPOSQUERY: + fc = *Fecode++ - OP_CRSTAR; + Lmin = rep_min[fc]; + Lmax = rep_max[fc]; + reptype = rep_typ[fc]; + break; - /* Word boundary assertions */ + case OP_CRRANGE: + case OP_CRMINRANGE: + case OP_CRPOSRANGE: + Lmin = GET2(Fecode, 1); + Lmax = GET2(Fecode, 1 + IMM2_SIZE); + if (Lmax == 0) Lmax = UINT32_MAX; /* Max 0 => infinity */ + reptype = rep_typ[*Fecode - OP_CRSTAR]; + Fecode += 1 + 2 * IMM2_SIZE; + break; - case OP_NOT_WORD_BOUNDARY: - case OP_WORD_BOUNDARY: - { + default: /* No repeat follows */ + Lmin = Lmax = 1; + break; + } - /* Find out if the previous and current characters are "word" characters. - It takes a bit more work in UTF-8 mode. Characters > 255 are assumed to - be "non-word" characters. Remember the earliest consulted character for - partial matching. */ + /* First, ensure the minimum number of matches are present. */ -#ifdef SUPPORT_UNICODE - if (utf) + for (i = 1; i <= Lmin; i++) { - /* Get status of previous character */ - - if (eptr == mb->start_subject) prev_is_word = FALSE; else + if (Feptr >= mb->end_subject) { - PCRE2_SPTR lastptr = eptr - 1; - BACKCHAR(lastptr); - if (lastptr < mb->start_used_ptr) mb->start_used_ptr = lastptr; - GETCHAR(c, lastptr); - if ((mb->poptions & PCRE2_UCP) != 0) - { - if (c == '_') prev_is_word = TRUE; else - { - int cat = UCD_CATEGORY(c); - prev_is_word = (cat == ucp_L || cat == ucp_N); - } - } - else - prev_is_word = c < 256 && (mb->ctypes[c] & ctype_word) != 0; + SCHECK_PARTIAL(); + RRETURN(MATCH_NOMATCH); } + GETCHARINCTEST(fc, Feptr); + if (!PRIV(xclass)(fc, Lxclass_data, utf)) RRETURN(MATCH_NOMATCH); + } - /* Get status of next character */ + /* If Lmax == Lmin we can just continue with the main loop. */ - if (eptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - cur_is_word = FALSE; - } - else + if (Lmin == Lmax) continue; + + /* If minimizing, keep testing the rest of the expression and advancing + the pointer while it matches the class. */ + + if (reptype == REPTYPE_MIN) + { + for (;;) { - PCRE2_SPTR nextptr = eptr + 1; - FORWARDCHARTEST(nextptr, mb->end_subject); - if (nextptr > mb->last_used_ptr) mb->last_used_ptr = nextptr; - GETCHAR(c, eptr); - if ((mb->poptions & PCRE2_UCP) != 0) + RMATCH(Fecode, RM100); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH); + if (Feptr >= mb->end_subject) { - if (c == '_') cur_is_word = TRUE; else - { - int cat = UCD_CATEGORY(c); - cur_is_word = (cat == ucp_L || cat == ucp_N); - } + SCHECK_PARTIAL(); + RRETURN(MATCH_NOMATCH); } - else - cur_is_word = c < 256 && (mb->ctypes[c] & ctype_word) != 0; + GETCHARINCTEST(fc, Feptr); + if (!PRIV(xclass)(fc, Lxclass_data, utf)) RRETURN(MATCH_NOMATCH); } + /* Control never gets here */ } - else -#endif /* SUPPORT UTF */ - /* Not in UTF-8 mode, but we may still have PCRE2_UCP set, and for - consistency with the behaviour of \w we do use it in this case. */ + /* If maximizing, find the longest possible run, then work backwards. */ + else { - /* Get status of previous character */ - - if (eptr == mb->start_subject) prev_is_word = FALSE; else + Lstart_eptr = Feptr; + for (i = Lmin; i < Lmax; i++) { - if (eptr <= mb->start_used_ptr) mb->start_used_ptr = eptr - 1; -#ifdef SUPPORT_UNICODE - if ((mb->poptions & PCRE2_UCP) != 0) + int len = 1; + if (Feptr >= mb->end_subject) { - c = eptr[-1]; - if (c == '_') prev_is_word = TRUE; else - { - int cat = UCD_CATEGORY(c); - prev_is_word = (cat == ucp_L || cat == ucp_N); - } + SCHECK_PARTIAL(); + break; } - else +#ifdef SUPPORT_UNICODE + GETCHARLENTEST(fc, Feptr, len); +#else + fc = *Feptr; #endif - prev_is_word = MAX_255(eptr[-1]) - && ((mb->ctypes[eptr[-1]] & ctype_word) != 0); + if (!PRIV(xclass)(fc, Lxclass_data, utf)) break; + Feptr += len; } - /* Get status of next character */ + if (reptype == REPTYPE_POS) continue; /* No backtracking */ - if (eptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - cur_is_word = FALSE; - } - else + for(;;) { - if (eptr >= mb->last_used_ptr) mb->last_used_ptr = eptr + 1; + RMATCH(Fecode, RM101); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + if (Feptr-- == Lstart_eptr) break; /* Tried at original position */ #ifdef SUPPORT_UNICODE - if ((mb->poptions & PCRE2_UCP) != 0) - { - c = *eptr; - if (c == '_') cur_is_word = TRUE; else - { - int cat = UCD_CATEGORY(c); - cur_is_word = (cat == ucp_L || cat == ucp_N); - } - } - else + if (utf) BACKCHAR(Feptr); #endif - cur_is_word = MAX_255(*eptr) - && ((mb->ctypes[*eptr] & ctype_word) != 0); } - } - - /* Now see if the situation is what we want */ - - if ((*ecode++ == OP_WORD_BOUNDARY)? - cur_is_word == prev_is_word : cur_is_word != prev_is_word) RRETURN(MATCH_NOMATCH); - } - break; - - /* Match any single character type except newline; have to take care with - CRLF newlines and partial matching. */ + } - case OP_ANY: - if (IS_NEWLINE(eptr)) RRETURN(MATCH_NOMATCH); - if (mb->partial != 0 && - eptr == mb->end_subject - 1 && - NLBLOCK->nltype == NLTYPE_FIXED && - NLBLOCK->nllen == 2 && - UCHAR21TEST(eptr) == NLBLOCK->nl[0]) - { - mb->hitend = TRUE; - if (mb->partial > 1) RRETURN(PCRE2_ERROR_PARTIAL); + /* Control never gets here */ } +#endif /* SUPPORT_WIDE_CHARS: end of XCLASS */ - /* Fall through */ - - /* Match any single character whatsoever. */ - - case OP_ALLANY: - if (eptr >= mb->end_subject) /* DO NOT merge the eptr++ here; it must */ - { /* not be updated before SCHECK_PARTIAL. */ - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - eptr++; -#ifdef SUPPORT_UNICODE - if (utf) ACROSSCHAR(eptr < mb->end_subject, *eptr, eptr++); -#endif - ecode++; - break; +#undef Lstart_eptr +#undef Lxclass_data +#undef Lmin +#undef Lmax - /* Match a single code unit, even in UTF-8 mode. This opcode really does - match any code unit, even newline. (It really should be called ANYCODEUNIT, - of course - the byte name is from pre-16 bit days.) */ - case OP_ANYBYTE: - if (eptr >= mb->end_subject) /* DO NOT merge the eptr++ here; it must */ - { /* not be updated before SCHECK_PARTIAL. */ - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - eptr++; - ecode++; - break; + /* ===================================================================== */ + /* Match various character types when PCRE2_UCP is not set. These opcodes + are not generated when PCRE2_UCP is set - instead appropriate property + tests are compiled. */ case OP_NOT_DIGIT: - if (eptr >= mb->end_subject) + if (Feptr >= mb->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } - GETCHARINCTEST(c, eptr); - if ( -#ifdef SUPPORT_WIDE_CHARS - c < 256 && -#endif - (mb->ctypes[c] & ctype_digit) != 0 - ) + GETCHARINCTEST(fc, Feptr); + if (CHMAX_255(fc) && (mb->ctypes[fc] & ctype_digit) != 0) RRETURN(MATCH_NOMATCH); - ecode++; + Fecode++; break; case OP_DIGIT: - if (eptr >= mb->end_subject) + if (Feptr >= mb->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } - GETCHARINCTEST(c, eptr); - if ( -#ifdef SUPPORT_WIDE_CHARS - c > 255 || -#endif - (mb->ctypes[c] & ctype_digit) == 0 - ) + GETCHARINCTEST(fc, Feptr); + if (!CHMAX_255(fc) || (mb->ctypes[fc] & ctype_digit) == 0) RRETURN(MATCH_NOMATCH); - ecode++; + Fecode++; break; case OP_NOT_WHITESPACE: - if (eptr >= mb->end_subject) + if (Feptr >= mb->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } - GETCHARINCTEST(c, eptr); - if ( -#ifdef SUPPORT_WIDE_CHARS - c < 256 && -#endif - (mb->ctypes[c] & ctype_space) != 0 - ) + GETCHARINCTEST(fc, Feptr); + if (CHMAX_255(fc) && (mb->ctypes[fc] & ctype_space) != 0) RRETURN(MATCH_NOMATCH); - ecode++; + Fecode++; break; case OP_WHITESPACE: - if (eptr >= mb->end_subject) + if (Feptr >= mb->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } - GETCHARINCTEST(c, eptr); - if ( -#ifdef SUPPORT_WIDE_CHARS - c > 255 || -#endif - (mb->ctypes[c] & ctype_space) == 0 - ) + GETCHARINCTEST(fc, Feptr); + if (!CHMAX_255(fc) || (mb->ctypes[fc] & ctype_space) == 0) RRETURN(MATCH_NOMATCH); - ecode++; + Fecode++; break; case OP_NOT_WORDCHAR: - if (eptr >= mb->end_subject) + if (Feptr >= mb->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } - GETCHARINCTEST(c, eptr); - if ( -#ifdef SUPPORT_WIDE_CHARS - c < 256 && -#endif - (mb->ctypes[c] & ctype_word) != 0 - ) + GETCHARINCTEST(fc, Feptr); + if (CHMAX_255(fc) && (mb->ctypes[fc] & ctype_word) != 0) RRETURN(MATCH_NOMATCH); - ecode++; + Fecode++; break; case OP_WORDCHAR: - if (eptr >= mb->end_subject) + if (Feptr >= mb->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } - GETCHARINCTEST(c, eptr); - if ( -#ifdef SUPPORT_WIDE_CHARS - c > 255 || -#endif - (mb->ctypes[c] & ctype_word) == 0 - ) + GETCHARINCTEST(fc, Feptr); + if (!CHMAX_255(fc) || (mb->ctypes[fc] & ctype_word) == 0) RRETURN(MATCH_NOMATCH); - ecode++; + Fecode++; break; case OP_ANYNL: - if (eptr >= mb->end_subject) + if (Feptr >= mb->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } - GETCHARINCTEST(c, eptr); - switch(c) + GETCHARINCTEST(fc, Feptr); + switch(fc) { default: RRETURN(MATCH_NOMATCH); case CHAR_CR: - if (eptr >= mb->end_subject) + if (Feptr >= mb->end_subject) { SCHECK_PARTIAL(); } - else if (UCHAR21TEST(eptr) == CHAR_LF) eptr++; + else if (UCHAR21TEST(Feptr) == CHAR_LF) Feptr++; break; case CHAR_LF: @@ -2554,110 +2257,113 @@ for (;;) if (mb->bsr_convention == PCRE2_BSR_ANYCRLF) RRETURN(MATCH_NOMATCH); break; } - ecode++; + Fecode++; break; case OP_NOT_HSPACE: - if (eptr >= mb->end_subject) + if (Feptr >= mb->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } - GETCHARINCTEST(c, eptr); - switch(c) + GETCHARINCTEST(fc, Feptr); + switch(fc) { HSPACE_CASES: RRETURN(MATCH_NOMATCH); /* Byte and multibyte cases */ default: break; } - ecode++; + Fecode++; break; case OP_HSPACE: - if (eptr >= mb->end_subject) + if (Feptr >= mb->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } - GETCHARINCTEST(c, eptr); - switch(c) + GETCHARINCTEST(fc, Feptr); + switch(fc) { HSPACE_CASES: break; /* Byte and multibyte cases */ default: RRETURN(MATCH_NOMATCH); } - ecode++; + Fecode++; break; case OP_NOT_VSPACE: - if (eptr >= mb->end_subject) + if (Feptr >= mb->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } - GETCHARINCTEST(c, eptr); - switch(c) + GETCHARINCTEST(fc, Feptr); + switch(fc) { VSPACE_CASES: RRETURN(MATCH_NOMATCH); default: break; } - ecode++; + Fecode++; break; case OP_VSPACE: - if (eptr >= mb->end_subject) + if (Feptr >= mb->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } - GETCHARINCTEST(c, eptr); - switch(c) + GETCHARINCTEST(fc, Feptr); + switch(fc) { VSPACE_CASES: break; default: RRETURN(MATCH_NOMATCH); } - ecode++; + Fecode++; break; + #ifdef SUPPORT_UNICODE + + /* ===================================================================== */ /* Check the next character by Unicode property. We will get here only if the support is in the binary; otherwise a compile-time error occurs. */ case OP_PROP: case OP_NOTPROP: - if (eptr >= mb->end_subject) + if (Feptr >= mb->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } - GETCHARINCTEST(c, eptr); + GETCHARINCTEST(fc, Feptr); { const uint32_t *cp; - const ucd_record *prop = GET_UCD(c); + const ucd_record *prop = GET_UCD(fc); - switch(ecode[1]) + switch(Fecode[1]) { case PT_ANY: - if (op == OP_NOTPROP) RRETURN(MATCH_NOMATCH); + if (Fop == OP_NOTPROP) RRETURN(MATCH_NOMATCH); break; case PT_LAMP: if ((prop->chartype == ucp_Lu || prop->chartype == ucp_Ll || - prop->chartype == ucp_Lt) == (op == OP_NOTPROP)) + prop->chartype == ucp_Lt) == (Fop == OP_NOTPROP)) RRETURN(MATCH_NOMATCH); break; case PT_GC: - if ((ecode[2] != PRIV(ucp_gentype)[prop->chartype]) == (op == OP_PROP)) + if ((Fecode[2] != PRIV(ucp_gentype)[prop->chartype]) == (Fop == OP_PROP)) RRETURN(MATCH_NOMATCH); break; case PT_PC: - if ((ecode[2] != prop->chartype) == (op == OP_PROP)) + if ((Fecode[2] != prop->chartype) == (Fop == OP_PROP)) RRETURN(MATCH_NOMATCH); break; case PT_SC: - if ((ecode[2] != prop->script) == (op == OP_PROP)) + if ((Fecode[2] != prop->script) == (Fop == OP_PROP)) RRETURN(MATCH_NOMATCH); break; @@ -2665,7 +2371,7 @@ for (;;) case PT_ALNUM: if ((PRIV(ucp_gentype)[prop->chartype] == ucp_L || - PRIV(ucp_gentype)[prop->chartype] == ucp_N) == (op == OP_NOTPROP)) + PRIV(ucp_gentype)[prop->chartype] == ucp_N) == (Fop == OP_NOTPROP)) RRETURN(MATCH_NOMATCH); break; @@ -2675,16 +2381,16 @@ for (;;) case PT_SPACE: /* Perl space */ case PT_PXSPACE: /* POSIX space */ - switch(c) + switch(fc) { HSPACE_CASES: VSPACE_CASES: - if (op == OP_NOTPROP) RRETURN(MATCH_NOMATCH); + if (Fop == OP_NOTPROP) RRETURN(MATCH_NOMATCH); break; default: if ((PRIV(ucp_gentype)[prop->chartype] == ucp_Z) == - (op == OP_NOTPROP)) RRETURN(MATCH_NOMATCH); + (Fop == OP_NOTPROP)) RRETURN(MATCH_NOMATCH); break; } break; @@ -2692,43 +2398,45 @@ for (;;) case PT_WORD: if ((PRIV(ucp_gentype)[prop->chartype] == ucp_L || PRIV(ucp_gentype)[prop->chartype] == ucp_N || - c == CHAR_UNDERSCORE) == (op == OP_NOTPROP)) + fc == CHAR_UNDERSCORE) == (Fop == OP_NOTPROP)) RRETURN(MATCH_NOMATCH); break; case PT_CLIST: - cp = PRIV(ucd_caseless_sets) + ecode[2]; + cp = PRIV(ucd_caseless_sets) + Fecode[2]; for (;;) { - if (c < *cp) - { if (op == OP_PROP) { RRETURN(MATCH_NOMATCH); } else break; } - if (c == *cp++) - { if (op == OP_PROP) break; else { RRETURN(MATCH_NOMATCH); } } + if (fc < *cp) + { if (Fop == OP_PROP) { RRETURN(MATCH_NOMATCH); } else break; } + if (fc == *cp++) + { if (Fop == OP_PROP) break; else { RRETURN(MATCH_NOMATCH); } } } break; case PT_UCNC: - if ((c == CHAR_DOLLAR_SIGN || c == CHAR_COMMERCIAL_AT || - c == CHAR_GRAVE_ACCENT || (c >= 0xa0 && c <= 0xd7ff) || - c >= 0xe000) == (op == OP_NOTPROP)) + if ((fc == CHAR_DOLLAR_SIGN || fc == CHAR_COMMERCIAL_AT || + fc == CHAR_GRAVE_ACCENT || (fc >= 0xa0 && fc <= 0xd7ff) || + fc >= 0xe000) == (Fop == OP_NOTPROP)) RRETURN(MATCH_NOMATCH); break; /* This should never occur */ default: - RRETURN(PCRE2_ERROR_INTERNAL); + return PCRE2_ERROR_INTERNAL; } - ecode += 3; + Fecode += 3; } break; + + /* ===================================================================== */ /* Match an extended Unicode sequence. We will get here only if the support is in the binary; otherwise a compile-time error occurs. */ case OP_EXTUNI: - if (eptr >= mb->end_subject) + if (Feptr >= mb->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); @@ -2736,1606 +2444,1032 @@ for (;;) else { int lgb, rgb; - GETCHARINCTEST(c, eptr); - lgb = UCD_GRAPHBREAK(c); - while (eptr < mb->end_subject) + GETCHARINCTEST(fc, Feptr); + lgb = UCD_GRAPHBREAK(fc); + while (Feptr < mb->end_subject) { int len = 1; - if (!utf) c = *eptr; else { GETCHARLEN(c, eptr, len); } - rgb = UCD_GRAPHBREAK(c); + if (!utf) fc = *Feptr; else { GETCHARLEN(fc, Feptr, len); } + rgb = UCD_GRAPHBREAK(fc); if ((PRIV(ucp_gbtable)[lgb] & (1 << rgb)) == 0) break; - lgb = rgb; - eptr += len; - } - } - CHECK_PARTIAL(); - ecode++; - break; -#endif /* SUPPORT_UNICODE */ + /* Not breaking between Regional Indicators is allowed only if there + are an even number of preceding RIs. */ - /* Match a back reference, possibly repeatedly. Look past the end of the - item to see if there is repeat information following. + if (lgb == ucp_gbRegionalIndicator && rgb == ucp_gbRegionalIndicator) + { + int ricount = 0; + PCRE2_SPTR bptr = Feptr - 1; +#ifdef SUPPORT_UNICODE + if (utf) BACKCHAR(bptr); +#endif + /* bptr is pointing to the left-hand character */ - The OP_REF and OP_REFI opcodes are used for a reference to a numbered group - or to a non-duplicated named group. For a duplicated named group, OP_DNREF - and OP_DNREFI are used. In this case we must scan the list of groups to - which the name refers, and use the first one that is set. */ + while (bptr > mb->start_subject) + { + bptr--; +#ifdef SUPPORT_UNICODE + if (utf) + { + BACKCHAR(bptr); + GETCHAR(fc, bptr); + } + else +#endif + fc = *bptr; + if (UCD_GRAPHBREAK(fc) != ucp_gbRegionalIndicator) break; + ricount++; + } + if ((ricount & 1) != 0) break; /* Grapheme break required */ + } - case OP_DNREF: - case OP_DNREFI: - caseless = op == OP_DNREFI; - { - int count = GET2(ecode, 1+IMM2_SIZE); - PCRE2_SPTR slot = mb->name_table + GET2(ecode, 1) * mb->name_entry_size; - ecode += 1 + 2*IMM2_SIZE; + /* If Extend follows E_Base[_GAZ] do not update lgb; this allows + any number of Extend before a following E_Modifier. */ - /* Initializing 'offset' avoids a compiler warning in the REF_REPEAT - code. */ + if (rgb != ucp_gbExtend || + (lgb != ucp_gbE_Base && lgb != ucp_gbE_Base_GAZ)) + lgb = rgb; - offset = 0; - while (count-- > 0) - { - offset = GET2(slot, 0) << 1; - if (offset < offset_top && mb->ovector[offset] != PCRE2_UNSET) break; - slot += mb->name_entry_size; + Feptr += len; } } - goto REF_REPEAT; + CHECK_PARTIAL(); + Fecode++; + break; - case OP_REF: - case OP_REFI: - caseless = op == OP_REFI; - offset = GET2(ecode, 1) << 1; /* Doubled ref number */ - ecode += 1 + IMM2_SIZE; +#endif /* SUPPORT_UNICODE */ - /* Set up for repetition, or handle the non-repeated case */ - REF_REPEAT: - switch (*ecode) - { - case OP_CRSTAR: - case OP_CRMINSTAR: - case OP_CRPLUS: - case OP_CRMINPLUS: - case OP_CRQUERY: - case OP_CRMINQUERY: - c = *ecode++ - OP_CRSTAR; - minimize = (c & 1) != 0; - min = rep_min[c]; /* Pick up values from tables; */ - max = rep_max[c]; /* zero for max => infinity */ - if (max == 0) max = INT_MAX; - break; + /* ===================================================================== */ + /* Match a single character type repeatedly. Note that the property type + does not need to be in a stack frame as it not used within an RMATCH() + loop. */ - case OP_CRRANGE: - case OP_CRMINRANGE: - minimize = (*ecode == OP_CRMINRANGE); - min = GET2(ecode, 1); - max = GET2(ecode, 1 + IMM2_SIZE); - if (max == 0) max = INT_MAX; - ecode += 1 + 2 * IMM2_SIZE; - break; +#define Lstart_eptr F->temp_sptr[0] +#define Lmin F->temp_32[0] +#define Lmax F->temp_32[1] +#define Lctype F->temp_32[2] +#define Lpropvalue F->temp_32[3] - default: /* No repeat follows */ - { - int rc = match_ref(offset, offset_top, eptr, mb, caseless, &length); - if (rc != 0) - { - if (rc > 0) eptr = mb->end_subject; /* Partial match */ - CHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - } - eptr += length; - continue; /* With the main loop */ - } + case OP_TYPEEXACT: + Lmin = Lmax = GET2(Fecode, 1); + Fecode += 1 + IMM2_SIZE; + goto REPEATTYPE; - /* Handle repeated back references. If a set group has length zero, just - continue with the main loop, because it matches however many times. For an - unset reference, if the minimum is zero, we can also just continue. We an - also continue if PCRE2_MATCH_UNSET_BACKREF is set, because this makes unset - group be have as a zero-length group. For any other unset cases, carrying - on will result in NOMATCH. */ + case OP_TYPEUPTO: + case OP_TYPEMINUPTO: + Lmin = 0; + Lmax = GET2(Fecode, 1); + reptype = (*Fecode == OP_TYPEMINUPTO)? REPTYPE_MIN : REPTYPE_MAX; + Fecode += 1 + IMM2_SIZE; + goto REPEATTYPE; - if (offset < offset_top && mb->ovector[offset] != PCRE2_UNSET) - { - if (mb->ovector[offset] == mb->ovector[offset + 1]) continue; - } - else /* Group is not set */ - { - if (min == 0 || (mb->poptions & PCRE2_MATCH_UNSET_BACKREF) != 0) - continue; - } + case OP_TYPEPOSSTAR: + reptype = REPTYPE_POS; + Lmin = 0; + Lmax = UINT32_MAX; + Fecode++; + goto REPEATTYPE; - /* First, ensure the minimum number of matches are present. */ + case OP_TYPEPOSPLUS: + reptype = REPTYPE_POS; + Lmin = 1; + Lmax = UINT32_MAX; + Fecode++; + goto REPEATTYPE; - for (i = 1; i <= min; i++) - { - PCRE2_SIZE slength; - int rc = match_ref(offset, offset_top, eptr, mb, caseless, &slength); - if (rc != 0) - { - if (rc > 0) eptr = mb->end_subject; /* Partial match */ - CHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - eptr += slength; - } + case OP_TYPEPOSQUERY: + reptype = REPTYPE_POS; + Lmin = 0; + Lmax = 1; + Fecode++; + goto REPEATTYPE; + + case OP_TYPEPOSUPTO: + reptype = REPTYPE_POS; + Lmin = 0; + Lmax = GET2(Fecode, 1); + Fecode += 1 + IMM2_SIZE; + goto REPEATTYPE; - /* If min = max, continue at the same level without recursion. - They are not both allowed to be zero. */ + case OP_TYPESTAR: + case OP_TYPEMINSTAR: + case OP_TYPEPLUS: + case OP_TYPEMINPLUS: + case OP_TYPEQUERY: + case OP_TYPEMINQUERY: + fc = *Fecode++ - OP_TYPESTAR; + Lmin = rep_min[fc]; + Lmax = rep_max[fc]; + reptype = rep_typ[fc]; - if (min == max) continue; + /* Common code for all repeated character type matches. */ - /* If minimizing, keep trying and advancing the pointer */ + REPEATTYPE: + Lctype = *Fecode++; /* Code for the character type */ - if (minimize) +#ifdef SUPPORT_UNICODE + if (Lctype == OP_PROP || Lctype == OP_NOTPROP) { - for (fi = min;; fi++) - { - int rc; - PCRE2_SIZE slength; - RMATCH(eptr, ecode, offset_top, mb, eptrb, RM14); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - if (fi >= max) RRETURN(MATCH_NOMATCH); - rc = match_ref(offset, offset_top, eptr, mb, caseless, &slength); - if (rc != 0) - { - if (rc > 0) eptr = mb->end_subject; /* Partial match */ - CHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - eptr += slength; - } - /* Control never gets here */ + proptype = *Fecode++; + Lpropvalue = *Fecode++; } + else proptype = -1; +#endif - /* If maximizing, find the longest string and work backwards, as long as - the matched lengths for each iteration are the same. */ + /* First, ensure the minimum number of matches are present. Use inline + code for maximizing the speed, and do the type test once at the start + (i.e. keep it out of the loop). The code for UTF mode is separated out for + tidiness, except for Unicode property tests. */ - else + if (Lmin > 0) { - BOOL samelengths = TRUE; - pp = eptr; - length = mb->ovector[offset+1] - mb->ovector[offset]; - - for (i = min; i < max; i++) +#ifdef SUPPORT_UNICODE + if (proptype >= 0) /* Property tests in all modes */ { - PCRE2_SIZE slength; - int rc = match_ref(offset, offset_top, eptr, mb, caseless, &slength); - - if (rc != 0) + switch(proptype) { - /* Can't use CHECK_PARTIAL because we don't want to update eptr in - the soft partial matching case. */ - - if (rc > 0 && mb->partial != 0 && - mb->end_subject > mb->start_used_ptr) + case PT_ANY: + if (Lctype == OP_NOTPROP) RRETURN(MATCH_NOMATCH); + for (i = 1; i <= Lmin; i++) { - mb->hitend = TRUE; - if (mb->partial > 1) RRETURN(PCRE2_ERROR_PARTIAL); + if (Feptr >= mb->end_subject) + { + SCHECK_PARTIAL(); + RRETURN(MATCH_NOMATCH); + } + GETCHARINCTEST(fc, Feptr); } break; - } - - if (slength != length) samelengths = FALSE; - eptr += slength; - } - - /* If the length matched for each repetition is the same as the length of - the captured group, we can easily work backwards. This is the normal - case. However, in caseless UTF-8 mode there are pairs of case-equivalent - characters whose lengths (in terms of code units) differ. However, this - is very rare, so we handle it by re-matching fewer and fewer times. */ - - if (samelengths) - { - while (eptr >= pp) - { - RMATCH(eptr, ecode, offset_top, mb, eptrb, RM15); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - eptr -= length; - } - } - - /* The rare case of non-matching lengths. Re-scan the repetition for each - iteration. We know that match_ref() will succeed every time. */ - else - { - max = i; - for (;;) - { - RMATCH(eptr, ecode, offset_top, mb, eptrb, RM68); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - if (eptr == pp) break; /* Failed after minimal repetition */ - eptr = pp; - max--; - for (i = min; i < max; i++) + case PT_LAMP: + for (i = 1; i <= Lmin; i++) { - PCRE2_SIZE slength; - (void)match_ref(offset, offset_top, eptr, mb, caseless, &slength); - eptr += slength; + int chartype; + if (Feptr >= mb->end_subject) + { + SCHECK_PARTIAL(); + RRETURN(MATCH_NOMATCH); + } + GETCHARINCTEST(fc, Feptr); + chartype = UCD_CHARTYPE(fc); + if ((chartype == ucp_Lu || + chartype == ucp_Ll || + chartype == ucp_Lt) == (Lctype == OP_NOTPROP)) + RRETURN(MATCH_NOMATCH); } - } - } - - RRETURN(MATCH_NOMATCH); - } - /* Control never gets here */ - - /* Match a bit-mapped character class, possibly repeatedly. This op code is - used when all the characters in the class have values in the range 0-255, - and either the matching is caseful, or the characters are in the range - 0-127 when UTF-8 processing is enabled. The only difference between - OP_CLASS and OP_NCLASS occurs when a data character outside the range is - encountered. - - First, look past the end of the item to see if there is repeat information - following. Then obey similar code to character type repeats - written out - again for speed. */ - - case OP_NCLASS: - case OP_CLASS: - { - /* The data variable is saved across frames, so the byte map needs to - be stored there. */ -#define BYTE_MAP ((uint8_t *)data) - data = ecode + 1; /* Save for matching */ - ecode += 1 + (32 / sizeof(PCRE2_UCHAR)); /* Advance past the item */ - - switch (*ecode) - { - case OP_CRSTAR: - case OP_CRMINSTAR: - case OP_CRPLUS: - case OP_CRMINPLUS: - case OP_CRQUERY: - case OP_CRMINQUERY: - case OP_CRPOSSTAR: - case OP_CRPOSPLUS: - case OP_CRPOSQUERY: - c = *ecode++ - OP_CRSTAR; - if (c < OP_CRPOSSTAR - OP_CRSTAR) minimize = (c & 1) != 0; - else possessive = TRUE; - min = rep_min[c]; /* Pick up values from tables; */ - max = rep_max[c]; /* zero for max => infinity */ - if (max == 0) max = INT_MAX; - break; - - case OP_CRRANGE: - case OP_CRMINRANGE: - case OP_CRPOSRANGE: - minimize = (*ecode == OP_CRMINRANGE); - possessive = (*ecode == OP_CRPOSRANGE); - min = GET2(ecode, 1); - max = GET2(ecode, 1 + IMM2_SIZE); - if (max == 0) max = INT_MAX; - ecode += 1 + 2 * IMM2_SIZE; - break; - - default: /* No repeat follows */ - min = max = 1; - break; - } - - /* First, ensure the minimum number of matches are present. */ + break; -#ifdef SUPPORT_UNICODE - if (utf) - { - for (i = 1; i <= min; i++) - { - if (eptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - GETCHARINC(c, eptr); - if (c > 255) - { - if (op == OP_CLASS) RRETURN(MATCH_NOMATCH); - } - else - if ((BYTE_MAP[c/8] & (1 << (c&7))) == 0) RRETURN(MATCH_NOMATCH); - } - } - else -#endif - /* Not UTF mode */ - { - for (i = 1; i <= min; i++) - { - if (eptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - c = *eptr++; -#if PCRE2_CODE_UNIT_WIDTH != 8 - if (c > 255) + case PT_GC: + for (i = 1; i <= Lmin; i++) { - if (op == OP_CLASS) RRETURN(MATCH_NOMATCH); + if (Feptr >= mb->end_subject) + { + SCHECK_PARTIAL(); + RRETURN(MATCH_NOMATCH); + } + GETCHARINCTEST(fc, Feptr); + if ((UCD_CATEGORY(fc) == Lpropvalue) == (Lctype == OP_NOTPROP)) + RRETURN(MATCH_NOMATCH); } - else -#endif - if ((BYTE_MAP[c/8] & (1 << (c&7))) == 0) RRETURN(MATCH_NOMATCH); - } - } - - /* If max == min we can continue with the main loop without the - need to recurse. */ - - if (min == max) continue; - - /* If minimizing, keep testing the rest of the expression and advancing - the pointer while it matches the class. */ + break; - if (minimize) - { -#ifdef SUPPORT_UNICODE - if (utf) - { - for (fi = min;; fi++) + case PT_PC: + for (i = 1; i <= Lmin; i++) { - RMATCH(eptr, ecode, offset_top, mb, eptrb, RM16); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - if (fi >= max) RRETURN(MATCH_NOMATCH); - if (eptr >= mb->end_subject) + if (Feptr >= mb->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } - GETCHARINC(c, eptr); - if (c > 255) - { - if (op == OP_CLASS) RRETURN(MATCH_NOMATCH); - } - else - if ((BYTE_MAP[c/8] & (1 << (c&7))) == 0) RRETURN(MATCH_NOMATCH); + GETCHARINCTEST(fc, Feptr); + if ((UCD_CHARTYPE(fc) == Lpropvalue) == (Lctype == OP_NOTPROP)) + RRETURN(MATCH_NOMATCH); } - } - else -#endif - /* Not UTF mode */ - { - for (fi = min;; fi++) + break; + + case PT_SC: + for (i = 1; i <= Lmin; i++) { - RMATCH(eptr, ecode, offset_top, mb, eptrb, RM17); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - if (fi >= max) RRETURN(MATCH_NOMATCH); - if (eptr >= mb->end_subject) + if (Feptr >= mb->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } - c = *eptr++; -#if PCRE2_CODE_UNIT_WIDTH != 8 - if (c > 255) + GETCHARINCTEST(fc, Feptr); + if ((UCD_SCRIPT(fc) == Lpropvalue) == (Lctype == OP_NOTPROP)) + RRETURN(MATCH_NOMATCH); + } + break; + + case PT_ALNUM: + for (i = 1; i <= Lmin; i++) + { + int category; + if (Feptr >= mb->end_subject) { - if (op == OP_CLASS) RRETURN(MATCH_NOMATCH); + SCHECK_PARTIAL(); + RRETURN(MATCH_NOMATCH); } - else -#endif - if ((BYTE_MAP[c/8] & (1 << (c&7))) == 0) RRETURN(MATCH_NOMATCH); + GETCHARINCTEST(fc, Feptr); + category = UCD_CATEGORY(fc); + if ((category == ucp_L || category == ucp_N) == (Lctype == OP_NOTPROP)) + RRETURN(MATCH_NOMATCH); } - } - /* Control never gets here */ - } - - /* If maximizing, find the longest possible run, then work backwards. */ + break; - else - { - pp = eptr; + /* Perl space used to exclude VT, but from Perl 5.18 it is included, + which means that Perl space and POSIX space are now identical. PCRE + was changed at release 8.34. */ -#ifdef SUPPORT_UNICODE - if (utf) - { - for (i = min; i < max; i++) + case PT_SPACE: /* Perl space */ + case PT_PXSPACE: /* POSIX space */ + for (i = 1; i <= Lmin; i++) { - int len = 1; - if (eptr >= mb->end_subject) + if (Feptr >= mb->end_subject) { SCHECK_PARTIAL(); - break; + RRETURN(MATCH_NOMATCH); } - GETCHARLEN(c, eptr, len); - if (c > 255) + GETCHARINCTEST(fc, Feptr); + switch(fc) { - if (op == OP_CLASS) break; + HSPACE_CASES: + VSPACE_CASES: + if (Lctype == OP_NOTPROP) RRETURN(MATCH_NOMATCH); + break; + + default: + if ((UCD_CATEGORY(fc) == ucp_Z) == (Lctype == OP_NOTPROP)) + RRETURN(MATCH_NOMATCH); + break; } - else - if ((BYTE_MAP[c/8] & (1 << (c&7))) == 0) break; - eptr += len; } + break; - if (possessive) continue; /* No backtracking */ - - for (;;) + case PT_WORD: + for (i = 1; i <= Lmin; i++) { - RMATCH(eptr, ecode, offset_top, mb, eptrb, RM18); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - if (eptr-- == pp) break; /* Stop if tried at original pos */ - BACKCHAR(eptr); + int category; + if (Feptr >= mb->end_subject) + { + SCHECK_PARTIAL(); + RRETURN(MATCH_NOMATCH); + } + GETCHARINCTEST(fc, Feptr); + category = UCD_CATEGORY(fc); + if ((category == ucp_L || category == ucp_N || + fc == CHAR_UNDERSCORE) == (Lctype == OP_NOTPROP)) + RRETURN(MATCH_NOMATCH); } - } - else -#endif - /* Not UTF mode */ - { - for (i = min; i < max; i++) + break; + + case PT_CLIST: + for (i = 1; i <= Lmin; i++) { - if (eptr >= mb->end_subject) + const uint32_t *cp; + if (Feptr >= mb->end_subject) { SCHECK_PARTIAL(); - break; + RRETURN(MATCH_NOMATCH); } - c = *eptr; -#if PCRE2_CODE_UNIT_WIDTH != 8 - if (c > 255) + GETCHARINCTEST(fc, Feptr); + cp = PRIV(ucd_caseless_sets) + Lpropvalue; + for (;;) { - if (op == OP_CLASS) break; + if (fc < *cp) + { + if (Lctype == OP_NOTPROP) break; + RRETURN(MATCH_NOMATCH); + } + if (fc == *cp++) + { + if (Lctype == OP_NOTPROP) RRETURN(MATCH_NOMATCH); + break; + } } - else -#endif - if ((BYTE_MAP[c/8] & (1 << (c&7))) == 0) break; - eptr++; } + break; - if (possessive) continue; /* No backtracking */ - - while (eptr >= pp) + case PT_UCNC: + for (i = 1; i <= Lmin; i++) { - RMATCH(eptr, ecode, offset_top, mb, eptrb, RM19); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - eptr--; + if (Feptr >= mb->end_subject) + { + SCHECK_PARTIAL(); + RRETURN(MATCH_NOMATCH); + } + GETCHARINCTEST(fc, Feptr); + if ((fc == CHAR_DOLLAR_SIGN || fc == CHAR_COMMERCIAL_AT || + fc == CHAR_GRAVE_ACCENT || (fc >= 0xa0 && fc <= 0xd7ff) || + fc >= 0xe000) == (Lctype == OP_NOTPROP)) + RRETURN(MATCH_NOMATCH); } - } + break; - RRETURN(MATCH_NOMATCH); + /* This should not occur */ + + default: + return PCRE2_ERROR_INTERNAL; + } } -#undef BYTE_MAP - } - /* Control never gets here */ + /* Match extended Unicode sequences. We will get here only if the + support is in the binary; otherwise a compile-time error occurs. */ - /* Match an extended character class. In the 8-bit library, this opcode is - encountered only when UTF-8 mode mode is supported. In the 16-bit and - 32-bit libraries, codepoints greater than 255 may be encountered even when - UTF is not supported. */ + else if (Lctype == OP_EXTUNI) + { + for (i = 1; i <= Lmin; i++) + { + if (Feptr >= mb->end_subject) + { + SCHECK_PARTIAL(); + RRETURN(MATCH_NOMATCH); + } + else + { + int lgb, rgb; + GETCHARINCTEST(fc, Feptr); + lgb = UCD_GRAPHBREAK(fc); + while (Feptr < mb->end_subject) + { + int len = 1; + if (!utf) fc = *Feptr; else { GETCHARLEN(fc, Feptr, len); } + rgb = UCD_GRAPHBREAK(fc); + if ((PRIV(ucp_gbtable)[lgb] & (1 << rgb)) == 0) break; -#ifdef SUPPORT_WIDE_CHARS - case OP_XCLASS: - { - data = ecode + 1 + LINK_SIZE; /* Save for matching */ - ecode += GET(ecode, 1); /* Advance past the item */ + /* Not breaking between Regional Indicators is allowed only if + there are an even number of preceding RIs. */ - switch (*ecode) - { - case OP_CRSTAR: - case OP_CRMINSTAR: - case OP_CRPLUS: - case OP_CRMINPLUS: - case OP_CRQUERY: - case OP_CRMINQUERY: - case OP_CRPOSSTAR: - case OP_CRPOSPLUS: - case OP_CRPOSQUERY: - c = *ecode++ - OP_CRSTAR; - if (c < OP_CRPOSSTAR - OP_CRSTAR) minimize = (c & 1) != 0; - else possessive = TRUE; - min = rep_min[c]; /* Pick up values from tables; */ - max = rep_max[c]; /* zero for max => infinity */ - if (max == 0) max = INT_MAX; - break; + if (lgb == ucp_gbRegionalIndicator && + rgb == ucp_gbRegionalIndicator) + { + int ricount = 0; + PCRE2_SPTR bptr = Feptr - 1; +#ifdef SUPPORT_UNICODE + if (utf) BACKCHAR(bptr); +#endif + /* bptr is pointing to the left-hand character */ - case OP_CRRANGE: - case OP_CRMINRANGE: - case OP_CRPOSRANGE: - minimize = (*ecode == OP_CRMINRANGE); - possessive = (*ecode == OP_CRPOSRANGE); - min = GET2(ecode, 1); - max = GET2(ecode, 1 + IMM2_SIZE); - if (max == 0) max = INT_MAX; - ecode += 1 + 2 * IMM2_SIZE; - break; + while (bptr > mb->start_subject) + { + bptr--; +#ifdef SUPPORT_UNICODE + if (utf) + { + BACKCHAR(bptr); + GETCHAR(fc, bptr); + } + else +#endif + fc = *bptr; + if (UCD_GRAPHBREAK(fc) != ucp_gbRegionalIndicator) break; + ricount++; + } + if ((ricount & 1) != 0) break; /* Grapheme break required */ + } - default: /* No repeat follows */ - min = max = 1; - break; - } + /* If Extend follows E_Base[_GAZ] do not update lgb; this allows + any number of Extend before a following E_Modifier. */ - /* First, ensure the minimum number of matches are present. */ + if (rgb != ucp_gbExtend || + (lgb != ucp_gbE_Base && lgb != ucp_gbE_Base_GAZ)) + lgb = rgb; - for (i = 1; i <= min; i++) - { - if (eptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); + Feptr += len; + } + } + CHECK_PARTIAL(); } - GETCHARINCTEST(c, eptr); - if (!PRIV(xclass)(c, data, utf)) RRETURN(MATCH_NOMATCH); } - /* If max == min we can continue with the main loop without the - need to recurse. */ - - if (min == max) continue; + else +#endif /* SUPPORT_UNICODE */ - /* If minimizing, keep testing the rest of the expression and advancing - the pointer while it matches the class. */ +/* Handle all other cases in UTF mode */ - if (minimize) +#ifdef SUPPORT_UNICODE + if (utf) switch(Lctype) { - for (fi = min;; fi++) + case OP_ANY: + for (i = 1; i <= Lmin; i++) { - RMATCH(eptr, ecode, offset_top, mb, eptrb, RM20); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - if (fi >= max) RRETURN(MATCH_NOMATCH); - if (eptr >= mb->end_subject) + if (Feptr >= mb->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } - GETCHARINCTEST(c, eptr); - if (!PRIV(xclass)(c, data, utf)) RRETURN(MATCH_NOMATCH); + if (IS_NEWLINE(Feptr)) RRETURN(MATCH_NOMATCH); + if (mb->partial != 0 && + Feptr + 1 >= mb->end_subject && + NLBLOCK->nltype == NLTYPE_FIXED && + NLBLOCK->nllen == 2 && + UCHAR21(Feptr) == NLBLOCK->nl[0]) + { + mb->hitend = TRUE; + if (mb->partial > 1) return PCRE2_ERROR_PARTIAL; + } + Feptr++; + ACROSSCHAR(Feptr < mb->end_subject, *Feptr, Feptr++); } - /* Control never gets here */ - } - - /* If maximizing, find the longest possible run, then work backwards. */ + break; - else - { - pp = eptr; - for (i = min; i < max; i++) + case OP_ALLANY: + for (i = 1; i <= Lmin; i++) { - int len = 1; - if (eptr >= mb->end_subject) + if (Feptr >= mb->end_subject) { SCHECK_PARTIAL(); - break; + RRETURN(MATCH_NOMATCH); } -#ifdef SUPPORT_UNICODE - GETCHARLENTEST(c, eptr, len); -#else - c = *eptr; -#endif - if (!PRIV(xclass)(c, data, utf)) break; - eptr += len; + Feptr++; + ACROSSCHAR(Feptr < mb->end_subject, *Feptr, Feptr++); } + break; - if (possessive) continue; /* No backtracking */ + case OP_ANYBYTE: + if (Feptr > mb->end_subject - Lmin) RRETURN(MATCH_NOMATCH); + Feptr += Lmin; + break; - for(;;) + case OP_ANYNL: + for (i = 1; i <= Lmin; i++) { - RMATCH(eptr, ecode, offset_top, mb, eptrb, RM21); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - if (eptr-- == pp) break; /* Stop if tried at original pos */ -#ifdef SUPPORT_UNICODE - if (utf) BACKCHAR(eptr); -#endif - } - RRETURN(MATCH_NOMATCH); - } + if (Feptr >= mb->end_subject) + { + SCHECK_PARTIAL(); + RRETURN(MATCH_NOMATCH); + } + GETCHARINC(fc, Feptr); + switch(fc) + { + default: RRETURN(MATCH_NOMATCH); - /* Control never gets here */ - } -#endif /* End of XCLASS */ + case CHAR_CR: + if (Feptr < mb->end_subject && UCHAR21(Feptr) == CHAR_LF) Feptr++; + break; - /* Match a single character, casefully */ + case CHAR_LF: + break; - case OP_CHAR: -#ifdef SUPPORT_UNICODE - if (utf) - { - length = 1; - ecode++; - GETCHARLEN(fc, ecode, length); - if (length > (PCRE2_SIZE)(mb->end_subject - eptr)) - { - CHECK_PARTIAL(); /* Not SCHECK_PARTIAL() */ - RRETURN(MATCH_NOMATCH); - } - for (; length > 0; length--) - { - if (*ecode++ != UCHAR21INC(eptr)) RRETURN(MATCH_NOMATCH); - } - } - else -#endif - /* Not UTF mode */ - { - if (mb->end_subject - eptr < 1) - { - SCHECK_PARTIAL(); /* This one can use SCHECK_PARTIAL() */ - RRETURN(MATCH_NOMATCH); - } - if (ecode[1] != *eptr++) RRETURN(MATCH_NOMATCH); - ecode += 2; - } - break; + case CHAR_VT: + case CHAR_FF: + case CHAR_NEL: +#ifndef EBCDIC + case 0x2028: + case 0x2029: +#endif /* Not EBCDIC */ + if (mb->bsr_convention == PCRE2_BSR_ANYCRLF) RRETURN(MATCH_NOMATCH); + break; + } + } + break; - /* Match a single character, caselessly. If we are at the end of the - subject, give up immediately. */ + case OP_NOT_HSPACE: + for (i = 1; i <= Lmin; i++) + { + if (Feptr >= mb->end_subject) + { + SCHECK_PARTIAL(); + RRETURN(MATCH_NOMATCH); + } + GETCHARINC(fc, Feptr); + switch(fc) + { + HSPACE_CASES: RRETURN(MATCH_NOMATCH); + default: break; + } + } + break; - case OP_CHARI: - if (eptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } + case OP_HSPACE: + for (i = 1; i <= Lmin; i++) + { + if (Feptr >= mb->end_subject) + { + SCHECK_PARTIAL(); + RRETURN(MATCH_NOMATCH); + } + GETCHARINC(fc, Feptr); + switch(fc) + { + HSPACE_CASES: break; + default: RRETURN(MATCH_NOMATCH); + } + } + break; -#ifdef SUPPORT_UNICODE - if (utf) - { - length = 1; - ecode++; - GETCHARLEN(fc, ecode, length); - - /* If the pattern character's value is < 128, we have only one byte, and - we know that its other case must also be one byte long, so we can use the - fast lookup table. We know that there is at least one byte left in the - subject. */ - - if (fc < 128) - { - uint32_t cc = UCHAR21(eptr); - if (mb->lcc[fc] != TABLE_GET(cc, mb->lcc, cc)) RRETURN(MATCH_NOMATCH); - ecode++; - eptr++; - } - - /* Otherwise we must pick up the subject character. Note that we cannot - use the value of "length" to check for sufficient bytes left, because the - other case of the character may have more or fewer bytes. */ - - else - { - uint32_t dc; - GETCHARINC(dc, eptr); - ecode += length; - - /* If we have Unicode property support, we can use it to test the other - case of the character, if there is one. */ - - if (fc != dc) + case OP_NOT_VSPACE: + for (i = 1; i <= Lmin; i++) { -#ifdef SUPPORT_UNICODE - if (dc != UCD_OTHERCASE(fc)) -#endif + if (Feptr >= mb->end_subject) + { + SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); + } + GETCHARINC(fc, Feptr); + switch(fc) + { + VSPACE_CASES: RRETURN(MATCH_NOMATCH); + default: break; + } } - } - } - else -#endif /* SUPPORT_UNICODE */ - - /* Not UTF mode */ - { - if (TABLE_GET(ecode[1], mb->lcc, ecode[1]) - != TABLE_GET(*eptr, mb->lcc, *eptr)) RRETURN(MATCH_NOMATCH); - eptr++; - ecode += 2; - } - break; - - /* Match a single character repeatedly. */ - - case OP_EXACT: - case OP_EXACTI: - min = max = GET2(ecode, 1); - ecode += 1 + IMM2_SIZE; - goto REPEATCHAR; - - case OP_POSUPTO: - case OP_POSUPTOI: - possessive = TRUE; - /* Fall through */ - - case OP_UPTO: - case OP_UPTOI: - case OP_MINUPTO: - case OP_MINUPTOI: - min = 0; - max = GET2(ecode, 1); - minimize = *ecode == OP_MINUPTO || *ecode == OP_MINUPTOI; - ecode += 1 + IMM2_SIZE; - goto REPEATCHAR; - - case OP_POSSTAR: - case OP_POSSTARI: - possessive = TRUE; - min = 0; - max = INT_MAX; - ecode++; - goto REPEATCHAR; - - case OP_POSPLUS: - case OP_POSPLUSI: - possessive = TRUE; - min = 1; - max = INT_MAX; - ecode++; - goto REPEATCHAR; - - case OP_POSQUERY: - case OP_POSQUERYI: - possessive = TRUE; - min = 0; - max = 1; - ecode++; - goto REPEATCHAR; - - case OP_STAR: - case OP_STARI: - case OP_MINSTAR: - case OP_MINSTARI: - case OP_PLUS: - case OP_PLUSI: - case OP_MINPLUS: - case OP_MINPLUSI: - case OP_QUERY: - case OP_QUERYI: - case OP_MINQUERY: - case OP_MINQUERYI: - c = *ecode++ - ((op < OP_STARI)? OP_STAR : OP_STARI); - minimize = (c & 1) != 0; - min = rep_min[c]; /* Pick up values from tables; */ - max = rep_max[c]; /* zero for max => infinity */ - if (max == 0) max = INT_MAX; - - /* Common code for all repeated single-character matches. We first check - for the minimum number of characters. If the minimum equals the maximum, we - are done. Otherwise, if minimizing, check the rest of the pattern for a - match; if there isn't one, advance up to the maximum, one character at a - time. - - If maximizing, advance up to the maximum number of matching characters, - until eptr is past the end of the maximum run. If possessive, we are - then done (no backing up). Otherwise, match at this position; anything - other than no match is immediately returned. For nomatch, back up one - character, unless we are matching \R and the last thing matched was - \r\n, in which case, back up two bytes. When we reach the first optional - character position, we can save stack by doing a tail recurse. - - The various UTF/non-UTF and caseful/caseless cases are handled separately, - for speed. */ - - REPEATCHAR: -#ifdef SUPPORT_UNICODE - if (utf) - { - length = 1; - charptr = ecode; - GETCHARLEN(fc, ecode, length); - ecode += length; - - /* Handle multibyte character matching specially here. There is - support for caseless matching if UCP support is present. */ - - if (length > 1) - { - uint32_t othercase; - if (op >= OP_STARI && /* Caseless */ - (othercase = UCD_OTHERCASE(fc)) != fc) - oclength = PRIV(ord2utf)(othercase, occhars); - else oclength = 0; + break; - for (i = 1; i <= min; i++) + case OP_VSPACE: + for (i = 1; i <= Lmin; i++) { - if (eptr <= mb->end_subject - length && - memcmp(eptr, charptr, CU2BYTES(length)) == 0) eptr += length; - else if (oclength > 0 && - eptr <= mb->end_subject - oclength && - memcmp(eptr, occhars, CU2BYTES(oclength)) == 0) eptr += oclength; - else + if (Feptr >= mb->end_subject) { - CHECK_PARTIAL(); + SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } + GETCHARINC(fc, Feptr); + switch(fc) + { + VSPACE_CASES: break; + default: RRETURN(MATCH_NOMATCH); + } } + break; - if (min == max) continue; - - if (minimize) + case OP_NOT_DIGIT: + for (i = 1; i <= Lmin; i++) { - for (fi = min;; fi++) + if (Feptr >= mb->end_subject) { - RMATCH(eptr, ecode, offset_top, mb, eptrb, RM22); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - if (fi >= max) RRETURN(MATCH_NOMATCH); - if (eptr <= mb->end_subject - length && - memcmp(eptr, charptr, CU2BYTES(length)) == 0) eptr += length; - else if (oclength > 0 && - eptr <= mb->end_subject - oclength && - memcmp(eptr, occhars, CU2BYTES(oclength)) == 0) eptr += oclength; - else - { - CHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } + SCHECK_PARTIAL(); + RRETURN(MATCH_NOMATCH); } - /* Control never gets here */ + GETCHARINC(fc, Feptr); + if (fc < 128 && (mb->ctypes[fc] & ctype_digit) != 0) + RRETURN(MATCH_NOMATCH); } + break; - else /* Maximize */ + case OP_DIGIT: + for (i = 1; i <= Lmin; i++) { - pp = eptr; - for (i = min; i < max; i++) - { - if (eptr <= mb->end_subject - length && - memcmp(eptr, charptr, CU2BYTES(length)) == 0) eptr += length; - else if (oclength > 0 && - eptr <= mb->end_subject - oclength && - memcmp(eptr, occhars, CU2BYTES(oclength)) == 0) eptr += oclength; - else - { - CHECK_PARTIAL(); - break; - } - } - - if (possessive) continue; /* No backtracking */ - - /* After \C in UTF mode, pp might be in the middle of a Unicode - character. Use <= pp to ensure backtracking doesn't go too far. */ - - for(;;) + uint32_t cc; + if (Feptr >= mb->end_subject) { - if (eptr <= pp) goto TAIL_RECURSE; - RMATCH(eptr, ecode, offset_top, mb, eptrb, RM23); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - eptr--; - BACKCHAR(eptr); + SCHECK_PARTIAL(); + RRETURN(MATCH_NOMATCH); } + cc = UCHAR21(Feptr); + if (cc >= 128 || (mb->ctypes[cc] & ctype_digit) == 0) + RRETURN(MATCH_NOMATCH); + Feptr++; + /* No need to skip more code units - we know it has only one. */ } - /* Control never gets here */ - } - - /* If the length of a UTF-8 character is 1, we fall through here, and - obey the code as for non-UTF-8 characters below, though in this case the - value of fc will always be < 128. */ - } - else -#endif /* SUPPORT_UNICODE */ - - /* When not in UTF-8 mode, load a single-byte character. */ - fc = *ecode++; - - /* The value of fc at this point is always one character, though we may - or may not be in UTF mode. The code is duplicated for the caseless and - caseful cases, for speed, since matching characters is likely to be quite - common. First, ensure the minimum number of matches are present. If min = - max, continue at the same level without recursing. Otherwise, if - minimizing, keep trying the rest of the expression and advancing one - matching character if failing, up to the maximum. Alternatively, if - maximizing, find the maximum number of characters and work backwards. */ - - if (op >= OP_STARI) /* Caseless */ - { -#if PCRE2_CODE_UNIT_WIDTH == 8 - /* fc must be < 128 if UTF is enabled. */ - foc = mb->fcc[fc]; -#else -#ifdef SUPPORT_UNICODE - if (utf && fc > 127) - foc = UCD_OTHERCASE(fc); - else -#endif /* SUPPORT_UNICODE */ - foc = TABLE_GET(fc, mb->fcc, fc); -#endif /* PCRE2_CODE_UNIT_WIDTH == 8 */ + break; - for (i = 1; i <= min; i++) - { - uint32_t cc; /* Faster than PCRE2_UCHAR */ - if (eptr >= mb->end_subject) + case OP_NOT_WHITESPACE: + for (i = 1; i <= Lmin; i++) { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); + uint32_t cc; + if (Feptr >= mb->end_subject) + { + SCHECK_PARTIAL(); + RRETURN(MATCH_NOMATCH); + } + cc = UCHAR21(Feptr); + if (cc < 128 && (mb->ctypes[cc] & ctype_space) != 0) + RRETURN(MATCH_NOMATCH); + Feptr++; + ACROSSCHAR(Feptr < mb->end_subject, *Feptr, Feptr++); } - cc = UCHAR21TEST(eptr); - if (fc != cc && foc != cc) RRETURN(MATCH_NOMATCH); - eptr++; - } - if (min == max) continue; - if (minimize) - { - for (fi = min;; fi++) + break; + + case OP_WHITESPACE: + for (i = 1; i <= Lmin; i++) { - uint32_t cc; /* Faster than PCRE2_UCHAR */ - RMATCH(eptr, ecode, offset_top, mb, eptrb, RM24); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - if (fi >= max) RRETURN(MATCH_NOMATCH); - if (eptr >= mb->end_subject) + uint32_t cc; + if (Feptr >= mb->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } - cc = UCHAR21TEST(eptr); - if (fc != cc && foc != cc) RRETURN(MATCH_NOMATCH); - eptr++; + cc = UCHAR21(Feptr); + if (cc >= 128 || (mb->ctypes[cc] & ctype_space) == 0) + RRETURN(MATCH_NOMATCH); + Feptr++; + /* No need to skip more code units - we know it has only one. */ } - /* Control never gets here */ - } - else /* Maximize */ - { - pp = eptr; - for (i = min; i < max; i++) + break; + + case OP_NOT_WORDCHAR: + for (i = 1; i <= Lmin; i++) { - uint32_t cc; /* Faster than PCRE2_UCHAR */ - if (eptr >= mb->end_subject) + uint32_t cc; + if (Feptr >= mb->end_subject) { SCHECK_PARTIAL(); - break; + RRETURN(MATCH_NOMATCH); } - cc = UCHAR21TEST(eptr); - if (fc != cc && foc != cc) break; - eptr++; + cc = UCHAR21(Feptr); + if (cc < 128 && (mb->ctypes[cc] & ctype_word) != 0) + RRETURN(MATCH_NOMATCH); + Feptr++; + ACROSSCHAR(Feptr < mb->end_subject, *Feptr, Feptr++); } - if (possessive) continue; /* No backtracking */ - for (;;) + break; + + case OP_WORDCHAR: + for (i = 1; i <= Lmin; i++) { - if (eptr == pp) goto TAIL_RECURSE; - RMATCH(eptr, ecode, offset_top, mb, eptrb, RM25); - eptr--; - if (rrc != MATCH_NOMATCH) RRETURN(rrc); + uint32_t cc; + if (Feptr >= mb->end_subject) + { + SCHECK_PARTIAL(); + RRETURN(MATCH_NOMATCH); + } + cc = UCHAR21(Feptr); + if (cc >= 128 || (mb->ctypes[cc] & ctype_word) == 0) + RRETURN(MATCH_NOMATCH); + Feptr++; + /* No need to skip more code units - we know it has only one. */ } - /* Control never gets here */ - } - } + break; - /* Caseful comparisons (includes all multi-byte characters) */ + default: + return PCRE2_ERROR_INTERNAL; + } /* End switch(Lctype) */ - else - { - for (i = 1; i <= min; i++) - { - if (eptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - if (fc != UCHAR21INCTEST(eptr)) RRETURN(MATCH_NOMATCH); - } + else +#endif /* SUPPORT_UNICODE */ - if (min == max) continue; + /* Code for the non-UTF case for minimum matching of operators other + than OP_PROP and OP_NOTPROP. */ - if (minimize) + switch(Lctype) { - for (fi = min;; fi++) + case OP_ANY: + for (i = 1; i <= Lmin; i++) { - RMATCH(eptr, ecode, offset_top, mb, eptrb, RM26); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - if (fi >= max) RRETURN(MATCH_NOMATCH); - if (eptr >= mb->end_subject) + if (Feptr >= mb->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } - if (fc != UCHAR21INCTEST(eptr)) RRETURN(MATCH_NOMATCH); - } - /* Control never gets here */ - } - else /* Maximize */ - { - pp = eptr; - for (i = min; i < max; i++) - { - if (eptr >= mb->end_subject) + if (IS_NEWLINE(Feptr)) RRETURN(MATCH_NOMATCH); + if (mb->partial != 0 && + Feptr + 1 >= mb->end_subject && + NLBLOCK->nltype == NLTYPE_FIXED && + NLBLOCK->nllen == 2 && + *Feptr == NLBLOCK->nl[0]) { - SCHECK_PARTIAL(); - break; + mb->hitend = TRUE; + if (mb->partial > 1) return PCRE2_ERROR_PARTIAL; } - if (fc != UCHAR21TEST(eptr)) break; - eptr++; + Feptr++; } - if (possessive) continue; /* No backtracking */ - for (;;) + break; + + case OP_ALLANY: + if (Feptr > mb->end_subject - Lmin) { - if (eptr == pp) goto TAIL_RECURSE; - RMATCH(eptr, ecode, offset_top, mb, eptrb, RM27); - eptr--; - if (rrc != MATCH_NOMATCH) RRETURN(rrc); + SCHECK_PARTIAL(); + RRETURN(MATCH_NOMATCH); } - /* Control never gets here */ - } - } - /* Control never gets here */ - - /* Match a negated single one-byte character. The character we are - checking can be multibyte. */ + Feptr += Lmin; + break; - case OP_NOT: - case OP_NOTI: - if (eptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } -#ifdef SUPPORT_UNICODE - if (utf) - { - uint32_t ch, och; - - ecode++; - GETCHARINC(ch, ecode); - GETCHARINC(c, eptr); - - if (op == OP_NOT) - { - if (ch == c) RRETURN(MATCH_NOMATCH); - } - else - { - if (ch > 127) - och = UCD_OTHERCASE(ch); - else - och = TABLE_GET(ch, mb->fcc, ch); - if (ch == c || och == c) RRETURN(MATCH_NOMATCH); - } - } - else -#endif /* SUPPORT_UNICODE */ - { - uint32_t ch = ecode[1]; - c = *eptr++; - if (ch == c || (op == OP_NOTI && TABLE_GET(ch, mb->fcc, ch) == c)) - RRETURN(MATCH_NOMATCH); - ecode += 2; - } - break; - - /* Match a negated single one-byte character repeatedly. This is almost a - repeat of the code for a repeated single character, but I haven't found a - nice way of commoning these up that doesn't require a test of the - positive/negative option for each character match. Maybe that wouldn't add - very much to the time taken, but character matching *is* what this is all - about... */ - - case OP_NOTEXACT: - case OP_NOTEXACTI: - min = max = GET2(ecode, 1); - ecode += 1 + IMM2_SIZE; - goto REPEATNOTCHAR; - - case OP_NOTUPTO: - case OP_NOTUPTOI: - case OP_NOTMINUPTO: - case OP_NOTMINUPTOI: - min = 0; - max = GET2(ecode, 1); - minimize = *ecode == OP_NOTMINUPTO || *ecode == OP_NOTMINUPTOI; - ecode += 1 + IMM2_SIZE; - goto REPEATNOTCHAR; - - case OP_NOTPOSSTAR: - case OP_NOTPOSSTARI: - possessive = TRUE; - min = 0; - max = INT_MAX; - ecode++; - goto REPEATNOTCHAR; - - case OP_NOTPOSPLUS: - case OP_NOTPOSPLUSI: - possessive = TRUE; - min = 1; - max = INT_MAX; - ecode++; - goto REPEATNOTCHAR; - - case OP_NOTPOSQUERY: - case OP_NOTPOSQUERYI: - possessive = TRUE; - min = 0; - max = 1; - ecode++; - goto REPEATNOTCHAR; - - case OP_NOTPOSUPTO: - case OP_NOTPOSUPTOI: - possessive = TRUE; - min = 0; - max = GET2(ecode, 1); - ecode += 1 + IMM2_SIZE; - goto REPEATNOTCHAR; - - case OP_NOTSTAR: - case OP_NOTSTARI: - case OP_NOTMINSTAR: - case OP_NOTMINSTARI: - case OP_NOTPLUS: - case OP_NOTPLUSI: - case OP_NOTMINPLUS: - case OP_NOTMINPLUSI: - case OP_NOTQUERY: - case OP_NOTQUERYI: - case OP_NOTMINQUERY: - case OP_NOTMINQUERYI: - c = *ecode++ - ((op >= OP_NOTSTARI)? OP_NOTSTARI: OP_NOTSTAR); - minimize = (c & 1) != 0; - min = rep_min[c]; /* Pick up values from tables; */ - max = rep_max[c]; /* zero for max => infinity */ - if (max == 0) max = INT_MAX; - - /* Common code for all repeated single-byte matches. */ + /* This OP_ANYBYTE case will never be reached because \C gets turned + into OP_ALLANY in non-UTF mode. Cut out the code so that coverage + reports don't complain about it's never being used. */ + +/* case OP_ANYBYTE: +* if (Feptr > mb->end_subject - Lmin) +* { +* SCHECK_PARTIAL(); +* RRETURN(MATCH_NOMATCH); +* } +* Feptr += Lmin; +* break; +*/ + case OP_ANYNL: + for (i = 1; i <= Lmin; i++) + { + if (Feptr >= mb->end_subject) + { + SCHECK_PARTIAL(); + RRETURN(MATCH_NOMATCH); + } + switch(*Feptr++) + { + default: RRETURN(MATCH_NOMATCH); - REPEATNOTCHAR: - GETCHARINCTEST(fc, ecode); + case CHAR_CR: + if (Feptr < mb->end_subject && *Feptr == CHAR_LF) Feptr++; + break; - /* The code is duplicated for the caseless and caseful cases, for speed, - since matching characters is likely to be quite common. First, ensure the - minimum number of matches are present. If min = max, continue at the same - level without recursing. Otherwise, if minimizing, keep trying the rest of - the expression and advancing one matching character if failing, up to the - maximum. Alternatively, if maximizing, find the maximum number of - characters and work backwards. */ + case CHAR_LF: + break; - if (op >= OP_NOTSTARI) /* Caseless */ - { -#ifdef SUPPORT_UNICODE - if (utf && fc > 127) - foc = UCD_OTHERCASE(fc); - else -#endif /* SUPPORT_UNICODE */ - foc = TABLE_GET(fc, mb->fcc, fc); + case CHAR_VT: + case CHAR_FF: + case CHAR_NEL: +#if PCRE2_CODE_UNIT_WIDTH != 8 + case 0x2028: + case 0x2029: +#endif + if (mb->bsr_convention == PCRE2_BSR_ANYCRLF) RRETURN(MATCH_NOMATCH); + break; + } + } + break; -#ifdef SUPPORT_UNICODE - if (utf) - { - uint32_t d; - for (i = 1; i <= min; i++) + case OP_NOT_HSPACE: + for (i = 1; i <= Lmin; i++) { - if (eptr >= mb->end_subject) + if (Feptr >= mb->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } - GETCHARINC(d, eptr); - if (fc == d || (uint32_t)foc == d) RRETURN(MATCH_NOMATCH); - } - } - else -#endif /* SUPPORT_UNICODE */ - /* Not UTF mode */ - { - for (i = 1; i <= min; i++) - { - if (eptr >= mb->end_subject) + switch(*Feptr++) { - SCHECK_PARTIAL(); + default: break; + HSPACE_BYTE_CASES: +#if PCRE2_CODE_UNIT_WIDTH != 8 + HSPACE_MULTIBYTE_CASES: +#endif RRETURN(MATCH_NOMATCH); } - if (fc == *eptr || foc == *eptr) RRETURN(MATCH_NOMATCH); - eptr++; } - } - - if (min == max) continue; + break; - if (minimize) - { -#ifdef SUPPORT_UNICODE - if (utf) + case OP_HSPACE: + for (i = 1; i <= Lmin; i++) { - uint32_t d; - for (fi = min;; fi++) + if (Feptr >= mb->end_subject) { - RMATCH(eptr, ecode, offset_top, mb, eptrb, RM28); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - if (fi >= max) RRETURN(MATCH_NOMATCH); - if (eptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - GETCHARINC(d, eptr); - if (fc == d || (uint32_t)foc == d) RRETURN(MATCH_NOMATCH); + SCHECK_PARTIAL(); + RRETURN(MATCH_NOMATCH); } - } - else -#endif /*SUPPORT_UNICODE */ - /* Not UTF mode */ - { - for (fi = min;; fi++) + switch(*Feptr++) { - RMATCH(eptr, ecode, offset_top, mb, eptrb, RM29); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - if (fi >= max) RRETURN(MATCH_NOMATCH); - if (eptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - if (fc == *eptr || foc == *eptr) RRETURN(MATCH_NOMATCH); - eptr++; + default: RRETURN(MATCH_NOMATCH); + HSPACE_BYTE_CASES: +#if PCRE2_CODE_UNIT_WIDTH != 8 + HSPACE_MULTIBYTE_CASES: +#endif + break; } } - /* Control never gets here */ - } - - /* Maximize case */ - - else - { - pp = eptr; + break; -#ifdef SUPPORT_UNICODE - if (utf) + case OP_NOT_VSPACE: + for (i = 1; i <= Lmin; i++) { - uint32_t d; - for (i = min; i < max; i++) + if (Feptr >= mb->end_subject) { - int len = 1; - if (eptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - break; - } - GETCHARLEN(d, eptr, len); - if (fc == d || (uint32_t)foc == d) break; - eptr += len; + SCHECK_PARTIAL(); + RRETURN(MATCH_NOMATCH); } - if (possessive) continue; /* No backtracking */ - - /* After \C in UTF mode, pp might be in the middle of a Unicode - character. Use <= pp to ensure backtracking doesn't go too far. */ - - for(;;) + switch(*Feptr++) { - if (eptr <= pp) goto TAIL_RECURSE; - RMATCH(eptr, ecode, offset_top, mb, eptrb, RM30); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - eptr--; - BACKCHAR(eptr); + VSPACE_BYTE_CASES: +#if PCRE2_CODE_UNIT_WIDTH != 8 + VSPACE_MULTIBYTE_CASES: +#endif + RRETURN(MATCH_NOMATCH); + default: break; } } - else -#endif /* SUPPORT_UNICODE */ - /* Not UTF mode */ + break; + + case OP_VSPACE: + for (i = 1; i <= Lmin; i++) { - for (i = min; i < max; i++) + if (Feptr >= mb->end_subject) { - if (eptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - break; - } - if (fc == *eptr || foc == *eptr) break; - eptr++; + SCHECK_PARTIAL(); + RRETURN(MATCH_NOMATCH); } - if (possessive) continue; /* No backtracking */ - for (;;) + switch(*Feptr++) { - if (eptr == pp) goto TAIL_RECURSE; - RMATCH(eptr, ecode, offset_top, mb, eptrb, RM31); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - eptr--; + default: RRETURN(MATCH_NOMATCH); + VSPACE_BYTE_CASES: +#if PCRE2_CODE_UNIT_WIDTH != 8 + VSPACE_MULTIBYTE_CASES: +#endif + break; } } - /* Control never gets here */ - } - } - - /* Caseful comparisons */ + break; - else - { -#ifdef SUPPORT_UNICODE - if (utf) - { - uint32_t d; - for (i = 1; i <= min; i++) + case OP_NOT_DIGIT: + for (i = 1; i <= Lmin; i++) { - if (eptr >= mb->end_subject) + if (Feptr >= mb->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } - GETCHARINC(d, eptr); - if (fc == d) RRETURN(MATCH_NOMATCH); + if (MAX_255(*Feptr) && (mb->ctypes[*Feptr] & ctype_digit) != 0) + RRETURN(MATCH_NOMATCH); + Feptr++; } - } - else -#endif - /* Not UTF mode */ - { - for (i = 1; i <= min; i++) + break; + + case OP_DIGIT: + for (i = 1; i <= Lmin; i++) { - if (eptr >= mb->end_subject) + if (Feptr >= mb->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } - if (fc == *eptr++) RRETURN(MATCH_NOMATCH); + if (!MAX_255(*Feptr) || (mb->ctypes[*Feptr] & ctype_digit) == 0) + RRETURN(MATCH_NOMATCH); + Feptr++; } - } - - if (min == max) continue; + break; - if (minimize) - { -#ifdef SUPPORT_UNICODE - if (utf) + case OP_NOT_WHITESPACE: + for (i = 1; i <= Lmin; i++) { - uint32_t d; - for (fi = min;; fi++) + if (Feptr >= mb->end_subject) { - RMATCH(eptr, ecode, offset_top, mb, eptrb, RM32); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - if (fi >= max) RRETURN(MATCH_NOMATCH); - if (eptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - GETCHARINC(d, eptr); - if (fc == d) RRETURN(MATCH_NOMATCH); + SCHECK_PARTIAL(); + RRETURN(MATCH_NOMATCH); } + if (MAX_255(*Feptr) && (mb->ctypes[*Feptr] & ctype_space) != 0) + RRETURN(MATCH_NOMATCH); + Feptr++; } - else -#endif - /* Not UTF mode */ + break; + + case OP_WHITESPACE: + for (i = 1; i <= Lmin; i++) { - for (fi = min;; fi++) + if (Feptr >= mb->end_subject) { - RMATCH(eptr, ecode, offset_top, mb, eptrb, RM33); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - if (fi >= max) RRETURN(MATCH_NOMATCH); - if (eptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - if (fc == *eptr++) RRETURN(MATCH_NOMATCH); + SCHECK_PARTIAL(); + RRETURN(MATCH_NOMATCH); } + if (!MAX_255(*Feptr) || (mb->ctypes[*Feptr] & ctype_space) == 0) + RRETURN(MATCH_NOMATCH); + Feptr++; } - /* Control never gets here */ - } - - /* Maximize case */ - - else - { - pp = eptr; + break; -#ifdef SUPPORT_UNICODE - if (utf) + case OP_NOT_WORDCHAR: + for (i = 1; i <= Lmin; i++) { - uint32_t d; - for (i = min; i < max; i++) - { - int len = 1; - if (eptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - break; - } - GETCHARLEN(d, eptr, len); - if (fc == d) break; - eptr += len; - } - if (possessive) continue; /* No backtracking */ - - /* After \C in UTF mode, pp might be in the middle of a Unicode - character. Use <= pp to ensure backtracking doesn't go too far. */ - - for(;;) + if (Feptr >= mb->end_subject) { - if (eptr <= pp) goto TAIL_RECURSE; - RMATCH(eptr, ecode, offset_top, mb, eptrb, RM34); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - eptr--; - BACKCHAR(eptr); + SCHECK_PARTIAL(); + RRETURN(MATCH_NOMATCH); } + if (MAX_255(*Feptr) && (mb->ctypes[*Feptr] & ctype_word) != 0) + RRETURN(MATCH_NOMATCH); + Feptr++; } - else -#endif - /* Not UTF mode */ + break; + + case OP_WORDCHAR: + for (i = 1; i <= Lmin; i++) { - for (i = min; i < max; i++) - { - if (eptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - break; - } - if (fc == *eptr) break; - eptr++; - } - if (possessive) continue; /* No backtracking */ - for (;;) + if (Feptr >= mb->end_subject) { - if (eptr == pp) goto TAIL_RECURSE; - RMATCH(eptr, ecode, offset_top, mb, eptrb, RM35); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - eptr--; + SCHECK_PARTIAL(); + RRETURN(MATCH_NOMATCH); } + if (!MAX_255(*Feptr) || (mb->ctypes[*Feptr] & ctype_word) == 0) + RRETURN(MATCH_NOMATCH); + Feptr++; } - /* Control never gets here */ + break; + + default: + return PCRE2_ERROR_INTERNAL; } } - /* Control never gets here */ - - /* Match a single character type repeatedly; several different opcodes - share code. This is very similar to the code for single characters, but we - repeat it in the interests of efficiency. */ - - case OP_TYPEEXACT: - min = max = GET2(ecode, 1); - minimize = TRUE; - ecode += 1 + IMM2_SIZE; - goto REPEATTYPE; - - case OP_TYPEUPTO: - case OP_TYPEMINUPTO: - min = 0; - max = GET2(ecode, 1); - minimize = *ecode == OP_TYPEMINUPTO; - ecode += 1 + IMM2_SIZE; - goto REPEATTYPE; - - case OP_TYPEPOSSTAR: - possessive = TRUE; - min = 0; - max = INT_MAX; - ecode++; - goto REPEATTYPE; - - case OP_TYPEPOSPLUS: - possessive = TRUE; - min = 1; - max = INT_MAX; - ecode++; - goto REPEATTYPE; - - case OP_TYPEPOSQUERY: - possessive = TRUE; - min = 0; - max = 1; - ecode++; - goto REPEATTYPE; - - case OP_TYPEPOSUPTO: - possessive = TRUE; - min = 0; - max = GET2(ecode, 1); - ecode += 1 + IMM2_SIZE; - goto REPEATTYPE; - - case OP_TYPESTAR: - case OP_TYPEMINSTAR: - case OP_TYPEPLUS: - case OP_TYPEMINPLUS: - case OP_TYPEQUERY: - case OP_TYPEMINQUERY: - c = *ecode++ - OP_TYPESTAR; - minimize = (c & 1) != 0; - min = rep_min[c]; /* Pick up values from tables; */ - max = rep_max[c]; /* zero for max => infinity */ - if (max == 0) max = INT_MAX; - /* Common code for all repeated single character type matches. Note that - in UTF-8 mode, '.' matches a character of any length, but for the other - character types, the valid characters are all one-byte long. */ - - REPEATTYPE: - ctype = *ecode++; /* Code for the character type */ + /* If Lmin = Lmax we are done. Continue with the main loop. */ -#ifdef SUPPORT_UNICODE - if (ctype == OP_PROP || ctype == OP_NOTPROP) - { - prop_fail_result = ctype == OP_NOTPROP; - prop_type = *ecode++; - prop_value = *ecode++; - } - else prop_type = -1; -#endif + if (Lmin == Lmax) continue; - /* First, ensure the minimum number of matches are present. Use inline - code for maximizing the speed, and do the type test once at the start - (i.e. keep it out of the loop). Separate the UTF-8 code completely as that - is tidier. Also separate the UCP code, which can be the same for both UTF-8 - and single-bytes. */ + /* If minimizing, we have to test the rest of the pattern before each + subsequent match. */ - if (min > 0) + if (reptype == REPTYPE_MIN) { #ifdef SUPPORT_UNICODE - if (prop_type >= 0) + if (proptype >= 0) { - switch(prop_type) + switch(proptype) { case PT_ANY: - if (prop_fail_result) RRETURN(MATCH_NOMATCH); - for (i = 1; i <= min; i++) + for (;;) { - if (eptr >= mb->end_subject) + RMATCH(Fecode, RM208); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH); + if (Feptr >= mb->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } - GETCHARINCTEST(c, eptr); + GETCHARINCTEST(fc, Feptr); + if (Lctype == OP_NOTPROP) RRETURN(MATCH_NOMATCH); } - break; + /* Control never gets here */ case PT_LAMP: - for (i = 1; i <= min; i++) + for (;;) { int chartype; - if (eptr >= mb->end_subject) + RMATCH(Fecode, RM209); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH); + if (Feptr >= mb->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } - GETCHARINCTEST(c, eptr); - chartype = UCD_CHARTYPE(c); + GETCHARINCTEST(fc, Feptr); + chartype = UCD_CHARTYPE(fc); if ((chartype == ucp_Lu || chartype == ucp_Ll || - chartype == ucp_Lt) == prop_fail_result) + chartype == ucp_Lt) == (Lctype == OP_NOTPROP)) RRETURN(MATCH_NOMATCH); } - break; + /* Control never gets here */ case PT_GC: - for (i = 1; i <= min; i++) + for (;;) { - if (eptr >= mb->end_subject) + RMATCH(Fecode, RM210); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH); + if (Feptr >= mb->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } - GETCHARINCTEST(c, eptr); - if ((UCD_CATEGORY(c) == prop_value) == prop_fail_result) + GETCHARINCTEST(fc, Feptr); + if ((UCD_CATEGORY(fc) == Lpropvalue) == (Lctype == OP_NOTPROP)) RRETURN(MATCH_NOMATCH); } - break; + /* Control never gets here */ case PT_PC: - for (i = 1; i <= min; i++) + for (;;) { - if (eptr >= mb->end_subject) + RMATCH(Fecode, RM211); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH); + if (Feptr >= mb->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } - GETCHARINCTEST(c, eptr); - if ((UCD_CHARTYPE(c) == prop_value) == prop_fail_result) + GETCHARINCTEST(fc, Feptr); + if ((UCD_CHARTYPE(fc) == Lpropvalue) == (Lctype == OP_NOTPROP)) RRETURN(MATCH_NOMATCH); } - break; + /* Control never gets here */ case PT_SC: - for (i = 1; i <= min; i++) + for (;;) { - if (eptr >= mb->end_subject) + RMATCH(Fecode, RM212); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH); + if (Feptr >= mb->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } - GETCHARINCTEST(c, eptr); - if ((UCD_SCRIPT(c) == prop_value) == prop_fail_result) + GETCHARINCTEST(fc, Feptr); + if ((UCD_SCRIPT(fc) == Lpropvalue) == (Lctype == OP_NOTPROP)) RRETURN(MATCH_NOMATCH); } - break; + /* Control never gets here */ case PT_ALNUM: - for (i = 1; i <= min; i++) + for (;;) { int category; - if (eptr >= mb->end_subject) + RMATCH(Fecode, RM213); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH); + if (Feptr >= mb->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } - GETCHARINCTEST(c, eptr); - category = UCD_CATEGORY(c); - if ((category == ucp_L || category == ucp_N) == prop_fail_result) + GETCHARINCTEST(fc, Feptr); + category = UCD_CATEGORY(fc); + if ((category == ucp_L || category == ucp_N) == + (Lctype == OP_NOTPROP)) RRETURN(MATCH_NOMATCH); } - break; + /* Control never gets here */ /* Perl space used to exclude VT, but from Perl 5.18 it is included, which means that Perl space and POSIX space are now identical. PCRE @@ -4343,98 +3477,119 @@ for (;;) case PT_SPACE: /* Perl space */ case PT_PXSPACE: /* POSIX space */ - for (i = 1; i <= min; i++) + for (;;) { - if (eptr >= mb->end_subject) + RMATCH(Fecode, RM214); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH); + if (Feptr >= mb->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } - GETCHARINCTEST(c, eptr); - switch(c) + GETCHARINCTEST(fc, Feptr); + switch(fc) { HSPACE_CASES: VSPACE_CASES: - if (prop_fail_result) RRETURN(MATCH_NOMATCH); + if (Lctype == OP_NOTPROP) RRETURN(MATCH_NOMATCH); break; default: - if ((UCD_CATEGORY(c) == ucp_Z) == prop_fail_result) + if ((UCD_CATEGORY(fc) == ucp_Z) == (Lctype == OP_NOTPROP)) RRETURN(MATCH_NOMATCH); break; } } - break; + /* Control never gets here */ case PT_WORD: - for (i = 1; i <= min; i++) + for (;;) { int category; - if (eptr >= mb->end_subject) + RMATCH(Fecode, RM215); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH); + if (Feptr >= mb->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } - GETCHARINCTEST(c, eptr); - category = UCD_CATEGORY(c); - if ((category == ucp_L || category == ucp_N || c == CHAR_UNDERSCORE) - == prop_fail_result) + GETCHARINCTEST(fc, Feptr); + category = UCD_CATEGORY(fc); + if ((category == ucp_L || + category == ucp_N || + fc == CHAR_UNDERSCORE) == (Lctype == OP_NOTPROP)) RRETURN(MATCH_NOMATCH); } - break; + /* Control never gets here */ case PT_CLIST: - for (i = 1; i <= min; i++) + for (;;) { const uint32_t *cp; - if (eptr >= mb->end_subject) + RMATCH(Fecode, RM216); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH); + if (Feptr >= mb->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } - GETCHARINCTEST(c, eptr); - cp = PRIV(ucd_caseless_sets) + prop_value; + GETCHARINCTEST(fc, Feptr); + cp = PRIV(ucd_caseless_sets) + Lpropvalue; for (;;) { - if (c < *cp) - { if (prop_fail_result) break; else { RRETURN(MATCH_NOMATCH); } } - if (c == *cp++) - { if (prop_fail_result) { RRETURN(MATCH_NOMATCH); } else break; } + if (fc < *cp) + { + if (Lctype == OP_NOTPROP) break; + RRETURN(MATCH_NOMATCH); + } + if (fc == *cp++) + { + if (Lctype == OP_NOTPROP) RRETURN(MATCH_NOMATCH); + break; + } } } - break; + /* Control never gets here */ case PT_UCNC: - for (i = 1; i <= min; i++) + for (;;) { - if (eptr >= mb->end_subject) + RMATCH(Fecode, RM217); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH); + if (Feptr >= mb->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } - GETCHARINCTEST(c, eptr); - if ((c == CHAR_DOLLAR_SIGN || c == CHAR_COMMERCIAL_AT || - c == CHAR_GRAVE_ACCENT || (c >= 0xa0 && c <= 0xd7ff) || - c >= 0xe000) == prop_fail_result) + GETCHARINCTEST(fc, Feptr); + if ((fc == CHAR_DOLLAR_SIGN || fc == CHAR_COMMERCIAL_AT || + fc == CHAR_GRAVE_ACCENT || (fc >= 0xa0 && fc <= 0xd7ff) || + fc >= 0xe000) == (Lctype == OP_NOTPROP)) RRETURN(MATCH_NOMATCH); } - break; - - /* This should not occur */ + /* Control never gets here */ + /* This should never occur */ default: - RRETURN(PCRE2_ERROR_INTERNAL); + return PCRE2_ERROR_INTERNAL; } } /* Match extended Unicode sequences. We will get here only if the support is in the binary; otherwise a compile-time error occurs. */ - else if (ctype == OP_EXTUNI) + else if (Lctype == OP_EXTUNI) { - for (i = 1; i <= min; i++) + for (;;) { - if (eptr >= mb->end_subject) + RMATCH(Fecode, RM218); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH); + if (Feptr >= mb->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); @@ -4442,645 +3597,449 @@ for (;;) else { int lgb, rgb; - GETCHARINCTEST(c, eptr); - lgb = UCD_GRAPHBREAK(c); - while (eptr < mb->end_subject) + GETCHARINCTEST(fc, Feptr); + lgb = UCD_GRAPHBREAK(fc); + while (Feptr < mb->end_subject) { int len = 1; - if (!utf) c = *eptr; else { GETCHARLEN(c, eptr, len); } - rgb = UCD_GRAPHBREAK(c); + if (!utf) fc = *Feptr; else { GETCHARLEN(fc, Feptr, len); } + rgb = UCD_GRAPHBREAK(fc); if ((PRIV(ucp_gbtable)[lgb] & (1 << rgb)) == 0) break; - lgb = rgb; - eptr += len; + + /* Not breaking between Regional Indicators is allowed only if + there are an even number of preceding RIs. */ + + if (lgb == ucp_gbRegionalIndicator && + rgb == ucp_gbRegionalIndicator) + { + int ricount = 0; + PCRE2_SPTR bptr = Feptr - 1; +#ifdef SUPPORT_UNICODE + if (utf) BACKCHAR(bptr); +#endif + /* bptr is pointing to the left-hand character */ + + while (bptr > mb->start_subject) + { + bptr--; +#ifdef SUPPORT_UNICODE + if (utf) + { + BACKCHAR(bptr); + GETCHAR(fc, bptr); + } + else +#endif + fc = *bptr; + if (UCD_GRAPHBREAK(fc) != ucp_gbRegionalIndicator) break; + ricount++; + } + if ((ricount & 1) != 0) break; /* Grapheme break required */ + } + + /* If Extend follows E_Base[_GAZ] do not update lgb; this allows + any number of Extend before a following E_Modifier. */ + + if (rgb != ucp_gbExtend || + (lgb != ucp_gbE_Base && lgb != ucp_gbE_Base_GAZ)) + lgb = rgb; + + Feptr += len; } } CHECK_PARTIAL(); } } - else #endif /* SUPPORT_UNICODE */ -/* Handle all other cases when the coding is UTF-8 */ + /* UTF mode for non-property testing character types. */ #ifdef SUPPORT_UNICODE - if (utf) switch(ctype) + if (utf) { - case OP_ANY: - for (i = 1; i <= min; i++) + for (;;) { - if (eptr >= mb->end_subject) + RMATCH(Fecode, RM219); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH); + if (Feptr >= mb->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } - if (IS_NEWLINE(eptr)) RRETURN(MATCH_NOMATCH); - if (mb->partial != 0 && - eptr + 1 >= mb->end_subject && - NLBLOCK->nltype == NLTYPE_FIXED && - NLBLOCK->nllen == 2 && - UCHAR21(eptr) == NLBLOCK->nl[0]) + if (Lctype == OP_ANY && IS_NEWLINE(Feptr)) RRETURN(MATCH_NOMATCH); + GETCHARINC(fc, Feptr); + switch(Lctype) { - mb->hitend = TRUE; - if (mb->partial > 1) RRETURN(PCRE2_ERROR_PARTIAL); - } - eptr++; - ACROSSCHAR(eptr < mb->end_subject, *eptr, eptr++); - } - break; + case OP_ANY: /* This is the non-NL case */ + if (mb->partial != 0 && /* Take care with CRLF partial */ + Feptr >= mb->end_subject && + NLBLOCK->nltype == NLTYPE_FIXED && + NLBLOCK->nllen == 2 && + fc == NLBLOCK->nl[0]) + { + mb->hitend = TRUE; + if (mb->partial > 1) return PCRE2_ERROR_PARTIAL; + } + break; - case OP_ALLANY: - for (i = 1; i <= min; i++) - { - if (eptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - eptr++; - ACROSSCHAR(eptr < mb->end_subject, *eptr, eptr++); - } - break; + case OP_ALLANY: + case OP_ANYBYTE: + break; - case OP_ANYBYTE: - if (eptr > mb->end_subject - min) RRETURN(MATCH_NOMATCH); - eptr += min; - break; + case OP_ANYNL: + switch(fc) + { + default: RRETURN(MATCH_NOMATCH); - case OP_ANYNL: - for (i = 1; i <= min; i++) - { - if (eptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - GETCHARINC(c, eptr); - switch(c) - { - default: RRETURN(MATCH_NOMATCH); + case CHAR_CR: + if (Feptr < mb->end_subject && UCHAR21(Feptr) == CHAR_LF) Feptr++; + break; - case CHAR_CR: - if (eptr < mb->end_subject && UCHAR21(eptr) == CHAR_LF) eptr++; + case CHAR_LF: + break; + + case CHAR_VT: + case CHAR_FF: + case CHAR_NEL: +#ifndef EBCDIC + case 0x2028: + case 0x2029: +#endif /* Not EBCDIC */ + if (mb->bsr_convention == PCRE2_BSR_ANYCRLF) + RRETURN(MATCH_NOMATCH); + break; + } break; - case CHAR_LF: + case OP_NOT_HSPACE: + switch(fc) + { + HSPACE_CASES: RRETURN(MATCH_NOMATCH); + default: break; + } break; - case CHAR_VT: - case CHAR_FF: - case CHAR_NEL: -#ifndef EBCDIC - case 0x2028: - case 0x2029: -#endif /* Not EBCDIC */ - if (mb->bsr_convention == PCRE2_BSR_ANYCRLF) RRETURN(MATCH_NOMATCH); + case OP_HSPACE: + switch(fc) + { + HSPACE_CASES: break; + default: RRETURN(MATCH_NOMATCH); + } break; - } - } - break; - case OP_NOT_HSPACE: - for (i = 1; i <= min; i++) - { - if (eptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - GETCHARINC(c, eptr); - switch(c) - { - HSPACE_CASES: RRETURN(MATCH_NOMATCH); /* Byte and multibyte cases */ - default: break; - } - } - break; + case OP_NOT_VSPACE: + switch(fc) + { + VSPACE_CASES: RRETURN(MATCH_NOMATCH); + default: break; + } + break; - case OP_HSPACE: - for (i = 1; i <= min; i++) - { - if (eptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - GETCHARINC(c, eptr); - switch(c) - { - HSPACE_CASES: break; /* Byte and multibyte cases */ - default: RRETURN(MATCH_NOMATCH); - } - } - break; + case OP_VSPACE: + switch(fc) + { + VSPACE_CASES: break; + default: RRETURN(MATCH_NOMATCH); + } + break; - case OP_NOT_VSPACE: - for (i = 1; i <= min; i++) - { - if (eptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - GETCHARINC(c, eptr); - switch(c) - { - VSPACE_CASES: RRETURN(MATCH_NOMATCH); - default: break; - } - } - break; - - case OP_VSPACE: - for (i = 1; i <= min; i++) - { - if (eptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - GETCHARINC(c, eptr); - switch(c) - { - VSPACE_CASES: break; - default: RRETURN(MATCH_NOMATCH); - } - } - break; + case OP_NOT_DIGIT: + if (fc < 256 && (mb->ctypes[fc] & ctype_digit) != 0) + RRETURN(MATCH_NOMATCH); + break; - case OP_NOT_DIGIT: - for (i = 1; i <= min; i++) - { - if (eptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - GETCHARINC(c, eptr); - if (c < 128 && (mb->ctypes[c] & ctype_digit) != 0) - RRETURN(MATCH_NOMATCH); - } - break; + case OP_DIGIT: + if (fc >= 256 || (mb->ctypes[fc] & ctype_digit) == 0) + RRETURN(MATCH_NOMATCH); + break; - case OP_DIGIT: - for (i = 1; i <= min; i++) - { - uint32_t cc; - if (eptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - cc = UCHAR21(eptr); - if (cc >= 128 || (mb->ctypes[cc] & ctype_digit) == 0) - RRETURN(MATCH_NOMATCH); - eptr++; - /* No need to skip more bytes - we know it's a 1-byte character */ - } - break; + case OP_NOT_WHITESPACE: + if (fc < 256 && (mb->ctypes[fc] & ctype_space) != 0) + RRETURN(MATCH_NOMATCH); + break; - case OP_NOT_WHITESPACE: - for (i = 1; i <= min; i++) - { - uint32_t cc; - if (eptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - cc = UCHAR21(eptr); - if (cc < 128 && (mb->ctypes[cc] & ctype_space) != 0) - RRETURN(MATCH_NOMATCH); - eptr++; - ACROSSCHAR(eptr < mb->end_subject, *eptr, eptr++); - } - break; + case OP_WHITESPACE: + if (fc >= 256 || (mb->ctypes[fc] & ctype_space) == 0) + RRETURN(MATCH_NOMATCH); + break; - case OP_WHITESPACE: - for (i = 1; i <= min; i++) - { - uint32_t cc; - if (eptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - cc = UCHAR21(eptr); - if (cc >= 128 || (mb->ctypes[cc] & ctype_space) == 0) - RRETURN(MATCH_NOMATCH); - eptr++; - /* No need to skip more bytes - we know it's a 1-byte character */ - } - break; + case OP_NOT_WORDCHAR: + if (fc < 256 && (mb->ctypes[fc] & ctype_word) != 0) + RRETURN(MATCH_NOMATCH); + break; - case OP_NOT_WORDCHAR: - for (i = 1; i <= min; i++) - { - uint32_t cc; - if (eptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - cc = UCHAR21(eptr); - if (cc < 128 && (mb->ctypes[cc] & ctype_word) != 0) - RRETURN(MATCH_NOMATCH); - eptr++; - ACROSSCHAR(eptr < mb->end_subject, *eptr, eptr++); - } - break; + case OP_WORDCHAR: + if (fc >= 256 || (mb->ctypes[fc] & ctype_word) == 0) + RRETURN(MATCH_NOMATCH); + break; - case OP_WORDCHAR: - for (i = 1; i <= min; i++) - { - uint32_t cc; - if (eptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); + default: + return PCRE2_ERROR_INTERNAL; } - cc = UCHAR21(eptr); - if (cc >= 128 || (mb->ctypes[cc] & ctype_word) == 0) - RRETURN(MATCH_NOMATCH); - eptr++; - /* No need to skip more bytes - we know it's a 1-byte character */ } - break; - - default: - RRETURN(PCRE2_ERROR_INTERNAL); - } /* End switch(ctype) */ - + } else -#endif /* SUPPORT_UNICODE */ - - /* Code for the non-UTF-8 case for minimum matching of operators other - than OP_PROP and OP_NOTPROP. */ +#endif /* SUPPORT_UNICODE */ - switch(ctype) + /* Not UTF mode */ { - case OP_ANY: - for (i = 1; i <= min; i++) + for (;;) { - if (eptr >= mb->end_subject) + RMATCH(Fecode, RM33); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH); + if (Feptr >= mb->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } - if (IS_NEWLINE(eptr)) RRETURN(MATCH_NOMATCH); - if (mb->partial != 0 && - eptr + 1 >= mb->end_subject && - NLBLOCK->nltype == NLTYPE_FIXED && - NLBLOCK->nllen == 2 && - *eptr == NLBLOCK->nl[0]) + if (Lctype == OP_ANY && IS_NEWLINE(Feptr)) + RRETURN(MATCH_NOMATCH); + fc = *Feptr++; + switch(Lctype) { - mb->hitend = TRUE; - if (mb->partial > 1) RRETURN(PCRE2_ERROR_PARTIAL); - } - eptr++; - } - break; + case OP_ANY: /* This is the non-NL case */ + if (mb->partial != 0 && /* Take care with CRLF partial */ + Feptr >= mb->end_subject && + NLBLOCK->nltype == NLTYPE_FIXED && + NLBLOCK->nllen == 2 && + fc == NLBLOCK->nl[0]) + { + mb->hitend = TRUE; + if (mb->partial > 1) return PCRE2_ERROR_PARTIAL; + } + break; - case OP_ALLANY: - if (eptr > mb->end_subject - min) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - eptr += min; - break; + case OP_ALLANY: + case OP_ANYBYTE: + break; - case OP_ANYBYTE: - if (eptr > mb->end_subject - min) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - eptr += min; - break; + case OP_ANYNL: + switch(fc) + { + default: RRETURN(MATCH_NOMATCH); - case OP_ANYNL: - for (i = 1; i <= min; i++) - { - if (eptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - switch(*eptr++) - { - default: RRETURN(MATCH_NOMATCH); + case CHAR_CR: + if (Feptr < mb->end_subject && *Feptr == CHAR_LF) Feptr++; + break; - case CHAR_CR: - if (eptr < mb->end_subject && *eptr == CHAR_LF) eptr++; - break; + case CHAR_LF: + break; - case CHAR_LF: + case CHAR_VT: + case CHAR_FF: + case CHAR_NEL: +#if PCRE2_CODE_UNIT_WIDTH != 8 + case 0x2028: + case 0x2029: +#endif + if (mb->bsr_convention == PCRE2_BSR_ANYCRLF) + RRETURN(MATCH_NOMATCH); + break; + } break; - case CHAR_VT: - case CHAR_FF: - case CHAR_NEL: + case OP_NOT_HSPACE: + switch(fc) + { + default: break; + HSPACE_BYTE_CASES: #if PCRE2_CODE_UNIT_WIDTH != 8 - case 0x2028: - case 0x2029: + HSPACE_MULTIBYTE_CASES: #endif - if (mb->bsr_convention == PCRE2_BSR_ANYCRLF) RRETURN(MATCH_NOMATCH); + RRETURN(MATCH_NOMATCH); + } break; - } - } - break; - case OP_NOT_HSPACE: - for (i = 1; i <= min; i++) - { - if (eptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - switch(*eptr++) - { - default: break; - HSPACE_BYTE_CASES: + case OP_HSPACE: + switch(fc) + { + default: RRETURN(MATCH_NOMATCH); + HSPACE_BYTE_CASES: #if PCRE2_CODE_UNIT_WIDTH != 8 - HSPACE_MULTIBYTE_CASES: + HSPACE_MULTIBYTE_CASES: #endif - RRETURN(MATCH_NOMATCH); - } - } - break; + break; + } + break; - case OP_HSPACE: - for (i = 1; i <= min; i++) - { - if (eptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - switch(*eptr++) - { - default: RRETURN(MATCH_NOMATCH); - HSPACE_BYTE_CASES: + case OP_NOT_VSPACE: + switch(fc) + { + default: break; + VSPACE_BYTE_CASES: #if PCRE2_CODE_UNIT_WIDTH != 8 - HSPACE_MULTIBYTE_CASES: + VSPACE_MULTIBYTE_CASES: #endif + RRETURN(MATCH_NOMATCH); + } break; - } - } - break; - case OP_NOT_VSPACE: - for (i = 1; i <= min; i++) - { - if (eptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - switch(*eptr++) - { - VSPACE_BYTE_CASES: + case OP_VSPACE: + switch(fc) + { + default: RRETURN(MATCH_NOMATCH); + VSPACE_BYTE_CASES: #if PCRE2_CODE_UNIT_WIDTH != 8 - VSPACE_MULTIBYTE_CASES: -#endif - RRETURN(MATCH_NOMATCH); - default: break; - } - } - break; - - case OP_VSPACE: - for (i = 1; i <= min; i++) - { - if (eptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - switch(*eptr++) - { - default: RRETURN(MATCH_NOMATCH); - VSPACE_BYTE_CASES: -#if PCRE2_CODE_UNIT_WIDTH != 8 - VSPACE_MULTIBYTE_CASES: + VSPACE_MULTIBYTE_CASES: #endif + break; + } break; - } - } - break; - case OP_NOT_DIGIT: - for (i = 1; i <= min; i++) - { - if (eptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - if (MAX_255(*eptr) && (mb->ctypes[*eptr] & ctype_digit) != 0) - RRETURN(MATCH_NOMATCH); - eptr++; - } - break; + case OP_NOT_DIGIT: + if (MAX_255(fc) && (mb->ctypes[fc] & ctype_digit) != 0) + RRETURN(MATCH_NOMATCH); + break; - case OP_DIGIT: - for (i = 1; i <= min; i++) - { - if (eptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - if (!MAX_255(*eptr) || (mb->ctypes[*eptr] & ctype_digit) == 0) - RRETURN(MATCH_NOMATCH); - eptr++; - } - break; + case OP_DIGIT: + if (!MAX_255(fc) || (mb->ctypes[fc] & ctype_digit) == 0) + RRETURN(MATCH_NOMATCH); + break; - case OP_NOT_WHITESPACE: - for (i = 1; i <= min; i++) - { - if (eptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - if (MAX_255(*eptr) && (mb->ctypes[*eptr] & ctype_space) != 0) - RRETURN(MATCH_NOMATCH); - eptr++; - } - break; + case OP_NOT_WHITESPACE: + if (MAX_255(fc) && (mb->ctypes[fc] & ctype_space) != 0) + RRETURN(MATCH_NOMATCH); + break; - case OP_WHITESPACE: - for (i = 1; i <= min; i++) - { - if (eptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - if (!MAX_255(*eptr) || (mb->ctypes[*eptr] & ctype_space) == 0) - RRETURN(MATCH_NOMATCH); - eptr++; - } - break; + case OP_WHITESPACE: + if (!MAX_255(fc) || (mb->ctypes[fc] & ctype_space) == 0) + RRETURN(MATCH_NOMATCH); + break; - case OP_NOT_WORDCHAR: - for (i = 1; i <= min; i++) - { - if (eptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - if (MAX_255(*eptr) && (mb->ctypes[*eptr] & ctype_word) != 0) - RRETURN(MATCH_NOMATCH); - eptr++; - } - break; + case OP_NOT_WORDCHAR: + if (MAX_255(fc) && (mb->ctypes[fc] & ctype_word) != 0) + RRETURN(MATCH_NOMATCH); + break; - case OP_WORDCHAR: - for (i = 1; i <= min; i++) - { - if (eptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); + case OP_WORDCHAR: + if (!MAX_255(fc) || (mb->ctypes[fc] & ctype_word) == 0) + RRETURN(MATCH_NOMATCH); + break; + + default: + return PCRE2_ERROR_INTERNAL; } - if (!MAX_255(*eptr) || (mb->ctypes[*eptr] & ctype_word) == 0) - RRETURN(MATCH_NOMATCH); - eptr++; } - break; - - default: - RRETURN(PCRE2_ERROR_INTERNAL); } + /* Control never gets here */ } - /* If min = max, continue at the same level without recursing */ - - if (min == max) continue; - - /* If minimizing, we have to test the rest of the pattern before each - subsequent match. Again, separate the UTF-8 case for speed, and also - separate the UCP cases. */ + /* If maximizing, it is worth using inline code for speed, doing the type + test once at the start (i.e. keep it out of the loop). */ - if (minimize) + else { + Lstart_eptr = Feptr; /* Remember where we started */ + #ifdef SUPPORT_UNICODE - if (prop_type >= 0) + if (proptype >= 0) { - switch(prop_type) + switch(proptype) { case PT_ANY: - for (fi = min;; fi++) + for (i = Lmin; i < Lmax; i++) { - RMATCH(eptr, ecode, offset_top, mb, eptrb, RM36); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - if (fi >= max) RRETURN(MATCH_NOMATCH); - if (eptr >= mb->end_subject) + int len = 1; + if (Feptr >= mb->end_subject) { SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); + break; } - GETCHARINCTEST(c, eptr); - if (prop_fail_result) RRETURN(MATCH_NOMATCH); + GETCHARLENTEST(fc, Feptr, len); + if (Lctype == OP_NOTPROP) break; + Feptr+= len; } - /* Control never gets here */ + break; case PT_LAMP: - for (fi = min;; fi++) + for (i = Lmin; i < Lmax; i++) { int chartype; - RMATCH(eptr, ecode, offset_top, mb, eptrb, RM37); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - if (fi >= max) RRETURN(MATCH_NOMATCH); - if (eptr >= mb->end_subject) + int len = 1; + if (Feptr >= mb->end_subject) { SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); + break; } - GETCHARINCTEST(c, eptr); - chartype = UCD_CHARTYPE(c); + GETCHARLENTEST(fc, Feptr, len); + chartype = UCD_CHARTYPE(fc); if ((chartype == ucp_Lu || chartype == ucp_Ll || - chartype == ucp_Lt) == prop_fail_result) - RRETURN(MATCH_NOMATCH); + chartype == ucp_Lt) == (Lctype == OP_NOTPROP)) + break; + Feptr+= len; } - /* Control never gets here */ + break; case PT_GC: - for (fi = min;; fi++) + for (i = Lmin; i < Lmax; i++) { - RMATCH(eptr, ecode, offset_top, mb, eptrb, RM38); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - if (fi >= max) RRETURN(MATCH_NOMATCH); - if (eptr >= mb->end_subject) + int len = 1; + if (Feptr >= mb->end_subject) { SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); + break; } - GETCHARINCTEST(c, eptr); - if ((UCD_CATEGORY(c) == prop_value) == prop_fail_result) - RRETURN(MATCH_NOMATCH); + GETCHARLENTEST(fc, Feptr, len); + if ((UCD_CATEGORY(fc) == Lpropvalue) == (Lctype == OP_NOTPROP)) + break; + Feptr+= len; } - /* Control never gets here */ + break; case PT_PC: - for (fi = min;; fi++) + for (i = Lmin; i < Lmax; i++) { - RMATCH(eptr, ecode, offset_top, mb, eptrb, RM39); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - if (fi >= max) RRETURN(MATCH_NOMATCH); - if (eptr >= mb->end_subject) + int len = 1; + if (Feptr >= mb->end_subject) { SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); + break; } - GETCHARINCTEST(c, eptr); - if ((UCD_CHARTYPE(c) == prop_value) == prop_fail_result) - RRETURN(MATCH_NOMATCH); + GETCHARLENTEST(fc, Feptr, len); + if ((UCD_CHARTYPE(fc) == Lpropvalue) == (Lctype == OP_NOTPROP)) + break; + Feptr+= len; } - /* Control never gets here */ + break; case PT_SC: - for (fi = min;; fi++) + for (i = Lmin; i < Lmax; i++) { - RMATCH(eptr, ecode, offset_top, mb, eptrb, RM40); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - if (fi >= max) RRETURN(MATCH_NOMATCH); - if (eptr >= mb->end_subject) + int len = 1; + if (Feptr >= mb->end_subject) { SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); + break; } - GETCHARINCTEST(c, eptr); - if ((UCD_SCRIPT(c) == prop_value) == prop_fail_result) - RRETURN(MATCH_NOMATCH); + GETCHARLENTEST(fc, Feptr, len); + if ((UCD_SCRIPT(fc) == Lpropvalue) == (Lctype == OP_NOTPROP)) + break; + Feptr+= len; } - /* Control never gets here */ + break; case PT_ALNUM: - for (fi = min;; fi++) + for (i = Lmin; i < Lmax; i++) { int category; - RMATCH(eptr, ecode, offset_top, mb, eptrb, RM59); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - if (fi >= max) RRETURN(MATCH_NOMATCH); - if (eptr >= mb->end_subject) + int len = 1; + if (Feptr >= mb->end_subject) { SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); + break; } - GETCHARINCTEST(c, eptr); - category = UCD_CATEGORY(c); - if ((category == ucp_L || category == ucp_N) == prop_fail_result) - RRETURN(MATCH_NOMATCH); + GETCHARLENTEST(fc, Feptr, len); + category = UCD_CATEGORY(fc); + if ((category == ucp_L || category == ucp_N) == + (Lctype == OP_NOTPROP)) + break; + Feptr+= len; } - /* Control never gets here */ + break; /* Perl space used to exclude VT, but from Perl 5.18 it is included, which means that Perl space and POSIX space are now identical. PCRE @@ -5088,1326 +4047,2098 @@ for (;;) case PT_SPACE: /* Perl space */ case PT_PXSPACE: /* POSIX space */ - for (fi = min;; fi++) + for (i = Lmin; i < Lmax; i++) { - RMATCH(eptr, ecode, offset_top, mb, eptrb, RM61); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - if (fi >= max) RRETURN(MATCH_NOMATCH); - if (eptr >= mb->end_subject) + int len = 1; + if (Feptr >= mb->end_subject) { SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); + break; } - GETCHARINCTEST(c, eptr); - switch(c) + GETCHARLENTEST(fc, Feptr, len); + switch(fc) { HSPACE_CASES: VSPACE_CASES: - if (prop_fail_result) RRETURN(MATCH_NOMATCH); + if (Lctype == OP_NOTPROP) goto ENDLOOP99; /* Break the loop */ break; default: - if ((UCD_CATEGORY(c) == ucp_Z) == prop_fail_result) - RRETURN(MATCH_NOMATCH); + if ((UCD_CATEGORY(fc) == ucp_Z) == (Lctype == OP_NOTPROP)) + goto ENDLOOP99; /* Break the loop */ break; } + Feptr+= len; } - /* Control never gets here */ + ENDLOOP99: + break; case PT_WORD: - for (fi = min;; fi++) + for (i = Lmin; i < Lmax; i++) { int category; - RMATCH(eptr, ecode, offset_top, mb, eptrb, RM62); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - if (fi >= max) RRETURN(MATCH_NOMATCH); - if (eptr >= mb->end_subject) + int len = 1; + if (Feptr >= mb->end_subject) { SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); + break; } - GETCHARINCTEST(c, eptr); - category = UCD_CATEGORY(c); - if ((category == ucp_L || - category == ucp_N || - c == CHAR_UNDERSCORE) - == prop_fail_result) - RRETURN(MATCH_NOMATCH); + GETCHARLENTEST(fc, Feptr, len); + category = UCD_CATEGORY(fc); + if ((category == ucp_L || category == ucp_N || + fc == CHAR_UNDERSCORE) == (Lctype == OP_NOTPROP)) + break; + Feptr+= len; } - /* Control never gets here */ + break; case PT_CLIST: - for (fi = min;; fi++) + for (i = Lmin; i < Lmax; i++) { const uint32_t *cp; - RMATCH(eptr, ecode, offset_top, mb, eptrb, RM67); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - if (fi >= max) RRETURN(MATCH_NOMATCH); - if (eptr >= mb->end_subject) + int len = 1; + if (Feptr >= mb->end_subject) { SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); + break; } - GETCHARINCTEST(c, eptr); - cp = PRIV(ucd_caseless_sets) + prop_value; + GETCHARLENTEST(fc, Feptr, len); + cp = PRIV(ucd_caseless_sets) + Lpropvalue; for (;;) { - if (c < *cp) - { if (prop_fail_result) break; else { RRETURN(MATCH_NOMATCH); } } - if (c == *cp++) - { if (prop_fail_result) { RRETURN(MATCH_NOMATCH); } else break; } + if (fc < *cp) + { if (Lctype == OP_NOTPROP) break; else goto GOT_MAX; } + if (fc == *cp++) + { if (Lctype == OP_NOTPROP) goto GOT_MAX; else break; } } + Feptr += len; } - /* Control never gets here */ + GOT_MAX: + break; case PT_UCNC: - for (fi = min;; fi++) + for (i = Lmin; i < Lmax; i++) { - RMATCH(eptr, ecode, offset_top, mb, eptrb, RM60); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - if (fi >= max) RRETURN(MATCH_NOMATCH); - if (eptr >= mb->end_subject) + int len = 1; + if (Feptr >= mb->end_subject) { SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); + break; } - GETCHARINCTEST(c, eptr); - if ((c == CHAR_DOLLAR_SIGN || c == CHAR_COMMERCIAL_AT || - c == CHAR_GRAVE_ACCENT || (c >= 0xa0 && c <= 0xd7ff) || - c >= 0xe000) == prop_fail_result) - RRETURN(MATCH_NOMATCH); + GETCHARLENTEST(fc, Feptr, len); + if ((fc == CHAR_DOLLAR_SIGN || fc == CHAR_COMMERCIAL_AT || + fc == CHAR_GRAVE_ACCENT || (fc >= 0xa0 && fc <= 0xd7ff) || + fc >= 0xe000) == (Lctype == OP_NOTPROP)) + break; + Feptr += len; } - /* Control never gets here */ + break; - /* This should never occur */ default: - RRETURN(PCRE2_ERROR_INTERNAL); + return PCRE2_ERROR_INTERNAL; + } + + /* Feptr is now past the end of the maximum run */ + + if (reptype == REPTYPE_POS) continue; /* No backtracking */ + + /* After \C in UTF mode, Lstart_eptr might be in the middle of a + Unicode character. Use <= pp to ensure backtracking doesn't go too far. + */ + + for(;;) + { + if (Feptr <= Lstart_eptr) break; + RMATCH(Fecode, RM222); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + Feptr--; + if (utf) BACKCHAR(Feptr); } } - /* Match extended Unicode sequences. We will get here only if the + /* Match extended Unicode grapheme clusters. We will get here only if the support is in the binary; otherwise a compile-time error occurs. */ - else if (ctype == OP_EXTUNI) + else if (Lctype == OP_EXTUNI) { - for (fi = min;; fi++) + for (i = Lmin; i < Lmax; i++) { - RMATCH(eptr, ecode, offset_top, mb, eptrb, RM41); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - if (fi >= max) RRETURN(MATCH_NOMATCH); - if (eptr >= mb->end_subject) + if (Feptr >= mb->end_subject) { SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); + break; } else { int lgb, rgb; - GETCHARINCTEST(c, eptr); - lgb = UCD_GRAPHBREAK(c); - while (eptr < mb->end_subject) + GETCHARINCTEST(fc, Feptr); + lgb = UCD_GRAPHBREAK(fc); + while (Feptr < mb->end_subject) { int len = 1; - if (!utf) c = *eptr; else { GETCHARLEN(c, eptr, len); } - rgb = UCD_GRAPHBREAK(c); + if (!utf) fc = *Feptr; else { GETCHARLEN(fc, Feptr, len); } + rgb = UCD_GRAPHBREAK(fc); if ((PRIV(ucp_gbtable)[lgb] & (1 << rgb)) == 0) break; - lgb = rgb; - eptr += len; + + /* Not breaking between Regional Indicators is allowed only if + there are an even number of preceding RIs. */ + + if (lgb == ucp_gbRegionalIndicator && + rgb == ucp_gbRegionalIndicator) + { + int ricount = 0; + PCRE2_SPTR bptr = Feptr - 1; +#ifdef SUPPORT_UNICODE + if (utf) BACKCHAR(bptr); +#endif + /* bptr is pointing to the left-hand character */ + + while (bptr > mb->start_subject) + { + bptr--; +#ifdef SUPPORT_UNICODE + if (utf) + { + BACKCHAR(bptr); + GETCHAR(fc, bptr); + } + else +#endif + fc = *bptr; + if (UCD_GRAPHBREAK(fc) != ucp_gbRegionalIndicator) break; + ricount++; + } + if ((ricount & 1) != 0) break; /* Grapheme break required */ + } + + /* If Extend follows E_Base[_GAZ] do not update lgb; this allows + any number of Extend before a following E_Modifier. */ + + if (rgb != ucp_gbExtend || + (lgb != ucp_gbE_Base && lgb != ucp_gbE_Base_GAZ)) + lgb = rgb; + + Feptr += len; } } CHECK_PARTIAL(); } + + /* Feptr is now past the end of the maximum run */ + + if (reptype == REPTYPE_POS) continue; /* No backtracking */ + + /* We use <= Lstart_eptr rather than == Lstart_eptr to detect the start + of the run while backtracking because the use of \C in UTF mode can + cause BACKCHAR to move back past Lstart_eptr. This is just palliative; + the use of \C in UTF mode is fraught with danger. */ + + for(;;) + { + int lgb, rgb; + PCRE2_SPTR fptr; + + if (Feptr <= Lstart_eptr) break; /* At start of char run */ + RMATCH(Fecode, RM220); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + + /* Backtracking over an extended grapheme cluster involves inspecting + the previous two characters (if present) to see if a break is + permitted between them. */ + + Feptr--; + if (!utf) fc = *Feptr; else + { + BACKCHAR(Feptr); + GETCHAR(fc, Feptr); + } + rgb = UCD_GRAPHBREAK(fc); + + for (;;) + { + if (Feptr <= Lstart_eptr) break; /* At start of char run */ + fptr = Feptr - 1; + if (!utf) fc = *fptr; else + { + BACKCHAR(fptr); + GETCHAR(fc, fptr); + } + lgb = UCD_GRAPHBREAK(fc); + if ((PRIV(ucp_gbtable)[lgb] & (1 << rgb)) == 0) break; + Feptr = fptr; + rgb = lgb; + } + } } + else -#endif /* SUPPORT_UNICODE */ +#endif /* SUPPORT_UNICODE */ #ifdef SUPPORT_UNICODE if (utf) { - for (fi = min;; fi++) + switch(Lctype) { - RMATCH(eptr, ecode, offset_top, mb, eptrb, RM42); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - if (fi >= max) RRETURN(MATCH_NOMATCH); - if (eptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - if (ctype == OP_ANY && IS_NEWLINE(eptr)) - RRETURN(MATCH_NOMATCH); - GETCHARINC(c, eptr); - switch(ctype) + case OP_ANY: + for (i = Lmin; i < Lmax; i++) { - case OP_ANY: /* This is the non-NL case */ + if (Feptr >= mb->end_subject) + { + SCHECK_PARTIAL(); + break; + } + if (IS_NEWLINE(Feptr)) break; if (mb->partial != 0 && /* Take care with CRLF partial */ - eptr >= mb->end_subject && + Feptr + 1 >= mb->end_subject && NLBLOCK->nltype == NLTYPE_FIXED && NLBLOCK->nllen == 2 && - c == NLBLOCK->nl[0]) + UCHAR21(Feptr) == NLBLOCK->nl[0]) { mb->hitend = TRUE; - if (mb->partial > 1) RRETURN(PCRE2_ERROR_PARTIAL); + if (mb->partial > 1) return PCRE2_ERROR_PARTIAL; } - break; - - case OP_ALLANY: - case OP_ANYBYTE: - break; + Feptr++; + ACROSSCHAR(Feptr < mb->end_subject, *Feptr, Feptr++); + } + break; - case OP_ANYNL: - switch(c) + case OP_ALLANY: + if (Lmax < UINT32_MAX) + { + for (i = Lmin; i < Lmax; i++) { - default: RRETURN(MATCH_NOMATCH); - case CHAR_CR: - if (eptr < mb->end_subject && UCHAR21(eptr) == CHAR_LF) eptr++; - break; - - case CHAR_LF: - break; - - case CHAR_VT: - case CHAR_FF: - case CHAR_NEL: -#ifndef EBCDIC - case 0x2028: - case 0x2029: -#endif /* Not EBCDIC */ - if (mb->bsr_convention == PCRE2_BSR_ANYCRLF) RRETURN(MATCH_NOMATCH); - break; - } - break; - - case OP_NOT_HSPACE: - switch(c) - { - HSPACE_CASES: RRETURN(MATCH_NOMATCH); - default: break; - } - break; - - case OP_HSPACE: - switch(c) - { - HSPACE_CASES: break; - default: RRETURN(MATCH_NOMATCH); - } - break; - - case OP_NOT_VSPACE: - switch(c) - { - VSPACE_CASES: RRETURN(MATCH_NOMATCH); - default: break; - } - break; - - case OP_VSPACE: - switch(c) - { - VSPACE_CASES: break; - default: RRETURN(MATCH_NOMATCH); + if (Feptr >= mb->end_subject) + { + SCHECK_PARTIAL(); + break; + } + Feptr++; + ACROSSCHAR(Feptr < mb->end_subject, *Feptr, Feptr++); } - break; - - case OP_NOT_DIGIT: - if (c < 256 && (mb->ctypes[c] & ctype_digit) != 0) - RRETURN(MATCH_NOMATCH); - break; - - case OP_DIGIT: - if (c >= 256 || (mb->ctypes[c] & ctype_digit) == 0) - RRETURN(MATCH_NOMATCH); - break; - - case OP_NOT_WHITESPACE: - if (c < 256 && (mb->ctypes[c] & ctype_space) != 0) - RRETURN(MATCH_NOMATCH); - break; - - case OP_WHITESPACE: - if (c >= 256 || (mb->ctypes[c] & ctype_space) == 0) - RRETURN(MATCH_NOMATCH); - break; - - case OP_NOT_WORDCHAR: - if (c < 256 && (mb->ctypes[c] & ctype_word) != 0) - RRETURN(MATCH_NOMATCH); - break; - - case OP_WORDCHAR: - if (c >= 256 || (mb->ctypes[c] & ctype_word) == 0) - RRETURN(MATCH_NOMATCH); - break; - - default: - RRETURN(PCRE2_ERROR_INTERNAL); } - } - } - else -#endif - /* Not UTF mode */ - { - for (fi = min;; fi++) - { - RMATCH(eptr, ecode, offset_top, mb, eptrb, RM43); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - if (fi >= max) RRETURN(MATCH_NOMATCH); - if (eptr >= mb->end_subject) + else { + Feptr = mb->end_subject; /* Unlimited UTF-8 repeat */ SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); } - if (ctype == OP_ANY && IS_NEWLINE(eptr)) - RRETURN(MATCH_NOMATCH); - c = *eptr++; - switch(ctype) - { - case OP_ANY: /* This is the non-NL case */ - if (mb->partial != 0 && /* Take care with CRLF partial */ - eptr >= mb->end_subject && - NLBLOCK->nltype == NLTYPE_FIXED && - NLBLOCK->nllen == 2 && - c == NLBLOCK->nl[0]) - { - mb->hitend = TRUE; - if (mb->partial > 1) RRETURN(PCRE2_ERROR_PARTIAL); - } - break; - - case OP_ALLANY: - case OP_ANYBYTE: - break; - - case OP_ANYNL: - switch(c) - { - default: RRETURN(MATCH_NOMATCH); - case CHAR_CR: - if (eptr < mb->end_subject && *eptr == CHAR_LF) eptr++; - break; - - case CHAR_LF: - break; + break; - case CHAR_VT: - case CHAR_FF: - case CHAR_NEL: -#if PCRE2_CODE_UNIT_WIDTH != 8 - case 0x2028: - case 0x2029: -#endif - if (mb->bsr_convention == PCRE2_BSR_ANYCRLF) RRETURN(MATCH_NOMATCH); - break; - } - break; + /* The "byte" (i.e. "code unit") case is the same as non-UTF */ - case OP_NOT_HSPACE: - switch(c) - { - default: break; - HSPACE_BYTE_CASES: -#if PCRE2_CODE_UNIT_WIDTH != 8 - HSPACE_MULTIBYTE_CASES: -#endif - RRETURN(MATCH_NOMATCH); - } - break; + case OP_ANYBYTE: + fc = Lmax - Lmin; + if (fc > (uint32_t)(mb->end_subject - Feptr)) + { + Feptr = mb->end_subject; + SCHECK_PARTIAL(); + } + else Feptr += fc; + break; - case OP_HSPACE: - switch(c) + case OP_ANYNL: + for (i = Lmin; i < Lmax; i++) + { + int len = 1; + if (Feptr >= mb->end_subject) { - default: RRETURN(MATCH_NOMATCH); - HSPACE_BYTE_CASES: -#if PCRE2_CODE_UNIT_WIDTH != 8 - HSPACE_MULTIBYTE_CASES: -#endif + SCHECK_PARTIAL(); break; } - break; - - case OP_NOT_VSPACE: - switch(c) + GETCHARLEN(fc, Feptr, len); + if (fc == CHAR_CR) { - default: break; - VSPACE_BYTE_CASES: -#if PCRE2_CODE_UNIT_WIDTH != 8 - VSPACE_MULTIBYTE_CASES: -#endif - RRETURN(MATCH_NOMATCH); + if (++Feptr >= mb->end_subject) break; + if (UCHAR21(Feptr) == CHAR_LF) Feptr++; } - break; - - case OP_VSPACE: - switch(c) + else { - default: RRETURN(MATCH_NOMATCH); - VSPACE_BYTE_CASES: -#if PCRE2_CODE_UNIT_WIDTH != 8 - VSPACE_MULTIBYTE_CASES: -#endif - break; + if (fc != CHAR_LF && + (mb->bsr_convention == PCRE2_BSR_ANYCRLF || + (fc != CHAR_VT && fc != CHAR_FF && fc != CHAR_NEL +#ifndef EBCDIC + && fc != 0x2028 && fc != 0x2029 +#endif /* Not EBCDIC */ + ))) + break; + Feptr += len; } - break; - - case OP_NOT_DIGIT: - if (MAX_255(c) && (mb->ctypes[c] & ctype_digit) != 0) RRETURN(MATCH_NOMATCH); - break; - - case OP_DIGIT: - if (!MAX_255(c) || (mb->ctypes[c] & ctype_digit) == 0) RRETURN(MATCH_NOMATCH); - break; - - case OP_NOT_WHITESPACE: - if (MAX_255(c) && (mb->ctypes[c] & ctype_space) != 0) RRETURN(MATCH_NOMATCH); - break; - - case OP_WHITESPACE: - if (!MAX_255(c) || (mb->ctypes[c] & ctype_space) == 0) RRETURN(MATCH_NOMATCH); - break; - - case OP_NOT_WORDCHAR: - if (MAX_255(c) && (mb->ctypes[c] & ctype_word) != 0) RRETURN(MATCH_NOMATCH); - break; - - case OP_WORDCHAR: - if (!MAX_255(c) || (mb->ctypes[c] & ctype_word) == 0) RRETURN(MATCH_NOMATCH); - break; - - default: - RRETURN(PCRE2_ERROR_INTERNAL); } - } - } - /* Control never gets here */ - } - - /* If maximizing, it is worth using inline code for speed, doing the type - test once at the start (i.e. keep it out of the loop). Again, keep the - UTF-8 and UCP stuff separate. */ - - else - { - pp = eptr; /* Remember where we started */ + break; -#ifdef SUPPORT_UNICODE - if (prop_type >= 0) - { - switch(prop_type) - { - case PT_ANY: - for (i = min; i < max; i++) + case OP_NOT_HSPACE: + case OP_HSPACE: + for (i = Lmin; i < Lmax; i++) { + BOOL gotspace; int len = 1; - if (eptr >= mb->end_subject) + if (Feptr >= mb->end_subject) { SCHECK_PARTIAL(); break; } - GETCHARLENTEST(c, eptr, len); - if (prop_fail_result) break; - eptr+= len; + GETCHARLEN(fc, Feptr, len); + switch(fc) + { + HSPACE_CASES: gotspace = TRUE; break; + default: gotspace = FALSE; break; + } + if (gotspace == (Lctype == OP_NOT_HSPACE)) break; + Feptr += len; } break; - case PT_LAMP: - for (i = min; i < max; i++) + case OP_NOT_VSPACE: + case OP_VSPACE: + for (i = Lmin; i < Lmax; i++) { - int chartype; + BOOL gotspace; int len = 1; - if (eptr >= mb->end_subject) + if (Feptr >= mb->end_subject) { SCHECK_PARTIAL(); break; } - GETCHARLENTEST(c, eptr, len); - chartype = UCD_CHARTYPE(c); - if ((chartype == ucp_Lu || - chartype == ucp_Ll || - chartype == ucp_Lt) == prop_fail_result) - break; - eptr+= len; + GETCHARLEN(fc, Feptr, len); + switch(fc) + { + VSPACE_CASES: gotspace = TRUE; break; + default: gotspace = FALSE; break; + } + if (gotspace == (Lctype == OP_NOT_VSPACE)) break; + Feptr += len; } break; - case PT_GC: - for (i = min; i < max; i++) + case OP_NOT_DIGIT: + for (i = Lmin; i < Lmax; i++) { int len = 1; - if (eptr >= mb->end_subject) + if (Feptr >= mb->end_subject) { SCHECK_PARTIAL(); break; } - GETCHARLENTEST(c, eptr, len); - if ((UCD_CATEGORY(c) == prop_value) == prop_fail_result) break; - eptr+= len; + GETCHARLEN(fc, Feptr, len); + if (fc < 256 && (mb->ctypes[fc] & ctype_digit) != 0) break; + Feptr+= len; } break; - case PT_PC: - for (i = min; i < max; i++) + case OP_DIGIT: + for (i = Lmin; i < Lmax; i++) { int len = 1; - if (eptr >= mb->end_subject) + if (Feptr >= mb->end_subject) { SCHECK_PARTIAL(); break; } - GETCHARLENTEST(c, eptr, len); - if ((UCD_CHARTYPE(c) == prop_value) == prop_fail_result) break; - eptr+= len; + GETCHARLEN(fc, Feptr, len); + if (fc >= 256 ||(mb->ctypes[fc] & ctype_digit) == 0) break; + Feptr+= len; } break; - case PT_SC: - for (i = min; i < max; i++) + case OP_NOT_WHITESPACE: + for (i = Lmin; i < Lmax; i++) { int len = 1; - if (eptr >= mb->end_subject) + if (Feptr >= mb->end_subject) { SCHECK_PARTIAL(); break; } - GETCHARLENTEST(c, eptr, len); - if ((UCD_SCRIPT(c) == prop_value) == prop_fail_result) break; - eptr+= len; + GETCHARLEN(fc, Feptr, len); + if (fc < 256 && (mb->ctypes[fc] & ctype_space) != 0) break; + Feptr+= len; } break; - case PT_ALNUM: - for (i = min; i < max; i++) + case OP_WHITESPACE: + for (i = Lmin; i < Lmax; i++) { - int category; int len = 1; - if (eptr >= mb->end_subject) + if (Feptr >= mb->end_subject) { SCHECK_PARTIAL(); break; } - GETCHARLENTEST(c, eptr, len); - category = UCD_CATEGORY(c); - if ((category == ucp_L || category == ucp_N) == prop_fail_result) - break; - eptr+= len; + GETCHARLEN(fc, Feptr, len); + if (fc >= 256 ||(mb->ctypes[fc] & ctype_space) == 0) break; + Feptr+= len; } break; - /* Perl space used to exclude VT, but from Perl 5.18 it is included, - which means that Perl space and POSIX space are now identical. PCRE - was changed at release 8.34. */ - - case PT_SPACE: /* Perl space */ - case PT_PXSPACE: /* POSIX space */ - for (i = min; i < max; i++) + case OP_NOT_WORDCHAR: + for (i = Lmin; i < Lmax; i++) { int len = 1; - if (eptr >= mb->end_subject) + if (Feptr >= mb->end_subject) { SCHECK_PARTIAL(); break; } - GETCHARLENTEST(c, eptr, len); - switch(c) - { - HSPACE_CASES: - VSPACE_CASES: - if (prop_fail_result) goto ENDLOOP99; /* Break the loop */ - break; - - default: - if ((UCD_CATEGORY(c) == ucp_Z) == prop_fail_result) - goto ENDLOOP99; /* Break the loop */ - break; - } - eptr+= len; + GETCHARLEN(fc, Feptr, len); + if (fc < 256 && (mb->ctypes[fc] & ctype_word) != 0) break; + Feptr+= len; } - ENDLOOP99: break; - case PT_WORD: - for (i = min; i < max; i++) + case OP_WORDCHAR: + for (i = Lmin; i < Lmax; i++) { - int category; int len = 1; - if (eptr >= mb->end_subject) + if (Feptr >= mb->end_subject) { SCHECK_PARTIAL(); break; } - GETCHARLENTEST(c, eptr, len); - category = UCD_CATEGORY(c); - if ((category == ucp_L || category == ucp_N || - c == CHAR_UNDERSCORE) == prop_fail_result) - break; - eptr+= len; - } - break; - - case PT_CLIST: - for (i = min; i < max; i++) - { - const uint32_t *cp; - int len = 1; - if (eptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - break; - } - GETCHARLENTEST(c, eptr, len); - cp = PRIV(ucd_caseless_sets) + prop_value; - for (;;) - { - if (c < *cp) - { if (prop_fail_result) break; else goto GOT_MAX; } - if (c == *cp++) - { if (prop_fail_result) goto GOT_MAX; else break; } - } - eptr += len; - } - GOT_MAX: - break; - - case PT_UCNC: - for (i = min; i < max; i++) - { - int len = 1; - if (eptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - break; - } - GETCHARLENTEST(c, eptr, len); - if ((c == CHAR_DOLLAR_SIGN || c == CHAR_COMMERCIAL_AT || - c == CHAR_GRAVE_ACCENT || (c >= 0xa0 && c <= 0xd7ff) || - c >= 0xe000) == prop_fail_result) - break; - eptr += len; + GETCHARLEN(fc, Feptr, len); + if (fc >= 256 || (mb->ctypes[fc] & ctype_word) == 0) break; + Feptr+= len; } break; default: - RRETURN(PCRE2_ERROR_INTERNAL); - } - - /* eptr is now past the end of the maximum run */ - - if (possessive) continue; /* No backtracking */ - - /* After \C in UTF mode, pp might be in the middle of a Unicode - character. Use <= pp to ensure backtracking doesn't go too far. */ - - for(;;) - { - if (eptr <= pp) goto TAIL_RECURSE; - RMATCH(eptr, ecode, offset_top, mb, eptrb, RM44); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - eptr--; - if (utf) BACKCHAR(eptr); - } - } - - /* Match extended Unicode grapheme clusters. We will get here only if the - support is in the binary; otherwise a compile-time error occurs. */ - - else if (ctype == OP_EXTUNI) - { - for (i = min; i < max; i++) - { - if (eptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - break; - } - else - { - int lgb, rgb; - GETCHARINCTEST(c, eptr); - lgb = UCD_GRAPHBREAK(c); - while (eptr < mb->end_subject) - { - int len = 1; - if (!utf) c = *eptr; else { GETCHARLEN(c, eptr, len); } - rgb = UCD_GRAPHBREAK(c); - if ((PRIV(ucp_gbtable)[lgb] & (1 << rgb)) == 0) break; - lgb = rgb; - eptr += len; - } - } - CHECK_PARTIAL(); + return PCRE2_ERROR_INTERNAL; } - /* eptr is now past the end of the maximum run */ + if (reptype == REPTYPE_POS) continue; /* No backtracking */ - if (possessive) continue; /* No backtracking */ - - /* We use <= pp rather than == pp to detect the start of the run while - backtracking because the use of \C in UTF mode can cause BACKCHAR to - move back past pp. This is just palliative; the use of \C in UTF mode - is fraught with danger. */ + /* After \C in UTF mode, Lstart_eptr might be in the middle of a + Unicode character. Use <= Lstart_eptr to ensure backtracking doesn't go + too far. */ for(;;) { - int lgb, rgb; - PCRE2_SPTR fptr; - - if (eptr <= pp) goto TAIL_RECURSE; /* At start of char run */ - RMATCH(eptr, ecode, offset_top, mb, eptrb, RM45); + if (Feptr <= Lstart_eptr) break; + RMATCH(Fecode, RM221); if (rrc != MATCH_NOMATCH) RRETURN(rrc); - - /* Backtracking over an extended grapheme cluster involves inspecting - the previous two characters (if present) to see if a break is - permitted between them. */ - - eptr--; - if (!utf) c = *eptr; else - { - BACKCHAR(eptr); - GETCHAR(c, eptr); - } - rgb = UCD_GRAPHBREAK(c); - - for (;;) - { - if (eptr <= pp) goto TAIL_RECURSE; /* At start of char run */ - fptr = eptr - 1; - if (!utf) c = *fptr; else - { - BACKCHAR(fptr); - GETCHAR(c, fptr); - } - lgb = UCD_GRAPHBREAK(c); - if ((PRIV(ucp_gbtable)[lgb] & (1 << rgb)) == 0) break; - eptr = fptr; - rgb = lgb; - } + Feptr--; + BACKCHAR(Feptr); + if (Lctype == OP_ANYNL && Feptr > Lstart_eptr && + UCHAR21(Feptr) == CHAR_NL && UCHAR21(Feptr - 1) == CHAR_CR) + Feptr--; } } - else -#endif /* SUPPORT_UNICODE */ +#endif /* SUPPORT_UNICODE */ -#ifdef SUPPORT_UNICODE - if (utf) + /* Not UTF mode */ { - switch(ctype) + switch(Lctype) { case OP_ANY: - for (i = min; i < max; i++) + for (i = Lmin; i < Lmax; i++) { - if (eptr >= mb->end_subject) + if (Feptr >= mb->end_subject) { SCHECK_PARTIAL(); break; } - if (IS_NEWLINE(eptr)) break; + if (IS_NEWLINE(Feptr)) break; if (mb->partial != 0 && /* Take care with CRLF partial */ - eptr + 1 >= mb->end_subject && + Feptr + 1 >= mb->end_subject && NLBLOCK->nltype == NLTYPE_FIXED && NLBLOCK->nllen == 2 && - UCHAR21(eptr) == NLBLOCK->nl[0]) + *Feptr == NLBLOCK->nl[0]) { mb->hitend = TRUE; - if (mb->partial > 1) RRETURN(PCRE2_ERROR_PARTIAL); + if (mb->partial > 1) return PCRE2_ERROR_PARTIAL; } - eptr++; - ACROSSCHAR(eptr < mb->end_subject, *eptr, eptr++); + Feptr++; } break; case OP_ALLANY: - if (max < INT_MAX) - { - for (i = min; i < max; i++) - { - if (eptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - break; - } - eptr++; - ACROSSCHAR(eptr < mb->end_subject, *eptr, eptr++); - } - } - else - { - eptr = mb->end_subject; /* Unlimited UTF-8 repeat */ - SCHECK_PARTIAL(); - } - break; - - /* The byte case is the same as non-UTF8 */ - case OP_ANYBYTE: - c = max - min; - if (c > (uint32_t)(mb->end_subject - eptr)) + fc = Lmax - Lmin; + if (fc > (uint32_t)(mb->end_subject - Feptr)) { - eptr = mb->end_subject; + Feptr = mb->end_subject; SCHECK_PARTIAL(); } - else eptr += c; + else Feptr += fc; break; case OP_ANYNL: - for (i = min; i < max; i++) + for (i = Lmin; i < Lmax; i++) { - int len = 1; - if (eptr >= mb->end_subject) + if (Feptr >= mb->end_subject) { SCHECK_PARTIAL(); break; } - GETCHARLEN(c, eptr, len); - if (c == CHAR_CR) + fc = *Feptr; + if (fc == CHAR_CR) { - if (++eptr >= mb->end_subject) break; - if (UCHAR21(eptr) == CHAR_LF) eptr++; + if (++Feptr >= mb->end_subject) break; + if (*Feptr == CHAR_LF) Feptr++; } else { - if (c != CHAR_LF && - (mb->bsr_convention == PCRE2_BSR_ANYCRLF || - (c != CHAR_VT && c != CHAR_FF && c != CHAR_NEL -#ifndef EBCDIC - && c != 0x2028 && c != 0x2029 -#endif /* Not EBCDIC */ - ))) - break; - eptr += len; + if (fc != CHAR_LF && (mb->bsr_convention == PCRE2_BSR_ANYCRLF || + (fc != CHAR_VT && fc != CHAR_FF && fc != CHAR_NEL +#if PCRE2_CODE_UNIT_WIDTH != 8 + && fc != 0x2028 && fc != 0x2029 +#endif + ))) break; + Feptr++; } } break; case OP_NOT_HSPACE: + for (i = Lmin; i < Lmax; i++) + { + if (Feptr >= mb->end_subject) + { + SCHECK_PARTIAL(); + break; + } + switch(*Feptr) + { + default: Feptr++; break; + HSPACE_BYTE_CASES: +#if PCRE2_CODE_UNIT_WIDTH != 8 + HSPACE_MULTIBYTE_CASES: +#endif + goto ENDLOOP00; + } + } + ENDLOOP00: + break; + case OP_HSPACE: - for (i = min; i < max; i++) + for (i = Lmin; i < Lmax; i++) { - BOOL gotspace; - int len = 1; - if (eptr >= mb->end_subject) + if (Feptr >= mb->end_subject) { SCHECK_PARTIAL(); break; } - GETCHARLEN(c, eptr, len); - switch(c) + switch(*Feptr) { - HSPACE_CASES: gotspace = TRUE; break; - default: gotspace = FALSE; break; + default: goto ENDLOOP01; + HSPACE_BYTE_CASES: +#if PCRE2_CODE_UNIT_WIDTH != 8 + HSPACE_MULTIBYTE_CASES: +#endif + Feptr++; break; } - if (gotspace == (ctype == OP_NOT_HSPACE)) break; - eptr += len; } + ENDLOOP01: break; case OP_NOT_VSPACE: + for (i = Lmin; i < Lmax; i++) + { + if (Feptr >= mb->end_subject) + { + SCHECK_PARTIAL(); + break; + } + switch(*Feptr) + { + default: Feptr++; break; + VSPACE_BYTE_CASES: +#if PCRE2_CODE_UNIT_WIDTH != 8 + VSPACE_MULTIBYTE_CASES: +#endif + goto ENDLOOP02; + } + } + ENDLOOP02: + break; + case OP_VSPACE: - for (i = min; i < max; i++) + for (i = Lmin; i < Lmax; i++) { - BOOL gotspace; - int len = 1; - if (eptr >= mb->end_subject) + if (Feptr >= mb->end_subject) { SCHECK_PARTIAL(); break; } - GETCHARLEN(c, eptr, len); - switch(c) + switch(*Feptr) { - VSPACE_CASES: gotspace = TRUE; break; - default: gotspace = FALSE; break; + default: goto ENDLOOP03; + VSPACE_BYTE_CASES: +#if PCRE2_CODE_UNIT_WIDTH != 8 + VSPACE_MULTIBYTE_CASES: +#endif + Feptr++; break; } - if (gotspace == (ctype == OP_NOT_VSPACE)) break; - eptr += len; } + ENDLOOP03: break; case OP_NOT_DIGIT: - for (i = min; i < max; i++) + for (i = Lmin; i < Lmax; i++) { - int len = 1; - if (eptr >= mb->end_subject) + if (Feptr >= mb->end_subject) { SCHECK_PARTIAL(); break; } - GETCHARLEN(c, eptr, len); - if (c < 256 && (mb->ctypes[c] & ctype_digit) != 0) break; - eptr+= len; + if (MAX_255(*Feptr) && (mb->ctypes[*Feptr] & ctype_digit) != 0) + break; + Feptr++; } break; case OP_DIGIT: - for (i = min; i < max; i++) + for (i = Lmin; i < Lmax; i++) { - int len = 1; - if (eptr >= mb->end_subject) + if (Feptr >= mb->end_subject) { SCHECK_PARTIAL(); break; } - GETCHARLEN(c, eptr, len); - if (c >= 256 ||(mb->ctypes[c] & ctype_digit) == 0) break; - eptr+= len; + if (!MAX_255(*Feptr) || (mb->ctypes[*Feptr] & ctype_digit) == 0) + break; + Feptr++; } break; case OP_NOT_WHITESPACE: - for (i = min; i < max; i++) + for (i = Lmin; i < Lmax; i++) { - int len = 1; - if (eptr >= mb->end_subject) + if (Feptr >= mb->end_subject) { SCHECK_PARTIAL(); break; } - GETCHARLEN(c, eptr, len); - if (c < 256 && (mb->ctypes[c] & ctype_space) != 0) break; - eptr+= len; + if (MAX_255(*Feptr) && (mb->ctypes[*Feptr] & ctype_space) != 0) + break; + Feptr++; } break; case OP_WHITESPACE: - for (i = min; i < max; i++) + for (i = Lmin; i < Lmax; i++) { - int len = 1; - if (eptr >= mb->end_subject) + if (Feptr >= mb->end_subject) { SCHECK_PARTIAL(); break; } - GETCHARLEN(c, eptr, len); - if (c >= 256 ||(mb->ctypes[c] & ctype_space) == 0) break; - eptr+= len; + if (!MAX_255(*Feptr) || (mb->ctypes[*Feptr] & ctype_space) == 0) + break; + Feptr++; } break; case OP_NOT_WORDCHAR: - for (i = min; i < max; i++) + for (i = Lmin; i < Lmax; i++) { - int len = 1; - if (eptr >= mb->end_subject) + if (Feptr >= mb->end_subject) { SCHECK_PARTIAL(); break; } - GETCHARLEN(c, eptr, len); - if (c < 256 && (mb->ctypes[c] & ctype_word) != 0) break; - eptr+= len; + if (MAX_255(*Feptr) && (mb->ctypes[*Feptr] & ctype_word) != 0) + break; + Feptr++; } break; case OP_WORDCHAR: - for (i = min; i < max; i++) + for (i = Lmin; i < Lmax; i++) { - int len = 1; - if (eptr >= mb->end_subject) + if (Feptr >= mb->end_subject) { SCHECK_PARTIAL(); break; } - GETCHARLEN(c, eptr, len); - if (c >= 256 || (mb->ctypes[c] & ctype_word) == 0) break; - eptr+= len; + if (!MAX_255(*Feptr) || (mb->ctypes[*Feptr] & ctype_word) == 0) + break; + Feptr++; } break; default: - RRETURN(PCRE2_ERROR_INTERNAL); + return PCRE2_ERROR_INTERNAL; } - if (possessive) continue; /* No backtracking */ + if (reptype == REPTYPE_POS) continue; /* No backtracking */ - /* After \C in UTF mode, pp might be in the middle of a Unicode - character. Use <= pp to ensure backtracking doesn't go too far. */ - - for(;;) + for (;;) { - if (eptr <= pp) goto TAIL_RECURSE; - RMATCH(eptr, ecode, offset_top, mb, eptrb, RM46); + if (Feptr == Lstart_eptr) break; + RMATCH(Fecode, RM34); if (rrc != MATCH_NOMATCH) RRETURN(rrc); - eptr--; - BACKCHAR(eptr); - if (ctype == OP_ANYNL && eptr > pp && UCHAR21(eptr) == CHAR_NL && - UCHAR21(eptr - 1) == CHAR_CR) eptr--; + Feptr--; + if (Lctype == OP_ANYNL && Feptr > Lstart_eptr && *Feptr == CHAR_LF && + Feptr[-1] == CHAR_CR) Feptr--; } } - else -#endif /* SUPPORT_UNICODE */ - /* Not UTF mode */ - { - switch(ctype) - { - case OP_ANY: - for (i = min; i < max; i++) - { - if (eptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - break; - } - if (IS_NEWLINE(eptr)) break; - if (mb->partial != 0 && /* Take care with CRLF partial */ - eptr + 1 >= mb->end_subject && - NLBLOCK->nltype == NLTYPE_FIXED && - NLBLOCK->nllen == 2 && - *eptr == NLBLOCK->nl[0]) - { - mb->hitend = TRUE; - if (mb->partial > 1) RRETURN(PCRE2_ERROR_PARTIAL); - } - eptr++; - } - break; + } + break; /* End of repeat character type processing */ - case OP_ALLANY: - case OP_ANYBYTE: - c = max - min; - if (c > (uint32_t)(mb->end_subject - eptr)) - { - eptr = mb->end_subject; - SCHECK_PARTIAL(); - } - else eptr += c; - break; +#undef Lstart_eptr +#undef Lmin +#undef Lmax +#undef Lctype +#undef Lpropvalue - case OP_ANYNL: - for (i = min; i < max; i++) - { - if (eptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - break; - } - c = *eptr; - if (c == CHAR_CR) - { - if (++eptr >= mb->end_subject) break; - if (*eptr == CHAR_LF) eptr++; - } - else - { - if (c != CHAR_LF && (mb->bsr_convention == PCRE2_BSR_ANYCRLF || - (c != CHAR_VT && c != CHAR_FF && c != CHAR_NEL -#if PCRE2_CODE_UNIT_WIDTH != 8 - && c != 0x2028 && c != 0x2029 -#endif - ))) break; - eptr++; - } - } - break; - case OP_NOT_HSPACE: - for (i = min; i < max; i++) - { - if (eptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - break; - } - switch(*eptr) - { - default: eptr++; break; - HSPACE_BYTE_CASES: -#if PCRE2_CODE_UNIT_WIDTH != 8 - HSPACE_MULTIBYTE_CASES: -#endif - goto ENDLOOP00; - } - } - ENDLOOP00: - break; + /* ===================================================================== */ + /* Match a back reference, possibly repeatedly. Look past the end of the + item to see if there is repeat information following. The OP_REF and + OP_REFI opcodes are used for a reference to a numbered group or to a + non-duplicated named group. For a duplicated named group, OP_DNREF and + OP_DNREFI are used. In this case we must scan the list of groups to which + the name refers, and use the first one that is set. */ + +#define Lmin F->temp_32[0] +#define Lmax F->temp_32[1] +#define Lcaseless F->temp_32[2] +#define Lstart F->temp_sptr[0] +#define Loffset F->temp_size - case OP_HSPACE: - for (i = min; i < max; i++) - { - if (eptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - break; - } - switch(*eptr) - { - default: goto ENDLOOP01; - HSPACE_BYTE_CASES: -#if PCRE2_CODE_UNIT_WIDTH != 8 - HSPACE_MULTIBYTE_CASES: -#endif - eptr++; break; - } - } - ENDLOOP01: - break; + case OP_DNREF: + case OP_DNREFI: + Lcaseless = (Fop == OP_DNREFI); + { + int count = GET2(Fecode, 1+IMM2_SIZE); + PCRE2_SPTR slot = mb->name_table + GET2(Fecode, 1) * mb->name_entry_size; + Fecode += 1 + 2*IMM2_SIZE; - case OP_NOT_VSPACE: - for (i = min; i < max; i++) - { - if (eptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - break; - } - switch(*eptr) - { - default: eptr++; break; - VSPACE_BYTE_CASES: -#if PCRE2_CODE_UNIT_WIDTH != 8 - VSPACE_MULTIBYTE_CASES: -#endif - goto ENDLOOP02; - } - } - ENDLOOP02: - break; + while (count-- > 0) + { + Loffset = (GET2(slot, 0) << 1) - 2; + if (Loffset < Foffset_top && Fovector[Loffset] != PCRE2_UNSET) break; + slot += mb->name_entry_size; + } + } + goto REF_REPEAT; - case OP_VSPACE: - for (i = min; i < max; i++) - { - if (eptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - break; - } - switch(*eptr) - { - default: goto ENDLOOP03; - VSPACE_BYTE_CASES: -#if PCRE2_CODE_UNIT_WIDTH != 8 - VSPACE_MULTIBYTE_CASES: -#endif - eptr++; break; - } - } - ENDLOOP03: - break; + case OP_REF: + case OP_REFI: + Lcaseless = (Fop == OP_REFI); + Loffset = (GET2(Fecode, 1) << 1) - 2; + Fecode += 1 + IMM2_SIZE; - case OP_NOT_DIGIT: - for (i = min; i < max; i++) + /* Set up for repetition, or handle the non-repeated case. The maximum and + minimum must be in the heap frame, but as they are short-term values, we + use temporary fields. */ + + REF_REPEAT: + switch (*Fecode) + { + case OP_CRSTAR: + case OP_CRMINSTAR: + case OP_CRPLUS: + case OP_CRMINPLUS: + case OP_CRQUERY: + case OP_CRMINQUERY: + fc = *Fecode++ - OP_CRSTAR; + Lmin = rep_min[fc]; + Lmax = rep_max[fc]; + reptype = rep_typ[fc]; + break; + + case OP_CRRANGE: + case OP_CRMINRANGE: + Lmin = GET2(Fecode, 1); + Lmax = GET2(Fecode, 1 + IMM2_SIZE); + reptype = rep_typ[*Fecode - OP_CRSTAR]; + if (Lmax == 0) Lmax = UINT32_MAX; /* Max 0 => infinity */ + Fecode += 1 + 2 * IMM2_SIZE; + break; + + default: /* No repeat follows */ + { + rrc = match_ref(Loffset, Lcaseless, F, mb, &length); + if (rrc != 0) + { + if (rrc > 0) Feptr = mb->end_subject; /* Partial match */ + CHECK_PARTIAL(); + RRETURN(MATCH_NOMATCH); + } + } + Feptr += length; + continue; /* With the main loop */ + } + + /* Handle repeated back references. If a set group has length zero, just + continue with the main loop, because it matches however many times. For an + unset reference, if the minimum is zero, we can also just continue. We can + also continue if PCRE2_MATCH_UNSET_BACKREF is set, because this makes unset + group behave as a zero-length group. For any other unset cases, carrying + on will result in NOMATCH. */ + + if (Loffset < Foffset_top && Fovector[Loffset] != PCRE2_UNSET) + { + if (Fovector[Loffset] == Fovector[Loffset + 1]) continue; + } + else /* Group is not set */ + { + if (Lmin == 0 || (mb->poptions & PCRE2_MATCH_UNSET_BACKREF) != 0) + continue; + } + + /* First, ensure the minimum number of matches are present. */ + + for (i = 1; i <= Lmin; i++) + { + PCRE2_SIZE slength; + rrc = match_ref(Loffset, Lcaseless, F, mb, &slength); + if (rrc != 0) + { + if (rrc > 0) Feptr = mb->end_subject; /* Partial match */ + CHECK_PARTIAL(); + RRETURN(MATCH_NOMATCH); + } + Feptr += slength; + } + + /* If min = max, we are done. They are not both allowed to be zero. */ + + if (Lmin == Lmax) continue; + + /* If minimizing, keep trying and advancing the pointer. */ + + if (reptype == REPTYPE_MIN) + { + for (;;) + { + PCRE2_SIZE slength; + RMATCH(Fecode, RM20); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH); + rrc = match_ref(Loffset, Lcaseless, F, mb, &slength); + if (rrc != 0) + { + if (rrc > 0) Feptr = mb->end_subject; /* Partial match */ + CHECK_PARTIAL(); + RRETURN(MATCH_NOMATCH); + } + Feptr += slength; + } + /* Control never gets here */ + } + + /* If maximizing, find the longest string and work backwards, as long as + the matched lengths for each iteration are the same. */ + + else + { + BOOL samelengths = TRUE; + Lstart = Feptr; /* Starting position */ + Flength = Fovector[Loffset+1] - Fovector[Loffset]; + + for (i = Lmin; i < Lmax; i++) + { + PCRE2_SIZE slength; + rrc = match_ref(Loffset, Lcaseless, F, mb, &slength); + if (rrc != 0) + { + /* Can't use CHECK_PARTIAL because we don't want to update Feptr in + the soft partial matching case. */ + + if (rrc > 0 && mb->partial != 0 && + mb->end_subject > mb->start_used_ptr) { - if (eptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - break; - } - if (MAX_255(*eptr) && (mb->ctypes[*eptr] & ctype_digit) != 0) break; - eptr++; + mb->hitend = TRUE; + if (mb->partial > 1) return PCRE2_ERROR_PARTIAL; } break; + } - case OP_DIGIT: - for (i = min; i < max; i++) + if (slength != Flength) samelengths = FALSE; + Feptr += slength; + } + + /* If the length matched for each repetition is the same as the length of + the captured group, we can easily work backwards. This is the normal + case. However, in caseless UTF-8 mode there are pairs of case-equivalent + characters whose lengths (in terms of code units) differ. However, this + is very rare, so we handle it by re-matching fewer and fewer times. */ + + if (samelengths) + { + while (Feptr >= Lstart) + { + RMATCH(Fecode, RM21); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + Feptr -= Flength; + } + } + + /* The rare case of non-matching lengths. Re-scan the repetition for each + iteration. We know that match_ref() will succeed every time. */ + + else + { + Lmax = i; + for (;;) + { + RMATCH(Fecode, RM22); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + if (Feptr == Lstart) break; /* Failed after minimal repetition */ + Feptr = Lstart; + Lmax--; + for (i = Lmin; i < Lmax; i++) { - if (eptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - break; - } - if (!MAX_255(*eptr) || (mb->ctypes[*eptr] & ctype_digit) == 0) break; - eptr++; + PCRE2_SIZE slength; + (void)match_ref(Loffset, Lcaseless, F, mb, &slength); + Feptr += slength; } + } + } + + RRETURN(MATCH_NOMATCH); + } + /* Control never gets here */ + +#undef Lcaseless +#undef Lmin +#undef Lmax +#undef Lstart +#undef Loffset + + + +/* ========================================================================= */ +/* Opcodes for the start of various parenthesized items */ +/* ========================================================================= */ + + /* In all cases, if the result of RMATCH() is MATCH_THEN, check whether the + (*THEN) is within the current branch by comparing the address of OP_THEN + that is passed back with the end of the branch. If (*THEN) is within the + current branch, and the branch is one of two or more alternatives (it + either starts or ends with OP_ALT), we have reached the limit of THEN's + action, so convert the return code to NOMATCH, which will cause normal + backtracking to happen from now on. Otherwise, THEN is passed back to an + outer alternative. This implements Perl's treatment of parenthesized + groups, where a group not containing | does not affect the current + alternative, that is, (X) is NOT the same as (X|(*F)). */ + + + /* ===================================================================== */ + /* BRAZERO, BRAMINZERO and SKIPZERO occur just before a non-possessive + bracket group, indicating that it may occur zero times. It may repeat + infinitely, or not at all - i.e. it could be ()* or ()? or even (){0} in + the pattern. Brackets with fixed upper repeat limits are compiled as a + number of copies, with the optional ones preceded by BRAZERO or BRAMINZERO. + Possessive groups with possible zero repeats are preceded by BRAPOSZERO. */ + +#define Lnext_ecode F->temp_sptr[0] + + case OP_BRAZERO: + Lnext_ecode = Fecode + 1; + RMATCH(Lnext_ecode, RM9); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + do Lnext_ecode += GET(Lnext_ecode, 1); while (*Lnext_ecode == OP_ALT); + Fecode = Lnext_ecode + 1 + LINK_SIZE; + break; + + case OP_BRAMINZERO: + Lnext_ecode = Fecode + 1; + do Lnext_ecode += GET(Lnext_ecode, 1); while (*Lnext_ecode == OP_ALT); + RMATCH(Lnext_ecode + 1 + LINK_SIZE, RM10); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + Fecode++; + break; + +#undef Lnext_ecode + + case OP_SKIPZERO: + Fecode++; + do Fecode += GET(Fecode,1); while (*Fecode == OP_ALT); + Fecode += 1 + LINK_SIZE; + break; + + + /* ===================================================================== */ + /* Handle possessive brackets with an unlimited repeat. The end of these + brackets will always be OP_KETRPOS, which returns MATCH_KETRPOS without + going further in the pattern. */ + +#define Lframe_type F->temp_32[0] +#define Lmatched_once F->temp_32[1] +#define Lzero_allowed F->temp_32[2] +#define Lstart_eptr F->temp_sptr[0] +#define Lstart_group F->temp_sptr[1] + + case OP_BRAPOSZERO: + Lzero_allowed = TRUE; /* Zero repeat is allowed */ + Fecode += 1; + if (*Fecode == OP_CBRAPOS || *Fecode == OP_SCBRAPOS) + goto POSSESSIVE_CAPTURE; + goto POSSESSIVE_NON_CAPTURE; + + case OP_BRAPOS: + case OP_SBRAPOS: + Lzero_allowed = FALSE; /* Zero repeat not allowed */ + + POSSESSIVE_NON_CAPTURE: + Lframe_type = GF_NOCAPTURE; /* Remembered frame type */ + goto POSSESSIVE_GROUP; + + case OP_CBRAPOS: + case OP_SCBRAPOS: + Lzero_allowed = FALSE; /* Zero repeat not allowed */ + + POSSESSIVE_CAPTURE: + number = GET2(Fecode, 1+LINK_SIZE); + Lframe_type = GF_CAPTURE | number; /* Remembered frame type */ + + POSSESSIVE_GROUP: + Lmatched_once = FALSE; /* Never matched */ + Lstart_group = Fecode; /* Start of this group */ + + for (;;) + { + Lstart_eptr = Feptr; /* Position at group start */ + group_frame_type = Lframe_type; + RMATCH(Fecode + PRIV(OP_lengths)[*Fecode], RM8); + if (rrc == MATCH_KETRPOS) + { + Lmatched_once = TRUE; /* Matched at least once */ + if (Feptr == Lstart_eptr) /* Empty match; skip to end */ + { + do Fecode += GET(Fecode, 1); while (*Fecode == OP_ALT); break; + } + + Fecode = Lstart_group; + continue; + } + + /* See comment above about handling THEN. */ + + if (rrc == MATCH_THEN) + { + PCRE2_SPTR next_ecode = Fecode + GET(Fecode,1); + if (mb->verb_ecode_ptr < next_ecode && + (*Fecode == OP_ALT || *next_ecode == OP_ALT)) + rrc = MATCH_NOMATCH; + } + + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + Fecode += GET(Fecode, 1); + if (*Fecode != OP_ALT) break; + } + + /* Success if matched something or zero repeat allowed */ + + if (Lmatched_once || Lzero_allowed) + { + Fecode += 1 + LINK_SIZE; + break; + } + + RRETURN(MATCH_NOMATCH); + +#undef Lmatched_once +#undef Lzero_allowed +#undef Lframe_type +#undef Lstart_eptr +#undef Lstart_group + + + /* ===================================================================== */ + /* Handle non-capturing brackets that cannot match an empty string. When we + get to the final alternative within the brackets, as long as there are no + THEN's in the pattern, we can optimize by not recording a new backtracking + point. (Ideally we should test for a THEN within this group, but we don't + have that information.) Don't do this if we are at the very top level, + however, because that would make handling assertions and once-only brackets + messier when there is nothing to go back to. */ + +#define Lframe_type F->temp_32[0] /* Set for all that use GROUPLOOP */ +#define Lnext_branch F->temp_sptr[0] /* Used only in OP_BRA handling */ + + case OP_BRA: + if (mb->hasthen || Frdepth == 0) + { + Lframe_type = 0; + goto GROUPLOOP; + } + + for (;;) + { + Lnext_branch = Fecode + GET(Fecode, 1); + if (*Lnext_branch != OP_ALT) break; + + /* This is never the final branch. We do not need to test for MATCH_THEN + here because this code is not used when there is a THEN in the pattern. */ + + RMATCH(Fecode + PRIV(OP_lengths)[*Fecode], RM1); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + Fecode = Lnext_branch; + } + + /* Hit the start of the final branch. Continue at this level. */ + + Fecode += PRIV(OP_lengths)[*Fecode]; + break; + +#undef Lnext_branch + + + /* ===================================================================== */ + /* Handle a capturing bracket, other than those that are possessive with an + unlimited repeat. */ + + case OP_CBRA: + case OP_SCBRA: + Lframe_type = GF_CAPTURE | GET2(Fecode, 1+LINK_SIZE); + goto GROUPLOOP; + + + /* ===================================================================== */ + /* Atomic groups and non-capturing brackets that can match an empty string + must record a backtracking point and also set up a chained frame. */ + + case OP_ONCE: + case OP_SBRA: + Lframe_type = GF_NOCAPTURE | Fop; + + GROUPLOOP: + for (;;) + { + group_frame_type = Lframe_type; + RMATCH(Fecode + PRIV(OP_lengths)[*Fecode], RM2); + if (rrc == MATCH_THEN) + { + PCRE2_SPTR next_ecode = Fecode + GET(Fecode,1); + if (mb->verb_ecode_ptr < next_ecode && + (*Fecode == OP_ALT || *next_ecode == OP_ALT)) + rrc = MATCH_NOMATCH; + } + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + Fecode += GET(Fecode, 1); + if (*Fecode != OP_ALT) RRETURN(MATCH_NOMATCH); + } + /* Control never reaches here. */ + +#undef Lframe_type + + + /* ===================================================================== */ + /* Recursion either matches the current regex, or some subexpression. The + offset data is the offset to the starting bracket from the start of the + whole pattern. (This is so that it works from duplicated subpatterns.) */ + +#define Lframe_type F->temp_32[0] +#define Lstart_branch F->temp_sptr[0] + + case OP_RECURSE: + bracode = mb->start_code + GET(Fecode, 1); + number = (bracode == mb->start_code)? 0 : GET2(bracode, 1 + LINK_SIZE); + + /* If we are already in a recursion, check for repeating the same one + without advancing the subject pointer. This should catch convoluted mutual + recursions. (Some simple cases are caught at compile time.) */ + + if (Fcurrent_recurse != RECURSE_UNSET) + { + offset = Flast_group_offset; + while (offset != PCRE2_UNSET) + { + N = (heapframe *)((char *)mb->match_frames + offset); + P = (heapframe *)((char *)N - frame_size); + if (N->group_frame_type == (GF_RECURSE | number)) + { + if (Feptr == P->eptr) RRETURN(PCRE2_ERROR_RECURSELOOP); + break; + } + offset = P->last_group_offset; + } + } + + /* Now run the recursion, branch by branch. */ + + Lstart_branch = bracode; + Lframe_type = GF_RECURSE | number; + + for (;;) + { + PCRE2_SPTR next_ecode; + + group_frame_type = Lframe_type; + RMATCH(Lstart_branch + PRIV(OP_lengths)[*Lstart_branch], RM11); + next_ecode = Lstart_branch + GET(Lstart_branch,1); + + /* Handle backtracking verbs, which are defined in a range that can + easily be tested for. PCRE does not allow THEN, SKIP, PRUNE or COMMIT to + escape beyond a recursion; they cause a NOMATCH for the entire recursion. + + When one of these verbs triggers, the current recursion group number is + recorded. If it matches the recursion we are processing, the verb + happened within the recursion and we must deal with it. Otherwise it must + have happened after the recursion completed, and so has to be passed + back. See comment above about handling THEN. */ + + if (rrc >= MATCH_BACKTRACK_MIN && rrc <= MATCH_BACKTRACK_MAX && + mb->verb_current_recurse == (Lframe_type ^ GF_RECURSE)) + { + if (rrc == MATCH_THEN && mb->verb_ecode_ptr < next_ecode && + (*Lstart_branch == OP_ALT || *next_ecode == OP_ALT)) + rrc = MATCH_NOMATCH; + else RRETURN(MATCH_NOMATCH); + } + + /* Note that carrying on after (*ACCEPT) in a recursion is handled in the + OP_ACCEPT code. Nothing needs to be done here. */ + + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + Lstart_branch = next_ecode; + if (*Lstart_branch != OP_ALT) RRETURN(MATCH_NOMATCH); + } + /* Control never reaches here. */ + +#undef Lframe_type +#undef Lstart_branch + + + /* ===================================================================== */ + /* Positive assertions are like other groups except that PCRE doesn't allow + the effect of (*THEN) to escape beyond an assertion; it is therefore + treated as NOMATCH. (*ACCEPT) is treated as successful assertion, with its + captures retained. Any other return is an error. */ + +#define Lframe_type F->temp_32[0] + + case OP_ASSERT: + case OP_ASSERTBACK: + Lframe_type = GF_NOCAPTURE | Fop; + for (;;) + { + group_frame_type = Lframe_type; + RMATCH(Fecode + PRIV(OP_lengths)[*Fecode], RM3); + if (rrc == MATCH_ACCEPT) + { + memcpy(Fovector, + (char *)assert_accept_frame + offsetof(heapframe, ovector), + assert_accept_frame->offset_top * sizeof(PCRE2_SIZE)); + Foffset_top = assert_accept_frame->offset_top; + break; + } + if (rrc != MATCH_NOMATCH && rrc != MATCH_THEN) RRETURN(rrc); + Fecode += GET(Fecode, 1); + if (*Fecode != OP_ALT) RRETURN(MATCH_NOMATCH); + } + + do Fecode += GET(Fecode, 1); while (*Fecode == OP_ALT); + Fecode += 1 + LINK_SIZE; + break; + +#undef Lframe_type + + + /* ===================================================================== */ + /* Handle negative assertions. Loop for each non-matching branch as for + positive assertions. */ + +#define Lframe_type F->temp_32[0] + + case OP_ASSERT_NOT: + case OP_ASSERTBACK_NOT: + Lframe_type = GF_NOCAPTURE | Fop; + + for (;;) + { + group_frame_type = Lframe_type; + RMATCH(Fecode + PRIV(OP_lengths)[*Fecode], RM4); + switch(rrc) + { + case MATCH_ACCEPT: /* Assertion matched, therefore it fails. */ + case MATCH_MATCH: + RRETURN (MATCH_NOMATCH); + + case MATCH_NOMATCH: /* Branch failed, try next if present. */ + case MATCH_THEN: + Fecode += GET(Fecode, 1); + if (*Fecode != OP_ALT) goto ASSERT_NOT_FAILED; + break; + + case MATCH_COMMIT: /* Assertion forced to fail, therefore continue. */ + case MATCH_SKIP: + case MATCH_PRUNE: + do Fecode += GET(Fecode, 1); while (*Fecode == OP_ALT); + goto ASSERT_NOT_FAILED; + + default: /* Pass back any other return */ + RRETURN(rrc); + } + } + + /* None of the branches have matched or there was a backtrack to (*COMMIT), + (*SKIP), (*PRUNE), or (*THEN) in the last branch. This is success for a + negative assertion, so carry on. */ + + ASSERT_NOT_FAILED: + Fecode += 1 + LINK_SIZE; + break; + +#undef Lframe_type + + + /* ===================================================================== */ + /* The callout item calls an external function, if one is provided, passing + details of the match so far. This is mainly for debugging, though the + function is able to force a failure. */ + + case OP_CALLOUT: + case OP_CALLOUT_STR: + rrc = do_callout(F, mb, &length); + if (rrc > 0) RRETURN(MATCH_NOMATCH); + if (rrc < 0) RRETURN(rrc); + Fecode += length; + break; + + + /* ===================================================================== */ + /* Conditional group: compilation checked that there are no more than two + branches. If the condition is false, skipping the first branch takes us + past the end of the item if there is only one branch, but that's exactly + what we want. */ + + case OP_COND: + case OP_SCOND: + + /* The variable Flength will be added to Fecode when the condition is + false, to get to the second branch. Setting it to the offset to the ALT or + KET, then incrementing Fecode achieves this effect. However, if the second + branch is non-existent, we must point to the KET so that the end of the + group is correctly processed. We now have Fecode pointing to the condition + or callout. */ + + Flength = GET(Fecode, 1); /* Offset to the second branch */ + if (Fecode[Flength] != OP_ALT) Flength -= 1 + LINK_SIZE; + Fecode += 1 + LINK_SIZE; /* From this opcode */ + + /* Because of the way auto-callout works during compile, a callout item is + inserted between OP_COND and an assertion condition. Such a callout can + also be inserted manually. */ + + if (*Fecode == OP_CALLOUT || *Fecode == OP_CALLOUT_STR) + { + rrc = do_callout(F, mb, &length); + if (rrc > 0) RRETURN(MATCH_NOMATCH); + if (rrc < 0) RRETURN(rrc); + + /* Advance Fecode past the callout, so it now points to the condition. We + must adjust Flength so that the value of Fecode+Flength is unchanged. */ + + Fecode += length; + Flength -= length; + } + + /* Test the various possible conditions */ + + condition = FALSE; + switch(*Fecode) + { + case OP_RREF: /* Group recursion test */ + if (Fcurrent_recurse != RECURSE_UNSET) + { + number = GET2(Fecode, 1); + condition = (number == RREF_ANY || number == Fcurrent_recurse); + } + break; + + case OP_DNRREF: /* Duplicate named group recursion test */ + if (Fcurrent_recurse != RECURSE_UNSET) + { + int count = GET2(Fecode, 1 + IMM2_SIZE); + PCRE2_SPTR slot = mb->name_table + GET2(Fecode, 1) * mb->name_entry_size; + while (count-- > 0) + { + number = GET2(slot, 0); + condition = number == Fcurrent_recurse; + if (condition) break; + slot += mb->name_entry_size; + } + } + break; + + case OP_CREF: /* Numbered group used test */ + offset = (GET2(Fecode, 1) << 1) - 2; /* Doubled ref number */ + condition = offset < Foffset_top && Fovector[offset] != PCRE2_UNSET; + break; + + case OP_DNCREF: /* Duplicate named group used test */ + { + int count = GET2(Fecode, 1 + IMM2_SIZE); + PCRE2_SPTR slot = mb->name_table + GET2(Fecode, 1) * mb->name_entry_size; + while (count-- > 0) + { + offset = (GET2(slot, 0) << 1) - 2; + condition = offset < Foffset_top && Fovector[offset] != PCRE2_UNSET; + if (condition) break; + slot += mb->name_entry_size; + } + } + break; + + case OP_FALSE: + case OP_FAIL: /* The assertion (?!) becomes OP_FAIL */ + break; + + case OP_TRUE: + condition = TRUE; + break; + + /* The condition is an assertion. Run code similar to the assertion code + above. */ + +#define Lpositive F->temp_32[0] +#define Lstart_branch F->temp_sptr[0] + + default: + Lpositive = (*Fecode == OP_ASSERT || *Fecode == OP_ASSERTBACK); + Lstart_branch = Fecode; + + for (;;) + { + group_frame_type = GF_CONDASSERT | *Fecode; + RMATCH(Lstart_branch + PRIV(OP_lengths)[*Lstart_branch], RM5); + + switch(rrc) + { + case MATCH_ACCEPT: /* Save captures */ + memcpy(Fovector, + (char *)assert_accept_frame + offsetof(heapframe, ovector), + assert_accept_frame->offset_top * sizeof(PCRE2_SIZE)); + Foffset_top = assert_accept_frame->offset_top; + + /* Fall through */ + /* In the case of a match, the captures have already been put into + the current frame. */ + + case MATCH_MATCH: + condition = Lpositive; /* TRUE for positive assertion */ + break; + + /* PCRE doesn't allow the effect of (*THEN) to escape beyond an + assertion; it is therefore always treated as NOMATCH. */ + + case MATCH_NOMATCH: + case MATCH_THEN: + Lstart_branch += GET(Lstart_branch, 1); + if (*Lstart_branch == OP_ALT) continue; /* Try next branch */ + condition = !Lpositive; /* TRUE for negative assertion */ + break; + + /* These force no match without checking other branches. */ + + case MATCH_COMMIT: + case MATCH_SKIP: + case MATCH_PRUNE: + condition = !Lpositive; + break; + + default: + RRETURN(rrc); + } + break; /* Out of the branch loop */ + } + + /* If the condition is true, find the end of the assertion so that + advancing past it gets us to the start of the first branch. */ + + if (condition) + { + do Fecode += GET(Fecode, 1); while (*Fecode == OP_ALT); + } + break; /* End of assertion condition */ + } + +#undef Lpositive +#undef Lstart_branch + + /* Choose branch according to the condition. */ + + Fecode += condition? PRIV(OP_lengths)[*Fecode] : Flength; + + /* If the opcode is OP_SCOND it means we are at a repeated conditional + group that might match an empty string. We must therefore descend a level + so that the start is remembered for checking. For OP_COND we can just + continue at this level. */ + + if (Fop == OP_SCOND) + { + group_frame_type = GF_NOCAPTURE | Fop; + RMATCH(Fecode, RM35); + RRETURN(rrc); + } + break; + + + +/* ========================================================================= */ +/* End of start of parenthesis opcodes */ +/* ========================================================================= */ + + + /* ===================================================================== */ + /* Move the subject pointer back. This occurs only at the start of each + branch of a lookbehind assertion. If we are too close to the start to move + back, fail. When working with UTF-8 we move back a number of characters, + not bytes. */ + + case OP_REVERSE: + number = GET(Fecode, 1); +#ifdef SUPPORT_UNICODE + if (utf) + { + while (number-- > 0) + { + if (Feptr <= mb->start_subject) RRETURN(MATCH_NOMATCH); + Feptr--; + BACKCHAR(Feptr); + } + } + else +#endif + + /* No UTF-8 support, or not in UTF-8 mode: count is byte count */ + + { + if ((ptrdiff_t)number > Feptr - mb->start_subject) RRETURN(MATCH_NOMATCH); + Feptr -= number; + } + + /* Save the earliest consulted character, then skip to next op code */ + + if (Feptr < mb->start_used_ptr) mb->start_used_ptr = Feptr; + Fecode += 1 + LINK_SIZE; + break; + + + /* ===================================================================== */ + /* An alternation is the end of a branch; scan along to find the end of the + bracketed group. */ + + case OP_ALT: + do Fecode += GET(Fecode,1); while (*Fecode == OP_ALT); + break; + + + /* ===================================================================== */ + /* The end of a parenthesized group. For all but OP_BRA and OP_COND, the + starting frame was added to the chained frames in order to remember the + starting subject position for the group. */ + + case OP_KET: + case OP_KETRMIN: + case OP_KETRMAX: + case OP_KETRPOS: + + bracode = Fecode - GET(Fecode, 1); + + /* Point N to the frame at the start of the most recent group. + Remember the subject pointer at the start of the group. */ + + if (*bracode != OP_BRA && *bracode != OP_COND) + { + N = (heapframe *)((char *)mb->match_frames + Flast_group_offset); + P = (heapframe *)((char *)N - frame_size); + Flast_group_offset = P->last_group_offset; + +#ifdef DEBUG_SHOW_RMATCH + fprintf(stderr, "++ KET for frame=%d type=%x prev char offset=%lu\n", + N->rdepth, N->group_frame_type, + (char *)P->eptr - (char *)mb->start_subject); +#endif + + /* If we are at the end of an assertion that is a condition, return a + match, discarding any intermediate backtracking points. Copy back the + captures into the frame before N so that they are set on return. Doing + this for all assertions, both positive and negative, seems to match what + Perl does. */ + + if (GF_IDMASK(N->group_frame_type) == GF_CONDASSERT) + { + memcpy((char *)P + offsetof(heapframe, ovector), Fovector, + Foffset_top * sizeof(PCRE2_SIZE)); + P->offset_top = Foffset_top; + Fback_frame = (char *)F - (char *)P; + RRETURN(MATCH_MATCH); + } + } + else P = NULL; /* Indicates starting frame not recorded */ + + /* The group was not a conditional assertion. */ + + switch (*bracode) + { + case OP_BRA: /* No need to do anything for these */ + case OP_COND: + case OP_SCOND: + break; + + /* Positive assertions are like OP_ONCE, except that in addition the + subject pointer must be put back to where it was at the start of the + assertion. */ + + case OP_ASSERT: + case OP_ASSERTBACK: + if (Feptr > mb->last_used_ptr) mb->last_used_ptr = Feptr; + Feptr = P->eptr; + /* Fall through */ + + /* For an atomic group, discard internal backtracking points. We must + also ensure that any remaining branches within the top-level of the group + are not tried. Do this by adjusting the code pointer within the backtrack + frame so that it points to the final branch. */ + + case OP_ONCE: + Fback_frame = ((char *)F - (char *)P) + frame_size; + for (;;) + { + uint32_t y = GET(P->ecode,1); + if ((P->ecode)[y] != OP_ALT) break; + P->ecode += y; + } + break; + + /* A matching negative assertion returns MATCH, which is turned into + NOMATCH at the assertion level. */ + + case OP_ASSERT_NOT: + case OP_ASSERTBACK_NOT: + RRETURN(MATCH_MATCH); + + /* Whole-pattern recursion is coded as a recurse into group 0, so it + won't be picked up here. Instead, we catch it when the OP_END is reached. + Other recursion is handled here. */ + + case OP_CBRA: + case OP_CBRAPOS: + case OP_SCBRA: + case OP_SCBRAPOS: + number = GET2(bracode, 1+LINK_SIZE); + + /* Handle a recursively called group. We reinstate the previous set of + captures and then carry on after the recursion call. */ + + if (Fcurrent_recurse == number) + { + P = (heapframe *)((char *)N - frame_size); + memcpy((char *)F + offsetof(heapframe, ovector), P->ovector, + P->offset_top * sizeof(PCRE2_SIZE)); + Foffset_top = P->offset_top; + Fcapture_last = P->capture_last; + Fcurrent_recurse = P->current_recurse; + Fecode = P->ecode + 1 + LINK_SIZE; + continue; /* With next opcode */ + } + + /* Deal with actual capturing. */ + + offset = (number << 1) - 2; + Fcapture_last = number; + Fovector[offset] = P->eptr - mb->start_subject; + Fovector[offset+1] = Feptr - mb->start_subject; + if (offset >= Foffset_top) Foffset_top = offset + 2; + break; + } /* End actions relating to the starting opcode */ + + /* OP_KETRPOS is a possessive repeating ket. Remember the current position, + and return the MATCH_KETRPOS. This makes it possible to do the repeats one + at a time from the outer level. This must precede the empty string test - + in this case that test is done at the outer level. */ + + if (*Fecode == OP_KETRPOS) + { + memcpy((char *)P + offsetof(heapframe, eptr), + (char *)F + offsetof(heapframe, eptr), + frame_copy_size); + RRETURN(MATCH_KETRPOS); + } + + /* Handle the different kinds of closing brackets. A non-repeating ket + needs no special action, just continuing at this level. This also happens + for the repeating kets if the group matched no characters, in order to + forcibly break infinite loops. Otherwise, the repeating kets try the rest + of the pattern or restart from the preceding bracket, in the appropriate + order. */ + + if (Fop != OP_KET && (P == NULL || Feptr != P->eptr)) + { + if (Fop == OP_KETRMIN) + { + RMATCH(Fecode + 1 + LINK_SIZE, RM6); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + Fecode -= GET(Fecode, 1); + break; /* End of ket processing */ + } + + /* Repeat the maximum number of times (KETRMAX) */ + + RMATCH(bracode, RM7); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + } + + /* Carry on at this level for a non-repeating ket, or after matching an + empty string, or after repeating for a maximum number of times. */ + + Fecode += 1 + LINK_SIZE; + break; + + + /* ===================================================================== */ + /* Start and end of line assertions, not multiline mode. */ + + case OP_CIRC: /* Start of line, unless PCRE2_NOTBOL is set. */ + if (Feptr != mb->start_subject || (mb->moptions & PCRE2_NOTBOL) != 0) + RRETURN(MATCH_NOMATCH); + Fecode++; + break; + + case OP_SOD: /* Unconditional start of subject */ + if (Feptr != mb->start_subject) RRETURN(MATCH_NOMATCH); + Fecode++; + break; + + /* When PCRE2_NOTEOL is unset, assert before the subject end, or a + terminating newline unless PCRE2_DOLLAR_ENDONLY is set. */ + + case OP_DOLL: + if ((mb->moptions & PCRE2_NOTEOL) != 0) RRETURN(MATCH_NOMATCH); + if ((mb->poptions & PCRE2_DOLLAR_ENDONLY) == 0) goto ASSERT_NL_OR_EOS; + + /* Fall through */ + /* Unconditional end of subject assertion (\z) */ + + case OP_EOD: + if (Feptr < mb->end_subject) RRETURN(MATCH_NOMATCH); + SCHECK_PARTIAL(); + Fecode++; + break; + + /* End of subject or ending \n assertion (\Z) */ + + case OP_EODN: + ASSERT_NL_OR_EOS: + if (Feptr < mb->end_subject && + (!IS_NEWLINE(Feptr) || Feptr != mb->end_subject - mb->nllen)) + { + if (mb->partial != 0 && + Feptr + 1 >= mb->end_subject && + NLBLOCK->nltype == NLTYPE_FIXED && + NLBLOCK->nllen == 2 && + UCHAR21TEST(Feptr) == NLBLOCK->nl[0]) + { + mb->hitend = TRUE; + if (mb->partial > 1) return PCRE2_ERROR_PARTIAL; + } + RRETURN(MATCH_NOMATCH); + } + + /* Either at end of string or \n before end. */ + + SCHECK_PARTIAL(); + Fecode++; + break; + + + /* ===================================================================== */ + /* Start and end of line assertions, multiline mode. */ + + /* Start of subject unless notbol, or after any newline except for one at + the very end, unless PCRE2_ALT_CIRCUMFLEX is set. */ + + case OP_CIRCM: + if ((mb->moptions & PCRE2_NOTBOL) != 0 && Feptr == mb->start_subject) + RRETURN(MATCH_NOMATCH); + if (Feptr != mb->start_subject && + ((Feptr == mb->end_subject && + (mb->poptions & PCRE2_ALT_CIRCUMFLEX) == 0) || + !WAS_NEWLINE(Feptr))) + RRETURN(MATCH_NOMATCH); + Fecode++; + break; + + /* Assert before any newline, or before end of subject unless noteol is + set. */ + + case OP_DOLLM: + if (Feptr < mb->end_subject) + { + if (!IS_NEWLINE(Feptr)) + { + if (mb->partial != 0 && + Feptr + 1 >= mb->end_subject && + NLBLOCK->nltype == NLTYPE_FIXED && + NLBLOCK->nllen == 2 && + UCHAR21TEST(Feptr) == NLBLOCK->nl[0]) + { + mb->hitend = TRUE; + if (mb->partial > 1) return PCRE2_ERROR_PARTIAL; + } + RRETURN(MATCH_NOMATCH); + } + } + else + { + if ((mb->moptions & PCRE2_NOTEOL) != 0) RRETURN(MATCH_NOMATCH); + SCHECK_PARTIAL(); + } + Fecode++; + break; + + + /* ===================================================================== */ + /* Start of match assertion */ + + case OP_SOM: + if (Feptr != mb->start_subject + mb->start_offset) RRETURN(MATCH_NOMATCH); + Fecode++; + break; + + + /* ===================================================================== */ + /* Reset the start of match point */ + + case OP_SET_SOM: + Fstart_match = Feptr; + Fecode++; + break; + + + /* ===================================================================== */ + /* Word boundary assertions. Find out if the previous and current + characters are "word" characters. It takes a bit more work in UTF mode. + Characters > 255 are assumed to be "non-word" characters when PCRE2_UCP is + not set. When it is set, use Unicode properties if available, even when not + in UTF mode. Remember the earliest and latest consulted characters. */ + + case OP_NOT_WORD_BOUNDARY: + case OP_WORD_BOUNDARY: + if (Feptr == mb->start_subject) prev_is_word = FALSE; else + { + PCRE2_SPTR lastptr = Feptr - 1; +#ifdef SUPPORT_UNICODE + if (utf) + { + BACKCHAR(lastptr); + GETCHAR(fc, lastptr); + } + else +#endif /* SUPPORT_UNICODE */ + fc = *lastptr; + if (lastptr < mb->start_used_ptr) mb->start_used_ptr = lastptr; +#ifdef SUPPORT_UNICODE + if ((mb->poptions & PCRE2_UCP) != 0) + { + if (fc == '_') prev_is_word = TRUE; else + { + int cat = UCD_CATEGORY(fc); + prev_is_word = (cat == ucp_L || cat == ucp_N); + } + } + else +#endif /* SUPPORT_UNICODE */ + prev_is_word = CHMAX_255(fc) && (mb->ctypes[fc] & ctype_word) != 0; + } + + /* Get status of next character */ + + if (Feptr >= mb->end_subject) + { + SCHECK_PARTIAL(); + cur_is_word = FALSE; + } + else + { + PCRE2_SPTR nextptr = Feptr + 1; +#ifdef SUPPORT_UNICODE + if (utf) + { + FORWARDCHARTEST(nextptr, mb->end_subject); + GETCHAR(fc, Feptr); + } + else +#endif /* SUPPORT_UNICODE */ + fc = *Feptr; + if (nextptr > mb->last_used_ptr) mb->last_used_ptr = nextptr; +#ifdef SUPPORT_UNICODE + if ((mb->poptions & PCRE2_UCP) != 0) + { + if (fc == '_') cur_is_word = TRUE; else + { + int cat = UCD_CATEGORY(fc); + cur_is_word = (cat == ucp_L || cat == ucp_N); + } + } + else +#endif /* SUPPORT_UNICODE */ + cur_is_word = CHMAX_255(fc) && (mb->ctypes[fc] & ctype_word) != 0; + } + + /* Now see if the situation is what we want */ + + if ((*Fecode++ == OP_WORD_BOUNDARY)? + cur_is_word == prev_is_word : cur_is_word != prev_is_word) + RRETURN(MATCH_NOMATCH); + break; + + + /* ===================================================================== */ + /* Backtracking (*VERB)s, with and without arguments. Note that if the + pattern is successfully matched, we do not come back from RMATCH. */ + + case OP_MARK: + Fmark = mb->nomatch_mark = Fecode + 2; + RMATCH(Fecode + PRIV(OP_lengths)[*Fecode] + Fecode[1], RM12); + + /* A return of MATCH_SKIP_ARG means that matching failed at SKIP with an + argument, and we must check whether that argument matches this MARK's + argument. It is passed back in mb->verb_skip_ptr. If it does match, we + return MATCH_SKIP with mb->verb_skip_ptr now pointing to the subject + position that corresponds to this mark. Otherwise, pass back the return + code unaltered. */ + + if (rrc == MATCH_SKIP_ARG && + PRIV(strcmp)(Fecode + 2, mb->verb_skip_ptr) == 0) + { + mb->verb_skip_ptr = Feptr; /* Pass back current position */ + RRETURN(MATCH_SKIP); + } + RRETURN(rrc); + + case OP_FAIL: + RRETURN(MATCH_NOMATCH); + + /* Record the current recursing group number in mb->verb_current_recurse + when a backtracking return such as MATCH_COMMIT is given. This enables the + recurse processing to catch verbs from within the recursion. */ + + case OP_COMMIT: + RMATCH(Fecode + PRIV(OP_lengths)[*Fecode], RM13); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + mb->verb_current_recurse = Fcurrent_recurse; + RRETURN(MATCH_COMMIT); + + case OP_PRUNE: + RMATCH(Fecode + PRIV(OP_lengths)[*Fecode], RM14); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + mb->verb_current_recurse = Fcurrent_recurse; + RRETURN(MATCH_PRUNE); + + case OP_PRUNE_ARG: + Fmark = mb->nomatch_mark = Fecode + 2; + RMATCH(Fecode + PRIV(OP_lengths)[*Fecode] + Fecode[1], RM15); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + mb->verb_current_recurse = Fcurrent_recurse; + RRETURN(MATCH_PRUNE); + + case OP_SKIP: + RMATCH(Fecode + PRIV(OP_lengths)[*Fecode], RM16); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + mb->verb_skip_ptr = Feptr; /* Pass back current position */ + mb->verb_current_recurse = Fcurrent_recurse; + RRETURN(MATCH_SKIP); - case OP_NOT_WHITESPACE: - for (i = min; i < max; i++) - { - if (eptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - break; - } - if (MAX_255(*eptr) && (mb->ctypes[*eptr] & ctype_space) != 0) break; - eptr++; - } - break; + /* Note that, for Perl compatibility, SKIP with an argument does NOT set + nomatch_mark. When a pattern match ends with a SKIP_ARG for which there was + not a matching mark, we have to re-run the match, ignoring the SKIP_ARG + that failed and any that precede it (either they also failed, or were not + triggered). To do this, we maintain a count of executed SKIP_ARGs. If a + SKIP_ARG gets to top level, the match is re-run with mb->ignore_skip_arg + set to the count of the one that failed. */ - case OP_WHITESPACE: - for (i = min; i < max; i++) - { - if (eptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - break; - } - if (!MAX_255(*eptr) || (mb->ctypes[*eptr] & ctype_space) == 0) break; - eptr++; - } - break; + case OP_SKIP_ARG: + mb->skip_arg_count++; + if (mb->skip_arg_count <= mb->ignore_skip_arg) + { + Fecode += PRIV(OP_lengths)[*Fecode] + Fecode[1]; + break; + } + RMATCH(Fecode + PRIV(OP_lengths)[*Fecode] + Fecode[1], RM17); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); - case OP_NOT_WORDCHAR: - for (i = min; i < max; i++) - { - if (eptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - break; - } - if (MAX_255(*eptr) && (mb->ctypes[*eptr] & ctype_word) != 0) break; - eptr++; - } - break; + /* Pass back the current skip name and return the special MATCH_SKIP_ARG + return code. This will either be caught by a matching MARK, or get to the + top, where it causes a rematch with mb->ignore_skip_arg set to the value of + mb->skip_arg_count. */ - case OP_WORDCHAR: - for (i = min; i < max; i++) - { - if (eptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - break; - } - if (!MAX_255(*eptr) || (mb->ctypes[*eptr] & ctype_word) == 0) break; - eptr++; - } - break; + mb->verb_skip_ptr = Fecode + 2; + mb->verb_current_recurse = Fcurrent_recurse; + RRETURN(MATCH_SKIP_ARG); - default: - RRETURN(PCRE2_ERROR_INTERNAL); - } + /* For THEN (and THEN_ARG) we pass back the address of the opcode, so that + the branch in which it occurs can be determined. */ - if (possessive) continue; /* No backtracking */ - for (;;) - { - if (eptr == pp) goto TAIL_RECURSE; - RMATCH(eptr, ecode, offset_top, mb, eptrb, RM47); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - eptr--; - if (ctype == OP_ANYNL && eptr > pp && *eptr == CHAR_LF && - eptr[-1] == CHAR_CR) eptr--; - } - } + case OP_THEN: + RMATCH(Fecode + PRIV(OP_lengths)[*Fecode], RM18); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + mb->verb_ecode_ptr = Fecode; + mb->verb_current_recurse = Fcurrent_recurse; + RRETURN(MATCH_THEN); + + case OP_THEN_ARG: + Fmark = mb->nomatch_mark = Fecode + 2; + RMATCH(Fecode + PRIV(OP_lengths)[*Fecode] + Fecode[1], RM19); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + mb->verb_ecode_ptr = Fecode; + mb->verb_current_recurse = Fcurrent_recurse; + RRETURN(MATCH_THEN); - /* Control never gets here */ - } + /* ===================================================================== */ /* There's been some horrible disaster. Arrival here can only mean there is something seriously wrong in the code above or the OP_xxx definitions. */ default: - RRETURN(PCRE2_ERROR_INTERNAL); + return PCRE2_ERROR_INTERNAL; } - /* Do not stick any code in here without much thought; it is assumed + /* Do not insert any code in here without much thought; it is assumed that "continue" in the code above comes out to here to repeat the main loop. */ - } /* End of main loop */ + } /* End of main loop */ /* Control never reaches here */ -/* When compiling to use the heap rather than the stack for recursive calls to -match(), the RRETURN() macro jumps here. The number that is saved in -frame->Xwhere indicates which label we actually want to return to. */ +/* ========================================================================= */ +/* The RRETURN() macro jumps here. The number that is saved in Freturn_id +indicates which label we actually want to return to. The value in Frdepth is +the index number of the frame in the vector. The return value has been placed +in rrc. */ -#ifdef HEAP_MATCH_RECURSE #define LBL(val) case val: goto L_RM##val; -HEAP_RETURN: -switch (frame->Xwhere) + +RETURN_SWITCH: +if (Frdepth == 0) return rrc; /* Exit from the top level */ +F = (heapframe *)((char *)F - Fback_frame); /* Back track */ + +#ifdef DEBUG_SHOW_RMATCH +fprintf(stderr, "++ RETURN %d to %d\n", rrc, Freturn_id); +#endif + +switch (Freturn_id) { LBL( 1) LBL( 2) LBL( 3) LBL( 4) LBL( 5) LBL( 6) LBL( 7) LBL( 8) - LBL( 9) LBL(10) LBL(11) LBL(12) LBL(13) LBL(14) LBL(15) LBL(17) - LBL(19) LBL(24) LBL(25) LBL(26) LBL(27) LBL(29) LBL(31) LBL(33) - LBL(35) LBL(43) LBL(47) LBL(48) LBL(49) LBL(50) LBL(51) LBL(52) - LBL(53) LBL(54) LBL(55) LBL(56) LBL(57) LBL(58) LBL(63) LBL(64) - LBL(65) LBL(66) LBL(68) + LBL( 9) LBL(10) LBL(11) LBL(12) LBL(13) LBL(14) LBL(15) LBL(16) + LBL(17) LBL(18) LBL(19) LBL(20) LBL(21) LBL(22) LBL(23) LBL(24) + LBL(25) LBL(26) LBL(27) LBL(28) LBL(29) LBL(30) LBL(31) LBL(32) + LBL(33) LBL(34) LBL(35) + #ifdef SUPPORT_WIDE_CHARS - LBL(20) LBL(21) + LBL(100) LBL(101) #endif + #ifdef SUPPORT_UNICODE - LBL(16) LBL(18) - LBL(22) LBL(23) LBL(28) LBL(30) - LBL(32) LBL(34) LBL(42) LBL(46) - LBL(36) LBL(37) LBL(38) LBL(39) LBL(40) LBL(41) LBL(44) LBL(45) - LBL(59) LBL(60) LBL(61) LBL(62) LBL(67) -#endif /* SUPPORT_UNICODE */ + LBL(200) LBL(201) LBL(202) LBL(203) LBL(204) LBL(205) LBL(206) + LBL(207) LBL(208) LBL(209) LBL(210) LBL(211) LBL(212) LBL(213) + LBL(214) LBL(215) LBL(216) LBL(217) LBL(218) LBL(219) LBL(220) + LBL(221) LBL(222) +#endif + default: return PCRE2_ERROR_INTERNAL; } #undef LBL -#endif /* HEAP_MATCH_RECURSE */ -} - - -/*************************************************************************** -**************************************************************************** - RECURSION IN THE match() FUNCTION - -Undefine all the macros that were defined above to handle this. */ - -#ifdef HEAP_MATCH_RECURSE -#undef eptr -#undef ecode -#undef mstart -#undef offset_top -#undef eptrb -#undef flags - -#undef callpat -#undef charptr -#undef data -#undef next_ecode -#undef pp -#undef prev -#undef saved_eptr - -#undef new_recursive - -#undef cur_is_word -#undef condition -#undef prev_is_word - -#undef ctype -#undef length -#undef max -#undef min -#undef number -#undef offset -#undef op -#undef save_capture_last -#undef save_offset1 -#undef save_offset2 -#undef save_offset3 - -#undef newptrb -#endif /* HEAP_MATCH_RECURSE */ - -/* These two are defined as macros in both cases */ - -#undef fc -#undef fi - -/*************************************************************************** -***************************************************************************/ - - -#ifdef HEAP_MATCH_RECURSE -/************************************************* -* Release allocated heap frames * -*************************************************/ - -/* This function releases all the allocated frames. The base frame is on the -machine stack, and so must not be freed. - -Argument: - frame_base the address of the base frame - mb the match block - -Returns: nothing -*/ - -static void -release_match_heapframes (heapframe *frame_base, match_block *mb) -{ -heapframe *nextframe = frame_base->Xnextframe; -while (nextframe != NULL) - { - heapframe *oldframe = nextframe; - nextframe = nextframe->Xnextframe; - mb->stack_memctl.free(oldframe, mb->stack_memctl.memory_data); - } } -#endif /* HEAP_MATCH_RECURSE */ - /************************************************* @@ -6440,8 +6171,6 @@ pcre2_match(const pcre2_code *code, PCRE2_SPTR subject, PCRE2_SIZE length, pcre2_match_context *mcontext) { int rc; -int ocount; - const uint8_t *start_bits = NULL; const pcre2_real_code *re = (const pcre2_real_code *)code; @@ -6451,7 +6180,6 @@ BOOL firstline; BOOL has_first_cu = FALSE; BOOL has_req_cu = FALSE; BOOL startline; -BOOL using_temporary_offsets = FALSE; BOOL utf; PCRE2_UCHAR first_cu = 0; @@ -6466,18 +6194,21 @@ PCRE2_SPTR req_cu_ptr = start_match - 1; PCRE2_SPTR start_partial = NULL; PCRE2_SPTR match_partial = NULL; -/* We need to have mb pointing to a match block, because the IS_NEWLINE macro -is used below, and it expects NLBLOCK to be defined as a pointer. */ +PCRE2_SIZE frame_size; + +/* We need to have mb as a pointer to a match block, because the IS_NEWLINE +macro is used below, and it expects NLBLOCK to be defined as a pointer. */ match_block actual_match_block; match_block *mb = &actual_match_block; -#ifdef HEAP_MATCH_RECURSE -heapframe frame_zero; -frame_zero.Xprevframe = NULL; /* Marks the top level */ -frame_zero.Xnextframe = NULL; /* None are allocated yet */ -mb->match_frames_base = &frame_zero; -#endif +/* Allocate an initial vector of backtracking frames on the stack. If this +proves to be too small, it is replaced by a larger one on the heap. To get a +vector of the size required that is aligned for pointers, allocate it as a +vector of pointers. */ + +PCRE2_SPTR stack_frames_vector[START_FRAMES_SIZE/sizeof(PCRE2_SPTR)]; +mb->stack_frames = (heapframe *)stack_frames_vector; /* A length equal to PCRE2_ZERO_TERMINATED implies a zero-terminated subject string. */ @@ -6506,8 +6237,8 @@ options variable for this function. Users of PCRE2 who are not calling the function directly would like to have a way of setting these flags, in the same way that they can set pcre2_compile() flags like PCRE2_NO_AUTOPOSSESS with constructions like (*NO_AUTOPOSSESS). To enable this, (*NOTEMPTY) and -(*NOTEMPTY_ATSTART) set bits in the pattern's "flag" function which can now be -transferred to the options for this function. The bits are guaranteed to be +(*NOTEMPTY_ATSTART) set bits in the pattern's "flag" function which we now +transfer to the options for this function. The bits are guaranteed to be adjacent, but do not have the same values. This bit of Boolean trickery assumes that the match-time bits are not more significant than the flag bits. If by accident this is not the case, a compile-time division by zero error will @@ -6519,20 +6250,22 @@ options |= (re->flags & FF) / ((FF & (~FF+1)) / (OO & (~OO+1))); #undef FF #undef OO -/* A NULL match context means "use a default context" */ - -if (mcontext == NULL) - mcontext = (pcre2_match_context *)(&PRIV(default_match_context)); - /* These two settings are used in the code for checking a UTF string that follows immediately afterwards. Other values in the mb block are used only -during interpretive pcre_match() processing, not when the JIT support is in -use, so they are set up later. */ +during interpretive processing, not when the JIT support is in use, so they are +set up later. */ utf = (re->overall_options & PCRE2_UTF) != 0; mb->partial = ((options & PCRE2_PARTIAL_HARD) != 0)? 2 : ((options & PCRE2_PARTIAL_SOFT) != 0)? 1 : 0; +/* Partial matching and PCRE2_ENDANCHORED are currently not allowed at the same +time. */ + +if (mb->partial != 0 && + ((re->overall_options | options) & PCRE2_ENDANCHORED) != 0) + return PCRE2_ERROR_BADOPTION; + /* Check a UTF string for validity if required. For 8-bit and 16-bit strings, we must also check that a starting offset does not point into the middle of a multiunit character. We check only the portion of the subject that is going to @@ -6591,7 +6324,7 @@ if (utf && (options & PCRE2_NO_UTF_CHECK) == 0) /* It is an error to set an offset limit without setting the flag at compile time. */ -if (mcontext->offset_limit != PCRE2_UNSET && +if (mcontext != NULL && mcontext->offset_limit != PCRE2_UNSET && (re->overall_options & PCRE2_USE_OFFSET_LIMIT) == 0) return PCRE2_ERROR_BADOFFSETLIMIT; @@ -6610,7 +6343,15 @@ if (re->executable_jit != NULL && (options & ~PUBLIC_JIT_MATCH_OPTIONS) == 0) } #endif -/* Carry on with non-JIT matching. */ +/* Carry on with non-JIT matching. A NULL match context means "use a default +context", but we take the memory control functions from the pattern. */ + +if (mcontext == NULL) + { + mcontext = (pcre2_match_context *)(&PRIV(default_match_context)); + mb->memctl = re->memctl; + } +else mb->memctl = mcontext->memctl; anchored = ((re->overall_options | options) & PCRE2_ANCHORED) != 0; firstline = (re->overall_options & PCRE2_FIRSTLINE) != 0; @@ -6618,14 +6359,10 @@ startline = (re->flags & PCRE2_STARTLINE) != 0; bumpalong_limit = (mcontext->offset_limit == PCRE2_UNSET)? end_subject : subject + mcontext->offset_limit; -/* Fill in the fields in the match block. */ +/* Fill in the remaining fields in the match block. */ mb->callout = mcontext->callout; mb->callout_data = mcontext->callout_data; -mb->memctl = mcontext->memctl; -#ifdef HEAP_MATCH_RECURSE -mb->stack_memctl = mcontext->stack_memctl; -#endif mb->start_subject = subject; mb->start_offset = start_offset; @@ -6637,8 +6374,6 @@ mb->poptions = re->overall_options; /* Pattern options */ mb->ignore_skip_arg = 0; mb->mark = mb->nomatch_mark = NULL; /* In case never set */ -mb->recursive = NULL; /* No recursion at top level */ -mb->ovecsave_chain = NULL; /* No ovecsave blocks yet */ mb->hitend = FALSE; /* The name table is needed for finding all the numbers associated with a @@ -6649,20 +6384,6 @@ mb->name_count = re->name_count; mb->name_entry_size = re->name_entry_size; mb->start_code = mb->name_table + re->name_count * re->name_entry_size; -/* Limits set in the pattern override the match context only if they are -smaller. */ - -mb->match_limit = (mcontext->match_limit < re->limit_match)? - mcontext->match_limit : re->limit_match; -mb->match_limit_recursion = (mcontext->recursion_limit < re->limit_recursion)? - mcontext->recursion_limit : re->limit_recursion; - -/* Pointers to the individual character tables */ - -mb->lcc = re->tables + lcc_offset; -mb->fcc = re->tables + fcc_offset; -mb->ctypes = re->tables + ctypes_offset; - /* Process the \R and newline settings. */ mb->bsr_convention = re->bsr_convention; @@ -6679,6 +6400,11 @@ switch(re->newline_convention) mb->nl[0] = CHAR_NL; break; + case PCRE2_NEWLINE_NUL: + mb->nllen = 1; + mb->nl[0] = CHAR_NUL; + break; + case PCRE2_NEWLINE_CRLF: mb->nllen = 2; mb->nl[0] = CHAR_CR; @@ -6696,71 +6422,91 @@ switch(re->newline_convention) default: return PCRE2_ERROR_INTERNAL; } -/* If the expression has got more back references than the offsets supplied can -hold, we get a temporary chunk of memory to use during the matching. Otherwise, -we can use the vector supplied. The size of the ovector is three times the -value in the oveccount field. Two-thirds of it is pairs for storing matching -offsets, and the top third is working space. */ +/* The backtracking frames have fixed data at the front, and a PCRE2_SIZE +vector at the end, whose size depends on the number of capturing parentheses in +the pattern. It is not used at all if there are no capturing parentheses. + + frame_size is the total size of each frame + mb->frame_vector_size is the total usable size of the vector (rounded down + to a whole number of frames) + +The last of these is changed within the match() function if the frame vector +has to be expanded. We therefore put it into the match block so that it is +correct when calling match() more than once for non-anchored patterns. */ + +frame_size = offsetof(heapframe, ovector) + + re->top_bracket * 2 * sizeof(PCRE2_SIZE); + +/* Limits set in the pattern override the match context only if they are +smaller. */ + +mb->heap_limit = (mcontext->heap_limit < re->limit_heap)? + mcontext->heap_limit : re->limit_heap; + +mb->match_limit = (mcontext->match_limit < re->limit_match)? + mcontext->match_limit : re->limit_match; + +mb->match_limit_depth = (mcontext->depth_limit < re->limit_depth)? + mcontext->depth_limit : re->limit_depth; + +/* If a pattern has very many capturing parentheses, the frame size may be very +large. Ensure that there are at least 10 available frames by getting an initial +vector on the heap if necessary, except when the heap limit prevents this. Get +fewer if possible. (The heap limit is in kilobytes.) */ -if (re->top_backref >= match_data->oveccount) +if (frame_size <= START_FRAMES_SIZE/10) { - ocount = re->top_backref * 3 + 3; - mb->ovector = (PCRE2_SIZE *)(mb->memctl.malloc(ocount * sizeof(PCRE2_SIZE), - mb->memctl.memory_data)); - if (mb->ovector == NULL) return PCRE2_ERROR_NOMEMORY; - using_temporary_offsets = TRUE; + mb->match_frames = mb->stack_frames; /* Initial frame vector on the stack */ + mb->frame_vector_size = ((START_FRAMES_SIZE/frame_size) * frame_size); } else { - ocount = 3 * match_data->oveccount; - mb->ovector = match_data->ovector; + mb->frame_vector_size = frame_size * 10; + if ((mb->frame_vector_size / 1024) > mb->heap_limit) + { + if (frame_size > mb->heap_limit * 1024) return PCRE2_ERROR_HEAPLIMIT; + mb->frame_vector_size = ((mb->heap_limit * 1024)/frame_size) * frame_size; + } + mb->match_frames = mb->memctl.malloc(mb->frame_vector_size, + mb->memctl.memory_data); + if (mb->match_frames == NULL) return PCRE2_ERROR_NOMEMORY; } -mb->offset_end = ocount; -mb->offset_max = (2*ocount)/3; +mb->match_frames_top = + (heapframe *)((char *)mb->match_frames + mb->frame_vector_size); -/* Reset the working variable associated with each extraction. These should -never be used unless previously set, but they get saved and restored, and so we -initialize them to avoid reading uninitialized locations. Also, unset the -offsets for the matched string. This is really just for tidiness with callouts, -in case they inspect these fields. */ +/* Write to the ovector within the first frame to mark every capture unset and +to avoid uninitialized memory read errors when it is copied to a new frame. */ -if (ocount > 0) - { - PCRE2_SIZE *iptr = mb->ovector + ocount; - PCRE2_SIZE *iend = iptr - re->top_bracket; - if (iend < mb->ovector + 2) iend = mb->ovector + 2; - while (--iptr >= iend) *iptr = PCRE2_UNSET; - mb->ovector[0] = mb->ovector[1] = PCRE2_UNSET; - } +memset((char *)(mb->match_frames) + offsetof(heapframe, ovector), 0xff, + re->top_bracket * 2 * sizeof(PCRE2_SIZE)); + +/* Pointers to the individual character tables */ + +mb->lcc = re->tables + lcc_offset; +mb->fcc = re->tables + fcc_offset; +mb->ctypes = re->tables + ctypes_offset; -/* Set up the first code unit to match, if available. The first_codeunit value -is never set for an anchored regular expression, but the anchoring may be -forced at run time, so we have to test for anchoring. The first code unit may -be unset for an unanchored pattern, of course. If there's no first code unit -there may be a bitmap of possible first characters. */ +/* Set up the first code unit to match, if available. If there's no first code +unit there may be a bitmap of possible first characters. */ -if (!anchored) +if ((re->flags & PCRE2_FIRSTSET) != 0) { - if ((re->flags & PCRE2_FIRSTSET) != 0) + has_first_cu = TRUE; + first_cu = first_cu2 = (PCRE2_UCHAR)(re->first_codeunit); + if ((re->flags & PCRE2_FIRSTCASELESS) != 0) { - has_first_cu = TRUE; - first_cu = first_cu2 = (PCRE2_UCHAR)(re->first_codeunit); - if ((re->flags & PCRE2_FIRSTCASELESS) != 0) - { - first_cu2 = TABLE_GET(first_cu, mb->fcc, first_cu); + first_cu2 = TABLE_GET(first_cu, mb->fcc, first_cu); #if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 8 - if (utf && first_cu > 127) first_cu2 = UCD_OTHERCASE(first_cu); + if (utf && first_cu > 127) first_cu2 = UCD_OTHERCASE(first_cu); #endif - } } - else - if (!startline && (re->flags & PCRE2_FIRSTMAPSET) != 0) - start_bits = re->start_bitmap; } +else + if (!startline && (re->flags & PCRE2_FIRSTMAPSET) != 0) + start_bits = re->start_bitmap; -/* For anchored or unanchored matches, there may be a "last known required -character" set. */ +/* There may also be a "last known required character" set. */ if ((re->flags & PCRE2_LASTSET) != 0) { @@ -6784,7 +6530,6 @@ the loop runs just once. */ for(;;) { PCRE2_SPTR new_start_match; - mb->capture_last = 0; /* ----------------- Start of match optimizations ---------------- */ @@ -6800,8 +6545,8 @@ for(;;) /* If firstline is TRUE, the start of the match is constrained to the first line of a multiline string. That is, the match must be before or at the first newline. Implement this by temporarily adjusting end_subject so that - we stop the optimization scans at a newline. If the match fails at the - newline, later code breaks this loop. */ + we stop the optimization scans for a first code unit at a newline. If the + match fails at the newline, later code breaks this loop. */ if (firstline) { @@ -6821,90 +6566,156 @@ for(;;) end_subject = t; } - /* Advance to a unique first code unit if there is one. In 8-bit mode, the - use of memchr() gives a big speed up. */ + /* Anchored: check the first code unit if one is recorded. This may seem + pointless but it can help in detecting a no match case without scanning for + the required code unit. */ - if (has_first_cu) + if (anchored) { - PCRE2_UCHAR smc; - if (first_cu != first_cu2) - while (start_match < end_subject && - (smc = UCHAR21TEST(start_match)) != first_cu && smc != first_cu2) - start_match++; - else + if (has_first_cu || start_bits != NULL) { + BOOL ok = start_match < end_subject; + if (ok) + { + PCRE2_UCHAR c = UCHAR21TEST(start_match); + ok = has_first_cu && (c == first_cu || c == first_cu2); + if (!ok && start_bits != NULL) + { #if PCRE2_CODE_UNIT_WIDTH != 8 - while (start_match < end_subject && UCHAR21TEST(start_match) != first_cu) - start_match++; -#else - start_match = memchr(start_match, first_cu, end_subject - start_match); - if (start_match == NULL) start_match = end_subject; + if (c > 255) c = 255; #endif + ok = (start_bits[c/8] & (1 << (c&7))) != 0; + } + } + if (!ok) + { + rc = MATCH_NOMATCH; + break; + } } } - /* Or to just after a linebreak for a multiline match */ + /* Not anchored. Advance to a unique first code unit if there is one. In + 8-bit mode, the use of memchr() gives a big speed up, even though we have + to call it twice in caseless mode, in order to find the earliest occurrence + of the character in either of its cases. */ - else if (startline) + else { - if (start_match > mb->start_subject + start_offset) + if (has_first_cu) { -#ifdef SUPPORT_UNICODE - if (utf) + if (first_cu != first_cu2) /* Caseless */ { - while (start_match < end_subject && !WAS_NEWLINE(start_match)) - { +#if PCRE2_CODE_UNIT_WIDTH != 8 + PCRE2_UCHAR smc; + while (start_match < end_subject && + (smc = UCHAR21TEST(start_match)) != first_cu && + smc != first_cu2) start_match++; - ACROSSCHAR(start_match < end_subject, *start_match, - start_match++); - } +#else /* 8-bit code units */ + PCRE2_SPTR pp1 = + memchr(start_match, first_cu, end_subject-start_match); + PCRE2_SPTR pp2 = + memchr(start_match, first_cu2, end_subject-start_match); + if (pp1 == NULL) + start_match = (pp2 == NULL)? end_subject : pp2; + else + start_match = (pp2 == NULL || pp1 < pp2)? pp1 : pp2; +#endif } + + /* The caseful case */ + else + { +#if PCRE2_CODE_UNIT_WIDTH != 8 + while (start_match < end_subject && UCHAR21TEST(start_match) != + first_cu) + start_match++; +#else + start_match = memchr(start_match, first_cu, end_subject - start_match); + if (start_match == NULL) start_match = end_subject; #endif - while (start_match < end_subject && !WAS_NEWLINE(start_match)) - start_match++; + } - /* If we have just passed a CR and the newline option is ANY or - ANYCRLF, and we are now at a LF, advance the match position by one more - code unit. */ + /* If we can't find the required code unit, break the bumpalong loop, + to force a match failure, except when doing partial matching, when we + let the next cycle run at the end of the subject. To see why, consider + the pattern /(?<=abc)def/, which partially matches "abc", even though + the string does not contain the starting character "d". */ - if (start_match[-1] == CHAR_CR && - (mb->nltype == NLTYPE_ANY || mb->nltype == NLTYPE_ANYCRLF) && - start_match < end_subject && - UCHAR21TEST(start_match) == CHAR_NL) - start_match++; + if (!mb->partial && start_match >= end_subject) + { + rc = MATCH_NOMATCH; + break; + } } - } - /* Or to a non-unique first code unit if any have been identified. The - bitmap contains only 256 bits. When code units are 16 or 32 bits wide, all - code units greater than 254 set the 255 bit. */ + /* If there's no first code unit, advance to just after a linebreak for a + multiline match if required. */ - else if (start_bits != NULL) - { - while (start_match < end_subject) + else if (startline) + { + if (start_match > mb->start_subject + start_offset) + { +#ifdef SUPPORT_UNICODE + if (utf) + { + while (start_match < end_subject && !WAS_NEWLINE(start_match)) + { + start_match++; + ACROSSCHAR(start_match < end_subject, *start_match, + start_match++); + } + } + else +#endif + while (start_match < end_subject && !WAS_NEWLINE(start_match)) + start_match++; + + /* If we have just passed a CR and the newline option is ANY or + ANYCRLF, and we are now at a LF, advance the match position by one + more code unit. */ + + if (start_match[-1] == CHAR_CR && + (mb->nltype == NLTYPE_ANY || mb->nltype == NLTYPE_ANYCRLF) && + start_match < end_subject && + UCHAR21TEST(start_match) == CHAR_NL) + start_match++; + } + } + + /* If there's no first code unit or a requirement for a multiline line + start, advance to a non-unique first code unit if any have been + identified. The bitmap contains only 256 bits. When code units are 16 or + 32 bits wide, all code units greater than 254 set the 255 bit. */ + + else if (start_bits != NULL) { - uint32_t c = UCHAR21TEST(start_match); + while (start_match < end_subject) + { + uint32_t c = UCHAR21TEST(start_match); #if PCRE2_CODE_UNIT_WIDTH != 8 - if (c > 255) c = 255; + if (c > 255) c = 255; #endif - if ((start_bits[c/8] & (1 << (c&7))) != 0) break; - start_match++; + if ((start_bits[c/8] & (1 << (c&7))) != 0) break; + start_match++; + } } - } + } /* End first code unit handling */ /* Restore fudged end_subject */ end_subject = save_end_subject; - /* The following two optimizations are disabled for partial matching. */ + /* The following two optimizations must be disabled for partial matching. */ if (!mb->partial) { - /* The minimum matching length is a lower bound; no actual string of that - length may actually match the pattern. Although the value is, strictly, - in characters, we treat it as code units to avoid spending too much time - in this optimization. */ + /* The minimum matching length is a lower bound; no string of that length + may actually match the pattern. Although the value is, strictly, in + characters, we treat it as code units to avoid spending too much time in + this optimization. */ if (end_subject - start_match < re->minlength) { @@ -6913,12 +6724,16 @@ for(;;) } /* If req_cu is set, we know that that code unit must appear in the - subject for the match to succeed. If the first code unit is set, req_cu - must be later in the subject; otherwise the test starts at the match - point. This optimization can save a huge amount of backtracking in - patterns with nested unlimited repeats that aren't going to match. - Writing separate code for cased/caseless versions makes it go faster, as - does using an autoincrement and backing off on a match. + subject for the (non-partial) match to succeed. If the first code unit is + set, req_cu must be later in the subject; otherwise the test starts at + the match point. This optimization can save a huge amount of backtracking + in patterns with nested unlimited repeats that aren't going to match. + Writing separate code for caseful/caseless versions makes it go faster, + as does using an autoincrement and backing off on a match. As in the case + of the first code unit, using memchr() in the 8-bit library gives a big + speed up. Unlike the first_cu check above, we do not need to call + memchr() twice in the caseless case because we only need to check for the + presence of the character in either case, not find the first occurrence. HOWEVER: when the subject string is very, very long, searching to its end can take a long time, and give bad performance on quite ordinary @@ -6931,27 +6746,52 @@ for(;;) PCRE2_SPTR p = start_match + (has_first_cu? 1:0); /* We don't need to repeat the search if we haven't yet reached the - place we found it at last time. */ + place we found it last time round the bumpalong loop. */ if (p > req_cu_ptr) { - if (req_cu != req_cu2) + if (p < end_subject) { - while (p < end_subject) + if (req_cu != req_cu2) /* Caseless */ { - uint32_t pp = UCHAR21INCTEST(p); - if (pp == req_cu || pp == req_cu2) { p--; break; } +#if PCRE2_CODE_UNIT_WIDTH != 8 + do + { + uint32_t pp = UCHAR21INCTEST(p); + if (pp == req_cu || pp == req_cu2) { p--; break; } + } + while (p < end_subject); + +#else /* 8-bit code units */ + PCRE2_SPTR pp = p; + p = memchr(pp, req_cu, end_subject - pp); + if (p == NULL) + { + p = memchr(pp, req_cu2, end_subject - pp); + if (p == NULL) p = end_subject; + } +#endif /* PCRE2_CODE_UNIT_WIDTH != 8 */ } - } - else - { - while (p < end_subject) + + /* The caseful case */ + + else { - if (UCHAR21INCTEST(p) == req_cu) { p--; break; } +#if PCRE2_CODE_UNIT_WIDTH != 8 + do + { + if (UCHAR21INCTEST(p) == req_cu) { p--; break; } + } + while (p < end_subject); + +#else /* 8-bit code units */ + p = memchr(p, req_cu, end_subject - p); + if (p == NULL) p = end_subject; +#endif } } - /* If we can't find the required code unit, break the matching loop, + /* If we can't find the required code unit, break the bumpalong loop, forcing a match failure. */ if (p >= end_subject) @@ -6961,8 +6801,8 @@ for(;;) } /* If we have found the required code unit, save the point where we - found it, so that we don't search again next time round the loop if - the start hasn't passed this code unit yet. */ + found it, so that we don't search again next time round the bumpalong + loop if the start hasn't yet passed this code unit. */ req_cu_ptr = p; } @@ -6983,14 +6823,14 @@ for(;;) /* OK, we can now run the match. If "hitend" is set afterwards, remember the first starting point for which a partial match was found. */ - mb->start_match_ptr = start_match; mb->start_used_ptr = start_match; mb->last_used_ptr = start_match; mb->match_call_count = 0; - mb->match_function_type = 0; mb->end_offset_top = 0; mb->skip_arg_count = 0; - rc = match(start_match, mb->start_code, start_match, 2, mb, NULL, 0); + + rc = match(start_match, mb->start_code, match_data->ovector, + match_data->oveccount, re->top_bracket, frame_size, mb); if (mb->hitend && start_partial == NULL) { @@ -7016,9 +6856,9 @@ for(;;) greater than the match we have just done, treat it as NOMATCH. */ case MATCH_SKIP: - if (mb->start_match_ptr > start_match) + if (mb->verb_skip_ptr > start_match) { - new_start_match = mb->start_match_ptr; + new_start_match = mb->verb_skip_ptr; break; } /* Fall through */ @@ -7092,11 +6932,11 @@ for(;;) /* ==========================================================================*/ -/* When we reach here, one of the stopping conditions is true: +/* When we reach here, one of the following stopping conditions is true: (1) The match succeeded, either completely, or partially; -(2) The pattern is anchored or the match was failed by (*COMMIT); +(2) The pattern is anchored or the match was failed after (*COMMIT); (3) We are past the end of the subject or the bumpalong limit; @@ -7110,18 +6950,10 @@ for(;;) ENDLOOP: -#ifdef HEAP_MATCH_RECURSE -release_match_heapframes(&frame_zero, mb); -#endif - -/* Release any frames that were saved from recursions. */ +/* Release an enlarged frame vector that is on the heap. */ -while (mb->ovecsave_chain != NULL) - { - ovecsave_frame *this = mb->ovecsave_chain; - mb->ovecsave_chain = this->next; - mb->memctl.free(this, mb->memctl.memory_data); - } +if (mb->match_frames != mb->stack_frames) + mb->memctl.free(mb->match_frames, mb->memctl.memory_data); /* Fill in fields that are always returned in the match data. */ @@ -7130,68 +6962,14 @@ match_data->subject = subject; match_data->mark = mb->mark; match_data->matchedby = PCRE2_MATCHEDBY_INTERPRETER; -/* Handle a fully successful match. */ +/* Handle a fully successful match. Set the return code to the number of +captured strings, or 0 if there were too many to fit into the ovector, and then +set the remaining returned values before returning. */ -if (rc == MATCH_MATCH || rc == MATCH_ACCEPT) +if (rc == MATCH_MATCH) { - uint32_t arg_offset_max = 2 * match_data->oveccount; - - /* When the offset vector is big enough to deal with any backreferences, - captured substring offsets will already be set up. In the case where we had - to get some local memory to hold offsets for backreference processing, copy - those that we can. In this case there need not be overflow if certain parts - of the pattern were not used, even though there are more capturing - parentheses than vector slots. */ - - if (using_temporary_offsets) - { - if (arg_offset_max >= 4) - { - memcpy(match_data->ovector + 2, mb->ovector + 2, - (arg_offset_max - 2) * sizeof(PCRE2_SIZE)); - } - if (mb->end_offset_top > arg_offset_max) mb->capture_last |= OVFLBIT; - mb->memctl.free(mb->ovector, mb->memctl.memory_data); - } - - /* Set the return code to the number of captured strings, or 0 if there were - too many to fit into the ovector. */ - - match_data->rc = ((mb->capture_last & OVFLBIT) != 0)? - 0 : (int)mb->end_offset_top/2; - - /* If there is space in the offset vector, set any pairs that follow the - highest-numbered captured string but are less than the number of capturing - groups in the pattern (and are within the ovector) to PCRE2_UNSET. It is - documented that this happens. In earlier versions, the whole set of potential - capturing offsets was initialized each time round the loop, but this is - handled differently now. "Gaps" are set to PCRE2_UNSET dynamically instead - (this fixed a bug). Thus, it is only those at the end that need setting here. - We can't just mark them all unset at the start of the whole thing because - they may get set in one branch that is not the final matching branch. */ - - if (mb->end_offset_top/2 <= re->top_bracket) - { - PCRE2_SIZE *iptr, *iend; - int resetcount = re->top_bracket + 1; - if (resetcount > match_data->oveccount) resetcount = match_data->oveccount; - iptr = match_data->ovector + mb->end_offset_top; - iend = match_data->ovector + 2 * resetcount; - while (iptr < iend) *iptr++ = PCRE2_UNSET; - } - - /* If there is space, set up the whole thing as substring 0. The value of - mb->start_match_ptr might be modified if \K was encountered on the success - matching path. */ - - if (match_data->oveccount < 1) rc = 0; else - { - match_data->ovector[0] = mb->start_match_ptr - mb->start_subject; - match_data->ovector[1] = mb->end_match_ptr - mb->start_subject; - } - - /* Set the remaining returned values */ - + match_data->rc = ((int)mb->end_offset_top >= 2 * match_data->oveccount)? + 0 : (int)mb->end_offset_top/2 + 1; match_data->startchar = start_match - subject; match_data->leftchar = mb->start_used_ptr - subject; match_data->rightchar = ((mb->last_used_ptr > mb->end_match_ptr)? @@ -7207,18 +6985,14 @@ match_data->mark = mb->nomatch_mark; /* For anything other than nomatch or partial match, just return the code. */ -if (rc != MATCH_NOMATCH && rc != PCRE2_ERROR_PARTIAL) - match_data->rc = rc; +if (rc != MATCH_NOMATCH && rc != PCRE2_ERROR_PARTIAL) match_data->rc = rc; -/* Else handle a partial match. */ +/* Handle a partial match. */ else if (match_partial != NULL) { - if (match_data->oveccount > 0) - { - match_data->ovector[0] = match_partial - subject; - match_data->ovector[1] = end_subject - subject; - } + match_data->ovector[0] = match_partial - subject; + match_data->ovector[1] = end_subject - subject; match_data->startchar = match_partial - subject; match_data->leftchar = start_partial - subject; match_data->rightchar = end_subject - subject; @@ -7229,11 +7003,9 @@ else if (match_partial != NULL) else match_data->rc = PCRE2_ERROR_NOMATCH; -/* Free any temporary offsets. */ - -if (using_temporary_offsets) - mb->memctl.free(mb->ovector, mb->memctl.memory_data); return match_data->rc; } /* End of pcre2_match.c */ + +#pragma warning(pop) diff --git a/ProcessHacker/pcre/pcre2_match_data.c b/ProcessHacker/pcre/pcre2_match_data.c index 6e2e0a40c8d1..b297f326b556 100644 --- a/ProcessHacker/pcre/pcre2_match_data.c +++ b/ProcessHacker/pcre/pcre2_match_data.c @@ -7,7 +7,7 @@ and semantics are as close as possible to those of the Perl 5 language. Written by Philip Hazel Original API code Copyright (c) 1997-2012 University of Cambridge - New API code Copyright (c) 2016 University of Cambridge + New API code Copyright (c) 2016-2017 University of Cambridge ----------------------------------------------------------------------------- Redistribution and use in source and binary forms, with or without @@ -38,7 +38,6 @@ POSSIBILITY OF SUCH DAMAGE. ----------------------------------------------------------------------------- */ -#define HAVE_CONFIG_H #ifdef HAVE_CONFIG_H #include "config.h" @@ -52,7 +51,7 @@ POSSIBILITY OF SUCH DAMAGE. * Create a match data block given ovector size * *************************************************/ -/* A minimum of 1 is imposed on the number of ovector triplets. */ +/* A minimum of 1 is imposed on the number of ovector pairs. */ PCRE2_EXP_DEFN pcre2_match_data * PCRE2_CALL_CONVENTION pcre2_match_data_create(uint32_t oveccount, pcre2_general_context *gcontext) @@ -60,7 +59,7 @@ pcre2_match_data_create(uint32_t oveccount, pcre2_general_context *gcontext) pcre2_match_data *yield; if (oveccount < 1) oveccount = 1; yield = PRIV(memctl_malloc)( - sizeof(pcre2_match_data) + 3*oveccount*sizeof(PCRE2_SIZE), + offsetof(pcre2_match_data, ovector) + 2*oveccount*sizeof(PCRE2_SIZE), (pcre2_memctl *)gcontext); if (yield == NULL) return NULL; yield->oveccount = oveccount; diff --git a/ProcessHacker/pcre/pcre2_newline.c b/ProcessHacker/pcre/pcre2_newline.c index 1d22666380bb..6e9366db93c6 100644 --- a/ProcessHacker/pcre/pcre2_newline.c +++ b/ProcessHacker/pcre/pcre2_newline.c @@ -47,7 +47,6 @@ only NLTYPE_FIXED, which gets handled without these functions, NLTYPE_ANYCRLF, and NLTYPE_ANY. The full list of Unicode newline characters is taken from http://unicode.org/unicode/reports/tr18/. */ -#define HAVE_CONFIG_H #ifdef HAVE_CONFIG_H #include "config.h" diff --git a/ProcessHacker/pcre/pcre2_ord2utf.c b/ProcessHacker/pcre/pcre2_ord2utf.c index 07ab10fda25f..1403730996d6 100644 --- a/ProcessHacker/pcre/pcre2_ord2utf.c +++ b/ProcessHacker/pcre/pcre2_ord2utf.c @@ -39,8 +39,6 @@ POSSIBILITY OF SUCH DAMAGE. */ -#define HAVE_CONFIG_H - /* This file contains a function that converts a Unicode character code point into a UTF string. The behaviour is different for each code unit width. */ diff --git a/ProcessHacker/pcre/pcre2_pattern_info.c b/ProcessHacker/pcre/pcre2_pattern_info.c index fadad4b324a2..540707b2258c 100644 --- a/ProcessHacker/pcre/pcre2_pattern_info.c +++ b/ProcessHacker/pcre/pcre2_pattern_info.c @@ -7,7 +7,7 @@ and semantics are as close as possible to those of the Perl 5 language. Written by Philip Hazel Original API code Copyright (c) 1997-2012 University of Cambridge - New API code Copyright (c) 2016 University of Cambridge + New API code Copyright (c) 2016-2017 University of Cambridge ----------------------------------------------------------------------------- Redistribution and use in source and binary forms, with or without @@ -39,8 +39,6 @@ POSSIBILITY OF SUCH DAMAGE. */ -#define HAVE_CONFIG_H - #ifdef HAVE_CONFIG_H #include "config.h" #endif @@ -77,10 +75,12 @@ if (where == NULL) /* Requests field length */ case PCRE2_INFO_BACKREFMAX: case PCRE2_INFO_BSR: case PCRE2_INFO_CAPTURECOUNT: + case PCRE2_INFO_DEPTHLIMIT: case PCRE2_INFO_FIRSTCODETYPE: case PCRE2_INFO_FIRSTCODEUNIT: case PCRE2_INFO_HASBACKSLASHC: case PCRE2_INFO_HASCRORLF: + case PCRE2_INFO_HEAPLIMIT: case PCRE2_INFO_JCHANGED: case PCRE2_INFO_LASTCODETYPE: case PCRE2_INFO_LASTCODEUNIT: @@ -91,7 +91,6 @@ if (where == NULL) /* Requests field length */ case PCRE2_INFO_NAMEENTRYSIZE: case PCRE2_INFO_NAMECOUNT: case PCRE2_INFO_NEWLINE: - case PCRE2_INFO_RECURSIONLIMIT: return sizeof(uint32_t); case PCRE2_INFO_FIRSTBITMAP: @@ -99,6 +98,7 @@ if (where == NULL) /* Requests field length */ case PCRE2_INFO_JITSIZE: case PCRE2_INFO_SIZE: + case PCRE2_INFO_FRAMESIZE: return sizeof(size_t); case PCRE2_INFO_NAMETABLE: @@ -139,6 +139,11 @@ switch(what) *((uint32_t *)where) = re->top_bracket; break; + case PCRE2_INFO_DEPTHLIMIT: + *((uint32_t *)where) = re->limit_depth; + if (re->limit_depth == UINT32_MAX) return PCRE2_ERROR_UNSET; + break; + case PCRE2_INFO_FIRSTCODETYPE: *((uint32_t *)where) = ((re->flags & PCRE2_FIRSTSET) != 0)? 1 : ((re->flags & PCRE2_STARTLINE) != 0)? 2 : 0; @@ -154,6 +159,11 @@ switch(what) &(re->start_bitmap[0]) : NULL; break; + case PCRE2_INFO_FRAMESIZE: + *((size_t *)where) = offsetof(heapframe, ovector) + + re->top_bracket * 2 * sizeof(PCRE2_SIZE); + break; + case PCRE2_INFO_HASBACKSLASHC: *((uint32_t *)where) = (re->flags & PCRE2_HASBKC) != 0; break; @@ -162,6 +172,11 @@ switch(what) *((uint32_t *)where) = (re->flags & PCRE2_HASCRORLF) != 0; break; + case PCRE2_INFO_HEAPLIMIT: + *((uint32_t *)where) = re->limit_heap; + if (re->limit_heap == UINT32_MAX) return PCRE2_ERROR_UNSET; + break; + case PCRE2_INFO_JCHANGED: *((uint32_t *)where) = (re->flags & PCRE2_JCHANGED) != 0; break; @@ -217,11 +232,6 @@ switch(what) *((uint32_t *)where) = re->newline_convention; break; - case PCRE2_INFO_RECURSIONLIMIT: - *((uint32_t *)where) = re->limit_recursion; - if (re->limit_recursion == UINT32_MAX) return PCRE2_ERROR_UNSET; - break; - case PCRE2_INFO_SIZE: *((size_t *)where) = re->blocksize; break; @@ -257,11 +267,15 @@ pcre2_real_code *re = (pcre2_real_code *)code; pcre2_callout_enumerate_block cb; PCRE2_SPTR cc; #ifdef SUPPORT_UNICODE -BOOL utf = (re->overall_options & PCRE2_UTF) != 0; +BOOL utf; #endif if (re == NULL) return PCRE2_ERROR_NULL; +#ifdef SUPPORT_UNICODE +utf = (re->overall_options & PCRE2_UTF) != 0; +#endif + /* Check that the first field in the block is the magic number. If it is not, return with PCRE2_ERROR_BADMAGIC. */ diff --git a/ProcessHacker/pcre/pcre2_printint.c b/ProcessHacker/pcre/pcre2_printint.c index 62074976489b..e4dd53fe8ca0 100644 --- a/ProcessHacker/pcre/pcre2_printint.c +++ b/ProcessHacker/pcre/pcre2_printint.c @@ -7,7 +7,7 @@ and semantics are as close as possible to those of the Perl 5 language. Written by Philip Hazel Original API code Copyright (c) 1997-2012 University of Cambridge - New API code Copyright (c) 2016 University of Cambridge + New API code Copyright (c) 2016-2017 University of Cambridge ----------------------------------------------------------------------------- Redistribution and use in source and binary forms, with or without @@ -340,7 +340,7 @@ for(;;) case OP_TABLE_LENGTH + ((sizeof(OP_names)/sizeof(const char *) == OP_TABLE_LENGTH) && (sizeof(OP_lengths) == OP_TABLE_LENGTH)): - break; + return; /* ========================================================================== */ case OP_END: @@ -393,7 +393,6 @@ for(;;) case OP_ASSERTBACK: case OP_ASSERTBACK_NOT: case OP_ONCE: - case OP_ONCE_NC: case OP_COND: case OP_SCOND: case OP_REVERSE: diff --git a/ProcessHacker/pcre/pcre2_serialize.c b/ProcessHacker/pcre/pcre2_serialize.c index 41d36a910c4a..d2cc603cbb5b 100644 --- a/ProcessHacker/pcre/pcre2_serialize.c +++ b/ProcessHacker/pcre/pcre2_serialize.c @@ -7,7 +7,7 @@ and semantics are as close as possible to those of the Perl 5 language. Written by Philip Hazel Original API code Copyright (c) 1997-2012 University of Cambridge - New API code Copyright (c) 2016 University of Cambridge + New API code Copyright (c) 2016-2017 University of Cambridge ----------------------------------------------------------------------------- Redistribution and use in source and binary forms, with or without @@ -41,7 +41,6 @@ POSSIBILITY OF SUCH DAMAGE. /* This module contains functions for serializing and deserializing a sequence of compiled codes. */ -#define HAVE_CONFIG_H #ifdef HAVE_CONFIG_H #include "config.h" @@ -215,7 +214,10 @@ for (i = 0; i < number_of_codes; i++) if (dst_re->magic_number != MAGIC_NUMBER || dst_re->name_entry_size > MAX_NAME_SIZE + IMM2_SIZE + 1 || dst_re->name_count > MAX_NAME_COUNT) + { + memctl->free(dst_re, memctl->memory_data); return PCRE2_ERROR_BADSERIALIZEDDATA; + } /* At the moment only one table is supported. */ diff --git a/ProcessHacker/pcre/pcre2_string_utils.c b/ProcessHacker/pcre/pcre2_string_utils.c index f3666460bd78..2a1f282629ab 100644 --- a/ProcessHacker/pcre/pcre2_string_utils.c +++ b/ProcessHacker/pcre/pcre2_string_utils.c @@ -42,7 +42,6 @@ POSSIBILITY OF SUCH DAMAGE. of strings. These are used instead of strcmp() etc because the standard functions work only on 8-bit data. */ -#define HAVE_CONFIG_H #ifdef HAVE_CONFIG_H #include "config.h" diff --git a/ProcessHacker/pcre/pcre2_study.c b/ProcessHacker/pcre/pcre2_study.c index d6403dccb0bb..b92686759dac 100644 --- a/ProcessHacker/pcre/pcre2_study.c +++ b/ProcessHacker/pcre/pcre2_study.c @@ -7,7 +7,7 @@ and semantics are as close as possible to those of the Perl 5 language. Written by Philip Hazel Original API code Copyright (c) 1997-2012 University of Cambridge - New API code Copyright (c) 2016 University of Cambridge + New API code Copyright (c) 2016-2017 University of Cambridge ----------------------------------------------------------------------------- Redistribution and use in source and binary forms, with or without @@ -42,15 +42,12 @@ POSSIBILITY OF SUCH DAMAGE. collecting data (e.g. minimum matching length). */ -#define HAVE_CONFIG_H #ifdef HAVE_CONFIG_H #include "config.h" #endif - #include "pcre2_internal.h" - /* The maximum remembered capturing brackets minimum. */ #define MAX_CACHE_BACKREF 128 @@ -159,12 +156,12 @@ for (;;) } goto PROCESS_NON_CAPTURE; - /* There's a special case of OP_ONCE, when it is wrapped round an + case OP_BRA: + /* There's a special case of OP_BRA, when it is wrapped round a repeated OP_RECURSE. We'd like to process the latter at this level so that remembering the value works for repeated cases. So we do nothing, but set a fudge value to skip over the OP_KET after the recurse. */ - case OP_ONCE: if (cc[1+LINK_SIZE] == OP_RECURSE && cc[2*(1+LINK_SIZE)] == OP_KET) { once_fudge = 1 + LINK_SIZE; @@ -173,8 +170,7 @@ for (;;) } /* Fall through */ - case OP_ONCE_NC: - case OP_BRA: + case OP_ONCE: case OP_SBRA: case OP_BRAPOS: case OP_SBRAPOS: @@ -790,6 +786,7 @@ if (utf) if (caseless) { +#ifdef SUPPORT_UNICODE if (utf) { #if PCRE2_CODE_UNIT_WIDTH == 8 @@ -802,10 +799,12 @@ if (caseless) if (c > 0xff) SET_BIT(0xff); else SET_BIT(c); #endif } + else +#endif /* SUPPORT_UNICODE */ /* Not UTF */ - else if (MAX_255(c)) SET_BIT(re->tables[fcc_offset + c]); + if (MAX_255(c)) SET_BIT(re->tables[fcc_offset + c]); } return p; @@ -954,7 +953,6 @@ do case OP_ALLANY: case OP_ANY: case OP_ANYBYTE: - case OP_CIRC: case OP_CIRCM: case OP_CLOSE: case OP_COMMIT: @@ -1022,6 +1020,13 @@ do case OP_THEN_ARG: return SSB_FAIL; + /* OP_CIRC happens only at the start of an anchored branch (multiline ^ + uses OP_CIRCM). Skip over it. */ + + case OP_CIRC: + tcode += PRIV(OP_lengths)[OP_CIRC]; + break; + /* A "real" property test implies no starting bits, but the fake property PT_CLIST identifies a list of characters. These lists are short, as they are used for characters with more than one "other case", so there is no @@ -1068,7 +1073,6 @@ do case OP_CBRAPOS: case OP_SCBRAPOS: case OP_ONCE: - case OP_ONCE_NC: case OP_ASSERT: rc = set_start_bits(re, tcode, utf); if (rc == SSB_FAIL || rc == SSB_UNKNOWN) return rc; @@ -1450,6 +1454,10 @@ do classmap = ((tcode[1 + LINK_SIZE] & XCL_MAP) == 0)? NULL : (uint8_t *)(tcode + 1 + LINK_SIZE + 1); #endif + /* It seems that the fall through comment must be outside the #ifdef if + it is to avoid the gcc compiler warning. */ + + /* Fall through */ /* Enter here for a negative non-XCLASS. In the 8-bit library, if we are in UTF mode, any byte with a value >= 0xc4 is a potentially valid starter @@ -1577,12 +1585,11 @@ BOOL utf = (re->overall_options & PCRE2_UTF) != 0; code = (PCRE2_UCHAR *)((uint8_t *)re + sizeof(pcre2_real_code)) + re->name_entry_size * re->name_count; -/* For an anchored pattern, or an unanchored pattern that has a first code -unit, or a multiline pattern that matches only at "line start", there is no -point in seeking a list of starting code units. */ +/* For a pattern that has a first code unit, or a multiline pattern that +matches only at "line start", there is no point in seeking a list of starting +code units. */ -if ((re->overall_options & PCRE2_ANCHORED) == 0 && - (re->flags & (PCRE2_FIRSTSET|PCRE2_STARTLINE)) == 0) +if ((re->flags & (PCRE2_FIRSTSET|PCRE2_STARTLINE)) == 0) { int rc = set_start_bits(re, code, utf); if (rc == SSB_UNKNOWN) return 1; diff --git a/ProcessHacker/pcre/pcre2_substitute.c b/ProcessHacker/pcre/pcre2_substitute.c index c828e307f643..8da951fc6e2a 100644 --- a/ProcessHacker/pcre/pcre2_substitute.c +++ b/ProcessHacker/pcre/pcre2_substitute.c @@ -39,7 +39,6 @@ POSSIBILITY OF SUCH DAMAGE. */ -#define HAVE_CONFIG_H #ifdef HAVE_CONFIG_H #include "config.h" #endif diff --git a/ProcessHacker/pcre/pcre2_substring.c b/ProcessHacker/pcre/pcre2_substring.c index bee84b1d8e73..f6d7c3972270 100644 --- a/ProcessHacker/pcre/pcre2_substring.c +++ b/ProcessHacker/pcre/pcre2_substring.c @@ -38,7 +38,7 @@ POSSIBILITY OF SUCH DAMAGE. ----------------------------------------------------------------------------- */ -#define HAVE_CONFIG_H + #ifdef HAVE_CONFIG_H #include "config.h" #endif diff --git a/ProcessHacker/pcre/pcre2_tables.c b/ProcessHacker/pcre/pcre2_tables.c index be0c101bc226..9f8dc293aa22 100644 --- a/ProcessHacker/pcre/pcre2_tables.c +++ b/ProcessHacker/pcre/pcre2_tables.c @@ -7,7 +7,7 @@ and semantics are as close as possible to those of the Perl 5 language. Written by Philip Hazel Original API code Copyright (c) 1997-2012 University of Cambridge - New API code Copyright (c) 2016 University of Cambridge + New API code Copyright (c) 2016-2017 University of Cambridge ----------------------------------------------------------------------------- Redistribution and use in source and binary forms, with or without @@ -39,12 +39,11 @@ POSSIBILITY OF SUCH DAMAGE. */ /* This module contains some fixed tables that are used by more than one of the -PCRE code modules. The tables are also #included by the pcre2test program, +PCRE2 code modules. The tables are also #included by the pcre2test program, which uses macros to change their names from _pcre2_xxx to xxxx, thereby avoiding name clashes with the library. In this case, PCRE2_PCRE2TEST is defined. */ -#define HAVE_CONFIG_H #ifndef PCRE2_PCRE2TEST /* We're compiling the library */ #ifdef HAVE_CONFIG_H #include "config.h" @@ -149,7 +148,7 @@ two code points. The breaking rules are as follows: 1. Break at the start and end of text (pretty obviously). -2. Do not break between a CR and LF; otherwise, break before and after +2. Do not break between a CR and LF; otherwise, break before and after controls. 3. Do not break Hangul syllable sequences, the rules for which are: @@ -158,44 +157,62 @@ two code points. The breaking rules are as follows: LV or V may be followed by V or T LVT or T may be followed by T -4. Do not break before extending characters. +4. Do not break before extending characters or zero-width-joiner (ZWJ). -The next two rules are only for extended grapheme clusters (but that's what we +The following rules are only for extended grapheme clusters (but that's what we are implementing). 5. Do not break before SpacingMarks. 6. Do not break after Prepend characters. -7. Otherwise, break everywhere. +7. Do not break within emoji modifier sequences (E_Base or E_Base_GAZ followed + by E_Modifier). Extend characters are allowed before the modifier; this + cannot be represented in this table, the code has to deal with it. + +8. Do not break within emoji zwj sequences (ZWJ followed by Glue_After_Zwj or + E_Base_GAZ). + +9. Do not break within emoji flag sequences. That is, do not break between + regional indicator (RI) symbols if there are an odd number of RI characters + before the break point. This table encodes "join RI characters"; the code + has to deal with checking for previous adjoining RIs. + +10. Otherwise, break everywhere. */ +#define ESZ (1< 0; p++) if (c < 0xc0) /* Isolated 10xx xxxx byte */ { - *erroroffset = (int)(p - string); + *erroroffset = (PCRE2_SIZE)(p - string); return PCRE2_ERROR_UTF8_ERR20; } if (c >= 0xfe) /* Invalid 0xfe or 0xff bytes */ { - *erroroffset = (int)(p - string); + *erroroffset = (PCRE2_SIZE)(p - string); return PCRE2_ERROR_UTF8_ERR21; } ab = PRIV(utf8_table4)[c & 0x3f]; /* Number of additional bytes (1-5) */ if (length < ab) /* Missing bytes */ { - *erroroffset = (int)(p - string); + *erroroffset = (PCRE2_SIZE)(p - string); switch(ab - length) { case 1: return PCRE2_ERROR_UTF8_ERR1; diff --git a/ProcessHacker/pcre/pcre2_xclass.c b/ProcessHacker/pcre/pcre2_xclass.c index 43d0150e7554..407d3f5b8796 100644 --- a/ProcessHacker/pcre/pcre2_xclass.c +++ b/ProcessHacker/pcre/pcre2_xclass.c @@ -43,7 +43,6 @@ class. It is used by pcre2_auto_possessify() and by both pcre2_match() and pcre2_def_match(). */ -#define HAVE_CONFIG_H #ifdef HAVE_CONFIG_H #include "config.h" #endif diff --git a/ProcessHacker/pcre/pcre2posix.c b/ProcessHacker/pcre/pcre2posix.c index 343b835aa216..908f91cded92 100644 --- a/ProcessHacker/pcre/pcre2posix.c +++ b/ProcessHacker/pcre/pcre2posix.c @@ -44,8 +44,7 @@ functions. */ // dmex: Disable warnings. #pragma warning(push) -#pragma warning(disable : 4267) -#define HAVE_CONFIG_H +#pragma warning(disable : 4267) #ifdef HAVE_CONFIG_H #include "config.h" @@ -102,7 +101,7 @@ PCRE2_CALL_CONVENTION just before their names. It is rarely needed; if not set, we ensure here that it has no effect. */ #ifndef PCRE2_CALL_CONVENTION -#define PCRE2_CALL_CONVENTION +#define PCRE2_CALL_CONVENTION #endif /* Table to translate PCRE2 compile time error codes into POSIX error codes. @@ -146,6 +145,7 @@ static const int eint2[] = { 32, REG_INVARG, /* this version of PCRE2 does not have Unicode support */ 37, REG_EESCAPE, /* PCRE2 does not support \L, \l, \N{name}, \U, or \u */ 56, REG_INVARG, /* internal error: unknown newline setting */ + 92, REG_INVARG, /* invalid option bits with PCRE2_LITERAL */ }; /* Table of texts corresponding to POSIX error codes */ @@ -235,20 +235,25 @@ PCRE2POSIX_EXP_DEFN int PCRE2_CALL_CONVENTION regcomp(regex_t *preg, const char *pattern, int cflags) { PCRE2_SIZE erroffset; +PCRE2_SIZE patlen; int errorcode; int options = 0; int re_nsub = 0; +patlen = ((cflags & REG_PEND) != 0)? (PCRE2_SIZE)(preg->re_endp - pattern) : + PCRE2_ZERO_TERMINATED; + if ((cflags & REG_ICASE) != 0) options |= PCRE2_CASELESS; if ((cflags & REG_NEWLINE) != 0) options |= PCRE2_MULTILINE; if ((cflags & REG_DOTALL) != 0) options |= PCRE2_DOTALL; +if ((cflags & REG_NOSPEC) != 0) options |= PCRE2_LITERAL; if ((cflags & REG_UTF) != 0) options |= PCRE2_UTF; if ((cflags & REG_UCP) != 0) options |= PCRE2_UCP; if ((cflags & REG_UNGREEDY) != 0) options |= PCRE2_UNGREEDY; preg->re_cflags = cflags; -preg->re_pcre2_code = pcre2_compile((PCRE2_SPTR)pattern, PCRE2_ZERO_TERMINATED, - options, &errorcode, &erroffset, NULL); +preg->re_pcre2_code = pcre2_compile((PCRE2_SPTR)pattern, patlen, options, + &errorcode, &erroffset, NULL); preg->re_erroffset = erroffset; if (preg->re_pcre2_code == NULL) @@ -263,7 +268,7 @@ if (preg->re_pcre2_code == NULL) if (errorcode < (int)(sizeof(eint1)/sizeof(const int))) return eint1[errorcode]; - for (i = 0; i < sizeof(eint2)/(2*sizeof(const int)); i += 2) + for (i = 0; i < sizeof(eint2)/sizeof(const int); i += 2) if (errorcode == eint2[i]) return eint2[i+1]; return REG_BADPAT; } @@ -342,8 +347,8 @@ if (rc >= 0) if ((size_t)rc > nmatch) rc = (int)nmatch; for (i = 0; i < (size_t)rc; i++) { - pmatch[i].rm_so = ovector[i*2]; - pmatch[i].rm_eo = ovector[i*2+1]; + pmatch[i].rm_so = ovector[i*2] + so; + pmatch[i].rm_eo = ovector[i*2+1] + so; } for (; i < nmatch; i++) pmatch[i].rm_so = pmatch[i].rm_eo = -1; return 0; diff --git a/ProcessHacker/pcre/pcre2posix.h b/ProcessHacker/pcre/pcre2posix.h index 6505976aa493..4ae1d3c2a051 100644 --- a/ProcessHacker/pcre/pcre2posix.h +++ b/ProcessHacker/pcre/pcre2posix.h @@ -62,6 +62,8 @@ extern "C" { #define REG_NOTEMPTY 0x0100 /* NOT defined by POSIX; maps to PCRE2_NOTEMPTY */ #define REG_UNGREEDY 0x0200 /* NOT defined by POSIX; maps to PCRE2_UNGREEDY */ #define REG_UCP 0x0400 /* NOT defined by POSIX; maps to PCRE2_UCP */ +#define REG_PEND 0x0800 /* GNU feature: pass end pattern by re_endp */ +#define REG_NOSPEC 0x1000 /* Maps to PCRE2_LITERAL */ /* This is not used by PCRE2, but by defining it we make it easier to slot PCRE2 into existing programs that make POSIX calls. */ @@ -91,11 +93,13 @@ enum { }; -/* The structure representing a compiled regular expression. */ +/* The structure representing a compiled regular expression. It is also used +for passing the pattern end pointer when REG_PEND is set. */ typedef struct { void *re_pcre2_code; void *re_match_data; + const char *re_endp; size_t re_nsub; size_t re_erroffset; int re_cflags; From 672659157bf8659da4a422b5faed16f6d6f0d67a Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 3 Dec 2017 13:18:44 +1100 Subject: [PATCH 0604/2058] Add temporary workaround for extra mitigation options --- ProcessHacker/mtgndlg.c | 199 +++++++++++++++++++++++++++++++++++----- ProcessHacker/prpggen.c | 22 +---- 2 files changed, 177 insertions(+), 44 deletions(-) diff --git a/ProcessHacker/mtgndlg.c b/ProcessHacker/mtgndlg.c index 164152b0f52f..80317341f046 100644 --- a/ProcessHacker/mtgndlg.c +++ b/ProcessHacker/mtgndlg.c @@ -3,6 +3,7 @@ * process mitigation policy details * * Copyright (C) 2016 wj32 + * Copyright (C) 2016-2017 dmex * * This file is part of Process Hacker. * @@ -26,12 +27,15 @@ typedef struct _MITIGATION_POLICY_ENTRY { + BOOLEAN NonStandard; PPH_STRING ShortDescription; PPH_STRING LongDescription; } MITIGATION_POLICY_ENTRY, *PMITIGATION_POLICY_ENTRY; typedef struct _MITIGATION_POLICY_CONTEXT { + HWND ListViewHandle; + PPS_SYSTEM_DLL_INIT_BLOCK SystemDllInitBlock; MITIGATION_POLICY_ENTRY Entries[MaxProcessMitigationPolicy]; } MITIGATION_POLICY_CONTEXT, *PMITIGATION_POLICY_CONTEXT; @@ -42,44 +46,127 @@ INT_PTR CALLBACK PhpProcessMitigationPolicyDlgProc( _In_ LPARAM lParam ); +NTSTATUS PhpGetProcessSystemDllInitBlock( + _In_ HANDLE ProcessHandle, + _Out_ PPS_SYSTEM_DLL_INIT_BLOCK *SystemDllInitBlock + ) +{ + NTSTATUS status; + PPS_SYSTEM_DLL_INIT_BLOCK ldrInitBlock = NULL; + PVOID ldrInitBlockBaseAddress = NULL; + PPH_STRING ntdllFileName; + + ldrInitBlock = PhAllocate(sizeof(PS_SYSTEM_DLL_INIT_BLOCK)); + memset(ldrInitBlock, 0, sizeof(PS_SYSTEM_DLL_INIT_BLOCK)); + + ntdllFileName = PhConcatStrings2(USER_SHARED_DATA->NtSystemRoot, L"\\System32\\ntdll.dll"); + status = PhGetProcedureAddressRemote( + ProcessHandle, + ntdllFileName->Buffer, + "LdrSystemDllInitBlock", + 0, + &ldrInitBlockBaseAddress, + NULL + ); + + PhDereferenceObject(ntdllFileName); + + if (NT_SUCCESS(status) && ldrInitBlockBaseAddress) + { + status = NtReadVirtualMemory( + ProcessHandle, + ldrInitBlockBaseAddress, + ldrInitBlock, + sizeof(PS_SYSTEM_DLL_INIT_BLOCK), + NULL + ); + } + + if (NT_SUCCESS(status)) + { + *SystemDllInitBlock = ldrInitBlock; + } + + return status; +} + VOID PhShowProcessMitigationPolicyDialog( _In_ HWND ParentWindowHandle, - _In_ struct _PH_PROCESS_MITIGATION_POLICY_ALL_INFORMATION *Information + _In_ HANDLE ProcessId ) { + NTSTATUS status; + HANDLE processHandle; + PH_PROCESS_MITIGATION_POLICY_ALL_INFORMATION information; MITIGATION_POLICY_CONTEXT context; PROCESS_MITIGATION_POLICY policy; PPH_STRING shortDescription; PPH_STRING longDescription; + memset(&context, 0, sizeof(MITIGATION_POLICY_CONTEXT)); memset(&context.Entries, 0, sizeof(context.Entries)); - for (policy = 0; policy < MaxProcessMitigationPolicy; policy++) + if (NT_SUCCESS(status = PhOpenProcess( + &processHandle, + PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, + ProcessId + ))) { - if (Information->Pointers[policy] && PhDescribeProcessMitigationPolicy( - policy, - Information->Pointers[policy], - &shortDescription, - &longDescription - )) + PPS_SYSTEM_DLL_INIT_BLOCK dllInitBlock; + + if (NT_SUCCESS(PhpGetProcessSystemDllInitBlock(processHandle, &dllInitBlock))) { - context.Entries[policy].ShortDescription = shortDescription; - context.Entries[policy].LongDescription = longDescription; + context.SystemDllInitBlock = dllInitBlock; } + + NtClose(processHandle); } - DialogBoxParam( - PhInstanceHandle, - MAKEINTRESOURCE(IDD_MITIGATION), - ParentWindowHandle, - PhpProcessMitigationPolicyDlgProc, - (LPARAM)&context - ); + if (NT_SUCCESS(status = PhOpenProcess( + &processHandle, + PROCESS_QUERY_INFORMATION, + ProcessId + ))) + { + if (NT_SUCCESS(PhGetProcessMitigationPolicy(processHandle, &information))) + { + for (policy = 0; policy < MaxProcessMitigationPolicy; policy++) + { + if (information.Pointers[policy] && PhDescribeProcessMitigationPolicy( + policy, + information.Pointers[policy], + &shortDescription, + &longDescription + )) + { + context.Entries[policy].ShortDescription = shortDescription; + context.Entries[policy].LongDescription = longDescription; + } + } + + DialogBoxParam( + PhInstanceHandle, + MAKEINTRESOURCE(IDD_MITIGATION), + ParentWindowHandle, + PhpProcessMitigationPolicyDlgProc, + (LPARAM)&context + ); + + for (policy = 0; policy < MaxProcessMitigationPolicy; policy++) + { + PhClearReference(&context.Entries[policy].ShortDescription); + PhClearReference(&context.Entries[policy].LongDescription); + } + } + + if (context.SystemDllInitBlock) + PhFree(context.SystemDllInitBlock); - for (policy = 0; policy < MaxProcessMitigationPolicy; policy++) + NtClose(processHandle); + } + else { - PhClearReference(&context.Entries[policy].ShortDescription); - PhClearReference(&context.Entries[policy].LongDescription); + PhShowStatus(ParentWindowHandle, L"Unable to open the process", status, 0); } } @@ -90,16 +177,36 @@ INT_PTR CALLBACK PhpProcessMitigationPolicyDlgProc( _In_ LPARAM lParam ) { + PMITIGATION_POLICY_CONTEXT context = NULL; + + if (uMsg == WM_INITDIALOG) + { + context = (PMITIGATION_POLICY_CONTEXT)lParam; + SetProp(hwndDlg, L"Context", (HANDLE)context); + } + else + { + context = (PMITIGATION_POLICY_CONTEXT)GetProp(hwndDlg, L"Context"); + + if (uMsg == WM_DESTROY) + { + RemoveProp(hwndDlg, L"Context"); + } + } + + if (context == NULL) + return FALSE; + + switch (uMsg) { case WM_INITDIALOG: { - PMITIGATION_POLICY_CONTEXT context = (PMITIGATION_POLICY_CONTEXT)lParam; HWND lvHandle; PROCESS_MITIGATION_POLICY policy; PhCenterWindow(hwndDlg, GetParent(hwndDlg)); - lvHandle = GetDlgItem(hwndDlg, IDC_LIST); + context->ListViewHandle = lvHandle = GetDlgItem(hwndDlg, IDC_LIST); PhSetListViewStyle(lvHandle, FALSE, TRUE); PhSetControlTheme(lvHandle, L"explorer"); PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 350, L"Policy"); @@ -115,6 +222,33 @@ INT_PTR CALLBACK PhpProcessMitigationPolicyDlgProc( PhAddListViewItem(lvHandle, MAXINT, entry->ShortDescription->Buffer, entry); } + if (context->SystemDllInitBlock) + { + if (context->SystemDllInitBlock->MitigationOptionsMap.Map[0] & PROCESS_CREATION_MITIGATION_POLICY2_LOADER_INTEGRITY_CONTINUITY_ALWAYS_ON) + { + PMITIGATION_POLICY_ENTRY entry; + + entry = PhAllocate(sizeof(MITIGATION_POLICY_ENTRY)); + entry->NonStandard = TRUE; + entry->ShortDescription = PhCreateString(L"Loader Integrity"); + entry->LongDescription = PhCreateString(L"OS signing levels for depenedent module loads are enabled."); + + PhAddListViewItem(lvHandle, MAXINT, entry->ShortDescription->Buffer, entry); + } + + if (context->SystemDllInitBlock->MitigationOptionsMap.Map[0] & PROCESS_CREATION_MITIGATION_POLICY2_MODULE_TAMPERING_PROTECTION_ALWAYS_ON) + { + PMITIGATION_POLICY_ENTRY entry; + + entry = PhAllocate(sizeof(MITIGATION_POLICY_ENTRY)); + entry->NonStandard = TRUE; + entry->ShortDescription = PhCreateString(L"Module Tampering"); + entry->LongDescription = PhCreateString(L"Module Tampering protection is enabled."); + + PhAddListViewItem(lvHandle, MAXINT, entry->ShortDescription->Buffer, entry); + } + } + ExtendedListView_SortItems(lvHandle); ExtendedListView_SetColumnWidth(lvHandle, 0, ELVSCW_AUTOSIZE_REMAININGSPACE); ListView_SetItemState(lvHandle, 0, LVIS_FOCUSED | LVIS_SELECTED, LVIS_FOCUSED | LVIS_SELECTED); @@ -123,7 +257,26 @@ INT_PTR CALLBACK PhpProcessMitigationPolicyDlgProc( break; case WM_DESTROY: { - // Nothing + ULONG index = -1; + + while ((index = PhFindListViewItemByFlags( + context->ListViewHandle, + index, + LVNI_ALL + )) != -1) + { + PMITIGATION_POLICY_ENTRY entry; + + if (PhGetListViewItemParam(context->ListViewHandle, index, &entry)) + { + if (entry->NonStandard) + { + PhClearReference(&entry->ShortDescription); + PhClearReference(&entry->LongDescription); + PhFree(entry); + } + } + } } break; case WM_COMMAND: diff --git a/ProcessHacker/prpggen.c b/ProcessHacker/prpggen.c index a6d288b7c7d9..ad5c5c54bac6 100644 --- a/ProcessHacker/prpggen.c +++ b/ProcessHacker/prpggen.c @@ -527,27 +527,7 @@ INT_PTR CALLBACK PhpProcessGeneralDlgProc( break; case IDC_VIEWMITIGATION: { - NTSTATUS status; - HANDLE processHandle; - PH_PROCESS_MITIGATION_POLICY_ALL_INFORMATION information; - - if (NT_SUCCESS(status = PhOpenProcess( - &processHandle, - PROCESS_QUERY_INFORMATION, - processItem->ProcessId - ))) - { - if (NT_SUCCESS(PhGetProcessMitigationPolicy(processHandle, &information))) - { - PhShowProcessMitigationPolicyDialog(hwndDlg, &information); - } - - NtClose(processHandle); - } - else - { - PhShowStatus(hwndDlg, L"Unable to open the process", status, 0); - } + PhShowProcessMitigationPolicyDialog(hwndDlg, processItem->ProcessId); } break; case IDC_TERMINATE: From c498bc0772554b0bedc37e9bf8c87e91e3345745 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 3 Dec 2017 13:23:22 +1100 Subject: [PATCH 0605/2058] Update header --- ProcessHacker/include/phapp.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ProcessHacker/include/phapp.h b/ProcessHacker/include/phapp.h index ab2ee920e15f..5c1740621268 100644 --- a/ProcessHacker/include/phapp.h +++ b/ProcessHacker/include/phapp.h @@ -482,7 +482,7 @@ VOID PhShowMemoryStringDialog( VOID PhShowProcessMitigationPolicyDialog( _In_ HWND ParentWindowHandle, - _In_ struct _PH_PROCESS_MITIGATION_POLICY_ALL_INFORMATION *Information + _In_ HANDLE ProcessId ); // netstk @@ -614,7 +614,7 @@ NTAPI PhCreateSearchControl( _In_ HWND Parent, _In_ HWND WindowHandle, - _In_ PWSTR BannerText + _In_opt_ PWSTR BannerText ); PHAPPAPI From d7524e366a5c619fefb18df0104434460144ff2c Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 4 Dec 2017 03:24:57 +1100 Subject: [PATCH 0606/2058] Add missing error case when editing environment variables --- ProcessHacker/prpgenv.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/ProcessHacker/prpgenv.c b/ProcessHacker/prpgenv.c index d81c73a68264..02d007c0610d 100644 --- a/ProcessHacker/prpgenv.c +++ b/ProcessHacker/prpgenv.c @@ -304,16 +304,25 @@ INT_PTR CALLBACK PhpProcessEnvironmentDlgProc( for (i = 0; i < numberOfIndices; i++) { item = PhItemArray(&environmentContext->Items, PtrToUlong(indices[i]) - 1); - PhSetEnvironmentVariableRemote(processHandle, &item->Name->sr, NULL, &timeout); + status = PhSetEnvironmentVariableRemote(processHandle, &item->Name->sr, NULL, &timeout); } NtClose(processHandle); PhpRefreshEnvironment(hwndDlg, environmentContext, processItem); + + if (!NT_SUCCESS(status)) + { + PhShowStatus(hwndDlg, L"Unable to delete the environment variable.", status, 0); + } + else if (status == STATUS_TIMEOUT) + { + PhShowStatus(hwndDlg, L"Unable to delete the environment variable.", 0, WAIT_TIMEOUT); + } } else { - PhShowStatus(hwndDlg, L"Unable to open the process", status, 0); + PhShowStatus(hwndDlg, L"Unable to open the process.", status, 0); } } @@ -543,7 +552,12 @@ INT_PTR CALLBACK PhpEditEnvDlgProc( if (!NT_SUCCESS(status)) { - PhShowStatus(hwndDlg, L"Unable to set the environment variable", status, 0); + PhShowStatus(hwndDlg, L"Unable to set the environment variable.", status, 0); + break; + } + else if (status == STATUS_TIMEOUT) + { + PhShowStatus(hwndDlg, L"Unable to delete the environment variable.", 0, WAIT_TIMEOUT); break; } From 2512bd079e33ce2164909a439663acee8d4c7922 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 4 Dec 2017 03:40:00 +1100 Subject: [PATCH 0607/2058] Fix stale token privileges after changing token integrity level --- ProcessHacker/tokprp.c | 96 +++++++++++++++++++++++++----------------- 1 file changed, 58 insertions(+), 38 deletions(-) diff --git a/ProcessHacker/tokprp.c b/ProcessHacker/tokprp.c index 3e6596d6b7f4..906bd4dc7222 100644 --- a/ProcessHacker/tokprp.c +++ b/ProcessHacker/tokprp.c @@ -389,7 +389,6 @@ BOOLEAN PhpUpdateTokenGroups( return FALSE; ExtendedListView_SetRedraw(GroupsLv, FALSE); - ListView_DeleteAllItems(GroupsLv); PhpUpdateSidsFromTokenGroups(GroupsLv, groups, FALSE); @@ -400,7 +399,6 @@ BOOLEAN PhpUpdateTokenGroups( } ExtendedListView_SortItems(GroupsLv); - ExtendedListView_SetRedraw(GroupsLv, TRUE); if (TokenPageContext->RestrictedSids) @@ -416,6 +414,59 @@ BOOLEAN PhpUpdateTokenGroups( return TRUE; } +BOOLEAN PhpUpdateTokenPrivileges( + _In_ HWND hwndDlg, + _In_ PTOKEN_PAGE_CONTEXT TokenPageContext, + _In_ HWND PrivilegesLv, + _In_ HANDLE TokenHandle + ) +{ + PTOKEN_PRIVILEGES privileges; + ULONG i; + + if (!NT_SUCCESS(PhGetTokenPrivileges(TokenHandle, &privileges))) + return FALSE; + + ExtendedListView_SetRedraw(PrivilegesLv, FALSE); + ListView_DeleteAllItems(PrivilegesLv); + + for (i = 0; i < privileges->PrivilegeCount; i++) + { + INT lvItemIndex; + PPH_STRING privilegeName; + PPH_STRING privilegeDisplayName; + + if (PhLookupPrivilegeName( + &privileges->Privileges[i].Luid, + &privilegeName + )) + { + privilegeDisplayName = NULL; + PhLookupPrivilegeDisplayName(&privilegeName->sr, &privilegeDisplayName); + + // Name + lvItemIndex = PhAddListViewItem(PrivilegesLv, MAXINT, privilegeName->Buffer, &privileges->Privileges[i]); + // Status + PhSetListViewSubItem(PrivilegesLv, lvItemIndex, 1, PhGetPrivilegeAttributesString(privileges->Privileges[i].Attributes)); + // Description + PhSetListViewSubItem(PrivilegesLv, lvItemIndex, 2, PhGetString(privilegeDisplayName)); + + if (privilegeDisplayName) PhDereferenceObject(privilegeDisplayName); + PhDereferenceObject(privilegeName); + } + } + + ExtendedListView_SortItems(PrivilegesLv); + ExtendedListView_SetRedraw(PrivilegesLv, TRUE); + + if (TokenPageContext->Privileges) + PhFree(TokenPageContext->Privileges); + + TokenPageContext->Privileges = privileges; + + return TRUE; +} + FORCEINLINE PTOKEN_PAGE_CONTEXT PhpTokenPageHeader( _In_ HWND hwndDlg, _In_ UINT uMsg, @@ -495,7 +546,6 @@ INT_PTR CALLBACK PhpTokenPageProc( BOOLEAN isVirtualizationEnabled; PTOKEN_APPCONTAINER_INFORMATION appContainerInfo; PPH_STRING appContainerSid; - ULONG i; if (NT_SUCCESS(PhGetTokenUser(tokenHandle, &tokenUser))) { @@ -570,40 +620,7 @@ INT_PTR CALLBACK PhpTokenPageProc( PhpUpdateTokenGroups(hwndDlg, tokenPageContext, groupsLv, tokenHandle); // Privileges - if (NT_SUCCESS(PhGetTokenPrivileges(tokenHandle, &tokenPageContext->Privileges))) - { - for (i = 0; i < tokenPageContext->Privileges->PrivilegeCount; i++) - { - INT lvItemIndex; - PPH_STRING privilegeName; - PPH_STRING privilegeDisplayName; - - if (PhLookupPrivilegeName( - &tokenPageContext->Privileges->Privileges[i].Luid, - &privilegeName - )) - { - privilegeDisplayName = NULL; - PhLookupPrivilegeDisplayName(&privilegeName->sr, &privilegeDisplayName); - - // Name - lvItemIndex = PhAddListViewItem(privilegesLv, MAXINT, privilegeName->Buffer, - &tokenPageContext->Privileges->Privileges[i]); - // Status - PhSetListViewSubItem(privilegesLv, lvItemIndex, 1, - PhGetPrivilegeAttributesString( - tokenPageContext->Privileges->Privileges[i].Attributes)); - // Description - PhSetListViewSubItem(privilegesLv, lvItemIndex, 2, - PhGetString(privilegeDisplayName)); - - if (privilegeDisplayName) PhDereferenceObject(privilegeDisplayName); - PhDereferenceObject(privilegeName); - } - } - - ExtendedListView_SortItems(privilegesLv); - } + PhpUpdateTokenPrivileges(hwndDlg, tokenPageContext, privilegesLv, tokenHandle); NtClose(tokenHandle); } @@ -903,7 +920,10 @@ INT_PTR CALLBACK PhpTokenPageProc( ); if (NT_SUCCESS(status)) - PhpUpdateTokenGroups(hwndDlg, tokenPageContext, GetDlgItem(hwndDlg, IDC_GROUPS), tokenHandle); + { + PhpUpdateTokenGroups(hwndDlg, tokenPageContext, tokenPageContext->GroupsListViewHandle, tokenHandle); + PhpUpdateTokenPrivileges(hwndDlg, tokenPageContext, tokenPageContext->PrivilegesListViewHandle, tokenHandle); + } NtClose(tokenHandle); } From ab7b45412a981cbea423955220c9927f1ee77c69 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 4 Dec 2017 04:19:22 +1100 Subject: [PATCH 0608/2058] UserNotes: Fix crash changing affinity settings, Fix changing affinity for system processes, Add extra error checking/messages --- plugins/UserNotes/main.c | 58 ++++++++++++++++++++++++++++++---------- 1 file changed, 44 insertions(+), 14 deletions(-) diff --git a/plugins/UserNotes/main.c b/plugins/UserNotes/main.c index 409f92957f66..06df65c71879 100644 --- a/plugins/UserNotes/main.c +++ b/plugins/UserNotes/main.c @@ -171,21 +171,23 @@ PPH_STRING SaveCustomColors( return PhFinalStringBuilderString(&stringBuilder); } -ULONG_PTR GetProcessAffinity( - _In_ HANDLE ProcessId +NTSTATUS GetProcessAffinity( + _In_ HANDLE ProcessId, + _Out_ ULONG_PTR *Affinity ) { + NTSTATUS status; HANDLE processHandle; ULONG_PTR affinityMask = 0; PROCESS_BASIC_INFORMATION basicInfo; - if (NT_SUCCESS(PhOpenProcess( + if (NT_SUCCESS(status = PhOpenProcess( &processHandle, ProcessQueryAccess, ProcessId ))) { - if (NT_SUCCESS(PhGetProcessBasicInformation( + if (NT_SUCCESS(status = PhGetProcessBasicInformation( processHandle, &basicInfo ))) @@ -196,7 +198,10 @@ ULONG_PTR GetProcessAffinity( NtClose(processHandle); } - return affinityMask; + if (NT_SUCCESS(status)) + *Affinity = affinityMask; + + return status; } IO_PRIORITY_HINT GetProcessIoPriority( @@ -438,7 +443,7 @@ VOID NTAPI MenuItemCallback( if (!highlightPresent) { CHOOSECOLOR chooseColor = { sizeof(CHOOSECOLOR) }; - chooseColor.hwndOwner = PhMainWndHandle; + chooseColor.hwndOwner = menuItem->OwnerWindow; chooseColor.lpCustColors = ProcessCustomColors; chooseColor.lpfnHook = ColorDlgHookProc; chooseColor.Flags = CC_ANYCOLOR | CC_FULLOPEN | CC_SOLIDCOLOR | CC_ENABLEHOOK; @@ -503,8 +508,18 @@ VOID NTAPI MenuItemCallback( } else { - object = CreateDbObject(FILE_TAG, &processItem->ProcessName->sr, NULL); - object->AffinityMask = GetProcessAffinity(processItem->ProcessId); + NTSTATUS status; + ULONG_PTR affinityMask; + + if (NT_SUCCESS(status = GetProcessAffinity(processItem->ProcessId, &affinityMask))) + { + object = CreateDbObject(FILE_TAG, &processItem->ProcessName->sr, NULL); + object->AffinityMask = affinityMask; + } + else + { + PhShowStatus(menuItem->OwnerWindow, L"Unable to query the process affinity.", status, 0); + } } UnlockDb(); @@ -524,8 +539,18 @@ VOID NTAPI MenuItemCallback( } else { - object = CreateDbObject(COMMAND_LINE_TAG, &processItem->CommandLine->sr, NULL); - object->AffinityMask = GetProcessAffinity(processItem->ProcessId); + NTSTATUS status; + ULONG_PTR affinityMask; + + if (NT_SUCCESS(status = GetProcessAffinity(processItem->ProcessId, &affinityMask))) + { + object = CreateDbObject(COMMAND_LINE_TAG, &processItem->CommandLine->sr, NULL); + object->AffinityMask = affinityMask; + } + else + { + PhShowStatus(menuItem->OwnerWindow, L"Unable to query the process affinity.", status, 0); + } } UnlockDb(); @@ -622,6 +647,7 @@ VOID NTAPI MenuHookCallback( break; case PHAPP_ID_PROCESS_AFFINITY: { + NTSTATUS status; BOOLEAN changed = FALSE; ULONG_PTR affinityMask; ULONG_PTR newAffinityMask; @@ -630,14 +656,18 @@ VOID NTAPI MenuHookCallback( if (!processItem) break; + // Query the current process affinity. + if (!NT_SUCCESS(status = GetProcessAffinity(processItem->ProcessId, &affinityMask))) + { + // TODO: Fix issue saving affinity for system processes. + break; + } + // Don't show the default Process Hacker affinity dialog. menuHookInfo->Handled = TRUE; - // Query the current process affinity. - affinityMask = GetProcessAffinity(processItem->ProcessId); - // Show the affinity dialog (with our values). - if (PhShowProcessAffinityDialog2(PhMainWndHandle, affinityMask, &newAffinityMask)) + if (PhShowProcessAffinityDialog2(menuHookInfo->MenuInfo->OwnerWindow, affinityMask, &newAffinityMask)) { PDB_OBJECT object; From 94789a8bcf82ad3f238a05ea0fc018f926659c86 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 4 Dec 2017 04:29:42 +1100 Subject: [PATCH 0609/2058] Fix error saving column sets #180 --- ProcessHacker/colsetmgr.c | 5 +++-- ProcessHacker/mainwnd.c | 3 +-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ProcessHacker/colsetmgr.c b/ProcessHacker/colsetmgr.c index 63c0617b6c55..901dd3628c4c 100644 --- a/ProcessHacker/colsetmgr.c +++ b/ProcessHacker/colsetmgr.c @@ -113,7 +113,7 @@ VOID PhSaveSettingsColumnList( PhRemoveEndStringBuilder(&stringBuilder, 1); settingsString = PH_AUTO(PhFinalStringBuilderString(&stringBuilder)); - PhSetStringSetting2(L"ProcessTreeColumnSetConfig", &settingsString->sr); + PhSetStringSetting2(SettingName, &settingsString->sr); } VOID PhDeleteColumnSetList( @@ -136,6 +136,7 @@ VOID PhDeleteColumnSetList( PhDereferenceObject(ColumnSetList); } +_Success_(return) BOOLEAN PhLoadSettingsColumnSet( _In_ PWSTR SettingName, _In_ PPH_STRING ColumnSetName, @@ -151,7 +152,7 @@ BOOLEAN PhLoadSettingsColumnSet( PH_STRINGREF remaining; PH_STRINGREF part; - settingsString = PhaGetStringSetting(L"ProcessTreeColumnSetConfig"); + settingsString = PhaGetStringSetting(SettingName); remaining = settingsString->sr; if (remaining.Length == 0) diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index c803890aa2ef..ad2de4ecbda7 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -2381,7 +2381,7 @@ VOID PhMwpDispatchMenuCommand( break; } - if (columnSetName) + if (!PhIsNullOrEmptyString(columnSetName)) { PPH_STRING treeSettings; PPH_STRING sortSettings; @@ -2393,7 +2393,6 @@ VOID PhMwpDispatchMenuCommand( PhDereferenceObject(treeSettings); PhDereferenceObject(sortSettings); - PhDereferenceObject(columnSetName); } } return; From 7853b856525252952f9e897ac807c1b114754dd7 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 4 Dec 2017 15:02:15 +1100 Subject: [PATCH 0610/2058] Fix race introduced from commit c63ad12d --- ProcessHacker/procprv.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ProcessHacker/procprv.c b/ProcessHacker/procprv.c index e65e512f4b8b..40b692dde21b 100644 --- a/ProcessHacker/procprv.c +++ b/ProcessHacker/procprv.c @@ -1179,8 +1179,6 @@ VOID PhpProcessQueryStage1( { Data->PackageFullName = PhGetProcessPackageFullName(processHandleLimited); } - - PhpQueueProcessQueryStage2(processItem); } VOID PhpProcessQueryStage2( @@ -1323,6 +1321,9 @@ VOID PhpFillProcessItemStage1( processItem->IsImmersive = Data->IsImmersive; PhSwapReference(&processItem->Record->CommandLine, processItem->CommandLine); + + // Note: Queue stage 2 processing after filling stage1 process data. + PhpQueueProcessQueryStage2(processItem); } VOID PhpFillProcessItemStage2( From f853e5930624ee0d0728084b716b4c166fcbf69d Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 10 Dec 2017 08:08:29 +1100 Subject: [PATCH 0611/2058] Add PhLoadAppKey, PhLoadString, PhLoadIndirectString helper functions --- ProcessHacker/ProcessHacker.def | 5 ++ phlib/include/phnative.h | 10 +++ phlib/include/phutil.h | 16 +++++ phlib/native.c | 83 ++++++++++++++++++++++ phlib/util.c | 121 ++++++++++++++++++++++++++++++++ phnt/include/ntregapi.h | 6 ++ 6 files changed, 241 insertions(+) diff --git a/ProcessHacker/ProcessHacker.def b/ProcessHacker/ProcessHacker.def index f36b044488fa..b77f3d95a2d3 100644 --- a/ProcessHacker/ProcessHacker.def +++ b/ProcessHacker/ProcessHacker.def @@ -181,6 +181,8 @@ EXPORTS PhInsertStringBuilderEx PhIntegerToString64 PhInvokeCallback + PhLoadIndirectString + PhLoadResource PhLocalTimeToSystemTime PhLowerBoundElementAvlTree PhLowerDualBoundElementAvlTree @@ -284,6 +286,7 @@ EXPORTS PhInjectDllProcess PhListenNamedPipe PhOpenKey + PhLoadAppKey PhOpenProcess = PhOpenProcessPublic PhOpenThread = PhOpenThreadPublic PhOpenThreadProcess @@ -373,6 +376,8 @@ EXPORTS PhParseCommandLineFuzzy PhParseCommandLinePart PhQueryRegistryString + PhQueryRegistryUlong + PhQueryRegistryUlong64 PhReferenceObjects PhSetFileDialogFileName PhSetFileDialogFilter diff --git a/phlib/include/phnative.h b/phlib/include/phnative.h index 1ab3c6574068..14467aa734e5 100644 --- a/phlib/include/phnative.h +++ b/phlib/include/phnative.h @@ -935,6 +935,16 @@ PhOpenKey( _In_ ULONG Attributes ); +PHLIBAPI +NTSTATUS +NTAPI +PhLoadAppKey( + _Out_ PHANDLE KeyHandle, + _In_ PWSTR FileName, + _In_ ACCESS_MASK DesiredAccess, + _In_opt_ ULONG Flags + ); + PHLIBAPI NTSTATUS NTAPI diff --git a/phlib/include/phutil.h b/phlib/include/phutil.h index cdfbbdbdba2b..84a3c84b047d 100644 --- a/phlib/include/phutil.h +++ b/phlib/include/phutil.h @@ -819,6 +819,14 @@ PhQueryRegistryString( _In_opt_ PWSTR ValueName ); +PHLIBAPI +ULONG +NTAPI +PhQueryRegistryUlong( + _In_ HANDLE KeyHandle, + _In_opt_ PWSTR ValueName + ); + PHLIBAPI ULONG64 NTAPI @@ -891,6 +899,7 @@ PhShowFileDialog( #define PH_FILEDIALOG_DEFAULTEXPANDED 0x40 #define PH_FILEDIALOG_STRICTFILETYPES 0x80 #define PH_FILEDIALOG_PICKFOLDERS 0x100 +#define PH_FILEDIALOG_NOPATHVALIDATE 0x200 PHLIBAPI ULONG @@ -1110,6 +1119,13 @@ PhLoadResource( _Out_ PVOID *ResourceBuffer ); +PHLIBAPI +PPH_STRING +NTAPI +PhLoadIndirectString( + _In_ PWSTR SourceString + ); + #ifdef __cplusplus } #endif diff --git a/phlib/native.c b/phlib/native.c index 1ffe2d2a675b..4f66d48c3d4c 100644 --- a/phlib/native.c +++ b/phlib/native.c @@ -5942,6 +5942,89 @@ NTSTATUS PhOpenKey( return status; } +// rev from RegLoadAppKey +/** + * Loads the specified registry hive file into a private application hive. + * + * \param KeyHandle A variable which receives a handle to the key. + * \param FileName The Win32 file name. + * \param DesiredAccess The desired access to the key. + * \param Flags Optional flags for loading the hive. + */ +NTSTATUS PhLoadAppKey( + _Out_ PHANDLE KeyHandle, + _In_ PWSTR FileName, + _In_ ACCESS_MASK DesiredAccess, + _In_opt_ ULONG Flags + ) +{ + NTSTATUS status; + GUID guid; + UNICODE_STRING fileName; + UNICODE_STRING objectName; + UNICODE_STRING guidStringUs; + OBJECT_ATTRIBUTES targetAttributes; + OBJECT_ATTRIBUTES sourceAttributes; + WCHAR objectNameBuffer[MAX_PATH]; + + RtlInitEmptyUnicodeString(&objectName, objectNameBuffer, sizeof(objectNameBuffer)); + + PhGenerateGuid(&guid); + + if (!NT_SUCCESS(status = RtlStringFromGUID(&guid, &guidStringUs))) + return status; + + if (!NT_SUCCESS(status = RtlAppendUnicodeToString(&objectName, L"\\REGISTRY\\A\\"))) + goto CleanupExit; + + if (!NT_SUCCESS(status = RtlAppendUnicodeStringToString(&objectName, &guidStringUs))) + goto CleanupExit; + + if (!NT_SUCCESS(status = RtlDosPathNameToNtPathName_U_WithStatus( + FileName, + &fileName, + NULL, + NULL + ))) + { + goto CleanupExit; + } + + InitializeObjectAttributes( + &targetAttributes, + &objectName, + OBJ_CASE_INSENSITIVE, + NULL, + NULL + ); + + InitializeObjectAttributes( + &sourceAttributes, + &fileName, + OBJ_CASE_INSENSITIVE, + NULL, + NULL + ); + + status = NtLoadKeyEx( + &targetAttributes, + &sourceAttributes, + REG_APP_HIVE | Flags, + NULL, + NULL, + DesiredAccess, + KeyHandle, + NULL + ); + + RtlFreeUnicodeString(&fileName); + +CleanupExit: + RtlFreeUnicodeString(&guidStringUs); + + return status; +} + /** * Gets information about a registry key. * diff --git a/phlib/util.c b/phlib/util.c index 979a6a5ca74f..6e9b9c2bb9db 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -3512,6 +3512,34 @@ PPH_STRING PhQueryRegistryString( return string; } +ULONG PhQueryRegistryUlong( + _In_ HANDLE KeyHandle, + _In_opt_ PWSTR ValueName + ) +{ + ULONG ulong = 0; + PH_STRINGREF valueName; + PKEY_VALUE_PARTIAL_INFORMATION buffer; + + if (ValueName) + PhInitializeStringRef(&valueName, ValueName); + else + PhInitializeEmptyStringRef(&valueName); + + if (NT_SUCCESS(PhQueryValueKey(KeyHandle, &valueName, KeyValuePartialInformation, &buffer))) + { + if (buffer->Type == REG_DWORD) + { + if (buffer->DataLength == sizeof(ULONG)) + ulong = *(PULONG)buffer->Data; + } + + PhFree(buffer); + } + + return ulong; +} + ULONG64 PhQueryRegistryUlong64( _In_ HANDLE KeyHandle, _In_opt_ PWSTR ValueName @@ -5216,3 +5244,96 @@ BOOLEAN PhLoadResource( return TRUE; } + +PPH_STRING PhLoadString( + _In_ PVOID DllBase, + _In_ ULONG ResourceId + ) +{ + PPH_STRING string = NULL; + ULONG resourceLength; + PVOID resourceBuffer; + ULONG stringCount; + PWSTR stringBuffer; + ULONG i; + + if (!PhLoadResource( + DllBase, + MAKEINTRESOURCE((LOWORD(ResourceId) >> 4) + 1), + RT_STRING, + &resourceLength, + &resourceBuffer + )) + { + return NULL; + } + + stringBuffer = resourceBuffer; + stringCount = ResourceId & 0x000F; + + for (i = 0; i < stringCount; i++) // dmex: Copied from ReactOS. + { + stringBuffer += *stringBuffer + 1; + } + + i = min(resourceLength - 1, *stringBuffer); + + if (i > 0) + { + string = PhCreateStringEx(stringBuffer + 1, i * sizeof(WCHAR)); + } + + PhFree(resourceBuffer); + return string; +} + +PPH_STRING PhLoadIndirectString( + _In_ PWSTR SourceString + ) +{ + PPH_STRING indirectString = NULL; + + if (SourceString[0] == L'@') + { + PPH_STRING libraryString; + PVOID libraryModule; + PH_STRINGREF sourceRef; + PH_STRINGREF dllNameRef; + PH_STRINGREF dllIndexRef; + ULONG64 index64; + LONG index; + + PhInitializeStringRefLongHint(&sourceRef, SourceString); + PhSkipStringRef(&sourceRef, sizeof(WCHAR)); // Skip the @ character. + + if (!PhSplitStringRefAtChar(&sourceRef, L',', &dllNameRef, &dllIndexRef)) + return NULL; + if (!PhStringToInteger64(&dllIndexRef, 10, &index64)) + return NULL; + + libraryString = PhCreateString2(&dllNameRef); + index = (LONG)index64; + + if (libraryString->Buffer[0] == L'%') + { + PPH_STRING expandedString; + + if (expandedString = PhExpandEnvironmentStrings(&libraryString->sr)) + PhMoveReference(&libraryString, expandedString); + } + + if (libraryModule = LoadLibraryEx(libraryString->Buffer, NULL, LOAD_LIBRARY_AS_DATAFILE)) + { + indirectString = PhLoadString(libraryModule, -index); + FreeLibrary(libraryModule); + } + + PhDereferenceObject(libraryString); + } + else + { + //indirectString = PhCreateString(SourceString); + } + + return indirectString; +} diff --git a/phnt/include/ntregapi.h b/phnt/include/ntregapi.h index da9bc244de3a..a6e1240898ef 100644 --- a/phnt/include/ntregapi.h +++ b/phnt/include/ntregapi.h @@ -534,6 +534,12 @@ NtUnloadKey( _In_ POBJECT_ATTRIBUTES TargetKey ); +// +// NtUnloadKey2 Flags (from winnt.h) +// +//#define REG_FORCE_UNLOAD 1 +//#define REG_UNLOAD_LEGAL_FLAGS (REG_FORCE_UNLOAD) + NTSYSCALLAPI NTSTATUS NTAPI From b1e80bc0a4b34330b948e0ef78bb86478e3232c5 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 12 Dec 2017 20:52:07 +1100 Subject: [PATCH 0612/2058] Remove about window parent (Feature request #201) --- ProcessHacker/about.c | 4 ++-- ProcessHacker/include/phapp.h | 2 +- ProcessHacker/mainwnd.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ProcessHacker/about.c b/ProcessHacker/about.c index 91c61818a748..83a005208958 100644 --- a/ProcessHacker/about.c +++ b/ProcessHacker/about.c @@ -128,13 +128,13 @@ static INT_PTR CALLBACK PhpAboutDlgProc( } VOID PhShowAboutDialog( - _In_ HWND ParentWindowHandle + VOID ) { DialogBox( PhInstanceHandle, MAKEINTRESOURCE(IDD_ABOUT), - ParentWindowHandle, + NULL, PhpAboutDlgProc ); } diff --git a/ProcessHacker/include/phapp.h b/ProcessHacker/include/phapp.h index 5c1740621268..ea1fda8a0e3c 100644 --- a/ProcessHacker/include/phapp.h +++ b/ProcessHacker/include/phapp.h @@ -294,7 +294,7 @@ BOOLEAN PhUiCreateDumpFileProcess( // about VOID PhShowAboutDialog( - _In_ HWND ParentWindowHandle + VOID ); PPH_STRING PhGetDiagnosticsString( diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index ad2de4ecbda7..b2031ecb6b7c 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -943,7 +943,7 @@ VOID PhMwpOnCommand( break; case ID_HELP_ABOUT: { - PhShowAboutDialog(PhMainWndHandle); + PhShowAboutDialog(); } break; case ID_PROCESS_TERMINATE: From f0b3516ab417689bf4acdfba3e9fc89f3caa8669 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 13 Dec 2017 00:00:17 +1100 Subject: [PATCH 0613/2058] Fix runas service regression from 2cfb6835 --- ProcessHacker/runas.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/ProcessHacker/runas.c b/ProcessHacker/runas.c index 954f4fb811eb..e204caab1d10 100644 --- a/ProcessHacker/runas.c +++ b/ProcessHacker/runas.c @@ -370,6 +370,7 @@ INT_PTR CALLBACK PhpRunAsDlgProc( { NTSTATUS status; PPH_STRING program; + PPH_STRING programEscaped; PPH_STRING userName; PPH_STRING password; PPH_STRING logonTypeString; @@ -382,6 +383,15 @@ INT_PTR CALLBACK PhpRunAsDlgProc( userName = PhaGetDlgItemText(hwndDlg, IDC_USERNAME); logonTypeString = PhaGetDlgItemText(hwndDlg, IDC_TYPE); + if (PhIsNullOrEmptyString(program)) + break; + + // Escape the path. (dmex: poor man's PathQuoteSpaces) + if (!PhStartsWithString2(program, L"\"", FALSE) && PhFindCharInString(program, 0, L' ') != -1) + { + programEscaped = PhaConcatStrings(3, L"\"", PhGetString(program), L"\""); + } + // Fix up the user name if it doesn't have a domain. if (PhFindCharInString(userName, 0, '\\') == -1) { @@ -431,7 +441,7 @@ INT_PTR CALLBACK PhpRunAsDlgProc( PhpSplitUserName(userName->Buffer, &domainPart, &userPart); memset(&createInfo, 0, sizeof(PH_CREATE_PROCESS_AS_USER_INFO)); - createInfo.CommandLine = program->Buffer; + createInfo.CommandLine = programEscaped->Buffer; createInfo.UserName = PhGetString(userPart); createInfo.DomainName = PhGetString(domainPart); createInfo.Password = PhGetStringOrEmpty(password); @@ -457,7 +467,7 @@ INT_PTR CALLBACK PhpRunAsDlgProc( { status = PhExecuteRunAsCommand2( hwndDlg, - program->Buffer, + programEscaped->Buffer, userName->Buffer, PhGetStringOrEmpty(password), logonType, From e30b1fe9fd5a342cbd4a958454a7d930b6dc1080 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 13 Dec 2017 00:03:26 +1100 Subject: [PATCH 0614/2058] Tidy up --- ProcessHacker/include/memlist.h | 2 +- ProcessHacker/memrslt.c | 2 +- phlib/basesup.c | 5 ----- 3 files changed, 2 insertions(+), 7 deletions(-) diff --git a/ProcessHacker/include/memlist.h b/ProcessHacker/include/memlist.h index 482f485a62cd..a7f714d32fa8 100644 --- a/ProcessHacker/include/memlist.h +++ b/ProcessHacker/include/memlist.h @@ -114,7 +114,7 @@ VOID PhSetOptionsMemoryList( VOID PhReplaceMemoryList( _Inout_ PPH_MEMORY_LIST_CONTEXT Context, - _In_ PPH_MEMORY_ITEM_LIST List + _In_opt_ PPH_MEMORY_ITEM_LIST List ); VOID PhUpdateMemoryNode( diff --git a/ProcessHacker/memrslt.c b/ProcessHacker/memrslt.c index ba3b0750c547..efe9d74ff961 100644 --- a/ProcessHacker/memrslt.c +++ b/ProcessHacker/memrslt.c @@ -108,7 +108,7 @@ static PPH_STRING PhpGetStringForSelectedResults( result = Results->Items[i]; - PhAppendFormatStringBuilder(&stringBuilder, L"0x%Ix (%u): %s\r\n", result->Address, result->Length, + PhAppendFormatStringBuilder(&stringBuilder, L"0x%Ix (%lu): %s\r\n", result->Address, result->Length, result->Display.Buffer ? result->Display.Buffer : L""); } diff --git a/phlib/basesup.c b/phlib/basesup.c index 93a08cfe4c43..35364e49c0af 100644 --- a/phlib/basesup.c +++ b/phlib/basesup.c @@ -88,11 +88,6 @@ VOID NTAPI PhpPointerListDeleteProcedure( _In_ ULONG Flags ); -VOID NTAPI PhpQueueDeleteProcedure( - _In_ PVOID Object, - _In_ ULONG Flags - ); - VOID NTAPI PhpHashtableDeleteProcedure( _In_ PVOID Object, _In_ ULONG Flags From 9ccc789b83cae3fc6a5c7221704c25f4a1ce6e05 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 13 Dec 2017 00:04:27 +1100 Subject: [PATCH 0615/2058] Disable contextmenu for system and idle processes --- ProcessHacker/mwpgproc.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/ProcessHacker/mwpgproc.c b/ProcessHacker/mwpgproc.c index bc88c3fd8fda..acaa84fa7bc8 100644 --- a/ProcessHacker/mwpgproc.c +++ b/ProcessHacker/mwpgproc.c @@ -543,7 +543,11 @@ VOID PhMwpInitializeProcessMenu( // If the user selected a fake process, disable all but // a few menu items. - if (PH_IS_FAKE_PROCESS_ID(Processes[0]->ProcessId)) + if ( + PH_IS_FAKE_PROCESS_ID(Processes[0]->ProcessId) || + Processes[0]->ProcessId == SYSTEM_IDLE_PROCESS_ID || + Processes[0]->ProcessId == SYSTEM_PROCESS_ID // TODO: Some menu entires could be enabled for the system process? + ) { PhSetFlagsAllEMenuItems(Menu, PH_EMENU_DISABLED, PH_EMENU_DISABLED); PhEnableEMenuItem(Menu, ID_PROCESS_PROPERTIES, TRUE); From ff755fb6fcbf9439b3ed6eb6fbfbc235ddb7c9af Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 14 Dec 2017 23:47:32 +1100 Subject: [PATCH 0616/2058] Fix macro usage, Improve struct checks --- phlib/mapimg.c | 40 ++++++++++++---------------------------- tools/peview/ldprp.c | 14 +++++--------- 2 files changed, 17 insertions(+), 37 deletions(-) diff --git a/phlib/mapimg.c b/phlib/mapimg.c index fbee31dec399..1ddb46aa6510 100644 --- a/phlib/mapimg.c +++ b/phlib/mapimg.c @@ -1219,7 +1219,7 @@ NTSTATUS PhGetMappedImageCfg64( return status; // Not every load configuration defines CFG characteristics - if (config64->Size < UFIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY64, GuardFlags)) + if (!RTL_CONTAINS_FIELD(config64, config64->Size, GuardFlags)) return STATUS_INVALID_VIEW_SIZE; CfgConfig->MappedImage = MappedImage; @@ -1238,7 +1238,7 @@ NTSTATUS PhGetMappedImageCfg64( CfgConfig->NumberOfGuardFunctionEntries = config64->GuardCFFunctionCount; CfgConfig->GuardFunctionTable = PhMappedImageRvaToVa( MappedImage, - (ULONG)(ULONG_PTR)PTR_SUB_OFFSET(config64->GuardCFFunctionTable, MappedImage->NtHeaders->OptionalHeader.ImageBase), + (ULONG)(config64->GuardCFFunctionTable - MappedImage->NtHeaders->OptionalHeader.ImageBase), NULL ); @@ -1261,16 +1261,12 @@ NTSTATUS PhGetMappedImageCfg64( CfgConfig->NumberOfGuardAdressIatEntries = 0; CfgConfig->GuardAdressIatTable = 0; - if ( - config64->Size >= UFIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY64, GuardAddressTakenIatEntryTable) + - sizeof(config64->GuardAddressTakenIatEntryTable) + - sizeof(config64->GuardAddressTakenIatEntryCount) - ) + if (RTL_CONTAINS_FIELD(config64, config64->Size, GuardAddressTakenIatEntryTable)) { CfgConfig->NumberOfGuardAdressIatEntries = config64->GuardAddressTakenIatEntryCount; CfgConfig->GuardAdressIatTable = PhMappedImageRvaToVa( MappedImage, - (ULONG)(ULONG_PTR)PTR_SUB_OFFSET(config64->GuardAddressTakenIatEntryTable, MappedImage->NtHeaders->OptionalHeader.ImageBase), + (ULONG)(config64->GuardAddressTakenIatEntryTable - MappedImage->NtHeaders->OptionalHeader.ImageBase), NULL ); @@ -1294,16 +1290,12 @@ NTSTATUS PhGetMappedImageCfg64( CfgConfig->NumberOfGuardLongJumpEntries = 0; CfgConfig->GuardLongJumpTable = 0; - if ( - config64->Size >= UFIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY64, GuardLongJumpTargetTable) + - sizeof(config64->GuardLongJumpTargetTable) + - sizeof(config64->GuardLongJumpTargetCount) - ) + if (RTL_CONTAINS_FIELD(config64, config64->Size, GuardLongJumpTargetTable)) { CfgConfig->NumberOfGuardLongJumpEntries = config64->GuardLongJumpTargetCount; CfgConfig->GuardLongJumpTable = PhMappedImageRvaToVa( MappedImage, - (ULONG)(ULONG_PTR)PTR_SUB_OFFSET(config64->GuardLongJumpTargetTable, MappedImage->NtHeaders->OptionalHeader.ImageBase), + (ULONG)(config64->GuardLongJumpTargetTable - MappedImage->NtHeaders->OptionalHeader.ImageBase), NULL ); @@ -1339,7 +1331,7 @@ NTSTATUS PhGetMappedImageCfg32( return status; // Not every load configuration defines CFG characteristics - if (config32->Size < UFIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY32, GuardFlags)) + if (!RTL_CONTAINS_FIELD(config32, config32->Size, GuardFlags)) return STATUS_INVALID_VIEW_SIZE; CfgConfig->MappedImage = MappedImage; @@ -1358,7 +1350,7 @@ NTSTATUS PhGetMappedImageCfg32( CfgConfig->NumberOfGuardFunctionEntries = config32->GuardCFFunctionCount; CfgConfig->GuardFunctionTable = PhMappedImageRvaToVa( MappedImage, - (ULONG)(ULONG_PTR)PTR_SUB_OFFSET(config32->GuardCFFunctionTable , MappedImage->NtHeaders32->OptionalHeader.ImageBase), + config32->GuardCFFunctionTable - MappedImage->NtHeaders32->OptionalHeader.ImageBase, NULL ); @@ -1381,16 +1373,12 @@ NTSTATUS PhGetMappedImageCfg32( CfgConfig->NumberOfGuardAdressIatEntries = 0; CfgConfig->GuardAdressIatTable = 0; - if ( - config32->Size >= UFIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY32, GuardAddressTakenIatEntryTable) + - sizeof(config32->GuardAddressTakenIatEntryTable) + - sizeof(config32->GuardAddressTakenIatEntryCount) - ) + if (RTL_CONTAINS_FIELD(config32, config32->Size, GuardAddressTakenIatEntryTable)) { CfgConfig->NumberOfGuardAdressIatEntries = config32->GuardAddressTakenIatEntryCount; CfgConfig->GuardAdressIatTable = PhMappedImageRvaToVa( MappedImage, - (ULONG)(ULONG_PTR)PTR_SUB_OFFSET(config32->GuardAddressTakenIatEntryTable, MappedImage->NtHeaders32->OptionalHeader.ImageBase), + config32->GuardAddressTakenIatEntryTable - MappedImage->NtHeaders32->OptionalHeader.ImageBase, NULL ); @@ -1414,16 +1402,12 @@ NTSTATUS PhGetMappedImageCfg32( CfgConfig->NumberOfGuardLongJumpEntries = 0; CfgConfig->GuardLongJumpTable = 0; - if ( - config32->Size >= UFIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY32, GuardLongJumpTargetTable) + - sizeof(config32->GuardLongJumpTargetTable) + - sizeof(config32->GuardLongJumpTargetCount) - ) + if (RTL_CONTAINS_FIELD(config32, config32->Size, GuardLongJumpTargetTable)) { CfgConfig->NumberOfGuardLongJumpEntries = config32->GuardLongJumpTargetCount; CfgConfig->GuardLongJumpTable = PhMappedImageRvaToVa( MappedImage, - (ULONG)(ULONG_PTR)PTR_SUB_OFFSET(config32->GuardLongJumpTargetTable, MappedImage->NtHeaders32->OptionalHeader.ImageBase), + config32->GuardLongJumpTargetTable - MappedImage->NtHeaders32->OptionalHeader.ImageBase, NULL ); diff --git a/tools/peview/ldprp.c b/tools/peview/ldprp.c index d19cb649d83b..39516c7b0dae 100644 --- a/tools/peview/ldprp.c +++ b/tools/peview/ldprp.c @@ -85,23 +85,19 @@ INT_PTR CALLBACK PvpPeLoadConfigDlgProc( ADD_VALUE(L"SEH handler table", PhaFormatString(L"0x%Ix", (Config)->SEHandlerTable)->Buffer); \ ADD_VALUE(L"SEH handler count", PhaFormatUInt64((Config)->SEHandlerCount, TRUE)->Buffer); \ \ - if ((Config)->Size >= UFIELD_OFFSET(Type, GuardCFCheckFunctionPointer)) \ + if (RTL_CONTAINS_FIELD((Config), (Config)->Size, GuardCFCheckFunctionPointer)) \ { \ ADD_VALUE(L"CFG GuardFlags", PhaFormatString(L"0x%Ix", (Config)->GuardFlags)->Buffer); \ ADD_VALUE(L"CFG Check Function pointer", PhaFormatString(L"0x%Ix", (Config)->GuardCFCheckFunctionPointer)->Buffer); \ ADD_VALUE(L"CFG Check Dispatch pointer", PhaFormatString(L"0x%Ix", (Config)->GuardCFDispatchFunctionPointer)->Buffer); \ ADD_VALUE(L"CFG Function table", PhaFormatString(L"0x%Ix", (Config)->GuardCFFunctionTable)->Buffer); \ ADD_VALUE(L"CFG Function table entry count", PhaFormatUInt64((Config)->GuardCFFunctionCount, TRUE)->Buffer); \ - if ((Config)->Size >= UFIELD_OFFSET(Type, GuardAddressTakenIatEntryTable) \ - + sizeof((Config)->GuardAddressTakenIatEntryTable) \ - + sizeof((Config)->GuardAddressTakenIatEntryCount)) \ + if (RTL_CONTAINS_FIELD((Config), (Config)->Size, GuardAddressTakenIatEntryTable)) \ { \ - ADD_VALUE(L"CFG IatEntry table", PhaFormatString(L"0x%Ix", (Config)->GuardAddressTakenIatEntryTable)->Buffer); \ - ADD_VALUE(L"CFG IatEntry table entry count", PhaFormatUInt64((Config)->GuardAddressTakenIatEntryCount, TRUE)->Buffer); \ + ADD_VALUE(L"CFG IatEntry table", PhaFormatString(L"0x%Ix", (Config)->GuardAddressTakenIatEntryTable)->Buffer); \ + ADD_VALUE(L"CFG IatEntry table entry count", PhaFormatUInt64((Config)->GuardAddressTakenIatEntryCount, TRUE)->Buffer); \ } \ - if ((Config)->Size >= UFIELD_OFFSET(Type, GuardLongJumpTargetTable) \ - + sizeof((Config)->GuardLongJumpTargetTable) \ - + sizeof((Config)->GuardLongJumpTargetCount)) \ + if (RTL_CONTAINS_FIELD((Config), (Config)->Size, GuardLongJumpTargetTable)) \ { \ ADD_VALUE(L"CFG LongJump table", PhaFormatString(L"0x%Ix", (Config)->GuardLongJumpTargetTable)->Buffer); \ ADD_VALUE(L"CFG LongJump table entry count", PhaFormatUInt64((Config)->GuardLongJumpTargetCount, TRUE)->Buffer); \ From 5e34ca62e18296b33ced1d1b91a1336af5409b32 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 15 Dec 2017 09:27:02 +1100 Subject: [PATCH 0617/2058] Add RtlQueryImageMitigationPolicy/RtlSetImageMitigationPolicy types --- phnt/include/ntrtl.h | 178 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 178 insertions(+) diff --git a/phnt/include/ntrtl.h b/phnt/include/ntrtl.h index 4d505b1f7602..92ad843fd878 100644 --- a/phnt/include/ntrtl.h +++ b/phnt/include/ntrtl.h @@ -6589,4 +6589,182 @@ RtlCrc64( #endif +// Image Mitigation + +// rev +typedef enum _IMAGE_MITIGATION_POLICY +{ + ImageDepPolicy, // RTL_IMAGE_MITIGATION_DEP_POLICY + ImageAslrPolicy, // RTL_IMAGE_MITIGATION_ASLR_POLICY + ImageDynamicCodePolicy, // RTL_IMAGE_MITIGATION_DYNAMIC_CODE_POLICY + ImageStrictHandleCheckPolicy, // RTL_IMAGE_MITIGATION_STRICT_HANDLE_CHECK_POLICY + ImageSystemCallDisablePolicy, // RTL_IMAGE_MITIGATION_SYSTEM_CALL_DISABLE_POLICY + ImageMitigationOptionsMask, + ImageExtensionPointDisablePolicy, // RTL_IMAGE_MITIGATION_EXTENSION_POINT_DISABLE_POLICY + ImageControlFlowGuardPolicy, // RTL_IMAGE_MITIGATION_CONTROL_FLOW_GUARD_POLICY + ImageSignaturePolicy, // RTL_IMAGE_MITIGATION_BINARY_SIGNATURE_POLICY + ImageFontDisablePolicy, // RTL_IMAGE_MITIGATION_FONT_DISABLE_POLICY + ImageImageLoadPolicy, // RTL_IMAGE_MITIGATION_IMAGE_LOAD_POLICY + ImagePayloadRestrictionPolicy, // RTL_IMAGE_MITIGATION_PAYLOAD_RESTRICTION_POLICY + ImageChildProcessPolicy, // RTL_IMAGE_MITIGATION_CHILD_PROCESS_POLICY + ImageSehopPolicy, // RTL_IMAGE_MITIGATION_SEHOP_POLICY + ImageHeapPolicy, // RTL_IMAGE_MITIGATION_HEAP_POLICY + MaxImageMitigationPolicy +} IMAGE_MITIGATION_POLICY; + +// rev +typedef union _RTL_IMAGE_MITIGATION_POLICY +{ + struct + { + ULONG64 AuditState : 2; + ULONG64 AuditFlag : 1; + ULONG64 EnableAdditionalAuditingOption : 1; + ULONG64 Reserved : 60; + }; + struct + { + ULONG64 PolicyState : 2; + ULONG64 AlwaysInherit : 1; + ULONG64 EnableAdditionalPolicyOption : 1; + ULONG64 AuditReserved : 60; + }; +} RTL_IMAGE_MITIGATION_POLICY, *PRTL_IMAGE_MITIGATION_POLICY; + +// rev +typedef struct _RTL_IMAGE_MITIGATION_DEP_POLICY +{ + RTL_IMAGE_MITIGATION_POLICY Dep; +} RTL_IMAGE_MITIGATION_DEP_POLICY, *PRTL_IMAGE_MITIGATION_DEP_POLICY; + +// rev +typedef struct _RTL_IMAGE_MITIGATION_ASLR_POLICY +{ + RTL_IMAGE_MITIGATION_POLICY ForceRelocateImages; + RTL_IMAGE_MITIGATION_POLICY BottomUpRandomization; + RTL_IMAGE_MITIGATION_POLICY HighEntropyRandomization; +} RTL_IMAGE_MITIGATION_ASLR_POLICY, *PRTL_IMAGE_MITIGATION_ASLR_POLICY; + +// rev +typedef struct _RTL_IMAGE_MITIGATION_DYNAMIC_CODE_POLICY +{ + RTL_IMAGE_MITIGATION_POLICY BlockDynamicCode; +} RTL_IMAGE_MITIGATION_DYNAMIC_CODE_POLICY, *PRTL_IMAGE_MITIGATION_DYNAMIC_CODE_POLICY; + +// rev +typedef struct _RTL_IMAGE_MITIGATION_STRICT_HANDLE_CHECK_POLICY +{ + RTL_IMAGE_MITIGATION_POLICY StrictHandleChecks; +} RTL_IMAGE_MITIGATION_STRICT_HANDLE_CHECK_POLICY, *PRTL_IMAGE_MITIGATION_STRICT_HANDLE_CHECK_POLICY; + +// rev +typedef struct _RTL_IMAGE_MITIGATION_SYSTEM_CALL_DISABLE_POLICY +{ + RTL_IMAGE_MITIGATION_POLICY BlockWin32kSystemCalls; +} RTL_IMAGE_MITIGATION_SYSTEM_CALL_DISABLE_POLICY, *PRTL_IMAGE_MITIGATION_SYSTEM_CALL_DISABLE_POLICY; + +// rev +typedef struct _RTL_IMAGE_MITIGATION_EXTENSION_POINT_DISABLE_POLICY +{ + RTL_IMAGE_MITIGATION_POLICY DisableExtensionPoints; +} RTL_IMAGE_MITIGATION_EXTENSION_POINT_DISABLE_POLICY, *PRTL_IMAGE_MITIGATION_EXTENSION_POINT_DISABLE_POLICY; + +// rev +typedef struct _RTL_IMAGE_MITIGATION_CONTROL_FLOW_GUARD_POLICY +{ + RTL_IMAGE_MITIGATION_POLICY ControlFlowGuard; + RTL_IMAGE_MITIGATION_POLICY StrictControlFlowGuard; +} RTL_IMAGE_MITIGATION_CONTROL_FLOW_GUARD_POLICY, *PRTL_IMAGE_MITIGATION_CONTROL_FLOW_GUARD_POLICY; + +// rev +typedef struct _RTL_IMAGE_MITIGATION_BINARY_SIGNATURE_POLICY +{ + RTL_IMAGE_MITIGATION_POLICY BlockNonMicrosoftSignedBinaries; + RTL_IMAGE_MITIGATION_POLICY EnforceSigningOnModuleDependencies; +} RTL_IMAGE_MITIGATION_BINARY_SIGNATURE_POLICY, *PRTL_IMAGE_MITIGATION_BINARY_SIGNATURE_POLICY; + +// rev +typedef struct _RTL_IMAGE_MITIGATION_FONT_DISABLE_POLICY +{ + RTL_IMAGE_MITIGATION_POLICY DisableNonSystemFonts; +} RTL_IMAGE_MITIGATION_FONT_DISABLE_POLICY, *PRTL_IMAGE_MITIGATION_FONT_DISABLE_POLICY; + +// rev +typedef struct _RTL_IMAGE_MITIGATION_IMAGE_LOAD_POLICY +{ + RTL_IMAGE_MITIGATION_POLICY BlockRemoteImageLoads; + RTL_IMAGE_MITIGATION_POLICY BlockLowLabelImageLoads; + RTL_IMAGE_MITIGATION_POLICY PreferSystem32; +} RTL_IMAGE_MITIGATION_IMAGE_LOAD_POLICY, *PRTL_IMAGE_MITIGATION_IMAGE_LOAD_POLICY; + +// rev +typedef struct _RTL_IMAGE_MITIGATION_PAYLOAD_RESTRICTION_POLICY +{ + RTL_IMAGE_MITIGATION_POLICY EnableExportAddressFilter; + RTL_IMAGE_MITIGATION_POLICY EnableExportAddressFilterPlus; + RTL_IMAGE_MITIGATION_POLICY EnableImportAddressFilter; + RTL_IMAGE_MITIGATION_POLICY EnableRopStackPivot; + RTL_IMAGE_MITIGATION_POLICY EnableRopCallerCheck; + RTL_IMAGE_MITIGATION_POLICY EnableRopSimExec; +} RTL_IMAGE_MITIGATION_PAYLOAD_RESTRICTION_POLICY, *PRTL_IMAGE_MITIGATION_PAYLOAD_RESTRICTION_POLICY; + +// rev +typedef struct _RTL_IMAGE_MITIGATION_CHILD_PROCESS_POLICY +{ + RTL_IMAGE_MITIGATION_POLICY DisallowChildProcessCreation; +} RTL_IMAGE_MITIGATION_CHILD_PROCESS_POLICY, *PRTL_IMAGE_MITIGATION_CHILD_PROCESS_POLICY; + +// rev +typedef struct _RTL_IMAGE_MITIGATION_SEHOP_POLICY +{ + RTL_IMAGE_MITIGATION_POLICY Sehop; +} RTL_IMAGE_MITIGATION_SEHOP_POLICY, *PRTL_IMAGE_MITIGATION_SEHOP_POLICY; + +// rev +typedef struct _RTL_IMAGE_MITIGATION_HEAP_POLICY +{ + RTL_IMAGE_MITIGATION_POLICY TerminateOnHeapErrors; +} RTL_IMAGE_MITIGATION_HEAP_POLICY, *PRTL_IMAGE_MITIGATION_HEAP_POLICY; + +typedef enum _RTL_IMAGE_MITIGATION_OPTION_STATE +{ + RtlMitigationOptionStateNotConfigured, + RtlMitigationOptionStateOn, + RtlMitigationOptionStateOff +} RTL_IMAGE_MITIGATION_OPTION_STATE; + +// rev from PROCESS_MITIGATION_FLAGS +#define RTL_IMAGE_MITIGATION_FLAG_RESET 0x1 +#define RTL_IMAGE_MITIGATION_FLAG_REMOVE 0x2 +#define RTL_IMAGE_MITIGATION_FLAG_OSDEFAULT 0x4 +#define RTL_IMAGE_MITIGATION_FLAG_AUDIT 0x8 + +#if (PHNT_VERSION >= PHNT_REDSTONE3) + +// rev +NTSYSAPI +NTSTATUS +NTAPI +RtlQueryImageMitigationPolicy( + _In_opt_ PWSTR ImagePath, // NULL for system-wide defaults + _In_ IMAGE_MITIGATION_POLICY Policy, + _In_ ULONG Flags, + _Inout_ PVOID Buffer, + _In_ ULONG BufferSize + ); + +// rev +NTSYSAPI +NTSTATUS +NTAPI +RtlSetImageMitigationPolicy( + _In_opt_ PWSTR ImagePath, // NULL for system-wide defaults + _In_ IMAGE_MITIGATION_POLICY Policy, + _In_ ULONG Flags, + _Inout_ PVOID Buffer, + _In_ ULONG BufferSize + ); + +#endif + #endif From fc07a5d1b69df0076bb85ff48e556c74b3234fc4 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 16 Dec 2017 00:06:55 +1100 Subject: [PATCH 0618/2058] Fix HideDriverServices regression from commit 1f39694e5a79ea18e6c8f5a8ed56e9fd45042f17 --- ProcessHacker/mwpgsrv.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/ProcessHacker/mwpgsrv.c b/ProcessHacker/mwpgsrv.c index c5ac2d0119f9..9d07c0cedab9 100644 --- a/ProcessHacker/mwpgsrv.c +++ b/ProcessHacker/mwpgsrv.c @@ -117,7 +117,8 @@ BOOLEAN PhMwpServicesPageCallback( return TRUE; case MainTabPageLoadSettings: { - // Nothing + if (PhGetIntegerSetting(L"HideDriverServices")) + DriverFilterEntry = PhAddTreeNewFilter(PhGetFilterSupportServiceTreeList(), PhMwpDriverServiceTreeFilter, NULL); } return TRUE; case MainTabPageSaveSettings: @@ -159,11 +160,7 @@ VOID PhMwpNeedServiceTreeList( if (!ServiceTreeListLoaded) { ServiceTreeListLoaded = TRUE; - PhLoadSettingsServiceTreeList(); - - if (PhGetIntegerSetting(L"HideDriverServices")) - DriverFilterEntry = PhAddTreeNewFilter(PhGetFilterSupportServiceTreeList(), PhMwpDriverServiceTreeFilter, NULL); } } From 3e9ad6f7ec57590a9b1e9ece88f63f6db3dcac11 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 16 Dec 2017 01:02:57 +1100 Subject: [PATCH 0619/2058] Fix typo --- ProcessHacker/proctree.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ProcessHacker/proctree.c b/ProcessHacker/proctree.c index 7dadc864a055..ceee54151cad 100644 --- a/ProcessHacker/proctree.c +++ b/ProcessHacker/proctree.c @@ -320,7 +320,7 @@ FORCEINLINE ULONG PhHashProcessNode( return HandleToUlong(Value->ProcessId) / 4; } -FORCEINLINE BOOLEAN PhpValidateParentCreateTime( +FORCEINLINE BOOLEAN PhpValidateParentProcessNode( _In_ PPH_PROCESS_NODE Child, _In_ PPH_PROCESS_NODE Parent ) @@ -375,7 +375,7 @@ PPH_PROCESS_NODE PhAddProcessNode( // Find this process' parent and add the process to it if we found it. if ( (parentNode = PhFindProcessNode(ProcessItem->ParentProcessId)) && - PhpValidateParentCreateTime(processNode, parentNode) + PhpValidateParentProcessNode(processNode, parentNode) ) { PhAddItemList(parentNode->Children, processNode); @@ -397,7 +397,7 @@ PPH_PROCESS_NODE PhAddProcessNode( if ( node != processNode && // for cases where the parent PID = PID (e.g. System Idle Process) node->ProcessItem->ParentProcessId == ProcessItem->ProcessId && - PhpValidateParentCreateTime(node, processNode) + PhpValidateParentProcessNode(node, processNode) ) { node->Parent = processNode; From ac4e206311a12188507e4adbd94832faaace04ab Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 16 Dec 2017 01:05:03 +1100 Subject: [PATCH 0620/2058] Change default physical memory color (old graphs only) --- ProcessHacker/settings.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ProcessHacker/settings.c b/ProcessHacker/settings.c index 6df4cc013175..77dadc5362c3 100644 --- a/ProcessHacker/settings.c +++ b/ProcessHacker/settings.c @@ -211,7 +211,7 @@ VOID PhAddDefaultSettings( PhpAddIntegerSetting(L"ColorIoReadOther", L"00ffff"); PhpAddIntegerSetting(L"ColorIoWrite", L"ff0077"); PhpAddIntegerSetting(L"ColorPrivate", L"0077ff"); - PhpAddIntegerSetting(L"ColorPhysical", L"ffff00"); + PhpAddIntegerSetting(L"ColorPhysical", L"ff8000"); // Blue PhpAddIntegerSetting(L"UseColorServiceStop", L"1"); PhpAddIntegerSetting(L"ColorServiceStop", L"6d6d6d"); // Dark grey From 5e4ed22ec7ab6b91946379fbde5eb8c84e6d1399 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 16 Dec 2017 04:55:39 +1100 Subject: [PATCH 0621/2058] Add PhExtractIcon --- ProcessHacker/hidnproc.c | 6 ++---- ProcessHacker/procprv.c | 9 +++------ phlib/guisup.c | 16 ++++++---------- phlib/include/phutil.h | 9 +++++++++ phlib/util.c | 24 ++++++++++++++++++++++++ tools/peview/peprp.c | 8 +++----- 6 files changed, 47 insertions(+), 25 deletions(-) diff --git a/ProcessHacker/hidnproc.c b/ProcessHacker/hidnproc.c index f3b342c8c2fc..7744af80173f 100644 --- a/ProcessHacker/hidnproc.c +++ b/ProcessHacker/hidnproc.c @@ -665,12 +665,10 @@ static PPH_PROCESS_ITEM PhpCreateProcessItemForHiddenProcess( if (processItem->FileName) { // Small icon, large icon. - ExtractIconEx( + PhExtractIcon( processItem->FileName->Buffer, - 0, &processItem->LargeIcon, - &processItem->SmallIcon, - 1 + &processItem->SmallIcon ); // Version info. diff --git a/ProcessHacker/procprv.c b/ProcessHacker/procprv.c index 40b692dde21b..1671ce92029a 100644 --- a/ProcessHacker/procprv.c +++ b/ProcessHacker/procprv.c @@ -956,14 +956,11 @@ VOID PhpProcessQueryStage1( if (processItem->FileName) { - // Small icon, large icon. - if (ExtractIconEx( + if (!PhExtractIcon( processItem->FileName->Buffer, - 0, &Data->LargeIcon, - &Data->SmallIcon, - 1 - ) == 0) + &Data->SmallIcon + )) { Data->LargeIcon = NULL; Data->SmallIcon = NULL; diff --git a/phlib/guisup.c b/phlib/guisup.c index e223e14d9d43..1753b9fd85da 100644 --- a/phlib/guisup.c +++ b/phlib/guisup.c @@ -689,16 +689,14 @@ VOID PhGetStockApplicationIcon( if (systemDirectory = PhGetSystemDirectory()) { PH_STRINGREF dllBaseName; - ULONG index; PhInitializeStringRef(&dllBaseName, L"\\user32.dll"); - index = 0; - dllFileName = PhConcatStringRef2(&systemDirectory->sr, &dllBaseName); - PhDereferenceObject(systemDirectory); - ExtractIconEx(dllFileName->Buffer, index, &largeIcon, &smallIcon, 1); + PhExtractIcon(dllFileName->Buffer, &largeIcon, &smallIcon); + PhDereferenceObject(dllFileName); + PhDereferenceObject(systemDirectory); } } @@ -735,12 +733,10 @@ HICON PhGetFileShellIcon( if (FileName) { - ExtractIconEx( + PhExtractIcon( FileName, - 0, LargeIcon ? &icon : NULL, - !LargeIcon ? &icon : NULL, - 1 + !LargeIcon ? &icon : NULL ); } @@ -752,7 +748,7 @@ HICON PhGetFileShellIcon( ); if (icon) - icon = DuplicateIcon(NULL, icon); + icon = CopyIcon(icon); } return icon; diff --git a/phlib/include/phutil.h b/phlib/include/phutil.h index 84a3c84b047d..8c04bc616f06 100644 --- a/phlib/include/phutil.h +++ b/phlib/include/phutil.h @@ -1126,6 +1126,15 @@ PhLoadIndirectString( _In_ PWSTR SourceString ); +PHLIBAPI +BOOLEAN +NTAPI +PhExtractIcon( + _In_ PWSTR FileName, + _In_ HICON *IconLarge, + _In_ HICON *IconSmall + ); + #ifdef __cplusplus } #endif diff --git a/phlib/util.c b/phlib/util.c index 6e9b9c2bb9db..58c897b28ac5 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -5287,6 +5287,12 @@ PPH_STRING PhLoadString( return string; } +// rev from SHLoadIndirectString +/** + * Extracts a specified text resource when given that resource in the form of an indirect string (a string that begins with the '@' symbol). + * + * \param SourceString The indirect string from which the resource will be retrieved. + */ PPH_STRING PhLoadIndirectString( _In_ PWSTR SourceString ) @@ -5337,3 +5343,21 @@ PPH_STRING PhLoadIndirectString( return indirectString; } + +// rev from ExtractIconExW +BOOLEAN PhExtractIcon( + _In_ PWSTR FileName, + _In_ HICON *IconLarge, + _In_ HICON *IconSmall + ) +{ + static UINT (WINAPI *PrivateExtractIconExW)(PCWSTR, INT, HICON*, HICON*, UINT) = NULL; + + if (!PrivateExtractIconExW) + PrivateExtractIconExW = PhGetModuleProcAddress(L"user32.dll", "PrivateExtractIconExW"); + + if (!PrivateExtractIconExW) + return FALSE; + + return PrivateExtractIconExW(FileName, 0, IconLarge, IconSmall, 1) > 0; +} \ No newline at end of file diff --git a/tools/peview/peprp.c b/tools/peview/peprp.c index 22ec46ba10f2..c13e90a75d9d 100644 --- a/tools/peview/peprp.c +++ b/tools/peview/peprp.c @@ -338,13 +338,11 @@ INT_PTR CALLBACK PvpPeGeneralDlgProc( { PhInitializeImageVersionInfo(&PvImageVersionInfo, PvFileName->Buffer); - if (ExtractIconEx( + if (!PhExtractIcon( PvFileName->Buffer, - 0, &PvImageLargeIcon, - NULL, - 1 - ) == 0) + NULL + )) { PvImageLargeIcon = PhGetFileShellIcon(PvFileName->Buffer, NULL, TRUE); } From 48bc87a5a02246162dc0be31d4bce38f3fb2ff3e Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 16 Dec 2017 04:56:27 +1100 Subject: [PATCH 0622/2058] Add PH_FILEDIALOG_NOPATHVALIDATE flags, Fix PhpConvertProcessInformation warnings --- phlib/util.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/phlib/util.c b/phlib/util.c index 58c897b28ac5..9471249823ca 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -2527,12 +2527,12 @@ FORCEINLINE VOID PhpConvertProcessInformation( if (ProcessHandle) *ProcessHandle = ProcessInfo->hProcess; - else + else if (ProcessInfo->hProcess) NtClose(ProcessInfo->hProcess); if (ThreadHandle) *ThreadHandle = ProcessInfo->hThread; - else + else if (ProcessInfo->hThread) NtClose(ProcessInfo->hThread); } @@ -3894,7 +3894,8 @@ static const PH_FLAG_MAPPING PhpFileDialogIfdMappings[] = { PH_FILEDIALOG_OVERWRITEPROMPT, FOS_OVERWRITEPROMPT }, { PH_FILEDIALOG_DEFAULTEXPANDED, FOS_DEFAULTNOMINIMODE }, { PH_FILEDIALOG_STRICTFILETYPES, FOS_STRICTFILETYPES }, - { PH_FILEDIALOG_PICKFOLDERS, FOS_PICKFOLDERS } + { PH_FILEDIALOG_PICKFOLDERS, FOS_PICKFOLDERS }, + { PH_FILEDIALOG_NOPATHVALIDATE, FOS_NOVALIDATE }, }; static const PH_FLAG_MAPPING PhpFileDialogOfnMappings[] = @@ -3904,7 +3905,8 @@ static const PH_FLAG_MAPPING PhpFileDialogOfnMappings[] = { PH_FILEDIALOG_FILEMUSTEXIST, OFN_FILEMUSTEXIST }, { PH_FILEDIALOG_SHOWHIDDEN, OFN_FORCESHOWHIDDEN }, { PH_FILEDIALOG_NODEREFERENCELINKS, OFN_NODEREFERENCELINKS }, - { PH_FILEDIALOG_OVERWRITEPROMPT, OFN_OVERWRITEPROMPT } + { PH_FILEDIALOG_OVERWRITEPROMPT, OFN_OVERWRITEPROMPT }, + { PH_FILEDIALOG_NOPATHVALIDATE, OFN_NOVALIDATE } }; /** From bfd5a9fd5649cf59d2386e0844960a18f4e9b946 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 16 Dec 2017 07:04:05 +1100 Subject: [PATCH 0623/2058] Move Stage2 cached settings --- ProcessHacker/mainwnd.c | 3 +++ ProcessHacker/settings.c | 3 --- phlib/settings.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index b2031ecb6b7c..fc0b3fef3eef 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -2100,6 +2100,9 @@ VOID PhMwpLoadSettings( PhEnableServiceNonPoll = !!PhGetIntegerSetting(L"EnableServiceNonPoll"); PhEnableNetworkProviderResolve = !!PhGetIntegerSetting(L"EnableNetworkResolve"); + PhEnableProcessQueryStage2 = !!PhGetIntegerSetting(L"EnableStage2"); + PhEnableServiceQueryStage2 = !!PhGetIntegerSetting(L"EnableServiceStage2"); + PhNfLoadStage1(); PhMwpNotifyIconNotifyMask = PhGetIntegerSetting(L"IconNotifyMask"); diff --git a/ProcessHacker/settings.c b/ProcessHacker/settings.c index 77dadc5362c3..d7235af1a9e2 100644 --- a/ProcessHacker/settings.c +++ b/ProcessHacker/settings.c @@ -223,9 +223,6 @@ VOID PhUpdateCachedSettings( VOID ) { - PhEnableProcessQueryStage2 = !!PhGetIntegerSetting(L"EnableStage2"); - PhEnableServiceQueryStage2 = !!PhGetIntegerSetting(L"EnableServiceStage2"); - PH_UPDATE_SETTING(CollapseServicesOnStart); PH_UPDATE_SETTING(ForceNoParent); PH_UPDATE_SETTING(HighlightingDuration); diff --git a/phlib/settings.c b/phlib/settings.c index fd5ce5fd3e2f..0ed937f79648 100644 --- a/phlib/settings.c +++ b/phlib/settings.c @@ -83,7 +83,7 @@ VOID PhSettingsInitialization( PhIgnoredSettings = PhCreateList(4); PhAddDefaultSettings(); - PhUpdateCachedSettings(); + //PhUpdateCachedSettings(); } BOOLEAN NTAPI PhpSettingsHashtableEqualFunction( From e2536adcdb0b8335a319adb2ab8e272d6eda8f41 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 16 Dec 2017 07:19:31 +1100 Subject: [PATCH 0624/2058] Update ntldr.h types --- phnt/include/ntldr.h | 54 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/phnt/include/ntldr.h b/phnt/include/ntldr.h index 37ed1d78536b..190afe199733 100644 --- a/phnt/include/ntldr.h +++ b/phnt/include/ntldr.h @@ -625,4 +625,58 @@ typedef struct _RTL_PROCESS_MODULE_INFORMATION_EX PVOID DefaultBase; } RTL_PROCESS_MODULE_INFORMATION_EX, *PRTL_PROCESS_MODULE_INFORMATION_EX; +NTSYSAPI +NTSTATUS +NTAPI +LdrQueryProcessModuleInformation( + _In_opt_ PRTL_PROCESS_MODULES ModuleInformation, + _In_opt_ ULONG Size, + _Out_ PULONG ReturnedSize + ); + +typedef VOID (NTAPI *PLDR_ENUM_CALLBACK)( + _In_ PLDR_DATA_TABLE_ENTRY ModuleInformation, + _In_ PVOID Parameter, + _Out_ BOOLEAN *Stop + ); + +NTSYSAPI +NTSTATUS +NTAPI +LdrEnumerateLoadedModules( + _In_ BOOLEAN ReservedFlag, + _In_ PLDR_ENUM_CALLBACK EnumProc, + _In_ PVOID Context + ); + +NTSTATUS +NTAPI +LdrOpenImageFileOptionsKey( + _In_ PUNICODE_STRING SubKey, + _In_ BOOLEAN Wow64, + _Out_ PHANDLE NewKeyHandle + ); + +NTSTATUS +NTAPI +LdrQueryImageFileKeyOption( + _In_ HANDLE KeyHandle, + _In_ PCWSTR ValueName, + _In_ ULONG Type, + _Out_ PVOID Buffer, + _In_ ULONG BufferSize, + _Out_opt_ PULONG ReturnedLength + ); + +NTSTATUS +NTAPI +LdrQueryImageFileExecutionOptions( + _In_ PUNICODE_STRING SubKey, + _In_ PCWSTR ValueName, + _In_ ULONG ValueSize, + _Out_ PVOID Buffer, + _In_ ULONG BufferSize, + _Out_opt_ PULONG RetunedLength + ); + #endif From 037deb59c3aab7645532440fb72cad0548e7db65 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 16 Dec 2017 07:21:10 +1100 Subject: [PATCH 0625/2058] NetworkTools: Add preliminary warning text for extended TCP statistics --- plugins/NetworkTools/main.c | 12 ++++++++++++ plugins/NetworkTools/tracert.c | 18 ++++-------------- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/plugins/NetworkTools/main.c b/plugins/NetworkTools/main.c index 1ff9eaa5d195..cff7a526fb14 100644 --- a/plugins/NetworkTools/main.c +++ b/plugins/NetworkTools/main.c @@ -609,24 +609,36 @@ VOID UpdateNetworkNode( { if (Extension->NumberOfBytesIn) PhMoveReference(&Extension->BytesIn, PhFormatSize(Extension->NumberOfBytesIn, -1)); + + if (!NetworkExtensionEnabled && !Extension->BytesIn && PhGetOwnTokenAttributes().Elevated) + PhMoveReference(&Extension->BytesIn, PhCreateString(L"Extended TCP statisitics are disabled")); } break; case NETWORK_COLUMN_ID_BYTES_OUT: { if (Extension->NumberOfBytesOut) PhMoveReference(&Extension->BytesOut, PhFormatSize(Extension->NumberOfBytesOut, -1)); + + if (!NetworkExtensionEnabled && !Extension->BytesOut && PhGetOwnTokenAttributes().Elevated) + PhMoveReference(&Extension->BytesOut, PhCreateString(L"Extended TCP statisitics are disabled")); } break; case NETWORK_COLUMN_ID_PACKETLOSS: { if (Extension->NumberOfLostPackets) PhMoveReference(&Extension->PacketLossText, PhFormatUInt64(Extension->NumberOfLostPackets, TRUE)); + + if (!NetworkExtensionEnabled && !Extension->PacketLossText && PhGetOwnTokenAttributes().Elevated) + PhMoveReference(&Extension->PacketLossText, PhCreateString(L"Extended TCP statisitics are disabled")); } break; case NETWORK_COLUMN_ID_LATENCY: { if (Extension->SampleRtt) PhMoveReference(&Extension->LatencyText, PhFormatUInt64(Extension->SampleRtt, TRUE)); + + if (!NetworkExtensionEnabled && !Extension->LatencyText && PhGetOwnTokenAttributes().Elevated) + PhMoveReference(&Extension->LatencyText, PhCreateString(L"Extended TCP statisitics are disabled")); } break; } diff --git a/plugins/NetworkTools/tracert.c b/plugins/NetworkTools/tracert.c index c69ccd659198..87a986b61e71 100644 --- a/plugins/NetworkTools/tracert.c +++ b/plugins/NetworkTools/tracert.c @@ -178,13 +178,8 @@ VOID TracertQueueHostLookup( &remoteCountryName )) { - if (Node->RemoteCountryCode) - PhDereferenceObject(Node->RemoteCountryCode); - if (Node->RemoteCountryName) - PhDereferenceObject(Node->RemoteCountryName); - - Node->RemoteCountryCode = remoteCountryCode; - Node->RemoteCountryName = remoteCountryName; + PhMoveReference(&Node->RemoteCountryCode, remoteCountryCode); + PhMoveReference(&Node->RemoteCountryName, remoteCountryName); } } else if (Context->RemoteEndpoint.Address.Type == PH_IPV6_NETWORK_TYPE) @@ -234,13 +229,8 @@ VOID TracertQueueHostLookup( &remoteCountryName )) { - if (Node->RemoteCountryCode) - PhDereferenceObject(Node->RemoteCountryCode); - if (Node->RemoteCountryName) - PhDereferenceObject(Node->RemoteCountryName); - - Node->RemoteCountryCode = remoteCountryCode; - Node->RemoteCountryName = remoteCountryName; + PhMoveReference(&Node->RemoteCountryCode, remoteCountryCode); + PhMoveReference(&Node->RemoteCountryName, remoteCountryName); } } } From e8e11bfdddb9881399e6fbd77cf97f2fd62c3095 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 16 Dec 2017 07:24:54 +1100 Subject: [PATCH 0626/2058] Fix service error dialog #203 --- ProcessHacker/srvprp.c | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/ProcessHacker/srvprp.c b/ProcessHacker/srvprp.c index c3edcfdb001f..2cdb40209fe3 100644 --- a/ProcessHacker/srvprp.c +++ b/ProcessHacker/srvprp.c @@ -185,7 +185,8 @@ static VOID PhpRefreshControls( EnableWindow(GetDlgItem(hwndDlg, IDC_DELAYEDSTART), FALSE); } - if (PhEqualString2(PhaGetDlgItemText(hwndDlg, IDC_TYPE), L"Driver", FALSE)) + if (PhEqualString2(PhaGetDlgItemText(hwndDlg, IDC_TYPE), L"Driver", FALSE) || + PhEqualString2(PhaGetDlgItemText(hwndDlg, IDC_TYPE), L"FS driver", FALSE)) { EnableWindow(GetDlgItem(hwndDlg, IDC_USERACCOUNT), FALSE); EnableWindow(GetDlgItem(hwndDlg, IDC_PASSWORD), FALSE); @@ -552,17 +553,9 @@ INT_PTR CALLBACK PhpServiceGeneralDlgProc( goto Cleanup; ErrorCase: - if (PhShowMessage2( - hwndDlg, - TDCBF_RETRY_BUTTON | TDCBF_CANCEL_BUTTON, - TD_ERROR_ICON, - L"Unable to change service configuration.", - L"%s", - PH_AUTO_T(PH_STRING, PhGetWin32Message(GetLastError()))->Buffer - ) == IDRETRY) - { - SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_INVALID); - } + + PhShowStatus(hwndDlg, L"Unable to change service configuration.", 0, GetLastError()); + SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_INVALID); Cleanup: if (newServicePassword) From 63f295a13af3fe8e0b2f80f0a0aed577280d150e Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 16 Dec 2017 10:00:11 +1100 Subject: [PATCH 0627/2058] Add icons to services tab, Add filename to services tab, Add ServiceChangeNotification support (#203) --- ProcessHacker/include/srvlist.h | 3 +- ProcessHacker/include/srvprv.h | 6 +- ProcessHacker/srvlist.c | 60 +++-- ProcessHacker/srvprv.c | 457 +++++++++++++++++++++++--------- 4 files changed, 374 insertions(+), 152 deletions(-) diff --git a/ProcessHacker/include/srvlist.h b/ProcessHacker/include/srvlist.h index ea73a2824be3..9636369dd48d 100644 --- a/ProcessHacker/include/srvlist.h +++ b/ProcessHacker/include/srvlist.h @@ -19,8 +19,9 @@ #define PHSVTLC_KEYMODIFIEDTIME 10 #define PHSVTLC_VERIFICATIONSTATUS 11 #define PHSVTLC_VERIFIEDSIGNER 12 +#define PHSVTLC_FILENAME 13 -#define PHSVTLC_MAXIMUM 13 +#define PHSVTLC_MAXIMUM 14 #define PHSN_CONFIG 0x1 #define PHSN_DESCRIPTION 0x2 diff --git a/ProcessHacker/include/srvprv.h b/ProcessHacker/include/srvprv.h index ea4ca015cc4e..7a1034f557cd 100644 --- a/ProcessHacker/include/srvprv.h +++ b/ProcessHacker/include/srvprv.h @@ -18,6 +18,10 @@ typedef struct _PH_SERVICE_ITEM PH_STRINGREF Key; // points to Name PPH_STRING Name; PPH_STRING DisplayName; + PPH_STRING FileName; // only available after first update + + HICON SmallIcon; + HICON LargeIcon; // State ULONG Type; @@ -40,7 +44,7 @@ typedef struct _PH_SERVICE_ITEM BOOLEAN HasTriggers : 1; BOOLEAN PendingProcess : 1; BOOLEAN NeedsConfigUpdate : 1; - BOOLEAN NeedsVerifyUpdate : 1; + BOOLEAN JustProcessed : 1; BOOLEAN Spare : 3; }; }; diff --git a/ProcessHacker/srvlist.c b/ProcessHacker/srvlist.c index c1ee3fd12dfe..ee2cdc4ef3e6 100644 --- a/ProcessHacker/srvlist.c +++ b/ProcessHacker/srvlist.c @@ -77,9 +77,7 @@ static PH_TN_FILTER_SUPPORT FilterSupport; static BOOLEAN ServiceIconsLoaded = FALSE; static HICON ServiceApplicationIcon; -static HICON ServiceApplicationGoIcon; static HICON ServiceCogIcon; -static HICON ServiceCogGoIcon; BOOLEAN PhServiceTreeListStateHighlighting = TRUE; static PPH_POINTER_LIST ServiceNodeStateList = NULL; // list of nodes which need to be processed @@ -142,6 +140,7 @@ VOID PhInitializeServiceTreeList( PhAddTreeNewColumnEx(hwnd, PHSVTLC_KEYMODIFIEDTIME, FALSE, L"Key modified time", 140, PH_ALIGN_LEFT, -1, 0, TRUE); PhAddTreeNewColumn(hwnd, PHSVTLC_VERIFICATIONSTATUS, FALSE, L"Verification status", 70, PH_ALIGN_LEFT, -1, 0); PhAddTreeNewColumn(hwnd, PHSVTLC_VERIFIEDSIGNER, FALSE, L"Verified signer", 100, PH_ALIGN_LEFT, -1, 0); + PhAddTreeNewColumn(hwnd, PHSVTLC_FILENAME, FALSE, L"File name", 100, PH_ALIGN_LEFT, -1, DT_PATH_ELLIPSIS); TreeNew_SetRedraw(hwnd, TRUE); @@ -300,9 +299,7 @@ VOID PhpRemoveServiceNode( PhClearReference(&ServiceNode->BinaryPath); PhClearReference(&ServiceNode->LoadOrderGroup); PhClearReference(&ServiceNode->Description); - PhClearReference(&ServiceNode->TooltipText); - PhClearReference(&ServiceNode->KeyModifiedTimeText); PhDereferenceObject(ServiceNode->ServiceItem); @@ -495,8 +492,8 @@ static VOID PhpUpdateServiceNodeKey( int sortResult = 0; #define END_SORT_FUNCTION \ - /* if (sortResult == 0) */ \ - /* sortResult = PhCompareString(serviceItem1->Name, serviceItem2->Name, TRUE); */ \ + if (sortResult == 0) \ + sortResult = PhCompareString(serviceItem1->Name, serviceItem2->Name, TRUE); \ \ return PhModifySort(sortResult, ServiceTreeListSortOrder); \ } @@ -525,24 +522,24 @@ END_SORT_FUNCTION BEGIN_SORT_FUNCTION(Type) { - sortResult = intcmp(serviceItem1->Type, serviceItem2->Type); + sortResult = uintcmp(serviceItem1->Type, serviceItem2->Type); } END_SORT_FUNCTION BEGIN_SORT_FUNCTION(Status) { - sortResult = intcmp(serviceItem1->State, serviceItem2->State); + sortResult = uintcmp(serviceItem1->State, serviceItem2->State); } END_SORT_FUNCTION BEGIN_SORT_FUNCTION(StartType) { - sortResult = intcmp(serviceItem1->StartType, serviceItem2->StartType); + sortResult = uintcmp(serviceItem1->StartType, serviceItem2->StartType); if (sortResult == 0) - sortResult = intcmp(serviceItem1->DelayedStart, serviceItem2->DelayedStart); + sortResult = uintcmp(serviceItem1->DelayedStart, serviceItem2->DelayedStart); if (sortResult == 0) - sortResult = intcmp(serviceItem1->HasTriggers, serviceItem2->HasTriggers); + sortResult = uintcmp(serviceItem1->HasTriggers, serviceItem2->HasTriggers); } END_SORT_FUNCTION @@ -562,7 +559,7 @@ END_SORT_FUNCTION BEGIN_SORT_FUNCTION(ErrorControl) { - sortResult = intcmp(serviceItem1->ErrorControl, serviceItem2->ErrorControl); + sortResult = uintcmp(serviceItem1->ErrorControl, serviceItem2->ErrorControl); } END_SORT_FUNCTION @@ -592,7 +589,7 @@ END_SORT_FUNCTION BEGIN_SORT_FUNCTION(VerificationStatus) { - sortResult = intcmp(serviceItem1->VerifyResult, serviceItem2->VerifyResult); + sortResult = uintcmp(serviceItem1->VerifyResult, serviceItem2->VerifyResult); } END_SORT_FUNCTION @@ -606,6 +603,16 @@ BEGIN_SORT_FUNCTION(VerifiedSigner) } END_SORT_FUNCTION +BEGIN_SORT_FUNCTION(FileName) +{ + sortResult = PhCompareStringWithNull( + serviceItem1->FileName, + serviceItem2->FileName, + TRUE + ); +} +END_SORT_FUNCTION + BOOLEAN NTAPI PhpServiceTreeNewCallback( _In_ HWND hwnd, _In_ PH_TREENEW_MESSAGE Message, @@ -641,7 +648,8 @@ BOOLEAN NTAPI PhpServiceTreeNewCallback( SORT_FUNCTION(Description), SORT_FUNCTION(KeyModifiedTime), SORT_FUNCTION(VerificationStatus), - SORT_FUNCTION(VerifiedSigner) + SORT_FUNCTION(VerifiedSigner), + SORT_FUNCTION(FileName) }; int (__cdecl *sortFunction)(const void *, const void *); @@ -761,6 +769,9 @@ BOOLEAN NTAPI PhpServiceTreeNewCallback( case PHSVTLC_VERIFIEDSIGNER: getCellText->Text = PhGetStringRef(serviceItem->VerifySignerName); break; + case PHSVTLC_FILENAME: + getCellText->Text = PhGetStringRef(serviceItem->FileName); + break; default: return FALSE; } @@ -776,25 +787,22 @@ BOOLEAN NTAPI PhpServiceTreeNewCallback( if (!ServiceIconsLoaded) { - ServiceApplicationIcon = PH_LOAD_SHARED_ICON_SMALL(PhInstanceHandle, MAKEINTRESOURCE(IDI_PHAPPLICATION)); - ServiceApplicationGoIcon = PH_LOAD_SHARED_ICON_SMALL(PhInstanceHandle, MAKEINTRESOURCE(IDI_PHAPPLICATIONGO)); + HICON icon; + + PhGetStockApplicationIcon(&icon, NULL); + + ServiceApplicationIcon = icon; ServiceCogIcon = PH_LOAD_SHARED_ICON_SMALL(PhInstanceHandle, MAKEINTRESOURCE(IDI_COG)); - ServiceCogGoIcon = PH_LOAD_SHARED_ICON_SMALL(PhInstanceHandle, MAKEINTRESOURCE(IDI_COGGO)); ServiceIconsLoaded = TRUE; } - if (node->ServiceItem->Type == SERVICE_KERNEL_DRIVER || node->ServiceItem->Type == SERVICE_FILE_SYSTEM_DRIVER) - { - if (node->ServiceItem->State == SERVICE_RUNNING) - getNodeIcon->Icon = ServiceCogGoIcon; - else - getNodeIcon->Icon = ServiceCogIcon; - } + if (node->ServiceItem->SmallIcon) + getNodeIcon->Icon = node->ServiceItem->SmallIcon; else { - if (node->ServiceItem->State == SERVICE_RUNNING) - getNodeIcon->Icon = ServiceApplicationGoIcon; + if (node->ServiceItem->Type == SERVICE_KERNEL_DRIVER || node->ServiceItem->Type == SERVICE_FILE_SYSTEM_DRIVER) + getNodeIcon->Icon = ServiceCogIcon; else getNodeIcon->Icon = ServiceApplicationIcon; } diff --git a/ProcessHacker/srvprv.c b/ProcessHacker/srvprv.c index 137c1f58a4a8..3c43a2c7d99c 100644 --- a/ProcessHacker/srvprv.c +++ b/ProcessHacker/srvprv.c @@ -32,6 +32,18 @@ #include #include +typedef ULONG (WINAPI *_SubscribeServiceChangeNotifications)( + _In_ SC_HANDLE hService, + _In_ SC_EVENT_TYPE eEventType, + _In_ PSC_NOTIFICATION_CALLBACK pCallback, + _In_opt_ PVOID pCallbackContext, + _Out_ PSC_NOTIFICATION_REGISTRATION* pSubscription + ); + +typedef VOID (WINAPI *_UnsubscribeServiceChangeNotifications)( + _In_ PSC_NOTIFICATION_REGISTRATION pSubscription + ); + typedef struct _PHP_SERVICE_NAME_ENTRY { PH_HASH_ENTRY HashEntry; @@ -51,12 +63,46 @@ typedef struct _PHP_SERVICE_NOTIFY_CONTEXT { LIST_ENTRY ListEntry; SC_HANDLE ServiceHandle; - PPH_STRING ServiceName; // Valid only when adding - BOOLEAN IsServiceManager; + PPH_STRING ServiceName; + union + { + BOOLEAN Flags; + struct + { + BOOLEAN IsServiceManager : 1; + BOOLEAN JustAddedNotifyRegistration : 1; + BOOLEAN Spare : 6; + }; + }; PHP_SERVICE_NOTIFY_STATE State; SERVICE_NOTIFY Buffer; + PSC_NOTIFICATION_REGISTRATION NotifyRegistration; } PHP_SERVICE_NOTIFY_CONTEXT, *PPHP_SERVICE_NOTIFY_CONTEXT; +typedef struct _PH_SERVICE_QUERY_DATA +{ + SLIST_ENTRY ListEntry; + ULONG Stage; + PPH_SERVICE_ITEM ServiceItem; +} PH_SERVICE_QUERY_DATA, *PPH_SERVICE_QUERY_DATA; + +typedef struct _PH_SERVICE_QUERY_S1_DATA +{ + PH_SERVICE_QUERY_DATA Header; + + PPH_STRING FileName; + HICON SmallIcon; + HICON LargeIcon; +} PH_SERVICE_QUERY_S1_DATA, *PPH_SERVICE_QUERY_S1_DATA; + +typedef struct _PH_SERVICE_QUERY_S2_DATA +{ + PH_SERVICE_QUERY_DATA Header; + + VERIFY_RESULT VerifyResult; + PPH_STRING VerifySignerName; +} PH_SERVICE_QUERY_S2_DATA, *PPH_SERVICE_QUERY_S2_DATA; + VOID NTAPI PhpServiceItemDeleteProcedure( _In_ PVOID Object, _In_ ULONG Flags @@ -85,6 +131,10 @@ VOID PhpInitializeServiceNonPoll( VOID ); +VOID PhpWorkaroundWindows10ServiceTypeBug( + _Inout_ LPENUM_SERVICE_STATUS_PROCESS ServieEntry + ); + PPH_OBJECT_TYPE PhServiceItemType; PPH_HASHTABLE PhServiceHashtable; PH_QUEUED_LOCK PhServiceHashtableLock = PH_QUEUED_LOCK_INIT; @@ -102,16 +152,10 @@ static HANDLE PhpNonPollEventHandle; static PH_QUEUED_LOCK PhpNonPollServiceListLock = PH_QUEUED_LOCK_INIT; static LIST_ENTRY PhpNonPollServiceListHead; static LIST_ENTRY PhpNonPollServicePendingListHead; -static SLIST_HEADER PhpServiceQueryListHead; +static SLIST_HEADER PhpServiceQueryDataListHead; -typedef struct _PH_SERVICE_QUERY_DATA -{ - SLIST_ENTRY ListEntry; - PPH_SERVICE_ITEM ServiceItem; - - VERIFY_RESULT VerifyResult; - PPH_STRING VerifySignerName; -} PH_SERVICE_QUERY_DATA, *PPH_SERVICE_QUERY_DATA; +static _SubscribeServiceChangeNotifications SubscribeServiceChangeNotifications_I; +static _UnsubscribeServiceChangeNotifications UnsubscribeServiceChangeNotifications_I; BOOLEAN PhServiceProviderInitialization( VOID @@ -125,7 +169,13 @@ BOOLEAN PhServiceProviderInitialization( 40 ); - RtlInitializeSListHead(&PhpServiceQueryListHead); + RtlInitializeSListHead(&PhpServiceQueryDataListHead); + + if (WindowsVersion > WINDOWS_7) + { + SubscribeServiceChangeNotifications_I = PhGetModuleProcAddress(L"secHost.dll", "SubscribeServiceChangeNotifications"); + UnsubscribeServiceChangeNotifications_I = PhGetModuleProcAddress(L"secHost.dll", "UnsubscribeServiceChangeNotifications"); + } return TRUE; } @@ -144,15 +194,6 @@ PPH_SERVICE_ITEM PhCreateServiceItem( if (Information) { - if (WindowsVersion >= WINDOWS_10_RS2) - { - // https://github.com/processhacker2/processhacker/issues/120 - if (Information->ServiceStatusProcess.dwServiceType == SERVICE_WIN32) - Information->ServiceStatusProcess.dwServiceType = SERVICE_WIN32_SHARE_PROCESS; - if (Information->ServiceStatusProcess.dwServiceType == (SERVICE_WIN32 | SERVICE_USER_SHARE_PROCESS | SERVICE_USERSERVICE_INSTANCE)) - Information->ServiceStatusProcess.dwServiceType = SERVICE_USER_SHARE_PROCESS | SERVICE_USERSERVICE_INSTANCE; - } - serviceItem->Name = PhCreateString(Information->lpServiceName); serviceItem->Key = serviceItem->Name->sr; serviceItem->DisplayName = PhCreateString(Information->lpDisplayName); @@ -182,6 +223,11 @@ VOID PhpServiceItemDeleteProcedure( if (serviceItem->Name) PhDereferenceObject(serviceItem->Name); if (serviceItem->DisplayName) PhDereferenceObject(serviceItem->DisplayName); + if (serviceItem->FileName) PhDereferenceObject(serviceItem->FileName); + if (serviceItem->VerifySignerName) PhDereferenceObject(serviceItem->VerifySignerName); + if (serviceItem->SmallIcon) DestroyIcon(serviceItem->SmallIcon); + if (serviceItem->LargeIcon) DestroyIcon(serviceItem->LargeIcon); + //PhDeleteImageVersionInfo(&serviceItem->VersionInfo); } BOOLEAN PhpServiceHashtableEqualFunction( @@ -247,22 +293,21 @@ PPH_SERVICE_ITEM PhReferenceServiceItem( return serviceItem; } -VOID PhMarkNeedsConfigUpdateServiceItem( - _In_ PPH_SERVICE_ITEM ServiceItem +VOID PhpResetServiceNonPollGate( + VOID ) { - ServiceItem->NeedsConfigUpdate = TRUE; - if (PhEnableServiceNonPoll) - PhpNonPollGate = 1; + InterlockedExchange(&PhpNonPollGate, 1); } -VOID PhpResetServiceNonPollGate( - VOID +VOID PhMarkNeedsConfigUpdateServiceItem( + _In_ PPH_SERVICE_ITEM ServiceItem ) { - if (PhEnableServiceNonPoll) - PhpNonPollGate = 1; + ServiceItem->NeedsConfigUpdate = TRUE; + + PhpResetServiceNonPollGate(); } VOID PhpRemoveServiceItem( @@ -464,61 +509,149 @@ static ULONG PhpHashServiceNameEntry( return PhHashStringRef(&Value->Name, TRUE); } -NTSTATUS PhpServiceQueryWorker( - _In_ PVOID Parameter +VOID PhpServiceQueryStage1( + _Inout_ PPH_SERVICE_QUERY_S1_DATA Data ) { - PPH_SERVICE_QUERY_DATA data = (PPH_SERVICE_QUERY_DATA)Parameter; + PPH_SERVICE_ITEM serviceItem = Data->Header.ServiceItem; SC_HANDLE serviceHandle; - PPH_STRING serviceFileName = NULL; - if (serviceHandle = PhOpenService(data->ServiceItem->Name->Buffer, SERVICE_QUERY_CONFIG)) + if (serviceHandle = PhOpenService(serviceItem->Name->Buffer, SERVICE_QUERY_CONFIG)) { - serviceFileName = PhGetServiceRelevantFileName(&data->ServiceItem->Name->sr, serviceHandle); + Data->FileName = PhGetServiceRelevantFileName(&serviceItem->Name->sr, serviceHandle); CloseServiceHandle(serviceHandle); } - if (serviceFileName) + if (Data->FileName) + { + if (!PhExtractIcon(Data->FileName->Buffer, &Data->LargeIcon, &Data->SmallIcon)) + { + Data->LargeIcon = NULL; + Data->SmallIcon = NULL; + } + + // Version info. + //PhInitializeImageVersionInfo(&Data->VersionInfo, Data->FileName->Buffer); + } + + PhpResetServiceNonPollGate(); // HACK +} + +VOID PhpServiceQueryStage2( + _Inout_ PPH_SERVICE_QUERY_S2_DATA Data + ) +{ + PPH_SERVICE_ITEM serviceItem = Data->Header.ServiceItem; + + if (serviceItem->FileName) { - data->VerifyResult = PhVerifyFileCached( - serviceFileName, + Data->VerifyResult = PhVerifyFileCached( + serviceItem->FileName, NULL, - &data->VerifySignerName, + &Data->VerifySignerName, FALSE ); - - PhDereferenceObject(serviceFileName); } PhpResetServiceNonPollGate(); // HACK +} - RtlInterlockedPushEntrySList(&PhpServiceQueryListHead, &data->ListEntry); +NTSTATUS PhpServiceQueryStage1Worker( + _In_ PVOID Parameter + ) +{ + PPH_SERVICE_QUERY_S1_DATA data; + PPH_SERVICE_ITEM serviceItem = (PPH_SERVICE_ITEM)Parameter; + + data = PhAllocate(sizeof(PH_SERVICE_QUERY_S1_DATA)); + memset(data, 0, sizeof(PH_SERVICE_QUERY_S1_DATA)); + data->Header.Stage = 1; + data->Header.ServiceItem = serviceItem; + + PhpServiceQueryStage1(data); + + RtlInterlockedPushEntrySList(&PhpServiceQueryDataListHead, &data->Header.ListEntry); return STATUS_SUCCESS; } -VOID PhpQueueServiceQuery( +NTSTATUS PhpServiceQueryStage2Worker( + _In_ PVOID Parameter + ) +{ + PPH_SERVICE_QUERY_S2_DATA data; + PPH_SERVICE_ITEM serviceItem = (PPH_SERVICE_ITEM)Parameter; + + data = PhAllocate(sizeof(PH_SERVICE_QUERY_S2_DATA)); + memset(data, 0, sizeof(PH_SERVICE_QUERY_S2_DATA)); + data->Header.Stage = 2; + data->Header.ServiceItem = serviceItem; + + PhpServiceQueryStage2(data); + + RtlInterlockedPushEntrySList(&PhpServiceQueryDataListHead, &data->Header.ListEntry); + + return STATUS_SUCCESS; +} + +VOID PhpQueueServiceQueryStage1( + _In_ PPH_SERVICE_ITEM ServiceItem + ) +{ + PH_WORK_QUEUE_ENVIRONMENT environment; + + PhReferenceObject(ServiceItem); + + PhInitializeWorkQueueEnvironment(&environment); + environment.BasePriority = THREAD_PRIORITY_BELOW_NORMAL; + environment.IoPriority = IoPriorityLow; + environment.PagePriority = MEMORY_PRIORITY_LOW; + + PhQueueItemWorkQueueEx(PhGetGlobalWorkQueue(), PhpServiceQueryStage1Worker, ServiceItem, NULL, &environment); +} + +VOID PhpQueueServiceQueryStage2( _In_ PPH_SERVICE_ITEM ServiceItem ) { - PPH_SERVICE_QUERY_DATA data; PH_WORK_QUEUE_ENVIRONMENT environment; if (!PhEnableServiceQueryStage2) return; - data = PhAllocate(sizeof(PH_SERVICE_QUERY_DATA)); - memset(data, 0, sizeof(PH_SERVICE_QUERY_DATA)); - data->ServiceItem = ServiceItem; - PhReferenceObject(ServiceItem); PhInitializeWorkQueueEnvironment(&environment); environment.BasePriority = THREAD_PRIORITY_BELOW_NORMAL; - environment.IoPriority = IoPriorityLow; - environment.PagePriority = MEMORY_PRIORITY_LOW; + environment.IoPriority = IoPriorityVeryLow; + environment.PagePriority = MEMORY_PRIORITY_VERY_LOW; + + PhQueueItemWorkQueueEx(PhGetGlobalWorkQueue(), PhpServiceQueryStage2Worker, ServiceItem, NULL, &environment); +} + +VOID PhpFillServiceItemStage1( + _In_ PPH_SERVICE_QUERY_S1_DATA Data + ) +{ + PPH_SERVICE_ITEM serviceItem = Data->Header.ServiceItem; + + serviceItem->FileName = Data->FileName; + serviceItem->SmallIcon = Data->SmallIcon; + serviceItem->LargeIcon = Data->LargeIcon; + //memcpy(&processItem->VersionInfo, &Data->VersionInfo, sizeof(PH_IMAGE_VERSION_INFO)); + + // Note: Queue stage 2 processing after filling stage1 process data. + PhpQueueServiceQueryStage2(serviceItem); +} + +VOID PhpFillServiceItemStage2( + _In_ PPH_SERVICE_QUERY_S2_DATA Data + ) +{ + PPH_SERVICE_ITEM serviceItem = Data->Header.ServiceItem; - PhQueueItemWorkQueueEx(PhGetGlobalWorkQueue(), PhpServiceQueryWorker, data, NULL, &environment); + serviceItem->VerifyResult = Data->VerifyResult; + serviceItem->VerifySignerName = Data->VerifySignerName; } VOID PhFlushServiceQueryData( @@ -528,20 +661,26 @@ VOID PhFlushServiceQueryData( PSLIST_ENTRY entry; PPH_SERVICE_QUERY_DATA data; - if (!RtlFirstEntrySList(&PhpServiceQueryListHead)) + if (!RtlFirstEntrySList(&PhpServiceQueryDataListHead)) return; - entry = RtlInterlockedFlushSList(&PhpServiceQueryListHead); + entry = RtlInterlockedFlushSList(&PhpServiceQueryDataListHead); while (entry) { data = CONTAINING_RECORD(entry, PH_SERVICE_QUERY_DATA, ListEntry); entry = entry->Next; - data->ServiceItem->VerifyResult = data->VerifyResult; - data->ServiceItem->VerifySignerName = data->VerifySignerName; + if (data->Stage == 1) + { + PhpFillServiceItemStage1((PPH_SERVICE_QUERY_S1_DATA)data); + } + else if (data->Stage == 2) + { + PhpFillServiceItemStage2((PPH_SERVICE_QUERY_S2_DATA)data); + } - data->ServiceItem->NeedsVerifyUpdate = TRUE; + data->ServiceItem->JustProcessed = TRUE; PhDereferenceObject(data->ServiceItem); PhFree(data); @@ -554,12 +693,10 @@ VOID PhServiceProviderUpdate( { static SC_HANDLE scManagerHandle = NULL; static ULONG runCount = 0; - static PPH_HASH_ENTRY nameHashSet[256]; static PPHP_SERVICE_NAME_ENTRY nameEntries = NULL; static ULONG nameEntriesCount; static ULONG nameEntriesAllocated = 0; - LPENUM_SERVICE_STATUS_PROCESS services; ULONG numberOfServices; ULONG i; @@ -622,6 +759,10 @@ VOID PhServiceProviderUpdate( entry = &nameEntries[nameEntriesCount++]; PhInitializeStringRefLongHint(&entry->Name, services[i].lpServiceName); entry->ServiceEntry = &services[i]; + + if (WindowsVersion >= WINDOWS_10_RS2) + PhpWorkaroundWindows10ServiceTypeBug(entry->ServiceEntry); + PhAddEntryHashSet( nameHashSet, PH_HASH_SET_SIZE(nameHashSet), @@ -754,8 +895,23 @@ VOID PhServiceProviderUpdate( } } - // Queue for verification. - PhpQueueServiceQuery(serviceItem); + // If this is the first run of the provider, queue the + // process query tasks. Otherwise, perform stage 1 + // processing now and queue stage 2 processing. + if (runCount > 0) + { + PH_SERVICE_QUERY_S1_DATA data; + + memset(&data, 0, sizeof(PH_SERVICE_QUERY_S1_DATA)); + data.Header.Stage = 1; + data.Header.ServiceItem = serviceItem; + PhpServiceQueryStage1(&data); + PhpFillServiceItemStage1(&data); + } + else + { + PhpQueueServiceQueryStage1(serviceItem); + } // Add the service item to the hashtable. PhAcquireQueuedLockExclusive(&PhServiceHashtableLock); @@ -767,22 +923,13 @@ VOID PhServiceProviderUpdate( } else { - if (WindowsVersion >= WINDOWS_10_RS2) - { - // https://github.com/processhacker2/processhacker/issues/120 - if (serviceEntry->ServiceStatusProcess.dwServiceType == SERVICE_WIN32) - serviceEntry->ServiceStatusProcess.dwServiceType = SERVICE_WIN32_SHARE_PROCESS; - if (serviceEntry->ServiceStatusProcess.dwServiceType == (SERVICE_WIN32 | SERVICE_USER_SHARE_PROCESS | SERVICE_USERSERVICE_INSTANCE)) - serviceEntry->ServiceStatusProcess.dwServiceType = SERVICE_USER_SHARE_PROCESS | SERVICE_USERSERVICE_INSTANCE; - } - if ( serviceItem->Type != serviceEntry->ServiceStatusProcess.dwServiceType || serviceItem->State != serviceEntry->ServiceStatusProcess.dwCurrentState || serviceItem->ControlsAccepted != serviceEntry->ServiceStatusProcess.dwControlsAccepted || serviceItem->ProcessId != UlongToHandle(serviceEntry->ServiceStatusProcess.dwProcessId) || serviceItem->NeedsConfigUpdate || - serviceItem->NeedsVerifyUpdate + serviceItem->JustProcessed ) { PH_SERVICE_MODIFIED_DATA serviceModifiedData; @@ -876,8 +1023,8 @@ VOID PhServiceProviderUpdate( serviceItem->NeedsConfigUpdate = FALSE; } - if (serviceItem->NeedsVerifyUpdate) // HACK - serviceItem->NeedsVerifyUpdate = FALSE; + if (serviceItem->JustProcessed) // HACK + serviceItem->JustProcessed = FALSE; // Raise the service modified event. PhInvokeCallback(&PhServiceModifiedEvent, &serviceModifiedData); @@ -897,12 +1044,12 @@ VOID CALLBACK PhpServiceNonPollScNotifyCallback( _In_ PVOID pParameter ) { - PSERVICE_NOTIFYW notifyBuffer = pParameter; + PSERVICE_NOTIFY notifyBuffer = pParameter; PPHP_SERVICE_NOTIFY_CONTEXT notifyContext = notifyBuffer->pContext; if (notifyBuffer->dwNotificationStatus == ERROR_SUCCESS) { - if ((notifyBuffer->dwNotificationTriggered & (SERVICE_NOTIFY_CREATED | SERVICE_NOTIFY_DELETED)) && + if ((notifyBuffer->dwNotificationTriggered & (SERVICE_NOTIFY_CREATED | SERVICE_NOTIFY_DELETED)) && notifyBuffer->pszServiceNames) { PWSTR name; @@ -963,6 +1110,9 @@ VOID PhpDestroyServiceNotifyContext( _In_ PPHP_SERVICE_NOTIFY_CONTEXT NotifyContext ) { + if (UnsubscribeServiceChangeNotifications_I && NotifyContext->NotifyRegistration) + UnsubscribeServiceChangeNotifications_I(NotifyContext->NotifyRegistration); + if (NotifyContext->Buffer.pszServiceNames) LocalFree(NotifyContext->Buffer.pszServiceNames); @@ -971,6 +1121,31 @@ VOID PhpDestroyServiceNotifyContext( PhFree(NotifyContext); } +VOID CALLBACK PhpServicePropertyChangeNotifyCallback( + _In_ ULONG ServiceNotifyFlags, + _In_opt_ PVOID Context + ) +{ + PPHP_SERVICE_NOTIFY_CONTEXT notifyContext = Context; + PPH_SERVICE_ITEM serviceItem; + + if (notifyContext->JustAddedNotifyRegistration) + { + notifyContext->JustAddedNotifyRegistration = FALSE; + return; + } + + if (!PhIsNullOrEmptyString(notifyContext->ServiceName)) + { + if (serviceItem = PhReferenceServiceItem(notifyContext->ServiceName->Buffer)) + { + PhMarkNeedsConfigUpdateServiceItem(serviceItem); + + PhDereferenceObject(serviceItem); + } + } +} + NTSTATUS PhpServiceNonPollThreadStart( _In_ PVOID Parameter ) @@ -1007,12 +1182,16 @@ NTSTATUS PhpServiceNonPollThreadStart( { SC_HANDLE serviceHandle; - if (serviceHandle = OpenService(scManagerHandle, services[i].lpServiceName, SERVICE_QUERY_STATUS)) + if (!(serviceHandle = OpenService(scManagerHandle, services[i].lpServiceName, SERVICE_QUERY_STATUS | SERVICE_QUERY_CONFIG))) + serviceHandle = OpenService(scManagerHandle, services[i].lpServiceName, SERVICE_QUERY_STATUS); + + if (serviceHandle) { notifyContext = PhAllocate(sizeof(PHP_SERVICE_NOTIFY_CONTEXT)); memset(notifyContext, 0, sizeof(PHP_SERVICE_NOTIFY_CONTEXT)); notifyContext->ServiceHandle = serviceHandle; notifyContext->State = SnNotify; + notifyContext->ServiceName = PhCreateString(services[i].lpServiceName); InsertTailList(&PhpNonPollServicePendingListHead, ¬ifyContext->ListEntry); } } @@ -1039,61 +1218,80 @@ NTSTATUS PhpServiceNonPollThreadStart( switch (notifyContext->State) { - case SnNone: - break; - case SnAdding: - notifyContext->ServiceHandle = - OpenService(scManagerHandle, notifyContext->ServiceName->Buffer, SERVICE_QUERY_STATUS); - - if (!notifyContext->ServiceHandle) - { - RemoveEntryList(¬ifyContext->ListEntry); - PhpDestroyServiceNotifyContext(notifyContext); - continue; - } - - PhClearReference(¬ifyContext->ServiceName); - notifyContext->State = SnNotify; - goto NotifyCase; case SnRemoving: RemoveEntryList(¬ifyContext->ListEntry); PhpDestroyServiceNotifyContext(notifyContext); break; - case SnNotify: -NotifyCase: - memset(¬ifyContext->Buffer, 0, sizeof(SERVICE_NOTIFY)); - notifyContext->Buffer.dwVersion = SERVICE_NOTIFY_STATUS_CHANGE; - notifyContext->Buffer.pfnNotifyCallback = PhpServiceNonPollScNotifyCallback; - notifyContext->Buffer.pContext = notifyContext; - - result = NotifyServiceStatusChange( - notifyContext->ServiceHandle, - notifyContext->IsServiceManager - ? (SERVICE_NOTIFY_CREATED | SERVICE_NOTIFY_DELETED) - : (SERVICE_NOTIFY_STOPPED | SERVICE_NOTIFY_START_PENDING | SERVICE_NOTIFY_STOP_PENDING | - SERVICE_NOTIFY_RUNNING | SERVICE_NOTIFY_CONTINUE_PENDING | SERVICE_NOTIFY_PAUSE_PENDING | - SERVICE_NOTIFY_PAUSED | SERVICE_NOTIFY_DELETE_PENDING), - ¬ifyContext->Buffer - ); - - switch (result) + case SnAdding: { - case ERROR_SUCCESS: - notifyContext->State = SnNone; - RemoveEntryList(¬ifyContext->ListEntry); - InsertTailList(&PhpNonPollServiceListHead, ¬ifyContext->ListEntry); - break; - case ERROR_SERVICE_NOTIFY_CLIENT_LAGGING: - // We are lagging behind. Re-open the handle to the SCM as soon as possible. - lagging = TRUE; - break; - case ERROR_SERVICE_MARKED_FOR_DELETE: - default: - RemoveEntryList(¬ifyContext->ListEntry); - PhpDestroyServiceNotifyContext(notifyContext); - break; + notifyContext->ServiceHandle = + OpenService(scManagerHandle, notifyContext->ServiceName->Buffer, SERVICE_QUERY_STATUS | SERVICE_QUERY_CONFIG); + + if (!notifyContext->ServiceHandle) + OpenService(scManagerHandle, notifyContext->ServiceName->Buffer, SERVICE_QUERY_STATUS); + + if (!notifyContext->ServiceHandle) + { + RemoveEntryList(¬ifyContext->ListEntry); + PhpDestroyServiceNotifyContext(notifyContext); + continue; + } + + notifyContext->State = SnNotify; } + __fallthrough; + case SnNotify: + { + if (SubscribeServiceChangeNotifications_I && !notifyContext->IsServiceManager) + { + PSC_NOTIFICATION_REGISTRATION serviceNotifyRegistration; + + if (SubscribeServiceChangeNotifications_I( + notifyContext->ServiceHandle, + SC_EVENT_PROPERTY_CHANGE, // TODO: SC_EVENT_STATUS_CHANGE + PhpServicePropertyChangeNotifyCallback, + notifyContext, + &serviceNotifyRegistration + ) == ERROR_SUCCESS) + { + notifyContext->JustAddedNotifyRegistration = TRUE; + notifyContext->NotifyRegistration = serviceNotifyRegistration; + } + } + memset(¬ifyContext->Buffer, 0, sizeof(SERVICE_NOTIFY)); + notifyContext->Buffer.dwVersion = SERVICE_NOTIFY_STATUS_CHANGE; + notifyContext->Buffer.pfnNotifyCallback = PhpServiceNonPollScNotifyCallback; + notifyContext->Buffer.pContext = notifyContext; + + result = NotifyServiceStatusChange( + notifyContext->ServiceHandle, + notifyContext->IsServiceManager + ? (SERVICE_NOTIFY_CREATED | SERVICE_NOTIFY_DELETED) + : (SERVICE_NOTIFY_STOPPED | SERVICE_NOTIFY_START_PENDING | SERVICE_NOTIFY_STOP_PENDING | + SERVICE_NOTIFY_RUNNING | SERVICE_NOTIFY_CONTINUE_PENDING | SERVICE_NOTIFY_PAUSE_PENDING | + SERVICE_NOTIFY_PAUSED | SERVICE_NOTIFY_DELETE_PENDING), + ¬ifyContext->Buffer + ); + + switch (result) + { + case ERROR_SUCCESS: + notifyContext->State = SnNone; + RemoveEntryList(¬ifyContext->ListEntry); + InsertTailList(&PhpNonPollServiceListHead, ¬ifyContext->ListEntry); + break; + case ERROR_SERVICE_NOTIFY_CLIENT_LAGGING: + // We are lagging behind. Re-open the handle to the SCM as soon as possible. + lagging = TRUE; + break; + case ERROR_SERVICE_MARKED_FOR_DELETE: + default: + RemoveEntryList(¬ifyContext->ListEntry); + PhpDestroyServiceNotifyContext(notifyContext); + break; + } + } break; } } @@ -1149,3 +1347,14 @@ VOID PhpInitializeServiceNonPoll( PhCreateThread2(PhpServiceNonPollThreadStart, NULL); } + +VOID PhpWorkaroundWindows10ServiceTypeBug( + _Inout_ LPENUM_SERVICE_STATUS_PROCESS ServieEntry + ) +{ + // https://github.com/processhacker2/processhacker/issues/120 + if (ServieEntry->ServiceStatusProcess.dwServiceType == SERVICE_WIN32) + ServieEntry->ServiceStatusProcess.dwServiceType = SERVICE_WIN32_SHARE_PROCESS; + if (ServieEntry->ServiceStatusProcess.dwServiceType == (SERVICE_WIN32 | SERVICE_USER_SHARE_PROCESS | SERVICE_USERSERVICE_INSTANCE)) + ServieEntry->ServiceStatusProcess.dwServiceType = SERVICE_USER_SHARE_PROCESS | SERVICE_USERSERVICE_INSTANCE; +} From 7f39241515d08bf7574c97c5b32270548a34fc60 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 16 Dec 2017 22:12:13 +1100 Subject: [PATCH 0628/2058] Fix typo --- ProcessHacker/srvprv.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ProcessHacker/srvprv.c b/ProcessHacker/srvprv.c index 3c43a2c7d99c..b6d1caf0fabf 100644 --- a/ProcessHacker/srvprv.c +++ b/ProcessHacker/srvprv.c @@ -173,8 +173,8 @@ BOOLEAN PhServiceProviderInitialization( if (WindowsVersion > WINDOWS_7) { - SubscribeServiceChangeNotifications_I = PhGetModuleProcAddress(L"secHost.dll", "SubscribeServiceChangeNotifications"); - UnsubscribeServiceChangeNotifications_I = PhGetModuleProcAddress(L"secHost.dll", "UnsubscribeServiceChangeNotifications"); + SubscribeServiceChangeNotifications_I = PhGetModuleProcAddress(L"sechost.dll", "SubscribeServiceChangeNotifications"); + UnsubscribeServiceChangeNotifications_I = PhGetModuleProcAddress(L"sechost.dll", "UnsubscribeServiceChangeNotifications"); } return TRUE; From 007ce0f63dd5698c127f0ee6b389c24159d508d7 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 17 Dec 2017 06:20:28 +1100 Subject: [PATCH 0629/2058] Fix crash handling service property notifications --- ProcessHacker/srvprv.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ProcessHacker/srvprv.c b/ProcessHacker/srvprv.c index b6d1caf0fabf..b6738b57cdc7 100644 --- a/ProcessHacker/srvprv.c +++ b/ProcessHacker/srvprv.c @@ -1129,6 +1129,11 @@ VOID CALLBACK PhpServicePropertyChangeNotifyCallback( PPHP_SERVICE_NOTIFY_CONTEXT notifyContext = Context; PPH_SERVICE_ITEM serviceItem; + // Note: Ignore deleted nofications since we handle this elsewhere and our + // notify context gets destroyed before services.exe invokes this callback. + if (ServiceNotifyFlags == SERVICE_NOTIFY_DELETED) + return; + if (notifyContext->JustAddedNotifyRegistration) { notifyContext->JustAddedNotifyRegistration = FALSE; From f527abf107124297aa2c39b276a7a4a5c4224671 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 17 Dec 2017 06:21:33 +1100 Subject: [PATCH 0630/2058] Fix service error message text --- ProcessHacker/actions.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ProcessHacker/actions.c b/ProcessHacker/actions.c index 868753e1df70..485f4a2ea2ef 100644 --- a/ProcessHacker/actions.c +++ b/ProcessHacker/actions.c @@ -1924,7 +1924,7 @@ static VOID PhpShowErrorService( PhShowStatus( hWnd, PhaFormatString( - L"Unable to %s %s", + L"Unable to %s %s.", Verb, Service->Name->Buffer )->Buffer, From 6ad67a6153fd813ef3a31b5337ba60efc0f102a4 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 17 Dec 2017 06:50:21 +1100 Subject: [PATCH 0631/2058] Allow partial runas dialog executable paths, Fix runas crash --- ProcessHacker/runas.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/ProcessHacker/runas.c b/ProcessHacker/runas.c index e204caab1d10..592fd75192c2 100644 --- a/ProcessHacker/runas.c +++ b/ProcessHacker/runas.c @@ -386,10 +386,23 @@ INT_PTR CALLBACK PhpRunAsDlgProc( if (PhIsNullOrEmptyString(program)) break; - // Escape the path. (dmex: poor man's PathQuoteSpaces) - if (!PhStartsWithString2(program, L"\"", FALSE) && PhFindCharInString(program, 0, L' ') != -1) + if (RtlDoesFileExists_U(program->Buffer)) { - programEscaped = PhaConcatStrings(3, L"\"", PhGetString(program), L"\""); + // Escape the path. (dmex: poor man's PathQuoteSpaces) + if (!PhStartsWithString2(program, L"\"", FALSE) && PhFindCharInString(program, 0, L' ') != -1) + programEscaped = PhaConcatStrings(3, L"\"", PhGetString(program), L"\""); + else + programEscaped = program; + } + else + { + WCHAR buffer[MAX_PATH]; + + // The user typed a name without a path so attempt to locate the executable. + if (PhSearchFilePath(program->Buffer, L".exe", buffer)) + programEscaped = PhaConcatStrings(3, L"\"", buffer, L"\""); + else + programEscaped = NULL; } // Fix up the user name if it doesn't have a domain. @@ -441,7 +454,7 @@ INT_PTR CALLBACK PhpRunAsDlgProc( PhpSplitUserName(userName->Buffer, &domainPart, &userPart); memset(&createInfo, 0, sizeof(PH_CREATE_PROCESS_AS_USER_INFO)); - createInfo.CommandLine = programEscaped->Buffer; + createInfo.CommandLine = PhGetString(programEscaped); createInfo.UserName = PhGetString(userPart); createInfo.DomainName = PhGetString(domainPart); createInfo.Password = PhGetStringOrEmpty(password); @@ -467,7 +480,7 @@ INT_PTR CALLBACK PhpRunAsDlgProc( { status = PhExecuteRunAsCommand2( hwndDlg, - programEscaped->Buffer, + PhGetString(programEscaped), userName->Buffer, PhGetStringOrEmpty(password), logonType, From 685a8228cc8c2c97fda142290398527d2f50743a Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 17 Dec 2017 07:18:08 +1100 Subject: [PATCH 0632/2058] Export PhSearchFilePath --- phlib/include/phutil.h | 9 +++ phlib/util.c | 121 ++++++++++++++++++++++------------------- 2 files changed, 73 insertions(+), 57 deletions(-) diff --git a/phlib/include/phutil.h b/phlib/include/phutil.h index 8c04bc616f06..38027644c8e1 100644 --- a/phlib/include/phutil.h +++ b/phlib/include/phutil.h @@ -1073,6 +1073,15 @@ PhParseCommandLineFuzzy( _Out_opt_ PPH_STRING *FullFileName ); +PHLIBAPI +BOOLEAN +NTAPI +PhSearchFilePath( + _In_ PWSTR FileName, + _In_opt_ PWSTR Extension, + _Out_writes_(MAX_PATH) PWSTR Buffer + ); + PHLIBAPI PPH_STRING NTAPI diff --git a/phlib/util.c b/phlib/util.c index 9471249823ca..d21a2fe255d5 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -4860,59 +4860,6 @@ PPH_STRING PhEscapeCommandLinePart( return PhFinalStringBuilderString(&stringBuilder); } -BOOLEAN PhpSearchFilePath( - _In_ PWSTR FileName, - _In_opt_ PWSTR Extension, - _Out_writes_(MAX_PATH) PWSTR Buffer - ) -{ - NTSTATUS status; - ULONG result; - UNICODE_STRING fileName; - OBJECT_ATTRIBUTES objectAttributes; - FILE_BASIC_INFORMATION basicInfo; - - result = SearchPath( - NULL, - FileName, - Extension, - MAX_PATH, - Buffer, - NULL - ); - - if (result == 0 || result >= MAX_PATH) - return FALSE; - - // Make sure this is not a directory. - - if (!NT_SUCCESS(RtlDosPathNameToNtPathName_U_WithStatus( - Buffer, - &fileName, - NULL, - NULL - ))) - return FALSE; - - InitializeObjectAttributes( - &objectAttributes, - &fileName, - OBJ_CASE_INSENSITIVE, - NULL, - NULL - ); - - status = NtQueryAttributesFile(&objectAttributes, &basicInfo); - RtlFreeUnicodeString(&fileName); - - if (!NT_SUCCESS(status)) - return FALSE; - if (basicInfo.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) - return FALSE; - - return TRUE; -} - /** * Parses a command line string. If the string does not contain quotation marks around the file name * part, the function determines the file name to use. @@ -4984,7 +4931,7 @@ BOOLEAN PhParseCommandLineFuzzy( tempCommandLine = PhCreateString2(&commandLine); - if (PhpSearchFilePath(tempCommandLine->Buffer, L".exe", buffer)) + if (PhSearchFilePath(tempCommandLine->Buffer, L".exe", buffer)) { *FullFileName = PhCreateString(buffer); } @@ -5030,7 +4977,7 @@ BOOLEAN PhParseCommandLineFuzzy( *(remainingPart.Buffer - 1) = 0; } - result = PhpSearchFilePath(temp.Buffer, L".exe", buffer); + result = PhSearchFilePath(temp.Buffer, L".exe", buffer); if (found) { @@ -5065,6 +5012,60 @@ BOOLEAN PhParseCommandLineFuzzy( return FALSE; } +BOOLEAN PhSearchFilePath( + _In_ PWSTR FileName, + _In_opt_ PWSTR Extension, + _Out_writes_(MAX_PATH) PWSTR Buffer + ) +{ + NTSTATUS status; + ULONG result; + UNICODE_STRING fileName; + OBJECT_ATTRIBUTES objectAttributes; + FILE_BASIC_INFORMATION basicInfo; + + result = SearchPath( + NULL, + FileName, + Extension, + MAX_PATH, + Buffer, + NULL + ); + + if (result == 0 || result >= MAX_PATH) + return FALSE; + + // Make sure this is not a directory. + + if (!NT_SUCCESS(RtlDosPathNameToNtPathName_U_WithStatus( + Buffer, + &fileName, + NULL, + NULL + ))) + return FALSE; + + InitializeObjectAttributes( + &objectAttributes, + &fileName, + OBJ_CASE_INSENSITIVE, + NULL, + NULL + ); + + status = NtQueryAttributesFile(&objectAttributes, &basicInfo); + RtlFreeUnicodeString(&fileName); + + if (!NT_SUCCESS(status)) + return FALSE; + if (basicInfo.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) + return FALSE; + + return TRUE; +} + + PPH_STRING PhGetCacheDirectory( VOID ) @@ -5353,10 +5354,16 @@ BOOLEAN PhExtractIcon( _In_ HICON *IconSmall ) { + static PH_INITONCE initOnce = PH_INITONCE_INIT; static UINT (WINAPI *PrivateExtractIconExW)(PCWSTR, INT, HICON*, HICON*, UINT) = NULL; - if (!PrivateExtractIconExW) - PrivateExtractIconExW = PhGetModuleProcAddress(L"user32.dll", "PrivateExtractIconExW"); + if (PhBeginInitOnce(&initOnce)) + { + if (!PrivateExtractIconExW) + PrivateExtractIconExW = PhGetModuleProcAddress(L"user32.dll", "PrivateExtractIconExW"); + + PhEndInitOnce(&initOnce); + } if (!PrivateExtractIconExW) return FALSE; From 49a1d795226205c5cf25fac16450ccf4bc8e3e50 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 18 Dec 2017 02:56:42 +1100 Subject: [PATCH 0633/2058] Partial revert bfd5a9fd --- phlib/settings.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phlib/settings.c b/phlib/settings.c index 0ed937f79648..fd5ce5fd3e2f 100644 --- a/phlib/settings.c +++ b/phlib/settings.c @@ -83,7 +83,7 @@ VOID PhSettingsInitialization( PhIgnoredSettings = PhCreateList(4); PhAddDefaultSettings(); - //PhUpdateCachedSettings(); + PhUpdateCachedSettings(); } BOOLEAN NTAPI PhpSettingsHashtableEqualFunction( From 0afaccf3d089a90189f736e216695c81020205e0 Mon Sep 17 00:00:00 2001 From: diversenok <30962924+diversenok@users.noreply.github.com> Date: Mon, 18 Dec 2017 03:02:23 +0300 Subject: [PATCH 0634/2058] Ampersands everywhere (#206) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit • Ampersands for many menu items • New macro: PhCreateEMenuSeparator() • Separators creation standardization --- ProcessHacker/ProcessHacker.rc | 162 ++++++++++++++++---------------- ProcessHacker/appsup.c | 2 +- ProcessHacker/hndlmenu.c | 10 +- ProcessHacker/mainwnd.c | 24 ++--- ProcessHacker/memrslt.c | 2 +- ProcessHacker/mwpgproc.c | 16 ++-- ProcessHacker/plugman.c | 4 +- ProcessHacker/prpgmem.c | 6 +- ProcessHacker/prpgmod.c | 6 +- ProcessHacker/prpgwmi.c | 8 +- phlib/include/emenu.h | 5 + plugins/ExtendedServices/main.c | 16 ++-- plugins/ExtendedTools/iconext.c | 6 +- plugins/ExtendedTools/main.c | 8 +- plugins/HardwareDevices/main.c | 2 +- plugins/NetworkTools/main.c | 20 ++-- plugins/NetworkTools/tracert.c | 2 +- plugins/OnlineChecks/main.c | 26 ++--- plugins/ToolStatus/main.c | 12 +-- plugins/Updater/main.c | 2 +- plugins/UserNotes/main.c | 12 +-- plugins/WindowExplorer/main.c | 6 +- tools/peview/pdbprp.c | 2 +- 23 files changed, 182 insertions(+), 177 deletions(-) diff --git a/ProcessHacker/ProcessHacker.rc b/ProcessHacker/ProcessHacker.rc index 793a20ab1c10..a4ed4608a3c8 100644 --- a/ProcessHacker/ProcessHacker.rc +++ b/ProcessHacker/ProcessHacker.rc @@ -81,7 +81,7 @@ BEGIN POPUP "&Hacker" BEGIN MENUITEM "&Run...\aCtrl+R", ID_HACKER_RUN - MENUITEM "Run as administrator...", ID_HACKER_RUNASADMINISTRATOR + MENUITEM "Run as ad&ministrator...", ID_HACKER_RUNASADMINISTRATOR MENUITEM "Run as &limited user...", ID_HACKER_RUNASLIMITEDUSER MENUITEM "Run &as...\aCtrl+Shift+R", ID_HACKER_RUNAS MENUITEM "Show &details for all processes", ID_HACKER_SHOWDETAILSFORALLPROCESSES @@ -123,35 +123,35 @@ BEGIN MENUITEM "&Always on top", ID_VIEW_ALWAYSONTOP POPUP "&Opacity" BEGIN - MENUITEM "10%", ID_OPACITY_10 - MENUITEM "20%", ID_OPACITY_20 - MENUITEM "30%", ID_OPACITY_30 - MENUITEM "40%", ID_OPACITY_40 - MENUITEM "50%", ID_OPACITY_50 - MENUITEM "60%", ID_OPACITY_60 - MENUITEM "70%", ID_OPACITY_70 - MENUITEM "80%", ID_OPACITY_80 - MENUITEM "90%", ID_OPACITY_90 - MENUITEM "Opaque", ID_OPACITY_OPAQUE + MENUITEM "&10%", ID_OPACITY_10 + MENUITEM "&20%", ID_OPACITY_20 + MENUITEM "&30%", ID_OPACITY_30 + MENUITEM "&40%", ID_OPACITY_40 + MENUITEM "&50%", ID_OPACITY_50 + MENUITEM "&60%", ID_OPACITY_60 + MENUITEM "&70%", ID_OPACITY_70 + MENUITEM "&80%", ID_OPACITY_80 + MENUITEM "&90%", ID_OPACITY_90 + MENUITEM "&Opaque", ID_OPACITY_OPAQUE END MENUITEM SEPARATOR MENUITEM "&Refresh\aF5", ID_VIEW_REFRESH POPUP "Refresh i&nterval" BEGIN - MENUITEM "Fast (0.5s)", ID_UPDATEINTERVAL_FAST - MENUITEM "Normal (1s)", ID_UPDATEINTERVAL_NORMAL - MENUITEM "Below normal (2s)", ID_UPDATEINTERVAL_BELOWNORMAL - MENUITEM "Slow (5s)", ID_UPDATEINTERVAL_SLOW - MENUITEM "Very slow (10s)", ID_UPDATEINTERVAL_VERYSLOW + MENUITEM "&Fast (0.5s)", ID_UPDATEINTERVAL_FAST + MENUITEM "&Normal (1s)", ID_UPDATEINTERVAL_NORMAL + MENUITEM "&Below normal (2s)", ID_UPDATEINTERVAL_BELOWNORMAL + MENUITEM "&Slow (5s)", ID_UPDATEINTERVAL_SLOW + MENUITEM "&Very slow (10s)", ID_UPDATEINTERVAL_VERYSLOW END MENUITEM "Refresh a&utomatically\aF6", ID_VIEW_UPDATEAUTOMATICALLY END POPUP "&Tools" BEGIN - MENUITEM "Create service...", ID_TOOLS_CREATESERVICE - MENUITEM "Hidden processes", ID_TOOLS_HIDDENPROCESSES - MENUITEM "Inspect executable file...", ID_TOOLS_INSPECTEXECUTABLEFILE - MENUITEM "Pagefiles", ID_TOOLS_PAGEFILES + MENUITEM "&Create service...", ID_TOOLS_CREATESERVICE + MENUITEM "&Hidden processes", ID_TOOLS_HIDDENPROCESSES + MENUITEM "Inspect e&xecutable file...", ID_TOOLS_INSPECTEXECUTABLEFILE + MENUITEM "&Pagefiles", ID_TOOLS_PAGEFILES MENUITEM "Start &Task Manager", ID_TOOLS_STARTTASKMANAGER END POPUP "&Users" @@ -181,32 +181,32 @@ BEGIN MENUITEM "&Token", ID_THREAD_TOKEN POPUP "Analy&ze" BEGIN - MENUITEM "Wait", ID_ANALYZE_WAIT + MENUITEM "&Wait", ID_ANALYZE_WAIT END POPUP "&Priority" BEGIN - MENUITEM "Time critical", ID_PRIORITY_TIMECRITICAL - MENUITEM "Highest", ID_PRIORITY_HIGHEST - MENUITEM "Above normal", ID_PRIORITY_ABOVENORMAL - MENUITEM "Normal", ID_PRIORITY_NORMAL - MENUITEM "Below normal", ID_PRIORITY_BELOWNORMAL - MENUITEM "Lowest", ID_PRIORITY_LOWEST - MENUITEM "Idle", ID_PRIORITY_IDLE + MENUITEM "Time &critical", ID_PRIORITY_TIMECRITICAL + MENUITEM "&Highest", ID_PRIORITY_HIGHEST + MENUITEM "&Above normal", ID_PRIORITY_ABOVENORMAL + MENUITEM "&Normal", ID_PRIORITY_NORMAL + MENUITEM "&Below normal", ID_PRIORITY_BELOWNORMAL + MENUITEM "&Lowest", ID_PRIORITY_LOWEST + MENUITEM "&Idle", ID_PRIORITY_IDLE END - POPUP "I/O priority" + POPUP "&I/O priority" BEGIN - MENUITEM "High", ID_IOPRIORITY_HIGH - MENUITEM "Normal", ID_IOPRIORITY_NORMAL - MENUITEM "Low", ID_IOPRIORITY_LOW - MENUITEM "Very low", ID_IOPRIORITY_VERYLOW + MENUITEM "&High", ID_IOPRIORITY_HIGH + MENUITEM "&Normal", ID_IOPRIORITY_NORMAL + MENUITEM "&Low", ID_IOPRIORITY_LOW + MENUITEM "&Very low", ID_IOPRIORITY_VERYLOW END - POPUP "Page priority" + POPUP "Pa&ge priority" BEGIN - MENUITEM "Normal", ID_PAGEPRIORITY_NORMAL - MENUITEM "Below normal", ID_PAGEPRIORITY_BELOWNORMAL - MENUITEM "Medium", ID_PAGEPRIORITY_MEDIUM - MENUITEM "Low", ID_PAGEPRIORITY_LOW - MENUITEM "Very low", ID_PAGEPRIORITY_VERYLOW + MENUITEM "&Normal", ID_PAGEPRIORITY_NORMAL + MENUITEM "&Below normal", ID_PAGEPRIORITY_BELOWNORMAL + MENUITEM "&Medium", ID_PAGEPRIORITY_MEDIUM + MENUITEM "&Low", ID_PAGEPRIORITY_LOW + MENUITEM "&Very low", ID_PAGEPRIORITY_VERYLOW END MENUITEM SEPARATOR MENUITEM "&Copy\aCtrl+C", ID_THREAD_COPY @@ -267,39 +267,39 @@ BEGIN MENUITEM "Res&ume", ID_PROCESS_RESUME MENUITEM "Res&tart", ID_PROCESS_RESTART MENUITEM SEPARATOR - MENUITEM "Create dump file...", ID_PROCESS_CREATEDUMPFILE - MENUITEM "Debug", ID_PROCESS_DEBUG - MENUITEM "Virtualization", ID_PROCESS_VIRTUALIZATION + MENUITEM "Create dump fi&le...", ID_PROCESS_CREATEDUMPFILE + MENUITEM "De&bug", ID_PROCESS_DEBUG + MENUITEM "Virtuali&zation", ID_PROCESS_VIRTUALIZATION MENUITEM SEPARATOR MENUITEM "&Affinity", ID_PROCESS_AFFINITY POPUP "&Priority" BEGIN - MENUITEM "Real time", ID_PRIORITY_REALTIME - MENUITEM "High", ID_PRIORITY_HIGH - MENUITEM "Above normal", ID_PRIORITY_ABOVENORMAL - MENUITEM "Normal", ID_PRIORITY_NORMAL - MENUITEM "Below normal", ID_PRIORITY_BELOWNORMAL - MENUITEM "Idle", ID_PRIORITY_IDLE + MENUITEM "&Real time", ID_PRIORITY_REALTIME + MENUITEM "&High", ID_PRIORITY_HIGH + MENUITEM "&Above normal", ID_PRIORITY_ABOVENORMAL + MENUITEM "&Normal", ID_PRIORITY_NORMAL + MENUITEM "&Below normal", ID_PRIORITY_BELOWNORMAL + MENUITEM "&Idle", ID_PRIORITY_IDLE END POPUP "&I/O priority" BEGIN - MENUITEM "High", ID_IOPRIORITY_HIGH - MENUITEM "Normal", ID_IOPRIORITY_NORMAL - MENUITEM "Low", ID_IOPRIORITY_LOW - MENUITEM "Very low", ID_IOPRIORITY_VERYLOW + MENUITEM "&High", ID_IOPRIORITY_HIGH + MENUITEM "&Normal", ID_IOPRIORITY_NORMAL + MENUITEM "&Low", ID_IOPRIORITY_LOW + MENUITEM "&Very low", ID_IOPRIORITY_VERYLOW END POPUP "&Miscellaneous" BEGIN - MENUITEM "Detach from debugger", ID_MISCELLANEOUS_DETACHFROMDEBUGGER - MENUITEM "GDI handles", ID_MISCELLANEOUS_GDIHANDLES - MENUITEM "Inject DLL...", ID_MISCELLANEOUS_INJECTDLL - POPUP "Page priority" + MENUITEM "&Detach from debugger", ID_MISCELLANEOUS_DETACHFROMDEBUGGER + MENUITEM "GDI &handles", ID_MISCELLANEOUS_GDIHANDLES + MENUITEM "&Inject DLL...", ID_MISCELLANEOUS_INJECTDLL + POPUP "Pa&ge priority" BEGIN - MENUITEM "Normal", ID_PAGEPRIORITY_NORMAL - MENUITEM "Below normal", ID_PAGEPRIORITY_BELOWNORMAL - MENUITEM "Medium", ID_PAGEPRIORITY_MEDIUM - MENUITEM "Low", ID_PAGEPRIORITY_LOW - MENUITEM "Very low", ID_PAGEPRIORITY_VERYLOW + MENUITEM "&Normal", ID_PAGEPRIORITY_NORMAL + MENUITEM "&Below normal", ID_PAGEPRIORITY_BELOWNORMAL + MENUITEM "&Medium", ID_PAGEPRIORITY_MEDIUM + MENUITEM "&Low", ID_PAGEPRIORITY_LOW + MENUITEM "&Very low", ID_PAGEPRIORITY_VERYLOW END MENUITEM "Reduce working &set", ID_MISCELLANEOUS_REDUCEWORKINGSET MENUITEM "&Run as...", ID_MISCELLANEOUS_RUNAS @@ -307,15 +307,15 @@ BEGIN END POPUP "&Window" BEGIN - MENUITEM "Bring to front", ID_WINDOW_BRINGTOFRONT - MENUITEM "Restore", ID_WINDOW_RESTORE - MENUITEM "Minimize", ID_WINDOW_MINIMIZE - MENUITEM "Maximize", ID_WINDOW_MAXIMIZE + MENUITEM "Bring to &front", ID_WINDOW_BRINGTOFRONT + MENUITEM "&Restore", ID_WINDOW_RESTORE + MENUITEM "M&inimize", ID_WINDOW_MINIMIZE + MENUITEM "M&aximize", ID_WINDOW_MAXIMIZE MENUITEM SEPARATOR - MENUITEM "Close", ID_WINDOW_CLOSE + MENUITEM "&Close", ID_WINDOW_CLOSE END MENUITEM SEPARATOR - MENUITEM "Search online\aCtrl+M", ID_PROCESS_SEARCHONLINE + MENUITEM "Search &online\aCtrl+M", ID_PROCESS_SEARCHONLINE MENUITEM "Open &file location\aCtrl+Enter", ID_PROCESS_OPENFILELOCATION MENUITEM "P&roperties\aEnter", ID_PROCESS_PROPERTIES MENUITEM "&Copy\aCtrl+C", ID_PROCESS_COPY @@ -398,15 +398,15 @@ BEGIN MENUITEM "System &information", ID_ICON_SYSTEMINFORMATION POPUP "N&otifications" BEGIN - MENUITEM "Enable all", ID_NOTIFICATIONS_ENABLEALL - MENUITEM "Disable all", ID_NOTIFICATIONS_DISABLEALL + MENUITEM "&Enable all", ID_NOTIFICATIONS_ENABLEALL + MENUITEM "&Disable all", ID_NOTIFICATIONS_DISABLEALL MENUITEM SEPARATOR - MENUITEM "New processes", ID_NOTIFICATIONS_NEWPROCESSES - MENUITEM "Terminated processes", ID_NOTIFICATIONS_TERMINATEDPROCESSES - MENUITEM "New services", ID_NOTIFICATIONS_NEWSERVICES - MENUITEM "Started services", ID_NOTIFICATIONS_STARTEDSERVICES - MENUITEM "Stopped services", ID_NOTIFICATIONS_STOPPEDSERVICES - MENUITEM "Deleted services", ID_NOTIFICATIONS_DELETEDSERVICES + MENUITEM "New &processes", ID_NOTIFICATIONS_NEWPROCESSES + MENUITEM "T&erminated processes", ID_NOTIFICATIONS_TERMINATEDPROCESSES + MENUITEM "New &services", ID_NOTIFICATIONS_NEWSERVICES + MENUITEM "St&arted services", ID_NOTIFICATIONS_STARTEDSERVICES + MENUITEM "St&opped services", ID_NOTIFICATIONS_STOPPEDSERVICES + MENUITEM "&Deleted services", ID_NOTIFICATIONS_DELETEDSERVICES END POPUP "&Processes" BEGIN @@ -422,7 +422,7 @@ BEGIN MENUITEM "&Hibernate", ID_COMPUTER_HIBERNATE MENUITEM SEPARATOR MENUITEM "R&estart", ID_COMPUTER_RESTART - MENUITEM "Restart to boot options", ID_COMPUTER_RESTARTBOOTOPTIONS + MENUITEM "Restart to boot &options", ID_COMPUTER_RESTARTBOOTOPTIONS MENUITEM "Shu&t down", ID_COMPUTER_SHUTDOWN MENUITEM "H&ybrid shut down", ID_COMPUTER_SHUTDOWNHYBRID END @@ -459,11 +459,11 @@ IDR_EMPTYMEMLISTS MENU BEGIN POPUP "Empty" BEGIN - MENUITEM "Combine memory lists", ID_EMPTY_COMBINEMEMORYLISTS - MENUITEM "Empty working sets", ID_EMPTY_EMPTYWORKINGSETS - MENUITEM "Empty modified page list", ID_EMPTY_EMPTYMODIFIEDPAGELIST - MENUITEM "Empty standby list", ID_EMPTY_EMPTYSTANDBYLIST - MENUITEM "Empty priority 0 standby list", ID_EMPTY_EMPTYPRIORITY0STANDBYLIST + MENUITEM "&Combine memory lists", ID_EMPTY_COMBINEMEMORYLISTS + MENUITEM "Empty &working sets", ID_EMPTY_EMPTYWORKINGSETS + MENUITEM "Empty &modified page list", ID_EMPTY_EMPTYMODIFIEDPAGELIST + MENUITEM "Empty &standby list", ID_EMPTY_EMPTYSTANDBYLIST + MENUITEM "Empty &priority 0 standby list", ID_EMPTY_EMPTYPRIORITY0STANDBYLIST END END diff --git a/ProcessHacker/appsup.c b/ProcessHacker/appsup.c index dcf264aca322..caab2c547dcd 100644 --- a/ProcessHacker/appsup.c +++ b/ProcessHacker/appsup.c @@ -1617,7 +1617,7 @@ VOID PhInitializeTreeNewColumnMenuEx( if (resetSortMenuItem) PhInsertEMenuItem(Data->Menu, resetSortMenuItem, -1); - PhInsertEMenuItem(Data->Menu, PhCreateEMenuItem(PH_EMENU_SEPARATOR, 0, L"", NULL, NULL), -1); + PhInsertEMenuItem(Data->Menu, PhCreateEMenuSeparator(), -1); PhInsertEMenuItem(Data->Menu, chooseColumnsMenuItem, -1); if (TreeNew_GetFixedColumn(Data->TreeNewHandle)) diff --git a/ProcessHacker/hndlmenu.c b/ProcessHacker/hndlmenu.c index 8b86873713e0..bb24b7938a41 100644 --- a/ProcessHacker/hndlmenu.c +++ b/ProcessHacker/hndlmenu.c @@ -48,25 +48,25 @@ VOID PhInsertHandleObjectPropertiesEMenuItems( PhEqualString2(Info->TypeName, L"Mapped file", TRUE) || PhEqualString2(Info->TypeName, L"Mapped image", TRUE)) { if (PhEqualString2(Info->TypeName, L"File", TRUE)) - PhInsertEMenuItem(parentItem, PhCreateEMenuItem(0, ID_HANDLE_OBJECTPROPERTIES2, L"File properties", NULL, NULL), indexInParent); + PhInsertEMenuItem(parentItem, PhCreateEMenuItem(0, ID_HANDLE_OBJECTPROPERTIES2, L"File propert&ies", NULL, NULL), indexInParent); PhInsertEMenuItem(parentItem, PhCreateEMenuItem(0, ID_HANDLE_OBJECTPROPERTIES1, PhaAppendCtrlEnter(L"Open &file location", EnableShortcut), NULL, NULL), indexInParent); } else if (PhEqualString2(Info->TypeName, L"Key", TRUE)) { - PhInsertEMenuItem(parentItem, PhCreateEMenuItem(0, ID_HANDLE_OBJECTPROPERTIES1, PhaAppendCtrlEnter(L"Open key", EnableShortcut), NULL, NULL), indexInParent); + PhInsertEMenuItem(parentItem, PhCreateEMenuItem(0, ID_HANDLE_OBJECTPROPERTIES1, PhaAppendCtrlEnter(L"Open &key", EnableShortcut), NULL, NULL), indexInParent); } else if (PhEqualString2(Info->TypeName, L"Process", TRUE)) { - PhInsertEMenuItem(parentItem, PhCreateEMenuItem(0, ID_HANDLE_OBJECTPROPERTIES1, PhaAppendCtrlEnter(L"Process properties", EnableShortcut), NULL, NULL), indexInParent); + PhInsertEMenuItem(parentItem, PhCreateEMenuItem(0, ID_HANDLE_OBJECTPROPERTIES1, PhaAppendCtrlEnter(L"Process propert&ies", EnableShortcut), NULL, NULL), indexInParent); } else if (PhEqualString2(Info->TypeName, L"Section", TRUE)) { - PhInsertEMenuItem(parentItem, PhCreateEMenuItem(0, ID_HANDLE_OBJECTPROPERTIES1, PhaAppendCtrlEnter(L"Read/Write memory", EnableShortcut), NULL, NULL), indexInParent); + PhInsertEMenuItem(parentItem, PhCreateEMenuItem(0, ID_HANDLE_OBJECTPROPERTIES1, PhaAppendCtrlEnter(L"Read/Write &memory", EnableShortcut), NULL, NULL), indexInParent); } else if (PhEqualString2(Info->TypeName, L"Thread", TRUE)) { - PhInsertEMenuItem(parentItem, PhCreateEMenuItem(0, ID_HANDLE_OBJECTPROPERTIES1, PhaAppendCtrlEnter(L"Go to thread", EnableShortcut), NULL, NULL), indexInParent); + PhInsertEMenuItem(parentItem, PhCreateEMenuItem(0, ID_HANDLE_OBJECTPROPERTIES1, PhaAppendCtrlEnter(L"Go to t&hread", EnableShortcut), NULL, NULL), indexInParent); } } diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index fc0b3fef3eef..5df7a059dca7 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -2866,23 +2866,23 @@ VOID PhAddMiniProcessMenuItems( // Priority - priorityMenu = PhCreateEMenuItem(0, 0, L"Priority", NULL, ProcessId); + priorityMenu = PhCreateEMenuItem(0, 0, L"&Priority", NULL, ProcessId); - PhInsertEMenuItem(priorityMenu, PhCreateEMenuItem(0, ID_PRIORITY_REALTIME, L"Real time", NULL, ProcessId), -1); - PhInsertEMenuItem(priorityMenu, PhCreateEMenuItem(0, ID_PRIORITY_HIGH, L"High", NULL, ProcessId), -1); - PhInsertEMenuItem(priorityMenu, PhCreateEMenuItem(0, ID_PRIORITY_ABOVENORMAL, L"Above normal", NULL, ProcessId), -1); - PhInsertEMenuItem(priorityMenu, PhCreateEMenuItem(0, ID_PRIORITY_NORMAL, L"Normal", NULL, ProcessId), -1); - PhInsertEMenuItem(priorityMenu, PhCreateEMenuItem(0, ID_PRIORITY_BELOWNORMAL, L"Below normal", NULL, ProcessId), -1); - PhInsertEMenuItem(priorityMenu, PhCreateEMenuItem(0, ID_PRIORITY_IDLE, L"Idle", NULL, ProcessId), -1); + PhInsertEMenuItem(priorityMenu, PhCreateEMenuItem(0, ID_PRIORITY_REALTIME, L"&Real time", NULL, ProcessId), -1); + PhInsertEMenuItem(priorityMenu, PhCreateEMenuItem(0, ID_PRIORITY_HIGH, L"&High", NULL, ProcessId), -1); + PhInsertEMenuItem(priorityMenu, PhCreateEMenuItem(0, ID_PRIORITY_ABOVENORMAL, L"&Above normal", NULL, ProcessId), -1); + PhInsertEMenuItem(priorityMenu, PhCreateEMenuItem(0, ID_PRIORITY_NORMAL, L"&Normal", NULL, ProcessId), -1); + PhInsertEMenuItem(priorityMenu, PhCreateEMenuItem(0, ID_PRIORITY_BELOWNORMAL, L"&Below normal", NULL, ProcessId), -1); + PhInsertEMenuItem(priorityMenu, PhCreateEMenuItem(0, ID_PRIORITY_IDLE, L"&Idle", NULL, ProcessId), -1); // I/O priority - ioPriorityMenu = PhCreateEMenuItem(0, 0, L"I/O priority", NULL, ProcessId); + ioPriorityMenu = PhCreateEMenuItem(0, 0, L"&I/O priority", NULL, ProcessId); - PhInsertEMenuItem(ioPriorityMenu, PhCreateEMenuItem(0, ID_IOPRIORITY_HIGH, L"High", NULL, ProcessId), -1); - PhInsertEMenuItem(ioPriorityMenu, PhCreateEMenuItem(0, ID_IOPRIORITY_NORMAL, L"Normal", NULL, ProcessId), -1); - PhInsertEMenuItem(ioPriorityMenu, PhCreateEMenuItem(0, ID_IOPRIORITY_LOW, L"Low", NULL, ProcessId), -1); - PhInsertEMenuItem(ioPriorityMenu, PhCreateEMenuItem(0, ID_IOPRIORITY_VERYLOW, L"Very low", NULL, ProcessId), -1); + PhInsertEMenuItem(ioPriorityMenu, PhCreateEMenuItem(0, ID_IOPRIORITY_HIGH, L"&High", NULL, ProcessId), -1); + PhInsertEMenuItem(ioPriorityMenu, PhCreateEMenuItem(0, ID_IOPRIORITY_NORMAL, L"&Normal", NULL, ProcessId), -1); + PhInsertEMenuItem(ioPriorityMenu, PhCreateEMenuItem(0, ID_IOPRIORITY_LOW, L"&Low", NULL, ProcessId), -1); + PhInsertEMenuItem(ioPriorityMenu, PhCreateEMenuItem(0, ID_IOPRIORITY_VERYLOW, L"&Very low", NULL, ProcessId), -1); // Menu diff --git a/ProcessHacker/memrslt.c b/ProcessHacker/memrslt.c index efe9d74ff961..f4b3140a86d9 100644 --- a/ProcessHacker/memrslt.c +++ b/ProcessHacker/memrslt.c @@ -633,7 +633,7 @@ INT_PTR CALLBACK PhpMemoryResultsDlgProc( menu = PhCreateEMenu(); PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_MEMORY_READWRITEMEMORY, L"Read/Write memory", NULL, NULL), -1); - PhInsertEMenuItem(menu, PhCreateEMenuItem(PH_EMENU_SEPARATOR, 0, L"", NULL, NULL), -1); + PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), -1); PhInsertEMenuItem(menu, PhCreateEMenuItem(0, IDC_COPY, L"Copy", NULL, NULL), -1); GetCursorPos(&point); diff --git a/ProcessHacker/mwpgproc.c b/ProcessHacker/mwpgproc.c index acaa84fa7bc8..0a5edbf21902 100644 --- a/ProcessHacker/mwpgproc.c +++ b/ProcessHacker/mwpgproc.c @@ -113,10 +113,10 @@ BOOLEAN PhMwpProcessesPageCallback( PPH_EMENU_ITEM menuItem; PPH_EMENU_ITEM columnSetMenuItem; - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_VIEW_HIDEPROCESSESFROMOTHERUSERS, L"Hide processes from other users", NULL, NULL), startIndex); - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_VIEW_HIDESIGNEDPROCESSES, L"Hide signed processes", NULL, NULL), startIndex + 1); - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_VIEW_SCROLLTONEWPROCESSES, L"Scroll to new processes", NULL, NULL), startIndex + 2); - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_VIEW_SHOWCPUBELOW001, L"Show CPU below 0.01", NULL, NULL), startIndex + 3); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_VIEW_HIDEPROCESSESFROMOTHERUSERS, L"&Hide processes from other users", NULL, NULL), startIndex); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_VIEW_HIDESIGNEDPROCESSES, L"Hide si&gned processes", NULL, NULL), startIndex + 1); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_VIEW_SCROLLTONEWPROCESSES, L"Scrol&l to new processes", NULL, NULL), startIndex + 2); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_VIEW_SHOWCPUBELOW001, L"Show CPU &below 0.01", NULL, NULL), startIndex + 3); if (CurrentUserFilterEntry && (menuItem = PhFindEMenuItem(menu, 0, NULL, ID_VIEW_HIDEPROCESSESFROMOTHERUSERS))) menuItem->Flags |= PH_EMENU_CHECKED; @@ -138,10 +138,10 @@ BOOLEAN PhMwpProcessesPageCallback( } } - PhInsertEMenuItem(menu, PhCreateEMenuItem(PH_EMENU_SEPARATOR, 0, NULL, NULL, NULL), startIndex + 4); - PhInsertEMenuItem(menu, menuItem = PhCreateEMenuItem(0, ID_VIEW_ORGANIZECOLUMNSETS, L"Organize column sets...", NULL, NULL), startIndex + 5); - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_VIEW_SAVECOLUMNSET, L"Save column set...", NULL, NULL), startIndex + 6); - PhInsertEMenuItem(menu, columnSetMenuItem = PhCreateEMenuItem(0, 0, L"&Load column set", NULL, NULL), startIndex + 7); + PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), startIndex + 4); + PhInsertEMenuItem(menu, menuItem = PhCreateEMenuItem(0, ID_VIEW_ORGANIZECOLUMNSETS, L"Organi&ze column sets...", NULL, NULL), startIndex + 5); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_VIEW_SAVECOLUMNSET, L"Sa&ve column set...", NULL, NULL), startIndex + 6); + PhInsertEMenuItem(menu, columnSetMenuItem = PhCreateEMenuItem(0, 0, L"Loa&d column set", NULL, NULL), startIndex + 7); // Add column set sub menu entries. { diff --git a/ProcessHacker/plugman.c b/ProcessHacker/plugman.c index b05852f3bb21..70d9d552b4d6 100644 --- a/ProcessHacker/plugman.c +++ b/ProcessHacker/plugman.c @@ -732,9 +732,9 @@ INT_PTR CALLBACK PhpPluginsDlgProc( menu = PhCreateEMenu(); //PhInsertEMenuItem(menu, uninstallItem = PhCreateEMenuItem(0, PH_PLUGIN_TREE_ITEM_MENU_UNINSTALL, L"Uninstall", NULL, NULL), -1); - //PhInsertEMenuItem(menu, PhCreateEMenuItem(PH_EMENU_SEPARATOR, 0, NULL, NULL, NULL), -1); + //PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), -1); PhInsertEMenuItem(menu, PhCreateEMenuItem(0, PH_PLUGIN_TREE_ITEM_MENU_DISABLE, L"Disable", NULL, NULL), -1); - PhInsertEMenuItem(menu, PhCreateEMenuItem(PH_EMENU_SEPARATOR, 0, NULL, NULL, NULL), -1); + PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), -1); PhInsertEMenuItem(menu, PhCreateEMenuItem(0, PH_PLUGIN_TREE_ITEM_MENU_PROPERTIES, L"Properties", NULL, NULL), -1); //if (!PhGetOwnTokenAttributes().Elevated) diff --git a/ProcessHacker/prpgmem.c b/ProcessHacker/prpgmem.c index b835125aca20..c6ffe297f24d 100644 --- a/ProcessHacker/prpgmem.c +++ b/ProcessHacker/prpgmem.c @@ -639,14 +639,14 @@ INT_PTR CALLBACK PhpProcessMemoryDlgProc( PhInsertEMenuItem(menu, freeItem = PhCreateEMenuItem(0, PH_MEMORY_FILTER_MENU_HIDE_FREE, L"Hide free pages", NULL, NULL), -1); PhInsertEMenuItem(menu, reservedItem = PhCreateEMenuItem(0, PH_MEMORY_FILTER_MENU_HIDE_RESERVED, L"Hide reserved pages", NULL, NULL), -1); - PhInsertEMenuItem(menu, PhCreateEMenuItem(PH_EMENU_SEPARATOR, 0, NULL, NULL, NULL), -1); + PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), -1); PhInsertEMenuItem(menu, privateItem = PhCreateEMenuItem(0, PH_MEMORY_FILTER_MENU_HIGHLIGHT_PRIVATE, L"Highlight private pages", NULL, NULL), -1); PhInsertEMenuItem(menu, systemItem = PhCreateEMenuItem(0, PH_MEMORY_FILTER_MENU_HIGHLIGHT_SYSTEM, L"Highlight system pages", NULL, NULL), -1); PhInsertEMenuItem(menu, cfgItem = PhCreateEMenuItem(0, PH_MEMORY_FILTER_MENU_HIGHLIGHT_CFG, L"Highlight CFG pages", NULL, NULL), -1); PhInsertEMenuItem(menu, typeItem = PhCreateEMenuItem(0, PH_MEMORY_FILTER_MENU_HIGHLIGHT_EXECUTE, L"Highlight executable pages", NULL, NULL), -1); - PhInsertEMenuItem(menu, PhCreateEMenuItem(PH_EMENU_SEPARATOR, 0, NULL, NULL, NULL), -1); + PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), -1); PhInsertEMenuItem(menu, PhCreateEMenuItem(0, PH_MEMORY_FILTER_MENU_READ_ADDRESS, L"Read/Write &address...", NULL, NULL), -1); - PhInsertEMenuItem(menu, PhCreateEMenuItem(PH_EMENU_SEPARATOR, 0, NULL, NULL, NULL), -1); + PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), -1); PhInsertEMenuItem(menu, PhCreateEMenuItem(0, PH_MEMORY_FILTER_MENU_STRINGS, L"Strings...", NULL, NULL), -1); if (memoryContext->ListContext.HideFreeRegions) diff --git a/ProcessHacker/prpgmod.c b/ProcessHacker/prpgmod.c index 9ab53e012387..496cfe371017 100644 --- a/ProcessHacker/prpgmod.c +++ b/ProcessHacker/prpgmod.c @@ -684,14 +684,14 @@ INT_PTR CALLBACK PhpProcessModulesDlgProc( PhInsertEMenuItem(menu, mappedItem = PhCreateEMenuItem(0, PH_MODULE_FLAGS_MAPPED_OPTION, L"Hide mapped", NULL, NULL), -1); PhInsertEMenuItem(menu, staticItem = PhCreateEMenuItem(0, PH_MODULE_FLAGS_STATIC_OPTION, L"Hide static", NULL, NULL), -1); PhInsertEMenuItem(menu, verifiedItem = PhCreateEMenuItem(0, PH_MODULE_FLAGS_SIGNED_OPTION, L"Hide verified", NULL, NULL), -1); - PhInsertEMenuItem(menu, PhCreateEMenuItem(PH_EMENU_SEPARATOR, 0, NULL, NULL, NULL), -1); + PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), -1); PhInsertEMenuItem(menu, dotnetItem = PhCreateEMenuItem(0, PH_MODULE_FLAGS_HIGHLIGHT_DOTNET_OPTION, L"Highlight .NET modules", NULL, NULL), -1); PhInsertEMenuItem(menu, immersiveItem = PhCreateEMenuItem(0, PH_MODULE_FLAGS_HIGHLIGHT_IMMERSIVE_OPTION, L"Highlight immersive modules", NULL, NULL), -1); PhInsertEMenuItem(menu, relocatedItem = PhCreateEMenuItem(0, PH_MODULE_FLAGS_HIGHLIGHT_RELOCATED_OPTION, L"Highlight relocated modules", NULL, NULL), -1); PhInsertEMenuItem(menu, untrustedItem = PhCreateEMenuItem(0, PH_MODULE_FLAGS_HIGHLIGHT_UNSIGNED_OPTION, L"Highlight untrusted modules", NULL, NULL), -1); - PhInsertEMenuItem(menu, PhCreateEMenuItem(PH_EMENU_SEPARATOR, 0, NULL, NULL, NULL), -1); + PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), -1); PhInsertEMenuItem(menu, PhCreateEMenuItem(0, PH_MODULE_FLAGS_LOAD_MODULE_OPTION, L"Load module", NULL, NULL), -1); - PhInsertEMenuItem(menu, PhCreateEMenuItem(PH_EMENU_SEPARATOR, 0, NULL, NULL, NULL), -1); + PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), -1); PhInsertEMenuItem(menu, stringsItem = PhCreateEMenuItem(0, PH_MODULE_FLAGS_MODULE_STRINGS_OPTION, L"Strings...", NULL, NULL), -1); if (modulesContext->ListContext.HideDynamicModules) diff --git a/ProcessHacker/prpgwmi.c b/ProcessHacker/prpgwmi.c index d24f7c4d63ca..22d21aeaaac0 100644 --- a/ProcessHacker/prpgwmi.c +++ b/ProcessHacker/prpgwmi.c @@ -677,10 +677,10 @@ INT_PTR CALLBACK PhpProcessWmiProvidersDlgProc( menu = PhCreateEMenu(); if (PhGetIntegerSetting(L"WmiProviderEnableHiddenMenu")) { - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, 1, L"Suspend", NULL, NULL), -1); - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, 2, L"Resume", NULL, NULL), -1); - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, 3, L"Unload", NULL, NULL), -1); - PhInsertEMenuItem(menu, PhCreateEMenuItem(PH_EMENU_SEPARATOR, 0, NULL, NULL, NULL), -1); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, 1, L"&Suspend", NULL, NULL), -1); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, 2, L"Res&ume", NULL, NULL), -1); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, 3, L"Un&load", NULL, NULL), -1); + PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), -1); } PhInsertEMenuItem(menu, PhCreateEMenuItem(0, 4, L"Open &file location", NULL, NULL), -1); PhInsertEMenuItem(menu, PhCreateEMenuItem(0, 5, L"&Copy", NULL, NULL), -1); diff --git a/phlib/include/emenu.h b/phlib/include/emenu.h index 95c39f355d64..f6ece558f6fa 100644 --- a/phlib/include/emenu.h +++ b/phlib/include/emenu.h @@ -58,6 +58,11 @@ VOID PhDestroyEMenuItem( _In_ PPH_EMENU_ITEM Item ); +/** +* Creates a menu separator. +*/ +#define PhCreateEMenuSeparator() PhCreateEMenuItem(PH_EMENU_SEPARATOR, 0, L"", NULL, NULL) + #define PH_EMENU_FIND_DESCEND 0x1 #define PH_EMENU_FIND_STARTSWITH 0x2 #define PH_EMENU_FIND_LITERAL 0x4 diff --git a/plugins/ExtendedServices/main.c b/plugins/ExtendedServices/main.c index a84cdc669ae4..343d328d02db 100644 --- a/plugins/ExtendedServices/main.c +++ b/plugins/ExtendedServices/main.c @@ -154,7 +154,7 @@ VOID NTAPI ProcessMenuInitializingCallback( // * There are no extra submenus. if (serviceList->Count != 1) { - servicesMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, 0, L"Services", NULL); + servicesMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, 0, L"Ser&vices", NULL); } // Create and add a menu item for each service. @@ -174,7 +174,7 @@ VOID NTAPI ProcessMenuInitializingCallback( if (serviceList->Count == 1) { // "Service (Xxx)" - escapedName = PhaFormatString(L"Service (%s)", escapedName->Buffer); + escapedName = PhaFormatString(L"Ser&vice (%s)", escapedName->Buffer); } serviceMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, 0, escapedName->Buffer, NULL); @@ -185,11 +185,11 @@ VOID NTAPI ProcessMenuInitializingCallback( servicesMenuItem = serviceMenuItem; } - PhInsertEMenuItem(serviceMenuItem, PhPluginCreateEMenuItem(PluginInstance, 0, ID_SERVICE_GOTOSERVICE, L"Go to service", serviceItem), -1); - PhInsertEMenuItem(serviceMenuItem, startMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, ID_SERVICE_START, L"Start", serviceItem), -1); - PhInsertEMenuItem(serviceMenuItem, continueMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, ID_SERVICE_CONTINUE, L"Continue", serviceItem), -1); - PhInsertEMenuItem(serviceMenuItem, pauseMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, ID_SERVICE_PAUSE, L"Pause", serviceItem), -1); - PhInsertEMenuItem(serviceMenuItem, stopMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, ID_SERVICE_STOP, L"Stop", serviceItem), -1); + PhInsertEMenuItem(serviceMenuItem, PhPluginCreateEMenuItem(PluginInstance, 0, ID_SERVICE_GOTOSERVICE, L"&Go to service", serviceItem), -1); + PhInsertEMenuItem(serviceMenuItem, startMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, ID_SERVICE_START, L"Sta&rt", serviceItem), -1); + PhInsertEMenuItem(serviceMenuItem, continueMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, ID_SERVICE_CONTINUE, L"&Continue", serviceItem), -1); + PhInsertEMenuItem(serviceMenuItem, pauseMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, ID_SERVICE_PAUSE, L"&Pause", serviceItem), -1); + PhInsertEMenuItem(serviceMenuItem, stopMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, ID_SERVICE_STOP, L"St&op", serviceItem), -1); // Massive copy and paste from mainwnd.c. // == START == @@ -383,7 +383,7 @@ VOID NTAPI ServiceMenuInitializingCallback( PhInsertEMenuItem( menuInfo->Menu, - PhPluginCreateEMenuItem(PluginInstance, 0, ID_SERVICE_RESTART, L"Restart", menuInfo->u.Service.Services[0]), + PhPluginCreateEMenuItem(PluginInstance, 0, ID_SERVICE_RESTART, L"R&estart", menuInfo->u.Service.Services[0]), indexOfMenuItem + 1 ); } diff --git a/plugins/ExtendedTools/iconext.c b/plugins/ExtendedTools/iconext.c index e125bf364e64..b073696f3ef4 100644 --- a/plugins/ExtendedTools/iconext.c +++ b/plugins/ExtendedTools/iconext.c @@ -85,7 +85,7 @@ VOID EtRegisterNotifyIcons( PluginInstance, GPU_ICON_ID, NULL, - L"GPU history", + L"&GPU history", PH_NF_ICON_SHOW_MINIINFO | (EtGpuEnabled ? 0 : PH_NF_ICON_UNAVAILABLE), &data ); @@ -96,7 +96,7 @@ VOID EtRegisterNotifyIcons( PluginInstance, DISK_ICON_ID, NULL, - L"Disk history", + L"&Disk history", PH_NF_ICON_SHOW_MINIINFO | (EtEtwEnabled ? 0 : PH_NF_ICON_UNAVAILABLE), &data ); @@ -107,7 +107,7 @@ VOID EtRegisterNotifyIcons( PluginInstance, NETWORK_ICON_ID, NULL, - L"Network history", + L"&Network history", PH_NF_ICON_SHOW_MINIINFO | (EtEtwEnabled ? 0 : PH_NF_ICON_UNAVAILABLE), &data ); diff --git a/plugins/ExtendedTools/main.c b/plugins/ExtendedTools/main.c index fe84e010489f..f552223ac6de 100644 --- a/plugins/ExtendedTools/main.c +++ b/plugins/ExtendedTools/main.c @@ -181,8 +181,8 @@ VOID NTAPI ProcessMenuInitializingCallback( if (miscMenu) { - PhInsertEMenuItem(miscMenu, PhPluginCreateEMenuItem(PluginInstance, flags, ID_PROCESS_UNLOADEDMODULES, L"Unloaded modules", processItem), -1); - PhInsertEMenuItem(miscMenu, PhPluginCreateEMenuItem(PluginInstance, flags, ID_PROCESS_WSWATCH, L"WS watch", processItem), -1); + PhInsertEMenuItem(miscMenu, PhPluginCreateEMenuItem(PluginInstance, flags, ID_PROCESS_UNLOADEDMODULES, L"&Unloaded modules", processItem), -1); + PhInsertEMenuItem(miscMenu, PhPluginCreateEMenuItem(PluginInstance, flags, ID_PROCESS_WSWATCH, L"&WS watch", processItem), -1); } } @@ -207,7 +207,7 @@ VOID NTAPI ThreadMenuInitializingCallback( insertIndex = 0; PhInsertEMenuItem(menuInfo->Menu, menuItem = PhPluginCreateEMenuItem(PluginInstance, 0, ID_THREAD_CANCELIO, - L"Cancel I/O", threadItem), insertIndex); + L"Ca&ncel I/O", threadItem), insertIndex); if (!threadItem) menuItem->Flags |= PH_EMENU_DISABLED; } @@ -250,7 +250,7 @@ VOID NTAPI ModuleMenuInitializingCallback( ModuleProcessId = menuInfo->u.Module.ProcessId; PhInsertEMenuItem(menuInfo->Menu, menuItem = PhPluginCreateEMenuItem(PluginInstance, 0, ID_MODULE_SERVICES, - L"Services", moduleItem), insertIndex); + L"Ser&vices", moduleItem), insertIndex); if (!moduleItem) menuItem->Flags |= PH_EMENU_DISABLED; } diff --git a/plugins/HardwareDevices/main.c b/plugins/HardwareDevices/main.c index 19366f4c7515..379add20b60c 100644 --- a/plugins/HardwareDevices/main.c +++ b/plugins/HardwareDevices/main.c @@ -241,7 +241,7 @@ VOID ShowDeviceMenu( menu = PhCreateEMenu(); //PhInsertEMenuItem(menu, PhCreateEMenuItem(0, 0, L"Enable", NULL, NULL), -1); //PhInsertEMenuItem(menu, PhCreateEMenuItem(0, 1, L"Disable", NULL, NULL), -1); - //PhInsertEMenuItem(menu, PhCreateEMenuItem(PH_EMENU_SEPARATOR, 0, NULL, NULL, NULL), -1); + //PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), -1); PhInsertEMenuItem(menu, PhCreateEMenuItem(0, 1, L"Properties", NULL, NULL), -1); selectedItem = PhShowEMenu( diff --git a/plugins/NetworkTools/main.c b/plugins/NetworkTools/main.c index cff7a526fb14..b40be0fb3dd3 100644 --- a/plugins/NetworkTools/main.c +++ b/plugins/NetworkTools/main.c @@ -260,12 +260,12 @@ VOID NTAPI MainMenuInitializingCallback( if (menuInfo->u.MainMenu.SubMenuIndex != PH_MENU_ITEM_LOCATION_TOOLS) return; - networkToolsMenu = PhPluginCreateEMenuItem(PluginInstance, 0, 0, L"Network Tools", NULL); - PhInsertEMenuItem(networkToolsMenu, PhPluginCreateEMenuItem(PluginInstance, 0, MAINMENU_ACTION_GEOIP_UPDATE, L"GeoIP database update...", NULL), -1); - PhInsertEMenuItem(networkToolsMenu, PhPluginCreateEMenuItem(PluginInstance, PH_EMENU_SEPARATOR, 0, NULL, NULL), -1); - PhInsertEMenuItem(networkToolsMenu, PhPluginCreateEMenuItem(PluginInstance, 0, MAINMENU_ACTION_PING, L"Ping address...", NULL), -1); - PhInsertEMenuItem(networkToolsMenu, PhPluginCreateEMenuItem(PluginInstance, 0, MAINMENU_ACTION_TRACERT, L"Traceroute address...", NULL), -1); - PhInsertEMenuItem(networkToolsMenu, PhPluginCreateEMenuItem(PluginInstance, 0, MAINMENU_ACTION_WHOIS, L"Whois address...", NULL), -1); + networkToolsMenu = PhPluginCreateEMenuItem(PluginInstance, 0, 0, L"&Network Tools", NULL); + PhInsertEMenuItem(networkToolsMenu, PhPluginCreateEMenuItem(PluginInstance, 0, MAINMENU_ACTION_GEOIP_UPDATE, L"&GeoIP database update...", NULL), -1); + PhInsertEMenuItem(networkToolsMenu, PhCreateEMenuSeparator(), -1); + PhInsertEMenuItem(networkToolsMenu, PhPluginCreateEMenuItem(PluginInstance, 0, MAINMENU_ACTION_PING, L"&Ping address...", NULL), -1); + PhInsertEMenuItem(networkToolsMenu, PhPluginCreateEMenuItem(PluginInstance, 0, MAINMENU_ACTION_TRACERT, L"&Traceroute address...", NULL), -1); + PhInsertEMenuItem(networkToolsMenu, PhPluginCreateEMenuItem(PluginInstance, 0, MAINMENU_ACTION_WHOIS, L"&Whois address...", NULL), -1); PhInsertEMenuItem(menuInfo->Menu, networkToolsMenu, -1); } @@ -285,10 +285,10 @@ VOID NTAPI NetworkMenuInitializingCallback( else networkItem = NULL; - PhInsertEMenuItem(menuInfo->Menu, PhPluginCreateEMenuItem(PluginInstance, PH_EMENU_SEPARATOR, 0, NULL, NULL), 0); - PhInsertEMenuItem(menuInfo->Menu, whoisMenu = PhPluginCreateEMenuItem(PluginInstance, 0, NETWORK_ACTION_WHOIS, L"Whois", networkItem), 0); - PhInsertEMenuItem(menuInfo->Menu, traceMenu = PhPluginCreateEMenuItem(PluginInstance, 0, NETWORK_ACTION_TRACEROUTE, L"Traceroute", networkItem), 0); - PhInsertEMenuItem(menuInfo->Menu, pingMenu = PhPluginCreateEMenuItem(PluginInstance, 0, NETWORK_ACTION_PING, L"Ping", networkItem), 0); + PhInsertEMenuItem(menuInfo->Menu, PhCreateEMenuSeparator(), 0); + PhInsertEMenuItem(menuInfo->Menu, whoisMenu = PhPluginCreateEMenuItem(PluginInstance, 0, NETWORK_ACTION_WHOIS, L"&Whois", networkItem), 0); + PhInsertEMenuItem(menuInfo->Menu, traceMenu = PhPluginCreateEMenuItem(PluginInstance, 0, NETWORK_ACTION_TRACEROUTE, L"&Traceroute", networkItem), 0); + PhInsertEMenuItem(menuInfo->Menu, pingMenu = PhPluginCreateEMenuItem(PluginInstance, 0, NETWORK_ACTION_PING, L"&Ping", networkItem), 0); if (networkItem) { diff --git a/plugins/NetworkTools/tracert.c b/plugins/NetworkTools/tracert.c index 87a986b61e71..a0683dc89945 100644 --- a/plugins/NetworkTools/tracert.c +++ b/plugins/NetworkTools/tracert.c @@ -700,7 +700,7 @@ INT_PTR CALLBACK TracertDlgProc( PhInsertEMenuItem(menu, PhCreateEMenuItem(0, MAINMENU_ACTION_PING, L"Ping", NULL, NULL), -1); PhInsertEMenuItem(menu, PhCreateEMenuItem(0, NETWORK_ACTION_TRACEROUTE, L"Traceroute", NULL, NULL), -1); PhInsertEMenuItem(menu, PhCreateEMenuItem(0, NETWORK_ACTION_WHOIS, L"Whois", NULL, NULL), -1); - PhInsertEMenuItem(menu, PhCreateEMenuItem(PH_EMENU_SEPARATOR, 0, NULL, NULL, NULL), -1); + PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), -1); PhInsertEMenuItem(menu, PhCreateEMenuItem(0, MENU_ACTION_COPY, L"Copy", NULL, NULL), -1); PhInsertCopyCellEMenuItem(menu, MENU_ACTION_COPY, context->TreeNewHandle, contextMenuEvent->Column); diff --git a/plugins/OnlineChecks/main.c b/plugins/OnlineChecks/main.c index c199c8070458..09caed0e07a7 100644 --- a/plugins/OnlineChecks/main.c +++ b/plugins/OnlineChecks/main.c @@ -260,10 +260,10 @@ VOID NTAPI MainMenuInitializingCallback( if (menuInfo->u.MainMenu.SubMenuIndex != PH_MENU_ITEM_LOCATION_TOOLS) return; - onlineMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, 0, L"Online Checks", NULL); - PhInsertEMenuItem(onlineMenuItem, enableMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, ENABLE_SERVICE_VIRUSTOTAL, L"Enable VirusTotal scanning", NULL), -1); - PhInsertEMenuItem(onlineMenuItem, PhPluginCreateEMenuItem(PluginInstance, PH_EMENU_SEPARATOR, 0, NULL, NULL), -1); - PhInsertEMenuItem(onlineMenuItem, PhPluginCreateEMenuItem(PluginInstance, 0, MENUITEM_VIRUSTOTAL_UPLOAD_FILE, L"Upload file to VirusTotal...", NULL), -1); + onlineMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, 0, L"&Online Checks", NULL); + PhInsertEMenuItem(onlineMenuItem, enableMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, ENABLE_SERVICE_VIRUSTOTAL, L"&Enable VirusTotal scanning", NULL), -1); + PhInsertEMenuItem(onlineMenuItem, PhCreateEMenuSeparator(), -1); + PhInsertEMenuItem(onlineMenuItem, PhPluginCreateEMenuItem(PluginInstance, 0, MENUITEM_VIRUSTOTAL_UPLOAD_FILE, L"&Upload file to VirusTotal...", NULL), -1); //PhInsertEMenuItem(onlineMenuItem, PhPluginCreateEMenuItem(PluginInstance, 0, MENUITEM_VIRUSTOTAL_QUEUE, L"Upload unknown files to VirusTotal...", NULL), -1); PhInsertEMenuItem(menuInfo->Menu, onlineMenuItem, -1); @@ -281,19 +281,19 @@ PPH_EMENU_ITEM CreateSendToMenu( PPH_EMENU_ITEM menuItem; ULONG insertIndex; - sendToMenu = PhPluginCreateEMenuItem(PluginInstance, 0, 0, L"Send to", NULL); - PhInsertEMenuItem(sendToMenu, PhPluginCreateEMenuItem(PluginInstance, 0, MENUITEM_VIRUSTOTAL_UPLOAD, L"virustotal.com", FileName), -1); - PhInsertEMenuItem(sendToMenu, PhPluginCreateEMenuItem(PluginInstance, 0, MENUITEM_JOTTI_UPLOAD, L"virusscan.jotti.org", FileName), -1); + sendToMenu = PhPluginCreateEMenuItem(PluginInstance, 0, 0, L"Sen&d to", NULL); + PhInsertEMenuItem(sendToMenu, PhPluginCreateEMenuItem(PluginInstance, 0, MENUITEM_VIRUSTOTAL_UPLOAD, L"&virustotal.com", FileName), -1); + PhInsertEMenuItem(sendToMenu, PhPluginCreateEMenuItem(PluginInstance, 0, MENUITEM_JOTTI_UPLOAD, L"virusscan.&jotti.org", FileName), -1); if (ProcessesMenu && (menuItem = PhFindEMenuItem(Parent, PH_EMENU_FIND_STARTSWITH, L"Search online", 0))) { insertIndex = PhIndexOfEMenuItem(Parent, menuItem); PhInsertEMenuItem(Parent, sendToMenu, insertIndex + 1); - PhInsertEMenuItem(Parent, PhPluginCreateEMenuItem(PluginInstance, PH_EMENU_SEPARATOR, 0, NULL, NULL), insertIndex + 2); + PhInsertEMenuItem(Parent, PhCreateEMenuSeparator(), insertIndex + 2); } else { - PhInsertEMenuItem(Parent, PhPluginCreateEMenuItem(PluginInstance, PH_EMENU_SEPARATOR, 0, NULL, NULL), -1); + PhInsertEMenuItem(Parent, PhCreateEMenuSeparator(), -1); PhInsertEMenuItem(Parent, sendToMenu, -1); } @@ -359,10 +359,10 @@ VOID NTAPI ServiceMenuInitializingCallback( else serviceItem = NULL; - sendToMenu = PhPluginCreateEMenuItem(PluginInstance, 0, 0, L"Send to", NULL); - PhInsertEMenuItem(sendToMenu, PhPluginCreateEMenuItem(PluginInstance, 0, MENUITEM_VIRUSTOTAL_UPLOAD_SERVICE, L"virustotal.com", serviceItem ? serviceItem : NULL), -1); - PhInsertEMenuItem(sendToMenu, PhPluginCreateEMenuItem(PluginInstance, 0, MENUITEM_JOTTI_UPLOAD_SERVICE, L"virusscan.jotti.org", serviceItem ? serviceItem : NULL), -1); - PhInsertEMenuItem(menuInfo->Menu, PhPluginCreateEMenuItem(PluginInstance, PH_EMENU_SEPARATOR, 0, NULL, NULL), -1); + sendToMenu = PhPluginCreateEMenuItem(PluginInstance, 0, 0, L"Sen&d to", NULL); + PhInsertEMenuItem(sendToMenu, PhPluginCreateEMenuItem(PluginInstance, 0, MENUITEM_VIRUSTOTAL_UPLOAD_SERVICE, L"&virustotal.com", serviceItem ? serviceItem : NULL), -1); + PhInsertEMenuItem(sendToMenu, PhPluginCreateEMenuItem(PluginInstance, 0, MENUITEM_JOTTI_UPLOAD_SERVICE, L"virusscan.&jotti.org", serviceItem ? serviceItem : NULL), -1); + PhInsertEMenuItem(menuInfo->Menu, PhCreateEMenuSeparator(), -1); PhInsertEMenuItem(menuInfo->Menu, sendToMenu, -1); if (!serviceItem) diff --git a/plugins/ToolStatus/main.c b/plugins/ToolStatus/main.c index ae24130f3e41..9ca760f3e568 100644 --- a/plugins/ToolStatus/main.c +++ b/plugins/ToolStatus/main.c @@ -211,7 +211,7 @@ VOID ShowCustomizeMenu( PhInsertEMenuItem(menu, PhCreateEMenuItem(0, COMMAND_ID_ENABLE_IO_GRAPH, L"I/O history", NULL, NULL), -1); PhInsertEMenuItem(menu, PhCreateEMenuItem(0, COMMAND_ID_ENABLE_MEMORY_GRAPH, L"Physical memory history", NULL, NULL), -1); PhInsertEMenuItem(menu, PhCreateEMenuItem(0, COMMAND_ID_ENABLE_COMMIT_GRAPH, L"Commit charge history", NULL, NULL), -1); - PhInsertEMenuItem(menu, PhCreateEMenuItem(PH_EMENU_SEPARATOR, 0, NULL, NULL, NULL), -1); + PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), -1); PhInsertEMenuItem(menu, PhCreateEMenuItem(0, COMMAND_ID_TOOLBAR_LOCKUNLOCK, L"Lock the toolbar", NULL, NULL), -1); PhInsertEMenuItem(menu, PhCreateEMenuItem(0, COMMAND_ID_TOOLBAR_CUSTOMIZE, L"Customize...", NULL, NULL), -1); @@ -806,7 +806,7 @@ LRESULT CALLBACK MainWndSubclassProc( if (buttonInfo.fsStyle == BTNS_SEP) { // Add separators to menu. - PhInsertEMenuItem(menu, PhCreateEMenuItem(PH_EMENU_SEPARATOR, 0, NULL, NULL, NULL), -1); + PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), -1); } else { @@ -847,10 +847,10 @@ LRESULT CALLBACK MainWndSubclassProc( // Create the sub-menu... PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, PHAPP_ID_COMPUTER_LOCK, L"&Lock", NULL, NULL), -1); PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, PHAPP_ID_COMPUTER_LOGOFF, L"Log o&ff", NULL, NULL), -1); - PhInsertEMenuItem(menuItem, PhCreateEMenuItem(PH_EMENU_SEPARATOR, 0, NULL, NULL, NULL), -1); + PhInsertEMenuItem(menuItem, PhCreateEMenuSeparator(), -1); PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, PHAPP_ID_COMPUTER_SLEEP, L"&Sleep", NULL, NULL), -1); PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, PHAPP_ID_COMPUTER_HIBERNATE, L"&Hibernate", NULL, NULL), -1); - PhInsertEMenuItem(menuItem, PhCreateEMenuItem(PH_EMENU_SEPARATOR, 0, NULL, NULL, NULL), -1); + PhInsertEMenuItem(menuItem, PhCreateEMenuSeparator(), -1); PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, PHAPP_ID_COMPUTER_RESTART, L"R&estart", NULL, NULL), -1); PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, PHAPP_ID_COMPUTER_RESTARTBOOTOPTIONS, L"Restart to boot &options", NULL, NULL), -1); PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, PHAPP_ID_COMPUTER_SHUTDOWN, L"Shu&t down", NULL, NULL), -1); @@ -975,10 +975,10 @@ LRESULT CALLBACK MainWndSubclassProc( menu = PhCreateEMenu(); PhInsertEMenuItem(menu, PhCreateEMenuItem(0, PHAPP_ID_COMPUTER_LOCK, L"&Lock", NULL, NULL), -1); PhInsertEMenuItem(menu, PhCreateEMenuItem(0, PHAPP_ID_COMPUTER_LOGOFF, L"Log o&ff", NULL, NULL), -1); - PhInsertEMenuItem(menu, PhCreateEMenuItem(PH_EMENU_SEPARATOR, 0, NULL, NULL, NULL), -1); + PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), -1); PhInsertEMenuItem(menu, PhCreateEMenuItem(0, PHAPP_ID_COMPUTER_SLEEP, L"&Sleep", NULL, NULL), -1); PhInsertEMenuItem(menu, PhCreateEMenuItem(0, PHAPP_ID_COMPUTER_HIBERNATE, L"&Hibernate", NULL, NULL), -1); - PhInsertEMenuItem(menu, PhCreateEMenuItem(PH_EMENU_SEPARATOR, 0, NULL, NULL, NULL), -1); + PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), -1); PhInsertEMenuItem(menu, PhCreateEMenuItem(0, PHAPP_ID_COMPUTER_RESTART, L"R&estart", NULL, NULL), -1); PhInsertEMenuItem(menu, PhCreateEMenuItem(0, PHAPP_ID_COMPUTER_RESTARTBOOTOPTIONS, L"Restart to boot &options", NULL, NULL), -1); PhInsertEMenuItem(menu, PhCreateEMenuItem(0, PHAPP_ID_COMPUTER_SHUTDOWN, L"Shu&t down", NULL, NULL), -1); diff --git a/plugins/Updater/main.c b/plugins/Updater/main.c index 9d9e795e2607..251a6987195e 100644 --- a/plugins/Updater/main.c +++ b/plugins/Updater/main.c @@ -52,7 +52,7 @@ VOID NTAPI MainMenuInitializingCallback( if (menuInfo->u.MainMenu.SubMenuIndex != 4) return; - PhInsertEMenuItem(menuInfo->Menu, PhPluginCreateEMenuItem(PluginInstance, 0, UPDATE_MENUITEM, L"Check for updates", NULL), 0); + PhInsertEMenuItem(menuInfo->Menu, PhPluginCreateEMenuItem(PluginInstance, 0, UPDATE_MENUITEM, L"Check for &updates", NULL), 0); } VOID NTAPI MenuItemCallback( diff --git a/plugins/UserNotes/main.c b/plugins/UserNotes/main.c index 06df65c71879..69c0ca077f65 100644 --- a/plugins/UserNotes/main.c +++ b/plugins/UserNotes/main.c @@ -912,7 +912,7 @@ VOID AddSavePriorityMenuItemsAndHook( //PhRemoveEMenuItem(affinityMenuItem, affinityMenuItem, 0); // Insert standard menu-items - PhInsertEMenuItem(affinityMenuItem, PhPluginCreateEMenuItem(PluginInstance, PH_EMENU_SEPARATOR, 0, NULL, NULL), -1); + PhInsertEMenuItem(affinityMenuItem, PhCreateEMenuSeparator(), -1); PhInsertEMenuItem(affinityMenuItem, saveMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, PROCESS_AFFINITY_SAVE_ID, PhaFormatString(L"&Save for %s", ProcessItem->ProcessName->Buffer)->Buffer, NULL), -1); PhInsertEMenuItem(affinityMenuItem, saveForCommandLineMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, PROCESS_AFFINITY_SAVE_FOR_THIS_COMMAND_LINE_ID, L"Save &for this command line", NULL), -1); @@ -932,7 +932,7 @@ VOID AddSavePriorityMenuItemsAndHook( // Priority if (priorityMenuItem = PhFindEMenuItem(MenuInfo->Menu, 0, L"Priority", 0)) { - PhInsertEMenuItem(priorityMenuItem, PhPluginCreateEMenuItem(PluginInstance, PH_EMENU_SEPARATOR, 0, NULL, NULL), -1); + PhInsertEMenuItem(priorityMenuItem, PhCreateEMenuSeparator(), -1); PhInsertEMenuItem(priorityMenuItem, saveMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, PROCESS_PRIORITY_SAVE_ID, PhaFormatString(L"&Save for %s", ProcessItem->ProcessName->Buffer)->Buffer, NULL), -1); PhInsertEMenuItem(priorityMenuItem, saveForCommandLineMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, PROCESS_PRIORITY_SAVE_FOR_THIS_COMMAND_LINE_ID, L"Save &for this command line", NULL), -1); @@ -952,7 +952,7 @@ VOID AddSavePriorityMenuItemsAndHook( // I/O Priority if (ioPriorityMenuItem = PhFindEMenuItem(MenuInfo->Menu, 0, L"I/O Priority", 0)) { - PhInsertEMenuItem(ioPriorityMenuItem, PhPluginCreateEMenuItem(PluginInstance, PH_EMENU_SEPARATOR, 0, NULL, NULL), -1); + PhInsertEMenuItem(ioPriorityMenuItem, PhCreateEMenuSeparator(), -1); PhInsertEMenuItem(ioPriorityMenuItem, saveMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, PROCESS_IO_PRIORITY_SAVE_ID, PhaFormatString(L"&Save for %s", ProcessItem->ProcessName->Buffer)->Buffer, NULL), -1); PhInsertEMenuItem(ioPriorityMenuItem, saveForCommandLineMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, PROCESS_IO_PRIORITY_SAVE_FOR_THIS_COMMAND_LINE_ID, L"Save &for this command line", NULL), -1); @@ -1001,9 +1001,9 @@ VOID ProcessMenuInitializingCallback( highlightPresent = TRUE; UnlockDb(); - PhInsertEMenuItem(miscMenuItem, collapseMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, PROCESS_COLLAPSE_ID, L"Collapse by default", NULL), 0); - PhInsertEMenuItem(miscMenuItem, highlightMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, PROCESS_HIGHLIGHT_ID, L"Highlight", UlongToPtr(highlightPresent)), 1); - PhInsertEMenuItem(miscMenuItem, PhPluginCreateEMenuItem(PluginInstance, PH_EMENU_SEPARATOR, 0, NULL, NULL), 2); + PhInsertEMenuItem(miscMenuItem, collapseMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, PROCESS_COLLAPSE_ID, L"Col&lapse by default", NULL), 0); + PhInsertEMenuItem(miscMenuItem, highlightMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, PROCESS_HIGHLIGHT_ID, L"Highligh&t", UlongToPtr(highlightPresent)), 1); + PhInsertEMenuItem(miscMenuItem, PhCreateEMenuSeparator(), 2); LockDb(); diff --git a/plugins/WindowExplorer/main.c b/plugins/WindowExplorer/main.c index e6a4aadfa86f..ad0658fd76d9 100644 --- a/plugins/WindowExplorer/main.c +++ b/plugins/WindowExplorer/main.c @@ -143,13 +143,13 @@ VOID NTAPI MainMenuInitializingCallback( else insertIndex = 0; - PhInsertEMenuItem(menuInfo->Menu, menuItem = PhPluginCreateEMenuItem(PluginInstance, 0, ID_VIEW_WINDOWS, L"Windows", NULL), insertIndex); + PhInsertEMenuItem(menuInfo->Menu, menuItem = PhPluginCreateEMenuItem(PluginInstance, 0, ID_VIEW_WINDOWS, L"&Windows", NULL), insertIndex); if (PhGetIntegerSetting(SETTING_NAME_SHOW_DESKTOP_WINDOWS)) { insertIndex = PhIndexOfEMenuItem(menuInfo->Menu, menuItem) + 1; - PhInsertEMenuItem(menuInfo->Menu, PhPluginCreateEMenuItem(PluginInstance, 0, ID_VIEW_DESKTOPWINDOWS, L"Desktop Windows...", NULL), insertIndex); + PhInsertEMenuItem(menuInfo->Menu, PhPluginCreateEMenuItem(PluginInstance, 0, ID_VIEW_DESKTOPWINDOWS, L"Deskto&p Windows...", NULL), insertIndex); } } @@ -194,7 +194,7 @@ VOID NTAPI ThreadMenuInitializingCallback( insertIndex = 0; PhInsertEMenuItem(menuInfo->Menu, menuItem = PhPluginCreateEMenuItem(PluginInstance, 0, ID_THREAD_WINDOWS, - L"Windows", threadItem), insertIndex); + L"&Windows", threadItem), insertIndex); if (!threadItem) menuItem->Flags |= PH_EMENU_DISABLED; } diff --git a/tools/peview/pdbprp.c b/tools/peview/pdbprp.c index 438436d75740..fb8bc689a367 100644 --- a/tools/peview/pdbprp.c +++ b/tools/peview/pdbprp.c @@ -78,7 +78,7 @@ VOID PhInitializeTreeNewColumnMenuEx( if (resetSortMenuItem) PhInsertEMenuItem(Data->Menu, resetSortMenuItem, -1); - PhInsertEMenuItem(Data->Menu, PhCreateEMenuItem(PH_EMENU_SEPARATOR, 0, L"", NULL, NULL), -1); + PhInsertEMenuItem(Data->Menu, PhCreateEMenuSeparator(), -1); PhInsertEMenuItem(Data->Menu, chooseColumnsMenuItem, -1); if (TreeNew_GetFixedColumn(Data->TreeNewHandle)) From 74735873a1b02f32bb7836d0c3898c1aa44bba7f Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 18 Dec 2017 11:08:57 +1100 Subject: [PATCH 0635/2058] Fix runas service regression from 2cfb6835 --- phlib/util.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/phlib/util.c b/phlib/util.c index d21a2fe255d5..bf4185367d1b 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -2588,6 +2588,19 @@ NTSTATUS PhCreateProcessWin32Ex( PhMoveReference(&fileName, PhCreateString(cmdlineArgList[0])); LocalFree(cmdlineArgList); } + + if (!RtlDoesFileExists_U(fileName->Buffer)) + { + WCHAR buffer[MAX_PATH]; + + // The user typed a name without a path so attempt to locate the executable. + if (PhSearchFilePath(fileName->Buffer, L".exe", buffer)) + PhMoveReference(&fileName, PhCreateString(buffer)); + else + fileName = NULL; + } + else + fileName = NULL; } newFlags = 0; From 89849dcfe58d1b3ce62ab87d19da0c7b79fa623f Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 18 Dec 2017 11:09:38 +1100 Subject: [PATCH 0636/2058] Fix PhFindEMenuItem crash for seperators #205 --- phlib/util.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/phlib/util.c b/phlib/util.c index bf4185367d1b..f7162474085f 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -1105,6 +1105,9 @@ LONG PhCompareUnicodeStringZIgnoreMenuPrefix( { WCHAR t; + if (!A || !B) + return -1; + if (!IgnoreCase) { while (TRUE) From 01d1e3aa03bbe925623f30d8213e64e878a9f64e Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 18 Dec 2017 11:16:25 +1100 Subject: [PATCH 0637/2058] Move emenu type --- phlib/include/emenu.h | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/phlib/include/emenu.h b/phlib/include/emenu.h index f6ece558f6fa..8bab5f575b8a 100644 --- a/phlib/include/emenu.h +++ b/phlib/include/emenu.h @@ -58,11 +58,6 @@ VOID PhDestroyEMenuItem( _In_ PPH_EMENU_ITEM Item ); -/** -* Creates a menu separator. -*/ -#define PhCreateEMenuSeparator() PhCreateEMenuItem(PH_EMENU_SEPARATOR, 0, L"", NULL, NULL) - #define PH_EMENU_FIND_DESCEND 0x1 #define PH_EMENU_FIND_STARTSWITH 0x2 #define PH_EMENU_FIND_LITERAL 0x4 @@ -181,6 +176,14 @@ PPH_EMENU_ITEM PhShowEMenu( // Convenience functions +FORCEINLINE +PPH_EMENU_ITEM PhCreateEMenuSeparator( + VOID + ) +{ + return PhCreateEMenuItem(PH_EMENU_SEPARATOR, 0, NULL, NULL, NULL); +} + PHLIBAPI BOOLEAN PhSetFlagsEMenuItem( _Inout_ PPH_EMENU_ITEM Item, From 7a481ef6ee98d6ec36b94aab1416fbabbf09e0c6 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 18 Dec 2017 23:58:56 +1100 Subject: [PATCH 0638/2058] Fix spacing --- ProcessHacker/memlist.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ProcessHacker/memlist.c b/ProcessHacker/memlist.c index 87b45fcbdd9a..2bad4c6b43bc 100644 --- a/ProcessHacker/memlist.c +++ b/ProcessHacker/memlist.c @@ -974,7 +974,7 @@ VOID PhGetSelectedMemoryNodes( PPH_MEMORY_NODE node = Context->RegionNodeList->Items[i]; if (node->Node.Selected) - PhAddItemArray(&array, &node); + PhAddItemArray(&array, &node); } *NumberOfMemoryNodes = (ULONG)array.Count; From 61dba75f72503e009d2d6fe95cad2e8e7865c3ee Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 19 Dec 2017 03:32:20 +1100 Subject: [PATCH 0639/2058] Add PhMainWndEarlyExit --- ProcessHacker/mainwnd.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index 5df7a059dca7..0d1e77077371 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -60,6 +60,7 @@ PHAPPAPI HWND PhMainWndHandle; BOOLEAN PhMainWndExiting = FALSE; +BOOLEAN PhMainWndEarlyExit = FALSE; HMENU PhMainWndMenuHandle; PH_PROVIDER_REGISTRATION PhMwpProcessProviderRegistration; @@ -493,6 +494,8 @@ VOID PhMwpOnDestroy( VOID ) { + PhMainWndExiting = TRUE; + PhSetIntegerSetting(L"MainWindowTabRestoreIndex", TabCtrl_GetCurSel(TabControlHandle)); // Notify pages and plugins that we are shutting down. @@ -502,8 +505,8 @@ VOID PhMwpOnDestroy( if (PhPluginsEnabled) PhUnloadPlugins(); - if (!PhMainWndExiting) - ProcessHacker_SaveAllSettings(PhMainWndHandle); + if (!PhMainWndEarlyExit) + PhMwpSaveSettings(); PhNfUninitialization(); @@ -1836,7 +1839,7 @@ ULONG_PTR PhMwpOnUserMessage( { case WM_PH_ACTIVATE: { - if (!PhMainWndExiting) + if (!PhMainWndEarlyExit && !PhMainWndExiting) { if (WParam != 0) { @@ -1882,12 +1885,12 @@ ULONG_PTR PhMwpOnUserMessage( case WM_PH_PREPARE_FOR_EARLY_SHUTDOWN: { PhMwpSaveSettings(); - PhMainWndExiting = TRUE; + PhMainWndEarlyExit = TRUE; } break; case WM_PH_CANCEL_EARLY_SHUTDOWN: { - PhMainWndExiting = FALSE; + PhMainWndEarlyExit = FALSE; } break; case WM_PH_DELAYED_LOAD_COMPLETED: From 02ab65119e916fafda12184df440304c5dcdf40e Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 20 Dec 2017 07:42:26 +1100 Subject: [PATCH 0640/2058] Fix crash --- phlib/util.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/phlib/util.c b/phlib/util.c index f7162474085f..a78c8142c484 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -2592,7 +2592,7 @@ NTSTATUS PhCreateProcessWin32Ex( LocalFree(cmdlineArgList); } - if (!RtlDoesFileExists_U(fileName->Buffer)) + if (fileName && !RtlDoesFileExists_U(fileName->Buffer)) { WCHAR buffer[MAX_PATH]; @@ -2600,10 +2600,8 @@ NTSTATUS PhCreateProcessWin32Ex( if (PhSearchFilePath(fileName->Buffer, L".exe", buffer)) PhMoveReference(&fileName, PhCreateString(buffer)); else - fileName = NULL; + PhClearReference(&fileName); } - else - fileName = NULL; } newFlags = 0; From fe73013a1139f97d6cf8779c57f6e3faf3ddb084 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 20 Dec 2017 07:46:18 +1100 Subject: [PATCH 0641/2058] Add LdrFindResource_U/LdrEnumResources --- phnt/include/ntldr.h | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/phnt/include/ntldr.h b/phnt/include/ntldr.h index 190afe199733..f8f086c352ce 100644 --- a/phnt/include/ntldr.h +++ b/phnt/include/ntldr.h @@ -583,6 +583,50 @@ LdrAccessResource( _Out_opt_ ULONG *ResourceLength ); +typedef struct _LDR_RESOURCE_INFO +{ + ULONG_PTR Type; + ULONG_PTR Name; + ULONG_PTR Language; +} LDR_RESOURCE_INFO, *PLDR_RESOURCE_INFO; + +#define RESOURCE_TYPE_LEVEL 0 +#define RESOURCE_NAME_LEVEL 1 +#define RESOURCE_LANGUAGE_LEVEL 2 +#define RESOURCE_DATA_LEVEL 3 + +NTSTATUS +NTAPI +LdrFindResource_U( + _In_ PVOID BaseAddress, + _In_ PLDR_RESOURCE_INFO ResourceInfo, + _In_ ULONG Level, + _Out_ PIMAGE_RESOURCE_DATA_ENTRY *ResourceDataEntry + ); + +typedef struct _LDR_ENUM_RESOURCE_INFO +{ + ULONG_PTR Type; + ULONG_PTR Name; + ULONG_PTR Language; + PVOID Data; + SIZE_T Size; + ULONG_PTR Reserved; +} LDR_ENUM_RESOURCE_INFO, *PLDR_ENUM_RESOURCE_INFO; + +#define NAME_FROM_RESOURCE_ENTRY(RootDirectory, Entry) \ + ((Entry)->NameIsString ? (ULONG_PTR)PTR_ADD_OFFSET((RootDirectory), (Entry)->NameOffset) : (Entry)->Id) + +NTSTATUS +NTAPI +LdrEnumResources( + _In_ PVOID BaseAddress, + _In_ PLDR_RESOURCE_INFO ResourceInfo, + _In_ ULONG Level, + _Inout_ ULONG *ResourceCount, + _Out_writes_to_(*ResourceCount,*ResourceCount) LDR_ENUM_RESOURCE_INFO *Resources + ); + NTSYSAPI NTSTATUS NTAPI From 28bf431a477d6cd446b427bdb63b58de3bc258f7 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 20 Dec 2017 08:09:00 +1100 Subject: [PATCH 0642/2058] Update PhLoadResource --- phlib/util.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/phlib/util.c b/phlib/util.c index a78c8142c484..17f0186cc211 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -5237,22 +5237,19 @@ BOOLEAN PhLoadResource( _Out_ PVOID *ResourceBuffer ) { + LDR_RESOURCE_INFO resourceInfo; + PIMAGE_RESOURCE_DATA_ENTRY resourceData; ULONG resourceLength; - PVOID resourceInfo; PVOID resourceBuffer; - resourceInfo = FindResource(DllBase, Name, Type); + resourceInfo.Type = (ULONG_PTR)Type; + resourceInfo.Name = (ULONG_PTR)Name; + resourceInfo.Language = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL); - if (!resourceInfo) + if (!NT_SUCCESS(LdrFindResource_U(DllBase, &resourceInfo, RESOURCE_DATA_LEVEL, &resourceData))) return FALSE; - if (!NT_SUCCESS(LdrAccessResource(DllBase, resourceInfo, &resourceBuffer, &resourceLength))) - return FALSE; - - if (!resourceBuffer) - return FALSE; - - if (resourceLength == 0) + if (!NT_SUCCESS(LdrAccessResource(DllBase, resourceData, &resourceBuffer, &resourceLength))) return FALSE; if (ResourceLength) From c3def7ef99cc818b36acf281b889a11462f219d5 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 20 Dec 2017 08:09:55 +1100 Subject: [PATCH 0643/2058] Fix PS_SYSTEM_DLL_INIT_BLOCK version check --- ProcessHacker/memprv.c | 2 +- ProcessHacker/mtgndlg.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ProcessHacker/memprv.c b/ProcessHacker/memprv.c index 0b38809c1d1e..747b9a8b9135 100644 --- a/ProcessHacker/memprv.c +++ b/ProcessHacker/memprv.c @@ -494,7 +494,7 @@ NTSTATUS PhpUpdateMemoryRegionTypes( PVOID cfgBitmapAddress = NULL; PVOID cfgBitmapWow64Address = NULL; - if (ldrInitBlock.Size >= UFIELD_OFFSET(PS_SYSTEM_DLL_INIT_BLOCK, Wow64CfgBitMap)) + if (RTL_CONTAINS_FIELD(&ldrInitBlock, ldrInitBlock.Size, Wow64CfgBitMap)) { cfgBitmapAddress = (PVOID)ldrInitBlock.CfgBitMap; cfgBitmapWow64Address = (PVOID)ldrInitBlock.Wow64CfgBitMap; diff --git a/ProcessHacker/mtgndlg.c b/ProcessHacker/mtgndlg.c index 80317341f046..a9c5c8ef7ed6 100644 --- a/ProcessHacker/mtgndlg.c +++ b/ProcessHacker/mtgndlg.c @@ -222,7 +222,7 @@ INT_PTR CALLBACK PhpProcessMitigationPolicyDlgProc( PhAddListViewItem(lvHandle, MAXINT, entry->ShortDescription->Buffer, entry); } - if (context->SystemDllInitBlock) + if (context->SystemDllInitBlock && RTL_CONTAINS_FIELD(context->SystemDllInitBlock, context->SystemDllInitBlock->Size, MitigationOptionsMap)) { if (context->SystemDllInitBlock->MitigationOptionsMap.Map[0] & PROCESS_CREATION_MITIGATION_POLICY2_LOADER_INTEGRITY_CONTINUITY_ALWAYS_ON) { From 39dc233eb6e59177b53bb195c2f9910342077518 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 20 Dec 2017 08:10:44 +1100 Subject: [PATCH 0644/2058] Fix wmi provider tab not using user-configured browse executable --- ProcessHacker/prpgwmi.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/ProcessHacker/prpgwmi.c b/ProcessHacker/prpgwmi.c index 22d21aeaaac0..24ca81fd52d7 100644 --- a/ProcessHacker/prpgwmi.c +++ b/ProcessHacker/prpgwmi.c @@ -716,7 +716,13 @@ INT_PTR CALLBACK PhpProcessWmiProvidersDlgProc( { if (!PhIsNullOrEmptyString(entry->FileName) && RtlDoesFileExists_U(entry->FileName->Buffer)) { - PhShellExploreFile(hwndDlg, entry->FileName->Buffer); + PhShellExecuteUserString( + hwndDlg, + L"FileBrowseExecutable", + processItem->FileName->Buffer, + FALSE, + L"Make sure the Explorer executable file is present." + ); } } break; From d32be6cc691c3449aadf97a59d6c9bcfef0987dd Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 20 Dec 2017 21:37:35 +1100 Subject: [PATCH 0645/2058] Fix LdrEnumResources rs3 symbols --- phnt/include/ntldr.h | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/phnt/include/ntldr.h b/phnt/include/ntldr.h index f8f086c352ce..a2cf3000b477 100644 --- a/phnt/include/ntldr.h +++ b/phnt/include/ntldr.h @@ -604,15 +604,23 @@ LdrFindResource_U( _Out_ PIMAGE_RESOURCE_DATA_ENTRY *ResourceDataEntry ); -typedef struct _LDR_ENUM_RESOURCE_INFO +// private +typedef struct _LDR_ENUM_RESOURCE_ENTRY { - ULONG_PTR Type; - ULONG_PTR Name; - ULONG_PTR Language; + union + { + ULONG_PTR NameOrId; + PIMAGE_RESOURCE_DIRECTORY_STRING Name; + struct + { + USHORT Id; + USHORT NameIsPresent; + }; + } Path[3]; PVOID Data; - SIZE_T Size; - ULONG_PTR Reserved; -} LDR_ENUM_RESOURCE_INFO, *PLDR_ENUM_RESOURCE_INFO; + ULONG Size; + ULONG Reserved; +} LDR_ENUM_RESOURCE_ENTRY, *PLDR_ENUM_RESOURCE_ENTRY; #define NAME_FROM_RESOURCE_ENTRY(RootDirectory, Entry) \ ((Entry)->NameIsString ? (ULONG_PTR)PTR_ADD_OFFSET((RootDirectory), (Entry)->NameOffset) : (Entry)->Id) @@ -624,7 +632,7 @@ LdrEnumResources( _In_ PLDR_RESOURCE_INFO ResourceInfo, _In_ ULONG Level, _Inout_ ULONG *ResourceCount, - _Out_writes_to_(*ResourceCount,*ResourceCount) LDR_ENUM_RESOURCE_INFO *Resources + _Out_writes_to_opt_(*ResourceCount, *ResourceCount) PLDR_ENUM_RESOURCE_ENTRY Resources ); NTSYSAPI From 22665ad456f42b5cb920d81000f883338887844d Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 21 Dec 2017 12:12:20 +1100 Subject: [PATCH 0646/2058] Fix kph build errors --- phnt/include/ntldr.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/phnt/include/ntldr.h b/phnt/include/ntldr.h index a2cf3000b477..2951d7d7fab4 100644 --- a/phnt/include/ntldr.h +++ b/phnt/include/ntldr.h @@ -677,6 +677,8 @@ typedef struct _RTL_PROCESS_MODULE_INFORMATION_EX PVOID DefaultBase; } RTL_PROCESS_MODULE_INFORMATION_EX, *PRTL_PROCESS_MODULE_INFORMATION_EX; +#if (PHNT_MODE != PHNT_MODE_KERNEL) + NTSYSAPI NTSTATUS NTAPI @@ -731,4 +733,6 @@ LdrQueryImageFileExecutionOptions( _Out_opt_ PULONG RetunedLength ); +#endif // (PHNT_MODE != PHNT_MODE_KERNEL) + #endif From 3aa5a55c05d475b768d6f2e18a1d7c8aa4b7e17d Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 21 Dec 2017 12:49:23 +1100 Subject: [PATCH 0647/2058] Fix types --- phnt/include/ntldr.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/phnt/include/ntldr.h b/phnt/include/ntldr.h index 2951d7d7fab4..d03cd284e4e0 100644 --- a/phnt/include/ntldr.h +++ b/phnt/include/ntldr.h @@ -595,6 +595,7 @@ typedef struct _LDR_RESOURCE_INFO #define RESOURCE_LANGUAGE_LEVEL 2 #define RESOURCE_DATA_LEVEL 3 +NTSYSAPI NTSTATUS NTAPI LdrFindResource_U( @@ -604,6 +605,16 @@ LdrFindResource_U( _Out_ PIMAGE_RESOURCE_DATA_ENTRY *ResourceDataEntry ); +NTSYSAPI +NTSTATUS +NTAPI +LdrFindResourceDirectory_U( + _In_ PVOID BaseAddress, + _In_ PLDR_RESOURCE_INFO ResourceInfo, + _In_ ULONG Level, + _Out_ PIMAGE_RESOURCE_DIRECTORY *ResourceDirectory + ); + // private typedef struct _LDR_ENUM_RESOURCE_ENTRY { @@ -625,6 +636,7 @@ typedef struct _LDR_ENUM_RESOURCE_ENTRY #define NAME_FROM_RESOURCE_ENTRY(RootDirectory, Entry) \ ((Entry)->NameIsString ? (ULONG_PTR)PTR_ADD_OFFSET((RootDirectory), (Entry)->NameOffset) : (Entry)->Id) +NTSYSAPI NTSTATUS NTAPI LdrEnumResources( From 32af4dfe9432b36f8b63c70667f2bd103f7cb03b Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 21 Dec 2017 12:57:24 +1100 Subject: [PATCH 0648/2058] Add PhGetMappedImageResources --- phlib/include/mapimg.h | 27 ++++++++ phlib/mapimg.c | 140 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 166 insertions(+), 1 deletion(-) diff --git a/phlib/include/mapimg.h b/phlib/include/mapimg.h index 8590b1b50f67..88cdb031ab60 100644 --- a/phlib/include/mapimg.h +++ b/phlib/include/mapimg.h @@ -454,6 +454,33 @@ PhGetMappedImageCfgEntry( _Out_ PIMAGE_CFG_ENTRY Entry ); +typedef struct _PH_IMAGE_RESOURCE_ENTRY +{ + ULONG_PTR Type; + ULONG_PTR Name; + ULONG_PTR Language; + ULONG Size; + PVOID Data; +} PH_IMAGE_RESOURCE_ENTRY, *PPH_IMAGE_RESOURCE_ENTRY; + +typedef struct _PH_MAPPED_IMAGE_RESOURCES +{ + PPH_MAPPED_IMAGE MappedImage; + PIMAGE_DATA_DIRECTORY DataDirectory; + PIMAGE_RESOURCE_DIRECTORY ResourceDirectory; + + ULONG NumberOfEntries; + PPH_IMAGE_RESOURCE_ENTRY ResourceEntries; +} PH_MAPPED_IMAGE_RESOURCES, *PPH_MAPPED_IMAGE_RESOURCES; + +PHLIBAPI +NTSTATUS +NTAPI +PhGetMappedImageResources( + _Out_ PPH_MAPPED_IMAGE_RESOURCES Resources, + _In_ PPH_MAPPED_IMAGE MappedImage + ); + #ifdef __cplusplus } #endif diff --git a/phlib/mapimg.c b/phlib/mapimg.c index 1ddb46aa6510..24523ff12cc9 100644 --- a/phlib/mapimg.c +++ b/phlib/mapimg.c @@ -1496,4 +1496,142 @@ NTSTATUS PhGetMappedImageCfgEntry( } return STATUS_SUCCESS; -} \ No newline at end of file +} + +NTSTATUS PhGetMappedImageResources( + _Out_ PPH_MAPPED_IMAGE_RESOURCES Resources, + _In_ PPH_MAPPED_IMAGE MappedImage + ) +{ + NTSTATUS status; + PIMAGE_RESOURCE_DIRECTORY resourceDirectory; + PIMAGE_RESOURCE_DIRECTORY nameDirectory; + PIMAGE_RESOURCE_DIRECTORY languageDirectory; + PIMAGE_RESOURCE_DIRECTORY_ENTRY resourceType; + PIMAGE_RESOURCE_DIRECTORY_ENTRY resourceName; + PIMAGE_RESOURCE_DIRECTORY_ENTRY resourceLanguage; + ULONG resourceCount = 0; + ULONG resourceIndex = 0; + ULONG resourceTypeCount; + ULONG resourceNameCount; + ULONG resourceLanguageCount; + + // Get a pointer to the resource directory. + + status = PhGetMappedImageDataEntry( + MappedImage, + IMAGE_DIRECTORY_ENTRY_RESOURCE, + &Resources->DataDirectory + ); + + if (!NT_SUCCESS(status)) + return status; + + resourceDirectory = PhMappedImageRvaToVa( + MappedImage, + Resources->DataDirectory->VirtualAddress, + NULL + ); + + if (!resourceDirectory) + return STATUS_INVALID_PARAMETER; + + __try + { + PhpMappedImageProbe(MappedImage, resourceDirectory, sizeof(IMAGE_RESOURCE_DIRECTORY)); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + return GetExceptionCode(); + } + + Resources->ResourceDirectory = resourceDirectory; + + // NOTE: We can't use LdrEnumResources here because we're using an image mapped with SEC_COMMIT. + + // Do a scan to determine how many resources there are. + + resourceType = PTR_ADD_OFFSET(resourceDirectory, sizeof(IMAGE_RESOURCE_DIRECTORY)); + resourceTypeCount = resourceDirectory->NumberOfNamedEntries + resourceDirectory->NumberOfIdEntries; + + for (ULONG i = 0; i < resourceTypeCount; ++i, ++resourceType) + { + if (!resourceType->DataIsDirectory) + return STATUS_RESOURCE_TYPE_NOT_FOUND; + + nameDirectory = PTR_ADD_OFFSET(resourceDirectory, resourceType->OffsetToDirectory); + resourceName = PTR_ADD_OFFSET(nameDirectory, sizeof(IMAGE_RESOURCE_DIRECTORY)); + resourceNameCount = nameDirectory->NumberOfNamedEntries + nameDirectory->NumberOfIdEntries; + + for (ULONG j = 0; j < resourceNameCount; ++j, ++resourceName) + { + if (!resourceName->DataIsDirectory) + return STATUS_RESOURCE_NAME_NOT_FOUND; + + languageDirectory = PTR_ADD_OFFSET(resourceDirectory, resourceName->OffsetToDirectory); + resourceLanguage = PTR_ADD_OFFSET(languageDirectory, sizeof(IMAGE_RESOURCE_DIRECTORY)); + resourceLanguageCount = languageDirectory->NumberOfNamedEntries + languageDirectory->NumberOfIdEntries; + + for (ULONG k = 0; k < resourceLanguageCount; ++k, ++resourceLanguage) + { + if (resourceLanguage->DataIsDirectory) + return STATUS_RESOURCE_DATA_NOT_FOUND; + + resourceCount++; + } + } + } + + if (resourceCount == 0) + return STATUS_INVALID_IMAGE_FORMAT; + + // Allocate the number of resources. + + Resources->NumberOfEntries = resourceCount; + Resources->ResourceEntries = PhAllocate(sizeof(PH_IMAGE_RESOURCE_ENTRY) * resourceCount); + memset(Resources->ResourceEntries, 0, sizeof(PH_IMAGE_RESOURCE_ENTRY) * resourceCount); + + // Enumerate the resources adding them into our buffer. + + resourceType = PTR_ADD_OFFSET(resourceDirectory, sizeof(IMAGE_RESOURCE_DIRECTORY)); + resourceTypeCount = resourceDirectory->NumberOfNamedEntries + resourceDirectory->NumberOfIdEntries; + + for (ULONG i = 0; i < resourceTypeCount; ++i, ++resourceType) + { + if (!resourceType->DataIsDirectory) + goto CleanupExit; + + nameDirectory = PTR_ADD_OFFSET(resourceDirectory, resourceType->OffsetToDirectory); + resourceName = PTR_ADD_OFFSET(nameDirectory, sizeof(IMAGE_RESOURCE_DIRECTORY)); + resourceNameCount = nameDirectory->NumberOfNamedEntries + nameDirectory->NumberOfIdEntries; + + for (ULONG j = 0; j < resourceNameCount; ++j, ++resourceName) + { + if (!resourceName->DataIsDirectory) + goto CleanupExit; + + languageDirectory = PTR_ADD_OFFSET(resourceDirectory, resourceName->OffsetToDirectory); + resourceLanguage = PTR_ADD_OFFSET(languageDirectory, sizeof(IMAGE_RESOURCE_DIRECTORY)); + resourceLanguageCount = languageDirectory->NumberOfNamedEntries + languageDirectory->NumberOfIdEntries; + + for (ULONG k = 0; k < resourceLanguageCount; ++k, ++resourceLanguage) + { + PIMAGE_RESOURCE_DATA_ENTRY resourceData; + + if (resourceLanguage->DataIsDirectory) + goto CleanupExit; + + resourceData = PTR_ADD_OFFSET(resourceDirectory, resourceLanguage->OffsetToData); + + Resources->ResourceEntries[resourceIndex].Type = NAME_FROM_RESOURCE_ENTRY(resourceDirectory, resourceType); + Resources->ResourceEntries[resourceIndex].Name = NAME_FROM_RESOURCE_ENTRY(resourceDirectory, resourceName); + Resources->ResourceEntries[resourceIndex].Language = NAME_FROM_RESOURCE_ENTRY(resourceDirectory, resourceLanguage); + Resources->ResourceEntries[resourceIndex].Data = PTR_ADD_OFFSET(MappedImage->ViewBase, resourceData->OffsetToData); + Resources->ResourceEntries[resourceIndex++].Size = resourceData->Size; + } + } + } + +CleanupExit: + return status; +} From e11ff90b70659d600556b1d90f8e8af0aa0ce59c Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 21 Dec 2017 12:57:50 +1100 Subject: [PATCH 0649/2058] Fix space --- phlib/mapimg.c | 1 + 1 file changed, 1 insertion(+) diff --git a/phlib/mapimg.c b/phlib/mapimg.c index 24523ff12cc9..5a5ddb846056 100644 --- a/phlib/mapimg.c +++ b/phlib/mapimg.c @@ -1635,3 +1635,4 @@ NTSTATUS PhGetMappedImageResources( CleanupExit: return status; } + \ No newline at end of file From fa734e51c062962965d99a954ab3f3ee0b5d06d9 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 21 Dec 2017 13:00:52 +1100 Subject: [PATCH 0650/2058] peview: Add module resources tab --- tools/peview/include/peview.h | 7 + tools/peview/peprp.c | 11 ++ tools/peview/peview.rc | 16 +++ tools/peview/peview.vcxproj | 1 + tools/peview/peview.vcxproj.filters | 3 + tools/peview/resource.h | 2 +- tools/peview/resprp.c | 209 ++++++++++++++++++++++++++++ tools/peview/settings.c | 5 +- 8 files changed, 251 insertions(+), 3 deletions(-) create mode 100644 tools/peview/resprp.c diff --git a/tools/peview/include/peview.h b/tools/peview/include/peview.h index b3cc6ccdab5d..dc3f53bc9512 100644 --- a/tools/peview/include/peview.h +++ b/tools/peview/include/peview.h @@ -315,4 +315,11 @@ INT_PTR CALLBACK PvpPeCgfDlgProc( _In_ LPARAM lParam ); +INT_PTR CALLBACK PvpPeResourcesDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + #endif diff --git a/tools/peview/peprp.c b/tools/peview/peprp.c index c13e90a75d9d..56a469d4f2bd 100644 --- a/tools/peview/peprp.c +++ b/tools/peview/peprp.c @@ -129,6 +129,17 @@ VOID PvPeProperties( PvAddPropPage(propContext, newPage); } + // Resources page + if (NT_SUCCESS(PhGetMappedImageDataEntry(&PvMappedImage, IMAGE_DIRECTORY_ENTRY_RESOURCE, &entry)) && entry->VirtualAddress) + { + newPage = PvCreatePropPageContext( + MAKEINTRESOURCE(IDD_PERESOURCES), + PvpPeResourcesDlgProc, + NULL + ); + PvAddPropPage(propContext, newPage); + } + // CLR page if (NT_SUCCESS(PhGetMappedImageDataEntry(&PvMappedImage, IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR, &entry)) && entry->VirtualAddress && diff --git a/tools/peview/peview.rc b/tools/peview/peview.rc index c9dd19af9d33..785a4906fba3 100644 --- a/tools/peview/peview.rc +++ b/tools/peview/peview.rc @@ -116,6 +116,14 @@ BEGIN TOPMARGIN, 3 BOTTOMMARGIN, 277 END + + IDD_PERESOURCES, DIALOG + BEGIN + LEFTMARGIN, 3 + RIGHTMARGIN, 297 + TOPMARGIN, 3 + BOTTOMMARGIN, 277 + END END #endif // APSTUDIO_INVOKED @@ -221,6 +229,14 @@ BEGIN EDITTEXT IDC_SYMSEARCH,157,3,141,14,ES_AUTOHSCROLL END +IDD_PERESOURCES DIALOGEX 0, 0, 300, 280 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Resources" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,3,3,294,274 +END + ///////////////////////////////////////////////////////////////////////////// // diff --git a/tools/peview/peview.vcxproj b/tools/peview/peview.vcxproj index 9ea3c2dce967..ca02ad300e64 100644 --- a/tools/peview/peview.vcxproj +++ b/tools/peview/peview.vcxproj @@ -222,6 +222,7 @@ + diff --git a/tools/peview/peview.vcxproj.filters b/tools/peview/peview.vcxproj.filters index d81436dc0011..977007a3472b 100644 --- a/tools/peview/peview.vcxproj.filters +++ b/tools/peview/peview.vcxproj.filters @@ -60,6 +60,9 @@ Source Files + + Source Files + diff --git a/tools/peview/resource.h b/tools/peview/resource.h index 010f9d43fd37..29c9488f2611 100644 --- a/tools/peview/resource.h +++ b/tools/peview/resource.h @@ -10,6 +10,7 @@ #define IDD_PELOADCONFIG 106 #define IDD_PECFG 107 #define IDD_PESYMBOLS 108 +#define IDD_PERESOURCES 109 #define IDB_SEARCH_ACTIVE 110 #define IDB_SEARCH_INACTIVE 111 #define IDB_SEARCH_ACTIVE_BMP 112 @@ -35,7 +36,6 @@ #define IDC_SYMSEARCH 1017 #define IDC_NAME 1019 #define IDC_COMPANYNAME_LINK 1020 -#define IDC_BUTTON1 1021 #define IDC_STOP 1021 #define IDC_PROGRESS 1022 diff --git a/tools/peview/resprp.c b/tools/peview/resprp.c new file mode 100644 index 000000000000..0016ecc90fbc --- /dev/null +++ b/tools/peview/resprp.c @@ -0,0 +1,209 @@ +/* + * Process Hacker - + * PE viewer + * + * Copyright (C) 2017 dmex + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include + +PWSTR PvpGetResourceTypeString(ULONG_PTR Type) +{ + switch (Type) + { + case RT_CURSOR: + return L"RT_CURSOR"; + case RT_BITMAP: + return L"RT_BITMAP"; + case RT_ICON: + return L"RT_ICON"; + case RT_MENU: + return L"RT_MENU"; + case RT_DIALOG: + return L"RT_DIALOG"; + case RT_STRING: + return L"RT_STRING"; + case RT_FONTDIR: + return L"RT_FONTDIR"; + case RT_FONT: + return L"RT_FONT"; + case RT_ACCELERATOR: + return L"RT_ACCELERATOR"; + case RT_RCDATA: + return L"RT_RCDATA"; + case RT_MESSAGETABLE: + return L"RT_MESSAGETABLE"; + case RT_GROUP_CURSOR: + return L"RT_GROUP_CURSOR"; + case RT_GROUP_ICON: + return L"RT_GROUP_ICON"; + case RT_VERSION: + return L"RT_VERSION"; + case RT_ANICURSOR: + return L"RT_ANICURSOR"; + case RT_MANIFEST: + return L"RT_MANIFEST"; + } + + return L"ERROR"; +} + +INT_PTR CALLBACK PvpPeResourcesDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + LPPROPSHEETPAGE propSheetPage; + PPV_PROPPAGECONTEXT propPageContext; + + if (!PvPropPageDlgProcHeader(hwndDlg, uMsg, lParam, &propSheetPage, &propPageContext)) + return FALSE; + + switch (uMsg) + { + case WM_INITDIALOG: + { + NTSTATUS status; + HWND lvHandle; + PH_MAPPED_IMAGE_RESOURCES resources; + PH_IMAGE_RESOURCE_ENTRY entry; + ULONG count = 0; + ULONG i; + INT lvItemIndex; + + lvHandle = GetDlgItem(hwndDlg, IDC_LIST); + PhSetListViewStyle(lvHandle, TRUE, TRUE); + PhSetControlTheme(lvHandle, L"explorer"); + PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 40, L"#"); + PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 80, L"Name"); + PhAddListViewColumn(lvHandle, 2, 2, 2, LVCFMT_LEFT, 150, L"Type"); + PhAddListViewColumn(lvHandle, 3, 3, 3, LVCFMT_LEFT, 100, L"Language"); + PhAddListViewColumn(lvHandle, 4, 4, 4, LVCFMT_LEFT, 100, L"Size"); + PhSetExtendedListView(lvHandle); + PhLoadListViewColumnsFromSetting(L"ImageResourcesListViewColumns", lvHandle); + + status = PhGetMappedImageResources(&resources, &PvMappedImage); + + if (NT_SUCCESS(status)) + { + for (i = 0; i < resources.NumberOfEntries; i++) + { + PPH_STRING string; + WCHAR number[PH_INT32_STR_LEN_1]; + + entry = resources.ResourceEntries[i]; + + PhPrintUInt64(number, ++count); + lvItemIndex = PhAddListViewItem(lvHandle, MAXINT, number, NULL); + + if (IS_INTRESOURCE(entry.Name)) + { + PhPrintUInt32(number, (ULONG)entry.Name); + PhSetListViewSubItem(lvHandle, lvItemIndex, 1, number); + } + else + { + PIMAGE_RESOURCE_DIR_STRING_U resourceString = (PIMAGE_RESOURCE_DIR_STRING_U)entry.Name; + + string = PhCreateStringEx(resourceString->NameString, resourceString->Length * sizeof(WCHAR)); + PhSetListViewSubItem(lvHandle, lvItemIndex, 1, string->Buffer); + PhDereferenceObject(string); + } + + if (IS_INTRESOURCE(entry.Type)) + { + PhSetListViewSubItem(lvHandle, lvItemIndex, 2, PvpGetResourceTypeString(entry.Type)); + } + else + { + PIMAGE_RESOURCE_DIR_STRING_U resourceString = (PIMAGE_RESOURCE_DIR_STRING_U)entry.Type; + + string = PhCreateStringEx(resourceString->NameString, resourceString->Length * sizeof(WCHAR)); + PhSetListViewSubItem(lvHandle, lvItemIndex, 2, string->Buffer); + PhDereferenceObject(string); + } + + if (IS_INTRESOURCE(entry.Language)) + { + WCHAR localeName[LOCALE_NAME_MAX_LENGTH]; + + PhPrintUInt32(number, (ULONG)entry.Language); + + if (LCIDToLocaleName((ULONG)entry.Language, localeName, LOCALE_NAME_MAX_LENGTH, LOCALE_ALLOW_NEUTRAL_NAMES)) + PhSetListViewSubItem(lvHandle, lvItemIndex, 3, PhaFormatString(L"%s (%s)", number, localeName)->Buffer); + else + PhSetListViewSubItem(lvHandle, lvItemIndex, 3, number); + } + else + { + PIMAGE_RESOURCE_DIR_STRING_U resourceString = (PIMAGE_RESOURCE_DIR_STRING_U)entry.Language; + + string = PhCreateStringEx(resourceString->NameString, resourceString->Length * sizeof(WCHAR)); + PhSetListViewSubItem(lvHandle, lvItemIndex, 3, string->Buffer); + PhDereferenceObject(string); + } + + PhSetListViewSubItem(lvHandle, lvItemIndex, 4, PhaFormatSize(entry.Size, -1)->Buffer); + } + + if (resources.ResourceEntries) + PhFree(resources.ResourceEntries); + } + else + { + PhShowStatus(hwndDlg, L"Unable to enumerate module resources.", status, 0); + } + + ExtendedListView_SortItems(lvHandle); + + EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); + } + break; + case WM_DESTROY: + { + PhSaveListViewColumnsToSetting(L"ImageResourcesListViewColumns", GetDlgItem(hwndDlg, IDC_LIST)); + } + break; + case WM_SHOWWINDOW: + { + if (!propPageContext->LayoutInitialized) + { + PPH_LAYOUT_ITEM dialogItem; + + dialogItem = PvAddPropPageLayoutItem(hwndDlg, hwndDlg, + PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL); + PvAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_LIST), + dialogItem, PH_ANCHOR_ALL); + + PvDoPropPageLayout(hwndDlg); + + propPageContext->LayoutInitialized = TRUE; + } + } + break; + case WM_NOTIFY: + { + PvHandleListViewNotifyForCopy(lParam, GetDlgItem(hwndDlg, IDC_LIST)); + } + break; + } + + return FALSE; +} diff --git a/tools/peview/settings.c b/tools/peview/settings.c index 224075b64973..dc97ffcf2492 100644 --- a/tools/peview/settings.c +++ b/tools/peview/settings.c @@ -35,10 +35,11 @@ VOID PhAddDefaultSettings( PhpAddStringSetting(L"MainWindowPage", L"General"); PhpAddIntegerPairSetting(L"MainWindowPosition", L"150,150"); PhpAddScalableIntegerPairSetting(L"MainWindowSize", L"@96|550,580"); - PhpAddStringSetting(L"ImageCfgListViewColumns", L""); + PhpAddStringSetting(L"ImageLoadCfgListViewColumns", L""); PhpAddStringSetting(L"ImageExportsListViewColumns", L""); PhpAddStringSetting(L"ImageImportsListViewColumns", L""); - PhpAddStringSetting(L"ImageLoadCfgListViewColumns", L""); + PhpAddStringSetting(L"ImageCfgListViewColumns", L""); + PhpAddStringSetting(L"ImageResourcesListViewColumns", L""); PhpAddStringSetting(L"LibListViewColumns", L""); PhpAddStringSetting(L"PdbTreeListColumns", L""); } From 633cbebd54918d6ffd315086689b42d4f08c102d Mon Sep 17 00:00:00 2001 From: lucasg Date: Fri, 22 Dec 2017 09:54:17 +0100 Subject: [PATCH 0651/2058] Tagging Apiset memory page (#210) --- ProcessHacker/include/memprv.h | 3 ++- ProcessHacker/memlist.c | 2 ++ ProcessHacker/memprv.c | 25 +++++++++++++++++++++++++ 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/ProcessHacker/include/memprv.h b/ProcessHacker/include/memprv.h index dcd62a55fbea..1a1fc8914b56 100644 --- a/ProcessHacker/include/memprv.h +++ b/ProcessHacker/include/memprv.h @@ -22,7 +22,8 @@ typedef enum _PH_MEMORY_REGION_TYPE HeapSegmentRegion, HeapSegment32Region, CfgBitmapRegion, - CfgBitmap32Region + CfgBitmap32Region, + ApiSetMapRegion, } PH_MEMORY_REGION_TYPE; typedef struct _PH_MEMORY_ITEM diff --git a/ProcessHacker/memlist.c b/ProcessHacker/memlist.c index 2bad4c6b43bc..a182eaaee435 100644 --- a/ProcessHacker/memlist.c +++ b/ProcessHacker/memlist.c @@ -462,6 +462,8 @@ PPH_STRING PhGetMemoryRegionUseText( case CfgBitmap32Region: return PhFormatString(L"CFG Bitmap%s", type == CfgBitmap32Region ? L" 32-bit" : L""); + case ApiSetMapRegion: + return PhFormatString(L"API Set schema"); default: return PhReferenceEmptyString(); } diff --git a/ProcessHacker/memprv.c b/ProcessHacker/memprv.c index 747b9a8b9135..14f8e49e1ca2 100644 --- a/ProcessHacker/memprv.c +++ b/ProcessHacker/memprv.c @@ -534,6 +534,31 @@ NTSTATUS PhpUpdateMemoryRegionTypes( } #endif + + // ApiSet schema map + { + PVOID peb; + PVOID apiSetMap; + PROCESS_BASIC_INFORMATION basicInfo; + + + if (NT_SUCCESS(PhGetProcessBasicInformation(ProcessHandle, &basicInfo)) && basicInfo.PebBaseAddress != 0) + { + peb = basicInfo.PebBaseAddress; + + if (NT_SUCCESS(NtReadVirtualMemory( + ProcessHandle, + PTR_ADD_OFFSET(peb, FIELD_OFFSET(PEB, ApiSetMap)), + &apiSetMap, + sizeof(PVOID), + NULL + ))) + { + PhpSetMemoryRegionType(List, apiSetMap, TRUE, ApiSetMapRegion); + } + } + } + PhFree(processes); return STATUS_SUCCESS; From 5e091f2a8563b8eaf48d71659ebc1480a4d77737 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 23 Dec 2017 16:21:13 +1100 Subject: [PATCH 0652/2058] Fix ApiSetMap tagging for 32bit processes --- ProcessHacker/memlist.c | 2 +- ProcessHacker/memprv.c | 51 +++++++++++++++++++++-------------------- 2 files changed, 27 insertions(+), 26 deletions(-) diff --git a/ProcessHacker/memlist.c b/ProcessHacker/memlist.c index a182eaaee435..7eec2d32af0c 100644 --- a/ProcessHacker/memlist.c +++ b/ProcessHacker/memlist.c @@ -463,7 +463,7 @@ PPH_STRING PhGetMemoryRegionUseText( return PhFormatString(L"CFG Bitmap%s", type == CfgBitmap32Region ? L" 32-bit" : L""); case ApiSetMapRegion: - return PhFormatString(L"API Set schema"); + return PhFormatString(L"ApiSetMap"); default: return PhReferenceEmptyString(); } diff --git a/ProcessHacker/memprv.c b/ProcessHacker/memprv.c index 14f8e49e1ca2..26a01daaf4c9 100644 --- a/ProcessHacker/memprv.c +++ b/ProcessHacker/memprv.c @@ -275,11 +275,13 @@ NTSTATUS PhpUpdateMemoryRegionTypes( ULONG numberOfHeaps; PVOID processHeapsPtr; PVOID *processHeaps; + PVOID apiSetMap; ULONG i; #ifdef _WIN64 PVOID peb32; ULONG processHeapsPtr32; ULONG *processHeaps32; + ULONG apiSetMap32; #endif if (NT_SUCCESS(PhGetProcessBasicInformation(ProcessHandle, &basicInfo)) && basicInfo.PebBaseAddress != 0) @@ -308,6 +310,18 @@ NTSTATUS PhpUpdateMemoryRegionTypes( PhFree(processHeaps); } + + // ApiSet schema map + if (NT_SUCCESS(NtReadVirtualMemory( + ProcessHandle, + PTR_ADD_OFFSET(basicInfo.PebBaseAddress, FIELD_OFFSET(PEB, ApiSetMap)), + &apiSetMap, + sizeof(PVOID), + NULL + ))) + { + PhpSetMemoryRegionType(List, apiSetMap, TRUE, ApiSetMapRegion); + } } #ifdef _WIN64 @@ -338,6 +352,18 @@ NTSTATUS PhpUpdateMemoryRegionTypes( PhFree(processHeaps32); } + + // ApiSet schema map + if (NT_SUCCESS(NtReadVirtualMemory( + ProcessHandle, + PTR_ADD_OFFSET(peb32, FIELD_OFFSET(PEB32, ApiSetMap)), + &apiSetMap32, + sizeof(ULONG), + NULL + ))) + { + PhpSetMemoryRegionType(List, UlongToPtr(apiSetMap32), TRUE, ApiSetMapRegion); + } } #endif } @@ -534,31 +560,6 @@ NTSTATUS PhpUpdateMemoryRegionTypes( } #endif - - // ApiSet schema map - { - PVOID peb; - PVOID apiSetMap; - PROCESS_BASIC_INFORMATION basicInfo; - - - if (NT_SUCCESS(PhGetProcessBasicInformation(ProcessHandle, &basicInfo)) && basicInfo.PebBaseAddress != 0) - { - peb = basicInfo.PebBaseAddress; - - if (NT_SUCCESS(NtReadVirtualMemory( - ProcessHandle, - PTR_ADD_OFFSET(peb, FIELD_OFFSET(PEB, ApiSetMap)), - &apiSetMap, - sizeof(PVOID), - NULL - ))) - { - PhpSetMemoryRegionType(List, apiSetMap, TRUE, ApiSetMapRegion); - } - } - } - PhFree(processes); return STATUS_SUCCESS; From d453dd676d3671ae6e899df2ab6cc35539e9bfba Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 23 Dec 2017 17:12:17 +1100 Subject: [PATCH 0653/2058] Fix find handles regex type filter --- ProcessHacker/findobj.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/ProcessHacker/findobj.c b/ProcessHacker/findobj.c index 1e06baf50a0d..adf2b7a9471e 100644 --- a/ProcessHacker/findobj.c +++ b/ProcessHacker/findobj.c @@ -769,15 +769,10 @@ static BOOLEAN MatchTypeString( _In_ PPH_STRINGREF Input ) { - if (Context->SearchRegexCompiledExpression && Context->SearchRegexMatchData) + if (PhEqualString2(Context->SearchTypeString, L"Everything", FALSE)) return TRUE; - else - { - if (PhEqualString2(Context->SearchTypeString, L"Everything", FALSE)) - return TRUE; - return PhFindStringInStringRef(Input, &Context->SearchTypeString->sr, TRUE) != -1; - } + return PhFindStringInStringRef(Input, &Context->SearchTypeString->sr, TRUE) != -1; } typedef struct _SEARCH_HANDLE_CONTEXT From aa98c2b6a65eab5c5cd8a7ddb969251719e5ca7b Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 24 Dec 2017 03:46:59 +1100 Subject: [PATCH 0654/2058] Improve find handles window layout --- ProcessHacker/ProcessHacker.rc | 9 ++++----- ProcessHacker/findobj.c | 8 +++----- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/ProcessHacker/ProcessHacker.rc b/ProcessHacker/ProcessHacker.rc index a4ed4608a3c8..a42887027506 100644 --- a/ProcessHacker/ProcessHacker.rc +++ b/ProcessHacker/ProcessHacker.rc @@ -725,11 +725,10 @@ STYLE DS_SETFONT | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS CAPTION "Find Handles or DLLs" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN - LTEXT "Filter:",IDC_STATIC,7,7,19,8 - EDITTEXT IDC_FILTER,29,4,134,13,ES_AUTOHSCROLL - PUSHBUTTON "Find",IDOK,301,3,50,14 - CONTROL "&Regex",IDC_REGEX,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,263,6,34,10 - COMBOBOX IDC_FILTERTYPE,165,4,93,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + EDITTEXT IDC_FILTER,97,4,171,13,ES_AUTOHSCROLL + PUSHBUTTON "Find",IDOK,306,3,50,14 + CONTROL "&Regex",IDC_REGEX,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,271,6,34,10 + COMBOBOX IDC_FILTERTYPE,2,4,93,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP CONTROL "",IDC_TREELIST,"PhTreeNew",WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP | 0x2,2,19,353,212,WS_EX_CLIENTEDGE END diff --git a/ProcessHacker/findobj.c b/ProcessHacker/findobj.c index adf2b7a9471e..9b531b0fb34e 100644 --- a/ProcessHacker/findobj.c +++ b/ProcessHacker/findobj.c @@ -1120,15 +1120,15 @@ INT_PTR CALLBACK PhpFindObjectsDlgProc( context->WindowHandle = hwndDlg; context->TreeNewHandle = GetDlgItem(hwndDlg, IDC_TREELIST); - PhCreateSearchControl(hwndDlg, GetDlgItem(hwndDlg, IDC_FILTER), L"Search Handles or DLLs"); + PhCreateSearchControl(hwndDlg, GetDlgItem(hwndDlg, IDC_FILTER), L"Find Handles or DLLs"); PhpPopulateObjectTypes(GetDlgItem(hwndDlg, IDC_FILTERTYPE)); InitializeHandleObjectTree(context); PhInitializeLayoutManager(&context->LayoutManager, hwndDlg); + PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_FILTERTYPE), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_TOP); PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_FILTER), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); - PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_FILTERTYPE), NULL, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_REGEX), NULL, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDOK), NULL, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); PhAddLayoutItem(&context->LayoutManager, context->TreeNewHandle, NULL, PH_ANCHOR_ALL); @@ -1160,10 +1160,8 @@ INT_PTR CALLBACK PhpFindObjectsDlgProc( ); } - Button_SetCheck(GetDlgItem(hwndDlg, IDC_REGEX), PhGetIntegerSetting(L"FindObjRegex") ? BST_CHECKED : BST_UNCHECKED); - - SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hwndDlg, IDC_FILTER), TRUE); Edit_SetSel(GetDlgItem(hwndDlg, IDC_FILTER), 0, -1); + Button_SetCheck(GetDlgItem(hwndDlg, IDC_REGEX), PhGetIntegerSetting(L"FindObjRegex") ? BST_CHECKED : BST_UNCHECKED); } break; case WM_DESTROY: From 232579a75074ef3f0a59ef65b66b36a3c093fed7 Mon Sep 17 00:00:00 2001 From: ge0rdi Date: Wed, 27 Dec 2017 10:55:28 +0100 Subject: [PATCH 0655/2058] Sort advanced options by name initially (#213) --- ProcessHacker/options.c | 1 + 1 file changed, 1 insertion(+) diff --git a/ProcessHacker/options.c b/ProcessHacker/options.c index 31ef37cd061c..115b54a70252 100644 --- a/ProcessHacker/options.c +++ b/ProcessHacker/options.c @@ -1532,6 +1532,7 @@ INT_PTR CALLBACK PhpOptionsAdvancedDlgProc( PhSetExtendedListView(listviewHandle); PhEnumSettings(PhpOptionsSettingsCallback, listviewHandle); + ExtendedListView_SortItems(listviewHandle); } break; case WM_DESTROY: From 49753ad8cd649006ec0ae0a5e7a6d436d6cf43aa Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 27 Dec 2017 22:40:26 +1100 Subject: [PATCH 0656/2058] Revert 6ad67a6 --- ProcessHacker/runas.c | 24 ++---------------------- 1 file changed, 2 insertions(+), 22 deletions(-) diff --git a/ProcessHacker/runas.c b/ProcessHacker/runas.c index 592fd75192c2..bc53241c45c5 100644 --- a/ProcessHacker/runas.c +++ b/ProcessHacker/runas.c @@ -370,7 +370,6 @@ INT_PTR CALLBACK PhpRunAsDlgProc( { NTSTATUS status; PPH_STRING program; - PPH_STRING programEscaped; PPH_STRING userName; PPH_STRING password; PPH_STRING logonTypeString; @@ -386,25 +385,6 @@ INT_PTR CALLBACK PhpRunAsDlgProc( if (PhIsNullOrEmptyString(program)) break; - if (RtlDoesFileExists_U(program->Buffer)) - { - // Escape the path. (dmex: poor man's PathQuoteSpaces) - if (!PhStartsWithString2(program, L"\"", FALSE) && PhFindCharInString(program, 0, L' ') != -1) - programEscaped = PhaConcatStrings(3, L"\"", PhGetString(program), L"\""); - else - programEscaped = program; - } - else - { - WCHAR buffer[MAX_PATH]; - - // The user typed a name without a path so attempt to locate the executable. - if (PhSearchFilePath(program->Buffer, L".exe", buffer)) - programEscaped = PhaConcatStrings(3, L"\"", buffer, L"\""); - else - programEscaped = NULL; - } - // Fix up the user name if it doesn't have a domain. if (PhFindCharInString(userName, 0, '\\') == -1) { @@ -454,7 +434,7 @@ INT_PTR CALLBACK PhpRunAsDlgProc( PhpSplitUserName(userName->Buffer, &domainPart, &userPart); memset(&createInfo, 0, sizeof(PH_CREATE_PROCESS_AS_USER_INFO)); - createInfo.CommandLine = PhGetString(programEscaped); + createInfo.CommandLine = PhGetString(program); createInfo.UserName = PhGetString(userPart); createInfo.DomainName = PhGetString(domainPart); createInfo.Password = PhGetStringOrEmpty(password); @@ -480,7 +460,7 @@ INT_PTR CALLBACK PhpRunAsDlgProc( { status = PhExecuteRunAsCommand2( hwndDlg, - PhGetString(programEscaped), + PhGetString(program), userName->Buffer, PhGetStringOrEmpty(password), logonType, From 0e201784d4fe38e6b0a6c8a7fd7ed0bf62b9488e Mon Sep 17 00:00:00 2001 From: ge0rdi Date: Wed, 27 Dec 2017 19:07:51 +0100 Subject: [PATCH 0657/2058] Add aggregation support to more performance counters (#212) Fixes #99 --- ProcessHacker/proctree.c | 215 ++++++++++++++++++++++++++++----------- 1 file changed, 157 insertions(+), 58 deletions(-) diff --git a/ProcessHacker/proctree.c b/ProcessHacker/proctree.c index ceee54151cad..edaabb63e496 100644 --- a/ProcessHacker/proctree.c +++ b/ProcessHacker/proctree.c @@ -2152,8 +2152,12 @@ BOOLEAN NTAPI PhpProcessTreeNewCallback( getCellText->Text = node->PeakWorkingSetText->sr; break; case PHPRTLC_PRIVATEWS: - PhMoveReference(&node->PrivateWsText, PhFormatSize(processItem->WorkingSetPrivateSize, -1)); - getCellText->Text = node->PrivateWsText->sr; + { + SIZE_T value = 0; + PhpAggregateFieldIfNeeded(node, AggregateTypeIntPtr, AggregateLocationProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, WorkingSetPrivateSize), &value); + PhMoveReference(&node->PrivateWsText, PhFormatSize(value, -1)); + getCellText->Text = node->PrivateWsText->sr; + } break; case PHPRTLC_SHAREDWS: PhpUpdateProcessNodeWsCounters(node); @@ -2166,16 +2170,24 @@ BOOLEAN NTAPI PhpProcessTreeNewCallback( getCellText->Text = node->ShareableWsText->sr; break; case PHPRTLC_VIRTUALSIZE: - PhMoveReference(&node->VirtualSizeText, PhFormatSize(processItem->VmCounters.VirtualSize, -1)); - getCellText->Text = node->VirtualSizeText->sr; + { + SIZE_T value = 0; + PhpAggregateFieldIfNeeded(node, AggregateTypeIntPtr, AggregateLocationProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, VmCounters.VirtualSize), &value); + PhMoveReference(&node->VirtualSizeText, PhFormatSize(value, -1)); + getCellText->Text = node->VirtualSizeText->sr; + } break; case PHPRTLC_PEAKVIRTUALSIZE: PhMoveReference(&node->PeakVirtualSizeText, PhFormatSize(processItem->VmCounters.PeakVirtualSize, -1)); getCellText->Text = node->PeakVirtualSizeText->sr; break; case PHPRTLC_PAGEFAULTS: - PhMoveReference(&node->PageFaultsText, PhFormatUInt64(processItem->VmCounters.PageFaultCount, TRUE)); - getCellText->Text = node->PageFaultsText->sr; + { + ULONG value = 0; + PhpAggregateFieldIfNeeded(node, AggregateTypeInt32, AggregateLocationProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, VmCounters.PageFaultCount), &value); + PhMoveReference(&node->PageFaultsText, PhFormatUInt64(value, TRUE)); + getCellText->Text = node->PageFaultsText->sr; + } break; case PHPRTLC_SESSIONID: PhInitializeStringRefLongHint(&getCellText->Text, processItem->SessionIdString); @@ -2202,12 +2214,22 @@ BOOLEAN NTAPI PhpProcessTreeNewCallback( } break; case PHPRTLC_GDIHANDLES: - PhpUpdateProcessNodeGdiUserHandles(node); - PhpFormatInt32GroupDigits(node->GdiHandles, node->GdiHandlesText, sizeof(node->GdiHandlesText), &getCellText->Text); + { + PhpUpdateProcessNodeGdiUserHandles(node); + + ULONG value = 0; + PhpAggregateFieldIfNeeded(node, AggregateTypeInt32, AggregateLocationProcessNode, FIELD_OFFSET(PH_PROCESS_NODE, GdiHandles), &value); + PhpFormatInt32GroupDigits(value, node->GdiHandlesText, sizeof(node->GdiHandlesText), &getCellText->Text); + } break; case PHPRTLC_USERHANDLES: - PhpUpdateProcessNodeGdiUserHandles(node); - PhpFormatInt32GroupDigits(node->UserHandles, node->UserHandlesText, sizeof(node->UserHandlesText), &getCellText->Text); + { + PhpUpdateProcessNodeGdiUserHandles(node); + + ULONG value = 0; + PhpAggregateFieldIfNeeded(node, AggregateTypeInt32, AggregateLocationProcessNode, FIELD_OFFSET(PH_PROCESS_NODE, UserHandles), &value); + PhpFormatInt32GroupDigits(value, node->UserHandlesText, sizeof(node->UserHandlesText), &getCellText->Text); + } break; case PHPRTLC_IORORATE: { @@ -2413,87 +2435,148 @@ BOOLEAN NTAPI PhpProcessTreeNewCallback( break; case PHPRTLC_CONTEXTSWITCHES: - if (processItem->ContextSwitchesDelta.Value != 0) { - PhMoveReference(&node->ContextSwitchesText, PhFormatUInt64(processItem->ContextSwitchesDelta.Value, TRUE)); - getCellText->Text = node->ContextSwitchesText->sr; + ULONG value = 0; + PhpAggregateFieldIfNeeded(node, AggregateTypeInt32, AggregateLocationProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, ContextSwitchesDelta.Value), &value); + + if (value != 0) + { + PhMoveReference(&node->ContextSwitchesText, PhFormatUInt64(value, TRUE)); + getCellText->Text = node->ContextSwitchesText->sr; + } } break; case PHPRTLC_CONTEXTSWITCHESDELTA: - if ((LONG)processItem->ContextSwitchesDelta.Delta > 0) // the delta may be negative if a thread exits - just don't show anything + if ((LONG)processItem->ContextSwitchesDelta.Delta >= 0) // the delta may be negative if a thread exits - just don't show anything { - PhMoveReference(&node->ContextSwitchesDeltaText, PhFormatUInt64(processItem->ContextSwitchesDelta.Delta, TRUE)); - getCellText->Text = node->ContextSwitchesDeltaText->sr; + ULONG value = 0; + PhpAggregateFieldIfNeeded(node, AggregateTypeInt32, AggregateLocationProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, ContextSwitchesDelta.Delta), &value); + + if (value != 0) + { + PhMoveReference(&node->ContextSwitchesDeltaText, PhFormatUInt64(value, TRUE)); + getCellText->Text = node->ContextSwitchesDeltaText->sr; + } } break; case PHPRTLC_PAGEFAULTSDELTA: - if (processItem->PageFaultsDelta.Delta != 0) { - PhMoveReference(&node->PageFaultsDeltaText, PhFormatUInt64(processItem->PageFaultsDelta.Delta, TRUE)); - getCellText->Text = node->PageFaultsDeltaText->sr; + ULONG value = 0; + PhpAggregateFieldIfNeeded(node, AggregateTypeInt32, AggregateLocationProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, PageFaultsDelta.Delta), &value); + + if (value != 0) + { + PhMoveReference(&node->PageFaultsDeltaText, PhFormatUInt64(value, TRUE)); + getCellText->Text = node->PageFaultsDeltaText->sr; + } } break; case PHPRTLC_IOREADS: - if (processItem->IoReadCountDelta.Value != 0) { - PhMoveReference(&node->IoGroupText[0], PhFormatUInt64(processItem->IoReadCountDelta.Value, TRUE)); - getCellText->Text = node->IoGroupText[0]->sr; + ULONG64 value = 0; + PhpAggregateFieldIfNeeded(node, AggregateTypeInt64, AggregateLocationProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, IoReadCountDelta.Value), &value); + + if (value != 0) + { + PhMoveReference(&node->IoGroupText[0], PhFormatUInt64(value, TRUE)); + getCellText->Text = node->IoGroupText[0]->sr; + } } break; case PHPRTLC_IOWRITES: - if (processItem->IoWriteCountDelta.Value != 0) { - PhMoveReference(&node->IoGroupText[1], PhFormatUInt64(processItem->IoWriteCountDelta.Value, TRUE)); - getCellText->Text = node->IoGroupText[1]->sr; + ULONG64 value = 0; + PhpAggregateFieldIfNeeded(node, AggregateTypeInt64, AggregateLocationProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, IoWriteCountDelta.Value), &value); + + if (value != 0) + { + PhMoveReference(&node->IoGroupText[1], PhFormatUInt64(value, TRUE)); + getCellText->Text = node->IoGroupText[1]->sr; + } } break; case PHPRTLC_IOOTHER: - if (processItem->IoOtherCountDelta.Value != 0) { - PhMoveReference(&node->IoGroupText[2], PhFormatUInt64(processItem->IoOtherCountDelta.Value, TRUE)); - getCellText->Text = node->IoGroupText[2]->sr; + ULONG64 value = 0; + PhpAggregateFieldIfNeeded(node, AggregateTypeInt64, AggregateLocationProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, IoOtherCountDelta.Value), &value); + + if (value != 0) + { + PhMoveReference(&node->IoGroupText[2], PhFormatUInt64(value, TRUE)); + getCellText->Text = node->IoGroupText[2]->sr; + } } break; case PHPRTLC_IOREADBYTES: - if (processItem->IoReadDelta.Value != 0) { - PhMoveReference(&node->IoGroupText[3], PhFormatSize(processItem->IoReadDelta.Value, -1)); - getCellText->Text = node->IoGroupText[3]->sr; + ULONG64 value = 0; + PhpAggregateFieldIfNeeded(node, AggregateTypeInt64, AggregateLocationProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, IoReadDelta.Value), &value); + + if (value != 0) + { + PhMoveReference(&node->IoGroupText[3], PhFormatSize(value, -1)); + getCellText->Text = node->IoGroupText[3]->sr; + } } break; case PHPRTLC_IOWRITEBYTES: - if (processItem->IoWriteDelta.Value != 0) { - PhMoveReference(&node->IoGroupText[4], PhFormatSize(processItem->IoWriteDelta.Value, -1)); - getCellText->Text = node->IoGroupText[4]->sr; + ULONG64 value = 0; + PhpAggregateFieldIfNeeded(node, AggregateTypeInt64, AggregateLocationProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, IoWriteDelta.Value), &value); + + if (value != 0) + { + PhMoveReference(&node->IoGroupText[4], PhFormatSize(value, -1)); + getCellText->Text = node->IoGroupText[4]->sr; + } } break; case PHPRTLC_IOOTHERBYTES: - if (processItem->IoOtherDelta.Value != 0) { - PhMoveReference(&node->IoGroupText[5], PhFormatSize(processItem->IoOtherDelta.Value, -1)); - getCellText->Text = node->IoGroupText[5]->sr; + ULONG64 value = 0; + PhpAggregateFieldIfNeeded(node, AggregateTypeInt64, AggregateLocationProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, IoOtherDelta.Value), &value); + + if (value != 0) + { + PhMoveReference(&node->IoGroupText[5], PhFormatSize(value, -1)); + getCellText->Text = node->IoGroupText[5]->sr; + } } break; case PHPRTLC_IOREADSDELTA: - if (processItem->IoReadCountDelta.Delta != 0) { - PhMoveReference(&node->IoGroupText[6], PhFormatUInt64(processItem->IoReadCountDelta.Delta, TRUE)); - getCellText->Text = node->IoGroupText[6]->sr; + ULONG64 value = 0; + PhpAggregateFieldIfNeeded(node, AggregateTypeInt64, AggregateLocationProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, IoReadCountDelta.Delta), &value); + + if (value != 0) + { + PhMoveReference(&node->IoGroupText[6], PhFormatUInt64(value, TRUE)); + getCellText->Text = node->IoGroupText[6]->sr; + } } break; case PHPRTLC_IOWRITESDELTA: - if (processItem->IoWriteCountDelta.Delta != 0) { - PhMoveReference(&node->IoGroupText[7], PhFormatUInt64(processItem->IoWriteCountDelta.Delta, TRUE)); - getCellText->Text = node->IoGroupText[7]->sr; + ULONG64 value = 0; + PhpAggregateFieldIfNeeded(node, AggregateTypeInt64, AggregateLocationProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, IoWriteCountDelta.Delta), &value); + + if (value != 0) + { + PhMoveReference(&node->IoGroupText[7], PhFormatUInt64(value, TRUE)); + getCellText->Text = node->IoGroupText[7]->sr; + } } break; case PHPRTLC_IOOTHERDELTA: - if (processItem->IoOtherCountDelta.Delta != 0) { - PhMoveReference(&node->IoGroupText[8], PhFormatUInt64(processItem->IoOtherCountDelta.Delta, TRUE)); - getCellText->Text = node->IoGroupText[8]->sr; + ULONG64 value = 0; + PhpAggregateFieldIfNeeded(node, AggregateTypeInt64, AggregateLocationProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, IoOtherCountDelta.Delta), &value); + + if (value != 0) + { + PhMoveReference(&node->IoGroupText[8], PhFormatUInt64(value, TRUE)); + getCellText->Text = node->IoGroupText[8]->sr; + } } break; case PHPRTLC_OSCONTEXT: @@ -2521,36 +2604,52 @@ BOOLEAN NTAPI PhpProcessTreeNewCallback( } break; case PHPRTLC_PAGEDPOOL: - PhMoveReference(&node->PagedPoolText, PhFormatSize(processItem->VmCounters.QuotaPagedPoolUsage, -1)); - getCellText->Text = node->PagedPoolText->sr; + { + SIZE_T value = 0; + PhpAggregateFieldIfNeeded(node, AggregateTypeIntPtr, AggregateLocationProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, VmCounters.QuotaPagedPoolUsage), &value); + PhMoveReference(&node->PagedPoolText, PhFormatSize(value, -1)); + getCellText->Text = node->PagedPoolText->sr; + } break; case PHPRTLC_PEAKPAGEDPOOL: PhMoveReference(&node->PeakPagedPoolText, PhFormatSize(processItem->VmCounters.QuotaPeakPagedPoolUsage, -1)); getCellText->Text = node->PeakPagedPoolText->sr; break; case PHPRTLC_NONPAGEDPOOL: - PhMoveReference(&node->NonPagedPoolText, PhFormatSize(processItem->VmCounters.QuotaNonPagedPoolUsage, -1)); - getCellText->Text = node->NonPagedPoolText->sr; + { + SIZE_T value = 0; + PhpAggregateFieldIfNeeded(node, AggregateTypeIntPtr, AggregateLocationProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, VmCounters.QuotaNonPagedPoolUsage), &value); + PhMoveReference(&node->NonPagedPoolText, PhFormatSize(value, -1)); + getCellText->Text = node->NonPagedPoolText->sr; + } break; case PHPRTLC_PEAKNONPAGEDPOOL: PhMoveReference(&node->PeakNonPagedPoolText, PhFormatSize(processItem->VmCounters.QuotaPeakNonPagedPoolUsage, -1)); getCellText->Text = node->PeakNonPagedPoolText->sr; break; case PHPRTLC_MINIMUMWORKINGSET: - PhpUpdateProcessNodeQuotaLimits(node); - PhMoveReference(&node->MinimumWorkingSetText, PhFormatSize(node->MinimumWorkingSetSize, -1)); - getCellText->Text = node->MinimumWorkingSetText->sr; + { + PhpUpdateProcessNodeQuotaLimits(node); + SIZE_T value = 0; + PhpAggregateFieldIfNeeded(node, AggregateTypeIntPtr, AggregateLocationProcessNode, FIELD_OFFSET(PH_PROCESS_NODE, MinimumWorkingSetSize), &value); + PhMoveReference(&node->MinimumWorkingSetText, PhFormatSize(value, -1)); + getCellText->Text = node->MinimumWorkingSetText->sr; + } break; case PHPRTLC_MAXIMUMWORKINGSET: - PhpUpdateProcessNodeQuotaLimits(node); - PhMoveReference(&node->MaximumWorkingSetText, PhFormatSize(node->MaximumWorkingSetSize, -1)); - getCellText->Text = node->MaximumWorkingSetText->sr; + { + PhpUpdateProcessNodeQuotaLimits(node); + SIZE_T value = 0; + PhpAggregateFieldIfNeeded(node, AggregateTypeIntPtr, AggregateLocationProcessNode, FIELD_OFFSET(PH_PROCESS_NODE, MaximumWorkingSetSize), &value); + PhMoveReference(&node->MaximumWorkingSetText, PhFormatSize(value, -1)); + getCellText->Text = node->MaximumWorkingSetText->sr; + } break; case PHPRTLC_PRIVATEBYTESDELTA: { - LONG_PTR delta; + LONG_PTR delta = 0; - delta = processItem->PrivateBytesDelta.Delta; + PhpAggregateFieldIfNeeded(node, AggregateTypeIntPtr, AggregateLocationProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, PrivateBytesDelta.Delta), &delta); if (delta != 0) { From 7835a1e80e5081777371b813db07ff7d286ae75a Mon Sep 17 00:00:00 2001 From: ge0rdi Date: Wed, 27 Dec 2017 22:00:59 +0100 Subject: [PATCH 0658/2058] Alternative dbghelp.dll path (#214) Sometimes Windbg is installed in "Program Files" (instead of "Program Files (x86)"). --- ProcessHacker/appsup.c | 1 + 1 file changed, 1 insertion(+) diff --git a/ProcessHacker/appsup.c b/ProcessHacker/appsup.c index caab2c547dcd..9b389494655f 100644 --- a/ProcessHacker/appsup.c +++ b/ProcessHacker/appsup.c @@ -1019,6 +1019,7 @@ PPH_STRING PhFindDbghelpPath( { #ifdef _WIN64 { CSIDL_PROGRAM_FILESX86, L"\\Windows Kits\\10\\Debuggers\\x64\\dbghelp.dll" }, + { CSIDL_PROGRAM_FILES, L"\\Windows Kits\\10\\Debuggers\\x64\\dbghelp.dll" }, { CSIDL_PROGRAM_FILESX86, L"\\Windows Kits\\8.1\\Debuggers\\x64\\dbghelp.dll" }, { CSIDL_PROGRAM_FILESX86, L"\\Windows Kits\\8.0\\Debuggers\\x64\\dbghelp.dll" }, { CSIDL_PROGRAM_FILES, L"\\Debugging Tools for Windows (x64)\\dbghelp.dll" } From 7a066005ea3401a4a3181110c4a55d6452e047f8 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 1 Jan 2018 16:21:06 +1100 Subject: [PATCH 0659/2058] peview: update resource column order --- tools/peview/resprp.c | 80 +++++++++++++++++++++++-------------------- 1 file changed, 43 insertions(+), 37 deletions(-) diff --git a/tools/peview/resprp.c b/tools/peview/resprp.c index 0016ecc90fbc..59ac129adfae 100644 --- a/tools/peview/resprp.c +++ b/tools/peview/resprp.c @@ -22,7 +22,9 @@ #include -PWSTR PvpGetResourceTypeString(ULONG_PTR Type) +static PWSTR PvpGetResourceTypeString( + _In_ ULONG_PTR Type + ) { switch (Type) { @@ -63,6 +65,15 @@ PWSTR PvpGetResourceTypeString(ULONG_PTR Type) return L"ERROR"; } +typedef enum _PVE_RESOURCES_COLUMN_INDEX +{ + PVE_RESOURCES_COLUMN_INDEX_COUNT, + PVE_RESOURCES_COLUMN_INDEX_TYPE, + PVE_RESOURCES_COLUMN_INDEX_NAME, + PVE_RESOURCES_COLUMN_INDEX_SIZE, + PVE_RESOURCES_COLUMN_INDEX_LCID +} PVE_RESOURCES_COLUMN_INDEX; + INT_PTR CALLBACK PvpPeResourcesDlgProc( _In_ HWND hwndDlg, _In_ UINT uMsg, @@ -80,7 +91,6 @@ INT_PTR CALLBACK PvpPeResourcesDlgProc( { case WM_INITDIALOG: { - NTSTATUS status; HWND lvHandle; PH_MAPPED_IMAGE_RESOURCES resources; PH_IMAGE_RESOURCE_ENTRY entry; @@ -92,20 +102,18 @@ INT_PTR CALLBACK PvpPeResourcesDlgProc( PhSetListViewStyle(lvHandle, TRUE, TRUE); PhSetControlTheme(lvHandle, L"explorer"); PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 40, L"#"); - PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 80, L"Name"); - PhAddListViewColumn(lvHandle, 2, 2, 2, LVCFMT_LEFT, 150, L"Type"); - PhAddListViewColumn(lvHandle, 3, 3, 3, LVCFMT_LEFT, 100, L"Language"); - PhAddListViewColumn(lvHandle, 4, 4, 4, LVCFMT_LEFT, 100, L"Size"); + PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 150, L"Type"); + PhAddListViewColumn(lvHandle, 2, 2, 2, LVCFMT_LEFT, 80, L"Name"); + PhAddListViewColumn(lvHandle, 3, 3, 3, LVCFMT_LEFT, 100, L"Size"); + PhAddListViewColumn(lvHandle, 4, 4, 4, LVCFMT_LEFT, 100, L"Language"); PhSetExtendedListView(lvHandle); PhLoadListViewColumnsFromSetting(L"ImageResourcesListViewColumns", lvHandle); - status = PhGetMappedImageResources(&resources, &PvMappedImage); - - if (NT_SUCCESS(status)) + if (NT_SUCCESS(PhGetMappedImageResources(&resources, &PvMappedImage))) { for (i = 0; i < resources.NumberOfEntries; i++) { - PPH_STRING string; + PVOID string; WCHAR number[PH_INT32_STR_LEN_1]; entry = resources.ResourceEntries[i]; @@ -113,62 +121,60 @@ INT_PTR CALLBACK PvpPeResourcesDlgProc( PhPrintUInt64(number, ++count); lvItemIndex = PhAddListViewItem(lvHandle, MAXINT, number, NULL); - if (IS_INTRESOURCE(entry.Name)) + if (IS_INTRESOURCE(entry.Type)) { - PhPrintUInt32(number, (ULONG)entry.Name); - PhSetListViewSubItem(lvHandle, lvItemIndex, 1, number); + PhSetListViewSubItem(lvHandle, lvItemIndex, PVE_RESOURCES_COLUMN_INDEX_TYPE, PvpGetResourceTypeString(entry.Type)); } else { - PIMAGE_RESOURCE_DIR_STRING_U resourceString = (PIMAGE_RESOURCE_DIR_STRING_U)entry.Name; + PIMAGE_RESOURCE_DIR_STRING_U resourceString = (PIMAGE_RESOURCE_DIR_STRING_U)entry.Type; + + string = PhAllocateCopy(resourceString->NameString, resourceString->Length * sizeof(WCHAR)); - string = PhCreateStringEx(resourceString->NameString, resourceString->Length * sizeof(WCHAR)); - PhSetListViewSubItem(lvHandle, lvItemIndex, 1, string->Buffer); - PhDereferenceObject(string); + PhSetListViewSubItem(lvHandle, lvItemIndex, PVE_RESOURCES_COLUMN_INDEX_TYPE, string); + PhFree(string); } - if (IS_INTRESOURCE(entry.Type)) + if (IS_INTRESOURCE(entry.Name)) { - PhSetListViewSubItem(lvHandle, lvItemIndex, 2, PvpGetResourceTypeString(entry.Type)); + PhPrintUInt32(number, (ULONG)entry.Name); + PhSetListViewSubItem(lvHandle, lvItemIndex, PVE_RESOURCES_COLUMN_INDEX_NAME, number); } else { - PIMAGE_RESOURCE_DIR_STRING_U resourceString = (PIMAGE_RESOURCE_DIR_STRING_U)entry.Type; + PIMAGE_RESOURCE_DIR_STRING_U resourceString = (PIMAGE_RESOURCE_DIR_STRING_U)entry.Name; - string = PhCreateStringEx(resourceString->NameString, resourceString->Length * sizeof(WCHAR)); - PhSetListViewSubItem(lvHandle, lvItemIndex, 2, string->Buffer); - PhDereferenceObject(string); + string = PhAllocateCopy(resourceString->NameString, resourceString->Length * sizeof(WCHAR)); + + PhSetListViewSubItem(lvHandle, lvItemIndex, PVE_RESOURCES_COLUMN_INDEX_NAME, string); + PhFree(string); } if (IS_INTRESOURCE(entry.Language)) { - WCHAR localeName[LOCALE_NAME_MAX_LENGTH]; + WCHAR name[LOCALE_NAME_MAX_LENGTH]; PhPrintUInt32(number, (ULONG)entry.Language); - if (LCIDToLocaleName((ULONG)entry.Language, localeName, LOCALE_NAME_MAX_LENGTH, LOCALE_ALLOW_NEUTRAL_NAMES)) - PhSetListViewSubItem(lvHandle, lvItemIndex, 3, PhaFormatString(L"%s (%s)", number, localeName)->Buffer); + if (LCIDToLocaleName((ULONG)entry.Language, name, LOCALE_NAME_MAX_LENGTH, LOCALE_ALLOW_NEUTRAL_NAMES)) + PhSetListViewSubItem(lvHandle, lvItemIndex, PVE_RESOURCES_COLUMN_INDEX_LCID, PhaFormatString(L"%s (%s)", number, name)->Buffer); else - PhSetListViewSubItem(lvHandle, lvItemIndex, 3, number); + PhSetListViewSubItem(lvHandle, lvItemIndex, PVE_RESOURCES_COLUMN_INDEX_LCID, number); } else { PIMAGE_RESOURCE_DIR_STRING_U resourceString = (PIMAGE_RESOURCE_DIR_STRING_U)entry.Language; - string = PhCreateStringEx(resourceString->NameString, resourceString->Length * sizeof(WCHAR)); - PhSetListViewSubItem(lvHandle, lvItemIndex, 3, string->Buffer); - PhDereferenceObject(string); + string = PhAllocateCopy(resourceString->NameString, resourceString->Length * sizeof(WCHAR)); + + PhSetListViewSubItem(lvHandle, lvItemIndex, PVE_RESOURCES_COLUMN_INDEX_LCID, string); + PhFree(string); } - PhSetListViewSubItem(lvHandle, lvItemIndex, 4, PhaFormatSize(entry.Size, -1)->Buffer); + PhSetListViewSubItem(lvHandle, lvItemIndex, PVE_RESOURCES_COLUMN_INDEX_SIZE, PhaFormatSize(entry.Size, -1)->Buffer); } - if (resources.ResourceEntries) - PhFree(resources.ResourceEntries); - } - else - { - PhShowStatus(hwndDlg, L"Unable to enumerate module resources.", status, 0); + PhFree(resources.ResourceEntries); } ExtendedListView_SortItems(lvHandle); From 6d475b8617aa9f622b5886da712b227cbbdbab96 Mon Sep 17 00:00:00 2001 From: David Krutsko Date: Sat, 6 Jan 2018 10:22:25 -0500 Subject: [PATCH 0660/2058] Added new system information classes (#219) --- phnt/include/ntexapi.h | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/phnt/include/ntexapi.h b/phnt/include/ntexapi.h index 033d7963f31a..f39ecbd000a0 100644 --- a/phnt/include/ntexapi.h +++ b/phnt/include/ntexapi.h @@ -1393,6 +1393,8 @@ typedef enum _SYSTEM_INFORMATION_CLASS SystemProcessorIdleMaskInformation, // since REDSTONE3 SystemSecureDumpEncryptionInformation, SystemWriteConstraintInformation, // SYSTEM_WRITE_CONSTRAINT_INFORMATION + SystemKernelVaShadowInformation, // SYSTEM_KERNEL_VA_SHADOW_INFORMATION + SystemSpeculationControlInformation = 201, // SYSTEM_SPECULATION_CONTROL_INFORMATION MaxSystemInfoClass } SYSTEM_INFORMATION_CLASS; @@ -3078,6 +3080,44 @@ typedef struct _SYSTEM_WRITE_CONSTRAINT_INFORMATION ULONG Reserved; } SYSTEM_WRITE_CONSTRAINT_INFORMATION, *PSYSTEM_WRITE_CONSTRAINT_INFORMATION; +// private +typedef struct _SYSTEM_KERNEL_VA_SHADOW_INFORMATION +{ + union + { + ULONG Flags; + struct + { + ULONG KvaShadowEnabled : 1; + ULONG KvaShadowUserGlobal : 1; + ULONG KvaShadowPcid : 1; + ULONG KvaShadowInvpcid : 1; + ULONG Reserved : 28; + }; + }; +} SYSTEM_KERNEL_VA_SHADOW_INFORMATION, *PSYSTEM_KERNEL_VA_SHADOW_INFORMATION; + +// private +typedef struct _SYSTEM_SPECULATION_CONTROL_INFORMATION +{ + union + { + ULONG Flags; + struct + { + ULONG BpbEnabled : 1; + ULONG BpbDisabledSystemPolicy : 1; + ULONG BpbDisabledNoHardwareSupport : 1; + ULONG SpecCtrlEnumerated : 1; + ULONG SpecCmdEnumerated : 1; + ULONG IbrsPresent : 1; + ULONG StibpPresent : 1; + ULONG SmepPresent : 1; + ULONG Reserved : 24; + }; + }; +} SYSTEM_SPECULATION_CONTROL_INFORMATION, *PSYSTEM_SPECULATION_CONTROL_INFORMATION; + #if (PHNT_MODE != PHNT_MODE_KERNEL) NTSYSCALLAPI From f6e08a704886aa5a71c4d8d37c315a703c284ebb Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 7 Jan 2018 03:14:16 +1100 Subject: [PATCH 0661/2058] ELF image support for WSL process modules (#220) --- phlib/include/exlf.h | 420 ++++++++++++++++++++++ phlib/include/mapimg.h | 264 +++++++++----- phlib/mapexlf.c | 517 ++++++++++++++++++++++++++++ phlib/mapimg.c | 70 +++- phlib/phlib.vcxproj | 2 + phlib/phlib.vcxproj.filters | 6 + tools/peview/exlfexports.c | 126 +++++++ tools/peview/exlfimports.c | 122 +++++++ tools/peview/exlfprp.c | 390 +++++++++++++++++++++ tools/peview/include/peview.h | 37 ++ tools/peview/main.c | 34 +- tools/peview/peprp.c | 16 +- tools/peview/peview.rc | 25 ++ tools/peview/peview.vcxproj | 5 + tools/peview/peview.vcxproj.filters | 58 ++-- tools/peview/resource.h | 3 + tools/peview/settings.c | 3 + 17 files changed, 1968 insertions(+), 130 deletions(-) create mode 100644 phlib/include/exlf.h create mode 100644 phlib/mapexlf.c create mode 100644 tools/peview/exlfexports.c create mode 100644 tools/peview/exlfimports.c create mode 100644 tools/peview/exlfprp.c diff --git a/phlib/include/exlf.h b/phlib/include/exlf.h new file mode 100644 index 000000000000..736b88ee0c2a --- /dev/null +++ b/phlib/include/exlf.h @@ -0,0 +1,420 @@ +#ifndef _PH_EXLF_H +#define _PH_EXLF_H + +/* + * This file contains the required types for ELF bianires. + * + * References: + * http://man7.org/linux/man-pages/man5/elf.5.html + * http://www.skyfree.org/linux/references/ELF_Format.pdf + * https://github.com/torvalds/linux/blob/master/include/uapi/linux/elf.h + * https://chromium.googlesource.com/chromiumos/chromite/+/HEAD/lib/parseelf.py + */ + +#define EI_NIDENT 16 + +// e_ident[] indexes +#define EI_MAG0 0 +#define EI_MAG1 1 +#define EI_MAG2 2 +#define EI_MAG3 3 +#define EI_CLASS 4 +#define EI_DATA 5 +#define EI_VERSION 6 +#define EI_OSABI 7 +#define EI_PAD 8 + +// EI_MAG +#define ELFMAG0 0x7f +#define ELFMAG1 'E' +#define ELFMAG2 'L' +#define ELFMAG3 'F' +// EI_CLASS +#define ELFCLASSNONE 0 +#define ELFCLASS32 1 +#define ELFCLASS64 2 + +// EI_DATA +#define ELFDATANONE 0 +#define ELFDATA2LSB 1 +#define ELFDATA2MSB 2 + +// EI_VERSION and e_version +#define EV_NONE 0 +#define EV_CURRENT 1 + +#define ELFOSABI_NONE 0 +#define ELFOSABI_LINUX 3 + +// e_type +#define ET_NONE 0 +#define ET_REL 1 +#define ET_EXEC 2 +#define ET_DYN 3 +#define ET_CORE 4 +#define ET_LOPROC 0xff00 +#define ET_HIPROC 0xffff + +// e_machine +#define EM_386 3 +#define EM_X86_64 62 + +/* segment types */ +#define PT_NULL 0 +#define PT_LOAD 1 +#define PT_DYNAMIC 2 +#define PT_INTERP 3 +#define PT_NOTE 4 +#define PT_SHLIB 5 +#define PT_PHDR 6 +#define PT_TLS 7 /* Thread local storage segment */ +#define PT_LOOS 0x60000000 /* OS-specific */ +#define PT_HIOS 0x6fffffff /* OS-specific */ +#define PT_LOPROC 0x70000000 +#define PT_HIPROC 0x7fffffff +#define PT_GNU_EH_FRAME 0x6474e550 +#define PT_GNU_STACK (PT_LOOS + 0x474e551) + +/* permissions on sections in the program header, p_flags. */ +#define PF_NONE 0x0 +#define PF_X 0x1 +#define PF_W 0x2 +#define PF_R 0x4 + +// sh_type +#define SHT_NULL 0 // Section header table entry (unused). +#define SHT_PROGBITS 1 // Program data. +#define SHT_SYMTAB 2 // Link editing symbol table. +#define SHT_STRTAB 3 // A string table. +#define SHT_RELA 4 // Relocation entries with addends. +#define SHT_HASH 5 // A symbol hash table. +#define SHT_DYNAMIC 6 // Information for dynamic linking. +#define SHT_NOTE 7 // Information that marks file. +#define SHT_NOBITS 8 // Section occupies no space in file. +#define SHT_REL 9 // Relocation entries, no addends. +#define SHT_SHLIB 10 // Reserved, unspecified semantics. +#define SHT_DYNSYM 11 // Dynamic linking symbol table. +//#define SHT_NUM 12 +#define SHT_INIT_ARRAY 14 // Array of constructors. +#define SHT_FINI_ARRAY 15 // Array of destructors. +#define SHT_PREINIT_ARRAY 16 // Array of pre-constructors. +#define SHT_GROUP 17 // Section group. +#define SHT_SYMTAB_SHNDX 18 // Extended section indeces. +#define SHT_NUM 19 // Number of defined types. (dmex: Some tools define this as 19 and others as 12???) +#define SHT_LOOS 0x60000000 // First of OS specific semantics. +#define SHT_HIOS 0x6fffffff // Last of OS specific semantics. +#define SHT_GNU_INCREMENTAL_INPUTS 0x6fff4700 // incremental build data. +#define SHT_GNU_ATTRIBUTES 0x6ffffff5 // Object attributes. +#define SHT_GNU_HASH 0x6ffffff6 // GNU style symbol hash table. +#define SHT_GNU_LIBLIST 0x6ffffff7 // List of prelink dependencies. +#define SHT_LOPROC 0x70000000 +#define SHT_HIPROC 0x7fffffff +#define SHT_LOUSER 0x80000000 +#define SHT_HIUSER 0xffffffff +#define SHT_SUNW_verdef 0x6ffffffd // Versions defined by file. +#define SHT_SUNW_verneed 0x6ffffffe // Versions needed by file. +#define SHT_SUNW_versym 0x6fffffff // Symbol versions. + +// sh_flags +#define SHF_WRITE 0x1 /* Section contains writable data. */ +#define SHF_ALLOC 0x2 /* Section occupies memory. */ +#define SHF_EXECINSTR 0x4 /* Section contains instructions. */ +#define SHF_MERGE 0x10 /* Section may be merged. */ +#define SHF_STRINGS 0x20 /* Section contains strings. */ +#define SHF_INFO_LINK 0x40 /* sh_info holds section index. */ +#define SHF_LINK_ORDER 0x80 /* Special ordering requirements. */ +#define SHF_OS_NONCONFORMING 0x100 /* OS-specific processing required. */ +#define SHF_GROUP 0x200 /* Member of section group. */ +#define SHF_TLS 0x400 /* Section contains TLS data. */ +#define SHF_MASKOS 0x0ff00000 /* OS-specific semantics. */ +#define SHF_MASKPROC 0xf0000000 /* Processor-specific semantics. */ + +// special section indexes. +#define SHN_UNDEF 0 // An undefined symbol. +#define SHN_LORESERVE 0xff00 +#define SHN_LOPROC 0xff00 +#define SHN_HIPROC 0xff1f +#define SHN_LIVEPATCH 0xff20 +#define SHN_ABS 0xfff1 +#define SHN_COMMON 0xfff2 +#define SHN_HIRESERVE 0xffff + +// dynamic section +#define DT_NULL 0 +#define DT_NEEDED 1 +#define DT_PLTRELSZ 2 +#define DT_PLTGOT 3 +#define DT_HASH 4 +#define DT_STRTAB 5 +#define DT_SYMTAB 6 +#define DT_RELA 7 +#define DT_RELASZ 8 +#define DT_RELAENT 9 +#define DT_STRSZ 10 +#define DT_SYMENT 11 +#define DT_INIT 12 +#define DT_FINI 13 +#define DT_SONAME 14 +#define DT_RPATH 15 +#define DT_SYMBOLIC 16 +#define DT_REL 17 +#define DT_RELSZ 18 +#define DT_RELENT 19 +#define DT_PLTREL 20 +#define DT_DEBUG 21 +#define DT_TEXTREL 22 +#define DT_JMPREL 23 +#define DT_ENCODING 32 +#define OLD_DT_LOOS 0x60000000 +#define DT_LOOS 0x6000000d +#define DT_HIOS 0x6ffff000 +#define DT_VALRNGLO 0x6ffffd00 +#define DT_VALRNGHI 0x6ffffdff +#define DT_ADDRRNGLO 0x6ffffe00 +#define DT_ADDRRNGHI 0x6ffffeff +#define DT_VERSYM 0x6ffffff0 +#define DT_RELACOUNT 0x6ffffff9 +#define DT_RELCOUNT 0x6ffffffa +#define DT_FLAGS_1 0x6ffffffb +#define DT_VERDEF 0x6ffffffc +#define DT_VERDEFNUM 0x6ffffffd +#define DT_VERNEED 0x6ffffffe +#define DT_VERNEEDNUM 0x6fffffff +#define OLD_DT_HIOS 0x6fffffff +#define DT_LOPROC 0x70000000 +#define DT_HIPROC 0x7fffffff + +// symbol table section +#define STB_LOCAL 0 +#define STB_GLOBAL 1 +#define STB_WEAK 2 + +#define STT_NOTYPE 0 +#define STT_OBJECT 1 +#define STT_FUNC 2 +#define STT_SECTION 3 +#define STT_FILE 4 +#define STT_COMMON 5 +#define STT_TLS 6 +#define STT_GNU_IFUNC 10 +#define STT_LOOS 10 +#define STT_HIOS 12 +#define STT_LOPROC 13 +#define STT_HIPROC 15 + +#define STV_DEFAULT 0 /* Default symbol visibility rules */ +#define STV_INTERNAL 1 /* Processor specific hidden class */ +#define STV_HIDDEN 2 /* Sym unavailable in other modules */ +#define STV_PROTECTED 3 /* Not preemptible, not exported */ + +#define ELF_ST_BIND(x) ((x) >> 4) +#define ELF_ST_TYPE(x) ((x) & 0xF) +#define ELF_ST_VISIBILITY(x) ((x) & 0x03) + +#define ELF32_ST_BIND(x) ELF_ST_BIND(x) +#define ELF32_ST_TYPE(x) ELF_ST_TYPE(x) +#define ELF32_ST_VIS(a) ELF_ST_VISIBILITY(a) +#define ELF64_ST_BIND(x) ELF_ST_BIND(x) +#define ELF64_ST_TYPE(x) ELF_ST_TYPE(x) +#define ELF64_ST_VIS(a) ELF_ST_VISIBILITY(a) + +// Non-standard ELF definitions (dmex) + +#define IMAGE_ELF_SIGNATURE 0x457f // "\x7fELF" +#define ELFMAG ((BYTE[4]){ELFMAG0,ELFMAG1,ELFMAG2,ELFMAG3}) + +typedef struct _ELF_IMAGE_HEADER +{ + union + { + unsigned char e_ident[EI_NIDENT]; + struct + { + unsigned char MagicNumber[4]; + unsigned char Class; + unsigned char Data; + unsigned char Version; + unsigned char Abi; + unsigned char AbiVersion; + unsigned char Unused[7]; + }; + }; + unsigned short e_type; + unsigned short e_machine; + unsigned int e_version; + //union { + // PELF_IMAGE_HEADER32 Headers32; + // PELF_IMAGE_HEADER64 Headers64; + //}; +} ELF_IMAGE_HEADER, *PELF_IMAGE_HEADER; + +typedef struct _ELF_IMAGE_HEADER32 +{ + // ELF_IMAGE_HEADER Header; + unsigned int e_entry; // Entry point virtual address. + unsigned int e_phoff; // Program header table file offset. + unsigned int e_shoff; // Section header table file offset. + unsigned int e_flags; // Processor-specific flags. + unsigned short e_ehsize; // ELF header size in bytes. + unsigned short e_phentsize; // Program header table entry size. + unsigned short e_phnum; // Program header table entry count. + unsigned short e_shentsize; // Section header table entry size. + unsigned short e_shnum; // Section header table entry count. + unsigned short e_shstrndx; // Section header string table index. +} ELF_IMAGE_HEADER32, *PELF_IMAGE_HEADER32; + +typedef struct _ELF_IMAGE_HEADER64 +{ + // ELF_IMAGE_HEADER Header; + unsigned long long e_entry; // Entry point virtual address. + unsigned long long e_phoff; // Program header table file offset. + unsigned long long e_shoff; // Section header table file offset. + unsigned int e_flags; // Processor-specific flags. + unsigned short e_ehsize; // ELF header size in bytes. + unsigned short e_phentsize; // Program header table entry size. + unsigned short e_phnum; // Program header table entry count. + unsigned short e_shentsize; // Section header table entry size. + unsigned short e_shnum; // Section header table entry count. + unsigned short e_shstrndx; // Section header string table index. +} ELF_IMAGE_HEADER64, *PELF_IMAGE_HEADER64; + +typedef struct _ELF32_IMAGE_SEGMENT_HEADER +{ + unsigned int p_type; // Segment type. + unsigned int p_offset; // Segment file offset. + unsigned int p_vaddr; // Segment virtual address. + unsigned int p_paddr; // Segment physical address. + unsigned int p_filesz; // Segment size in file. + unsigned int p_memsz; // Segment size in memory. + unsigned int p_flags; // Segment flags. + unsigned int p_align; // Segment alignment. +} ELF32_IMAGE_SEGMENT_HEADER; + +typedef struct _ELF64_IMAGE_SEGMENT_HEADER +{ + unsigned int p_type; // Segment type. + unsigned int p_flags; // Segment flags. + unsigned long long p_offset; // Segment file offset. + unsigned long long p_vaddr; // Segment virtual address. + unsigned long long p_paddr; // Segment physical address. + unsigned long long p_filesz; // Segment size in file. + unsigned long long p_memsz; // Segment size in memory. + unsigned long long p_align; // Segment alignment. +} ELF64_IMAGE_SEGMENT_HEADER, *PELF64_IMAGE_SEGMENT_HEADER; + +#define IMAGE_FIRST_ELF64_SEGMENT(MappedWslImage) \ + ((PELF64_IMAGE_SEGMENT_HEADER)PTR_ADD_OFFSET(MappedWslImage->Header, MappedWslImage->Headers64->e_phoff)) + +#define IMAGE_ELF64_SEGMENT_BY_INDEX(SegmentHeader, Index) \ + ((PELF64_IMAGE_SEGMENT_HEADER)PTR_ADD_OFFSET(SegmentHeader, sizeof(ELF64_IMAGE_SEGMENT_HEADER) * Index)) + //((PELF64_IMAGE_SEGMENT_HEADER)&SegmentHeaderTable[Index]) + +typedef struct _ELF32_IMAGE_SECTION_HEADER +{ + unsigned int sh_name; + unsigned int sh_type; + unsigned int sh_flags; + unsigned int sh_addr; + unsigned int sh_offset; + unsigned int sh_size; + unsigned int sh_link; + unsigned int sh_info; + unsigned int sh_addralign; + unsigned int sh_entsize; +} ELF32_IMAGE_SECTION_HEADER; + +typedef struct _ELF64_IMAGE_SECTION_HEADER +{ + unsigned int sh_name; /* Section name, index in string tbl */ + unsigned int sh_type; /* Type of section */ + unsigned long long sh_flags; /* Miscellaneous section attributes */ + unsigned long long sh_addr; /* Section virtual addr at execution */ + unsigned long long sh_offset; /* Section file offset */ + unsigned long long sh_size; /* Size of section in bytes */ + unsigned int sh_link; /* Index of another section */ + unsigned int sh_info; /* Additional section information */ + unsigned long long sh_addralign; /* Section alignment */ + unsigned long long sh_entsize; /* Entry size if section holds table */ +} ELF64_IMAGE_SECTION_HEADER, *PELF64_IMAGE_SECTION_HEADER; + +#define IMAGE_FIRST_ELF64_SECTION(MappedWslImage) \ + ((PELF64_IMAGE_SECTION_HEADER)PTR_ADD_OFFSET(MappedWslImage->Header, MappedWslImage->Headers64->e_shoff)) + +#define IMAGE_ELF64_SECTION_BY_INDEX(SectionHeader, Index) \ + ((PELF64_IMAGE_SECTION_HEADER)PTR_ADD_OFFSET(SectionHeader, sizeof(ELF64_IMAGE_SECTION_HEADER) * Index)) + // ((PELF64_IMAGE_SECTION_HEADER)&SectionHeaderTable[Index]) + +// ELF dynamic entries + +typedef struct _ELF32_IMAGE_DYNAMIC_ENTRY // Elf32_Dyn +{ + int d_tag; + unsigned int d_val; +} ELF32_IMAGE_DYNAMIC_ENTRY, *PELF32_IMAGE_DYNAMIC_ENTRY; + +typedef struct _ELF64_IMAGE_DYNAMIC_ENTRY // Elf64_Dyn +{ + long long d_tag; + unsigned long long d_val; +} ELF64_IMAGE_DYNAMIC_ENTRY, *PELF64_IMAGE_DYNAMIC_ENTRY; + +// ELF symbol entries + +typedef struct _ELF_IMAGE_SYMBOL_ENTRY // Elf_Sym +{ + unsigned int st_name; + unsigned char st_info; + unsigned char st_other; + unsigned short st_shndx; + unsigned long long st_value; + unsigned long long st_size; +} ELF_IMAGE_SYMBOL_ENTRY, *PELF_IMAGE_SYMBOL_ENTRY; + +// ELF version entires + +typedef struct _ELF_VERSION_TABLE // Elf_Versym +{ + unsigned short vs_vers; +} ELF_VERSION_TABLE, *PELF_VERSION_TABLE; + +typedef struct +{ + unsigned short vd_version; + unsigned short vd_flags; // flags (VER_FLG_*). + unsigned short vd_ndx; // version index. + unsigned short vd_cnt; // number of verdaux entries. + unsigned int vd_hash; // hash of name. + unsigned int vd_aux; // offset to verdaux entries. + unsigned int vd_next; // offset to next verdef. +} Elf_Verdef; + +typedef struct +{ + unsigned int vda_name; /* string table offset of name */ + unsigned int vda_next; /* offset to verdaux */ +} Elf_Verdaux; + +// vn_version +#define VER_NEED_NONE 0 /* No version */ +#define VER_NEED_CURRENT 1 /* Current version */ +#define VER_NEED_NUM 2 /* Given version number */ + +typedef struct _ELF_VERSION_NEED // Elf_Verneed +{ + unsigned short vn_version; + unsigned short vn_cnt; + unsigned int vn_file; + unsigned int vn_aux; + unsigned int vn_next; +} ELF_VERSION_NEED, *PELF_VERSION_NEED; + +typedef struct _ELF_VERSION_AUX // Elf_Vernaux +{ + unsigned int vna_hash; // dependency name hash. + unsigned short vna_flags; // flags (VER_FLG_*). + unsigned short vna_other; + unsigned int vna_name; + unsigned int vna_next; +} ELF_VERSION_AUX, *PELF_VERSION_AUX; + +#endif diff --git a/phlib/include/mapimg.h b/phlib/include/mapimg.h index 88cdb031ab60..95f9a90faf45 100644 --- a/phlib/include/mapimg.h +++ b/phlib/include/mapimg.h @@ -5,19 +5,38 @@ extern "C" { #endif +#include + typedef struct _PH_MAPPED_IMAGE { + USHORT Signature; PVOID ViewBase; SIZE_T Size; - union { - PIMAGE_NT_HEADERS32 NtHeaders32; - PIMAGE_NT_HEADERS NtHeaders; + union + { + struct + { + union + { + PIMAGE_NT_HEADERS32 NtHeaders32; + PIMAGE_NT_HEADERS NtHeaders; + }; + + ULONG NumberOfSections; + PIMAGE_SECTION_HEADER Sections; + USHORT Magic; + }; + struct + { + struct _ELF_IMAGE_HEADER *Header; + union + { + struct _ELF_IMAGE_HEADER32 *Headers32; + struct _ELF_IMAGE_HEADER64 *Headers64; + }; + }; }; - - ULONG NumberOfSections; - PIMAGE_SECTION_HEADER Sections; - USHORT Magic; } PH_MAPPED_IMAGE, *PPH_MAPPED_IMAGE; PHLIBAPI @@ -39,6 +58,16 @@ PhLoadMappedImage( _Out_ PPH_MAPPED_IMAGE MappedImage ); +PHLIBAPI +NTSTATUS +NTAPI +PhLoadMappedImageEx( + _In_opt_ PWSTR FileName, + _In_opt_ HANDLE FileHandle, + _In_ BOOLEAN ReadOnly, + _Out_ PPH_MAPPED_IMAGE MappedImage + ); + PHLIBAPI NTSTATUS NTAPI @@ -285,6 +314,101 @@ PhCheckSumMappedImage( _In_ PPH_MAPPED_IMAGE MappedImage ); +typedef struct _IMAGE_CFG_ENTRY +{ + ULONG Rva; + struct + { + BOOLEAN SuppressedCall : 1; + BOOLEAN Reserved : 7; + }; +} IMAGE_CFG_ENTRY, *PIMAGE_CFG_ENTRY; + +typedef struct _PH_MAPPED_IMAGE_CFG +{ + PPH_MAPPED_IMAGE MappedImage; + ULONG EntrySize; + + union + { + ULONG GuardFlags; + struct + { + ULONG CfgInstrumented : 1; + ULONG WriteIntegrityChecks : 1; + ULONG CfgFunctionTablePresent : 1; + ULONG SecurityCookieUnused : 1; + ULONG ProtectDelayLoadedIat : 1; + ULONG DelayLoadInDidatSection : 1; + ULONG HasExportSuppressionInfos : 1; + ULONG EnableExportSuppression : 1; + ULONG CfgLongJumpTablePresent : 1; + ULONG Spare : 23; + }; + }; + + PULONGLONG GuardFunctionTable; + ULONGLONG NumberOfGuardFunctionEntries; + + PULONGLONG GuardAdressIatTable; // not currently used + ULONGLONG NumberOfGuardAdressIatEntries; + + PULONGLONG GuardLongJumpTable; // not currently used + ULONGLONG NumberOfGuardLongJumpEntries; +} PH_MAPPED_IMAGE_CFG, *PPH_MAPPED_IMAGE_CFG; + +typedef enum _CFG_ENTRY_TYPE +{ + ControlFlowGuardFunction, + ControlFlowGuardtakenIatEntry, + ControlFlowGuardLongJump +} CFG_ENTRY_TYPE; + +PHLIBAPI +NTSTATUS +NTAPI +PhGetMappedImageCfg( + _Out_ PPH_MAPPED_IMAGE_CFG CfgConfig, + _In_ PPH_MAPPED_IMAGE MappedImage + ); + +PHLIBAPI +NTSTATUS +NTAPI +PhGetMappedImageCfgEntry( + _In_ PPH_MAPPED_IMAGE_CFG CfgConfig, + _In_ ULONGLONG Index, + _In_ CFG_ENTRY_TYPE Type, + _Out_ PIMAGE_CFG_ENTRY Entry + ); + +typedef struct _PH_IMAGE_RESOURCE_ENTRY +{ + ULONG_PTR Type; + ULONG_PTR Name; + ULONG_PTR Language; + ULONG Size; + PVOID Data; +} PH_IMAGE_RESOURCE_ENTRY, *PPH_IMAGE_RESOURCE_ENTRY; + +typedef struct _PH_MAPPED_IMAGE_RESOURCES +{ + PPH_MAPPED_IMAGE MappedImage; + PIMAGE_DATA_DIRECTORY DataDirectory; + PIMAGE_RESOURCE_DIRECTORY ResourceDirectory; + + ULONG NumberOfEntries; + PPH_IMAGE_RESOURCE_ENTRY ResourceEntries; +} PH_MAPPED_IMAGE_RESOURCES, *PPH_MAPPED_IMAGE_RESOURCES; + +PHLIBAPI +NTSTATUS +NTAPI +PhGetMappedImageResources( + _Out_ PPH_MAPPED_IMAGE_RESOURCES Resources, + _In_ PPH_MAPPED_IMAGE MappedImage + ); + // maplib struct _PH_MAPPED_ARCHIVE; @@ -386,99 +510,61 @@ PhGetMappedArchiveImportEntry( _Out_ PPH_MAPPED_ARCHIVE_IMPORT_ENTRY Entry ); -typedef struct _IMAGE_CFG_ENTRY -{ - ULONG Rva; - struct - { - BOOLEAN SuppressedCall : 1; - BOOLEAN Reserved : 7; - }; -} IMAGE_CFG_ENTRY, *PIMAGE_CFG_ENTRY; +// ELF binary support -typedef struct _PH_MAPPED_IMAGE_CFG +NTSTATUS PhInitializeMappedWslImage( + _Out_ PPH_MAPPED_IMAGE MappedWslImage, + _In_ PVOID ViewBase, + _In_ SIZE_T Size + ); + +ULONG64 PhGetMappedWslImageBaseAddress( + _In_ PPH_MAPPED_IMAGE MappedWslImage + ); + +typedef struct _PH_ELF_IMAGE_SECTION { - PPH_MAPPED_IMAGE MappedImage; - ULONG EntrySize; + UINT32 Type; + ULONGLONG Flags; + ULONGLONG Address; + ULONGLONG Offset; + ULONGLONG Size; + WCHAR Name[MAX_PATH]; +} PH_ELF_IMAGE_SECTION, *PPH_ELF_IMAGE_SECTION; + +BOOLEAN PhGetMappedWslImageSections( + _In_ PPH_MAPPED_IMAGE MappedWslImage, + _Out_ USHORT *NumberOfSections, + _Out_ PPH_ELF_IMAGE_SECTION *ImageSections + ); +typedef struct _PH_ELF_IMAGE_SYMBOL_ENTRY +{ union { - ULONG GuardFlags; + BOOLEAN Flags; struct { - ULONG CfgInstrumented : 1; - ULONG WriteIntegrityChecks : 1; - ULONG CfgFunctionTablePresent : 1; - ULONG SecurityCookieUnused : 1; - ULONG ProtectDelayLoadedIat : 1; - ULONG DelayLoadInDidatSection : 1; - ULONG HasExportSuppressionInfos : 1; - ULONG EnableExportSuppression : 1; - ULONG CfgLongJumpTablePresent : 1; - ULONG Spare : 23; + BOOLEAN ImportSymbol : 1; + BOOLEAN ExportSymbol : 1; + BOOLEAN UnknownSymbol : 1; + BOOLEAN Spare : 5; }; }; - - PULONGLONG GuardFunctionTable; - ULONGLONG NumberOfGuardFunctionEntries; - - PULONGLONG GuardAdressIatTable; // not currently used - ULONGLONG NumberOfGuardAdressIatEntries; - - PULONGLONG GuardLongJumpTable; // not currently used - ULONGLONG NumberOfGuardLongJumpEntries; -} PH_MAPPED_IMAGE_CFG, *PPH_MAPPED_IMAGE_CFG; - -typedef enum _CFG_ENTRY_TYPE -{ - ControlFlowGuardFunction, - ControlFlowGuardtakenIatEntry, - ControlFlowGuardLongJump -} CFG_ENTRY_TYPE; - -PHLIBAPI -NTSTATUS -NTAPI -PhGetMappedImageCfg( - _Out_ PPH_MAPPED_IMAGE_CFG CfgConfig, - _In_ PPH_MAPPED_IMAGE MappedImage - ); - -PHLIBAPI -NTSTATUS -NTAPI -PhGetMappedImageCfgEntry( - _In_ PPH_MAPPED_IMAGE_CFG CfgConfig, - _In_ ULONGLONG Index, - _In_ CFG_ENTRY_TYPE Type, - _Out_ PIMAGE_CFG_ENTRY Entry + UCHAR TypeInfo; + ULONGLONG Address; + ULONGLONG Size; + WCHAR Name[0x80]; + WCHAR Module[0x80]; +} PH_ELF_IMAGE_SYMBOL_ENTRY, *PPH_ELF_IMAGE_SYMBOL_ENTRY; + +BOOLEAN PhGetMappedWslImageSymbols( + _In_ PPH_MAPPED_IMAGE MappedWslImage, + _Out_ PPH_LIST *ImageSymbols ); -typedef struct _PH_IMAGE_RESOURCE_ENTRY -{ - ULONG_PTR Type; - ULONG_PTR Name; - ULONG_PTR Language; - ULONG Size; - PVOID Data; -} PH_IMAGE_RESOURCE_ENTRY, *PPH_IMAGE_RESOURCE_ENTRY; - -typedef struct _PH_MAPPED_IMAGE_RESOURCES -{ - PPH_MAPPED_IMAGE MappedImage; - PIMAGE_DATA_DIRECTORY DataDirectory; - PIMAGE_RESOURCE_DIRECTORY ResourceDirectory; - - ULONG NumberOfEntries; - PPH_IMAGE_RESOURCE_ENTRY ResourceEntries; -} PH_MAPPED_IMAGE_RESOURCES, *PPH_MAPPED_IMAGE_RESOURCES; - -PHLIBAPI -NTSTATUS -NTAPI -PhGetMappedImageResources( - _Out_ PPH_MAPPED_IMAGE_RESOURCES Resources, - _In_ PPH_MAPPED_IMAGE MappedImage +VOID PhFreeMappedWslImageSymbols( + _In_ PPH_LIST ImageSymbols ); #ifdef __cplusplus diff --git a/phlib/mapexlf.c b/phlib/mapexlf.c new file mode 100644 index 000000000000..796d517f9e82 --- /dev/null +++ b/phlib/mapexlf.c @@ -0,0 +1,517 @@ +/* + * Process Hacker - + * ELF library support + * + * Copyright (C) 2017 dmex + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include +#include + +NTSTATUS PhInitializeMappedWslImage( + _Out_ PPH_MAPPED_IMAGE MappedWslImage, + _In_ PVOID ViewBase, + _In_ SIZE_T Size + ) +{ + MappedWslImage->ViewBase = ViewBase; + MappedWslImage->Size = Size; + MappedWslImage->Header = (PELF_IMAGE_HEADER)ViewBase; + + __try + { + PhProbeAddress( + MappedWslImage->Header, + sizeof(ELF_IMAGE_HEADER), + MappedWslImage->ViewBase, + MappedWslImage->Size, + 1 + ); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + return GetExceptionCode(); + } + + // Check the magic number. + + if (!RtlEqualMemory(MappedWslImage->Header->e_ident, ELFMAG, sizeof(ELFMAG))) + return STATUS_FAIL_CHECK; + + // Check the class type. + + if (MappedWslImage->Header->e_ident[EI_CLASS] == ELFCLASS64) + { + MappedWslImage->Headers64 = PTR_ADD_OFFSET(MappedWslImage->Header, sizeof(ELF_IMAGE_HEADER)); + + __try + { + PhProbeAddress( + MappedWslImage->Headers64, + sizeof(ELF64_IMAGE_SECTION_HEADER), + MappedWslImage->ViewBase, + MappedWslImage->Size, + 1 + ); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + return GetExceptionCode(); + } + } + else + { + // TODO: Add 32bit ELF support. + return STATUS_IMAGE_SUBSYSTEM_NOT_PRESENT; + } + + if (MappedWslImage->Headers64->e_phentsize != sizeof(ELF64_IMAGE_SEGMENT_HEADER)) + return STATUS_FAIL_CHECK; + if (MappedWslImage->Headers64->e_shentsize != sizeof(ELF64_IMAGE_SECTION_HEADER)) + return STATUS_FAIL_CHECK; + + return STATUS_SUCCESS; +} + +PELF64_IMAGE_SEGMENT_HEADER PhGetMappedWslImageSegment( + _In_ PPH_MAPPED_IMAGE MappedWslImage, + _In_ USHORT Index + ) +{ + return IMAGE_ELF64_SEGMENT_BY_INDEX(IMAGE_FIRST_ELF64_SEGMENT(MappedWslImage), Index); +} + +PELF64_IMAGE_SEGMENT_HEADER PhGetWslImageSegmentByType( + _In_ PPH_MAPPED_IMAGE MappedWslImage, + _In_opt_ USHORT Type + ) +{ + PELF64_IMAGE_SEGMENT_HEADER segmentHeader; + USHORT i; + + segmentHeader = IMAGE_FIRST_ELF64_SEGMENT(MappedWslImage); + + for (i = 0; i < MappedWslImage->Headers64->e_phnum; i++) + { + if (segmentHeader[i].p_type == Type) + return segmentHeader; + } + + return NULL; +} + +PVOID PhGetMappedWslImageSectionData( + _In_ PPH_MAPPED_IMAGE MappedWslImage, + _In_opt_ PSTR Name, + _In_opt_ USHORT Index + ) +{ + if (Name) + { + PELF64_IMAGE_SECTION_HEADER sectionHeader; + PELF64_IMAGE_SECTION_HEADER stringSection; + PELF64_IMAGE_SECTION_HEADER section; + PVOID stringTable; + USHORT i; + + sectionHeader = IMAGE_FIRST_ELF64_SECTION(MappedWslImage); + stringSection = IMAGE_ELF64_SECTION_BY_INDEX(sectionHeader, MappedWslImage->Headers64->e_shstrndx); + stringTable = PTR_ADD_OFFSET(MappedWslImage->Header, stringSection->sh_offset); + + for (i = 0; i < MappedWslImage->Headers64->e_shnum; i++) + { + section = IMAGE_ELF64_SECTION_BY_INDEX(sectionHeader, i); + + if (strcmp(Name, PTR_ADD_OFFSET(stringTable, section->sh_name)) == 0) + { + return PTR_ADD_OFFSET(MappedWslImage->Header, section->sh_offset); + } + } + + return NULL; + } + else + { + PELF64_IMAGE_SECTION_HEADER sectionHeader; + PELF64_IMAGE_SECTION_HEADER section; + + sectionHeader = IMAGE_FIRST_ELF64_SECTION(MappedWslImage); + section = IMAGE_ELF64_SECTION_BY_INDEX(sectionHeader, Index); + + return PTR_ADD_OFFSET(MappedWslImage->Header, section->sh_offset); + } +} + +PVOID PhGetMappedWslImageSectionDataByType( + _In_ PPH_MAPPED_IMAGE MappedWslImage, + _In_ UINT32 Type + ) +{ + PELF64_IMAGE_SECTION_HEADER sectionHeader; + PELF64_IMAGE_SECTION_HEADER section; + USHORT i; + + sectionHeader = IMAGE_FIRST_ELF64_SECTION(MappedWslImage); + + for (i = 0; i < MappedWslImage->Headers64->e_shnum; i++) + { + section = IMAGE_ELF64_SECTION_BY_INDEX(sectionHeader, i); + + if (section->sh_type == Type) + { + return PTR_ADD_OFFSET(MappedWslImage->Header, section->sh_offset); + } + } + + return NULL; +} + +PELF64_IMAGE_SECTION_HEADER PhGetMappedWslImageSectionByIndex( + _In_ PPH_MAPPED_IMAGE MappedWslImage, + _In_ USHORT Index + ) +{ + return IMAGE_ELF64_SECTION_BY_INDEX(IMAGE_FIRST_ELF64_SECTION(MappedWslImage), Index); +} + +PELF64_IMAGE_SECTION_HEADER PhGetMappedWslImageSectionByType( + _In_ PPH_MAPPED_IMAGE MappedWslImage, + _In_ UINT32 Type + ) +{ + PELF64_IMAGE_SECTION_HEADER sectionHeader; + PELF64_IMAGE_SECTION_HEADER section; + USHORT i; + + sectionHeader = IMAGE_FIRST_ELF64_SECTION(MappedWslImage); + + for (i = 0; i < MappedWslImage->Headers64->e_shnum; i++) + { + section = IMAGE_ELF64_SECTION_BY_INDEX(sectionHeader, i); + + if (section->sh_type == Type) + return section; + } + + return NULL; +} + +// TODO: Check this is actually correct. +// https://stackoverflow.com/questions/18296276/base-address-of-elf +ULONG64 PhGetMappedWslImageBaseAddress( + _In_ PPH_MAPPED_IMAGE MappedWslImage + ) +{ + ULONG64 baseAddress = MAXULONG64; + PELF64_IMAGE_SEGMENT_HEADER segment; + USHORT i; + + segment = IMAGE_FIRST_ELF64_SEGMENT(MappedWslImage); + + for (i = 0; i < MappedWslImage->Headers64->e_phnum; i++) + { + if (segment[i].p_type == PT_LOAD) + { + if (segment[i].p_paddr < baseAddress) + baseAddress = segment[i].p_paddr; + } + } + + if (baseAddress == MAXULONG64) + baseAddress = 0; + + return baseAddress; +} + +BOOLEAN PhGetMappedWslImageSections( + _In_ PPH_MAPPED_IMAGE MappedWslImage, + _Out_ USHORT *NumberOfSections, + _Out_ PPH_ELF_IMAGE_SECTION *ImageSections + ) +{ + USHORT count; + USHORT i; + PPH_ELF_IMAGE_SECTION sections; + PELF64_IMAGE_SECTION_HEADER sectionHeader; + PELF64_IMAGE_SECTION_HEADER stringSection; + PVOID stringTableAddress; + + count = MappedWslImage->Headers64->e_shnum; + sections = PhAllocate(sizeof(PH_ELF_IMAGE_SECTION) * count); + memset(sections, 0, sizeof(PH_ELF_IMAGE_SECTION) * count); + + // Get the first section. + sectionHeader = IMAGE_FIRST_ELF64_SECTION(MappedWslImage); + + // Get the string section. + stringSection = IMAGE_ELF64_SECTION_BY_INDEX(sectionHeader, MappedWslImage->Headers64->e_shstrndx); + + // Get the string table (The string table is an array of null terminated strings). + stringTableAddress = PTR_ADD_OFFSET(MappedWslImage->Header, stringSection->sh_offset); + + // Enumerate the sections. + for (i = 0; i < count; i++) + { + sections[i].Type = sectionHeader[i].sh_type; + sections[i].Flags = sectionHeader[i].sh_flags; + sections[i].Address = sectionHeader[i].sh_addr; + sections[i].Offset = sectionHeader[i].sh_offset; + sections[i].Size = sectionHeader[i].sh_size; + + if (sectionHeader[i].sh_name) + { + // Get the section name from the ELF string table and convert to unicode. + PhCopyStringZFromBytes( + PTR_ADD_OFFSET(stringTableAddress, sectionHeader[i].sh_name), + -1, + sections[i].Name, + sizeof(sections[i].Name), + NULL + ); + } + } + + *NumberOfSections = count; + *ImageSections = sections; + + return TRUE; +} + +typedef struct _PH_ELF_VERSION_RECORD +{ + USHORT Version; + PSTR Name; + PSTR FileName; +} PH_ELF_VERSION_RECORD, *PPH_ELF_VERSION_RECORD; + +static PPH_LIST PhpParseMappedWslImageVersionRecords( + _In_ PPH_MAPPED_IMAGE MappedWslImage, + _In_ PVOID SymbolStringTable + ) +{ + PPH_LIST recordsList; + PELF_VERSION_NEED version; + + if (!(version = PhGetMappedWslImageSectionDataByType(MappedWslImage, SHT_SUNW_verneed))) + return NULL; + + recordsList = PhCreateList(10); + + while (TRUE) + { + PELF_VERSION_AUX versionAux = PTR_ADD_OFFSET(version, version->vn_aux); + + while (TRUE) + { + PPH_ELF_VERSION_RECORD versionInfo; + + versionInfo = PhAllocate(sizeof(PH_ELF_VERSION_RECORD)); + memset(versionInfo, 0, sizeof(PH_ELF_VERSION_RECORD)); + versionInfo->Version = versionAux->vna_other; + versionInfo->Name = PTR_ADD_OFFSET(SymbolStringTable, versionAux->vna_name); + versionInfo->FileName = PTR_ADD_OFFSET(SymbolStringTable, version->vn_file); + + PhAddItemList(recordsList, versionInfo); + + if (versionAux->vna_next == 0) + break; + + versionAux = PTR_ADD_OFFSET(versionAux, versionAux->vna_next); + } + + if (version->vn_next == 0) + break; + + version = PTR_ADD_OFFSET(version, version->vn_next); + } + + return recordsList; +} + +static VOID PhpFreeMappedWslImageVersionRecords( + _In_ PPH_LIST RecordsList + ) +{ + for (ULONG i = 0; i < RecordsList->Count; i++) + PhFree(RecordsList->Items[i]); + + PhDereferenceObject(RecordsList); +} + +static PSTR PhpFindWslImageVersionRecordName( + _In_ PPH_LIST VersionRecordList, + _In_ USHORT VersionIndex + ) +{ + // Note: 'ldconfig -v' and 'ldconfig -p' can be used to locate the path from the FileName. + for (ULONG i = 0; i < VersionRecordList->Count; i++) + { + PPH_ELF_VERSION_RECORD versionInfo = VersionRecordList->Items[i]; + + if (versionInfo->Version == VersionIndex) + return versionInfo->FileName; + } + + return NULL; +} + +// TODO: Optimize this function. +BOOLEAN PhGetMappedWslImageSymbols( + _In_ PPH_MAPPED_IMAGE MappedWslImage, + _Out_ PPH_LIST *ImageSymbols + ) +{ + PELF64_IMAGE_SECTION_HEADER section; + PPH_LIST symbols = PhCreateList(2000); + + if (section = PhGetMappedWslImageSectionByType(MappedWslImage, SHT_SYMTAB)) + { + // TODO: Need to find a WSL binary with a symbol table. + // SHT_SYMTAB should be parsed idential to SHT_DYNSYM? + } + + if (section = PhGetMappedWslImageSectionByType(MappedWslImage, SHT_DYNSYM)) + { + ULONGLONG count; + ULONGLONG i; + PELF_IMAGE_SYMBOL_ENTRY entry; + PVOID stringTable; + PELF_VERSION_TABLE versionTable; + PPH_LIST versionRecords; + + if (section->sh_entsize != sizeof(ELF_IMAGE_SYMBOL_ENTRY)) + return FALSE; + + count = section->sh_size / sizeof(ELF_IMAGE_SYMBOL_ENTRY); + entry = PTR_ADD_OFFSET(MappedWslImage->Header, section->sh_offset); + stringTable = PhGetMappedWslImageSectionData(MappedWslImage, NULL, section->sh_link); + + versionTable = PhGetMappedWslImageSectionDataByType(MappedWslImage, SHT_SUNW_versym); + versionRecords = PhpParseMappedWslImageVersionRecords(MappedWslImage, stringTable); + + for (i = 1; i < count; i++) + { + if (entry[i].st_shndx == SHN_UNDEF) + { + PPH_ELF_IMAGE_SYMBOL_ENTRY import; + + import = PhAllocate(sizeof(PH_ELF_IMAGE_SYMBOL_ENTRY)); + memset(import, 0, sizeof(PH_ELF_IMAGE_SYMBOL_ENTRY)); + + import->ImportSymbol = TRUE; + import->Address = entry[i].st_value; + import->Size = entry[i].st_size; + import->TypeInfo = entry[i].st_info; + + // function name + PhCopyStringZFromBytes( + PTR_ADD_OFFSET(stringTable, entry[i].st_name), + -1, + import->Name, + sizeof(import->Name), + NULL + ); + + // import library name + if (versionTable && versionRecords) + { + PSTR moduleName; + + if (moduleName = PhpFindWslImageVersionRecordName(versionRecords, versionTable[i].vs_vers)) + { + PhCopyStringZFromBytes( + moduleName, + -1, + import->Module, + sizeof(import->Module), + NULL + ); + } + } + + PhAddItemList(symbols, import); + } + else if (entry[i].st_shndx != SHN_UNDEF && entry[i].st_value != 0) + { + PPH_ELF_IMAGE_SYMBOL_ENTRY export; + + if (ELF_ST_TYPE(entry[i].st_info) == STT_SECTION) // Ignore section symbol types. + continue; + + export = PhAllocate(sizeof(PH_ELF_IMAGE_SYMBOL_ENTRY)); + memset(export, 0, sizeof(PH_ELF_IMAGE_SYMBOL_ENTRY)); + + export->ExportSymbol = TRUE; + export->Address = entry[i].st_value; + export->Size = entry[i].st_size; + export->TypeInfo = entry[i].st_info; + + // function name + PhCopyStringZFromBytes( + PTR_ADD_OFFSET(stringTable, entry[i].st_name), + -1, + export->Name, + sizeof(export->Name), + NULL + ); + + PhAddItemList(symbols, export); + } + else + { + PPH_ELF_IMAGE_SYMBOL_ENTRY export; + + export = PhAllocate(sizeof(PH_ELF_IMAGE_SYMBOL_ENTRY)); + memset(export, 0, sizeof(PH_ELF_IMAGE_SYMBOL_ENTRY)); + + export->UnknownSymbol = TRUE; + export->Address = entry[i].st_value; + export->Size = entry[i].st_size; + export->TypeInfo = entry[i].st_info; + + // function name + PhCopyStringZFromBytes( + PTR_ADD_OFFSET(stringTable, entry[i].st_name), + -1, + export->Name, + sizeof(export->Name), + NULL + ); + + PhAddItemList(symbols, export); + } + } + + if (versionRecords) + PhpFreeMappedWslImageVersionRecords(versionRecords); + } + + *ImageSymbols = symbols; + + return TRUE; +} + +VOID PhFreeMappedWslImageSymbols( + _In_ PPH_LIST ImageSymbols + ) +{ + for (ULONG i = 0; i < ImageSymbols->Count; i++) + PhFree(ImageSymbols->Items[i]); + + PhDereferenceObject(ImageSymbols); +} \ No newline at end of file diff --git a/phlib/mapimg.c b/phlib/mapimg.c index 5a5ddb846056..5f9086de1dd7 100644 --- a/phlib/mapimg.c +++ b/phlib/mapimg.c @@ -130,21 +130,23 @@ NTSTATUS PhLoadMappedImage( ) { NTSTATUS status; + PVOID viewBase; + SIZE_T size; status = PhMapViewOfEntireFile( FileName, FileHandle, ReadOnly, - &MappedImage->ViewBase, - &MappedImage->Size + &viewBase, + &size ); if (NT_SUCCESS(status)) { status = PhInitializeMappedImage( MappedImage, - MappedImage->ViewBase, - MappedImage->Size + viewBase, + size ); if (!NT_SUCCESS(status)) @@ -156,6 +158,66 @@ NTSTATUS PhLoadMappedImage( return status; } +NTSTATUS PhLoadMappedImageEx( + _In_opt_ PWSTR FileName, + _In_opt_ HANDLE FileHandle, + _In_ BOOLEAN ReadOnly, + _Out_ PPH_MAPPED_IMAGE MappedImage + ) +{ + NTSTATUS status; + PVOID viewBase; + SIZE_T size; + + status = PhMapViewOfEntireFile( + FileName, + FileHandle, + ReadOnly, + &viewBase, + &size + ); + + if (NT_SUCCESS(status)) + { + PUSHORT imageHeaderSignature = viewBase; + + __try + { + PhProbeAddress(imageHeaderSignature, sizeof(USHORT), viewBase, size, 1); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + return GetExceptionCode(); + } + + MappedImage->Signature = *imageHeaderSignature; + + switch (MappedImage->Signature) + { + case IMAGE_DOS_SIGNATURE: + { + status = PhInitializeMappedImage( + MappedImage, + viewBase, + size + ); + } + break; + case IMAGE_ELF_SIGNATURE: + { + status = PhInitializeMappedWslImage( + MappedImage, + viewBase, + size + ); + } + break; + } + } + + return status; +} + NTSTATUS PhUnloadMappedImage( _Inout_ PPH_MAPPED_IMAGE MappedImage ) diff --git a/phlib/phlib.vcxproj b/phlib/phlib.vcxproj index 8582f9290f38..b8ae87a725c6 100644 --- a/phlib/phlib.vcxproj +++ b/phlib/phlib.vcxproj @@ -176,6 +176,7 @@ + @@ -208,6 +209,7 @@ + diff --git a/phlib/phlib.vcxproj.filters b/phlib/phlib.vcxproj.filters index 2ebb7ab5f4b3..088326bcfc68 100644 --- a/phlib/phlib.vcxproj.filters +++ b/phlib/phlib.vcxproj.filters @@ -218,6 +218,9 @@ Json-C + + Source Files + @@ -460,5 +463,8 @@ Header Files + + Header Files + \ No newline at end of file diff --git a/tools/peview/exlfexports.c b/tools/peview/exlfexports.c new file mode 100644 index 000000000000..80088eed1d04 --- /dev/null +++ b/tools/peview/exlfexports.c @@ -0,0 +1,126 @@ +/* + * Process Hacker - + * PE viewer + * + * Copyright (C) 2017 dmex + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include + +VOID PvpProcessElfExports( + _In_ HWND ListViewHandle + ) +{ + PPH_LIST exports; + ULONG count = 0; + + PhGetMappedWslImageSymbols(&PvMappedImage, &exports); + + for (ULONG i = 0; i < exports->Count; i++) + { + PPH_ELF_IMAGE_SYMBOL_ENTRY export = exports->Items[i]; + INT lvItemIndex; + WCHAR number[PH_INT32_STR_LEN_1]; + WCHAR pointer[PH_PTR_STR_LEN_1]; + + if (!export->ExportSymbol) + continue; + + PhPrintUInt64(number, count++); + lvItemIndex = PhAddListViewItem(ListViewHandle, MAXINT, number, NULL); + + PhPrintPointer(pointer, (PVOID)export->Address); + + PhSetListViewSubItem(ListViewHandle, lvItemIndex, 1, pointer); + PhSetListViewSubItem(ListViewHandle, lvItemIndex, 2, export->Name); + PhSetListViewSubItem(ListViewHandle, lvItemIndex, 3, PhaFormatSize(export->Size, -1)->Buffer); + PhSetListViewSubItem(ListViewHandle, lvItemIndex, 4, PvpGetSymbolTypeName(export->TypeInfo)); + PhSetListViewSubItem(ListViewHandle, lvItemIndex, 5, PvpGetSymbolBindingName(export->TypeInfo)); + } + + PhFreeMappedWslImageSymbols(exports); +} + +INT_PTR CALLBACK PvpExlfExportsDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + LPPROPSHEETPAGE propSheetPage; + PPV_PROPPAGECONTEXT propPageContext; + + if (!PvPropPageDlgProcHeader(hwndDlg, uMsg, lParam, &propSheetPage, &propPageContext)) + return FALSE; + + switch (uMsg) + { + case WM_INITDIALOG: + { + HWND lvHandle; + + lvHandle = GetDlgItem(hwndDlg, IDC_LIST); + PhSetListViewStyle(lvHandle, TRUE, TRUE); + PhSetControlTheme(lvHandle, L"explorer"); + PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 40, L"#"); + PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_RIGHT, 80, L"RVA"); + PhAddListViewColumn(lvHandle, 2, 2, 2, LVCFMT_LEFT, 250, L"Name"); + PhAddListViewColumn(lvHandle, 3, 3, 3, LVCFMT_LEFT, 250, L"Size"); + PhAddListViewColumn(lvHandle, 4, 4, 4, LVCFMT_LEFT, 80, L"Type"); + PhAddListViewColumn(lvHandle, 5, 5, 5, LVCFMT_LEFT, 80, L"Binding"); + PhSetExtendedListView(lvHandle); + PhLoadListViewColumnsFromSetting(L"ImageExportsListViewColumns", lvHandle); + + PvpProcessElfExports(lvHandle); + ExtendedListView_SortItems(lvHandle); + + EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); + } + break; + case WM_DESTROY: + { + PhSaveListViewColumnsToSetting(L"ImageExportsListViewColumns", GetDlgItem(hwndDlg, IDC_LIST)); + } + break; + case WM_SHOWWINDOW: + { + if (!propPageContext->LayoutInitialized) + { + PPH_LAYOUT_ITEM dialogItem; + + dialogItem = PvAddPropPageLayoutItem(hwndDlg, hwndDlg, + PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL); + PvAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_LIST), + dialogItem, PH_ANCHOR_ALL); + + PvDoPropPageLayout(hwndDlg); + + propPageContext->LayoutInitialized = TRUE; + } + } + break; + case WM_NOTIFY: + { + PvHandleListViewNotifyForCopy(lParam, GetDlgItem(hwndDlg, IDC_LIST)); + } + break; + } + + return FALSE; +} diff --git a/tools/peview/exlfimports.c b/tools/peview/exlfimports.c new file mode 100644 index 000000000000..d8f4df98ec89 --- /dev/null +++ b/tools/peview/exlfimports.c @@ -0,0 +1,122 @@ +/* + * Process Hacker - + * PE viewer + * + * Copyright (C) 2017 dmex + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include + +VOID PvpProcessElfImports( + _In_ HWND ListViewHandle + ) +{ + PPH_LIST imports; + ULONG count = 0; + + PhGetMappedWslImageSymbols(&PvMappedImage, &imports); + + for (ULONG i = 0; i < imports->Count; i++) + { + PPH_ELF_IMAGE_SYMBOL_ENTRY import = imports->Items[i]; + INT lvItemIndex; + WCHAR number[PH_INT32_STR_LEN_1]; + + if (!import->ImportSymbol) + continue; + + PhPrintUInt64(number, count++); + lvItemIndex = PhAddListViewItem(ListViewHandle, MAXINT, number, NULL); + + PhSetListViewSubItem(ListViewHandle, lvItemIndex, 1, import->Module); + PhSetListViewSubItem(ListViewHandle, lvItemIndex, 2, import->Name); + //PhSetListViewSubItem(ListViewHandle, lvItemIndex, 3, PhaFormatSize(import->Size, -1)->Buffer); + PhSetListViewSubItem(ListViewHandle, lvItemIndex, 4, PvpGetSymbolTypeName(import->TypeInfo)); + PhSetListViewSubItem(ListViewHandle, lvItemIndex, 5, PvpGetSymbolBindingName(import->TypeInfo)); + } + + PhFreeMappedWslImageSymbols(imports); +} + +INT_PTR CALLBACK PvpExlfImportsDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + LPPROPSHEETPAGE propSheetPage; + PPV_PROPPAGECONTEXT propPageContext; + + if (!PvPropPageDlgProcHeader(hwndDlg, uMsg, lParam, &propSheetPage, &propPageContext)) + return FALSE; + + switch (uMsg) + { + case WM_INITDIALOG: + { + HWND lvHandle; + + lvHandle = GetDlgItem(hwndDlg, IDC_LIST); + PhSetListViewStyle(lvHandle, TRUE, TRUE); + PhSetControlTheme(lvHandle, L"explorer"); + PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 40, L"#"); + PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 130, L"Module"); + PhAddListViewColumn(lvHandle, 2, 2, 2, LVCFMT_LEFT, 210, L"Name"); + PhAddListViewColumn(lvHandle, 3, 3, 3, LVCFMT_LEFT, 100, L"Type"); + PhAddListViewColumn(lvHandle, 4, 4, 4, LVCFMT_LEFT, 80, L"Binding"); + PhSetExtendedListView(lvHandle); + PhLoadListViewColumnsFromSetting(L"ImageImportsListViewColumns", lvHandle); + + PvpProcessElfImports(lvHandle); + ExtendedListView_SortItems(lvHandle); + + EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); + } + break; + case WM_DESTROY: + { + PhSaveListViewColumnsToSetting(L"ImageImportsListViewColumns", GetDlgItem(hwndDlg, IDC_LIST)); + } + break; + case WM_SHOWWINDOW: + { + if (!propPageContext->LayoutInitialized) + { + PPH_LAYOUT_ITEM dialogItem; + + dialogItem = PvAddPropPageLayoutItem(hwndDlg, hwndDlg, + PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL); + PvAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_LIST), + dialogItem, PH_ANCHOR_ALL); + + PvDoPropPageLayout(hwndDlg); + + propPageContext->LayoutInitialized = TRUE; + } + } + break; + case WM_NOTIFY: + { + PvHandleListViewNotifyForCopy(lParam, GetDlgItem(hwndDlg, IDC_LIST)); + } + break; + } + + return FALSE; +} diff --git a/tools/peview/exlfprp.c b/tools/peview/exlfprp.c new file mode 100644 index 000000000000..3dca74aca3e8 --- /dev/null +++ b/tools/peview/exlfprp.c @@ -0,0 +1,390 @@ +/* + * Process Hacker - + * PE viewer + * + * Copyright (C) 2017 dmex + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include +#include +#include + +PWSTR PvpGetSymbolTypeName( + _In_ UCHAR TypeInfo + ) +{ + switch (ELF_ST_TYPE(TypeInfo)) + { + case STT_NOTYPE: + return L"No type"; + case STT_OBJECT: + return L"Object"; + case STT_FUNC: + return L"Function"; + case STT_SECTION: + return L"Section"; + case STT_FILE: + return L"File"; + case STT_COMMON: + return L"Common"; + case STT_TLS: + return L"TLS"; + case STT_GNU_IFUNC: + return L"IFUNC"; + } + + return L"***ERROR***"; +} + +PWSTR PvpGetSymbolBindingName( + _In_ UCHAR TypeInfo + ) +{ + switch (ELF_ST_BIND(TypeInfo)) + { + case STB_LOCAL: + return L"Local"; + case STB_GLOBAL: + return L"Global"; + case STB_WEAK: + return L"Weak"; + } + + return L"***ERROR***"; +} + +VOID PvExlfProperties( + VOID + ) +{ + PPV_PROPCONTEXT propContext; + + if (propContext = PvCreatePropContext(PvFileName)) + { + PPV_PROPPAGECONTEXT newPage; + + // General + newPage = PvCreatePropPageContext( + MAKEINTRESOURCE(IDD_ELFGENERAL), + PvpExlfGeneralDlgProc, + NULL + ); + PvAddPropPage(propContext, newPage); + + // Imports + newPage = PvCreatePropPageContext( + MAKEINTRESOURCE(IDD_PEIMPORTS), + PvpExlfImportsDlgProc, + NULL + ); + PvAddPropPage(propContext, newPage); + + // Exports + newPage = PvCreatePropPageContext( + MAKEINTRESOURCE(IDD_PEEXPORTS), + PvpExlfExportsDlgProc, + NULL + ); + PvAddPropPage(propContext, newPage); + + PhModalPropertySheet(&propContext->PropSheetHeader); + + PhDereferenceObject(propContext); + } +} + +VOID PvpSetWslImageType( + _In_ HWND hwndDlg + ) +{ + PWSTR type = L"N/A"; + + switch (PvMappedImage.Header->e_type) + { + case ET_DYN: + type = L"Dynamic"; + break; + case ET_EXEC: + type = L"Executable"; + break; + default: + type = L"ERROR"; + break; + } + + SetDlgItemText(hwndDlg, IDC_IMAGETYPE, type); +} + +VOID PvpSetWslImageMachineType( + _In_ HWND hwndDlg + ) +{ + PWSTR type = L"N/A"; + + switch (PvMappedImage.Header->e_machine) + { + case EM_386: + type = L"i386"; + break; + case EM_X86_64: + type = L"AMD64"; + break; + default: + type = L"ERROR"; + break; + } + + SetDlgItemText(hwndDlg, IDC_TARGETMACHINE, type); +} + +VOID PvpSetWslImageBase( + _In_ HWND hwndDlg + ) +{ + PPH_STRING string; + + if (PvMappedImage.Header->e_ident[EI_CLASS] == ELFCLASS32) + { + string = PhFormatString(L"0x%I32x", PhGetMappedWslImageBaseAddress(&PvMappedImage)); + SetDlgItemText(hwndDlg, IDC_IMAGEBASE, string->Buffer); + PhDereferenceObject(string); + } + else if (PvMappedImage.Header->e_ident[EI_CLASS] == ELFCLASS64) + { + string = PhFormatString(L"0x%I64x", PhGetMappedWslImageBaseAddress(&PvMappedImage)); + SetDlgItemText(hwndDlg, IDC_IMAGEBASE, string->Buffer); + PhDereferenceObject(string); + } +} + +VOID PvpSetWslEntrypoint( + _In_ HWND hwndDlg + ) +{ + PPH_STRING string; + + if (PvMappedImage.Header->e_ident[EI_CLASS] == ELFCLASS32) + { + string = PhFormatString(L"0x%I32x", PvMappedImage.Headers32->e_entry); + SetDlgItemText(hwndDlg, IDC_ENTRYPOINT, string->Buffer); + PhDereferenceObject(string); + } + else if (PvMappedImage.Header->e_ident[EI_CLASS] == ELFCLASS64) + { + string = PhFormatString(L"0x%I64x", PvMappedImage.Headers64->e_entry); + SetDlgItemText(hwndDlg, IDC_ENTRYPOINT, string->Buffer); + PhDereferenceObject(string); + } +} + +PWSTR PvpGetWslImageSectionTypeName( + _In_ UINT32 Type + ) +{ + switch (Type) + { + case SHT_NULL: + return L"NULL"; + case SHT_PROGBITS: + return L"PROGBITS"; + case SHT_SYMTAB: + return L"SYMTAB"; + case SHT_STRTAB: + return L"STRTAB"; + case SHT_RELA: + return L"RELA"; + case SHT_HASH: + return L"HASH"; + case SHT_DYNAMIC: + return L"DYNAMIC"; + case SHT_NOTE: + return L"NOTE"; + case SHT_NOBITS: + return L"NOBITS"; + case SHT_REL: + return L"REL"; + case SHT_SHLIB: + return L"SHLIB"; + case SHT_DYNSYM: + return L"DYNSYM"; + case SHT_NUM: + return L"NUM"; + case SHT_INIT_ARRAY: + return L"INIT_ARRAY"; + case SHT_FINI_ARRAY: + return L"FINI_ARRAY"; + case SHT_PREINIT_ARRAY: + return L"PREINIT_ARRAY"; + case SHT_GROUP: + return L"GROUP"; + case SHT_SYMTAB_SHNDX: + return L"SYMTAB_SHNDX"; + case SHT_GNU_INCREMENTAL_INPUTS: + return L"GNU_INCREMENTAL_INPUTS"; + case SHT_GNU_ATTRIBUTES: + return L"GNU_ATTRIBUTES"; + case SHT_GNU_HASH: + return L"GNU_HASH"; + case SHT_GNU_LIBLIST: + return L"GNU_LIBLIST"; + case SHT_SUNW_verdef: + return L"VERDEF"; + case SHT_SUNW_verneed: + return L"VERNEED"; + case SHT_SUNW_versym: + return L"VERSYM"; + } + + return L"***ERROR***"; +} + +PPH_STRING PvpGetWslImageSectionFlagsString( + _In_ ULONGLONG Flags + ) +{ + PH_STRING_BUILDER sb; + + PhInitializeStringBuilder(&sb, 100); + + if (Flags & SHF_ALLOC) + PhAppendStringBuilder2(&sb, L"Allocated, "); + + if (!(Flags & SHF_WRITE)) + PhAppendStringBuilder2(&sb, L"Read-only, "); + + if (Flags & SHF_EXECINSTR) + PhAppendStringBuilder2(&sb, L"Code, "); + else + PhAppendStringBuilder2(&sb, L"Data, "); + + if (sb.String->Length != 0) + PhRemoveEndStringBuilder(&sb, 2); + else + PhAppendStringBuilder2(&sb, L"(None)"); + + // TODO: The "objdump -h /bin/su --wide" command shows section flags + // such as CONTENT which appears to be based on ElfSectionType != SHT_NOBITS + // but I can't find the relevant source-code and check. + + return PhFinalStringBuilderString(&sb); +} + +VOID PvpLoadWslSections( + _In_ HWND LvHandle + ) +{ + USHORT sectionCount; + PPH_ELF_IMAGE_SECTION imageSections; + + if (PhGetMappedWslImageSections(&PvMappedImage, §ionCount, &imageSections)) + { + for (USHORT i = 0; i < sectionCount; i++) + { + INT lvItemIndex; + WCHAR pointer[PH_PTR_STR_LEN_1]; + + if (!imageSections[i].Address && !imageSections[i].Size) + continue; + + lvItemIndex = PhAddListViewItem(LvHandle, MAXINT, imageSections[i].Name, NULL); + PhSetListViewSubItem(LvHandle, lvItemIndex, 1, PvpGetWslImageSectionTypeName(imageSections[i].Type)); + + PhPrintPointer(pointer, (PVOID)imageSections[i].Address); + PhSetListViewSubItem(LvHandle, lvItemIndex, 2, pointer); + + PhPrintPointer(pointer, (PVOID)imageSections[i].Offset); + PhSetListViewSubItem(LvHandle, lvItemIndex, 3, pointer); + + PhSetListViewSubItem(LvHandle, lvItemIndex, 4, PhaFormatSize(imageSections[i].Size, -1)->Buffer); + PhSetListViewSubItem(LvHandle, lvItemIndex, 5, PH_AUTO_T(PH_STRING, PvpGetWslImageSectionFlagsString(imageSections[i].Flags))->Buffer); + } + + PhFree(imageSections); + } +} + +INT_PTR CALLBACK PvpExlfGeneralDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + LPPROPSHEETPAGE propSheetPage; + PPV_PROPPAGECONTEXT propPageContext; + + if (!PvPropPageDlgProcHeader(hwndDlg, uMsg, lParam, &propSheetPage, &propPageContext)) + return FALSE; + + switch (uMsg) + { + case WM_INITDIALOG: + { + HWND lvHandle; + + lvHandle = GetDlgItem(hwndDlg, IDC_LIST); + PhSetListViewStyle(lvHandle, FALSE, TRUE); + PhSetControlTheme(lvHandle, L"explorer"); + PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 80, L"Name"); + PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 80, L"Type"); + PhAddListViewColumn(lvHandle, 2, 2, 2, LVCFMT_LEFT, 80, L"VA"); + PhAddListViewColumn(lvHandle, 3, 3, 3, LVCFMT_LEFT, 80, L"Offset"); + PhAddListViewColumn(lvHandle, 4, 4, 4, LVCFMT_LEFT, 80, L"Size"); + PhAddListViewColumn(lvHandle, 5, 5, 5, LVCFMT_LEFT, 80, L"Flags"); + PhSetExtendedListView(lvHandle); + PhLoadListViewColumnsFromSetting(L"GeneralWslTreeListColumns", lvHandle); + + PvpSetWslImageType(hwndDlg); + PvpSetWslImageMachineType(hwndDlg); + PvpSetWslImageBase(hwndDlg); + PvpSetWslEntrypoint(hwndDlg); + + PvpLoadWslSections(lvHandle); + + EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); + } + break; + case WM_DESTROY: + { + PhSaveListViewColumnsToSetting(L"GeneralWslTreeListColumns", GetDlgItem(hwndDlg, IDC_LIST)); + } + break; + case WM_SHOWWINDOW: + { + if (!propPageContext->LayoutInitialized) + { + PPH_LAYOUT_ITEM dialogItem; + + dialogItem = PvAddPropPageLayoutItem(hwndDlg, hwndDlg, PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL); + PvAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_LIST), dialogItem, PH_ANCHOR_ALL); + + PvDoPropPageLayout(hwndDlg); + + propPageContext->LayoutInitialized = TRUE; + } + } + break; + case WM_NOTIFY: + { + PvHandleListViewNotifyForCopy(lParam, GetDlgItem(hwndDlg, IDC_LIST)); + } + break; + } + + return FALSE; +} diff --git a/tools/peview/include/peview.h b/tools/peview/include/peview.h index dc3f53bc9512..912c73869622 100644 --- a/tools/peview/include/peview.h +++ b/tools/peview/include/peview.h @@ -58,6 +58,12 @@ VOID PvLibProperties( VOID ); +// exlfprp + +VOID PvExlfProperties( + VOID + ); + // misc PPH_STRING PvResolveShortcutTarget( @@ -322,4 +328,35 @@ INT_PTR CALLBACK PvpPeResourcesDlgProc( _In_ LPARAM lParam ); +// ELF + +PWSTR PvpGetSymbolTypeName( + _In_ UCHAR TypeInfo + ); + +PWSTR PvpGetSymbolBindingName( + _In_ UCHAR TypeInfo + ); + +INT_PTR CALLBACK PvpExlfGeneralDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +INT_PTR CALLBACK PvpExlfImportsDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +INT_PTR CALLBACK PvpExlfExportsDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + #endif diff --git a/tools/peview/main.c b/tools/peview/main.c index 2338bf6d2a59..a0a3e54ef6a5 100644 --- a/tools/peview/main.c +++ b/tools/peview/main.c @@ -88,7 +88,7 @@ INT WINAPI wWinMain( CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE); fileDialog = PhCreateOpenFileDialog(); - PhSetFileDialogFilter(fileDialog, filters, sizeof(filters) / sizeof(PH_FILETYPE_FILTER)); + PhSetFileDialogFilter(fileDialog, filters, ARRAYSIZE(filters)); if (PhShowFileDialog(NULL, fileDialog)) { @@ -116,7 +116,37 @@ INT WINAPI wWinMain( else if (PhEndsWithString2(PvFileName, L".pdb", TRUE)) PvPdbProperties(); else - PvPeProperties(); + { + NTSTATUS status; + + status = PhLoadMappedImageEx( + PvFileName->Buffer, + NULL, + TRUE, + &PvMappedImage + ); + + if (NT_SUCCESS(status)) + { + switch (PvMappedImage.Signature) + { + case IMAGE_DOS_SIGNATURE: + PvPeProperties(); + break; + case IMAGE_ELF_SIGNATURE: + PvExlfProperties(); + break; + default: + status = STATUS_IMAGE_SUBSYSTEM_NOT_PRESENT; + break; + } + } + + if (NT_SUCCESS(status)) + PhUnloadMappedImage(&PvMappedImage); + else + PhShowStatus(NULL, L"Unable to load the file.", status, 0); + } PeSaveSettings(); diff --git a/tools/peview/peprp.c b/tools/peview/peprp.c index 56a469d4f2bd..265271a3a3ce 100644 --- a/tools/peview/peprp.c +++ b/tools/peview/peprp.c @@ -54,23 +54,11 @@ VOID PvPeProperties( VOID ) { - NTSTATUS status; PPV_PROPCONTEXT propContext; PH_MAPPED_IMAGE_IMPORTS imports; PH_MAPPED_IMAGE_EXPORTS exports; PIMAGE_DATA_DIRECTORY entry; - if (!NT_SUCCESS(status = PhLoadMappedImage( - PvFileName->Buffer, - NULL, - TRUE, - &PvMappedImage - ))) - { - PhShowStatus(NULL, L"Unable to load the PE file", status, 0); - return; - } - if (PvpLoadDbgHelp(&PvSymbolProvider)) { // Load current PE pdb @@ -145,7 +133,7 @@ VOID PvPeProperties( entry->VirtualAddress && (PvImageCor20Header = PhMappedImageRvaToVa(&PvMappedImage, entry->VirtualAddress, NULL))) { - status = STATUS_SUCCESS; + NTSTATUS status = STATUS_SUCCESS; __try { @@ -199,8 +187,6 @@ VOID PvPeProperties( PhDereferenceObject(propContext); } - - PhUnloadMappedImage(&PvMappedImage); } static NTSTATUS CheckSumImageThreadStart( diff --git a/tools/peview/peview.rc b/tools/peview/peview.rc index 785a4906fba3..c762a3799c3a 100644 --- a/tools/peview/peview.rc +++ b/tools/peview/peview.rc @@ -124,6 +124,14 @@ BEGIN TOPMARGIN, 3 BOTTOMMARGIN, 277 END + + IDD_ELFGENERAL, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 293 + TOPMARGIN, 7 + BOTTOMMARGIN, 273 + END END #endif // APSTUDIO_INVOKED @@ -237,6 +245,23 @@ BEGIN CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,3,3,294,274 END +IDD_ELFGENERAL DIALOGEX 0, 0, 300, 280 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "General" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "Target machine:",IDC_STATIC,7,7,53,8 + LTEXT "Static",IDC_TARGETMACHINE,78,7,215,8 + CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,75,286,197 + LTEXT "Sections:",IDC_STATIC,7,64,30,8 + LTEXT "Entry point:",IDC_STATIC,7,47,39,8 + LTEXT "Static",IDC_ENTRYPOINT,78,47,215,8 + LTEXT "Image base:",IDC_STATIC,7,34,41,8 + LTEXT "Static",IDC_IMAGEBASE,78,34,215,8 + LTEXT "Image type:",IDC_STATIC,7,20,40,8 + LTEXT "Static",IDC_IMAGETYPE,78,20,215,8 +END + ///////////////////////////////////////////////////////////////////////////// // diff --git a/tools/peview/peview.vcxproj b/tools/peview/peview.vcxproj index ca02ad300e64..b0d32756b17c 100644 --- a/tools/peview/peview.vcxproj +++ b/tools/peview/peview.vcxproj @@ -94,6 +94,7 @@ true true true + true noarg.obj;noenv.obj;phlib.lib;ntdll.lib;uxtheme.lib;windowscodecs.lib;%(AdditionalDependencies) @@ -123,6 +124,7 @@ true true true + true noarg.obj;noenv.obj;phlib.lib;ntdll.lib;uxtheme.lib;windowscodecs.lib;%(AdditionalDependencies) @@ -212,6 +214,9 @@ + + + diff --git a/tools/peview/peview.vcxproj.filters b/tools/peview/peview.vcxproj.filters index 977007a3472b..9058c1d666c7 100644 --- a/tools/peview/peview.vcxproj.filters +++ b/tools/peview/peview.vcxproj.filters @@ -13,17 +13,20 @@ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav + + {227fbc2c-1da0-44f4-95c8-47aca5abb52a} + + + {d170a140-b947-49a4-87e8-e1d35b1024c1} + + + {3213da7e-9e01-48a4-8895-c4dd1499b2fa} + - - Source Files - Source Files - - Source Files - Source Files @@ -36,32 +39,47 @@ Source Files - - Source Files - - + Source Files - + Source Files - Source Files + Source Files\Pages\Windows + + + Source Files\Pages\Windows + + + Source Files\Pages\Windows + + + Source Files\Pages\Windows - Source Files + Source Files\Pages\Windows - Source Files - - - Source Files + Source Files\Pages\Windows - - Source Files + + Source Files\Pages\Windows - Source Files + Source Files\Pages\Windows + + + Source Files\Pages\Windows + + + Source Files\Pages\Linux + + + Source Files\Pages\Linux + + + Source Files\Pages\Linux diff --git a/tools/peview/resource.h b/tools/peview/resource.h index 29c9488f2611..67a136b18427 100644 --- a/tools/peview/resource.h +++ b/tools/peview/resource.h @@ -12,6 +12,7 @@ #define IDD_PESYMBOLS 108 #define IDD_PERESOURCES 109 #define IDB_SEARCH_ACTIVE 110 +#define IDD_ELFGENERAL 110 #define IDB_SEARCH_INACTIVE 111 #define IDB_SEARCH_ACTIVE_BMP 112 #define IDB_SEARCH_INACTIVE_BMP 113 @@ -34,6 +35,8 @@ #define IDC_IMAGEBASE 1015 #define IDC_ENTRYPOINT 1016 #define IDC_SYMSEARCH 1017 +#define IDC_IMAGEBASE2 1017 +#define IDC_IMAGETYPE 1017 #define IDC_NAME 1019 #define IDC_COMPANYNAME_LINK 1020 #define IDC_STOP 1021 diff --git a/tools/peview/settings.c b/tools/peview/settings.c index dc97ffcf2492..02933ce572b8 100644 --- a/tools/peview/settings.c +++ b/tools/peview/settings.c @@ -42,6 +42,9 @@ VOID PhAddDefaultSettings( PhpAddStringSetting(L"ImageResourcesListViewColumns", L""); PhpAddStringSetting(L"LibListViewColumns", L""); PhpAddStringSetting(L"PdbTreeListColumns", L""); + + // Wsl properties + PhpAddStringSetting(L"GeneralWslTreeListColumns", L""); } VOID PhUpdateCachedSettings( From 2482628937399d9c5505b5b76ced445e9e7cee70 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 7 Jan 2018 03:17:55 +1100 Subject: [PATCH 0662/2058] Fix general options checkbox support #218 --- ProcessHacker/options.c | 71 ++++++++++++++++++++++++----------------- 1 file changed, 42 insertions(+), 29 deletions(-) diff --git a/ProcessHacker/options.c b/ProcessHacker/options.c index 115b54a70252..0a533db00fe6 100644 --- a/ProcessHacker/options.c +++ b/ProcessHacker/options.c @@ -1313,50 +1313,63 @@ INT_PTR CALLBACK PhpOptionsGeneralDlgProc( // } //} - if (header->code == LVN_ITEMCHANGED) + switch (header->code) { - LPNM_LISTVIEW listView = (LPNM_LISTVIEW)lParam; - - if (listView->uChanged & LVIF_STATE) + case NM_CLICK: { - switch (listView->uNewState & LVIS_STATEIMAGEMASK) + LPNMITEMACTIVATE itemActivate = (LPNMITEMACTIVATE)header; + BOOLEAN itemChecked; + + itemChecked = ListView_GetCheckState(GetDlgItem(hwndDlg, IDC_SETTINGS), itemActivate->iItem) == BST_CHECKED; + ListView_SetCheckState(GetDlgItem(hwndDlg, IDC_SETTINGS), itemActivate->iItem, !itemChecked); + } + break; + case LVN_ITEMCHANGED: + { + LPNM_LISTVIEW listView = (LPNM_LISTVIEW)lParam; + + if (listView->uChanged & LVIF_STATE) { - case INDEXTOSTATEIMAGEMASK(2): // checked + switch (listView->uNewState & LVIS_STATEIMAGEMASK) { - switch (listView->iItem) + case INDEXTOSTATEIMAGEMASK(2): // checked { - case PHP_OPTIONS_INDEX_START_ATLOGON: + switch (listView->iItem) { - PhpSetListViewItemState(listView->hdr.hwndFrom, PHP_OPTIONS_INDEX_START_HIDDEN, FALSE); + case PHP_OPTIONS_INDEX_START_ATLOGON: + { + PhpSetListViewItemState(listView->hdr.hwndFrom, PHP_OPTIONS_INDEX_START_HIDDEN, FALSE); + } + break; + case PHP_OPTIONS_INDEX_SHOW_ADVANCED_OPTIONS: + { + PhpOptionsShowHideTreeViewItem(FALSE); + } + break; } - break; - case PHP_OPTIONS_INDEX_SHOW_ADVANCED_OPTIONS: - { - PhpOptionsShowHideTreeViewItem(FALSE); - } - break; } - } - break; - case INDEXTOSTATEIMAGEMASK(1): // unchecked - { - switch (listView->iItem) + break; + case INDEXTOSTATEIMAGEMASK(1): // unchecked { - case PHP_OPTIONS_INDEX_START_ATLOGON: + switch (listView->iItem) { - PhpSetListViewItemState(listView->hdr.hwndFrom, PHP_OPTIONS_INDEX_START_HIDDEN, TRUE); + case PHP_OPTIONS_INDEX_START_ATLOGON: + { + PhpSetListViewItemState(listView->hdr.hwndFrom, PHP_OPTIONS_INDEX_START_HIDDEN, TRUE); + } + break; + case PHP_OPTIONS_INDEX_SHOW_ADVANCED_OPTIONS: + { + PhpOptionsShowHideTreeViewItem(TRUE); + } + break; } - break; - case PHP_OPTIONS_INDEX_SHOW_ADVANCED_OPTIONS: - { - PhpOptionsShowHideTreeViewItem(TRUE); - } - break; } + break; } - break; } } + break; } } break; From 327fc3c0ed81bbd4e38f8e79a795cbebd2466f0a Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 7 Jan 2018 03:36:59 +1100 Subject: [PATCH 0663/2058] peview: fix elf imports column typo --- tools/peview/exlfimports.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tools/peview/exlfimports.c b/tools/peview/exlfimports.c index d8f4df98ec89..3170d6dbc785 100644 --- a/tools/peview/exlfimports.c +++ b/tools/peview/exlfimports.c @@ -45,9 +45,8 @@ VOID PvpProcessElfImports( PhSetListViewSubItem(ListViewHandle, lvItemIndex, 1, import->Module); PhSetListViewSubItem(ListViewHandle, lvItemIndex, 2, import->Name); - //PhSetListViewSubItem(ListViewHandle, lvItemIndex, 3, PhaFormatSize(import->Size, -1)->Buffer); - PhSetListViewSubItem(ListViewHandle, lvItemIndex, 4, PvpGetSymbolTypeName(import->TypeInfo)); - PhSetListViewSubItem(ListViewHandle, lvItemIndex, 5, PvpGetSymbolBindingName(import->TypeInfo)); + PhSetListViewSubItem(ListViewHandle, lvItemIndex, 3, PvpGetSymbolTypeName(import->TypeInfo)); + PhSetListViewSubItem(ListViewHandle, lvItemIndex, 4, PvpGetSymbolBindingName(import->TypeInfo)); } PhFreeMappedWslImageSymbols(imports); From e0c6384595d63720f399adcce0f60cd938fbac0a Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 7 Jan 2018 04:30:07 +1100 Subject: [PATCH 0664/2058] Fix general options checkbox regresion #218 --- ProcessHacker/options.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/ProcessHacker/options.c b/ProcessHacker/options.c index 0a533db00fe6..f0d777b1f738 100644 --- a/ProcessHacker/options.c +++ b/ProcessHacker/options.c @@ -1318,10 +1318,22 @@ INT_PTR CALLBACK PhpOptionsGeneralDlgProc( case NM_CLICK: { LPNMITEMACTIVATE itemActivate = (LPNMITEMACTIVATE)header; - BOOLEAN itemChecked; - - itemChecked = ListView_GetCheckState(GetDlgItem(hwndDlg, IDC_SETTINGS), itemActivate->iItem) == BST_CHECKED; - ListView_SetCheckState(GetDlgItem(hwndDlg, IDC_SETTINGS), itemActivate->iItem, !itemChecked); + LVHITTESTINFO lvHitInfo; + + lvHitInfo.pt = itemActivate->ptAction; + + if (ListView_HitTest(GetDlgItem(hwndDlg, IDC_SETTINGS), &lvHitInfo) != -1) + { + // Ignore click notifications for the listview checkbox region. + if (!(lvHitInfo.flags & LVHT_ONITEMSTATEICON)) + { + BOOLEAN itemChecked; + + // Emulate the checkbox control label click behavior and check/uncheck the checkbox when the listview item is clicked. + itemChecked = ListView_GetCheckState(GetDlgItem(hwndDlg, IDC_SETTINGS), itemActivate->iItem) == BST_CHECKED; + ListView_SetCheckState(GetDlgItem(hwndDlg, IDC_SETTINGS), itemActivate->iItem, !itemChecked); + } + } } break; case LVN_ITEMCHANGED: From 6bfff70cb23f79722ffe038212429dbba7814b6f Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 7 Jan 2018 05:00:52 +1100 Subject: [PATCH 0665/2058] Add missing checkbox state #218 --- ProcessHacker/options.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/ProcessHacker/options.c b/ProcessHacker/options.c index f0d777b1f738..d9a46dad16b8 100644 --- a/ProcessHacker/options.c +++ b/ProcessHacker/options.c @@ -1320,6 +1320,15 @@ INT_PTR CALLBACK PhpOptionsGeneralDlgProc( LPNMITEMACTIVATE itemActivate = (LPNMITEMACTIVATE)header; LVHITTESTINFO lvHitInfo; + // HACK: Don't change the checkbox state for the 'Start hidden' item when the 'Start at logon' item hasn't been enabled. + if ( + itemActivate->iItem == PHP_OPTIONS_INDEX_START_HIDDEN && + ListView_GetCheckState(GetDlgItem(hwndDlg, IDC_SETTINGS), PHP_OPTIONS_INDEX_START_ATLOGON) != BST_CHECKED + ) + { + break; + } + lvHitInfo.pt = itemActivate->ptAction; if (ListView_HitTest(GetDlgItem(hwndDlg, IDC_SETTINGS), &lvHitInfo) != -1) From f32c37abfc2839be2e82ff9b322f5364f280f960 Mon Sep 17 00:00:00 2001 From: ge0rdi Date: Sun, 7 Jan 2018 08:50:51 +0100 Subject: [PATCH 0666/2058] Add "Protection" column to process tree (#221) * Store process protection info in PH_PROCESS_ITEM * Format process protection in separate function * Add "Protection" column to process tree --- ProcessHacker/include/procprv.h | 1 + ProcessHacker/include/proctree.h | 4 +- ProcessHacker/procprv.c | 18 ++++++ ProcessHacker/proctree.c | 19 ++++++- ProcessHacker/prpggen.c | 95 +++++++++++++++----------------- 5 files changed, 84 insertions(+), 53 deletions(-) diff --git a/ProcessHacker/include/procprv.h b/ProcessHacker/include/procprv.h index 1237d1c8995a..b8726974e22b 100644 --- a/ProcessHacker/include/procprv.h +++ b/ProcessHacker/include/procprv.h @@ -231,6 +231,7 @@ typedef struct _PH_PROCESS_ITEM ULONGLONG ProcessSequenceNumber; PH_KNOWN_PROCESS_TYPE KnownProcessType; + PS_PROTECTION Protection; ULONG JobObjectId; } PH_PROCESS_ITEM, *PPH_PROCESS_ITEM; // end_phapppub diff --git a/ProcessHacker/include/proctree.h b/ProcessHacker/include/proctree.h index 65dba46ed220..889486cc13bb 100644 --- a/ProcessHacker/include/proctree.h +++ b/ProcessHacker/include/proctree.h @@ -91,8 +91,9 @@ #define PHPRTLC_FILESIZE 78 #define PHPRTLC_SUBPROCESSCOUNT 79 #define PHPRTLC_JOBOBJECTID 80 +#define PHPRTLC_PROTECTION 81 -#define PHPRTLC_MAXIMUM 81 +#define PHPRTLC_MAXIMUM 82 #define PHPRTLC_IOGROUP_COUNT 9 #define PHPN_WSCOUNTERS 0x1 @@ -217,6 +218,7 @@ typedef struct _PH_PROCESS_NODE PPH_STRING FileSizeText; PPH_STRING SubprocessCountText; WCHAR JobObjectIdText[PH_INT32_STR_LEN_1]; + PPH_STRING ProtectionText; // Graph buffers PH_GRAPH_BUFFERS CpuGraphBuffers; diff --git a/ProcessHacker/procprv.c b/ProcessHacker/procprv.c index 1671ce92029a..eeb780c3d7f5 100644 --- a/ProcessHacker/procprv.c +++ b/ProcessHacker/procprv.c @@ -1453,6 +1453,24 @@ VOID PhpFillProcessItem( ); } + // Protection + if (ProcessItem->QueryHandle) + { + if (WindowsVersion >= WINDOWS_8_1) + { + NtQueryInformationProcess( + ProcessItem->QueryHandle, + ProcessProtectionInformation, + &ProcessItem->Protection, + sizeof(ProcessItem->Protection), + NULL); + } + } + else + { + ProcessItem->Protection.Level = (UCHAR)-1; + } + // On Windows 8.1 and above, processes without threads are reflected processes // which will not terminate if we have a handle open. if (Process->NumberOfThreads == 0) diff --git a/ProcessHacker/proctree.c b/ProcessHacker/proctree.c index edaabb63e496..817713a15e2a 100644 --- a/ProcessHacker/proctree.c +++ b/ProcessHacker/proctree.c @@ -210,6 +210,7 @@ VOID PhInitializeProcessTreeList( PhAddTreeNewColumnEx(hwnd, PHPRTLC_FILESIZE, FALSE, L"File size", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); PhAddTreeNewColumnEx(hwnd, PHPRTLC_SUBPROCESSCOUNT, FALSE, L"Subprocesses", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); PhAddTreeNewColumnEx(hwnd, PHPRTLC_JOBOBJECTID, FALSE, L"Job Object ID", 50, PH_ALIGN_LEFT, -1, 0, TRUE); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_PROTECTION, FALSE, L"Protection", 105, PH_ALIGN_LEFT, -1, 0, TRUE); TreeNew_SetRedraw(hwnd, TRUE); @@ -599,6 +600,7 @@ VOID PhpRemoveProcessNode( PhClearReference(&ProcessNode->FileModifiedTimeText); PhClearReference(&ProcessNode->FileSizeText); PhClearReference(&ProcessNode->SubprocessCountText); + PhClearReference(&ProcessNode->ProtectionText); PhDeleteGraphBuffers(&ProcessNode->CpuGraphBuffers); PhDeleteGraphBuffers(&ProcessNode->PrivateGraphBuffers); @@ -1869,6 +1871,12 @@ BEGIN_SORT_FUNCTION(JobObjectId) } END_SORT_FUNCTION +BEGIN_SORT_FUNCTION(Protection) +{ + sortResult = intcmp((CHAR)processItem1->Protection.Level, (CHAR)processItem2->Protection.Level); +} +END_SORT_FUNCTION + BOOLEAN NTAPI PhpProcessTreeNewCallback( _In_ HWND hwnd, _In_ PH_TREENEW_MESSAGE Message, @@ -1989,7 +1997,8 @@ BOOLEAN NTAPI PhpProcessTreeNewCallback( SORT_FUNCTION(FileModifiedTime), SORT_FUNCTION(FileSize), SORT_FUNCTION(Subprocesses), - SORT_FUNCTION(JobObjectId) + SORT_FUNCTION(JobObjectId), + SORT_FUNCTION(Protection), }; int (__cdecl *sortFunction)(const void *, const void *); @@ -2790,6 +2799,14 @@ BOOLEAN NTAPI PhpProcessTreeNewCallback( } } break; + case PHPRTLC_PROTECTION: + { + extern PPH_STRING PhpFormatProcessProtection(_In_ PPH_PROCESS_ITEM ProcessItem); + + PhMoveReference(&node->ProtectionText, PhpFormatProcessProtection(processItem)); + getCellText->Text = node->ProtectionText->sr; + } + break; default: return FALSE; } diff --git a/ProcessHacker/prpggen.c b/ProcessHacker/prpggen.c index ad5c5c54bac6..4f12e13b9b8d 100644 --- a/ProcessHacker/prpggen.c +++ b/ProcessHacker/prpggen.c @@ -38,6 +38,47 @@ static PWSTR ProtectedSignerStrings[] = { L"", L" (Authenticode)", L" (CodeGen)", L" (Antimalware)", L" (Lsa)", L" (Windows)", L" (WinTcb)", L" (WinSystem)", L" (StoreApp)" }; +PPH_STRING PhpFormatProcessProtection(_In_ PPH_PROCESS_ITEM ProcessItem) +{ + if (ProcessItem->Protection.Level != (UCHAR)-1) + { + if (WindowsVersion >= WINDOWS_8_1) + { + PWSTR type; + PWSTR signer; + + switch (ProcessItem->Protection.Type) + { + case PsProtectedTypeNone: + type = L"None"; + break; + case PsProtectedTypeProtectedLight: + type = L"Light"; + break; + case PsProtectedTypeProtected: + type = L"Full"; + break; + default: + type = L"Unknown"; + break; + } + + if (ProcessItem->Protection.Signer < sizeof(ProtectedSignerStrings) / sizeof(PWSTR)) + signer = ProtectedSignerStrings[ProcessItem->Protection.Signer]; + else + signer = L""; + + return PhConcatStrings2(type, signer); + } + else + { + return PhCreateString(ProcessItem->IsProtectedProcess ? L"Yes" : L"None"); + } + } + + return PhCreateString(L"N/A"); +} + NTSTATUS PhpProcessGeneralOpenProcess( _Out_ PHANDLE Handle, _In_ ACCESS_MASK DesiredAccess, @@ -334,61 +375,13 @@ INT_PTR CALLBACK PhpProcessGeneralDlgProc( #ifdef _WIN64 } #endif + NtClose(processHandle); + processHandle = NULL; } // Protection - SetDlgItemText(hwndDlg, IDC_PROTECTION, L"N/A"); - - if (processHandle) - { - if (WindowsVersion >= WINDOWS_8_1) - { - PS_PROTECTION protection; - - if (NT_SUCCESS(NtQueryInformationProcess( - processHandle, - ProcessProtectionInformation, - &protection, - sizeof(PS_PROTECTION), - NULL - ))) - { - PWSTR type; - PWSTR signer; - - switch (protection.Type) - { - case PsProtectedTypeNone: - type = L"None"; - break; - case PsProtectedTypeProtectedLight: - type = L"Light"; - break; - case PsProtectedTypeProtected: - type = L"Full"; - break; - default: - type = L"Unknown"; - break; - } - - if (protection.Signer < sizeof(ProtectedSignerStrings) / sizeof(PWSTR)) - signer = ProtectedSignerStrings[protection.Signer]; - else - signer = L""; - - SetDlgItemText(hwndDlg, IDC_PROTECTION, PhaConcatStrings2(type, signer)->Buffer); - } - } - else - { - SetDlgItemText(hwndDlg, IDC_PROTECTION, processItem->IsProtectedProcess ? L"Yes" : L"None"); - } - } - - if (processHandle) - NtClose(processHandle); + SetDlgItemText(hwndDlg, IDC_PROTECTION, PH_AUTO_T(PH_STRING, PhpFormatProcessProtection(processItem))->Buffer); #ifdef _WIN64 if (processItem->IsWow64Valid) From 9ca557b3b6b406c7bad0c6180985508d458c1c55 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 7 Jan 2018 19:24:07 +1100 Subject: [PATCH 0667/2058] Tidy up #221 --- ProcessHacker/include/phapp.h | 6 ++++++ ProcessHacker/procprv.c | 23 +++++++++++------------ ProcessHacker/proctree.c | 9 +++++---- ProcessHacker/prpggen.c | 16 ++++++++-------- 4 files changed, 30 insertions(+), 24 deletions(-) diff --git a/ProcessHacker/include/phapp.h b/ProcessHacker/include/phapp.h index ea1fda8a0e3c..651992748e26 100644 --- a/ProcessHacker/include/phapp.h +++ b/ProcessHacker/include/phapp.h @@ -810,4 +810,10 @@ HPROPSHEETPAGE PhCreateTokenPage( _In_opt_ DLGPROC HookProc ); +// prpggen + +PPH_STRING PhGetProcessItemProtectionText( + _In_ PPH_PROCESS_ITEM ProcessItem + ); + #endif diff --git a/ProcessHacker/procprv.c b/ProcessHacker/procprv.c index eeb780c3d7f5..b9a6fc1b79cd 100644 --- a/ProcessHacker/procprv.c +++ b/ProcessHacker/procprv.c @@ -1454,22 +1454,21 @@ VOID PhpFillProcessItem( } // Protection - if (ProcessItem->QueryHandle) + if (WindowsVersion >= WINDOWS_8_1 && ProcessItem->QueryHandle) { - if (WindowsVersion >= WINDOWS_8_1) + PS_PROTECTION protection; + + if (NT_SUCCESS(NtQueryInformationProcess( + ProcessItem->QueryHandle, + ProcessProtectionInformation, + &protection, + sizeof(PS_PROTECTION), + NULL + ))) { - NtQueryInformationProcess( - ProcessItem->QueryHandle, - ProcessProtectionInformation, - &ProcessItem->Protection, - sizeof(ProcessItem->Protection), - NULL); + ProcessItem->Protection.Level = protection.Level; } } - else - { - ProcessItem->Protection.Level = (UCHAR)-1; - } // On Windows 8.1 and above, processes without threads are reflected processes // which will not terminate if we have a handle open. diff --git a/ProcessHacker/proctree.c b/ProcessHacker/proctree.c index 817713a15e2a..ce0bb323eaa2 100644 --- a/ProcessHacker/proctree.c +++ b/ProcessHacker/proctree.c @@ -2801,10 +2801,11 @@ BOOLEAN NTAPI PhpProcessTreeNewCallback( break; case PHPRTLC_PROTECTION: { - extern PPH_STRING PhpFormatProcessProtection(_In_ PPH_PROCESS_ITEM ProcessItem); - - PhMoveReference(&node->ProtectionText, PhpFormatProcessProtection(processItem)); - getCellText->Text = node->ProtectionText->sr; + if (processItem->Protection.Level != 0) + { + PhMoveReference(&node->ProtectionText, PhGetProcessItemProtectionText(processItem)); + getCellText->Text = node->ProtectionText->sr; + } } break; default: diff --git a/ProcessHacker/prpggen.c b/ProcessHacker/prpggen.c index 4f12e13b9b8d..c22312acc594 100644 --- a/ProcessHacker/prpggen.c +++ b/ProcessHacker/prpggen.c @@ -38,11 +38,13 @@ static PWSTR ProtectedSignerStrings[] = { L"", L" (Authenticode)", L" (CodeGen)", L" (Antimalware)", L" (Lsa)", L" (Windows)", L" (WinTcb)", L" (WinSystem)", L" (StoreApp)" }; -PPH_STRING PhpFormatProcessProtection(_In_ PPH_PROCESS_ITEM ProcessItem) +PPH_STRING PhGetProcessItemProtectionText( + _In_ PPH_PROCESS_ITEM ProcessItem + ) { - if (ProcessItem->Protection.Level != (UCHAR)-1) + if (WindowsVersion >= WINDOWS_8_1) { - if (WindowsVersion >= WINDOWS_8_1) + if (ProcessItem->Protection.Level != 0) { PWSTR type; PWSTR signer; @@ -350,13 +352,11 @@ INT_PTR CALLBACK PhpProcessGeneralDlgProc( SetDlgItemText(hwndDlg, IDC_PEBADDRESS, L"N/A"); - PhOpenProcess( + if (NT_SUCCESS(PhOpenProcess( &processHandle, ProcessQueryAccess, processItem->ProcessId - ); - - if (processHandle) + ))) { PhGetProcessBasicInformation(processHandle, &basicInfo); #ifdef _WIN64 @@ -381,7 +381,7 @@ INT_PTR CALLBACK PhpProcessGeneralDlgProc( // Protection - SetDlgItemText(hwndDlg, IDC_PROTECTION, PH_AUTO_T(PH_STRING, PhpFormatProcessProtection(processItem))->Buffer); + SetDlgItemText(hwndDlg, IDC_PROTECTION, PH_AUTO_T(PH_STRING, PhGetProcessItemProtectionText(processItem))->Buffer); #ifdef _WIN64 if (processItem->IsWow64Valid) From 63ada7c2d543ca2b24df44a2a2702c2eee838a2e Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 7 Jan 2018 22:02:33 +1100 Subject: [PATCH 0668/2058] Revert commit 9ca557b --- ProcessHacker/procprv.c | 29 ++++++++++++++++++----------- ProcessHacker/proctree.c | 7 ++----- ProcessHacker/prpggen.c | 28 ++++++++++++++-------------- 3 files changed, 34 insertions(+), 30 deletions(-) diff --git a/ProcessHacker/procprv.c b/ProcessHacker/procprv.c index b9a6fc1b79cd..ef63c2daab28 100644 --- a/ProcessHacker/procprv.c +++ b/ProcessHacker/procprv.c @@ -1454,21 +1454,28 @@ VOID PhpFillProcessItem( } // Protection - if (WindowsVersion >= WINDOWS_8_1 && ProcessItem->QueryHandle) + if (ProcessItem->QueryHandle) { - PS_PROTECTION protection; - - if (NT_SUCCESS(NtQueryInformationProcess( - ProcessItem->QueryHandle, - ProcessProtectionInformation, - &protection, - sizeof(PS_PROTECTION), - NULL - ))) + if (WindowsVersion >= WINDOWS_8_1) { - ProcessItem->Protection.Level = protection.Level; + PS_PROTECTION protection; + + if (NT_SUCCESS(NtQueryInformationProcess( + ProcessItem->QueryHandle, + ProcessProtectionInformation, + &protection, + sizeof(PS_PROTECTION), + NULL + ))) + { + ProcessItem->Protection.Level = protection.Level; + } } } + else + { + ProcessItem->Protection.Level = UCHAR_MAX; + } // On Windows 8.1 and above, processes without threads are reflected processes // which will not terminate if we have a handle open. diff --git a/ProcessHacker/proctree.c b/ProcessHacker/proctree.c index ce0bb323eaa2..1bba410d58d3 100644 --- a/ProcessHacker/proctree.c +++ b/ProcessHacker/proctree.c @@ -2801,11 +2801,8 @@ BOOLEAN NTAPI PhpProcessTreeNewCallback( break; case PHPRTLC_PROTECTION: { - if (processItem->Protection.Level != 0) - { - PhMoveReference(&node->ProtectionText, PhGetProcessItemProtectionText(processItem)); - getCellText->Text = node->ProtectionText->sr; - } + PhMoveReference(&node->ProtectionText, PhGetProcessItemProtectionText(processItem)); + getCellText->Text = node->ProtectionText->sr; } break; default: diff --git a/ProcessHacker/prpggen.c b/ProcessHacker/prpggen.c index c22312acc594..c1c197b2c79d 100644 --- a/ProcessHacker/prpggen.c +++ b/ProcessHacker/prpggen.c @@ -42,27 +42,27 @@ PPH_STRING PhGetProcessItemProtectionText( _In_ PPH_PROCESS_ITEM ProcessItem ) { - if (WindowsVersion >= WINDOWS_8_1) + if (ProcessItem->Protection.Level != UCHAR_MAX) { - if (ProcessItem->Protection.Level != 0) + if (WindowsVersion >= WINDOWS_8_1) { PWSTR type; PWSTR signer; switch (ProcessItem->Protection.Type) { - case PsProtectedTypeNone: - type = L"None"; - break; - case PsProtectedTypeProtectedLight: - type = L"Light"; - break; - case PsProtectedTypeProtected: - type = L"Full"; - break; - default: - type = L"Unknown"; - break; + case PsProtectedTypeNone: + type = L"None"; + break; + case PsProtectedTypeProtectedLight: + type = L"Light"; + break; + case PsProtectedTypeProtected: + type = L"Full"; + break; + default: + type = L"Unknown"; + break; } if (ProcessItem->Protection.Signer < sizeof(ProtectedSignerStrings) / sizeof(PWSTR)) From 0168d9c9d78440df23bb28a1b1854c2e74a6d095 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 7 Jan 2018 22:53:53 +1100 Subject: [PATCH 0669/2058] Add double click checkbox state #218 --- ProcessHacker/options.c | 1 + 1 file changed, 1 insertion(+) diff --git a/ProcessHacker/options.c b/ProcessHacker/options.c index d9a46dad16b8..15e6f4e6d531 100644 --- a/ProcessHacker/options.c +++ b/ProcessHacker/options.c @@ -1316,6 +1316,7 @@ INT_PTR CALLBACK PhpOptionsGeneralDlgProc( switch (header->code) { case NM_CLICK: + case NM_DBLCLK: { LPNMITEMACTIVATE itemActivate = (LPNMITEMACTIVATE)header; LVHITTESTINFO lvHitInfo; From 02b2c0afcb1117f6cbab0ba4280c074c65286fd5 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 8 Jan 2018 04:15:30 +1100 Subject: [PATCH 0670/2058] Remove dll injection feature --- ProcessHacker/actions.c | 56 -------------- ProcessHacker/cmdmode.c | 22 ------ ProcessHacker/include/actions.h | 8 -- ProcessHacker/prpgmod.c | 20 +---- ProcessHacker/resource.h | 1 - phlib/include/phnative.h | 9 --- phlib/native.c | 132 -------------------------------- 7 files changed, 4 insertions(+), 244 deletions(-) diff --git a/ProcessHacker/actions.c b/ProcessHacker/actions.c index 485f4a2ea2ef..2e905a3cf5a3 100644 --- a/ProcessHacker/actions.c +++ b/ProcessHacker/actions.c @@ -1663,62 +1663,6 @@ BOOLEAN PhUiDetachFromDebuggerProcess( return TRUE; } -BOOLEAN PhUiInjectDllProcess( - _In_ HWND hWnd, - _In_ PPH_PROCESS_ITEM Process - ) -{ - static PH_FILETYPE_FILTER filters[] = - { - { L"DLL files (*.dll)", L"*.dll" }, - { L"All files (*.*)", L"*.*" } - }; - - NTSTATUS status; - PVOID fileDialog; - PPH_STRING fileName; - HANDLE processHandle; - - fileDialog = PhCreateOpenFileDialog(); - PhSetFileDialogFilter(fileDialog, filters, sizeof(filters) / sizeof(PH_FILETYPE_FILTER)); - - if (!PhShowFileDialog(hWnd, fileDialog)) - { - PhFreeFileDialog(fileDialog); - return FALSE; - } - - fileName = PH_AUTO(PhGetFileDialogFileName(fileDialog)); - PhFreeFileDialog(fileDialog); - - if (NT_SUCCESS(status = PhOpenProcess( - &processHandle, - ProcessQueryAccess | PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | - PROCESS_VM_READ | PROCESS_VM_WRITE, - Process->ProcessId - ))) - { - LARGE_INTEGER timeout; - - timeout.QuadPart = -5 * PH_TIMEOUT_SEC; - status = PhInjectDllProcess( - processHandle, - fileName->Buffer, - &timeout - ); - - NtClose(processHandle); - } - - if (!NT_SUCCESS(status)) - { - PhpShowErrorProcess(hWnd, L"inject the DLL into", Process, status, 0); - return FALSE; - } - - return TRUE; -} - BOOLEAN PhUiSetIoPriorityProcesses( _In_ HWND hWnd, _In_ PPH_PROCESS_ITEM *Processes, diff --git a/ProcessHacker/cmdmode.c b/ProcessHacker/cmdmode.c index 6dcd32625fbe..9ea771073c32 100644 --- a/ProcessHacker/cmdmode.c +++ b/ProcessHacker/cmdmode.c @@ -226,28 +226,6 @@ NTSTATUS PhCommandModeStart( NtClose(processHandle); } } - else if (PhEqualString2(PhStartupParameters.CommandAction, L"injectdll", TRUE)) - { - if (!PhStartupParameters.CommandValue) - return STATUS_INVALID_PARAMETER; - - if (NT_SUCCESS(status = PhOpenProcessPublic( - &processHandle, - ProcessQueryAccess | PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE, - processId - ))) - { - LARGE_INTEGER timeout; - - timeout.QuadPart = -5 * PH_TIMEOUT_SEC; - status = PhInjectDllProcess( - processHandle, - PhStartupParameters.CommandValue->Buffer, - &timeout - ); - NtClose(processHandle); - } - } else if (PhEqualString2(PhStartupParameters.CommandAction, L"unloaddll", TRUE)) { if (!PhStartupParameters.CommandValue) diff --git a/ProcessHacker/include/actions.h b/ProcessHacker/include/actions.h index dd484c00333d..62cb0d758b04 100644 --- a/ProcessHacker/include/actions.h +++ b/ProcessHacker/include/actions.h @@ -188,14 +188,6 @@ PhUiDetachFromDebuggerProcess( _In_ PPH_PROCESS_ITEM Process ); -PHAPPAPI -BOOLEAN -NTAPI -PhUiInjectDllProcess( - _In_ HWND hWnd, - _In_ PPH_PROCESS_ITEM Process - ); - PHAPPAPI BOOLEAN NTAPI diff --git a/ProcessHacker/prpgmod.c b/ProcessHacker/prpgmod.c index 496cfe371017..ab2cdc1c647e 100644 --- a/ProcessHacker/prpgmod.c +++ b/ProcessHacker/prpgmod.c @@ -690,8 +690,6 @@ INT_PTR CALLBACK PhpProcessModulesDlgProc( PhInsertEMenuItem(menu, relocatedItem = PhCreateEMenuItem(0, PH_MODULE_FLAGS_HIGHLIGHT_RELOCATED_OPTION, L"Highlight relocated modules", NULL, NULL), -1); PhInsertEMenuItem(menu, untrustedItem = PhCreateEMenuItem(0, PH_MODULE_FLAGS_HIGHLIGHT_UNSIGNED_OPTION, L"Highlight untrusted modules", NULL, NULL), -1); PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), -1); - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, PH_MODULE_FLAGS_LOAD_MODULE_OPTION, L"Load module", NULL, NULL), -1); - PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), -1); PhInsertEMenuItem(menu, stringsItem = PhCreateEMenuItem(0, PH_MODULE_FLAGS_MODULE_STRINGS_OPTION, L"Strings...", NULL, NULL), -1); if (modulesContext->ListContext.HideDynamicModules) @@ -724,20 +722,10 @@ INT_PTR CALLBACK PhpProcessModulesDlgProc( if (selectedItem && selectedItem->Id) { - if (selectedItem->Id == PH_MODULE_FLAGS_LOAD_MODULE_OPTION) - { - PhReferenceObject(processItem); - PhUiInjectDllProcess(hwndDlg, processItem); - PhDereferenceObject(processItem); - } - else - { - PhSetOptionsModuleList(&modulesContext->ListContext, selectedItem->Id); - - PhSaveSettingsModuleList(&modulesContext->ListContext); - - PhApplyTreeNewFilters(&modulesContext->ListContext.TreeFilterSupport); - } + PhSetOptionsModuleList(&modulesContext->ListContext, selectedItem->Id); + PhSaveSettingsModuleList(&modulesContext->ListContext); + + PhApplyTreeNewFilters(&modulesContext->ListContext.TreeFilterSupport); } PhDestroyEMenu(menu); diff --git a/ProcessHacker/resource.h b/ProcessHacker/resource.h index 82c94b02a94a..7b5748ed6395 100644 --- a/ProcessHacker/resource.h +++ b/ProcessHacker/resource.h @@ -560,7 +560,6 @@ #define ID_PROCESS_AFFINITY 40035 #define ID_PROCESS_CREATEDUMPFILE 40036 #define ID_MISCELLANEOUS_DETACHFROMDEBUGGER 40039 -#define ID_MISCELLANEOUS_INJECTDLL 40041 #define ID_PRIORITY_REALTIME 40048 #define ID_PRIORITY_HIGH 40049 #define ID_WINDOW_BRINGTOFRONT 40055 diff --git a/phlib/include/phnative.h b/phlib/include/phnative.h index 14467aa734e5..8dcb3aa2b9a9 100644 --- a/phlib/include/phnative.h +++ b/phlib/include/phnative.h @@ -270,15 +270,6 @@ PhGetProcessWsCounters( _Out_ PPH_PROCESS_WS_COUNTERS WsCounters ); -PHLIBAPI -NTSTATUS -NTAPI -PhInjectDllProcess( - _In_ HANDLE ProcessHandle, - _In_ PWSTR FileName, - _In_opt_ PLARGE_INTEGER Timeout - ); - PHLIBAPI NTSTATUS NTAPI diff --git a/phlib/native.c b/phlib/native.c index 4f66d48c3d4c..dadad9f0eaaf 100644 --- a/phlib/native.c +++ b/phlib/native.c @@ -1208,138 +1208,6 @@ NTSTATUS PhGetProcessWsCounters( return status; } -/** - * Causes a process to load a DLL. - * - * \param ProcessHandle A handle to a process. The handle must have - * PROCESS_QUERY_LIMITED_INFORMATION, PROCESS_CREATE_THREAD, PROCESS_VM_OPERATION, PROCESS_VM_READ - * and PROCESS_VM_WRITE access. - * \param FileName The file name of the DLL to inject. - * \param Timeout The timeout, in milliseconds, for the process to load the DLL. - * - * \remarks If the process does not load the DLL before the timeout expires it may crash. Choose the - * timeout value carefully. - */ -NTSTATUS PhInjectDllProcess( - _In_ HANDLE ProcessHandle, - _In_ PWSTR FileName, - _In_opt_ PLARGE_INTEGER Timeout - ) -{ -#ifdef _WIN64 - static PVOID loadLibraryW32 = NULL; -#endif - - NTSTATUS status; -#ifdef _WIN64 - BOOLEAN isWow64 = FALSE; - BOOLEAN isModule32 = FALSE; - PH_MAPPED_IMAGE mappedImage; -#endif - PVOID threadStart; - PH_STRINGREF fileName; - PVOID baseAddress = NULL; - SIZE_T allocSize; - HANDLE threadHandle; - -#ifdef _WIN64 - PhGetProcessIsWow64(ProcessHandle, &isWow64); - - if (isWow64) - { - if (!NT_SUCCESS(status = PhLoadMappedImage(FileName, NULL, TRUE, &mappedImage))) - return status; - - isModule32 = mappedImage.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC; - PhUnloadMappedImage(&mappedImage); - } - - if (!isModule32) - { -#endif - threadStart = PhGetModuleProcAddress(L"kernel32.dll", "LoadLibraryW"); -#ifdef _WIN64 - } - else - { - threadStart = loadLibraryW32; - - if (!threadStart) - { - PPH_STRING kernel32FileName; - - kernel32FileName = PhConcatStrings2(USER_SHARED_DATA->NtSystemRoot, L"\\SysWow64\\kernel32.dll"); - status = PhGetProcedureAddressRemote( - ProcessHandle, - kernel32FileName->Buffer, - "LoadLibraryW", - 0, - &loadLibraryW32, - NULL - ); - PhDereferenceObject(kernel32FileName); - - if (!NT_SUCCESS(status)) - return status; - - threadStart = loadLibraryW32; - } - } -#endif - - PhInitializeStringRefLongHint(&fileName, FileName); - allocSize = fileName.Length + sizeof(WCHAR); - - if (!NT_SUCCESS(status = NtAllocateVirtualMemory( - ProcessHandle, - &baseAddress, - 0, - &allocSize, - MEM_COMMIT, - PAGE_READWRITE - ))) - return status; - - if (!NT_SUCCESS(status = NtWriteVirtualMemory( - ProcessHandle, - baseAddress, - fileName.Buffer, - fileName.Length + sizeof(WCHAR), - NULL - ))) - goto FreeExit; - - if (!NT_SUCCESS(status = RtlCreateUserThread( - ProcessHandle, - NULL, - FALSE, - 0, - 0, - 0, - threadStart, - baseAddress, - &threadHandle, - NULL - ))) - goto FreeExit; - - // Wait for the thread to finish. - status = NtWaitForSingleObject(threadHandle, FALSE, Timeout); - NtClose(threadHandle); - -FreeExit: - // Size needs to be zero if we're freeing. - allocSize = 0; - NtFreeVirtualMemory( - ProcessHandle, - &baseAddress, - &allocSize, - MEM_RELEASE - ); - - return status; -} - /** * Causes a process to unload a DLL. * From 486e6af165ff186a0a2fbe5296e722ef776ce12a Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 8 Jan 2018 04:27:26 +1100 Subject: [PATCH 0671/2058] Remove dll injection menu --- ProcessHacker/mainwnd.c | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index 0d1e77077371..23c41d4d95f0 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -1094,18 +1094,6 @@ VOID PhMwpOnCommand( } } break; - case ID_MISCELLANEOUS_INJECTDLL: - { - PPH_PROCESS_ITEM processItem = PhGetSelectedProcessItem(); - - if (processItem) - { - PhReferenceObject(processItem); - PhUiInjectDllProcess(PhMainWndHandle, processItem); - PhDereferenceObject(processItem); - } - } - break; case ID_PAGEPRIORITY_VERYLOW: case ID_PAGEPRIORITY_LOW: case ID_PAGEPRIORITY_MEDIUM: From 98eb7ebed563d22164ff8258c7459d3db1da237c Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 8 Jan 2018 04:32:07 +1100 Subject: [PATCH 0672/2058] (missing file from previous commit) --- ProcessHacker/ProcessHacker.rc | 1 - 1 file changed, 1 deletion(-) diff --git a/ProcessHacker/ProcessHacker.rc b/ProcessHacker/ProcessHacker.rc index a42887027506..c3de1b33c431 100644 --- a/ProcessHacker/ProcessHacker.rc +++ b/ProcessHacker/ProcessHacker.rc @@ -292,7 +292,6 @@ BEGIN BEGIN MENUITEM "&Detach from debugger", ID_MISCELLANEOUS_DETACHFROMDEBUGGER MENUITEM "GDI &handles", ID_MISCELLANEOUS_GDIHANDLES - MENUITEM "&Inject DLL...", ID_MISCELLANEOUS_INJECTDLL POPUP "Pa&ge priority" BEGIN MENUITEM "&Normal", ID_PAGEPRIORITY_NORMAL From 65da06e5d6ec21f884c78079967a1020ef54fb94 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 8 Jan 2018 04:35:38 +1100 Subject: [PATCH 0673/2058] Fix build --- ProcessHacker/ProcessHacker.def | 1 - 1 file changed, 1 deletion(-) diff --git a/ProcessHacker/ProcessHacker.def b/ProcessHacker/ProcessHacker.def index b77f3d95a2d3..6fe9f2e81071 100644 --- a/ProcessHacker/ProcessHacker.def +++ b/ProcessHacker/ProcessHacker.def @@ -283,7 +283,6 @@ EXPORTS PhGetTokenPrivileges PhGetTokenUser PhImpersonateClientOfNamedPipe - PhInjectDllProcess PhListenNamedPipe PhOpenKey PhLoadAppKey From 13f70744c2d2f2f8014db8088d5f222091399aa5 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 14 Jan 2018 00:56:15 +1100 Subject: [PATCH 0674/2058] peview: Add symbol tab enumeration workaround for data symbols, Fix symbol tab sorting --- tools/peview/include/peview.h | 1 - tools/peview/pdb.c | 48 +++++++++++++++--- tools/peview/pdbprp.c | 92 ++++++++++++++++++++++++----------- 3 files changed, 105 insertions(+), 36 deletions(-) diff --git a/tools/peview/include/peview.h b/tools/peview/include/peview.h index 912c73869622..75fdeaf11ce3 100644 --- a/tools/peview/include/peview.h +++ b/tools/peview/include/peview.h @@ -134,7 +134,6 @@ typedef struct _PV_SYMBOL_NODE { PH_TREENEW_NODE Node; - ULONG64 Index; PV_SYMBOL_TYPE Type; ULONG Size; ULONG64 Address; diff --git a/tools/peview/pdb.c b/tools/peview/pdb.c index 53239934e5f2..d18dec6485c6 100644 --- a/tools/peview/pdb.c +++ b/tools/peview/pdb.c @@ -59,6 +59,18 @@ typedef BOOL (WINAPI *_SymEnumTypesW)( _In_opt_ PVOID UserContext ); +typedef BOOL (WINAPI *_SymSearchW)( + _In_ HANDLE hProcess, + _In_ ULONG64 BaseOfDll, + _In_opt_ DWORD Index, + _In_opt_ DWORD SymTag, + _In_opt_ PCWSTR Mask, + _In_opt_ DWORD64 Address, + _In_ PSYM_ENUMERATESYMBOLS_CALLBACKW EnumSymbolsCallback, + _In_opt_ PVOID UserContext, + _In_ DWORD Options + ); + typedef BOOL (WINAPI *_SymSetSearchPathW)( _In_ HANDLE hProcess, _In_opt_ PCWSTR SearchPath @@ -112,6 +124,7 @@ _SymGetModuleInfoW64 SymGetModuleInfoW64_I = NULL; _SymGetTypeFromNameW SymGetTypeFromNameW_I = NULL; _SymGetTypeInfo SymGetTypeInfo_I = NULL; _SymSetContext SymSetContext_I = NULL; +_SymSearchW SymSearchW_I = NULL; ULONG SearchResultsAddIndex = 0; PPH_LIST SearchResults = NULL; @@ -1932,9 +1945,8 @@ BOOL CALLBACK EnumCallbackProc( PPDB_SYMBOL_CONTEXT context = Context; PPV_SYMBOL_NODE symbol; - // TODO: Remove filter - //if (SymbolInfo->Tag != SymTagPublicSymbol) - // break; + if (SymbolInfo->Address == 0) + break; symbol = PhAllocate(sizeof(PV_SYMBOL_NODE)); memset(symbol, 0, sizeof(PV_SYMBOL_NODE)); @@ -1942,10 +1954,17 @@ BOOL CALLBACK EnumCallbackProc( symbol->Type = PV_SYMBOL_TYPE_SYMBOL; symbol->Address = SymbolInfo->Address; symbol->Size = SymbolInfo->Size; - symbol->Name = PhCreateStringEx(SymbolInfo->Name, SymbolInfo->NameLen * sizeof(WCHAR)); symbol->Data = SymbolInfo_GetTypeName(context, SymbolInfo->TypeIndex, SymbolInfo->Name); SymbolInfo_SymbolLocationStr(SymbolInfo, symbol->Pointer); + if (SymbolInfo->Name[0]) // HACK + { + if (SymbolInfo->NameLen) + symbol->Name = PhCreateStringEx(SymbolInfo->Name, SymbolInfo->NameLen * sizeof(WCHAR)); + else + symbol->Name = PhCreateString(SymbolInfo->Name); + } + PhAcquireQueuedLockExclusive(&SearchResultsLock); PhAddItemList(SearchResults, symbol); PhReleaseQueuedLockExclusive(&SearchResultsLock); @@ -2327,6 +2346,7 @@ NTSTATUS PeDumpFileSymbols( SymGetTypeFromNameW_I = PhGetProcedureAddress(dbghelpHandle, "SymGetTypeFromNameW", 0); SymGetTypeInfo_I = PhGetProcedureAddress(dbghelpHandle, "SymGetTypeInfo", 0); SymSetContext_I = PhGetProcedureAddress(dbghelpHandle, "SymSetContext", 0); + SymSearchW_I = PhGetProcedureAddress(dbghelpHandle, "SymSearchW", 0); SymSetOptions_I( SymGetOptions_I() | @@ -2372,9 +2392,25 @@ NTSTATUS PeDumpFileSymbols( //ShowModuleSymbolInfo(symbolBaseAddress); SymEnumSymbolsW_I(NtCurrentProcess(), Context->BaseAddress, NULL, EnumCallbackProc, Context); - // Enumerate user defined types - //PrintUserDefinedTypes(Context); + // Enumerate user defined types. SymEnumTypesW_I(NtCurrentProcess(), Context->BaseAddress, EnumCallbackProc, Context); + //PrintUserDefinedTypes(Context); // Commented out due to verbosity. + + // NOTE: The SymEnumSymbolsW and SymEnumTypesW functions don't enumerate exported DATA symbols such as + // as PsActiveProcessHead and PsLoadedModuleList from ntoskrnl.exe?? + // TODO: SymSearchW does enumerate those symbols but we'll need to filter out duplicate symbol entries properly or + // find out why the SymEnumSymbolsW and SymEnumTypesW functions can't enumerate those symbols. + SymSearchW_I( + NtCurrentProcess(), + Context->BaseAddress, + 0, + 0, + NULL, + 0, + EnumCallbackProc, + Context, + SYMSEARCH_RECURSE | SYMSEARCH_ALLITEMS + ); } CleanupExit: diff --git a/tools/peview/pdbprp.c b/tools/peview/pdbprp.c index fb8bc689a367..e523b8e302c5 100644 --- a/tools/peview/pdbprp.c +++ b/tools/peview/pdbprp.c @@ -406,7 +406,7 @@ ULONG SymbolNodeHashtableHashFunction( _In_ PVOID Entry ) { - return PhHashInt64((*(PPV_SYMBOL_NODE*)Entry)->Index); + return PhHashStringRef(&(*(PPV_SYMBOL_NODE*)Entry)->Name->sr, TRUE); } VOID PvSymbolAddTreeNode( @@ -414,21 +414,20 @@ VOID PvSymbolAddTreeNode( _In_ PPV_SYMBOL_NODE Entry ) { - static ULONG64 index = 0; - PhInitializeTreeNewNode(&Entry->Node); - Entry->Index = index++; memset(Entry->TextCache, 0, sizeof(PH_STRINGREF) * TREE_COLUMN_ITEM_MAXIMUM); Entry->Node.TextCache = Entry->TextCache; Entry->Node.TextCacheSize = TREE_COLUMN_ITEM_MAXIMUM; - PhAddEntryHashtable(Context->NodeHashtable, &Entry); - PhAddItemList(Context->NodeList, Entry); - - if (Context->FilterSupport.NodeList) + if (PhAddEntryHashtable(Context->NodeHashtable, &Entry)) // HACK { - Entry->Node.Visible = PhApplyTreeNewFiltersToNode(&Context->FilterSupport, &Entry->Node); + PhAddItemList(Context->NodeList, Entry); + + if (Context->FilterSupport.NodeList) + { + Entry->Node.Visible = PhApplyTreeNewFiltersToNode(&Context->FilterSupport, &Entry->Node); + } } } @@ -437,15 +436,21 @@ PPV_SYMBOL_NODE PvFindSymbolNode( _In_ PPH_STRING Name ) { - for (ULONG i = 0; i < Context->NodeList->Count; i++) - { - PPV_SYMBOL_NODE entry = Context->NodeList->Items[i]; + PV_SYMBOL_NODE lookupSymbolNode; + PPV_SYMBOL_NODE lookupSymbolNodePtr = &lookupSymbolNode; + PPV_SYMBOL_NODE *threadNode; - if (PhEqualString(entry->Name, Name, TRUE)) - return entry; - } + lookupSymbolNode.Name = Name; - return NULL; + threadNode = (PPV_SYMBOL_NODE *)PhFindEntryHashtable( + Context->NodeHashtable, + &lookupSymbolNodePtr + ); + + if (threadNode) + return *threadNode; + else + return NULL; } VOID PvRemoveSymbolNode( @@ -482,36 +487,51 @@ VOID PvDestroySymbolNode( int sortResult = 0; #define END_SORT_FUNCTION \ - if (sortResult == 0) \ - sortResult = uintptrcmp((ULONG_PTR)node1->Node.Index, (ULONG_PTR)node2->Node.Index); \ - \ + /*if (sortResult == 0) \ + // sortResult = uintptrcmp((ULONG_PTR)node1->Node.Index, (ULONG_PTR)node2->Node.Index); \ + */\ return PhModifySort(sortResult, ((PPDB_SYMBOL_CONTEXT)_context)->TreeNewSortOrder); \ } -BEGIN_SORT_FUNCTION(Symbol) +BEGIN_SORT_FUNCTION(Type) { - sortResult = PhCompareString(node1->Name, node2->Name, FALSE); + sortResult = uintptrcmp((ULONG_PTR)node1->Type, (ULONG_PTR)node2->Type); } END_SORT_FUNCTION BEGIN_SORT_FUNCTION(VA) { sortResult = uintptrcmp((ULONG_PTR)node1->Address, (ULONG_PTR)node2->Address); + + if (sortResult == 0) + sortResult = uintptrcmp((ULONG_PTR)node1->Node.Index, (ULONG_PTR)node2->Node.Index); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(Symbol) +{ + sortResult = PhCompareStringWithNull(node1->Name, node2->Name, FALSE); } END_SORT_FUNCTION -BEGIN_SORT_FUNCTION(Name) +BEGIN_SORT_FUNCTION(Data) { - sortResult = PhCompareString(node1->Name, node2->Name, FALSE); + sortResult = PhCompareStringWithNull(node1->Data, node2->Data, FALSE); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(Size) +{ + sortResult = uintcmp(node1->Size, node2->Size); } END_SORT_FUNCTION BOOLEAN NTAPI PvSymbolTreeNewCallback( _In_ HWND hwnd, _In_ PH_TREENEW_MESSAGE Message, - __in_opt PVOID Parameter1, - __in_opt PVOID Parameter2, - __in_opt PVOID Context + _In_opt_ PVOID Parameter1, + _In_opt_ PVOID Parameter2, + _In_opt_ PVOID Context ) { PPDB_SYMBOL_CONTEXT context; @@ -530,9 +550,11 @@ BOOLEAN NTAPI PvSymbolTreeNewCallback( { static PVOID sortFunctions[] = { - SORT_FUNCTION(Name), + SORT_FUNCTION(Type), SORT_FUNCTION(VA), - SORT_FUNCTION(Symbol) + SORT_FUNCTION(Symbol), + SORT_FUNCTION(Data), + SORT_FUNCTION(Size) }; int (__cdecl *sortFunction)(void *, const void *, const void *); @@ -765,7 +787,7 @@ VOID PvInitializeSymbolTree( PhAddTreeNewColumnEx2(TreeNewHandle, TREE_COLUMN_ITEM_SYMBOL, TRUE, L"Data", 150, PH_ALIGN_LEFT, TREE_COLUMN_ITEM_SYMBOL, 0, 0); PhAddTreeNewColumnEx2(TreeNewHandle, TREE_COLUMN_ITEM_SIZE, TRUE, L"Size", 40, PH_ALIGN_LEFT, TREE_COLUMN_ITEM_SIZE, 0, 0); - TreeNew_SetSort(TreeNewHandle, 0, NoSortOrder); + TreeNew_SetSort(TreeNewHandle, TREE_COLUMN_ITEM_VA, AscendingSortOrder); PPH_STRING settings = PhGetStringSetting(L"PdbTreeListColumns"); PhCmLoadSettings(TreeNewHandle, &settings->sr); @@ -1043,6 +1065,18 @@ INT_PTR CALLBACK PvpSymbolsDlgProc( //NtWaitForSingleObject(context->SearchThreadHandle, FALSE, NULL); //SearchStop = FALSE; + + //if (context->UpdateTimerHandle) + //{ + // RtlDeleteTimer(context->TimerQueueHandle, context->UpdateTimerHandle, NULL); + // context->UpdateTimerHandle = NULL; + //} + + //if (context->TimerQueueHandle) + //{ + // RtlDeleteTimerQueue(context->TimerQueueHandle); + // context->TimerQueueHandle = NULL; + //} } break; case WM_NOTIFY: From 247bb7ce433173b014ebbf20ecfe32b4184f2ee2 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 14 Jan 2018 00:57:23 +1100 Subject: [PATCH 0675/2058] peview: Fix resources tab string termination --- tools/peview/resprp.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/tools/peview/resprp.c b/tools/peview/resprp.c index 59ac129adfae..0877b0b24f23 100644 --- a/tools/peview/resprp.c +++ b/tools/peview/resprp.c @@ -113,7 +113,7 @@ INT_PTR CALLBACK PvpPeResourcesDlgProc( { for (i = 0; i < resources.NumberOfEntries; i++) { - PVOID string; + PPH_STRING string; WCHAR number[PH_INT32_STR_LEN_1]; entry = resources.ResourceEntries[i]; @@ -129,10 +129,10 @@ INT_PTR CALLBACK PvpPeResourcesDlgProc( { PIMAGE_RESOURCE_DIR_STRING_U resourceString = (PIMAGE_RESOURCE_DIR_STRING_U)entry.Type; - string = PhAllocateCopy(resourceString->NameString, resourceString->Length * sizeof(WCHAR)); + string = PhCreateStringEx(resourceString->NameString, resourceString->Length * sizeof(WCHAR)); - PhSetListViewSubItem(lvHandle, lvItemIndex, PVE_RESOURCES_COLUMN_INDEX_TYPE, string); - PhFree(string); + PhSetListViewSubItem(lvHandle, lvItemIndex, PVE_RESOURCES_COLUMN_INDEX_TYPE, string->Buffer); + PhDereferenceObject(string); } if (IS_INTRESOURCE(entry.Name)) @@ -144,10 +144,10 @@ INT_PTR CALLBACK PvpPeResourcesDlgProc( { PIMAGE_RESOURCE_DIR_STRING_U resourceString = (PIMAGE_RESOURCE_DIR_STRING_U)entry.Name; - string = PhAllocateCopy(resourceString->NameString, resourceString->Length * sizeof(WCHAR)); + string = PhCreateStringEx(resourceString->NameString, resourceString->Length * sizeof(WCHAR)); - PhSetListViewSubItem(lvHandle, lvItemIndex, PVE_RESOURCES_COLUMN_INDEX_NAME, string); - PhFree(string); + PhSetListViewSubItem(lvHandle, lvItemIndex, PVE_RESOURCES_COLUMN_INDEX_NAME, string->Buffer); + PhDereferenceObject(string); } if (IS_INTRESOURCE(entry.Language)) @@ -165,10 +165,10 @@ INT_PTR CALLBACK PvpPeResourcesDlgProc( { PIMAGE_RESOURCE_DIR_STRING_U resourceString = (PIMAGE_RESOURCE_DIR_STRING_U)entry.Language; - string = PhAllocateCopy(resourceString->NameString, resourceString->Length * sizeof(WCHAR)); + string = PhCreateStringEx(resourceString->NameString, resourceString->Length * sizeof(WCHAR)); - PhSetListViewSubItem(lvHandle, lvItemIndex, PVE_RESOURCES_COLUMN_INDEX_LCID, string); - PhFree(string); + PhSetListViewSubItem(lvHandle, lvItemIndex, PVE_RESOURCES_COLUMN_INDEX_LCID, string->Buffer); + PhDereferenceObject(string); } PhSetListViewSubItem(lvHandle, lvItemIndex, PVE_RESOURCES_COLUMN_INDEX_SIZE, PhaFormatSize(entry.Size, -1)->Buffer); From 1bf61b3ac1c792f134d2ddcb3a19fa46c455e297 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 14 Jan 2018 21:53:16 +1100 Subject: [PATCH 0676/2058] peview: fix typo --- tools/peview/exlfexports.c | 2 +- tools/peview/exlfimports.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/peview/exlfexports.c b/tools/peview/exlfexports.c index 80088eed1d04..fda3971a57f0 100644 --- a/tools/peview/exlfexports.c +++ b/tools/peview/exlfexports.c @@ -41,7 +41,7 @@ VOID PvpProcessElfExports( if (!export->ExportSymbol) continue; - PhPrintUInt64(number, count++); + PhPrintUInt64(number, ++count); lvItemIndex = PhAddListViewItem(ListViewHandle, MAXINT, number, NULL); PhPrintPointer(pointer, (PVOID)export->Address); diff --git a/tools/peview/exlfimports.c b/tools/peview/exlfimports.c index 3170d6dbc785..9e6368e40968 100644 --- a/tools/peview/exlfimports.c +++ b/tools/peview/exlfimports.c @@ -40,7 +40,7 @@ VOID PvpProcessElfImports( if (!import->ImportSymbol) continue; - PhPrintUInt64(number, count++); + PhPrintUInt64(number, ++count); lvItemIndex = PhAddListViewItem(ListViewHandle, MAXINT, number, NULL); PhSetListViewSubItem(ListViewHandle, lvItemIndex, 1, import->Module); From 870f86fe6785a9df9f3b922f44ba3b4a32999555 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 15 Jan 2018 02:07:27 +1100 Subject: [PATCH 0677/2058] Move process flags for PR #222 --- ProcessHacker/procprv.c | 45 ++++++++++++++++------------------------- 1 file changed, 17 insertions(+), 28 deletions(-) diff --git a/ProcessHacker/procprv.c b/ProcessHacker/procprv.c index ef63c2daab28..e487607e27d3 100644 --- a/ProcessHacker/procprv.c +++ b/ProcessHacker/procprv.c @@ -105,16 +105,10 @@ typedef struct _PH_PROCESS_QUERY_S1_DATA ULONG IsElevated : 1; ULONG IsInJob : 1; ULONG IsInSignificantJob : 1; - ULONG IsWow64 : 1; - ULONG IsWow64Valid : 1; - ULONG IsProtectedProcess : 1; - ULONG IsSecureProcess : 1; - ULONG IsSubsystemProcess : 1; - ULONG IsBeingDebugged : 1; ULONG IsImmersive : 1; - ULONG Spare : 21; + ULONG Spare : 26; }; }; } PH_PROCESS_QUERY_S1_DATA, *PPH_PROCESS_QUERY_S1_DATA; @@ -991,21 +985,6 @@ VOID PhpProcessQueryStage1( } } - // Process flags - if (processHandleLimited) - { - PROCESS_EXTENDED_BASIC_INFORMATION basicInfo; - - if (NT_SUCCESS(PhGetProcessExtendedBasicInformation(processHandleLimited, &basicInfo))) - { - Data->IsProtectedProcess = basicInfo.IsProtectedProcess; - Data->IsSecureProcess = basicInfo.IsSecureProcess; - Data->IsSubsystemProcess = basicInfo.IsSubsystemProcess; - Data->IsWow64 = basicInfo.IsWow64Process; - Data->IsWow64Valid = TRUE; - } - } - // Debugged if (processHandleLimited) { @@ -1046,7 +1025,7 @@ VOID PhpProcessQueryStage1( processId, processHandle, #ifdef _WIN64 - processQueryFlags | PH_CLR_NO_WOW64_CHECK | (Data->IsWow64 ? PH_CLR_KNOWN_IS_WOW64 : 0), + processQueryFlags | PH_CLR_NO_WOW64_CHECK | (processItem->IsWow64 ? PH_CLR_KNOWN_IS_WOW64 : 0), #else processQueryFlags, #endif @@ -1309,11 +1288,6 @@ VOID PhpFillProcessItemStage1( processItem->IsElevated = Data->IsElevated; processItem->IsInJob = Data->IsInJob; processItem->IsInSignificantJob = Data->IsInSignificantJob; - processItem->IsWow64 = Data->IsWow64; - processItem->IsWow64Valid = Data->IsWow64Valid; - processItem->IsProtectedProcess = Data->IsProtectedProcess; - processItem->IsSecureProcess = Data->IsSecureProcess; - processItem->IsSubsystemProcess = Data->IsSubsystemProcess; processItem->IsBeingDebugged = Data->IsBeingDebugged; processItem->IsImmersive = Data->IsImmersive; @@ -1377,6 +1351,21 @@ VOID PhpFillProcessItem( PhOpenProcess(&ProcessItem->QueryHandle, PROCESS_QUERY_LIMITED_INFORMATION, ProcessItem->ProcessId); } + // Process flags + if (ProcessItem->QueryHandle) + { + PROCESS_EXTENDED_BASIC_INFORMATION basicInfo; + + if (NT_SUCCESS(PhGetProcessExtendedBasicInformation(ProcessItem->QueryHandle, &basicInfo))) + { + ProcessItem->IsProtectedProcess = basicInfo.IsProtectedProcess; + ProcessItem->IsSecureProcess = basicInfo.IsSecureProcess; + ProcessItem->IsSubsystemProcess = basicInfo.IsSubsystemProcess; + ProcessItem->IsWow64 = basicInfo.IsWow64Process; + ProcessItem->IsWow64Valid = TRUE; + } + } + // Process information { // If we're dealing with System (PID 4), we need to get the From 1553dc0272bb36b648a1e6ba4efd89fdf8f78595 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 15 Jan 2018 12:14:19 +1100 Subject: [PATCH 0678/2058] peview: Add symbols tab copy menu --- tools/peview/include/peview.h | 1 + tools/peview/pdb.c | 12 ++- tools/peview/pdbprp.c | 176 ++++++++++++++++++++++++++++++---- tools/peview/resource.h | 4 - 4 files changed, 171 insertions(+), 22 deletions(-) diff --git a/tools/peview/include/peview.h b/tools/peview/include/peview.h index 75fdeaf11ce3..105ddca4d85c 100644 --- a/tools/peview/include/peview.h +++ b/tools/peview/include/peview.h @@ -92,6 +92,7 @@ VOID PeSaveSettings( // symbols #define WM_PV_SEARCH_FINISHED (WM_APP + 701) +#define WM_PV_SEARCH_SHOWMENU (WM_APP + 702) extern ULONG SearchResultsAddIndex; extern PPH_LIST SearchResults; diff --git a/tools/peview/pdb.c b/tools/peview/pdb.c index d18dec6485c6..2a668eba64f6 100644 --- a/tools/peview/pdb.c +++ b/tools/peview/pdb.c @@ -1305,8 +1305,13 @@ BOOLEAN SymbolInfo_GetTypeNameHelper( switch (Info.Tag) { case SymTagBaseType: - PhAppendStringBuilder2(TypeName, SymbolInfo_BaseTypeStr(Info.BaseTypeInfo.BaseType, Info.BaseTypeInfo.Length)); - PhAppendStringBuilder2(TypeName, L" "); + { + if (Info.BaseTypeInfo.Length == 0) + break; + + PhAppendStringBuilder2(TypeName, SymbolInfo_BaseTypeStr(Info.BaseTypeInfo.BaseType, Info.BaseTypeInfo.Length)); + PhAppendStringBuilder2(TypeName, L" "); + } break; case SymTagTypedef: PhAppendStringBuilder2(TypeName, Info.TypedefInfo.Name); @@ -1435,7 +1440,10 @@ PPH_STRING SymbolInfo_GetTypeName( typeVarName = VarName; if (!SymbolInfo_GetTypeNameHelper(Index, Context, &typeVarName, &typeNamesb)) + { + PhDeleteStringBuilder(&typeNamesb); return NULL; + } return PhFinalStringBuilderString(&typeNamesb); } diff --git a/tools/peview/pdbprp.c b/tools/peview/pdbprp.c index e523b8e302c5..d6b471f28854 100644 --- a/tools/peview/pdbprp.c +++ b/tools/peview/pdbprp.c @@ -25,6 +25,8 @@ #include #include "colmgr.h" +#pragma region copied from appsup.c + VOID PhInitializeTreeNewColumnMenu( _Inout_ PPH_TN_COLUMN_MENU_DATA Data ) @@ -356,6 +358,123 @@ VOID PhApplyTreeNewFilters( TreeNew_NodesStructured(Support->TreeNewHandle); } +#define ID_COPY_CELL 136 +#define ID_SYMBOL_COPY 40201 + +typedef struct _PH_COPY_CELL_CONTEXT +{ + HWND TreeNewHandle; + ULONG Id; // column ID + PPH_STRING MenuItemText; +} PH_COPY_CELL_CONTEXT, *PPH_COPY_CELL_CONTEXT; + +VOID NTAPI PhpCopyCellEMenuItemDeleteFunction( + _In_ struct _PH_EMENU_ITEM *Item + ) +{ + PPH_COPY_CELL_CONTEXT context; + + context = Item->Context; + PhDereferenceObject(context->MenuItemText); + PhFree(context); +} + +BOOLEAN PhInsertCopyCellEMenuItem( + _In_ struct _PH_EMENU_ITEM *Menu, + _In_ ULONG InsertAfterId, + _In_ HWND TreeNewHandle, + _In_ PPH_TREENEW_COLUMN Column + ) +{ + PPH_EMENU_ITEM parentItem; + ULONG indexInParent; + PPH_COPY_CELL_CONTEXT context; + PH_STRINGREF columnText; + PPH_STRING escapedText; + PPH_STRING menuItemText; + PPH_EMENU_ITEM copyCellItem; + + if (!Column) + return FALSE; + + if (!PhFindEMenuItemEx(Menu, 0, NULL, InsertAfterId, &parentItem, &indexInParent)) + return FALSE; + + indexInParent++; + + context = PhAllocate(sizeof(PH_COPY_CELL_CONTEXT)); + context->TreeNewHandle = TreeNewHandle; + context->Id = Column->Id; + + PhInitializeStringRef(&columnText, Column->Text); + escapedText = PhEscapeStringForMenuPrefix(&columnText); + menuItemText = PhFormatString(L"Copy \"%s\"", escapedText->Buffer); + PhDereferenceObject(escapedText); + copyCellItem = PhCreateEMenuItem(0, ID_COPY_CELL, menuItemText->Buffer, NULL, context); + copyCellItem->DeleteFunction = PhpCopyCellEMenuItemDeleteFunction; + context->MenuItemText = menuItemText; + + if (Column->CustomDraw) + copyCellItem->Flags |= PH_EMENU_DISABLED; + + PhInsertEMenuItem(parentItem, copyCellItem, indexInParent); + + return TRUE; +} + +BOOLEAN PhHandleCopyCellEMenuItem( + _In_ struct _PH_EMENU_ITEM *SelectedItem + ) +{ + PPH_COPY_CELL_CONTEXT context; + PH_STRING_BUILDER stringBuilder; + ULONG count; + ULONG selectedCount; + ULONG i; + PPH_TREENEW_NODE node; + PH_TREENEW_GET_CELL_TEXT getCellText; + + if (!SelectedItem) + return FALSE; + if (SelectedItem->Id != ID_COPY_CELL) + return FALSE; + + context = SelectedItem->Context; + + PhInitializeStringBuilder(&stringBuilder, 0x100); + count = TreeNew_GetFlatNodeCount(context->TreeNewHandle); + selectedCount = 0; + + for (i = 0; i < count; i++) + { + node = TreeNew_GetFlatNode(context->TreeNewHandle, i); + + if (node && node->Selected) + { + selectedCount++; + + getCellText.Flags = 0; + getCellText.Node = node; + getCellText.Id = context->Id; + PhInitializeEmptyStringRef(&getCellText.Text); + TreeNew_GetCellText(context->TreeNewHandle, &getCellText); + + PhAppendStringBuilder(&stringBuilder, &getCellText.Text); + PhAppendStringBuilder2(&stringBuilder, L"\r\n"); + } + } + + if (stringBuilder.String->Length != 0 && selectedCount == 1) + PhRemoveEndStringBuilder(&stringBuilder, 2); + + PhSetClipboardString(context->TreeNewHandle, &stringBuilder.String->sr); + PhDeleteStringBuilder(&stringBuilder); + + return TRUE; +} + +#pragma endregion + BOOLEAN SymbolNodeHashtableCompareFunction( _In_ PVOID Entry1, _In_ PVOID Entry2 @@ -687,9 +806,9 @@ BOOLEAN NTAPI PvSymbolTreeNewCallback( return TRUE; case TreeNewContextMenu: { - PPH_TREENEW_MOUSE_EVENT mouseEvent = (PPH_TREENEW_MOUSE_EVENT)Parameter1; + PPH_TREENEW_CONTEXT_MENU contextMenu = Parameter1; - //SendMessage(context->ParentWindowHandle, WM_COMMAND, ID_WCTSHOWCONTEXTMENU, MAKELONG(mouseEvent->Location.x, mouseEvent->Location.y)); + SendMessage(context->ParentWindowHandle, WM_PV_SEARCH_SHOWMENU, 0, (LPARAM)contextMenu); } return TRUE; case TreeNewHeaderRightClick: @@ -978,9 +1097,6 @@ INT_PTR CALLBACK PvpSymbolsDlgProc( PvInitializeSymbolTree(context, hwndDlg, context->TreeNewHandle); PhAddTreeNewFilter(GetSymbolListFilterSupport(context), PvSymbolTreeFilterCallback, context); - PhSetWindowStyle(GetDlgItem(hwndDlg, IDC_PROGRESS), PBS_MARQUEE, PBS_MARQUEE); - SendMessage(GetDlgItem(hwndDlg, IDC_PROGRESS), PBM_SETMARQUEE, TRUE, 75); - SearchResults = PhCreateList(0x1000); context->UdtList = PhCreateList(0x100); @@ -1079,23 +1195,51 @@ INT_PTR CALLBACK PvpSymbolsDlgProc( //} } break; - case WM_NOTIFY: + case WM_PV_SEARCH_SHOWMENU: { - LPNMHDR header = (LPNMHDR)lParam; - LPPSHNOTIFY pageNotify = (LPPSHNOTIFY)header; + PPH_TREENEW_CONTEXT_MENU contextMenuEvent = (PPH_TREENEW_CONTEXT_MENU)lParam; + PPH_EMENU menu; + PPH_EMENU_ITEM selectedItem; + PPV_SYMBOL_NODE *symbolNodes = NULL; + ULONG numberOfSymbolNodes = 0; + + PvGetSelectedSymbolNodes(context, &symbolNodes, &numberOfSymbolNodes); - switch (pageNotify->hdr.code) + if (numberOfSymbolNodes != 0) { - case PSN_SETACTIVE: - PostMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(GetParent(hwndDlg), IDCANCEL), TRUE); // HACK - break; - case PSN_QUERYINITIALFOCUS: - SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, (LPARAM)GetDlgItem(GetParent(hwndDlg), IDCANCEL)); - return TRUE; + menu = PhCreateEMenu(); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_SYMBOL_COPY, L"Copy", NULL, NULL), -1); + PhInsertCopyCellEMenuItem(menu, ID_SYMBOL_COPY, context->TreeNewHandle, contextMenuEvent->Column); + + selectedItem = PhShowEMenu( + menu, + hwndDlg, + PH_EMENU_SHOW_SEND_COMMAND | PH_EMENU_SHOW_LEFTRIGHT, + PH_ALIGN_LEFT | PH_ALIGN_TOP, + contextMenuEvent->Location.x, + contextMenuEvent->Location.y + ); + + if (selectedItem && selectedItem->Id != -1) + { + BOOLEAN handled = FALSE; + + handled = PhHandleCopyCellEMenuItem(selectedItem); + + if (!handled && selectedItem->Id == ID_SYMBOL_COPY) + { + PPH_STRING text; + + text = PhGetTreeNewText(context->TreeNewHandle, 0); + PhSetClipboardString(context->TreeNewHandle, &text->sr); + PhDereferenceObject(text); + } + } + + PhDestroyEMenu(menu); } } break; - } return FALSE; diff --git a/tools/peview/resource.h b/tools/peview/resource.h index 67a136b18427..7c67918dd9ab 100644 --- a/tools/peview/resource.h +++ b/tools/peview/resource.h @@ -24,7 +24,6 @@ #define IDC_CHARACTERISTICS 1007 #define IDC_LIST 1008 #define IDC_FILEICON 1009 -#define IDC_SECTION 1009 #define IDC_TIMESTAMP 1010 #define IDC_RUNTIMEVERSION 1011 #define IDC_FILE 1011 @@ -35,12 +34,9 @@ #define IDC_IMAGEBASE 1015 #define IDC_ENTRYPOINT 1016 #define IDC_SYMSEARCH 1017 -#define IDC_IMAGEBASE2 1017 #define IDC_IMAGETYPE 1017 #define IDC_NAME 1019 #define IDC_COMPANYNAME_LINK 1020 -#define IDC_STOP 1021 -#define IDC_PROGRESS 1022 // Next default values for new objects // From 08ce139e2d3ae7cee20709232e9495b29387431f Mon Sep 17 00:00:00 2001 From: ge0rdi Date: Mon, 15 Jan 2018 08:06:33 +0100 Subject: [PATCH 0679/2058] Add option to control tree list border (TreeListBorderEnable) (#225) * Don't show border in main tabs * Add option to control tree list border (TreeListBorderEnable) --- ProcessHacker/mainwnd.c | 8 +++++--- ProcessHacker/settings.c | 1 + plugins/ExtendedTools/disktab.c | 4 +++- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index 23c41d4d95f0..659779f72d12 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -394,6 +394,7 @@ VOID PhMwpInitializeControls( ) { ULONG thinRows; + ULONG treelistBorder; TabControlHandle = CreateWindow( WC_TABCONTROL, @@ -412,11 +413,12 @@ VOID PhMwpInitializeControls( BringWindowToTop(TabControlHandle); thinRows = PhGetIntegerSetting(L"ThinRows") ? TN_STYLE_THIN_ROWS : 0; + treelistBorder = PhGetIntegerSetting(L"TreeListBorderEnable") ? WS_BORDER : 0; PhMwpProcessTreeNewHandle = CreateWindow( PH_TREENEW_CLASSNAME, NULL, - WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_BORDER | TN_STYLE_ICONS | TN_STYLE_DOUBLE_BUFFERED | TN_STYLE_ANIMATE_DIVIDER | thinRows, + WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | TN_STYLE_ICONS | TN_STYLE_DOUBLE_BUFFERED | TN_STYLE_ANIMATE_DIVIDER | thinRows | treelistBorder, 0, 0, 3, @@ -431,7 +433,7 @@ VOID PhMwpInitializeControls( PhMwpServiceTreeNewHandle = CreateWindow( PH_TREENEW_CLASSNAME, NULL, - WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_BORDER | TN_STYLE_ICONS | TN_STYLE_DOUBLE_BUFFERED | thinRows, + WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | TN_STYLE_ICONS | TN_STYLE_DOUBLE_BUFFERED | thinRows | treelistBorder, 0, 0, 3, @@ -446,7 +448,7 @@ VOID PhMwpInitializeControls( PhMwpNetworkTreeNewHandle = CreateWindow( PH_TREENEW_CLASSNAME, NULL, - WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_BORDER | TN_STYLE_ICONS | TN_STYLE_DOUBLE_BUFFERED | thinRows, + WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | TN_STYLE_ICONS | TN_STYLE_DOUBLE_BUFFERED | thinRows | treelistBorder, 0, 0, 3, diff --git a/ProcessHacker/settings.c b/ProcessHacker/settings.c index d7235af1a9e2..2021120adece 100644 --- a/ProcessHacker/settings.c +++ b/ProcessHacker/settings.c @@ -164,6 +164,7 @@ VOID PhAddDefaultSettings( PhpAddIntegerSetting(L"TokenSplitterEnable", L"0"); PhpAddIntegerSetting(L"TokenSplitterPosition", L"150"); PhpAddStringSetting(L"TokenPrivilegesListViewColumns", L""); + PhpAddIntegerSetting(L"TreeListBorderEnable", L"1"); PhpAddIntegerSetting(L"UpdateInterval", L"3e8"); // 1000ms PhpAddIntegerSetting(L"WmiProviderEnableHiddenMenu", L"0"); PhpAddStringSetting(L"WmiProviderListViewColumns", L""); diff --git a/plugins/ExtendedTools/disktab.c b/plugins/ExtendedTools/disktab.c index f669e3cc93ae..55a873d0d19e 100644 --- a/plugins/ExtendedTools/disktab.c +++ b/plugins/ExtendedTools/disktab.c @@ -91,12 +91,14 @@ BOOLEAN EtpDiskPageCallback( if (EtEtwEnabled) { ULONG thinRows; + ULONG treelistBorder; thinRows = PhGetIntegerSetting(L"ThinRows") ? TN_STYLE_THIN_ROWS : 0; + treelistBorder = PhGetIntegerSetting(L"TreeListBorderEnable") ? WS_BORDER : 0; hwnd = CreateWindow( PH_TREENEW_CLASSNAME, NULL, - WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_BORDER | TN_STYLE_ICONS | TN_STYLE_DOUBLE_BUFFERED | thinRows, + WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | TN_STYLE_ICONS | TN_STYLE_DOUBLE_BUFFERED | thinRows | treelistBorder, 0, 0, 3, From 7ff4a1a81356ea848bbbcc9493af328ad87adb4c Mon Sep 17 00:00:00 2001 From: ge0rdi Date: Mon, 15 Jan 2018 11:35:36 +0100 Subject: [PATCH 0680/2058] Improve behavior of "Protection" column in process tree (#222) --- ProcessHacker/procprv.c | 8 ++++++++ ProcessHacker/proctree.c | 7 +++++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/ProcessHacker/procprv.c b/ProcessHacker/procprv.c index e487607e27d3..75136885980f 100644 --- a/ProcessHacker/procprv.c +++ b/ProcessHacker/procprv.c @@ -1460,9 +1460,17 @@ VOID PhpFillProcessItem( ProcessItem->Protection.Level = protection.Level; } } + else + { + // "emulate" PS_PROTECTION info for older OSes + if (ProcessItem->IsProtectedProcess) + ProcessItem->Protection.Type = PsProtectedTypeProtected; + } } else { + // we weren't able to get protection info + // lets signalize that with special value ProcessItem->Protection.Level = UCHAR_MAX; } diff --git a/ProcessHacker/proctree.c b/ProcessHacker/proctree.c index 1bba410d58d3..d8332a80d8ee 100644 --- a/ProcessHacker/proctree.c +++ b/ProcessHacker/proctree.c @@ -2801,8 +2801,11 @@ BOOLEAN NTAPI PhpProcessTreeNewCallback( break; case PHPRTLC_PROTECTION: { - PhMoveReference(&node->ProtectionText, PhGetProcessItemProtectionText(processItem)); - getCellText->Text = node->ProtectionText->sr; + if (processItem->Protection.Level != 0 && processItem->Protection.Level != UCHAR_MAX) + { + PhMoveReference(&node->ProtectionText, PhGetProcessItemProtectionText(processItem)); + getCellText->Text = node->ProtectionText->sr; + } } break; default: From b9aa907034b29ee1a579bdbc92742f3524415b0a Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 19 Jan 2018 16:23:04 +1100 Subject: [PATCH 0681/2058] peview: Add missing ELF image unique bindings --- phlib/include/exlf.h | 12 +++++++++--- tools/peview/exlfprp.c | 2 ++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/phlib/include/exlf.h b/phlib/include/exlf.h index 736b88ee0c2a..35ad1c93b7a1 100644 --- a/phlib/include/exlf.h +++ b/phlib/include/exlf.h @@ -185,9 +185,15 @@ #define DT_HIPROC 0x7fffffff // symbol table section -#define STB_LOCAL 0 -#define STB_GLOBAL 1 -#define STB_WEAK 2 +#define STB_LOCAL 0 /* Local symbol */ +#define STB_GLOBAL 1 /* Global symbol */ +#define STB_WEAK 2 /* Weak symbol */ +#define STB_NUM 3 /* Number of defined types. */ +#define STB_LOOS 10 /* Start of OS-specific */ +#define STB_GNU_UNIQUE 10 /* Unique symbol. */ +#define STB_HIOS 12 /* End of OS-specific */ +#define STB_LOPROC 13 /* Start of processor-specific */ +#define STB_HIPROC 15 /* End of processor-specific */ #define STT_NOTYPE 0 #define STT_OBJECT 1 diff --git a/tools/peview/exlfprp.c b/tools/peview/exlfprp.c index 3dca74aca3e8..d9e67e3a0cf4 100644 --- a/tools/peview/exlfprp.c +++ b/tools/peview/exlfprp.c @@ -63,6 +63,8 @@ PWSTR PvpGetSymbolBindingName( return L"Global"; case STB_WEAK: return L"Weak"; + case STB_GNU_UNIQUE: + return L"Unique"; } return L"***ERROR***"; From d14385247cacdd5425879574525ec73f12e34377 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 19 Jan 2018 16:24:02 +1100 Subject: [PATCH 0682/2058] peview: Add hack for SymSearchW crashes --- tools/peview/pdb.c | 50 +++++++++++++++++++++++++++------------------- 1 file changed, 29 insertions(+), 21 deletions(-) diff --git a/tools/peview/pdb.c b/tools/peview/pdb.c index 2a668eba64f6..8912fb428071 100644 --- a/tools/peview/pdb.c +++ b/tools/peview/pdb.c @@ -1889,12 +1889,14 @@ BOOL CALLBACK EnumCallbackProc( symDataKind = SymbolInfo_DataKindStr(dataKindType); - //if (dataKindType == DataIsLocal || - // dataKindType == DataIsParam || - // dataKindType == DataIsObjectPtr) - //{ - // break; - //} + if ( + dataKindType == DataIsLocal || + dataKindType == DataIsParam || + dataKindType == DataIsObjectPtr + ) + { + break; + } symbol = PhAllocate(sizeof(PV_SYMBOL_NODE)); memset(symbol, 0, sizeof(PV_SYMBOL_NODE)); @@ -2404,21 +2406,27 @@ NTSTATUS PeDumpFileSymbols( SymEnumTypesW_I(NtCurrentProcess(), Context->BaseAddress, EnumCallbackProc, Context); //PrintUserDefinedTypes(Context); // Commented out due to verbosity. - // NOTE: The SymEnumSymbolsW and SymEnumTypesW functions don't enumerate exported DATA symbols such as - // as PsActiveProcessHead and PsLoadedModuleList from ntoskrnl.exe?? - // TODO: SymSearchW does enumerate those symbols but we'll need to filter out duplicate symbol entries properly or - // find out why the SymEnumSymbolsW and SymEnumTypesW functions can't enumerate those symbols. - SymSearchW_I( - NtCurrentProcess(), - Context->BaseAddress, - 0, - 0, - NULL, - 0, - EnumCallbackProc, - Context, - SYMSEARCH_RECURSE | SYMSEARCH_ALLITEMS - ); + if ( + PhFindStringInString(PvFileName, 0, L"ntkrnlmp.pdb") != -1 || + PhFindStringInString(PvFileName, 0, L"ntoskrnl.exe") != -1 // HACK: SymSearchW crashes for ole32.dll + ) + { + // NOTE: The SymEnumSymbolsW and SymEnumTypesW functions don't enumerate exported DATA symbols such as + // as PsActiveProcessHead and PsLoadedModuleList from ntoskrnl.exe?? + // TODO: SymSearchW does enumerate those symbols but we'll need to filter out duplicate symbol entries properly or + // find out why the SymEnumSymbolsW and SymEnumTypesW functions can't enumerate those symbols. + SymSearchW_I( + NtCurrentProcess(), + Context->BaseAddress, + 0, + 0, + NULL, + 0, + EnumCallbackProc, + Context, + SYMSEARCH_RECURSE | SYMSEARCH_ALLITEMS + ); + } } CleanupExit: From b4af9dfc6b1652be1278011db9b106233e426a89 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 19 Jan 2018 16:26:38 +1100 Subject: [PATCH 0683/2058] Prevent 32bit builds from running on 64bit due to NTAPI compatibility issues (release builds only) --- ProcessHacker/main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/ProcessHacker/main.c b/ProcessHacker/main.c index 74c1e506236b..5386cd7ae90c 100644 --- a/ProcessHacker/main.c +++ b/ProcessHacker/main.c @@ -222,6 +222,7 @@ INT WINAPI wWinMain( L"Most features will not work correctly.\n\n" L"Please run the 64-bit version of Process Hacker instead." ); + RtlExitUserProcess(STATUS_IMAGE_SUBSYSTEM_NOT_PRESENT); } #endif From 9626b8e21ed59a22163e21fe034daa5b78ce22f4 Mon Sep 17 00:00:00 2001 From: ge0rdi Date: Fri, 19 Jan 2018 13:36:45 +0100 Subject: [PATCH 0684/2058] GF Guard column improvements (#224) * Show "CF Guard" column only when CFG available * Show info in "CF Guard" column only when CFG mitigation is active for process --- ProcessHacker/include/procprv.h | 7 ++++++- ProcessHacker/modlist.c | 11 ++--------- ProcessHacker/modprv.c | 7 +++++++ ProcessHacker/procprv.c | 31 +++++++++++++++++++++++++++++++ ProcessHacker/proctree.c | 19 ++++--------------- 5 files changed, 50 insertions(+), 25 deletions(-) diff --git a/ProcessHacker/include/procprv.h b/ProcessHacker/include/procprv.h index b8726974e22b..72ebd3ea04b1 100644 --- a/ProcessHacker/include/procprv.h +++ b/ProcessHacker/include/procprv.h @@ -168,8 +168,9 @@ typedef struct _PH_PROCESS_ITEM ULONG IsProtectedProcess : 1; ULONG IsSecureProcess : 1; ULONG IsSubsystemProcess : 1; + ULONG IsControlFlowGuardEnabled : 1; - ULONG Spare : 15; + ULONG Spare : 14; }; }; @@ -411,4 +412,8 @@ PhReferenceProcessItemForRecord( ); // end_phapppub +BOOLEAN PhProcessIsCFGuardEnabled( + _In_ HANDLE ProcessHandle +); + #endif diff --git a/ProcessHacker/modlist.c b/ProcessHacker/modlist.c index b6a24c56edd8..27089f52468a 100644 --- a/ProcessHacker/modlist.c +++ b/ProcessHacker/modlist.c @@ -774,15 +774,8 @@ BOOLEAN NTAPI PhpModuleTreeNewCallback( } break; case PHMOTLC_CFGUARD: - if (WindowsVersion >= WINDOWS_8_1) - { - if (moduleItem->ImageDllCharacteristics & IMAGE_DLLCHARACTERISTICS_GUARD_CF) - PhInitializeStringRef(&getCellText->Text, L"CF Guard"); - } - else - { - PhInitializeStringRef(&getCellText->Text, L"N/A"); - } + if (moduleItem->ImageDllCharacteristics & IMAGE_DLLCHARACTERISTICS_GUARD_CF) + PhInitializeStringRef(&getCellText->Text, L"CF Guard"); break; case PHMOTLC_LOADTIME: { diff --git a/ProcessHacker/modprv.c b/ProcessHacker/modprv.c index 7a39345db8aa..17a9c3179688 100644 --- a/ProcessHacker/modprv.c +++ b/ProcessHacker/modprv.c @@ -354,6 +354,7 @@ VOID PhModuleProviderUpdate( PPH_MODULE_PROVIDER moduleProvider = (PPH_MODULE_PROVIDER)Object; PPH_LIST modules; ULONG i; + BOOLEAN cfGuardEnabled = FALSE; // If we didn't get a handle when we created the provider, // abort (unless this is the System process - in that case @@ -444,6 +445,8 @@ VOID PhModuleProviderUpdate( } } + cfGuardEnabled = PhProcessIsCFGuardEnabled(moduleProvider->ProcessHandle); + // Look for new modules. for (i = 0; i < modules->Count; i++) { @@ -527,6 +530,10 @@ VOID PhModuleProviderUpdate( } } + // remove CF Guard flag if CFG mitigation is not enabled for the process + if (!cfGuardEnabled) + moduleItem->ImageDllCharacteristics &= ~IMAGE_DLLCHARACTERISTICS_GUARD_CF; + if (NT_SUCCESS(PhQueryFullAttributesFileWin32(moduleItem->FileName->Buffer, &networkOpenInfo))) { moduleItem->FileLastWriteTime = networkOpenInfo.LastWriteTime; diff --git a/ProcessHacker/procprv.c b/ProcessHacker/procprv.c index 75136885980f..4ab5bcb163d2 100644 --- a/ProcessHacker/procprv.c +++ b/ProcessHacker/procprv.c @@ -1474,6 +1474,10 @@ VOID PhpFillProcessItem( ProcessItem->Protection.Level = UCHAR_MAX; } + // Control Flow Guard + if (ProcessItem->QueryHandle) + ProcessItem->IsControlFlowGuardEnabled = PhProcessIsCFGuardEnabled(ProcessItem->QueryHandle); + // On Windows 8.1 and above, processes without threads are reflected processes // which will not terminate if we have a handle open. if (Process->NumberOfThreads == 0) @@ -2984,3 +2988,30 @@ PPH_PROCESS_ITEM PhReferenceProcessItemForRecord( return processItem; } + +BOOLEAN PhProcessIsCFGuardEnabled( + _In_ HANDLE ProcessHandle +) +{ + BOOLEAN cfgEnabled = FALSE; + + if (WindowsVersion >= WINDOWS_8_1) + { + PROCESS_MITIGATION_POLICY_INFORMATION policyInfo; + + policyInfo.Policy = ProcessControlFlowGuardPolicy; + + if (NT_SUCCESS(NtQueryInformationProcess( + ProcessHandle, + ProcessMitigationPolicy, + &policyInfo, + sizeof(PROCESS_MITIGATION_POLICY_INFORMATION), + NULL + ))) + { + cfgEnabled = (policyInfo.ControlFlowGuardPolicy.EnableControlFlowGuard != 0); + } + } + + return cfgEnabled; +} diff --git a/ProcessHacker/proctree.c b/ProcessHacker/proctree.c index d8332a80d8ee..0247bb88506e 100644 --- a/ProcessHacker/proctree.c +++ b/ProcessHacker/proctree.c @@ -1826,11 +1826,9 @@ END_SORT_FUNCTION BEGIN_SORT_FUNCTION(CfGuard) { - PhpUpdateProcessNodeImage(node1); - PhpUpdateProcessNodeImage(node2); sortResult = intcmp( - node1->ImageDllCharacteristics & IMAGE_DLLCHARACTERISTICS_GUARD_CF, - node2->ImageDllCharacteristics & IMAGE_DLLCHARACTERISTICS_GUARD_CF + node1->ProcessItem->IsControlFlowGuardEnabled, + node2->ProcessItem->IsControlFlowGuardEnabled ); } END_SORT_FUNCTION @@ -2736,17 +2734,8 @@ BOOLEAN NTAPI PhpProcessTreeNewCallback( } break; case PHPRTLC_CFGUARD: - PhpUpdateProcessNodeImage(node); - - if (WindowsVersion >= WINDOWS_8_1) - { - if (node->ImageDllCharacteristics & IMAGE_DLLCHARACTERISTICS_GUARD_CF) - PhInitializeStringRef(&getCellText->Text, L"CF Guard"); - } - else - { - PhInitializeStringRef(&getCellText->Text, L"N/A"); - } + if (processItem->IsControlFlowGuardEnabled) + PhInitializeStringRef(&getCellText->Text, L"CF Guard"); break; case PHPRTLC_TIMESTAMP: PhpUpdateProcessNodeImage(node); From fced060675af435b54347872e8c6a84ef7e110ce Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 20 Jan 2018 00:13:24 +1100 Subject: [PATCH 0685/2058] Add PhGetProcessIsCFGuardEnabled --- phlib/include/phnativeinl.h | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/phlib/include/phnativeinl.h b/phlib/include/phnativeinl.h index d2954d866481..17ffac82d1e5 100644 --- a/phlib/include/phnativeinl.h +++ b/phlib/include/phnativeinl.h @@ -376,6 +376,34 @@ PhGetProcessConsoleHostProcessId( return status; } +FORCEINLINE +NTSTATUS +PhGetProcessIsCFGuardEnabled( + _In_ HANDLE ProcessHandle, + _Out_ PBOOLEAN IsControlFlowGuardEnabled + ) +{ + NTSTATUS status; + PROCESS_MITIGATION_POLICY_INFORMATION policyInfo; + + policyInfo.Policy = ProcessControlFlowGuardPolicy; + + status = NtQueryInformationProcess( + ProcessHandle, + ProcessMitigationPolicy, + &policyInfo, + sizeof(PROCESS_MITIGATION_POLICY_INFORMATION), + NULL + ); + + if (!NT_SUCCESS(status)) + return status; + + *IsControlFlowGuardEnabled = !!policyInfo.ControlFlowGuardPolicy.EnableControlFlowGuard; + + return status; +} + /** * Sets a process' affinity mask. * From 43bbd2f8755d8d038c83f74ebf285522afb25bea Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 20 Jan 2018 00:32:58 +1100 Subject: [PATCH 0686/2058] Add PhGetProcessProtection --- phlib/include/phnativeinl.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/phlib/include/phnativeinl.h b/phlib/include/phnativeinl.h index 17ffac82d1e5..572dfda47a1c 100644 --- a/phlib/include/phnativeinl.h +++ b/phlib/include/phnativeinl.h @@ -376,6 +376,22 @@ PhGetProcessConsoleHostProcessId( return status; } +FORCEINLINE +NTSTATUS +PhGetProcessProtection( + _In_ HANDLE ProcessHandle, + _Out_ PPS_PROTECTION Protection + ) +{ + return NtQueryInformationProcess( + ProcessHandle, + ProcessProtectionInformation, + Protection, + sizeof(PS_PROTECTION), + NULL + ); +} + FORCEINLINE NTSTATUS PhGetProcessIsCFGuardEnabled( From c8a3b3802198bb3e228c8f866f51b1814358896d Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 20 Jan 2018 00:59:42 +1100 Subject: [PATCH 0687/2058] Improve PR #224 --- ProcessHacker/include/procprv.h | 4 --- ProcessHacker/modprv.c | 20 +++++++++---- ProcessHacker/procprv.c | 51 +++++++++------------------------ 3 files changed, 28 insertions(+), 47 deletions(-) diff --git a/ProcessHacker/include/procprv.h b/ProcessHacker/include/procprv.h index 72ebd3ea04b1..7ee4e9f3711a 100644 --- a/ProcessHacker/include/procprv.h +++ b/ProcessHacker/include/procprv.h @@ -412,8 +412,4 @@ PhReferenceProcessItemForRecord( ); // end_phapppub -BOOLEAN PhProcessIsCFGuardEnabled( - _In_ HANDLE ProcessHandle -); - #endif diff --git a/ProcessHacker/modprv.c b/ProcessHacker/modprv.c index 17a9c3179688..9a7589f415d6 100644 --- a/ProcessHacker/modprv.c +++ b/ProcessHacker/modprv.c @@ -84,6 +84,7 @@ PPH_MODULE_PROVIDER PhCreateModuleProvider( PhEmGetObjectSize(EmModuleProviderType, sizeof(PH_MODULE_PROVIDER)), PhModuleProviderType ); + memset(moduleProvider, 0, sizeof(PH_MODULE_PROVIDER)); moduleProvider->ModuleHashtable = PhCreateHashtable( sizeof(PPH_MODULE_ITEM), @@ -122,9 +123,21 @@ PPH_MODULE_PROVIDER PhCreateModuleProvider( moduleProvider->RunStatus = status; } - if (moduleProvider->ProcessHandle) + if (WindowsVersion >= WINDOWS_8 && moduleProvider->ProcessHandle) + { moduleProvider->PackageFullName = PhGetProcessPackageFullName(moduleProvider->ProcessHandle); + if (WindowsVersion >= WINDOWS_8_1) + { + BOOLEAN cfguardEnabled; + + if (NT_SUCCESS(PhGetProcessIsCFGuardEnabled(moduleProvider->ProcessHandle, &cfguardEnabled))) + { + moduleProvider->ControlFlowGuardEnabled = cfguardEnabled; + } + } + } + RtlInitializeSListHead(&moduleProvider->QueryListHead); PhEmCallObjectOperation(EmModuleProviderType, moduleProvider, EmObjectCreate); @@ -354,7 +367,6 @@ VOID PhModuleProviderUpdate( PPH_MODULE_PROVIDER moduleProvider = (PPH_MODULE_PROVIDER)Object; PPH_LIST modules; ULONG i; - BOOLEAN cfGuardEnabled = FALSE; // If we didn't get a handle when we created the provider, // abort (unless this is the System process - in that case @@ -445,8 +457,6 @@ VOID PhModuleProviderUpdate( } } - cfGuardEnabled = PhProcessIsCFGuardEnabled(moduleProvider->ProcessHandle); - // Look for new modules. for (i = 0; i < modules->Count; i++) { @@ -531,7 +541,7 @@ VOID PhModuleProviderUpdate( } // remove CF Guard flag if CFG mitigation is not enabled for the process - if (!cfGuardEnabled) + if (!moduleProvider->ControlFlowGuardEnabled) moduleItem->ImageDllCharacteristics &= ~IMAGE_DLLCHARACTERISTICS_GUARD_CF; if (NT_SUCCESS(PhQueryFullAttributesFileWin32(moduleItem->FileName->Buffer, &networkOpenInfo))) diff --git a/ProcessHacker/procprv.c b/ProcessHacker/procprv.c index 4ab5bcb163d2..ce3e38e025f8 100644 --- a/ProcessHacker/procprv.c +++ b/ProcessHacker/procprv.c @@ -1449,34 +1449,35 @@ VOID PhpFillProcessItem( { PS_PROTECTION protection; - if (NT_SUCCESS(NtQueryInformationProcess( - ProcessItem->QueryHandle, - ProcessProtectionInformation, - &protection, - sizeof(PS_PROTECTION), - NULL - ))) + if (NT_SUCCESS(PhGetProcessProtection(ProcessItem->QueryHandle, &protection))) { ProcessItem->Protection.Level = protection.Level; } } else { - // "emulate" PS_PROTECTION info for older OSes + // HACK: 'emulate' the PS_PROTECTION info for older OSes. if (ProcessItem->IsProtectedProcess) ProcessItem->Protection.Type = PsProtectedTypeProtected; } } else { - // we weren't able to get protection info - // lets signalize that with special value + // Signalize that we weren't able to get protection info with a special value. + // Note: We use this value to determine if we should show protection information. ProcessItem->Protection.Level = UCHAR_MAX; } // Control Flow Guard - if (ProcessItem->QueryHandle) - ProcessItem->IsControlFlowGuardEnabled = PhProcessIsCFGuardEnabled(ProcessItem->QueryHandle); + if (WindowsVersion >= WINDOWS_8_1 && ProcessItem->QueryHandle) + { + BOOLEAN cfguardEnabled; + + if (NT_SUCCESS(PhGetProcessIsCFGuardEnabled(ProcessItem->QueryHandle, &cfguardEnabled))) + { + ProcessItem->IsControlFlowGuardEnabled = cfguardEnabled; + } + } // On Windows 8.1 and above, processes without threads are reflected processes // which will not terminate if we have a handle open. @@ -2989,29 +2990,3 @@ PPH_PROCESS_ITEM PhReferenceProcessItemForRecord( return processItem; } -BOOLEAN PhProcessIsCFGuardEnabled( - _In_ HANDLE ProcessHandle -) -{ - BOOLEAN cfgEnabled = FALSE; - - if (WindowsVersion >= WINDOWS_8_1) - { - PROCESS_MITIGATION_POLICY_INFORMATION policyInfo; - - policyInfo.Policy = ProcessControlFlowGuardPolicy; - - if (NT_SUCCESS(NtQueryInformationProcess( - ProcessHandle, - ProcessMitigationPolicy, - &policyInfo, - sizeof(PROCESS_MITIGATION_POLICY_INFORMATION), - NULL - ))) - { - cfgEnabled = (policyInfo.ControlFlowGuardPolicy.EnableControlFlowGuard != 0); - } - } - - return cfgEnabled; -} From f4e8de1d30fa4eee862194e34cedecb24b1be8ae Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 20 Jan 2018 02:00:39 +1100 Subject: [PATCH 0688/2058] Update process tree node cache --- ProcessHacker/proctree.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ProcessHacker/proctree.c b/ProcessHacker/proctree.c index 0247bb88506e..f5f3196bb93f 100644 --- a/ProcessHacker/proctree.c +++ b/ProcessHacker/proctree.c @@ -646,7 +646,7 @@ VOID PhTickProcessNodes( // The name and PID never change, so we don't invalidate that. memset(&node->TextCache[2], 0, sizeof(PH_STRINGREF) * (PHPRTLC_MAXIMUM - 2)); - node->ValidMask &= PHPN_OSCONTEXT | PHPN_IMAGE | PHPN_DPIAWARENESS; // Items that always remain valid + node->ValidMask &= PHPN_OSCONTEXT | PHPN_IMAGE | PHPN_DPIAWARENESS | PHPRTLC_CFGUARD | PHPRTLC_PROTECTION; // Items that always remain valid // Invalidate graph buffers. node->CpuGraphBuffers.Valid = FALSE; From b8ff1d37b66a5731050cfa69cbdf6aa566828537 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 20 Jan 2018 02:06:59 +1100 Subject: [PATCH 0689/2058] Revert "Update process tree node cache" This reverts commit f4e8de1d30fa4eee862194e34cedecb24b1be8ae. --- ProcessHacker/proctree.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ProcessHacker/proctree.c b/ProcessHacker/proctree.c index f5f3196bb93f..0247bb88506e 100644 --- a/ProcessHacker/proctree.c +++ b/ProcessHacker/proctree.c @@ -646,7 +646,7 @@ VOID PhTickProcessNodes( // The name and PID never change, so we don't invalidate that. memset(&node->TextCache[2], 0, sizeof(PH_STRINGREF) * (PHPRTLC_MAXIMUM - 2)); - node->ValidMask &= PHPN_OSCONTEXT | PHPN_IMAGE | PHPN_DPIAWARENESS | PHPRTLC_CFGUARD | PHPRTLC_PROTECTION; // Items that always remain valid + node->ValidMask &= PHPN_OSCONTEXT | PHPN_IMAGE | PHPN_DPIAWARENESS; // Items that always remain valid // Invalidate graph buffers. node->CpuGraphBuffers.Valid = FALSE; From 08d57997d34c95166b403ee3b7a2e2bae79def56 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 20 Jan 2018 02:18:07 +1100 Subject: [PATCH 0690/2058] Improve process tree sorting --- ProcessHacker/proctree.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/ProcessHacker/proctree.c b/ProcessHacker/proctree.c index 0247bb88506e..02a0b0e7e840 100644 --- a/ProcessHacker/proctree.c +++ b/ProcessHacker/proctree.c @@ -1664,7 +1664,7 @@ BEGIN_SORT_FUNCTION(Virtualized) { PhpUpdateProcessNodeToken(node1); PhpUpdateProcessNodeToken(node2); - sortResult = intcmp(node1->VirtualizationEnabled, node2->VirtualizationEnabled); + sortResult = ucharcmp(node1->VirtualizationEnabled, node2->VirtualizationEnabled); } END_SORT_FUNCTION @@ -1798,7 +1798,7 @@ BEGIN_SORT_FUNCTION(Subsystem) { PhpUpdateProcessNodeImage(node1); PhpUpdateProcessNodeImage(node2); - sortResult = intcmp(node1->ImageSubsystem, node2->ImageSubsystem); + sortResult = ushortcmp(node1->ImageSubsystem, node2->ImageSubsystem); } END_SORT_FUNCTION @@ -1826,10 +1826,7 @@ END_SORT_FUNCTION BEGIN_SORT_FUNCTION(CfGuard) { - sortResult = intcmp( - node1->ProcessItem->IsControlFlowGuardEnabled, - node2->ProcessItem->IsControlFlowGuardEnabled - ); + sortResult = uintcmp(node1->ProcessItem->IsControlFlowGuardEnabled, node2->ProcessItem->IsControlFlowGuardEnabled); } END_SORT_FUNCTION @@ -1871,7 +1868,9 @@ END_SORT_FUNCTION BEGIN_SORT_FUNCTION(Protection) { - sortResult = intcmp((CHAR)processItem1->Protection.Level, (CHAR)processItem2->Protection.Level); + // Use signed char so processes that we were unable to query (e.g. indicated by UCHAR_MAX) + // are placed below processes we are able to query (e.g. 0 and above). + sortResult = charcmp((CHAR)processItem1->Protection.Level, (CHAR)processItem2->Protection.Level); } END_SORT_FUNCTION From db4d7d4c7edec33d2ca69ff50d2c7d0b1b1072b7 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 20 Jan 2018 02:31:08 +1100 Subject: [PATCH 0691/2058] Improve mini info window popup location calculation (experimental) --- ProcessHacker/miniinfo.c | 37 ++++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/ProcessHacker/miniinfo.c b/ProcessHacker/miniinfo.c index ccef3ad0b9c1..f6b151608b98 100644 --- a/ProcessHacker/miniinfo.c +++ b/ProcessHacker/miniinfo.c @@ -25,7 +25,7 @@ #include #include -#include +#include #include #include @@ -35,6 +35,8 @@ #include #include #include + +#include #include static HWND PhMipContainerWindow = NULL; @@ -699,38 +701,43 @@ VOID PhMipCalculateWindowRectangle( { PH_RECTANGLE bounds; - if (memcmp(&monitorInfo.rcWork, &monitorInfo.rcMonitor, sizeof(RECT)) == 0) + if (RtlEqualMemory(&monitorInfo.rcWork, &monitorInfo.rcMonitor, sizeof(RECT))) { - HWND trayWindow; - RECT taskbarRect; + APPBARDATA taskbarRect = { sizeof(APPBARDATA) }; + + // dmex: FindWindow + Shell_TrayWnd causes a lot of FPs by security software (malware uses this string to inject code into Explorer)... + // TODO: This comment block should be removed if the SHAppBarMessage function is more reliable. + //HWND trayWindow; + //RECT taskbarRect; + //if ((trayWindow = FindWindow(L"Shell_TrayWnd", NULL)) && + // GetMonitorInfo(MonitorFromWindow(trayWindow, MONITOR_DEFAULTTOPRIMARY), &monitorInfo) && // Just in case + // GetWindowRect(trayWindow, &taskbarRect)) // The taskbar probably has auto-hide enabled. We need to adjust for that. - if ((trayWindow = FindWindow(L"Shell_TrayWnd", NULL)) && - GetMonitorInfo(MonitorFromWindow(trayWindow, MONITOR_DEFAULTTOPRIMARY), &monitorInfo) && // Just in case - GetWindowRect(trayWindow, &taskbarRect)) + if (SHAppBarMessage(ABM_GETTASKBARPOS, &taskbarRect)) { LONG monitorMidX = (monitorInfo.rcMonitor.left + monitorInfo.rcMonitor.right) / 2; LONG monitorMidY = (monitorInfo.rcMonitor.top + monitorInfo.rcMonitor.bottom) / 2; - if (taskbarRect.right < monitorMidX) + if (taskbarRect.rc.right < monitorMidX) { // Left - monitorInfo.rcWork.left += taskbarRect.right - taskbarRect.left; + monitorInfo.rcWork.left += taskbarRect.rc.right - taskbarRect.rc.left; } - else if (taskbarRect.bottom < monitorMidY) + else if (taskbarRect.rc.bottom < monitorMidY) { // Top - monitorInfo.rcWork.top += taskbarRect.bottom - taskbarRect.top; + monitorInfo.rcWork.top += taskbarRect.rc.bottom - taskbarRect.rc.top; } - else if (taskbarRect.left > monitorMidX) + else if (taskbarRect.rc.left > monitorMidX) { // Right - monitorInfo.rcWork.right -= taskbarRect.right - taskbarRect.left; + monitorInfo.rcWork.right -= taskbarRect.rc.right - taskbarRect.rc.left; } - else if (taskbarRect.top > monitorMidY) + else if (taskbarRect.rc.top > monitorMidY) { // Bottom - monitorInfo.rcWork.bottom -= taskbarRect.bottom - taskbarRect.top; + monitorInfo.rcWork.bottom -= taskbarRect.rc.bottom - taskbarRect.rc.top; } } } From 6351e9527aea8b975fd21a647efd49ab3febef10 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 20 Jan 2018 02:32:27 +1100 Subject: [PATCH 0692/2058] Fix build (missing file from commit c8a3b38) --- ProcessHacker/include/modprv.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/ProcessHacker/include/modprv.h b/ProcessHacker/include/modprv.h index 05e36ef3b664..6a47722515bc 100644 --- a/ProcessHacker/include/modprv.h +++ b/ProcessHacker/include/modprv.h @@ -51,6 +51,16 @@ typedef struct _PH_MODULE_PROVIDER PPH_STRING PackageFullName; SLIST_HEADER QueryListHead; NTSTATUS RunStatus; + + union + { + BOOLEAN Flags; + struct + { + BOOLEAN ControlFlowGuardEnabled : 1; + BOOLEAN Spare : 7; + }; + }; } PH_MODULE_PROVIDER, *PPH_MODULE_PROVIDER; // end_phapppub From 74c5cd4f7fa2345ffe34c4567c33e80d0764b8bf Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 20 Jan 2018 02:41:33 +1100 Subject: [PATCH 0693/2058] Plugins: Add PhHttpSocketSetCredentials --- plugins/CommonUtil/http.c | 19 ++++++++++++++++++- plugins/CommonUtil/http.h | 9 +++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/plugins/CommonUtil/http.c b/plugins/CommonUtil/http.c index e909ae5605c1..35e30725e209 100644 --- a/plugins/CommonUtil/http.c +++ b/plugins/CommonUtil/http.c @@ -492,4 +492,21 @@ PPH_STRING PhHttpSocketGetErrorMessage( } return message; -} \ No newline at end of file +} + +BOOLEAN PhHttpSocketSetCredentials( + _In_ PPH_HTTP_CONTEXT HttpContext, + _In_ PCWSTR Name, + _In_ PCWSTR Value + ) +{ + return WinHttpSetCredentials( + HttpContext->RequestHandle, + WINHTTP_AUTH_TARGET_SERVER, + WINHTTP_AUTH_SCHEME_BASIC, + Name, + Value, + NULL + ); +} + diff --git a/plugins/CommonUtil/http.h b/plugins/CommonUtil/http.h index 5636f4f1523d..52f56dc2db26 100644 --- a/plugins/CommonUtil/http.h +++ b/plugins/CommonUtil/http.h @@ -160,6 +160,15 @@ PhHttpSocketGetErrorMessage( _In_ ULONG ErrorCode ); +_Check_return_ +BOOLEAN +NTAPI +PhHttpSocketSetCredentials( + _In_ PPH_HTTP_CONTEXT HttpContext, + _In_ PCWSTR Name, + _In_ PCWSTR Value + ); + #ifdef __cplusplus } #endif From 69bb84b21e186ae5d70fdb7fc83e89fd9d2bb348 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 20 Jan 2018 02:45:00 +1100 Subject: [PATCH 0694/2058] Add workaround for ProcessSequenceNumber bug when running under wow64 --- ProcessHacker/procprv.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ProcessHacker/procprv.c b/ProcessHacker/procprv.c index ce3e38e025f8..d7dd2fa7d73e 100644 --- a/ProcessHacker/procprv.c +++ b/ProcessHacker/procprv.c @@ -1317,7 +1317,7 @@ VOID PhpFillProcessItemExtension( { PSYSTEM_PROCESS_INFORMATION_EXTENSION processExtension; - if (WindowsVersion < WINDOWS_10_RS3) + if (WindowsVersion < WINDOWS_10_RS3 || PhIsExecutingInWow64()) return; processExtension = PH_PROCESS_EXTENSION(Process); @@ -2059,7 +2059,7 @@ VOID PhProcessProviderUpdate( { PPH_PROCESS_ITEM processItem; - if (WindowsVersion >= WINDOWS_10_RS3) + if (WindowsVersion >= WINDOWS_10_RS3 && !PhIsExecutingInWow64()) { if ((processItem = PhpLookupProcessItem(process->UniqueProcessId)) && processItem->ProcessSequenceNumber == PH_PROCESS_EXTENSION(process)->ProcessSequenceNumber) sysTotalCycleTime += process->CycleTime - processItem->CycleTimeDelta.Value; // existing process @@ -2128,7 +2128,7 @@ VOID PhProcessProviderUpdate( processEntry = (PSYSTEM_PROCESS_INFORMATION)processEntry->UniqueProcessKey; } - if (WindowsVersion >= WINDOWS_10_RS3) + if (WindowsVersion >= WINDOWS_10_RS3 && !PhIsExecutingInWow64()) { if (!processEntry || PH_PROCESS_EXTENSION(processEntry)->ProcessSequenceNumber != processItem->ProcessSequenceNumber) processRemoved = TRUE; @@ -2936,7 +2936,7 @@ PPH_PROCESS_ITEM PhReferenceProcessItemForParent( parentProcessItem = PhpLookupProcessItem(ProcessItem->ParentProcessId); - if (WindowsVersion >= WINDOWS_10_RS3) + if (WindowsVersion >= WINDOWS_10_RS3 && !PhIsExecutingInWow64()) { // We make sure that the process item we found is actually the parent process - its sequence number // must not be higher than the supplied sequence. @@ -2970,7 +2970,7 @@ PPH_PROCESS_ITEM PhReferenceProcessItemForRecord( processItem = PhpLookupProcessItem(Record->ProcessId); - if (WindowsVersion >= WINDOWS_10_RS3) + if (WindowsVersion >= WINDOWS_10_RS3 && !PhIsExecutingInWow64()) { if (processItem && processItem->ProcessSequenceNumber == Record->ProcessSequenceNumber) PhReferenceObject(processItem); From 6da8decc50f8e1ac6cc6e5a98104ee7c05bd1d97 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 20 Jan 2018 02:46:14 +1100 Subject: [PATCH 0695/2058] Add PhGetServiceNameForModuleReference --- phlib/include/svcsup.h | 8 ++++++++ phlib/svcsup.c | 45 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/phlib/include/svcsup.h b/phlib/include/svcsup.h index ab3b9437c6c4..a968f54e21da 100644 --- a/phlib/include/svcsup.h +++ b/phlib/include/svcsup.h @@ -122,6 +122,14 @@ PhGetServiceNameFromTag( _In_ PVOID ServiceTag ); +PHLIBAPI +PPH_STRING +NTAPI +PhGetServiceNameForModuleReference( + _In_ HANDLE ProcessId, + _In_ PWSTR ModuleName + ); + PHLIBAPI NTSTATUS NTAPI diff --git a/phlib/svcsup.c b/phlib/svcsup.c index 07e33948a58e..e5625cf6b93d 100644 --- a/phlib/svcsup.c +++ b/phlib/svcsup.c @@ -50,7 +50,7 @@ static PH_KEY_VALUE_PAIR PhpServiceTypePairs[] = SIP(L"User own process", SERVICE_USER_OWN_PROCESS), SIP(L"User own process (instance)", SERVICE_USER_OWN_PROCESS | SERVICE_USERSERVICE_INSTANCE), SIP(L"User share process", SERVICE_USER_SHARE_PROCESS), - SIP(L"User share process (instance)", SERVICE_USER_SHARE_PROCESS | SERVICE_USERSERVICE_INSTANCE), + SIP(L"User share process (instance)", SERVICE_USER_SHARE_PROCESS | SERVICE_USERSERVICE_INSTANCE) }; static PH_KEY_VALUE_PAIR PhpServiceStartTypePairs[] = @@ -460,6 +460,49 @@ PPH_STRING PhGetServiceNameFromTag( return serviceName; } +PPH_STRING PhGetServiceNameForModuleReference( + _In_ HANDLE ProcessId, + _In_ PWSTR ModuleName + ) +{ + static PQUERY_TAG_INFORMATION I_QueryTagInformation = NULL; + PPH_STRING serviceNames = NULL; + TAG_INFO_NAMES_REFERENCING_MODULE moduleNameRef; + + if (!I_QueryTagInformation) + { + I_QueryTagInformation = PhGetModuleProcAddress(L"advapi32.dll", "I_QueryTagInformation"); + + if (!I_QueryTagInformation) + return NULL; + } + + memset(&moduleNameRef, 0, sizeof(TAG_INFO_NAMES_REFERENCING_MODULE)); + moduleNameRef.InParams.dwPid = HandleToUlong(ProcessId); + moduleNameRef.InParams.pszModule = ModuleName; + + I_QueryTagInformation(NULL, eTagInfoLevelNamesReferencingModule, &moduleNameRef); + + if (moduleNameRef.OutParams.pmszNames) + { + PH_STRING_BUILDER sb; + PWSTR serviceName; + + PhInitializeStringBuilder(&sb, 0x40); + + for (serviceName = moduleNameRef.OutParams.pmszNames; *serviceName; serviceName += PhCountStringZ(serviceName) + 1) + PhAppendFormatStringBuilder(&sb, L"%s, ", serviceName); + + if (sb.String->Length != 0) + PhRemoveEndStringBuilder(&sb, 2); + + serviceNames = PhFinalStringBuilderString(&sb); + LocalFree(moduleNameRef.OutParams.pmszNames); + } + + return serviceNames; +} + NTSTATUS PhGetThreadServiceTag( _In_ HANDLE ThreadHandle, _In_opt_ HANDLE ProcessHandle, From 2c87ebeee8179466d60197c009cbe7a3c25d97de Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 20 Jan 2018 02:54:55 +1100 Subject: [PATCH 0696/2058] Improve ProcessorBrandString query (experimental) --- ProcessHacker/syssccpu.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/ProcessHacker/syssccpu.c b/ProcessHacker/syssccpu.c index a08ab77f489a..e26d1aa480e5 100644 --- a/ProcessHacker/syssccpu.c +++ b/ProcessHacker/syssccpu.c @@ -824,13 +824,23 @@ VOID PhSipGetCpuBrandString( _Out_writes_(49) PWSTR BrandString ) { - ULONG brandString[4 * 3]; - - __cpuid(&brandString[0], 0x80000002); - __cpuid(&brandString[4], 0x80000003); - __cpuid(&brandString[8], 0x80000004); + // dmex: The __cpuid instruction generates quite a few FPs by security software (malware uses this as an anti-VM trick)... + // TODO: This comment block should be removed if the SystemProcessorBrandString class is more reliable. + //ULONG brandString[4 * 3]; + //__cpuid(&brandString[0], 0x80000002); + //__cpuid(&brandString[4], 0x80000003); + //__cpuid(&brandString[8], 0x80000004); + + CHAR brandString[49]; + + NtQuerySystemInformation( + SystemProcessorBrandString, + brandString, + sizeof(brandString), + NULL + ); - PhZeroExtendToUtf16Buffer((PSTR)brandString, 48, BrandString); + PhZeroExtendToUtf16Buffer(brandString, 48, BrandString); BrandString[48] = 0; } From 6fa0c7f21d10b1858b669403fc8a2d80bcc6e437 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 20 Jan 2018 03:50:15 +1100 Subject: [PATCH 0697/2058] phlib: Add appmodel support functions --- phlib/appresolver.c | 242 ++++++++++++++++ phlib/include/appresolver.h | 43 +++ phlib/include/appresolverp.h | 527 +++++++++++++++++++++++++++++++++++ phlib/phlib.vcxproj | 3 + phlib/phlib.vcxproj.filters | 9 + 5 files changed, 824 insertions(+) create mode 100644 phlib/appresolver.c create mode 100644 phlib/include/appresolver.h create mode 100644 phlib/include/appresolverp.h diff --git a/phlib/appresolver.c b/phlib/appresolver.c new file mode 100644 index 000000000000..4082a433206b --- /dev/null +++ b/phlib/appresolver.c @@ -0,0 +1,242 @@ +/* + * Process Hacker - + * Appmodel support functions + * + * Copyright (C) 2017-2018 dmex + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#define COBJMACROS +#define CINTERFACE +#include + +#include +#include +#include + +#include +#include + +static PVOID PhpQueryAppResolverInterface( + VOID + ) +{ + static PH_INITONCE initOnce = PH_INITONCE_INIT; + static PVOID resolverInterface = NULL; + + if (PhBeginInitOnce(&initOnce)) + { + if (WindowsVersion < WINDOWS_8) + CoCreateInstance(&CLSID_StartMenuCacheAndAppResolver_I, NULL, CLSCTX_INPROC_SERVER, &IID_IApplicationResolver61_I, &resolverInterface); + else + CoCreateInstance(&CLSID_StartMenuCacheAndAppResolver_I, NULL, CLSCTX_INPROC_SERVER, &IID_IApplicationResolver62_I, &resolverInterface); + + PhEndInitOnce(&initOnce); + } + + return resolverInterface; +} + +static PVOID PhpQueryStartMenuCacheInterface( + VOID + ) +{ + static PH_INITONCE initOnce = PH_INITONCE_INIT; + static PVOID startMenuInterface = NULL; + + if (PhBeginInitOnce(&initOnce)) + { + if (WindowsVersion < WINDOWS_8) + CoCreateInstance(&CLSID_StartMenuCacheAndAppResolver_I, NULL, CLSCTX_INPROC_SERVER, &IID_IStartMenuAppItems61_I, &startMenuInterface); + else + CoCreateInstance(&CLSID_StartMenuCacheAndAppResolver_I, NULL, CLSCTX_INPROC_SERVER, &IID_IStartMenuAppItems62_I, &startMenuInterface); + + PhEndInitOnce(&initOnce); + } + + return startMenuInterface; +} + +BOOLEAN PhAppResolverGetAppIdForProcess( + _In_ HANDLE ProcessId, + _Out_ PPH_STRING *ApplicationUserModelId + ) +{ + PVOID resolverInterface; + PWSTR appIdText = NULL; + + if (!(resolverInterface = PhpQueryAppResolverInterface())) + return FALSE; + + if (WindowsVersion < WINDOWS_8) + { + IApplicationResolver_GetAppIDForProcess( + (IApplicationResolver61*)resolverInterface, + HandleToUlong(ProcessId), + &appIdText, + NULL, + NULL, + NULL + ); + } + else + { + IApplicationResolver2_GetAppIDForProcess( + (IApplicationResolver62*)resolverInterface, + HandleToUlong(ProcessId), + &appIdText, + NULL, + NULL, + NULL + ); + } + + if (appIdText) + { + *ApplicationUserModelId = PhCreateString(appIdText); + return TRUE; + } + + return FALSE; +} + +PPH_LIST PhGetPackageAssetsFromResourceFile( + _In_ PWSTR FilePath + ) +{ + IMrtResourceManager* resourceManager = NULL; + IResourceMap* resourceMap = NULL; + PPH_LIST resourceList = NULL; + ULONG resourceCount = 0; + + if (FAILED(CoCreateInstance( + &CLSID_MrtResourceManager_I, + NULL, + CLSCTX_INPROC_SERVER, + &IID_IMrtResourceManager_I, + &resourceManager + ))) + { + return FALSE; + } + + if (FAILED(IMrtResourceManager_InitializeForFile(resourceManager, FilePath))) + goto CleanupExit; + + if (FAILED(IMrtResourceManager_GetMainResourceMap(resourceManager, &IID_IResourceMap_I, &resourceMap))) + goto CleanupExit; + + if (FAILED(IResourceMap_GetNamedResourceCount(resourceMap, &resourceCount))) + goto CleanupExit; + + resourceList = PhCreateList(10); + + for (ULONG i = 0; i < resourceCount; i++) + { + PWSTR resourceName; + + if (SUCCEEDED(IResourceMap_GetNamedResourceUri(resourceMap, i, &resourceName))) + { + PhAddItemList(resourceList, PhCreateString(resourceName)); + } + } + +CleanupExit: + + if (resourceMap) + IResourceMap_Release(resourceMap); + + if (resourceManager) + IMrtResourceManager_Release(resourceManager); + + return resourceList; +} + +// TODO: FIXME +//HICON PhAppResolverGetPackageIcon( +// _In_ HANDLE ProcessId, +// _In_ PPH_STRING PackageFullName +// ) +//{ +// PVOID startMenuInterface; +// PPH_STRING applicationUserModelId; +// IPropertyStore* propStoreInterface; +// HICON packageIcon = NULL; +// +// if (!(startMenuInterface = PhpQueryStartMenuCacheInterface())) +// return NULL; +// +// if (!PhAppResolverGetAppIdForProcess(ProcessId, &applicationUserModelId)) +// return NULL; +// +// if (WindowsVersion < WINDOWS_8) +// { +// IStartMenuAppItems_GetItem( +// (IStartMenuAppItems61*)startMenuInterface, +// SMAIF_DEFAULT, +// applicationUserModelId->Buffer, +// &IID_IPropertyStore, +// &propStoreInterface +// ); +// } +// else +// { +// IStartMenuAppItems2_GetItem( +// (IStartMenuAppItems62*)startMenuInterface, +// SMAIF_DEFAULT, +// applicationUserModelId->Buffer, +// &IID_IPropertyStore, +// &propStoreInterface +// ); +// } +// +// if (propStoreInterface) +// { +// IMrtResourceManager* mrtResourceManager; +// IResourceMap* resourceMap; +// PROPVARIANT propVar; +// PWSTR filePath; +// +// IPropertyStore_GetValue(propStoreInterface, &PKEY_Tile_Background, &propVar); +// IPropertyStore_GetValue(propStoreInterface, &PKEY_Tile_SmallLogoPath, &propVar); +// +// CoCreateInstance( +// &CLSID_MrtResourceManager_I, +// NULL, +// CLSCTX_INPROC_SERVER, +// &IID_IMrtResourceManager_I, +// &mrtResourceManager +// ); +// +// IMrtResourceManager_InitializeForPackage(mrtResourceManager, PackageFullName->Buffer); +// IMrtResourceManager_GetMainResourceMap(mrtResourceManager, &IID_IResourceMap_I, &resourceMap); +// IResourceMap_GetFilePath(resourceMap, propVar.pwszVal, &filePath); +// +// //HBITMAP bitmap = PhLoadImageFromFile(filePath, 32, 32); +// //packageIcon = PhBitmapToIcon(bitmap, 32, 32); +// +// IResourceMap_Release(resourceMap); +// IMrtResourceManager_Release(mrtResourceManager); +// PropVariantClear(&propVar); +// +// IPropertyStore_Release(propStoreInterface); +// } +// +// PhDereferenceObject(applicationUserModelId); +// +// return packageIcon; +//} diff --git a/phlib/include/appresolver.h b/phlib/include/appresolver.h new file mode 100644 index 000000000000..f1c31a91cb9e --- /dev/null +++ b/phlib/include/appresolver.h @@ -0,0 +1,43 @@ +/* + * Process Hacker - + * Appmodel support functions + * + * Copyright (C) 2017-2018 dmex + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#ifndef _PH_APPRESOLVER_H +#define _PH_APPRESOLVER_H + +#ifdef __cplusplus +extern "C" { +#endif + +BOOLEAN PhAppResolverGetAppIdForProcess( + _In_ HANDLE ProcessId, + _Out_ PPH_STRING *ApplicationUserModelId + ); + +PPH_LIST PhGetPackageAssetsFromResourceFile( + _In_ PWSTR FilePath + ); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/phlib/include/appresolverp.h b/phlib/include/appresolverp.h new file mode 100644 index 000000000000..c556904470e6 --- /dev/null +++ b/phlib/include/appresolverp.h @@ -0,0 +1,527 @@ +/* + * Process Hacker - + * Appmodel support functions + * + * Copyright (C) 2017-2018 dmex + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#ifndef _PH_APPRESOLVER_P_H +#define _PH_APPRESOLVER_P_H + +// "660B90C8-73A9-4B58-8CAE-355B7F55341B" +static CLSID CLSID_StartMenuCacheAndAppResolver_I = { 0x660B90C8, 0x73A9, 0x4B58,{ 0x8C, 0xAE, 0x35, 0x5B, 0x7F, 0x55, 0x34, 0x1B } }; +// "46A6EEFF-908E-4DC6-92A6-64BE9177B41C" +static IID IID_IApplicationResolver61_I = { 0x46A6EEFF, 0x908E, 0x4DC6,{ 0x92, 0xA6, 0x64, 0xBE, 0x91, 0x77, 0xB4, 0x1c } }; +// "DE25675A-72DE-44b4-9373-05170450C140" +static IID IID_IApplicationResolver62_I = { 0xDE25675A, 0x72DE, 0x44b4,{ 0x93, 0x73, 0x05, 0x17, 0x04, 0x50, 0xC1, 0x40 } }; +// "33F71155-C2E9-4FFE-9786-A32D98577CFF" +static IID IID_IStartMenuAppItems61_I = { 0x33F71155, 0xC2E9, 0x4FFE,{ 0x97, 0x86, 0xA3, 0x2D, 0x98, 0x57, 0x7C, 0xFF } }; +// "02C5CCF3-805F-4654-A7B7-340A74335365" +static IID IID_IStartMenuAppItems62_I = { 0x02C5CCF3, 0x805F, 0x4654,{ 0xA7, 0xB7, 0x34, 0x0A, 0x74, 0x33, 0x53, 0x65 } }; + +// "DBCE7E40-7345-439D-B12C-114A11819A09" +static CLSID CLSID_MrtResourceManager_I = { 0xDBCE7E40, 0x7345, 0x439D,{ 0xB1, 0x2C, 0x11, 0x4A, 0x11, 0x81, 0x9A, 0x09 } }; +// "130A2F65-2BE7-4309-9A58-A9052FF2B61C" +static IID IID_IMrtResourceManager_I = { 0x130A2F65, 0x2BE7, 0x4309,{ 0x9A, 0x58, 0xA9, 0x05, 0x2F, 0xF2, 0xB6, 0x1C } }; +// "E3C22B30-8502-4B2F-9133-559674587E51" +static IID IID_IResourceContext_I = { 0xE3C22B30, 0x8502, 0x4B2F,{ 0x91, 0x33, 0x55, 0x96, 0x74, 0x58, 0x7E, 0x51 } }; +// "6E21E72B-B9B0-42AE-A686-983CF784EDCD" +static IID IID_IResourceMap_I = { 0x6E21E72B, 0xB9B0, 0x42AE,{ 0xA6, 0x86, 0x98, 0x3C, 0xF7, 0x84, 0xED, 0xCD } }; + +typedef enum _START_MENU_APP_ITEMS_FLAGS +{ + SMAIF_DEFAULT = 0, + SMAIF_EXTENDED = 1, + SMAIF_USAGEINFO = 2 +} START_MENU_APP_ITEMS_FLAGS; + +#undef INTERFACE +#define INTERFACE IApplicationResolver61 +DECLARE_INTERFACE_IID(IApplicationResolver61, IUnknown) +{ + BEGIN_INTERFACE + + // IUnknown + STDMETHOD(QueryInterface)(THIS, REFIID riid, PVOID *ppvObject) PURE; + STDMETHOD_(ULONG, AddRef)(THIS) PURE; + STDMETHOD_(ULONG, Release)(THIS) PURE; + + // IApplicationResolver61 + STDMETHOD(GetAppIDForShortcut)(THIS, + _In_ IShellItem *psi, + _Outptr_ PWSTR *ppszAppID + ) PURE; + STDMETHOD(GetAppIDForWindow)(THIS, + _In_ HWND hwnd, + _Outptr_ PWSTR *ppszAppID, + _Out_opt_ BOOL *pfPinningPrevented, + _Out_opt_ BOOL *pfExplicitAppID, + _Out_opt_ BOOL *pfEmbeddedShortcutValid + ) PURE; + STDMETHOD(GetAppIDForProcess)(THIS, + _In_ ULONG dwProcessID, + _Outptr_ PWSTR *ppszAppID, + _Out_opt_ BOOL *pfPinningPrevented, + _Out_opt_ BOOL *pfExplicitAppID, + _Out_opt_ BOOL *pfEmbeddedShortcutValid + ) PURE; + STDMETHOD(GetShortcutForProcess)(THIS, + _In_ ULONG dwProcessID, + _Outptr_ IShellItem **ppsi + ) PURE; + STDMETHOD(GetBestShortcutForAppID)(THIS, + _In_ PCWSTR pszAppID, + _Outptr_ IShellItem **ppsi + ) PURE; + STDMETHOD(GetBestShortcutAndAppIDForAppPath)(THIS, + _In_ PCWSTR pszAppPath, + _Outptr_opt_ IShellItem **ppsi, + _Outptr_opt_ PWSTR *ppszAppID + ) PURE; + STDMETHOD(CanPinApp)(THIS, + _In_ IShellItem *psi + ) PURE; + STDMETHOD(GetRelaunchProperties)(THIS, + _In_ HWND hwnd, + _Outptr_opt_result_maybenull_ PWSTR *ppszAppID, + _Outptr_opt_result_maybenull_ PWSTR *ppszCmdLine, + _Outptr_opt_result_maybenull_ PWSTR *ppszIconResource, + _Outptr_opt_result_maybenull_ PWSTR *ppszDisplayNameResource, + _Out_opt_ BOOL *pfPinnable + ) PURE; + STDMETHOD(GenerateShortcutFromWindowProperties)(THIS, + _In_ HWND hwnd, + _Outptr_ IShellItem **ppsi + ) PURE; + STDMETHOD(GenerateShortcutFromItemProperties)(THIS, + _In_ IShellItem2 *psi2, + _Out_opt_ IShellItem **ppsi + ) PURE; + + END_INTERFACE +}; + +#define IApplicationResolver_QueryInterface(This, riid, ppvObject) \ + ((This)->lpVtbl->QueryInterface(This, riid, ppvObject)) +#define IApplicationResolver_AddRef(This) \ + ((This)->lpVtbl->AddRef(This)) +#define IApplicationResolver_Release(This) \ + ((This)->lpVtbl->Release(This)) +#define IApplicationResolver_GetAppIDForShortcut(This, psi, ppszAppID) \ + ((This)->lpVtbl->GetAppIDForShortcut(This, psi, ppszAppID)) +#define IApplicationResolver_GetAppIDForWindow(This, hwnd, ppszAppID, pfPinningPrevented, pfExplicitAppID, pfEmbeddedShortcutValid) \ + ((This)->lpVtbl->GetAppIDForWindow(This, hwnd, ppszAppID, pfPinningPrevented, pfExplicitAppID, pfEmbeddedShortcutValid)) +#define IApplicationResolver_GetAppIDForProcess(This, dwProcessID, ppszAppID, pfPinningPrevented, pfExplicitAppID, pfEmbeddedShortcutValid) \ + ((This)->lpVtbl->GetAppIDForProcess(This, dwProcessID, ppszAppID, pfPinningPrevented, pfExplicitAppID, pfEmbeddedShortcutValid)) +#define IApplicationResolver_GetShortcutForProcess(This, dwProcessID, ppsi) \ + ((This)->lpVtbl->GetShortcutForProcess(This, dwProcessID, ppsi)) +#define IApplicationResolver_GetBestShortcutForAppID(This, pszAppID, ppsi) \ + ((This)->lpVtbl->GetBestShortcutForAppID(This, pszAppID, ppsi)) +#define IApplicationResolver_GetBestShortcutAndAppIDForAppPath(This, pszAppPath, ppsi, ppszAppID) \ + ((This)->lpVtbl->GetBestShortcutAndAppIDForAppPath(This, pszAppPath, ppsi, ppszAppID)) +#define IApplicationResolver_CanPinApp(This, psi) \ + ((This)->lpVtbl->CanPinApp(This, psi)) +#define IApplicationResolver_GetRelaunchProperties(This, hwnd, ppszAppID, ppszCmdLine, ppszIconResource, ppszDisplayNameResource, pfPinnable) \ + ((This)->lpVtbl->GetRelaunchProperties(This, hwnd, ppszAppID, ppszCmdLine, ppszIconResource, ppszDisplayNameResource, pfPinnable)) +#define IApplicationResolver_GenerateShortcutFromWindowProperties(This, ppsi) \ + ((This)->lpVtbl->GenerateShortcutFromWindowProperties(This, ppsi)) +#define IApplicationResolver_GenerateShortcutFromItemProperties(This, psi2, ppsi) \ + ((This)->lpVtbl->GenerateShortcutFromItemProperties(This, psi2, ppsi)) + +#undef INTERFACE +#define INTERFACE IApplicationResolver62 +DECLARE_INTERFACE_IID(IApplicationResolver62, IUnknown) +{ + BEGIN_INTERFACE + + // IUnknown + STDMETHOD(QueryInterface)(THIS, REFIID riid, PVOID *ppvObject) PURE; + STDMETHOD_(ULONG, AddRef)(THIS) PURE; + STDMETHOD_(ULONG, Release)(THIS) PURE; + + // IApplicationResolver62 + STDMETHOD(GetAppIDForShortcut)(THIS, + _In_ IShellItem *psi, + _Outptr_ PWSTR *ppszAppID + ) PURE; + STDMETHOD(GetAppIDForShortcutObject)(THIS, + _In_ IShellLinkW *psl, + _In_ IShellItem *psi, + _Outptr_ PWSTR *ppszAppID + ) PURE; + STDMETHOD(GetAppIDForWindow)(THIS, + _In_ HWND hwnd, + _Outptr_ PWSTR *ppszAppID, + _Out_opt_ BOOL *pfPinningPrevented, + _Out_opt_ BOOL *pfExplicitAppID, + _Out_opt_ BOOL *pfEmbeddedShortcutValid + ) PURE; + STDMETHOD(GetAppIDForProcess)(THIS, + _In_ ULONG dwProcessID, + _Outptr_ PWSTR *ppszAppID, + _Out_opt_ BOOL *pfPinningPrevented, + _Out_opt_ BOOL *pfExplicitAppID, + _Out_opt_ BOOL *pfEmbeddedShortcutValid + ) PURE; + STDMETHOD(GetShortcutForProcess)(THIS, + _In_ ULONG dwProcessID, + _Outptr_ IShellItem **ppsi + ) PURE; + STDMETHOD(GetBestShortcutForAppID)(THIS, + _In_ PCWSTR pszAppID, + _Outptr_ IShellItem **ppsi + ) PURE; + STDMETHOD(GetBestShortcutAndAppIDForAppPath)(THIS, + _In_ PCWSTR pszAppPath, + _Outptr_opt_ IShellItem **ppsi, + _Outptr_opt_ PWSTR *ppszAppID + ) PURE; + STDMETHOD(CanPinApp)(THIS, + _In_ IShellItem *psi + ) PURE; + STDMETHOD(CanPinAppShortcut)(THIS, + _In_ IShellLinkW *psl, + _In_ IShellItem *psi + ) PURE; + STDMETHOD(GetRelaunchProperties)(THIS, + _In_ HWND hwnd, + _Outptr_opt_result_maybenull_ PWSTR *ppszAppID, + _Outptr_opt_result_maybenull_ PWSTR *ppszCmdLine, + _Outptr_opt_result_maybenull_ PWSTR *ppszIconResource, + _Outptr_opt_result_maybenull_ PWSTR *ppszDisplayNameResource, + _Out_opt_ BOOL *pfPinnable + ) PURE; + STDMETHOD(GenerateShortcutFromWindowProperties)(THIS, + _In_ HWND hwnd, + _Outptr_ IShellItem **ppsi + ) PURE; + STDMETHOD(GenerateShortcutFromItemProperties)(THIS, + _In_ IShellItem2 *psi2, + _Out_opt_ IShellItem **ppsi + ) PURE; + + END_INTERFACE +}; + +#define IApplicationResolver2_QueryInterface(This, riid, ppvObject) \ + ((This)->lpVtbl->QueryInterface(This, riid, ppvObject)) +#define IApplicationResolver2_AddRef(This) \ + ((This)->lpVtbl->AddRef(This)) +#define IApplicationResolver2_Release(This) \ + ((This)->lpVtbl->Release(This)) +#define IApplicationResolver2_GetAppIDForShortcut(This, psl, psi, ppszAppID) \ + ((This)->lpVtbl->GetAppIDForShortcut(This, psl, psi, ppszAppID)) +#define IApplicationResolver2_GetAppIDForShortcutObject(This, psl, ppszAppID) \ + ((This)->lpVtbl->GetAppIDForShortcutObject(This, psl, ppszAppID)) +#define IApplicationResolver2_GetAppIDForWindow(This, hwnd, ppszAppID, pfPinningPrevented, pfExplicitAppID, pfEmbeddedShortcutValid) \ + ((This)->lpVtbl->GetAppIDForWindow(This, hwnd, ppszAppID, pfPinningPrevented, pfExplicitAppID, pfEmbeddedShortcutValid)) +#define IApplicationResolver2_GetAppIDForProcess(This, dwProcessID, ppszAppID, pfPinningPrevented, pfExplicitAppID, pfEmbeddedShortcutValid) \ + ((This)->lpVtbl->GetAppIDForProcess(This, dwProcessID, ppszAppID, pfPinningPrevented, pfExplicitAppID, pfEmbeddedShortcutValid)) +#define IApplicationResolver2_GetShortcutForProcess(This, dwProcessID, ppsi) \ + ((This)->lpVtbl->GetShortcutForProcess(This, dwProcessID, ppsi)) +#define IApplicationResolver2_GetBestShortcutForAppID(This, pszAppID, ppsi) \ + ((This)->lpVtbl->GetBestShortcutForAppID(This, pszAppID, ppsi)) +#define IApplicationResolver2_GetBestShortcutAndAppIDForAppPath(This, pszAppPath, ppsi, ppszAppID) \ + ((This)->lpVtbl->GetBestShortcutAndAppIDForAppPath(This, pszAppPath, ppsi, ppszAppID)) +#define IApplicationResolver2_CanPinApp(This, psi) \ + ((This)->lpVtbl->CanPinApp(This, psi)) +#define IApplicationResolver2_CanPinAppShortcut(This, psl, psi) \ + ((This)->lpVtbl->CanPinAppShortcut(This, psl, psi)) +#define IApplicationResolver2_GetRelaunchProperties(This, hwnd, ppszAppID, ppszCmdLine, ppszIconResource, ppszDisplayNameResource, pfPinnable) \ + ((This)->lpVtbl->GetRelaunchProperties(This, hwnd, ppszAppID, ppszCmdLine, ppszIconResource, ppszDisplayNameResource, pfPinnable)) +#define IApplicationResolver2_GenerateShortcutFromWindowProperties(This, ppsi) \ + ((This)->lpVtbl->GenerateShortcutFromWindowProperties(This, ppsi)) +#define IApplicationResolver2_GenerateShortcutFromItemProperties(This, psi2, ppsi) \ + ((This)->lpVtbl->GenerateShortcutFromItemProperties(This, psi2, ppsi)) + +#undef INTERFACE +#define INTERFACE IStartMenuAppItems61 +DECLARE_INTERFACE_IID(IStartMenuAppItems61, IUnknown) +{ + BEGIN_INTERFACE + + // IUnknown + STDMETHOD(QueryInterface)(THIS, REFIID riid, PVOID *ppvObject) PURE; + STDMETHOD_(ULONG, AddRef)(THIS) PURE; + STDMETHOD_(ULONG, Release)(THIS) PURE; + + // IStartMenuAppItems61 + STDMETHOD(EnumItems)(THIS, + _In_ ULONG Flags, + _In_ REFIID riid, + _Outptr_ IEnumObjects *ppvObject + ) PURE; + STDMETHOD(GetItem)(THIS, + _In_ ULONG Flags, + _In_ PWSTR AppUserModelId, + _In_ REFIID riid, + _Outptr_ PVOID *ppvObject // ppvObject == IPropertyStore, IStartMenuAppItems61 + ) PURE; + + END_INTERFACE +}; + +#define IStartMenuAppItems_QueryInterface(This, riid, ppvObject) \ + ((This)->lpVtbl->QueryInterface(This, riid, ppvObject)) +#define IStartMenuAppItems_AddRef(This) \ + ((This)->lpVtbl->AddRef(This)) +#define IStartMenuAppItems_Release(This) \ + ((This)->lpVtbl->Release(This)) +#define IStartMenuAppItems_EnumItems(This, Flags, riid, ppvObject) \ + ((This)->lpVtbl->EnumItems(This, Flags, riid, ppvObject)) +#define IStartMenuAppItems_GetItem(This, Flags, AppUserModelId, riid, ppvObject) \ + ((This)->lpVtbl->GetItem(This, Flags, AppUserModelId, riid, ppvObject)) + +#undef INTERFACE +#define INTERFACE IStartMenuAppItems62 +DECLARE_INTERFACE_IID(IStartMenuAppItems62, IUnknown) +{ + BEGIN_INTERFACE + + // IUnknown + STDMETHOD(QueryInterface)(THIS, REFIID riid, PVOID *ppvObject) PURE; + STDMETHOD_(ULONG, AddRef)(THIS) PURE; + STDMETHOD_(ULONG, Release)(THIS) PURE; + + // IStartMenuAppItems62 + STDMETHOD(EnumItems)(THIS, + _In_ ULONG Flags, + _In_ REFIID riid, + _Outptr_ IEnumObjects *ppvObject + ) PURE; + STDMETHOD(GetItem)(THIS, + _In_ ULONG Flags, + _In_ PWSTR AppUserModelId, + _In_ REFIID riid, + _Outptr_ PVOID *ppvObject // ppvObject == IPropertyStore, IStartMenuAppItems61 + ) PURE; + // STDMETHOD(Unknown)(THIS) + // STDMETHOD(Unknown)(THIS) + + END_INTERFACE +}; + +#define IStartMenuAppItems2_QueryInterface(This, riid, ppvObject) \ + ((This)->lpVtbl->QueryInterface(This, riid, ppvObject)) +#define IStartMenuAppItems2_AddRef(This) \ + ((This)->lpVtbl->AddRef(This)) +#define IStartMenuAppItems2_Release(This) \ + ((This)->lpVtbl->Release(This)) +#define IStartMenuAppItems2_EnumItems(This, Flags, riid, ppvObject) \ + ((This)->lpVtbl->EnumItems(This, Flags, riid, ppvObject)) +#define IStartMenuAppItems2_GetItem(This, Flags, AppUserModelId, riid, ppvObject) \ + ((This)->lpVtbl->GetItem(This, Flags, AppUserModelId, riid, ppvObject)) + +#undef INTERFACE +#define INTERFACE IMrtResourceManager +DECLARE_INTERFACE_IID(IMrtResourceManager, IUnknown) +{ + BEGIN_INTERFACE + + // IUnknown + STDMETHOD(QueryInterface)(THIS, REFIID riid, PVOID *ppvObject) PURE; + STDMETHOD_(ULONG, AddRef)(THIS) PURE; + STDMETHOD_(ULONG, Release)(THIS) PURE; + + // IMrtResourceManager + STDMETHOD(Initialize)(THIS) PURE; + STDMETHOD(InitializeForCurrentApplication)(THIS) PURE; + STDMETHOD(InitializeForPackage)(THIS, PCWSTR PackageName) PURE; + STDMETHOD(InitializeForFile)(THIS, PCWSTR) PURE; + STDMETHOD(GetMainResourceMap)(THIS, REFIID riid, PVOID *ppvObject) PURE; // IResourceMap + STDMETHOD(GetResourceMap)(THIS, PCWSTR, REFIID riid, PVOID *ppvObject) PURE; // IResourceMap + STDMETHOD(GetDefaultContext)(THIS, REFIID riid, PVOID *ppvObject) PURE; // IResourceContext + STDMETHOD(GetReference)(THIS, REFIID riid, PVOID *ppvObject) PURE; + STDMETHOD(IsResourceReference)(THIS, PCWSTR, BOOL *IsReference) PURE; + + END_INTERFACE +}; + +#define IMrtResourceManager_QueryInterface(This, riid, ppvObject) \ + ((This)->lpVtbl->QueryInterface(This, riid, ppvObject)) +#define IMrtResourceManager_AddRef(This) \ + ((This)->lpVtbl->AddRef(This)) +#define IMrtResourceManager_Release(This) \ + ((This)->lpVtbl->Release(This)) +#define IMrtResourceManager_Initialize(This) \ + ((This)->lpVtbl->Initialize(This)) +#define IMrtResourceManager_InitializeForCurrentApplication(This) \ + ((This)->lpVtbl->InitializeForCurrentApplication(This)) +#define IMrtResourceManager_InitializeForPackage(This, PackageName) \ + ((This)->lpVtbl->InitializeForPackage(This, PackageName)) +#define IMrtResourceManager_InitializeForFile(This, FilePath) \ + ((This)->lpVtbl->InitializeForFile(This, FilePath)) +#define IMrtResourceManager_GetMainResourceMap(This, riid, ppvObject) \ + ((This)->lpVtbl->GetMainResourceMap(This, riid, ppvObject)) +#define IMrtResourceManager_GetResourceMap(This, Name, riid, ppvObject) \ + ((This)->lpVtbl->GetResourceMap(This, Name, riid, ppvObject)) +#define IMrtResourceManager_GetDefaultContext(This, riid, ppvObject) \ + ((This)->lpVtbl->GetDefaultContext(This, riid, ppvObject)) +#define IMrtResourceManager_GetReference(This, riid, ppvObject) \ + ((This)->lpVtbl->GetReference(This, riid, ppvObject)) +#define IMrtResourceManager_IsResourceReference(This, Name, IsReference) \ + ((This)->lpVtbl->IsResourceReference(This, Name, IsReference)) + +#undef INTERFACE +#define INTERFACE IResourceContext +DECLARE_INTERFACE_IID(IResourceContext, IUnknown) +{ + BEGIN_INTERFACE + + // IUnknown + STDMETHOD(QueryInterface)(THIS, REFIID riid, PVOID *ppvObject) PURE; + STDMETHOD_(ULONG, AddRef)(THIS) PURE; + STDMETHOD_(ULONG, Release)(THIS) PURE; + + // IResourceContext + STDMETHOD(GetLanguage)(THIS, PWSTR*) PURE; + STDMETHOD(GetHomeRegion)(THIS, PCWSTR*) PURE; + STDMETHOD(GetLayoutDirection)(THIS, ULONG*) PURE; // RESOURCE_LAYOUT_DIRECTION + STDMETHOD(GetTargetSize)(THIS, USHORT*) PURE; + STDMETHOD(GetScale)(THIS, ULONG*) PURE; // RESOURCE_SCALE + STDMETHOD(GetContrast)(THIS, ULONG*) PURE; // RESOURCE_CONTRAST + STDMETHOD(GetAlternateForm)(THIS, PCWSTR*) PURE; + STDMETHOD(GetQualifierValue)(THIS, LPCWSTR, LPWSTR*) PURE; + STDMETHOD(SetLanguage)(THIS, LPCWSTR) PURE; + STDMETHOD(SetHomeRegion)(THIS, LPCWSTR) PURE; + STDMETHOD(SetLayoutDirection)(THIS, ULONG) PURE; // RESOURCE_LAYOUT_DIRECTION + STDMETHOD(SetTargetSize)(THIS, USHORT) PURE; + STDMETHOD(SetScale)(THIS, ULONG) PURE; // RESOURCE_SCALE + STDMETHOD(SetContrast)(THIS, ULONG) PURE; // RESOURCE_CONTRAST + STDMETHOD(SetAlternateForm)(THIS, LPCWSTR) PURE; + STDMETHOD(SetQualifierValue)(THIS, LPCWSTR, LPCWSTR) PURE; + STDMETHOD(TrySetQualifierValue)(THIS, LPCWSTR, LPCWSTR, HRESULT*) PURE; + STDMETHOD(Reset)(THIS) PURE; + STDMETHOD(ResetQualifierValue)(THIS, LPCWSTR) PURE; + STDMETHOD(Clone)(THIS, IResourceContext**) PURE; + STDMETHOD(OverrideToMatch)(THIS, struct IResourceCandidate*) PURE; + + END_INTERFACE +}; + +#undef INTERFACE +#define INTERFACE IResourceMap +DECLARE_INTERFACE_IID(IResourceMap, IUnknown) +{ + BEGIN_INTERFACE + + // IUnknown + STDMETHOD(QueryInterface)(THIS, REFIID riid, PVOID *ppvObject) PURE; + STDMETHOD_(ULONG, AddRef)(THIS) PURE; + STDMETHOD_(ULONG, Release)(THIS) PURE; + + // IResourceMap + STDMETHOD(GetUri)(THIS, PWSTR *UriString) PURE; + STDMETHOD(GetSubtree)(THIS, PCWSTR *Name, IResourceMap** ResourceMap) PURE; + STDMETHOD(GetString)(THIS, PCWSTR Key, PWSTR *Value) PURE; + STDMETHOD(GetStringForContext)(THIS, IResourceContext* Context, PCWSTR Key, PWSTR *Value) PURE; + STDMETHOD(GetFilePath)(THIS, PCWSTR Key, PWSTR *Value) PURE; + STDMETHOD(GetFilePathForContext)(THIS, IResourceContext*, PCWSTR, PWSTR*) PURE; + STDMETHOD(GetNamedResourceCount)(THIS, PULONG) PURE; + STDMETHOD(GetNamedResourceUri)(THIS, ULONG, PWSTR*) PURE; + STDMETHOD(GetNamedResource)(THIS, PCWSTR, REFIID riid, PVOID *ppvObject) PURE; + STDMETHOD(GetFullyQualifiedReference)(THIS, LPCWSTR, LPCWSTR, LPWSTR*) PURE; + STDMETHOD(GetFilePathByUri)(THIS, IUri*, LPWSTR*) PURE; + STDMETHOD(GetFilePathForContextByUri)(THIS, IResourceContext*, IUri*, LPWSTR*) PURE; + + END_INTERFACE +}; + +#define IResourceMap_QueryInterface(This, riid, ppvObject) \ + ((This)->lpVtbl->QueryInterface(This, riid, ppvObject)) +#define IResourceMap_AddRef(This) \ + ((This)->lpVtbl->AddRef(This)) +#define IResourceMap_Release(This) \ + ((This)->lpVtbl->Release(This)) +#define IResourceMap_GetUri(This, UriString) \ + ((This)->lpVtbl->GetUri(This, UriString)) +#define IResourceMap_GetSubtree(This, Name, ResourceMap) \ + ((This)->lpVtbl->GetSubtree(This, Name, ResourceMap)) +#define IResourceMap_GetString(This, Key, Value) \ + ((This)->lpVtbl->GetString(This, Key, Value)) +#define IResourceMap_GetStringForContext(This, Context, Key, Value) \ + ((This)->lpVtbl->GetStringForContext(This, Context, Key, Value)) +#define IResourceMap_GetFilePath(This, Key, Value) \ + ((This)->lpVtbl->GetFilePath(This, Key, Value)) +#define IResourceMap_GetFilePathForContext(This) \ + ((This)->lpVtbl->GetFilePathForContext(This)) +#define IResourceMap_GetNamedResourceCount(This, Count) \ + ((This)->lpVtbl->GetNamedResourceCount(This, Count)) +#define IResourceMap_GetNamedResourceUri(This, Index, Name) \ + ((This)->lpVtbl->GetNamedResourceUri(This, Index, Name)) +#define IResourceMap_GetNamedResource(This) \ + ((This)->lpVtbl->GetNamedResource(This)) +#define IResourceMap_GetFullyQualifiedReference(This) \ + ((This)->lpVtbl->GetFullyQualifiedReference(This)) +#define IResourceMap_GetFilePathByUri(This) \ + ((This)->lpVtbl->GetFilePathByUri(This)) +#define IResourceMap_GetFilePathForContextByUri(This) \ + ((This)->lpVtbl->GetFilePathForContextByUri(This)) + +// Note: Documented PKEY_AppUserModel_XYZ keys can be found in propkey.h +DEFINE_PROPERTYKEY(PKEY_AppUserModel_HostEnvironment, 0x9F4C2855, 0x9F79, 0x4B39, 0xA8, 0xD0, 0xE1, 0xD4, 0x2D, 0xE1, 0xD5, 0xF3, 14); +DEFINE_PROPERTYKEY(PKEY_AppUserModel_PackageInstallPath, 0x9F4C2855, 0x9F79, 0x4B39, 0xA8, 0xD0, 0xE1, 0xD4, 0x2D, 0xE1, 0xD5, 0xF3, 15); +DEFINE_PROPERTYKEY(PKEY_AppUserModel_PackageFamilyName, 0x9F4C2855, 0x9F79, 0x4B39, 0xA8, 0xD0, 0xE1, 0xD4, 0x2D, 0xE1, 0xD5, 0xF3, 17); +DEFINE_PROPERTYKEY(PKEY_AppUserModel_ParentID, 0x9F4C2855, 0x9F79, 0x4B39, 0xA8, 0xD0, 0xE1, 0xD4, 0x2D, 0xE1, 0xD5, 0xF3, 19); +DEFINE_PROPERTYKEY(PKEY_AppUserModel_PackageFullName, 0x9F4C2855, 0x9F79, 0x4B39, 0xA8, 0xD0, 0xE1, 0xD4, 0x2D, 0xE1, 0xD5, 0xF3, 21); +// PKEY_AppUserModel_ExcludeFromShowInNewInstall {9f4c2855-9f79-4b39-a8d0-e1d42de1d5f3} 8 +//2 PKEY_AppUserModel_ID {9f4c2855-9f79-4b39-a8d0-e1d42de1d5f3} 5 +//3 PKEY_AppUserModel_IsDestListSeparator {9f4c2855-9f79-4b39-a8d0-e1d42de1d5f3} 6 +//4 PKEY_AppUserModel_IsDualMode {9f4c2855-9f79-4b39-a8d0-e1d42de1d5f3} 11 +//5 PKEY_AppUserModel_PreventPinning {9f4c2855-9f79-4b39-a8d0-e1d42de1d5f3} 9 +//6 PKEY_AppUserModel_RelaunchCommand {9f4c2855-9f79-4b39-a8d0-e1d42de1d5f3} 2 +//7 PKEY_AppUserModel_RelaunchDisplayNameResource {9f4c2855-9f79-4b39-a8d0-e1d42de1d5f3} 4 +//8 PKEY_AppUserModel_RelaunchIconResource {9f4c2855-9f79-4b39-a8d0-e1d42de1d5f3} 3 +//9 PKEY_AppUserModel_StartPinOption {9f4c2855-9f79-4b39-a8d0-e1d42de1d5f3} 12 +//10 PKEY_AppUserModel_ToastActivatorCLSID {9f4c2855-9f79-4b39-a8d0-e1d42de1d5f3} 26 +//11 PKEY_AppUserModel_PackageInstallPath {9f4c2855-9f79-4b39-a8d0-e1d42de1d5f3} 15 +//12 PKEY_AppUserModel_RecordState {9f4c2855-9f79-4b39-a8d0-e1d42de1d5f3} 16 +//13 PKEY_AppUserModel_PackageFullName {9f4c2855-9f79-4b39-a8d0-e1d42de1d5f3} 21 +//14 PKEY_AppUserModel_DestListProvidedTitle {9f4c2855-9f79-4b39-a8d0-e1d42de1d5f3} 27 +//15 PKEY_AppUserModel_DestListProvidedDescription {9f4c2855-9f79-4b39-a8d0-e1d42de1d5f3} 28 +//16 PKEY_AppUserModel_ParentID {9f4c2855-9f79-4b39-a8d0-e1d42de1d5f3} 19 +//17 PKEY_AppUserModel_HostEnvironment {9f4c2855-9f79-4b39-a8d0-e1d42de1d5f3} 14 +//18 PKEY_AppUserModel_Relevance {9f4c2855-9f79-4b39-a8d0-e1d42de1d5f3} 13 +//19 PKEY_AppUserModel_PackageRelativeApplicationID {9f4c2855-9f79-4b39-a8d0-e1d42de1d5f3} 22 +//20 PKEY_AppUserModel_ExcludedFromLauncher {9f4c2855-9f79-4b39-a8d0-e1d42de1d5f3} 23 +//21 PKEY_AppUserModel_DestListLogoUri {9f4c2855-9f79-4b39-a8d0-e1d42de1d5f3} 29 +//22 PKEY_AppUserModel_ActivationContext {9f4c2855-9f79-4b39-a8d0-e1d42de1d5f3} 20 +//23 PKEY_AppUserModel_PackageFamilyName {9f4c2855-9f79-4b39-a8d0-e1d42de1d5f3} 17 +//24 PKEY_AppUserModel_BestShortcut {9f4c2855-9f79-4b39-a8d0-e1d42de1d5f3} 10 +//25 PKEY_AppUserModel_IsDestListLink {9f4c2855-9f79-4b39-a8d0-e1d42de1d5f3} 7 +//26 PKEY_AppUserModel_InstalledBy {9f4c2855-9f79-4b39-a8d0-e1d42de1d5f3} 18 +//27 PKEY_AppUserModel_RunFlags {9f4c2855-9f79-4b39-a8d0-e1d42de1d5f3} 25 +//28 PKEY_AppUserModel_DestListProvidedGroupName {9f4c2855-9f79-4b39-a8d0-e1d42de1d5f3} 30 +DEFINE_PROPERTYKEY(PKEY_Tile_SmallLogoPath, 0x86D40B4D, 0x9069, 0x443C, 0x81, 0x9A, 0x2A, 0x54, 0x09, 0x0D, 0xCC, 0xEC, 2); +DEFINE_PROPERTYKEY(PKEY_Tile_Background, 0x86D40B4D, 0x9069, 0x443C, 0x81, 0x9A, 0x2A, 0x54, 0x09, 0x0D, 0xCC, 0xEC, 4); +DEFINE_PROPERTYKEY(PKEY_Tile_Foreground, 0x86D40B4D, 0x9069, 0x443C, 0x81, 0x9A, 0x2A, 0x54, 0x09, 0x0D, 0xCC, 0xEC, 5); +DEFINE_PROPERTYKEY(PKEY_Tile_LongDisplayName, 0x86D40B4D, 0x9069, 0x443C, 0x81, 0x9A, 0x2A, 0x54, 0x09, 0x0D, 0xCC, 0xEC, 11); +DEFINE_PROPERTYKEY(PKEY_Tile_Flags, 0x86D40B4D, 0x9069, 0x443C, 0x81, 0x9A, 0x2A, 0x54, 0x09, 0x0D, 0xCC, 0xEC, 14); +DEFINE_PROPERTYKEY(PKEY_Tile_SuiteDisplayName, 0x86D40B4D, 0x9069, 0x443C, 0x81, 0x9A, 0x2A, 0x54, 0x09, 0x0D, 0xCC, 0xEC, 16); +DEFINE_PROPERTYKEY(PKEY_Tile_SuiteSortName, 0x86D40B4D, 0x9069, 0x443C, 0x81, 0x9A, 0x2A, 0x54, 0x09, 0x0D, 0xCC, 0xEC, 17); +DEFINE_PROPERTYKEY(PKEY_Tile_DisplayNameLanguage, 0x86D40B4D, 0x9069, 0x443C, 0x81, 0x9A, 0x2A, 0x54, 0x09, 0x0D, 0xCC, 0xEC, 18); +DEFINE_PROPERTYKEY(PKEY_Tile_BadgeLogoPath, 0x86D40B4D, 0x9069, 0x443C, 0x81, 0x9A, 0x2A, 0x54, 0x09, 0x0D, 0xCC, 0xEC, 15); +DEFINE_PROPERTYKEY(PKEY_Tile_Square150x150LogoPath, 0x86D40B4D, 0x9069, 0x443C, 0x81, 0x9A, 0x2A, 0x54, 0x09, 0x0D, 0xCC, 0xEC, 12); +DEFINE_PROPERTYKEY(PKEY_Tile_Wide310x150LogoPath, 0x86D40B4D, 0x9069, 0x443C, 0x81, 0x9A, 0x2A, 0x54, 0x09, 0x0D, 0xCC, 0xEC, 13); +DEFINE_PROPERTYKEY(PKEY_Tile_Square310x310LogoPath, 0x86D40B4D, 0x9069, 0x443C, 0x81, 0x9A, 0x2A, 0x54, 0x09, 0x0D, 0xCC, 0xEC, 19); +DEFINE_PROPERTYKEY(PKEY_Tile_Square70x70LogoPath, 0x86D40B4D, 0x9069, 0x443C, 0x81, 0x9A, 0x2A, 0x54, 0x09, 0x0D, 0xCC, 0xEC, 20); +DEFINE_PROPERTYKEY(PKEY_Tile_FencePost, 0x86D40B4D, 0x9069, 0x443C, 0x81, 0x9A, 0x2A, 0x54, 0x09, 0x0D, 0xCC, 0xEC, 21); +DEFINE_PROPERTYKEY(PKEY_Tile_InstallProgress, 0x86D40B4D, 0x9069, 0x443C, 0x81, 0x9A, 0x2A, 0x54, 0x09, 0x0D, 0xCC, 0xEC, 22); +DEFINE_PROPERTYKEY(PKEY_Tile_EncodedTargetPath, 0x86D40B4D, 0x9069, 0x443C, 0x81, 0x9A, 0x2A, 0x54, 0x09, 0x0D, 0xCC, 0xEC, 23); + +#endif diff --git a/phlib/phlib.vcxproj b/phlib/phlib.vcxproj index b8ae87a725c6..c518c7699a96 100644 --- a/phlib/phlib.vcxproj +++ b/phlib/phlib.vcxproj @@ -140,6 +140,7 @@ + @@ -208,6 +209,8 @@ + + diff --git a/phlib/phlib.vcxproj.filters b/phlib/phlib.vcxproj.filters index 088326bcfc68..146a23ef377e 100644 --- a/phlib/phlib.vcxproj.filters +++ b/phlib/phlib.vcxproj.filters @@ -221,6 +221,9 @@ Source Files + + Source Files + @@ -466,5 +469,11 @@ Header Files + + Header Files + + + Header Files + \ No newline at end of file From 1573163d4ce2c021951969c1ffc287a42a9634bb Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 20 Jan 2018 03:56:03 +1100 Subject: [PATCH 0698/2058] Improve process AppId column (now shows the real AppUserModelId for all processes) --- ProcessHacker/proctree.c | 127 +++++++++++++++++++++------------------ 1 file changed, 67 insertions(+), 60 deletions(-) diff --git a/ProcessHacker/proctree.c b/ProcessHacker/proctree.c index 02a0b0e7e840..6288e19e5924 100644 --- a/ProcessHacker/proctree.c +++ b/ProcessHacker/proctree.c @@ -31,6 +31,7 @@ #include #include +#include #include #include #include @@ -1125,71 +1126,77 @@ static VOID PhpUpdateProcessNodeAppId( if (!(ProcessNode->ValidMask & PHPN_APPID)) { ULONG windowFlags; - PPH_STRING windowTitle; + PPH_STRING applicationUserModelId; PhClearReference(&ProcessNode->AppIdText); - if (ProcessNode->ProcessItem->QueryHandle) + if (PhAppResolverGetAppIdForProcess(ProcessNode->ProcessItem->ProcessId, &applicationUserModelId)) { - //if (WindowsVersion >= WINDOWS_8 && ProcessNode->ProcessItem->IsImmersive) - //{ - // HANDLE tokenHandle; - // PTOKEN_SECURITY_ATTRIBUTES_INFORMATION info; - // - // if (NT_SUCCESS(PhOpenProcessToken( - // ProcessNode->ProcessItem->QueryHandle, - // TOKEN_QUERY, - // &tokenHandle - // ))) - // { - // // rev from GetApplicationUserModelId - // if (NT_SUCCESS(PhQueryTokenVariableSize(tokenHandle, TokenSecurityAttributes, &info))) - // { - // for (ULONG i = 0; i < info->AttributeCount; i++) - // { - // static UNICODE_STRING attributeNameUs = RTL_CONSTANT_STRING(L"WIN://SYSAPPID"); - // PTOKEN_SECURITY_ATTRIBUTE_V1 attribute = &info->Attribute.pAttributeV1[i]; - // - // if (RtlEqualUnicodeString(&attribute->Name, &attributeNameUs, FALSE)) - // { - // if (attribute->ValueType == TOKEN_SECURITY_ATTRIBUTE_TYPE_STRING) - // { - // PPH_STRING attributeValue1; - // PPH_STRING attributeValue2; - // - // attributeValue1 = PH_AUTO(PhCreateStringFromUnicodeString(&attribute->Values.pString[1])); - // attributeValue2 = PH_AUTO(PhCreateStringFromUnicodeString(&attribute->Values.pString[2])); - // - // ProcessNode->AppIdText = PhConcatStrings( - // 3, - // attributeValue2->Buffer, - // L"!", - // attributeValue1->Buffer - // ); - // - // break; - // } - // } - // } - // - // PhFree(info); - // } - // - // NtClose(tokenHandle); - // } - //} - //else - - if (NT_SUCCESS(PhGetProcessWindowTitle( - ProcessNode->ProcessItem->QueryHandle, - &windowFlags, - &windowTitle - ))) + ProcessNode->AppIdText = applicationUserModelId; + } + else + { + if (ProcessNode->ProcessItem->QueryHandle) { - if (windowFlags & STARTF_TITLEISAPPID) - ProcessNode->AppIdText = windowTitle; - else - PhDereferenceObject(windowTitle); + if (NT_SUCCESS(PhGetProcessWindowTitle( + ProcessNode->ProcessItem->QueryHandle, + &windowFlags, + &applicationUserModelId + ))) + { + if (windowFlags & STARTF_TITLEISAPPID) + ProcessNode->AppIdText = applicationUserModelId; + else + PhDereferenceObject(applicationUserModelId); + } + + //if (WindowsVersion >= WINDOWS_8 && ProcessNode->ProcessItem->IsImmersive) + //{ + // HANDLE tokenHandle; + // PTOKEN_SECURITY_ATTRIBUTES_INFORMATION info; + // + // if (NT_SUCCESS(PhOpenProcessToken( + // ProcessNode->ProcessItem->QueryHandle, + // TOKEN_QUERY, + // &tokenHandle + // ))) + // { + // // rev from GetApplicationUserModelId + // if (NT_SUCCESS(PhQueryTokenVariableSize(tokenHandle, TokenSecurityAttributes, &info))) + // { + // for (ULONG i = 0; i < info->AttributeCount; i++) + // { + // static UNICODE_STRING attributeNameUs = RTL_CONSTANT_STRING(L"WIN://SYSAPPID"); + // PTOKEN_SECURITY_ATTRIBUTE_V1 attribute = &info->Attribute.pAttributeV1[i]; + // + // if (RtlEqualUnicodeString(&attribute->Name, &attributeNameUs, FALSE)) + // { + // if (attribute->ValueType == TOKEN_SECURITY_ATTRIBUTE_TYPE_STRING) + // { + // PPH_STRING attributeValue1; + // PPH_STRING attributeValue2; + // + // attributeValue1 = PH_AUTO(PhCreateStringFromUnicodeString(&attribute->Values.pString[1])); + // attributeValue2 = PH_AUTO(PhCreateStringFromUnicodeString(&attribute->Values.pString[2])); + // + // ProcessNode->AppIdText = PhConcatStrings( + // 3, + // attributeValue2->Buffer, + // L"!", + // attributeValue1->Buffer + // ); + // + // break; + // } + // } + // } + // + // PhFree(info); + // } + // + // NtClose(tokenHandle); + // } + //} } } From 8348df1a4ae5686dfd5e47a68496f2d24bad33cb Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 20 Jan 2018 03:58:30 +1100 Subject: [PATCH 0699/2058] Add AppId column to process node cache --- ProcessHacker/proctree.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ProcessHacker/proctree.c b/ProcessHacker/proctree.c index 6288e19e5924..641dd4c0836e 100644 --- a/ProcessHacker/proctree.c +++ b/ProcessHacker/proctree.c @@ -647,7 +647,7 @@ VOID PhTickProcessNodes( // The name and PID never change, so we don't invalidate that. memset(&node->TextCache[2], 0, sizeof(PH_STRINGREF) * (PHPRTLC_MAXIMUM - 2)); - node->ValidMask &= PHPN_OSCONTEXT | PHPN_IMAGE | PHPN_DPIAWARENESS; // Items that always remain valid + node->ValidMask &= PHPN_OSCONTEXT | PHPN_IMAGE | PHPN_DPIAWARENESS | PHPN_APPID; // Items that always remain valid // Invalidate graph buffers. node->CpuGraphBuffers.Valid = FALSE; From 3f1572babb6616f49ba7fac35c1d55029fba562b Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 20 Jan 2018 05:56:46 +1100 Subject: [PATCH 0700/2058] Add text trayicon support, Update View->Tray Icons menu --- ProcessHacker/ProcessHacker.def | 1 + ProcessHacker/ProcessHacker.rc | 9 +- ProcessHacker/include/mainwndp.h | 4 - ProcessHacker/include/notifico.h | 64 ++- ProcessHacker/include/notificop.h | 81 ++- ProcessHacker/include/phplug.h | 42 +- ProcessHacker/mainwnd.c | 126 +--- ProcessHacker/notifico.c | 920 ++++++++++++++++++++---------- ProcessHacker/plugin.c | 34 +- ProcessHacker/procprv.c | 2 +- ProcessHacker/resource.h | 3 +- ProcessHacker/settings.c | 5 +- phlib/graph.c | 98 ++++ phlib/include/graph.h | 9 + plugins/ExtendedTools/exttools.h | 2 +- plugins/ExtendedTools/iconext.c | 308 +++++++++- plugins/ExtendedTools/main.c | 18 +- 17 files changed, 1213 insertions(+), 513 deletions(-) diff --git a/ProcessHacker/ProcessHacker.def b/ProcessHacker/ProcessHacker.def index 6fe9f2e81071..16e4545ff152 100644 --- a/ProcessHacker/ProcessHacker.def +++ b/ProcessHacker/ProcessHacker.def @@ -466,6 +466,7 @@ EXPORTS ; graph PhDeleteGraphState PhDrawGraphDirect + PhDrawTrayIconText PhGetDrawInfoGraphBuffers PhGraphStateGetDrawInfo PhInitializeGraphState diff --git a/ProcessHacker/ProcessHacker.rc b/ProcessHacker/ProcessHacker.rc index c3de1b33c431..f96309641440 100644 --- a/ProcessHacker/ProcessHacker.rc +++ b/ProcessHacker/ProcessHacker.rc @@ -109,14 +109,7 @@ BEGIN POPUP "&View" BEGIN MENUITEM "System &information\aCtrl+I", ID_VIEW_SYSTEMINFORMATION - POPUP "&Tray icons" - BEGIN - MENUITEM "CPU &history", ID_TRAYICONS_CPUHISTORY - MENUITEM "CPU &usage", ID_TRAYICONS_CPUUSAGE - MENUITEM "&I/O history", ID_TRAYICONS_IOHISTORY - MENUITEM "&Commit charge history", ID_TRAYICONS_COMMITHISTORY - MENUITEM "&Physical memory history", ID_TRAYICONS_PHYSICALMEMORYHISTORY - END + MENUITEM "&Tray icons", ID_VIEW_TRAYICONS MENUITEM SEPARATOR MENUITEM "
    ", ID_VIEW_SECTIONPLACEHOLDER MENUITEM SEPARATOR diff --git a/ProcessHacker/include/mainwndp.h b/ProcessHacker/include/mainwndp.h index 13d25a772259..21351beb4ae3 100644 --- a/ProcessHacker/include/mainwndp.h +++ b/ProcessHacker/include/mainwndp.h @@ -185,10 +185,6 @@ VOID PhMwpInitializeSubMenu( _In_ ULONG Index ); -PPH_EMENU_ITEM PhMwpFindTrayIconsMenuItem( - _In_ PPH_EMENU Menu - ); - VOID PhMwpInitializeSectionMenuItems( _In_ PPH_EMENU Menu, _In_ ULONG StartIndex diff --git a/ProcessHacker/include/notifico.h b/ProcessHacker/include/notifico.h index b0a8d613c34e..d37459f2d095 100644 --- a/ProcessHacker/include/notifico.h +++ b/ProcessHacker/include/notifico.h @@ -1,14 +1,23 @@ #ifndef PH_NOTIFICO_H #define PH_NOTIFICO_H -#define PH_ICON_MINIMUM 0x1 -#define PH_ICON_CPU_HISTORY 0x1 -#define PH_ICON_IO_HISTORY 0x2 -#define PH_ICON_COMMIT_HISTORY 0x4 -#define PH_ICON_PHYSICAL_HISTORY 0x8 -#define PH_ICON_CPU_USAGE 0x10 -#define PH_ICON_DEFAULT_MAXIMUM 0x20 -#define PH_ICON_DEFAULT_ALL 0x1f +extern PPH_LIST PhTrayIconItemList; + +typedef enum _PH_TRAY_ICON_ID +{ + PH_TRAY_ICON_ID_NONE, + PH_TRAY_ICON_ID_CPU_USAGE, + PH_TRAY_ICON_ID_CPU_HISTORY, + PH_TRAY_ICON_ID_IO_HISTORY, + PH_TRAY_ICON_ID_COMMIT_HISTORY, + PH_TRAY_ICON_ID_PHYSICAL_HISTORY, + PH_TRAY_ICON_ID_CPU_TEXT, + PH_TRAY_ICON_ID_IO_TEXT, + PH_TRAY_ICON_ID_COMMIT_TEXT, + PH_TRAY_ICON_ID_PHYSICAL_TEXT +} PH_TRAY_ICON_ID; + +#define PH_TRAY_ICON_ID_PLUGIN 0x80 #define PH_ICON_LIMIT 0x80000000 #define PH_ICON_ALL 0xffffffff @@ -29,7 +38,6 @@ typedef VOID (NTAPI *PPH_NF_BEGIN_BITMAP)( typedef struct _PH_NF_POINTERS { - PPH_NF_UPDATE_REGISTERED_ICON UpdateRegisteredIcon; PPH_NF_BEGIN_BITMAP BeginBitmap; } PH_NF_POINTERS, *PPH_NF_POINTERS; @@ -63,8 +71,9 @@ typedef struct _PH_NF_MSG_SHOWMINIINFOSECTION_DATA // Structures and internal functions -#define PH_NF_ICON_UNAVAILABLE 0x1 -#define PH_NF_ICON_SHOW_MINIINFO 0x2 +#define PH_NF_ICON_ENABLED 0x1 +#define PH_NF_ICON_UNAVAILABLE 0x2 +#define PH_NF_ICON_NOSHOW_MINIINFO 0x4 // end_phapppub // begin_phapppub @@ -85,6 +94,9 @@ typedef struct _PH_NF_ICON ULONG IconId; PPH_NF_ICON_UPDATE_CALLBACK UpdateCallback; PPH_NF_ICON_MESSAGE_CALLBACK MessageCallback; + + PPH_STRING TextCache; + // begin_phapppub } PH_NF_ICON, *PPH_NF_ICON; // end_phapppub @@ -110,16 +122,8 @@ VOID PhNfForwardMessage( _In_ ULONG_PTR LParam ); -ULONG PhNfGetMaximumIconId( - VOID - ); - -ULONG PhNfTestIconMask( - _In_ ULONG Id - ); - VOID PhNfSetVisibleIcon( - _In_ ULONG Id, + _In_ PPH_NF_ICON Icon, _In_ BOOLEAN Visible ); @@ -135,9 +139,18 @@ HICON PhNfBitmapToIcon( _In_ HBITMAP Bitmap ); +struct _PH_NF_ICON *PhNfPluginRegisterIcon( + _In_ struct _PH_PLUGIN * Plugin, + _In_ ULONG SubId, + _In_opt_ PVOID Context, + _In_ PWSTR Text, + _In_ ULONG Flags, + _In_ struct _PH_NF_ICON_REGISTRATION_DATA *RegistrationData + ); + PPH_NF_ICON PhNfRegisterIcon( _In_ struct _PH_PLUGIN *Plugin, - _In_ ULONG SubId, + _In_ ULONG Id, _In_opt_ PVOID Context, _In_ PWSTR Text, _In_ ULONG Flags, @@ -154,6 +167,10 @@ PPH_NF_ICON PhNfFindIcon( _In_ ULONG SubId ); +BOOLEAN PhNfIconsEnabled( + VOID + ); + VOID PhNfNotifyMiniInfoPinned( _In_ BOOLEAN Pinned ); @@ -168,4 +185,9 @@ typedef struct _PH_NF_ICON_REGISTRATION_DATA } PH_NF_ICON_REGISTRATION_DATA, *PPH_NF_ICON_REGISTRATION_DATA; // end_phapppub + +VOID PhShowTrayIconCustomizeDialog( + VOID +); + #endif diff --git a/ProcessHacker/include/notificop.h b/ProcessHacker/include/notificop.h index 00a993da9040..5518f9b83a21 100644 --- a/ProcessHacker/include/notificop.h +++ b/ProcessHacker/include/notificop.h @@ -15,18 +15,18 @@ HICON PhNfpGetBlackIcon( ); BOOLEAN PhNfpAddNotifyIcon( - _In_ ULONG Id + _In_ PPH_NF_ICON Icon ); BOOLEAN PhNfpRemoveNotifyIcon( - _In_ ULONG Id + _In_ PPH_NF_ICON Icon ); BOOLEAN PhNfpModifyNotifyIcon( - _In_ ULONG Id, + _In_ PPH_NF_ICON Icon, _In_ ULONG Flags, _In_opt_ PPH_STRING Text, - _In_opt_ HICON Icon + _In_opt_ HICON IconHandle ); VOID PhNfpProcessesUpdatedHandler( @@ -57,24 +57,71 @@ VOID PhNfpBeginBitmap2( _Out_ HBITMAP *OldBitmap ); -VOID PhNfpUpdateIconCpuHistory( - VOID +VOID PhNfpCpuHistoryIconUpdateCallback( + _In_ struct _PH_NF_ICON *Icon, + _Out_ PVOID *NewIconOrBitmap, + _Out_ PULONG Flags, + _Out_ PPH_STRING *NewText, + _In_opt_ PVOID Context ); - -VOID PhNfpUpdateIconIoHistory( - VOID +VOID PhNfpIoHistoryIconUpdateCallback( + _In_ struct _PH_NF_ICON *Icon, + _Out_ PVOID *NewIconOrBitmap, + _Out_ PULONG Flags, + _Out_ PPH_STRING *NewText, + _In_opt_ PVOID Context ); - -VOID PhNfpUpdateIconCommitHistory( - VOID +VOID PhNfpCommitHistoryIconUpdateCallback( + _In_ struct _PH_NF_ICON *Icon, + _Out_ PVOID *NewIconOrBitmap, + _Out_ PULONG Flags, + _Out_ PPH_STRING *NewText, + _In_opt_ PVOID Context ); - -VOID PhNfpUpdateIconPhysicalHistory( - VOID +VOID PhNfpPhysicalHistoryIconUpdateCallback( + _In_ struct _PH_NF_ICON *Icon, + _Out_ PVOID *NewIconOrBitmap, + _Out_ PULONG Flags, + _Out_ PPH_STRING *NewText, + _In_opt_ PVOID Context + ); +VOID PhNfpCpuUsageIconUpdateCallback( + _In_ struct _PH_NF_ICON *Icon, + _Out_ PVOID *NewIconOrBitmap, + _Out_ PULONG Flags, + _Out_ PPH_STRING *NewText, + _In_opt_ PVOID Context ); -VOID PhNfpUpdateIconCpuUsage( - VOID +// Text icons + +VOID PhNfpCpuUsageTextIconUpdateCallback( + _In_ struct _PH_NF_ICON *Icon, + _Out_ PVOID *NewIconOrBitmap, + _Out_ PULONG Flags, + _Out_ PPH_STRING *NewText, + _In_opt_ PVOID Context + ); +VOID PhNfpIoUsageTextIconUpdateCallback( + _In_ struct _PH_NF_ICON *Icon, + _Out_ PVOID *NewIconOrBitmap, + _Out_ PULONG Flags, + _Out_ PPH_STRING *NewText, + _In_opt_ PVOID Context + ); +VOID PhNfpCommitTextIconUpdateCallback( + _In_ struct _PH_NF_ICON *Icon, + _Out_ PVOID *NewIconOrBitmap, + _Out_ PULONG Flags, + _Out_ PPH_STRING *NewText, + _In_opt_ PVOID Context + ); +VOID PhNfpPhysicalUsageTextIconUpdateCallback( + _In_ struct _PH_NF_ICON *Icon, + _Out_ PVOID *NewIconOrBitmap, + _Out_ PULONG Flags, + _Out_ PPH_STRING *NewText, + _In_opt_ PVOID Context ); BOOLEAN PhNfpGetShowMiniInfoSectionData( diff --git a/ProcessHacker/include/phplug.h b/ProcessHacker/include/phplug.h index 2be5efb9d36c..a4a4c36d44b9 100644 --- a/ProcessHacker/include/phplug.h +++ b/ProcessHacker/include/phplug.h @@ -45,6 +45,7 @@ typedef enum _PH_GENERAL_CALLBACK GeneralCallbackMiniInformationInitializing = 32, // PPH_PLUGIN_MINIINFO_POINTERS Data [main thread] GeneralCallbackMiListSectionMenuInitializing = 33, // PPH_PLUGIN_MENU_INFORMATION Data [main thread] GeneralCallbackOptionsWindowInitializing, // PPH_PLUGIN_OBJECT_PROPERTIES Data [main thread] + GeneralCallbackTrayIconsInitializing, GeneralCallbackMaximum } PH_GENERAL_CALLBACK, *PPH_GENERAL_CALLBACK; @@ -327,6 +328,35 @@ typedef struct _PH_PLUGIN_MINIINFO_POINTERS } PH_PLUGIN_MINIINFO_POINTERS, *PPH_PLUGIN_MINIINFO_POINTERS; // end_phapppub +// begin_phapppub +/** + * Creates a notification icon. + * + * \param Plugin A plugin instance structure. + * \param SubId An identifier for the column. This should be unique within the + * plugin. + * \param Context A user-defined value. + * \param Text A string describing the notification icon. + * \param Flags A combination of flags. + * \li \c PH_NF_ICON_UNAVAILABLE The notification icon is currently unavailable. + * \param RegistrationData A \ref PH_NF_ICON_REGISTRATION_DATA structure that + * contains registration information. + */ +typedef struct _PH_NF_ICON * (NTAPI *PPH_REGISTER_TRAY_ICON)( + _In_ struct _PH_PLUGIN * Plugin, + _In_ ULONG SubId, + _In_opt_ PVOID Context, + _In_ PWSTR Text, + _In_ ULONG Flags, + _In_ struct _PH_NF_ICON_REGISTRATION_DATA *RegistrationData + ); + +typedef struct _PH_TRAY_ICON_POINTERS +{ + PPH_REGISTER_TRAY_ICON RegisterTrayIcon; +} PH_TRAY_ICON_POINTERS, *PPH_TRAY_ICON_POINTERS; +// end_phapppub + // begin_phapppub typedef struct _PH_OPTIONS_SECTION { @@ -661,18 +691,6 @@ PhPluginGetObjectExtension( _In_ PH_EM_OBJECT_TYPE ObjectType ); -PHAPPAPI -struct _PH_NF_ICON * -NTAPI -PhPluginRegisterIcon( - _In_ PPH_PLUGIN Plugin, - _In_ ULONG SubId, - _In_opt_ PVOID Context, - _In_ PWSTR Text, - _In_ ULONG Flags, - _In_ struct _PH_NF_ICON_REGISTRATION_DATA *RegistrationData - ); - PHAPPAPI VOID NTAPI diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index 659779f72d12..0d7ef374a445 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -3,7 +3,7 @@ * Main window * * Copyright (C) 2009-2016 wj32 - * Copyright (C) 2017 dmex + * Copyright (C) 2017-2018 dmex * * This file is part of Process Hacker. * @@ -199,7 +199,7 @@ BOOLEAN PhMainWndInitialization( UpdateWindow(PhMainWndHandle); - if ((PhStartupParameters.ShowHidden || PhGetIntegerSetting(L"StartHidden")) && PhNfTestIconMask(PH_ICON_ALL)) + if ((PhStartupParameters.ShowHidden || PhGetIntegerSetting(L"StartHidden")) && PhNfIconsEnabled()) ShowCommand = SW_HIDE; if (PhStartupParameters.ShowVisible) ShowCommand = SW_SHOW; @@ -544,7 +544,7 @@ VOID PhMwpOnCommand( { if (PhGetIntegerSetting(L"HideOnClose")) { - if (PhNfTestIconMask(PH_ICON_ALL)) + if (PhNfIconsEnabled()) ShowWindow(PhMainWndHandle, SW_HIDE); } else if (PhGetIntegerSetting(L"CloseOnEscape")) @@ -714,36 +714,6 @@ VOID PhMwpOnCommand( case ID_VIEW_SYSTEMINFORMATION: PhShowSystemInformationDialog(NULL); break; - case ID_TRAYICONS_CPUHISTORY: - case ID_TRAYICONS_CPUUSAGE: - case ID_TRAYICONS_IOHISTORY: - case ID_TRAYICONS_COMMITHISTORY: - case ID_TRAYICONS_PHYSICALMEMORYHISTORY: - { - ULONG i; - - switch (Id) - { - case ID_TRAYICONS_CPUHISTORY: - i = PH_ICON_CPU_HISTORY; - break; - case ID_TRAYICONS_CPUUSAGE: - i = PH_ICON_CPU_USAGE; - break; - case ID_TRAYICONS_IOHISTORY: - i = PH_ICON_IO_HISTORY; - break; - case ID_TRAYICONS_COMMITHISTORY: - i = PH_ICON_COMMIT_HISTORY; - break; - case ID_TRAYICONS_PHYSICALMEMORYHISTORY: - i = PH_ICON_PHYSICAL_HISTORY; - break; - } - - PhNfSetVisibleIcon(i, !PhNfTestIconMask(i)); - } - break; case ID_VIEW_HIDEPROCESSESFROMOTHERUSERS: { PhMwpToggleCurrentUserProcessTreeFilter(); @@ -1544,7 +1514,7 @@ BOOLEAN PhMwpOnSysCommand( { case SC_CLOSE: { - if (PhGetIntegerSetting(L"HideOnClose") && PhNfTestIconMask(PH_ICON_ALL)) + if (PhGetIntegerSetting(L"HideOnClose") && PhNfIconsEnabled()) { ShowWindow(PhMainWndHandle, SW_HIDE); return TRUE; @@ -1556,7 +1526,7 @@ BOOLEAN PhMwpOnSysCommand( // Save the current window state because we may not have a chance to later. PhMwpSaveWindowState(); - if (PhGetIntegerSetting(L"HideOnMinimize") && PhNfTestIconMask(PH_ICON_ALL)) + if (PhGetIntegerSetting(L"HideOnMinimize") && PhNfIconsEnabled()) { ShowWindow(PhMainWndHandle, SW_HIDE); return TRUE; @@ -2325,7 +2295,7 @@ VOID PhMwpDispatchMenuCommand( PPH_NF_ICON icon; icon = menuItem->Context; - PhNfSetVisibleIcon(icon->IconId, !PhNfTestIconMask(icon->IconId)); + PhNfSetVisibleIcon(icon, !(icon->Flags & PH_NF_ICON_ENABLED)); } return; @@ -2459,71 +2429,31 @@ VOID PhMwpInitializeSubMenu( ULONG id; ULONG placeholderIndex; - trayIconsMenuItem = PhMwpFindTrayIconsMenuItem(Menu); - - if (trayIconsMenuItem) + if (trayIconsMenuItem = PhFindEMenuItem(Menu, PH_EMENU_FIND_DESCEND, NULL, ID_VIEW_TRAYICONS)) { - ULONG maximum; - PPH_NF_ICON icon; - // Add menu items for the registered tray icons. - id = PH_ICON_DEFAULT_MAXIMUM; - maximum = PhNfGetMaximumIconId(); - - for (; id != maximum; id <<= 1) + for (i = 0; i < PhTrayIconItemList->Count; i++) { - if (icon = PhNfGetIconById(id)) - { - PhInsertEMenuItem(trayIconsMenuItem, PhCreateEMenuItem(0, ID_TRAYICONS_REGISTERED, icon->Text, NULL, icon), -1); - } - } + PPH_NF_ICON icon = PhTrayIconItemList->Items[i]; - // Update the text and check marks on the menu items. - - for (i = 0; i < trayIconsMenuItem->Items->Count; i++) - { - menuItem = trayIconsMenuItem->Items->Items[i]; + menuItem = PhCreateEMenuItem(0, ID_TRAYICONS_REGISTERED, icon->Text, NULL, icon); + PhInsertEMenuItem(trayIconsMenuItem, menuItem, -1); - id = -1; - icon = NULL; + // Update the text and check marks on the menu items. - switch (menuItem->Id) + if (icon->Flags & PH_NF_ICON_ENABLED) { - case ID_TRAYICONS_CPUHISTORY: - id = PH_ICON_CPU_HISTORY; - break; - case ID_TRAYICONS_IOHISTORY: - id = PH_ICON_IO_HISTORY; - break; - case ID_TRAYICONS_COMMITHISTORY: - id = PH_ICON_COMMIT_HISTORY; - break; - case ID_TRAYICONS_PHYSICALMEMORYHISTORY: - id = PH_ICON_PHYSICAL_HISTORY; - break; - case ID_TRAYICONS_CPUUSAGE: - id = PH_ICON_CPU_USAGE; - break; - case ID_TRAYICONS_REGISTERED: - icon = menuItem->Context; - id = icon->IconId; - break; + menuItem->Flags |= PH_EMENU_CHECKED; } - if (id != -1) + if (icon->Flags & PH_NF_ICON_UNAVAILABLE) { - if (PhNfTestIconMask(id)) - menuItem->Flags |= PH_EMENU_CHECKED; + PPH_STRING newText; - if (icon && (icon->Flags & PH_NF_ICON_UNAVAILABLE)) - { - PPH_STRING newText; - - newText = PhaConcatStrings2(icon->Text, L" (Unavailable)"); - PhModifyEMenuItem(menuItem, PH_EMENU_MODIFY_TEXT, PH_EMENU_TEXT_OWNED, - PhAllocateCopy(newText->Buffer, newText->Length + sizeof(WCHAR)), NULL); - } + newText = PhaConcatStrings2(icon->Text, L" (Unavailable)"); + PhModifyEMenuItem(menuItem, PH_EMENU_MODIFY_TEXT, PH_EMENU_TEXT_OWNED, + PhAllocateCopy(newText->Buffer, newText->Length + sizeof(WCHAR)), NULL); } } } @@ -2592,24 +2522,6 @@ VOID PhMwpInitializeSubMenu( } } -PPH_EMENU_ITEM PhMwpFindTrayIconsMenuItem( - _In_ PPH_EMENU Menu - ) -{ - ULONG i; - PPH_EMENU_ITEM menuItem; - - for (i = 0; i < Menu->Items->Count; i++) - { - menuItem = Menu->Items->Items[i]; - - if (PhFindEMenuItem(menuItem, 0, NULL, ID_TRAYICONS_CPUHISTORY)) - return menuItem; - } - - return NULL; -} - VOID PhMwpInitializeSectionMenuItems( _In_ PPH_EMENU Menu, _In_ ULONG StartIndex diff --git a/ProcessHacker/notifico.c b/ProcessHacker/notifico.c index 4b72394b0adf..e88f771870c2 100644 --- a/ProcessHacker/notifico.c +++ b/ProcessHacker/notifico.c @@ -3,6 +3,7 @@ * notification icon manager * * Copyright (C) 2011-2016 wj32 + * Copyright (C) 2017-2018 dmex * * This file is part of Process Hacker. * @@ -36,12 +37,6 @@ #include #include -BOOLEAN PhNfTerminating = FALSE; -ULONG PhNfIconMask; -ULONG PhNfIconNotifyMask; -ULONG PhNfMaximumIconId = PH_ICON_DEFAULT_MAXIMUM; -PPH_NF_ICON PhNfRegisteredIcons[32] = { 0 }; -PPH_STRING PhNfIconTextCache[32] = { 0 }; BOOLEAN PhNfMiniInfoEnabled; BOOLEAN PhNfMiniInfoPinned; @@ -57,127 +52,164 @@ static PH_NF_MSG_SHOWMINIINFOSECTION_DATA IconClickShowMiniInfoSectionData; static BOOLEAN IconClickUpDueToDown; static BOOLEAN IconDisableHover; +// Note: no lock is needed because we only ever modify the list on this same thread. +PPH_LIST PhTrayIconItemList = NULL; + VOID PhNfLoadStage1( VOID ) { - PPH_STRING iconList; - PH_STRINGREF part; - PH_STRINGREF remainingPart; + PhTrayIconItemList = PhCreateList(20); - PhNfpPointers.UpdateRegisteredIcon = PhNfpUpdateRegisteredIcon; PhNfpPointers.BeginBitmap = PhNfpBeginBitmap; +} + +VOID PhNfLoadSettings( + VOID + ) +{ + PPH_STRING settingsString; + PH_STRINGREF remaining; + + settingsString = PhGetStringSetting(L"IconSettings"); + remaining = settingsString->sr; - // Load settings for default icons. - PhNfIconMask = PhGetIntegerSetting(L"IconMask"); + if (remaining.Length == 0) + { + PPH_NF_ICON icon; - // Load settings for registered icons. + // Load default settings. + if (icon = PhNfGetIconById(PH_TRAY_ICON_ID_CPU_USAGE)) + icon->Flags |= PH_NF_ICON_ENABLED; - iconList = PhGetStringSetting(L"IconMaskList"); - remainingPart = iconList->sr; + PhDereferenceObject(settingsString); + return; + } - while (remainingPart.Length != 0) + while (remaining.Length != 0) { - PhSplitStringRefAtChar(&remainingPart, '|', &part, &remainingPart); + PH_STRINGREF idPart; + PH_STRINGREF flagsPart; + PH_STRINGREF pluginNamePart; + ULONG64 idInteger; + ULONG64 flagsInteger; + + PhSplitStringRefAtChar(&remaining, '|', &idPart, &remaining); + PhSplitStringRefAtChar(&remaining, '|', &flagsPart, &remaining); + PhSplitStringRefAtChar(&remaining, '|', &pluginNamePart, &remaining); + + if (!PhStringToInteger64(&idPart, 10, &idInteger)) + break; + if (!PhStringToInteger64(&flagsPart, 10, &flagsInteger)) + break; - if (part.Length != 0) + if (flagsInteger) { - PH_STRINGREF pluginName; - ULONG subId; PPH_NF_ICON icon; - if (PhEmParseCompoundId(&part, &pluginName, &subId) && - (icon = PhNfFindIcon(&pluginName, subId))) + if (icon = PhNfFindIcon(&pluginNamePart, (ULONG)idInteger)) { - PhNfIconMask |= icon->IconId; + icon->Flags |= PH_NF_ICON_ENABLED; } } } - PhDereferenceObject(iconList); + PhDereferenceObject(settingsString); } -VOID PhNfLoadStage2( +VOID PhNfSaveSettings( VOID ) { - ULONG i; + PPH_STRING settingsString; + PH_STRING_BUILDER iconListBuilder; - PhNfMiniInfoEnabled = !!PhGetIntegerSetting(L"MiniInfoWindowEnabled"); + PhInitializeStringBuilder(&iconListBuilder, 100); - for (i = PH_ICON_MINIMUM; i != PhNfMaximumIconId; i <<= 1) + for (ULONG i = 0; i < PhTrayIconItemList->Count; i++) { - if (PhNfIconMask & i) - PhNfpAddNotifyIcon(i); + PPH_NF_ICON icon = PhTrayIconItemList->Items[i]; + + if (!(icon->Flags & PH_NF_ICON_ENABLED)) + continue; + + PhAppendFormatStringBuilder( + &iconListBuilder, + L"%lu|%lu|%s|", + icon->SubId, + icon->Flags & PH_NF_ICON_ENABLED ? 1 : 0, + icon->Plugin ? icon->Plugin->Name.Buffer : L"" + ); } - PhRegisterCallback( - &PhProcessesUpdatedEvent, - PhNfpProcessesUpdatedHandler, - NULL, - &PhNfpProcessesUpdatedRegistration - ); + if (iconListBuilder.String->Length != 0) + PhRemoveEndStringBuilder(&iconListBuilder, 1); + + settingsString = PhFinalStringBuilderString(&iconListBuilder); + PhSetStringSetting2(L"IconSettings", &settingsString->sr); + PhDereferenceObject(settingsString); } -VOID PhNfSaveSettings( +VOID PhNfLoadStage2( VOID ) { - ULONG registeredIconMask; - - PhSetIntegerSetting(L"IconMask", PhNfIconMask & PH_ICON_DEFAULT_ALL); - - registeredIconMask = PhNfIconMask & ~PH_ICON_DEFAULT_ALL; + PhNfMiniInfoEnabled = !!PhGetIntegerSetting(L"MiniInfoWindowEnabled"); - if (registeredIconMask != 0) + PhNfRegisterIcon(NULL, PH_TRAY_ICON_ID_CPU_USAGE, NULL, L"CPU &usage", 0, PhNfpCpuUsageIconUpdateCallback, NULL); + PhNfRegisterIcon(NULL, PH_TRAY_ICON_ID_CPU_HISTORY, NULL, L"CPU &history", 0, PhNfpCpuHistoryIconUpdateCallback, NULL); + PhNfRegisterIcon(NULL, PH_TRAY_ICON_ID_IO_HISTORY, NULL, L"&I/O history", 0, PhNfpIoHistoryIconUpdateCallback, NULL); + PhNfRegisterIcon(NULL, PH_TRAY_ICON_ID_COMMIT_HISTORY, NULL, L"&Commit charge history", 0, PhNfpCommitHistoryIconUpdateCallback, NULL); + PhNfRegisterIcon(NULL, PH_TRAY_ICON_ID_PHYSICAL_HISTORY, NULL, L"&Physical memory history", 0, PhNfpPhysicalHistoryIconUpdateCallback, NULL); + PhNfRegisterIcon(NULL, PH_TRAY_ICON_ID_CPU_TEXT, NULL, L"CPU usage (text)", 0, PhNfpCpuUsageTextIconUpdateCallback, NULL); + PhNfRegisterIcon(NULL, PH_TRAY_ICON_ID_IO_TEXT, NULL, L"IO usage (text)", 0, PhNfpIoUsageTextIconUpdateCallback, NULL); + PhNfRegisterIcon(NULL, PH_TRAY_ICON_ID_COMMIT_TEXT, NULL, L"Commit usage (text)", 0, PhNfpCommitTextIconUpdateCallback, NULL); + PhNfRegisterIcon(NULL, PH_TRAY_ICON_ID_PHYSICAL_TEXT, NULL, L"Physical usage (text)", 0, PhNfpPhysicalUsageTextIconUpdateCallback, NULL); + + if (PhPluginsEnabled) { - PH_STRING_BUILDER iconListBuilder; - ULONG i; + PH_TRAY_ICON_POINTERS pointers; - PhInitializeStringBuilder(&iconListBuilder, 60); + pointers.RegisterTrayIcon = PhNfPluginRegisterIcon; - for (i = 0; i < sizeof(PhNfRegisteredIcons) / sizeof(PPH_NF_ICON); i++) - { - if (PhNfRegisteredIcons[i]) - { - if (registeredIconMask & PhNfRegisteredIcons[i]->IconId) - { - PhAppendFormatStringBuilder( - &iconListBuilder, - L"+%s+%u|", - PhNfRegisteredIcons[i]->Plugin->Name.Buffer, - PhNfRegisteredIcons[i]->SubId - ); - } - } - } + PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackTrayIconsInitializing), &pointers); + } - if (iconListBuilder.String->Length != 0) - PhRemoveEndStringBuilder(&iconListBuilder, 1); + // Load tray icon settings. + PhNfLoadSettings(); - PhSetStringSetting2(L"IconMaskList", &iconListBuilder.String->sr); - PhDeleteStringBuilder(&iconListBuilder); - } - else + for (ULONG i = 0; i < PhTrayIconItemList->Count; i++) { - PhSetStringSetting(L"IconMaskList", L""); + PPH_NF_ICON icon = PhTrayIconItemList->Items[i]; + + if (!(icon->Flags & PH_NF_ICON_ENABLED)) + continue; + + PhNfpAddNotifyIcon(icon); } + + PhRegisterCallback( + &PhProcessesUpdatedEvent, + PhNfpProcessesUpdatedHandler, + NULL, + &PhNfpProcessesUpdatedRegistration + ); } VOID PhNfUninitialization( VOID ) { - ULONG i; - // Remove all icons to prevent them hanging around after we exit. - PhNfTerminating = TRUE; // prevent further icon updating - - for (i = PH_ICON_MINIMUM; i != PhNfMaximumIconId; i <<= 1) + for (ULONG i = 0; i < PhTrayIconItemList->Count; i++) { - if (PhNfIconMask & i) - PhNfpRemoveNotifyIcon(i); + PPH_NF_ICON icon = PhTrayIconItemList->Items[i]; + + if (!(icon->Flags & PH_NF_ICON_ENABLED)) + continue; + + PhNfpRemoveNotifyIcon(icon); } } @@ -189,21 +221,33 @@ VOID PhNfForwardMessage( ULONG iconIndex = HIWORD(LParam); PPH_NF_ICON registeredIcon = NULL; - if (iconIndex < sizeof(PhNfRegisteredIcons) / sizeof(PPH_NF_ICON) && PhNfRegisteredIcons[iconIndex]) + if (iconIndex == 0) + return; + + for (ULONG i = 0; i < PhTrayIconItemList->Count; i++) { - registeredIcon = PhNfRegisteredIcons[iconIndex]; + PPH_NF_ICON icon = PhTrayIconItemList->Items[i]; - if (registeredIcon->MessageCallback) + if (icon->IconId == iconIndex) { - if (registeredIcon->MessageCallback( - registeredIcon, - WParam, - LParam, - registeredIcon->Context - )) - { - return; - } + registeredIcon = icon; + break; + } + } + + if (!registeredIcon) + return; + + if (registeredIcon->MessageCallback) + { + if (registeredIcon->MessageCallback( + registeredIcon, + WParam, + LParam, + registeredIcon->Context + )) + { + return; } } @@ -309,34 +353,20 @@ VOID PhNfForwardMessage( } } -ULONG PhNfGetMaximumIconId( - VOID - ) -{ - return PhNfMaximumIconId; -} - -ULONG PhNfTestIconMask( - _In_ ULONG Id - ) -{ - return PhNfIconMask & Id; -} - VOID PhNfSetVisibleIcon( - _In_ ULONG Id, + _In_ PPH_NF_ICON Icon, _In_ BOOLEAN Visible ) { if (Visible) { - PhNfIconMask |= Id; - PhNfpAddNotifyIcon(Id); + Icon->Flags |= PH_NF_ICON_ENABLED; + PhNfpAddNotifyIcon(Icon); } else { - PhNfIconMask &= ~Id; - PhNfpRemoveNotifyIcon(Id); + Icon->Flags &= ~PH_NF_ICON_ENABLED; + PhNfpRemoveNotifyIcon(Icon); } } @@ -348,22 +378,32 @@ BOOLEAN PhNfShowBalloonTip( _In_ ULONG Flags ) { - NOTIFYICONDATA notifyIcon = { NOTIFYICONDATA_V3_SIZE }; + NOTIFYICONDATA notifyIcon = { sizeof(NOTIFYICONDATA) }; + PPH_NF_ICON registeredIcon = NULL; + ULONG iconID = Id; - if (Id == 0) + if (iconID == 0) { - // Choose the first visible icon. - Id = PhNfIconMask; - } + for (ULONG i = 0; i < PhTrayIconItemList->Count; i++) + { + PPH_NF_ICON icon = PhTrayIconItemList->Items[i]; - if (!_BitScanForward(&Id, Id)) - return FALSE; + if (!(icon->Flags & PH_NF_ICON_ENABLED)) + continue; + + iconID = icon->IconId; + break; + } + + if (iconID == 0) + return FALSE; + } notifyIcon.hWnd = PhMainWndHandle; - notifyIcon.uID = Id; + notifyIcon.uID = iconID; notifyIcon.uFlags = NIF_INFO; - wcsncpy_s(notifyIcon.szInfoTitle, sizeof(notifyIcon.szInfoTitle) / sizeof(WCHAR), Title, _TRUNCATE); - wcsncpy_s(notifyIcon.szInfo, sizeof(notifyIcon.szInfo) / sizeof(WCHAR), Text, _TRUNCATE); + wcsncpy_s(notifyIcon.szInfoTitle, ARRAYSIZE(notifyIcon.szInfoTitle), Title, _TRUNCATE); + wcsncpy_s(notifyIcon.szInfo, ARRAYSIZE(notifyIcon.szInfo), Text, _TRUNCATE); notifyIcon.uTimeout = Timeout; notifyIcon.dwInfoFlags = Flags; @@ -391,7 +431,7 @@ HICON PhNfBitmapToIcon( PPH_NF_ICON PhNfRegisterIcon( _In_ struct _PH_PLUGIN *Plugin, - _In_ ULONG SubId, + _In_ ULONG Id, _In_opt_ PVOID Context, _In_ PWSTR Text, _In_ ULONG Flags, @@ -400,83 +440,112 @@ PPH_NF_ICON PhNfRegisterIcon( ) { PPH_NF_ICON icon; - ULONG iconId; - ULONG iconIndex; - - if (PhNfMaximumIconId == PH_ICON_LIMIT) - { - // No room for any more icons. - return NULL; - } - - iconId = PhNfMaximumIconId; - - if (!_BitScanReverse(&iconIndex, iconId) || - iconIndex >= sizeof(PhNfRegisteredIcons) / sizeof(PPH_NF_ICON)) - { - // Should never happen. - return NULL; - } - - PhNfMaximumIconId <<= 1; icon = PhAllocate(sizeof(PH_NF_ICON)); icon->Plugin = Plugin; - icon->SubId = SubId; + icon->SubId = Id; icon->Context = Context; icon->Pointers = &PhNfpPointers; icon->Text = Text; icon->Flags = Flags; - icon->IconId = iconId; icon->UpdateCallback = UpdateCallback; icon->MessageCallback = MessageCallback; + icon->TextCache = PhReferenceEmptyString(); + icon->IconId = PhTrayIconItemList->Count + 1; // HACK - PhNfRegisteredIcons[iconIndex] = icon; + PhAddItemList(PhTrayIconItemList, icon); return icon; } +struct _PH_NF_ICON *PhNfPluginRegisterIcon( + _In_ struct _PH_PLUGIN * Plugin, + _In_ ULONG Id, + _In_opt_ PVOID Context, + _In_ PWSTR Text, + _In_ ULONG Flags, + _In_ struct _PH_NF_ICON_REGISTRATION_DATA *RegistrationData + ) +{ + return PhNfRegisterIcon( + Plugin, + Id, + Context, + Text, + Flags, + RegistrationData->UpdateCallback, + RegistrationData->MessageCallback + ); +} + PPH_NF_ICON PhNfGetIconById( - _In_ ULONG Id + _In_ ULONG SubId ) { - ULONG iconIndex; + for (ULONG i = 0; i < PhTrayIconItemList->Count; i++) + { + PPH_NF_ICON icon = PhTrayIconItemList->Items[i]; - if (!_BitScanReverse(&iconIndex, Id)) - return NULL; + if (icon->SubId == SubId) + return icon; + } - return PhNfRegisteredIcons[iconIndex]; + return NULL; } PPH_NF_ICON PhNfFindIcon( - _In_ PPH_STRINGREF PluginName, + _In_opt_ PPH_STRINGREF PluginName, _In_ ULONG SubId ) { - ULONG i; - - for (i = 0; i < sizeof(PhNfRegisteredIcons) / sizeof(PPH_NF_ICON); i++) + for (ULONG i = 0; i < PhTrayIconItemList->Count; i++) { - if (PhNfRegisteredIcons[i]) + PPH_NF_ICON icon = PhTrayIconItemList->Items[i]; + + if (PluginName) { - if (PhNfRegisteredIcons[i]->SubId == SubId && - PhEqualStringRef(PluginName, &PhNfRegisteredIcons[i]->Plugin->AppContext.AppName, FALSE)) + if ( + icon->SubId == SubId && + (icon->Plugin ? PhEqualStringRef(PluginName, &icon->Plugin->AppContext.AppName, TRUE) : TRUE) + ) { - return PhNfRegisteredIcons[i]; + return icon; } } + else + { + if (icon->SubId == SubId) + return icon; + } } return NULL; } +BOOLEAN PhNfIconsEnabled( + VOID + ) +{ + BOOLEAN enabled = FALSE; + + for (ULONG i = 0; i < PhTrayIconItemList->Count; i++) + { + PPH_NF_ICON icon = PhTrayIconItemList->Items[i]; + + if (icon->Flags & PH_NF_ICON_ENABLED) + { + enabled = TRUE; + break; + } + } + + return enabled; +} + VOID PhNfNotifyMiniInfoPinned( _In_ BOOLEAN Pinned ) { - ULONG i; - ULONG id; - if (PhNfMiniInfoPinned != Pinned) { PhNfMiniInfoPinned = Pinned; @@ -484,14 +553,15 @@ VOID PhNfNotifyMiniInfoPinned( // Go through every icon and set/clear the NIF_SHOWTIP flag depending on whether the mini info window is // pinned. If it's pinned then we want to show normal tooltips, because the section doesn't change // automatically when the cursor hovers over an icon. - for (i = 0; i < sizeof(PhNfRegisteredIcons) / sizeof(PPH_NF_ICON); i++) + + for (ULONG i = 0; i < PhTrayIconItemList->Count; i++) { - id = 1 << i; + PPH_NF_ICON icon = PhTrayIconItemList->Items[i]; - if (PhNfIconMask & id) - { - PhNfpModifyNotifyIcon(id, NIF_TIP, PhNfIconTextCache[i], NULL); - } + if (!(icon->Flags & PH_NF_ICON_ENABLED)) + continue; + + PhNfpModifyNotifyIcon(icon, NIF_TIP, icon->TextCache, NULL); } } } @@ -526,34 +596,26 @@ HICON PhNfpGetBlackIcon( } BOOLEAN PhNfpAddNotifyIcon( - _In_ ULONG Id + _In_ PPH_NF_ICON Icon ) { NOTIFYICONDATA notifyIcon = { sizeof(NOTIFYICONDATA) }; - PPH_NF_ICON icon; - if (PhNfTerminating) - return FALSE; - if ((icon = PhNfGetIconById(Id)) && (icon->Flags & PH_NF_ICON_UNAVAILABLE)) - return FALSE; - - // The IDs we pass to explorer are bit indicies, not the normal mask values. - - if (!_BitScanForward(&Id, Id)) + if (PhMainWndExiting) return FALSE; notifyIcon.hWnd = PhMainWndHandle; - notifyIcon.uID = Id; + notifyIcon.uID = Icon->IconId; notifyIcon.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP; notifyIcon.uCallbackMessage = WM_PH_NOTIFY_ICON_MESSAGE; wcsncpy_s( notifyIcon.szTip, sizeof(notifyIcon.szTip) / sizeof(WCHAR), - PhGetStringOrDefault(PhNfIconTextCache[Id], PhApplicationName), + PhGetStringOrDefault(Icon->TextCache, PhApplicationName), _TRUNCATE ); notifyIcon.hIcon = PhNfpGetBlackIcon(); - if (!PhNfMiniInfoEnabled || PhNfMiniInfoPinned || (icon && !(icon->Flags & PH_NF_ICON_SHOW_MINIINFO))) + if (!PhNfMiniInfoEnabled || PhNfMiniInfoPinned || (Icon->Flags & PH_NF_ICON_NOSHOW_MINIINFO)) notifyIcon.uFlags |= NIF_SHOWTIP; Shell_NotifyIcon(NIM_ADD, ¬ifyIcon); @@ -565,20 +627,13 @@ BOOLEAN PhNfpAddNotifyIcon( } BOOLEAN PhNfpRemoveNotifyIcon( - _In_ ULONG Id + _In_ PPH_NF_ICON Icon ) { NOTIFYICONDATA notifyIcon = { sizeof(NOTIFYICONDATA) }; - PPH_NF_ICON icon; - - if ((icon = PhNfGetIconById(Id)) && (icon->Flags & PH_NF_ICON_UNAVAILABLE)) - return FALSE; - - if (!_BitScanForward(&Id, Id)) - return FALSE; notifyIcon.hWnd = PhMainWndHandle; - notifyIcon.uID = Id; + notifyIcon.uID = Icon->IconId; Shell_NotifyIcon(NIM_DELETE, ¬ifyIcon); @@ -586,88 +641,90 @@ BOOLEAN PhNfpRemoveNotifyIcon( } BOOLEAN PhNfpModifyNotifyIcon( - _In_ ULONG Id, + _In_ PPH_NF_ICON Icon, _In_ ULONG Flags, _In_opt_ PPH_STRING Text, - _In_opt_ HICON Icon + _In_opt_ HICON IconHandle ) { NOTIFYICONDATA notifyIcon = { sizeof(NOTIFYICONDATA) }; - PPH_NF_ICON icon; - ULONG notifyId; - if (PhNfTerminating) - return FALSE; - if ((icon = PhNfGetIconById(Id)) && (icon->Flags & PH_NF_ICON_UNAVAILABLE)) + if (PhMainWndExiting) return FALSE; - - if (!_BitScanForward(¬ifyId, Id)) + if (Icon->Flags & PH_NF_ICON_UNAVAILABLE) return FALSE; notifyIcon.hWnd = PhMainWndHandle; - notifyIcon.uID = notifyId; + notifyIcon.uID = Icon->IconId; notifyIcon.uFlags = Flags; + notifyIcon.hIcon = IconHandle; + + if (!PhNfMiniInfoEnabled || PhNfMiniInfoPinned || (Icon->Flags & PH_NF_ICON_NOSHOW_MINIINFO)) + notifyIcon.uFlags |= NIF_SHOWTIP; if (Flags & NIF_TIP) { - PhSwapReference(&PhNfIconTextCache[notifyId], Text); + PhSwapReference(&Icon->TextCache, Text); wcsncpy_s( notifyIcon.szTip, - sizeof(notifyIcon.szTip) / sizeof(WCHAR), + ARRAYSIZE(notifyIcon.szTip), PhGetStringOrDefault(Text, PhApplicationName), _TRUNCATE ); } - notifyIcon.hIcon = Icon; - - if (!PhNfMiniInfoEnabled || PhNfMiniInfoPinned || (icon && !(icon->Flags & PH_NF_ICON_SHOW_MINIINFO))) - notifyIcon.uFlags |= NIF_SHOWTIP; - if (!Shell_NotifyIcon(NIM_MODIFY, ¬ifyIcon)) { // Explorer probably died and we lost our icon. Try to add the icon, and try again. - PhNfpAddNotifyIcon(Id); + PhNfpAddNotifyIcon(Icon); Shell_NotifyIcon(NIM_MODIFY, ¬ifyIcon); } return TRUE; } +//BOOLEAN PhNfpGetNotifyIconRect( +// _In_ ULONG Id, +// _In_opt_ PPH_RECTANGLE IconRectangle +// ) +//{ +// NOTIFYICONIDENTIFIER notifyIconId = { sizeof(NOTIFYICONIDENTIFIER) }; +// PPH_NF_ICON icon; +// RECT notifyRect; +// +// if (PhMainWndExiting) +// return FALSE; +// if ((icon = PhNfGetIconById(Id)) && (icon->Flags & PH_NF_ICON_UNAVAILABLE)) +// return FALSE; +// +// notifyIconId.hWnd = PhMainWndHandle; +// notifyIconId.uID = Id; +// +// if (SUCCEEDED(Shell_NotifyIconGetRect(¬ifyIconId, ¬ifyRect))) +// { +// *IconRectangle = PhRectToRectangle(notifyRect); +// return TRUE; +// } +// +// return FALSE; +//} + VOID PhNfpProcessesUpdatedHandler( _In_opt_ PVOID Parameter, _In_opt_ PVOID Context ) { - ULONG registeredIconMask; - // We do icon updating on the provider thread so we don't block the main GUI when // explorer is not responding. - if (PhNfIconMask & PH_ICON_CPU_HISTORY) - PhNfpUpdateIconCpuHistory(); - if (PhNfIconMask & PH_ICON_IO_HISTORY) - PhNfpUpdateIconIoHistory(); - if (PhNfIconMask & PH_ICON_COMMIT_HISTORY) - PhNfpUpdateIconCommitHistory(); - if (PhNfIconMask & PH_ICON_PHYSICAL_HISTORY) - PhNfpUpdateIconPhysicalHistory(); - if (PhNfIconMask & PH_ICON_CPU_USAGE) - PhNfpUpdateIconCpuUsage(); - - registeredIconMask = PhNfIconMask & ~PH_ICON_DEFAULT_ALL; - - if (registeredIconMask != 0) + for (ULONG i = 0; i < PhTrayIconItemList->Count; i++) { - ULONG i; + PPH_NF_ICON icon = PhTrayIconItemList->Items[i]; - for (i = 0; i < sizeof(PhNfRegisteredIcons) / sizeof(PPH_NF_ICON); i++) - { - if (PhNfRegisteredIcons[i] && (registeredIconMask & PhNfRegisteredIcons[i]->IconId)) - { - PhNfpUpdateRegisteredIcon(PhNfRegisteredIcons[i]); - } - } + if (!(icon->Flags & PH_NF_ICON_ENABLED)) + continue; + + PhNfpUpdateRegisteredIcon(icon); } } @@ -711,7 +768,7 @@ VOID PhNfpUpdateRegisteredIcon( flags |= NIF_TIP; if (flags != 0) - PhNfpModifyNotifyIcon(Icon->IconId, flags, newText, newIcon); + PhNfpModifyNotifyIcon(Icon, flags, newText, newIcon); if (newIcon && (updateFlags & PH_NF_UPDATE_IS_BITMAP)) DestroyIcon(newIcon); @@ -778,8 +835,12 @@ VOID PhNfpBeginBitmap2( *OldBitmap = SelectObject(Context->Hdc, Context->Bitmap); } -VOID PhNfpUpdateIconCpuHistory( - VOID +VOID PhNfpCpuHistoryIconUpdateCallback( + _In_ struct _PH_NF_ICON *Icon, + _Out_ PVOID *NewIconOrBitmap, + _Out_ PULONG Flags, + _Out_ PPH_STRING *NewText, + _In_opt_ PVOID Context ) { static PH_GRAPH_DRAW_INFO drawInfo = @@ -789,7 +850,6 @@ VOID PhNfpUpdateIconCpuHistory( PH_GRAPH_USE_LINE_2, 2, RGB(0x00, 0x00, 0x00), - 16, NULL, NULL, @@ -806,15 +866,13 @@ VOID PhNfpUpdateIconCpuHistory( PVOID bits; HDC hdc; HBITMAP oldBitmap; - HICON icon; HANDLE maxCpuProcessId; PPH_PROCESS_ITEM maxCpuProcessItem; PH_FORMAT format[8]; - PPH_STRING text; // Icon - PhNfpBeginBitmap(&drawInfo.Width, &drawInfo.Height, &bitmap, &bits, &hdc, &oldBitmap); + Icon->Pointers->BeginBitmap(&drawInfo.Width, &drawInfo.Height, &bitmap, &bits, &hdc, &oldBitmap); maxDataCount = drawInfo.Width / 2 + 1; lineData1 = _alloca(maxDataCount * sizeof(FLOAT)); lineData2 = _alloca(maxDataCount * sizeof(FLOAT)); @@ -835,7 +893,8 @@ VOID PhNfpUpdateIconCpuHistory( PhDrawGraphDirect(hdc, bits, &drawInfo); SelectObject(hdc, oldBitmap); - icon = PhNfBitmapToIcon(bitmap); + *NewIconOrBitmap = bitmap; + *Flags = PH_NF_UPDATE_IS_BITMAP; // Text @@ -862,17 +921,16 @@ VOID PhNfpUpdateIconCpuHistory( PhInitFormatC(&format[7], '%'); } - text = PhFormat(format, maxCpuProcessItem ? 8 : 3, 128); + *NewText = PhFormat(format, maxCpuProcessItem ? 8 : 3, 128); if (maxCpuProcessItem) PhDereferenceObject(maxCpuProcessItem); - - PhNfpModifyNotifyIcon(PH_ICON_CPU_HISTORY, NIF_TIP | NIF_ICON, text, icon); - - DestroyIcon(icon); - PhDereferenceObject(text); } -VOID PhNfpUpdateIconIoHistory( - VOID +VOID PhNfpIoHistoryIconUpdateCallback( + _In_ struct _PH_NF_ICON *Icon, + _Out_ PVOID *NewIconOrBitmap, + _Out_ PULONG Flags, + _Out_ PPH_STRING *NewText, + _In_opt_ PVOID Context ) { static PH_GRAPH_DRAW_INFO drawInfo = @@ -882,7 +940,6 @@ VOID PhNfpUpdateIconIoHistory( PH_GRAPH_USE_LINE_2, 2, RGB(0x00, 0x00, 0x00), - 16, NULL, NULL, @@ -901,15 +958,13 @@ VOID PhNfpUpdateIconIoHistory( PVOID bits; HDC hdc; HBITMAP oldBitmap; - HICON icon; HANDLE maxIoProcessId; PPH_PROCESS_ITEM maxIoProcessItem; PH_FORMAT format[8]; - PPH_STRING text; // Icon - PhNfpBeginBitmap(&drawInfo.Width, &drawInfo.Height, &bitmap, &bits, &hdc, &oldBitmap); + Icon->Pointers->BeginBitmap(&drawInfo.Width, &drawInfo.Height, &bitmap, &bits, &hdc, &oldBitmap); maxDataCount = drawInfo.Width / 2 + 1; lineData1 = _alloca(maxDataCount * sizeof(FLOAT)); lineData2 = _alloca(maxDataCount * sizeof(FLOAT)); @@ -944,7 +999,8 @@ VOID PhNfpUpdateIconIoHistory( PhDrawGraphDirect(hdc, bits, &drawInfo); SelectObject(hdc, oldBitmap); - icon = PhNfBitmapToIcon(bitmap); + *NewIconOrBitmap = bitmap; + *Flags = PH_NF_UPDATE_IS_BITMAP; // Text @@ -971,17 +1027,16 @@ VOID PhNfpUpdateIconIoHistory( PhInitFormatSR(&format[7], maxIoProcessItem->ProcessName->sr); } - text = PhFormat(format, maxIoProcessItem ? 8 : 6, 128); + *NewText = PhFormat(format, maxIoProcessItem ? 8 : 6, 128); if (maxIoProcessItem) PhDereferenceObject(maxIoProcessItem); - - PhNfpModifyNotifyIcon(PH_ICON_IO_HISTORY, NIF_TIP | NIF_ICON, text, icon); - - DestroyIcon(icon); - PhDereferenceObject(text); } -VOID PhNfpUpdateIconCommitHistory( - VOID +VOID PhNfpCommitHistoryIconUpdateCallback( + _In_ struct _PH_NF_ICON *Icon, + _Out_ PVOID *NewIconOrBitmap, + _Out_ PULONG Flags, + _Out_ PPH_STRING *NewText, + _In_opt_ PVOID Context ) { static PH_GRAPH_DRAW_INFO drawInfo = @@ -991,7 +1046,6 @@ VOID PhNfpUpdateIconCommitHistory( 0, 2, RGB(0x00, 0x00, 0x00), - 16, NULL, NULL, @@ -1008,14 +1062,12 @@ VOID PhNfpUpdateIconCommitHistory( PVOID bits; HDC hdc; HBITMAP oldBitmap; - HICON icon; DOUBLE commitFraction; PH_FORMAT format[5]; - PPH_STRING text; // Icon - PhNfpBeginBitmap(&drawInfo.Width, &drawInfo.Height, &bitmap, &bits, &hdc, &oldBitmap); + Icon->Pointers->BeginBitmap(&drawInfo.Width, &drawInfo.Height, &bitmap, &bits, &hdc, &oldBitmap); maxDataCount = drawInfo.Width / 2 + 1; lineData1 = _alloca(maxDataCount * sizeof(FLOAT)); @@ -1035,7 +1087,8 @@ VOID PhNfpUpdateIconCommitHistory( PhDrawGraphDirect(hdc, bits, &drawInfo); SelectObject(hdc, oldBitmap); - icon = PhNfBitmapToIcon(bitmap); + *NewIconOrBitmap = bitmap; + *Flags = PH_NF_UPDATE_IS_BITMAP; // Text @@ -1047,16 +1100,15 @@ VOID PhNfpUpdateIconCommitHistory( PhInitFormatF(&format[3], commitFraction * 100, 2); PhInitFormatS(&format[4], L"%)"); - text = PhFormat(format, 5, 96); - - PhNfpModifyNotifyIcon(PH_ICON_COMMIT_HISTORY, NIF_TIP | NIF_ICON, text, icon); - - DestroyIcon(icon); - PhDereferenceObject(text); + *NewText = PhFormat(format, 5, 96); } -VOID PhNfpUpdateIconPhysicalHistory( - VOID +VOID PhNfpPhysicalHistoryIconUpdateCallback( + _In_ struct _PH_NF_ICON *Icon, + _Out_ PVOID *NewIconOrBitmap, + _Out_ PULONG Flags, + _Out_ PPH_STRING *NewText, + _In_opt_ PVOID Context ) { static PH_GRAPH_DRAW_INFO drawInfo = @@ -1066,7 +1118,6 @@ VOID PhNfpUpdateIconPhysicalHistory( 0, 2, RGB(0x00, 0x00, 0x00), - 16, NULL, NULL, @@ -1083,19 +1134,17 @@ VOID PhNfpUpdateIconPhysicalHistory( PVOID bits; HDC hdc; HBITMAP oldBitmap; - HICON icon; ULONG physicalUsage; FLOAT physicalFraction; PH_FORMAT format[5]; - PPH_STRING text; // Icon - PhNfpBeginBitmap(&drawInfo.Width, &drawInfo.Height, &bitmap, &bits, &hdc, &oldBitmap); + Icon->Pointers->BeginBitmap(&drawInfo.Width, &drawInfo.Height, &bitmap, &bits, &hdc, &oldBitmap); maxDataCount = drawInfo.Width / 2 + 1; lineData1 = _alloca(maxDataCount * sizeof(FLOAT)); - lineDataCount = min(maxDataCount, PhCommitHistory.Count); + lineDataCount = min(maxDataCount, PhPhysicalHistory.Count); for (i = 0; i < lineDataCount; i++) lineData1[i] = (FLOAT)PhGetItemCircularBuffer_ULONG(&PhPhysicalHistory, i); @@ -1111,7 +1160,8 @@ VOID PhNfpUpdateIconPhysicalHistory( PhDrawGraphDirect(hdc, bits, &drawInfo); SelectObject(hdc, oldBitmap); - icon = PhNfBitmapToIcon(bitmap); + *NewIconOrBitmap = bitmap; + *Flags = PH_NF_UPDATE_IS_BITMAP; // Text @@ -1124,16 +1174,15 @@ VOID PhNfpUpdateIconPhysicalHistory( PhInitFormatF(&format[3], physicalFraction * 100, 2); PhInitFormatS(&format[4], L"%)"); - text = PhFormat(format, 5, 96); - - PhNfpModifyNotifyIcon(PH_ICON_PHYSICAL_HISTORY, NIF_TIP | NIF_ICON, text, icon); - - DestroyIcon(icon); - PhDereferenceObject(text); + *NewText = PhFormat(format, 5, 96); } -VOID PhNfpUpdateIconCpuUsage( - VOID +VOID PhNfpCpuUsageIconUpdateCallback( + _In_ struct _PH_NF_ICON *Icon, + _Out_ PVOID *NewIconOrBitmap, + _Out_ PULONG Flags, + _Out_ PPH_STRING *NewText, + _In_opt_ PVOID Context ) { ULONG width; @@ -1141,15 +1190,13 @@ VOID PhNfpUpdateIconCpuUsage( HBITMAP bitmap; HDC hdc; HBITMAP oldBitmap; - HICON icon; HANDLE maxCpuProcessId; PPH_PROCESS_ITEM maxCpuProcessItem; PPH_STRING maxCpuText = NULL; - PPH_STRING text; // Icon - PhNfpBeginBitmap(&width, &height, &bitmap, NULL, &hdc, &oldBitmap); + Icon->Pointers->BeginBitmap(&width, &height, &bitmap, NULL, &hdc, &oldBitmap); // This stuff is copied from CpuUsageIcon.cs (PH 1.x). { @@ -1226,7 +1273,8 @@ VOID PhNfpUpdateIconCpuUsage( } SelectObject(hdc, oldBitmap); - icon = PhNfBitmapToIcon(bitmap); + *NewIconOrBitmap = bitmap; + *Flags = PH_NF_UPDATE_IS_BITMAP; // Text @@ -1248,13 +1296,289 @@ VOID PhNfpUpdateIconCpuUsage( } } - text = PhFormatString(L"CPU usage: %.2f%%%s", (PhCpuKernelUsage + PhCpuUserUsage) * 100, PhGetStringOrEmpty(maxCpuText)); + *NewText = PhFormatString(L"CPU usage: %.2f%%%s", (PhCpuKernelUsage + PhCpuUserUsage) * 100, PhGetStringOrEmpty(maxCpuText)); if (maxCpuText) PhDereferenceObject(maxCpuText); +} - PhNfpModifyNotifyIcon(PH_ICON_CPU_USAGE, NIF_TIP | NIF_ICON, text, icon); +// Text icons - DestroyIcon(icon); +VOID PhNfpCpuUsageTextIconUpdateCallback( + _In_ struct _PH_NF_ICON *Icon, + _Out_ PVOID *NewIconOrBitmap, + _Out_ PULONG Flags, + _Out_ PPH_STRING *NewText, + _In_opt_ PVOID Context + ) +{ + static PH_GRAPH_DRAW_INFO drawInfo = + { + 16, + 16, + 0, + 2, + RGB(0x00, 0x00, 0x00), + 16, + NULL, + NULL, + 0, + 0, + 0, + 0 + }; + HBITMAP bitmap; + PVOID bits; + HDC hdc; + HBITMAP oldBitmap; + PH_FORMAT format[5]; + HANDLE maxCpuProcessId; + PPH_PROCESS_ITEM maxCpuProcessItem; + PPH_STRING maxCpuText = NULL; + PPH_STRING text; + + // Icon + + Icon->Pointers->BeginBitmap(&drawInfo.Width, &drawInfo.Height, &bitmap, &bits, &hdc, &oldBitmap); + + PhInitFormatF(&format[0], (PhCpuKernelUsage + PhCpuUserUsage) * 100, 0); + text = PhFormat(format, 1, 10); + + drawInfo.TextColor = PhCsColorCpuKernel; + if (bits) + PhDrawTrayIconText(hdc, bits, &drawInfo, &text->sr); + PhDereferenceObject(text); + + SelectObject(hdc, oldBitmap); + *NewIconOrBitmap = bitmap; + *Flags = PH_NF_UPDATE_IS_BITMAP; + + // Text + + if (PhMaxCpuHistory.Count != 0) + maxCpuProcessId = UlongToHandle(PhGetItemCircularBuffer_ULONG(&PhMaxCpuHistory, 0)); + else + maxCpuProcessId = NULL; + + if (maxCpuProcessId) + { + if (maxCpuProcessItem = PhReferenceProcessItem(maxCpuProcessId)) + { + maxCpuText = PhFormatString( + L"\n%s: %.2f%%", + maxCpuProcessItem->ProcessName->Buffer, + maxCpuProcessItem->CpuUsage * 100 + ); + PhDereferenceObject(maxCpuProcessItem); + } + } + + *NewText = PhFormatString(L"CPU usage: %.2f%%%s", (PhCpuKernelUsage + PhCpuUserUsage) * 100, PhGetStringOrEmpty(maxCpuText)); + if (maxCpuText) PhDereferenceObject(maxCpuText); +} + +VOID PhNfpIoUsageTextIconUpdateCallback( + _In_ struct _PH_NF_ICON *Icon, + _Out_ PVOID *NewIconOrBitmap, + _Out_ PULONG Flags, + _Out_ PPH_STRING *NewText, + _In_opt_ PVOID Context + ) +{ + static PH_GRAPH_DRAW_INFO drawInfo = + { + 16, + 16, + 0, + 0, + RGB(0x00, 0x00, 0x00), + 0, + NULL, + NULL, + 0, + 0, + 0, + 0 + }; + HBITMAP bitmap; + PVOID bits; + HDC hdc; + HBITMAP oldBitmap; + HANDLE maxIoProcessId; + PPH_PROCESS_ITEM maxIoProcessItem; + PH_FORMAT format[8]; + PPH_STRING text; + static ULONG64 maxValue = 100000 * 1024; // minimum scaling of 100 MB. + + // TODO: Reset maxValue every X amount of time. + + // Icon + + Icon->Pointers->BeginBitmap(&drawInfo.Width, &drawInfo.Height, &bitmap, &bits, &hdc, &oldBitmap); + + if (maxValue < (PhIoReadDelta.Delta + PhIoWriteDelta.Delta + PhIoOtherDelta.Delta)) + maxValue = (PhIoReadDelta.Delta + PhIoWriteDelta.Delta + PhIoOtherDelta.Delta); + + PhInitFormatF(&format[0], (FLOAT)(PhIoReadDelta.Delta + PhIoWriteDelta.Delta + PhIoOtherDelta.Delta) / maxValue * 100, 0); + text = PhFormat(format, 1, 10); + + drawInfo.TextColor = PhCsColorIoReadOther; + if (bits) + PhDrawTrayIconText(hdc, bits, &drawInfo, &text->sr); + PhDereferenceObject(text); + + SelectObject(hdc, oldBitmap); + *NewIconOrBitmap = bitmap; + *Flags = PH_NF_UPDATE_IS_BITMAP; + + // Text + + if (PhMaxIoHistory.Count != 0) + maxIoProcessId = UlongToHandle(PhGetItemCircularBuffer_ULONG(&PhMaxIoHistory, 0)); + else + maxIoProcessId = NULL; + + if (maxIoProcessId) + maxIoProcessItem = PhReferenceProcessItem(maxIoProcessId); + else + maxIoProcessItem = NULL; + + PhInitFormatS(&format[0], L"I/O\nR: "); + PhInitFormatSize(&format[1], PhIoReadDelta.Delta); + PhInitFormatS(&format[2], L"\nW: "); + PhInitFormatSize(&format[3], PhIoWriteDelta.Delta); + PhInitFormatS(&format[4], L"\nO: "); + PhInitFormatSize(&format[5], PhIoOtherDelta.Delta); + + if (maxIoProcessItem) + { + PhInitFormatC(&format[6], '\n'); + PhInitFormatSR(&format[7], maxIoProcessItem->ProcessName->sr); + } + + *NewText = PhFormat(format, maxIoProcessItem ? 8 : 6, 128); + if (maxIoProcessItem) PhDereferenceObject(maxIoProcessItem); +} + +VOID PhNfpCommitTextIconUpdateCallback( + _In_ struct _PH_NF_ICON *Icon, + _Out_ PVOID *NewIconOrBitmap, + _Out_ PULONG Flags, + _Out_ PPH_STRING *NewText, + _In_opt_ PVOID Context + ) +{ + static PH_GRAPH_DRAW_INFO drawInfo = + { + 16, + 16, + 0, + 0, + RGB(0x00, 0x00, 0x00), + 0, + NULL, + NULL, + 0, + 0, + 0, + 0 + }; + HBITMAP bitmap; + PVOID bits; + HDC hdc; + HBITMAP oldBitmap; + DOUBLE commitFraction; + PH_FORMAT format[5]; + PPH_STRING text; + + // Icon + + Icon->Pointers->BeginBitmap(&drawInfo.Width, &drawInfo.Height, &bitmap, &bits, &hdc, &oldBitmap); + + PhInitFormatF(&format[0], (FLOAT)PhPerfInformation.CommittedPages / PhPerfInformation.CommitLimit * 100, 0); + text = PhFormat(format, 1, 10); + + drawInfo.TextColor = PhCsColorPrivate; + PhDrawTrayIconText(hdc, bits, &drawInfo, &text->sr); + PhDereferenceObject(text); + + SelectObject(hdc, oldBitmap); + *NewIconOrBitmap = bitmap; + *Flags = PH_NF_UPDATE_IS_BITMAP; + + // Text + + commitFraction = (DOUBLE)PhPerfInformation.CommittedPages / PhPerfInformation.CommitLimit; + + PhInitFormatS(&format[0], L"Commit: "); + PhInitFormatSize(&format[1], UInt32x32To64(PhPerfInformation.CommittedPages, PAGE_SIZE)); + PhInitFormatS(&format[2], L" ("); + PhInitFormatF(&format[3], commitFraction * 100, 2); + PhInitFormatS(&format[4], L"%)"); + + *NewText = PhFormat(format, 5, 96); +} + +VOID PhNfpPhysicalUsageTextIconUpdateCallback( + _In_ struct _PH_NF_ICON *Icon, + _Out_ PVOID *NewIconOrBitmap, + _Out_ PULONG Flags, + _Out_ PPH_STRING *NewText, + _In_opt_ PVOID Context + ) +{ + static PH_GRAPH_DRAW_INFO drawInfo = + { + 16, + 16, + 0, + 0, + RGB(0x00, 0x00, 0x00), + 0, + NULL, + NULL, + 0, + 0, + 0, + 0 + }; + HBITMAP bitmap; + PVOID bits; + HDC hdc; + HBITMAP oldBitmap; + ULONG physicalUsage; + FLOAT physicalFraction; + PH_FORMAT format[5]; + PPH_STRING text; + + // Icon + + Icon->Pointers->BeginBitmap(&drawInfo.Width, &drawInfo.Height, &bitmap, &bits, &hdc, &oldBitmap); + + physicalUsage = PhSystemBasicInformation.NumberOfPhysicalPages - PhPerfInformation.AvailablePages; + physicalFraction = (FLOAT)physicalUsage / PhSystemBasicInformation.NumberOfPhysicalPages; + + PhInitFormatF(&format[0], (FLOAT)physicalFraction * 100, 0); + text = PhFormat(format, 1, 10); + + drawInfo.TextColor = PhCsColorPhysical; + PhDrawTrayIconText(hdc, bits, &drawInfo, &text->sr); PhDereferenceObject(text); + + SelectObject(hdc, oldBitmap); + *NewIconOrBitmap = bitmap; + *Flags = PH_NF_UPDATE_IS_BITMAP; + + // Text + + physicalUsage = PhSystemBasicInformation.NumberOfPhysicalPages - PhPerfInformation.AvailablePages; + physicalFraction = (FLOAT)physicalUsage / PhSystemBasicInformation.NumberOfPhysicalPages; + + PhInitFormatS(&format[0], L"Physical memory: "); + PhInitFormatSize(&format[1], UInt32x32To64(physicalUsage, PAGE_SIZE)); + PhInitFormatS(&format[2], L" ("); + PhInitFormatF(&format[3], physicalFraction * 100, 2); + PhInitFormatS(&format[4], L"%)"); + + *NewText = PhFormat(format, 5, 96); } BOOLEAN PhNfpGetShowMiniInfoSectionData( @@ -1265,11 +1589,11 @@ BOOLEAN PhNfpGetShowMiniInfoSectionData( { BOOLEAN showMiniInfo = FALSE; - if (RegisteredIcon) + if (RegisteredIcon && RegisteredIcon->MessageCallback) { Data->SectionName = NULL; - if (RegisteredIcon->Flags & PH_NF_ICON_SHOW_MINIINFO) + if (!(RegisteredIcon->Flags & PH_NF_ICON_NOSHOW_MINIINFO)) { if (RegisteredIcon->MessageCallback) { @@ -1286,19 +1610,23 @@ BOOLEAN PhNfpGetShowMiniInfoSectionData( } else { - switch (1 << IconIndex) + switch (IconIndex) { - case PH_ICON_CPU_HISTORY: - case PH_ICON_CPU_USAGE: + case PH_TRAY_ICON_ID_CPU_HISTORY: + case PH_TRAY_ICON_ID_CPU_USAGE: + case PH_TRAY_ICON_ID_CPU_TEXT: Data->SectionName = L"CPU"; break; - case PH_ICON_IO_HISTORY: + case PH_TRAY_ICON_ID_IO_HISTORY: + case PH_TRAY_ICON_ID_IO_TEXT: Data->SectionName = L"I/O"; break; - case PH_ICON_COMMIT_HISTORY: + case PH_TRAY_ICON_ID_COMMIT_HISTORY: + case PH_TRAY_ICON_ID_COMMIT_TEXT: Data->SectionName = L"Commit charge"; break; - case PH_ICON_PHYSICAL_HISTORY: + case PH_TRAY_ICON_ID_PHYSICAL_HISTORY: + case PH_TRAY_ICON_ID_PHYSICAL_TEXT: Data->SectionName = L"Physical memory"; break; } diff --git a/ProcessHacker/plugin.c b/ProcessHacker/plugin.c index a62dd703b31e..5dde37daed95 100644 --- a/ProcessHacker/plugin.c +++ b/ProcessHacker/plugin.c @@ -3,6 +3,7 @@ * plugin support * * Copyright (C) 2010-2015 wj32 + * Copyright (C) 2017-2018 dmex * * This file is part of Process Hacker. * @@ -913,39 +914,6 @@ PVOID PhPluginGetObjectExtension( ); } -/** - * Creates a notification icon. - * - * \param Plugin A plugin instance structure. - * \param SubId An identifier for the column. This should be unique within the - * plugin. - * \param Context A user-defined value. - * \param Text A string describing the notification icon. - * \param Flags A combination of flags. - * \li \c PH_NF_ICON_UNAVAILABLE The notification icon is currently unavailable. - * \param RegistrationData A \ref PH_NF_ICON_REGISTRATION_DATA structure that - * contains registration information. - */ -struct _PH_NF_ICON *PhPluginRegisterIcon( - _In_ PPH_PLUGIN Plugin, - _In_ ULONG SubId, - _In_opt_ PVOID Context, - _In_ PWSTR Text, - _In_ ULONG Flags, - _In_ struct _PH_NF_ICON_REGISTRATION_DATA *RegistrationData - ) -{ - return PhNfRegisterIcon( - Plugin, - SubId, - Context, - Text, - Flags, - RegistrationData->UpdateCallback, - RegistrationData->MessageCallback - ); -} - /** * Allows a plugin to receive all treenew messages, not just column-related ones. * diff --git a/ProcessHacker/procprv.c b/ProcessHacker/procprv.c index d7dd2fa7d73e..a7973d3403d1 100644 --- a/ProcessHacker/procprv.c +++ b/ProcessHacker/procprv.c @@ -3,7 +3,7 @@ * process provider * * Copyright (C) 2009-2016 wj32 - * Copyright (C) 2017 dmex + * Copyright (C) 2017-2018 dmex * * This file is part of Process Hacker. * diff --git a/ProcessHacker/resource.h b/ProcessHacker/resource.h index 7b5748ed6395..1aac68d75d05 100644 --- a/ProcessHacker/resource.h +++ b/ProcessHacker/resource.h @@ -129,6 +129,7 @@ #define IDD_PLUGINSDISABLED 241 #define IDD_PROCWMIPROVIDERS 242 #define IDD_COLUMNSETS 243 +#define ID_VIEW_TRAYICONS 244 #define IDC_TERMINATE 1003 #define IDC_FILEICON 1005 #define IDC_FILE 1006 @@ -738,7 +739,7 @@ // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 244 +#define _APS_NEXT_RESOURCE_VALUE 245 #define _APS_NEXT_COMMAND_VALUE 40297 #define _APS_NEXT_CONTROL_VALUE 1404 #define _APS_NEXT_SYMED_VALUE 170 diff --git a/ProcessHacker/settings.c b/ProcessHacker/settings.c index 2021120adece..3ab7aa1b0f65 100644 --- a/ProcessHacker/settings.c +++ b/ProcessHacker/settings.c @@ -3,7 +3,7 @@ * program settings cache * * Copyright (C) 2010-2016 wj32 - * Copyright (C) 2017 dmex + * Copyright (C) 2017-2018 dmex * * This file is part of Process Hacker. * @@ -76,8 +76,7 @@ VOID PhAddDefaultSettings( PhpAddIntegerSetting(L"HideSignedProcesses", L"0"); PhpAddIntegerSetting(L"HideUnnamedHandles", L"1"); PhpAddIntegerSetting(L"HighlightingDuration", L"3e8"); // 1000ms - PhpAddIntegerSetting(L"IconMask", L"1"); // PH_ICON_CPU_HISTORY - PhpAddStringSetting(L"IconMaskList", L""); + PhpAddStringSetting(L"IconSettings", L"1|1"); PhpAddIntegerSetting(L"IconNotifyMask", L"c"); // PH_NOTIFY_SERVICE_CREATE | PH_NOTIFY_SERVICE_DELETE PhpAddIntegerSetting(L"IconProcesses", L"f"); // 15 PhpAddIntegerSetting(L"IconSingleClick", L"0"); diff --git a/phlib/graph.c b/phlib/graph.c index 6bcc69ab67aa..86e6a4b767cc 100644 --- a/phlib/graph.c +++ b/phlib/graph.c @@ -3,6 +3,7 @@ * graph control * * Copyright (C) 2010-2016 wj32 + * Copyright (C) 2017-2018 dmex * * This file is part of Process Hacker. * @@ -632,6 +633,103 @@ VOID PhSetGraphText( DrawInfo->TextBoxRect = PhRectangleToRect(boxRectangle); } + +static HFONT PhpTrayIconFont( + VOID + ) +{ + static HFONT iconTextFont = NULL; + + if (!iconTextFont) + { + iconTextFont = CreateFont( + PhMultiplyDivideSigned(-11, PhGlobalDpi, 96), + 0, + 0, + 0, + FW_NORMAL, + FALSE, + FALSE, + FALSE, + ANSI_CHARSET, + OUT_DEFAULT_PRECIS, + CLIP_DEFAULT_PRECIS, + ANTIALIASED_QUALITY, + DEFAULT_PITCH, + L"Tahoma" + ); + } + + return iconTextFont; +} + +VOID PhDrawTrayIconText( + _In_ HDC hdc, + _In_ PVOID Bits, + _Inout_ PPH_GRAPH_DRAW_INFO DrawInfo, + _In_ PPH_STRINGREF Text + ) +{ + PULONG bits = Bits; + LONG width = DrawInfo->Width; + LONG height = DrawInfo->Height; + LONG numberOfPixels = width * height; + ULONG flags = DrawInfo->Flags; + HFONT oldFont = NULL; + SIZE textSize; + PH_RECTANGLE boxRectangle; + PH_RECTANGLE textRectangle; + + if (DrawInfo->BackColor == 0) + { + memset(bits, 0, numberOfPixels * 4); + } + else + { + PhFillMemoryUlong(bits, COLORREF_TO_BITS(DrawInfo->BackColor), numberOfPixels); + } + + if (!DrawInfo->TextFont) // HACK: default font for plugins. + DrawInfo->TextFont = PhpTrayIconFont(); + + if (DrawInfo->TextFont) + oldFont = SelectObject(hdc, DrawInfo->TextFont); + + DrawInfo->Text = *Text; + GetTextExtentPoint32(hdc, Text->Buffer, (ULONG)Text->Length / 2, &textSize); + + // Calculate the box rectangle. + + boxRectangle.Width = textSize.cx; + boxRectangle.Height = textSize.cy; + boxRectangle.Left = (DrawInfo->Width - boxRectangle.Width) / 2; + boxRectangle.Top = (DrawInfo->Height - boxRectangle.Height) / 2; + + // Calculate the text rectangle. + + textRectangle.Left = boxRectangle.Left; + textRectangle.Top = boxRectangle.Top; + textRectangle.Width = textSize.cx; + textRectangle.Height = textSize.cy; + + // Save the rectangles. + DrawInfo->TextRect = PhRectangleToRect(textRectangle); + DrawInfo->TextBoxRect = PhRectangleToRect(boxRectangle); + + // Fill in the text box. + //SetDCBrushColor(hdc, DrawInfo->TextBoxColor); + //FillRect(hdc, &DrawInfo->TextBoxRect, GetStockObject(DC_BRUSH)); + + // Draw the text. + SetTextColor(hdc, DrawInfo->TextColor); + SetBkMode(hdc, TRANSPARENT); + + DrawText(hdc, DrawInfo->Text.Buffer, (ULONG)DrawInfo->Text.Length / 2, &DrawInfo->TextRect, DT_NOCLIP | DT_SINGLELINE); + + if (oldFont) + SelectObject(hdc, oldFont); +} + VOID PhpCreateGraphContext( _Out_ PPHP_GRAPH_CONTEXT *Context ) diff --git a/phlib/include/graph.h b/phlib/include/graph.h index bc15a12d6039..2b10225c5954 100644 --- a/phlib/include/graph.h +++ b/phlib/include/graph.h @@ -92,6 +92,15 @@ VOID PhSetGraphText( _In_ ULONG Align ); +PHLIBAPI +VOID PhDrawTrayIconText( + _In_ HDC hdc, + _In_ PVOID Bits, + _Inout_ PPH_GRAPH_DRAW_INFO DrawInfo, + _In_ PPH_STRINGREF Text + ); + + // Configuration typedef struct _PH_GRAPH_OPTIONS diff --git a/plugins/ExtendedTools/exttools.h b/plugins/ExtendedTools/exttools.h index 410615b3d068..c3ec61004af1 100644 --- a/plugins/ExtendedTools/exttools.h +++ b/plugins/ExtendedTools/exttools.h @@ -505,7 +505,7 @@ VOID EtGpuMiniInformationInitializing( // iconext VOID EtRegisterNotifyIcons( - VOID + _In_ PPH_TRAY_ICON_POINTERS Pointers ); // modsrv diff --git a/plugins/ExtendedTools/iconext.c b/plugins/ExtendedTools/iconext.c index b073696f3ef4..3bdec4ac9749 100644 --- a/plugins/ExtendedTools/iconext.c +++ b/plugins/ExtendedTools/iconext.c @@ -25,6 +25,9 @@ #define GPU_ICON_ID 1 #define DISK_ICON_ID 2 #define NETWORK_ICON_ID 3 +#define GPU_ICON_TEXT_ID 4 +#define DISK_ICON_TEXT_ID 5 +#define NETWORK_ICON_TEXT_ID 6 VOID EtpGpuIconUpdateCallback( _In_ struct _PH_NF_ICON *Icon, @@ -71,8 +74,32 @@ BOOLEAN EtpNetworkIconMessageCallback( _In_opt_ PVOID Context ); +VOID EtpGpuTextIconUpdateCallback( + _In_ struct _PH_NF_ICON *Icon, + _Out_ PVOID *NewIconOrBitmap, + _Out_ PULONG Flags, + _Out_ PPH_STRING *NewText, + _In_opt_ PVOID Context + ); + +VOID EtpDiskTextIconUpdateCallback( + _In_ struct _PH_NF_ICON *Icon, + _Out_ PVOID *NewIconOrBitmap, + _Out_ PULONG Flags, + _Out_ PPH_STRING *NewText, + _In_opt_ PVOID Context + ); + +VOID EtpNetworkTextIconUpdateCallback( + _In_ struct _PH_NF_ICON *Icon, + _Out_ PVOID *NewIconOrBitmap, + _Out_ PULONG Flags, + _Out_ PPH_STRING *NewText, + _In_opt_ PVOID Context + ); + VOID EtRegisterNotifyIcons( - VOID + _In_ PPH_TRAY_ICON_POINTERS Pointers ) { PH_NF_ICON_REGISTRATION_DATA data; @@ -81,34 +108,67 @@ VOID EtRegisterNotifyIcons( data.UpdateCallback = EtpGpuIconUpdateCallback; data.MessageCallback = EtpGpuIconMessageCallback; - PhPluginRegisterIcon( + Pointers->RegisterTrayIcon( PluginInstance, GPU_ICON_ID, NULL, L"&GPU history", - PH_NF_ICON_SHOW_MINIINFO | (EtGpuEnabled ? 0 : PH_NF_ICON_UNAVAILABLE), + EtGpuEnabled ? 0 : PH_NF_ICON_UNAVAILABLE, &data ); data.UpdateCallback = EtpDiskIconUpdateCallback; data.MessageCallback = EtpDiskIconMessageCallback; - PhPluginRegisterIcon( + Pointers->RegisterTrayIcon( PluginInstance, DISK_ICON_ID, NULL, L"&Disk history", - PH_NF_ICON_SHOW_MINIINFO | (EtEtwEnabled ? 0 : PH_NF_ICON_UNAVAILABLE), + EtEtwEnabled ? 0 : PH_NF_ICON_UNAVAILABLE, &data ); data.UpdateCallback = EtpNetworkIconUpdateCallback; data.MessageCallback = EtpNetworkIconMessageCallback; - PhPluginRegisterIcon( + Pointers->RegisterTrayIcon( PluginInstance, NETWORK_ICON_ID, NULL, L"&Network history", - PH_NF_ICON_SHOW_MINIINFO | (EtEtwEnabled ? 0 : PH_NF_ICON_UNAVAILABLE), + EtEtwEnabled ? 0 : PH_NF_ICON_UNAVAILABLE, + &data + ); + + data.UpdateCallback = EtpGpuTextIconUpdateCallback; + data.MessageCallback = EtpGpuIconMessageCallback; + Pointers->RegisterTrayIcon( + PluginInstance, + GPU_ICON_TEXT_ID, + NULL, + L"&GPU usage (Text)", + EtGpuEnabled ? 0 : PH_NF_ICON_UNAVAILABLE, + &data + ); + + data.UpdateCallback = EtpDiskTextIconUpdateCallback; + data.MessageCallback = EtpDiskIconMessageCallback; + Pointers->RegisterTrayIcon( + PluginInstance, + DISK_ICON_TEXT_ID, + NULL, + L"&Disk usage (Text)", + EtEtwEnabled ? 0 : PH_NF_ICON_UNAVAILABLE, + &data + ); + + data.UpdateCallback = EtpNetworkIconUpdateCallback; + data.MessageCallback = EtpNetworkIconMessageCallback; + Pointers->RegisterTrayIcon( + PluginInstance, + NETWORK_ICON_TEXT_ID, + NULL, + L"&Network usage (Text)", + EtEtwEnabled ? 0 : PH_NF_ICON_UNAVAILABLE, &data ); } @@ -464,3 +524,237 @@ BOOLEAN EtpNetworkIconMessageCallback( return FALSE; } + +// Text + +VOID EtpGpuTextIconUpdateCallback( + _In_ struct _PH_NF_ICON *Icon, + _Out_ PVOID *NewIconOrBitmap, + _Out_ PULONG Flags, + _Out_ PPH_STRING *NewText, + _In_opt_ PVOID Context + ) +{ + static PH_GRAPH_DRAW_INFO drawInfo = + { + 16, + 16, + 0, + 0, + RGB(0x00, 0x00, 0x00), + 0, + NULL, + NULL, + 0, + 0, + 0, + 0 + }; + HBITMAP bitmap; + PVOID bits; + HDC hdc; + HBITMAP oldBitmap; + HANDLE maxGpuProcessId; + PPH_PROCESS_ITEM maxGpuProcessItem; + PH_FORMAT format[8]; + PPH_STRING text; + + // Icon + + Icon->Pointers->BeginBitmap(&drawInfo.Width, &drawInfo.Height, &bitmap, &bits, &hdc, &oldBitmap); + + PhInitFormatF(&format[0], (FLOAT)EtGpuNodeUsage * 100, 0); + text = PhFormat(format, 1, 10); + + drawInfo.TextColor = PhGetIntegerSetting(L"ColorCpuKernel"); + PhDrawTrayIconText(hdc, bits, &drawInfo, &text->sr); + PhDereferenceObject(text); + + SelectObject(hdc, oldBitmap); + *NewIconOrBitmap = bitmap; + *Flags = PH_NF_UPDATE_IS_BITMAP; + + // Text + + if (EtMaxGpuNodeHistory.Count != 0) + maxGpuProcessId = UlongToHandle(PhGetItemCircularBuffer_ULONG(&EtMaxGpuNodeHistory, 0)); + else + maxGpuProcessId = NULL; + + if (maxGpuProcessId) + maxGpuProcessItem = PhReferenceProcessItem(maxGpuProcessId); + else + maxGpuProcessItem = NULL; + + PhInitFormatS(&format[0], L"GPU Usage: "); + PhInitFormatF(&format[1], EtGpuNodeUsage * 100, 2); + PhInitFormatC(&format[2], '%'); + + if (maxGpuProcessItem) + { + PhInitFormatC(&format[3], '\n'); + PhInitFormatSR(&format[4], maxGpuProcessItem->ProcessName->sr); + PhInitFormatS(&format[5], L": "); + PhInitFormatF(&format[6], EtGetProcessBlock(maxGpuProcessItem)->GpuNodeUsage * 100, 2); + PhInitFormatC(&format[7], '%'); + } + + *NewText = PhFormat(format, maxGpuProcessItem ? 8 : 3, 128); + if (maxGpuProcessItem) PhDereferenceObject(maxGpuProcessItem); +} + +VOID EtpDiskTextIconUpdateCallback( + _In_ struct _PH_NF_ICON *Icon, + _Out_ PVOID *NewIconOrBitmap, + _Out_ PULONG Flags, + _Out_ PPH_STRING *NewText, + _In_opt_ PVOID Context + ) +{ + static PH_GRAPH_DRAW_INFO drawInfo = + { + 16, + 16, + 0, + 0, + RGB(0x00, 0x00, 0x00), + 0, + NULL, + NULL, + 0, + 0, + 0, + 0 + }; + HBITMAP bitmap; + PVOID bits; + HDC hdc; + HBITMAP oldBitmap; + HANDLE maxDiskProcessId; + PPH_PROCESS_ITEM maxDiskProcessItem; + PH_FORMAT format[6]; + PPH_STRING text; + static ULONG64 maxValue = 100000 * 1024; // minimum scaling of 100 MB. + + // Icon + + Icon->Pointers->BeginBitmap(&drawInfo.Width, &drawInfo.Height, &bitmap, &bits, &hdc, &oldBitmap); + + if (maxValue < (EtDiskReadDelta.Delta + EtDiskWriteDelta.Delta)) + maxValue = (EtDiskReadDelta.Delta + EtDiskWriteDelta.Delta); + + PhInitFormatF(&format[0], (FLOAT)(EtDiskReadDelta.Delta + EtDiskWriteDelta.Delta) / maxValue * 100, 0); + text = PhFormat(format, 1, 10); + + drawInfo.TextColor = PhGetIntegerSetting(L"ColorIoReadOther"); // ColorIoWrite + PhDrawTrayIconText(hdc, bits, &drawInfo, &text->sr); + PhDereferenceObject(text); + + SelectObject(hdc, oldBitmap); + *NewIconOrBitmap = bitmap; + *Flags = PH_NF_UPDATE_IS_BITMAP; + + // Text + + if (EtMaxDiskHistory.Count != 0) + maxDiskProcessId = UlongToHandle(PhGetItemCircularBuffer_ULONG(&EtMaxDiskHistory, 0)); + else + maxDiskProcessId = NULL; + + if (maxDiskProcessId) + maxDiskProcessItem = PhReferenceProcessItem(maxDiskProcessId); + else + maxDiskProcessItem = NULL; + + PhInitFormatS(&format[0], L"Disk\nR: "); + PhInitFormatSize(&format[1], EtDiskReadDelta.Delta); + PhInitFormatS(&format[2], L"\nW: "); + PhInitFormatSize(&format[3], EtDiskWriteDelta.Delta); + + if (maxDiskProcessItem) + { + PhInitFormatC(&format[4], '\n'); + PhInitFormatSR(&format[5], maxDiskProcessItem->ProcessName->sr); + } + + *NewText = PhFormat(format, maxDiskProcessItem ? 6 : 4, 128); + if (maxDiskProcessItem) PhDereferenceObject(maxDiskProcessItem); +} + +VOID EtpNetworkTextIconUpdateCallback( + _In_ struct _PH_NF_ICON *Icon, + _Out_ PVOID *NewIconOrBitmap, + _Out_ PULONG Flags, + _Out_ PPH_STRING *NewText, + _In_opt_ PVOID Context + ) +{ + static PH_GRAPH_DRAW_INFO drawInfo = + { + 16, + 16, + 0, + 0, + RGB(0x00, 0x00, 0x00), + 0, + NULL, + NULL, + 0, + 0, + 0, + 0 + }; + HBITMAP bitmap; + PVOID bits; + HDC hdc; + HBITMAP oldBitmap; + HANDLE maxNetworkProcessId; + PPH_PROCESS_ITEM maxNetworkProcessItem; + PH_FORMAT format[6]; + PPH_STRING text; + static ULONG64 maxValue = 1024 * 1024; // minimum scaling of 1 MB. + + // Icon + + Icon->Pointers->BeginBitmap(&drawInfo.Width, &drawInfo.Height, &bitmap, &bits, &hdc, &oldBitmap); + + if (maxValue < (EtNetworkReceiveDelta.Delta + EtNetworkSendDelta.Delta)) + maxValue = (EtNetworkReceiveDelta.Delta + EtNetworkSendDelta.Delta); + + PhInitFormatF(&format[0], (FLOAT)(EtNetworkReceiveDelta.Delta + EtNetworkSendDelta.Delta) / maxValue * 100, 0); + text = PhFormat(format, 1, 10); + + drawInfo.TextColor = PhGetIntegerSetting(L"ColorIoReadOther"); // ColorIoWrite + PhDrawTrayIconText(hdc, bits, &drawInfo, &text->sr); + PhDereferenceObject(text); + + SelectObject(hdc, oldBitmap); + *NewIconOrBitmap = bitmap; + *Flags = PH_NF_UPDATE_IS_BITMAP; + + // Text + + if (EtMaxNetworkHistory.Count != 0) + maxNetworkProcessId = UlongToHandle(PhGetItemCircularBuffer_ULONG(&EtMaxNetworkHistory, 0)); + else + maxNetworkProcessId = NULL; + + if (maxNetworkProcessId) + maxNetworkProcessItem = PhReferenceProcessItem(maxNetworkProcessId); + else + maxNetworkProcessItem = NULL; + + PhInitFormatS(&format[0], L"Network\nR: "); + PhInitFormatSize(&format[1], EtNetworkReceiveDelta.Delta); + PhInitFormatS(&format[2], L"\nS: "); + PhInitFormatSize(&format[3], EtNetworkSendDelta.Delta); + + if (maxNetworkProcessItem) + { + PhInitFormatC(&format[4], '\n'); + PhInitFormatSR(&format[5], maxNetworkProcessItem->ProcessName->sr); + } + + *NewText = PhFormat(format, maxNetworkProcessItem ? 6 : 4, 128); + if (maxNetworkProcessItem) PhDereferenceObject(maxNetworkProcessItem); +} diff --git a/plugins/ExtendedTools/main.c b/plugins/ExtendedTools/main.c index f552223ac6de..0b745fd3e5ac 100644 --- a/plugins/ExtendedTools/main.c +++ b/plugins/ExtendedTools/main.c @@ -42,6 +42,7 @@ PH_CALLBACK_REGISTRATION ProcessTreeNewInitializingCallbackRegistration; PH_CALLBACK_REGISTRATION NetworkTreeNewInitializingCallbackRegistration; PH_CALLBACK_REGISTRATION SystemInformationInitializingCallbackRegistration; PH_CALLBACK_REGISTRATION MiniInformationInitializingCallbackRegistration; +PH_CALLBACK_REGISTRATION TrayIconsInitializingCallbackRegistration; PH_CALLBACK_REGISTRATION ProcessesUpdatedCallbackRegistration; PH_CALLBACK_REGISTRATION NetworkItemsUpdatedCallbackRegistration; @@ -54,8 +55,6 @@ VOID NTAPI LoadCallback( { EtEtwStatisticsInitialization(); EtGpuMonitorInitialization(); - - EtRegisterNotifyIcons(); } VOID NTAPI UnloadCallback( @@ -299,6 +298,14 @@ VOID NTAPI MiniInformationInitializingCallback( EtEtwMiniInformationInitializing(Parameter); } +VOID NTAPI TrayIconsInitializingCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + EtRegisterNotifyIcons(Parameter); +} + VOID NTAPI ProcessesUpdatedCallback( _In_opt_ PVOID Parameter, _In_opt_ PVOID Context @@ -571,6 +578,13 @@ LOGICAL DllMain( &MiniInformationInitializingCallbackRegistration ); + PhRegisterCallback( + PhGetGeneralCallback(GeneralCallbackTrayIconsInitializing), + TrayIconsInitializingCallback, + NULL, + &TrayIconsInitializingCallbackRegistration + ); + PhRegisterCallback( &PhProcessesUpdatedEvent, ProcessesUpdatedCallback, From e317b8e16b73d37011b696086270fe5bf9b3d3d9 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 20 Jan 2018 05:58:09 +1100 Subject: [PATCH 0701/2058] Remove deprecated icons --- ProcessHacker/ProcessHacker.rc | 4 ---- ProcessHacker/ProcessHacker.vcxproj | 2 -- ProcessHacker/ProcessHacker.vcxproj.filters | 6 ------ ProcessHacker/resources/application_go.ico | Bin 9574 -> 0 bytes ProcessHacker/resources/cog_go.ico | Bin 9574 -> 0 bytes 5 files changed, 12 deletions(-) delete mode 100644 ProcessHacker/resources/application_go.ico delete mode 100644 ProcessHacker/resources/cog_go.ico diff --git a/ProcessHacker/ProcessHacker.rc b/ProcessHacker/ProcessHacker.rc index f96309641440..f057df71c700 100644 --- a/ProcessHacker/ProcessHacker.rc +++ b/ProcessHacker/ProcessHacker.rc @@ -58,10 +58,6 @@ IDI_PHAPPLICATION ICON "resources\\application.ico" IDI_COG ICON "resources\\cog.ico" -IDI_PHAPPLICATIONGO ICON "resources\\application_go.ico" - -IDI_COGGO ICON "resources\\cog_go.ico" - IDI_PIN ICON "resources\\pin.ico" IDI_FOLDER ICON "resources\\folder.ico" diff --git a/ProcessHacker/ProcessHacker.vcxproj b/ProcessHacker/ProcessHacker.vcxproj index f5b99fe1b1a1..196b6949ee97 100644 --- a/ProcessHacker/ProcessHacker.vcxproj +++ b/ProcessHacker/ProcessHacker.vcxproj @@ -404,9 +404,7 @@ - - diff --git a/ProcessHacker/ProcessHacker.vcxproj.filters b/ProcessHacker/ProcessHacker.vcxproj.filters index 3a8cdc58efd6..550d5b2b5c2b 100644 --- a/ProcessHacker/ProcessHacker.vcxproj.filters +++ b/ProcessHacker/ProcessHacker.vcxproj.filters @@ -571,12 +571,6 @@ Resources - - Resources - - - Resources - Module diff --git a/ProcessHacker/resources/application_go.ico b/ProcessHacker/resources/application_go.ico deleted file mode 100644 index 0a72a48bd77ec0b36c4fe9ad3de5ab80e0df27fc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9574 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 diff --git a/ProcessHacker/resources/cog_go.ico b/ProcessHacker/resources/cog_go.ico deleted file mode 100644 index d679437a07c48a69dbe683afec677fafd3e34879..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9574 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 SX Date: Sat, 20 Jan 2018 08:02:00 +1100 Subject: [PATCH 0702/2058] Always display tooltips even when the window doesn't have focus (https://wj32.org/processhacker/forums/viewtopic.php?t=186) --- phlib/graph.c | 2 +- phlib/treenew.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/phlib/graph.c b/phlib/graph.c index 86e6a4b767cc..fb7032e4f921 100644 --- a/phlib/graph.c +++ b/phlib/graph.c @@ -1281,7 +1281,7 @@ LRESULT CALLBACK PhpGraphWndProc( context->TooltipHandle = CreateWindow( TOOLTIPS_CLASS, NULL, - WS_POPUP | WS_EX_TRANSPARENT | TTS_NOPREFIX, + WS_POPUP | WS_EX_TRANSPARENT | TTS_NOPREFIX | TTS_ALWAYSTIP, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, diff --git a/phlib/treenew.c b/phlib/treenew.c index 639d57cf4a17..635759affda9 100644 --- a/phlib/treenew.c +++ b/phlib/treenew.c @@ -5735,7 +5735,7 @@ VOID PhTnpInitializeTooltips( WS_EX_TRANSPARENT, // solves double-click problem TOOLTIPS_CLASS, NULL, - WS_POPUP | TTS_NOPREFIX, + WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP, 0, 0, 0, From 6ea0d664be0acf3bba040aa8584505bad7fd3b7e Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 20 Jan 2018 09:08:02 +1100 Subject: [PATCH 0703/2058] Remove unused code --- ProcessHacker/notifico.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/ProcessHacker/notifico.c b/ProcessHacker/notifico.c index e88f771870c2..29b0f66b87c8 100644 --- a/ProcessHacker/notifico.c +++ b/ProcessHacker/notifico.c @@ -142,9 +142,6 @@ VOID PhNfSaveSettings( ); } - if (iconListBuilder.String->Length != 0) - PhRemoveEndStringBuilder(&iconListBuilder, 1); - settingsString = PhFinalStringBuilderString(&iconListBuilder); PhSetStringSetting2(L"IconSettings", &settingsString->sr); PhDereferenceObject(settingsString); From 8aab7a17ee6e91ce37eddc4f19a05501d19143c0 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 20 Jan 2018 09:08:51 +1100 Subject: [PATCH 0704/2058] Fix refreshing plugin nodes after disabling a plugin --- ProcessHacker/plugman.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/ProcessHacker/plugman.c b/ProcessHacker/plugman.c index 70d9d552b4d6..6d5462c518ea 100644 --- a/ProcessHacker/plugman.c +++ b/ProcessHacker/plugman.c @@ -3,7 +3,7 @@ * plugins * * Copyright (C) 2010-2011 wj32 - * Copyright (C) 2017 dmex + * Copyright (C) 2017-2018 dmex * * This file is part of Process Hacker. * @@ -782,9 +782,8 @@ INT_PTR CALLBACK PhpPluginsDlgProc( PhSetPluginDisabled(&baseNameRef, TRUE); - ClearPluginsTree(context); - PhpEnumerateLoadedPlugins(context); - TreeNew_AutoSizeColumn(context->TreeNewHandle, PH_PLUGIN_TREE_COLUMN_ITEM_NAME, TN_AUTOSIZE_REMAINING_SPACE); + RemovePluginsNode(context, selectedNode); + SetWindowText(GetDlgItem(hwndDlg, IDC_DISABLED), PhaFormatString(L"Disabled Plugins (%lu)", PhpDisabledPluginsCount())->Buffer); } break; From 528b134944066905c1fc5a126279559c97443712 Mon Sep 17 00:00:00 2001 From: lucasg Date: Sun, 21 Jan 2018 08:21:18 +0100 Subject: [PATCH 0705/2058] Make PH_IMAGE_RESOURCE_ENTRY.Data return a VA instead of a RVA (#227) PIMAGE_RESOURCE_DATA_ENTRY return a RVA per the PE-COFF specification, so we need to convert it into a VA before using it. --- phlib/mapimg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phlib/mapimg.c b/phlib/mapimg.c index 5f9086de1dd7..8e8da7003868 100644 --- a/phlib/mapimg.c +++ b/phlib/mapimg.c @@ -1688,7 +1688,7 @@ NTSTATUS PhGetMappedImageResources( Resources->ResourceEntries[resourceIndex].Type = NAME_FROM_RESOURCE_ENTRY(resourceDirectory, resourceType); Resources->ResourceEntries[resourceIndex].Name = NAME_FROM_RESOURCE_ENTRY(resourceDirectory, resourceName); Resources->ResourceEntries[resourceIndex].Language = NAME_FROM_RESOURCE_ENTRY(resourceDirectory, resourceLanguage); - Resources->ResourceEntries[resourceIndex].Data = PTR_ADD_OFFSET(MappedImage->ViewBase, resourceData->OffsetToData); + Resources->ResourceEntries[resourceIndex].Data = PhMappedImageRvaToVa(MappedImage, resourceData->OffsetToData, NULL); Resources->ResourceEntries[resourceIndex++].Size = resourceData->Size; } } From ffe6d9347ffa0e3956ac05899ecec9e8440683f3 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 23 Jan 2018 12:26:39 +1100 Subject: [PATCH 0706/2058] Update CustomBuildTools binaries --- tools/CustomBuildTool/Source Files/Build.cs | 3 ++- .../bin/Release/CustomBuildTool.exe | Bin 163840 -> 163840 bytes .../bin/Release/CustomBuildTool.pdb | Bin 75264 -> 75264 bytes 3 files changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/CustomBuildTool/Source Files/Build.cs b/tools/CustomBuildTool/Source Files/Build.cs index ac7a3f1f6170..8dac9e821fc5 100644 --- a/tools/CustomBuildTool/Source Files/Build.cs +++ b/tools/CustomBuildTool/Source Files/Build.cs @@ -2,7 +2,7 @@ * Process Hacker Toolchain - * Build script * - * Copyright (C) 2017 dmex + * Copyright (C) 2017-2018 dmex * * This file is part of Process Hacker. * @@ -118,6 +118,7 @@ public static class Build "dltmgr.h", "dspick.h", "emenu.h", + "exlf.h", "fastlock.h", "filestream.h", "graph.h", diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe b/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe index 6d4f94ed7598186a47d75359070eba401bea087f..109a98cde269e8b23dc2f5243c9aa522fd4c41f4 100644 GIT binary patch delta 14622 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 CaAYU| delta 14471 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 diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb b/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb index 596e48415e9b89b3d78904c08a570cc77e4b95ca..7b5e32c5e289a00b0c3ec023fefa7f253c862c82 100644 GIT binary patch delta 15269 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 Date: Tue, 23 Jan 2018 12:27:18 +1100 Subject: [PATCH 0707/2058] Fix missing 'PhUnloadMappedImage' function export --- ProcessHacker/ProcessHacker.def | 1 + 1 file changed, 1 insertion(+) diff --git a/ProcessHacker/ProcessHacker.def b/ProcessHacker/ProcessHacker.def index 16e4545ff152..fcb0537c4d8a 100644 --- a/ProcessHacker/ProcessHacker.def +++ b/ProcessHacker/ProcessHacker.def @@ -534,6 +534,7 @@ EXPORTS PhGetMappedImageLoadConfig64 PhInitializeMappedImage PhLoadMappedImage + PhUnloadMappedImage ; settings PhAddSetting From 0aa25a2b07b4a7a3dfb07818d75db46831ca37c4 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 23 Jan 2018 12:27:48 +1100 Subject: [PATCH 0708/2058] Plugins: Improve CommonBitmapToIcon --- plugins/include/commonutil.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/include/commonutil.h b/plugins/include/commonutil.h index 57d730baee46..18f4aea48cd2 100644 --- a/plugins/include/commonutil.h +++ b/plugins/include/commonutil.h @@ -37,7 +37,7 @@ CommonBitmapToIcon( HBITMAP screenBitmap; ICONINFO iconInfo = { 0 }; - screenDc = CreateIC(L"DISPLAY", NULL, NULL, NULL); + screenDc = GetDC(NULL); screenBitmap = CreateCompatibleBitmap(screenDc, Width, Height); iconInfo.fIcon = TRUE; @@ -47,7 +47,7 @@ CommonBitmapToIcon( icon = CreateIconIndirect(&iconInfo); DeleteObject(screenBitmap); - DeleteDC(screenDc); + ReleaseDC(NULL, screenDc); return icon; } From 3419fdd34ff82739e41611637adb24fb99631f3a Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 23 Jan 2018 13:55:19 +1100 Subject: [PATCH 0709/2058] Add MiniInfoWindowClassName setting --- ProcessHacker/miniinfo.c | 11 +++++++---- ProcessHacker/settings.c | 1 + 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/ProcessHacker/miniinfo.c b/ProcessHacker/miniinfo.c index f6b151608b98..adf3e23e627b 100644 --- a/ProcessHacker/miniinfo.c +++ b/ProcessHacker/miniinfo.c @@ -104,6 +104,8 @@ VOID PhPinMiniInformation( if (!PhMipContainerWindow) { WNDCLASSEX wcex; + RTL_ATOM windowAtom; + PPH_STRING className; memset(&wcex, 0, sizeof(WNDCLASSEX)); wcex.cbSize = sizeof(WNDCLASSEX); @@ -115,13 +117,14 @@ VOID PhPinMiniInformation( wcex.hIcon = PH_LOAD_SHARED_ICON_LARGE(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER)); wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1); - wcex.lpszClassName = MIP_CONTAINER_CLASSNAME; + className = PhaGetStringSetting(L"MiniInfoWindowClassName"); + wcex.lpszClassName = PhGetStringOrDefault(className, L"MiniInfoWindowClassName"); wcex.hIconSm = PH_LOAD_SHARED_ICON_SMALL(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER)); - RegisterClassEx(&wcex); + windowAtom = RegisterClassEx(&wcex); PhMipContainerWindow = CreateWindow( - MIP_CONTAINER_CLASSNAME, - L"Process Hacker", + MAKEINTATOM(windowAtom), + PhGetIntegerSetting(L"EnableWindowText") ? L"Process Hacker" : NULL, WS_BORDER | WS_THICKFRAME | WS_POPUP, 0, 0, diff --git a/ProcessHacker/settings.c b/ProcessHacker/settings.c index 3ab7aa1b0f65..e571b1a79fc1 100644 --- a/ProcessHacker/settings.c +++ b/ProcessHacker/settings.c @@ -109,6 +109,7 @@ VOID PhAddDefaultSettings( PhpAddStringSetting(L"MemoryTreeListSort", L"0,0"); // 0, NoSortOrder PhpAddIntegerPairSetting(L"MemoryListsWindowPosition", L"400,400"); PhpAddStringSetting(L"MemoryReadWriteAddressChoices", L""); + PhpAddStringSetting(L"MiniInfoWindowClassName", L"MiniInfoWindowClassName"); PhpAddIntegerSetting(L"MiniInfoWindowEnabled", L"1"); PhpAddIntegerSetting(L"MiniInfoWindowOpacity", L"0"); // means 100% PhpAddIntegerSetting(L"MiniInfoWindowPinned", L"0"); From 9c8cfc6512afde090ceda910f87d31c21bef41ad Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 23 Jan 2018 14:03:43 +1100 Subject: [PATCH 0710/2058] Update default TreeListBorderEnable setting --- ProcessHacker/settings.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ProcessHacker/settings.c b/ProcessHacker/settings.c index e571b1a79fc1..1c79a5f768d5 100644 --- a/ProcessHacker/settings.c +++ b/ProcessHacker/settings.c @@ -164,7 +164,7 @@ VOID PhAddDefaultSettings( PhpAddIntegerSetting(L"TokenSplitterEnable", L"0"); PhpAddIntegerSetting(L"TokenSplitterPosition", L"150"); PhpAddStringSetting(L"TokenPrivilegesListViewColumns", L""); - PhpAddIntegerSetting(L"TreeListBorderEnable", L"1"); + PhpAddIntegerSetting(L"TreeListBorderEnable", L"0"); PhpAddIntegerSetting(L"UpdateInterval", L"3e8"); // 1000ms PhpAddIntegerSetting(L"WmiProviderEnableHiddenMenu", L"0"); PhpAddStringSetting(L"WmiProviderListViewColumns", L""); From 8d9acaad2896d7d8654dac062aec8e081115819a Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 25 Jan 2018 09:24:22 +1100 Subject: [PATCH 0711/2058] Update treenew control; Add TreeListCustomColorsEnable setting --- ProcessHacker/mainwnd.c | 21 ++++-- phlib/include/treenew.h | 9 +++ phlib/include/treenewp.h | 7 +- phlib/treenew.c | 149 +++++++++++++++++++++++++++++++-------- 4 files changed, 149 insertions(+), 37 deletions(-) diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index 0d7ef374a445..b6f77f729c88 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -395,6 +395,8 @@ VOID PhMwpInitializeControls( { ULONG thinRows; ULONG treelistBorder; + ULONG treelistCustomColors; + PH_TREENEW_CREATEPARAMS treelistCreateParams; TabControlHandle = CreateWindow( WC_TABCONTROL, @@ -414,11 +416,18 @@ VOID PhMwpInitializeControls( thinRows = PhGetIntegerSetting(L"ThinRows") ? TN_STYLE_THIN_ROWS : 0; treelistBorder = PhGetIntegerSetting(L"TreeListBorderEnable") ? WS_BORDER : 0; + treelistCustomColors = PhGetIntegerSetting(L"TreeListCustomColorsEnable") ? TN_STYLE_CUSTOM_COLORS : 0; + + if (treelistCustomColors) + { + treelistCreateParams.FocusColor = PhGetIntegerSetting(L"TreeListCustomColorFocus"); + treelistCreateParams.SelectionColor = PhGetIntegerSetting(L"TreeListCustomColorSelection"); + } PhMwpProcessTreeNewHandle = CreateWindow( PH_TREENEW_CLASSNAME, NULL, - WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | TN_STYLE_ICONS | TN_STYLE_DOUBLE_BUFFERED | TN_STYLE_ANIMATE_DIVIDER | thinRows | treelistBorder, + WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | TN_STYLE_ICONS | TN_STYLE_DOUBLE_BUFFERED | TN_STYLE_ANIMATE_DIVIDER | thinRows | treelistBorder | treelistCustomColors, 0, 0, 3, @@ -426,14 +435,14 @@ VOID PhMwpInitializeControls( PhMainWndHandle, NULL, PhInstanceHandle, - NULL + &treelistCreateParams ); BringWindowToTop(PhMwpProcessTreeNewHandle); PhMwpServiceTreeNewHandle = CreateWindow( PH_TREENEW_CLASSNAME, NULL, - WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | TN_STYLE_ICONS | TN_STYLE_DOUBLE_BUFFERED | thinRows | treelistBorder, + WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | TN_STYLE_ICONS | TN_STYLE_DOUBLE_BUFFERED | thinRows | treelistBorder | treelistCustomColors, 0, 0, 3, @@ -441,14 +450,14 @@ VOID PhMwpInitializeControls( PhMainWndHandle, NULL, PhInstanceHandle, - NULL + &treelistCreateParams ); BringWindowToTop(PhMwpServiceTreeNewHandle); PhMwpNetworkTreeNewHandle = CreateWindow( PH_TREENEW_CLASSNAME, NULL, - WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | TN_STYLE_ICONS | TN_STYLE_DOUBLE_BUFFERED | thinRows | treelistBorder, + WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | TN_STYLE_ICONS | TN_STYLE_DOUBLE_BUFFERED | thinRows | treelistBorder | treelistCustomColors, 0, 0, 3, @@ -456,7 +465,7 @@ VOID PhMwpInitializeControls( PhMainWndHandle, NULL, PhInstanceHandle, - NULL + &treelistCreateParams ); BringWindowToTop(PhMwpNetworkTreeNewHandle); diff --git a/phlib/include/treenew.h b/phlib/include/treenew.h index 51e24253eaa3..3eac52a3b170 100644 --- a/phlib/include/treenew.h +++ b/phlib/include/treenew.h @@ -10,6 +10,13 @@ extern "C" { #define PH_TREENEW_SEARCH_TIMEOUT 1000 #define PH_TREENEW_SEARCH_MAXIMUM_LENGTH 1023 +typedef struct _PH_TREENEW_CREATEPARAMS +{ + COLORREF FocusColor; + COLORREF SelectionColor; + // Add new fields here. +} PH_TREENEW_CREATEPARAMS, *PPH_TREENEW_CREATEPARAMS; + typedef struct _PH_TREENEW_COLUMN { union @@ -101,6 +108,8 @@ typedef struct _PH_TREENEW_NODE #define TN_STYLE_NO_COLUMN_REORDER 0x20 #define TN_STYLE_THIN_ROWS 0x40 #define TN_STYLE_NO_COLUMN_HEADER 0x80 +#define TN_STYLE_CUSTOM_COLORS 0x100 +#define TN_STYLE_ALWAYS_SHOW_SELECTION 0x200 // Extended flags #define TN_FLAG_ITEM_DRAG_SELECT 0x1 diff --git a/phlib/include/treenewp.h b/phlib/include/treenewp.h index 997bbf8980ca..a90c1695cdab 100644 --- a/phlib/include/treenewp.h +++ b/phlib/include/treenewp.h @@ -57,7 +57,9 @@ typedef struct _PH_TREENEW_CONTEXT ULONG DragSelectionActive : 1; ULONG SelectionRectangleAlpha : 1; // use alpha blending for the selection rectangle ULONG CustomRowHeight : 1; - ULONG Spare : 4; + ULONG CustomColors : 1; + ULONG ContextMenuActive : 1; + ULONG Spare : 2; }; ULONG Flags; }; @@ -134,6 +136,9 @@ typedef struct _PH_TREENEW_CONTEXT HTHEME ThemeData; COLORREF DefaultBackColor; COLORREF DefaultForeColor; + HBRUSH CustomFocusBrush; + HBRUSH CustomSelectedBrush; + LONG SystemBorderX; LONG SystemBorderY; LONG SystemEdgeX; diff --git a/phlib/treenew.c b/phlib/treenew.c index 635759affda9..b2bc4aa95545 100644 --- a/phlib/treenew.c +++ b/phlib/treenew.c @@ -183,7 +183,11 @@ LRESULT CALLBACK PhTnpWndProc( return 0; case WM_KILLFOCUS: { + if (!context->ContextMenuActive && !(context->Style & TN_STYLE_ALWAYS_SHOW_SELECTION)) + PhTnpSelectRange(context, -1, -1, TN_SELECT_RESET, NULL, NULL); + context->HasFocus = FALSE; + InvalidateRect(context->Handle, NULL, FALSE); } return 0; @@ -208,6 +212,20 @@ LRESULT CALLBACK PhTnpWndProc( break; case WM_MOUSELEAVE: { + if (!context->ContextMenuActive && !(context->Style & TN_STYLE_ALWAYS_SHOW_SELECTION)) + { + ULONG changedStart; + ULONG changedEnd; + RECT rect; + + PhTnpSelectRange(context, -1, -1, TN_SELECT_RESET, &changedStart, &changedEnd); + + if (PhTnpGetRowRects(context, changedStart, changedEnd, TRUE, &rect)) + { + InvalidateRect(context->Handle, &rect, FALSE); + } + } + if (!context->SuspendUpdateStructure) PhTnpOnMouseLeave(hwnd, context); } @@ -386,6 +404,14 @@ VOID PhTnpDestroyTreeNewContext( if (Context->SuspendUpdateRegion) DeleteObject(Context->SuspendUpdateRegion); + if (Context->CustomColors) + { + if (Context->CustomFocusBrush) + DeleteObject(Context->CustomFocusBrush); + if (Context->CustomSelectedBrush) + DeleteObject(Context->CustomSelectedBrush); + } + PhFree(Context); } @@ -396,11 +422,13 @@ BOOLEAN PhTnpOnCreate( ) { ULONG headerStyle; + PPH_TREENEW_CREATEPARAMS createParamaters; Context->Handle = hwnd; Context->InstanceHandle = CreateStruct->hInstance; Context->Style = CreateStruct->style; Context->ExtendedStyle = CreateStruct->dwExStyle; + createParamaters = CreateStruct->lpCreateParams; if (Context->Style & TN_STYLE_DOUBLE_BUFFERED) Context->DoubleBuffered = TRUE; @@ -414,6 +442,26 @@ BOOLEAN PhTnpOnCreate( if (!(Context->Style & TN_STYLE_NO_COLUMN_HEADER)) headerStyle |= WS_VISIBLE; + if (Context->Style & TN_STYLE_CUSTOM_COLORS) + { + Context->CustomColors = TRUE; + + if (createParamaters->FocusColor) + Context->CustomFocusBrush = CreateSolidBrush(createParamaters->FocusColor); + else + Context->CustomFocusBrush = CreateSolidBrush(RGB(0, 0, 0xff)); + + if (createParamaters->SelectionColor) + Context->CustomSelectedBrush = CreateSolidBrush(createParamaters->FocusColor); + else + Context->CustomSelectedBrush = CreateSolidBrush(RGB(0, 0, 0x80)); + } + else + { + Context->CustomFocusBrush = GetSysColorBrush(COLOR_HOTLIGHT); + Context->CustomSelectedBrush = GetSysColorBrush(COLOR_HIGHLIGHT); + } + if (!(Context->FixedHeaderHandle = CreateWindow( WC_HEADER, NULL, @@ -1295,7 +1343,9 @@ VOID PhTnpOnContextMenu( contextMenu.Node = hitTest.Node; contextMenu.Column = hitTest.Column; contextMenu.KeyboardInvoked = keyboardInvoked; + Context->ContextMenuActive = TRUE; Context->Callback(hwnd, TreeNewContextMenu, &contextMenu, NULL, Context->CallbackContext); + Context->ContextMenuActive = FALSE; } VOID PhTnpOnVScroll( @@ -3085,6 +3135,31 @@ VOID PhTnpAutoSizeColumnHeader( if (Column->Fixed) newWidth++; + + // Check the column header text width. + if (Column->Text) + { + PWSTR text; + SIZE_T textCount; + HDC hdc; + SIZE textSize; + + text = Column->Text; + textCount = PhCountStringZ(text); + + if (hdc = GetDC(Context->Handle)) + { + SelectObject(hdc, Context->Font); + + if (GetTextExtentPoint32(hdc, text, (ULONG)textCount, &textSize)) + { + if (newWidth < textSize.cx + 6 + 6) // HACK: Magic values (same as our cell margins?) + newWidth = textSize.cx + 6 + 6; + } + + ReleaseDC(Context->Handle, hdc); + } + } } item.mask = HDI_WIDTH; @@ -5006,26 +5081,59 @@ VOID PhTnpPaint( for (i = firstRowToUpdate; i <= lastRowToUpdate; i++) { + INT stateId; + node = Context->FlatList->Items[i]; // Prepare the row for drawing. PhTnpPrepareRowForDraw(Context, hdc, node); - if (node->Selected && !Context->ThemeHasItemBackground) + + if (node->Selected) { - // Non-themed background - if (Context->HasFocus) - { - SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT)); - backBrush = GetSysColorBrush(COLOR_HIGHLIGHT); - } + if (i == Context->HotNodeIndex) + stateId = TREIS_HOTSELECTED; + else if (!Context->HasFocus) + stateId = TREIS_SELECTEDNOTFOCUS; + else + stateId = TREIS_SELECTED; + } + else + { + if (i == Context->HotNodeIndex) + stateId = TREIS_HOT; else + stateId = -1; + } + + if (Context->CustomColors || !Context->ThemeHasItemBackground) + { + switch (stateId) { - SetTextColor(hdc, GetSysColor(COLOR_BTNTEXT)); - backBrush = GetSysColorBrush(COLOR_BTNFACE); + case TREIS_SELECTED: + case TREIS_SELECTEDNOTFOCUS: + { + SetTextColor(hdc, RGB(0xff, 0xff, 0xff)); + backBrush = Context->CustomSelectedBrush; + } + break; + case TREIS_HOT: + case TREIS_HOTSELECTED: + { + SetTextColor(hdc, RGB(0xff, 0xff, 0xff)); + backBrush = Context->CustomFocusBrush; + } + break; + default: + { + SetTextColor(hdc, node->s.DrawForeColor); + SetDCBrushColor(hdc, node->s.DrawBackColor); + backBrush = GetStockObject(DC_BRUSH); + } + break; } - } + } else { SetTextColor(hdc, node->s.DrawForeColor); @@ -5035,29 +5143,10 @@ VOID PhTnpPaint( FillRect(hdc, &rowRect, backBrush); - if (Context->ThemeHasItemBackground) + if (!Context->CustomColors && Context->ThemeHasItemBackground) { - INT stateId; - // Themed background - if (node->Selected) - { - if (i == Context->HotNodeIndex) - stateId = TREIS_HOTSELECTED; - else if (!Context->HasFocus) - stateId = TREIS_SELECTEDNOTFOCUS; - else - stateId = TREIS_SELECTED; - } - else - { - if (i == Context->HotNodeIndex) - stateId = TREIS_HOT; - else - stateId = -1; - } - if (stateId != -1) { if (!Context->FixedColumnVisible) From c15ef2018b0fac2814936eeebdc0a06f0ae0febf Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 25 Jan 2018 09:26:47 +1100 Subject: [PATCH 0712/2058] Add missing settings from previous commit --- ProcessHacker/settings.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ProcessHacker/settings.c b/ProcessHacker/settings.c index 1c79a5f768d5..380c07aa77fe 100644 --- a/ProcessHacker/settings.c +++ b/ProcessHacker/settings.c @@ -165,6 +165,9 @@ VOID PhAddDefaultSettings( PhpAddIntegerSetting(L"TokenSplitterPosition", L"150"); PhpAddStringSetting(L"TokenPrivilegesListViewColumns", L""); PhpAddIntegerSetting(L"TreeListBorderEnable", L"0"); + PhpAddIntegerSetting(L"TreeListCustomColorsEnable", L"0"); + PhpAddIntegerSetting(L"TreeListCustomColorFocus", L"0"); + PhpAddIntegerSetting(L"TreeListCustomColorSelection", L"0"); PhpAddIntegerSetting(L"UpdateInterval", L"3e8"); // 1000ms PhpAddIntegerSetting(L"WmiProviderEnableHiddenMenu", L"0"); PhpAddStringSetting(L"WmiProviderListViewColumns", L""); From 8fadaec3f88e5303188c9d43374b6e09cd5a30d7 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 25 Jan 2018 09:27:41 +1100 Subject: [PATCH 0713/2058] Update ntrtl.h: Add offset macros --- phnt/include/ntrtl.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/phnt/include/ntrtl.h b/phnt/include/ntrtl.h index 92ad843fd878..adbd3f164e50 100644 --- a/phnt/include/ntrtl.h +++ b/phnt/include/ntrtl.h @@ -1,6 +1,9 @@ #ifndef _NTRTL_H #define _NTRTL_H +#define RtlOffsetToPointer(Base, Offset) ((PCHAR)(((PCHAR)(Base)) + ((ULONG_PTR)(Offset)))) +#define RtlPointerToOffset(Base, Pointer) ((ULONG)(((PCHAR)(Pointer)) - ((PCHAR)(Base)))) + // Linked lists FORCEINLINE VOID InitializeListHead( From 24f849fcbccc60ff6b209d62bee26e3732fe9977 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 25 Jan 2018 09:41:49 +1100 Subject: [PATCH 0714/2058] Remove unused define --- ProcessHacker/include/miniinfop.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/ProcessHacker/include/miniinfop.h b/ProcessHacker/include/miniinfop.h index 64e5141ac26a..a9c36442e4dc 100644 --- a/ProcessHacker/include/miniinfop.h +++ b/ProcessHacker/include/miniinfop.h @@ -3,8 +3,6 @@ // Constants -#define MIP_CONTAINER_CLASSNAME L"ProcessHackerMiniInfo" - #define MIP_TIMER_PIN_FIRST 1 #define MIP_TIMER_PIN_LAST (MIP_TIMER_PIN_FIRST + MaxMiniInfoPinType - 1) From a3bcc28ebefa9539eb5936885c7e36350575dd7e Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 25 Jan 2018 12:57:12 +1100 Subject: [PATCH 0715/2058] Update default confirmation dialog icon --- phlib/util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phlib/util.c b/phlib/util.c index 17f0186cc211..2cf209f74456 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -608,7 +608,7 @@ BOOLEAN PhShowConfirmMessage( config.hInstance = PhInstanceHandle; config.dwFlags = TDF_ALLOW_DIALOG_CANCELLATION | (IsWindowVisible(hWnd) ? TDF_POSITION_RELATIVE_TO_WINDOW : 0); config.pszWindowTitle = PhApplicationName; - config.pszMainIcon = Warning ? TD_WARNING_ICON : NULL; + config.pszMainIcon = Warning ? TD_WARNING_ICON : TD_INFORMATION_ICON; config.pszMainInstruction = PhaConcatStrings(3, L"Do you want to ", action->Buffer, L"?")->Buffer; if (Message) From 5b7d4cfa275be23e74836be3af5b9ef7de87e062 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 25 Jan 2018 12:58:28 +1100 Subject: [PATCH 0716/2058] Update native API wrapper functions --- ProcessHacker/thrdprv.c | 40 +----- phlib/include/phnative.h | 8 ++ phlib/include/phnativeinl.h | 246 ++++++++++++++++++++++++++++-------- phlib/native.c | 46 +++++++ 4 files changed, 252 insertions(+), 88 deletions(-) diff --git a/ProcessHacker/thrdprv.c b/ProcessHacker/thrdprv.c index 42c41e2f78fd..933999061a41 100644 --- a/ProcessHacker/thrdprv.c +++ b/ProcessHacker/thrdprv.c @@ -584,46 +584,12 @@ NTSTATUS PhpThreadQueryWorker( if (data->ThreadItem->ThreadHandle && WindowsVersion >= WINDOWS_10_RS1) { - NTSTATUS status; - PVOID buffer; - ULONG bufferSize; - ULONG returnLength; - PTHREAD_NAME_INFORMATION threadNameInfo; + PPH_STRING threadName; - bufferSize = 0x100; - buffer = PhAllocate(bufferSize); - - status = NtQueryInformationThread( - data->ThreadItem->ThreadHandle, - ThreadNameInformation, - buffer, - bufferSize, - &returnLength - ); - - if (status == STATUS_BUFFER_OVERFLOW) - { - PhFree(buffer); - bufferSize = returnLength; - buffer = PhAllocate(bufferSize); - - status = NtQueryInformationThread( - data->ThreadItem->ThreadHandle, - ThreadNameInformation, - buffer, - bufferSize, - &returnLength - ); - } - - if (NT_SUCCESS(status)) + if (NT_SUCCESS(PhGetThreadName(data->ThreadItem->ThreadHandle, &threadName))) { - threadNameInfo = (PTHREAD_NAME_INFORMATION)buffer; - - data->ThreadName = PhCreateStringFromUnicodeString(&threadNameInfo->ThreadName); + data->ThreadName = threadName; } - - PhFree(buffer); } Done: diff --git a/phlib/include/phnative.h b/phlib/include/phnative.h index 8dcb3aa2b9a9..75652c55fc2d 100644 --- a/phlib/include/phnative.h +++ b/phlib/include/phnative.h @@ -1087,6 +1087,14 @@ PhImpersonateClientOfNamedPipe( _In_ HANDLE PipeHandle ); +PHLIBAPI +NTSTATUS +NTAPI +PhGetThreadName( + _In_ HANDLE ThreadHandle, + _Out_ PPH_STRING *ThreadName + ); + #ifdef __cplusplus } #endif diff --git a/phlib/include/phnativeinl.h b/phlib/include/phnativeinl.h index 572dfda47a1c..dc746e769f92 100644 --- a/phlib/include/phnativeinl.h +++ b/phlib/include/phnativeinl.h @@ -261,6 +261,37 @@ PhGetProcessExecuteFlags( ); } +FORCEINLINE +NTSTATUS +PhGetProcessPriority( + _In_ HANDLE ProcessHandle, + _Out_ PPROCESS_PRIORITY_CLASS PriorityClass + ) +{ + return NtQueryInformationProcess( + ProcessHandle, + ProcessPriorityClass, + PriorityClass, + sizeof(PROCESS_PRIORITY_CLASS), + NULL + ); +} + +FORCEINLINE +NTSTATUS +PhSetProcessPriority( + _In_ HANDLE ProcessHandle, + _In_ PROCESS_PRIORITY_CLASS PriorityClass + ) +{ + return NtSetInformationProcess( + ProcessHandle, + ProcessPriorityClass, + &PriorityClass, + sizeof(PROCESS_PRIORITY_CLASS) + ); +} + /** * Gets a process' I/O priority. * @@ -284,6 +315,27 @@ PhGetProcessIoPriority( ); } +/** + * Sets a process' I/O priority. + * + * \param ProcessHandle A handle to a process. The handle must have PROCESS_SET_INFORMATION access. + * \param IoPriority The new I/O priority. + */ +FORCEINLINE +NTSTATUS +PhSetProcessIoPriority( + _In_ HANDLE ProcessHandle, + _In_ IO_PRIORITY_HINT IoPriority + ) +{ + return NtSetInformationProcess( + ProcessHandle, + ProcessIoPriority, + &IoPriority, + sizeof(IO_PRIORITY_HINT) + ); +} + /** * Gets a process' page priority. * @@ -317,6 +369,25 @@ PhGetProcessPagePriority( return status; } +FORCEINLINE +NTSTATUS +PhSetProcessPagePriority( + _In_ HANDLE ProcessHandle, + _In_ ULONG PagePriority + ) +{ + PAGE_PRIORITY_INFORMATION pagePriorityInfo; + + pagePriorityInfo.PagePriority = PagePriority; + + return NtSetInformationProcess( + ProcessHandle, + ProcessPagePriority, + &pagePriorityInfo, + sizeof(PAGE_PRIORITY_INFORMATION) + ); +} + /** * Gets a process' cycle count. * @@ -394,30 +465,33 @@ PhGetProcessProtection( FORCEINLINE NTSTATUS -PhGetProcessIsCFGuardEnabled( +PhGetProcessQuotaLimits( _In_ HANDLE ProcessHandle, - _Out_ PBOOLEAN IsControlFlowGuardEnabled + _Out_ PQUOTA_LIMITS QuotaLimits ) { - NTSTATUS status; - PROCESS_MITIGATION_POLICY_INFORMATION policyInfo; - - policyInfo.Policy = ProcessControlFlowGuardPolicy; - - status = NtQueryInformationProcess( + return NtQueryInformationProcess( ProcessHandle, - ProcessMitigationPolicy, - &policyInfo, - sizeof(PROCESS_MITIGATION_POLICY_INFORMATION), + ProcessQuotaLimits, + QuotaLimits, + sizeof(QUOTA_LIMITS), NULL ); +} - if (!NT_SUCCESS(status)) - return status; - - *IsControlFlowGuardEnabled = !!policyInfo.ControlFlowGuardPolicy.EnableControlFlowGuard; - - return status; +FORCEINLINE +NTSTATUS +PhSetProcessQuotaLimits( + _In_ HANDLE ProcessHandle, + _In_ QUOTA_LIMITS QuotaLimits + ) +{ + return NtSetInformationProcess( + ProcessHandle, + ProcessQuotaLimits, + &QuotaLimits, + sizeof(QUOTA_LIMITS) + ); } /** @@ -441,25 +515,32 @@ PhSetProcessAffinityMask( ); } -/** - * Sets a process' I/O priority. - * - * \param ProcessHandle A handle to a process. The handle must have PROCESS_SET_INFORMATION access. - * \param IoPriority The new I/O priority. - */ FORCEINLINE NTSTATUS -PhSetProcessIoPriority( +PhGetProcessIsCFGuardEnabled( _In_ HANDLE ProcessHandle, - _In_ IO_PRIORITY_HINT IoPriority + _Out_ PBOOLEAN IsControlFlowGuardEnabled ) { - return NtSetInformationProcess( + NTSTATUS status; + PROCESS_MITIGATION_POLICY_INFORMATION policyInfo; + + policyInfo.Policy = ProcessControlFlowGuardPolicy; + + status = NtQueryInformationProcess( ProcessHandle, - ProcessIoPriority, - &IoPriority, - sizeof(IO_PRIORITY_HINT) + ProcessMitigationPolicy, + &policyInfo, + sizeof(PROCESS_MITIGATION_POLICY_INFORMATION), + NULL ); + + if (!NT_SUCCESS(status)) + return status; + + *IsControlFlowGuardEnabled = !!policyInfo.ControlFlowGuardPolicy.EnableControlFlowGuard; + + return status; } /** @@ -485,6 +566,49 @@ PhGetThreadBasicInformation( ); } +FORCEINLINE +NTSTATUS +PhGetThreadBasePriority( + _In_ HANDLE ThreadHandle, + _Out_ PLONG Increment + ) +{ + NTSTATUS status; + THREAD_BASIC_INFORMATION basicInfo; + + status = PhGetThreadBasicInformation(ThreadHandle, &basicInfo); + + if (NT_SUCCESS(status)) + { + *Increment = basicInfo.BasePriority; + } + + return status; + + //return NtQueryInformationThread( + // ThreadHandle, + // ThreadBasePriority, + // Increment, + // sizeof(LONG), + // NULL + // ); +} + +FORCEINLINE +NTSTATUS +PhSetThreadBasePriority( + _In_ HANDLE ThreadHandle, + _In_ LONG Increment + ) +{ + return NtSetInformationThread( + ThreadHandle, + ThreadBasePriority, + &Increment, + sizeof(LONG) + ); +} + /** * Gets a thread's I/O priority. * @@ -508,6 +632,28 @@ PhGetThreadIoPriority( ); } +/** + * Sets a thread's I/O priority. + * + * \param ThreadHandle A handle to a thread. The handle must have THREAD_SET_LIMITED_INFORMATION + * access. + * \param IoPriority The new I/O priority. + */ +FORCEINLINE +NTSTATUS +PhSetThreadIoPriority( + _In_ HANDLE ThreadHandle, + _In_ IO_PRIORITY_HINT IoPriority + ) +{ + return NtSetInformationThread( + ThreadHandle, + ThreadIoPriority, + &IoPriority, + sizeof(IO_PRIORITY_HINT) + ); +} + /** * Gets a thread's page priority. * @@ -541,6 +687,26 @@ PhGetThreadPagePriority( return status; } +FORCEINLINE +NTSTATUS +PhSetThreadPagePriority( + _In_ HANDLE ThreadHandle, + _In_ ULONG PagePriority + ) +{ + PAGE_PRIORITY_INFORMATION pagePriorityInfo; + + pagePriorityInfo.PagePriority = PagePriority; + + return NtSetInformationThread( + ThreadHandle, + ThreadPagePriority, + &pagePriorityInfo, + sizeof(PAGE_PRIORITY_INFORMATION) + ); +} + + /** * Gets a thread's cycle count. * @@ -596,28 +762,6 @@ PhSetThreadAffinityMask( ); } -/** - * Sets a thread's I/O priority. - * - * \param ThreadHandle A handle to a thread. The handle must have THREAD_SET_LIMITED_INFORMATION - * access. - * \param IoPriority The new I/O priority. - */ -FORCEINLINE -NTSTATUS -PhSetThreadIoPriority( - _In_ HANDLE ThreadHandle, - _In_ IO_PRIORITY_HINT IoPriority - ) -{ - return NtSetInformationThread( - ThreadHandle, - ThreadIoPriority, - &IoPriority, - sizeof(IO_PRIORITY_HINT) - ); -} - FORCEINLINE NTSTATUS PhGetJobBasicAndIoAccounting( diff --git a/phlib/native.c b/phlib/native.c index dadad9f0eaaf..ac6fa54a6025 100644 --- a/phlib/native.c +++ b/phlib/native.c @@ -6933,3 +6933,49 @@ NTSTATUS PhImpersonateClientOfNamedPipe( 0 ); } + +NTSTATUS PhGetThreadName( + _In_ HANDLE ThreadHandle, + _Out_ PPH_STRING *ThreadName + ) +{ + NTSTATUS status; + PTHREAD_NAME_INFORMATION buffer; + ULONG bufferSize; + ULONG returnLength; + + bufferSize = 0x100; + buffer = PhAllocate(bufferSize); + + status = NtQueryInformationThread( + ThreadHandle, + ThreadNameInformation, + buffer, + bufferSize, + &returnLength + ); + + if (status == STATUS_BUFFER_OVERFLOW) + { + PhFree(buffer); + bufferSize = returnLength; + buffer = PhAllocate(bufferSize); + + status = NtQueryInformationThread( + ThreadHandle, + ThreadNameInformation, + buffer, + bufferSize, + &returnLength + ); + } + + if (NT_SUCCESS(status)) + { + *ThreadName = PhCreateStringFromUnicodeString(&buffer->ThreadName); + } + + PhFree(buffer); + + return status; +} From 491e9b1b14581ea935cfb5d14a1e7fc3621bf219 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 25 Jan 2018 14:05:41 +1100 Subject: [PATCH 0717/2058] Improve TreeListCustomColorsEnable setting --- ProcessHacker/mainwnd.c | 1 + ProcessHacker/settings.c | 1 + phlib/include/treenew.h | 1 + phlib/include/treenewp.h | 7 +++++-- phlib/treenew.c | 35 +++++++++++------------------------ 5 files changed, 19 insertions(+), 26 deletions(-) diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index b6f77f729c88..b574cb535fdf 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -420,6 +420,7 @@ VOID PhMwpInitializeControls( if (treelistCustomColors) { + treelistCreateParams.TextColor = PhGetIntegerSetting(L"TreeListCustomColorText"); treelistCreateParams.FocusColor = PhGetIntegerSetting(L"TreeListCustomColorFocus"); treelistCreateParams.SelectionColor = PhGetIntegerSetting(L"TreeListCustomColorSelection"); } diff --git a/ProcessHacker/settings.c b/ProcessHacker/settings.c index 380c07aa77fe..319d88ebd3f1 100644 --- a/ProcessHacker/settings.c +++ b/ProcessHacker/settings.c @@ -166,6 +166,7 @@ VOID PhAddDefaultSettings( PhpAddStringSetting(L"TokenPrivilegesListViewColumns", L""); PhpAddIntegerSetting(L"TreeListBorderEnable", L"0"); PhpAddIntegerSetting(L"TreeListCustomColorsEnable", L"0"); + PhpAddIntegerSetting(L"TreeListCustomColorText", L"0"); PhpAddIntegerSetting(L"TreeListCustomColorFocus", L"0"); PhpAddIntegerSetting(L"TreeListCustomColorSelection", L"0"); PhpAddIntegerSetting(L"UpdateInterval", L"3e8"); // 1000ms diff --git a/phlib/include/treenew.h b/phlib/include/treenew.h index 3eac52a3b170..61d08081b1c2 100644 --- a/phlib/include/treenew.h +++ b/phlib/include/treenew.h @@ -12,6 +12,7 @@ extern "C" { typedef struct _PH_TREENEW_CREATEPARAMS { + COLORREF TextColor; COLORREF FocusColor; COLORREF SelectionColor; // Add new fields here. diff --git a/phlib/include/treenewp.h b/phlib/include/treenewp.h index a90c1695cdab..21fcfb9b95b1 100644 --- a/phlib/include/treenewp.h +++ b/phlib/include/treenewp.h @@ -136,8 +136,11 @@ typedef struct _PH_TREENEW_CONTEXT HTHEME ThemeData; COLORREF DefaultBackColor; COLORREF DefaultForeColor; - HBRUSH CustomFocusBrush; - HBRUSH CustomSelectedBrush; + + // User configurable colors. + COLORREF CustomTextColor; + COLORREF CustomFocusColor; + COLORREF CustomSelectedColor; LONG SystemBorderX; LONG SystemBorderY; diff --git a/phlib/treenew.c b/phlib/treenew.c index b2bc4aa95545..b89d582c2618 100644 --- a/phlib/treenew.c +++ b/phlib/treenew.c @@ -404,14 +404,6 @@ VOID PhTnpDestroyTreeNewContext( if (Context->SuspendUpdateRegion) DeleteObject(Context->SuspendUpdateRegion); - if (Context->CustomColors) - { - if (Context->CustomFocusBrush) - DeleteObject(Context->CustomFocusBrush); - if (Context->CustomSelectedBrush) - DeleteObject(Context->CustomSelectedBrush); - } - PhFree(Context); } @@ -444,22 +436,15 @@ BOOLEAN PhTnpOnCreate( if (Context->Style & TN_STYLE_CUSTOM_COLORS) { + Context->CustomTextColor = createParamaters->TextColor ? createParamaters->TextColor : RGB(0xff, 0xff, 0xff); + Context->CustomFocusColor = createParamaters->FocusColor ? createParamaters->FocusColor : RGB(0x0, 0x0, 0xff); + Context->CustomSelectedColor = createParamaters->SelectionColor ? createParamaters->SelectionColor : RGB(0x0, 0x0, 0x80); Context->CustomColors = TRUE; - - if (createParamaters->FocusColor) - Context->CustomFocusBrush = CreateSolidBrush(createParamaters->FocusColor); - else - Context->CustomFocusBrush = CreateSolidBrush(RGB(0, 0, 0xff)); - - if (createParamaters->SelectionColor) - Context->CustomSelectedBrush = CreateSolidBrush(createParamaters->FocusColor); - else - Context->CustomSelectedBrush = CreateSolidBrush(RGB(0, 0, 0x80)); } else { - Context->CustomFocusBrush = GetSysColorBrush(COLOR_HOTLIGHT); - Context->CustomSelectedBrush = GetSysColorBrush(COLOR_HIGHLIGHT); + Context->CustomFocusColor = GetSysColor(COLOR_HOTLIGHT); + Context->CustomSelectedColor = GetSysColor(COLOR_HIGHLIGHT); } if (!(Context->FixedHeaderHandle = CreateWindow( @@ -5114,15 +5099,17 @@ VOID PhTnpPaint( case TREIS_SELECTED: case TREIS_SELECTEDNOTFOCUS: { - SetTextColor(hdc, RGB(0xff, 0xff, 0xff)); - backBrush = Context->CustomSelectedBrush; + SetTextColor(hdc, Context->CustomTextColor); + SetDCBrushColor(hdc, Context->CustomSelectedColor); + backBrush = GetStockObject(DC_BRUSH); } break; case TREIS_HOT: case TREIS_HOTSELECTED: { - SetTextColor(hdc, RGB(0xff, 0xff, 0xff)); - backBrush = Context->CustomFocusBrush; + SetTextColor(hdc, Context->CustomTextColor); + SetDCBrushColor(hdc, Context->CustomFocusColor); + backBrush = GetStockObject(DC_BRUSH); } break; default: From 7f54bac9b7246f8a410d5ebe3807a899da3ed6d1 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 25 Jan 2018 19:28:59 +1100 Subject: [PATCH 0718/2058] Remove unused code, Update copyright text --- phlib/treenew.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/phlib/treenew.c b/phlib/treenew.c index b89d582c2618..cd85bfff576d 100644 --- a/phlib/treenew.c +++ b/phlib/treenew.c @@ -3,7 +3,7 @@ * tree new (tree list control) * * Copyright (C) 2011-2016 wj32 - * Copyright (C) 2017 dmex + * Copyright (C) 2017-2018 dmex * * This file is part of Process Hacker. * @@ -4984,7 +4984,6 @@ VOID PhTnpPaint( LONG normalUpdateRightIndex; LONG normalTotalX; RECT cellRect; - HBRUSH backBrush; HRGN oldClipRegion; PhTnpInitializeThemeData(Context); @@ -5074,7 +5073,6 @@ VOID PhTnpPaint( PhTnpPrepareRowForDraw(Context, hdc, node); - if (node->Selected) { if (i == Context->HotNodeIndex) @@ -5101,7 +5099,6 @@ VOID PhTnpPaint( { SetTextColor(hdc, Context->CustomTextColor); SetDCBrushColor(hdc, Context->CustomSelectedColor); - backBrush = GetStockObject(DC_BRUSH); } break; case TREIS_HOT: @@ -5109,14 +5106,12 @@ VOID PhTnpPaint( { SetTextColor(hdc, Context->CustomTextColor); SetDCBrushColor(hdc, Context->CustomFocusColor); - backBrush = GetStockObject(DC_BRUSH); } break; default: { SetTextColor(hdc, node->s.DrawForeColor); SetDCBrushColor(hdc, node->s.DrawBackColor); - backBrush = GetStockObject(DC_BRUSH); } break; } @@ -5125,10 +5120,9 @@ VOID PhTnpPaint( { SetTextColor(hdc, node->s.DrawForeColor); SetDCBrushColor(hdc, node->s.DrawBackColor); - backBrush = GetStockObject(DC_BRUSH); } - FillRect(hdc, &rowRect, backBrush); + FillRect(hdc, &rowRect, GetStockObject(DC_BRUSH)); if (!Context->CustomColors && Context->ThemeHasItemBackground) { From bf863e4d6bbb6bc03742f3aa628ff3e05ad4f14f Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 25 Jan 2018 20:38:14 +1100 Subject: [PATCH 0719/2058] Update native API wrapper functions --- phlib/include/phnativeinl.h | 97 ++++++++++++++++++++++++++++++++++++- 1 file changed, 96 insertions(+), 1 deletion(-) diff --git a/phlib/include/phnativeinl.h b/phlib/include/phnativeinl.h index dc746e769f92..c3bc53598e63 100644 --- a/phlib/include/phnativeinl.h +++ b/phlib/include/phnativeinl.h @@ -543,6 +543,22 @@ PhGetProcessIsCFGuardEnabled( return status; } +FORCEINLINE +NTSTATUS +PhGetProcessHandleCount( + _In_ HANDLE ProcessHandle, + _Out_ PPROCESS_HANDLE_INFORMATION HandleInfo + ) +{ + return NtQueryInformationProcess( + ProcessHandle, + ProcessHandleCount, + HandleInfo, + sizeof(PROCESS_HANDLE_INFORMATION), + NULL + ); +} + /** * Gets basic information for a thread. * @@ -594,6 +610,22 @@ PhGetThreadBasePriority( // ); } +FORCEINLINE +NTSTATUS +PhGetThreadStartAddress( + _In_ HANDLE ThreadHandle, + _Out_ PVOID *StartAddress + ) +{ + return NtQueryInformationThread( + ThreadHandle, + ThreadQuerySetWin32StartAddress, + StartAddress, + sizeof(PVOID), + NULL + ); +} + FORCEINLINE NTSTATUS PhSetThreadBasePriority( @@ -706,7 +738,6 @@ PhSetThreadPagePriority( ); } - /** * Gets a thread's cycle count. * @@ -740,6 +771,70 @@ PhGetThreadCycleTime( return status; } +FORCEINLINE +NTSTATUS +PhGetThreadIdealProcessor( + _In_ HANDLE ThreadHandle, + _Out_ PPROCESSOR_NUMBER ProcessorNumber + ) +{ + return NtQueryInformationThread( + ThreadHandle, + ThreadIdealProcessorEx, + ProcessorNumber, + sizeof(PROCESSOR_NUMBER), + NULL + ); +} + +FORCEINLINE +NTSTATUS +PhGetThreadSuspendCount( + _In_ HANDLE ThreadHandle, + _Out_ PULONG SuspendCount + ) +{ + return NtQueryInformationThread( + ThreadHandle, + ThreadSuspendCount, + SuspendCount, + sizeof(ULONG), + NULL + ); +} + +FORCEINLINE +NTSTATUS +PhGetThreadLastSystemCall( + _In_ HANDLE ThreadHandle, + _Out_ PTHREAD_LAST_SYSCALL_INFORMATION LastSystemCall + ) +{ + return NtQueryInformationThread( + ThreadHandle, + ThreadLastSystemCall, + LastSystemCall, + RTL_SIZEOF_THROUGH_FIELD(THREAD_LAST_SYSCALL_INFORMATION, Pad), // HACK: Win7 requires exact size. + NULL + ); +} + +FORCEINLINE +NTSTATUS +PhGetThreadWow64Context( + _In_ HANDLE ThreadHandle, + _Out_ PWOW64_CONTEXT Context + ) +{ + return NtQueryInformationThread( + ThreadHandle, + ThreadWow64Context, + Context, + sizeof(WOW64_CONTEXT), + NULL + ); +} + /** * Sets a thread's affinity mask. * From 3ffb71ed1949ac56faf1be87fc53e5d41ef98903 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 25 Jan 2018 23:17:21 +1100 Subject: [PATCH 0720/2058] Update native API wrapper functions --- ProcessHacker/actions.c | 30 ++----- ProcessHacker/anawait.c | 16 +--- ProcessHacker/cmdmode.c | 13 ++- ProcessHacker/hidnproc.c | 20 +---- ProcessHacker/main.c | 163 ++++++++++++++++++++++++++--------- ProcessHacker/mwpgproc.c | 8 +- ProcessHacker/phsvc/svcapi.c | 3 +- ProcessHacker/procprv.c | 8 +- ProcessHacker/proctree.c | 7 +- ProcessHacker/prpgstat.c | 8 +- ProcessHacker/prpgthrd.c | 11 +-- ProcessHacker/thrdprv.c | 8 +- phlib/include/phutil.h | 1 + phlib/symprv.c | 21 +---- phlib/util.c | 21 ++--- phlib/workqueue.c | 10 +-- phnt/include/ntpsapi.h | 8 +- 17 files changed, 177 insertions(+), 179 deletions(-) diff --git a/ProcessHacker/actions.c b/ProcessHacker/actions.c index 2e905a3cf5a3..4551bb8a50d9 100644 --- a/ProcessHacker/actions.c +++ b/ProcessHacker/actions.c @@ -1528,12 +1528,7 @@ BOOLEAN PhUiReduceWorkingSetProcesses( quotaLimits.MinimumWorkingSetSize = -1; quotaLimits.MaximumWorkingSetSize = -1; - status = NtSetInformationProcess( - processHandle, - ProcessQuotaLimits, - "aLimits, - sizeof(QUOTA_LIMITS) - ); + status = PhSetProcessQuotaLimits(processHandle, quotaLimits); NtClose(processHandle); } @@ -1754,12 +1749,7 @@ BOOLEAN PhUiSetPagePriorityProcess( { if (Process->ProcessId != SYSTEM_PROCESS_ID) { - status = NtSetInformationProcess( - processHandle, - ProcessPagePriority, - &PagePriority, - sizeof(ULONG) - ); + status = PhSetProcessPagePriority(processHandle, PagePriority); } else { @@ -1794,7 +1784,6 @@ BOOLEAN PhUiSetPriorityProcesses( { NTSTATUS status; HANDLE processHandle; - PROCESS_PRIORITY_CLASS priorityClass; if (NT_SUCCESS(status = PhOpenProcess( &processHandle, @@ -1804,9 +1793,12 @@ BOOLEAN PhUiSetPriorityProcesses( { if (Processes[i]->ProcessId != SYSTEM_PROCESS_ID) { + PROCESS_PRIORITY_CLASS priorityClass; + priorityClass.Foreground = FALSE; priorityClass.PriorityClass = (UCHAR)PriorityClass; - status = NtSetInformationProcess(processHandle, ProcessPriorityClass, &priorityClass, sizeof(PROCESS_PRIORITY_CLASS)); + + status = PhSetProcessPriority(processHandle, priorityClass); } else { @@ -2519,7 +2511,7 @@ BOOLEAN PhUiSetPriorityThread( Thread->ThreadId ))) { - status = NtSetInformationThread(threadHandle, ThreadBasePriority, &Increment, sizeof(LONG)); + status = PhSetThreadBasePriority(threadHandle, Increment); NtClose(threadHandle); } @@ -2600,12 +2592,8 @@ BOOLEAN PhUiSetPagePriorityThread( Thread->ThreadId ))) { - status = NtSetInformationThread( - threadHandle, - ThreadPagePriority, - &PagePriority, - sizeof(ULONG) - ); + status = PhSetThreadPagePriority(threadHandle, PagePriority); + NtClose(threadHandle); } diff --git a/ProcessHacker/anawait.c b/ProcessHacker/anawait.c index 6e8d9f0f957b..93bb2d675458 100644 --- a/ProcessHacker/anawait.c +++ b/ProcessHacker/anawait.c @@ -213,13 +213,7 @@ VOID PhpAnalyzeWaitPassive( return; } - if (!NT_SUCCESS(status = NtQueryInformationThread( - threadHandle, - ThreadLastSystemCall, - &lastSystemCall, - sizeof(THREAD_LAST_SYSCALL_INFORMATION), - NULL - ))) + if (!NT_SUCCESS(status = PhGetThreadLastSystemCall(threadHandle, &lastSystemCall))) { NtClose(threadHandle); PhShowStatus(hWnd, L"Unable to determine whether the thread is waiting.", status, 0); @@ -715,13 +709,7 @@ static VOID PhpGetThreadLastSystemCallNumber( { THREAD_LAST_SYSCALL_INFORMATION lastSystemCall; - if (NT_SUCCESS(NtQueryInformationThread( - ThreadHandle, - ThreadLastSystemCall, - &lastSystemCall, - sizeof(THREAD_LAST_SYSCALL_INFORMATION), - NULL - ))) + if (NT_SUCCESS(PhGetThreadLastSystemCall(ThreadHandle, &lastSystemCall))) { *LastSystemCallNumber = lastSystemCall.SystemCallNumber; } diff --git a/ProcessHacker/cmdmode.c b/ProcessHacker/cmdmode.c index 9ea771073c32..1d7cb4f3761e 100644 --- a/ProcessHacker/cmdmode.c +++ b/ProcessHacker/cmdmode.c @@ -174,9 +174,12 @@ NTSTATUS PhCommandModeStart( if (NT_SUCCESS(status = PhOpenProcessPublic(&processHandle, PROCESS_SET_INFORMATION, processId))) { PROCESS_PRIORITY_CLASS priorityClass; + priorityClass.Foreground = FALSE; priorityClass.PriorityClass = priority; - status = NtSetInformationProcess(processHandle, ProcessPriorityClass, &priorityClass, sizeof(PROCESS_PRIORITY_CLASS)); + + status = PhSetProcessPriority(processHandle, priorityClass); + NtClose(processHandle); } } @@ -217,12 +220,8 @@ NTSTATUS PhCommandModeStart( if (NT_SUCCESS(status = PhOpenProcessPublic(&processHandle, PROCESS_SET_INFORMATION, processId))) { - status = NtSetInformationProcess( - processHandle, - ProcessPagePriority, - &pagePriority, - sizeof(ULONG) - ); + status = PhSetProcessPagePriority(processHandle, pagePriority); + NtClose(processHandle); } } diff --git a/ProcessHacker/hidnproc.c b/ProcessHacker/hidnproc.c index 7744af80173f..e2398510b385 100644 --- a/ProcessHacker/hidnproc.c +++ b/ProcessHacker/hidnproc.c @@ -551,7 +551,7 @@ static PPH_PROCESS_ITEM PhpCreateProcessItemForHiddenProcess( PROCESS_BASIC_INFORMATION basicInfo; KERNEL_USER_TIMES times; PROCESS_PRIORITY_CLASS priorityClass; - ULONG handleCount; + PROCESS_HANDLE_INFORMATION handleInfo; HANDLE processHandle2; if (Entry->Type == NormalProcess) @@ -636,26 +636,14 @@ static PPH_PROCESS_ITEM PhpCreateProcessItemForHiddenProcess( // TODO: Token information? - if (NT_SUCCESS(NtQueryInformationProcess( - processHandle, - ProcessPriorityClass, - &priorityClass, - sizeof(PROCESS_PRIORITY_CLASS), - NULL - ))) + if (NT_SUCCESS(PhGetProcessPriority(processHandle, &priorityClass))) { processItem->PriorityClass = priorityClass.PriorityClass; } - if (NT_SUCCESS(NtQueryInformationProcess( - processHandle, - ProcessHandleCount, - &handleCount, - sizeof(ULONG), - NULL - ))) + if (NT_SUCCESS(PhGetProcessHandleCount(processHandle, &handleInfo))) { - processItem->NumberOfHandles = handleCount; + processItem->NumberOfHandles = handleInfo.HandleCount; } } diff --git a/ProcessHacker/main.c b/ProcessHacker/main.c index 5386cd7ae90c..0acc622d12f4 100644 --- a/ProcessHacker/main.c +++ b/ProcessHacker/main.c @@ -75,6 +75,14 @@ VOID PhpEnablePrivileges( VOID ); +BOOLEAN PhInitializeMitigationPolicy( + VOID + ); + +VOID PhInitializeRestartPolicy( + VOID + ); + PPH_STRING PhApplicationDirectory = NULL; PPH_STRING PhApplicationFileName = NULL; PHAPPAPI HFONT PhApplicationFont = NULL; @@ -113,6 +121,8 @@ INT WINAPI wWinMain( if (!NT_SUCCESS(PhInitializePhLibEx(ULONG_MAX, Instance, 0, 0))) return 1; + if (PhInitializeMitigationPolicy()) + return 0; if (!PhInitializeAppSystem()) return 1; @@ -234,6 +244,7 @@ INT WINAPI wWinMain( PhLoadPlugins(); } +#ifndef DEBUG if (WindowsVersion >= WINDOWS_10) { PROCESS_MITIGATION_POLICY_INFORMATION policyInfo; @@ -246,6 +257,7 @@ INT WINAPI wWinMain( NtSetInformationProcess(NtCurrentProcess(), ProcessMitigationPolicy, &policyInfo, sizeof(PROCESS_MITIGATION_POLICY_INFORMATION)); } +#endif if (PhStartupParameters.PhSvc) { @@ -285,7 +297,7 @@ INT WINAPI wWinMain( PhDereferenceObject(objectName); } - // Set priority. + // Set the default priority. { PROCESS_PRIORITY_CLASS priorityClass; @@ -295,9 +307,12 @@ INT WINAPI wWinMain( if (PhStartupParameters.PriorityClass != 0) priorityClass.PriorityClass = (UCHAR)PhStartupParameters.PriorityClass; - NtSetInformationProcess(NtCurrentProcess(), ProcessPriorityClass, &priorityClass, sizeof(PROCESS_PRIORITY_CLASS)); + PhSetProcessPriority(NtCurrentProcess(), priorityClass); } + // Create the restart policy. + PhInitializeRestartPolicy(); + if (!PhMainWndInitialization(CmdShow)) { PhShowError(NULL, L"Unable to initialize the main window."); @@ -517,19 +532,13 @@ VOID PhInitializeFont( } } -VOID PhInitializeMitigationPolicy( +BOOLEAN PhInitializeMitigationPolicy( VOID ) { - static PH_STRINGREF policyKeyName = PH_STRINGREF_INIT(L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\ProcessHacker.exe"); - static UNICODE_STRING policyKeyValue = RTL_CONSTANT_STRING(L"MitigationOptions"); - BOOLEAN policyKeyValid = FALSE; - HANDLE keyReadHandle; - HANDLE keyWriteHandle; - - if (WindowsVersion < WINDOWS_10 || !PhGetOwnTokenAttributes().Elevated) - return; - +#ifdef DEBUG + return FALSE; +#else #define DEFAULT_MITIGATION_POLICY_FLAGS \ (PROCESS_CREATION_MITIGATION_POLICY_HEAP_TERMINATE_ALWAYS_ON | \ PROCESS_CREATION_MITIGATION_POLICY_BOTTOM_UP_ASLR_ALWAYS_ON | \ @@ -540,43 +549,113 @@ VOID PhInitializeMitigationPolicy( PROCESS_CREATION_MITIGATION_POLICY_IMAGE_LOAD_NO_REMOTE_ALWAYS_ON | \ PROCESS_CREATION_MITIGATION_POLICY_IMAGE_LOAD_NO_LOW_LABEL_ALWAYS_ON) - if (NT_SUCCESS(PhOpenKey( - &keyReadHandle, - KEY_READ, - PH_KEY_LOCAL_MACHINE, - &policyKeyName, - 0 - ))) - { - if (PhQueryRegistryUlong64(keyReadHandle, L"MitigationOptions") == DEFAULT_MITIGATION_POLICY_FLAGS) - policyKeyValid = TRUE; + BOOLEAN success = FALSE; + PS_SYSTEM_DLL_INIT_BLOCK (*LdrSystemDllInitBlock_I); + HANDLE jobObjectHandle; + SIZE_T attributeListLength = 0; + PROCESS_INFORMATION processInfo = { 0 }; + STARTUPINFOEX startupInfo = { sizeof(STARTUPINFOEX) }; + JOBOBJECT_EXTENDED_LIMIT_INFORMATION extendedInfo = { 0 }; - NtClose(keyReadHandle); - } + if (WindowsVersion < WINDOWS_10_RS2) + return FALSE; - if (policyKeyValid) - return; + LdrSystemDllInitBlock_I = PhGetModuleProcAddress(L"ntdll.dll", "LdrSystemDllInitBlock"); + + if (!LdrSystemDllInitBlock_I) + return FALSE; + + if ((LdrSystemDllInitBlock_I->MitigationOptionsMap.Map[0] & DEFAULT_MITIGATION_POLICY_FLAGS) == DEFAULT_MITIGATION_POLICY_FLAGS) + return FALSE; + + if (!InitializeProcThreadAttributeList(NULL, 2, 0, &attributeListLength) && GetLastError() != ERROR_INSUFFICIENT_BUFFER) + return FALSE; + + startupInfo.lpAttributeList = PhAllocate(attributeListLength); + + if (!InitializeProcThreadAttributeList(startupInfo.lpAttributeList, 2, 0, &attributeListLength)) + goto CleanupExit; + + if (!UpdateProcThreadAttribute(startupInfo.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY, &(ULONG64){ DEFAULT_MITIGATION_POLICY_FLAGS }, sizeof(ULONG64), NULL, NULL)) + goto CleanupExit; - if (NT_SUCCESS(PhCreateKey( - &keyWriteHandle, - KEY_WRITE | DELETE, - PH_KEY_LOCAL_MACHINE, - &policyKeyName, - OBJ_OPENIF, - 0, + if (!NT_SUCCESS(NtCreateJobObject(&jobObjectHandle, JOB_OBJECT_ALL_ACCESS, NULL))) + goto CleanupExit; + + extendedInfo.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_BREAKAWAY_OK | JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK | JOB_OBJECT_LIMIT_ACTIVE_PROCESS; + extendedInfo.BasicLimitInformation.ActiveProcessLimit = 1; + + if (!NT_SUCCESS(NtSetInformationJobObject( + jobObjectHandle, + JobObjectExtendedLimitInformation, + &extendedInfo, + sizeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION) + ))) + goto CleanupExit; + + if (!UpdateProcThreadAttribute(startupInfo.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_JOB_LIST, &(HANDLE){ jobObjectHandle }, sizeof(HANDLE), NULL, NULL)) + goto CleanupExit; + + if (NT_SUCCESS(PhCreateProcessWin32Ex( + NtCurrentPeb()->ProcessParameters->ImagePathName.Buffer, + NtCurrentPeb()->ProcessParameters->CommandLine.Buffer, + NULL, + NULL, + &startupInfo.StartupInfo, + PH_CREATE_PROCESS_EXTENDED_STARTUPINFO | PH_CREATE_PROCESS_BREAKAWAY_FROM_JOB, + NULL, + NULL, + NULL, NULL ))) { - NtSetValueKey( - keyWriteHandle, - &policyKeyValue, - 0, - REG_QWORD, - &(ULONG64) { DEFAULT_MITIGATION_POLICY_FLAGS }, - sizeof(ULONG64) - ); - NtClose(keyWriteHandle); + success = TRUE; } + +CleanupExit: + + if (processInfo.hProcess) + NtClose(processInfo.hProcess); + + if (processInfo.hThread) + NtClose(processInfo.hThread); + + if (jobObjectHandle) + NtClose(jobObjectHandle); + + if (startupInfo.lpAttributeList) + { + DeleteProcThreadAttributeList(startupInfo.lpAttributeList); + PhFree(startupInfo.lpAttributeList); + } + + return success; +#endif +} + +VOID PhInitializeRestartPolicy( + VOID + ) +{ + PH_STRINGREF commandLine; + PH_STRINGREF fileName; + PH_STRINGREF arguments; + PPH_STRING argumentsString = NULL; + + // dmex: Restart process after a crash, hang, patch installation or + // after Windows 10 auto-restarts the machine due to an update. + + PhUnicodeStringToStringRef(&NtCurrentPeb()->ProcessParameters->CommandLine, &commandLine); + PhParseCommandLineFuzzy(&commandLine, &fileName, &arguments, NULL); + + if (arguments.Length > 0) + argumentsString = PhCreateString2(&arguments); + + // Note: Do not include the file name in the command line. + RegisterApplicationRestart(PhGetString(argumentsString), 0); + + if (argumentsString) + PhDereferenceObject(argumentsString); } NTSTATUS PhpReadSignature( diff --git a/ProcessHacker/mwpgproc.c b/ProcessHacker/mwpgproc.c index 0a5edbf21902..c437a25c22e4 100644 --- a/ProcessHacker/mwpgproc.c +++ b/ProcessHacker/mwpgproc.c @@ -399,13 +399,7 @@ VOID PhMwpSetProcessMenuPriorityChecks( { if (SetPriority) { - NtQueryInformationProcess( - processHandle, - ProcessPriorityClass, - &priorityClass, - sizeof(PROCESS_PRIORITY_CLASS), - NULL - ); + PhGetProcessPriority(processHandle, &priorityClass); } if (SetIoPriority) diff --git a/ProcessHacker/phsvc/svcapi.c b/ProcessHacker/phsvc/svcapi.c index 9aba65bd33e3..9f8ded087e2e 100644 --- a/ProcessHacker/phsvc/svcapi.c +++ b/ProcessHacker/phsvc/svcapi.c @@ -521,7 +521,8 @@ NTSTATUS PhSvcApiControlProcess( priorityClass.Foreground = FALSE; priorityClass.PriorityClass = (UCHAR)Payload->u.ControlProcess.i.Argument; - status = NtSetInformationProcess(processHandle, ProcessPriorityClass, &priorityClass, sizeof(PROCESS_PRIORITY_CLASS)); + + status = PhSetProcessPriority(processHandle, priorityClass); NtClose(processHandle); } diff --git a/ProcessHacker/procprv.c b/ProcessHacker/procprv.c index a7973d3403d1..29b54475c6dd 100644 --- a/ProcessHacker/procprv.c +++ b/ProcessHacker/procprv.c @@ -1499,13 +1499,7 @@ FORCEINLINE VOID PhpUpdateDynamicInfoProcessItem( { PROCESS_PRIORITY_CLASS priorityClass; - if (NT_SUCCESS(NtQueryInformationProcess( - ProcessItem->QueryHandle, - ProcessPriorityClass, - &priorityClass, - sizeof(PROCESS_PRIORITY_CLASS), - NULL - ))) + if (NT_SUCCESS(PhGetProcessPriority(ProcessItem->QueryHandle, &priorityClass))) { ProcessItem->PriorityClass = priorityClass.PriorityClass; } diff --git a/ProcessHacker/proctree.c b/ProcessHacker/proctree.c index 641dd4c0836e..6bb97961da4b 100644 --- a/ProcessHacker/proctree.c +++ b/ProcessHacker/proctree.c @@ -1040,12 +1040,9 @@ static VOID PhpUpdateProcessNodeQuotaLimits( { QUOTA_LIMITS quotaLimits; - if (ProcessNode->ProcessItem->QueryHandle && NT_SUCCESS(NtQueryInformationProcess( + if (ProcessNode->ProcessItem->QueryHandle && NT_SUCCESS(PhGetProcessQuotaLimits( ProcessNode->ProcessItem->QueryHandle, - ProcessQuotaLimits, - "aLimits, - sizeof(QUOTA_LIMITS), - NULL + "aLimits ))) { ProcessNode->MinimumWorkingSetSize = quotaLimits.MinimumWorkingSetSize; diff --git a/ProcessHacker/prpgstat.c b/ProcessHacker/prpgstat.c index 3f0f2f862649..18eecfc8b870 100644 --- a/ProcessHacker/prpgstat.c +++ b/ProcessHacker/prpgstat.c @@ -105,13 +105,7 @@ VOID PhpUpdateProcessStatistics( ULONG64 cycleTime; PROCESS_HANDLE_INFORMATION handleInfo; - if (NT_SUCCESS(NtQueryInformationProcess( - ProcessItem->QueryHandle, - ProcessHandleCount, - &handleInfo, - sizeof(PROCESS_HANDLE_INFORMATION), - NULL - ))) + if (NT_SUCCESS(PhGetProcessHandleCount(ProcessItem->QueryHandle, &handleInfo))) { peakHandles = PhaFormatUInt64(handleInfo.HandleCountHighWatermark, TRUE); } diff --git a/ProcessHacker/prpgthrd.c b/ProcessHacker/prpgthrd.c index 68565ddee871..93bfd1381110 100644 --- a/ProcessHacker/prpgthrd.c +++ b/ProcessHacker/prpgthrd.c @@ -148,14 +148,9 @@ VOID PhpInitializeThreadMenu( Threads[0]->ThreadId ))) { - THREAD_BASIC_INFORMATION basicInfo; HANDLE tokenHandle; - if (NT_SUCCESS(PhGetThreadBasicInformation(threadHandle, &basicInfo))) - { - threadPriority = basicInfo.BasePriority; - } - + PhGetThreadBasePriority(threadHandle, &threadPriority); PhGetThreadIoPriority(threadHandle, &ioPriority); PhGetThreadPagePriority(threadHandle, &pagePriority); @@ -376,7 +371,7 @@ VOID PhpUpdateThreadDetails( pagePriority = PhPagePriorityNames[pagePriorityInteger]; } - if (NT_SUCCESS(NtQueryInformationThread(threadHandle, ThreadIdealProcessorEx, &idealProcessorNumber, sizeof(PROCESSOR_NUMBER), NULL))) + if (NT_SUCCESS(PhGetThreadIdealProcessor(threadHandle, &idealProcessorNumber))) { PH_FORMAT format[3]; @@ -386,7 +381,7 @@ VOID PhpUpdateThreadDetails( PhFormatToBuffer(format, 3, idealProcessor, sizeof(idealProcessor), NULL); } - if (threadItem->WaitReason == Suspended && NT_SUCCESS(NtQueryInformationThread(threadHandle, ThreadSuspendCount, &suspendCount, sizeof(ULONG), NULL))) + if (threadItem->WaitReason == Suspended && NT_SUCCESS(PhGetThreadSuspendCount(threadHandle, &suspendCount))) { PH_FORMAT format[4]; diff --git a/ProcessHacker/thrdprv.c b/ProcessHacker/thrdprv.c index 933999061a41..4e34dd964f5b 100644 --- a/ProcessHacker/thrdprv.c +++ b/ProcessHacker/thrdprv.c @@ -912,13 +912,7 @@ VOID PhpThreadProviderUpdate( if (threadItem->ThreadHandle) { - NtQueryInformationThread( - threadItem->ThreadHandle, - ThreadQuerySetWin32StartAddress, - &startAddress, - sizeof(PVOID), - NULL - ); + PhGetThreadStartAddress(threadItem->ThreadHandle, &startAddress); } if (!startAddress) diff --git a/phlib/include/phutil.h b/phlib/include/phutil.h index 38027644c8e1..a135ac89f21b 100644 --- a/phlib/include/phutil.h +++ b/phlib/include/phutil.h @@ -660,6 +660,7 @@ typedef struct _PH_CREATE_PROCESS_INFO #define PH_CREATE_PROCESS_SUSPENDED 0x4 #define PH_CREATE_PROCESS_BREAKAWAY_FROM_JOB 0x8 #define PH_CREATE_PROCESS_NEW_CONSOLE 0x10 +#define PH_CREATE_PROCESS_EXTENDED_STARTUPINFO 0x20 PHLIBAPI NTSTATUS diff --git a/phlib/symprv.c b/phlib/symprv.c index ac3a4da3045e..04bb84099eec 100644 --- a/phlib/symprv.c +++ b/phlib/symprv.c @@ -1579,8 +1579,7 @@ NTSTATUS PhWalkThreadStack( { PVOID startAddress; - if (NT_SUCCESS(NtQueryInformationThread(ThreadHandle, ThreadQuerySetWin32StartAddress, - &startAddress, sizeof(PVOID), NULL))) + if (NT_SUCCESS(PhGetThreadStartAddress(ThreadHandle, &startAddress))) { if ((ULONG_PTR)startAddress > PhSystemBasicInformation.MaximumUserModeAddress) isSystemThread = TRUE; @@ -1637,10 +1636,7 @@ NTSTATUS PhWalkThreadStack( context.ContextFlags = CONTEXT_ALL; - if (!NT_SUCCESS(status = NtGetContextThread( - ThreadHandle, - &context - ))) + if (!NT_SUCCESS(status = NtGetContextThread(ThreadHandle, &context))) goto SkipAmd64Stack; memset(&stackFrame, 0, sizeof(STACKFRAME64)); @@ -1693,23 +1689,14 @@ NTSTATUS PhWalkThreadStack( context.ContextFlags = CONTEXT_ALL; - if (!NT_SUCCESS(status = NtGetContextThread( - ThreadHandle, - &context - ))) + if (!NT_SUCCESS(status = NtGetContextThread(ThreadHandle, &context))) goto SkipI386Stack; #else WOW64_CONTEXT context; context.ContextFlags = WOW64_CONTEXT_ALL; - if (!NT_SUCCESS(status = NtQueryInformationThread( - ThreadHandle, - ThreadWow64Context, - &context, - sizeof(WOW64_CONTEXT), - NULL - ))) + if (!NT_SUCCESS(status = PhGetThreadWow64Context(ThreadHandle, &context))) goto SkipI386Stack; #endif diff --git a/phlib/util.c b/phlib/util.c index 2cf209f74456..42dd323c6288 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -2512,7 +2512,8 @@ static const PH_FLAG_MAPPING PhpCreateProcessMappings[] = { PH_CREATE_PROCESS_UNICODE_ENVIRONMENT, CREATE_UNICODE_ENVIRONMENT }, { PH_CREATE_PROCESS_SUSPENDED, CREATE_SUSPENDED }, { PH_CREATE_PROCESS_BREAKAWAY_FROM_JOB, CREATE_BREAKAWAY_FROM_JOB }, - { PH_CREATE_PROCESS_NEW_CONSOLE, CREATE_NEW_CONSOLE } + { PH_CREATE_PROCESS_NEW_CONSOLE, CREATE_NEW_CONSOLE }, + { PH_CREATE_PROCESS_EXTENDED_STARTUPINFO, EXTENDED_STARTUPINFO_PRESENT } }; FORCEINLINE VOID PhpConvertProcessInformation( @@ -2607,19 +2608,16 @@ NTSTATUS PhCreateProcessWin32Ex( newFlags = 0; PhMapFlags1(&newFlags, Flags, PhpCreateProcessMappings, sizeof(PhpCreateProcessMappings) / sizeof(PH_FLAG_MAPPING)); - if (StartupInfo) - { - startupInfo = *StartupInfo; - } - else + if (!StartupInfo) { memset(&startupInfo, 0, sizeof(STARTUPINFO)); startupInfo.cb = sizeof(STARTUPINFO); } - if (!TokenHandle) + if (TokenHandle) { - if (CreateProcess( + if (CreateProcessAsUser( + TokenHandle, PhGetString(fileName), PhGetString(commandLine), NULL, @@ -2628,7 +2626,7 @@ NTSTATUS PhCreateProcessWin32Ex( newFlags, Environment, CurrentDirectory, - &startupInfo, + StartupInfo ? StartupInfo : &startupInfo, &processInfo )) status = STATUS_SUCCESS; @@ -2637,8 +2635,7 @@ NTSTATUS PhCreateProcessWin32Ex( } else { - if (CreateProcessAsUser( - TokenHandle, + if (CreateProcess( PhGetString(fileName), PhGetString(commandLine), NULL, @@ -2647,7 +2644,7 @@ NTSTATUS PhCreateProcessWin32Ex( newFlags, Environment, CurrentDirectory, - &startupInfo, + StartupInfo ? StartupInfo : &startupInfo, &processInfo )) status = STATUS_SUCCESS; diff --git a/phlib/workqueue.c b/phlib/workqueue.c index 2ccc3495e626..f0e364a9960d 100644 --- a/phlib/workqueue.c +++ b/phlib/workqueue.c @@ -24,6 +24,7 @@ #include #include +#include #include @@ -260,8 +261,7 @@ VOID PhpUpdateWorkQueueEnvironment( increment = NewEnvironment->BasePriority; - if (NT_SUCCESS(NtSetInformationThread(NtCurrentThread(), ThreadBasePriority, - &increment, sizeof(LONG)))) + if (NT_SUCCESS(PhSetThreadBasePriority(NtCurrentThread(), increment))) { CurrentEnvironment->BasePriority = NewEnvironment->BasePriority; } @@ -273,8 +273,7 @@ VOID PhpUpdateWorkQueueEnvironment( ioPriority = NewEnvironment->IoPriority; - if (NT_SUCCESS(NtSetInformationThread(NtCurrentThread(), ThreadIoPriority, - &ioPriority, sizeof(IO_PRIORITY_HINT)))) + if (NT_SUCCESS(PhSetThreadIoPriority(NtCurrentThread(), ioPriority))) { CurrentEnvironment->IoPriority = NewEnvironment->IoPriority; } @@ -286,8 +285,7 @@ VOID PhpUpdateWorkQueueEnvironment( pagePriority = NewEnvironment->PagePriority; - if (NT_SUCCESS(NtSetInformationThread(NtCurrentThread(), ThreadPagePriority, - &pagePriority, sizeof(ULONG)))) + if (NT_SUCCESS(PhSetThreadPagePriority(NtCurrentThread(), pagePriority))) { CurrentEnvironment->PagePriority = NewEnvironment->PagePriority; } diff --git a/phnt/include/ntpsapi.h b/phnt/include/ntpsapi.h index 513505172b0b..e134eb368b0c 100644 --- a/phnt/include/ntpsapi.h +++ b/phnt/include/ntpsapi.h @@ -809,8 +809,12 @@ typedef struct _THREAD_LAST_SYSCALL_INFORMATION { PVOID FirstArgument; USHORT SystemCallNumber; - //USHORT Reserved; // since REDSTONE2 - //ULONG64 WaitTime; +#ifdef WIN64 + USHORT Pad[0x3]; // since REDSTONE2 +#else + USHORT Pad[0x1]; // since REDSTONE2 +#endif + ULONG64 WaitTime; } THREAD_LAST_SYSCALL_INFORMATION, *PTHREAD_LAST_SYSCALL_INFORMATION; // private From e65de2e434bff8072d12e1d3d6c1f166b222c5bc Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 25 Jan 2018 23:17:45 +1100 Subject: [PATCH 0721/2058] HardwareDevices: Fix tabspace --- plugins/HardwareDevices/diskdetails.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/HardwareDevices/diskdetails.c b/plugins/HardwareDevices/diskdetails.c index a6912b73bb20..1165e41be5ec 100644 --- a/plugins/HardwareDevices/diskdetails.c +++ b/plugins/HardwareDevices/diskdetails.c @@ -169,20 +169,20 @@ VOID DiskDriveQuerySmart( MAXINT, SmartAttributeGetText(attribute->AttributeId), IntToPtr(attribute->AttributeId) - ); + ); PhSetListViewSubItem( Context->ListViewHandle, lvItemIndex, 1, PhaFormatString(L"%lu", attribute->CurrentValue)->Buffer - ); + ); PhSetListViewSubItem( Context->ListViewHandle, lvItemIndex, 2, PhaFormatString(L"%lu", attribute->WorstValue)->Buffer - ); + ); if (attribute->RawValue) { @@ -191,7 +191,7 @@ VOID DiskDriveQuerySmart( lvItemIndex, 3, PhaFormatString(L"%lu", attribute->RawValue)->Buffer - ); + ); } PhFree(attribute); From 8904c575121aec15336cd8e5543ddb1d72b6441d Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 25 Jan 2018 23:29:01 +1100 Subject: [PATCH 0722/2058] Show the 'Create this task with administrative privileges' checkbox on the RunFileDlg --- ProcessHacker/mainwnd.c | 100 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 99 insertions(+), 1 deletion(-) diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index b574cb535fdf..0d0167014eb4 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -24,6 +24,7 @@ #include #include +#include #include #include @@ -568,7 +569,7 @@ VOID PhMwpOnCommand( if (RunFileDlg) { SelectedRunAsMode = 0; - RunFileDlg(PhMainWndHandle, NULL, NULL, NULL, NULL, 0); + RunFileDlg(PhMainWndHandle, NULL, NULL, NULL, NULL, RFF_OPTRUNAS); } } break; @@ -1795,6 +1796,103 @@ BOOLEAN PhMwpOnNotify( return TRUE; } } + else if (Header->code == RFN_LIMITEDRUNAS) + { + LPNMRUNFILEDLG runFileDlg = (LPNMRUNFILEDLG)Header; + PVOID WdcLibraryHandle; + ULONG (WINAPI* WdcRunTaskAsInteractiveUser_I)( + _In_ PCWSTR CommandLine, + _In_ PCWSTR CurrentDirectory, + _In_ ULONG Reserved + ); + + // dmex: Task Manager uses RFF_OPTRUNAS and RFN_LIMITEDRUNAS to show the 'Create this task with administrative privileges' checkbox + // on the RunFileDlg when the current process is elevated. Task Manager also uses the WdcRunTaskAsInteractiveUser function to launch processes + // as the interactive user from an elevated token. The WdcRunTaskAsInteractiveUser function + // invokes the "\Microsoft\Windows\Task Manager\Interactive" Task Scheduler task for launching the process but + // doesn't return error information and we need to perform some sanity checks before invoking the task. + // Ideally, we should use our own task but for now just re-use the existing task and do what Task Manager does... + + if (WdcLibraryHandle = LoadLibrary(L"wdc.dll")) + { + if (WdcRunTaskAsInteractiveUser_I = PhGetProcedureAddress(WdcLibraryHandle, "WdcRunTaskAsInteractiveUser", 0)) + { + PH_STRINGREF string; + PPH_STRING commandlineString; + PPH_STRING executeString = NULL; + INT cmdlineArgCount; + PWSTR* cmdlineArgList; + + PhInitializeStringRefLongHint(&string, (PWSTR)runFileDlg->lpszFile); + commandlineString = PhCreateString2(&string); + + // Extract the filename. + if (cmdlineArgList = CommandLineToArgvW(commandlineString->Buffer, &cmdlineArgCount)) + { + PPH_STRING fileName = PhCreateString(cmdlineArgList[0]); + + if (fileName && !RtlDoesFileExists_U(fileName->Buffer)) + { + WCHAR buffer[MAX_PATH]; + + // The user typed a name without a path so attempt to locate the executable. + if (PhSearchFilePath(fileName->Buffer, L".exe", buffer)) + PhMoveReference(&fileName, PhCreateString(buffer)); + else + PhClearReference(&fileName); + } + + if (fileName) + { + // Escape the filename. + PhMoveReference(&fileName, PhConcatStrings(3, L"\"", fileName->Buffer, L"\"")); + + if (cmdlineArgCount == 2) + { + PPH_STRING fileArgs = PhCreateString(cmdlineArgList[1]); + + // Escape the parameters. + PhMoveReference(&fileArgs, PhConcatStrings(3, L"\"", fileArgs->Buffer, L"\"")); + + // Create the escaped execute string. + PhMoveReference(&executeString, PhConcatStrings(3, fileName->Buffer, L" ", fileArgs->Buffer)); + + // Cleanup. + PhDereferenceObject(fileArgs); + } + else + { + // Create the escaped execute string. + PhMoveReference(&executeString, fileName); + } + + PhDereferenceObject(fileName); + } + + LocalFree(cmdlineArgList); + } + + if (!PhIsNullOrEmptyString(executeString)) + { + if (WdcRunTaskAsInteractiveUser_I(executeString->Buffer, NULL, 0) == 0) + *Result = RF_CANCEL; + else + *Result = RF_RETRY; + } + else + { + *Result = RF_RETRY; + } + + if (executeString) + PhDereferenceObject(executeString); + PhDereferenceObject(commandlineString); + } + + FreeLibrary(WdcLibraryHandle); + } + return TRUE; + } return FALSE; } From ba5be2bc43b6556361ec924edfc3187d06dcbd37 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 25 Jan 2018 23:30:31 +1100 Subject: [PATCH 0723/2058] OnlineChecks: Add hybrid-analysis.com upload support --- plugins/OnlineChecks/db.c | 2 + plugins/OnlineChecks/db.h | 2 + plugins/OnlineChecks/main.c | 17 ++- plugins/OnlineChecks/onlnchk.h | 29 ++-- plugins/OnlineChecks/upload.c | 220 ++++++++++++++++++++++++------ plugins/OnlineChecks/virustotal.c | 14 +- 6 files changed, 218 insertions(+), 66 deletions(-) diff --git a/plugins/OnlineChecks/db.c b/plugins/OnlineChecks/db.c index e1082a5bb5ff..4029c9091e60 100644 --- a/plugins/OnlineChecks/db.c +++ b/plugins/OnlineChecks/db.c @@ -25,6 +25,8 @@ PPH_HASHTABLE ProcessObjectDb; PH_QUEUED_LOCK ProcessObjectDbLock = PH_QUEUED_LOCK_INIT; PH_STRINGREF ProcessObjectDbHash = PH_STRINGREF_INIT(L"386f3b6b3f6c35346c69346c6b343d69396b6b3468386b683d383d356b3e383e38356b343f69393b683d3b3a39386b3c6b3a3a3e696835696e686f6b38683e6e"); +PH_STRINGREF ServiceObjectDbHash = PH_STRINGREF_INIT(L"6b396f3b3f6e693b3a6e696c386c393d3c3b3b386f383e3e3e3e343c3e6c3d386f6b3f3f6e69396f3c3a34686b38353a"); +PH_STRINGREF NetworkObjectDbHash = PH_STRINGREF_INIT(L"6e61653c676065676b6b7a393d6a66357a396a6e6e66397a35"); BOOLEAN NTAPI ProcessObjectDbEqualFunction( _In_ PVOID Entry1, diff --git a/plugins/OnlineChecks/db.h b/plugins/OnlineChecks/db.h index 8753c31115f4..2232c1d9e6cd 100644 --- a/plugins/OnlineChecks/db.h +++ b/plugins/OnlineChecks/db.h @@ -24,6 +24,8 @@ #define DB_H extern PH_STRINGREF ProcessObjectDbHash; +extern PH_STRINGREF ServiceObjectDbHash; +extern PH_STRINGREF NetworkObjectDbHash; typedef struct _PROCESS_DB_OBJECT { diff --git a/plugins/OnlineChecks/main.c b/plugins/OnlineChecks/main.c index 09caed0e07a7..286e5ff6a8dd 100644 --- a/plugins/OnlineChecks/main.c +++ b/plugins/OnlineChecks/main.c @@ -3,7 +3,7 @@ * Main Program * * Copyright (C) 2010-2013 wj32 - * Copyright (C) 2012-2017 dmex + * Copyright (C) 2012-2018 dmex * * This file is part of Process Hacker. * @@ -214,15 +214,21 @@ VOID NTAPI MenuItemCallback( case MENUITEM_VIRUSTOTAL_UPLOAD: UploadToOnlineService(menuItem->Context, MENUITEM_VIRUSTOTAL_UPLOAD); break; - case MENUITEM_JOTTI_UPLOAD: - UploadToOnlineService(menuItem->Context, MENUITEM_JOTTI_UPLOAD); - break; case MENUITEM_VIRUSTOTAL_UPLOAD_SERVICE: UploadServiceToOnlineService(menuItem->Context, MENUITEM_VIRUSTOTAL_UPLOAD_SERVICE); break; + case MENUITEM_JOTTI_UPLOAD: + UploadToOnlineService(menuItem->Context, MENUITEM_JOTTI_UPLOAD); + break; case MENUITEM_JOTTI_UPLOAD_SERVICE: UploadServiceToOnlineService(menuItem->Context, MENUITEM_JOTTI_UPLOAD_SERVICE); break; + case MENUITEM_FALCON_UPLOAD: + UploadToOnlineService(menuItem->Context, MENUITEM_FALCON_UPLOAD); + break; + case MENUITEM_FALCON_UPLOAD_SERVICE: + UploadServiceToOnlineService(menuItem->Context, MENUITEM_FALCON_UPLOAD_SERVICE); + break; case MENUITEM_VIRUSTOTAL_UPLOAD_FILE: { static PH_FILETYPE_FILTER filters[] = @@ -263,6 +269,7 @@ VOID NTAPI MainMenuInitializingCallback( onlineMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, 0, L"&Online Checks", NULL); PhInsertEMenuItem(onlineMenuItem, enableMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, ENABLE_SERVICE_VIRUSTOTAL, L"&Enable VirusTotal scanning", NULL), -1); PhInsertEMenuItem(onlineMenuItem, PhCreateEMenuSeparator(), -1); + PhInsertEMenuItem(onlineMenuItem, PhPluginCreateEMenuItem(PluginInstance, 0, MENUITEM_FALCON_UPLOAD, L"Upload file to &hybrid-analysis", NULL), -1); PhInsertEMenuItem(onlineMenuItem, PhPluginCreateEMenuItem(PluginInstance, 0, MENUITEM_VIRUSTOTAL_UPLOAD_FILE, L"&Upload file to VirusTotal...", NULL), -1); //PhInsertEMenuItem(onlineMenuItem, PhPluginCreateEMenuItem(PluginInstance, 0, MENUITEM_VIRUSTOTAL_QUEUE, L"Upload unknown files to VirusTotal...", NULL), -1); PhInsertEMenuItem(menuInfo->Menu, onlineMenuItem, -1); @@ -282,6 +289,7 @@ PPH_EMENU_ITEM CreateSendToMenu( ULONG insertIndex; sendToMenu = PhPluginCreateEMenuItem(PluginInstance, 0, 0, L"Sen&d to", NULL); + PhInsertEMenuItem(sendToMenu, PhPluginCreateEMenuItem(PluginInstance, 0, MENUITEM_FALCON_UPLOAD, L"&hybrid-analysis.com", FileName), -1); PhInsertEMenuItem(sendToMenu, PhPluginCreateEMenuItem(PluginInstance, 0, MENUITEM_VIRUSTOTAL_UPLOAD, L"&virustotal.com", FileName), -1); PhInsertEMenuItem(sendToMenu, PhPluginCreateEMenuItem(PluginInstance, 0, MENUITEM_JOTTI_UPLOAD, L"virusscan.&jotti.org", FileName), -1); @@ -360,6 +368,7 @@ VOID NTAPI ServiceMenuInitializingCallback( serviceItem = NULL; sendToMenu = PhPluginCreateEMenuItem(PluginInstance, 0, 0, L"Sen&d to", NULL); + PhInsertEMenuItem(sendToMenu, PhPluginCreateEMenuItem(PluginInstance, 0, MENUITEM_FALCON_UPLOAD_SERVICE, L"&hybrid-analysis.com", serviceItem ? serviceItem : NULL), -1); PhInsertEMenuItem(sendToMenu, PhPluginCreateEMenuItem(PluginInstance, 0, MENUITEM_VIRUSTOTAL_UPLOAD_SERVICE, L"&virustotal.com", serviceItem ? serviceItem : NULL), -1); PhInsertEMenuItem(sendToMenu, PhPluginCreateEMenuItem(PluginInstance, 0, MENUITEM_JOTTI_UPLOAD_SERVICE, L"virusscan.&jotti.org", serviceItem ? serviceItem : NULL), -1); PhInsertEMenuItem(menuInfo->Menu, PhCreateEMenuSeparator(), -1); diff --git a/plugins/OnlineChecks/onlnchk.h b/plugins/OnlineChecks/onlnchk.h index 1940fc053220..24a3ac6ce508 100644 --- a/plugins/OnlineChecks/onlnchk.h +++ b/plugins/OnlineChecks/onlnchk.h @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -57,8 +58,6 @@ typedef struct _SERVICE_INFO { ULONG Id; PWSTR HostName; - USHORT HostPort; - ULONG HostFlags; PWSTR UploadObjectName; PWSTR FileNameFieldName; } SERVICE_INFO, *PSERVICE_INFO; @@ -186,13 +185,20 @@ VOID VirusTotalShowErrorDialog( ); // upload -#define ENABLE_SERVICE_VIRUSTOTAL 100 -#define MENUITEM_VIRUSTOTAL_QUEUE 101 -#define MENUITEM_VIRUSTOTAL_UPLOAD 102 -#define MENUITEM_VIRUSTOTAL_UPLOAD_SERVICE 103 -#define MENUITEM_VIRUSTOTAL_UPLOAD_FILE 104 -#define MENUITEM_JOTTI_UPLOAD 105 -#define MENUITEM_JOTTI_UPLOAD_SERVICE 106 +#define ENABLE_SERVICE_FALCON 100 +#define MENUITEM_FALCON_QUEUE 101 +#define MENUITEM_FALCON_UPLOAD 102 +#define MENUITEM_FALCON_UPLOAD_SERVICE 103 +#define MENUITEM_FALCON_UPLOAD_FILE 104 + +#define ENABLE_SERVICE_VIRUSTOTAL 110 +#define MENUITEM_VIRUSTOTAL_QUEUE 111 +#define MENUITEM_VIRUSTOTAL_UPLOAD 112 +#define MENUITEM_VIRUSTOTAL_UPLOAD_SERVICE 113 +#define MENUITEM_VIRUSTOTAL_UPLOAD_FILE 114 + +#define MENUITEM_JOTTI_UPLOAD 120 +#define MENUITEM_JOTTI_UPLOAD_SERVICE 121 VOID UploadToOnlineService( _In_ PPH_STRING FileName, @@ -239,7 +245,7 @@ PVIRUSTOTAL_FILE_HASH_ENTRY VirusTotalGetCachedResult( ); PPH_BYTES VirusTotalGetCachedDbHash( - VOID + _In_ PPH_STRINGREF CachedHash ); typedef struct _VT_SYSINT_FILE_REPORT_RESULT @@ -262,7 +268,7 @@ typedef struct _VT_SYSINT_FILE_REPORT_RESULT PPH_STRING VirusTotalStringToTime( _In_ PPH_STRING Time -); + ); typedef struct _VIRUSTOTAL_API_RESPONSE { @@ -303,7 +309,6 @@ PVIRUSTOTAL_API_RESPONSE VirusTotalRequestFileReScan( _In_ PPH_STRING FileHash ); - VOID InitializeVirusTotalProcessMonitor( VOID ); diff --git a/plugins/OnlineChecks/upload.c b/plugins/OnlineChecks/upload.c index 4c6309239c69..3048e570cab7 100644 --- a/plugins/OnlineChecks/upload.c +++ b/plugins/OnlineChecks/upload.c @@ -2,7 +2,7 @@ * Process Hacker Plugins - * Online Checks Plugin * - * Copyright (C) 2016 dmex + * Copyright (C) 2016-2018 dmex * * This file is part of Process Hacker. * @@ -21,16 +21,17 @@ */ #include "onlnchk.h" -#include PPH_OBJECT_TYPE UploadContextType = NULL; PH_INITONCE UploadContextTypeInitOnce = PH_INITONCE_INIT; SERVICE_INFO UploadServiceInfo[] = -{ - { MENUITEM_VIRUSTOTAL_UPLOAD, L"www.virustotal.com", PH_HTTP_DEFAULT_HTTPS_PORT, PH_HTTP_FLAG_SECURE, L"???", L"file" }, - { MENUITEM_VIRUSTOTAL_UPLOAD_SERVICE, L"www.virustotal.com", PH_HTTP_DEFAULT_HTTPS_PORT, PH_HTTP_FLAG_SECURE, L"???", L"file" }, - { MENUITEM_JOTTI_UPLOAD, L"virusscan.jotti.org", PH_HTTP_DEFAULT_HTTPS_PORT, PH_HTTP_FLAG_SECURE, L"/en-US/submit-file?isAjax=true", L"sample-file[]" }, - { MENUITEM_JOTTI_UPLOAD_SERVICE, L"virusscan.jotti.org", PH_HTTP_DEFAULT_HTTPS_PORT, PH_HTTP_FLAG_SECURE, L"/en-US/submit-file?isAjax=true", L"sample-file[]" }, +{ + { MENUITEM_FALCON_UPLOAD, L"www.hybrid-analysis.com", L"/api/submit", L"file" }, + { MENUITEM_FALCON_UPLOAD_SERVICE, L"www.hybrid-analysis.com", L"/api/submit", L"file" }, + { MENUITEM_VIRUSTOTAL_UPLOAD, L"www.virustotal.com", L"???", L"file" }, + { MENUITEM_VIRUSTOTAL_UPLOAD_SERVICE, L"www.virustotal.com", L"???", L"file" }, + { MENUITEM_JOTTI_UPLOAD, L"virusscan.jotti.org", L"/en-US/submit-file?isAjax=true", L"sample-file[]" }, + { MENUITEM_JOTTI_UPLOAD_SERVICE, L"virusscan.jotti.org", L"/en-US/submit-file?isAjax=true", L"sample-file[]" }, }; VOID RaiseUploadError( @@ -254,34 +255,24 @@ NTSTATUS HashFileAndResetPosition( PPH_BYTES PerformSubRequest( _In_ PUPLOAD_CONTEXT Context, _In_ PWSTR HostName, - _In_ USHORT HostPort, - _In_ ULONG HostFlags, _In_ PWSTR ObjectName ) { PPH_BYTES result = NULL; PPH_HTTP_CONTEXT httpContext = NULL; - PPH_STRING phVersion = NULL; - PPH_STRING userAgent = NULL; + PPH_STRING phVersion; + PPH_STRING userAgent; - // Create a user agent string. phVersion = PhGetPhVersion(); userAgent = PhConcatStrings2(L"ProcessHacker_", phVersion->Buffer); - if (!PhHttpSocketCreate( - &httpContext, - PhGetString(userAgent) - )) + if (!PhHttpSocketCreate(&httpContext, userAgent->Buffer)) { RaiseUploadError(Context, L"Unable to create the http socket.", GetLastError()); goto CleanupExit; } - if (!PhHttpSocketConnect( - httpContext, - HostName, - HostPort - )) + if (!PhHttpSocketConnect(httpContext, HostName, PH_HTTP_DEFAULT_HTTPS_PORT)) { RaiseUploadError(Context, L"Unable to connect to the service.", GetLastError()); goto CleanupExit; @@ -291,7 +282,7 @@ PPH_BYTES PerformSubRequest( httpContext, NULL, ObjectName, - PH_HTTP_FLAG_REFRESH | HostFlags + PH_HTTP_FLAG_REFRESH | PH_HTTP_FLAG_SECURE )) { RaiseUploadError(Context, L"Unable to create the request.", GetLastError()); @@ -309,7 +300,7 @@ PPH_BYTES PerformSubRequest( RaiseUploadError(Context, L"Unable to receive the request.", GetLastError()); goto CleanupExit; } - + if (!(result = PhHttpSocketDownloadString(httpContext, FALSE))) { RaiseUploadError(Context, L"Unable to download the response.", GetLastError()); @@ -327,6 +318,24 @@ PPH_BYTES PerformSubRequest( return result; } +BOOLEAN UploadGetFileArchitecture( + _In_ HANDLE FileHandle, + _Out_ PUSHORT FileArchitecture + ) +{ + NTSTATUS status; + PH_MAPPED_IMAGE mappedImage; + + if (!NT_SUCCESS(status = PhLoadMappedImage(NULL, FileHandle, TRUE, &mappedImage))) + return FALSE; + + *FileArchitecture = mappedImage.NtHeaders->FileHeader.Machine; + + PhUnloadMappedImage(&mappedImage); + + return TRUE; +} + NTSTATUS UploadFileThreadStart( _In_ PVOID Parameter ) @@ -426,22 +435,92 @@ NTSTATUS UploadFileThreadStart( PhInitializeStringBuilder(&httpPostHeader, DOS_MAX_PATH_LENGTH); PhInitializeStringBuilder(&httpPostFooter, DOS_MAX_PATH_LENGTH); - // build request boundary string + // HTTP request boundary string. postBoundary = PhFormatString( - L"------------------------%I64u", + L"--%I64u", (ULONG64)RtlRandomEx(&httpPostSeed) | ((ULONG64)RtlRandomEx(&httpPostSeed) << 31) ); - // build request header string + // HTTP request header string. PhAppendFormatStringBuilder( &httpRequestHeaders, L"Content-Type: multipart/form-data; boundary=%s\r\n", postBoundary->Buffer ); - if (context->Service == MENUITEM_JOTTI_UPLOAD) + if (context->Service == MENUITEM_FALCON_UPLOAD || context->Service == MENUITEM_FALCON_UPLOAD_SERVICE) { - // POST boundary header + USHORT machineType; + USHORT environmentId; + + if (!UploadGetFileArchitecture(fileHandle, &machineType)) + { + RaiseUploadError(context, L"Unable to create the request.", GetLastError()); + goto CleanupExit; + } + + switch (machineType) + { + case IMAGE_FILE_MACHINE_I386: + environmentId = 100; + break; + case IMAGE_FILE_MACHINE_AMD64: + environmentId = 120; + break; + default: + { + RaiseUploadError(context, L"File architecture not supported.", GetLastError()); + goto CleanupExit; + } + } + + { + PPH_BYTES serviceHash; + PPH_BYTES networkHash; + PPH_STRING resourceNameString; + PPH_STRING resourceHashString; + + serviceHash = VirusTotalGetCachedDbHash(&ServiceObjectDbHash); + networkHash = VirusTotalGetCachedDbHash(&NetworkObjectDbHash); + + resourceNameString = PhZeroExtendToUtf16(serviceHash->Buffer); + resourceHashString = PhZeroExtendToUtf16(networkHash->Buffer); + PhHttpSocketSetCredentials(httpContext, PhGetString(resourceHashString), PhGetString(resourceNameString)); + PhClearReference(&resourceHashString); + PhClearReference(&resourceNameString); + PhClearReference(&networkHash); + PhClearReference(&serviceHash); + } + + // POST boundary header. + PhAppendFormatStringBuilder( + &httpPostHeader, + L"--%s\r\nContent-Disposition: form-data; name=\"environmentId\"\r\n\r\n%hu\r\n", + postBoundary->Buffer, + environmentId + ); + PhAppendFormatStringBuilder( + &httpPostHeader, + L"--%s\r\nContent-Disposition: form-data; name=\"nosharevt\"\r\n\r\n1\r\n", + postBoundary->Buffer + ); + PhAppendFormatStringBuilder( + &httpPostHeader, + L"--%s\r\nContent-Disposition: form-data; name=\"file\"; filename=\"%s\"\r\n\r\n", + postBoundary->Buffer, + PhGetStringOrEmpty(context->BaseFileName) + ); + + // POST boundary footer. + PhAppendFormatStringBuilder( + &httpPostFooter, + L"\r\n--%s--\r\n", + postBoundary->Buffer + ); + } + else if (context->Service == MENUITEM_JOTTI_UPLOAD) + { + // POST boundary header. PhAppendFormatStringBuilder( &httpPostHeader, L"\r\n--%s\r\n", @@ -467,7 +546,7 @@ NTSTATUS UploadFileThreadStart( L"Content-Type: application/x-msdownload\r\n\r\n" ); - // POST boundary footer + // POST boundary footer. PhAppendFormatStringBuilder( &httpPostFooter, L"\r\n--%s--\r\n", @@ -667,6 +746,58 @@ NTSTATUS UploadFileThreadStart( { switch (context->Service) { + case MENUITEM_FALCON_UPLOAD: + case MENUITEM_FALCON_UPLOAD_SERVICE: + { + PPH_BYTES jsonString; + PVOID jsonRootObject; + + if (!(jsonString = PhHttpSocketDownloadString(httpContext, FALSE))) + { + RaiseUploadError(context, L"Unable to download the response.", GetLastError()); + goto CleanupExit; + } + + if (jsonRootObject = PhCreateJsonParser(jsonString->Buffer)) + { + INT64 errorCode = PhGetJsonValueAsLong64(jsonRootObject, "response_code"); + + if (errorCode == 0) + { + PVOID jsonResponse; + PPH_STRING jsonHashString = NULL; + + if (jsonResponse = PhGetJsonObject(jsonRootObject, "response")) + jsonHashString = PhGetJsonValueAsString(jsonResponse, "sha256"); + + if (jsonHashString) + { + PhMoveReference(&context->LaunchCommand, PhFormatString( + L"https://www.hybrid-analysis.com/sample/%s", + context->FileHash ? PhGetString(context->FileHash) : PhGetString(jsonHashString) + )); + + PhDereferenceObject(jsonHashString); + } + } + else + { + RaiseUploadError(context, L"Hybrid Analysis API error.", (ULONG)errorCode); + PhDereferenceObject(jsonString); + goto CleanupExit; + } + + PhFreeJsonParser(jsonRootObject); + } + else + { + RaiseUploadError(context, L"Unable to complete the request.", RtlNtStatusToDosError(STATUS_FAIL_CHECK)); + goto CleanupExit; + } + + PhDereferenceObject(jsonString); + } + break; case MENUITEM_VIRUSTOTAL_UPLOAD: case MENUITEM_VIRUSTOTAL_UPLOAD_SERVICE: { @@ -757,6 +888,9 @@ NTSTATUS UploadFileThreadStart( CleanupExit: + if (httpContext) + PhHttpSocketDestroy(httpContext); + // Reset Taskbar progress state(s) if (context->TaskbarListClass) { @@ -876,8 +1010,6 @@ NTSTATUS UploadCheckThreadStart( if (!(subRequestBuffer = PerformSubRequest( context, serviceInfo->HostName, - serviceInfo->HostPort, - serviceInfo->HostFlags, subObjectName->Buffer ))) { @@ -921,7 +1053,7 @@ NTSTATUS UploadCheckThreadStart( if (context->VtApiUpload) { - PPH_BYTES resource = VirusTotalGetCachedDbHash(); + PPH_BYTES resource = VirusTotalGetCachedDbHash(&ProcessObjectDbHash); PhMoveReference(&context->UploadUrl, PhFormatString( L"%s%s?\x0061\x0070\x0069\x006B\x0065\x0079=%S&resource=%s", @@ -969,20 +1101,21 @@ NTSTATUS UploadCheckThreadStart( case MENUITEM_JOTTI_UPLOAD: case MENUITEM_JOTTI_UPLOAD_SERVICE: { - // Create the default upload URL - context->UploadUrl = PhFormatString(L"https://virusscan.jotti.org%s", serviceInfo->UploadObjectName); + // Create the default upload URL. + context->UploadUrl = PhFormatString(L"https://%s%s", serviceInfo->HostName, serviceInfo->UploadObjectName); - // No file found... Start the upload. - if (!PhIsNullOrEmptyString(context->UploadUrl)) - { - PostMessage(context->DialogHandle, UM_UPLOAD, 0, 0); - } - else - { - RaiseUploadError(context, L"Unable to parse the response.", RtlNtStatusToDosError(STATUS_FAIL_CHECK)); - } + // Start the upload. + PostMessage(context->DialogHandle, UM_UPLOAD, 0, 0); } break; + case MENUITEM_FALCON_UPLOAD: + case MENUITEM_FALCON_UPLOAD_SERVICE: + { + // Create the default upload URL. + context->UploadUrl = PhFormatString(L"https://%s%s", serviceInfo->HostName, serviceInfo->UploadObjectName); + + PostMessage(context->DialogHandle, UM_UPLOAD, 0, 0); + } } CleanupExit: @@ -1155,6 +1288,7 @@ NTSTATUS ShowUpdateDialogThread( PhInitializeAutoPool(&autoPool); + config.hInstance = PluginInstance->DllBase; config.dwFlags = TDF_ALLOW_DIALOG_CANCELLATION | TDF_CAN_BE_MINIMIZED; config.pszContent = L"Initializing..."; config.lpCallbackData = (LONG_PTR)context; diff --git a/plugins/OnlineChecks/virustotal.c b/plugins/OnlineChecks/virustotal.c index 630575214429..4e9eb77f064f 100644 --- a/plugins/OnlineChecks/virustotal.c +++ b/plugins/OnlineChecks/virustotal.c @@ -180,19 +180,19 @@ PVIRUSTOTAL_FILE_HASH_ENTRY VirusTotalGetCachedResultFromHash( } PPH_BYTES VirusTotalGetCachedDbHash( - VOID + _In_ PPH_STRINGREF CachedHash ) { ULONG length; PUCHAR buffer; PPH_BYTES string; - length = (ULONG)ProcessObjectDbHash.Length / sizeof(WCHAR) / 2; + length = (ULONG)CachedHash->Length / sizeof(WCHAR) / 2; buffer = PhAllocate(length + 1); memset(buffer, 0, length + 1); - PhHexStringToBuffer(&ProcessObjectDbHash, buffer); + PhHexStringToBuffer(CachedHash, buffer); string = PhCreateBytes(buffer); @@ -310,7 +310,7 @@ PPH_BYTES VirusTotalSendHttpRequest( goto CleanupExit; { - PPH_BYTES resourceString = VirusTotalGetCachedDbHash(); + PPH_BYTES resourceString = VirusTotalGetCachedDbHash(&ProcessObjectDbHash); urlPathString = PhFormatString( L"%s%s%s%s%S", @@ -395,7 +395,7 @@ PVIRUSTOTAL_FILE_REPORT VirusTotalRequestFileReport( } { - PPH_BYTES resourceString = VirusTotalGetCachedDbHash(); + PPH_BYTES resourceString = VirusTotalGetCachedDbHash(&ProcessObjectDbHash); urlPathString = PhFormatString( L"%s%s%s%s%s%S%s%s", @@ -529,7 +529,7 @@ PVIRUSTOTAL_API_RESPONSE VirusTotalRequestFileReScan( } { - PPH_BYTES resourceString = VirusTotalGetCachedDbHash(); + PPH_BYTES resourceString = VirusTotalGetCachedDbHash(&ProcessObjectDbHash); urlPathString = PhFormatString( L"%s%s%s%s%s%S%s%s", @@ -627,7 +627,7 @@ PVIRUSTOTAL_API_RESPONSE VirusTotalRequestIpAddressReport( } { - PPH_BYTES resourceString = VirusTotalGetCachedDbHash(); + PPH_BYTES resourceString = VirusTotalGetCachedDbHash(&ProcessObjectDbHash); urlPathString = PhFormatString( L"%s%s%s%s%s%S%s%s", From 978b25c54aa98002d73606874d084a17324bb6c1 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 25 Jan 2018 23:32:55 +1100 Subject: [PATCH 0724/2058] Fix typo --- ProcessHacker/main.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/ProcessHacker/main.c b/ProcessHacker/main.c index 0acc622d12f4..e9c2bda26895 100644 --- a/ProcessHacker/main.c +++ b/ProcessHacker/main.c @@ -553,7 +553,6 @@ BOOLEAN PhInitializeMitigationPolicy( PS_SYSTEM_DLL_INIT_BLOCK (*LdrSystemDllInitBlock_I); HANDLE jobObjectHandle; SIZE_T attributeListLength = 0; - PROCESS_INFORMATION processInfo = { 0 }; STARTUPINFOEX startupInfo = { sizeof(STARTUPINFOEX) }; JOBOBJECT_EXTENDED_LIMIT_INFORMATION extendedInfo = { 0 }; @@ -614,12 +613,6 @@ BOOLEAN PhInitializeMitigationPolicy( CleanupExit: - if (processInfo.hProcess) - NtClose(processInfo.hProcess); - - if (processInfo.hThread) - NtClose(processInfo.hThread); - if (jobObjectHandle) NtClose(jobObjectHandle); From 43cc8ba1a13e6686ddf3723c4fca71c98265d694 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 25 Jan 2018 23:36:28 +1100 Subject: [PATCH 0725/2058] OnlineChecks: Fix hybrid-analysis.com upload support --- plugins/OnlineChecks/main.c | 14 +++++++------- plugins/OnlineChecks/onlnchk.h | 10 +++++----- plugins/OnlineChecks/upload.c | 14 +++++++------- 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/plugins/OnlineChecks/main.c b/plugins/OnlineChecks/main.c index 286e5ff6a8dd..209c3d6d8d04 100644 --- a/plugins/OnlineChecks/main.c +++ b/plugins/OnlineChecks/main.c @@ -223,11 +223,11 @@ VOID NTAPI MenuItemCallback( case MENUITEM_JOTTI_UPLOAD_SERVICE: UploadServiceToOnlineService(menuItem->Context, MENUITEM_JOTTI_UPLOAD_SERVICE); break; - case MENUITEM_FALCON_UPLOAD: - UploadToOnlineService(menuItem->Context, MENUITEM_FALCON_UPLOAD); + case MENUITEM_HYBRIDANALYSIS_UPLOAD: + UploadToOnlineService(menuItem->Context, MENUITEM_HYBRIDANALYSIS_UPLOAD); break; - case MENUITEM_FALCON_UPLOAD_SERVICE: - UploadServiceToOnlineService(menuItem->Context, MENUITEM_FALCON_UPLOAD_SERVICE); + case MENUITEM_HYBRIDANALYSIS_UPLOAD_SERVICE: + UploadServiceToOnlineService(menuItem->Context, MENUITEM_HYBRIDANALYSIS_UPLOAD_SERVICE); break; case MENUITEM_VIRUSTOTAL_UPLOAD_FILE: { @@ -269,7 +269,7 @@ VOID NTAPI MainMenuInitializingCallback( onlineMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, 0, L"&Online Checks", NULL); PhInsertEMenuItem(onlineMenuItem, enableMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, ENABLE_SERVICE_VIRUSTOTAL, L"&Enable VirusTotal scanning", NULL), -1); PhInsertEMenuItem(onlineMenuItem, PhCreateEMenuSeparator(), -1); - PhInsertEMenuItem(onlineMenuItem, PhPluginCreateEMenuItem(PluginInstance, 0, MENUITEM_FALCON_UPLOAD, L"Upload file to &hybrid-analysis", NULL), -1); + PhInsertEMenuItem(onlineMenuItem, PhPluginCreateEMenuItem(PluginInstance, 0, MENUITEM_HYBRIDANALYSIS_UPLOAD, L"Upload file to &hybrid-analysis", NULL), -1); PhInsertEMenuItem(onlineMenuItem, PhPluginCreateEMenuItem(PluginInstance, 0, MENUITEM_VIRUSTOTAL_UPLOAD_FILE, L"&Upload file to VirusTotal...", NULL), -1); //PhInsertEMenuItem(onlineMenuItem, PhPluginCreateEMenuItem(PluginInstance, 0, MENUITEM_VIRUSTOTAL_QUEUE, L"Upload unknown files to VirusTotal...", NULL), -1); PhInsertEMenuItem(menuInfo->Menu, onlineMenuItem, -1); @@ -289,7 +289,7 @@ PPH_EMENU_ITEM CreateSendToMenu( ULONG insertIndex; sendToMenu = PhPluginCreateEMenuItem(PluginInstance, 0, 0, L"Sen&d to", NULL); - PhInsertEMenuItem(sendToMenu, PhPluginCreateEMenuItem(PluginInstance, 0, MENUITEM_FALCON_UPLOAD, L"&hybrid-analysis.com", FileName), -1); + PhInsertEMenuItem(sendToMenu, PhPluginCreateEMenuItem(PluginInstance, 0, MENUITEM_HYBRIDANALYSIS_UPLOAD, L"&hybrid-analysis.com", FileName), -1); PhInsertEMenuItem(sendToMenu, PhPluginCreateEMenuItem(PluginInstance, 0, MENUITEM_VIRUSTOTAL_UPLOAD, L"&virustotal.com", FileName), -1); PhInsertEMenuItem(sendToMenu, PhPluginCreateEMenuItem(PluginInstance, 0, MENUITEM_JOTTI_UPLOAD, L"virusscan.&jotti.org", FileName), -1); @@ -368,7 +368,7 @@ VOID NTAPI ServiceMenuInitializingCallback( serviceItem = NULL; sendToMenu = PhPluginCreateEMenuItem(PluginInstance, 0, 0, L"Sen&d to", NULL); - PhInsertEMenuItem(sendToMenu, PhPluginCreateEMenuItem(PluginInstance, 0, MENUITEM_FALCON_UPLOAD_SERVICE, L"&hybrid-analysis.com", serviceItem ? serviceItem : NULL), -1); + PhInsertEMenuItem(sendToMenu, PhPluginCreateEMenuItem(PluginInstance, 0, MENUITEM_HYBRIDANALYSIS_UPLOAD_SERVICE, L"&hybrid-analysis.com", serviceItem ? serviceItem : NULL), -1); PhInsertEMenuItem(sendToMenu, PhPluginCreateEMenuItem(PluginInstance, 0, MENUITEM_VIRUSTOTAL_UPLOAD_SERVICE, L"&virustotal.com", serviceItem ? serviceItem : NULL), -1); PhInsertEMenuItem(sendToMenu, PhPluginCreateEMenuItem(PluginInstance, 0, MENUITEM_JOTTI_UPLOAD_SERVICE, L"virusscan.&jotti.org", serviceItem ? serviceItem : NULL), -1); PhInsertEMenuItem(menuInfo->Menu, PhCreateEMenuSeparator(), -1); diff --git a/plugins/OnlineChecks/onlnchk.h b/plugins/OnlineChecks/onlnchk.h index 24a3ac6ce508..e07b3245d69c 100644 --- a/plugins/OnlineChecks/onlnchk.h +++ b/plugins/OnlineChecks/onlnchk.h @@ -185,11 +185,11 @@ VOID VirusTotalShowErrorDialog( ); // upload -#define ENABLE_SERVICE_FALCON 100 -#define MENUITEM_FALCON_QUEUE 101 -#define MENUITEM_FALCON_UPLOAD 102 -#define MENUITEM_FALCON_UPLOAD_SERVICE 103 -#define MENUITEM_FALCON_UPLOAD_FILE 104 +#define ENABLE_SERVICE_HYBRIDANALYSIS 100 +#define MENUITEM_HYBRIDANALYSIS_QUEUE 101 +#define MENUITEM_HYBRIDANALYSIS_UPLOAD 102 +#define MENUITEM_HYBRIDANALYSIS_UPLOAD_SERVICE 103 +#define MENUITEM_HYBRIDANALYSIS_UPLOAD_FILE 104 #define ENABLE_SERVICE_VIRUSTOTAL 110 #define MENUITEM_VIRUSTOTAL_QUEUE 111 diff --git a/plugins/OnlineChecks/upload.c b/plugins/OnlineChecks/upload.c index 3048e570cab7..023a7e38b54c 100644 --- a/plugins/OnlineChecks/upload.c +++ b/plugins/OnlineChecks/upload.c @@ -26,8 +26,8 @@ PPH_OBJECT_TYPE UploadContextType = NULL; PH_INITONCE UploadContextTypeInitOnce = PH_INITONCE_INIT; SERVICE_INFO UploadServiceInfo[] = { - { MENUITEM_FALCON_UPLOAD, L"www.hybrid-analysis.com", L"/api/submit", L"file" }, - { MENUITEM_FALCON_UPLOAD_SERVICE, L"www.hybrid-analysis.com", L"/api/submit", L"file" }, + { MENUITEM_HYBRIDANALYSIS_UPLOAD, L"www.hybrid-analysis.com", L"/api/submit", L"file" }, + { MENUITEM_HYBRIDANALYSIS_UPLOAD_SERVICE, L"www.hybrid-analysis.com", L"/api/submit", L"file" }, { MENUITEM_VIRUSTOTAL_UPLOAD, L"www.virustotal.com", L"???", L"file" }, { MENUITEM_VIRUSTOTAL_UPLOAD_SERVICE, L"www.virustotal.com", L"???", L"file" }, { MENUITEM_JOTTI_UPLOAD, L"virusscan.jotti.org", L"/en-US/submit-file?isAjax=true", L"sample-file[]" }, @@ -448,7 +448,7 @@ NTSTATUS UploadFileThreadStart( postBoundary->Buffer ); - if (context->Service == MENUITEM_FALCON_UPLOAD || context->Service == MENUITEM_FALCON_UPLOAD_SERVICE) + if (context->Service == MENUITEM_HYBRIDANALYSIS_UPLOAD || context->Service == MENUITEM_HYBRIDANALYSIS_UPLOAD_SERVICE) { USHORT machineType; USHORT environmentId; @@ -746,8 +746,8 @@ NTSTATUS UploadFileThreadStart( { switch (context->Service) { - case MENUITEM_FALCON_UPLOAD: - case MENUITEM_FALCON_UPLOAD_SERVICE: + case MENUITEM_HYBRIDANALYSIS_UPLOAD: + case MENUITEM_HYBRIDANALYSIS_UPLOAD_SERVICE: { PPH_BYTES jsonString; PVOID jsonRootObject; @@ -1108,8 +1108,8 @@ NTSTATUS UploadCheckThreadStart( PostMessage(context->DialogHandle, UM_UPLOAD, 0, 0); } break; - case MENUITEM_FALCON_UPLOAD: - case MENUITEM_FALCON_UPLOAD_SERVICE: + case MENUITEM_HYBRIDANALYSIS_UPLOAD: + case MENUITEM_HYBRIDANALYSIS_UPLOAD_SERVICE: { // Create the default upload URL. context->UploadUrl = PhFormatString(L"https://%s%s", serviceInfo->HostName, serviceInfo->UploadObjectName); From 5d72b081f38fd3b2cdb4484c394802aab7513886 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 26 Jan 2018 02:33:47 +1100 Subject: [PATCH 0726/2058] ExtendedTools: Fix network usage text icon --- plugins/ExtendedTools/iconext.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/ExtendedTools/iconext.c b/plugins/ExtendedTools/iconext.c index 3bdec4ac9749..921e86d94f71 100644 --- a/plugins/ExtendedTools/iconext.c +++ b/plugins/ExtendedTools/iconext.c @@ -161,7 +161,7 @@ VOID EtRegisterNotifyIcons( &data ); - data.UpdateCallback = EtpNetworkIconUpdateCallback; + data.UpdateCallback = EtpNetworkTextIconUpdateCallback; data.MessageCallback = EtpNetworkIconMessageCallback; Pointers->RegisterTrayIcon( PluginInstance, From a50831329f2ffb1c48143b4a9e1b8f189409b6dc Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 26 Jan 2018 02:37:22 +1100 Subject: [PATCH 0727/2058] Fix notify icons settings --- ProcessHacker/notifico.c | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/ProcessHacker/notifico.c b/ProcessHacker/notifico.c index 29b0f66b87c8..b5584a4c3ab2 100644 --- a/ProcessHacker/notifico.c +++ b/ProcessHacker/notifico.c @@ -107,9 +107,15 @@ VOID PhNfLoadSettings( { PPH_NF_ICON icon; - if (icon = PhNfFindIcon(&pluginNamePart, (ULONG)idInteger)) + if (pluginNamePart.Length) { - icon->Flags |= PH_NF_ICON_ENABLED; + if (icon = PhNfFindIcon(&pluginNamePart, (ULONG)idInteger)) + icon->Flags |= PH_NF_ICON_ENABLED; + } + else + { + if (icon = PhNfGetIconById((ULONG)idInteger)) + icon->Flags |= PH_NF_ICON_ENABLED; } } } @@ -142,6 +148,9 @@ VOID PhNfSaveSettings( ); } + if (iconListBuilder.String->Length != 0) + PhRemoveEndStringBuilder(&iconListBuilder, 1); + settingsString = PhFinalStringBuilderString(&iconListBuilder); PhSetStringSetting2(L"IconSettings", &settingsString->sr); PhDereferenceObject(settingsString); @@ -491,7 +500,7 @@ PPH_NF_ICON PhNfGetIconById( } PPH_NF_ICON PhNfFindIcon( - _In_opt_ PPH_STRINGREF PluginName, + _In_ PPH_STRINGREF PluginName, _In_ ULONG SubId ) { @@ -499,21 +508,14 @@ PPH_NF_ICON PhNfFindIcon( { PPH_NF_ICON icon = PhTrayIconItemList->Items[i]; - if (PluginName) + if (icon->Plugin) { - if ( - icon->SubId == SubId && - (icon->Plugin ? PhEqualStringRef(PluginName, &icon->Plugin->AppContext.AppName, TRUE) : TRUE) - ) + if (icon->SubId == SubId && + PhEqualStringRef(PluginName, &icon->Plugin->Name, TRUE)) { return icon; } } - else - { - if (icon->SubId == SubId) - return icon; - } } return NULL; From 8ac3afb7d3858cf54958076b48c55ac76b6c33c6 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 26 Jan 2018 04:00:00 +1100 Subject: [PATCH 0728/2058] Fix treelist regression (show_always) --- phlib/treenew.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/phlib/treenew.c b/phlib/treenew.c index cd85bfff576d..492739319042 100644 --- a/phlib/treenew.c +++ b/phlib/treenew.c @@ -183,8 +183,8 @@ LRESULT CALLBACK PhTnpWndProc( return 0; case WM_KILLFOCUS: { - if (!context->ContextMenuActive && !(context->Style & TN_STYLE_ALWAYS_SHOW_SELECTION)) - PhTnpSelectRange(context, -1, -1, TN_SELECT_RESET, NULL, NULL); + //if (!context->ContextMenuActive && !(context->Style & TN_STYLE_ALWAYS_SHOW_SELECTION)) + // PhTnpSelectRange(context, -1, -1, TN_SELECT_RESET, NULL, NULL); context->HasFocus = FALSE; @@ -212,19 +212,19 @@ LRESULT CALLBACK PhTnpWndProc( break; case WM_MOUSELEAVE: { - if (!context->ContextMenuActive && !(context->Style & TN_STYLE_ALWAYS_SHOW_SELECTION)) - { - ULONG changedStart; - ULONG changedEnd; - RECT rect; - - PhTnpSelectRange(context, -1, -1, TN_SELECT_RESET, &changedStart, &changedEnd); - - if (PhTnpGetRowRects(context, changedStart, changedEnd, TRUE, &rect)) - { - InvalidateRect(context->Handle, &rect, FALSE); - } - } + //if (!context->ContextMenuActive && !(context->Style & TN_STYLE_ALWAYS_SHOW_SELECTION)) + //{ + // ULONG changedStart; + // ULONG changedEnd; + // RECT rect; + // + // PhTnpSelectRange(context, -1, -1, TN_SELECT_RESET, &changedStart, &changedEnd); + // + // if (PhTnpGetRowRects(context, changedStart, changedEnd, TRUE, &rect)) + // { + // InvalidateRect(context->Handle, &rect, FALSE); + // } + //} if (!context->SuspendUpdateStructure) PhTnpOnMouseLeave(hwnd, context); From 40ed7196aa123b6c4367a9f009fba062686c0ff7 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 26 Jan 2018 06:35:02 +1100 Subject: [PATCH 0729/2058] Fix version check #229 --- ProcessHacker/main.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/ProcessHacker/main.c b/ProcessHacker/main.c index e9c2bda26895..d855053ed18e 100644 --- a/ProcessHacker/main.c +++ b/ProcessHacker/main.c @@ -564,6 +564,9 @@ BOOLEAN PhInitializeMitigationPolicy( if (!LdrSystemDllInitBlock_I) return FALSE; + if (!RTL_CONTAINS_FIELD(LdrSystemDllInitBlock_I, LdrSystemDllInitBlock_I->Size, MitigationOptionsMap)) + return FALSE; + if ((LdrSystemDllInitBlock_I->MitigationOptionsMap.Map[0] & DEFAULT_MITIGATION_POLICY_FLAGS) == DEFAULT_MITIGATION_POLICY_FLAGS) return FALSE; @@ -595,8 +598,8 @@ BOOLEAN PhInitializeMitigationPolicy( if (!UpdateProcThreadAttribute(startupInfo.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_JOB_LIST, &(HANDLE){ jobObjectHandle }, sizeof(HANDLE), NULL, NULL)) goto CleanupExit; - if (NT_SUCCESS(PhCreateProcessWin32Ex( - NtCurrentPeb()->ProcessParameters->ImagePathName.Buffer, + if (NT_SUCCESS(status = PhCreateProcessWin32Ex( + NULL, NtCurrentPeb()->ProcessParameters->CommandLine.Buffer, NULL, NULL, From c0f2c535c640582b3c871cf0a63e3e58f71ae71b Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 26 Jan 2018 06:42:14 +1100 Subject: [PATCH 0730/2058] Fix build warning --- ProcessHacker/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ProcessHacker/main.c b/ProcessHacker/main.c index d855053ed18e..f2f3f92b1323 100644 --- a/ProcessHacker/main.c +++ b/ProcessHacker/main.c @@ -598,7 +598,7 @@ BOOLEAN PhInitializeMitigationPolicy( if (!UpdateProcThreadAttribute(startupInfo.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_JOB_LIST, &(HANDLE){ jobObjectHandle }, sizeof(HANDLE), NULL, NULL)) goto CleanupExit; - if (NT_SUCCESS(status = PhCreateProcessWin32Ex( + if (NT_SUCCESS(PhCreateProcessWin32Ex( NULL, NtCurrentPeb()->ProcessParameters->CommandLine.Buffer, NULL, From d31507dbe27e65b9d85c0c172306cb8267fc2de6 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 27 Jan 2018 11:57:27 +1100 Subject: [PATCH 0731/2058] Fix #229 restart issue --- ProcessHacker/main.c | 117 +++++++++++++++++++------------------------ 1 file changed, 52 insertions(+), 65 deletions(-) diff --git a/ProcessHacker/main.c b/ProcessHacker/main.c index f2f3f92b1323..517b191ec328 100644 --- a/ProcessHacker/main.c +++ b/ProcessHacker/main.c @@ -532,6 +532,36 @@ VOID PhInitializeFont( } } +VOID PhInitializeRestartPolicy( + VOID + ) +{ + PH_STRINGREF commandLineSr; + PH_STRINGREF fileNameSr; + PH_STRINGREF argumentsSr; + PPH_STRING argumentsString = NULL; + + PhUnicodeStringToStringRef(&NtCurrentPeb()->ProcessParameters->CommandLine, &commandLineSr); + + if (!PhParseCommandLineFuzzy(&commandLineSr, &fileNameSr, &argumentsSr, NULL)) + return; + + if (argumentsSr.Length) + { + static PH_STRINGREF commandlinePart = PH_STRINGREF_INIT(L"-nomp"); + + if (PhEndsWithStringRef(&argumentsSr, &commandlinePart, FALSE)) + PhTrimStringRef(&argumentsSr, &commandlinePart, PH_TRIM_END_ONLY); + + argumentsString = PhCreateString2(&argumentsSr); + } + + // MSDN: Do not include the file name in the command line. + RegisterApplicationRestart(PhGetString(argumentsString), 0); + + PhClearReference(&argumentsString); +} + BOOLEAN PhInitializeMitigationPolicy( VOID ) @@ -549,75 +579,57 @@ BOOLEAN PhInitializeMitigationPolicy( PROCESS_CREATION_MITIGATION_POLICY_IMAGE_LOAD_NO_REMOTE_ALWAYS_ON | \ PROCESS_CREATION_MITIGATION_POLICY_IMAGE_LOAD_NO_LOW_LABEL_ALWAYS_ON) + static PH_STRINGREF commandlinePart = PH_STRINGREF_INIT(L" -nomp"); BOOLEAN success = FALSE; - PS_SYSTEM_DLL_INIT_BLOCK (*LdrSystemDllInitBlock_I); - HANDLE jobObjectHandle; - SIZE_T attributeListLength = 0; + PH_STRINGREF commandlineSr; + PPH_STRING commandline = NULL; + PS_SYSTEM_DLL_INIT_BLOCK (*LdrSystemDllInitBlock_I) = NULL; STARTUPINFOEX startupInfo = { sizeof(STARTUPINFOEX) }; - JOBOBJECT_EXTENDED_LIMIT_INFORMATION extendedInfo = { 0 }; + SIZE_T attributeListLength; - if (WindowsVersion < WINDOWS_10_RS2) - return FALSE; + PhUnicodeStringToStringRef(&NtCurrentPeb()->ProcessParameters->CommandLine, &commandlineSr); - LdrSystemDllInitBlock_I = PhGetModuleProcAddress(L"ntdll.dll", "LdrSystemDllInitBlock"); + if (PhEndsWithStringRef(&commandlineSr, &commandlinePart, FALSE)) + goto CleanupExit; - if (!LdrSystemDllInitBlock_I) - return FALSE; + if (!(LdrSystemDllInitBlock_I = PhGetModuleProcAddress(L"ntdll.dll", "LdrSystemDllInitBlock"))) + goto CleanupExit; if (!RTL_CONTAINS_FIELD(LdrSystemDllInitBlock_I, LdrSystemDllInitBlock_I->Size, MitigationOptionsMap)) - return FALSE; - - if ((LdrSystemDllInitBlock_I->MitigationOptionsMap.Map[0] & DEFAULT_MITIGATION_POLICY_FLAGS) == DEFAULT_MITIGATION_POLICY_FLAGS) - return FALSE; - - if (!InitializeProcThreadAttributeList(NULL, 2, 0, &attributeListLength) && GetLastError() != ERROR_INSUFFICIENT_BUFFER) - return FALSE; - - startupInfo.lpAttributeList = PhAllocate(attributeListLength); - - if (!InitializeProcThreadAttributeList(startupInfo.lpAttributeList, 2, 0, &attributeListLength)) goto CleanupExit; - if (!UpdateProcThreadAttribute(startupInfo.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY, &(ULONG64){ DEFAULT_MITIGATION_POLICY_FLAGS }, sizeof(ULONG64), NULL, NULL)) + if ((LdrSystemDllInitBlock_I->MitigationOptionsMap.Map[0] & DEFAULT_MITIGATION_POLICY_FLAGS) == DEFAULT_MITIGATION_POLICY_FLAGS) goto CleanupExit; - if (!NT_SUCCESS(NtCreateJobObject(&jobObjectHandle, JOB_OBJECT_ALL_ACCESS, NULL))) + if (!InitializeProcThreadAttributeList(NULL, 1, 0, &attributeListLength) && GetLastError() != ERROR_INSUFFICIENT_BUFFER) goto CleanupExit; - extendedInfo.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_BREAKAWAY_OK | JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK | JOB_OBJECT_LIMIT_ACTIVE_PROCESS; - extendedInfo.BasicLimitInformation.ActiveProcessLimit = 1; + startupInfo.lpAttributeList = PhAllocate(attributeListLength); - if (!NT_SUCCESS(NtSetInformationJobObject( - jobObjectHandle, - JobObjectExtendedLimitInformation, - &extendedInfo, - sizeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION) - ))) + if (!InitializeProcThreadAttributeList(startupInfo.lpAttributeList, 1, 0, &attributeListLength)) goto CleanupExit; - if (!UpdateProcThreadAttribute(startupInfo.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_JOB_LIST, &(HANDLE){ jobObjectHandle }, sizeof(HANDLE), NULL, NULL)) + if (!UpdateProcThreadAttribute(startupInfo.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY, &(ULONG64){ DEFAULT_MITIGATION_POLICY_FLAGS }, sizeof(ULONG64), NULL, NULL)) goto CleanupExit; - if (NT_SUCCESS(PhCreateProcessWin32Ex( + commandline = PhConcatStringRef2(&commandlineSr, &commandlinePart); + success = NT_SUCCESS(PhCreateProcessWin32Ex( NULL, - NtCurrentPeb()->ProcessParameters->CommandLine.Buffer, + PhGetString(commandline), NULL, NULL, &startupInfo.StartupInfo, PH_CREATE_PROCESS_EXTENDED_STARTUPINFO | PH_CREATE_PROCESS_BREAKAWAY_FROM_JOB, NULL, - NULL, + NULL, NULL, NULL - ))) - { - success = TRUE; - } + )); CleanupExit: - if (jobObjectHandle) - NtClose(jobObjectHandle); + if (commandline) + PhDereferenceObject(commandline); if (startupInfo.lpAttributeList) { @@ -629,31 +641,6 @@ BOOLEAN PhInitializeMitigationPolicy( #endif } -VOID PhInitializeRestartPolicy( - VOID - ) -{ - PH_STRINGREF commandLine; - PH_STRINGREF fileName; - PH_STRINGREF arguments; - PPH_STRING argumentsString = NULL; - - // dmex: Restart process after a crash, hang, patch installation or - // after Windows 10 auto-restarts the machine due to an update. - - PhUnicodeStringToStringRef(&NtCurrentPeb()->ProcessParameters->CommandLine, &commandLine); - PhParseCommandLineFuzzy(&commandLine, &fileName, &arguments, NULL); - - if (arguments.Length > 0) - argumentsString = PhCreateString2(&arguments); - - // Note: Do not include the file name in the command line. - RegisterApplicationRestart(PhGetString(argumentsString), 0); - - if (argumentsString) - PhDereferenceObject(argumentsString); -} - NTSTATUS PhpReadSignature( _In_ PWSTR FileName, _Out_ PUCHAR *Signature, From 593e93888968e9b5324f49fb16133eb9cfa71a3d Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 29 Jan 2018 03:49:54 +1100 Subject: [PATCH 0732/2058] OnlineChecks: Fix crash #231 --- plugins/OnlineChecks/main.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/plugins/OnlineChecks/main.c b/plugins/OnlineChecks/main.c index 209c3d6d8d04..1aef27e43015 100644 --- a/plugins/OnlineChecks/main.c +++ b/plugins/OnlineChecks/main.c @@ -228,8 +228,9 @@ VOID NTAPI MenuItemCallback( break; case MENUITEM_HYBRIDANALYSIS_UPLOAD_SERVICE: UploadServiceToOnlineService(menuItem->Context, MENUITEM_HYBRIDANALYSIS_UPLOAD_SERVICE); - break; + break; case MENUITEM_VIRUSTOTAL_UPLOAD_FILE: + case MENUITEM_HYBRIDANALYSIS_UPLOAD_FILE: { static PH_FILETYPE_FILTER filters[] = { @@ -245,7 +246,15 @@ VOID NTAPI MenuItemCallback( { fileName = PH_AUTO(PhGetFileDialogFileName(fileDialog)); - UploadToOnlineService(fileName, MENUITEM_VIRUSTOTAL_UPLOAD); + switch (menuItem->Id) + { + case MENUITEM_VIRUSTOTAL_UPLOAD_FILE: + UploadToOnlineService(fileName, MENUITEM_VIRUSTOTAL_UPLOAD); + break; + case MENUITEM_HYBRIDANALYSIS_UPLOAD_FILE: + UploadToOnlineService(fileName, MENUITEM_HYBRIDANALYSIS_UPLOAD); + break; + } } PhFreeFileDialog(fileDialog); @@ -269,7 +278,7 @@ VOID NTAPI MainMenuInitializingCallback( onlineMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, 0, L"&Online Checks", NULL); PhInsertEMenuItem(onlineMenuItem, enableMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, ENABLE_SERVICE_VIRUSTOTAL, L"&Enable VirusTotal scanning", NULL), -1); PhInsertEMenuItem(onlineMenuItem, PhCreateEMenuSeparator(), -1); - PhInsertEMenuItem(onlineMenuItem, PhPluginCreateEMenuItem(PluginInstance, 0, MENUITEM_HYBRIDANALYSIS_UPLOAD, L"Upload file to &hybrid-analysis", NULL), -1); + PhInsertEMenuItem(onlineMenuItem, PhPluginCreateEMenuItem(PluginInstance, 0, MENUITEM_HYBRIDANALYSIS_UPLOAD_FILE, L"Upload file to &Hybrid-Analysis...", NULL), -1); PhInsertEMenuItem(onlineMenuItem, PhPluginCreateEMenuItem(PluginInstance, 0, MENUITEM_VIRUSTOTAL_UPLOAD_FILE, L"&Upload file to VirusTotal...", NULL), -1); //PhInsertEMenuItem(onlineMenuItem, PhPluginCreateEMenuItem(PluginInstance, 0, MENUITEM_VIRUSTOTAL_QUEUE, L"Upload unknown files to VirusTotal...", NULL), -1); PhInsertEMenuItem(menuInfo->Menu, onlineMenuItem, -1); From a2afd6364004e3457818a61dac30ed70d49ae1c9 Mon Sep 17 00:00:00 2001 From: ge0rdi Date: Sun, 28 Jan 2018 19:04:50 +0100 Subject: [PATCH 0733/2058] Get proper information for kernel modules (#226) * PhLoadRemoteMappedImageEx Similar to PhLoadRemoteMappedImage. Caller needs to provide own virtual memory reading function. * Get proper information for kernel modules Fixes "CF Guard", "ASLR" and "Entry point" columns for kernel modules. As well as relocated modules highlighting. --- ProcessHacker/modprv.c | 38 +++++++++++++++++++++++++++++--------- phlib/include/mapimg.h | 17 +++++++++++++++++ phlib/mapimg.c | 16 +++++++++++++--- 3 files changed, 59 insertions(+), 12 deletions(-) diff --git a/ProcessHacker/modprv.c b/ProcessHacker/modprv.c index 9a7589f415d6..dd0d901009c5 100644 --- a/ProcessHacker/modprv.c +++ b/ProcessHacker/modprv.c @@ -24,6 +24,7 @@ #include #include +#include #include #include @@ -486,7 +487,6 @@ VOID PhModuleProviderUpdate( moduleItem->FileName = module->FileName; PhPrintPointer(moduleItem->BaseAddressString, moduleItem->BaseAddress); - PhPrintPointer(moduleItem->EntryPointAddressString, moduleItem->EntryPoint); PhInitializeImageVersionInfo(&moduleItem->VersionInfo, moduleItem->FileName->Buffer); @@ -502,9 +502,16 @@ VOID PhModuleProviderUpdate( if (moduleItem->Type == PH_MODULE_TYPE_MODULE || moduleItem->Type == PH_MODULE_TYPE_WOW64_MODULE || - moduleItem->Type == PH_MODULE_TYPE_MAPPED_IMAGE) + moduleItem->Type == PH_MODULE_TYPE_MAPPED_IMAGE || + moduleItem->Type == PH_MODULE_TYPE_KERNEL_MODULE) { PH_REMOTE_MAPPED_IMAGE remoteMappedImage; + PPH_READ_VIRTUAL_MEMORY readVirtualMemory; + + if (moduleItem->Type == PH_MODULE_TYPE_KERNEL_MODULE) + readVirtualMemory = KphReadVirtualMemoryUnsafe; + else + readVirtualMemory = NtReadVirtualMemory; // Note: // On Windows 7 the LDRP_IMAGE_NOT_AT_BASE flag doesn't appear to be used @@ -516,30 +523,43 @@ VOID PhModuleProviderUpdate( moduleItem->Flags &= ~LDRP_IMAGE_NOT_AT_BASE; - if (NT_SUCCESS(PhLoadRemoteMappedImage(moduleProvider->ProcessHandle, moduleItem->BaseAddress, &remoteMappedImage))) + if (NT_SUCCESS(PhLoadRemoteMappedImageEx(moduleProvider->ProcessHandle, moduleItem->BaseAddress, readVirtualMemory, &remoteMappedImage))) { + ULONG_PTR imageBase = 0; + DWORD entryPoint = 0; + moduleItem->ImageTimeDateStamp = remoteMappedImage.NtHeaders->FileHeader.TimeDateStamp; moduleItem->ImageCharacteristics = remoteMappedImage.NtHeaders->FileHeader.Characteristics; if (remoteMappedImage.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) { - if ((ULONG_PTR)((PIMAGE_OPTIONAL_HEADER32)&remoteMappedImage.NtHeaders->OptionalHeader)->ImageBase != (ULONG_PTR)moduleItem->BaseAddress) - moduleItem->Flags |= LDRP_IMAGE_NOT_AT_BASE; + PIMAGE_OPTIONAL_HEADER32 optionalHeader = (PIMAGE_OPTIONAL_HEADER32)&remoteMappedImage.NtHeaders->OptionalHeader; - moduleItem->ImageDllCharacteristics = ((PIMAGE_OPTIONAL_HEADER32)&remoteMappedImage.NtHeaders->OptionalHeader)->DllCharacteristics; + imageBase = (ULONG_PTR)optionalHeader->ImageBase; + entryPoint = optionalHeader->AddressOfEntryPoint; + moduleItem->ImageDllCharacteristics = optionalHeader->DllCharacteristics; } else if (remoteMappedImage.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) { - if ((ULONG_PTR)((PIMAGE_OPTIONAL_HEADER64)&remoteMappedImage.NtHeaders->OptionalHeader)->ImageBase != (ULONG_PTR)moduleItem->BaseAddress) - moduleItem->Flags |= LDRP_IMAGE_NOT_AT_BASE; + PIMAGE_OPTIONAL_HEADER64 optionalHeader = (PIMAGE_OPTIONAL_HEADER64)&remoteMappedImage.NtHeaders->OptionalHeader; - moduleItem->ImageDllCharacteristics = ((PIMAGE_OPTIONAL_HEADER64)&remoteMappedImage.NtHeaders->OptionalHeader)->DllCharacteristics; + imageBase = (ULONG_PTR)optionalHeader->ImageBase; + entryPoint = optionalHeader->AddressOfEntryPoint; + moduleItem->ImageDllCharacteristics = optionalHeader->DllCharacteristics; } + if (imageBase != (ULONG_PTR)moduleItem->BaseAddress) + moduleItem->Flags |= LDRP_IMAGE_NOT_AT_BASE; + + if (entryPoint != 0) + moduleItem->EntryPoint = PTR_ADD_OFFSET(moduleItem->BaseAddress, entryPoint); + PhUnloadRemoteMappedImage(&remoteMappedImage); } } + PhPrintPointer(moduleItem->EntryPointAddressString, moduleItem->EntryPoint); + // remove CF Guard flag if CFG mitigation is not enabled for the process if (!moduleProvider->ControlFlowGuardEnabled) moduleItem->ImageDllCharacteristics &= ~IMAGE_DLLCHARACTERISTICS_GUARD_CF; diff --git a/phlib/include/mapimg.h b/phlib/include/mapimg.h index 95f9a90faf45..0d41efbb4926 100644 --- a/phlib/include/mapimg.h +++ b/phlib/include/mapimg.h @@ -156,6 +156,23 @@ PhLoadRemoteMappedImage( _Out_ PPH_REMOTE_MAPPED_IMAGE RemoteMappedImage ); +typedef NTSTATUS (NTAPI *PPH_READ_VIRTUAL_MEMORY)( + _In_ HANDLE ProcessHandle, + _In_opt_ PVOID BaseAddress, + _Out_writes_bytes_(BufferSize) PVOID Buffer, + _In_ SIZE_T BufferSize, + _Out_opt_ PSIZE_T NumberOfBytesRead + ); + +NTSTATUS +NTAPI +PhLoadRemoteMappedImageEx( + _In_ HANDLE ProcessHandle, + _In_ PVOID ViewBase, + _In_ PPH_READ_VIRTUAL_MEMORY ReadVirtualMemory, + _Out_ PPH_REMOTE_MAPPED_IMAGE RemoteMappedImage + ); + NTSTATUS NTAPI PhUnloadRemoteMappedImage( diff --git a/phlib/mapimg.c b/phlib/mapimg.c index 8e8da7003868..12e2203372e9 100644 --- a/phlib/mapimg.c +++ b/phlib/mapimg.c @@ -501,6 +501,16 @@ NTSTATUS PhLoadRemoteMappedImage( _In_ PVOID ViewBase, _Out_ PPH_REMOTE_MAPPED_IMAGE RemoteMappedImage ) +{ + return PhLoadRemoteMappedImageEx(ProcessHandle, ViewBase, NtReadVirtualMemory, RemoteMappedImage); +} + +NTSTATUS PhLoadRemoteMappedImageEx( + _In_ HANDLE ProcessHandle, + _In_ PVOID ViewBase, + _In_ PPH_READ_VIRTUAL_MEMORY ReadVirtualMemory, + _Out_ PPH_REMOTE_MAPPED_IMAGE RemoteMappedImage + ) { NTSTATUS status; IMAGE_DOS_HEADER dosHeader; @@ -510,7 +520,7 @@ NTSTATUS PhLoadRemoteMappedImage( RemoteMappedImage->ViewBase = ViewBase; - status = NtReadVirtualMemory( + status = ReadVirtualMemory( ProcessHandle, ViewBase, &dosHeader, @@ -533,7 +543,7 @@ NTSTATUS PhLoadRemoteMappedImage( if (ntHeadersOffset == 0 || ntHeadersOffset >= 0x10000000) return STATUS_INVALID_IMAGE_FORMAT; - status = NtReadVirtualMemory( + status = ReadVirtualMemory( ProcessHandle, PTR_ADD_OFFSET(ViewBase, ntHeadersOffset), &ntHeaders, @@ -569,7 +579,7 @@ NTSTATUS PhLoadRemoteMappedImage( RemoteMappedImage->NtHeaders = PhAllocate(ntHeadersSize); - status = NtReadVirtualMemory( + status = ReadVirtualMemory( ProcessHandle, PTR_ADD_OFFSET(ViewBase, ntHeadersOffset), RemoteMappedImage->NtHeaders, From 9679e5d151f099c837c41836172bcb6a1e4c9a01 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 29 Jan 2018 17:55:54 +1100 Subject: [PATCH 0734/2058] Add window context functions --- phlib/guisup.c | 101 +++++++++++++++++++++++++++++++++++++++++ phlib/include/guisup.h | 24 ++++++++++ 2 files changed, 125 insertions(+) diff --git a/phlib/guisup.c b/phlib/guisup.c index 1753b9fd85da..0512215a6bb1 100644 --- a/phlib/guisup.c +++ b/phlib/guisup.c @@ -31,6 +31,22 @@ #define SCALE_DPI(Value) PhMultiplyDivide(Value, PhGlobalDpi, 96) +BOOLEAN NTAPI PhpWindowContextHashtableEqualFunction( + _In_ PVOID Entry1, + _In_ PVOID Entry2 + ); + +ULONG NTAPI PhpWindowContextHashtableHashFunction( + _In_ PVOID Entry + ); + +typedef struct _PH_WINDOW_PROPERTY_CONTEXT +{ + ULONG PropertyHash; + HWND WindowHandle; + PVOID Context; +} PH_WINDOW_PROPERTY_CONTEXT, *PPH_WINDOW_PROPERTY_CONTEXT; + _IsImmersiveProcess IsImmersiveProcess_I; _RunFileDlg RunFileDlg; _SHAutoComplete SHAutoComplete_I; @@ -39,6 +55,9 @@ static PH_INITONCE SharedIconCacheInitOnce = PH_INITONCE_INIT; static PPH_HASHTABLE SharedIconCacheHashtable; static PH_QUEUED_LOCK SharedIconCacheLock = PH_QUEUED_LOCK_INIT; +static PPH_HASHTABLE WindowContextHashTable = NULL; +static PH_QUEUED_LOCK WindowContextListLock = PH_QUEUED_LOCK_INIT; + VOID PhGuiSupportInitialization( VOID ) @@ -47,6 +66,13 @@ VOID PhGuiSupportInitialization( PVOID shell32Handle; PVOID shlwapiHandle; + WindowContextHashTable = PhCreateHashtable( + sizeof(PH_WINDOW_PROPERTY_CONTEXT), + PhpWindowContextHashtableEqualFunction, + PhpWindowContextHashtableHashFunction, + 10 + ); + if (hdc = GetDC(NULL)) { PhGlobalDpi = GetDeviceCaps(hdc, LOGPIXELSY); @@ -1208,3 +1234,78 @@ VOID PhLayoutManagerLayout( Manager->RootItem.DeferHandle = NULL; } } + +static BOOLEAN NTAPI PhpWindowContextHashtableEqualFunction( + _In_ PVOID Entry1, + _In_ PVOID Entry2 + ) +{ + PPH_WINDOW_PROPERTY_CONTEXT entry1 = Entry1; + PPH_WINDOW_PROPERTY_CONTEXT entry2 = Entry2; + + return + entry1->WindowHandle == entry2->WindowHandle && + entry1->PropertyHash == entry2->PropertyHash; +} + +static ULONG NTAPI PhpWindowContextHashtableHashFunction( + _In_ PVOID Entry + ) +{ + PPH_WINDOW_PROPERTY_CONTEXT entry = Entry; + + return PhHashIntPtr((ULONG_PTR)entry->WindowHandle) ^ PhHashInt32(entry->PropertyHash); +} + +PVOID PhGetWindowContext( + _In_ HWND WindowHandle, + _In_ ULONG PropertyHash + ) +{ + PH_WINDOW_PROPERTY_CONTEXT lookupEntry; + PPH_WINDOW_PROPERTY_CONTEXT entry; + + lookupEntry.WindowHandle = WindowHandle; + lookupEntry.PropertyHash = PropertyHash; + + PhAcquireQueuedLockShared(&WindowContextListLock); + entry = PhFindEntryHashtable(WindowContextHashTable, &lookupEntry); + PhReleaseQueuedLockShared(&WindowContextListLock); + + if (entry) + return entry->Context; + else + return NULL; +} + +VOID PhSetWindowContext( + _In_ HWND WindowHandle, + _In_ ULONG PropertyHash, + _In_ PVOID Context + ) +{ + PH_WINDOW_PROPERTY_CONTEXT entry; + + entry.WindowHandle = WindowHandle; + entry.PropertyHash = PropertyHash; + entry.Context = Context; + + PhAcquireQueuedLockExclusive(&WindowContextListLock); + PhAddEntryHashtable(WindowContextHashTable, &entry); + PhReleaseQueuedLockExclusive(&WindowContextListLock); +} + +VOID PhRemoveWindowContext( + _In_ HWND WindowHandle, + _In_ ULONG PropertyHash + ) +{ + PH_WINDOW_PROPERTY_CONTEXT lookupEntry; + + lookupEntry.WindowHandle = WindowHandle; + lookupEntry.PropertyHash = PropertyHash; + + PhAcquireQueuedLockExclusive(&WindowContextListLock); + PhRemoveEntryHashtable(WindowContextHashTable, &lookupEntry); + PhReleaseQueuedLockExclusive(&WindowContextListLock); +} diff --git a/phlib/include/guisup.h b/phlib/include/guisup.h index f7d7abb6d655..b999a4e38953 100644 --- a/phlib/include/guisup.h +++ b/phlib/include/guisup.h @@ -457,6 +457,30 @@ VOID PhLayoutManagerLayout( _Inout_ PPH_LAYOUT_MANAGER Manager ); +#define PH_WINDOW_CONTEXT_DEFAULT 0xFFFF + +PHLIBAPI +PVOID +PhGetWindowContext( + _In_ HWND WindowHandle, + _In_ ULONG PropertyHash + ); + +PHLIBAPI +VOID +PhSetWindowContext( + _In_ HWND WindowHandle, + _In_ ULONG PropertyHash, + _In_ PVOID Context + ); + +PHLIBAPI +VOID +PhRemoveWindowContext( + _In_ HWND WindowHandle, + _In_ ULONG PropertyHash + ); + FORCEINLINE VOID PhResizingMinimumSize( _Inout_ PRECT Rect, _In_ WPARAM Edge, From 019e1a1d835cf416cc783ab473c7d81b3bb12164 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 29 Jan 2018 18:35:29 +1100 Subject: [PATCH 0735/2058] Improve window property callbacks --- ProcessHacker/affinity.c | 6 ++-- ProcessHacker/appsup.c | 7 ---- ProcessHacker/chcol.c | 6 ++-- ProcessHacker/chdlg.c | 6 ++-- ProcessHacker/chproc.c | 6 ++-- ProcessHacker/colsetmgr.c | 6 ++-- ProcessHacker/findobj.c | 6 ++-- ProcessHacker/gdihndl.c | 23 +++++++++--- ProcessHacker/hndlprp.c | 23 +++++++++--- ProcessHacker/include/appsup.h | 16 +++------ ProcessHacker/include/procprpp.h | 7 ++-- ProcessHacker/infodlg.c | 58 ++++++++++++++---------------- ProcessHacker/jobprp.c | 3 +- ProcessHacker/mdump.c | 30 +++++++++------- ProcessHacker/memedit.c | 6 ++-- ProcessHacker/memprot.c | 6 ++-- ProcessHacker/memrslt.c | 6 ++-- ProcessHacker/memsrch.c | 20 +++++++++-- ProcessHacker/miniinfo.c | 20 ++++++++--- ProcessHacker/mtgndlg.c | 7 ++-- ProcessHacker/netstk.c | 62 ++++++++++++++++---------------- ProcessHacker/ntobjprp.c | 3 +- ProcessHacker/options.c | 6 ++-- ProcessHacker/plugman.c | 18 +++++----- ProcessHacker/procprp.c | 6 ++-- ProcessHacker/procrec.c | 6 ++-- ProcessHacker/prpgenv.c | 6 ++-- ProcessHacker/prpgjob.c | 6 ++-- ProcessHacker/prpgtok.c | 6 ++-- ProcessHacker/runas.c | 6 ++-- ProcessHacker/sessmsg.c | 7 ++-- ProcessHacker/sessprp.c | 6 ---- ProcessHacker/sessshad.c | 7 ++-- ProcessHacker/splitter.c | 9 +++-- ProcessHacker/srvctl.c | 6 ++-- ProcessHacker/srvprp.c | 28 +++++++++------ ProcessHacker/thrdstk.c | 12 +++---- ProcessHacker/tokprp.c | 3 +- 38 files changed, 257 insertions(+), 214 deletions(-) diff --git a/ProcessHacker/affinity.c b/ProcessHacker/affinity.c index 48c3a19f96c6..a46695abf7b9 100644 --- a/ProcessHacker/affinity.c +++ b/ProcessHacker/affinity.c @@ -118,7 +118,7 @@ static INT_PTR CALLBACK PhpProcessAffinityDlgProc( ULONG_PTR affinityMask; ULONG i; - SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)context); + PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context); PhCenterWindow(hwndDlg, GetParent(hwndDlg)); systemAffinityMask = 0; @@ -227,7 +227,7 @@ static INT_PTR CALLBACK PhpProcessAffinityDlgProc( break; case WM_DESTROY: { - RemoveProp(hwndDlg, PhMakeContextAtom()); + PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); } break; case WM_COMMAND: @@ -240,7 +240,7 @@ static INT_PTR CALLBACK PhpProcessAffinityDlgProc( case IDOK: { NTSTATUS status; - PAFFINITY_DIALOG_CONTEXT context = (PAFFINITY_DIALOG_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom()); + PAFFINITY_DIALOG_CONTEXT context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); ULONG i; ULONG_PTR affinityMask; diff --git a/ProcessHacker/appsup.c b/ProcessHacker/appsup.c index 9b389494655f..b4d9388062fc 100644 --- a/ProcessHacker/appsup.c +++ b/ProcessHacker/appsup.c @@ -1109,13 +1109,6 @@ VOID PhLoadSymbolProviderOptions( PhDereferenceObject(searchPath); } -PWSTR PhMakeContextAtom( - VOID - ) -{ - PH_DEFINE_MAKE_ATOM(L"PH2_Context"); -} - /** * Copies a string into a NMLVGETINFOTIP structure. * diff --git a/ProcessHacker/chcol.c b/ProcessHacker/chcol.c index 75e453219617..96b422507398 100644 --- a/ProcessHacker/chcol.c +++ b/ProcessHacker/chcol.c @@ -110,11 +110,11 @@ INT_PTR CALLBACK PhpColumnsDlgProc( if (uMsg == WM_INITDIALOG) { context = (PCOLUMNS_DIALOG_CONTEXT)lParam; - SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)context); + PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context); } else { - context = (PCOLUMNS_DIALOG_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom()); + context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); } if (!context) @@ -202,7 +202,7 @@ INT_PTR CALLBACK PhpColumnsDlgProc( for (i = 0; i < context->Columns->Count; i++) PhFree(context->Columns->Items[i]); - RemoveProp(hwndDlg, PhMakeContextAtom()); + PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); } break; case WM_COMMAND: diff --git a/ProcessHacker/chdlg.c b/ProcessHacker/chdlg.c index b7acd39a9ed4..e9d8ddc22863 100644 --- a/ProcessHacker/chdlg.c +++ b/ProcessHacker/chdlg.c @@ -108,7 +108,7 @@ INT_PTR CALLBACK PhpChoiceDlgProc( RECT rect; ULONG diff; - SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)context); + PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context); PhCenterWindow(hwndDlg, GetParent(hwndDlg)); SetWindowText(hwndDlg, context->Title); @@ -267,7 +267,7 @@ INT_PTR CALLBACK PhpChoiceDlgProc( break; case WM_DESTROY: { - RemoveProp(hwndDlg, PhMakeContextAtom()); + PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); } break; case WM_COMMAND: @@ -279,7 +279,7 @@ INT_PTR CALLBACK PhpChoiceDlgProc( break; case IDOK: { - PCHOICE_DIALOG_CONTEXT context = (PCHOICE_DIALOG_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom()); + PCHOICE_DIALOG_CONTEXT context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); PPH_STRING selectedChoice; if ((context->Flags & PH_CHOICE_DIALOG_TYPE_MASK) != PH_CHOICE_DIALOG_PASSWORD) diff --git a/ProcessHacker/chproc.c b/ProcessHacker/chproc.c index e9f3c532d482..05d45796d3cf 100644 --- a/ProcessHacker/chproc.c +++ b/ProcessHacker/chproc.c @@ -184,15 +184,15 @@ INT_PTR CALLBACK PhpChooseProcessDlgProc( if (uMsg == WM_INITDIALOG) { context = (PCHOOSE_PROCESS_DIALOG_CONTEXT)lParam; - SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)context); + PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context); } else { - context = (PCHOOSE_PROCESS_DIALOG_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom()); + context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); if (uMsg == WM_DESTROY) { - RemoveProp(hwndDlg, PhMakeContextAtom()); + PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); } } diff --git a/ProcessHacker/colsetmgr.c b/ProcessHacker/colsetmgr.c index 901dd3628c4c..26516aa53d30 100644 --- a/ProcessHacker/colsetmgr.c +++ b/ProcessHacker/colsetmgr.c @@ -377,11 +377,11 @@ INT_PTR CALLBACK PhpColumnSetEditorDlgProc( context->SettingName = PhCreateString((PWSTR)lParam); - SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)context); + PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context); } else { - context = (PCOLUMNSET_DIALOG_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom()); + context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); } if (!context) @@ -424,7 +424,7 @@ INT_PTR CALLBACK PhpColumnSetEditorDlgProc( { PhDeleteColumnSetList(context->ColumnSetList); - RemoveProp(hwndDlg, PhMakeContextAtom()); + PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); PhFree(context); } break; diff --git a/ProcessHacker/findobj.c b/ProcessHacker/findobj.c index 9b531b0fb34e..ff8692d61265 100644 --- a/ProcessHacker/findobj.c +++ b/ProcessHacker/findobj.c @@ -1100,11 +1100,11 @@ INT_PTR CALLBACK PhpFindObjectsDlgProc( context = PhCreateAlloc(sizeof(PH_HANDLE_SEARCH_CONTEXT)); memset(context, 0, sizeof(PH_HANDLE_SEARCH_CONTEXT)); - SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)context); + PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context); } else { - context = (PPH_HANDLE_SEARCH_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom()); + context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); } if (!context) @@ -1217,6 +1217,8 @@ INT_PTR CALLBACK PhpFindObjectsDlgProc( PhClearList(context->SearchResults); } + PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); + PhDereferenceObject(context); PostQuitMessage(0); diff --git a/ProcessHacker/gdihndl.c b/ProcessHacker/gdihndl.c index e5d62f7018ae..762c404c1e4c 100644 --- a/ProcessHacker/gdihndl.c +++ b/ProcessHacker/gdihndl.c @@ -320,17 +320,30 @@ INT_PTR CALLBACK PhpGdiHandlesDlgProc( _In_ LPARAM lParam ) { + PGDI_HANDLES_CONTEXT context = NULL; + + if (uMsg == WM_INITDIALOG) + { + context = (PGDI_HANDLES_CONTEXT)lParam; + + PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context); + } + else + { + context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); + } + + if (!context) + return FALSE; + switch (uMsg) { case WM_INITDIALOG: { - PGDI_HANDLES_CONTEXT context = (PGDI_HANDLES_CONTEXT)lParam; HWND lvHandle; PhCenterWindow(hwndDlg, GetParent(hwndDlg)); - SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)context); - lvHandle = GetDlgItem(hwndDlg, IDC_LIST); PhSetListViewStyle(lvHandle, FALSE, TRUE); @@ -351,7 +364,7 @@ INT_PTR CALLBACK PhpGdiHandlesDlgProc( break; case WM_DESTROY: { - RemoveProp(hwndDlg, PhMakeContextAtom()); + PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); } break; case WM_COMMAND: @@ -364,7 +377,7 @@ INT_PTR CALLBACK PhpGdiHandlesDlgProc( break; case IDC_REFRESH: { - PhpRefreshGdiHandles(hwndDlg, (PGDI_HANDLES_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom())); + PhpRefreshGdiHandles(hwndDlg, context); } break; } diff --git a/ProcessHacker/hndlprp.c b/ProcessHacker/hndlprp.c index e98ce8c949ad..f9de4930cf80 100644 --- a/ProcessHacker/hndlprp.c +++ b/ProcessHacker/hndlprp.c @@ -220,12 +220,27 @@ INT_PTR CALLBACK PhpHandleGeneralDlgProc( _In_ LPARAM lParam ) { + PHANDLE_PROPERTIES_CONTEXT context; + + if (uMsg == WM_INITDIALOG) + { + LPPROPSHEETPAGE propSheetPage = (LPPROPSHEETPAGE)lParam; + context = (PHANDLE_PROPERTIES_CONTEXT)propSheetPage->lParam; + + PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context); + } + else + { + context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); + } + + if (!context) + return FALSE; + switch (uMsg) { case WM_INITDIALOG: { - LPPROPSHEETPAGE propSheetPage = (LPPROPSHEETPAGE)lParam; - PHANDLE_PROPERTIES_CONTEXT context = (PHANDLE_PROPERTIES_CONTEXT)propSheetPage->lParam; PPH_ACCESS_ENTRY accessEntries; ULONG numberOfAccessEntries; HANDLE processHandle; @@ -235,8 +250,6 @@ INT_PTR CALLBACK PhpHandleGeneralDlgProc( // HACK PhCenterWindow(GetParent(hwndDlg), GetParent(GetParent(hwndDlg))); - SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)context); - SetDlgItemText(hwndDlg, IDC_NAME, PhGetString(context->HandleItem->BestObjectName)); SetDlgItemText(hwndDlg, IDC_TYPE, context->HandleItem->TypeName->Buffer); SetDlgItemText(hwndDlg, IDC_ADDRESS, context->HandleItem->ObjectString); @@ -315,7 +328,7 @@ INT_PTR CALLBACK PhpHandleGeneralDlgProc( break; case WM_DESTROY: { - RemoveProp(hwndDlg, PhMakeContextAtom()); + PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); } break; case WM_NOTIFY: diff --git a/ProcessHacker/include/appsup.h b/ProcessHacker/include/appsup.h index fd79e97e2bd3..335339db4ce7 100644 --- a/ProcessHacker/include/appsup.h +++ b/ProcessHacker/include/appsup.h @@ -179,13 +179,7 @@ NTAPI PhLoadSymbolProviderOptions( _Inout_ PPH_SYMBOL_PROVIDER SymbolProvider ); -// end_phapppub -PWSTR PhMakeContextAtom( - VOID - ); - -// begin_phapppub PHAPPAPI VOID NTAPI @@ -458,7 +452,7 @@ FORCEINLINE PVOID PhpGenericPropertyPageHeader( _In_ UINT uMsg, _In_ WPARAM wParam, _In_ LPARAM lParam, - _In_ PWSTR ContextName + _In_ ULONG ContextHash ) { PVOID context; @@ -470,18 +464,18 @@ FORCEINLINE PVOID PhpGenericPropertyPageHeader( LPPROPSHEETPAGE propSheetPage = (LPPROPSHEETPAGE)lParam; context = (PVOID)propSheetPage->lParam; - SetProp(hwndDlg, ContextName, (HANDLE)context); + PhSetWindowContext(hwndDlg, ContextHash, context); } break; case WM_DESTROY: { - context = (PVOID)GetProp(hwndDlg, ContextName); - RemoveProp(hwndDlg, ContextName); + context = PhGetWindowContext(hwndDlg, ContextHash); + PhRemoveWindowContext(hwndDlg, ContextHash); } break; default: { - context = (PVOID)GetProp(hwndDlg, ContextName); + context = PhGetWindowContext(hwndDlg, ContextHash); } break; } diff --git a/ProcessHacker/include/procprpp.h b/ProcessHacker/include/procprpp.h index b38f340a7a58..f1878dead5a4 100644 --- a/ProcessHacker/include/procprpp.h +++ b/ProcessHacker/include/procprpp.h @@ -63,11 +63,10 @@ FORCEINLINE BOOLEAN PhpPropPageDlgProcHeader( if (uMsg == WM_INITDIALOG) { - // Save the context. - SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)lParam); + PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, (PVOID)lParam); } - propSheetPage = (LPPROPSHEETPAGE)GetProp(hwndDlg, PhMakeContextAtom()); + propSheetPage = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); if (!propSheetPage) return FALSE; @@ -83,7 +82,7 @@ FORCEINLINE VOID PhpPropPageDlgProcDestroy( _In_ HWND hwndDlg ) { - RemoveProp(hwndDlg, PhMakeContextAtom()); + PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); } #define SET_BUTTON_ICON(Id, Icon) \ diff --git a/ProcessHacker/infodlg.c b/ProcessHacker/infodlg.c index 73b8fa1916d3..c2faefa86b87 100644 --- a/ProcessHacker/infodlg.c +++ b/ProcessHacker/infodlg.c @@ -28,6 +28,7 @@ typedef struct _INFORMATION_CONTEXT { PWSTR String; ULONG Flags; + PH_LAYOUT_MANAGER LayoutManager; } INFORMATION_CONTEXT, *PINFORMATION_CONTEXT; static RECT MinimumSize = { -1, -1, -1, -1 }; @@ -39,13 +40,25 @@ static INT_PTR CALLBACK PhpInformationDlgProc( _In_ LPARAM lParam ) { + PINFORMATION_CONTEXT context; + + if (uMsg == WM_INITDIALOG) + { + context = (PINFORMATION_CONTEXT)lParam; + PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context); + } + else + { + context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); + } + + if (!context) + return FALSE; + switch (uMsg) { case WM_INITDIALOG: { - PINFORMATION_CONTEXT context = (PINFORMATION_CONTEXT)lParam; - PPH_LAYOUT_MANAGER layoutManager; - SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER))); SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER))); @@ -53,16 +66,11 @@ static INT_PTR CALLBACK PhpInformationDlgProc( SetDlgItemText(hwndDlg, IDC_TEXT, context->String); - layoutManager = PhAllocate(sizeof(PH_LAYOUT_MANAGER)); - PhInitializeLayoutManager(layoutManager, hwndDlg); - PhAddLayoutItem(layoutManager, GetDlgItem(hwndDlg, IDC_TEXT), NULL, - PH_ANCHOR_ALL); - PhAddLayoutItem(layoutManager, GetDlgItem(hwndDlg, IDOK), NULL, - PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); - PhAddLayoutItem(layoutManager, GetDlgItem(hwndDlg, IDC_COPY), NULL, - PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); - PhAddLayoutItem(layoutManager, GetDlgItem(hwndDlg, IDC_SAVE), NULL, - PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); + PhInitializeLayoutManager(&context->LayoutManager, hwndDlg); + PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_TEXT), NULL, PH_ANCHOR_ALL); + PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDOK), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); + PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_COPY), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); + PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_SAVE), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); if (MinimumSize.left == -1) { @@ -77,21 +85,14 @@ static INT_PTR CALLBACK PhpInformationDlgProc( MinimumSize.left = 0; } - SetProp(hwndDlg, L"LayoutManager", (HANDLE)layoutManager); - SetProp(hwndDlg, L"String", (HANDLE)context->String); - SendMessage(hwndDlg, WM_NEXTDLGCTL, (LPARAM)GetDlgItem(hwndDlg, IDOK), TRUE); } break; case WM_DESTROY: { - PPH_LAYOUT_MANAGER layoutManager; + PhDeleteLayoutManager(&context->LayoutManager); - layoutManager = (PPH_LAYOUT_MANAGER)GetProp(hwndDlg, L"LayoutManager"); - PhDeleteLayoutManager(layoutManager); - PhFree(layoutManager); - RemoveProp(hwndDlg, L"String"); - RemoveProp(hwndDlg, L"LayoutManager"); + PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); } break; case WM_COMMAND: @@ -107,22 +108,20 @@ static INT_PTR CALLBACK PhpInformationDlgProc( HWND editControl; LONG selStart; LONG selEnd; - PWSTR buffer; PH_STRINGREF string; editControl = GetDlgItem(hwndDlg, IDC_TEXT); SendMessage(editControl, EM_GETSEL, (WPARAM)&selStart, (LPARAM)&selEnd); - buffer = (PWSTR)GetProp(hwndDlg, L"String"); if (selStart == selEnd) { // Select and copy the entire string. - PhInitializeStringRefLongHint(&string, buffer); + PhInitializeStringRefLongHint(&string, context->String); Edit_SetSel(editControl, 0, -1); } else { - string.Buffer = buffer + selStart; + string.Buffer = context->String + selStart; string.Length = (selEnd - selStart) * 2; } @@ -164,7 +163,7 @@ static INT_PTR CALLBACK PhpInformationDlgProc( PH_STRINGREF string; PhWriteStringAsUtf8FileStream(fileStream, &PhUnicodeByteOrderMark); - PhInitializeStringRef(&string, (PWSTR)GetProp(hwndDlg, L"String")); + PhInitializeStringRef(&string, context->String); PhWriteStringAsUtf8FileStream(fileStream, &string); PhDereferenceObject(fileStream); } @@ -181,10 +180,7 @@ static INT_PTR CALLBACK PhpInformationDlgProc( break; case WM_SIZE: { - PPH_LAYOUT_MANAGER layoutManager; - - layoutManager = (PPH_LAYOUT_MANAGER)GetProp(hwndDlg, L"LayoutManager"); - PhLayoutManagerLayout(layoutManager); + PhLayoutManagerLayout(&context->LayoutManager); } break; case WM_SIZING: diff --git a/ProcessHacker/jobprp.c b/ProcessHacker/jobprp.c index a8151338c781..0ccbf6be37d7 100644 --- a/ProcessHacker/jobprp.c +++ b/ProcessHacker/jobprp.c @@ -147,8 +147,7 @@ FORCEINLINE PJOB_PAGE_CONTEXT PhpJobPageHeader( _In_ LPARAM lParam ) { - return (PJOB_PAGE_CONTEXT)PhpGenericPropertyPageHeader( - hwndDlg, uMsg, wParam, lParam, L"JobPageContext"); + return PhpGenericPropertyPageHeader(hwndDlg, uMsg, wParam, lParam, 1); } static VOID PhpAddLimit( diff --git a/ProcessHacker/mdump.c b/ProcessHacker/mdump.c index e4bf2a239f32..f923a0f01ee4 100644 --- a/ProcessHacker/mdump.c +++ b/ProcessHacker/mdump.c @@ -362,14 +362,27 @@ INT_PTR CALLBACK PhpProcessMiniDumpDlgProc( _In_ LPARAM lParam ) { + PPROCESS_MINIDUMP_CONTEXT context; + + if (uMsg == WM_INITDIALOG) + { + context = (PPROCESS_MINIDUMP_CONTEXT)lParam; + + PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context); + } + else + { + context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); + } + + if (!context) + return FALSE; + switch (uMsg) { case WM_INITDIALOG: { - PPROCESS_MINIDUMP_CONTEXT context = (PPROCESS_MINIDUMP_CONTEXT)lParam; - PhCenterWindow(hwndDlg, GetParent(hwndDlg)); - SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)context); SetDlgItemText(hwndDlg, IDC_PROGRESSTEXT, L"Creating the dump file..."); @@ -385,7 +398,7 @@ INT_PTR CALLBACK PhpProcessMiniDumpDlgProc( break; case WM_DESTROY: { - RemoveProp(hwndDlg, PhMakeContextAtom()); + PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); } break; case WM_COMMAND: @@ -394,9 +407,6 @@ INT_PTR CALLBACK PhpProcessMiniDumpDlgProc( { case IDCANCEL: { - PPROCESS_MINIDUMP_CONTEXT context = - (PPROCESS_MINIDUMP_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom()); - EnableWindow(GetDlgItem(hwndDlg, IDCANCEL), FALSE); context->Stop = TRUE; } @@ -408,8 +418,6 @@ INT_PTR CALLBACK PhpProcessMiniDumpDlgProc( { if (wParam == 1) { - PPROCESS_MINIDUMP_CONTEXT context = - (PPROCESS_MINIDUMP_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom()); ULONG64 currentTickCount; currentTickCount = NtGetTickCount64(); @@ -429,10 +437,6 @@ INT_PTR CALLBACK PhpProcessMiniDumpDlgProc( break; case WM_PH_MINIDUMP_STATUS_UPDATE: { - PPROCESS_MINIDUMP_CONTEXT context; - - context = (PPROCESS_MINIDUMP_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom()); - switch (wParam) { case PH_MINIDUMP_STATUS_UPDATE: diff --git a/ProcessHacker/memedit.c b/ProcessHacker/memedit.c index 1d78c2caa17b..5690bf817dea 100644 --- a/ProcessHacker/memedit.c +++ b/ProcessHacker/memedit.c @@ -172,12 +172,12 @@ INT_PTR CALLBACK PhpMemoryEditorDlgProc( if (uMsg != WM_INITDIALOG) { - context = GetProp(hwndDlg, PhMakeContextAtom()); + context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); } else { context = (PMEMORY_EDITOR_CONTEXT)lParam; - SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)context); + PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context); } if (!context) @@ -328,7 +328,7 @@ INT_PTR CALLBACK PhpMemoryEditorDlgProc( PhUnregisterDialog(hwndDlg); } - RemoveProp(hwndDlg, PhMakeContextAtom()); + PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); PhDeleteLayoutManager(&context->LayoutManager); diff --git a/ProcessHacker/memprot.c b/ProcessHacker/memprot.c index 17b6d09f09e3..15b2bf0e563d 100644 --- a/ProcessHacker/memprot.c +++ b/ProcessHacker/memprot.c @@ -71,7 +71,7 @@ static INT_PTR CALLBACK PhpMemoryProtectDlgProc( { case WM_INITDIALOG: { - SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)lParam); + PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, (PVOID)lParam); PhCenterWindow(hwndDlg, GetParent(hwndDlg)); @@ -97,7 +97,7 @@ static INT_PTR CALLBACK PhpMemoryProtectDlgProc( break; case WM_DESTROY: { - RemoveProp(hwndDlg, PhMakeContextAtom()); + PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); } break; case WM_COMMAND: @@ -110,7 +110,7 @@ static INT_PTR CALLBACK PhpMemoryProtectDlgProc( case IDOK: { NTSTATUS status; - PMEMORY_PROTECT_CONTEXT context = (PMEMORY_PROTECT_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom()); + PMEMORY_PROTECT_CONTEXT context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); HANDLE processHandle; ULONG64 protect; diff --git a/ProcessHacker/memrslt.c b/ProcessHacker/memrslt.c index f4b3140a86d9..8d36878e31b9 100644 --- a/ProcessHacker/memrslt.c +++ b/ProcessHacker/memrslt.c @@ -263,12 +263,12 @@ INT_PTR CALLBACK PhpMemoryResultsDlgProc( if (uMsg != WM_INITDIALOG) { - context = GetProp(hwndDlg, PhMakeContextAtom()); + context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); } else { context = (PMEMORY_RESULTS_CONTEXT)lParam; - SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)context); + PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context); } if (!context) @@ -362,7 +362,7 @@ INT_PTR CALLBACK PhpMemoryResultsDlgProc( PhDeleteLayoutManager(&context->LayoutManager); PhUnregisterDialog(hwndDlg); - RemoveProp(hwndDlg, PhMakeContextAtom()); + PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); PhDereferenceMemoryResults((PPH_MEMORY_RESULT *)context->Results->Items, context->Results->Count); PhDereferenceObject(context->Results); diff --git a/ProcessHacker/memsrch.c b/ProcessHacker/memsrch.c index 1d38f573cf66..fe66dd890010 100644 --- a/ProcessHacker/memsrch.c +++ b/ProcessHacker/memsrch.c @@ -540,12 +540,27 @@ INT_PTR CALLBACK PhpMemoryStringDlgProc( _In_ LPARAM lParam ) { + PMEMORY_STRING_CONTEXT context; + + if (uMsg == WM_INITDIALOG) + { + context = (PMEMORY_STRING_CONTEXT)lParam; + + PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context); + } + else + { + context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); + } + + if (!context) + return FALSE; + switch (uMsg) { case WM_INITDIALOG: { PhCenterWindow(hwndDlg, GetParent(hwndDlg)); - SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)lParam); SetDlgItemText(hwndDlg, IDC_MINIMUMLENGTH, L"10"); Button_SetCheck(GetDlgItem(hwndDlg, IDC_DETECTUNICODE), BST_CHECKED); @@ -554,7 +569,7 @@ INT_PTR CALLBACK PhpMemoryStringDlgProc( break; case WM_DESTROY: { - RemoveProp(hwndDlg, PhMakeContextAtom()); + PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); } break; case WM_COMMAND: @@ -566,7 +581,6 @@ INT_PTR CALLBACK PhpMemoryStringDlgProc( break; case IDOK: { - PMEMORY_STRING_CONTEXT context = (PMEMORY_STRING_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom()); ULONG64 minimumLength = 10; PhStringToInteger64(&PhaGetDlgItemText(hwndDlg, IDC_MINIMUMLENGTH)->sr, 0, &minimumLength); diff --git a/ProcessHacker/miniinfo.c b/ProcessHacker/miniinfo.c index adf3e23e627b..599135aba062 100644 --- a/ProcessHacker/miniinfo.c +++ b/ProcessHacker/miniinfo.c @@ -1278,7 +1278,20 @@ INT_PTR CALLBACK PhMipListSectionDialogProc( _In_ LPARAM lParam ) { - PPH_MINIINFO_LIST_SECTION listSection = (PPH_MINIINFO_LIST_SECTION)GetProp(hwndDlg, PhMakeContextAtom()); + PPH_MINIINFO_LIST_SECTION listSection; + + if (uMsg == WM_INITDIALOG) + { + listSection = (PPH_MINIINFO_LIST_SECTION)lParam; + PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, listSection); + } + else + { + listSection = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); + } + + if (!listSection) + return FALSE; switch (uMsg) { @@ -1286,9 +1299,6 @@ INT_PTR CALLBACK PhMipListSectionDialogProc( { PPH_LAYOUT_ITEM layoutItem; - listSection = (PPH_MINIINFO_LIST_SECTION)lParam; - SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)listSection); - listSection->DialogHandle = hwndDlg; listSection->TreeNewHandle = GetDlgItem(hwndDlg, IDC_LIST); @@ -1313,7 +1323,7 @@ INT_PTR CALLBACK PhMipListSectionDialogProc( case WM_DESTROY: { PhDeleteLayoutManager(&listSection->LayoutManager); - RemoveProp(hwndDlg, PhMakeContextAtom()); + PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); } break; case WM_SIZE: diff --git a/ProcessHacker/mtgndlg.c b/ProcessHacker/mtgndlg.c index a9c5c8ef7ed6..2d5630e7d6a7 100644 --- a/ProcessHacker/mtgndlg.c +++ b/ProcessHacker/mtgndlg.c @@ -182,22 +182,21 @@ INT_PTR CALLBACK PhpProcessMitigationPolicyDlgProc( if (uMsg == WM_INITDIALOG) { context = (PMITIGATION_POLICY_CONTEXT)lParam; - SetProp(hwndDlg, L"Context", (HANDLE)context); + PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context); } else { - context = (PMITIGATION_POLICY_CONTEXT)GetProp(hwndDlg, L"Context"); + context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); if (uMsg == WM_DESTROY) { - RemoveProp(hwndDlg, L"Context"); + PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); } } if (context == NULL) return FALSE; - switch (uMsg) { case WM_INITDIALOG: diff --git a/ProcessHacker/netstk.c b/ProcessHacker/netstk.c index 8ae55638bfed..5ab9e2c76ce8 100644 --- a/ProcessHacker/netstk.c +++ b/ProcessHacker/netstk.c @@ -28,6 +28,7 @@ typedef struct NETWORK_STACK_CONTEXT { HWND ListViewHandle; + PH_LAYOUT_MANAGER LayoutManager; PPH_NETWORK_ITEM NetworkItem; PPH_SYMBOL_PROVIDER SymbolProvider; HANDLE LoadingProcessId; @@ -126,36 +127,44 @@ static INT_PTR CALLBACK PhpNetworkStackDlgProc( _In_ LPARAM lParam ) { + PNETWORK_STACK_CONTEXT context = NULL; + + if (uMsg == WM_INITDIALOG) + { + context = (PNETWORK_STACK_CONTEXT)lParam; + PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context); + } + else + { + context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); + + if (uMsg == WM_DESTROY) + { + PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); + } + } + + if (!context) + return FALSE; + switch (uMsg) { case WM_INITDIALOG: { - PNETWORK_STACK_CONTEXT networkStackContext; HWND lvHandle; - PPH_LAYOUT_MANAGER layoutManager; PVOID address; ULONG i; PhCenterWindow(hwndDlg, GetParent(hwndDlg)); - networkStackContext = (PNETWORK_STACK_CONTEXT)lParam; - SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)networkStackContext); - - lvHandle = GetDlgItem(hwndDlg, IDC_LIST); + context->ListViewHandle = lvHandle = GetDlgItem(hwndDlg, IDC_LIST); PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 350, L"Name"); PhSetListViewStyle(lvHandle, FALSE, TRUE); PhSetControlTheme(lvHandle, L"explorer"); - networkStackContext->ListViewHandle = lvHandle; - - layoutManager = PhAllocate(sizeof(PH_LAYOUT_MANAGER)); - PhInitializeLayoutManager(layoutManager, hwndDlg); - SetProp(hwndDlg, L"LayoutManager", (HANDLE)layoutManager); - - PhAddLayoutItem(layoutManager, lvHandle, NULL, - PH_ANCHOR_ALL); - PhAddLayoutItem(layoutManager, GetDlgItem(hwndDlg, IDOK), - NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); + PhInitializeLayoutManager(&context->LayoutManager, hwndDlg); + PhAddLayoutItem(&context->LayoutManager, lvHandle, NULL, PH_ANCHOR_ALL); + PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDOK), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); if (MinimumSize.left == -1) { @@ -174,13 +183,13 @@ static INT_PTR CALLBACK PhpNetworkStackDlgProc( { PPH_STRING name; - address = *(PVOID *)&networkStackContext->NetworkItem->OwnerInfo[i]; + address = *(PVOID *)&context->NetworkItem->OwnerInfo[i]; if ((ULONG_PTR)address < PAGE_SIZE) // stop at an invalid address break; name = PhGetSymbolFromAddress( - networkStackContext->SymbolProvider, + context->SymbolProvider, (ULONG64)address, NULL, NULL, @@ -194,17 +203,9 @@ static INT_PTR CALLBACK PhpNetworkStackDlgProc( break; case WM_DESTROY: { - PPH_LAYOUT_MANAGER layoutManager; - PNETWORK_STACK_CONTEXT networkStackContext; - - layoutManager = (PPH_LAYOUT_MANAGER)GetProp(hwndDlg, L"LayoutManager"); - PhDeleteLayoutManager(layoutManager); - PhFree(layoutManager); + PhDeleteLayoutManager(&context->LayoutManager); - networkStackContext = (PNETWORK_STACK_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom()); - - RemoveProp(hwndDlg, PhMakeContextAtom()); - RemoveProp(hwndDlg, L"LayoutManager"); + PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); } break; case WM_COMMAND: @@ -220,10 +221,7 @@ static INT_PTR CALLBACK PhpNetworkStackDlgProc( break; case WM_SIZE: { - PPH_LAYOUT_MANAGER layoutManager; - - layoutManager = (PPH_LAYOUT_MANAGER)GetProp(hwndDlg, L"LayoutManager"); - PhLayoutManagerLayout(layoutManager); + PhLayoutManagerLayout(&context->LayoutManager); } break; case WM_SIZING: diff --git a/ProcessHacker/ntobjprp.c b/ProcessHacker/ntobjprp.c index e7aa709fa6e8..4196733c8e6e 100644 --- a/ProcessHacker/ntobjprp.c +++ b/ProcessHacker/ntobjprp.c @@ -150,8 +150,7 @@ FORCEINLINE PCOMMON_PAGE_CONTEXT PhpCommonPageHeader( _In_ LPARAM lParam ) { - return (PCOMMON_PAGE_CONTEXT)PhpGenericPropertyPageHeader( - hwndDlg, uMsg, wParam, lParam, L"PageContext"); + return PhpGenericPropertyPageHeader(hwndDlg, uMsg, wParam, lParam, 2); } HPROPSHEETPAGE PhCreateEventPage( diff --git a/ProcessHacker/options.c b/ProcessHacker/options.c index 15e6f4e6d531..0992214bbd1d 100644 --- a/ProcessHacker/options.c +++ b/ProcessHacker/options.c @@ -1472,7 +1472,7 @@ static INT_PTR CALLBACK PhpOptionsAdvancedEditDlgProc( SetWindowText(hwndDlg, L"Setting Editor"); PhCenterWindow(hwndDlg, GetParent(hwndDlg)); - SetProp(hwndDlg, PhMakeContextAtom(), setting); + PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, setting); PhInitializeLayoutManager(&LayoutManager, hwndDlg); PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDC_NAME), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); @@ -1490,7 +1490,7 @@ static INT_PTR CALLBACK PhpOptionsAdvancedEditDlgProc( break; case WM_DESTROY: { - RemoveProp(hwndDlg, PhMakeContextAtom()); + PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); PhDeleteLayoutManager(&LayoutManager); } @@ -1509,7 +1509,7 @@ static INT_PTR CALLBACK PhpOptionsAdvancedEditDlgProc( break; case IDOK: { - PPH_SETTING setting = (PPH_SETTING)GetProp(hwndDlg, PhMakeContextAtom()); + PPH_SETTING setting = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); PPH_STRING settingValue = PH_AUTO(PhGetWindowText(GetDlgItem(hwndDlg, IDC_VALUE))); if (!PhSettingFromString( diff --git a/ProcessHacker/plugman.c b/ProcessHacker/plugman.c index 6d5462c518ea..b105bbd93b21 100644 --- a/ProcessHacker/plugman.c +++ b/ProcessHacker/plugman.c @@ -628,11 +628,11 @@ INT_PTR CALLBACK PhpPluginsDlgProc( context = PhAllocate(sizeof(PH_PLUGMAN_CONTEXT)); memset(context, 0, sizeof(PH_PLUGMAN_CONTEXT)); - SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)context); + PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context); } else { - context = (PPH_PLUGMAN_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom()); + context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); } if (!context) @@ -679,6 +679,8 @@ INT_PTR CALLBACK PhpPluginsDlgProc( DeletePluginsTree(context); + PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); + PhFree(context); PostQuitMessage(0); @@ -955,15 +957,15 @@ INT_PTR CALLBACK PhpPluginPropertiesDlgProc( if (uMsg == WM_INITDIALOG) { selectedPlugin = (PPH_PLUGIN)lParam; - SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)selectedPlugin); + PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, selectedPlugin); } else { - selectedPlugin = (PPH_PLUGIN)GetProp(hwndDlg, PhMakeContextAtom()); + selectedPlugin = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); if (uMsg == WM_DESTROY) { - RemoveProp(hwndDlg, PhMakeContextAtom()); + PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); } } @@ -1097,15 +1099,15 @@ INT_PTR CALLBACK PhpPluginsDisabledDlgProc( context = PhAllocate(sizeof(PLUGIN_DISABLED_CONTEXT)); memset(context, 0, sizeof(PLUGIN_DISABLED_CONTEXT)); - SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)context); + PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context); } else { - context = (PPLUGIN_DISABLED_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom()); + context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); if (uMsg == WM_DESTROY) { - RemoveProp(hwndDlg, PhMakeContextAtom()); + PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); PhFree(context); } } diff --git a/ProcessHacker/procprp.c b/ProcessHacker/procprp.c index a9909f48b557..593cb33b8114 100644 --- a/ProcessHacker/procprp.c +++ b/ProcessHacker/procprp.c @@ -167,7 +167,7 @@ INT CALLBACK PhpPropSheetProc( PhInitializeLayoutManager(&propSheetContext->LayoutManager, hwndDlg); - SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)propSheetContext); + PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, propSheetContext); SetWindowSubclass(hwndDlg, PhpPropSheetWndProc, 0, (ULONG_PTR)propSheetContext); if (MinimumSize.left == -1) @@ -193,7 +193,7 @@ PPH_PROCESS_PROPSHEETCONTEXT PhpGetPropSheetContext( _In_ HWND hwnd ) { - return (PPH_PROCESS_PROPSHEETCONTEXT)GetProp(hwnd, PhMakeContextAtom()); + return PhGetWindowContext(hwnd, PH_WINDOW_CONTEXT_DEFAULT); } LRESULT CALLBACK PhpPropSheetWndProc( @@ -236,7 +236,7 @@ LRESULT CALLBACK PhpPropSheetWndProc( case WM_NCDESTROY: { RemoveWindowSubclass(hwnd, PhpPropSheetWndProc, uIdSubclass); - RemoveProp(hwnd, PhMakeContextAtom()); + PhRemoveWindowContext(hwnd, PH_WINDOW_CONTEXT_DEFAULT); PhDeleteLayoutManager(&propSheetContext->LayoutManager); PhFree(propSheetContext); diff --git a/ProcessHacker/procrec.c b/ProcessHacker/procrec.c index fb654e1aa669..8237b18fabc9 100644 --- a/ProcessHacker/procrec.c +++ b/ProcessHacker/procrec.c @@ -98,15 +98,15 @@ INT_PTR CALLBACK PhpProcessRecordDlgProc( if (uMsg == WM_INITDIALOG) { context = (PPROCESS_RECORD_CONTEXT)lParam; - SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)context); + PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context); } else { - context = (PPROCESS_RECORD_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom()); + context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); if (uMsg == WM_DESTROY) { - RemoveProp(hwndDlg, PhMakeContextAtom()); + PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); } } diff --git a/ProcessHacker/prpgenv.c b/ProcessHacker/prpgenv.c index 02d007c0610d..fa220acf37bb 100644 --- a/ProcessHacker/prpgenv.c +++ b/ProcessHacker/prpgenv.c @@ -442,15 +442,15 @@ INT_PTR CALLBACK PhpEditEnvDlgProc( if (uMsg == WM_INITDIALOG) { context = (PEDIT_ENV_DIALOG_CONTEXT)lParam; - SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)context); + PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context); } else { - context = (PEDIT_ENV_DIALOG_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom()); + context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); if (uMsg == WM_DESTROY) { - RemoveProp(hwndDlg, PhMakeContextAtom()); + PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); } } diff --git a/ProcessHacker/prpgjob.c b/ProcessHacker/prpgjob.c index a6858385e81e..fcbe8ae1e249 100644 --- a/ProcessHacker/prpgjob.c +++ b/ProcessHacker/prpgjob.c @@ -69,12 +69,12 @@ INT_PTR CALLBACK PhpProcessJobHookProc( { case WM_DESTROY: { - RemoveProp(hwndDlg, PhMakeContextAtom()); + PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); } break; case WM_SHOWWINDOW: { - if (!GetProp(hwndDlg, PhMakeContextAtom())) // LayoutInitialized + if (!PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT)) // LayoutInitialized { PPH_LAYOUT_ITEM dialogItem; @@ -97,7 +97,7 @@ INT_PTR CALLBACK PhpProcessJobHookProc( PhDoPropPageLayout(hwndDlg); - SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)TRUE); + PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, UlongToPtr(TRUE)); } } break; diff --git a/ProcessHacker/prpgtok.c b/ProcessHacker/prpgtok.c index d19a654673e9..44a1e9a287d9 100644 --- a/ProcessHacker/prpgtok.c +++ b/ProcessHacker/prpgtok.c @@ -59,12 +59,12 @@ INT_PTR CALLBACK PhpProcessTokenHookProc( { case WM_DESTROY: { - RemoveProp(hwndDlg, PhMakeContextAtom()); + PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); } break; case WM_SHOWWINDOW: { - if (!GetProp(hwndDlg, PhMakeContextAtom())) // LayoutInitialized + if (!PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT)) // LayoutInitialized { PPH_LAYOUT_ITEM dialogItem; @@ -97,7 +97,7 @@ INT_PTR CALLBACK PhpProcessTokenHookProc( PhDoPropPageLayout(hwndDlg); - SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)TRUE); + PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, UlongToPtr(TRUE)); } } break; diff --git a/ProcessHacker/runas.c b/ProcessHacker/runas.c index bc53241c45c5..1c93b78e143a 100644 --- a/ProcessHacker/runas.c +++ b/ProcessHacker/runas.c @@ -247,12 +247,12 @@ INT_PTR CALLBACK PhpRunAsDlgProc( if (uMsg != WM_INITDIALOG) { - context = (PRUNAS_DIALOG_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom()); + context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); } else { context = (PRUNAS_DIALOG_CONTEXT)lParam; - SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)context); + PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context); } if (!context) @@ -356,7 +356,7 @@ INT_PTR CALLBACK PhpRunAsDlgProc( if (context->DesktopList) PhDereferenceObject(context->DesktopList); - RemoveProp(hwndDlg, PhMakeContextAtom()); + PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); } break; case WM_COMMAND: diff --git a/ProcessHacker/sessmsg.c b/ProcessHacker/sessmsg.c index 2e48174e87e2..390ffca4d547 100644 --- a/ProcessHacker/sessmsg.c +++ b/ProcessHacker/sessmsg.c @@ -70,7 +70,8 @@ INT_PTR CALLBACK PhpSessionSendMessageDlgProc( { HWND iconComboBox; - SetProp(hwndDlg, L"SessionId", UlongToHandle((ULONG)lParam)); + PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, UlongToPtr((ULONG)lParam)); + PhCenterWindow(hwndDlg, GetParent(hwndDlg)); iconComboBox = GetDlgItem(hwndDlg, IDC_TYPE); @@ -96,7 +97,7 @@ INT_PTR CALLBACK PhpSessionSendMessageDlgProc( break; case WM_DESTROY: { - RemoveProp(hwndDlg, L"SessionId"); + PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); } break; case WM_COMMAND: @@ -108,7 +109,7 @@ INT_PTR CALLBACK PhpSessionSendMessageDlgProc( break; case IDOK: { - ULONG sessionId = HandleToUlong(GetProp(hwndDlg, L"SessionId")); + ULONG sessionId = PtrToUlong(PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT)); PPH_STRING title; PPH_STRING text; ULONG icon = 0; diff --git a/ProcessHacker/sessprp.c b/ProcessHacker/sessprp.c index 076696e7b71a..91e06a80cdee 100644 --- a/ProcessHacker/sessprp.c +++ b/ProcessHacker/sessprp.c @@ -81,7 +81,6 @@ INT_PTR CALLBACK PhpSessionPropertiesDlgProc( ULONG returnLength; PWSTR stateString; - SetProp(hwndDlg, L"SessionId", UlongToHandle(sessionId)); PhCenterWindow(hwndDlg, GetParent(hwndDlg)); // Query basic session information @@ -215,11 +214,6 @@ INT_PTR CALLBACK PhpSessionPropertiesDlgProc( SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hwndDlg, IDOK), TRUE); } break; - case WM_DESTROY: - { - RemoveProp(hwndDlg, L"SessionId"); - } - break; case WM_COMMAND: { switch (LOWORD(wParam)) diff --git a/ProcessHacker/sessshad.c b/ProcessHacker/sessshad.c index 62bd01a8317a..23b156373480 100644 --- a/ProcessHacker/sessshad.c +++ b/ProcessHacker/sessshad.c @@ -140,7 +140,8 @@ INT_PTR CALLBACK PhpSessionShadowDlgProc( ULONG i; PWSTR stringToSelect; - SetProp(hwndDlg, L"SessionId", UlongToHandle((ULONG)lParam)); + PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, UlongToPtr((ULONG)lParam)); + PhCenterWindow(hwndDlg, GetParent(hwndDlg)); hotkey = PhGetIntegerPairSetting(L"SessionShadowHotkey"); @@ -171,7 +172,7 @@ INT_PTR CALLBACK PhpSessionShadowDlgProc( break; case WM_DESTROY: { - RemoveProp(hwndDlg, L"SessionId"); + PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); } break; case WM_COMMAND: @@ -183,7 +184,7 @@ INT_PTR CALLBACK PhpSessionShadowDlgProc( break; case IDOK: { - ULONG sessionId = HandleToUlong(GetProp(hwndDlg, L"SessionId")); + ULONG sessionId = PtrToUlong(PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT)); ULONG virtualKey; ULONG modifiers; WCHAR computerName[64]; diff --git a/ProcessHacker/splitter.c b/ProcessHacker/splitter.c index 208e3c22d8e9..df6aa2baed33 100644 --- a/ProcessHacker/splitter.c +++ b/ProcessHacker/splitter.c @@ -110,11 +110,16 @@ LRESULT CALLBACK HSplitterWindowProc( { LPCREATESTRUCT cs = (LPCREATESTRUCT)lParam; context = cs->lpCreateParams; - SetProp(hwnd, PhMakeContextAtom(), (HANDLE)context); + PhSetWindowContext(hwnd, PH_WINDOW_CONTEXT_DEFAULT, context); } else { - context = (PPH_HSPLITTER_CONTEXT)GetProp(hwnd, PhMakeContextAtom()); + context = PhGetWindowContext(hwnd, PH_WINDOW_CONTEXT_DEFAULT); + + if (uMsg == WM_DESTROY) + { + PhRemoveWindowContext(hwnd, PH_WINDOW_CONTEXT_DEFAULT); + } } if (!context) diff --git a/ProcessHacker/srvctl.c b/ProcessHacker/srvctl.c index 4992df84a96e..a3aab1c31363 100644 --- a/ProcessHacker/srvctl.c +++ b/ProcessHacker/srvctl.c @@ -207,15 +207,15 @@ INT_PTR CALLBACK PhpServicesPageProc( if (uMsg == WM_INITDIALOG) { servicesContext = (PPH_SERVICES_CONTEXT)lParam; - SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)servicesContext); + PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, servicesContext); } else { - servicesContext = (PPH_SERVICES_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom()); + servicesContext = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); if (uMsg == WM_DESTROY) { - RemoveProp(hwndDlg, PhMakeContextAtom()); + PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); } } diff --git a/ProcessHacker/srvprp.c b/ProcessHacker/srvprp.c index 2cdb40209fe3..e093b457f993 100644 --- a/ProcessHacker/srvprp.c +++ b/ProcessHacker/srvprp.c @@ -209,12 +209,27 @@ INT_PTR CALLBACK PhpServiceGeneralDlgProc( _In_ LPARAM lParam ) { + PSERVICE_PROPERTIES_CONTEXT context; + + if (uMsg == WM_INITDIALOG) + { + LPPROPSHEETPAGE propSheetPage = (LPPROPSHEETPAGE)lParam; + context = (PSERVICE_PROPERTIES_CONTEXT)propSheetPage->lParam; + + PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context); + } + else + { + context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); + } + + if (!context) + return FALSE; + switch (uMsg) { case WM_INITDIALOG: { - LPPROPSHEETPAGE propSheetPage = (LPPROPSHEETPAGE)lParam; - PSERVICE_PROPERTIES_CONTEXT context = (PSERVICE_PROPERTIES_CONTEXT)propSheetPage->lParam; PPH_SERVICE_ITEM serviceItem = context->ServiceItem; SC_HANDLE serviceHandle; ULONG startType; @@ -224,8 +239,6 @@ INT_PTR CALLBACK PhpServiceGeneralDlgProc( // HACK PhCenterWindow(GetParent(hwndDlg), GetParent(GetParent(hwndDlg))); - SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)context); - PhAddComboBoxStrings(GetDlgItem(hwndDlg, IDC_TYPE), PhServiceTypeStrings, sizeof(PhServiceTypeStrings) / sizeof(WCHAR *)); PhAddComboBoxStrings(GetDlgItem(hwndDlg, IDC_STARTTYPE), PhServiceStartTypeStrings, @@ -305,14 +318,11 @@ INT_PTR CALLBACK PhpServiceGeneralDlgProc( break; case WM_DESTROY: { - RemoveProp(hwndDlg, PhMakeContextAtom()); + PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); } break; case WM_COMMAND: { - PSERVICE_PROPERTIES_CONTEXT context = - (PSERVICE_PROPERTIES_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom()); - switch (LOWORD(wParam)) { case IDCANCEL: @@ -415,8 +425,6 @@ INT_PTR CALLBACK PhpServiceGeneralDlgProc( case PSN_APPLY: { NTSTATUS status; - PSERVICE_PROPERTIES_CONTEXT context = - (PSERVICE_PROPERTIES_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom()); PPH_SERVICE_ITEM serviceItem = context->ServiceItem; SC_HANDLE serviceHandle; PPH_STRING newServiceTypeString; diff --git a/ProcessHacker/thrdstk.c b/ProcessHacker/thrdstk.c index b63a2f5c2619..8ba355c9777b 100644 --- a/ProcessHacker/thrdstk.c +++ b/ProcessHacker/thrdstk.c @@ -738,11 +738,11 @@ static INT_PTR CALLBACK PhpThreadStackDlgProc( if (uMsg == WM_INITDIALOG) { context = (PPH_THREAD_STACK_CONTEXT)lParam; - SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)context); + PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context); } else { - context = (PPH_THREAD_STACK_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom()); + context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); } if (!context) @@ -835,7 +835,7 @@ static INT_PTR CALLBACK PhpThreadStackDlgProc( PhSaveWindowPlacementToSetting(NULL, L"ThreadStackWindowSize", hwndDlg); - RemoveProp(hwndDlg, PhMakeContextAtom()); + PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); } break; case WM_COMMAND: @@ -1147,11 +1147,11 @@ static INT_PTR CALLBACK PhpThreadStackProgressDlgProc( if (uMsg == WM_INITDIALOG) { context = (PPH_THREAD_STACK_CONTEXT)lParam; - SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)context); + PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context); } else { - context = (PPH_THREAD_STACK_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom()); + context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); } if (!context) @@ -1185,7 +1185,7 @@ static INT_PTR CALLBACK PhpThreadStackProgressDlgProc( break; case WM_DESTROY: { - RemoveProp(hwndDlg, PhMakeContextAtom()); + PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); } break; case WM_COMMAND: diff --git a/ProcessHacker/tokprp.c b/ProcessHacker/tokprp.c index 906bd4dc7222..85de914d2542 100644 --- a/ProcessHacker/tokprp.c +++ b/ProcessHacker/tokprp.c @@ -474,8 +474,7 @@ FORCEINLINE PTOKEN_PAGE_CONTEXT PhpTokenPageHeader( _In_ LPARAM lParam ) { - return (PTOKEN_PAGE_CONTEXT)PhpGenericPropertyPageHeader( - hwndDlg, uMsg, wParam, lParam, L"TokenPageContext"); + return PhpGenericPropertyPageHeader(hwndDlg, uMsg, wParam, lParam, 3); } INT_PTR CALLBACK PhpTokenPageProc( From e404712aceb9a9f7cb0e8a93314de90bf74e770e Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 29 Jan 2018 18:36:00 +1100 Subject: [PATCH 0736/2058] Update export definitions --- ProcessHacker/ProcessHacker.def | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ProcessHacker/ProcessHacker.def b/ProcessHacker/ProcessHacker.def index fcb0537c4d8a..45755ab3a0bd 100644 --- a/ProcessHacker/ProcessHacker.def +++ b/ProcessHacker/ProcessHacker.def @@ -509,6 +509,9 @@ EXPORTS PhSetListViewItemImageIndex PhSetListViewSubItem PhSetStateAllListViewItems + PhGetWindowContext + PhSetWindowContext + PhRemoveWindowContext ; hndlinfo PhEnumObjectTypes From 57e2436861222719543e53719e2028bee85037e9 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 29 Jan 2018 18:39:30 +1100 Subject: [PATCH 0737/2058] Plugins: Improve window property callbacks --- plugins/ExtendedServices/depend.c | 12 ++++++------ plugins/ExtendedServices/other.c | 6 +++--- plugins/ExtendedServices/recovery.c | 12 ++++++------ plugins/ExtendedServices/srvprgrs.c | 6 +++--- plugins/ExtendedServices/trigger.c | 12 ++++++------ plugins/ExtendedServices/triggpg.c | 6 +++--- plugins/ExtendedTools/gpuprprp.c | 12 ++++++------ plugins/ExtendedTools/unldll.c | 6 +++--- plugins/ExtendedTools/wswatch.c | 6 +++--- plugins/HardwareDevices/diskdetails.c | 12 ++++++------ plugins/HardwareDevices/diskgraph.c | 12 ++++++------ plugins/HardwareDevices/diskoptions.c | 6 +++--- plugins/HardwareDevices/netdetails.c | 6 +++--- plugins/HardwareDevices/netgraph.c | 12 ++++++------ plugins/HardwareDevices/netoptions.c | 6 +++--- plugins/HardwareDevices/prpsh.c | 4 ++-- plugins/HardwareDevices/prpsh.h | 6 +++--- plugins/NetworkTools/ping.c | 6 +++--- plugins/NetworkTools/tracert.c | 6 +++--- plugins/NetworkTools/whois.c | 6 +++--- plugins/ToolStatus/customizesb.c | 6 +++--- plugins/ToolStatus/customizetb.c | 6 +++--- plugins/UserNotes/main.c | 6 +++--- plugins/WindowExplorer/wnddlg.c | 6 +++--- plugins/WindowExplorer/wndprp.c | 20 ++++++++++---------- 25 files changed, 102 insertions(+), 102 deletions(-) diff --git a/plugins/ExtendedServices/depend.c b/plugins/ExtendedServices/depend.c index dc15aa52f2ad..99b6aaeecff2 100644 --- a/plugins/ExtendedServices/depend.c +++ b/plugins/ExtendedServices/depend.c @@ -117,14 +117,14 @@ INT_PTR CALLBACK EspServiceDependenciesDlgProc( context = PhAllocate(sizeof(SERVICE_LIST_CONTEXT)); memset(context, 0, sizeof(SERVICE_LIST_CONTEXT)); - SetProp(hwndDlg, L"Context", (HANDLE)context); + PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context); } else { - context = (PSERVICE_LIST_CONTEXT)GetProp(hwndDlg, L"Context"); + context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); if (uMsg == WM_DESTROY) - RemoveProp(hwndDlg, L"Context"); + PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); } if (!context) @@ -245,14 +245,14 @@ INT_PTR CALLBACK EspServiceDependentsDlgProc( context = PhAllocate(sizeof(SERVICE_LIST_CONTEXT)); memset(context, 0, sizeof(SERVICE_LIST_CONTEXT)); - SetProp(hwndDlg, L"Context", (HANDLE)context); + PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context); } else { - context = (PSERVICE_LIST_CONTEXT)GetProp(hwndDlg, L"Context"); + context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); if (uMsg == WM_DESTROY) - RemoveProp(hwndDlg, L"Context"); + PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); } if (!context) diff --git a/plugins/ExtendedServices/other.c b/plugins/ExtendedServices/other.c index 28d98146d6a9..e93bfb620a1b 100644 --- a/plugins/ExtendedServices/other.c +++ b/plugins/ExtendedServices/other.c @@ -319,14 +319,14 @@ INT_PTR CALLBACK EspServiceOtherDlgProc( context = PhAllocate(sizeof(SERVICE_OTHER_CONTEXT)); memset(context, 0, sizeof(SERVICE_OTHER_CONTEXT)); - SetProp(hwndDlg, L"Context", (HANDLE)context); + PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context); } else { - context = (PSERVICE_OTHER_CONTEXT)GetProp(hwndDlg, L"Context"); + context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); if (uMsg == WM_DESTROY) - RemoveProp(hwndDlg, L"Context"); + PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); } if (!context) diff --git a/plugins/ExtendedServices/recovery.c b/plugins/ExtendedServices/recovery.c index 47a55520c2f0..1949ff3a7ffc 100644 --- a/plugins/ExtendedServices/recovery.c +++ b/plugins/ExtendedServices/recovery.c @@ -274,14 +274,14 @@ INT_PTR CALLBACK EspServiceRecoveryDlgProc( context = PhAllocate(sizeof(SERVICE_RECOVERY_CONTEXT)); memset(context, 0, sizeof(SERVICE_RECOVERY_CONTEXT)); - SetProp(hwndDlg, L"Context", (HANDLE)context); + PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context); } else { - context = (PSERVICE_RECOVERY_CONTEXT)GetProp(hwndDlg, L"Context"); + context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); if (uMsg == WM_DESTROY) - RemoveProp(hwndDlg, L"Context"); + PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); } if (!context) @@ -594,14 +594,14 @@ INT_PTR CALLBACK RestartComputerDlgProc( if (uMsg == WM_INITDIALOG) { context = (PSERVICE_RECOVERY_CONTEXT)lParam; - SetProp(hwndDlg, L"Context", (HANDLE)context); + PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context); } else { - context = (PSERVICE_RECOVERY_CONTEXT)GetProp(hwndDlg, L"Context"); + context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); if (uMsg == WM_DESTROY) - RemoveProp(hwndDlg, L"Context"); + PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); } if (!context) diff --git a/plugins/ExtendedServices/srvprgrs.c b/plugins/ExtendedServices/srvprgrs.c index 3b19031596ef..059b95b36a93 100644 --- a/plugins/ExtendedServices/srvprgrs.c +++ b/plugins/ExtendedServices/srvprgrs.c @@ -42,14 +42,14 @@ INT_PTR CALLBACK EspRestartServiceDlgProc( if (uMsg == WM_INITDIALOG) { context = (PRESTART_SERVICE_CONTEXT)lParam; - SetProp(hwndDlg, L"Context", (HANDLE)context); + PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context); } else { - context = (PRESTART_SERVICE_CONTEXT)GetProp(hwndDlg, L"Context"); + context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); if (uMsg == WM_DESTROY) - RemoveProp(hwndDlg, L"Context"); + PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); } if (!context) diff --git a/plugins/ExtendedServices/trigger.c b/plugins/ExtendedServices/trigger.c index fb2c2803837e..a423158167a4 100644 --- a/plugins/ExtendedServices/trigger.c +++ b/plugins/ExtendedServices/trigger.c @@ -1264,14 +1264,14 @@ INT_PTR CALLBACK EspServiceTriggerDlgProc( if (uMsg == WM_INITDIALOG) { context = (PES_TRIGGER_CONTEXT)lParam; - SetProp(hwndDlg, L"Context", (HANDLE)context); + PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context); } else { - context = (PES_TRIGGER_CONTEXT)GetProp(hwndDlg, L"Context"); + context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); if (uMsg == WM_DESTROY) - RemoveProp(hwndDlg, L"Context"); + PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); } if (!context) @@ -1678,14 +1678,14 @@ INT_PTR CALLBACK ValueDlgProc( if (uMsg == WM_INITDIALOG) { context = (PES_TRIGGER_CONTEXT)lParam; - SetProp(hwndDlg, L"Context", (HANDLE)context); + PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context); } else { - context = (PES_TRIGGER_CONTEXT)GetProp(hwndDlg, L"Context"); + context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); if (uMsg == WM_DESTROY) - RemoveProp(hwndDlg, L"Context"); + PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); } if (!context) diff --git a/plugins/ExtendedServices/triggpg.c b/plugins/ExtendedServices/triggpg.c index 514dd38a0d5b..103ee6672e7f 100644 --- a/plugins/ExtendedServices/triggpg.c +++ b/plugins/ExtendedServices/triggpg.c @@ -60,14 +60,14 @@ INT_PTR CALLBACK EspServiceTriggersDlgProc( context = PhAllocate(sizeof(SERVICE_TRIGGERS_CONTEXT)); memset(context, 0, sizeof(SERVICE_TRIGGERS_CONTEXT)); - SetProp(hwndDlg, L"Context", (HANDLE)context); + PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context); } else { - context = (PSERVICE_TRIGGERS_CONTEXT)GetProp(hwndDlg, L"Context"); + context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); if (uMsg == WM_DESTROY) - RemoveProp(hwndDlg, L"Context"); + PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); } if (!context) diff --git a/plugins/ExtendedTools/gpuprprp.c b/plugins/ExtendedTools/gpuprprp.c index fc9138bf0915..bd89018f544e 100644 --- a/plugins/ExtendedTools/gpuprprp.c +++ b/plugins/ExtendedTools/gpuprprp.c @@ -73,16 +73,16 @@ INT_PTR CALLBACK GpuDetailsDialogProc( if (uMsg == WM_INITDIALOG) { context = (PET_GPU_CONTEXT)lParam; - SetProp(hwndDlg, L"Context", (HANDLE)context); + PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context); } else { - context = (PET_GPU_CONTEXT)GetProp(hwndDlg, L"Context"); + context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); if (uMsg == WM_DESTROY) { context->DetailsHandle = NULL; - RemoveProp(hwndDlg, L"Context"); + PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); } } @@ -126,15 +126,15 @@ INT_PTR CALLBACK GpuPanelDialogProc( if (uMsg == WM_INITDIALOG) { context = (PET_GPU_CONTEXT)lParam; - SetProp(hwndDlg, L"Context", (HANDLE)context); + PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context); } else { - context = (PET_GPU_CONTEXT)GetProp(hwndDlg, L"Context"); + context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); if (uMsg == WM_DESTROY) { - RemoveProp(hwndDlg, L"Context"); + PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); } } diff --git a/plugins/ExtendedTools/unldll.c b/plugins/ExtendedTools/unldll.c index 7640363288c0..02cd7cff34cf 100644 --- a/plugins/ExtendedTools/unldll.c +++ b/plugins/ExtendedTools/unldll.c @@ -287,14 +287,14 @@ INT_PTR CALLBACK EtpUnloadedDllsDlgProc( if (uMsg == WM_INITDIALOG) { context = (PUNLOADED_DLLS_CONTEXT)lParam; - SetProp(hwndDlg, L"Context", (HANDLE)context); + PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context); } else { - context = (PUNLOADED_DLLS_CONTEXT)GetProp(hwndDlg, L"Context"); + context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); if (uMsg == WM_DESTROY) - RemoveProp(hwndDlg, L"Context"); + PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); } if (!context) diff --git a/plugins/ExtendedTools/wswatch.c b/plugins/ExtendedTools/wswatch.c index 9e7ca403c5b5..e8aa9d969a13 100644 --- a/plugins/ExtendedTools/wswatch.c +++ b/plugins/ExtendedTools/wswatch.c @@ -411,14 +411,14 @@ INT_PTR CALLBACK EtpWsWatchDlgProc( if (uMsg == WM_INITDIALOG) { context = (PWS_WATCH_CONTEXT)lParam; - SetProp(hwndDlg, L"Context", (HANDLE)context); + PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context); } else { - context = (PWS_WATCH_CONTEXT)GetProp(hwndDlg, L"Context"); + context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); if (uMsg == WM_DESTROY) - RemoveProp(hwndDlg, L"Context"); + PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); } if (!context) diff --git a/plugins/HardwareDevices/diskdetails.c b/plugins/HardwareDevices/diskdetails.c index 1165e41be5ec..79986e5bbf1f 100644 --- a/plugins/HardwareDevices/diskdetails.c +++ b/plugins/HardwareDevices/diskdetails.c @@ -568,15 +568,15 @@ INT_PTR CALLBACK DiskDriveFileSystemDetailsDlgProc( context->PageContext = (PCOMMON_PAGE_CONTEXT)propPageContext->Context; - SetProp(hwndDlg, L"Context", (HANDLE)context); + PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context); } else { - context = (PDV_DISK_PAGE_CONTEXT)GetProp(hwndDlg, L"Context"); + context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); if (uMsg == WM_DESTROY) { - RemoveProp(hwndDlg, L"Context"); + PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); PhSaveListViewColumnsToSetting(SETTING_NAME_DISK_COUNTERS_COLUMNS, context->ListViewHandle); PhFree(context); @@ -648,15 +648,15 @@ INT_PTR CALLBACK DiskDriveSmartDetailsDlgProc( context->PageContext = (PCOMMON_PAGE_CONTEXT)propPageContext->Context; - SetProp(hwndDlg, L"Context", (HANDLE)context); + PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context); } else { - context = (PDV_DISK_PAGE_CONTEXT)GetProp(hwndDlg, L"Context"); + context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); if (uMsg == WM_DESTROY) { - RemoveProp(hwndDlg, L"Context"); + PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); PhSaveListViewColumnsToSetting(SETTING_NAME_SMART_COUNTERS_COLUMNS, context->ListViewHandle); PhFree(context); diff --git a/plugins/HardwareDevices/diskgraph.c b/plugins/HardwareDevices/diskgraph.c index 422f031bee74..bc25e20236aa 100644 --- a/plugins/HardwareDevices/diskgraph.c +++ b/plugins/HardwareDevices/diskgraph.c @@ -115,15 +115,15 @@ INT_PTR CALLBACK DiskDrivePanelDialogProc( { context = (PDV_DISK_SYSINFO_CONTEXT)lParam; - SetProp(hwndDlg, L"Context", (HANDLE)context); + PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context); } else { - context = (PDV_DISK_SYSINFO_CONTEXT)GetProp(hwndDlg, L"Context"); + context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); if (uMsg == WM_NCDESTROY) { - RemoveProp(hwndDlg, L"Context"); + PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); } } @@ -160,11 +160,11 @@ INT_PTR CALLBACK DiskDriveDialogProc( { context = (PDV_DISK_SYSINFO_CONTEXT)lParam; - SetProp(hwndDlg, L"Context", (HANDLE)context); + PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context); } else { - context = (PDV_DISK_SYSINFO_CONTEXT)GetProp(hwndDlg, L"Context"); + context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); if (uMsg == WM_DESTROY) { @@ -177,7 +177,7 @@ INT_PTR CALLBACK DiskDriveDialogProc( if (context->PanelWindowHandle) DestroyWindow(context->PanelWindowHandle); - RemoveProp(hwndDlg, L"Context"); + PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); } } diff --git a/plugins/HardwareDevices/diskoptions.c b/plugins/HardwareDevices/diskoptions.c index 968ec97569f0..b3648a3db728 100644 --- a/plugins/HardwareDevices/diskoptions.c +++ b/plugins/HardwareDevices/diskoptions.c @@ -595,11 +595,11 @@ INT_PTR CALLBACK DiskDriveOptionsDlgProc( context = (PDV_DISK_OPTIONS_CONTEXT)PhAllocate(sizeof(DV_DISK_OPTIONS_CONTEXT)); memset(context, 0, sizeof(DV_DISK_OPTIONS_CONTEXT)); - SetProp(hwndDlg, L"Context", (HANDLE)context); + PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context); } else { - context = (PDV_DISK_OPTIONS_CONTEXT)GetProp(hwndDlg, L"Context"); + context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); if (uMsg == WM_DESTROY) { @@ -610,7 +610,7 @@ INT_PTR CALLBACK DiskDriveOptionsDlgProc( FreeListViewDiskDriveEntries(context); - RemoveProp(hwndDlg, L"Context"); + PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); PhFree(context); } } diff --git a/plugins/HardwareDevices/netdetails.c b/plugins/HardwareDevices/netdetails.c index 03cd4e92cf0a..491deee744cb 100644 --- a/plugins/HardwareDevices/netdetails.c +++ b/plugins/HardwareDevices/netdetails.c @@ -497,14 +497,14 @@ INT_PTR CALLBACK NetAdapterDetailsDlgProc( if (uMsg == WM_INITDIALOG) { context = (PDV_NETADAPTER_DETAILS_CONTEXT)lParam; - SetProp(hwndDlg, L"Context", (HANDLE)context); + PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context); } else { - context = (PDV_NETADAPTER_DETAILS_CONTEXT)GetProp(hwndDlg, L"Context"); + context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); if (uMsg == WM_DESTROY) - RemoveProp(hwndDlg, L"Context"); + PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); } if (!context) diff --git a/plugins/HardwareDevices/netgraph.c b/plugins/HardwareDevices/netgraph.c index 83890c9e8fa7..12b53cba95b2 100644 --- a/plugins/HardwareDevices/netgraph.c +++ b/plugins/HardwareDevices/netgraph.c @@ -166,15 +166,15 @@ INT_PTR CALLBACK NetAdapterPanelDialogProc( { context = (PDV_NETADAPTER_SYSINFO_CONTEXT)lParam; - SetProp(hwndDlg, L"Context", (HANDLE)context); + PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context); } else { - context = (PDV_NETADAPTER_SYSINFO_CONTEXT)GetProp(hwndDlg, L"Context"); + context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); if (uMsg == WM_NCDESTROY) { - RemoveProp(hwndDlg, L"Context"); + PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); } } @@ -211,11 +211,11 @@ INT_PTR CALLBACK NetAdapterDialogProc( { context = (PDV_NETADAPTER_SYSINFO_CONTEXT)lParam; - SetProp(hwndDlg, L"Context", (HANDLE)context); + PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context); } else { - context = (PDV_NETADAPTER_SYSINFO_CONTEXT)GetProp(hwndDlg, L"Context"); + context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); if (uMsg == WM_DESTROY) { @@ -228,7 +228,7 @@ INT_PTR CALLBACK NetAdapterDialogProc( if (context->PanelWindowHandle) DestroyWindow(context->PanelWindowHandle); - RemoveProp(hwndDlg, L"Context"); + PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); } } diff --git a/plugins/HardwareDevices/netoptions.c b/plugins/HardwareDevices/netoptions.c index e6a24711514f..c6c82890e62b 100644 --- a/plugins/HardwareDevices/netoptions.c +++ b/plugins/HardwareDevices/netoptions.c @@ -694,11 +694,11 @@ INT_PTR CALLBACK NetworkAdapterOptionsDlgProc( context = (PDV_NETADAPTER_CONTEXT)PhAllocate(sizeof(DV_NETADAPTER_CONTEXT)); memset(context, 0, sizeof(DV_NETADAPTER_CONTEXT)); - SetProp(hwndDlg, L"Context", (HANDLE)context); + PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context); } else { - context = (PDV_NETADAPTER_CONTEXT)GetProp(hwndDlg, L"Context"); + context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); if (uMsg == WM_DESTROY) { @@ -709,7 +709,7 @@ INT_PTR CALLBACK NetworkAdapterOptionsDlgProc( FreeListViewAdapterEntries(context); - RemoveProp(hwndDlg, L"Context"); + PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); PhFree(context); } } diff --git a/plugins/HardwareDevices/prpsh.c b/plugins/HardwareDevices/prpsh.c index 546ec8f469db..4b0aedf56512 100644 --- a/plugins/HardwareDevices/prpsh.c +++ b/plugins/HardwareDevices/prpsh.c @@ -144,8 +144,8 @@ INT CALLBACK PvpPropSheetProc( PhInitializeLayoutManager(&propSheetContext->LayoutManager, hwndDlg); - SetProp(hwndDlg, L"HdContext", (HANDLE)propSheetContext); SetWindowSubclass(hwndDlg, PvpPropSheetWndProc, 0, (ULONG_PTR)propSheetContext); + PhSetWindowContext(hwndDlg, ULONG_MAX, propSheetContext); if (MinimumSize.left == -1) { @@ -170,7 +170,7 @@ PPV_PROPSHEETCONTEXT PvpGetPropSheetContext( _In_ HWND hwnd ) { - return (PPV_PROPSHEETCONTEXT)GetProp(hwnd, L"HdContext"); + return PhGetWindowContext(hwnd, ULONG_MAX); } LRESULT CALLBACK PvpPropSheetWndProc( diff --git a/plugins/HardwareDevices/prpsh.h b/plugins/HardwareDevices/prpsh.h index d6417da4f404..dd2411ab700c 100644 --- a/plugins/HardwareDevices/prpsh.h +++ b/plugins/HardwareDevices/prpsh.h @@ -29,9 +29,9 @@ typedef struct _PV_PROPSHEETCONTEXT { + BOOLEAN LayoutInitialized; PH_LAYOUT_MANAGER LayoutManager; PPH_LAYOUT_ITEM TabPageItem; - BOOLEAN LayoutInitialized; } PV_PROPSHEETCONTEXT, *PPV_PROPSHEETCONTEXT; typedef struct _PV_PROPCONTEXT @@ -114,10 +114,10 @@ FORCEINLINE BOOLEAN PvPropPageDlgProcHeader( if (uMsg == WM_INITDIALOG) { // Save the context. - SetProp(hwndDlg, L"HdContext", (HANDLE)lParam); + PhSetWindowContext(hwndDlg, ULONG_MAX, (HANDLE)lParam); } - propSheetPage = (LPPROPSHEETPAGE)GetProp(hwndDlg, L"HdContext"); + propSheetPage = PhGetWindowContext(hwndDlg, ULONG_MAX); if (!propSheetPage) return FALSE; diff --git a/plugins/NetworkTools/ping.c b/plugins/NetworkTools/ping.c index 4fd646f6e450..2dab53790826 100644 --- a/plugins/NetworkTools/ping.c +++ b/plugins/NetworkTools/ping.c @@ -269,11 +269,11 @@ INT_PTR CALLBACK NetworkPingWndProc( if (uMsg == WM_INITDIALOG) { context = (PNETWORK_PING_CONTEXT)lParam; - SetProp(hwndDlg, L"Context", (HANDLE)context); + PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context); } else { - context = (PNETWORK_PING_CONTEXT)GetProp(hwndDlg, L"Context"); + context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); } if (context == NULL) @@ -385,7 +385,7 @@ INT_PTR CALLBACK NetworkPingWndProc( PhDeleteGraphState(&context->PingGraphState); PhDeleteLayoutManager(&context->LayoutManager); - RemoveProp(hwndDlg, L"Context"); + PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); PhFree(context); PostQuitMessage(0); diff --git a/plugins/NetworkTools/tracert.c b/plugins/NetworkTools/tracert.c index a0683dc89945..3ed9273c75b6 100644 --- a/plugins/NetworkTools/tracert.c +++ b/plugins/NetworkTools/tracert.c @@ -585,11 +585,11 @@ INT_PTR CALLBACK TracertDlgProc( if (uMsg == WM_INITDIALOG) { context = (PNETWORK_TRACERT_CONTEXT)lParam; - SetProp(hwndDlg, L"Context", (HANDLE)context); + PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context); } else { - context = (PNETWORK_TRACERT_CONTEXT)GetProp(hwndDlg, L"Context"); + context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); if (uMsg == WM_DESTROY) { @@ -604,7 +604,7 @@ INT_PTR CALLBACK TracertDlgProc( PhDeleteWorkQueue(&context->WorkQueue); PhDeleteLayoutManager(&context->LayoutManager); - RemoveProp(hwndDlg, L"Context"); + PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); PhDereferenceObject(context); PostQuitMessage(0); diff --git a/plugins/NetworkTools/whois.c b/plugins/NetworkTools/whois.c index 0f8e0bf73469..686dc934ccb5 100644 --- a/plugins/NetworkTools/whois.c +++ b/plugins/NetworkTools/whois.c @@ -370,17 +370,17 @@ INT_PTR CALLBACK NetworkOutputDlgProc( if (uMsg == WM_INITDIALOG) { context = (PNETWORK_WHOIS_CONTEXT)lParam; - SetProp(hwndDlg, L"Context", (HANDLE)context); + PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context); } else { - context = (PNETWORK_WHOIS_CONTEXT)GetProp(hwndDlg, L"Context"); + context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); if (uMsg == WM_DESTROY) { PhSaveWindowPlacementToSetting(SETTING_NAME_WHOIS_WINDOW_POSITION, SETTING_NAME_WHOIS_WINDOW_SIZE, hwndDlg); PhDeleteLayoutManager(&context->LayoutManager); - RemoveProp(hwndDlg, L"Context"); + PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); PhDereferenceObject(context); PostQuitMessage(0); diff --git a/plugins/ToolStatus/customizesb.c b/plugins/ToolStatus/customizesb.c index d823a35a3339..680eb6b368cb 100644 --- a/plugins/ToolStatus/customizesb.c +++ b/plugins/ToolStatus/customizesb.c @@ -279,15 +279,15 @@ INT_PTR CALLBACK CustomizeStatusBarDialogProc( context = (PCUSTOMIZE_CONTEXT)PhAllocate(sizeof(CUSTOMIZE_CONTEXT)); memset(context, 0, sizeof(CUSTOMIZE_CONTEXT)); - SetProp(hwndDlg, L"Context", (HANDLE)context); + PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context); } else { - context = (PCUSTOMIZE_CONTEXT)GetProp(hwndDlg, L"Context"); + context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); if (uMsg == WM_NCDESTROY) { - RemoveProp(hwndDlg, L"Context"); + PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); PhFree(context); } } diff --git a/plugins/ToolStatus/customizetb.c b/plugins/ToolStatus/customizetb.c index c103c01b4d18..1b7c48c04547 100644 --- a/plugins/ToolStatus/customizetb.c +++ b/plugins/ToolStatus/customizetb.c @@ -490,15 +490,15 @@ INT_PTR CALLBACK CustomizeToolbarDialogProc( context = (PCUSTOMIZE_CONTEXT)PhAllocate(sizeof(CUSTOMIZE_CONTEXT)); memset(context, 0, sizeof(CUSTOMIZE_CONTEXT)); - SetProp(hwndDlg, L"Context", (HANDLE)context); + PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context); } else { - context = (PCUSTOMIZE_CONTEXT)GetProp(hwndDlg, L"Context"); + context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); if (uMsg == WM_NCDESTROY) { - RemoveProp(hwndDlg, L"Context"); + PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); PhFree(context); } } diff --git a/plugins/UserNotes/main.c b/plugins/UserNotes/main.c index 69c0ca077f65..05cfa44a0138 100644 --- a/plugins/UserNotes/main.c +++ b/plugins/UserNotes/main.c @@ -1803,14 +1803,14 @@ INT_PTR CALLBACK ServiceCommentPageDlgProc( context = PhAllocate(sizeof(SERVICE_COMMENT_PAGE_CONTEXT)); memset(context, 0, sizeof(SERVICE_COMMENT_PAGE_CONTEXT)); - SetProp(hwndDlg, L"Context", (HANDLE)context); + PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context); } else { - context = (PSERVICE_COMMENT_PAGE_CONTEXT)GetProp(hwndDlg, L"Context"); + context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); if (uMsg == WM_DESTROY) - RemoveProp(hwndDlg, L"Context"); + PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); } if (!context) diff --git a/plugins/WindowExplorer/wnddlg.c b/plugins/WindowExplorer/wnddlg.c index 9aa47dd23c1f..4ab23fe9a491 100644 --- a/plugins/WindowExplorer/wnddlg.c +++ b/plugins/WindowExplorer/wnddlg.c @@ -329,14 +329,14 @@ INT_PTR CALLBACK WepWindowsDlgProc( if (uMsg == WM_INITDIALOG) { context = (PWINDOWS_CONTEXT)lParam; - SetProp(hwndDlg, L"Context", (HANDLE)context); + PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context); } else { - context = (PWINDOWS_CONTEXT)GetProp(hwndDlg, L"Context"); + context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); if (uMsg == WM_DESTROY) - RemoveProp(hwndDlg, L"Context"); + PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); } if (!context) diff --git a/plugins/WindowExplorer/wndprp.c b/plugins/WindowExplorer/wndprp.c index c853353a0b11..98360506b553 100644 --- a/plugins/WindowExplorer/wndprp.c +++ b/plugins/WindowExplorer/wndprp.c @@ -362,7 +362,7 @@ static INT CALLBACK WepPropSheetProc( oldWndProc = (WNDPROC)GetWindowLongPtr(hwndDlg, GWLP_WNDPROC); SetWindowLongPtr(hwndDlg, GWLP_WNDPROC, (LONG_PTR)WepPropSheetWndProc); - SetProp(hwndDlg, L"OldWndProc", (HANDLE)oldWndProc); + PhSetWindowContext(hwndDlg, 1, (HANDLE)oldWndProc); // Hide the Cancel button. ShowWindow(GetDlgItem(hwndDlg, IDCANCEL), SW_HIDE); @@ -386,20 +386,20 @@ LRESULT CALLBACK WepPropSheetWndProc( _In_ LPARAM lParam ) { - WNDPROC oldWndProc = (WNDPROC)GetProp(hwnd, L"OldWndProc"); + WNDPROC oldWndProc = PhGetWindowContext(hwnd, 1); switch (uMsg) { case WM_DESTROY: { SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)oldWndProc); - RemoveProp(hwnd, L"OldWndProc"); - RemoveProp(hwnd, L"Moved"); + PhRemoveWindowContext(hwnd, 1); + PhRemoveWindowContext(hwnd, 2); } break; case WM_SHOWWINDOW: { - if (!GetProp(hwnd, L"Moved")) + if (!PhGetWindowContext(hwnd, 2)) { // Move the Refresh button to where the OK button is, and move the OK button to // where the Cancel button is. @@ -407,7 +407,7 @@ LRESULT CALLBACK WepPropSheetWndProc( // in the right places. PhCopyControlRectangle(hwnd, GetDlgItem(hwnd, IDOK), GetDlgItem(hwnd, IDC_REFRESH)); PhCopyControlRectangle(hwnd, GetDlgItem(hwnd, IDCANCEL), GetDlgItem(hwnd, IDOK)); - SetProp(hwnd, L"Moved", (HANDLE)1); + PhSetWindowContext(hwnd, 2, UlongToPtr(1)); } } break; @@ -568,15 +568,15 @@ FORCEINLINE BOOLEAN WepPropPageDlgProcHeader( if (uMsg == WM_INITDIALOG) { propSheetPage = (LPPROPSHEETPAGE)lParam; - // Save the context. - SetProp(hwndDlg, L"PropSheetPage", (HANDLE)lParam); + + PhSetWindowContext(hwndDlg, ULONG_MAX, (HANDLE)lParam); } else { - propSheetPage = (LPPROPSHEETPAGE)GetProp(hwndDlg, L"PropSheetPage"); + propSheetPage = PhGetWindowContext(hwndDlg, ULONG_MAX); if (uMsg == WM_DESTROY) - RemoveProp(hwndDlg, L"PropSheetPage"); + PhRemoveWindowContext(hwndDlg, ULONG_MAX); } if (!propSheetPage) From 6b67c9e5efba29d5904bc1f68258d3a790081479 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 29 Jan 2018 18:40:23 +1100 Subject: [PATCH 0738/2058] Fix type name --- phlib/include/mapimg.h | 4 ++-- phlib/mapimg.c | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/phlib/include/mapimg.h b/phlib/include/mapimg.h index 0d41efbb4926..1293fa34ac3a 100644 --- a/phlib/include/mapimg.h +++ b/phlib/include/mapimg.h @@ -156,7 +156,7 @@ PhLoadRemoteMappedImage( _Out_ PPH_REMOTE_MAPPED_IMAGE RemoteMappedImage ); -typedef NTSTATUS (NTAPI *PPH_READ_VIRTUAL_MEMORY)( +typedef NTSTATUS (NTAPI *PPH_READ_VIRTUAL_MEMORY_CALLBACK)( _In_ HANDLE ProcessHandle, _In_opt_ PVOID BaseAddress, _Out_writes_bytes_(BufferSize) PVOID Buffer, @@ -169,7 +169,7 @@ NTAPI PhLoadRemoteMappedImageEx( _In_ HANDLE ProcessHandle, _In_ PVOID ViewBase, - _In_ PPH_READ_VIRTUAL_MEMORY ReadVirtualMemory, + _In_ PPH_READ_VIRTUAL_MEMORY_CALLBACK ReadVirtualMemoryCallback, _Out_ PPH_REMOTE_MAPPED_IMAGE RemoteMappedImage ); diff --git a/phlib/mapimg.c b/phlib/mapimg.c index 12e2203372e9..18f226724789 100644 --- a/phlib/mapimg.c +++ b/phlib/mapimg.c @@ -508,7 +508,7 @@ NTSTATUS PhLoadRemoteMappedImage( NTSTATUS PhLoadRemoteMappedImageEx( _In_ HANDLE ProcessHandle, _In_ PVOID ViewBase, - _In_ PPH_READ_VIRTUAL_MEMORY ReadVirtualMemory, + _In_ PPH_READ_VIRTUAL_MEMORY_CALLBACK ReadVirtualMemoryCallback, _Out_ PPH_REMOTE_MAPPED_IMAGE RemoteMappedImage ) { @@ -520,7 +520,7 @@ NTSTATUS PhLoadRemoteMappedImageEx( RemoteMappedImage->ViewBase = ViewBase; - status = ReadVirtualMemory( + status = ReadVirtualMemoryCallback( ProcessHandle, ViewBase, &dosHeader, @@ -543,7 +543,7 @@ NTSTATUS PhLoadRemoteMappedImageEx( if (ntHeadersOffset == 0 || ntHeadersOffset >= 0x10000000) return STATUS_INVALID_IMAGE_FORMAT; - status = ReadVirtualMemory( + status = ReadVirtualMemoryCallback( ProcessHandle, PTR_ADD_OFFSET(ViewBase, ntHeadersOffset), &ntHeaders, @@ -579,7 +579,7 @@ NTSTATUS PhLoadRemoteMappedImageEx( RemoteMappedImage->NtHeaders = PhAllocate(ntHeadersSize); - status = ReadVirtualMemory( + status = ReadVirtualMemoryCallback( ProcessHandle, PTR_ADD_OFFSET(ViewBase, ntHeadersOffset), RemoteMappedImage->NtHeaders, From d2d3043ca703c38deb31b00f894e92ba90bacf28 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 29 Jan 2018 18:42:02 +1100 Subject: [PATCH 0739/2058] OnlineChecks: Fix hybrid-anaysis maximum upload size --- plugins/OnlineChecks/upload.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/plugins/OnlineChecks/upload.c b/plugins/OnlineChecks/upload.c index 023a7e38b54c..2e925bac3bfe 100644 --- a/plugins/OnlineChecks/upload.c +++ b/plugins/OnlineChecks/upload.c @@ -246,8 +246,8 @@ NTSTATUS HashFileAndResetPosition( ); } - NtSetInformationThread(NtCurrentThread(), ThreadBasePriority, &priority, sizeof(LONG)); - NtSetInformationThread(NtCurrentThread(), ThreadIoPriority, &ioPriority, sizeof(IO_PRIORITY_HINT)); + PhSetThreadBasePriority(NtCurrentThread(), priority); + PhSetThreadIoPriority(NtCurrentThread(), ioPriority); return status; } @@ -970,6 +970,17 @@ NTSTATUS UploadCheckThreadStart( goto CleanupExit; } } + else if ( + context->Service == MENUITEM_HYBRIDANALYSIS_UPLOAD || + context->Service == MENUITEM_HYBRIDANALYSIS_UPLOAD_SERVICE + ) + { + if (fileSize64.QuadPart > 128 * 1024 * 1024) // 128 MB + { + RaiseUploadError(context, L"The file is too large (over 128 MB)", ERROR_FILE_TOO_LARGE); + goto CleanupExit; + } + } else { if (fileSize64.QuadPart > 20 * 1024 * 1024) // 20 MB From 4141c87897fae6236d524eb05ea71ee53d0d8e48 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 29 Jan 2018 18:46:48 +1100 Subject: [PATCH 0740/2058] Add missing file from commit 6b67c9e --- ProcessHacker/modprv.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ProcessHacker/modprv.c b/ProcessHacker/modprv.c index dd0d901009c5..ec632a63569c 100644 --- a/ProcessHacker/modprv.c +++ b/ProcessHacker/modprv.c @@ -506,12 +506,12 @@ VOID PhModuleProviderUpdate( moduleItem->Type == PH_MODULE_TYPE_KERNEL_MODULE) { PH_REMOTE_MAPPED_IMAGE remoteMappedImage; - PPH_READ_VIRTUAL_MEMORY readVirtualMemory; + PPH_READ_VIRTUAL_MEMORY_CALLBACK readVirtualMemoryCallback; if (moduleItem->Type == PH_MODULE_TYPE_KERNEL_MODULE) - readVirtualMemory = KphReadVirtualMemoryUnsafe; + readVirtualMemoryCallback = KphReadVirtualMemoryUnsafe; else - readVirtualMemory = NtReadVirtualMemory; + readVirtualMemoryCallback = NtReadVirtualMemory; // Note: // On Windows 7 the LDRP_IMAGE_NOT_AT_BASE flag doesn't appear to be used @@ -523,7 +523,7 @@ VOID PhModuleProviderUpdate( moduleItem->Flags &= ~LDRP_IMAGE_NOT_AT_BASE; - if (NT_SUCCESS(PhLoadRemoteMappedImageEx(moduleProvider->ProcessHandle, moduleItem->BaseAddress, readVirtualMemory, &remoteMappedImage))) + if (NT_SUCCESS(PhLoadRemoteMappedImageEx(moduleProvider->ProcessHandle, moduleItem->BaseAddress, readVirtualMemoryCallback, &remoteMappedImage))) { ULONG_PTR imageBase = 0; DWORD entryPoint = 0; From a685bac6ac2c8a058cb114ba81650933691cd124 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 31 Jan 2018 07:20:58 +1100 Subject: [PATCH 0741/2058] BuildTools: Fix build flag issue --- tools/CustomBuildTool/Source Files/Build.cs | 5 +++-- .../bin/Release/CustomBuildTool.exe | Bin 163840 -> 163840 bytes .../bin/Release/CustomBuildTool.pdb | Bin 75264 -> 75264 bytes 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/tools/CustomBuildTool/Source Files/Build.cs b/tools/CustomBuildTool/Source Files/Build.cs index 8dac9e821fc5..05ea621f630e 100644 --- a/tools/CustomBuildTool/Source Files/Build.cs +++ b/tools/CustomBuildTool/Source Files/Build.cs @@ -546,7 +546,7 @@ public static bool CopyKProcessHacker(BuildFlags Flags) if (!File.Exists("build\\kph.key")) return true; - if (Flags.HasFlag(BuildFlags.BuildDebug)) + if ((Flags & BuildFlags.Build32bit) == BuildFlags.Build32bit) { if (File.Exists("bin\\Debug32\\ProcessHacker.exe")) { @@ -572,7 +572,8 @@ public static bool CopyKProcessHacker(BuildFlags Flags) } } } - else + + if ((Flags & BuildFlags.Build64bit) == BuildFlags.Build64bit) { if (File.Exists("bin\\Release32\\ProcessHacker.exe")) { diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe b/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe index 109a98cde269e8b23dc2f5243c9aa522fd4c41f4..66b2a6015e56716d1ae01195b8cd4b1ef15531b9 100644 GIT binary patch delta 2007 zcmY+_ZERCj7zgnG={C5%?aFl#g=_X;VT|%KP+}?S4zqTz$-bi)E%$pPKHpT3jJl zc^}P4%uZK?Dm3~EpYZKYEOeZn8}$?!?#KE(zg0o~OsV<|Lzh^srh1EIcHu@N8)c1} z+F2sAbEekbDRtV^IhNIK%nlHPKSZSmqEEY-Kq!FQzKUx<_W&W^3BLQom$} zX=42xsbRI$qWay+X)0KQ1c%>K!5R#+j#0r{9AkY+1#9sstB4BL;VkPuDp-dfSf5cr zAAV(hM+JTOlXa2m)#Iw6D3!lP1?eSjkz2ZxwzL5X>kw^e18!jbOwIU_&ALj>_~B-G zshLL1U^P)QjhMx{K+Oa&hn1ve0`QoMb}PTB5j0^jhgVdM)WABD8NpICvrc7dq&C(} z`VE(16>9wqOTqGEHp3+pISz z3t@H?16*Xst8pajYm3*$0}lK$k=>cIbSe@<>MAz zjvO=VL|z}jG1~7z*4YlRRc*x~<|VOR zZ5y{}JC1VZ$1b%UTG(i`6R(IpY6p5)`C^y)2zHo~t*sol%1XSGxZR)LskOel`pnp= zb=6%5k{<-RY+DlEZ%SN6bkUk;l!cbgp{uituGy~3bUyn$KG#57=M#6wtKa*g**&9X z)3(IU%ZkuWYQ_yKKR?m;7xxugTyzuL6F-g=i+G8>(=mF`F)FV0SVl_@e&`ls;(r|l Bn+gB` delta 2030 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 delta 7442 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 From 41e6ac72d87bc694c24516307115ad3e25f83822 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 2 Feb 2018 00:20:40 +1100 Subject: [PATCH 0742/2058] Fix disabling notifyicons regression --- ProcessHacker/notifico.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/ProcessHacker/notifico.c b/ProcessHacker/notifico.c index b5584a4c3ab2..a767031bc1ee 100644 --- a/ProcessHacker/notifico.c +++ b/ProcessHacker/notifico.c @@ -75,16 +75,7 @@ VOID PhNfLoadSettings( remaining = settingsString->sr; if (remaining.Length == 0) - { - PPH_NF_ICON icon; - - // Load default settings. - if (icon = PhNfGetIconById(PH_TRAY_ICON_ID_CPU_USAGE)) - icon->Flags |= PH_NF_ICON_ENABLED; - - PhDereferenceObject(settingsString); return; - } while (remaining.Length != 0) { From 3b7f3baf96ca28ff39f0665615476f0933da8230 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 3 Feb 2018 04:59:34 +1100 Subject: [PATCH 0743/2058] OnlineChecks: Fix hybrid-analysis error uploading 32bit binaries --- plugins/OnlineChecks/upload.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/OnlineChecks/upload.c b/plugins/OnlineChecks/upload.c index 2e925bac3bfe..fabb0a4353bd 100644 --- a/plugins/OnlineChecks/upload.c +++ b/plugins/OnlineChecks/upload.c @@ -462,7 +462,7 @@ NTSTATUS UploadFileThreadStart( switch (machineType) { case IMAGE_FILE_MACHINE_I386: - environmentId = 100; + environmentId = 110; break; case IMAGE_FILE_MACHINE_AMD64: environmentId = 120; From d7912f701ff8916ce8e19103da5bc478c236ad72 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 4 Feb 2018 02:42:54 +1100 Subject: [PATCH 0744/2058] Add protected handle highlighting --- ProcessHacker/include/phsettings.h | 2 ++ ProcessHacker/include/procprv.h | 2 +- ProcessHacker/procprv.c | 45 ++++++++++++++++++++++++++++-- ProcessHacker/proctree.c | 2 ++ ProcessHacker/settings.c | 4 +++ 5 files changed, 52 insertions(+), 3 deletions(-) diff --git a/ProcessHacker/include/phsettings.h b/ProcessHacker/include/phsettings.h index c74d741f692b..1485bfe86aa7 100644 --- a/ProcessHacker/include/phsettings.h +++ b/ProcessHacker/include/phsettings.h @@ -37,6 +37,8 @@ EXT ULONG PhCsUseColorWow64Processes; EXT ULONG PhCsColorWow64Processes; EXT ULONG PhCsUseColorDebuggedProcesses; EXT ULONG PhCsColorDebuggedProcesses; +EXT ULONG PhCsUseColorHandleProtected; +EXT ULONG PhCsColorHandleProtected; EXT ULONG PhCsUseColorElevatedProcesses; EXT ULONG PhCsColorElevatedProcesses; EXT ULONG PhCsUseColorPicoProcesses; diff --git a/ProcessHacker/include/procprv.h b/ProcessHacker/include/procprv.h index 7ee4e9f3711a..2749bdf1d365 100644 --- a/ProcessHacker/include/procprv.h +++ b/ProcessHacker/include/procprv.h @@ -164,7 +164,7 @@ typedef struct _PH_PROCESS_ITEM ULONG IsImmersive : 1; ULONG IsWow64Valid : 1; ULONG IsPartiallySuspended : 1; - ULONG Unused : 1; + ULONG IsProtectedHandle : 1; ULONG IsProtectedProcess : 1; ULONG IsSecureProcess : 1; ULONG IsSubsystemProcess : 1; diff --git a/ProcessHacker/procprv.c b/ProcessHacker/procprv.c index 29b54475c6dd..4a4be997cad6 100644 --- a/ProcessHacker/procprv.c +++ b/ProcessHacker/procprv.c @@ -1344,11 +1344,52 @@ VOID PhpFillProcessItem( PhPrintUInt32(ProcessItem->SessionIdString, ProcessItem->SessionId); // Open a handle to the process for later usage. + + if ( + ProcessItem->ProcessId != SYSTEM_IDLE_PROCESS_ID && + ProcessItem->ProcessId != DPCS_PROCESS_ID && + ProcessItem->ProcessId != INTERRUPTS_PROCESS_ID + ) { - PhOpenProcess(&ProcessItem->QueryHandle, PROCESS_QUERY_INFORMATION, ProcessItem->ProcessId); + PhOpenProcess( + &ProcessItem->QueryHandle, + PROCESS_QUERY_INFORMATION, + ProcessItem->ProcessId + ); if (!ProcessItem->QueryHandle) - PhOpenProcess(&ProcessItem->QueryHandle, PROCESS_QUERY_LIMITED_INFORMATION, ProcessItem->ProcessId); + { + PhOpenProcess( + &ProcessItem->QueryHandle, + PROCESS_QUERY_LIMITED_INFORMATION, + ProcessItem->ProcessId + ); + } + else + { + OBJECT_BASIC_INFORMATION basicInfo; + + if (NT_SUCCESS(PhGetHandleInformationEx( + NtCurrentProcess(), + ProcessItem->QueryHandle, + -1, + 0, + NULL, + &basicInfo, + NULL, + NULL, + NULL, + NULL + ))) + { + if ((basicInfo.GrantedAccess & PROCESS_QUERY_INFORMATION) != PROCESS_QUERY_INFORMATION) + ProcessItem->IsProtectedHandle = TRUE; + } + else + { + ProcessItem->IsProtectedHandle = TRUE; + } + } } // Process flags diff --git a/ProcessHacker/proctree.c b/ProcessHacker/proctree.c index 6bb97961da4b..895fa96758c4 100644 --- a/ProcessHacker/proctree.c +++ b/ProcessHacker/proctree.c @@ -2844,6 +2844,8 @@ BOOLEAN NTAPI PhpProcessTreeNewCallback( getNodeColor->BackColor = PhCsColorDebuggedProcesses; else if (PhCsUseColorSuspended && processItem->IsSuspended) getNodeColor->BackColor = PhCsColorSuspended; + else if (PhCsUseColorHandleProtected && processItem->IsProtectedHandle) + getNodeColor->BackColor = PhCsColorHandleProtected; else if (PhCsUseColorElevatedProcesses && processItem->IsElevated) getNodeColor->BackColor = PhCsColorElevatedProcesses; else if (PhCsUseColorPicoProcesses && processItem->IsSubsystemProcess) diff --git a/ProcessHacker/settings.c b/ProcessHacker/settings.c index 319d88ebd3f1..e4bba431e458 100644 --- a/ProcessHacker/settings.c +++ b/ProcessHacker/settings.c @@ -188,6 +188,8 @@ VOID PhAddDefaultSettings( PhpAddIntegerSetting(L"ColorWow64Processes", L"8f8fbc"); // Rosy Brown PhpAddIntegerSetting(L"UseColorDebuggedProcesses", L"1"); PhpAddIntegerSetting(L"ColorDebuggedProcesses", L"ffbbcc"); + PhpAddIntegerSetting(L"UseColorHandleProtected", L"1"); + PhpAddIntegerSetting(L"ColorHandleProtected", L"000000"); // Black PhpAddIntegerSetting(L"UseColorElevatedProcesses", L"1"); PhpAddIntegerSetting(L"ColorElevatedProcesses", L"00aaff"); PhpAddIntegerSetting(L"UseColorPicoProcesses", L"1"); @@ -250,6 +252,8 @@ VOID PhUpdateCachedSettings( PH_UPDATE_SETTING(ColorWow64Processes); PH_UPDATE_SETTING(UseColorDebuggedProcesses); PH_UPDATE_SETTING(ColorDebuggedProcesses); + PH_UPDATE_SETTING(UseColorHandleProtected); + PH_UPDATE_SETTING(ColorHandleProtected); PH_UPDATE_SETTING(UseColorElevatedProcesses); PH_UPDATE_SETTING(ColorElevatedProcesses); PH_UPDATE_SETTING(UseColorPicoProcesses); From bc4b87c67f4ac0a3fd1ec7ba96b17503f9fdb8f3 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 4 Feb 2018 02:52:45 +1100 Subject: [PATCH 0745/2058] revert 6a02c5b0 Update window procedure callbacks --- phlib/extlv.c | 39 ++++++++++++++++++--------------------- 1 file changed, 18 insertions(+), 21 deletions(-) diff --git a/phlib/extlv.c b/phlib/extlv.c index 4ab2b593390c..0e210ed59863 100644 --- a/phlib/extlv.c +++ b/phlib/extlv.c @@ -38,6 +38,7 @@ typedef struct _PH_EXTLV_CONTEXT { HWND Handle; + WNDPROC OldWndProc; PVOID Context; // Sorting @@ -66,9 +67,7 @@ LRESULT CALLBACK PhpExtendedListViewWndProc( _In_ HWND hwnd, _In_ UINT uMsg, _In_ WPARAM wParam, - _In_ LPARAM lParam, - _In_ UINT_PTR uIdSubclass, - _In_ ULONG_PTR dwRefData + _In_ LPARAM lParam ); INT PhpExtendedListViewCompareFunc( @@ -114,6 +113,7 @@ VOID PhSetExtendedListView( context = PhAllocate(sizeof(PH_EXTLV_CONTEXT)); context->Handle = hWnd; + context->OldWndProc = (WNDPROC)GetWindowLongPtr(hWnd, GWLP_WNDPROC); context->Context = NULL; context->TriState = FALSE; context->SortColumn = 0; @@ -122,14 +122,13 @@ VOID PhSetExtendedListView( context->TriStateCompareFunction = NULL; memset(context->CompareFunctions, 0, sizeof(context->CompareFunctions)); context->NumberOfFallbackColumns = 0; - context->ItemColorFunction = NULL; context->ItemFontFunction = NULL; - context->EnableRedraw = 1; context->Cursor = NULL; - SetWindowSubclass(hWnd, PhpExtendedListViewWndProc, 0, (ULONG_PTR)context); + PhSetWindowContext(hWnd, 5, context); + SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)PhpExtendedListViewWndProc); ExtendedListView_Init(hWnd); } @@ -138,19 +137,17 @@ LRESULT CALLBACK PhpExtendedListViewWndProc( _In_ HWND hwnd, _In_ UINT uMsg, _In_ WPARAM wParam, - _In_ LPARAM lParam, - _In_ UINT_PTR uIdSubclass, - _In_ ULONG_PTR dwRefData + _In_ LPARAM lParam ) { - PPH_EXTLV_CONTEXT context = (PPH_EXTLV_CONTEXT)dwRefData; + PPH_EXTLV_CONTEXT context = PhGetWindowContext(hwnd, 5); switch (uMsg) { case WM_DESTROY: { - RemoveWindowSubclass(hwnd, PhpExtendedListViewWndProc, uIdSubclass); - + SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)context->OldWndProc); + PhRemoveWindowContext(hwnd, 5); PhFree(context); } break; @@ -164,7 +161,7 @@ LRESULT CALLBACK PhpExtendedListViewWndProc( { HWND headerHandle; - headerHandle = (HWND)SendMessage(hwnd, LVM_GETHEADER, 0, 0); + headerHandle = (HWND)CallWindowProc(context->OldWndProc, hwnd, LVM_GETHEADER, 0, 0); if (header->hwndFrom == headerHandle) { @@ -352,7 +349,7 @@ LRESULT CALLBACK PhpExtendedListViewWndProc( { if (i != column) { - if (SendMessage(hwnd, LVM_GETCOLUMN, i, (LPARAM)&lvColumn)) + if (CallWindowProc(context->OldWndProc, hwnd, LVM_GETCOLUMN, i, (LPARAM)&lvColumn)) { availableWidth -= lvColumn.cx; } @@ -366,10 +363,10 @@ LRESULT CALLBACK PhpExtendedListViewWndProc( } if (availableWidth >= 40) - return SendMessage(hwnd, LVM_SETCOLUMNWIDTH, column, availableWidth); + return CallWindowProc(context->OldWndProc, hwnd, LVM_SETCOLUMNWIDTH, column, availableWidth); } - return SendMessage(hwnd, LVM_SETCOLUMNWIDTH, column, width); + return CallWindowProc(context->OldWndProc, hwnd, LVM_SETCOLUMNWIDTH, column, width); } break; case ELVM_SETCOMPAREFUNCTION: @@ -471,7 +468,7 @@ LRESULT CALLBACK PhpExtendedListViewWndProc( return TRUE; } - return DefSubclassProc(hwnd, uMsg, wParam, lParam); + return CallWindowProc(context->OldWndProc, hwnd, uMsg, wParam, lParam); } /** @@ -549,9 +546,9 @@ static INT PhpExtendedListViewCompareFunc( yItem.iItem = y; yItem.iSubItem = 0; - if (!SendMessage(context->Handle, LVM_GETITEM, 0, (LPARAM)&xItem)) + if (!CallWindowProc(context->OldWndProc, context->Handle, LVM_GETITEM, 0, (LPARAM)&xItem)) return 0; - if (!SendMessage(context->Handle, LVM_GETITEM, 0, (LPARAM)&yItem)) + if (!CallWindowProc(context->OldWndProc, context->Handle, LVM_GETITEM, 0, (LPARAM)&yItem)) return 0; // First, do tri-state sorting. @@ -713,7 +710,7 @@ static INT PhpDefaultCompareListViewItems( item.cchTextMax = 260; xText[0] = 0; - SendMessage(Context->Handle, LVM_GETITEM, 0, (LPARAM)&item); + CallWindowProc(Context->OldWndProc, Context->Handle, LVM_GETITEM, 0, (LPARAM)&item); // Get the Y item text. @@ -722,7 +719,7 @@ static INT PhpDefaultCompareListViewItems( item.cchTextMax = 260; yText[0] = 0; - SendMessage(Context->Handle, LVM_GETITEM, 0, (LPARAM)&item); + CallWindowProc(Context->OldWndProc, Context->Handle, LVM_GETITEM, 0, (LPARAM)&item); // Compare them. From bef059f4dd1795ee804f1594722424b94e698dea Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 4 Feb 2018 02:56:29 +1100 Subject: [PATCH 0746/2058] Add CallWindowProc wrappers --- phlib/guisup.c | 90 ++++++++++++++++++++++++++++++++++++++++++ phlib/include/guisup.h | 39 ++++++++++++++++++ 2 files changed, 129 insertions(+) diff --git a/phlib/guisup.c b/phlib/guisup.c index 0512215a6bb1..b5e0001a1d57 100644 --- a/phlib/guisup.c +++ b/phlib/guisup.c @@ -1309,3 +1309,93 @@ VOID PhRemoveWindowContext( PhRemoveEntryHashtable(WindowContextHashTable, &lookupEntry); PhReleaseQueuedLockExclusive(&WindowContextListLock); } + +static LRESULT CALLBACK PhWindowSubclassCallback( + _In_ HWND WindowHandle, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + PPH_WINDOW_SUBCLASS context; + PPH_WINDOW_SUBCLASS_ENTRY entry; + ULONG i; + + if (!(context = PhGetWindowContext(WindowHandle, PH_WINDOW_SUBCLASS_CONTEXT))) + return 0; + + for (i = 0; i < context->WindowCallbackArray.Count; i++) + { + entry = PhItemArray(&context->WindowCallbackArray, i); + + if (entry->SubclassCallback(WindowHandle, uMsg, wParam, lParam, entry->Context)) + { + return DefWindowProc(WindowHandle, uMsg, wParam, lParam); + } + } + + return CallWindowProc(context->DefaultWindowProc, WindowHandle, uMsg, wParam, lParam); +} + +VOID PhRegisterWindowSubclass( + _In_ HWND WindowHandle, + _In_ PPH_WINDOW_SUBCLASS_CALLBACK SubclassCallback, + _In_opt_ PVOID Context + ) +{ + PPH_WINDOW_SUBCLASS context; + PH_WINDOW_SUBCLASS_ENTRY entry; + + entry.SubclassCallback = SubclassCallback; + entry.Context = Context; + + if (context = PhGetWindowContext(WindowHandle, PH_WINDOW_SUBCLASS_CONTEXT)) + { + PhAddItemArray(&context->WindowCallbackArray, &entry); + } + else + { + context = PhAllocate(sizeof(PH_WINDOW_SUBCLASS)); + memset(context, 0, sizeof(PH_WINDOW_SUBCLASS)); + + PhInitializeArray(&context->WindowCallbackArray, sizeof(PH_WINDOW_SUBCLASS_ENTRY), 1); + PhAddItemArray(&context->WindowCallbackArray, &entry); + + context->DefaultWindowProc = (WNDPROC)GetWindowLongPtr(WindowHandle, GWLP_WNDPROC); + + PhSetWindowContext(WindowHandle, PH_WINDOW_SUBCLASS_CONTEXT, context); + + SetWindowLongPtr(WindowHandle, GWLP_WNDPROC, (LONG_PTR)PhWindowSubclassCallback); + } +} + +VOID PhUnregisterWindowSubclass( + _In_ HWND WindowHandle, + _In_ PPH_WINDOW_SUBCLASS_CALLBACK SubclassCallback + ) +{ + PPH_WINDOW_SUBCLASS context; + PPH_WINDOW_SUBCLASS_ENTRY entry; + ULONG i; + + if (!(context = PhGetWindowContext(WindowHandle, PH_WINDOW_SUBCLASS_CONTEXT))) + return; + + for (i = 0; i < context->WindowCallbackArray.Count; i++) + { + entry = PhItemArray(&context->WindowCallbackArray, i); + + if (entry->SubclassCallback == SubclassCallback) + PhRemoveItemArray(&context->WindowCallbackArray, i); + } + + if (context->WindowCallbackArray.Count == 0) + { + SetWindowLongPtr(WindowHandle, GWLP_WNDPROC, (LONG_PTR)context->DefaultWindowProc); + + PhRemoveWindowContext(WindowHandle, PH_WINDOW_SUBCLASS_CONTEXT); + + PhDeleteArray(&context->WindowCallbackArray); + PhFree(context); + } +} diff --git a/phlib/include/guisup.h b/phlib/include/guisup.h index b999a4e38953..832df97fc2b4 100644 --- a/phlib/include/guisup.h +++ b/phlib/include/guisup.h @@ -481,6 +481,45 @@ PhRemoveWindowContext( _In_ ULONG PropertyHash ); +typedef BOOLEAN (NTAPI *PPH_WINDOW_SUBCLASS_CALLBACK)( + _In_ HWND hWnd, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam, + _In_ PVOID Context + ); + +typedef struct _PH_WINDOW_SUBCLASS_ENTRY +{ + PPH_WINDOW_SUBCLASS_CALLBACK SubclassCallback; + PVOID Context; +} PH_WINDOW_SUBCLASS_ENTRY, *PPH_WINDOW_SUBCLASS_ENTRY; + +typedef struct _PH_WINDOW_SUBCLASS +{ + WNDPROC DefaultWindowProc; + PH_ARRAY WindowCallbackArray; +} PH_WINDOW_SUBCLASS, *PPH_WINDOW_SUBCLASS; + +#define PH_WINDOW_SUBCLASS_CONTEXT 0xFFFFFF + +PHLIBAPI +VOID +NTAPI +PhRegisterWindowSubclass( + _In_ HWND WindowHandle, + _In_ PPH_WINDOW_SUBCLASS_CALLBACK SubclassWindowProc, + _In_opt_ PVOID Context + ); + +PHLIBAPI +VOID +NTAPI +PhUnregisterWindowSubclass( + _In_ HWND WindowHandle, + _In_ PPH_WINDOW_SUBCLASS_CALLBACK SubclassWindowProc + ); + FORCEINLINE VOID PhResizingMinimumSize( _Inout_ PRECT Rect, _In_ WPARAM Edge, From 08917fa0ac46ccc2ac877abd88924102c4ba8ede Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 4 Feb 2018 02:57:16 +1100 Subject: [PATCH 0747/2058] Fix PhStringRefToUnicodeString MaximumLength --- phlib/include/phbasesup.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phlib/include/phbasesup.h b/phlib/include/phbasesup.h index 9b2c871b6ae2..d487e6c56e0c 100644 --- a/phlib/include/phbasesup.h +++ b/phlib/include/phbasesup.h @@ -826,7 +826,7 @@ PhStringRefToUnicodeString( ) { UnicodeString->Length = (USHORT)String->Length; - UnicodeString->MaximumLength = (USHORT)String->Length; + UnicodeString->MaximumLength = (USHORT)String->Length + sizeof(UNICODE_NULL); UnicodeString->Buffer = String->Buffer; return String->Length <= UNICODE_STRING_MAX_BYTES; From d5b4ad224df525ab57e3d3adc92262897e7e892e Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 4 Feb 2018 03:02:34 +1100 Subject: [PATCH 0748/2058] Remove PhEnableServiceQueryStage2 --- ProcessHacker/include/phplug.h | 1 + ProcessHacker/include/phsettings.h | 1 - ProcessHacker/mainwnd.c | 1 - ProcessHacker/proctree.c | 9 ++++++--- ProcessHacker/settings.c | 1 - ProcessHacker/srvlist.c | 5 +++-- ProcessHacker/srvprv.c | 2 +- phlib/native.c | 10 ++++------ 8 files changed, 15 insertions(+), 15 deletions(-) diff --git a/ProcessHacker/include/phplug.h b/ProcessHacker/include/phplug.h index a4a4c36d44b9..02cd6cfb99b8 100644 --- a/ProcessHacker/include/phplug.h +++ b/ProcessHacker/include/phplug.h @@ -68,6 +68,7 @@ typedef struct _PH_PLUGIN_GET_HIGHLIGHTING_COLOR PVOID Parameter; COLORREF BackColor; + COLORREF ForeColor; BOOLEAN Handled; BOOLEAN Cache; } PH_PLUGIN_GET_HIGHLIGHTING_COLOR, *PPH_PLUGIN_GET_HIGHLIGHTING_COLOR; diff --git a/ProcessHacker/include/phsettings.h b/ProcessHacker/include/phsettings.h index 1485bfe86aa7..1081d65bfac0 100644 --- a/ProcessHacker/include/phsettings.h +++ b/ProcessHacker/include/phsettings.h @@ -12,7 +12,6 @@ #endif EXT BOOLEAN PhEnableProcessQueryStage2; -EXT BOOLEAN PhEnableServiceQueryStage2; EXT ULONG PhCsCollapseServicesOnStart; EXT ULONG PhCsForceNoParent; diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index 0d0167014eb4..4dda48ddfb67 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -2172,7 +2172,6 @@ VOID PhMwpLoadSettings( PhEnableNetworkProviderResolve = !!PhGetIntegerSetting(L"EnableNetworkResolve"); PhEnableProcessQueryStage2 = !!PhGetIntegerSetting(L"EnableStage2"); - PhEnableServiceQueryStage2 = !!PhGetIntegerSetting(L"EnableServiceStage2"); PhNfLoadStage1(); PhMwpNotifyIconNotifyMask = PhGetIntegerSetting(L"IconNotifyMask"); diff --git a/ProcessHacker/proctree.c b/ProcessHacker/proctree.c index 895fa96758c4..f0c32570aff7 100644 --- a/ProcessHacker/proctree.c +++ b/ProcessHacker/proctree.c @@ -2829,7 +2829,10 @@ BOOLEAN NTAPI PhpProcessTreeNewCallback( if (getHighlightingColor.Handled) { getNodeColor->BackColor = getHighlightingColor.BackColor; - getNodeColor->Flags = TN_AUTO_FORECOLOR; + getNodeColor->ForeColor = getHighlightingColor.ForeColor; + + if (!getNodeColor->ForeColor) + getNodeColor->Flags |= TN_AUTO_FORECOLOR; if (getHighlightingColor.Cache) getNodeColor->Flags |= TN_CACHE; @@ -2838,6 +2841,8 @@ BOOLEAN NTAPI PhpProcessTreeNewCallback( } } + getNodeColor->Flags = TN_CACHE | TN_AUTO_FORECOLOR; + if (!processItem) ; // Dummy else if (PhCsUseColorDebuggedProcesses && processItem->IsBeingDebugged) @@ -2875,8 +2880,6 @@ BOOLEAN NTAPI PhpProcessTreeNewCallback( PhEqualString(processItem->UserName, PhCurrentUserName, TRUE) ) getNodeColor->BackColor = PhCsColorOwnProcesses; - - getNodeColor->Flags = TN_CACHE | TN_AUTO_FORECOLOR; } return TRUE; case TreeNewGetNodeIcon: diff --git a/ProcessHacker/settings.c b/ProcessHacker/settings.c index e4bba431e458..eb4d2ab41396 100644 --- a/ProcessHacker/settings.c +++ b/ProcessHacker/settings.c @@ -48,7 +48,6 @@ VOID PhAddDefaultSettings( PhpAddIntegerSetting(L"EnableNetworkResolve", L"1"); PhpAddIntegerSetting(L"EnablePlugins", L"1"); PhpAddIntegerSetting(L"EnableServiceNonPoll", L"1"); - PhpAddIntegerSetting(L"EnableServiceStage2", L"0"); PhpAddIntegerSetting(L"EnableStage2", L"1"); PhpAddIntegerSetting(L"EnableWarnings", L"1"); PhpAddIntegerSetting(L"EnableWindowText", L"1"); diff --git a/ProcessHacker/srvlist.c b/ProcessHacker/srvlist.c index ee2cdc4ef3e6..1359c062d164 100644 --- a/ProcessHacker/srvlist.c +++ b/ProcessHacker/srvlist.c @@ -820,15 +820,16 @@ BOOLEAN NTAPI PhpServiceTreeNewCallback( if (!serviceItem) ; // Dummy - else if (PhEnableServiceQueryStage2 && PhCsUseColorUnknown && serviceItem->VerifyResult != VrTrusted) + else if (PhEnableProcessQueryStage2 && PhCsUseColorUnknown && serviceItem->VerifyResult != VrTrusted) { - getNodeColor->Flags = TN_AUTO_FORECOLOR; getNodeColor->BackColor = PhCsColorUnknown; } else if (PhCsUseColorServiceStop && serviceItem->StartType == SERVICE_DISABLED) { getNodeColor->ForeColor = PhCsColorServiceStop; } + + getNodeColor->Flags = TN_AUTO_FORECOLOR; } return TRUE; case TreeNewGetCellTooltip: diff --git a/ProcessHacker/srvprv.c b/ProcessHacker/srvprv.c index b6738b57cdc7..69912965dd0e 100644 --- a/ProcessHacker/srvprv.c +++ b/ProcessHacker/srvprv.c @@ -616,7 +616,7 @@ VOID PhpQueueServiceQueryStage2( { PH_WORK_QUEUE_ENVIRONMENT environment; - if (!PhEnableServiceQueryStage2) + if (!PhEnableProcessQueryStage2) return; PhReferenceObject(ServiceItem); diff --git a/phlib/native.c b/phlib/native.c index ac6fa54a6025..e5d80619004c 100644 --- a/phlib/native.c +++ b/phlib/native.c @@ -5070,7 +5070,6 @@ static BOOLEAN EnumGenericProcessModulesCallback( { PENUM_GENERIC_PROCESS_MODULES_CONTEXT context; PH_MODULE_INFO moduleInfo; - PPH_STRING fileName; BOOLEAN cont; context = (PENUM_GENERIC_PROCESS_MODULES_CONTEXT)Context; @@ -5085,19 +5084,18 @@ static BOOLEAN EnumGenericProcessModulesCallback( PhAddEntryHashtable(context->BaseAddressHashtable, &Module->DllBase); } - fileName = PhCreateStringFromUnicodeString(&Module->FullDllName); - moduleInfo.Type = context->Type; moduleInfo.BaseAddress = Module->DllBase; moduleInfo.Size = Module->SizeOfImage; moduleInfo.EntryPoint = Module->EntryPoint; moduleInfo.Flags = Module->Flags; - moduleInfo.Name = PhCreateStringFromUnicodeString(&Module->BaseDllName); - moduleInfo.FileName = PhGetFileName(fileName); - moduleInfo.OriginalFileName = fileName; moduleInfo.LoadOrderIndex = (USHORT)(context->LoadOrderIndex++); moduleInfo.LoadCount = Module->ObsoleteLoadCount; + moduleInfo.Name = PhCreateStringFromUnicodeString(&Module->BaseDllName); + moduleInfo.OriginalFileName = PhCreateStringFromUnicodeString(&Module->FullDllName); + moduleInfo.FileName = PhGetFileName(moduleInfo.OriginalFileName); + if (WindowsVersion >= WINDOWS_8) { moduleInfo.LoadReason = (USHORT)Module->LoadReason; From 62ff94b057b44b822ce9ddd481a829ee9011fe11 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 4 Feb 2018 03:35:04 +1100 Subject: [PATCH 0749/2058] Fix provider handle check --- ProcessHacker/include/procprv.h | 2 +- ProcessHacker/procprv.c | 72 +++++++++++++++------------------ 2 files changed, 33 insertions(+), 41 deletions(-) diff --git a/ProcessHacker/include/procprv.h b/ProcessHacker/include/procprv.h index 2749bdf1d365..0405382525f6 100644 --- a/ProcessHacker/include/procprv.h +++ b/ProcessHacker/include/procprv.h @@ -158,7 +158,7 @@ typedef struct _PH_PROCESS_ITEM ULONG IsInJob : 1; ULONG IsInSignificantJob : 1; ULONG IsPacked : 1; - ULONG Reserved : 1; + ULONG IsValidHandle : 1; ULONG IsSuspended : 1; ULONG IsWow64 : 1; ULONG IsImmersive : 1; diff --git a/ProcessHacker/procprv.c b/ProcessHacker/procprv.c index 4a4be997cad6..638e8edc68dd 100644 --- a/ProcessHacker/procprv.c +++ b/ProcessHacker/procprv.c @@ -107,8 +107,8 @@ typedef struct _PH_PROCESS_QUERY_S1_DATA ULONG IsInSignificantJob : 1; ULONG IsBeingDebugged : 1; ULONG IsImmersive : 1; - - ULONG Spare : 26; + ULONG IsProtectedHandle : 1; + ULONG Spare : 25; }; }; } PH_PROCESS_QUERY_S1_DATA, *PPH_PROCESS_QUERY_S1_DATA; @@ -1155,6 +1155,32 @@ VOID PhpProcessQueryStage1( { Data->PackageFullName = PhGetProcessPackageFullName(processHandleLimited); } + + if (processHandleLimited && processItem->IsValidHandle) + { + OBJECT_BASIC_INFORMATION basicInfo; + + if (NT_SUCCESS(PhGetHandleInformationEx( + NtCurrentProcess(), + processHandleLimited, + -1, + 0, + NULL, + &basicInfo, + NULL, + NULL, + NULL, + NULL + ))) + { + if ((basicInfo.GrantedAccess & PROCESS_QUERY_INFORMATION) != PROCESS_QUERY_INFORMATION) + Data->IsProtectedHandle = TRUE; + } + else + { + Data->IsProtectedHandle = TRUE; + } + } } VOID PhpProcessQueryStage2( @@ -1290,6 +1316,7 @@ VOID PhpFillProcessItemStage1( processItem->IsInSignificantJob = Data->IsInSignificantJob; processItem->IsBeingDebugged = Data->IsBeingDebugged; processItem->IsImmersive = Data->IsImmersive; + processItem->IsProtectedHandle = Data->IsProtectedHandle; PhSwapReference(&processItem->Record->CommandLine, processItem->CommandLine); @@ -1344,51 +1371,16 @@ VOID PhpFillProcessItem( PhPrintUInt32(ProcessItem->SessionIdString, ProcessItem->SessionId); // Open a handle to the process for later usage. - - if ( - ProcessItem->ProcessId != SYSTEM_IDLE_PROCESS_ID && - ProcessItem->ProcessId != DPCS_PROCESS_ID && - ProcessItem->ProcessId != INTERRUPTS_PROCESS_ID - ) + if (PH_IS_REAL_PROCESS_ID(ProcessItem->ProcessId)) { - PhOpenProcess( &ProcessItem->QueryHandle, PROCESS_QUERY_INFORMATION, ProcessItem->ProcessId - ); + )); if (!ProcessItem->QueryHandle) { - PhOpenProcess( - &ProcessItem->QueryHandle, - PROCESS_QUERY_LIMITED_INFORMATION, - ProcessItem->ProcessId - ); - } - else - { - OBJECT_BASIC_INFORMATION basicInfo; - - if (NT_SUCCESS(PhGetHandleInformationEx( - NtCurrentProcess(), - ProcessItem->QueryHandle, - -1, - 0, - NULL, - &basicInfo, - NULL, - NULL, - NULL, - NULL - ))) - { - if ((basicInfo.GrantedAccess & PROCESS_QUERY_INFORMATION) != PROCESS_QUERY_INFORMATION) - ProcessItem->IsProtectedHandle = TRUE; - } - else - { - ProcessItem->IsProtectedHandle = TRUE; - } + PhOpenProcess(&ProcessItem->QueryHandle, PROCESS_QUERY_LIMITED_INFORMATION, ProcessItem->ProcessId); } } From 2cc6d3d773f27a7f37c06d66c7a2559b703b9ea4 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 4 Feb 2018 03:36:52 +1100 Subject: [PATCH 0750/2058] Add missing file from pevious commit --- ProcessHacker/procprv.c | 1 + 1 file changed, 1 insertion(+) diff --git a/ProcessHacker/procprv.c b/ProcessHacker/procprv.c index 638e8edc68dd..adae0dbd01f5 100644 --- a/ProcessHacker/procprv.c +++ b/ProcessHacker/procprv.c @@ -1373,6 +1373,7 @@ VOID PhpFillProcessItem( // Open a handle to the process for later usage. if (PH_IS_REAL_PROCESS_ID(ProcessItem->ProcessId)) { + ProcessItem->IsValidHandle = NT_SUCCESS(PhOpenProcess( &ProcessItem->QueryHandle, PROCESS_QUERY_INFORMATION, ProcessItem->ProcessId From 704c25606421796d4e54f4430fe7b185b14b1e57 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 4 Feb 2018 03:55:41 +1100 Subject: [PATCH 0751/2058] Update LDR_DATA_TABLE_ENTRY types --- phnt/include/ntldr.h | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/phnt/include/ntldr.h b/phnt/include/ntldr.h index d03cd284e4e0..8f8fea39570d 100644 --- a/phnt/include/ntldr.h +++ b/phnt/include/ntldr.h @@ -5,6 +5,12 @@ // DLLs +typedef BOOLEAN (NTAPI *PLDR_INIT_ROUTINE)( + _In_ PVOID DllHandle, + _In_ ULONG Reason, + _In_opt_ PVOID Context + ); + // symbols typedef struct _LDR_SERVICE_TAG_RECORD { @@ -98,6 +104,7 @@ typedef enum _LDR_DLL_LOAD_REASON #define LDR_DATA_TABLE_ENTRY_SIZE_WINXP FIELD_OFFSET(LDR_DATA_TABLE_ENTRY, DdagNode) #define LDR_DATA_TABLE_ENTRY_SIZE_WIN7 FIELD_OFFSET(LDR_DATA_TABLE_ENTRY, BaseNameHashValue) #define LDR_DATA_TABLE_ENTRY_SIZE_WIN8 FIELD_OFFSET(LDR_DATA_TABLE_ENTRY, ImplicitPathOptions) +#define LDR_DATA_TABLE_ENTRY_SIZE sizeof(LDR_DATA_TABLE_ENTRY) // symbols typedef struct _LDR_DATA_TABLE_ENTRY @@ -110,7 +117,7 @@ typedef struct _LDR_DATA_TABLE_ENTRY LIST_ENTRY InProgressLinks; }; PVOID DllBase; - PVOID EntryPoint; + PLDR_INIT_ROUTINE EntryPoint; ULONG SizeOfImage; UNICODE_STRING FullDllName; UNICODE_STRING BaseDllName; @@ -172,12 +179,6 @@ typedef struct _LDR_DATA_TABLE_ENTRY UCHAR SigningLevel; // since REDSTONE2 } LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY; -typedef BOOLEAN (NTAPI *PDLL_INIT_ROUTINE)( - _In_ PVOID DllHandle, - _In_ ULONG Reason, - _In_opt_ PCONTEXT Context - ); - NTSYSAPI NTSTATUS NTAPI From ef67afdcf439c1fa47b8e6889524d49a7e46b3bb Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 4 Feb 2018 03:56:24 +1100 Subject: [PATCH 0752/2058] Update PEB types --- phnt/include/ntpebteb.h | 42 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/phnt/include/ntpebteb.h b/phnt/include/ntpebteb.h index 7114a1bb7bb9..e6f0a82e372e 100644 --- a/phnt/include/ntpebteb.h +++ b/phnt/include/ntpebteb.h @@ -14,6 +14,46 @@ typedef struct _ACTIVATION_CONTEXT_STACK ULONG StackId; } ACTIVATION_CONTEXT_STACK, *PACTIVATION_CONTEXT_STACK; +// private +typedef struct _API_SET_NAMESPACE +{ + ULONG Version; + ULONG Size; + ULONG Flags; + ULONG Count; + ULONG EntryOffset; + ULONG HashOffset; + ULONG HashFactor; +} API_SET_NAMESPACE, *PAPI_SET_NAMESPACE; + +// private +typedef struct _API_SET_HASH_ENTRY +{ + ULONG Hash; + ULONG Index; +} API_SET_HASH_ENTRY, *PAPI_SET_HASH_ENTRY; + +// private +typedef struct _API_SET_NAMESPACE_ENTRY +{ + ULONG Flags; + ULONG NameOffset; + ULONG NameLength; + ULONG HashedLength; + ULONG ValueOffset; + ULONG ValueCount; +} API_SET_NAMESPACE_ENTRY, *PAPI_SET_NAMESPACE_ENTRY; + +// private +typedef struct _API_SET_VALUE_ENTRY +{ + ULONG Flags; + ULONG NameOffset; + ULONG NameLength; + ULONG ValueOffset; + ULONG ValueLength; +} API_SET_VALUE_ENTRY, *PAPI_SET_VALUE_ENTRY; + // symbols typedef struct _PEB { @@ -68,7 +108,7 @@ typedef struct _PEB }; ULONG SystemReserved[1]; ULONG AtlThunkSListPtr32; - PVOID ApiSetMap; + PAPI_SET_NAMESPACE ApiSetMap; ULONG TlsExpansionCounter; PVOID TlsBitmap; ULONG TlsBitmapBits[2]; From 70d8be3244f0884e844dd3dd5a192df8b01258a7 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 4 Feb 2018 04:31:41 +1100 Subject: [PATCH 0753/2058] Update window subclass callbacks --- ProcessHacker/ProcessHacker.def | 2 ++ ProcessHacker/include/miniinfop.h | 4 +--- ProcessHacker/include/procprpp.h | 5 ++-- ProcessHacker/include/sysinfop.h | 10 ++++---- ProcessHacker/memsrch.c | 13 +++++----- ProcessHacker/miniinfo.c | 36 ++++++++++++++++------------ ProcessHacker/procprp.c | 15 ++++++------ ProcessHacker/searchbox.c | 27 ++++++++++++--------- ProcessHacker/splitter.c | 14 +++++------ ProcessHacker/sysinfo.c | 28 ++++++++++------------ phlib/include/treenewp.h | 6 ++--- phlib/treenew.c | 18 +++++++------- plugins/HardwareDevices/disknotify.c | 11 ++++----- plugins/OnlineChecks/upload.c | 18 ++++++-------- plugins/ToolStatus/main.c | 11 ++++----- plugins/Updater/updater.c | 15 ++++++------ plugins/WindowExplorer/wndprp.c | 26 +++++++++----------- 17 files changed, 123 insertions(+), 136 deletions(-) diff --git a/ProcessHacker/ProcessHacker.def b/ProcessHacker/ProcessHacker.def index 45755ab3a0bd..eafb53d70c24 100644 --- a/ProcessHacker/ProcessHacker.def +++ b/ProcessHacker/ProcessHacker.def @@ -512,6 +512,8 @@ EXPORTS PhGetWindowContext PhSetWindowContext PhRemoveWindowContext + PhRegisterWindowSubclass + PhUnregisterWindowSubclass ; hndlinfo PhEnumObjectTypes diff --git a/ProcessHacker/include/miniinfop.h b/ProcessHacker/include/miniinfop.h index a9c36442e4dc..00e81b5eca46 100644 --- a/ProcessHacker/include/miniinfop.h +++ b/ProcessHacker/include/miniinfop.h @@ -215,9 +215,7 @@ LRESULT CALLBACK PhMipSectionControlHookWndProc( _In_ HWND hwnd, _In_ UINT uMsg, _In_ WPARAM wParam, - _In_ LPARAM lParam, - _In_ UINT_PTR uIdSubclass, - _In_ ULONG_PTR dwRefData + _In_ LPARAM lParam ); // List-based section diff --git a/ProcessHacker/include/procprpp.h b/ProcessHacker/include/procprpp.h index f1878dead5a4..061aa3892692 100644 --- a/ProcessHacker/include/procprpp.h +++ b/ProcessHacker/include/procprpp.h @@ -29,13 +29,12 @@ PPH_PROCESS_PROPSHEETCONTEXT PhpGetPropSheetContext( _In_ HWND hwnd ); -LRESULT CALLBACK PhpPropSheetWndProc( +BOOLEAN CALLBACK PhpPropSheetWndProc( _In_ HWND hwnd, _In_ UINT uMsg, _In_ WPARAM wParam, _In_ LPARAM lParam, - _In_ UINT_PTR uIdSubclass, - _In_ ULONG_PTR dwRefData + _In_ PVOID Context ); VOID NTAPI PhpProcessPropPageContextDeleteProcedure( diff --git a/ProcessHacker/include/sysinfop.h b/ProcessHacker/include/sysinfop.h index 2428889df949..87ed3b71b470 100644 --- a/ProcessHacker/include/sysinfop.h +++ b/ProcessHacker/include/sysinfop.h @@ -189,22 +189,20 @@ VOID PhSipCreateSectionDialog( _In_ PPH_SYSINFO_SECTION Section ); -LRESULT CALLBACK PhSipGraphHookWndProc( +BOOLEAN CALLBACK PhSipGraphHookWndProc( _In_ HWND hwnd, _In_ UINT uMsg, _In_ WPARAM wParam, _In_ LPARAM lParam, - _In_ UINT_PTR uIdSubclass, - _In_ ULONG_PTR dwRefData + _In_ PVOID Context ); -LRESULT CALLBACK PhSipPanelHookWndProc( +BOOLEAN CALLBACK PhSipPanelHookWndProc( _In_ HWND hwnd, _In_ UINT uMsg, _In_ WPARAM wParam, _In_ LPARAM lParam, - _In_ UINT_PTR uIdSubclass, - _In_ ULONG_PTR dwRefData + _In_ PVOID Context ); // Misc. diff --git a/ProcessHacker/memsrch.c b/ProcessHacker/memsrch.c index fe66dd890010..78e4e0e62b91 100644 --- a/ProcessHacker/memsrch.c +++ b/ProcessHacker/memsrch.c @@ -650,21 +650,20 @@ NTSTATUS PhpMemoryStringThreadStart( return STATUS_SUCCESS; } -LRESULT CALLBACK PhpMemoryStringTaskDialogSubclassProc( +BOOLEAN CALLBACK PhpMemoryStringTaskDialogSubclassProc( _In_ HWND hwndDlg, _In_ UINT uMsg, _In_ WPARAM wParam, _In_ LPARAM lParam, - _In_ UINT_PTR uIdSubclass, - _In_ ULONG_PTR dwRefData + _In_ PVOID Context ) { - PMEMORY_STRING_CONTEXT context = (PMEMORY_STRING_CONTEXT)dwRefData; + PMEMORY_STRING_CONTEXT context = (PMEMORY_STRING_CONTEXT)Context; switch (uMsg) { case WM_NCDESTROY: - RemoveWindowSubclass(hwndDlg, PhpMemoryStringTaskDialogSubclassProc, uIdSubclass); + PhUnregisterWindowSubclass(hwndDlg, PhpMemoryStringTaskDialogSubclassProc); break; case WM_PH_MEMORY_STATUS_UPDATE: { @@ -681,7 +680,7 @@ LRESULT CALLBACK PhpMemoryStringTaskDialogSubclassProc( break; } - return DefSubclassProc(hwndDlg, uMsg, wParam, lParam); + return FALSE; } HRESULT CALLBACK PhpMemoryStringTaskDialogCallback( @@ -715,7 +714,7 @@ HRESULT CALLBACK PhpMemoryStringTaskDialogCallback( SendMessage(hwndDlg, TDM_SET_PROGRESS_BAR_MARQUEE, TRUE, 1); // Subclass the Taskdialog. - SetWindowSubclass(hwndDlg, PhpMemoryStringTaskDialogSubclassProc, 0, (ULONG_PTR)context); + PhRegisterWindowSubclass(hwndDlg, PhpMemoryStringTaskDialogSubclassProc, context); // Create the search thread. PhCreateThread2(PhpMemoryStringThreadStart, context); diff --git a/ProcessHacker/miniinfo.c b/ProcessHacker/miniinfo.c index 599135aba062..a3be5d07940e 100644 --- a/ProcessHacker/miniinfo.c +++ b/ProcessHacker/miniinfo.c @@ -452,6 +452,7 @@ VOID PhMipOnInitDialog( { HICON cog; HICON pin; + WNDPROC oldWndProc; cog = PH_LOAD_SHARED_ICON_SMALL(PhInstanceHandle, MAKEINTRESOURCE(IDI_COG)); SET_BUTTON_ICON(PhMipWindow, IDC_OPTIONS, cog); @@ -460,18 +461,17 @@ VOID PhMipOnInitDialog( SET_BUTTON_ICON(PhMipWindow, IDC_PINWINDOW, pin); PhInitializeLayoutManager(&PhMipLayoutManager, PhMipWindow); - PhAddLayoutItem(&PhMipLayoutManager, GetDlgItem(PhMipWindow, IDC_LAYOUT), NULL, - PH_ANCHOR_ALL); - PhAddLayoutItem(&PhMipLayoutManager, GetDlgItem(PhMipWindow, IDC_SECTION), NULL, - PH_ANCHOR_LEFT | PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM | PH_LAYOUT_FORCE_INVALIDATE); - PhAddLayoutItem(&PhMipLayoutManager, GetDlgItem(PhMipWindow, IDC_OPTIONS), NULL, - PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); - PhAddLayoutItem(&PhMipLayoutManager, GetDlgItem(PhMipWindow, IDC_PINWINDOW), NULL, - PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); - - SetWindowSubclass(GetDlgItem(PhMipWindow, IDC_SECTION), PhMipSectionControlHookWndProc, 0, 0); + PhAddLayoutItem(&PhMipLayoutManager, GetDlgItem(PhMipWindow, IDC_LAYOUT), NULL, PH_ANCHOR_ALL); + PhAddLayoutItem(&PhMipLayoutManager, GetDlgItem(PhMipWindow, IDC_SECTION), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM | PH_LAYOUT_FORCE_INVALIDATE); + PhAddLayoutItem(&PhMipLayoutManager, GetDlgItem(PhMipWindow, IDC_OPTIONS), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); + PhAddLayoutItem(&PhMipLayoutManager, GetDlgItem(PhMipWindow, IDC_PINWINDOW), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); Button_SetCheck(GetDlgItem(PhMipWindow, IDC_PINWINDOW), !!PhGetIntegerSetting(L"MiniInfoWindowPinned")); + + // Subclass the window procedure. + oldWndProc = (WNDPROC)GetWindowLongPtr(GetDlgItem(PhMipWindow, IDC_SECTION), GWLP_WNDPROC); + PhSetWindowContext(GetDlgItem(PhMipWindow, IDC_SECTION), 10, oldWndProc); + SetWindowLongPtr(GetDlgItem(PhMipWindow, IDC_SECTION), GWLP_WNDPROC, (LONG_PTR)PhMipSectionControlHookWndProc); } VOID PhMipOnShowWindow( @@ -1154,15 +1154,21 @@ LRESULT CALLBACK PhMipSectionControlHookWndProc( _In_ HWND hwnd, _In_ UINT uMsg, _In_ WPARAM wParam, - _In_ LPARAM lParam, - _In_ UINT_PTR uIdSubclass, - _In_ ULONG_PTR dwRefData + _In_ LPARAM lParam ) { + WNDPROC oldWndProc; + + if (!(oldWndProc = PhGetWindowContext(hwnd, 10))) + return 0; + switch (uMsg) { case WM_DESTROY: - RemoveWindowSubclass(hwnd, PhMipSectionControlHookWndProc, uIdSubclass); + { + SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)oldWndProc); + PhRemoveWindowContext(hwnd, 10); + } break; case WM_SETCURSOR: { @@ -1171,7 +1177,7 @@ LRESULT CALLBACK PhMipSectionControlHookWndProc( return TRUE; } - return DefSubclassProc(hwnd, uMsg, wParam, lParam); + return CallWindowProc(oldWndProc, hwnd, uMsg, wParam, lParam); } PPH_MINIINFO_LIST_SECTION PhMipCreateListSection( diff --git a/ProcessHacker/procprp.c b/ProcessHacker/procprp.c index 593cb33b8114..fec4120ed7fb 100644 --- a/ProcessHacker/procprp.c +++ b/ProcessHacker/procprp.c @@ -168,7 +168,7 @@ INT CALLBACK PhpPropSheetProc( PhInitializeLayoutManager(&propSheetContext->LayoutManager, hwndDlg); PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, propSheetContext); - SetWindowSubclass(hwndDlg, PhpPropSheetWndProc, 0, (ULONG_PTR)propSheetContext); + PhRegisterWindowSubclass(hwndDlg, PhpPropSheetWndProc, propSheetContext); if (MinimumSize.left == -1) { @@ -196,16 +196,15 @@ PPH_PROCESS_PROPSHEETCONTEXT PhpGetPropSheetContext( return PhGetWindowContext(hwnd, PH_WINDOW_CONTEXT_DEFAULT); } -LRESULT CALLBACK PhpPropSheetWndProc( +BOOLEAN CALLBACK PhpPropSheetWndProc( _In_ HWND hwnd, _In_ UINT uMsg, _In_ WPARAM wParam, - _In_ LPARAM lParam, - _In_ UINT_PTR uIdSubclass, - _In_ ULONG_PTR dwRefData + _In_ LPARAM lParam, + _In_ PVOID Context ) { - PPH_PROCESS_PROPSHEETCONTEXT propSheetContext = (PPH_PROCESS_PROPSHEETCONTEXT)dwRefData; + PPH_PROCESS_PROPSHEETCONTEXT propSheetContext = (PPH_PROCESS_PROPSHEETCONTEXT)Context; switch (uMsg) { @@ -235,7 +234,7 @@ LRESULT CALLBACK PhpPropSheetWndProc( break; case WM_NCDESTROY: { - RemoveWindowSubclass(hwnd, PhpPropSheetWndProc, uIdSubclass); + PhUnregisterWindowSubclass(hwnd, PhpPropSheetWndProc); PhRemoveWindowContext(hwnd, PH_WINDOW_CONTEXT_DEFAULT); PhDeleteLayoutManager(&propSheetContext->LayoutManager); @@ -269,7 +268,7 @@ LRESULT CALLBACK PhpPropSheetWndProc( break; } - return DefSubclassProc(hwnd, uMsg, wParam, lParam); + return FALSE; } BOOLEAN PhpInitializePropSheetLayoutStage1( diff --git a/ProcessHacker/searchbox.c b/ProcessHacker/searchbox.c index b6ec86880b23..080bd02e5484 100644 --- a/ProcessHacker/searchbox.c +++ b/ProcessHacker/searchbox.c @@ -48,6 +48,7 @@ typedef struct _EDIT_CONTEXT INT ImageWidth; INT ImageHeight; HWND WindowHandle; + WNDPROC DefaultWindowProc; HFONT WindowFont; HICON BitmapActive; HICON BitmapInactive; @@ -249,12 +250,13 @@ LRESULT CALLBACK PhpSearchWndSubclassProc( _In_ HWND hWnd, _In_ UINT uMsg, _In_ WPARAM wParam, - _In_ LPARAM lParam, - _In_ UINT_PTR uIdSubclass, - _In_ ULONG_PTR dwRefData + _In_ LPARAM lParam ) { - PEDIT_CONTEXT context = (PEDIT_CONTEXT)dwRefData; + PEDIT_CONTEXT context; + + if (!(context = PhGetWindowContext(hWnd, 10))) + return 0; switch (uMsg) { @@ -265,7 +267,8 @@ LRESULT CALLBACK PhpSearchWndSubclassProc( if (context->WindowFont) DeleteObject(context->WindowFont); - RemoveWindowSubclass(hWnd, PhpSearchWndSubclassProc, uIdSubclass); + SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)context->DefaultWindowProc); + PhRemoveWindowContext(hWnd, 10); PhFree(context); } break; @@ -276,7 +279,7 @@ LRESULT CALLBACK PhpSearchWndSubclassProc( LPNCCALCSIZE_PARAMS ncCalcSize = (NCCALCSIZE_PARAMS*)lParam; // Let Windows handle the non-client defaults. - DefSubclassProc(hWnd, uMsg, wParam, lParam); + CallWindowProc(context->DefaultWindowProc, hWnd, uMsg, wParam, lParam); // Deflate the client area to accommodate the custom button. ncCalcSize->rgrc[0].right -= context->CXWidth; @@ -287,7 +290,7 @@ LRESULT CALLBACK PhpSearchWndSubclassProc( RECT windowRect; // Let Windows handle the non-client defaults. - DefSubclassProc(hWnd, uMsg, wParam, lParam); + CallWindowProc(context->DefaultWindowProc, hWnd, uMsg, wParam, lParam); // Get the screen coordinates of the window. GetWindowRect(hWnd, &windowRect); @@ -479,7 +482,7 @@ LRESULT CALLBACK PhpSearchWndSubclassProc( break; } - return DefSubclassProc(hWnd, uMsg, wParam, lParam); + return CallWindowProc(context->DefaultWindowProc, hWnd, uMsg, wParam, lParam); } HICON PhpSearchBitmapToIcon( @@ -520,19 +523,21 @@ VOID PhCreateSearchControl( memset(context, 0, sizeof(EDIT_CONTEXT)); context->WindowHandle = WindowHandle; + context->DefaultWindowProc = (WNDPROC)GetWindowLongPtr(WindowHandle, GWLP_WNDPROC); //PhpSearchInitializeTheme(context); PhpSearchInitializeImages(context); // Set initial text if (BannerText) - Edit_SetCueBannerText(context->WindowHandle, BannerText); + Edit_SetCueBannerText(WindowHandle, BannerText); // Subclass the Edit control window procedure. - SetWindowSubclass(context->WindowHandle, PhpSearchWndSubclassProc, 0, (ULONG_PTR)context); + PhSetWindowContext(WindowHandle, 10, context); + SetWindowLongPtr(WindowHandle, GWLP_WNDPROC, (LONG_PTR)PhpSearchWndSubclassProc); // Initialize the theme parameters. - SendMessage(context->WindowHandle, WM_THEMECHANGED, 0, 0); + SendMessage(WindowHandle, WM_THEMECHANGED, 0, 0); } HBITMAP PhLoadPngImageFromResource( diff --git a/ProcessHacker/splitter.c b/ProcessHacker/splitter.c index df6aa2baed33..1dcb8dba9783 100644 --- a/ProcessHacker/splitter.c +++ b/ProcessHacker/splitter.c @@ -264,23 +264,21 @@ LRESULT CALLBACK HSplitterWindowProc( return DefWindowProc(hwnd, uMsg, wParam, lParam); } -LRESULT CALLBACK HSplitterParentWindowProc( +BOOLEAN CALLBACK HSplitterParentWindowProc( _In_ HWND hwnd, _In_ UINT uMsg, _In_ WPARAM wParam, _In_ LPARAM lParam, - _In_ UINT_PTR uIdSubclass, - _In_ ULONG_PTR dwRefData + _In_ PVOID Context ) { - PPH_HSPLITTER_CONTEXT context = (PPH_HSPLITTER_CONTEXT)dwRefData; + PPH_HSPLITTER_CONTEXT context = (PPH_HSPLITTER_CONTEXT)Context; switch (uMsg) { case WM_DESTROY: { - RemoveWindowSubclass(hwnd, HSplitterParentWindowProc, uIdSubclass); - + PhUnregisterWindowSubclass(hwnd, HSplitterParentWindowProc); PhDeleteHSplitter(context); } break; @@ -291,7 +289,7 @@ LRESULT CALLBACK HSplitterParentWindowProc( break; } - return DefSubclassProc(hwnd, uMsg, wParam, lParam); + return FALSE; } VOID PhInitializeHSplitter( @@ -355,7 +353,7 @@ VOID PhInitializeHSplitter( ShowWindow(context->Window, SW_SHOW); UpdateWindow(context->Window); - SetWindowSubclass(ParentWindow, HSplitterParentWindowProc, 0, (ULONG_PTR)context); + PhRegisterWindowSubclass(ParentWindow, HSplitterParentWindowProc, context); } VOID PhDeleteHSplitter( diff --git a/ProcessHacker/sysinfo.c b/ProcessHacker/sysinfo.c index 509a4b75a5ec..c313c7fc812e 100644 --- a/ProcessHacker/sysinfo.c +++ b/ProcessHacker/sysinfo.c @@ -417,7 +417,7 @@ VOID PhSipOnShowWindow( NULL ); - SetWindowSubclass(RestoreSummaryControl, PhSipPanelHookWndProc, 0, 0); + PhRegisterWindowSubclass(RestoreSummaryControl, PhSipPanelHookWndProc, NULL); RestoreSummaryControlHot = FALSE; EnableThemeDialogTexture(ContainerControl, ETDT_ENABLETAB); @@ -1155,8 +1155,8 @@ PPH_SYSINFO_SECTION PhSipCreateSection( NULL ); - SetWindowSubclass(section->GraphHandle, PhSipGraphHookWndProc, 0, (ULONG_PTR)section); - SetWindowSubclass(section->PanelHandle, PhSipPanelHookWndProc, 0, (ULONG_PTR)section); + PhRegisterWindowSubclass(section->GraphHandle, PhSipGraphHookWndProc, section); + PhRegisterWindowSubclass(section->PanelHandle, PhSipPanelHookWndProc, section); PhAddItemList(SectionList, section); @@ -1715,21 +1715,20 @@ VOID PhSipCreateSectionDialog( } } -LRESULT CALLBACK PhSipGraphHookWndProc( +BOOLEAN CALLBACK PhSipGraphHookWndProc( _In_ HWND hwnd, _In_ UINT uMsg, _In_ WPARAM wParam, _In_ LPARAM lParam, - _In_ UINT_PTR uIdSubclass, - _In_ ULONG_PTR dwRefData + _In_ PVOID Context ) { - PPH_SYSINFO_SECTION section = (PPH_SYSINFO_SECTION)dwRefData; + PPH_SYSINFO_SECTION section = (PPH_SYSINFO_SECTION)Context; switch (uMsg) { case WM_DESTROY: - RemoveWindowSubclass(hwnd, PhSipGraphHookWndProc, uIdSubclass); + PhUnregisterWindowSubclass(hwnd, PhSipGraphHookWndProc); break; case WM_SETFOCUS: section->HasFocus = TRUE; @@ -1865,24 +1864,23 @@ LRESULT CALLBACK PhSipGraphHookWndProc( break; } - return DefSubclassProc(hwnd, uMsg, wParam, lParam); + return FALSE; } -LRESULT CALLBACK PhSipPanelHookWndProc( +BOOLEAN CALLBACK PhSipPanelHookWndProc( _In_ HWND hwnd, _In_ UINT uMsg, _In_ WPARAM wParam, _In_ LPARAM lParam, - _In_ UINT_PTR uIdSubclass, - _In_ ULONG_PTR dwRefData + _In_ PVOID Context ) { - PPH_SYSINFO_SECTION section = (PPH_SYSINFO_SECTION)dwRefData; + PPH_SYSINFO_SECTION section = (PPH_SYSINFO_SECTION)Context; switch (uMsg) { case WM_DESTROY: - RemoveWindowSubclass(hwnd, PhSipPanelHookWndProc, uIdSubclass); + PhUnregisterWindowSubclass(hwnd, PhSipPanelHookWndProc); break; case WM_SETFOCUS: { @@ -1986,7 +1984,7 @@ LRESULT CALLBACK PhSipPanelHookWndProc( break; } - return DefSubclassProc(hwnd, uMsg, wParam, lParam); + return FALSE; } VOID PhSipUpdateThemeData( diff --git a/phlib/include/treenewp.h b/phlib/include/treenewp.h index 21fcfb9b95b1..fc0dc1974680 100644 --- a/phlib/include/treenewp.h +++ b/phlib/include/treenewp.h @@ -730,14 +730,12 @@ VOID PhTnpGetHeaderTooltipText( _Out_ PWSTR *Text ); - -LRESULT CALLBACK PhTnpHeaderHookWndProc( +BOOLEAN CALLBACK PhTnpHeaderHookWndProc( _In_ HWND hwnd, _In_ UINT uMsg, _In_ WPARAM wParam, _In_ LPARAM lParam, - _In_ UINT_PTR uIdSubclass, - _In_ ULONG_PTR dwRefData + _In_ PVOID Context ); // Drag selection diff --git a/phlib/treenew.c b/phlib/treenew.c index 492739319042..1330fc93376d 100644 --- a/phlib/treenew.c +++ b/phlib/treenew.c @@ -5845,10 +5845,9 @@ VOID PhTnpInitializeTooltips( toolInfo.lParam = TNP_TOOLTIPS_HEADER; SendMessage(Context->TooltipsHandle, TTM_ADDTOOL, 0, (LPARAM)&toolInfo); - // Hook the header control window procedures so we can forward mouse messages to the tooltip - // control. - SetWindowSubclass(Context->FixedHeaderHandle, PhTnpHeaderHookWndProc, 0, (ULONG_PTR)Context); - SetWindowSubclass(Context->HeaderHandle, PhTnpHeaderHookWndProc, 0, (ULONG_PTR)Context); + // Hook the header control window procedures so we can forward mouse messages to the tooltip control. + PhRegisterWindowSubclass(Context->FixedHeaderHandle, PhTnpHeaderHookWndProc, Context); + PhRegisterWindowSubclass(Context->HeaderHandle, PhTnpHeaderHookWndProc, Context); SendMessage(Context->TooltipsHandle, TTM_SETMAXTIPWIDTH, 0, MAXSHORT); // no limit SendMessage(Context->TooltipsHandle, WM_SETFONT, (WPARAM)Context->Font, FALSE); @@ -6135,21 +6134,20 @@ VOID PhTnpGetHeaderTooltipText( SendMessage(Context->TooltipsHandle, TTM_SETMAXTIPWIDTH, 0, TNP_TOOLTIPS_DEFAULT_MAXIMUM_WIDTH); } -LRESULT CALLBACK PhTnpHeaderHookWndProc( +BOOLEAN CALLBACK PhTnpHeaderHookWndProc( _In_ HWND hwnd, _In_ UINT uMsg, _In_ WPARAM wParam, _In_ LPARAM lParam, - _In_ UINT_PTR uIdSubclass, - _In_ ULONG_PTR dwRefData + _In_ PVOID Context ) { - PPH_TREENEW_CONTEXT context = (PPH_TREENEW_CONTEXT)dwRefData; + PPH_TREENEW_CONTEXT context = (PPH_TREENEW_CONTEXT)Context; switch (uMsg) { case WM_DESTROY: - RemoveWindowSubclass(hwnd, PhTnpHeaderHookWndProc, uIdSubclass); + PhUnregisterWindowSubclass(hwnd, PhTnpHeaderHookWndProc); break; case WM_MOUSEMOVE: { @@ -6235,7 +6233,7 @@ LRESULT CALLBACK PhTnpHeaderHookWndProc( break; } - return DefSubclassProc(hwnd, uMsg, wParam, lParam); + return FALSE; } BOOLEAN PhTnpDetectDrag( diff --git a/plugins/HardwareDevices/disknotify.c b/plugins/HardwareDevices/disknotify.c index f4025a6cc345..c227704b1e8a 100644 --- a/plugins/HardwareDevices/disknotify.c +++ b/plugins/HardwareDevices/disknotify.c @@ -25,13 +25,12 @@ static BOOLEAN SubclassActive = FALSE; -LRESULT CALLBACK MainWndDevicesSubclassProc( +BOOLEAN CALLBACK MainWndDevicesSubclassProc( _In_ HWND hWnd, _In_ UINT uMsg, _In_ WPARAM wParam, _In_ LPARAM lParam, - _In_ UINT_PTR uIdSubclass, - _In_ ULONG_PTR dwRefData + _In_ PVOID Context ) { // Subclassing the main window just to process drive letter notifications @@ -81,7 +80,7 @@ LRESULT CALLBACK MainWndDevicesSubclassProc( break; } - return DefSubclassProc(hWnd, uMsg, wParam, lParam); + return FALSE; } VOID AddRemoveDeviceChangeCallback( @@ -98,7 +97,7 @@ VOID AddRemoveDeviceChangeCallback( if (!SubclassActive) { // We have a disk device, subclass the main window to detect drive letter changes. - SetWindowSubclass(PhMainWndHandle, MainWndDevicesSubclassProc, 0, 0); + PhRegisterWindowSubclass(PhMainWndHandle, MainWndDevicesSubclassProc, NULL); SubclassActive = TRUE; } } @@ -107,7 +106,7 @@ VOID AddRemoveDeviceChangeCallback( if (SubclassActive) { // The user has removed the last disk device, remove the subclass. - RemoveWindowSubclass(PhMainWndHandle, MainWndDevicesSubclassProc, 0); + PhUnregisterWindowSubclass(PhMainWndHandle, MainWndDevicesSubclassProc); SubclassActive = FALSE; } } diff --git a/plugins/OnlineChecks/upload.c b/plugins/OnlineChecks/upload.c index fabb0a4353bd..97d871d9c094 100644 --- a/plugins/OnlineChecks/upload.c +++ b/plugins/OnlineChecks/upload.c @@ -1169,25 +1169,22 @@ NTSTATUS UploadRecheckThreadStart( return STATUS_SUCCESS; } - -LRESULT CALLBACK TaskDialogSubclassProc( +BOOLEAN CALLBACK TaskDialogSubclassProc( _In_ HWND hwndDlg, _In_ UINT uMsg, _In_ WPARAM wParam, _In_ LPARAM lParam, - _In_ UINT_PTR uIdSubclass, - _In_ ULONG_PTR dwRefData + _In_ PVOID Context ) { - PUPLOAD_CONTEXT context = (PUPLOAD_CONTEXT)dwRefData; + PUPLOAD_CONTEXT context = (PUPLOAD_CONTEXT)Context; switch (uMsg) { - case WM_NCDESTROY: + case WM_DESTROY: { TaskDialogFreeContext(context); - - RemoveWindowSubclass(hwndDlg, TaskDialogSubclassProc, uIdSubclass); + PhUnregisterWindowSubclass(hwndDlg, TaskDialogSubclassProc); } break; case UM_UPLOAD: @@ -1243,7 +1240,7 @@ LRESULT CALLBACK TaskDialogSubclassProc( break; } - return DefSubclassProc(hwndDlg, uMsg, wParam, lParam); + return FALSE; } HRESULT CALLBACK TaskDialogBootstrapCallback( @@ -1277,8 +1274,7 @@ HRESULT CALLBACK TaskDialogBootstrapCallback( } } - // Subclass the Taskdialog - SetWindowSubclass(hwndDlg, TaskDialogSubclassProc, 0, (ULONG_PTR)context); + PhRegisterWindowSubclass(hwndDlg, TaskDialogSubclassProc, context); ShowVirusTotalUploadDialog(context); } diff --git a/plugins/ToolStatus/main.c b/plugins/ToolStatus/main.c index 9ca760f3e568..6e653d207597 100644 --- a/plugins/ToolStatus/main.c +++ b/plugins/ToolStatus/main.c @@ -620,13 +620,12 @@ VOID DrawWindowBorderForTargeting( } } -LRESULT CALLBACK MainWndSubclassProc( +BOOLEAN CALLBACK MainWndSubclassProc( _In_ HWND hWnd, _In_ UINT uMsg, _In_ WPARAM wParam, _In_ LPARAM lParam, - _In_ UINT_PTR uIdSubclass, - _In_ ULONG_PTR dwRefData + _In_ PVOID Context ) { switch (uMsg) @@ -1306,10 +1305,10 @@ LRESULT CALLBACK MainWndSubclassProc( break; } - return DefSubclassProc(hWnd, uMsg, wParam, lParam); + return FALSE; DefaultWndProc: - return DefWindowProc(hWnd, uMsg, wParam, lParam); + return TRUE; } VOID NTAPI MainWindowShowingCallback( @@ -1324,7 +1323,7 @@ VOID NTAPI MainWindowShowingCallback( NULL, &LayoutPaddingCallbackRegistration ); - SetWindowSubclass(PhMainWndHandle, MainWndSubclassProc, 0, 0); + PhRegisterWindowSubclass(PhMainWndHandle, MainWndSubclassProc, NULL); ToolbarLoadSettings(); ReBarLoadLayoutSettings(); diff --git a/plugins/Updater/updater.c b/plugins/Updater/updater.c index 6e593160c14f..040435c7a5ee 100644 --- a/plugins/Updater/updater.c +++ b/plugins/Updater/updater.c @@ -755,16 +755,15 @@ NTSTATUS UpdateDownloadThread( return STATUS_SUCCESS; } -LRESULT CALLBACK TaskDialogSubclassProc( +BOOLEAN NTAPI TaskDialogSubclassProc( _In_ HWND hwndDlg, _In_ UINT uMsg, _In_ WPARAM wParam, _In_ LPARAM lParam, - _In_ UINT_PTR uIdSubclass, - _In_ ULONG_PTR dwRefData + _In_ PVOID Context ) { - PPH_UPDATER_CONTEXT context = (PPH_UPDATER_CONTEXT)dwRefData; + PPH_UPDATER_CONTEXT context = (PPH_UPDATER_CONTEXT)Context; switch (uMsg) { @@ -778,9 +777,9 @@ LRESULT CALLBACK TaskDialogSubclassProc( SetForegroundWindow(hwndDlg); } break; - case WM_NCDESTROY: + case WM_DESTROY: { - RemoveWindowSubclass(hwndDlg, TaskDialogSubclassProc, uIdSubclass); + PhUnregisterWindowSubclass(hwndDlg, TaskDialogSubclassProc); } break; //case WM_PARENTNOTIFY: @@ -825,7 +824,7 @@ LRESULT CALLBACK TaskDialogSubclassProc( // break; } - return DefSubclassProc(hwndDlg, uMsg, wParam, lParam); + return FALSE; } HRESULT CALLBACK TaskDialogBootstrapCallback( @@ -851,7 +850,7 @@ HRESULT CALLBACK TaskDialogBootstrapCallback( TaskDialogCreateIcons(context); // Subclass the Taskdialog - SetWindowSubclass(hwndDlg, TaskDialogSubclassProc, 0, (ULONG_PTR)context); + PhRegisterWindowSubclass(hwndDlg, TaskDialogSubclassProc, context); if (context->StartupCheck) ShowAvailableDialog(context); diff --git a/plugins/WindowExplorer/wndprp.c b/plugins/WindowExplorer/wndprp.c index 98360506b553..865fb60ba65c 100644 --- a/plugins/WindowExplorer/wndprp.c +++ b/plugins/WindowExplorer/wndprp.c @@ -94,11 +94,12 @@ INT CALLBACK WepPropSheetProc( _In_ LPARAM lParam ); -LRESULT CALLBACK WepPropSheetWndProc( +BOOLEAN CALLBACK WepPropSheetWndProc( _In_ HWND hwnd, _In_ UINT uMsg, _In_ WPARAM wParam, - _In_ LPARAM lParam + _In_ LPARAM lParam, + _In_ PVOID Context ); HPROPSHEETPAGE WepCommonCreatePage( @@ -357,12 +358,9 @@ static INT CALLBACK WepPropSheetProc( { case PSCB_INITIALIZED: { - WNDPROC oldWndProc; HWND refreshButtonHandle; - oldWndProc = (WNDPROC)GetWindowLongPtr(hwndDlg, GWLP_WNDPROC); - SetWindowLongPtr(hwndDlg, GWLP_WNDPROC, (LONG_PTR)WepPropSheetWndProc); - PhSetWindowContext(hwndDlg, 1, (HANDLE)oldWndProc); + PhRegisterWindowSubclass(hwndDlg, WepPropSheetWndProc, NULL); // Hide the Cancel button. ShowWindow(GetDlgItem(hwndDlg, IDCANCEL), SW_HIDE); @@ -379,27 +377,24 @@ static INT CALLBACK WepPropSheetProc( return 0; } -LRESULT CALLBACK WepPropSheetWndProc( +BOOLEAN CALLBACK WepPropSheetWndProc( _In_ HWND hwnd, _In_ UINT uMsg, _In_ WPARAM wParam, - _In_ LPARAM lParam + _In_ LPARAM lParam, + _In_ PVOID Context ) { - WNDPROC oldWndProc = PhGetWindowContext(hwnd, 1); - switch (uMsg) { case WM_DESTROY: { - SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)oldWndProc); PhRemoveWindowContext(hwnd, 1); - PhRemoveWindowContext(hwnd, 2); } break; case WM_SHOWWINDOW: { - if (!PhGetWindowContext(hwnd, 2)) + if (!PhGetWindowContext(hwnd, 1)) { // Move the Refresh button to where the OK button is, and move the OK button to // where the Cancel button is. @@ -407,7 +402,8 @@ LRESULT CALLBACK WepPropSheetWndProc( // in the right places. PhCopyControlRectangle(hwnd, GetDlgItem(hwnd, IDOK), GetDlgItem(hwnd, IDC_REFRESH)); PhCopyControlRectangle(hwnd, GetDlgItem(hwnd, IDCANCEL), GetDlgItem(hwnd, IDOK)); - PhSetWindowContext(hwnd, 2, UlongToPtr(1)); + + PhSetWindowContext(hwnd, 1, UlongToPtr(1)); } } break; @@ -433,7 +429,7 @@ LRESULT CALLBACK WepPropSheetWndProc( break; } - return CallWindowProc(oldWndProc, hwnd, uMsg, wParam, lParam); + return FALSE; } static HPROPSHEETPAGE WepCommonCreatePage( From 9a42ebf84501f464159a3dd56caa56002688b754 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 4 Feb 2018 05:54:19 +1100 Subject: [PATCH 0754/2058] Add listview group wrappers --- phlib/guisup.c | 45 ++++++++++++++++++++++++++++++++++++++++++ phlib/include/guisup.h | 19 ++++++++++++++++++ 2 files changed, 64 insertions(+) diff --git a/phlib/guisup.c b/phlib/guisup.c index b5e0001a1d57..c5eb12b8346d 100644 --- a/phlib/guisup.c +++ b/phlib/guisup.c @@ -246,6 +246,51 @@ VOID PhSetListViewSubItem( ListView_SetItem(ListViewHandle, &item); } +INT PhAddListViewGroup( + _In_ HWND ListViewHandle, + _In_ INT GroupId, + _In_ PWSTR Text + ) +{ + LVGROUP group; + + memset(&group, 0, sizeof(LVGROUP)); + group.cbSize = sizeof(LVGROUP); + group.mask = LVGF_HEADER | LVGF_ALIGN | LVGF_STATE | LVGF_GROUPID; + group.uAlign = LVGA_HEADER_LEFT; + group.state = LVGS_COLLAPSIBLE; + group.iGroupId = GroupId; + group.pszHeader = Text; + + return (INT)ListView_InsertGroup(ListViewHandle, MAXINT, &group); +} + +INT PhAddListViewGroupItem( + _In_ HWND ListViewHandle, + _In_ INT GroupId, + _In_ INT Index, + _In_ PWSTR Text, + _In_opt_ PVOID Param + ) +{ + LVITEM item; + + item.mask = LVIF_TEXT | LVIF_GROUPID; + item.iItem = Index; + item.iSubItem = 0; + item.pszText = Text; + item.iGroupId = GroupId; + + if (Param) + { + item.mask |= LVIF_PARAM; + item.lParam = (LPARAM)Param; + } + + return ListView_InsertItem(ListViewHandle, &item); +} + + INT PhAddTabControlTab( _In_ HWND TabControlHandle, _In_ INT Index, diff --git a/phlib/include/guisup.h b/phlib/include/guisup.h index 832df97fc2b4..216536889b6f 100644 --- a/phlib/include/guisup.h +++ b/phlib/include/guisup.h @@ -247,6 +247,25 @@ VOID PhSetListViewSubItem( _In_ PWSTR Text ); +PHLIBAPI +INT +NTAPI +PhAddListViewGroup( + _In_ HWND ListViewHandle, + _In_ INT GroupId, + _In_ PWSTR Text + ); + +PHLIBAPI +INT +NTAPI PhAddListViewGroupItem( + _In_ HWND ListViewHandle, + _In_ INT GroupId, + _In_ INT Index, + _In_ PWSTR Text, + _In_opt_ PVOID Param + ); + PHLIBAPI INT PhAddTabControlTab( _In_ HWND TabControlHandle, From aa8cbb286f7a73f1d2a66f9af339822af392c677 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 4 Feb 2018 05:59:06 +1100 Subject: [PATCH 0755/2058] Update process statistics tab layout --- ProcessHacker/ProcessHacker.rc | 68 +------- ProcessHacker/prpgstat.c | 304 ++++++++++++++++++++++----------- ProcessHacker/resource.h | 5 +- 3 files changed, 214 insertions(+), 163 deletions(-) diff --git a/ProcessHacker/ProcessHacker.rc b/ProcessHacker/ProcessHacker.rc index f057df71c700..b3f3f753654d 100644 --- a/ProcessHacker/ProcessHacker.rc +++ b/ProcessHacker/ProcessHacker.rc @@ -1247,65 +1247,7 @@ STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSM CAPTION "Statistics" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN - GROUPBOX "CPU",IDC_STATIC,7,7,119,64 - GROUPBOX "I/O",IDC_STATIC,131,7,122,83 - LTEXT "Priority",IDC_STATIC,14,17,24,8 - LTEXT "Cycles",IDC_STATIC,14,27,22,8 - LTEXT "Kernel time",IDC_STATIC,14,37,38,8 - LTEXT "User time",IDC_STATIC,14,47,32,8 - LTEXT "Total time",IDC_STATIC,14,57,34,8 - RTEXT "Static",IDC_ZPRIORITY_V,59,17,61,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZCYCLES_V,43,27,77,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZKERNELTIME_V,59,37,61,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZUSERTIME_V,59,47,61,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZTOTALTIME_V,59,57,61,8,SS_ENDELLIPSIS - GROUPBOX "Memory",IDC_STATIC,7,74,120,128 - LTEXT "Private bytes",IDC_STATIC,14,84,44,8 - LTEXT "Working set",IDC_STATIC,14,136,40,8 - LTEXT "Peak working set",IDC_STATIC,14,178,57,8 - LTEXT "Virtual size",IDC_STATIC,14,105,36,8 - LTEXT "Peak virtual size",IDC_STATIC,14,115,53,8 - LTEXT "Peak private bytes",IDC_STATIC,14,95,61,8 - LTEXT "Page faults",IDC_STATIC,14,125,38,8 - LTEXT "Page priority",IDC_STATIC,14,188,42,8 - RTEXT "Static",IDC_ZPRIVATEBYTES_V,72,84,48,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZWORKINGSET_V,72,136,48,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZPEAKWORKINGSET_V,78,178,42,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZVIRTUALSIZE_V,72,105,48,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZPEAKVIRTUALSIZE_V,72,115,48,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZPEAKPRIVATEBYTES_V,80,95,40,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZPAGEFAULTS_V,72,125,48,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZPAGEPRIORITY_V,72,188,48,8,SS_ENDELLIPSIS - LTEXT "Reads",IDC_STATIC,138,17,21,8 - LTEXT "Read bytes",IDC_STATIC,138,27,38,8 - LTEXT "Writes",IDC_STATIC,138,37,22,8 - LTEXT "Write bytes",IDC_STATIC,138,47,38,8 - LTEXT "Other",IDC_STATIC,138,57,20,8 - LTEXT "Other bytes",IDC_STATIC,138,67,40,8 - LTEXT "I/O priority",IDC_STATIC,138,77,36,8 - RTEXT "Static",IDC_ZIOREADS_V,184,17,63,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZIOREADBYTES_V,184,27,63,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZIOWRITES_V,184,37,63,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZIOWRITEBYTES_V,184,47,63,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZIOOTHER_V,184,57,63,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZIOOTHERBYTES_V,184,67,63,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZIOPRIORITY_V,184,77,63,8,SS_ENDELLIPSIS - GROUPBOX "Other",IDC_STATIC,131,92,122,70 - LTEXT "Handles",IDC_STATIC,138,102,26,8 - LTEXT "GDI handles",IDC_STATIC,138,122,40,8 - LTEXT "USER handles",IDC_STATIC,138,132,46,8 - RTEXT "Static",IDC_ZHANDLES_V,193,102,54,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZGDIHANDLES_V,193,122,54,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZUSERHANDLES_V,193,132,54,8,SS_ENDELLIPSIS - PUSHBUTTON "Details",IDC_DETAILS,137,143,50,14 - LTEXT "Peak handles",IDC_STATIC,138,112,44,8 - RTEXT "Static",IDC_ZPEAKHANDLES_V,192,112,55,8,SS_ENDELLIPSIS - LTEXT "Private WS",IDC_STATIC,22,147,36,8 - LTEXT "Shareable WS",IDC_STATIC,22,157,46,8 - LTEXT "Shared WS",IDC_STATIC,22,167,36,8 - RTEXT "Static",IDC_ZPRIVATEWS_V,78,147,42,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZSHAREABLEWS_V,78,157,42,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZSHAREDWS_V,78,167,42,8,SS_ENDELLIPSIS + CONTROL "",IDC_STATISTICS_LIST,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_ALIGNLEFT | LVS_NOCOLUMNHEADER | WS_BORDER | WS_TABSTOP,2,3,255,255 END IDD_OPTADVANCED DIALOGEX 0, 0, 317, 225 @@ -2206,10 +2148,10 @@ BEGIN IDD_PROCSTATISTICS, DIALOG BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 253 - TOPMARGIN, 7 - BOTTOMMARGIN, 253 + LEFTMARGIN, 2 + RIGHTMARGIN, 257 + TOPMARGIN, 3 + BOTTOMMARGIN, 258 END IDD_OPTADVANCED, DIALOG diff --git a/ProcessHacker/prpgstat.c b/ProcessHacker/prpgstat.c index 18eecfc8b870..67f9b6f125b2 100644 --- a/ProcessHacker/prpgstat.c +++ b/ProcessHacker/prpgstat.c @@ -3,6 +3,7 @@ * Process properties: Statistics page * * Copyright (C) 2009-2016 wj32 + * Copyright (C) 2017-2018 dmex * * This file is part of Process Hacker. * @@ -23,67 +24,142 @@ #include #include #include - #include +#include -static VOID NTAPI StatisticsUpdateHandler( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context +typedef enum _PH_PROCESS_STATISTICS_CATEGORY +{ + PH_PROCESS_STATISTICS_CATEGORY_CPU, + PH_PROCESS_STATISTICS_CATEGORY_MEMORY, + PH_PROCESS_STATISTICS_CATEGORY_IO, + PH_PROCESS_STATISTICS_CATEGORY_OTHER, + PH_PROCESS_STATISTICS_CATEGORY_EXTENSION +} PH_PROCESS_STATISTICS_CATEGORY; + +typedef enum _PH_PROCESS_STATISTICS_INDEX +{ + PH_PROCESS_STATISTICS_INDEX_PRIORITY, + PH_PROCESS_STATISTICS_INDEX_CYCLES, + PH_PROCESS_STATISTICS_INDEX_KERNELTIME, + PH_PROCESS_STATISTICS_INDEX_USERTIME, + PH_PROCESS_STATISTICS_INDEX_TOTALTIME, + + PH_PROCESS_STATISTICS_INDEX_PRIVATEBYTES, + PH_PROCESS_STATISTICS_INDEX_PEAKPRIVATEBYTES, + PH_PROCESS_STATISTICS_INDEX_VIRTUALSIZE, + PH_PROCESS_STATISTICS_INDEX_PEAKVIRTUALSIZE, + PH_PROCESS_STATISTICS_INDEX_PAGEFAULTS, + PH_PROCESS_STATISTICS_INDEX_WORKINGSET, + PH_PROCESS_STATISTICS_INDEX_PEAKWORKINGSET, + PH_PROCESS_STATISTICS_INDEX_PRIVATEWS, + PH_PROCESS_STATISTICS_INDEX_SHAREABLEWS, + PH_PROCESS_STATISTICS_INDEX_SHAREDWS, + PH_PROCESS_STATISTICS_INDEX_PAGEPRIORITY, + + PH_PROCESS_STATISTICS_INDEX_READS, + PH_PROCESS_STATISTICS_INDEX_READBYTES, + PH_PROCESS_STATISTICS_INDEX_WRITES, + PH_PROCESS_STATISTICS_INDEX_WRITEBYTES, + PH_PROCESS_STATISTICS_INDEX_OTHER, + PH_PROCESS_STATISTICS_INDEX_OTHERBYTES, + PH_PROCESS_STATISTICS_INDEX_IOPRIORITY, + + PH_PROCESS_STATISTICS_INDEX_HANDLES, + PH_PROCESS_STATISTICS_INDEX_PEAKHANDLES, + PH_PROCESS_STATISTICS_INDEX_GDIHANDLES, + PH_PROCESS_STATISTICS_INDEX_USERHANDLES, + + PH_PROCESS_STATISTICS_INDEX_CONTEXTSWITCHES, + PH_PROCESS_STATISTICS_INDEX_DISKENERGY, + PH_PROCESS_STATISTICS_INDEX_NETWORKTAILENERGY, + PH_PROCESS_STATISTICS_INDEX_MBBTAILENERGY, + PH_PROCESS_STATISTICS_INDEX_NETWORKTXRXBYTES, + PH_PROCESS_STATISTICS_INDEX_MBBTXRXBYTES, + PH_PROCESS_STATISTICS_INDEX_FOREGROUNDDURATION +} PH_PROCESS_STATISTICS_INDEX; + +VOID PhpUpdateStatisticsAddListViewGroups( + _In_ HWND ListViewHandle ) { - PPH_STATISTICS_CONTEXT statisticsContext = (PPH_STATISTICS_CONTEXT)Context; - - if (statisticsContext->Enabled) - PostMessage(statisticsContext->WindowHandle, WM_PH_STATISTICS_UPDATE, 0, 0); + ListView_EnableGroupView(ListViewHandle, TRUE); + + PhAddListViewGroup(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_CPU, L"CPU"); + PhAddListViewGroup(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_MEMORY, L"Memory"); + PhAddListViewGroup(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_IO, L"I/O"); + PhAddListViewGroup(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_OTHER, L"Other"); + PhAddListViewGroup(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_EXTENSION, L"Extension"); + + PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_CPU, PH_PROCESS_STATISTICS_INDEX_PRIORITY, L"Priority", NULL); + PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_CPU, PH_PROCESS_STATISTICS_INDEX_CYCLES, L"Cycles", NULL); + PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_CPU, PH_PROCESS_STATISTICS_INDEX_KERNELTIME, L"Kernel time", NULL); + PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_CPU, PH_PROCESS_STATISTICS_INDEX_USERTIME, L"User time", NULL); + PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_CPU, PH_PROCESS_STATISTICS_INDEX_TOTALTIME, L"Total time", NULL); + PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_MEMORY, PH_PROCESS_STATISTICS_INDEX_PRIVATEBYTES, L"Private bytes", NULL); + PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_MEMORY, PH_PROCESS_STATISTICS_INDEX_PEAKPRIVATEBYTES, L"Peak private bytes", NULL); + PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_MEMORY, PH_PROCESS_STATISTICS_INDEX_VIRTUALSIZE, L"Virtual size", NULL); + PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_MEMORY, PH_PROCESS_STATISTICS_INDEX_PEAKVIRTUALSIZE, L"Peak virtual size", NULL); + PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_MEMORY, PH_PROCESS_STATISTICS_INDEX_PAGEFAULTS, L"Page faults", NULL); + PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_MEMORY, PH_PROCESS_STATISTICS_INDEX_WORKINGSET, L"Working set", NULL); + PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_MEMORY, PH_PROCESS_STATISTICS_INDEX_PEAKWORKINGSET, L"Peak working set", NULL); + PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_MEMORY, PH_PROCESS_STATISTICS_INDEX_PRIVATEWS, L"Private WS", NULL); + PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_MEMORY, PH_PROCESS_STATISTICS_INDEX_SHAREABLEWS, L"Shareable WS", NULL); + PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_MEMORY, PH_PROCESS_STATISTICS_INDEX_SHAREDWS, L"Shared WS", NULL); + PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_MEMORY, PH_PROCESS_STATISTICS_INDEX_PAGEPRIORITY, L"Page priority", NULL); + PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_IO, PH_PROCESS_STATISTICS_INDEX_READS, L"Reads", NULL); + PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_IO, PH_PROCESS_STATISTICS_INDEX_READBYTES, L"Read bytes", NULL); + PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_IO, PH_PROCESS_STATISTICS_INDEX_WRITES, L"Writes", NULL); + PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_IO, PH_PROCESS_STATISTICS_INDEX_WRITEBYTES, L"Write bytes", NULL); + PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_IO, PH_PROCESS_STATISTICS_INDEX_OTHER, L"Other", NULL); + PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_IO, PH_PROCESS_STATISTICS_INDEX_OTHERBYTES, L"Other bytes", NULL); + PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_IO, PH_PROCESS_STATISTICS_INDEX_IOPRIORITY, L"I/O priority", NULL); + PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_OTHER, PH_PROCESS_STATISTICS_INDEX_HANDLES, L"Handles", NULL); + PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_OTHER, PH_PROCESS_STATISTICS_INDEX_PEAKHANDLES, L"Peak handles", NULL); + PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_OTHER, PH_PROCESS_STATISTICS_INDEX_GDIHANDLES, L"GDI handles", NULL); + PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_OTHER, PH_PROCESS_STATISTICS_INDEX_USERHANDLES, L"USER handles", NULL); + + if (WindowsVersion >= WINDOWS_10_RS3 || !PhIsExecutingInWow64()) + { + PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_EXTENSION, PH_PROCESS_STATISTICS_INDEX_CONTEXTSWITCHES, L"ContextSwitches", NULL); + PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_EXTENSION, PH_PROCESS_STATISTICS_INDEX_DISKENERGY, L"DiskEnergy", NULL); + PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_EXTENSION, PH_PROCESS_STATISTICS_INDEX_NETWORKTAILENERGY, L"NetworkTailEnergy", NULL); + PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_EXTENSION, PH_PROCESS_STATISTICS_INDEX_MBBTAILENERGY, L"MBBTailEnergy", NULL); + PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_EXTENSION, PH_PROCESS_STATISTICS_INDEX_NETWORKTXRXBYTES, L"NetworkTxRxBytes", NULL); + PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_EXTENSION, PH_PROCESS_STATISTICS_INDEX_MBBTXRXBYTES, L"MBBTxRxBytes", NULL); + PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_EXTENSION, PH_PROCESS_STATISTICS_INDEX_FOREGROUNDDURATION, L"ForegroundDuration", NULL); + } } VOID PhpUpdateProcessStatistics( - _In_ HWND hwndDlg, _In_ PPH_PROCESS_ITEM ProcessItem, _In_ PPH_STATISTICS_CONTEXT Context ) { - WCHAR timeSpan[PH_TIMESPAN_STR_LEN_1]; - - SetDlgItemInt(hwndDlg, IDC_ZPRIORITY_V, ProcessItem->BasePriority, TRUE); // priority - PhPrintTimeSpan(timeSpan, ProcessItem->KernelTime.QuadPart, PH_TIMESPAN_HMSM); // kernel time - SetDlgItemText(hwndDlg, IDC_ZKERNELTIME_V, timeSpan); - PhPrintTimeSpan(timeSpan, ProcessItem->UserTime.QuadPart, PH_TIMESPAN_HMSM); // user time - SetDlgItemText(hwndDlg, IDC_ZUSERTIME_V, timeSpan); - PhPrintTimeSpan(timeSpan, - ProcessItem->KernelTime.QuadPart + ProcessItem->UserTime.QuadPart, PH_TIMESPAN_HMSM); // total time - SetDlgItemText(hwndDlg, IDC_ZTOTALTIME_V, timeSpan); - - SetDlgItemText(hwndDlg, IDC_ZPRIVATEBYTES_V, - PhaFormatSize(ProcessItem->VmCounters.PagefileUsage, -1)->Buffer); // private bytes (same as PrivateUsage) - SetDlgItemText(hwndDlg, IDC_ZPEAKPRIVATEBYTES_V, - PhaFormatSize(ProcessItem->VmCounters.PeakPagefileUsage, -1)->Buffer); // peak private bytes - SetDlgItemText(hwndDlg, IDC_ZVIRTUALSIZE_V, - PhaFormatSize(ProcessItem->VmCounters.VirtualSize, -1)->Buffer); // virtual size - SetDlgItemText(hwndDlg, IDC_ZPEAKVIRTUALSIZE_V, - PhaFormatSize(ProcessItem->VmCounters.PeakVirtualSize, -1)->Buffer); // peak virtual size - SetDlgItemText(hwndDlg, IDC_ZPAGEFAULTS_V, - PhaFormatUInt64(ProcessItem->VmCounters.PageFaultCount, TRUE)->Buffer); // page faults - SetDlgItemText(hwndDlg, IDC_ZWORKINGSET_V, - PhaFormatSize(ProcessItem->VmCounters.WorkingSetSize, -1)->Buffer); // working set - SetDlgItemText(hwndDlg, IDC_ZPEAKWORKINGSET_V, - PhaFormatSize(ProcessItem->VmCounters.PeakWorkingSetSize, -1)->Buffer); // peak working set - - SetDlgItemText(hwndDlg, IDC_ZIOREADS_V, - PhaFormatUInt64(ProcessItem->IoCounters.ReadOperationCount, TRUE)->Buffer); // reads - SetDlgItemText(hwndDlg, IDC_ZIOREADBYTES_V, - PhaFormatSize(ProcessItem->IoCounters.ReadTransferCount, -1)->Buffer); // read bytes - SetDlgItemText(hwndDlg, IDC_ZIOWRITES_V, - PhaFormatUInt64(ProcessItem->IoCounters.WriteOperationCount, TRUE)->Buffer); // writes - SetDlgItemText(hwndDlg, IDC_ZIOWRITEBYTES_V, - PhaFormatSize(ProcessItem->IoCounters.WriteTransferCount, -1)->Buffer); // write bytes - SetDlgItemText(hwndDlg, IDC_ZIOOTHER_V, - PhaFormatUInt64(ProcessItem->IoCounters.OtherOperationCount, TRUE)->Buffer); // other - SetDlgItemText(hwndDlg, IDC_ZIOOTHERBYTES_V, - PhaFormatSize(ProcessItem->IoCounters.OtherTransferCount, -1)->Buffer); // read bytes - - SetDlgItemText(hwndDlg, IDC_ZHANDLES_V, - PhaFormatUInt64(ProcessItem->NumberOfHandles, TRUE)->Buffer); // handles + WCHAR priority[PH_INT32_STR_LEN_1] = L""; + WCHAR timeSpan[PH_TIMESPAN_STR_LEN_1] = L""; + + PhPrintInt32(priority, ProcessItem->BasePriority); + PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_PRIORITY, 1, priority); + PhPrintTimeSpan(timeSpan, ProcessItem->KernelTime.QuadPart, PH_TIMESPAN_HMSM); + PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_KERNELTIME, 1, timeSpan); + PhPrintTimeSpan(timeSpan, ProcessItem->UserTime.QuadPart, PH_TIMESPAN_HMSM); + PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_USERTIME, 1, timeSpan); + PhPrintTimeSpan(timeSpan, ProcessItem->KernelTime.QuadPart + ProcessItem->UserTime.QuadPart, PH_TIMESPAN_HMSM); + PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_TOTALTIME, 1, timeSpan); + PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_PRIVATEBYTES, 1, PhaFormatSize(ProcessItem->VmCounters.PagefileUsage, -1)->Buffer); + PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_PEAKPRIVATEBYTES, 1, PhaFormatSize(ProcessItem->VmCounters.PeakPagefileUsage, -1)->Buffer); + PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_VIRTUALSIZE, 1, PhaFormatSize(ProcessItem->VmCounters.VirtualSize, -1)->Buffer); + PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_PEAKVIRTUALSIZE, 1, PhaFormatSize(ProcessItem->VmCounters.PeakVirtualSize, -1)->Buffer); + PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_PAGEFAULTS, 1, PhaFormatUInt64(ProcessItem->VmCounters.PageFaultCount, TRUE)->Buffer); + PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_WORKINGSET, 1, PhaFormatSize(ProcessItem->VmCounters.WorkingSetSize, -1)->Buffer); + PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_PEAKWORKINGSET, 1, PhaFormatSize(ProcessItem->VmCounters.PeakWorkingSetSize, -1)->Buffer); + PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_READS, 1, PhaFormatUInt64(ProcessItem->IoCounters.ReadOperationCount, TRUE)->Buffer); + PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_READBYTES, 1, PhaFormatSize(ProcessItem->IoCounters.ReadTransferCount, -1)->Buffer); + PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_WRITES, 1, PhaFormatUInt64(ProcessItem->IoCounters.WriteOperationCount, TRUE)->Buffer); + PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_WRITEBYTES, 1, PhaFormatSize(ProcessItem->IoCounters.WriteTransferCount, -1)->Buffer); + PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_OTHER, 1, PhaFormatUInt64(ProcessItem->IoCounters.OtherOperationCount, TRUE)->Buffer); + PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_OTHERBYTES, 1, PhaFormatSize(ProcessItem->IoCounters.OtherTransferCount, -1)->Buffer); + PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_HANDLES, 1, PhaFormatUInt64(ProcessItem->NumberOfHandles, TRUE)->Buffer); // Optional information if (!PH_IS_FAKE_PROCESS_ID(ProcessItem->ProcessId)) @@ -141,39 +217,64 @@ VOID PhpUpdateProcessStatistics( if (!gotWsCounters) privateWs = PhaFormatSize(ProcessItem->WorkingSetPrivateSize, -1); - SetDlgItemText(hwndDlg, IDC_ZPEAKHANDLES_V, PhGetStringOrDefault(peakHandles, L"Unknown")); - SetDlgItemText(hwndDlg, IDC_ZGDIHANDLES_V, PhGetStringOrDefault(gdiHandles, L"Unknown")); - SetDlgItemText(hwndDlg, IDC_ZUSERHANDLES_V, PhGetStringOrDefault(userHandles, L"Unknown")); - SetDlgItemText(hwndDlg, IDC_ZCYCLES_V, PhGetStringOrDefault(cycles, L"Unknown")); + PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_CYCLES, 1, PhGetStringOrEmpty(cycles)); if (pagePriority != -1 && pagePriority <= MEMORY_PRIORITY_NORMAL) - SetDlgItemText(hwndDlg, IDC_ZPAGEPRIORITY_V, PhPagePriorityNames[pagePriority]); + PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_PAGEPRIORITY, 1, PhPagePriorityNames[pagePriority]); else - SetDlgItemText(hwndDlg, IDC_ZPAGEPRIORITY_V, L"Unknown"); + PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_PAGEPRIORITY, 1, L""); if (ioPriority != -1 && ioPriority < MaxIoPriorityTypes) - SetDlgItemText(hwndDlg, IDC_ZIOPRIORITY_V, PhIoPriorityHintNames[ioPriority]); + PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_IOPRIORITY, 1, PhIoPriorityHintNames[ioPriority]); else - SetDlgItemText(hwndDlg, IDC_ZIOPRIORITY_V, L"Unknown"); + PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_IOPRIORITY, 1, L""); - SetDlgItemText(hwndDlg, IDC_ZPRIVATEWS_V, PhGetStringOrDefault(privateWs, L"Unknown")); - SetDlgItemText(hwndDlg, IDC_ZSHAREABLEWS_V, PhGetStringOrDefault(shareableWs, L"Unknown")); - SetDlgItemText(hwndDlg, IDC_ZSHAREDWS_V, PhGetStringOrDefault(sharedWs, L"Unknown")); + PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_PRIVATEWS, 1, PhGetStringOrEmpty(privateWs)); + PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_SHAREABLEWS, 1, PhGetStringOrEmpty(shareableWs)); + PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_SHAREDWS, 1, PhGetStringOrEmpty(sharedWs)); + + PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_PEAKHANDLES, 1, PhGetStringOrEmpty(peakHandles)); + PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_GDIHANDLES, 1, PhGetStringOrEmpty(gdiHandles)); + PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_USERHANDLES, 1, PhGetStringOrEmpty(userHandles)); } - else + + if (WindowsVersion >= WINDOWS_10_RS3 || !PhIsExecutingInWow64()) { - SetDlgItemText(hwndDlg, IDC_ZPEAKHANDLES_V, L"N/A"); - SetDlgItemText(hwndDlg, IDC_ZGDIHANDLES_V, L"N/A"); - SetDlgItemText(hwndDlg, IDC_ZUSERHANDLES_V, L"N/A"); - SetDlgItemText(hwndDlg, IDC_ZCYCLES_V, L"N/A"); - SetDlgItemText(hwndDlg, IDC_ZPAGEPRIORITY_V, L"N/A"); - SetDlgItemText(hwndDlg, IDC_ZIOPRIORITY_V, L"N/A"); - SetDlgItemText(hwndDlg, IDC_ZPRIVATEWS_V, L"N/A"); - SetDlgItemText(hwndDlg, IDC_ZSHAREABLEWS_V, L"N/A"); - SetDlgItemText(hwndDlg, IDC_ZSHAREDWS_V, L"N/A"); + PVOID processes; + PSYSTEM_PROCESS_INFORMATION processInfo; + PSYSTEM_PROCESS_INFORMATION_EXTENSION processExtension; + + if (NT_SUCCESS(PhEnumProcesses(&processes))) + { + processInfo = PhFindProcessInformation(processes, ProcessItem->ProcessId); + + if (processInfo && (processExtension = PH_PROCESS_EXTENSION(processInfo))) + { + PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_CONTEXTSWITCHES, 1, PhaFormatUInt64(processExtension->ContextSwitches, TRUE)->Buffer); + PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_DISKENERGY, 1, PhaFormatUInt64(processExtension->EnergyValues.DiskEnergy, TRUE)->Buffer); + PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_NETWORKTAILENERGY, 1, PhaFormatSize(processExtension->EnergyValues.NetworkTailEnergy, -1)->Buffer); + PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_MBBTAILENERGY, 1, PhaFormatSize(processExtension->EnergyValues.MBBTailEnergy, -1)->Buffer); + PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_NETWORKTXRXBYTES, 1, PhaFormatSize(processExtension->EnergyValues.NetworkTxRxBytes, -1)->Buffer); + PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_MBBTXRXBYTES, 1, PhaFormatSize(processExtension->EnergyValues.MBBTxRxBytes, -1)->Buffer); + PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_FOREGROUNDDURATION, 1, PhaFormatUInt64(processExtension->EnergyValues.ForegroundDuration.Value, TRUE)->Buffer); + } + + PhFree(processes); + } } } +static VOID NTAPI StatisticsUpdateHandler( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + PPH_STATISTICS_CONTEXT statisticsContext = (PPH_STATISTICS_CONTEXT)Context; + + if (statisticsContext->Enabled) + PostMessage(statisticsContext->WindowHandle, WM_PH_STATISTICS_UPDATE, 0, 0); +} + INT_PTR CALLBACK PhpProcessStatisticsDlgProc( _In_ HWND hwndDlg, _In_ UINT uMsg, @@ -186,8 +287,7 @@ INT_PTR CALLBACK PhpProcessStatisticsDlgProc( PPH_PROCESS_ITEM processItem; PPH_STATISTICS_CONTEXT statisticsContext; - if (PhpPropPageDlgProcHeader(hwndDlg, uMsg, lParam, - &propSheetPage, &propPageContext, &processItem)) + if (PhpPropPageDlgProcHeader(hwndDlg, uMsg, lParam, &propSheetPage, &propPageContext, &processItem)) { statisticsContext = (PPH_STATISTICS_CONTEXT)propPageContext->Context; } @@ -200,20 +300,31 @@ INT_PTR CALLBACK PhpProcessStatisticsDlgProc( { case WM_INITDIALOG: { - statisticsContext = propPageContext->Context = - PhAllocate(sizeof(PH_STATISTICS_CONTEXT)); + propPageContext->Context = statisticsContext = PhAllocate(sizeof(PH_STATISTICS_CONTEXT)); + memset(statisticsContext, 0, sizeof(PH_STATISTICS_CONTEXT)); statisticsContext->WindowHandle = hwndDlg; + statisticsContext->ListViewHandle = GetDlgItem(hwndDlg, IDC_STATISTICS_LIST); statisticsContext->Enabled = TRUE; statisticsContext->ProcessHandle = NULL; - // Try to open a process handle with PROCESS_QUERY_INFORMATION access for - // WS information. - PhOpenProcess( - &statisticsContext->ProcessHandle, - PROCESS_QUERY_INFORMATION, - processItem->ProcessId - ); + // Try to open a process handle with PROCESS_QUERY_INFORMATION access for WS information. + if (PH_IS_REAL_PROCESS_ID(processItem->ProcessId)) + { + PhOpenProcess( + &statisticsContext->ProcessHandle, + PROCESS_QUERY_INFORMATION, + processItem->ProcessId + ); + } + + PhSetListViewStyle(statisticsContext->ListViewHandle, FALSE, TRUE); + PhSetControlTheme(statisticsContext->ListViewHandle, L"explorer"); + PhAddListViewColumn(statisticsContext->ListViewHandle, 0, 0, 0, LVCFMT_LEFT, 135, L"Property"); + PhAddListViewColumn(statisticsContext->ListViewHandle, 1, 1, 1, LVCFMT_LEFT, 150, L"Value"); + PhSetExtendedListView(statisticsContext->ListViewHandle); + + PhpUpdateStatisticsAddListViewGroups(statisticsContext->ListViewHandle); PhRegisterCallback( &PhProcessesUpdatedEvent, @@ -222,7 +333,9 @@ INT_PTR CALLBACK PhpProcessStatisticsDlgProc( &statisticsContext->ProcessesUpdatedRegistration ); - PhpUpdateProcessStatistics(hwndDlg, processItem, statisticsContext); + PhpUpdateProcessStatistics(processItem, statisticsContext); + + EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); } break; case WM_DESTROY: @@ -246,27 +359,17 @@ INT_PTR CALLBACK PhpProcessStatisticsDlgProc( { PPH_LAYOUT_ITEM dialogItem; - dialogItem = PhAddPropPageLayoutItem(hwndDlg, hwndDlg, - PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL); + dialogItem = PhAddPropPageLayoutItem(hwndDlg, hwndDlg, PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL); + PhAddPropPageLayoutItem(hwndDlg, statisticsContext->ListViewHandle, dialogItem, PH_ANCHOR_ALL); PhDoPropPageLayout(hwndDlg); + ExtendedListView_SetColumnWidth(statisticsContext->ListViewHandle, 0, ELVSCW_AUTOSIZE_REMAININGSPACE); + propPageContext->LayoutInitialized = TRUE; } } break; - case WM_COMMAND: - { - switch (LOWORD(wParam)) - { - case IDC_DETAILS: - { - PhShowHandleStatisticsDialog(hwndDlg, processItem->ProcessId); - } - break; - } - } - break; case WM_NOTIFY: { LPNMHDR header = (LPNMHDR)lParam; @@ -284,7 +387,12 @@ INT_PTR CALLBACK PhpProcessStatisticsDlgProc( break; case WM_PH_STATISTICS_UPDATE: { - PhpUpdateProcessStatistics(hwndDlg, processItem, statisticsContext); + PhpUpdateProcessStatistics(processItem, statisticsContext); + } + break; + case WM_SIZE: + { + ExtendedListView_SetColumnWidth(statisticsContext->ListViewHandle, 0, ELVSCW_AUTOSIZE_REMAININGSPACE); } break; } diff --git a/ProcessHacker/resource.h b/ProcessHacker/resource.h index 1aac68d75d05..80e0ffeb0da9 100644 --- a/ProcessHacker/resource.h +++ b/ProcessHacker/resource.h @@ -533,6 +533,7 @@ #define IDC_DISABLED 1401 #define IDC_LIST_DISABLED 1402 #define IDC_COLUMNSETLIST 1403 +#define IDC_STATISTICS_LIST 1404 #define ID_HACKER_EXIT 40001 #define ID_PROCESS_PROPERTIES 40006 #define ID_PROCESS_TERMINATE 40007 @@ -739,9 +740,9 @@ // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 245 +#define _APS_NEXT_RESOURCE_VALUE 246 #define _APS_NEXT_COMMAND_VALUE 40297 -#define _APS_NEXT_CONTROL_VALUE 1404 +#define _APS_NEXT_CONTROL_VALUE 1405 #define _APS_NEXT_SYMED_VALUE 170 #endif #endif From 38242adc14d7fe233bf629efb34d60b435e9544f Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 4 Feb 2018 06:02:23 +1100 Subject: [PATCH 0756/2058] Add missing file from previous commit --- ProcessHacker/include/procprpp.h | 1 + 1 file changed, 1 insertion(+) diff --git a/ProcessHacker/include/procprpp.h b/ProcessHacker/include/procprpp.h index 061aa3892692..4fd34d324121 100644 --- a/ProcessHacker/include/procprpp.h +++ b/ProcessHacker/include/procprpp.h @@ -326,6 +326,7 @@ typedef struct _PH_STATISTICS_CONTEXT PH_CALLBACK_REGISTRATION ProcessesUpdatedRegistration; HWND WindowHandle; + HWND ListViewHandle; BOOLEAN Enabled; HANDLE ProcessHandle; } PH_STATISTICS_CONTEXT, *PPH_STATISTICS_CONTEXT; From 592d5a9cd0099e122f3db4cd6051d81816dd8297 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 4 Feb 2018 06:04:33 +1100 Subject: [PATCH 0757/2058] Fix typo --- ProcessHacker/procprv.c | 13 ++++++------- ProcessHacker/proctree.c | 18 +++++++----------- 2 files changed, 13 insertions(+), 18 deletions(-) diff --git a/ProcessHacker/procprv.c b/ProcessHacker/procprv.c index adae0dbd01f5..d7b77cf4cc39 100644 --- a/ProcessHacker/procprv.c +++ b/ProcessHacker/procprv.c @@ -1000,7 +1000,7 @@ VOID PhpProcessQueryStage1( if (processHandleLimited) { BOOLEAN isDotNet = FALSE; - PPH_STRING commandLine; + PPH_STRING commandLine = NULL; HANDLE processHandle = NULL; ULONG processQueryFlags = 0; @@ -1040,7 +1040,7 @@ VOID PhpProcessQueryStage1( status = PhGetProcessCommandLine(processHandle, &commandLine); } - if (NT_SUCCESS(status)) + if (NT_SUCCESS(status) && commandLine) { // Some command lines (e.g. from taskeng.exe) have nulls in them. Since Windows // can't display them, we'll replace them with spaces. @@ -1373,11 +1373,10 @@ VOID PhpFillProcessItem( // Open a handle to the process for later usage. if (PH_IS_REAL_PROCESS_ID(ProcessItem->ProcessId)) { - ProcessItem->IsValidHandle = NT_SUCCESS(PhOpenProcess( - &ProcessItem->QueryHandle, - PROCESS_QUERY_INFORMATION, - ProcessItem->ProcessId - )); + if (NT_SUCCESS(PhOpenProcess(&ProcessItem->QueryHandle, PROCESS_QUERY_INFORMATION, ProcessItem->ProcessId))) + { + ProcessItem->IsValidHandle = TRUE; + } if (!ProcessItem->QueryHandle) { diff --git a/ProcessHacker/proctree.c b/ProcessHacker/proctree.c index f0c32570aff7..42aa4d10f58a 100644 --- a/ProcessHacker/proctree.c +++ b/ProcessHacker/proctree.c @@ -838,19 +838,15 @@ static VOID PhpUpdateProcessNodeWsCounters( BOOLEAN success = FALSE; HANDLE processHandle; - if (NT_SUCCESS(PhOpenProcess( - &processHandle, - PROCESS_QUERY_INFORMATION, - ProcessNode->ProcessItem->ProcessId - ))) + if (PH_IS_REAL_PROCESS_ID(ProcessNode->ProcessItem->ProcessId)) { - if (NT_SUCCESS(PhGetProcessWsCounters( - processHandle, - &ProcessNode->WsCounters - ))) - success = TRUE; + if (NT_SUCCESS(PhOpenProcess(&processHandle, PROCESS_QUERY_INFORMATION, ProcessNode->ProcessItem->ProcessId))) + { + if (NT_SUCCESS(PhGetProcessWsCounters(processHandle, &ProcessNode->WsCounters))) + success = TRUE; - NtClose(processHandle); + NtClose(processHandle); + } } if (!success) From b3ac10496fc68e3a2ccb807e288b189de142b24b Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 4 Feb 2018 07:49:27 +1100 Subject: [PATCH 0758/2058] Fix process statistics tab crash --- ProcessHacker/prpgstat.c | 3 +-- phlib/extlv.c | 9 +++++---- phlib/guisup.c | 1 - 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/ProcessHacker/prpgstat.c b/ProcessHacker/prpgstat.c index 67f9b6f125b2..6b49061e2655 100644 --- a/ProcessHacker/prpgstat.c +++ b/ProcessHacker/prpgstat.c @@ -348,9 +348,8 @@ INT_PTR CALLBACK PhpProcessStatisticsDlgProc( if (statisticsContext->ProcessHandle) NtClose(statisticsContext->ProcessHandle); - PhFree(statisticsContext); - PhpPropPageDlgProcDestroy(hwndDlg); + PhFree(statisticsContext); } break; case WM_SHOWWINDOW: diff --git a/phlib/extlv.c b/phlib/extlv.c index 0e210ed59863..0bed9ab7f6cf 100644 --- a/phlib/extlv.c +++ b/phlib/extlv.c @@ -113,7 +113,6 @@ VOID PhSetExtendedListView( context = PhAllocate(sizeof(PH_EXTLV_CONTEXT)); context->Handle = hWnd; - context->OldWndProc = (WNDPROC)GetWindowLongPtr(hWnd, GWLP_WNDPROC); context->Context = NULL; context->TriState = FALSE; context->SortColumn = 0; @@ -127,7 +126,9 @@ VOID PhSetExtendedListView( context->EnableRedraw = 1; context->Cursor = NULL; - PhSetWindowContext(hWnd, 5, context); + PhSetWindowContext(hWnd, MAXBYTE, context); + + context->OldWndProc = (WNDPROC)GetWindowLongPtr(hWnd, GWLP_WNDPROC); SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)PhpExtendedListViewWndProc); ExtendedListView_Init(hWnd); @@ -140,14 +141,14 @@ LRESULT CALLBACK PhpExtendedListViewWndProc( _In_ LPARAM lParam ) { - PPH_EXTLV_CONTEXT context = PhGetWindowContext(hwnd, 5); + PPH_EXTLV_CONTEXT context = PhGetWindowContext(hwnd, MAXBYTE); switch (uMsg) { case WM_DESTROY: { SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)context->OldWndProc); - PhRemoveWindowContext(hwnd, 5); + PhRemoveWindowContext(hwnd, MAXBYTE); PhFree(context); } break; diff --git a/phlib/guisup.c b/phlib/guisup.c index c5eb12b8346d..8bb8adc2abab 100644 --- a/phlib/guisup.c +++ b/phlib/guisup.c @@ -290,7 +290,6 @@ INT PhAddListViewGroupItem( return ListView_InsertItem(ListViewHandle, &item); } - INT PhAddTabControlTab( _In_ HWND TabControlHandle, _In_ INT Index, From ad60fed1e348ade43c370e0092bb90252e569126 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 4 Feb 2018 07:56:06 +1100 Subject: [PATCH 0759/2058] Remove plugin error prompt --- ProcessHacker/plugin.c | 20 +++----------------- 1 file changed, 3 insertions(+), 17 deletions(-) diff --git a/ProcessHacker/plugin.c b/ProcessHacker/plugin.c index 5dde37daed95..8554c80d545d 100644 --- a/ProcessHacker/plugin.c +++ b/ProcessHacker/plugin.c @@ -299,25 +299,11 @@ VOID PhLoadPlugins( PhDereferenceObject(baseName); } - PhAppendStringBuilder2(&sb, L"\nDo you want to disable the above plugin(s)?"); - - if (PhShowMessage2( - NULL, - TDCBF_YES_BUTTON | TDCBF_NO_BUTTON, - TD_ERROR_ICON, + PhShowError2( + NULL, L"Unable to load the following plugin(s)", - L"%s", sb.String->Buffer - ) == IDYES) - { - for (i = 0; i < LoadErrors->Count; i++) - { - loadError = LoadErrors->Items[i]; - baseName = PhGetBaseName(loadError->FileName); - PhSetPluginDisabled(&baseName->sr, TRUE); - PhDereferenceObject(baseName); - } - } + ); PhDeleteStringBuilder(&sb); } From 3531bfe3671a46e9a9dd2eb4740a317bce0f2679 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 4 Feb 2018 08:03:03 +1100 Subject: [PATCH 0760/2058] Fix stat page context --- ProcessHacker/prpgstat.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/ProcessHacker/prpgstat.c b/ProcessHacker/prpgstat.c index 6b49061e2655..6ec4ed2bdd9f 100644 --- a/ProcessHacker/prpgstat.c +++ b/ProcessHacker/prpgstat.c @@ -289,7 +289,15 @@ INT_PTR CALLBACK PhpProcessStatisticsDlgProc( if (PhpPropPageDlgProcHeader(hwndDlg, uMsg, lParam, &propSheetPage, &propPageContext, &processItem)) { - statisticsContext = (PPH_STATISTICS_CONTEXT)propPageContext->Context; + if (propPageContext->Context) + { + statisticsContext = propPageContext->Context; + } + else + { + statisticsContext = propPageContext->Context = PhAllocate(sizeof(PH_STATISTICS_CONTEXT)); + memset(propPageContext->Context, 0, sizeof(PH_STATISTICS_CONTEXT)); + } } else { @@ -300,9 +308,6 @@ INT_PTR CALLBACK PhpProcessStatisticsDlgProc( { case WM_INITDIALOG: { - propPageContext->Context = statisticsContext = PhAllocate(sizeof(PH_STATISTICS_CONTEXT)); - memset(statisticsContext, 0, sizeof(PH_STATISTICS_CONTEXT)); - statisticsContext->WindowHandle = hwndDlg; statisticsContext->ListViewHandle = GetDlgItem(hwndDlg, IDC_STATISTICS_LIST); statisticsContext->Enabled = TRUE; From 9a400fb43390e7e6e71ff4177850c6782b12da2f Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 4 Feb 2018 08:31:03 +1100 Subject: [PATCH 0761/2058] Fix build --- ProcessHacker/ProcessHacker.def | 2 ++ ProcessHacker/prpgstat.c | 16 +++++----------- tools/peview/include/prpsh.h | 4 ++-- tools/peview/prpsh.c | 4 ++-- 4 files changed, 11 insertions(+), 15 deletions(-) diff --git a/ProcessHacker/ProcessHacker.def b/ProcessHacker/ProcessHacker.def index eafb53d70c24..8a5dc9bb6eec 100644 --- a/ProcessHacker/ProcessHacker.def +++ b/ProcessHacker/ProcessHacker.def @@ -508,6 +508,8 @@ EXPORTS PhSetImageListBitmap PhSetListViewItemImageIndex PhSetListViewSubItem + PhAddListViewGroup + PhAddListViewGroupItem PhSetStateAllListViewItems PhGetWindowContext PhSetWindowContext diff --git a/ProcessHacker/prpgstat.c b/ProcessHacker/prpgstat.c index 6ec4ed2bdd9f..e2cb541e8c58 100644 --- a/ProcessHacker/prpgstat.c +++ b/ProcessHacker/prpgstat.c @@ -289,15 +289,7 @@ INT_PTR CALLBACK PhpProcessStatisticsDlgProc( if (PhpPropPageDlgProcHeader(hwndDlg, uMsg, lParam, &propSheetPage, &propPageContext, &processItem)) { - if (propPageContext->Context) - { - statisticsContext = propPageContext->Context; - } - else - { - statisticsContext = propPageContext->Context = PhAllocate(sizeof(PH_STATISTICS_CONTEXT)); - memset(propPageContext->Context, 0, sizeof(PH_STATISTICS_CONTEXT)); - } + statisticsContext = (PPH_STATISTICS_CONTEXT)propPageContext->Context; } else { @@ -308,6 +300,8 @@ INT_PTR CALLBACK PhpProcessStatisticsDlgProc( { case WM_INITDIALOG: { + statisticsContext = propPageContext->Context = PhAllocate(sizeof(PH_STATISTICS_CONTEXT)); + statisticsContext->WindowHandle = hwndDlg; statisticsContext->ListViewHandle = GetDlgItem(hwndDlg, IDC_STATISTICS_LIST); statisticsContext->Enabled = TRUE; @@ -368,10 +362,10 @@ INT_PTR CALLBACK PhpProcessStatisticsDlgProc( PhDoPropPageLayout(hwndDlg); - ExtendedListView_SetColumnWidth(statisticsContext->ListViewHandle, 0, ELVSCW_AUTOSIZE_REMAININGSPACE); - propPageContext->LayoutInitialized = TRUE; } + + ExtendedListView_SetColumnWidth(statisticsContext->ListViewHandle, 0, ELVSCW_AUTOSIZE_REMAININGSPACE); } break; case WM_NOTIFY: diff --git a/tools/peview/include/prpsh.h b/tools/peview/include/prpsh.h index 1290e7f63120..6857565c5061 100644 --- a/tools/peview/include/prpsh.h +++ b/tools/peview/include/prpsh.h @@ -116,10 +116,10 @@ FORCEINLINE BOOLEAN PvPropPageDlgProcHeader( if (uMsg == WM_INITDIALOG) { // Save the context. - SetProp(hwndDlg, L"PvContext", (HANDLE)lParam); + PhSetWindowContext(hwndDlg, ULONG_MAX, (PVOID)lParam); } - propSheetPage = (LPPROPSHEETPAGE)GetProp(hwndDlg, L"PvContext"); + propSheetPage = PhGetWindowContext(hwndDlg, ULONG_MAX); if (!propSheetPage) return FALSE; diff --git a/tools/peview/prpsh.c b/tools/peview/prpsh.c index f697d1bcb282..14fcba4fe066 100644 --- a/tools/peview/prpsh.c +++ b/tools/peview/prpsh.c @@ -155,7 +155,7 @@ INT CALLBACK PvpPropSheetProc( PhInitializeLayoutManager(&propSheetContext->LayoutManager, hwndDlg); - SetProp(hwndDlg, L"PvContext", (HANDLE)propSheetContext); + PhSetWindowContext(hwndDlg, ULONG_MAX, propSheetContext); SetWindowSubclass(hwndDlg, PvpPropSheetWndProc, 0, (ULONG_PTR)propSheetContext); if (MinimumSize.left == -1) @@ -181,7 +181,7 @@ PPV_PROPSHEETCONTEXT PvpGetPropSheetContext( _In_ HWND hwnd ) { - return (PPV_PROPSHEETCONTEXT)GetProp(hwnd, L"PvContext"); + return PhGetWindowContext(hwnd, ULONG_MAX); } LRESULT CALLBACK PvpPropSheetWndProc( From 3e6d9e4415e6ea7b94625e3558536a3242b6c136 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 4 Feb 2018 20:13:57 +1100 Subject: [PATCH 0762/2058] Plugins: Fix #235 --- plugins/Updater/updater.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/Updater/updater.c b/plugins/Updater/updater.c index 040435c7a5ee..0570ee4c60ad 100644 --- a/plugins/Updater/updater.c +++ b/plugins/Updater/updater.c @@ -216,7 +216,7 @@ ULONG64 ParseVersionString( PH_STRINGREF remaining, majorPart, minorPart, revisionPart; ULONG64 majorInteger = 0, minorInteger = 0, revisionInteger = 0; - PhInitializeStringRef(&remaining, PhGetString(VersionString)); + PhInitializeStringRef(&remaining, PhGetStringOrEmpty(VersionString)); PhSplitStringRefAtChar(&remaining, '.', &majorPart, &remaining); PhSplitStringRefAtChar(&remaining, '.', &minorPart, &remaining); @@ -880,6 +880,7 @@ NTSTATUS ShowUpdateDialogThread( // Start TaskDialog bootstrap config.dwFlags = TDF_ALLOW_DIALOG_CANCELLATION | TDF_CAN_BE_MINIMIZED; + config.hInstance = PluginInstance->DllBase; config.pszContent = L"Initializing..."; config.lpCallbackData = (LONG_PTR)context; config.pfCallback = TaskDialogBootstrapCallback; From bc8b88f1432e964be15552d72b5fcc5cdb485145 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 4 Feb 2018 20:16:23 +1100 Subject: [PATCH 0763/2058] Fix crash #234 --- phlib/guisup.c | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/phlib/guisup.c b/phlib/guisup.c index 8bb8adc2abab..3edefee52593 100644 --- a/phlib/guisup.c +++ b/phlib/guisup.c @@ -1378,6 +1378,25 @@ static LRESULT CALLBACK PhWindowSubclassCallback( } } + if (uMsg == WM_DESTROY) + { + LRESULT result; + + result = CallWindowProc(context->DefaultWindowProc, WindowHandle, uMsg, wParam, lParam); + + if (context->WindowCallbackArray.Count == 0) + { + SetWindowLongPtr(WindowHandle, GWLP_WNDPROC, (LONG_PTR)context->DefaultWindowProc); + + PhRemoveWindowContext(WindowHandle, PH_WINDOW_SUBCLASS_CONTEXT); + + PhDeleteArray(&context->WindowCallbackArray); + PhFree(context); + } + + return result; + } + return CallWindowProc(context->DefaultWindowProc, WindowHandle, uMsg, wParam, lParam); } @@ -1432,14 +1451,4 @@ VOID PhUnregisterWindowSubclass( if (entry->SubclassCallback == SubclassCallback) PhRemoveItemArray(&context->WindowCallbackArray, i); } - - if (context->WindowCallbackArray.Count == 0) - { - SetWindowLongPtr(WindowHandle, GWLP_WNDPROC, (LONG_PTR)context->DefaultWindowProc); - - PhRemoveWindowContext(WindowHandle, PH_WINDOW_SUBCLASS_CONTEXT); - - PhDeleteArray(&context->WindowCallbackArray); - PhFree(context); - } } From 33e0ab1d9678927b677e62d8b55b6085bfe440ba Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 5 Feb 2018 04:00:58 +1100 Subject: [PATCH 0764/2058] Revert commit 6a02c5b0 --- ProcessHacker/ProcessHacker.def | 2 - ProcessHacker/include/procprpp.h | 6 +- ProcessHacker/include/procprv.h | 2 +- ProcessHacker/include/sysinfo.h | 3 + ProcessHacker/include/sysinfop.h | 10 ++- ProcessHacker/memsrch.c | 24 ++++--- ProcessHacker/miniinfo.c | 6 +- ProcessHacker/procprp.c | 28 +++++--- ProcessHacker/procprv.c | 60 ++++++++--------- ProcessHacker/searchbox.c | 2 +- ProcessHacker/splitter.c | 32 +++++---- ProcessHacker/sysinfo.c | 57 +++++++++++----- phlib/guisup.c | 99 ---------------------------- phlib/include/guisup.h | 39 ----------- phlib/include/treenewp.h | 8 ++- phlib/treenew.c | 32 ++++++--- plugins/ExtendedNotifications/main.c | 28 +++++--- plugins/HardwareDevices/disknotify.c | 29 ++++---- plugins/HardwareDevices/prpsh.c | 39 +++++------ plugins/HardwareDevices/prpsh.h | 1 + plugins/OnlineChecks/onlnchk.h | 1 + plugins/OnlineChecks/upload.c | 22 +++++-- plugins/ToolStatus/main.c | 21 +++--- plugins/Updater/updater.c | 33 ++++++---- plugins/Updater/updater.h | 1 + plugins/WindowExplorer/wndprp.c | 26 +++++--- tools/peview/include/prpsh.h | 3 +- tools/peview/pdbprp.c | 9 +++ tools/peview/prpsh.c | 37 ++++++----- 29 files changed, 320 insertions(+), 340 deletions(-) diff --git a/ProcessHacker/ProcessHacker.def b/ProcessHacker/ProcessHacker.def index 8a5dc9bb6eec..c021c8433379 100644 --- a/ProcessHacker/ProcessHacker.def +++ b/ProcessHacker/ProcessHacker.def @@ -514,8 +514,6 @@ EXPORTS PhGetWindowContext PhSetWindowContext PhRemoveWindowContext - PhRegisterWindowSubclass - PhUnregisterWindowSubclass ; hndlinfo PhEnumObjectTypes diff --git a/ProcessHacker/include/procprpp.h b/ProcessHacker/include/procprpp.h index 4fd34d324121..9c1846441c34 100644 --- a/ProcessHacker/include/procprpp.h +++ b/ProcessHacker/include/procprpp.h @@ -9,6 +9,7 @@ typedef struct _PH_PROCESS_PROPSHEETCONTEXT { + WNDPROC PropSheetWindowHookProc; PH_LAYOUT_MANAGER LayoutManager; PPH_LAYOUT_ITEM TabPageItem; BOOLEAN LayoutInitialized; @@ -29,12 +30,11 @@ PPH_PROCESS_PROPSHEETCONTEXT PhpGetPropSheetContext( _In_ HWND hwnd ); -BOOLEAN CALLBACK PhpPropSheetWndProc( +LRESULT CALLBACK PhpPropSheetWndProc( _In_ HWND hwnd, _In_ UINT uMsg, _In_ WPARAM wParam, - _In_ LPARAM lParam, - _In_ PVOID Context + _In_ LPARAM lParam ); VOID NTAPI PhpProcessPropPageContextDeleteProcedure( diff --git a/ProcessHacker/include/procprv.h b/ProcessHacker/include/procprv.h index 0405382525f6..6b6d218ce201 100644 --- a/ProcessHacker/include/procprv.h +++ b/ProcessHacker/include/procprv.h @@ -158,7 +158,7 @@ typedef struct _PH_PROCESS_ITEM ULONG IsInJob : 1; ULONG IsInSignificantJob : 1; ULONG IsPacked : 1; - ULONG IsValidHandle : 1; + ULONG IsHandleValid : 1; ULONG IsSuspended : 1; ULONG IsWow64 : 1; ULONG IsImmersive : 1; diff --git a/ProcessHacker/include/sysinfo.h b/ProcessHacker/include/sysinfo.h index 89127b2a383d..4d7931ff1b18 100644 --- a/ProcessHacker/include/sysinfo.h +++ b/ProcessHacker/include/sysinfo.h @@ -128,6 +128,9 @@ typedef struct _PH_SYSINFO_SECTION HWND DialogHandle; HWND PanelHandle; ULONG PanelId; + + WNDPROC GraphWindowProc; + WNDPROC PanelWindowProc; // begin_phapppub } PH_SYSINFO_SECTION, *PPH_SYSINFO_SECTION; // end_phapppub diff --git a/ProcessHacker/include/sysinfop.h b/ProcessHacker/include/sysinfop.h index 87ed3b71b470..875a38587a07 100644 --- a/ProcessHacker/include/sysinfop.h +++ b/ProcessHacker/include/sysinfop.h @@ -189,20 +189,18 @@ VOID PhSipCreateSectionDialog( _In_ PPH_SYSINFO_SECTION Section ); -BOOLEAN CALLBACK PhSipGraphHookWndProc( +LRESULT CALLBACK PhSipGraphHookWndProc( _In_ HWND hwnd, _In_ UINT uMsg, _In_ WPARAM wParam, - _In_ LPARAM lParam, - _In_ PVOID Context + _In_ LPARAM lParam ); -BOOLEAN CALLBACK PhSipPanelHookWndProc( +LRESULT CALLBACK PhSipPanelHookWndProc( _In_ HWND hwnd, _In_ UINT uMsg, _In_ WPARAM wParam, - _In_ LPARAM lParam, - _In_ PVOID Context + _In_ LPARAM lParam ); // Misc. diff --git a/ProcessHacker/memsrch.c b/ProcessHacker/memsrch.c index 78e4e0e62b91..9d665ab2cbe2 100644 --- a/ProcessHacker/memsrch.c +++ b/ProcessHacker/memsrch.c @@ -56,6 +56,7 @@ typedef struct _MEMORY_STRING_CONTEXT HWND ParentWindowHandle; HWND WindowHandle; + WNDPROC DefaultWindowProc; PH_MEMORY_STRING_OPTIONS Options; PPH_LIST Results; } MEMORY_STRING_CONTEXT, *PMEMORY_STRING_CONTEXT; @@ -650,20 +651,25 @@ NTSTATUS PhpMemoryStringThreadStart( return STATUS_SUCCESS; } -BOOLEAN CALLBACK PhpMemoryStringTaskDialogSubclassProc( +LRESULT CALLBACK PhpMemoryStringTaskDialogSubclassProc( _In_ HWND hwndDlg, _In_ UINT uMsg, _In_ WPARAM wParam, - _In_ LPARAM lParam, - _In_ PVOID Context + _In_ LPARAM lParam ) { - PMEMORY_STRING_CONTEXT context = (PMEMORY_STRING_CONTEXT)Context; + PMEMORY_STRING_CONTEXT context = PhGetWindowContext(hwndDlg, 0xF); + + if (!context) + return 0; switch (uMsg) { - case WM_NCDESTROY: - PhUnregisterWindowSubclass(hwndDlg, PhpMemoryStringTaskDialogSubclassProc); + case WM_DESTROY: + { + SetWindowLongPtr(hwndDlg, GWLP_WNDPROC, (LONG_PTR)context->DefaultWindowProc); + PhRemoveWindowContext(hwndDlg, 0xF); + } break; case WM_PH_MEMORY_STATUS_UPDATE: { @@ -680,7 +686,7 @@ BOOLEAN CALLBACK PhpMemoryStringTaskDialogSubclassProc( break; } - return FALSE; + return CallWindowProc(context->DefaultWindowProc, hwndDlg, uMsg, wParam, lParam); } HRESULT CALLBACK PhpMemoryStringTaskDialogCallback( @@ -714,7 +720,9 @@ HRESULT CALLBACK PhpMemoryStringTaskDialogCallback( SendMessage(hwndDlg, TDM_SET_PROGRESS_BAR_MARQUEE, TRUE, 1); // Subclass the Taskdialog. - PhRegisterWindowSubclass(hwndDlg, PhpMemoryStringTaskDialogSubclassProc, context); + context->DefaultWindowProc = (WNDPROC)GetWindowLongPtr(hwndDlg, GWLP_WNDPROC); + PhSetWindowContext(hwndDlg, 0xF, context); + SetWindowLongPtr(hwndDlg, GWLP_WNDPROC, (LONG_PTR)PhpMemoryStringTaskDialogSubclassProc); // Create the search thread. PhCreateThread2(PhpMemoryStringThreadStart, context); diff --git a/ProcessHacker/miniinfo.c b/ProcessHacker/miniinfo.c index a3be5d07940e..4208da0cfc09 100644 --- a/ProcessHacker/miniinfo.c +++ b/ProcessHacker/miniinfo.c @@ -470,7 +470,7 @@ VOID PhMipOnInitDialog( // Subclass the window procedure. oldWndProc = (WNDPROC)GetWindowLongPtr(GetDlgItem(PhMipWindow, IDC_SECTION), GWLP_WNDPROC); - PhSetWindowContext(GetDlgItem(PhMipWindow, IDC_SECTION), 10, oldWndProc); + PhSetWindowContext(GetDlgItem(PhMipWindow, IDC_SECTION), 0xF, oldWndProc); SetWindowLongPtr(GetDlgItem(PhMipWindow, IDC_SECTION), GWLP_WNDPROC, (LONG_PTR)PhMipSectionControlHookWndProc); } @@ -1159,7 +1159,7 @@ LRESULT CALLBACK PhMipSectionControlHookWndProc( { WNDPROC oldWndProc; - if (!(oldWndProc = PhGetWindowContext(hwnd, 10))) + if (!(oldWndProc = PhGetWindowContext(hwnd, 0xF))) return 0; switch (uMsg) @@ -1167,7 +1167,7 @@ LRESULT CALLBACK PhMipSectionControlHookWndProc( case WM_DESTROY: { SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)oldWndProc); - PhRemoveWindowContext(hwnd, 10); + PhRemoveWindowContext(hwnd, 0xF); } break; case WM_SETCURSOR: diff --git a/ProcessHacker/procprp.c b/ProcessHacker/procprp.c index fec4120ed7fb..9273e4c19a71 100644 --- a/ProcessHacker/procprp.c +++ b/ProcessHacker/procprp.c @@ -166,9 +166,11 @@ INT CALLBACK PhpPropSheetProc( memset(propSheetContext, 0, sizeof(PH_PROCESS_PROPSHEETCONTEXT)); PhInitializeLayoutManager(&propSheetContext->LayoutManager, hwndDlg); - PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, propSheetContext); - PhRegisterWindowSubclass(hwndDlg, PhpPropSheetWndProc, propSheetContext); + + propSheetContext->PropSheetWindowHookProc = (WNDPROC)GetWindowLongPtr(hwndDlg, GWLP_WNDPROC); + PhSetWindowContext(hwndDlg, 0xF, propSheetContext); + SetWindowLongPtr(hwndDlg, GWLP_WNDPROC, (LONG_PTR)PhpPropSheetWndProc); if (MinimumSize.left == -1) { @@ -196,15 +198,19 @@ PPH_PROCESS_PROPSHEETCONTEXT PhpGetPropSheetContext( return PhGetWindowContext(hwnd, PH_WINDOW_CONTEXT_DEFAULT); } -BOOLEAN CALLBACK PhpPropSheetWndProc( +LRESULT CALLBACK PhpPropSheetWndProc( _In_ HWND hwnd, _In_ UINT uMsg, _In_ WPARAM wParam, - _In_ LPARAM lParam, - _In_ PVOID Context + _In_ LPARAM lParam ) { - PPH_PROCESS_PROPSHEETCONTEXT propSheetContext = (PPH_PROCESS_PROPSHEETCONTEXT)Context; + PPH_PROCESS_PROPSHEETCONTEXT propSheetContext; + + propSheetContext = PhGetWindowContext(hwnd, 0xF); + + if (!propSheetContext) + return 0; switch (uMsg) { @@ -234,11 +240,15 @@ BOOLEAN CALLBACK PhpPropSheetWndProc( break; case WM_NCDESTROY: { - PhUnregisterWindowSubclass(hwnd, PhpPropSheetWndProc); - PhRemoveWindowContext(hwnd, PH_WINDOW_CONTEXT_DEFAULT); + LRESULT result; + + result = CallWindowProc(propSheetContext->PropSheetWindowHookProc, hwnd, uMsg, wParam, lParam); + SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)propSheetContext->PropSheetWindowHookProc); + PhRemoveWindowContext(hwnd, 0xF); PhDeleteLayoutManager(&propSheetContext->LayoutManager); PhFree(propSheetContext); + return result; } break; case WM_COMMAND: @@ -268,7 +278,7 @@ BOOLEAN CALLBACK PhpPropSheetWndProc( break; } - return FALSE; + return CallWindowProc(propSheetContext->PropSheetWindowHookProc, hwnd, uMsg, wParam, lParam); } BOOLEAN PhpInitializePropSheetLayoutStage1( diff --git a/ProcessHacker/procprv.c b/ProcessHacker/procprv.c index d7b77cf4cc39..491898b25d23 100644 --- a/ProcessHacker/procprv.c +++ b/ProcessHacker/procprv.c @@ -107,7 +107,7 @@ typedef struct _PH_PROCESS_QUERY_S1_DATA ULONG IsInSignificantJob : 1; ULONG IsBeingDebugged : 1; ULONG IsImmersive : 1; - ULONG IsProtectedHandle : 1; + ULONG IsFilteredHandle : 1; ULONG Spare : 25; }; }; @@ -1000,7 +1000,6 @@ VOID PhpProcessQueryStage1( if (processHandleLimited) { BOOLEAN isDotNet = FALSE; - PPH_STRING commandLine = NULL; HANDLE processHandle = NULL; ULONG processQueryFlags = 0; @@ -1019,6 +1018,24 @@ VOID PhpProcessQueryStage1( ); } + if (NT_SUCCESS(status)) + { + PPH_STRING commandLine; + + if (NT_SUCCESS(PhGetProcessCommandLine(processHandle, &commandLine))) + { + // Some command lines (e.g. from taskeng.exe) have nulls in them. Since Windows + // can't display them, we'll replace them with spaces. + for (ULONG i = 0; i < (ULONG)commandLine->Length / 2; i++) + { + if (commandLine->Buffer[i] == 0) + commandLine->Buffer[i] = ' '; + } + + Data->CommandLine = commandLine; + } + } + if (NT_SUCCESS(status)) { PhGetProcessIsDotNetEx( @@ -1035,24 +1052,6 @@ VOID PhpProcessQueryStage1( Data->IsDotNet = isDotNet; } - if (NT_SUCCESS(status)) - { - status = PhGetProcessCommandLine(processHandle, &commandLine); - } - - if (NT_SUCCESS(status) && commandLine) - { - // Some command lines (e.g. from taskeng.exe) have nulls in them. Since Windows - // can't display them, we'll replace them with spaces. - for (ULONG i = 0; i < (ULONG)commandLine->Length / 2; i++) - { - if (commandLine->Buffer[i] == 0) - commandLine->Buffer[i] = ' '; - } - - Data->CommandLine = commandLine; - } - if (!(processQueryFlags & PH_CLR_USE_SECTION_CHECK) && processHandle) NtClose(processHandle); } @@ -1062,9 +1061,7 @@ VOID PhpProcessQueryStage1( { HANDLE tokenHandle; - status = PhOpenProcessToken(processHandleLimited, TOKEN_QUERY, &tokenHandle); - - if (NT_SUCCESS(status)) + if (NT_SUCCESS(PhOpenProcessToken(processHandleLimited, TOKEN_QUERY, &tokenHandle))) { // Elevation if (NT_SUCCESS(PhGetTokenElevationType( @@ -1156,14 +1153,14 @@ VOID PhpProcessQueryStage1( Data->PackageFullName = PhGetProcessPackageFullName(processHandleLimited); } - if (processHandleLimited && processItem->IsValidHandle) + if (processHandleLimited && processItem->IsHandleValid) { OBJECT_BASIC_INFORMATION basicInfo; if (NT_SUCCESS(PhGetHandleInformationEx( NtCurrentProcess(), processHandleLimited, - -1, + ULONG_MAX, 0, NULL, &basicInfo, @@ -1174,11 +1171,11 @@ VOID PhpProcessQueryStage1( ))) { if ((basicInfo.GrantedAccess & PROCESS_QUERY_INFORMATION) != PROCESS_QUERY_INFORMATION) - Data->IsProtectedHandle = TRUE; + Data->IsFilteredHandle = TRUE; } else { - Data->IsProtectedHandle = TRUE; + Data->IsFilteredHandle = TRUE; } } } @@ -1187,11 +1184,12 @@ VOID PhpProcessQueryStage2( _Inout_ PPH_PROCESS_QUERY_S2_DATA Data ) { - NTSTATUS status; PPH_PROCESS_ITEM processItem = Data->Header.ProcessItem; if (PhEnableProcessQueryStage2 && processItem->FileName) { + NTSTATUS status; + Data->VerifyResult = PhVerifyFileCached( processItem->FileName, processItem->PackageFullName, @@ -1316,7 +1314,7 @@ VOID PhpFillProcessItemStage1( processItem->IsInSignificantJob = Data->IsInSignificantJob; processItem->IsBeingDebugged = Data->IsBeingDebugged; processItem->IsImmersive = Data->IsImmersive; - processItem->IsProtectedHandle = Data->IsProtectedHandle; + processItem->IsProtectedHandle = Data->IsFilteredHandle; PhSwapReference(&processItem->Record->CommandLine, processItem->CommandLine); @@ -1375,7 +1373,7 @@ VOID PhpFillProcessItem( { if (NT_SUCCESS(PhOpenProcess(&ProcessItem->QueryHandle, PROCESS_QUERY_INFORMATION, ProcessItem->ProcessId))) { - ProcessItem->IsValidHandle = TRUE; + ProcessItem->IsHandleValid = TRUE; } if (!ProcessItem->QueryHandle) @@ -1514,7 +1512,7 @@ VOID PhpFillProcessItem( // On Windows 8.1 and above, processes without threads are reflected processes // which will not terminate if we have a handle open. - if (Process->NumberOfThreads == 0) + if (Process->NumberOfThreads == 0 && ProcessItem->QueryHandle) { NtClose(ProcessItem->QueryHandle); ProcessItem->QueryHandle = NULL; diff --git a/ProcessHacker/searchbox.c b/ProcessHacker/searchbox.c index 080bd02e5484..8c12ecef56cf 100644 --- a/ProcessHacker/searchbox.c +++ b/ProcessHacker/searchbox.c @@ -523,7 +523,6 @@ VOID PhCreateSearchControl( memset(context, 0, sizeof(EDIT_CONTEXT)); context->WindowHandle = WindowHandle; - context->DefaultWindowProc = (WNDPROC)GetWindowLongPtr(WindowHandle, GWLP_WNDPROC); //PhpSearchInitializeTheme(context); PhpSearchInitializeImages(context); @@ -533,6 +532,7 @@ VOID PhCreateSearchControl( Edit_SetCueBannerText(WindowHandle, BannerText); // Subclass the Edit control window procedure. + context->DefaultWindowProc = (WNDPROC)GetWindowLongPtr(WindowHandle, GWLP_WNDPROC); PhSetWindowContext(WindowHandle, 10, context); SetWindowLongPtr(WindowHandle, GWLP_WNDPROC, (LONG_PTR)PhpSearchWndSubclassProc); diff --git a/ProcessHacker/splitter.c b/ProcessHacker/splitter.c index 1dcb8dba9783..e6ce1a57abc9 100644 --- a/ProcessHacker/splitter.c +++ b/ProcessHacker/splitter.c @@ -43,10 +43,11 @@ typedef struct _PH_HSPLITTER_CONTEXT LONG SplitterOffset; - HWND Window; + HWND WindowHandle; HWND ParentWindow; HWND TopWindow; HWND BottomWindow; + WNDPROC DefaultWindowProc; HBRUSH FocusBrush; HBRUSH HotBrush; @@ -237,7 +238,7 @@ LRESULT CALLBACK HSplitterWindowProc( ); DeferWindowPos( deferHandle, - context->Window, + context->WindowHandle, NULL, 0, cursorPos.y, @@ -264,22 +265,25 @@ LRESULT CALLBACK HSplitterWindowProc( return DefWindowProc(hwnd, uMsg, wParam, lParam); } -BOOLEAN CALLBACK HSplitterParentWindowProc( +LRESULT CALLBACK HSplitterParentWindowProc( _In_ HWND hwnd, _In_ UINT uMsg, _In_ WPARAM wParam, - _In_ LPARAM lParam, - _In_ PVOID Context + _In_ LPARAM lParam ) { - PPH_HSPLITTER_CONTEXT context = (PPH_HSPLITTER_CONTEXT)Context; + PPH_HSPLITTER_CONTEXT context = PhGetWindowContext(hwnd, 0x200); + + if (!context) + return 0; switch (uMsg) { case WM_DESTROY: { - PhUnregisterWindowSubclass(hwnd, HSplitterParentWindowProc); + SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)context->DefaultWindowProc); PhDeleteHSplitter(context); + PhRemoveWindowContext(hwnd, 0x200); } break; case WM_SIZE: @@ -289,7 +293,7 @@ BOOLEAN CALLBACK HSplitterParentWindowProc( break; } - return FALSE; + return CallWindowProc(context->DefaultWindowProc, hwnd, uMsg, wParam, lParam); } VOID PhInitializeHSplitter( @@ -335,7 +339,7 @@ VOID PhInitializeHSplitter( PhEndInitOnce(&initOnce); } - context->Window = CreateWindowEx( + context->WindowHandle = CreateWindowEx( WS_EX_TRANSPARENT, L"PhHSplitter", NULL, @@ -350,10 +354,12 @@ VOID PhInitializeHSplitter( context ); - ShowWindow(context->Window, SW_SHOW); - UpdateWindow(context->Window); + ShowWindow(context->WindowHandle, SW_SHOW); + UpdateWindow(context->WindowHandle); - PhRegisterWindowSubclass(ParentWindow, HSplitterParentWindowProc, context); + context->DefaultWindowProc = (WNDPROC)GetWindowLongPtr(ParentWindow, GWLP_WNDPROC); + PhSetWindowContext(ParentWindow, 0x200, context); + SetWindowLongPtr(ParentWindow, GWLP_WNDPROC, (LONG_PTR)HSplitterParentWindowProc); } VOID PhDeleteHSplitter( @@ -391,7 +397,7 @@ VOID PhHSplitterHandleWmSize( DeferWindowPos( deferHandle, - Context->Window, + Context->WindowHandle, NULL, 0, Context->SplitterOffset - 65, diff --git a/ProcessHacker/sysinfo.c b/ProcessHacker/sysinfo.c index c313c7fc812e..c2fa5ecd4b6f 100644 --- a/ProcessHacker/sysinfo.c +++ b/ProcessHacker/sysinfo.c @@ -75,6 +75,7 @@ static PPH_SYSINFO_SECTION CurrentSection; static HWND ContainerControl; static HWND SeparatorControl; static HWND RestoreSummaryControl; +static WNDPROC RestoreSummaryControlOldWndProc; static BOOLEAN RestoreSummaryControlHot; static BOOLEAN RestoreSummaryControlHasFocus; @@ -417,7 +418,8 @@ VOID PhSipOnShowWindow( NULL ); - PhRegisterWindowSubclass(RestoreSummaryControl, PhSipPanelHookWndProc, NULL); + RestoreSummaryControlOldWndProc = (WNDPROC)GetWindowLongPtr(RestoreSummaryControl, GWLP_WNDPROC); + SetWindowLongPtr(RestoreSummaryControl, GWLP_WNDPROC, (LONG_PTR)PhSipPanelHookWndProc); RestoreSummaryControlHot = FALSE; EnableThemeDialogTexture(ContainerControl, ETDT_ENABLETAB); @@ -1150,13 +1152,19 @@ PPH_SYSINFO_SECTION PhSipCreateSection( 3, 3, PhSipWindow, - (HMENU)(ULONG_PTR)section->PanelId, + UlongToHandle(section->PanelId), PhInstanceHandle, NULL ); - PhRegisterWindowSubclass(section->GraphHandle, PhSipGraphHookWndProc, section); - PhRegisterWindowSubclass(section->PanelHandle, PhSipPanelHookWndProc, section); + section->GraphWindowProc = (WNDPROC)GetWindowLongPtr(section->GraphHandle, GWLP_WNDPROC); + section->PanelWindowProc = (WNDPROC)GetWindowLongPtr(section->PanelHandle, GWLP_WNDPROC); + + PhSetWindowContext(section->GraphHandle, 0xF, section); + PhSetWindowContext(section->PanelHandle, 0xF, section); + + SetWindowLongPtr(section->GraphHandle, GWLP_WNDPROC, (LONG_PTR)PhSipGraphHookWndProc); + SetWindowLongPtr(section->PanelHandle, GWLP_WNDPROC, (LONG_PTR)PhSipPanelHookWndProc); PhAddItemList(SectionList, section); @@ -1715,20 +1723,27 @@ VOID PhSipCreateSectionDialog( } } -BOOLEAN CALLBACK PhSipGraphHookWndProc( +LRESULT CALLBACK PhSipGraphHookWndProc( _In_ HWND hwnd, _In_ UINT uMsg, _In_ WPARAM wParam, - _In_ LPARAM lParam, - _In_ PVOID Context + _In_ LPARAM lParam ) { - PPH_SYSINFO_SECTION section = (PPH_SYSINFO_SECTION)Context; + PPH_SYSINFO_SECTION section; + + section = PhGetWindowContext(hwnd, 0xF); + + if (!section) + return 0; switch (uMsg) { case WM_DESTROY: - PhUnregisterWindowSubclass(hwnd, PhSipGraphHookWndProc); + { + SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)section->GraphWindowProc); + PhRemoveWindowContext(hwnd, 0xF); + } break; case WM_SETFOCUS: section->HasFocus = TRUE; @@ -1864,23 +1879,33 @@ BOOLEAN CALLBACK PhSipGraphHookWndProc( break; } - return FALSE; + return CallWindowProc(section->GraphWindowProc, hwnd, uMsg, wParam, lParam); } -BOOLEAN CALLBACK PhSipPanelHookWndProc( +LRESULT CALLBACK PhSipPanelHookWndProc( _In_ HWND hwnd, _In_ UINT uMsg, _In_ WPARAM wParam, - _In_ LPARAM lParam, - _In_ PVOID Context + _In_ LPARAM lParam ) { - PPH_SYSINFO_SECTION section = (PPH_SYSINFO_SECTION)Context; + PPH_SYSINFO_SECTION section; + WNDPROC oldWndProc; + + section = PhGetWindowContext(hwnd, 0xF); + + if (section) + oldWndProc = section->PanelWindowProc; + else + oldWndProc = RestoreSummaryControlOldWndProc; switch (uMsg) { case WM_DESTROY: - PhUnregisterWindowSubclass(hwnd, PhSipPanelHookWndProc); + { + SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)oldWndProc); + PhRemoveWindowContext(hwnd, 0xF); + } break; case WM_SETFOCUS: { @@ -1984,7 +2009,7 @@ BOOLEAN CALLBACK PhSipPanelHookWndProc( break; } - return FALSE; + return CallWindowProc(oldWndProc, hwnd, uMsg, wParam, lParam); } VOID PhSipUpdateThemeData( diff --git a/phlib/guisup.c b/phlib/guisup.c index 3edefee52593..2d24f76a515b 100644 --- a/phlib/guisup.c +++ b/phlib/guisup.c @@ -1353,102 +1353,3 @@ VOID PhRemoveWindowContext( PhRemoveEntryHashtable(WindowContextHashTable, &lookupEntry); PhReleaseQueuedLockExclusive(&WindowContextListLock); } - -static LRESULT CALLBACK PhWindowSubclassCallback( - _In_ HWND WindowHandle, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - PPH_WINDOW_SUBCLASS context; - PPH_WINDOW_SUBCLASS_ENTRY entry; - ULONG i; - - if (!(context = PhGetWindowContext(WindowHandle, PH_WINDOW_SUBCLASS_CONTEXT))) - return 0; - - for (i = 0; i < context->WindowCallbackArray.Count; i++) - { - entry = PhItemArray(&context->WindowCallbackArray, i); - - if (entry->SubclassCallback(WindowHandle, uMsg, wParam, lParam, entry->Context)) - { - return DefWindowProc(WindowHandle, uMsg, wParam, lParam); - } - } - - if (uMsg == WM_DESTROY) - { - LRESULT result; - - result = CallWindowProc(context->DefaultWindowProc, WindowHandle, uMsg, wParam, lParam); - - if (context->WindowCallbackArray.Count == 0) - { - SetWindowLongPtr(WindowHandle, GWLP_WNDPROC, (LONG_PTR)context->DefaultWindowProc); - - PhRemoveWindowContext(WindowHandle, PH_WINDOW_SUBCLASS_CONTEXT); - - PhDeleteArray(&context->WindowCallbackArray); - PhFree(context); - } - - return result; - } - - return CallWindowProc(context->DefaultWindowProc, WindowHandle, uMsg, wParam, lParam); -} - -VOID PhRegisterWindowSubclass( - _In_ HWND WindowHandle, - _In_ PPH_WINDOW_SUBCLASS_CALLBACK SubclassCallback, - _In_opt_ PVOID Context - ) -{ - PPH_WINDOW_SUBCLASS context; - PH_WINDOW_SUBCLASS_ENTRY entry; - - entry.SubclassCallback = SubclassCallback; - entry.Context = Context; - - if (context = PhGetWindowContext(WindowHandle, PH_WINDOW_SUBCLASS_CONTEXT)) - { - PhAddItemArray(&context->WindowCallbackArray, &entry); - } - else - { - context = PhAllocate(sizeof(PH_WINDOW_SUBCLASS)); - memset(context, 0, sizeof(PH_WINDOW_SUBCLASS)); - - PhInitializeArray(&context->WindowCallbackArray, sizeof(PH_WINDOW_SUBCLASS_ENTRY), 1); - PhAddItemArray(&context->WindowCallbackArray, &entry); - - context->DefaultWindowProc = (WNDPROC)GetWindowLongPtr(WindowHandle, GWLP_WNDPROC); - - PhSetWindowContext(WindowHandle, PH_WINDOW_SUBCLASS_CONTEXT, context); - - SetWindowLongPtr(WindowHandle, GWLP_WNDPROC, (LONG_PTR)PhWindowSubclassCallback); - } -} - -VOID PhUnregisterWindowSubclass( - _In_ HWND WindowHandle, - _In_ PPH_WINDOW_SUBCLASS_CALLBACK SubclassCallback - ) -{ - PPH_WINDOW_SUBCLASS context; - PPH_WINDOW_SUBCLASS_ENTRY entry; - ULONG i; - - if (!(context = PhGetWindowContext(WindowHandle, PH_WINDOW_SUBCLASS_CONTEXT))) - return; - - for (i = 0; i < context->WindowCallbackArray.Count; i++) - { - entry = PhItemArray(&context->WindowCallbackArray, i); - - if (entry->SubclassCallback == SubclassCallback) - PhRemoveItemArray(&context->WindowCallbackArray, i); - } -} diff --git a/phlib/include/guisup.h b/phlib/include/guisup.h index 216536889b6f..06d4799f1cf9 100644 --- a/phlib/include/guisup.h +++ b/phlib/include/guisup.h @@ -500,45 +500,6 @@ PhRemoveWindowContext( _In_ ULONG PropertyHash ); -typedef BOOLEAN (NTAPI *PPH_WINDOW_SUBCLASS_CALLBACK)( - _In_ HWND hWnd, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam, - _In_ PVOID Context - ); - -typedef struct _PH_WINDOW_SUBCLASS_ENTRY -{ - PPH_WINDOW_SUBCLASS_CALLBACK SubclassCallback; - PVOID Context; -} PH_WINDOW_SUBCLASS_ENTRY, *PPH_WINDOW_SUBCLASS_ENTRY; - -typedef struct _PH_WINDOW_SUBCLASS -{ - WNDPROC DefaultWindowProc; - PH_ARRAY WindowCallbackArray; -} PH_WINDOW_SUBCLASS, *PPH_WINDOW_SUBCLASS; - -#define PH_WINDOW_SUBCLASS_CONTEXT 0xFFFFFF - -PHLIBAPI -VOID -NTAPI -PhRegisterWindowSubclass( - _In_ HWND WindowHandle, - _In_ PPH_WINDOW_SUBCLASS_CALLBACK SubclassWindowProc, - _In_opt_ PVOID Context - ); - -PHLIBAPI -VOID -NTAPI -PhUnregisterWindowSubclass( - _In_ HWND WindowHandle, - _In_ PPH_WINDOW_SUBCLASS_CALLBACK SubclassWindowProc - ); - FORCEINLINE VOID PhResizingMinimumSize( _Inout_ PRECT Rect, _In_ WPARAM Edge, diff --git a/phlib/include/treenewp.h b/phlib/include/treenewp.h index fc0dc1974680..e1d9eb397500 100644 --- a/phlib/include/treenewp.h +++ b/phlib/include/treenewp.h @@ -160,6 +160,9 @@ typedef struct _PH_TREENEW_CONTEXT HRGN SuspendUpdateRegion; PH_STRINGREF EmptyText; + + WNDPROC HeaderWindowProc; + WNDPROC FixedHeaderWindowProc; } PH_TREENEW_CONTEXT, *PPH_TREENEW_CONTEXT; LRESULT CALLBACK PhTnpWndProc( @@ -730,12 +733,11 @@ VOID PhTnpGetHeaderTooltipText( _Out_ PWSTR *Text ); -BOOLEAN CALLBACK PhTnpHeaderHookWndProc( +LRESULT CALLBACK PhTnpHeaderHookWndProc( _In_ HWND hwnd, _In_ UINT uMsg, _In_ WPARAM wParam, - _In_ LPARAM lParam, - _In_ PVOID Context + _In_ LPARAM lParam ); // Drag selection diff --git a/phlib/treenew.c b/phlib/treenew.c index 1330fc93376d..fa4818e5461f 100644 --- a/phlib/treenew.c +++ b/phlib/treenew.c @@ -5846,8 +5846,14 @@ VOID PhTnpInitializeTooltips( SendMessage(Context->TooltipsHandle, TTM_ADDTOOL, 0, (LPARAM)&toolInfo); // Hook the header control window procedures so we can forward mouse messages to the tooltip control. - PhRegisterWindowSubclass(Context->FixedHeaderHandle, PhTnpHeaderHookWndProc, Context); - PhRegisterWindowSubclass(Context->HeaderHandle, PhTnpHeaderHookWndProc, Context); + Context->HeaderWindowProc = (WNDPROC)GetWindowLongPtr(Context->HeaderHandle, GWLP_WNDPROC); + Context->FixedHeaderWindowProc = (WNDPROC)GetWindowLongPtr(Context->FixedHeaderHandle, GWLP_WNDPROC); + + PhSetWindowContext(Context->HeaderHandle, 0xF, Context); + PhSetWindowContext(Context->FixedHeaderHandle, 0xF, Context); + + SetWindowLongPtr(Context->FixedHeaderHandle, GWLP_WNDPROC, (LONG_PTR)PhTnpHeaderHookWndProc); + SetWindowLongPtr(Context->HeaderHandle, GWLP_WNDPROC, (LONG_PTR)PhTnpHeaderHookWndProc); SendMessage(Context->TooltipsHandle, TTM_SETMAXTIPWIDTH, 0, MAXSHORT); // no limit SendMessage(Context->TooltipsHandle, WM_SETFONT, (WPARAM)Context->Font, FALSE); @@ -6134,20 +6140,30 @@ VOID PhTnpGetHeaderTooltipText( SendMessage(Context->TooltipsHandle, TTM_SETMAXTIPWIDTH, 0, TNP_TOOLTIPS_DEFAULT_MAXIMUM_WIDTH); } -BOOLEAN CALLBACK PhTnpHeaderHookWndProc( +LRESULT CALLBACK PhTnpHeaderHookWndProc( _In_ HWND hwnd, _In_ UINT uMsg, _In_ WPARAM wParam, - _In_ LPARAM lParam, - _In_ PVOID Context + _In_ LPARAM lParam ) { - PPH_TREENEW_CONTEXT context = (PPH_TREENEW_CONTEXT)Context; + PPH_TREENEW_CONTEXT context; + WNDPROC oldWndProc; + + context = PhGetWindowContext(hwnd, 0xF); + + if (hwnd == context->FixedHeaderHandle) + oldWndProc = context->FixedHeaderWindowProc; + else + oldWndProc = context->HeaderWindowProc; switch (uMsg) { case WM_DESTROY: - PhUnregisterWindowSubclass(hwnd, PhTnpHeaderHookWndProc); + { + SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)oldWndProc); + PhRemoveWindowContext(hwnd, 0xF); + } break; case WM_MOUSEMOVE: { @@ -6233,7 +6249,7 @@ BOOLEAN CALLBACK PhTnpHeaderHookWndProc( break; } - return FALSE; + return CallWindowProc(oldWndProc, hwnd, uMsg, wParam, lParam);; } BOOLEAN PhTnpDetectDrag( diff --git a/plugins/ExtendedNotifications/main.c b/plugins/ExtendedNotifications/main.c index d8940a4879d5..d92de3748d08 100644 --- a/plugins/ExtendedNotifications/main.c +++ b/plugins/ExtendedNotifications/main.c @@ -606,15 +606,21 @@ LRESULT CALLBACK TextBoxSubclassProc( _In_ HWND hWnd, _In_ UINT uMsg, _In_ WPARAM wParam, - _In_ LPARAM lParam, - _In_ UINT_PTR uIdSubclass, - _In_ ULONG_PTR dwRefData + _In_ LPARAM lParam ) { + WNDPROC oldWndProc = PhGetWindowContext(hWnd, UCHAR_MAX); + + if (!oldWndProc) + return 0; + switch (uMsg) { - case WM_NCDESTROY: - RemoveWindowSubclass(hWnd, TextBoxSubclassProc, uIdSubclass); + case WM_DESTROY: + { + SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)oldWndProc); + PhRemoveWindowContext(hWnd, UCHAR_MAX); + } break; case WM_GETDLGCODE: { @@ -633,7 +639,7 @@ LRESULT CALLBACK TextBoxSubclassProc( break; } - return DefSubclassProc(hWnd, uMsg, wParam, lParam); + return CallWindowProc(oldWndProc, hWnd, uMsg, wParam, lParam); } VOID FixControlStates( @@ -665,8 +671,14 @@ INT_PTR HandleCommonMessages( { case WM_INITDIALOG: { - SetWindowSubclass(GetDlgItem(hwndDlg, IDC_TEXT), TextBoxSubclassProc, 0, 0); - + HWND textBoxHandle; + WNDPROC oldWndProc; + + textBoxHandle = GetDlgItem(hwndDlg, IDC_TEXT); + oldWndProc = (WNDPROC)GetWindowLongPtr(textBoxHandle, GWLP_WNDPROC); + PhSetWindowContext(textBoxHandle, UCHAR_MAX, oldWndProc); + SetWindowLongPtr(textBoxHandle, GWLP_WNDPROC, (LONG_PTR)TextBoxSubclassProc); + Button_SetCheck(GetDlgItem(hwndDlg, IDC_INCLUDE), BST_CHECKED); FixControlStates(hwndDlg, ListBox); diff --git a/plugins/HardwareDevices/disknotify.c b/plugins/HardwareDevices/disknotify.c index c227704b1e8a..8330bd2eaf63 100644 --- a/plugins/HardwareDevices/disknotify.c +++ b/plugins/HardwareDevices/disknotify.c @@ -23,20 +23,17 @@ #include "devices.h" #include -static BOOLEAN SubclassActive = FALSE; +static WNDPROC SubclassMainWindowProc = NULL; -BOOLEAN CALLBACK MainWndDevicesSubclassProc( +LRESULT CALLBACK MainWndDevicesSubclassProc( _In_ HWND hWnd, _In_ UINT uMsg, _In_ WPARAM wParam, - _In_ LPARAM lParam, - _In_ PVOID Context + _In_ LPARAM lParam ) { - // Subclassing the main window just to process drive letter notifications - // is bad and I don't know of any other way to achieve this. - // The IOCTL_MOUNTMGR_CHANGE_NOTIFY callback would have been preferred but - // doesn't work from non-elevated processes. + if (!SubclassMainWindowProc) + return 0; switch (uMsg) { @@ -80,7 +77,7 @@ BOOLEAN CALLBACK MainWndDevicesSubclassProc( break; } - return FALSE; + return CallWindowProc(SubclassMainWindowProc, hWnd, uMsg, wParam, lParam); } VOID AddRemoveDeviceChangeCallback( @@ -92,22 +89,22 @@ VOID AddRemoveDeviceChangeCallback( return; // Add the subclass only when disks are being monitored, remove when no longer needed. - if (DiskDrivesList->Count != 0) + if (DiskDrivesList->Count) { - if (!SubclassActive) + if (!SubclassMainWindowProc) { // We have a disk device, subclass the main window to detect drive letter changes. - PhRegisterWindowSubclass(PhMainWndHandle, MainWndDevicesSubclassProc, NULL); - SubclassActive = TRUE; + SubclassMainWindowProc = (WNDPROC)GetWindowLongPtr(PhMainWndHandle, GWLP_WNDPROC); + SetWindowLongPtr(PhMainWndHandle, GWLP_WNDPROC, (LONG_PTR)MainWndDevicesSubclassProc); } } else { - if (SubclassActive) + if (SubclassMainWindowProc) { // The user has removed the last disk device, remove the subclass. - PhUnregisterWindowSubclass(PhMainWndHandle, MainWndDevicesSubclassProc); - SubclassActive = FALSE; + SetWindowLongPtr(PhMainWndHandle, GWLP_WNDPROC, (LONG_PTR)SubclassMainWindowProc); + SubclassMainWindowProc = NULL; } } } \ No newline at end of file diff --git a/plugins/HardwareDevices/prpsh.c b/plugins/HardwareDevices/prpsh.c index 4b0aedf56512..d0d7d107b799 100644 --- a/plugins/HardwareDevices/prpsh.c +++ b/plugins/HardwareDevices/prpsh.c @@ -47,9 +47,7 @@ LRESULT CALLBACK PvpPropSheetWndProc( _In_ HWND hWnd, _In_ UINT uMsg, _In_ WPARAM wParam, - _In_ LPARAM lParam, - _In_ UINT_PTR uIdSubclass, - _In_ ULONG_PTR dwRefData + _In_ LPARAM lParam ); INT CALLBACK PvpStandardPropPageProc( @@ -137,15 +135,16 @@ INT CALLBACK PvpPropSheetProc( break; case PSCB_INITIALIZED: { - PPV_PROPSHEETCONTEXT propSheetContext; + PPV_PROPSHEETCONTEXT context; - propSheetContext = PhAllocate(sizeof(PV_PROPSHEETCONTEXT)); - memset(propSheetContext, 0, sizeof(PV_PROPSHEETCONTEXT)); + context = PhAllocate(sizeof(PV_PROPSHEETCONTEXT)); + memset(context, 0, sizeof(PV_PROPSHEETCONTEXT)); - PhInitializeLayoutManager(&propSheetContext->LayoutManager, hwndDlg); + PhInitializeLayoutManager(&context->LayoutManager, hwndDlg); - SetWindowSubclass(hwndDlg, PvpPropSheetWndProc, 0, (ULONG_PTR)propSheetContext); - PhSetWindowContext(hwndDlg, ULONG_MAX, propSheetContext); + context->DefaultWindowProc = (WNDPROC)GetWindowLongPtr(hwndDlg, GWLP_WNDPROC); + PhSetWindowContext(hwndDlg, ULONG_MAX, context); + SetWindowLongPtr(hwndDlg, GWLP_WNDPROC, (LONG_PTR)PvpPropSheetWndProc); if (MinimumSize.left == -1) { @@ -177,23 +176,25 @@ LRESULT CALLBACK PvpPropSheetWndProc( _In_ HWND hWnd, _In_ UINT uMsg, _In_ WPARAM wParam, - _In_ LPARAM lParam, - _In_ UINT_PTR uIdSubclass, - _In_ ULONG_PTR dwRefData + _In_ LPARAM lParam ) { - PPV_PROPSHEETCONTEXT propSheetContext = (PPV_PROPSHEETCONTEXT)dwRefData; + PPV_PROPSHEETCONTEXT context = PhGetWindowContext(hWnd, ULONG_MAX); + + if (!context) + return 0; switch (uMsg) { - case WM_NCDESTROY: + case WM_DESTROY: { - RemoveWindowSubclass(hWnd, PvpPropSheetWndProc, uIdSubclass); + SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)context->DefaultWindowProc); + PhRemoveWindowContext(hWnd, ULONG_MAX); PhSaveWindowPlacementToSetting(SETTING_NAME_DISK_POSITION, SETTING_NAME_DISK_SIZE, hWnd); - PhDeleteLayoutManager(&propSheetContext->LayoutManager); + PhDeleteLayoutManager(&context->LayoutManager); - PhFree(propSheetContext); + PhFree(context); } break; case WM_COMMAND: @@ -212,7 +213,7 @@ LRESULT CALLBACK PvpPropSheetWndProc( { if (!IsIconic(hWnd)) { - PhLayoutManagerLayout(&propSheetContext->LayoutManager); + PhLayoutManagerLayout(&context->LayoutManager); } } break; @@ -223,7 +224,7 @@ LRESULT CALLBACK PvpPropSheetWndProc( break; } - return DefSubclassProc(hWnd, uMsg, wParam, lParam); + return CallWindowProc(context->DefaultWindowProc, hWnd, uMsg, wParam, lParam); } BOOLEAN PhpInitializePropSheetLayoutStage1( diff --git a/plugins/HardwareDevices/prpsh.h b/plugins/HardwareDevices/prpsh.h index dd2411ab700c..f3f0e6d3e7b5 100644 --- a/plugins/HardwareDevices/prpsh.h +++ b/plugins/HardwareDevices/prpsh.h @@ -30,6 +30,7 @@ typedef struct _PV_PROPSHEETCONTEXT { BOOLEAN LayoutInitialized; + WNDPROC DefaultWindowProc; PH_LAYOUT_MANAGER LayoutManager; PPH_LAYOUT_ITEM TabPageItem; } PV_PROPSHEETCONTEXT, *PPV_PROPSHEETCONTEXT; diff --git a/plugins/OnlineChecks/onlnchk.h b/plugins/OnlineChecks/onlnchk.h index e07b3245d69c..4f109a9aeccd 100644 --- a/plugins/OnlineChecks/onlnchk.h +++ b/plugins/OnlineChecks/onlnchk.h @@ -122,6 +122,7 @@ typedef struct _UPLOAD_CONTEXT ULONG TotalFileLength; HWND DialogHandle; + WNDPROC DialogWindowProc; HANDLE UploadThreadHandle; HICON IconLargeHandle; HICON IconSmallHandle; diff --git a/plugins/OnlineChecks/upload.c b/plugins/OnlineChecks/upload.c index 97d871d9c094..ab421a4a79b7 100644 --- a/plugins/OnlineChecks/upload.c +++ b/plugins/OnlineChecks/upload.c @@ -1169,22 +1169,28 @@ NTSTATUS UploadRecheckThreadStart( return STATUS_SUCCESS; } -BOOLEAN CALLBACK TaskDialogSubclassProc( +LRESULT CALLBACK TaskDialogSubclassProc( _In_ HWND hwndDlg, _In_ UINT uMsg, _In_ WPARAM wParam, - _In_ LPARAM lParam, - _In_ PVOID Context + _In_ LPARAM lParam ) { - PUPLOAD_CONTEXT context = (PUPLOAD_CONTEXT)Context; + PUPLOAD_CONTEXT context; + + context = PhGetWindowContext(hwndDlg, 0xF); + + if (!context) + return 0; switch (uMsg) { case WM_DESTROY: { + SetWindowLongPtr(hwndDlg, GWLP_WNDPROC, (LONG_PTR)context->DialogWindowProc); + PhRemoveWindowContext(hwndDlg, 0xF); + TaskDialogFreeContext(context); - PhUnregisterWindowSubclass(hwndDlg, TaskDialogSubclassProc); } break; case UM_UPLOAD: @@ -1240,7 +1246,7 @@ BOOLEAN CALLBACK TaskDialogSubclassProc( break; } - return FALSE; + return CallWindowProc(context->DialogWindowProc, hwndDlg, uMsg, wParam, lParam); } HRESULT CALLBACK TaskDialogBootstrapCallback( @@ -1274,7 +1280,9 @@ HRESULT CALLBACK TaskDialogBootstrapCallback( } } - PhRegisterWindowSubclass(hwndDlg, TaskDialogSubclassProc, context); + context->DialogWindowProc = (WNDPROC)GetWindowLongPtr(hwndDlg, GWLP_WNDPROC); + PhSetWindowContext(hwndDlg, 0xF, context); + SetWindowLongPtr(hwndDlg, GWLP_WNDPROC, (LONG_PTR)TaskDialogSubclassProc); ShowVirusTotalUploadDialog(context); } diff --git a/plugins/ToolStatus/main.c b/plugins/ToolStatus/main.c index 6e653d207597..dd16c542cc45 100644 --- a/plugins/ToolStatus/main.c +++ b/plugins/ToolStatus/main.c @@ -49,6 +49,7 @@ REBAR_DISPLAY_LOCATION RebarDisplayLocation = REBAR_DISPLAY_LOCATION_TOP; HWND RebarHandle = NULL; HWND ToolBarHandle = NULL; HWND SearchboxHandle = NULL; +WNDPROC MainWindowHookProc = NULL; HMENU MainMenu = NULL; HACCEL AcceleratorTable = NULL; PPH_STRING SearchboxText = NULL; @@ -620,16 +621,18 @@ VOID DrawWindowBorderForTargeting( } } -BOOLEAN CALLBACK MainWndSubclassProc( +LRESULT CALLBACK MainWndSubclassProc( _In_ HWND hWnd, _In_ UINT uMsg, _In_ WPARAM wParam, - _In_ LPARAM lParam, - _In_ PVOID Context + _In_ LPARAM lParam ) { switch (uMsg) { + case WM_DESTROY: + SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)MainWindowHookProc); + break; case WM_COMMAND: { switch (GET_WM_COMMAND_CMD(wParam, lParam)) @@ -721,7 +724,7 @@ BOOLEAN CALLBACK MainWndSubclassProc( case PHAPP_ID_VIEW_ALWAYSONTOP: { // Let Process Hacker perform the default processing. - DefSubclassProc(hWnd, uMsg, wParam, lParam); + CallWindowProc(MainWindowHookProc, hWnd, uMsg, wParam, lParam); // Query the settings. BOOLEAN isAlwaysOnTopEnabled = (BOOLEAN)PhGetIntegerSetting(L"MainWindowAlwaysOnTop"); @@ -737,7 +740,7 @@ BOOLEAN CALLBACK MainWndSubclassProc( case PHAPP_ID_UPDATEINTERVAL_VERYSLOW: { // Let Process Hacker perform the default processing. - DefSubclassProc(hWnd, uMsg, wParam, lParam); + CallWindowProc(MainWindowHookProc, hWnd, uMsg, wParam, lParam); StatusBarUpdate(TRUE); } @@ -1305,10 +1308,10 @@ BOOLEAN CALLBACK MainWndSubclassProc( break; } - return FALSE; + return CallWindowProc(MainWindowHookProc, hWnd, uMsg, wParam, lParam); DefaultWndProc: - return TRUE; + return DefWindowProc(hWnd, uMsg, wParam, lParam); } VOID NTAPI MainWindowShowingCallback( @@ -1323,7 +1326,9 @@ VOID NTAPI MainWindowShowingCallback( NULL, &LayoutPaddingCallbackRegistration ); - PhRegisterWindowSubclass(PhMainWndHandle, MainWndSubclassProc, NULL); + + MainWindowHookProc = (WNDPROC)GetWindowLongPtr(PhMainWndHandle, GWLP_WNDPROC); + SetWindowLongPtr(PhMainWndHandle, GWLP_WNDPROC, (LONG_PTR)MainWndSubclassProc); ToolbarLoadSettings(); ReBarLoadLayoutSettings(); diff --git a/plugins/Updater/updater.c b/plugins/Updater/updater.c index 0570ee4c60ad..3b5245112115 100644 --- a/plugins/Updater/updater.c +++ b/plugins/Updater/updater.c @@ -755,18 +755,26 @@ NTSTATUS UpdateDownloadThread( return STATUS_SUCCESS; } -BOOLEAN NTAPI TaskDialogSubclassProc( +LRESULT CALLBACK TaskDialogSubclassProc( _In_ HWND hwndDlg, _In_ UINT uMsg, _In_ WPARAM wParam, - _In_ LPARAM lParam, - _In_ PVOID Context + _In_ LPARAM lParam ) { - PPH_UPDATER_CONTEXT context = (PPH_UPDATER_CONTEXT)Context; + PPH_UPDATER_CONTEXT context = PhGetWindowContext(hwndDlg, UCHAR_MAX); + + if (!context) + return 0; switch (uMsg) { + case WM_DESTROY: + { + SetWindowLongPtr(hwndDlg, GWLP_WNDPROC, (LONG_PTR)context->DefaultWindowProc); + PhRemoveWindowContext(hwndDlg, UCHAR_MAX); + } + break; case PH_SHOWDIALOG: { if (IsMinimized(hwndDlg)) @@ -777,11 +785,6 @@ BOOLEAN NTAPI TaskDialogSubclassProc( SetForegroundWindow(hwndDlg); } break; - case WM_DESTROY: - { - PhUnregisterWindowSubclass(hwndDlg, TaskDialogSubclassProc); - } - break; //case WM_PARENTNOTIFY: // { // if (wParam == WM_CREATE) @@ -823,8 +826,8 @@ BOOLEAN NTAPI TaskDialogSubclassProc( // } // break; } - - return FALSE; + + return CallWindowProc(context->DefaultWindowProc, hwndDlg, uMsg, wParam, lParam); } HRESULT CALLBACK TaskDialogBootstrapCallback( @@ -846,11 +849,13 @@ HRESULT CALLBACK TaskDialogBootstrapCallback( // Center the update window on PH if it's visible else we center on the desktop. PhCenterWindow(hwndDlg, (IsWindowVisible(PhMainWndHandle) && !IsMinimized(PhMainWndHandle)) ? PhMainWndHandle : NULL); - // Create the Taskdialog icons + // Create the Taskdialog icons. TaskDialogCreateIcons(context); - // Subclass the Taskdialog - PhRegisterWindowSubclass(hwndDlg, TaskDialogSubclassProc, context); + // Subclass the Taskdialog. + context->DefaultWindowProc = (WNDPROC)GetWindowLongPtr(hwndDlg, GWLP_WNDPROC); + PhSetWindowContext(hwndDlg, UCHAR_MAX, context); + SetWindowLongPtr(hwndDlg, GWLP_WNDPROC, (LONG_PTR)TaskDialogSubclassProc); if (context->StartupCheck) ShowAvailableDialog(context); diff --git a/plugins/Updater/updater.h b/plugins/Updater/updater.h index ebc867f041a1..d7749ce02c92 100644 --- a/plugins/Updater/updater.h +++ b/plugins/Updater/updater.h @@ -85,6 +85,7 @@ typedef struct _PH_UPDATER_CONTEXT HICON IconLargeHandle; HWND DialogHandle; + WNDPROC DefaultWindowProc; ULONG ErrorCode; PPH_STRING SetupFilePath; diff --git a/plugins/WindowExplorer/wndprp.c b/plugins/WindowExplorer/wndprp.c index 865fb60ba65c..33f4a2e09380 100644 --- a/plugins/WindowExplorer/wndprp.c +++ b/plugins/WindowExplorer/wndprp.c @@ -94,12 +94,11 @@ INT CALLBACK WepPropSheetProc( _In_ LPARAM lParam ); -BOOLEAN CALLBACK WepPropSheetWndProc( +LRESULT CALLBACK WepPropSheetWndProc( _In_ HWND hwnd, _In_ UINT uMsg, _In_ WPARAM wParam, - _In_ LPARAM lParam, - _In_ PVOID Context + _In_ LPARAM lParam ); HPROPSHEETPAGE WepCommonCreatePage( @@ -360,7 +359,8 @@ static INT CALLBACK WepPropSheetProc( { HWND refreshButtonHandle; - PhRegisterWindowSubclass(hwndDlg, WepPropSheetWndProc, NULL); + PhSetWindowContext(hwndDlg, 0xF, (WNDPROC)GetWindowLongPtr(hwndDlg, GWLP_WNDPROC)); + SetWindowLongPtr(hwndDlg, GWLP_WNDPROC, (LONG_PTR)WepPropSheetWndProc); // Hide the Cancel button. ShowWindow(GetDlgItem(hwndDlg, IDCANCEL), SW_HIDE); @@ -377,19 +377,27 @@ static INT CALLBACK WepPropSheetProc( return 0; } -BOOLEAN CALLBACK WepPropSheetWndProc( +LRESULT CALLBACK WepPropSheetWndProc( _In_ HWND hwnd, _In_ UINT uMsg, _In_ WPARAM wParam, - _In_ LPARAM lParam, - _In_ PVOID Context + _In_ LPARAM lParam ) { + WNDPROC defaultPropSheetWindowProc = PhGetWindowContext(hwnd, 0xF); + + if (!defaultPropSheetWindowProc) + return 0; + switch (uMsg) { case WM_DESTROY: { - PhRemoveWindowContext(hwnd, 1); + SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)defaultPropSheetWindowProc); + PhRemoveWindowContext(hwnd, 0xF); + + if (PhGetWindowContext(hwnd, 1)) + PhRemoveWindowContext(hwnd, 1); } break; case WM_SHOWWINDOW: @@ -429,7 +437,7 @@ BOOLEAN CALLBACK WepPropSheetWndProc( break; } - return FALSE; + return CallWindowProc(defaultPropSheetWindowProc, hwnd, uMsg, wParam, lParam); } static HPROPSHEETPAGE WepCommonCreatePage( diff --git a/tools/peview/include/prpsh.h b/tools/peview/include/prpsh.h index 6857565c5061..14d8801f10a9 100644 --- a/tools/peview/include/prpsh.h +++ b/tools/peview/include/prpsh.h @@ -29,9 +29,10 @@ typedef struct _PV_PROPSHEETCONTEXT { + BOOLEAN LayoutInitialized; + WNDPROC DefaultWindowProc; PH_LAYOUT_MANAGER LayoutManager; PPH_LAYOUT_ITEM TabPageItem; - BOOLEAN LayoutInitialized; } PV_PROPSHEETCONTEXT, *PPV_PROPSHEETCONTEXT; typedef struct _PV_PROPCONTEXT diff --git a/tools/peview/pdbprp.c b/tools/peview/pdbprp.c index d6b471f28854..7d4751f39084 100644 --- a/tools/peview/pdbprp.c +++ b/tools/peview/pdbprp.c @@ -1040,6 +1040,9 @@ VOID CALLBACK PvSymbolTreeUpdateCallback( { ULONG i; + if (!Context->UpdateTimerHandle) + return; + TreeNew_SetRedraw(Context->TreeNewHandle, FALSE); PhAcquireQueuedLockExclusive(&SearchResultsLock); @@ -1121,10 +1124,16 @@ INT_PTR CALLBACK PvpSymbolsDlgProc( case WM_DESTROY: { if (context->UpdateTimerHandle) + { RtlDeleteTimer(context->TimerQueueHandle, context->UpdateTimerHandle, NULL); + context->UpdateTimerHandle = NULL; + } if (context->TimerQueueHandle) + { RtlDeleteTimerQueue(context->TimerQueueHandle); + context->TimerQueueHandle = NULL; + } PvDeleteSymbolTree(context); } diff --git a/tools/peview/prpsh.c b/tools/peview/prpsh.c index 14fcba4fe066..10842ae18765 100644 --- a/tools/peview/prpsh.c +++ b/tools/peview/prpsh.c @@ -49,9 +49,7 @@ LRESULT CALLBACK PvpPropSheetWndProc( _In_ HWND hWnd, _In_ UINT uMsg, _In_ WPARAM wParam, - _In_ LPARAM lParam, - _In_ UINT_PTR uIdSubclass, - _In_ ULONG_PTR dwRefData + _In_ LPARAM lParam ); INT CALLBACK PvpStandardPropPageProc( @@ -148,15 +146,16 @@ INT CALLBACK PvpPropSheetProc( break; case PSCB_INITIALIZED: { - PPV_PROPSHEETCONTEXT propSheetContext; + PPV_PROPSHEETCONTEXT context; - propSheetContext = PhAllocate(sizeof(PV_PROPSHEETCONTEXT)); - memset(propSheetContext, 0, sizeof(PV_PROPSHEETCONTEXT)); + context = PhAllocate(sizeof(PV_PROPSHEETCONTEXT)); + memset(context, 0, sizeof(PV_PROPSHEETCONTEXT)); - PhInitializeLayoutManager(&propSheetContext->LayoutManager, hwndDlg); + PhInitializeLayoutManager(&context->LayoutManager, hwndDlg); - PhSetWindowContext(hwndDlg, ULONG_MAX, propSheetContext); - SetWindowSubclass(hwndDlg, PvpPropSheetWndProc, 0, (ULONG_PTR)propSheetContext); + context->DefaultWindowProc = (WNDPROC)GetWindowLongPtr(hwndDlg, GWLP_WNDPROC); + PhSetWindowContext(hwndDlg, UCHAR_MAX, context); + SetWindowLongPtr(hwndDlg, GWLP_WNDPROC, (LONG_PTR)PvpPropSheetWndProc); if (MinimumSize.left == -1) { @@ -181,19 +180,20 @@ PPV_PROPSHEETCONTEXT PvpGetPropSheetContext( _In_ HWND hwnd ) { - return PhGetWindowContext(hwnd, ULONG_MAX); + return PhGetWindowContext(hwnd, UCHAR_MAX); } LRESULT CALLBACK PvpPropSheetWndProc( _In_ HWND hWnd, _In_ UINT uMsg, _In_ WPARAM wParam, - _In_ LPARAM lParam, - _In_ UINT_PTR uIdSubclass, - _In_ ULONG_PTR dwRefData + _In_ LPARAM lParam ) { - PPV_PROPSHEETCONTEXT propSheetContext = (PPV_PROPSHEETCONTEXT)dwRefData; + PPV_PROPSHEETCONTEXT propSheetContext = PhGetWindowContext(hWnd, UCHAR_MAX); + + if (!propSheetContext) + return 0; switch (uMsg) { @@ -223,10 +223,15 @@ LRESULT CALLBACK PvpPropSheetWndProc( break; case WM_NCDESTROY: { - RemoveWindowSubclass(hWnd, PvpPropSheetWndProc, uIdSubclass); + LRESULT result; + + result = CallWindowProc(propSheetContext->DefaultWindowProc, hWnd, uMsg, wParam, lParam); + SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)propSheetContext->DefaultWindowProc); + PhRemoveWindowContext(hWnd, UCHAR_MAX); PhDeleteLayoutManager(&propSheetContext->LayoutManager); PhFree(propSheetContext); + return result; } break; case WM_COMMAND: @@ -256,7 +261,7 @@ LRESULT CALLBACK PvpPropSheetWndProc( break; } - return DefSubclassProc(hWnd, uMsg, wParam, lParam); + return CallWindowProc(propSheetContext->DefaultWindowProc, hWnd, uMsg, wParam, lParam); } BOOLEAN PhpInitializePropSheetLayoutStage1( From f6e9f29598eea32ba52537d925ec5528b0783df9 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 5 Feb 2018 04:23:29 +1100 Subject: [PATCH 0765/2058] BuildTools: update binaries --- tools/CustomBuildTool/Source Files/Build.cs | 30 ++++++++++-------- tools/CustomBuildTool/Source Files/Program.cs | 2 ++ .../bin/Release/CustomBuildTool.exe | Bin 163840 -> 163840 bytes .../bin/Release/CustomBuildTool.pdb | Bin 75264 -> 75264 bytes 4 files changed, 19 insertions(+), 13 deletions(-) diff --git a/tools/CustomBuildTool/Source Files/Build.cs b/tools/CustomBuildTool/Source Files/Build.cs index 05ea621f630e..27cda72084db 100644 --- a/tools/CustomBuildTool/Source Files/Build.cs +++ b/tools/CustomBuildTool/Source Files/Build.cs @@ -257,11 +257,6 @@ public static void ShowBuildEnvironment(string Platform, bool ShowBuildInfo, boo BuildBranch = Win32.ShellExecute(GitExePath, "rev-parse --abbrev-ref HEAD").Trim(); BuildCommit = Win32.ShellExecute(GitExePath, "rev-parse HEAD").Trim(); - Program.PrintColorMessage("Branch: ", ConsoleColor.Cyan, false); - Program.PrintColorMessage(BuildBranch, ConsoleColor.White); - Program.PrintColorMessage("Commit: ", ConsoleColor.Cyan, false); - Program.PrintColorMessage(BuildCommit.Substring(0, 8), ConsoleColor.White); - string currentGitTag = Win32.ShellExecute(GitExePath, "describe --abbrev=0 --tags --always").Trim(); BuildRevision = Win32.ShellExecute(GitExePath, "rev-list --count \"" + currentGitTag + ".." + BuildBranch + "\"").Trim(); BuildCount = Win32.ShellExecute(GitExePath, "rev-list --count " + BuildBranch).Trim(); @@ -277,8 +272,13 @@ public static void ShowBuildEnvironment(string Platform, bool ShowBuildInfo, boo if (ShowBuildInfo && !GitExportBuild) { - Program.PrintColorMessage("Version: ", ConsoleColor.Cyan, false); - Program.PrintColorMessage(BuildVersion + Environment.NewLine, ConsoleColor.White); + Program.PrintColorMessage("Branch: ", ConsoleColor.DarkGray, false); + Program.PrintColorMessage(BuildBranch, ConsoleColor.Green, true); + Program.PrintColorMessage("Version: ", ConsoleColor.DarkGray, false); + Program.PrintColorMessage(BuildVersion, ConsoleColor.Green, false); + Program.PrintColorMessage(" (", ConsoleColor.DarkGray, false); + Program.PrintColorMessage(BuildCommit.Substring(0, 8), ConsoleColor.DarkYellow, false); + Program.PrintColorMessage(")" + Environment.NewLine, ConsoleColor.DarkGray, true); if (!BuildNightly && ShowLogInfo && File.Exists(GitExePath)) { @@ -292,6 +292,7 @@ public static void ShowBuildEnvironment(string Platform, bool ShowBuildInfo, boo //BuildMessage = Win32.ShellExecute(GitExePath, "log -n 1 --date=format:%Y-%m-%d --pretty=format:\"[%cd] %an: %<(65,trunc)%s (%h)\" --abbrev-commit"); //Console.WriteLine(BuildMessage + Environment.NewLine); } + } } @@ -299,10 +300,11 @@ public static void ShowBuildStats() { TimeSpan buildTime = DateTime.Now - TimeStart; - Console.WriteLine( - Environment.NewLine + "Build Time: " + - buildTime.Minutes + " minute(s), " + - buildTime.Seconds + " second(s)"); + Program.PrintColorMessage(Environment.NewLine + "Build Time: ", ConsoleColor.DarkGray, false); + Program.PrintColorMessage(buildTime.Minutes.ToString(), ConsoleColor.Green, false); + Program.PrintColorMessage(" minute(s), ", ConsoleColor.DarkGray, false); + Program.PrintColorMessage(buildTime.Seconds.ToString(), ConsoleColor.Green, false); + Program.PrintColorMessage(" second(s) " + Environment.NewLine, ConsoleColor.DarkGray, true); } public static bool CopyTextFiles() @@ -1040,14 +1042,16 @@ public static bool AppveyorUploadBuildFiles() //BuildOutputFolder + "\\processhacker-build-websetup.exe", BuildOutputFolder + "\\processhacker-build-setup.exe", BuildOutputFolder + "\\processhacker-build-bin.zip", - BuildOutputFolder + "\\processhacker-build-checksums.txt" + BuildOutputFolder + "\\processhacker-build-checksums.txt", + BuildOutputFolder + "\\processhacker-build-pdb.zip" }; string[] releaseFileArray = { //BuildOutputFolder + "\\processhacker-websetup.exe", BuildOutputFolder + "\\processhacker-" + BuildVersion + "-setup.exe", BuildOutputFolder + "\\processhacker-" + BuildVersion + "-bin.zip", - BuildOutputFolder + "\\processhacker-" + BuildVersion + "-checksums.txt" + BuildOutputFolder + "\\processhacker-" + BuildVersion + "-checksums.txt", + BuildOutputFolder + "\\processhacker-" + BuildVersion + "-pdb.zip" }; if (!BuildNightly) diff --git a/tools/CustomBuildTool/Source Files/Program.cs b/tools/CustomBuildTool/Source Files/Program.cs index 572f1a1d682c..82d1f4f7d1bb 100644 --- a/tools/CustomBuildTool/Source Files/Program.cs +++ b/tools/CustomBuildTool/Source Files/Program.cs @@ -228,6 +228,8 @@ public static void Main(string[] args) return; //if (!Build.BuildWebSetupExe()) // return; + if (!Build.BuildPdbZip()) + return; if (!Build.BuildSetupExe()) return; if (!Build.BuildChecksumsFile()) diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe b/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe index 66b2a6015e56716d1ae01195b8cd4b1ef15531b9..2b5fcdef709a14d4ced37d19ebf0522d453cb0d1 100644 GIT binary patch delta 13787 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 delta 13774 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 D^Kk~x From dc203a1fa2ced798305e897e2f4ee1b9f44c8cfa Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 5 Feb 2018 04:39:08 +1100 Subject: [PATCH 0766/2058] Fix crash --- phlib/extlv.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/phlib/extlv.c b/phlib/extlv.c index 0bed9ab7f6cf..2ca05cc32704 100644 --- a/phlib/extlv.c +++ b/phlib/extlv.c @@ -126,9 +126,8 @@ VOID PhSetExtendedListView( context->EnableRedraw = 1; context->Cursor = NULL; - PhSetWindowContext(hWnd, MAXBYTE, context); - context->OldWndProc = (WNDPROC)GetWindowLongPtr(hWnd, GWLP_WNDPROC); + PhSetWindowContext(hWnd, MAXCHAR, context); SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)PhpExtendedListViewWndProc); ExtendedListView_Init(hWnd); @@ -141,14 +140,22 @@ LRESULT CALLBACK PhpExtendedListViewWndProc( _In_ LPARAM lParam ) { - PPH_EXTLV_CONTEXT context = PhGetWindowContext(hwnd, MAXBYTE); + PPH_EXTLV_CONTEXT context; + WNDPROC oldWndProc; + + context = PhGetWindowContext(hwnd, MAXCHAR); + + if (!context) + return 0; + + oldWndProc = context->OldWndProc; switch (uMsg) { case WM_DESTROY: { - SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)context->OldWndProc); - PhRemoveWindowContext(hwnd, MAXBYTE); + SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)oldWndProc); + PhRemoveWindowContext(hwnd, MAXCHAR); PhFree(context); } break; @@ -469,7 +476,7 @@ LRESULT CALLBACK PhpExtendedListViewWndProc( return TRUE; } - return CallWindowProc(context->OldWndProc, hwnd, uMsg, wParam, lParam); + return CallWindowProc(oldWndProc, hwnd, uMsg, wParam, lParam); } /** From 8cfb5f794c7682c81dcb34ca9580c276d62a9ab6 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 5 Feb 2018 04:40:40 +1100 Subject: [PATCH 0767/2058] Fix typo --- phlib/extlv.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/phlib/extlv.c b/phlib/extlv.c index 2ca05cc32704..35f442bea4d9 100644 --- a/phlib/extlv.c +++ b/phlib/extlv.c @@ -169,7 +169,7 @@ LRESULT CALLBACK PhpExtendedListViewWndProc( { HWND headerHandle; - headerHandle = (HWND)CallWindowProc(context->OldWndProc, hwnd, LVM_GETHEADER, 0, 0); + headerHandle = (HWND)CallWindowProc(oldWndProc, hwnd, LVM_GETHEADER, 0, 0); if (header->hwndFrom == headerHandle) { @@ -357,7 +357,7 @@ LRESULT CALLBACK PhpExtendedListViewWndProc( { if (i != column) { - if (CallWindowProc(context->OldWndProc, hwnd, LVM_GETCOLUMN, i, (LPARAM)&lvColumn)) + if (CallWindowProc(oldWndProc, hwnd, LVM_GETCOLUMN, i, (LPARAM)&lvColumn)) { availableWidth -= lvColumn.cx; } @@ -371,10 +371,10 @@ LRESULT CALLBACK PhpExtendedListViewWndProc( } if (availableWidth >= 40) - return CallWindowProc(context->OldWndProc, hwnd, LVM_SETCOLUMNWIDTH, column, availableWidth); + return CallWindowProc(oldWndProc, hwnd, LVM_SETCOLUMNWIDTH, column, availableWidth); } - return CallWindowProc(context->OldWndProc, hwnd, LVM_SETCOLUMNWIDTH, column, width); + return CallWindowProc(oldWndProc, hwnd, LVM_SETCOLUMNWIDTH, column, width); } break; case ELVM_SETCOMPAREFUNCTION: From f2d5edce93f3a29e0a17e220bfd9bc21afa24896 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 5 Feb 2018 05:03:14 +1100 Subject: [PATCH 0768/2058] Fix commit 33e0ab1 --- ProcessHacker/memsrch.c | 11 +++++++---- ProcessHacker/procprp.c | 11 +++++------ ProcessHacker/searchbox.c | 13 ++++++++----- ProcessHacker/splitter.c | 14 +++++++++----- ProcessHacker/sysinfo.c | 11 ++++++----- plugins/HardwareDevices/prpsh.c | 11 +++++++---- plugins/OnlineChecks/upload.c | 11 ++++++----- plugins/Updater/updater.c | 13 ++++++++----- plugins/WindowExplorer/wndprp.c | 8 ++++---- tools/peview/prpsh.c | 15 +++++++-------- 10 files changed, 67 insertions(+), 51 deletions(-) diff --git a/ProcessHacker/memsrch.c b/ProcessHacker/memsrch.c index 9d665ab2cbe2..7e6a85d81fb8 100644 --- a/ProcessHacker/memsrch.c +++ b/ProcessHacker/memsrch.c @@ -658,16 +658,19 @@ LRESULT CALLBACK PhpMemoryStringTaskDialogSubclassProc( _In_ LPARAM lParam ) { - PMEMORY_STRING_CONTEXT context = PhGetWindowContext(hwndDlg, 0xF); + PMEMORY_STRING_CONTEXT context; + WNDPROC oldWndProc; - if (!context) + if (!(context = PhGetWindowContext(hwndDlg, 0xF))) return 0; + oldWndProc = context->DefaultWindowProc; + switch (uMsg) { case WM_DESTROY: { - SetWindowLongPtr(hwndDlg, GWLP_WNDPROC, (LONG_PTR)context->DefaultWindowProc); + SetWindowLongPtr(hwndDlg, GWLP_WNDPROC, (LONG_PTR)oldWndProc); PhRemoveWindowContext(hwndDlg, 0xF); } break; @@ -686,7 +689,7 @@ LRESULT CALLBACK PhpMemoryStringTaskDialogSubclassProc( break; } - return CallWindowProc(context->DefaultWindowProc, hwndDlg, uMsg, wParam, lParam); + return CallWindowProc(oldWndProc, hwndDlg, uMsg, wParam, lParam); } HRESULT CALLBACK PhpMemoryStringTaskDialogCallback( diff --git a/ProcessHacker/procprp.c b/ProcessHacker/procprp.c index 9273e4c19a71..8fde7b3904dd 100644 --- a/ProcessHacker/procprp.c +++ b/ProcessHacker/procprp.c @@ -206,12 +206,15 @@ LRESULT CALLBACK PhpPropSheetWndProc( ) { PPH_PROCESS_PROPSHEETCONTEXT propSheetContext; + WNDPROC oldWndProc; propSheetContext = PhGetWindowContext(hwnd, 0xF); if (!propSheetContext) return 0; + oldWndProc = propSheetContext->PropSheetWindowHookProc; + switch (uMsg) { case WM_DESTROY: @@ -240,15 +243,11 @@ LRESULT CALLBACK PhpPropSheetWndProc( break; case WM_NCDESTROY: { - LRESULT result; - - result = CallWindowProc(propSheetContext->PropSheetWindowHookProc, hwnd, uMsg, wParam, lParam); - SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)propSheetContext->PropSheetWindowHookProc); + SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)oldWndProc); PhRemoveWindowContext(hwnd, 0xF); PhDeleteLayoutManager(&propSheetContext->LayoutManager); PhFree(propSheetContext); - return result; } break; case WM_COMMAND: @@ -278,7 +277,7 @@ LRESULT CALLBACK PhpPropSheetWndProc( break; } - return CallWindowProc(propSheetContext->PropSheetWindowHookProc, hwnd, uMsg, wParam, lParam); + return CallWindowProc(oldWndProc, hwnd, uMsg, wParam, lParam); } BOOLEAN PhpInitializePropSheetLayoutStage1( diff --git a/ProcessHacker/searchbox.c b/ProcessHacker/searchbox.c index 8c12ecef56cf..436e91e94d8f 100644 --- a/ProcessHacker/searchbox.c +++ b/ProcessHacker/searchbox.c @@ -254,20 +254,23 @@ LRESULT CALLBACK PhpSearchWndSubclassProc( ) { PEDIT_CONTEXT context; + WNDPROC oldWndProc; if (!(context = PhGetWindowContext(hWnd, 10))) return 0; + oldWndProc = context->DefaultWindowProc; + switch (uMsg) { - case WM_NCDESTROY: + case WM_DESTROY: { PhpSearchFreeTheme(context); if (context->WindowFont) DeleteObject(context->WindowFont); - SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)context->DefaultWindowProc); + SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)oldWndProc); PhRemoveWindowContext(hWnd, 10); PhFree(context); } @@ -279,7 +282,7 @@ LRESULT CALLBACK PhpSearchWndSubclassProc( LPNCCALCSIZE_PARAMS ncCalcSize = (NCCALCSIZE_PARAMS*)lParam; // Let Windows handle the non-client defaults. - CallWindowProc(context->DefaultWindowProc, hWnd, uMsg, wParam, lParam); + CallWindowProc(oldWndProc, hWnd, uMsg, wParam, lParam); // Deflate the client area to accommodate the custom button. ncCalcSize->rgrc[0].right -= context->CXWidth; @@ -290,7 +293,7 @@ LRESULT CALLBACK PhpSearchWndSubclassProc( RECT windowRect; // Let Windows handle the non-client defaults. - CallWindowProc(context->DefaultWindowProc, hWnd, uMsg, wParam, lParam); + CallWindowProc(oldWndProc, hWnd, uMsg, wParam, lParam); // Get the screen coordinates of the window. GetWindowRect(hWnd, &windowRect); @@ -482,7 +485,7 @@ LRESULT CALLBACK PhpSearchWndSubclassProc( break; } - return CallWindowProc(context->DefaultWindowProc, hWnd, uMsg, wParam, lParam); + return CallWindowProc(oldWndProc, hWnd, uMsg, wParam, lParam); } HICON PhpSearchBitmapToIcon( diff --git a/ProcessHacker/splitter.c b/ProcessHacker/splitter.c index e6ce1a57abc9..74a9eb79a3e9 100644 --- a/ProcessHacker/splitter.c +++ b/ProcessHacker/splitter.c @@ -272,18 +272,22 @@ LRESULT CALLBACK HSplitterParentWindowProc( _In_ LPARAM lParam ) { - PPH_HSPLITTER_CONTEXT context = PhGetWindowContext(hwnd, 0x200); + PPH_HSPLITTER_CONTEXT context; + WNDPROC oldWndProc; - if (!context) + if (!(context = PhGetWindowContext(hwnd, 0x200))) return 0; + oldWndProc = context->DefaultWindowProc; + switch (uMsg) { case WM_DESTROY: { - SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)context->DefaultWindowProc); - PhDeleteHSplitter(context); + SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)oldWndProc); PhRemoveWindowContext(hwnd, 0x200); + + PhDeleteHSplitter(context); } break; case WM_SIZE: @@ -293,7 +297,7 @@ LRESULT CALLBACK HSplitterParentWindowProc( break; } - return CallWindowProc(context->DefaultWindowProc, hwnd, uMsg, wParam, lParam); + return CallWindowProc(oldWndProc, hwnd, uMsg, wParam, lParam); } VOID PhInitializeHSplitter( diff --git a/ProcessHacker/sysinfo.c b/ProcessHacker/sysinfo.c index c2fa5ecd4b6f..140af05c3af2 100644 --- a/ProcessHacker/sysinfo.c +++ b/ProcessHacker/sysinfo.c @@ -1731,17 +1731,18 @@ LRESULT CALLBACK PhSipGraphHookWndProc( ) { PPH_SYSINFO_SECTION section; + WNDPROC oldWndProc; - section = PhGetWindowContext(hwnd, 0xF); - - if (!section) + if (!(section = PhGetWindowContext(hwnd, 0xF))) return 0; + oldWndProc = section->GraphWindowProc; + switch (uMsg) { case WM_DESTROY: { - SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)section->GraphWindowProc); + SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)oldWndProc); PhRemoveWindowContext(hwnd, 0xF); } break; @@ -1879,7 +1880,7 @@ LRESULT CALLBACK PhSipGraphHookWndProc( break; } - return CallWindowProc(section->GraphWindowProc, hwnd, uMsg, wParam, lParam); + return CallWindowProc(oldWndProc, hwnd, uMsg, wParam, lParam); } LRESULT CALLBACK PhSipPanelHookWndProc( diff --git a/plugins/HardwareDevices/prpsh.c b/plugins/HardwareDevices/prpsh.c index d0d7d107b799..9da89afa7c3d 100644 --- a/plugins/HardwareDevices/prpsh.c +++ b/plugins/HardwareDevices/prpsh.c @@ -179,16 +179,19 @@ LRESULT CALLBACK PvpPropSheetWndProc( _In_ LPARAM lParam ) { - PPV_PROPSHEETCONTEXT context = PhGetWindowContext(hWnd, ULONG_MAX); + PPV_PROPSHEETCONTEXT context; + WNDPROC oldWndProc; - if (!context) + if (!(context = PhGetWindowContext(hWnd, ULONG_MAX))) return 0; + oldWndProc = context->DefaultWindowProc; + switch (uMsg) { case WM_DESTROY: { - SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)context->DefaultWindowProc); + SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)oldWndProc); PhRemoveWindowContext(hWnd, ULONG_MAX); PhSaveWindowPlacementToSetting(SETTING_NAME_DISK_POSITION, SETTING_NAME_DISK_SIZE, hWnd); @@ -224,7 +227,7 @@ LRESULT CALLBACK PvpPropSheetWndProc( break; } - return CallWindowProc(context->DefaultWindowProc, hWnd, uMsg, wParam, lParam); + return CallWindowProc(oldWndProc, hWnd, uMsg, wParam, lParam); } BOOLEAN PhpInitializePropSheetLayoutStage1( diff --git a/plugins/OnlineChecks/upload.c b/plugins/OnlineChecks/upload.c index ab421a4a79b7..a8026d87ba8c 100644 --- a/plugins/OnlineChecks/upload.c +++ b/plugins/OnlineChecks/upload.c @@ -1177,17 +1177,18 @@ LRESULT CALLBACK TaskDialogSubclassProc( ) { PUPLOAD_CONTEXT context; + WNDPROC oldWndProc; - context = PhGetWindowContext(hwndDlg, 0xF); - - if (!context) + if (!(context = PhGetWindowContext(hwndDlg, 0xF))) return 0; + oldWndProc = context->DialogWindowProc; + switch (uMsg) { case WM_DESTROY: { - SetWindowLongPtr(hwndDlg, GWLP_WNDPROC, (LONG_PTR)context->DialogWindowProc); + SetWindowLongPtr(hwndDlg, GWLP_WNDPROC, (LONG_PTR)oldWndProc); PhRemoveWindowContext(hwndDlg, 0xF); TaskDialogFreeContext(context); @@ -1246,7 +1247,7 @@ LRESULT CALLBACK TaskDialogSubclassProc( break; } - return CallWindowProc(context->DialogWindowProc, hwndDlg, uMsg, wParam, lParam); + return CallWindowProc(oldWndProc, hwndDlg, uMsg, wParam, lParam); } HRESULT CALLBACK TaskDialogBootstrapCallback( diff --git a/plugins/Updater/updater.c b/plugins/Updater/updater.c index 3b5245112115..a448b8892a31 100644 --- a/plugins/Updater/updater.c +++ b/plugins/Updater/updater.c @@ -762,16 +762,19 @@ LRESULT CALLBACK TaskDialogSubclassProc( _In_ LPARAM lParam ) { - PPH_UPDATER_CONTEXT context = PhGetWindowContext(hwndDlg, UCHAR_MAX); + PPH_UPDATER_CONTEXT context; + WNDPROC oldWndProc; - if (!context) + if (!(context = PhGetWindowContext(hwndDlg, UCHAR_MAX))) return 0; + oldWndProc = context->DefaultWindowProc; + switch (uMsg) { case WM_DESTROY: { - SetWindowLongPtr(hwndDlg, GWLP_WNDPROC, (LONG_PTR)context->DefaultWindowProc); + SetWindowLongPtr(hwndDlg, GWLP_WNDPROC, (LONG_PTR)oldWndProc); PhRemoveWindowContext(hwndDlg, UCHAR_MAX); } break; @@ -826,8 +829,8 @@ LRESULT CALLBACK TaskDialogSubclassProc( // } // break; } - - return CallWindowProc(context->DefaultWindowProc, hwndDlg, uMsg, wParam, lParam); + + return CallWindowProc(oldWndProc, hwndDlg, uMsg, wParam, lParam); } HRESULT CALLBACK TaskDialogBootstrapCallback( diff --git a/plugins/WindowExplorer/wndprp.c b/plugins/WindowExplorer/wndprp.c index 33f4a2e09380..8c6aabc94e8e 100644 --- a/plugins/WindowExplorer/wndprp.c +++ b/plugins/WindowExplorer/wndprp.c @@ -384,16 +384,16 @@ LRESULT CALLBACK WepPropSheetWndProc( _In_ LPARAM lParam ) { - WNDPROC defaultPropSheetWindowProc = PhGetWindowContext(hwnd, 0xF); + WNDPROC oldWndProc; - if (!defaultPropSheetWindowProc) + if (!(oldWndProc = PhGetWindowContext(hwnd, 0xF))) return 0; switch (uMsg) { case WM_DESTROY: { - SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)defaultPropSheetWindowProc); + SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)oldWndProc); PhRemoveWindowContext(hwnd, 0xF); if (PhGetWindowContext(hwnd, 1)) @@ -437,7 +437,7 @@ LRESULT CALLBACK WepPropSheetWndProc( break; } - return CallWindowProc(defaultPropSheetWindowProc, hwnd, uMsg, wParam, lParam); + return CallWindowProc(oldWndProc, hwnd, uMsg, wParam, lParam); } static HPROPSHEETPAGE WepCommonCreatePage( diff --git a/tools/peview/prpsh.c b/tools/peview/prpsh.c index 10842ae18765..7cda0029f125 100644 --- a/tools/peview/prpsh.c +++ b/tools/peview/prpsh.c @@ -190,11 +190,14 @@ LRESULT CALLBACK PvpPropSheetWndProc( _In_ LPARAM lParam ) { - PPV_PROPSHEETCONTEXT propSheetContext = PhGetWindowContext(hWnd, UCHAR_MAX); + PPV_PROPSHEETCONTEXT propSheetContext; + WNDPROC oldWndProc; - if (!propSheetContext) + if (!(propSheetContext = PhGetWindowContext(hWnd, UCHAR_MAX))) return 0; + oldWndProc = propSheetContext->DefaultWindowProc; + switch (uMsg) { case WM_DESTROY: @@ -223,15 +226,11 @@ LRESULT CALLBACK PvpPropSheetWndProc( break; case WM_NCDESTROY: { - LRESULT result; - - result = CallWindowProc(propSheetContext->DefaultWindowProc, hWnd, uMsg, wParam, lParam); - SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)propSheetContext->DefaultWindowProc); + SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)oldWndProc); PhRemoveWindowContext(hWnd, UCHAR_MAX); PhDeleteLayoutManager(&propSheetContext->LayoutManager); PhFree(propSheetContext); - return result; } break; case WM_COMMAND: @@ -261,7 +260,7 @@ LRESULT CALLBACK PvpPropSheetWndProc( break; } - return CallWindowProc(propSheetContext->DefaultWindowProc, hWnd, uMsg, wParam, lParam); + return CallWindowProc(oldWndProc, hWnd, uMsg, wParam, lParam); } BOOLEAN PhpInitializePropSheetLayoutStage1( From 237f5727a420ce231608490e7cf3ec5c38a95dda Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 5 Feb 2018 05:53:58 +1100 Subject: [PATCH 0769/2058] Add ProcessErrorMode wrappers --- ProcessHacker/main.c | 50 ++++++++++++++++++++++++++++--------- phlib/include/phnativeinl.h | 31 +++++++++++++++++++++++ 2 files changed, 69 insertions(+), 12 deletions(-) diff --git a/ProcessHacker/main.c b/ProcessHacker/main.c index 517b191ec328..29122e1acb4c 100644 --- a/ProcessHacker/main.c +++ b/ProcessHacker/main.c @@ -75,6 +75,10 @@ VOID PhpEnablePrivileges( VOID ); +BOOLEAN PhInitializeExceptionPolicy( + VOID + ); + BOOLEAN PhInitializeMitigationPolicy( VOID ); @@ -115,14 +119,13 @@ INT WINAPI wWinMain( HANDLE currentTokenHandle; CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE); -#ifndef DEBUG - SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX); -#endif if (!NT_SUCCESS(PhInitializePhLibEx(ULONG_MAX, Instance, 0, 0))) return 1; - if (PhInitializeMitigationPolicy()) - return 0; + if (!PhInitializeExceptionPolicy()) + return 1; + if (!PhInitializeMitigationPolicy()) + return 1; if (!PhInitializeAppSystem()) return 1; @@ -562,13 +565,27 @@ VOID PhInitializeRestartPolicy( PhClearReference(&argumentsString); } +BOOLEAN PhInitializeExceptionPolicy( + VOID + ) +{ +#ifndef DEBUG + ULONG errorMode; + + if (NT_SUCCESS(PhGetProcessErrorMode(NtCurrentProcess(), &errorMode))) + { + errorMode &= ~(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX); + PhSetProcessErrorMode(NtCurrentProcess(), errorMode); + } +#endif + return TRUE; +} + BOOLEAN PhInitializeMitigationPolicy( VOID ) { -#ifdef DEBUG - return FALSE; -#else +#ifndef DEBUG #define DEFAULT_MITIGATION_POLICY_FLAGS \ (PROCESS_CREATION_MITIGATION_POLICY_HEAP_TERMINATE_ALWAYS_ON | \ PROCESS_CREATION_MITIGATION_POLICY_BOTTOM_UP_ASLR_ALWAYS_ON | \ @@ -580,17 +597,20 @@ BOOLEAN PhInitializeMitigationPolicy( PROCESS_CREATION_MITIGATION_POLICY_IMAGE_LOAD_NO_LOW_LABEL_ALWAYS_ON) static PH_STRINGREF commandlinePart = PH_STRINGREF_INIT(L" -nomp"); - BOOLEAN success = FALSE; + BOOLEAN success = TRUE; PH_STRINGREF commandlineSr; PPH_STRING commandline = NULL; PS_SYSTEM_DLL_INIT_BLOCK (*LdrSystemDllInitBlock_I) = NULL; STARTUPINFOEX startupInfo = { sizeof(STARTUPINFOEX) }; SIZE_T attributeListLength; + if (WindowsVersion < WINDOWS_10_RS3) + return TRUE; + PhUnicodeStringToStringRef(&NtCurrentPeb()->ProcessParameters->CommandLine, &commandlineSr); if (PhEndsWithStringRef(&commandlineSr, &commandlinePart, FALSE)) - goto CleanupExit; + return TRUE; if (!(LdrSystemDllInitBlock_I = PhGetModuleProcAddress(L"ntdll.dll", "LdrSystemDllInitBlock"))) goto CleanupExit; @@ -613,7 +633,8 @@ BOOLEAN PhInitializeMitigationPolicy( goto CleanupExit; commandline = PhConcatStringRef2(&commandlineSr, &commandlinePart); - success = NT_SUCCESS(PhCreateProcessWin32Ex( + + if (NT_SUCCESS(PhCreateProcessWin32Ex( NULL, PhGetString(commandline), NULL, @@ -624,7 +645,10 @@ BOOLEAN PhInitializeMitigationPolicy( NULL, NULL, NULL - )); + ))) + { + success = FALSE; + } CleanupExit: @@ -638,6 +662,8 @@ BOOLEAN PhInitializeMitigationPolicy( } return success; +#else + return TRUE; #endif } diff --git a/phlib/include/phnativeinl.h b/phlib/include/phnativeinl.h index c3bc53598e63..cd136d9d6d49 100644 --- a/phlib/include/phnativeinl.h +++ b/phlib/include/phnativeinl.h @@ -238,6 +238,37 @@ PhGetProcessDebugObject( ); } +FORCEINLINE +NTSTATUS +PhGetProcessErrorMode( + _In_ HANDLE ProcessHandle, + _Out_ PULONG ErrorMode + ) +{ + return NtQueryInformationProcess( + ProcessHandle, + ProcessDefaultHardErrorMode, + ErrorMode, + sizeof(ULONG), + NULL + ); +} + +FORCEINLINE +NTSTATUS +PhSetProcessErrorMode( + _In_ HANDLE ProcessHandle, + _In_ ULONG ErrorMode + ) +{ + return NtSetInformationProcess( + ProcessHandle, + ProcessDefaultHardErrorMode, + &ErrorMode, + sizeof(ULONG) + ); +} + /** * Gets a process' no-execute status. * From 74c73d5d1fb4899e12d817379c005a838c4522da Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 5 Feb 2018 07:39:26 +1100 Subject: [PATCH 0770/2058] Improve dynamic dbghelp initialization --- ProcessHacker/appsup.c | 84 ------------- ProcessHacker/include/appsup.h | 14 --- ProcessHacker/include/mainwndp.h | 5 - ProcessHacker/include/phsvc.h | 5 - ProcessHacker/include/phsvcapi.h | 12 +- ProcessHacker/include/phsvccl.h | 4 - ProcessHacker/main.c | 17 +-- ProcessHacker/mainwnd.c | 28 +---- ProcessHacker/mdump.c | 5 - ProcessHacker/phsvc/clapi.c | 67 +++++------ ProcessHacker/phsvc/svcapi.c | 24 ---- phlib/include/symprv.h | 8 -- phlib/symprv.c | 201 +++++++++++++++++++++---------- tools/peview/main.c | 26 ++++ tools/peview/peprp.c | 91 -------------- 15 files changed, 209 insertions(+), 382 deletions(-) diff --git a/ProcessHacker/appsup.c b/ProcessHacker/appsup.c index b4d9388062fc..66413ad6e5cc 100644 --- a/ProcessHacker/appsup.c +++ b/ProcessHacker/appsup.c @@ -27,7 +27,6 @@ #include #include #include -#include #include #include @@ -1007,89 +1006,6 @@ VOID PhShellExecuteUserString( PhDereferenceObject(executeString); } -PPH_STRING PhFindDbghelpPath( - VOID - ) -{ - static struct - { - ULONG Folder; - PWSTR AppendPath; - } locations[] = - { -#ifdef _WIN64 - { CSIDL_PROGRAM_FILESX86, L"\\Windows Kits\\10\\Debuggers\\x64\\dbghelp.dll" }, - { CSIDL_PROGRAM_FILES, L"\\Windows Kits\\10\\Debuggers\\x64\\dbghelp.dll" }, - { CSIDL_PROGRAM_FILESX86, L"\\Windows Kits\\8.1\\Debuggers\\x64\\dbghelp.dll" }, - { CSIDL_PROGRAM_FILESX86, L"\\Windows Kits\\8.0\\Debuggers\\x64\\dbghelp.dll" }, - { CSIDL_PROGRAM_FILES, L"\\Debugging Tools for Windows (x64)\\dbghelp.dll" } -#else - { CSIDL_PROGRAM_FILES, L"\\Windows Kits\\10\\Debuggers\\x86\\dbghelp.dll" }, - { CSIDL_PROGRAM_FILES, L"\\Windows Kits\\8.1\\Debuggers\\x86\\dbghelp.dll" }, - { CSIDL_PROGRAM_FILES, L"\\Windows Kits\\8.0\\Debuggers\\x86\\dbghelp.dll" }, - { CSIDL_PROGRAM_FILES, L"\\Debugging Tools for Windows (x86)\\dbghelp.dll" } -#endif - }; - - PPH_STRING path; - ULONG i; - - for (i = 0; i < sizeof(locations) / sizeof(locations[0]); i++) - { - path = PhGetKnownLocation(locations[i].Folder, locations[i].AppendPath); - - if (path) - { - if (RtlDoesFileExists_U(path->Buffer)) - return path; - - PhDereferenceObject(path); - } - } - - return NULL; -} - -VOID PhLoadSymbolProviderDbgHelpFromPath( - _In_ PWSTR DbgHelpPath - ) -{ - HMODULE dbghelpModule; - - if (dbghelpModule = LoadLibrary(DbgHelpPath)) - { - PPH_STRING fullDbghelpPath; - ULONG indexOfFileName; - PH_STRINGREF dbghelpFolder; - PPH_STRING symsrvPath; - - fullDbghelpPath = PhGetDllFileName(dbghelpModule, &indexOfFileName); - - if (fullDbghelpPath) - { - if (indexOfFileName != 0) - { - static PH_STRINGREF symsrvString = PH_STRINGREF_INIT(L"\\symsrv.dll"); - - dbghelpFolder.Buffer = fullDbghelpPath->Buffer; - dbghelpFolder.Length = indexOfFileName * sizeof(WCHAR); - - symsrvPath = PhConcatStringRef2(&dbghelpFolder, &symsrvString); - LoadLibrary(symsrvPath->Buffer); - PhDereferenceObject(symsrvPath); - } - - PhDereferenceObject(fullDbghelpPath); - } - } - else - { - dbghelpModule = LoadLibrary(L"dbghelp.dll"); - } - - PhSymbolProviderCompleteInitialization(dbghelpModule); -} - VOID PhLoadSymbolProviderOptions( _Inout_ PPH_SYMBOL_PROVIDER SymbolProvider ) diff --git a/ProcessHacker/include/appsup.h b/ProcessHacker/include/appsup.h index 335339db4ce7..62038ebf4caf 100644 --- a/ProcessHacker/include/appsup.h +++ b/ProcessHacker/include/appsup.h @@ -159,20 +159,6 @@ PhShellExecuteUserString( _In_opt_ PWSTR ErrorMessage ); -PHAPPAPI -PPH_STRING -NTAPI -PhFindDbghelpPath( - VOID - ); - -PHAPPAPI -VOID -NTAPI -PhLoadSymbolProviderDbgHelpFromPath( - _In_ PWSTR DbgHelpPath - ); - PHAPPAPI VOID NTAPI diff --git a/ProcessHacker/include/mainwndp.h b/ProcessHacker/include/mainwndp.h index 21351beb4ae3..14f212db7e8c 100644 --- a/ProcessHacker/include/mainwndp.h +++ b/ProcessHacker/include/mainwndp.h @@ -137,11 +137,6 @@ VOID PhMwpSaveWindowState( // Misc. -VOID PhMwpSymInitHandler( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ); - VOID PhMwpUpdateLayoutPadding( VOID ); diff --git a/ProcessHacker/include/phsvc.h b/ProcessHacker/include/phsvc.h index d2f762541a4d..b35b87017bb1 100644 --- a/ProcessHacker/include/phsvc.h +++ b/ProcessHacker/include/phsvc.h @@ -225,11 +225,6 @@ NTSTATUS PhSvcApiSetServiceSecurity( _Inout_ PPHSVC_API_PAYLOAD Payload ); -NTSTATUS PhSvcApiLoadDbgHelp( - _In_ PPHSVC_CLIENT Client, - _Inout_ PPHSVC_API_PAYLOAD Payload - ); - NTSTATUS PhSvcApiWriteMiniDumpProcess( _In_ PPHSVC_CLIENT Client, _Inout_ PPHSVC_API_PAYLOAD Payload diff --git a/ProcessHacker/include/phsvcapi.h b/ProcessHacker/include/phsvcapi.h index cb9458073036..ad6c9105e80b 100644 --- a/ProcessHacker/include/phsvcapi.h +++ b/ProcessHacker/include/phsvcapi.h @@ -23,8 +23,7 @@ typedef enum _PHSVC_API_NUMBER PhSvcSendMessageApiNumber = 15, PhSvcCreateProcessIgnoreIfeoDebuggerApiNumber = 16, PhSvcSetServiceSecurityApiNumber = 17, - PhSvcLoadDbgHelpApiNumber = 18, // WOW64 compatible - PhSvcWriteMiniDumpProcessApiNumber = 19, // WOW64 compatible + PhSvcWriteMiniDumpProcessApiNumber = 18, // WOW64 compatible PhSvcMaximumApiNumber } PHSVC_API_NUMBER, *PPHSVC_API_NUMBER; @@ -241,14 +240,6 @@ typedef union _PHSVC_API_SETSERVICESECURITY } i; } PHSVC_API_SETSERVICESECURITY, *PPHSVC_API_SETSERVICESECURITY; -typedef union _PHSVC_API_LOADDBGHELP -{ - struct - { - PH_RELATIVE_STRINGREF DbgHelpPath; - } i; -} PHSVC_API_LOADDBGHELP, *PPHSVC_API_LOADDBGHELP; - typedef union _PHSVC_API_WRITEMINIDUMPPROCESS { struct @@ -285,7 +276,6 @@ typedef union _PHSVC_API_PAYLOAD PHSVC_API_POSTMESSAGE PostMessage; PHSVC_API_CREATEPROCESSIGNOREIFEODEBUGGER CreateProcessIgnoreIfeoDebugger; PHSVC_API_SETSERVICESECURITY SetServiceSecurity; - PHSVC_API_LOADDBGHELP LoadDbgHelp; PHSVC_API_WRITEMINIDUMPPROCESS WriteMiniDumpProcess; } u; }; diff --git a/ProcessHacker/include/phsvccl.h b/ProcessHacker/include/phsvccl.h index 93fe474f2cf2..94edd38987e5 100644 --- a/ProcessHacker/include/phsvccl.h +++ b/ProcessHacker/include/phsvccl.h @@ -141,10 +141,6 @@ NTSTATUS PhSvcCallSetServiceSecurity( _In_ PSECURITY_DESCRIPTOR SecurityDescriptor ); -NTSTATUS PhSvcCallLoadDbgHelp( - _In_ PWSTR DbgHelpPath - ); - NTSTATUS PhSvcCallWriteMiniDumpProcess( _In_ HANDLE ProcessHandle, _In_ HANDLE ProcessId, diff --git a/ProcessHacker/main.c b/ProcessHacker/main.c index 29122e1acb4c..e2afe98cf44e 100644 --- a/ProcessHacker/main.c +++ b/ProcessHacker/main.c @@ -83,7 +83,7 @@ BOOLEAN PhInitializeMitigationPolicy( VOID ); -VOID PhInitializeRestartPolicy( +BOOLEAN PhInitializeRestartPolicy( VOID ); @@ -126,6 +126,8 @@ INT WINAPI wWinMain( return 1; if (!PhInitializeMitigationPolicy()) return 1; + if (!PhInitializeRestartPolicy()) + return 1; if (!PhInitializeAppSystem()) return 1; @@ -313,9 +315,6 @@ INT WINAPI wWinMain( PhSetProcessPriority(NtCurrentProcess(), priorityClass); } - // Create the restart policy. - PhInitializeRestartPolicy(); - if (!PhMainWndInitialization(CmdShow)) { PhShowError(NULL, L"Unable to initialize the main window."); @@ -535,10 +534,11 @@ VOID PhInitializeFont( } } -VOID PhInitializeRestartPolicy( +BOOLEAN PhInitializeRestartPolicy( VOID ) { +#ifndef DEBUG PH_STRINGREF commandLineSr; PH_STRINGREF fileNameSr; PH_STRINGREF argumentsSr; @@ -547,7 +547,7 @@ VOID PhInitializeRestartPolicy( PhUnicodeStringToStringRef(&NtCurrentPeb()->ProcessParameters->CommandLine, &commandLineSr); if (!PhParseCommandLineFuzzy(&commandLineSr, &fileNameSr, &argumentsSr, NULL)) - return; + return FALSE; if (argumentsSr.Length) { @@ -562,7 +562,10 @@ VOID PhInitializeRestartPolicy( // MSDN: Do not include the file name in the command line. RegisterApplicationRestart(PhGetString(argumentsString), 0); - PhClearReference(&argumentsString); + if (argumentsString) + PhDereferenceObject(argumentsString); +#endif + return TRUE; } BOOLEAN PhInitializeExceptionPolicy( diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index 4dda48ddfb67..65c5e9ce78d9 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -32,7 +32,6 @@ #include #include #include -#include #include #include #include @@ -104,22 +103,17 @@ BOOLEAN PhMainWndInitialization( PH_STRING_BUILDER stringBuilder; PH_RECTANGLE windowRectangle; - if (PhGetIntegerSetting(L"FirstRun")) - { - PPH_STRING autoDbghelpPath; - - // Try to set up the dbghelp path automatically if this is the first run. - if (autoDbghelpPath = PH_AUTO(PhFindDbghelpPath())) - PhSetStringSetting2(L"DbgHelpPath", &autoDbghelpPath->sr); + // Set FirstRun default settings. + if (PhGetIntegerSetting(L"FirstRun")) PhSetIntegerSetting(L"FirstRun", FALSE); - } - // This was added to be able to delay-load dbghelp.dll and symsrv.dll. - PhRegisterCallback(&PhSymInitCallback, PhMwpSymInitHandler, NULL, &SymInitRegistration); + // Initialize the main providers. PhMwpInitializeProviders(); + // Initialize the window. + if ((windowAtom = PhMwpInitializeWindowClass()) == INVALID_ATOM) return FALSE; @@ -2214,18 +2208,6 @@ VOID PhMwpSaveWindowState( PhSetIntegerSetting(L"MainWindowState", SW_MAXIMIZE); } -VOID PhMwpSymInitHandler( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - PPH_STRING dbghelpPath; - - dbghelpPath = PhGetStringSetting(L"DbgHelpPath"); - PhLoadSymbolProviderDbgHelpFromPath(dbghelpPath->Buffer); - PhDereferenceObject(dbghelpPath); -} - VOID PhMwpUpdateLayoutPadding( VOID ) diff --git a/ProcessHacker/mdump.c b/ProcessHacker/mdump.c index f923a0f01ee4..549b549bbba5 100644 --- a/ProcessHacker/mdump.c +++ b/ProcessHacker/mdump.c @@ -234,11 +234,6 @@ NTSTATUS PhpProcessMiniDumpThreadStart( if (PhUiConnectToPhSvcEx(NULL, Wow64PhSvcMode, FALSE)) { NTSTATUS status; - PPH_STRING dbgHelpPath; - - dbgHelpPath = PhGetStringSetting(L"DbgHelpPath"); - PhSvcCallLoadDbgHelp(dbgHelpPath->Buffer); - PhDereferenceObject(dbgHelpPath); if (NT_SUCCESS(status = PhSvcCallWriteMiniDumpProcess( context->ProcessHandle, diff --git a/ProcessHacker/phsvc/clapi.c b/ProcessHacker/phsvc/clapi.c index 8863149b2333..8afb38cf4cad 100644 --- a/ProcessHacker/phsvc/clapi.c +++ b/ProcessHacker/phsvc/clapi.c @@ -1128,33 +1128,6 @@ NTSTATUS PhSvcCallSetServiceSecurity( return status; } -NTSTATUS PhSvcCallLoadDbgHelp( - _In_ PWSTR DbgHelpPath - ) -{ - NTSTATUS status; - PHSVC_API_MSG m; - PVOID dbgHelpPath = NULL; - - memset(&m, 0, sizeof(PHSVC_API_MSG)); - - if (!PhSvcClPortHandle) - return STATUS_PORT_DISCONNECTED; - - m.p.ApiNumber = PhSvcLoadDbgHelpApiNumber; - dbgHelpPath = PhSvcpCreateString(DbgHelpPath, -1, &m.p.u.LoadDbgHelp.i.DbgHelpPath); - - if (!dbgHelpPath) - return STATUS_NO_MEMORY; - - status = PhSvcpCallServer(&m); - - if (dbgHelpPath) - PhSvcpFreeHeap(dbgHelpPath); - - return status; -} - NTSTATUS PhSvcCallWriteMiniDumpProcess( _In_ HANDLE ProcessHandle, _In_ HANDLE ProcessId, @@ -1178,22 +1151,40 @@ NTSTATUS PhSvcCallWriteMiniDumpProcess( m.p.ApiNumber = PhSvcWriteMiniDumpProcessApiNumber; - if (!NT_SUCCESS(status = PhOpenProcess(&serverHandle, PROCESS_DUP_HANDLE, PhSvcClServerProcessId))) - { + status = PhOpenProcess( + &serverHandle, + PROCESS_DUP_HANDLE, + PhSvcClServerProcessId + ); + + if (!NT_SUCCESS(status)) goto CleanupExit; - } - if (!NT_SUCCESS(status = NtDuplicateObject(NtCurrentProcess(), ProcessHandle, serverHandle, &remoteProcessHandle, - PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, 0, 0))) - { + status = NtDuplicateObject( + NtCurrentProcess(), + ProcessHandle, + serverHandle, + &remoteProcessHandle, + PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, + 0, + 0 + ); + + if (!NT_SUCCESS(status)) goto CleanupExit; - } - if (!NT_SUCCESS(status = NtDuplicateObject(NtCurrentProcess(), FileHandle, serverHandle, &remoteFileHandle, - FILE_GENERIC_WRITE, 0, 0))) - { + status = NtDuplicateObject( + NtCurrentProcess(), + FileHandle, + serverHandle, + &remoteFileHandle, + FILE_GENERIC_WRITE, + 0, + 0 + ); + + if (!NT_SUCCESS(status)) goto CleanupExit; - } m.p.u.WriteMiniDumpProcess.i.LocalProcessHandle = HandleToUlong(remoteProcessHandle); m.p.u.WriteMiniDumpProcess.i.ProcessId = HandleToUlong(ProcessId); diff --git a/ProcessHacker/phsvc/svcapi.c b/ProcessHacker/phsvc/svcapi.c index 9f8ded087e2e..dda20bdde1a8 100644 --- a/ProcessHacker/phsvc/svcapi.c +++ b/ProcessHacker/phsvc/svcapi.c @@ -63,7 +63,6 @@ PPHSVC_API_PROCEDURE PhSvcApiCallTable[] = PhSvcApiSendMessage, PhSvcApiCreateProcessIgnoreIfeoDebugger, PhSvcApiSetServiceSecurity, - PhSvcApiLoadDbgHelp, PhSvcApiWriteMiniDumpProcess }; C_ASSERT(sizeof(PhSvcApiCallTable) / sizeof(PPHSVC_API_PROCEDURE) == PhSvcMaximumApiNumber - 1); @@ -1392,29 +1391,6 @@ NTSTATUS PhSvcApiSetServiceSecurity( return status; } -NTSTATUS PhSvcApiLoadDbgHelp( - _In_ PPHSVC_CLIENT Client, - _Inout_ PPHSVC_API_PAYLOAD Payload - ) -{ - static BOOLEAN alreadyLoaded; - - NTSTATUS status; - PPH_STRING dbgHelpPath; - - if (alreadyLoaded) - return STATUS_SOME_NOT_MAPPED; - - if (NT_SUCCESS(status = PhSvcCaptureString(&Payload->u.LoadDbgHelp.i.DbgHelpPath, FALSE, &dbgHelpPath))) - { - PH_AUTO(dbgHelpPath); - PhLoadSymbolProviderDbgHelpFromPath(dbgHelpPath->Buffer); - alreadyLoaded = TRUE; - } - - return status; -} - NTSTATUS PhSvcApiWriteMiniDumpProcess( _In_ PPHSVC_CLIENT Client, _Inout_ PPHSVC_API_PAYLOAD Payload diff --git a/phlib/include/symprv.h b/phlib/include/symprv.h index f0a83df00d5d..dfa8a2900bd5 100644 --- a/phlib/include/symprv.h +++ b/phlib/include/symprv.h @@ -6,7 +6,6 @@ extern "C" { #endif extern PPH_OBJECT_TYPE PhSymbolProviderType; -extern PH_CALLBACK PhSymInitCallback; #define PH_MAX_SYMBOL_NAME_LEN 128 @@ -72,13 +71,6 @@ PhSymbolProviderInitialization( VOID ); -PHLIBAPI -VOID -NTAPI -PhSymbolProviderCompleteInitialization( - _In_opt_ PVOID DbgHelpBase - ); - PHLIBAPI PPH_SYMBOL_PROVIDER NTAPI diff --git a/phlib/symprv.c b/phlib/symprv.c index 04bb84099eec..93f32b500d35 100644 --- a/phlib/symprv.c +++ b/phlib/symprv.c @@ -3,6 +3,7 @@ * symbol provider * * Copyright (C) 2010-2015 wj32 + * Copyright (C) 2017-2018 dmex * * This file is part of Process Hacker. * @@ -24,6 +25,7 @@ #include #include +#include #include #include @@ -60,13 +62,9 @@ LONG NTAPI PhpSymbolModuleCompareFunction( ); PPH_OBJECT_TYPE PhSymbolProviderType; - static PH_INITONCE PhSymInitOnce = PH_INITONCE_INIT; -DECLSPEC_SELECTANY PH_CALLBACK_DECLARE(PhSymInitCallback); - static HANDLE PhNextFakeHandle = (HANDLE)0; static PH_FAST_LOCK PhSymMutex = PH_FAST_LOCK_INIT; - #define PH_LOCK_SYMBOLS() PhAcquireFastLockExclusive(&PhSymMutex) #define PH_UNLOCK_SYMBOLS() PhReleaseFastLockExclusive(&PhSymMutex) @@ -108,64 +106,6 @@ BOOLEAN PhSymbolProviderInitialization( return TRUE; } -VOID PhSymbolProviderCompleteInitialization( - _In_opt_ PVOID DbgHelpBase - ) -{ - PVOID dbghelpHandle; - PVOID symsrvHandle; - - // The user should have loaded dbghelp.dll and symsrv.dll already. If not, it's not our problem. - - // The Unicode versions aren't available in dbghelp.dll 5.1, so we fallback on the ANSI versions. - - if (DbgHelpBase) - dbghelpHandle = DbgHelpBase; - else - dbghelpHandle = PhGetDllHandle(L"dbghelp.dll"); - - symsrvHandle = PhGetDllHandle(L"symsrv.dll"); - - SymInitialize_I = PhGetProcedureAddress(dbghelpHandle, "SymInitialize", 0); - SymCleanup_I = PhGetProcedureAddress(dbghelpHandle, "SymCleanup", 0); - if (!(SymEnumSymbolsW_I = PhGetProcedureAddress(dbghelpHandle, "SymEnumSymbolsW", 0))) - SymEnumSymbols_I = PhGetProcedureAddress(dbghelpHandle, "SymEnumSymbols", 0); - if (!(SymFromAddrW_I = PhGetProcedureAddress(dbghelpHandle, "SymFromAddrW", 0))) - SymFromAddr_I = PhGetProcedureAddress(dbghelpHandle, "SymFromAddr", 0); - if (!(SymFromNameW_I = PhGetProcedureAddress(dbghelpHandle, "SymFromNameW", 0))) - SymFromName_I = PhGetProcedureAddress(dbghelpHandle, "SymFromName", 0); - if (!(SymGetLineFromAddrW64_I = PhGetProcedureAddress(dbghelpHandle, "SymGetLineFromAddrW64", 0))) - SymGetLineFromAddr64_I = PhGetProcedureAddress(dbghelpHandle, "SymGetLineFromAddr64", 0); - if (!(SymLoadModuleExW_I = PhGetProcedureAddress(dbghelpHandle, "SymLoadModuleExW", 0))) - SymLoadModule64_I = PhGetProcedureAddress(dbghelpHandle, "SymLoadModule64", 0); - SymGetOptions_I = PhGetProcedureAddress(dbghelpHandle, "SymGetOptions", 0); - SymSetOptions_I = PhGetProcedureAddress(dbghelpHandle, "SymSetOptions", 0); - if (!(SymGetSearchPathW_I = PhGetProcedureAddress(dbghelpHandle, "SymGetSearchPathW", 0))) - SymGetSearchPath_I = PhGetProcedureAddress(dbghelpHandle, "SymGetSearchPath", 0); - if (!(SymSetSearchPathW_I = PhGetProcedureAddress(dbghelpHandle, "SymSetSearchPathW", 0))) - SymSetSearchPath_I = PhGetProcedureAddress(dbghelpHandle, "SymSetSearchPath", 0); - SymUnloadModule64_I = PhGetProcedureAddress(dbghelpHandle, "SymUnloadModule64", 0); - SymFunctionTableAccess64_I = PhGetProcedureAddress(dbghelpHandle, "SymFunctionTableAccess64", 0); - SymGetModuleBase64_I = PhGetProcedureAddress(dbghelpHandle, "SymGetModuleBase64", 0); - SymRegisterCallbackW64_I = PhGetProcedureAddress(dbghelpHandle, "SymRegisterCallbackW64", 0); - StackWalk64_I = PhGetProcedureAddress(dbghelpHandle, "StackWalk64", 0); - MiniDumpWriteDump_I = PhGetProcedureAddress(dbghelpHandle, "MiniDumpWriteDump", 0); - SymbolServerGetOptions = PhGetProcedureAddress(symsrvHandle, "SymbolServerGetOptions", 0); - SymbolServerSetOptions = PhGetProcedureAddress(symsrvHandle, "SymbolServerSetOptions", 0); - UnDecorateSymbolName_I = PhGetProcedureAddress(dbghelpHandle, "UnDecorateSymbolName", 0); - UnDecorateSymbolNameW_I = PhGetProcedureAddress(dbghelpHandle, "UnDecorateSymbolNameW", 0); - - if (SymGetOptions_I && SymSetOptions_I) - { - SymSetOptions_I( - SymGetOptions_I() | - SYMOPT_AUTO_PUBLICS | SYMOPT_CASE_INSENSITIVE | SYMOPT_DEFERRED_LOADS | - SYMOPT_FAIL_CRITICAL_ERRORS | SYMOPT_INCLUDE_32BIT_MODULES | - SYMOPT_LOAD_LINES | SYMOPT_OMAP_FIND_NEAREST | SYMOPT_UNDNAME - ); - } -} - PPH_SYMBOL_PROVIDER PhCreateSymbolProvider( _In_opt_ HANDLE ProcessId ) @@ -309,13 +249,148 @@ BOOL CALLBACK PhpSymbolCallbackFunction( return FALSE; } +VOID PhpSymbolProviderCompleteInitialization( + VOID + ) +{ + static struct + { + ULONG Folder; + PWSTR AppendPath; + } locations[] = + { +#ifdef _WIN64 + { CSIDL_PROGRAM_FILESX86, L"\\Windows Kits\\10\\Debuggers\\x64\\dbghelp.dll" }, + { CSIDL_PROGRAM_FILES, L"\\Windows Kits\\10\\Debuggers\\x64\\dbghelp.dll" }, + { CSIDL_PROGRAM_FILESX86, L"\\Windows Kits\\8.1\\Debuggers\\x64\\dbghelp.dll" }, + { CSIDL_PROGRAM_FILESX86, L"\\Windows Kits\\8.0\\Debuggers\\x64\\dbghelp.dll" }, + { CSIDL_PROGRAM_FILES, L"\\Debugging Tools for Windows (x64)\\dbghelp.dll" } +#else + { CSIDL_PROGRAM_FILES, L"\\Windows Kits\\10\\Debuggers\\x86\\dbghelp.dll" }, + { CSIDL_PROGRAM_FILES, L"\\Windows Kits\\8.1\\Debuggers\\x86\\dbghelp.dll" }, + { CSIDL_PROGRAM_FILES, L"\\Windows Kits\\8.0\\Debuggers\\x86\\dbghelp.dll" }, + { CSIDL_PROGRAM_FILES, L"\\Debugging Tools for Windows (x86)\\dbghelp.dll" } +#endif + }; + + PVOID dbghelpHandle; + PVOID symsrvHandle; + PPH_STRING dbghelpPath = NULL; + + dbghelpHandle = PhGetDllHandle(L"dbghelp.dll"); + symsrvHandle = PhGetDllHandle(L"symsrv.dll"); + + if (dbghelpHandle && symsrvHandle) + return; + + for (ULONG i = 0; i < ARRAYSIZE(locations); i++) + { + if (dbghelpPath = PhGetKnownLocation(locations[i].Folder, locations[i].AppendPath)) + { + if (RtlDoesFileExists_U(dbghelpPath->Buffer)) + break; + + PhClearReference(&dbghelpPath); + } + } + + if (dbghelpPath) + { + if (dbghelpHandle = LoadLibrary(dbghelpPath->Buffer)) + { + PPH_STRING fullDbghelpPath; + ULONG indexOfFileName; + PH_STRINGREF dbghelpFolder; + PPH_STRING symsrvPath; + + if (fullDbghelpPath = PhGetDllFileName(dbghelpHandle, &indexOfFileName)) + { + if (indexOfFileName != 0) + { + static PH_STRINGREF symsrvString = PH_STRINGREF_INIT(L"\\symsrv.dll"); + + dbghelpFolder.Buffer = fullDbghelpPath->Buffer; + dbghelpFolder.Length = indexOfFileName * sizeof(WCHAR); + + symsrvPath = PhConcatStringRef2(&dbghelpFolder, &symsrvString); + symsrvHandle = LoadLibrary(symsrvPath->Buffer); + PhDereferenceObject(symsrvPath); + } + + PhDereferenceObject(fullDbghelpPath); + } + } + + PhDereferenceObject(dbghelpPath); + } + + if (!dbghelpHandle) + dbghelpHandle = LoadLibrary(L"dbghelp.dll"); + + if (!symsrvHandle) + symsrvHandle = LoadLibrary(L"symsrv.dll"); + + if (dbghelpHandle) + { + // The Unicode versions aren't available in dbghelp.dll 5.1, so we fallback on the ANSI versions. + + SymInitialize_I = PhGetProcedureAddress(dbghelpHandle, "SymInitialize", 0); + SymCleanup_I = PhGetProcedureAddress(dbghelpHandle, "SymCleanup", 0); + if (!(SymEnumSymbolsW_I = PhGetProcedureAddress(dbghelpHandle, "SymEnumSymbolsW", 0))) + SymEnumSymbols_I = PhGetProcedureAddress(dbghelpHandle, "SymEnumSymbols", 0); + if (!(SymFromAddrW_I = PhGetProcedureAddress(dbghelpHandle, "SymFromAddrW", 0))) + SymFromAddr_I = PhGetProcedureAddress(dbghelpHandle, "SymFromAddr", 0); + if (!(SymFromNameW_I = PhGetProcedureAddress(dbghelpHandle, "SymFromNameW", 0))) + SymFromName_I = PhGetProcedureAddress(dbghelpHandle, "SymFromName", 0); + if (!(SymGetLineFromAddrW64_I = PhGetProcedureAddress(dbghelpHandle, "SymGetLineFromAddrW64", 0))) + SymGetLineFromAddr64_I = PhGetProcedureAddress(dbghelpHandle, "SymGetLineFromAddr64", 0); + if (!(SymLoadModuleExW_I = PhGetProcedureAddress(dbghelpHandle, "SymLoadModuleExW", 0))) + SymLoadModule64_I = PhGetProcedureAddress(dbghelpHandle, "SymLoadModule64", 0); + SymGetOptions_I = PhGetProcedureAddress(dbghelpHandle, "SymGetOptions", 0); + SymSetOptions_I = PhGetProcedureAddress(dbghelpHandle, "SymSetOptions", 0); + if (!(SymGetSearchPathW_I = PhGetProcedureAddress(dbghelpHandle, "SymGetSearchPathW", 0))) + SymGetSearchPath_I = PhGetProcedureAddress(dbghelpHandle, "SymGetSearchPath", 0); + if (!(SymSetSearchPathW_I = PhGetProcedureAddress(dbghelpHandle, "SymSetSearchPathW", 0))) + SymSetSearchPath_I = PhGetProcedureAddress(dbghelpHandle, "SymSetSearchPath", 0); + SymUnloadModule64_I = PhGetProcedureAddress(dbghelpHandle, "SymUnloadModule64", 0); + SymFunctionTableAccess64_I = PhGetProcedureAddress(dbghelpHandle, "SymFunctionTableAccess64", 0); + SymGetModuleBase64_I = PhGetProcedureAddress(dbghelpHandle, "SymGetModuleBase64", 0); + SymRegisterCallbackW64_I = PhGetProcedureAddress(dbghelpHandle, "SymRegisterCallbackW64", 0); + StackWalk64_I = PhGetProcedureAddress(dbghelpHandle, "StackWalk64", 0); + MiniDumpWriteDump_I = PhGetProcedureAddress(dbghelpHandle, "MiniDumpWriteDump", 0); + UnDecorateSymbolName_I = PhGetProcedureAddress(dbghelpHandle, "UnDecorateSymbolName", 0); + UnDecorateSymbolNameW_I = PhGetProcedureAddress(dbghelpHandle, "UnDecorateSymbolNameW", 0); + } + + if (symsrvHandle) + { + SymbolServerGetOptions = PhGetProcedureAddress(symsrvHandle, "SymbolServerGetOptions", 0); + SymbolServerSetOptions = PhGetProcedureAddress(symsrvHandle, "SymbolServerSetOptions", 0); + } +} + VOID PhpRegisterSymbolProvider( _In_opt_ PPH_SYMBOL_PROVIDER SymbolProvider ) { if (PhBeginInitOnce(&PhSymInitOnce)) { - PhInvokeCallback(&PhSymInitCallback, NULL); + PhpSymbolProviderCompleteInitialization(); + + if (SymGetOptions_I && SymSetOptions_I) + { + PH_LOCK_SYMBOLS(); + + SymSetOptions_I( + SymGetOptions_I() | + SYMOPT_AUTO_PUBLICS | SYMOPT_CASE_INSENSITIVE | SYMOPT_DEFERRED_LOADS | + SYMOPT_FAIL_CRITICAL_ERRORS | SYMOPT_INCLUDE_32BIT_MODULES | + SYMOPT_LOAD_LINES | SYMOPT_OMAP_FIND_NEAREST | SYMOPT_UNDNAME + ); + + PH_UNLOCK_SYMBOLS(); + } + PhEndInitOnce(&PhSymInitOnce); } diff --git a/tools/peview/main.c b/tools/peview/main.c index a0a3e54ef6a5..73988a910c25 100644 --- a/tools/peview/main.c +++ b/tools/peview/main.c @@ -55,6 +55,32 @@ INT WINAPI wWinMain( if (!NT_SUCCESS(PhInitializePhLib())) return 1; + // Create a mutant for the installer. + { + HANDLE mutantHandle; + OBJECT_ATTRIBUTES oa; + UNICODE_STRING mutantName; + PPH_STRING objectName; + PH_FORMAT format[2]; + + PhInitFormatS(&format[0], L"PeViewer_"); + PhInitFormatU(&format[1], HandleToUlong(NtCurrentProcessId())); + + objectName = PhFormat(format, 2, 16); + PhStringRefToUnicodeString(&objectName->sr, &mutantName); + + InitializeObjectAttributes( + &oa, + &mutantName, + OBJ_CASE_INSENSITIVE, + PhGetNamespaceHandle(), + NULL + ); + + NtCreateMutant(&mutantHandle, MUTANT_ALL_ACCESS, &oa, FALSE); + PhDereferenceObject(objectName); + } + PhGuiSupportInitialization(); PhSettingsInitialization(); PeInitializeSettings(); diff --git a/tools/peview/peprp.c b/tools/peview/peprp.c index 265271a3a3ce..b448a5938bc6 100644 --- a/tools/peview/peprp.c +++ b/tools/peview/peprp.c @@ -655,98 +655,12 @@ INT_PTR CALLBACK PvpPeGeneralDlgProc( return FALSE; } -VOID PvpLoadDbgHelpFromPath( - _In_ PWSTR DbgHelpPath - ) -{ - HMODULE dbghelpModule; - - if (DbgHelpPath && (dbghelpModule = LoadLibrary(DbgHelpPath))) - { - PPH_STRING fullDbghelpPath; - ULONG indexOfFileName; - PH_STRINGREF dbghelpFolder; - PPH_STRING symsrvPath; - - fullDbghelpPath = PhGetDllFileName(dbghelpModule, &indexOfFileName); - - if (fullDbghelpPath) - { - if (indexOfFileName != 0) - { - static PH_STRINGREF symsrvString = PH_STRINGREF_INIT(L"\\symsrv.dll"); - - dbghelpFolder.Buffer = fullDbghelpPath->Buffer; - dbghelpFolder.Length = indexOfFileName * sizeof(WCHAR); - - symsrvPath = PhConcatStringRef2(&dbghelpFolder, &symsrvString); - - LoadLibrary(symsrvPath->Buffer); - - PhDereferenceObject(symsrvPath); - } - - PhDereferenceObject(fullDbghelpPath); - } - } - else - { - dbghelpModule = LoadLibrary(L"dbghelp.dll"); - } - - PhSymbolProviderCompleteInitialization(dbghelpModule); -} - -PPH_STRING PhFindDbghelpPath( - VOID - ) -{ - static struct - { - ULONG Folder; - PWSTR AppendPath; - } locations[] = - { -#ifdef _WIN64 - { CSIDL_PROGRAM_FILESX86, L"\\Windows Kits\\10\\Debuggers\\x64\\dbghelp.dll" }, - { CSIDL_PROGRAM_FILESX86, L"\\Windows Kits\\8.1\\Debuggers\\x64\\dbghelp.dll" }, - { CSIDL_PROGRAM_FILESX86, L"\\Windows Kits\\8.0\\Debuggers\\x64\\dbghelp.dll" }, - { CSIDL_PROGRAM_FILES, L"\\Debugging Tools for Windows (x64)\\dbghelp.dll" } -#else - { CSIDL_PROGRAM_FILES, L"\\Windows Kits\\10\\Debuggers\\x86\\dbghelp.dll" }, - { CSIDL_PROGRAM_FILES, L"\\Windows Kits\\8.1\\Debuggers\\x86\\dbghelp.dll" }, - { CSIDL_PROGRAM_FILES, L"\\Windows Kits\\8.0\\Debuggers\\x86\\dbghelp.dll" }, - { CSIDL_PROGRAM_FILES, L"\\Debugging Tools for Windows (x86)\\dbghelp.dll" } -#endif - }; - - PPH_STRING path; - ULONG i; - - for (i = 0; i < sizeof(locations) / sizeof(locations[0]); i++) - { - path = PhGetKnownLocation(locations[i].Folder, locations[i].AppendPath); - - if (path) - { - if (RtlDoesFileExists_U(path->Buffer)) - return path; - - PhDereferenceObject(path); - } - } - - return NULL; -} - - BOOLEAN PvpLoadDbgHelp( _Inout_ PPH_SYMBOL_PROVIDER *SymbolProvider ) { static UNICODE_STRING symbolPathVarName = RTL_CONSTANT_STRING(L"_NT_SYMBOL_PATH"); PPH_STRING symbolSearchPath; - PPH_STRING dbgHelpPath; PPH_SYMBOL_PROVIDER symbolProvider; UNICODE_STRING symbolPathUs; WCHAR buffer[512]; @@ -756,8 +670,6 @@ BOOLEAN PvpLoadDbgHelp( if (!PhSymbolProviderInitialization()) return FALSE; - dbgHelpPath = PhFindDbghelpPath(); - PvpLoadDbgHelpFromPath(PhGetString(dbgHelpPath)); symbolProvider = PhCreateSymbolProvider(NULL); // Load symbol path from _NT_SYMBOL_PATH if configured by the user. @@ -774,9 +686,6 @@ BOOLEAN PvpLoadDbgHelp( PhSetSearchPathSymbolProvider(symbolProvider, symbolSearchPath->Buffer); PhDereferenceObject(symbolSearchPath); - if (dbgHelpPath) - PhDereferenceObject(dbgHelpPath); - *SymbolProvider = symbolProvider; return TRUE; } \ No newline at end of file From 5ed252623ff7c398baa745c7da03194b6d6ed069 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 5 Feb 2018 09:25:41 +1100 Subject: [PATCH 0771/2058] BuildTools: Update build log format --- tools/CustomBuildTool/Source Files/Build.cs | 7 ++++--- tools/CustomBuildTool/Source Files/Program.cs | 6 +++--- .../bin/Release/CustomBuildTool.exe | Bin 163840 -> 163840 bytes .../bin/Release/CustomBuildTool.pdb | Bin 75264 -> 75264 bytes 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/tools/CustomBuildTool/Source Files/Build.cs b/tools/CustomBuildTool/Source Files/Build.cs index 27cda72084db..c30c120f55fd 100644 --- a/tools/CustomBuildTool/Source Files/Build.cs +++ b/tools/CustomBuildTool/Source Files/Build.cs @@ -278,14 +278,15 @@ public static void ShowBuildEnvironment(string Platform, bool ShowBuildInfo, boo Program.PrintColorMessage(BuildVersion, ConsoleColor.Green, false); Program.PrintColorMessage(" (", ConsoleColor.DarkGray, false); Program.PrintColorMessage(BuildCommit.Substring(0, 8), ConsoleColor.DarkYellow, false); - Program.PrintColorMessage(")" + Environment.NewLine, ConsoleColor.DarkGray, true); + Program.PrintColorMessage(")", ConsoleColor.DarkGray, false); + Program.PrintColorMessage(Environment.NewLine, ConsoleColor.DarkGray, true); if (!BuildNightly && ShowLogInfo && File.Exists(GitExePath)) { Win32.GetConsoleMode(Win32.GetStdHandle(Win32.STD_OUTPUT_HANDLE), out ConsoleMode mode); Win32.SetConsoleMode(Win32.GetStdHandle(Win32.STD_OUTPUT_HANDLE), mode | ConsoleMode.ENABLE_VIRTUAL_TERMINAL_PROCESSING); - BuildMessage = Win32.ShellExecute(GitExePath, "log -n 5 --date=format:%Y-%m-%d --pretty=format:\"%C(green)[%cd]%Creset %C(bold blue)%an%Creset %<(65,trunc)%s%Creset (%C(yellow)%h%Creset)\" --abbrev-commit"); + BuildMessage = Win32.ShellExecute(GitExePath, "log -n 5 --date=format:%Y-%m-%d --pretty=format:\"%C(green)[%cd]%Creset %C(bold blue)%an%Creset %<(65,trunc)%s%Creset %C(#696969)(%Creset%C(yellow)%h%Creset%C(#696969))%Creset\" --abbrev-commit"); Console.WriteLine(BuildMessage + Environment.NewLine); //BuildMessage = Win32.ShellExecute(GitExePath, "log -n 5 --date=format:%Y-%m-%d --pretty=format:\"[%cd] %an %s\" --abbrev-commit"); @@ -377,7 +378,7 @@ public static bool CopyLibFiles(BuildFlags Flags) public static bool CopyWow64Files(BuildFlags Flags) { - Program.PrintColorMessage("Copying Wow64 support files...", ConsoleColor.Cyan); + //Program.PrintColorMessage("Copying Wow64 support files...", ConsoleColor.Cyan); try { diff --git a/tools/CustomBuildTool/Source Files/Program.cs b/tools/CustomBuildTool/Source Files/Program.cs index 82d1f4f7d1bb..2d089279e9e2 100644 --- a/tools/CustomBuildTool/Source Files/Program.cs +++ b/tools/CustomBuildTool/Source Files/Program.cs @@ -32,7 +32,7 @@ public static class Program private static bool BuildSdk(BuildFlags Flags) { - PrintColorMessage("Copying Plugin SDK...", ConsoleColor.Cyan); + //PrintColorMessage("Copying Plugin SDK...", ConsoleColor.Cyan); if (!Build.CopyTextFiles()) return false; @@ -228,8 +228,8 @@ public static void Main(string[] args) return; //if (!Build.BuildWebSetupExe()) // return; - if (!Build.BuildPdbZip()) - return; + //if (!Build.BuildPdbZip()) + // return; if (!Build.BuildSetupExe()) return; if (!Build.BuildChecksumsFile()) diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe b/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe index 2b5fcdef709a14d4ced37d19ebf0522d453cb0d1..fd6f7537e90a034be99c58d475746b45ed3e9764 100644 GIT binary patch delta 8733 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 diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb b/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb index 74e8fe35eb15763cc893ebd651eae19c1e9eb5d5..e9427627252d9655f9e3aaba42f6942b4d5b35f8 100644 GIT binary patch delta 9824 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 From d304fcdd0416c144af4b44c1fbcd3d319c0c69fa Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 5 Feb 2018 10:35:04 +1100 Subject: [PATCH 0772/2058] Update process token tab layout --- ProcessHacker/ProcessHacker.rc | 16 +- ProcessHacker/resource.h | 2 - ProcessHacker/tokprp.c | 337 +++++++++++++++++++++------------ 3 files changed, 216 insertions(+), 139 deletions(-) diff --git a/ProcessHacker/ProcessHacker.rc b/ProcessHacker/ProcessHacker.rc index b3f3f753654d..030c715f4038 100644 --- a/ProcessHacker/ProcessHacker.rc +++ b/ProcessHacker/ProcessHacker.rc @@ -328,18 +328,6 @@ BEGIN END END -IDR_PRIVILEGE MENU -BEGIN - POPUP "Privilege" - BEGIN - MENUITEM "&Enable", ID_PRIVILEGE_ENABLE - MENUITEM "&Disable", ID_PRIVILEGE_DISABLE - MENUITEM "&Remove", ID_PRIVILEGE_REMOVE - MENUITEM SEPARATOR - MENUITEM "&Copy\aCtrl+C", ID_PRIVILEGE_COPY - END -END - IDR_FINDOBJ MENU BEGIN POPUP "Object" @@ -737,9 +725,7 @@ BEGIN LTEXT "Unknown",IDC_VIRTUALIZED,209,29,44,8 LTEXT "App container SID:",IDC_STATIC,7,40,62,8 EDITTEXT IDC_APPCONTAINERSID,75,40,178,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER - CONTROL "",IDC_GROUPS,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,53,246,112 - CONTROL "",IDC_PRIVILEGES,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,168,246,57 - LTEXT "To view capabilities, claims and other attributes, click Advanced.",IDC_INSTRUCTION,7,228,206,8 + CONTROL "",IDC_GROUPS,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,53,246,183 PUSHBUTTON "Integrity",IDC_INTEGRITY,149,239,50,14 PUSHBUTTON "Advanced",IDC_ADVANCED,203,239,50,14 END diff --git a/ProcessHacker/resource.h b/ProcessHacker/resource.h index 80e0ffeb0da9..8727dc0e5325 100644 --- a/ProcessHacker/resource.h +++ b/ProcessHacker/resource.h @@ -39,7 +39,6 @@ #define IDD_FINDOBJECTS 130 #define IDD_OBJTOKEN 131 #define ID_PLUGIN_MENU_ITEM 131 -#define IDR_PRIVILEGE 133 #define IDC_SEPARATOR 133 #define IDR_FINDOBJ 134 #define IDD_HIDDENPROCESSES 135 @@ -188,7 +187,6 @@ #define IDC_OWNER 1054 #define IDC_GROUPS 1055 #define IDC_PRIMARYGROUP 1055 -#define IDC_PRIVILEGES 1056 #define IDC_VIRTUALIZATION 1056 #define IDC_SESSIONID 1057 #define IDC_ELEVATED 1058 diff --git a/ProcessHacker/tokprp.c b/ProcessHacker/tokprp.c index 85de914d2542..05b19f7160e3 100644 --- a/ProcessHacker/tokprp.c +++ b/ProcessHacker/tokprp.c @@ -32,6 +32,29 @@ #include #include +typedef enum _PH_PROCESS_TOKEN_CATEGORY +{ + PH_PROCESS_TOKEN_CATEGORY_PRIVILEGES, + PH_PROCESS_TOKEN_CATEGORY_GROUPS +} PH_PROCESS_TOKEN_CATEGORY; + +typedef enum _PH_PROCESS_TOKEN_INDEX +{ + PH_PROCESS_TOKEN_INDEX_NAME, + PH_PROCESS_TOKEN_INDEX_STATUS, + PH_PROCESS_TOKEN_INDEX_DESCRIPTION, +} PH_PROCESS_TOKEN_INDEX; + +typedef struct _PHP_TOKEN_PAGE_LISTVIEW_ITEM +{ + BOOLEAN IsTokenGroupEntry; + union + { + PSID_AND_ATTRIBUTES TokenGroup; + PLUID_AND_ATTRIBUTES TokenPrivilege; + }; +} PHP_TOKEN_PAGE_LISTVIEW_ITEM, *PPHP_TOKEN_PAGE_LISTVIEW_ITEM; + typedef struct _ATTRIBUTE_NODE { PH_TREENEW_NODE Node; @@ -51,8 +74,8 @@ typedef struct _TOKEN_PAGE_CONTEXT PVOID Context; DLGPROC HookProc; - HWND GroupsListViewHandle; - HWND PrivilegesListViewHandle; + HWND ListViewHandle; + HIMAGELIST ListViewImageList; PTOKEN_GROUPS Groups; PTOKEN_GROUPS RestrictedSids; @@ -285,15 +308,30 @@ COLORREF PhGetGroupAttributesColor( return RGB(0xf0, 0xe0, 0xe0); } +COLORREF PhGetPrivilegeAttributesColor( + _In_ ULONG Attributes + ) +{ + if (Attributes & SE_PRIVILEGE_ENABLED_BY_DEFAULT) + return RGB(0xc0, 0xf0, 0xc0); + else if (Attributes & SE_PRIVILEGE_ENABLED) + return RGB(0xe0, 0xf0, 0xe0); + else + return RGB(0xf0, 0xe0, 0xe0); +} + static COLORREF NTAPI PhpTokenGroupColorFunction( _In_ INT Index, _In_ PVOID Param, _In_opt_ PVOID Context ) { - PSID_AND_ATTRIBUTES sidAndAttributes = Param; + PPHP_TOKEN_PAGE_LISTVIEW_ITEM entry = Param; - return PhGetGroupAttributesColor(sidAndAttributes->Attributes); + if (entry->IsTokenGroupEntry) + return PhGetGroupAttributesColor(entry->TokenGroup->Attributes); + else + return PhGetPrivilegeAttributesColor(entry->TokenPrivilege->Attributes); } PWSTR PhGetPrivilegeAttributesString( @@ -308,29 +346,6 @@ PWSTR PhGetPrivilegeAttributesString( return L"Disabled"; } -COLORREF PhGetPrivilegeAttributesColor( - _In_ ULONG Attributes - ) -{ - if (Attributes & SE_PRIVILEGE_ENABLED_BY_DEFAULT) - return RGB(0xc0, 0xf0, 0xc0); - else if (Attributes & SE_PRIVILEGE_ENABLED) - return RGB(0xe0, 0xf0, 0xe0); - else - return RGB(0xf0, 0xe0, 0xe0); -} - -static COLORREF NTAPI PhpTokenPrivilegeColorFunction( - _In_ INT Index, - _In_ PVOID Param, - _In_opt_ PVOID Context - ) -{ - PLUID_AND_ATTRIBUTES luidAndAttributes = Param; - - return PhGetPrivilegeAttributesColor(luidAndAttributes->Attributes); -} - PWSTR PhGetElevationTypeString( _In_ TOKEN_ELEVATION_TYPE ElevationType ) @@ -346,8 +361,29 @@ PWSTR PhGetElevationTypeString( } } +VOID PhpTokenPageFreeListViewEntries( + _In_ PTOKEN_PAGE_CONTEXT TokenPageContext + ) +{ + ULONG index = -1; + + while ((index = PhFindListViewItemByFlags( + TokenPageContext->ListViewHandle, + index, + LVNI_ALL + )) != -1) + { + PPHP_TOKEN_PAGE_LISTVIEW_ITEM entry; + + if (PhGetListViewItemParam(TokenPageContext->ListViewHandle, index, &entry)) + { + PhFree(entry); + } + } +} + VOID PhpUpdateSidsFromTokenGroups( - _In_ HWND GroupsLv, + _In_ HWND ListViewHandle, _In_ PTOKEN_GROUPS Groups, _In_ BOOLEAN Restricted ) @@ -365,9 +401,23 @@ VOID PhpUpdateSidsFromTokenGroups( if (fullName) { - lvItemIndex = PhAddListViewItem(GroupsLv, MAXINT, fullName->Buffer, &Groups->Groups[i]); + PPHP_TOKEN_PAGE_LISTVIEW_ITEM lvitem; + + lvitem = PhAllocate(sizeof(PHP_TOKEN_PAGE_LISTVIEW_ITEM)); + memset(lvitem, 0, sizeof(PHP_TOKEN_PAGE_LISTVIEW_ITEM)); + + lvitem->IsTokenGroupEntry = TRUE; + lvitem->TokenGroup = &Groups->Groups[i]; + + lvItemIndex = PhAddListViewGroupItem( + ListViewHandle, + PH_PROCESS_TOKEN_CATEGORY_GROUPS, + PH_PROCESS_TOKEN_INDEX_NAME, + fullName->Buffer, + lvitem + ); attributesString = PhGetGroupAttributesString(Groups->Groups[i].Attributes, Restricted); - PhSetListViewSubItem(GroupsLv, lvItemIndex, 1, attributesString->Buffer); + PhSetListViewSubItem(ListViewHandle, lvItemIndex, PH_PROCESS_TOKEN_INDEX_STATUS, attributesString->Buffer); PhDereferenceObject(attributesString); PhDereferenceObject(fullName); @@ -378,7 +428,7 @@ VOID PhpUpdateSidsFromTokenGroups( BOOLEAN PhpUpdateTokenGroups( _In_ HWND hwndDlg, _In_ PTOKEN_PAGE_CONTEXT TokenPageContext, - _In_ HWND GroupsLv, + _In_ HWND ListViewHandle, _In_ HANDLE TokenHandle ) { @@ -388,19 +438,13 @@ BOOLEAN PhpUpdateTokenGroups( if (!NT_SUCCESS(PhGetTokenGroups(TokenHandle, &groups))) return FALSE; - ExtendedListView_SetRedraw(GroupsLv, FALSE); - ListView_DeleteAllItems(GroupsLv); - - PhpUpdateSidsFromTokenGroups(GroupsLv, groups, FALSE); + PhpUpdateSidsFromTokenGroups(ListViewHandle, groups, FALSE); if (NT_SUCCESS(PhGetTokenRestrictedSids(TokenHandle, &restrictedSIDs))) { - PhpUpdateSidsFromTokenGroups(GroupsLv, restrictedSIDs, TRUE); + PhpUpdateSidsFromTokenGroups(ListViewHandle, restrictedSIDs, TRUE); } - ExtendedListView_SortItems(GroupsLv); - ExtendedListView_SetRedraw(GroupsLv, TRUE); - if (TokenPageContext->RestrictedSids) PhFree(TokenPageContext->RestrictedSids); @@ -417,7 +461,7 @@ BOOLEAN PhpUpdateTokenGroups( BOOLEAN PhpUpdateTokenPrivileges( _In_ HWND hwndDlg, _In_ PTOKEN_PAGE_CONTEXT TokenPageContext, - _In_ HWND PrivilegesLv, + _In_ HWND ListViewHandle, _In_ HANDLE TokenHandle ) { @@ -427,9 +471,6 @@ BOOLEAN PhpUpdateTokenPrivileges( if (!NT_SUCCESS(PhGetTokenPrivileges(TokenHandle, &privileges))) return FALSE; - ExtendedListView_SetRedraw(PrivilegesLv, FALSE); - ListView_DeleteAllItems(PrivilegesLv); - for (i = 0; i < privileges->PrivilegeCount; i++) { INT lvItemIndex; @@ -441,24 +482,34 @@ BOOLEAN PhpUpdateTokenPrivileges( &privilegeName )) { + PPHP_TOKEN_PAGE_LISTVIEW_ITEM lvitem; + + lvitem = PhAllocate(sizeof(PHP_TOKEN_PAGE_LISTVIEW_ITEM)); + memset(lvitem, 0, sizeof(PHP_TOKEN_PAGE_LISTVIEW_ITEM)); + + lvitem->TokenPrivilege = &privileges->Privileges[i]; + privilegeDisplayName = NULL; PhLookupPrivilegeDisplayName(&privilegeName->sr, &privilegeDisplayName); // Name - lvItemIndex = PhAddListViewItem(PrivilegesLv, MAXINT, privilegeName->Buffer, &privileges->Privileges[i]); + lvItemIndex = PhAddListViewGroupItem( + ListViewHandle, + PH_PROCESS_TOKEN_CATEGORY_PRIVILEGES, + PH_PROCESS_TOKEN_INDEX_NAME, + privilegeName->Buffer, + lvitem + ); // Status - PhSetListViewSubItem(PrivilegesLv, lvItemIndex, 1, PhGetPrivilegeAttributesString(privileges->Privileges[i].Attributes)); + PhSetListViewSubItem(ListViewHandle, lvItemIndex, PH_PROCESS_TOKEN_INDEX_STATUS, PhGetPrivilegeAttributesString(privileges->Privileges[i].Attributes)); // Description - PhSetListViewSubItem(PrivilegesLv, lvItemIndex, 2, PhGetString(privilegeDisplayName)); + PhSetListViewSubItem(ListViewHandle, lvItemIndex, PH_PROCESS_TOKEN_INDEX_DESCRIPTION, PhGetString(privilegeDisplayName)); if (privilegeDisplayName) PhDereferenceObject(privilegeDisplayName); PhDereferenceObject(privilegeName); } } - ExtendedListView_SortItems(PrivilegesLv); - ExtendedListView_SetRedraw(PrivilegesLv, TRUE); - if (TokenPageContext->Privileges) PhFree(TokenPageContext->Privileges); @@ -501,30 +552,25 @@ INT_PTR CALLBACK PhpTokenPageProc( { case WM_INITDIALOG: { - HWND groupsLv; - HWND privilegesLv; HANDLE tokenHandle; - tokenPageContext->GroupsListViewHandle = groupsLv = GetDlgItem(hwndDlg, IDC_GROUPS); - tokenPageContext->PrivilegesListViewHandle = privilegesLv = GetDlgItem(hwndDlg, IDC_PRIVILEGES); - PhSetListViewStyle(groupsLv, FALSE, TRUE); - PhSetListViewStyle(privilegesLv, FALSE, TRUE); - PhSetControlTheme(groupsLv, L"explorer"); - PhSetControlTheme(privilegesLv, L"explorer"); + tokenPageContext->ListViewHandle = GetDlgItem(hwndDlg, IDC_GROUPS); + tokenPageContext->ListViewImageList = ImageList_Create(2, 20, ILC_COLOR, 1, 1); - PhAddListViewColumn(groupsLv, 0, 0, 0, LVCFMT_LEFT, 160, L"Name"); - PhAddListViewColumn(groupsLv, 1, 1, 1, LVCFMT_LEFT, 200, L"Flags"); + PhSetListViewStyle(tokenPageContext->ListViewHandle, FALSE, TRUE); + PhSetControlTheme(tokenPageContext->ListViewHandle, L"explorer"); + PhAddListViewColumn(tokenPageContext->ListViewHandle, 0, 0, 0, LVCFMT_LEFT, 100, L"Name"); + PhAddListViewColumn(tokenPageContext->ListViewHandle, 1, 1, 1, LVCFMT_LEFT, 100, L"Status"); + PhAddListViewColumn(tokenPageContext->ListViewHandle, 2, 2, 2, LVCFMT_LEFT, 170, L"Description"); - PhAddListViewColumn(privilegesLv, 0, 0, 0, LVCFMT_LEFT, 100, L"Name"); - PhAddListViewColumn(privilegesLv, 1, 1, 1, LVCFMT_LEFT, 100, L"Status"); - PhAddListViewColumn(privilegesLv, 2, 2, 2, LVCFMT_LEFT, 170, L"Description"); + PhSetExtendedListView(tokenPageContext->ListViewHandle); + ExtendedListView_SetItemColorFunction(tokenPageContext->ListViewHandle, PhpTokenGroupColorFunction); + PhLoadListViewColumnsFromSetting(L"TokenGroupsListViewColumns", tokenPageContext->ListViewHandle); - PhSetExtendedListView(groupsLv); - ExtendedListView_SetItemColorFunction(groupsLv, PhpTokenGroupColorFunction); - PhSetExtendedListView(privilegesLv); - ExtendedListView_SetItemColorFunction(privilegesLv, PhpTokenPrivilegeColorFunction); - PhLoadListViewColumnsFromSetting(L"TokenGroupsListViewColumns", groupsLv); - PhLoadListViewColumnsFromSetting(L"TokenPrivilegesListViewColumns", privilegesLv); + ListView_EnableGroupView(tokenPageContext->ListViewHandle, TRUE); + PhAddListViewGroup(tokenPageContext->ListViewHandle, PH_PROCESS_TOKEN_CATEGORY_PRIVILEGES, L"Privileges"); + PhAddListViewGroup(tokenPageContext->ListViewHandle, PH_PROCESS_TOKEN_CATEGORY_GROUPS, L"Groups"); + ListView_SetImageList(tokenPageContext->ListViewHandle, tokenPageContext->ListViewImageList, LVSIL_SMALL); SetDlgItemText(hwndDlg, IDC_USER, L"Unknown"); SetDlgItemText(hwndDlg, IDC_USERSID, L"Unknown"); @@ -615,30 +661,26 @@ INT_PTR CALLBACK PhpTokenPageProc( SetDlgItemText(hwndDlg, IDC_APPCONTAINERSID, L"N/A"); } - // Groups - PhpUpdateTokenGroups(hwndDlg, tokenPageContext, groupsLv, tokenHandle); - - // Privileges - PhpUpdateTokenPrivileges(hwndDlg, tokenPageContext, privilegesLv, tokenHandle); + ExtendedListView_SetRedraw(tokenPageContext->ListViewHandle, FALSE); + PhpTokenPageFreeListViewEntries(tokenPageContext); + ListView_DeleteAllItems(tokenPageContext->ListViewHandle); + PhpUpdateTokenGroups(hwndDlg, tokenPageContext, tokenPageContext->ListViewHandle, tokenHandle); + PhpUpdateTokenPrivileges(hwndDlg, tokenPageContext, tokenPageContext->ListViewHandle, tokenHandle); + ExtendedListView_SortItems(tokenPageContext->ListViewHandle); + ExtendedListView_SetRedraw(tokenPageContext->ListViewHandle, TRUE); NtClose(tokenHandle); } - - if (PhGetIntegerSetting(L"TokenSplitterEnable")) - { - PhInitializeHSplitter( - L"TokenSplitterPosition", - hwndDlg, - tokenPageContext->GroupsListViewHandle, - tokenPageContext->PrivilegesListViewHandle - ); - } } break; case WM_DESTROY: { - PhSaveListViewColumnsToSetting(L"TokenGroupsListViewColumns", tokenPageContext->GroupsListViewHandle); - PhSaveListViewColumnsToSetting(L"TokenPrivilegesListViewColumns", tokenPageContext->PrivilegesListViewHandle); + if (tokenPageContext->ListViewImageList) + ImageList_Destroy(tokenPageContext->ListViewImageList); + + PhpTokenPageFreeListViewEntries(tokenPageContext); + + PhSaveListViewColumnsToSetting(L"TokenGroupsListViewColumns", tokenPageContext->ListViewHandle); if (tokenPageContext->Groups) PhFree(tokenPageContext->Groups); if (tokenPageContext->RestrictedSids) PhFree(tokenPageContext->RestrictedSids); @@ -654,11 +696,33 @@ INT_PTR CALLBACK PhpTokenPageProc( case ID_PRIVILEGE_REMOVE: { NTSTATUS status; - PLUID_AND_ATTRIBUTES *privileges; - ULONG numberOfPrivileges; + BOOLEAN listViewGroupItemsValid = FALSE; + PPHP_TOKEN_PAGE_LISTVIEW_ITEM *listViewItems; + ULONG numberOfItems; HANDLE tokenHandle; ULONG i; + PhGetSelectedListViewItemParams( + tokenPageContext->ListViewHandle, + &listViewItems, + &numberOfItems + ); + + for (i = 0; i < numberOfItems; i++) + { + if (listViewItems[i]->IsTokenGroupEntry) + { + listViewGroupItemsValid = TRUE; + break; + } + } + + if (listViewGroupItemsValid) + { + PhFree(listViewItems); + break; + } + if (LOWORD(wParam) == ID_PRIVILEGE_REMOVE) { if (!PhShowConfirmMessage( @@ -672,12 +736,6 @@ INT_PTR CALLBACK PhpTokenPageProc( break; } - PhGetSelectedListViewItemParams( - tokenPageContext->PrivilegesListViewHandle, - &privileges, - &numberOfPrivileges - ); - status = tokenPageContext->OpenObject( &tokenHandle, TOKEN_ADJUST_PRIVILEGES, @@ -686,14 +744,14 @@ INT_PTR CALLBACK PhpTokenPageProc( if (NT_SUCCESS(status)) { - ExtendedListView_SetRedraw(tokenPageContext->PrivilegesListViewHandle, FALSE); + ExtendedListView_SetRedraw(tokenPageContext->ListViewHandle, FALSE); - for (i = 0; i < numberOfPrivileges; i++) + for (i = 0; i < numberOfItems; i++) { PPH_STRING privilegeName = NULL; ULONG newAttributes; - PhLookupPrivilegeName(&privileges[i]->Luid, &privilegeName); + PhLookupPrivilegeName(&listViewItems[i]->TokenPrivilege->Luid, &privilegeName); PH_AUTO(privilegeName); switch (LOWORD(wParam)) @@ -713,7 +771,7 @@ INT_PTR CALLBACK PhpTokenPageProc( // modified except to remove them. if ( - privileges[i]->Attributes & SE_PRIVILEGE_ENABLED_BY_DEFAULT && + listViewItems[i]->TokenPrivilege->Attributes & SE_PRIVILEGE_ENABLED_BY_DEFAULT && LOWORD(wParam) != ID_PRIVILEGE_REMOVE ) { @@ -734,32 +792,31 @@ INT_PTR CALLBACK PhpTokenPageProc( if (PhSetTokenPrivilege( tokenHandle, NULL, - &privileges[i]->Luid, + &listViewItems[i]->TokenPrivilege->Luid, newAttributes )) { INT lvItemIndex = PhFindListViewItemByParam( - tokenPageContext->PrivilegesListViewHandle, + tokenPageContext->ListViewHandle, -1, - privileges[i] + listViewItems[i] ); if (LOWORD(wParam) != ID_PRIVILEGE_REMOVE) { - // Refresh the status text (and background - // color). - privileges[i]->Attributes = newAttributes; + // Refresh the status text (and background color). + listViewItems[i]->TokenPrivilege->Attributes = newAttributes; PhSetListViewSubItem( - tokenPageContext->PrivilegesListViewHandle, + tokenPageContext->ListViewHandle, lvItemIndex, - 1, + PH_PROCESS_TOKEN_INDEX_STATUS, PhGetPrivilegeAttributesString(newAttributes) ); } else { ListView_DeleteItem( - tokenPageContext->PrivilegesListViewHandle, + tokenPageContext->ListViewHandle, lvItemIndex ); } @@ -791,7 +848,7 @@ INT_PTR CALLBACK PhpTokenPageProc( } } - ExtendedListView_SetRedraw(tokenPageContext->PrivilegesListViewHandle, TRUE); + ExtendedListView_SetRedraw(tokenPageContext->ListViewHandle, TRUE); NtClose(tokenHandle); } @@ -800,14 +857,14 @@ INT_PTR CALLBACK PhpTokenPageProc( PhShowStatus(hwndDlg, L"Unable to open the token", status, 0); } - PhFree(privileges); + PhFree(listViewItems); - ExtendedListView_SortItems(tokenPageContext->PrivilegesListViewHandle); + ExtendedListView_SortItems(tokenPageContext->ListViewHandle); } break; case ID_PRIVILEGE_COPY: { - PhCopyListView(tokenPageContext->PrivilegesListViewHandle); + PhCopyListView(tokenPageContext->ListViewHandle); } break; case IDC_INTEGRITY: @@ -822,7 +879,6 @@ INT_PTR CALLBACK PhpTokenPageProc( GetWindowRect(GetDlgItem(hwndDlg, IDC_INTEGRITY), &rect); menu = PhCreateEMenu(); - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, MandatoryLevelSecureProcess, L"Protected", NULL, NULL), -1); PhInsertEMenuItem(menu, PhCreateEMenuItem(0, MandatoryLevelSystem, L"System", NULL, NULL), -1); PhInsertEMenuItem(menu, PhCreateEMenuItem(0, MandatoryLevelHigh, L"High", NULL, NULL), -1); @@ -920,8 +976,13 @@ INT_PTR CALLBACK PhpTokenPageProc( if (NT_SUCCESS(status)) { - PhpUpdateTokenGroups(hwndDlg, tokenPageContext, tokenPageContext->GroupsListViewHandle, tokenHandle); - PhpUpdateTokenPrivileges(hwndDlg, tokenPageContext, tokenPageContext->PrivilegesListViewHandle, tokenHandle); + ExtendedListView_SetRedraw(tokenPageContext->ListViewHandle, FALSE); + PhpTokenPageFreeListViewEntries(tokenPageContext); + ListView_DeleteAllItems(tokenPageContext->ListViewHandle); + PhpUpdateTokenGroups(hwndDlg, tokenPageContext, tokenPageContext->ListViewHandle, tokenHandle); + PhpUpdateTokenPrivileges(hwndDlg, tokenPageContext, tokenPageContext->ListViewHandle, tokenHandle); + ExtendedListView_SortItems(tokenPageContext->ListViewHandle); + ExtendedListView_SetRedraw(tokenPageContext->ListViewHandle, TRUE); } NtClose(tokenHandle); @@ -957,13 +1018,12 @@ INT_PTR CALLBACK PhpTokenPageProc( break; } - PhHandleListViewNotifyBehaviors(lParam, tokenPageContext->GroupsListViewHandle, PH_LIST_VIEW_DEFAULT_1_BEHAVIORS); - PhHandleListViewNotifyBehaviors(lParam, tokenPageContext->PrivilegesListViewHandle, PH_LIST_VIEW_DEFAULT_1_BEHAVIORS); + PhHandleListViewNotifyBehaviors(lParam, tokenPageContext->ListViewHandle, PH_LIST_VIEW_DEFAULT_1_BEHAVIORS); } break; case WM_CONTEXTMENU: { - if ((HWND)wParam == tokenPageContext->PrivilegesListViewHandle) + if ((HWND)wParam == tokenPageContext->ListViewHandle) { POINT point; @@ -973,23 +1033,56 @@ INT_PTR CALLBACK PhpTokenPageProc( if (point.x == -1 && point.y == -1) PhGetListViewContextMenuPoint((HWND)wParam, &point); - if (ListView_GetSelectedCount(tokenPageContext->PrivilegesListViewHandle) != 0) + if (ListView_GetSelectedCount(tokenPageContext->ListViewHandle) != 0) { PPH_EMENU menu; + BOOLEAN listViewGroupItemsValid = TRUE; + PPHP_TOKEN_PAGE_LISTVIEW_ITEM *listviewItems; + ULONG numberOfItems; + ULONG i; + + PhGetSelectedListViewItemParams( + tokenPageContext->ListViewHandle, + &listviewItems, + &numberOfItems + ); + + for (i = 0; i < numberOfItems; i++) + { + if (listviewItems[i]->IsTokenGroupEntry) + { + listViewGroupItemsValid = FALSE; + break; + } + } menu = PhCreateEMenu(); - PhLoadResourceEMenuItem(menu, PhInstanceHandle, MAKEINTRESOURCE(IDR_PRIVILEGE), 0); - PhShowEMenu(menu, hwndDlg, PH_EMENU_SHOW_SEND_COMMAND | PH_EMENU_SHOW_LEFTRIGHT, - PH_ALIGN_LEFT | PH_ALIGN_TOP, point.x, point.y); + if (listViewGroupItemsValid) + { + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_PRIVILEGE_ENABLE, L"&Enable", NULL, NULL), -1); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_PRIVILEGE_DISABLE, L"&Disable", NULL, NULL), -1); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_PRIVILEGE_REMOVE, L"&Remove", NULL, NULL), -1); + PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), -1); + } + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_PRIVILEGE_COPY, L"&Copy", NULL, NULL), -1); + PhShowEMenu( + menu, + hwndDlg, + PH_EMENU_SHOW_SEND_COMMAND | PH_EMENU_SHOW_LEFTRIGHT, + PH_ALIGN_LEFT | PH_ALIGN_TOP, + point.x, + point.y + ); PhDestroyEMenu(menu); + + PhFree(listviewItems); } } } break; } - REFLECT_MESSAGE_DLG(hwndDlg, tokenPageContext->GroupsListViewHandle, uMsg, wParam, lParam); - REFLECT_MESSAGE_DLG(hwndDlg, tokenPageContext->PrivilegesListViewHandle, uMsg, wParam, lParam); + REFLECT_MESSAGE_DLG(hwndDlg, tokenPageContext->ListViewHandle, uMsg, wParam, lParam); return FALSE; } From dd5645ce176aa188af1dc89da5cb37123b3095bc Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 5 Feb 2018 10:55:19 +1100 Subject: [PATCH 0773/2058] Fix build --- ProcessHacker/prpgtok.c | 39 ++++++++++++--------------------------- 1 file changed, 12 insertions(+), 27 deletions(-) diff --git a/ProcessHacker/prpgtok.c b/ProcessHacker/prpgtok.c index 44a1e9a287d9..af2946f77f66 100644 --- a/ProcessHacker/prpgtok.c +++ b/ProcessHacker/prpgtok.c @@ -59,45 +59,30 @@ INT_PTR CALLBACK PhpProcessTokenHookProc( { case WM_DESTROY: { - PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); + if (PhGetWindowContext(hwndDlg, 0xD)) + PhRemoveWindowContext(hwndDlg, 0xD); } break; case WM_SHOWWINDOW: { - if (!PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT)) // LayoutInitialized + if (!PhGetWindowContext(hwndDlg, 0xD)) // LayoutInitialized { PPH_LAYOUT_ITEM dialogItem; // This is a big violation of abstraction... - dialogItem = PhAddPropPageLayoutItem(hwndDlg, hwndDlg, - PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL); - PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_USER), - dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); - PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_USERSID), - dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); - PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_VIRTUALIZED), - dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); - PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_APPCONTAINERSID), - dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); - PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_INSTRUCTION), - dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_BOTTOM); - PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_INTEGRITY), - dialogItem, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); - PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_ADVANCED), - dialogItem, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); - - if (!PhGetIntegerSetting(L"TokenSplitterEnable")) - { - PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_GROUPS), - dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); - PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_PRIVILEGES), - dialogItem, PH_ANCHOR_ALL); - } + dialogItem = PhAddPropPageLayoutItem(hwndDlg, hwndDlg, PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL); + PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_USER), dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); + PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_USERSID), dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); + PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_VIRTUALIZED), dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); + PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_APPCONTAINERSID), dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); + PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_GROUPS), dialogItem, PH_ANCHOR_ALL); + PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_INTEGRITY), dialogItem, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); + PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_ADVANCED), dialogItem, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); PhDoPropPageLayout(hwndDlg); - PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, UlongToPtr(TRUE)); + PhSetWindowContext(hwndDlg, 0xD, UlongToPtr(TRUE)); } } break; From f8182c5bf427c05361e9b65f67ef3d3ece3815a5 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 5 Feb 2018 12:14:58 +1100 Subject: [PATCH 0774/2058] Export PhEnumChildWindows --- ProcessHacker/appsup.c | 105 --------------------------------- ProcessHacker/include/appsup.h | 23 -------- phlib/guisup.c | 105 +++++++++++++++++++++++++++++++++ phlib/include/guisup.h | 23 ++++++++ 4 files changed, 128 insertions(+), 128 deletions(-) diff --git a/ProcessHacker/appsup.c b/ProcessHacker/appsup.c index 66413ad6e5cc..2662baa237b2 100644 --- a/ProcessHacker/appsup.c +++ b/ProcessHacker/appsup.c @@ -679,111 +679,6 @@ BOOLEAN PhaGetProcessKnownCommandLine( return TRUE; } -VOID PhEnumChildWindows( - _In_opt_ HWND WindowHandle, - _In_ ULONG Limit, - _In_ PH_CHILD_ENUM_CALLBACK Callback, - _In_ PVOID Context - ) -{ - HWND childWindow = NULL; - ULONG i = 0; - - while (i < Limit && (childWindow = FindWindowEx(WindowHandle, childWindow, NULL, NULL))) - { - if (!Callback(childWindow, Context)) - return; - - i++; - } -} - -typedef struct _GET_PROCESS_MAIN_WINDOW_CONTEXT -{ - HWND Window; - HWND ImmersiveWindow; - HANDLE ProcessId; - BOOLEAN IsImmersive; - BOOLEAN SkipInvisible; -} GET_PROCESS_MAIN_WINDOW_CONTEXT, *PGET_PROCESS_MAIN_WINDOW_CONTEXT; - -BOOLEAN CALLBACK PhpGetProcessMainWindowEnumWindowsProc( - _In_ HWND WindowHandle, - _In_opt_ PVOID Context - ) -{ - PGET_PROCESS_MAIN_WINDOW_CONTEXT context = (PGET_PROCESS_MAIN_WINDOW_CONTEXT)Context; - ULONG processId; - HWND parentWindow; - WINDOWINFO windowInfo; - - if (context->SkipInvisible && !IsWindowVisible(WindowHandle)) - return TRUE; - - GetWindowThreadProcessId(WindowHandle, &processId); - - if (UlongToHandle(processId) == context->ProcessId && (context->SkipInvisible ? - !((parentWindow = GetParent(WindowHandle)) && IsWindowVisible(parentWindow)) && // skip windows with a visible parent - PhGetWindowTextEx(WindowHandle, PH_GET_WINDOW_TEXT_INTERNAL | PH_GET_WINDOW_TEXT_LENGTH_ONLY, NULL) != 0 : TRUE)) // skip windows with no title - { - if (!context->ImmersiveWindow && context->IsImmersive && - GetProp(WindowHandle, L"Windows.ImmersiveShell.IdentifyAsMainCoreWindow")) - { - context->ImmersiveWindow = WindowHandle; - } - - windowInfo.cbSize = sizeof(WINDOWINFO); - - if (!context->Window && GetWindowInfo(WindowHandle, &windowInfo) && (windowInfo.dwStyle & WS_DLGFRAME)) - { - context->Window = WindowHandle; - - // If we're not looking at an immersive process, there's no need to search any more windows. - if (!context->IsImmersive) - return FALSE; - } - } - - return TRUE; -} - -HWND PhGetProcessMainWindow( - _In_ HANDLE ProcessId, - _In_opt_ HANDLE ProcessHandle - ) -{ - return PhGetProcessMainWindowEx(ProcessId, ProcessHandle, TRUE); -} - -HWND PhGetProcessMainWindowEx( - _In_ HANDLE ProcessId, - _In_opt_ HANDLE ProcessHandle, - _In_ BOOLEAN SkipInvisible - ) -{ - GET_PROCESS_MAIN_WINDOW_CONTEXT context; - HANDLE processHandle = NULL; - - memset(&context, 0, sizeof(GET_PROCESS_MAIN_WINDOW_CONTEXT)); - context.ProcessId = ProcessId; - context.SkipInvisible = SkipInvisible; - - if (ProcessHandle) - processHandle = ProcessHandle; - else - PhOpenProcess(&processHandle, ProcessQueryAccess, ProcessId); - - if (processHandle && IsImmersiveProcess_I) - context.IsImmersive = IsImmersiveProcess_I(processHandle); - - PhEnumChildWindows(NULL, 0x800, PhpGetProcessMainWindowEnumWindowsProc, &context); - - if (!ProcessHandle && processHandle) - NtClose(processHandle); - - return context.ImmersiveWindow ? context.ImmersiveWindow : context.Window; -} - PPH_STRING PhGetServiceRelevantFileName( _In_ PPH_STRINGREF ServiceName, _In_ SC_HANDLE ServiceHandle diff --git a/ProcessHacker/include/appsup.h b/ProcessHacker/include/appsup.h index 62038ebf4caf..261fdd058666 100644 --- a/ProcessHacker/include/appsup.h +++ b/ProcessHacker/include/appsup.h @@ -101,29 +101,6 @@ PhaGetProcessKnownCommandLine( ); // end_phapppub -typedef BOOLEAN (CALLBACK *PH_CHILD_ENUM_CALLBACK)( - _In_ HWND WindowHandle, - _In_opt_ PVOID Context - ); - -VOID PhEnumChildWindows( - _In_opt_ HWND WindowHandle, - _In_ ULONG Limit, - _In_ PH_CHILD_ENUM_CALLBACK Callback, - _In_ PVOID Context - ); - -HWND PhGetProcessMainWindow( - _In_ HANDLE ProcessId, - _In_opt_ HANDLE ProcessHandle - ); - -HWND PhGetProcessMainWindowEx( - _In_ HANDLE ProcessId, - _In_opt_ HANDLE ProcessHandle, - _In_ BOOLEAN SkipInvisible - ); - PPH_STRING PhGetServiceRelevantFileName( _In_ PPH_STRINGREF ServiceName, _In_ SC_HANDLE ServiceHandle diff --git a/phlib/guisup.c b/phlib/guisup.c index 2d24f76a515b..7305c65a21db 100644 --- a/phlib/guisup.c +++ b/phlib/guisup.c @@ -1353,3 +1353,108 @@ VOID PhRemoveWindowContext( PhRemoveEntryHashtable(WindowContextHashTable, &lookupEntry); PhReleaseQueuedLockExclusive(&WindowContextListLock); } + +VOID PhEnumChildWindows( + _In_opt_ HWND WindowHandle, + _In_ ULONG Limit, + _In_ PH_CHILD_ENUM_CALLBACK Callback, + _In_ PVOID Context + ) +{ + HWND childWindow = NULL; + ULONG i = 0; + + while (i < Limit && (childWindow = FindWindowEx(WindowHandle, childWindow, NULL, NULL))) + { + if (!Callback(childWindow, Context)) + return; + + i++; + } +} + +typedef struct _GET_PROCESS_MAIN_WINDOW_CONTEXT +{ + HWND Window; + HWND ImmersiveWindow; + HANDLE ProcessId; + BOOLEAN IsImmersive; + BOOLEAN SkipInvisible; +} GET_PROCESS_MAIN_WINDOW_CONTEXT, *PGET_PROCESS_MAIN_WINDOW_CONTEXT; + +BOOLEAN CALLBACK PhpGetProcessMainWindowEnumWindowsProc( + _In_ HWND WindowHandle, + _In_opt_ PVOID Context + ) +{ + PGET_PROCESS_MAIN_WINDOW_CONTEXT context = (PGET_PROCESS_MAIN_WINDOW_CONTEXT)Context; + ULONG processId; + HWND parentWindow; + WINDOWINFO windowInfo; + + if (context->SkipInvisible && !IsWindowVisible(WindowHandle)) + return TRUE; + + GetWindowThreadProcessId(WindowHandle, &processId); + + if (UlongToHandle(processId) == context->ProcessId && (context->SkipInvisible ? + !((parentWindow = GetParent(WindowHandle)) && IsWindowVisible(parentWindow)) && // skip windows with a visible parent + PhGetWindowTextEx(WindowHandle, PH_GET_WINDOW_TEXT_INTERNAL | PH_GET_WINDOW_TEXT_LENGTH_ONLY, NULL) != 0 : TRUE)) // skip windows with no title + { + if (!context->ImmersiveWindow && context->IsImmersive && + GetProp(WindowHandle, L"Windows.ImmersiveShell.IdentifyAsMainCoreWindow")) + { + context->ImmersiveWindow = WindowHandle; + } + + windowInfo.cbSize = sizeof(WINDOWINFO); + + if (!context->Window && GetWindowInfo(WindowHandle, &windowInfo) && (windowInfo.dwStyle & WS_DLGFRAME)) + { + context->Window = WindowHandle; + + // If we're not looking at an immersive process, there's no need to search any more windows. + if (!context->IsImmersive) + return FALSE; + } + } + + return TRUE; +} + +HWND PhGetProcessMainWindow( + _In_ HANDLE ProcessId, + _In_opt_ HANDLE ProcessHandle + ) +{ + return PhGetProcessMainWindowEx(ProcessId, ProcessHandle, TRUE); +} + +HWND PhGetProcessMainWindowEx( + _In_ HANDLE ProcessId, + _In_opt_ HANDLE ProcessHandle, + _In_ BOOLEAN SkipInvisible + ) +{ + GET_PROCESS_MAIN_WINDOW_CONTEXT context; + HANDLE processHandle = NULL; + + memset(&context, 0, sizeof(GET_PROCESS_MAIN_WINDOW_CONTEXT)); + context.ProcessId = ProcessId; + context.SkipInvisible = SkipInvisible; + + if (ProcessHandle) + processHandle = ProcessHandle; + else + PhOpenProcess(&processHandle, ProcessQueryAccess, ProcessId); + + if (processHandle && IsImmersiveProcess_I) + context.IsImmersive = IsImmersiveProcess_I(processHandle); + + PhEnumChildWindows(NULL, 0x800, PhpGetProcessMainWindowEnumWindowsProc, &context); + + if (!ProcessHandle && processHandle) + NtClose(processHandle); + + return context.ImmersiveWindow ? context.ImmersiveWindow : context.Window; +} diff --git a/phlib/include/guisup.h b/phlib/include/guisup.h index 06d4799f1cf9..38c83defb8d6 100644 --- a/phlib/include/guisup.h +++ b/phlib/include/guisup.h @@ -500,6 +500,29 @@ PhRemoveWindowContext( _In_ ULONG PropertyHash ); +typedef BOOLEAN (CALLBACK *PH_CHILD_ENUM_CALLBACK)( + _In_ HWND WindowHandle, + _In_opt_ PVOID Context + ); + +VOID PhEnumChildWindows( + _In_opt_ HWND WindowHandle, + _In_ ULONG Limit, + _In_ PH_CHILD_ENUM_CALLBACK Callback, + _In_ PVOID Context + ); + +HWND PhGetProcessMainWindow( + _In_ HANDLE ProcessId, + _In_opt_ HANDLE ProcessHandle + ); + +HWND PhGetProcessMainWindowEx( + _In_ HANDLE ProcessId, + _In_opt_ HANDLE ProcessHandle, + _In_ BOOLEAN SkipInvisible + ); + FORCEINLINE VOID PhResizingMinimumSize( _Inout_ PRECT Rect, _In_ WPARAM Edge, From ab93a3c5ecc8b7de1b6528d512689f7d79236647 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 5 Feb 2018 12:20:39 +1100 Subject: [PATCH 0775/2058] SetupTool: Fix header conflict, Update to latset phsdk --- .../CustomSetupTool/CustomSetupTool.vcxproj | 2 +- .../CustomSetupTool.vcxproj.filters | 6 +- .../CustomSetupTool/CustomSetupTool/appsup.c | 190 +++++++++++------- .../CustomSetupTool/download.c | 5 +- .../CustomSetupTool/CustomSetupTool/extract.c | 62 +++--- .../CustomSetupTool/include/setup.h | 2 +- .../include/{appsup.h => setupsup.h} | 10 +- .../CustomSetupTool/licencepage.c | 9 +- tools/CustomSetupTool/CustomSetupTool/main.c | 15 +- tools/CustomSetupTool/CustomSetupTool/setup.c | 2 +- .../CustomSetupTool/startpage.c | 6 +- .../CustomSetupTool/uninstall.c | 2 +- .../CustomSetupTool/CustomSetupTool/update.c | 2 +- 13 files changed, 174 insertions(+), 139 deletions(-) rename tools/CustomSetupTool/CustomSetupTool/include/{appsup.h => setupsup.h} (92%) diff --git a/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj b/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj index 3f43de47288d..ada56f42b999 100644 --- a/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj +++ b/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj @@ -126,7 +126,7 @@ - + diff --git a/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj.filters b/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj.filters index 851ba8eb5075..9a3eebbb5c71 100644 --- a/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj.filters +++ b/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj.filters @@ -86,12 +86,12 @@ Header Files - - Header Files - Header Files\zip + + Header Files + diff --git a/tools/CustomSetupTool/CustomSetupTool/appsup.c b/tools/CustomSetupTool/CustomSetupTool/appsup.c index 51e3eb7de171..dac67fa7e4f4 100644 --- a/tools/CustomSetupTool/CustomSetupTool/appsup.c +++ b/tools/CustomSetupTool/CustomSetupTool/appsup.c @@ -19,6 +19,7 @@ */ #include +#include #include #include #include @@ -30,22 +31,19 @@ VOID ExtractResourceToFile( ) { HANDLE fileHandle = NULL; - ULONG resourceLength; - HRSRC resourceHandle = NULL; - HGLOBAL resourceData; PVOID resourceBuffer; + ULONG resourceLength; IO_STATUS_BLOCK isb; - if (!(resourceHandle = FindResource(PhInstanceHandle, Resource, RT_RCDATA))) - goto CleanupExit; - - resourceLength = SizeofResource(PhInstanceHandle, resourceHandle); - - if (!(resourceData = LoadResource(PhInstanceHandle, resourceHandle))) - goto CleanupExit; - - if (!(resourceBuffer = LockResource(resourceData))) + if (!PhLoadResource( + PhInstanceHandle, + Resource, RT_RCDATA, + &resourceLength, + &resourceBuffer + )) + { goto CleanupExit; + } if (!NT_SUCCESS(PhCreateFileWin32( &fileHandle, @@ -82,43 +80,6 @@ VOID ExtractResourceToFile( if (fileHandle) NtClose(fileHandle); - - if (resourceHandle) - FreeResource(resourceHandle); -} - -PVOID ExtractResourceToBuffer( - _In_ PWSTR Resource - ) -{ - ULONG resourceLength; - HRSRC resourceHandle = NULL; - HGLOBAL resourceData; - PVOID resourceBuffer; - PVOID buffer = NULL; - - if (!(resourceHandle = FindResource(PhInstanceHandle, Resource, RT_RCDATA))) - goto CleanupExit; - - resourceLength = SizeofResource(PhInstanceHandle, resourceHandle); - - if (!(resourceData = LoadResource(PhInstanceHandle, resourceHandle))) - goto CleanupExit; - - if (!(resourceBuffer = LockResource(resourceData))) - goto CleanupExit; - - if (!(buffer = PhAllocate(resourceLength))) - goto CleanupExit; - - memcpy(buffer, resourceBuffer, resourceLength); - -CleanupExit: - - if (resourceHandle) - FreeResource(resourceHandle); - - return buffer; } HBITMAP LoadPngImageFromResources( @@ -127,10 +88,8 @@ HBITMAP LoadPngImageFromResources( { BOOLEAN success = FALSE; UINT frameCount = 0; - ULONG resourceLength = 0; - HGLOBAL resourceHandle = NULL; - HRSRC resourceHandleSource = NULL; - WICInProcPointer resourceBuffer = NULL; + ULONG resourceLength; + PVOID resourceBuffer = NULL; HDC screenHdc = NULL; HDC bufferDc = NULL; BITMAPINFO bitmapInfo = { 0 }; @@ -149,18 +108,8 @@ HBITMAP LoadPngImageFromResources( if (FAILED(CoCreateInstance(&CLSID_WICImagingFactory1, NULL, CLSCTX_INPROC_SERVER, &IID_IWICImagingFactory, &wicFactory))) goto CleanupExit; - // Find the resource - if ((resourceHandleSource = FindResource(PhInstanceHandle, Name, L"PNG")) == NULL) - goto CleanupExit; - - // Get the resource length - resourceLength = SizeofResource(PhInstanceHandle, resourceHandleSource); - // Load the resource - if ((resourceHandle = LoadResource(PhInstanceHandle, resourceHandleSource)) == NULL) - goto CleanupExit; - - if ((resourceBuffer = (WICInProcPointer)LockResource(resourceHandle)) == NULL) + if (!PhLoadResource(PhInstanceHandle, Name, L"PNG", &resourceLength, &resourceBuffer)) goto CleanupExit; // Create the Stream @@ -270,8 +219,8 @@ HBITMAP LoadPngImageFromResources( if (wicFactory) IWICImagingFactory_Release(wicFactory); - if (resourceHandle) - FreeResource(resourceHandle); + if (resourceBuffer) + PhFree(resourceBuffer); if (success) { @@ -483,29 +432,74 @@ static BOOLEAN NTAPI PhpPreviousInstancesCallback( _In_opt_ PVOID Context ) { - ULONG64 processId64; - PH_STRINGREF firstPart; - PH_STRINGREF secondPart; - if ( - PhStartsWithStringRef2(Name, L"PhMutant_", TRUE) && - PhSplitStringRefAtChar(Name, L'_', &firstPart, &secondPart) && - PhStringToInteger64(&secondPart, 10, &processId64) + PhStartsWithStringRef2(Name, L"PhMainWindow_", TRUE) || + PhStartsWithStringRef2(Name, L"PhSetupWindow_", TRUE) || + PhStartsWithStringRef2(Name, L"PeViewerWindow_", TRUE) ) { HANDLE processHandle; + HWND hwnd; + ULONG64 sessionId64; + ULONG64 processId64; + PH_STRINGREF remaining; + PH_STRINGREF sessionIdPart; + PH_STRINGREF processIdPart; + + if (!PhSplitStringRefAtChar(Name, L'_', &remaining, &remaining)) + return TRUE; + if (!PhSplitStringRefAtChar(&remaining, L'_', &sessionIdPart, &processIdPart)) + return TRUE; + if (!PhStringToInteger64(&sessionIdPart, 10, &sessionId64)) + return TRUE; + if (!PhStringToInteger64(&processIdPart, 10, &processId64)) + return TRUE; - if (NT_SUCCESS(PhOpenProcess( + PhOpenProcess( &processHandle, - SYNCHRONIZE | PROCESS_TERMINATE, + PROCESS_TERMINATE | SYNCHRONIZE, ULongToHandle((ULONG)processId64) - ))) + ); + + if (sessionId64 == NtCurrentPeb()->SessionId) + { + if (hwnd = PhGetProcessMainWindowEx(UlongToHandle((ULONG)processId64), NULL, FALSE)) + { + SendMessageTimeout(hwnd, WM_QUIT, 0, 0, SMTO_BLOCK, 5000, NULL); + } + } + + if (processHandle) { NtTerminateProcess(processHandle, 1); NtClose(processHandle); } } + { + ULONG64 processId64; + PH_STRINGREF firstPart; + PH_STRINGREF secondPart; + + if (( + PhStartsWithStringRef2(Name, L"PhMutant_", TRUE) || + PhStartsWithStringRef2(Name, L"PhSetupMutant_", TRUE) || + PhStartsWithStringRef2(Name, L"PeViewer_", TRUE) + ) && + PhSplitStringRefAtChar(Name, L'_', &firstPart, &secondPart) && + PhStringToInteger64(&secondPart, 10, &processId64) + ) + { + HANDLE processHandle; + + if (NT_SUCCESS(PhOpenProcess(&processHandle, PROCESS_TERMINATE | SYNCHRONIZE, ULongToHandle((ULONG)processId64)))) + { + NtTerminateProcess(processHandle, 1); + NtClose(processHandle); + } + } + } + return TRUE; } @@ -514,3 +508,47 @@ BOOLEAN ShutdownProcessHacker(VOID) PhEnumDirectoryObjects(PhGetNamespaceHandle(), PhpPreviousInstancesCallback, NULL); return TRUE; } + +NTSTATUS QueryProcessesUsingVolumeOrFile( + _In_ HANDLE VolumeOrFileHandle, + _Out_ PFILE_PROCESS_IDS_USING_FILE_INFORMATION *Information + ) +{ + static ULONG initialBufferSize = 0x4000; + NTSTATUS status; + PVOID buffer; + ULONG bufferSize; + IO_STATUS_BLOCK isb; + + bufferSize = initialBufferSize; + buffer = malloc(bufferSize); + + while ((status = NtQueryInformationFile( + VolumeOrFileHandle, + &isb, + buffer, + bufferSize, + FileProcessIdsUsingFileInformation + )) == STATUS_INFO_LENGTH_MISMATCH) + { + free(buffer); + bufferSize *= 2; + + // Fail if we're resizing the buffer to something very large. + if (bufferSize > SIZE_MAX) + return STATUS_INSUFFICIENT_RESOURCES; + + buffer = malloc(bufferSize); + } + + if (!NT_SUCCESS(status)) + { + free(buffer); + return status; + } + + if (bufferSize <= 0x100000) initialBufferSize = bufferSize; + *Information = (PFILE_PROCESS_IDS_USING_FILE_INFORMATION)buffer; + + return status; +} diff --git a/tools/CustomSetupTool/CustomSetupTool/download.c b/tools/CustomSetupTool/CustomSetupTool/download.c index 51f76385dc58..a41abb3b351e 100644 --- a/tools/CustomSetupTool/CustomSetupTool/download.c +++ b/tools/CustomSetupTool/CustomSetupTool/download.c @@ -1,5 +1,5 @@ #include -#include +#include #include #include @@ -79,8 +79,7 @@ ULONG64 ParseVersionString( PH_STRINGREF remaining, majorPart, minorPart, revisionPart; ULONG64 majorInteger = 0, minorInteger = 0, revisionInteger = 0; - PhInitializeStringRef(&remaining, PhGetString(VersionString)); - + PhInitializeStringRef(&remaining, PhGetStringOrEmpty(VersionString)); PhSplitStringRefAtChar(&remaining, '.', &majorPart, &remaining); PhSplitStringRefAtChar(&remaining, '.', &minorPart, &remaining); PhSplitStringRefAtChar(&remaining, '.', &revisionPart, &remaining); diff --git a/tools/CustomSetupTool/CustomSetupTool/extract.c b/tools/CustomSetupTool/CustomSetupTool/extract.c index f5c74259fb86..861501f39a9a 100644 --- a/tools/CustomSetupTool/CustomSetupTool/extract.c +++ b/tools/CustomSetupTool/CustomSetupTool/extract.c @@ -19,36 +19,9 @@ */ #include -#include +#include #include "miniz\miniz.h" -PVOID GetZipResourceData( - _In_ PULONG resourceLength - ) -{ - HRSRC resourceHandle = NULL; - HGLOBAL resourceData; - PVOID resourceBuffer = NULL; - - if (!(resourceHandle = FindResource(PhInstanceHandle, MAKEINTRESOURCE(IDR_BIN_DATA), RT_RCDATA))) - goto CleanupExit; - - *resourceLength = SizeofResource(PhInstanceHandle, resourceHandle); - - if (!(resourceData = LoadResource(PhInstanceHandle, resourceHandle))) - goto CleanupExit; - - if (!(resourceBuffer = LockResource(resourceData))) - goto CleanupExit; - -CleanupExit: - - if (resourceHandle) - FreeResource(resourceHandle); - - return resourceBuffer; -} - BOOLEAN SetupExtractBuild( _In_ PPH_SETUP_CONTEXT Context ) @@ -58,16 +31,13 @@ BOOLEAN SetupExtractBuild( ULONG64 currentLength = 0; mz_zip_archive zip_archive = { 0 }; PPH_STRING extractPath = NULL; - SYSTEM_INFO info; - - GetNativeSystemInfo(&info); #ifdef PH_BUILD_API ULONG resourceLength; - PVOID resourceBuffer; + PVOID resourceBuffer = NULL; - if (!(resourceBuffer = GetZipResourceData(&resourceLength))) - goto CleanupExit; + if (!PhLoadResource(PhInstanceHandle, MAKEINTRESOURCE(IDR_BIN_DATA), RT_RCDATA, &resourceLength, &resourceBuffer)) + return FALSE; if (!(status = mz_zip_reader_init_mem(&zip_archive, resourceBuffer, resourceLength, 0))) goto CleanupExit; @@ -99,7 +69,7 @@ BOOLEAN SetupExtractBuild( fileName = PhConvertUtf8ToUtf16(zipFileStat.m_filename); - if (info.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) + if (USER_SHARED_DATA->NativeProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) { if (PhStartsWithString2(fileName, L"x32\\", TRUE)) continue; @@ -145,7 +115,7 @@ BOOLEAN SetupExtractBuild( if (PhFindStringInString(fileName, 0, L"usernotesdb.xml") != -1) continue; - if (info.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) + if (USER_SHARED_DATA->NativeProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) { if (PhStartsWithString2(fileName, L"x32\\", TRUE)) continue; @@ -264,15 +234,29 @@ BOOLEAN SetupExtractBuild( mz_free(buffer); } - mz_zip_reader_end(&zip_archive); - if (extractPath) - PhDereferenceObject(extractPath); + { + mz_zip_reader_end(&zip_archive); + +#ifdef PH_BUILD_API + if (resourceBuffer) + PhFree(resourceBuffer); +#endif + if (extractPath) + PhDereferenceObject(extractPath); + } + return TRUE; CleanupExit: mz_zip_reader_end(&zip_archive); + +#ifdef PH_BUILD_API + if (resourceBuffer) + PhFree(resourceBuffer); +#endif if (extractPath) PhDereferenceObject(extractPath); + return FALSE; } diff --git a/tools/CustomSetupTool/CustomSetupTool/include/setup.h b/tools/CustomSetupTool/CustomSetupTool/include/setup.h index 5e025039333f..f0625c8809a5 100644 --- a/tools/CustomSetupTool/CustomSetupTool/include/setup.h +++ b/tools/CustomSetupTool/CustomSetupTool/include/setup.h @@ -33,7 +33,7 @@ #include #include #include -#include +#include #include #include diff --git a/tools/CustomSetupTool/CustomSetupTool/include/appsup.h b/tools/CustomSetupTool/CustomSetupTool/include/setupsup.h similarity index 92% rename from tools/CustomSetupTool/CustomSetupTool/include/appsup.h rename to tools/CustomSetupTool/CustomSetupTool/include/setupsup.h index 3f0c27bb759e..876bc9cbe89e 100644 --- a/tools/CustomSetupTool/CustomSetupTool/include/appsup.h +++ b/tools/CustomSetupTool/CustomSetupTool/include/setupsup.h @@ -40,10 +40,6 @@ PPH_STRING SetupFindInstallDirectory( VOID ); -PVOID ExtractResourceToBuffer( - _In_ PWSTR Resource - ); - VOID SetupInitializeFont( _In_ HWND ControlHandle, _In_ LONG Height, @@ -77,4 +73,10 @@ BOOLEAN ShutdownProcessHacker( VOID ); +NTSTATUS +QueryProcessesUsingVolumeOrFile( + _In_ HANDLE VolumeOrFileHandle, + _Out_ PFILE_PROCESS_IDS_USING_FILE_INFORMATION *Information + ); + #endif diff --git a/tools/CustomSetupTool/CustomSetupTool/licencepage.c b/tools/CustomSetupTool/CustomSetupTool/licencepage.c index 87c3bdbe90c1..aff021b833a9 100644 --- a/tools/CustomSetupTool/CustomSetupTool/licencepage.c +++ b/tools/CustomSetupTool/CustomSetupTool/licencepage.c @@ -45,17 +45,18 @@ INT_PTR CALLBACK SetupPropPage2_WndProc( switch (uMsg) { case WM_INITDIALOG: - { - PSTR resourceBuffer; + { + ULONG resourceLength; + PVOID resourceBuffer; PPH_STRING eulaTextString; SetupInitializeFont(GetDlgItem(hwndDlg, IDC_MAINHEADER), -17, FW_SEMIBOLD); SetupInitializeFont(GetDlgItem(hwndDlg, IDC_SUBHEADER), -12, FW_NORMAL); SetupInitializeFont(GetDlgItem(hwndDlg, IDC_EDIT1), -12, FW_NORMAL); - if (resourceBuffer = ExtractResourceToBuffer(MAKEINTRESOURCE(IDR_LICENCE_DATA))) + if (PhLoadResource(PhInstanceHandle, MAKEINTRESOURCE(IDR_LICENCE_DATA), RT_RCDATA, &resourceLength, &resourceBuffer)) { - if (eulaTextString = PhConvertUtf8ToUtf16(resourceBuffer)) + if (eulaTextString = PhConvertUtf8ToUtf16Ex(resourceBuffer, resourceLength)) { SetWindowText(GetDlgItem(hwndDlg, IDC_EDIT1), eulaTextString->Buffer); PhDereferenceObject(eulaTextString); diff --git a/tools/CustomSetupTool/CustomSetupTool/main.c b/tools/CustomSetupTool/CustomSetupTool/main.c index b1327e184520..5177477843b2 100644 --- a/tools/CustomSetupTool/CustomSetupTool/main.c +++ b/tools/CustomSetupTool/CustomSetupTool/main.c @@ -220,8 +220,17 @@ VOID SetupInitializeMutant( HANDLE mutantHandle; OBJECT_ATTRIBUTES oa; UNICODE_STRING mutantName; + PPH_STRING objectName; + PH_FORMAT format[4]; + + PhInitFormatS(&format[0], L"PhSetupWindow_"); + PhInitFormatU(&format[1], NtCurrentPeb()->SessionId); + PhInitFormatS(&format[2], L"_"); + PhInitFormatU(&format[3], HandleToUlong(NtCurrentProcessId())); + + objectName = PhFormat(format, 4, 16); + PhStringRefToUnicodeString(&objectName->sr, &mutantName); - RtlInitUnicodeString(&mutantName, L"PhSetupMutant"); InitializeObjectAttributes( &oa, &mutantName, @@ -230,7 +239,9 @@ VOID SetupInitializeMutant( NULL ); - NtCreateMutant(&mutantHandle, MUTANT_ALL_ACCESS, &oa, FALSE); + NtCreateMutant(&mutantHandle, MUTANT_ALL_ACCESS, &oa, TRUE); + + PhDereferenceObject(objectName); } INT WINAPI wWinMain( diff --git a/tools/CustomSetupTool/CustomSetupTool/setup.c b/tools/CustomSetupTool/CustomSetupTool/setup.c index d914e1d90444..399b0642b55d 100644 --- a/tools/CustomSetupTool/CustomSetupTool/setup.c +++ b/tools/CustomSetupTool/CustomSetupTool/setup.c @@ -21,7 +21,7 @@ */ #include -#include +#include #include PH_STRINGREF UninstallKeyName = PH_STRINGREF_INIT(L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\ProcessHacker"); diff --git a/tools/CustomSetupTool/CustomSetupTool/startpage.c b/tools/CustomSetupTool/CustomSetupTool/startpage.c index 17a087b8664c..199161b43be8 100644 --- a/tools/CustomSetupTool/CustomSetupTool/startpage.c +++ b/tools/CustomSetupTool/CustomSetupTool/startpage.c @@ -108,9 +108,9 @@ INT_PTR CALLBACK SetupPropPage1_WndProc( { case PSN_SETACTIVE: { -#ifdef _DEBUG - PostMessage(context->DialogHandle, PSM_SETCURSELID, 0, IDD_DIALOG3); -#endif +//#ifdef _DEBUG +// PostMessage(context->DialogHandle, PSM_SETCURSELID, 0, IDD_DIALOG3); +//#endif // Reset the button state. PropSheet_SetWizButtons(context->DialogHandle, PSWIZB_NEXT); } diff --git a/tools/CustomSetupTool/CustomSetupTool/uninstall.c b/tools/CustomSetupTool/CustomSetupTool/uninstall.c index 697576a43c22..f78b5cbb6b86 100644 --- a/tools/CustomSetupTool/CustomSetupTool/uninstall.c +++ b/tools/CustomSetupTool/CustomSetupTool/uninstall.c @@ -19,7 +19,7 @@ */ #include -#include +#include #include #define WM_TASKDIALOGINIT (WM_APP + 550) diff --git a/tools/CustomSetupTool/CustomSetupTool/update.c b/tools/CustomSetupTool/CustomSetupTool/update.c index 47f46f81e0ce..a45fcc04ed41 100644 --- a/tools/CustomSetupTool/CustomSetupTool/update.c +++ b/tools/CustomSetupTool/CustomSetupTool/update.c @@ -19,7 +19,7 @@ */ #include -#include +#include #define WM_TASKDIALOGINIT (WM_APP + 550) HWND UpdateDialogHandle = NULL; From 8a4641584ec32d7af4fad3df1821086e568a677a Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 5 Feb 2018 12:23:18 +1100 Subject: [PATCH 0776/2058] Fix single instance session check --- ProcessHacker/main.c | 44 ++++++++++++++++++++++++++------------------ tools/peview/main.c | 13 ++++++++----- 2 files changed, 34 insertions(+), 23 deletions(-) diff --git a/ProcessHacker/main.c b/ProcessHacker/main.c index e2afe98cf44e..757b52f15073 100644 --- a/ProcessHacker/main.c +++ b/ProcessHacker/main.c @@ -281,12 +281,14 @@ INT WINAPI wWinMain( OBJECT_ATTRIBUTES oa; UNICODE_STRING mutantName; PPH_STRING objectName; - PH_FORMAT format[2]; + PH_FORMAT format[4]; - PhInitFormatS(&format[0], L"PhMutant_"); - PhInitFormatU(&format[1], HandleToUlong(NtCurrentProcessId())); + PhInitFormatS(&format[0], L"PhMainWindow_"); + PhInitFormatU(&format[1], NtCurrentPeb()->SessionId); + PhInitFormatS(&format[2], L"_"); + PhInitFormatU(&format[3], HandleToUlong(NtCurrentProcessId())); - objectName = PhFormat(format, 2, 16); + objectName = PhFormat(format, 4, 16); PhStringRefToUnicodeString(&objectName->sr, &mutantName); InitializeObjectAttributes( @@ -297,7 +299,7 @@ INT WINAPI wWinMain( NULL ); - NtCreateMutant(&mutantHandle, MUTANT_ALL_ACCESS, &oa, FALSE); + NtCreateMutant(&mutantHandle, MUTANT_ALL_ACCESS, &oa, TRUE); PhDereferenceObject(objectName); } @@ -461,21 +463,27 @@ static BOOLEAN NTAPI PhpPreviousInstancesCallback( _In_opt_ PVOID Context ) { - ULONG64 processId64; - PH_STRINGREF firstPart; - PH_STRINGREF secondPart; - - if ( - PhStartsWithStringRef2(Name, L"PhMutant_", TRUE) && - PhSplitStringRefAtChar(Name, L'_', &firstPart, &secondPart) && - PhStringToInteger64(&secondPart, 10, &processId64) - ) + if (PhStartsWithStringRef2(Name, L"PhMainWindow_", TRUE)) { HWND hwnd; - - hwnd = PhGetProcessMainWindowEx((HANDLE)processId64, NULL, FALSE); - - if (hwnd) + ULONG64 sessionId64; + ULONG64 processId64; + PH_STRINGREF remaining; + PH_STRINGREF sessionIdPart; + PH_STRINGREF processIdPart; + + if (!PhSplitStringRefAtChar(Name, L'_', &remaining, &remaining)) + return TRUE; + if (!PhSplitStringRefAtChar(&remaining, L'_', &sessionIdPart, &processIdPart)) + return TRUE; + if (!PhStringToInteger64(&sessionIdPart, 10, &sessionId64)) + return TRUE; + if (!PhStringToInteger64(&processIdPart, 10, &processId64)) + return TRUE; + if (NtCurrentPeb()->SessionId != sessionId64) + return TRUE; + + if (hwnd = PhGetProcessMainWindowEx(UlongToHandle((ULONG)processId64), NULL, FALSE)) { ULONG_PTR result; diff --git a/tools/peview/main.c b/tools/peview/main.c index 73988a910c25..86c387a4427c 100644 --- a/tools/peview/main.c +++ b/tools/peview/main.c @@ -61,12 +61,14 @@ INT WINAPI wWinMain( OBJECT_ATTRIBUTES oa; UNICODE_STRING mutantName; PPH_STRING objectName; - PH_FORMAT format[2]; + PH_FORMAT format[4]; - PhInitFormatS(&format[0], L"PeViewer_"); - PhInitFormatU(&format[1], HandleToUlong(NtCurrentProcessId())); + PhInitFormatS(&format[0], L"PeViewerWindow_"); + PhInitFormatU(&format[1], NtCurrentPeb()->SessionId); + PhInitFormatS(&format[2], L"_"); + PhInitFormatU(&format[3], HandleToUlong(NtCurrentProcessId())); - objectName = PhFormat(format, 2, 16); + objectName = PhFormat(format, 4, 16); PhStringRefToUnicodeString(&objectName->sr, &mutantName); InitializeObjectAttributes( @@ -77,7 +79,8 @@ INT WINAPI wWinMain( NULL ); - NtCreateMutant(&mutantHandle, MUTANT_ALL_ACCESS, &oa, FALSE); + NtCreateMutant(&mutantHandle, MUTANT_ALL_ACCESS, &oa, TRUE); + PhDereferenceObject(objectName); } From 5cb8e7a2b6f243cf363b3decd1d0f2403cab6ad2 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 5 Feb 2018 14:08:20 +1100 Subject: [PATCH 0777/2058] SetupTool: Fix previous version check --- tools/CustomSetupTool/CustomSetupTool/appsup.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/CustomSetupTool/CustomSetupTool/appsup.c b/tools/CustomSetupTool/CustomSetupTool/appsup.c index dac67fa7e4f4..4e2606e6c35c 100644 --- a/tools/CustomSetupTool/CustomSetupTool/appsup.c +++ b/tools/CustomSetupTool/CustomSetupTool/appsup.c @@ -454,6 +454,8 @@ static BOOLEAN NTAPI PhpPreviousInstancesCallback( return TRUE; if (!PhStringToInteger64(&processIdPart, 10, &processId64)) return TRUE; + if (UlongToHandle((ULONG)processId64) == NtCurrentProcessId()) + return TRUE; PhOpenProcess( &processHandle, From 505e37f86535d08a72b97fd2c099f889779014c2 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 5 Feb 2018 17:17:41 +1100 Subject: [PATCH 0778/2058] Fix incorrect PEB offsets --- phnt/include/ntpebteb.h | 10 +++++++++- phnt/include/ntpsapi.h | 2 +- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/phnt/include/ntpebteb.h b/phnt/include/ntpebteb.h index e6f0a82e372e..10e458f7ada9 100644 --- a/phnt/include/ntpebteb.h +++ b/phnt/include/ntpebteb.h @@ -124,7 +124,7 @@ typedef struct _PEB ULONG NumberOfProcessors; ULONG NtGlobalFlag; - LARGE_INTEGER CriticalSectionTimeout; + ULARGE_INTEGER CriticalSectionTimeout; SIZE_T HeapSegmentReserve; SIZE_T HeapSegmentCommit; SIZE_T HeapDeCommitTotalFreeThreshold; @@ -200,6 +200,14 @@ typedef struct _PEB ULONG CloudFileFlags; } PEB, *PPEB; +#ifdef _WIN64 +C_ASSERT(FIELD_OFFSET(PEB, SessionId) == 0x2C0); +C_ASSERT(sizeof(PEB) == 0x7B0); +#else +C_ASSERT(FIELD_OFFSET(PEB, SessionId) == 0x1D4); +C_ASSERT(sizeof(PEB) == 0x468); +#endif + #define GDI_BATCH_BUFFER_SIZE 310 typedef struct _GDI_TEB_BATCH diff --git a/phnt/include/ntpsapi.h b/phnt/include/ntpsapi.h index e134eb368b0c..ab6e2dfc4c73 100644 --- a/phnt/include/ntpsapi.h +++ b/phnt/include/ntpsapi.h @@ -44,7 +44,7 @@ #define GDI_HANDLE_BUFFER_SIZE32 34 #define GDI_HANDLE_BUFFER_SIZE64 60 -#ifndef WIN64 +#ifndef _WIN64 #define GDI_HANDLE_BUFFER_SIZE GDI_HANDLE_BUFFER_SIZE32 #else #define GDI_HANDLE_BUFFER_SIZE GDI_HANDLE_BUFFER_SIZE64 From a9a0fb3da012983965a1b05a093a2ee0f5d7dc1c Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 6 Feb 2018 15:18:18 +1100 Subject: [PATCH 0779/2058] Setup: Fix 32bit install #236 --- tools/CustomSetupTool/CustomSetupTool/extract.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tools/CustomSetupTool/CustomSetupTool/extract.c b/tools/CustomSetupTool/CustomSetupTool/extract.c index 861501f39a9a..2c05c6dd9bf2 100644 --- a/tools/CustomSetupTool/CustomSetupTool/extract.c +++ b/tools/CustomSetupTool/CustomSetupTool/extract.c @@ -31,6 +31,9 @@ BOOLEAN SetupExtractBuild( ULONG64 currentLength = 0; mz_zip_archive zip_archive = { 0 }; PPH_STRING extractPath = NULL; + SYSTEM_INFO info; + + GetNativeSystemInfo(&info); #ifdef PH_BUILD_API ULONG resourceLength; @@ -69,7 +72,7 @@ BOOLEAN SetupExtractBuild( fileName = PhConvertUtf8ToUtf16(zipFileStat.m_filename); - if (USER_SHARED_DATA->NativeProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) + if (info.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) { if (PhStartsWithString2(fileName, L"x32\\", TRUE)) continue; @@ -115,7 +118,7 @@ BOOLEAN SetupExtractBuild( if (PhFindStringInString(fileName, 0, L"usernotesdb.xml") != -1) continue; - if (USER_SHARED_DATA->NativeProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) + if (info.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) { if (PhStartsWithString2(fileName, L"x32\\", TRUE)) continue; From 5612e9cb9235e5900119bfbbe2b7a9e3ec4e3879 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 6 Feb 2018 17:25:53 +1100 Subject: [PATCH 0780/2058] Fix runas assert --- ProcessHacker/mainwnd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index 65c5e9ce78d9..27b37e528790 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -1857,7 +1857,7 @@ BOOLEAN PhMwpOnNotify( else { // Create the escaped execute string. - PhMoveReference(&executeString, fileName); + executeString = PhReferenceObject(fileName); } PhDereferenceObject(fileName); From c776627a7838c22287ff40f23e1ca0f3528695d0 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 6 Feb 2018 20:01:08 +1100 Subject: [PATCH 0781/2058] Fix token page properties and coloring --- ProcessHacker/tokprp.c | 92 +++++++++++++++++++++++++----------------- 1 file changed, 54 insertions(+), 38 deletions(-) diff --git a/ProcessHacker/tokprp.c b/ProcessHacker/tokprp.c index 05b19f7160e3..36e4432d2547 100644 --- a/ProcessHacker/tokprp.c +++ b/ProcessHacker/tokprp.c @@ -3,7 +3,7 @@ * token properties * * Copyright (C) 2010-2012 wj32 - * Copyright (C) 2017 dmex + * Copyright (C) 2017-2018 dmex * * This file is part of Process Hacker. * @@ -233,15 +233,47 @@ PPH_STRING PhGetGroupAttributesString( _In_ BOOLEAN Restricted ) { - PWSTR baseString; PPH_STRING string; if (Attributes & SE_GROUP_INTEGRITY) { if (Attributes & SE_GROUP_INTEGRITY_ENABLED) - string = PhCreateString(L"Integrity"); + string = PhReferenceEmptyString(); + else + string = PhCreateString(L"Disabled"); + } + else + { + if (Attributes & SE_GROUP_ENABLED_BY_DEFAULT) + string = PhCreateString(L"Default Enabled"); + else if (Attributes & SE_GROUP_ENABLED) + string = PhReferenceEmptyString(); + else + string = PhCreateString(L"Disabled"); + } + + if (Restricted) + { + PPH_STRING prefixString = string; + string = PhConcatStrings2(prefixString->Buffer, L" (restricted)"); + PhDereferenceObject(prefixString); + } + + return string; +} + +PWSTR PhGetGroupDescriptionString( + _In_ ULONG Attributes + ) +{ + PWSTR baseString; + + if (Attributes & SE_GROUP_INTEGRITY) + { + if (Attributes & SE_GROUP_INTEGRITY_ENABLED) + baseString = L"Integrity"; else - string = PhCreateString(L"Integrity (disabled)"); + baseString = NULL; } else { @@ -257,37 +289,12 @@ PPH_STRING PhGetGroupAttributesString( baseString = L"Use for deny only"; else baseString = NULL; - - if (!baseString) - { - if (Attributes & SE_GROUP_ENABLED_BY_DEFAULT) - string = PhCreateString(L"Default enabled"); - else if (Attributes & SE_GROUP_ENABLED) - string = PhReferenceEmptyString(); - else - string = PhCreateString(L"Disabled"); - } - else - { - if (Attributes & SE_GROUP_ENABLED_BY_DEFAULT) - string = PhConcatStrings2(baseString, L" (default enabled)"); - else if (Attributes & SE_GROUP_ENABLED) - string = PhCreateString(baseString); - else - string = PhConcatStrings2(baseString, L" (disabled)"); - } } - if (Restricted) - { - PPH_STRING prefixString = string; - string = PhConcatStrings2(prefixString->Buffer, L" (restricted)"); - PhDereferenceObject(prefixString); - } - - return string; + return baseString; } + COLORREF PhGetGroupAttributesColor( _In_ ULONG Attributes ) @@ -295,15 +302,15 @@ COLORREF PhGetGroupAttributesColor( if (Attributes & SE_GROUP_INTEGRITY) { if (Attributes & SE_GROUP_INTEGRITY_ENABLED) - return RGB(0xe0, 0xf0, 0xe0); + return RGB(0xff, 0xf0, 0xc0); else return GetSysColor(COLOR_WINDOW); } if (Attributes & SE_GROUP_ENABLED_BY_DEFAULT) - return RGB(0xe0, 0xf0, 0xe0); + return RGB(0xc0, 0xf0, 0xc0); else if (Attributes & SE_GROUP_ENABLED) - return GetSysColor(COLOR_WINDOW); + return RGB(0x00, 0xff, 0x7f); else return RGB(0xf0, 0xe0, 0xe0); } @@ -315,7 +322,7 @@ COLORREF PhGetPrivilegeAttributesColor( if (Attributes & SE_PRIVILEGE_ENABLED_BY_DEFAULT) return RGB(0xc0, 0xf0, 0xc0); else if (Attributes & SE_PRIVILEGE_ENABLED) - return RGB(0xe0, 0xf0, 0xe0); + return RGB(0x00, 0xff, 0x7f); else return RGB(0xf0, 0xe0, 0xe0); } @@ -395,6 +402,7 @@ VOID PhpUpdateSidsFromTokenGroups( INT lvItemIndex; PPH_STRING fullName; PPH_STRING attributesString; + PWSTR descriptionString; if (!(fullName = PhGetSidFullName(Groups->Groups[i].Sid, TRUE, NULL))) fullName = PhSidToStringSid(Groups->Groups[i].Sid); @@ -416,10 +424,18 @@ VOID PhpUpdateSidsFromTokenGroups( fullName->Buffer, lvitem ); - attributesString = PhGetGroupAttributesString(Groups->Groups[i].Attributes, Restricted); - PhSetListViewSubItem(ListViewHandle, lvItemIndex, PH_PROCESS_TOKEN_INDEX_STATUS, attributesString->Buffer); - PhDereferenceObject(attributesString); + if (attributesString = PhGetGroupAttributesString(Groups->Groups[i].Attributes, Restricted)) + { + PhSetListViewSubItem(ListViewHandle, lvItemIndex, PH_PROCESS_TOKEN_INDEX_STATUS, PhGetString(attributesString)); + PhDereferenceObject(attributesString); + } + + if (descriptionString = PhGetGroupDescriptionString(Groups->Groups[i].Attributes)) + { + PhSetListViewSubItem(ListViewHandle, lvItemIndex, PH_PROCESS_TOKEN_INDEX_DESCRIPTION, descriptionString); + } + PhDereferenceObject(fullName); } } From 3c1cb4fa7af4591c2ead3d03042116b74c2bfddb Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 6 Feb 2018 21:15:56 +1100 Subject: [PATCH 0782/2058] Fix instance bug updating/running with multiple logged on users --- ProcessHacker/main.c | 110 ++++++++++++------ .../CustomSetupTool/CustomSetupTool/appsup.c | 110 +++++++++--------- tools/CustomSetupTool/CustomSetupTool/main.c | 24 +--- tools/peview/main.c | 24 +--- 4 files changed, 142 insertions(+), 126 deletions(-) diff --git a/ProcessHacker/main.c b/ProcessHacker/main.c index 757b52f15073..8f3f788481a4 100644 --- a/ProcessHacker/main.c +++ b/ProcessHacker/main.c @@ -277,31 +277,19 @@ INT WINAPI wWinMain( // Create a mutant for the installer. { - HANDLE mutantHandle; - OBJECT_ATTRIBUTES oa; - UNICODE_STRING mutantName; - PPH_STRING objectName; - PH_FORMAT format[4]; - - PhInitFormatS(&format[0], L"PhMainWindow_"); - PhInitFormatU(&format[1], NtCurrentPeb()->SessionId); - PhInitFormatS(&format[2], L"_"); - PhInitFormatU(&format[3], HandleToUlong(NtCurrentProcessId())); - - objectName = PhFormat(format, 4, 16); - PhStringRefToUnicodeString(&objectName->sr, &mutantName); + static UNICODE_STRING objectNameUs = RTL_CONSTANT_STRING(L"PhMutant"); + OBJECT_ATTRIBUTES objectAttributes; + HANDLE objectHandle; InitializeObjectAttributes( - &oa, - &mutantName, + &objectAttributes, + &objectNameUs, OBJ_CASE_INSENSITIVE, PhGetNamespaceHandle(), NULL ); - NtCreateMutant(&mutantHandle, MUTANT_ALL_ACCESS, &oa, TRUE); - - PhDereferenceObject(objectName); + NtCreateMutant(&objectHandle, MUTANT_ALL_ACCESS, &objectAttributes, TRUE); } // Set the default priority. @@ -463,27 +451,68 @@ static BOOLEAN NTAPI PhpPreviousInstancesCallback( _In_opt_ PVOID Context ) { - if (PhStartsWithStringRef2(Name, L"PhMainWindow_", TRUE)) + static PH_STRINGREF objectNameSr = PH_STRINGREF_INIT(L"PhMutant"); + HANDLE objectHandle; + UNICODE_STRING objectNameUs; + OBJECT_ATTRIBUTES objectAttributes; + MUTANT_OWNER_INFORMATION objectInfo; + + if (!PhEqualStringRef(Name, &objectNameSr, FALSE)) + return TRUE; + if (!PhStringRefToUnicodeString(Name, &objectNameUs)) + return TRUE; + + InitializeObjectAttributes( + &objectAttributes, + &objectNameUs, + OBJ_CASE_INSENSITIVE, + PhGetNamespaceHandle(), + NULL + ); + + if (!NT_SUCCESS(NtOpenMutant( + &objectHandle, + MUTANT_QUERY_STATE, + &objectAttributes + ))) + { + return TRUE; + } + + if (NT_SUCCESS(NtQueryMutant( + objectHandle, + MutantOwnerInformation, + &objectInfo, + sizeof(MUTANT_OWNER_INFORMATION), + NULL + ))) { HWND hwnd; - ULONG64 sessionId64; - ULONG64 processId64; - PH_STRINGREF remaining; - PH_STRINGREF sessionIdPart; - PH_STRINGREF processIdPart; - - if (!PhSplitStringRefAtChar(Name, L'_', &remaining, &remaining)) - return TRUE; - if (!PhSplitStringRefAtChar(&remaining, L'_', &sessionIdPart, &processIdPart)) - return TRUE; - if (!PhStringToInteger64(&sessionIdPart, 10, &sessionId64)) - return TRUE; - if (!PhStringToInteger64(&processIdPart, 10, &processId64)) - return TRUE; - if (NtCurrentPeb()->SessionId != sessionId64) - return TRUE; - - if (hwnd = PhGetProcessMainWindowEx(UlongToHandle((ULONG)processId64), NULL, FALSE)) + HANDLE processHandle = NULL; + HANDLE tokenHandle = NULL; + PTOKEN_USER tokenCurrent = NULL; + PTOKEN_USER tokenUser = NULL; + + if (objectInfo.ClientId.UniqueProcess == NtCurrentProcessId()) + goto CleanupExit; + if (!NT_SUCCESS(PhOpenProcess(&processHandle, ProcessQueryAccess, objectInfo.ClientId.UniqueProcess))) + goto CleanupExit; + if (!NT_SUCCESS(PhOpenProcessToken(processHandle, TOKEN_QUERY, &tokenHandle))) + goto CleanupExit; + if (!NT_SUCCESS(PhGetTokenUser(tokenHandle, &tokenUser))) + goto CleanupExit; + if (!NT_SUCCESS(PhGetTokenUser(PhGetOwnTokenAttributes().TokenHandle, &tokenCurrent))) + goto CleanupExit; + if (!RtlEqualSid(tokenUser->User.Sid, tokenCurrent->User.Sid)) + goto CleanupExit; + + hwnd = PhGetProcessMainWindowEx( + objectInfo.ClientId.UniqueProcess, + processHandle, + FALSE + ); + + if (hwnd) { ULONG_PTR result; @@ -495,8 +524,15 @@ static BOOLEAN NTAPI PhpPreviousInstancesCallback( RtlExitUserProcess(STATUS_SUCCESS); } } + + CleanupExit: + if (tokenUser) PhFree(tokenUser); + if (tokenCurrent) PhFree(tokenCurrent); + if (tokenHandle) NtClose(tokenHandle); + if (processHandle) NtClose(processHandle); } + NtClose(objectHandle); return TRUE; } diff --git a/tools/CustomSetupTool/CustomSetupTool/appsup.c b/tools/CustomSetupTool/CustomSetupTool/appsup.c index 4e2606e6c35c..bbc367e52209 100644 --- a/tools/CustomSetupTool/CustomSetupTool/appsup.c +++ b/tools/CustomSetupTool/CustomSetupTool/appsup.c @@ -432,76 +432,80 @@ static BOOLEAN NTAPI PhpPreviousInstancesCallback( _In_opt_ PVOID Context ) { - if ( - PhStartsWithStringRef2(Name, L"PhMainWindow_", TRUE) || - PhStartsWithStringRef2(Name, L"PhSetupWindow_", TRUE) || - PhStartsWithStringRef2(Name, L"PeViewerWindow_", TRUE) - ) + HANDLE objectHandle; + UNICODE_STRING objectNameUs; + OBJECT_ATTRIBUTES objectAttributes; + MUTANT_OWNER_INFORMATION objectInfo; + + if (!PhEqualStringRef2(Name, L"PhMutant", TRUE) && + !PhEqualStringRef2(Name, L"PhSetupMutant", TRUE) && + !PhEqualStringRef2(Name, L"PeViewerMutant", TRUE)) + { + return TRUE; + } + + if (!PhStringRefToUnicodeString(Name, &objectNameUs)) + return TRUE; + + InitializeObjectAttributes( + &objectAttributes, + &objectNameUs, + OBJ_CASE_INSENSITIVE, + PhGetNamespaceHandle(), + NULL + ); + + if (!NT_SUCCESS(NtOpenMutant( + &objectHandle, + MUTANT_QUERY_STATE, + &objectAttributes + ))) + { + return TRUE; + } + + if (NT_SUCCESS(NtQueryMutant( + objectHandle, + MutantOwnerInformation, + &objectInfo, + sizeof(MUTANT_OWNER_INFORMATION), + NULL + ))) { - HANDLE processHandle; HWND hwnd; - ULONG64 sessionId64; - ULONG64 processId64; - PH_STRINGREF remaining; - PH_STRINGREF sessionIdPart; - PH_STRINGREF processIdPart; + HANDLE processHandle = NULL; - if (!PhSplitStringRefAtChar(Name, L'_', &remaining, &remaining)) - return TRUE; - if (!PhSplitStringRefAtChar(&remaining, L'_', &sessionIdPart, &processIdPart)) - return TRUE; - if (!PhStringToInteger64(&sessionIdPart, 10, &sessionId64)) - return TRUE; - if (!PhStringToInteger64(&processIdPart, 10, &processId64)) - return TRUE; - if (UlongToHandle((ULONG)processId64) == NtCurrentProcessId()) - return TRUE; + if (objectInfo.ClientId.UniqueProcess == NtCurrentProcessId()) + goto CleanupExit; PhOpenProcess( - &processHandle, - PROCESS_TERMINATE | SYNCHRONIZE, - ULongToHandle((ULONG)processId64) + &processHandle, + ProcessQueryAccess, + objectInfo.ClientId.UniqueProcess + ); + + hwnd = PhGetProcessMainWindowEx( + objectInfo.ClientId.UniqueProcess, + processHandle, + FALSE ); - if (sessionId64 == NtCurrentPeb()->SessionId) + if (hwnd) { - if (hwnd = PhGetProcessMainWindowEx(UlongToHandle((ULONG)processId64), NULL, FALSE)) - { - SendMessageTimeout(hwnd, WM_QUIT, 0, 0, SMTO_BLOCK, 5000, NULL); - } + SendMessageTimeout(hwnd, WM_QUIT, 0, 0, SMTO_BLOCK, 5000, NULL); } if (processHandle) { NtTerminateProcess(processHandle, 1); - NtClose(processHandle); } - } - - { - ULONG64 processId64; - PH_STRINGREF firstPart; - PH_STRINGREF secondPart; - - if (( - PhStartsWithStringRef2(Name, L"PhMutant_", TRUE) || - PhStartsWithStringRef2(Name, L"PhSetupMutant_", TRUE) || - PhStartsWithStringRef2(Name, L"PeViewer_", TRUE) - ) && - PhSplitStringRefAtChar(Name, L'_', &firstPart, &secondPart) && - PhStringToInteger64(&secondPart, 10, &processId64) - ) - { - HANDLE processHandle; - if (NT_SUCCESS(PhOpenProcess(&processHandle, PROCESS_TERMINATE | SYNCHRONIZE, ULongToHandle((ULONG)processId64)))) - { - NtTerminateProcess(processHandle, 1); - NtClose(processHandle); - } - } + CleanupExit: + if (processHandle) NtClose(processHandle); } + NtClose(objectHandle); + return TRUE; } diff --git a/tools/CustomSetupTool/CustomSetupTool/main.c b/tools/CustomSetupTool/CustomSetupTool/main.c index 5177477843b2..bf23797055c3 100644 --- a/tools/CustomSetupTool/CustomSetupTool/main.c +++ b/tools/CustomSetupTool/CustomSetupTool/main.c @@ -217,31 +217,19 @@ VOID SetupInitializeMutant( VOID ) { - HANDLE mutantHandle; - OBJECT_ATTRIBUTES oa; - UNICODE_STRING mutantName; - PPH_STRING objectName; - PH_FORMAT format[4]; - - PhInitFormatS(&format[0], L"PhSetupWindow_"); - PhInitFormatU(&format[1], NtCurrentPeb()->SessionId); - PhInitFormatS(&format[2], L"_"); - PhInitFormatU(&format[3], HandleToUlong(NtCurrentProcessId())); - - objectName = PhFormat(format, 4, 16); - PhStringRefToUnicodeString(&objectName->sr, &mutantName); + static UNICODE_STRING objectNameUs = RTL_CONSTANT_STRING(L"PhSetupMutant"); + OBJECT_ATTRIBUTES objectAttributes; + HANDLE objectHandle; InitializeObjectAttributes( - &oa, - &mutantName, + &objectAttributes, + &objectNameUs, OBJ_CASE_INSENSITIVE, PhGetNamespaceHandle(), NULL ); - NtCreateMutant(&mutantHandle, MUTANT_ALL_ACCESS, &oa, TRUE); - - PhDereferenceObject(objectName); + NtCreateMutant(&objectHandle, MUTANT_ALL_ACCESS, &objectAttributes, TRUE); } INT WINAPI wWinMain( diff --git a/tools/peview/main.c b/tools/peview/main.c index 86c387a4427c..7d991176f18c 100644 --- a/tools/peview/main.c +++ b/tools/peview/main.c @@ -57,31 +57,19 @@ INT WINAPI wWinMain( // Create a mutant for the installer. { - HANDLE mutantHandle; - OBJECT_ATTRIBUTES oa; - UNICODE_STRING mutantName; - PPH_STRING objectName; - PH_FORMAT format[4]; - - PhInitFormatS(&format[0], L"PeViewerWindow_"); - PhInitFormatU(&format[1], NtCurrentPeb()->SessionId); - PhInitFormatS(&format[2], L"_"); - PhInitFormatU(&format[3], HandleToUlong(NtCurrentProcessId())); - - objectName = PhFormat(format, 4, 16); - PhStringRefToUnicodeString(&objectName->sr, &mutantName); + static UNICODE_STRING objectNameUs = RTL_CONSTANT_STRING(L"PeViewerMutant"); + OBJECT_ATTRIBUTES objectAttributes; + HANDLE objectHandle; InitializeObjectAttributes( - &oa, - &mutantName, + &objectAttributes, + &objectNameUs, OBJ_CASE_INSENSITIVE, PhGetNamespaceHandle(), NULL ); - NtCreateMutant(&mutantHandle, MUTANT_ALL_ACCESS, &oa, TRUE); - - PhDereferenceObject(objectName); + NtCreateMutant(&objectHandle, MUTANT_ALL_ACCESS, &objectAttributes, TRUE); } PhGuiSupportInitialization(); From 1f45ce9bc164dca54ec1bfa47379b5eaefea5faa Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 6 Feb 2018 21:17:12 +1100 Subject: [PATCH 0783/2058] Fix token highlighting inconsistency --- ProcessHacker/tokprp.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ProcessHacker/tokprp.c b/ProcessHacker/tokprp.c index 36e4432d2547..6ee67424fe8d 100644 --- a/ProcessHacker/tokprp.c +++ b/ProcessHacker/tokprp.c @@ -302,7 +302,7 @@ COLORREF PhGetGroupAttributesColor( if (Attributes & SE_GROUP_INTEGRITY) { if (Attributes & SE_GROUP_INTEGRITY_ENABLED) - return RGB(0xff, 0xf0, 0xc0); + return RGB(0xe0, 0xf0, 0xe0); else return GetSysColor(COLOR_WINDOW); } @@ -310,7 +310,7 @@ COLORREF PhGetGroupAttributesColor( if (Attributes & SE_GROUP_ENABLED_BY_DEFAULT) return RGB(0xc0, 0xf0, 0xc0); else if (Attributes & SE_GROUP_ENABLED) - return RGB(0x00, 0xff, 0x7f); + return GetSysColor(COLOR_WINDOW); else return RGB(0xf0, 0xe0, 0xe0); } @@ -322,7 +322,7 @@ COLORREF PhGetPrivilegeAttributesColor( if (Attributes & SE_PRIVILEGE_ENABLED_BY_DEFAULT) return RGB(0xc0, 0xf0, 0xc0); else if (Attributes & SE_PRIVILEGE_ENABLED) - return RGB(0x00, 0xff, 0x7f); + return RGB(0xe0, 0xf0, 0xe0); else return RGB(0xf0, 0xe0, 0xe0); } @@ -581,7 +581,7 @@ INT_PTR CALLBACK PhpTokenPageProc( PhSetExtendedListView(tokenPageContext->ListViewHandle); ExtendedListView_SetItemColorFunction(tokenPageContext->ListViewHandle, PhpTokenGroupColorFunction); - PhLoadListViewColumnsFromSetting(L"TokenGroupsListViewColumns", tokenPageContext->ListViewHandle); + PhLoadListViewColumnsFromSetting(L"TokenGroupsListViewColumns", tokenPageContext->ListViewHandle); ListView_EnableGroupView(tokenPageContext->ListViewHandle, TRUE); PhAddListViewGroup(tokenPageContext->ListViewHandle, PH_PROCESS_TOKEN_CATEGORY_PRIVILEGES, L"Privileges"); From dee06e37dc654fe47f4180bb46545bf7c5944a79 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 6 Feb 2018 22:19:57 +1100 Subject: [PATCH 0784/2058] Fix find handles window handle type dropdown --- ProcessHacker/findobj.c | 35 ++++++++++++++++++++++++++++++----- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/ProcessHacker/findobj.c b/ProcessHacker/findobj.c index ff8692d61265..85714d3d42ed 100644 --- a/ProcessHacker/findobj.c +++ b/ProcessHacker/findobj.c @@ -3,7 +3,7 @@ * object search * * Copyright (C) 2010-2016 wj32 - * Copyright (C) 2017 dmex + * Copyright (C) 2017-2018 dmex * * This file is part of Process Hacker. * @@ -651,11 +651,36 @@ VOID PhpPopulateObjectTypes( // Sort the object types. qsort(objectTypeList->Items, objectTypeList->Count, sizeof(PVOID), PhpStringObjectTypeCompare); - // Add the types to the object filter combobox. - for (ULONG i = 0; i < objectTypeList->Count; i++) { - ComboBox_AddString(FilterTypeCombo, PhGetString(objectTypeList->Items[i])); - PhDereferenceObject(objectTypeList->Items[i]); + LONG maxLength; + HDC screenDc; + + maxLength = 0; + screenDc = GetDC(FilterTypeCombo); + + SendMessage(FilterTypeCombo, WM_SETFONT, (WPARAM)PhApplicationFont, TRUE); + + for (ULONG i = 0; i < objectTypeList->Count; i++) + { + PPH_STRING entry = objectTypeList->Items[i]; + SIZE textSize; + + if (GetTextExtentPoint32(screenDc, entry->Buffer, (ULONG)entry->Length / sizeof(WCHAR), &textSize)) + { + if (textSize.cx > maxLength) + maxLength = textSize.cx; + } + + ComboBox_AddString(FilterTypeCombo, PhGetString(objectTypeList->Items[i])); + PhDereferenceObject(objectTypeList->Items[i]); + } + + ReleaseDC(FilterTypeCombo, screenDc); + + if (maxLength) + { + SendMessage(FilterTypeCombo, CB_SETDROPPEDWIDTH, maxLength, 0); + } } PhDereferenceObject(objectTypeList); From f38f7154b5a26835f5ad6c6c9efea11ceefe4da6 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 6 Feb 2018 22:34:25 +1100 Subject: [PATCH 0785/2058] Fix handle type combobox focus --- ProcessHacker/findobj.c | 38 ++++++++++++++++++++++++++++---------- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/ProcessHacker/findobj.c b/ProcessHacker/findobj.c index 85714d3d42ed..3d5914e88bbb 100644 --- a/ProcessHacker/findobj.c +++ b/ProcessHacker/findobj.c @@ -56,6 +56,9 @@ typedef struct _PH_HANDLE_SEARCH_CONTEXT HWND WindowHandle; HWND TreeNewHandle; + HWND TypeWindowHandle; + HWND SearchWindowHandle; + ULONG TreeNewSortColumn; PH_SORT_ORDER TreeNewSortOrder; PPH_HASHTABLE NodeHashtable; @@ -1144,16 +1147,21 @@ INT_PTR CALLBACK PhpFindObjectsDlgProc( context->WindowHandle = hwndDlg; context->TreeNewHandle = GetDlgItem(hwndDlg, IDC_TREELIST); + context->TypeWindowHandle = GetDlgItem(hwndDlg, IDC_FILTERTYPE); + context->SearchWindowHandle = GetDlgItem(hwndDlg, IDC_FILTER); + + PhCenterWindow(hwndDlg, NULL); + PhRegisterDialog(hwndDlg); - PhCreateSearchControl(hwndDlg, GetDlgItem(hwndDlg, IDC_FILTER), L"Find Handles or DLLs"); + PhCreateSearchControl(hwndDlg, context->SearchWindowHandle, L"Find Handles or DLLs"); - PhpPopulateObjectTypes(GetDlgItem(hwndDlg, IDC_FILTERTYPE)); + PhpPopulateObjectTypes(context->TypeWindowHandle); InitializeHandleObjectTree(context); PhInitializeLayoutManager(&context->LayoutManager, hwndDlg); - PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_FILTERTYPE), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_TOP); - PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_FILTER), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); + PhAddLayoutItem(&context->LayoutManager, context->TypeWindowHandle, NULL, PH_ANCHOR_LEFT | PH_ANCHOR_TOP); + PhAddLayoutItem(&context->LayoutManager, context->SearchWindowHandle, NULL, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_REGEX), NULL, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDOK), NULL, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); PhAddLayoutItem(&context->LayoutManager, context->TreeNewHandle, NULL, PH_ANCHOR_ALL); @@ -1164,9 +1172,6 @@ INT_PTR CALLBACK PhpFindObjectsDlgProc( context->MinimumSize.bottom = 100; MapDialogRect(hwndDlg, &context->MinimumSize); - PhRegisterDialog(hwndDlg); - - PhCenterWindow(hwndDlg, NULL); PhLoadWindowPlacementFromSetting(L"FindObjWindowPosition", L"FindObjWindowSize", hwndDlg); context->SearchResults = PhCreateList(128); @@ -1185,7 +1190,7 @@ INT_PTR CALLBACK PhpFindObjectsDlgProc( ); } - Edit_SetSel(GetDlgItem(hwndDlg, IDC_FILTER), 0, -1); + Edit_SetSel(context->SearchWindowHandle, 0, -1); Button_SetCheck(GetDlgItem(hwndDlg, IDC_REGEX), PhGetIntegerSetting(L"FindObjRegex") ? BST_CHECKED : BST_UNCHECKED); } break; @@ -1271,6 +1276,19 @@ INT_PTR CALLBACK PhpFindObjectsDlgProc( break; case WM_COMMAND: { + if (GET_WM_COMMAND_HWND(wParam, lParam) == context->TypeWindowHandle) + { + switch (GET_WM_COMMAND_CMD(wParam, lParam)) + { + case CBN_SELCHANGE: + { + // Change focus from the dropdown list to the searchbox. + SetFocus(context->SearchWindowHandle); + } + break; + } + } + switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDOK: @@ -1281,8 +1299,8 @@ INT_PTR CALLBACK PhpFindObjectsDlgProc( if (!context->SearchThreadHandle) { - PhMoveReference(&context->SearchString, PhGetWindowText(GetDlgItem(hwndDlg, IDC_FILTER))); - PhMoveReference(&context->SearchTypeString, PhGetWindowText(GetDlgItem(hwndDlg, IDC_FILTERTYPE))); + PhMoveReference(&context->SearchString, PhGetWindowText(context->SearchWindowHandle)); + PhMoveReference(&context->SearchTypeString, PhGetWindowText(context->TypeWindowHandle)); if (context->SearchRegexCompiledExpression) { From e13ce47785f65cb6b7404e67d52c9df1677102a8 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 6 Feb 2018 22:43:42 +1100 Subject: [PATCH 0786/2058] Add debug macro for the UseColorHandleProtected setting --- phlib/native.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/phlib/native.c b/phlib/native.c index e5d80619004c..1373e48883a1 100644 --- a/phlib/native.c +++ b/phlib/native.c @@ -120,6 +120,14 @@ NTSTATUS PhOpenProcess( clientId.UniqueProcess = ProcessId; clientId.UniqueThread = NULL; +#ifdef _DEBUG + if (ProcessId == NtCurrentProcessId()) + { + *ProcessHandle = NtCurrentProcess(); + return STATUS_SUCCESS; + } +#endif + if (KphIsVerified() && (DesiredAccess & KPH_PROCESS_READ_ACCESS) == DesiredAccess) { status = KphOpenProcess( From 6dfc9dd92b6972bbff5b726bfa04e97df609e4f3 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 6 Feb 2018 22:51:13 +1100 Subject: [PATCH 0787/2058] Fix options window parenting --- ProcessHacker/include/phplug.h | 1 + ProcessHacker/options.c | 65 +++++++++++++--------------------- 2 files changed, 25 insertions(+), 41 deletions(-) diff --git a/ProcessHacker/include/phplug.h b/ProcessHacker/include/phplug.h index 02cd6cfb99b8..f7d00fc2e765 100644 --- a/ProcessHacker/include/phplug.h +++ b/ProcessHacker/include/phplug.h @@ -370,6 +370,7 @@ typedef struct _PH_OPTIONS_SECTION PVOID Parameter; HWND DialogHandle; + HTREEITEM TreeItemHandle; // begin_phapppub } PH_OPTIONS_SECTION, *PPH_OPTIONS_SECTION; // end_phapppub diff --git a/ProcessHacker/options.c b/ProcessHacker/options.c index 0992214bbd1d..e9dba405afcc 100644 --- a/ProcessHacker/options.c +++ b/ProcessHacker/options.c @@ -175,7 +175,7 @@ VOID PhShowOptionsDialog( DialogBox( PhInstanceHandle, MAKEINTRESOURCE(IDD_OPTIONS), - ParentWindowHandle, + NULL, PhOptionsDialogProc ); @@ -211,10 +211,10 @@ VOID PhShowOptionsDialog( } } -static HTREEITEM PhpOptionsTreeViewAddItem( +static HTREEITEM PhpTreeViewInsertItem( + _In_opt_ HTREEITEM HandleInsertAfter, _In_ PWSTR Text, - _In_ PVOID Context, - _In_ HTREEITEM InsertAfter + _In_ PVOID Context ) { TV_INSERTSTRUCT insert; @@ -222,7 +222,7 @@ static HTREEITEM PhpOptionsTreeViewAddItem( memset(&insert, 0, sizeof(TV_INSERTSTRUCT)); insert.hParent = TVI_ROOT; - insert.hInsertAfter = InsertAfter; + insert.hInsertAfter = HandleInsertAfter; insert.item.mask = TVIF_TEXT | TVIF_PARAM; insert.item.pszText = Text; insert.item.lParam = (LPARAM)Context; @@ -234,52 +234,36 @@ static VOID PhpOptionsShowHideTreeViewItem( _In_ BOOLEAN Hide ) { - HTREEITEM tvItemGeneral = NULL; - HTREEITEM tvItemAdvanced = NULL; - HTREEITEM tvItemCurrent; - - tvItemCurrent = TreeView_GetRoot(OptionsTreeControl); + static PH_STRINGREF generalName = PH_STRINGREF_INIT(L"General"); + static PH_STRINGREF advancedName = PH_STRINGREF_INIT(L"Advanced"); - while (tvItemCurrent) + if (Hide) { - TVITEM tvItem; - WCHAR buffer[MAX_PATH]; - - tvItem.mask = TVIF_TEXT | TVIF_HANDLE; - tvItem.hItem = tvItemCurrent; - tvItem.cchTextMax = ARRAYSIZE(buffer); - tvItem.pszText = buffer; + PPH_OPTIONS_SECTION advancedSection; - if (TreeView_GetItem(OptionsTreeControl, &tvItem)) + if (advancedSection = PhOptionsFindSection(&advancedName)) { - if (PhEqualStringZ(buffer, L"Advanced", TRUE)) + if (advancedSection->TreeItemHandle) { - tvItemAdvanced = tvItemCurrent; - } - else if (PhEqualStringZ(buffer, L"General", TRUE)) - { - tvItemGeneral = tvItemCurrent; + TreeView_DeleteItem(OptionsTreeControl, advancedSection->TreeItemHandle); + advancedSection->TreeItemHandle = NULL; } } - - tvItemCurrent = TreeView_GetNextSibling(OptionsTreeControl, tvItemCurrent); - } - - if (Hide) - { - if (tvItemAdvanced) - TreeView_DeleteItem(OptionsTreeControl, tvItemAdvanced); } else { - static PH_STRINGREF sectionName = PH_STRINGREF_INIT(L"Advanced"); + PPH_OPTIONS_SECTION generalSection; + PPH_OPTIONS_SECTION advancedSection; + + generalSection = PhOptionsFindSection(&generalName); + advancedSection = PhOptionsFindSection(&advancedName); - if (tvItemGeneral) + if (generalSection && advancedSection) { - PhpOptionsTreeViewAddItem( - sectionName.Buffer, - PhOptionsFindSection(§ionName), - tvItemGeneral + advancedSection->TreeItemHandle = PhpTreeViewInsertItem( + generalSection->TreeItemHandle, + advancedName.Buffer, + advancedSection ); } } @@ -547,11 +531,10 @@ PPH_OPTIONS_SECTION PhOptionsCreateSection( section->Template = Template; section->DialogProc = DialogProc; section->Parameter = Parameter; + section->TreeItemHandle = PhpTreeViewInsertItem(TVI_LAST, Name, section); PhAddItemList(SectionList, section); - PhpOptionsTreeViewAddItem(Name, section, TVI_LAST); - return section; } From ad89fab1edb5a3661bbfd6352e4c389eb515cfc3 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 7 Feb 2018 16:06:08 +1100 Subject: [PATCH 0788/2058] Fix commit 3c1cb4f --- ProcessHacker/main.c | 25 +++++++++++++++---- .../CustomSetupTool/CustomSetupTool/appsup.c | 6 ++--- tools/CustomSetupTool/CustomSetupTool/main.c | 21 +++++++++++++--- tools/peview/main.c | 21 +++++++++++++--- 4 files changed, 59 insertions(+), 14 deletions(-) diff --git a/ProcessHacker/main.c b/ProcessHacker/main.c index 8f3f788481a4..3fdcb508f75b 100644 --- a/ProcessHacker/main.c +++ b/ProcessHacker/main.c @@ -277,9 +277,17 @@ INT WINAPI wWinMain( // Create a mutant for the installer. { - static UNICODE_STRING objectNameUs = RTL_CONSTANT_STRING(L"PhMutant"); + HANDLE mutantHandle; + PPH_STRING objectName; OBJECT_ATTRIBUTES objectAttributes; - HANDLE objectHandle; + UNICODE_STRING objectNameUs; + PH_FORMAT format[2]; + + PhInitFormatS(&format[0], L"PhMutant_"); + PhInitFormatU(&format[1], HandleToUlong(NtCurrentProcessId())); + + objectName = PhFormat(format, 2, 16); + PhStringRefToUnicodeString(&objectName->sr, &objectNameUs); InitializeObjectAttributes( &objectAttributes, @@ -289,7 +297,14 @@ INT WINAPI wWinMain( NULL ); - NtCreateMutant(&objectHandle, MUTANT_ALL_ACCESS, &objectAttributes, TRUE); + NtCreateMutant( + &mutantHandle, + MUTANT_QUERY_STATE, + &objectAttributes, + TRUE + ); + + PhDereferenceObject(objectName); } // Set the default priority. @@ -451,13 +466,13 @@ static BOOLEAN NTAPI PhpPreviousInstancesCallback( _In_opt_ PVOID Context ) { - static PH_STRINGREF objectNameSr = PH_STRINGREF_INIT(L"PhMutant"); + static PH_STRINGREF objectNameSr = PH_STRINGREF_INIT(L"PhMutant_"); HANDLE objectHandle; UNICODE_STRING objectNameUs; OBJECT_ATTRIBUTES objectAttributes; MUTANT_OWNER_INFORMATION objectInfo; - if (!PhEqualStringRef(Name, &objectNameSr, FALSE)) + if (!PhStartsWithStringRef(Name, &objectNameSr, FALSE)) return TRUE; if (!PhStringRefToUnicodeString(Name, &objectNameUs)) return TRUE; diff --git a/tools/CustomSetupTool/CustomSetupTool/appsup.c b/tools/CustomSetupTool/CustomSetupTool/appsup.c index bbc367e52209..0ffce62ff37f 100644 --- a/tools/CustomSetupTool/CustomSetupTool/appsup.c +++ b/tools/CustomSetupTool/CustomSetupTool/appsup.c @@ -437,9 +437,9 @@ static BOOLEAN NTAPI PhpPreviousInstancesCallback( OBJECT_ATTRIBUTES objectAttributes; MUTANT_OWNER_INFORMATION objectInfo; - if (!PhEqualStringRef2(Name, L"PhMutant", TRUE) && - !PhEqualStringRef2(Name, L"PhSetupMutant", TRUE) && - !PhEqualStringRef2(Name, L"PeViewerMutant", TRUE)) + if (!PhStartsWithStringRef2(Name, L"PhMutant_", TRUE) && + !PhStartsWithStringRef2(Name, L"PhSetupMutant_", TRUE) && + !PhStartsWithStringRef2(Name, L"PeViewerMutant_", TRUE)) { return TRUE; } diff --git a/tools/CustomSetupTool/CustomSetupTool/main.c b/tools/CustomSetupTool/CustomSetupTool/main.c index bf23797055c3..a5eb7e27a9a5 100644 --- a/tools/CustomSetupTool/CustomSetupTool/main.c +++ b/tools/CustomSetupTool/CustomSetupTool/main.c @@ -217,9 +217,17 @@ VOID SetupInitializeMutant( VOID ) { - static UNICODE_STRING objectNameUs = RTL_CONSTANT_STRING(L"PhSetupMutant"); + HANDLE mutantHandle; + PPH_STRING objectName; OBJECT_ATTRIBUTES objectAttributes; - HANDLE objectHandle; + UNICODE_STRING objectNameUs; + PH_FORMAT format[2]; + + PhInitFormatS(&format[0], L"PhSetupMutant_"); + PhInitFormatU(&format[1], HandleToUlong(NtCurrentProcessId())); + + objectName = PhFormat(format, 2, 16); + PhStringRefToUnicodeString(&objectName->sr, &objectNameUs); InitializeObjectAttributes( &objectAttributes, @@ -229,7 +237,14 @@ VOID SetupInitializeMutant( NULL ); - NtCreateMutant(&objectHandle, MUTANT_ALL_ACCESS, &objectAttributes, TRUE); + NtCreateMutant( + &mutantHandle, + MUTANT_QUERY_STATE, + &objectAttributes, + TRUE + ); + + PhDereferenceObject(objectName); } INT WINAPI wWinMain( diff --git a/tools/peview/main.c b/tools/peview/main.c index 7d991176f18c..4a31bb982852 100644 --- a/tools/peview/main.c +++ b/tools/peview/main.c @@ -57,9 +57,17 @@ INT WINAPI wWinMain( // Create a mutant for the installer. { - static UNICODE_STRING objectNameUs = RTL_CONSTANT_STRING(L"PeViewerMutant"); + HANDLE mutantHandle; + PPH_STRING objectName; OBJECT_ATTRIBUTES objectAttributes; - HANDLE objectHandle; + UNICODE_STRING objectNameUs; + PH_FORMAT format[2]; + + PhInitFormatS(&format[0], L"PeViewerMutant_"); + PhInitFormatU(&format[1], HandleToUlong(NtCurrentProcessId())); + + objectName = PhFormat(format, 2, 16); + PhStringRefToUnicodeString(&objectName->sr, &objectNameUs); InitializeObjectAttributes( &objectAttributes, @@ -69,7 +77,14 @@ INT WINAPI wWinMain( NULL ); - NtCreateMutant(&objectHandle, MUTANT_ALL_ACCESS, &objectAttributes, TRUE); + NtCreateMutant( + &mutantHandle, + MUTANT_QUERY_STATE, + &objectAttributes, + TRUE + ); + + PhDereferenceObject(objectName); } PhGuiSupportInitialization(); From f553421c67302fd690c595c0681b7631844fa352 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 7 Feb 2018 16:07:36 +1100 Subject: [PATCH 0789/2058] Add missing LDR_IS_IMAGEMAPPING macro --- phnt/include/ntldr.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/phnt/include/ntldr.h b/phnt/include/ntldr.h index 8f8fea39570d..5e90c65ea148 100644 --- a/phnt/include/ntldr.h +++ b/phnt/include/ntldr.h @@ -574,6 +574,10 @@ LdrDisableThreadCalloutsForDll( // Resources +#define LDR_IS_DATAFILE(BaseAddress) (((ULONG_PTR)(BaseAddress)) & (ULONG_PTR)1) +#define LDR_IS_IMAGEMAPPING(BaseAddress) (((ULONG_PTR)(BaseAddress)) & (ULONG_PTR)2) +#define LDR_IS_RESOURCE(BaseAddress) (LDR_IS_IMAGEMAPPING(BaseAddress) || LDR_IS_DATAFILE(BaseAddress)) + NTSYSAPI NTSTATUS NTAPI From 9c2ef424abc8873d00d08c90b151e11604c09ed1 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 7 Feb 2018 16:08:36 +1100 Subject: [PATCH 0790/2058] Add missing IMAGE_RESOURCE flag --- phlib/util.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/phlib/util.c b/phlib/util.c index 42dd323c6288..ce7005a51386 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -1539,7 +1539,11 @@ PVOID PhGetFileVersionInfo( PVOID libraryModule; PVOID versionInfo; - libraryModule = LoadLibraryEx(FileName, NULL, LOAD_LIBRARY_AS_DATAFILE); + libraryModule = LoadLibraryEx( + FileName, + NULL, + LOAD_LIBRARY_AS_DATAFILE | LOAD_LIBRARY_AS_IMAGE_RESOURCE + ); if (!libraryModule) return NULL; @@ -5339,7 +5343,7 @@ PPH_STRING PhLoadIndirectString( PhMoveReference(&libraryString, expandedString); } - if (libraryModule = LoadLibraryEx(libraryString->Buffer, NULL, LOAD_LIBRARY_AS_DATAFILE)) + if (libraryModule = LoadLibraryEx(libraryString->Buffer, NULL, LOAD_LIBRARY_AS_DATAFILE | LOAD_LIBRARY_AS_IMAGE_RESOURCE)) { indirectString = PhLoadString(libraryModule, -index); FreeLibrary(libraryModule); From b23025e7b7a9daf2e9c88b798f20de4b7b4df7b6 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 7 Feb 2018 18:09:11 +1100 Subject: [PATCH 0791/2058] Move ntldr type --- phnt/include/ntldr.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/phnt/include/ntldr.h b/phnt/include/ntldr.h index 5e90c65ea148..0f2d93769799 100644 --- a/phnt/include/ntldr.h +++ b/phnt/include/ntldr.h @@ -179,6 +179,10 @@ typedef struct _LDR_DATA_TABLE_ENTRY UCHAR SigningLevel; // since REDSTONE2 } LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY; +#define LDR_IS_DATAFILE(DllHandle) (((ULONG_PTR)(DllHandle)) & (ULONG_PTR)1) +#define LDR_IS_IMAGEMAPPING(DllHandle) (((ULONG_PTR)(DllHandle)) & (ULONG_PTR)2) +#define LDR_IS_RESOURCE(DllHandle) (LDR_IS_IMAGEMAPPING(DllHandle) || LDR_IS_DATAFILE(DllHandle)) + NTSYSAPI NTSTATUS NTAPI @@ -574,10 +578,6 @@ LdrDisableThreadCalloutsForDll( // Resources -#define LDR_IS_DATAFILE(BaseAddress) (((ULONG_PTR)(BaseAddress)) & (ULONG_PTR)1) -#define LDR_IS_IMAGEMAPPING(BaseAddress) (((ULONG_PTR)(BaseAddress)) & (ULONG_PTR)2) -#define LDR_IS_RESOURCE(BaseAddress) (LDR_IS_IMAGEMAPPING(BaseAddress) || LDR_IS_DATAFILE(BaseAddress)) - NTSYSAPI NTSTATUS NTAPI From 5f37aa50a5b0b4b771e8c0fd879ab32c2f7b0ed1 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 8 Feb 2018 00:59:18 +1100 Subject: [PATCH 0792/2058] Updater: Fix update dialog responsiveness after startup --- plugins/Updater/page2.c | 2 +- plugins/Updater/updater.c | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/plugins/Updater/page2.c b/plugins/Updater/page2.c index c07909b22af8..57fc49df0d40 100644 --- a/plugins/Updater/page2.c +++ b/plugins/Updater/page2.c @@ -40,7 +40,7 @@ HRESULT CALLBACK CheckingForUpdatesCallbackProc( SendMessage(hwndDlg, TDM_SET_PROGRESS_BAR_MARQUEE, TRUE, 1); PhReferenceObject(context); - PhQueueItemWorkQueue(PhGetGlobalWorkQueue(), UpdateCheckThread, context); + PhCreateThread2(UpdateCheckThread, context); } break; } diff --git a/plugins/Updater/updater.c b/plugins/Updater/updater.c index a448b8892a31..8be7e0cbdd87 100644 --- a/plugins/Updater/updater.c +++ b/plugins/Updater/updater.c @@ -426,13 +426,16 @@ NTSTATUS UpdateCheckThread( _In_ PVOID Parameter ) { - PPH_UPDATER_CONTEXT context = NULL; + PPH_UPDATER_CONTEXT context; ULONGLONG currentVersion = 0; ULONGLONG latestVersion = 0; + PH_AUTO_POOL autoPool; context = (PPH_UPDATER_CONTEXT)Parameter; context->ErrorCode = STATUS_SUCCESS; + PhInitializeAutoPool(&autoPool); + // Check if we have cached update data if (!context->HaveData) { @@ -444,6 +447,7 @@ NTSTATUS UpdateCheckThread( ShowUpdateFailedDialog(context, FALSE, FALSE); PhDereferenceObject(context); + PhDeleteAutoPool(&autoPool); return STATUS_SUCCESS; } @@ -477,6 +481,7 @@ NTSTATUS UpdateCheckThread( } PhDereferenceObject(context); + PhDeleteAutoPool(&autoPool); return STATUS_SUCCESS; } From 152ae4e5138361139fea6c424f361eab98b3b8b5 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 8 Feb 2018 03:46:46 +1100 Subject: [PATCH 0793/2058] Fix default debugger directory --- ProcessHacker/ProcessHacker.vcxproj | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/ProcessHacker/ProcessHacker.vcxproj b/ProcessHacker/ProcessHacker.vcxproj index 196b6949ee97..08dc681c1413 100644 --- a/ProcessHacker/ProcessHacker.vcxproj +++ b/ProcessHacker/ProcessHacker.vcxproj @@ -30,22 +30,30 @@ Unicode true v141 + WindowsLocalDebugger + $(SolutionDir)bin\$(Configuration)$(PlatformArchitecture)\ Application Unicode v141 + WindowsLocalDebugger + $(SolutionDir)bin\$(Configuration)$(PlatformArchitecture)\ Application Unicode true v141 + WindowsLocalDebugger + $(SolutionDir)bin\$(Configuration)$(PlatformArchitecture)\ Application Unicode v141 + WindowsLocalDebugger + $(SolutionDir)bin\$(Configuration)$(PlatformArchitecture)\ From 3b504dd405b08ead4b58ede7d5993485244e68b8 Mon Sep 17 00:00:00 2001 From: diversenok <30962924+diversenok@users.noreply.github.com> Date: Wed, 7 Feb 2018 21:16:56 +0300 Subject: [PATCH 0794/2058] Lost check for abandoned mutexes (#238) --- phlib/util.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/phlib/util.c b/phlib/util.c index ce7005a51386..f74f27e543d9 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -2301,7 +2301,10 @@ NTSTATUS PhWaitForMultipleObjectsAndPump( QS_ALLEVENTS ); - if (status >= STATUS_WAIT_0 && status < (NTSTATUS)(STATUS_WAIT_0 + NumberOfHandles)) + if ( + status >= STATUS_WAIT_0 && status < (NTSTATUS)(STATUS_WAIT_0 + NumberOfHandles) || + status >= STATUS_ABANDONED_WAIT_0 && status < (NTSTATUS)(STATUS_ABANDONED_WAIT_0 + NumberOfHandles) + ) { return status; } From 45bbffcee8adaf1274f104746696199d83337be8 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 9 Feb 2018 08:03:22 +1100 Subject: [PATCH 0795/2058] Remove unused code --- ProcessHacker/include/procprp.h | 2 -- ProcessHacker/procprp.c | 30 +----------------------------- 2 files changed, 1 insertion(+), 31 deletions(-) diff --git a/ProcessHacker/include/procprp.h b/ProcessHacker/include/procprp.h index 065926df5f2a..db5f5d7be97c 100644 --- a/ProcessHacker/include/procprp.h +++ b/ProcessHacker/include/procprp.h @@ -6,8 +6,6 @@ typedef struct _PH_PROCESS_PROPCONTEXT { PPH_PROCESS_ITEM ProcessItem; - HWND WindowHandle; - PH_EVENT CreatedEvent; PPH_STRING Title; PROPSHEETHEADER PropSheetHeader; HPROPSHEETPAGE *PropSheetPages; diff --git a/ProcessHacker/procprp.c b/ProcessHacker/procprp.c index 8fde7b3904dd..107806984313 100644 --- a/ProcessHacker/procprp.c +++ b/ProcessHacker/procprp.c @@ -101,7 +101,6 @@ PPH_PROCESS_PROPCONTEXT PhCreateProcessPropContext( memcpy(&propContext->PropSheetHeader, &propSheetHeader, sizeof(PROPSHEETHEADER)); PhSetReference(&propContext->ProcessItem, ProcessItem); - PhInitializeEvent(&propContext->CreatedEvent); return propContext; } @@ -549,9 +548,6 @@ NTSTATUS PhpProcessPropertiesThreadStart( PPH_PROCESS_PROPCONTEXT PropContext = (PPH_PROCESS_PROPCONTEXT)Parameter; PPH_PROCESS_PROPPAGECONTEXT newPage; PPH_STRING startPage; - HWND hwnd; - BOOL result; - MSG message; PhInitializeAutoPool(&autoPool); @@ -689,33 +685,9 @@ NTSTATUS PhpProcessPropertiesThreadStart( PropContext->PropSheetHeader.dwFlags |= PSH_USEPSTARTPAGE; PropContext->PropSheetHeader.pStartPage = startPage->Buffer; - hwnd = (HWND)PropertySheet(&PropContext->PropSheetHeader); + PhModalPropertySheet(&PropContext->PropSheetHeader);; PhDereferenceObject(startPage); - - PropContext->WindowHandle = hwnd; - PhSetEvent(&PropContext->CreatedEvent); - - // Main event loop - - while (result = GetMessage(&message, NULL, 0, 0)) - { - if (result == -1) - break; - - if (!PropSheet_IsDialogMessage(hwnd, &message)) - { - TranslateMessage(&message); - DispatchMessage(&message); - } - - PhDrainAutoPool(&autoPool); - - if (!PropSheet_GetCurrentPageHwnd(hwnd)) - break; - } - - DestroyWindow(hwnd); PhDereferenceObject(PropContext); PhDeleteAutoPool(&autoPool); From ff534a7118dd82c39fd38831267b62e63eba21dd Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 9 Feb 2018 08:12:59 +1100 Subject: [PATCH 0796/2058] Update runas dialog; Fix autosuggest, Fix MRU list, Update dialog layout --- ProcessHacker/ProcessHacker.rc | 27 +- ProcessHacker/include/phapp.h | 17 + ProcessHacker/include/phsvcapi.h | 1 + ProcessHacker/phsvc/clapi.c | 1 + ProcessHacker/phsvc/svcapi.c | 1 + ProcessHacker/resource.h | 8 +- ProcessHacker/runas.c | 1018 +++++++++++++++++++++--------- 7 files changed, 766 insertions(+), 307 deletions(-) diff --git a/ProcessHacker/ProcessHacker.rc b/ProcessHacker/ProcessHacker.rc index 030c715f4038..32a0990ecc10 100644 --- a/ProcessHacker/ProcessHacker.rc +++ b/ProcessHacker/ProcessHacker.rc @@ -745,30 +745,29 @@ BEGIN DEFPUSHBUTTON "Close",IDOK,280,200,50,14 END -IDD_RUNAS DIALOGEX 0, 0, 278, 127 +IDD_RUNAS DIALOGEX 0, 0, 293, 127 STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Run As" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN - LTEXT "Enter the command to start as the specified user.",IDC_STATIC,7,7,160,8 + LTEXT "Enter the command to start as the specified user.",IDC_TITLE,7,7,160,8 LTEXT "Program:",IDC_STATIC,7,23,30,8 - EDITTEXT IDC_PROGRAM,53,21,163,12,ES_AUTOHSCROLL - PUSHBUTTON "Browse...",IDC_BROWSE,221,20,50,14 LTEXT "User name:",IDC_STATIC,7,40,38,8 - COMBOBOX IDC_USERNAME,53,38,123,12,CBS_DROPDOWN | CBS_AUTOHSCROLL | CBS_SORT | WS_VSCROLL | WS_TABSTOP - LTEXT "Type:",IDC_STATIC,183,40,20,8 - COMBOBOX IDC_TYPE,207,38,64,30,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_USERNAME,53,38,123,12,CBS_DROPDOWN | CBS_AUTOHSCROLL | WS_VSCROLL | WS_TABSTOP + LTEXT "Type:",IDC_STATIC,184,40,20,8 + COMBOBOX IDC_TYPE,208,38,78,12,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP LTEXT "Password:",IDC_STATIC,7,56,34,8 EDITTEXT IDC_PASSWORD,53,55,123,12,ES_PASSWORD | ES_AUTOHSCROLL CONTROL "Toggle elevation",IDC_TOGGLEELEVATION,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,183,56,69,10 LTEXT "Session ID:",IDC_STATIC,7,73,37,8 - EDITTEXT IDC_SESSIONID,53,72,104,12,ES_AUTOHSCROLL | ES_NUMBER - PUSHBUTTON "...",IDC_SESSIONS,161,71,16,14 LTEXT "Desktop:",IDC_STATIC,7,90,30,8 - EDITTEXT IDC_DESKTOP,53,88,104,12,ES_AUTOHSCROLL - PUSHBUTTON "...",IDC_DESKTOPS,161,87,16,14 - DEFPUSHBUTTON "OK",IDOK,168,106,50,14 - PUSHBUTTON "Cancel",IDCANCEL,221,106,50,14 + DEFPUSHBUTTON "OK",IDOK,127,106,50,14 + PUSHBUTTON "Cancel",IDCANCEL,182,106,50,14 + COMBOBOX IDC_SESSIONCOMBO,53,72,123,12,CBS_DROPDOWNLIST | CBS_AUTOHSCROLL | CBS_SORT | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_DESKTOPCOMBO,53,88,123,12,CBS_DROPDOWNLIST | CBS_AUTOHSCROLL | CBS_SORT | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Browse",IDC_BROWSE,237,106,50,14 + CONTROL "Create suspended",IDC_TOGGLESUSPENDED,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,183,70,75,10 + COMBOBOX IDC_PROGRAMCOMBO,53,21,233,12,CBS_DROPDOWN | CBS_AUTOHSCROLL | WS_VSCROLL | WS_TABSTOP END IDD_PROGRESS DIALOGEX 0, 0, 216, 62 @@ -1935,7 +1934,7 @@ BEGIN IDD_RUNAS, DIALOG BEGIN LEFTMARGIN, 7 - RIGHTMARGIN, 271 + RIGHTMARGIN, 286 TOPMARGIN, 7 BOTTOMMARGIN, 120 END diff --git a/ProcessHacker/include/phapp.h b/ProcessHacker/include/phapp.h index 651992748e26..65b9200bd700 100644 --- a/ProcessHacker/include/phapp.h +++ b/ProcessHacker/include/phapp.h @@ -569,6 +569,7 @@ typedef struct _PH_RUNAS_SERVICE_PARAMETERS PWSTR DesktopName; BOOLEAN UseLinkedToken; PWSTR ServiceName; + BOOLEAN CreateSuspendedProcess; } PH_RUNAS_SERVICE_PARAMETERS, *PPH_RUNAS_SERVICE_PARAMETERS; VOID PhShowRunAsDialog( @@ -597,6 +598,22 @@ PhExecuteRunAsCommand2( ); // end_phapppub +PHAPPAPI +NTSTATUS +NTAPI +PhExecuteRunAsCommand3( + _In_ HWND hWnd, + _In_ PWSTR Program, + _In_opt_ PWSTR UserName, + _In_opt_ PWSTR Password, + _In_opt_ ULONG LogonType, + _In_opt_ HANDLE ProcessIdWithToken, + _In_ ULONG SessionId, + _In_ PWSTR DesktopName, + _In_ BOOLEAN UseLinkedToken, + _In_ BOOLEAN CreateSuspendedProcess + ); + NTSTATUS PhRunAsServiceStart( _In_ PPH_STRING ServiceName ); diff --git a/ProcessHacker/include/phsvcapi.h b/ProcessHacker/include/phsvcapi.h index ad6c9105e80b..a4a1b5d1bab8 100644 --- a/ProcessHacker/include/phsvcapi.h +++ b/ProcessHacker/include/phsvcapi.h @@ -60,6 +60,7 @@ typedef union _PHSVC_API_EXECUTERUNASCOMMAND PH_RELATIVE_STRINGREF DesktopName; BOOLEAN UseLinkedToken; PH_RELATIVE_STRINGREF ServiceName; + BOOLEAN CreateSuspendedProcess; } i; } PHSVC_API_EXECUTERUNASCOMMAND, *PPHSVC_API_EXECUTERUNASCOMMAND; diff --git a/ProcessHacker/phsvc/clapi.c b/ProcessHacker/phsvc/clapi.c index 8afb38cf4cad..724571350472 100644 --- a/ProcessHacker/phsvc/clapi.c +++ b/ProcessHacker/phsvc/clapi.c @@ -283,6 +283,7 @@ NTSTATUS PhSvcpCallExecuteRunAsCommand( m.p.u.ExecuteRunAsCommand.i.LogonType = Parameters->LogonType; m.p.u.ExecuteRunAsCommand.i.SessionId = Parameters->SessionId; m.p.u.ExecuteRunAsCommand.i.UseLinkedToken = Parameters->UseLinkedToken; + m.p.u.ExecuteRunAsCommand.i.CreateSuspendedProcess = Parameters->CreateSuspendedProcess; status = STATUS_NO_MEMORY; diff --git a/ProcessHacker/phsvc/svcapi.c b/ProcessHacker/phsvc/svcapi.c index dda20bdde1a8..e649469d03d6 100644 --- a/ProcessHacker/phsvc/svcapi.c +++ b/ProcessHacker/phsvc/svcapi.c @@ -395,6 +395,7 @@ NTSTATUS PhSvcpCaptureRunAsServiceParameters( Parameters->DesktopName = PhGetString(CapturedParameters->DesktopName); Parameters->UseLinkedToken = Payload->u.ExecuteRunAsCommand.i.UseLinkedToken; Parameters->ServiceName = PhGetString(CapturedParameters->ServiceName); + Parameters->CreateSuspendedProcess = Payload->u.ExecuteRunAsCommand.i.CreateSuspendedProcess; return status; } diff --git a/ProcessHacker/resource.h b/ProcessHacker/resource.h index 8727dc0e5325..d68f44785fb2 100644 --- a/ProcessHacker/resource.h +++ b/ProcessHacker/resource.h @@ -204,7 +204,10 @@ #define IDC_PROGRAM 1069 #define IDC_BROWSE 1070 #define IDC_USERNAME 1071 +#define IDC_SESSIONCOMBO 1072 +#define IDC_DESKTOPCOMBO 1073 #define IDC_SESSIONS 1074 +#define IDC_PROGRAMCOMBO 1074 #define IDC_DESKTOPS 1075 #define IDC_PROGRESS 1076 #define IDC_PROGRESSTEXT 1077 @@ -406,6 +409,7 @@ #define IDC_ICONPROCESSES 1248 #define IDC_CLEANUP 1251 #define IDC_TOGGLEELEVATION 1254 +#define IDC_TOGGLESUSPENDED 1255 #define IDC_PARENT 1263 #define IDC_PROCESSNAME 1264 #define IDC_SERVICES_LAYOUT 1266 @@ -738,9 +742,9 @@ // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 246 +#define _APS_NEXT_RESOURCE_VALUE 247 #define _APS_NEXT_COMMAND_VALUE 40297 -#define _APS_NEXT_CONTROL_VALUE 1405 +#define _APS_NEXT_CONTROL_VALUE 1406 #define _APS_NEXT_SYMED_VALUE 170 #endif #endif diff --git a/ProcessHacker/runas.c b/ProcessHacker/runas.c index 1c93b78e143a..6fd8865eb0bc 100644 --- a/ProcessHacker/runas.c +++ b/ProcessHacker/runas.c @@ -3,6 +3,7 @@ * run as dialog * * Copyright (C) 2010-2013 wj32 + * Copyright (C) 2018 dmex * * This file is part of Process Hacker. * @@ -63,6 +64,8 @@ #include #include #include +#include +#include #include #include @@ -71,14 +74,81 @@ #include #include #include +#include typedef struct _RUNAS_DIALOG_CONTEXT { + HWND ProgramComboBoxWindowHandle; + HWND UserComboBoxWindowHandle; + HWND TypeComboBoxWindowHandle; + HWND PasswordEditWindowHandle; + HWND SessionEditWindowHandle; + HWND DesktopEditWindowHandle; HANDLE ProcessId; PPH_LIST DesktopList; PPH_STRING CurrentWinStaName; } RUNAS_DIALOG_CONTEXT, *PRUNAS_DIALOG_CONTEXT; +typedef struct _PH_RUNAS_SESSION_ITEM +{ + ULONG SessionId; + PPH_STRING SessionName; +} PH_RUNAS_SESSION_ITEM, *PPH_RUNAS_SESSION_ITEM; + +typedef struct _PH_RUNAS_DESKTOP_ITEM +{ + PPH_STRING DesktopName; +} PH_RUNAS_DESKTOP_ITEM, *PPH_RUNAS_DESKTOP_ITEM; + +typedef INT (CALLBACK *MRUSTRINGCMPPROC)(PCWSTR pString1, PCWSTR pString2); +typedef INT (CALLBACK *MRUINARYCMPPROC)(LPCVOID pString1, LPCVOID pString2, ULONG length); + +#define MRU_STRING 0x0000 // list will contain strings. +#define MRU_BINARY 0x0001 // list will contain binary data. +#define MRU_CACHEWRITE 0x0002 // only save list order to reg. is FreeMRUList. + +typedef struct _MRUINFO +{ + ULONG cbSize; + UINT uMaxItems; + UINT uFlags; + HKEY hKey; + LPCTSTR lpszSubKey; + MRUSTRINGCMPPROC lpfnCompare; +} MRUINFO, *PMRUINFO; + +static ULONG (WINAPI *NetUserEnum_I)( + _In_ PCWSTR servername, + _In_ ULONG level, + _In_ ULONG filter, + _Out_ PBYTE *bufptr, + _In_ ULONG prefmaxlen, + _Out_ PULONG entriesread, + _Out_ PULONG totalentries, + _Inout_ PULONG resume_handle + ); + +static ULONG (WINAPI *NetApiBufferFree_I)( + _Frees_ptr_opt_ PVOID Buffer + ); + +static HANDLE (WINAPI *CreateMRUList_I)( + _In_ PMRUINFO lpmi + ); +static INT (WINAPI *AddMRUString_I)( + _In_ HANDLE hMRU, + _In_ PWSTR szString + ); +static INT (WINAPI *EnumMRUList_I)( + _In_ HANDLE hMRU, + _In_ INT nItem, + _Out_ PVOID lpData, + _In_ UINT uLen + ); +static INT (WINAPI *FreeMRUList_I)( + _In_ HANDLE hMRU + ); + INT_PTR CALLBACK PhpRunAsDlgProc( _In_ HWND hwndDlg, _In_ UINT uMsg, @@ -119,63 +189,16 @@ VOID PhShowRunAsDialog( _In_opt_ HANDLE ProcessId ) { - RUNAS_DIALOG_CONTEXT context; - - context.ProcessId = ProcessId; - context.DesktopList = NULL; - DialogBoxParam( PhInstanceHandle, MAKEINTRESOURCE(IDD_RUNAS), - ParentWindowHandle, + NULL, PhpRunAsDlgProc, - (LPARAM)&context + (LPARAM)ProcessId ); } -static VOID PhpAddAccountsToComboBox( - _In_ HWND ComboBoxHandle - ) -{ - LSA_HANDLE policyHandle; - LSA_ENUMERATION_HANDLE enumerationContext = 0; - PLSA_ENUMERATION_INFORMATION buffer; - ULONG count; - ULONG i; - PPH_STRING name; - SID_NAME_USE nameUse; - - if (NT_SUCCESS(PhOpenLsaPolicy(&policyHandle, POLICY_VIEW_LOCAL_INFORMATION, NULL))) - { - while (NT_SUCCESS(LsaEnumerateAccounts( - policyHandle, - &enumerationContext, - &buffer, - 0x100, - &count - ))) - { - for (i = 0; i < count; i++) - { - name = PhGetSidFullName(buffer[i].Sid, TRUE, &nameUse); - - if (name) - { - if (nameUse == SidTypeUser) - ComboBox_AddString(ComboBoxHandle, name->Buffer); - - PhDereferenceObject(name); - } - } - - LsaFreeMemory(buffer); - } - - LsaClose(policyHandle); - } -} - -static BOOLEAN IsServiceAccount( +BOOLEAN IsServiceAccount( _In_ PPH_STRING UserName ) { @@ -193,7 +216,34 @@ static BOOLEAN IsServiceAccount( } } -static PPH_STRING GetCurrentWinStaName( +BOOLEAN IsCurrentUserAccount( + _In_ PPH_STRING UserName + ) +{ + PTOKEN_USER userToken; + PPH_STRING userName; + + if (NT_SUCCESS(PhGetTokenUser(PhGetOwnTokenAttributes().TokenHandle, &userToken))) + { + if (userName = PhGetSidFullName(userToken->User.Sid, TRUE, NULL)) + { + if (PhEndsWithString(userName, UserName, TRUE)) + { + PhDereferenceObject(userName); + PhFree(userToken); + return TRUE; + } + + PhDereferenceObject(userName); + } + + PhFree(userToken); + } + + return FALSE; +} + +PPH_STRING GetCurrentWinStaName( VOID ) { @@ -219,6 +269,351 @@ static PPH_STRING GetCurrentWinStaName( } } +BOOLEAN PhpInitializeNetApi(VOID) +{ + PVOID netapiModuleHandle; + + if (!(netapiModuleHandle = LoadLibrary(L"netapi32.dll"))) + return FALSE; + + NetUserEnum_I = PhGetProcedureAddress(netapiModuleHandle, "NetUserEnum", 0); + NetApiBufferFree_I = PhGetProcedureAddress(netapiModuleHandle, "NetApiBufferFree", 0); + + if (!NetUserEnum_I && !NetApiBufferFree_I) + { + FreeLibrary(netapiModuleHandle); + return FALSE; + } + + return TRUE; +} + +BOOLEAN PhpInitializeMRUList(VOID) +{ + PVOID comctl32ModuleHandle; + + if (!(comctl32ModuleHandle = LoadLibrary(L"comctl32.dll"))) + return FALSE; + + CreateMRUList_I = PhGetProcedureAddress(comctl32ModuleHandle, "CreateMRUListW", 0); + AddMRUString_I = PhGetProcedureAddress(comctl32ModuleHandle, "AddMRUStringW", 0); + EnumMRUList_I = PhGetProcedureAddress(comctl32ModuleHandle, "EnumMRUListW", 0); + FreeMRUList_I = PhGetProcedureAddress(comctl32ModuleHandle, "FreeMRUList", 0); + + if (!CreateMRUList_I && !AddMRUString_I && !EnumMRUList_I && !FreeMRUList_I) + { + FreeLibrary(comctl32ModuleHandle); + return FALSE; + } + + return TRUE; +} + +static HANDLE PhpCreateRunMRUList( + VOID + ) +{ + MRUINFO info; + + if (!CreateMRUList_I) + return NULL; + + memset(&info, 0, sizeof(MRUINFO)); + info.cbSize = sizeof(MRUINFO); + info.uMaxItems = UINT_MAX; + info.hKey = HKEY_CURRENT_USER; + info.lpszSubKey = L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\RunMRU"; + + return CreateMRUList_I(&info); +} + +static VOID PhpAddRunMRUListEntry( + _In_ PWSTR CommandLine + ) +{ + HANDLE listHandle; + PPH_STRING commandString; + + if (!(listHandle = PhpCreateRunMRUList())) + return; + + commandString = PhConcatStrings2(CommandLine, L"\\1"); + AddMRUString_I(listHandle, commandString->Buffer); + PhDereferenceObject(commandString); + + FreeMRUList_I(listHandle); +} + +static VOID PhpAddProgramsToComboBox( + _In_ HWND ComboBoxHandle + ) +{ + static PH_STRINGREF prefixSr = PH_STRINGREF_INIT(L"\\1"); + HANDLE listHandle; + INT listCount; + + if (!PhpInitializeMRUList()) + return; + if (!(listHandle = PhpCreateRunMRUList())) + return; + + listCount = EnumMRUList_I( + listHandle, + MAXINT, + NULL, + 0 + ); + + for (INT i = 0; i < listCount; i++) + { + static PH_STRINGREF keyNamePlusEquals = PH_STRINGREF_INIT(L"\\1"); + PPH_STRING programName; + PH_STRINGREF nameSr; + PH_STRINGREF firstPart; + PH_STRINGREF remainingPart; + WCHAR entry[MAX_PATH]; + + if (!EnumMRUList_I( + listHandle, + i, + entry, + ARRAYSIZE(entry) + )) + { + break; + } + + PhInitializeStringRefLongHint(&nameSr, entry); + + if (!PhSplitStringRefAtString(&nameSr, &keyNamePlusEquals, TRUE, &firstPart, &remainingPart)) + { + ComboBox_AddString(ComboBoxHandle, entry); + continue; + } + + programName = PhCreateString2(&firstPart); + ComboBox_AddString(ComboBoxHandle, PhGetString(programName)); + PhDereferenceObject(programName); + } + + FreeMRUList_I(listHandle); +} + +static VOID PhpAddAccountsToComboBox( + _In_ HWND ComboBoxHandle + ) +{ + NET_API_STATUS status; + LPUSER_INFO_0 userinfoArray = NULL; + ULONG userinfoMaxLength = MAX_PREFERRED_LENGTH; + ULONG userinfoEntriesRead = 0; + ULONG userinfoTotalEntries = 0; + ULONG userinfoResumeHandle = 0; + + ComboBox_ResetContent(ComboBoxHandle); + ComboBox_AddString(ComboBoxHandle, L"NT AUTHORITY\\SYSTEM"); + ComboBox_AddString(ComboBoxHandle, L"NT AUTHORITY\\LOCAL SERVICE"); + ComboBox_AddString(ComboBoxHandle, L"NT AUTHORITY\\NETWORK SERVICE"); + + if (!PhpInitializeNetApi()) + return; + + NetUserEnum_I( + NULL, + 0, + FILTER_NORMAL_ACCOUNT, + (PBYTE*)&userinfoArray, + userinfoMaxLength, + &userinfoEntriesRead, + &userinfoTotalEntries, + &userinfoResumeHandle + ); + + if (userinfoArray) + { + NetApiBufferFree_I(userinfoArray); + userinfoArray = NULL; + } + + status = NetUserEnum_I( + NULL, + 0, + FILTER_NORMAL_ACCOUNT, + (PBYTE*)&userinfoArray, + userinfoMaxLength, + &userinfoEntriesRead, + &userinfoTotalEntries, + &userinfoResumeHandle + ); + + if (status == NERR_Success) + { + PTOKEN_USER userToken; + PPH_STRING userDomainName = NULL; + + if (NT_SUCCESS(PhGetTokenUser(PhGetOwnTokenAttributes().TokenHandle, &userToken))) + { + PPH_STRING username; + + if (username = PhGetSidFullName(userToken->User.Sid, TRUE, NULL)) + { + PhpSplitUserName(username->Buffer, &userDomainName, NULL); + PhDereferenceObject(username); + } + + PhFree(userToken); + } + + for (ULONG i = 0; i < userinfoEntriesRead; i++) + { + LPUSER_INFO_0 entry = PTR_ADD_OFFSET(userinfoArray, sizeof(USER_INFO_0) * i); + + if (entry->usri0_name) + { + if (userDomainName) + { + PPH_STRING usernameString; + + usernameString = PhConcatStrings( + 3, + userDomainName->Buffer, + L"\\", + entry->usri0_name + ); + + ComboBox_AddString(ComboBoxHandle, usernameString->Buffer); + PhDereferenceObject(usernameString); + } + else + { + ComboBox_AddString(ComboBoxHandle, entry->usri0_name); + } + } + } + + if (userDomainName) + PhDereferenceObject(userDomainName); + } + + if (userinfoArray) + NetApiBufferFree_I(userinfoArray); + + //LSA_HANDLE policyHandle; + //LSA_ENUMERATION_HANDLE enumerationContext = 0; + //PLSA_ENUMERATION_INFORMATION buffer; + //ULONG count; + //PPH_STRING name; + //SID_NAME_USE nameUse; + // + //if (NT_SUCCESS(PhOpenLsaPolicy(&policyHandle, POLICY_VIEW_LOCAL_INFORMATION, NULL))) + //{ + // while (NT_SUCCESS(LsaEnumerateAccounts( + // policyHandle, + // &enumerationContext, + // &buffer, + // 0x100, + // &count + // ))) + // { + // for (i = 0; i < count; i++) + // { + // name = PhGetSidFullName(buffer[i].Sid, TRUE, &nameUse); + // if (name) + // { + // if (nameUse == SidTypeUser) + // ComboBox_AddString(ComboBoxHandle, name->Buffer); + // PhDereferenceObject(name); + // } + // } + // LsaFreeMemory(buffer); + // } + // + // LsaClose(policyHandle); + //} +} + +static VOID PhpAddSessionsToComboBox( + _In_ HWND ComboBoxHandle + ) +{ + PSESSIONIDW sessions; + ULONG numberOfSessions; + ULONG i; + + ComboBox_ResetContent(ComboBoxHandle); + + if (WinStationEnumerateW(NULL, &sessions, &numberOfSessions)) + { + for (i = 0; i < numberOfSessions; i++) + { + PPH_STRING menuString; + WINSTATIONINFORMATION winStationInfo; + ULONG returnLength; + + if (!WinStationQueryInformationW( + NULL, + sessions[i].SessionId, + WinStationInformation, + &winStationInfo, + sizeof(WINSTATIONINFORMATION), + &returnLength + )) + { + winStationInfo.Domain[0] = 0; + winStationInfo.UserName[0] = 0; + } + + if ( + winStationInfo.UserName[0] != 0 && + sessions[i].WinStationName[0] != 0 + ) + { + menuString = PhaFormatString(L"%u: %s (%s\\%s)", + sessions[i].SessionId, + sessions[i].WinStationName, + winStationInfo.Domain, + winStationInfo.UserName + ); + } + else if (winStationInfo.UserName[0] != 0) + { + menuString = PhaFormatString(L"%u: %s\\%s", + sessions[i].SessionId, + winStationInfo.Domain, + winStationInfo.UserName + ); + } + else if (sessions[i].WinStationName[0] != 0) + { + menuString = PhaFormatString(L"%u: %s", + sessions[i].SessionId, + sessions[i].WinStationName + ); + } + else + { + menuString = PhaFormatString(L"%u", sessions[i].SessionId); + } + + + PPH_RUNAS_SESSION_ITEM entry; + + entry = PhAllocate(sizeof(PH_RUNAS_SESSION_ITEM)); + entry->SessionId = sessions[i].SessionId; + entry->SessionName = menuString; + + INT itemIndex = ComboBox_AddString(ComboBoxHandle, menuString->Buffer); + + if (itemIndex != CB_ERR) + { + ComboBox_SetItemData(ComboBoxHandle, itemIndex, entry); + } + } + + WinStationFreeMemory(sessions); + } +} + static BOOL CALLBACK EnumDesktopsCallback( _In_ PWSTR DesktopName, _In_ LPARAM Context @@ -231,11 +626,101 @@ static BOOL CALLBACK EnumDesktopsCallback( context->CurrentWinStaName->Buffer, L"\\", DesktopName - )); + )); return TRUE; } +static VOID PhpAddDesktopsToComboBox( + _In_ PRUNAS_DIALOG_CONTEXT Context, + _In_ HWND ComboBoxHandle + ) +{ + ULONG i; + + Context->DesktopList = PhCreateList(10); + Context->CurrentWinStaName = GetCurrentWinStaName(); + ComboBox_ResetContent(ComboBoxHandle); + + EnumDesktops(GetProcessWindowStation(), EnumDesktopsCallback, (LPARAM)Context); + + for (i = 0; i < Context->DesktopList->Count; i++) + { + PPH_RUNAS_DESKTOP_ITEM entry; + + entry = PhAllocate(sizeof(PH_RUNAS_DESKTOP_ITEM)); + entry->DesktopName = ((PPH_STRING)Context->DesktopList->Items[i]); + + INT itemIndex = ComboBox_AddString(ComboBoxHandle, entry->DesktopName->Buffer); + + if (itemIndex != CB_ERR) + { + ComboBox_SetItemData(ComboBoxHandle, itemIndex, entry); + } + } + + PhClearList(Context->DesktopList); // leak + PhDereferenceObject(Context->CurrentWinStaName); +} + +VOID SetDefaultProgramEntry( + _In_ HWND ComboBoxHandle + ) +{ + //Edit_SetText(ComboBoxHandle, PhaGetStringSetting(L"RunAsProgram")->Buffer); + ComboBox_SetCurSel(ComboBoxHandle, 0); +} + +VOID SetDefaultSessionEntry( + _In_ HWND ComboBoxHandle + ) +{ + INT sessionCount; + ULONG currentSessionId = 0; + + if (!NT_SUCCESS(PhGetProcessSessionId(NtCurrentProcess(), ¤tSessionId))) + return; + + if ((sessionCount = ComboBox_GetCount(ComboBoxHandle)) == CB_ERR) + return; + + for (INT i = 0; i < sessionCount; i++) + { + PPH_RUNAS_SESSION_ITEM entry = (PPH_RUNAS_SESSION_ITEM)ComboBox_GetItemData(ComboBoxHandle, i); + + if (entry && entry->SessionId == currentSessionId) + { + ComboBox_SetCurSel(ComboBoxHandle, i); + break; + } + } +} + +VOID SetDefaultDesktopEntry( + _In_ PRUNAS_DIALOG_CONTEXT Context, + _In_ HWND ComboBoxHandle + ) +{ + INT sessionCount; + PH_STRINGREF desktopName; + + PhUnicodeStringToStringRef(&NtCurrentPeb()->ProcessParameters->DesktopInfo, &desktopName); + + if ((sessionCount = ComboBox_GetCount(ComboBoxHandle)) == CB_ERR) + return; + + for (INT i = 0; i < sessionCount; i++) + { + PPH_RUNAS_DESKTOP_ITEM entry = (PPH_RUNAS_DESKTOP_ITEM)ComboBox_GetItemData(ComboBoxHandle, i); + + if (PhEqualStringRef(&entry->DesktopName->sr, &desktopName, TRUE)) + { + ComboBox_SetCurSel(ComboBoxHandle, i); + break; + } + } +} + INT_PTR CALLBACK PhpRunAsDlgProc( _In_ HWND hwndDlg, _In_ UINT uMsg, @@ -245,14 +730,16 @@ INT_PTR CALLBACK PhpRunAsDlgProc( { PRUNAS_DIALOG_CONTEXT context; - if (uMsg != WM_INITDIALOG) + if (uMsg == WM_INITDIALOG) { - context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); + context = PhAllocate(sizeof(RUNAS_DIALOG_CONTEXT)); + memset(context, 0, sizeof(RUNAS_DIALOG_CONTEXT)); + + PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context); } else { - context = (PRUNAS_DIALOG_CONTEXT)lParam; - PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context); + context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); } if (!context) @@ -262,43 +749,51 @@ INT_PTR CALLBACK PhpRunAsDlgProc( { case WM_INITDIALOG: { - HWND typeComboBoxHandle = GetDlgItem(hwndDlg, IDC_TYPE); - HWND userNameComboBoxHandle = GetDlgItem(hwndDlg, IDC_USERNAME); - ULONG sessionId; + SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER))); + SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER))); - PhCenterWindow(hwndDlg, GetParent(hwndDlg)); + context->ProgramComboBoxWindowHandle = GetDlgItem(hwndDlg, IDC_PROGRAMCOMBO); + context->SessionEditWindowHandle = GetDlgItem(hwndDlg, IDC_SESSIONCOMBO); + context->DesktopEditWindowHandle = GetDlgItem(hwndDlg, IDC_DESKTOPCOMBO); + context->TypeComboBoxWindowHandle = GetDlgItem(hwndDlg, IDC_TYPE); + context->UserComboBoxWindowHandle = GetDlgItem(hwndDlg, IDC_USERNAME); + context->PasswordEditWindowHandle = GetDlgItem(hwndDlg, IDC_PASSWORD); + context->ProcessId = (HANDLE)lParam; - if (SHAutoComplete_I) - { - SHAutoComplete_I( - GetDlgItem(hwndDlg, IDC_PROGRAM), - SHACF_AUTOAPPEND_FORCE_ON | SHACF_AUTOSUGGEST_FORCE_ON | SHACF_FILESYS_ONLY - ); - } + PhCenterWindow(hwndDlg, (IsWindowVisible(PhMainWndHandle) && !IsMinimized(PhMainWndHandle)) ? PhMainWndHandle : NULL); - ComboBox_AddString(typeComboBoxHandle, L"Batch"); - ComboBox_AddString(typeComboBoxHandle, L"Interactive"); - ComboBox_AddString(typeComboBoxHandle, L"Network"); - ComboBox_AddString(typeComboBoxHandle, L"New credentials"); - ComboBox_AddString(typeComboBoxHandle, L"Service"); - PhSelectComboBoxString(typeComboBoxHandle, L"Interactive", FALSE); + { + COMBOBOXINFO info = { sizeof(COMBOBOXINFO) }; - ComboBox_AddString(userNameComboBoxHandle, L"NT AUTHORITY\\SYSTEM"); - ComboBox_AddString(userNameComboBoxHandle, L"NT AUTHORITY\\LOCAL SERVICE"); - ComboBox_AddString(userNameComboBoxHandle, L"NT AUTHORITY\\NETWORK SERVICE"); + if (SendMessage(context->ProgramComboBoxWindowHandle, CB_GETCOMBOBOXINFO, 0, (LPARAM)&info)) + { + if (SHAutoComplete_I) + SHAutoComplete_I(info.hwndItem, SHACF_DEFAULT); + } + } - PhpAddAccountsToComboBox(userNameComboBoxHandle); + ComboBox_AddString(context->TypeComboBoxWindowHandle, L"Batch"); + ComboBox_AddString(context->TypeComboBoxWindowHandle, L"Interactive"); + ComboBox_AddString(context->TypeComboBoxWindowHandle, L"Network"); + ComboBox_AddString(context->TypeComboBoxWindowHandle, L"New credentials"); + ComboBox_AddString(context->TypeComboBoxWindowHandle, L"Service"); + PhSelectComboBoxString(context->TypeComboBoxWindowHandle, L"Interactive", FALSE); - if (NT_SUCCESS(PhGetProcessSessionId(NtCurrentProcess(), &sessionId))) - SetDlgItemInt(hwndDlg, IDC_SESSIONID, sessionId, FALSE); + PhpAddProgramsToComboBox(context->ProgramComboBoxWindowHandle); + PhpAddAccountsToComboBox(context->UserComboBoxWindowHandle); + PhpAddSessionsToComboBox(context->SessionEditWindowHandle); + PhpAddDesktopsToComboBox(context, context->DesktopEditWindowHandle); - SetDlgItemText(hwndDlg, IDC_DESKTOP, L"WinSta0\\Default"); - SetDlgItemText(hwndDlg, IDC_PROGRAM, PhaGetStringSetting(L"RunAsProgram")->Buffer); + SetDefaultProgramEntry(context->ProgramComboBoxWindowHandle); + SetDefaultSessionEntry(context->SessionEditWindowHandle); + SetDefaultDesktopEntry(context, context->DesktopEditWindowHandle); if (!context->ProcessId) { - SetDlgItemText(hwndDlg, IDC_USERNAME, - PH_AUTO_T(PH_STRING, PhGetStringSetting(L"RunAsUserName"))->Buffer); + SetWindowText( + context->UserComboBoxWindowHandle, + PH_AUTO_T(PH_STRING, PhGetStringSetting(L"RunAsUserName"))->Buffer + ); // Fire the user name changed event so we can fix the logon type. SendMessage(hwndDlg, WM_COMMAND, MAKEWPARAM(IDC_USERNAME, CBN_EDITCHANGE), 0); @@ -326,7 +821,7 @@ INT_PTR CALLBACK PhpRunAsDlgProc( { if (userName = PhGetSidFullName(user->User.Sid, TRUE, NULL)) { - SetDlgItemText(hwndDlg, IDC_USERNAME, userName->Buffer); + SetWindowText(context->UserComboBoxWindowHandle, userName->Buffer); PhDereferenceObject(userName); } @@ -339,16 +834,18 @@ INT_PTR CALLBACK PhpRunAsDlgProc( NtClose(processHandle); } - EnableWindow(GetDlgItem(hwndDlg, IDC_USERNAME), FALSE); - EnableWindow(GetDlgItem(hwndDlg, IDC_PASSWORD), FALSE); - EnableWindow(GetDlgItem(hwndDlg, IDC_TYPE), FALSE); + EnableWindow(context->UserComboBoxWindowHandle, FALSE); + EnableWindow(context->PasswordEditWindowHandle, FALSE); + EnableWindow(context->TypeComboBoxWindowHandle, FALSE); } - SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hwndDlg, IDC_PROGRAM), TRUE); - Edit_SetSel(GetDlgItem(hwndDlg, IDC_PROGRAM), 0, -1); + SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)context->ProgramComboBoxWindowHandle, TRUE); + Edit_SetSel(context->ProgramComboBoxWindowHandle, -1, -1); //if (!PhGetOwnTokenAttributes().Elevated) // SendMessage(GetDlgItem(hwndDlg, IDOK), BCM_SETSHIELD, 0, TRUE); + + EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); } break; case WM_DESTROY: @@ -357,11 +854,36 @@ INT_PTR CALLBACK PhpRunAsDlgProc( PhDereferenceObject(context->DesktopList); PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); + PhFree(context); } break; case WM_COMMAND: - { - switch (LOWORD(wParam)) + { + switch (GET_WM_COMMAND_CMD(wParam, lParam)) + { + case CBN_DROPDOWN: + { + if (GET_WM_COMMAND_HWND(wParam, lParam) == context->UserComboBoxWindowHandle) + { + //PhpAddAccountsToComboBox(context->UserComboBoxWindowHandle); + } + + if (GET_WM_COMMAND_HWND(wParam, lParam) == context->SessionEditWindowHandle) + { + PhpAddSessionsToComboBox(context->SessionEditWindowHandle); + SetDefaultSessionEntry(context->SessionEditWindowHandle); + } + + if (GET_WM_COMMAND_HWND(wParam, lParam) == context->DesktopEditWindowHandle) + { + PhpAddDesktopsToComboBox(context, context->DesktopEditWindowHandle); + SetDefaultDesktopEntry(context, context->DesktopEditWindowHandle); + } + } + break; + } + + switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDCANCEL: EndDialog(hwndDlg, IDCANCEL); @@ -369,45 +891,85 @@ INT_PTR CALLBACK PhpRunAsDlgProc( case IDOK: { NTSTATUS status; - PPH_STRING program; - PPH_STRING userName; - PPH_STRING password; + BOOLEAN useLinkedToken = FALSE; + BOOLEAN createSuspended = FALSE; + ULONG logonType = ULONG_MAX; + ULONG sessionId = ULONG_MAX; + PPH_STRING program = NULL; + PPH_STRING username = NULL; + PPH_STRING password = NULL; PPH_STRING logonTypeString; - ULONG logonType; - ULONG sessionId; - PPH_STRING desktopName; - BOOLEAN useLinkedToken; + PPH_STRING desktopName = NULL; + INT selectionIndex = CB_ERR; - program = PhaGetDlgItemText(hwndDlg, IDC_PROGRAM); - userName = PhaGetDlgItemText(hwndDlg, IDC_USERNAME); - logonTypeString = PhaGetDlgItemText(hwndDlg, IDC_TYPE); + program = PH_AUTO(PhGetWindowText(context->ProgramComboBoxWindowHandle)); + username = PH_AUTO(PhGetWindowText(context->UserComboBoxWindowHandle)); + logonTypeString = PH_AUTO(PhGetWindowText(context->TypeComboBoxWindowHandle)); + useLinkedToken = Button_GetCheck(GetDlgItem(hwndDlg, IDC_TOGGLEELEVATION)) == BST_CHECKED; + createSuspended = Button_GetCheck(GetDlgItem(hwndDlg, IDC_TOGGLESUSPENDED)) == BST_CHECKED; if (PhIsNullOrEmptyString(program)) break; + if ((selectionIndex = ComboBox_GetCurSel(context->SessionEditWindowHandle)) != CB_ERR) + { + PPH_RUNAS_SESSION_ITEM sessionEntry; + + if (sessionEntry = (PPH_RUNAS_SESSION_ITEM)ComboBox_GetItemData(context->SessionEditWindowHandle, selectionIndex)) + { + sessionId = sessionEntry->SessionId; + } + } + + if ((selectionIndex = ComboBox_GetCurSel(context->DesktopEditWindowHandle)) != CB_ERR) + { + PPH_RUNAS_DESKTOP_ITEM desktopEntry; + + if (desktopEntry = (PPH_RUNAS_DESKTOP_ITEM)ComboBox_GetItemData(context->DesktopEditWindowHandle, selectionIndex)) + { + desktopName = desktopEntry->DesktopName; + } + } + + if (selectionIndex == CB_ERR) + break; + if (sessionId == ULONG_MAX) + break; + // Fix up the user name if it doesn't have a domain. - if (PhFindCharInString(userName, 0, '\\') == -1) + if (PhFindCharInString(username, 0, '\\') == -1) { PSID sid; PPH_STRING newUserName; - if (NT_SUCCESS(PhLookupName(&userName->sr, &sid, NULL, NULL))) + if (NT_SUCCESS(PhLookupName(&username->sr, &sid, NULL, NULL))) { if (newUserName = PH_AUTO(PhGetSidFullName(sid, TRUE, NULL))) - userName = newUserName; + username = newUserName; PhFree(sid); } } - if (!IsServiceAccount(userName)) - password = PhGetWindowText(GetDlgItem(hwndDlg, IDC_PASSWORD)); - else - password = NULL; + if (!IsServiceAccount(username)) + { + password = PhGetWindowText(context->PasswordEditWindowHandle); + SetWindowText(context->PasswordEditWindowHandle, L""); + } - sessionId = GetDlgItemInt(hwndDlg, IDC_SESSIONID, NULL, FALSE); - desktopName = PhaGetDlgItemText(hwndDlg, IDC_DESKTOP); - useLinkedToken = Button_GetCheck(GetDlgItem(hwndDlg, IDC_TOGGLEELEVATION)) == BST_CHECKED; + //if (IsCurrentUserAccount(username)) + //{ + // status = PhCreateProcessWin32( + // NULL, + // program->Buffer, + // NULL, + // NULL, + // 0, + // NULL, + // NULL, + // NULL + // ); + //} if (PhFindIntegerSiKeyValuePairs( PhpLogonTypePairs, @@ -431,7 +993,7 @@ INT_PTR CALLBACK PhpRunAsDlgProc( PPH_STRING domainPart = NULL; PPH_STRING userPart = NULL; - PhpSplitUserName(userName->Buffer, &domainPart, &userPart); + PhpSplitUserName(username->Buffer, &domainPart, &userPart); memset(&createInfo, 0, sizeof(PH_CREATE_PROCESS_AS_USER_INFO)); createInfo.CommandLine = PhGetString(program); @@ -447,7 +1009,7 @@ INT_PTR CALLBACK PhpRunAsDlgProc( status = PhCreateProcessAsUser( &createInfo, - PH_CREATE_PROCESS_WITH_PROFILE, + PH_CREATE_PROCESS_WITH_PROFILE | (createSuspended ? PH_CREATE_PROCESS_SUSPENDED : 0), NULL, NULL, NULL @@ -458,16 +1020,17 @@ INT_PTR CALLBACK PhpRunAsDlgProc( } else { - status = PhExecuteRunAsCommand2( + status = PhExecuteRunAsCommand3( hwndDlg, PhGetString(program), - userName->Buffer, + PhGetString(username), PhGetStringOrEmpty(password), logonType, context->ProcessId, sessionId, - desktopName->Buffer, - useLinkedToken + PhGetString(desktopName), + useLinkedToken, + createSuspended ); } } @@ -485,12 +1048,14 @@ INT_PTR CALLBACK PhpRunAsDlgProc( if (!NT_SUCCESS(status)) { if (status != STATUS_CANCELLED) - PhShowStatus(hwndDlg, L"Unable to start the program", status, 0); + PhShowStatus(hwndDlg, L"Unable to start the program.", status, 0); } else if (status != STATUS_TIMEOUT) { - PhSetStringSetting2(L"RunAsProgram", &program->sr); - PhSetStringSetting2(L"RunAsUserName", &userName->sr); + PhpAddRunMRUListEntry(program->Buffer); + + //PhSetStringSetting2(L"RunAsProgram", &program->sr); + PhSetStringSetting2(L"RunAsUserName", &username->sr); EndDialog(hwndDlg, IDOK); } } @@ -506,14 +1071,14 @@ INT_PTR CALLBACK PhpRunAsDlgProc( fileDialog = PhCreateOpenFileDialog(); PhSetFileDialogFilter(fileDialog, filters, sizeof(filters) / sizeof(PH_FILETYPE_FILTER)); - PhSetFileDialogFileName(fileDialog, PhaGetDlgItemText(hwndDlg, IDC_PROGRAM)->Buffer); + PhSetFileDialogFileName(fileDialog, PH_AUTO_T(PH_STRING, PhGetWindowText(context->ProgramComboBoxWindowHandle))->Buffer); if (PhShowFileDialog(hwndDlg, fileDialog)) { PPH_STRING fileName; fileName = PhGetFileDialogFileName(fileDialog); - SetDlgItemText(hwndDlg, IDC_PROGRAM, fileName->Buffer); + SetWindowText(context->ProgramComboBoxWindowHandle, fileName->Buffer); PhDereferenceObject(fileName); } @@ -522,184 +1087,33 @@ INT_PTR CALLBACK PhpRunAsDlgProc( break; case IDC_USERNAME: { - PPH_STRING userName = NULL; + PPH_STRING username = NULL; - if (!context->ProcessId && HIWORD(wParam) == CBN_SELCHANGE) + if (!context->ProcessId && GET_WM_COMMAND_CMD(wParam, lParam) == CBN_SELCHANGE) { - userName = PH_AUTO(PhGetComboBoxString(GetDlgItem(hwndDlg, IDC_USERNAME), -1)); + username = PH_AUTO(PhGetComboBoxString(context->UserComboBoxWindowHandle, -1)); } else if (!context->ProcessId && ( - HIWORD(wParam) == CBN_EDITCHANGE || - HIWORD(wParam) == CBN_CLOSEUP + GET_WM_COMMAND_CMD(wParam, lParam) == CBN_EDITCHANGE || + GET_WM_COMMAND_CMD(wParam, lParam) == CBN_CLOSEUP )) { - userName = PhaGetDlgItemText(hwndDlg, IDC_USERNAME); + username = PH_AUTO(PhGetWindowText(context->UserComboBoxWindowHandle)); } - if (userName) + if (username) { - if (IsServiceAccount(userName)) + if (IsServiceAccount(username)) { - EnableWindow(GetDlgItem(hwndDlg, IDC_PASSWORD), FALSE); - PhSelectComboBoxString(GetDlgItem(hwndDlg, IDC_TYPE), L"Service", FALSE); + EnableWindow(context->PasswordEditWindowHandle, FALSE); + PhSelectComboBoxString(context->TypeComboBoxWindowHandle, L"Service", FALSE); } else { - EnableWindow(GetDlgItem(hwndDlg, IDC_PASSWORD), TRUE); - PhSelectComboBoxString(GetDlgItem(hwndDlg, IDC_TYPE), L"Interactive", FALSE); - } - } - } - break; - case IDC_SESSIONS: - { - PPH_EMENU sessionsMenu; - PSESSIONIDW sessions; - ULONG numberOfSessions; - ULONG i; - RECT buttonRect; - PPH_EMENU_ITEM selectedItem; - - sessionsMenu = PhCreateEMenu(); - - if (WinStationEnumerateW(NULL, &sessions, &numberOfSessions)) - { - for (i = 0; i < numberOfSessions; i++) - { - PPH_STRING menuString; - WINSTATIONINFORMATION winStationInfo; - ULONG returnLength; - - if (!WinStationQueryInformationW( - NULL, - sessions[i].SessionId, - WinStationInformation, - &winStationInfo, - sizeof(WINSTATIONINFORMATION), - &returnLength - )) - { - winStationInfo.Domain[0] = 0; - winStationInfo.UserName[0] = 0; - } - - if ( - winStationInfo.UserName[0] != 0 && - sessions[i].WinStationName[0] != 0 - ) - { - menuString = PhaFormatString( - L"%u: %s (%s\\%s)", - sessions[i].SessionId, - sessions[i].WinStationName, - winStationInfo.Domain, - winStationInfo.UserName - ); - } - else if (winStationInfo.UserName[0] != 0) - { - menuString = PhaFormatString( - L"%u: %s\\%s", - sessions[i].SessionId, - winStationInfo.Domain, - winStationInfo.UserName - ); - } - else if (sessions[i].WinStationName[0] != 0) - { - menuString = PhaFormatString( - L"%u: %s", - sessions[i].SessionId, - sessions[i].WinStationName - ); - } - else - { - menuString = PhaFormatString(L"%u", sessions[i].SessionId); - } - - PhInsertEMenuItem(sessionsMenu, - PhCreateEMenuItem(0, 0, menuString->Buffer, NULL, UlongToPtr(sessions[i].SessionId)), -1); - } - - WinStationFreeMemory(sessions); - - GetWindowRect(GetDlgItem(hwndDlg, IDC_SESSIONS), &buttonRect); - - selectedItem = PhShowEMenu( - sessionsMenu, - hwndDlg, - PH_EMENU_SHOW_LEFTRIGHT, - PH_ALIGN_LEFT | PH_ALIGN_TOP, - buttonRect.right, - buttonRect.top - ); - - if (selectedItem) - { - SetDlgItemInt( - hwndDlg, - IDC_SESSIONID, - PtrToUlong(selectedItem->Context), - FALSE - ); + EnableWindow(context->PasswordEditWindowHandle, TRUE); + PhSelectComboBoxString(context->TypeComboBoxWindowHandle, L"Interactive", FALSE); } - - PhDestroyEMenu(sessionsMenu); - } - } - break; - case IDC_DESKTOPS: - { - PPH_EMENU desktopsMenu; - ULONG i; - RECT buttonRect; - PPH_EMENU_ITEM selectedItem; - - desktopsMenu = PhCreateEMenu(); - - if (!context->DesktopList) - context->DesktopList = PhCreateList(10); - - context->CurrentWinStaName = GetCurrentWinStaName(); - - EnumDesktops(GetProcessWindowStation(), EnumDesktopsCallback, (LPARAM)context); - - for (i = 0; i < context->DesktopList->Count; i++) - { - PhInsertEMenuItem( - desktopsMenu, - PhCreateEMenuItem(0, 0, ((PPH_STRING)context->DesktopList->Items[i])->Buffer, NULL, NULL), - -1 - ); } - - GetWindowRect(GetDlgItem(hwndDlg, IDC_DESKTOPS), &buttonRect); - - selectedItem = PhShowEMenu( - desktopsMenu, - hwndDlg, - PH_EMENU_SHOW_LEFTRIGHT, - PH_ALIGN_LEFT | PH_ALIGN_TOP, - buttonRect.right, - buttonRect.top - ); - - if (selectedItem) - { - SetDlgItemText( - hwndDlg, - IDC_DESKTOP, - selectedItem->Text - ); - } - - for (i = 0; i < context->DesktopList->Count; i++) - PhDereferenceObject(context->DesktopList->Items[i]); - - PhClearList(context->DesktopList); - PhDereferenceObject(context->CurrentWinStaName); - PhDestroyEMenu(desktopsMenu); } break; } @@ -744,10 +1158,9 @@ VOID PhSetDesktopWinStaAccess( (ULONG)sizeof(ACCESS_ALLOWED_ACE) + RtlLengthSid(allAppPackagesSid); securityDescriptor = PhAllocate(allocationLength); - dacl = (PACL)PTR_ADD_OFFSET(securityDescriptor, SECURITY_DESCRIPTOR_MIN_LENGTH); + dacl = PTR_ADD_OFFSET(securityDescriptor, SECURITY_DESCRIPTOR_MIN_LENGTH); RtlCreateSecurityDescriptor(securityDescriptor, SECURITY_DESCRIPTOR_REVISION); - RtlCreateAcl(dacl, allocationLength - SECURITY_DESCRIPTOR_MIN_LENGTH, ACL_REVISION); RtlAddAccessAllowedAce(dacl, ACL_REVISION, GENERIC_ALL, &PhSeEveryoneSid); @@ -909,6 +1322,22 @@ NTSTATUS PhExecuteRunAsCommand2( _In_ PWSTR DesktopName, _In_ BOOLEAN UseLinkedToken ) +{ + return PhExecuteRunAsCommand3(hWnd, Program, UserName, Password, LogonType, ProcessIdWithToken, SessionId, DesktopName, UseLinkedToken, FALSE); +} + +NTSTATUS PhExecuteRunAsCommand3( + _In_ HWND hWnd, + _In_ PWSTR Program, + _In_opt_ PWSTR UserName, + _In_opt_ PWSTR Password, + _In_opt_ ULONG LogonType, + _In_opt_ HANDLE ProcessIdWithToken, + _In_ ULONG SessionId, + _In_ PWSTR DesktopName, + _In_ BOOLEAN UseLinkedToken, + _In_ BOOLEAN CreateSuspendedProcess + ) { NTSTATUS status = STATUS_SUCCESS; PH_RUNAS_SERVICE_PARAMETERS parameters; @@ -925,6 +1354,7 @@ NTSTATUS PhExecuteRunAsCommand2( parameters.CommandLine = Program; parameters.DesktopName = DesktopName; parameters.UseLinkedToken = UseLinkedToken; + parameters.CreateSuspendedProcess = CreateSuspendedProcess; // Try to use an existing instance of the service if possible. if (RunAsOldServiceName[0] != 0) @@ -994,13 +1424,17 @@ static VOID PhpSplitUserName( if (PhSplitStringRefAtChar(&userName, '\\', &domainPart, &userPart)) { - *DomainPart = PhCreateString2(&domainPart); - *UserPart = PhCreateString2(&userPart); + if (DomainPart) + *DomainPart = PhCreateString2(&domainPart); + if (UserPart) + *UserPart = PhCreateString2(&userPart); } else { - *DomainPart = NULL; - *UserPart = PhCreateString2(&userName); + if (DomainPart) + *DomainPart = NULL; + if (UserPart) + *UserPart = PhCreateString2(&userName); } } @@ -1134,6 +1568,8 @@ NTSTATUS PhInvokeRunAsService( if (Parameters->UseLinkedToken) flags |= PH_CREATE_PROCESS_USE_LINKED_TOKEN; + if (Parameters->CreateSuspendedProcess) + flags |= PH_CREATE_PROCESS_SUSPENDED; status = PhCreateProcessAsUser( &createInfo, From 0950643eed9ac33ad9dcfdbf6b8c0d3933bd427b Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 10 Feb 2018 00:12:41 +1100 Subject: [PATCH 0797/2058] Add NtCurrentProcessToken macro; Tidy up runas code --- ProcessHacker/main.c | 34 +++--------- ProcessHacker/runas.c | 119 ++++++++++++++++++++--------------------- phlib/include/lsasup.h | 8 +++ phlib/lsasup.c | 17 ++++++ phlib/native.c | 66 +++++++++++++---------- phnt/include/ntpsapi.h | 5 ++ 6 files changed, 135 insertions(+), 114 deletions(-) diff --git a/ProcessHacker/main.c b/ProcessHacker/main.c index 3fdcb508f75b..5efe777b2adf 100644 --- a/ProcessHacker/main.c +++ b/ProcessHacker/main.c @@ -116,7 +116,6 @@ INT WINAPI wWinMain( #ifdef DEBUG PHP_BASE_THREAD_DBG dbg; #endif - HANDLE currentTokenHandle; CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE); @@ -133,33 +132,14 @@ INT WINAPI wWinMain( PhInitializeCommonControls(); - currentTokenHandle = PhGetOwnTokenAttributes().TokenHandle; - - if (currentTokenHandle) - { - PTOKEN_USER tokenUser; - - if (NT_SUCCESS(PhGetTokenUser(currentTokenHandle, &tokenUser))) - { - PhCurrentUserName = PhGetSidFullName(tokenUser->User.Sid, TRUE, NULL); - PhFree(tokenUser); - } - } - - PhLocalSystemName = PhGetSidFullName(&PhSeLocalSystemSid, TRUE, NULL); - - // There has been a report of the above call failing. - if (!PhLocalSystemName) - PhLocalSystemName = PhCreateString(L"NT AUTHORITY\\SYSTEM"); - - PhApplicationFileName = PhGetApplicationFileName(); - PhApplicationDirectory = PhGetApplicationDirectory(); - - // Just in case - if (!PhApplicationFileName) + if (!(PhApplicationFileName = PhGetApplicationFileName())) PhApplicationFileName = PhCreateString(L"ProcessHacker.exe"); - if (!PhApplicationDirectory) + if (!(PhApplicationDirectory = PhGetApplicationDirectory())) PhApplicationDirectory = PhReferenceEmptyString(); + if (!(PhLocalSystemName = PhGetSidFullName(&PhSeLocalSystemSid, TRUE, NULL))) + PhLocalSystemName = PhCreateString(L"NT AUTHORITY\\SYSTEM"); + if (!(PhCurrentUserName = PhGetTokenUserString(PhGetOwnTokenAttributes().TokenHandle, TRUE))) + PhLocalSystemName = PhReferenceEmptyString(); PhpProcessStartupParameters(); PhSettingsInitialization(); @@ -1324,7 +1304,7 @@ VOID PhpEnablePrivileges( { HANDLE tokenHandle; - if (NT_SUCCESS(NtOpenProcessToken( + if (NT_SUCCESS(PhOpenProcessToken( NtCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &tokenHandle diff --git a/ProcessHacker/runas.c b/ProcessHacker/runas.c index 6fd8865eb0bc..c99eb008b8c1 100644 --- a/ProcessHacker/runas.c +++ b/ProcessHacker/runas.c @@ -220,24 +220,17 @@ BOOLEAN IsCurrentUserAccount( _In_ PPH_STRING UserName ) { - PTOKEN_USER userToken; PPH_STRING userName; - if (NT_SUCCESS(PhGetTokenUser(PhGetOwnTokenAttributes().TokenHandle, &userToken))) + if (userName = PhGetTokenUserString(PhGetOwnTokenAttributes().TokenHandle, TRUE)) { - if (userName = PhGetSidFullName(userToken->User.Sid, TRUE, NULL)) + if (PhEndsWithString(userName, UserName, TRUE)) { - if (PhEndsWithString(userName, UserName, TRUE)) - { - PhDereferenceObject(userName); - PhFree(userToken); - return TRUE; - } - PhDereferenceObject(userName); + return TRUE; } - PhFree(userToken); + PhDereferenceObject(userName); } return FALSE; @@ -271,42 +264,60 @@ PPH_STRING GetCurrentWinStaName( BOOLEAN PhpInitializeNetApi(VOID) { - PVOID netapiModuleHandle; + static PH_INITONCE initOnce = PH_INITONCE_INIT; + static PVOID netapiModuleHandle = NULL; - if (!(netapiModuleHandle = LoadLibrary(L"netapi32.dll"))) - return FALSE; + if (PhBeginInitOnce(&initOnce)) + { + if (netapiModuleHandle = LoadLibrary(L"netapi32.dll")) + { + NetUserEnum_I = PhGetProcedureAddress(netapiModuleHandle, "NetUserEnum", 0); + NetApiBufferFree_I = PhGetProcedureAddress(netapiModuleHandle, "NetApiBufferFree", 0); + } - NetUserEnum_I = PhGetProcedureAddress(netapiModuleHandle, "NetUserEnum", 0); - NetApiBufferFree_I = PhGetProcedureAddress(netapiModuleHandle, "NetApiBufferFree", 0); + if (!NetUserEnum_I && !NetApiBufferFree_I) + { + FreeLibrary(netapiModuleHandle); + netapiModuleHandle = NULL; + } - if (!NetUserEnum_I && !NetApiBufferFree_I) - { - FreeLibrary(netapiModuleHandle); - return FALSE; + PhEndInitOnce(&initOnce); } - return TRUE; + if (netapiModuleHandle) + return TRUE; + + return FALSE; } BOOLEAN PhpInitializeMRUList(VOID) { - PVOID comctl32ModuleHandle; + static PH_INITONCE initOnce = PH_INITONCE_INIT; + static PVOID comctl32ModuleHandle = NULL; - if (!(comctl32ModuleHandle = LoadLibrary(L"comctl32.dll"))) - return FALSE; + if (PhBeginInitOnce(&initOnce)) + { + if (comctl32ModuleHandle = LoadLibrary(L"comctl32.dll")) + { + CreateMRUList_I = PhGetProcedureAddress(comctl32ModuleHandle, "CreateMRUListW", 0); + AddMRUString_I = PhGetProcedureAddress(comctl32ModuleHandle, "AddMRUStringW", 0); + EnumMRUList_I = PhGetProcedureAddress(comctl32ModuleHandle, "EnumMRUListW", 0); + FreeMRUList_I = PhGetProcedureAddress(comctl32ModuleHandle, "FreeMRUList", 0); + } - CreateMRUList_I = PhGetProcedureAddress(comctl32ModuleHandle, "CreateMRUListW", 0); - AddMRUString_I = PhGetProcedureAddress(comctl32ModuleHandle, "AddMRUStringW", 0); - EnumMRUList_I = PhGetProcedureAddress(comctl32ModuleHandle, "EnumMRUListW", 0); - FreeMRUList_I = PhGetProcedureAddress(comctl32ModuleHandle, "FreeMRUList", 0); + if (!CreateMRUList_I && !AddMRUString_I && !EnumMRUList_I && !FreeMRUList_I) + { + FreeLibrary(comctl32ModuleHandle); + comctl32ModuleHandle = NULL; + } - if (!CreateMRUList_I && !AddMRUString_I && !EnumMRUList_I && !FreeMRUList_I) - { - FreeLibrary(comctl32ModuleHandle); - return FALSE; + PhEndInitOnce(&initOnce); } - return TRUE; + if (comctl32ModuleHandle) + return TRUE; + + return FALSE; } static HANDLE PhpCreateRunMRUList( @@ -328,19 +339,21 @@ static HANDLE PhpCreateRunMRUList( } static VOID PhpAddRunMRUListEntry( - _In_ PWSTR CommandLine + _In_ PPH_STRING CommandLine ) { + static PH_STRINGREF prefixSr = PH_STRINGREF_INIT(L"\\1"); HANDLE listHandle; PPH_STRING commandString; if (!(listHandle = PhpCreateRunMRUList())) return; - commandString = PhConcatStrings2(CommandLine, L"\\1"); + commandString = PhConcatStringRef2(&CommandLine->sr, &prefixSr); + AddMRUString_I(listHandle, commandString->Buffer); - PhDereferenceObject(commandString); + PhDereferenceObject(commandString); FreeMRUList_I(listHandle); } @@ -366,7 +379,6 @@ static VOID PhpAddProgramsToComboBox( for (INT i = 0; i < listCount; i++) { - static PH_STRINGREF keyNamePlusEquals = PH_STRINGREF_INIT(L"\\1"); PPH_STRING programName; PH_STRINGREF nameSr; PH_STRINGREF firstPart; @@ -385,7 +397,7 @@ static VOID PhpAddProgramsToComboBox( PhInitializeStringRefLongHint(&nameSr, entry); - if (!PhSplitStringRefAtString(&nameSr, &keyNamePlusEquals, TRUE, &firstPart, &remainingPart)) + if (!PhSplitStringRefAtString(&nameSr, &prefixSr, TRUE, &firstPart, &remainingPart)) { ComboBox_AddString(ComboBoxHandle, entry); continue; @@ -448,20 +460,13 @@ static VOID PhpAddAccountsToComboBox( if (status == NERR_Success) { - PTOKEN_USER userToken; + PPH_STRING username; PPH_STRING userDomainName = NULL; - if (NT_SUCCESS(PhGetTokenUser(PhGetOwnTokenAttributes().TokenHandle, &userToken))) + if (username = PhGetTokenUserString(PhGetOwnTokenAttributes().TokenHandle, TRUE)) { - PPH_STRING username; - - if (username = PhGetSidFullName(userToken->User.Sid, TRUE, NULL)) - { - PhpSplitUserName(username->Buffer, &userDomainName, NULL); - PhDereferenceObject(username); - } - - PhFree(userToken); + PhpSplitUserName(username->Buffer, &userDomainName, NULL); + PhDereferenceObject(username); } for (ULONG i = 0; i < userinfoEntriesRead; i++) @@ -802,7 +807,6 @@ INT_PTR CALLBACK PhpRunAsDlgProc( { HANDLE processHandle; HANDLE tokenHandle; - PTOKEN_USER user; PPH_STRING userName; if (NT_SUCCESS(PhOpenProcess( @@ -817,15 +821,10 @@ INT_PTR CALLBACK PhpRunAsDlgProc( &tokenHandle ))) { - if (NT_SUCCESS(PhGetTokenUser(tokenHandle, &user))) + if (userName = PhGetTokenUserString(tokenHandle, TRUE)) { - if (userName = PhGetSidFullName(user->User.Sid, TRUE, NULL)) - { - SetWindowText(context->UserComboBoxWindowHandle, userName->Buffer); - PhDereferenceObject(userName); - } - - PhFree(user); + SetWindowText(context->UserComboBoxWindowHandle, userName->Buffer); + PhDereferenceObject(userName); } NtClose(tokenHandle); @@ -1052,7 +1051,7 @@ INT_PTR CALLBACK PhpRunAsDlgProc( } else if (status != STATUS_TIMEOUT) { - PhpAddRunMRUListEntry(program->Buffer); + PhpAddRunMRUListEntry(program); //PhSetStringSetting2(L"RunAsProgram", &program->sr); PhSetStringSetting2(L"RunAsUserName", &username->sr); @@ -1503,7 +1502,7 @@ NTSTATUS PhRunAsServiceStart( // Enable some required privileges. - if (NT_SUCCESS(NtOpenProcessToken( + if (NT_SUCCESS(PhOpenProcessToken( NtCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &tokenHandle diff --git a/phlib/include/lsasup.h b/phlib/include/lsasup.h index 3784f413bd6d..dd16247d3a34 100644 --- a/phlib/include/lsasup.h +++ b/phlib/include/lsasup.h @@ -81,6 +81,14 @@ PhSidToStringSid( _In_ PSID Sid ); +PHLIBAPI +PPH_STRING +NTAPI +PhGetTokenUserString( + _In_ HANDLE TokenHandle, + _In_ BOOLEAN IncludeDomain + ); + #ifdef __cplusplus } #endif diff --git a/phlib/lsasup.c b/phlib/lsasup.c index d526ca2ffc67..64ba602c422b 100644 --- a/phlib/lsasup.c +++ b/phlib/lsasup.c @@ -480,3 +480,20 @@ PPH_STRING PhSidToStringSid( return NULL; } } + +PPH_STRING PhGetTokenUserString( + _In_ HANDLE TokenHandle, + _In_ BOOLEAN IncludeDomain + ) +{ + PPH_STRING tokenUserString = NULL; + PTOKEN_USER tokenUser; + + if (NT_SUCCESS(PhGetTokenUser(TokenHandle, &tokenUser))) + { + tokenUserString = PhGetSidFullName(tokenUser->User.Sid, IncludeDomain, NULL); + PhFree(tokenUser); + } + + return tokenUserString; +} \ No newline at end of file diff --git a/phlib/native.c b/phlib/native.c index 1373e48883a1..95243249014a 100644 --- a/phlib/native.c +++ b/phlib/native.c @@ -78,22 +78,23 @@ PH_TOKEN_ATTRIBUTES PhGetOwnTokenAttributes( if (PhBeginInitOnce(&initOnce)) { - if (NT_SUCCESS(NtOpenProcessToken( - NtCurrentProcess(), - TOKEN_QUERY, - &attributes.TokenHandle - ))) - { - BOOLEAN elevated = TRUE; - TOKEN_ELEVATION_TYPE elevationType = TokenElevationTypeFull; + BOOLEAN elevated = TRUE; + TOKEN_ELEVATION_TYPE elevationType = TokenElevationTypeFull; + + if (WindowsVersion >= WINDOWS_8) + attributes.TokenHandle = NtCurrentProcessToken(); + else + PhOpenProcessToken(NtCurrentProcess(), TOKEN_QUERY, &attributes.TokenHandle); + if (attributes.TokenHandle) + { PhGetTokenIsElevated(attributes.TokenHandle, &elevated); PhGetTokenElevationType(attributes.TokenHandle, &elevationType); - - attributes.Elevated = elevated; - attributes.ElevationType = elevationType; } + attributes.Elevated = elevated; + attributes.ElevationType = elevationType; + PhEndInitOnce(&initOnce); } @@ -201,6 +202,14 @@ NTSTATUS PhOpenThread( clientId.UniqueProcess = NULL; clientId.UniqueThread = ThreadId; +#ifdef _DEBUG + if (ThreadId == NtCurrentThreadId()) + { + *ThreadHandle = NtCurrentThread(); + return STATUS_SUCCESS; + } +#endif + if (KphIsVerified() && (DesiredAccess & KPH_THREAD_READ_ACCESS) == DesiredAccess) { status = KphOpenThread( @@ -303,6 +312,14 @@ NTSTATUS PhOpenProcessToken( { NTSTATUS status; +#ifdef _DEBUG + if (WINDOWS_HAS_IMMERSIVE && ProcessHandle == NtCurrentProcess()) + { + *TokenHandle = NtCurrentProcessToken(); + return STATUS_SUCCESS; + } +#endif + if (KphIsVerified() && (DesiredAccess & KPH_TOKEN_READ_ACCESS) == DesiredAccess) { status = KphOpenProcessToken( @@ -5574,35 +5591,30 @@ VOID PhpInitializePredefineKeys( ) { static UNICODE_STRING currentUserPrefix = RTL_CONSTANT_STRING(L"\\Registry\\User\\"); - NTSTATUS status; - HANDLE tokenHandle; PTOKEN_USER tokenUser; UNICODE_STRING stringSid; WCHAR stringSidBuffer[SECURITY_MAX_SID_STRING_CHARACTERS]; PUNICODE_STRING currentUserKeyName; // Get the string SID of the current user. - if (NT_SUCCESS(status = NtOpenProcessToken(NtCurrentProcess(), TOKEN_QUERY, &tokenHandle))) - { - if (NT_SUCCESS(status = PhGetTokenUser(tokenHandle, &tokenUser))) - { - stringSid.Buffer = stringSidBuffer; - stringSid.MaximumLength = sizeof(stringSidBuffer); - status = RtlConvertSidToUnicodeString( - &stringSid, - tokenUser->User.Sid, - FALSE - ); + if (NT_SUCCESS(status = PhGetTokenUser(PhGetOwnTokenAttributes().TokenHandle, &tokenUser))) + { + stringSid.Buffer = stringSidBuffer; + stringSid.MaximumLength = sizeof(stringSidBuffer); - PhFree(tokenUser); - } + status = RtlConvertSidToUnicodeString( + &stringSid, + tokenUser->User.Sid, + FALSE + ); - NtClose(tokenHandle); + PhFree(tokenUser); } // Construct the current user key name. + if (NT_SUCCESS(status)) { currentUserKeyName = &PhPredefineKeyNames[PH_KEY_CURRENT_USER_NUMBER]; diff --git a/phnt/include/ntpsapi.h b/phnt/include/ntpsapi.h index ab6e2dfc4c73..28a083a8eedc 100644 --- a/phnt/include/ntpsapi.h +++ b/phnt/include/ntpsapi.h @@ -1004,6 +1004,11 @@ NtResumeProcess( #define ZwCurrentSession() NtCurrentSession() #define NtCurrentPeb() (NtCurrentTeb()->ProcessEnvironmentBlock) +// Windows 8 and above +#define NtCurrentProcessToken() ((HANDLE)(LONG_PTR)-4) +#define NtCurrentThreadToken() ((HANDLE)(LONG_PTR)-5) +#define NtCurrentEffectiveToken() ((HANDLE)(LONG_PTR)-6) + // Not NT, but useful. #define NtCurrentProcessId() (NtCurrentTeb()->ClientId.UniqueProcess) #define NtCurrentThreadId() (NtCurrentTeb()->ClientId.UniqueThread) From 2849881a2f797d3b1d6ab6b922b125a902ebdb0b Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 10 Feb 2018 00:38:59 +1100 Subject: [PATCH 0798/2058] Add PhGetAppContainerPackageName --- phlib/appresolver.c | 71 ++++++++++++++++++++++++++++++++++++ phlib/include/appresolver.h | 4 ++ phlib/include/appresolverp.h | 24 ++++++++++++ 3 files changed, 99 insertions(+) diff --git a/phlib/appresolver.c b/phlib/appresolver.c index 4082a433206b..25bb716e3e9c 100644 --- a/phlib/appresolver.c +++ b/phlib/appresolver.c @@ -24,6 +24,8 @@ #define CINTERFACE #include +#include +#include #include #include #include @@ -71,6 +73,45 @@ static PVOID PhpQueryStartMenuCacheInterface( return startMenuInterface; } +static BOOLEAN PhpQueryKernelAppCoreInitialized( + VOID + ) +{ + static PH_INITONCE initOnce = PH_INITONCE_INIT; + static BOOLEAN kernelAppCoreInitialized = FALSE; + + if (PhBeginInitOnce(&initOnce)) + { + if (WindowsVersion >= WINDOWS_8) + { + PVOID kernelAppBaseAddress; + + if (kernelAppBaseAddress = LoadLibrary(L"kernel.appcore.dll")) + { + AppContainerLookupMoniker_I = PhGetProcedureAddress(kernelAppBaseAddress, "AppContainerLookupMoniker", 0); + AppContainerFreeMemory_I = PhGetProcedureAddress(kernelAppBaseAddress, "AppContainerFreeMemory", 0); + AppContainerRegisterSid_I = PhGetProcedureAddress(kernelAppBaseAddress, "AppContainerRegisterSid", 0); + AppContainerUnregisterSid_I = PhGetProcedureAddress(kernelAppBaseAddress, "AppContainerUnregisterSid", 0); + AppPolicyGetWindowingModel_I = PhGetProcedureAddress(kernelAppBaseAddress, "AppPolicyGetWindowingModel", 0); + } + + if ( + AppContainerLookupMoniker_I && + AppContainerFreeMemory_I && + AppContainerRegisterSid_I && + AppContainerUnregisterSid_I + ) + { + kernelAppCoreInitialized = TRUE; + } + } + + PhEndInitOnce(&initOnce); + } + + return kernelAppCoreInitialized; +} + BOOLEAN PhAppResolverGetAppIdForProcess( _In_ HANDLE ProcessId, _Out_ PPH_STRING *ApplicationUserModelId @@ -114,6 +155,36 @@ BOOLEAN PhAppResolverGetAppIdForProcess( return FALSE; } +PPH_STRING PhGetAppContainerPackageName( + _In_ PSID AppContainerSid + ) +{ + PPH_STRING packageFamilyName = NULL; + PWSTR packageMonikerName; + + if (!PhpQueryKernelAppCoreInitialized()) + return NULL; + + if (SUCCEEDED(AppContainerLookupMoniker_I(AppContainerSid, &packageMonikerName))) + { + packageFamilyName = PhConcatStrings2(packageMonikerName, L" (APP_PACKAGE)"); + AppContainerFreeMemory_I(packageMonikerName); + } + + return packageFamilyName; +} + +BOOLEAN PhGetAppWindowingModel( + _In_ HANDLE ProcessTokenHandle, + _Out_ AppPolicyWindowingModel *ProcessWindowingModelPolicy + ) +{ + if (!PhpQueryKernelAppCoreInitialized() && !AppPolicyGetWindowingModel_I) + return FALSE; + + return SUCCEEDED(AppPolicyGetWindowingModel_I(ProcessTokenHandle, ProcessWindowingModelPolicy)); +} + PPH_LIST PhGetPackageAssetsFromResourceFile( _In_ PWSTR FilePath ) diff --git a/phlib/include/appresolver.h b/phlib/include/appresolver.h index f1c31a91cb9e..dbea2044333a 100644 --- a/phlib/include/appresolver.h +++ b/phlib/include/appresolver.h @@ -32,6 +32,10 @@ BOOLEAN PhAppResolverGetAppIdForProcess( _Out_ PPH_STRING *ApplicationUserModelId ); +PPH_STRING PhGetAppContainerPackageName( + _In_ PSID AppContainerSid + ); + PPH_LIST PhGetPackageAssetsFromResourceFile( _In_ PWSTR FilePath ); diff --git a/phlib/include/appresolverp.h b/phlib/include/appresolverp.h index c556904470e6..4654c30abfe4 100644 --- a/phlib/include/appresolverp.h +++ b/phlib/include/appresolverp.h @@ -43,6 +43,30 @@ static IID IID_IResourceContext_I = { 0xE3C22B30, 0x8502, 0x4B2F,{ 0x91, 0x33, 0 // "6E21E72B-B9B0-42AE-A686-983CF784EDCD" static IID IID_IResourceMap_I = { 0x6E21E72B, 0xB9B0, 0x42AE,{ 0xA6, 0x86, 0x98, 0x3C, 0xF7, 0x84, 0xED, 0xCD } }; +//static HRESULT (WINAPI* AppContainerDeriveSidFromMoniker_I)( // DeriveAppContainerSidFromAppContainerName +// _In_ PCWSTR AppContainerName, +// _Out_ PSID *AppContainerSid +// ) = NULL; +static HRESULT (WINAPI* AppContainerLookupMoniker_I)( + _In_ PSID AppContainerSid, + _Out_ PWSTR *PackageFamilyName + ) = NULL; +static HRESULT (WINAPI* AppContainerRegisterSid_I)( + _In_ PSID Sid, + _In_ PCWSTR AppContainerName, + _In_ PCWSTR DisplayName + ) = NULL; +static HRESULT (WINAPI* AppContainerUnregisterSid_I)( + _In_ PSID Sid + ) = NULL; +static BOOL (WINAPI* AppContainerFreeMemory_I)( + _Frees_ptr_opt_ PVOID Memory + ) = NULL; +static HRESULT (WINAPI* AppPolicyGetWindowingModel_I)( + _In_ HANDLE ProcessTokenHandle, + _Out_ AppPolicyWindowingModel *ProcessWindowingModelPolicy + ); + typedef enum _START_MENU_APP_ITEMS_FLAGS { SMAIF_DEFAULT = 0, From 56b9305fa1aa865a05caa1279f4a357071428a26 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 10 Feb 2018 00:46:23 +1100 Subject: [PATCH 0799/2058] Add process token SID package name --- ProcessHacker/ProcessHacker.rc | 8 +++----- ProcessHacker/prpgtok.c | 1 - ProcessHacker/resource.h | 2 ++ ProcessHacker/tokprp.c | 25 ++++++++++++++----------- phlib/appresolver.c | 6 +++--- 5 files changed, 22 insertions(+), 20 deletions(-) diff --git a/ProcessHacker/ProcessHacker.rc b/ProcessHacker/ProcessHacker.rc index 32a0990ecc10..106581f6e3c7 100644 --- a/ProcessHacker/ProcessHacker.rc +++ b/ProcessHacker/ProcessHacker.rc @@ -713,9 +713,9 @@ STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSM CAPTION "Token" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN - LTEXT "User:",IDC_STATIC,7,7,18,8 + LTEXT "User:",IDC_TOKENUSER,7,7,18,8 EDITTEXT IDC_USER,48,7,205,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER - LTEXT "User SID:",IDC_STATIC,7,18,32,8 + LTEXT "User SID:",IDC_TOKENSID,7,18,32,8 EDITTEXT IDC_USERSID,48,18,205,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER LTEXT "Session:",IDC_STATIC,7,29,28,8 LTEXT "Unknown",IDC_SESSIONID,38,29,30,8 @@ -723,9 +723,7 @@ BEGIN LTEXT "Unknown",IDC_ELEVATED,120,29,30,8 LTEXT "Virtualized:",IDC_STATIC,169,29,36,8 LTEXT "Unknown",IDC_VIRTUALIZED,209,29,44,8 - LTEXT "App container SID:",IDC_STATIC,7,40,62,8 - EDITTEXT IDC_APPCONTAINERSID,75,40,178,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER - CONTROL "",IDC_GROUPS,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,53,246,183 + CONTROL "",IDC_GROUPS,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,42,246,194 PUSHBUTTON "Integrity",IDC_INTEGRITY,149,239,50,14 PUSHBUTTON "Advanced",IDC_ADVANCED,203,239,50,14 END diff --git a/ProcessHacker/prpgtok.c b/ProcessHacker/prpgtok.c index af2946f77f66..5b46413e304a 100644 --- a/ProcessHacker/prpgtok.c +++ b/ProcessHacker/prpgtok.c @@ -75,7 +75,6 @@ INT_PTR CALLBACK PhpProcessTokenHookProc( PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_USER), dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_USERSID), dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_VIRTUALIZED), dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); - PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_APPCONTAINERSID), dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_GROUPS), dialogItem, PH_ANCHOR_ALL); PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_INTEGRITY), dialogItem, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_ADVANCED), dialogItem, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); diff --git a/ProcessHacker/resource.h b/ProcessHacker/resource.h index d68f44785fb2..e82c9362d713 100644 --- a/ProcessHacker/resource.h +++ b/ProcessHacker/resource.h @@ -196,6 +196,8 @@ #define IDC_SOURCELUID 1060 #define IDC_APPCONTAINERSID 1060 #define IDC_LIST 1061 +#define IDC_TOKENUSER 1061 +#define IDC_TOKENSID 1062 #define IDC_PROCESSES 1063 #define IDC_SCAN 1064 #define IDC_SAVE 1065 diff --git a/ProcessHacker/tokprp.c b/ProcessHacker/tokprp.c index 6ee67424fe8d..05532b519fdb 100644 --- a/ProcessHacker/tokprp.c +++ b/ProcessHacker/tokprp.c @@ -22,6 +22,7 @@ */ #include +#include #include #include #include @@ -590,7 +591,6 @@ INT_PTR CALLBACK PhpTokenPageProc( SetDlgItemText(hwndDlg, IDC_USER, L"Unknown"); SetDlgItemText(hwndDlg, IDC_USERSID, L"Unknown"); - SetDlgItemText(hwndDlg, IDC_APPCONTAINERSID, L"Unknown"); if (NT_SUCCESS(tokenPageContext->OpenObject( &tokenHandle, @@ -606,6 +606,7 @@ INT_PTR CALLBACK PhpTokenPageProc( BOOLEAN isVirtualizationAllowed; BOOLEAN isVirtualizationEnabled; PTOKEN_APPCONTAINER_INFORMATION appContainerInfo; + PPH_STRING appContainerName; PPH_STRING appContainerSid; if (NT_SUCCESS(PhGetTokenUser(tokenHandle, &tokenUser))) @@ -652,30 +653,32 @@ INT_PTR CALLBACK PhpTokenPageProc( if (WINDOWS_HAS_IMMERSIVE) { + appContainerName = NULL; appContainerSid = NULL; if (NT_SUCCESS(PhQueryTokenVariableSize(tokenHandle, TokenAppContainerSid, &appContainerInfo))) { if (appContainerInfo->TokenAppContainer) - appContainerSid = PhSidToStringSid(appContainerInfo->TokenAppContainer); + { + appContainerName = PhGetAppContainerPackageName(appContainerInfo->TokenAppContainer); + appContainerSid = PhSidToStringSid(appContainerInfo->TokenAppContainer); + } PhFree(appContainerInfo); } - if (appContainerSid) + if (appContainerName) { - SetDlgItemText(hwndDlg, IDC_APPCONTAINERSID, appContainerSid->Buffer); - PhDereferenceObject(appContainerSid); + SetDlgItemText(hwndDlg, IDC_USER, appContainerName->Buffer); + PhDereferenceObject(appContainerName); } - else + + if (appContainerSid) { - SetDlgItemText(hwndDlg, IDC_APPCONTAINERSID, L"N/A"); + SetDlgItemText(hwndDlg, IDC_USERSID, appContainerSid->Buffer); + PhDereferenceObject(appContainerSid); } } - else - { - SetDlgItemText(hwndDlg, IDC_APPCONTAINERSID, L"N/A"); - } ExtendedListView_SetRedraw(tokenPageContext->ListViewHandle, FALSE); PhpTokenPageFreeListViewEntries(tokenPageContext); diff --git a/phlib/appresolver.c b/phlib/appresolver.c index 25bb716e3e9c..3087c198fc47 100644 --- a/phlib/appresolver.c +++ b/phlib/appresolver.c @@ -73,7 +73,7 @@ static PVOID PhpQueryStartMenuCacheInterface( return startMenuInterface; } -static BOOLEAN PhpQueryKernelAppCoreInitialized( +static BOOLEAN PhpKernelAppCoreInitialized( VOID ) { @@ -162,7 +162,7 @@ PPH_STRING PhGetAppContainerPackageName( PPH_STRING packageFamilyName = NULL; PWSTR packageMonikerName; - if (!PhpQueryKernelAppCoreInitialized()) + if (!PhpKernelAppCoreInitialized()) return NULL; if (SUCCEEDED(AppContainerLookupMoniker_I(AppContainerSid, &packageMonikerName))) @@ -179,7 +179,7 @@ BOOLEAN PhGetAppWindowingModel( _Out_ AppPolicyWindowingModel *ProcessWindowingModelPolicy ) { - if (!PhpQueryKernelAppCoreInitialized() && !AppPolicyGetWindowingModel_I) + if (!PhpKernelAppCoreInitialized() && !AppPolicyGetWindowingModel_I) return FALSE; return SUCCEEDED(AppPolicyGetWindowingModel_I(ProcessTokenHandle, ProcessWindowingModelPolicy)); From 8112a2442216370b5664d823d43398d694b76879 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 10 Feb 2018 01:24:50 +1100 Subject: [PATCH 0800/2058] Export EtpRefreshUnloadedDlls --- ProcessHacker/ProcessHacker.def | 1 + phlib/include/phnative.h | 10 ++++ phlib/native.c | 96 +++++++++++++++++++++++++++++++++ 3 files changed, 107 insertions(+) diff --git a/ProcessHacker/ProcessHacker.def b/ProcessHacker/ProcessHacker.def index c021c8433379..c9bbe2bba07f 100644 --- a/ProcessHacker/ProcessHacker.def +++ b/ProcessHacker/ProcessHacker.def @@ -273,6 +273,7 @@ EXPORTS PhGetProcessIsDotNetEx PhGetProcessMappedFileName PhGetProcessPebString + PhGetProcessUnloadedDlls PhGetProcessWindowTitle PhGetProcessWorkingSetInformation PhGetProcessWsCounters diff --git a/phlib/include/phnative.h b/phlib/include/phnative.h index 75652c55fc2d..6676e3015984 100644 --- a/phlib/include/phnative.h +++ b/phlib/include/phnative.h @@ -279,6 +279,16 @@ PhUnloadDllProcess( _In_opt_ PLARGE_INTEGER Timeout ); +PHLIBAPI +NTSTATUS +NTAPI +PhGetProcessUnloadedDlls( + _In_ HANDLE ProcessId, + _Out_ PVOID *EventTrace, + _Out_ ULONG *EventTraceSize, + _Out_ ULONG *EventTraceCount + ); + PHLIBAPI NTSTATUS NTAPI diff --git a/phlib/native.c b/phlib/native.c index 95243249014a..edba7b613e9f 100644 --- a/phlib/native.c +++ b/phlib/native.c @@ -1233,6 +1233,102 @@ NTSTATUS PhGetProcessWsCounters( return status; } +NTSTATUS PhGetProcessUnloadedDlls( + _In_ HANDLE ProcessId, + _Out_ PVOID *EventTrace, + _Out_ ULONG *EventTraceSize, + _Out_ ULONG *EventTraceCount + ) +{ + NTSTATUS status; + PULONG elementSize; + PULONG elementCount; + PVOID eventTrace; + HANDLE processHandle = NULL; + ULONG eventTraceSize; + ULONG capturedElementSize; + ULONG capturedElementCount; + PVOID capturedEventTracePointer; + PVOID capturedEventTrace = NULL; + + RtlGetUnloadEventTraceEx(&elementSize, &elementCount, &eventTrace); + + if (!NT_SUCCESS(status = PhOpenProcess(&processHandle, PROCESS_VM_READ, ProcessId))) + goto CleanupExit; + + // We have the pointers for the unload event trace information. + // Since ntdll is loaded at the same base address across all processes, + // we can read the information in. + + if (!NT_SUCCESS(status = NtReadVirtualMemory( + processHandle, + elementSize, + &capturedElementSize, + sizeof(ULONG), + NULL + ))) + goto CleanupExit; + + if (!NT_SUCCESS(status = NtReadVirtualMemory( + processHandle, + elementCount, + &capturedElementCount, + sizeof(ULONG), + NULL + ))) + goto CleanupExit; + + if (!NT_SUCCESS(status = NtReadVirtualMemory( + processHandle, + eventTrace, + &capturedEventTracePointer, + sizeof(PVOID), + NULL + ))) + goto CleanupExit; + + if (!capturedEventTracePointer) + { + status = STATUS_NOT_FOUND; // no events + goto CleanupExit; + } + + if (capturedElementCount > 0x4000) + capturedElementCount = 0x4000; + + eventTraceSize = capturedElementSize * capturedElementCount; + capturedEventTrace = PhAllocateSafe(eventTraceSize); + + if (!capturedEventTrace) + { + status = STATUS_NO_MEMORY; + goto CleanupExit; + } + + if (!NT_SUCCESS(status = NtReadVirtualMemory( + processHandle, + capturedEventTracePointer, + capturedEventTrace, + eventTraceSize, + NULL + ))) + goto CleanupExit; + +CleanupExit: + + if (processHandle) + NtClose(processHandle); + + if (NT_SUCCESS(status)) + { + *EventTrace = capturedEventTrace; + *EventTraceSize = capturedElementSize; + *EventTraceCount = capturedElementCount; + } + + return status; +} + /** * Causes a process to unload a DLL. * From 41f830e5f5156781f4fda8e0545b0d7325b06160 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 10 Feb 2018 02:48:18 +1100 Subject: [PATCH 0801/2058] Fix token usage --- ProcessHacker/memlists.c | 10 ++++++++-- ProcessHacker/tokprp.c | 7 ++++++- phlib/appresolver.c | 2 +- phlib/hndlinfo.c | 8 +------- phlib/native.c | 21 ++++++++++----------- plugins/DotNetTools/counters.c | 2 +- 6 files changed, 27 insertions(+), 23 deletions(-) diff --git a/ProcessHacker/memlists.c b/ProcessHacker/memlists.c index c61d9a321db0..e8c8c8a06d0c 100644 --- a/ProcessHacker/memlists.c +++ b/ProcessHacker/memlists.c @@ -170,6 +170,12 @@ INT_PTR CALLBACK PhpMemoryListsDlgProc( { case WM_INITDIALOG: { + if (NT_SUCCESS(PhOpenProcessToken(NtCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &tokenHandle))) + { + PhSetTokenPrivilege(tokenHandle, L"SeProfileSingleProcessPrivilege", NULL, SE_PRIVILEGE_ENABLED); + NtClose(tokenHandle); + } + PhRegisterCallback(&PhProcessesUpdatedEvent, ProcessesUpdatedCallback, NULL, &ProcessesUpdatedRegistration); PhpUpdateMemoryListInfo(hwndDlg); @@ -237,9 +243,9 @@ INT_PTR CALLBACK PhpMemoryListsDlgProc( HANDLE tokenHandle; MEMORY_COMBINE_INFORMATION_EX combineInfo = { 0 }; - if (NT_SUCCESS(NtOpenProcessToken(NtCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &tokenHandle))) + if (NT_SUCCESS(PhOpenProcessToken(NtCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &tokenHandle))) { - PhSetTokenPrivilege(tokenHandle, SE_PROF_SINGLE_PROCESS_NAME, NULL, SE_PRIVILEGE_ENABLED); + PhSetTokenPrivilege(tokenHandle, L"SeProfileSingleProcessPrivilege", NULL, SE_PRIVILEGE_ENABLED); NtClose(tokenHandle); } diff --git a/ProcessHacker/tokprp.c b/ProcessHacker/tokprp.c index 05532b519fdb..9477a0576b8e 100644 --- a/ProcessHacker/tokprp.c +++ b/ProcessHacker/tokprp.c @@ -669,7 +669,12 @@ INT_PTR CALLBACK PhpTokenPageProc( if (appContainerName) { - SetDlgItemText(hwndDlg, IDC_USER, appContainerName->Buffer); + PPH_STRING packageFamilyName; + + packageFamilyName = PhConcatStrings2(appContainerName->Buffer, L" (APP_PACKAGE)"); + SetDlgItemText(hwndDlg, IDC_USER, packageFamilyName->Buffer); + + PhDereferenceObject(packageFamilyName); PhDereferenceObject(appContainerName); } diff --git a/phlib/appresolver.c b/phlib/appresolver.c index 3087c198fc47..b9c0e546b505 100644 --- a/phlib/appresolver.c +++ b/phlib/appresolver.c @@ -167,7 +167,7 @@ PPH_STRING PhGetAppContainerPackageName( if (SUCCEEDED(AppContainerLookupMoniker_I(AppContainerSid, &packageMonikerName))) { - packageFamilyName = PhConcatStrings2(packageMonikerName, L" (APP_PACKAGE)"); + packageFamilyName = PhCreateString(packageMonikerName); AppContainerFreeMemory_I(packageMonikerName); } diff --git a/phlib/hndlinfo.c b/phlib/hndlinfo.c index 877b530f9fd5..dff6e983bdcf 100644 --- a/phlib/hndlinfo.c +++ b/phlib/hndlinfo.c @@ -371,16 +371,10 @@ PPH_STRING PhFormatNativeKeyName( if (PhBeginInitOnce(&initOnce)) { - HANDLE currentTokenHandle; PTOKEN_USER tokenUser; PPH_STRING stringSid = NULL; - currentTokenHandle = PhGetOwnTokenAttributes().TokenHandle; - - if (currentTokenHandle && NT_SUCCESS(PhGetTokenUser( - currentTokenHandle, - &tokenUser - ))) + if (NT_SUCCESS(PhGetTokenUser(PhGetOwnTokenAttributes().TokenHandle, &tokenUser))) { stringSid = PhSidToStringSid(tokenUser->User.Sid); PhFree(tokenUser); diff --git a/phlib/native.c b/phlib/native.c index edba7b613e9f..d68af22a6183 100644 --- a/phlib/native.c +++ b/phlib/native.c @@ -74,7 +74,7 @@ PH_TOKEN_ATTRIBUTES PhGetOwnTokenAttributes( ) { static PH_INITONCE initOnce = PH_INITONCE_INIT; - static PH_TOKEN_ATTRIBUTES attributes; + static PH_TOKEN_ATTRIBUTES attributes = { 0 }; if (PhBeginInitOnce(&initOnce)) { @@ -82,9 +82,16 @@ PH_TOKEN_ATTRIBUTES PhGetOwnTokenAttributes( TOKEN_ELEVATION_TYPE elevationType = TokenElevationTypeFull; if (WindowsVersion >= WINDOWS_8) - attributes.TokenHandle = NtCurrentProcessToken(); + { + attributes.TokenHandle = NtCurrentProcessToken(); + } else - PhOpenProcessToken(NtCurrentProcess(), TOKEN_QUERY, &attributes.TokenHandle); + { + HANDLE tokenHandle; + + if (NT_SUCCESS(PhOpenProcessToken(NtCurrentProcess(), TOKEN_QUERY, &tokenHandle))) + attributes.TokenHandle = tokenHandle; + } if (attributes.TokenHandle) { @@ -312,14 +319,6 @@ NTSTATUS PhOpenProcessToken( { NTSTATUS status; -#ifdef _DEBUG - if (WINDOWS_HAS_IMMERSIVE && ProcessHandle == NtCurrentProcess()) - { - *TokenHandle = NtCurrentProcessToken(); - return STATUS_SUCCESS; - } -#endif - if (KphIsVerified() && (DesiredAccess & KPH_TOKEN_READ_ACCESS) == DesiredAccess) { status = KphOpenProcessToken( diff --git a/plugins/DotNetTools/counters.c b/plugins/DotNetTools/counters.c index badf758550f0..c299f2ac18ec 100644 --- a/plugins/DotNetTools/counters.c +++ b/plugins/DotNetTools/counters.c @@ -557,7 +557,7 @@ BOOLEAN OpenDotNetPublicControlBlock_V4( if (WINDOWS_HAS_IMMERSIVE && IsImmersive) { - if (NT_SUCCESS(NtOpenProcessToken(&tokenHandle, TOKEN_QUERY, ProcessHandle))) + if (NT_SUCCESS(NtOpenProcessToken(ProcessHandle, TOKEN_QUERY, &tokenHandle))) { ULONG returnLength = 0; From 448adba524441164f12ce916c341f70ea72b2d73 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 10 Feb 2018 02:49:41 +1100 Subject: [PATCH 0802/2058] Fix build --- ProcessHacker/memlists.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ProcessHacker/memlists.c b/ProcessHacker/memlists.c index e8c8c8a06d0c..5bccafe87648 100644 --- a/ProcessHacker/memlists.c +++ b/ProcessHacker/memlists.c @@ -170,6 +170,8 @@ INT_PTR CALLBACK PhpMemoryListsDlgProc( { case WM_INITDIALOG: { + HANDLE tokenHandle; + if (NT_SUCCESS(PhOpenProcessToken(NtCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &tokenHandle))) { PhSetTokenPrivilege(tokenHandle, L"SeProfileSingleProcessPrivilege", NULL, SE_PRIVILEGE_ENABLED); From 6bc67f01edd0e8bd7760fae19f2ce99e461bf632 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 10 Feb 2018 02:50:51 +1100 Subject: [PATCH 0803/2058] ExtendedTools: Fix unloaded dll event trace for system processes --- plugins/ExtendedTools/unldll.c | 95 +++++----------------------------- 1 file changed, 13 insertions(+), 82 deletions(-) diff --git a/plugins/ExtendedTools/unldll.c b/plugins/ExtendedTools/unldll.c index 02cd7cff34cf..d76a6d84bf03 100644 --- a/plugins/ExtendedTools/unldll.c +++ b/plugins/ExtendedTools/unldll.c @@ -64,88 +64,32 @@ BOOLEAN EtpRefreshUnloadedDlls( ) { NTSTATUS status; - PULONG elementSize; - PULONG elementCount; - PVOID eventTrace; - HANDLE processHandle = NULL; - ULONG eventTraceSize; ULONG capturedElementSize; ULONG capturedElementCount; - PVOID capturedEventTracePointer; PVOID capturedEventTrace = NULL; ULONG i; PVOID currentEvent; HWND lvHandle; - lvHandle = GetDlgItem(hwndDlg, IDC_LIST); - - RtlGetUnloadEventTraceEx(&elementSize, &elementCount, &eventTrace); - - if (!NT_SUCCESS(status = PhOpenProcess(&processHandle, PROCESS_VM_READ, Context->ProcessItem->ProcessId))) - goto CleanupExit; - - // We have the pointers for the unload event trace information. - // Since ntdll is loaded at the same base address across all processes, - // we can read the information in. - - if (!NT_SUCCESS(status = NtReadVirtualMemory( - processHandle, - elementSize, + status = PhGetProcessUnloadedDlls( + Context->ProcessItem->ProcessId, + &capturedEventTrace, &capturedElementSize, - sizeof(ULONG), - NULL - ))) - goto CleanupExit; - - if (!NT_SUCCESS(status = NtReadVirtualMemory( - processHandle, - elementCount, - &capturedElementCount, - sizeof(ULONG), - NULL - ))) - goto CleanupExit; - - if (!NT_SUCCESS(status = NtReadVirtualMemory( - processHandle, - eventTrace, - &capturedEventTracePointer, - sizeof(PVOID), - NULL - ))) - goto CleanupExit; - - if (!capturedEventTracePointer) - goto CleanupExit; // no events - - if (capturedElementCount > 0x4000) - capturedElementCount = 0x4000; - - eventTraceSize = capturedElementSize * capturedElementCount; - - capturedEventTrace = PhAllocateSafe(eventTraceSize); - - if (!capturedEventTrace) + &capturedElementCount + ); + + if (!NT_SUCCESS(status)) { - status = STATUS_NO_MEMORY; - goto CleanupExit; + PhShowStatus(NULL, L"Unable to retrieve unload event trace information.", status, 0); + return FALSE; } - if (!NT_SUCCESS(status = NtReadVirtualMemory( - processHandle, - capturedEventTracePointer, - capturedEventTrace, - eventTraceSize, - NULL - ))) - goto CleanupExit; - - currentEvent = capturedEventTrace; - + lvHandle = GetDlgItem(hwndDlg, IDC_LIST); ExtendedListView_SetRedraw(lvHandle, FALSE); - ListView_DeleteAllItems(lvHandle); + currentEvent = capturedEventTrace; + for (i = 0; i < capturedElementCount; i++) { PRTL_UNLOAD_EVENT_TRACE rtlEvent = currentEvent; @@ -199,20 +143,7 @@ BOOLEAN EtpRefreshUnloadedDlls( Context->CapturedEventTrace = capturedEventTrace; -CleanupExit: - - if (processHandle) - NtClose(processHandle); - - if (NT_SUCCESS(status)) - { - return TRUE; - } - else - { - PhShowStatus(hwndDlg, L"Unable to retrieve unload event trace information", status, 0); - return FALSE; - } + return NT_SUCCESS(status); } static INT NTAPI EtpNumberCompareFunction( From 2d38629ade2432d6cc62d7c8bfbb8078df4dffd4 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 10 Feb 2018 04:46:39 +1100 Subject: [PATCH 0804/2058] Fix options window crash --- ProcessHacker/options.c | 121 ++++++++++++++++++++++++++-------------- 1 file changed, 80 insertions(+), 41 deletions(-) diff --git a/ProcessHacker/options.c b/ProcessHacker/options.c index e9dba405afcc..8032b5d4e0f0 100644 --- a/ProcessHacker/options.c +++ b/ProcessHacker/options.c @@ -37,6 +37,7 @@ #include #define WM_PH_CHILD_EXIT (WM_APP + 301) +#define WM_PH_SHOWDIALOG (WM_APP + 302) INT_PTR CALLBACK PhpOptionsGeneralDlgProc( _In_ HWND hwndDlg, @@ -134,6 +135,8 @@ VOID PhpSetDefaultTaskManager( ); static HWND PhOptionsWindowHandle = NULL; +static HANDLE PhOptionsWindowThreadHandle = NULL; +static PH_EVENT PhOptionsWindowInitializedEvent = PH_EVENT_INIT; static PPH_LIST PhOptionsDialogList = NULL; static PH_LAYOUT_MANAGER WindowLayoutManager; @@ -148,19 +151,71 @@ static BOOLEAN RestartRequired = FALSE; // General static PH_STRINGREF CurrentUserRunKeyName = PH_STRINGREF_INIT(L"Software\\Microsoft\\Windows\\CurrentVersion\\Run"); -static BOOLEAN CurrentUserRunPresent; -static BOOLEAN CurrentUserRunStartHidden; -static HFONT CurrentFontInstance; -static PPH_STRING NewFontSelection; +static BOOLEAN CurrentUserRunPresent = FALSE; +static BOOLEAN CurrentUserRunStartHidden = FALSE; +static HFONT CurrentFontInstance = NULL; +static PPH_STRING NewFontSelection = NULL; static HIMAGELIST GeneralListviewImageList = NULL; // Advanced static PH_STRINGREF TaskMgrImageOptionsKeyName = PH_STRINGREF_INIT(L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\taskmgr.exe"); -static PPH_STRING OldTaskMgrDebugger; -static HWND WindowHandleForElevate; +static PPH_STRING OldTaskMgrDebugger = NULL; +static HWND WindowHandleForElevate = NULL; // Highlighting -static HWND HighlightingListViewHandle; +static HWND HighlightingListViewHandle = NULL; + +NTSTATUS ShowUpdateDialogThread( + _In_ PVOID Parameter + ) +{ + PH_AUTO_POOL autoPool; + + PhInitializeAutoPool(&autoPool); + + DialogBox( + PhInstanceHandle, + MAKEINTRESOURCE(IDD_OPTIONS), + NULL, + PhOptionsDialogProc + ); + + PhUpdateCachedSettings(); + ProcessHacker_SaveAllSettings(PhMainWndHandle); + PhInvalidateAllProcessNodes(); + PhReloadSettingsProcessTreeList(); + PhSiNotifyChangeSettings(); + + if (RestartRequired) + { + if (PhShowMessage2( + PhMainWndHandle, + TDCBF_YES_BUTTON | TDCBF_NO_BUTTON, + TD_INFORMATION_ICON, + L"One or more options you have changed requires a restart of Process Hacker.", + L"Do you want to restart Process Hacker now?" + ) == IDYES) + { + ProcessHacker_PrepareForEarlyShutdown(PhMainWndHandle); + PhShellProcessHacker( + PhMainWndHandle, + L"-v", + SW_SHOW, + 0, + PH_SHELL_APP_PROPAGATE_PARAMETERS | PH_SHELL_APP_PROPAGATE_PARAMETERS_IGNORE_VISIBILITY, + 0, + NULL + ); + ProcessHacker_Destroy(PhMainWndHandle); + } + } + + PhDeleteAutoPool(&autoPool); + + PhResetEvent(&PhOptionsWindowInitializedEvent); + + return STATUS_SUCCESS; +} VOID PhShowOptionsDialog( _In_ HWND ParentWindowHandle @@ -172,42 +227,14 @@ VOID PhShowOptionsDialog( } else { - DialogBox( - PhInstanceHandle, - MAKEINTRESOURCE(IDD_OPTIONS), - NULL, - PhOptionsDialogProc - ); - - PhUpdateCachedSettings(); - ProcessHacker_SaveAllSettings(PhMainWndHandle); - PhInvalidateAllProcessNodes(); - PhReloadSettingsProcessTreeList(); - PhSiNotifyChangeSettings(); - - if (RestartRequired) + if (!PhTestEvent(&PhOptionsWindowInitializedEvent)) { - if (PhShowMessage2( - PhMainWndHandle, - TDCBF_YES_BUTTON | TDCBF_NO_BUTTON, - TD_INFORMATION_ICON, - L"One or more options you have changed requires a restart of Process Hacker.", - L"Do you want to restart Process Hacker now?" - ) == IDYES) - { - ProcessHacker_PrepareForEarlyShutdown(PhMainWndHandle); - PhShellProcessHacker( - PhMainWndHandle, - L"-v", - SW_SHOW, - 0, - PH_SHELL_APP_PROPAGATE_PARAMETERS | PH_SHELL_APP_PROPAGATE_PARAMETERS_IGNORE_VISIBILITY, - 0, - NULL - ); - ProcessHacker_Destroy(PhMainWndHandle); - } + PhCreateThread2(ShowUpdateDialogThread, NULL); + + PhWaitForEvent(&PhOptionsWindowInitializedEvent, NULL); } + + PostMessage(PhOptionsWindowHandle, WM_PH_SHOWDIALOG, 0, 0); } } @@ -354,6 +381,8 @@ INT_PTR CALLBACK PhOptionsDialogProc( PhOptionsEnterSectionView(section); PhOptionsOnSize(); } + + PhSetEvent(&PhOptionsWindowInitializedEvent); } break; case WM_NCDESTROY: @@ -375,6 +404,16 @@ INT_PTR CALLBACK PhOptionsDialogProc( PhDeleteLayoutManager(&WindowLayoutManager); } break; + case WM_PH_SHOWDIALOG: + { + if (IsMinimized(hwndDlg)) + ShowWindow(hwndDlg, SW_RESTORE); + else + ShowWindow(hwndDlg, SW_SHOW); + + SetForegroundWindow(hwndDlg); + } + break; case WM_SIZE: { PhOptionsOnSize(); From 70b5cbaff05143b511a22d6320ced97e38e21b0e Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 10 Feb 2018 04:47:08 +1100 Subject: [PATCH 0805/2058] Fix typo --- phnt/include/ntrtl.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phnt/include/ntrtl.h b/phnt/include/ntrtl.h index adbd3f164e50..3c480d565934 100644 --- a/phnt/include/ntrtl.h +++ b/phnt/include/ntrtl.h @@ -3212,7 +3212,7 @@ RtlDosSearchPath_U( #define RTL_DOS_SEARCH_PATH_FLAG_APPLY_ISOLATION_REDIRECTION 0x00000001 #define RTL_DOS_SEARCH_PATH_FLAG_DISALLOW_DOT_RELATIVE_PATH_SEARCH 0x00000002 -#define RTL_DOS_SEARCH_PATH_FLAG_APPLY_DEFAULT_EXTENSION_WHEN_NOT_RELATIVE_PATH_EVEN_IF_FILE_HAS_EXTENSION 0x00000004) +#define RTL_DOS_SEARCH_PATH_FLAG_APPLY_DEFAULT_EXTENSION_WHEN_NOT_RELATIVE_PATH_EVEN_IF_FILE_HAS_EXTENSION 0x00000004 NTSYSAPI NTSTATUS From 4bcaaa0b76b1ede1c838a536de2230bec720a4ac Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 10 Feb 2018 04:51:02 +1100 Subject: [PATCH 0806/2058] Update PhSearchFilePath parameters --- ProcessHacker/mainwnd.c | 6 +++--- phlib/util.c | 44 +++++++++++++++++++++++------------------ 2 files changed, 28 insertions(+), 22 deletions(-) diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index 27b37e528790..6ea93141f474 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -1827,11 +1827,11 @@ BOOLEAN PhMwpOnNotify( if (fileName && !RtlDoesFileExists_U(fileName->Buffer)) { - WCHAR buffer[MAX_PATH]; + PPH_STRING filePathString; // The user typed a name without a path so attempt to locate the executable. - if (PhSearchFilePath(fileName->Buffer, L".exe", buffer)) - PhMoveReference(&fileName, PhCreateString(buffer)); + if (PhSearchFilePath(fileName->Buffer, L".exe", &filePathString)) + PhMoveReference(&fileName, filePathString); else PhClearReference(&fileName); } diff --git a/phlib/util.c b/phlib/util.c index f74f27e543d9..4c45de2b944b 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -2602,11 +2602,11 @@ NTSTATUS PhCreateProcessWin32Ex( if (fileName && !RtlDoesFileExists_U(fileName->Buffer)) { - WCHAR buffer[MAX_PATH]; + PPH_STRING filePathSr; // The user typed a name without a path so attempt to locate the executable. - if (PhSearchFilePath(fileName->Buffer, L".exe", buffer)) - PhMoveReference(&fileName, PhCreateString(buffer)); + if (PhSearchFilePath(fileName->Buffer, L".exe", &filePathSr)) + PhMoveReference(&fileName, filePathSr); else PhClearReference(&fileName); } @@ -4902,7 +4902,7 @@ BOOLEAN PhParseCommandLineFuzzy( PH_STRINGREF temp; PH_STRINGREF currentPart; PH_STRINGREF remainingPart; - WCHAR buffer[MAX_PATH]; + PPH_STRING filePathSr; WCHAR originalChar; commandLine = *CommandLine; @@ -4949,9 +4949,9 @@ BOOLEAN PhParseCommandLineFuzzy( tempCommandLine = PhCreateString2(&commandLine); - if (PhSearchFilePath(tempCommandLine->Buffer, L".exe", buffer)) + if (PhSearchFilePath(tempCommandLine->Buffer, L".exe", &filePathSr)) { - *FullFileName = PhCreateString(buffer); + *FullFileName = filePathSr; } else { @@ -4995,7 +4995,7 @@ BOOLEAN PhParseCommandLineFuzzy( *(remainingPart.Buffer - 1) = 0; } - result = PhSearchFilePath(temp.Buffer, L".exe", buffer); + result = PhSearchFilePath(temp.Buffer, L".exe", &filePathSr); if (found) { @@ -5011,7 +5011,9 @@ BOOLEAN PhParseCommandLineFuzzy( *Arguments = remainingPart; if (FullFileName) - *FullFileName = PhCreateString(buffer); + *FullFileName = filePathSr; + else + PhDereferenceObject(filePathSr); PhFree(temp.Buffer); @@ -5019,6 +5021,7 @@ BOOLEAN PhParseCommandLineFuzzy( } } + PhDereferenceObject(filePathSr); PhFree(temp.Buffer); *FileName = *CommandLine; @@ -5033,57 +5036,60 @@ BOOLEAN PhParseCommandLineFuzzy( BOOLEAN PhSearchFilePath( _In_ PWSTR FileName, _In_opt_ PWSTR Extension, - _Out_writes_(MAX_PATH) PWSTR Buffer + _Out_ PPH_STRING *FilePath ) { NTSTATUS status; - ULONG result; - UNICODE_STRING fileName; + ULONG bufferLength; + UNICODE_STRING fileNameUs; OBJECT_ATTRIBUTES objectAttributes; FILE_BASIC_INFORMATION basicInfo; + WCHAR buffer[MAX_PATH + 1] = L""; - result = SearchPath( + bufferLength = SearchPath( NULL, FileName, Extension, MAX_PATH, - Buffer, + buffer, NULL ); - if (result == 0 || result >= MAX_PATH) + if (bufferLength == 0 && bufferLength <= MAX_PATH) return FALSE; // Make sure this is not a directory. if (!NT_SUCCESS(RtlDosPathNameToNtPathName_U_WithStatus( - Buffer, - &fileName, + buffer, + &fileNameUs, NULL, NULL ))) + { return FALSE; + } InitializeObjectAttributes( &objectAttributes, - &fileName, + &fileNameUs, OBJ_CASE_INSENSITIVE, NULL, NULL ); status = NtQueryAttributesFile(&objectAttributes, &basicInfo); - RtlFreeUnicodeString(&fileName); + RtlFreeUnicodeString(&fileNameUs); if (!NT_SUCCESS(status)) return FALSE; if (basicInfo.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) return FALSE; + *FilePath = PhCreateString(buffer); return TRUE; } - PPH_STRING PhGetCacheDirectory( VOID ) From 48ab1f7af46038dc9e48f5e0e795ae81786cda13 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 10 Feb 2018 05:02:39 +1100 Subject: [PATCH 0807/2058] Remove duplicate token handle --- ProcessHacker/memlists.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/ProcessHacker/memlists.c b/ProcessHacker/memlists.c index 5bccafe87648..2922350923d5 100644 --- a/ProcessHacker/memlists.c +++ b/ProcessHacker/memlists.c @@ -242,15 +242,8 @@ INT_PTR CALLBACK PhpMemoryListsDlgProc( case ID_EMPTY_COMBINEMEMORYLISTS: { NTSTATUS status; - HANDLE tokenHandle; MEMORY_COMBINE_INFORMATION_EX combineInfo = { 0 }; - if (NT_SUCCESS(PhOpenProcessToken(NtCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &tokenHandle))) - { - PhSetTokenPrivilege(tokenHandle, L"SeProfileSingleProcessPrivilege", NULL, SE_PRIVILEGE_ENABLED); - NtClose(tokenHandle); - } - status = NtSetSystemInformation( SystemCombinePhysicalMemoryInformation, &combineInfo, From 87fc6e587cb428a783ffe125c3b5ba7380376bf3 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 10 Feb 2018 05:08:42 +1100 Subject: [PATCH 0808/2058] Add permissions button to service properties window, Add ServiceStage2 delayload workaround --- ProcessHacker/ProcessHacker.rc | 1 + ProcessHacker/include/srvlist.h | 3 +- ProcessHacker/include/srvprv.h | 4 +++ ProcessHacker/srvlist.c | 50 ++++++++++--------------------- ProcessHacker/srvprp.c | 52 +++++++++++++++++---------------- ProcessHacker/srvprv.c | 9 +++--- 6 files changed, 53 insertions(+), 66 deletions(-) diff --git a/ProcessHacker/ProcessHacker.rc b/ProcessHacker/ProcessHacker.rc index 106581f6e3c7..12e2c50f452c 100644 --- a/ProcessHacker/ProcessHacker.rc +++ b/ProcessHacker/ProcessHacker.rc @@ -657,6 +657,7 @@ BEGIN LTEXT "Service DLL:",IDC_STATIC,7,144,48,8 EDITTEXT IDC_SERVICEDLL,58,142,217,12,ES_AUTOHSCROLL | ES_READONLY CONTROL "Delayed start",IDC_DELAYEDSTART,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,158,59,10 + PUSHBUTTON "Permissions",IDC_PERMISSIONS,225,162,50,14 END IDD_HNDLGENERAL DIALOGEX 0, 0, 260, 181 diff --git a/ProcessHacker/include/srvlist.h b/ProcessHacker/include/srvlist.h index 9636369dd48d..0c3cd530901a 100644 --- a/ProcessHacker/include/srvlist.h +++ b/ProcessHacker/include/srvlist.h @@ -49,10 +49,9 @@ typedef struct _PH_SERVICE_NODE PPH_STRING Description; // Key LARGE_INTEGER KeyLastWriteTime; - PPH_STRING TooltipText; - PPH_STRING KeyModifiedTimeText; + BOOLEAN ServiceQueryStage2; // begin_phapppub } PH_SERVICE_NODE, *PPH_SERVICE_NODE; // end_phapppub diff --git a/ProcessHacker/include/srvprv.h b/ProcessHacker/include/srvprv.h index 7a1034f557cd..a884dd2d9f20 100644 --- a/ProcessHacker/include/srvprv.h +++ b/ProcessHacker/include/srvprv.h @@ -106,6 +106,10 @@ VOID PhUpdateProcessItemServices( _In_ PPH_PROCESS_ITEM ProcessItem ); +VOID PhQueueServiceQueryStage2( // HACK + _In_ PPH_SERVICE_ITEM ServiceItem + ); + VOID PhServiceProviderUpdate( _In_ PVOID Object ); diff --git a/ProcessHacker/srvlist.c b/ProcessHacker/srvlist.c index 1359c062d164..3f5192bc7d0e 100644 --- a/ProcessHacker/srvlist.c +++ b/ProcessHacker/srvlist.c @@ -383,45 +383,19 @@ static VOID PhpUpdateServiceNodeDescription( 0 ))) { - LSTATUS result; - PWSTR buffer; - ULONG bufferSize; - ULONG returnLength = 0; - - bufferSize = 0x100; - buffer = PhAllocate(bufferSize); - - if ((result = RegLoadMUIString( - keyHandle, - L"Description", - buffer, - bufferSize, - &returnLength, - 0, - NULL - )) == ERROR_MORE_DATA) - { - PhFree(buffer); - bufferSize = returnLength; - buffer = PhAllocate(bufferSize); - - result = RegLoadMUIString( - keyHandle, - L"Description", - buffer, - bufferSize, - &returnLength, - 0, - NULL - ); - } + PPH_STRING descriptionString; + PPH_STRING serviceDescriptionString; - if (result == ERROR_SUCCESS) + if (descriptionString = PhQueryRegistryString(keyHandle, L"Description")) { - PhMoveReference(&ServiceNode->Description, PhCreateStringEx(buffer, returnLength)); + if (serviceDescriptionString = PhLoadIndirectString(descriptionString->Buffer)) + PhMoveReference(&ServiceNode->Description, serviceDescriptionString); + else + PhSwapReference(&ServiceNode->Description, descriptionString); + + PhDereferenceObject(descriptionString); } - PhFree(buffer); NtClose(keyHandle); } @@ -797,6 +771,12 @@ BOOLEAN NTAPI PhpServiceTreeNewCallback( ServiceIconsLoaded = TRUE; } + if (!node->ServiceQueryStage2) + { + PhQueueServiceQueryStage2(node->ServiceItem); + node->ServiceQueryStage2 = TRUE; + } + if (node->ServiceItem->SmallIcon) getNodeIcon->Icon = node->ServiceItem->SmallIcon; else diff --git a/ProcessHacker/srvprp.c b/ProcessHacker/srvprp.c index e093b457f993..4285902595ad 100644 --- a/ProcessHacker/srvprp.c +++ b/ProcessHacker/srvprp.c @@ -106,9 +106,6 @@ VOID PhShowServiceProperties( PROPSHEETPAGE propSheetPage; HPROPSHEETPAGE pages[32]; SERVICE_PROPERTIES_CONTEXT context; - PH_STD_OBJECT_SECURITY stdObjectSecurity; - PPH_ACCESS_ENTRY accessEntries; - ULONG numberOfAccessEntries; propSheetHeader.dwFlags = PSH_NOAPPLYNOW | @@ -136,25 +133,6 @@ VOID PhShowServiceProperties( propSheetPage.lParam = (LPARAM)&context; pages[propSheetHeader.nPages++] = CreatePropertySheetPage(&propSheetPage); - // Security - - stdObjectSecurity.OpenObject = PhpOpenService; - stdObjectSecurity.ObjectType = L"Service"; - stdObjectSecurity.Context = ServiceItem; - - if (PhGetAccessEntries(L"Service", &accessEntries, &numberOfAccessEntries)) - { - pages[propSheetHeader.nPages++] = PhCreateSecurityPage( - ServiceItem->Name->Buffer, - PhStdGetObjectSecurity, - PhpSetServiceSecurity, - &stdObjectSecurity, - accessEntries, - numberOfAccessEntries - ); - PhFree(accessEntries); - } - if (PhPluginsEnabled) { PH_PLUGIN_OBJECT_PROPERTIES objectProperties; @@ -323,12 +301,11 @@ INT_PTR CALLBACK PhpServiceGeneralDlgProc( break; case WM_COMMAND: { - switch (LOWORD(wParam)) + switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDCANCEL: { // Workaround for property sheet + multiline edit: http://support.microsoft.com/kb/130765 - SendMessage(GetParent(hwndDlg), uMsg, wParam, lParam); } break; @@ -390,9 +367,34 @@ INT_PTR CALLBACK PhpServiceGeneralDlgProc( PhFreeFileDialog(fileDialog); } break; + case IDC_PERMISSIONS: + { + PH_STD_OBJECT_SECURITY stdObjectSecurity; + PPH_ACCESS_ENTRY accessEntries; + ULONG numberOfAccessEntries; + + stdObjectSecurity.OpenObject = PhpOpenService; + stdObjectSecurity.ObjectType = L"Service"; + stdObjectSecurity.Context = context->ServiceItem; + + if (PhGetAccessEntries(L"Service", &accessEntries, &numberOfAccessEntries)) + { + PhEditSecurity( + hwndDlg, + context->ServiceItem->DisplayName->Buffer, + PhStdGetObjectSecurity, + PhStdSetObjectSecurity, + &stdObjectSecurity, + accessEntries, + numberOfAccessEntries + ); + PhFree(accessEntries); + } + } + break; } - switch (HIWORD(wParam)) + switch (GET_WM_COMMAND_CMD(wParam, lParam)) { case EN_CHANGE: case CBN_SELCHANGE: diff --git a/ProcessHacker/srvprv.c b/ProcessHacker/srvprv.c index 69912965dd0e..f6f56d58a150 100644 --- a/ProcessHacker/srvprv.c +++ b/ProcessHacker/srvprv.c @@ -610,7 +610,7 @@ VOID PhpQueueServiceQueryStage1( PhQueueItemWorkQueueEx(PhGetGlobalWorkQueue(), PhpServiceQueryStage1Worker, ServiceItem, NULL, &environment); } -VOID PhpQueueServiceQueryStage2( +VOID PhQueueServiceQueryStage2( _In_ PPH_SERVICE_ITEM ServiceItem ) { @@ -639,9 +639,10 @@ VOID PhpFillServiceItemStage1( serviceItem->SmallIcon = Data->SmallIcon; serviceItem->LargeIcon = Data->LargeIcon; //memcpy(&processItem->VersionInfo, &Data->VersionInfo, sizeof(PH_IMAGE_VERSION_INFO)); - - // Note: Queue stage 2 processing after filling stage1 process data. - PhpQueueServiceQueryStage2(serviceItem); + + // Note: Queue stage 2 processing after filling stage1 process data. + // HACK: We delay-load stage processing for services from the TreeNewGetNodeIcon callback in srvlist.c. + //PhQueueServiceQueryStage2(serviceItem); } VOID PhpFillServiceItemStage2( From 3b884f8a4430609c4a1dbad40c8be400f0599d03 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 10 Feb 2018 05:11:23 +1100 Subject: [PATCH 0809/2058] Add missing type --- phlib/include/phutil.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phlib/include/phutil.h b/phlib/include/phutil.h index a135ac89f21b..8fd56b6ea7bf 100644 --- a/phlib/include/phutil.h +++ b/phlib/include/phutil.h @@ -1080,7 +1080,7 @@ NTAPI PhSearchFilePath( _In_ PWSTR FileName, _In_opt_ PWSTR Extension, - _Out_writes_(MAX_PATH) PWSTR Buffer + _Out_ PPH_STRING *FilePath ); PHLIBAPI From eeda23177a57724b62751c1702b510c4d1602bbd Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 14 Feb 2018 02:09:29 +1100 Subject: [PATCH 0810/2058] Setup: Fix terminating previous instances --- tools/CustomSetupTool/CustomSetupTool/appsup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/CustomSetupTool/CustomSetupTool/appsup.c b/tools/CustomSetupTool/CustomSetupTool/appsup.c index 0ffce62ff37f..2cd9a5c4037f 100644 --- a/tools/CustomSetupTool/CustomSetupTool/appsup.c +++ b/tools/CustomSetupTool/CustomSetupTool/appsup.c @@ -480,7 +480,7 @@ static BOOLEAN NTAPI PhpPreviousInstancesCallback( PhOpenProcess( &processHandle, - ProcessQueryAccess, + ProcessQueryAccess | PROCESS_TERMINATE, objectInfo.ClientId.UniqueProcess ); From 4e282e6e710fe56da86b780983db8f47dc11f20a Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 14 Feb 2018 04:39:41 +1100 Subject: [PATCH 0811/2058] Fix bug querying object information --- phlib/hndlinfo.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/phlib/hndlinfo.c b/phlib/hndlinfo.c index dff6e983bdcf..9b1bafe98f92 100644 --- a/phlib/hndlinfo.c +++ b/phlib/hndlinfo.c @@ -122,7 +122,10 @@ NTSTATUS PhpGetObjectBasicInformation( { NTSTATUS status; - if (KphIsConnected()) + // TODO: KphIsVerified() fixes a bug on Windows 10 but this should be removed + // since KphQueryInformationObject doesn't require verification. (dmex) + + if (KphIsConnected() && KphIsVerified()) { status = KphQueryInformationObject( ProcessHandle, From 8861cc950949b1327482bfc0a5469bd8bde80d95 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 14 Feb 2018 13:59:16 +1100 Subject: [PATCH 0812/2058] Fix showing appcontainer names on the security dialog --- ProcessHacker/tokprp.c | 4 +-- phlib/appresolver.c | 43 ++++++++++++++++++++++++++++-- phlib/include/appresolver.h | 6 ++++- phlib/secedit.c | 52 +++++++++---------------------------- 4 files changed, 60 insertions(+), 45 deletions(-) diff --git a/ProcessHacker/tokprp.c b/ProcessHacker/tokprp.c index 9477a0576b8e..9f8d04df62b7 100644 --- a/ProcessHacker/tokprp.c +++ b/ProcessHacker/tokprp.c @@ -660,7 +660,7 @@ INT_PTR CALLBACK PhpTokenPageProc( { if (appContainerInfo->TokenAppContainer) { - appContainerName = PhGetAppContainerPackageName(appContainerInfo->TokenAppContainer); + appContainerName = PhGetAppContainerName(appContainerInfo->TokenAppContainer); appContainerSid = PhSidToStringSid(appContainerInfo->TokenAppContainer); } @@ -671,7 +671,7 @@ INT_PTR CALLBACK PhpTokenPageProc( { PPH_STRING packageFamilyName; - packageFamilyName = PhConcatStrings2(appContainerName->Buffer, L" (APP_PACKAGE)"); + packageFamilyName = PhConcatStrings2(appContainerName->Buffer, L" (APP_CONTAINER)"); SetDlgItemText(hwndDlg, IDC_USER, packageFamilyName->Buffer); PhDereferenceObject(packageFamilyName); diff --git a/phlib/appresolver.c b/phlib/appresolver.c index b9c0e546b505..961234d6e389 100644 --- a/phlib/appresolver.c +++ b/phlib/appresolver.c @@ -22,7 +22,8 @@ #define COBJMACROS #define CINTERFACE -#include +#include +#include #include #include @@ -155,7 +156,7 @@ BOOLEAN PhAppResolverGetAppIdForProcess( return FALSE; } -PPH_STRING PhGetAppContainerPackageName( +PPH_STRING PhGetAppContainerName( _In_ PSID AppContainerSid ) { @@ -174,6 +175,44 @@ PPH_STRING PhGetAppContainerPackageName( return packageFamilyName; } +PPH_STRING PhGetAppContainerPackageName( + _In_ PSID Sid + ) +{ + static PH_STRINGREF appcontainerMappings = PH_STRINGREF_INIT(L"Software\\Classes\\Local Settings\\Software\\Microsoft\\Windows\\CurrentVersion\\AppContainer\\Mappings\\"); + HANDLE keyHandle; + PPH_STRING sidString; + PPH_STRING keyPath; + PPH_STRING packageName = NULL; + + sidString = PhSidToStringSid(Sid); + + if (PhEqualString2(sidString, L"S-1-15-3-4096", FALSE)) // HACK + { + PhDereferenceObject(sidString); + return PhCreateString(L"InternetExplorer"); + } + + keyPath = PhConcatStringRef2(&appcontainerMappings, &sidString->sr); + + if (NT_SUCCESS(PhOpenKey( + &keyHandle, + KEY_READ, + PH_KEY_CURRENT_USER, + &keyPath->sr, + 0 + ))) + { + PhMoveReference(&packageName, PhQueryRegistryString(keyHandle, L"Moniker")); + NtClose(keyHandle); + } + + PhDereferenceObject(keyPath); + PhDereferenceObject(sidString); + + return packageName; +} + BOOLEAN PhGetAppWindowingModel( _In_ HANDLE ProcessTokenHandle, _Out_ AppPolicyWindowingModel *ProcessWindowingModelPolicy diff --git a/phlib/include/appresolver.h b/phlib/include/appresolver.h index dbea2044333a..45aeefbfa618 100644 --- a/phlib/include/appresolver.h +++ b/phlib/include/appresolver.h @@ -32,10 +32,14 @@ BOOLEAN PhAppResolverGetAppIdForProcess( _Out_ PPH_STRING *ApplicationUserModelId ); -PPH_STRING PhGetAppContainerPackageName( +PPH_STRING PhGetAppContainerName( _In_ PSID AppContainerSid ); +PPH_STRING PhGetAppContainerPackageName( + _In_ PSID Sid + ); + PPH_LIST PhGetPackageAssetsFromResourceFile( _In_ PWSTR FilePath ); diff --git a/phlib/secedit.c b/phlib/secedit.c index 83e5611e9502..be964c0fe2fa 100644 --- a/phlib/secedit.c +++ b/phlib/secedit.c @@ -3,7 +3,7 @@ * object security editor * * Copyright (C) 2010-2016 wj32 - * Copyright (C) 2017 dmex + * Copyright (C) 2017-2018 dmex * * This file is part of Process Hacker. * @@ -22,6 +22,7 @@ */ #include +#include #include #include @@ -560,46 +561,17 @@ HRESULT STDMETHODCALLTYPE PhSecurityDataObject_GetData( sidInfo.pwzCommonName = PhGetString(sidString); PhAddItemList(this->NameCache, sidString); } - else if (sidString = PhSidToStringSid(sidInfo.pSid)) + else if (sidString = PhGetAppContainerPackageName(sidInfo.pSid)) { - static PH_STRINGREF appcontainerMappings = PH_STRINGREF_INIT(L"Software\\Classes\\Local Settings\\Software\\Microsoft\\Windows\\CurrentVersion\\AppContainer\\Mappings\\"); - HANDLE keyHandle; - PPH_STRING keyPath; - PPH_STRING packageName = NULL; - - if (PhEqualString2(sidString, L"S-1-15-3-4096", FALSE)) - { - // Special case for Edge and Internet Explorer objects. - packageName = PhCreateString(L"InternetExplorer (APP_PACKAGE)"); - sidInfo.pwzCommonName = PhGetString(packageName);; - PhAddItemList(this->NameCache, packageName); - sidInfoList->aSidInfo[i] = sidInfo; - continue; - } - - keyPath = PhConcatStringRef2(&appcontainerMappings, &sidString->sr); - - if (NT_SUCCESS(PhOpenKey( - &keyHandle, - KEY_READ, - PH_KEY_CURRENT_USER, - &keyPath->sr, - 0 - ))) - { - packageName = PhQueryRegistryString(keyHandle, L"Moniker"); - NtClose(keyHandle); - } - - if (packageName) - { - PhMoveReference(&packageName, PhFormatString(L"%s (APP_PACKAGE)", PhGetString(packageName))); - sidInfo.pwzCommonName = PhGetString(packageName); - PhAddItemList(this->NameCache, packageName); - } - - PhDereferenceObject(keyPath); - PhDereferenceObject(sidString); + PhMoveReference(&sidString, PhFormatString(L"%s (APP_PACKAGE)", PhGetString(sidString))); + sidInfo.pwzCommonName = PhGetString(sidString); + PhAddItemList(this->NameCache, sidString); + } + else if (sidString = PhGetAppContainerName(sidInfo.pSid)) + { + PhMoveReference(&sidString, PhFormatString(L"%s (APP_CONTAINER)", PhGetString(sidString))); + sidInfo.pwzCommonName = PhGetString(sidString); + PhAddItemList(this->NameCache, sidString); } sidInfoList->aSidInfo[i] = sidInfo; From 824e249c5f5cf9b1017416e2cf2ab07318f196c0 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 17 Feb 2018 01:39:20 +1100 Subject: [PATCH 0813/2058] BuildTools: Fix crash when git installed into custom paths --- tools/CustomBuildTool/Source Files/Build.cs | 25 ++++++++++++------ tools/CustomBuildTool/Source Files/Utils.cs | 15 +++++++++++ .../bin/Release/CustomBuildTool.exe | Bin 163840 -> 163840 bytes .../bin/Release/CustomBuildTool.pdb | Bin 75264 -> 77312 bytes 4 files changed, 32 insertions(+), 8 deletions(-) diff --git a/tools/CustomBuildTool/Source Files/Build.cs b/tools/CustomBuildTool/Source Files/Build.cs index c30c120f55fd..9a2ebc5cccc1 100644 --- a/tools/CustomBuildTool/Source Files/Build.cs +++ b/tools/CustomBuildTool/Source Files/Build.cs @@ -160,8 +160,8 @@ public static bool InitializeBuildEnvironment(bool CheckDependencies) BuildOutputFolder = "build\\output"; MSBuildExePath = VisualStudio.GetMsbuildFilePath(); CustomSignToolPath = "tools\\CustomSignTool\\bin\\Release32\\CustomSignTool.exe"; - GitExePath = Environment.ExpandEnvironmentVariables("%ProgramFiles%\\Git\\cmd\\git.exe"); - CertUtilExePath = Environment.ExpandEnvironmentVariables("%SystemRoot%\\system32\\Certutil.exe"); + GitExePath = VisualStudio.GetFilePathFromPath("git.exe"); + CertUtilExePath = VisualStudio.GetFilePathFromPath("certutil.exe"); MakeAppxExePath = Environment.ExpandEnvironmentVariables("%ProgramFiles(x86)%\\Windows Kits\\10\\bin\\x64\\MakeAppx.exe"); BuildNightly = !string.Equals(Environment.ExpandEnvironmentVariables("%APPVEYOR_BUILD_API%"), "%APPVEYOR_BUILD_API%", StringComparison.OrdinalIgnoreCase); @@ -207,7 +207,7 @@ public static bool InitializeBuildEnvironment(bool CheckDependencies) { if (CheckDependencies) { - Program.PrintColorMessage("[Warning] Git not installed...", ConsoleColor.Yellow); + Program.PrintColorMessage("[Warning] Git not installed.", ConsoleColor.Yellow); } } @@ -272,13 +272,22 @@ public static void ShowBuildEnvironment(string Platform, bool ShowBuildInfo, boo if (ShowBuildInfo && !GitExportBuild) { - Program.PrintColorMessage("Branch: ", ConsoleColor.DarkGray, false); - Program.PrintColorMessage(BuildBranch, ConsoleColor.Green, true); + if (!string.IsNullOrEmpty(BuildBranch)) + { + Program.PrintColorMessage("Branch: ", ConsoleColor.DarkGray, false); + Program.PrintColorMessage(BuildBranch, ConsoleColor.Green, true); + } + Program.PrintColorMessage("Version: ", ConsoleColor.DarkGray, false); Program.PrintColorMessage(BuildVersion, ConsoleColor.Green, false); - Program.PrintColorMessage(" (", ConsoleColor.DarkGray, false); - Program.PrintColorMessage(BuildCommit.Substring(0, 8), ConsoleColor.DarkYellow, false); - Program.PrintColorMessage(")", ConsoleColor.DarkGray, false); + + if (!string.IsNullOrEmpty(BuildCommit)) + { + Program.PrintColorMessage(" (", ConsoleColor.DarkGray, false); + Program.PrintColorMessage(BuildCommit.Substring(0, 8), ConsoleColor.DarkYellow, false); + Program.PrintColorMessage(")", ConsoleColor.DarkGray, false); + } + Program.PrintColorMessage(Environment.NewLine, ConsoleColor.DarkGray, true); if (!BuildNightly && ShowLogInfo && File.Exists(GitExePath)) diff --git a/tools/CustomBuildTool/Source Files/Utils.cs b/tools/CustomBuildTool/Source Files/Utils.cs index 39cfc47bb98f..ba1b493d5026 100644 --- a/tools/CustomBuildTool/Source Files/Utils.cs +++ b/tools/CustomBuildTool/Source Files/Utils.cs @@ -205,6 +205,21 @@ public static string HashFile(string FileName) public static class VisualStudio { + public static string GetFilePathFromPath(string FileName) + { + string where = Environment.ExpandEnvironmentVariables("%windir%\\System32\\where.exe"); + + if (File.Exists(where)) + { + string whereResult = Win32.ShellExecute(where, FileName); + + if (!string.IsNullOrEmpty(whereResult)) + return whereResult; + } + + return null; + } + public static string GetMsbuildFilePath() { string vswhere = Environment.ExpandEnvironmentVariables("%ProgramFiles(x86)%\\Microsoft Visual Studio\\Installer\\vswhere.exe"); diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe b/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe index fd6f7537e90a034be99c58d475746b45ed3e9764..e4971dd5c781e4e11dc3445a30d56af19cc44f24 100644 GIT binary patch delta 16585 zcma)k33wD$*7m9DPW6^_y0dhrlkTKDos}f)I|2zH5EhX|HbFqbCP?rCj)J6vAd7;6 z1&GQhC?Y5>h>oJj58}p%jyU26>L84w;*7haB8vZePgSQoasKD~^F005`<`>|xwr1U zb?a7@*x2Z7Y;>+$W%2xL#roSq%GK+4jj8f@6&gnP3oCSDwIW&bzk@2J!g3;Ap`af5 zzEU5jlqxgzrAjQ)4`t=wK>Sonp@CC~8g~#$>qH{$bv>e9K4}41V+xT~8p26DOYCblT)%|GZ4|}hFi=AYe<(ZE0lRLj;4*hL(w^gw@P}`;I(x74rA9KPqO>x zlF3@iD&elm6AO_o-)HnCI|`iU*^8A)F8%Wqx4S`}gHf=xxL5xnpVi8hYW<8>q>R@!TeL=KG*7Gol+8ewiyczF)FeNZQnkgsC19dgT%HOz#Z@-_ zj3-xLZtH8qteGeF+w`|=dD<_Mchy7-G!odH~(%-ra z%VKs1d~!gmT!MKSc!?-WGBY>KV__B>q>o#FLdq;>T#f}3TbtxJQg(Hj-im9)D#^{d zn3vH6S=sI+J9DG5(=dy0YCQW)FtM{qek0{2X>sp5F!5nrHapQP(%QN)CsTNKh#~qv z9c|O5ON%{jDRAb;mct@;0*q68OG-(kMt~tdl(ITAE_Z{8tSnQW3T8Uw_-d|^?U%zS4#Yj; z-%{ph$IJBt6W7P(senrsi&!%Ck1U$L-4*J{zRs8mPOYqqoEjvH|fnE2chSX29^){(_s+o3DYR6cS54H1xrTSZ`{z?AoJ8|g=Ii-yCsHdn#2(Ln% zwZV>yOWY)j$>j+x;VaZ9O8qoX^RHZGWIj~BcpK=X|0liY;IV2vmG61+tdL{+YtD9sU1bUK&xm(xo7 z+4Io3a{$ITKO&_kXv&Iw!T!tQ2EqPyafyMqig$u~8+Z5KsUZ}ScNHNSx4;~)j!hoP z5+0Wr)#Mqa?{tS_H$ykA`My?0cU5}C{^oY0H(>v+xt&BwKAJBF+*Wp-T;_U7eHB16 z^vzQ51lU=h%1sk*K{?8b(eMI&KzjS>-$56+;wx|40-EP93m{jO>T5-O9}>%9``JdGag& z)~voUxH}pRwM61|OvMQ|tz}(fJ>f|7$#pVJUQm@z!JO-UBgx8~t?a)9vGqM=r?8_* zp0bpj!j)KDn8?SROHN5xV}b>nIiM+n;b@X(!avKRa=ou~3CaCs<+Ad}lFX8u<`+RZ ztgM%eIw>WGO358_wfK)LDsS@5Mm%BVrpf(?(UA$q)p8cfHV9dbQG-m*)v#>p=AgbY zqvNzT(WI{CT?$u;&DK=uiEoIS=Hj1W{bS1#R@pLRv-3ZQG@3VDZ=D&GOXQHuK+2D} zN!#_9$EP=DhAP(pDK^a9}12d|rOP(5S2Hb|-C^kM`p%f>TGz!(g^vAX(tlT!a zvlHv}-dWk|Li+#CDfxgK%C6-Z+c)k@HGwH6lcFo7LgjU=jcfR$@ znaYi6{R&BAm>E{ly%ow{Dm!+SG>Tr(954POJ>2EDa<~`aW&LI38qSm zKMp#$xPi+*$!2cWZqTv;XsdZ=u2fpJc#cZk=F-GO*-*YUPSmS&qRL9WE~i30T%oVe z$yAS5=sR+X)SoK!qdBd#pAhP`@l#BCpi9@LS&qk(7E=NbD~6?MT0T&0&h*!c^oD?c zQh8;(tGTD-Q%F;qgpY^8@R3Xl1umb3cU@vWyampKiNAvxv&?jzlrDZi>#e7U zf=Y^B8On`JX-)GgQp9{5faZ(oMJA^~@#@sVXoP*VvNPlp3YY*3e#N8vg*n`sd-(6`P znz?v~AQtO46+~h&xbo`9pgmPFuT88@NURQGV?s`W+?J3dARkT0zK*=L!|}qX*vBV= zk@wo<^nL~*SS=9zB3Rj2)KfnWz%M*-#(FRuRo3g(;Yi^J9BM2+vgr3lQSK8N9_Xka zisnS7b>vqlra4F4&Dxkm9H#FN2Rg_h%CvjUL6R2=j|rQa4^yVy==E8;J(3?wjEFb6 zZ_l8Tq`qzD<1tC}doy2)F=^&&IVf^FsA5zejwFvt_eMNIdef2z<~qovfw>woX<$Y| zCJjtK?;l4dEqP?pM7vHcM@H$b4=gNEpJ=1cEBxcY3`2bU4j_AcVW_<5UFa-NvG9MJdkDJ_t(N=Uo<&0kFGZ5(>)@V*#asu^G+CU&+ckNy8UST1 zR$^aQ{diIDf#uzrH3fQEl>Yi(i$j-9=n-G4_=M!JHMd%x!WKZ@=59&XZ6vyPlBbF6$`6cq0BWCh3 zAeQqnSKP{y5jIGw=xmTQF~}fpG1(yLVu3+CVwFL> z;y#09h{p|*DGnGUOT5D*R*)?|HB3J7gF*bl-kWR95kZ3lL|cR8ie3iE6Jre$6xSOh zBsNLXm?OKSG~OjU+36Si`IsZ#GD`J$SS=#udU zaf)jU;u1F*Bvq_4NSfGT5Vv^RAnD>&gLuUI2Jwo28ze(qlq6PMkSXjne7ad8*C5%V zy+M3pph5g%yg_orJc9(p8iQb14U#8z8zd+W7$hX#HAuer${+>e7lVX_yN|52T|q&LLwtZ#2IU<*j7+F5%ihg{|6QlVU6f^l45{vklFK*`}2I7IfJZlS_;%UR=60aL1 zRlIMIH1Ul=+``(A`!-$V7{nu58^kO67$ifCHAtqIV~{M-V32Har$KyTr$PMUd5}T4 zByz-ChAANaX^>p;vq3PMF6CN-B5aV5=qSmO0`9Uw;7cM*Z`|9l!lfwB>eZEbLyz^x z>LReZR7P#yl*O|V;S{*s0{AQ!d$`U6!%l$Z3ct4fs@ zb${zN$^m^q>n_Uw(POO#Du?ygTTfE|(_b%d)3f}%Y``5zWEa1KdYy}Nk%AvRczHB^ z=lkn-w7HmO8-Qp$UpgyGg-ySwZG{rhUu_%qb!xI->Mz4)QmeuvVPE~%w$;iQy=S{} z|CFYH5?@om5k+6pE?mB_$yb-~$=69ff0+fj%CLRaN(7=GZ68r$`kUEk<;r=<*x_gQO^qOa?atwi)49m4uu?K9M*b1K!N9jo!Ft*+zS$^gAn zr&pB4`h`xHj857N*J)nsJ;}SSk!(oXclBXI($1?L8;XjY|DB^lQxoFhh)!aF<8Yd`u?t;DYxz2-fgs^Y}|XH`?U&A zY1SoeVwr7K!b?dil5fj?M=b9n@O1%W=&a1pRK8oszY(amR#~kmudS7~piHqW)1|gW zna-NnFKzO9&n#D|X0@`3S@Nq+Vy~4dEx5MXB-55HM2S>;Wh;CAjbJU~Gh3R|PK8bd z@T&hIy|iaLd|VvYv%7M$zM*Hi@~VEIXJ>7ZOmbZRrRP0L>E4aKW~=TpG`L|FCTCSx zd^AXR*L1AdD}%}hW0P_X?Db#btXmOfwzUwR@(FKfy(+I6xC-@aYdYn;fcW`eBdWOZ zT6sa@8mMU1dj9kJ^EHDqP!i#CMOZ8sZ-Hys*QZwmkH20Ef90+J5hb0P=!**T>hT5K zSvgq4WBkHC5sb%OeFkQ}g8Yr>2y3hUmiiI0aTE3L`n2x(GzKWzKomx&Z^17*a)FpN zcLtU(qWy!2HV=mFijg#G6OjkD=zuF~`{7sz9n>fG?GSkt3acNb;CBJP68s*)4_|xv z<9&s`r*BQ{L`b7&y%Il9zbBMVvvJ4KsNAz6pwY*SFEiffm6mH5mobiEd$wmE$}UKk zcpF=U=ZZ{?W(K|rYqZlNaZmc}VvUY_CDsoy|2-JaE<=WxHgyz zJ`geY(q4Qxxu0V)sF%_mnL8`8t~S7!M&r`u*`G_3XK*v0$M4*_zFuiL!S-rC%bn_( z0*yQ&S$J{rFrP-Vd=j&~(()#sK$Sn&;-j7!7jxY7OXQwVE`98LA~To%kt=b1=!r}> zEzi9NnZL?e;m?oJn?YNyMwg29p$D4sq!ob zI%UV!J1^!G(ud)TIX=3wSa$Lj-^Cn_R^-Wwbzm;t?DVU-^bliJVJ}R^TY1PHKoj%n z^Wb1i@8$;mRwQTsm3gvplh9kZe8`Qvy}XJPTB>AG z%yGasoRxxW@q3q4xs(r!hko=+6`}%CJRW)>B2^Tt?>1bt(ZGS24+ku)Qu^}`B&ouH zp~~6Us2Hl!D41@jDpp^kdYPpStLuV>>cZ-OOkX!vSD0C9Sfx4-_+ql)2$o^DQE)uY z$wMQ!-BJ7}3JUfSi^B(eXVB^??DOQwv#4N|McGIy)im}UBdOZZwXBX88LFPu+qs6C z&pq>!?6nv|uV7)F4=slhbTG-ckX|M)or$iud+~nVwh@Qx9UJwp2bRWCgAH(fP$==r z9ErCuzKVs|OHSsBOY#lbn^CSHOY)a8BtFcRYuIAXY@l}ZV*b7Mc64t<;##0abJ7~H zOdT({ANwvBFlJ#C+T zbmRSn5+7lFKU4B2+!EXS_Srkr9`!}=O{$E)g>eBeLXT@3?GXyvHtN6C_P~p^ZiDWK z9Ykbz%VA(2#&L`djO!R@Gfq)u%pk@hwwz}H|?KNPnPvT0e z#5);xMqZ0S3`&0ueff_64d80`+vuAjj6i2{s>kg<+Ds>bOX#1#CzXE#-%x%9eyXH8 zGWX4q2*)!$*Fqc3d9D=+h?Z8Xe?N$cl}KR3oEjttvH|DmFVh%%Re5 z+-#*&Ej(*Yp^muSO0}$Dv?GOfn<`u|9%{L~i^AuH!tG7&q@a37MmuaY7P|+j7UW5F z)KrsMb;VXe`uZcMjn>6gEI1x=L8akb52u}$R~c$lhE(C!hMLCeps9Y%mA)c;FO*5` zsKQR~;zNg2->`3IJ41cKDz&|#9H}z$U;9T$5^Wq*597J<|7j!JUqDx!Gb3Fax3X$Yv*g}75Usdv&IbtIG{KUw`f@??^4VD>Xf>gUj-4t&z% zzgJThbnIU=Iwx6W>4Pu3v>+#EgOZ52A?LNE($%h``V*JsDaZ9U zE(=t2%&sGBW6Wx|Ay-0mO#4Dfs4w*NVHGIVW0+AY*sN4S$x;dRg&rFg>h^&HkF{nU z_v2g=YEI$lBsCkYN%;0e&g#d9m0CW}|3d$LSZTUE(}Xum?{xX4F?ps5+kFLJCuPgb z_`wmTQJ2Yz*HaJQct?a*vD!o_Ip-aPGzuGI>01~6-4UgetTs`h%jLv{EBEd2{VO_` z%IGFjJzU^(mXmdq^lhTuvAo}?lB`!4@++v;w8d0!L$##^qYa-WVMC${ zr0u5K7yOO*dZ0$y6kh2naq{)RYPhq)iFe2NlfKE$4$e!O)W)J%cV{o^Jyu$btDqMR zVYP`?XI!cDqTQxinbFJHo2=tFk{0>;Ijd<1t4(w=I@no5M@@AMsvix(i(7ey@41H4 z0D96?;q2k~?{z;h)y-K?#i*9H;L%Zb)B(o`XDwYnL8=w@Nv;h_Ej5^`U%FH)Om%Z= z9m?HqsvEPU+GMJ}801>I&s0TeQtdF+`vIvQH`QU3i`CL!Ou3QM95B_Dm`Szts;S!I zim9cyO!Zgy7&P>Rp|Dy^fZ9LNXtu0=5WQ@wVL2YCH%;|QVI2*o#o9ZoJ9Sx>LKpUv<Y>rKe0a4viU0FPQ3cG-ezfzA9#P;?HQ!I67)N&pGR8JiTkG z|2RER|1i~o%sRS~&YJ3IrU&XPQ&nLIC(w_k>W?9uK);)65_}WMHp!^(diW-iXA;T! zSJ;nXdR;|1rt>qa2P$H!-{6}><)+F;!AaEKR1d;8nYx?md6b)+d=tYy*tn%FleaXe zejKUW^MhAAr_d6p7?Ezj&OH-yx#?Wuo(r|cR2QO8VSk%+XN20$zGYNL7nQ5YG8yM! zt{zjHMNXx3_AR4rw9q+~icPhW7NLi$q>5o%{k+oXoJL(u=W%6?b2?R<>KkRVb4IhI zGijjd8;wV)nY7tdTa-tgv&cJz@VAU2%0td;sGOCtu+46kWj1wUUu+qL=~<_I9ih;p z`4V6D%YRSMKbOctvw#ZS8g7Xf12QJrKDR)|WJjg_O}vY-&_$QDd{Cf-75ctV4XgAs z&_au>hDAQ4Ey~H3haYn!j&P|cyeUUT;eY8rjqcRNs9*os#F;Acr0`<&Ev6} zjmXBnQK4th2$c@&Q^#~tcIbDH8PL8vpTN!RJ&`KCM}ZbHEPwki7Cm+B?&7w1Zd0gh zUQ3iI6l{YT^?!^FVVk4iAwy2D0MLmSRTD!VJY-1h##qBx%Q&2I9OD#VHlCJbz|_I-qzyTW$dAcn;cS+Pf4l z1@D=DC+v^=jZ!1;gSf4DE*IDid?<4_DtkKZDLm~wk~SaJ|0%Ga4$;8yE3{9&6RXD| zdMxw`9a6Su{0&vkDw55*&ml8xa{L6#LVfV~Xh8PL5p{KTrE-M(;0WEH)>c77^_AnJ zytzC^^CQ!hbLvcMC;C=Z)H%v|oUl-ikoIvJ$-#>w?vtQw}_yYWBSX%xbzNnl-8`9NtL^%OqmsmKg)>wvx zO4M)ZwrGV~Yq=b^HhIEr;U1dN8TL^{8KgMfCUZaOq;H_#$j=Y4i9}No~REKcM#DnM3o!+bs)_dY|Pcq<+h?oV{zzn09%;SvJske<$k} z(^610!Mfe#Qwwji-bAA`R8X!=)O$|wV~09j-OX*>&F3`5vL9XjG#x2guFkUD?S94j zGz!0Am1pozmv*=G63H7aGP#anB6uHRbv6*{zU)r*C56tB9k z$P0dNrVltHT&l^KD(zcKx55tEc}sm}Uo8Sltrk$vyN7Fvbw(^aMsrvX6;%P>vs7u@ z)JayK;;=3X&C$vcDzrmt@7x%?*TB*amW^6Bphgkvh0H%|<<>hhAJSen$J^?DUmI?D zBYIxDTe&XHZM$1(1n#1+)eF28i_4A5`J#|*3Nl22_h!Z_Y^&AH8C`5g%@mLMK2p0` zpD7$@dzY?P-m<()F69nooBBe*WLv;;FjWpvFe+D+p&4H&bI6l1$5vxK?_P*JuLSGx z+GxCgh0TsPS@#2H0W<{Rk#7#y2vyG_OVc@}&N?E?Op_5!!kZPTf?c>aq0~mvzcSIaLiWaw5=3(@9nnMc;bHF*&0vD z9|QA9b+yL(Ko_uru>&5mT2l`y1NLRhV7df+q_oGdCzI}}G!i(QmH_9|t**Xw8&W?= z_tFX1gYcel9i|7#m3kPwYwE|qtAUTgYf+@dqDUSEUy~YT-WU8YsePGG1wWlSmH9Go zXWBC64=S;#)G_Tr7Q2+g6mlPi`>M3VY&il;JNL)1tV;WsE$3kA=eDR*>8Uh}Dywv; zhiR<495~0_SKW(7*Mcu|&jN0CFH_}dtOnoh-UWQgeFXS{`yB8)x5IKcM)vfm#(0SF45Q-U0*p0`Qy7;rZeu*e zc!p7Nay;Wfx8$c8DP8g~V>M%JG9MZlw=y1NJk3ZRF2FdMv5|2r<3YyLjO67=#%jjN zjE#(284og^W~2;`kMW_JaWZ2g<5tFljHekXlM66bGfrk~WZcSlknuDlWpO-XHREK) zM#im-2eV=_=rjw;<^qh>jFTA~8MiVXWIWACJ{cdOmG&sDwin}AieESUdf?ZS*4TT~ z?f5Th*4XWMWBr+}53R&f_ZMtv-lNay8@yak!@q4kKea>bN$q(p#pbtlu#L7&x8-2l z8lW@^;#&dHRM(46{KMgNiF48p0T*UV{3=Ic7q)yEko>hQi4QZ*<(NKJY59ly6`&D+ zx=>pFoWgdW#J92!#c(L%Vy|ULQ?_4X2D|Ioo|efLw!h64r?Yn=dw=Cpl`a|cHb)NP z3KlW`iyIMOet>yl@UMtm?|vKjd-OeLOvUF53-jZuuP{p^@F5p{%IE`(1{7~otph^$oPNCqY z*8}_^>IuFBsM5pK8+<2F#YVjb{1KpvTR>m%-9VKdqf5ab2deZ0US%n`VGaP_ix)yF zZkvN)c?PIr77nF7zER35Wwd&g{?PQ&lw;Z@wxRm5=^+K*ai(VvmEWGfF?(_sT4buFcF>+UvzL!%F+T{b!!dO6@;u&a}&?EST9})L*+d zy5t8>M*0kFNfzM6r|9?8E8AMNg`d-U%lk)l#fB)$QJEJ3Ys-cfq+VdnNw=0{nha#VG}GUO(Xf9q_}qL?cG_8`kjpD+64(ZSD5+57ajcE!`xD^K6}8v%aTp4MuP+Rv+h`rW(B+&?_){z3U= PwOZHiS?}fQkIMfA92oC+ delta 16536 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 diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb b/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb index e9427627252d9655f9e3aaba42f6942b4d5b35f8..3ba53e1eed6b41a9a0f78f957953f165bc2b8988 100644 GIT binary patch delta 14990 zcmZ{r2Y6J)`nb<5*(HGlSpuX{5<& z>xTF&%i87O!0(mf7}r6y%~8prP8Tc3CAG~J5D;GR*Xg|!p-srCi({+!-fEYujQ2VM0;E>mIvVZkPF96-pl&?J zYjwjM9|g#fv}a^ULb&=tUQCGRxG5pbG0|ze>(&cbKFO&UAK`Oamabw|tBkvc%d%D= z5!h3ts9wHWF8Assb4*GMQ|qNwqDLK*f<%uaq^!J`nC=J&l*@?|1LFeyX^1)(DpMbJ zN0c~pqSFXGgy<^A$)<Qo~haIhGn9(Kz_; zJkC|Htojf6+h+yw^3`scn-(9j`++#C3BPFKoVC-c-yqykCPdmds1sQx&_Jt|xZ8s@8patnV$iAfK0JoOOKd)ckABt1MZ zpX_uOO5TOaax}f7%9k_gVQQA#N>5YgCCQWTaJglJXOucE)iZ{x8!|T|nd9z^gKD45 z%1l#-WOrsWl_B>s^8-6qHmP;`HA>!SY9osq$8+4DxzfAU)2g3**y>Eg7~1K-h~lrh znfldfxvzCR_!h;T9MRcf&Y%9LB?+ zVO@9~)`NlMoCvGIG#Fwvw%k@f@wG{g$*`(eJ(2Esv~)$ZuM08+=`26BiR%y$;IG3Z z%C3K9k-l2t=OIPLm6ZwOVI$ZKX2Hi`W7rQif%&khbZVTXtG+t8n87? zf^A@9*cLX0?VwKcQP>4O2A_bB!=5l#PPI*=qulMHyxsAI;_CtHKvvYL4PjsGw(uEj zeeOVW?sISm_7MEKe50`ELHcg$QaBNNIn0MEU;%s=PKG;R5&QtsONDN$k!)<&inZ<< zC3y*tF3B8N6V8S8;5?WP>CeI(xB%wDh45)8a2R|A7Qk1b7cPRc;bQn2d>y_C-+-Io zQcAoFu7n5a2x|?>_c+$W^Y9%a{t7q4i*PHn7$ncfFDwVO&AMdmgH_?@P!DMx9%I7wFgS$2zVW9TI|ClZ-_7`Y8~-!#2!7oSIvrhk zZI87quk{7WLKCpa1gwC^@Nb4+!;j!M@G$%qo`l~)UD*@xHv9nwQMr>a9R3KIE!Iyk z9iE1aL+cFe3jYJ2Rf(4Me<=NNFs%w1G}c)-3H}$-`PKzE75*w?A6up3B%(u9=WF=5 zvRS{uV0axy!5dHyftyfYq5gzf@D|hq{tnbb;V$e7|AO72<&fze(pl4XcZh1|a#)4s z@iDLM@l_7i#tw$bumVhh4?*4ZZrB=Dg6&}y_!z7zF&)!_4$`}Neae($pM~Z`5~jPi z24rQnYQjhu4XeQzsJlBB>O5*gJ-gze2iBFX9h1HOE2Ywd!~W5VRz+4H{d<_0x=E6t z&gl`Tb4Z3dhZGnG)1c0wAxn8{VJRYS3@uUw_qV$2d6;2)=z~W!|Cu- zI0J@QsjS@9x&G9*+|nm^t@j|aRrl*Ps-S=2$iu|ezuBCj+k6ge0O!Jv@MWkc=X|Kw z$c0d^NUy-5@Krb*`rvrD7`_N!hcn<3_%dAPu(}uO#dA51xZ`?XcvN&P~{^sV-4@-{IA{ zeGm2E{Q>G+bbV{WpRo1xI1Ssu|B#zr?apHBT>cCD!}D+gyZ{T}C8(GD%Tmy#8QZ?y zU7|97!>9AQ3H1v52TXu}LcONkhE3re*c{%6E#Y6{?wY8#giX6fddrmYCsG#b5fBJ# z!ys56mV=F8Fw_MOfqJ%8fW6>Du(x3!s4Myu48{K(tPID%DzFe%g)hNy$Yk_d5h%K^ zBH;!Y1veV%i=x=_!`dXO!L^)P%4 zCc)l%Ie!GD4~}H`6ik7mU@9C38^RZ0x)gO=Rmjk4iJb#mK|Q3unW`+RyX(t>|VyIQMd%92M#@J zdct?%lkh#*NA`AqoK3p>iKxsxe7Z3Gp&lIrpdK9qp)Sl|s7J?hP>+tGP>+sb(*KD> zw(tv{i1LoYr_&e*^`ICJGhjaK2q!_k_V5-V^9d=1WmKIzkApw~sG=sxcqvcTd(F&-WWfe?^YoKn9x1hdOu7^*;jqo}6Hq=#r2kNSC zf%DYwC6!JD?sQyQOE(M;)i#^7_z7_s7HzVGR970Q(i|h8*h|<^3FQ zFrNK(sAV015!nBRx~vCb9e4=pE;1Q^ourFXXJPLE*m#`E33g*GD%UDbE$nAIR z!SFg{w`<*m(-d>@50vFNZo#$iHq;lIJCMDhbr)`f_u;>xBY@Q!aywASHp_BBc0X1i z3~;b`!16E{M!*U%4OWC)#_b7_ZJ6VTWi}DOW!kC)Tfxe(7pwxgys|?H>AhUv5%!Mq zMg~|j9;a5d;Ab$AIC{VLFw}!C8R|=io^{8Ktw%%({{Mpw;RTouFG3Hz3^QRFD$xj* zhx+`7piWO;=CdLDMXwzYiK97=IM^Dd!ZuJ}|Jy>nk!%mSQL!F{`m(PR=xNv&cEZ-% z0G-hwW9vcQ1;1W+y1{v{CtL%2!L=&OvU;Pe$I%CV1fPPRK%LM5s1s&aZ1saz;Q;s> z94M;KM(&e0^@;L6k1vQ?4}}lGVK4~}hh$-mfO_2@1@-zq8V-hI;50ZE>I?dKdf_fC z#MV=L3Z#{+sZcl43>XV%!36jcY@@7h)@+n+IOf1-;XF7Vz6__r`EVIr0Cz$mqpA#r zCD?3Atz|G3E{6@^Dkw*vN|!I6YRdlD{dAOfeSr0nkFsqiXbpTH>gDr8co6P_XW?$B z%l;4|UNGKs~Si4fTz{LFj{rAk)Qb9Y*0k$NBUyZFh=Bof}S`+GUlJG*P!`al?@fW}!@v{T6&Jd3sf^{Coma(jB__?lG*I^pG z0b9eHuxA%aWluAU5aB`K0U0`hjo`!L72&@BV!g#nE)`kCq_26-s z2+zYuI6vOSq=k8~DgJ>_7i_SxN5E|S6JQQ(sPDY&rZf@e!4?F}hb`ek*cz^dZQy#? zwzyATyz<7gY15aI7ApVqx$!l(|WN9q&|g@!fsICn{|hIuooN%?Xnqr1bh;| zzTEeLh0rb<)bZ!RzD{fAe)yb|8wtm z{8gwI3Lf0r`)OTz-74Cy4HrWXd;_+DOQ7B>=y2US%V7_=0``P&!l7^#90lKkdc(LD zx~&0huu`~%X)bT{%jBur@qVFY77mJbe#XV-g2WAq3rl^vKC$(aUWS=|$YXEGE)?et z%2MirEFB!BqGadbfzEB5(pKW0tEt*btLL6~7Gpmy+n-C0d7M2B=h=yT4WlulVRz$? zl&#Z4CH(ouYMXR>KGw;W%QZ;~o^OG@7n{qxYl@t=?W7^GPPRU-S<-Dt8@JBWVY%$< zye?*2$r~Ca`-fBu^5?0nB#D_3x^QTNph5W9eb#MZW}#tzL!p;qTH!?Ygu(ly=QE18r~XKty1qf+sj4vAKojrmle7& z#)>PAd(-xEA?7JULaFzj_EuuE`42CRGkH{GrHub^(@@%-iTlA4(`ee==zn6*ma24zXH|joQXJS7E=?Zrez=h4e-+BV> z!)9g`eh!~5K0M|Lr8Y_2xLA(u#(B6MEgI)lS454EkGPWh_W;q?{}o6hPP-yGuIPI75qt%t-o-cf^f3gD#T5%GE0rj5ljAvdn7mf?mm8B~IYxN1)DY?B^{CM@m*Yg)=Y3gi zk#6j7w#bCSEcL!@=Qidexx{gw#1*})?#T9{SdJ%(vK)>EQguorM}-E`dCGLsJ~5>? zsa~5JCAm{qkixa8AF4aWo2HFc!MX;^{%)FZX*s>JV_AlDTv1CVO>e9cWasp!)w1G< z8ReBaC2=!jIkua**%4AtZqKX{5yHr!{q2P<5QVX=diI<@M;7|W8c_NhO;wsV@E6Bw(|=6s!9)7z=8YNDderctnmS_1BF_41 zpW9qIy%yDM{Gk4$`kPQ)c)fGeGo+hIO|LAvl5}zDiesPCx&P>~L&nJR@l9eHnUZC* zY0^JE14@2lDA{0%d#z@5eHXwpQ#*99Nj;L(b<8-)do8R=T{2pP=$Sal#Hb}_e4(=9 zweScX`Zc2O$%-E+okNx`ijs@31%~Jt`t3^uG0sUI-fF(Kk>LTD{EqlxADP20XG59n zt5dxtC;ZIXse_#j{Y_ZM6swNx^~KAek-<`JQJ~!QRaSMxy{IO~ltr=CXL9Cg&YaJg z$>z+eoT>AxBO@1uR?i?*Z}_-wSRNBYHz->zVyv`N+Pf%<^iD169nu%CzY`S;dEN`5 z9lm6jQ6BHtFcf|Rqu_Ti7M_4{@FWbe`tfA0Hoepy(Jz(iVn^63;a%bkmL`j%yl051 zQ~Vj~6wk6>VH0Lu!qx-oGSts8u0nl-at*eDze9baqW2^1;VtZ3cn5ZY_uzBzKIA&6 zo3W59pQT_CECXNTxs?@wvIvI@z77MGTv*)Q>u-5g+DUo{Qbzk1OjKQFZW`>xy8_f* zToLNpSAumRHxu?^9tN38c3D|3?U#H_AU8_(Gsq~YAE#DV*0l97R#|ll-$v0VZZrG< z#$&S;vbdwNA6X~LFR%BG2*(p$fvJu>iRcF&i;z9i>5a_`a@Q?f67AYc1>-WM&XPLr zxJ>_;s%6GhJ?XO~R(dQAmN`o@SZDVwiFJNV^Z{~dNxXZ2iCr==SR$9ky5||M9$k!a zD^YqbZNa%qm&Q6j;oPre-_jP9cA%B4$c>3b0V0<*R|BNavVlQg*-0oX%-#TgoTM^H(!-^SfIF7IIsut31WwN71vdmlEUXHE|<}LB5 zm06DA$+B!!9m#$(SiK+}-ki!?+GB6(7xHsgKN`Z5QcK_F=yB6T@>XT3RuZ!&K7{8_ z)>Why{*H2N)l@Zuv%;mq%?gsg+Kn}L^%H6%XC#Mw&17N&ZoNR&j$U5 zy$9JZd)IufS`^QEtBlgwuKiWbD4wwHAys1x)tQg1LyjWnkjfQ#fPwU=xFDz3!VS^R zsWjOYiQC|DPD8sXd1x=9-It{s(p=NgoF4gRL#k^AYKTWFY)p5}M6K+R_NcQ^t9fMl z##Gl!sIeaT2z54UqDO9SOs_BpHI@Ck?lfz(+}{`}UEi+kV$0xaJMFlOx5Ni8$J%S^B{6qH<)Q+dId}sBp(Oze?0{(3 zMx0R@a-_IvFcaTZt0X++uP{k|H^#LIXT1#R{%&*EJE$ocvJ7=IYG#IrD%JU_Eu=c1Ss*|=k{P{jgY2R^HP^n7Q7!-X#h)1 z3#(13m$9aIOxYj&Gu6t{>4Td8NRi=3ME79MZ)UY9JwMh?ReM`nZA-n3N}cM}4+13m z!(f#v>cg5L?X8Zb5gJJno*b)HsVB!y=y?)q&4s0;9_{?O^6>Z{x#sG~ZtZ2b`b(F)DnADPe5adB37Fz;9V6&g(n59a-bov!vinExt&vi5ehdX#$i`Xi6S{iyYLse8X2S$lK&WTYgCqyEU_aX(n* zZ|%t1`(T-W@<*P4`@vy)){d;b4>spzf8>d{AMD5*c4X~+Fu!~L$UK_+N8<;Gdv}yu zdmpTJu#B7(f@{PaWHqt}`3|{`1hZMKi)15DB4d#G$U5Xx zqEPPWwxAqE&LM%7*>50? zk*>%HWG1p2*@b+ETtzBYp>PuPQLHzkDtDmB2xKO*4%vg8M*c*?!^jqS4C#jyB8!lB zkweHiM8CkUi)15%kV0e~vIjYb=uLKQq%qPLc>!60?1*5KcN*nSBs!802#~&!TXWj0 zg?nnVY`fO$px{j25@|akWCm?#<`3wQGA5IadETOkI?Q zALpwYvi0Lcj;B5z&gX0$K1oyAQuIj{_kz1W*~rb(;7?;Y&iyo>Z|j2gC9AEHxv!b} zSSIXCQ%SN3&onu;?|BN*?lUiW9r$c^&>?n^`lhS1#B>Oi5ueXgHHvS2K3u7m#e)z0 zuHs&x_;Zle$fw9jBSum#VX!ck32k8y)8EmCvuEA z62>v}NU|!H!5lx7#Yd((Dy2$|FX}{8O7&m0^!-@_wnY~ay~S=MeZKfrt(1009}P-R z@t1O(UCJ#-XX@mReWjDA@a2z0y7Z-|hQ2jeg1n1-ja)%25mD=`sV;^Iaro)e$^WuX1c8K8t!U!*KC7EK+DktB6UB|oF zoZrcmXRs+plXCv^*PHxXnQ~Pzwalbxbbdu8;ii18On!Tf{}z*4$LnL#TS*^jyB%{5 ziuZU>On*~`BvXccj1nD(FK=v4koCtse6V!pc$hcE#64l^Ka2UR=XJ((KlfcYfQFtO}0Bt=vdkM zP0eOCoUQ^f;C25<&Rxz3LDTrO@orYu0n9ef| zpJVLxCVn^5fD`;3BAyd&?@rS>d|PFwb;fjFj48_vQ-+?#E;401W*RicbgF)tq&w#@ zR~pSTCeQO`zEv^jEjHoT{PRS%La66jzGkY@^TLRNks zmax)f-`^y^(qy~U*hS{7m2&3$FzHx*7j9Gb3*K<3D4)STcG{hU-nG+nItC7#=fpn?^WbdMU^BtTOCl3V7ZW zAV!Y;5Y~RNiM`46$ppg$b5@Fpect5K-`GxPV0O836)j3{1?W+rB=zJ~X8>(%`SL2L z&~iK&bkx!zfzt9+a}_8vPBr6Yu+pEeOmp-gp1+qZD;ljZT0fw&I30yAF?2d5zvyhg zCS`uibAE^Zvkd;x>m0%GnIxBfobAkD;+ zls{Vfoc>AuEKSZx%nn-hQ{*Ia4!Mq4v|un2j?|V;1)I0#=BjP~`J`Nw{Zg)~mB3ig z)#XL7RX@Exzh~3s$BT*VZ^~WDk_nf}OYWrv)j%d*O5?MocP@F@qnx#mH7DuauXEuOz8wrPmdY9Kc$F)nERNm3g(i1YdpFkx^e7UG=CG z8Ff`>x9sX#DY!;<*Ys(VuX*?&|2>ZVfjHQzcIW9+jF<{irt3l1B!GGaO3l?|1s^?`bHnUr(c0M>wX6<3^fF zD^9Yur+~v_BR*HOZ*F!CTyPGCG@0FMO_jF(Px~Kbk9>;X~_+B&e za@^Pd{L!3arcAltOzzz;FNf}@sAuHHVHQ-6CS z^-`JF0#r5C*jGJ3J+4~5KQursca*E92OhsM4&UUm>XG+bmR0@AsOmmg}zheRFv}vJiBaDFtyy5Ql3ElA4NUEhDY8|y+vg4@S^W<=6aA;?4-0qr<27XEYVD7g z?<>;r^cQX4`vXs-R`IJhQ2W@`QJsC)h^N~4LPAuOtANqB!R4D*PE~d4FBp#d>vGqZ zN2qgj44=68TOqYJpB4G8(IBqbalCZ2e9J;qRdvXBjEJg+?~+cfWxW2d*A8)>O5ny! zuUBC%{c`D}GQPSkM2>AskUi1W6u32^Egj+cEo4-sc2YOt-UO}+&>&K2J#9Vao38xUViMf#|}PgNvf ziywD<)v=uVJw?3i9Tw`#tw`tS_c=@cHucl|Bc-Nqh+FmWjj5=@NqwYF>!u&~Y&Zha zee)`+NJn|YN`?`J(SADh+wuLr1-eXEe5c%YIw_UFeZS@OxkFWyBgEtT(XAp?WxrX? zn6Z8{(U_@zvym}#{AN32=K9SZ#(dgu4m9R4zd6pB1%C5IW6trLuNd_w5<6QI2)p1;z z`s4+i>9dVhy$Z!?u)UQB>`l^SM*H^wy;Usp!H#A%&sypv54p)zs zSy=A>|F4_xSF5J3mr;p6ceF}YwS76!DmLY9F1Y$@igm0YJJ=yiW6fyE1vr2;A)8A| zE}K$7*|5!wW@fw1%$(+w2@yiI9C8*aA@0qbrd0Exo2M`$ zl*P=k2N5F`50y$!Do=-B2ZX3p^nYL9@5Q6%_4?22bG@(6=Q^LS@ArEv_$;8{y@2PN zhKOZZ+g&*PEvbm}ysNgkYP-~L70Pu%ZSw>K)PH}$wEGpIcORbJZR748xhq}X<-c4g zty&RXt+}Vppie^r5)zM2Tl<_<`fc&{A9BujT3g<6o!VBryQj|XY~{(_dc6HjcX4Lj zMNgMcxPGO~4vY+R1?|nW3$^xEghv1B4lH=<#G9T~A1MFi8Y--$PXp=DC^q2RI-9-2F)C@`}BUdIc!A1SMwS<|YnN>ts!$&vm|vG-{fl(X;7nHCm1}O~k$2G~D${ zfSgEsSjH#SSBGR?QX+0yQn>43w{33PtiJL|$7YEUKDTA*Cf2j6gbwmpRw)vJK2{2w z%~T8IMza*$7RlkNL~@h8YLCoH_PVZlWM^`Q>wHzYm^>peB+$u2)cG(eY91PK%b+uz zOW=EmZgPl}HBVFB1YfMVvR~>S7+NZdnJAY>H_hD^t8`l$^%hEg>zvN=Yv6 z5}DOf7jV60B5qvjR5eeQrOu=;Lt7=|X15AgRV6fSxa@9KUp0|atr8=e1pl{xzN=wb zEo(acvygZ*)p}W+mKd@AjyUTGKX2lku=8r!y1whjVCmU9A@avNB0f~hvNj^Rv%A-@ zN9BC$`gDamJrTD>dboOCa?`!al3D39RRg(>y@AAKguA-dB>Me!Z@iRIKX5q3=^>Q- zi*@8=MlCg5&SiwF$#Oj-O`Vb!-kGk8wd7Ur6!o?=XfsKjmBnpRaQC%&SCvU|W}4bA z`!aJ>tlY?)8Q8Xt$*u2CQSxHjP}Nq-+74GWB{VBdB}i_TSKTACvQpGUDZ{^3zQKM@ zBHH;>imYgthkxuA~jRW zb8;A`%Q;!zKt%c6XYozLvsHDY)gG z!f}svN@I|3bn>cplHPfy8d6c-dA)LvvO=thG9>pwX2U;o&qWNSpZ*U~{BxV7A4S*o zksV#9j_gQC9c2~V1M5N^yB-`1!{IboA3hBu;BpuV*TZPI55~avU_U8s9+`R!09m5YAc6&88}=eTh^y|Mq>Ckd<33_Pr=V2 zLu{Rc46*eeS={So6(Xs5QT@Kd#t~(G4};;4P_N+gP)~siP#-lv!7RwyvnTu&sHeiu zus{3--UokGvMMiQKW4${tSD;stjx%)HA0q zWW%-Yg-zf9$gXDH2id`_L9h=T4EsSnmG6ZQp^sAcTGqoZtB7sG8U@)5tg!^J30M=* zm%+(!9ee^iYt)(sS)h16axEkulmBJU%x7wQxo&y+G z!jo_nd>^icAHX&6|KM799MeC!}>+#zlu#yjm=Ommoj*3bJ6ERIl6A# zHmLVrq28^(k!APhxYh?tvw@LqzsINx zy8!j>co8PSpP=3kF2nZl3hV^0!7lI@m&_iRAbt7=1Ua`dWzCSjcZd0YCxXuKCe*|J z7u2iWs^VamJN7xSP#nZluwLp(?H}pc-11^I-q26kG!53j3dMv*RyNCO6(!i+9K^S#qhC)3jhCw|i9)P+s4?#UA@}Zs+BcPrWBW2dWWNy!!21fbD zVAFX_fO_~R!ZvUU>LaTZ4uxysSokv3ty~XvD>uOB;YO&h4zE?Qigv&)@DsQl zdx$kurVY;JVPoImsL(yOWw&*O&=0BRS^0i&ly5)QU@ULip**?42=s$c*Y_=$01rVu zf`?%mtb}@-Is!Yuqp%}92K&NyU_N}einWsKr}YE+82BU9xA+TiuCm5j7xApda0zaJ zm!UoouE28mGu#HR!FS+wcoO~rxzAWP;1BRG7~tYg5WpP)R)G=F4bxy%xp04YTp$`} zqZI@>8?EZ_ei#gg!VrlcvfAf7c`54}`RYGCU|ehLzt8|{!9DmQ;1Sq}l=@EA80u-3 z0QFg**V$>Ke+rvo{|YvTKfo4HpAmP#i?AiELK&$6mam{X9-To=s58_@vKQ)0owoC= zV`ZYp!)(|Jwukzt&Vl-}*Ad-0Pr*n9|fM;`@sexr@9r*+SOfzGbdiwMtR z=mXcozEF=)Ke!3@hg^-V0q_vi86AT<<5O@5yab2AEARn{81|YkrJnQ9mqBmqKYa%F zAyof8Ow1rS0@j2hVGB44X2D0G-s#6cy`ztXW8gSA7mkPe;GW3X{0XO_>m@!N>aLp+ zU`@39ZZ?L-7z$t#EQHPqi~A#e{2gKxkl@SiXp z?u9+!n^4#J0Msk(Ak=sFx1b*$f-E4Pbr=s%5Y`d+1w0DBg?ik$yxY1Sr*{IZxm+l% z4+t-SI-Dz(9nO`>I*t7`_zCei^sO%;N0;>-c1|SgN66`8orhiF1vt10_l1jiCSkY) z*@dmka3Q<`*TJ75`;T=Meg?0>-{7yXT7YH!23dY~h3Xl-0sMmsFa@jtH;+pue1{3A zS1b?qfBWzRxvjYoZVq&KFN`AKK^P6k!v=66jDhQ5L-;0)gQsC5_&tm#eWHgo4D(?+ z_D7)ZsWC=>6ne2whizcGeps@*(nNR`wk6Y`6iohnrwd#pC&jiZ?GSACB^M zc3bnZnIJt0yc_m{_rW}v5BtJLpj`{2KMHB7eS7N<3rzTY6aFk5=(ZNV4f6^A91e&2 zkQf1fhmX+8F3Nh?nt(yyPbNXVgFFiLQ{z;(HD@lIhQ0z$hh=aEWae2Gs+zENp zS@13_fO;!0g73q*vSPT8S4a^fqI`?61ycAkP;Uj#LcLY!#x*c{6ZkxKFI)nK zpyTV#c>(H6p&t&0E1-TR_y?QW! zv^<^Vds}ZYzOkDl-_uhDjPDkz3v*c>`*_#&3zGZ^QS$cq=pd&s#Vs*zLD-TBt%I`d z(v{_rH50<5&xBg4Gm*Wno^53R;7Hj%VZ8fsa$73#6SE|CVt{&4Mo#p~L-^Lpnu%%d zCkfpoXYg@j^lX*TNnZC1e7huXQkHurzWuUzQkLf_e3j{PVp3brEWGcfON~b}JhSnB zkS;wRZR=rE@O+vsi?9~pJ(n&=uomL|E?qp6W8%I`|8GatVJqNTW9e(t-?ldWA8Vy;<@otq z-1oG#YBQ|VSALotUp3i@AyHG}t2Q_GZd2lGx4@rhCEKOw2}GAwdo0qIf|;$ueo0vy zwnC4AX;60^cLe*!$r)nbxw$J8=nD;ZUi-$`2I@mK6EY2~wvZ9A^oz{JP`|KT3Ohjk zAkY!M3_HQs^ysix*zX{6;T{6I!Z%=d$SSgWz@xBF#qq}mDz!}FpJCLEA6E>1@~8@?5YINVvLy6c zv~-`*TsKl@z!xwGj z;>@nKcj3LYw)E`T<}8$lo~q>{)7euZZt}OZArlKCc=gi*X;8O5by8xeVZPvRtMYWU1A%gNKn<y5$Lz}fWJAxH!r(~RL>Qqlmoi=*pl#%v!+W}o)yVyXiY?G#ul)Mlo3;p#Q z=umwt*N-@lna~(=6-&ALL1~kTRgYM9eWavWXNi43FsYMiLreB7 z{ddBF?LI~uj+m5|+%>v>G-iFI3?FYWlkSpy?~jVtYgp&l2kTXY4chwcjwW%Bv2=dANdZ#2B9PoRt%$;{TrtG` zC!x(`@js$`?{iRBM>`F};Ky8x8$zxM_7mY3kjY`4gZh&GAE-~_uVD|UPwbwMhaUSK zC*5m*;J66KV*d$pI#`#X4_<+V@G5-4vcjxuc$Q=M75)QWx1{Zh_xYUOQMbEQ?{$=E z|J@*}uJcW(?SDZ%ScwnDFlo(-$R?l2fmgEf>jcN46m ztb~Hicyz*ThHO9fN2w!Fe~fw$MoaojLu%K;7h8h`gA7IH)+p)t`jS<#o&!vSZ`(-1 zs)VZFI*U`b%&#k>SJhWZQn;!!dsF4A#_oeeOOy+%5|8eR7#D!Lmv ziJV6QxQ4}6gsurwYOBPrO~lPxyMVjt>9szUECXInaV4k7v#<1&lP?GJW%BIHS+0R8 zvTA*TbXXUx9+JFuMSK}NwN8HoUi`}4A$q#%>%E>N@shtjOL0TlkQnj|Hr@ts0<%ix z)cPVdiB$Dv!Yd8&Eq-O75@M%>e8_Tpl3DyD@m?fl8gE!ntsfqA1^ocBRSs@As*)>; zH&#))$W1@0Nfpyyt*K(#(3Jkjcw{NE8TkacghbaW>3IK=&9Uw|bQ}%c>~$C6+a>w< z=Hh!(R&Gx7%)@siLq6Kv%EMjSb0R}(lx27p;60roJ@GEYdp1Mnm$mW~}t!_8^yaml9Fz3yl6Rg-UCPjf$q zFH{PSg>qMIe>86o@1bKEcD8;3o|&35dWD!JRT z+$-_T&~caD#TWb1ZL#iESmsD2VXN^K+xbLPB)Ut{_~k-HmU|7p<+gnV_O)oGQd!}3 zzl?8#sO?_&I(%Cs8{c|-J7xNIZ}2Pl_IsV_?+OQH|@9siQC@lblZBwj;pPmt!}riC+xU9Ui>ZJ({@~Ky))mlcHH~1=2)F? z=fH<~>Y%M%tnRn1=k2&d{wIf@?YP?7lTUBA>idTsmotfXd%3r*E=k=TRa;xTT0L)D zt9kWhCzSWqf2%~O9a&rNtVDzp`9aKgwmH_0tgYRxUbk~@>O_7Ba}O);wmHR)tgXHI zgnz5bUMDhdLjKl6?d{0gdT0B(I*}j7d}lTC?8w@BXEg>mkw;*@vl>I~$l7{mHAdKx z<$_q??y>H@ZJJ@{%KJIKkq)|To#W&hyE`D{ zZhoq8tIfqkZdjuaKVZ0JDRJsL`hV)W+|E^7@2qR7lj})xy>kk0kaN2mhTJ*Lwn)gH zh9P&3<4!xnasN}yey8*anD6ZEN*y^=TkmY?aoIjjm$+}LUto3k@H9ZmrQ-(Y=iVi#v==nQe-dkA#w=`tj)fFv_l3Vk0Q?? z>yQJ;C&*PKm@8IOqysWEj7{P(JWG+y$a~1wh*gK12GSbog^Wh@$Lp7n?Z}77c_g^5 zzO||Yjfb_aM@(cqG8b8g>_t99t|GOW!QpWAp`;(4sXS7CI2rfs;Ys{FDz7q)Czis>EFO*a zRldfv!oy(-g>rm>}$VHq!HkB*}fJ>K?F*0Hyr4%*ID zP(Oq86SXW%9zC{Dc`B|So1|3piZSp0tm4~6GWN)5WFbqau{)Q_rIdc1#kP>dZ%Sx?wC-unJRo!ti?=qze{_&Jd- zeCTb^g=#&7Jc%qvwj%E#Un74~U0+F`4of}?>{}}kJNGC3P_J)|gPDGsx!5%4F}*eQ zJ73K+CVagi-%xD(L1vi_KQ8$nh5K&MFC&4#lQlTA2D~%bt(D zYM5O9INXmlE>QB`4t)-G-)rGzBy&;(RY4p0L{)%;{(+@D=Zd1=nQ~z5( zlMHd%RZagO%t;_6pM*!OG{yEc#p*8|I=f6c_({Vaai*{prm!_8))>QFQ^}4@FP$p> zRwtQUu9*RhlcX~ZeG}MxbgVI^%=P%Se#10jpW$&++GLaKFjEVj=#C7e2%XH6ZxH}m(5Gu2$yFgf<` zhH9Vm{Vd$a*9kjvh-qM)>BLZzNxZ3SkQt>lrV^)3gZTlNo!)IKUu^6nt2*{I#=gds zbJ`3}k~80Z*5X^M(~L;2DR`tQc%`xTH9cNP({$@jn~JP31)VVkl^cD!$!ERE=eQY( zLKAO-T~TVY#?<(fNf;U|k!NGZ95cPy(d;rIhVx9Xeq;19Q_eT0oCwpv%Vs(3Gx7O7 zgkA4Fru-Eq{|QoZHayO4#;DTdHq6Ys3r3HZb7#YQ)-`!fHiMCE*utc~c5B2jpzI@uvhjD&k zvG`n(=PGl8&nfl(6XPCFHcv|Cf0Ba&se3HaTqgYI3w25IzLJQ;^w~+|GvqtuDq=Bj zf~D`Q@NM57supE`U8-j#F_yZC{2a+@nbDHJ;py`ErDT;V)h=hLR?_uyno5%yxUJ>& z%U+c(-`Z}>6|c&W`>v!Yugu47BRj98sZ9BSXV~wrRF~#Ix8ObV{XctU@XyudCA1Op z4%#ua;H%AD-ci!_s#mp?DOYu2tFCTf!|8fWznq?Z%`3C6RhI+TbfSycMph*J!pjwJ zMYCV4Dw*(Gl=S+oR*eKJ-mblVmlmRjc8sPGh{S<)h!yD5cu=8(t~9QC%+GXhCr?H+6CS zaMNWzZic*p>y?W)y%d%3mzPd_;IAwh_E&XT_gAW{fM5QVs)jGCt+LdJWxbVmS)QuC z?0MDPl{sqJenlrP`vo`Ef0t5e{uWAA_m5X93I7WiRBQh`8tMLPGjPNrCIclUoBS5ux<&WC+M1Wev zXUldk1gdBi>u(UK?orKmO$b!0UDfo>QvU_J{Ijd8yLNS{u0~W*ZhvT~3U})(=TrW3 zHB`77?LS*XMY;L$fVJ1QxcO?!8sk64gsTPq)S3k9|6DT23Dm#Z?QMGlD)35ZbRBnOCnYP~ev5wMwn{c>EJyZ{%7i_ zLF#RPi7tJsKee8Ua_!3S_pYZR)tiob#Hc46^|VpXI_lR(J@2SL8}$!cRW5%XIjU;@ zH5#Fg7U5{Ij@H!CQXI|eXzd-XtE1&P+5krz>S!YzZJeV`b+j3dHpkJ59j(OCmOEOh zqit}sEsnO+(e^u9rK25pv=1HaGe`T%(SCHaD~|TNt+`nJcE<(zX>63LfG*U!2S=hLMBW|WF_pTJbjF@55g_%P`N>5mQ_{ga8U z68(Ln$!4j4g2rq9;%Jqu_U_sdt?p(oiC$9e|No!xc16dkt5sA@e`phxqL`IURO3v3 zZDQ#!_8U3>cXM3NWyyEpG(6AA-+?2vPPG0ZFF({kotO++UcW(#pH^Qu_6`RZ^k8`$PRd*28=^ From 9209b42d029738fa0ac4dc6eb8b0ccc2dee9f7b0 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 17 Feb 2018 01:42:24 +1100 Subject: [PATCH 0814/2058] Fix typo --- phlib/appresolver.c | 50 ++++++++++++++++++++++++++++++++++--- phlib/include/appresolver.h | 6 +++++ 2 files changed, 52 insertions(+), 4 deletions(-) diff --git a/phlib/appresolver.c b/phlib/appresolver.c index 961234d6e389..423837f22077 100644 --- a/phlib/appresolver.c +++ b/phlib/appresolver.c @@ -93,6 +93,7 @@ static BOOLEAN PhpKernelAppCoreInitialized( AppContainerFreeMemory_I = PhGetProcedureAddress(kernelAppBaseAddress, "AppContainerFreeMemory", 0); AppContainerRegisterSid_I = PhGetProcedureAddress(kernelAppBaseAddress, "AppContainerRegisterSid", 0); AppContainerUnregisterSid_I = PhGetProcedureAddress(kernelAppBaseAddress, "AppContainerUnregisterSid", 0); + AppPolicyGetWindowingModel_I = PhGetProcedureAddress(kernelAppBaseAddress, "AppPolicyGetWindowingModel", 0); } @@ -156,11 +157,52 @@ BOOLEAN PhAppResolverGetAppIdForProcess( return FALSE; } +HRESULT PhAppResolverActivateAppId( + _In_ PPH_STRING AppUserModelId, + _In_opt_ PWSTR CommandLine, + _Out_opt_ HANDLE *ProcessId + ) +{ + HRESULT status; + ULONG processId = 0; + IApplicationActivationManager* applicationActivationManager; + + status = CoCreateInstance( + &CLSID_ApplicationActivationManager, + NULL, + CLSCTX_LOCAL_SERVER, + &IID_IApplicationActivationManager, + &applicationActivationManager + ); + + if (SUCCEEDED(status)) + { + CoAllowSetForegroundWindow((IUnknown*)applicationActivationManager, NULL); + + status = IApplicationActivationManager_ActivateApplication( + applicationActivationManager, + PhGetString(AppUserModelId), + CommandLine, + AO_NONE, + &processId + ); + + IApplicationActivationManager_Release(applicationActivationManager); + } + + if (SUCCEEDED(status)) + { + if (ProcessId) *ProcessId = UlongToHandle(processId); + } + + return status; +} + PPH_STRING PhGetAppContainerName( _In_ PSID AppContainerSid ) -{ - PPH_STRING packageFamilyName = NULL; +{ + PPH_STRING appContainerName = NULL; PWSTR packageMonikerName; if (!PhpKernelAppCoreInitialized()) @@ -168,11 +210,11 @@ PPH_STRING PhGetAppContainerName( if (SUCCEEDED(AppContainerLookupMoniker_I(AppContainerSid, &packageMonikerName))) { - packageFamilyName = PhCreateString(packageMonikerName); + appContainerName = PhCreateString(packageMonikerName); AppContainerFreeMemory_I(packageMonikerName); } - return packageFamilyName; + return appContainerName; } PPH_STRING PhGetAppContainerPackageName( diff --git a/phlib/include/appresolver.h b/phlib/include/appresolver.h index 45aeefbfa618..85c2f6d3e81e 100644 --- a/phlib/include/appresolver.h +++ b/phlib/include/appresolver.h @@ -32,6 +32,12 @@ BOOLEAN PhAppResolverGetAppIdForProcess( _Out_ PPH_STRING *ApplicationUserModelId ); +HRESULT PhAppResolverActivateAppId( + _In_ PPH_STRING AppUserModelId, + _In_opt_ PWSTR CommandLine, + _Out_opt_ HANDLE *ProcessId + ); + PPH_STRING PhGetAppContainerName( _In_ PSID AppContainerSid ); From de2db0a7387b1b68117518fe132871e2dafa92e2 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 17 Feb 2018 01:50:18 +1100 Subject: [PATCH 0815/2058] Improve startup initialization, Fix handle check, Remove duplicate main window delayed load --- ProcessHacker/include/mainwnd.h | 4 + ProcessHacker/include/mainwndp.h | 6 +- ProcessHacker/mainwnd.c | 133 ++++++++++++------------------- 3 files changed, 57 insertions(+), 86 deletions(-) diff --git a/ProcessHacker/include/mainwnd.h b/ProcessHacker/include/mainwnd.h index 8c24ec999766..1ee352a36662 100644 --- a/ProcessHacker/include/mainwnd.h +++ b/ProcessHacker/include/mainwnd.h @@ -207,6 +207,10 @@ BOOLEAN PhMainWndInitialization( _In_ INT ShowCommand ); +BOOLEAN PhInitializeRestartPolicy( + VOID + ); + VOID PhAddMiniProcessMenuItems( _Inout_ struct _PH_EMENU_ITEM *Menu, _In_ HANDLE ProcessId diff --git a/ProcessHacker/include/mainwndp.h b/ProcessHacker/include/mainwndp.h index 14f212db7e8c..cbb1f7a5d9e8 100644 --- a/ProcessHacker/include/mainwndp.h +++ b/ProcessHacker/include/mainwndp.h @@ -49,7 +49,7 @@ VOID PhMwpInitializeControls( VOID ); -NTSTATUS PhMwpDelayedLoadFunction( +NTSTATUS PhMwpLoadStage1Worker( _In_ PVOID Parameter ); @@ -106,10 +106,6 @@ VOID PhMwpOnSetFocus( VOID ); -VOID PhMwpOnTimer( - _In_ ULONG Id - ); - BOOLEAN PhMwpOnNotify( _In_ NMHDR *Header, _Out_ LRESULT *Result diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index 6ea93141f474..057818e6457f 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -156,17 +156,22 @@ BOOLEAN PhMainWndInitialization( NULL ); PhDeleteStringBuilder(&stringBuilder); - PhMainWndMenuHandle = GetMenu(PhMainWndHandle); if (!PhMainWndHandle) return FALSE; + PhMainWndMenuHandle = GetMenu(PhMainWndHandle); PhMwpInitializeMainMenu(PhMainWndMenuHandle); // Choose a more appropriate rectangle for the window. PhAdjustRectangleToWorkingArea(PhMainWndHandle, &windowRectangle); - MoveWindow(PhMainWndHandle, windowRectangle.Left, windowRectangle.Top, - windowRectangle.Width, windowRectangle.Height, FALSE); + MoveWindow( + PhMainWndHandle, + windowRectangle.Left, windowRectangle.Top, + windowRectangle.Width, windowRectangle.Height, + FALSE + ); + UpdateWindow(PhMainWndHandle); // Allow WM_PH_ACTIVATE to pass through UIPI. ChangeWindowMessageFilter(WM_PH_ACTIVATE, MSGFLT_ADD); @@ -178,21 +183,17 @@ BOOLEAN PhMainWndInitialization( PhMwpLoadSettings(); PhLogInitialization(); - PhQueueItemWorkQueue(PhGetGlobalWorkQueue(), PhMwpDelayedLoadFunction, NULL); - - PhMwpSelectionChangedTabControl(-1); - - // Perform a layout. - PhMwpOnSize(); + // Start the main providers. PhStartProviderThread(&PhPrimaryProviderThread); PhStartProviderThread(&PhSecondaryProviderThread); - // See PhMwpOnTimer for more details. - if (PhCsUpdateInterval > PH_FLUSH_PROCESS_QUERY_DATA_INTERVAL_1) - SetTimer(PhMainWndHandle, TIMER_FLUSH_PROCESS_QUERY_DATA, PH_FLUSH_PROCESS_QUERY_DATA_INTERVAL_1, NULL); + // Queue delayed init functions. + PhQueueItemWorkQueue(PhGetGlobalWorkQueue(), PhMwpLoadStage1Worker, NULL); - UpdateWindow(PhMainWndHandle); + // Perform a layout. + PhMwpSelectionChangedTabControl(-1); + PhMwpOnSize(); if ((PhStartupParameters.ShowHidden || PhGetIntegerSetting(L"StartHidden")) && PhNfIconsEnabled()) ShowCommand = SW_HIDE; @@ -305,11 +306,6 @@ LRESULT CALLBACK PhMwpWndProc( PhMwpOnSetFocus(); } break; - case WM_TIMER: - { - PhMwpOnTimer((ULONG)wParam); - } - break; case WM_NOTIFY: { LRESULT result; @@ -362,18 +358,23 @@ VOID PhMwpInitializeProviders( if (interval == 0) { - interval = 1000; + interval = PH_FLUSH_PROCESS_QUERY_DATA_INTERVAL_LONG_TERM; PH_SET_INTEGER_CACHED_SETTING(UpdateInterval, interval); } + // See PhMwpLoadStage1Worker for more details. + if (interval > PH_FLUSH_PROCESS_QUERY_DATA_INTERVAL_LONG_TERM) + interval = 1000; + PhInitializeProviderThread(&PhPrimaryProviderThread, interval); PhInitializeProviderThread(&PhSecondaryProviderThread, interval); PhRegisterProvider(&PhPrimaryProviderThread, PhProcessProviderUpdate, NULL, &PhMwpProcessProviderRegistration); - PhSetEnabledProvider(&PhMwpProcessProviderRegistration, TRUE); PhRegisterProvider(&PhPrimaryProviderThread, PhServiceProviderUpdate, NULL, &PhMwpServiceProviderRegistration); - PhSetEnabledProvider(&PhMwpServiceProviderRegistration, TRUE); PhRegisterProvider(&PhPrimaryProviderThread, PhNetworkProviderUpdate, NULL, &PhMwpNetworkProviderRegistration); + + PhSetEnabledProvider(&PhMwpProcessProviderRegistration, TRUE); + PhSetEnabledProvider(&PhMwpServiceProviderRegistration, TRUE); } VOID PhMwpApplyUpdateInterval( @@ -482,14 +483,32 @@ VOID PhMwpInitializeControls( CurrentPage = PageList->Items[0]; } -NTSTATUS PhMwpDelayedLoadFunction( +NTSTATUS PhMwpLoadStage1Worker( _In_ PVOID Parameter ) { + // If the update interval is too large, the user might have to wait a while before seeing some types of + // process-related data. We force an update by boosting the provider shortly after the program + // starts up to either make things appear more quickly or delay the . + + if (PhCsUpdateInterval >= PH_FLUSH_PROCESS_QUERY_DATA_INTERVAL_LONG_TERM) + { + PhDelayExecution(PH_FLUSH_PROCESS_QUERY_DATA_INTERVAL_1); + } + + PhMwpApplyUpdateInterval(PhCsUpdateInterval); + + if (PhCsUpdateInterval >= PH_FLUSH_PROCESS_QUERY_DATA_INTERVAL_LONG_TERM) + { + PhBoostProvider(&PhMwpProcessProviderRegistration, NULL); + PhBoostProvider(&PhMwpServiceProviderRegistration, NULL); + } + PhNfLoadStage2(); // Make sure we get closed late in the shutdown process. - SetProcessShutdownParameters(0x100, 0); + SetProcessShutdownParameters(0x100, 0); + PhInitializeRestartPolicy(); DelayedLoadCompleted = TRUE; //PostMessage(PhMainWndHandle, WM_PH_DELAYED_LOAD_COMPLETED, 0, 0); @@ -1653,51 +1672,6 @@ VOID PhMwpOnSetFocus( SetFocus(CurrentPage->WindowHandle); } -VOID PhMwpOnTimer( - _In_ ULONG Id - ) -{ - if (Id == TIMER_FLUSH_PROCESS_QUERY_DATA) - { - static ULONG state = 1; - - // If the update interval is too large, the user might have to wait a while before seeing some types of - // process-related data. Here we force an update. - // - // In addition, we force updates shortly after the program starts up to make things appear more quickly. - - switch (state) - { - case 1: - state = 2; - - if (PhCsUpdateInterval > PH_FLUSH_PROCESS_QUERY_DATA_INTERVAL_2) - SetTimer(PhMainWndHandle, TIMER_FLUSH_PROCESS_QUERY_DATA, PH_FLUSH_PROCESS_QUERY_DATA_INTERVAL_2, NULL); - else - KillTimer(PhMainWndHandle, TIMER_FLUSH_PROCESS_QUERY_DATA); - - break; - case 2: - state = 3; - - if (PhCsUpdateInterval > PH_FLUSH_PROCESS_QUERY_DATA_INTERVAL_LONG_TERM) - SetTimer(PhMainWndHandle, TIMER_FLUSH_PROCESS_QUERY_DATA, PH_FLUSH_PROCESS_QUERY_DATA_INTERVAL_LONG_TERM, NULL); - else - KillTimer(PhMainWndHandle, TIMER_FLUSH_PROCESS_QUERY_DATA); - - break; - case 3: - { - KillTimer(PhMainWndHandle, TIMER_FLUSH_PROCESS_QUERY_DATA); - } - break; - } - - PhBoostProvider(&PhMwpProcessProviderRegistration, NULL); - PhBoostProvider(&PhMwpServiceProviderRegistration, NULL); - } -} - BOOLEAN PhMwpOnNotify( _In_ NMHDR *Header, _Out_ LRESULT *Result @@ -2147,6 +2121,16 @@ VOID PhMwpLoadSettings( ULONG opacity; PPH_STRING customFont; + customFont = PhaGetStringSetting(L"Font"); + opacity = PhGetIntegerSetting(L"MainWindowOpacity"); + PhStatisticsSampleCount = PhGetIntegerSetting(L"SampleCount"); + PhEnablePurgeProcessRecords = !PhGetIntegerSetting(L"NoPurgeProcessRecords"); + PhEnableCycleCpuUsage = !!PhGetIntegerSetting(L"EnableCycleCpuUsage"); + PhEnableServiceNonPoll = !!PhGetIntegerSetting(L"EnableServiceNonPoll"); + PhEnableNetworkProviderResolve = !!PhGetIntegerSetting(L"EnableNetworkResolve"); + PhEnableProcessQueryStage2 = !!PhGetIntegerSetting(L"EnableStage2"); + PhMwpNotifyIconNotifyMask = PhGetIntegerSetting(L"IconNotifyMask"); + if (PhGetIntegerSetting(L"MainWindowAlwaysOnTop")) { AlwaysOnTop = TRUE; @@ -2154,23 +2138,10 @@ VOID PhMwpLoadSettings( SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOREDRAW | SWP_NOSIZE); } - opacity = PhGetIntegerSetting(L"MainWindowOpacity"); - if (opacity != 0) PhSetWindowOpacity(PhMainWndHandle, opacity); - PhStatisticsSampleCount = PhGetIntegerSetting(L"SampleCount"); - PhEnablePurgeProcessRecords = !PhGetIntegerSetting(L"NoPurgeProcessRecords"); - PhEnableCycleCpuUsage = !!PhGetIntegerSetting(L"EnableCycleCpuUsage"); - PhEnableServiceNonPoll = !!PhGetIntegerSetting(L"EnableServiceNonPoll"); - PhEnableNetworkProviderResolve = !!PhGetIntegerSetting(L"EnableNetworkResolve"); - - PhEnableProcessQueryStage2 = !!PhGetIntegerSetting(L"EnableStage2"); - PhNfLoadStage1(); - PhMwpNotifyIconNotifyMask = PhGetIntegerSetting(L"IconNotifyMask"); - - customFont = PhaGetStringSetting(L"Font"); if (customFont->Length / 2 / 2 == sizeof(LOGFONT)) SendMessage(PhMainWndHandle, WM_PH_UPDATE_FONT, 0, 0); From 90ef1cde3d4d8b2160df1250b27872e211fa600e Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 17 Feb 2018 01:54:18 +1100 Subject: [PATCH 0816/2058] Add missing header --- phlib/include/phbasesup.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/phlib/include/phbasesup.h b/phlib/include/phbasesup.h index d487e6c56e0c..98aa90c7b216 100644 --- a/phlib/include/phbasesup.h +++ b/phlib/include/phbasesup.h @@ -154,6 +154,20 @@ PhLocalTimeToSystemTime( _Out_ PLARGE_INTEGER SystemTime ); +FORCEINLINE +NTSTATUS +NTAPI +PhDelayExecution( + _In_ LONGLONG Interval + ) +{ + LARGE_INTEGER interval; + + interval.QuadPart = -Interval * PH_TIMEOUT_MS; + + return NtDelayExecution(FALSE, &interval); +} + // Heap _May_raise_ From 343c655eec812e830a0689ba229f07c405476511 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 17 Feb 2018 02:23:43 +1100 Subject: [PATCH 0817/2058] Tidy up previous commits --- ProcessHacker/ProcessHacker.rc | 14 +-- ProcessHacker/main.c | 14 +-- ProcessHacker/options.c | 161 +++++++++------------------------ ProcessHacker/runas.c | 6 +- ProcessHacker/settings.c | 1 - 5 files changed, 54 insertions(+), 142 deletions(-) diff --git a/ProcessHacker/ProcessHacker.rc b/ProcessHacker/ProcessHacker.rc index 12e2c50f452c..78a1bb4076aa 100644 --- a/ProcessHacker/ProcessHacker.rc +++ b/ProcessHacker/ProcessHacker.rc @@ -165,13 +165,10 @@ BEGIN MENUITEM "&Suspend", ID_THREAD_SUSPEND MENUITEM "Res&ume", ID_THREAD_RESUME MENUITEM SEPARATOR + MENUITEM "Analy&ze", ID_ANALYZE_WAIT MENUITEM "&Affinity", ID_THREAD_AFFINITY MENUITEM "Per&missions", ID_THREAD_PERMISSIONS MENUITEM "&Token", ID_THREAD_TOKEN - POPUP "Analy&ze" - BEGIN - MENUITEM "&Wait", ID_ANALYZE_WAIT - END POPUP "&Priority" BEGIN MENUITEM "Time &critical", ID_PRIORITY_TIMECRITICAL @@ -1271,12 +1268,9 @@ STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSM CAPTION "Symbols" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN - LTEXT "Dbghelp.dll path:",IDC_STATIC,7,9,56,8 - EDITTEXT IDC_DBGHELPPATH,66,8,123,12,ES_AUTOHSCROLL - PUSHBUTTON "Browse...",IDC_BROWSE,193,7,50,14 - LTEXT "Search path:",IDC_STATIC,7,24,42,8 - EDITTEXT IDC_DBGHELPSEARCHPATH,66,23,177,12,ES_AUTOHSCROLL - CONTROL "Undecorate symbols",IDC_UNDECORATESYMBOLS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,38,81,10 + LTEXT "Search path:",IDC_STATIC,7,8,42,8 + EDITTEXT IDC_DBGHELPSEARCHPATH,66,7,177,12,ES_AUTOHSCROLL + CONTROL "Undecorate symbols",IDC_UNDECORATESYMBOLS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,22,81,10 END IDD_MEMEDIT DIALOGEX 0, 0, 441, 269 diff --git a/ProcessHacker/main.c b/ProcessHacker/main.c index 5efe777b2adf..6a909d2a77d5 100644 --- a/ProcessHacker/main.c +++ b/ProcessHacker/main.c @@ -83,10 +83,6 @@ BOOLEAN PhInitializeMitigationPolicy( VOID ); -BOOLEAN PhInitializeRestartPolicy( - VOID - ); - PPH_STRING PhApplicationDirectory = NULL; PPH_STRING PhApplicationFileName = NULL; PHAPPAPI HFONT PhApplicationFont = NULL; @@ -546,10 +542,14 @@ VOID PhInitializeCommonControls( icex.dwSize = sizeof(INITCOMMONCONTROLSEX); icex.dwICC = - ICC_LINK_CLASS | ICC_LISTVIEW_CLASSES | + ICC_TREEVIEW_CLASSES | + ICC_BAR_CLASSES | + ICC_TAB_CLASSES | ICC_PROGRESS_CLASS | - ICC_TAB_CLASSES + ICC_COOL_CLASSES | + ICC_STANDARD_CLASSES | + ICC_LINK_CLASS ; InitCommonControlsEx(&icex); @@ -937,7 +937,7 @@ VOID PhpInitializeSettings( if (status == STATUS_FILE_CORRUPT_ERROR) { if (PhShowMessage2( - PhMainWndHandle, + NULL, TDCBF_YES_BUTTON | TDCBF_NO_BUTTON, TD_WARNING_ICON, L"Process Hacker's settings file is corrupt. Do you want to reset it?", diff --git a/ProcessHacker/options.c b/ProcessHacker/options.c index 8032b5d4e0f0..0a0f0968930f 100644 --- a/ProcessHacker/options.c +++ b/ProcessHacker/options.c @@ -37,7 +37,6 @@ #include #define WM_PH_CHILD_EXIT (WM_APP + 301) -#define WM_PH_SHOWDIALOG (WM_APP + 302) INT_PTR CALLBACK PhpOptionsGeneralDlgProc( _In_ HWND hwndDlg, @@ -135,7 +134,6 @@ VOID PhpSetDefaultTaskManager( ); static HWND PhOptionsWindowHandle = NULL; -static HANDLE PhOptionsWindowThreadHandle = NULL; static PH_EVENT PhOptionsWindowInitializedEvent = PH_EVENT_INIT; static PPH_LIST PhOptionsDialogList = NULL; static PH_LAYOUT_MANAGER WindowLayoutManager; @@ -155,7 +153,6 @@ static BOOLEAN CurrentUserRunPresent = FALSE; static BOOLEAN CurrentUserRunStartHidden = FALSE; static HFONT CurrentFontInstance = NULL; static PPH_STRING NewFontSelection = NULL; -static HIMAGELIST GeneralListviewImageList = NULL; // Advanced static PH_STRINGREF TaskMgrImageOptionsKeyName = PH_STRINGREF_INIT(L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\taskmgr.exe"); @@ -165,58 +162,6 @@ static HWND WindowHandleForElevate = NULL; // Highlighting static HWND HighlightingListViewHandle = NULL; -NTSTATUS ShowUpdateDialogThread( - _In_ PVOID Parameter - ) -{ - PH_AUTO_POOL autoPool; - - PhInitializeAutoPool(&autoPool); - - DialogBox( - PhInstanceHandle, - MAKEINTRESOURCE(IDD_OPTIONS), - NULL, - PhOptionsDialogProc - ); - - PhUpdateCachedSettings(); - ProcessHacker_SaveAllSettings(PhMainWndHandle); - PhInvalidateAllProcessNodes(); - PhReloadSettingsProcessTreeList(); - PhSiNotifyChangeSettings(); - - if (RestartRequired) - { - if (PhShowMessage2( - PhMainWndHandle, - TDCBF_YES_BUTTON | TDCBF_NO_BUTTON, - TD_INFORMATION_ICON, - L"One or more options you have changed requires a restart of Process Hacker.", - L"Do you want to restart Process Hacker now?" - ) == IDYES) - { - ProcessHacker_PrepareForEarlyShutdown(PhMainWndHandle); - PhShellProcessHacker( - PhMainWndHandle, - L"-v", - SW_SHOW, - 0, - PH_SHELL_APP_PROPAGATE_PARAMETERS | PH_SHELL_APP_PROPAGATE_PARAMETERS_IGNORE_VISIBILITY, - 0, - NULL - ); - ProcessHacker_Destroy(PhMainWndHandle); - } - } - - PhDeleteAutoPool(&autoPool); - - PhResetEvent(&PhOptionsWindowInitializedEvent); - - return STATUS_SUCCESS; -} - VOID PhShowOptionsDialog( _In_ HWND ParentWindowHandle ) @@ -227,14 +172,42 @@ VOID PhShowOptionsDialog( } else { - if (!PhTestEvent(&PhOptionsWindowInitializedEvent)) - { - PhCreateThread2(ShowUpdateDialogThread, NULL); + DialogBox( + PhInstanceHandle, + MAKEINTRESOURCE(IDD_OPTIONS), + !!PhGetIntegerSetting(L"ForceNoParent") ? NULL : ParentWindowHandle, + PhOptionsDialogProc + ); - PhWaitForEvent(&PhOptionsWindowInitializedEvent, NULL); - } + PhUpdateCachedSettings(); + ProcessHacker_SaveAllSettings(PhMainWndHandle); + PhInvalidateAllProcessNodes(); + PhReloadSettingsProcessTreeList(); + PhSiNotifyChangeSettings(); - PostMessage(PhOptionsWindowHandle, WM_PH_SHOWDIALOG, 0, 0); + if (RestartRequired) + { + if (PhShowMessage2( + PhMainWndHandle, + TDCBF_YES_BUTTON | TDCBF_NO_BUTTON, + TD_INFORMATION_ICON, + L"One or more options you have changed requires a restart of Process Hacker.", + L"Do you want to restart Process Hacker now?" + ) == IDYES) + { + ProcessHacker_PrepareForEarlyShutdown(PhMainWndHandle); + PhShellProcessHacker( + PhMainWndHandle, + L"-v", + SW_SHOW, + 0, + PH_SHELL_APP_PROPAGATE_PARAMETERS | PH_SHELL_APP_PROPAGATE_PARAMETERS_IGNORE_VISIBILITY, + 0, + NULL + ); + ProcessHacker_Destroy(PhMainWndHandle); + } + } } } @@ -352,8 +325,6 @@ INT_PTR CALLBACK PhOptionsDialogProc( //PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(PhOptionsWindowHandle, IDC_APPLY), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(PhOptionsWindowHandle, IDOK), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); - EnableThemeDialogTexture(ContainerControl, ETDT_ENABLETAB); - { PPH_OPTIONS_SECTION section; @@ -380,9 +351,9 @@ INT_PTR CALLBACK PhOptionsDialogProc( PhOptionsEnterSectionView(section); PhOptionsOnSize(); - } - PhSetEvent(&PhOptionsWindowInitializedEvent); + EnableThemeDialogTexture(ContainerControl, ETDT_ENABLETAB); + } } break; case WM_NCDESTROY: @@ -404,16 +375,6 @@ INT_PTR CALLBACK PhOptionsDialogProc( PhDeleteLayoutManager(&WindowLayoutManager); } break; - case WM_PH_SHOWDIALOG: - { - if (IsMinimized(hwndDlg)) - ShowWindow(hwndDlg, SW_RESTORE); - else - ShowWindow(hwndDlg, SW_SHOW); - - SetForegroundWindow(hwndDlg); - } - break; case WM_SIZE: { PhOptionsOnSize(); @@ -1162,7 +1123,6 @@ INT_PTR CALLBACK PhpOptionsGeneralDlgProc( ULONG i; LOGFONT font; - GeneralListviewImageList = ImageList_Create(2, 20, ILC_COLOR, 1, 1); comboBoxHandle = GetDlgItem(hwndDlg, IDC_MAXSIZEUNIT); listviewHandle = GetDlgItem(hwndDlg, IDC_SETTINGS); @@ -1173,7 +1133,7 @@ INT_PTR CALLBACK PhpOptionsGeneralDlgProc( PhSetListViewStyle(listviewHandle, FALSE, TRUE); ListView_SetExtendedListViewStyleEx(listviewHandle, LVS_EX_CHECKBOXES, LVS_EX_CHECKBOXES); - ListView_SetImageList(listviewHandle, GeneralListviewImageList, LVSIL_SMALL); + //ListView_SetImageList(listviewHandle, GeneralListviewImageList, LVSIL_SMALL); PhSetControlTheme(listviewHandle, L"explorer"); PhAddListViewColumn(listviewHandle, 0, 0, 0, LVCFMT_LEFT, 250, L"Name"); PhSetExtendedListView(listviewHandle); @@ -1222,8 +1182,6 @@ INT_PTR CALLBACK PhpOptionsGeneralDlgProc( PhClearReference(&NewFontSelection); PhClearReference(&OldTaskMgrDebugger); - ImageList_Destroy(GeneralListviewImageList); - PhDeleteLayoutManager(&LayoutManager); } break; @@ -1654,49 +1612,13 @@ INT_PTR CALLBACK PhpOptionsSymbolsDlgProc( { case WM_INITDIALOG: { - SetDlgItemText(hwndDlg, IDC_DBGHELPPATH, PhaGetStringSetting(L"DbgHelpPath")->Buffer); SetDlgItemText(hwndDlg, IDC_DBGHELPSEARCHPATH, PhaGetStringSetting(L"DbgHelpSearchPath")->Buffer); - SetDlgItemCheckForSetting(hwndDlg, IDC_UNDECORATESYMBOLS, L"DbgHelpUndecorate"); PhInitializeLayoutManager(&LayoutManager, hwndDlg); - PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDC_DBGHELPPATH), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); - PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDC_BROWSE), NULL, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDC_DBGHELPSEARCHPATH), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); } break; - case WM_COMMAND: - { - switch (LOWORD(wParam)) - { - case IDC_BROWSE: - { - static PH_FILETYPE_FILTER filters[] = - { - { L"dbghelp.dll", L"dbghelp.dll" }, - { L"All files (*.*)", L"*.*" } - }; - PVOID fileDialog; - PPH_STRING fileName; - - fileDialog = PhCreateOpenFileDialog(); - PhSetFileDialogFilter(fileDialog, filters, sizeof(filters) / sizeof(PH_FILETYPE_FILTER)); - - fileName = PH_AUTO(PhGetFileName(PhaGetDlgItemText(hwndDlg, IDC_DBGHELPPATH))); - PhSetFileDialogFileName(fileDialog, fileName->Buffer); - - if (PhShowFileDialog(hwndDlg, fileDialog)) - { - fileName = PH_AUTO(PhGetFileDialogFileName(fileDialog)); - SetDlgItemText(hwndDlg, IDC_DBGHELPPATH, fileName->Buffer); - } - - PhFreeFileDialog(fileDialog); - } - break; - } - } - break; case WM_SIZE: { PhLayoutManagerLayout(&LayoutManager); @@ -1704,13 +1626,12 @@ INT_PTR CALLBACK PhpOptionsSymbolsDlgProc( break; case WM_DESTROY: { - PPH_STRING dbgHelpPath = PhaGetDlgItemText(hwndDlg, IDC_DBGHELPPATH); - - if (!PhEqualString(dbgHelpPath, PhaGetStringSetting(L"DbgHelpPath"), TRUE)) + if (!PhEqualString(PhaGetDlgItemText(hwndDlg, IDC_DBGHELPSEARCHPATH), PhaGetStringSetting(L"DbgHelpSearchPath"), TRUE)) + { RestartRequired = TRUE; + PhSetStringSetting2(L"DbgHelpSearchPath", &(PhaGetDlgItemText(hwndDlg, IDC_DBGHELPSEARCHPATH)->sr)); + } - PhSetStringSetting2(L"DbgHelpPath", &dbgHelpPath->sr); - PhSetStringSetting2(L"DbgHelpSearchPath", &(PhaGetDlgItemText(hwndDlg, IDC_DBGHELPSEARCHPATH)->sr)); SetSettingForDlgItemCheck(hwndDlg, IDC_UNDECORATESYMBOLS, L"DbgHelpUndecorate"); PhDeleteLayoutManager(&LayoutManager); diff --git a/ProcessHacker/runas.c b/ProcessHacker/runas.c index c99eb008b8c1..74fd7ec72b4c 100644 --- a/ProcessHacker/runas.c +++ b/ProcessHacker/runas.c @@ -192,7 +192,7 @@ VOID PhShowRunAsDialog( DialogBoxParam( PhInstanceHandle, MAKEINTRESOURCE(IDD_RUNAS), - NULL, + !!PhGetIntegerSetting(L"ForceNoParent") ? NULL : ParentWindowHandle, PhpRunAsDlgProc, (LPARAM)ProcessId ); @@ -1213,7 +1213,6 @@ NTSTATUS PhExecuteRunAsCommand( PPH_STRING portName; UNICODE_STRING portNameUs; ULONG attempts; - LARGE_INTEGER interval; if (!(scManagerHandle = OpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE))) return PhGetLastWin32ErrorAsNtStatus(); @@ -1264,8 +1263,7 @@ NTSTATUS PhExecuteRunAsCommand( if (NT_SUCCESS(status)) break; - interval.QuadPart = -50 * PH_TIMEOUT_MS; - NtDelayExecution(FALSE, &interval); + PhDelayExecution(50); } while (--attempts != 0); PhDereferenceObject(portName); diff --git a/ProcessHacker/settings.c b/ProcessHacker/settings.c index eb4d2ab41396..38b80d3fd070 100644 --- a/ProcessHacker/settings.c +++ b/ProcessHacker/settings.c @@ -36,7 +36,6 @@ VOID PhAddDefaultSettings( PhpAddIntegerSetting(L"AllowOnlyOneInstance", L"1"); PhpAddIntegerSetting(L"CloseOnEscape", L"0"); PhpAddIntegerSetting(L"CollapseServicesOnStart", L"0"); - PhpAddStringSetting(L"DbgHelpPath", L"dbghelp.dll"); PhpAddStringSetting(L"DbgHelpSearchPath", L""); PhpAddIntegerSetting(L"DbgHelpUndecorate", L"1"); PhpAddStringSetting(L"DisabledPlugins", L""); From 082904182dadaa811ea70f38fbf8c92fec834d28 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 17 Feb 2018 03:56:23 +1100 Subject: [PATCH 0818/2058] Fix runas dialog default username --- ProcessHacker/runas.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/ProcessHacker/runas.c b/ProcessHacker/runas.c index 74fd7ec72b4c..31b6ed6a3409 100644 --- a/ProcessHacker/runas.c +++ b/ProcessHacker/runas.c @@ -795,12 +795,24 @@ INT_PTR CALLBACK PhpRunAsDlgProc( if (!context->ProcessId) { - SetWindowText( - context->UserComboBoxWindowHandle, - PH_AUTO_T(PH_STRING, PhGetStringSetting(L"RunAsUserName"))->Buffer - ); + PPH_STRING runAsUserName = PhaGetStringSetting(L"RunAsUserName"); + INT runAsUserNameIndex = CB_ERR; // Fire the user name changed event so we can fix the logon type. + if (!PhIsNullOrEmptyString(runAsUserName)) + { + runAsUserNameIndex = ComboBox_FindString( + context->UserComboBoxWindowHandle, + 0, + PhGetString(runAsUserName) + ); + } + + if (runAsUserNameIndex != CB_ERR) + ComboBox_SetCurSel(context->UserComboBoxWindowHandle, runAsUserNameIndex); + else + ComboBox_SetCurSel(context->UserComboBoxWindowHandle, 0); + SendMessage(hwndDlg, WM_COMMAND, MAKEWPARAM(IDC_USERNAME, CBN_EDITCHANGE), 0); } else From 0d4344c3944ee6bf30b52520a6c208b7fcd6250e Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 19 Feb 2018 11:56:53 +1100 Subject: [PATCH 0819/2058] Tidy up main provider initialization --- ProcessHacker/mainwnd.c | 38 +++++++++++--------------------------- 1 file changed, 11 insertions(+), 27 deletions(-) diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index 057818e6457f..d2740e6a341f 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -108,10 +108,6 @@ BOOLEAN PhMainWndInitialization( if (PhGetIntegerSetting(L"FirstRun")) PhSetIntegerSetting(L"FirstRun", FALSE); - // Initialize the main providers. - - PhMwpInitializeProviders(); - // Initialize the window. if ((windowAtom = PhMwpInitializeWindowClass()) == INVALID_ATOM) @@ -184,9 +180,8 @@ BOOLEAN PhMainWndInitialization( PhMwpLoadSettings(); PhLogInitialization(); - // Start the main providers. - PhStartProviderThread(&PhPrimaryProviderThread); - PhStartProviderThread(&PhSecondaryProviderThread); + // Initialize the main providers. + PhMwpInitializeProviders(); // Queue delayed init functions. PhQueueItemWorkQueue(PhGetGlobalWorkQueue(), PhMwpLoadStage1Worker, NULL); @@ -352,22 +347,15 @@ VOID PhMwpInitializeProviders( VOID ) { - ULONG interval; - - interval = PhGetIntegerSetting(L"UpdateInterval"); - - if (interval == 0) + if (PhCsUpdateInterval == 0) { - interval = PH_FLUSH_PROCESS_QUERY_DATA_INTERVAL_LONG_TERM; - PH_SET_INTEGER_CACHED_SETTING(UpdateInterval, interval); + PH_SET_INTEGER_CACHED_SETTING(UpdateInterval, PH_FLUSH_PROCESS_QUERY_DATA_INTERVAL_LONG_TERM); } // See PhMwpLoadStage1Worker for more details. - if (interval > PH_FLUSH_PROCESS_QUERY_DATA_INTERVAL_LONG_TERM) - interval = 1000; - PhInitializeProviderThread(&PhPrimaryProviderThread, interval); - PhInitializeProviderThread(&PhSecondaryProviderThread, interval); + PhInitializeProviderThread(&PhPrimaryProviderThread, PhCsUpdateInterval); + PhInitializeProviderThread(&PhSecondaryProviderThread, PhCsUpdateInterval); PhRegisterProvider(&PhPrimaryProviderThread, PhProcessProviderUpdate, NULL, &PhMwpProcessProviderRegistration); PhRegisterProvider(&PhPrimaryProviderThread, PhServiceProviderUpdate, NULL, &PhMwpServiceProviderRegistration); @@ -375,6 +363,9 @@ VOID PhMwpInitializeProviders( PhSetEnabledProvider(&PhMwpProcessProviderRegistration, TRUE); PhSetEnabledProvider(&PhMwpServiceProviderRegistration, TRUE); + + PhStartProviderThread(&PhPrimaryProviderThread); + PhStartProviderThread(&PhSecondaryProviderThread); } VOID PhMwpApplyUpdateInterval( @@ -489,16 +480,9 @@ NTSTATUS PhMwpLoadStage1Worker( { // If the update interval is too large, the user might have to wait a while before seeing some types of // process-related data. We force an update by boosting the provider shortly after the program - // starts up to either make things appear more quickly or delay the . - - if (PhCsUpdateInterval >= PH_FLUSH_PROCESS_QUERY_DATA_INTERVAL_LONG_TERM) - { - PhDelayExecution(PH_FLUSH_PROCESS_QUERY_DATA_INTERVAL_1); - } - - PhMwpApplyUpdateInterval(PhCsUpdateInterval); + // starts up to either make things appear more quickly. - if (PhCsUpdateInterval >= PH_FLUSH_PROCESS_QUERY_DATA_INTERVAL_LONG_TERM) + if (PhCsUpdateInterval > PH_FLUSH_PROCESS_QUERY_DATA_INTERVAL_LONG_TERM) { PhBoostProvider(&PhMwpProcessProviderRegistration, NULL); PhBoostProvider(&PhMwpServiceProviderRegistration, NULL); From 9bc7f86a6fde4468ef02aefaab88a4d82c29608e Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 19 Feb 2018 12:00:17 +1100 Subject: [PATCH 0820/2058] Update ShowContinueStatus with task dialog support, Fix string format crash --- phlib/util.c | 33 +++++++++------------------------ 1 file changed, 9 insertions(+), 24 deletions(-) diff --git a/phlib/util.c b/phlib/util.c index 4c45de2b944b..474be742bff5 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -418,10 +418,9 @@ INT PhShowMessage2( if (!message) return -1; - config.hwndParent = hWnd; - config.hInstance = PhInstanceHandle; config.dwFlags = TDF_ALLOW_DIALOG_CANCELLATION | (IsWindowVisible(hWnd) ? TDF_POSITION_RELATIVE_TO_WINDOW : 0); config.dwCommonButtons = Buttons; + config.hwndParent = hWnd; config.pszWindowTitle = PhApplicationName; config.pszMainIcon = Icon; config.pszMainInstruction = Title; @@ -540,30 +539,16 @@ BOOLEAN PhShowContinueStatus( statusMessage = PhGetStatusMessage(Status, Win32Result); - if (!statusMessage) - { - if (Message) - { - result = PhShowMessage(hWnd, MB_ICONERROR | MB_OKCANCEL, L"%s.", Message); - } - else - { - result = PhShowMessage(hWnd, MB_ICONERROR | MB_OKCANCEL, L"Unable to perform the operation."); - } - - return result == IDOK; - } - - if (Message) - { - result = PhShowError2(hWnd, Message, statusMessage->Buffer); - } + if (Message && statusMessage) + result = PhShowMessage2(hWnd, TDCBF_CLOSE_BUTTON, TD_ERROR_ICON, Message, L"%s", statusMessage->Buffer); + else if (Message) + result = PhShowMessage2(hWnd, TDCBF_OK_BUTTON | TDCBF_CANCEL_BUTTON, TD_ERROR_ICON, L"", L"%s", Message); + else if (statusMessage) + result = PhShowMessage2(hWnd, TDCBF_OK_BUTTON | TDCBF_CANCEL_BUTTON, TD_ERROR_ICON, L"", L"%s", statusMessage->Buffer); else - { - result = PhShowMessage(hWnd, MB_ICONERROR | MB_OKCANCEL, L"%s", statusMessage->Buffer); - } + result = PhShowMessage2(hWnd, TDCBF_OK_BUTTON | TDCBF_CANCEL_BUTTON, TD_ERROR_ICON, L"Unable to perform the operation.", L"%s", L""); - PhDereferenceObject(statusMessage); + if (statusMessage) PhDereferenceObject(statusMessage); return result == IDOK; } From e9cd2587a4b3a1e08df2c0f1120181524fd6c81b Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 24 Feb 2018 02:42:17 +1100 Subject: [PATCH 0821/2058] Improve network address comparison --- ProcessHacker/netlist.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ProcessHacker/netlist.c b/ProcessHacker/netlist.c index 8845df4fcb40..cf1983b12102 100644 --- a/ProcessHacker/netlist.c +++ b/ProcessHacker/netlist.c @@ -371,7 +371,7 @@ END_SORT_FUNCTION BEGIN_SORT_FUNCTION(LocalAddress) { - sortResult = PhCompareStringZ(networkItem1->LocalAddressString, networkItem2->LocalAddressString, TRUE); + sortResult = PhCompareStringZ(networkItem1->LocalAddressString, networkItem2->LocalAddressString, FALSE); } END_SORT_FUNCTION @@ -389,7 +389,7 @@ END_SORT_FUNCTION BEGIN_SORT_FUNCTION(RemoteAddress) { - sortResult = PhCompareStringZ(networkItem1->RemoteAddressString, networkItem2->RemoteAddressString, TRUE); + sortResult = PhCompareStringZ(networkItem1->RemoteAddressString, networkItem2->RemoteAddressString, FALSE); } END_SORT_FUNCTION From 9be955e7757146599e4e7a72864efe4a5dc76697 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 24 Feb 2018 02:45:37 +1100 Subject: [PATCH 0822/2058] Add permissons button to token tab --- ProcessHacker/ProcessHacker.rc | 1 + ProcessHacker/prpgtok.c | 1 + ProcessHacker/tokprp.c | 49 ++++++++++++++++++---------------- 3 files changed, 28 insertions(+), 23 deletions(-) diff --git a/ProcessHacker/ProcessHacker.rc b/ProcessHacker/ProcessHacker.rc index 78a1bb4076aa..933c45a7bfab 100644 --- a/ProcessHacker/ProcessHacker.rc +++ b/ProcessHacker/ProcessHacker.rc @@ -724,6 +724,7 @@ BEGIN CONTROL "",IDC_GROUPS,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,42,246,194 PUSHBUTTON "Integrity",IDC_INTEGRITY,149,239,50,14 PUSHBUTTON "Advanced",IDC_ADVANCED,203,239,50,14 + PUSHBUTTON "Permissions",IDC_PERMISSIONS,95,239,50,14 END IDD_HIDDENPROCESSES DIALOGEX 0, 0, 337, 221 diff --git a/ProcessHacker/prpgtok.c b/ProcessHacker/prpgtok.c index 5b46413e304a..060811d57673 100644 --- a/ProcessHacker/prpgtok.c +++ b/ProcessHacker/prpgtok.c @@ -76,6 +76,7 @@ INT_PTR CALLBACK PhpProcessTokenHookProc( PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_USERSID), dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_VIRTUALIZED), dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_GROUPS), dialogItem, PH_ANCHOR_ALL); + PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_PERMISSIONS), dialogItem, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_INTEGRITY), dialogItem, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_ADVANCED), dialogItem, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); diff --git a/ProcessHacker/tokprp.c b/ProcessHacker/tokprp.c index 9f8d04df62b7..bd25d2346d1f 100644 --- a/ProcessHacker/tokprp.c +++ b/ProcessHacker/tokprp.c @@ -891,6 +891,31 @@ INT_PTR CALLBACK PhpTokenPageProc( PhCopyListView(tokenPageContext->ListViewHandle); } break; + case IDC_PERMISSIONS: + { + PH_STD_OBJECT_SECURITY stdObjectSecurity; + PPH_ACCESS_ENTRY accessEntries; + ULONG numberOfAccessEntries; + + stdObjectSecurity.OpenObject = tokenPageContext->OpenObject; + stdObjectSecurity.ObjectType = L"Token"; + stdObjectSecurity.Context = tokenPageContext->Context; + + if (PhGetAccessEntries(L"Token", &accessEntries, &numberOfAccessEntries)) + { + PhEditSecurity( + hwndDlg, + L"Token", + PhStdGetObjectSecurity, + PhStdSetObjectSecurity, + &stdObjectSecurity, + accessEntries, + numberOfAccessEntries + ); + PhFree(accessEntries); + } + } + break; case IDC_INTEGRITY: { NTSTATUS status; @@ -1117,12 +1142,9 @@ VOID PhpShowTokenAdvancedProperties( ) { PROPSHEETHEADER propSheetHeader = { sizeof(propSheetHeader) }; - HPROPSHEETPAGE pages[6]; + HPROPSHEETPAGE pages[5]; PROPSHEETPAGE page; ULONG numberOfPages; - PH_STD_OBJECT_SECURITY stdObjectSecurity; - PPH_ACCESS_ENTRY accessEntries; - ULONG numberOfAccessEntries; propSheetHeader.dwFlags = PSH_NOAPPLYNOW | @@ -1193,25 +1215,6 @@ VOID PhpShowTokenAdvancedProperties( pages[numberOfPages++] = CreatePropertySheetPage(&page); } - // Security - - stdObjectSecurity.OpenObject = Context->OpenObject; - stdObjectSecurity.ObjectType = L"Token"; - stdObjectSecurity.Context = Context->Context; - - if (PhGetAccessEntries(L"Token", &accessEntries, &numberOfAccessEntries)) - { - pages[numberOfPages++] = PhCreateSecurityPage( - L"Token", - PhStdGetObjectSecurity, - PhStdSetObjectSecurity, - &stdObjectSecurity, - accessEntries, - numberOfAccessEntries - ); - PhFree(accessEntries); - } - propSheetHeader.nPages = numberOfPages; PhModalPropertySheet(&propSheetHeader); } From 1ee22b9895b6eb8a10ec6e1b45d8317c55a8ab1e Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 24 Feb 2018 12:58:04 +1100 Subject: [PATCH 0823/2058] Add RS4 information classes --- phnt/include/ntexapi.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/phnt/include/ntexapi.h b/phnt/include/ntexapi.h index f39ecbd000a0..47dbf28604e4 100644 --- a/phnt/include/ntexapi.h +++ b/phnt/include/ntexapi.h @@ -1394,7 +1394,13 @@ typedef enum _SYSTEM_INFORMATION_CLASS SystemSecureDumpEncryptionInformation, SystemWriteConstraintInformation, // SYSTEM_WRITE_CONSTRAINT_INFORMATION SystemKernelVaShadowInformation, // SYSTEM_KERNEL_VA_SHADOW_INFORMATION - SystemSpeculationControlInformation = 201, // SYSTEM_SPECULATION_CONTROL_INFORMATION + SystemHypervisorSharedPageInformation, // REDSTONE4 + SystemFirmwareBootPerformanceInformation, + SystemCodeIntegrityVerificationInformation, + SystemFirmwarePartitionInformation, // 200 + SystemSpeculationControlInformation, // SYSTEM_SPECULATION_CONTROL_INFORMATION // (CVE-2017-5715) REDSTONE3 and above. + SystemDmaGuardPolicyInformation, + SystemEnclaveLaunchControlInformation, MaxSystemInfoClass } SYSTEM_INFORMATION_CLASS; From 7ce10e3aab6a00ddff13e250367f772b926275e4 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 24 Feb 2018 12:58:40 +1100 Subject: [PATCH 0824/2058] Fix typo --- phlib/mapexlf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phlib/mapexlf.c b/phlib/mapexlf.c index 796d517f9e82..a4c8f8a36cd5 100644 --- a/phlib/mapexlf.c +++ b/phlib/mapexlf.c @@ -137,7 +137,7 @@ PVOID PhGetMappedWslImageSectionData( { section = IMAGE_ELF64_SECTION_BY_INDEX(sectionHeader, i); - if (strcmp(Name, PTR_ADD_OFFSET(stringTable, section->sh_name)) == 0) + if (PhEqualBytesZ(Name, PTR_ADD_OFFSET(stringTable, section->sh_name), FALSE)) { return PTR_ADD_OFFSET(MappedWslImage->Header, section->sh_offset); } From adef72b934dd7ec49346a719b72fc0689af8823a Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 24 Feb 2018 13:50:53 +1100 Subject: [PATCH 0825/2058] Fix missing macro parameter --- phlib/include/phutil.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/phlib/include/phutil.h b/phlib/include/phutil.h index 8fd56b6ea7bf..6b09b3289c9e 100644 --- a/phlib/include/phutil.h +++ b/phlib/include/phutil.h @@ -238,9 +238,9 @@ PhShowMessage2( ... ); -#define PhShowError2(hWnd, Format, ...) PhShowMessage2(hWnd, TDCBF_CLOSE_BUTTON, TD_ERROR_ICON, Format, __VA_ARGS__) -#define PhShowWarning2(hWnd, Format, ...) PhShowMessage2(hWnd, TDCBF_CLOSE_BUTTON, TD_WARNING_ICON, Format, __VA_ARGS__) -#define PhShowInformation2(hWnd, Format, ...) PhShowMessage2(hWnd, TDCBF_CLOSE_BUTTON, TD_INFORMATION_ICON, Format, __VA_ARGS__) +#define PhShowError2(hWnd, Title, Format, ...) PhShowMessage2(hWnd, TDCBF_CLOSE_BUTTON, TD_ERROR_ICON, Title, Format, __VA_ARGS__) +#define PhShowWarning2(hWnd, Title, Format, ...) PhShowMessage2(hWnd, TDCBF_CLOSE_BUTTON, TD_WARNING_ICON, Title, Format, __VA_ARGS__) +#define PhShowInformation2(hWnd, Title, Format, ...) PhShowMessage2(hWnd, TDCBF_CLOSE_BUTTON, TD_INFORMATION_ICON, Title, Format, __VA_ARGS__) PHLIBAPI PPH_STRING From 05233ba1aec64d28d7518a4d440b439dc5039d15 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 24 Feb 2018 14:03:10 +1100 Subject: [PATCH 0826/2058] Fix error dialog crash --- ProcessHacker/plugin.c | 1 + 1 file changed, 1 insertion(+) diff --git a/ProcessHacker/plugin.c b/ProcessHacker/plugin.c index 8554c80d545d..0c2e4c82d47d 100644 --- a/ProcessHacker/plugin.c +++ b/ProcessHacker/plugin.c @@ -302,6 +302,7 @@ VOID PhLoadPlugins( PhShowError2( NULL, L"Unable to load the following plugin(s)", + L"%s", sb.String->Buffer ); From f5d2df8caeb8e7549e0aa2314db67934a1426104 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 24 Feb 2018 14:13:10 +1100 Subject: [PATCH 0827/2058] Fix PhShowError2 crash --- phlib/util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phlib/util.c b/phlib/util.c index 474be742bff5..af696f8c731e 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -506,7 +506,7 @@ VOID PhShowStatus( if (Message) { - PhShowError2(hWnd, Message, statusMessage->Buffer); + PhShowError2(hWnd, Message, L"%s", statusMessage->Buffer); } else { From 1693d0ffb6588185dc37876b877a02d19ecde974 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 24 Feb 2018 14:49:44 +1100 Subject: [PATCH 0828/2058] Fix crash from commit 4bcaaa0b --- phlib/util.c | 1 - 1 file changed, 1 deletion(-) diff --git a/phlib/util.c b/phlib/util.c index af696f8c731e..c630c86dcf05 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -5006,7 +5006,6 @@ BOOLEAN PhParseCommandLineFuzzy( } } - PhDereferenceObject(filePathSr); PhFree(temp.Buffer); *FileName = *CommandLine; From c2108377e53a89978d89bdaf9298607ed26f61c0 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 24 Feb 2018 14:51:57 +1100 Subject: [PATCH 0829/2058] ExtendedTools: Fix disk tab filenames when running under wow64 --- plugins/ExtendedTools/etwmon.c | 32 ++++++++++++++++++++++++++------ plugins/ExtendedTools/etwmon.h | 6 ++++++ 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/plugins/ExtendedTools/etwmon.c b/plugins/ExtendedTools/etwmon.c index 7c4823ae21ba..c9787ceeb6a2 100644 --- a/plugins/ExtendedTools/etwmon.c +++ b/plugins/ExtendedTools/etwmon.c @@ -289,10 +289,20 @@ VOID NTAPI EtpEtwEventCallback( if (fileEvent.Type != -1) { - FileIo_Name *data = EventRecord->UserData; + if (PhIsExecutingInWow64()) + { + FileIo_Name_Wow64 *dataWow64 = EventRecord->UserData; + + fileEvent.FileObject = (PVOID)dataWow64->FileObject; + PhInitializeStringRef(&fileEvent.FileName, dataWow64->FileName); + } + else + { + FileIo_Name *data = EventRecord->UserData; - fileEvent.FileObject = (PVOID)data->FileObject; - PhInitializeStringRef(&fileEvent.FileName, data->FileName); + fileEvent.FileObject = (PVOID)data->FileObject; + PhInitializeStringRef(&fileEvent.FileName, data->FileName); + } EtDiskProcessFileEvent(&fileEvent); } @@ -521,10 +531,20 @@ VOID NTAPI EtpRundownEtwEventCallback( if (fileEvent.Type != -1) { - FileIo_Name *data = EventRecord->UserData; + if (PhIsExecutingInWow64()) + { + FileIo_Name_Wow64 *dataWow64 = EventRecord->UserData; + + fileEvent.FileObject = (PVOID)dataWow64->FileObject; + PhInitializeStringRef(&fileEvent.FileName, dataWow64->FileName); + } + else + { + FileIo_Name *data = EventRecord->UserData; - fileEvent.FileObject = (PVOID)data->FileObject; - PhInitializeStringRef(&fileEvent.FileName, data->FileName); + fileEvent.FileObject = (PVOID)data->FileObject; + PhInitializeStringRef(&fileEvent.FileName, data->FileName); + } EtDiskProcessFileEvent(&fileEvent); } diff --git a/plugins/ExtendedTools/etwmon.h b/plugins/ExtendedTools/etwmon.h index 85f3e399bb98..68aef52ff55c 100644 --- a/plugins/ExtendedTools/etwmon.h +++ b/plugins/ExtendedTools/etwmon.h @@ -22,6 +22,12 @@ typedef struct WCHAR FileName[1]; } FileIo_Name; +typedef struct +{ + ULONGLONG FileObject; + WCHAR FileName[1]; +} FileIo_Name_Wow64; + typedef struct { ULONG PID; From c85265c1f05bac2a1b516071b90b87003229ac75 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 24 Feb 2018 21:06:20 +1100 Subject: [PATCH 0830/2058] Fix extended statistics version check --- ProcessHacker/prpgstat.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ProcessHacker/prpgstat.c b/ProcessHacker/prpgstat.c index e2cb541e8c58..61c7b7b75a58 100644 --- a/ProcessHacker/prpgstat.c +++ b/ProcessHacker/prpgstat.c @@ -118,7 +118,7 @@ VOID PhpUpdateStatisticsAddListViewGroups( PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_OTHER, PH_PROCESS_STATISTICS_INDEX_GDIHANDLES, L"GDI handles", NULL); PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_OTHER, PH_PROCESS_STATISTICS_INDEX_USERHANDLES, L"USER handles", NULL); - if (WindowsVersion >= WINDOWS_10_RS3 || !PhIsExecutingInWow64()) + if (WindowsVersion >= WINDOWS_10_RS3 && !PhIsExecutingInWow64()) { PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_EXTENSION, PH_PROCESS_STATISTICS_INDEX_CONTEXTSWITCHES, L"ContextSwitches", NULL); PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_EXTENSION, PH_PROCESS_STATISTICS_INDEX_DISKENERGY, L"DiskEnergy", NULL); @@ -238,7 +238,7 @@ VOID PhpUpdateProcessStatistics( PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_USERHANDLES, 1, PhGetStringOrEmpty(userHandles)); } - if (WindowsVersion >= WINDOWS_10_RS3 || !PhIsExecutingInWow64()) + if (WindowsVersion >= WINDOWS_10_RS3 && !PhIsExecutingInWow64()) { PVOID processes; PSYSTEM_PROCESS_INFORMATION processInfo; From 1c4fc097ebde036f7f7ea6aa7e11a7307dcab045 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 26 Feb 2018 15:12:15 +1100 Subject: [PATCH 0831/2058] Fix missing object name for named job objects (Thanks Alex!) --- phlib/hndlinfo.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/phlib/hndlinfo.c b/phlib/hndlinfo.c index 9b1bafe98f92..a6d7bc20cfae 100644 --- a/phlib/hndlinfo.c +++ b/phlib/hndlinfo.c @@ -699,6 +699,10 @@ NTSTATUS PhpGetBestObjectName( if (!NT_SUCCESS(status)) goto CleanupExit; + // dmex: Don't do anything when we already have a valid job object name. + if (!PhIsNullOrEmptyString(ObjectName)) + goto CleanupExit; + if (handleGetClientIdName && NT_SUCCESS(PhGetJobProcessIdList(dupHandle, &processIdList))) { PH_STRING_BUILDER sb; From 035a10e9307bed0ecfe830c091cb58da57f3736b Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 26 Feb 2018 17:09:02 +1100 Subject: [PATCH 0832/2058] Fix handle leak --- phlib/hndlinfo.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/phlib/hndlinfo.c b/phlib/hndlinfo.c index a6d7bc20cfae..ffc797c112bf 100644 --- a/phlib/hndlinfo.c +++ b/phlib/hndlinfo.c @@ -686,6 +686,10 @@ NTSTATUS PhpGetBestObjectName( HANDLE dupHandle; PJOBOBJECT_BASIC_PROCESS_ID_LIST processIdList; + // dmex: Don't do anything when we already have a valid job object name. + if (!PhIsNullOrEmptyString(ObjectName)) + goto CleanupExit; + status = NtDuplicateObject( ProcessHandle, Handle, @@ -699,10 +703,6 @@ NTSTATUS PhpGetBestObjectName( if (!NT_SUCCESS(status)) goto CleanupExit; - // dmex: Don't do anything when we already have a valid job object name. - if (!PhIsNullOrEmptyString(ObjectName)) - goto CleanupExit; - if (handleGetClientIdName && NT_SUCCESS(PhGetJobProcessIdList(dupHandle, &processIdList))) { PH_STRING_BUILDER sb; From 66e43f03d0608df70fdac5104a1b41ff1c8bbb04 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 26 Feb 2018 18:50:39 +1100 Subject: [PATCH 0833/2058] Add some wrapper functions --- phlib/include/phutil.h | 35 ++- phlib/util.c | 536 +++++++++++++++++++++++++++++++++-------- 2 files changed, 460 insertions(+), 111 deletions(-) diff --git a/phlib/include/phutil.h b/phlib/include/phutil.h index 6b09b3289c9e..6296d8c2b814 100644 --- a/phlib/include/phutil.h +++ b/phlib/include/phutil.h @@ -597,20 +597,11 @@ PhGetSystemRoot( _Out_ PPH_STRINGREF SystemRoot ); -PHLIBAPI -PLDR_DATA_TABLE_ENTRY -NTAPI -PhFindLoaderEntry( - _In_opt_ PVOID DllBase, - _In_opt_ PPH_STRINGREF FullDllName, - _In_opt_ PPH_STRINGREF BaseDllName - ); - PHLIBAPI PPH_STRING NTAPI PhGetDllFileName( - _In_ PVOID DllHandle, + _In_ PVOID DllBase, _Out_opt_ PULONG IndexOfFileName ); @@ -1145,6 +1136,30 @@ PhExtractIcon( _In_ HICON *IconSmall ); +PHLIBAPI +PLDR_DATA_TABLE_ENTRY +NTAPI +PhFindLoaderEntry( + _In_opt_ PVOID DllBase, + _In_opt_ PPH_STRINGREF FullDllName, + _In_opt_ PPH_STRINGREF BaseDllName + ); + +PHLIBAPI +PVOID +NTAPI +PhGetLoaderEntryDllBase( + _In_opt_ PWSTR DllName + ); + +PHLIBAPI +NTSTATUS +NTAPI +PhLoadPluginImage( + _In_ PPH_STRING FileName, + _Out_opt_ PVOID *BaseAddress + ); + #ifdef __cplusplus } #endif diff --git a/phlib/util.c b/phlib/util.c index c630c86dcf05..71d7ca6b29da 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -2052,106 +2052,6 @@ VOID PhGetSystemRoot( systemRoot.Buffer = localSystemRoot.Buffer; } -/** - * Locates a loader entry in the current process. - * - * \param DllBase The base address of the DLL. Specify NULL if this is not a search criteria. - * \param FullDllName The full name of the DLL. Specify NULL if this is not a search criteria. - * \param BaseDllName The base name of the DLL. Specify NULL if this is not a search criteria. - * - * \remarks This function must be called with the loader lock acquired. The first entry matching all - * of the specified values is returned. - */ -PLDR_DATA_TABLE_ENTRY PhFindLoaderEntry( - _In_opt_ PVOID DllBase, - _In_opt_ PPH_STRINGREF FullDllName, - _In_opt_ PPH_STRINGREF BaseDllName - ) -{ - PLDR_DATA_TABLE_ENTRY result = NULL; - PLDR_DATA_TABLE_ENTRY entry; - PH_STRINGREF fullDllName; - PH_STRINGREF baseDllName; - PLIST_ENTRY listHead; - PLIST_ENTRY listEntry; - - listHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList; - listEntry = listHead->Flink; - - while (listEntry != listHead) - { - entry = CONTAINING_RECORD(listEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks); - PhUnicodeStringToStringRef(&entry->FullDllName, &fullDllName); - PhUnicodeStringToStringRef(&entry->BaseDllName, &baseDllName); - - if ( - (!DllBase || entry->DllBase == DllBase) && - (!FullDllName || PhEqualStringRef(&fullDllName, FullDllName, TRUE)) && - (!BaseDllName || PhEqualStringRef(&baseDllName, BaseDllName, TRUE)) - ) - { - result = entry; - break; - } - - listEntry = listEntry->Flink; - } - - return result; -} - -/** - * Retrieves the file name of a DLL loaded by the current process. - * - * \param DllHandle The base address of the DLL. - * \param IndexOfFileName A variable which receives the index of the base name of the DLL in the - * returned string. - * - * \return The file name of the DLL, or NULL if the DLL could not be found. - */ -PPH_STRING PhGetDllFileName( - _In_ PVOID DllHandle, - _Out_opt_ PULONG IndexOfFileName - ) -{ - PLDR_DATA_TABLE_ENTRY entry; - PPH_STRING fileName; - PPH_STRING newFileName; - ULONG_PTR indexOfFileName; - - RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock); - - entry = PhFindLoaderEntry(DllHandle, NULL, NULL); - - if (entry) - fileName = PhCreateStringFromUnicodeString(&entry->FullDllName); - else - fileName = NULL; - - RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock); - - if (!fileName) - return NULL; - - newFileName = PhGetFileName(fileName); - PhDereferenceObject(fileName); - fileName = newFileName; - - if (IndexOfFileName) - { - indexOfFileName = PhFindLastCharInString(fileName, 0, '\\'); - - if (indexOfFileName != -1) - indexOfFileName++; - else - indexOfFileName = 0; - - *IndexOfFileName = (ULONG)indexOfFileName; - } - - return fileName; -} - /** * Retrieves the file name of the current process image. */ @@ -5374,4 +5274,438 @@ BOOLEAN PhExtractIcon( return FALSE; return PrivateExtractIconExW(FileName, 0, IconLarge, IconSmall, 1) > 0; -} \ No newline at end of file +} + +/** + * Locates a loader entry in the current process. + * + * \param DllBase The base address of the DLL. Specify NULL if this is not a search criteria. + * \param FullDllName The full name of the DLL. Specify NULL if this is not a search criteria. + * \param BaseDllName The base name of the DLL. Specify NULL if this is not a search criteria. + * + * \remarks This function must be called with the loader lock acquired. The first entry matching all + * of the specified values is returned. + */ +PLDR_DATA_TABLE_ENTRY PhFindLoaderEntry( + _In_opt_ PVOID DllBase, + _In_opt_ PPH_STRINGREF FullDllName, + _In_opt_ PPH_STRINGREF BaseDllName + ) +{ + PLDR_DATA_TABLE_ENTRY result = NULL; + PLDR_DATA_TABLE_ENTRY entry; + PH_STRINGREF fullDllName; + PH_STRINGREF baseDllName; + PLIST_ENTRY listHead; + PLIST_ENTRY listEntry; + + listHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList; + listEntry = listHead->Flink; + + while (listEntry != listHead) + { + entry = CONTAINING_RECORD(listEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks); + PhUnicodeStringToStringRef(&entry->FullDllName, &fullDllName); + PhUnicodeStringToStringRef(&entry->BaseDllName, &baseDllName); + + if ( + (!DllBase || entry->DllBase == DllBase) && + (!FullDllName || PhEqualStringRef(&fullDllName, FullDllName, TRUE)) && + (!BaseDllName || PhEqualStringRef(&baseDllName, BaseDllName, TRUE)) + ) + { + result = entry; + break; + } + + listEntry = listEntry->Flink; + } + + return result; +} + +/** + * Retrieves the file name of a DLL loaded by the current process. + * + * \param DllBase The base address of the DLL. + * \param IndexOfFileName A variable which receives the index of the base name of the DLL in the + * returned string. + * + * \return The file name of the DLL, or NULL if the DLL could not be found. + */ +PPH_STRING PhGetDllFileName( + _In_ PVOID DllBase, + _Out_opt_ PULONG IndexOfFileName + ) +{ + PLDR_DATA_TABLE_ENTRY entry; + PPH_STRING fileName; + PPH_STRING newFileName; + ULONG_PTR indexOfFileName; + + RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock); + + entry = PhFindLoaderEntry(DllBase, NULL, NULL); + + if (entry) + fileName = PhCreateStringFromUnicodeString(&entry->FullDllName); + else + fileName = NULL; + + RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock); + + if (!fileName) + return NULL; + + newFileName = PhGetFileName(fileName); + PhDereferenceObject(fileName); + fileName = newFileName; + + if (IndexOfFileName) + { + indexOfFileName = PhFindLastCharInString(fileName, 0, '\\'); + + if (indexOfFileName != -1) + indexOfFileName++; + else + indexOfFileName = 0; + + *IndexOfFileName = (ULONG)indexOfFileName; + } + + return fileName; +} + +PVOID PhGetLoaderEntryDllBase( + _In_opt_ PWSTR BaseDllName + ) +{ + PH_STRINGREF entryNameSr; + PLDR_DATA_TABLE_ENTRY ldrEntry; + + PhInitializeStringRefLongHint(&entryNameSr, BaseDllName); + + RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock); + ldrEntry = PhFindLoaderEntry(NULL, NULL, &entryNameSr); + RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock); + + if (ldrEntry) + return ldrEntry->DllBase; + else + return NULL; +} + +NTSTATUS PhGetLoaderEntryImageNtHeaders( + _In_ PVOID BaseAddress, + _Out_ PIMAGE_NT_HEADERS *ImageNtHeaders + ) +{ + PIMAGE_NT_HEADERS ntHeader; + PIMAGE_DOS_HEADER dosHeader; + ULONG ntHeadersOffset; + + dosHeader = PTR_ADD_OFFSET(BaseAddress, 0); + + if (dosHeader->e_magic != IMAGE_DOS_SIGNATURE) + return STATUS_IMAGE_SUBSYSTEM_NOT_PRESENT; + + ntHeadersOffset = (ULONG)dosHeader->e_lfanew; + + if (ntHeadersOffset == 0 || ntHeadersOffset >= 0x10000000) + return STATUS_IMAGE_SUBSYSTEM_NOT_PRESENT; + + ntHeader = PTR_ADD_OFFSET(BaseAddress, ntHeadersOffset); + + if (ntHeader->Signature != IMAGE_NT_SIGNATURE) + return STATUS_IMAGE_SUBSYSTEM_NOT_PRESENT; + + *ImageNtHeaders = ntHeader; + return STATUS_SUCCESS; +} + +NTSTATUS PhGetLoaderEntryImageEntryPoint( + _In_ PVOID BaseAddress, + _In_ PIMAGE_NT_HEADERS ImageNtHeader, + _Out_ PLDR_INIT_ROUTINE *ImageEntryPoint + ) +{ + if (ImageNtHeader->OptionalHeader.AddressOfEntryPoint == 0) + return STATUS_FAIL_CHECK; // STATUS_ENTRYPOINT_NOT_FOUND + + *ImageEntryPoint = PTR_ADD_OFFSET(BaseAddress, ImageNtHeader->OptionalHeader.AddressOfEntryPoint); + return STATUS_SUCCESS; +} + +NTSTATUS PhGetLoaderEntryImageDirectory( + _In_ PVOID BaseAddress, + _In_ PIMAGE_NT_HEADERS ImageNtHeader, + _In_ ULONG ImageDirectoryIndex, + _Out_ PVOID *ImageDirectoryEntry, + _Out_opt_ SIZE_T *ImageDirectoryLength + ) +{ + IMAGE_DATA_DIRECTORY directory; + + directory = ImageNtHeader->OptionalHeader.DataDirectory[ImageDirectoryIndex]; + + if (directory.VirtualAddress == 0 || directory.Size == 0) + return STATUS_INVALID_FILE_FOR_SECTION; + + *ImageDirectoryEntry = PTR_ADD_OFFSET(BaseAddress, directory.VirtualAddress); + if (ImageDirectoryLength) *ImageDirectoryLength = directory.Size; + + return STATUS_SUCCESS; +} + +NTSTATUS PhGetLoaderEntryImageSection( + _In_ PVOID BaseAddress, + _In_ PIMAGE_NT_HEADERS ImageNtHeader, + _In_ PIMAGE_IMPORT_DESCRIPTOR ImageDirectory, + _Out_ PIMAGE_SECTION_HEADER *ImageSection, + _Out_ SIZE_T *ImageSectionLength + ) +{ + SIZE_T directorySectionLength = 0; + PIMAGE_SECTION_HEADER sectionHeader; + PIMAGE_SECTION_HEADER directorySectionHeader = NULL; + ULONG i; + + for (i = 0; i < ImageNtHeader->FileHeader.NumberOfSections; i++) + { + sectionHeader = PTR_ADD_OFFSET(IMAGE_FIRST_SECTION(ImageNtHeader), sizeof(IMAGE_SECTION_HEADER) * i); + + if ( + ((ULONG_PTR)ImageDirectory >= (ULONG_PTR)PTR_ADD_OFFSET(BaseAddress, sectionHeader->VirtualAddress)) && + ((ULONG_PTR)ImageDirectory < (ULONG_PTR)PTR_ADD_OFFSET(PTR_ADD_OFFSET(BaseAddress, sectionHeader->VirtualAddress), sectionHeader->SizeOfRawData)) + ) + { + directorySectionLength = sectionHeader->Misc.VirtualSize; + directorySectionHeader = PTR_ADD_OFFSET(BaseAddress, sectionHeader->VirtualAddress); + break; + } + } + + if (directorySectionHeader && directorySectionLength) + { + *ImageSection = directorySectionHeader; + *ImageSectionLength = directorySectionLength; + return STATUS_SUCCESS; + } + + return STATUS_SECTION_NOT_IMAGE; +} + +static NTSTATUS PhpFixupLoaderEntryImageImports( + _In_ PVOID BaseAddress, + _In_ PIMAGE_NT_HEADERS ImageNtHeader + ) +{ + NTSTATUS status; + SIZE_T importDirectorySize; + ULONG importDirectoryLength; + PIMAGE_IMPORT_DESCRIPTOR importDirectory; + PIMAGE_SECTION_HEADER importDirectorySection; + + status = PhGetLoaderEntryImageDirectory( + BaseAddress, + ImageNtHeader, + IMAGE_DIRECTORY_ENTRY_IMPORT, + &importDirectory, + NULL + ); + + if (!NT_SUCCESS(status)) + goto CleanupExit; + + status = PhGetLoaderEntryImageSection( + BaseAddress, + ImageNtHeader, + importDirectory, + &importDirectorySection, + &importDirectorySize + ); + + if (!NT_SUCCESS(status)) + goto CleanupExit; + + status = NtProtectVirtualMemory( + NtCurrentProcess(), + &importDirectorySection, + &importDirectorySize, + PAGE_READWRITE, + &importDirectoryLength + ); + + if (!NT_SUCCESS(status)) + goto CleanupExit; + + for (importDirectory = importDirectory; importDirectory->Name; importDirectory++) + { + PSTR importName; + PIMAGE_THUNK_DATA importThunk; + PIMAGE_THUNK_DATA originalThunk; + PVOID importBaseAddress; + + importName = PTR_ADD_OFFSET(BaseAddress, importDirectory->Name); + importThunk = PTR_ADD_OFFSET(BaseAddress, importDirectory->FirstThunk); + originalThunk = PTR_ADD_OFFSET(BaseAddress, importDirectory->OriginalFirstThunk ? importDirectory->OriginalFirstThunk : importDirectory->FirstThunk); + + if (PhEqualBytesZ(importName, "ProcessHacker.exe", FALSE)) + { + importBaseAddress = NtCurrentPeb()->ImageBaseAddress; + } + else + { + PPH_STRING importNameSr; + UNICODE_STRING dllNameUs; + + importNameSr = PhZeroExtendToUtf16(importName); + PhStringRefToUnicodeString(&importNameSr->sr, &dllNameUs); + + if (!NT_SUCCESS(status = LdrGetDllHandle(NULL, NULL, &dllNameUs, &importBaseAddress))) + { + if (importBaseAddress = LoadLibrary(importNameSr->Buffer)) + status = STATUS_SUCCESS; + else + status = PhGetLastWin32ErrorAsNtStatus(); + } + + PhDereferenceObject(importNameSr); + } + + if (!NT_SUCCESS(status)) + goto CleanupExit; + + for ( + originalThunk = originalThunk, importThunk = importThunk; + originalThunk->u1.AddressOfData; + originalThunk++, importThunk++ + ) + { + if (IMAGE_SNAP_BY_ORDINAL(originalThunk->u1.Ordinal)) + { + USHORT procedureOrdinal; + PVOID procedureAddress; + + procedureOrdinal = IMAGE_ORDINAL(originalThunk->u1.Ordinal); + procedureAddress = PhGetProcedureAddress(importBaseAddress, NULL, procedureOrdinal); + + if (!procedureAddress) + { + status = STATUS_ORDINAL_NOT_FOUND; + PhShowError(NULL, L"Error locating ordinal: %u\r\nModule: %hs", procedureOrdinal, importName); + goto CleanupExit; + } + + importThunk->u1.Function = (ULONG_PTR)procedureAddress; + } + else + { + PIMAGE_IMPORT_BY_NAME importByName; + PVOID procedureAddress; + + importByName = PTR_ADD_OFFSET(BaseAddress, originalThunk->u1.AddressOfData); + procedureAddress = PhGetProcedureAddress(importBaseAddress, importByName->Name, importByName->Hint); + + if (!procedureAddress) + { + status = STATUS_PROCEDURE_NOT_FOUND; + PhShowError(NULL, L"Error locating procedure: %hs\r\nModule: %hs", importByName->Name, importName); + goto CleanupExit; + } + + importThunk->u1.Function = (ULONG_PTR)procedureAddress; + } + } + } + + status = NtProtectVirtualMemory( + NtCurrentProcess(), + &importDirectorySection, + &importDirectorySize, + importDirectoryLength, + &importDirectoryLength + ); + + if (!NT_SUCCESS(status)) + goto CleanupExit; + +CleanupExit: + return status; +} + +// dmex: This function and the other LoaderEntryImage functions don't belong in this file +// and should be moved into mapimg.c at some stage. +// +// We use this function to load plugins since we can 'fixup' the import table at runtime which is required when +// users have renamed the main executable to avoid malware, spyware and other software that targets Process Hacker. +// This function can only fixup images that have static imports from processhacker.exe, +// plugins that use LoadLibrary/GetProcAddress will continue to fail when the main executable is renamed. +// Note: This functionality is a WIP and not be used for anything other than plugins. +NTSTATUS PhLoadPluginImage( + _In_ PPH_STRING FileName, + _Out_opt_ PVOID *BaseAddress + ) +{ + NTSTATUS status; + ULONG imageType; + PVOID imageBaseAddress; + PIMAGE_NT_HEADERS imageHeaders; + PLDR_INIT_ROUTINE imageEntryRoutine; + UNICODE_STRING fileNameUs; + + imageType = IMAGE_FILE_EXECUTABLE_IMAGE; + PhStringRefToUnicodeString(&FileName->sr, &fileNameUs); + + status = LdrLoadDll( + NULL, + &imageType, + &fileNameUs, + &imageBaseAddress + ); + + if (!NT_SUCCESS(status)) + goto CleanupExit; + + status = PhGetLoaderEntryImageNtHeaders( + imageBaseAddress, + &imageHeaders + ); + + if (!NT_SUCCESS(status)) + goto CleanupExit; + + status = PhpFixupLoaderEntryImageImports( + imageBaseAddress, + imageHeaders + ); + + if (!NT_SUCCESS(status)) + goto CleanupExit; + + status = PhGetLoaderEntryImageEntryPoint( + imageBaseAddress, + imageHeaders, + &imageEntryRoutine + ); + + if (!NT_SUCCESS(status)) + goto CleanupExit; + + if (!imageEntryRoutine(imageBaseAddress, DLL_PROCESS_ATTACH, NULL)) + status = STATUS_DLL_INIT_FAILED; + +CleanupExit: + + if (NT_SUCCESS(status)) + { + if (BaseAddress) + *BaseAddress = imageBaseAddress; + } + else + { + LdrUnloadDll(imageBaseAddress); + } + + return status; +} From 9d8dc67667eb2674cb80030e6c50ed37ba9b7c1d Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 26 Feb 2018 19:02:03 +1100 Subject: [PATCH 0834/2058] Add UNICODE_NULL macro --- ProcessHacker/mainwnd.c | 6 +++--- ProcessHacker/runas.c | 35 ++++++++++++++++++----------------- ProcessHacker/sessprp.c | 2 +- phlib/basesup.c | 8 ++++---- phlib/format.c | 2 +- phlib/util.c | 28 ++++++++++++++-------------- 6 files changed, 41 insertions(+), 40 deletions(-) diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index d2740e6a341f..d03d2cc0718b 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -3310,11 +3310,11 @@ VOID PhMwpUpdateUsersMenu( &returnLength )) { - winStationInfo.Domain[0] = 0; - winStationInfo.UserName[0] = 0; + winStationInfo.Domain[0] = UNICODE_NULL; + winStationInfo.UserName[0] = UNICODE_NULL; } - if (winStationInfo.Domain[0] == 0 || winStationInfo.UserName[0] == 0) + if (winStationInfo.Domain[0] == UNICODE_NULL || winStationInfo.UserName[0] == UNICODE_NULL) { // Probably the Services or RDP-Tcp session. continue; diff --git a/ProcessHacker/runas.c b/ProcessHacker/runas.c index 31b6ed6a3409..15ed2f65e5cb 100644 --- a/ProcessHacker/runas.c +++ b/ProcessHacker/runas.c @@ -564,13 +564,13 @@ static VOID PhpAddSessionsToComboBox( &returnLength )) { - winStationInfo.Domain[0] = 0; - winStationInfo.UserName[0] = 0; + winStationInfo.Domain[0] = UNICODE_NULL; + winStationInfo.UserName[0] = UNICODE_NULL; } if ( - winStationInfo.UserName[0] != 0 && - sessions[i].WinStationName[0] != 0 + winStationInfo.UserName[0] != UNICODE_NULL && + sessions[i].WinStationName[0] != UNICODE_NULL ) { menuString = PhaFormatString(L"%u: %s (%s\\%s)", @@ -580,7 +580,7 @@ static VOID PhpAddSessionsToComboBox( winStationInfo.UserName ); } - else if (winStationInfo.UserName[0] != 0) + else if (winStationInfo.UserName[0] != UNICODE_NULL) { menuString = PhaFormatString(L"%u: %s\\%s", sessions[i].SessionId, @@ -588,7 +588,7 @@ static VOID PhpAddSessionsToComboBox( winStationInfo.UserName ); } - else if (sessions[i].WinStationName[0] != 0) + else if (sessions[i].WinStationName[0] != UNICODE_NULL) { menuString = PhaFormatString(L"%u: %s", sessions[i].SessionId, @@ -600,18 +600,19 @@ static VOID PhpAddSessionsToComboBox( menuString = PhaFormatString(L"%u", sessions[i].SessionId); } + { + PPH_RUNAS_SESSION_ITEM entry; - PPH_RUNAS_SESSION_ITEM entry; - - entry = PhAllocate(sizeof(PH_RUNAS_SESSION_ITEM)); - entry->SessionId = sessions[i].SessionId; - entry->SessionName = menuString; + entry = PhAllocate(sizeof(PH_RUNAS_SESSION_ITEM)); + entry->SessionId = sessions[i].SessionId; + entry->SessionName = menuString; - INT itemIndex = ComboBox_AddString(ComboBoxHandle, menuString->Buffer); + INT itemIndex = ComboBox_AddString(ComboBoxHandle, menuString->Buffer); - if (itemIndex != CB_ERR) - { - ComboBox_SetItemData(ComboBoxHandle, itemIndex, entry); + if (itemIndex != CB_ERR) + { + ComboBox_SetItemData(ComboBoxHandle, itemIndex, entry); + } } } @@ -631,7 +632,7 @@ static BOOL CALLBACK EnumDesktopsCallback( context->CurrentWinStaName->Buffer, L"\\", DesktopName - )); + )); return TRUE; } @@ -1366,7 +1367,7 @@ NTSTATUS PhExecuteRunAsCommand3( parameters.CreateSuspendedProcess = CreateSuspendedProcess; // Try to use an existing instance of the service if possible. - if (RunAsOldServiceName[0] != 0) + if (RunAsOldServiceName[0] != UNICODE_NULL) { PhAcquireQueuedLockExclusive(&RunAsOldServiceLock); diff --git a/ProcessHacker/sessprp.c b/ProcessHacker/sessprp.c index 91e06a80cdee..ffdfb14f1a4c 100644 --- a/ProcessHacker/sessprp.c +++ b/ProcessHacker/sessprp.c @@ -170,7 +170,7 @@ INT_PTR CALLBACK PhpSessionPropertiesDlgProc( PhDereferenceObject(time); } - if (haveClientInfo && clientInfo.ClientName[0] != 0) + if (haveClientInfo && clientInfo.ClientName[0] != UNICODE_NULL) { WCHAR addressString[65]; diff --git a/phlib/basesup.c b/phlib/basesup.c index 35364e49c0af..c14f780e7291 100644 --- a/phlib/basesup.c +++ b/phlib/basesup.c @@ -2146,7 +2146,7 @@ PPH_STRING PhCreateStringEx( assert(!(Length & 1)); string->Length = Length; string->Buffer = string->Data; - *(PWCHAR)PTR_ADD_OFFSET(string->Buffer, Length) = 0; + *(PWCHAR)PTR_ADD_OFFSET(string->Buffer, Length) = UNICODE_NULL; if (Buffer) { @@ -2433,7 +2433,7 @@ PPH_BYTES PhCreateBytesEx( bytes->Length = Length; bytes->Buffer = bytes->Data; - bytes->Buffer[Length] = 0; + bytes->Buffer[Length] = ANSI_NULL; if (Buffer) { @@ -3474,7 +3474,7 @@ FORCEINLINE VOID PhpWriteNullTerminatorStringBuilder( ) { assert(!(StringBuilder->String->Length & 1)); - *(PWCHAR)PTR_ADD_OFFSET(StringBuilder->String->Buffer, StringBuilder->String->Length) = 0; + *(PWCHAR)PTR_ADD_OFFSET(StringBuilder->String->Buffer, StringBuilder->String->Length) = UNICODE_NULL; } /** @@ -3781,7 +3781,7 @@ VOID PhInitializeBytesBuilder( BytesBuilder->AllocatedLength = InitialCapacity; BytesBuilder->Bytes = PhCreateBytesEx(NULL, BytesBuilder->AllocatedLength); BytesBuilder->Bytes->Length = 0; - BytesBuilder->Bytes->Buffer[0] = 0; + BytesBuilder->Bytes->Buffer[0] = ANSI_NULL; } /** diff --git a/phlib/format.c b/phlib/format.c index b45fd38439c4..bd273a8a1981 100644 --- a/phlib/format.c +++ b/phlib/format.c @@ -202,7 +202,7 @@ PPH_STRING PhFormat( string->Length = usedLength; // Null-terminate the string. - string->Buffer[usedLength / sizeof(WCHAR)] = 0; + string->Buffer[usedLength / sizeof(WCHAR)] = UNICODE_NULL; return string; } diff --git a/phlib/util.c b/phlib/util.c index 71d7ca6b29da..2f96846f4347 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -827,7 +827,7 @@ VOID PhGenerateRandomAlphaString( Buffer[i] = 'A' + (RtlRandomEx(&seed) % 26); } - Buffer[Count - 1] = 0; + Buffer[Count - 1] = UNICODE_NULL; } /** @@ -1106,7 +1106,7 @@ LONG PhCompareUnicodeStringZIgnoreMenuPrefix( t = *A; - if (t == 0) + if (t == UNICODE_NULL) { if (MatchIfPrefix) return 0; @@ -1134,7 +1134,7 @@ LONG PhCompareUnicodeStringZIgnoreMenuPrefix( t = *A; - if (t == 0) + if (t == UNICODE_NULL) { if (MatchIfPrefix) return 0; @@ -1169,7 +1169,7 @@ PPH_STRING PhFormatDate( ULONG bufferSize; bufferSize = GetDateFormat(LOCALE_USER_DEFAULT, 0, Date, Format, NULL, 0); - string = PhCreateStringEx(NULL, bufferSize * 2); + string = PhCreateStringEx(NULL, bufferSize * sizeof(WCHAR)); if (!GetDateFormat(LOCALE_USER_DEFAULT, 0, Date, Format, string->Buffer, bufferSize)) { @@ -1198,7 +1198,7 @@ PPH_STRING PhFormatTime( ULONG bufferSize; bufferSize = GetTimeFormat(LOCALE_USER_DEFAULT, 0, Time, Format, NULL, 0); - string = PhCreateStringEx(NULL, bufferSize * 2); + string = PhCreateStringEx(NULL, bufferSize * sizeof(WCHAR)); if (!GetTimeFormat(LOCALE_USER_DEFAULT, 0, Time, Format, string->Buffer, bufferSize)) { @@ -1230,7 +1230,7 @@ PPH_STRING PhFormatDateTime( timeBufferSize = GetTimeFormat(LOCALE_USER_DEFAULT, 0, DateTime, NULL, NULL, 0); dateBufferSize = GetDateFormat(LOCALE_USER_DEFAULT, 0, DateTime, NULL, NULL, 0); - string = PhCreateStringEx(NULL, (timeBufferSize + 1 + dateBufferSize) * 2); + string = PhCreateStringEx(NULL, (timeBufferSize + 1 + dateBufferSize) * sizeof(WCHAR)); if (!GetTimeFormat(LOCALE_USER_DEFAULT, 0, DateTime, NULL, &string->Buffer[0], timeBufferSize)) { @@ -1426,13 +1426,13 @@ PPH_STRING PhFormatDecimal( if (!GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, decimalSeparator, 4)) { decimalSeparator[0] = '.'; - decimalSeparator[1] = 0; + decimalSeparator[1] = UNICODE_NULL; } if (!GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, thousandSeparator, 4)) { thousandSeparator[0] = ','; - thousandSeparator[1] = 0; + thousandSeparator[1] = UNICODE_NULL; } PhEndInitOnce(&initOnce); @@ -1446,7 +1446,7 @@ PPH_STRING PhFormatDecimal( format.NegativeOrder = 1; bufferSize = GetNumberFormat(LOCALE_USER_DEFAULT, 0, Value, &format, NULL, 0); - string = PhCreateStringEx(NULL, bufferSize * 2); + string = PhCreateStringEx(NULL, bufferSize * sizeof(WCHAR)); if (!GetNumberFormat(LOCALE_USER_DEFAULT, 0, Value, &format, string->Buffer, bufferSize)) { @@ -1944,7 +1944,7 @@ PPH_STRING PhExpandEnvironmentStrings( } string->Length = outputString.Length; - string->Buffer[string->Length / 2] = 0; // make sure there is a null terminator + string->Buffer[string->Length / 2] = UNICODE_NULL; // make sure there is a null terminator return string; } @@ -2119,7 +2119,7 @@ PPH_STRING PhGetKnownLocation( SIZE_T appendPathLength; if (AppendPath) - appendPathLength = PhCountStringZ(AppendPath) * 2; + appendPathLength = PhCountStringZ(AppendPath) * sizeof(WCHAR); else appendPathLength = 0; @@ -2137,7 +2137,7 @@ PPH_STRING PhGetKnownLocation( if (AppendPath) { - memcpy(&path->Buffer[path->Length / 2], AppendPath, appendPathLength + 2); // +2 for null terminator + memcpy(&path->Buffer[path->Length / sizeof(WCHAR)], AppendPath, appendPathLength + 2); // +2 for null terminator path->Length += appendPathLength; } @@ -3611,7 +3611,7 @@ OPENFILENAME *PhpCreateOpenFileName( ofn->Flags = OFN_ENABLEHOOK | OFN_EXPLORER; ofn->lpfnHook = PhpOpenFileNameHookProc; - ofn->lpstrFile[0] = 0; + ofn->lpstrFile[0] = UNICODE_NULL; return ofn; } @@ -4863,7 +4863,7 @@ BOOLEAN PhParseCommandLineFuzzy( temp.Buffer = PhAllocate(commandLine.Length + sizeof(WCHAR)); memcpy(temp.Buffer, commandLine.Buffer, commandLine.Length); - temp.Buffer[commandLine.Length / sizeof(WCHAR)] = 0; + temp.Buffer[commandLine.Length / sizeof(WCHAR)] = UNICODE_NULL; temp.Length = commandLine.Length; remainingPart = temp; From 4824a014a70d6803b6d26a3bb3c0bcc31502f9dc Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 26 Feb 2018 19:18:53 +1100 Subject: [PATCH 0835/2058] Move symbol settings to general options tab --- ProcessHacker/ProcessHacker.rc | 55 ++++++++++++------------- ProcessHacker/options.c | 74 ++++++++-------------------------- ProcessHacker/resource.h | 3 +- 3 files changed, 43 insertions(+), 89 deletions(-) diff --git a/ProcessHacker/ProcessHacker.rc b/ProcessHacker/ProcessHacker.rc index 933c45a7bfab..f595f2b01605 100644 --- a/ProcessHacker/ProcessHacker.rc +++ b/ProcessHacker/ProcessHacker.rc @@ -1131,18 +1131,20 @@ BEGIN EDITTEXT IDC_SEARCHENGINE,61,7,247,12,ES_AUTOHSCROLL LTEXT "PE viewer:",IDC_STATIC,7,23,35,8 EDITTEXT IDC_PEVIEWER,61,22,247,12,ES_AUTOHSCROLL - LTEXT "Max. size unit:",IDC_STATIC,7,38,49,8 - COMBOBOX IDC_MAXSIZEUNIT,61,37,39,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LTEXT "Icon processes:",IDC_STATIC,7,55,52,8 - EDITTEXT IDC_ICONPROCESSES,61,53,40,12,ES_AUTOHSCROLL | ES_NUMBER - PUSHBUTTON "Font...",IDC_FONT,179,53,49,14 - PUSHBUTTON "Make default...",IDC_REPLACETASKMANAGER,179,69,72,14 - LTEXT "Graph history length:",IDC_STATIC,106,39,69,8 - EDITTEXT IDC_SAMPLECOUNT,180,38,48,12,ES_AUTOHSCROLL | ES_NUMBER - CONTROL "Automatic",IDC_SAMPLECOUNTAUTOMATIC,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,233,39,48,10 - CONTROL "",IDC_SETTINGS,"SysListView32",LVS_LIST | LVS_SINGLESEL | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,88,301,125 - LTEXT "Application font:",IDC_STATIC,121,55,54,8 - RTEXT "Process Hacker is the default Task Manager:",IDC_DEFSTATE,7,71,166,8 + LTEXT "Max. size unit:",IDC_STATIC,7,55,49,8 + COMBOBOX IDC_MAXSIZEUNIT,61,54,39,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + LTEXT "Icon processes:",IDC_STATIC,7,72,52,8 + EDITTEXT IDC_ICONPROCESSES,61,70,40,12,ES_AUTOHSCROLL | ES_NUMBER + PUSHBUTTON "Font...",IDC_FONT,179,70,49,14 + PUSHBUTTON "Make default...",IDC_REPLACETASKMANAGER,179,86,72,14 + LTEXT "Graph history length:",IDC_STATIC,106,56,69,8 + EDITTEXT IDC_SAMPLECOUNT,180,55,48,12,ES_AUTOHSCROLL | ES_NUMBER + CONTROL "Automatic",IDC_SAMPLECOUNTAUTOMATIC,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,233,56,48,10 + CONTROL "",IDC_SETTINGS,"SysListView32",LVS_LIST | LVS_SINGLESEL | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,103,301,110 + LTEXT "Application font:",IDC_STATIC,121,72,54,8 + RTEXT "Process Hacker is the default Task Manager:",IDC_DEFSTATE,7,88,166,8 + LTEXT "Symbol path:",IDC_STATIC,7,39,43,8 + EDITTEXT IDC_DBGHELPSEARCHPATH,61,38,247,12,ES_AUTOHSCROLL END IDD_OPTHIGHLIGHTING DIALOGEX 0, 0, 250, 174 @@ -1264,16 +1266,6 @@ BEGIN DEFPUSHBUTTON "Close",IDOK,256,282,50,14 END -IDD_OPTSYMBOLS DIALOGEX 0, 0, 250, 75 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Symbols" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "Search path:",IDC_STATIC,7,8,42,8 - EDITTEXT IDC_DBGHELPSEARCHPATH,66,7,177,12,ES_AUTOHSCROLL - CONTROL "Undecorate symbols",IDC_UNDECORATESYMBOLS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,22,81,10 -END - IDD_MEMEDIT DIALOGEX 0, 0, 441, 269 STYLE DS_SETFONT | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME EXSTYLE WS_EX_APPWINDOW @@ -2157,14 +2149,6 @@ BEGIN BOTTOMMARGIN, 296 END - IDD_OPTSYMBOLS, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 243 - TOPMARGIN, 7 - BOTTOMMARGIN, 68 - END - IDD_MEMEDIT, DIALOG BEGIN LEFTMARGIN, 7 @@ -2455,6 +2439,17 @@ IDB_SEARCH_ACTIVE PNG "resources\\active_search.png" IDB_SEARCH_INACTIVE PNG "resources\\inactive_search.png" + +///////////////////////////////////////////////////////////////////////////// +// +// AFX_DIALOG_LAYOUT +// + +IDD_OPTGENERAL AFX_DIALOG_LAYOUT +BEGIN + 0 +END + #endif // English (Australia) resources ///////////////////////////////////////////////////////////////////////////// diff --git a/ProcessHacker/options.c b/ProcessHacker/options.c index 0a0f0968930f..60119f6dfc1b 100644 --- a/ProcessHacker/options.c +++ b/ProcessHacker/options.c @@ -52,13 +52,6 @@ INT_PTR CALLBACK PhpOptionsAdvancedDlgProc( _In_ LPARAM lParam ); -INT_PTR CALLBACK PhpOptionsSymbolsDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - INT_PTR CALLBACK PhpOptionsHighlightingDlgProc( _In_ HWND hwndDlg, _In_ UINT uMsg, @@ -333,7 +326,6 @@ INT_PTR CALLBACK PhOptionsDialogProc( section = PhOptionsCreateSection(L"General", PhInstanceHandle, MAKEINTRESOURCE(IDD_OPTGENERAL), PhpOptionsGeneralDlgProc, NULL); PhOptionsCreateSectionAdvanced(L"Advanced", PhInstanceHandle, MAKEINTRESOURCE(IDD_OPTADVANCED), PhpOptionsAdvancedDlgProc, NULL); - PhOptionsCreateSection(L"Symbols", PhInstanceHandle, MAKEINTRESOURCE(IDD_OPTSYMBOLS), PhpOptionsSymbolsDlgProc, NULL); PhOptionsCreateSection(L"Highlighting", PhInstanceHandle, MAKEINTRESOURCE(IDD_OPTHIGHLIGHTING), PhpOptionsHighlightingDlgProc, NULL); PhOptionsCreateSection(L"Graphs", PhInstanceHandle, MAKEINTRESOURCE(IDD_OPTGRAPHS), PhpOptionsGraphsDlgProc, NULL); @@ -954,6 +946,7 @@ typedef enum _PHP_OPTIONS_INDEX PHP_OPTIONS_INDEX_ENABLE_DRIVER, PHP_OPTIONS_INDEX_ENABLE_WARNINGS, PHP_OPTIONS_INDEX_ENABLE_PLUGINS, + PHP_OPTIONS_INDEX_ENABLE_UNDECORATE_SYMBOLS, PHP_OPTIONS_INDEX_ENABLE_NETWORK_RESOLVE, PHP_OPTIONS_INDEX_ENABLE_INSTANT_TOOLTIPS, PHP_OPTIONS_INDEX_ENABLE_CYCLE_CPU_USAGE, @@ -962,7 +955,7 @@ typedef enum _PHP_OPTIONS_INDEX PHP_OPTIONS_INDEX_ICON_SINGLE_CLICK, PHP_OPTIONS_INDEX_ICON_TOGGLE_VISIBILITY, PHP_OPTIONS_INDEX_PROPAGATE_CPU_USAGE, - PHP_OPTIONS_INDEX_SHOW_ADVANCED_OPTIONS, + PHP_OPTIONS_INDEX_SHOW_ADVANCED_OPTIONS } PHP_OPTIONS_GENERAL_INDEX; VOID PhpSetListViewItemState( @@ -997,6 +990,7 @@ static VOID PhpAdvancedPageLoad( PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_DRIVER, L"Enable kernel-mode driver", NULL); PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_WARNINGS, L"Enable warnings", NULL); PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_PLUGINS, L"Enable plugins", NULL); + PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_UNDECORATE_SYMBOLS, L"Enable undecorated symbols", NULL); PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_NETWORK_RESOLVE, L"Resolve network addresses", NULL); PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_INSTANT_TOOLTIPS, L"Show tooltips instantly", NULL); PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_CYCLE_CPU_USAGE, L"Enable cycle-based CPU usage", NULL); @@ -1010,18 +1004,19 @@ static VOID PhpAdvancedPageLoad( SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_SINGLE_INSTANCE, L"AllowOnlyOneInstance"); SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_HIDE_WHENCLOSED, L"HideOnClose"); SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_HIDE_WHENMINIMIZED, L"HideOnMinimize"); - SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_WARNINGS, L"EnableWarnings"); - SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_PLUGINS, L"EnablePlugins"); SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_MINIINFO_WINDOW, L"MiniInfoWindowEnabled"); SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_DRIVER, L"EnableKph"); - SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_STAGE2, L"EnableStage2"); + SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_WARNINGS, L"EnableWarnings"); + SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_PLUGINS, L"EnablePlugins"); + SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_UNDECORATE_SYMBOLS, L"DbgHelpUndecorate"); SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_NETWORK_RESOLVE, L"EnableNetworkResolve"); - SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_PROPAGATE_CPU_USAGE, L"PropagateCpuUsage"); SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_INSTANT_TOOLTIPS, L"EnableInstantTooltips"); SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_CYCLE_CPU_USAGE, L"EnableCycleCpuUsage"); + SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_STAGE2, L"EnableStage2"); SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_COLLAPSE_SERVICES_ON_START, L"CollapseServicesOnStart"); SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_ICON_SINGLE_CLICK, L"IconSingleClick"); SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_ICON_TOGGLE_VISIBILITY, L"IconTogglesVisibility"); + SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_PROPAGATE_CPU_USAGE, L"PropagateCpuUsage"); if (CurrentUserRunPresent) { @@ -1060,6 +1055,12 @@ static VOID PhpAdvancedPageSave( PhSetIntegerSetting(L"MaxSizeUnit", PhMaxSizeUnit = ComboBox_GetCurSel(GetDlgItem(hwndDlg, IDC_MAXSIZEUNIT))); PhSetIntegerSetting(L"IconProcesses", GetDlgItemInt(hwndDlg, IDC_ICONPROCESSES, NULL, FALSE)); + if (!PhEqualString(PhaGetDlgItemText(hwndDlg, IDC_DBGHELPSEARCHPATH), PhaGetStringSetting(L"DbgHelpSearchPath"), TRUE)) + { + PhSetStringSetting2(L"DbgHelpSearchPath", &(PhaGetDlgItemText(hwndDlg, IDC_DBGHELPSEARCHPATH)->sr)); + RestartRequired = TRUE; + } + SetSettingForLvItemCheck(listViewHandle, PHP_OPTIONS_INDEX_SINGLE_INSTANCE, L"AllowOnlyOneInstance"); SetSettingForLvItemCheck(listViewHandle, PHP_OPTIONS_INDEX_HIDE_WHENCLOSED, L"HideOnClose"); SetSettingForLvItemCheck(listViewHandle, PHP_OPTIONS_INDEX_HIDE_WHENMINIMIZED, L"HideOnMinimize"); @@ -1067,6 +1068,7 @@ static VOID PhpAdvancedPageSave( SetSettingForLvItemCheckRestartRequired(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_DRIVER, L"EnableKph"); SetSettingForLvItemCheck(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_WARNINGS, L"EnableWarnings"); SetSettingForLvItemCheckRestartRequired(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_PLUGINS, L"EnablePlugins"); + SetSettingForLvItemCheck(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_UNDECORATE_SYMBOLS, L"DbgHelpUndecorate"); SetSettingForLvItemCheckRestartRequired(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_NETWORK_RESOLVE, L"EnableNetworkResolve"); SetSettingForLvItemCheck(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_INSTANT_TOOLTIPS, L"EnableInstantTooltips"); SetSettingForLvItemCheckRestartRequired(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_CYCLE_CPU_USAGE, L"EnableCycleCpuUsage"); @@ -1130,6 +1132,7 @@ INT_PTR CALLBACK PhpOptionsGeneralDlgProc( PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDC_SEARCHENGINE), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDC_PEVIEWER), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); PhAddLayoutItem(&LayoutManager, listviewHandle, NULL, PH_ANCHOR_ALL); + PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDC_DBGHELPSEARCHPATH), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); PhSetListViewStyle(listviewHandle, FALSE, TRUE); ListView_SetExtendedListViewStyleEx(listviewHandle, LVS_EX_CHECKBOXES, LVS_EX_CHECKBOXES); @@ -1148,8 +1151,8 @@ INT_PTR CALLBACK PhpOptionsGeneralDlgProc( SetDlgItemText(hwndDlg, IDC_SEARCHENGINE, PhaGetStringSetting(L"SearchEngine")->Buffer); SetDlgItemText(hwndDlg, IDC_PEVIEWER, PhaGetStringSetting(L"ProgramInspectExecutables")->Buffer); - SetDlgItemInt(hwndDlg, IDC_ICONPROCESSES, PhGetIntegerSetting(L"IconProcesses"), FALSE); + SetDlgItemText(hwndDlg, IDC_DBGHELPSEARCHPATH, PhaGetStringSetting(L"DbgHelpSearchPath")->Buffer); ReadCurrentUserRun(); @@ -1599,49 +1602,6 @@ INT_PTR CALLBACK PhpOptionsAdvancedDlgProc( return FALSE; } -INT_PTR CALLBACK PhpOptionsSymbolsDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - static PH_LAYOUT_MANAGER LayoutManager; - - switch (uMsg) - { - case WM_INITDIALOG: - { - SetDlgItemText(hwndDlg, IDC_DBGHELPSEARCHPATH, PhaGetStringSetting(L"DbgHelpSearchPath")->Buffer); - SetDlgItemCheckForSetting(hwndDlg, IDC_UNDECORATESYMBOLS, L"DbgHelpUndecorate"); - - PhInitializeLayoutManager(&LayoutManager, hwndDlg); - PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDC_DBGHELPSEARCHPATH), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); - } - break; - case WM_SIZE: - { - PhLayoutManagerLayout(&LayoutManager); - } - break; - case WM_DESTROY: - { - if (!PhEqualString(PhaGetDlgItemText(hwndDlg, IDC_DBGHELPSEARCHPATH), PhaGetStringSetting(L"DbgHelpSearchPath"), TRUE)) - { - RestartRequired = TRUE; - PhSetStringSetting2(L"DbgHelpSearchPath", &(PhaGetDlgItemText(hwndDlg, IDC_DBGHELPSEARCHPATH)->sr)); - } - - SetSettingForDlgItemCheck(hwndDlg, IDC_UNDECORATESYMBOLS, L"DbgHelpUndecorate"); - - PhDeleteLayoutManager(&LayoutManager); - } - break; - } - - return FALSE; -} - typedef struct _COLOR_ITEM { PWSTR SettingName; diff --git a/ProcessHacker/resource.h b/ProcessHacker/resource.h index e82c9362d713..aca3b7524fab 100644 --- a/ProcessHacker/resource.h +++ b/ProcessHacker/resource.h @@ -77,7 +77,6 @@ #define IDR_ICON 173 #define IDD_GDIHANDLES 175 #define IDD_LOG 178 -#define IDD_OPTSYMBOLS 179 #define IDD_MEMEDIT 180 #define IDR_MEMORY 181 #define IDD_MEMPROTECT 182 @@ -744,7 +743,7 @@ // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 247 +#define _APS_NEXT_RESOURCE_VALUE 249 #define _APS_NEXT_COMMAND_VALUE 40297 #define _APS_NEXT_CONTROL_VALUE 1406 #define _APS_NEXT_SYMED_VALUE 170 From b088c8f91ad64085bede9d308d6dbc5ebc5cf130 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 26 Feb 2018 19:21:55 +1100 Subject: [PATCH 0836/2058] Fix issues loading plugins when main executable renamed --- ProcessHacker/plugin.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/ProcessHacker/plugin.c b/ProcessHacker/plugin.c index 0c2e4c82d47d..3531ba60d976 100644 --- a/ProcessHacker/plugin.c +++ b/ProcessHacker/plugin.c @@ -338,6 +338,7 @@ BOOLEAN PhLoadPlugin( _In_ PPH_STRING FileName ) { + NTSTATUS status; PPH_STRING fileName; PPH_STRING errorMessage; PPHP_PLUGIN_LOAD_ERROR loadError; @@ -347,13 +348,15 @@ BOOLEAN PhLoadPlugin( if (!fileName) PhSetReference(&fileName, FileName); - if (LoadLibrary(fileName->Buffer)) + status = PhLoadPluginImage(fileName, NULL); + + if (NT_SUCCESS(status)) { PhDereferenceObject(fileName); return TRUE; } - errorMessage = PhGetWin32Message(GetLastError()); + errorMessage = PhGetNtMessage(status); loadError = PhAllocate(sizeof(PHP_PLUGIN_LOAD_ERROR)); PhSetReference(&loadError->FileName, fileName); From baad8d3d634074823852f03fcc699f4138613b3a Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 26 Feb 2018 19:22:11 +1100 Subject: [PATCH 0837/2058] Fix missing copyright --- ProcessHacker/main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/ProcessHacker/main.c b/ProcessHacker/main.c index 6a909d2a77d5..054f92f371f5 100644 --- a/ProcessHacker/main.c +++ b/ProcessHacker/main.c @@ -3,6 +3,7 @@ * main program * * Copyright (C) 2009-2016 wj32 + * Copyright (C) 2017-2018 dmex * * This file is part of Process Hacker. * From a2f76581fdc554b73cef9ae7dd970fe49c6a42e7 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 26 Feb 2018 19:24:43 +1100 Subject: [PATCH 0838/2058] Add inline NtDelayExecution wrapper --- ProcessHacker/actions.c | 4 +--- ProcessHacker/anawait.c | 7 ++----- ProcessHacker/hidnproc.c | 8 +++----- 3 files changed, 6 insertions(+), 13 deletions(-) diff --git a/ProcessHacker/actions.c b/ProcessHacker/actions.c index 4551bb8a50d9..86cd9e93e1ad 100644 --- a/ProcessHacker/actions.c +++ b/ProcessHacker/actions.c @@ -452,7 +452,6 @@ BOOLEAN PhUiConnectToPhSvcEx( if (started) { ULONG attempts = 10; - LARGE_INTEGER interval; // Try to connect several times because the server may take // a while to initialize. @@ -463,8 +462,7 @@ BOOLEAN PhUiConnectToPhSvcEx( if (NT_SUCCESS(status)) break; - interval.QuadPart = -50 * PH_TIMEOUT_MS; - NtDelayExecution(FALSE, &interval); + PhDelayExecution(50); } while (--attempts != 0); // Increment the reference count even if we failed. diff --git a/ProcessHacker/anawait.c b/ProcessHacker/anawait.c index 93bb2d675458..354a61b29636 100644 --- a/ProcessHacker/anawait.c +++ b/ProcessHacker/anawait.c @@ -663,10 +663,8 @@ static BOOLEAN PhpWaitUntilThreadIsWaiting( PVOID processes; PSYSTEM_PROCESS_INFORMATION processInfo; ULONG i; - LARGE_INTEGER interval; - interval.QuadPart = -100 * PH_TIMEOUT_MS; - NtDelayExecution(FALSE, &interval); + PhDelayExecution(100); if (!NT_SUCCESS(PhEnumProcesses(&processes))) break; @@ -695,8 +693,7 @@ static BOOLEAN PhpWaitUntilThreadIsWaiting( if (isWaiting) break; - interval.QuadPart = -500 * PH_TIMEOUT_MS; - NtDelayExecution(FALSE, &interval); + PhDelayExecution(500); } return isWaiting; diff --git a/ProcessHacker/hidnproc.c b/ProcessHacker/hidnproc.c index e2398510b385..8bbd8a5bc327 100644 --- a/ProcessHacker/hidnproc.c +++ b/ProcessHacker/hidnproc.c @@ -318,12 +318,10 @@ static INT_PTR CALLBACK PhpHiddenProcessesDlgProc( if (refresh) { - LARGE_INTEGER interval; + // Sleep for a bit before continuing. It seems to help avoid BSODs. + + PhDelayExecution(250); - // Sleep for a bit before continuing. It seems to help avoid - // BSODs. - interval.QuadPart = -250 * PH_TIMEOUT_MS; - NtDelayExecution(FALSE, &interval); SendMessage(hwndDlg, WM_COMMAND, IDC_SCAN, 0); } } From dc7ba9ca9bdb5d50df983aba1cec52ede75cb6e1 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 26 Feb 2018 19:48:03 +1100 Subject: [PATCH 0839/2058] Fix options window crash (Partial revert 6dfc9dd9) --- ProcessHacker/options.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ProcessHacker/options.c b/ProcessHacker/options.c index 60119f6dfc1b..2cbfa8249f06 100644 --- a/ProcessHacker/options.c +++ b/ProcessHacker/options.c @@ -168,7 +168,7 @@ VOID PhShowOptionsDialog( DialogBox( PhInstanceHandle, MAKEINTRESOURCE(IDD_OPTIONS), - !!PhGetIntegerSetting(L"ForceNoParent") ? NULL : ParentWindowHandle, + ParentWindowHandle, PhOptionsDialogProc ); From b854dae46d31b21e84fc8c259f7305fca928bad3 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 10 Mar 2018 10:09:15 +1100 Subject: [PATCH 0840/2058] BuildToold: Remove deprecated delaylib --- tools/delaylib/bin/Debug32/delaylib.lib | Bin 21466 -> 0 bytes tools/delaylib/bin/Debug32/delaylib.pdb | Bin 135168 -> 0 bytes tools/delaylib/bin/Debug64/delaylib.lib | Bin 22424 -> 0 bytes tools/delaylib/bin/Debug64/delaylib.pdb | Bin 135168 -> 0 bytes tools/delaylib/bin/Release32/delaylib.lib | Bin 227024 -> 0 bytes tools/delaylib/bin/Release32/delaylib.pdb | Bin 126976 -> 0 bytes tools/delaylib/bin/Release64/delaylib.lib | Bin 226788 -> 0 bytes tools/delaylib/bin/Release64/delaylib.pdb | Bin 135168 -> 0 bytes tools/delaylib/delaylib.sln | 28 ---- tools/delaylib/delaylib.vcxproj | 182 ---------------------- tools/delaylib/delaylib.vcxproj.filters | 22 --- tools/delaylib/main.c | 159 ------------------- 12 files changed, 391 deletions(-) delete mode 100644 tools/delaylib/bin/Debug32/delaylib.lib delete mode 100644 tools/delaylib/bin/Debug32/delaylib.pdb delete mode 100644 tools/delaylib/bin/Debug64/delaylib.lib delete mode 100644 tools/delaylib/bin/Debug64/delaylib.pdb delete mode 100644 tools/delaylib/bin/Release32/delaylib.lib delete mode 100644 tools/delaylib/bin/Release32/delaylib.pdb delete mode 100644 tools/delaylib/bin/Release64/delaylib.lib delete mode 100644 tools/delaylib/bin/Release64/delaylib.pdb delete mode 100644 tools/delaylib/delaylib.sln delete mode 100644 tools/delaylib/delaylib.vcxproj delete mode 100644 tools/delaylib/delaylib.vcxproj.filters delete mode 100644 tools/delaylib/main.c diff --git a/tools/delaylib/bin/Debug32/delaylib.lib b/tools/delaylib/bin/Debug32/delaylib.lib deleted file mode 100644 index cc2d9ac662d043be09abfdc7695e9b120c70135a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 21466 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

    C2+eD1%JVXW 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 diff --git a/tools/delaylib/bin/Debug64/delaylib.lib b/tools/delaylib/bin/Debug64/delaylib.lib deleted file mode 100644 index e96a466a53b9216b9f5bba836c06982ceba88282..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 22424 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 diff --git a/tools/delaylib/bin/Debug64/delaylib.pdb b/tools/delaylib/bin/Debug64/delaylib.pdb deleted file mode 100644 index ab1a155a96e73301d81eef11bc81aba98ec44ba2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 135168 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

    4A6nZbXBM`wQnuuFnCUuRREPG&qe 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 W0~2L2D?oi8r{ diff --git a/tools/delaylib/bin/Release64/delaylib.lib b/tools/delaylib/bin/Release64/delaylib.lib deleted file mode 100644 index b02b934e17e3e210055d34ce0fbb739c1a0788ba..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 226788 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 diff --git a/tools/delaylib/delaylib.sln b/tools/delaylib/delaylib.sln deleted file mode 100644 index e94606b52622..000000000000 --- a/tools/delaylib/delaylib.sln +++ /dev/null @@ -1,28 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.26430.6 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "delaylib", "delaylib.vcxproj", "{9648DD70-47A8-4B73-B379-12368E8EF919}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|x64 = Debug|x64 - Debug|x86 = Debug|x86 - Release|x64 = Release|x64 - Release|x86 = Release|x86 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {9648DD70-47A8-4B73-B379-12368E8EF919}.Debug|x64.ActiveCfg = Debug|x64 - {9648DD70-47A8-4B73-B379-12368E8EF919}.Debug|x64.Build.0 = Debug|x64 - {9648DD70-47A8-4B73-B379-12368E8EF919}.Debug|x86.ActiveCfg = Debug|Win32 - {9648DD70-47A8-4B73-B379-12368E8EF919}.Debug|x86.Build.0 = Debug|Win32 - {9648DD70-47A8-4B73-B379-12368E8EF919}.Release|x64.ActiveCfg = Release|x64 - {9648DD70-47A8-4B73-B379-12368E8EF919}.Release|x64.Build.0 = Release|x64 - {9648DD70-47A8-4B73-B379-12368E8EF919}.Release|x86.ActiveCfg = Release|Win32 - {9648DD70-47A8-4B73-B379-12368E8EF919}.Release|x86.Build.0 = Release|Win32 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/tools/delaylib/delaylib.vcxproj b/tools/delaylib/delaylib.vcxproj deleted file mode 100644 index 112cba61cfd8..000000000000 --- a/tools/delaylib/delaylib.vcxproj +++ /dev/null @@ -1,182 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - - - - 15.0 - {9648DD70-47A8-4B73-B379-12368E8EF919} - Win32Proj - delaylib - 10.0.15063.0 - delaylib - - - - StaticLibrary - true - v141 - Unicode - - - StaticLibrary - false - v141 - true - Unicode - - - StaticLibrary - true - v141 - Unicode - - - StaticLibrary - false - v141 - true - Unicode - - - - - - - - - - - - - - - - - - - - - $(ProjectDir)bin\$(Configuration)$(PlatformArchitecture)\ - $(ProjectDir)obj\$(Configuration)$(PlatformArchitecture)\ - - - $(ProjectDir)bin\$(Configuration)$(PlatformArchitecture)\ - $(ProjectDir)obj\$(Configuration)$(PlatformArchitecture)\ - - - $(ProjectDir)bin\$(Configuration)$(PlatformArchitecture)\ - $(ProjectDir)obj\$(Configuration)$(PlatformArchitecture)\ - - - $(ProjectDir)bin\$(Configuration)$(PlatformArchitecture)\ - $(ProjectDir)obj\$(Configuration)$(PlatformArchitecture)\ - - - - Level3 - Disabled - _DEBUG;_LIB;%(PreprocessorDefinitions) - true - StdCall - false - MultiThreadedDebug - ..\..\phnt\include;..\..\phlib\include;include;%(AdditionalIncludeDirectories) - true - true - true - ProgramDatabase - $(OutDir)$(TargetName).pdb - - - Windows - - - - - Level3 - Disabled - WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) - true - StdCall - false - MultiThreadedDebug - ..\..\phnt\include;..\..\phlib\include;include;%(AdditionalIncludeDirectories) - true - true - true - ProgramDatabase - $(OutDir)$(TargetName).pdb - - - Windows - - - - - Level3 - MaxSpeed - true - true - WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) - true - StdCall - MultiThreaded - ..\..\phnt\include;..\..\phlib\include;include;%(AdditionalIncludeDirectories) - true - true - true - ProgramDatabase - $(OutDir)$(TargetName).pdb - - - Windows - true - true - - - - - Level3 - MaxSpeed - true - true - NDEBUG;_LIB;%(PreprocessorDefinitions) - true - StdCall - MultiThreaded - ..\..\phnt\include;..\..\phlib\include;include;%(AdditionalIncludeDirectories) - true - true - true - ProgramDatabase - $(OutDir)$(TargetName).pdb - - - Windows - true - true - - - - - - \ No newline at end of file diff --git a/tools/delaylib/delaylib.vcxproj.filters b/tools/delaylib/delaylib.vcxproj.filters deleted file mode 100644 index 6827613af933..000000000000 --- a/tools/delaylib/delaylib.vcxproj.filters +++ /dev/null @@ -1,22 +0,0 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hh;hpp;hxx;hm;inl;inc;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - - - - - Source Files - - - \ No newline at end of file diff --git a/tools/delaylib/main.c b/tools/delaylib/main.c deleted file mode 100644 index 128852511c33..000000000000 --- a/tools/delaylib/main.c +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Process Hacker Toolchain - - * Image DelayLoad Helper - * - * Copyright (C) 2017 dmex - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include -#include - -extern const IMAGE_DOS_HEADER __ImageBase; - -PVOID WINAPI __delayLoadHelper2( - _In_ PIMAGE_DELAYLOAD_DESCRIPTOR Entry, - _Out_ PVOID *ImportAddress - ) -{ - BOOLEAN needsFree = FALSE; - MEMORY_BASIC_INFORMATION info; - ULONG delayLoadJunk; - PSTR importName; - PVOID procedureAddress; - PVOID moduleHandle; - PVOID* importHandle; - PIMAGE_THUNK_DATA entry; - PIMAGE_THUNK_DATA importTable; - PIMAGE_THUNK_DATA importNameTable; - - importName = PTR_ADD_OFFSET(&__ImageBase, Entry->DllNameRVA); - importHandle = PTR_ADD_OFFSET(&__ImageBase, Entry->ModuleHandleRVA); - importTable = PTR_ADD_OFFSET(&__ImageBase, Entry->ImportAddressTableRVA); - importNameTable = PTR_ADD_OFFSET(&__ImageBase, Entry->ImportNameTableRVA); - - if (!strcmp(importName, "ProcessHacker.exe")) - { - moduleHandle = NtCurrentPeb()->ImageBaseAddress; - } - else - { - if (moduleHandle = LoadLibraryA(importName)) - { - needsFree = TRUE; - } - else - { - DelayLoadInfo dli = - { - sizeof(DelayLoadInfo), - (PCImgDelayDescr)Entry, - (FARPROC*)ImportAddress, - importName - }; - - RaiseException( - VcppException(ERROR_SEVERITY_ERROR, ERROR_MOD_NOT_FOUND), - 0, - 1, - (PULONG_PTR)&dli - ); - - return NULL; - } - } - - entry = PTR_ADD_OFFSET(importNameTable, (ULONG)((PBYTE)ImportAddress - (PBYTE)importTable)); - - if (IMAGE_SNAP_BY_ORDINAL(entry->u1.Ordinal)) - { - ULONG procedureOrdinal = IMAGE_ORDINAL(entry->u1.Ordinal); - procedureAddress = PhGetProcedureAddress(moduleHandle, NULL, procedureOrdinal); - } - else - { - PSTR procedureName = ((PIMAGE_IMPORT_BY_NAME)PTR_ADD_OFFSET(&__ImageBase, entry->u1.AddressOfData))->Name; - procedureAddress = PhGetProcedureAddress(moduleHandle, procedureName, 0); - } - - if (!procedureAddress) - { - PSTR procedureName = ((PIMAGE_IMPORT_BY_NAME)PTR_ADD_OFFSET(&__ImageBase, entry->u1.AddressOfData))->Name; - DelayLoadInfo dli = - { - sizeof(DelayLoadInfo), - (PCImgDelayDescr)Entry, - (FARPROC*)ImportAddress, - procedureName - }; - - RaiseException( - VcppException(ERROR_SEVERITY_ERROR, ERROR_PROC_NOT_FOUND), - 0, - 1, - (PULONG_PTR)&dli - ); - - return NULL; - } - - if (!NT_SUCCESS(NtQueryVirtualMemory( - NtCurrentProcess(), - ImportAddress, - MemoryBasicInformation, - &info, - sizeof(MEMORY_BASIC_INFORMATION), - NULL - ))) - { - return NULL; - } - - if (!VirtualProtect( - info.BaseAddress, - info.RegionSize, - PAGE_EXECUTE_READWRITE, - &info.Protect - )) - { - return NULL; - } - - // Cache the procedure address (Fixes CRT delayload bug). - if (InterlockedExchangePointer(ImportAddress, procedureAddress)) - { - NOTHING; - } - - if (!VirtualProtect( - info.BaseAddress, - info.RegionSize, - info.Protect, - &delayLoadJunk - )) - { - return NULL; - } - - // Cache the module handle in the IAT entry (required) (Fixes CRT use-after-free bug). - if (InterlockedExchangePointer(importHandle, moduleHandle) == moduleHandle && needsFree) - { - FreeLibrary(moduleHandle); // A different thread has already updated the cache. - } - - return procedureAddress; -} From 64ed7939e1cf0e740db337aa333e7e6716ac7d05 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 10 Mar 2018 10:36:12 +1100 Subject: [PATCH 0841/2058] Update default DbgHelpSearchPath setting --- ProcessHacker/settings.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ProcessHacker/settings.c b/ProcessHacker/settings.c index 38b80d3fd070..e9c294cacf47 100644 --- a/ProcessHacker/settings.c +++ b/ProcessHacker/settings.c @@ -36,7 +36,7 @@ VOID PhAddDefaultSettings( PhpAddIntegerSetting(L"AllowOnlyOneInstance", L"1"); PhpAddIntegerSetting(L"CloseOnEscape", L"0"); PhpAddIntegerSetting(L"CollapseServicesOnStart", L"0"); - PhpAddStringSetting(L"DbgHelpSearchPath", L""); + PhpAddStringSetting(L"DbgHelpSearchPath", L"SRV*C:\\Symbols*http://msdl.microsoft.com/download/symbols"); PhpAddIntegerSetting(L"DbgHelpUndecorate", L"1"); PhpAddStringSetting(L"DisabledPlugins", L""); PhpAddIntegerSetting(L"ElevationLevel", L"1"); // PromptElevateAction From a6efcd3ed516945627b01ca5808a2af339beae28 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 10 Mar 2018 11:08:43 +1100 Subject: [PATCH 0842/2058] Fix missing ServiceDll for "user service instance" processes #244 Co-Authored-By: hsebs --- ProcessHacker/appsup.c | 2 +- ProcessHacker/srvprp.c | 2 +- phlib/include/svcsup.h | 1 + phlib/svcsup.c | 22 ++++++++++++++++++++-- plugins/OnlineChecks/virustotal.c | 2 +- plugins/ToolStatus/filter.c | 2 +- 6 files changed, 25 insertions(+), 6 deletions(-) diff --git a/ProcessHacker/appsup.c b/ProcessHacker/appsup.c index 2662baa237b2..222d73b93133 100644 --- a/ProcessHacker/appsup.c +++ b/ProcessHacker/appsup.c @@ -689,7 +689,7 @@ PPH_STRING PhGetServiceRelevantFileName( if (config = PhGetServiceConfig(ServiceHandle)) { - PhGetServiceDllParameter(ServiceName, &fileName); + PhGetServiceDllParameter(config->dwServiceType, ServiceName, &fileName); if (!fileName) { diff --git a/ProcessHacker/srvprp.c b/ProcessHacker/srvprp.c index 4285902595ad..36f9d0e97e22 100644 --- a/ProcessHacker/srvprp.c +++ b/ProcessHacker/srvprp.c @@ -279,7 +279,7 @@ INT_PTR CALLBACK PhpServiceGeneralDlgProc( SetDlgItemText(hwndDlg, IDC_PASSWORD, L"password"); Button_SetCheck(GetDlgItem(hwndDlg, IDC_PASSWORDCHECK), BST_UNCHECKED); - if (NT_SUCCESS(PhGetServiceDllParameter(&serviceItem->Name->sr, &serviceDll))) + if (NT_SUCCESS(PhGetServiceDllParameter(serviceItem->Type, &serviceItem->Name->sr, &serviceDll))) { SetDlgItemText(hwndDlg, IDC_SERVICEDLL, serviceDll->Buffer); PhDereferenceObject(serviceDll); diff --git a/phlib/include/svcsup.h b/phlib/include/svcsup.h index a968f54e21da..47fb1fbeb51f 100644 --- a/phlib/include/svcsup.h +++ b/phlib/include/svcsup.h @@ -143,6 +143,7 @@ PHLIBAPI NTSTATUS NTAPI PhGetServiceDllParameter( + _In_ ULONG ServiceType, _In_ PPH_STRINGREF ServiceName, _Out_ PPH_STRING *ServiceDll ); diff --git a/phlib/svcsup.c b/phlib/svcsup.c index e5625cf6b93d..9bbb45b4690e 100644 --- a/phlib/svcsup.c +++ b/phlib/svcsup.c @@ -543,18 +543,36 @@ NTSTATUS PhGetThreadServiceTag( } NTSTATUS PhGetServiceDllParameter( + _In_ ULONG ServiceType, _In_ PPH_STRINGREF ServiceName, _Out_ PPH_STRING *ServiceDll ) { static PH_STRINGREF servicesKeyName = PH_STRINGREF_INIT(L"System\\CurrentControlSet\\Services\\"); static PH_STRINGREF parameters = PH_STRINGREF_INIT(L"\\Parameters"); - NTSTATUS status; HANDLE keyHandle; PPH_STRING keyName; - keyName = PhConcatStringRef3(&servicesKeyName, ServiceName, ¶meters); + if (ServiceType & SERVICE_USERSERVICE_INSTANCE) + { + PH_STRINGREF hostServiceName; + PH_STRINGREF userSessionLuid; + + // The SCM creates multiple "user service instance" processes for each user session with the following template: + // [Host Service Instance Name]_[LUID for Session] + // The SCM internally uses the ServiceDll of the "host service instance" for all "user service instance" processes/services + // and we need to parse the user service template and query the "host service instance" configuration. + + if (PhSplitStringRefAtLastChar(ServiceName, L'_', &hostServiceName, &userSessionLuid)) + keyName = PhConcatStringRef3(&servicesKeyName, &hostServiceName, ¶meters); + else + keyName = PhConcatStringRef3(&servicesKeyName, ServiceName, ¶meters); + } + else + { + keyName = PhConcatStringRef3(&servicesKeyName, ServiceName, ¶meters); + } if (NT_SUCCESS(status = PhOpenKey( &keyHandle, diff --git a/plugins/OnlineChecks/virustotal.c b/plugins/OnlineChecks/virustotal.c index 4e9eb77f064f..e494d438fa9e 100644 --- a/plugins/OnlineChecks/virustotal.c +++ b/plugins/OnlineChecks/virustotal.c @@ -965,7 +965,7 @@ NTSTATUS QueryServiceFileName( if (NT_SUCCESS(status)) { - PhGetServiceDllParameter(ServiceName, &fileName); + PhGetServiceDllParameter(serviceType, ServiceName, &fileName); if (!fileName) { diff --git a/plugins/ToolStatus/filter.c b/plugins/ToolStatus/filter.c index 8e0002aa3c85..aa7d5f536be2 100644 --- a/plugins/ToolStatus/filter.c +++ b/plugins/ToolStatus/filter.c @@ -706,7 +706,7 @@ NTSTATUS QueryServiceFileName( if (NT_SUCCESS(status)) { - PhGetServiceDllParameter(ServiceName, &fileName); + PhGetServiceDllParameter(serviceType, ServiceName, &fileName); if (!fileName) { From 2a634e498561996671e96f6bf416f49d85031ff0 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 10 Mar 2018 11:27:02 +1100 Subject: [PATCH 0843/2058] BuildTools: Fix build error when output directory doesn't exist --- ProcessHacker/ProcessHacker.vcxproj | 4 +- tools/CustomBuildTool/Source Files/Build.cs | 54 ++++++++++++------ .../bin/Release/CustomBuildTool.exe | Bin 163840 -> 164352 bytes .../bin/Release/CustomBuildTool.pdb | Bin 77312 -> 77312 bytes 4 files changed, 37 insertions(+), 21 deletions(-) diff --git a/ProcessHacker/ProcessHacker.vcxproj b/ProcessHacker/ProcessHacker.vcxproj index 08dc681c1413..2d60b5ef8fc8 100644 --- a/ProcessHacker/ProcessHacker.vcxproj +++ b/ProcessHacker/ProcessHacker.vcxproj @@ -174,7 +174,6 @@ aclui.lib;comctl32.lib;iphlpapi.lib;noarg.obj;noenv.obj;ntdll.lib;phlib.lib;uxtheme.lib;version.lib;wbemuuid.lib;windowscodecs.lib;winsta.lib;ws2_32.lib;%(AdditionalDependencies) - true Windows true true @@ -184,6 +183,7 @@ $(SolutionDir)phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) ProcessHacker.def aclui.dll;comdlg32.dll;iphlpapi.dll;winsta.dll;ws2_32.dll;%(DelayLoadDLLs) + $(ExternalDebugOptions) _UNICODE;UNICODE;%(PreprocessorDefinitions);$(ExternalCompilerOptions) @@ -212,7 +212,6 @@ aclui.lib;comctl32.lib;iphlpapi.lib;noarg.obj;noenv.obj;ntdll.lib;phlib.lib;uxtheme.lib;version.lib;wbemuuid.lib;windowscodecs.lib;winsta.lib;ws2_32.lib;%(AdditionalDependencies) - true Windows true true @@ -222,6 +221,7 @@ $(SolutionDir)phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) ProcessHacker.def aclui.dll;comdlg32.dll;iphlpapi.dll;winsta.dll;ws2_32.dll;%(DelayLoadDLLs) + $(ExternalDebugOptions) _UNICODE;UNICODE;%(PreprocessorDefinitions);$(ExternalCompilerOptions) diff --git a/tools/CustomBuildTool/Source Files/Build.cs b/tools/CustomBuildTool/Source Files/Build.cs index 9a2ebc5cccc1..afefe815e0c0 100644 --- a/tools/CustomBuildTool/Source Files/Build.cs +++ b/tools/CustomBuildTool/Source Files/Build.cs @@ -616,25 +616,39 @@ public static bool CopyKProcessHacker(BuildFlags Flags) { if (Flags.HasFlag(BuildFlags.BuildDebug)) { - Win32.CopyIfNewer( - "KProcessHacker\\bin-signed\\i386\\kprocesshacker.sys", - "bin\\Debug32\\kprocesshacker.sys" - ); - Win32.CopyIfNewer( - "KProcessHacker\\bin-signed\\amd64\\kprocesshacker.sys", - "bin\\Debug64\\kprocesshacker.sys" - ); + if (Directory.Exists("bin\\Debug32")) + { + Win32.CopyIfNewer( + "KProcessHacker\\bin-signed\\i386\\kprocesshacker.sys", + "bin\\Debug32\\kprocesshacker.sys" + ); + } + + if (Directory.Exists("bin\\Debug64")) + { + Win32.CopyIfNewer( + "KProcessHacker\\bin-signed\\amd64\\kprocesshacker.sys", + "bin\\Debug64\\kprocesshacker.sys" + ); + } } else { - Win32.CopyIfNewer( - "KProcessHacker\\bin-signed\\i386\\kprocesshacker.sys", - "bin\\Release32\\kprocesshacker.sys" - ); - Win32.CopyIfNewer( - "KProcessHacker\\bin-signed\\amd64\\kprocesshacker.sys", - "bin\\Release64\\kprocesshacker.sys" - ); + if (Directory.Exists("bin\\Release32")) + { + Win32.CopyIfNewer( + "KProcessHacker\\bin-signed\\i386\\kprocesshacker.sys", + "bin\\Release32\\kprocesshacker.sys" + ); + } + + if (Directory.Exists("bin\\Release64")) + { + Win32.CopyIfNewer( + "KProcessHacker\\bin-signed\\amd64\\kprocesshacker.sys", + "bin\\Release64\\kprocesshacker.sys" + ); + } } } catch (Exception ex) @@ -727,7 +741,7 @@ public static bool BuildSetupExe() { Program.PrintColorMessage("Building build-setup.exe...", ConsoleColor.Cyan); - if (!BuildSolution("tools\\CustomSetupTool\\CustomSetupTool.sln", BuildFlags.Build32bit | BuildFlags.BuildApi)) + if (!BuildSolution("tools\\CustomSetupTool\\CustomSetupTool.sln", BuildFlags.Build32bit | BuildFlags.BuildApi)) return false; try @@ -1146,12 +1160,13 @@ public static bool BuildSolution(string Solution, BuildFlags Flags) "/p:Configuration=" + (Flags.HasFlag(BuildFlags.BuildDebug) ? "Debug " : "Release ") + "/p:Platform=Win32 " + "/p:ExternalCompilerOptions=\"" + compilerOptions.ToString() + "\" " + + "/p:ExternalDebugOptions=\"" + (Flags.HasFlag(BuildFlags.BuildDebug) ? "true" : "false") + "\" " + Solution ); if (!string.IsNullOrEmpty(error32)) { - Program.PrintColorMessage("[ERROR] " + error32, ConsoleColor.Red, true, Flags); + Program.PrintColorMessage("[ERROR] " + error32, ConsoleColor.Red, true, Flags | BuildFlags.BuildVerbose); return false; } } @@ -1174,12 +1189,13 @@ public static bool BuildSolution(string Solution, BuildFlags Flags) "/p:Configuration=" + (Flags.HasFlag(BuildFlags.BuildDebug) ? "Debug " : "Release ") + "/p:Platform=x64 " + "/p:ExternalCompilerOptions=\"" + compilerOptions.ToString() + "\" " + + "/p:ExternalDebugOptions=\"" + (Flags.HasFlag(BuildFlags.BuildDebug) ? "true" : "false") + "\" " + Solution ); if (!string.IsNullOrEmpty(error64)) { - Program.PrintColorMessage("[ERROR] " + error64, ConsoleColor.Red, true, Flags); + Program.PrintColorMessage("[ERROR] " + error64, ConsoleColor.Red, true, Flags | BuildFlags.BuildVerbose); return false; } } diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe b/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe index e4971dd5c781e4e11dc3445a30d56af19cc44f24..4487982fe747fadeb0e9e56280d279659592b57e 100644 GIT binary patch delta 10602 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 GQTcDgsAdlU delta 10371 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 diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb b/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb index 3ba53e1eed6b41a9a0f78f957953f165bc2b8988..b342d4f835a9747699cd02797756925cefda00fc 100644 GIT binary patch delta 7877 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 b{ZXn@rT_Pz(&bTgRg6t_FK-c}J_z`4HA)cg delta 7820 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 From e88c57129d1f77daebc475bc042fc5fd7eb6296e Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 12 Mar 2018 10:04:29 +1100 Subject: [PATCH 0844/2058] Add HYPERVISOR_SHARED_PAGE_INFORMATION types --- phnt/include/ntexapi.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/phnt/include/ntexapi.h b/phnt/include/ntexapi.h index 47dbf28604e4..815ee07fa6f8 100644 --- a/phnt/include/ntexapi.h +++ b/phnt/include/ntexapi.h @@ -1394,7 +1394,7 @@ typedef enum _SYSTEM_INFORMATION_CLASS SystemSecureDumpEncryptionInformation, SystemWriteConstraintInformation, // SYSTEM_WRITE_CONSTRAINT_INFORMATION SystemKernelVaShadowInformation, // SYSTEM_KERNEL_VA_SHADOW_INFORMATION - SystemHypervisorSharedPageInformation, // REDSTONE4 + SystemHypervisorSharedPageInformation, // SYSTEM_HYPERVISOR_SHARED_PAGE_INFORMATION // REDSTONE4 SystemFirmwareBootPerformanceInformation, SystemCodeIntegrityVerificationInformation, SystemFirmwarePartitionInformation, // 200 @@ -3103,6 +3103,12 @@ typedef struct _SYSTEM_KERNEL_VA_SHADOW_INFORMATION }; } SYSTEM_KERNEL_VA_SHADOW_INFORMATION, *PSYSTEM_KERNEL_VA_SHADOW_INFORMATION; +// private +typedef struct _SYSTEM_HYPERVISOR_SHARED_PAGE_INFORMATION +{ + PVOID HypervisorSharedUserVa; +} SYSTEM_HYPERVISOR_SHARED_PAGE_INFORMATION, *PSYSTEM_HYPERVISOR_SHARED_PAGE_INFORMATION; + // private typedef struct _SYSTEM_SPECULATION_CONTROL_INFORMATION { From f705176d88a81ed556274d5f141ad594dd841bd5 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 12 Mar 2018 12:34:25 +1100 Subject: [PATCH 0845/2058] Show process HYPERVISOR_SHARED_DATA memory regions on Win10-RS4 (HVCI required), Add missing copyrights --- ProcessHacker/include/memprv.h | 1 + ProcessHacker/memlist.c | 5 ++++- ProcessHacker/memprv.c | 30 ++++++++++++++++++++++++++++++ 3 files changed, 35 insertions(+), 1 deletion(-) diff --git a/ProcessHacker/include/memprv.h b/ProcessHacker/include/memprv.h index 1a1fc8914b56..1dc3b161141e 100644 --- a/ProcessHacker/include/memprv.h +++ b/ProcessHacker/include/memprv.h @@ -24,6 +24,7 @@ typedef enum _PH_MEMORY_REGION_TYPE CfgBitmapRegion, CfgBitmap32Region, ApiSetMapRegion, + HypervisorSharedDataRegion, } PH_MEMORY_REGION_TYPE; typedef struct _PH_MEMORY_ITEM diff --git a/ProcessHacker/memlist.c b/ProcessHacker/memlist.c index 7eec2d32af0c..687fbf275c0f 100644 --- a/ProcessHacker/memlist.c +++ b/ProcessHacker/memlist.c @@ -3,6 +3,7 @@ * memory region list * * Copyright (C) 2015 wj32 + * Copyright (C) 2017-2018 dmex * * This file is part of Process Hacker. * @@ -439,6 +440,8 @@ PPH_STRING PhGetMemoryRegionUseText( return MemoryItem->u.MappedFile.FileName; case UserSharedDataRegion: return PhCreateString(L"USER_SHARED_DATA"); + case HypervisorSharedDataRegion: + return PhCreateString(L"HYPERVISOR_SHARED_DATA"); case PebRegion: case Peb32Region: return PhFormatString(L"PEB%s", type == Peb32Region ? L" 32-bit" : L""); @@ -463,7 +466,7 @@ PPH_STRING PhGetMemoryRegionUseText( return PhFormatString(L"CFG Bitmap%s", type == CfgBitmap32Region ? L" 32-bit" : L""); case ApiSetMapRegion: - return PhFormatString(L"ApiSetMap"); + return PhFormatString(L"ApiSetMap"); default: return PhReferenceEmptyString(); } diff --git a/ProcessHacker/memprv.c b/ProcessHacker/memprv.c index 26a01daaf4c9..7f32ccc2510c 100644 --- a/ProcessHacker/memprv.c +++ b/ProcessHacker/memprv.c @@ -3,6 +3,7 @@ * memory provider * * Copyright (C) 2010-2015 wj32 + * Copyright (C) 2017-2018 dmex * * This file is part of Process Hacker. * @@ -269,6 +270,35 @@ NTSTATUS PhpUpdateMemoryRegionTypes( // USER_SHARED_DATA PhpSetMemoryRegionType(List, USER_SHARED_DATA, TRUE, UserSharedDataRegion); + // HYPERVISOR_SHARED_DATA + if (WindowsVersion > WINDOWS_10_RS3) // TODO: Update version check after RS4 release. + { + static PVOID HypervisorSharedDataVa = NULL; + static PH_INITONCE HypervisorSharedDataInitOnce = PH_INITONCE_INIT; + + if (PhBeginInitOnce(&HypervisorSharedDataInitOnce)) + { + SYSTEM_HYPERVISOR_SHARED_PAGE_INFORMATION hypervSharedPageInfo; + + if (NT_SUCCESS(NtQuerySystemInformation( + SystemHypervisorSharedPageInformation, + &hypervSharedPageInfo, + sizeof(SYSTEM_HYPERVISOR_SHARED_PAGE_INFORMATION), + NULL + ))) + { + HypervisorSharedDataVa = hypervSharedPageInfo.HypervisorSharedUserVa; + } + + PhEndInitOnce(&HypervisorSharedDataInitOnce); + } + + if (HypervisorSharedDataVa) + { + PhpSetMemoryRegionType(List, HypervisorSharedDataVa, TRUE, HypervisorSharedDataRegion); + } + } + // PEB, heap { PROCESS_BASIC_INFORMATION basicInfo; From 9f54dc81cfc1f644359829b2eb2bc03bd1a03986 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 12 Mar 2018 12:37:03 +1100 Subject: [PATCH 0846/2058] Fix Windows 10 bug showing TEB/PEB sub-VAD segments on the memory tab --- ProcessHacker/memprv.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/ProcessHacker/memprv.c b/ProcessHacker/memprv.c index 7f32ccc2510c..0a434e533c38 100644 --- a/ProcessHacker/memprv.c +++ b/ProcessHacker/memprv.c @@ -316,7 +316,8 @@ NTSTATUS PhpUpdateMemoryRegionTypes( if (NT_SUCCESS(PhGetProcessBasicInformation(ProcessHandle, &basicInfo)) && basicInfo.PebBaseAddress != 0) { - PhpSetMemoryRegionType(List, basicInfo.PebBaseAddress, TRUE, PebRegion); + // HACK: Windows 10 RS2 and above 'added TEB/PEB sub-VAD segments' and we need to tag individual sections. + PhpSetMemoryRegionType(List, basicInfo.PebBaseAddress, WindowsVersion < WINDOWS_10_RS2 ? TRUE : FALSE, PebRegion); if (NT_SUCCESS(NtReadVirtualMemory(ProcessHandle, PTR_ADD_OFFSET(basicInfo.PebBaseAddress, FIELD_OFFSET(PEB, NumberOfHeaps)), @@ -408,7 +409,8 @@ NTSTATUS PhpUpdateMemoryRegionTypes( NT_TIB ntTib; SIZE_T bytesRead; - if (memoryItem = PhpSetMemoryRegionType(List, thread->TebBase, TRUE, TebRegion)) + // HACK: Windows 10 RS2 and above 'added TEB/PEB sub-VAD segments' and we need to tag individual sections. + if (memoryItem = PhpSetMemoryRegionType(List, thread->TebBase, WindowsVersion < WINDOWS_10_RS2 ? TRUE : FALSE, TebRegion)) memoryItem->u.Teb.ThreadId = thread->ThreadInfo.ClientId.UniqueThread; if (NT_SUCCESS(NtReadVirtualMemory(ProcessHandle, thread->TebBase, &ntTib, sizeof(NT_TIB), &bytesRead)) && From d66d5b785b131510fd32bd450c716fbc9382bbdb Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 12 Mar 2018 14:50:47 +1100 Subject: [PATCH 0847/2058] Update url settings with https prefix --- ProcessHacker/settings.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ProcessHacker/settings.c b/ProcessHacker/settings.c index e9c294cacf47..8f0e7f7c19ce 100644 --- a/ProcessHacker/settings.c +++ b/ProcessHacker/settings.c @@ -36,7 +36,7 @@ VOID PhAddDefaultSettings( PhpAddIntegerSetting(L"AllowOnlyOneInstance", L"1"); PhpAddIntegerSetting(L"CloseOnEscape", L"0"); PhpAddIntegerSetting(L"CollapseServicesOnStart", L"0"); - PhpAddStringSetting(L"DbgHelpSearchPath", L"SRV*C:\\Symbols*http://msdl.microsoft.com/download/symbols"); + PhpAddStringSetting(L"DbgHelpSearchPath", L"SRV*C:\\Symbols*https://msdl.microsoft.com/download/symbols"); PhpAddIntegerSetting(L"DbgHelpUndecorate", L"1"); PhpAddStringSetting(L"DisabledPlugins", L""); PhpAddIntegerSetting(L"ElevationLevel", L"1"); // PromptElevateAction @@ -138,7 +138,7 @@ VOID PhAddDefaultSettings( PhpAddIntegerSetting(L"SampleCount", L"200"); // 512 PhpAddIntegerSetting(L"SampleCountAutomatic", L"1"); PhpAddIntegerSetting(L"ScrollToNewProcesses", L"0"); - PhpAddStringSetting(L"SearchEngine", L"http://www.google.com/search?q=\"%s\""); + PhpAddStringSetting(L"SearchEngine", L"https://www.google.com/search?q=\"%s\""); PhpAddStringSetting(L"ServiceListViewColumns", L""); PhpAddStringSetting(L"ServiceTreeListColumns", L""); PhpAddStringSetting(L"ServiceTreeListSort", L"0,1"); // 0, AscendingSortOrder From da9689e58f9c4076b3f8dee9afe8cec448721500 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 18 Mar 2018 19:31:58 +1100 Subject: [PATCH 0848/2058] Use macro --- ProcessHacker/main.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/ProcessHacker/main.c b/ProcessHacker/main.c index 054f92f371f5..d45446a4bb88 100644 --- a/ProcessHacker/main.c +++ b/ProcessHacker/main.c @@ -471,12 +471,9 @@ static BOOLEAN NTAPI PhpPreviousInstancesCallback( return TRUE; } - if (NT_SUCCESS(NtQueryMutant( + if (NT_SUCCESS(PhGetMutantOwnerInformation( objectHandle, - MutantOwnerInformation, - &objectInfo, - sizeof(MUTANT_OWNER_INFORMATION), - NULL + &objectInfo ))) { HWND hwnd; From 498eed86ad2b4deacc184ec9c6ce5e15baa22a26 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 18 Mar 2018 19:33:36 +1100 Subject: [PATCH 0849/2058] BuildTools: Add commit hash to ExternalCompilerOptions --- tools/CustomBuildTool/Source Files/Build.cs | 30 ++++++++++-------- .../bin/Release/CustomBuildTool.exe | Bin 164352 -> 163840 bytes .../bin/Release/CustomBuildTool.pdb | Bin 77312 -> 77312 bytes 3 files changed, 17 insertions(+), 13 deletions(-) diff --git a/tools/CustomBuildTool/Source Files/Build.cs b/tools/CustomBuildTool/Source Files/Build.cs index afefe815e0c0..8e5d2ed53eb6 100644 --- a/tools/CustomBuildTool/Source Files/Build.cs +++ b/tools/CustomBuildTool/Source Files/Build.cs @@ -290,19 +290,19 @@ public static void ShowBuildEnvironment(string Platform, bool ShowBuildInfo, boo Program.PrintColorMessage(Environment.NewLine, ConsoleColor.DarkGray, true); - if (!BuildNightly && ShowLogInfo && File.Exists(GitExePath)) - { - Win32.GetConsoleMode(Win32.GetStdHandle(Win32.STD_OUTPUT_HANDLE), out ConsoleMode mode); - Win32.SetConsoleMode(Win32.GetStdHandle(Win32.STD_OUTPUT_HANDLE), mode | ConsoleMode.ENABLE_VIRTUAL_TERMINAL_PROCESSING); - - BuildMessage = Win32.ShellExecute(GitExePath, "log -n 5 --date=format:%Y-%m-%d --pretty=format:\"%C(green)[%cd]%Creset %C(bold blue)%an%Creset %<(65,trunc)%s%Creset %C(#696969)(%Creset%C(yellow)%h%Creset%C(#696969))%Creset\" --abbrev-commit"); - Console.WriteLine(BuildMessage + Environment.NewLine); - - //BuildMessage = Win32.ShellExecute(GitExePath, "log -n 5 --date=format:%Y-%m-%d --pretty=format:\"[%cd] %an %s\" --abbrev-commit"); - //BuildMessage = Win32.ShellExecute(GitExePath, "log -n 1 --date=format:%Y-%m-%d --pretty=format:\"[%cd] %an: %<(65,trunc)%s (%h)\" --abbrev-commit"); - //Console.WriteLine(BuildMessage + Environment.NewLine); - } - + // TODO: The Win10 RS4 release has issues with the git pretty format. + //if (!BuildNightly && ShowLogInfo && File.Exists(GitExePath)) + //{ + // Win32.GetConsoleMode(Win32.GetStdHandle(Win32.STD_OUTPUT_HANDLE), out ConsoleMode mode); + // Win32.SetConsoleMode(Win32.GetStdHandle(Win32.STD_OUTPUT_HANDLE), mode | ConsoleMode.ENABLE_VIRTUAL_TERMINAL_PROCESSING); + // + // BuildMessage = Win32.ShellExecute(GitExePath, "log -n 5 --date=format:%Y-%m-%d --pretty=format:\"%C(green)[%cd]%Creset %C(bold blue)%an%Creset %<(65,trunc)%s%Creset %C(#696969)(%Creset%C(yellow)%h%Creset%C(#696969))%Creset\" --abbrev-commit"); + // Console.WriteLine(BuildMessage + Environment.NewLine); + // + // //BuildMessage = Win32.ShellExecute(GitExePath, "log -n 5 --date=format:%Y-%m-%d --pretty=format:\"[%cd] %an %s\" --abbrev-commit"); + // //BuildMessage = Win32.ShellExecute(GitExePath, "log -n 1 --date=format:%Y-%m-%d --pretty=format:\"[%cd] %an: %<(65,trunc)%s (%h)\" --abbrev-commit"); + // //Console.WriteLine(BuildMessage + Environment.NewLine); + //} } } @@ -1151,6 +1151,8 @@ public static bool BuildSolution(string Solution, BuildFlags Flags) if (Flags.HasFlag(BuildFlags.BuildApi)) compilerOptions.Append("PH_BUILD_API;"); + if (!string.IsNullOrEmpty(BuildCommit)) + compilerOptions.Append("PHAPP_VERSION_COMMITHASH=\"" + BuildCommit.Substring(0, 8) + "\";"); compilerOptions.Append("PHAPP_VERSION_REVISION=\"" + BuildRevision + "\";"); compilerOptions.Append("PHAPP_VERSION_BUILD=\"" + BuildCount + "\""); @@ -1180,6 +1182,8 @@ public static bool BuildSolution(string Solution, BuildFlags Flags) if (Flags.HasFlag(BuildFlags.BuildApi)) compilerOptions.Append("PH_BUILD_API;"); + if (!string.IsNullOrEmpty(BuildCommit)) + compilerOptions.Append("PHAPP_VERSION_COMMITHASH=\"" + BuildCommit.Substring(0, 8) + "\";"); compilerOptions.Append("PHAPP_VERSION_REVISION=\"" + BuildRevision + "\";"); compilerOptions.Append("PHAPP_VERSION_BUILD=\"" + BuildCount + "\""); diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe b/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe index 4487982fe747fadeb0e9e56280d279659592b57e..f2a6424ef1a182497f64f0b7bf11af834bd40103 100644 GIT binary patch delta 14678 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 F{vYA2xn2MO diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb b/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb index b342d4f835a9747699cd02797756925cefda00fc..30eaad40c0eded665c0264b4b3a2138e056b46dd 100644 GIT binary patch delta 7764 zcmZ{p4Ompw*2m8p8DhwR89|0&M4;ir92E!=a5O+oMTI0KKhhGx)B*&h)Ib^35;45u z(vEulzy#Bj1P6me{3t*0mR&8a>}ti6rkVIr`lPq(d*A;)XF#9#dEVjK>$lfh|Gm#X z`<%1q%*Jui&2iDK&dt;R*^rMWlO#!B&wVZFXj$Nh@*3~CwOYp-XAjRl?!MPO(sr%r z7j*r%U)qk0DF`hZ>fI7mpIlA*x_Nl&$_AnxK4ng0k3Y2@U9yaKDi3{4a)B55RE`bg zq^B0RtxQTB(jlPe zMl{=r`fU_5{8!xg%b4k!%UaHR+HXj)OC=4RlfQ7x?CHa2=ggSrYSl+8Np&a(;dkgn zZ`p|LK@q)Kw4yh2l{@PAcqju`>rdcZ;yJmuCF~l+IZ%jfJn9|83Px-eis;D7rMyEILhecYu(vg=8rtvBt;i;!-qFux)T0phLE};UoXw^eky(gX5t+-2Y&I_u zsX`}($h-}VdJ�eHA+{+ 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 delta 7892 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 Date: Sun, 18 Mar 2018 19:34:10 +1100 Subject: [PATCH 0850/2058] SetupTool: Use macro --- tools/CustomSetupTool/CustomSetupTool/appsup.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/tools/CustomSetupTool/CustomSetupTool/appsup.c b/tools/CustomSetupTool/CustomSetupTool/appsup.c index 2cd9a5c4037f..d387a3f9a115 100644 --- a/tools/CustomSetupTool/CustomSetupTool/appsup.c +++ b/tools/CustomSetupTool/CustomSetupTool/appsup.c @@ -464,12 +464,9 @@ static BOOLEAN NTAPI PhpPreviousInstancesCallback( return TRUE; } - if (NT_SUCCESS(NtQueryMutant( + if (NT_SUCCESS(PhGetMutantOwnerInformation( objectHandle, - MutantOwnerInformation, - &objectInfo, - sizeof(MUTANT_OWNER_INFORMATION), - NULL + &objectInfo ))) { HWND hwnd; From 4ab5d8b4d16c6d051b9921f09d9253eb3ff43e83 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 18 Mar 2018 19:37:20 +1100 Subject: [PATCH 0851/2058] Update About window, Add commit hash, Update URL prefixes to https, Update copyright year --- ProcessHacker/ProcessHacker.rc | 4 ++-- ProcessHacker/about.c | 14 ++++++++------ ProcessHacker/include/phappres.h | 6 ++++++ 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/ProcessHacker/ProcessHacker.rc b/ProcessHacker/ProcessHacker.rc index f595f2b01605..972a27af58b2 100644 --- a/ProcessHacker/ProcessHacker.rc +++ b/ProcessHacker/ProcessHacker.rc @@ -611,9 +611,9 @@ BEGIN ICON IDI_PROCESSHACKER,IDC_STATIC,16,15,20,20 LTEXT "Process Hacker",IDC_ABOUT_NAME,45,14,192,8 LTEXT "Licensed under the GNU GPL, v3.",IDC_STATIC,45,27,193,8 - LTEXT "Copyright (c) 2008-2017",IDC_STATIC,45,40,80,8 + LTEXT "Copyright (c) 2008-2018",IDC_STATIC,45,40,80,8 CONTROL "Credits.",IDC_CREDITS,"SysLink",WS_TABSTOP,15,55,248,115 - CONTROL "Process Hacker on SourceForge.net",IDC_LINK_SF, + CONTROL "Process Hacker on SourceForge.net",IDC_LINK_SF, "SysLink",WS_TABSTOP,7,177,130,11 PUSHBUTTON "Diagnostics",IDC_DIAGNOSTICS,160,174,50,14 DEFPUSHBUTTON "OK",IDOK,213,174,50,14 diff --git a/ProcessHacker/about.c b/ProcessHacker/about.c index 83a005208958..2339f288e6dd 100644 --- a/ProcessHacker/about.c +++ b/ProcessHacker/about.c @@ -3,7 +3,7 @@ * about dialog * * Copyright (C) 2010-2016 wj32 - * Copyright (C) 2017 dmex + * Copyright (C) 2017-2018 dmex * * This file is part of Process Hacker. * @@ -52,10 +52,11 @@ static INT_PTR CALLBACK PhpAboutDlgProc( #if (PHAPP_VERSION_REVISION != 0) appName = PhFormatString( - L"Process Hacker %u.%u.%u", + L"Process Hacker %u.%u.%u (%hs)", PHAPP_VERSION_MAJOR, PHAPP_VERSION_MINOR, - PHAPP_VERSION_REVISION + PHAPP_VERSION_REVISION, + PHAPP_VERSION_COMMIT ); #else appName = PhFormatString( @@ -75,12 +76,13 @@ static INT_PTR CALLBACK PhpAboutDlgProc( L" XhmikosR\n" L" Donors - thank you for your support!\n\n" L"Process Hacker uses the following components:\n" - L" Mini-XML by Michael Sweet\n" - L" PCRE\n" + L" Mini-XML by Michael Sweet\n" + L" PCRE\n" + L" json-c\n" L" MD5 code by Jouni Malinen\n" L" SHA1 code by Filip Navara, based on code by Steve Reid\n" L" Silk icons\n" - L" Farm-fresh web icons\n" + L" Farm-fresh web icons\n" ); SendMessage(hwndDlg, WM_NEXTDLGCTL, (LPARAM)GetDlgItem(hwndDlg, IDOK), TRUE); diff --git a/ProcessHacker/include/phappres.h b/ProcessHacker/include/phappres.h index c0267bfd3ea9..d019dcd74080 100644 --- a/ProcessHacker/include/phappres.h +++ b/ProcessHacker/include/phappres.h @@ -17,6 +17,10 @@ #define PHAPP_VERSION_REVISION 0 #endif +#ifndef PHAPP_VERSION_COMMITHASH +#define PHAPP_VERSION_COMMITHASH "" +#endif + #if (PHAPP_VERSION_BUILD == 0) #define TWO_DIGIT_VER 1 #else @@ -34,4 +38,6 @@ #define PHAPP_VERSION_NUMBER PHAPP_VERSION_MAJOR,PHAPP_VERSION_MINOR,PHAPP_VERSION_BUILD,PHAPP_VERSION_REVISION +#define PHAPP_VERSION_COMMIT MAKE_STR(PHAPP_VERSION_COMMITHASH) + #endif // PHAPPRES_H From a6fb66d2aa1fae313df848b2a76775f3045c74cf Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 18 Mar 2018 19:39:03 +1100 Subject: [PATCH 0852/2058] Add missing type --- phnt/include/ntmmapi.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/phnt/include/ntmmapi.h b/phnt/include/ntmmapi.h index 2ae1234f5551..f9c37b449fb6 100644 --- a/phnt/include/ntmmapi.h +++ b/phnt/include/ntmmapi.h @@ -136,6 +136,15 @@ typedef struct _MEMORY_REGION_INFORMATION SIZE_T CommitSize; } MEMORY_REGION_INFORMATION, *PMEMORY_REGION_INFORMATION; +// private +typedef enum _MEMORY_WORKING_SET_EX_LOCATION +{ + MemoryLocationInvalid, + MemoryLocationResident, + MemoryLocationPagefile, + MemoryLocationReserved +} MEMORY_WORKING_SET_EX_LOCATION; + // private typedef struct _MEMORY_WORKING_SET_EX_BLOCK { From 2d2a38e1ed0d2810b7cc7292b2ae911ac6489780 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 18 Mar 2018 19:41:50 +1100 Subject: [PATCH 0853/2058] peview: Add export 'hint' column (same as dumpbin /exports) --- phlib/include/mapimg.h | 1 + phlib/mapimg.c | 2 ++ tools/peview/expprp.c | 7 +++++++ 3 files changed, 10 insertions(+) diff --git a/phlib/include/mapimg.h b/phlib/include/mapimg.h index 1293fa34ac3a..32a09d8bd09a 100644 --- a/phlib/include/mapimg.h +++ b/phlib/include/mapimg.h @@ -194,6 +194,7 @@ typedef struct _PH_MAPPED_IMAGE_EXPORTS typedef struct _PH_MAPPED_IMAGE_EXPORT_ENTRY { USHORT Ordinal; + ULONG Hint; PSTR Name; } PH_MAPPED_IMAGE_EXPORT_ENTRY, *PPH_MAPPED_IMAGE_EXPORT_ENTRY; diff --git a/phlib/mapimg.c b/phlib/mapimg.c index 18f226724789..78baa8ed7923 100644 --- a/phlib/mapimg.c +++ b/phlib/mapimg.c @@ -746,10 +746,12 @@ NTSTATUS PhGetMappedImageExportEntry( // TODO: Probe the name. Entry->Name = name; + Entry->Hint = nameIndex; } else { Entry->Name = NULL; + Entry->Hint = 0; } return STATUS_SUCCESS; diff --git a/tools/peview/expprp.c b/tools/peview/expprp.c index 1b521fb12754..aa20fb1c4bba 100644 --- a/tools/peview/expprp.c +++ b/tools/peview/expprp.c @@ -53,6 +53,7 @@ INT_PTR CALLBACK PvpPeExportsDlgProc( PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_RIGHT, 80, L"RVA"); PhAddListViewColumn(lvHandle, 2, 2, 2, LVCFMT_LEFT, 250, L"Name"); PhAddListViewColumn(lvHandle, 3, 3, 3, LVCFMT_LEFT, 50, L"Ordinal"); + PhAddListViewColumn(lvHandle, 4, 4, 4, LVCFMT_LEFT, 50, L"Hint"); PhSetExtendedListView(lvHandle); PhLoadListViewColumnsFromSetting(L"ImageExportsListViewColumns", lvHandle); @@ -152,6 +153,12 @@ INT_PTR CALLBACK PvpPeExportsDlgProc( PhPrintUInt32(number, exportEntry.Ordinal); PhSetListViewSubItem(lvHandle, lvItemIndex, 3, number); + + if (exportEntry.Name) // Note: The 'Hint' is only valid for named exports. + { + PhPrintUInt32(number, exportEntry.Hint); + PhSetListViewSubItem(lvHandle, lvItemIndex, 4, number); + } } } } From 541c605f1dc754cade61f0a640c34040e69c5e9b Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 22 Mar 2018 03:18:37 +1100 Subject: [PATCH 0854/2058] Add workaround for service descriptions based on inf data, Fix typo, Add unused helper functions --- phlib/include/phutil.h | 40 +++++++++++++++++++++++ phlib/util.c | 72 ++++++++++++++++++++++++++++++++++++------ 2 files changed, 102 insertions(+), 10 deletions(-) diff --git a/phlib/include/phutil.h b/phlib/include/phutil.h index 6296d8c2b814..f71159da9ac3 100644 --- a/phlib/include/phutil.h +++ b/phlib/include/phutil.h @@ -1152,6 +1152,46 @@ PhGetLoaderEntryDllBase( _In_opt_ PWSTR DllName ); +PHLIBAPI +NTSTATUS +NTAPI +PhGetLoaderEntryImageNtHeaders( + _In_ PVOID BaseAddress, + _Out_ PIMAGE_NT_HEADERS *ImageNtHeaders + ); + +PHLIBAPI +NTSTATUS +NTAPI +PhGetLoaderEntryImageDirectory( + _In_ PVOID BaseAddress, + _In_ PIMAGE_NT_HEADERS ImageNtHeader, + _In_ ULONG ImageDirectoryIndex, + _Out_ PVOID *ImageDirectoryEntry, + _Out_opt_ SIZE_T *ImageDirectoryLength + ); + +PHLIBAPI +NTSTATUS +NTAPI +PhGetLoaderEntryImageSection( + _In_ PVOID BaseAddress, + _In_ PIMAGE_NT_HEADERS ImageNtHeader, + _In_ PVOID ImageDirectory, + _Out_ PIMAGE_SECTION_HEADER *ImageSection, + _Out_ SIZE_T *ImageSectionLength + ); + +PHLIBAPI +PVOID +NTAPI +PhGetLoaderEntryImageExportFunction( + _In_ PVOID BaseAddress, + _In_ PIMAGE_EXPORT_DIRECTORY ExportDirectory, + _In_opt_ PSTR ExportName, + _In_opt_ USHORT ExportOrdinal + ); + PHLIBAPI NTSTATUS NTAPI diff --git a/phlib/util.c b/phlib/util.c index 2f96846f4347..f0f295ee9800 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -5222,8 +5222,17 @@ PPH_STRING PhLoadIndirectString( if (!PhSplitStringRefAtChar(&sourceRef, L',', &dllNameRef, &dllIndexRef)) return NULL; + if (!PhStringToInteger64(&dllIndexRef, 10, &index64)) - return NULL; + { + // HACK: Services.exe includes custom logic for indirect Service description strings by reading descriptions from inf files, + // these strings use the following format: "@FileName.inf,%SectionKeyName%;DefaultString". + // Return the last token of the service string instead of locating and parsing the inf file with GetPrivateProfileString. + if (dllIndexRef.Buffer[0] == L'%' && PhSplitStringRefAtChar(&sourceRef, L';', &dllNameRef, &dllIndexRef)) + return PhCreateString2(&dllIndexRef); + else + return NULL; + } libraryString = PhCreateString2(&dllNameRef); index = (LONG)index64; @@ -5244,10 +5253,6 @@ PPH_STRING PhLoadIndirectString( PhDereferenceObject(libraryString); } - else - { - //indirectString = PhCreateString(SourceString); - } return indirectString; } @@ -5460,7 +5465,7 @@ NTSTATUS PhGetLoaderEntryImageDirectory( NTSTATUS PhGetLoaderEntryImageSection( _In_ PVOID BaseAddress, _In_ PIMAGE_NT_HEADERS ImageNtHeader, - _In_ PIMAGE_IMPORT_DESCRIPTOR ImageDirectory, + _In_ PVOID ImageDirectory, _Out_ PIMAGE_SECTION_HEADER *ImageSection, _Out_ SIZE_T *ImageSectionLength ) @@ -5495,6 +5500,53 @@ NTSTATUS PhGetLoaderEntryImageSection( return STATUS_SECTION_NOT_IMAGE; } +PVOID PhGetLoaderEntryImageExportFunction( + _In_ PVOID BaseAddress, + _In_ PIMAGE_EXPORT_DIRECTORY ExportDirectory, + _In_opt_ PSTR ExportName, + _In_opt_ USHORT ExportOrdinal + ) +{ + PVOID exportFunction = NULL; + PULONG exportAddressTable; + PULONG exportNameTable; + PUSHORT exportOrdinalTable; + + exportAddressTable = PTR_ADD_OFFSET(BaseAddress, ExportDirectory->AddressOfFunctions); + + if (ExportName) + { + PSTR exportName; + ULONG i; + + exportNameTable = PTR_ADD_OFFSET(BaseAddress, ExportDirectory->AddressOfNames); + + for (i = 0; i < ExportDirectory->NumberOfNames; i++) + { + exportName = PTR_ADD_OFFSET(BaseAddress, exportNameTable[i]); + + if (PhEqualBytesZ(exportName, ExportName, FALSE)) + { + exportFunction = PTR_ADD_OFFSET(BaseAddress, exportAddressTable[i + 1]); + break; + } + } + } + else + { + exportOrdinalTable = PTR_ADD_OFFSET(BaseAddress, ExportDirectory->AddressOfNameOrdinals); + + // TODO: Validate exportFunction and exportAddressTable are located within the image range. + // HACK: I'm not sure which value we're supposed to -1 because the PE spec omits details about OrdinalBase... so just -1 the entire result. (dmex) + exportFunction = PTR_ADD_OFFSET(BaseAddress, exportAddressTable[exportOrdinalTable[ExportOrdinal] - ExportDirectory->Base - 1]); + + //PULONG exportNameTable = PTR_ADD_OFFSET(BaseAddress, ExportDirectory->AddressOfNames); + //PSTR exportName = PTR_ADD_OFFSET(BaseAddress, exportNameTable[exportOrdinalTable[ExportOrdinal] - ExportDirectory->Base - 2]); + } + + return exportFunction; +} + static NTSTATUS PhpFixupLoaderEntryImageImports( _In_ PVOID BaseAddress, _In_ PIMAGE_NT_HEADERS ImageNtHeader @@ -5502,7 +5554,7 @@ static NTSTATUS PhpFixupLoaderEntryImageImports( { NTSTATUS status; SIZE_T importDirectorySize; - ULONG importDirectoryLength; + ULONG importDirectoryProtect; PIMAGE_IMPORT_DESCRIPTOR importDirectory; PIMAGE_SECTION_HEADER importDirectorySection; @@ -5533,7 +5585,7 @@ static NTSTATUS PhpFixupLoaderEntryImageImports( &importDirectorySection, &importDirectorySize, PAGE_READWRITE, - &importDirectoryLength + &importDirectoryProtect ); if (!NT_SUCCESS(status)) @@ -5623,8 +5675,8 @@ static NTSTATUS PhpFixupLoaderEntryImageImports( NtCurrentProcess(), &importDirectorySection, &importDirectorySize, - importDirectoryLength, - &importDirectoryLength + importDirectoryProtect, + &importDirectoryProtect ); if (!NT_SUCCESS(status)) From 0aaa1e2e99665ba3bae18c79ec141093d9a46128 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 22 Mar 2018 05:55:21 +1100 Subject: [PATCH 0855/2058] Fix process module tab columns showing incorrect info for WSL processes --- ProcessHacker/include/modprv.h | 1 + ProcessHacker/modlist.c | 18 ++++++++++++++---- ProcessHacker/modprv.c | 32 ++++++++++++++++++++++++++------ phlib/include/phnative.h | 1 + 4 files changed, 42 insertions(+), 10 deletions(-) diff --git a/ProcessHacker/include/modprv.h b/ProcessHacker/include/modprv.h index 6a47722515bc..84a31c62d85d 100644 --- a/ProcessHacker/include/modprv.h +++ b/ProcessHacker/include/modprv.h @@ -58,6 +58,7 @@ typedef struct _PH_MODULE_PROVIDER struct { BOOLEAN ControlFlowGuardEnabled : 1; + BOOLEAN IsSubsystemProcess : 1; BOOLEAN Spare : 7; }; }; diff --git a/ProcessHacker/modlist.c b/ProcessHacker/modlist.c index 27089f52468a..c5096e12c5ea 100644 --- a/ProcessHacker/modlist.c +++ b/ProcessHacker/modlist.c @@ -709,6 +709,7 @@ BOOLEAN NTAPI PhpModuleTreeNewCallback( typeString = L"Mapped file"; break; case PH_MODULE_TYPE_MAPPED_IMAGE: + case PH_MODULE_TYPE_ELF_MAPPED_IMAGE: typeString = L"Mapped image"; break; case PH_MODULE_TYPE_WOW64_MODULE: @@ -729,7 +730,7 @@ BOOLEAN NTAPI PhpModuleTreeNewCallback( if (moduleItem->Type == PH_MODULE_TYPE_MODULE || moduleItem->Type == PH_MODULE_TYPE_KERNEL_MODULE || moduleItem->Type == PH_MODULE_TYPE_WOW64_MODULE) { - if (moduleItem->LoadCount != (USHORT)-1) + if (moduleItem->LoadCount != USHRT_MAX) { PhPrintInt32(node->LoadCountText, moduleItem->LoadCount); PhInitializeStringRefLongHint(&getCellText->Text, node->LoadCountText); @@ -745,8 +746,17 @@ BOOLEAN NTAPI PhpModuleTreeNewCallback( } break; case PHMOTLC_VERIFICATIONSTATUS: - PhInitializeStringRef(&getCellText->Text, - moduleItem->VerifyResult == VrTrusted ? L"Trusted" : L"Not trusted"); + { + if (moduleItem->Type != PH_MODULE_TYPE_ELF_MAPPED_IMAGE) + { + PhInitializeStringRef(&getCellText->Text, + moduleItem->VerifyResult == VrTrusted ? L"Trusted" : L"Not trusted"); + } + else + { + PhInitializeEmptyStringRef(&getCellText->Text); + } + } break; case PHMOTLC_VERIFIEDSIGNER: getCellText->Text = PhGetStringRef(moduleItem->VerifySignerName); @@ -875,7 +885,7 @@ BOOLEAN NTAPI PhpModuleTreeNewCallback( if (!moduleItem) ; // Dummy - else if (PhEnableProcessQueryStage2 && context->HighlightUntrustedModules && moduleItem->VerifyResult != VrTrusted) + else if (PhEnableProcessQueryStage2 && context->HighlightUntrustedModules && moduleItem->VerifyResult != VrTrusted && moduleItem->Type != PH_MODULE_TYPE_ELF_MAPPED_IMAGE) getNodeColor->BackColor = PhCsColorUnknown; else if (context->HighlightDotNetModules && (moduleItem->Flags & LDRP_COR_IMAGE)) getNodeColor->BackColor = PhCsColorDotNet; diff --git a/ProcessHacker/modprv.c b/ProcessHacker/modprv.c index ec632a63569c..66b26760675f 100644 --- a/ProcessHacker/modprv.c +++ b/ProcessHacker/modprv.c @@ -139,6 +139,16 @@ PPH_MODULE_PROVIDER PhCreateModuleProvider( } } + if (WindowsVersion >= WINDOWS_10 && moduleProvider->ProcessHandle) + { + PROCESS_EXTENDED_BASIC_INFORMATION basicInfo; + + if (NT_SUCCESS(PhGetProcessExtendedBasicInformation(moduleProvider->ProcessHandle, &basicInfo))) + { + moduleProvider->IsSubsystemProcess = !!basicInfo.IsSubsystemProcess; + } + } + RtlInitializeSListHead(&moduleProvider->QueryListHead); PhEmCallObjectOperation(EmModuleProviderType, moduleProvider, EmObjectCreate); @@ -492,12 +502,20 @@ VOID PhModuleProviderUpdate( moduleItem->IsFirst = i == 0; - // Fix up the load count. If this is not an ordinary DLL or kernel module, set the load count to 0. - if (moduleItem->Type != PH_MODULE_TYPE_MODULE && - moduleItem->Type != PH_MODULE_TYPE_WOW64_MODULE && - moduleItem->Type != PH_MODULE_TYPE_KERNEL_MODULE) + if (moduleProvider->IsSubsystemProcess) { - moduleItem->LoadCount = 0; + // HACK: Update the module type. (TODO: Move into PhEnumGenericModules) (dmex) + moduleItem->Type = PH_MODULE_TYPE_ELF_MAPPED_IMAGE; + } + else + { + // Fix up the load count. If this is not an ordinary DLL or kernel module, set the load count to 0. + if (moduleItem->Type != PH_MODULE_TYPE_MODULE && + moduleItem->Type != PH_MODULE_TYPE_WOW64_MODULE && + moduleItem->Type != PH_MODULE_TYPE_KERNEL_MODULE) + { + moduleItem->LoadCount = 0; + } } if (moduleItem->Type == PH_MODULE_TYPE_MODULE || @@ -558,7 +576,8 @@ VOID PhModuleProviderUpdate( } } - PhPrintPointer(moduleItem->EntryPointAddressString, moduleItem->EntryPoint); + if (moduleItem->EntryPoint) + PhPrintPointer(moduleItem->EntryPointAddressString, moduleItem->EntryPoint); // remove CF Guard flag if CFG mitigation is not enabled for the process if (!moduleProvider->ControlFlowGuardEnabled) @@ -574,6 +593,7 @@ VOID PhModuleProviderUpdate( moduleItem->FileEndOfFile.QuadPart = -1; } + if (moduleItem->Type != PH_MODULE_TYPE_ELF_MAPPED_IMAGE) { // See if the file has already been verified; if not, queue for verification. diff --git a/phlib/include/phnative.h b/phlib/include/phnative.h index 6676e3015984..d4e99662962d 100644 --- a/phlib/include/phnative.h +++ b/phlib/include/phnative.h @@ -855,6 +855,7 @@ PhGetFileName( #define PH_MODULE_TYPE_WOW64_MODULE 3 #define PH_MODULE_TYPE_KERNEL_MODULE 4 #define PH_MODULE_TYPE_MAPPED_IMAGE 5 +#define PH_MODULE_TYPE_ELF_MAPPED_IMAGE 6 typedef struct _PH_MODULE_INFO { From 8d6d23b4d6669ee65dd619fe4c86f32aa7154bbf Mon Sep 17 00:00:00 2001 From: diversenok <30962924+diversenok@users.noreply.github.com> Date: Thu, 22 Mar 2018 00:04:47 +0300 Subject: [PATCH 0856/2058] Handling atypical integrity levels (#249) * Handling atypical integrity levels * Renaming menu item --- ProcessHacker/ProcessHacker.def | 1 + ProcessHacker/tokprp.c | 41 ++++++---- phlib/include/phnative.h | 18 +++++ phlib/native.c | 134 ++++++++++++++++++++++---------- 4 files changed, 141 insertions(+), 53 deletions(-) diff --git a/ProcessHacker/ProcessHacker.def b/ProcessHacker/ProcessHacker.def index c9bbe2bba07f..58dd6f1d2ce7 100644 --- a/ProcessHacker/ProcessHacker.def +++ b/ProcessHacker/ProcessHacker.def @@ -278,6 +278,7 @@ EXPORTS PhGetProcessWorkingSetInformation PhGetProcessWsCounters PhGetTokenGroups + PhGetTokenIntegrityLevelRID PhGetTokenIntegrityLevel PhGetTokenOwner PhGetTokenPrimaryGroup diff --git a/ProcessHacker/tokprp.c b/ProcessHacker/tokprp.c index bd25d2346d1f..0b09b993f8ed 100644 --- a/ProcessHacker/tokprp.c +++ b/ProcessHacker/tokprp.c @@ -922,20 +922,20 @@ INT_PTR CALLBACK PhpTokenPageProc( RECT rect; PPH_EMENU menu; HANDLE tokenHandle; - MANDATORY_LEVEL integrityLevel; + MANDATORY_LEVEL_RID integrityLevelRID; PPH_EMENU_ITEM selectedItem; GetWindowRect(GetDlgItem(hwndDlg, IDC_INTEGRITY), &rect); menu = PhCreateEMenu(); - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, MandatoryLevelSecureProcess, L"Protected", NULL, NULL), -1); - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, MandatoryLevelSystem, L"System", NULL, NULL), -1); - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, MandatoryLevelHigh, L"High", NULL, NULL), -1); - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, MandatoryLevelMedium, L"Medium", NULL, NULL), -1); - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, MandatoryLevelLow, L"Low", NULL, NULL), -1); - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, MandatoryLevelUntrusted, L"Untrusted", NULL, NULL), -1); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, MandatorySecureProcessRID, L"Protected", NULL, NULL), -1); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, MandatorySystemRID, L"System", NULL, NULL), -1); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, MandatoryHighRID, L"High", NULL, NULL), -1); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, MandatoryMediumRID, L"Medium", NULL, NULL), -1); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, MandatoryLowRID, L"Low", NULL, NULL), -1); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, MandatoryUntrustedRID, L"Untrusted", NULL, NULL), -1); - integrityLevel = -1; + integrityLevelRID = -1; // Put a radio check on the menu item that corresponds with the current integrity level. // Also disable menu items which correspond to higher integrity levels since @@ -946,25 +946,38 @@ INT_PTR CALLBACK PhpTokenPageProc( tokenPageContext->Context ))) { - if (NT_SUCCESS(status = PhGetTokenIntegrityLevel( + if (NT_SUCCESS(status = PhGetTokenIntegrityLevelRID( tokenHandle, - &integrityLevel, + &integrityLevelRID, NULL ))) { + ULONG customLevelPosition = 0; // Processing atypical integrity levels + for (ULONG i = 0; i < menu->Items->Count; i++) { PPH_EMENU_ITEM menuItem = menu->Items->Items[i]; - if (menuItem->Id == (ULONG)integrityLevel) + if (menuItem->Id == (ULONG)integrityLevelRID) { menuItem->Flags |= PH_EMENU_CHECKED | PH_EMENU_RADIOCHECK; + customLevelPosition = 0; // The integrity level is a well-known one. No need to add a new menu item. } - else if (menuItem->Id > (ULONG)integrityLevel) + else if (menuItem->Id > (ULONG)integrityLevelRID) { menuItem->Flags |= PH_EMENU_DISABLED; + customLevelPosition = i + 1; } } + + if (customLevelPosition) + { + PPH_EMENU_ITEM unknownIntegrityItem; + + unknownIntegrityItem = PhCreateEMenuItem(0, (ULONG)integrityLevelRID, L"Intermediate level", NULL, NULL); + unknownIntegrityItem->Flags |= PH_EMENU_CHECKED | PH_EMENU_RADIOCHECK; + PhInsertEMenuItem(menu, unknownIntegrityItem, customLevelPosition); + } } NtClose(tokenHandle); @@ -988,7 +1001,7 @@ INT_PTR CALLBACK PhpTokenPageProc( rect.bottom ); - if (selectedItem && selectedItem->Id != integrityLevel) + if (selectedItem && selectedItem->Id != integrityLevelRID) { if (PhShowConfirmMessage( hwndDlg, @@ -1012,7 +1025,7 @@ INT_PTR CALLBACK PhpTokenPageProc( newSid = (PSID)newSidBuffer; RtlInitializeSid(newSid, &mandatoryLabelAuthority, 1); - *RtlSubAuthoritySid(newSid, 0) = MANDATORY_LEVEL_TO_MANDATORY_RID(selectedItem->Id); + *RtlSubAuthoritySid(newSid, 0) = selectedItem->Id; mandatoryLabel.Label.Sid = newSid; mandatoryLabel.Label.Attributes = SE_GROUP_INTEGRITY; diff --git a/phlib/include/phnative.h b/phlib/include/phnative.h index d4e99662962d..49ca8ba7be97 100644 --- a/phlib/include/phnative.h +++ b/phlib/include/phnative.h @@ -44,6 +44,15 @@ typedef struct _PH_TOKEN_ATTRIBUTES ULONG Reserved; } PH_TOKEN_ATTRIBUTES, *PPH_TOKEN_ATTRIBUTES; +typedef enum _MANDATORY_LEVEL_RID { + MandatoryUntrustedRID = SECURITY_MANDATORY_UNTRUSTED_RID, + MandatoryLowRID = SECURITY_MANDATORY_LOW_RID, + MandatoryMediumRID = SECURITY_MANDATORY_MEDIUM_RID, + MandatoryHighRID = SECURITY_MANDATORY_HIGH_RID, + MandatorySystemRID = SECURITY_MANDATORY_SYSTEM_RID, + MandatorySecureProcessRID = SECURITY_MANDATORY_PROTECTED_PROCESS_RID +} MANDATORY_LEVEL_RID, *PMANDATORY_LEVEL_RID; + PHLIBAPI PH_TOKEN_ATTRIBUTES NTAPI @@ -399,6 +408,15 @@ PhSetTokenIsVirtualizationEnabled( _In_ BOOLEAN IsVirtualizationEnabled ); +PHLIBAPI +NTSTATUS +NTAPI +PhGetTokenIntegrityLevelRID( + _In_ HANDLE TokenHandle, + _Out_opt_ PMANDATORY_LEVEL_RID IntegrityLevelRID, + _Out_opt_ PWSTR *IntegrityString + ); + PHLIBAPI NTSTATUS NTAPI diff --git a/phlib/native.c b/phlib/native.c index d68af22a6183..fa9e91bef515 100644 --- a/phlib/native.c +++ b/phlib/native.c @@ -2001,11 +2001,78 @@ NTSTATUS PhSetTokenIsVirtualizationEnabled( ); } +/** +* Gets a token's integrity level RID. Can handle custom integrity levels. +* +* \param TokenHandle A handle to a token. The handle must have TOKEN_QUERY access. +* \param IntegrityLevelRID A variable which receives the integrity level of the token. +* \param IntegrityString A variable which receives a pointer to a string containing a string +* representation of the integrity level. +*/ +NTSTATUS PhGetTokenIntegrityLevelRID( + _In_ HANDLE TokenHandle, + _Out_opt_ PMANDATORY_LEVEL_RID IntegrityLevelRID, + _Out_opt_ PWSTR *IntegrityString +) +{ + NTSTATUS status; + PTOKEN_MANDATORY_LABEL mandatoryLabel; + ULONG subAuthority; + PWSTR integrityString; + + status = PhpQueryTokenVariableSize(TokenHandle, TokenIntegrityLevel, &mandatoryLabel); + + if (!NT_SUCCESS(status)) + return status; + + subAuthority = *RtlSubAuthoritySid(mandatoryLabel->Label.Sid, 0); + PhFree(mandatoryLabel); + + if (IntegrityString) + { + switch (subAuthority) + { + case SECURITY_MANDATORY_UNTRUSTED_RID: + integrityString = L"Untrusted"; + break; + case SECURITY_MANDATORY_LOW_RID: + integrityString = L"Low"; + break; + case SECURITY_MANDATORY_MEDIUM_RID: + integrityString = L"Medium"; + break; + case SECURITY_MANDATORY_MEDIUM_PLUS_RID: + integrityString = L"Medium +"; + break; + case SECURITY_MANDATORY_HIGH_RID: + integrityString = L"High"; + break; + case SECURITY_MANDATORY_SYSTEM_RID: + integrityString = L"System"; + break; + case SECURITY_MANDATORY_PROTECTED_PROCESS_RID: + integrityString = L"Protected"; + break; + default: + integrityString = L"Other"; + break; + } + + *IntegrityString = integrityString; + } + + if (IntegrityLevelRID) + *IntegrityLevelRID = subAuthority; + + return status; +} + /** * Gets a token's integrity level. * * \param TokenHandle A handle to a token. The handle must have TOKEN_QUERY access. * \param IntegrityLevel A variable which receives the integrity level of the token. + * If the integrity level is not a well-known one the function fails. * \param IntegrityString A variable which receives a pointer to a string containing a string * representation of the integrity level. */ @@ -2016,54 +2083,43 @@ NTSTATUS PhGetTokenIntegrityLevel( ) { NTSTATUS status; - PTOKEN_MANDATORY_LABEL mandatoryLabel; - ULONG subAuthority; + MANDATORY_LEVEL_RID integrityLevelRID; MANDATORY_LEVEL integrityLevel; - PWSTR integrityString; - status = PhpQueryTokenVariableSize(TokenHandle, TokenIntegrityLevel, &mandatoryLabel); + status = PhGetTokenIntegrityLevelRID(TokenHandle, &integrityLevelRID, IntegrityString); if (!NT_SUCCESS(status)) return status; - subAuthority = *RtlSubAuthoritySid(mandatoryLabel->Label.Sid, 0); - PhFree(mandatoryLabel); - - switch (subAuthority) + if (IntegrityLevel) { - case SECURITY_MANDATORY_UNTRUSTED_RID: - integrityLevel = MandatoryLevelUntrusted; - integrityString = L"Untrusted"; - break; - case SECURITY_MANDATORY_LOW_RID: - integrityLevel = MandatoryLevelLow; - integrityString = L"Low"; - break; - case SECURITY_MANDATORY_MEDIUM_RID: - integrityLevel = MandatoryLevelMedium; - integrityString = L"Medium"; - break; - case SECURITY_MANDATORY_HIGH_RID: - integrityLevel = MandatoryLevelHigh; - integrityString = L"High"; - break; - case SECURITY_MANDATORY_SYSTEM_RID: - integrityLevel = MandatoryLevelSystem; - integrityString = L"System"; - break; - case SECURITY_MANDATORY_PROTECTED_PROCESS_RID: - integrityLevel = MandatoryLevelSecureProcess; - integrityString = L"Protected"; - break; - default: - return STATUS_UNSUCCESSFUL; - } + switch (integrityLevelRID) + { + case SECURITY_MANDATORY_UNTRUSTED_RID: + integrityLevel = MandatoryLevelUntrusted; + break; + case SECURITY_MANDATORY_LOW_RID: + integrityLevel = MandatoryLevelLow; + break; + case SECURITY_MANDATORY_MEDIUM_RID: + integrityLevel = MandatoryLevelMedium; + break; + case SECURITY_MANDATORY_HIGH_RID: + integrityLevel = MandatoryLevelHigh; + break; + case SECURITY_MANDATORY_SYSTEM_RID: + integrityLevel = MandatoryLevelSystem; + break; + case SECURITY_MANDATORY_PROTECTED_PROCESS_RID: + integrityLevel = MandatoryLevelSecureProcess; + break; + default: + return STATUS_UNSUCCESSFUL; + } - if (IntegrityLevel) *IntegrityLevel = integrityLevel; - if (IntegrityString) - *IntegrityString = integrityString; - + } + return status; } From ee1d88aef90b97c08ce36ee9d5e9e54c72e75f56 Mon Sep 17 00:00:00 2001 From: Anton Sosnin Date: Fri, 23 Mar 2018 16:48:06 +0700 Subject: [PATCH 0857/2058] Fix bringing to front minimized window (#250) --- plugins/WindowExplorer/wnddlg.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/plugins/WindowExplorer/wnddlg.c b/plugins/WindowExplorer/wnddlg.c index 4ab23fe9a491..f10007c9cc2b 100644 --- a/plugins/WindowExplorer/wnddlg.c +++ b/plugins/WindowExplorer/wnddlg.c @@ -558,10 +558,12 @@ INT_PTR CALLBACK WepWindowsDlgProc( GetWindowPlacement(selectedNode->WindowHandle, &placement); - if (placement.showCmd == SW_MINIMIZE) + if (placement.showCmd == SW_SHOWMINIMIZED) + { ShowWindowAsync(selectedNode->WindowHandle, SW_RESTORE); - else - SetForegroundWindow(selectedNode->WindowHandle); + } + + SetForegroundWindow(selectedNode->WindowHandle); } } break; From 361bfe85ba39f1c851ced694a82a9dfcb5b0300e Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 25 Mar 2018 04:55:49 +1100 Subject: [PATCH 0858/2058] peview: Add image section characteristics to the general tab --- tools/peview/peprp.c | 558 +++++++++++++++++++++++++++---------------- 1 file changed, 348 insertions(+), 210 deletions(-) diff --git a/tools/peview/peprp.c b/tools/peview/peprp.c index b448a5938bc6..6dbc0546672c 100644 --- a/tools/peview/peprp.c +++ b/tools/peview/peprp.c @@ -3,7 +3,7 @@ * PE viewer * * Copyright (C) 2010-2011 wj32 - * Copyright (C) 2017 dmex + * Copyright (C) 2017-2018 dmex * * This file is part of Process Hacker. * @@ -307,214 +307,364 @@ FORCEINLINE PWSTR PvpGetStringOrNa( return L"N/A"; } -INT_PTR CALLBACK PvpPeGeneralDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam +FORCEINLINE PPH_STRING PvpGetSectionCharacteristics( + _In_ ULONG Characteristics ) { - LPPROPSHEETPAGE propSheetPage; - PPV_PROPPAGECONTEXT propPageContext; + PH_STRING_BUILDER stringBuilder; + WCHAR pointer[PH_PTR_STR_LEN_1]; + + PhInitializeStringBuilder(&stringBuilder, 10); + + if (Characteristics & IMAGE_SCN_TYPE_NO_PAD) + PhAppendStringBuilder2(&stringBuilder, L"No Padding, "); + if (Characteristics & IMAGE_SCN_CNT_CODE) + PhAppendStringBuilder2(&stringBuilder, L"Code, "); + if (Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA) + PhAppendStringBuilder2(&stringBuilder, L"Initialized data, "); + if (Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA) + PhAppendStringBuilder2(&stringBuilder, L"Uninitialized data, "); + if (Characteristics & IMAGE_SCN_LNK_INFO) + PhAppendStringBuilder2(&stringBuilder, L"Comments, "); + if (Characteristics & IMAGE_SCN_LNK_REMOVE) + PhAppendStringBuilder2(&stringBuilder, L"Excluded, "); + if (Characteristics & IMAGE_SCN_LNK_COMDAT) + PhAppendStringBuilder2(&stringBuilder, L"COMDAT, "); + if (Characteristics & IMAGE_SCN_NO_DEFER_SPEC_EXC) + PhAppendStringBuilder2(&stringBuilder, L"Speculative exceptions, "); + if (Characteristics & IMAGE_SCN_GPREL) + PhAppendStringBuilder2(&stringBuilder, L"GP relative, "); + if (Characteristics & IMAGE_SCN_MEM_PURGEABLE) + PhAppendStringBuilder2(&stringBuilder, L"Purgeable, "); + if (Characteristics & IMAGE_SCN_MEM_LOCKED) + PhAppendStringBuilder2(&stringBuilder, L"Locked, "); + if (Characteristics & IMAGE_SCN_MEM_PRELOAD) + PhAppendStringBuilder2(&stringBuilder, L"Preload, "); + if (Characteristics & IMAGE_SCN_LNK_NRELOC_OVFL) + PhAppendStringBuilder2(&stringBuilder, L"Extended relocations, "); + if (Characteristics & IMAGE_SCN_MEM_DISCARDABLE) + PhAppendStringBuilder2(&stringBuilder, L"Discardable, "); + if (Characteristics & IMAGE_SCN_MEM_NOT_CACHED) + PhAppendStringBuilder2(&stringBuilder, L"Not cachable, "); + if (Characteristics & IMAGE_SCN_MEM_NOT_PAGED) + PhAppendStringBuilder2(&stringBuilder, L"Not pageable, "); + if (Characteristics & IMAGE_SCN_MEM_SHARED) + PhAppendStringBuilder2(&stringBuilder, L"Shareable, "); + if (Characteristics & IMAGE_SCN_MEM_EXECUTE) + PhAppendStringBuilder2(&stringBuilder, L"Executable, "); + if (Characteristics & IMAGE_SCN_MEM_READ) + PhAppendStringBuilder2(&stringBuilder, L"Readable, "); + if (Characteristics & IMAGE_SCN_MEM_WRITE) + PhAppendStringBuilder2(&stringBuilder, L"Writeable, "); + + if (PhEndsWithString2(stringBuilder.String, L", ", FALSE)) + PhRemoveEndStringBuilder(&stringBuilder, 2); + + PhPrintPointer(pointer, (PVOID)(ULONG_PTR)Characteristics); + PhAppendFormatStringBuilder(&stringBuilder, L" (%s)", pointer); + + return PhFinalStringBuilderString(&stringBuilder); +} - if (!PvPropPageDlgProcHeader(hwndDlg, uMsg, lParam, &propSheetPage, &propPageContext)) - return FALSE; +VOID PvpSetPeImageVersionInfo( + _In_ HWND WindowHandle + ) +{ + PPH_STRING string; - switch (uMsg) + PhInitializeImageVersionInfo(&PvImageVersionInfo, PvFileName->Buffer); + + if (!PhExtractIcon( + PvFileName->Buffer, + &PvImageLargeIcon, + NULL + )) { - case WM_INITDIALOG: - { - HWND lvHandle; - ULONG i; - PPH_STRING string; - PWSTR type; - PH_STRING_BUILDER stringBuilder; + PvImageLargeIcon = PhGetFileShellIcon(PvFileName->Buffer, NULL, TRUE); + } - // File version information + if (PvImageLargeIcon) + { + SendMessage(GetDlgItem(WindowHandle, IDC_FILEICON), STM_SETICON, (WPARAM)PvImageLargeIcon, 0); + } - { - PhInitializeImageVersionInfo(&PvImageVersionInfo, PvFileName->Buffer); + string = PhConcatStrings2(L"(Verifying...) ", PvpGetStringOrNa(PvImageVersionInfo.CompanyName)); - if (!PhExtractIcon( - PvFileName->Buffer, - &PvImageLargeIcon, - NULL - )) - { - PvImageLargeIcon = PhGetFileShellIcon(PvFileName->Buffer, NULL, TRUE); - } + SetDlgItemText(WindowHandle, IDC_NAME, PvpGetStringOrNa(PvImageVersionInfo.FileDescription)); + SetDlgItemText(WindowHandle, IDC_COMPANYNAME, string->Buffer); + SetDlgItemText(WindowHandle, IDC_VERSION, PvpGetStringOrNa(PvImageVersionInfo.FileVersion)); - SendMessage(GetDlgItem(hwndDlg, IDC_FILEICON), STM_SETICON, (WPARAM)PvImageLargeIcon, 0); + PhQueueItemWorkQueue(PhGetGlobalWorkQueue(), VerifyImageThreadStart, WindowHandle); - SetDlgItemText(hwndDlg, IDC_NAME, PvpGetStringOrNa(PvImageVersionInfo.FileDescription)); - string = PhConcatStrings2(L"(Verifying...) ", PvpGetStringOrNa(PvImageVersionInfo.CompanyName)); - SetDlgItemText(hwndDlg, IDC_COMPANYNAME, string->Buffer); - PhDereferenceObject(string); - SetDlgItemText(hwndDlg, IDC_VERSION, PvpGetStringOrNa(PvImageVersionInfo.FileVersion)); + PhDereferenceObject(string); +} - PhQueueItemWorkQueue(PhGetGlobalWorkQueue(), VerifyImageThreadStart, hwndDlg); - } +VOID PvpSetPeImageMachineType( + _In_ HWND WindowHandle + ) +{ + PWSTR type; - // PE properties + switch (PvMappedImage.NtHeaders->FileHeader.Machine) + { + case IMAGE_FILE_MACHINE_I386: + type = L"i386"; + break; + case IMAGE_FILE_MACHINE_AMD64: + type = L"AMD64"; + break; + case IMAGE_FILE_MACHINE_IA64: + type = L"IA64"; + break; + case IMAGE_FILE_MACHINE_ARMNT: + type = L"ARM Thumb-2"; + break; + default: + type = L"Unknown"; + break; + } - switch (PvMappedImage.NtHeaders->FileHeader.Machine) - { - case IMAGE_FILE_MACHINE_I386: - type = L"i386"; - break; - case IMAGE_FILE_MACHINE_AMD64: - type = L"AMD64"; - break; - case IMAGE_FILE_MACHINE_IA64: - type = L"IA64"; - break; - case IMAGE_FILE_MACHINE_ARMNT: - type = L"ARM Thumb-2"; - break; - default: - type = L"Unknown"; - break; - } + SetDlgItemText(WindowHandle, IDC_TARGETMACHINE, type); +} - SetDlgItemText(hwndDlg, IDC_TARGETMACHINE, type); +VOID PvpSetPeImageTimeStamp( + _In_ HWND WindowHandle + ) +{ + LARGE_INTEGER time; + SYSTEMTIME systemTime; + PPH_STRING string; - { - LARGE_INTEGER time; - SYSTEMTIME systemTime; + RtlSecondsSince1970ToTime(PvMappedImage.NtHeaders->FileHeader.TimeDateStamp, &time); + PhLargeIntegerToLocalSystemTime(&systemTime, &time); - RtlSecondsSince1970ToTime(PvMappedImage.NtHeaders->FileHeader.TimeDateStamp, &time); - PhLargeIntegerToLocalSystemTime(&systemTime, &time); + string = PhFormatDateTime(&systemTime); + SetDlgItemText(WindowHandle, IDC_TIMESTAMP, string->Buffer); + PhDereferenceObject(string); +} - string = PhFormatDateTime(&systemTime); - SetDlgItemText(hwndDlg, IDC_TIMESTAMP, string->Buffer); - PhDereferenceObject(string); - } +VOID PvpSetPeImageBaseAddress( + _In_ HWND WindowHandle + ) +{ + PPH_STRING string; - if (PvMappedImage.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) - { - string = PhFormatString(L"0x%I32x", ((PIMAGE_OPTIONAL_HEADER32)&PvMappedImage.NtHeaders->OptionalHeader)->ImageBase); - } - else - { - string = PhFormatString(L"0x%I64x", ((PIMAGE_OPTIONAL_HEADER64)&PvMappedImage.NtHeaders->OptionalHeader)->ImageBase); - } + if (PvMappedImage.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) + string = PhFormatString(L"0x%I32x", ((PIMAGE_OPTIONAL_HEADER32)&PvMappedImage.NtHeaders->OptionalHeader)->ImageBase); + else + string = PhFormatString(L"0x%I64x", ((PIMAGE_OPTIONAL_HEADER64)&PvMappedImage.NtHeaders->OptionalHeader)->ImageBase); - SetDlgItemText(hwndDlg, IDC_IMAGEBASE, string->Buffer); - PhDereferenceObject(string); + SetDlgItemText(WindowHandle, IDC_IMAGEBASE, string->Buffer); + PhDereferenceObject(string); +} - if (PvMappedImage.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) - { - string = PhFormatString(L"0x%I32x", ((PIMAGE_OPTIONAL_HEADER32)&PvMappedImage.NtHeaders->OptionalHeader)->AddressOfEntryPoint); - } - else - { - string = PhFormatString(L"0x%I64x", ((PIMAGE_OPTIONAL_HEADER64)&PvMappedImage.NtHeaders->OptionalHeader)->AddressOfEntryPoint); - } +VOID PvpSetPeImageEntryPoint( + _In_ HWND WindowHandle + ) +{ + PPH_STRING string; - SetDlgItemText(hwndDlg, IDC_ENTRYPOINT, string->Buffer); - PhDereferenceObject(string); + if (PvMappedImage.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) + string = PhFormatString(L"0x%I32x", ((PIMAGE_OPTIONAL_HEADER32)&PvMappedImage.NtHeaders->OptionalHeader)->AddressOfEntryPoint); + else + string = PhFormatString(L"0x%I64x", ((PIMAGE_OPTIONAL_HEADER64)&PvMappedImage.NtHeaders->OptionalHeader)->AddressOfEntryPoint); - string = PhFormatString(L"0x%Ix (verifying...)", PvMappedImage.NtHeaders->OptionalHeader.CheckSum); // same for 32-bit and 64-bit images - SetDlgItemText(hwndDlg, IDC_CHECKSUM, string->Buffer); - PhDereferenceObject(string); + SetDlgItemText(WindowHandle, IDC_ENTRYPOINT, string->Buffer); + PhDereferenceObject(string); +} - PhQueueItemWorkQueue(PhGetGlobalWorkQueue(), CheckSumImageThreadStart, hwndDlg); +VOID PvpSetPeImageCheckSum( + _In_ HWND WindowHandle + ) +{ + PPH_STRING string; - switch (PvMappedImage.NtHeaders->OptionalHeader.Subsystem) - { - case IMAGE_SUBSYSTEM_NATIVE: - type = L"Native"; - break; - case IMAGE_SUBSYSTEM_WINDOWS_GUI: - type = L"Windows GUI"; - break; - case IMAGE_SUBSYSTEM_WINDOWS_CUI: - type = L"Windows CUI"; - break; - case IMAGE_SUBSYSTEM_OS2_CUI: - type = L"OS/2 CUI"; - break; - case IMAGE_SUBSYSTEM_POSIX_CUI: - type = L"POSIX CUI"; - break; - case IMAGE_SUBSYSTEM_WINDOWS_CE_GUI: - type = L"Windows CE CUI"; - break; - case IMAGE_SUBSYSTEM_EFI_APPLICATION: - type = L"EFI Application"; - break; - case IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER: - type = L"EFI Boot Service Driver"; - break; - case IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER: - type = L"EFI Runtime Driver"; - break; - case IMAGE_SUBSYSTEM_EFI_ROM: - type = L"EFI ROM"; - break; - case IMAGE_SUBSYSTEM_XBOX: - type = L"Xbox"; - break; - case IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION: - type = L"Windows Boot Application"; - break; - default: - type = L"Unknown"; - break; - } + string = PhFormatString(L"0x%Ix (verifying...)", PvMappedImage.NtHeaders->OptionalHeader.CheckSum); // same for 32-bit and 64-bit images + + SetDlgItemText(WindowHandle, IDC_CHECKSUM, string->Buffer); + + PhQueueItemWorkQueue(PhGetGlobalWorkQueue(), CheckSumImageThreadStart, WindowHandle); + + PhDereferenceObject(string); +} + +VOID PvpSetPeImageSubsystem( + _In_ HWND WindowHandle + ) +{ + PWSTR type; + + switch (PvMappedImage.NtHeaders->OptionalHeader.Subsystem) + { + case IMAGE_SUBSYSTEM_NATIVE: + type = L"Native"; + break; + case IMAGE_SUBSYSTEM_WINDOWS_GUI: + type = L"Windows GUI"; + break; + case IMAGE_SUBSYSTEM_WINDOWS_CUI: + type = L"Windows CUI"; + break; + case IMAGE_SUBSYSTEM_OS2_CUI: + type = L"OS/2 CUI"; + break; + case IMAGE_SUBSYSTEM_POSIX_CUI: + type = L"POSIX CUI"; + break; + case IMAGE_SUBSYSTEM_WINDOWS_CE_GUI: + type = L"Windows CE CUI"; + break; + case IMAGE_SUBSYSTEM_EFI_APPLICATION: + type = L"EFI Application"; + break; + case IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER: + type = L"EFI Boot Service Driver"; + break; + case IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER: + type = L"EFI Runtime Driver"; + break; + case IMAGE_SUBSYSTEM_EFI_ROM: + type = L"EFI ROM"; + break; + case IMAGE_SUBSYSTEM_XBOX: + type = L"Xbox"; + break; + case IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION: + type = L"Windows Boot Application"; + break; + default: + type = L"Unknown"; + break; + } - SetDlgItemText(hwndDlg, IDC_SUBSYSTEM, type); - SetDlgItemText(hwndDlg, IDC_SUBSYSTEMVERSION, PhaFormatString( - L"%u.%u", - PvMappedImage.NtHeaders->OptionalHeader.MajorSubsystemVersion, // same for 32-bit and 64-bit images - PvMappedImage.NtHeaders->OptionalHeader.MinorSubsystemVersion - )->Buffer); - - PhInitializeStringBuilder(&stringBuilder, 10); - - if (PvMappedImage.NtHeaders->FileHeader.Characteristics & IMAGE_FILE_EXECUTABLE_IMAGE) - PhAppendStringBuilder2(&stringBuilder, L"Executable, "); - if (PvMappedImage.NtHeaders->FileHeader.Characteristics & IMAGE_FILE_DLL) - PhAppendStringBuilder2(&stringBuilder, L"DLL, "); - if (PvMappedImage.NtHeaders->FileHeader.Characteristics & IMAGE_FILE_LARGE_ADDRESS_AWARE) - PhAppendStringBuilder2(&stringBuilder, L"Large address aware, "); - if (PvMappedImage.NtHeaders->FileHeader.Characteristics & IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP) - PhAppendStringBuilder2(&stringBuilder, L"Removable run from swap, "); - if (PvMappedImage.NtHeaders->FileHeader.Characteristics & IMAGE_FILE_NET_RUN_FROM_SWAP) - PhAppendStringBuilder2(&stringBuilder, L"Net run from swap, "); - if (PvMappedImage.NtHeaders->FileHeader.Characteristics & IMAGE_FILE_SYSTEM) - PhAppendStringBuilder2(&stringBuilder, L"System, "); - if (PvMappedImage.NtHeaders->FileHeader.Characteristics & IMAGE_FILE_UP_SYSTEM_ONLY) - PhAppendStringBuilder2(&stringBuilder, L"Uni-processor only, "); - - if (PvMappedImage.NtHeaders->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA) - PhAppendStringBuilder2(&stringBuilder, L"High entropy VA, "); - if (PvMappedImage.NtHeaders->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE) - PhAppendStringBuilder2(&stringBuilder, L"Dynamic base, "); - if (PvMappedImage.NtHeaders->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY) - PhAppendStringBuilder2(&stringBuilder, L"Force integrity check, "); - if (PvMappedImage.NtHeaders->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_NX_COMPAT) - PhAppendStringBuilder2(&stringBuilder, L"NX compatible, "); - if (PvMappedImage.NtHeaders->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_NO_ISOLATION) - PhAppendStringBuilder2(&stringBuilder, L"No isolation, "); - if (PvMappedImage.NtHeaders->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_NO_SEH) - PhAppendStringBuilder2(&stringBuilder, L"No SEH, "); - if (PvMappedImage.NtHeaders->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_NO_BIND) - PhAppendStringBuilder2(&stringBuilder, L"Do not bind, "); - if (PvMappedImage.NtHeaders->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_APPCONTAINER) - PhAppendStringBuilder2(&stringBuilder, L"AppContainer, "); - if (PvMappedImage.NtHeaders->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_WDM_DRIVER) - PhAppendStringBuilder2(&stringBuilder, L"WDM driver, "); - if (PvMappedImage.NtHeaders->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_GUARD_CF) - PhAppendStringBuilder2(&stringBuilder, L"Control Flow Guard, "); - if (PvMappedImage.NtHeaders->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE) - PhAppendStringBuilder2(&stringBuilder, L"Terminal server aware, "); - - if (PhEndsWithString2(stringBuilder.String, L", ", FALSE)) - PhRemoveEndStringBuilder(&stringBuilder, 2); - - SetDlgItemText(hwndDlg, IDC_CHARACTERISTICS, stringBuilder.String->Buffer); - PhDeleteStringBuilder(&stringBuilder); + SetDlgItemText(WindowHandle, IDC_SUBSYSTEM, type); + SetDlgItemText(WindowHandle, IDC_SUBSYSTEMVERSION, PhaFormatString( + L"%u.%u", + PvMappedImage.NtHeaders->OptionalHeader.MajorSubsystemVersion, // same for 32-bit and 64-bit images + PvMappedImage.NtHeaders->OptionalHeader.MinorSubsystemVersion + )->Buffer); +} + +VOID PvpSetPeImageCharacteristics( + _In_ HWND WindowHandle + ) +{ + PH_STRING_BUILDER stringBuilder; + + PhInitializeStringBuilder(&stringBuilder, 10); + + if (PvMappedImage.NtHeaders->FileHeader.Characteristics & IMAGE_FILE_EXECUTABLE_IMAGE) + PhAppendStringBuilder2(&stringBuilder, L"Executable, "); + if (PvMappedImage.NtHeaders->FileHeader.Characteristics & IMAGE_FILE_DLL) + PhAppendStringBuilder2(&stringBuilder, L"DLL, "); + if (PvMappedImage.NtHeaders->FileHeader.Characteristics & IMAGE_FILE_LARGE_ADDRESS_AWARE) + PhAppendStringBuilder2(&stringBuilder, L"Large address aware, "); + if (PvMappedImage.NtHeaders->FileHeader.Characteristics & IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP) + PhAppendStringBuilder2(&stringBuilder, L"Removable run from swap, "); + if (PvMappedImage.NtHeaders->FileHeader.Characteristics & IMAGE_FILE_NET_RUN_FROM_SWAP) + PhAppendStringBuilder2(&stringBuilder, L"Net run from swap, "); + if (PvMappedImage.NtHeaders->FileHeader.Characteristics & IMAGE_FILE_SYSTEM) + PhAppendStringBuilder2(&stringBuilder, L"System, "); + if (PvMappedImage.NtHeaders->FileHeader.Characteristics & IMAGE_FILE_UP_SYSTEM_ONLY) + PhAppendStringBuilder2(&stringBuilder, L"Uni-processor only, "); + + if (PvMappedImage.NtHeaders->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA) + PhAppendStringBuilder2(&stringBuilder, L"High entropy VA, "); + if (PvMappedImage.NtHeaders->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE) + PhAppendStringBuilder2(&stringBuilder, L"Dynamic base, "); + if (PvMappedImage.NtHeaders->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY) + PhAppendStringBuilder2(&stringBuilder, L"Force integrity check, "); + if (PvMappedImage.NtHeaders->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_NX_COMPAT) + PhAppendStringBuilder2(&stringBuilder, L"NX compatible, "); + if (PvMappedImage.NtHeaders->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_NO_ISOLATION) + PhAppendStringBuilder2(&stringBuilder, L"No isolation, "); + if (PvMappedImage.NtHeaders->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_NO_SEH) + PhAppendStringBuilder2(&stringBuilder, L"No SEH, "); + if (PvMappedImage.NtHeaders->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_NO_BIND) + PhAppendStringBuilder2(&stringBuilder, L"Do not bind, "); + if (PvMappedImage.NtHeaders->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_APPCONTAINER) + PhAppendStringBuilder2(&stringBuilder, L"AppContainer, "); + if (PvMappedImage.NtHeaders->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_WDM_DRIVER) + PhAppendStringBuilder2(&stringBuilder, L"WDM driver, "); + if (PvMappedImage.NtHeaders->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_GUARD_CF) + PhAppendStringBuilder2(&stringBuilder, L"Control Flow Guard, "); + if (PvMappedImage.NtHeaders->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE) + PhAppendStringBuilder2(&stringBuilder, L"Terminal server aware, "); + + if (PhEndsWithString2(stringBuilder.String, L", ", FALSE)) + PhRemoveEndStringBuilder(&stringBuilder, 2); + + SetDlgItemText(WindowHandle, IDC_CHARACTERISTICS, stringBuilder.String->Buffer); + PhDeleteStringBuilder(&stringBuilder); +} + +VOID PvpSetPeImageSections( + _In_ HWND ListViewHandle + ) +{ + for (ULONG i = 0; i < PvMappedImage.NumberOfSections; i++) + { + INT lvItemIndex; + WCHAR sectionName[IMAGE_SIZEOF_SHORT_NAME + 1]; + WCHAR pointer[PH_PTR_STR_LEN_1]; + + if (PhGetMappedImageSectionName(&PvMappedImage.Sections[i], sectionName, ARRAYSIZE(sectionName), NULL)) + { + PhPrintPointer(pointer, UlongToPtr(PvMappedImage.Sections[i].VirtualAddress)); + + lvItemIndex = PhAddListViewItem(ListViewHandle, MAXINT, sectionName, NULL); + PhSetListViewSubItem(ListViewHandle, lvItemIndex, 1, pointer); + PhSetListViewSubItem(ListViewHandle, lvItemIndex, 2, PhaFormatSize(PvMappedImage.Sections[i].SizeOfRawData, -1)->Buffer); + PhSetListViewSubItem(ListViewHandle, lvItemIndex, 3, PH_AUTO_T(PH_STRING, PvpGetSectionCharacteristics(PvMappedImage.Sections[i].Characteristics))->Buffer); + + //if (PvMappedImage.Sections[i].PointerToRawData && PvMappedImage.Sections[i].SizeOfRawData) + //{ + // PH_HASH_CONTEXT hashContext; + // PPH_STRING hashString; + // UCHAR hash[32]; + // + // PhInitializeHash(&hashContext, Md5HashAlgorithm); + // PhUpdateHash(&hashContext, PTR_ADD_OFFSET(PvMappedImage.ViewBase, PvMappedImage.Sections[i].PointerToRawData), PvMappedImage.Sections[i].SizeOfRawData); + // PhFinalHash(&hashContext, hash, 16, NULL); + // + // hashString = PhBufferToHexString(hash, 16); + // PhSetListViewSubItem(ListViewHandle, lvItemIndex, 4, hashString->Buffer); + // PhDereferenceObject(hashString); + //} + } + } +} + +INT_PTR CALLBACK PvpPeGeneralDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + LPPROPSHEETPAGE propSheetPage; + PPV_PROPPAGECONTEXT propPageContext; + + if (!PvPropPageDlgProcHeader(hwndDlg, uMsg, lParam, &propSheetPage, &propPageContext)) + return FALSE; + + switch (uMsg) + { + case WM_INITDIALOG: + { + HWND lvHandle; + + // File version information + PvpSetPeImageVersionInfo(hwndDlg); + + // PE properties + PvpSetPeImageMachineType(hwndDlg); + PvpSetPeImageTimeStamp(hwndDlg); + PvpSetPeImageBaseAddress(hwndDlg); + PvpSetPeImageEntryPoint(hwndDlg); + PvpSetPeImageCheckSum(hwndDlg); + PvpSetPeImageSubsystem(hwndDlg); + PvpSetPeImageCharacteristics(hwndDlg); lvHandle = GetDlgItem(hwndDlg, IDC_LIST); PhSetListViewStyle(lvHandle, TRUE, TRUE); @@ -522,23 +672,16 @@ INT_PTR CALLBACK PvpPeGeneralDlgProc( PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 80, L"Name"); PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 80, L"VA"); PhAddListViewColumn(lvHandle, 2, 2, 2, LVCFMT_LEFT, 80, L"Size"); + PhAddListViewColumn(lvHandle, 3, 3, 3, LVCFMT_LEFT, 250, L"Characteristics"); + //PhAddListViewColumn(lvHandle, 4, 4, 4, LVCFMT_LEFT, 80, L"Hash"); + PhLoadListViewColumnsFromSetting(L"ImageGeneralListViewColumns", lvHandle); - for (i = 0; i < PvMappedImage.NumberOfSections; i++) - { - INT lvItemIndex; - WCHAR sectionName[IMAGE_SIZEOF_SHORT_NAME + 1]; - WCHAR pointer[PH_PTR_STR_LEN_1]; - - if (PhGetMappedImageSectionName(&PvMappedImage.Sections[i], sectionName, ARRAYSIZE(sectionName), NULL)) - { - lvItemIndex = PhAddListViewItem(lvHandle, MAXINT, sectionName, NULL); - - PhPrintPointer(pointer, UlongToPtr(PvMappedImage.Sections[i].VirtualAddress)); - - PhSetListViewSubItem(lvHandle, lvItemIndex, 1, pointer); - PhSetListViewSubItem(lvHandle, lvItemIndex, 2, PhaFormatSize(PvMappedImage.Sections[i].SizeOfRawData, -1)->Buffer); - } - } + PvpSetPeImageSections(lvHandle); + } + break; + case WM_DESTROY: + { + PhSaveListViewColumnsToSetting(L"ImageGeneralListViewColumns", GetDlgItem(hwndDlg, IDC_LIST)); } break; case WM_SHOWWINDOW: @@ -547,16 +690,11 @@ INT_PTR CALLBACK PvpPeGeneralDlgProc( { PPH_LAYOUT_ITEM dialogItem; - dialogItem = PvAddPropPageLayoutItem(hwndDlg, hwndDlg, - PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL); - PvAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_FILE), - dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); - PvAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_NAME), - dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); - PvAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_CHARACTERISTICS), - dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); - PvAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_LIST), - dialogItem, PH_ANCHOR_ALL); + dialogItem = PvAddPropPageLayoutItem(hwndDlg, hwndDlg, PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL); + PvAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_FILE), dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); + PvAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_NAME), dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); + PvAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_CHARACTERISTICS), dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); + PvAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_LIST), dialogItem, PH_ANCHOR_ALL); PvDoPropPageLayout(hwndDlg); From bf475c91084d89d32dd732683f46545c9c72784e Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 25 Mar 2018 05:02:00 +1100 Subject: [PATCH 0859/2058] Update privileges --- ProcessHacker/main.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/ProcessHacker/main.c b/ProcessHacker/main.c index d45446a4bb88..607478b0cf03 100644 --- a/ProcessHacker/main.c +++ b/ProcessHacker/main.c @@ -1308,12 +1308,12 @@ VOID PhpEnablePrivileges( &tokenHandle ))) { - CHAR privilegesBuffer[FIELD_OFFSET(TOKEN_PRIVILEGES, Privileges) + sizeof(LUID_AND_ATTRIBUTES) * 8]; + CHAR privilegesBuffer[FIELD_OFFSET(TOKEN_PRIVILEGES, Privileges) + sizeof(LUID_AND_ATTRIBUTES) * 9]; PTOKEN_PRIVILEGES privileges; ULONG i; privileges = (PTOKEN_PRIVILEGES)privilegesBuffer; - privileges->PrivilegeCount = 8; + privileges->PrivilegeCount = 9; for (i = 0; i < privileges->PrivilegeCount; i++) { @@ -1326,9 +1326,10 @@ VOID PhpEnablePrivileges( privileges->Privileges[2].Luid.LowPart = SE_INC_WORKING_SET_PRIVILEGE; privileges->Privileges[3].Luid.LowPart = SE_LOAD_DRIVER_PRIVILEGE; privileges->Privileges[4].Luid.LowPart = SE_PROF_SINGLE_PROCESS_PRIVILEGE; - privileges->Privileges[5].Luid.LowPart = SE_RESTORE_PRIVILEGE; - privileges->Privileges[6].Luid.LowPart = SE_SHUTDOWN_PRIVILEGE; - privileges->Privileges[7].Luid.LowPart = SE_TAKE_OWNERSHIP_PRIVILEGE; + privileges->Privileges[5].Luid.LowPart = SE_BACKUP_PRIVILEGE; + privileges->Privileges[6].Luid.LowPart = SE_RESTORE_PRIVILEGE; + privileges->Privileges[7].Luid.LowPart = SE_SHUTDOWN_PRIVILEGE; + privileges->Privileges[8].Luid.LowPart = SE_TAKE_OWNERSHIP_PRIVILEGE; NtAdjustPrivilegesToken( tokenHandle, From 68eca83c328ea89749e1c8efe05f4411012956c0 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 25 Mar 2018 05:02:23 +1100 Subject: [PATCH 0860/2058] Fix tabspace --- phlib/native.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/phlib/native.c b/phlib/native.c index fa9e91bef515..1a8d7b28e16d 100644 --- a/phlib/native.c +++ b/phlib/native.c @@ -2013,7 +2013,7 @@ NTSTATUS PhGetTokenIntegrityLevelRID( _In_ HANDLE TokenHandle, _Out_opt_ PMANDATORY_LEVEL_RID IntegrityLevelRID, _Out_opt_ PWSTR *IntegrityString -) + ) { NTSTATUS status; PTOKEN_MANDATORY_LABEL mandatoryLabel; @@ -2062,7 +2062,7 @@ NTSTATUS PhGetTokenIntegrityLevelRID( } if (IntegrityLevelRID) - *IntegrityLevelRID = subAuthority; + *IntegrityLevelRID = subAuthority; return status; } @@ -2119,7 +2119,7 @@ NTSTATUS PhGetTokenIntegrityLevel( *IntegrityLevel = integrityLevel; } - + return status; } From b945ad780823c2d17189fa8599f6ae508b8d6c6c Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 25 Mar 2018 05:08:27 +1100 Subject: [PATCH 0861/2058] Add workaround for appcontainer name lookup bug --- phlib/appresolver.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/phlib/appresolver.c b/phlib/appresolver.c index 423837f22077..65d72d8d8c8a 100644 --- a/phlib/appresolver.c +++ b/phlib/appresolver.c @@ -202,17 +202,30 @@ PPH_STRING PhGetAppContainerName( _In_ PSID AppContainerSid ) { + HRESULT result; PPH_STRING appContainerName = NULL; PWSTR packageMonikerName; if (!PhpKernelAppCoreInitialized()) return NULL; - if (SUCCEEDED(AppContainerLookupMoniker_I(AppContainerSid, &packageMonikerName))) + result = AppContainerLookupMoniker_I( + AppContainerSid, + &packageMonikerName + ); + + if (SUCCEEDED(result)) { appContainerName = PhCreateString(packageMonikerName); AppContainerFreeMemory_I(packageMonikerName); } + else + { + // NOTE: The AppContainerLookupMoniker function is not able to lookup the appcontainer names created using the + // CreateAppContainerProfile function from Win32 desktop applications (e.g. Google Chrome). + // HACK: Return the error message until the above bug is fixed or have a better workaround -dmex + appContainerName = PhGetStatusMessage(0, HRESULT_CODE(result)); + } return appContainerName; } From d0bc13d24ecb3c12a356014871a0009304db8bb9 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 25 Mar 2018 06:06:06 +1100 Subject: [PATCH 0862/2058] peview: Add missing setting --- tools/peview/settings.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/peview/settings.c b/tools/peview/settings.c index 02933ce572b8..ff5ff7e38b29 100644 --- a/tools/peview/settings.c +++ b/tools/peview/settings.c @@ -35,6 +35,7 @@ VOID PhAddDefaultSettings( PhpAddStringSetting(L"MainWindowPage", L"General"); PhpAddIntegerPairSetting(L"MainWindowPosition", L"150,150"); PhpAddScalableIntegerPairSetting(L"MainWindowSize", L"@96|550,580"); + PhpAddStringSetting(L"ImageGeneralListViewColumns", L""); PhpAddStringSetting(L"ImageLoadCfgListViewColumns", L""); PhpAddStringSetting(L"ImageExportsListViewColumns", L""); PhpAddStringSetting(L"ImageImportsListViewColumns", L""); From 30e5bfc453173c43bec38a433d1cd40c7c4d78ba Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 29 Mar 2018 08:16:40 +1100 Subject: [PATCH 0863/2058] Update warning message text, Disable unloaddll commandline --- ProcessHacker/actions.c | 2 +- ProcessHacker/cmdmode.c | 64 ++++++++++++++++++++--------------------- ProcessHacker/memedit.c | 11 +++++++ 3 files changed, 44 insertions(+), 33 deletions(-) diff --git a/ProcessHacker/actions.c b/ProcessHacker/actions.c index 86cd9e93e1ad..2bf2255b07ca 100644 --- a/ProcessHacker/actions.c +++ b/ProcessHacker/actions.c @@ -2627,7 +2627,7 @@ BOOLEAN PhUiUnloadModule( message = L"Unloading a module may cause the process to crash."; if (WindowsVersion >= WINDOWS_8) - message = L"Unloading a module may cause the process to crash. NOTE: This feature may not work correctly on your version of Windows."; + message = L"Unloading a module may cause the process to crash. NOTE: This feature may not work correctly on your version of Windows and some programs may restrict access or ban your account."; break; case PH_MODULE_TYPE_KERNEL_MODULE: diff --git a/ProcessHacker/cmdmode.c b/ProcessHacker/cmdmode.c index 1d7cb4f3761e..d54ba0f7bb17 100644 --- a/ProcessHacker/cmdmode.c +++ b/ProcessHacker/cmdmode.c @@ -225,38 +225,38 @@ NTSTATUS PhCommandModeStart( NtClose(processHandle); } } - else if (PhEqualString2(PhStartupParameters.CommandAction, L"unloaddll", TRUE)) - { - if (!PhStartupParameters.CommandValue) - return STATUS_INVALID_PARAMETER; - - if (NT_SUCCESS(status = PhOpenProcessPublic( - &processHandle, - ProcessQueryAccess | PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE, - processId - ))) - { - PVOID baseAddress; - - if (NT_SUCCESS(status = PhpGetDllBaseRemote( - processHandle, - &PhStartupParameters.CommandValue->sr, - &baseAddress - ))) - { - LARGE_INTEGER timeout; - - timeout.QuadPart = -5 * PH_TIMEOUT_SEC; - status = PhUnloadDllProcess( - processHandle, - baseAddress, - &timeout - ); - } - - NtClose(processHandle); - } - } + //else if (PhEqualString2(PhStartupParameters.CommandAction, L"unloaddll", TRUE)) + //{ + // if (!PhStartupParameters.CommandValue) + // return STATUS_INVALID_PARAMETER; + // + // if (NT_SUCCESS(status = PhOpenProcessPublic( + // &processHandle, + // ProcessQueryAccess | PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE, + // processId + // ))) + // { + // PVOID baseAddress; + // + // if (NT_SUCCESS(status = PhpGetDllBaseRemote( + // processHandle, + // &PhStartupParameters.CommandValue->sr, + // &baseAddress + // ))) + // { + // LARGE_INTEGER timeout; + // + // timeout.QuadPart = -5 * PH_TIMEOUT_SEC; + // status = PhUnloadDllProcess( + // processHandle, + // baseAddress, + // &timeout + // ); + // } + // + // NtClose(processHandle); + // } + //} } else if (PhEqualString2(PhStartupParameters.CommandType, L"service", TRUE)) { diff --git a/ProcessHacker/memedit.c b/ProcessHacker/memedit.c index 5690bf817dea..e514311dd7cf 100644 --- a/ProcessHacker/memedit.c +++ b/ProcessHacker/memedit.c @@ -450,6 +450,17 @@ INT_PTR CALLBACK PhpMemoryEditorDlgProc( { NTSTATUS status; + if (!PhGetIntegerSetting(L"EnableWarnings") || PhShowConfirmMessage( + hwndDlg, + L"write", + L"process memory", + L"Some programs may restrict access or ban your account when editing the memory of the process.", + FALSE + )) + { + break; + } + if (!context->WriteAccess) { HANDLE processHandle; From 191cfd1b0cb3eed8cacc81c6a9a85b9efe89c1a1 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 29 Mar 2018 08:17:51 +1100 Subject: [PATCH 0864/2058] ToolStatus: Show disabled buttons --- plugins/ToolStatus/toolbar.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/ToolStatus/toolbar.c b/plugins/ToolStatus/toolbar.c index 10c86c351482..0b69d9b92846 100644 --- a/plugins/ToolStatus/toolbar.c +++ b/plugins/ToolStatus/toolbar.c @@ -321,7 +321,7 @@ VOID ToolbarLoadSettings( { if (PhGetOwnTokenAttributes().Elevated) { - buttonInfo.fsState |= TBSTATE_HIDDEN; + buttonInfo.fsState &= ~TBSTATE_ENABLED; } } break; From 9d9719bf5d538483925d309ad2109304d654931a Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 29 Mar 2018 08:21:26 +1100 Subject: [PATCH 0865/2058] peview: Add hash column to resource tab --- tools/peview/peprp.c | 2 +- tools/peview/resprp.c | 21 +++++++++++++++++++-- tools/peview/settings.c | 1 + 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/tools/peview/peprp.c b/tools/peview/peprp.c index 6dbc0546672c..7e1e6e24f053 100644 --- a/tools/peview/peprp.c +++ b/tools/peview/peprp.c @@ -623,7 +623,7 @@ VOID PvpSetPeImageSections( // PPH_STRING hashString; // UCHAR hash[32]; // - // PhInitializeHash(&hashContext, Md5HashAlgorithm); + // PhInitializeHash(&hashContext, PhGetIntegerSetting(L"HashAlgorithm")); // PhUpdateHash(&hashContext, PTR_ADD_OFFSET(PvMappedImage.ViewBase, PvMappedImage.Sections[i].PointerToRawData), PvMappedImage.Sections[i].SizeOfRawData); // PhFinalHash(&hashContext, hash, 16, NULL); // diff --git a/tools/peview/resprp.c b/tools/peview/resprp.c index 0877b0b24f23..7fadaa99bdc5 100644 --- a/tools/peview/resprp.c +++ b/tools/peview/resprp.c @@ -2,7 +2,7 @@ * Process Hacker - * PE viewer * - * Copyright (C) 2017 dmex + * Copyright (C) 2017-2018 dmex * * This file is part of Process Hacker. * @@ -71,7 +71,8 @@ typedef enum _PVE_RESOURCES_COLUMN_INDEX PVE_RESOURCES_COLUMN_INDEX_TYPE, PVE_RESOURCES_COLUMN_INDEX_NAME, PVE_RESOURCES_COLUMN_INDEX_SIZE, - PVE_RESOURCES_COLUMN_INDEX_LCID + PVE_RESOURCES_COLUMN_INDEX_LCID, + PVE_RESOURCES_COLUMN_INDEX_HASH } PVE_RESOURCES_COLUMN_INDEX; INT_PTR CALLBACK PvpPeResourcesDlgProc( @@ -106,6 +107,7 @@ INT_PTR CALLBACK PvpPeResourcesDlgProc( PhAddListViewColumn(lvHandle, 2, 2, 2, LVCFMT_LEFT, 80, L"Name"); PhAddListViewColumn(lvHandle, 3, 3, 3, LVCFMT_LEFT, 100, L"Size"); PhAddListViewColumn(lvHandle, 4, 4, 4, LVCFMT_LEFT, 100, L"Language"); + PhAddListViewColumn(lvHandle, 5, 5, 5, LVCFMT_LEFT, 100, L"Hash"); PhSetExtendedListView(lvHandle); PhLoadListViewColumnsFromSetting(L"ImageResourcesListViewColumns", lvHandle); @@ -172,6 +174,21 @@ INT_PTR CALLBACK PvpPeResourcesDlgProc( } PhSetListViewSubItem(lvHandle, lvItemIndex, PVE_RESOURCES_COLUMN_INDEX_SIZE, PhaFormatSize(entry.Size, -1)->Buffer); + + if (entry.Data && entry.Size) + { + PH_HASH_CONTEXT hashContext; + PPH_STRING hashString; + UCHAR hash[32]; + + PhInitializeHash(&hashContext, PhGetIntegerSetting(L"HashAlgorithm")); + PhUpdateHash(&hashContext, entry.Data, entry.Size); + PhFinalHash(&hashContext, hash, 16, NULL); + + hashString = PhBufferToHexString(hash, 16); + PhSetListViewSubItem(lvHandle, lvItemIndex, PVE_RESOURCES_COLUMN_INDEX_HASH, hashString->Buffer); + PhDereferenceObject(hashString); + } } PhFree(resources.ResourceEntries); diff --git a/tools/peview/settings.c b/tools/peview/settings.c index ff5ff7e38b29..7b5fa547709f 100644 --- a/tools/peview/settings.c +++ b/tools/peview/settings.c @@ -31,6 +31,7 @@ VOID PhAddDefaultSettings( { PhpAddIntegerSetting(L"FirstRun", L"1"); PhpAddStringSetting(L"Font", L""); // null + PhpAddIntegerSetting(L"HashAlgorithm", L"0"); PhpAddIntegerSetting(L"MaxSizeUnit", L"6"); PhpAddStringSetting(L"MainWindowPage", L"General"); PhpAddIntegerPairSetting(L"MainWindowPosition", L"150,150"); From f16e9d95a214120cce6e8a2eb78f0a60c78bbfc1 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 29 Mar 2018 08:44:54 +1100 Subject: [PATCH 0866/2058] BuildTools: Fix 32bit vswhere path --- tools/CustomBuildTool/Source Files/Utils.cs | 7 ++++++- .../bin/Release/CustomBuildTool.exe | Bin 163840 -> 163840 bytes .../bin/Release/CustomBuildTool.pdb | Bin 77312 -> 77312 bytes 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/tools/CustomBuildTool/Source Files/Utils.cs b/tools/CustomBuildTool/Source Files/Utils.cs index ba1b493d5026..2da55499afaf 100644 --- a/tools/CustomBuildTool/Source Files/Utils.cs +++ b/tools/CustomBuildTool/Source Files/Utils.cs @@ -222,7 +222,12 @@ public static string GetFilePathFromPath(string FileName) public static string GetMsbuildFilePath() { - string vswhere = Environment.ExpandEnvironmentVariables("%ProgramFiles(x86)%\\Microsoft Visual Studio\\Installer\\vswhere.exe"); + string vswhere = string.Empty; + + if (Environment.Is64BitOperatingSystem) + vswhere = Environment.ExpandEnvironmentVariables("%ProgramFiles(x86)%\\Microsoft Visual Studio\\Installer\\vswhere.exe"); + else + vswhere = Environment.ExpandEnvironmentVariables("%ProgramFiles%\\Microsoft Visual Studio\\Installer\\vswhere.exe"); // Note: vswere.exe was only released with build 15.0.26418.1 if (File.Exists(vswhere)) diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe b/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe index f2a6424ef1a182497f64f0b7bf11af834bd40103..de0d0c33d304d643aeff3d3c93523e10553cd428 100644 GIT binary patch delta 7214 zcmZXZ3tUw7w#V0h@0mR>=EcCk3=9l2gMi|z%(o^=1-=mQg)bNdMKtk&rj-ncSzPnQ zPRcZeG?ViBxabkP<^?Isq|%O=mKtQ8B+a9ynd#}=^&fVKRShF<~HaLtc-+X1+DGJw=y%fO<=qK@^Wgy?>Ozo9=Kz*^b?K(9~y z5t(e9Uz7%O6J6ZX$uR$)_l1<`OUFCxms>%(o9kuLor?FXSOl z$FPo&xDX3Mw8GH_|VZH8`885glIBcrxc`n;EW+3p4cEe2foODl3yR#lP#>um8b#eWLOY`la7}Xe@9R8 zZP_}cL&R+~_0s%nIDAy`>nM_kN%N&)^2j01$UjipDU>*#S1dq;vf?{(*^mwf8sjc^ z-;?(ai4^q1z;JaT4sXaPBp)h?n4ND`&o^HbR1zjGX74&VVSvWd|49NX~;% zi+y@X^Y)LD;4?Vk)`Q8=KgtAllh18}Aui4W=5tG+Vt2(*_!I7m74R%xs}dYSTY@XZ z9nns-(=cZveBl7tLOG!@kd48SdotduD>5KKj+w8%-N;w4jMnjQn%xj9_naaBAX?=P z;a;o+om{-QIzGcL!Av`6n3a1jMR0bGaEf*q5bAK4Al$Rx<%Em+-8Luu;pE)u+HEtz z7UzB(S%=Gx3BaXjk5huDuuOub_S-%Qirt*OBRFHoKU;O%7XzcM(;c`wNE5tiE{T@l zIBuB)1EQafkzlbi6a6Oh3cCsJAthMj zeqxLD4u=PByB!WYEQ;qRd6V6N7iMh~Z@dfXgk|~&!3pmW(>w$5Vtj|T>}{NA42Z7j zm~Zm&UW?q_`AObEr}_)xT0QstH`$-igd*elmA@#87vzT2%D0~B+Q%As*q#Y4h{gMn z1y09twgXPV()v zB=a>NAE_%8lkc+JH9d+Y$ivc;#1S!<{fJ6uQHim>O+&_*)$34kTVG z#!~$8x)!?)?c*^!@ez_5Uy6^EHJHhuJ`l?fi6PweW)x>5PRI`X-TSqYbY8S+#+H3* zJggmC_JN1xOB9%fM+|+Pt zbeum(@|B@JRxMkHtqFXL1N0R?MGhwB5KD<`iL;1)f#(b*`pDBx_BOH)5s#ARFJd<& zUkV@pQ)3G<-Ol;4inEH?9M=*+G1T0Gr})>16Ua)_*LcdF#Et0*df{8G9o~Qo$ffWz zau2(XJkFTT4*y_QodieS9%N-~2jqIzO~`$)-4z_kXqb5sQ&HbndcOx3*l<*kiJl-hmavbm2PT~3=r~EP)#CLLuy@Qsq3Q30JHe36s(9`jQ1b| zlsux&rSn)hERLO{GeCcQ=8`hS26Q2?Q;`?t%#l%JcsYLv^UqQB0^i%Z2dY;T16weJ zv27lFqTE+s8F%U)C|}IO>Z;r{GRkE`U-gewk>4McB#5!{ zX-wcP9wc;?jhVp~4}1q@e`b=|9r>ru181`MSnJ?@c|&GYAIUcd@LC%k^c{(f&?mtw zq^jYQsJoC1uZ-cbYS2aBg)ZP88&sF&Uo(@~DLEpmmwAt`pMD@TtIai3v2^I5s8lmoT@Xw76v5IP@x+wugt|vKNQ4_;?>KsLNQ*pIOQJa5*@YKNi@;Y3Hm9z}f?Zb5ZWQ5sxQ1~e(k7G^>9nWA=v=EErXY6|fF zE3^kfEhxWJf)0?8t|;mZHq3&Xin@div*2HfO2&rSpw100sV_Fn29u(` zz=os2uBh*@-)M+M72xgv!iHlYK?#~7EU3CE>hE|;$3kyK{fwt{ETkyv51h<6NLQ2r zCpr$Y6qSaP84nW_m4lNR57QKN2`7^Sv$zUi`#*3tIZ&bm+x7V{0bW$pExiTRONu&d z%ZG`uN>ME~3#w{Gb;d261e+E0G;ZM}cvn%m7@G{c6}1Rslc9lBV1@Q1US3n6Q3?L6 zvYUr`lwr}V=W%9OQzqNnNo5TD1l zNe*b|nP#F)4odA(Q!%O@in9Cmz|=fp>W2w1x} zQovftAzv8RqgSwV6ZH==83z?$fXiYLq0wlusFX=`!?z0tCvXx1T#(bpKf#*h!1!l6 zjiD91MbR_(2MGaMkRk*M4;rkI$K9=LcUBD>=-wOv)4@pQ1 zzLawIA*K-1iJ8P4q8}L!Gs&JuTtciwI`LV<$J{{lGj7jAy74u8u`2=AA-ljqwm5)+ z6oH4+iJ8bJAcyQF$bL`CHy1VtckyviDWrG`p;qYY znFDpg)c6JDS&ZC;@6C0JKP$c*?E&U0^dE}|R*l$%Vtf1?DtH_Dj_o~cw$Hc+8&^3# zfF_vcZpJs|D!er`!KbcfXkyz!KgVXveSAWjb-cD(cMCmh=>>7 z7;G_iVK_zk*@<4d>QBPzxO~^d%WE;|W!)e^?U{q#Z-?_I^(z^kuf zI`N1}0;~9*aRE5Q!I7D84A$tn(D)3Ov_AGUjvr%hMOKD4(<&~Z{j-~UuDb8BcASY( zXosjkWCR|v+%ZCmSmg2v*I~OiNk|uG;nRyZ=z`G^p*_%F?5kq6w18-$PqB+!`9d;Q ztzyZPt=yRUoV!mScieDtohL!HO#S$F!fcPQ~+9EEe=&MT3@Tj}uYcL_= zan&Zp)7LjawN0^0J(a2#p*VmIlJEkwfM3iubG~Pkh!&g#U*Are?@n5uUp#~-e;@ql zTPDmDH<+4L`*65pD!!Ulwht$L3O&;zPN}S7gzFqK+q?kJWp8|$tz-Y?y{6iWy?#gb z3;CC-TwLtJKY^TO29HX8mKB8P)s^B(yoAfeH$p7PWPEWb7q5yI%mJT8T`u&~JCHiB zOYIQH8TmEWJ1z^TDZXdbP2x+sd<+O)3EJ2%hJd=AEtUsNaRuJx4Wlc9Lp^TvZs;sn)xSq$JFoD;*RjIG1AdCG>Phk1X{;N)V^IYuhL#sj6&S zrE+0aM1%B^a!sgA-%FX|KfHfQ8`wOfO|yZO83Q&=9k^9?!zs`-U#ilX;FswPy2bHkLrYHgys}1VlCn+FtAmuRyZA7pmB(eA$-evdHMZjMCc_p z8!VyoG%2b(rsr{-*64hgjTh`njTQ=E8*(OW3ur>&SrYSz3z4C)gzVRdZ$OV=qWDV3Kw~@UAK16#D96|1bPmm4JqS3){whcLo)gec-UC8mQ9yy6MAoJLV znp_>^vy&(a*=gi#_8oFAYekk&*| zCzcayiA}^dBGXeovC+isRw9_W?IsQ)<`K(?HN-$89a@QCp#owav5Z(lY$Uc4!AhCL zLBu>_8L@`gNNgoSDCH9e5%Y*;0XozW8;Pw%uu%bV5HXKfMyw$=5?hH7M)|}+#5`gd zv4+@4Y$ZZC<%f^she0Irh-JhYVk5DY2zH(s2d`?quv#0B#{~TL!EZnO4uEyqCqdSx z;8BZzx4R;LnLo^MNYZPfHN7F*;C_o&iL=Xo)YG_KOjrY3v@j#|NyglQ`Ti38?@9ghWnrfJb*rzYu_f}- zqt1HwH@$^WfNz_nJv~RQ8nUs)n{#l^S6k}~&o)RZ97?Enw{8*Yn}7J)l#Ktyo4{KO z_>IQ?h4>%3!W#ft*{Ru&|HrBuV=wei-Eq1-{qV4XQS~2P*D}ja<^OfO>L}W;@9iQ) cvIhCq4S$8{<^j`9_GhJVru%^=5Br_{FS2@Q-v9sr delta 7192 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 diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb b/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb index 30eaad40c0eded665c0264b4b3a2138e056b46dd..ea00cfc1af476cdef61fb53e07d4fcb0bfc64244 100644 GIT binary patch delta 3358 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�LV780qGVLc=|#lHY`#Emj$Jo1QG)Tv1@SCsgu|XDWB= z$0rgzXWzMvZ*jp2^y$-FyY=B~gDyxRi-r**9;HWF@fFPt2aZ#cK~ zLc36CwODJocT}O25wkUP)VsWR#Ayv3agsN~30>U-y`^orig<|)J5WirE!3LQQ*i$_s4 zbm)0{)p}G79e$Cjy6B48S|-YkS-Ftxw7x1{HyjUF!6^~z4QI7pumJ@(h}R6aSQY#d z1=ooZ!!GAXSDaC$VuRsq))S-mqJQW#x9L@-8#>KORrUR=W^3r-tmp2l&MAA>$m4KA z-`GJ}FnZrJ!?beqr&EuLPan7md7+E!P_t}?T_nnk$#?0=(tSm|YPdaWmJdIjy7oS% zYffwE+5@}*PUtwJdchVH4BgBdYIHB`0#{MBL{8K?n&%Ws8(oDXi_+&(5m25XjkY|IIGaBBV2xA`-A4QQ9Lzi zi{nuKkX9sdOsO`dPAJu_)H$X4l^Rj%x>7flx~0?|rS2*wUgL1Qy+k&!E$@-vdRPta@wkqih$_^#F zg0e@+zMu>!IU1BVlpGJr+ZwjfK@(as5H7!kPt#Hz6dyhl&FAzc#c8!NCsR8vbL2Oz zpJ|kYm%-Xo`QU_hPvVSH=XHb+A}vR&MOye{G^_L`PDfP|Quk^{lPHsp1csBSB<%nG TUlT}5p*3c@5ZInhA6fnj^!;m5 From aa07c6e4676a2bc2193710d08a2b919f6fd0ad3d Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 4 Apr 2018 19:59:54 +1000 Subject: [PATCH 0867/2058] Fix typo --- ProcessHacker/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ProcessHacker/main.c b/ProcessHacker/main.c index 607478b0cf03..e6e423cb924c 100644 --- a/ProcessHacker/main.c +++ b/ProcessHacker/main.c @@ -136,7 +136,7 @@ INT WINAPI wWinMain( if (!(PhLocalSystemName = PhGetSidFullName(&PhSeLocalSystemSid, TRUE, NULL))) PhLocalSystemName = PhCreateString(L"NT AUTHORITY\\SYSTEM"); if (!(PhCurrentUserName = PhGetTokenUserString(PhGetOwnTokenAttributes().TokenHandle, TRUE))) - PhLocalSystemName = PhReferenceEmptyString(); + PhCurrentUserName = PhReferenceEmptyString(); PhpProcessStartupParameters(); PhSettingsInitialization(); From 16bedfb443d665cf677877b7e9685ed54450a423 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 4 Apr 2018 20:28:52 +1000 Subject: [PATCH 0868/2058] Update PCRE to 10.31 --- ProcessHacker/pcre/config.h | 11 +- ProcessHacker/pcre/dftables.c | 214 +++++++++ ProcessHacker/pcre/pcre2.h | 16 +- ProcessHacker/pcre/pcre2_auto_possess.c | 56 ++- ProcessHacker/pcre/pcre2_compile.c | 36 +- ProcessHacker/pcre/pcre2_config.c | 34 +- ProcessHacker/pcre/pcre2_dfa_match.c | 430 +++++------------ ProcessHacker/pcre/pcre2_extuni.c | 148 ++++++ ProcessHacker/pcre/pcre2_internal.h | 8 + ProcessHacker/pcre/pcre2_intmodedep.h | 31 +- ProcessHacker/pcre/pcre2_jit_compile.c | 592 +++++++++++++++++------- ProcessHacker/pcre/pcre2_jit_match.c | 8 +- ProcessHacker/pcre/pcre2_jit_test.c | 2 + ProcessHacker/pcre/pcre2_match.c | 341 ++++---------- ProcessHacker/pcre/pcre2_pattern_info.c | 5 + ProcessHacker/pcre/pcre2_substring.c | 9 +- ProcessHacker/pcre/pcre2posix.c | 7 +- 17 files changed, 1159 insertions(+), 789 deletions(-) create mode 100644 ProcessHacker/pcre/dftables.c create mode 100644 ProcessHacker/pcre/pcre2_extuni.c diff --git a/ProcessHacker/pcre/config.h b/ProcessHacker/pcre/config.h index 2843be569595..c15b764c4783 100644 --- a/ProcessHacker/pcre/config.h +++ b/ProcessHacker/pcre/config.h @@ -33,7 +33,10 @@ sure both macros are undefined; an emulation function will then be used. */ value), this is changed so that backslash-R matches only CR, LF, or CRLF. The build-time default can be overridden by the user of PCRE2 at runtime. */ -#undef BSR_ANYCRLF +#ifndef BSR_ANYCRLF +#define BSR_ANYCRLF 1 +#endif + /* If you are compiling for a system that uses EBCDIC instead of ASCII character codes, define this macro to any value. When EBCDIC is set, PCRE2 @@ -232,7 +235,7 @@ sure both macros are undefined; an emulation function will then be used. */ #define PACKAGE_NAME "PCRE2" /* Define to the full name and version of this package. */ -#define PACKAGE_STRING "PCRE2 10.30" +#define PACKAGE_STRING "PCRE2 10.31" /* Define to the one symbol short name of this package. */ #define PACKAGE_TARNAME "pcre2" @@ -241,7 +244,7 @@ sure both macros are undefined; an emulation function will then be used. */ #define PACKAGE_URL "" /* Define to the version of this package. */ -#define PACKAGE_VERSION "10.30" +#define PACKAGE_VERSION "10.31" /* The value of PARENS_NEST_LIMIT specifies the maximum depth of nested parentheses (of any kind) in a pattern. This limits the amount of system @@ -369,7 +372,7 @@ sure both macros are undefined; an emulation function will then be used. */ #endif /* Version number of package */ -#define VERSION "10.30" +#define VERSION "10.31" /* Define to 1 if on MINIX. */ #undef _MINIX diff --git a/ProcessHacker/pcre/dftables.c b/ProcessHacker/pcre/dftables.c new file mode 100644 index 000000000000..dfb90b594a45 --- /dev/null +++ b/ProcessHacker/pcre/dftables.c @@ -0,0 +1,214 @@ +/************************************************* +* Perl-Compatible Regular Expressions * +*************************************************/ + +/* PCRE is a library of functions to support regular expressions whose syntax +and semantics are as close as possible to those of the Perl 5 language. + + Written by Philip Hazel + Original API code Copyright (c) 1997-2012 University of Cambridge + New API code Copyright (c) 2016 University of Cambridge + +----------------------------------------------------------------------------- +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of the University of Cambridge nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +----------------------------------------------------------------------------- +*/ + + +/* This is a freestanding support program to generate a file containing +character tables for PCRE2. The tables are built according to the current +locale using the pcre2_maketables() function, which is part of the PCRE2 API. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include + +#define PCRE2_CODE_UNIT_WIDTH 0 /* Must be set, but not relevant here */ +#include "pcre2_internal.h" + +#define DFTABLES /* pcre2_maketables.c notices this */ +#include "pcre2_maketables.c" + +int main(int argc, char **argv) +{ +FILE *f; +int i = 1; +const unsigned char *tables; +const unsigned char *base_of_tables; + +/* By default, the default C locale is used rather than what the building user +happens to have set. However, if the -L option is given, set the locale from +the LC_xxx environment variables. */ + +if (argc > 1 && strcmp(argv[1], "-L") == 0) + { + setlocale(LC_ALL, ""); /* Set from environment variables */ + i++; + } + +if (argc < i + 1) + { + fprintf(stderr, "dftables: one filename argument is required\n"); + return 1; + } + +tables = maketables(); +base_of_tables = tables; + +f = fopen(argv[i], "wb"); +if (f == NULL) + { + fprintf(stderr, "dftables: failed to open %s for writing\n", argv[1]); + return 1; + } + +/* There are several fprintf() calls here, because gcc in pedantic mode +complains about the very long string otherwise. */ + +fprintf(f, + "/*************************************************\n" + "* Perl-Compatible Regular Expressions *\n" + "*************************************************/\n\n" + "/* This file was automatically written by the dftables auxiliary\n" + "program. It contains character tables that are used when no external\n" + "tables are passed to PCRE2 by the application that calls it. The tables\n" + "are used only for characters whose code values are less than 256. */\n\n"); + +/* Force config.h in z/OS */ + +#if defined NATIVE_ZOS +fprintf(f, + "/* For z/OS, config.h is forced */\n" + "#ifndef HAVE_CONFIG_H\n" + "#define HAVE_CONFIG_H 1\n" + "#endif\n\n"); +#endif + +fprintf(f, + "/* The following #includes are present because without them gcc 4.x may remove\n" + "the array definition from the final binary if PCRE2 is built into a static\n" + "library and dead code stripping is activated. This leads to link errors.\n" + "Pulling in the header ensures that the array gets flagged as \"someone\n" + "outside this compilation unit might reference this\" and so it will always\n" + "be supplied to the linker. */\n\n"); + +fprintf(f, + "#ifdef HAVE_CONFIG_H\n" + "#include \"config.h\"\n" + "#endif\n\n" + "#include \"pcre2_internal.h\"\n\n"); + +fprintf(f, + "const uint8_t PRIV(default_tables)[] = {\n\n" + "/* This table is a lower casing table. */\n\n"); + +fprintf(f, " "); +for (i = 0; i < 256; i++) + { + if ((i & 7) == 0 && i != 0) fprintf(f, "\n "); + fprintf(f, "%3d", *tables++); + if (i != 255) fprintf(f, ","); + } +fprintf(f, ",\n\n"); + +fprintf(f, "/* This table is a case flipping table. */\n\n"); + +fprintf(f, " "); +for (i = 0; i < 256; i++) + { + if ((i & 7) == 0 && i != 0) fprintf(f, "\n "); + fprintf(f, "%3d", *tables++); + if (i != 255) fprintf(f, ","); + } +fprintf(f, ",\n\n"); + +fprintf(f, + "/* This table contains bit maps for various character classes.\n" + "Each map is 32 bytes long and the bits run from the least\n" + "significant end of each byte. The classes that have their own\n" + "maps are: space, xdigit, digit, upper, lower, word, graph\n" + "print, punct, and cntrl. Other classes are built from combinations. */\n\n"); + +fprintf(f, " "); +for (i = 0; i < cbit_length; i++) + { + if ((i & 7) == 0 && i != 0) + { + if ((i & 31) == 0) fprintf(f, "\n"); + fprintf(f, "\n "); + } + fprintf(f, "0x%02x", *tables++); + if (i != cbit_length - 1) fprintf(f, ","); + } +fprintf(f, ",\n\n"); + +fprintf(f, + "/* This table identifies various classes of character by individual bits:\n" + " 0x%02x white space character\n" + " 0x%02x letter\n" + " 0x%02x decimal digit\n" + " 0x%02x hexadecimal digit\n" + " 0x%02x alphanumeric or '_'\n" + " 0x%02x regular expression metacharacter or binary zero\n*/\n\n", + ctype_space, ctype_letter, ctype_digit, ctype_xdigit, ctype_word, + ctype_meta); + +fprintf(f, " "); +for (i = 0; i < 256; i++) + { + if ((i & 7) == 0 && i != 0) + { + fprintf(f, " /* "); + if (isprint(i-8)) fprintf(f, " %c -", i-8); + else fprintf(f, "%3d-", i-8); + if (isprint(i-1)) fprintf(f, " %c ", i-1); + else fprintf(f, "%3d", i-1); + fprintf(f, " */\n "); + } + fprintf(f, "0x%02x", *tables++); + if (i != 255) fprintf(f, ","); + } + +fprintf(f, "};/* "); +if (isprint(i-8)) fprintf(f, " %c -", i-8); + else fprintf(f, "%3d-", i-8); +if (isprint(i-1)) fprintf(f, " %c ", i-1); + else fprintf(f, "%3d", i-1); +fprintf(f, " */\n\n/* End of pcre2_chartables.c */\n"); + +fclose(f); +free((void *)base_of_tables); +return 0; +} + +/* End of dftables.c */ diff --git a/ProcessHacker/pcre/pcre2.h b/ProcessHacker/pcre/pcre2.h index 2cceb5cb79ba..ac15ba885be1 100644 --- a/ProcessHacker/pcre/pcre2.h +++ b/ProcessHacker/pcre/pcre2.h @@ -48,9 +48,9 @@ POSSIBILITY OF SUCH DAMAGE. /* The current PCRE version information. */ #define PCRE2_MAJOR 10 -#define PCRE2_MINOR 30 -#define PCRE2_PRERELEASE -#define PCRE2_DATE 2017-08-14 +#define PCRE2_MINOR 31 +#define PCRE2_PRERELEASE +#define PCRE2_DATE 2018-02-12 /* When an application links to a PCRE DLL in Windows, the symbols that are imported have to be identified as such. When building PCRE2, the appropriate @@ -327,6 +327,7 @@ numbers must not be changed. */ #define PCRE2_INFO_HASBACKSLASHC 23 #define PCRE2_INFO_FRAMESIZE 24 #define PCRE2_INFO_HEAPLIMIT 25 +#define PCRE2_INFO_EXTRAOPTIONS 26 /* Request types for pcre2_config(). */ @@ -344,6 +345,8 @@ numbers must not be changed. */ #define PCRE2_CONFIG_UNICODE_VERSION 10 #define PCRE2_CONFIG_VERSION 11 #define PCRE2_CONFIG_HEAPLIMIT 12 +#define PCRE2_CONFIG_NEVER_BACKSLASH_C 13 +#define PCRE2_CONFIG_COMPILED_WIDTHS 14 /* Types for code units in patterns and subject strings. */ @@ -399,6 +402,11 @@ without changing the API of the function, thereby allowing old clients to work without modification. Define the generic version in a macro; the width-specific versions are generated from this macro below. */ +/* Flags for the callout_flags field. These are cleared after a callout. */ + +#define PCRE2_CALLOUT_STARTMATCH 0x00000001u /* Set for each bumpalong */ +#define PCRE2_CALLOUT_BACKTRACK 0x00000002u /* Set after a backtrack */ + #define PCRE2_STRUCTURE_LIST \ typedef struct pcre2_callout_block { \ uint32_t version; /* Identifies version of block */ \ @@ -418,6 +426,8 @@ typedef struct pcre2_callout_block { \ PCRE2_SIZE callout_string_offset; /* Offset to string within pattern */ \ PCRE2_SIZE callout_string_length; /* Length of string compiled into pattern */ \ PCRE2_SPTR callout_string; /* String compiled into pattern */ \ + /* ------------------- Added for Version 2 -------------------------- */ \ + uint32_t callout_flags; /* See above for list */ \ /* ------------------------------------------------------------------ */ \ } pcre2_callout_block; \ \ diff --git a/ProcessHacker/pcre/pcre2_auto_possess.c b/ProcessHacker/pcre/pcre2_auto_possess.c index ad3543f62737..23275a2e39cd 100644 --- a/ProcessHacker/pcre/pcre2_auto_possess.c +++ b/ProcessHacker/pcre/pcre2_auto_possess.c @@ -558,47 +558,73 @@ for(;;) continue; } + /* At the end of a branch, skip to the end of the group. */ + if (c == OP_ALT) { do code += GET(code, 1); while (*code == OP_ALT); c = *code; } + /* Inspect the next opcode. */ + switch(c) { - case OP_END: - case OP_KETRPOS: - /* TRUE only in greedy case. The non-greedy case could be replaced by - an OP_EXACT, but it is probably not worth it. (And note that OP_EXACT - uses more memory, which we cannot get at this stage.) */ + /* We can always possessify a greedy iterator at the end of the pattern, + which is reached after skipping over the final OP_KET. A non-greedy + iterator must never be possessified. */ + case OP_END: return base_list[1] != 0; + /* When an iterator is at the end of certain kinds of group we can inspect + what follows the group by skipping over the closing ket. Note that this + does not apply to OP_KETRMAX or OP_KETRMIN because what follows any given + iteration is variable (could be another iteration or could be the next + item). As these two opcodes are not listed in the next switch, they will + end up as the next code to inspect, and return FALSE by virtue of being + unsupported. */ + case OP_KET: - /* If the bracket is capturing, and referenced by an OP_RECURSE, or - it is an atomic sub-pattern (assert, once, etc.) the non-greedy case - cannot be converted to a possessive form. */ + case OP_KETRPOS: + /* The non-greedy case cannot be converted to a possessive form. */ if (base_list[1] == 0) return FALSE; + /* If the bracket is capturing it might be referenced by an OP_RECURSE + so its last iterator can never be possessified if the pattern contains + recursions. (This could be improved by keeping a list of group numbers that + are called by recursion.) */ + switch(*(code - GET(code, 1))) { + case OP_CBRA: + case OP_SCBRA: + case OP_CBRAPOS: + case OP_SCBRAPOS: + if (cb->had_recurse) return FALSE; + break; + + /* Atomic sub-patterns and assertions can always auto-possessify their + last iterator. However, if the group was entered as a result of checking + a previous iterator, this is not possible. */ + case OP_ASSERT: case OP_ASSERT_NOT: case OP_ASSERTBACK: case OP_ASSERTBACK_NOT: case OP_ONCE: - /* Atomic sub-patterns and assertions can always auto-possessify their - last iterator. However, if the group was entered as a result of checking - a previous iterator, this is not possible. */ - return !entered_a_group; } + /* Skip over the bracket and inspect what comes next. */ + code += PRIV(OP_lengths)[c]; continue; + /* Handle cases where the next item is a group. */ + case OP_ONCE: case OP_BRA: case OP_CBRA: @@ -637,11 +663,15 @@ for(;;) code += PRIV(OP_lengths)[c]; continue; + /* The next opcode does not need special handling; fall through and use it + to see if the base can be possessified. */ + default: break; } - /* Check for a supported opcode, and load its properties. */ + /* We now have the next appropriate opcode to compare with the base. Check + for a supported opcode, and load its properties. */ code = get_chr_property_list(code, utf, cb->fcc, list); if (code == NULL) return FALSE; /* Unsupported */ diff --git a/ProcessHacker/pcre/pcre2_compile.c b/ProcessHacker/pcre/pcre2_compile.c index e8de8dabbce4..87530fb58441 100644 --- a/ProcessHacker/pcre/pcre2_compile.c +++ b/ProcessHacker/pcre/pcre2_compile.c @@ -38,9 +38,6 @@ POSSIBILITY OF SUCH DAMAGE. ----------------------------------------------------------------------------- */ -// dmex: Disable warnings. -#pragma warning(push) -#pragma warning(disable : 4244 4267) #ifdef HAVE_CONFIG_H #include "config.h" @@ -2197,8 +2194,8 @@ manage_callouts(PCRE2_SPTR ptr, uint32_t **pcalloutptr, BOOL auto_callout, { uint32_t *previous_callout = *pcalloutptr; -if (previous_callout != NULL) previous_callout[2] = ptr - cb->start_pattern - - (PCRE2_SIZE)previous_callout[1]; +if (previous_callout != NULL) previous_callout[2] = (uint32_t)(ptr - + cb->start_pattern - (PCRE2_SIZE)previous_callout[1]); if (!auto_callout) previous_callout = NULL; else { @@ -3809,7 +3806,7 @@ while (ptr < ptrend) /* Remember the offset to the next item in the pattern, and set a default length. This should get updated after the next item is read. */ - previous_callout[1] = ptr - cb->start_pattern; + previous_callout[1] = (uint32_t)(ptr - cb->start_pattern); previous_callout[2] = 0; break; /* End callout */ @@ -5602,14 +5599,17 @@ for (;; pptr++) /* ===================================================================*/ /* Deal with (*VERB)s. */ - /* Check for open captures before ACCEPT and convert it to ASSERT_ACCEPT if - in an assertion. In the first pass, just accumulate the length required; + /* Check for open captures before ACCEPT and close those that are within + the same assertion level, also converting ACCEPT to ASSERT_ACCEPT in an + assertion. In the first pass, just accumulate the length required; otherwise hitting (*ACCEPT) inside many nested parentheses can cause workspace overflow. Do not set firstcu after *ACCEPT. */ case META_ACCEPT: cb->had_accept = TRUE; - for (oc = cb->open_caps; oc != NULL; oc = oc->next) + for (oc = cb->open_caps; + oc != NULL && oc->assert_depth >= cb->assert_depth; + oc = oc->next) { if (lengthptr != NULL) { @@ -7135,7 +7135,7 @@ for (;; pptr++) later. */ HANDLE_SINGLE_REFERENCE: - if (firstcuflags == REQ_UNSET) firstcuflags = REQ_NONE; + if (firstcuflags == REQ_UNSET) zerofirstcuflags = firstcuflags = REQ_NONE; *code++ = ((options & PCRE2_CASELESS) != 0)? OP_REFI : OP_REF; PUT2INC(code, 0, meta_arg); @@ -7486,6 +7486,7 @@ if (*code == OP_CBRA) capitem.number = capnumber; capitem.next = cb->open_caps; capitem.flag = FALSE; + capitem.assert_depth = cb->assert_depth; cb->open_caps = &capitem; } @@ -8105,13 +8106,13 @@ REQ_NONE in the flags. Arguments: code points to start of compiled pattern flags points to the first code unit flags - inassert TRUE if in an assertion + inassert non-zero if in an assertion Returns: the fixed first code unit, or 0 with REQ_NONE in flags */ static uint32_t -find_firstassertedcu(PCRE2_SPTR code, int32_t *flags, BOOL inassert) +find_firstassertedcu(PCRE2_SPTR code, int32_t *flags, uint32_t inassert) { uint32_t c = 0; int cflags = REQ_NONE; @@ -8138,7 +8139,7 @@ do { case OP_SCBRAPOS: case OP_ASSERT: case OP_ONCE: - d = find_firstassertedcu(scode, &dflags, op == OP_ASSERT); + d = find_firstassertedcu(scode, &dflags, inassert + ((op==OP_ASSERT)?1:0)); if (dflags < 0) return 0; if (cflags < 0) { c = d; cflags = dflags; } @@ -8153,7 +8154,7 @@ do { case OP_PLUS: case OP_MINPLUS: case OP_POSPLUS: - if (!inassert) return 0; + if (inassert == 0) return 0; if (cflags < 0) { c = scode[1]; cflags = 0; } else if (c != scode[1]) return 0; break; @@ -8166,7 +8167,7 @@ do { case OP_PLUSI: case OP_MINPLUSI: case OP_POSPLUSI: - if (!inassert) return 0; + if (inassert == 0) return 0; if (cflags < 0) { c = scode[1]; cflags = REQ_CASELESS; } else if (c != scode[1]) return 0; break; @@ -9484,6 +9485,7 @@ re->blocksize = re_blocksize; re->magic_number = MAGIC_NUMBER; re->compile_options = options; re->overall_options = cb.external_options; +re->extra_options = ccontext->extra_options; re->flags = PCRE2_CODE_UNIT_WIDTH/8 | cb.external_flags | setflags; re->limit_heap = limit_heap; re->limit_match = limit_match; @@ -9673,7 +9675,7 @@ if ((re->overall_options & PCRE2_NO_START_OPTIMIZE) == 0) actual literals that follow). */ if (firstcuflags < 0) - firstcu = find_firstassertedcu(codestart, &firstcuflags, FALSE); + firstcu = find_firstassertedcu(codestart, &firstcuflags, 0); /* Save the data for a first code unit. */ @@ -9787,5 +9789,3 @@ goto EXIT; } /* End of pcre2_compile.c */ - -#pragma warning(pop) diff --git a/ProcessHacker/pcre/pcre2_config.c b/ProcessHacker/pcre/pcre2_config.c index d009c0a676a5..e487b1022070 100644 --- a/ProcessHacker/pcre/pcre2_config.c +++ b/ProcessHacker/pcre/pcre2_config.c @@ -84,11 +84,13 @@ if (where == NULL) /* Requests a length */ return PCRE2_ERROR_BADOPTION; case PCRE2_CONFIG_BSR: + case PCRE2_CONFIG_COMPILED_WIDTHS: + case PCRE2_CONFIG_DEPTHLIMIT: case PCRE2_CONFIG_HEAPLIMIT: case PCRE2_CONFIG_JIT: case PCRE2_CONFIG_LINKSIZE: case PCRE2_CONFIG_MATCHLIMIT: - case PCRE2_CONFIG_DEPTHLIMIT: + case PCRE2_CONFIG_NEVER_BACKSLASH_C: case PCRE2_CONFIG_NEWLINE: case PCRE2_CONFIG_PARENSLIMIT: case PCRE2_CONFIG_STACKRECURSE: /* Obsolete */ @@ -117,6 +119,24 @@ switch (what) #endif break; + case PCRE2_CONFIG_COMPILED_WIDTHS: + *((uint32_t *)where) = 0 +#ifdef SUPPORT_PCRE2_8 + + 1 +#endif +#ifdef SUPPORT_PCRE2_16 + + 2 +#endif +#ifdef SUPPORT_PCRE2_32 + + 4 +#endif + ; + break; + + case PCRE2_CONFIG_DEPTHLIMIT: + *((uint32_t *)where) = MATCH_LIMIT_DEPTH; + break; + case PCRE2_CONFIG_HEAPLIMIT: *((uint32_t *)where) = HEAP_LIMIT; break; @@ -148,14 +168,18 @@ switch (what) *((uint32_t *)where) = MATCH_LIMIT; break; - case PCRE2_CONFIG_DEPTHLIMIT: - *((uint32_t *)where) = MATCH_LIMIT_DEPTH; - break; - case PCRE2_CONFIG_NEWLINE: *((uint32_t *)where) = NEWLINE_DEFAULT; break; + case PCRE2_CONFIG_NEVER_BACKSLASH_C: +#ifdef NEVER_BACKSLASH_C + *((uint32_t *)where) = 1; +#else + *((uint32_t *)where) = 0; +#endif + break; + case PCRE2_CONFIG_PARENSLIMIT: *((uint32_t *)where) = PARENS_NEST_LIMIT; break; diff --git a/ProcessHacker/pcre/pcre2_dfa_match.c b/ProcessHacker/pcre/pcre2_dfa_match.c index 5ae13944c72b..c6184ff5e9ea 100644 --- a/ProcessHacker/pcre/pcre2_dfa_match.c +++ b/ProcessHacker/pcre/pcre2_dfa_match.c @@ -7,7 +7,7 @@ and semantics are as close as possible to those of the Perl 5 language. Written by Philip Hazel Original API code Copyright (c) 1997-2012 University of Cambridge - New API code Copyright (c) 2016-2017 University of Cambridge + New API code Copyright (c) 2016-2018 University of Cambridge ----------------------------------------------------------------------------- Redistribution and use in source and binary forms, with or without @@ -293,6 +293,66 @@ typedef struct stateblock { +/************************************************* +* Process a callout * +*************************************************/ + +/* This function is called to perform a callout. + +Arguments: + code current code pointer + offsets points to current capture offsets + current_subject start of current subject match + ptr current position in subject + mb the match block + extracode extra code offset when called from condition + lengthptr where to return the callout length + +Returns: the return from the callout +*/ + +static int +do_callout(PCRE2_SPTR code, PCRE2_SIZE *offsets, PCRE2_SPTR current_subject, + PCRE2_SPTR ptr, dfa_match_block *mb, PCRE2_SIZE extracode, + PCRE2_SIZE *lengthptr) +{ +pcre2_callout_block *cb = mb->cb; + +*lengthptr = (code[extracode] == OP_CALLOUT)? + (PCRE2_SIZE)PRIV(OP_lengths)[OP_CALLOUT] : + (PCRE2_SIZE)GET(code, 1 + 2*LINK_SIZE + extracode); + +if (mb->callout == NULL) return 0; /* No callout provided */ + +/* Fixed fields in the callout block are set once and for all at the start of +matching. */ + +cb->offset_vector = offsets; +cb->start_match = (PCRE2_SIZE)(current_subject - mb->start_subject); +cb->current_position = (PCRE2_SIZE)(ptr - mb->start_subject); +cb->pattern_position = GET(code, 1 + extracode); +cb->next_item_length = GET(code, 1 + LINK_SIZE + extracode); + +if (code[extracode] == OP_CALLOUT) + { + cb->callout_number = code[1 + 2*LINK_SIZE + extracode]; + cb->callout_string_offset = 0; + cb->callout_string = NULL; + cb->callout_string_length = 0; + } +else + { + cb->callout_number = 0; + cb->callout_string_offset = GET(code, 1 + 3*LINK_SIZE + extracode); + cb->callout_string = code + (1 + 4*LINK_SIZE + extracode) + 1; + cb->callout_string_length = *lengthptr - (1 + 4*LINK_SIZE) - 2; + } + +return (mb->callout)(cb, mb->callout_data); +} + + + /************************************************* * Match a Regular Expression - DFA engine * *************************************************/ @@ -448,7 +508,8 @@ if (*this_start_code == OP_ASSERTBACK || *this_start_code == OP_ASSERTBACK_NOT) { if (current_subject <= start_subject) break; current_subject--; - ACROSSCHAR(current_subject > start_subject, *current_subject, current_subject--); + ACROSSCHAR(current_subject > start_subject, current_subject, + current_subject--); } } else @@ -1364,63 +1425,14 @@ for (;;) if (count > 0) { ADD_ACTIVE(state_offset + 2, 0); } if (clen > 0) { - uint32_t lgb, rgb; - PCRE2_SPTR nptr = ptr + clen; int ncount = 0; if (count > 0 && codevalue == OP_EXTUNI_EXTRA + OP_TYPEPOSPLUS) { active_count--; /* Remove non-match possibility */ next_active_state--; } - lgb = UCD_GRAPHBREAK(c); - while (nptr < end_subject) - { - dlen = 1; - if (!utf) d = *nptr; else { GETCHARLEN(d, nptr, dlen); } - rgb = UCD_GRAPHBREAK(d); - if ((PRIV(ucp_gbtable)[lgb] & (1u << rgb)) == 0) break; - - /* Not breaking between Regional Indicators is allowed only if - there are an even number of preceding RIs. */ - - if (lgb == ucp_gbRegionalIndicator && - rgb == ucp_gbRegionalIndicator) - { - int ricount = 0; - PCRE2_SPTR bptr = nptr - 1; -#ifdef SUPPORT_UNICODE - if (utf) BACKCHAR(bptr); -#endif - /* bptr is pointing to the left-hand character */ - - while (bptr > mb->start_subject) - { - bptr--; -#ifdef SUPPORT_UNICODE - if (utf) - { - BACKCHAR(bptr); - GETCHAR(d, bptr); - } - else -#endif - d = *bptr; - if (UCD_GRAPHBREAK(d) != ucp_gbRegionalIndicator) break; - ricount++; - } - if ((ricount & 1) != 0) break; /* Grapheme break required */ - } - - /* If Extend follows E_Base[_GAZ] do not update lgb; this allows - any number of Extend before a following E_Modifier. */ - - if (rgb != ucp_gbExtend || - (lgb != ucp_gbE_Base && lgb != ucp_gbE_Base_GAZ)) - lgb = rgb; - - ncount++; - nptr += dlen; - } + (void)PRIV(extuni)(c, ptr + clen, mb->start_subject, end_subject, utf, + &ncount); count++; ADD_NEW_DATA(-state_offset, count, ncount); } @@ -1663,8 +1675,6 @@ for (;;) ADD_ACTIVE(state_offset + 2, 0); if (clen > 0) { - uint32_t lgb, rgb; - PCRE2_SPTR nptr = ptr + clen; int ncount = 0; if (codevalue == OP_EXTUNI_EXTRA + OP_TYPEPOSSTAR || codevalue == OP_EXTUNI_EXTRA + OP_TYPEPOSQUERY) @@ -1672,55 +1682,8 @@ for (;;) active_count--; /* Remove non-match possibility */ next_active_state--; } - lgb = UCD_GRAPHBREAK(c); - while (nptr < end_subject) - { - dlen = 1; - if (!utf) d = *nptr; else { GETCHARLEN(d, nptr, dlen); } - rgb = UCD_GRAPHBREAK(d); - if ((PRIV(ucp_gbtable)[lgb] & (1u << rgb)) == 0) break; - - /* Not breaking between Regional Indicators is allowed only if - there are an even number of preceding RIs. */ - - if (lgb == ucp_gbRegionalIndicator && - rgb == ucp_gbRegionalIndicator) - { - int ricount = 0; - PCRE2_SPTR bptr = nptr - 1; -#ifdef SUPPORT_UNICODE - if (utf) BACKCHAR(bptr); -#endif - /* bptr is pointing to the left-hand character */ - - while (bptr > mb->start_subject) - { - bptr--; -#ifdef SUPPORT_UNICODE - if (utf) - { - BACKCHAR(bptr); - GETCHAR(d, bptr); - } - else -#endif - d = *bptr; - if (UCD_GRAPHBREAK(d) != ucp_gbRegionalIndicator) break; - ricount++; - } - if ((ricount & 1) != 0) break; /* Grapheme break required */ - } - - /* If Extend follows E_Base[_GAZ] do not update lgb; this allows - any number of Extend before a following E_Modifier. */ - - if (rgb != ucp_gbExtend || - (lgb != ucp_gbE_Base && lgb != ucp_gbE_Base_GAZ)) - lgb = rgb; - - ncount++; - nptr += dlen; - } + (void)PRIV(extuni)(c, ptr + clen, mb->start_subject, end_subject, utf, + &ncount); ADD_NEW_DATA(-(state_offset + count), 0, ncount); } break; @@ -1973,63 +1936,15 @@ for (;;) count = current_state->count; /* Number already matched */ if (clen > 0) { - uint32_t lgb, rgb; - PCRE2_SPTR nptr = ptr + clen; + PCRE2_SPTR nptr; int ncount = 0; if (codevalue == OP_EXTUNI_EXTRA + OP_TYPEPOSUPTO) { active_count--; /* Remove non-match possibility */ next_active_state--; } - lgb = UCD_GRAPHBREAK(c); - while (nptr < end_subject) - { - dlen = 1; - if (!utf) d = *nptr; else { GETCHARLEN(d, nptr, dlen); } - rgb = UCD_GRAPHBREAK(d); - if ((PRIV(ucp_gbtable)[lgb] & (1u << rgb)) == 0) break; - - /* Not breaking between Regional Indicators is allowed only if - there are an even number of preceding RIs. */ - - if (lgb == ucp_gbRegionalIndicator && - rgb == ucp_gbRegionalIndicator) - { - int ricount = 0; - PCRE2_SPTR bptr = nptr - 1; -#ifdef SUPPORT_UNICODE - if (utf) BACKCHAR(bptr); -#endif - /* bptr is pointing to the left-hand character */ - - while (bptr > mb->start_subject) - { - bptr--; -#ifdef SUPPORT_UNICODE - if (utf) - { - BACKCHAR(bptr); - GETCHAR(d, bptr); - } - else -#endif - d = *bptr; - if (UCD_GRAPHBREAK(d) != ucp_gbRegionalIndicator) break; - ricount++; - } - if ((ricount & 1) != 0) break; /* Grapheme break required */ - } - - /* If Extend follows E_Base[_GAZ] do not update lgb; this allows - any number of Extend before a following E_Modifier. */ - - if (rgb != ucp_gbExtend || - (lgb != ucp_gbE_Base && lgb != ucp_gbE_Base_GAZ)) - lgb = rgb; - - ncount++; - nptr += dlen; - } + nptr = PRIV(extuni)(c, ptr + clen, mb->start_subject, end_subject, utf, + &ncount); if (nptr >= end_subject && (mb->moptions & PCRE2_PARTIAL_HARD) != 0) reset_could_continue = TRUE; if (++count >= (int)GET2(code, 1)) @@ -2206,58 +2121,9 @@ for (;;) case OP_EXTUNI: if (clen > 0) { - uint32_t lgb, rgb; - PCRE2_SPTR nptr = ptr + clen; int ncount = 0; - lgb = UCD_GRAPHBREAK(c); - while (nptr < end_subject) - { - dlen = 1; - if (!utf) d = *nptr; else { GETCHARLEN(d, nptr, dlen); } - rgb = UCD_GRAPHBREAK(d); - if ((PRIV(ucp_gbtable)[lgb] & (1u << rgb)) == 0) break; - - /* Not breaking between Regional Indicators is allowed only if - there are an even number of preceding RIs. */ - - if (lgb == ucp_gbRegionalIndicator && - rgb == ucp_gbRegionalIndicator) - { - int ricount = 0; - PCRE2_SPTR bptr = nptr - 1; -#ifdef SUPPORT_UNICODE - if (utf) BACKCHAR(bptr); -#endif - /* bptr is pointing to the left-hand character */ - - while (bptr > mb->start_subject) - { - bptr--; -#ifdef SUPPORT_UNICODE - if (utf) - { - BACKCHAR(bptr); - GETCHAR(d, bptr); - } - else -#endif - d = *bptr; - if (UCD_GRAPHBREAK(d) != ucp_gbRegionalIndicator) break; - ricount++; - } - if ((ricount & 1) != 0) break; /* Grapheme break required */ - } - - /* If Extend follows E_Base[_GAZ] do not update lgb; this allows - any number of Extend before a following E_Modifier. */ - - if (rgb != ucp_gbExtend || - (lgb != ucp_gbE_Base && lgb != ucp_gbE_Base_GAZ)) - lgb = rgb; - - ncount++; - nptr += dlen; - } + PCRE2_SPTR nptr = PRIV(extuni)(c, ptr + clen, mb->start_subject, + end_subject, utf, &ncount); if (nptr >= end_subject && (mb->moptions & PCRE2_PARTIAL_HARD) != 0) reset_could_continue = TRUE; ADD_NEW_DATA(-(state_offset + 1), 0, ncount); @@ -2371,7 +2237,7 @@ for (;;) case OP_NOTI: if (clen > 0) { - unsigned int otherd; + uint32_t otherd; #ifdef SUPPORT_UNICODE if (utf && d >= 128) otherd = UCD_OTHERCASE(d); @@ -2761,45 +2627,10 @@ for (;;) if (code[LINK_SIZE + 1] == OP_CALLOUT || code[LINK_SIZE + 1] == OP_CALLOUT_STR) { - PCRE2_SIZE callout_length = (code[LINK_SIZE + 1] == OP_CALLOUT)? - (PCRE2_SIZE)PRIV(OP_lengths)[OP_CALLOUT] : - (PCRE2_SIZE)GET(code, 2 + 3*LINK_SIZE); - - rrc = 0; - if (mb->callout != NULL) - { - pcre2_callout_block cb; - cb.version = 1; - cb.capture_top = 1; - cb.capture_last = 0; - cb.offset_vector = offsets; - cb.mark = NULL; /* No (*MARK) support */ - cb.subject = start_subject; - cb.subject_length = (PCRE2_SIZE)(end_subject - start_subject); - cb.start_match = (PCRE2_SIZE)(current_subject - start_subject); - cb.current_position = (PCRE2_SIZE)(ptr - start_subject); - cb.pattern_position = GET(code, LINK_SIZE + 2); - cb.next_item_length = GET(code, LINK_SIZE + 2 + LINK_SIZE); - - if (code[LINK_SIZE + 1] == OP_CALLOUT) - { - cb.callout_number = code[2 + 3*LINK_SIZE]; - cb.callout_string_offset = 0; - cb.callout_string = NULL; - cb.callout_string_length = 0; - } - else - { - cb.callout_number = 0; - cb.callout_string_offset = GET(code, 2 + 4*LINK_SIZE); - cb.callout_string = code + (2 + 5*LINK_SIZE) + 1; - cb.callout_string_length = - callout_length - (1 + 4*LINK_SIZE) - 2; - } - - if ((rrc = (mb->callout)(&cb, mb->callout_data)) < 0) - return rrc; /* Abandon */ - } + PCRE2_SIZE callout_length; + rrc = do_callout(code, offsets, current_subject, ptr, mb, + 1 + LINK_SIZE, &callout_length); + if (rrc < 0) return rrc; /* Abandon */ if (rrc > 0) break; /* Fail this thread */ code += callout_length; /* Skip callout data */ } @@ -3131,44 +2962,10 @@ for (;;) case OP_CALLOUT: case OP_CALLOUT_STR: { - unsigned int callout_length = (*code == OP_CALLOUT) - ? PRIV(OP_lengths)[OP_CALLOUT] : GET(code, 1 + 2*LINK_SIZE); - rrc = 0; - - if (mb->callout != NULL) - { - pcre2_callout_block cb; - cb.version = 1; - cb.capture_top = 1; - cb.capture_last = 0; - cb.offset_vector = offsets; - cb.mark = NULL; /* No (*MARK) support */ - cb.subject = start_subject; - cb.subject_length = (PCRE2_SIZE)(end_subject - start_subject); - cb.start_match = (PCRE2_SIZE)(current_subject - start_subject); - cb.current_position = (PCRE2_SIZE)(ptr - start_subject); - cb.pattern_position = GET(code, 1); - cb.next_item_length = GET(code, 1 + LINK_SIZE); - - if (*code == OP_CALLOUT) - { - cb.callout_number = code[1 + 2*LINK_SIZE]; - cb.callout_string_offset = 0; - cb.callout_string = NULL; - cb.callout_string_length = 0; - } - else - { - cb.callout_number = 0; - cb.callout_string_offset = GET(code, 1 + 3*LINK_SIZE); - cb.callout_string = code + (1 + 4*LINK_SIZE) + 1; - cb.callout_string_length = - callout_length - (1 + 4*LINK_SIZE) - 2; - } - - if ((rrc = (mb->callout)(&cb, mb->callout_data)) < 0) - return rrc; /* Abandon */ - } + PCRE2_SIZE callout_length; + rrc = do_callout(code, offsets, current_subject, ptr, mb, 0, + &callout_length); + if (rrc < 0) return rrc; /* Abandon */ if (rrc == 0) { ADD_ACTIVE(state_offset + (int)callout_length, 0); } } @@ -3287,6 +3084,7 @@ const uint8_t *start_bits = NULL; /* We need to have mb pointing to a match block, because the IS_NEWLINE macro is used below, and it expects NLBLOCK to be defined as a pointer. */ +pcre2_callout_block cb; dfa_match_block actual_match_block; dfa_match_block *mb = &actual_match_block; @@ -3364,9 +3162,21 @@ startline = (re->flags & PCRE2_STARTLINE) != 0; firstline = (re->overall_options & PCRE2_FIRSTLINE) != 0; bumpalong_limit = end_subject; -/* Get data from the match context, if present, and fill in the fields in the -match block. It is an error to set an offset limit without setting the flag at -compile time. */ +/* Initialize and set up the fixed fields in the callout block, with a pointer +in the match block. */ + +mb->cb = &cb; +cb.version = 2; +cb.subject = subject; +cb.subject_length = (PCRE2_SIZE)(end_subject - subject); +cb.callout_flags = 0; +cb.capture_top = 1; /* No capture support */ +cb.capture_last = 0; +cb.mark = NULL; /* No (*MARK) support */ + +/* Get data from the match context, if present, and fill in the remaining +fields in the match block. It is an error to set an offset limit without +setting the flag at compile time. */ if (mcontext == NULL) { @@ -3554,13 +3364,13 @@ for (;;) if ((re->overall_options & PCRE2_NO_START_OPTIMIZE) == 0 && (options & PCRE2_DFA_RESTART) == 0) { - PCRE2_SPTR save_end_subject = end_subject; - /* If firstline is TRUE, the start of the match is constrained to the first line of a multiline string. That is, the match must be before or at the - first newline. Implement this by temporarily adjusting end_subject so that - we stop the optimization scans for a first code unit at a newline. If the - match fails at the newline, later code breaks this loop. */ + first newline following the start of matching. Temporarily adjust + end_subject so that we stop the optimization scans for a first code unit + immediately after the first character of a newline (the first code unit can + legitimately be a newline). If the match fails at the newline, later code + breaks this loop. */ if (firstline) { @@ -3568,15 +3378,15 @@ for (;;) #ifdef SUPPORT_UNICODE if (utf) { - while (t < mb->end_subject && !IS_NEWLINE(t)) + while (t < end_subject && !IS_NEWLINE(t)) { t++; - ACROSSCHAR(t < end_subject, *t, t++); + ACROSSCHAR(t < end_subject, t, t++); } } else #endif - while (t < mb->end_subject && !IS_NEWLINE(t)) t++; + while (t < end_subject && !IS_NEWLINE(t)) t++; end_subject = t; } @@ -3648,14 +3458,18 @@ for (;;) #endif } - /* If we can't find the required code unit, break the bumpalong loop, - to force a match failure, except when doing partial matching, when we - let the next cycle run at the end of the subject. To see why, consider - the pattern /(?<=abc)def/, which partially matches "abc", even though - the string does not contain the starting character "d". */ + /* If we can't find the required code unit, having reached the true end + of the subject, break the bumpalong loop, to force a match failure, + except when doing partial matching, when we let the next cycle run at + the end of the subject. To see why, consider the pattern /(?<=abc)def/, + which partially matches "abc", even though the string does not contain + the starting character "d". If we have not reached the true end of the + subject (PCRE2_FIRSTLINE caused end_subject to be temporarily modified) + we also let the cycle run, because the matching string is legitimately + allowed to start with the first code unit of a newline. */ if ((mb->moptions & (PCRE2_PARTIAL_HARD|PCRE2_PARTIAL_SOFT)) == 0 && - start_match >= end_subject) + start_match >= mb->end_subject) break; } @@ -3672,8 +3486,7 @@ for (;;) while (start_match < end_subject && !WAS_NEWLINE(start_match)) { start_match++; - ACROSSCHAR(start_match < end_subject, *start_match, - start_match++); + ACROSSCHAR(start_match < end_subject, start_match, start_match++); } } else @@ -3709,12 +3522,18 @@ for (;;) if ((start_bits[c/8] & (1 << (c&7))) != 0) break; start_match++; } + + /* See comment above in first_cu checking about the next line. */ + + if ((mb->moptions & (PCRE2_PARTIAL_HARD|PCRE2_PARTIAL_SOFT)) == 0 && + start_match >= mb->end_subject) + break; } } /* End of first code unit handling */ /* Restore fudged end_subject */ - end_subject = save_end_subject; + end_subject = mb->end_subject; /* The following two optimizations are disabled for partial matching. */ @@ -3829,8 +3648,7 @@ for (;;) #ifdef SUPPORT_UNICODE if (utf) { - ACROSSCHAR(start_match < end_subject, *start_match, - start_match++); + ACROSSCHAR(start_match < end_subject, start_match, start_match++); } #endif if (start_match > end_subject) break; diff --git a/ProcessHacker/pcre/pcre2_extuni.c b/ProcessHacker/pcre/pcre2_extuni.c new file mode 100644 index 000000000000..11a0bfbdd679 --- /dev/null +++ b/ProcessHacker/pcre/pcre2_extuni.c @@ -0,0 +1,148 @@ +/************************************************* +* Perl-Compatible Regular Expressions * +*************************************************/ + +/* PCRE is a library of functions to support regular expressions whose syntax +and semantics are as close as possible to those of the Perl 5 language. + + Written by Philip Hazel + Original API code Copyright (c) 1997-2012 University of Cambridge + New API code Copyright (c) 2016-2018 University of Cambridge + +----------------------------------------------------------------------------- +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of the University of Cambridge nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +----------------------------------------------------------------------------- +*/ + +/* This module contains an internal function that is used to match a Unicode +extended grapheme sequence. It is used by both pcre2_match() and +pcre2_def_match(). However, it is called only when Unicode support is being +compiled. Nevertheless, we provide a dummy function when there is no Unicode +support, because some compilers do not like functionless source files. */ + + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + + +#include "pcre2_internal.h" + + +/* Dummy function */ + +#ifndef SUPPORT_UNICODE +PCRE2_SPTR +PRIV(extuni)(uint32_t c, PCRE2_SPTR eptr, PCRE2_SPTR start_subject, + PCRE2_SPTR end_subject, BOOL utf, int *xcount) +{ +(void)c; +(void)eptr; +(void)start_subject; +(void)end_subject; +(void)utf; +(void)xcount; +return NULL; +} +#else + + +/************************************************* +* Match an extended grapheme sequence * +*************************************************/ + +/* +Arguments: + c the first character + eptr pointer to next character + start_subject pointer to start of subject + end_subject pointer to end of subject + utf TRUE if in UTF mode + xcount pointer to count of additional characters, + or NULL if count not needed + +Returns: pointer after the end of the sequence +*/ + +PCRE2_SPTR +PRIV(extuni)(uint32_t c, PCRE2_SPTR eptr, PCRE2_SPTR start_subject, + PCRE2_SPTR end_subject, BOOL utf, int *xcount) +{ +int lgb = UCD_GRAPHBREAK(c); + +while (eptr < end_subject) + { + int rgb; + int len = 1; + if (!utf) c = *eptr; else { GETCHARLEN(c, eptr, len); } + rgb = UCD_GRAPHBREAK(c); + if ((PRIV(ucp_gbtable)[lgb] & (1 << rgb)) == 0) break; + + /* Not breaking between Regional Indicators is allowed only if there + are an even number of preceding RIs. */ + + if (lgb == ucp_gbRegionalIndicator && rgb == ucp_gbRegionalIndicator) + { + int ricount = 0; + PCRE2_SPTR bptr = eptr - 1; + if (utf) BACKCHAR(bptr); + + /* bptr is pointing to the left-hand character */ + + while (bptr > start_subject) + { + bptr--; + if (utf) + { + BACKCHAR(bptr); + GETCHAR(c, bptr); + } + else + c = *bptr; + if (UCD_GRAPHBREAK(c) != ucp_gbRegionalIndicator) break; + ricount++; + } + if ((ricount & 1) != 0) break; /* Grapheme break required */ + } + + /* If Extend follows E_Base[_GAZ] do not update lgb; this allows + any number of Extend before a following E_Modifier. */ + + if (rgb != ucp_gbExtend || + (lgb != ucp_gbE_Base && lgb != ucp_gbE_Base_GAZ)) + lgb = rgb; + + eptr += len; + if (xcount != NULL) *xcount += 1; + } + +return eptr; +} + +#endif /* SUPPORT_UNICODE */ + +/* End of pcre2_extuni.c */ diff --git a/ProcessHacker/pcre/pcre2_internal.h b/ProcessHacker/pcre/pcre2_internal.h index 9ccce25d4712..3db9d604f47d 100644 --- a/ProcessHacker/pcre/pcre2_internal.h +++ b/ProcessHacker/pcre/pcre2_internal.h @@ -38,6 +38,9 @@ POSSIBILITY OF SUCH DAMAGE. ----------------------------------------------------------------------------- */ +#ifndef PCRE2_INTERNAL_H_IDEMPOTENT_GUARD +#define PCRE2_INTERNAL_H_IDEMPOTENT_GUARD + /* We do not support both EBCDIC and Unicode at the same time. The "configure" script prevents both being selected, but not everybody uses "configure". EBCDIC is only supported for the 8-bit library, but the check for this has to be later @@ -1767,6 +1770,7 @@ typedef struct open_capitem { struct open_capitem *next; /* Chain link */ uint16_t number; /* Capture number */ uint16_t flag; /* Set TRUE if recursive back ref */ + uint16_t assert_depth; /* Assertion depth when opened */ } open_capitem; /* Layout of the UCP type table that translates property names into types and @@ -1926,6 +1930,7 @@ is available. */ #define _pcre2_auto_possessify PCRE2_SUFFIX(_pcre2_auto_possessify_) #define _pcre2_check_escape PCRE2_SUFFIX(_pcre2_check_escape_) +#define _pcre2_extuni PCRE2_SUFFIX(_pcre2_extuni_) #define _pcre2_find_bracket PCRE2_SUFFIX(_pcre2_find_bracket_) #define _pcre2_is_newline PCRE2_SUFFIX(_pcre2_is_newline_) #define _pcre2_jit_free_rodata PCRE2_SUFFIX(_pcre2_jit_free_rodata_) @@ -1949,6 +1954,8 @@ extern int _pcre2_auto_possessify(PCRE2_UCHAR *, BOOL, const compile_block *); extern int _pcre2_check_escape(PCRE2_SPTR *, PCRE2_SPTR, uint32_t *, int *, uint32_t, BOOL, compile_block *); +extern PCRE2_SPTR _pcre2_extuni(uint32_t, PCRE2_SPTR, PCRE2_SPTR, PCRE2_SPTR, + BOOL, int *); extern PCRE2_SPTR _pcre2_find_bracket(PCRE2_SPTR, BOOL, int); extern BOOL _pcre2_is_newline(PCRE2_SPTR, uint32_t, PCRE2_SPTR, uint32_t *, BOOL); @@ -1970,5 +1977,6 @@ extern BOOL _pcre2_was_newline(PCRE2_SPTR, uint32_t, PCRE2_SPTR, uint32_t *, BOOL); extern BOOL _pcre2_xclass(uint32_t, PCRE2_SPTR, BOOL); #endif /* PCRE2_CODE_UNIT_WIDTH */ +#endif /* PCRE2_INTERNAL_H_IDEMPOTENT_GUARD */ /* End of pcre2_internal.h */ diff --git a/ProcessHacker/pcre/pcre2_intmodedep.h b/ProcessHacker/pcre/pcre2_intmodedep.h index 387f65eb08a9..c4c4c3adb9d1 100644 --- a/ProcessHacker/pcre/pcre2_intmodedep.h +++ b/ProcessHacker/pcre/pcre2_intmodedep.h @@ -7,7 +7,7 @@ and semantics are as close as possible to those of the Perl 5 language. Written by Philip Hazel Original API code Copyright (c) 1997-2012 University of Cambridge - New API code Copyright (c) 2016-2017 University of Cambridge + New API code Copyright (c) 2016-2018 University of Cambridge ----------------------------------------------------------------------------- Redistribution and use in source and binary forms, with or without @@ -351,7 +351,7 @@ because almost all calls are already within a block of UTF-8 only code. */ /* Same as above, but it allows a fully customizable form. */ #define ACROSSCHAR(condition, eptr, action) \ - while((condition) && ((eptr) & 0xc0u) == 0x80u) action + while((condition) && ((*eptr) & 0xc0u) == 0x80u) action /* Deposit a character into memory, returning the number of code units. */ @@ -457,7 +457,7 @@ code. */ /* Same as above, but it allows a fully customizable form. */ #define ACROSSCHAR(condition, eptr, action) \ - if ((condition) && ((eptr) & 0xfc00u) == 0xdc00u) action + if ((condition) && ((*eptr) & 0xfc00u) == 0xdc00u) action /* Deposit a character into memory, returning the number of code units. */ @@ -623,6 +623,7 @@ typedef struct pcre2_real_code { uint32_t magic_number; /* Paranoid and endianness check */ uint32_t compile_options; /* Options passed to pcre2_compile() */ uint32_t overall_options; /* Options after processing the pattern */ + uint32_t extra_options; /* Taken from compile_context */ uint32_t flags; /* Various state flags */ uint32_t limit_heap; /* Limit set in the pattern */ uint32_t limit_match; /* Limit set in the pattern */ @@ -639,11 +640,13 @@ typedef struct pcre2_real_code { uint16_t name_count; /* Number of name entries in the table */ } pcre2_real_code; -/* The real match data structure. Define ovector large so that array bound -checkers don't grumble. Memory for this structure is obtained by calling -pcre2_match_data_create(), which sets the size as the offset of ovector plus -pairs of elements for each capturing group. (See also the heapframe structure -below.) */ +/* The real match data structure. Define ovector as large as it can ever +actually be so that array bound checkers don't grumble. Memory for this +structure is obtained by calling pcre2_match_data_create(), which sets the size +as the offset of ovector plus a pair of elements for each capturable string, so +the size varies from call to call. As the maximum number of capturing +subpatterns is 65535 we must allow for 65536 strings to include the overall +match. (See also the heapframe structure below.) */ typedef struct pcre2_real_match_data { pcre2_memctl memctl; @@ -656,7 +659,7 @@ typedef struct pcre2_real_match_data { uint16_t matchedby; /* Type of match (normal, JIT, DFA) */ uint16_t oveccount; /* Number of pairs */ int rc; /* The return code from the match */ - PCRE2_SIZE ovector[10000];/* The first field */ + PCRE2_SIZE ovector[131072]; /* Must be last in the structure */ } pcre2_real_match_data; @@ -723,6 +726,8 @@ typedef struct compile_block { PCRE2_SIZE erroroffset; /* Offset of error in pattern */ uint16_t names_found; /* Number of entries so far */ uint16_t name_entry_size; /* Size of each entry */ + uint16_t parens_depth; /* Depth of nested parentheses */ + uint16_t assert_depth; /* Depth of nested assertions */ open_capitem *open_caps; /* Chain of open capture items */ named_group *named_groups; /* Points to vector in pre-compile */ uint32_t named_group_list_size; /* Number of entries in the list */ @@ -741,8 +746,6 @@ typedef struct compile_block { uint32_t class_range_end; /* Overall class range end */ PCRE2_UCHAR nl[4]; /* Newline string when fixed length */ int max_lookbehind; /* Maximum lookbehind (characters) */ - int parens_depth; /* Depth of nested parentheses */ - int assert_depth; /* Depth of nested assertions */ int req_varyopt; /* "After variable item" flag for reqbyte */ BOOL had_accept; /* (*ACCEPT) encountered */ BOOL had_pruneorskip; /* (*PRUNE) or (*SKIP) encountered */ @@ -803,7 +806,7 @@ typedef struct heapframe { runtime array bound checks don't catch references to it. However, for any specific call to pcre2_match() the memory allocated for each frame structure allows for exactly the right size ovector for the number of capturing - parentheses. */ + parentheses. (See also the comment for pcre2_real_match_data above.) */ PCRE2_SPTR eptr; /* MUST BE FIRST */ PCRE2_SPTR start_match; /* Can be adjusted by \K */ @@ -812,7 +815,7 @@ typedef struct heapframe { uint32_t capture_last; /* Most recent capture */ PCRE2_SIZE last_group_offset; /* Saved offset to most recent group frame */ PCRE2_SIZE offset_top; /* Offset after highest capture */ - PCRE2_SIZE ovector[10000]; /* Must be last in the structure */ + PCRE2_SIZE ovector[131072]; /* Must be last in the structure */ } heapframe; typedef char check_heapframe_size[ @@ -861,6 +864,7 @@ typedef struct match_block { uint32_t nltype; /* Newline type */ uint32_t nllen; /* Newline string length */ PCRE2_UCHAR nl[4]; /* Newline string when fixed */ + pcre2_callout_block *cb; /* Points to a callout block */ void *callout_data; /* To pass back to callouts */ int (*callout)(pcre2_callout_block *,void *); /* Callout function or NULL */ } match_block; @@ -886,6 +890,7 @@ typedef struct dfa_match_block { uint32_t nllen; /* Newline string length */ PCRE2_UCHAR nl[4]; /* Newline string when fixed */ uint16_t bsr_convention; /* \R interpretation */ + pcre2_callout_block *cb; /* Points to a callout block */ void *callout_data; /* To pass back to callouts */ int (*callout)(pcre2_callout_block *,void *); /* Callout function or NULL */ dfa_recursion_info *recursive; /* Linked list of recursion data */ diff --git a/ProcessHacker/pcre/pcre2_jit_compile.c b/ProcessHacker/pcre/pcre2_jit_compile.c index c7bf0b2c3e02..80ed1c4ca6a7 100644 --- a/ProcessHacker/pcre/pcre2_jit_compile.c +++ b/ProcessHacker/pcre/pcre2_jit_compile.c @@ -228,7 +228,7 @@ enum control_types { type_then_trap = 1 }; -typedef int (SLJIT_CALL *jit_function)(jit_arguments *args); +typedef int (SLJIT_FUNC *jit_function)(jit_arguments *args); /* The following structure is the key data type for the recursive code generator. It is allocated by compile_matchingpath, and contains @@ -527,12 +527,27 @@ typedef struct compare_context { /* Used for accessing the elements of the stack. */ #define STACK(i) ((i) * (int)sizeof(sljit_sw)) +#ifdef SLJIT_PREF_SHIFT_REG +#if SLJIT_PREF_SHIFT_REG == SLJIT_R2 +/* Nothing. */ +#elif SLJIT_PREF_SHIFT_REG == SLJIT_R3 +#define SHIFT_REG_IS_R3 +#else +#error "Unsupported shift register" +#endif +#endif + #define TMP1 SLJIT_R0 +#ifdef SHIFT_REG_IS_R3 +#define TMP2 SLJIT_R3 +#define TMP3 SLJIT_R2 +#else #define TMP2 SLJIT_R2 #define TMP3 SLJIT_R3 -#define STR_PTR SLJIT_S0 -#define STR_END SLJIT_S1 -#define STACK_TOP SLJIT_R1 +#endif +#define STR_PTR SLJIT_R1 +#define STR_END SLJIT_S0 +#define STACK_TOP SLJIT_S1 #define STACK_LIMIT SLJIT_S2 #define COUNT_MATCH SLJIT_S3 #define ARGUMENTS SLJIT_S4 @@ -558,16 +573,13 @@ the start pointers when the end of the capturing group has not yet reached. */ #if PCRE2_CODE_UNIT_WIDTH == 8 #define MOV_UCHAR SLJIT_MOV_U8 -#define MOVU_UCHAR SLJIT_MOVU_U8 #define IN_UCHARS(x) (x) #elif PCRE2_CODE_UNIT_WIDTH == 16 #define MOV_UCHAR SLJIT_MOV_U16 -#define MOVU_UCHAR SLJIT_MOVU_U16 #define UCHAR_SHIFT (1) #define IN_UCHARS(x) ((x) * 2) #elif PCRE2_CODE_UNIT_WIDTH == 32 #define MOV_UCHAR SLJIT_MOV_U32 -#define MOVU_UCHAR SLJIT_MOVU_U32 #define UCHAR_SHIFT (2) #define IN_UCHARS(x) ((x) * 4) #else @@ -2697,12 +2709,25 @@ if (length < 8) } else { - GET_LOCAL_BASE(SLJIT_R1, 0, OVECTOR_START); - OP1(SLJIT_MOV, SLJIT_R2, 0, SLJIT_IMM, length - 1); - loop = LABEL(); - OP1(SLJIT_MOVU, SLJIT_MEM1(SLJIT_R1), sizeof(sljit_sw), SLJIT_R0, 0); - OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_R2, 0, SLJIT_R2, 0, SLJIT_IMM, 1); - JUMPTO(SLJIT_NOT_ZERO, loop); + if (sljit_emit_mem(compiler, SLJIT_MOV | SLJIT_MEM_SUPP | SLJIT_MEM_STORE | SLJIT_MEM_PRE, SLJIT_R0, SLJIT_MEM1(SLJIT_R1), sizeof(sljit_sw)) == SLJIT_SUCCESS) + { + GET_LOCAL_BASE(SLJIT_R1, 0, OVECTOR_START); + OP1(SLJIT_MOV, SLJIT_R2, 0, SLJIT_IMM, length - 1); + loop = LABEL(); + sljit_emit_mem(compiler, SLJIT_MOV | SLJIT_MEM_STORE | SLJIT_MEM_PRE, SLJIT_R0, SLJIT_MEM1(SLJIT_R1), sizeof(sljit_sw)); + OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_R2, 0, SLJIT_R2, 0, SLJIT_IMM, 1); + JUMPTO(SLJIT_NOT_ZERO, loop); + } + else + { + GET_LOCAL_BASE(SLJIT_R1, 0, OVECTOR_START + sizeof(sljit_sw)); + OP1(SLJIT_MOV, SLJIT_R2, 0, SLJIT_IMM, length - 1); + loop = LABEL(); + OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_R1), 0, SLJIT_R0, 0); + OP2(SLJIT_ADD, SLJIT_R1, 0, SLJIT_R1, 0, SLJIT_IMM, sizeof(sljit_sw)); + OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_R2, 0, SLJIT_R2, 0, SLJIT_IMM, 1); + JUMPTO(SLJIT_NOT_ZERO, loop); + } } } @@ -2735,12 +2760,25 @@ if (length < 8) } else { - GET_LOCAL_BASE(TMP2, 0, OVECTOR_START + sizeof(sljit_sw)); - OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_IMM, length - 2); - loop = LABEL(); - OP1(SLJIT_MOVU, SLJIT_MEM1(TMP2), sizeof(sljit_sw), TMP1, 0); - OP2(SLJIT_SUB | SLJIT_SET_Z, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, 1); - JUMPTO(SLJIT_NOT_ZERO, loop); + if (sljit_emit_mem(compiler, SLJIT_MOV | SLJIT_MEM_SUPP | SLJIT_MEM_STORE | SLJIT_MEM_PRE, TMP1, SLJIT_MEM1(TMP2), sizeof(sljit_sw)) == SLJIT_SUCCESS) + { + GET_LOCAL_BASE(TMP2, 0, OVECTOR_START + sizeof(sljit_sw)); + OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_IMM, length - 2); + loop = LABEL(); + sljit_emit_mem(compiler, SLJIT_MOV | SLJIT_MEM_STORE | SLJIT_MEM_PRE, TMP1, SLJIT_MEM1(TMP2), sizeof(sljit_sw)); + OP2(SLJIT_SUB | SLJIT_SET_Z, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, 1); + JUMPTO(SLJIT_NOT_ZERO, loop); + } + else + { + GET_LOCAL_BASE(TMP2, 0, OVECTOR_START + 2 * sizeof(sljit_sw)); + OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_IMM, length - 2); + loop = LABEL(); + OP1(SLJIT_MOV, SLJIT_MEM1(TMP2), 0, TMP1, 0); + OP2(SLJIT_ADD, TMP2, 0, TMP2, 0, SLJIT_IMM, sizeof(sljit_sw)); + OP2(SLJIT_SUB | SLJIT_SET_Z, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, 1); + JUMPTO(SLJIT_NOT_ZERO, loop); + } } OP1(SLJIT_MOV, STACK_TOP, 0, ARGUMENTS, 0); @@ -2750,10 +2788,10 @@ if (common->control_head_ptr != 0) OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, SLJIT_IMM, 0); OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(STACK_TOP), SLJIT_OFFSETOF(jit_arguments, stack)); OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->start_ptr); -OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(STACK_TOP), SLJIT_OFFSETOF(struct sljit_stack, base)); +OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(STACK_TOP), SLJIT_OFFSETOF(struct sljit_stack, end)); } -static sljit_sw SLJIT_CALL do_search_mark(sljit_sw *current, PCRE2_SPTR skip_arg) +static sljit_sw SLJIT_FUNC do_search_mark(sljit_sw *current, PCRE2_SPTR skip_arg) { while (current != NULL) { @@ -2774,13 +2812,14 @@ while (current != NULL) SLJIT_ASSERT(current[0] == 0 || current < (sljit_sw*)current[0]); current = (sljit_sw*)current[0]; } -return -1; +return 0; } static SLJIT_INLINE void copy_ovector(compiler_common *common, int topbracket) { DEFINE_COMPILER; struct sljit_label *loop; +BOOL has_pre; /* At this point we can freely use all registers. */ OP1(SLJIT_MOV, SLJIT_S2, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(1)); @@ -2797,36 +2836,62 @@ if (common->mark_ptr != 0) OP2(SLJIT_ADD, SLJIT_R2, 0, SLJIT_MEM1(SLJIT_R0), SLJIT_OFFSETOF(jit_arguments, match_data), SLJIT_IMM, SLJIT_OFFSETOF(pcre2_match_data, ovector) - sizeof(PCRE2_SIZE)); -GET_LOCAL_BASE(SLJIT_S0, 0, OVECTOR_START); +has_pre = sljit_emit_mem(compiler, SLJIT_MOV | SLJIT_MEM_SUPP | SLJIT_MEM_PRE, SLJIT_S1, SLJIT_MEM1(SLJIT_S0), sizeof(sljit_sw)) == SLJIT_SUCCESS; + +GET_LOCAL_BASE(SLJIT_S0, 0, OVECTOR_START - (has_pre ? sizeof(sljit_sw) : 0)); OP1(SLJIT_MOV, SLJIT_R0, 0, SLJIT_MEM1(SLJIT_R0), SLJIT_OFFSETOF(jit_arguments, begin)); loop = LABEL(); -OP2(SLJIT_SUB, SLJIT_S1, 0, SLJIT_MEM1(SLJIT_S0), 0, SLJIT_R0, 0); -OP2(SLJIT_ADD, SLJIT_S0, 0, SLJIT_S0, 0, SLJIT_IMM, sizeof(sljit_sw)); + +if (has_pre) + sljit_emit_mem(compiler, SLJIT_MOV | SLJIT_MEM_PRE, SLJIT_S1, SLJIT_MEM1(SLJIT_S0), sizeof(sljit_sw)); +else + { + OP1(SLJIT_MOV, SLJIT_S1, 0, SLJIT_MEM1(SLJIT_S0), 0); + OP2(SLJIT_ADD, SLJIT_S0, 0, SLJIT_S0, 0, SLJIT_IMM, sizeof(sljit_sw)); + } + +OP2(SLJIT_ADD, SLJIT_R2, 0, SLJIT_R2, 0, SLJIT_IMM, sizeof(PCRE2_SIZE)); +OP2(SLJIT_SUB, SLJIT_S1, 0, SLJIT_S1, 0, SLJIT_R0, 0); /* Copy the integer value to the output buffer */ #if PCRE2_CODE_UNIT_WIDTH == 16 || PCRE2_CODE_UNIT_WIDTH == 32 OP2(SLJIT_ASHR, SLJIT_S1, 0, SLJIT_S1, 0, SLJIT_IMM, UCHAR_SHIFT); #endif + SLJIT_ASSERT(sizeof(PCRE2_SIZE) == 4 || sizeof(PCRE2_SIZE) == 8); -if (sizeof(PCRE2_SIZE) == 4) - OP1(SLJIT_MOVU_U32, SLJIT_MEM1(SLJIT_R2), sizeof(PCRE2_SIZE), SLJIT_S1, 0); -else - OP1(SLJIT_MOVU, SLJIT_MEM1(SLJIT_R2), sizeof(PCRE2_SIZE), SLJIT_S1, 0); +OP1(((sizeof(PCRE2_SIZE) == 4) ? SLJIT_MOV_U32 : SLJIT_MOV), SLJIT_MEM1(SLJIT_R2), 0, SLJIT_S1, 0); + OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_R1, 0, SLJIT_R1, 0, SLJIT_IMM, 1); JUMPTO(SLJIT_NOT_ZERO, loop); /* Calculate the return value, which is the maximum ovector value. */ if (topbracket > 1) { - GET_LOCAL_BASE(SLJIT_R0, 0, OVECTOR_START + topbracket * 2 * sizeof(sljit_sw)); - OP1(SLJIT_MOV, SLJIT_R1, 0, SLJIT_IMM, topbracket + 1); + if (sljit_emit_mem(compiler, SLJIT_MOV | SLJIT_MEM_SUPP | SLJIT_MEM_PRE, SLJIT_R2, SLJIT_MEM1(SLJIT_R0), -(2 * (sljit_sw)sizeof(sljit_sw))) == SLJIT_SUCCESS) + { + GET_LOCAL_BASE(SLJIT_R0, 0, OVECTOR_START + topbracket * 2 * sizeof(sljit_sw)); + OP1(SLJIT_MOV, SLJIT_R1, 0, SLJIT_IMM, topbracket + 1); - /* OVECTOR(0) is never equal to SLJIT_S2. */ - loop = LABEL(); - OP1(SLJIT_MOVU, SLJIT_R2, 0, SLJIT_MEM1(SLJIT_R0), -(2 * (sljit_sw)sizeof(sljit_sw))); - OP2(SLJIT_SUB, SLJIT_R1, 0, SLJIT_R1, 0, SLJIT_IMM, 1); - CMPTO(SLJIT_EQUAL, SLJIT_R2, 0, SLJIT_S2, 0, loop); - OP1(SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_R1, 0); + /* OVECTOR(0) is never equal to SLJIT_S2. */ + loop = LABEL(); + sljit_emit_mem(compiler, SLJIT_MOV | SLJIT_MEM_PRE, SLJIT_R2, SLJIT_MEM1(SLJIT_R0), -(2 * (sljit_sw)sizeof(sljit_sw))); + OP2(SLJIT_SUB, SLJIT_R1, 0, SLJIT_R1, 0, SLJIT_IMM, 1); + CMPTO(SLJIT_EQUAL, SLJIT_R2, 0, SLJIT_S2, 0, loop); + OP1(SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_R1, 0); + } + else + { + GET_LOCAL_BASE(SLJIT_R0, 0, OVECTOR_START + (topbracket - 1) * 2 * sizeof(sljit_sw)); + OP1(SLJIT_MOV, SLJIT_R1, 0, SLJIT_IMM, topbracket + 1); + + /* OVECTOR(0) is never equal to SLJIT_S2. */ + loop = LABEL(); + OP1(SLJIT_MOV, SLJIT_R2, 0, SLJIT_MEM1(SLJIT_R0), 0); + OP2(SLJIT_SUB, SLJIT_R0, 0, SLJIT_R0, 0, SLJIT_IMM, 2 * (sljit_sw)sizeof(sljit_sw)); + OP2(SLJIT_SUB, SLJIT_R1, 0, SLJIT_R1, 0, SLJIT_IMM, 1); + CMPTO(SLJIT_EQUAL, SLJIT_R2, 0, SLJIT_S2, 0, loop); + OP1(SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_R1, 0); + } } else OP1(SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_IMM, 1); @@ -2837,7 +2902,7 @@ static SLJIT_INLINE void return_with_partial_match(compiler_common *common, stru DEFINE_COMPILER; sljit_s32 mov_opcode; -SLJIT_COMPILE_ASSERT(STR_END == SLJIT_S1, str_end_must_be_saved_reg2); +SLJIT_COMPILE_ASSERT(STR_END == SLJIT_S0, str_end_must_be_saved_reg0); SLJIT_ASSERT(common->start_used_ptr != 0 && common->start_ptr != 0 && (common->mode == PCRE2_JIT_PARTIAL_SOFT ? common->hit_start != 0 : common->hit_start == 0)); @@ -2847,19 +2912,19 @@ OP1(SLJIT_MOV, SLJIT_R2, 0, SLJIT_MEM1(SLJIT_SP), OP1(SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_IMM, PCRE2_ERROR_PARTIAL); /* Store match begin and end. */ -OP1(SLJIT_MOV, SLJIT_S0, 0, SLJIT_MEM1(SLJIT_R1), SLJIT_OFFSETOF(jit_arguments, begin)); +OP1(SLJIT_MOV, SLJIT_S1, 0, SLJIT_MEM1(SLJIT_R1), SLJIT_OFFSETOF(jit_arguments, begin)); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_R1), SLJIT_OFFSETOF(jit_arguments, startchar_ptr), SLJIT_R2, 0); OP1(SLJIT_MOV, SLJIT_R1, 0, SLJIT_MEM1(SLJIT_R1), SLJIT_OFFSETOF(jit_arguments, match_data)); mov_opcode = (sizeof(PCRE2_SIZE) == 4) ? SLJIT_MOV_U32 : SLJIT_MOV; -OP2(SLJIT_SUB, SLJIT_R2, 0, SLJIT_R2, 0, SLJIT_S0, 0); +OP2(SLJIT_SUB, SLJIT_R2, 0, SLJIT_R2, 0, SLJIT_S1, 0); #if PCRE2_CODE_UNIT_WIDTH == 16 || PCRE2_CODE_UNIT_WIDTH == 32 OP2(SLJIT_ASHR, SLJIT_R2, 0, SLJIT_R2, 0, SLJIT_IMM, UCHAR_SHIFT); #endif OP1(mov_opcode, SLJIT_MEM1(SLJIT_R1), SLJIT_OFFSETOF(pcre2_match_data, ovector), SLJIT_R2, 0); -OP2(SLJIT_SUB, STR_END, 0, STR_END, 0, SLJIT_S0, 0); +OP2(SLJIT_SUB, STR_END, 0, STR_END, 0, SLJIT_S1, 0); #if PCRE2_CODE_UNIT_WIDTH == 16 || PCRE2_CODE_UNIT_WIDTH == 32 OP2(SLJIT_ASHR, STR_END, 0, STR_END, 0, SLJIT_IMM, UCHAR_SHIFT); #endif @@ -4351,7 +4416,6 @@ struct sljit_jump *quit; struct sljit_jump *partial_quit[2]; sljit_u8 instruction[8]; sljit_s32 tmp1_ind = sljit_get_register_index(TMP1); -// sljit_s32 tmp2_ind = sljit_get_register_index(TMP2); sljit_s32 str_ptr_ind = sljit_get_register_index(STR_PTR); sljit_s32 data_ind = 0; sljit_s32 tmp_ind = 1; @@ -4376,8 +4440,6 @@ if (common->mode == PCRE2_JIT_COMPLETE) OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, character_to_int32(char1 | bit)); -// SLJIT_ASSERT(tmp1_ind < 8 && tmp2_ind == 1); - SLJIT_ASSERT(tmp1_ind < 8); /* MOVD xmm, r/m32 */ @@ -5976,93 +6038,190 @@ OP_FLAGS(SLJIT_OR | SLJIT_SET_Z, TMP2, 0, SLJIT_EQUAL); sljit_emit_fast_return(compiler, RETURN_ADDR, 0); } -#define CHAR1 STR_END -#define CHAR2 STACK_TOP - static void do_casefulcmp(compiler_common *common) { DEFINE_COMPILER; struct sljit_jump *jump; struct sljit_label *label; +int char1_reg; +int char2_reg; -sljit_emit_fast_enter(compiler, RETURN_ADDR, 0); +if (sljit_get_register_index(TMP3) < 0) + { + char1_reg = STR_END; + char2_reg = STACK_TOP; + } +else + { + char1_reg = TMP3; + char2_reg = RETURN_ADDR; + } + +sljit_emit_fast_enter(compiler, SLJIT_MEM1(SLJIT_SP), LOCALS0); OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, TMP2, 0); -OP1(SLJIT_MOV, TMP3, 0, CHAR1, 0); -OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LOCALS0, CHAR2, 0); -OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, IN_UCHARS(1)); -OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); -label = LABEL(); -OP1(MOVU_UCHAR, CHAR1, 0, SLJIT_MEM1(TMP1), IN_UCHARS(1)); -OP1(MOVU_UCHAR, CHAR2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(1)); -jump = CMP(SLJIT_NOT_EQUAL, CHAR1, 0, CHAR2, 0); -OP2(SLJIT_SUB | SLJIT_SET_Z, TMP2, 0, TMP2, 0, SLJIT_IMM, IN_UCHARS(1)); -JUMPTO(SLJIT_NOT_ZERO, label); +if (char1_reg == STR_END) + { + OP1(SLJIT_MOV, TMP3, 0, char1_reg, 0); + OP1(SLJIT_MOV, RETURN_ADDR, 0, char2_reg, 0); + } -JUMPHERE(jump); -OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); -OP1(SLJIT_MOV, CHAR1, 0, TMP3, 0); -OP1(SLJIT_MOV, CHAR2, 0, SLJIT_MEM1(SLJIT_SP), LOCALS0); -sljit_emit_fast_return(compiler, RETURN_ADDR, 0); -} +if (sljit_emit_mem(compiler, MOV_UCHAR | SLJIT_MEM_SUPP | SLJIT_MEM_POST, char1_reg, SLJIT_MEM1(TMP1), IN_UCHARS(1)) == SLJIT_SUCCESS) + { + label = LABEL(); + sljit_emit_mem(compiler, MOV_UCHAR | SLJIT_MEM_POST, char1_reg, SLJIT_MEM1(TMP1), IN_UCHARS(1)); + sljit_emit_mem(compiler, MOV_UCHAR | SLJIT_MEM_POST, char2_reg, SLJIT_MEM1(STR_PTR), IN_UCHARS(1)); + jump = CMP(SLJIT_NOT_EQUAL, char1_reg, 0, char2_reg, 0); + OP2(SLJIT_SUB | SLJIT_SET_Z, TMP2, 0, TMP2, 0, SLJIT_IMM, IN_UCHARS(1)); + JUMPTO(SLJIT_NOT_ZERO, label); + + JUMPHERE(jump); + OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), LOCALS0); + } +else if (sljit_emit_mem(compiler, MOV_UCHAR | SLJIT_MEM_SUPP | SLJIT_MEM_PRE, char1_reg, SLJIT_MEM1(TMP1), IN_UCHARS(1)) == SLJIT_SUCCESS) + { + OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, IN_UCHARS(1)); + OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); + + label = LABEL(); + sljit_emit_mem(compiler, MOV_UCHAR | SLJIT_MEM_PRE, char1_reg, SLJIT_MEM1(TMP1), IN_UCHARS(1)); + sljit_emit_mem(compiler, MOV_UCHAR | SLJIT_MEM_PRE, char2_reg, SLJIT_MEM1(STR_PTR), IN_UCHARS(1)); + jump = CMP(SLJIT_NOT_EQUAL, char1_reg, 0, char2_reg, 0); + OP2(SLJIT_SUB | SLJIT_SET_Z, TMP2, 0, TMP2, 0, SLJIT_IMM, IN_UCHARS(1)); + JUMPTO(SLJIT_NOT_ZERO, label); + + JUMPHERE(jump); + OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), LOCALS0); + OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); + } +else + { + label = LABEL(); + OP1(MOV_UCHAR, char1_reg, 0, SLJIT_MEM1(TMP1), 0); + OP1(MOV_UCHAR, char2_reg, 0, SLJIT_MEM1(STR_PTR), 0); + OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, IN_UCHARS(1)); + OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); + jump = CMP(SLJIT_NOT_EQUAL, char1_reg, 0, char2_reg, 0); + OP2(SLJIT_SUB | SLJIT_SET_Z, TMP2, 0, TMP2, 0, SLJIT_IMM, IN_UCHARS(1)); + JUMPTO(SLJIT_NOT_ZERO, label); -#define LCC_TABLE STACK_LIMIT + JUMPHERE(jump); + OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), LOCALS0); + } + +if (char1_reg == STR_END) + { + OP1(SLJIT_MOV, char1_reg, 0, TMP3, 0); + OP1(SLJIT_MOV, char2_reg, 0, RETURN_ADDR, 0); + } + +sljit_emit_fast_return(compiler, TMP1, 0); +} static void do_caselesscmp(compiler_common *common) { DEFINE_COMPILER; struct sljit_jump *jump; struct sljit_label *label; +int char1_reg = STR_END; +int char2_reg; +int lcc_table; +int opt_type = 0; -sljit_emit_fast_enter(compiler, RETURN_ADDR, 0); +if (sljit_get_register_index(TMP3) < 0) + { + char2_reg = STACK_TOP; + lcc_table = STACK_LIMIT; + } +else + { + char2_reg = RETURN_ADDR; + lcc_table = TMP3; + } + +if (sljit_emit_mem(compiler, MOV_UCHAR | SLJIT_MEM_SUPP | SLJIT_MEM_POST, char1_reg, SLJIT_MEM1(TMP1), IN_UCHARS(1)) == SLJIT_SUCCESS) + opt_type = 1; +else if (sljit_emit_mem(compiler, MOV_UCHAR | SLJIT_MEM_SUPP | SLJIT_MEM_PRE, char1_reg, SLJIT_MEM1(TMP1), IN_UCHARS(1)) == SLJIT_SUCCESS) + opt_type = 2; + +sljit_emit_fast_enter(compiler, SLJIT_MEM1(SLJIT_SP), LOCALS0); OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, TMP2, 0); -OP1(SLJIT_MOV, TMP3, 0, LCC_TABLE, 0); -OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LOCALS0, CHAR1, 0); -OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LOCALS1, CHAR2, 0); -OP1(SLJIT_MOV, LCC_TABLE, 0, SLJIT_IMM, common->lcc); -OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, IN_UCHARS(1)); -OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); +OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LOCALS1, char1_reg, 0); + +if (char2_reg == STACK_TOP) + { + OP1(SLJIT_MOV, TMP3, 0, char2_reg, 0); + OP1(SLJIT_MOV, RETURN_ADDR, 0, lcc_table, 0); + } + +OP1(SLJIT_MOV, lcc_table, 0, SLJIT_IMM, common->lcc); + +if (opt_type == 1) + { + label = LABEL(); + sljit_emit_mem(compiler, MOV_UCHAR | SLJIT_MEM_POST, char1_reg, SLJIT_MEM1(TMP1), IN_UCHARS(1)); + sljit_emit_mem(compiler, MOV_UCHAR | SLJIT_MEM_POST, char2_reg, SLJIT_MEM1(STR_PTR), IN_UCHARS(1)); + } +else if (opt_type == 2) + { + OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, IN_UCHARS(1)); + OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); + + label = LABEL(); + sljit_emit_mem(compiler, MOV_UCHAR | SLJIT_MEM_PRE, char1_reg, SLJIT_MEM1(TMP1), IN_UCHARS(1)); + sljit_emit_mem(compiler, MOV_UCHAR | SLJIT_MEM_PRE, char2_reg, SLJIT_MEM1(STR_PTR), IN_UCHARS(1)); + } +else + { + label = LABEL(); + OP1(MOV_UCHAR, char1_reg, 0, SLJIT_MEM1(TMP1), 0); + OP1(MOV_UCHAR, char2_reg, 0, SLJIT_MEM1(STR_PTR), 0); + OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, IN_UCHARS(1)); + } -label = LABEL(); -OP1(MOVU_UCHAR, CHAR1, 0, SLJIT_MEM1(TMP1), IN_UCHARS(1)); -OP1(MOVU_UCHAR, CHAR2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(1)); #if PCRE2_CODE_UNIT_WIDTH != 8 -jump = CMP(SLJIT_GREATER, CHAR1, 0, SLJIT_IMM, 255); +jump = CMP(SLJIT_GREATER, char1_reg, 0, SLJIT_IMM, 255); #endif -OP1(SLJIT_MOV_U8, CHAR1, 0, SLJIT_MEM2(LCC_TABLE, CHAR1), 0); +OP1(SLJIT_MOV_U8, char1_reg, 0, SLJIT_MEM2(lcc_table, char1_reg), 0); #if PCRE2_CODE_UNIT_WIDTH != 8 JUMPHERE(jump); -jump = CMP(SLJIT_GREATER, CHAR2, 0, SLJIT_IMM, 255); +jump = CMP(SLJIT_GREATER, char2_reg, 0, SLJIT_IMM, 255); #endif -OP1(SLJIT_MOV_U8, CHAR2, 0, SLJIT_MEM2(LCC_TABLE, CHAR2), 0); +OP1(SLJIT_MOV_U8, char2_reg, 0, SLJIT_MEM2(lcc_table, char2_reg), 0); #if PCRE2_CODE_UNIT_WIDTH != 8 JUMPHERE(jump); #endif -jump = CMP(SLJIT_NOT_EQUAL, CHAR1, 0, CHAR2, 0); + +if (opt_type == 0) + OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); + +jump = CMP(SLJIT_NOT_EQUAL, char1_reg, 0, char2_reg, 0); OP2(SLJIT_SUB | SLJIT_SET_Z, TMP2, 0, TMP2, 0, SLJIT_IMM, IN_UCHARS(1)); JUMPTO(SLJIT_NOT_ZERO, label); JUMPHERE(jump); -OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); -OP1(SLJIT_MOV, LCC_TABLE, 0, TMP3, 0); -OP1(SLJIT_MOV, CHAR1, 0, SLJIT_MEM1(SLJIT_SP), LOCALS0); -OP1(SLJIT_MOV, CHAR2, 0, SLJIT_MEM1(SLJIT_SP), LOCALS1); -sljit_emit_fast_return(compiler, RETURN_ADDR, 0); -} +OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), LOCALS0); -#undef LCC_TABLE -#undef CHAR1 -#undef CHAR2 +if (opt_type == 2) + OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); + +if (char2_reg == STACK_TOP) + { + OP1(SLJIT_MOV, char2_reg, 0, TMP3, 0); + OP1(SLJIT_MOV, lcc_table, 0, RETURN_ADDR, 0); + } + +OP1(SLJIT_MOV, char1_reg, 0, SLJIT_MEM1(SLJIT_SP), LOCALS1); +sljit_emit_fast_return(compiler, TMP1, 0); +} #if defined SUPPORT_UNICODE -static PCRE2_SPTR SLJIT_CALL do_utf_caselesscmp(PCRE2_SPTR src1, jit_arguments *args, PCRE2_SPTR end1) +static PCRE2_SPTR SLJIT_FUNC do_utf_caselesscmp(PCRE2_SPTR src1, PCRE2_SPTR src2, PCRE2_SPTR end1, PCRE2_SPTR end2) { /* This function would be ineffective to do in JIT level. */ sljit_u32 c1, c2; -PCRE2_SPTR src2 = args->startchar_ptr; -PCRE2_SPTR end2 = args->end; const ucd_record *ur; const sljit_u32 *pp; @@ -7048,6 +7207,122 @@ SLJIT_UNREACHABLE(); return cc; } +#ifdef SUPPORT_UNICODE + +#if PCRE2_CODE_UNIT_WIDTH != 32 + +static PCRE2_SPTR SLJIT_FUNC do_extuni_utf(jit_arguments *args, PCRE2_SPTR cc) +{ +PCRE2_SPTR start_subject = args->begin; +PCRE2_SPTR end_subject = args->end; +int lgb, rgb, len, ricount; +PCRE2_SPTR prevcc, bptr; +uint32_t c; + +prevcc = cc; +GETCHARINC(c, cc); +lgb = UCD_GRAPHBREAK(c); + +while (cc < end_subject) + { + len = 1; + GETCHARLEN(c, cc, len); + rgb = UCD_GRAPHBREAK(c); + + if ((PRIV(ucp_gbtable)[lgb] & (1 << rgb)) == 0) break; + + /* Not breaking between Regional Indicators is allowed only if there + are an even number of preceding RIs. */ + + if (lgb == ucp_gbRegionalIndicator && rgb == ucp_gbRegionalIndicator) + { + ricount = 0; + bptr = prevcc; + + /* bptr is pointing to the left-hand character */ + while (bptr > start_subject) + { + bptr--; + BACKCHAR(bptr); + GETCHAR(c, bptr); + + if (UCD_GRAPHBREAK(c) != ucp_gbRegionalIndicator) break; + + ricount++; + } + + if ((ricount & 1) != 0) break; /* Grapheme break required */ + } + + /* If Extend follows E_Base[_GAZ] do not update lgb; this allows + any number of Extend before a following E_Modifier. */ + + if (rgb != ucp_gbExtend || (lgb != ucp_gbE_Base && lgb != ucp_gbE_Base_GAZ)) + lgb = rgb; + + prevcc = cc; + cc += len; + } + +return cc; +} + +#endif + +static PCRE2_SPTR SLJIT_FUNC do_extuni_no_utf(jit_arguments *args, PCRE2_SPTR cc) +{ +PCRE2_SPTR start_subject = args->begin; +PCRE2_SPTR end_subject = args->end; +int lgb, rgb, ricount; +PCRE2_SPTR bptr; +uint32_t c; + +GETCHARINC(c, cc); +lgb = UCD_GRAPHBREAK(c); + +while (cc < end_subject) + { + c = *cc; + rgb = UCD_GRAPHBREAK(c); + + if ((PRIV(ucp_gbtable)[lgb] & (1 << rgb)) == 0) break; + + /* Not breaking between Regional Indicators is allowed only if there + are an even number of preceding RIs. */ + + if (lgb == ucp_gbRegionalIndicator && rgb == ucp_gbRegionalIndicator) + { + ricount = 0; + bptr = cc - 1; + + /* bptr is pointing to the left-hand character */ + while (bptr > start_subject) + { + bptr--; + c = *bptr; + + if (UCD_GRAPHBREAK(c) != ucp_gbRegionalIndicator) break; + + ricount++; + } + + if ((ricount & 1) != 0) break; /* Grapheme break required */ + } + + /* If Extend follows E_Base[_GAZ] do not update lgb; this allows + any number of Extend before a following E_Modifier. */ + + if (rgb != ucp_gbExtend || (lgb != ucp_gbE_Base && lgb != ucp_gbE_Base_GAZ)) + lgb = rgb; + + cc++; + } + +return cc; +} + +#endif + static PCRE2_SPTR compile_char1_matchingpath(compiler_common *common, PCRE2_UCHAR type, PCRE2_SPTR cc, jump_list **backtracks, BOOL check_str_ptr) { DEFINE_COMPILER; @@ -7057,7 +7332,6 @@ compare_context context; struct sljit_jump *jump[3]; jump_list *end_list; #ifdef SUPPORT_UNICODE -struct sljit_label *label; PCRE2_UCHAR propdata[5]; #endif /* SUPPORT_UNICODE */ @@ -7224,35 +7498,22 @@ switch(type) case OP_EXTUNI: if (check_str_ptr) detect_partial_match(common, backtracks); - read_char(common); - add_jump(compiler, &common->getucd, JUMP(SLJIT_FAST_CALL)); - OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, (sljit_sw)PRIV(ucd_records) + SLJIT_OFFSETOF(ucd_record, gbprop)); - /* Optimize register allocation: use a real register. */ - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LOCALS0, STACK_TOP, 0); - OP1(SLJIT_MOV_U8, STACK_TOP, 0, SLJIT_MEM2(TMP1, TMP2), 3); - label = LABEL(); - jump[0] = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0); - OP1(SLJIT_MOV, TMP3, 0, STR_PTR, 0); - read_char(common); - add_jump(compiler, &common->getucd, JUMP(SLJIT_FAST_CALL)); - OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, (sljit_sw)PRIV(ucd_records) + SLJIT_OFFSETOF(ucd_record, gbprop)); - OP1(SLJIT_MOV_U8, TMP2, 0, SLJIT_MEM2(TMP1, TMP2), 3); + SLJIT_ASSERT(TMP1 == SLJIT_R0 && STR_PTR == SLJIT_R1); + OP1(SLJIT_MOV, SLJIT_R0, 0, ARGUMENTS, 0); - OP2(SLJIT_SHL, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, 2); - OP1(SLJIT_MOV_U32, TMP1, 0, SLJIT_MEM1(STACK_TOP), (sljit_sw)PRIV(ucp_gbtable)); - OP1(SLJIT_MOV, STACK_TOP, 0, TMP2, 0); - OP2(SLJIT_SHL, TMP2, 0, SLJIT_IMM, 1, TMP2, 0); - OP2(SLJIT_AND | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, TMP2, 0); - JUMPTO(SLJIT_NOT_ZERO, label); +#if PCRE2_CODE_UNIT_WIDTH != 32 + sljit_emit_icall(compiler, SLJIT_CALL, SLJIT_RET(SW) | SLJIT_ARG1(SW) | SLJIT_ARG2(SW), SLJIT_IMM, + common->utf ? SLJIT_FUNC_OFFSET(do_extuni_utf) : SLJIT_FUNC_OFFSET(do_extuni_no_utf)); +#else + sljit_emit_icall(compiler, SLJIT_CALL, SLJIT_RET(SW) | SLJIT_ARG1(SW) | SLJIT_ARG2(SW), SLJIT_IMM, SLJIT_FUNC_OFFSET(do_extuni_no_utf)); +#endif - OP1(SLJIT_MOV, STR_PTR, 0, TMP3, 0); - JUMPHERE(jump[0]); - OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), LOCALS0); + OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_RETURN_REG, 0); if (common->mode == PCRE2_JIT_PARTIAL_HARD) { - jump[0] = CMP(SLJIT_LESS, STR_PTR, 0, STR_END, 0); + jump[0] = CMP(SLJIT_LESS, SLJIT_RETURN_REG, 0, STR_END, 0); /* Since we successfully read a char above, partial matching must occure. */ check_partial(common, TRUE); JUMPHERE(jump[0]); @@ -7585,32 +7846,34 @@ else #if defined SUPPORT_UNICODE if (common->utf && *cc == OP_REFI) { - SLJIT_ASSERT(TMP1 == SLJIT_R0 && STACK_TOP == SLJIT_R1 && TMP2 == SLJIT_R2); + SLJIT_ASSERT(TMP1 == SLJIT_R0 && STR_PTR == SLJIT_R1); if (ref) - OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset + 1)); + OP1(SLJIT_MOV, SLJIT_R2, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset + 1)); else - OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(TMP2), sizeof(sljit_sw)); + OP1(SLJIT_MOV, SLJIT_R2, 0, SLJIT_MEM1(TMP2), sizeof(sljit_sw)); if (withchecks) - jump = CMP(SLJIT_EQUAL, TMP1, 0, TMP2, 0); - - /* Needed to save important temporary registers. */ - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LOCALS0, STACK_TOP, 0); - OP1(SLJIT_MOV, SLJIT_R1, 0, ARGUMENTS, 0); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_R1), SLJIT_OFFSETOF(jit_arguments, startchar_ptr), STR_PTR, 0); - sljit_emit_ijump(compiler, SLJIT_CALL3, SLJIT_IMM, SLJIT_FUNC_OFFSET(do_utf_caselesscmp)); - OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), LOCALS0); + jump = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_R2, 0); + /* No free saved registers so save data on stack. */ + + OP1(SLJIT_MOV, SLJIT_R3, 0, STR_END, 0); + sljit_emit_icall(compiler, SLJIT_CALL, SLJIT_RET(SW) | SLJIT_ARG1(SW) | SLJIT_ARG2(SW) | SLJIT_ARG3(SW) | SLJIT_ARG4(SW), SLJIT_IMM, SLJIT_FUNC_OFFSET(do_utf_caselesscmp)); + OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_RETURN_REG, 0); + if (common->mode == PCRE2_JIT_COMPLETE) add_jump(compiler, backtracks, CMP(SLJIT_LESS_EQUAL, SLJIT_RETURN_REG, 0, SLJIT_IMM, 1)); else { - add_jump(compiler, backtracks, CMP(SLJIT_EQUAL, SLJIT_RETURN_REG, 0, SLJIT_IMM, 0)); - nopartial = CMP(SLJIT_NOT_EQUAL, SLJIT_RETURN_REG, 0, SLJIT_IMM, 1); + OP2(SLJIT_SUB | SLJIT_SET_Z | SLJIT_SET_LESS, SLJIT_UNUSED, 0, SLJIT_RETURN_REG, 0, SLJIT_IMM, 1); + + add_jump(compiler, backtracks, JUMP(SLJIT_LESS)); + + nopartial = JUMP(SLJIT_NOT_EQUAL); + OP1(SLJIT_MOV, STR_PTR, 0, STR_END, 0); check_partial(common, FALSE); add_jump(compiler, backtracks, JUMP(SLJIT_JUMP)); JUMPHERE(nopartial); } - OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_RETURN_REG, 0); } else #endif /* SUPPORT_UNICODE */ @@ -7924,7 +8187,7 @@ BACKTRACK_AS(recurse_backtrack)->matchingpath = LABEL(); return cc + 1 + LINK_SIZE; } -static int SLJIT_CALL do_callout(struct jit_arguments *arguments, pcre2_callout_block *callout_block, PCRE2_SPTR *jit_ovector) +static sljit_s32 SLJIT_FUNC do_callout(struct jit_arguments *arguments, pcre2_callout_block *callout_block, PCRE2_SPTR *jit_ovector) { PCRE2_SPTR begin; PCRE2_SIZE *ovector; @@ -7941,7 +8204,8 @@ oveccount = callout_block->capture_top; SLJIT_ASSERT(oveccount >= 1); -callout_block->version = 1; +callout_block->version = 2; +callout_block->callout_flags = 0; /* Offsets in subject. */ callout_block->subject_length = arguments->end - arguments->begin; @@ -8033,23 +8297,24 @@ OP1(mov_opcode, SLJIT_MEM1(STACK_TOP), CALLOUT_ARG_OFFSET(callout_string_length) OP1(mov_opcode, SLJIT_MEM1(STACK_TOP), CALLOUT_ARG_OFFSET(callout_string_offset), SLJIT_IMM, value3); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), CALLOUT_ARG_OFFSET(mark), (common->mark_ptr != 0) ? TMP2 : SLJIT_IMM, 0); +SLJIT_ASSERT(TMP1 == SLJIT_R0 && STR_PTR == SLJIT_R1); + /* Needed to save important temporary registers. */ -OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LOCALS0, STACK_TOP, 0); +OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LOCALS0, STR_PTR, 0); /* SLJIT_R0 = arguments */ OP1(SLJIT_MOV, SLJIT_R1, 0, STACK_TOP, 0); GET_LOCAL_BASE(SLJIT_R2, 0, OVECTOR_START); -sljit_emit_ijump(compiler, SLJIT_CALL3, SLJIT_IMM, SLJIT_FUNC_OFFSET(do_callout)); -OP1(SLJIT_MOV_S32, SLJIT_RETURN_REG, 0, SLJIT_RETURN_REG, 0); -OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), LOCALS0); +sljit_emit_icall(compiler, SLJIT_CALL, SLJIT_RET(S32) | SLJIT_ARG1(SW) | SLJIT_ARG2(SW) | SLJIT_ARG3(SW), SLJIT_IMM, SLJIT_FUNC_OFFSET(do_callout)); +OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(SLJIT_SP), LOCALS0); free_stack(common, callout_arg_size); /* Check return value. */ -OP2(SLJIT_SUB | SLJIT_SET_Z | SLJIT_SET_SIG_GREATER, SLJIT_UNUSED, 0, SLJIT_RETURN_REG, 0, SLJIT_IMM, 0); -add_jump(compiler, &backtrack->topbacktracks, JUMP(SLJIT_SIG_GREATER)); +OP2(SLJIT_SUB32 | SLJIT_SET_Z | SLJIT_SET_SIG_GREATER, SLJIT_UNUSED, 0, SLJIT_RETURN_REG, 0, SLJIT_IMM, 0); +add_jump(compiler, &backtrack->topbacktracks, JUMP(SLJIT_SIG_GREATER32)); if (common->abort_label == NULL) - add_jump(compiler, &common->abort, JUMP(SLJIT_NOT_EQUAL) /* SIG_LESS */); + add_jump(compiler, &common->abort, JUMP(SLJIT_NOT_EQUAL32) /* SIG_LESS */); else - JUMPTO(SLJIT_NOT_EQUAL /* SIG_LESS */, common->abort_label); + JUMPTO(SLJIT_NOT_EQUAL32 /* SIG_LESS */, common->abort_label); return cc + callout_length; } @@ -11279,15 +11544,13 @@ if (common->local_quit_available) if (opcode == OP_SKIP_ARG) { - SLJIT_ASSERT(common->control_head_ptr != 0); + SLJIT_ASSERT(common->control_head_ptr != 0 && TMP1 == SLJIT_R0 && STR_PTR == SLJIT_R1); OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LOCALS0, STACK_TOP, 0); - OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_IMM, (sljit_sw)(current->cc + 2)); - sljit_emit_ijump(compiler, SLJIT_CALL2, SLJIT_IMM, SLJIT_FUNC_OFFSET(do_search_mark)); - OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), LOCALS0); + OP1(SLJIT_MOV, SLJIT_R1, 0, SLJIT_IMM, (sljit_sw)(current->cc + 2)); + sljit_emit_icall(compiler, SLJIT_CALL, SLJIT_RET(SW) | SLJIT_ARG1(SW) | SLJIT_ARG2(SW), SLJIT_IMM, SLJIT_FUNC_OFFSET(do_search_mark)); - OP1(SLJIT_MOV, STR_PTR, 0, TMP1, 0); - add_jump(compiler, &common->reset_match, CMP(SLJIT_NOT_EQUAL, STR_PTR, 0, SLJIT_IMM, -1)); + OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_R0, 0); + add_jump(compiler, &common->reset_match, CMP(SLJIT_NOT_EQUAL, SLJIT_R0, 0, SLJIT_IMM, 0)); return; } @@ -11957,7 +12220,7 @@ if (!compiler) common->compiler = compiler; /* Main pcre_jit_exec entry. */ -sljit_emit_enter(compiler, 0, 1, 5, 5, 0, 0, private_data_size); +sljit_emit_enter(compiler, 0, SLJIT_ARG1(SW), 5, 5, 0, 0, private_data_size); /* Register init. */ reset_ovector(common, (re->top_bracket + 1) * 2); @@ -11970,8 +12233,8 @@ OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, str)) OP1(SLJIT_MOV, STR_END, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, end)); OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, stack)); OP1(SLJIT_MOV_U32, TMP1, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, limit_match)); -OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(TMP2), SLJIT_OFFSETOF(struct sljit_stack, base)); -OP1(SLJIT_MOV, STACK_LIMIT, 0, SLJIT_MEM1(TMP2), SLJIT_OFFSETOF(struct sljit_stack, limit)); +OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(TMP2), SLJIT_OFFSETOF(struct sljit_stack, end)); +OP1(SLJIT_MOV, STACK_LIMIT, 0, SLJIT_MEM1(TMP2), SLJIT_OFFSETOF(struct sljit_stack, start)); OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, 1); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LIMIT_MATCH, TMP1, 0); @@ -12200,20 +12463,23 @@ common->quit_label = quit_label; set_jumps(common->stackalloc, LABEL()); /* RETURN_ADDR is not a saved register. */ sljit_emit_fast_enter(compiler, SLJIT_MEM1(SLJIT_SP), LOCALS0); -OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LOCALS1, TMP2, 0); -OP1(SLJIT_MOV, TMP1, 0, ARGUMENTS, 0); -OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, stack)); -OP1(SLJIT_MOV, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(struct sljit_stack, top), STACK_TOP, 0); -OP2(SLJIT_SUB, TMP2, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(struct sljit_stack, limit), SLJIT_IMM, STACK_GROWTH_RATE); -sljit_emit_ijump(compiler, SLJIT_CALL2, SLJIT_IMM, SLJIT_FUNC_OFFSET(sljit_stack_resize)); -jump = CMP(SLJIT_NOT_EQUAL, SLJIT_RETURN_REG, 0, SLJIT_IMM, 0); -OP1(SLJIT_MOV, TMP1, 0, ARGUMENTS, 0); -OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, stack)); -OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(struct sljit_stack, top)); -OP1(SLJIT_MOV, STACK_LIMIT, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(struct sljit_stack, limit)); -OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), LOCALS1); -sljit_emit_fast_return(compiler, SLJIT_MEM1(SLJIT_SP), LOCALS0); +SLJIT_ASSERT(TMP1 == SLJIT_R0 && STR_PTR == SLJIT_R1); + +OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LOCALS1, STR_PTR, 0); +OP1(SLJIT_MOV, SLJIT_R0, 0, ARGUMENTS, 0); +OP2(SLJIT_SUB, SLJIT_R1, 0, STACK_LIMIT, 0, SLJIT_IMM, STACK_GROWTH_RATE); +OP1(SLJIT_MOV, SLJIT_R0, 0, SLJIT_MEM1(SLJIT_R0), SLJIT_OFFSETOF(jit_arguments, stack)); +OP1(SLJIT_MOV, STACK_LIMIT, 0, TMP2, 0); + +sljit_emit_icall(compiler, SLJIT_CALL, SLJIT_RET(SW) | SLJIT_ARG1(SW) | SLJIT_ARG2(SW), SLJIT_IMM, SLJIT_FUNC_OFFSET(sljit_stack_resize)); + +jump = CMP(SLJIT_EQUAL, SLJIT_RETURN_REG, 0, SLJIT_IMM, 0); +OP1(SLJIT_MOV, TMP2, 0, STACK_LIMIT, 0); +OP1(SLJIT_MOV, STACK_LIMIT, 0, SLJIT_RETURN_REG, 0); +OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), LOCALS0); +OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(SLJIT_SP), LOCALS1); +sljit_emit_fast_return(compiler, TMP1, 0); /* Allocation failed. */ JUMPHERE(jump); diff --git a/ProcessHacker/pcre/pcre2_jit_match.c b/ProcessHacker/pcre/pcre2_jit_match.c index 4cad754c759e..5a66545bae34 100644 --- a/ProcessHacker/pcre/pcre2_jit_match.c +++ b/ProcessHacker/pcre/pcre2_jit_match.c @@ -49,9 +49,9 @@ static SLJIT_NOINLINE int jit_machine_stack_exec(jit_arguments *arguments, jit_f sljit_u8 local_space[MACHINE_STACK_SIZE]; struct sljit_stack local_stack; -local_stack.max_limit = local_space; -local_stack.limit = local_space; -local_stack.base = local_space + MACHINE_STACK_SIZE; +local_stack.min_start = local_space; +local_stack.start = local_space; +local_stack.end = local_space + MACHINE_STACK_SIZE; local_stack.top = local_space + MACHINE_STACK_SIZE; arguments->stack = &local_stack; return executable_func(arguments); @@ -118,7 +118,7 @@ if ((options & PCRE2_PARTIAL_HARD) != 0) else if ((options & PCRE2_PARTIAL_SOFT) != 0) index = 1; -if (functions->executable_funcs[index] == NULL) +if (functions == NULL || functions->executable_funcs[index] == NULL) return PCRE2_ERROR_JIT_BADOPTION; /* Sanity checks should be handled by pcre_exec. */ diff --git a/ProcessHacker/pcre/pcre2_jit_test.c b/ProcessHacker/pcre/pcre2_jit_test.c index 96280b71680f..d9916b7ca065 100644 --- a/ProcessHacker/pcre/pcre2_jit_test.c +++ b/ProcessHacker/pcre/pcre2_jit_test.c @@ -179,10 +179,12 @@ static struct regression_test_case regression_test_cases[] = { { PCRE2_CASELESS, 0, 0, 0, "\xff#a", "\xff#\xff\xfe##\xff#A" }, { PCRE2_CASELESS, 0, 0, 0, "\xfe", "\xff\xfc#\xfe\xfe" }, { PCRE2_CASELESS, 0, 0, 0, "a1", "Aa1" }, +#ifndef NEVER_BACKSLASH_C { M, A, 0, 0, "\\Ca", "cda" }, { CM, A, 0, 0, "\\Ca", "CDA" }, { M, A, 0, 0 | F_NOMATCH, "\\Cx", "cda" }, { CM, A, 0, 0 | F_NOMATCH, "\\Cx", "CDA" }, +#endif { CMUP, A, 0, 0, "\xf0\x90\x90\x80\xf0\x90\x90\xa8", "\xf0\x90\x90\xa8\xf0\x90\x90\x80" }, { CMUP, A, 0, 0, "\xf0\x90\x90\x80{2}", "\xf0\x90\x90\x80#\xf0\x90\x90\xa8\xf0\x90\x90\x80" }, { CMUP, A, 0, 0, "\xf0\x90\x90\xa8{2}", "\xf0\x90\x90\x80#\xf0\x90\x90\xa8\xf0\x90\x90\x80" }, diff --git a/ProcessHacker/pcre/pcre2_match.c b/ProcessHacker/pcre/pcre2_match.c index 689169e837d1..79cc93f91800 100644 --- a/ProcessHacker/pcre/pcre2_match.c +++ b/ProcessHacker/pcre/pcre2_match.c @@ -7,7 +7,7 @@ and semantics are as close as possible to those of the Perl 5 language. Written by Philip Hazel Original API code Copyright (c) 1997-2012 University of Cambridge - New API code Copyright (c) 2015-2017 University of Cambridge + New API code Copyright (c) 2015-2018 University of Cambridge ----------------------------------------------------------------------------- Redistribution and use in source and binary forms, with or without @@ -38,9 +38,6 @@ POSSIBILITY OF SUCH DAMAGE. ----------------------------------------------------------------------------- */ -// dmex: Disable warnings. -#pragma warning(push) -#pragma warning(disable : 4244) #ifdef HAVE_CONFIG_H #include "config.h" @@ -252,7 +249,8 @@ for (i = 0, Q = mb->match_frames; /* This function is called for all callouts, whether "standalone" or at the start of a conditional group. Feptr will be pointing to either OP_CALLOUT or -OP_CALLOUT_STR. +OP_CALLOUT_STR. A callout block is allocated in pcre2_match() and initialized +with fixed values. Arguments: F points to the current backtracking frame @@ -269,7 +267,7 @@ do_callout(heapframe *F, match_block *mb, PCRE2_SIZE *lengthptr) int rc; PCRE2_SIZE save0, save1; PCRE2_SIZE *callout_ovector; -pcre2_callout_block cb; +pcre2_callout_block *cb; *lengthptr = (*Fecode == OP_CALLOUT)? PRIV(OP_lengths)[OP_CALLOUT] : GET(Fecode, 1 + 2*LINK_SIZE); @@ -288,40 +286,42 @@ pointer. */ callout_ovector = (PCRE2_SIZE *)(Fovector) - 2; -cb.version = 1; -cb.capture_top = (uint32_t)Foffset_top/2 + 1; -cb.capture_last = Fcapture_last; -cb.offset_vector = callout_ovector; -cb.mark = mb->nomatch_mark; -cb.subject = mb->start_subject; -cb.subject_length = (PCRE2_SIZE)(mb->end_subject - mb->start_subject); -cb.start_match = (PCRE2_SIZE)(Fstart_match - mb->start_subject); -cb.current_position = (PCRE2_SIZE)(Feptr - mb->start_subject); -cb.pattern_position = GET(Fecode, 1); -cb.next_item_length = GET(Fecode, 1 + LINK_SIZE); +/* The cb->version, cb->subject, cb->subject_length, and cb->start_match fields +are set externally. The first 3 never change; the last is updated for each +bumpalong. */ + +cb = mb->cb; +cb->capture_top = (uint32_t)Foffset_top/2 + 1; +cb->capture_last = Fcapture_last; +cb->offset_vector = callout_ovector; +cb->mark = mb->nomatch_mark; +cb->current_position = (PCRE2_SIZE)(Feptr - mb->start_subject); +cb->pattern_position = GET(Fecode, 1); +cb->next_item_length = GET(Fecode, 1 + LINK_SIZE); if (*Fecode == OP_CALLOUT) /* Numerical callout */ { - cb.callout_number = Fecode[1 + 2*LINK_SIZE]; - cb.callout_string_offset = 0; - cb.callout_string = NULL; - cb.callout_string_length = 0; + cb->callout_number = Fecode[1 + 2*LINK_SIZE]; + cb->callout_string_offset = 0; + cb->callout_string = NULL; + cb->callout_string_length = 0; } else /* String callout */ { - cb.callout_number = 0; - cb.callout_string_offset = GET(Fecode, 1 + 3*LINK_SIZE); - cb.callout_string = Fecode + (1 + 4*LINK_SIZE) + 1; - cb.callout_string_length = + cb->callout_number = 0; + cb->callout_string_offset = GET(Fecode, 1 + 3*LINK_SIZE); + cb->callout_string = Fecode + (1 + 4*LINK_SIZE) + 1; + cb->callout_string_length = *lengthptr - (1 + 4*LINK_SIZE) - 2; } save0 = callout_ovector[0]; save1 = callout_ovector[1]; callout_ovector[0] = callout_ovector[1] = PCRE2_UNSET; -rc = mb->callout(&cb, mb->callout_data); +rc = mb->callout(cb, mb->callout_data); callout_ovector[0] = save0; callout_ovector[1] = save1; +cb->callout_flags = 0; return rc; } @@ -732,7 +732,7 @@ for (;;) fprintf(stderr, "++ op=%d\n", *Fecode); #endif - Fop = *Fecode; + Fop = (uint8_t)(*Fecode); /* Cast needed for 16-bit and 32-bit modes */ switch(Fop) { /* ===================================================================== */ @@ -879,7 +879,7 @@ fprintf(stderr, "++ op=%d\n", *Fecode); } Feptr++; #ifdef SUPPORT_UNICODE - if (utf) ACROSSCHAR(Feptr < mb->end_subject, *Feptr, Feptr++); + if (utf) ACROSSCHAR(Feptr < mb->end_subject, Feptr, Feptr++); #endif Fecode++; break; @@ -2443,55 +2443,9 @@ fprintf(stderr, "++ op=%d\n", *Fecode); } else { - int lgb, rgb; GETCHARINCTEST(fc, Feptr); - lgb = UCD_GRAPHBREAK(fc); - while (Feptr < mb->end_subject) - { - int len = 1; - if (!utf) fc = *Feptr; else { GETCHARLEN(fc, Feptr, len); } - rgb = UCD_GRAPHBREAK(fc); - if ((PRIV(ucp_gbtable)[lgb] & (1 << rgb)) == 0) break; - - /* Not breaking between Regional Indicators is allowed only if there - are an even number of preceding RIs. */ - - if (lgb == ucp_gbRegionalIndicator && rgb == ucp_gbRegionalIndicator) - { - int ricount = 0; - PCRE2_SPTR bptr = Feptr - 1; -#ifdef SUPPORT_UNICODE - if (utf) BACKCHAR(bptr); -#endif - /* bptr is pointing to the left-hand character */ - - while (bptr > mb->start_subject) - { - bptr--; -#ifdef SUPPORT_UNICODE - if (utf) - { - BACKCHAR(bptr); - GETCHAR(fc, bptr); - } - else -#endif - fc = *bptr; - if (UCD_GRAPHBREAK(fc) != ucp_gbRegionalIndicator) break; - ricount++; - } - if ((ricount & 1) != 0) break; /* Grapheme break required */ - } - - /* If Extend follows E_Base[_GAZ] do not update lgb; this allows - any number of Extend before a following E_Modifier. */ - - if (rgb != ucp_gbExtend || - (lgb != ucp_gbE_Base && lgb != ucp_gbE_Base_GAZ)) - lgb = rgb; - - Feptr += len; - } + Feptr = PRIV(extuni)(fc, Feptr, mb->start_subject, mb->end_subject, utf, + NULL); } CHECK_PARTIAL(); Fecode++; @@ -2788,61 +2742,13 @@ fprintf(stderr, "++ op=%d\n", *Fecode); } else { - int lgb, rgb; GETCHARINCTEST(fc, Feptr); - lgb = UCD_GRAPHBREAK(fc); - while (Feptr < mb->end_subject) - { - int len = 1; - if (!utf) fc = *Feptr; else { GETCHARLEN(fc, Feptr, len); } - rgb = UCD_GRAPHBREAK(fc); - if ((PRIV(ucp_gbtable)[lgb] & (1 << rgb)) == 0) break; - - /* Not breaking between Regional Indicators is allowed only if - there are an even number of preceding RIs. */ - - if (lgb == ucp_gbRegionalIndicator && - rgb == ucp_gbRegionalIndicator) - { - int ricount = 0; - PCRE2_SPTR bptr = Feptr - 1; -#ifdef SUPPORT_UNICODE - if (utf) BACKCHAR(bptr); -#endif - /* bptr is pointing to the left-hand character */ - - while (bptr > mb->start_subject) - { - bptr--; -#ifdef SUPPORT_UNICODE - if (utf) - { - BACKCHAR(bptr); - GETCHAR(fc, bptr); - } - else -#endif - fc = *bptr; - if (UCD_GRAPHBREAK(fc) != ucp_gbRegionalIndicator) break; - ricount++; - } - if ((ricount & 1) != 0) break; /* Grapheme break required */ - } - - /* If Extend follows E_Base[_GAZ] do not update lgb; this allows - any number of Extend before a following E_Modifier. */ - - if (rgb != ucp_gbExtend || - (lgb != ucp_gbE_Base && lgb != ucp_gbE_Base_GAZ)) - lgb = rgb; - - Feptr += len; - } + Feptr = PRIV(extuni)(fc, Feptr, mb->start_subject, + mb->end_subject, utf, NULL); } CHECK_PARTIAL(); } } - else #endif /* SUPPORT_UNICODE */ @@ -2870,7 +2776,7 @@ fprintf(stderr, "++ op=%d\n", *Fecode); if (mb->partial > 1) return PCRE2_ERROR_PARTIAL; } Feptr++; - ACROSSCHAR(Feptr < mb->end_subject, *Feptr, Feptr++); + ACROSSCHAR(Feptr < mb->end_subject, Feptr, Feptr++); } break; @@ -2883,7 +2789,7 @@ fprintf(stderr, "++ op=%d\n", *Fecode); RRETURN(MATCH_NOMATCH); } Feptr++; - ACROSSCHAR(Feptr < mb->end_subject, *Feptr, Feptr++); + ACROSSCHAR(Feptr < mb->end_subject, Feptr, Feptr++); } break; @@ -3037,7 +2943,7 @@ fprintf(stderr, "++ op=%d\n", *Fecode); if (cc < 128 && (mb->ctypes[cc] & ctype_space) != 0) RRETURN(MATCH_NOMATCH); Feptr++; - ACROSSCHAR(Feptr < mb->end_subject, *Feptr, Feptr++); + ACROSSCHAR(Feptr < mb->end_subject, Feptr, Feptr++); } break; @@ -3071,7 +2977,7 @@ fprintf(stderr, "++ op=%d\n", *Fecode); if (cc < 128 && (mb->ctypes[cc] & ctype_word) != 0) RRETURN(MATCH_NOMATCH); Feptr++; - ACROSSCHAR(Feptr < mb->end_subject, *Feptr, Feptr++); + ACROSSCHAR(Feptr < mb->end_subject, Feptr, Feptr++); } break; @@ -3596,56 +3502,9 @@ fprintf(stderr, "++ op=%d\n", *Fecode); } else { - int lgb, rgb; GETCHARINCTEST(fc, Feptr); - lgb = UCD_GRAPHBREAK(fc); - while (Feptr < mb->end_subject) - { - int len = 1; - if (!utf) fc = *Feptr; else { GETCHARLEN(fc, Feptr, len); } - rgb = UCD_GRAPHBREAK(fc); - if ((PRIV(ucp_gbtable)[lgb] & (1 << rgb)) == 0) break; - - /* Not breaking between Regional Indicators is allowed only if - there are an even number of preceding RIs. */ - - if (lgb == ucp_gbRegionalIndicator && - rgb == ucp_gbRegionalIndicator) - { - int ricount = 0; - PCRE2_SPTR bptr = Feptr - 1; -#ifdef SUPPORT_UNICODE - if (utf) BACKCHAR(bptr); -#endif - /* bptr is pointing to the left-hand character */ - - while (bptr > mb->start_subject) - { - bptr--; -#ifdef SUPPORT_UNICODE - if (utf) - { - BACKCHAR(bptr); - GETCHAR(fc, bptr); - } - else -#endif - fc = *bptr; - if (UCD_GRAPHBREAK(fc) != ucp_gbRegionalIndicator) break; - ricount++; - } - if ((ricount & 1) != 0) break; /* Grapheme break required */ - } - - /* If Extend follows E_Base[_GAZ] do not update lgb; this allows - any number of Extend before a following E_Modifier. */ - - if (rgb != ucp_gbExtend || - (lgb != ucp_gbE_Base && lgb != ucp_gbE_Base_GAZ)) - lgb = rgb; - - Feptr += len; - } + Feptr = PRIV(extuni)(fc, Feptr, mb->start_subject, mb->end_subject, + utf, NULL); } CHECK_PARTIAL(); } @@ -4170,56 +4029,9 @@ fprintf(stderr, "++ op=%d\n", *Fecode); } else { - int lgb, rgb; GETCHARINCTEST(fc, Feptr); - lgb = UCD_GRAPHBREAK(fc); - while (Feptr < mb->end_subject) - { - int len = 1; - if (!utf) fc = *Feptr; else { GETCHARLEN(fc, Feptr, len); } - rgb = UCD_GRAPHBREAK(fc); - if ((PRIV(ucp_gbtable)[lgb] & (1 << rgb)) == 0) break; - - /* Not breaking between Regional Indicators is allowed only if - there are an even number of preceding RIs. */ - - if (lgb == ucp_gbRegionalIndicator && - rgb == ucp_gbRegionalIndicator) - { - int ricount = 0; - PCRE2_SPTR bptr = Feptr - 1; -#ifdef SUPPORT_UNICODE - if (utf) BACKCHAR(bptr); -#endif - /* bptr is pointing to the left-hand character */ - - while (bptr > mb->start_subject) - { - bptr--; -#ifdef SUPPORT_UNICODE - if (utf) - { - BACKCHAR(bptr); - GETCHAR(fc, bptr); - } - else -#endif - fc = *bptr; - if (UCD_GRAPHBREAK(fc) != ucp_gbRegionalIndicator) break; - ricount++; - } - if ((ricount & 1) != 0) break; /* Grapheme break required */ - } - - /* If Extend follows E_Base[_GAZ] do not update lgb; this allows - any number of Extend before a following E_Modifier. */ - - if (rgb != ucp_gbExtend || - (lgb != ucp_gbE_Base && lgb != ucp_gbE_Base_GAZ)) - lgb = rgb; - - Feptr += len; - } + Feptr = PRIV(extuni)(fc, Feptr, mb->start_subject, mb->end_subject, + utf, NULL); } CHECK_PARTIAL(); } @@ -4298,7 +4110,7 @@ fprintf(stderr, "++ op=%d\n", *Fecode); if (mb->partial > 1) return PCRE2_ERROR_PARTIAL; } Feptr++; - ACROSSCHAR(Feptr < mb->end_subject, *Feptr, Feptr++); + ACROSSCHAR(Feptr < mb->end_subject, Feptr, Feptr++); } break; @@ -4313,7 +4125,7 @@ fprintf(stderr, "++ op=%d\n", *Fecode); break; } Feptr++; - ACROSSCHAR(Feptr < mb->end_subject, *Feptr, Feptr++); + ACROSSCHAR(Feptr < mb->end_subject, Feptr, Feptr++); } } else @@ -5243,7 +5055,7 @@ fprintf(stderr, "++ op=%d\n", *Fecode); P = (heapframe *)((char *)N - frame_size); if (N->group_frame_type == (GF_RECURSE | number)) { - if (Feptr == P->eptr) RRETURN(PCRE2_ERROR_RECURSELOOP); + if (Feptr == P->eptr) return PCRE2_ERROR_RECURSELOOP; break; } offset = P->last_group_offset; @@ -6108,8 +5920,9 @@ in rrc. */ #define LBL(val) case val: goto L_RM##val; RETURN_SWITCH: -if (Frdepth == 0) return rrc; /* Exit from the top level */ -F = (heapframe *)((char *)F - Fback_frame); /* Back track */ +if (Frdepth == 0) return rrc; /* Exit from the top level */ +F = (heapframe *)((char *)F - Fback_frame); /* Back track */ +mb->cb->callout_flags |= PCRE2_CALLOUT_BACKTRACK; /* Note for callouts */ #ifdef DEBUG_SHOW_RMATCH fprintf(stderr, "++ RETURN %d to %d\n", rrc, Freturn_id); @@ -6199,6 +6012,7 @@ PCRE2_SIZE frame_size; /* We need to have mb as a pointer to a match block, because the IS_NEWLINE macro is used below, and it expects NLBLOCK to be defined as a pointer. */ +pcre2_callout_block cb; match_block actual_match_block; match_block *mb = &actual_match_block; @@ -6359,6 +6173,15 @@ startline = (re->flags & PCRE2_STARTLINE) != 0; bumpalong_limit = (mcontext->offset_limit == PCRE2_UNSET)? end_subject : subject + mcontext->offset_limit; +/* Initialize and set up the fixed fields in the callout block, with a pointer +in the match block. */ + +mb->cb = &cb; +cb.version = 2; +cb.subject = subject; +cb.subject_length = (PCRE2_SIZE)(end_subject - subject); +cb.callout_flags = 0; + /* Fill in the remaining fields in the match block. */ mb->callout = mcontext->callout; @@ -6540,13 +6363,11 @@ for(;;) if ((re->overall_options & PCRE2_NO_START_OPTIMIZE) == 0) { - PCRE2_SPTR save_end_subject = end_subject; - /* If firstline is TRUE, the start of the match is constrained to the first line of a multiline string. That is, the match must be before or at the - first newline. Implement this by temporarily adjusting end_subject so that - we stop the optimization scans for a first code unit at a newline. If the - match fails at the newline, later code breaks this loop. */ + first newline following the start of matching. Temporarily adjust + end_subject so that we stop the scans for a first code unit at a newline. + If the match fails at the newline, later code breaks the loop. */ if (firstline) { @@ -6554,15 +6375,15 @@ for(;;) #ifdef SUPPORT_UNICODE if (utf) { - while (t < mb->end_subject && !IS_NEWLINE(t)) + while (t < end_subject && !IS_NEWLINE(t)) { t++; - ACROSSCHAR(t < end_subject, *t, t++); + ACROSSCHAR(t < end_subject, t, t++); } } else #endif - while (t < mb->end_subject && !IS_NEWLINE(t)) t++; + while (t < end_subject && !IS_NEWLINE(t)) t++; end_subject = t; } @@ -6638,13 +6459,17 @@ for(;;) #endif } - /* If we can't find the required code unit, break the bumpalong loop, - to force a match failure, except when doing partial matching, when we - let the next cycle run at the end of the subject. To see why, consider - the pattern /(?<=abc)def/, which partially matches "abc", even though - the string does not contain the starting character "d". */ - - if (!mb->partial && start_match >= end_subject) + /* If we can't find the required code unit, having reached the true end + of the subject, break the bumpalong loop, to force a match failure, + except when doing partial matching, when we let the next cycle run at + the end of the subject. To see why, consider the pattern /(?<=abc)def/, + which partially matches "abc", even though the string does not contain + the starting character "d". If we have not reached the true end of the + subject (PCRE2_FIRSTLINE caused end_subject to be temporarily modified) + we also let the cycle run, because the matching string is legitimately + allowed to start with the first code unit of a newline. */ + + if (!mb->partial && start_match >= mb->end_subject) { rc = MATCH_NOMATCH; break; @@ -6664,8 +6489,7 @@ for(;;) while (start_match < end_subject && !WAS_NEWLINE(start_match)) { start_match++; - ACROSSCHAR(start_match < end_subject, *start_match, - start_match++); + ACROSSCHAR(start_match < end_subject, start_match, start_match++); } } else @@ -6701,12 +6525,20 @@ for(;;) if ((start_bits[c/8] & (1 << (c&7))) != 0) break; start_match++; } + + /* See comment above in first_cu checking about the next few lines. */ + + if (!mb->partial && start_match >= mb->end_subject) + { + rc = MATCH_NOMATCH; + break; + } } } /* End first code unit handling */ /* Restore fudged end_subject */ - end_subject = save_end_subject; + end_subject = mb->end_subject; /* The following two optimizations must be disabled for partial matching. */ @@ -6823,6 +6655,9 @@ for(;;) /* OK, we can now run the match. If "hitend" is set afterwards, remember the first starting point for which a partial match was found. */ + cb.start_match = (PCRE2_SIZE)(start_match - subject); + cb.callout_flags |= PCRE2_CALLOUT_STARTMATCH; + mb->start_used_ptr = start_match; mb->last_used_ptr = start_match; mb->match_call_count = 0; @@ -6873,7 +6708,7 @@ for(;;) new_start_match = start_match + 1; #ifdef SUPPORT_UNICODE if (utf) - ACROSSCHAR(new_start_match < end_subject, *new_start_match, + ACROSSCHAR(new_start_match < end_subject, new_start_match, new_start_match++); #endif break; @@ -7007,5 +6842,3 @@ return match_data->rc; } /* End of pcre2_match.c */ - -#pragma warning(pop) diff --git a/ProcessHacker/pcre/pcre2_pattern_info.c b/ProcessHacker/pcre/pcre2_pattern_info.c index 540707b2258c..906e9198f590 100644 --- a/ProcessHacker/pcre/pcre2_pattern_info.c +++ b/ProcessHacker/pcre/pcre2_pattern_info.c @@ -76,6 +76,7 @@ if (where == NULL) /* Requests field length */ case PCRE2_INFO_BSR: case PCRE2_INFO_CAPTURECOUNT: case PCRE2_INFO_DEPTHLIMIT: + case PCRE2_INFO_EXTRAOPTIONS: case PCRE2_INFO_FIRSTCODETYPE: case PCRE2_INFO_FIRSTCODEUNIT: case PCRE2_INFO_HASBACKSLASHC: @@ -144,6 +145,10 @@ switch(what) if (re->limit_depth == UINT32_MAX) return PCRE2_ERROR_UNSET; break; + case PCRE2_INFO_EXTRAOPTIONS: + *((uint32_t *)where) = re->extra_options; + break; + case PCRE2_INFO_FIRSTCODETYPE: *((uint32_t *)where) = ((re->flags & PCRE2_FIRSTSET) != 0)? 1 : ((re->flags & PCRE2_STARTLINE) != 0)? 2 : 0; diff --git a/ProcessHacker/pcre/pcre2_substring.c b/ProcessHacker/pcre/pcre2_substring.c index f6d7c3972270..ddf5774e1501 100644 --- a/ProcessHacker/pcre/pcre2_substring.c +++ b/ProcessHacker/pcre/pcre2_substring.c @@ -7,7 +7,7 @@ and semantics are as close as possible to those of the Perl 5 language. Written by Philip Hazel Original API code Copyright (c) 1997-2012 University of Cambridge - New API code Copyright (c) 2016 University of Cambridge + New API code Copyright (c) 2016-2018 University of Cambridge ----------------------------------------------------------------------------- Redistribution and use in source and binary forms, with or without @@ -414,7 +414,12 @@ else for (i = 0; i < count2; i += 2) { size = (ovector[i+1] > ovector[i])? (ovector[i+1] - ovector[i]) : 0; - memcpy(sp, match_data->subject + ovector[i], CU2BYTES(size)); + + /* Size == 0 includes the case when the capture is unset. Avoid adding + PCRE2_UNSET to match_data->subject because it overflows, even though with + zero size calling memcpy() is harmless. */ + + if (size != 0) memcpy(sp, match_data->subject + ovector[i], CU2BYTES(size)); *listp++ = sp; if (lensp != NULL) *lensp++ = size; sp += size; diff --git a/ProcessHacker/pcre/pcre2posix.c b/ProcessHacker/pcre/pcre2posix.c index 908f91cded92..6a860844649d 100644 --- a/ProcessHacker/pcre/pcre2posix.c +++ b/ProcessHacker/pcre/pcre2posix.c @@ -38,13 +38,13 @@ POSSIBILITY OF SUCH DAMAGE. ----------------------------------------------------------------------------- */ +// dmex: Disable warnings. +#pragma warning(push) +#pragma warning(disable : 4267) /* This module is a wrapper that provides a POSIX API to the underlying PCRE2 functions. */ -// dmex: Disable warnings. -#pragma warning(push) -#pragma warning(disable : 4267) #ifdef HAVE_CONFIG_H #include "config.h" @@ -374,5 +374,4 @@ switch(rc) } /* End of pcre2posix.c */ - #pragma warning(pop) From 7b045ec19cfeb1728cb944eed303a1172d6ab4f3 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 4 Apr 2018 21:06:24 +1000 Subject: [PATCH 0869/2058] ExtendedTools: Add GPU commit graph, Fix Disk/Network/GPU graph resize flicker --- plugins/ExtendedTools/ExtendedTools.rc | 11 +- plugins/ExtendedTools/etwprprp.c | 14 +- plugins/ExtendedTools/exttools.h | 1 + plugins/ExtendedTools/gpumon.c | 2 + plugins/ExtendedTools/gpuprprp.c | 202 ++++++++++++++++++++----- plugins/ExtendedTools/resource.h | 3 +- 6 files changed, 188 insertions(+), 45 deletions(-) diff --git a/plugins/ExtendedTools/ExtendedTools.rc b/plugins/ExtendedTools/ExtendedTools.rc index ca97a242e353..40a1f204c3a1 100644 --- a/plugins/ExtendedTools/ExtendedTools.rc +++ b/plugins/ExtendedTools/ExtendedTools.rc @@ -130,8 +130,8 @@ STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSM CAPTION "Disk and Network" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN - GROUPBOX "Disk",IDC_GROUPDISK,7,7,251,69 - GROUPBOX "Network",IDC_GROUPNETWORK,7,81,251,69 + GROUPBOX "Disk",IDC_GROUPDISK,7,7,251,69,0,WS_EX_TRANSPARENT + GROUPBOX "Network",IDC_GROUPNETWORK,7,81,251,69,0,WS_EX_TRANSPARENT END IDD_SYSINFO_DISKPANEL DIALOGEX 0, 0, 146, 58 @@ -212,9 +212,10 @@ STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSM CAPTION "GPU" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN - GROUPBOX "GPU",IDC_GROUPGPU,7,7,355,69 - GROUPBOX "Dedicated memory",IDC_GROUPMEM,7,81,355,69 - GROUPBOX "Shared memory",IDC_GROUPSHARED,7,160,355,69 + GROUPBOX "GPU",IDC_GROUPGPU,7,7,355,53,0,WS_EX_TRANSPARENT + GROUPBOX "Dedicated memory",IDC_GROUPMEM,7,63,355,53,0,WS_EX_TRANSPARENT + GROUPBOX "Shared memory",IDC_GROUPSHARED,7,119,355,53,0,WS_EX_TRANSPARENT + GROUPBOX "Commit memory",IDC_GROUPCOMMIT,7,175,355,53,0,WS_EX_TRANSPARENT END IDD_SYSINFO_DISK DIALOGEX 0, 0, 315, 186 diff --git a/plugins/ExtendedTools/etwprprp.c b/plugins/ExtendedTools/etwprprp.c index 67e7ce1b0cd6..7cbb27017645 100644 --- a/plugins/ExtendedTools/etwprprp.c +++ b/plugins/ExtendedTools/etwprprp.c @@ -73,7 +73,7 @@ VOID EtwDiskNetworkCreateGraphs( Context->DiskGraphHandle = CreateWindow( PH_GRAPH_CLASSNAME, NULL, - WS_VISIBLE | WS_CHILD | WS_BORDER, + WS_VISIBLE | WS_CHILD | WS_BORDER | WS_CLIPSIBLINGS, 0, 0, 3, @@ -88,7 +88,7 @@ VOID EtwDiskNetworkCreateGraphs( Context->NetworkGraphHandle = CreateWindow( PH_GRAPH_CLASSNAME, NULL, - WS_VISIBLE | WS_CHILD | WS_BORDER, + WS_VISIBLE | WS_CHILD | WS_BORDER | WS_CLIPSIBLINGS, 0, 0, 3, @@ -298,6 +298,12 @@ INT_PTR CALLBACK EtwDiskNetworkPageDlgProc( { ULONG sampleCount; + // We have already set the group boxes to have WS_EX_TRANSPARENT to fix + // the drawing issue that arises when using WS_CLIPCHILDREN. However + // in removing the flicker from the graphs the group boxes will now flicker. + // It's a good tradeoff since no one stares at the group boxes. + PhSetWindowStyle(hwndDlg, WS_CLIPCHILDREN, WS_CLIPCHILDREN); + sampleCount = PhGetIntegerSetting(L"SampleCount"); context = PhAllocate(sizeof(ET_DISKNET_CONTEXT)); @@ -547,7 +553,7 @@ INT_PTR CALLBACK EtwDiskNetworkPageDlgProc( )); } - getTooltipText->Text = context->DiskGraphState.TooltipText->sr; + getTooltipText->Text = PhGetStringRef(context->DiskGraphState.TooltipText); } else if (header->hwndFrom == context->NetworkGraphHandle) { @@ -571,7 +577,7 @@ INT_PTR CALLBACK EtwDiskNetworkPageDlgProc( )); } - getTooltipText->Text = context->NetworkGraphState.TooltipText->sr; + getTooltipText->Text = PhGetStringRef(context->NetworkGraphState.TooltipText); } } } diff --git a/plugins/ExtendedTools/exttools.h b/plugins/ExtendedTools/exttools.h index c3ec61004af1..da6153fae6dc 100644 --- a/plugins/ExtendedTools/exttools.h +++ b/plugins/ExtendedTools/exttools.h @@ -199,6 +199,7 @@ typedef struct _ET_PROCESS_BLOCK FLOAT GpuNodeUsage; ULONG64 GpuDedicatedUsage; ULONG64 GpuSharedUsage; + ULONG64 GpuCommitUsage; PH_UINT32_DELTA HardFaultsDelta; diff --git a/plugins/ExtendedTools/gpumon.c b/plugins/ExtendedTools/gpumon.c index ca608783baa3..62af0e107a56 100644 --- a/plugins/ExtendedTools/gpumon.c +++ b/plugins/ExtendedTools/gpumon.c @@ -439,10 +439,12 @@ VOID EtpUpdateSegmentInformation( if (WindowsVersion >= WINDOWS_8) { bytesCommitted = queryStatistics.QueryResult.SegmentInformation.BytesResident; + // TODO: SegmentInformation.CommitLimit } else { bytesCommitted = queryStatistics.QueryResult.SegmentInformationV1.BytesResident; + // TODO: SegmentInformationV1.CommitLimit } if (RtlCheckBit(&gpuAdapter->ApertureBitMap, j)) diff --git a/plugins/ExtendedTools/gpuprprp.c b/plugins/ExtendedTools/gpuprprp.c index bd89018f544e..84c0fa0c1e09 100644 --- a/plugins/ExtendedTools/gpuprprp.c +++ b/plugins/ExtendedTools/gpuprprp.c @@ -36,22 +36,29 @@ typedef struct _ET_GPU_CONTEXT HWND GpuGroupBox; HWND MemGroupBox; HWND SharedGroupBox; + HWND CommittedGroupBox; HWND GpuGraphHandle; HWND MemGraphHandle; HWND SharedGraphHandle; + HWND CommittedGraphHandle; FLOAT CurrentGpuUsage; ULONG CurrentMemUsage; ULONG CurrentMemSharedUsage; + ULONG CurrentCommitUsage; PH_GRAPH_STATE GpuGraphState; PH_GRAPH_STATE MemoryGraphState; PH_GRAPH_STATE MemorySharedGraphState; + PH_GRAPH_STATE GpuCommittedGraphState; PH_CIRCULAR_BUFFER_FLOAT GpuHistory; PH_CIRCULAR_BUFFER_ULONG MemoryHistory; PH_CIRCULAR_BUFFER_ULONG MemorySharedHistory; + PH_CIRCULAR_BUFFER_ULONG GpuCommittedHistory; + + ET_PROCESS_GPU_STATISTICS GpuStatistics; } ET_GPU_CONTEXT, *PET_GPU_CONTEXT; static RECT NormalGraphTextMargin = { 5, 5, 5, 5 }; @@ -173,7 +180,7 @@ VOID GpuPropCreateGraphs( Context->GpuGraphHandle = CreateWindow( PH_GRAPH_CLASSNAME, NULL, - WS_VISIBLE | WS_CHILD | WS_BORDER, + WS_VISIBLE | WS_CHILD | WS_BORDER | WS_CLIPSIBLINGS, 0, 0, 3, @@ -188,7 +195,7 @@ VOID GpuPropCreateGraphs( Context->MemGraphHandle = CreateWindow( PH_GRAPH_CLASSNAME, NULL, - WS_VISIBLE | WS_CHILD | WS_BORDER, + WS_VISIBLE | WS_CHILD | WS_BORDER | WS_CLIPSIBLINGS, 0, 0, 3, @@ -203,7 +210,7 @@ VOID GpuPropCreateGraphs( Context->SharedGraphHandle = CreateWindow( PH_GRAPH_CLASSNAME, NULL, - WS_VISIBLE | WS_CHILD | WS_BORDER, + WS_VISIBLE | WS_CHILD | WS_BORDER | WS_CLIPSIBLINGS, 0, 0, 3, @@ -214,6 +221,21 @@ VOID GpuPropCreateGraphs( NULL ); Graph_SetTooltip(Context->SharedGraphHandle, TRUE); + + Context->CommittedGraphHandle = CreateWindow( + PH_GRAPH_CLASSNAME, + NULL, + WS_VISIBLE | WS_CHILD | WS_BORDER | WS_CLIPSIBLINGS, + 0, + 0, + 3, + 3, + Context->WindowHandle, + NULL, + NULL, + NULL + ); + Graph_SetTooltip(Context->CommittedGraphHandle, TRUE); } VOID GpuPropCreatePanel( @@ -283,9 +305,9 @@ VOID GpuPropLayoutGraphs( clientRect.bottom = panelRect.top + 10; // +10 removing extra spacing graphWidth = clientRect.right - margin.left - margin.right; - graphHeight = (clientRect.bottom - margin.top - margin.bottom - between * 2) / 3; + graphHeight = (clientRect.bottom - margin.top - margin.bottom - between * 4) / 4; - deferHandle = BeginDeferWindowPos(6); + deferHandle = BeginDeferWindowPos(8); deferHandle = DeferWindowPos(deferHandle, Context->GpuGroupBox, NULL, margin.left, margin.top, graphWidth, graphHeight, SWP_NOACTIVATE | SWP_NOZORDER); deferHandle = DeferWindowPos( @@ -323,6 +345,18 @@ VOID GpuPropLayoutGraphs( SWP_NOACTIVATE | SWP_NOZORDER ); + deferHandle = DeferWindowPos(deferHandle, Context->CommittedGroupBox, NULL, margin.left, margin.top + (graphHeight + between) * 3, graphWidth, graphHeight, SWP_NOACTIVATE | SWP_NOZORDER); + deferHandle = DeferWindowPos( + deferHandle, + Context->CommittedGraphHandle, + NULL, + margin.left + innerMargin.left, + margin.top + (graphHeight + between) * 3 + innerMargin.top, + graphWidth - innerMargin.left - innerMargin.right, + graphHeight - innerMargin.top - innerMargin.bottom, + SWP_NOACTIVATE | SWP_NOZORDER + ); + EndDeferWindowPos(deferHandle); } @@ -350,40 +384,41 @@ VOID GpuPropUpdateGraphs( Graph_Draw(Context->SharedGraphHandle); Graph_UpdateTooltip(Context->SharedGraphHandle); InvalidateRect(Context->SharedGraphHandle, NULL, FALSE); + + Context->GpuCommittedGraphState.Valid = FALSE; + Context->GpuCommittedGraphState.TooltipIndex = -1; + Graph_MoveGrid(Context->CommittedGraphHandle, 1); + Graph_Draw(Context->CommittedGraphHandle); + Graph_UpdateTooltip(Context->CommittedGraphHandle); + InvalidateRect(Context->CommittedGraphHandle, NULL, FALSE); } VOID GpuPropUpdatePanel( _Inout_ PET_GPU_CONTEXT Context ) { - ET_PROCESS_GPU_STATISTICS statistics; WCHAR runningTimeString[PH_TIMESPAN_STR_LEN_1] = L"N/A"; - if (Context->Block->ProcessItem->QueryHandle) - EtQueryProcessGpuStatistics(Context->Block->ProcessItem->QueryHandle, &statistics); - else - memset(&statistics, 0, sizeof(ET_PROCESS_GPU_STATISTICS)); - - PhPrintTimeSpan(runningTimeString, statistics.RunningTime * 10, PH_TIMESPAN_HMSM); + PhPrintTimeSpan(runningTimeString, Context->GpuStatistics.RunningTime * 10, PH_TIMESPAN_HMSM); SetDlgItemText(Context->PanelHandle, IDC_ZRUNNINGTIME_V, runningTimeString); - SetDlgItemText(Context->PanelHandle, IDC_ZCONTEXTSWITCHES_V, PhaFormatUInt64(statistics.ContextSwitches, TRUE)->Buffer); - SetDlgItemText(Context->PanelHandle, IDC_ZTOTALNODES_V, PhaFormatUInt64(statistics.NodeCount, TRUE)->Buffer); - SetDlgItemText(Context->PanelHandle, IDC_ZTOTALSEGMENTS_V, PhaFormatUInt64(statistics.SegmentCount, TRUE)->Buffer); + SetDlgItemText(Context->PanelHandle, IDC_ZCONTEXTSWITCHES_V, PhaFormatUInt64(Context->GpuStatistics.ContextSwitches, TRUE)->Buffer); + SetDlgItemText(Context->PanelHandle, IDC_ZTOTALNODES_V, PhaFormatUInt64(Context->GpuStatistics.NodeCount, TRUE)->Buffer); + SetDlgItemText(Context->PanelHandle, IDC_ZTOTALSEGMENTS_V, PhaFormatUInt64(Context->GpuStatistics.SegmentCount, TRUE)->Buffer); if (Context->DetailsHandle) { // Note: no lock is needed because we only ever update the 'details' dialog text on this same thread. - SetDlgItemText(Context->DetailsHandle, IDC_ZDEDICATEDCOMMITTED_V, PhaFormatSize(statistics.DedicatedCommitted, -1)->Buffer); - SetDlgItemText(Context->DetailsHandle, IDC_ZSHAREDCOMMITTED_V, PhaFormatSize(statistics.SharedCommitted, -1)->Buffer); - SetDlgItemText(Context->DetailsHandle, IDC_ZTOTALALLOCATED_V, PhaFormatSize(statistics.BytesAllocated, -1)->Buffer); - SetDlgItemText(Context->DetailsHandle, IDC_ZTOTALRESERVED_V, PhaFormatSize(statistics.BytesReserved, -1)->Buffer); - SetDlgItemText(Context->DetailsHandle, IDC_ZWRITECOMBINEDALLOCATED_V, PhaFormatSize(statistics.WriteCombinedBytesAllocated, -1)->Buffer); - SetDlgItemText(Context->DetailsHandle, IDC_ZWRITECOMBINEDRESERVED_V, PhaFormatSize(statistics.WriteCombinedBytesReserved, -1)->Buffer); - SetDlgItemText(Context->DetailsHandle, IDC_ZCACHEDALLOCATED_V, PhaFormatSize(statistics.CachedBytesAllocated, -1)->Buffer); - SetDlgItemText(Context->DetailsHandle, IDC_ZCACHEDRESERVED_V, PhaFormatSize(statistics.CachedBytesReserved, -1)->Buffer); - SetDlgItemText(Context->DetailsHandle, IDC_ZSECTIONALLOCATED_V, PhaFormatSize(statistics.SectionBytesAllocated, -1)->Buffer); - SetDlgItemText(Context->DetailsHandle, IDC_ZSECTIONRESERVED_V, PhaFormatSize(statistics.SectionBytesReserved, -1)->Buffer); + SetDlgItemText(Context->DetailsHandle, IDC_ZDEDICATEDCOMMITTED_V, PhaFormatSize(Context->GpuStatistics.DedicatedCommitted, -1)->Buffer); + SetDlgItemText(Context->DetailsHandle, IDC_ZSHAREDCOMMITTED_V, PhaFormatSize(Context->GpuStatistics.SharedCommitted, -1)->Buffer); + SetDlgItemText(Context->DetailsHandle, IDC_ZTOTALALLOCATED_V, PhaFormatSize(Context->GpuStatistics.BytesAllocated, -1)->Buffer); + SetDlgItemText(Context->DetailsHandle, IDC_ZTOTALRESERVED_V, PhaFormatSize(Context->GpuStatistics.BytesReserved, -1)->Buffer); + SetDlgItemText(Context->DetailsHandle, IDC_ZWRITECOMBINEDALLOCATED_V, PhaFormatSize(Context->GpuStatistics.WriteCombinedBytesAllocated, -1)->Buffer); + SetDlgItemText(Context->DetailsHandle, IDC_ZWRITECOMBINEDRESERVED_V, PhaFormatSize(Context->GpuStatistics.WriteCombinedBytesReserved, -1)->Buffer); + SetDlgItemText(Context->DetailsHandle, IDC_ZCACHEDALLOCATED_V, PhaFormatSize(Context->GpuStatistics.CachedBytesAllocated, -1)->Buffer); + SetDlgItemText(Context->DetailsHandle, IDC_ZCACHEDRESERVED_V, PhaFormatSize(Context->GpuStatistics.CachedBytesReserved, -1)->Buffer); + SetDlgItemText(Context->DetailsHandle, IDC_ZSECTIONALLOCATED_V, PhaFormatSize(Context->GpuStatistics.SectionBytesAllocated, -1)->Buffer); + SetDlgItemText(Context->DetailsHandle, IDC_ZSECTIONRESERVED_V, PhaFormatSize(Context->GpuStatistics.SectionBytesReserved, -1)->Buffer); } } @@ -393,13 +428,20 @@ VOID GpuPropUpdateInfo( { PET_PROCESS_BLOCK block = Context->Block; + if (Context->Block->ProcessItem->QueryHandle) + EtQueryProcessGpuStatistics(Context->Block->ProcessItem->QueryHandle, &Context->GpuStatistics); + else + memset(&Context->GpuStatistics, 0, sizeof(ET_PROCESS_GPU_STATISTICS)); + Context->CurrentGpuUsage = block->GpuNodeUsage; Context->CurrentMemUsage = (ULONG)(block->GpuDedicatedUsage / PAGE_SIZE); Context->CurrentMemSharedUsage = (ULONG)(block->GpuSharedUsage / PAGE_SIZE); + Context->CurrentCommitUsage = (ULONG)(Context->GpuStatistics.BytesAllocated / PAGE_SIZE); // HACK HACK HACK PhAddItemCircularBuffer_FLOAT(&Context->GpuHistory, Context->CurrentGpuUsage); PhAddItemCircularBuffer_ULONG(&Context->MemoryHistory, Context->CurrentMemUsage); PhAddItemCircularBuffer_ULONG(&Context->MemorySharedHistory, Context->CurrentMemSharedUsage); + PhAddItemCircularBuffer_ULONG(&Context->GpuCommittedHistory, Context->CurrentCommitUsage); } VOID NTAPI ProcessesUpdatedHandler( @@ -445,6 +487,12 @@ INT_PTR CALLBACK EtpGpuPageDlgProc( { ULONG sampleCount; + // We have already set the group boxes to have WS_EX_TRANSPARENT to fix + // the drawing issue that arises when using WS_CLIPCHILDREN. However + // in removing the flicker from the graphs the group boxes will now flicker. + // It's a good tradeoff since no one stares at the group boxes. + PhSetWindowStyle(hwndDlg, WS_CLIPCHILDREN, WS_CLIPCHILDREN); + sampleCount = PhGetIntegerSetting(L"SampleCount"); context = PhAllocate(sizeof(ET_GPU_CONTEXT)); @@ -456,6 +504,7 @@ INT_PTR CALLBACK EtpGpuPageDlgProc( context->GpuGroupBox = GetDlgItem(hwndDlg, IDC_GROUPGPU); context->MemGroupBox = GetDlgItem(hwndDlg, IDC_GROUPMEM); context->SharedGroupBox = GetDlgItem(hwndDlg, IDC_GROUPSHARED); + context->CommittedGroupBox = GetDlgItem(hwndDlg, IDC_GROUPCOMMIT); propPageContext->Context = context; PhInitializeLayoutManager(&context->LayoutManager, hwndDlg); @@ -463,10 +512,12 @@ INT_PTR CALLBACK EtpGpuPageDlgProc( PhInitializeGraphState(&context->GpuGraphState); PhInitializeGraphState(&context->MemoryGraphState); PhInitializeGraphState(&context->MemorySharedGraphState); + PhInitializeGraphState(&context->GpuCommittedGraphState); PhInitializeCircularBuffer_FLOAT(&context->GpuHistory, sampleCount); PhInitializeCircularBuffer_ULONG(&context->MemoryHistory, sampleCount); PhInitializeCircularBuffer_ULONG(&context->MemorySharedHistory, sampleCount); + PhInitializeCircularBuffer_ULONG(&context->GpuCommittedHistory, sampleCount); GpuPropCreateGraphs(context); GpuPropCreatePanel(context); @@ -488,10 +539,12 @@ INT_PTR CALLBACK EtpGpuPageDlgProc( PhDeleteGraphState(&context->GpuGraphState); PhDeleteGraphState(&context->MemoryGraphState); PhDeleteGraphState(&context->MemorySharedGraphState); + PhDeleteGraphState(&context->GpuCommittedGraphState); PhDeleteCircularBuffer_FLOAT(&context->GpuHistory); PhDeleteCircularBuffer_ULONG(&context->MemoryHistory); PhDeleteCircularBuffer_ULONG(&context->MemorySharedHistory); + PhDeleteCircularBuffer_ULONG(&context->GpuCommittedHistory); if (context->GpuGraphHandle) DestroyWindow(context->GpuGraphHandle); @@ -499,6 +552,8 @@ INT_PTR CALLBACK EtpGpuPageDlgProc( DestroyWindow(context->MemGraphHandle); if (context->SharedGraphHandle) DestroyWindow(context->SharedGraphHandle); + if (context->CommittedGraphHandle) + DestroyWindow(context->CommittedGraphHandle); if (context->PanelHandle) DestroyWindow(context->PanelHandle); @@ -668,6 +723,60 @@ INT_PTR CALLBACK EtpGpuPageDlgProc( context->MemorySharedGraphState.Valid = TRUE; } } + else if (header->hwndFrom == context->CommittedGraphHandle) + { + if (PhGetIntegerSetting(L"GraphShowText")) + { + HDC hdc; + + PhMoveReference(&context->GpuCommittedGraphState.Text, PhFormatString( + L"%s", + PhaFormatSize(UInt32x32To64(context->CurrentCommitUsage, PAGE_SIZE), -1)->Buffer + )); + + hdc = Graph_GetBufferedContext(context->CommittedGraphHandle); + SelectObject(hdc, PhApplicationFont); + PhSetGraphText(hdc, drawInfo, &context->GpuCommittedGraphState.Text->sr, + &NormalGraphTextMargin, &NormalGraphTextPadding, PH_ALIGN_TOP | PH_ALIGN_LEFT); + } + else + { + drawInfo->Text.Buffer = NULL; + } + + drawInfo->Flags = PH_GRAPH_USE_GRID_X | PH_GRAPH_USE_GRID_Y; + PhSiSetColorsGraphDrawInfo(drawInfo, PhGetIntegerSetting(L"ColorPrivate"), 0); + PhGraphStateGetDrawInfo( + &context->GpuCommittedGraphState, + getDrawInfo, + context->GpuCommittedHistory.Count + ); + + if (!context->GpuCommittedGraphState.Valid) + { + ULONG i; + static FLOAT max = 1024 * 1024; // minimum scaling + + for (i = 0; i < drawInfo->LineDataCount; i++) + { + FLOAT data1; + + context->GpuCommittedGraphState.Data1[i] = data1 = (FLOAT)PhGetItemCircularBuffer_ULONG(&context->GpuCommittedHistory, i); + + if (max < data1) + max = data1; + } + + // Scale the data. + PhDivideSinglesBySingle( + context->GpuCommittedGraphState.Data1, + max, + drawInfo->LineDataCount + ); + + context->GpuCommittedGraphState.Valid = TRUE; + } + } } break; case GCN_GETTOOLTIPTEXT: @@ -686,12 +795,13 @@ INT_PTR CALLBACK EtpGpuPageDlgProc( ); PhMoveReference(&context->GpuGraphState.TooltipText, PhFormatString( - L"%.2f%%", - gpuUsage * 100 - )); + L"%.2f%%\n%s", + gpuUsage * 100, + PH_AUTO_T(PH_STRING, PhGetStatisticsTimeString(NULL, getTooltipText->Index))->Buffer) + ); } - getTooltipText->Text = context->GpuGraphState.TooltipText->sr; + getTooltipText->Text = PhGetStringRef(context->GpuGraphState.TooltipText); } else if (header->hwndFrom == context->MemGraphHandle) { @@ -702,12 +812,14 @@ INT_PTR CALLBACK EtpGpuPageDlgProc( getTooltipText->Index ); - PhMoveReference(&context->MemoryGraphState.TooltipText, - PhFormatSize(UInt32x32To64(gpuMemory, PAGE_SIZE), -1) + PhMoveReference(&context->MemoryGraphState.TooltipText, PhFormatString( + L"%s\n%s", + PhFormatSize(UInt32x32To64(gpuMemory, PAGE_SIZE), -1)->Buffer, + PH_AUTO_T(PH_STRING, PhGetStatisticsTimeString(NULL, getTooltipText->Index))->Buffer) ); } - getTooltipText->Text = context->MemoryGraphState.TooltipText->sr; + getTooltipText->Text = PhGetStringRef(context->MemoryGraphState.TooltipText); } else if (header->hwndFrom == context->SharedGraphHandle) { @@ -718,12 +830,32 @@ INT_PTR CALLBACK EtpGpuPageDlgProc( getTooltipText->Index ); - PhMoveReference(&context->MemorySharedGraphState.TooltipText, - PhFormatSize(UInt32x32To64(gpuSharedMemory, PAGE_SIZE), -1) + PhMoveReference(&context->MemorySharedGraphState.TooltipText, PhFormatString( + L"%s\n%s", + PhFormatSize(UInt32x32To64(gpuSharedMemory, PAGE_SIZE), -1)->Buffer, + PH_AUTO_T(PH_STRING, PhGetStatisticsTimeString(NULL, getTooltipText->Index))->Buffer) + ); + } + + getTooltipText->Text = PhGetStringRef(context->MemorySharedGraphState.TooltipText); + } + else if (header->hwndFrom == context->CommittedGraphHandle) + { + if (context->GpuCommittedGraphState.TooltipIndex != getTooltipText->Index) + { + ULONG gpuCommitMemory = PhGetItemCircularBuffer_ULONG( + &context->GpuCommittedHistory, + getTooltipText->Index + ); + + PhMoveReference(&context->GpuCommittedGraphState.TooltipText, PhFormatString( + L"%s\n%s", + PhFormatSize(UInt32x32To64(gpuCommitMemory, PAGE_SIZE), -1)->Buffer, + PH_AUTO_T(PH_STRING, PhGetStatisticsTimeString(NULL, getTooltipText->Index))->Buffer) ); } - getTooltipText->Text = context->MemorySharedGraphState.TooltipText->sr; + getTooltipText->Text = PhGetStringRef(context->GpuCommittedGraphState.TooltipText); } } } diff --git a/plugins/ExtendedTools/resource.h b/plugins/ExtendedTools/resource.h index 27a55506b591..94eb49f20103 100644 --- a/plugins/ExtendedTools/resource.h +++ b/plugins/ExtendedTools/resource.h @@ -61,6 +61,7 @@ #define IDC_GROUPMEM 1052 #define IDC_GROUPSHARED 1053 #define IDC_GROUPDEDICATED 1054 +#define IDC_GROUPCOMMIT 1054 #define IDC_ZDEDICATEDCURRENT_V 1055 #define IDC_ZDEDICATEDLIMIT_V 1056 #define IDC_ZSHAREDCURRENT_V 1057 @@ -106,7 +107,7 @@ // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 135 +#define _APS_NEXT_RESOURCE_VALUE 138 #define _APS_NEXT_COMMAND_VALUE 40009 #define _APS_NEXT_CONTROL_VALUE 1091 #define _APS_NEXT_SYMED_VALUE 130 From 94098feb4d59a8498497072712786d10f25d4f8d Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 4 Apr 2018 21:08:53 +1000 Subject: [PATCH 0870/2058] ExtendedTools: Add select/deslect button to GPU nodes window --- plugins/ExtendedTools/ExtendedTools.rc | 1 + plugins/ExtendedTools/gpunodes.c | 34 ++++++++++++++++++++------ plugins/ExtendedTools/resource.h | 1 + 3 files changed, 28 insertions(+), 8 deletions(-) diff --git a/plugins/ExtendedTools/ExtendedTools.rc b/plugins/ExtendedTools/ExtendedTools.rc index 40a1f204c3a1..543ef65c9b70 100644 --- a/plugins/ExtendedTools/ExtendedTools.rc +++ b/plugins/ExtendedTools/ExtendedTools.rc @@ -262,6 +262,7 @@ BEGIN LTEXT "Graph layout",IDC_LAYOUT,7,21,303,137,NOT WS_VISIBLE CONTROL "Example checkbox",IDC_EXAMPLE,"Button",BS_AUTOCHECKBOX | NOT WS_VISIBLE | WS_TABSTOP,7,166,75,10 DEFPUSHBUTTON "OK",IDOK,260,162,50,14 + CONTROL "Select/Deselect",IDC_SELECTALL,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,190,165,65,10 END IDD_PROCGPU_PANEL DIALOGEX 0, 0, 248, 46 diff --git a/plugins/ExtendedTools/gpunodes.c b/plugins/ExtendedTools/gpunodes.c index fa1292a44ace..59e15005c172 100644 --- a/plugins/ExtendedTools/gpunodes.c +++ b/plugins/ExtendedTools/gpunodes.c @@ -65,17 +65,24 @@ static VOID ProcessesUpdatedCallback( } VOID EtpLoadNodeBitMap( - VOID + _In_ HWND WindowHandle ) { ULONG i; + BOOLEAN allSelected = TRUE; for (i = 0; i < EtGpuTotalNodeCount; i++) { - Button_SetCheck( - CheckBoxHandle[i], - RtlCheckBit(&EtGpuNodeBitMap, i) ? BST_CHECKED : BST_UNCHECKED - ); + BOOLEAN nodeEnabled = RtlCheckBit(&EtGpuNodeBitMap, i); + + Button_SetCheck(CheckBoxHandle[i], nodeEnabled ? BST_CHECKED : BST_UNCHECKED); + + if (!nodeEnabled) allSelected = FALSE; + } + + if (allSelected) + { + Button_SetCheck(GetDlgItem(WindowHandle, IDC_SELECTALL), BST_CHECKED); } } @@ -125,11 +132,10 @@ INT_PTR CALLBACK EtpGpuNodesDlgProc( SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhInstanceHandle, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); PhInitializeLayoutManager(&LayoutManager, hwndDlg); + PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDC_SELECTALL), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDOK), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); LayoutMargin = PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDC_LAYOUT), NULL, PH_ANCHOR_ALL)->Margin; - PhRegisterCallback(&PhProcessesUpdatedEvent, ProcessesUpdatedCallback, NULL, &ProcessesUpdatedCallbackRegistration); - GraphHandle = PhAllocate(sizeof(HWND) * EtGpuTotalNodeCount); CheckBoxHandle = PhAllocate(sizeof(HWND) * EtGpuTotalNodeCount); GraphState = PhAllocate(sizeof(PH_GRAPH_STATE) * EtGpuTotalNodeCount); @@ -205,7 +211,9 @@ INT_PTR CALLBACK EtpGpuNodesDlgProc( // Note: This dialog must be centered after all other graphs and controls have been added. PhCenterWindow(hwndDlg, GetParent(hwndDlg)); - EtpLoadNodeBitMap(); + EtpLoadNodeBitMap(hwndDlg); + + PhRegisterCallback(&PhProcessesUpdatedEvent, ProcessesUpdatedCallback, NULL, &ProcessesUpdatedCallbackRegistration); } break; case WM_DESTROY: @@ -318,6 +326,16 @@ INT_PTR CALLBACK EtpGpuNodesDlgProc( EndDialog(hwndDlg, IDOK); } break; + case IDC_SELECTALL: + { + BOOLEAN selectAll = Button_GetCheck(GetDlgItem(hwndDlg, IDC_SELECTALL)) == BST_CHECKED; + + for (ULONG i = 0; i < EtGpuTotalNodeCount; i++) + { + Button_SetCheck(CheckBoxHandle[i], selectAll ? BST_CHECKED : BST_UNCHECKED); + } + } + break; } } break; diff --git a/plugins/ExtendedTools/resource.h b/plugins/ExtendedTools/resource.h index 94eb49f20103..3cbcf4ec25a1 100644 --- a/plugins/ExtendedTools/resource.h +++ b/plugins/ExtendedTools/resource.h @@ -58,6 +58,7 @@ #define IDC_EXAMPLE 1050 #define IDC_ENABLESYSINFOGRAPHS 1050 #define IDC_GROUPGPU 1051 +#define IDC_SELECTALL 1051 #define IDC_GROUPMEM 1052 #define IDC_GROUPSHARED 1053 #define IDC_GROUPDEDICATED 1054 From 90f12e52472f5fa915713eba0642ac490f1da1b6 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 4 Apr 2018 21:41:10 +1000 Subject: [PATCH 0871/2058] Add missing PCRE file from commit 16bedfb --- ProcessHacker/ProcessHacker.vcxproj | 1 + ProcessHacker/ProcessHacker.vcxproj.filters | 3 +++ 2 files changed, 4 insertions(+) diff --git a/ProcessHacker/ProcessHacker.vcxproj b/ProcessHacker/ProcessHacker.vcxproj index 2d60b5ef8fc8..66fadf3819d8 100644 --- a/ProcessHacker/ProcessHacker.vcxproj +++ b/ProcessHacker/ProcessHacker.vcxproj @@ -290,6 +290,7 @@ + diff --git a/ProcessHacker/ProcessHacker.vcxproj.filters b/ProcessHacker/ProcessHacker.vcxproj.filters index 550d5b2b5c2b..dbc7c34f8115 100644 --- a/ProcessHacker/ProcessHacker.vcxproj.filters +++ b/ProcessHacker/ProcessHacker.vcxproj.filters @@ -387,6 +387,9 @@ Process Hacker + + PCRE + From 689e967d8d9bb26e22c35656516c47d4bb1f1da9 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 5 Apr 2018 18:15:16 +1000 Subject: [PATCH 0872/2058] Add options imagelist --- ProcessHacker/options.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/ProcessHacker/options.c b/ProcessHacker/options.c index 2cbfa8249f06..8da5452307a8 100644 --- a/ProcessHacker/options.c +++ b/ProcessHacker/options.c @@ -146,6 +146,7 @@ static BOOLEAN CurrentUserRunPresent = FALSE; static BOOLEAN CurrentUserRunStartHidden = FALSE; static HFONT CurrentFontInstance = NULL; static PPH_STRING NewFontSelection = NULL; +static HIMAGELIST GeneralListviewImageList = NULL; // Advanced static PH_STRINGREF TaskMgrImageOptionsKeyName = PH_STRINGREF_INIT(L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\taskmgr.exe"); @@ -1058,12 +1059,13 @@ static VOID PhpAdvancedPageSave( if (!PhEqualString(PhaGetDlgItemText(hwndDlg, IDC_DBGHELPSEARCHPATH), PhaGetStringSetting(L"DbgHelpSearchPath"), TRUE)) { PhSetStringSetting2(L"DbgHelpSearchPath", &(PhaGetDlgItemText(hwndDlg, IDC_DBGHELPSEARCHPATH)->sr)); - RestartRequired = TRUE; + RestartRequired = TRUE; } SetSettingForLvItemCheck(listViewHandle, PHP_OPTIONS_INDEX_SINGLE_INSTANCE, L"AllowOnlyOneInstance"); SetSettingForLvItemCheck(listViewHandle, PHP_OPTIONS_INDEX_HIDE_WHENCLOSED, L"HideOnClose"); SetSettingForLvItemCheck(listViewHandle, PHP_OPTIONS_INDEX_HIDE_WHENMINIMIZED, L"HideOnMinimize"); + //SetSettingForLvItemCheck(listViewHandle, PHP_OPTIONS_INDEX_START_HIDDEN, L"StartHidden"); SetSettingForLvItemCheckRestartRequired(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_MINIINFO_WINDOW, L"MiniInfoWindowEnabled"); SetSettingForLvItemCheckRestartRequired(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_DRIVER, L"EnableKph"); SetSettingForLvItemCheck(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_WARNINGS, L"EnableWarnings"); @@ -1127,6 +1129,7 @@ INT_PTR CALLBACK PhpOptionsGeneralDlgProc( comboBoxHandle = GetDlgItem(hwndDlg, IDC_MAXSIZEUNIT); listviewHandle = GetDlgItem(hwndDlg, IDC_SETTINGS); + GeneralListviewImageList = ImageList_Create(2, 16, ILC_COLOR, 1, 1); PhInitializeLayoutManager(&LayoutManager, hwndDlg); PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDC_SEARCHENGINE), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); @@ -1136,7 +1139,7 @@ INT_PTR CALLBACK PhpOptionsGeneralDlgProc( PhSetListViewStyle(listviewHandle, FALSE, TRUE); ListView_SetExtendedListViewStyleEx(listviewHandle, LVS_EX_CHECKBOXES, LVS_EX_CHECKBOXES); - //ListView_SetImageList(listviewHandle, GeneralListviewImageList, LVSIL_SMALL); + ListView_SetImageList(listviewHandle, GeneralListviewImageList, LVSIL_SMALL); PhSetControlTheme(listviewHandle, L"explorer"); PhAddListViewColumn(listviewHandle, 0, 0, 0, LVCFMT_LEFT, 250, L"Name"); PhSetExtendedListView(listviewHandle); @@ -1182,6 +1185,9 @@ INT_PTR CALLBACK PhpOptionsGeneralDlgProc( if (CurrentFontInstance) DeleteObject(CurrentFontInstance); + if (GeneralListviewImageList) + ImageList_Destroy(GeneralListviewImageList); + PhClearReference(&NewFontSelection); PhClearReference(&OldTaskMgrDebugger); From eb2f2463216e90fa5cdb9559c30b8d9d307c78b8 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 5 Apr 2018 18:16:42 +1000 Subject: [PATCH 0873/2058] Update warning text --- ProcessHacker/memedit.c | 2 +- ProcessHacker/prpgenv.c | 40 ++++++++++++++++++++++++++++++++++------ 2 files changed, 35 insertions(+), 7 deletions(-) diff --git a/ProcessHacker/memedit.c b/ProcessHacker/memedit.c index e514311dd7cf..ef818d0e43d1 100644 --- a/ProcessHacker/memedit.c +++ b/ProcessHacker/memedit.c @@ -450,7 +450,7 @@ INT_PTR CALLBACK PhpMemoryEditorDlgProc( { NTSTATUS status; - if (!PhGetIntegerSetting(L"EnableWarnings") || PhShowConfirmMessage( + if (PhGetIntegerSetting(L"EnableWarnings") && !PhShowConfirmMessage( hwndDlg, L"write", L"process memory", diff --git a/ProcessHacker/prpgenv.c b/ProcessHacker/prpgenv.c index fa220acf37bb..4380e5c372d3 100644 --- a/ProcessHacker/prpgenv.c +++ b/ProcessHacker/prpgenv.c @@ -247,6 +247,17 @@ INT_PTR CALLBACK PhpProcessEnvironmentDlgProc( { BOOLEAN refresh; + if (PhGetIntegerSetting(L"EnableWarnings") && !PhShowConfirmMessage( + hwndDlg, + L"create", + L"environment variable", + L"Some programs may restrict access or ban your account when creating new environment variable(s).", + FALSE + )) + { + break; + } + if (PhpShowEditEnvDialog(hwndDlg, processItem, L"", NULL, &refresh) == IDOK && refresh) { @@ -264,6 +275,17 @@ INT_PTR CALLBACK PhpProcessEnvironmentDlgProc( PPH_ENVIRONMENT_ITEM item = PhItemArray(&environmentContext->Items, PtrToUlong(index) - 1); BOOLEAN refresh; + if (PhGetIntegerSetting(L"EnableWarnings") && !PhShowConfirmMessage( + hwndDlg, + L"edit", + L"the selected environment variable", + L"Some programs may restrict access or ban your account when editing the environment variable(s) of the process.", + FALSE + )) + { + break; + } + if (PhpShowEditEnvDialog(hwndDlg, processItem, item->Name->Buffer, item->Value->Buffer, &refresh) == IDOK && refresh) { @@ -285,13 +307,19 @@ INT_PTR CALLBACK PhpProcessEnvironmentDlgProc( PhGetSelectedListViewItemParams(lvHandle, &indices, &numberOfIndices); - if (numberOfIndices != 0 && PhShowConfirmMessage( - hwndDlg, - L"delete", - numberOfIndices != 1 ? L"the selected environment variables" : L"the selected environment variable", - NULL, - FALSE)) + if (numberOfIndices != 0) { + if (PhGetIntegerSetting(L"EnableWarnings") && !PhShowConfirmMessage( + hwndDlg, + L"delete", + numberOfIndices != 1 ? L"the selected environment variables" : L"the selected environment variable", + L"Some programs may restrict access or ban your account when editing the environment variable(s) of the process.", + FALSE + )) + { + break; + } + if (NT_SUCCESS(status = PhOpenProcess( &processHandle, ProcessQueryAccess | PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | From 1fabadb677c06150fedad08966e2a9894c0f9372 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 5 Apr 2018 18:17:10 +1000 Subject: [PATCH 0874/2058] peview: Show unknown resource types --- tools/peview/resprp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/peview/resprp.c b/tools/peview/resprp.c index 7fadaa99bdc5..928c804bab32 100644 --- a/tools/peview/resprp.c +++ b/tools/peview/resprp.c @@ -62,7 +62,8 @@ static PWSTR PvpGetResourceTypeString( return L"RT_MANIFEST"; } - return L"ERROR"; + // TODO: Some binaries include undocumented resource types. + return PhaFormatString(L"%lu", Type)->Buffer; } typedef enum _PVE_RESOURCES_COLUMN_INDEX From fa6f0edcd1a9446788a7eec1f25ae767c3d1064f Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 9 Apr 2018 19:07:09 +1000 Subject: [PATCH 0875/2058] Fix loader entry bug, Add loader entry export wrappers --- phlib/include/phutil.h | 21 ++++++ phlib/util.c | 149 ++++++++++++++++++++++++++++++++++------- 2 files changed, 144 insertions(+), 26 deletions(-) diff --git a/phlib/include/phutil.h b/phlib/include/phutil.h index f71159da9ac3..9b9c893a7b4a 100644 --- a/phlib/include/phutil.h +++ b/phlib/include/phutil.h @@ -605,6 +605,24 @@ PhGetDllFileName( _Out_opt_ PULONG IndexOfFileName ); +PHLIBAPI +PVOID +NTAPI +PhGetDllBaseProcedureAddress( + _In_ PVOID DllBase, + _In_opt_ PSTR ProcedureName, + _In_opt_ USHORT ProcedureNumber + ); + +PHLIBAPI +PVOID +NTAPI +PhGetDllProcedureAddress( + _In_ PWSTR DllEntryName, + _In_opt_ PSTR ProcedureName, + _In_opt_ USHORT ProcedureNumber + ); + PHLIBAPI PPH_STRING NTAPI @@ -1167,6 +1185,7 @@ PhGetLoaderEntryImageDirectory( _In_ PVOID BaseAddress, _In_ PIMAGE_NT_HEADERS ImageNtHeader, _In_ ULONG ImageDirectoryIndex, + _Out_ PIMAGE_DATA_DIRECTORY *ImageDataDirectoryEntry, _Out_ PVOID *ImageDirectoryEntry, _Out_opt_ SIZE_T *ImageDirectoryLength ); @@ -1187,6 +1206,8 @@ PVOID NTAPI PhGetLoaderEntryImageExportFunction( _In_ PVOID BaseAddress, + _In_ PIMAGE_NT_HEADERS ImageNtHeader, + _In_ PIMAGE_DATA_DIRECTORY DataDirectory, _In_ PIMAGE_EXPORT_DIRECTORY ExportDirectory, _In_opt_ PSTR ExportName, _In_opt_ USHORT ExportOrdinal diff --git a/phlib/util.c b/phlib/util.c index f0f295ee9800..60944715c748 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -2599,11 +2599,11 @@ NTSTATUS PhCreateProcessAsUser( HMODULE userEnv; winsta = LoadLibrary(L"winsta.dll"); - WinStationQueryInformationW_I = PhGetProcedureAddress(winsta, "WinStationQueryInformationW", 0); + WinStationQueryInformationW_I = PhGetDllBaseProcedureAddress(winsta, "WinStationQueryInformationW", 0); userEnv = LoadLibrary(L"userenv.dll"); - CreateEnvironmentBlock_I = PhGetProcedureAddress(userEnv, "CreateEnvironmentBlock", 0); - DestroyEnvironmentBlock_I = PhGetProcedureAddress(userEnv, "DestroyEnvironmentBlock", 0); + CreateEnvironmentBlock_I = PhGetDllBaseProcedureAddress(userEnv, "CreateEnvironmentBlock", 0); + DestroyEnvironmentBlock_I = PhGetDllBaseProcedureAddress(userEnv, "DestroyEnvironmentBlock", 0); PhEndInitOnce(&initOnce); } @@ -5270,7 +5270,7 @@ BOOLEAN PhExtractIcon( if (PhBeginInitOnce(&initOnce)) { if (!PrivateExtractIconExW) - PrivateExtractIconExW = PhGetModuleProcAddress(L"user32.dll", "PrivateExtractIconExW"); + PrivateExtractIconExW = PhGetDllProcedureAddress(L"user32.dll", "PrivateExtractIconExW", 0); PhEndInitOnce(&initOnce); } @@ -5381,6 +5381,57 @@ PPH_STRING PhGetDllFileName( return fileName; } +PVOID PhGetDllBaseProcedureAddress( + _In_ PVOID DllBase, + _In_opt_ PSTR ProcedureName, + _In_opt_ USHORT ProcedureNumber + ) +{ + PIMAGE_NT_HEADERS imageNtHeader; + PIMAGE_DATA_DIRECTORY dataDirectory; + PIMAGE_EXPORT_DIRECTORY exportDirectory; + + if (!NT_SUCCESS(PhGetLoaderEntryImageNtHeaders(DllBase, &imageNtHeader))) + return NULL; + + if (!NT_SUCCESS(PhGetLoaderEntryImageDirectory( + DllBase, + imageNtHeader, + IMAGE_DIRECTORY_ENTRY_EXPORT, + &dataDirectory, + &exportDirectory, + NULL + ))) + return NULL; + + return PhGetLoaderEntryImageExportFunction( + DllBase, + imageNtHeader, + dataDirectory, + exportDirectory, + ProcedureName, + ProcedureNumber + ); +} + +PVOID PhGetDllProcedureAddress( + _In_ PWSTR DllEntryName, + _In_opt_ PSTR ProcedureName, + _In_opt_ USHORT ProcedureNumber + ) +{ + PVOID dllBaseAddress; + + if (!(dllBaseAddress = PhGetLoaderEntryDllBase(DllEntryName))) + return NULL; + + return PhGetDllBaseProcedureAddress( + dllBaseAddress, + ProcedureName, + ProcedureNumber + ); +} + PVOID PhGetLoaderEntryDllBase( _In_opt_ PWSTR BaseDllName ) @@ -5445,19 +5496,21 @@ NTSTATUS PhGetLoaderEntryImageDirectory( _In_ PVOID BaseAddress, _In_ PIMAGE_NT_HEADERS ImageNtHeader, _In_ ULONG ImageDirectoryIndex, + _Out_ PIMAGE_DATA_DIRECTORY *ImageDataDirectoryEntry, _Out_ PVOID *ImageDirectoryEntry, _Out_opt_ SIZE_T *ImageDirectoryLength ) { - IMAGE_DATA_DIRECTORY directory; + PIMAGE_DATA_DIRECTORY directory; - directory = ImageNtHeader->OptionalHeader.DataDirectory[ImageDirectoryIndex]; + directory = &ImageNtHeader->OptionalHeader.DataDirectory[ImageDirectoryIndex]; - if (directory.VirtualAddress == 0 || directory.Size == 0) + if (directory->VirtualAddress == 0 || directory->Size == 0) return STATUS_INVALID_FILE_FOR_SECTION; - *ImageDirectoryEntry = PTR_ADD_OFFSET(BaseAddress, directory.VirtualAddress); - if (ImageDirectoryLength) *ImageDirectoryLength = directory.Size; + *ImageDataDirectoryEntry = directory; + *ImageDirectoryEntry = PTR_ADD_OFFSET(BaseAddress, directory->VirtualAddress); + if (ImageDirectoryLength) *ImageDirectoryLength = directory->Size; return STATUS_SUCCESS; } @@ -5501,38 +5554,82 @@ NTSTATUS PhGetLoaderEntryImageSection( } PVOID PhGetLoaderEntryImageExportFunction( - _In_ PVOID BaseAddress, + _In_ PVOID BaseAddress, + _In_ PIMAGE_NT_HEADERS ImageNtHeader, + _In_ PIMAGE_DATA_DIRECTORY DataDirectory, _In_ PIMAGE_EXPORT_DIRECTORY ExportDirectory, _In_opt_ PSTR ExportName, _In_opt_ USHORT ExportOrdinal ) { - PVOID exportFunction = NULL; + PVOID baseAddress = NULL; PULONG exportAddressTable; PULONG exportNameTable; PUSHORT exportOrdinalTable; exportAddressTable = PTR_ADD_OFFSET(BaseAddress, ExportDirectory->AddressOfFunctions); + exportNameTable = PTR_ADD_OFFSET(BaseAddress, ExportDirectory->AddressOfNames); + exportOrdinalTable = PTR_ADD_OFFSET(BaseAddress, ExportDirectory->AddressOfNameOrdinals); - if (ExportName) + if (ExportOrdinal) { - PSTR exportName; - ULONG i; + if (ExportOrdinal > ExportDirectory->Base + ExportDirectory->NumberOfFunctions) + return NULL; + + baseAddress = PTR_ADD_OFFSET(BaseAddress, exportAddressTable[ExportOrdinal - ExportDirectory->Base]); + } + else if (ExportName) + { + for (ULONG i = 0; i < ExportDirectory->NumberOfNames; i++) + { + if (PhEqualBytesZ(ExportName, PTR_ADD_OFFSET(BaseAddress, exportNameTable[i]), FALSE)) + { + baseAddress = PTR_ADD_OFFSET(BaseAddress, exportAddressTable[exportOrdinalTable[i]]); + break; + } + } + } + + if (!baseAddress) + return NULL; + + if ( + ((ULONG_PTR)baseAddress >= (ULONG_PTR)ExportDirectory) && + ((ULONG_PTR)baseAddress < (ULONG_PTR)PTR_ADD_OFFSET(ExportDirectory, DataDirectory->Size)) + ) + { + PPH_STRING dllForwarderString; + PH_STRINGREF dllNameRef; + PH_STRINGREF dllProcedureRef; - exportNameTable = PTR_ADD_OFFSET(BaseAddress, ExportDirectory->AddressOfNames); + // This is a forwarder RVA. - for (i = 0; i < ExportDirectory->NumberOfNames; i++) + dllForwarderString = PhZeroExtendToUtf16((PSTR)baseAddress); + + if (PhSplitStringRefAtChar(&dllForwarderString->sr, L'.', &dllNameRef, &dllProcedureRef)) { - exportName = PTR_ADD_OFFSET(BaseAddress, exportNameTable[i]); + PPH_STRING libraryNameString; + PPH_BYTES libraryFunctionString; + PVOID libraryModule; + + libraryNameString = PhCreateStringEx(dllNameRef.Buffer, dllNameRef.Length); + libraryFunctionString = PhConvertUtf16ToUtf8Ex(dllProcedureRef.Buffer, dllProcedureRef.Length); - if (PhEqualBytesZ(exportName, ExportName, FALSE)) + if (libraryModule = LoadLibrary(libraryNameString->Buffer)) { - exportFunction = PTR_ADD_OFFSET(BaseAddress, exportAddressTable[i + 1]); - break; + baseAddress = PhGetDllBaseProcedureAddress(libraryModule, libraryFunctionString->Buffer, 0); } + + PhDereferenceObject(libraryFunctionString); + PhDereferenceObject(libraryNameString); } + + PhDereferenceObject(dllForwarderString); } - else + + return baseAddress; +} + { exportOrdinalTable = PTR_ADD_OFFSET(BaseAddress, ExportDirectory->AddressOfNameOrdinals); @@ -5555,6 +5652,7 @@ static NTSTATUS PhpFixupLoaderEntryImageImports( NTSTATUS status; SIZE_T importDirectorySize; ULONG importDirectoryProtect; + PIMAGE_DATA_DIRECTORY dataDirectory; PIMAGE_IMPORT_DESCRIPTOR importDirectory; PIMAGE_SECTION_HEADER importDirectorySection; @@ -5562,6 +5660,7 @@ static NTSTATUS PhpFixupLoaderEntryImageImports( BaseAddress, ImageNtHeader, IMAGE_DIRECTORY_ENTRY_IMPORT, + &dataDirectory, &importDirectory, NULL ); @@ -5609,12 +5708,10 @@ static NTSTATUS PhpFixupLoaderEntryImageImports( else { PPH_STRING importNameSr; - UNICODE_STRING dllNameUs; importNameSr = PhZeroExtendToUtf16(importName); - PhStringRefToUnicodeString(&importNameSr->sr, &dllNameUs); - if (!NT_SUCCESS(status = LdrGetDllHandle(NULL, NULL, &dllNameUs, &importBaseAddress))) + if (!(importBaseAddress = PhGetLoaderEntryDllBase(importNameSr->Buffer))) { if (importBaseAddress = LoadLibrary(importNameSr->Buffer)) status = STATUS_SUCCESS; @@ -5640,7 +5737,7 @@ static NTSTATUS PhpFixupLoaderEntryImageImports( PVOID procedureAddress; procedureOrdinal = IMAGE_ORDINAL(originalThunk->u1.Ordinal); - procedureAddress = PhGetProcedureAddress(importBaseAddress, NULL, procedureOrdinal); + procedureAddress = PhGetDllBaseProcedureAddress(importBaseAddress, NULL, procedureOrdinal); if (!procedureAddress) { @@ -5657,7 +5754,7 @@ static NTSTATUS PhpFixupLoaderEntryImageImports( PVOID procedureAddress; importByName = PTR_ADD_OFFSET(BaseAddress, originalThunk->u1.AddressOfData); - procedureAddress = PhGetProcedureAddress(importBaseAddress, importByName->Name, importByName->Hint); + procedureAddress = PhGetDllBaseProcedureAddress(importBaseAddress, importByName->Name, 0); if (!procedureAddress) { From 485dad46763e0e11a1091e96dd869ac528b37b94 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 9 Apr 2018 19:08:51 +1000 Subject: [PATCH 0876/2058] Update ntpsapi types --- phnt/include/ntpsapi.h | 78 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 64 insertions(+), 14 deletions(-) diff --git a/phnt/include/ntpsapi.h b/phnt/include/ntpsapi.h index 28a083a8eedc..fe1838afa42f 100644 --- a/phnt/include/ntpsapi.h +++ b/phnt/include/ntpsapi.h @@ -105,7 +105,7 @@ typedef enum _PROCESSINFOCLASS ProcessBasePriority, // s: KPRIORITY ProcessRaisePriority, // s: ULONG ProcessDebugPort, // q: HANDLE - ProcessExceptionPort, // s: HANDLE + ProcessExceptionPort, // s: PROCESS_EXCEPTION_PORT ProcessAccessToken, // s: PROCESS_ACCESS_TOKEN ProcessLdtInformation, // qs: PROCESS_LDT_INFORMATION // 10 ProcessLdtSize, // s: PROCESS_LDT_SIZE @@ -132,12 +132,12 @@ typedef enum _PROCESSINFOCLASS ProcessHandleTracing, // q: PROCESS_HANDLE_TRACING_QUERY; s: size 0 disables, otherwise enables ProcessIoPriority, // qs: IO_PRIORITY_HINT ProcessExecuteFlags, // qs: ULONG - ProcessResourceManagement, + ProcessResourceManagement, // ProcessTlsInformation // PROCESS_TLS_INFORMATION ProcessCookie, // q: ULONG ProcessImageInformation, // q: SECTION_IMAGE_INFORMATION ProcessCycleTime, // q: PROCESS_CYCLE_TIME_INFORMATION // since VISTA - ProcessPagePriority, // q: ULONG - ProcessInstrumentationCallback, // 40 + ProcessPagePriority, // q: PAGE_PRIORITY_INFORMATION + ProcessInstrumentationCallback, // qs: PROCESS_INSTRUMENTATION_CALLBACK_INFORMATION // 40 ProcessThreadStackAllocation, // s: PROCESS_STACK_ALLOCATION_INFORMATION, PROCESS_STACK_ALLOCATION_INFORMATION_EX ProcessWorkingSetWatchEx, // q: PROCESS_WS_WATCH_INFORMATION_EX[] ProcessImageFileNameWin32, // q: UNICODE_STRING @@ -146,7 +146,7 @@ typedef enum _PROCESSINFOCLASS ProcessMemoryAllocationMode, // qs: PROCESS_MEMORY_ALLOCATION_MODE ProcessGroupInformation, // q: USHORT[] ProcessTokenVirtualizationEnabled, // s: ULONG - ProcessConsoleHostProcess, // q: ULONG_PTR + ProcessConsoleHostProcess, // q: ULONG_PTR // ProcessOwnerInformation ProcessWindowInformation, // q: PROCESS_WINDOW_INFORMATION // 50 ProcessHandleInformation, // q: PROCESS_HANDLE_SNAPSHOT_INFORMATION // since WIN8 ProcessMitigationPolicy, // s: PROCESS_MITIGATION_POLICY_INFORMATION @@ -353,6 +353,15 @@ typedef struct _POOLED_USAGE_AND_LIMITS SIZE_T PagefileLimit; } POOLED_USAGE_AND_LIMITS, *PPOOLED_USAGE_AND_LIMITS; +#define PROCESS_EXCEPTION_PORT_ALL_STATE_BITS 0x00000003 +#define PROCESS_EXCEPTION_PORT_ALL_STATE_FLAGS ((ULONG_PTR)((1UL << PROCESS_EXCEPTION_PORT_ALL_STATE_BITS) - 1)) + +typedef struct _PROCESS_EXCEPTION_PORT +{ + _In_ HANDLE ExceptionPortHandle; // Handle to the exception port. No particular access required. + _Inout_ ULONG StateFlags; // Miscellaneous state flags to be cached along with the exception port in the kernel. +} PROCESS_EXCEPTION_PORT, *PPROCESS_EXCEPTION_PORT; + typedef struct _PROCESS_ACCESS_TOKEN { HANDLE Token; // needs TOKEN_ASSIGN_PRIMARY access @@ -448,6 +457,8 @@ typedef struct _PROCESS_SESSION_INFORMATION ULONG SessionId; } PROCESS_SESSION_INFORMATION, *PPROCESS_SESSION_INFORMATION; +#define PROCESS_HANDLE_EXCEPTIONS_ENABLED 0x00000001 + #define PROCESS_HANDLE_RAISE_EXCEPTION_ON_INVALID_HANDLE_CLOSE_DISABLED 0x00000000 #define PROCESS_HANDLE_RAISE_EXCEPTION_ON_INVALID_HANDLE_CLOSE_ENABLED 0x00000001 @@ -487,6 +498,42 @@ typedef struct _PROCESS_HANDLE_TRACING_QUERY #endif +// private +typedef struct _THREAD_TLS_INFORMATION +{ + ULONG Flags; + PVOID NewTlsData; + PVOID OldTlsData; + HANDLE ThreadId; +} THREAD_TLS_INFORMATION, *PTHREAD_TLS_INFORMATION; + +// private +typedef enum _PROCESS_TLS_INFORMATION_TYPE +{ + ProcessTlsReplaceIndex, + ProcessTlsReplaceVector, + MaxProcessTlsOperation +} PROCESS_TLS_INFORMATION_TYPE, *PPROCESS_TLS_INFORMATION_TYPE; + +// private +typedef struct _PROCESS_TLS_INFORMATION +{ + ULONG Flags; + ULONG OperationType; + ULONG ThreadDataCount; + ULONG TlsIndex; + ULONG PreviousCount; + THREAD_TLS_INFORMATION ThreadData[1]; +} PROCESS_TLS_INFORMATION, *PPROCESS_TLS_INFORMATION; + +// private +typedef struct _PROCESS_INSTRUMENTATION_CALLBACK_INFORMATION +{ + ULONG Version; + ULONG Reserved; + PVOID Callback; +} PROCESS_INSTRUMENTATION_CALLBACK_INFORMATION, *PPROCESS_INSTRUMENTATION_CALLBACK_INFORMATION; + // private typedef struct _PROCESS_STACK_ALLOCATION_INFORMATION { @@ -757,17 +804,19 @@ typedef struct _MANAGE_WRITES_TO_EXECUTABLE_MEMORY ULONG Spare : 22; } MANAGE_WRITES_TO_EXECUTABLE_MEMORY, *PMANAGE_WRITES_TO_EXECUTABLE_MEMORY; -typedef struct _PROCESS_READWRITEVM_LOGGING_INFORMATION +#define PROCESS_READWRITEVM_LOGGING_ENABLE_READVM 1 +#define PROCESS_READWRITEVM_LOGGING_ENABLE_WRITEVM 2 +#define PROCESS_READWRITEVM_LOGGING_ENABLE_READVM_V 1UL +#define PROCESS_READWRITEVM_LOGGING_ENABLE_WRITEVM_V 2UL + +typedef union _PROCESS_READWRITEVM_LOGGING_INFORMATION { - union + UCHAR Flags; + struct { - BOOLEAN Flags; - struct - { - BOOLEAN EnableReadVmLogging : 1; - BOOLEAN EnableWriteVmLogging : 1; - BOOLEAN Unused : 6; - }; + UCHAR EnableReadVmLogging : 1; + UCHAR EnableWriteVmLogging : 1; + UCHAR Unused : 6; }; } PROCESS_READWRITEVM_LOGGING_INFORMATION, *PPROCESS_READWRITEVM_LOGGING_INFORMATION; @@ -1008,6 +1057,7 @@ NtResumeProcess( #define NtCurrentProcessToken() ((HANDLE)(LONG_PTR)-4) #define NtCurrentThreadToken() ((HANDLE)(LONG_PTR)-5) #define NtCurrentEffectiveToken() ((HANDLE)(LONG_PTR)-6) +#define NtCurrentSilo() ((HANDLE)(LONG_PTR)-1) // Not NT, but useful. #define NtCurrentProcessId() (NtCurrentTeb()->ClientId.UniqueProcess) From a57c091e8268aaee1ba666bf481026e00683fdce Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 9 Apr 2018 19:10:42 +1000 Subject: [PATCH 0877/2058] Fix PhCreateProcessIgnoreIfeoDebugger thread safety issues --- ProcessHacker/appsup.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ProcessHacker/appsup.c b/ProcessHacker/appsup.c index 222d73b93133..483d51ce3ed0 100644 --- a/ProcessHacker/appsup.c +++ b/ProcessHacker/appsup.c @@ -1341,9 +1341,10 @@ BOOLEAN PhCreateProcessIgnoreIfeoDebugger( result = FALSE; - // This is NOT thread-safe. + RtlEnterCriticalSection(NtCurrentPeb()->FastPebLock); originalValue = NtCurrentPeb()->ReadImageFileExecOptions; NtCurrentPeb()->ReadImageFileExecOptions = FALSE; + RtlLeaveCriticalSection(NtCurrentPeb()->FastPebLock); memset(&startupInfo, 0, sizeof(STARTUPINFO)); startupInfo.cb = sizeof(STARTUPINFO); @@ -1364,7 +1365,9 @@ BOOLEAN PhCreateProcessIgnoreIfeoDebugger( if (processInfo.hThread) NtClose(processInfo.hThread); + RtlEnterCriticalSection(NtCurrentPeb()->FastPebLock); NtCurrentPeb()->ReadImageFileExecOptions = originalValue; + RtlLeaveCriticalSection(NtCurrentPeb()->FastPebLock); return result; } From 4cbbd470bc242a2c3a4eec6d2a1448ab0a9cd532 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 9 Apr 2018 19:16:03 +1000 Subject: [PATCH 0878/2058] Fix module name, Add PhGetAppContainerSidFromName wrapper --- phlib/appresolver.c | 42 ++++++++++++++++++++++++++++-------- phlib/include/appresolver.h | 4 ++++ phlib/include/appresolverp.h | 13 +++++++---- 3 files changed, 46 insertions(+), 13 deletions(-) diff --git a/phlib/appresolver.c b/phlib/appresolver.c index 65d72d8d8c8a..6052531ba1d0 100644 --- a/phlib/appresolver.c +++ b/phlib/appresolver.c @@ -80,24 +80,25 @@ static BOOLEAN PhpKernelAppCoreInitialized( { static PH_INITONCE initOnce = PH_INITONCE_INIT; static BOOLEAN kernelAppCoreInitialized = FALSE; - + if (PhBeginInitOnce(&initOnce)) { if (WindowsVersion >= WINDOWS_8) { - PVOID kernelAppBaseAddress; + PVOID kernelBaseModuleHandle; - if (kernelAppBaseAddress = LoadLibrary(L"kernel.appcore.dll")) + if (kernelBaseModuleHandle = LoadLibrary(L"kernelbase.dll")) // kernel.appcore.dll { - AppContainerLookupMoniker_I = PhGetProcedureAddress(kernelAppBaseAddress, "AppContainerLookupMoniker", 0); - AppContainerFreeMemory_I = PhGetProcedureAddress(kernelAppBaseAddress, "AppContainerFreeMemory", 0); - AppContainerRegisterSid_I = PhGetProcedureAddress(kernelAppBaseAddress, "AppContainerRegisterSid", 0); - AppContainerUnregisterSid_I = PhGetProcedureAddress(kernelAppBaseAddress, "AppContainerUnregisterSid", 0); - - AppPolicyGetWindowingModel_I = PhGetProcedureAddress(kernelAppBaseAddress, "AppPolicyGetWindowingModel", 0); + AppContainerDeriveSidFromMoniker_I = PhGetDllBaseProcedureAddress(kernelBaseModuleHandle, "AppContainerDeriveSidFromMoniker", 0); + AppContainerLookupMoniker_I = PhGetDllBaseProcedureAddress(kernelBaseModuleHandle, "AppContainerLookupMoniker", 0); + AppContainerFreeMemory_I = PhGetDllBaseProcedureAddress(kernelBaseModuleHandle, "AppContainerFreeMemory", 0); + AppContainerRegisterSid_I = PhGetDllBaseProcedureAddress(kernelBaseModuleHandle, "AppContainerRegisterSid", 0); + AppContainerUnregisterSid_I = PhGetDllBaseProcedureAddress(kernelBaseModuleHandle, "AppContainerUnregisterSid", 0); + AppPolicyGetWindowingModel_I = PhGetDllBaseProcedureAddress(kernelBaseModuleHandle, "AppPolicyGetWindowingModel", 0); } if ( + AppContainerDeriveSidFromMoniker_I && AppContainerLookupMoniker_I && AppContainerFreeMemory_I && AppContainerRegisterSid_I && @@ -230,6 +231,29 @@ PPH_STRING PhGetAppContainerName( return appContainerName; } +PPH_STRING PhGetAppContainerSidFromName( + _In_ PWSTR AppContainerName + ) +{ + PSID appContainerSid; + PPH_STRING packageSidString = NULL; + + if (!PhpKernelAppCoreInitialized()) + return NULL; + + if (SUCCEEDED(AppContainerDeriveSidFromMoniker_I( + AppContainerName, + &appContainerSid + ))) + { + packageSidString = PhSidToStringSid(appContainerSid); + + RtlFreeSid(appContainerSid); + } + + return packageSidString; +} + PPH_STRING PhGetAppContainerPackageName( _In_ PSID Sid ) diff --git a/phlib/include/appresolver.h b/phlib/include/appresolver.h index 85c2f6d3e81e..aa0c310f5909 100644 --- a/phlib/include/appresolver.h +++ b/phlib/include/appresolver.h @@ -42,6 +42,10 @@ PPH_STRING PhGetAppContainerName( _In_ PSID AppContainerSid ); +PPH_STRING PhGetAppContainerSidFromName( + _In_ PWSTR AppContainerName + ); + PPH_STRING PhGetAppContainerPackageName( _In_ PSID Sid ); diff --git a/phlib/include/appresolverp.h b/phlib/include/appresolverp.h index 4654c30abfe4..790cb406a8f0 100644 --- a/phlib/include/appresolverp.h +++ b/phlib/include/appresolverp.h @@ -43,25 +43,30 @@ static IID IID_IResourceContext_I = { 0xE3C22B30, 0x8502, 0x4B2F,{ 0x91, 0x33, 0 // "6E21E72B-B9B0-42AE-A686-983CF784EDCD" static IID IID_IResourceMap_I = { 0x6E21E72B, 0xB9B0, 0x42AE,{ 0xA6, 0x86, 0x98, 0x3C, 0xF7, 0x84, 0xED, 0xCD } }; -//static HRESULT (WINAPI* AppContainerDeriveSidFromMoniker_I)( // DeriveAppContainerSidFromAppContainerName -// _In_ PCWSTR AppContainerName, -// _Out_ PSID *AppContainerSid -// ) = NULL; +static HRESULT (WINAPI* AppContainerDeriveSidFromMoniker_I)( // DeriveAppContainerSidFromAppContainerName + _In_ PCWSTR AppContainerName, + _Out_ PSID *AppContainerSid + ) = NULL; + static HRESULT (WINAPI* AppContainerLookupMoniker_I)( _In_ PSID AppContainerSid, _Out_ PWSTR *PackageFamilyName ) = NULL; + static HRESULT (WINAPI* AppContainerRegisterSid_I)( _In_ PSID Sid, _In_ PCWSTR AppContainerName, _In_ PCWSTR DisplayName ) = NULL; + static HRESULT (WINAPI* AppContainerUnregisterSid_I)( _In_ PSID Sid ) = NULL; + static BOOL (WINAPI* AppContainerFreeMemory_I)( _Frees_ptr_opt_ PVOID Memory ) = NULL; + static HRESULT (WINAPI* AppPolicyGetWindowingModel_I)( _In_ HANDLE ProcessTokenHandle, _Out_ AppPolicyWindowingModel *ProcessWindowingModelPolicy From 239e46e6543014270aad00999e37aa6579cbd9a0 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 9 Apr 2018 19:19:02 +1000 Subject: [PATCH 0879/2058] Update ntrtl.h (Add RtlGetNtSystemRoot prototype) --- phnt/include/ntrtl.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/phnt/include/ntrtl.h b/phnt/include/ntrtl.h index 3c480d565934..c930b0afb92a 100644 --- a/phnt/include/ntrtl.h +++ b/phnt/include/ntrtl.h @@ -3236,6 +3236,15 @@ RtlDoesFileExists_U( _In_ PWSTR FileName ); +#if (PHNT_VERSION >= PHNT_REDSTONE2) +NTSYSAPI +PCWSTR +NTAPI +RtlGetNtSystemRoot( + VOID + ); +#endif + // Heaps typedef struct _RTL_HEAP_ENTRY From 042f07e60da0776128938d9258fba89185317188 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 9 Apr 2018 23:28:00 +1000 Subject: [PATCH 0880/2058] Fix commit fa6f0ed --- phlib/util.c | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/phlib/util.c b/phlib/util.c index 60944715c748..86f9f17d2f35 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -5630,20 +5630,6 @@ PVOID PhGetLoaderEntryImageExportFunction( return baseAddress; } - { - exportOrdinalTable = PTR_ADD_OFFSET(BaseAddress, ExportDirectory->AddressOfNameOrdinals); - - // TODO: Validate exportFunction and exportAddressTable are located within the image range. - // HACK: I'm not sure which value we're supposed to -1 because the PE spec omits details about OrdinalBase... so just -1 the entire result. (dmex) - exportFunction = PTR_ADD_OFFSET(BaseAddress, exportAddressTable[exportOrdinalTable[ExportOrdinal] - ExportDirectory->Base - 1]); - - //PULONG exportNameTable = PTR_ADD_OFFSET(BaseAddress, ExportDirectory->AddressOfNames); - //PSTR exportName = PTR_ADD_OFFSET(BaseAddress, exportNameTable[exportOrdinalTable[ExportOrdinal] - ExportDirectory->Base - 2]); - } - - return exportFunction; -} - static NTSTATUS PhpFixupLoaderEntryImageImports( _In_ PVOID BaseAddress, _In_ PIMAGE_NT_HEADERS ImageNtHeader From e69b08e63fdd5f9ef5f4716c7b11b1a3b4087d3a Mon Sep 17 00:00:00 2001 From: diversenok <30962924+diversenok@users.noreply.github.com> Date: Mon, 9 Apr 2018 19:35:32 +0300 Subject: [PATCH 0881/2058] Race condition fix (#254) --- ProcessHacker/appsup.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/ProcessHacker/appsup.c b/ProcessHacker/appsup.c index 483d51ce3ed0..e447263dc45b 100644 --- a/ProcessHacker/appsup.c +++ b/ProcessHacker/appsup.c @@ -1364,10 +1364,13 @@ BOOLEAN PhCreateProcessIgnoreIfeoDebugger( NtClose(processInfo.hProcess); if (processInfo.hThread) NtClose(processInfo.hThread); - - RtlEnterCriticalSection(NtCurrentPeb()->FastPebLock); - NtCurrentPeb()->ReadImageFileExecOptions = originalValue; - RtlLeaveCriticalSection(NtCurrentPeb()->FastPebLock); + + if (originalValue) + { + RtlEnterCriticalSection(NtCurrentPeb()->FastPebLock); + NtCurrentPeb()->ReadImageFileExecOptions = originalValue; + RtlLeaveCriticalSection(NtCurrentPeb()->FastPebLock); + } return result; } From 8c73e80002902489dd7ffd5ed56a86017f2d64e0 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 10 Apr 2018 18:09:02 +1000 Subject: [PATCH 0882/2058] Add workaround for token container name --- ProcessHacker/tokprp.c | 2 +- phlib/appresolver.c | 6 ++++-- phlib/include/appresolver.h | 3 ++- phlib/secedit.c | 2 +- 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/ProcessHacker/tokprp.c b/ProcessHacker/tokprp.c index 0b09b993f8ed..0010fee5f69c 100644 --- a/ProcessHacker/tokprp.c +++ b/ProcessHacker/tokprp.c @@ -660,7 +660,7 @@ INT_PTR CALLBACK PhpTokenPageProc( { if (appContainerInfo->TokenAppContainer) { - appContainerName = PhGetAppContainerName(appContainerInfo->TokenAppContainer); + appContainerName = PhGetAppContainerName(appContainerInfo->TokenAppContainer, TRUE); appContainerSid = PhSidToStringSid(appContainerInfo->TokenAppContainer); } diff --git a/phlib/appresolver.c b/phlib/appresolver.c index 6052531ba1d0..fc0c3cacf8bb 100644 --- a/phlib/appresolver.c +++ b/phlib/appresolver.c @@ -200,7 +200,8 @@ HRESULT PhAppResolverActivateAppId( } PPH_STRING PhGetAppContainerName( - _In_ PSID AppContainerSid + _In_ PSID AppContainerSid, + _In_ BOOLEAN TokenPageHack ) { HRESULT result; @@ -225,7 +226,8 @@ PPH_STRING PhGetAppContainerName( // NOTE: The AppContainerLookupMoniker function is not able to lookup the appcontainer names created using the // CreateAppContainerProfile function from Win32 desktop applications (e.g. Google Chrome). // HACK: Return the error message until the above bug is fixed or have a better workaround -dmex - appContainerName = PhGetStatusMessage(0, HRESULT_CODE(result)); + if (!TokenPageHack) + appContainerName = PhGetStatusMessage(0, HRESULT_CODE(result)); } return appContainerName; diff --git a/phlib/include/appresolver.h b/phlib/include/appresolver.h index aa0c310f5909..70094fafb8be 100644 --- a/phlib/include/appresolver.h +++ b/phlib/include/appresolver.h @@ -39,7 +39,8 @@ HRESULT PhAppResolverActivateAppId( ); PPH_STRING PhGetAppContainerName( - _In_ PSID AppContainerSid + _In_ PSID AppContainerSid, + _In_ BOOLEAN TokenPageHack ); PPH_STRING PhGetAppContainerSidFromName( diff --git a/phlib/secedit.c b/phlib/secedit.c index be964c0fe2fa..276a26557637 100644 --- a/phlib/secedit.c +++ b/phlib/secedit.c @@ -567,7 +567,7 @@ HRESULT STDMETHODCALLTYPE PhSecurityDataObject_GetData( sidInfo.pwzCommonName = PhGetString(sidString); PhAddItemList(this->NameCache, sidString); } - else if (sidString = PhGetAppContainerName(sidInfo.pSid)) + else if (sidString = PhGetAppContainerName(sidInfo.pSid, FALSE)) { PhMoveReference(&sidString, PhFormatString(L"%s (APP_CONTAINER)", PhGetString(sidString))); sidInfo.pwzCommonName = PhGetString(sidString); From b0a392672d4c2489921dcc656be0f118e283296f Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 10 Apr 2018 18:11:23 +1000 Subject: [PATCH 0883/2058] HardwareDevices: Reduce network adapter guid allocations --- plugins/HardwareDevices/adapter.c | 4 +++- plugins/HardwareDevices/devices.h | 3 ++- plugins/HardwareDevices/ndis.c | 4 ++-- plugins/HardwareDevices/netdetails.c | 2 +- plugins/HardwareDevices/netgraph.c | 2 +- plugins/HardwareDevices/netoptions.c | 6 +++++- 6 files changed, 14 insertions(+), 7 deletions(-) diff --git a/plugins/HardwareDevices/adapter.c b/plugins/HardwareDevices/adapter.c index 2011a31b07a5..4cd3c0daf0c8 100644 --- a/plugins/HardwareDevices/adapter.c +++ b/plugins/HardwareDevices/adapter.c @@ -74,7 +74,7 @@ VOID NetAdaptersUpdate( if (PhGetIntegerSetting(SETTING_NAME_ENABLE_NDIS)) { - if (NT_SUCCESS(NetworkAdapterCreateHandle(&deviceHandle, entry->Id.InterfaceGuid))) + if (NT_SUCCESS(NetworkAdapterCreateHandle(&deviceHandle, entry->Id.InterfaceDevice))) { if (!entry->CheckedDeviceSupport) { @@ -204,6 +204,7 @@ VOID InitializeNetAdapterId( Id->InterfaceIndex = InterfaceIndex; Id->InterfaceLuid = InterfaceLuid; PhSetReference(&Id->InterfaceGuid, InterfaceGuid); + Id->InterfaceDevice = PhConcatStrings2(L"\\\\.\\", InterfaceGuid->Buffer); } VOID CopyNetAdapterId( @@ -224,6 +225,7 @@ VOID DeleteNetAdapterId( ) { PhClearReference(&Id->InterfaceGuid); + PhClearReference(&Id->InterfaceDevice); } BOOLEAN EquivalentNetAdapterId( diff --git a/plugins/HardwareDevices/devices.h b/plugins/HardwareDevices/devices.h index 1c415a429d92..c5fd9a1d1753 100644 --- a/plugins/HardwareDevices/devices.h +++ b/plugins/HardwareDevices/devices.h @@ -101,6 +101,7 @@ typedef struct _DV_NETADAPTER_ID NET_IFINDEX InterfaceIndex; IF_LUID InterfaceLuid; PPH_STRING InterfaceGuid; + PPH_STRING InterfaceDevice; } DV_NETADAPTER_ID, *PDV_NETADAPTER_ID; typedef struct _DV_NETADAPTER_ENTRY @@ -306,7 +307,7 @@ typedef ULONG (WINAPI* _GetInterfaceDescriptionFromGuid)( NTSTATUS NetworkAdapterCreateHandle( _Out_ PHANDLE DeviceHandle, - _In_ PPH_STRING InterfaceGuid + _In_ PPH_STRING InterfaceDevice ); BOOLEAN NetworkAdapterQuerySupported( diff --git a/plugins/HardwareDevices/ndis.c b/plugins/HardwareDevices/ndis.c index 78f19832481f..c90fcd4bda11 100644 --- a/plugins/HardwareDevices/ndis.c +++ b/plugins/HardwareDevices/ndis.c @@ -28,12 +28,12 @@ _GetInterfaceDescriptionFromGuid GetInterfaceDescriptionFromGuid_I = NULL; NTSTATUS NetworkAdapterCreateHandle( _Out_ PHANDLE DeviceHandle, - _In_ PPH_STRING InterfaceGuid + _In_ PPH_STRING InterfaceDevice ) { return PhCreateFileWin32( DeviceHandle, - PhaConcatStrings(2, L"\\\\.\\", InterfaceGuid->Buffer)->Buffer, + PhGetString(InterfaceDevice), FILE_GENERIC_READ, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE, diff --git a/plugins/HardwareDevices/netdetails.c b/plugins/HardwareDevices/netdetails.c index 491deee744cb..1485bbcad47d 100644 --- a/plugins/HardwareDevices/netdetails.c +++ b/plugins/HardwareDevices/netdetails.c @@ -353,7 +353,7 @@ VOID NetAdapterUpdateDetails( if (PhGetIntegerSetting(SETTING_NAME_ENABLE_NDIS)) { - if (NT_SUCCESS(NetworkAdapterCreateHandle(&deviceHandle, Context->AdapterId.InterfaceGuid))) + if (NT_SUCCESS(NetworkAdapterCreateHandle(&deviceHandle, Context->AdapterId.InterfaceDevice))) { if (!Context->CheckedDeviceSupport) { diff --git a/plugins/HardwareDevices/netgraph.c b/plugins/HardwareDevices/netgraph.c index 12b53cba95b2..95b1545e2a02 100644 --- a/plugins/HardwareDevices/netgraph.c +++ b/plugins/HardwareDevices/netgraph.c @@ -48,7 +48,7 @@ VOID NetAdapterUpdatePanel( if (PhGetIntegerSetting(SETTING_NAME_ENABLE_NDIS)) { // Create the handle to the network device - if (NT_SUCCESS(NetworkAdapterCreateHandle(&deviceHandle, Context->AdapterEntry->Id.InterfaceGuid))) + if (NT_SUCCESS(NetworkAdapterCreateHandle(&deviceHandle, Context->AdapterEntry->Id.InterfaceDevice))) { if (!Context->AdapterEntry->CheckedDeviceSupport) { diff --git a/plugins/HardwareDevices/netoptions.c b/plugins/HardwareDevices/netoptions.c index c6c82890e62b..ef95f4cee8ad 100644 --- a/plugins/HardwareDevices/netoptions.c +++ b/plugins/HardwareDevices/netoptions.c @@ -32,6 +32,7 @@ typedef struct _NET_ENUM_ENTRY IF_LUID DeviceLuid; PPH_STRING DeviceGuid; PPH_STRING DeviceName; + PPH_STRING DeviceInterface; } NET_ENUM_ENTRY, *PNET_ENUM_ENTRY; static int __cdecl AdapterEntryCompareFunction( @@ -435,10 +436,11 @@ VOID FindNetworkAdapters( memset(adapterEntry, 0, sizeof(NET_ENUM_ENTRY)); adapterEntry->DeviceGuid = PhQueryRegistryString(keyHandle, L"NetCfgInstanceId"); + adapterEntry->DeviceInterface = PhConcatStrings2(L"\\\\.\\", adapterEntry->DeviceGuid->Buffer); adapterEntry->DeviceLuid.Info.IfType = QueryRegistryUlong64(keyHandle, L"*IfType"); adapterEntry->DeviceLuid.Info.NetLuidIndex = QueryRegistryUlong64(keyHandle, L"NetLuidIndex"); - if (NT_SUCCESS(NetworkAdapterCreateHandle(&deviceHandle, adapterEntry->DeviceGuid))) + if (NT_SUCCESS(NetworkAdapterCreateHandle(&deviceHandle, adapterEntry->DeviceInterface))) { PPH_STRING adapterName; @@ -484,6 +486,8 @@ VOID FindNetworkAdapters( if (entry->DeviceName) PhDereferenceObject(entry->DeviceName); + if (entry->DeviceInterface) + PhDereferenceObject(entry->DeviceInterface); // Note: DeviceGuid is disposed by WM_DESTROY. PhFree(entry); From d7c753db0ac381ed87e232ce0633364878499449 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 10 Apr 2018 18:15:18 +1000 Subject: [PATCH 0884/2058] Fix typo --- plugins/HardwareDevices/devices.h | 2 +- plugins/HardwareDevices/ndis.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/HardwareDevices/devices.h b/plugins/HardwareDevices/devices.h index c5fd9a1d1753..d4b8cc9923b1 100644 --- a/plugins/HardwareDevices/devices.h +++ b/plugins/HardwareDevices/devices.h @@ -307,7 +307,7 @@ typedef ULONG (WINAPI* _GetInterfaceDescriptionFromGuid)( NTSTATUS NetworkAdapterCreateHandle( _Out_ PHANDLE DeviceHandle, - _In_ PPH_STRING InterfaceDevice + _In_ PPH_STRING DeviceInterface ); BOOLEAN NetworkAdapterQuerySupported( diff --git a/plugins/HardwareDevices/ndis.c b/plugins/HardwareDevices/ndis.c index c90fcd4bda11..59909af53787 100644 --- a/plugins/HardwareDevices/ndis.c +++ b/plugins/HardwareDevices/ndis.c @@ -28,12 +28,12 @@ _GetInterfaceDescriptionFromGuid GetInterfaceDescriptionFromGuid_I = NULL; NTSTATUS NetworkAdapterCreateHandle( _Out_ PHANDLE DeviceHandle, - _In_ PPH_STRING InterfaceDevice + _In_ PPH_STRING DeviceInterface ) { return PhCreateFileWin32( DeviceHandle, - PhGetString(InterfaceDevice), + PhGetString(DeviceInterface), FILE_GENERIC_READ, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE, From 00a9f41cce6833fc0bac3c8f8e167e226e329af7 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 10 Apr 2018 19:12:48 +1000 Subject: [PATCH 0885/2058] Update PhGetModuleProcAddress --- ProcessHacker/actions.c | 8 ++--- ProcessHacker/anawait.c | 4 +-- ProcessHacker/appsup.c | 4 +-- ProcessHacker/dbgcon.c | 2 +- ProcessHacker/main.c | 2 +- ProcessHacker/mainwnd.c | 2 +- ProcessHacker/miniinfo.c | 2 +- ProcessHacker/phsvc/svcapi.c | 2 +- ProcessHacker/proctree.c | 2 +- ProcessHacker/runas.c | 12 ++++---- ProcessHacker/srvprv.c | 4 +-- ProcessHacker/sysscmem.c | 2 +- phlib/guisup.c | 6 ++-- phlib/include/phutil.h | 18 +++++++++++ phlib/native.c | 2 +- phlib/svcsup.c | 4 +-- phlib/symprv.c | 58 ++++++++++++++++++------------------ phlib/util.c | 8 ++--- 18 files changed, 80 insertions(+), 62 deletions(-) diff --git a/ProcessHacker/actions.c b/ProcessHacker/actions.c index 2bf2255b07ca..d6190f3eebfe 100644 --- a/ProcessHacker/actions.c +++ b/ProcessHacker/actions.c @@ -2153,7 +2153,7 @@ BOOLEAN PhUiCloseConnections( _SetTcpEntry SetTcpEntry_I; MIB_TCPROW tcpRow; - SetTcpEntry_I = PhGetModuleProcAddress(L"iphlpapi.dll", "SetTcpEntry"); + SetTcpEntry_I = PhGetDllProcedureAddress(L"iphlpapi.dll", "SetTcpEntry", 0); if (!SetTcpEntry_I) { @@ -2801,18 +2801,18 @@ BOOLEAN PhUiFreeMemory( if (Free) { verb = L"free"; - message = L"Freeing memory regions may cause the process to crash."; + message = L"Freeing memory regions may cause the process to crash.\r\n\r\nSome programs may also restrict access or ban your account when freeing the memory of the process."; } else { verb = L"decommit"; - message = L"Decommitting memory regions may cause the process to crash."; + message = L"Decommitting memory regions may cause the process to crash.\r\n\r\nSome programs may also restrict access or ban your account when decommitting the memory of the process."; } } else { verb = L"unmap"; - message = L"Unmapping a section view may cause the process to crash."; + message = L"Unmapping a section view may cause the process to crash.\r\n\r\nSome programs may also restrict access or ban your account when unmapping the memory of the process."; } cont = PhShowConfirmMessage( diff --git a/ProcessHacker/anawait.c b/ProcessHacker/anawait.c index 354a61b29636..e78569c7cd41 100644 --- a/ProcessHacker/anawait.c +++ b/ProcessHacker/anawait.c @@ -984,7 +984,7 @@ static PPH_STRING PhpaGetSendMessageReceiver( // is sending a message to. if (!GetSendMessageReceiver_I) - GetSendMessageReceiver_I = PhGetModuleProcAddress(L"user32.dll", "GetSendMessageReceiver"); + GetSendMessageReceiver_I = PhGetDllProcedureAddress(L"user32.dll", "GetSendMessageReceiver", 0); if (!GetSendMessageReceiver_I) return NULL; @@ -1021,7 +1021,7 @@ static PPH_STRING PhpaGetAlpcInformation( ULONG bufferLength; if (!NtAlpcQueryInformation_I) - NtAlpcQueryInformation_I = PhGetModuleProcAddress(L"ntdll.dll", "NtAlpcQueryInformation"); + NtAlpcQueryInformation_I = PhGetDllProcedureAddress(L"ntdll.dll", "NtAlpcQueryInformation", 0); if (!NtAlpcQueryInformation_I) return NULL; diff --git a/ProcessHacker/appsup.c b/ProcessHacker/appsup.c index e447263dc45b..00dd278ed0ff 100644 --- a/ProcessHacker/appsup.c +++ b/ProcessHacker/appsup.c @@ -1335,8 +1335,8 @@ BOOLEAN PhCreateProcessIgnoreIfeoDebugger( STARTUPINFO startupInfo; PROCESS_INFORMATION processInfo; - if (!(debugSetProcessKillOnExit = PhGetModuleProcAddress(L"kernel32.dll", "DebugSetProcessKillOnExit")) || - !(debugActiveProcessStop = PhGetModuleProcAddress(L"kernel32.dll", "DebugActiveProcessStop"))) + if (!(debugSetProcessKillOnExit = PhGetDllProcedureAddress(L"kernel32.dll", "DebugSetProcessKillOnExit", 0)) || + !(debugActiveProcessStop = PhGetDllProcedureAddress(L"kernel32.dll", "DebugActiveProcessStop", 0))) return FALSE; result = FALSE; diff --git a/ProcessHacker/dbgcon.c b/ProcessHacker/dbgcon.c index bcd6cab3ae10..d74807964979 100644 --- a/ProcessHacker/dbgcon.c +++ b/ProcessHacker/dbgcon.c @@ -1567,7 +1567,7 @@ NTSTATUS PhpDebugConsoleThreadStart( VOID (NTAPI *rtlDetectHeapLeaks)(VOID); PWSTR options = wcstok_s(NULL, delims, &context); - rtlDetectHeapLeaks = PhGetModuleProcAddress(L"ntdll.dll", "RtlDetectHeapLeaks"); + rtlDetectHeapLeaks = PhGetDllProcedureAddress(L"ntdll.dll", "RtlDetectHeapLeaks", 0); if (!(NtCurrentPeb()->NtGlobalFlag & FLG_USER_STACK_TRACE_DB)) { diff --git a/ProcessHacker/main.c b/ProcessHacker/main.c index e6e423cb924c..95331d4083b2 100644 --- a/ProcessHacker/main.c +++ b/ProcessHacker/main.c @@ -652,7 +652,7 @@ BOOLEAN PhInitializeMitigationPolicy( if (PhEndsWithStringRef(&commandlineSr, &commandlinePart, FALSE)) return TRUE; - if (!(LdrSystemDllInitBlock_I = PhGetModuleProcAddress(L"ntdll.dll", "LdrSystemDllInitBlock"))) + if (!(LdrSystemDllInitBlock_I = PhGetDllProcedureAddress(L"ntdll.dll", "LdrSystemDllInitBlock", 0))) goto CleanupExit; if (!RTL_CONTAINS_FIELD(LdrSystemDllInitBlock_I, LdrSystemDllInitBlock_I->Size, MitigationOptionsMap)) diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index d03d2cc0718b..0b27413b4311 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -1767,7 +1767,7 @@ BOOLEAN PhMwpOnNotify( if (WdcLibraryHandle = LoadLibrary(L"wdc.dll")) { - if (WdcRunTaskAsInteractiveUser_I = PhGetProcedureAddress(WdcLibraryHandle, "WdcRunTaskAsInteractiveUser", 0)) + if (WdcRunTaskAsInteractiveUser_I = PhGetDllBaseProcedureAddress(WdcLibraryHandle, "WdcRunTaskAsInteractiveUser", 0)) { PH_STRINGREF string; PPH_STRING commandlineString; diff --git a/ProcessHacker/miniinfo.c b/ProcessHacker/miniinfo.c index 4208da0cfc09..26c0bb793dfd 100644 --- a/ProcessHacker/miniinfo.c +++ b/ProcessHacker/miniinfo.c @@ -1453,7 +1453,7 @@ PPH_MIP_GROUP_NODE PhMipAddGroupNode( if (node->RepresentativeIsHung) { if (!HungWindowFromGhostWindow_I) - HungWindowFromGhostWindow_I = PhGetModuleProcAddress(L"user32.dll", "HungWindowFromGhostWindow"); + HungWindowFromGhostWindow_I = PhGetDllProcedureAddress(L"user32.dll", "HungWindowFromGhostWindow", 0); // Make sure this is a real hung window, not a ghost window. if (HungWindowFromGhostWindow_I && HungWindowFromGhostWindow_I(ProcessGroup->WindowHandle)) diff --git a/ProcessHacker/phsvc/svcapi.c b/ProcessHacker/phsvc/svcapi.c index e649469d03d6..ee88d2632758 100644 --- a/ProcessHacker/phsvc/svcapi.c +++ b/ProcessHacker/phsvc/svcapi.c @@ -1131,7 +1131,7 @@ NTSTATUS PhSvcApiSetTcpEntry( if (iphlpapiModule) { - localSetTcpEntry = PhGetProcedureAddress(iphlpapiModule, "SetTcpEntry", 0); + localSetTcpEntry = PhGetDllBaseProcedureAddress(iphlpapiModule, "SetTcpEntry", 0); if (localSetTcpEntry) { diff --git a/ProcessHacker/proctree.c b/ProcessHacker/proctree.c index 42aa4d10f58a..ad4806ec0ae5 100644 --- a/ProcessHacker/proctree.c +++ b/ProcessHacker/proctree.c @@ -1209,7 +1209,7 @@ static VOID PhpUpdateProcessNodeDpiAwareness( if (PhBeginInitOnce(&initOnce)) { - getProcessDpiAwarenessInternal = PhGetModuleProcAddress(L"user32.dll", "GetProcessDpiAwarenessInternal"); + getProcessDpiAwarenessInternal = PhGetDllProcedureAddress(L"user32.dll", "GetProcessDpiAwarenessInternal", 0); PhEndInitOnce(&initOnce); } diff --git a/ProcessHacker/runas.c b/ProcessHacker/runas.c index 15ed2f65e5cb..4ee7750a98b8 100644 --- a/ProcessHacker/runas.c +++ b/ProcessHacker/runas.c @@ -271,8 +271,8 @@ BOOLEAN PhpInitializeNetApi(VOID) { if (netapiModuleHandle = LoadLibrary(L"netapi32.dll")) { - NetUserEnum_I = PhGetProcedureAddress(netapiModuleHandle, "NetUserEnum", 0); - NetApiBufferFree_I = PhGetProcedureAddress(netapiModuleHandle, "NetApiBufferFree", 0); + NetUserEnum_I = PhGetDllBaseProcedureAddress(netapiModuleHandle, "NetUserEnum", 0); + NetApiBufferFree_I = PhGetDllBaseProcedureAddress(netapiModuleHandle, "NetApiBufferFree", 0); } if (!NetUserEnum_I && !NetApiBufferFree_I) @@ -299,10 +299,10 @@ BOOLEAN PhpInitializeMRUList(VOID) { if (comctl32ModuleHandle = LoadLibrary(L"comctl32.dll")) { - CreateMRUList_I = PhGetProcedureAddress(comctl32ModuleHandle, "CreateMRUListW", 0); - AddMRUString_I = PhGetProcedureAddress(comctl32ModuleHandle, "AddMRUStringW", 0); - EnumMRUList_I = PhGetProcedureAddress(comctl32ModuleHandle, "EnumMRUListW", 0); - FreeMRUList_I = PhGetProcedureAddress(comctl32ModuleHandle, "FreeMRUList", 0); + CreateMRUList_I = PhGetDllBaseProcedureAddress(comctl32ModuleHandle, "CreateMRUListW", 0); + AddMRUString_I = PhGetDllBaseProcedureAddress(comctl32ModuleHandle, "AddMRUStringW", 0); + EnumMRUList_I = PhGetDllBaseProcedureAddress(comctl32ModuleHandle, "EnumMRUListW", 0); + FreeMRUList_I = PhGetDllBaseProcedureAddress(comctl32ModuleHandle, "FreeMRUList", 0); } if (!CreateMRUList_I && !AddMRUString_I && !EnumMRUList_I && !FreeMRUList_I) diff --git a/ProcessHacker/srvprv.c b/ProcessHacker/srvprv.c index f6f56d58a150..4c99f5afa74a 100644 --- a/ProcessHacker/srvprv.c +++ b/ProcessHacker/srvprv.c @@ -173,8 +173,8 @@ BOOLEAN PhServiceProviderInitialization( if (WindowsVersion > WINDOWS_7) { - SubscribeServiceChangeNotifications_I = PhGetModuleProcAddress(L"sechost.dll", "SubscribeServiceChangeNotifications"); - UnsubscribeServiceChangeNotifications_I = PhGetModuleProcAddress(L"sechost.dll", "UnsubscribeServiceChangeNotifications"); + SubscribeServiceChangeNotifications_I = PhGetDllProcedureAddress(L"sechost.dll", "SubscribeServiceChangeNotifications", 0); + UnsubscribeServiceChangeNotifications_I = PhGetDllProcedureAddress(L"sechost.dll", "UnsubscribeServiceChangeNotifications", 0); } return TRUE; diff --git a/ProcessHacker/sysscmem.c b/ProcessHacker/sysscmem.c index 2b7a9c4833cd..82168237dd34 100644 --- a/ProcessHacker/sysscmem.c +++ b/ProcessHacker/sysscmem.c @@ -303,7 +303,7 @@ INT_PTR CALLBACK PhSipMemoryDialogProc( SendMessage(GetDlgItem(hwndDlg, IDC_TOTALPHYSICAL), WM_SETFONT, (WPARAM)MemorySection->Parameters->MediumFont, FALSE); if (!getPhysicallyInstalledSystemMemory) - getPhysicallyInstalledSystemMemory = PhGetModuleProcAddress(L"kernel32.dll", "GetPhysicallyInstalledSystemMemory"); + getPhysicallyInstalledSystemMemory = PhGetDllProcedureAddress(L"kernel32.dll", "GetPhysicallyInstalledSystemMemory", 0); InstalledMemory = 0; diff --git a/phlib/guisup.c b/phlib/guisup.c index 7305c65a21db..2017e014def5 100644 --- a/phlib/guisup.c +++ b/phlib/guisup.c @@ -83,9 +83,9 @@ VOID PhGuiSupportInitialization( shlwapiHandle = LoadLibrary(L"shlwapi.dll"); if (WINDOWS_HAS_IMMERSIVE) - IsImmersiveProcess_I = PhGetModuleProcAddress(L"user32.dll", "IsImmersiveProcess"); - RunFileDlg = PhGetProcedureAddress(shell32Handle, NULL, 61); - SHAutoComplete_I = PhGetProcedureAddress(shlwapiHandle, "SHAutoComplete", 0); + IsImmersiveProcess_I = PhGetDllProcedureAddress(L"user32.dll", "IsImmersiveProcess", 0); + RunFileDlg = PhGetDllBaseProcedureAddress(shell32Handle, NULL, 61); + SHAutoComplete_I = PhGetDllBaseProcedureAddress(shlwapiHandle, "SHAutoComplete", 0); } VOID PhSetControlTheme( diff --git a/phlib/include/phutil.h b/phlib/include/phutil.h index 9b9c893a7b4a..6bddc0d3d6ac 100644 --- a/phlib/include/phutil.h +++ b/phlib/include/phutil.h @@ -1163,6 +1163,24 @@ PhFindLoaderEntry( _In_opt_ PPH_STRINGREF BaseDllName ); +PHLIBAPI +PVOID +NTAPI +PhGetDllBaseProcedureAddress( + _In_ PVOID DllBase, + _In_opt_ PSTR ProcedureName, + _In_opt_ USHORT ProcedureNumber + ); + +PHLIBAPI +PVOID +NTAPI +PhGetDllProcedureAddress( + _In_ PWSTR DllName, + _In_opt_ PSTR ProcedureName, + _In_opt_ USHORT ProcedureNumber + ); + PHLIBAPI PVOID NTAPI diff --git a/phlib/native.c b/phlib/native.c index 1a8d7b28e16d..fe40ce33517a 100644 --- a/phlib/native.c +++ b/phlib/native.c @@ -1393,7 +1393,7 @@ NTSTATUS PhUnloadDllProcess( if (!isModule32) { #endif - threadStart = PhGetModuleProcAddress(L"ntdll.dll", "LdrUnloadDll"); + threadStart = PhGetDllProcedureAddress(L"ntdll.dll", "LdrUnloadDll", 0); #ifdef _WIN64 } else diff --git a/phlib/svcsup.c b/phlib/svcsup.c index 9bbb45b4690e..0a04876341ae 100644 --- a/phlib/svcsup.c +++ b/phlib/svcsup.c @@ -439,7 +439,7 @@ PPH_STRING PhGetServiceNameFromTag( if (!I_QueryTagInformation) { - I_QueryTagInformation = PhGetModuleProcAddress(L"advapi32.dll", "I_QueryTagInformation"); + I_QueryTagInformation = PhGetDllProcedureAddress(L"advapi32.dll", "I_QueryTagInformation", 0); if (!I_QueryTagInformation) return NULL; @@ -471,7 +471,7 @@ PPH_STRING PhGetServiceNameForModuleReference( if (!I_QueryTagInformation) { - I_QueryTagInformation = PhGetModuleProcAddress(L"advapi32.dll", "I_QueryTagInformation"); + I_QueryTagInformation = PhGetDllProcedureAddress(L"advapi32.dll", "I_QueryTagInformation", 0); if (!I_QueryTagInformation) return NULL; diff --git a/phlib/symprv.c b/phlib/symprv.c index 93f32b500d35..a11eb9382c40 100644 --- a/phlib/symprv.c +++ b/phlib/symprv.c @@ -334,38 +334,38 @@ VOID PhpSymbolProviderCompleteInitialization( { // The Unicode versions aren't available in dbghelp.dll 5.1, so we fallback on the ANSI versions. - SymInitialize_I = PhGetProcedureAddress(dbghelpHandle, "SymInitialize", 0); - SymCleanup_I = PhGetProcedureAddress(dbghelpHandle, "SymCleanup", 0); - if (!(SymEnumSymbolsW_I = PhGetProcedureAddress(dbghelpHandle, "SymEnumSymbolsW", 0))) - SymEnumSymbols_I = PhGetProcedureAddress(dbghelpHandle, "SymEnumSymbols", 0); - if (!(SymFromAddrW_I = PhGetProcedureAddress(dbghelpHandle, "SymFromAddrW", 0))) - SymFromAddr_I = PhGetProcedureAddress(dbghelpHandle, "SymFromAddr", 0); - if (!(SymFromNameW_I = PhGetProcedureAddress(dbghelpHandle, "SymFromNameW", 0))) - SymFromName_I = PhGetProcedureAddress(dbghelpHandle, "SymFromName", 0); - if (!(SymGetLineFromAddrW64_I = PhGetProcedureAddress(dbghelpHandle, "SymGetLineFromAddrW64", 0))) - SymGetLineFromAddr64_I = PhGetProcedureAddress(dbghelpHandle, "SymGetLineFromAddr64", 0); - if (!(SymLoadModuleExW_I = PhGetProcedureAddress(dbghelpHandle, "SymLoadModuleExW", 0))) - SymLoadModule64_I = PhGetProcedureAddress(dbghelpHandle, "SymLoadModule64", 0); - SymGetOptions_I = PhGetProcedureAddress(dbghelpHandle, "SymGetOptions", 0); - SymSetOptions_I = PhGetProcedureAddress(dbghelpHandle, "SymSetOptions", 0); - if (!(SymGetSearchPathW_I = PhGetProcedureAddress(dbghelpHandle, "SymGetSearchPathW", 0))) - SymGetSearchPath_I = PhGetProcedureAddress(dbghelpHandle, "SymGetSearchPath", 0); - if (!(SymSetSearchPathW_I = PhGetProcedureAddress(dbghelpHandle, "SymSetSearchPathW", 0))) - SymSetSearchPath_I = PhGetProcedureAddress(dbghelpHandle, "SymSetSearchPath", 0); - SymUnloadModule64_I = PhGetProcedureAddress(dbghelpHandle, "SymUnloadModule64", 0); - SymFunctionTableAccess64_I = PhGetProcedureAddress(dbghelpHandle, "SymFunctionTableAccess64", 0); - SymGetModuleBase64_I = PhGetProcedureAddress(dbghelpHandle, "SymGetModuleBase64", 0); - SymRegisterCallbackW64_I = PhGetProcedureAddress(dbghelpHandle, "SymRegisterCallbackW64", 0); - StackWalk64_I = PhGetProcedureAddress(dbghelpHandle, "StackWalk64", 0); - MiniDumpWriteDump_I = PhGetProcedureAddress(dbghelpHandle, "MiniDumpWriteDump", 0); - UnDecorateSymbolName_I = PhGetProcedureAddress(dbghelpHandle, "UnDecorateSymbolName", 0); - UnDecorateSymbolNameW_I = PhGetProcedureAddress(dbghelpHandle, "UnDecorateSymbolNameW", 0); + SymInitialize_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymInitialize", 0); + SymCleanup_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymCleanup", 0); + if (!(SymEnumSymbolsW_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymEnumSymbolsW", 0))) + SymEnumSymbols_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymEnumSymbols", 0); + if (!(SymFromAddrW_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymFromAddrW", 0))) + SymFromAddr_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymFromAddr", 0); + if (!(SymFromNameW_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymFromNameW", 0))) + SymFromName_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymFromName", 0); + if (!(SymGetLineFromAddrW64_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymGetLineFromAddrW64", 0))) + SymGetLineFromAddr64_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymGetLineFromAddr64", 0); + if (!(SymLoadModuleExW_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymLoadModuleExW", 0))) + SymLoadModule64_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymLoadModule64", 0); + SymGetOptions_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymGetOptions", 0); + SymSetOptions_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymSetOptions", 0); + if (!(SymGetSearchPathW_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymGetSearchPathW", 0))) + SymGetSearchPath_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymGetSearchPath", 0); + if (!(SymSetSearchPathW_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymSetSearchPathW", 0))) + SymSetSearchPath_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymSetSearchPath", 0); + SymUnloadModule64_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymUnloadModule64", 0); + SymFunctionTableAccess64_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymFunctionTableAccess64", 0); + SymGetModuleBase64_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymGetModuleBase64", 0); + SymRegisterCallbackW64_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymRegisterCallbackW64", 0); + StackWalk64_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "StackWalk64", 0); + MiniDumpWriteDump_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "MiniDumpWriteDump", 0); + UnDecorateSymbolName_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "UnDecorateSymbolName", 0); + UnDecorateSymbolNameW_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "UnDecorateSymbolNameW", 0); } if (symsrvHandle) { - SymbolServerGetOptions = PhGetProcedureAddress(symsrvHandle, "SymbolServerGetOptions", 0); - SymbolServerSetOptions = PhGetProcedureAddress(symsrvHandle, "SymbolServerSetOptions", 0); + SymbolServerGetOptions = PhGetDllBaseProcedureAddress(symsrvHandle, "SymbolServerGetOptions", 0); + SymbolServerSetOptions = PhGetDllBaseProcedureAddress(symsrvHandle, "SymbolServerSetOptions", 0); } } @@ -1066,7 +1066,7 @@ NTSTATUS PhpLookupDynamicFunctionTable( ULONG i; BOOLEAN foundNull; - rtlGetFunctionTableListHead = PhGetModuleProcAddress(L"ntdll.dll", "RtlGetFunctionTableListHead"); + rtlGetFunctionTableListHead = PhGetDllProcedureAddress(L"ntdll.dll", "RtlGetFunctionTableListHead", 0); if (!rtlGetFunctionTableListHead) return STATUS_PROCEDURE_NOT_FOUND; diff --git a/phlib/util.c b/phlib/util.c index 86f9f17d2f35..ea33aa45887c 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -5415,18 +5415,18 @@ PVOID PhGetDllBaseProcedureAddress( } PVOID PhGetDllProcedureAddress( - _In_ PWSTR DllEntryName, + _In_ PWSTR DllName, _In_opt_ PSTR ProcedureName, _In_opt_ USHORT ProcedureNumber ) { - PVOID dllBaseAddress; + PVOID baseAddress; - if (!(dllBaseAddress = PhGetLoaderEntryDllBase(DllEntryName))) + if (!(baseAddress = PhGetLoaderEntryDllBase(DllName))) return NULL; return PhGetDllBaseProcedureAddress( - dllBaseAddress, + baseAddress, ProcedureName, ProcedureNumber ); From 0e53be2b64993c7cd45e0f1a81671c6a42edb57a Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 10 Apr 2018 19:13:37 +1000 Subject: [PATCH 0886/2058] Fix inconsistent parameters --- ProcessHacker/chproc.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/ProcessHacker/chproc.c b/ProcessHacker/chproc.c index 05d45796d3cf..51c91672cbbb 100644 --- a/ProcessHacker/chproc.c +++ b/ProcessHacker/chproc.c @@ -77,21 +77,17 @@ static VOID PhpRefreshProcessList( ) { NTSTATUS status; - HWND lvHandle; PVOID processes; PSYSTEM_PROCESS_INFORMATION process; - lvHandle = Context->ListViewHandle; - if (!NT_SUCCESS(status = PhEnumProcesses(&processes))) { PhShowStatus(hwndDlg, L"Unable to enumerate processes", status, 0); return; } - ExtendedListView_SetRedraw(lvHandle, FALSE); - - ListView_DeleteAllItems(lvHandle); + ExtendedListView_SetRedraw(Context->ListViewHandle, FALSE); + ListView_DeleteAllItems(Context->ListViewHandle); ImageList_RemoveAll(Context->ImageList); process = PH_FIRST_PROCESS(processes); @@ -112,7 +108,7 @@ static VOID PhpRefreshProcessList( else name = PhCreateString(SYSTEM_IDLE_PROCESS_NAME); - lvItemIndex = PhAddListViewItem(lvHandle, MAXINT, name->Buffer, process->UniqueProcessId); + lvItemIndex = PhAddListViewItem(Context->ListViewHandle, MAXINT, name->Buffer, process->UniqueProcessId); PhDereferenceObject(name); if (NT_SUCCESS(PhOpenProcess(&processHandle, ProcessQueryAccess, process->UniqueProcessId))) @@ -168,8 +164,8 @@ static VOID PhpRefreshProcessList( PhFree(processes); - ExtendedListView_SortItems(lvHandle); - ExtendedListView_SetRedraw(lvHandle, TRUE); + ExtendedListView_SortItems(Context->ListViewHandle); + ExtendedListView_SetRedraw(Context->ListViewHandle, TRUE); } INT_PTR CALLBACK PhpChooseProcessDlgProc( From e27a46e74f6812e5c742d9f4deb72211209d155e Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 10 Apr 2018 19:14:31 +1000 Subject: [PATCH 0887/2058] Fix MitigationOptionsMap POLICY2 index --- ProcessHacker/mtgndlg.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ProcessHacker/mtgndlg.c b/ProcessHacker/mtgndlg.c index 2d5630e7d6a7..bebfdc8791ee 100644 --- a/ProcessHacker/mtgndlg.c +++ b/ProcessHacker/mtgndlg.c @@ -223,7 +223,7 @@ INT_PTR CALLBACK PhpProcessMitigationPolicyDlgProc( if (context->SystemDllInitBlock && RTL_CONTAINS_FIELD(context->SystemDllInitBlock, context->SystemDllInitBlock->Size, MitigationOptionsMap)) { - if (context->SystemDllInitBlock->MitigationOptionsMap.Map[0] & PROCESS_CREATION_MITIGATION_POLICY2_LOADER_INTEGRITY_CONTINUITY_ALWAYS_ON) + if (context->SystemDllInitBlock->MitigationOptionsMap.Map[1] & PROCESS_CREATION_MITIGATION_POLICY2_LOADER_INTEGRITY_CONTINUITY_ALWAYS_ON) { PMITIGATION_POLICY_ENTRY entry; @@ -235,7 +235,7 @@ INT_PTR CALLBACK PhpProcessMitigationPolicyDlgProc( PhAddListViewItem(lvHandle, MAXINT, entry->ShortDescription->Buffer, entry); } - if (context->SystemDllInitBlock->MitigationOptionsMap.Map[0] & PROCESS_CREATION_MITIGATION_POLICY2_MODULE_TAMPERING_PROTECTION_ALWAYS_ON) + if (context->SystemDllInitBlock->MitigationOptionsMap.Map[1] & PROCESS_CREATION_MITIGATION_POLICY2_MODULE_TAMPERING_PROTECTION_ALWAYS_ON) { PMITIGATION_POLICY_ENTRY entry; From 07238c715de25365a88ee623532b8e3212830fa9 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 11 Apr 2018 23:26:37 +1000 Subject: [PATCH 0888/2058] Add workaround for minimal/reflected processes showing as suspended --- ProcessHacker/procprv.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/ProcessHacker/procprv.c b/ProcessHacker/procprv.c index 491898b25d23..ece16bdff108 100644 --- a/ProcessHacker/procprv.c +++ b/ProcessHacker/procprv.c @@ -1963,6 +1963,13 @@ VOID PhpGetProcessThreadInformation( contextSwitches += Process->Threads[i].ContextSwitches; } + // HACK: Minimal/Reflected processes don't have threads (TODO: Use PhGetProcessIsSuspended instead). + if (Process->NumberOfThreads == 0) + { + isSuspended = FALSE; + isPartiallySuspended = FALSE; + } + if (IsSuspended) *IsSuspended = isSuspended; if (IsPartiallySuspended) From 7f94a9e7360a1be7c46d9a8260c8b3db18ed2f58 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 11 Apr 2018 23:27:57 +1000 Subject: [PATCH 0889/2058] Fix typo --- phlib/util.c | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/phlib/util.c b/phlib/util.c index ea33aa45887c..2ebc1d6f2144 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -5381,6 +5381,25 @@ PPH_STRING PhGetDllFileName( return fileName; } +PVOID PhGetLoaderEntryDllBase( + _In_opt_ PWSTR BaseDllName + ) +{ + PH_STRINGREF entryNameSr; + PLDR_DATA_TABLE_ENTRY ldrEntry; + + PhInitializeStringRefLongHint(&entryNameSr, BaseDllName); + + RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock); + ldrEntry = PhFindLoaderEntry(NULL, NULL, &entryNameSr); + RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock); + + if (ldrEntry) + return ldrEntry->DllBase; + else + return NULL; +} + PVOID PhGetDllBaseProcedureAddress( _In_ PVOID DllBase, _In_opt_ PSTR ProcedureName, @@ -5432,32 +5451,13 @@ PVOID PhGetDllProcedureAddress( ); } -PVOID PhGetLoaderEntryDllBase( - _In_opt_ PWSTR BaseDllName - ) -{ - PH_STRINGREF entryNameSr; - PLDR_DATA_TABLE_ENTRY ldrEntry; - - PhInitializeStringRefLongHint(&entryNameSr, BaseDllName); - - RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock); - ldrEntry = PhFindLoaderEntry(NULL, NULL, &entryNameSr); - RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock); - - if (ldrEntry) - return ldrEntry->DllBase; - else - return NULL; -} - NTSTATUS PhGetLoaderEntryImageNtHeaders( _In_ PVOID BaseAddress, _Out_ PIMAGE_NT_HEADERS *ImageNtHeaders ) { - PIMAGE_NT_HEADERS ntHeader; PIMAGE_DOS_HEADER dosHeader; + PIMAGE_NT_HEADERS ntHeader; ULONG ntHeadersOffset; dosHeader = PTR_ADD_OFFSET(BaseAddress, 0); From 15343c5a3b3d4fc2d3f3bc6a1d4e3c42a9bf23af Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 12 Apr 2018 00:36:37 +1000 Subject: [PATCH 0890/2058] HardwareDevices: Fix options crash --- plugins/HardwareDevices/netoptions.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/HardwareDevices/netoptions.c b/plugins/HardwareDevices/netoptions.c index ef95f4cee8ad..5df23140da9a 100644 --- a/plugins/HardwareDevices/netoptions.c +++ b/plugins/HardwareDevices/netoptions.c @@ -185,7 +185,7 @@ VOID AddNetworkAdapterToListView( BOOLEAN found = FALSE; PDV_NETADAPTER_ID newId = NULL; - InitializeNetAdapterId(&adapterId, IfIndex, Luid, NULL); + InitializeNetAdapterId(&adapterId, IfIndex, Luid, Guid); for (ULONG i = 0; i < NetworkAdaptersList->Count; i++) { From 7359a5ee0c7d9eef4870c1695ae23dd4afbee0df Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 12 Apr 2018 00:37:05 +1000 Subject: [PATCH 0891/2058] Update PhpImportProcedure --- phlib/apiimport.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phlib/apiimport.c b/phlib/apiimport.c index a14facf43a3c..13e8d9473ea9 100644 --- a/phlib/apiimport.c +++ b/phlib/apiimport.c @@ -41,7 +41,7 @@ PVOID PhpImportProcedure( if (!module) return NULL; - procedure = PhGetProcedureAddress(module, ProcedureName, 0); + procedure = PhGetDllBaseProcedureAddress(module, ProcedureName, 0); *Cache = procedure; MemoryBarrier(); *CacheValid = TRUE; From 1d0bab1f102314a5137ebb8fada4382ec7190fb6 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 13 Apr 2018 08:31:18 +1000 Subject: [PATCH 0892/2058] Update PhpVerifyInitialization --- phlib/verify.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/phlib/verify.c b/phlib/verify.c index 72e0213787cc..7a0caef23c3b 100644 --- a/phlib/verify.c +++ b/phlib/verify.c @@ -53,20 +53,20 @@ static VOID PhpVerifyInitialization( wintrust = LoadLibrary(L"wintrust.dll"); crypt32 = LoadLibrary(L"crypt32.dll"); - CryptCATAdminCalcHashFromFileHandle = PhGetProcedureAddress(wintrust, "CryptCATAdminCalcHashFromFileHandle", 0); - CryptCATAdminCalcHashFromFileHandle2 = PhGetProcedureAddress(wintrust, "CryptCATAdminCalcHashFromFileHandle2", 0); - CryptCATAdminAcquireContext = PhGetProcedureAddress(wintrust, "CryptCATAdminAcquireContext", 0); - CryptCATAdminAcquireContext2 = PhGetProcedureAddress(wintrust, "CryptCATAdminAcquireContext2", 0); - CryptCATAdminEnumCatalogFromHash = PhGetProcedureAddress(wintrust, "CryptCATAdminEnumCatalogFromHash", 0); - CryptCATCatalogInfoFromContext = PhGetProcedureAddress(wintrust, "CryptCATCatalogInfoFromContext", 0); - CryptCATAdminReleaseCatalogContext = PhGetProcedureAddress(wintrust, "CryptCATAdminReleaseCatalogContext", 0); - CryptCATAdminReleaseContext = PhGetProcedureAddress(wintrust, "CryptCATAdminReleaseContext", 0); - WTHelperProvDataFromStateData_I = PhGetProcedureAddress(wintrust, "WTHelperProvDataFromStateData", 0); - WTHelperGetProvSignerFromChain_I = PhGetProcedureAddress(wintrust, "WTHelperGetProvSignerFromChain", 0); - WinVerifyTrust_I = PhGetProcedureAddress(wintrust, "WinVerifyTrust", 0); - CertNameToStr_I = PhGetProcedureAddress(crypt32, "CertNameToStrW", 0); - CertDuplicateCertificateContext_I = PhGetProcedureAddress(crypt32, "CertDuplicateCertificateContext", 0); - CertFreeCertificateContext_I = PhGetProcedureAddress(crypt32, "CertFreeCertificateContext", 0); + CryptCATAdminCalcHashFromFileHandle = PhGetDllBaseProcedureAddress(wintrust, "CryptCATAdminCalcHashFromFileHandle", 0); + CryptCATAdminCalcHashFromFileHandle2 = PhGetDllBaseProcedureAddress(wintrust, "CryptCATAdminCalcHashFromFileHandle2", 0); + CryptCATAdminAcquireContext = PhGetDllBaseProcedureAddress(wintrust, "CryptCATAdminAcquireContext", 0); + CryptCATAdminAcquireContext2 = PhGetDllBaseProcedureAddress(wintrust, "CryptCATAdminAcquireContext2", 0); + CryptCATAdminEnumCatalogFromHash = PhGetDllBaseProcedureAddress(wintrust, "CryptCATAdminEnumCatalogFromHash", 0); + CryptCATCatalogInfoFromContext = PhGetDllBaseProcedureAddress(wintrust, "CryptCATCatalogInfoFromContext", 0); + CryptCATAdminReleaseCatalogContext = PhGetDllBaseProcedureAddress(wintrust, "CryptCATAdminReleaseCatalogContext", 0); + CryptCATAdminReleaseContext = PhGetDllBaseProcedureAddress(wintrust, "CryptCATAdminReleaseContext", 0); + WTHelperProvDataFromStateData_I = PhGetDllBaseProcedureAddress(wintrust, "WTHelperProvDataFromStateData", 0); + WTHelperGetProvSignerFromChain_I = PhGetDllBaseProcedureAddress(wintrust, "WTHelperGetProvSignerFromChain", 0); + WinVerifyTrust_I = PhGetDllBaseProcedureAddress(wintrust, "WinVerifyTrust", 0); + CertNameToStr_I = PhGetDllBaseProcedureAddress(crypt32, "CertNameToStrW", 0); + CertDuplicateCertificateContext_I = PhGetDllBaseProcedureAddress(crypt32, "CertDuplicateCertificateContext", 0); + CertFreeCertificateContext_I = PhGetDllBaseProcedureAddress(crypt32, "CertFreeCertificateContext", 0); } VERIFY_RESULT PhpStatusToVerifyResult( @@ -164,7 +164,7 @@ VOID PhpViewSignerInfo( { HMODULE cryptui = LoadLibrary(L"cryptui.dll"); - cryptUIDlgViewSignerInfo = PhGetProcedureAddress(cryptui, "CryptUIDlgViewSignerInfoW", 0); + cryptUIDlgViewSignerInfo = PhGetDllBaseProcedureAddress(cryptui, "CryptUIDlgViewSignerInfoW", 0); PhEndInitOnce(&initOnce); } From 4ce74af4be54f36241e697b9df064259727474cc Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 14 Apr 2018 09:11:21 +1000 Subject: [PATCH 0893/2058] ExtendedTools: Fix text position --- plugins/ExtendedTools/ExtendedTools.rc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/ExtendedTools/ExtendedTools.rc b/plugins/ExtendedTools/ExtendedTools.rc index 543ef65c9b70..9301a428c85a 100644 --- a/plugins/ExtendedTools/ExtendedTools.rc +++ b/plugins/ExtendedTools/ExtendedTools.rc @@ -312,13 +312,13 @@ BEGIN LTEXT "Receives",IDC_STATIC,132,11,30,8 LTEXT "Receive bytes",IDC_STATIC,132,23,46,8 LTEXT "Receive bytes delta",IDC_STATIC,132,34,65,8 - LTEXT "Sends",IDC_STATIC,132,46,20,8 + LTEXT "Sends",IDC_STATIC,132,45,20,8 LTEXT "Send bytes",IDC_STATIC,132,56,37,8 LTEXT "Send bytes delta",IDC_STATIC,132,67,56,8 RTEXT "Static",IDC_ZRECEIVES_V,184,11,54,8,SS_ENDELLIPSIS RTEXT "Static",IDC_ZRECEIVEBYTES_V,200,23,38,8,SS_ENDELLIPSIS RTEXT "Static",IDC_ZRECEIVEBYTESDELTA_V,200,34,38,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZSENDS_V,184,46,54,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZSENDS_V,184,45,54,8,SS_ENDELLIPSIS RTEXT "Static",IDC_ZSENDBYTES_V,200,56,38,8,SS_ENDELLIPSIS RTEXT "Static",IDC_ZSENDBYTESDELTA_V,200,67,38,8,SS_ENDELLIPSIS END From ba7016659e1caeb8a15faf66d5690967d3afa8f7 Mon Sep 17 00:00:00 2001 From: diversenok Date: Sat, 14 Apr 2018 18:35:08 +0300 Subject: [PATCH 0894/2058] Type comparison fix for handle search (#257) --- ProcessHacker/findobj.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ProcessHacker/findobj.c b/ProcessHacker/findobj.c index 3d5914e88bbb..184c083c0cb3 100644 --- a/ProcessHacker/findobj.c +++ b/ProcessHacker/findobj.c @@ -800,7 +800,7 @@ static BOOLEAN MatchTypeString( if (PhEqualString2(Context->SearchTypeString, L"Everything", FALSE)) return TRUE; - return PhFindStringInStringRef(Input, &Context->SearchTypeString->sr, TRUE) != -1; + return PhEqualStringRef(Input, &Context->SearchTypeString->sr, TRUE); } typedef struct _SEARCH_HANDLE_CONTEXT From f7268b27195a15128350916bd3f18609f0769f3a Mon Sep 17 00:00:00 2001 From: diversenok Date: Mon, 16 Apr 2018 01:00:14 +0300 Subject: [PATCH 0895/2058] New properties page for file handles (#258) Obtaining more information from file handles and showing it in a new page in handle properties. --- ProcessHacker/ProcessHacker.rc | 24 ++++ ProcessHacker/hndlprp.c | 7 + ProcessHacker/include/phapp.h | 5 + ProcessHacker/ntobjprp.c | 240 +++++++++++++++++++++++++++++++++ ProcessHacker/resource.h | 10 +- 5 files changed, 284 insertions(+), 2 deletions(-) diff --git a/ProcessHacker/ProcessHacker.rc b/ProcessHacker/ProcessHacker.rc index 972a27af58b2..030bd70221a3 100644 --- a/ProcessHacker/ProcessHacker.rc +++ b/ProcessHacker/ProcessHacker.rc @@ -864,6 +864,22 @@ BEGIN PUSHBUTTON "Pulse",IDC_PULSE,115,34,50,14 END +IDD_OBJFILE DIALOGEX 0, 0, 257, 86 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "File" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "Type:",IDC_STATIC,7,7,28,8 + LTEXT "Unknown",IDC_FILETYPE,40,7,210,8 + LTEXT "Position:",IDC_STATIC,7,29,28,8 + LTEXT "Unknown",IDC_POSITION,40,29,210,8 + LTEXT "File size:",IDC_STATIC,7,40,28,8 + LTEXT "Unknown",IDC_FILESIZE,40,40,210,8 + PUSHBUTTON "Flush",IDC_FLUSH,7,56,50,14 + LTEXT "Mode:",IDC_STATIC,7,18,28,8 + EDITTEXT IDC_FILEMODE,40,18,207,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER +END + IDD_OBJMUTANT DIALOGEX 0, 0, 186, 76 STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Mutant" @@ -1973,6 +1989,14 @@ BEGIN BOTTOMMARGIN, 69 END + IDD_OBJFILE, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 250 + TOPMARGIN, 7 + BOTTOMMARGIN, 79 + END + IDD_OBJMUTANT, DIALOG BEGIN LEFTMARGIN, 7 diff --git a/ProcessHacker/hndlprp.c b/ProcessHacker/hndlprp.c index f9de4930cf80..c04b39029285 100644 --- a/ProcessHacker/hndlprp.c +++ b/ProcessHacker/hndlprp.c @@ -129,6 +129,13 @@ VOID PhShowHandleProperties( &context ); } + else if (PhEqualString2(HandleItem->TypeName, L"File", TRUE)) + { + pages[propSheetHeader.nPages++] = PhCreateFilePage( + PhpDuplicateHandleFromProcess, + &context + ); + } else if (PhEqualString2(HandleItem->TypeName, L"Job", TRUE)) { pages[propSheetHeader.nPages++] = PhCreateJobPage( diff --git a/ProcessHacker/include/phapp.h b/ProcessHacker/include/phapp.h index 65b9200bd700..775281ad9d7d 100644 --- a/ProcessHacker/include/phapp.h +++ b/ProcessHacker/include/phapp.h @@ -504,6 +504,11 @@ HPROPSHEETPAGE PhCreateEventPairPage( _In_opt_ PVOID Context ); +HPROPSHEETPAGE PhCreateFilePage( + _In_ PPH_OPEN_OBJECT OpenObject, + _In_opt_ PVOID Context +); + HPROPSHEETPAGE PhCreateMutantPage( _In_ PPH_OPEN_OBJECT OpenObject, _In_opt_ PVOID Context diff --git a/ProcessHacker/ntobjprp.c b/ProcessHacker/ntobjprp.c index 4196733c8e6e..fbc3d1d903a9 100644 --- a/ProcessHacker/ntobjprp.c +++ b/ProcessHacker/ntobjprp.c @@ -24,6 +24,7 @@ #include #include +#include #include @@ -33,6 +34,18 @@ typedef struct _COMMON_PAGE_CONTEXT PVOID Context; } COMMON_PAGE_CONTEXT, *PCOMMON_PAGE_CONTEXT; +#define PH_FILEMODE_ASYNC 0x01000000 +#define PhFileModeUpdAsyncFlag(mode) mode & (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT) ? mode &~ PH_FILEMODE_ASYNC: mode | PH_FILEMODE_ASYNC + +PH_ACCESS_ENTRY FileModeAccessEntries[6] = { + { L"FILE_FLAG_OVERLAPPED", PH_FILEMODE_ASYNC, FALSE, FALSE, L"Asynchronous" }, + { L"FILE_FLAG_WRITE_THROUGH", FILE_WRITE_THROUGH, FALSE, FALSE, L"Write through" }, + { L"FILE_FLAG_SEQUENTIAL_SCAN", FILE_SEQUENTIAL_ONLY, FALSE, FALSE, L"Sequental" }, + { L"FILE_FLAG_NO_BUFFERING", FILE_NO_INTERMEDIATE_BUFFERING, FALSE, FALSE, L"No buffering" }, + { L"FILE_SYNCHRONOUS_IO_ALERT", FILE_SYNCHRONOUS_IO_ALERT, FALSE, FALSE, L"Synchronous alert" }, + { L"FILE_SYNCHRONOUS_IO_NONALERT", FILE_SYNCHRONOUS_IO_NONALERT, FALSE, FALSE, L"Synchronous non-alert" }, +}; + HPROPSHEETPAGE PhpCommonCreatePage( _In_ PPH_OPEN_OBJECT OpenObject, _In_opt_ PVOID Context, @@ -60,6 +73,13 @@ INT_PTR CALLBACK PhpEventPairPageProc( _In_ LPARAM lParam ); +INT_PTR CALLBACK PhpFilePageProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + INT_PTR CALLBACK PhpMutantPageProc( _In_ HWND hwndDlg, _In_ UINT uMsg, @@ -348,6 +368,226 @@ INT_PTR CALLBACK PhpEventPairPageProc( return FALSE; } +HPROPSHEETPAGE PhCreateFilePage( + _In_ PPH_OPEN_OBJECT OpenObject, + _In_opt_ PVOID Context +) +{ + return PhpCommonCreatePage( + OpenObject, + Context, + MAKEINTRESOURCE(IDD_OBJFILE), + PhpFilePageProc + ); +} + +static VOID PhpRefreshFilePageInfo( + _In_ HWND hwndDlg, + _In_ PCOMMON_PAGE_CONTEXT PageContext +) +{ + HANDLE hFile; + + if (NT_SUCCESS(PageContext->OpenObject( + &hFile, + MAXIMUM_ALLOWED, + PageContext->Context + ))) + { + IO_STATUS_BLOCK ioStatusBlock; + FILE_MODE_INFORMATION fileModeInfo; + FILE_STANDARD_INFORMATION fileStandardInfo; + FILE_POSITION_INFORMATION filePositionInfo; + FILE_FS_DEVICE_INFORMATION deviceInformation; + NTSTATUS statusStandardInfo; + BOOL disableFlushButton = FALSE; + BOOL isFileOrDirectory = FALSE; + + // Obtain the file type + if (NT_SUCCESS(NtQueryVolumeInformationFile( + hFile, + &ioStatusBlock, + &deviceInformation, + sizeof(deviceInformation), + FileFsDeviceInformation + ))) + { + switch (deviceInformation.DeviceType) + { + case FILE_DEVICE_NAMED_PIPE: + SetDlgItemText(hwndDlg, IDC_FILETYPE, L"Pipe"); + break; + case FILE_DEVICE_CD_ROM: + case FILE_DEVICE_CD_ROM_FILE_SYSTEM: + case FILE_DEVICE_CONTROLLER: + case FILE_DEVICE_DATALINK: + case FILE_DEVICE_DFS: + case FILE_DEVICE_DISK: + case FILE_DEVICE_DISK_FILE_SYSTEM: + case FILE_DEVICE_VIRTUAL_DISK: + isFileOrDirectory = TRUE; + SetDlgItemText(hwndDlg, IDC_FILETYPE, L"File or directory"); + break; + default: + SetDlgItemText(hwndDlg, IDC_FILETYPE, L"Other"); + break; + } + } + + // Obtain the file size and distinguish files from directories + if (NT_SUCCESS(statusStandardInfo = NtQueryInformationFile( + hFile, + &ioStatusBlock, + &fileStandardInfo, + sizeof(fileStandardInfo), + FileStandardInformation + ))) + { + PPH_STRING fileSizeStr; + + fileSizeStr = PhFormatUInt64(fileStandardInfo.EndOfFile.QuadPart, TRUE); + SetDlgItemText(hwndDlg, IDC_FILESIZE, fileSizeStr->Buffer); + disableFlushButton |= fileStandardInfo.Directory; + PhDereferenceObject(fileSizeStr); + + if (isFileOrDirectory) + { + SetDlgItemText(hwndDlg, IDC_FILETYPE, fileStandardInfo.Directory ? L"Directory" : L"File"); + } + } + + // Obtain current position + if (NT_SUCCESS(NtQueryInformationFile( + hFile, + &ioStatusBlock, + &filePositionInfo, + sizeof(filePositionInfo), + FilePositionInformation + ))) + { + PPH_STRING filePosStr; + + // If we also know the size of the file, we can calculate the percentage + if (NT_SUCCESS(statusStandardInfo) && + filePositionInfo.CurrentByteOffset.QuadPart != 0 && + fileStandardInfo.EndOfFile.QuadPart != 0 + ) + { + PH_FORMAT format[4]; + + PhInitFormatI64U(&format[0], filePositionInfo.CurrentByteOffset.QuadPart); + format[0].Type |= FormatGroupDigits; + PhInitFormatS(&format[1], L" ("); + PhInitFormatF(&format[2], (double)filePositionInfo.CurrentByteOffset.QuadPart / fileStandardInfo.EndOfFile.QuadPart * 100, 1); + PhInitFormatS(&format[3], L"%)"); + + filePosStr = PhFormat(format, 4, 18); + } + else // or we can't + { + filePosStr = PhFormatUInt64(filePositionInfo.CurrentByteOffset.QuadPart, TRUE); + } + + SetDlgItemText(hwndDlg, IDC_POSITION, filePosStr->Buffer); + PhDereferenceObject(filePosStr); + } + + // Obtain the file mode + if (NT_SUCCESS(NtQueryInformationFile( + hFile, + &ioStatusBlock, + &fileModeInfo, + sizeof(fileModeInfo), + FileModeInformation + ))) + { + PH_FORMAT format[5]; + PPH_STRING fileModeStr, fileModeAccessStr; + + // Since FILE_MODE_INFORMATION has no flag for asynchronous I/O we should use our own flag and set + // it only if none of synchronous flags are present. That's why we need PhFileModeUpdAsyncFlag. + fileModeAccessStr = PhGetAccessString( + PhFileModeUpdAsyncFlag(fileModeInfo.Mode), + FileModeAccessEntries, + sizeof(FileModeAccessEntries) / sizeof(PH_ACCESS_ENTRY) + ); + + PhInitFormatS(&format[0], L"0x"); + PhInitFormatX(&format[1], fileModeInfo.Mode); + PhInitFormatS(&format[2], L" ("); + PhInitFormatSR(&format[3], fileModeAccessStr->sr); + PhInitFormatS(&format[4], L")"); + fileModeStr = PhFormat(format, 5, 64); + PhDereferenceObject(fileModeAccessStr); + + SetDlgItemText(hwndDlg, IDC_FILEMODE, fileModeStr->Buffer); + PhDereferenceObject(fileModeStr); + disableFlushButton |= fileModeInfo.Mode & (FILE_WRITE_THROUGH | FILE_NO_INTERMEDIATE_BUFFERING); + } + else + { + SetDlgItemText(hwndDlg, IDC_FILEMODE, L"Unknown"); + } + + EnableWindow(GetDlgItem(hwndDlg, IDC_FLUSH), !disableFlushButton); + NtClose(hFile); + } +} + +INT_PTR CALLBACK PhpFilePageProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam +) +{ + PCOMMON_PAGE_CONTEXT pageContext; + + pageContext = PhpCommonPageHeader(hwndDlg, uMsg, wParam, lParam); + + if (!pageContext) + return FALSE; + + switch (uMsg) + { + case WM_INITDIALOG: + { + PhpRefreshFilePageInfo(hwndDlg, pageContext); + } + break; + case WM_COMMAND: + { + switch (GET_WM_COMMAND_ID(wParam, lParam)) + { + case IDC_FLUSH: + { + HANDLE fileHandle; + NTSTATUS status; + + if (NT_SUCCESS(status = pageContext->OpenObject( + &fileHandle, + GENERIC_WRITE, + pageContext->Context + ))) + { + IO_STATUS_BLOCK ioStatusBlock; + + status = NtFlushBuffersFile(fileHandle, &ioStatusBlock); + NtClose(fileHandle); + } + + if (!NT_SUCCESS(status)) + PhShowStatus(hwndDlg, L"Unable to flush the file buffer", status, 0); + } + break; + } + } + break; + } + + return FALSE; +} + HPROPSHEETPAGE PhCreateMutantPage( _In_ PPH_OPEN_OBJECT OpenObject, _In_opt_ PVOID Context diff --git a/ProcessHacker/resource.h b/ProcessHacker/resource.h index aca3b7524fab..3616f5c0d8b9 100644 --- a/ProcessHacker/resource.h +++ b/ProcessHacker/resource.h @@ -128,6 +128,7 @@ #define IDD_PROCWMIPROVIDERS 242 #define IDD_COLUMNSETS 243 #define ID_VIEW_TRAYICONS 244 +#define IDD_OBJFILE 249 #define IDC_TERMINATE 1003 #define IDC_FILEICON 1005 #define IDC_FILE 1006 @@ -537,6 +538,11 @@ #define IDC_LIST_DISABLED 1402 #define IDC_COLUMNSETLIST 1403 #define IDC_STATISTICS_LIST 1404 +#define IDC_FLUSH 1406 +#define IDC_POSITION 1407 +#define IDC_FILESIZE 1408 +#define IDC_FILETYPE 1409 +#define IDC_FILEMODE 1410 #define ID_HACKER_EXIT 40001 #define ID_PROCESS_PROPERTIES 40006 #define ID_PROCESS_TERMINATE 40007 @@ -743,9 +749,9 @@ // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 249 +#define _APS_NEXT_RESOURCE_VALUE 252 #define _APS_NEXT_COMMAND_VALUE 40297 -#define _APS_NEXT_CONTROL_VALUE 1406 +#define _APS_NEXT_CONTROL_VALUE 1410 #define _APS_NEXT_SYMED_VALUE 170 #endif #endif From 991da98e509b5c6257669aacbed226bbdf89d194 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 16 Apr 2018 08:41:22 +1000 Subject: [PATCH 0896/2058] Fix tabspace --- ProcessHacker/hndlprp.c | 2 +- ProcessHacker/include/phapp.h | 2 +- ProcessHacker/ntobjprp.c | 115 ++++++++++++++++++---------------- 3 files changed, 62 insertions(+), 57 deletions(-) diff --git a/ProcessHacker/hndlprp.c b/ProcessHacker/hndlprp.c index c04b39029285..156a035f6f07 100644 --- a/ProcessHacker/hndlprp.c +++ b/ProcessHacker/hndlprp.c @@ -134,7 +134,7 @@ VOID PhShowHandleProperties( pages[propSheetHeader.nPages++] = PhCreateFilePage( PhpDuplicateHandleFromProcess, &context - ); + ); } else if (PhEqualString2(HandleItem->TypeName, L"Job", TRUE)) { diff --git a/ProcessHacker/include/phapp.h b/ProcessHacker/include/phapp.h index 775281ad9d7d..cb032cf90e01 100644 --- a/ProcessHacker/include/phapp.h +++ b/ProcessHacker/include/phapp.h @@ -507,7 +507,7 @@ HPROPSHEETPAGE PhCreateEventPairPage( HPROPSHEETPAGE PhCreateFilePage( _In_ PPH_OPEN_OBJECT OpenObject, _In_opt_ PVOID Context -); + ); HPROPSHEETPAGE PhCreateMutantPage( _In_ PPH_OPEN_OBJECT OpenObject, diff --git a/ProcessHacker/ntobjprp.c b/ProcessHacker/ntobjprp.c index fbc3d1d903a9..073c6e729781 100644 --- a/ProcessHacker/ntobjprp.c +++ b/ProcessHacker/ntobjprp.c @@ -35,9 +35,11 @@ typedef struct _COMMON_PAGE_CONTEXT } COMMON_PAGE_CONTEXT, *PCOMMON_PAGE_CONTEXT; #define PH_FILEMODE_ASYNC 0x01000000 -#define PhFileModeUpdAsyncFlag(mode) mode & (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT) ? mode &~ PH_FILEMODE_ASYNC: mode | PH_FILEMODE_ASYNC +#define PhFileModeUpdAsyncFlag(mode) \ + (mode & (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT) ? mode &~ PH_FILEMODE_ASYNC: mode | PH_FILEMODE_ASYNC) -PH_ACCESS_ENTRY FileModeAccessEntries[6] = { +PH_ACCESS_ENTRY FileModeAccessEntries[6] = +{ { L"FILE_FLAG_OVERLAPPED", PH_FILEMODE_ASYNC, FALSE, FALSE, L"Asynchronous" }, { L"FILE_FLAG_WRITE_THROUGH", FILE_WRITE_THROUGH, FALSE, FALSE, L"Write through" }, { L"FILE_FLAG_SEQUENTIAL_SCAN", FILE_SEQUENTIAL_ONLY, FALSE, FALSE, L"Sequental" }, @@ -371,28 +373,28 @@ INT_PTR CALLBACK PhpEventPairPageProc( HPROPSHEETPAGE PhCreateFilePage( _In_ PPH_OPEN_OBJECT OpenObject, _In_opt_ PVOID Context -) + ) { return PhpCommonCreatePage( OpenObject, Context, MAKEINTRESOURCE(IDD_OBJFILE), PhpFilePageProc - ); + ); } static VOID PhpRefreshFilePageInfo( _In_ HWND hwndDlg, _In_ PCOMMON_PAGE_CONTEXT PageContext -) + ) { - HANDLE hFile; + HANDLE fileHandle; if (NT_SUCCESS(PageContext->OpenObject( - &hFile, + &fileHandle, MAXIMUM_ALLOWED, PageContext->Context - ))) + ))) { IO_STATUS_BLOCK ioStatusBlock; FILE_MODE_INFORMATION fileModeInfo; @@ -400,17 +402,17 @@ static VOID PhpRefreshFilePageInfo( FILE_POSITION_INFORMATION filePositionInfo; FILE_FS_DEVICE_INFORMATION deviceInformation; NTSTATUS statusStandardInfo; - BOOL disableFlushButton = FALSE; - BOOL isFileOrDirectory = FALSE; + BOOLEAN disableFlushButton = FALSE; + BOOLEAN isFileOrDirectory = FALSE; // Obtain the file type if (NT_SUCCESS(NtQueryVolumeInformationFile( - hFile, + fileHandle, &ioStatusBlock, &deviceInformation, sizeof(deviceInformation), FileFsDeviceInformation - ))) + ))) { switch (deviceInformation.DeviceType) { @@ -436,18 +438,19 @@ static VOID PhpRefreshFilePageInfo( // Obtain the file size and distinguish files from directories if (NT_SUCCESS(statusStandardInfo = NtQueryInformationFile( - hFile, + fileHandle, &ioStatusBlock, &fileStandardInfo, sizeof(fileStandardInfo), FileStandardInformation - ))) + ))) { PPH_STRING fileSizeStr; + disableFlushButton |= fileStandardInfo.Directory; + fileSizeStr = PhFormatUInt64(fileStandardInfo.EndOfFile.QuadPart, TRUE); SetDlgItemText(hwndDlg, IDC_FILESIZE, fileSizeStr->Buffer); - disableFlushButton |= fileStandardInfo.Directory; PhDereferenceObject(fileSizeStr); if (isFileOrDirectory) @@ -458,12 +461,12 @@ static VOID PhpRefreshFilePageInfo( // Obtain current position if (NT_SUCCESS(NtQueryInformationFile( - hFile, + fileHandle, &ioStatusBlock, &filePositionInfo, sizeof(filePositionInfo), FilePositionInformation - ))) + ))) { PPH_STRING filePosStr; @@ -494,15 +497,18 @@ static VOID PhpRefreshFilePageInfo( // Obtain the file mode if (NT_SUCCESS(NtQueryInformationFile( - hFile, + fileHandle, &ioStatusBlock, &fileModeInfo, sizeof(fileModeInfo), FileModeInformation - ))) + ))) { PH_FORMAT format[5]; - PPH_STRING fileModeStr, fileModeAccessStr; + PPH_STRING fileModeStr; + PPH_STRING fileModeAccessStr; + + disableFlushButton |= fileModeInfo.Mode & (FILE_WRITE_THROUGH | FILE_NO_INTERMEDIATE_BUFFERING); // Since FILE_MODE_INFORMATION has no flag for asynchronous I/O we should use our own flag and set // it only if none of synchronous flags are present. That's why we need PhFileModeUpdAsyncFlag. @@ -510,27 +516,28 @@ static VOID PhpRefreshFilePageInfo( PhFileModeUpdAsyncFlag(fileModeInfo.Mode), FileModeAccessEntries, sizeof(FileModeAccessEntries) / sizeof(PH_ACCESS_ENTRY) - ); + ); PhInitFormatS(&format[0], L"0x"); PhInitFormatX(&format[1], fileModeInfo.Mode); PhInitFormatS(&format[2], L" ("); PhInitFormatSR(&format[3], fileModeAccessStr->sr); PhInitFormatS(&format[4], L")"); - fileModeStr = PhFormat(format, 5, 64); - PhDereferenceObject(fileModeAccessStr); + fileModeStr = PhFormat(format, 5, 64); SetDlgItemText(hwndDlg, IDC_FILEMODE, fileModeStr->Buffer); + PhDereferenceObject(fileModeStr); - disableFlushButton |= fileModeInfo.Mode & (FILE_WRITE_THROUGH | FILE_NO_INTERMEDIATE_BUFFERING); + PhDereferenceObject(fileModeAccessStr); } else { SetDlgItemText(hwndDlg, IDC_FILEMODE, L"Unknown"); } - EnableWindow(GetDlgItem(hwndDlg, IDC_FLUSH), !disableFlushButton); - NtClose(hFile); + EnableWindow(GetDlgItem(hwndDlg, IDC_FLUSH), !disableFlushButton); + + NtClose(fileHandle); } } @@ -539,50 +546,48 @@ INT_PTR CALLBACK PhpFilePageProc( _In_ UINT uMsg, _In_ WPARAM wParam, _In_ LPARAM lParam -) + ) { PCOMMON_PAGE_CONTEXT pageContext; - pageContext = PhpCommonPageHeader(hwndDlg, uMsg, wParam, lParam); - - if (!pageContext) + if (!(pageContext = PhpCommonPageHeader(hwndDlg, uMsg, wParam, lParam))) return FALSE; switch (uMsg) { case WM_INITDIALOG: - { - PhpRefreshFilePageInfo(hwndDlg, pageContext); - } - break; - case WM_COMMAND: - { - switch (GET_WM_COMMAND_ID(wParam, lParam)) { - case IDC_FLUSH: + PhpRefreshFilePageInfo(hwndDlg, pageContext); + } + break; + case WM_COMMAND: { - HANDLE fileHandle; - NTSTATUS status; - - if (NT_SUCCESS(status = pageContext->OpenObject( - &fileHandle, - GENERIC_WRITE, - pageContext->Context - ))) + switch (GET_WM_COMMAND_ID(wParam, lParam)) { - IO_STATUS_BLOCK ioStatusBlock; + case IDC_FLUSH: + { + NTSTATUS status; + HANDLE fileHandle; - status = NtFlushBuffersFile(fileHandle, &ioStatusBlock); - NtClose(fileHandle); - } + if (NT_SUCCESS(status = pageContext->OpenObject( + &fileHandle, + GENERIC_WRITE, + pageContext->Context + ))) + { + IO_STATUS_BLOCK ioStatusBlock; + + status = NtFlushBuffersFile(fileHandle, &ioStatusBlock); + NtClose(fileHandle); + } - if (!NT_SUCCESS(status)) - PhShowStatus(hwndDlg, L"Unable to flush the file buffer", status, 0); + if (!NT_SUCCESS(status)) + PhShowStatus(hwndDlg, L"Unable to flush the file buffer", status, 0); + } + break; + } } break; - } - } - break; } return FALSE; From f5fedf92e4e33098af1a724e1c31ac339b7c57c8 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 16 Apr 2018 08:46:00 +1000 Subject: [PATCH 0897/2058] Add missing line from previous commit --- ProcessHacker/ntobjprp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ProcessHacker/ntobjprp.c b/ProcessHacker/ntobjprp.c index 073c6e729781..25830ece149d 100644 --- a/ProcessHacker/ntobjprp.c +++ b/ProcessHacker/ntobjprp.c @@ -396,12 +396,12 @@ static VOID PhpRefreshFilePageInfo( PageContext->Context ))) { + NTSTATUS statusStandardInfo; IO_STATUS_BLOCK ioStatusBlock; FILE_MODE_INFORMATION fileModeInfo; FILE_STANDARD_INFORMATION fileStandardInfo; FILE_POSITION_INFORMATION filePositionInfo; FILE_FS_DEVICE_INFORMATION deviceInformation; - NTSTATUS statusStandardInfo; BOOLEAN disableFlushButton = FALSE; BOOLEAN isFileOrDirectory = FALSE; From c287cf7375f65f1ece2f15cc58d59a3c990134ae Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 16 Apr 2018 10:54:08 +1000 Subject: [PATCH 0898/2058] SetupTool: Fix updater installing KPH by default --- .../CustomSetupTool/include/setup.h | 6 +- .../CustomSetupTool/CustomSetupTool/install.c | 4 +- tools/CustomSetupTool/CustomSetupTool/setup.c | 82 +++++++++++++------ .../CustomSetupTool/CustomSetupTool/update.c | 3 +- 4 files changed, 66 insertions(+), 29 deletions(-) diff --git a/tools/CustomSetupTool/CustomSetupTool/include/setup.h b/tools/CustomSetupTool/CustomSetupTool/include/setup.h index f0625c8809a5..5b7fdb91efbb 100644 --- a/tools/CustomSetupTool/CustomSetupTool/include/setup.h +++ b/tools/CustomSetupTool/CustomSetupTool/include/setup.h @@ -109,7 +109,8 @@ typedef struct _PH_SETUP_CONTEXT ULONG SetupInstallKphService : 1; ULONG SetupResetSettings : 1; ULONG SetupStartAppAfterExit : 1; - ULONG Spare : 22; + ULONG SetupKphInstallRequired : 1; + ULONG Spare : 21; }; }; @@ -204,7 +205,8 @@ extern ULONG64 ExtractTotalLength; // setup.c VOID SetupStartKph( - _In_ PPH_SETUP_CONTEXT Context + _In_ PPH_SETUP_CONTEXT Context, + _In_ BOOLEAN ForceInstall ); BOOLEAN SetupUninstallKph( diff --git a/tools/CustomSetupTool/CustomSetupTool/install.c b/tools/CustomSetupTool/CustomSetupTool/install.c index 28e57eda6da7..d96bc33004d7 100644 --- a/tools/CustomSetupTool/CustomSetupTool/install.c +++ b/tools/CustomSetupTool/CustomSetupTool/install.c @@ -68,9 +68,9 @@ NTSTATUS SetupProgressThread( if (!SetupExtractBuild(Context)) goto CleanupExit; - // Install updated kernel driver + // Setup kernel driver. if (Context->SetupInstallKphService) - SetupStartKph(Context); + SetupStartKph(Context, TRUE); PhClearCacheDirectory(); diff --git a/tools/CustomSetupTool/CustomSetupTool/setup.c b/tools/CustomSetupTool/CustomSetupTool/setup.c index 399b0642b55d..9be35201cf2f 100644 --- a/tools/CustomSetupTool/CustomSetupTool/setup.c +++ b/tools/CustomSetupTool/CustomSetupTool/setup.c @@ -313,7 +313,7 @@ VOID SetupStartService( } } - Sleep(1000); + PhDelayExecution(1000); } while (--attempts != 0); } @@ -375,7 +375,7 @@ VOID SetupStopService( } } - Sleep(1000); + PhDelayExecution(1000); } while (--attempts != 0); } @@ -387,44 +387,78 @@ VOID SetupStopService( } } -VOID SetupStartKph( - _In_ PPH_SETUP_CONTEXT Context +BOOLEAN SetupKphCheckInstallState( + VOID ) { - PPH_STRING clientPath = PhConcatStrings2(PhGetString(Context->SetupInstallPath), L"\\ProcessHacker.exe"); + static PH_STRINGREF kph3ServiceKeyName = PH_STRINGREF_INIT(L"System\\CurrentControlSet\\Services\\KProcessHacker3"); + BOOLEAN kphInstallRequired = FALSE; + HANDLE runKeyHandle; - if (RtlDoesFileExists_U(PhGetString(clientPath))) + if (NT_SUCCESS(PhOpenKey( + &runKeyHandle, + KEY_READ, + PH_KEY_LOCAL_MACHINE, + &kph3ServiceKeyName, + 0 + ))) { - HANDLE processHandle; - LARGE_INTEGER timeout; - ULONG retries = 0; + // Make sure we re-install the driver when KPH was installed as a service. + if (PhQueryRegistryUlong(runKeyHandle, L"Start") == SERVICE_SYSTEM_START) + { + kphInstallRequired = TRUE; + } - timeout.QuadPart = -10 * PH_TIMEOUT_SEC; + NtClose(runKeyHandle); + } - if (PhShellExecuteEx( - NULL, - PhGetString(clientPath), - L"-installkph", - SW_NORMAL, - 0, - 0, - &processHandle - )) + return kphInstallRequired; +} + +VOID SetupStartKph( + _In_ PPH_SETUP_CONTEXT Context, + _In_ BOOLEAN ForceInstall + ) +{ + if (ForceInstall || Context->SetupKphInstallRequired) + { + PPH_STRING clientPath; + + clientPath = PhConcatStrings2(PhGetString(Context->SetupInstallPath), L"\\ProcessHacker.exe"); + + if (RtlDoesFileExists_U(PhGetString(clientPath))) { - NtWaitForSingleObject(processHandle, FALSE, &timeout); - NtClose(processHandle); + HANDLE processHandle; + + if (PhShellExecuteEx( + NULL, + PhGetString(clientPath), + L"-installkph", + SW_NORMAL, + 0, + 0, + &processHandle + )) + { + NtWaitForSingleObject(processHandle, FALSE, NULL); + NtClose(processHandle); + } } - SetupStartService(L"KProcessHacker3"); + PhDereferenceObject(clientPath); } - PhDereferenceObject(clientPath); + SetupStartService(L"KProcessHacker3"); } BOOLEAN SetupUninstallKph( _In_ PPH_SETUP_CONTEXT Context ) { + // Query the current KPH installation state. + Context->SetupKphInstallRequired = SetupKphCheckInstallState(); + + // Stop and uninstall the current installation. SetupStopService(L"KProcessHacker2"); SetupStopService(L"KProcessHacker3"); @@ -559,7 +593,7 @@ VOID SetupSetWindowsOptions( if (Context->SetupCreateSystemStartup) { NTSTATUS status; - HANDLE runKeyHandle = NULL; + HANDLE runKeyHandle; if (NT_SUCCESS(status = PhOpenKey( &runKeyHandle, diff --git a/tools/CustomSetupTool/CustomSetupTool/update.c b/tools/CustomSetupTool/CustomSetupTool/update.c index a45fcc04ed41..2813e29fdace 100644 --- a/tools/CustomSetupTool/CustomSetupTool/update.c +++ b/tools/CustomSetupTool/CustomSetupTool/update.c @@ -49,7 +49,8 @@ NTSTATUS SetupUpdateBuild( // Set the default image execution options. SetupCreateImageFileExecutionOptions(); - SetupStartKph(Context); + // Set the default KPH configuration. + SetupStartKph(Context, FALSE); if (!SetupExecuteProcessHacker(Context)) goto CleanupExit; From 311b451c1f7f2e255095d99cad8238e70e44b8ac Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 16 Apr 2018 11:18:07 +1000 Subject: [PATCH 0899/2058] Fix file tab filesize not using user settings --- ProcessHacker/ntobjprp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ProcessHacker/ntobjprp.c b/ProcessHacker/ntobjprp.c index 25830ece149d..ae561a3b91a0 100644 --- a/ProcessHacker/ntobjprp.c +++ b/ProcessHacker/ntobjprp.c @@ -449,7 +449,7 @@ static VOID PhpRefreshFilePageInfo( disableFlushButton |= fileStandardInfo.Directory; - fileSizeStr = PhFormatUInt64(fileStandardInfo.EndOfFile.QuadPart, TRUE); + fileSizeStr = PhFormatSize(fileStandardInfo.EndOfFile.QuadPart, -1); SetDlgItemText(hwndDlg, IDC_FILESIZE, fileSizeStr->Buffer); PhDereferenceObject(fileSizeStr); From c3a7411161794663f5fb130664f187e92d7ebcdd Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 19 Apr 2018 09:24:13 +1000 Subject: [PATCH 0900/2058] Tidy up --- ProcessHacker/appsup.c | 70 ----------- ProcessHacker/include/appsup.h | 8 -- ProcessHacker/include/procprv.h | 1 - ProcessHacker/modprv.c | 1 + ProcessHacker/procprv.c | 213 +------------------------------- phlib/appresolver.c | 70 +++++++++++ phlib/include/appresolver.h | 8 ++ phlib/include/appresolverp.h | 1 + phlib/include/verifyp.h | 14 +++ phlib/verify.c | 201 +++++++++++++++++++++++++++++- 10 files changed, 295 insertions(+), 292 deletions(-) diff --git a/ProcessHacker/appsup.c b/ProcessHacker/appsup.c index 00dd278ed0ff..d510526807aa 100644 --- a/ProcessHacker/appsup.c +++ b/ProcessHacker/appsup.c @@ -218,76 +218,6 @@ NTSTATUS PhGetProcessSwitchContext( return STATUS_SUCCESS; } -PPH_STRING PhGetProcessPackageFullName( - _In_ HANDLE ProcessHandle - ) -{ - HANDLE tokenHandle; - PTOKEN_SECURITY_ATTRIBUTES_INFORMATION info; - PPH_STRING name = NULL; - - if (NT_SUCCESS(PhOpenProcessToken( - ProcessHandle, - TOKEN_QUERY, - &tokenHandle - ))) - { - // rev from PackageIdFromFullName - if (NT_SUCCESS(PhQueryTokenVariableSize(tokenHandle, TokenSecurityAttributes, &info))) - { - for (ULONG i = 0; i < info->AttributeCount; i++) - { - static UNICODE_STRING attributeNameUs = RTL_CONSTANT_STRING(L"WIN://SYSAPPID"); - PTOKEN_SECURITY_ATTRIBUTE_V1 attribute = &info->Attribute.pAttributeV1[i]; - - if (RtlEqualUnicodeString(&attribute->Name, &attributeNameUs, FALSE)) - { - if (attribute->ValueType == TOKEN_SECURITY_ATTRIBUTE_TYPE_STRING) - { - name = PhCreateStringFromUnicodeString(&attribute->Values.pString[0]); - break; - } - } - } - - PhFree(info); - } - - NtClose(tokenHandle); - } - - return name; -} - -PPH_STRING PhGetPackagePath( - _In_ PPH_STRING PackageFullName - ) -{ - static PH_STRINGREF storeAppPackages = PH_STRINGREF_INIT(L"Software\\Classes\\Local Settings\\Software\\Microsoft\\Windows\\CurrentVersion\\AppModel\\Repository\\Packages\\"); - HANDLE keyHandle; - PPH_STRING keyPath; - PPH_STRING packagePath = NULL; - - keyPath = PhConcatStringRef2(&storeAppPackages, &PackageFullName->sr); - - // rev from GetPackagePath - if (NT_SUCCESS(PhOpenKey( - &keyHandle, - KEY_READ, - PH_KEY_CURRENT_USER, - &keyPath->sr, - 0 - ))) - { - packagePath = PhQueryRegistryString(keyHandle, L"PackageRootFolder"); - NtClose(keyHandle); - } - - PhDereferenceObject(keyPath); - - return packagePath; -} - /** * Determines the type of a process based on its image file name. * diff --git a/ProcessHacker/include/appsup.h b/ProcessHacker/include/appsup.h index 261fdd058666..128b3cbe227b 100644 --- a/ProcessHacker/include/appsup.h +++ b/ProcessHacker/include/appsup.h @@ -22,14 +22,6 @@ NTSTATUS PhGetProcessSwitchContext( _Out_ PGUID Guid ); -PPH_STRING PhGetProcessPackageFullName( - _In_ HANDLE ProcessHandle - ); - -PPH_STRING PhGetPackagePath( - _In_ PPH_STRING PackageFullName - ); - // begin_phapppub typedef enum _PH_KNOWN_PROCESS_TYPE { diff --git a/ProcessHacker/include/procprv.h b/ProcessHacker/include/procprv.h index 6b6d218ce201..13fb02dfafef 100644 --- a/ProcessHacker/include/procprv.h +++ b/ProcessHacker/include/procprv.h @@ -2,7 +2,6 @@ #define PH_PROCPRV_H #define PH_RECORD_MAX_USAGE -#define PH_ENABLE_VERIFY_CACHE extern PPH_OBJECT_TYPE PhProcessItemType; diff --git a/ProcessHacker/modprv.c b/ProcessHacker/modprv.c index 66b26760675f..0c59975c48df 100644 --- a/ProcessHacker/modprv.c +++ b/ProcessHacker/modprv.c @@ -21,6 +21,7 @@ */ #include +#include #include #include diff --git a/ProcessHacker/procprv.c b/ProcessHacker/procprv.c index ece16bdff108..fb7bebfeba74 100644 --- a/ProcessHacker/procprv.c +++ b/ProcessHacker/procprv.c @@ -54,6 +54,7 @@ #include #include #include +#include #include #include @@ -125,15 +126,6 @@ typedef struct _PH_PROCESS_QUERY_S2_DATA ULONG ImportModules; } PH_PROCESS_QUERY_S2_DATA, *PPH_PROCESS_QUERY_S2_DATA; -typedef struct _PH_VERIFY_CACHE_ENTRY -{ - PH_AVL_LINKS Links; - - PPH_STRING FileName; - VERIFY_RESULT VerifyResult; - PPH_STRING VerifySignerName; -} PH_VERIFY_CACHE_ENTRY, *PPH_VERIFY_CACHE_ENTRY; - typedef struct _PH_SID_FULL_NAME_CACHE_ENTRY { PSID Sid; @@ -145,11 +137,6 @@ VOID NTAPI PhpProcessItemDeleteProcedure( _In_ ULONG Flags ); -INT NTAPI PhpVerifyCacheCompareFunction( - _In_ PPH_AVL_LINKS Links1, - _In_ PPH_AVL_LINKS Links2 - ); - VOID PhpQueueProcessQueryStage1( _In_ PPH_PROCESS_ITEM ProcessItem ); @@ -254,12 +241,6 @@ PH_CIRCULAR_BUFFER_ULONG64 PhMaxIoWriteHistory; static PTS_ALL_PROCESSES_INFO PhpTsProcesses = NULL; static ULONG PhpTsNumberOfProcesses; - -#ifdef PH_ENABLE_VERIFY_CACHE -static PH_AVL_TREE PhpVerifyCacheSet = PH_AVL_TREE_INIT(PhpVerifyCacheCompareFunction); -static PH_QUEUED_LOCK PhpVerifyCacheLock = PH_QUEUED_LOCK_INIT; -#endif - static PPH_HASHTABLE PhpSidFullNameCacheHashtable; BOOLEAN PhProcessProviderInitialization( @@ -665,198 +646,6 @@ VOID PhpRemoveProcessItem( PhDereferenceObject(ProcessItem); } -INT NTAPI PhpVerifyCacheCompareFunction( - _In_ PPH_AVL_LINKS Links1, - _In_ PPH_AVL_LINKS Links2 - ) -{ - PPH_VERIFY_CACHE_ENTRY entry1 = CONTAINING_RECORD(Links1, PH_VERIFY_CACHE_ENTRY, Links); - PPH_VERIFY_CACHE_ENTRY entry2 = CONTAINING_RECORD(Links2, PH_VERIFY_CACHE_ENTRY, Links); - - return PhCompareString(entry1->FileName, entry2->FileName, TRUE); -} - -VERIFY_RESULT PhVerifyFileWithAdditionalCatalog( - _In_ PPH_VERIFY_FILE_INFO Information, - _In_opt_ PPH_STRING PackageFullName, - _Out_opt_ PPH_STRING *SignerName - ) -{ - static PH_STRINGREF codeIntegrityFileName = PH_STRINGREF_INIT(L"\\AppxMetadata\\CodeIntegrity.cat"); - - VERIFY_RESULT result; - PPH_STRING additionalCatalogFileName = NULL; - PCERT_CONTEXT *signatures; - ULONG numberOfSignatures; - - if (PackageFullName) - { - PPH_STRING packagePath; - - if (packagePath = PhGetPackagePath(PackageFullName)) - { - additionalCatalogFileName = PhConcatStringRef2(&packagePath->sr, &codeIntegrityFileName); - PhDereferenceObject(packagePath); - } - } - - if (additionalCatalogFileName) - { - Information->NumberOfCatalogFileNames = 1; - Information->CatalogFileNames = &additionalCatalogFileName->Buffer; - } - - if (!NT_SUCCESS(PhVerifyFileEx(Information, &result, &signatures, &numberOfSignatures))) - { - result = VrNoSignature; - signatures = NULL; - numberOfSignatures = 0; - } - - if (additionalCatalogFileName) - PhDereferenceObject(additionalCatalogFileName); - - if (SignerName) - { - if (numberOfSignatures != 0) - *SignerName = PhGetSignerNameFromCertificate(signatures[0]); - else - *SignerName = NULL; - } - - PhFreeVerifySignatures(signatures, numberOfSignatures); - - return result; -} - -/** - * Verifies a file's digital signature, using a cached result if possible. - * - * \param FileName A file name. - * \param ProcessItem An associated process item. - * \param SignerName A variable which receives a pointer to a string containing the signer name. You - * must free the string using PhDereferenceObject() when you no longer need it. Note that the signer - * name may be NULL if it is not valid. - * \param CachedOnly Specify TRUE to fail the function when no cached result exists. - * - * \return A VERIFY_RESULT value. - */ -VERIFY_RESULT PhVerifyFileCached( - _In_ PPH_STRING FileName, - _In_opt_ PPH_STRING PackageFullName, - _Out_opt_ PPH_STRING *SignerName, - _In_ BOOLEAN CachedOnly - ) -{ -#ifdef PH_ENABLE_VERIFY_CACHE - PPH_AVL_LINKS links; - PPH_VERIFY_CACHE_ENTRY entry; - PH_VERIFY_CACHE_ENTRY lookupEntry; - - lookupEntry.FileName = FileName; - - PhAcquireQueuedLockShared(&PhpVerifyCacheLock); - links = PhFindElementAvlTree(&PhpVerifyCacheSet, &lookupEntry.Links); - PhReleaseQueuedLockShared(&PhpVerifyCacheLock); - - if (links) - { - entry = CONTAINING_RECORD(links, PH_VERIFY_CACHE_ENTRY, Links); - - if (SignerName) - PhSetReference(SignerName, entry->VerifySignerName); - - return entry->VerifyResult; - } - else - { - VERIFY_RESULT result; - PPH_STRING signerName; - - if (!CachedOnly) - { - PH_VERIFY_FILE_INFO info; - - memset(&info, 0, sizeof(PH_VERIFY_FILE_INFO)); - info.FileName = FileName->Buffer; - info.Flags = PH_VERIFY_PREVENT_NETWORK_ACCESS; - result = PhVerifyFileWithAdditionalCatalog(&info, PackageFullName, &signerName); - - if (result != VrTrusted) - PhClearReference(&signerName); - } - else - { - result = VrUnknown; - signerName = NULL; - } - - if (result != VrUnknown) - { - entry = PhAllocate(sizeof(PH_VERIFY_CACHE_ENTRY)); - entry->FileName = FileName; - entry->VerifyResult = result; - entry->VerifySignerName = signerName; - - PhAcquireQueuedLockExclusive(&PhpVerifyCacheLock); - links = PhAddElementAvlTree(&PhpVerifyCacheSet, &entry->Links); - PhReleaseQueuedLockExclusive(&PhpVerifyCacheLock); - - if (!links) - { - // We successfully added the cache entry. Add references. - - PhReferenceObject(entry->FileName); - - if (entry->VerifySignerName) - PhReferenceObject(entry->VerifySignerName); - } - else - { - // Entry already exists. - PhFree(entry); - } - } - - if (SignerName) - { - *SignerName = signerName; - } - else - { - if (signerName) - PhDereferenceObject(signerName); - } - - return result; - } -#else - VERIFY_RESULT result; - PPH_STRING signerName; - PH_VERIFY_FILE_INFO info; - - memset(&info, 0, sizeof(PH_VERIFY_FILE_INFO)); - info.FileName = FileName->Buffer; - info.Flags = PH_VERIFY_PREVENT_NETWORK_ACCESS; - result = PhVerifyFileWithAdditionalCatalog(&info, PackageFullName, &signerName); - - if (result != VrTrusted) - PhClearReference(&signerName); - - if (SignerName) - { - *SignerName = signerName; - } - else - { - if (signerName) - PhDereferenceObject(signerName); - } - - return result; -#endif -} - BOOLEAN PhpSidFullNameCacheHashtableEqualFunction( _In_ PVOID Entry1, _In_ PVOID Entry2 diff --git a/phlib/appresolver.c b/phlib/appresolver.c index fc0c3cacf8bb..bf1558fc4155 100644 --- a/phlib/appresolver.c +++ b/phlib/appresolver.c @@ -294,6 +294,76 @@ PPH_STRING PhGetAppContainerPackageName( return packageName; } +PPH_STRING PhGetPackagePath( + _In_ PPH_STRING PackageFullName + ) +{ + static PH_STRINGREF storeAppPackages = PH_STRINGREF_INIT(L"Software\\Classes\\Local Settings\\Software\\Microsoft\\Windows\\CurrentVersion\\AppModel\\Repository\\Packages\\"); + HANDLE keyHandle; + PPH_STRING keyPath; + PPH_STRING packagePath = NULL; + + keyPath = PhConcatStringRef2(&storeAppPackages, &PackageFullName->sr); + + // rev from GetPackagePath + if (NT_SUCCESS(PhOpenKey( + &keyHandle, + KEY_READ, + PH_KEY_CURRENT_USER, + &keyPath->sr, + 0 + ))) + { + packagePath = PhQueryRegistryString(keyHandle, L"PackageRootFolder"); + NtClose(keyHandle); + } + + PhDereferenceObject(keyPath); + + return packagePath; +} + +PPH_STRING PhGetProcessPackageFullName( + _In_ HANDLE ProcessHandle + ) +{ + HANDLE tokenHandle; + PTOKEN_SECURITY_ATTRIBUTES_INFORMATION info; + PPH_STRING packageName = NULL; + + if (NT_SUCCESS(PhOpenProcessToken( + ProcessHandle, + TOKEN_QUERY, + &tokenHandle + ))) + { + // rev from PackageIdFromFullName + if (NT_SUCCESS(PhQueryTokenVariableSize(tokenHandle, TokenSecurityAttributes, &info))) + { + for (ULONG i = 0; i < info->AttributeCount; i++) + { + static UNICODE_STRING attributeNameUs = RTL_CONSTANT_STRING(L"WIN://SYSAPPID"); + PTOKEN_SECURITY_ATTRIBUTE_V1 attribute = &info->Attribute.pAttributeV1[i]; + + if (RtlEqualUnicodeString(&attribute->Name, &attributeNameUs, FALSE)) + { + if (attribute->ValueType == TOKEN_SECURITY_ATTRIBUTE_TYPE_STRING) + { + packageName = PhCreateStringFromUnicodeString(&attribute->Values.pString[0]); + break; + } + } + } + + PhFree(info); + } + + NtClose(tokenHandle); + } + + return packageName; +} + BOOLEAN PhGetAppWindowingModel( _In_ HANDLE ProcessTokenHandle, _Out_ AppPolicyWindowingModel *ProcessWindowingModelPolicy diff --git a/phlib/include/appresolver.h b/phlib/include/appresolver.h index 70094fafb8be..588ac78f63d3 100644 --- a/phlib/include/appresolver.h +++ b/phlib/include/appresolver.h @@ -51,6 +51,14 @@ PPH_STRING PhGetAppContainerPackageName( _In_ PSID Sid ); +PPH_STRING PhGetProcessPackageFullName( + _In_ HANDLE ProcessHandle + ); + +PPH_STRING PhGetPackagePath( + _In_ PPH_STRING PackageFullName + ); + PPH_LIST PhGetPackageAssetsFromResourceFile( _In_ PWSTR FilePath ); diff --git a/phlib/include/appresolverp.h b/phlib/include/appresolverp.h index 790cb406a8f0..89d71a8adf39 100644 --- a/phlib/include/appresolverp.h +++ b/phlib/include/appresolverp.h @@ -48,6 +48,7 @@ static HRESULT (WINAPI* AppContainerDeriveSidFromMoniker_I)( // DeriveAppContain _Out_ PSID *AppContainerSid ) = NULL; +// Note: LookupAppContainerDisplayName (userenv.dll, ordinal 211) has the same prototype but returns 'PackageName/ContainerName'. static HRESULT (WINAPI* AppContainerLookupMoniker_I)( _In_ PSID AppContainerSid, _Out_ PWSTR *PackageFamilyName diff --git a/phlib/include/verifyp.h b/phlib/include/verifyp.h index cc308d6758cb..65831d223f07 100644 --- a/phlib/include/verifyp.h +++ b/phlib/include/verifyp.h @@ -3,6 +3,20 @@ #include +typedef struct _PH_VERIFY_CACHE_ENTRY +{ + PH_AVL_LINKS Links; + + PPH_STRING FileName; + VERIFY_RESULT VerifyResult; + PPH_STRING VerifySignerName; +} PH_VERIFY_CACHE_ENTRY, *PPH_VERIFY_CACHE_ENTRY; + +INT NTAPI PhpVerifyCacheCompareFunction( + _In_ PPH_AVL_LINKS Links1, + _In_ PPH_AVL_LINKS Links2 + ); + typedef struct _CATALOG_INFO { ULONG cbStruct; diff --git a/phlib/verify.c b/phlib/verify.c index 7a0caef23c3b..7bfddad6c6ff 100644 --- a/phlib/verify.c +++ b/phlib/verify.c @@ -20,7 +20,9 @@ * along with Process Hacker. If not, see . */ +#define PH_ENABLE_VERIFY_CACHE #include +#include #include #include @@ -38,11 +40,16 @@ _WinVerifyTrust WinVerifyTrust_I; _CertNameToStr CertNameToStr_I; _CertDuplicateCertificateContext CertDuplicateCertificateContext_I; _CertFreeCertificateContext CertFreeCertificateContext_I; -static PH_INITONCE PhpVerifyInitOnce = PH_INITONCE_INIT; +static PH_INITONCE PhpVerifyInitOnce = PH_INITONCE_INIT; static GUID WinTrustActionGenericVerifyV2 = WINTRUST_ACTION_GENERIC_VERIFY_V2; static GUID DriverActionVerify = DRIVER_ACTION_VERIFY; +#ifdef PH_ENABLE_VERIFY_CACHE +static PH_AVL_TREE PhpVerifyCacheSet = PH_AVL_TREE_INIT(PhpVerifyCacheCompareFunction); +static PH_QUEUED_LOCK PhpVerifyCacheLock = PH_QUEUED_LOCK_INIT; +#endif + static VOID PhpVerifyInitialization( VOID ) @@ -666,3 +673,195 @@ VERIFY_RESULT PhVerifyFile( return VrNoSignature; } } + +INT NTAPI PhpVerifyCacheCompareFunction( + _In_ PPH_AVL_LINKS Links1, + _In_ PPH_AVL_LINKS Links2 + ) +{ + PPH_VERIFY_CACHE_ENTRY entry1 = CONTAINING_RECORD(Links1, PH_VERIFY_CACHE_ENTRY, Links); + PPH_VERIFY_CACHE_ENTRY entry2 = CONTAINING_RECORD(Links2, PH_VERIFY_CACHE_ENTRY, Links); + + return PhCompareString(entry1->FileName, entry2->FileName, TRUE); +} + +VERIFY_RESULT PhVerifyFileWithAdditionalCatalog( + _In_ PPH_VERIFY_FILE_INFO Information, + _In_opt_ PPH_STRING PackageFullName, + _Out_opt_ PPH_STRING *SignerName + ) +{ + static PH_STRINGREF codeIntegrityFileName = PH_STRINGREF_INIT(L"\\AppxMetadata\\CodeIntegrity.cat"); + + VERIFY_RESULT result; + PPH_STRING additionalCatalogFileName = NULL; + PCERT_CONTEXT *signatures; + ULONG numberOfSignatures; + + if (PackageFullName) + { + PPH_STRING packagePath; + + if (packagePath = PhGetPackagePath(PackageFullName)) + { + additionalCatalogFileName = PhConcatStringRef2(&packagePath->sr, &codeIntegrityFileName); + PhDereferenceObject(packagePath); + } + } + + if (additionalCatalogFileName) + { + Information->NumberOfCatalogFileNames = 1; + Information->CatalogFileNames = &additionalCatalogFileName->Buffer; + } + + if (!NT_SUCCESS(PhVerifyFileEx(Information, &result, &signatures, &numberOfSignatures))) + { + result = VrNoSignature; + signatures = NULL; + numberOfSignatures = 0; + } + + if (additionalCatalogFileName) + PhDereferenceObject(additionalCatalogFileName); + + if (SignerName) + { + if (numberOfSignatures != 0) + *SignerName = PhGetSignerNameFromCertificate(signatures[0]); + else + *SignerName = NULL; + } + + PhFreeVerifySignatures(signatures, numberOfSignatures); + + return result; +} + +/** + * Verifies a file's digital signature, using a cached result if possible. + * + * \param FileName A file name. + * \param ProcessItem An associated process item. + * \param SignerName A variable which receives a pointer to a string containing the signer name. You + * must free the string using PhDereferenceObject() when you no longer need it. Note that the signer + * name may be NULL if it is not valid. + * \param CachedOnly Specify TRUE to fail the function when no cached result exists. + * + * \return A VERIFY_RESULT value. + */ +VERIFY_RESULT PhVerifyFileCached( + _In_ PPH_STRING FileName, + _In_opt_ PPH_STRING PackageFullName, + _Out_opt_ PPH_STRING *SignerName, + _In_ BOOLEAN CachedOnly + ) +{ +#ifdef PH_ENABLE_VERIFY_CACHE + PPH_AVL_LINKS links; + PPH_VERIFY_CACHE_ENTRY entry; + PH_VERIFY_CACHE_ENTRY lookupEntry; + + lookupEntry.FileName = FileName; + + PhAcquireQueuedLockShared(&PhpVerifyCacheLock); + links = PhFindElementAvlTree(&PhpVerifyCacheSet, &lookupEntry.Links); + PhReleaseQueuedLockShared(&PhpVerifyCacheLock); + + if (links) + { + entry = CONTAINING_RECORD(links, PH_VERIFY_CACHE_ENTRY, Links); + + if (SignerName) + PhSetReference(SignerName, entry->VerifySignerName); + + return entry->VerifyResult; + } + else + { + VERIFY_RESULT result; + PPH_STRING signerName; + + if (!CachedOnly) + { + PH_VERIFY_FILE_INFO info; + + memset(&info, 0, sizeof(PH_VERIFY_FILE_INFO)); + info.FileName = FileName->Buffer; + info.Flags = PH_VERIFY_PREVENT_NETWORK_ACCESS; + result = PhVerifyFileWithAdditionalCatalog(&info, PackageFullName, &signerName); + + if (result != VrTrusted) + PhClearReference(&signerName); + } + else + { + result = VrUnknown; + signerName = NULL; + } + + if (result != VrUnknown) + { + entry = PhAllocate(sizeof(PH_VERIFY_CACHE_ENTRY)); + entry->FileName = FileName; + entry->VerifyResult = result; + entry->VerifySignerName = signerName; + + PhAcquireQueuedLockExclusive(&PhpVerifyCacheLock); + links = PhAddElementAvlTree(&PhpVerifyCacheSet, &entry->Links); + PhReleaseQueuedLockExclusive(&PhpVerifyCacheLock); + + if (!links) + { + // We successfully added the cache entry. Add references. + + PhReferenceObject(entry->FileName); + + if (entry->VerifySignerName) + PhReferenceObject(entry->VerifySignerName); + } + else + { + // Entry already exists. + PhFree(entry); + } + } + + if (SignerName) + { + *SignerName = signerName; + } + else + { + if (signerName) + PhDereferenceObject(signerName); + } + + return result; + } +#else + VERIFY_RESULT result; + PPH_STRING signerName; + PH_VERIFY_FILE_INFO info; + + memset(&info, 0, sizeof(PH_VERIFY_FILE_INFO)); + info.FileName = FileName->Buffer; + info.Flags = PH_VERIFY_PREVENT_NETWORK_ACCESS; + result = PhVerifyFileWithAdditionalCatalog(&info, PackageFullName, &signerName); + + if (result != VrTrusted) + PhClearReference(&signerName); + + if (SignerName) + { + *SignerName = signerName; + } + else + { + if (signerName) + PhDereferenceObject(signerName); + } + + return result; +#endif +} From a3d23a09668421b01f05071d834005dc66053a61 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 19 Apr 2018 09:25:17 +1000 Subject: [PATCH 0901/2058] HardwareDevices: Fix missing SMART info for SSDs --- plugins/HardwareDevices/devices.h | 23 ++++++++++++++++++----- plugins/HardwareDevices/diskdetails.c | 8 ++++++++ plugins/HardwareDevices/storage.c | 20 +++++++++++++++++++- 3 files changed, 45 insertions(+), 6 deletions(-) diff --git a/plugins/HardwareDevices/devices.h b/plugins/HardwareDevices/devices.h index d4b8cc9923b1..c871b4f371a1 100644 --- a/plugins/HardwareDevices/devices.h +++ b/plugins/HardwareDevices/devices.h @@ -725,6 +725,7 @@ NTSTATUS DiskDriveQueryVolumeAttributes( _Out_ PFILE_FS_ATTRIBUTE_INFORMATION* AttributeInfo ); +// https://en.wikipedia.org/wiki/S.M.A.R.T.#Known_ATA_S.M.A.R.T._attributes typedef enum _SMART_ATTRIBUTE_ID { SMART_ATTRIBUTE_ID_READ_ERROR_RATE = 0x01, @@ -740,7 +741,16 @@ typedef enum _SMART_ATTRIBUTE_ID SMART_ATTRIBUTE_ID_CALIBRATION_RETRY_COUNT = 0x0B, SMART_ATTRIBUTE_ID_POWER_CYCLE_COUNT = 0x0C, SMART_ATTRIBUTE_ID_SOFT_READ_ERROR_RATE = 0x0D, - // Unknown values 14-182 + // TODO: Add values 14-170 + SMART_ATTRIBUTE_ID_SSD_PROGRAM_FAIL_COUNT = 0xAB, + SMART_ATTRIBUTE_ID_SSD_ERASE_FAIL_COUNT = 0xAC, + SMART_ATTRIBUTE_ID_SSD_WEAR_LEVELING_COUNT = 0xAD, + SMART_ATTRIBUTE_ID_UNEXPECTED_POWER_LOSS = 0xAE, + // TODO: Add values 175-176 + SMART_ATTRIBUTE_ID_WEAR_RANGE_DELTA = 0xB1, + // TODO: Add values 178-180 + SMART_ATTRIBUTE_ID_SSD_PROGRAM_FAIL_COUNT_TOTAL = 0xB5, + SMART_ATTRIBUTE_ID_ERASE_FAIL_COUNT = 0xB6, SMART_ATTRIBUTE_ID_SATA_DOWNSHIFT_ERROR_COUNT = 0xB7, SMART_ATTRIBUTE_ID_END_TO_END_ERROR = 0xB8, SMART_ATTRIBUTE_ID_HEAD_STABILITY = 0xB9, @@ -779,16 +789,19 @@ typedef enum _SMART_ATTRIBUTE_ID SMART_ATTRIBUTE_ID_LOAD_IN_TIME = 0xE2, SMART_ATTRIBUTE_ID_TORQUE_AMPLIFICATION_COUNT = 0xE3, SMART_ATTRIBUTE_ID_POWER_OFF_RETTRACT_CYCLE = 0xE4, - // Unknown values 229 + // TODO: Add value 229 SMART_ATTRIBUTE_ID_GMR_HEAD_AMPLITUDE = 0xE6, SMART_ATTRIBUTE_ID_DRIVE_TEMPERATURE = 0xE7, - // Unknown values 232-239 + // TODO: Add value 232 + SMART_ATTRIBUTE_ID_SSD_MEDIA_WEAROUT_HOURS = 0xE9, + SMART_ATTRIBUTE_ID_SSD_ERASE_COUNT = 0xEA, + // TODO: Add values 235-239 SMART_ATTRIBUTE_ID_HEAD_FLYING_HOURS = 0xF0, SMART_ATTRIBUTE_ID_TOTAL_LBA_WRITTEN = 0xF1, SMART_ATTRIBUTE_ID_TOTAL_LBA_READ = 0xF2, - // Unknown values 243-249 + // TODO: Add values 243-249 SMART_ATTRIBUTE_ID_READ_ERROR_RETY_RATE = 0xFA, - // Unknown values 251-253 + // TODO: Add values 251-253 SMART_ATTRIBUTE_ID_FREE_FALL_PROTECTION = 0xFE, } SMART_ATTRIBUTE_ID; diff --git a/plugins/HardwareDevices/diskdetails.c b/plugins/HardwareDevices/diskdetails.c index 79986e5bbf1f..1a713af152aa 100644 --- a/plugins/HardwareDevices/diskdetails.c +++ b/plugins/HardwareDevices/diskdetails.c @@ -192,6 +192,13 @@ VOID DiskDriveQuerySmart( 3, PhaFormatString(L"%lu", attribute->RawValue)->Buffer ); + + PhSetListViewSubItem( + Context->ListViewHandle, + lvItemIndex, + 4, + PhaFormatString(L"%#014x", attribute->RawValue)->Buffer + ); } PhFree(attribute); @@ -679,6 +686,7 @@ INT_PTR CALLBACK DiskDriveSmartDetailsDlgProc( PhAddListViewColumn(context->ListViewHandle, 1, 1, 1, LVCFMT_LEFT, 50, L"Value"); PhAddListViewColumn(context->ListViewHandle, 2, 2, 2, LVCFMT_LEFT, 50, L"Best"); PhAddListViewColumn(context->ListViewHandle, 3, 3, 3, LVCFMT_LEFT, 80, L"Raw"); + PhAddListViewColumn(context->ListViewHandle, 4, 4, 4, LVCFMT_LEFT, 80, L"Raw (Hex)"); PhSetExtendedListView(context->ListViewHandle); //ExtendedListView_SetItemColorFunction(context->ListViewHandle, PhpColorItemColorFunction); PhLoadListViewColumnsFromSetting(SETTING_NAME_SMART_COUNTERS_COLUMNS, context->ListViewHandle); diff --git a/plugins/HardwareDevices/storage.c b/plugins/HardwareDevices/storage.c index 2be01224b59c..654151433752 100644 --- a/plugins/HardwareDevices/storage.c +++ b/plugins/HardwareDevices/storage.c @@ -1499,7 +1499,25 @@ PWSTR SmartAttributeGetText( return L"Read Error Retry Rate"; case SMART_ATTRIBUTE_ID_FREE_FALL_PROTECTION: return L"Free Fall Protection"; + case SMART_ATTRIBUTE_ID_SSD_PROGRAM_FAIL_COUNT: + return L"SSD Program Fail Count"; + case SMART_ATTRIBUTE_ID_SSD_ERASE_FAIL_COUNT: + return L"SSD Erase Fail Count"; + case SMART_ATTRIBUTE_ID_SSD_WEAR_LEVELING_COUNT: + return L"SSD Wear Leveling Count"; + case SMART_ATTRIBUTE_ID_UNEXPECTED_POWER_LOSS: + return L"Unexpected power loss count"; + case SMART_ATTRIBUTE_ID_WEAR_RANGE_DELTA: + return L"Wear Range Delta"; + case SMART_ATTRIBUTE_ID_SSD_PROGRAM_FAIL_COUNT_TOTAL: + return L"Program Fail Count Total"; + case SMART_ATTRIBUTE_ID_ERASE_FAIL_COUNT: + return L"Erase Fail Count"; + case SMART_ATTRIBUTE_ID_SSD_MEDIA_WEAROUT_HOURS: + return L"Media Wearout Indicator"; + case SMART_ATTRIBUTE_ID_SSD_ERASE_COUNT: + return L"Erase count"; } - return L"Unknown"; + return L"BUG BUG BUG"; } \ No newline at end of file From b704af745a78e1f1954e539332bb122b796ef5a7 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 19 Apr 2018 09:28:11 +1000 Subject: [PATCH 0902/2058] Add PhRemoveMemoryNode function --- ProcessHacker/include/memlist.h | 6 ++++++ ProcessHacker/memlist.c | 27 +++++++++++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/ProcessHacker/include/memlist.h b/ProcessHacker/include/memlist.h index a7f714d32fa8..4a35acc97de2 100644 --- a/ProcessHacker/include/memlist.h +++ b/ProcessHacker/include/memlist.h @@ -117,6 +117,12 @@ VOID PhReplaceMemoryList( _In_opt_ PPH_MEMORY_ITEM_LIST List ); +VOID PhRemoveMemoryNode( + _Inout_ PPH_MEMORY_LIST_CONTEXT Context, + _In_ PPH_MEMORY_ITEM_LIST List, + _In_ PPH_MEMORY_NODE MemoryNode + ); + VOID PhUpdateMemoryNode( _In_ PPH_MEMORY_LIST_CONTEXT Context, _In_ PPH_MEMORY_NODE MemoryNode diff --git a/ProcessHacker/memlist.c b/ProcessHacker/memlist.c index 687fbf275c0f..61604aaeaa4b 100644 --- a/ProcessHacker/memlist.c +++ b/ProcessHacker/memlist.c @@ -376,6 +376,33 @@ VOID PhReplaceMemoryList( TreeNew_NodesStructured(Context->TreeNewHandle); } +VOID PhRemoveMemoryNode( + _Inout_ PPH_MEMORY_LIST_CONTEXT Context, + _In_ PPH_MEMORY_ITEM_LIST List, + _In_ PPH_MEMORY_NODE MemoryNode + ) +{ + ULONG index; + + // Remove from list and cleanup. + + PhRemoveElementAvlTree(&List->Set, &MemoryNode->MemoryItem->Links); + RemoveEntryList(&MemoryNode->MemoryItem->ListEntry); + + if ((index = PhFindItemList(Context->RegionNodeList, MemoryNode)) != -1) + PhRemoveItemList(Context->RegionNodeList, index); + + if (MemoryNode->MemoryItem->AllocationBaseItem == MemoryNode->MemoryItem) + { + if ((index = PhFindItemList(Context->AllocationBaseNodeList, MemoryNode->Parent)) != -1) + PhRemoveItemList(Context->AllocationBaseNodeList, index); + } + + PhpDestroyMemoryNode(MemoryNode); + + TreeNew_NodesStructured(Context->TreeNewHandle); +} + VOID PhUpdateMemoryNode( _In_ PPH_MEMORY_LIST_CONTEXT Context, _In_ PPH_MEMORY_NODE MemoryNode From bfd5f942a48b92c848d1bdcaa2dfb2bc7556eeb7 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 19 Apr 2018 09:32:04 +1000 Subject: [PATCH 0903/2058] Remove unused process extended statistics --- ProcessHacker/prpgstat.c | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/ProcessHacker/prpgstat.c b/ProcessHacker/prpgstat.c index 61c7b7b75a58..6bf227603184 100644 --- a/ProcessHacker/prpgstat.c +++ b/ProcessHacker/prpgstat.c @@ -70,12 +70,10 @@ typedef enum _PH_PROCESS_STATISTICS_INDEX PH_PROCESS_STATISTICS_INDEX_USERHANDLES, PH_PROCESS_STATISTICS_INDEX_CONTEXTSWITCHES, - PH_PROCESS_STATISTICS_INDEX_DISKENERGY, - PH_PROCESS_STATISTICS_INDEX_NETWORKTAILENERGY, - PH_PROCESS_STATISTICS_INDEX_MBBTAILENERGY, + PH_PROCESS_STATISTICS_INDEX_DISKREAD, + PH_PROCESS_STATISTICS_INDEX_DISKWRITE, PH_PROCESS_STATISTICS_INDEX_NETWORKTXRXBYTES, - PH_PROCESS_STATISTICS_INDEX_MBBTXRXBYTES, - PH_PROCESS_STATISTICS_INDEX_FOREGROUNDDURATION + PH_PROCESS_STATISTICS_INDEX_MBBTXRXBYTES } PH_PROCESS_STATISTICS_INDEX; VOID PhpUpdateStatisticsAddListViewGroups( @@ -121,12 +119,10 @@ VOID PhpUpdateStatisticsAddListViewGroups( if (WindowsVersion >= WINDOWS_10_RS3 && !PhIsExecutingInWow64()) { PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_EXTENSION, PH_PROCESS_STATISTICS_INDEX_CONTEXTSWITCHES, L"ContextSwitches", NULL); - PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_EXTENSION, PH_PROCESS_STATISTICS_INDEX_DISKENERGY, L"DiskEnergy", NULL); - PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_EXTENSION, PH_PROCESS_STATISTICS_INDEX_NETWORKTAILENERGY, L"NetworkTailEnergy", NULL); - PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_EXTENSION, PH_PROCESS_STATISTICS_INDEX_MBBTAILENERGY, L"MBBTailEnergy", NULL); + PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_EXTENSION, PH_PROCESS_STATISTICS_INDEX_DISKREAD, L"BytesRead", NULL); + PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_EXTENSION, PH_PROCESS_STATISTICS_INDEX_DISKWRITE, L"BytesWritten", NULL); PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_EXTENSION, PH_PROCESS_STATISTICS_INDEX_NETWORKTXRXBYTES, L"NetworkTxRxBytes", NULL); PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_EXTENSION, PH_PROCESS_STATISTICS_INDEX_MBBTXRXBYTES, L"MBBTxRxBytes", NULL); - PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_EXTENSION, PH_PROCESS_STATISTICS_INDEX_FOREGROUNDDURATION, L"ForegroundDuration", NULL); } } @@ -247,18 +243,16 @@ VOID PhpUpdateProcessStatistics( if (NT_SUCCESS(PhEnumProcesses(&processes))) { processInfo = PhFindProcessInformation(processes, ProcessItem->ProcessId); - + if (processInfo && (processExtension = PH_PROCESS_EXTENSION(processInfo))) { PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_CONTEXTSWITCHES, 1, PhaFormatUInt64(processExtension->ContextSwitches, TRUE)->Buffer); - PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_DISKENERGY, 1, PhaFormatUInt64(processExtension->EnergyValues.DiskEnergy, TRUE)->Buffer); - PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_NETWORKTAILENERGY, 1, PhaFormatSize(processExtension->EnergyValues.NetworkTailEnergy, -1)->Buffer); - PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_MBBTAILENERGY, 1, PhaFormatSize(processExtension->EnergyValues.MBBTailEnergy, -1)->Buffer); + PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_DISKREAD, 1, PhaFormatSize(processExtension->DiskCounters.BytesRead, -1)->Buffer); + PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_DISKWRITE, 1, PhaFormatSize(processExtension->DiskCounters.BytesWritten, -1)->Buffer); PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_NETWORKTXRXBYTES, 1, PhaFormatSize(processExtension->EnergyValues.NetworkTxRxBytes, -1)->Buffer); PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_MBBTXRXBYTES, 1, PhaFormatSize(processExtension->EnergyValues.MBBTxRxBytes, -1)->Buffer); - PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_FOREGROUNDDURATION, 1, PhaFormatUInt64(processExtension->EnergyValues.ForegroundDuration.Value, TRUE)->Buffer); } - + PhFree(processes); } } From d29d4329005d9e827d9eb5022e85f20d182f913d Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 19 Apr 2018 09:33:10 +1000 Subject: [PATCH 0904/2058] Improve service tab highlighting, Add new Options -> Highlighting color settings --- ProcessHacker/include/phsettings.h | 8 ++++---- ProcessHacker/options.c | 6 +++++- ProcessHacker/proctree.c | 4 ++-- ProcessHacker/settings.c | 12 ++++++------ ProcessHacker/srvlist.c | 14 +++++++++++--- 5 files changed, 28 insertions(+), 16 deletions(-) diff --git a/ProcessHacker/include/phsettings.h b/ProcessHacker/include/phsettings.h index 1081d65bfac0..f44b6ed259e6 100644 --- a/ProcessHacker/include/phsettings.h +++ b/ProcessHacker/include/phsettings.h @@ -36,14 +36,14 @@ EXT ULONG PhCsUseColorWow64Processes; EXT ULONG PhCsColorWow64Processes; EXT ULONG PhCsUseColorDebuggedProcesses; EXT ULONG PhCsColorDebuggedProcesses; -EXT ULONG PhCsUseColorHandleProtected; -EXT ULONG PhCsColorHandleProtected; EXT ULONG PhCsUseColorElevatedProcesses; EXT ULONG PhCsColorElevatedProcesses; -EXT ULONG PhCsUseColorPicoProcesses; -EXT ULONG PhCsColorPicoProcesses; +EXT ULONG PhCsUseColorHandleFiltered; +EXT ULONG PhCsColorHandleFiltered; EXT ULONG PhCsUseColorImmersiveProcesses; EXT ULONG PhCsColorImmersiveProcesses; +EXT ULONG PhCsUseColorPicoProcesses; +EXT ULONG PhCsColorPicoProcesses; EXT ULONG PhCsUseColorSuspended; EXT ULONG PhCsColorSuspended; EXT ULONG PhCsUseColorDotNet; diff --git a/ProcessHacker/options.c b/ProcessHacker/options.c index 8da5452307a8..2070413c883a 100644 --- a/ProcessHacker/options.c +++ b/ProcessHacker/options.c @@ -1640,7 +1640,11 @@ static COLOR_ITEM ColorItems[] = COLOR_ITEM(L"ColorGuiThreads", L"GUI threads", L"Threads that have made at least one GUI-related system call."), COLOR_ITEM(L"ColorRelocatedModules", L"Relocated DLLs", L"DLLs that were not loaded at their preferred image bases."), COLOR_ITEM(L"ColorProtectedHandles", L"Protected handles", L"Handles that are protected from being closed."), - COLOR_ITEM(L"ColorInheritHandles", L"Inheritable handles", L"Handles that can be inherited by child processes.") + COLOR_ITEM(L"ColorInheritHandles", L"Inheritable handles", L"Handles that can be inherited by child processes."), + + COLOR_ITEM(L"ColorHandleFiltered", L"Filtered processes", L"Processes that are protected by handle object callbacks."), + COLOR_ITEM(L"ColorUnknown", L"Untrusted DLLs and Services", L"Services and DLLs which are not digitally signed."), + COLOR_ITEM(L"ColorServiceStop", L"Disabled Services", L"Services which have been disabled.") }; COLORREF NTAPI PhpColorItemColorFunction( diff --git a/ProcessHacker/proctree.c b/ProcessHacker/proctree.c index ad4806ec0ae5..ed0dec371c3e 100644 --- a/ProcessHacker/proctree.c +++ b/ProcessHacker/proctree.c @@ -2845,8 +2845,8 @@ BOOLEAN NTAPI PhpProcessTreeNewCallback( getNodeColor->BackColor = PhCsColorDebuggedProcesses; else if (PhCsUseColorSuspended && processItem->IsSuspended) getNodeColor->BackColor = PhCsColorSuspended; - else if (PhCsUseColorHandleProtected && processItem->IsProtectedHandle) - getNodeColor->BackColor = PhCsColorHandleProtected; + else if (PhCsUseColorHandleFiltered && processItem->IsProtectedHandle) + getNodeColor->BackColor = PhCsColorHandleFiltered; else if (PhCsUseColorElevatedProcesses && processItem->IsElevated) getNodeColor->BackColor = PhCsColorElevatedProcesses; else if (PhCsUseColorPicoProcesses && processItem->IsSubsystemProcess) diff --git a/ProcessHacker/settings.c b/ProcessHacker/settings.c index 8f0e7f7c19ce..6e603e0f5620 100644 --- a/ProcessHacker/settings.c +++ b/ProcessHacker/settings.c @@ -186,14 +186,14 @@ VOID PhAddDefaultSettings( PhpAddIntegerSetting(L"ColorWow64Processes", L"8f8fbc"); // Rosy Brown PhpAddIntegerSetting(L"UseColorDebuggedProcesses", L"1"); PhpAddIntegerSetting(L"ColorDebuggedProcesses", L"ffbbcc"); - PhpAddIntegerSetting(L"UseColorHandleProtected", L"1"); - PhpAddIntegerSetting(L"ColorHandleProtected", L"000000"); // Black PhpAddIntegerSetting(L"UseColorElevatedProcesses", L"1"); PhpAddIntegerSetting(L"ColorElevatedProcesses", L"00aaff"); - PhpAddIntegerSetting(L"UseColorPicoProcesses", L"1"); - PhpAddIntegerSetting(L"ColorPicoProcesses", L"ff8000"); // Blue + PhpAddIntegerSetting(L"UseColorHandleFiltered", L"1"); + PhpAddIntegerSetting(L"ColorHandleFiltered", L"000000"); // Black PhpAddIntegerSetting(L"UseColorImmersiveProcesses", L"1"); PhpAddIntegerSetting(L"ColorImmersiveProcesses", L"cbc0ff"); // Pink + PhpAddIntegerSetting(L"UseColorPicoProcesses", L"1"); + PhpAddIntegerSetting(L"ColorPicoProcesses", L"ff8000"); // Blue PhpAddIntegerSetting(L"UseColorSuspended", L"1"); PhpAddIntegerSetting(L"ColorSuspended", L"777777"); PhpAddIntegerSetting(L"UseColorDotNet", L"1"); @@ -250,8 +250,8 @@ VOID PhUpdateCachedSettings( PH_UPDATE_SETTING(ColorWow64Processes); PH_UPDATE_SETTING(UseColorDebuggedProcesses); PH_UPDATE_SETTING(ColorDebuggedProcesses); - PH_UPDATE_SETTING(UseColorHandleProtected); - PH_UPDATE_SETTING(ColorHandleProtected); + PH_UPDATE_SETTING(UseColorHandleFiltered); + PH_UPDATE_SETTING(ColorHandleFiltered); PH_UPDATE_SETTING(UseColorElevatedProcesses); PH_UPDATE_SETTING(ColorElevatedProcesses); PH_UPDATE_SETTING(UseColorPicoProcesses); diff --git a/ProcessHacker/srvlist.c b/ProcessHacker/srvlist.c index 3f5192bc7d0e..46bc613ba4ac 100644 --- a/ProcessHacker/srvlist.c +++ b/ProcessHacker/srvlist.c @@ -803,13 +803,21 @@ BOOLEAN NTAPI PhpServiceTreeNewCallback( else if (PhEnableProcessQueryStage2 && PhCsUseColorUnknown && serviceItem->VerifyResult != VrTrusted) { getNodeColor->BackColor = PhCsColorUnknown; + getNodeColor->Flags |= TN_AUTO_FORECOLOR; } - else if (PhCsUseColorServiceStop && serviceItem->StartType == SERVICE_DISABLED) + else if (PhCsUseColorServiceStop && serviceItem->State == SERVICE_STOPPED && serviceItem->StartType == SERVICE_DISABLED) + { + getNodeColor->BackColor = PhCsColorServiceStop; + getNodeColor->Flags |= TN_AUTO_FORECOLOR; + } + else if (PhCsUseColorServiceStop && serviceItem->State == SERVICE_STOPPED) { getNodeColor->ForeColor = PhCsColorServiceStop; } - - getNodeColor->Flags = TN_AUTO_FORECOLOR; + else + { + getNodeColor->Flags |= TN_AUTO_FORECOLOR; + } } return TRUE; case TreeNewGetCellTooltip: From e2416bd7e0dff6927fe2d4596f6e87394db0c0b2 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 19 Apr 2018 09:43:41 +1000 Subject: [PATCH 0905/2058] ToolStatus: Tidy up toolbar dropdown states --- plugins/ToolStatus/main.c | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/plugins/ToolStatus/main.c b/plugins/ToolStatus/main.c index dd16c542cc45..c749951c149e 100644 --- a/plugins/ToolStatus/main.c +++ b/plugins/ToolStatus/main.c @@ -814,21 +814,23 @@ LRESULT CALLBACK MainWndSubclassProc( { PPH_EMENU_ITEM menuItem; - if (PhGetOwnTokenAttributes().Elevated && buttonInfo.idCommand == PHAPP_ID_HACKER_SHOWDETAILSFORALLPROCESSES) - { - // Don't show the 'Show Details for All Processes' button in the - // dropdown menu when we're elevated. - continue; - } - - // Add buttons to menu. + // Add toolbar buttons to the context menu. menuItem = PhCreateEMenuItem(0, buttonInfo.idCommand, ToolbarGetText(buttonInfo.idCommand), NULL, NULL); + // Add the button image to the context menu. menuItem->Flags |= PH_EMENU_BITMAP_OWNED; menuItem->Bitmap = ToolbarGetImage(buttonInfo.idCommand); switch (buttonInfo.idCommand) { + case TIDC_FINDWINDOW: + case TIDC_FINDWINDOWTHREAD: + case TIDC_FINDWINDOWKILL: + { + // Note: These buttons are incompatible with the context menu window messages. + menuItem->Flags |= PH_EMENU_DISABLED; + } + break; case PHAPP_ID_VIEW_ALWAYSONTOP: { // Set the pressed state. @@ -836,12 +838,13 @@ LRESULT CALLBACK MainWndSubclassProc( menuItem->Flags |= PH_EMENU_CHECKED; } break; - case TIDC_FINDWINDOW: - case TIDC_FINDWINDOWTHREAD: - case TIDC_FINDWINDOWKILL: + case PHAPP_ID_HACKER_SHOWDETAILSFORALLPROCESSES: { - // Note: These buttons are incompatible with menus. - menuItem->Flags |= PH_EMENU_DISABLED; + if (PhGetOwnTokenAttributes().Elevated) + { + // Disable the 'Show Details for All Processes' button when we're elevated. + menuItem->Flags |= PH_EMENU_DISABLED; + } } break; case TIDC_POWERMENUDROPDOWN: From 2b982932834c17f491861dc23c2502e9e7a7a9a5 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 19 Apr 2018 12:00:35 +1000 Subject: [PATCH 0906/2058] Enable RS5 window Sets tab bevahior, Add new EnableExperimentalWindowStyle setting for disabling Sets behavior --- ProcessHacker/findobj.c | 4 ++++ ProcessHacker/procprp.c | 4 ++++ ProcessHacker/settings.c | 5 ++++- ProcessHacker/sysinfo.c | 4 ++++ tools/peview/prpsh.c | 4 ++++ tools/peview/resprp.c | 1 + 6 files changed, 21 insertions(+), 1 deletion(-) diff --git a/ProcessHacker/findobj.c b/ProcessHacker/findobj.c index 184c083c0cb3..3f7fb4b716cb 100644 --- a/ProcessHacker/findobj.c +++ b/ProcessHacker/findobj.c @@ -1192,6 +1192,10 @@ INT_PTR CALLBACK PhpFindObjectsDlgProc( Edit_SetSel(context->SearchWindowHandle, 0, -1); Button_SetCheck(GetDlgItem(hwndDlg, IDC_REGEX), PhGetIntegerSetting(L"FindObjRegex") ? BST_CHECKED : BST_UNCHECKED); + + // HACK HACK HACK + if (WindowsVersion >= WINDOWS_10_RS3 && !!PhGetIntegerSetting(L"EnableExperimentalWindowStyle")) + PhSetWindowStyle(hwndDlg, WS_POPUP, 0); } break; case WM_DESTROY: diff --git a/ProcessHacker/procprp.c b/ProcessHacker/procprp.c index 107806984313..b378fa600970 100644 --- a/ProcessHacker/procprp.c +++ b/ProcessHacker/procprp.c @@ -171,6 +171,10 @@ INT CALLBACK PhpPropSheetProc( PhSetWindowContext(hwndDlg, 0xF, propSheetContext); SetWindowLongPtr(hwndDlg, GWLP_WNDPROC, (LONG_PTR)PhpPropSheetWndProc); + // HACK HACK HACK + if (WindowsVersion >= WINDOWS_10_RS3 && !!PhGetIntegerSetting(L"EnableExperimentalWindowStyle")) + PhSetWindowStyle(hwndDlg, WS_POPUP, 0); + if (MinimumSize.left == -1) { RECT rect; diff --git a/ProcessHacker/settings.c b/ProcessHacker/settings.c index 6e603e0f5620..149c23a21d93 100644 --- a/ProcessHacker/settings.c +++ b/ProcessHacker/settings.c @@ -80,7 +80,7 @@ VOID PhAddDefaultSettings( PhpAddIntegerSetting(L"IconSingleClick", L"0"); PhpAddIntegerSetting(L"IconTogglesVisibility", L"1"); PhpAddStringSetting(L"JobListViewColumns", L""); - PhpAddIntegerSetting(L"KphUnloadOnShutdown", L"0"); + //PhpAddIntegerSetting(L"KphUnloadOnShutdown", L"0"); PhpAddIntegerSetting(L"LogEntries", L"200"); // 512 PhpAddStringSetting(L"LogListViewColumns", L""); PhpAddIntegerPairSetting(L"LogWindowPosition", L"300,300"); @@ -222,6 +222,9 @@ VOID PhAddDefaultSettings( PhpAddIntegerSetting(L"ColorServiceStop", L"6d6d6d"); // Dark grey PhpAddIntegerSetting(L"UseColorUnknown", L"1"); PhpAddIntegerSetting(L"ColorUnknown", L"507fff"); // Deep Pink + + // Experimental features + PhpAddIntegerSetting(L"EnableExperimentalWindowStyle", L"1"); } VOID PhUpdateCachedSettings( diff --git a/ProcessHacker/sysinfo.c b/ProcessHacker/sysinfo.c index 140af05c3af2..0cd1d6d58f4a 100644 --- a/ProcessHacker/sysinfo.c +++ b/ProcessHacker/sysinfo.c @@ -307,6 +307,10 @@ VOID PhSipOnInitDialog( PhSetControlTheme(PhSipWindow, L"explorer"); PhSipUpdateThemeData(); + + // HACK HACK HACK + if (WindowsVersion >= WINDOWS_10_RS3 && !!PhGetIntegerSetting(L"EnableExperimentalWindowStyle")) + PhSetWindowStyle(PhSipWindow, WS_POPUP, 0); } VOID PhSipOnDestroy( diff --git a/tools/peview/prpsh.c b/tools/peview/prpsh.c index 7cda0029f125..b3c06169cafc 100644 --- a/tools/peview/prpsh.c +++ b/tools/peview/prpsh.c @@ -157,6 +157,10 @@ INT CALLBACK PvpPropSheetProc( PhSetWindowContext(hwndDlg, UCHAR_MAX, context); SetWindowLongPtr(hwndDlg, GWLP_WNDPROC, (LONG_PTR)PvpPropSheetWndProc); + // HACK HACK HACK + if (WindowsVersion >= WINDOWS_10_RS3) + PhSetWindowStyle(hwndDlg, WS_POPUP, 0); + if (MinimumSize.left == -1) { RECT rect; diff --git a/tools/peview/resprp.c b/tools/peview/resprp.c index 928c804bab32..bf51770ad66b 100644 --- a/tools/peview/resprp.c +++ b/tools/peview/resprp.c @@ -159,6 +159,7 @@ INT_PTR CALLBACK PvpPeResourcesDlgProc( PhPrintUInt32(number, (ULONG)entry.Language); + // TODO: RtlLcidToLocaleName if (LCIDToLocaleName((ULONG)entry.Language, name, LOCALE_NAME_MAX_LENGTH, LOCALE_ALLOW_NEUTRAL_NAMES)) PhSetListViewSubItem(lvHandle, lvItemIndex, PVE_RESOURCES_COLUMN_INDEX_LCID, PhaFormatString(L"%s (%s)", number, name)->Buffer); else From 175749685f6b20e1de3c940571ce907c57cecccb Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 19 Apr 2018 12:00:35 +1000 Subject: [PATCH 0907/2058] Enable RS5 window Sets tab behavior, Add new EnableExperimentalWindowStyle setting for disabling Sets behavior --- ProcessHacker/findobj.c | 4 ++++ ProcessHacker/procprp.c | 4 ++++ ProcessHacker/settings.c | 5 ++++- ProcessHacker/sysinfo.c | 4 ++++ tools/peview/prpsh.c | 4 ++++ tools/peview/resprp.c | 1 + 6 files changed, 21 insertions(+), 1 deletion(-) diff --git a/ProcessHacker/findobj.c b/ProcessHacker/findobj.c index 184c083c0cb3..3f7fb4b716cb 100644 --- a/ProcessHacker/findobj.c +++ b/ProcessHacker/findobj.c @@ -1192,6 +1192,10 @@ INT_PTR CALLBACK PhpFindObjectsDlgProc( Edit_SetSel(context->SearchWindowHandle, 0, -1); Button_SetCheck(GetDlgItem(hwndDlg, IDC_REGEX), PhGetIntegerSetting(L"FindObjRegex") ? BST_CHECKED : BST_UNCHECKED); + + // HACK HACK HACK + if (WindowsVersion >= WINDOWS_10_RS3 && !!PhGetIntegerSetting(L"EnableExperimentalWindowStyle")) + PhSetWindowStyle(hwndDlg, WS_POPUP, 0); } break; case WM_DESTROY: diff --git a/ProcessHacker/procprp.c b/ProcessHacker/procprp.c index 107806984313..b378fa600970 100644 --- a/ProcessHacker/procprp.c +++ b/ProcessHacker/procprp.c @@ -171,6 +171,10 @@ INT CALLBACK PhpPropSheetProc( PhSetWindowContext(hwndDlg, 0xF, propSheetContext); SetWindowLongPtr(hwndDlg, GWLP_WNDPROC, (LONG_PTR)PhpPropSheetWndProc); + // HACK HACK HACK + if (WindowsVersion >= WINDOWS_10_RS3 && !!PhGetIntegerSetting(L"EnableExperimentalWindowStyle")) + PhSetWindowStyle(hwndDlg, WS_POPUP, 0); + if (MinimumSize.left == -1) { RECT rect; diff --git a/ProcessHacker/settings.c b/ProcessHacker/settings.c index 6e603e0f5620..149c23a21d93 100644 --- a/ProcessHacker/settings.c +++ b/ProcessHacker/settings.c @@ -80,7 +80,7 @@ VOID PhAddDefaultSettings( PhpAddIntegerSetting(L"IconSingleClick", L"0"); PhpAddIntegerSetting(L"IconTogglesVisibility", L"1"); PhpAddStringSetting(L"JobListViewColumns", L""); - PhpAddIntegerSetting(L"KphUnloadOnShutdown", L"0"); + //PhpAddIntegerSetting(L"KphUnloadOnShutdown", L"0"); PhpAddIntegerSetting(L"LogEntries", L"200"); // 512 PhpAddStringSetting(L"LogListViewColumns", L""); PhpAddIntegerPairSetting(L"LogWindowPosition", L"300,300"); @@ -222,6 +222,9 @@ VOID PhAddDefaultSettings( PhpAddIntegerSetting(L"ColorServiceStop", L"6d6d6d"); // Dark grey PhpAddIntegerSetting(L"UseColorUnknown", L"1"); PhpAddIntegerSetting(L"ColorUnknown", L"507fff"); // Deep Pink + + // Experimental features + PhpAddIntegerSetting(L"EnableExperimentalWindowStyle", L"1"); } VOID PhUpdateCachedSettings( diff --git a/ProcessHacker/sysinfo.c b/ProcessHacker/sysinfo.c index 140af05c3af2..0cd1d6d58f4a 100644 --- a/ProcessHacker/sysinfo.c +++ b/ProcessHacker/sysinfo.c @@ -307,6 +307,10 @@ VOID PhSipOnInitDialog( PhSetControlTheme(PhSipWindow, L"explorer"); PhSipUpdateThemeData(); + + // HACK HACK HACK + if (WindowsVersion >= WINDOWS_10_RS3 && !!PhGetIntegerSetting(L"EnableExperimentalWindowStyle")) + PhSetWindowStyle(PhSipWindow, WS_POPUP, 0); } VOID PhSipOnDestroy( diff --git a/tools/peview/prpsh.c b/tools/peview/prpsh.c index 7cda0029f125..b3c06169cafc 100644 --- a/tools/peview/prpsh.c +++ b/tools/peview/prpsh.c @@ -157,6 +157,10 @@ INT CALLBACK PvpPropSheetProc( PhSetWindowContext(hwndDlg, UCHAR_MAX, context); SetWindowLongPtr(hwndDlg, GWLP_WNDPROC, (LONG_PTR)PvpPropSheetWndProc); + // HACK HACK HACK + if (WindowsVersion >= WINDOWS_10_RS3) + PhSetWindowStyle(hwndDlg, WS_POPUP, 0); + if (MinimumSize.left == -1) { RECT rect; diff --git a/tools/peview/resprp.c b/tools/peview/resprp.c index 928c804bab32..bf51770ad66b 100644 --- a/tools/peview/resprp.c +++ b/tools/peview/resprp.c @@ -159,6 +159,7 @@ INT_PTR CALLBACK PvpPeResourcesDlgProc( PhPrintUInt32(number, (ULONG)entry.Language); + // TODO: RtlLcidToLocaleName if (LCIDToLocaleName((ULONG)entry.Language, name, LOCALE_NAME_MAX_LENGTH, LOCALE_ALLOW_NEUTRAL_NAMES)) PhSetListViewSubItem(lvHandle, lvItemIndex, PVE_RESOURCES_COLUMN_INDEX_LCID, PhaFormatString(L"%s (%s)", number, name)->Buffer); else From 0d7f26f0c373964e17b7da7f7119b514ca7e0f6c Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 26 Apr 2018 00:51:24 +1000 Subject: [PATCH 0908/2058] Fix column sorting by null first and other characters last (now sorts A-Z first and null last) --- phlib/include/phbasesup.h | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/phlib/include/phbasesup.h b/phlib/include/phbasesup.h index 98aa90c7b216..e856df089137 100644 --- a/phlib/include/phbasesup.h +++ b/phlib/include/phbasesup.h @@ -1407,11 +1407,35 @@ PhCompareStringWithNull( } else if (!String1) { - return !String2 ? 0 : -1; + return !String2 ? 0 : 1; } else { - return 1; + return -1; + } +} + +// dmex: Compares two strings, always sorting NULL strings after all other strings. +FORCEINLINE +LONG +PhCompareStringWithNullSortOrder( + _In_opt_ PPH_STRING String1, + _In_opt_ PPH_STRING String2, + _In_ PH_SORT_ORDER Order, + _In_ BOOLEAN IgnoreCase + ) +{ + if (String1 && String2) + { + return PhCompareString(String1, String2, IgnoreCase); + } + else if (!String1) + { + return !String2 ? 0 : (Order == AscendingSortOrder ? 1 : -1); + } + else + { + return (Order == AscendingSortOrder ? -1 : 1); } } From 33b618257cace0369875e39686f94340abe8e02a Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 26 Apr 2018 04:03:22 +1000 Subject: [PATCH 0909/2058] Update default unknown color --- ProcessHacker/settings.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ProcessHacker/settings.c b/ProcessHacker/settings.c index 149c23a21d93..8cb906d91fa9 100644 --- a/ProcessHacker/settings.c +++ b/ProcessHacker/settings.c @@ -221,7 +221,7 @@ VOID PhAddDefaultSettings( PhpAddIntegerSetting(L"UseColorServiceStop", L"1"); PhpAddIntegerSetting(L"ColorServiceStop", L"6d6d6d"); // Dark grey PhpAddIntegerSetting(L"UseColorUnknown", L"1"); - PhpAddIntegerSetting(L"ColorUnknown", L"507fff"); // Deep Pink + PhpAddIntegerSetting(L"ColorUnknown", L"ff8080"); // Light Red // Experimental features PhpAddIntegerSetting(L"EnableExperimentalWindowStyle", L"1"); From 7b55523fce7445f8b001b27a9456f18871341305 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 26 Apr 2018 04:17:25 +1000 Subject: [PATCH 0910/2058] Fix handle type issues --- ProcessHacker/findobj.c | 16 +++++++---- ProcessHacker/hndllist.c | 12 ++++---- ProcessHacker/hndlmenu.c | 9 ++++++ ProcessHacker/hndlprp.c | 51 +++++++++++++++++++--------------- ProcessHacker/hndlprv.c | 15 ++++------ phlib/hndlinfo.c | 43 ++++++++++++++++++++++++---- plugins/ExtendedTools/objprp.c | 3 ++ 7 files changed, 99 insertions(+), 50 deletions(-) diff --git a/ProcessHacker/findobj.c b/ProcessHacker/findobj.c index 3f7fb4b716cb..13a7e000e1f1 100644 --- a/ProcessHacker/findobj.c +++ b/ProcessHacker/findobj.c @@ -1518,11 +1518,17 @@ INT_PTR CALLBACK PhpFindObjectsDlgProc( handleItem = PhCreateHandleItem(&handleObjectNode->HandleInfo); - handleItem->BestObjectName = handleItem->ObjectName = handleObjectNode->BestObjectName; - PhReferenceObjectEx(handleObjectNode->BestObjectName, 2); - - handleItem->TypeName = handleObjectNode->TypeNameString; - PhReferenceObject(handleObjectNode->TypeNameString); + if (!PhIsNullOrEmptyString(handleObjectNode->BestObjectName)) + { + handleItem->BestObjectName = handleItem->ObjectName = handleObjectNode->BestObjectName; + PhReferenceObjectEx(handleObjectNode->BestObjectName, 2); + } + + if (!PhIsNullOrEmptyString(handleObjectNode->TypeNameString)) + { + handleItem->TypeName = handleObjectNode->TypeNameString; + PhReferenceObject(handleObjectNode->TypeNameString); + } PhShowHandleProperties( hwndDlg, diff --git a/ProcessHacker/hndllist.c b/ProcessHacker/hndllist.c index d3a09bd54bbe..bc48a37bb1e9 100644 --- a/ProcessHacker/hndllist.c +++ b/ProcessHacker/hndllist.c @@ -3,7 +3,7 @@ * handle list * * Copyright (C) 2011-2013 wj32 - * Copyright (C) 2017 dmex + * Copyright (C) 2017-2018 dmex * * This file is part of Process Hacker. * @@ -389,13 +389,13 @@ LONG PhpHandleTreeNewPostSortFunction( BEGIN_SORT_FUNCTION(Type) { - sortResult = PhCompareString(handleItem1->TypeName, handleItem2->TypeName, TRUE); + sortResult = PhCompareStringWithNullSortOrder(handleItem1->TypeName, handleItem2->TypeName, context->TreeNewSortOrder, TRUE); } END_SORT_FUNCTION BEGIN_SORT_FUNCTION(Name) { - sortResult = PhCompareStringWithNull(handleItem1->BestObjectName, handleItem2->BestObjectName, TRUE); + sortResult = PhCompareStringWithNullSortOrder(handleItem1->BestObjectName, handleItem2->BestObjectName, context->TreeNewSortOrder, TRUE); } END_SORT_FUNCTION @@ -434,7 +434,7 @@ BEGIN_SORT_FUNCTION(FileShareAccess) sortResult = uintcmp(handleItem1->FileFlags & (PH_HANDLE_FILE_SHARED_MASK), handleItem2->FileFlags & (PH_HANDLE_FILE_SHARED_MASK)); // Make sure all file handles get grouped together regardless of share access. - if (sortResult == 0) + if (sortResult == 0 && !PhIsNullOrEmptyString(handleItem1->TypeName)) sortResult = intcmp(PhEqualString2(handleItem1->TypeName, L"File", TRUE), PhEqualString2(handleItem2->TypeName, L"File", TRUE)); } END_SORT_FUNCTION @@ -523,7 +523,7 @@ BOOLEAN NTAPI PhpHandleTreeNewCallback( switch (getCellText->Id) { case PHHNTLC_TYPE: - getCellText->Text = handleItem->TypeName->sr; + getCellText->Text = PhGetStringRef(handleItem->TypeName); break; case PHHNTLC_NAME: getCellText->Text = PhGetStringRef(handleItem->BestObjectName); @@ -559,7 +559,7 @@ BOOLEAN NTAPI PhpHandleTreeNewCallback( PPH_ACCESS_ENTRY accessEntries; ULONG numberOfAccessEntries; - if (PhGetAccessEntries(handleItem->TypeName->Buffer, &accessEntries, &numberOfAccessEntries)) + if (PhGetAccessEntries(PhGetStringOrEmpty(handleItem->TypeName), &accessEntries, &numberOfAccessEntries)) { node->GrantedAccessSymbolicText = PhGetAccessString(handleItem->GrantedAccess, accessEntries, numberOfAccessEntries); PhFree(accessEntries); diff --git a/ProcessHacker/hndlmenu.c b/ProcessHacker/hndlmenu.c index bb24b7938a41..e5d88120d883 100644 --- a/ProcessHacker/hndlmenu.c +++ b/ProcessHacker/hndlmenu.c @@ -44,6 +44,9 @@ VOID PhInsertHandleObjectPropertiesEMenuItems( if (!PhFindEMenuItemEx(Menu, 0, NULL, InsertBeforeId, &parentItem, &indexInParent)) return; + if (PhIsNullOrEmptyString(Info->TypeName)) + return; + if (PhEqualString2(Info->TypeName, L"File", TRUE) || PhEqualString2(Info->TypeName, L"DLL", TRUE) || PhEqualString2(Info->TypeName, L"Mapped file", TRUE) || PhEqualString2(Info->TypeName, L"Mapped image", TRUE)) { @@ -114,6 +117,9 @@ VOID PhShowHandleObjectProperties1( _In_ PPH_HANDLE_ITEM_INFO Info ) { + if (PhIsNullOrEmptyString(Info->TypeName)) + return; + if (PhEqualString2(Info->TypeName, L"File", TRUE) || PhEqualString2(Info->TypeName, L"DLL", TRUE) || PhEqualString2(Info->TypeName, L"Mapped file", TRUE) || PhEqualString2(Info->TypeName, L"Mapped image", TRUE)) { @@ -383,6 +389,9 @@ VOID PhShowHandleObjectProperties2( _In_ PPH_HANDLE_ITEM_INFO Info ) { + if (PhIsNullOrEmptyString(Info->TypeName)) + return; + if (PhEqualString2(Info->TypeName, L"File", TRUE) || PhEqualString2(Info->TypeName, L"DLL", TRUE) || PhEqualString2(Info->TypeName, L"Mapped file", TRUE) || PhEqualString2(Info->TypeName, L"Mapped image", TRUE)) { diff --git a/ProcessHacker/hndlprp.c b/ProcessHacker/hndlprp.c index 156a035f6f07..25a7737c22de 100644 --- a/ProcessHacker/hndlprp.c +++ b/ProcessHacker/hndlprp.c @@ -3,6 +3,7 @@ * handle properties * * Copyright (C) 2010-2013 wj32 + * Copyright (C) 2018 dmex * * This file is part of Process Hacker. * @@ -83,9 +84,6 @@ VOID PhShowHandleProperties( PROPSHEETPAGE propSheetPage; HPROPSHEETPAGE pages[16]; HANDLE_PROPERTIES_CONTEXT context; - PH_STD_OBJECT_SECURITY stdObjectSecurity; - PPH_ACCESS_ENTRY accessEntries; - ULONG numberOfAccessEntries; context.ProcessId = ProcessId; context.HandleItem = HandleItem; @@ -111,9 +109,9 @@ VOID PhShowHandleProperties( pages[propSheetHeader.nPages++] = CreatePropertySheetPage(&propSheetPage); // Object-specific page - if (!HandleItem->TypeName) + if (PhIsNullOrEmptyString(HandleItem->TypeName)) { - // Dummy + NOTHING; } else if (PhEqualString2(HandleItem->TypeName, L"Event", TRUE)) { @@ -181,22 +179,29 @@ VOID PhShowHandleProperties( ); } - // Security page - stdObjectSecurity.OpenObject = PhpDuplicateHandleFromProcess; - stdObjectSecurity.ObjectType = HandleItem->TypeName->Buffer; - stdObjectSecurity.Context = &context; - - if (PhGetAccessEntries(HandleItem->TypeName->Buffer, &accessEntries, &numberOfAccessEntries)) + if (!PhIsNullOrEmptyString(HandleItem->TypeName)) { - pages[propSheetHeader.nPages++] = PhCreateSecurityPage( - PhGetStringOrEmpty(HandleItem->BestObjectName), - PhStdGetObjectSecurity, - PhStdSetObjectSecurity, - &stdObjectSecurity, - accessEntries, - numberOfAccessEntries - ); - PhFree(accessEntries); + PH_STD_OBJECT_SECURITY stdObjectSecurity; + PPH_ACCESS_ENTRY accessEntries; + ULONG numberOfAccessEntries; + + // Security page + stdObjectSecurity.OpenObject = PhpDuplicateHandleFromProcess; + stdObjectSecurity.ObjectType = PhGetStringOrEmpty(HandleItem->TypeName); + stdObjectSecurity.Context = &context; + + if (PhGetAccessEntries(PhGetStringOrEmpty(HandleItem->TypeName), &accessEntries, &numberOfAccessEntries)) + { + pages[propSheetHeader.nPages++] = PhCreateSecurityPage( + PhGetStringOrEmpty(HandleItem->BestObjectName), + PhStdGetObjectSecurity, + PhStdSetObjectSecurity, + &stdObjectSecurity, + accessEntries, + numberOfAccessEntries + ); + PhFree(accessEntries); + } } if (PhPluginsEnabled) @@ -257,12 +262,12 @@ INT_PTR CALLBACK PhpHandleGeneralDlgProc( // HACK PhCenterWindow(GetParent(hwndDlg), GetParent(GetParent(hwndDlg))); - SetDlgItemText(hwndDlg, IDC_NAME, PhGetString(context->HandleItem->BestObjectName)); - SetDlgItemText(hwndDlg, IDC_TYPE, context->HandleItem->TypeName->Buffer); + SetDlgItemText(hwndDlg, IDC_NAME, PhGetStringOrEmpty(context->HandleItem->BestObjectName)); + SetDlgItemText(hwndDlg, IDC_TYPE, PhGetStringOrEmpty(context->HandleItem->TypeName)); SetDlgItemText(hwndDlg, IDC_ADDRESS, context->HandleItem->ObjectString); if (PhGetAccessEntries( - context->HandleItem->TypeName->Buffer, + PhGetStringOrEmpty(context->HandleItem->TypeName), &accessEntries, &numberOfAccessEntries )) diff --git a/ProcessHacker/hndlprv.c b/ProcessHacker/hndlprv.c index d831817461b9..9587a309d238 100644 --- a/ProcessHacker/hndlprv.c +++ b/ProcessHacker/hndlprv.c @@ -139,9 +139,11 @@ PPH_HANDLE_ITEM PhCreateHandleItem( handleItem->GrantedAccess = (ACCESS_MASK)Handle->GrantedAccess; handleItem->TypeIndex = Handle->ObjectTypeIndex; - PhPrintPointer(handleItem->HandleString, (PVOID)handleItem->Handle); - PhPrintPointer(handleItem->ObjectString, handleItem->Object); + PhPrintPointer(handleItem->HandleString, (PVOID)handleItem->Handle); PhPrintPointer(handleItem->GrantedAccessString, UlongToPtr(handleItem->GrantedAccess)); + + if (handleItem->Object) + PhPrintPointer(handleItem->ObjectString, handleItem->Object); } PhEmCallObjectOperation(EmHandleItemType, handleItem, EmObjectCreate); @@ -588,14 +590,7 @@ VOID PhHandleProviderUpdate( NULL ); - // We need at least a type name to continue. - if (!handleItem->TypeName) - { - PhDereferenceObject(handleItem); - continue; - } - - if (PhEqualString2(handleItem->TypeName, L"File", TRUE) && KphIsConnected()) + if (handleItem->TypeName && PhEqualString2(handleItem->TypeName, L"File", TRUE) && KphIsConnected()) { KPH_FILE_OBJECT_INFORMATION objectInfo; diff --git a/phlib/hndlinfo.c b/phlib/hndlinfo.c index ffc797c112bf..8d22bf123b92 100644 --- a/phlib/hndlinfo.c +++ b/phlib/hndlinfo.c @@ -3,6 +3,7 @@ * handle information * * Copyright (C) 2010-2015 wj32 + * Copyright (C) 2017-2018 dmex * * This file is part of Process Hacker. * @@ -177,9 +178,40 @@ NTSTATUS PhpGetObjectTypeName( NTSTATUS status = STATUS_SUCCESS; PPH_STRING typeName = NULL; + // dmex: Enumerate the available object types and pre-cache the object type name. + if (WindowsVersion >= WINDOWS_8_1) + { + static PH_INITONCE initOnce = PH_INITONCE_INIT; + + if (PhBeginInitOnce(&initOnce)) + { + POBJECT_TYPES_INFORMATION objectTypes; + POBJECT_TYPE_INFORMATION objectType; + + if (NT_SUCCESS(PhEnumObjectTypes(&objectTypes))) + { + objectType = PH_FIRST_OBJECT_TYPE(objectTypes); + + for (ULONG i = 0; i < objectTypes->NumberOfTypes; i++) + { + PhMoveReference( + &PhObjectTypeNames[objectType->TypeIndex], + PhCreateStringFromUnicodeString(&objectType->TypeName) + ); + + objectType = PH_NEXT_OBJECT_TYPE(objectType); + } + + PhFree(objectTypes); + } + + PhEndInitOnce(&initOnce); + } + } + // If the cache contains the object type name, use it. Otherwise, query the type name. - if (ObjectTypeNumber != -1 && ObjectTypeNumber < MAX_OBJECT_TYPE_NUMBER) + if (ObjectTypeNumber != ULONG_MAX && ObjectTypeNumber < MAX_OBJECT_TYPE_NUMBER) typeName = PhObjectTypeNames[ObjectTypeNumber]; if (typeName) @@ -251,7 +283,7 @@ NTSTATUS PhpGetObjectTypeName( // Create a copy of the type name. typeName = PhCreateStringFromUnicodeString(&buffer->TypeName); - if (ObjectTypeNumber != -1 && ObjectTypeNumber < MAX_OBJECT_TYPE_NUMBER) + if (ObjectTypeNumber != ULONG_MAX && ObjectTypeNumber < MAX_OBJECT_TYPE_NUMBER) { // Try to store the type name in the cache. oldTypeName = _InterlockedCompareExchangePointer( @@ -260,8 +292,7 @@ NTSTATUS PhpGetObjectTypeName( NULL ); - // Add a reference if we stored the type name - // successfully. + // Add a reference if we stored the type name successfully. if (!oldTypeName) PhReferenceObject(typeName); } @@ -1230,7 +1261,7 @@ NTSTATUS PhGetHandleInformationEx( if (Handle == NULL || Handle == NtCurrentProcess() || Handle == NtCurrentThread()) return STATUS_INVALID_HANDLE; - if (ObjectTypeNumber != -1 && ObjectTypeNumber >= MAX_OBJECT_TYPE_NUMBER) + if (ObjectTypeNumber != ULONG_MAX && ObjectTypeNumber >= MAX_OBJECT_TYPE_NUMBER) return STATUS_INVALID_PARAMETER_3; // Duplicate the handle if we're not using KPH. @@ -1419,7 +1450,7 @@ ULONG PhGetObjectTypeNumber( { POBJECT_TYPES_INFORMATION objectTypes; POBJECT_TYPE_INFORMATION objectType; - ULONG objectIndex = -1; + ULONG objectIndex = ULONG_MAX; ULONG i; if (NT_SUCCESS(PhEnumObjectTypes(&objectTypes))) diff --git a/plugins/ExtendedTools/objprp.c b/plugins/ExtendedTools/objprp.c index 6716448708b6..a8a74121ecfe 100644 --- a/plugins/ExtendedTools/objprp.c +++ b/plugins/ExtendedTools/objprp.c @@ -62,6 +62,9 @@ VOID EtHandlePropertiesInitializing( PPH_PLUGIN_OBJECT_PROPERTIES objectProperties = Parameter; PPH_PLUGIN_HANDLE_PROPERTIES_CONTEXT context = objectProperties->Parameter; + if (PhIsNullOrEmptyString(context->HandleItem->TypeName)) + return; + if (objectProperties->NumberOfPages < objectProperties->MaximumNumberOfPages) { HPROPSHEETPAGE page = NULL; From 45caa7af8825399756447ad6d2909d8f43e42782 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 26 Apr 2018 04:18:23 +1000 Subject: [PATCH 0911/2058] Add EnableHandleSnapshot setting --- ProcessHacker/hndlprv.c | 2 +- ProcessHacker/settings.c | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/ProcessHacker/hndlprv.c b/ProcessHacker/hndlprv.c index 9587a309d238..473c3f4d7888 100644 --- a/ProcessHacker/hndlprv.c +++ b/ProcessHacker/hndlprv.c @@ -308,7 +308,7 @@ NTSTATUS PhEnumHandlesGeneric( // * On Windows XP and later, NtQuerySystemInformation with SystemExtendedHandleInformation. // * Otherwise, NtQuerySystemInformation with SystemHandleInformation can be used. - if (WindowsVersion >= WINDOWS_8) + if (WindowsVersion >= WINDOWS_8 && !!PhGetIntegerSetting(L"EnableHandleSnapshot")) { PPROCESS_HANDLE_SNAPSHOT_INFORMATION handles; PSYSTEM_HANDLE_INFORMATION_EX convertedHandles; diff --git a/ProcessHacker/settings.c b/ProcessHacker/settings.c index 8cb906d91fa9..970bb9414a08 100644 --- a/ProcessHacker/settings.c +++ b/ProcessHacker/settings.c @@ -44,6 +44,7 @@ VOID PhAddDefaultSettings( PhpAddIntegerSetting(L"EnableInstantTooltips", L"0"); PhpAddIntegerSetting(L"EnableKph", L"1"); PhpAddIntegerSetting(L"EnableKphWarnings", L"1"); + PhpAddIntegerSetting(L"EnableHandleSnapshot", L"1"); PhpAddIntegerSetting(L"EnableNetworkResolve", L"1"); PhpAddIntegerSetting(L"EnablePlugins", L"1"); PhpAddIntegerSetting(L"EnableServiceNonPoll", L"1"); From eb7b08d08b74f815373dc4a69516b0351387b858 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 26 Apr 2018 04:18:38 +1000 Subject: [PATCH 0912/2058] Add missing header --- ProcessHacker/hndlprv.c | 1 + 1 file changed, 1 insertion(+) diff --git a/ProcessHacker/hndlprv.c b/ProcessHacker/hndlprv.c index 473c3f4d7888..6cba00801464 100644 --- a/ProcessHacker/hndlprv.c +++ b/ProcessHacker/hndlprv.c @@ -26,6 +26,7 @@ #include #include +#include #include #include From cddd2134d7f4cdaf6297edf9303ed2ca340cb50d Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 26 Apr 2018 04:48:33 +1000 Subject: [PATCH 0913/2058] BuildTools: Fix appx package sdk path --- tools/CustomBuildTool/Source Files/Build.cs | 29 +++++++++--------- .../bin/Release/CustomBuildTool.exe | Bin 163840 -> 163840 bytes .../bin/Release/CustomBuildTool.pdb | Bin 77312 -> 77312 bytes 3 files changed, 14 insertions(+), 15 deletions(-) diff --git a/tools/CustomBuildTool/Source Files/Build.cs b/tools/CustomBuildTool/Source Files/Build.cs index 8e5d2ed53eb6..c5ad9c99728b 100644 --- a/tools/CustomBuildTool/Source Files/Build.cs +++ b/tools/CustomBuildTool/Source Files/Build.cs @@ -32,24 +32,22 @@ namespace CustomBuildTool [SuppressUnmanagedCodeSecurity] public static class Build { + private static readonly string SdkVersion = "10.0.16299.0"; private static DateTime TimeStart; private static bool BuildNightly; private static bool GitExportBuild; private static string GitExePath; private static string MSBuildExePath; - private static string CertUtilExePath; - private static string MakeAppxExePath; private static string CustomSignToolPath; private static string BuildBranch; private static string BuildOutputFolder; private static string BuildCommit; private static string BuildVersion; - //private static string BuildWebSetupVersion; private static string BuildLongVersion; private static string BuildCount; private static string BuildRevision; - private static string BuildMessage; + //private static string BuildMessage; private static long BuildBinFileLength; private static string BuildBinHash; @@ -59,11 +57,12 @@ public static class Build private static string BuildSetupHash; private static string BuildSetupSig; + //private static string BuildWebSetupVersion; //private static long BuildWebSetupFileLength; //private static string BuildWebSetupHash; //private static string BuildWebSetupSig; -#region Build Config + #region Build Config private static readonly string[] sdk_directories = { "sdk", @@ -159,10 +158,8 @@ public static bool InitializeBuildEnvironment(bool CheckDependencies) TimeStart = DateTime.Now; BuildOutputFolder = "build\\output"; MSBuildExePath = VisualStudio.GetMsbuildFilePath(); - CustomSignToolPath = "tools\\CustomSignTool\\bin\\Release32\\CustomSignTool.exe"; GitExePath = VisualStudio.GetFilePathFromPath("git.exe"); - CertUtilExePath = VisualStudio.GetFilePathFromPath("certutil.exe"); - MakeAppxExePath = Environment.ExpandEnvironmentVariables("%ProgramFiles(x86)%\\Windows Kits\\10\\bin\\x64\\MakeAppx.exe"); + CustomSignToolPath = "tools\\CustomSignTool\\bin\\Release32\\CustomSignTool.exe"; BuildNightly = !string.Equals(Environment.ExpandEnvironmentVariables("%APPVEYOR_BUILD_API%"), "%APPVEYOR_BUILD_API%", StringComparison.OrdinalIgnoreCase); try @@ -1224,7 +1221,8 @@ public static void BuildAppxPackage(BuildFlags Flags) Program.PrintColorMessage("Building processhacker-build-package.appxbundle...", ConsoleColor.Cyan); - string signToolExePath = Environment.ExpandEnvironmentVariables("%ProgramFiles(x86)%\\Windows Kits\\10\\bin\\x64\\SignTool.exe"); + string makeAppxExePath = Environment.ExpandEnvironmentVariables("%ProgramFiles(x86)%\\Windows Kits\\10\\bin\\" + SdkVersion + "\\x64\\MakeAppx.exe"); + string signToolExePath = Environment.ExpandEnvironmentVariables("%ProgramFiles(x86)%\\Windows Kits\\10\\bin\\" + SdkVersion + "\\x64\\SignTool.exe"); try { @@ -1267,7 +1265,7 @@ public static void BuildAppxPackage(BuildFlags Flags) // create the package Win32.ShellExecute( - MakeAppxExePath, + makeAppxExePath, "pack /o /f " + BuildOutputFolder + "\\package32.map /p " + BuildOutputFolder + "\\processhacker-build-package-x32.appx" ); @@ -1316,7 +1314,7 @@ public static void BuildAppxPackage(BuildFlags Flags) // create the package Win32.ShellExecute( - MakeAppxExePath, + makeAppxExePath, "pack /o /f " + BuildOutputFolder + "\\package64.map /p " + BuildOutputFolder + "\\processhacker-build-package-x64.appx" ); @@ -1344,7 +1342,7 @@ public static void BuildAppxPackage(BuildFlags Flags) // create the appx bundle package Win32.ShellExecute( - MakeAppxExePath, + makeAppxExePath, "bundle /f " + BuildOutputFolder + "\\bundle.map /p " + BuildOutputFolder + "\\processhacker-build-package.appxbundle" ); @@ -1382,8 +1380,9 @@ public static bool BuildAppxSignature() Program.PrintColorMessage("Building Appx Signature...", ConsoleColor.Cyan); - var makeCertExePath = Environment.ExpandEnvironmentVariables("%ProgramFiles(x86)%\\Windows Kits\\10\\bin\\x64\\MakeCert.exe"); - var pvk2PfxExePath = Environment.ExpandEnvironmentVariables("%ProgramFiles(x86)%\\Windows Kits\\10\\bin\\x64\\Pvk2Pfx.exe"); + string makeCertExePath = Environment.ExpandEnvironmentVariables("%ProgramFiles(x86)%\\Windows Kits\\10\\bin\\" + SdkVersion + "\\x64\\MakeCert.exe"); + string pvk2PfxExePath = Environment.ExpandEnvironmentVariables("%ProgramFiles(x86)%\\Windows Kits\\10\\bin\\" + SdkVersion + "\\x64\\Pvk2Pfx.exe"); + string certUtilExePath = VisualStudio.GetFilePathFromPath("certutil.exe"); try { @@ -1421,7 +1420,7 @@ public static bool BuildAppxSignature() return false; } - output = Win32.ShellExecute(CertUtilExePath, + output = Win32.ShellExecute(certUtilExePath, "-addStore TrustedPeople " + BuildOutputFolder + "\\processhacker-appx.cer" ); diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe b/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe index de0d0c33d304d643aeff3d3c93523e10553cd428..c1aef97483a04a1504eff37b3b1b2594693b6398 100644 GIT binary patch delta 19465 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 I=^xU60Svin0{{R3 delta 19516 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 O{f%x-> diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb b/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb index ea00cfc1af476cdef61fb53e07d4fcb0bfc64244..5d75cc14fc642696c2838fff811b94a768acc53f 100644 GIT binary patch delta 10840 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 From ed7330a812c4c9b9a2af82fd09388f0e0f55d0f3 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 28 Apr 2018 07:09:30 +1000 Subject: [PATCH 0914/2058] Add helper macros --- ProcessHacker/ProcessHacker.def | 3 + ProcessHacker/about.c | 6 +- ProcessHacker/chdlg.c | 2 +- ProcessHacker/chproc.c | 17 ++-- ProcessHacker/findobj.c | 4 +- ProcessHacker/hidnproc.c | 41 +++------ ProcessHacker/hndlprp.c | 28 +++--- ProcessHacker/infodlg.c | 9 +- ProcessHacker/jobprp.c | 74 ++++++++-------- ProcessHacker/logwnd.c | 2 +- ProcessHacker/mdump.c | 7 +- ProcessHacker/memedit.c | 6 +- ProcessHacker/memlists.c | 98 ++++++++++----------- ProcessHacker/memprot.c | 6 +- ProcessHacker/memrslt.c | 6 +- ProcessHacker/memsrch.c | 2 +- ProcessHacker/miniinfo.c | 4 +- ProcessHacker/mtgndlg.c | 5 +- ProcessHacker/ntobjprp.c | 52 +++++------ ProcessHacker/options.c | 24 +++--- ProcessHacker/pagfiles.c | 2 +- ProcessHacker/plugman.c | 20 ++--- ProcessHacker/procprp.c | 2 +- ProcessHacker/procrec.c | 30 +++---- ProcessHacker/prpgenv.c | 8 +- ProcessHacker/prpggen.c | 48 +++++------ ProcessHacker/prpgthrd.c | 24 +++--- ProcessHacker/prpgwmi.c | 2 +- ProcessHacker/runas.c | 2 +- ProcessHacker/sessmsg.c | 4 +- ProcessHacker/sessprp.c | 22 ++--- ProcessHacker/srvcr.c | 4 +- ProcessHacker/srvprp.c | 31 ++++--- ProcessHacker/syssccpu.c | 30 +++---- ProcessHacker/sysscio.c | 36 ++++---- ProcessHacker/sysscmem.c | 124 +++++++++++++-------------- ProcessHacker/thrdstk.c | 2 +- ProcessHacker/tokprp.c | 52 +++++------ phlib/guisup.c | 58 ++++++++++++- phlib/include/guisup.h | 44 ++++++++++ plugins/ExtendedNotifications/main.c | 10 +-- plugins/ExtendedServices/depend.c | 8 +- plugins/ExtendedServices/other.c | 6 +- plugins/ExtendedServices/recovery.c | 28 +++--- plugins/ExtendedServices/srvprgrs.c | 4 +- plugins/ExtendedServices/trigger.c | 8 +- plugins/ExtendedTools/disktab.c | 2 +- plugins/ExtendedTools/etwprprp.c | 26 +++--- plugins/ExtendedTools/etwsys.c | 16 ++-- plugins/ExtendedTools/gpuprprp.c | 28 +++--- plugins/ExtendedTools/gpusys.c | 10 +-- plugins/ExtendedTools/modsrv.c | 2 +- plugins/ExtendedTools/objprp.c | 10 +-- plugins/HardwareDevices/diskgraph.c | 28 +++--- plugins/HardwareDevices/netgraph.c | 22 ++--- plugins/HardwareDevices/prpsh.c | 2 +- plugins/NetworkTools/options.c | 8 +- plugins/NetworkTools/ping.c | 14 +-- plugins/ToolStatus/customizesb.c | 2 +- plugins/ToolStatus/customizetb.c | 2 +- plugins/Updater/options.c | 2 +- plugins/UserNotes/main.c | 11 ++- plugins/WindowExplorer/wnddlg.c | 3 +- plugins/WindowExplorer/wndprp.c | 80 ++++++++--------- tools/peview/clrprp.c | 8 +- tools/peview/exlfprp.c | 12 +-- tools/peview/peprp.c | 36 ++++---- tools/peview/prpsh.c | 2 +- 68 files changed, 708 insertions(+), 623 deletions(-) diff --git a/ProcessHacker/ProcessHacker.def b/ProcessHacker/ProcessHacker.def index 58dd6f1d2ce7..1befe9968a7f 100644 --- a/ProcessHacker/ProcessHacker.def +++ b/ProcessHacker/ProcessHacker.def @@ -516,6 +516,9 @@ EXPORTS PhGetWindowContext PhSetWindowContext PhRemoveWindowContext + PhGetDialogItemValue + PhSetDialogItemValue + PhSetDialogItemText ; hndlinfo PhEnumObjectTypes diff --git a/ProcessHacker/about.c b/ProcessHacker/about.c index 2339f288e6dd..fff2e75d0f23 100644 --- a/ProcessHacker/about.c +++ b/ProcessHacker/about.c @@ -66,10 +66,10 @@ static INT_PTR CALLBACK PhpAboutDlgProc( ); #endif - SetDlgItemText(hwndDlg, IDC_ABOUT_NAME, appName->Buffer); + PhSetDialogItemText(hwndDlg, IDC_ABOUT_NAME, appName->Buffer); PhDereferenceObject(appName); - SetDlgItemText(hwndDlg, IDC_CREDITS, + PhSetDialogItemText(hwndDlg, IDC_CREDITS, L"Thanks to:\n" L" wj32 - Wen Jia Liu\n" L" dmex - Steven G\n" @@ -85,7 +85,7 @@ static INT_PTR CALLBACK PhpAboutDlgProc( L" Farm-fresh web icons\n" ); - SendMessage(hwndDlg, WM_NEXTDLGCTL, (LPARAM)GetDlgItem(hwndDlg, IDOK), TRUE); + PhSetDialogFocus(hwndDlg, GetDlgItem(hwndDlg, IDOK)); } break; case WM_COMMAND: diff --git a/ProcessHacker/chdlg.c b/ProcessHacker/chdlg.c index e9d8ddc22863..565fba2b2195 100644 --- a/ProcessHacker/chdlg.c +++ b/ProcessHacker/chdlg.c @@ -262,7 +262,7 @@ INT_PTR CALLBACK PhpChoiceDlgProc( SWP_NOACTIVATE | SWP_NOZORDER); } - SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)comboBoxHandle, TRUE); + PhSetDialogFocus(hwndDlg, comboBoxHandle); } break; case WM_DESTROY: diff --git a/ProcessHacker/chproc.c b/ProcessHacker/chproc.c index 51c91672cbbb..a4e5692eed3e 100644 --- a/ProcessHacker/chproc.c +++ b/ProcessHacker/chproc.c @@ -206,19 +206,14 @@ INT_PTR CALLBACK PhpChooseProcessDlgProc( PhCenterWindow(hwndDlg, GetParent(hwndDlg)); - SetDlgItemText(hwndDlg, IDC_MESSAGE, context->Message); + PhSetDialogItemText(hwndDlg, IDC_MESSAGE, context->Message); PhInitializeLayoutManager(&context->LayoutManager, hwndDlg); - PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_MESSAGE), NULL, - PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT | PH_LAYOUT_FORCE_INVALIDATE); - PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_LIST), NULL, - PH_ANCHOR_ALL); - PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDOK), NULL, - PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); - PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDCANCEL), NULL, - PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); - PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_REFRESH), NULL, - PH_ANCHOR_BOTTOM | PH_ANCHOR_LEFT); + PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_MESSAGE), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT | PH_LAYOUT_FORCE_INVALIDATE); + PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_LIST), NULL, PH_ANCHOR_ALL); + PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDOK), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); + PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDCANCEL), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); + PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_REFRESH), NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_LEFT); PhLayoutManagerLayout(&context->LayoutManager); context->MinimumSize.left = 0; diff --git a/ProcessHacker/findobj.c b/ProcessHacker/findobj.c index 13a7e000e1f1..363249909ca1 100644 --- a/ProcessHacker/findobj.c +++ b/ProcessHacker/findobj.c @@ -1356,7 +1356,7 @@ INT_PTR CALLBACK PhpFindObjectsDlgProc( if (!context->SearchThreadHandle) break; - SetDlgItemText(hwndDlg, IDOK, L"Cancel"); + PhSetDialogItemText(hwndDlg, IDOK, L"Cancel"); SetCursor(LoadCursor(NULL, IDC_APPSTARTING)); } @@ -1577,7 +1577,7 @@ INT_PTR CALLBACK PhpFindObjectsDlgProc( context->SearchThreadHandle = NULL; context->SearchStop = FALSE; - SetDlgItemText(hwndDlg, IDOK, L"Find"); + PhSetDialogItemText(hwndDlg, IDOK, L"Find"); EnableWindow(GetDlgItem(hwndDlg, IDOK), TRUE); SetCursor(LoadCursor(NULL, IDC_ARROW)); diff --git a/ProcessHacker/hidnproc.c b/ProcessHacker/hidnproc.c index 8bbd8a5bc327..7e5fcbbc639c 100644 --- a/ProcessHacker/hidnproc.c +++ b/ProcessHacker/hidnproc.c @@ -73,8 +73,8 @@ PPH_PROCESS_ITEM PhpCreateProcessItemForHiddenProcess( _In_ PPH_HIDDEN_PROCESS_ENTRY Entry ); -HWND PhHiddenProcessesWindowHandle = NULL; -HWND PhHiddenProcessesListViewHandle = NULL; +static HWND PhHiddenProcessesWindowHandle = NULL; +static HWND PhHiddenProcessesListViewHandle = NULL; static PH_LAYOUT_MANAGER WindowLayoutManager; static RECT MinimumSize; @@ -132,22 +132,14 @@ static INT_PTR CALLBACK PhpHiddenProcessesDlgProc( PhHiddenProcessesListViewHandle = lvHandle = GetDlgItem(hwndDlg, IDC_PROCESSES); PhInitializeLayoutManager(&WindowLayoutManager, hwndDlg); - PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDC_INTRO), - NULL, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT | PH_LAYOUT_FORCE_INVALIDATE); - PhAddLayoutItem(&WindowLayoutManager, lvHandle, - NULL, PH_ANCHOR_ALL); - PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDC_DESCRIPTION), - NULL, PH_ANCHOR_LEFT | PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM | PH_LAYOUT_FORCE_INVALIDATE); - PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDC_METHOD), - NULL, PH_ANCHOR_LEFT | PH_ANCHOR_BOTTOM); - PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDC_TERMINATE), - NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); - PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDC_SAVE), - NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); - PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDC_SCAN), - NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); - PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDOK), - NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); + PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDC_INTRO), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT | PH_LAYOUT_FORCE_INVALIDATE); + PhAddLayoutItem(&WindowLayoutManager, lvHandle, NULL, PH_ANCHOR_ALL); + PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDC_DESCRIPTION), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM | PH_LAYOUT_FORCE_INVALIDATE); + PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDC_METHOD), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_BOTTOM); + PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDC_TERMINATE), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); + PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDC_SAVE), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); + PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDC_SCAN), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); + PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDOK), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); MinimumSize.left = 0; MinimumSize.top = 0; @@ -181,15 +173,10 @@ static INT_PTR CALLBACK PhpHiddenProcessesDlgProc( { PhSaveWindowPlacementToSetting(L"HiddenProcessesWindowPosition", L"HiddenProcessesWindowSize", hwndDlg); PhSaveListViewColumnsToSetting(L"HiddenProcessesListViewColumns", PhHiddenProcessesListViewHandle); + + PhHiddenProcessesWindowHandle = NULL; } break; - case WM_CLOSE: - { - // Hide, don't close. - ShowWindow(hwndDlg, SW_HIDE); - SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, 0); - } - return TRUE; case WM_COMMAND: { switch (GET_WM_COMMAND_ID(wParam, lParam)) @@ -197,7 +184,7 @@ static INT_PTR CALLBACK PhpHiddenProcessesDlgProc( case IDCANCEL: case IDOK: { - SendMessage(hwndDlg, WM_CLOSE, 0, 0); + EndDialog(hwndDlg, IDOK); } break; case IDC_SCAN: @@ -245,7 +232,7 @@ static INT_PTR CALLBACK PhpHiddenProcessesDlgProc( if (NT_SUCCESS(status)) { - SetDlgItemText(hwndDlg, IDC_DESCRIPTION, + PhSetDialogItemText(hwndDlg, IDC_DESCRIPTION, PhaFormatString(L"%u hidden process(es), %u terminated process(es).", NumberOfHiddenProcesses, NumberOfTerminatedProcesses)->Buffer ); diff --git a/ProcessHacker/hndlprp.c b/ProcessHacker/hndlprp.c index 25a7737c22de..43d73bdf8777 100644 --- a/ProcessHacker/hndlprp.c +++ b/ProcessHacker/hndlprp.c @@ -262,9 +262,9 @@ INT_PTR CALLBACK PhpHandleGeneralDlgProc( // HACK PhCenterWindow(GetParent(hwndDlg), GetParent(GetParent(hwndDlg))); - SetDlgItemText(hwndDlg, IDC_NAME, PhGetStringOrEmpty(context->HandleItem->BestObjectName)); - SetDlgItemText(hwndDlg, IDC_TYPE, PhGetStringOrEmpty(context->HandleItem->TypeName)); - SetDlgItemText(hwndDlg, IDC_ADDRESS, context->HandleItem->ObjectString); + PhSetDialogItemText(hwndDlg, IDC_NAME, PhGetStringOrEmpty(context->HandleItem->BestObjectName)); + PhSetDialogItemText(hwndDlg, IDC_TYPE, PhGetStringOrEmpty(context->HandleItem->TypeName)); + PhSetDialogItemText(hwndDlg, IDC_ADDRESS, context->HandleItem->ObjectString); if (PhGetAccessEntries( PhGetStringOrEmpty(context->HandleItem->TypeName), @@ -288,18 +288,18 @@ INT_PTR CALLBACK PhpHandleGeneralDlgProc( context->HandleItem->GrantedAccessString, accessString->Buffer ); - SetDlgItemText(hwndDlg, IDC_GRANTED_ACCESS, grantedAccessString->Buffer); + PhSetDialogItemText(hwndDlg, IDC_GRANTED_ACCESS, grantedAccessString->Buffer); } else { - SetDlgItemText(hwndDlg, IDC_GRANTED_ACCESS, context->HandleItem->GrantedAccessString); + PhSetDialogItemText(hwndDlg, IDC_GRANTED_ACCESS, context->HandleItem->GrantedAccessString); } PhFree(accessEntries); } else { - SetDlgItemText(hwndDlg, IDC_GRANTED_ACCESS, context->HandleItem->GrantedAccessString); + PhSetDialogItemText(hwndDlg, IDC_GRANTED_ACCESS, context->HandleItem->GrantedAccessString); } if (NT_SUCCESS(PhOpenProcess( @@ -318,10 +318,10 @@ INT_PTR CALLBACK PhpHandleGeneralDlgProc( NULL ))) { - SetDlgItemInt(hwndDlg, IDC_REFERENCES, basicInfo.PointerCount, FALSE); - SetDlgItemInt(hwndDlg, IDC_HANDLES, basicInfo.HandleCount, FALSE); - SetDlgItemInt(hwndDlg, IDC_PAGED, basicInfo.PagedPoolCharge, FALSE); - SetDlgItemInt(hwndDlg, IDC_NONPAGED, basicInfo.NonPagedPoolCharge, FALSE); + PhSetDialogItemValue(hwndDlg, IDC_REFERENCES, basicInfo.PointerCount, FALSE); + PhSetDialogItemValue(hwndDlg, IDC_HANDLES, basicInfo.HandleCount, FALSE); + PhSetDialogItemValue(hwndDlg, IDC_PAGED, basicInfo.PagedPoolCharge, FALSE); + PhSetDialogItemValue(hwndDlg, IDC_NONPAGED, basicInfo.NonPagedPoolCharge, FALSE); haveBasicInfo = TRUE; } @@ -331,10 +331,10 @@ INT_PTR CALLBACK PhpHandleGeneralDlgProc( if (!haveBasicInfo) { - SetDlgItemText(hwndDlg, IDC_REFERENCES, L"Unknown"); - SetDlgItemText(hwndDlg, IDC_HANDLES, L"Unknown"); - SetDlgItemText(hwndDlg, IDC_PAGED, L"Unknown"); - SetDlgItemText(hwndDlg, IDC_NONPAGED, L"Unknown"); + PhSetDialogItemText(hwndDlg, IDC_REFERENCES, L"Unknown"); + PhSetDialogItemText(hwndDlg, IDC_HANDLES, L"Unknown"); + PhSetDialogItemText(hwndDlg, IDC_PAGED, L"Unknown"); + PhSetDialogItemText(hwndDlg, IDC_NONPAGED, L"Unknown"); } } break; diff --git a/ProcessHacker/infodlg.c b/ProcessHacker/infodlg.c index c2faefa86b87..035805ed3769 100644 --- a/ProcessHacker/infodlg.c +++ b/ProcessHacker/infodlg.c @@ -64,8 +64,6 @@ static INT_PTR CALLBACK PhpInformationDlgProc( PhCenterWindow(hwndDlg, GetParent(hwndDlg)); - SetDlgItemText(hwndDlg, IDC_TEXT, context->String); - PhInitializeLayoutManager(&context->LayoutManager, hwndDlg); PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_TEXT), NULL, PH_ANCHOR_ALL); PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDOK), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); @@ -85,7 +83,9 @@ static INT_PTR CALLBACK PhpInformationDlgProc( MinimumSize.left = 0; } - SendMessage(hwndDlg, WM_NEXTDLGCTL, (LPARAM)GetDlgItem(hwndDlg, IDOK), TRUE); + PhSetDialogItemText(hwndDlg, IDC_TEXT, context->String); + + PhSetDialogFocus(hwndDlg, GetDlgItem(hwndDlg, IDOK)); } break; case WM_DESTROY: @@ -126,7 +126,8 @@ static INT_PTR CALLBACK PhpInformationDlgProc( } PhSetClipboardString(hwndDlg, &string); - SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)editControl, TRUE); + + PhSetDialogFocus(hwndDlg, editControl); } break; case IDC_SAVE: diff --git a/ProcessHacker/jobprp.c b/ProcessHacker/jobprp.c index 0ccbf6be37d7..00d72d998795 100644 --- a/ProcessHacker/jobprp.c +++ b/ProcessHacker/jobprp.c @@ -233,7 +233,7 @@ INT_PTR CALLBACK PhpJobPageProc( PhAddListViewColumn(limitsLv, 1, 1, 1, LVCFMT_LEFT, 160, L"Value"); PhLoadListViewColumnsFromSetting(L"JobListViewColumns", limitsLv); - SetDlgItemText(hwndDlg, IDC_NAME, L"Unknown"); + PhSetDialogItemText(hwndDlg, IDC_NAME, L"Unknown"); if (NT_SUCCESS(jobPageContext->OpenObject( &jobHandle, @@ -261,7 +261,7 @@ INT_PTR CALLBACK PhpJobPageProc( if (jobObjectName && jobObjectName->Length == 0) jobObjectName = NULL; - SetDlgItemText(hwndDlg, IDC_NAME, PhGetStringOrDefault(jobObjectName, L"(unnamed job)")); + PhSetDialogItemText(hwndDlg, IDC_NAME, PhGetStringOrDefault(jobObjectName, L"(unnamed job)")); // Processes PhpAddJobProcesses(hwndDlg, jobHandle); @@ -562,47 +562,47 @@ static VOID PhpRefreshJobStatisticsInfo( { WCHAR timeSpan[PH_TIMESPAN_STR_LEN_1]; - SetDlgItemInt(hwndDlg, IDC_ZACTIVEPROCESSES_V, basicAndIo.BasicInfo.ActiveProcesses, FALSE); - SetDlgItemInt(hwndDlg, IDC_ZTOTALPROCESSES_V, basicAndIo.BasicInfo.TotalProcesses, FALSE); - SetDlgItemInt(hwndDlg, IDC_ZTERMINATEDPROCESSES_V, basicAndIo.BasicInfo.TotalTerminatedProcesses, FALSE); + PhSetDialogItemValue(hwndDlg, IDC_ZACTIVEPROCESSES_V, basicAndIo.BasicInfo.ActiveProcesses, FALSE); + PhSetDialogItemValue(hwndDlg, IDC_ZTOTALPROCESSES_V, basicAndIo.BasicInfo.TotalProcesses, FALSE); + PhSetDialogItemValue(hwndDlg, IDC_ZTERMINATEDPROCESSES_V, basicAndIo.BasicInfo.TotalTerminatedProcesses, FALSE); PhPrintTimeSpan(timeSpan, basicAndIo.BasicInfo.TotalUserTime.QuadPart, PH_TIMESPAN_HMSM); - SetDlgItemText(hwndDlg, IDC_ZUSERTIME_V, timeSpan); + PhSetDialogItemText(hwndDlg, IDC_ZUSERTIME_V, timeSpan); PhPrintTimeSpan(timeSpan, basicAndIo.BasicInfo.TotalKernelTime.QuadPart, PH_TIMESPAN_HMSM); - SetDlgItemText(hwndDlg, IDC_ZKERNELTIME_V, timeSpan); + PhSetDialogItemText(hwndDlg, IDC_ZKERNELTIME_V, timeSpan); PhPrintTimeSpan(timeSpan, basicAndIo.BasicInfo.ThisPeriodTotalUserTime.QuadPart, PH_TIMESPAN_HMSM); - SetDlgItemText(hwndDlg, IDC_ZUSERTIMEPERIOD_V, timeSpan); + PhSetDialogItemText(hwndDlg, IDC_ZUSERTIMEPERIOD_V, timeSpan); PhPrintTimeSpan(timeSpan, basicAndIo.BasicInfo.ThisPeriodTotalKernelTime.QuadPart, PH_TIMESPAN_HMSM); - SetDlgItemText(hwndDlg, IDC_ZKERNELTIMEPERIOD_V, timeSpan); + PhSetDialogItemText(hwndDlg, IDC_ZKERNELTIMEPERIOD_V, timeSpan); - SetDlgItemText(hwndDlg, IDC_ZPAGEFAULTS_V, PhaFormatUInt64(basicAndIo.BasicInfo.TotalPageFaultCount, TRUE)->Buffer); + PhSetDialogItemText(hwndDlg, IDC_ZPAGEFAULTS_V, PhaFormatUInt64(basicAndIo.BasicInfo.TotalPageFaultCount, TRUE)->Buffer); - SetDlgItemText(hwndDlg, IDC_ZIOREADS_V, PhaFormatUInt64(basicAndIo.IoInfo.ReadOperationCount, TRUE)->Buffer); - SetDlgItemText(hwndDlg, IDC_ZIOREADBYTES_V, PhaFormatSize(basicAndIo.IoInfo.ReadTransferCount, -1)->Buffer); - SetDlgItemText(hwndDlg, IDC_ZIOWRITES_V, PhaFormatUInt64(basicAndIo.IoInfo.WriteOperationCount, TRUE)->Buffer); - SetDlgItemText(hwndDlg, IDC_ZIOWRITEBYTES_V, PhaFormatSize(basicAndIo.IoInfo.WriteTransferCount, -1)->Buffer); - SetDlgItemText(hwndDlg, IDC_ZIOOTHER_V, PhaFormatUInt64(basicAndIo.IoInfo.OtherOperationCount, TRUE)->Buffer); - SetDlgItemText(hwndDlg, IDC_ZIOOTHERBYTES_V, PhaFormatSize(basicAndIo.IoInfo.OtherTransferCount, -1)->Buffer); + PhSetDialogItemText(hwndDlg, IDC_ZIOREADS_V, PhaFormatUInt64(basicAndIo.IoInfo.ReadOperationCount, TRUE)->Buffer); + PhSetDialogItemText(hwndDlg, IDC_ZIOREADBYTES_V, PhaFormatSize(basicAndIo.IoInfo.ReadTransferCount, -1)->Buffer); + PhSetDialogItemText(hwndDlg, IDC_ZIOWRITES_V, PhaFormatUInt64(basicAndIo.IoInfo.WriteOperationCount, TRUE)->Buffer); + PhSetDialogItemText(hwndDlg, IDC_ZIOWRITEBYTES_V, PhaFormatSize(basicAndIo.IoInfo.WriteTransferCount, -1)->Buffer); + PhSetDialogItemText(hwndDlg, IDC_ZIOOTHER_V, PhaFormatUInt64(basicAndIo.IoInfo.OtherOperationCount, TRUE)->Buffer); + PhSetDialogItemText(hwndDlg, IDC_ZIOOTHERBYTES_V, PhaFormatSize(basicAndIo.IoInfo.OtherTransferCount, -1)->Buffer); } else { - SetDlgItemText(hwndDlg, IDC_ZACTIVEPROCESSES_V, L"Unknown"); - SetDlgItemText(hwndDlg, IDC_ZTOTALPROCESSES_V, L"Unknown"); - SetDlgItemText(hwndDlg, IDC_ZTERMINATEDPROCESSES_V, L"Unknown"); - - SetDlgItemText(hwndDlg, IDC_ZUSERTIME_V, L"Unknown"); - SetDlgItemText(hwndDlg, IDC_ZKERNELTIME_V, L"Unknown"); - SetDlgItemText(hwndDlg, IDC_ZUSERTIMEPERIOD_V, L"Unknown"); - SetDlgItemText(hwndDlg, IDC_ZKERNELTIMEPERIOD_V, L"Unknown"); - - SetDlgItemText(hwndDlg, IDC_ZPAGEFAULTS_V, L"Unknown"); - - SetDlgItemText(hwndDlg, IDC_ZIOREADS_V, L"Unknown"); - SetDlgItemText(hwndDlg, IDC_ZIOREADBYTES_V, L"Unknown"); - SetDlgItemText(hwndDlg, IDC_ZIOWRITES_V, L"Unknown"); - SetDlgItemText(hwndDlg, IDC_ZIOWRITEBYTES_V, L"Unknown"); - SetDlgItemText(hwndDlg, IDC_ZIOOTHER_V, L"Unknown"); - SetDlgItemText(hwndDlg, IDC_ZIOOTHERBYTES_V, L"Unknown"); + PhSetDialogItemText(hwndDlg, IDC_ZACTIVEPROCESSES_V, L"Unknown"); + PhSetDialogItemText(hwndDlg, IDC_ZTOTALPROCESSES_V, L"Unknown"); + PhSetDialogItemText(hwndDlg, IDC_ZTERMINATEDPROCESSES_V, L"Unknown"); + + PhSetDialogItemText(hwndDlg, IDC_ZUSERTIME_V, L"Unknown"); + PhSetDialogItemText(hwndDlg, IDC_ZKERNELTIME_V, L"Unknown"); + PhSetDialogItemText(hwndDlg, IDC_ZUSERTIMEPERIOD_V, L"Unknown"); + PhSetDialogItemText(hwndDlg, IDC_ZKERNELTIMEPERIOD_V, L"Unknown"); + + PhSetDialogItemText(hwndDlg, IDC_ZPAGEFAULTS_V, L"Unknown"); + + PhSetDialogItemText(hwndDlg, IDC_ZIOREADS_V, L"Unknown"); + PhSetDialogItemText(hwndDlg, IDC_ZIOREADBYTES_V, L"Unknown"); + PhSetDialogItemText(hwndDlg, IDC_ZIOWRITES_V, L"Unknown"); + PhSetDialogItemText(hwndDlg, IDC_ZIOWRITEBYTES_V, L"Unknown"); + PhSetDialogItemText(hwndDlg, IDC_ZIOOTHER_V, L"Unknown"); + PhSetDialogItemText(hwndDlg, IDC_ZIOOTHERBYTES_V, L"Unknown"); } if (jobHandle && NT_SUCCESS(PhGetJobExtendedLimits( @@ -610,13 +610,13 @@ static VOID PhpRefreshJobStatisticsInfo( &extendedLimitInfo ))) { - SetDlgItemText(hwndDlg, IDC_ZPEAKPROCESSUSAGE_V, PhaFormatSize(extendedLimitInfo.PeakProcessMemoryUsed, -1)->Buffer); - SetDlgItemText(hwndDlg, IDC_ZPEAKJOBUSAGE_V, PhaFormatSize(extendedLimitInfo.PeakJobMemoryUsed, -1)->Buffer); + PhSetDialogItemText(hwndDlg, IDC_ZPEAKPROCESSUSAGE_V, PhaFormatSize(extendedLimitInfo.PeakProcessMemoryUsed, -1)->Buffer); + PhSetDialogItemText(hwndDlg, IDC_ZPEAKJOBUSAGE_V, PhaFormatSize(extendedLimitInfo.PeakJobMemoryUsed, -1)->Buffer); } else { - SetDlgItemText(hwndDlg, IDC_ZPEAKPROCESSUSAGE_V, L"Unknown"); - SetDlgItemText(hwndDlg, IDC_ZPEAKJOBUSAGE_V, L"Unknown"); + PhSetDialogItemText(hwndDlg, IDC_ZPEAKPROCESSUSAGE_V, L"Unknown"); + PhSetDialogItemText(hwndDlg, IDC_ZPEAKJOBUSAGE_V, L"Unknown"); } if (jobHandle) diff --git a/ProcessHacker/logwnd.c b/ProcessHacker/logwnd.c index 61f3df459a57..fc8bf864716e 100644 --- a/ProcessHacker/logwnd.c +++ b/ProcessHacker/logwnd.c @@ -242,7 +242,7 @@ INT_PTR CALLBACK PhpLogDlgProc( PhSetClipboardString(hwndDlg, &string->sr); PhDereferenceObject(string); - SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)ListViewHandle, TRUE); + PhSetDialogFocus(hwndDlg, ListViewHandle); } break; case IDC_SAVE: diff --git a/ProcessHacker/mdump.c b/ProcessHacker/mdump.c index 549b549bbba5..492dc9665a72 100644 --- a/ProcessHacker/mdump.c +++ b/ProcessHacker/mdump.c @@ -379,7 +379,7 @@ INT_PTR CALLBACK PhpProcessMiniDumpDlgProc( { PhCenterWindow(hwndDlg, GetParent(hwndDlg)); - SetDlgItemText(hwndDlg, IDC_PROGRESSTEXT, L"Creating the dump file..."); + PhSetDialogItemText(hwndDlg, IDC_PROGRESSTEXT, L"Creating the dump file..."); PhSetWindowStyle(GetDlgItem(hwndDlg, IDC_PROGRESS), PBS_MARQUEE, PBS_MARQUEE); SendMessage(GetDlgItem(hwndDlg, IDC_PROGRESS), PBM_SETMARQUEE, TRUE, 75); @@ -421,8 +421,7 @@ INT_PTR CALLBACK PhpProcessMiniDumpDlgProc( { // No status message update for 2 seconds. - SetDlgItemText(hwndDlg, IDC_PROGRESSTEXT, - (PWSTR)L"Creating the dump file..."); + PhSetDialogItemText(hwndDlg, IDC_PROGRESSTEXT, L"Creating the dump file..."); InvalidateRect(GetDlgItem(hwndDlg, IDC_PROGRESSTEXT), NULL, FALSE); context->LastTickCount = currentTickCount; @@ -435,7 +434,7 @@ INT_PTR CALLBACK PhpProcessMiniDumpDlgProc( switch (wParam) { case PH_MINIDUMP_STATUS_UPDATE: - SetDlgItemText(hwndDlg, IDC_PROGRESSTEXT, (PWSTR)lParam); + PhSetDialogItemText(hwndDlg, IDC_PROGRESSTEXT, (PWSTR)lParam); InvalidateRect(GetDlgItem(hwndDlg, IDC_PROGRESSTEXT), NULL, FALSE); context->LastTickCount = NtGetTickCount64(); break; diff --git a/ProcessHacker/memedit.c b/ProcessHacker/memedit.c index ef818d0e43d1..079ac2c343c6 100644 --- a/ProcessHacker/memedit.c +++ b/ProcessHacker/memedit.c @@ -344,7 +344,7 @@ INT_PTR CALLBACK PhpMemoryEditorDlgProc( break; case WM_SHOWWINDOW: { - SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)context->HexEditHandle, TRUE); + PhSetDialogFocus(hwndDlg, context->HexEditHandle); } break; case WM_COMMAND: @@ -439,7 +439,7 @@ INT_PTR CALLBACK PhpMemoryEditorDlgProc( continue; } - SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)context->HexEditHandle, TRUE); + PhSetDialogFocus(hwndDlg, context->HexEditHandle); HexEdit_SetSel(context->HexEditHandle, (LONG)offset, (LONG)offset); break; } @@ -524,7 +524,7 @@ INT_PTR CALLBACK PhpMemoryEditorDlgProc( { PhSetIntegerSetting(L"MemEditBytesPerRow", (ULONG)bytesPerRow64); HexEdit_SetBytesPerRow(context->HexEditHandle, (ULONG)bytesPerRow64); - SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)context->HexEditHandle, TRUE); + PhSetDialogFocus(hwndDlg, context->HexEditHandle); } } } diff --git a/ProcessHacker/memlists.c b/ProcessHacker/memlists.c index 2922350923d5..fd1a094a0396 100644 --- a/ProcessHacker/memlists.c +++ b/ProcessHacker/memlists.c @@ -101,61 +101,61 @@ static VOID PhpUpdateMemoryListInfo( repurposedPageCount += memoryListInfo.RepurposedPagesByPriority[i]; } - SetDlgItemText(hwndDlg, IDC_ZLISTZEROED_V, PhaFormatSize((ULONG64)memoryListInfo.ZeroPageCount * PAGE_SIZE, -1)->Buffer); - SetDlgItemText(hwndDlg, IDC_ZLISTFREE_V, PhaFormatSize((ULONG64)memoryListInfo.FreePageCount * PAGE_SIZE, -1)->Buffer); - SetDlgItemText(hwndDlg, IDC_ZLISTMODIFIED_V, PhaFormatSize((ULONG64)memoryListInfo.ModifiedPageCount * PAGE_SIZE, -1)->Buffer); - SetDlgItemText(hwndDlg, IDC_ZLISTMODIFIEDNOWRITE_V, PhaFormatSize((ULONG64)memoryListInfo.ModifiedNoWritePageCount * PAGE_SIZE, -1)->Buffer); - SetDlgItemText(hwndDlg, IDC_ZLISTBAD_V, PhaFormatSize((ULONG64)memoryListInfo.BadPageCount * PAGE_SIZE, -1)->Buffer); - SetDlgItemText(hwndDlg, IDC_ZLISTSTANDBY_V, PhaFormatSize((ULONG64)standbyPageCount * PAGE_SIZE, -1)->Buffer); - SetDlgItemText(hwndDlg, IDC_ZLISTSTANDBY0_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[0] * PAGE_SIZE, -1)->Buffer); - SetDlgItemText(hwndDlg, IDC_ZLISTSTANDBY1_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[1] * PAGE_SIZE, -1)->Buffer); - SetDlgItemText(hwndDlg, IDC_ZLISTSTANDBY2_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[2] * PAGE_SIZE, -1)->Buffer); - SetDlgItemText(hwndDlg, IDC_ZLISTSTANDBY3_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[3] * PAGE_SIZE, -1)->Buffer); - SetDlgItemText(hwndDlg, IDC_ZLISTSTANDBY4_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[4] * PAGE_SIZE, -1)->Buffer); - SetDlgItemText(hwndDlg, IDC_ZLISTSTANDBY5_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[5] * PAGE_SIZE, -1)->Buffer); - SetDlgItemText(hwndDlg, IDC_ZLISTSTANDBY6_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[6] * PAGE_SIZE, -1)->Buffer); - SetDlgItemText(hwndDlg, IDC_ZLISTSTANDBY7_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[7] * PAGE_SIZE, -1)->Buffer); - SetDlgItemText(hwndDlg, IDC_ZLISTREPURPOSED_V, PhaFormatSize((ULONG64)repurposedPageCount * PAGE_SIZE, -1)->Buffer); - SetDlgItemText(hwndDlg, IDC_ZLISTREPURPOSED0_V, PhaFormatSize((ULONG64)memoryListInfo.RepurposedPagesByPriority[0] * PAGE_SIZE, -1)->Buffer); - SetDlgItemText(hwndDlg, IDC_ZLISTREPURPOSED1_V, PhaFormatSize((ULONG64)memoryListInfo.RepurposedPagesByPriority[1] * PAGE_SIZE, -1)->Buffer); - SetDlgItemText(hwndDlg, IDC_ZLISTREPURPOSED2_V, PhaFormatSize((ULONG64)memoryListInfo.RepurposedPagesByPriority[2] * PAGE_SIZE, -1)->Buffer); - SetDlgItemText(hwndDlg, IDC_ZLISTREPURPOSED3_V, PhaFormatSize((ULONG64)memoryListInfo.RepurposedPagesByPriority[3] * PAGE_SIZE, -1)->Buffer); - SetDlgItemText(hwndDlg, IDC_ZLISTREPURPOSED4_V, PhaFormatSize((ULONG64)memoryListInfo.RepurposedPagesByPriority[4] * PAGE_SIZE, -1)->Buffer); - SetDlgItemText(hwndDlg, IDC_ZLISTREPURPOSED5_V, PhaFormatSize((ULONG64)memoryListInfo.RepurposedPagesByPriority[5] * PAGE_SIZE, -1)->Buffer); - SetDlgItemText(hwndDlg, IDC_ZLISTREPURPOSED6_V, PhaFormatSize((ULONG64)memoryListInfo.RepurposedPagesByPriority[6] * PAGE_SIZE, -1)->Buffer); - SetDlgItemText(hwndDlg, IDC_ZLISTREPURPOSED7_V, PhaFormatSize((ULONG64)memoryListInfo.RepurposedPagesByPriority[7] * PAGE_SIZE, -1)->Buffer); + PhSetDialogItemText(hwndDlg, IDC_ZLISTZEROED_V, PhaFormatSize((ULONG64)memoryListInfo.ZeroPageCount * PAGE_SIZE, -1)->Buffer); + PhSetDialogItemText(hwndDlg, IDC_ZLISTFREE_V, PhaFormatSize((ULONG64)memoryListInfo.FreePageCount * PAGE_SIZE, -1)->Buffer); + PhSetDialogItemText(hwndDlg, IDC_ZLISTMODIFIED_V, PhaFormatSize((ULONG64)memoryListInfo.ModifiedPageCount * PAGE_SIZE, -1)->Buffer); + PhSetDialogItemText(hwndDlg, IDC_ZLISTMODIFIEDNOWRITE_V, PhaFormatSize((ULONG64)memoryListInfo.ModifiedNoWritePageCount * PAGE_SIZE, -1)->Buffer); + PhSetDialogItemText(hwndDlg, IDC_ZLISTBAD_V, PhaFormatSize((ULONG64)memoryListInfo.BadPageCount * PAGE_SIZE, -1)->Buffer); + PhSetDialogItemText(hwndDlg, IDC_ZLISTSTANDBY_V, PhaFormatSize((ULONG64)standbyPageCount * PAGE_SIZE, -1)->Buffer); + PhSetDialogItemText(hwndDlg, IDC_ZLISTSTANDBY0_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[0] * PAGE_SIZE, -1)->Buffer); + PhSetDialogItemText(hwndDlg, IDC_ZLISTSTANDBY1_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[1] * PAGE_SIZE, -1)->Buffer); + PhSetDialogItemText(hwndDlg, IDC_ZLISTSTANDBY2_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[2] * PAGE_SIZE, -1)->Buffer); + PhSetDialogItemText(hwndDlg, IDC_ZLISTSTANDBY3_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[3] * PAGE_SIZE, -1)->Buffer); + PhSetDialogItemText(hwndDlg, IDC_ZLISTSTANDBY4_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[4] * PAGE_SIZE, -1)->Buffer); + PhSetDialogItemText(hwndDlg, IDC_ZLISTSTANDBY5_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[5] * PAGE_SIZE, -1)->Buffer); + PhSetDialogItemText(hwndDlg, IDC_ZLISTSTANDBY6_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[6] * PAGE_SIZE, -1)->Buffer); + PhSetDialogItemText(hwndDlg, IDC_ZLISTSTANDBY7_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[7] * PAGE_SIZE, -1)->Buffer); + PhSetDialogItemText(hwndDlg, IDC_ZLISTREPURPOSED_V, PhaFormatSize((ULONG64)repurposedPageCount * PAGE_SIZE, -1)->Buffer); + PhSetDialogItemText(hwndDlg, IDC_ZLISTREPURPOSED0_V, PhaFormatSize((ULONG64)memoryListInfo.RepurposedPagesByPriority[0] * PAGE_SIZE, -1)->Buffer); + PhSetDialogItemText(hwndDlg, IDC_ZLISTREPURPOSED1_V, PhaFormatSize((ULONG64)memoryListInfo.RepurposedPagesByPriority[1] * PAGE_SIZE, -1)->Buffer); + PhSetDialogItemText(hwndDlg, IDC_ZLISTREPURPOSED2_V, PhaFormatSize((ULONG64)memoryListInfo.RepurposedPagesByPriority[2] * PAGE_SIZE, -1)->Buffer); + PhSetDialogItemText(hwndDlg, IDC_ZLISTREPURPOSED3_V, PhaFormatSize((ULONG64)memoryListInfo.RepurposedPagesByPriority[3] * PAGE_SIZE, -1)->Buffer); + PhSetDialogItemText(hwndDlg, IDC_ZLISTREPURPOSED4_V, PhaFormatSize((ULONG64)memoryListInfo.RepurposedPagesByPriority[4] * PAGE_SIZE, -1)->Buffer); + PhSetDialogItemText(hwndDlg, IDC_ZLISTREPURPOSED5_V, PhaFormatSize((ULONG64)memoryListInfo.RepurposedPagesByPriority[5] * PAGE_SIZE, -1)->Buffer); + PhSetDialogItemText(hwndDlg, IDC_ZLISTREPURPOSED6_V, PhaFormatSize((ULONG64)memoryListInfo.RepurposedPagesByPriority[6] * PAGE_SIZE, -1)->Buffer); + PhSetDialogItemText(hwndDlg, IDC_ZLISTREPURPOSED7_V, PhaFormatSize((ULONG64)memoryListInfo.RepurposedPagesByPriority[7] * PAGE_SIZE, -1)->Buffer); if (WindowsVersion >= WINDOWS_8) - SetDlgItemText(hwndDlg, IDC_ZLISTMODIFIEDPAGEFILE_V, PhaFormatSize((ULONG64)memoryListInfo.ModifiedPageCountPageFile * PAGE_SIZE, -1)->Buffer); + PhSetDialogItemText(hwndDlg, IDC_ZLISTMODIFIEDPAGEFILE_V, PhaFormatSize((ULONG64)memoryListInfo.ModifiedPageCountPageFile * PAGE_SIZE, -1)->Buffer); else - SetDlgItemText(hwndDlg, IDC_ZLISTMODIFIEDPAGEFILE_V, L"N/A"); + PhSetDialogItemText(hwndDlg, IDC_ZLISTMODIFIEDPAGEFILE_V, L"N/A"); } else { - SetDlgItemText(hwndDlg, IDC_ZLISTZEROED_V, L"Unknown"); - SetDlgItemText(hwndDlg, IDC_ZLISTFREE_V, L"Unknown"); - SetDlgItemText(hwndDlg, IDC_ZLISTMODIFIED_V, L"Unknown"); - SetDlgItemText(hwndDlg, IDC_ZLISTMODIFIEDNOWRITE_V, L"Unknown"); - SetDlgItemText(hwndDlg, IDC_ZLISTMODIFIEDPAGEFILE_V, L"Unknown"); - SetDlgItemText(hwndDlg, IDC_ZLISTBAD_V, L"Unknown"); - SetDlgItemText(hwndDlg, IDC_ZLISTSTANDBY_V, L"Unknown"); - SetDlgItemText(hwndDlg, IDC_ZLISTSTANDBY0_V, L"Unknown"); - SetDlgItemText(hwndDlg, IDC_ZLISTSTANDBY1_V, L"Unknown"); - SetDlgItemText(hwndDlg, IDC_ZLISTSTANDBY2_V, L"Unknown"); - SetDlgItemText(hwndDlg, IDC_ZLISTSTANDBY3_V, L"Unknown"); - SetDlgItemText(hwndDlg, IDC_ZLISTSTANDBY4_V, L"Unknown"); - SetDlgItemText(hwndDlg, IDC_ZLISTSTANDBY5_V, L"Unknown"); - SetDlgItemText(hwndDlg, IDC_ZLISTSTANDBY6_V, L"Unknown"); - SetDlgItemText(hwndDlg, IDC_ZLISTSTANDBY7_V, L"Unknown"); - SetDlgItemText(hwndDlg, IDC_ZLISTREPURPOSED_V, L"Unknown"); - SetDlgItemText(hwndDlg, IDC_ZLISTREPURPOSED0_V, L"Unknown"); - SetDlgItemText(hwndDlg, IDC_ZLISTREPURPOSED1_V, L"Unknown"); - SetDlgItemText(hwndDlg, IDC_ZLISTREPURPOSED2_V, L"Unknown"); - SetDlgItemText(hwndDlg, IDC_ZLISTREPURPOSED3_V, L"Unknown"); - SetDlgItemText(hwndDlg, IDC_ZLISTREPURPOSED4_V, L"Unknown"); - SetDlgItemText(hwndDlg, IDC_ZLISTREPURPOSED5_V, L"Unknown"); - SetDlgItemText(hwndDlg, IDC_ZLISTREPURPOSED6_V, L"Unknown"); - SetDlgItemText(hwndDlg, IDC_ZLISTREPURPOSED7_V, L"Unknown"); + PhSetDialogItemText(hwndDlg, IDC_ZLISTZEROED_V, L"Unknown"); + PhSetDialogItemText(hwndDlg, IDC_ZLISTFREE_V, L"Unknown"); + PhSetDialogItemText(hwndDlg, IDC_ZLISTMODIFIED_V, L"Unknown"); + PhSetDialogItemText(hwndDlg, IDC_ZLISTMODIFIEDNOWRITE_V, L"Unknown"); + PhSetDialogItemText(hwndDlg, IDC_ZLISTMODIFIEDPAGEFILE_V, L"Unknown"); + PhSetDialogItemText(hwndDlg, IDC_ZLISTBAD_V, L"Unknown"); + PhSetDialogItemText(hwndDlg, IDC_ZLISTSTANDBY_V, L"Unknown"); + PhSetDialogItemText(hwndDlg, IDC_ZLISTSTANDBY0_V, L"Unknown"); + PhSetDialogItemText(hwndDlg, IDC_ZLISTSTANDBY1_V, L"Unknown"); + PhSetDialogItemText(hwndDlg, IDC_ZLISTSTANDBY2_V, L"Unknown"); + PhSetDialogItemText(hwndDlg, IDC_ZLISTSTANDBY3_V, L"Unknown"); + PhSetDialogItemText(hwndDlg, IDC_ZLISTSTANDBY4_V, L"Unknown"); + PhSetDialogItemText(hwndDlg, IDC_ZLISTSTANDBY5_V, L"Unknown"); + PhSetDialogItemText(hwndDlg, IDC_ZLISTSTANDBY6_V, L"Unknown"); + PhSetDialogItemText(hwndDlg, IDC_ZLISTSTANDBY7_V, L"Unknown"); + PhSetDialogItemText(hwndDlg, IDC_ZLISTREPURPOSED_V, L"Unknown"); + PhSetDialogItemText(hwndDlg, IDC_ZLISTREPURPOSED0_V, L"Unknown"); + PhSetDialogItemText(hwndDlg, IDC_ZLISTREPURPOSED1_V, L"Unknown"); + PhSetDialogItemText(hwndDlg, IDC_ZLISTREPURPOSED2_V, L"Unknown"); + PhSetDialogItemText(hwndDlg, IDC_ZLISTREPURPOSED3_V, L"Unknown"); + PhSetDialogItemText(hwndDlg, IDC_ZLISTREPURPOSED4_V, L"Unknown"); + PhSetDialogItemText(hwndDlg, IDC_ZLISTREPURPOSED5_V, L"Unknown"); + PhSetDialogItemText(hwndDlg, IDC_ZLISTREPURPOSED6_V, L"Unknown"); + PhSetDialogItemText(hwndDlg, IDC_ZLISTREPURPOSED7_V, L"Unknown"); } } diff --git a/ProcessHacker/memprot.c b/ProcessHacker/memprot.c index 15b2bf0e563d..80dfa060a5e3 100644 --- a/ProcessHacker/memprot.c +++ b/ProcessHacker/memprot.c @@ -75,7 +75,7 @@ static INT_PTR CALLBACK PhpMemoryProtectDlgProc( PhCenterWindow(hwndDlg, GetParent(hwndDlg)); - SetDlgItemText(hwndDlg, IDC_INTRO, + PhSetDialogItemText(hwndDlg, IDC_INTRO, L"Possible values:\r\n" L"\r\n" L"0x01 - PAGE_NOACCESS\r\n" @@ -92,7 +92,7 @@ static INT_PTR CALLBACK PhpMemoryProtectDlgProc( L"0x400 - PAGE_WRITECOMBINE\r\n" ); - SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hwndDlg, IDC_VALUE), TRUE); + PhSetDialogFocus(hwndDlg, GetDlgItem(hwndDlg, IDC_VALUE)); } break; case WM_DESTROY: @@ -148,7 +148,7 @@ static INT_PTR CALLBACK PhpMemoryProtectDlgProc( else { PhShowStatus(hwndDlg, L"Unable to change memory protection", status, 0); - SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hwndDlg, IDC_VALUE), TRUE); + PhSetDialogFocus(hwndDlg, GetDlgItem(hwndDlg, IDC_VALUE)); Edit_SetSel(GetDlgItem(hwndDlg, IDC_VALUE), 0, -1); } } diff --git a/ProcessHacker/memrslt.c b/ProcessHacker/memrslt.c index 8d36878e31b9..3ce7325d15d4 100644 --- a/ProcessHacker/memrslt.c +++ b/ProcessHacker/memrslt.c @@ -333,7 +333,7 @@ INT_PTR CALLBACK PhpMemoryResultsDlgProc( ListView_SetItemCount(lvHandle, context->Results->Count); - SetDlgItemText(hwndDlg, IDC_INTRO, PhaFormatString(L"%s results.", + PhSetDialogItemText(hwndDlg, IDC_INTRO, PhaFormatString(L"%s results.", PhaFormatUInt64(context->Results->Count, TRUE)->Buffer)->Buffer); { @@ -400,7 +400,7 @@ INT_PTR CALLBACK PhpMemoryResultsDlgProc( PhSetClipboardString(hwndDlg, &string->sr); PhDereferenceObject(string); - SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)lvHandle, TRUE); + PhSetDialogFocus(hwndDlg, lvHandle); } break; case IDC_SAVE: @@ -722,7 +722,7 @@ INT_PTR CALLBACK PhpMemoryResultsDlgProc( PhSetClipboardString(hwndDlg, &string->sr); PhDereferenceObject(string); - SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)lvHandle, TRUE); + PhSetDialogFocus(hwndDlg, lvHandle); } break; } diff --git a/ProcessHacker/memsrch.c b/ProcessHacker/memsrch.c index 7e6a85d81fb8..f3b2108bc6c0 100644 --- a/ProcessHacker/memsrch.c +++ b/ProcessHacker/memsrch.c @@ -563,7 +563,7 @@ INT_PTR CALLBACK PhpMemoryStringDlgProc( { PhCenterWindow(hwndDlg, GetParent(hwndDlg)); - SetDlgItemText(hwndDlg, IDC_MINIMUMLENGTH, L"10"); + PhSetDialogItemText(hwndDlg, IDC_MINIMUMLENGTH, L"10"); Button_SetCheck(GetDlgItem(hwndDlg, IDC_DETECTUNICODE), BST_CHECKED); Button_SetCheck(GetDlgItem(hwndDlg, IDC_PRIVATE), BST_CHECKED); } diff --git a/ProcessHacker/miniinfo.c b/ProcessHacker/miniinfo.c index 26c0bb793dfd..503d2af8bbc6 100644 --- a/ProcessHacker/miniinfo.c +++ b/ProcessHacker/miniinfo.c @@ -936,12 +936,12 @@ VOID PhMipUpdateSectionText( { if (Section->Text) { - SetDlgItemText(PhMipWindow, IDC_SECTION, + PhSetDialogItemText(PhMipWindow, IDC_SECTION, PH_AUTO_T(PH_STRING, PhConcatStringRef2(&DownArrowPrefix, &Section->Text->sr))->Buffer); } else { - SetDlgItemText(PhMipWindow, IDC_SECTION, + PhSetDialogItemText(PhMipWindow, IDC_SECTION, PH_AUTO_T(PH_STRING, PhConcatStringRef2(&DownArrowPrefix, &Section->Name))->Buffer); } } diff --git a/ProcessHacker/mtgndlg.c b/ProcessHacker/mtgndlg.c index bebfdc8791ee..ec27742c7a2a 100644 --- a/ProcessHacker/mtgndlg.c +++ b/ProcessHacker/mtgndlg.c @@ -251,7 +251,8 @@ INT_PTR CALLBACK PhpProcessMitigationPolicyDlgProc( ExtendedListView_SortItems(lvHandle); ExtendedListView_SetColumnWidth(lvHandle, 0, ELVSCW_AUTOSIZE_REMAININGSPACE); ListView_SetItemState(lvHandle, 0, LVIS_FOCUSED | LVIS_SELECTED, LVIS_FOCUSED | LVIS_SELECTED); - SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)lvHandle, TRUE); + + PhSetDialogFocus(hwndDlg, lvHandle); } break; case WM_DESTROY: @@ -307,7 +308,7 @@ INT_PTR CALLBACK PhpProcessMitigationPolicyDlgProc( else description = L""; - SetDlgItemText(hwndDlg, IDC_DESCRIPTION, description); + PhSetDialogItemText(hwndDlg, IDC_DESCRIPTION, description); } } break; diff --git a/ProcessHacker/ntobjprp.c b/ProcessHacker/ntobjprp.c index ae561a3b91a0..c091ed116d81 100644 --- a/ProcessHacker/ntobjprp.c +++ b/ProcessHacker/ntobjprp.c @@ -220,8 +220,8 @@ static VOID PhpRefreshEventPageInfo( eventState = basicInfo.EventState > 0 ? L"True" : L"False"; } - SetDlgItemText(hwndDlg, IDC_TYPE, eventType); - SetDlgItemText(hwndDlg, IDC_SIGNALED, eventState); + PhSetDialogItemText(hwndDlg, IDC_TYPE, eventType); + PhSetDialogItemText(hwndDlg, IDC_SIGNALED, eventState); NtClose(eventHandle); } @@ -417,7 +417,7 @@ static VOID PhpRefreshFilePageInfo( switch (deviceInformation.DeviceType) { case FILE_DEVICE_NAMED_PIPE: - SetDlgItemText(hwndDlg, IDC_FILETYPE, L"Pipe"); + PhSetDialogItemText(hwndDlg, IDC_FILETYPE, L"Pipe"); break; case FILE_DEVICE_CD_ROM: case FILE_DEVICE_CD_ROM_FILE_SYSTEM: @@ -428,10 +428,10 @@ static VOID PhpRefreshFilePageInfo( case FILE_DEVICE_DISK_FILE_SYSTEM: case FILE_DEVICE_VIRTUAL_DISK: isFileOrDirectory = TRUE; - SetDlgItemText(hwndDlg, IDC_FILETYPE, L"File or directory"); + PhSetDialogItemText(hwndDlg, IDC_FILETYPE, L"File or directory"); break; default: - SetDlgItemText(hwndDlg, IDC_FILETYPE, L"Other"); + PhSetDialogItemText(hwndDlg, IDC_FILETYPE, L"Other"); break; } } @@ -450,12 +450,12 @@ static VOID PhpRefreshFilePageInfo( disableFlushButton |= fileStandardInfo.Directory; fileSizeStr = PhFormatSize(fileStandardInfo.EndOfFile.QuadPart, -1); - SetDlgItemText(hwndDlg, IDC_FILESIZE, fileSizeStr->Buffer); + PhSetDialogItemText(hwndDlg, IDC_FILESIZE, fileSizeStr->Buffer); PhDereferenceObject(fileSizeStr); if (isFileOrDirectory) { - SetDlgItemText(hwndDlg, IDC_FILETYPE, fileStandardInfo.Directory ? L"Directory" : L"File"); + PhSetDialogItemText(hwndDlg, IDC_FILETYPE, fileStandardInfo.Directory ? L"Directory" : L"File"); } } @@ -491,7 +491,7 @@ static VOID PhpRefreshFilePageInfo( filePosStr = PhFormatUInt64(filePositionInfo.CurrentByteOffset.QuadPart, TRUE); } - SetDlgItemText(hwndDlg, IDC_POSITION, filePosStr->Buffer); + PhSetDialogItemText(hwndDlg, IDC_POSITION, filePosStr->Buffer); PhDereferenceObject(filePosStr); } @@ -525,14 +525,14 @@ static VOID PhpRefreshFilePageInfo( PhInitFormatS(&format[4], L")"); fileModeStr = PhFormat(format, 5, 64); - SetDlgItemText(hwndDlg, IDC_FILEMODE, fileModeStr->Buffer); + PhSetDialogItemText(hwndDlg, IDC_FILEMODE, fileModeStr->Buffer); PhDereferenceObject(fileModeStr); PhDereferenceObject(fileModeAccessStr); } else { - SetDlgItemText(hwndDlg, IDC_FILEMODE, L"Unknown"); + PhSetDialogItemText(hwndDlg, IDC_FILEMODE, L"Unknown"); } EnableWindow(GetDlgItem(hwndDlg, IDC_FLUSH), !disableFlushButton); @@ -624,13 +624,13 @@ static VOID PhpRefreshMutantPageInfo( if (NT_SUCCESS(PhGetMutantBasicInformation(mutantHandle, &basicInfo))) { - SetDlgItemInt(hwndDlg, IDC_COUNT, basicInfo.CurrentCount, TRUE); - SetDlgItemText(hwndDlg, IDC_ABANDONED, basicInfo.AbandonedState ? L"True" : L"False"); + PhSetDialogItemValue(hwndDlg, IDC_COUNT, basicInfo.CurrentCount, TRUE); + PhSetDialogItemText(hwndDlg, IDC_ABANDONED, basicInfo.AbandonedState ? L"True" : L"False"); } else { - SetDlgItemText(hwndDlg, IDC_COUNT, L"Unknown"); - SetDlgItemText(hwndDlg, IDC_ABANDONED, L"Unknown"); + PhSetDialogItemText(hwndDlg, IDC_COUNT, L"Unknown"); + PhSetDialogItemText(hwndDlg, IDC_ABANDONED, L"Unknown"); } if (NT_SUCCESS(PhGetMutantOwnerInformation(mutantHandle, &ownerInfo))) @@ -640,17 +640,17 @@ static VOID PhpRefreshMutantPageInfo( if (ownerInfo.ClientId.UniqueProcess) { name = PhGetClientIdName(&ownerInfo.ClientId); - SetDlgItemText(hwndDlg, IDC_OWNER, name->Buffer); + PhSetDialogItemText(hwndDlg, IDC_OWNER, name->Buffer); PhDereferenceObject(name); } else { - SetDlgItemText(hwndDlg, IDC_OWNER, L"N/A"); + PhSetDialogItemText(hwndDlg, IDC_OWNER, L"N/A"); } } else { - SetDlgItemText(hwndDlg, IDC_OWNER, L"Unknown"); + PhSetDialogItemText(hwndDlg, IDC_OWNER, L"Unknown"); } NtClose(mutantHandle); @@ -747,9 +747,9 @@ static VOID PhpRefreshSectionPageInfo( fileName = PH_AUTO(newFileName); } - SetDlgItemText(hwndDlg, IDC_TYPE, sectionType); - SetDlgItemText(hwndDlg, IDC_SIZE_, PhGetStringOrDefault(sectionSize, L"Unknown")); - SetDlgItemText(hwndDlg, IDC_FILE, PhGetStringOrDefault(fileName, L"N/A")); + PhSetDialogItemText(hwndDlg, IDC_TYPE, sectionType); + PhSetDialogItemText(hwndDlg, IDC_SIZE_, PhGetStringOrDefault(sectionSize, L"Unknown")); + PhSetDialogItemText(hwndDlg, IDC_FILE, PhGetStringOrDefault(fileName, L"N/A")); NtClose(sectionHandle); } @@ -810,13 +810,13 @@ static VOID PhpRefreshSemaphorePageInfo( if (NT_SUCCESS(PhGetSemaphoreBasicInformation(semaphoreHandle, &basicInfo))) { - SetDlgItemInt(hwndDlg, IDC_CURRENTCOUNT, basicInfo.CurrentCount, TRUE); - SetDlgItemInt(hwndDlg, IDC_MAXIMUMCOUNT, basicInfo.MaximumCount, TRUE); + PhSetDialogItemValue(hwndDlg, IDC_CURRENTCOUNT, basicInfo.CurrentCount, TRUE); + PhSetDialogItemValue(hwndDlg, IDC_MAXIMUMCOUNT, basicInfo.MaximumCount, TRUE); } else { - SetDlgItemText(hwndDlg, IDC_CURRENTCOUNT, L"Unknown"); - SetDlgItemText(hwndDlg, IDC_MAXIMUMCOUNT, L"Unknown"); + PhSetDialogItemText(hwndDlg, IDC_CURRENTCOUNT, L"Unknown"); + PhSetDialogItemText(hwndDlg, IDC_MAXIMUMCOUNT, L"Unknown"); } NtClose(semaphoreHandle); @@ -922,11 +922,11 @@ static VOID PhpRefreshTimerPageInfo( if (NT_SUCCESS(PhGetTimerBasicInformation(timerHandle, &basicInfo))) { - SetDlgItemText(hwndDlg, IDC_SIGNALED, basicInfo.TimerState ? L"True" : L"False"); + PhSetDialogItemText(hwndDlg, IDC_SIGNALED, basicInfo.TimerState ? L"True" : L"False"); } else { - SetDlgItemText(hwndDlg, IDC_SIGNALED, L"Unknown"); + PhSetDialogItemText(hwndDlg, IDC_SIGNALED, L"Unknown"); } NtClose(timerHandle); diff --git a/ProcessHacker/options.c b/ProcessHacker/options.c index 2070413c883a..2acc423573cc 100644 --- a/ProcessHacker/options.c +++ b/ProcessHacker/options.c @@ -976,7 +976,7 @@ static VOID PhpAdvancedPageLoad( listViewHandle = GetDlgItem(hwndDlg, IDC_SETTINGS); - SetDlgItemInt(hwndDlg, IDC_SAMPLECOUNT, PhGetIntegerSetting(L"SampleCount"), FALSE); + PhSetDialogItemValue(hwndDlg, IDC_SAMPLECOUNT, PhGetIntegerSetting(L"SampleCount"), FALSE); SetDlgItemCheckForSetting(hwndDlg, IDC_SAMPLECOUNTAUTOMATIC, L"SampleCountAutomatic"); if (PhGetIntegerSetting(L"SampleCountAutomatic")) @@ -1040,7 +1040,7 @@ static VOID PhpAdvancedPageSave( ULONG sampleCount; listViewHandle = GetDlgItem(hwndDlg, IDC_SETTINGS); - sampleCount = GetDlgItemInt(hwndDlg, IDC_SAMPLECOUNT, NULL, FALSE); + sampleCount = PhGetDialogItemValue(hwndDlg, IDC_SAMPLECOUNT); SetSettingForDlgItemCheckRestartRequired(hwndDlg, IDC_SAMPLECOUNTAUTOMATIC, L"SampleCountAutomatic"); @@ -1054,7 +1054,7 @@ static VOID PhpAdvancedPageSave( PhSetStringSetting2(L"SearchEngine", &PhaGetDlgItemText(hwndDlg, IDC_SEARCHENGINE)->sr); PhSetStringSetting2(L"ProgramInspectExecutables", &PhaGetDlgItemText(hwndDlg, IDC_PEVIEWER)->sr); PhSetIntegerSetting(L"MaxSizeUnit", PhMaxSizeUnit = ComboBox_GetCurSel(GetDlgItem(hwndDlg, IDC_MAXSIZEUNIT))); - PhSetIntegerSetting(L"IconProcesses", GetDlgItemInt(hwndDlg, IDC_ICONPROCESSES, NULL, FALSE)); + PhSetIntegerSetting(L"IconProcesses", PhGetDialogItemValue(hwndDlg, IDC_ICONPROCESSES)); if (!PhEqualString(PhaGetDlgItemText(hwndDlg, IDC_DBGHELPSEARCHPATH), PhaGetStringSetting(L"DbgHelpSearchPath"), TRUE)) { @@ -1152,10 +1152,10 @@ INT_PTR CALLBACK PhpOptionsGeneralDlgProc( else ComboBox_SetCurSel(comboBoxHandle, ARRAYSIZE(PhSizeUnitNames) - 1); - SetDlgItemText(hwndDlg, IDC_SEARCHENGINE, PhaGetStringSetting(L"SearchEngine")->Buffer); - SetDlgItemText(hwndDlg, IDC_PEVIEWER, PhaGetStringSetting(L"ProgramInspectExecutables")->Buffer); - SetDlgItemInt(hwndDlg, IDC_ICONPROCESSES, PhGetIntegerSetting(L"IconProcesses"), FALSE); - SetDlgItemText(hwndDlg, IDC_DBGHELPSEARCHPATH, PhaGetStringSetting(L"DbgHelpSearchPath")->Buffer); + PhSetDialogItemText(hwndDlg, IDC_SEARCHENGINE, PhaGetStringSetting(L"SearchEngine")->Buffer); + PhSetDialogItemText(hwndDlg, IDC_PEVIEWER, PhaGetStringSetting(L"ProgramInspectExecutables")->Buffer); + PhSetDialogItemValue(hwndDlg, IDC_ICONPROCESSES, PhGetIntegerSetting(L"IconProcesses"), FALSE); + PhSetDialogItemText(hwndDlg, IDC_DBGHELPSEARCHPATH, PhaGetStringSetting(L"DbgHelpSearchPath")->Buffer); ReadCurrentUserRun(); @@ -1469,12 +1469,12 @@ static INT_PTR CALLBACK PhpOptionsAdvancedEditDlgProc( PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDOK), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDCANCEL), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); - SetDlgItemText(hwndDlg, IDC_NAME, setting->Name.Buffer); - SetDlgItemText(hwndDlg, IDC_VALUE, PH_AUTO_T(PH_STRING, PhSettingToString(setting->Type, setting))->Buffer); + PhSetDialogItemText(hwndDlg, IDC_NAME, setting->Name.Buffer); + PhSetDialogItemText(hwndDlg, IDC_VALUE, PH_AUTO_T(PH_STRING, PhSettingToString(setting->Type, setting))->Buffer); EnableWindow(GetDlgItem(hwndDlg, IDC_NAME), FALSE); - SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hwndDlg, IDCANCEL), TRUE); + PhSetDialogFocus(hwndDlg, GetDlgItem(hwndDlg, IDCANCEL)); } break; case WM_DESTROY: @@ -1693,7 +1693,7 @@ INT_PTR CALLBACK PhpOptionsHighlightingDlgProc( case WM_INITDIALOG: { // Highlighting Duration - SetDlgItemInt(hwndDlg, IDC_HIGHLIGHTINGDURATION, PhCsHighlightingDuration, FALSE); + PhSetDialogItemValue(hwndDlg, IDC_HIGHLIGHTINGDURATION, PhCsHighlightingDuration, FALSE); // New Objects ColorBox_SetColor(GetDlgItem(hwndDlg, IDC_NEWOBJECTS), PhCsColorNew); @@ -1728,7 +1728,7 @@ INT_PTR CALLBACK PhpOptionsHighlightingDlgProc( break; case WM_DESTROY: { - PH_SET_INTEGER_CACHED_SETTING(HighlightingDuration, GetDlgItemInt(hwndDlg, IDC_HIGHLIGHTINGDURATION, NULL, FALSE)); + PH_SET_INTEGER_CACHED_SETTING(HighlightingDuration, PhGetDialogItemValue(hwndDlg, IDC_HIGHLIGHTINGDURATION)); PH_SET_INTEGER_CACHED_SETTING(ColorNew, ColorBox_GetColor(GetDlgItem(hwndDlg, IDC_NEWOBJECTS))); PH_SET_INTEGER_CACHED_SETTING(ColorRemoved, ColorBox_GetColor(GetDlgItem(hwndDlg, IDC_REMOVEDOBJECTS))); diff --git a/ProcessHacker/pagfiles.c b/ProcessHacker/pagfiles.c index 43fa8df9d759..21e319e376b3 100644 --- a/ProcessHacker/pagfiles.c +++ b/ProcessHacker/pagfiles.c @@ -122,7 +122,7 @@ INT_PTR CALLBACK PhpPagefilesDlgProc( EndDialog(hwndDlg, IDCANCEL); } - SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hwndDlg, IDOK), TRUE); + PhSetDialogFocus(hwndDlg, GetDlgItem(hwndDlg, IDOK)); } break; case WM_COMMAND: diff --git a/ProcessHacker/plugman.c b/ProcessHacker/plugman.c index b105bbd93b21..4259a97b1127 100644 --- a/ProcessHacker/plugman.c +++ b/ProcessHacker/plugman.c @@ -924,21 +924,21 @@ VOID PhpRefreshPluginDetails( fileName = SelectedPlugin->FileName; - SetDlgItemText(hwndDlg, IDC_NAME, SelectedPlugin->Information.DisplayName ? SelectedPlugin->Information.DisplayName : L"(unnamed)"); - SetDlgItemText(hwndDlg, IDC_INTERNALNAME, SelectedPlugin->Name.Buffer); - SetDlgItemText(hwndDlg, IDC_AUTHOR, SelectedPlugin->Information.Author); - SetDlgItemText(hwndDlg, IDC_FILENAME, PH_AUTO_T(PH_STRING, PhGetBaseName(fileName))->Buffer); - SetDlgItemText(hwndDlg, IDC_DESCRIPTION, SelectedPlugin->Information.Description); - SetDlgItemText(hwndDlg, IDC_URL, SelectedPlugin->Information.Url); + PhSetDialogItemText(hwndDlg, IDC_NAME, SelectedPlugin->Information.DisplayName ? SelectedPlugin->Information.DisplayName : L"(unnamed)"); + PhSetDialogItemText(hwndDlg, IDC_INTERNALNAME, SelectedPlugin->Name.Buffer); + PhSetDialogItemText(hwndDlg, IDC_AUTHOR, SelectedPlugin->Information.Author); + PhSetDialogItemText(hwndDlg, IDC_FILENAME, PH_AUTO_T(PH_STRING, PhGetBaseName(fileName))->Buffer); + PhSetDialogItemText(hwndDlg, IDC_DESCRIPTION, SelectedPlugin->Information.Description); + PhSetDialogItemText(hwndDlg, IDC_URL, SelectedPlugin->Information.Url); if (PhInitializeImageVersionInfo(&versionInfo, fileName->Buffer)) { - SetDlgItemText(hwndDlg, IDC_VERSION, PhGetStringOrDefault(versionInfo.FileVersion, L"Unknown")); + PhSetDialogItemText(hwndDlg, IDC_VERSION, PhGetStringOrDefault(versionInfo.FileVersion, L"Unknown")); PhDeleteImageVersionInfo(&versionInfo); } else { - SetDlgItemText(hwndDlg, IDC_VERSION, L"Unknown"); + PhSetDialogItemText(hwndDlg, IDC_VERSION, L"Unknown"); } ShowWindow(GetDlgItem(hwndDlg, IDC_OPENURL), SelectedPlugin->Information.Url ? SW_SHOW : SW_HIDE); @@ -980,7 +980,7 @@ INT_PTR CALLBACK PhpPluginPropertiesDlgProc( PhpRefreshPluginDetails(hwndDlg, selectedPlugin); - SendMessage(hwndDlg, WM_NEXTDLGCTL, (LPARAM)GetDlgItem(hwndDlg, IDOK), TRUE); + PhSetDialogFocus(hwndDlg, GetDlgItem(hwndDlg, IDOK)); } break; case WM_COMMAND: @@ -1135,7 +1135,7 @@ INT_PTR CALLBACK PhpPluginsDisabledDlgProc( PhpAddDisabledPlugins(context); ExtendedListView_SetColumnWidth(context->ListViewHandle, 0, ELVSCW_AUTOSIZE_REMAININGSPACE); - SendMessage(hwndDlg, WM_NEXTDLGCTL, (LPARAM)GetDlgItem(hwndDlg, IDOK), TRUE); + PhSetDialogFocus(hwndDlg, GetDlgItem(hwndDlg, IDOK)); } break; case WM_COMMAND: diff --git a/ProcessHacker/procprp.c b/ProcessHacker/procprp.c index b378fa600970..9e6d099932d2 100644 --- a/ProcessHacker/procprp.c +++ b/ProcessHacker/procprp.c @@ -308,7 +308,7 @@ BOOLEAN PhpInitializePropSheetLayoutStage1( // Hide the OK button. ShowWindow(GetDlgItem(hwnd, IDOK), SW_HIDE); // Set the Cancel button's text to "Close". - SetDlgItemText(hwnd, IDCANCEL, L"Close"); + PhSetDialogItemText(hwnd, IDCANCEL, L"Close"); Context->LayoutInitialized = TRUE; diff --git a/ProcessHacker/procrec.c b/ProcessHacker/procrec.c index 8237b18fabc9..26fc6d5b5227 100644 --- a/ProcessHacker/procrec.c +++ b/ProcessHacker/procrec.c @@ -133,10 +133,10 @@ INT_PTR CALLBACK PhpProcessRecordDlgProc( } PhCenterWindow(hwndDlg, GetParent(hwndDlg)); - SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hwndDlg, IDOK), TRUE); + PhSetDialogFocus(hwndDlg, GetDlgItem(hwndDlg, IDOK)); SetWindowText(hwndDlg, processNameString->Buffer); - SetDlgItemText(hwndDlg, IDC_PROCESSNAME, processNameString->Buffer); + PhSetDialogItemText(hwndDlg, IDC_PROCESSNAME, processNameString->Buffer); if (processItem = PhReferenceProcessItemForRecord(context->Record)) { @@ -149,14 +149,14 @@ INT_PTR CALLBACK PhpProcessRecordDlgProc( clientId.UniqueProcess = parentProcess->ProcessId; clientId.UniqueThread = NULL; - SetDlgItemText(hwndDlg, IDC_PARENT, + PhSetDialogItemText(hwndDlg, IDC_PARENT, PH_AUTO_T(PH_STRING, PhGetClientIdNameEx(&clientId, parentProcess->ProcessName))->Buffer); PhDereferenceObject(parentProcess); } else { - SetDlgItemText(hwndDlg, IDC_PARENT, PhaFormatString(L"Non-existent process (%u)", + PhSetDialogItemText(hwndDlg, IDC_PARENT, PhaFormatString(L"Non-existent process (%u)", HandleToUlong(context->Record->ParentProcessId))->Buffer); } @@ -164,7 +164,7 @@ INT_PTR CALLBACK PhpProcessRecordDlgProc( } else { - SetDlgItemText(hwndDlg, IDC_PARENT, PhaFormatString(L"Unknown process (%u)", + PhSetDialogItemText(hwndDlg, IDC_PARENT, PhaFormatString(L"Unknown process (%u)", HandleToUlong(context->Record->ParentProcessId))->Buffer); EnableWindow(GetDlgItem(hwndDlg, IDC_PROPERTIES), FALSE); @@ -186,10 +186,10 @@ INT_PTR CALLBACK PhpProcessRecordDlgProc( SendMessage(GetDlgItem(hwndDlg, IDC_FILEICON), STM_SETICON, (WPARAM)context->FileIcon, 0); - SetDlgItemText(hwndDlg, IDC_NAME, PhpGetStringOrNa(versionInfo.FileDescription)); - SetDlgItemText(hwndDlg, IDC_COMPANYNAME, PhpGetStringOrNa(versionInfo.CompanyName)); - SetDlgItemText(hwndDlg, IDC_VERSION, PhpGetStringOrNa(versionInfo.FileVersion)); - SetDlgItemText(hwndDlg, IDC_FILENAME, PhpGetStringOrNa(context->Record->FileName)); + PhSetDialogItemText(hwndDlg, IDC_NAME, PhpGetStringOrNa(versionInfo.FileDescription)); + PhSetDialogItemText(hwndDlg, IDC_COMPANYNAME, PhpGetStringOrNa(versionInfo.CompanyName)); + PhSetDialogItemText(hwndDlg, IDC_VERSION, PhpGetStringOrNa(versionInfo.FileVersion)); + PhSetDialogItemText(hwndDlg, IDC_FILENAME, PhpGetStringOrNa(context->Record->FileName)); if (versionInfoInitialized) PhDeleteImageVersionInfo(&versionInfo); @@ -197,19 +197,19 @@ INT_PTR CALLBACK PhpProcessRecordDlgProc( if (!context->Record->FileName) EnableWindow(GetDlgItem(hwndDlg, IDC_OPENFILENAME), FALSE); - SetDlgItemText(hwndDlg, IDC_CMDLINE, PhpGetStringOrNa(context->Record->CommandLine)); + PhSetDialogItemText(hwndDlg, IDC_CMDLINE, PhpGetStringOrNa(context->Record->CommandLine)); if (context->Record->CreateTime.QuadPart != 0) - SetDlgItemText(hwndDlg, IDC_STARTED, PhpaGetRelativeTimeString(&context->Record->CreateTime)->Buffer); + PhSetDialogItemText(hwndDlg, IDC_STARTED, PhpaGetRelativeTimeString(&context->Record->CreateTime)->Buffer); else - SetDlgItemText(hwndDlg, IDC_STARTED, L"N/A"); + PhSetDialogItemText(hwndDlg, IDC_STARTED, L"N/A"); if (context->Record->ExitTime.QuadPart != 0) - SetDlgItemText(hwndDlg, IDC_TERMINATED, PhpaGetRelativeTimeString(&context->Record->ExitTime)->Buffer); + PhSetDialogItemText(hwndDlg, IDC_TERMINATED, PhpaGetRelativeTimeString(&context->Record->ExitTime)->Buffer); else - SetDlgItemText(hwndDlg, IDC_TERMINATED, L"N/A"); + PhSetDialogItemText(hwndDlg, IDC_TERMINATED, L"N/A"); - SetDlgItemInt(hwndDlg, IDC_SESSIONID, context->Record->SessionId, FALSE); + PhSetDialogItemValue(hwndDlg, IDC_SESSIONID, context->Record->SessionId, FALSE); } break; case WM_DESTROY: diff --git a/ProcessHacker/prpgenv.c b/ProcessHacker/prpgenv.c index 4380e5c372d3..b9230dde9afe 100644 --- a/ProcessHacker/prpgenv.c +++ b/ProcessHacker/prpgenv.c @@ -511,10 +511,10 @@ INT_PTR CALLBACK PhpEditEnvDlgProc( context->MinimumSize.bottom = 140; MapDialogRect(hwndDlg, &context->MinimumSize); - SetDlgItemText(hwndDlg, IDC_NAME, context->Name); - SetDlgItemText(hwndDlg, IDC_VALUE, context->Value ? context->Value : L""); + PhSetDialogItemText(hwndDlg, IDC_NAME, context->Name); + PhSetDialogItemText(hwndDlg, IDC_VALUE, context->Value ? context->Value : L""); - SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hwndDlg, IDCANCEL), TRUE); + PhSetDialogFocus(hwndDlg, GetDlgItem(hwndDlg, IDCANCEL)); } break; case WM_DESTROY: @@ -600,7 +600,7 @@ INT_PTR CALLBACK PhpEditEnvDlgProc( { if (HIWORD(wParam) == EN_CHANGE) { - EnableWindow(GetDlgItem(hwndDlg, IDOK), GetWindowTextLength(GetDlgItem(hwndDlg, IDC_NAME)) > 0); + EnableWindow(GetDlgItem(hwndDlg, IDOK), PhGetWindowTextLength(GetDlgItem(hwndDlg, IDC_NAME)) > 0); } } break; diff --git a/ProcessHacker/prpggen.c b/ProcessHacker/prpggen.c index c1c197b2c79d..364e9e3e1360 100644 --- a/ProcessHacker/prpggen.c +++ b/ProcessHacker/prpggen.c @@ -109,7 +109,7 @@ VOID PhpUpdateProcessMitigationPolicies( HANDLE processHandle; PH_PROCESS_MITIGATION_POLICY_ALL_INFORMATION information; - SetDlgItemText(hwndDlg, IDC_MITIGATION, L"N/A"); + PhSetDialogItemText(hwndDlg, IDC_MITIGATION, L"N/A"); if (NT_SUCCESS(status = PhOpenProcess( &processHandle, @@ -143,11 +143,11 @@ VOID PhpUpdateProcessMitigationPolicies( if (sb.String->Length != 0) { PhRemoveEndStringBuilder(&sb, 2); - SetDlgItemText(hwndDlg, IDC_MITIGATION, sb.String->Buffer); + PhSetDialogItemText(hwndDlg, IDC_MITIGATION, sb.String->Buffer); } else { - SetDlgItemText(hwndDlg, IDC_MITIGATION, L"None"); + PhSetDialogItemText(hwndDlg, IDC_MITIGATION, L"None"); } PhDeleteStringBuilder(&sb); @@ -205,15 +205,15 @@ INT_PTR CALLBACK PhpProcessGeneralDlgProc( if (PH_IS_REAL_PROCESS_ID(processItem->ProcessId)) { - SetDlgItemText(hwndDlg, IDC_NAME, PhpGetStringOrNa(processItem->VersionInfo.FileDescription)); + PhSetDialogItemText(hwndDlg, IDC_NAME, PhpGetStringOrNa(processItem->VersionInfo.FileDescription)); } else { - SetDlgItemText(hwndDlg, IDC_NAME, processItem->ProcessName->Buffer); + PhSetDialogItemText(hwndDlg, IDC_NAME, processItem->ProcessName->Buffer); } - SetDlgItemText(hwndDlg, IDC_VERSION, PhpGetStringOrNa(processItem->VersionInfo.FileVersion)); - SetDlgItemText(hwndDlg, IDC_FILENAME, PhpGetStringOrNa(processItem->FileName)); + PhSetDialogItemText(hwndDlg, IDC_VERSION, PhpGetStringOrNa(processItem->VersionInfo.FileVersion)); + PhSetDialogItemText(hwndDlg, IDC_FILENAME, PhpGetStringOrNa(processItem->FileName)); if (!processItem->FileName) EnableWindow(GetDlgItem(hwndDlg, IDC_OPENFILENAME), FALSE); @@ -233,14 +233,14 @@ INT_PTR CALLBACK PhpProcessGeneralDlgProc( { if (processItem->VerifySignerName) { - SetDlgItemText(hwndDlg, IDC_COMPANYNAME_LINK, + PhSetDialogItemText(hwndDlg, IDC_COMPANYNAME_LINK, PhaFormatString(L"(Verified) %s", processItem->VerifySignerName->Buffer)->Buffer); ShowWindow(GetDlgItem(hwndDlg, IDC_COMPANYNAME), SW_HIDE); ShowWindow(GetDlgItem(hwndDlg, IDC_COMPANYNAME_LINK), SW_SHOW); } else { - SetDlgItemText(hwndDlg, IDC_COMPANYNAME, + PhSetDialogItemText(hwndDlg, IDC_COMPANYNAME, PhaConcatStrings2( L"(Verified) ", PhGetStringOrEmpty(processItem->VersionInfo.CompanyName) @@ -249,7 +249,7 @@ INT_PTR CALLBACK PhpProcessGeneralDlgProc( } else if (processItem->VerifyResult != VrUnknown) { - SetDlgItemText(hwndDlg, IDC_COMPANYNAME, + PhSetDialogItemText(hwndDlg, IDC_COMPANYNAME, PhaConcatStrings2( L"(UNVERIFIED) ", PhGetStringOrEmpty(processItem->VersionInfo.CompanyName) @@ -257,13 +257,13 @@ INT_PTR CALLBACK PhpProcessGeneralDlgProc( } else { - SetDlgItemText(hwndDlg, IDC_COMPANYNAME, + PhSetDialogItemText(hwndDlg, IDC_COMPANYNAME, PhpGetStringOrNa(processItem->VersionInfo.CompanyName)); } // Command Line - SetDlgItemText(hwndDlg, IDC_CMDLINE, PhpGetStringOrNa(processItem->CommandLine)); + PhSetDialogItemText(hwndDlg, IDC_CMDLINE, PhpGetStringOrNa(processItem->CommandLine)); if (!processItem->CommandLine) EnableWindow(GetDlgItem(hwndDlg, IDC_VIEWCOMMANDLINE), FALSE); @@ -298,7 +298,7 @@ INT_PTR CALLBACK PhpProcessGeneralDlgProc( processHandle = NULL; } - SetDlgItemText(hwndDlg, IDC_CURDIR, PhpGetStringOrNa(curDir)); + PhSetDialogItemText(hwndDlg, IDC_CURDIR, PhpGetStringOrNa(curDir)); // Started @@ -317,12 +317,12 @@ INT_PTR CALLBACK PhpProcessGeneralDlgProc( PhLargeIntegerToLocalSystemTime(&startTimeFields, &startTime); startTimeString = PhaFormatDateTime(&startTimeFields); - SetDlgItemText(hwndDlg, IDC_STARTED, + PhSetDialogItemText(hwndDlg, IDC_STARTED, PhaFormatString(L"%s ago (%s)", startTimeRelativeString->Buffer, startTimeString->Buffer)->Buffer); } else { - SetDlgItemText(hwndDlg, IDC_STARTED, L"N/A"); + PhSetDialogItemText(hwndDlg, IDC_STARTED, L"N/A"); } // Parent @@ -332,14 +332,14 @@ INT_PTR CALLBACK PhpProcessGeneralDlgProc( clientId.UniqueProcess = parentProcess->ProcessId; clientId.UniqueThread = NULL; - SetDlgItemText(hwndDlg, IDC_PARENTPROCESS, + PhSetDialogItemText(hwndDlg, IDC_PARENTPROCESS, PH_AUTO_T(PH_STRING, PhGetClientIdNameEx(&clientId, parentProcess->ProcessName))->Buffer); PhDereferenceObject(parentProcess); } else { - SetDlgItemText(hwndDlg, IDC_PARENTPROCESS, + PhSetDialogItemText(hwndDlg, IDC_PARENTPROCESS, PhaFormatString(L"Non-existent process (%u)", HandleToUlong(processItem->ParentProcessId))->Buffer); EnableWindow(GetDlgItem(hwndDlg, IDC_VIEWPARENTPROCESS), FALSE); } @@ -350,7 +350,7 @@ INT_PTR CALLBACK PhpProcessGeneralDlgProc( // PEB address - SetDlgItemText(hwndDlg, IDC_PEBADDRESS, L"N/A"); + PhSetDialogItemText(hwndDlg, IDC_PEBADDRESS, L"N/A"); if (NT_SUCCESS(PhOpenProcess( &processHandle, @@ -363,14 +363,14 @@ INT_PTR CALLBACK PhpProcessGeneralDlgProc( if (processItem->IsWow64) { PhGetProcessPeb32(processHandle, &peb32); - SetDlgItemText(hwndDlg, IDC_PEBADDRESS, + PhSetDialogItemText(hwndDlg, IDC_PEBADDRESS, PhaFormatString(L"0x%Ix (32-bit: 0x%x)", basicInfo.PebBaseAddress, PtrToUlong(peb32))->Buffer); } else { #endif - SetDlgItemText(hwndDlg, IDC_PEBADDRESS, + PhSetDialogItemText(hwndDlg, IDC_PEBADDRESS, PhaFormatString(L"0x%Ix", basicInfo.PebBaseAddress)->Buffer); #ifdef _WIN64 } @@ -381,19 +381,19 @@ INT_PTR CALLBACK PhpProcessGeneralDlgProc( // Protection - SetDlgItemText(hwndDlg, IDC_PROTECTION, PH_AUTO_T(PH_STRING, PhGetProcessItemProtectionText(processItem))->Buffer); + PhSetDialogItemText(hwndDlg, IDC_PROTECTION, PH_AUTO_T(PH_STRING, PhGetProcessItemProtectionText(processItem))->Buffer); #ifdef _WIN64 if (processItem->IsWow64Valid) { if (processItem->IsWow64) - SetDlgItemText(hwndDlg, IDC_PROCESSTYPETEXT, L"32-bit"); + PhSetDialogItemText(hwndDlg, IDC_PROCESSTYPETEXT, L"32-bit"); else - SetDlgItemText(hwndDlg, IDC_PROCESSTYPETEXT, L"64-bit"); + PhSetDialogItemText(hwndDlg, IDC_PROCESSTYPETEXT, L"64-bit"); } else { - SetDlgItemText(hwndDlg, IDC_PROCESSTYPETEXT, L"N/A"); + PhSetDialogItemText(hwndDlg, IDC_PROCESSTYPETEXT, L"N/A"); } ShowWindow(GetDlgItem(hwndDlg, IDC_PROCESSTYPELABEL), SW_SHOW); diff --git a/ProcessHacker/prpgthrd.c b/ProcessHacker/prpgthrd.c index 93bfd1381110..b7b8cdba460c 100644 --- a/ProcessHacker/prpgthrd.c +++ b/ProcessHacker/prpgthrd.c @@ -400,22 +400,22 @@ VOID PhpUpdateThreadDetails( { // These don't change... - SetDlgItemText(hwndDlg, IDC_STARTMODULE, PhGetStringOrEmpty(startModule)); + PhSetDialogItemText(hwndDlg, IDC_STARTMODULE, PhGetStringOrEmpty(startModule)); EnableWindow(GetDlgItem(hwndDlg, IDC_OPENSTARTMODULE), !!startModule); - SetDlgItemText(hwndDlg, IDC_STARTED, PhGetStringOrDefault(started, L"N/A")); + PhSetDialogItemText(hwndDlg, IDC_STARTED, PhGetStringOrDefault(started, L"N/A")); } - SetDlgItemText(hwndDlg, IDC_KERNELTIME, kernelTime); - SetDlgItemText(hwndDlg, IDC_USERTIME, userTime); - SetDlgItemText(hwndDlg, IDC_CONTEXTSWITCHES, PhGetStringOrDefault(contextSwitches, L"N/A")); - SetDlgItemText(hwndDlg, IDC_CYCLES, PhGetStringOrDefault(cycles, L"N/A")); - SetDlgItemText(hwndDlg, IDC_STATE, PhGetStringOrDefault(state, L"N/A")); - SetDlgItemText(hwndDlg, IDC_PRIORITY, priority); - SetDlgItemText(hwndDlg, IDC_BASEPRIORITY, basePriority); - SetDlgItemText(hwndDlg, IDC_IOPRIORITY, ioPriority); - SetDlgItemText(hwndDlg, IDC_PAGEPRIORITY, pagePriority); - SetDlgItemText(hwndDlg, IDC_IDEALPROCESSOR, idealProcessor); + PhSetDialogItemText(hwndDlg, IDC_KERNELTIME, kernelTime); + PhSetDialogItemText(hwndDlg, IDC_USERTIME, userTime); + PhSetDialogItemText(hwndDlg, IDC_CONTEXTSWITCHES, PhGetStringOrDefault(contextSwitches, L"N/A")); + PhSetDialogItemText(hwndDlg, IDC_CYCLES, PhGetStringOrDefault(cycles, L"N/A")); + PhSetDialogItemText(hwndDlg, IDC_STATE, PhGetStringOrDefault(state, L"N/A")); + PhSetDialogItemText(hwndDlg, IDC_PRIORITY, priority); + PhSetDialogItemText(hwndDlg, IDC_BASEPRIORITY, basePriority); + PhSetDialogItemText(hwndDlg, IDC_IOPRIORITY, ioPriority); + PhSetDialogItemText(hwndDlg, IDC_PAGEPRIORITY, pagePriority); + PhSetDialogItemText(hwndDlg, IDC_IDEALPROCESSOR, idealProcessor); } VOID PhShowThreadContextMenu( diff --git a/ProcessHacker/prpgwmi.c b/ProcessHacker/prpgwmi.c index 24ca81fd52d7..874f5326ca87 100644 --- a/ProcessHacker/prpgwmi.c +++ b/ProcessHacker/prpgwmi.c @@ -741,7 +741,7 @@ INT_PTR CALLBACK PhpProcessWmiProvidersDlgProc( PhSetClipboardString(hwndDlg, &string->sr); PhDereferenceObject(string); - SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)context->ListViewHandle, TRUE); + PhSetDialogFocus(hwndDlg, context->ListViewHandle); } break; } diff --git a/ProcessHacker/runas.c b/ProcessHacker/runas.c index 4ee7750a98b8..10c9431494d3 100644 --- a/ProcessHacker/runas.c +++ b/ProcessHacker/runas.c @@ -851,7 +851,7 @@ INT_PTR CALLBACK PhpRunAsDlgProc( EnableWindow(context->TypeComboBoxWindowHandle, FALSE); } - SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)context->ProgramComboBoxWindowHandle, TRUE); + PhSetDialogFocus(hwndDlg, context->ProgramComboBoxWindowHandle); Edit_SetSel(context->ProgramComboBoxWindowHandle, -1, -1); //if (!PhGetOwnTokenAttributes().Elevated) diff --git a/ProcessHacker/sessmsg.c b/ProcessHacker/sessmsg.c index 390ffca4d547..afbd3f6e2642 100644 --- a/ProcessHacker/sessmsg.c +++ b/ProcessHacker/sessmsg.c @@ -85,14 +85,14 @@ INT_PTR CALLBACK PhpSessionSendMessageDlgProc( if (PhCurrentUserName) { - SetDlgItemText( + PhSetDialogItemText( hwndDlg, IDC_TITLE, PhaFormatString(L"Message from %s", PhCurrentUserName->Buffer)->Buffer ); } - SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hwndDlg, IDC_TEXT), TRUE); + PhSetDialogFocus(hwndDlg, GetDlgItem(hwndDlg, IDC_TEXT)); } break; case WM_DESTROY: diff --git a/ProcessHacker/sessprp.c b/ProcessHacker/sessprp.c index ffdfb14f1a4c..b90e878587a2 100644 --- a/ProcessHacker/sessprp.c +++ b/ProcessHacker/sessprp.c @@ -107,11 +107,11 @@ INT_PTR CALLBACK PhpSessionPropertiesDlgProc( if (haveWinStationInfo) { - SetDlgItemText(hwndDlg, IDC_USERNAME, + PhSetDialogItemText(hwndDlg, IDC_USERNAME, PhaFormatString(L"%s\\%s", winStationInfo.Domain, winStationInfo.UserName)->Buffer); } - SetDlgItemInt(hwndDlg, IDC_SESSIONID, sessionId, FALSE); + PhSetDialogItemValue(hwndDlg, IDC_SESSIONID, sessionId, FALSE); if (haveWinStationInfo) { @@ -122,7 +122,7 @@ INT_PTR CALLBACK PhpSessionPropertiesDlgProc( &stateString )) { - SetDlgItemText(hwndDlg, IDC_STATE, stateString); + PhSetDialogItemText(hwndDlg, IDC_STATE, stateString); } } @@ -133,7 +133,7 @@ INT_PTR CALLBACK PhpSessionPropertiesDlgProc( PhLargeIntegerToLocalSystemTime(&systemTime, &winStationInfo.LogonTime); time = PhFormatDateTime(&systemTime); - SetDlgItemText(hwndDlg, IDC_LOGONTIME, time->Buffer); + PhSetDialogItemText(hwndDlg, IDC_LOGONTIME, time->Buffer); PhDereferenceObject(time); } @@ -144,7 +144,7 @@ INT_PTR CALLBACK PhpSessionPropertiesDlgProc( PhLargeIntegerToLocalSystemTime(&systemTime, &winStationInfo.ConnectTime); time = PhFormatDateTime(&systemTime); - SetDlgItemText(hwndDlg, IDC_CONNECTTIME, time->Buffer); + PhSetDialogItemText(hwndDlg, IDC_CONNECTTIME, time->Buffer); PhDereferenceObject(time); } @@ -155,7 +155,7 @@ INT_PTR CALLBACK PhpSessionPropertiesDlgProc( PhLargeIntegerToLocalSystemTime(&systemTime, &winStationInfo.DisconnectTime); time = PhFormatDateTime(&systemTime); - SetDlgItemText(hwndDlg, IDC_DISCONNECTTIME, time->Buffer); + PhSetDialogItemText(hwndDlg, IDC_DISCONNECTTIME, time->Buffer); PhDereferenceObject(time); } @@ -166,7 +166,7 @@ INT_PTR CALLBACK PhpSessionPropertiesDlgProc( PhLargeIntegerToLocalSystemTime(&systemTime, &winStationInfo.LastInputTime); time = PhFormatDateTime(&systemTime); - SetDlgItemText(hwndDlg, IDC_LASTINPUTTIME, time->Buffer); + PhSetDialogItemText(hwndDlg, IDC_LASTINPUTTIME, time->Buffer); PhDereferenceObject(time); } @@ -174,7 +174,7 @@ INT_PTR CALLBACK PhpSessionPropertiesDlgProc( { WCHAR addressString[65]; - SetDlgItemText(hwndDlg, IDC_CLIENTNAME, clientInfo.ClientName); + PhSetDialogItemText(hwndDlg, IDC_CLIENTNAME, clientInfo.ClientName); if (clientInfo.ClientAddressFamily == AF_INET6) { @@ -203,15 +203,15 @@ INT_PTR CALLBACK PhpSessionPropertiesDlgProc( wcscpy_s(addressString, 65, clientInfo.ClientAddress); } - SetDlgItemText(hwndDlg, IDC_CLIENTADDRESS, addressString); + PhSetDialogItemText(hwndDlg, IDC_CLIENTADDRESS, addressString); - SetDlgItemText(hwndDlg, IDC_CLIENTDISPLAY, + PhSetDialogItemText(hwndDlg, IDC_CLIENTDISPLAY, PhaFormatString(L"%ux%u@%u", clientInfo.HRes, clientInfo.VRes, clientInfo.ColorDepth)->Buffer ); } - SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hwndDlg, IDOK), TRUE); + PhSetDialogFocus(hwndDlg, GetDlgItem(hwndDlg, IDOK)); } break; case WM_COMMAND: diff --git a/ProcessHacker/srvcr.c b/ProcessHacker/srvcr.c index 2e19f821bc82..d52a209e80ee 100644 --- a/ProcessHacker/srvcr.c +++ b/ProcessHacker/srvcr.c @@ -77,7 +77,7 @@ INT_PTR CALLBACK PhpCreateServiceDlgProc( SendMessage(GetDlgItem(hwndDlg, IDOK), BCM_SETSHIELD, 0, TRUE); } - SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hwndDlg, IDC_NAME), TRUE); + PhSetDialogFocus(hwndDlg, GetDlgItem(hwndDlg, IDC_NAME)); } break; case WM_COMMAND: @@ -210,7 +210,7 @@ INT_PTR CALLBACK PhpCreateServiceDlgProc( if (PhShowFileDialog(hwndDlg, fileDialog)) { fileName = PhGetFileDialogFileName(fileDialog); - SetDlgItemText(hwndDlg, IDC_BINARYPATH, fileName->Buffer); + PhSetDialogItemText(hwndDlg, IDC_BINARYPATH, fileName->Buffer); PhDereferenceObject(fileName); } diff --git a/ProcessHacker/srvprp.c b/ProcessHacker/srvprp.c index 36f9d0e97e22..3f1606aaf83f 100644 --- a/ProcessHacker/srvprp.c +++ b/ProcessHacker/srvprp.c @@ -224,9 +224,8 @@ INT_PTR CALLBACK PhpServiceGeneralDlgProc( PhAddComboBoxStrings(GetDlgItem(hwndDlg, IDC_ERRORCONTROL), PhServiceErrorControlStrings, sizeof(PhServiceErrorControlStrings) / sizeof(WCHAR *)); - SetDlgItemText(hwndDlg, IDC_DESCRIPTION, serviceItem->DisplayName->Buffer); - PhSelectComboBoxString(GetDlgItem(hwndDlg, IDC_TYPE), - PhGetServiceTypeString(serviceItem->Type), FALSE); + PhSetDialogItemText(hwndDlg, IDC_DESCRIPTION, PhGetStringOrEmpty(serviceItem->DisplayName)); + PhSelectComboBoxString(GetDlgItem(hwndDlg, IDC_TYPE), PhGetServiceTypeString(serviceItem->Type), FALSE); startType = serviceItem->StartType; errorControl = serviceItem->ErrorControl; @@ -240,9 +239,9 @@ INT_PTR CALLBACK PhpServiceGeneralDlgProc( if (config = PhGetServiceConfig(serviceHandle)) { - SetDlgItemText(hwndDlg, IDC_GROUP, config->lpLoadOrderGroup); - SetDlgItemText(hwndDlg, IDC_BINARYPATH, config->lpBinaryPathName); - SetDlgItemText(hwndDlg, IDC_USERACCOUNT, config->lpServiceStartName); + PhSetDialogItemText(hwndDlg, IDC_GROUP, config->lpLoadOrderGroup); + PhSetDialogItemText(hwndDlg, IDC_BINARYPATH, config->lpBinaryPathName); + PhSetDialogItemText(hwndDlg, IDC_USERACCOUNT, config->lpServiceStartName); if (startType != config->dwStartType || errorControl != config->dwErrorControl) { @@ -256,7 +255,7 @@ INT_PTR CALLBACK PhpServiceGeneralDlgProc( if (description = PhGetServiceDescription(serviceHandle)) { - SetDlgItemText(hwndDlg, IDC_DESCRIPTION, description->Buffer); + PhSetDialogItemText(hwndDlg, IDC_DESCRIPTION, description->Buffer); PhDereferenceObject(description); } @@ -271,22 +270,22 @@ INT_PTR CALLBACK PhpServiceGeneralDlgProc( CloseServiceHandle(serviceHandle); } - PhSelectComboBoxString(GetDlgItem(hwndDlg, IDC_STARTTYPE), + PhSelectComboBoxString(GetDlgItem(hwndDlg, IDC_STARTTYPE), PhGetServiceStartTypeString(startType), FALSE); - PhSelectComboBoxString(GetDlgItem(hwndDlg, IDC_ERRORCONTROL), + PhSelectComboBoxString(GetDlgItem(hwndDlg, IDC_ERRORCONTROL), PhGetServiceErrorControlString(errorControl), FALSE); - SetDlgItemText(hwndDlg, IDC_PASSWORD, L"password"); + PhSetDialogItemText(hwndDlg, IDC_PASSWORD, L"password"); Button_SetCheck(GetDlgItem(hwndDlg, IDC_PASSWORDCHECK), BST_UNCHECKED); if (NT_SUCCESS(PhGetServiceDllParameter(serviceItem->Type, &serviceItem->Name->sr, &serviceDll))) { - SetDlgItemText(hwndDlg, IDC_SERVICEDLL, serviceDll->Buffer); + PhSetDialogItemText(hwndDlg, IDC_SERVICEDLL, serviceDll->Buffer); PhDereferenceObject(serviceDll); } else { - SetDlgItemText(hwndDlg, IDC_SERVICEDLL, L"N/A"); + PhSetDialogItemText(hwndDlg, IDC_SERVICEDLL, L"N/A"); } PhpRefreshControls(hwndDlg); @@ -360,7 +359,7 @@ INT_PTR CALLBACK PhpServiceGeneralDlgProc( if (PhShowFileDialog(hwndDlg, fileDialog)) { fileName = PhGetFileDialogFileName(fileDialog); - SetDlgItemText(hwndDlg, IDC_BINARYPATH, fileName->Buffer); + PhSetDialogItemText(hwndDlg, IDC_BINARYPATH, fileName->Buffer); PhDereferenceObject(fileName); } @@ -454,11 +453,11 @@ INT_PTR CALLBACK PhpServiceGeneralDlgProc( newServiceStartType = PhGetServiceStartTypeInteger(newServiceStartTypeString->Buffer); newServiceErrorControl = PhGetServiceErrorControlInteger(newServiceErrorControlString->Buffer); - if (GetWindowTextLength(GetDlgItem(hwndDlg, IDC_GROUP))) + if (PhGetWindowTextLength(GetDlgItem(hwndDlg, IDC_GROUP))) newServiceGroup = PH_AUTO(PhGetWindowText(GetDlgItem(hwndDlg, IDC_GROUP))); - if (GetWindowTextLength(GetDlgItem(hwndDlg, IDC_BINARYPATH))) + if (PhGetWindowTextLength(GetDlgItem(hwndDlg, IDC_BINARYPATH))) newServiceBinaryPath = PH_AUTO(PhGetWindowText(GetDlgItem(hwndDlg, IDC_BINARYPATH))); - if (GetWindowTextLength(GetDlgItem(hwndDlg, IDC_USERACCOUNT))) + if (PhGetWindowTextLength(GetDlgItem(hwndDlg, IDC_USERACCOUNT))) newServiceUserAccount = PH_AUTO(PhGetWindowText(GetDlgItem(hwndDlg, IDC_USERACCOUNT))); if (Button_GetCheck(GetDlgItem(hwndDlg, IDC_PASSWORDCHECK)) == BST_CHECKED) diff --git a/ProcessHacker/syssccpu.c b/ProcessHacker/syssccpu.c index e26d1aa480e5..6b7e6567670b 100644 --- a/ProcessHacker/syssccpu.c +++ b/ProcessHacker/syssccpu.c @@ -284,7 +284,7 @@ INT_PTR CALLBACK PhSipCpuDialogProc( SendMessage(GetDlgItem(hwndDlg, IDC_CPUNAME), WM_SETFONT, (WPARAM)CpuSection->Parameters->MediumFont, FALSE); PhSipGetCpuBrandString(brandString); - SetDlgItemText(hwndDlg, IDC_CPUNAME, brandString); + PhSetDialogItemText(hwndDlg, IDC_CPUNAME, brandString); CpuPanel = CreateDialog(PhInstanceHandle, MAKEINTRESOURCE(IDD_SYSINFO_CPUPANEL), hwndDlg, PhSipCpuPanelDialogProc); ShowWindow(CpuPanel, SW_SHOW); @@ -684,7 +684,7 @@ VOID PhSipUpdateCpuPanel( SYSTEM_TIMEOFDAY_INFORMATION timeOfDayInfo; WCHAR uptimeString[PH_TIMESPAN_STR_LEN_1] = L"Unknown"; - SetDlgItemText(hwnd, IDC_UTILIZATION, PhaFormatString(L"%.2f%%", (PhCpuUserUsage + PhCpuKernelUsage) * 100)->Buffer); + PhSetDialogItemText(hwnd, IDC_UTILIZATION, PhaFormatString(L"%.2f%%", (PhCpuUserUsage + PhCpuKernelUsage) * 100)->Buffer); cpuGhz = 0; distributionSucceeded = FALSE; @@ -701,11 +701,11 @@ VOID PhSipUpdateCpuPanel( if (!distributionSucceeded) cpuGhz = (DOUBLE)PowerInformation[0].CurrentMhz / 1000; - SetDlgItemText(hwnd, IDC_SPEED, PhaFormatString(L"%.2f / %.2f GHz", cpuGhz, (DOUBLE)PowerInformation[0].MaxMhz / 1000)->Buffer); + PhSetDialogItemText(hwnd, IDC_SPEED, PhaFormatString(L"%.2f / %.2f GHz", cpuGhz, (DOUBLE)PowerInformation[0].MaxMhz / 1000)->Buffer); - SetDlgItemText(hwnd, IDC_ZPROCESSES_V, PhaFormatUInt64(PhTotalProcesses, TRUE)->Buffer); - SetDlgItemText(hwnd, IDC_ZTHREADS_V, PhaFormatUInt64(PhTotalThreads, TRUE)->Buffer); - SetDlgItemText(hwnd, IDC_ZHANDLES_V, PhaFormatUInt64(PhTotalHandles, TRUE)->Buffer); + PhSetDialogItemText(hwnd, IDC_ZPROCESSES_V, PhaFormatUInt64(PhTotalProcesses, TRUE)->Buffer); + PhSetDialogItemText(hwnd, IDC_ZTHREADS_V, PhaFormatUInt64(PhTotalThreads, TRUE)->Buffer); + PhSetDialogItemText(hwnd, IDC_ZHANDLES_V, PhaFormatUInt64(PhTotalHandles, TRUE)->Buffer); if (NT_SUCCESS(NtQuerySystemInformation( SystemTimeOfDayInformation, @@ -717,27 +717,27 @@ VOID PhSipUpdateCpuPanel( PhPrintTimeSpan(uptimeString, timeOfDayInfo.CurrentTime.QuadPart - timeOfDayInfo.BootTime.QuadPart, PH_TIMESPAN_DHMS); } - SetDlgItemText(hwnd, IDC_ZUPTIME_V, uptimeString); + PhSetDialogItemText(hwnd, IDC_ZUPTIME_V, uptimeString); if (CpuTicked > 1) - SetDlgItemText(hwnd, IDC_ZCONTEXTSWITCHESDELTA_V, PhaFormatUInt64(ContextSwitchesDelta.Delta, TRUE)->Buffer); + PhSetDialogItemText(hwnd, IDC_ZCONTEXTSWITCHESDELTA_V, PhaFormatUInt64(ContextSwitchesDelta.Delta, TRUE)->Buffer); else - SetDlgItemText(hwnd, IDC_ZCONTEXTSWITCHESDELTA_V, L"-"); + PhSetDialogItemText(hwnd, IDC_ZCONTEXTSWITCHESDELTA_V, L"-"); if (CpuTicked > 1) - SetDlgItemText(hwnd, IDC_ZINTERRUPTSDELTA_V, PhaFormatUInt64(InterruptsDelta.Delta, TRUE)->Buffer); + PhSetDialogItemText(hwnd, IDC_ZINTERRUPTSDELTA_V, PhaFormatUInt64(InterruptsDelta.Delta, TRUE)->Buffer); else - SetDlgItemText(hwnd, IDC_ZINTERRUPTSDELTA_V, L"-"); + PhSetDialogItemText(hwnd, IDC_ZINTERRUPTSDELTA_V, L"-"); if (CpuTicked > 1) - SetDlgItemText(hwnd, IDC_ZDPCSDELTA_V, PhaFormatUInt64(DpcsDelta.Delta, TRUE)->Buffer); + PhSetDialogItemText(hwnd, IDC_ZDPCSDELTA_V, PhaFormatUInt64(DpcsDelta.Delta, TRUE)->Buffer); else - SetDlgItemText(hwnd, IDC_ZDPCSDELTA_V, L"-"); + PhSetDialogItemText(hwnd, IDC_ZDPCSDELTA_V, L"-"); if (CpuTicked > 1) - SetDlgItemText(hwnd, IDC_ZSYSTEMCALLSDELTA_V, PhaFormatUInt64(SystemCallsDelta.Delta, TRUE)->Buffer); + PhSetDialogItemText(hwnd, IDC_ZSYSTEMCALLSDELTA_V, PhaFormatUInt64(SystemCallsDelta.Delta, TRUE)->Buffer); else - SetDlgItemText(hwnd, IDC_ZSYSTEMCALLSDELTA_V, L"-"); + PhSetDialogItemText(hwnd, IDC_ZSYSTEMCALLSDELTA_V, L"-"); } PPH_PROCESS_RECORD PhSipReferenceMaxCpuRecord( diff --git a/ProcessHacker/sysscio.c b/ProcessHacker/sysscio.c index 87626b41a007..a49b0a6e85a4 100644 --- a/ProcessHacker/sysscio.c +++ b/ProcessHacker/sysscio.c @@ -434,38 +434,38 @@ VOID PhSipUpdateIoPanel( if (IoTicked > 1) { - SetDlgItemText(IoPanel, IDC_ZREADSDELTA_V, PhaFormatUInt64(IoReadDelta.Delta, TRUE)->Buffer); - SetDlgItemText(IoPanel, IDC_ZWRITESDELTA_V, PhaFormatUInt64(IoWriteDelta.Delta, TRUE)->Buffer); - SetDlgItemText(IoPanel, IDC_ZOTHERDELTA_V, PhaFormatUInt64(IoOtherDelta.Delta, TRUE)->Buffer); + PhSetDialogItemText(IoPanel, IDC_ZREADSDELTA_V, PhaFormatUInt64(IoReadDelta.Delta, TRUE)->Buffer); + PhSetDialogItemText(IoPanel, IDC_ZWRITESDELTA_V, PhaFormatUInt64(IoWriteDelta.Delta, TRUE)->Buffer); + PhSetDialogItemText(IoPanel, IDC_ZOTHERDELTA_V, PhaFormatUInt64(IoOtherDelta.Delta, TRUE)->Buffer); } else { - SetDlgItemText(IoPanel, IDC_ZREADSDELTA_V, L"-"); - SetDlgItemText(IoPanel, IDC_ZWRITESDELTA_V, L"-"); - SetDlgItemText(IoPanel, IDC_ZOTHERDELTA_V, L"-"); + PhSetDialogItemText(IoPanel, IDC_ZREADSDELTA_V, L"-"); + PhSetDialogItemText(IoPanel, IDC_ZWRITESDELTA_V, L"-"); + PhSetDialogItemText(IoPanel, IDC_ZOTHERDELTA_V, L"-"); } if (PhIoReadHistory.Count != 0) { - SetDlgItemText(IoPanel, IDC_ZREADBYTESDELTA_V, PhaFormatSize(PhIoReadDelta.Delta, -1)->Buffer); - SetDlgItemText(IoPanel, IDC_ZWRITEBYTESDELTA_V, PhaFormatSize(PhIoWriteDelta.Delta, -1)->Buffer); - SetDlgItemText(IoPanel, IDC_ZOTHERBYTESDELTA_V, PhaFormatSize(PhIoOtherDelta.Delta, -1)->Buffer); + PhSetDialogItemText(IoPanel, IDC_ZREADBYTESDELTA_V, PhaFormatSize(PhIoReadDelta.Delta, -1)->Buffer); + PhSetDialogItemText(IoPanel, IDC_ZWRITEBYTESDELTA_V, PhaFormatSize(PhIoWriteDelta.Delta, -1)->Buffer); + PhSetDialogItemText(IoPanel, IDC_ZOTHERBYTESDELTA_V, PhaFormatSize(PhIoOtherDelta.Delta, -1)->Buffer); } else { - SetDlgItemText(IoPanel, IDC_ZREADBYTESDELTA_V, L"-"); - SetDlgItemText(IoPanel, IDC_ZWRITEBYTESDELTA_V, L"-"); - SetDlgItemText(IoPanel, IDC_ZOTHERBYTESDELTA_V, L"-"); + PhSetDialogItemText(IoPanel, IDC_ZREADBYTESDELTA_V, L"-"); + PhSetDialogItemText(IoPanel, IDC_ZWRITEBYTESDELTA_V, L"-"); + PhSetDialogItemText(IoPanel, IDC_ZOTHERBYTESDELTA_V, L"-"); } // I/O Totals - SetDlgItemText(IoPanel, IDC_ZREADS_V, PhaFormatUInt64(PhPerfInformation.IoReadOperationCount, TRUE)->Buffer); - SetDlgItemText(IoPanel, IDC_ZREADBYTES_V, PhaFormatSize(PhPerfInformation.IoReadTransferCount.QuadPart, -1)->Buffer); - SetDlgItemText(IoPanel, IDC_ZWRITES_V, PhaFormatUInt64(PhPerfInformation.IoWriteOperationCount, TRUE)->Buffer); - SetDlgItemText(IoPanel, IDC_ZWRITEBYTES_V, PhaFormatSize(PhPerfInformation.IoWriteTransferCount.QuadPart, -1)->Buffer); - SetDlgItemText(IoPanel, IDC_ZOTHER_V, PhaFormatUInt64(PhPerfInformation.IoOtherOperationCount, TRUE)->Buffer); - SetDlgItemText(IoPanel, IDC_ZOTHERBYTES_V, PhaFormatSize(PhPerfInformation.IoOtherTransferCount.QuadPart, -1)->Buffer); + PhSetDialogItemText(IoPanel, IDC_ZREADS_V, PhaFormatUInt64(PhPerfInformation.IoReadOperationCount, TRUE)->Buffer); + PhSetDialogItemText(IoPanel, IDC_ZREADBYTES_V, PhaFormatSize(PhPerfInformation.IoReadTransferCount.QuadPart, -1)->Buffer); + PhSetDialogItemText(IoPanel, IDC_ZWRITES_V, PhaFormatUInt64(PhPerfInformation.IoWriteOperationCount, TRUE)->Buffer); + PhSetDialogItemText(IoPanel, IDC_ZWRITEBYTES_V, PhaFormatSize(PhPerfInformation.IoWriteTransferCount.QuadPart, -1)->Buffer); + PhSetDialogItemText(IoPanel, IDC_ZOTHER_V, PhaFormatUInt64(PhPerfInformation.IoOtherOperationCount, TRUE)->Buffer); + PhSetDialogItemText(IoPanel, IDC_ZOTHERBYTES_V, PhaFormatSize(PhPerfInformation.IoOtherTransferCount.QuadPart, -1)->Buffer); } PPH_PROCESS_RECORD PhSipReferenceMaxIoRecord( diff --git a/ProcessHacker/sysscmem.c b/ProcessHacker/sysscmem.c index 82168237dd34..462909ec4968 100644 --- a/ProcessHacker/sysscmem.c +++ b/ProcessHacker/sysscmem.c @@ -309,12 +309,12 @@ INT_PTR CALLBACK PhSipMemoryDialogProc( if (getPhysicallyInstalledSystemMemory && getPhysicallyInstalledSystemMemory(&InstalledMemory)) { - SetDlgItemText(hwndDlg, IDC_TOTALPHYSICAL, + PhSetDialogItemText(hwndDlg, IDC_TOTALPHYSICAL, PhaConcatStrings2(PhaFormatSize(InstalledMemory * 1024, -1)->Buffer, L" installed")->Buffer); } else { - SetDlgItemText(hwndDlg, IDC_TOTALPHYSICAL, + PhSetDialogItemText(hwndDlg, IDC_TOTALPHYSICAL, PhaConcatStrings2(PhaFormatSize(UInt32x32To64(PhSystemBasicInformation.NumberOfPhysicalPages, PAGE_SIZE), -1)->Buffer, L" total")->Buffer); } @@ -656,68 +656,68 @@ VOID PhSipUpdateMemoryPanel( // Commit charge - SetDlgItemText(MemoryPanel, IDC_ZCOMMITCURRENT_V, + PhSetDialogItemText(MemoryPanel, IDC_ZCOMMITCURRENT_V, PhaFormatSize(UInt32x32To64(PhPerfInformation.CommittedPages, PAGE_SIZE), -1)->Buffer); - SetDlgItemText(MemoryPanel, IDC_ZCOMMITPEAK_V, + PhSetDialogItemText(MemoryPanel, IDC_ZCOMMITPEAK_V, PhaFormatSize(UInt32x32To64(PhPerfInformation.PeakCommitment, PAGE_SIZE), -1)->Buffer); - SetDlgItemText(MemoryPanel, IDC_ZCOMMITLIMIT_V, + PhSetDialogItemText(MemoryPanel, IDC_ZCOMMITLIMIT_V, PhaFormatSize(UInt32x32To64(PhPerfInformation.CommitLimit, PAGE_SIZE), -1)->Buffer); // Physical memory - SetDlgItemText(MemoryPanel, IDC_ZPHYSICALCURRENT_V, + PhSetDialogItemText(MemoryPanel, IDC_ZPHYSICALCURRENT_V, PhaFormatSize(UInt32x32To64(PhSystemBasicInformation.NumberOfPhysicalPages - PhPerfInformation.AvailablePages, PAGE_SIZE), -1)->Buffer); - SetDlgItemText(MemoryPanel, IDC_ZPHYSICALTOTAL_V, + PhSetDialogItemText(MemoryPanel, IDC_ZPHYSICALTOTAL_V, PhaFormatSize(UInt32x32To64(PhSystemBasicInformation.NumberOfPhysicalPages, PAGE_SIZE), -1)->Buffer); if (InstalledMemory != 0) { - SetDlgItemText(MemoryPanel, IDC_ZPHYSICALRESERVED_V, + PhSetDialogItemText(MemoryPanel, IDC_ZPHYSICALRESERVED_V, PhaFormatSize(InstalledMemory * 1024 - UInt32x32To64(PhSystemBasicInformation.NumberOfPhysicalPages, PAGE_SIZE), -1)->Buffer); } else { - SetDlgItemText(MemoryPanel, IDC_ZPHYSICALRESERVED_V, L"-"); + PhSetDialogItemText(MemoryPanel, IDC_ZPHYSICALRESERVED_V, L"-"); } - SetDlgItemText(MemoryPanel, IDC_ZPHYSICALCACHEWS_V, + PhSetDialogItemText(MemoryPanel, IDC_ZPHYSICALCACHEWS_V, PhaFormatSize(UInt32x32To64(PhPerfInformation.ResidentSystemCachePage, PAGE_SIZE), -1)->Buffer); - SetDlgItemText(MemoryPanel, IDC_ZPHYSICALKERNELWS_V, + PhSetDialogItemText(MemoryPanel, IDC_ZPHYSICALKERNELWS_V, PhaFormatSize(UInt32x32To64(PhPerfInformation.ResidentSystemCodePage, PAGE_SIZE), -1)->Buffer); - SetDlgItemText(MemoryPanel, IDC_ZPHYSICALDRIVERWS_V, + PhSetDialogItemText(MemoryPanel, IDC_ZPHYSICALDRIVERWS_V, PhaFormatSize(UInt32x32To64(PhPerfInformation.ResidentSystemDriverPage, PAGE_SIZE), -1)->Buffer); // Paged pool - SetDlgItemText(MemoryPanel, IDC_ZPAGEDWORKINGSET_V, + PhSetDialogItemText(MemoryPanel, IDC_ZPAGEDWORKINGSET_V, PhaFormatSize(UInt32x32To64(PhPerfInformation.ResidentPagedPoolPage, PAGE_SIZE), -1)->Buffer); - SetDlgItemText(MemoryPanel, IDC_ZPAGEDVIRTUALSIZE_V, + PhSetDialogItemText(MemoryPanel, IDC_ZPAGEDVIRTUALSIZE_V, PhaFormatSize(UInt32x32To64(PhPerfInformation.PagedPoolPages, PAGE_SIZE), -1)->Buffer); if (MemoryTicked > 1) - SetDlgItemText(MemoryPanel, IDC_ZPAGEDALLOCSDELTA_V, PhaFormatUInt64(PagedAllocsDelta.Delta, TRUE)->Buffer); + PhSetDialogItemText(MemoryPanel, IDC_ZPAGEDALLOCSDELTA_V, PhaFormatUInt64(PagedAllocsDelta.Delta, TRUE)->Buffer); else - SetDlgItemText(MemoryPanel, IDC_ZPAGEDALLOCSDELTA_V, L"-"); + PhSetDialogItemText(MemoryPanel, IDC_ZPAGEDALLOCSDELTA_V, L"-"); if (MemoryTicked > 1) - SetDlgItemText(MemoryPanel, IDC_ZPAGEDFREESDELTA_V, PhaFormatUInt64(PagedFreesDelta.Delta, TRUE)->Buffer); + PhSetDialogItemText(MemoryPanel, IDC_ZPAGEDFREESDELTA_V, PhaFormatUInt64(PagedFreesDelta.Delta, TRUE)->Buffer); else - SetDlgItemText(MemoryPanel, IDC_ZPAGEDFREESDELTA_V, L"-"); + PhSetDialogItemText(MemoryPanel, IDC_ZPAGEDFREESDELTA_V, L"-"); // Non-paged pool - SetDlgItemText(MemoryPanel, IDC_ZNONPAGEDUSAGE_V, + PhSetDialogItemText(MemoryPanel, IDC_ZNONPAGEDUSAGE_V, PhaFormatSize(UInt32x32To64(PhPerfInformation.NonPagedPoolPages, PAGE_SIZE), -1)->Buffer); if (MemoryTicked > 1) - SetDlgItemText(MemoryPanel, IDC_ZNONPAGEDALLOCSDELTA_V, PhaFormatUInt64(PagedAllocsDelta.Delta, TRUE)->Buffer); + PhSetDialogItemText(MemoryPanel, IDC_ZNONPAGEDALLOCSDELTA_V, PhaFormatUInt64(PagedAllocsDelta.Delta, TRUE)->Buffer); else - SetDlgItemText(MemoryPanel, IDC_ZNONPAGEDALLOCSDELTA_V, L"-"); + PhSetDialogItemText(MemoryPanel, IDC_ZNONPAGEDALLOCSDELTA_V, L"-"); if (MemoryTicked > 1) - SetDlgItemText(MemoryPanel, IDC_ZNONPAGEDFREESDELTA_V, PhaFormatUInt64(NonPagedFreesDelta.Delta, TRUE)->Buffer); + PhSetDialogItemText(MemoryPanel, IDC_ZNONPAGEDFREESDELTA_V, PhaFormatUInt64(NonPagedFreesDelta.Delta, TRUE)->Buffer); else - SetDlgItemText(MemoryPanel, IDC_ZNONPAGEDFREESDELTA_V, L"-"); + PhSetDialogItemText(MemoryPanel, IDC_ZNONPAGEDFREESDELTA_V, L"-"); // Pools (KPH) @@ -750,30 +750,30 @@ VOID PhSipUpdateMemoryPanel( } } - SetDlgItemText(MemoryPanel, IDC_ZPAGEDLIMIT_V, pagedLimit); - SetDlgItemText(MemoryPanel, IDC_ZNONPAGEDLIMIT_V, nonPagedLimit); + PhSetDialogItemText(MemoryPanel, IDC_ZPAGEDLIMIT_V, pagedLimit); + PhSetDialogItemText(MemoryPanel, IDC_ZNONPAGEDLIMIT_V, nonPagedLimit); // Paging if (MemoryTicked > 1) - SetDlgItemText(MemoryPanel, IDC_ZPAGINGPAGEFAULTSDELTA_V, PhaFormatUInt64(PageFaultsDelta.Delta, TRUE)->Buffer); + PhSetDialogItemText(MemoryPanel, IDC_ZPAGINGPAGEFAULTSDELTA_V, PhaFormatUInt64(PageFaultsDelta.Delta, TRUE)->Buffer); else - SetDlgItemText(MemoryPanel, IDC_ZPAGINGPAGEFAULTSDELTA_V, L"-"); + PhSetDialogItemText(MemoryPanel, IDC_ZPAGINGPAGEFAULTSDELTA_V, L"-"); if (MemoryTicked > 1) - SetDlgItemText(MemoryPanel, IDC_ZPAGINGPAGEREADSDELTA_V, PhaFormatUInt64(PageReadsDelta.Delta, TRUE)->Buffer); + PhSetDialogItemText(MemoryPanel, IDC_ZPAGINGPAGEREADSDELTA_V, PhaFormatUInt64(PageReadsDelta.Delta, TRUE)->Buffer); else - SetDlgItemText(MemoryPanel, IDC_ZPAGINGPAGEREADSDELTA_V, L"-"); + PhSetDialogItemText(MemoryPanel, IDC_ZPAGINGPAGEREADSDELTA_V, L"-"); if (MemoryTicked > 1) - SetDlgItemText(MemoryPanel, IDC_ZPAGINGPAGEFILEWRITESDELTA_V, PhaFormatUInt64(PagefileWritesDelta.Delta, TRUE)->Buffer); + PhSetDialogItemText(MemoryPanel, IDC_ZPAGINGPAGEFILEWRITESDELTA_V, PhaFormatUInt64(PagefileWritesDelta.Delta, TRUE)->Buffer); else - SetDlgItemText(MemoryPanel, IDC_ZPAGINGPAGEFILEWRITESDELTA_V, L"-"); + PhSetDialogItemText(MemoryPanel, IDC_ZPAGINGPAGEFILEWRITESDELTA_V, L"-"); if (MemoryTicked > 1) - SetDlgItemText(MemoryPanel, IDC_ZPAGINGMAPPEDWRITESDELTA_V, PhaFormatUInt64(MappedWritesDelta.Delta, TRUE)->Buffer); + PhSetDialogItemText(MemoryPanel, IDC_ZPAGINGMAPPEDWRITESDELTA_V, PhaFormatUInt64(MappedWritesDelta.Delta, TRUE)->Buffer); else - SetDlgItemText(MemoryPanel, IDC_ZPAGINGMAPPEDWRITESDELTA_V, L"-"); + PhSetDialogItemText(MemoryPanel, IDC_ZPAGINGMAPPEDWRITESDELTA_V, L"-"); // Memory lists @@ -797,41 +797,41 @@ VOID PhSipUpdateMemoryPanel( repurposedPageCount += memoryListInfo.RepurposedPagesByPriority[i]; } - SetDlgItemText(MemoryPanel, IDC_ZLISTZEROED_V, PhaFormatSize((ULONG64)memoryListInfo.ZeroPageCount * PAGE_SIZE, -1)->Buffer); - SetDlgItemText(MemoryPanel, IDC_ZLISTFREE_V, PhaFormatSize((ULONG64)memoryListInfo.FreePageCount * PAGE_SIZE, -1)->Buffer); - SetDlgItemText(MemoryPanel, IDC_ZLISTMODIFIED_V, PhaFormatSize((ULONG64)memoryListInfo.ModifiedPageCount * PAGE_SIZE, -1)->Buffer); - SetDlgItemText(MemoryPanel, IDC_ZLISTMODIFIEDNOWRITE_V, PhaFormatSize((ULONG64)memoryListInfo.ModifiedNoWritePageCount * PAGE_SIZE, -1)->Buffer); - SetDlgItemText(MemoryPanel, IDC_ZLISTSTANDBY_V, PhaFormatSize((ULONG64)standbyPageCount * PAGE_SIZE, -1)->Buffer); - SetDlgItemText(MemoryPanel, IDC_ZLISTSTANDBY0_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[0] * PAGE_SIZE, -1)->Buffer); - SetDlgItemText(MemoryPanel, IDC_ZLISTSTANDBY1_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[1] * PAGE_SIZE, -1)->Buffer); - SetDlgItemText(MemoryPanel, IDC_ZLISTSTANDBY2_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[2] * PAGE_SIZE, -1)->Buffer); - SetDlgItemText(MemoryPanel, IDC_ZLISTSTANDBY3_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[3] * PAGE_SIZE, -1)->Buffer); - SetDlgItemText(MemoryPanel, IDC_ZLISTSTANDBY4_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[4] * PAGE_SIZE, -1)->Buffer); - SetDlgItemText(MemoryPanel, IDC_ZLISTSTANDBY5_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[5] * PAGE_SIZE, -1)->Buffer); - SetDlgItemText(MemoryPanel, IDC_ZLISTSTANDBY6_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[6] * PAGE_SIZE, -1)->Buffer); - SetDlgItemText(MemoryPanel, IDC_ZLISTSTANDBY7_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[7] * PAGE_SIZE, -1)->Buffer); + PhSetDialogItemText(MemoryPanel, IDC_ZLISTZEROED_V, PhaFormatSize((ULONG64)memoryListInfo.ZeroPageCount * PAGE_SIZE, -1)->Buffer); + PhSetDialogItemText(MemoryPanel, IDC_ZLISTFREE_V, PhaFormatSize((ULONG64)memoryListInfo.FreePageCount * PAGE_SIZE, -1)->Buffer); + PhSetDialogItemText(MemoryPanel, IDC_ZLISTMODIFIED_V, PhaFormatSize((ULONG64)memoryListInfo.ModifiedPageCount * PAGE_SIZE, -1)->Buffer); + PhSetDialogItemText(MemoryPanel, IDC_ZLISTMODIFIEDNOWRITE_V, PhaFormatSize((ULONG64)memoryListInfo.ModifiedNoWritePageCount * PAGE_SIZE, -1)->Buffer); + PhSetDialogItemText(MemoryPanel, IDC_ZLISTSTANDBY_V, PhaFormatSize((ULONG64)standbyPageCount * PAGE_SIZE, -1)->Buffer); + PhSetDialogItemText(MemoryPanel, IDC_ZLISTSTANDBY0_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[0] * PAGE_SIZE, -1)->Buffer); + PhSetDialogItemText(MemoryPanel, IDC_ZLISTSTANDBY1_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[1] * PAGE_SIZE, -1)->Buffer); + PhSetDialogItemText(MemoryPanel, IDC_ZLISTSTANDBY2_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[2] * PAGE_SIZE, -1)->Buffer); + PhSetDialogItemText(MemoryPanel, IDC_ZLISTSTANDBY3_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[3] * PAGE_SIZE, -1)->Buffer); + PhSetDialogItemText(MemoryPanel, IDC_ZLISTSTANDBY4_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[4] * PAGE_SIZE, -1)->Buffer); + PhSetDialogItemText(MemoryPanel, IDC_ZLISTSTANDBY5_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[5] * PAGE_SIZE, -1)->Buffer); + PhSetDialogItemText(MemoryPanel, IDC_ZLISTSTANDBY6_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[6] * PAGE_SIZE, -1)->Buffer); + PhSetDialogItemText(MemoryPanel, IDC_ZLISTSTANDBY7_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[7] * PAGE_SIZE, -1)->Buffer); if (WindowsVersion >= WINDOWS_8) - SetDlgItemText(MemoryPanel, IDC_ZLISTMODIFIEDPAGEFILE_V, PhaFormatSize((ULONG64)memoryListInfo.ModifiedPageCountPageFile * PAGE_SIZE, -1)->Buffer); + PhSetDialogItemText(MemoryPanel, IDC_ZLISTMODIFIEDPAGEFILE_V, PhaFormatSize((ULONG64)memoryListInfo.ModifiedPageCountPageFile * PAGE_SIZE, -1)->Buffer); else - SetDlgItemText(MemoryPanel, IDC_ZLISTMODIFIEDPAGEFILE_V, L"N/A"); + PhSetDialogItemText(MemoryPanel, IDC_ZLISTMODIFIEDPAGEFILE_V, L"N/A"); } else { - SetDlgItemText(MemoryPanel, IDC_ZLISTZEROED_V, L"N/A"); - SetDlgItemText(MemoryPanel, IDC_ZLISTFREE_V, L"N/A"); - SetDlgItemText(MemoryPanel, IDC_ZLISTMODIFIED_V, L"N/A"); - SetDlgItemText(MemoryPanel, IDC_ZLISTMODIFIEDNOWRITE_V, L"N/A"); - SetDlgItemText(MemoryPanel, IDC_ZLISTMODIFIEDPAGEFILE_V, L"N/A"); - SetDlgItemText(MemoryPanel, IDC_ZLISTSTANDBY_V, L"N/A"); - SetDlgItemText(MemoryPanel, IDC_ZLISTSTANDBY0_V, L"N/A"); - SetDlgItemText(MemoryPanel, IDC_ZLISTSTANDBY1_V, L"N/A"); - SetDlgItemText(MemoryPanel, IDC_ZLISTSTANDBY2_V, L"N/A"); - SetDlgItemText(MemoryPanel, IDC_ZLISTSTANDBY3_V, L"N/A"); - SetDlgItemText(MemoryPanel, IDC_ZLISTSTANDBY4_V, L"N/A"); - SetDlgItemText(MemoryPanel, IDC_ZLISTSTANDBY5_V, L"N/A"); - SetDlgItemText(MemoryPanel, IDC_ZLISTSTANDBY6_V, L"N/A"); - SetDlgItemText(MemoryPanel, IDC_ZLISTSTANDBY7_V, L"N/A"); + PhSetDialogItemText(MemoryPanel, IDC_ZLISTZEROED_V, L"N/A"); + PhSetDialogItemText(MemoryPanel, IDC_ZLISTFREE_V, L"N/A"); + PhSetDialogItemText(MemoryPanel, IDC_ZLISTMODIFIED_V, L"N/A"); + PhSetDialogItemText(MemoryPanel, IDC_ZLISTMODIFIEDNOWRITE_V, L"N/A"); + PhSetDialogItemText(MemoryPanel, IDC_ZLISTMODIFIEDPAGEFILE_V, L"N/A"); + PhSetDialogItemText(MemoryPanel, IDC_ZLISTSTANDBY_V, L"N/A"); + PhSetDialogItemText(MemoryPanel, IDC_ZLISTSTANDBY0_V, L"N/A"); + PhSetDialogItemText(MemoryPanel, IDC_ZLISTSTANDBY1_V, L"N/A"); + PhSetDialogItemText(MemoryPanel, IDC_ZLISTSTANDBY2_V, L"N/A"); + PhSetDialogItemText(MemoryPanel, IDC_ZLISTSTANDBY3_V, L"N/A"); + PhSetDialogItemText(MemoryPanel, IDC_ZLISTSTANDBY4_V, L"N/A"); + PhSetDialogItemText(MemoryPanel, IDC_ZLISTSTANDBY5_V, L"N/A"); + PhSetDialogItemText(MemoryPanel, IDC_ZLISTSTANDBY6_V, L"N/A"); + PhSetDialogItemText(MemoryPanel, IDC_ZLISTSTANDBY7_V, L"N/A"); } } diff --git a/ProcessHacker/thrdstk.c b/ProcessHacker/thrdstk.c index 8ba355c9777b..d706eb630796 100644 --- a/ProcessHacker/thrdstk.c +++ b/ProcessHacker/thrdstk.c @@ -1215,7 +1215,7 @@ static INT_PTR CALLBACK PhpThreadStackProgressDlgProc( PhReferenceObject(message); PhReleaseQueuedLockExclusive(&context->StatusLock); - SetDlgItemText(hwndDlg, IDC_PROGRESSTEXT, message->Buffer); + PhSetDialogItemText(hwndDlg, IDC_PROGRESSTEXT, message->Buffer); PhDereferenceObject(message); } break; diff --git a/ProcessHacker/tokprp.c b/ProcessHacker/tokprp.c index 0010fee5f69c..07674b4710b2 100644 --- a/ProcessHacker/tokprp.c +++ b/ProcessHacker/tokprp.c @@ -589,8 +589,8 @@ INT_PTR CALLBACK PhpTokenPageProc( PhAddListViewGroup(tokenPageContext->ListViewHandle, PH_PROCESS_TOKEN_CATEGORY_GROUPS, L"Groups"); ListView_SetImageList(tokenPageContext->ListViewHandle, tokenPageContext->ListViewImageList, LVSIL_SMALL); - SetDlgItemText(hwndDlg, IDC_USER, L"Unknown"); - SetDlgItemText(hwndDlg, IDC_USERSID, L"Unknown"); + PhSetDialogItemText(hwndDlg, IDC_USER, L"Unknown"); + PhSetDialogItemText(hwndDlg, IDC_USERSID, L"Unknown"); if (NT_SUCCESS(tokenPageContext->OpenObject( &tokenHandle, @@ -613,13 +613,13 @@ INT_PTR CALLBACK PhpTokenPageProc( { if (fullUserName = PhGetSidFullName(tokenUser->User.Sid, TRUE, NULL)) { - SetDlgItemText(hwndDlg, IDC_USER, fullUserName->Buffer); + PhSetDialogItemText(hwndDlg, IDC_USER, fullUserName->Buffer); PhDereferenceObject(fullUserName); } if (stringUserSid = PhSidToStringSid(tokenUser->User.Sid)) { - SetDlgItemText(hwndDlg, IDC_USERSID, stringUserSid->Buffer); + PhSetDialogItemText(hwndDlg, IDC_USERSID, stringUserSid->Buffer); PhDereferenceObject(stringUserSid); } @@ -627,10 +627,10 @@ INT_PTR CALLBACK PhpTokenPageProc( } if (NT_SUCCESS(PhGetTokenSessionId(tokenHandle, &sessionId))) - SetDlgItemInt(hwndDlg, IDC_SESSIONID, sessionId, FALSE); + PhSetDialogItemValue(hwndDlg, IDC_SESSIONID, sessionId, FALSE); if (NT_SUCCESS(PhGetTokenElevationType(tokenHandle, &elevationType))) - SetDlgItemText(hwndDlg, IDC_ELEVATED, PhGetElevationTypeString(elevationType)); + PhSetDialogItemText(hwndDlg, IDC_ELEVATED, PhGetElevationTypeString(elevationType)); if (NT_SUCCESS(PhGetTokenIsVirtualizationAllowed(tokenHandle, &isVirtualizationAllowed))) { @@ -638,7 +638,7 @@ INT_PTR CALLBACK PhpTokenPageProc( { if (NT_SUCCESS(PhGetTokenIsVirtualizationEnabled(tokenHandle, &isVirtualizationEnabled))) { - SetDlgItemText( + PhSetDialogItemText( hwndDlg, IDC_VIRTUALIZED, isVirtualizationEnabled ? L"Yes" : L"No" @@ -647,7 +647,7 @@ INT_PTR CALLBACK PhpTokenPageProc( } else { - SetDlgItemText(hwndDlg, IDC_VIRTUALIZED, L"Not allowed"); + PhSetDialogItemText(hwndDlg, IDC_VIRTUALIZED, L"Not allowed"); } } @@ -672,7 +672,7 @@ INT_PTR CALLBACK PhpTokenPageProc( PPH_STRING packageFamilyName; packageFamilyName = PhConcatStrings2(appContainerName->Buffer, L" (APP_CONTAINER)"); - SetDlgItemText(hwndDlg, IDC_USER, packageFamilyName->Buffer); + PhSetDialogItemText(hwndDlg, IDC_USER, packageFamilyName->Buffer); PhDereferenceObject(packageFamilyName); PhDereferenceObject(appContainerName); @@ -680,7 +680,7 @@ INT_PTR CALLBACK PhpTokenPageProc( if (appContainerSid) { - SetDlgItemText(hwndDlg, IDC_USERSID, appContainerSid->Buffer); + PhSetDialogItemText(hwndDlg, IDC_USERSID, appContainerSid->Buffer); PhDereferenceObject(appContainerSid); } } @@ -1358,20 +1358,20 @@ INT_PTR CALLBACK PhpTokenGeneralPageProc( NtClose(tokenHandle); } - SetDlgItemText(hwndDlg, IDC_USER, PhGetStringOrDefault(tokenUserName, L"Unknown")); - SetDlgItemText(hwndDlg, IDC_USERSID, PhGetStringOrDefault(tokenUserSid, L"Unknown")); - SetDlgItemText(hwndDlg, IDC_OWNER, PhGetStringOrDefault(tokenOwnerName, L"Unknown")); - SetDlgItemText(hwndDlg, IDC_PRIMARYGROUP, PhGetStringOrDefault(tokenPrimaryGroupName, L"Unknown")); + PhSetDialogItemText(hwndDlg, IDC_USER, PhGetStringOrDefault(tokenUserName, L"Unknown")); + PhSetDialogItemText(hwndDlg, IDC_USERSID, PhGetStringOrDefault(tokenUserSid, L"Unknown")); + PhSetDialogItemText(hwndDlg, IDC_OWNER, PhGetStringOrDefault(tokenOwnerName, L"Unknown")); + PhSetDialogItemText(hwndDlg, IDC_PRIMARYGROUP, PhGetStringOrDefault(tokenPrimaryGroupName, L"Unknown")); if (tokenSessionId != -1) - SetDlgItemInt(hwndDlg, IDC_SESSIONID, tokenSessionId, FALSE); + PhSetDialogItemValue(hwndDlg, IDC_SESSIONID, tokenSessionId, FALSE); else - SetDlgItemText(hwndDlg, IDC_SESSIONID, L"Unknown"); + PhSetDialogItemText(hwndDlg, IDC_SESSIONID, L"Unknown"); - SetDlgItemText(hwndDlg, IDC_ELEVATED, tokenElevated); - SetDlgItemText(hwndDlg, IDC_VIRTUALIZATION, tokenVirtualization); - SetDlgItemText(hwndDlg, IDC_SOURCENAME, tokenSourceName); - SetDlgItemText(hwndDlg, IDC_SOURCELUID, tokenSourceLuid); + PhSetDialogItemText(hwndDlg, IDC_ELEVATED, tokenElevated); + PhSetDialogItemText(hwndDlg, IDC_VIRTUALIZATION, tokenVirtualization); + PhSetDialogItemText(hwndDlg, IDC_SOURCENAME, tokenSourceName); + PhSetDialogItemText(hwndDlg, IDC_SOURCELUID, tokenSourceLuid); if (!hasLinkedToken) ShowWindow(GetDlgItem(hwndDlg, IDC_LINKEDTOKEN), SW_HIDE); @@ -1505,12 +1505,12 @@ INT_PTR CALLBACK PhpTokenAdvancedPageProc( NtClose(tokenHandle); } - SetDlgItemText(hwndDlg, IDC_TYPE, tokenType); - SetDlgItemText(hwndDlg, IDC_IMPERSONATIONLEVEL, tokenImpersonationLevel); - SetDlgItemText(hwndDlg, IDC_TOKENLUID, tokenLuid); - SetDlgItemText(hwndDlg, IDC_AUTHENTICATIONLUID, authenticationLuid); - SetDlgItemText(hwndDlg, IDC_MEMORYUSED, PhGetStringOrDefault(memoryUsed, L"Unknown")); - SetDlgItemText(hwndDlg, IDC_MEMORYAVAILABLE, PhGetStringOrDefault(memoryAvailable, L"Unknown")); + PhSetDialogItemText(hwndDlg, IDC_TYPE, tokenType); + PhSetDialogItemText(hwndDlg, IDC_IMPERSONATIONLEVEL, tokenImpersonationLevel); + PhSetDialogItemText(hwndDlg, IDC_TOKENLUID, tokenLuid); + PhSetDialogItemText(hwndDlg, IDC_AUTHENTICATIONLUID, authenticationLuid); + PhSetDialogItemText(hwndDlg, IDC_MEMORYUSED, PhGetStringOrDefault(memoryUsed, L"Unknown")); + PhSetDialogItemText(hwndDlg, IDC_MEMORYAVAILABLE, PhGetStringOrDefault(memoryAvailable, L"Unknown")); } break; } diff --git a/phlib/guisup.c b/phlib/guisup.c index 2017e014def5..c0041dea7bfe 100644 --- a/phlib/guisup.c +++ b/phlib/guisup.c @@ -347,7 +347,7 @@ ULONG PhGetWindowTextEx( } else { - length = GetWindowTextLength(hwnd); + length = PhGetWindowTextLength(hwnd); if (length == 0 || (Flags & PH_GET_WINDOW_TEXT_LENGTH_ONLY)) { @@ -1458,3 +1458,59 @@ HWND PhGetProcessMainWindowEx( return context.ImmersiveWindow ? context.ImmersiveWindow : context.Window; } + +ULONG PhGetDialogItemValue( + _In_ HWND WindowHandle, + _In_ INT ControlID + ) +{ + ULONG64 controlValue = 0; + HWND controlHandle; + PPH_STRING controlText; + + if (controlHandle = GetDlgItem(WindowHandle, ControlID)) + { + if (controlText = PhGetWindowText(controlHandle)) + { + PhStringToInteger64(&controlText->sr, 10, &controlValue); + PhDereferenceObject(controlText); + } + } + + return (ULONG)controlValue; +} + +VOID PhSetDialogItemValue( + _In_ HWND WindowHandle, + _In_ INT ControlID, + _In_ ULONG Value, + _In_ BOOLEAN Signed + ) +{ + HWND controlHandle; + WCHAR valueString[PH_INT32_STR_LEN_1]; + + if (Signed) + PhPrintInt32(valueString, (LONG)Value); + else + PhPrintUInt32(valueString, Value); + + if (controlHandle = GetDlgItem(WindowHandle, ControlID)) + { + SendMessage(controlHandle, WM_SETTEXT, 0, (LPARAM)valueString); // DefWindowProc + } +} + +VOID PhSetDialogItemText( + _In_ HWND WindowHandle, + _In_ INT ControlID, + _In_ PCWSTR WindowText + ) +{ + HWND controlHandle; + + if (controlHandle = GetDlgItem(WindowHandle, ControlID)) + { + SendMessage(controlHandle, WM_SETTEXT, 0, (LPARAM)WindowText); // DefWindowProc + } +} diff --git a/phlib/include/guisup.h b/phlib/include/guisup.h index 38c83defb8d6..fb5c9642e7d7 100644 --- a/phlib/include/guisup.h +++ b/phlib/include/guisup.h @@ -523,6 +523,50 @@ HWND PhGetProcessMainWindowEx( _In_ BOOLEAN SkipInvisible ); +PHLIBAPI +ULONG +NTAPI +PhGetDialogItemValue( + _In_ HWND WindowHandle, + _In_ INT ControlID + ); + +PHLIBAPI +VOID +NTAPI +PhSetDialogItemValue( + _In_ HWND WindowHandle, + _In_ INT ControlID, + _In_ ULONG Value, + _In_ BOOLEAN Signed + ); + +PHLIBAPI +VOID +NTAPI +PhSetDialogItemText( + _In_ HWND WindowHandle, + _In_ INT ControlID, + _In_ PCWSTR WindowText + ); + +FORCEINLINE ULONG PhGetWindowTextLength( + _In_ HWND WindowHandle + ) +{ + return (ULONG)SendMessage(WindowHandle, WM_GETTEXTLENGTH, 0, 0); // DefWindowProc +} + +FORCEINLINE VOID PhSetDialogFocus( + _In_ HWND WindowHandle, + _In_ HWND FocusHandle + ) +{ + // Do not use the SendMessage function to send a WM_NEXTDLGCTL message if your application will + // concurrently process other messages that set the focus. Use the PostMessage function instead. + SendMessage(WindowHandle, WM_NEXTDLGCTL, (WPARAM)FocusHandle, MAKELPARAM(TRUE, 0)); +} + FORCEINLINE VOID PhResizingMinimumSize( _Inout_ PRECT Rect, _In_ WPARAM Edge, diff --git a/plugins/ExtendedNotifications/main.c b/plugins/ExtendedNotifications/main.c index d92de3748d08..decda3f7e088 100644 --- a/plugins/ExtendedNotifications/main.c +++ b/plugins/ExtendedNotifications/main.c @@ -701,7 +701,7 @@ INT_PTR HandleCommonMessages( PFILTER_ENTRY entry; entry = FilterList->Items[i]; - SetDlgItemText(hwndDlg, IDC_TEXT, entry->Filter->Buffer); + PhSetDialogItemText(hwndDlg, IDC_TEXT, entry->Filter->Buffer); Button_SetCheck(GetDlgItem(hwndDlg, IDC_INCLUDE), entry->Type == FilterInclude ? BST_CHECKED : BST_UNCHECKED); Button_SetCheck(GetDlgItem(hwndDlg, IDC_EXCLUDE), @@ -768,7 +768,7 @@ INT_PTR HandleCommonMessages( ListBox_SetCurSel(ListBox, i); } - SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hwndDlg, IDC_TEXT), TRUE); + PhSetDialogFocus(hwndDlg, GetDlgItem(hwndDlg, IDC_TEXT)); Edit_SetSel(GetDlgItem(hwndDlg, IDC_TEXT), 0, -1); FixControlStates(hwndDlg, ListBox); @@ -998,7 +998,7 @@ INT_PTR CALLBACK LoggingDlgProc( { case WM_INITDIALOG: { - SetDlgItemText(hwndDlg, IDC_LOGFILENAME, PhaGetStringSetting(SETTING_NAME_LOG_FILENAME)->Buffer); + PhSetDialogItemText(hwndDlg, IDC_LOGFILENAME, PhaGetStringSetting(SETTING_NAME_LOG_FILENAME)->Buffer); PhInitializeLayoutManager(&LayoutManager, hwndDlg); PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDC_INFO), NULL, PH_ANCHOR_TOP | PH_ANCHOR_LEFT | PH_ANCHOR_RIGHT); @@ -1041,7 +1041,7 @@ INT_PTR CALLBACK LoggingDlgProc( if (PhShowFileDialog(hwndDlg, fileDialog)) { fileName = PH_AUTO(PhGetFileDialogFileName(fileDialog)); - SetDlgItemText(hwndDlg, IDC_LOGFILENAME, fileName->Buffer); + PhSetDialogItemText(hwndDlg, IDC_LOGFILENAME, fileName->Buffer); } PhFreeFileDialog(fileDialog); @@ -1068,7 +1068,7 @@ INT_PTR CALLBACK GrowlDlgProc( { case WM_INITDIALOG: { - SetDlgItemText(hwndDlg, IDC_LICENSE, PH_AUTO_T(PH_STRING, PhConvertUtf8ToUtf16(gntp_send_license_text))->Buffer); + PhSetDialogItemText(hwndDlg, IDC_LICENSE, PH_AUTO_T(PH_STRING, PhConvertUtf8ToUtf16(gntp_send_license_text))->Buffer); Button_SetCheck(GetDlgItem(hwndDlg, IDC_ENABLEGROWL), PhGetIntegerSetting(SETTING_NAME_ENABLE_GROWL) ? BST_CHECKED : BST_UNCHECKED); diff --git a/plugins/ExtendedServices/depend.c b/plugins/ExtendedServices/depend.c index 99b6aaeecff2..4aee76d26def 100644 --- a/plugins/ExtendedServices/depend.c +++ b/plugins/ExtendedServices/depend.c @@ -143,7 +143,7 @@ INT_PTR CALLBACK EspServiceDependenciesDlgProc( BOOLEAN success = FALSE; PPH_SERVICE_ITEM *services; - SetDlgItemText(hwndDlg, IDC_MESSAGE, L"This service depends on the following services:"); + PhSetDialogItemText(hwndDlg, IDC_MESSAGE, L"This service depends on the following services:"); PhInitializeLayoutManager(&context->LayoutManager, hwndDlg); PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_SERVICES_LAYOUT), NULL, PH_ANCHOR_ALL); @@ -206,7 +206,7 @@ INT_PTR CALLBACK EspServiceDependenciesDlgProc( if (!success) { - SetDlgItemText(hwndDlg, IDC_SERVICES_LAYOUT, PhaConcatStrings2(L"Unable to enumerate dependencies: ", + PhSetDialogItemText(hwndDlg, IDC_SERVICES_LAYOUT, PhaConcatStrings2(L"Unable to enumerate dependencies: ", ((PPH_STRING)PH_AUTO(PhGetWin32Message(win32Result)))->Buffer)->Buffer); ShowWindow(GetDlgItem(hwndDlg, IDC_SERVICES_LAYOUT), SW_SHOW); } @@ -271,7 +271,7 @@ INT_PTR CALLBACK EspServiceDependentsDlgProc( BOOLEAN success = FALSE; PPH_SERVICE_ITEM *services; - SetDlgItemText(hwndDlg, IDC_MESSAGE, L"The following services depend on this service:"); + PhSetDialogItemText(hwndDlg, IDC_MESSAGE, L"The following services depend on this service:"); PhInitializeLayoutManager(&context->LayoutManager, hwndDlg); PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_SERVICES_LAYOUT), NULL, PH_ANCHOR_ALL); @@ -318,7 +318,7 @@ INT_PTR CALLBACK EspServiceDependentsDlgProc( if (!success) { - SetDlgItemText(hwndDlg, IDC_SERVICES_LAYOUT, PhaConcatStrings2(L"Unable to enumerate dependents: ", + PhSetDialogItemText(hwndDlg, IDC_SERVICES_LAYOUT, PhaConcatStrings2(L"Unable to enumerate dependents: ", ((PPH_STRING)PH_AUTO(PhGetWin32Message(win32Result)))->Buffer)->Buffer); ShowWindow(GetDlgItem(hwndDlg, IDC_SERVICES_LAYOUT), SW_SHOW); } diff --git a/plugins/ExtendedServices/other.c b/plugins/ExtendedServices/other.c index e93bfb620a1b..04354d3a312e 100644 --- a/plugins/ExtendedServices/other.c +++ b/plugins/ExtendedServices/other.c @@ -154,7 +154,7 @@ NTSTATUS EspLoadOtherInfo( &returnLength )) { - SetDlgItemInt(hwndDlg, IDC_PRESHUTDOWNTIMEOUT, preshutdownInfo.dwPreshutdownTimeout, FALSE); + PhSetDialogItemValue(hwndDlg, IDC_PRESHUTDOWNTIMEOUT, preshutdownInfo.dwPreshutdownTimeout, FALSE); Context->PreshutdownTimeoutValid = TRUE; } @@ -368,7 +368,7 @@ INT_PTR CALLBACK EspServiceOtherDlgProc( if (WindowsVersion < WINDOWS_8_1) EnableWindow(GetDlgItem(hwndDlg, IDC_PROTECTION), FALSE); - SetDlgItemText(hwndDlg, IDC_SERVICESID, + PhSetDialogItemText(hwndDlg, IDC_SERVICESID, PhGetStringOrDefault(PH_AUTO(EspGetServiceSidString(&serviceItem->Name->sr)), L"N/A")); status = EspLoadOtherInfo(hwndDlg, context); @@ -633,7 +633,7 @@ INT_PTR CALLBACK EspServiceOtherDlgProc( if (context->PreshutdownTimeoutValid) { - preshutdownInfo.dwPreshutdownTimeout = GetDlgItemInt(hwndDlg, IDC_PRESHUTDOWNTIMEOUT, NULL, FALSE); + preshutdownInfo.dwPreshutdownTimeout = PhGetDialogItemValue(hwndDlg, IDC_PRESHUTDOWNTIMEOUT); if (!EspChangeServiceConfig2(context->ServiceItem->Name->Buffer, serviceHandle, SERVICE_CONFIG_PRESHUTDOWN_INFO, &preshutdownInfo)) diff --git a/plugins/ExtendedServices/recovery.c b/plugins/ExtendedServices/recovery.c index 1949ff3a7ffc..66436e7c9894 100644 --- a/plugins/ExtendedServices/recovery.c +++ b/plugins/ExtendedServices/recovery.c @@ -191,11 +191,11 @@ NTSTATUS EspLoadRecoveryInfo( // Reset fail count after - SetDlgItemInt(hwndDlg, IDC_RESETFAILCOUNT, failureActions->dwResetPeriod / (60 * 60 * 24), FALSE); // s to days + PhSetDialogItemValue(hwndDlg, IDC_RESETFAILCOUNT, failureActions->dwResetPeriod / (60 * 60 * 24), FALSE); // s to days // Restart service after - SetDlgItemText(hwndDlg, IDC_RESTARTSERVICEAFTER, L"1"); + PhSetDialogItemText(hwndDlg, IDC_RESTARTSERVICEAFTER, L"1"); for (i = 0; i < failureActions->cActions; i++) { @@ -203,7 +203,7 @@ NTSTATUS EspLoadRecoveryInfo( { if (failureActions->lpsaActions[i].Delay != 0) { - SetDlgItemInt(hwndDlg, IDC_RESTARTSERVICEAFTER, + PhSetDialogItemValue(hwndDlg, IDC_RESTARTSERVICEAFTER, failureActions->lpsaActions[i].Delay / (1000 * 60), FALSE); // ms to min } @@ -252,7 +252,7 @@ NTSTATUS EspLoadRecoveryInfo( // Run program - SetDlgItemText(hwndDlg, IDC_RUNPROGRAM, failureActions->lpCommand); + PhSetDialogItemText(hwndDlg, IDC_RUNPROGRAM, failureActions->lpCommand); PhFree(failureActions); CloseServiceHandle(serviceHandle); @@ -317,7 +317,7 @@ INT_PTR CALLBACK EspServiceRecoveryDlgProc( } else if (!NT_SUCCESS(status)) { - SetDlgItemText(hwndDlg, IDC_RESETFAILCOUNT, L"0"); + PhSetDialogItemText(hwndDlg, IDC_RESETFAILCOUNT, L"0"); context->EnableFlagCheckBox = TRUE; EnableWindow(GetDlgItem(hwndDlg, IDC_ENABLEFORERRORSTOPS), TRUE); @@ -381,7 +381,7 @@ INT_PTR CALLBACK EspServiceRecoveryDlgProc( if (PhShowFileDialog(hwndDlg, fileDialog)) { fileName = PH_AUTO(PhGetFileDialogFileName(fileDialog)); - SetDlgItemText(hwndDlg, IDC_RUNPROGRAM, fileName->Buffer); + PhSetDialogItemText(hwndDlg, IDC_RUNPROGRAM, fileName->Buffer); } PhFreeFileDialog(fileDialog); @@ -437,7 +437,7 @@ INT_PTR CALLBACK EspServiceRecoveryDlgProc( // Build the failure actions structure. - failureActions.dwResetPeriod = GetDlgItemInt(hwndDlg, IDC_RESETFAILCOUNT, NULL, FALSE) * 60 * 60 * 24; + failureActions.dwResetPeriod = PhGetDialogItemValue(hwndDlg, IDC_RESETFAILCOUNT) * 60 * 60 * 24; failureActions.lpRebootMsg = PhGetStringOrEmpty(context->RebootMessage); failureActions.lpCommand = PhaGetDlgItemText(hwndDlg, IDC_RUNPROGRAM)->Buffer; failureActions.cActions = 3; @@ -447,7 +447,7 @@ INT_PTR CALLBACK EspServiceRecoveryDlgProc( actions[1].Type = ComboBoxToServiceAction(GetDlgItem(hwndDlg, IDC_SECONDFAILURE)); actions[2].Type = ComboBoxToServiceAction(GetDlgItem(hwndDlg, IDC_SUBSEQUENTFAILURES)); - restartServiceAfter = GetDlgItemInt(hwndDlg, IDC_RESTARTSERVICEAFTER, NULL, FALSE) * 1000 * 60; + restartServiceAfter = PhGetDialogItemValue(hwndDlg, IDC_RESTARTSERVICEAFTER) * 1000 * 60; for (i = 0; i < 3; i++) { @@ -613,11 +613,11 @@ INT_PTR CALLBACK RestartComputerDlgProc( { PhCenterWindow(hwndDlg, GetParent(hwndDlg)); - SetDlgItemInt(hwndDlg, IDC_RESTARTCOMPAFTER, context->RebootAfter / (1000 * 60), FALSE); // ms to min + PhSetDialogItemValue(hwndDlg, IDC_RESTARTCOMPAFTER, context->RebootAfter / (1000 * 60), FALSE); // ms to min Button_SetCheck(GetDlgItem(hwndDlg, IDC_ENABLERESTARTMESSAGE), context->RebootMessage ? BST_CHECKED : BST_UNCHECKED); - SetDlgItemText(hwndDlg, IDC_RESTARTMESSAGE, PhGetString(context->RebootMessage)); + PhSetDialogItemText(hwndDlg, IDC_RESTARTMESSAGE, PhGetString(context->RebootMessage)); - SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hwndDlg, IDC_RESTARTCOMPAFTER), TRUE); + PhSetDialogFocus(hwndDlg, GetDlgItem(hwndDlg, IDC_RESTARTCOMPAFTER)); Edit_SetSel(GetDlgItem(hwndDlg, IDC_RESTARTCOMPAFTER), 0, -1); } break; @@ -630,7 +630,7 @@ INT_PTR CALLBACK RestartComputerDlgProc( break; case IDOK: { - context->RebootAfter = GetDlgItemInt(hwndDlg, IDC_RESTARTCOMPAFTER, NULL, FALSE) * 1000 * 60; + context->RebootAfter = PhGetDialogItemValue(hwndDlg, IDC_RESTARTCOMPAFTER) * 1000 * 60; if (Button_GetCheck(GetDlgItem(hwndDlg, IDC_ENABLERESTARTMESSAGE)) == BST_CHECKED) PhMoveReference(&context->RebootMessage, PhGetWindowText(GetDlgItem(hwndDlg, IDC_RESTARTMESSAGE))); @@ -678,7 +678,7 @@ INT_PTR CALLBACK RestartComputerDlgProc( computerName, computerName ); - SetDlgItemText(hwndDlg, IDC_RESTARTMESSAGE, message->Buffer); + PhSetDialogItemText(hwndDlg, IDC_RESTARTMESSAGE, message->Buffer); if (allocated) PhFree(computerName); @@ -692,7 +692,7 @@ INT_PTR CALLBACK RestartComputerDlgProc( { // A zero length restart message disables it, so we might as well uncheck the box. Button_SetCheck(GetDlgItem(hwndDlg, IDC_ENABLERESTARTMESSAGE), - GetWindowTextLength(GetDlgItem(hwndDlg, IDC_RESTARTMESSAGE)) != 0 ? BST_CHECKED : BST_UNCHECKED); + PhGetWindowTextLength(GetDlgItem(hwndDlg, IDC_RESTARTMESSAGE)) != 0 ? BST_CHECKED : BST_UNCHECKED); } } break; diff --git a/plugins/ExtendedServices/srvprgrs.c b/plugins/ExtendedServices/srvprgrs.c index 059b95b36a93..df1046898faf 100644 --- a/plugins/ExtendedServices/srvprgrs.c +++ b/plugins/ExtendedServices/srvprgrs.c @@ -65,7 +65,7 @@ INT_PTR CALLBACK EspRestartServiceDlgProc( PhSetWindowStyle(GetDlgItem(hwndDlg, IDC_PROGRESS), PBS_MARQUEE, PBS_MARQUEE); SendMessage(GetDlgItem(hwndDlg, IDC_PROGRESS), PBM_SETMARQUEE, TRUE, 75); - SetDlgItemText(hwndDlg, IDC_MESSAGE, PhaFormatString(L"Attempting to stop %s...", context->ServiceItem->Name->Buffer)->Buffer); + PhSetDialogItemText(hwndDlg, IDC_MESSAGE, PhaFormatString(L"Attempting to stop %s...", context->ServiceItem->Name->Buffer)->Buffer); if (PhUiStopService(hwndDlg, context->ServiceItem)) { @@ -101,7 +101,7 @@ INT_PTR CALLBACK EspRestartServiceDlgProc( { // The service is stopped, so start the service now. - SetDlgItemText(hwndDlg, IDC_MESSAGE, + PhSetDialogItemText(hwndDlg, IDC_MESSAGE, PhaFormatString(L"Attempting to start %s...", context->ServiceItem->Name->Buffer)->Buffer); context->DisableTimer = TRUE; diff --git a/plugins/ExtendedServices/trigger.c b/plugins/ExtendedServices/trigger.c index a423158167a4..f9c84703a697 100644 --- a/plugins/ExtendedServices/trigger.c +++ b/plugins/ExtendedServices/trigger.c @@ -1115,7 +1115,7 @@ VOID EspFixServiceTriggerControls( if (PhEqualString2(selectedSubTypeString, L"Custom", FALSE)) { EnableWindow(GetDlgItem(hwndDlg, IDC_SUBTYPECUSTOM), TRUE); - SetDlgItemText(hwndDlg, IDC_SUBTYPECUSTOM, Context->LastCustomSubType->Buffer); + PhSetDialogItemText(hwndDlg, IDC_SUBTYPECUSTOM, Context->LastCustomSubType->Buffer); } else { @@ -1123,7 +1123,7 @@ VOID EspFixServiceTriggerControls( { EnableWindow(GetDlgItem(hwndDlg, IDC_SUBTYPECUSTOM), FALSE); PhMoveReference(&Context->LastCustomSubType, PhGetWindowText(GetDlgItem(hwndDlg, IDC_SUBTYPECUSTOM))); - SetDlgItemText(hwndDlg, IDC_SUBTYPECUSTOM, L""); + PhSetDialogItemText(hwndDlg, IDC_SUBTYPECUSTOM, L""); } } @@ -1695,8 +1695,8 @@ INT_PTR CALLBACK ValueDlgProc( { case WM_INITDIALOG: { - SetDlgItemText(hwndDlg, IDC_VALUES, context->EditingValue->Buffer); - SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hwndDlg, IDC_VALUES), TRUE); + PhSetDialogItemText(hwndDlg, IDC_VALUES, context->EditingValue->Buffer); + PhSetDialogFocus(hwndDlg, GetDlgItem(hwndDlg, IDC_VALUES)); Edit_SetSel(GetDlgItem(hwndDlg, IDC_VALUES), 0, -1); } break; diff --git a/plugins/ExtendedTools/disktab.c b/plugins/ExtendedTools/disktab.c index 55a873d0d19e..bbd6cb66284e 100644 --- a/plugins/ExtendedTools/disktab.c +++ b/plugins/ExtendedTools/disktab.c @@ -1135,7 +1135,7 @@ INT_PTR CALLBACK EtpDiskTabErrorDialogProc( } else { - SetDlgItemText(hwndDlg, IDC_ERROR, L"Unable to start the kernel event tracing session."); + PhSetDialogItemText(hwndDlg, IDC_ERROR, L"Unable to start the kernel event tracing session."); ShowWindow(GetDlgItem(hwndDlg, IDC_RESTART), SW_HIDE); } } diff --git a/plugins/ExtendedTools/etwprprp.c b/plugins/ExtendedTools/etwprprp.c index 7cbb27017645..1af87271145b 100644 --- a/plugins/ExtendedTools/etwprprp.c +++ b/plugins/ExtendedTools/etwprprp.c @@ -223,19 +223,19 @@ VOID EtwDiskNetworkUpdatePanel( { PET_PROCESS_BLOCK block = Context->Block; - SetDlgItemText(Context->PanelHandle, IDC_ZREADS_V, PhaFormatUInt64(block->DiskReadCount, TRUE)->Buffer); - SetDlgItemText(Context->PanelHandle, IDC_ZREADBYTES_V, PhaFormatSize(block->DiskReadRawDelta.Value, -1)->Buffer); - SetDlgItemText(Context->PanelHandle, IDC_ZREADBYTESDELTA_V, PhaFormatSize(block->DiskReadRawDelta.Delta, -1)->Buffer); - SetDlgItemText(Context->PanelHandle, IDC_ZWRITES_V, PhaFormatUInt64(block->DiskWriteCount, TRUE)->Buffer); - SetDlgItemText(Context->PanelHandle, IDC_ZWRITEBYTES_V, PhaFormatSize(block->DiskWriteRawDelta.Value, -1)->Buffer); - SetDlgItemText(Context->PanelHandle, IDC_ZWRITEBYTESDELTA_V, PhaFormatSize(block->DiskWriteRawDelta.Delta, -1)->Buffer); - - SetDlgItemText(Context->PanelHandle, IDC_ZRECEIVES_V, PhaFormatUInt64(block->NetworkReceiveCount, TRUE)->Buffer); - SetDlgItemText(Context->PanelHandle, IDC_ZRECEIVEBYTES_V, PhaFormatSize(block->NetworkReceiveRawDelta.Value, -1)->Buffer); - SetDlgItemText(Context->PanelHandle, IDC_ZRECEIVEBYTESDELTA_V, PhaFormatSize(block->NetworkReceiveRawDelta.Delta, -1)->Buffer); - SetDlgItemText(Context->PanelHandle, IDC_ZSENDS_V, PhaFormatUInt64(block->NetworkSendCount, TRUE)->Buffer); - SetDlgItemText(Context->PanelHandle, IDC_ZSENDBYTES_V, PhaFormatSize(block->NetworkSendRawDelta.Value, -1)->Buffer); - SetDlgItemText(Context->PanelHandle, IDC_ZSENDBYTESDELTA_V, PhaFormatSize(block->NetworkSendRawDelta.Delta, -1)->Buffer); + PhSetDialogItemText(Context->PanelHandle, IDC_ZREADS_V, PhaFormatUInt64(block->DiskReadCount, TRUE)->Buffer); + PhSetDialogItemText(Context->PanelHandle, IDC_ZREADBYTES_V, PhaFormatSize(block->DiskReadRawDelta.Value, -1)->Buffer); + PhSetDialogItemText(Context->PanelHandle, IDC_ZREADBYTESDELTA_V, PhaFormatSize(block->DiskReadRawDelta.Delta, -1)->Buffer); + PhSetDialogItemText(Context->PanelHandle, IDC_ZWRITES_V, PhaFormatUInt64(block->DiskWriteCount, TRUE)->Buffer); + PhSetDialogItemText(Context->PanelHandle, IDC_ZWRITEBYTES_V, PhaFormatSize(block->DiskWriteRawDelta.Value, -1)->Buffer); + PhSetDialogItemText(Context->PanelHandle, IDC_ZWRITEBYTESDELTA_V, PhaFormatSize(block->DiskWriteRawDelta.Delta, -1)->Buffer); + + PhSetDialogItemText(Context->PanelHandle, IDC_ZRECEIVES_V, PhaFormatUInt64(block->NetworkReceiveCount, TRUE)->Buffer); + PhSetDialogItemText(Context->PanelHandle, IDC_ZRECEIVEBYTES_V, PhaFormatSize(block->NetworkReceiveRawDelta.Value, -1)->Buffer); + PhSetDialogItemText(Context->PanelHandle, IDC_ZRECEIVEBYTESDELTA_V, PhaFormatSize(block->NetworkReceiveRawDelta.Delta, -1)->Buffer); + PhSetDialogItemText(Context->PanelHandle, IDC_ZSENDS_V, PhaFormatUInt64(block->NetworkSendCount, TRUE)->Buffer); + PhSetDialogItemText(Context->PanelHandle, IDC_ZSENDBYTES_V, PhaFormatSize(block->NetworkSendRawDelta.Value, -1)->Buffer); + PhSetDialogItemText(Context->PanelHandle, IDC_ZSENDBYTESDELTA_V, PhaFormatSize(block->NetworkSendRawDelta.Delta, -1)->Buffer); } VOID EtwDiskNetworkUpdateInfo( diff --git a/plugins/ExtendedTools/etwsys.c b/plugins/ExtendedTools/etwsys.c index dd813a88c088..81bf8de75566 100644 --- a/plugins/ExtendedTools/etwsys.c +++ b/plugins/ExtendedTools/etwsys.c @@ -390,10 +390,10 @@ VOID EtpUpdateDiskPanel( VOID ) { - SetDlgItemText(DiskPanel, IDC_ZREADSDELTA_V, PhaFormatUInt64(EtDiskReadCountDelta.Delta, TRUE)->Buffer); - SetDlgItemText(DiskPanel, IDC_ZREADBYTESDELTA_V, PhaFormatSize(EtDiskReadDelta.Delta, -1)->Buffer); - SetDlgItemText(DiskPanel, IDC_ZWRITESDELTA_V, PhaFormatUInt64(EtDiskWriteCountDelta.Delta, TRUE)->Buffer); - SetDlgItemText(DiskPanel, IDC_ZWRITEBYTESDELTA_V, PhaFormatSize(EtDiskWriteDelta.Delta, -1)->Buffer); + PhSetDialogItemText(DiskPanel, IDC_ZREADSDELTA_V, PhaFormatUInt64(EtDiskReadCountDelta.Delta, TRUE)->Buffer); + PhSetDialogItemText(DiskPanel, IDC_ZREADBYTESDELTA_V, PhaFormatSize(EtDiskReadDelta.Delta, -1)->Buffer); + PhSetDialogItemText(DiskPanel, IDC_ZWRITESDELTA_V, PhaFormatUInt64(EtDiskWriteCountDelta.Delta, TRUE)->Buffer); + PhSetDialogItemText(DiskPanel, IDC_ZWRITEBYTESDELTA_V, PhaFormatSize(EtDiskWriteDelta.Delta, -1)->Buffer); } PPH_PROCESS_RECORD EtpReferenceMaxDiskRecord( @@ -766,10 +766,10 @@ VOID EtpUpdateNetworkPanel( VOID ) { - SetDlgItemText(NetworkPanel, IDC_ZRECEIVESDELTA_V, PhaFormatUInt64(EtNetworkReceiveCountDelta.Delta, TRUE)->Buffer); - SetDlgItemText(NetworkPanel, IDC_ZRECEIVEBYTESDELTA_V, PhaFormatSize(EtNetworkReceiveDelta.Delta, -1)->Buffer); - SetDlgItemText(NetworkPanel, IDC_ZSENDSDELTA_V, PhaFormatUInt64(EtNetworkSendCountDelta.Delta, TRUE)->Buffer); - SetDlgItemText(NetworkPanel, IDC_ZSENDBYTESDELTA_V, PhaFormatSize(EtNetworkSendDelta.Delta, -1)->Buffer); + PhSetDialogItemText(NetworkPanel, IDC_ZRECEIVESDELTA_V, PhaFormatUInt64(EtNetworkReceiveCountDelta.Delta, TRUE)->Buffer); + PhSetDialogItemText(NetworkPanel, IDC_ZRECEIVEBYTESDELTA_V, PhaFormatSize(EtNetworkReceiveDelta.Delta, -1)->Buffer); + PhSetDialogItemText(NetworkPanel, IDC_ZSENDSDELTA_V, PhaFormatUInt64(EtNetworkSendCountDelta.Delta, TRUE)->Buffer); + PhSetDialogItemText(NetworkPanel, IDC_ZSENDBYTESDELTA_V, PhaFormatSize(EtNetworkSendDelta.Delta, -1)->Buffer); } PPH_PROCESS_RECORD EtpReferenceMaxNetworkRecord( diff --git a/plugins/ExtendedTools/gpuprprp.c b/plugins/ExtendedTools/gpuprprp.c index 84c0fa0c1e09..78bfd0a0004d 100644 --- a/plugins/ExtendedTools/gpuprprp.c +++ b/plugins/ExtendedTools/gpuprprp.c @@ -401,24 +401,24 @@ VOID GpuPropUpdatePanel( PhPrintTimeSpan(runningTimeString, Context->GpuStatistics.RunningTime * 10, PH_TIMESPAN_HMSM); - SetDlgItemText(Context->PanelHandle, IDC_ZRUNNINGTIME_V, runningTimeString); - SetDlgItemText(Context->PanelHandle, IDC_ZCONTEXTSWITCHES_V, PhaFormatUInt64(Context->GpuStatistics.ContextSwitches, TRUE)->Buffer); - SetDlgItemText(Context->PanelHandle, IDC_ZTOTALNODES_V, PhaFormatUInt64(Context->GpuStatistics.NodeCount, TRUE)->Buffer); - SetDlgItemText(Context->PanelHandle, IDC_ZTOTALSEGMENTS_V, PhaFormatUInt64(Context->GpuStatistics.SegmentCount, TRUE)->Buffer); + PhSetDialogItemText(Context->PanelHandle, IDC_ZRUNNINGTIME_V, runningTimeString); + PhSetDialogItemText(Context->PanelHandle, IDC_ZCONTEXTSWITCHES_V, PhaFormatUInt64(Context->GpuStatistics.ContextSwitches, TRUE)->Buffer); + PhSetDialogItemText(Context->PanelHandle, IDC_ZTOTALNODES_V, PhaFormatUInt64(Context->GpuStatistics.NodeCount, TRUE)->Buffer); + PhSetDialogItemText(Context->PanelHandle, IDC_ZTOTALSEGMENTS_V, PhaFormatUInt64(Context->GpuStatistics.SegmentCount, TRUE)->Buffer); if (Context->DetailsHandle) { // Note: no lock is needed because we only ever update the 'details' dialog text on this same thread. - SetDlgItemText(Context->DetailsHandle, IDC_ZDEDICATEDCOMMITTED_V, PhaFormatSize(Context->GpuStatistics.DedicatedCommitted, -1)->Buffer); - SetDlgItemText(Context->DetailsHandle, IDC_ZSHAREDCOMMITTED_V, PhaFormatSize(Context->GpuStatistics.SharedCommitted, -1)->Buffer); - SetDlgItemText(Context->DetailsHandle, IDC_ZTOTALALLOCATED_V, PhaFormatSize(Context->GpuStatistics.BytesAllocated, -1)->Buffer); - SetDlgItemText(Context->DetailsHandle, IDC_ZTOTALRESERVED_V, PhaFormatSize(Context->GpuStatistics.BytesReserved, -1)->Buffer); - SetDlgItemText(Context->DetailsHandle, IDC_ZWRITECOMBINEDALLOCATED_V, PhaFormatSize(Context->GpuStatistics.WriteCombinedBytesAllocated, -1)->Buffer); - SetDlgItemText(Context->DetailsHandle, IDC_ZWRITECOMBINEDRESERVED_V, PhaFormatSize(Context->GpuStatistics.WriteCombinedBytesReserved, -1)->Buffer); - SetDlgItemText(Context->DetailsHandle, IDC_ZCACHEDALLOCATED_V, PhaFormatSize(Context->GpuStatistics.CachedBytesAllocated, -1)->Buffer); - SetDlgItemText(Context->DetailsHandle, IDC_ZCACHEDRESERVED_V, PhaFormatSize(Context->GpuStatistics.CachedBytesReserved, -1)->Buffer); - SetDlgItemText(Context->DetailsHandle, IDC_ZSECTIONALLOCATED_V, PhaFormatSize(Context->GpuStatistics.SectionBytesAllocated, -1)->Buffer); - SetDlgItemText(Context->DetailsHandle, IDC_ZSECTIONRESERVED_V, PhaFormatSize(Context->GpuStatistics.SectionBytesReserved, -1)->Buffer); + PhSetDialogItemText(Context->DetailsHandle, IDC_ZDEDICATEDCOMMITTED_V, PhaFormatSize(Context->GpuStatistics.DedicatedCommitted, -1)->Buffer); + PhSetDialogItemText(Context->DetailsHandle, IDC_ZSHAREDCOMMITTED_V, PhaFormatSize(Context->GpuStatistics.SharedCommitted, -1)->Buffer); + PhSetDialogItemText(Context->DetailsHandle, IDC_ZTOTALALLOCATED_V, PhaFormatSize(Context->GpuStatistics.BytesAllocated, -1)->Buffer); + PhSetDialogItemText(Context->DetailsHandle, IDC_ZTOTALRESERVED_V, PhaFormatSize(Context->GpuStatistics.BytesReserved, -1)->Buffer); + PhSetDialogItemText(Context->DetailsHandle, IDC_ZWRITECOMBINEDALLOCATED_V, PhaFormatSize(Context->GpuStatistics.WriteCombinedBytesAllocated, -1)->Buffer); + PhSetDialogItemText(Context->DetailsHandle, IDC_ZWRITECOMBINEDRESERVED_V, PhaFormatSize(Context->GpuStatistics.WriteCombinedBytesReserved, -1)->Buffer); + PhSetDialogItemText(Context->DetailsHandle, IDC_ZCACHEDALLOCATED_V, PhaFormatSize(Context->GpuStatistics.CachedBytesAllocated, -1)->Buffer); + PhSetDialogItemText(Context->DetailsHandle, IDC_ZCACHEDRESERVED_V, PhaFormatSize(Context->GpuStatistics.CachedBytesReserved, -1)->Buffer); + PhSetDialogItemText(Context->DetailsHandle, IDC_ZSECTIONALLOCATED_V, PhaFormatSize(Context->GpuStatistics.SectionBytesAllocated, -1)->Buffer); + PhSetDialogItemText(Context->DetailsHandle, IDC_ZSECTIONRESERVED_V, PhaFormatSize(Context->GpuStatistics.SectionBytesReserved, -1)->Buffer); } } diff --git a/plugins/ExtendedTools/gpusys.c b/plugins/ExtendedTools/gpusys.c index aae9aec7745a..fbcca7458959 100644 --- a/plugins/ExtendedTools/gpusys.c +++ b/plugins/ExtendedTools/gpusys.c @@ -180,7 +180,7 @@ INT_PTR CALLBACK EtpGpuDialogProc( SendMessage(GetDlgItem(hwndDlg, IDC_TITLE), WM_SETFONT, (WPARAM)GpuSection->Parameters->LargeFont, FALSE); SendMessage(GetDlgItem(hwndDlg, IDC_GPUNAME), WM_SETFONT, (WPARAM)GpuSection->Parameters->MediumFont, FALSE); - SetDlgItemText(hwndDlg, IDC_GPUNAME, ((PPH_STRING)PH_AUTO(EtpGetGpuNameString()))->Buffer); + PhSetDialogItemText(hwndDlg, IDC_GPUNAME, ((PPH_STRING)PH_AUTO(EtpGetGpuNameString()))->Buffer); GpuPanel = CreateDialog(PluginInstance->DllBase, MAKEINTRESOURCE(IDD_SYSINFO_GPUPANEL), hwndDlg, EtpGpuPanelDialogProc); ShowWindow(GpuPanel, SW_SHOW); @@ -633,11 +633,11 @@ VOID EtpUpdateGpuPanel( VOID ) { - SetDlgItemText(GpuPanel, IDC_ZDEDICATEDCURRENT_V, PhaFormatSize(EtGpuDedicatedUsage, -1)->Buffer); - SetDlgItemText(GpuPanel, IDC_ZDEDICATEDLIMIT_V, PhaFormatSize(EtGpuDedicatedLimit, -1)->Buffer); + PhSetDialogItemText(GpuPanel, IDC_ZDEDICATEDCURRENT_V, PhaFormatSize(EtGpuDedicatedUsage, -1)->Buffer); + PhSetDialogItemText(GpuPanel, IDC_ZDEDICATEDLIMIT_V, PhaFormatSize(EtGpuDedicatedLimit, -1)->Buffer); - SetDlgItemText(GpuPanel, IDC_ZSHAREDCURRENT_V, PhaFormatSize(EtGpuSharedUsage, -1)->Buffer); - SetDlgItemText(GpuPanel, IDC_ZSHAREDLIMIT_V, PhaFormatSize(EtGpuSharedLimit, -1)->Buffer); + PhSetDialogItemText(GpuPanel, IDC_ZSHAREDCURRENT_V, PhaFormatSize(EtGpuSharedUsage, -1)->Buffer); + PhSetDialogItemText(GpuPanel, IDC_ZSHAREDLIMIT_V, PhaFormatSize(EtGpuSharedLimit, -1)->Buffer); } PPH_PROCESS_RECORD EtpReferenceMaxNodeRecord( diff --git a/plugins/ExtendedTools/modsrv.c b/plugins/ExtendedTools/modsrv.c index 654578396009..b53b3133764b 100644 --- a/plugins/ExtendedTools/modsrv.c +++ b/plugins/ExtendedTools/modsrv.c @@ -152,7 +152,7 @@ INT_PTR CALLBACK EtpModuleServicesDlgProc( message = PhFormatString(L"Services referencing %s:", context->ModuleName); } - SetDlgItemText(hwndDlg, IDC_MESSAGE, message->Buffer); + PhSetDialogItemText(hwndDlg, IDC_MESSAGE, message->Buffer); PhDereferenceObject(message); } break; diff --git a/plugins/ExtendedTools/objprp.c b/plugins/ExtendedTools/objprp.c index a8a74121ecfe..5f65f10badcc 100644 --- a/plugins/ExtendedTools/objprp.c +++ b/plugins/ExtendedTools/objprp.c @@ -215,10 +215,10 @@ INT_PTR CALLBACK EtpAlpcPortPageDlgProc( format[1].Type |= FormatGroupDigits; string = PhFormat(format, 2, 128); - SetDlgItemText(hwndDlg, IDC_SEQUENCENUMBER, string->Buffer); + PhSetDialogItemText(hwndDlg, IDC_SEQUENCENUMBER, string->Buffer); PhDereferenceObject(string); - SetDlgItemText(hwndDlg, IDC_PORTCONTEXT, + PhSetDialogItemText(hwndDlg, IDC_PORTCONTEXT, PhaFormatString(L"Port Context: 0x%Ix", basicInfo.PortContext)->Buffer); } @@ -291,17 +291,17 @@ INT_PTR CALLBACK EtpTpWorkerFactoryPageDlgProc( if (symbol) { - SetDlgItemText(hwndDlg, IDC_WORKERTHREADSTART, + PhSetDialogItemText(hwndDlg, IDC_WORKERTHREADSTART, PhaFormatString(L"Worker Thread Start: %s", symbol->Buffer)->Buffer); PhDereferenceObject(symbol); } else { - SetDlgItemText(hwndDlg, IDC_WORKERTHREADSTART, + PhSetDialogItemText(hwndDlg, IDC_WORKERTHREADSTART, PhaFormatString(L"Worker Thread Start: 0x%Ix", basicInfo.StartRoutine)->Buffer); } - SetDlgItemText(hwndDlg, IDC_WORKERTHREADCONTEXT, + PhSetDialogItemText(hwndDlg, IDC_WORKERTHREADCONTEXT, PhaFormatString(L"Worker Thread Context: 0x%Ix", basicInfo.StartParameter)->Buffer); } diff --git a/plugins/HardwareDevices/diskgraph.c b/plugins/HardwareDevices/diskgraph.c index bc25e20236aa..571e27465c3c 100644 --- a/plugins/HardwareDevices/diskgraph.c +++ b/plugins/HardwareDevices/diskgraph.c @@ -38,17 +38,17 @@ VOID DiskDriveUpdatePanel( _Inout_ PDV_DISK_SYSINFO_CONTEXT Context ) { - SetDlgItemText(Context->PanelWindowHandle, IDC_STAT_BREAD, PhaFormatSize(Context->DiskEntry->BytesReadDelta.Value, -1)->Buffer); - SetDlgItemText(Context->PanelWindowHandle, IDC_STAT_BWRITE, PhaFormatSize(Context->DiskEntry->BytesWrittenDelta.Value, -1)->Buffer); - SetDlgItemText(Context->PanelWindowHandle, IDC_STAT_BTOTAL, PhaFormatSize(Context->DiskEntry->BytesReadDelta.Value + Context->DiskEntry->BytesWrittenDelta.Value, -1)->Buffer); + PhSetDialogItemText(Context->PanelWindowHandle, IDC_STAT_BREAD, PhaFormatSize(Context->DiskEntry->BytesReadDelta.Value, -1)->Buffer); + PhSetDialogItemText(Context->PanelWindowHandle, IDC_STAT_BWRITE, PhaFormatSize(Context->DiskEntry->BytesWrittenDelta.Value, -1)->Buffer); + PhSetDialogItemText(Context->PanelWindowHandle, IDC_STAT_BTOTAL, PhaFormatSize(Context->DiskEntry->BytesReadDelta.Value + Context->DiskEntry->BytesWrittenDelta.Value, -1)->Buffer); - SetDlgItemText(Context->PanelWindowHandle, IDC_STAT_ACTIVE, + PhSetDialogItemText(Context->PanelWindowHandle, IDC_STAT_ACTIVE, PhaFormatString(L"%.0f%%", Context->DiskEntry->ActiveTime)->Buffer ); - SetDlgItemText(Context->PanelWindowHandle, IDC_STAT_RESPONSETIME, + PhSetDialogItemText(Context->PanelWindowHandle, IDC_STAT_RESPONSETIME, PhaFormatString(L"%.1f ms", Context->DiskEntry->ResponseTime / PH_TICKS_PER_MS)->Buffer ); - SetDlgItemText(Context->PanelWindowHandle, IDC_STAT_QUEUELENGTH, + PhSetDialogItemText(Context->PanelWindowHandle, IDC_STAT_QUEUELENGTH, PhaFormatString(L"%lu", Context->DiskEntry->QueueDepth)->Buffer ); } @@ -58,14 +58,14 @@ VOID UpdateDiskDriveDialog( ) { if (!PhIsNullOrEmptyString(Context->DiskEntry->DiskName)) - SetDlgItemText(Context->WindowHandle, IDC_DISKNAME, PhGetString(Context->DiskEntry->DiskName)); + PhSetDialogItemText(Context->WindowHandle, IDC_DISKNAME, PhGetString(Context->DiskEntry->DiskName)); else - SetDlgItemText(Context->WindowHandle, IDC_DISKNAME, L"Unknown disk"); + PhSetDialogItemText(Context->WindowHandle, IDC_DISKNAME, L"Unknown disk"); if (!PhIsNullOrEmptyString(Context->DiskEntry->DiskIndexName)) - SetDlgItemText(Context->WindowHandle, IDC_DISKMOUNTPATH, PhGetString(Context->DiskEntry->DiskIndexName)); + PhSetDialogItemText(Context->WindowHandle, IDC_DISKMOUNTPATH, PhGetString(Context->DiskEntry->DiskIndexName)); else - SetDlgItemText(Context->WindowHandle, IDC_DISKMOUNTPATH, L"Unknown disk"); + PhSetDialogItemText(Context->WindowHandle, IDC_DISKMOUNTPATH, L"Unknown disk"); DiskDriveUpdateGraphs(Context); DiskDriveUpdatePanel(Context); @@ -205,14 +205,14 @@ INT_PTR CALLBACK DiskDriveDialogProc( SendMessage(GetDlgItem(hwndDlg, IDC_DISKNAME), WM_SETFONT, (WPARAM)context->SysinfoSection->Parameters->MediumFont, FALSE); if (context->DiskEntry->DiskIndexName) - SetDlgItemText(hwndDlg, IDC_DISKMOUNTPATH, context->DiskEntry->DiskIndexName->Buffer); + PhSetDialogItemText(hwndDlg, IDC_DISKMOUNTPATH, context->DiskEntry->DiskIndexName->Buffer); else - SetDlgItemText(hwndDlg, IDC_DISKMOUNTPATH, L"Unknown disk"); + PhSetDialogItemText(hwndDlg, IDC_DISKMOUNTPATH, L"Unknown disk"); if (context->DiskEntry->DiskName) - SetDlgItemText(hwndDlg, IDC_DISKNAME, context->DiskEntry->DiskName->Buffer); + PhSetDialogItemText(hwndDlg, IDC_DISKNAME, context->DiskEntry->DiskName->Buffer); else - SetDlgItemText(hwndDlg, IDC_DISKNAME, L"Unknown disk"); + PhSetDialogItemText(hwndDlg, IDC_DISKNAME, L"Unknown disk"); context->PanelWindowHandle = CreateDialogParam(PluginInstance->DllBase, MAKEINTRESOURCE(IDD_DISKDRIVE_PANEL), hwndDlg, DiskDrivePanelDialogProc, (LPARAM)context); ShowWindow(context->PanelWindowHandle, SW_SHOW); diff --git a/plugins/HardwareDevices/netgraph.c b/plugins/HardwareDevices/netgraph.c index 95b1545e2a02..2ed5ad71f9a7 100644 --- a/plugins/HardwareDevices/netgraph.c +++ b/plugins/HardwareDevices/netgraph.c @@ -124,19 +124,19 @@ VOID NetAdapterUpdatePanel( } } - SetDlgItemText(Context->PanelWindowHandle, IDC_STAT_BSENT, PhaFormatSize(outOctetsValue, -1)->Buffer); - SetDlgItemText(Context->PanelWindowHandle, IDC_STAT_BRECEIVED, PhaFormatSize(inOctetsValue, -1)->Buffer); - SetDlgItemText(Context->PanelWindowHandle, IDC_STAT_BTOTAL, PhaFormatSize(inOctetsValue + outOctetsValue, -1)->Buffer); + PhSetDialogItemText(Context->PanelWindowHandle, IDC_STAT_BSENT, PhaFormatSize(outOctetsValue, -1)->Buffer); + PhSetDialogItemText(Context->PanelWindowHandle, IDC_STAT_BRECEIVED, PhaFormatSize(inOctetsValue, -1)->Buffer); + PhSetDialogItemText(Context->PanelWindowHandle, IDC_STAT_BTOTAL, PhaFormatSize(inOctetsValue + outOctetsValue, -1)->Buffer); if (mediaState == MediaConnectStateConnected) { - SetDlgItemText(Context->PanelWindowHandle, IDC_LINK_STATE, L"Connected"); - SetDlgItemText(Context->PanelWindowHandle, IDC_LINK_SPEED, PhaFormatString(L"%s/s", PhaFormatSize(linkSpeedValue / BITS_IN_ONE_BYTE, -1)->Buffer)->Buffer); + PhSetDialogItemText(Context->PanelWindowHandle, IDC_LINK_STATE, L"Connected"); + PhSetDialogItemText(Context->PanelWindowHandle, IDC_LINK_SPEED, PhaFormatString(L"%s/s", PhaFormatSize(linkSpeedValue / BITS_IN_ONE_BYTE, -1)->Buffer)->Buffer); } else { - SetDlgItemText(Context->PanelWindowHandle, IDC_LINK_STATE, L"Disconnected"); - SetDlgItemText(Context->PanelWindowHandle, IDC_LINK_SPEED, L"N/A"); + PhSetDialogItemText(Context->PanelWindowHandle, IDC_LINK_STATE, L"Disconnected"); + PhSetDialogItemText(Context->PanelWindowHandle, IDC_LINK_SPEED, L"N/A"); } } @@ -145,9 +145,9 @@ VOID UpdateNetAdapterDialog( ) { if (Context->AdapterEntry->AdapterName) - SetDlgItemText(Context->WindowHandle, IDC_ADAPTERNAME, Context->AdapterEntry->AdapterName->Buffer); + PhSetDialogItemText(Context->WindowHandle, IDC_ADAPTERNAME, Context->AdapterEntry->AdapterName->Buffer); else - SetDlgItemText(Context->WindowHandle, IDC_ADAPTERNAME, L"Unknown network adapter"); + PhSetDialogItemText(Context->WindowHandle, IDC_ADAPTERNAME, L"Unknown network adapter"); NetAdapterUpdateGraphs(Context); NetAdapterUpdatePanel(Context); @@ -254,9 +254,9 @@ INT_PTR CALLBACK NetAdapterDialogProc( SendMessage(GetDlgItem(hwndDlg, IDC_ADAPTERNAME), WM_SETFONT, (WPARAM)context->SysinfoSection->Parameters->LargeFont, FALSE); if (context->AdapterEntry->AdapterName) - SetDlgItemText(hwndDlg, IDC_ADAPTERNAME, context->AdapterEntry->AdapterName->Buffer); + PhSetDialogItemText(hwndDlg, IDC_ADAPTERNAME, context->AdapterEntry->AdapterName->Buffer); else - SetDlgItemText(hwndDlg, IDC_ADAPTERNAME, L"Unknown network adapter"); + PhSetDialogItemText(hwndDlg, IDC_ADAPTERNAME, L"Unknown network adapter"); context->PanelWindowHandle = CreateDialogParam(PluginInstance->DllBase, MAKEINTRESOURCE(IDD_NETADAPTER_PANEL), hwndDlg, NetAdapterPanelDialogProc, (LPARAM)context); ShowWindow(context->PanelWindowHandle, SW_SHOW); diff --git a/plugins/HardwareDevices/prpsh.c b/plugins/HardwareDevices/prpsh.c index 9da89afa7c3d..5d27248dcb04 100644 --- a/plugins/HardwareDevices/prpsh.c +++ b/plugins/HardwareDevices/prpsh.c @@ -255,7 +255,7 @@ BOOLEAN PhpInitializePropSheetLayoutStage1( // Hide the OK button. ShowWindow(GetDlgItem(hwnd, IDOK), SW_HIDE); // Set the Cancel button's text to "Close". - SetDlgItemText(hwnd, IDCANCEL, L"Close"); + PhSetDialogItemText(hwnd, IDCANCEL, L"Close"); PhLoadWindowPlacementFromSetting(SETTING_NAME_DISK_POSITION, SETTING_NAME_DISK_SIZE, hwnd); diff --git a/plugins/NetworkTools/options.c b/plugins/NetworkTools/options.c index abe24349106e..1bdf98da77cb 100644 --- a/plugins/NetworkTools/options.c +++ b/plugins/NetworkTools/options.c @@ -34,15 +34,15 @@ INT_PTR CALLBACK OptionsDlgProc( { case WM_INITDIALOG: { - SetDlgItemInt(hwndDlg, IDC_PINGPACKETLENGTH, PhGetIntegerSetting(SETTING_NAME_PING_SIZE), FALSE); - SetDlgItemInt(hwndDlg, IDC_MAXHOPS, PhGetIntegerSetting(SETTING_NAME_TRACERT_MAX_HOPS), FALSE); + PhSetDialogItemValue(hwndDlg, IDC_PINGPACKETLENGTH, PhGetIntegerSetting(SETTING_NAME_PING_SIZE), FALSE); + PhSetDialogItemValue(hwndDlg, IDC_MAXHOPS, PhGetIntegerSetting(SETTING_NAME_TRACERT_MAX_HOPS), FALSE); Button_SetCheck(GetDlgItem(hwndDlg, IDC_ENABLE_EXTENDED_TCP), PhGetIntegerSetting(SETTING_NAME_EXTENDED_TCP_STATS) ? BST_CHECKED : BST_UNCHECKED); } break; case WM_DESTROY: { - PhSetIntegerSetting(SETTING_NAME_PING_SIZE, GetDlgItemInt(hwndDlg, IDC_PINGPACKETLENGTH, NULL, FALSE)); - PhSetIntegerSetting(SETTING_NAME_TRACERT_MAX_HOPS, GetDlgItemInt(hwndDlg, IDC_MAXHOPS, NULL, FALSE)); + PhSetIntegerSetting(SETTING_NAME_PING_SIZE, PhGetDialogItemValue(hwndDlg, IDC_PINGPACKETLENGTH)); + PhSetIntegerSetting(SETTING_NAME_TRACERT_MAX_HOPS, PhGetDialogItemValue(hwndDlg, IDC_MAXHOPS)); PhSetIntegerSetting(SETTING_NAME_EXTENDED_TCP_STATS, Button_GetCheck(GetDlgItem(hwndDlg, IDC_ENABLE_EXTENDED_TCP)) == BST_CHECKED); } break; diff --git a/plugins/NetworkTools/ping.c b/plugins/NetworkTools/ping.c index 2dab53790826..e69ab3e28e87 100644 --- a/plugins/NetworkTools/ping.c +++ b/plugins/NetworkTools/ping.c @@ -410,22 +410,22 @@ INT_PTR CALLBACK NetworkPingWndProc( pingAvgValue = maxGraphHeight / context->PingHistory.Count; } - SetDlgItemText(hwndDlg, IDC_ICMP_AVG, PhaFormatString( + PhSetDialogItemText(hwndDlg, IDC_ICMP_AVG, PhaFormatString( L"Average: %lums", pingAvgValue)->Buffer); - SetDlgItemText(hwndDlg, IDC_ICMP_MIN, PhaFormatString( + PhSetDialogItemText(hwndDlg, IDC_ICMP_MIN, PhaFormatString( L"Minimum: %lums", context->PingMinMs)->Buffer); - SetDlgItemText(hwndDlg, IDC_ICMP_MAX, PhaFormatString( + PhSetDialogItemText(hwndDlg, IDC_ICMP_MAX, PhaFormatString( L"Maximum: %lums", context->PingMaxMs)->Buffer); - SetDlgItemText(hwndDlg, IDC_PINGS_SENT, PhaFormatString( + PhSetDialogItemText(hwndDlg, IDC_PINGS_SENT, PhaFormatString( L"Pings sent: %lu", context->PingSentCount)->Buffer); - SetDlgItemText(hwndDlg, IDC_PINGS_LOST, PhaFormatString( + PhSetDialogItemText(hwndDlg, IDC_PINGS_LOST, PhaFormatString( L"Pings lost: %lu (%.0f%%)", context->PingLossCount, ((FLOAT)context->PingLossCount / context->PingSentCount * 100))->Buffer); - //SetDlgItemText(hwndDlg, IDC_BAD_HASH, PhaFormatString( + //PhSetDialogItemText(hwndDlg, IDC_BAD_HASH, PhaFormatString( // L"Bad hashes: %lu", context->HashFailCount)->Buffer); - SetDlgItemText(hwndDlg, IDC_ANON_ADDR, PhaFormatString( + PhSetDialogItemText(hwndDlg, IDC_ANON_ADDR, PhaFormatString( L"Anon replies: %lu", context->UnknownAddrCount)->Buffer); } break; diff --git a/plugins/ToolStatus/customizesb.c b/plugins/ToolStatus/customizesb.c index 680eb6b368cb..2c2a8421f594 100644 --- a/plugins/ToolStatus/customizesb.c +++ b/plugins/ToolStatus/customizesb.c @@ -315,7 +315,7 @@ INT_PTR CALLBACK CustomizeStatusBarDialogProc( CustomizeLoadStatusBarItems(context); - SendMessage(context->DialogHandle, WM_NEXTDLGCTL, (WPARAM)context->CurrentListHandle, TRUE); + PhSetDialogFocus(context->DialogHandle, context->CurrentListHandle); } break; case WM_DESTROY: diff --git a/plugins/ToolStatus/customizetb.c b/plugins/ToolStatus/customizetb.c index 1b7c48c04547..259b2e21325f 100644 --- a/plugins/ToolStatus/customizetb.c +++ b/plugins/ToolStatus/customizetb.c @@ -532,7 +532,7 @@ INT_PTR CALLBACK CustomizeToolbarDialogProc( CustomizeLoadToolbarItems(context); CustomizeLoadToolbarSettings(context); - SendMessage(context->DialogHandle, WM_NEXTDLGCTL, (WPARAM)context->CurrentListHandle, TRUE); + PhSetDialogFocus(context->DialogHandle, context->CurrentListHandle); } break; case WM_DESTROY: diff --git a/plugins/Updater/options.c b/plugins/Updater/options.c index 94879202df92..2c71b40d4f82 100644 --- a/plugins/Updater/options.c +++ b/plugins/Updater/options.c @@ -86,7 +86,7 @@ INT_PTR CALLBACK TextDlgProc( else PhCenterWindow(hwndDlg, GetParent(hwndDlg)); - SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hwndDlg, IDCANCEL), TRUE); + PhSetDialogFocus(hwndDlg, GetDlgItem(hwndDlg, IDCANCEL)); } break; case WM_DESTROY: diff --git a/plugins/UserNotes/main.c b/plugins/UserNotes/main.c index 05cfa44a0138..57f01835f85d 100644 --- a/plugins/UserNotes/main.c +++ b/plugins/UserNotes/main.c @@ -1527,14 +1527,13 @@ INT_PTR CALLBACK OptionsDlgProc( { case WM_INITDIALOG: { - SetDlgItemText(hwndDlg, IDC_DATABASE, PhaGetStringSetting(SETTING_NAME_DATABASE_PATH)->Buffer); + PhSetDialogItemText(hwndDlg, IDC_DATABASE, PhaGetStringSetting(SETTING_NAME_DATABASE_PATH)->Buffer); PhInitializeLayoutManager(&LayoutManager, hwndDlg); PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDC_DATABASE), NULL, PH_ANCHOR_TOP | PH_ANCHOR_LEFT | PH_ANCHOR_RIGHT); PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDC_BROWSE), NULL, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); - SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hwndDlg, IDCANCEL), TRUE); - + PhSetDialogFocus(hwndDlg, GetDlgItem(hwndDlg, IDCANCEL)); } break; case WM_DESTROY: @@ -1572,7 +1571,7 @@ INT_PTR CALLBACK OptionsDlgProc( if (PhShowFileDialog(hwndDlg, fileDialog)) { fileName = PH_AUTO(PhGetFileDialogFileName(fileDialog)); - SetDlgItemText(hwndDlg, IDC_DATABASE, fileName->Buffer); + PhSetDialogItemText(hwndDlg, IDC_DATABASE, fileName->Buffer); } PhFreeFileDialog(fileDialog); @@ -1763,7 +1762,7 @@ INT_PTR CALLBACK ProcessCommentPageDlgProc( { Edit_SetText(context->CommentHandle, context->OriginalComment->Buffer); SendMessage(context->CommentHandle, EM_SETSEL, 0, -1); - SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)context->CommentHandle, TRUE); + PhSetDialogFocus(hwndDlg, context->CommentHandle); EnableWindow(context->RevertHandle, FALSE); } break; @@ -1843,7 +1842,7 @@ INT_PTR CALLBACK ServiceCommentPageDlgProc( UnlockDb(); - SetDlgItemText(hwndDlg, IDC_COMMENT, comment->Buffer); + PhSetDialogItemText(hwndDlg, IDC_COMMENT, comment->Buffer); EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); } diff --git a/plugins/WindowExplorer/wnddlg.c b/plugins/WindowExplorer/wnddlg.c index f10007c9cc2b..645b4d12acdf 100644 --- a/plugins/WindowExplorer/wnddlg.c +++ b/plugins/WindowExplorer/wnddlg.c @@ -377,7 +377,8 @@ INT_PTR CALLBACK WepWindowsDlgProc( WepRefreshWindows(context); - SendMessage(GetParent(hwndDlg), WM_NEXTDLGCTL, (WPARAM)GetDlgItem(GetParent(hwndDlg), IDCANCEL), TRUE); + // HACK + PhSetDialogFocus(GetParent(hwndDlg), GetDlgItem(GetParent(hwndDlg), IDCANCEL)); } break; case WM_DESTROY: diff --git a/plugins/WindowExplorer/wndprp.c b/plugins/WindowExplorer/wndprp.c index 8c6aabc94e8e..234540002f4b 100644 --- a/plugins/WindowExplorer/wndprp.c +++ b/plugins/WindowExplorer/wndprp.c @@ -365,7 +365,7 @@ static INT CALLBACK WepPropSheetProc( // Hide the Cancel button. ShowWindow(GetDlgItem(hwndDlg, IDCANCEL), SW_HIDE); // Set the OK button's text to "Close". - SetDlgItemText(hwndDlg, IDOK, L"Close"); + PhSetDialogItemText(hwndDlg, IDOK, L"Close"); // Add the Refresh button. refreshButtonHandle = CreateWindow(L"BUTTON", L"Refresh", WS_CHILD | WS_TABSTOP | WS_VISIBLE, 0, 0, 3, 3, hwndDlg, (HMENU)IDC_REFRESH, PluginInstance->DllBase, NULL); @@ -741,24 +741,24 @@ static VOID WepRefreshWindowGeneralInfoSymbols( ) { if (Context->WndProcResolving != 0) - SetDlgItemText(hwndDlg, IDC_WINDOWPROC, PhaFormatString(L"0x%Ix (resolving...)", Context->WndProc)->Buffer); + PhSetDialogItemText(hwndDlg, IDC_WINDOWPROC, PhaFormatString(L"0x%Ix (resolving...)", Context->WndProc)->Buffer); else if (Context->WndProcSymbol) - SetDlgItemText(hwndDlg, IDC_WINDOWPROC, PhaFormatString(L"0x%Ix (%s)", Context->WndProc, Context->WndProcSymbol->Buffer)->Buffer); + PhSetDialogItemText(hwndDlg, IDC_WINDOWPROC, PhaFormatString(L"0x%Ix (%s)", Context->WndProc, Context->WndProcSymbol->Buffer)->Buffer); else if (Context->WndProc != 0) - SetDlgItemText(hwndDlg, IDC_WINDOWPROC, PhaFormatString(L"0x%Ix", Context->WndProc)->Buffer); + PhSetDialogItemText(hwndDlg, IDC_WINDOWPROC, PhaFormatString(L"0x%Ix", Context->WndProc)->Buffer); else - SetDlgItemText(hwndDlg, IDC_WINDOWPROC, L"Unknown"); + PhSetDialogItemText(hwndDlg, IDC_WINDOWPROC, L"Unknown"); if (Context->DlgProcResolving != 0) - SetDlgItemText(hwndDlg, IDC_DIALOGPROC, PhaFormatString(L"0x%Ix (resolving...)", Context->DlgProc)->Buffer); + PhSetDialogItemText(hwndDlg, IDC_DIALOGPROC, PhaFormatString(L"0x%Ix (resolving...)", Context->DlgProc)->Buffer); else if (Context->DlgProcSymbol) - SetDlgItemText(hwndDlg, IDC_DIALOGPROC, PhaFormatString(L"0x%Ix (%s)", Context->DlgProc, Context->DlgProcSymbol->Buffer)->Buffer); + PhSetDialogItemText(hwndDlg, IDC_DIALOGPROC, PhaFormatString(L"0x%Ix (%s)", Context->DlgProc, Context->DlgProcSymbol->Buffer)->Buffer); else if (Context->DlgProc != 0) - SetDlgItemText(hwndDlg, IDC_DIALOGPROC, PhaFormatString(L"0x%Ix", Context->DlgProc)->Buffer); + PhSetDialogItemText(hwndDlg, IDC_DIALOGPROC, PhaFormatString(L"0x%Ix", Context->DlgProc)->Buffer); else if (Context->WndProc != 0) - SetDlgItemText(hwndDlg, IDC_DIALOGPROC, L"N/A"); + PhSetDialogItemText(hwndDlg, IDC_DIALOGPROC, L"N/A"); else - SetDlgItemText(hwndDlg, IDC_DIALOGPROC, L"Unknown"); + PhSetDialogItemText(hwndDlg, IDC_DIALOGPROC, L"Unknown"); } static VOID WepRefreshWindowGeneralInfo( @@ -770,18 +770,18 @@ static VOID WepRefreshWindowGeneralInfo( WINDOWPLACEMENT windowPlacement = { sizeof(WINDOWPLACEMENT) }; MONITORINFO monitorInfo = { sizeof(MONITORINFO) }; - SetDlgItemText(hwndDlg, IDC_THREAD, PH_AUTO_T(PH_STRING, PhGetClientIdName(&Context->ClientId))->Buffer); - SetDlgItemText(hwndDlg, IDC_TEXT, PhGetStringOrEmpty(PH_AUTO(PhGetWindowText(Context->WindowHandle)))); + PhSetDialogItemText(hwndDlg, IDC_THREAD, PH_AUTO_T(PH_STRING, PhGetClientIdName(&Context->ClientId))->Buffer); + PhSetDialogItemText(hwndDlg, IDC_TEXT, PhGetStringOrEmpty(PH_AUTO(PhGetWindowText(Context->WindowHandle)))); if (GetWindowInfo(Context->WindowHandle, &windowInfo)) { - SetDlgItemText(hwndDlg, IDC_RECTANGLE, WepFormatRect(&windowInfo.rcWindow)->Buffer); - SetDlgItemText(hwndDlg, IDC_CLIENTRECTANGLE, WepFormatRect(&windowInfo.rcClient)->Buffer); + PhSetDialogItemText(hwndDlg, IDC_RECTANGLE, WepFormatRect(&windowInfo.rcWindow)->Buffer); + PhSetDialogItemText(hwndDlg, IDC_CLIENTRECTANGLE, WepFormatRect(&windowInfo.rcClient)->Buffer); } else { - SetDlgItemText(hwndDlg, IDC_RECTANGLE, L"N/A"); - SetDlgItemText(hwndDlg, IDC_CLIENTRECTANGLE, L"N/A"); + PhSetDialogItemText(hwndDlg, IDC_RECTANGLE, L"N/A"); + PhSetDialogItemText(hwndDlg, IDC_CLIENTRECTANGLE, L"N/A"); } if (GetWindowPlacement(Context->WindowHandle, &windowPlacement)) @@ -795,18 +795,18 @@ static VOID WepRefreshWindowGeneralInfo( windowPlacement.rcNormalPosition.bottom += monitorInfo.rcWork.top; } - SetDlgItemText(hwndDlg, IDC_NORMALRECTANGLE, WepFormatRect(&windowPlacement.rcNormalPosition)->Buffer); + PhSetDialogItemText(hwndDlg, IDC_NORMALRECTANGLE, WepFormatRect(&windowPlacement.rcNormalPosition)->Buffer); } else { - SetDlgItemText(hwndDlg, IDC_NORMALRECTANGLE, L"N/A"); + PhSetDialogItemText(hwndDlg, IDC_NORMALRECTANGLE, L"N/A"); } - SetDlgItemText(hwndDlg, IDC_INSTANCEHANDLE, PhaFormatString(L"0x%Ix", GetWindowLongPtr(Context->WindowHandle, GWLP_HINSTANCE))->Buffer); - SetDlgItemText(hwndDlg, IDC_MENUHANDLE, PhaFormatString(L"0x%Ix", GetMenu(Context->WindowHandle))->Buffer); - SetDlgItemText(hwndDlg, IDC_USERDATA, PhaFormatString(L"0x%Ix", GetWindowLongPtr(Context->WindowHandle, GWLP_USERDATA))->Buffer); - SetDlgItemText(hwndDlg, IDC_UNICODE, IsWindowUnicode(Context->WindowHandle) ? L"Yes" : L"No"); - SetDlgItemText(hwndDlg, IDC_CTRLID, PhaFormatString(L"%lu", GetWindowLongPtr(Context->WindowHandle, GWLP_ID))->Buffer); + PhSetDialogItemText(hwndDlg, IDC_INSTANCEHANDLE, PhaFormatString(L"0x%Ix", GetWindowLongPtr(Context->WindowHandle, GWLP_HINSTANCE))->Buffer); + PhSetDialogItemText(hwndDlg, IDC_MENUHANDLE, PhaFormatString(L"0x%Ix", GetMenu(Context->WindowHandle))->Buffer); + PhSetDialogItemText(hwndDlg, IDC_USERDATA, PhaFormatString(L"0x%Ix", GetWindowLongPtr(Context->WindowHandle, GWLP_USERDATA))->Buffer); + PhSetDialogItemText(hwndDlg, IDC_UNICODE, IsWindowUnicode(Context->WindowHandle) ? L"Yes" : L"No"); + PhSetDialogItemText(hwndDlg, IDC_CTRLID, PhaFormatString(L"%lu", GetWindowLongPtr(Context->WindowHandle, GWLP_ID))->Buffer); WepEnsureHookDataValid(Context); @@ -918,8 +918,8 @@ static VOID WepRefreshWindowStyles( if (GetWindowInfo(Context->WindowHandle, &windowInfo)) { - SetDlgItemText(hwndDlg, IDC_STYLES, PhaFormatString(L"0x%x", windowInfo.dwStyle)->Buffer); - SetDlgItemText(hwndDlg, IDC_EXTENDEDSTYLES, PhaFormatString(L"0x%x", windowInfo.dwExStyle)->Buffer); + PhSetDialogItemText(hwndDlg, IDC_STYLES, PhaFormatString(L"0x%x", windowInfo.dwStyle)->Buffer); + PhSetDialogItemText(hwndDlg, IDC_EXTENDEDSTYLES, PhaFormatString(L"0x%x", windowInfo.dwExStyle)->Buffer); for (i = 0; i < sizeof(WepStylePairs) / sizeof(STRING_INTEGER_PAIR); i++) { @@ -955,8 +955,8 @@ static VOID WepRefreshWindowStyles( } else { - SetDlgItemText(hwndDlg, IDC_STYLES, L"N/A"); - SetDlgItemText(hwndDlg, IDC_EXTENDEDSTYLES, L"N/A"); + PhSetDialogItemText(hwndDlg, IDC_STYLES, L"N/A"); + PhSetDialogItemText(hwndDlg, IDC_EXTENDEDSTYLES, L"N/A"); } } @@ -1000,13 +1000,13 @@ static VOID WepRefreshWindowClassInfoSymbols( ) { if (Context->ClassWndProcResolving != 0) - SetDlgItemText(hwndDlg, IDC_WINDOWPROC, PhaFormatString(L"0x%Ix (resolving...)", Context->ClassInfo.lpfnWndProc)->Buffer); + PhSetDialogItemText(hwndDlg, IDC_WINDOWPROC, PhaFormatString(L"0x%Ix (resolving...)", Context->ClassInfo.lpfnWndProc)->Buffer); else if (Context->ClassWndProcSymbol) - SetDlgItemText(hwndDlg, IDC_WINDOWPROC, PhaFormatString(L"0x%Ix (%s)", Context->ClassInfo.lpfnWndProc, Context->ClassWndProcSymbol->Buffer)->Buffer); + PhSetDialogItemText(hwndDlg, IDC_WINDOWPROC, PhaFormatString(L"0x%Ix (%s)", Context->ClassInfo.lpfnWndProc, Context->ClassWndProcSymbol->Buffer)->Buffer); else if (Context->ClassInfo.lpfnWndProc) - SetDlgItemText(hwndDlg, IDC_WINDOWPROC, PhaFormatString(L"0x%Ix", Context->ClassInfo.lpfnWndProc)->Buffer); + PhSetDialogItemText(hwndDlg, IDC_WINDOWPROC, PhaFormatString(L"0x%Ix", Context->ClassInfo.lpfnWndProc)->Buffer); else - SetDlgItemText(hwndDlg, IDC_WINDOWPROC, L"Unknown"); + PhSetDialogItemText(hwndDlg, IDC_WINDOWPROC, L"Unknown"); } static VOID WepRefreshWindowClassInfo( @@ -1029,12 +1029,12 @@ static VOID WepRefreshWindowClassInfo( GetClassInfoEx(NULL, className, &Context->ClassInfo); } - SetDlgItemText(hwndDlg, IDC_NAME, className); - SetDlgItemText(hwndDlg, IDC_ATOM, PhaFormatString(L"0x%x", GetClassWord(Context->WindowHandle, GCW_ATOM))->Buffer); - SetDlgItemText(hwndDlg, IDC_INSTANCEHANDLE, PhaFormatString(L"0x%Ix", GetClassLongPtr(Context->WindowHandle, GCLP_HMODULE))->Buffer); - SetDlgItemText(hwndDlg, IDC_ICONHANDLE, PhaFormatString(L"0x%Ix", Context->ClassInfo.hIcon)->Buffer); - SetDlgItemText(hwndDlg, IDC_SMALLICONHANDLE, PhaFormatString(L"0x%Ix", Context->ClassInfo.hIconSm)->Buffer); - SetDlgItemText(hwndDlg, IDC_MENUNAME, PhaFormatString(L"0x%Ix", Context->ClassInfo.lpszMenuName)->Buffer); + PhSetDialogItemText(hwndDlg, IDC_NAME, className); + PhSetDialogItemText(hwndDlg, IDC_ATOM, PhaFormatString(L"0x%x", GetClassWord(Context->WindowHandle, GCW_ATOM))->Buffer); + PhSetDialogItemText(hwndDlg, IDC_INSTANCEHANDLE, PhaFormatString(L"0x%Ix", GetClassLongPtr(Context->WindowHandle, GCLP_HMODULE))->Buffer); + PhSetDialogItemText(hwndDlg, IDC_ICONHANDLE, PhaFormatString(L"0x%Ix", Context->ClassInfo.hIcon)->Buffer); + PhSetDialogItemText(hwndDlg, IDC_SMALLICONHANDLE, PhaFormatString(L"0x%Ix", Context->ClassInfo.hIconSm)->Buffer); + PhSetDialogItemText(hwndDlg, IDC_MENUNAME, PhaFormatString(L"0x%Ix", Context->ClassInfo.lpszMenuName)->Buffer); PhInitializeStringBuilder(&stringBuilder, 100); PhAppendFormatStringBuilder(&stringBuilder, L"0x%x (", Context->ClassInfo.style); @@ -1059,12 +1059,12 @@ static VOID WepRefreshWindowClassInfo( PhRemoveEndStringBuilder(&stringBuilder, 1); } - SetDlgItemText(hwndDlg, IDC_STYLES, stringBuilder.String->Buffer); + PhSetDialogItemText(hwndDlg, IDC_STYLES, stringBuilder.String->Buffer); PhDeleteStringBuilder(&stringBuilder); // TODO: Add symbols for these values. - SetDlgItemText(hwndDlg, IDC_CURSORHANDLE, PhaFormatString(L"0x%Ix", Context->ClassInfo.hCursor)->Buffer); - SetDlgItemText(hwndDlg, IDC_BACKGROUNDBRUSH, PhaFormatString(L"0x%Ix", Context->ClassInfo.hbrBackground)->Buffer); + PhSetDialogItemText(hwndDlg, IDC_CURSORHANDLE, PhaFormatString(L"0x%Ix", Context->ClassInfo.hCursor)->Buffer); + PhSetDialogItemText(hwndDlg, IDC_BACKGROUNDBRUSH, PhaFormatString(L"0x%Ix", Context->ClassInfo.hbrBackground)->Buffer); if (Context->ClassInfo.lpfnWndProc) { diff --git a/tools/peview/clrprp.c b/tools/peview/clrprp.c index 8584c433bdb2..7ef8491697a1 100644 --- a/tools/peview/clrprp.c +++ b/tools/peview/clrprp.c @@ -89,7 +89,7 @@ INT_PTR CALLBACK PvpPeClrDlgProc( L"%u.%u", PvImageCor20Header->MajorRuntimeVersion, PvImageCor20Header->MinorRuntimeVersion); - SetDlgItemText(hwndDlg, IDC_RUNTIMEVERSION, string->Buffer); + PhSetDialogItemText(hwndDlg, IDC_RUNTIMEVERSION, string->Buffer); PhInitializeStringBuilder(&stringBuilder, 256); @@ -118,7 +118,7 @@ INT_PTR CALLBACK PvpPeClrDlgProc( if (PhEndsWithString2(stringBuilder.String, L", ", FALSE)) PhRemoveEndStringBuilder(&stringBuilder, 2); - SetDlgItemText(hwndDlg, IDC_FLAGS, stringBuilder.String->Buffer); + PhSetDialogItemText(hwndDlg, IDC_FLAGS, stringBuilder.String->Buffer); PhDeleteStringBuilder(&stringBuilder); metaData = PhMappedImageRvaToVa(&PvMappedImage, PvImageCor20Header->MetaData.VirtualAddress, NULL); @@ -138,7 +138,7 @@ INT_PTR CALLBACK PvpPeClrDlgProc( if (metaData && metaData->VersionLength != 0) { string = PhZeroExtendToUtf16Ex((PCHAR)metaData->VersionString, metaData->VersionLength); - SetDlgItemText(hwndDlg, IDC_VERSIONSTRING, string->Buffer); + PhSetDialogItemText(hwndDlg, IDC_VERSIONSTRING, string->Buffer); PhDereferenceObject(string); { @@ -175,7 +175,7 @@ INT_PTR CALLBACK PvpPeClrDlgProc( } else { - SetDlgItemText(hwndDlg, IDC_VERSIONSTRING, L"N/A"); + PhSetDialogItemText(hwndDlg, IDC_VERSIONSTRING, L"N/A"); } } break; diff --git a/tools/peview/exlfprp.c b/tools/peview/exlfprp.c index d9e67e3a0cf4..96deadeae353 100644 --- a/tools/peview/exlfprp.c +++ b/tools/peview/exlfprp.c @@ -129,7 +129,7 @@ VOID PvpSetWslImageType( break; } - SetDlgItemText(hwndDlg, IDC_IMAGETYPE, type); + PhSetDialogItemText(hwndDlg, IDC_IMAGETYPE, type); } VOID PvpSetWslImageMachineType( @@ -151,7 +151,7 @@ VOID PvpSetWslImageMachineType( break; } - SetDlgItemText(hwndDlg, IDC_TARGETMACHINE, type); + PhSetDialogItemText(hwndDlg, IDC_TARGETMACHINE, type); } VOID PvpSetWslImageBase( @@ -163,13 +163,13 @@ VOID PvpSetWslImageBase( if (PvMappedImage.Header->e_ident[EI_CLASS] == ELFCLASS32) { string = PhFormatString(L"0x%I32x", PhGetMappedWslImageBaseAddress(&PvMappedImage)); - SetDlgItemText(hwndDlg, IDC_IMAGEBASE, string->Buffer); + PhSetDialogItemText(hwndDlg, IDC_IMAGEBASE, string->Buffer); PhDereferenceObject(string); } else if (PvMappedImage.Header->e_ident[EI_CLASS] == ELFCLASS64) { string = PhFormatString(L"0x%I64x", PhGetMappedWslImageBaseAddress(&PvMappedImage)); - SetDlgItemText(hwndDlg, IDC_IMAGEBASE, string->Buffer); + PhSetDialogItemText(hwndDlg, IDC_IMAGEBASE, string->Buffer); PhDereferenceObject(string); } } @@ -183,13 +183,13 @@ VOID PvpSetWslEntrypoint( if (PvMappedImage.Header->e_ident[EI_CLASS] == ELFCLASS32) { string = PhFormatString(L"0x%I32x", PvMappedImage.Headers32->e_entry); - SetDlgItemText(hwndDlg, IDC_ENTRYPOINT, string->Buffer); + PhSetDialogItemText(hwndDlg, IDC_ENTRYPOINT, string->Buffer); PhDereferenceObject(string); } else if (PvMappedImage.Header->e_ident[EI_CLASS] == ELFCLASS64) { string = PhFormatString(L"0x%I64x", PvMappedImage.Headers64->e_entry); - SetDlgItemText(hwndDlg, IDC_ENTRYPOINT, string->Buffer); + PhSetDialogItemText(hwndDlg, IDC_ENTRYPOINT, string->Buffer); PhDereferenceObject(string); } } diff --git a/tools/peview/peprp.c b/tools/peview/peprp.c index 7e1e6e24f053..1e2773b3023f 100644 --- a/tools/peview/peprp.c +++ b/tools/peview/peprp.c @@ -390,9 +390,9 @@ VOID PvpSetPeImageVersionInfo( string = PhConcatStrings2(L"(Verifying...) ", PvpGetStringOrNa(PvImageVersionInfo.CompanyName)); - SetDlgItemText(WindowHandle, IDC_NAME, PvpGetStringOrNa(PvImageVersionInfo.FileDescription)); - SetDlgItemText(WindowHandle, IDC_COMPANYNAME, string->Buffer); - SetDlgItemText(WindowHandle, IDC_VERSION, PvpGetStringOrNa(PvImageVersionInfo.FileVersion)); + PhSetDialogItemText(WindowHandle, IDC_NAME, PvpGetStringOrNa(PvImageVersionInfo.FileDescription)); + PhSetDialogItemText(WindowHandle, IDC_COMPANYNAME, string->Buffer); + PhSetDialogItemText(WindowHandle, IDC_VERSION, PvpGetStringOrNa(PvImageVersionInfo.FileVersion)); PhQueueItemWorkQueue(PhGetGlobalWorkQueue(), VerifyImageThreadStart, WindowHandle); @@ -424,7 +424,7 @@ VOID PvpSetPeImageMachineType( break; } - SetDlgItemText(WindowHandle, IDC_TARGETMACHINE, type); + PhSetDialogItemText(WindowHandle, IDC_TARGETMACHINE, type); } VOID PvpSetPeImageTimeStamp( @@ -439,7 +439,7 @@ VOID PvpSetPeImageTimeStamp( PhLargeIntegerToLocalSystemTime(&systemTime, &time); string = PhFormatDateTime(&systemTime); - SetDlgItemText(WindowHandle, IDC_TIMESTAMP, string->Buffer); + PhSetDialogItemText(WindowHandle, IDC_TIMESTAMP, string->Buffer); PhDereferenceObject(string); } @@ -454,7 +454,7 @@ VOID PvpSetPeImageBaseAddress( else string = PhFormatString(L"0x%I64x", ((PIMAGE_OPTIONAL_HEADER64)&PvMappedImage.NtHeaders->OptionalHeader)->ImageBase); - SetDlgItemText(WindowHandle, IDC_IMAGEBASE, string->Buffer); + PhSetDialogItemText(WindowHandle, IDC_IMAGEBASE, string->Buffer); PhDereferenceObject(string); } @@ -469,7 +469,7 @@ VOID PvpSetPeImageEntryPoint( else string = PhFormatString(L"0x%I64x", ((PIMAGE_OPTIONAL_HEADER64)&PvMappedImage.NtHeaders->OptionalHeader)->AddressOfEntryPoint); - SetDlgItemText(WindowHandle, IDC_ENTRYPOINT, string->Buffer); + PhSetDialogItemText(WindowHandle, IDC_ENTRYPOINT, string->Buffer); PhDereferenceObject(string); } @@ -481,7 +481,7 @@ VOID PvpSetPeImageCheckSum( string = PhFormatString(L"0x%Ix (verifying...)", PvMappedImage.NtHeaders->OptionalHeader.CheckSum); // same for 32-bit and 64-bit images - SetDlgItemText(WindowHandle, IDC_CHECKSUM, string->Buffer); + PhSetDialogItemText(WindowHandle, IDC_CHECKSUM, string->Buffer); PhQueueItemWorkQueue(PhGetGlobalWorkQueue(), CheckSumImageThreadStart, WindowHandle); @@ -537,8 +537,8 @@ VOID PvpSetPeImageSubsystem( break; } - SetDlgItemText(WindowHandle, IDC_SUBSYSTEM, type); - SetDlgItemText(WindowHandle, IDC_SUBSYSTEMVERSION, PhaFormatString( + PhSetDialogItemText(WindowHandle, IDC_SUBSYSTEM, type); + PhSetDialogItemText(WindowHandle, IDC_SUBSYSTEMVERSION, PhaFormatString( L"%u.%u", PvMappedImage.NtHeaders->OptionalHeader.MajorSubsystemVersion, // same for 32-bit and 64-bit images PvMappedImage.NtHeaders->OptionalHeader.MinorSubsystemVersion @@ -594,7 +594,7 @@ VOID PvpSetPeImageCharacteristics( if (PhEndsWithString2(stringBuilder.String, L", ", FALSE)) PhRemoveEndStringBuilder(&stringBuilder, 2); - SetDlgItemText(WindowHandle, IDC_CHARACTERISTICS, stringBuilder.String->Buffer); + PhSetDialogItemText(WindowHandle, IDC_CHARACTERISTICS, stringBuilder.String->Buffer); PhDeleteStringBuilder(&stringBuilder); } @@ -715,19 +715,19 @@ INT_PTR CALLBACK PvpPeGeneralDlgProc( { // Some executables, like .NET ones, don't have a check sum. string = PhFormatString(L"0x0 (real 0x%Ix)", realCheckSum); - SetDlgItemText(hwndDlg, IDC_CHECKSUM, string->Buffer); + PhSetDialogItemText(hwndDlg, IDC_CHECKSUM, string->Buffer); PhDereferenceObject(string); } else if (headerCheckSum == realCheckSum) { string = PhFormatString(L"0x%Ix (correct)", headerCheckSum); - SetDlgItemText(hwndDlg, IDC_CHECKSUM, string->Buffer); + PhSetDialogItemText(hwndDlg, IDC_CHECKSUM, string->Buffer); PhDereferenceObject(string); } else { string = PhFormatString(L"0x%Ix (incorrect, real 0x%Ix)", headerCheckSum, realCheckSum); - SetDlgItemText(hwndDlg, IDC_CHECKSUM, string->Buffer); + PhSetDialogItemText(hwndDlg, IDC_CHECKSUM, string->Buffer); PhDereferenceObject(string); } } @@ -741,7 +741,7 @@ INT_PTR CALLBACK PvpPeGeneralDlgProc( if (PvImageSignerName) { string = PhFormatString(L"(Verified) %s", PvImageSignerName->Buffer); - SetDlgItemText(hwndDlg, IDC_COMPANYNAME_LINK, string->Buffer); + PhSetDialogItemText(hwndDlg, IDC_COMPANYNAME_LINK, string->Buffer); PhDereferenceObject(string); ShowWindow(GetDlgItem(hwndDlg, IDC_COMPANYNAME), SW_HIDE); ShowWindow(GetDlgItem(hwndDlg, IDC_COMPANYNAME_LINK), SW_SHOW); @@ -749,19 +749,19 @@ INT_PTR CALLBACK PvpPeGeneralDlgProc( else { string = PhConcatStrings2(L"(Verified) ", PhGetStringOrEmpty(PvImageVersionInfo.CompanyName)); - SetDlgItemText(hwndDlg, IDC_COMPANYNAME, string->Buffer); + PhSetDialogItemText(hwndDlg, IDC_COMPANYNAME, string->Buffer); PhDereferenceObject(string); } } else if (PvImageVerifyResult != VrUnknown) { string = PhConcatStrings2(L"(UNVERIFIED) ", PhGetStringOrEmpty(PvImageVersionInfo.CompanyName)); - SetDlgItemText(hwndDlg, IDC_COMPANYNAME, string->Buffer); + PhSetDialogItemText(hwndDlg, IDC_COMPANYNAME, string->Buffer); PhDereferenceObject(string); } else { - SetDlgItemText(hwndDlg, IDC_COMPANYNAME, PvpGetStringOrNa(PvImageVersionInfo.CompanyName)); + PhSetDialogItemText(hwndDlg, IDC_COMPANYNAME, PvpGetStringOrNa(PvImageVersionInfo.CompanyName)); } } break; diff --git a/tools/peview/prpsh.c b/tools/peview/prpsh.c index b3c06169cafc..f00bfe4021df 100644 --- a/tools/peview/prpsh.c +++ b/tools/peview/prpsh.c @@ -292,7 +292,7 @@ BOOLEAN PhpInitializePropSheetLayoutStage1( // Hide the OK button. ShowWindow(GetDlgItem(hwnd, IDOK), SW_HIDE); // Set the Cancel button's text to "Close". - SetDlgItemText(hwnd, IDCANCEL, L"Close"); + PhSetDialogItemText(hwnd, IDCANCEL, L"Close"); PropSheetContext->LayoutInitialized = TRUE; From e0f51a27fe416df39bfbdbdce05775ff2e729e06 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 28 Apr 2018 07:11:47 +1000 Subject: [PATCH 0915/2058] (Win10-RS5) Update default ExperimentalWindowStyle setting --- ProcessHacker/settings.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ProcessHacker/settings.c b/ProcessHacker/settings.c index 970bb9414a08..9ac3dfffcdf8 100644 --- a/ProcessHacker/settings.c +++ b/ProcessHacker/settings.c @@ -225,7 +225,7 @@ VOID PhAddDefaultSettings( PhpAddIntegerSetting(L"ColorUnknown", L"ff8080"); // Light Red // Experimental features - PhpAddIntegerSetting(L"EnableExperimentalWindowStyle", L"1"); + PhpAddIntegerSetting(L"EnableExperimentalWindowStyle", L"0"); } VOID PhUpdateCachedSettings( From 887bf12d04694f4fc38242b77009174669b7cf8f Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 29 Apr 2018 01:25:00 +1000 Subject: [PATCH 0916/2058] Fix crash --- ProcessHacker/hndlprp.c | 2 +- phlib/secedit.c | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/ProcessHacker/hndlprp.c b/ProcessHacker/hndlprp.c index 43d73bdf8777..83dbc02ad1fb 100644 --- a/ProcessHacker/hndlprp.c +++ b/ProcessHacker/hndlprp.c @@ -193,7 +193,7 @@ VOID PhShowHandleProperties( if (PhGetAccessEntries(PhGetStringOrEmpty(HandleItem->TypeName), &accessEntries, &numberOfAccessEntries)) { pages[propSheetHeader.nPages++] = PhCreateSecurityPage( - PhGetStringOrEmpty(HandleItem->BestObjectName), + PhGetString(HandleItem->BestObjectName), PhStdGetObjectSecurity, PhStdSetObjectSecurity, &stdObjectSecurity, diff --git a/phlib/secedit.c b/phlib/secedit.c index 276a26557637..41b758595f5b 100644 --- a/phlib/secedit.c +++ b/phlib/secedit.c @@ -171,7 +171,8 @@ ISecurityInformation *PhSecurityInformation_Create( info->VTable = &PhSecurityInformation_VTable; info->RefCount = 1; - info->ObjectName = PhCreateString(ObjectName); + if (ObjectName) // dmex: This fixes a crash caused by an 'antivirus' company. + info->ObjectName = PhCreateString(ObjectName); info->GetObjectSecurity = GetObjectSecurity; info->SetObjectSecurity = SetObjectSecurity; info->Context = Context; @@ -276,7 +277,7 @@ HRESULT STDMETHODCALLTYPE PhSecurityInformation_GetObjectInformation( //SI_NO_ACL_PROTECT | //SI_NO_TREE_APPLY; ObjectInfo->hInstance = NULL; - ObjectInfo->pszObjectName = this->ObjectName->Buffer; + ObjectInfo->pszObjectName = PhGetStringOrEmpty(this->ObjectName); return S_OK; } From 8030d96ee40b4079c33e1bd8d51dc1c331fc8638 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 29 Apr 2018 02:32:28 +1000 Subject: [PATCH 0917/2058] Revert "Fix crash" This reverts commit 887bf12d04694f4fc38242b77009174669b7cf8f. --- ProcessHacker/hndlprp.c | 2 +- phlib/secedit.c | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/ProcessHacker/hndlprp.c b/ProcessHacker/hndlprp.c index 83dbc02ad1fb..43d73bdf8777 100644 --- a/ProcessHacker/hndlprp.c +++ b/ProcessHacker/hndlprp.c @@ -193,7 +193,7 @@ VOID PhShowHandleProperties( if (PhGetAccessEntries(PhGetStringOrEmpty(HandleItem->TypeName), &accessEntries, &numberOfAccessEntries)) { pages[propSheetHeader.nPages++] = PhCreateSecurityPage( - PhGetString(HandleItem->BestObjectName), + PhGetStringOrEmpty(HandleItem->BestObjectName), PhStdGetObjectSecurity, PhStdSetObjectSecurity, &stdObjectSecurity, diff --git a/phlib/secedit.c b/phlib/secedit.c index 41b758595f5b..276a26557637 100644 --- a/phlib/secedit.c +++ b/phlib/secedit.c @@ -171,8 +171,7 @@ ISecurityInformation *PhSecurityInformation_Create( info->VTable = &PhSecurityInformation_VTable; info->RefCount = 1; - if (ObjectName) // dmex: This fixes a crash caused by an 'antivirus' company. - info->ObjectName = PhCreateString(ObjectName); + info->ObjectName = PhCreateString(ObjectName); info->GetObjectSecurity = GetObjectSecurity; info->SetObjectSecurity = SetObjectSecurity; info->Context = Context; @@ -277,7 +276,7 @@ HRESULT STDMETHODCALLTYPE PhSecurityInformation_GetObjectInformation( //SI_NO_ACL_PROTECT | //SI_NO_TREE_APPLY; ObjectInfo->hInstance = NULL; - ObjectInfo->pszObjectName = PhGetStringOrEmpty(this->ObjectName); + ObjectInfo->pszObjectName = this->ObjectName->Buffer; return S_OK; } From 4ed464d5785faa61e12a749c865edb64135883da Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 29 Apr 2018 03:15:09 +1000 Subject: [PATCH 0918/2058] Remove legacy dbghelp 5.1 (XP) functions --- phlib/include/symprv.h | 10 +- phlib/include/symprvp.h | 69 --------- phlib/symprv.c | 319 ++++++++++------------------------------ tools/peview/expprp.c | 32 ++-- tools/peview/impprp.c | 16 +- tools/peview/pdb.c | 26 ++-- 6 files changed, 115 insertions(+), 357 deletions(-) diff --git a/phlib/include/symprv.h b/phlib/include/symprv.h index dfa8a2900bd5..f9bd4c6216f4 100644 --- a/phlib/include/symprv.h +++ b/phlib/include/symprv.h @@ -291,15 +291,7 @@ PhWalkThreadStack( PHLIBAPI PPH_STRING NTAPI -PhUndecorateName( - _In_ PPH_SYMBOL_PROVIDER SymbolProvider, - _In_ PSTR DecoratedName - ); - -PHLIBAPI -PPH_STRING -NTAPI -PhUndecorateNameW( +PhUndecorateSymbolName( _In_ PPH_SYMBOL_PROVIDER SymbolProvider, _In_ PWSTR DecoratedName ); diff --git a/phlib/include/symprvp.h b/phlib/include/symprvp.h index 80512985ed87..4232e620d44b 100644 --- a/phlib/include/symprvp.h +++ b/phlib/include/symprvp.h @@ -11,14 +11,6 @@ typedef BOOL (WINAPI *_SymCleanup)( _In_ HANDLE hProcess ); -typedef BOOL (WINAPI *_SymEnumSymbols)( - _In_ HANDLE hProcess, - _In_ ULONG64 BaseOfDll, - _In_opt_ PCSTR Mask, - _In_ PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback, - _In_opt_ const PVOID UserContext - ); - typedef BOOL (WINAPI *_SymEnumSymbolsW)( _In_ HANDLE hProcess, _In_ ULONG64 BaseOfDll, @@ -27,13 +19,6 @@ typedef BOOL (WINAPI *_SymEnumSymbolsW)( _In_opt_ const PVOID UserContext ); -typedef BOOL (WINAPI *_SymFromAddr)( - _In_ HANDLE hProcess, - _In_ ULONG64 Address, - _Out_opt_ PULONG64 Displacement, - _Inout_ PSYMBOL_INFO Symbol - ); - typedef BOOL (WINAPI *_SymFromAddrW)( _In_ HANDLE hProcess, _In_ ULONG64 Address, @@ -41,12 +26,6 @@ typedef BOOL (WINAPI *_SymFromAddrW)( _Inout_ PSYMBOL_INFOW Symbol ); -typedef BOOL (WINAPI *_SymFromName)( - _In_ HANDLE hProcess, - _In_ PCSTR Name, - _Inout_ PSYMBOL_INFO Symbol - ); - typedef BOOL (WINAPI *_SymFromNameW)( _In_ HANDLE hProcess, _In_ PCWSTR Name, @@ -60,26 +39,12 @@ typedef BOOL (WINAPI *_SymEnumTypesW)( _In_opt_ PVOID UserContext ); -typedef BOOL (WINAPI *_SymEnumTypes)( - _In_ HANDLE hProcess, - _In_ ULONG64 BaseOfDll, - _In_ PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback, - _In_opt_ PVOID UserContext - ); - typedef BOOL (WINAPI *_SymGetModuleInfoW64)( _In_ HANDLE hProcess, _In_ ULONG64 qwAddr, _Out_ PIMAGEHLP_MODULEW64 ModuleInfo ); -typedef BOOL (WINAPI *_SymGetTypeFromName)( - _In_ HANDLE hProcess, - _In_ ULONG64 BaseOfDll, - _In_ PCSTR Name, - _Inout_ PSYMBOL_INFO Symbol - ); - typedef BOOL(WINAPI *_SymGetTypeFromNameW)( _In_ HANDLE hProcess, _In_ ULONG64 BaseOfDll, @@ -87,13 +52,6 @@ typedef BOOL(WINAPI *_SymGetTypeFromNameW)( _Inout_ PSYMBOL_INFOW Symbol ); -typedef BOOL (WINAPI *_SymGetLineFromAddr64)( - _In_ HANDLE hProcess, - _In_ ULONG64 dwAddr, - _Out_ PULONG pdwDisplacement, - _Out_ PIMAGEHLP_LINE64 Line - ); - typedef BOOL (WINAPI *_SymGetLineFromAddrW64)( _In_ HANDLE hProcess, _In_ ULONG64 dwAddr, @@ -101,15 +59,6 @@ typedef BOOL (WINAPI *_SymGetLineFromAddrW64)( _Out_ PIMAGEHLP_LINEW64 Line ); -typedef ULONG64 (WINAPI *_SymLoadModule64)( - _In_ HANDLE hProcess, - _In_opt_ HANDLE hFile, - _In_opt_ PCSTR ImageName, - _In_opt_ PCSTR ModuleName, - _In_ ULONG64 BaseOfDll, - _In_ ULONG SizeOfDll - ); - typedef ULONG64 (WINAPI *_SymLoadModuleExW)( _In_ HANDLE hProcess, _In_ HANDLE hFile, @@ -127,23 +76,12 @@ typedef ULONG (WINAPI *_SymSetOptions)( _In_ ULONG SymOptions ); -typedef BOOL (WINAPI *_SymGetSearchPath)( - _In_ HANDLE hProcess, - _Out_ PSTR SearchPath, - _In_ ULONG SearchPathLength - ); - typedef BOOL (WINAPI *_SymGetSearchPathW)( _In_ HANDLE hProcess, _Out_ PWSTR SearchPath, _In_ ULONG SearchPathLength ); -typedef BOOL (WINAPI *_SymSetSearchPath)( - _In_ HANDLE hProcess, - _In_opt_ PCSTR SearchPath - ); - typedef BOOL (WINAPI *_SymSetSearchPathW)( _In_ HANDLE hProcess, _In_opt_ PCWSTR SearchPath @@ -201,13 +139,6 @@ typedef BOOL (CALLBACK *_SymbolServerSetOptions)( _In_ ULONG64 data ); -typedef ULONG (WINAPI *_UnDecorateSymbolName)( - _In_ PCSTR DecoratedName, - _Out_ PSTR UnDecoratedName, - _In_ ULONG UndecoratedLength, - _In_ ULONG Flags - ); - typedef ULONG (WINAPI *_UnDecorateSymbolNameW)( _In_ PCWSTR DecoratedName, _Out_ PWSTR UnDecoratedName, diff --git a/phlib/symprv.c b/phlib/symprv.c index a11eb9382c40..c1e3eddb0b90 100644 --- a/phlib/symprv.c +++ b/phlib/symprv.c @@ -70,21 +70,14 @@ static PH_FAST_LOCK PhSymMutex = PH_FAST_LOCK_INIT; _SymInitialize SymInitialize_I; _SymCleanup SymCleanup_I; -_SymEnumSymbols SymEnumSymbols_I; _SymEnumSymbolsW SymEnumSymbolsW_I; -_SymFromAddr SymFromAddr_I; _SymFromAddrW SymFromAddrW_I; -_SymFromName SymFromName_I; _SymFromNameW SymFromNameW_I; -_SymGetLineFromAddr64 SymGetLineFromAddr64_I; _SymGetLineFromAddrW64 SymGetLineFromAddrW64_I; -_SymLoadModule64 SymLoadModule64_I; _SymLoadModuleExW SymLoadModuleExW_I; _SymGetOptions SymGetOptions_I; _SymSetOptions SymSetOptions_I; -_SymGetSearchPath SymGetSearchPath_I; _SymGetSearchPathW SymGetSearchPathW_I; -_SymSetSearchPath SymSetSearchPath_I; _SymSetSearchPathW SymSetSearchPathW_I; _SymUnloadModule64 SymUnloadModule64_I; _SymFunctionTableAccess64 SymFunctionTableAccess64_I; @@ -94,7 +87,6 @@ _StackWalk64 StackWalk64_I; _MiniDumpWriteDump MiniDumpWriteDump_I; _SymbolServerGetOptions SymbolServerGetOptions; _SymbolServerSetOptions SymbolServerSetOptions; -_UnDecorateSymbolName UnDecorateSymbolName_I; _UnDecorateSymbolNameW UnDecorateSymbolNameW_I; BOOLEAN PhSymbolProviderInitialization( @@ -332,33 +324,23 @@ VOID PhpSymbolProviderCompleteInitialization( if (dbghelpHandle) { - // The Unicode versions aren't available in dbghelp.dll 5.1, so we fallback on the ANSI versions. - SymInitialize_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymInitialize", 0); SymCleanup_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymCleanup", 0); - if (!(SymEnumSymbolsW_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymEnumSymbolsW", 0))) - SymEnumSymbols_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymEnumSymbols", 0); - if (!(SymFromAddrW_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymFromAddrW", 0))) - SymFromAddr_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymFromAddr", 0); - if (!(SymFromNameW_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymFromNameW", 0))) - SymFromName_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymFromName", 0); - if (!(SymGetLineFromAddrW64_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymGetLineFromAddrW64", 0))) - SymGetLineFromAddr64_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymGetLineFromAddr64", 0); - if (!(SymLoadModuleExW_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymLoadModuleExW", 0))) - SymLoadModule64_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymLoadModule64", 0); + SymEnumSymbolsW_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymEnumSymbolsW", 0); + SymFromAddrW_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymFromAddrW", 0); + SymFromNameW_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymFromNameW", 0); + SymGetLineFromAddrW64_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymGetLineFromAddrW64", 0); + SymLoadModuleExW_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymLoadModuleExW", 0); SymGetOptions_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymGetOptions", 0); SymSetOptions_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymSetOptions", 0); - if (!(SymGetSearchPathW_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymGetSearchPathW", 0))) - SymGetSearchPath_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymGetSearchPath", 0); - if (!(SymSetSearchPathW_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymSetSearchPathW", 0))) - SymSetSearchPath_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymSetSearchPath", 0); + SymGetSearchPathW_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymGetSearchPathW", 0); + SymSetSearchPathW_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymSetSearchPathW", 0); SymUnloadModule64_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymUnloadModule64", 0); SymFunctionTableAccess64_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymFunctionTableAccess64", 0); SymGetModuleBase64_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymGetModuleBase64", 0); SymRegisterCallbackW64_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymRegisterCallbackW64", 0); StackWalk64_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "StackWalk64", 0); MiniDumpWriteDump_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "MiniDumpWriteDump", 0); - UnDecorateSymbolName_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "UnDecorateSymbolName", 0); UnDecorateSymbolNameW_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "UnDecorateSymbolNameW", 0); } @@ -452,48 +434,25 @@ BOOLEAN PhGetLineFromAddress( PhpRegisterSymbolProvider(SymbolProvider); - if (!SymGetLineFromAddrW64_I && !SymGetLineFromAddr64_I) + if (!SymGetLineFromAddrW64_I) return FALSE; line.SizeOfStruct = sizeof(IMAGEHLP_LINEW64); PH_LOCK_SYMBOLS(); - if (SymGetLineFromAddrW64_I) - { - result = SymGetLineFromAddrW64_I( - SymbolProvider->ProcessHandle, - Address, - &displacement, - &line - ); - - if (result) - fileName = PhCreateString(line.FileName); - } - else - { - IMAGEHLP_LINE64 lineA; - - lineA.SizeOfStruct = sizeof(IMAGEHLP_LINE64); - - result = SymGetLineFromAddr64_I( - SymbolProvider->ProcessHandle, - Address, - &displacement, - &lineA - ); - - if (result) - { - fileName = PhConvertMultiByteToUtf16(lineA.FileName); - line.LineNumber = lineA.LineNumber; - line.Address = lineA.Address; - } - } + result = SymGetLineFromAddrW64_I( + SymbolProvider->ProcessHandle, + Address, + &displacement, + &line + ); PH_UNLOCK_SYMBOLS(); + if (result) + fileName = PhCreateString(line.FileName); + if (!result) return FALSE; @@ -628,7 +587,7 @@ PPH_STRING PhGetSymbolFromAddress( PhpRegisterSymbolProvider(SymbolProvider); - if (!SymFromAddrW_I && !SymFromAddr_I) + if (!SymFromAddrW_I) return NULL; symbolInfo = PhAllocate(FIELD_OFFSET(SYMBOL_INFOW, Name) + PH_MAX_SYMBOL_NAME_LEN * 2); @@ -644,74 +603,28 @@ PPH_STRING PhGetSymbolFromAddress( // will not write to the symbolInfo structure if it fails. We've already zeroed the structure, // so we can deal with it. - if (SymFromAddrW_I) - { - SymFromAddrW_I( - SymbolProvider->ProcessHandle, - Address, - &displacement, - symbolInfo - ); - nameLength = symbolInfo->NameLen; + SymFromAddrW_I( + SymbolProvider->ProcessHandle, + Address, + &displacement, + symbolInfo + ); + nameLength = symbolInfo->NameLen; - if (nameLength + 1 > PH_MAX_SYMBOL_NAME_LEN) - { - PhFree(symbolInfo); - symbolInfo = PhAllocate(FIELD_OFFSET(SYMBOL_INFOW, Name) + nameLength * 2 + 2); - memset(symbolInfo, 0, sizeof(SYMBOL_INFOW)); - symbolInfo->SizeOfStruct = sizeof(SYMBOL_INFOW); - symbolInfo->MaxNameLen = nameLength + 1; - - SymFromAddrW_I( - SymbolProvider->ProcessHandle, - Address, - &displacement, - symbolInfo - ); - } - } - else if (SymFromAddr_I) + if (nameLength + 1 > PH_MAX_SYMBOL_NAME_LEN) { - PSYMBOL_INFO symbolInfoA; + PhFree(symbolInfo); + symbolInfo = PhAllocate(FIELD_OFFSET(SYMBOL_INFOW, Name) + nameLength * 2 + 2); + memset(symbolInfo, 0, sizeof(SYMBOL_INFOW)); + symbolInfo->SizeOfStruct = sizeof(SYMBOL_INFOW); + symbolInfo->MaxNameLen = nameLength + 1; - symbolInfoA = PhAllocate(FIELD_OFFSET(SYMBOL_INFO, Name) + PH_MAX_SYMBOL_NAME_LEN); - memset(symbolInfoA, 0, sizeof(SYMBOL_INFO)); - symbolInfoA->SizeOfStruct = sizeof(SYMBOL_INFO); - symbolInfoA->MaxNameLen = PH_MAX_SYMBOL_NAME_LEN; - - SymFromAddr_I( + SymFromAddrW_I( SymbolProvider->ProcessHandle, Address, &displacement, - symbolInfoA + symbolInfo ); - nameLength = symbolInfoA->NameLen; - - if (nameLength + 1 > PH_MAX_SYMBOL_NAME_LEN) - { - PhFree(symbolInfoA); - symbolInfoA = PhAllocate(FIELD_OFFSET(SYMBOL_INFO, Name) + nameLength + 1); - memset(symbolInfoA, 0, sizeof(SYMBOL_INFO)); - symbolInfoA->SizeOfStruct = sizeof(SYMBOL_INFO); - symbolInfoA->MaxNameLen = nameLength + 1; - - SymFromAddr_I( - SymbolProvider->ProcessHandle, - Address, - &displacement, - symbolInfoA - ); - - // Also reallocate the Unicode-based buffer. - PhFree(symbolInfo); - symbolInfo = PhAllocate(FIELD_OFFSET(SYMBOL_INFOW, Name) + nameLength * 2 + 2); - memset(symbolInfo, 0, sizeof(SYMBOL_INFOW)); - symbolInfo->SizeOfStruct = sizeof(SYMBOL_INFOW); - symbolInfo->MaxNameLen = nameLength + 1; - } - - PhpSymbolInfoAnsiToUnicode(symbolInfo, symbolInfoA); - PhFree(symbolInfoA); } PH_UNLOCK_SYMBOLS(); @@ -836,7 +749,7 @@ BOOLEAN PhGetSymbolFromName( PhpRegisterSymbolProvider(SymbolProvider); - if (!SymFromNameW_I && !SymFromName_I) + if (!SymFromNameW_I) return FALSE; symbolInfo = (PSYMBOL_INFOW)symbolInfoBuffer; @@ -848,42 +761,11 @@ BOOLEAN PhGetSymbolFromName( PH_LOCK_SYMBOLS(); - if (SymFromNameW_I) - { - result = SymFromNameW_I( - SymbolProvider->ProcessHandle, - Name, - symbolInfo - ); - } - else if (SymFromName_I) - { - UCHAR buffer[FIELD_OFFSET(SYMBOL_INFO, Name) + PH_MAX_SYMBOL_NAME_LEN]; - PSYMBOL_INFO symbolInfoA; - PPH_BYTES name; - - symbolInfoA = (PSYMBOL_INFO)buffer; - memset(symbolInfoA, 0, sizeof(SYMBOL_INFO)); - symbolInfoA->SizeOfStruct = sizeof(SYMBOL_INFO); - symbolInfoA->MaxNameLen = PH_MAX_SYMBOL_NAME_LEN; - - name = PhConvertUtf16ToMultiByte(Name); - - if (result = SymFromName_I( - SymbolProvider->ProcessHandle, - name->Buffer, - symbolInfoA - )) - { - PhpSymbolInfoAnsiToUnicode(symbolInfo, symbolInfoA); - } - - PhDereferenceObject(name); - } - else - { - result = FALSE; - } + result = SymFromNameW_I( + SymbolProvider->ProcessHandle, + Name, + symbolInfo + ); PH_UNLOCK_SYMBOLS(); @@ -912,7 +794,7 @@ BOOLEAN PhLoadModuleSymbolProvider( PhpRegisterSymbolProvider(SymbolProvider); - if (!SymLoadModuleExW_I && !SymLoadModule64_I) + if (!SymLoadModuleExW_I) return FALSE; // Check for duplicates. It is better to do this before calling SymLoadModuleExW, because it @@ -928,34 +810,16 @@ BOOLEAN PhLoadModuleSymbolProvider( PH_LOCK_SYMBOLS(); - if (SymLoadModuleExW_I) - { - baseAddress = SymLoadModuleExW_I( - SymbolProvider->ProcessHandle, - NULL, - FileName, - NULL, - BaseAddress, - Size, - NULL, - 0 - ); - } - else - { - PPH_BYTES fileName; - - fileName = PhConvertUtf16ToMultiByte(FileName); - baseAddress = SymLoadModule64_I( - SymbolProvider->ProcessHandle, - NULL, - fileName->Buffer, - NULL, - BaseAddress, - Size - ); - PhDereferenceObject(fileName); - } + baseAddress = SymLoadModuleExW_I( + SymbolProvider->ProcessHandle, + NULL, + FileName, + NULL, + BaseAddress, + Size, + NULL, + 0 + ); PH_UNLOCK_SYMBOLS(); @@ -1021,23 +885,12 @@ VOID PhSetSearchPathSymbolProvider( { PhpRegisterSymbolProvider(SymbolProvider); - if (!SymSetSearchPathW_I && !SymSetSearchPath_I) + if (!SymSetSearchPathW_I) return; PH_LOCK_SYMBOLS(); - if (SymSetSearchPathW_I) - { - SymSetSearchPathW_I(SymbolProvider->ProcessHandle, Path); - } - else if (SymSetSearchPath_I) - { - PPH_BYTES path; - - path = PhConvertUtf16ToMultiByte(Path); - SymSetSearchPath_I(SymbolProvider->ProcessHandle, path->Buffer); - PhDereferenceObject(path); - } + SymSetSearchPathW_I(SymbolProvider->ProcessHandle, Path); PH_UNLOCK_SYMBOLS(); } @@ -1662,7 +1515,7 @@ NTSTATUS PhWalkThreadStack( } // Suspend the thread to avoid inaccurate results. Don't suspend if we're walking the stack of - // the current thread or this is a kernel-mode thread. + // the current thread or a kernel-mode thread. if (!isCurrentThread && !isSystemThread) { if (NT_SUCCESS(NtSuspendThread(ThreadHandle, NULL))) @@ -1832,64 +1685,40 @@ NTSTATUS PhWalkThreadStack( return status; } -PPH_STRING PhUndecorateName( - _In_ PPH_SYMBOL_PROVIDER SymbolProvider, - _In_ PSTR DecoratedName - ) -{ - PPH_STRING undecoratedStr = NULL; - PSTR undecoratedName = NULL; - - PhpRegisterSymbolProvider(SymbolProvider); - - if (!UnDecorateSymbolName_I) - return NULL; - - // lucasg: there is no way to know the resulting length of an undecorated name - // if there is not enough place, the function does not fail. Instead it - // return a truncated name. - - undecoratedName = PhAllocate(PAGE_SIZE * sizeof(CHAR)); - - PH_LOCK_SYMBOLS(); - if (UnDecorateSymbolName_I(DecoratedName, undecoratedName, PAGE_SIZE, UNDNAME_COMPLETE) != 0) - { - undecoratedStr = PhZeroExtendToUtf16(undecoratedName); - } - PH_UNLOCK_SYMBOLS(); - - PhFree(undecoratedName); - - return undecoratedStr; -} - -PPH_STRING PhUndecorateNameW( +PPH_STRING PhUndecorateSymbolName( _In_ PPH_SYMBOL_PROVIDER SymbolProvider, _In_ PWSTR DecoratedName ) { - PPH_STRING undecoratedStr = NULL; - PWSTR undecoratedName = NULL; + PPH_STRING undecoratedSymbolName = NULL; + PWSTR undecoratedBuffer; + ULONG result; PhpRegisterSymbolProvider(SymbolProvider); if (!UnDecorateSymbolNameW_I) return NULL; - // lucasg: there is no way to know the resulting length of an undecorated name - // if there is not enough place, the function does not fail. Instead it - // return a truncated name. + // lucasg: there is no way to know the resulting length of an undecorated name. + // If there is not enough space, the function does not fail and instead returns a truncated name. - undecoratedName = PhAllocate(PAGE_SIZE * sizeof(WCHAR)); + undecoratedBuffer = PhAllocate(PAGE_SIZE * sizeof(WCHAR)); + //memset(undecoratedBuffer, 0, PAGE_SIZE * sizeof(WCHAR)); PH_LOCK_SYMBOLS(); - if (UnDecorateSymbolNameW_I(DecoratedName, undecoratedName, PAGE_SIZE, UNDNAME_COMPLETE) != 0) - { - undecoratedStr = PhCreateString(undecoratedName); - } + + result = UnDecorateSymbolNameW_I( + DecoratedName, + undecoratedBuffer, + PAGE_SIZE, + UNDNAME_COMPLETE + ); + PH_UNLOCK_SYMBOLS(); - PhFree(undecoratedName); + if (result != 0) + undecoratedSymbolName = PhCreateStringEx(undecoratedBuffer, result * sizeof(WCHAR)); + PhFree(undecoratedBuffer); - return undecoratedStr; -} \ No newline at end of file + return undecoratedSymbolName; +} diff --git a/tools/peview/expprp.c b/tools/peview/expprp.c index aa20fb1c4bba..e37d38df8a4e 100644 --- a/tools/peview/expprp.c +++ b/tools/peview/expprp.c @@ -75,15 +75,17 @@ INT_PTR CALLBACK PvpPeExportsDlgProc( if (exportFunction.ForwardedName) { - PPH_STRING forwardName = NULL; + PPH_STRING forwardName; - if (exportFunction.ForwardedName[0] == '?') - forwardName = PhUndecorateName(PvSymbolProvider, exportFunction.ForwardedName); - else - forwardName = PhZeroExtendToUtf16(exportFunction.ForwardedName); + forwardName = PhZeroExtendToUtf16(exportFunction.ForwardedName); + + if (forwardName->Buffer[0] == '?') + { + PPH_STRING undecoratedName; - if (!forwardName) - forwardName = PhZeroExtendToUtf16(exportFunction.ForwardedName); + if (undecoratedName = PhUndecorateSymbolName(PvSymbolProvider, forwardName->Buffer)) + PhMoveReference(&forwardName, undecoratedName); + } PhSetListViewSubItem(lvHandle, lvItemIndex, 1, forwardName->Buffer); PhDereferenceObject(forwardName); @@ -96,15 +98,17 @@ INT_PTR CALLBACK PvpPeExportsDlgProc( if (exportEntry.Name) { - PPH_STRING exportName = NULL; + PPH_STRING exportName; - if (exportEntry.Name[0] == '?') - exportName = PhUndecorateName(PvSymbolProvider, exportEntry.Name); - else - exportName = PhZeroExtendToUtf16(exportEntry.Name); + exportName = PhZeroExtendToUtf16(exportEntry.Name); + + if (exportName->Buffer[0] == '?') + { + PPH_STRING undecoratedName; - if (!exportName) - exportName = PhZeroExtendToUtf16(exportEntry.Name); + if (undecoratedName = PhUndecorateSymbolName(PvSymbolProvider, exportName->Buffer)) + PhMoveReference(&exportName, undecoratedName); + } PhSetListViewSubItem(lvHandle, lvItemIndex, 2, exportName->Buffer); PhDereferenceObject(exportName); diff --git a/tools/peview/impprp.c b/tools/peview/impprp.c index 4decdd8721f6..a8dee5ca0b34 100644 --- a/tools/peview/impprp.c +++ b/tools/peview/impprp.c @@ -60,15 +60,17 @@ VOID PvpProcessImports( if (importEntry.Name) { - PPH_STRING importName = NULL; + PPH_STRING importName; - if (importEntry.Name[0] == '?') - importName = PhUndecorateName(PvSymbolProvider, importEntry.Name); - else - importName = PhZeroExtendToUtf16(importEntry.Name); + importName = PhZeroExtendToUtf16(importEntry.Name); - if (!importName) - importName = PhZeroExtendToUtf16(importEntry.Name); + if (importName->Buffer[0] == '?') + { + PPH_STRING undecoratedName; + + if (undecoratedName = PhUndecorateSymbolName(PvSymbolProvider, importName->Buffer)) + PhMoveReference(&importName, undecoratedName); + } PhSetListViewSubItem(ListViewHandle, lvItemIndex, 2, importName->Buffer); PhDereferenceObject(importName); diff --git a/tools/peview/pdb.c b/tools/peview/pdb.c index 8912fb428071..1e2cb793614b 100644 --- a/tools/peview/pdb.c +++ b/tools/peview/pdb.c @@ -2344,19 +2344,19 @@ NTSTATUS PeDumpFileSymbols( if (!(symsrvHandle = LoadLibrary(symsrvPath->Buffer))) return 1; - SymInitialize_I = PhGetProcedureAddress(dbghelpHandle, "SymInitialize", 0); - SymCleanup_I = PhGetProcedureAddress(dbghelpHandle, "SymCleanup", 0); - SymEnumSymbolsW_I = PhGetProcedureAddress(dbghelpHandle, "SymEnumSymbolsW", 0); - SymEnumTypesW_I = PhGetProcedureAddress(dbghelpHandle, "SymEnumTypesW", 0); - SymSetSearchPathW_I = PhGetProcedureAddress(dbghelpHandle, "SymSetSearchPathW", 0); - SymGetOptions_I = PhGetProcedureAddress(dbghelpHandle, "SymGetOptions", 0); - SymSetOptions_I = PhGetProcedureAddress(dbghelpHandle, "SymSetOptions", 0); - SymLoadModuleExW_I = PhGetProcedureAddress(dbghelpHandle, "SymLoadModuleExW", 0); - SymGetModuleInfoW64_I = PhGetProcedureAddress(dbghelpHandle, "SymGetModuleInfoW64", 0); - SymGetTypeFromNameW_I = PhGetProcedureAddress(dbghelpHandle, "SymGetTypeFromNameW", 0); - SymGetTypeInfo_I = PhGetProcedureAddress(dbghelpHandle, "SymGetTypeInfo", 0); - SymSetContext_I = PhGetProcedureAddress(dbghelpHandle, "SymSetContext", 0); - SymSearchW_I = PhGetProcedureAddress(dbghelpHandle, "SymSearchW", 0); + SymInitialize_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymInitialize", 0); + SymCleanup_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymCleanup", 0); + SymEnumSymbolsW_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymEnumSymbolsW", 0); + SymEnumTypesW_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymEnumTypesW", 0); + SymSetSearchPathW_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymSetSearchPathW", 0); + SymGetOptions_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymGetOptions", 0); + SymSetOptions_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymSetOptions", 0); + SymLoadModuleExW_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymLoadModuleExW", 0); + SymGetModuleInfoW64_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymGetModuleInfoW64", 0); + SymGetTypeFromNameW_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymGetTypeFromNameW", 0); + SymGetTypeInfo_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymGetTypeInfo", 0); + SymSetContext_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymSetContext", 0); + SymSearchW_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymSearchW", 0); SymSetOptions_I( SymGetOptions_I() | From 1ac2a69974fcd890a26e55cd5fb613c0a4383257 Mon Sep 17 00:00:00 2001 From: diversenok Date: Sat, 28 Apr 2018 20:19:29 +0300 Subject: [PATCH 0919/2058] A more accurate job statistics caption (#262) Only processes that were terminated due to limit violation are counted here. --- ProcessHacker/ProcessHacker.rc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ProcessHacker/ProcessHacker.rc b/ProcessHacker/ProcessHacker.rc index 030bd70221a3..737957c38089 100644 --- a/ProcessHacker/ProcessHacker.rc +++ b/ProcessHacker/ProcessHacker.rc @@ -926,8 +926,8 @@ BEGIN RTEXT "Static",IDC_ZACTIVEPROCESSES_V,99,18,37,8,SS_ENDELLIPSIS LTEXT "Total processes",IDC_STATIC,15,28,51,8 RTEXT "Static",IDC_ZTOTALPROCESSES_V,95,29,41,8,SS_ENDELLIPSIS - LTEXT "Terminated processes",IDC_STATIC,15,39,71,8 - RTEXT "Static",IDC_ZTERMINATEDPROCESSES_V,99,39,37,8,SS_ENDELLIPSIS + LTEXT "Terminated due to job limits",IDC_STATIC,15,39,98,8 + RTEXT "Static",IDC_ZTERMINATEDPROCESSES_V,107,39,29,8,SS_ENDELLIPSIS GROUPBOX "Time",IDC_STATIC,7,57,133,57 LTEXT "User time",IDC_STATIC,15,68,32,8 LTEXT "Kernel time",IDC_STATIC,15,79,38,8 From db0882b52b34bc43f3b127e1706cb1481cfe907a Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 29 Apr 2018 05:54:42 +1000 Subject: [PATCH 0920/2058] Fix regression viewing handle properties (commit 7b55523) --- ProcessHacker/hndlprp.c | 40 ++++++++++++++++++---------------------- 1 file changed, 18 insertions(+), 22 deletions(-) diff --git a/ProcessHacker/hndlprp.c b/ProcessHacker/hndlprp.c index 43d73bdf8777..ae8953721670 100644 --- a/ProcessHacker/hndlprp.c +++ b/ProcessHacker/hndlprp.c @@ -84,6 +84,9 @@ VOID PhShowHandleProperties( PROPSHEETPAGE propSheetPage; HPROPSHEETPAGE pages[16]; HANDLE_PROPERTIES_CONTEXT context; + PH_STD_OBJECT_SECURITY stdObjectSecurity; + PPH_ACCESS_ENTRY accessEntries; + ULONG numberOfAccessEntries; context.ProcessId = ProcessId; context.HandleItem = HandleItem; @@ -179,29 +182,22 @@ VOID PhShowHandleProperties( ); } - if (!PhIsNullOrEmptyString(HandleItem->TypeName)) - { - PH_STD_OBJECT_SECURITY stdObjectSecurity; - PPH_ACCESS_ENTRY accessEntries; - ULONG numberOfAccessEntries; - - // Security page - stdObjectSecurity.OpenObject = PhpDuplicateHandleFromProcess; - stdObjectSecurity.ObjectType = PhGetStringOrEmpty(HandleItem->TypeName); - stdObjectSecurity.Context = &context; + // Security page + stdObjectSecurity.OpenObject = PhpDuplicateHandleFromProcess; + stdObjectSecurity.ObjectType = PhGetStringOrEmpty(HandleItem->TypeName); + stdObjectSecurity.Context = &context; - if (PhGetAccessEntries(PhGetStringOrEmpty(HandleItem->TypeName), &accessEntries, &numberOfAccessEntries)) - { - pages[propSheetHeader.nPages++] = PhCreateSecurityPage( - PhGetStringOrEmpty(HandleItem->BestObjectName), - PhStdGetObjectSecurity, - PhStdSetObjectSecurity, - &stdObjectSecurity, - accessEntries, - numberOfAccessEntries - ); - PhFree(accessEntries); - } + if (PhGetAccessEntries(PhGetStringOrEmpty(HandleItem->TypeName), &accessEntries, &numberOfAccessEntries)) + { + pages[propSheetHeader.nPages++] = PhCreateSecurityPage( + PhGetStringOrEmpty(HandleItem->BestObjectName), + PhStdGetObjectSecurity, + PhStdSetObjectSecurity, + &stdObjectSecurity, + accessEntries, + numberOfAccessEntries + ); + PhFree(accessEntries); } if (PhPluginsEnabled) From dd7f016d5a965ef40b06672663a7579d03013bcf Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 2 May 2018 02:43:47 +1000 Subject: [PATCH 0921/2058] Remove PhGetAppContainerName parameter --- ProcessHacker/tokprp.c | 2 +- phlib/appresolver.c | 13 +++---------- phlib/include/appresolver.h | 3 +-- phlib/secedit.c | 2 +- 4 files changed, 6 insertions(+), 14 deletions(-) diff --git a/ProcessHacker/tokprp.c b/ProcessHacker/tokprp.c index 07674b4710b2..2aa7a801a922 100644 --- a/ProcessHacker/tokprp.c +++ b/ProcessHacker/tokprp.c @@ -660,7 +660,7 @@ INT_PTR CALLBACK PhpTokenPageProc( { if (appContainerInfo->TokenAppContainer) { - appContainerName = PhGetAppContainerName(appContainerInfo->TokenAppContainer, TRUE); + appContainerName = PhGetAppContainerName(appContainerInfo->TokenAppContainer); appContainerSid = PhSidToStringSid(appContainerInfo->TokenAppContainer); } diff --git a/phlib/appresolver.c b/phlib/appresolver.c index bf1558fc4155..5ca81481bb01 100644 --- a/phlib/appresolver.c +++ b/phlib/appresolver.c @@ -200,8 +200,7 @@ HRESULT PhAppResolverActivateAppId( } PPH_STRING PhGetAppContainerName( - _In_ PSID AppContainerSid, - _In_ BOOLEAN TokenPageHack + _In_ PSID AppContainerSid ) { HRESULT result; @@ -211,6 +210,8 @@ PPH_STRING PhGetAppContainerName( if (!PhpKernelAppCoreInitialized()) return NULL; + // NOTE: The AppContainerLookupMoniker function is not able to lookup the appcontainer names created using the + // CreateAppContainerProfile function from Win32 desktop applications (e.g. Google Chrome). result = AppContainerLookupMoniker_I( AppContainerSid, &packageMonikerName @@ -221,14 +222,6 @@ PPH_STRING PhGetAppContainerName( appContainerName = PhCreateString(packageMonikerName); AppContainerFreeMemory_I(packageMonikerName); } - else - { - // NOTE: The AppContainerLookupMoniker function is not able to lookup the appcontainer names created using the - // CreateAppContainerProfile function from Win32 desktop applications (e.g. Google Chrome). - // HACK: Return the error message until the above bug is fixed or have a better workaround -dmex - if (!TokenPageHack) - appContainerName = PhGetStatusMessage(0, HRESULT_CODE(result)); - } return appContainerName; } diff --git a/phlib/include/appresolver.h b/phlib/include/appresolver.h index 588ac78f63d3..835f414e7380 100644 --- a/phlib/include/appresolver.h +++ b/phlib/include/appresolver.h @@ -39,8 +39,7 @@ HRESULT PhAppResolverActivateAppId( ); PPH_STRING PhGetAppContainerName( - _In_ PSID AppContainerSid, - _In_ BOOLEAN TokenPageHack + _In_ PSID AppContainerSid ); PPH_STRING PhGetAppContainerSidFromName( diff --git a/phlib/secedit.c b/phlib/secedit.c index 276a26557637..be964c0fe2fa 100644 --- a/phlib/secedit.c +++ b/phlib/secedit.c @@ -567,7 +567,7 @@ HRESULT STDMETHODCALLTYPE PhSecurityDataObject_GetData( sidInfo.pwzCommonName = PhGetString(sidString); PhAddItemList(this->NameCache, sidString); } - else if (sidString = PhGetAppContainerName(sidInfo.pSid, FALSE)) + else if (sidString = PhGetAppContainerName(sidInfo.pSid)) { PhMoveReference(&sidString, PhFormatString(L"%s (APP_CONTAINER)", PhGetString(sidString))); sidInfo.pwzCommonName = PhGetString(sidString); From ce2608bf3643efdd5e7e0cfc4ec55c9c07bec3a6 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 2 May 2018 03:19:51 +1000 Subject: [PATCH 0922/2058] Add 'Extended unicode' checkbox to string search dialog --- ProcessHacker/ProcessHacker.rc | 1 + ProcessHacker/include/memsrch.h | 11 ++++++++++- ProcessHacker/memrslt.c | 3 ++- ProcessHacker/memsrch.c | 33 ++++++++++++++++++++++++++++++--- ProcessHacker/resource.h | 3 ++- 5 files changed, 45 insertions(+), 6 deletions(-) diff --git a/ProcessHacker/ProcessHacker.rc b/ProcessHacker/ProcessHacker.rc index 737957c38089..80f2dc46d03e 100644 --- a/ProcessHacker/ProcessHacker.rc +++ b/ProcessHacker/ProcessHacker.rc @@ -1336,6 +1336,7 @@ BEGIN CONTROL "Mapped",IDC_MAPPED,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,101,49,41,10 DEFPUSHBUTTON "OK",IDOK,131,65,50,14 PUSHBUTTON "Cancel",IDCANCEL,184,65,50,14 + CONTROL "Extended Unicode",IDC_EXTENDEDUNICODE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,80,22,74,10 END IDD_OPTGRAPHS DIALOGEX 0, 0, 250, 156 diff --git a/ProcessHacker/include/memsrch.h b/ProcessHacker/include/memsrch.h index 110d3d901f54..74459788d870 100644 --- a/ProcessHacker/include/memsrch.h +++ b/ProcessHacker/include/memsrch.h @@ -29,8 +29,17 @@ typedef struct _PH_MEMORY_STRING_OPTIONS PH_MEMORY_SEARCH_OPTIONS Header; ULONG MinimumLength; - BOOLEAN DetectUnicode; ULONG MemoryTypeMask; + union + { + BOOLEAN Flags; + struct + { + BOOLEAN DetectUnicode : 1; + BOOLEAN ExtendedUnicode : 1; + BOOLEAN Spare : 7; + }; + }; } PH_MEMORY_STRING_OPTIONS, *PPH_MEMORY_STRING_OPTIONS; PVOID PhAllocateForMemorySearch( diff --git a/ProcessHacker/memrslt.c b/ProcessHacker/memrslt.c index 3ce7325d15d4..8c0b206e9634 100644 --- a/ProcessHacker/memrslt.c +++ b/ProcessHacker/memrslt.c @@ -206,7 +206,8 @@ static VOID FilterResults( if (!compiledExpression) { - PhShowError(hwndDlg, L"Unable to compile the regular expression: \"%s\" at position %zu.", + PhShowError2(hwndDlg, L"Unable to compile the regular expression.", + L"\"%s\" at position %zu.", PhGetStringOrDefault(PH_AUTO(PhPcre2GetErrorMessage(errorCode)), L"Unknown error"), errorOffset ); diff --git a/ProcessHacker/memsrch.c b/ProcessHacker/memsrch.c index f3b2108bc6c0..9b39bc3dab8d 100644 --- a/ProcessHacker/memsrch.c +++ b/ProcessHacker/memsrch.c @@ -50,7 +50,8 @@ typedef struct _MEMORY_STRING_CONTEXT BOOLEAN Image : 1; BOOLEAN Mapped : 1; BOOLEAN EnableCloseDialog : 1; - BOOLEAN Spare : 3; + BOOLEAN ExtendedUnicode : 1; + BOOLEAN Spare : 2; }; }; @@ -191,6 +192,7 @@ VOID PhSearchMemoryString( { ULONG minimumLength; BOOLEAN detectUnicode; + BOOLEAN extendedUnicode; ULONG memoryTypeMask; PVOID baseAddress; MEMORY_BASIC_INFORMATION basicInfo; @@ -200,8 +202,9 @@ VOID PhSearchMemoryString( SIZE_T displayBufferCount; minimumLength = Options->MinimumLength; - detectUnicode = Options->DetectUnicode; memoryTypeMask = Options->MemoryTypeMask; + detectUnicode = Options->DetectUnicode; + extendedUnicode = Options->ExtendedUnicode; if (minimumLength < 4) return; @@ -295,7 +298,15 @@ VOID PhSearchMemoryString( for (i = 0; i < readSize; i++) { byte = buffer[i]; - printable = PhCharIsPrintable[byte]; + + // dmex: We don't want to enable extra bits in the PhCharIsPrintable array by default + // or we'll get higher amounts of false positive search results. If the user selects the + // ExtendedUnicode option then we'll use iswprint (GetStringTypeW) which does check + // every available character by default. + if (detectUnicode && extendedUnicode && !iswascii(byte)) + printable = iswprint(byte); + else + printable = PhCharIsPrintable[byte]; // To find strings Process Hacker uses a state table. // * byte2 - byte before previous byte @@ -564,6 +575,7 @@ INT_PTR CALLBACK PhpMemoryStringDlgProc( PhCenterWindow(hwndDlg, GetParent(hwndDlg)); PhSetDialogItemText(hwndDlg, IDC_MINIMUMLENGTH, L"10"); + Button_SetCheck(GetDlgItem(hwndDlg, IDC_DETECTUNICODE), BST_CHECKED); Button_SetCheck(GetDlgItem(hwndDlg, IDC_PRIVATE), BST_CHECKED); } @@ -594,6 +606,7 @@ INT_PTR CALLBACK PhpMemoryStringDlgProc( context->MinimumLength = (ULONG)minimumLength; context->DetectUnicode = Button_GetCheck(GetDlgItem(hwndDlg, IDC_DETECTUNICODE)) == BST_CHECKED; + context->ExtendedUnicode = Button_GetCheck(GetDlgItem(hwndDlg, IDC_EXTENDEDUNICODE)) == BST_CHECKED; context->Private = Button_GetCheck(GetDlgItem(hwndDlg, IDC_PRIVATE)) == BST_CHECKED; context->Image = Button_GetCheck(GetDlgItem(hwndDlg, IDC_IMAGE)) == BST_CHECKED; context->Mapped = Button_GetCheck(GetDlgItem(hwndDlg, IDC_MAPPED)) == BST_CHECKED; @@ -601,6 +614,19 @@ INT_PTR CALLBACK PhpMemoryStringDlgProc( EndDialog(hwndDlg, IDOK); } break; + case IDC_DETECTUNICODE: + { + if (Button_GetCheck(GetDlgItem(hwndDlg, IDC_DETECTUNICODE)) == BST_UNCHECKED) + { + Button_SetCheck(GetDlgItem(hwndDlg, IDC_EXTENDEDUNICODE), BST_UNCHECKED); + Button_Enable(GetDlgItem(hwndDlg, IDC_EXTENDEDUNICODE), FALSE); + } + else + { + Button_Enable(GetDlgItem(hwndDlg, IDC_EXTENDEDUNICODE), TRUE); + } + } + break; } } break; @@ -631,6 +657,7 @@ NTSTATUS PhpMemoryStringThreadStart( context->Options.Header.Context = context; context->Options.MinimumLength = context->MinimumLength; context->Options.DetectUnicode = context->DetectUnicode; + context->Options.ExtendedUnicode = context->ExtendedUnicode; if (context->Private) context->Options.MemoryTypeMask |= MEM_PRIVATE; diff --git a/ProcessHacker/resource.h b/ProcessHacker/resource.h index 3616f5c0d8b9..e8aa0f5d6a35 100644 --- a/ProcessHacker/resource.h +++ b/ProcessHacker/resource.h @@ -407,6 +407,7 @@ #define IDC_PRIVATE 1238 #define IDC_IMAGE 1239 #define IDC_MAPPED 1240 +#define IDC_EXTENDEDUNICODE 1241 #define IDC_SHOWTEXT 1245 #define IDC_ICONPROCESSES 1248 #define IDC_CLEANUP 1251 @@ -749,7 +750,7 @@ // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 252 +#define _APS_NEXT_RESOURCE_VALUE 253 #define _APS_NEXT_COMMAND_VALUE 40297 #define _APS_NEXT_CONTROL_VALUE 1410 #define _APS_NEXT_SYMED_VALUE 170 From f13847fb72e984503664709a5ed1565b60bcb04c Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 3 May 2018 04:03:48 +1000 Subject: [PATCH 0923/2058] Readability improvements --- ProcessHacker/appsup.c | 20 +++---- ProcessHacker/chdlg.c | 4 +- ProcessHacker/cmdmode.c | 4 +- ProcessHacker/dbgcon.c | 4 +- ProcessHacker/hidnproc.c | 2 +- ProcessHacker/mainwnd.c | 5 +- ProcessHacker/memprv.c | 6 +- ProcessHacker/miniinfo.c | 12 ++-- ProcessHacker/modprv.c | 2 +- ProcessHacker/netprv.c | 14 ++--- ProcessHacker/options.c | 6 +- ProcessHacker/plugin.c | 24 ++++---- ProcessHacker/plugman.c | 10 ++-- ProcessHacker/procprp.c | 2 +- ProcessHacker/procprv.c | 2 +- ProcessHacker/proctree.c | 6 +- ProcessHacker/prpgperf.c | 2 +- ProcessHacker/runas.c | 2 +- ProcessHacker/thrdprv.c | 4 +- phlib/basesup.c | 8 +-- phlib/graph.c | 20 +++---- phlib/guisup.c | 4 +- phlib/hndlinfo.c | 4 +- phlib/include/ph.h | 2 - phlib/lsasup.c | 2 +- phlib/native.c | 42 +++++++------- phlib/util.c | 82 ++++++++++++++-------------- phnt/include/phnt_ntdef.h | 2 + plugins/DotNetTools/asmpage.c | 2 +- plugins/ExtendedNotifications/main.c | 2 +- tools/peview/peprp.c | 2 +- tools/peview/prpsh.c | 2 +- 32 files changed, 152 insertions(+), 153 deletions(-) diff --git a/ProcessHacker/appsup.c b/ProcessHacker/appsup.c index d510526807aa..67f857b27958 100644 --- a/ProcessHacker/appsup.c +++ b/ProcessHacker/appsup.c @@ -453,7 +453,7 @@ BOOLEAN PhaGetProcessKnownCommandLine( // Get the DLL name part. - while (i < CommandLine->Length / 2 && CommandLine->Buffer[i] == ' ') + while (i < CommandLine->Length / sizeof(WCHAR) && CommandLine->Buffer[i] == ' ') i++; dllName = PhParseCommandLinePart(&CommandLine->sr, &i); @@ -517,7 +517,7 @@ BOOLEAN PhaGetProcessKnownCommandLine( // Get the argument part. - while (i < (ULONG)CommandLine->Length / 2 && CommandLine->Buffer[i] == ' ') + while (i < (ULONG)CommandLine->Length / sizeof(WCHAR) && CommandLine->Buffer[i] == ' ') i++; argPart = PhParseCommandLinePart(&CommandLine->sr, &i); @@ -538,7 +538,7 @@ BOOLEAN PhaGetProcessKnownCommandLine( guidString = PhaSubstring( argPart, indexOfProcessId + 11, - (ULONG)argPart->Length / 2 - indexOfProcessId - 11 + (ULONG)argPart->Length / sizeof(WCHAR) - indexOfProcessId - 11 ); PhStringRefToUnicodeString(&guidString->sr, &guidStringUs); @@ -661,8 +661,8 @@ PPH_STRING PhEscapeStringForDelimiter( SIZE_T i; WCHAR temp[2]; - length = String->Length / 2; - PhInitializeStringBuilder(&stringBuilder, String->Length / 2 * 3); + length = String->Length / sizeof(WCHAR); + PhInitializeStringBuilder(&stringBuilder, String->Length / sizeof(WCHAR) * 3); temp[0] = '\\'; @@ -691,8 +691,8 @@ PPH_STRING PhUnescapeStringForDelimiter( SIZE_T length; SIZE_T i; - length = String->Length / 2; - PhInitializeStringBuilder(&stringBuilder, String->Length / 2 * 3); + length = String->Length / sizeof(WCHAR); + PhInitializeStringBuilder(&stringBuilder, String->Length / sizeof(WCHAR) * 3); for (i = 0; i < length; i++) { @@ -883,7 +883,7 @@ VOID PhCopyListViewInfoTip( bufferRemaining = GetInfoTip->cchTextMax; } - copyLength = min((ULONG)Tip->Length / 2, bufferRemaining - 1); + copyLength = min((ULONG)Tip->Length / sizeof(WCHAR), bufferRemaining - 1); memcpy( &GetInfoTip->pszText[copyIndex], Tip->Buffer, @@ -1784,12 +1784,12 @@ BOOLEAN PhpSelectFavoriteInRegedit( info.cch = sizeof(buffer) / sizeof(WCHAR); GetMenuItemInfo(favoritesMenu, i, TRUE, &info); - if (info.cch == FavoriteName->Length / 2) + if (info.cch == FavoriteName->Length / sizeof(WCHAR)) { PH_STRINGREF text; text.Buffer = buffer; - text.Length = info.cch * 2; + text.Length = info.cch * sizeof(WCHAR); if (PhEqualStringRef(&text, FavoriteName, TRUE)) { diff --git a/ProcessHacker/chdlg.c b/ProcessHacker/chdlg.c index 565fba2b2195..7f511969f748 100644 --- a/ProcessHacker/chdlg.c +++ b/ProcessHacker/chdlg.c @@ -156,13 +156,13 @@ INT_PTR CALLBACK PhpChoiceDlgProc( i = 0; // Split the saved choices using the delimiter. - while (i < savedChoices->Length / 2) + while (i < savedChoices->Length / sizeof(WCHAR)) { // BUG BUG BUG - what if the user saves "\s"? indexOfDelim = PhFindStringInString(savedChoices, i, L"\\s"); if (indexOfDelim == -1) - indexOfDelim = savedChoices->Length / 2; + indexOfDelim = savedChoices->Length / sizeof(WCHAR); savedChoice = PhSubstring(savedChoices, i, indexOfDelim - i); diff --git a/ProcessHacker/cmdmode.c b/ProcessHacker/cmdmode.c index d54ba0f7bb17..d5e6b0d2307f 100644 --- a/ProcessHacker/cmdmode.c +++ b/ProcessHacker/cmdmode.c @@ -73,7 +73,7 @@ NTSTATUS PhCommandModeStart( PhParseCommandLine( &commandLine->sr, options, - sizeof(options) / sizeof(PH_COMMAND_LINE_OPTION), + RTL_NUMBER_OF(options), PH_COMMAND_LINE_IGNORE_UNKNOWN_OPTIONS, PhpCommandModeOptionCallback, NULL @@ -90,7 +90,7 @@ NTSTATUS PhCommandModeStart( if (!PhStartupParameters.CommandObject) return STATUS_INVALID_PARAMETER; - processIdLength = PhStartupParameters.CommandObject->Length / 2; + processIdLength = PhStartupParameters.CommandObject->Length / sizeof(WCHAR); for (i = 0; i < processIdLength; i++) { diff --git a/ProcessHacker/dbgcon.c b/ProcessHacker/dbgcon.c index d74807964979..a7e65d6ca842 100644 --- a/ProcessHacker/dbgcon.c +++ b/ProcessHacker/dbgcon.c @@ -709,7 +709,7 @@ NTSTATUS PhpDebugConsoleThreadStart( wprintf(L"dbg>"); - if (!fgetws(line, sizeof(line) / 2 - 1, stdin)) + if (!fgetws(line, sizeof(line) / sizeof(WCHAR) - 1, stdin)) break; // Remove the terminating new line character. @@ -954,7 +954,7 @@ NTSTATUS PhpDebugConsoleThreadStart( if (typeFilter) { - wcscpy_s(typeName, sizeof(typeName) / 2, PhGetObjectType(PhObjectHeaderToObject(objectHeader))->Name); + wcscpy_s(typeName, sizeof(typeName) / sizeof(WCHAR), PhGetObjectType(PhObjectHeaderToObject(objectHeader))->Name); _wcslwr(typeName); } diff --git a/ProcessHacker/hidnproc.c b/ProcessHacker/hidnproc.c index 7e5fcbbc639c..6a7ed098c030 100644 --- a/ProcessHacker/hidnproc.c +++ b/ProcessHacker/hidnproc.c @@ -687,7 +687,7 @@ static PPH_PROCESS_ITEM PhpCreateProcessItemForHiddenProcess( // Some command lines (e.g. from taskeng.exe) have nulls in them. // Since Windows can't display them, we'll replace them with // spaces. - for (i = 0; i < (ULONG)commandLine->Length / 2; i++) + for (i = 0; i < (ULONG)commandLine->Length / sizeof(WCHAR); i++) { if (commandLine->Buffer[i] == 0) commandLine->Buffer[i] = ' '; diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index 0b27413b4311..4948a40be56e 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -2021,7 +2021,7 @@ ULONG_PTR PhMwpOnUserMessage( fontHexString = PhaGetStringSetting(L"Font"); if ( - fontHexString->Length / 2 / 2 == sizeof(LOGFONT) && + fontHexString->Length / sizeof(WCHAR) / 2 == sizeof(LOGFONT) && PhHexStringToBuffer(&fontHexString->sr, (PUCHAR)&font) ) { @@ -2113,6 +2113,7 @@ VOID PhMwpLoadSettings( PhEnableServiceNonPoll = !!PhGetIntegerSetting(L"EnableServiceNonPoll"); PhEnableNetworkProviderResolve = !!PhGetIntegerSetting(L"EnableNetworkResolve"); PhEnableProcessQueryStage2 = !!PhGetIntegerSetting(L"EnableStage2"); + PhEnableServiceQueryStage2 = !!PhGetIntegerSetting(L"EnableServiceStage2"); PhMwpNotifyIconNotifyMask = PhGetIntegerSetting(L"IconNotifyMask"); if (PhGetIntegerSetting(L"MainWindowAlwaysOnTop")) @@ -2127,7 +2128,7 @@ VOID PhMwpLoadSettings( PhNfLoadStage1(); - if (customFont->Length / 2 / 2 == sizeof(LOGFONT)) + if (customFont->Length / sizeof(WCHAR) / 2 == sizeof(LOGFONT)) SendMessage(PhMainWndHandle, WM_PH_UPDATE_FONT, 0, 0); PhMwpNotifyAllPages(MainTabPageLoadSettings, NULL, NULL); diff --git a/ProcessHacker/memprv.c b/ProcessHacker/memprv.c index 0a434e533c38..6b8ec6d12487 100644 --- a/ProcessHacker/memprv.c +++ b/ProcessHacker/memprv.c @@ -85,19 +85,19 @@ VOID PhGetMemoryProtectionString( if (Protection & PAGE_GUARD) { - memcpy(string, L"+G", 2 * 2); + memcpy(string, L"+G", 2 * sizeof(WCHAR)); string += 2; } if (Protection & PAGE_NOCACHE) { - memcpy(string, L"+NC", 3 * 2); + memcpy(string, L"+NC", 3 * sizeof(WCHAR)); string += 3; } if (Protection & PAGE_WRITECOMBINE) { - memcpy(string, L"+WCM", 4 * 2); + memcpy(string, L"+WCM", 4 * sizeof(WCHAR)); string += 4; } diff --git a/ProcessHacker/miniinfo.c b/ProcessHacker/miniinfo.c index 503d2af8bbc6..a371a5bb97fc 100644 --- a/ProcessHacker/miniinfo.c +++ b/ProcessHacker/miniinfo.c @@ -1564,22 +1564,22 @@ BOOLEAN PhMipListSectionTreeNewCallback( // Top text = PhGetStringRef(getUsageText.Line1); - GetTextExtentPoint32(hdc, text.Buffer, (ULONG)text.Length / 2, &textSize); + GetTextExtentPoint32(hdc, text.Buffer, (ULONG)text.Length / sizeof(WCHAR), &textSize); usageTextTopWidth = textSize.cx; textRect = topRect; textRect.left = textRect.right - textSize.cx; SetTextColor(hdc, getUsageText.Line1Color); - DrawText(hdc, text.Buffer, (ULONG)text.Length / 2, &textRect, baseTextFlags | DT_RIGHT); + DrawText(hdc, text.Buffer, (ULONG)text.Length / sizeof(WCHAR), &textRect, baseTextFlags | DT_RIGHT); PhClearReference(&getUsageText.Line1); // Bottom text = PhGetStringRef(getUsageText.Line2); - GetTextExtentPoint32(hdc, text.Buffer, (ULONG)text.Length / 2, &textSize); + GetTextExtentPoint32(hdc, text.Buffer, (ULONG)text.Length / sizeof(WCHAR), &textSize); usageTextBottomWidth = textSize.cx; textRect = bottomRect; textRect.left = textRect.right - textSize.cx; SetTextColor(hdc, getUsageText.Line2Color); - DrawText(hdc, text.Buffer, (ULONG)text.Length / 2, &textRect, baseTextFlags | DT_RIGHT); + DrawText(hdc, text.Buffer, (ULONG)text.Length / sizeof(WCHAR), &textRect, baseTextFlags | DT_RIGHT); PhClearReference(&getUsageText.Line2); } @@ -1630,7 +1630,7 @@ BOOLEAN PhMipListSectionTreeNewCallback( DrawText( hdc, getTitleText.Title->Buffer, - (ULONG)getTitleText.Title->Length / 2, + (ULONG)getTitleText.Title->Length / sizeof(WCHAR), &textRect, baseTextFlags | DT_END_ELLIPSIS ); @@ -1646,7 +1646,7 @@ BOOLEAN PhMipListSectionTreeNewCallback( DrawText( hdc, getTitleText.Subtitle->Buffer, - (ULONG)getTitleText.Subtitle->Length / 2, + (ULONG)getTitleText.Subtitle->Length / sizeof(WCHAR), &textRect, baseTextFlags | DT_END_ELLIPSIS ); diff --git a/ProcessHacker/modprv.c b/ProcessHacker/modprv.c index 0c59975c48df..c2176e601269 100644 --- a/ProcessHacker/modprv.c +++ b/ProcessHacker/modprv.c @@ -545,7 +545,7 @@ VOID PhModuleProviderUpdate( if (NT_SUCCESS(PhLoadRemoteMappedImageEx(moduleProvider->ProcessHandle, moduleItem->BaseAddress, readVirtualMemoryCallback, &remoteMappedImage))) { ULONG_PTR imageBase = 0; - DWORD entryPoint = 0; + ULONG entryPoint = 0; moduleItem->ImageTimeDateStamp = remoteMappedImage.NtHeaders->FileHeader.TimeDateStamp; moduleItem->ImageCharacteristics = remoteMappedImage.NtHeaders->FileHeader.Characteristics; diff --git a/ProcessHacker/netprv.c b/ProcessHacker/netprv.c index 7df386b212c1..f3dbc170c48b 100644 --- a/ProcessHacker/netprv.c +++ b/ProcessHacker/netprv.c @@ -321,11 +321,11 @@ PPH_STRING PhGetHostNameFromAddress( hostName = PhCreateStringEx(NULL, 128); - if (GetNameInfoW( + if (GetNameInfo( address, length, hostName->Buffer, - (ULONG)hostName->Length / 2 + 1, + (ULONG)hostName->Length / sizeof(WCHAR) + 1, NULL, 0, NI_NAMEREQD @@ -333,13 +333,13 @@ PPH_STRING PhGetHostNameFromAddress( { // Try with the maximum host name size. PhDereferenceObject(hostName); - hostName = PhCreateStringEx(NULL, NI_MAXHOST * 2); + hostName = PhCreateStringEx(NULL, NI_MAXHOST * sizeof(WCHAR)); - if (GetNameInfoW( + if (GetNameInfo( address, length, hostName->Buffer, - (ULONG)hostName->Length / 2 + 1, + (ULONG)hostName->Length / sizeof(WCHAR) + 1, NULL, 0, NI_NAMEREQD @@ -661,8 +661,8 @@ VOID PhNetworkProviderUpdate( // Get process information. if (processItem = PhReferenceProcessItem(networkItem->ProcessId)) { - networkItem->ProcessName = processItem->ProcessName; PhReferenceObject(processItem->ProcessName); + networkItem->ProcessName = processItem->ProcessName; PhpUpdateNetworkItemOwner(networkItem, processItem); if (PhTestEvent(&processItem->Stage1Event)) @@ -702,8 +702,8 @@ VOID PhNetworkProviderUpdate( { if (!networkItem->ProcessName) { - networkItem->ProcessName = processItem->ProcessName; PhReferenceObject(processItem->ProcessName); + networkItem->ProcessName = processItem->ProcessName; PhpUpdateNetworkItemOwner(networkItem, processItem); modified = TRUE; } diff --git a/ProcessHacker/options.c b/ProcessHacker/options.c index 2acc423573cc..ed6c4266baa9 100644 --- a/ProcessHacker/options.c +++ b/ProcessHacker/options.c @@ -706,7 +706,7 @@ static BOOLEAN GetCurrentFont( else fontHexString = PhaGetStringSetting(L"Font"); - if (fontHexString->Length / 2 / 2 == sizeof(LOGFONT)) + if (fontHexString->Length / sizeof(WCHAR) / 2 == sizeof(LOGFONT)) result = PhHexStringToBuffer(&fontHexString->sr, (PUCHAR)Font); else result = FALSE; @@ -810,7 +810,7 @@ static BOOLEAN PathMatchesPh( } // Allow for a quoted value. else if ( - OldTaskMgrDebugger->Length == PhApplicationFileName->Length + sizeof(WCHAR) * 2 && + OldTaskMgrDebugger->Length == PhApplicationFileName->Length + sizeof(WCHAR) * sizeof(WCHAR) && OldTaskMgrDebugger->Buffer[0] == '"' && OldTaskMgrDebugger->Buffer[OldTaskMgrDebugger->Length / sizeof(WCHAR) - 1] == '"' ) @@ -818,7 +818,7 @@ static BOOLEAN PathMatchesPh( PH_STRINGREF partInside; partInside.Buffer = &OldTaskMgrDebugger->Buffer[1]; - partInside.Length = OldTaskMgrDebugger->Length - sizeof(WCHAR) * 2; + partInside.Length = OldTaskMgrDebugger->Length - sizeof(WCHAR) * sizeof(WCHAR); if (PhEqualStringRef(&partInside, &PhApplicationFileName->sr, TRUE)) match = TRUE; diff --git a/ProcessHacker/plugin.c b/ProcessHacker/plugin.c index 3531ba60d976..ab51dc3fac58 100644 --- a/ProcessHacker/plugin.c +++ b/ProcessHacker/plugin.c @@ -152,8 +152,8 @@ VOID PhSetPluginDisabled( // We have other disabled plugins. Append a pipe character followed by the plugin name. newDisabled = PhCreateStringEx(NULL, disabled->Length + sizeof(WCHAR) + BaseName->Length); memcpy(newDisabled->Buffer, disabled->Buffer, disabled->Length); - newDisabled->Buffer[disabled->Length / 2] = '|'; - memcpy(&newDisabled->Buffer[disabled->Length / 2 + 1], BaseName->Buffer, BaseName->Length); + newDisabled->Buffer[disabled->Length / sizeof(WCHAR)] = '|'; + memcpy(&newDisabled->Buffer[disabled->Length / sizeof(WCHAR) + 1], BaseName->Buffer, BaseName->Length); PhSetStringSetting2(L"DisabledPlugins", &newDisabled->sr); PhDereferenceObject(newDisabled); } @@ -169,9 +169,9 @@ VOID PhSetPluginDisabled( // We need to remove the plugin from the disabled list. - removeCount = (ULONG)BaseName->Length / 2; + removeCount = (ULONG)BaseName->Length / sizeof(WCHAR); - if (foundIndex + (ULONG)BaseName->Length / 2 < (ULONG)disabled->Length / 2) + if (foundIndex + (ULONG)BaseName->Length / sizeof(WCHAR) < (ULONG)disabled->Length / sizeof(WCHAR)) { // Remove the following pipe character as well. removeCount++; @@ -199,7 +199,7 @@ static BOOLEAN EnumPluginsDirectoryCallback( _In_opt_ PVOID Context ) { - static const PWSTR PhpPluginBlocklist[] = + static PWSTR PhpPluginBlocklist[] = { L"CommonUtil.dll", L"ExtraPlugins.dll" @@ -211,7 +211,7 @@ static BOOLEAN EnumPluginsDirectoryCallback( baseName.Buffer = Information->FileName; baseName.Length = Information->FileNameLength; - for (ULONG i = 0; i < ARRAYSIZE(PhpPluginBlocklist); i++) + for (ULONG i = 0; i < RTL_NUMBER_OF(PhpPluginBlocklist); i++) { if (PhEndsWithStringRef2(&baseName, PhpPluginBlocklist[i], TRUE)) { @@ -220,23 +220,19 @@ static BOOLEAN EnumPluginsDirectoryCallback( } } + fileName = PhConcatStringRef2(&PluginsDirectory->sr, &baseName); + if (blacklistedPlugin) { - fileName = PhConcatStringRef2(&PluginsDirectory->sr, &baseName); - PhDeleteFileWin32(fileName->Buffer); - - PhDereferenceObject(fileName); } else if (!PhIsPluginDisabled(&baseName)) { - fileName = PhConcatStringRef2(&PluginsDirectory->sr, &baseName); - PhLoadPlugin(fileName); - - PhDereferenceObject(fileName); } + PhDereferenceObject(fileName); + return TRUE; } diff --git a/ProcessHacker/plugman.c b/ProcessHacker/plugman.c index 4259a97b1127..3faa63da81f5 100644 --- a/ProcessHacker/plugman.c +++ b/ProcessHacker/plugman.c @@ -443,18 +443,18 @@ BOOLEAN NTAPI PluginsTreeNewCallback( SetTextColor(customDraw->Dc, RGB(0x0, 0x0, 0x0)); SelectObject(customDraw->Dc, context->TitleFontHandle); text = PhIsNullOrEmptyString(node->Name) ? PhGetStringRef(node->InternalName) : PhGetStringRef(node->Name); - GetTextExtentPoint32(customDraw->Dc, text.Buffer, (ULONG)text.Length / 2, &nameSize); - DrawText(customDraw->Dc, text.Buffer, (ULONG)text.Length / 2, &rect, DT_TOP | DT_LEFT | DT_END_ELLIPSIS | DT_SINGLELINE); + GetTextExtentPoint32(customDraw->Dc, text.Buffer, (ULONG)text.Length / sizeof(WCHAR), &nameSize); + DrawText(customDraw->Dc, text.Buffer, (ULONG)text.Length / sizeof(WCHAR), &rect, DT_TOP | DT_LEFT | DT_END_ELLIPSIS | DT_SINGLELINE); // bottom SetTextColor(customDraw->Dc, RGB(0x64, 0x64, 0x64)); SelectObject(customDraw->Dc, context->NormalFontHandle); text = PhGetStringRef(node->Description); - GetTextExtentPoint32(customDraw->Dc, text.Buffer, (ULONG)text.Length / 2, &textSize); + GetTextExtentPoint32(customDraw->Dc, text.Buffer, (ULONG)text.Length / sizeof(WCHAR), &textSize); DrawText( customDraw->Dc, text.Buffer, - (ULONG)text.Length / 2, + (ULONG)text.Length / sizeof(WCHAR), &rect, DT_BOTTOM | DT_LEFT | DT_END_ELLIPSIS | DT_SINGLELINE ); @@ -582,7 +582,7 @@ PWSTR PhpGetPluginBaseName( PH_STRINGREF pathNamePart; PH_STRINGREF baseNamePart; - if (PhSplitStringRefAtLastChar(&Plugin->FileName->sr, '\\', &pathNamePart, &baseNamePart)) + if (PhSplitStringRefAtLastChar(&Plugin->FileName->sr, OBJ_NAME_PATH_SEPARATOR, &pathNamePart, &baseNamePart)) return baseNamePart.Buffer; else return Plugin->FileName->Buffer; diff --git a/ProcessHacker/procprp.c b/ProcessHacker/procprp.c index 9e6d099932d2..d5a0d32bc8ac 100644 --- a/ProcessHacker/procprp.c +++ b/ProcessHacker/procprp.c @@ -236,7 +236,7 @@ LRESULT CALLBACK PhpPropSheetWndProc( tabItem.mask = TCIF_TEXT; tabItem.pszText = text; - tabItem.cchTextMax = sizeof(text) / 2 - 1; + tabItem.cchTextMax = RTL_NUMBER_OF(text) - 1; if (TabCtrl_GetItem(tabControl, TabCtrl_GetCurSel(tabControl), &tabItem)) { diff --git a/ProcessHacker/procprv.c b/ProcessHacker/procprv.c index fb7bebfeba74..1ba88e80eebd 100644 --- a/ProcessHacker/procprv.c +++ b/ProcessHacker/procprv.c @@ -815,7 +815,7 @@ VOID PhpProcessQueryStage1( { // Some command lines (e.g. from taskeng.exe) have nulls in them. Since Windows // can't display them, we'll replace them with spaces. - for (ULONG i = 0; i < (ULONG)commandLine->Length / 2; i++) + for (ULONG i = 0; i < (ULONG)commandLine->Length / sizeof(WCHAR); i++) { if (commandLine->Buffer[i] == 0) commandLine->Buffer[i] = ' '; diff --git a/ProcessHacker/proctree.c b/ProcessHacker/proctree.c index ed0dec371c3e..4c8a9df93458 100644 --- a/ProcessHacker/proctree.c +++ b/ProcessHacker/proctree.c @@ -3404,10 +3404,10 @@ VOID PhpPopulateTableWithProcessNodes( // If this is the first column in the row, add some indentation. text = PhaCreateStringEx( NULL, - getCellText.Text.Length + Level * 2 * sizeof(WCHAR) + getCellText.Text.Length + Level * sizeof(WCHAR) * sizeof(WCHAR) ); - wmemset(text->Buffer, ' ', Level * 2); - memcpy(&text->Buffer[Level * 2], getCellText.Text.Buffer, getCellText.Text.Length); + wmemset(text->Buffer, ' ', Level * sizeof(WCHAR)); + memcpy(&text->Buffer[Level * sizeof(WCHAR)], getCellText.Text.Buffer, getCellText.Text.Length); } Table[*Index][i] = text; diff --git a/ProcessHacker/prpgperf.c b/ProcessHacker/prpgperf.c index 9efb80e93072..217a973de8ec 100644 --- a/ProcessHacker/prpgperf.c +++ b/ProcessHacker/prpgperf.c @@ -412,7 +412,7 @@ INT_PTR CALLBACK PhpProcessPerformanceDlgProc( GetClientRect(hwndDlg, &clientRect); width = clientRect.right - margin.left - margin.right; - height = (clientRect.bottom - margin.top - margin.bottom - between * 2) / 3; + height = (clientRect.bottom - margin.top - margin.bottom - between * sizeof(WCHAR)) / 3; deferHandle = BeginDeferWindowPos(6); diff --git a/ProcessHacker/runas.c b/ProcessHacker/runas.c index 10c9431494d3..158a3fa2f507 100644 --- a/ProcessHacker/runas.c +++ b/ProcessHacker/runas.c @@ -389,7 +389,7 @@ static VOID PhpAddProgramsToComboBox( listHandle, i, entry, - ARRAYSIZE(entry) + RTL_NUMBER_OF(entry) )) { break; diff --git a/ProcessHacker/thrdprv.c b/ProcessHacker/thrdprv.c index 4e34dd964f5b..d2114f83c154 100644 --- a/ProcessHacker/thrdprv.c +++ b/ProcessHacker/thrdprv.c @@ -636,7 +636,7 @@ PPH_STRING PhpGetThreadBasicStartAddress( { *ResolveLevel = PhsrlAddress; - symbol = PhCreateStringEx(NULL, PH_PTR_STR_LEN * 2); + symbol = PhCreateStringEx(NULL, PH_PTR_STR_LEN * sizeof(WCHAR)); PhPrintPointer(symbol->Buffer, (PVOID)Address); PhTrimToNullTerminatorString(symbol); } @@ -945,7 +945,7 @@ VOID PhpThreadProviderUpdate( if (!threadItem->StartAddressString) { threadItem->StartAddressResolveLevel = PhsrlAddress; - threadItem->StartAddressString = PhCreateStringEx(NULL, PH_PTR_STR_LEN * 2); + threadItem->StartAddressString = PhCreateStringEx(NULL, PH_PTR_STR_LEN * sizeof(WCHAR)); PhPrintPointer( threadItem->StartAddressString->Buffer, (PVOID)threadItem->StartAddress diff --git a/phlib/basesup.c b/phlib/basesup.c index c14f780e7291..c960e155950b 100644 --- a/phlib/basesup.c +++ b/phlib/basesup.c @@ -5485,8 +5485,8 @@ BOOLEAN PhHexStringToBuffer( for (i = 0; i < length; i++) { Buffer[i] = - (UCHAR)(PhCharToInteger[(UCHAR)String->Buffer[i * 2]] << 4) + - (UCHAR)PhCharToInteger[(UCHAR)String->Buffer[i * 2 + 1]]; + (UCHAR)(PhCharToInteger[(UCHAR)String->Buffer[i * sizeof(WCHAR)]] << 4) + + (UCHAR)PhCharToInteger[(UCHAR)String->Buffer[i * sizeof(WCHAR) + 1]]; } return TRUE; @@ -5536,8 +5536,8 @@ PPH_STRING PhBufferToHexStringEx( for (i = 0; i < Length; i++) { - string->Buffer[i * 2] = table[Buffer[i] >> 4]; - string->Buffer[i * 2 + 1] = table[Buffer[i] & 0xf]; + string->Buffer[i * sizeof(WCHAR)] = table[Buffer[i] >> 4]; + string->Buffer[i * sizeof(WCHAR) + 1] = table[Buffer[i] & 0xf]; } return string; diff --git a/phlib/graph.c b/phlib/graph.c index fb7032e4f921..b0a2d0402db1 100644 --- a/phlib/graph.c +++ b/phlib/graph.c @@ -525,7 +525,7 @@ VOID PhDrawGraphDirect( SetTextColor(hdc, DrawInfo->LabelYColor); SetBkMode(hdc, TRANSPARENT); - GetTextExtentPoint32(hdc, label->Buffer, (ULONG)label->Length / 2, &textSize); + GetTextExtentPoint32(hdc, label->Buffer, (ULONG)label->Length / sizeof(WCHAR), &textSize); rect.bottom = height - yLabelMax - PhNormalGraphTextPadding.top; rect.top = rect.bottom - textSize.cy; @@ -538,7 +538,7 @@ VOID PhDrawGraphDirect( rect.left = 0; rect.right = width - min((LONG)yLabelDataIndex * 2, width) - PhNormalGraphTextPadding.right; - DrawText(hdc, label->Buffer, (ULONG)label->Length / 2, &rect, DT_NOCLIP | DT_RIGHT); + DrawText(hdc, label->Buffer, (ULONG)label->Length / sizeof(WCHAR), &rect, DT_NOCLIP | DT_RIGHT); if (oldFont) SelectObject(hdc, oldFont); @@ -561,7 +561,7 @@ VOID PhDrawGraphDirect( // Draw the text. SetTextColor(hdc, DrawInfo->TextColor); SetBkMode(hdc, TRANSPARENT); - DrawText(hdc, DrawInfo->Text.Buffer, (ULONG)DrawInfo->Text.Length / 2, &DrawInfo->TextRect, DT_NOCLIP); + DrawText(hdc, DrawInfo->Text.Buffer, (ULONG)DrawInfo->Text.Length / sizeof(WCHAR), &DrawInfo->TextRect, DT_NOCLIP); if (oldFont) SelectObject(hdc, oldFont); @@ -597,7 +597,7 @@ VOID PhSetGraphText( oldFont = SelectObject(hdc, DrawInfo->TextFont); DrawInfo->Text = *Text; - GetTextExtentPoint32(hdc, Text->Buffer, (ULONG)Text->Length / 2, &textSize); + GetTextExtentPoint32(hdc, Text->Buffer, (ULONG)Text->Length / sizeof(WCHAR), &textSize); if (oldFont) SelectObject(hdc, oldFont); @@ -612,14 +612,14 @@ VOID PhSetGraphText( else if (Align & PH_ALIGN_RIGHT) boxRectangle.Left = DrawInfo->Width - boxRectangle.Width - Margin->right; else - boxRectangle.Left = (DrawInfo->Width - boxRectangle.Width) / 2; + boxRectangle.Left = (DrawInfo->Width - boxRectangle.Width) / sizeof(WCHAR); if (Align & PH_ALIGN_TOP) boxRectangle.Top = Margin->top; else if (Align & PH_ALIGN_BOTTOM) boxRectangle.Top = DrawInfo->Height - boxRectangle.Height - Margin->bottom; else - boxRectangle.Top = (DrawInfo->Height - boxRectangle.Height) / 2; + boxRectangle.Top = (DrawInfo->Height - boxRectangle.Height) / sizeof(WCHAR); // Calculate the text rectangle. @@ -696,14 +696,14 @@ VOID PhDrawTrayIconText( oldFont = SelectObject(hdc, DrawInfo->TextFont); DrawInfo->Text = *Text; - GetTextExtentPoint32(hdc, Text->Buffer, (ULONG)Text->Length / 2, &textSize); + GetTextExtentPoint32(hdc, Text->Buffer, (ULONG)Text->Length / sizeof(WCHAR), &textSize); // Calculate the box rectangle. boxRectangle.Width = textSize.cx; boxRectangle.Height = textSize.cy; - boxRectangle.Left = (DrawInfo->Width - boxRectangle.Width) / 2; - boxRectangle.Top = (DrawInfo->Height - boxRectangle.Height) / 2; + boxRectangle.Left = (DrawInfo->Width - boxRectangle.Width) / sizeof(WCHAR); + boxRectangle.Top = (DrawInfo->Height - boxRectangle.Height) / sizeof(WCHAR); // Calculate the text rectangle. @@ -724,7 +724,7 @@ VOID PhDrawTrayIconText( SetTextColor(hdc, DrawInfo->TextColor); SetBkMode(hdc, TRANSPARENT); - DrawText(hdc, DrawInfo->Text.Buffer, (ULONG)DrawInfo->Text.Length / 2, &DrawInfo->TextRect, DT_NOCLIP | DT_SINGLELINE); + DrawText(hdc, DrawInfo->Text.Buffer, (ULONG)DrawInfo->Text.Length / sizeof(WCHAR), &DrawInfo->TextRect, DT_NOCLIP | DT_SINGLELINE); if (oldFont) SelectObject(hdc, oldFont); diff --git a/phlib/guisup.c b/phlib/guisup.c index c0041dea7bfe..8811d69e127f 100644 --- a/phlib/guisup.c +++ b/phlib/guisup.c @@ -415,7 +415,7 @@ PPH_STRING PhGetComboBoxString( if (length == 0) return PhReferenceEmptyString(); - string = PhCreateStringEx(NULL, length * 2); + string = PhCreateStringEx(NULL, length * sizeof(WCHAR)); if (ComboBox_GetLBText(hwnd, Index, string->Buffer) != CB_ERR) { @@ -476,7 +476,7 @@ PPH_STRING PhGetListBoxString( if (length == 0) return PhReferenceEmptyString(); - string = PhCreateStringEx(NULL, length * 2); + string = PhCreateStringEx(NULL, length * sizeof(WCHAR)); if (ListBox_GetText(hwnd, Index, string->Buffer) != LB_ERR) { diff --git a/phlib/hndlinfo.c b/phlib/hndlinfo.c index 8d22bf123b92..036af4e77a5d 100644 --- a/phlib/hndlinfo.c +++ b/phlib/hndlinfo.c @@ -561,7 +561,7 @@ _Callback_ PPH_STRING PhStdGetClientIdName( { name = PhFormatString( L"%.*s (%u): %u", - processInfo->ImageName.Length / 2, + processInfo->ImageName.Length / sizeof(WCHAR), processInfo->ImageName.Buffer, HandleToUlong(ClientId->UniqueProcess), HandleToUlong(ClientId->UniqueThread) @@ -582,7 +582,7 @@ _Callback_ PPH_STRING PhStdGetClientIdName( { name = PhFormatString( L"%.*s (%u)", - processInfo->ImageName.Length / 2, + processInfo->ImageName.Length / sizeof(WCHAR), processInfo->ImageName.Buffer, HandleToUlong(ClientId->UniqueProcess) ); diff --git a/phlib/include/ph.h b/phlib/include/ph.h index 632ee40d2c57..f64117102381 100644 --- a/phlib/include/ph.h +++ b/phlib/include/ph.h @@ -1,8 +1,6 @@ #ifndef _PH_PH_H #define _PH_PH_H -#pragma once - #include #include #include diff --git a/phlib/lsasup.c b/phlib/lsasup.c index 64ba602c422b..c60102ae79f0 100644 --- a/phlib/lsasup.c +++ b/phlib/lsasup.c @@ -414,7 +414,7 @@ PPH_STRING PhGetSidFullName( { fullName = PhCreateStringEx(NULL, domainNameLength + sizeof(WCHAR) + names[0].Name.Length); memcpy(&fullName->Buffer[0], domainNameBuffer, domainNameLength); - fullName->Buffer[domainNameLength / sizeof(WCHAR)] = '\\'; + fullName->Buffer[domainNameLength / sizeof(WCHAR)] = OBJ_NAME_PATH_SEPARATOR; memcpy(&fullName->Buffer[domainNameLength / sizeof(WCHAR) + 1], names[0].Name.Buffer, names[0].Name.Length); } else diff --git a/phlib/native.c b/phlib/native.c index fe40ce33517a..7cef0310dc61 100644 --- a/phlib/native.c +++ b/phlib/native.c @@ -1614,8 +1614,9 @@ NTSTATUS PhSetEnvironmentVariableRemote( else { #endif - if (!NT_SUCCESS(status = NtQueueApcThread( + if (!NT_SUCCESS(status = NtQueueApcThreadEx( threadHandle, + NULL, setEnvironmentVariableW, nameBaseAddress, valueBaseAddress, @@ -2898,7 +2899,7 @@ NTSTATUS PhUnloadDriver( // Remove the extension if it is present. if (PhEndsWithString2(name, L".sys", TRUE)) { - serviceKeyName = PhSubstring(name, 0, name->Length / 2 - 4); + serviceKeyName = PhSubstring(name, 0, name->Length / sizeof(WCHAR) - 4); PhDereferenceObject(name); } else @@ -3047,7 +3048,7 @@ BOOLEAN NTAPI PhpEnumProcessModulesCallback( ULONG_PTR indexOfLastBackslash; PhStringRefToUnicodeString(&mappedFileName->sr, &Entry->FullDllName); - indexOfLastBackslash = PhFindLastCharInString(mappedFileName, 0, '\\'); + indexOfLastBackslash = PhFindLastCharInString(mappedFileName, 0, OBJ_NAME_PATH_SEPARATOR); if (indexOfLastBackslash != -1) { @@ -3076,7 +3077,7 @@ BOOLEAN NTAPI PhpEnumProcessModulesCallback( NULL ))) { - fullDllNameBuffer[Entry->FullDllName.Length / 2] = 0; + fullDllNameBuffer[Entry->FullDllName.Length / sizeof(WCHAR)] = 0; } else { @@ -3114,7 +3115,7 @@ BOOLEAN NTAPI PhpEnumProcessModulesCallback( NULL ))) { - baseDllNameBuffer[Entry->BaseDllName.Length / 2] = 0; + baseDllNameBuffer[Entry->BaseDllName.Length / sizeof(WCHAR)] = 0; } else { @@ -3428,7 +3429,7 @@ BOOLEAN NTAPI PhpEnumProcessModules32Callback( ULONG_PTR indexOfLastBackslash; PhStringRefToUnicodeString(&mappedFileName->sr, &nativeEntry.FullDllName); - indexOfLastBackslash = PhFindLastCharInString(mappedFileName, 0, '\\'); + indexOfLastBackslash = PhFindLastCharInString(mappedFileName, 0, OBJ_NAME_PATH_SEPARATOR); if (indexOfLastBackslash != -1) { @@ -3455,7 +3456,7 @@ BOOLEAN NTAPI PhpEnumProcessModules32Callback( NULL ))) { - baseDllNameBuffer[nativeEntry.BaseDllName.Length / 2] = 0; + baseDllNameBuffer[nativeEntry.BaseDllName.Length / sizeof(WCHAR)] = 0; } else { @@ -3477,7 +3478,7 @@ BOOLEAN NTAPI PhpEnumProcessModules32Callback( NULL ))) { - fullDllNameBuffer[nativeEntry.FullDllName.Length / 2] = 0; + fullDllNameBuffer[nativeEntry.FullDllName.Length / sizeof(WCHAR)] = 0; if (!(parameters->Flags & PH_ENUM_PROCESS_MODULES_DONT_RESOLVE_WOW64_FS)) { @@ -5071,7 +5072,7 @@ PPH_STRING PhResolveDevicePrefix( { // To ensure we match the longest prefix, make sure the next character is a // backslash or the path is equal to the prefix. - if (Name->Length == prefix.Length || Name->Buffer[prefix.Length / sizeof(WCHAR)] == '\\') + if (Name->Length == prefix.Length || Name->Buffer[prefix.Length / sizeof(WCHAR)] == OBJ_NAME_PATH_SEPARATOR) { isPrefix = TRUE; } @@ -5116,7 +5117,7 @@ PPH_STRING PhResolveDevicePrefix( // To ensure we match the longest prefix, make sure the next character is a // backslash. Don't resolve if the name *is* the prefix. Otherwise, we will end // up with a useless string like "\". - if (Name->Length != prefixLength && Name->Buffer[prefixLength / sizeof(WCHAR)] == '\\') + if (Name->Length != prefixLength && Name->Buffer[prefixLength / sizeof(WCHAR)] == OBJ_NAME_PATH_SEPARATOR) { isPrefix = TRUE; } @@ -5127,7 +5128,7 @@ PPH_STRING PhResolveDevicePrefix( { // \path newName = PhCreateStringEx(NULL, 1 * sizeof(WCHAR) + Name->Length - prefixLength); - newName->Buffer[0] = '\\'; + newName->Buffer[0] = OBJ_NAME_PATH_SEPARATOR; memcpy( &newName->Buffer[1], &Name->Buffer[prefixLength / sizeof(WCHAR)], @@ -5169,8 +5170,8 @@ PPH_STRING PhGetFileName( // "\??\" refers to \GLOBAL??\. Just remove it. if (PhStartsWithString2(FileName, L"\\??\\", FALSE)) { - newFileName = PhCreateStringEx(NULL, FileName->Length - 4 * 2); - memcpy(newFileName->Buffer, &FileName->Buffer[4], FileName->Length - 4 * 2); + newFileName = PhCreateStringEx(NULL, FileName->Length - 4 * sizeof(WCHAR)); + memcpy(newFileName->Buffer, &FileName->Buffer[4], FileName->Length - 4 * sizeof(WCHAR)); } // "\SystemRoot" means "C:\Windows". else if (PhStartsWithString2(FileName, L"\\SystemRoot", TRUE)) @@ -5178,9 +5179,9 @@ PPH_STRING PhGetFileName( PH_STRINGREF systemRoot; PhGetSystemRoot(&systemRoot); - newFileName = PhCreateStringEx(NULL, systemRoot.Length + FileName->Length - 11 * 2); + newFileName = PhCreateStringEx(NULL, systemRoot.Length + FileName->Length - 11 * sizeof(WCHAR)); memcpy(newFileName->Buffer, systemRoot.Buffer, systemRoot.Length); - memcpy(PTR_ADD_OFFSET(newFileName->Buffer, systemRoot.Length), &FileName->Buffer[11], FileName->Length - 11 * 2); + memcpy(PTR_ADD_OFFSET(newFileName->Buffer, systemRoot.Length), &FileName->Buffer[11], FileName->Length - 11 * sizeof(WCHAR)); } // "system32\" means "C:\Windows\system32\". else if (PhStartsWithString2(FileName, L"system32\\", TRUE)) @@ -5190,10 +5191,10 @@ PPH_STRING PhGetFileName( PhGetSystemRoot(&systemRoot); newFileName = PhCreateStringEx(NULL, systemRoot.Length + 2 + FileName->Length); memcpy(newFileName->Buffer, systemRoot.Buffer, systemRoot.Length); - newFileName->Buffer[systemRoot.Length / 2] = '\\'; + newFileName->Buffer[systemRoot.Length / sizeof(WCHAR)] = OBJ_NAME_PATH_SEPARATOR; memcpy(PTR_ADD_OFFSET(newFileName->Buffer, systemRoot.Length + 2), FileName->Buffer, FileName->Length); } - else if (FileName->Length != 0 && FileName->Buffer[0] == '\\') + else if (FileName->Length != 0 && FileName->Buffer[0] == OBJ_NAME_PATH_SEPARATOR) { PPH_STRING resolvedName; @@ -5209,7 +5210,7 @@ PPH_STRING PhGetFileName( // If the file name starts with "\Windows", prepend the system drive. if (PhStartsWithString2(newFileName, L"\\Windows", TRUE)) { - newFileName = PhCreateStringEx(NULL, FileName->Length + 2 * 2); + newFileName = PhCreateStringEx(NULL, FileName->Length + 2 * sizeof(WCHAR)); newFileName->Buffer[0] = USER_SHARED_DATA->NtSystemRoot[0]; newFileName->Buffer[1] = ':'; memcpy(&newFileName->Buffer[2], FileName->Buffer, FileName->Length); @@ -6350,6 +6351,7 @@ NTSTATUS PhQueryFullAttributesFileWin32( ); status = NtQueryFullAttributesFile(&oa, FileInformation); + RtlFreeUnicodeString(&fileName); return status; @@ -6371,7 +6373,7 @@ NTSTATUS PhDeleteFileWin32( &fileHandle, FileName, DELETE, - 0, + FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN, FILE_DELETE_ON_CLOSE @@ -6409,7 +6411,7 @@ NTSTATUS PhCreateDirectory( while (remainingPart.Length != 0) { - PhSplitStringRefAtChar(&remainingPart, '\\', &part, &remainingPart); + PhSplitStringRefAtChar(&remainingPart, OBJ_NAME_PATH_SEPARATOR, &part, &remainingPart); if (part.Length != 0) { diff --git a/phlib/util.c b/phlib/util.c index 2ebc1d6f2144..629f3d689179 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -845,7 +845,7 @@ PPH_STRING PhEllipsisString( ) { if ( - (ULONG)String->Length / 2 <= DesiredCount || + (ULONG)String->Length / sizeof(WCHAR) <= DesiredCount || DesiredCount < 3 ) { @@ -855,8 +855,8 @@ PPH_STRING PhEllipsisString( { PPH_STRING string; - string = PhCreateStringEx(NULL, DesiredCount * 2); - memcpy(string->Buffer, String->Buffer, (DesiredCount - 3) * 2); + string = PhCreateStringEx(NULL, DesiredCount * sizeof(WCHAR)); + memcpy(string->Buffer, String->Buffer, (DesiredCount - 3) * sizeof(WCHAR)); memcpy(&string->Buffer[DesiredCount - 3], L"...", 6); return string; @@ -887,7 +887,7 @@ PPH_STRING PhEllipsisStringPath( return PhEllipsisString(String, DesiredCount); if ( - String->Length / 2 <= DesiredCount || + String->Length / sizeof(WCHAR) <= DesiredCount || DesiredCount < 3 ) { @@ -899,8 +899,8 @@ PPH_STRING PhEllipsisStringPath( ULONG_PTR firstPartCopyLength; ULONG_PTR secondPartCopyLength; - string = PhCreateStringEx(NULL, DesiredCount * 2); - secondPartCopyLength = String->Length / 2 - secondPartIndex; + string = PhCreateStringEx(NULL, DesiredCount * sizeof(WCHAR)); + secondPartCopyLength = String->Length / sizeof(WCHAR) - secondPartIndex; // Check if we have enough space for the entire second part of the string. if (secondPartCopyLength + 3 <= DesiredCount) @@ -912,15 +912,15 @@ PPH_STRING PhEllipsisStringPath( { // No, copy part of both, from the beginning of the first part and the end of the second // part. - firstPartCopyLength = (DesiredCount - 3) / 2; + firstPartCopyLength = (DesiredCount - 3) / sizeof(WCHAR); secondPartCopyLength = DesiredCount - 3 - firstPartCopyLength; - secondPartIndex = String->Length / 2 - secondPartCopyLength; + secondPartIndex = String->Length / sizeof(WCHAR) - secondPartCopyLength; } memcpy( string->Buffer, String->Buffer, - firstPartCopyLength * 2 + firstPartCopyLength * sizeof(WCHAR) ); memcpy( &string->Buffer[firstPartCopyLength], @@ -930,7 +930,7 @@ PPH_STRING PhEllipsisStringPath( memcpy( &string->Buffer[firstPartCopyLength + 3], &String->Buffer[secondPartIndex], - secondPartCopyLength * 2 + secondPartCopyLength * sizeof(WCHAR) ); return string; @@ -1852,7 +1852,7 @@ PPH_STRING PhGetFullPath( PWSTR filePart; bufferSize = 0x80; - fullPath = PhCreateStringEx(NULL, bufferSize * 2); + fullPath = PhCreateStringEx(NULL, bufferSize * sizeof(WCHAR)); returnLength = RtlGetFullPathName_U(FileName, bufferSize, fullPath->Buffer, &filePart); @@ -1860,7 +1860,7 @@ PPH_STRING PhGetFullPath( { PhDereferenceObject(fullPath); bufferSize = returnLength; - fullPath = PhCreateStringEx(NULL, bufferSize * 2); + fullPath = PhCreateStringEx(NULL, bufferSize * sizeof(WCHAR)); returnLength = RtlGetFullPathName_U(FileName, bufferSize, fullPath->Buffer, &filePart); } @@ -1944,7 +1944,7 @@ PPH_STRING PhExpandEnvironmentStrings( } string->Length = outputString.Length; - string->Buffer[string->Length / 2] = UNICODE_NULL; // make sure there is a null terminator + string->Buffer[string->Length / sizeof(WCHAR)] = UNICODE_NULL; // make sure there is a null terminator return string; } @@ -1961,7 +1961,7 @@ PPH_STRING PhGetBaseName( PH_STRINGREF pathPart; PH_STRINGREF baseNamePart; - if (!PhSplitStringRefAtLastChar(&FileName->sr, '\\', &pathPart, &baseNamePart)) + if (!PhSplitStringRefAtLastChar(&FileName->sr, OBJ_NAME_PATH_SEPARATOR, &pathPart, &baseNamePart)) return PhReferenceObject(FileName); return PhCreateString2(&baseNamePart); @@ -1979,7 +1979,7 @@ PPH_STRING PhGetBaseDirectory( PH_STRINGREF pathPart; PH_STRINGREF baseNamePart; - if (!PhSplitStringRefAtLastChar(&FileName->sr, '\\', &pathPart, &baseNamePart)) + if (!PhSplitStringRefAtLastChar(&FileName->sr, OBJ_NAME_PATH_SEPARATOR, &pathPart, &baseNamePart)) return NULL; return PhCreateString2(&pathPart); @@ -2042,7 +2042,7 @@ VOID PhGetSystemRoot( localSystemRoot.Length = count * sizeof(WCHAR); // Make sure the system root string doesn't have a trailing backslash. - if (localSystemRoot.Buffer[count - 1] == '\\') + if (localSystemRoot.Buffer[count - 1] == OBJ_NAME_PATH_SEPARATOR) localSystemRoot.Length -= sizeof(WCHAR); *SystemRoot = localSystemRoot; @@ -2059,15 +2059,15 @@ PPH_STRING PhGetApplicationFileName( VOID ) { - PPH_STRING fileName; - - if (NT_SUCCESS(PhGetProcessImageFileNameWin32(NtCurrentProcess(), &fileName))) - { - PhMoveReference(&fileName, PhGetFileName(fileName)); - return fileName; - } + //PPH_STRING fileName; + // + //if (NT_SUCCESS(PhGetProcessImageFileNameWin32(NtCurrentProcess(), &fileName))) + //{ + // PhMoveReference(&fileName, PhGetFileName(fileName)); + // return fileName; + //} - return PhGetDllFileName(NtCurrentPeb()->ImageBaseAddress, NULL); + return PhGetDllFileName(PhInstanceHandle, NULL); } /** @@ -2085,7 +2085,7 @@ PPH_STRING PhGetApplicationDirectory( if (fileName) { - indexOfFileName = PhFindLastCharInString(fileName, 0, '\\'); + indexOfFileName = PhFindLastCharInString(fileName, 0, OBJ_NAME_PATH_SEPARATOR); if (indexOfFileName != -1) indexOfFileName++; @@ -3577,7 +3577,7 @@ UINT_PTR CALLBACK PhpOpenFileNameHookProc( { PhFree(header->lpOFN->lpstrFile); header->lpOFN->nMaxFile = returnLength + 0x200; // pre-allocate some more - header->lpOFN->lpstrFile = PhAllocate(header->lpOFN->nMaxFile * 2); + header->lpOFN->lpstrFile = PhAllocate(header->lpOFN->nMaxFile * sizeof(WCHAR)); returnLength = CommDlg_OpenSave_GetFilePath( header->hdr.hwndFrom, @@ -3606,7 +3606,7 @@ OPENFILENAME *PhpCreateOpenFileName( ofn->lStructSize = sizeof(OPENFILENAME); ofn->nMaxFile = 0x400; - ofn->lpstrFile = PhAllocate(ofn->nMaxFile * 2); + ofn->lpstrFile = PhAllocate(ofn->nMaxFile * sizeof(WCHAR)); ofn->lpstrFileTitle = NULL; ofn->Flags = OFN_ENABLEHOOK | OFN_EXPLORER; ofn->lpfnHook = PhpOpenFileNameHookProc; @@ -4079,7 +4079,7 @@ VOID PhSetFileDialogFileName( PH_STRINGREF pathNamePart; PH_STRINGREF baseNamePart; - if (PhSplitStringRefAtLastChar(&fileName, '\\', &pathNamePart, &baseNamePart) && + if (PhSplitStringRefAtLastChar(&fileName, OBJ_NAME_PATH_SEPARATOR, &pathNamePart, &baseNamePart) && SHParseDisplayName_Import() && SHCreateShellItem_Import()) { LPITEMIDLIST item; @@ -4121,7 +4121,7 @@ VOID PhSetFileDialogFileName( PhFree(ofn->lpstrFile); ofn->nMaxFile = (ULONG)max(fileName.Length / sizeof(WCHAR) + 1, 0x400); - ofn->lpstrFile = PhAllocate(ofn->nMaxFile * 2); + ofn->lpstrFile = PhAllocate(ofn->nMaxFile * sizeof(WCHAR)); memcpy(ofn->lpstrFile, fileName.Buffer, fileName.Length + sizeof(WCHAR)); } } @@ -4465,7 +4465,7 @@ PPH_STRING PhParseCommandLinePart( BOOLEAN inQuote; BOOLEAN endOfValue; - length = CommandLine->Length / 2; + length = CommandLine->Length / sizeof(WCHAR); i = *Index; // This function follows the rules used by CommandLineToArgvW: @@ -4496,7 +4496,7 @@ PPH_STRING PhParseCommandLinePart( if (numberOfBackslashes != 0) { - PhAppendCharStringBuilder2(&stringBuilder, '\\', numberOfBackslashes); + PhAppendCharStringBuilder2(&stringBuilder, OBJ_NAME_PATH_SEPARATOR, numberOfBackslashes); numberOfBackslashes = 0; } @@ -4507,7 +4507,7 @@ PPH_STRING PhParseCommandLinePart( else { numberOfBackslashes /= 2; - PhAppendCharStringBuilder2(&stringBuilder, '\\', numberOfBackslashes); + PhAppendCharStringBuilder2(&stringBuilder, OBJ_NAME_PATH_SEPARATOR, numberOfBackslashes); numberOfBackslashes = 0; } } @@ -4521,7 +4521,7 @@ PPH_STRING PhParseCommandLinePart( default: if (numberOfBackslashes != 0) { - PhAppendCharStringBuilder2(&stringBuilder, '\\', numberOfBackslashes); + PhAppendCharStringBuilder2(&stringBuilder, OBJ_NAME_PATH_SEPARATOR, numberOfBackslashes); numberOfBackslashes = 0; } @@ -4583,7 +4583,7 @@ BOOLEAN PhParseCommandLine( return TRUE; i = 0; - length = CommandLine->Length / 2; + length = CommandLine->Length / sizeof(WCHAR); while (TRUE) { @@ -4630,7 +4630,7 @@ BOOLEAN PhParseCommandLine( optionNameLength = i - originalIndex; optionName.Buffer = &CommandLine->Buffer[originalIndex]; - optionName.Length = optionNameLength * 2; + optionName.Length = optionNameLength * sizeof(WCHAR); // Take care of any pending optional argument. @@ -4724,8 +4724,8 @@ PPH_STRING PhEscapeCommandLinePart( ULONG numberOfBackslashes; - length = (ULONG)String->Length / 2; - PhInitializeStringBuilder(&stringBuilder, String->Length / 2 * 3); + length = (ULONG)String->Length / sizeof(WCHAR); + PhInitializeStringBuilder(&stringBuilder, String->Length / sizeof(WCHAR) * 3); numberOfBackslashes = 0; // Simply replacing " with \" won't work here. See PhParseCommandLinePart for the quoting rules. @@ -4740,7 +4740,7 @@ PPH_STRING PhEscapeCommandLinePart( case '\"': if (numberOfBackslashes != 0) { - PhAppendCharStringBuilder2(&stringBuilder, '\\', numberOfBackslashes * 2); + PhAppendCharStringBuilder2(&stringBuilder, OBJ_NAME_PATH_SEPARATOR, numberOfBackslashes * 2); numberOfBackslashes = 0; } @@ -4750,7 +4750,7 @@ PPH_STRING PhEscapeCommandLinePart( default: if (numberOfBackslashes != 0) { - PhAppendCharStringBuilder2(&stringBuilder, '\\', numberOfBackslashes); + PhAppendCharStringBuilder2(&stringBuilder, OBJ_NAME_PATH_SEPARATOR, numberOfBackslashes); numberOfBackslashes = 0; } @@ -5368,7 +5368,7 @@ PPH_STRING PhGetDllFileName( if (IndexOfFileName) { - indexOfFileName = PhFindLastCharInString(fileName, 0, '\\'); + indexOfFileName = PhFindLastCharInString(fileName, 0, OBJ_NAME_PATH_SEPARATOR); if (indexOfFileName != -1) indexOfFileName++; @@ -5689,7 +5689,7 @@ static NTSTATUS PhpFixupLoaderEntryImageImports( if (PhEqualBytesZ(importName, "ProcessHacker.exe", FALSE)) { - importBaseAddress = NtCurrentPeb()->ImageBaseAddress; + importBaseAddress = PhInstanceHandle; } else { diff --git a/phnt/include/phnt_ntdef.h b/phnt/include/phnt_ntdef.h index 36cc781b4b97..b3ecedca9fc2 100644 --- a/phnt/include/phnt_ntdef.h +++ b/phnt/include/phnt_ntdef.h @@ -213,6 +213,8 @@ typedef const OBJECT_ATTRIBUTES *PCOBJECT_ATTRIBUTES; #define RTL_CONSTANT_OBJECT_ATTRIBUTES(n, a) { sizeof(OBJECT_ATTRIBUTES), NULL, n, a, NULL, NULL } #define RTL_INIT_OBJECT_ATTRIBUTES(n, a) RTL_CONSTANT_OBJECT_ATTRIBUTES(n, a) +#define OBJ_NAME_PATH_SEPARATOR ((WCHAR)L'\\') + // Portability typedef struct _OBJECT_ATTRIBUTES64 diff --git a/plugins/DotNetTools/asmpage.c b/plugins/DotNetTools/asmpage.c index df80c57ed190..b303f2694a98 100644 --- a/plugins/DotNetTools/asmpage.c +++ b/plugins/DotNetTools/asmpage.c @@ -848,7 +848,7 @@ VOID NTAPI DotNetEventCallback( // Use the name between the last backslash and the last dot for the structure column text. // (E.g. C:\...\AcmeSoft.BigLib.dll -> AcmeSoft.BigLib) - indexOfBackslash = PhFindLastCharInString(node->PathText, 0, '\\'); + indexOfBackslash = PhFindLastCharInString(node->PathText, 0, OBJ_NAME_PATH_SEPARATOR); indexOfLastDot = PhFindLastCharInString(node->PathText, 0, '.'); if (indexOfBackslash != -1) diff --git a/plugins/ExtendedNotifications/main.c b/plugins/ExtendedNotifications/main.c index decda3f7e088..e9905e86acf7 100644 --- a/plugins/ExtendedNotifications/main.c +++ b/plugins/ExtendedNotifications/main.c @@ -380,7 +380,7 @@ BOOLEAN MatchFilterList( ULONG i; BOOLEAN isFileName; - isFileName = PhFindCharInString(String, 0, '\\') != -1; + isFileName = PhFindCharInString(String, 0, OBJ_NAME_PATH_SEPARATOR) != -1; for (i = 0; i < FilterList->Count; i++) { diff --git a/tools/peview/peprp.c b/tools/peview/peprp.c index 1e2773b3023f..46e753156506 100644 --- a/tools/peview/peprp.c +++ b/tools/peview/peprp.c @@ -242,7 +242,7 @@ VERIFY_RESULT PvpVerifyFileWithAdditionalCatalog( remainingFileName = FileName->sr; PhSkipStringRef(&remainingFileName, windowsAppsPath->Length); - indexOfBackslash = PhFindCharInStringRef(&remainingFileName, '\\', FALSE); + indexOfBackslash = PhFindCharInStringRef(&remainingFileName, OBJ_NAME_PATH_SEPARATOR, FALSE); if (indexOfBackslash != -1) { diff --git a/tools/peview/prpsh.c b/tools/peview/prpsh.c index f00bfe4021df..bd6ff160c24e 100644 --- a/tools/peview/prpsh.c +++ b/tools/peview/prpsh.c @@ -220,7 +220,7 @@ LRESULT CALLBACK PvpPropSheetWndProc( tabItem.mask = TCIF_TEXT; tabItem.pszText = text; - tabItem.cchTextMax = sizeof(text) / 2 - 1; + tabItem.cchTextMax = RTL_NUMBER_OF(text) - 1; if (TabCtrl_GetItem(tabControl, TabCtrl_GetCurSel(tabControl), &tabItem)) { From 54d3d19235dcdf5143c68cd68acc44e888dc1a8c Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 3 May 2018 05:12:57 +1000 Subject: [PATCH 0924/2058] Update PhPluginAddTreeNewColumn callbacks --- ProcessHacker/colmgr.c | 2 +- ProcessHacker/include/phplug.h | 1 + ProcessHacker/netlist.c | 6 +++--- plugins/DotNetTools/treeext.c | 2 ++ plugins/ExtendedTools/treeext.c | 4 ++++ plugins/NetworkTools/main.c | 7 ++++--- plugins/OnlineChecks/main.c | 8 ++++++-- plugins/UserNotes/main.c | 2 ++ 8 files changed, 23 insertions(+), 9 deletions(-) diff --git a/ProcessHacker/colmgr.c b/ProcessHacker/colmgr.c index 3f4aafb68c40..fd2765d1467a 100644 --- a/ProcessHacker/colmgr.c +++ b/ProcessHacker/colmgr.c @@ -258,7 +258,7 @@ static int __cdecl PhCmpSortFunction( PVOID node2 = *(PVOID *)elem2; LONG result; - result = sortContext->SortFunction(node1, node2, sortContext->SubId, sortContext->Context); + result = sortContext->SortFunction(node1, node2, sortContext->SubId, sortContext->SortOrder, sortContext->Context); return sortContext->PostSortFunction(result, node1, node2, sortContext->SortOrder); } diff --git a/ProcessHacker/include/phplug.h b/ProcessHacker/include/phplug.h index f7d00fc2e765..35c23d954785 100644 --- a/ProcessHacker/include/phplug.h +++ b/ProcessHacker/include/phplug.h @@ -416,6 +416,7 @@ typedef LONG (NTAPI *PPH_PLUGIN_TREENEW_SORT_FUNCTION)( _In_ PVOID Node1, _In_ PVOID Node2, _In_ ULONG SubId, + _In_ PH_SORT_ORDER SortOrder, _In_ PVOID Context ); diff --git a/ProcessHacker/netlist.c b/ProcessHacker/netlist.c index cf1983b12102..8393fccc408b 100644 --- a/ProcessHacker/netlist.c +++ b/ProcessHacker/netlist.c @@ -377,7 +377,7 @@ END_SORT_FUNCTION BEGIN_SORT_FUNCTION(LocalHostname) { - sortResult = PhCompareStringWithNull(networkItem1->LocalHostString, networkItem2->LocalHostString, TRUE); + sortResult = PhCompareStringWithNullSortOrder(networkItem1->LocalHostString, networkItem2->LocalHostString, NetworkTreeListSortOrder, TRUE); } END_SORT_FUNCTION @@ -395,7 +395,7 @@ END_SORT_FUNCTION BEGIN_SORT_FUNCTION(RemoteHostname) { - sortResult = PhCompareStringWithNull(networkItem1->RemoteHostString, networkItem2->RemoteHostString, TRUE); + sortResult = PhCompareStringWithNullSortOrder(networkItem1->RemoteHostString, networkItem2->RemoteHostString, NetworkTreeListSortOrder, TRUE); } END_SORT_FUNCTION @@ -419,7 +419,7 @@ END_SORT_FUNCTION BEGIN_SORT_FUNCTION(Owner) { - sortResult = PhCompareStringWithNull(networkItem1->OwnerName, networkItem2->OwnerName, TRUE); + sortResult = PhCompareStringWithNullSortOrder(networkItem1->OwnerName, networkItem2->OwnerName, NetworkTreeListSortOrder, TRUE); } END_SORT_FUNCTION diff --git a/plugins/DotNetTools/treeext.c b/plugins/DotNetTools/treeext.c index 874e899718a9..e30af549d2be 100644 --- a/plugins/DotNetTools/treeext.c +++ b/plugins/DotNetTools/treeext.c @@ -43,6 +43,7 @@ LONG ThreadTreeNewSortFunction( _In_ PVOID Node1, _In_ PVOID Node2, _In_ ULONG SubId, + _In_ PH_SORT_ORDER SortOrder, _In_ PVOID Context ); @@ -268,6 +269,7 @@ LONG ThreadTreeNewSortFunction( _In_ PVOID Node1, _In_ PVOID Node2, _In_ ULONG SubId, + _In_ PH_SORT_ORDER SortOrder, _In_ PVOID Context ) { diff --git a/plugins/ExtendedTools/treeext.c b/plugins/ExtendedTools/treeext.c index ac9a2e133b44..cad709645797 100644 --- a/plugins/ExtendedTools/treeext.c +++ b/plugins/ExtendedTools/treeext.c @@ -29,6 +29,7 @@ LONG EtpProcessTreeNewSortFunction( _In_ PVOID Node1, _In_ PVOID Node2, _In_ ULONG SubId, + _In_ PH_SORT_ORDER SortOrder, _In_ PVOID Context ); @@ -36,6 +37,7 @@ LONG EtpNetworkTreeNewSortFunction( _In_ PVOID Node1, _In_ PVOID Node2, _In_ ULONG SubId, + _In_ PH_SORT_ORDER SortOrder, _In_ PVOID Context ); @@ -358,6 +360,7 @@ LONG EtpProcessTreeNewSortFunction( _In_ PVOID Node1, _In_ PVOID Node2, _In_ ULONG SubId, + _In_ PH_SORT_ORDER SortOrder, _In_ PVOID Context ) { @@ -638,6 +641,7 @@ LONG EtpNetworkTreeNewSortFunction( _In_ PVOID Node1, _In_ PVOID Node2, _In_ ULONG SubId, + _In_ PH_SORT_ORDER SortOrder, _In_ PVOID Context ) { diff --git a/plugins/NetworkTools/main.c b/plugins/NetworkTools/main.c index b40be0fb3dd3..a2e8bb24db43 100644 --- a/plugins/NetworkTools/main.c +++ b/plugins/NetworkTools/main.c @@ -329,6 +329,7 @@ LONG NTAPI NetworkServiceSortFunction( _In_ PVOID Node1, _In_ PVOID Node2, _In_ ULONG SubId, + _In_ PH_SORT_ORDER SortOrder, _In_ PVOID Context ) { @@ -340,11 +341,11 @@ LONG NTAPI NetworkServiceSortFunction( switch (SubId) { case NETWORK_COLUMN_ID_REMOTE_COUNTRY: - return PhCompareStringWithNull(extension1->RemoteCountryCode, extension2->RemoteCountryCode, TRUE); + return PhCompareStringWithNullSortOrder(extension1->RemoteCountryCode, extension2->RemoteCountryCode, SortOrder, TRUE); case NETWORK_COLUMN_ID_LOCAL_SERVICE: - return PhCompareStringWithNull(extension1->LocalServiceName, extension2->LocalServiceName, TRUE); + return PhCompareStringWithNullSortOrder(extension1->LocalServiceName, extension2->LocalServiceName, SortOrder, TRUE); case NETWORK_COLUMN_ID_REMOTE_SERVICE: - return PhCompareStringWithNull(extension1->RemoteServiceName, extension2->RemoteServiceName, TRUE); + return PhCompareStringWithNullSortOrder(extension1->RemoteServiceName, extension2->RemoteServiceName, SortOrder, TRUE); case NETWORK_COLUMN_ID_BYTES_IN: return uint64cmp(extension1->NumberOfBytesIn, extension2->NumberOfBytesIn); case NETWORK_COLUMN_ID_BYTES_OUT: diff --git a/plugins/OnlineChecks/main.c b/plugins/OnlineChecks/main.c index 1aef27e43015..69c5bd2dc4fc 100644 --- a/plugins/OnlineChecks/main.c +++ b/plugins/OnlineChecks/main.c @@ -55,10 +55,11 @@ VOID ProcessesUpdatedCallback( if (!VirusTotalScanningEnabled) return; - ProcessesUpdatedCount++; - if (ProcessesUpdatedCount < 2) + { + ProcessesUpdatedCount++; return; + } listEntry = ProcessListHead.Flink; @@ -423,6 +424,7 @@ LONG NTAPI VirusTotalProcessNodeSortFunction( _In_ PVOID Node1, _In_ PVOID Node2, _In_ ULONG SubId, + _In_ PH_SORT_ORDER SortOrder, _In_ PVOID Context ) { @@ -438,6 +440,7 @@ LONG NTAPI VirusTotalModuleNodeSortFunction( _In_ PVOID Node1, _In_ PVOID Node2, _In_ ULONG SubId, + _In_ PH_SORT_ORDER SortOrder, _In_ PVOID Context ) { @@ -453,6 +456,7 @@ LONG NTAPI VirusTotalServiceNodeSortFunction( _In_ PVOID Node1, _In_ PVOID Node2, _In_ ULONG SubId, + _In_ PH_SORT_ORDER SortOrder, _In_ PVOID Context ) { diff --git a/plugins/UserNotes/main.c b/plugins/UserNotes/main.c index 57f01835f85d..e669d921ad30 100644 --- a/plugins/UserNotes/main.c +++ b/plugins/UserNotes/main.c @@ -1019,6 +1019,7 @@ static LONG NTAPI ProcessCommentSortFunction( _In_ PVOID Node1, _In_ PVOID Node2, _In_ ULONG SubId, + _In_ PH_SORT_ORDER SortOrder, _In_ PVOID Context ) { @@ -1101,6 +1102,7 @@ LONG NTAPI ServiceCommentSortFunction( _In_ PVOID Node1, _In_ PVOID Node2, _In_ ULONG SubId, + _In_ PH_SORT_ORDER SortOrder, _In_ PVOID Context ) { From 44857efb074027e57b228fbcfd395965c8bbd8ed Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 3 May 2018 05:31:49 +1000 Subject: [PATCH 0925/2058] Add new Options -> General -> 'Check services for digital signatures' checkbox --- ProcessHacker/include/phsettings.h | 1 + ProcessHacker/include/srvlist.h | 1 - ProcessHacker/options.c | 18 +++++++++++------- ProcessHacker/settings.c | 21 +++++++++++---------- ProcessHacker/srvlist.c | 8 +------- ProcessHacker/srvprv.c | 5 ++--- 6 files changed, 26 insertions(+), 28 deletions(-) diff --git a/ProcessHacker/include/phsettings.h b/ProcessHacker/include/phsettings.h index f44b6ed259e6..6736aca2d197 100644 --- a/ProcessHacker/include/phsettings.h +++ b/ProcessHacker/include/phsettings.h @@ -12,6 +12,7 @@ #endif EXT BOOLEAN PhEnableProcessQueryStage2; +EXT BOOLEAN PhEnableServiceQueryStage2; EXT ULONG PhCsCollapseServicesOnStart; EXT ULONG PhCsForceNoParent; diff --git a/ProcessHacker/include/srvlist.h b/ProcessHacker/include/srvlist.h index 0c3cd530901a..193d8127adbc 100644 --- a/ProcessHacker/include/srvlist.h +++ b/ProcessHacker/include/srvlist.h @@ -51,7 +51,6 @@ typedef struct _PH_SERVICE_NODE LARGE_INTEGER KeyLastWriteTime; PPH_STRING TooltipText; PPH_STRING KeyModifiedTimeText; - BOOLEAN ServiceQueryStage2; // begin_phapppub } PH_SERVICE_NODE, *PPH_SERVICE_NODE; // end_phapppub diff --git a/ProcessHacker/options.c b/ProcessHacker/options.c index ed6c4266baa9..f5eed6009d7f 100644 --- a/ProcessHacker/options.c +++ b/ProcessHacker/options.c @@ -3,7 +3,7 @@ * options window * * Copyright (C) 2010-2016 wj32 - * Copyright (C) 2017 dmex + * Copyright (C) 2017-2018 dmex * * This file is part of Process Hacker. * @@ -952,6 +952,7 @@ typedef enum _PHP_OPTIONS_INDEX PHP_OPTIONS_INDEX_ENABLE_INSTANT_TOOLTIPS, PHP_OPTIONS_INDEX_ENABLE_CYCLE_CPU_USAGE, PHP_OPTIONS_INDEX_ENABLE_STAGE2, + PHP_OPTIONS_INDEX_ENABLE_SERVICE_STAGE2, PHP_OPTIONS_INDEX_COLLAPSE_SERVICES_ON_START, PHP_OPTIONS_INDEX_ICON_SINGLE_CLICK, PHP_OPTIONS_INDEX_ICON_TOGGLE_VISIBILITY, @@ -996,6 +997,7 @@ static VOID PhpAdvancedPageLoad( PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_INSTANT_TOOLTIPS, L"Show tooltips instantly", NULL); PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_CYCLE_CPU_USAGE, L"Enable cycle-based CPU usage", NULL); PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_STAGE2, L"Check images for digital signatures", NULL); + PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_SERVICE_STAGE2, L"Check services for digital signatures", NULL); PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_COLLAPSE_SERVICES_ON_START, L"Collapse services on start", NULL); PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_ICON_SINGLE_CLICK, L"Single-click tray icons", NULL); PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_ICON_TOGGLE_VISIBILITY, L"Icon click toggles visibility", NULL); @@ -1014,6 +1016,7 @@ static VOID PhpAdvancedPageLoad( SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_INSTANT_TOOLTIPS, L"EnableInstantTooltips"); SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_CYCLE_CPU_USAGE, L"EnableCycleCpuUsage"); SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_STAGE2, L"EnableStage2"); + SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_SERVICE_STAGE2, L"EnableServiceStage2"); SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_COLLAPSE_SERVICES_ON_START, L"CollapseServicesOnStart"); SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_ICON_SINGLE_CLICK, L"IconSingleClick"); SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_ICON_TOGGLE_VISIBILITY, L"IconTogglesVisibility"); @@ -1075,6 +1078,7 @@ static VOID PhpAdvancedPageSave( SetSettingForLvItemCheck(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_INSTANT_TOOLTIPS, L"EnableInstantTooltips"); SetSettingForLvItemCheckRestartRequired(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_CYCLE_CPU_USAGE, L"EnableCycleCpuUsage"); SetSettingForLvItemCheckRestartRequired(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_STAGE2, L"EnableStage2"); + SetSettingForLvItemCheckRestartRequired(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_SERVICE_STAGE2, L"EnableServiceStage2"); SetSettingForLvItemCheck(listViewHandle, PHP_OPTIONS_INDEX_COLLAPSE_SERVICES_ON_START, L"CollapseServicesOnStart"); SetSettingForLvItemCheck(listViewHandle, PHP_OPTIONS_INDEX_ICON_SINGLE_CLICK, L"IconSingleClick"); SetSettingForLvItemCheck(listViewHandle, PHP_OPTIONS_INDEX_ICON_TOGGLE_VISIBILITY, L"IconTogglesVisibility"); @@ -1144,13 +1148,13 @@ INT_PTR CALLBACK PhpOptionsGeneralDlgProc( PhAddListViewColumn(listviewHandle, 0, 0, 0, LVCFMT_LEFT, 250, L"Name"); PhSetExtendedListView(listviewHandle); - for (i = 0; i < ARRAYSIZE(PhSizeUnitNames); i++) + for (i = 0; i < RTL_NUMBER_OF(PhSizeUnitNames); i++) ComboBox_AddString(comboBoxHandle, PhSizeUnitNames[i]); if (PhMaxSizeUnit != -1) ComboBox_SetCurSel(comboBoxHandle, PhMaxSizeUnit); else - ComboBox_SetCurSel(comboBoxHandle, ARRAYSIZE(PhSizeUnitNames) - 1); + ComboBox_SetCurSel(comboBoxHandle, RTL_NUMBER_OF(PhSizeUnitNames) - 1); PhSetDialogItemText(hwndDlg, IDC_SEARCHENGINE, PhaGetStringSetting(L"SearchEngine")->Buffer); PhSetDialogItemText(hwndDlg, IDC_PEVIEWER, PhaGetStringSetting(L"ProgramInspectExecutables")->Buffer); @@ -1709,7 +1713,7 @@ INT_PTR CALLBACK PhpOptionsHighlightingDlgProc( PhSetExtendedListView(HighlightingListViewHandle); ExtendedListView_SetItemColorFunction(HighlightingListViewHandle, PhpColorItemColorFunction); - for (ULONG i = 0; i < ARRAYSIZE(ColorItems); i++) + for (ULONG i = 0; i < RTL_NUMBER_OF(ColorItems); i++) { INT lvItemIndex; @@ -1732,7 +1736,7 @@ INT_PTR CALLBACK PhpOptionsHighlightingDlgProc( PH_SET_INTEGER_CACHED_SETTING(ColorNew, ColorBox_GetColor(GetDlgItem(hwndDlg, IDC_NEWOBJECTS))); PH_SET_INTEGER_CACHED_SETTING(ColorRemoved, ColorBox_GetColor(GetDlgItem(hwndDlg, IDC_REMOVEDOBJECTS))); - for (ULONG i = 0; i < ARRAYSIZE(ColorItems); i++) + for (ULONG i = 0; i < RTL_NUMBER_OF(ColorItems); i++) { ColorItems[i].CurrentUse = !!ListView_GetCheckState(HighlightingListViewHandle, i); PhSetIntegerSetting(ColorItems[i].SettingName, ColorItems[i].CurrentColor); @@ -1755,13 +1759,13 @@ INT_PTR CALLBACK PhpOptionsHighlightingDlgProc( { case IDC_ENABLEALL: { - for (ULONG i = 0; i < ARRAYSIZE(ColorItems); i++) + for (ULONG i = 0; i < RTL_NUMBER_OF(ColorItems); i++) ListView_SetCheckState(HighlightingListViewHandle, i, TRUE); } break; case IDC_DISABLEALL: { - for (ULONG i = 0; i < ARRAYSIZE(ColorItems); i++) + for (ULONG i = 0; i < RTL_NUMBER_OF(ColorItems); i++) ListView_SetCheckState(HighlightingListViewHandle, i, FALSE); } break; diff --git a/ProcessHacker/settings.c b/ProcessHacker/settings.c index 9ac3dfffcdf8..7e47a22c77ef 100644 --- a/ProcessHacker/settings.c +++ b/ProcessHacker/settings.c @@ -49,6 +49,7 @@ VOID PhAddDefaultSettings( PhpAddIntegerSetting(L"EnablePlugins", L"1"); PhpAddIntegerSetting(L"EnableServiceNonPoll", L"1"); PhpAddIntegerSetting(L"EnableStage2", L"1"); + PhpAddIntegerSetting(L"EnableServiceStage2", L"0"); PhpAddIntegerSetting(L"EnableWarnings", L"1"); PhpAddIntegerSetting(L"EnableWindowText", L"1"); PhpAddIntegerSetting(L"EnableSecurityAdvancedDialog", L"1"); @@ -209,6 +210,10 @@ VOID PhAddDefaultSettings( PhpAddIntegerSetting(L"ColorProtectedHandles", L"777777"); PhpAddIntegerSetting(L"UseColorInheritHandles", L"1"); PhpAddIntegerSetting(L"ColorInheritHandles", L"ffff77"); + PhpAddIntegerSetting(L"UseColorServiceStop", L"1"); + PhpAddIntegerSetting(L"ColorServiceStop", L"6d6d6d"); // Dark grey + PhpAddIntegerSetting(L"UseColorUnknown", L"1"); + PhpAddIntegerSetting(L"ColorUnknown", L"8080ff"); // Light Red PhpAddIntegerSetting(L"GraphShowText", L"1"); PhpAddIntegerSetting(L"GraphColorMode", L"0"); @@ -219,11 +224,6 @@ VOID PhAddDefaultSettings( PhpAddIntegerSetting(L"ColorPrivate", L"0077ff"); PhpAddIntegerSetting(L"ColorPhysical", L"ff8000"); // Blue - PhpAddIntegerSetting(L"UseColorServiceStop", L"1"); - PhpAddIntegerSetting(L"ColorServiceStop", L"6d6d6d"); // Dark grey - PhpAddIntegerSetting(L"UseColorUnknown", L"1"); - PhpAddIntegerSetting(L"ColorUnknown", L"ff8080"); // Light Red - // Experimental features PhpAddIntegerSetting(L"EnableExperimentalWindowStyle", L"0"); } @@ -240,6 +240,7 @@ VOID PhUpdateCachedSettings( PH_UPDATE_SETTING(ShowCpuBelow001); PH_UPDATE_SETTING(ShowHexId); PH_UPDATE_SETTING(UpdateInterval); + PH_UPDATE_SETTING(ColorNew); PH_UPDATE_SETTING(ColorRemoved); PH_UPDATE_SETTING(UseColorOwnProcesses); @@ -276,6 +277,11 @@ VOID PhUpdateCachedSettings( PH_UPDATE_SETTING(ColorProtectedHandles); PH_UPDATE_SETTING(UseColorInheritHandles); PH_UPDATE_SETTING(ColorInheritHandles); + PH_UPDATE_SETTING(UseColorServiceStop); + PH_UPDATE_SETTING(ColorServiceStop); + PH_UPDATE_SETTING(UseColorUnknown); + PH_UPDATE_SETTING(ColorUnknown); + PH_UPDATE_SETTING(GraphShowText); PH_UPDATE_SETTING(GraphColorMode); PH_UPDATE_SETTING(ColorCpuKernel); @@ -284,9 +290,4 @@ VOID PhUpdateCachedSettings( PH_UPDATE_SETTING(ColorIoWrite); PH_UPDATE_SETTING(ColorPrivate); PH_UPDATE_SETTING(ColorPhysical); - - PH_UPDATE_SETTING(UseColorServiceStop); - PH_UPDATE_SETTING(ColorServiceStop); - PH_UPDATE_SETTING(UseColorUnknown); - PH_UPDATE_SETTING(ColorUnknown); } diff --git a/ProcessHacker/srvlist.c b/ProcessHacker/srvlist.c index 46bc613ba4ac..f6df1fd83a51 100644 --- a/ProcessHacker/srvlist.c +++ b/ProcessHacker/srvlist.c @@ -771,12 +771,6 @@ BOOLEAN NTAPI PhpServiceTreeNewCallback( ServiceIconsLoaded = TRUE; } - if (!node->ServiceQueryStage2) - { - PhQueueServiceQueryStage2(node->ServiceItem); - node->ServiceQueryStage2 = TRUE; - } - if (node->ServiceItem->SmallIcon) getNodeIcon->Icon = node->ServiceItem->SmallIcon; else @@ -800,7 +794,7 @@ BOOLEAN NTAPI PhpServiceTreeNewCallback( if (!serviceItem) ; // Dummy - else if (PhEnableProcessQueryStage2 && PhCsUseColorUnknown && serviceItem->VerifyResult != VrTrusted) + else if (PhEnableServiceQueryStage2 && PhCsUseColorUnknown && serviceItem->VerifyResult != VrTrusted) { getNodeColor->BackColor = PhCsColorUnknown; getNodeColor->Flags |= TN_AUTO_FORECOLOR; diff --git a/ProcessHacker/srvprv.c b/ProcessHacker/srvprv.c index 4c99f5afa74a..61d9d51d867d 100644 --- a/ProcessHacker/srvprv.c +++ b/ProcessHacker/srvprv.c @@ -616,7 +616,7 @@ VOID PhQueueServiceQueryStage2( { PH_WORK_QUEUE_ENVIRONMENT environment; - if (!PhEnableProcessQueryStage2) + if (!PhEnableServiceQueryStage2) return; PhReferenceObject(ServiceItem); @@ -641,8 +641,7 @@ VOID PhpFillServiceItemStage1( //memcpy(&processItem->VersionInfo, &Data->VersionInfo, sizeof(PH_IMAGE_VERSION_INFO)); // Note: Queue stage 2 processing after filling stage1 process data. - // HACK: We delay-load stage processing for services from the TreeNewGetNodeIcon callback in srvlist.c. - //PhQueueServiceQueryStage2(serviceItem); + PhQueueServiceQueryStage2(serviceItem); } VOID PhpFillServiceItemStage2( From be9575187446cf2c4e35e7f445998d6fceb6f8c2 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 3 May 2018 05:47:58 +1000 Subject: [PATCH 0926/2058] Update headers with RS4 types --- phnt/include/ntexapi.h | 94 ++++++++++++++++++++++++++++++++++++----- phnt/include/ntpebteb.h | 13 ++++-- phnt/include/ntpsapi.h | 16 ++++++- 3 files changed, 107 insertions(+), 16 deletions(-) diff --git a/phnt/include/ntexapi.h b/phnt/include/ntexapi.h index 815ee07fa6f8..88e39146b788 100644 --- a/phnt/include/ntexapi.h +++ b/phnt/include/ntexapi.h @@ -1394,13 +1394,13 @@ typedef enum _SYSTEM_INFORMATION_CLASS SystemSecureDumpEncryptionInformation, SystemWriteConstraintInformation, // SYSTEM_WRITE_CONSTRAINT_INFORMATION SystemKernelVaShadowInformation, // SYSTEM_KERNEL_VA_SHADOW_INFORMATION - SystemHypervisorSharedPageInformation, // SYSTEM_HYPERVISOR_SHARED_PAGE_INFORMATION // REDSTONE4 + SystemHypervisorSharedPageInformation, // SYSTEM_HYPERVISOR_SHARED_PAGE_INFORMATION // since REDSTONE4 SystemFirmwareBootPerformanceInformation, - SystemCodeIntegrityVerificationInformation, + SystemCodeIntegrityVerificationInformation, // SYSTEM_CODEINTEGRITYVERIFICATION_INFORMATION SystemFirmwarePartitionInformation, // 200 SystemSpeculationControlInformation, // SYSTEM_SPECULATION_CONTROL_INFORMATION // (CVE-2017-5715) REDSTONE3 and above. - SystemDmaGuardPolicyInformation, - SystemEnclaveLaunchControlInformation, + SystemDmaGuardPolicyInformation, // SYSTEM_DMA_GUARD_POLICY_INFORMATION + SystemEnclaveLaunchControlInformation, // SYSTEM_ENCLAVE_LAUNCH_CONTROL_INFORMATION MaxSystemInfoClass } SYSTEM_INFORMATION_CLASS; @@ -1424,7 +1424,7 @@ typedef struct _SYSTEM_PROCESSOR_INFORMATION USHORT ProcessorArchitecture; USHORT ProcessorLevel; USHORT ProcessorRevision; - USHORT ProcessorCount; + USHORT MaximumProcessors; ULONG ProcessorFeatureBits; } SYSTEM_PROCESSOR_INFORMATION, *PSYSTEM_PROCESSOR_INFORMATION; @@ -1845,6 +1845,11 @@ typedef enum _EVENT_TRACE_INFORMATION_CLASS EventTraceSoftRestartInformation, // EVENT_TRACE_SOFT_RESTART_INFORMATION EventTraceLastBranchConfigurationInformation, // REDSTONE3 EventTraceLastBranchEventListInformation, + EventTraceProfileSourceAddInformation, // EVENT_TRACE_PROFILE_ADD_INFORMATION // REDSTONE4 + EventTraceProfileSourceRemoveInformation, // EVENT_TRACE_PROFILE_REMOVE_INFORMATION + EventTraceProcessorTraceConfigurationInformation, + EventTraceProcessorTraceEventListInformation, + EventTraceCoverageSamplerInformation, // EVENT_TRACE_COVERAGE_SAMPLER_INFORMATION MaxEventTraceInfoClass } EVENT_TRACE_INFORMATION_CLASS; @@ -1955,6 +1960,36 @@ typedef struct _EVENT_TRACE_SOFT_RESTART_INFORMATION WCHAR FileName[1]; } EVENT_TRACE_SOFT_RESTART_INFORMATION, *PEVENT_TRACE_SOFT_RESTART_INFORMATION; +typedef struct _EVENT_TRACE_PROFILE_ADD_INFORMATION +{ + EVENT_TRACE_INFORMATION_CLASS EventTraceInformationClass; + BOOLEAN PerfEvtEventSelect; + BOOLEAN PerfEvtUnitSelect; + ULONG PerfEvtType; + ULONG CpuInfoHierarchy[0x3]; + ULONG InitialInterval; + BOOLEAN AllowsHalt; + BOOLEAN Persist; + WCHAR ProfileSourceDescription[0x1]; +} EVENT_TRACE_PROFILE_ADD_INFORMATION, *PEVENT_TRACE_PROFILE_ADD_INFORMATION; + +typedef struct _EVENT_TRACE_PROFILE_REMOVE_INFORMATION +{ + EVENT_TRACE_INFORMATION_CLASS EventTraceInformationClass; + KPROFILE_SOURCE ProfileSource; + ULONG CpuInfoHierarchy[0x3]; +} EVENT_TRACE_PROFILE_REMOVE_INFORMATION, *PEVENT_TRACE_PROFILE_REMOVE_INFORMATION; + +typedef struct _EVENT_TRACE_COVERAGE_SAMPLER_INFORMATION +{ + EVENT_TRACE_INFORMATION_CLASS EventTraceInformationClass; + BOOLEAN CoverageSamplerInformationClass; + UCHAR MajorVersion; + UCHAR MinorVersion; + UCHAR Reserved; + HANDLE SamplerHandle; +} EVENT_TRACE_COVERAGE_SAMPLER_INFORMATION, *PEVENT_TRACE_COVERAGE_SAMPLER_INFORMATION; + typedef struct _SYSTEM_EXCEPTION_INFORMATION { ULONG AlignmentFixupCount; @@ -2256,7 +2291,17 @@ typedef struct _SYSTEM_BOOT_ENVIRONMENT_INFORMATION { GUID BootIdentifier; FIRMWARE_TYPE FirmwareType; - ULONGLONG BootFlags; + union + { + ULONGLONG BootFlags; + struct + { + ULONGLONG DbgMenuOsSelection : 1; // REDSTONE4 + ULONGLONG DbgHiberBoot : 1; + ULONGLONG DbgSoftBoot : 1; + ULONGLONG DbgMeasuredLaunch : 1; + }; + }; } SYSTEM_BOOT_ENVIRONMENT_INFORMATION, *PSYSTEM_BOOT_ENVIRONMENT_INFORMATION; // private @@ -2788,6 +2833,7 @@ typedef enum _SYSTEM_PROCESS_CLASSIFICATION SystemProcessClassificationSystem, SystemProcessClassificationSecureSystem, SystemProcessClassificationMemCompression, + SystemProcessClassificationRegistry, // REDSTONE4 SystemProcessClassificationMaximum } SYSTEM_PROCESS_CLASSIFICATION; @@ -3007,6 +3053,7 @@ typedef struct _SYSTEM_MEMORY_USAGE_INFORMATION typedef struct _SYSTEM_CODEINTEGRITY_CERTIFICATE_INFORMATION { HANDLE ImageFile; + ULONG Type; // REDSTONE4 } SYSTEM_CODEINTEGRITY_CERTIFICATE_INFORMATION, *PSYSTEM_CODEINTEGRITY_CERTIFICATE_INFORMATION; // private @@ -3021,8 +3068,8 @@ typedef struct _SYSTEM_PHYSICAL_MEMORY_INFORMATION typedef enum _SYSTEM_ACTIVITY_MODERATION_STATE { SystemActivityModerationStateSystemManaged, - SystemActivityModerationStateAlwaysThrottled, - SystemActivityModerationStateNeverThrottled, + SystemActivityModerationStateUserManagedAllowThrottling, + SystemActivityModerationStateUserManagedDisableThrottling, MaxSystemActivityModerationState } SYSTEM_ACTIVITY_MODERATION_STATE; @@ -3065,9 +3112,11 @@ typedef struct _SYSTEM_CODEINTEGRITY_UNLOCK_INFORMATION ULONG Locked : 1; ULONG Unlockable : 1; ULONG UnlockApplied : 1; - ULONG Reserved : 29; + ULONG UnlockIdValid : 1; // REDSTONE4 + ULONG Reserved : 28; }; }; + UCHAR UnlockId[32]; // REDSTONE4 } SYSTEM_CODEINTEGRITY_UNLOCK_INFORMATION, *PSYSTEM_CODEINTEGRITY_UNLOCK_INFORMATION; // private @@ -3098,11 +3147,21 @@ typedef struct _SYSTEM_KERNEL_VA_SHADOW_INFORMATION ULONG KvaShadowUserGlobal : 1; ULONG KvaShadowPcid : 1; ULONG KvaShadowInvpcid : 1; - ULONG Reserved : 28; + ULONG KvaShadowRequired : 1; // REDSTONE4 + ULONG KvaShadowRequiredAvailable : 1; + ULONG Reserved : 26; }; }; } SYSTEM_KERNEL_VA_SHADOW_INFORMATION, *PSYSTEM_KERNEL_VA_SHADOW_INFORMATION; +// private +typedef struct _SYSTEM_CODEINTEGRITYVERIFICATION_INFORMATION +{ + HANDLE FileHandle; + ULONG ImageSize; + PVOID Image; +} SYSTEM_CODEINTEGRITYVERIFICATION_INFORMATION, *PSYSTEM_CODEINTEGRITYVERIFICATION_INFORMATION; + // private typedef struct _SYSTEM_HYPERVISOR_SHARED_PAGE_INFORMATION { @@ -3130,6 +3189,18 @@ typedef struct _SYSTEM_SPECULATION_CONTROL_INFORMATION }; } SYSTEM_SPECULATION_CONTROL_INFORMATION, *PSYSTEM_SPECULATION_CONTROL_INFORMATION; +// private +typedef struct _SYSTEM_DMA_GUARD_POLICY_INFORMATION +{ + BOOLEAN DmaGuardPolicyEnabled; +} SYSTEM_DMA_GUARD_POLICY_INFORMATION, *PSYSTEM_DMA_GUARD_POLICY_INFORMATION; + +// private +typedef struct _SYSTEM_ENCLAVE_LAUNCH_CONTROL_INFORMATION +{ + UCHAR EnclaveLaunchSigner[32]; +} SYSTEM_ENCLAVE_LAUNCH_CONTROL_INFORMATION, *PSYSTEM_ENCLAVE_LAUNCH_CONTROL_INFORMATION; + #if (PHNT_MODE != PHNT_MODE_KERNEL) NTSYSCALLAPI @@ -3284,7 +3355,8 @@ typedef union _SYSDBG_LIVEDUMP_CONTROL_FLAGS ULONG UseDumpStorageStack : 1; ULONG CompressMemoryPagesData : 1; ULONG IncludeUserSpaceMemoryPages : 1; - ULONG Reserved : 29; + ULONG AbortIfMemoryPressure : 1; // REDSTONE4 + ULONG Reserved : 28; }; ULONG AsUlong; } SYSDBG_LIVEDUMP_CONTROL_FLAGS, *PSYSDBG_LIVEDUMP_CONTROL_FLAGS; diff --git a/phnt/include/ntpebteb.h b/phnt/include/ntpebteb.h index 10e458f7ada9..577097e51be2 100644 --- a/phnt/include/ntpebteb.h +++ b/phnt/include/ntpebteb.h @@ -84,8 +84,8 @@ typedef struct _PEB PVOID SubSystemData; PVOID ProcessHeap; PRTL_CRITICAL_SECTION FastPebLock; - PVOID AtlThunkSListPtr; PVOID IFEOKey; + PSLIST_HEADER AtlThunkSListPtr; union { ULONG CrossProcessFlags; @@ -193,19 +193,24 @@ typedef struct _PEB }; }; ULONGLONG CsrServerReadOnlySharedMemoryBase; - PVOID TppWorkerpListLock; + PRTL_CRITICAL_SECTION TppWorkerpListLock; LIST_ENTRY TppWorkerpList; PVOID WaitOnAddressHashTable[128]; PVOID TelemetryCoverageHeader; // REDSTONE3 ULONG CloudFileFlags; + ULONG CloudFileDiagFlags; // REDSTONE4 + CHAR PlaceholderCompatibilityMode; + CHAR PlaceholderCompatibilityModeReserved[7]; } PEB, *PPEB; #ifdef _WIN64 C_ASSERT(FIELD_OFFSET(PEB, SessionId) == 0x2C0); -C_ASSERT(sizeof(PEB) == 0x7B0); +//C_ASSERT(sizeof(PEB) == 0x7B0); // REDSTONE3 +C_ASSERT(sizeof(PEB) == 0x7B8); // REDSTONE4 #else C_ASSERT(FIELD_OFFSET(PEB, SessionId) == 0x1D4); -C_ASSERT(sizeof(PEB) == 0x468); +//C_ASSERT(sizeof(PEB) == 0x468); // REDSTONE3 +C_ASSERT(sizeof(PEB) == 0x470); #endif #define GDI_BATCH_BUFFER_SIZE 310 diff --git a/phnt/include/ntpsapi.h b/phnt/include/ntpsapi.h index fe1838afa42f..7de4443d8214 100644 --- a/phnt/include/ntpsapi.h +++ b/phnt/include/ntpsapi.h @@ -187,6 +187,9 @@ typedef enum _PROCESSINFOCLASS ProcessEnableReadWriteVmLogging, // PROCESS_READWRITEVM_LOGGING_INFORMATION ProcessUptimeInformation, // PROCESS_UPTIME_INFORMATION ProcessImageSection, + ProcessDebugAuthInformation, // since REDSTONE4 + ProcessSystemResourceManagement, // PROCESS_SYSTEM_RESOURCE_MANAGEMENT + ProcessSequenceNumber, // q: ULONGLONG MaxProcessInfoClass } PROCESSINFOCLASS; #endif @@ -837,6 +840,16 @@ typedef struct _PROCESS_UPTIME_INFORMATION }; } PROCESS_UPTIME_INFORMATION, *PPROCESS_UPTIME_INFORMATION; +typedef union _PROCESS_SYSTEM_RESOURCE_MANAGEMENT +{ + ULONG Flags; + struct + { + ULONG Foreground : 1; + ULONG Reserved : 31; + }; +} PROCESS_SYSTEM_RESOURCE_MANAGEMENT, *PPROCESS_SYSTEM_RESOURCE_MANAGEMENT; + // end_private #endif @@ -1521,7 +1534,8 @@ typedef enum _PS_MITIGATION_OPTION PS_MITIGATION_OPTION_EXPORT_ADDRESS_FILTER_PLUS, PS_MITIGATION_OPTION_RESTRICT_CHILD_PROCESS_CREATION, PS_MITIGATION_OPTION_IMPORT_ADDRESS_FILTER, - PS_MITIGATION_OPTION_MODULE_TAMPERING_PROTECTION + PS_MITIGATION_OPTION_MODULE_TAMPERING_PROTECTION, + PS_MITIGATION_OPTION_RESTRICT_INDIRECT_BRANCH_PREDICTION } PS_MITIGATION_OPTION; // windows-internals-book:"Chapter 5" From 85837ca22df5bfef76526819b71c09723fae9252 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 3 May 2018 08:00:28 +1000 Subject: [PATCH 0927/2058] Add new Desktop column to processes tab --- ProcessHacker/include/proctree.h | 5 +++- ProcessHacker/mainwnd.c | 5 ++-- ProcessHacker/proctree.c | 50 ++++++++++++++++++++++++++++++-- phlib/include/phnative.h | 8 +++++ phlib/native.c | 8 +++++ 5 files changed, 70 insertions(+), 6 deletions(-) diff --git a/ProcessHacker/include/proctree.h b/ProcessHacker/include/proctree.h index 889486cc13bb..400b33263670 100644 --- a/ProcessHacker/include/proctree.h +++ b/ProcessHacker/include/proctree.h @@ -92,8 +92,9 @@ #define PHPRTLC_SUBPROCESSCOUNT 79 #define PHPRTLC_JOBOBJECTID 80 #define PHPRTLC_PROTECTION 81 +#define PHPRTLC_DESKTOP 82 -#define PHPRTLC_MAXIMUM 82 +#define PHPRTLC_MAXIMUM 83 #define PHPRTLC_IOGROUP_COUNT 9 #define PHPN_WSCOUNTERS 0x1 @@ -108,6 +109,7 @@ #define PHPN_APPID 0x200 #define PHPN_DPIAWARENESS 0x400 #define PHPN_FILEATTRIBUTES 0x800 +#define PHPN_DESKTOPINFO 0x1000 // begin_phapppub typedef struct _PH_PROCESS_NODE @@ -219,6 +221,7 @@ typedef struct _PH_PROCESS_NODE PPH_STRING SubprocessCountText; WCHAR JobObjectIdText[PH_INT32_STR_LEN_1]; PPH_STRING ProtectionText; + PPH_STRING DesktopInfoText; // Graph buffers PH_GRAPH_BUFFERS CpuGraphBuffers; diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index 4948a40be56e..58f6344f71c8 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -1575,7 +1575,7 @@ VOID PhMwpOnInitMenuPopup( found = FALSE; - for (i = 0; i < sizeof(SubMenuHandles) / sizeof(HWND); i++) + for (i = 0; i < sizeof(SubMenuHandles) / sizeof(HMENU); i++) { if (Menu == SubMenuHandles[i]) { @@ -1588,7 +1588,8 @@ VOID PhMwpOnInitMenuPopup( return; // Delete all items in this submenu. - while (DeleteMenu(Menu, 0, MF_BYPOSITION)) ; + while (DeleteMenu(Menu, 0, MF_BYPOSITION)) + NOTHING; // Delete the previous EMENU for this submenu. if (SubMenuObjects[Index]) diff --git a/ProcessHacker/proctree.c b/ProcessHacker/proctree.c index 4c8a9df93458..a9f5e39f6bdf 100644 --- a/ProcessHacker/proctree.c +++ b/ProcessHacker/proctree.c @@ -212,6 +212,7 @@ VOID PhInitializeProcessTreeList( PhAddTreeNewColumnEx(hwnd, PHPRTLC_SUBPROCESSCOUNT, FALSE, L"Subprocesses", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); PhAddTreeNewColumnEx(hwnd, PHPRTLC_JOBOBJECTID, FALSE, L"Job Object ID", 50, PH_ALIGN_LEFT, -1, 0, TRUE); PhAddTreeNewColumnEx(hwnd, PHPRTLC_PROTECTION, FALSE, L"Protection", 105, PH_ALIGN_LEFT, -1, 0, TRUE); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_DESKTOP, FALSE, L"Desktop", 80, PH_ALIGN_LEFT, -1, 0, TRUE); TreeNew_SetRedraw(hwnd, TRUE); @@ -647,7 +648,7 @@ VOID PhTickProcessNodes( // The name and PID never change, so we don't invalidate that. memset(&node->TextCache[2], 0, sizeof(PH_STRINGREF) * (PHPRTLC_MAXIMUM - 2)); - node->ValidMask &= PHPN_OSCONTEXT | PHPN_IMAGE | PHPN_DPIAWARENESS | PHPN_APPID; // Items that always remain valid + node->ValidMask &= PHPN_OSCONTEXT | PHPN_IMAGE | PHPN_DPIAWARENESS | PHPN_APPID | PHPN_DESKTOPINFO; // Items that always remain valid // Invalidate graph buffers. node->CpuGraphBuffers.Valid = FALSE; @@ -1255,6 +1256,34 @@ static VOID PhpUpdateProcessNodeFileAttributes( } } +static VOID PhpUpdateProcessNodeDesktopInfo( + _Inout_ PPH_PROCESS_NODE ProcessNode + ) +{ + if (!(ProcessNode->ValidMask & PHPN_DESKTOPINFO)) + { + HANDLE processHandle; + + PhClearReference(&ProcessNode->DesktopInfoText); + + if (NT_SUCCESS(PhOpenProcess( + &processHandle, + ProcessQueryAccess | PROCESS_VM_READ, + ProcessNode->ProcessId + ))) + { + PPH_STRING desktopinfo; + + if (NT_SUCCESS(PhGetProcessDesktopInfo(processHandle, &desktopinfo))) + { + ProcessNode->DesktopInfoText = desktopinfo; + } + } + + ProcessNode->ValidMask |= PHPN_DESKTOPINFO; + } +} + #define SORT_FUNCTION(Column) PhpProcessTreeNewCompare##Column #define BEGIN_SORT_FUNCTION(Column) static int __cdecl PhpProcessTreeNewCompare##Column( \ @@ -1804,7 +1833,7 @@ END_SORT_FUNCTION BEGIN_SORT_FUNCTION(PackageName) { - sortResult = PhCompareStringWithNull(processItem1->PackageFullName, processItem2->PackageFullName, TRUE); + sortResult = PhCompareStringWithNullSortOrder(processItem1->PackageFullName, processItem2->PackageFullName, ProcessTreeListSortOrder, TRUE); } END_SORT_FUNCTION @@ -1812,7 +1841,7 @@ BEGIN_SORT_FUNCTION(AppId) { PhpUpdateProcessNodeAppId(node1); PhpUpdateProcessNodeAppId(node2); - sortResult = PhCompareStringWithNull(node1->AppIdText, node2->AppIdText, TRUE); + sortResult = PhCompareStringWithNullSortOrder(node1->AppIdText, node2->AppIdText, ProcessTreeListSortOrder, TRUE); } END_SORT_FUNCTION @@ -1874,6 +1903,14 @@ BEGIN_SORT_FUNCTION(Protection) } END_SORT_FUNCTION +BEGIN_SORT_FUNCTION(DesktopInfo) +{ + PhpUpdateProcessNodeDesktopInfo(node1); + PhpUpdateProcessNodeDesktopInfo(node2); + sortResult = PhCompareStringWithNullSortOrder(node1->DesktopInfoText, node2->DesktopInfoText, ProcessTreeListSortOrder, TRUE); +} +END_SORT_FUNCTION + BOOLEAN NTAPI PhpProcessTreeNewCallback( _In_ HWND hwnd, _In_ PH_TREENEW_MESSAGE Message, @@ -1996,6 +2033,7 @@ BOOLEAN NTAPI PhpProcessTreeNewCallback( SORT_FUNCTION(Subprocesses), SORT_FUNCTION(JobObjectId), SORT_FUNCTION(Protection), + SORT_FUNCTION(DesktopInfo) }; int (__cdecl *sortFunction)(const void *, const void *); @@ -2796,6 +2834,12 @@ BOOLEAN NTAPI PhpProcessTreeNewCallback( } } break; + case PHPRTLC_DESKTOP: + { + PhpUpdateProcessNodeDesktopInfo(node); + getCellText->Text = PhGetStringRef(node->DesktopInfoText); + } + break; default: return FALSE; } diff --git a/phlib/include/phnative.h b/phlib/include/phnative.h index 49ca8ba7be97..a9f2c0ad4def 100644 --- a/phlib/include/phnative.h +++ b/phlib/include/phnative.h @@ -197,6 +197,14 @@ PhGetProcessCommandLine( _Out_ PPH_STRING *CommandLine ); +PHLIBAPI +NTSTATUS +NTAPI +PhGetProcessDesktopInfo( + _In_ HANDLE ProcessHandle, + _Out_ PPH_STRING *DesktopInfo + ); + PHLIBAPI NTSTATUS NTAPI diff --git a/phlib/native.c b/phlib/native.c index 7cef0310dc61..40871c88f876 100644 --- a/phlib/native.c +++ b/phlib/native.c @@ -739,6 +739,14 @@ NTSTATUS PhGetProcessCommandLine( return PhGetProcessPebString(ProcessHandle, PhpoCommandLine, CommandLine); } +NTSTATUS PhGetProcessDesktopInfo( + _In_ HANDLE ProcessHandle, + _Out_ PPH_STRING *DesktopInfo + ) +{ + return PhGetProcessPebString(ProcessHandle, PhpoDesktopInfo, DesktopInfo); +} + /** * Gets the window flags and window title of a process. * From a48e59e6a66fd038764df2c6b6d45ad093dd3c31 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 3 May 2018 09:19:31 +1000 Subject: [PATCH 0928/2058] Add more RS4 types --- ProcessHacker/actions.c | 8 ++++---- phnt/include/ntdbg.h | 3 ++- phnt/include/ntexapi.h | 5 ++++- phnt/include/ntioapi.h | 30 ++++++++++++++++++++++++++++++ phnt/include/ntldr.h | 3 +++ phnt/include/ntmisc.h | 12 ------------ phnt/include/ntmmapi.h | 17 +++++++++++++---- 7 files changed, 56 insertions(+), 22 deletions(-) diff --git a/ProcessHacker/actions.c b/ProcessHacker/actions.c index d6190f3eebfe..4d59fe89bc91 100644 --- a/ProcessHacker/actions.c +++ b/ProcessHacker/actions.c @@ -1621,14 +1621,14 @@ BOOLEAN PhUiDetachFromDebuggerProcess( &debugObjectHandle ))) { - ULONG flags; + ULONG killProcessOnExit; // Disable kill-on-close. - flags = 0; + killProcessOnExit = 0; NtSetInformationDebugObject( debugObjectHandle, - DebugObjectFlags, - &flags, + DebugObjectKillProcessOnExitInformation, + &killProcessOnExit, sizeof(ULONG), NULL ); diff --git a/phnt/include/ntdbg.h b/phnt/include/ntdbg.h index deb804e5cee0..ff1c0601aad0 100644 --- a/phnt/include/ntdbg.h +++ b/phnt/include/ntdbg.h @@ -107,7 +107,8 @@ typedef struct _DBGUI_WAIT_STATE_CHANGE typedef enum _DEBUGOBJECTINFOCLASS { - DebugObjectFlags = 1, + DebugObjectUnusedInformation, + DebugObjectKillProcessOnExitInformation, MaxDebugObjectInfoClass } DEBUGOBJECTINFOCLASS, *PDEBUGOBJECTINFOCLASS; diff --git a/phnt/include/ntexapi.h b/phnt/include/ntexapi.h index 88e39146b788..0a429e566cc1 100644 --- a/phnt/include/ntexapi.h +++ b/phnt/include/ntexapi.h @@ -4052,12 +4052,15 @@ NtDisplayString( _In_ PUNICODE_STRING String ); +// Boot graphics + #if (PHNT_VERSION >= PHNT_WIN7) +// rev NTSYSCALLAPI NTSTATUS NTAPI NtDrawText( - _In_ PUNICODE_STRING String + _In_ PUNICODE_STRING Text ); #endif diff --git a/phnt/include/ntioapi.h b/phnt/include/ntioapi.h index 158e3b091840..7bc7ae41b53a 100644 --- a/phnt/include/ntioapi.h +++ b/phnt/include/ntioapi.h @@ -243,6 +243,8 @@ typedef enum _FILE_INFORMATION_CLASS FileDesiredStorageClassInformation, // FILE_DESIRED_STORAGE_CLASS_INFORMATION // since REDSTONE2 FileStatInformation, // FILE_STAT_INFORMATION FileMemoryPartitionInformation, // FILE_MEMORY_PARTITION_INFORMATION // since REDSTONE3 + FileStatLxInformation, // FILE_STAT_LX_INFORMATION // since REDSTONE4 + FileCaseSensitiveInformation, // FILE_CASE_SENSITIVE_INFORMATION FileMaximumInformation } FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS; @@ -711,6 +713,34 @@ typedef struct _FILE_MEMORY_PARTITION_INFORMATION } Flags; } FILE_MEMORY_PARTITION_INFORMATION, *PFILE_MEMORY_PARTITION_INFORMATION; +// private +typedef struct _FILE_STAT_LX_INFORMATION +{ + LARGE_INTEGER FileId; + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER AllocationSize; + LARGE_INTEGER EndOfFile; + ULONG FileAttributes; + ULONG ReparseTag; + ULONG NumberOfLinks; + ULONG EffectiveAccess; + ULONG LxFlags; + ULONG LxUid; + ULONG LxGid; + ULONG LxMode; + ULONG LxDeviceIdMajor; + ULONG LxDeviceIdMinor; +} FILE_STAT_LX_INFORMATION, *PFILE_STAT_LX_INFORMATION; + +// private +typedef struct _FILE_CASE_SENSITIVE_INFORMATION +{ + ULONG Flags; +} FILE_CASE_SENSITIVE_INFORMATION, *PFILE_CASE_SENSITIVE_INFORMATION; + // NtQueryDirectoryFile types typedef struct _FILE_DIRECTORY_INFORMATION diff --git a/phnt/include/ntldr.h b/phnt/include/ntldr.h index 0f2d93769799..6f5a214ef8fd 100644 --- a/phnt/include/ntldr.h +++ b/phnt/include/ntldr.h @@ -720,6 +720,7 @@ LdrEnumerateLoadedModules( _In_ PVOID Context ); +NTSYSAPI NTSTATUS NTAPI LdrOpenImageFileOptionsKey( @@ -728,6 +729,7 @@ LdrOpenImageFileOptionsKey( _Out_ PHANDLE NewKeyHandle ); +NTSYSAPI NTSTATUS NTAPI LdrQueryImageFileKeyOption( @@ -739,6 +741,7 @@ LdrQueryImageFileKeyOption( _Out_opt_ PULONG ReturnedLength ); +NTSYSAPI NTSTATUS NTAPI LdrQueryImageFileExecutionOptions( diff --git a/phnt/include/ntmisc.h b/phnt/include/ntmisc.h index 7ba023de5fb2..1d32c9ae8ae8 100644 --- a/phnt/include/ntmisc.h +++ b/phnt/include/ntmisc.h @@ -1,18 +1,6 @@ #ifndef _NTMISC_H #define _NTMISC_H -// Boot graphics - -#if (PHNT_VERSION >= PHNT_WIN7) -// rev -NTSYSCALLAPI -NTSTATUS -NTAPI -NtDrawText( - _In_ PUNICODE_STRING Text - ); -#endif - // Filter manager #define FLT_PORT_CONNECT 0x0001 diff --git a/phnt/include/ntmmapi.h b/phnt/include/ntmmapi.h index f9c37b449fb6..aa2a9bf01392 100644 --- a/phnt/include/ntmmapi.h +++ b/phnt/include/ntmmapi.h @@ -75,7 +75,7 @@ typedef enum _MEMORY_INFORMATION_CLASS MemoryImageInformation, // MEMORY_IMAGE_INFORMATION MemoryRegionInformationEx, MemoryPrivilegedBasicInformation, - MemoryEnclaveImageInformation, // since REDSTONE3 + MemoryEnclaveImageInformation, // MEMORY_ENCLAVE_IMAGE_INFORMATION // since REDSTONE3 MemoryBasicInformationCapped } MEMORY_INFORMATION_CLASS; #else @@ -216,12 +216,20 @@ typedef struct _MEMORY_IMAGE_INFORMATION { ULONG ImagePartialMap : 1; ULONG ImageNotExecutable : 1; - ULONG ImageSigningLevel : 1; // REDSTONE3 - ULONG Reserved : 30; + ULONG ImageSigningLevel : 4; // REDSTONE3 + ULONG Reserved : 26; }; }; } MEMORY_IMAGE_INFORMATION, *PMEMORY_IMAGE_INFORMATION; +// private +typedef struct _MEMORY_ENCLAVE_IMAGE_INFORMATION +{ + MEMORY_IMAGE_INFORMATION ImageInfo; + UCHAR UniqueID[32]; + UCHAR AuthorID[32]; +} MEMORY_ENCLAVE_IMAGE_INFORMATION, *PMEMORY_ENCLAVE_IMAGE_INFORMATION; + #define MMPFNLIST_ZERO 0 #define MMPFNLIST_FREE 1 #define MMPFNLIST_STANDBY 2 @@ -663,7 +671,8 @@ typedef enum _MEMORY_PARTITION_INFORMATION_CLASS SystemMemoryPartitionAddPagefile, // s: MEMORY_PARTITION_PAGEFILE_INFORMATION SystemMemoryPartitionCombineMemory, // q; s: MEMORY_PARTITION_PAGE_COMBINE_INFORMATION SystemMemoryPartitionInitialAddMemory, // q; s: MEMORY_PARTITION_INITIAL_ADD_INFORMATION - SystemMemoryPartitionGetMemoryEvents // MEMORY_PARTITION_MEMORY_EVENTS_INFORMATION // since REDSTONE2 + SystemMemoryPartitionGetMemoryEvents, // MEMORY_PARTITION_MEMORY_EVENTS_INFORMATION // since REDSTONE2 + SystemMemoryPartitionMax } MEMORY_PARTITION_INFORMATION_CLASS; // private From 20106bc08d40310be928770ad80730e91a749bab Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 4 May 2018 14:09:58 +1000 Subject: [PATCH 0929/2058] Add warning when closing critical process handles with strict handle checks enabled --- ProcessHacker/actions.c | 62 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 58 insertions(+), 4 deletions(-) diff --git a/ProcessHacker/actions.c b/ProcessHacker/actions.c index 4d59fe89bc91..0eeccd5a2bcd 100644 --- a/ProcessHacker/actions.c +++ b/ProcessHacker/actions.c @@ -3,7 +3,7 @@ * UI actions * * Copyright (C) 2010-2016 wj32 - * Copyright (C) 2017 dmex + * Copyright (C) 2017-2018 dmex * * This file is part of Process Hacker. * @@ -2966,13 +2966,67 @@ BOOLEAN PhUiCloseHandles( if (NT_SUCCESS(status = PhOpenProcess( &processHandle, - PROCESS_DUP_HANDLE, + PROCESS_QUERY_INFORMATION | PROCESS_DUP_HANDLE, ProcessId ))) { - ULONG i; + BOOLEAN critical = FALSE; + BOOLEAN strict = FALSE; - for (i = 0; i < NumberOfHandles; i++) + if (WindowsVersion >= WINDOWS_10) + { + ULONG breakOnTermination; + PROCESS_MITIGATION_POLICY_INFORMATION policyInfo; + + breakOnTermination = 0; + + if (NT_SUCCESS(NtQueryInformationProcess( + processHandle, + ProcessBreakOnTermination, + &breakOnTermination, + sizeof(ULONG), + NULL + ))) + { + if (breakOnTermination != 0) + { + critical = TRUE; + } + } + + policyInfo.Policy = ProcessStrictHandleCheckPolicy; + policyInfo.StrictHandleCheckPolicy.Flags = 0; + + if (NT_SUCCESS(NtQueryInformationProcess( + processHandle, + ProcessMitigationPolicy, + &policyInfo, + sizeof(PROCESS_MITIGATION_POLICY_INFORMATION), + NULL + ))) + { + if (policyInfo.StrictHandleCheckPolicy.Flags != 0) + { + strict = TRUE; + } + } + } + + if (critical && strict) + { + cont = PhShowConfirmMessage( + hWnd, + L"close", + L"critical process handle(s)", + L"You are about to close one or more handles for a critical process with strict handle checks enabled. This will shut down the operating system immediately.\r\n\r\n", + TRUE + ); + } + + if (!cont) + return FALSE; + + for (ULONG i = 0; i < NumberOfHandles; i++) { status = NtDuplicateObject( processHandle, From 66f03b4b0be4f59af0f0eb8e5c3eb03ce81966de Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 4 May 2018 14:14:38 +1000 Subject: [PATCH 0930/2058] DotNetTools: Fix memory leak, Fix missing appdomain for 32bit process threads --- plugins/DotNetTools/svcext.c | 108 ++++++++++++++++++++++++++++++++ plugins/DotNetTools/svcext.h | 23 ++++++- plugins/DotNetTools/treeext.c | 113 ++++++++++++++++++++++++++++------ 3 files changed, 224 insertions(+), 20 deletions(-) diff --git a/plugins/DotNetTools/svcext.c b/plugins/DotNetTools/svcext.c index 9606c84307b9..1acf9566e8c9 100644 --- a/plugins/DotNetTools/svcext.c +++ b/plugins/DotNetTools/svcext.c @@ -3,6 +3,7 @@ * phsvc extensions * * Copyright (C) 2015 wj32 + * Copyright (C) 2018 dmex * * This file is part of Process Hacker. * @@ -185,6 +186,110 @@ NTSTATUS DispatchPredictAddressesFromClrData( return STATUS_SUCCESS; } +PPH_STRING CallGetClrThreadAppDomain( + _In_ HANDLE ProcessId, + _In_ HANDLE ThreadId + ) +{ + NTSTATUS status; + PH_PLUGIN_PHSVC_CLIENT client; + DN_API_GETWOW64THREADAPPDOMAIN in; + DN_API_GETWOW64THREADAPPDOMAIN out; + ULONG bufferSize; + PVOID buffer; + PPH_STRING name = NULL; + + if (!PhPluginQueryPhSvc(&client)) + return NULL; + + in.i.ProcessId = HandleToUlong(ProcessId); + in.i.ThreadId = HandleToUlong(ThreadId); + + bufferSize = 0x1000; + + if (!(buffer = client.CreateString(NULL, bufferSize, &in.i.Name))) + return NULL; + + status = PhPluginCallPhSvc(PluginInstance, DnGetGetClrWow64ThreadAppDomainApiNumber, &in, sizeof(in), &out, sizeof(out)); + + if (status == STATUS_BUFFER_OVERFLOW) + { + client.FreeHeap(buffer); + bufferSize = out.o.NameLength; + + if (!(buffer = client.CreateString(NULL, bufferSize, &in.i.Name))) + return NULL; + + status = PhPluginCallPhSvc(PluginInstance, DnGetGetClrWow64ThreadAppDomainApiNumber, &in, sizeof(in), &out, sizeof(out)); + } + + if (NT_SUCCESS(status)) + { + name = PhCreateStringEx(buffer, out.o.NameLength); + } + + client.FreeHeap(buffer); + + return name; +} + +NTSTATUS DispatchGetClrThreadAppDomain( + _In_ PPH_PLUGIN_PHSVC_REQUEST Request, + _In_ PDN_API_GETWOW64THREADAPPDOMAIN In, + _Out_ PDN_API_GETWOW64THREADAPPDOMAIN Out + ) +{ + NTSTATUS status = STATUS_SUCCESS; + PVOID nameBuffer; + PCLR_PROCESS_SUPPORT support; + IXCLRDataProcess *process; + IXCLRDataTask *task; + IXCLRDataAppDomain *appDomain; + PPH_STRING AppDomainText = NULL; + + if (!NT_SUCCESS(status = Request->ProbeBuffer(&In->i.Name, sizeof(WCHAR), FALSE, &nameBuffer))) + return status; + + if (!(support = CreateClrProcessSupport(UlongToHandle(In->i.ProcessId)))) + return STATUS_UNSUCCESSFUL; + + if (!(process = support->DataProcess)) + { + status = STATUS_UNSUCCESSFUL; + goto CleanupExit; + } + + if (SUCCEEDED(IXCLRDataProcess_GetTaskByOSThreadID(process, In->i.ThreadId, &task))) + { + if (SUCCEEDED(IXCLRDataTask_GetCurrentAppDomain(task, &appDomain))) + { + AppDomainText = GetNameXClrDataAppDomain(appDomain); + IXCLRDataAppDomain_Release(appDomain); + } + + IXCLRDataTask_Release(task); + } + + if (!AppDomainText) + { + status = STATUS_UNSUCCESSFUL; + goto CleanupExit; + } + + memcpy(nameBuffer, AppDomainText->Buffer, min(AppDomainText->Length, In->i.Name.Length)); + Out->o.NameLength = (ULONG)AppDomainText->Length; + + if (In->i.Name.Length < AppDomainText->Length) + status = STATUS_BUFFER_OVERFLOW; + +CleanupExit: + + if (support) + FreeClrProcessSupport(support); + + return status; +} + VOID DispatchPhSvcRequest( _In_ PVOID Parameter ) @@ -203,6 +308,9 @@ VOID DispatchPhSvcRequest( case DnPredictAddressesFromClrDataApiNumber: request->ReturnStatus = DispatchPredictAddressesFromClrData(request, inBuffer, request->OutBuffer); break; + case DnGetGetClrWow64ThreadAppDomainApiNumber: + request->ReturnStatus = DispatchGetClrThreadAppDomain(request, inBuffer, request->OutBuffer); + break; } PhFree(inBuffer); diff --git a/plugins/DotNetTools/svcext.h b/plugins/DotNetTools/svcext.h index 1600336277f0..31d16927a63f 100644 --- a/plugins/DotNetTools/svcext.h +++ b/plugins/DotNetTools/svcext.h @@ -3,6 +3,7 @@ * phsvc extensions * * Copyright (C) 2015 wj32 + * Copyright (C) 2018 dmex * * This file is part of Process Hacker. * @@ -28,7 +29,8 @@ typedef enum _DN_API_NUMBER { DnGetRuntimeNameByAddressApiNumber = 1, - DnPredictAddressesFromClrDataApiNumber = 2 + DnPredictAddressesFromClrDataApiNumber = 2, + DnGetGetClrWow64ThreadAppDomainApiNumber = 3 } DN_API_NUMBER; typedef union _DN_API_GETRUNTIMENAMEBYADDRESS @@ -65,6 +67,20 @@ typedef union _DN_API_PREDICTADDRESSESFROMCLRDATA } o; } DN_API_PREDICTADDRESSESFROMCLRDATA, *PDN_API_PREDICTADDRESSESFROMCLRDATA; +typedef union _DN_API_GETWOW64THREADAPPDOMAIN +{ + struct + { + ULONG ProcessId; + ULONG ThreadId; + PH_RELATIVE_STRINGREF Name; // out + } i; + struct + { + ULONG NameLength; + } o; +} DN_API_GETWOW64THREADAPPDOMAIN, *PDN_API_GETWOW64THREADAPPDOMAIN; + // Calls PPH_STRING CallGetRuntimeNameByAddress( @@ -84,4 +100,9 @@ VOID CallPredictAddressesFromClrData( _Out_ PVOID *PredictedEsp ); +PPH_STRING CallGetClrThreadAppDomain( + _In_ HANDLE ProcessId, + _In_ HANDLE ThreadId + ); + #endif \ No newline at end of file diff --git a/plugins/DotNetTools/treeext.c b/plugins/DotNetTools/treeext.c index e30af549d2be..45f0338aaaa8 100644 --- a/plugins/DotNetTools/treeext.c +++ b/plugins/DotNetTools/treeext.c @@ -3,6 +3,7 @@ * thread list extensions * * Copyright (C) 2015 wj32 + * Copyright (C) 2018 dmex * * This file is part of Process Hacker. * @@ -22,6 +23,7 @@ #include "dn.h" #include "clrsup.h" +#include "svcext.h" VOID NTAPI ThreadsContextCreateCallback( _In_ PVOID Object, @@ -53,7 +55,12 @@ typedef struct _THREAD_TREE_CONTEXT { ULONG Type; HANDLE ProcessId; +#if _WIN64 + BOOLEAN IsWow64; + BOOLEAN ConnectedToPhSvc; +#endif PH_CALLBACK_REGISTRATION AddedCallbackRegistration; + PH_CALLBACK_REGISTRATION RemovedCallbackRegistration; PCLR_PROCESS_SUPPORT Support; } THREAD_TREE_CONTEXT, *PTHREAD_TREE_CONTEXT; @@ -136,6 +143,23 @@ static VOID ThreadAddedHandler( dnThread->ThreadItem = threadItem; } +static VOID ThreadRemovedHandler( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + PPH_THREAD_ITEM threadItem = Parameter; + PDN_THREAD_ITEM dnThread; + PTHREAD_TREE_CONTEXT context = Context; + + dnThread = PhPluginGetObjectExtension(PluginInstance, threadItem, EmThreadItemType); + + if (dnThread) + { + PhClearReference(&dnThread->AppDomainText); + } +} + VOID NTAPI ThreadsContextCreateCallback( _In_ PVOID Object, _In_ PH_EM_OBJECT_TYPE ObjectType, @@ -155,6 +179,13 @@ VOID NTAPI ThreadsContextCreateCallback( context, &context->AddedCallbackRegistration ); + + PhRegisterCallback( + &threadsContext->Provider->ThreadRemovedEvent, + ThreadRemovedHandler, + context, + &context->RemovedCallbackRegistration + ); } VOID NTAPI ThreadsContextDeleteCallback( @@ -171,8 +202,21 @@ VOID NTAPI ThreadsContextDeleteCallback( &context->AddedCallbackRegistration ); + PhUnregisterCallback( + &threadsContext->Provider->ThreadRemovedEvent, + &context->RemovedCallbackRegistration + ); + if (context->Support) FreeClrProcessSupport(context->Support); + +#if _WIN64 + if (context->ConnectedToPhSvc) + { + PhUiDisconnectFromPhSvc(); + context->ConnectedToPhSvc = FALSE; + } +#endif } VOID ThreadTreeNewInitializing( @@ -189,14 +233,31 @@ VOID ThreadTreeNewInitializing( if (NT_SUCCESS(PhGetProcessIsDotNet(threadsContext->Provider->ProcessId, &isDotNet)) && isDotNet) { - PCLR_PROCESS_SUPPORT support; +#if _WIN64 + HANDLE processHandle; - support = CreateClrProcessSupport(threadsContext->Provider->ProcessId); + if (NT_SUCCESS(PhOpenProcess(&processHandle, ProcessQueryAccess, threadsContext->Provider->ProcessId))) + { + PhGetProcessIsWow64(processHandle, &context->IsWow64); + NtClose(processHandle); + } - if (!support) - return; + if (context->IsWow64) + { + context->ConnectedToPhSvc = PhUiConnectToPhSvcEx(NULL, Wow64PhSvcMode, FALSE); + } + else +#endif + { + PCLR_PROCESS_SUPPORT support; - context->Support = support; + support = CreateClrProcessSupport(threadsContext->Provider->ProcessId); + + if (!support) + return; + + context->Support = support; + } AddTreeNewColumn(info, context, DNTHTNC_APPDOMAIN, TRUE, L"AppDomain", 120, PH_ALIGN_LEFT, 0, FALSE, ThreadTreeNewSortFunction); } @@ -216,24 +277,38 @@ VOID UpdateThreadClrData( { if (!DnThread->ClrDataValid) { - IXCLRDataProcess *process; - IXCLRDataTask *task; - IXCLRDataAppDomain *appDomain; + PhClearReference(&DnThread->AppDomainText); - if (Context->Support) - process = Context->Support->DataProcess; +#if _WIN64 + if (Context->IsWow64) + { + if (Context->ConnectedToPhSvc) + { + DnThread->AppDomainText = CallGetClrThreadAppDomain(Context->ProcessId, DnThread->ThreadItem->ThreadId); + } + } else - return; - - if (SUCCEEDED(IXCLRDataProcess_GetTaskByOSThreadID(process, HandleToUlong(DnThread->ThreadItem->ThreadId), &task))) +#endif { - if (SUCCEEDED(IXCLRDataTask_GetCurrentAppDomain(task, &appDomain))) + if (Context->Support) { - DnThread->AppDomainText = GetNameXClrDataAppDomain(appDomain); - IXCLRDataAppDomain_Release(appDomain); + IXCLRDataProcess *process; + IXCLRDataTask *task; + IXCLRDataAppDomain *appDomain; + + process = Context->Support->DataProcess; + + if (SUCCEEDED(IXCLRDataProcess_GetTaskByOSThreadID(process, HandleToUlong(DnThread->ThreadItem->ThreadId), &task))) + { + if (SUCCEEDED(IXCLRDataTask_GetCurrentAppDomain(task, &appDomain))) + { + DnThread->AppDomainText = GetNameXClrDataAppDomain(appDomain); + IXCLRDataAppDomain_Release(appDomain); + } + + IXCLRDataTask_Release(task); + } } - - IXCLRDataTask_Release(task); } DnThread->ClrDataValid = TRUE; @@ -290,7 +365,7 @@ LONG ThreadTreeNewSortFunction( case DNTHTNC_APPDOMAIN: UpdateThreadClrData(context, dnThread1); UpdateThreadClrData(context, dnThread2); - result = PhCompareStringWithNull(dnThread1->AppDomainText, dnThread2->AppDomainText, TRUE); + result = PhCompareStringWithNullSortOrder(dnThread1->AppDomainText, dnThread2->AppDomainText, SortOrder, TRUE); break; } From b6792bda27a91a057bee6b3aff8fb1c752f6aef4 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 6 May 2018 01:05:59 +1000 Subject: [PATCH 0931/2058] Enable RS4 platform features --- ProcessHacker/memprv.c | 2 +- phlib/global.c | 21 ++++++++++----------- phlib/include/phconfig.h | 1 + phlib/kphdata.c | 6 +++++- phnt/include/phnt.h | 1 + 5 files changed, 18 insertions(+), 13 deletions(-) diff --git a/ProcessHacker/memprv.c b/ProcessHacker/memprv.c index 6b8ec6d12487..4a04f712de9b 100644 --- a/ProcessHacker/memprv.c +++ b/ProcessHacker/memprv.c @@ -271,7 +271,7 @@ NTSTATUS PhpUpdateMemoryRegionTypes( PhpSetMemoryRegionType(List, USER_SHARED_DATA, TRUE, UserSharedDataRegion); // HYPERVISOR_SHARED_DATA - if (WindowsVersion > WINDOWS_10_RS3) // TODO: Update version check after RS4 release. + if (WindowsVersion >= WINDOWS_10_RS4) { static PVOID HypervisorSharedDataVa = NULL; static PH_INITONCE HypervisorSharedDataInitOnce = PH_INITONCE_INIT; diff --git a/phlib/global.c b/phlib/global.c index 325b13764b8f..73670e07eae7 100644 --- a/phlib/global.c +++ b/phlib/global.c @@ -178,26 +178,22 @@ static VOID PhInitializeWindowsVersion( minorVersion = versionInfo.dwMinorVersion; buildVersion = versionInfo.dwBuildNumber; - if (majorVersion == 6 && minorVersion < 1 || majorVersion < 6) - { - WindowsVersion = WINDOWS_ANCIENT; - } - /* Windows 7, Windows Server 2008 R2 */ - else if (majorVersion == 6 && minorVersion == 1) + // Windows 7, Windows Server 2008 R2 + if (majorVersion == 6 && minorVersion == 1) { WindowsVersion = WINDOWS_7; } - /* Windows 8 */ + // Windows 8, Windows Server 2012 else if (majorVersion == 6 && minorVersion == 2) { WindowsVersion = WINDOWS_8; } - /* Windows 8.1 */ + // Windows 8.1, Windows Server 2012 R2 else if (majorVersion == 6 && minorVersion == 3) { WindowsVersion = WINDOWS_8_1; } - /* Windows 10 */ + // Windows 10, Windows Server 2016 else if (majorVersion == 10 && minorVersion == 0) { switch (buildVersion) @@ -217,12 +213,15 @@ static VOID PhInitializeWindowsVersion( case 16299: WindowsVersion = WINDOWS_10_RS3; break; + case 17134: + WindowsVersion = WINDOWS_10_RS4; + break; default: - WindowsVersion = WINDOWS_NEW; + WindowsVersion = WINDOWS_10; break; } } - else if (majorVersion == 10 && minorVersion > 0 || majorVersion > 10) + else { WindowsVersion = WINDOWS_NEW; } diff --git a/phlib/include/phconfig.h b/phlib/include/phconfig.h index dcff8133381b..bb4f7700a972 100644 --- a/phlib/include/phconfig.h +++ b/phlib/include/phconfig.h @@ -32,6 +32,7 @@ PHLIBAPI extern ACCESS_MASK ThreadAllAccess; #define WINDOWS_10_RS1 102 #define WINDOWS_10_RS2 103 #define WINDOWS_10_RS3 104 +#define WINDOWS_10_RS4 105 #define WINDOWS_NEW MAXLONG #define WINDOWS_HAS_IMMERSIVE (WindowsVersion >= WINDOWS_8) diff --git a/phlib/kphdata.c b/phlib/kphdata.c index 472c7800d2c2..924d1f7a3c27 100644 --- a/phlib/kphdata.c +++ b/phlib/kphdata.c @@ -124,7 +124,7 @@ NTSTATUS KphInitializeDynamicPackage( Package->StructData.ObDecodeShift = 16; Package->StructData.ObAttributesShift = 17; } - // Windows 10 + // Windows 10, Windows Server 2016 else if (majorVersion == 10 && minorVersion == 0) { switch (buildNumber) @@ -149,6 +149,10 @@ NTSTATUS KphInitializeDynamicPackage( Package->BuildNumber = 16299; Package->ResultingNtVersion = PHNT_REDSTONE3; break; + case 17134: + Package->BuildNumber = 17134; + Package->ResultingNtVersion = PHNT_REDSTONE4; + break; default: Package->BuildNumber = USHRT_MAX; Package->ResultingNtVersion = PHNT_THRESHOLD; diff --git a/phnt/include/phnt.h b/phnt/include/phnt.h index 924b09b6f2fc..f3412176e1a1 100644 --- a/phnt/include/phnt.h +++ b/phnt/include/phnt.h @@ -36,6 +36,7 @@ #define PHNT_REDSTONE 102 #define PHNT_REDSTONE2 103 #define PHNT_REDSTONE3 104 +#define PHNT_REDSTONE4 105 #ifndef PHNT_MODE #define PHNT_MODE PHNT_MODE_USER From 6d32bb3795cab9108dd7fe583b61d3e269cd8040 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 6 May 2018 01:53:10 +1000 Subject: [PATCH 0932/2058] Add hexeditor support for extended unicode --- phlib/hexedit.c | 22 +++++++++++++++++++--- phlib/include/hexedit.h | 4 ++++ phlib/include/hexeditp.h | 24 +++++++++++++++--------- 3 files changed, 38 insertions(+), 12 deletions(-) diff --git a/phlib/hexedit.c b/phlib/hexedit.c index 5fce14a1c383..4eb36d9b375a 100644 --- a/phlib/hexedit.c +++ b/phlib/hexedit.c @@ -888,12 +888,28 @@ LRESULT CALLBACK PhpHexEditWndProc( } } return TRUE; + case HEM_SETEXTENDEDUNICODE: + { + context->ExtendedUnicode = !!(LONG)wParam; + } + return TRUE; } DefaultHandler: return DefWindowProc(hwnd, uMsg, wParam, lParam); } +FORCEINLINE INT PhpIsPrintable( + _In_ PPHP_HEXEDIT_CONTEXT Context, + _In_ UCHAR Byte + ) +{ + if (Context->ExtendedUnicode) + return iswctype(Byte, _PUNCT | _ALPHA | _DIGIT); // iswprint + else + return ((ULONG)((Byte)-' ') <= (ULONG)('~' - ' ')); +} + FORCEINLINE VOID PhpPrintHex( _In_ HDC hdc, _In_ PPHP_HEXEDIT_CONTEXT Context, @@ -931,7 +947,7 @@ FORCEINLINE VOID PhpPrintAscii( { WCHAR c; - c = IS_PRINTABLE(Byte) ? Byte : '.'; + c = PhpIsPrintable(Context, Byte) ? Byte : '.'; TextOut(hdc, *X, *Y, &c, 1); *X += Context->NullWidth; (*N)++; @@ -1279,7 +1295,7 @@ VOID PhpHexEditOnPaint( for (n = 0; n < Context->BytesPerRow && i < Context->Length; n++) { - *p++ = IS_PRINTABLE(Context->Data[i]) ? Context->Data[i] : '.'; // 1 + *p++ = PhpIsPrintable(Context, Context->Data[i]) ? Context->Data[i] : '.'; // 1 i++; } @@ -1657,7 +1673,7 @@ VOID PhpHexEditCopyEdit( for (i = 0; i < length; i++) { - if (!IS_PRINTABLE(*p)) + if (!PhpIsPrintable(Context, *p)) *p = '.'; p++; } diff --git a/phlib/include/hexedit.h b/phlib/include/hexedit.h index 3fbd74ac32ce..ce63c80e07b4 100644 --- a/phlib/include/hexedit.h +++ b/phlib/include/hexedit.h @@ -23,6 +23,7 @@ BOOLEAN PhHexEditInitialization( #define HEM_SETSEL (WM_USER + 4) #define HEM_SETEDITMODE (WM_USER + 5) #define HEM_SETBYTESPERROW (WM_USER + 6) +#define HEM_SETEXTENDEDUNICODE (WM_USER + 7) #define HexEdit_SetBuffer(hWnd, Buffer, Length) \ SendMessage((hWnd), HEM_SETBUFFER, (WPARAM)(Length), (LPARAM)(Buffer)) @@ -42,6 +43,9 @@ BOOLEAN PhHexEditInitialization( #define HexEdit_SetBytesPerRow(hWnd, BytesPerRow) \ SendMessage((hWnd), HEM_SETBYTESPERROW, (WPARAM)(BytesPerRow), 0) +#define HexEdit_SetExtendedUnicode(hWnd, ExtendedUnicode) \ + SendMessage((hWnd), HEM_SETEXTENDEDUNICODE, (WPARAM)(ExtendedUnicode), 0) + #ifdef __cplusplus } #endif diff --git a/phlib/include/hexeditp.h b/phlib/include/hexeditp.h index 53bb4f0d0029..b32d1c1d0155 100644 --- a/phlib/include/hexeditp.h +++ b/phlib/include/hexeditp.h @@ -15,14 +15,22 @@ typedef struct _PHP_HEXEDIT_CONTEXT LONG BytesPerRow; LONG LinesPerPage; - BOOLEAN ShowAddress; - BOOLEAN ShowAscii; - BOOLEAN ShowHex; - BOOLEAN AddressIsWide; - BOOLEAN AllowLengthChange; - BOOLEAN NoAddressChange; - BOOLEAN HalfPage; + union + { + BOOLEAN Flags; + struct + { + BOOLEAN ShowAddress : 1; + BOOLEAN ShowAscii : 1; + BOOLEAN ShowHex : 1; + BOOLEAN AddressIsWide : 1; + BOOLEAN AllowLengthChange : 1; + BOOLEAN NoAddressChange : 1; + BOOLEAN HalfPage : 1; + BOOLEAN ExtendedUnicode : 1; + }; + }; HFONT Font; LONG LineHeight; @@ -39,8 +47,6 @@ typedef struct _PHP_HEXEDIT_CONTEXT POINT EditPosition; } PHP_HEXEDIT_CONTEXT, *PPHP_HEXEDIT_CONTEXT; -#define IS_PRINTABLE(Byte) ((ULONG)((Byte) - ' ') <= (ULONG)('~' - ' ')) - #define TO_HEX(Buffer, Byte) \ { \ *(Buffer)++ = PhIntegerToChar[(Byte) >> 4]; \ From 64b6818ac5dc69a39210ea3165d0ebfee8193f97 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 7 May 2018 01:50:04 +1000 Subject: [PATCH 0933/2058] SetupTool: Fix creating WoW64 IFEO options --- tools/CustomSetupTool/CustomSetupTool/setup.c | 61 ++++++++++++++++--- 1 file changed, 52 insertions(+), 9 deletions(-) diff --git a/tools/CustomSetupTool/CustomSetupTool/setup.c b/tools/CustomSetupTool/CustomSetupTool/setup.c index 9be35201cf2f..53002aa2e34a 100644 --- a/tools/CustomSetupTool/CustomSetupTool/setup.c +++ b/tools/CustomSetupTool/CustomSetupTool/setup.c @@ -2,7 +2,7 @@ * Process Hacker Toolchain - * project setup * - * Copyright (C) 2017 dmex + * Copyright (C) 2017-2018 dmex * * This file is part of Process Hacker. * @@ -25,6 +25,10 @@ #include PH_STRINGREF UninstallKeyName = PH_STRINGREF_INIT(L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\ProcessHacker"); +PH_STRINGREF CurrentUserRunKeyName = PH_STRINGREF_INIT(L"Software\\Microsoft\\Windows\\CurrentVersion\\Run"); +PH_STRINGREF PhImageOptionsKeyName = PH_STRINGREF_INIT(L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\ProcessHacker.exe"); +PH_STRINGREF PhImageOptionsWow64KeyName = PH_STRINGREF_INIT(L"Software\\WOW6432Node\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\ProcessHacker.exe"); +PH_STRINGREF TmImageOptionsKeyName = PH_STRINGREF_INIT(L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\taskmgr.exe"); NTSTATUS SetupCreateUninstallKey( _In_ PPH_SETUP_CONTEXT Context @@ -469,8 +473,6 @@ VOID SetupSetWindowsOptions( _In_ PPH_SETUP_CONTEXT Context ) { - static PH_STRINGREF TaskMgrImageOptionsKeyName = PH_STRINGREF_INIT(L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\taskmgr.exe"); - static PH_STRINGREF CurrentUserRunKeyName = PH_STRINGREF_INIT(L"Software\\Microsoft\\Windows\\CurrentVersion\\Run"); PPH_STRING clientPathString; PPH_STRING startmenuFolderString; @@ -556,7 +558,7 @@ VOID SetupSetWindowsOptions( &taskmgrKeyHandle, KEY_READ | KEY_WRITE, PH_KEY_LOCAL_MACHINE, - &TaskMgrImageOptionsKeyName, + &TmImageOptionsKeyName, OBJ_OPENIF, 0, NULL @@ -627,9 +629,6 @@ VOID SetupDeleteWindowsOptions( _In_ PPH_SETUP_CONTEXT Context ) { - static PH_STRINGREF PhImageOptionsKeyName = PH_STRINGREF_INIT(L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\ProcessHacker.exe"); - static PH_STRINGREF TaskMgrImageOptionsKeyName = PH_STRINGREF_INIT(L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\taskmgr.exe"); - static PH_STRINGREF CurrentUserRunKeyName = PH_STRINGREF_INIT(L"Software\\Microsoft\\Windows\\CurrentVersion\\Run"); PPH_STRING startmenuFolderString; HANDLE keyHandle; @@ -673,7 +672,19 @@ VOID SetupDeleteWindowsOptions( &keyHandle, KEY_WRITE | DELETE, PH_KEY_LOCAL_MACHINE, - &TaskMgrImageOptionsKeyName, + &PhImageOptionsWow64KeyName, + 0 + ))) + { + NtDeleteKey(keyHandle); + NtClose(keyHandle); + } + + if (NT_SUCCESS(PhOpenKey( + &keyHandle, + KEY_WRITE | DELETE, + PH_KEY_LOCAL_MACHINE, + &TmImageOptionsKeyName, 0 ))) { @@ -743,12 +754,14 @@ VOID SetupCreateImageFileExecutionOptions( VOID ) { - static PH_STRINGREF PhImageOptionsKeyName = PH_STRINGREF_INIT(L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\ProcessHacker.exe"); HANDLE keyHandle; + SYSTEM_INFO info; if (WindowsVersion < WINDOWS_10) return; + GetNativeSystemInfo(&info); + if (NT_SUCCESS(PhCreateKey( &keyHandle, KEY_WRITE, @@ -775,4 +788,34 @@ VOID SetupCreateImageFileExecutionOptions( NtClose(keyHandle); } + + if (info.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) + { + if (NT_SUCCESS(PhCreateKey( + &keyHandle, + KEY_WRITE, + PH_KEY_LOCAL_MACHINE, + &PhImageOptionsWow64KeyName, + OBJ_OPENIF, + 0, + NULL + ))) + { + static UNICODE_STRING valueName = RTL_CONSTANT_STRING(L"MitigationOptions"); + + NtSetValueKey(keyHandle, &valueName, 0, REG_QWORD, &(ULONG64) + { + PROCESS_CREATION_MITIGATION_POLICY_HEAP_TERMINATE_ALWAYS_ON | + PROCESS_CREATION_MITIGATION_POLICY_BOTTOM_UP_ASLR_ALWAYS_ON | + PROCESS_CREATION_MITIGATION_POLICY_HIGH_ENTROPY_ASLR_ALWAYS_ON | + PROCESS_CREATION_MITIGATION_POLICY_EXTENSION_POINT_DISABLE_ALWAYS_ON | + PROCESS_CREATION_MITIGATION_POLICY_PROHIBIT_DYNAMIC_CODE_ALWAYS_ON | + PROCESS_CREATION_MITIGATION_POLICY_CONTROL_FLOW_GUARD_ALWAYS_ON | + PROCESS_CREATION_MITIGATION_POLICY_IMAGE_LOAD_NO_REMOTE_ALWAYS_ON | + PROCESS_CREATION_MITIGATION_POLICY_IMAGE_LOAD_NO_LOW_LABEL_ALWAYS_ON + }, sizeof(ULONG64)); + + NtClose(keyHandle); + } + } } \ No newline at end of file From 0e316b65e10c1a068c39603cea9810af4b82112e Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 7 May 2018 04:01:11 +1000 Subject: [PATCH 0934/2058] OnlineChecks: Fix uploading files to VirusTotal --- plugins/OnlineChecks/upload.c | 67 ++++++++++++++++++++++++----------- 1 file changed, 46 insertions(+), 21 deletions(-) diff --git a/plugins/OnlineChecks/upload.c b/plugins/OnlineChecks/upload.c index a8026d87ba8c..df69a177bc3e 100644 --- a/plugins/OnlineChecks/upload.c +++ b/plugins/OnlineChecks/upload.c @@ -448,7 +448,10 @@ NTSTATUS UploadFileThreadStart( postBoundary->Buffer ); - if (context->Service == MENUITEM_HYBRIDANALYSIS_UPLOAD || context->Service == MENUITEM_HYBRIDANALYSIS_UPLOAD_SERVICE) + if ( + context->Service == MENUITEM_HYBRIDANALYSIS_UPLOAD || + context->Service == MENUITEM_HYBRIDANALYSIS_UPLOAD_SERVICE + ) { USHORT machineType; USHORT environmentId; @@ -803,6 +806,7 @@ NTSTATUS UploadFileThreadStart( { PPH_BYTES jsonString; PVOID jsonRootObject; + PVOID jsonDataObject; if (!(jsonString = PhHttpSocketDownloadString(httpContext, FALSE))) { @@ -812,26 +816,25 @@ NTSTATUS UploadFileThreadStart( if (jsonRootObject = PhCreateJsonParser(jsonString->Buffer)) { - INT64 errorCode = PhGetJsonValueAsLong64(jsonRootObject, "response_code"); - //PhGetJsonValueAsString(jsonRootObject, "scan_id"); - //PhGetJsonValueAsString(jsonRootObject, "verbose_msg"); - - if (errorCode != 1) - { - RaiseUploadError(context, L"VirusTotal API error", (ULONG)errorCode); - PhDereferenceObject(jsonString); - goto CleanupExit; - } - else + if (jsonDataObject = PhGetJsonObject(jsonRootObject, "data")) { - PhMoveReference(&context->LaunchCommand, PhGetJsonValueAsString(jsonRootObject, "permalink")); + PPH_STRING analysisId = PhGetJsonValueAsString(jsonDataObject, "id"); + + PhMoveReference(&context->LaunchCommand, PhFormatString( + L"https://www.virustotal.com/#/file-analysis/%s", + analysisId->Buffer + )); + + PhDereferenceObject(analysisId); } PhFreeJsonParser(jsonRootObject); } - else + + if (PhIsNullOrEmptyString(context->LaunchCommand)) { RaiseUploadError(context, L"Unable to complete the request", RtlNtStatusToDosError(STATUS_FAIL_CHECK)); + PhDereferenceObject(jsonString); goto CleanupExit; } @@ -1013,11 +1016,6 @@ NTSTATUS UploadCheckThreadStart( context->FileHash = tempHashString; subObjectName = PhConcatStrings2(L"/file/upload/?sha256=", PhGetString(context->FileHash)); - PhMoveReference(&context->LaunchCommand, PhFormatString( - L"https://www.virustotal.com/file/%s/analysis/", - PhGetString(context->FileHash) - )); - if (!(subRequestBuffer = PerformSubRequest( context, serviceInfo->HostName, @@ -1077,6 +1075,11 @@ NTSTATUS UploadCheckThreadStart( PhClearReference(&resource); } + PhMoveReference(&context->LaunchCommand, PhFormatString( + L"https://www.virustotal.com/file/%s/analysis/", + PhGetString(context->FileHash) + )); + if (!PhIsNullOrEmptyString(context->UploadUrl)) { PostMessage(context->DialogHandle, UM_EXISTS, 0, 0); @@ -1088,7 +1091,27 @@ NTSTATUS UploadCheckThreadStart( } else { - context->UploadUrl = PhGetJsonValueAsString(rootJsonObject, "upload_url"); + PPH_STRING vt3UploadUrl; + PPH_BYTES vt3UploadRequestBuffer; + PVOID vt3RootJsonObject; + + vt3UploadUrl = PhCreateString(L"/ui/files/upload_url"); + + if (!(vt3UploadRequestBuffer = PerformSubRequest( + context, + serviceInfo->HostName, + vt3UploadUrl->Buffer + ))) + { + PhDereferenceObject(vt3UploadUrl); + goto CleanupExit; + } + + if (vt3RootJsonObject = PhCreateJsonParser(vt3UploadRequestBuffer->Buffer)) + { + context->UploadUrl = PhGetJsonValueAsString(vt3RootJsonObject, "data"); + PhFreeJsonParser(vt3RootJsonObject); + } // No file found... Start the upload. if (!PhIsNullOrEmptyString(context->UploadUrl)) @@ -1097,8 +1120,10 @@ NTSTATUS UploadCheckThreadStart( } else { - RaiseUploadError(context, L"Received invalid response.", RtlNtStatusToDosError(STATUS_FAIL_CHECK)); + RaiseUploadError(context, L"Received invalid VT3 response.", RtlNtStatusToDosError(STATUS_FAIL_CHECK)); } + + PhClearReference(&vt3UploadRequestBuffer); } PhFreeJsonParser(rootJsonObject); From 546c6185b86f8c0d5b73ee341f2f9a9b22e7b3dc Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 7 May 2018 10:54:23 +1000 Subject: [PATCH 0935/2058] OnlineChecks: Fix rescan link, Fix memory leak --- plugins/OnlineChecks/onlnchk.h | 21 ++++++ plugins/OnlineChecks/page2.c | 24 ++++-- plugins/OnlineChecks/page3.c | 120 ++++++++++++++++++++++++++++++ plugins/OnlineChecks/upload.c | 107 ++++++++++++++++++++++---- plugins/OnlineChecks/virustotal.c | 58 ++++++++++++--- 5 files changed, 297 insertions(+), 33 deletions(-) diff --git a/plugins/OnlineChecks/onlnchk.h b/plugins/OnlineChecks/onlnchk.h index 4f109a9aeccd..668c03f63600 100644 --- a/plugins/OnlineChecks/onlnchk.h +++ b/plugins/OnlineChecks/onlnchk.h @@ -51,6 +51,7 @@ #define UM_LAUNCH (WM_APP + 3) #define UM_ERROR (WM_APP + 4) #define UM_SHOWDIALOG (WM_APP + 5) +#define UM_EXITDIALOG (WM_APP + 6) extern PPH_PLUGIN PluginInstance; @@ -169,6 +170,10 @@ NTSTATUS UploadRecheckThreadStart( _In_ PVOID Parameter ); +NTSTATUS ViewReportThreadStart( + _In_ PVOID Parameter + ); + VOID ShowVirusTotalUploadDialog( _In_ PUPLOAD_CONTEXT Context ); @@ -181,6 +186,14 @@ VOID ShowVirusTotalProgressDialog( _In_ PUPLOAD_CONTEXT Context ); +VOID ShowVirusTotalReScanProgressDialog( + _In_ PUPLOAD_CONTEXT Context + ); + +VOID ShowVirusTotalViewReportProgressDialog( + _In_ PUPLOAD_CONTEXT Context + ); + VOID VirusTotalShowErrorDialog( _In_ PUPLOAD_CONTEXT Context ); @@ -306,10 +319,18 @@ PVIRUSTOTAL_FILE_REPORT VirusTotalRequestFileReport( _In_ PPH_STRING FileHash ); +VOID VirusTotalFreeFileReport( + _In_ PVIRUSTOTAL_FILE_REPORT FileReport + ); + PVIRUSTOTAL_API_RESPONSE VirusTotalRequestFileReScan( _In_ PPH_STRING FileHash ); +VOID VirusTotalFreeFileReScan( + _In_ PVIRUSTOTAL_API_RESPONSE FileReScan + ); + VOID InitializeVirusTotalProcessMonitor( VOID ); diff --git a/plugins/OnlineChecks/page2.c b/plugins/OnlineChecks/page2.c index dbee6f4d88b5..c2714c4a4f2f 100644 --- a/plugins/OnlineChecks/page2.c +++ b/plugins/OnlineChecks/page2.c @@ -60,15 +60,27 @@ HRESULT CALLBACK TaskDialogResultFoundProc( } else if (buttonID == IDRETRY) { - if (!PhIsNullOrEmptyString(context->ReAnalyseUrl)) - PhShellExecute(hwndDlg, PhGetString(context->ReAnalyseUrl), NULL); +//#ifdef PH_BUILD_API + ShowVirusTotalReScanProgressDialog(context); + return S_FALSE; +//#else +// if (!PhIsNullOrEmptyString(context->ReAnalyseUrl)) +// { +// PhShellExecute(hwndDlg, PhGetString(context->ReAnalyseUrl), NULL); +// } +//#endif } else if (buttonID == IDYES) { - if (!PhIsNullOrEmptyString(context->LaunchCommand)) - { - PhShellExecute(hwndDlg, PhGetString(context->LaunchCommand), NULL); - } +//#ifdef PH_BUILD_API + ShowVirusTotalViewReportProgressDialog(context); + return S_FALSE; +//#else +// if (!PhIsNullOrEmptyString(context->LaunchCommand)) +// { +// PhShellExecute(hwndDlg, PhGetString(context->LaunchCommand), NULL); +// } +//#endif } } break; diff --git a/plugins/OnlineChecks/page3.c b/plugins/OnlineChecks/page3.c index c35e7309c7ec..df23e83e9b2a 100644 --- a/plugins/OnlineChecks/page3.c +++ b/plugins/OnlineChecks/page3.c @@ -63,6 +63,82 @@ HRESULT CALLBACK TaskDialogProgressCallbackProc( return S_OK; } +HRESULT CALLBACK TaskDialogReScanProgressCallbackProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam, + _In_ LONG_PTR dwRefData + ) +{ + PUPLOAD_CONTEXT context = (PUPLOAD_CONTEXT)dwRefData; + + switch (uMsg) + { + case TDN_NAVIGATED: + { + SendMessage(hwndDlg, TDM_SET_MARQUEE_PROGRESS_BAR, TRUE, 0); + SendMessage(hwndDlg, TDM_SET_PROGRESS_BAR_MARQUEE, TRUE, 1); + + PhReferenceObject(context); + context->UploadThreadHandle = PhCreateThread(0, UploadRecheckThreadStart, context); + } + break; + case TDN_BUTTON_CLICKED: + { + if ((INT)wParam == IDCANCEL) + { + if (context->UploadThreadHandle) + { + NtClose(context->UploadThreadHandle); + context->UploadThreadHandle = NULL; + } + } + } + break; + } + + return S_OK; +} + +HRESULT CALLBACK TaskDialogViewReportProgressCallbackProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam, + _In_ LONG_PTR dwRefData + ) +{ + PUPLOAD_CONTEXT context = (PUPLOAD_CONTEXT)dwRefData; + + switch (uMsg) + { + case TDN_NAVIGATED: + { + SendMessage(hwndDlg, TDM_SET_MARQUEE_PROGRESS_BAR, TRUE, 0); + SendMessage(hwndDlg, TDM_SET_PROGRESS_BAR_MARQUEE, TRUE, 1); + + PhReferenceObject(context); + context->UploadThreadHandle = PhCreateThread(0, ViewReportThreadStart, context); + } + break; + case TDN_BUTTON_CLICKED: + { + if ((INT)wParam == IDCANCEL) + { + if (context->UploadThreadHandle) + { + NtClose(context->UploadThreadHandle); + context->UploadThreadHandle = NULL; + } + } + } + break; + } + + return S_OK; +} + VOID ShowVirusTotalProgressDialog( _In_ PUPLOAD_CONTEXT Context ) @@ -85,3 +161,47 @@ VOID ShowVirusTotalProgressDialog( SendMessage(Context->DialogHandle, TDM_NAVIGATE_PAGE, 0, (LPARAM)&config); } + +VOID ShowVirusTotalReScanProgressDialog( + _In_ PUPLOAD_CONTEXT Context + ) +{ + TASKDIALOGCONFIG config; + + memset(&config, 0, sizeof(TASKDIALOGCONFIG)); + config.cbSize = sizeof(TASKDIALOGCONFIG); + config.dwFlags = TDF_USE_HICON_MAIN | TDF_ALLOW_DIALOG_CANCELLATION | TDF_CAN_BE_MINIMIZED | TDF_EXPAND_FOOTER_AREA | TDF_ENABLE_HYPERLINKS | TDF_SHOW_PROGRESS_BAR; + config.dwCommonButtons = TDCBF_CANCEL_BUTTON; + config.hMainIcon = Context->IconLargeHandle; + + config.pszWindowTitle = PhaFormatString(L"Rescanning %s...", PhGetStringOrEmpty(Context->BaseFileName))->Buffer; + config.pszMainInstruction = PhaFormatString(L"Rescanning %s...", PhGetStringOrEmpty(Context->BaseFileName))->Buffer; + + config.cxWidth = 200; + config.lpCallbackData = (LONG_PTR)Context; + config.pfCallback = TaskDialogReScanProgressCallbackProc; + + SendMessage(Context->DialogHandle, TDM_NAVIGATE_PAGE, 0, (LPARAM)&config); +} + +VOID ShowVirusTotalViewReportProgressDialog( + _In_ PUPLOAD_CONTEXT Context + ) +{ + TASKDIALOGCONFIG config; + + memset(&config, 0, sizeof(TASKDIALOGCONFIG)); + config.cbSize = sizeof(TASKDIALOGCONFIG); + config.dwFlags = TDF_USE_HICON_MAIN | TDF_ALLOW_DIALOG_CANCELLATION | TDF_CAN_BE_MINIMIZED | TDF_EXPAND_FOOTER_AREA | TDF_ENABLE_HYPERLINKS | TDF_SHOW_PROGRESS_BAR; + config.dwCommonButtons = TDCBF_CANCEL_BUTTON; + config.hMainIcon = Context->IconLargeHandle; + + config.pszWindowTitle = PhaFormatString(L"Locating analysis for %s...", PhGetStringOrEmpty(Context->BaseFileName))->Buffer; + config.pszMainInstruction = PhaFormatString(L"Locating analysis for %s...", PhGetStringOrEmpty(Context->BaseFileName))->Buffer; + + config.cxWidth = 200; + config.lpCallbackData = (LONG_PTR)Context; + config.pfCallback = TaskDialogViewReportProgressCallbackProc; + + SendMessage(Context->DialogHandle, TDM_NAVIGATE_PAGE, 0, (LPARAM)&config); +} \ No newline at end of file diff --git a/plugins/OnlineChecks/upload.c b/plugins/OnlineChecks/upload.c index df69a177bc3e..62420af20245 100644 --- a/plugins/OnlineChecks/upload.c +++ b/plugins/OnlineChecks/upload.c @@ -814,8 +814,19 @@ NTSTATUS UploadFileThreadStart( goto CleanupExit; } + if (!PhIsNullOrEmptyString(context->FileHash)) + { + PVIRUSTOTAL_FILE_REPORT fileReport; + + if (fileReport = VirusTotalRequestFileReport(context->FileHash)) + { + VirusTotalFreeFileReport(fileReport); + } + } + if (jsonRootObject = PhCreateJsonParser(jsonString->Buffer)) { + // New interface if (jsonDataObject = PhGetJsonObject(jsonRootObject, "data")) { PPH_STRING analysisId = PhGetJsonValueAsString(jsonDataObject, "id"); @@ -827,13 +838,21 @@ NTSTATUS UploadFileThreadStart( PhDereferenceObject(analysisId); } + else + { + // Old interface + if (PhGetJsonValueAsLong64(jsonRootObject, "response_code") == 1) + { + PhMoveReference(&context->LaunchCommand, PhGetJsonValueAsString(jsonRootObject, "permalink")); + } + } PhFreeJsonParser(jsonRootObject); } if (PhIsNullOrEmptyString(context->LaunchCommand)) { - RaiseUploadError(context, L"Unable to complete the request", RtlNtStatusToDosError(STATUS_FAIL_CHECK)); + RaiseUploadError(context, L"Unable to complete the request.", RtlNtStatusToDosError(STATUS_FAIL_CHECK)); PhDereferenceObject(jsonString); goto CleanupExit; } @@ -1172,25 +1191,66 @@ NTSTATUS UploadRecheckThreadStart( ) { PUPLOAD_CONTEXT context = (PUPLOAD_CONTEXT)Parameter; - PVIRUSTOTAL_API_RESPONSE response; + PVIRUSTOTAL_API_RESPONSE fileRescan; - response = VirusTotalRequestFileReScan(context->FileHash); + if (fileRescan = VirusTotalRequestFileReScan(context->FileHash)) + { + if (fileRescan->ResponseCode == 1) + { + PhMoveReference(&context->ReAnalyseUrl, fileRescan->PermaLink); + + PhShellExecute(NULL, PhGetString(context->ReAnalyseUrl), NULL); + + PostMessage(context->DialogHandle, UM_EXITDIALOG, 0, 0); + } + else + { + RaiseUploadError(context, L"VirusTotal ReScan API error.", (ULONG)fileRescan->ResponseCode); + } - if (response->ResponseCode == 1) - PhMoveReference(&context->ReAnalyseUrl, response->PermaLink); + VirusTotalFreeFileReScan(fileRescan); + } else - RaiseUploadError(context, L"VirusTotal API error", (ULONG)response->ResponseCode); + { + RaiseUploadError(context, L"VirusTotal ReScan API error.", RtlNtStatusToDosError(STATUS_FAIL_CHECK)); + } + + PhDereferenceObject(context); - if (!PhIsNullOrEmptyString(context->ReAnalyseUrl)) + return STATUS_SUCCESS; +} + +NTSTATUS ViewReportThreadStart( + _In_ PVOID Parameter + ) +{ + PUPLOAD_CONTEXT context = (PUPLOAD_CONTEXT)Parameter; + PVIRUSTOTAL_FILE_REPORT fileReport; + + if (fileReport = VirusTotalRequestFileReport(context->FileHash)) { - PhShellExecute(NULL, PhGetString(context->ReAnalyseUrl), NULL); - //PostMessage(context->DialogHandle, UM_LAUNCH, 0, 0); + if (fileReport->ResponseCode == 1) + { + PhMoveReference(&context->LaunchCommand, fileReport->PermaLink); + + PhShellExecute(NULL, PhGetString(context->LaunchCommand), NULL); + + PostMessage(context->DialogHandle, UM_EXITDIALOG, 0, 0); + } + else + { + RaiseUploadError(context, L"VirusTotal ViewReport API error.", (ULONG)fileReport->ResponseCode); + } + + VirusTotalFreeFileReport(fileReport); } else { - RaiseUploadError(context, L"Unable to complete the ReAnalyse request (please try again after a few minutes)", ERROR_INVALID_DATA); + RaiseUploadError(context, L"VirusTotal ViewReport API error.", RtlNtStatusToDosError(STATUS_FAIL_CHECK)); } + PhDereferenceObject(context); + return STATUS_SUCCESS; } @@ -1236,16 +1296,26 @@ LRESULT CALLBACK TaskDialogSubclassProc( break; case 2: { - if (!PhIsNullOrEmptyString(context->ReAnalyseUrl)) - PhShellExecute(hwndDlg, PhGetString(context->ReAnalyseUrl), NULL); +//#ifdef PH_BUILD_API + ShowVirusTotalReScanProgressDialog(context); +//#else +// if (!PhIsNullOrEmptyString(context->ReAnalyseUrl)) +// { +// PhShellExecute(hwndDlg, PhGetString(context->ReAnalyseUrl), NULL); +// } +//#endif } break; case 3: { - if (!PhIsNullOrEmptyString(context->LaunchCommand)) - { - PhShellExecute(hwndDlg, PhGetString(context->LaunchCommand), NULL); - } +//#ifdef PH_BUILD_API + ShowVirusTotalViewReportProgressDialog(context); +//#else +// if (!PhIsNullOrEmptyString(context->LaunchCommand)) +// { +// PhShellExecute(hwndDlg, PhGetString(context->LaunchCommand), NULL); +// } +//#endif } break; default: @@ -1270,6 +1340,11 @@ LRESULT CALLBACK TaskDialogSubclassProc( VirusTotalShowErrorDialog(context); } break; + case UM_EXITDIALOG: + { + PostQuitMessage(0); + } + break; } return CallWindowProc(oldWndProc, hwndDlg, uMsg, wParam, lParam); diff --git a/plugins/OnlineChecks/virustotal.c b/plugins/OnlineChecks/virustotal.c index e494d438fa9e..fff09e230f62 100644 --- a/plugins/OnlineChecks/virustotal.c +++ b/plugins/OnlineChecks/virustotal.c @@ -496,6 +496,37 @@ PVIRUSTOTAL_FILE_REPORT VirusTotalRequestFileReport( return result; } +VOID VirusTotalFreeFileReport( + _In_ PVIRUSTOTAL_FILE_REPORT FileReport + ) +{ + PhClearReference(&FileReport->StatusMessage); + PhClearReference(&FileReport->PermaLink); + PhClearReference(&FileReport->ScanId); + PhClearReference(&FileReport->ScanDate); + PhClearReference(&FileReport->Positives); + PhClearReference(&FileReport->Total); + + if (FileReport->ScanResults) + { + for (ULONG i = 0; i < FileReport->ScanResults->Count; i++) + { + PVIRUSTOTAL_FILE_REPORT_RESULT object = FileReport->ScanResults->Items[i]; + + PhClearReference(&object->Vendor); + PhClearReference(&object->EngineVersion); + PhClearReference(&object->DetectionName); + PhClearReference(&object->DatabaseDate); + + PhFree(object); + } + + PhClearReference(&FileReport->ScanResults); + } + + PhFree(FileReport); +} + PVIRUSTOTAL_API_RESPONSE VirusTotalRequestFileReScan( _In_ PPH_STRING FileHash ) @@ -594,6 +625,17 @@ PVIRUSTOTAL_API_RESPONSE VirusTotalRequestFileReScan( return result; } +VOID VirusTotalFreeFileReScan( + _In_ PVIRUSTOTAL_API_RESPONSE FileReScan + ) +{ + PhClearReference(&FileReScan->StatusMessage); + PhClearReference(&FileReScan->PermaLink); + PhClearReference(&FileReScan->ScanId); + + PhFree(FileReScan); +} + PVIRUSTOTAL_API_RESPONSE VirusTotalRequestIpAddressReport( _In_ PPH_STRING IpAddress ) @@ -696,17 +738,11 @@ NTSTATUS NTAPI VirusTotalProcessApiThread( _In_ PVOID Parameter ) { - LONG priority; - IO_PRIORITY_HINT ioPriority; - // TODO: Workqueue support. - priority = THREAD_PRIORITY_LOWEST; - ioPriority = IoPriorityVeryLow; - - NtSetInformationThread(NtCurrentThread(), ThreadBasePriority, &priority, sizeof(LONG)); - NtSetInformationThread(NtCurrentThread(), ThreadIoPriority, &ioPriority, sizeof(IO_PRIORITY_HINT)); + PhSetThreadBasePriority(NtCurrentThread(), THREAD_PRIORITY_LOWEST); + PhSetThreadIoPriority(NtCurrentThread(), IoPriorityVeryLow); - Sleep(10 * 1000); + PhDelayExecution(10 * 1000); do { @@ -744,7 +780,7 @@ NTSTATUS NTAPI VirusTotalProcessApiThread( if (resultTempList->Count == 0) { - Sleep(30 * 1000); // Wait 30 seconds + PhDelayExecution(30 * 1000); // Wait 30 seconds goto CleanupExit; } @@ -857,7 +893,7 @@ NTSTATUS NTAPI VirusTotalProcessApiThread( PhDereferenceObject(resultTempList); } - Sleep(5 * 1000); // Wait 5 seconds + PhDelayExecution(5 * 1000); // Wait 5 seconds } while (VirusTotalHandle); From c386554c7a3b25587c0ac5702541bf8aa823c0c5 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 7 May 2018 11:15:27 +1000 Subject: [PATCH 0936/2058] Plugins: Fix macro usage --- plugins/ExtendedServices/other.c | 6 +++--- plugins/ExtendedTools/etwmon.c | 2 +- plugins/OnlineChecks/upload.c | 12 ++++-------- plugins/ToolStatus/graph.c | 10 +++++----- plugins/ToolStatus/toolbar.c | 8 ++++---- plugins/Updater/updater.c | 2 +- plugins/UserNotes/main.c | 2 +- plugins/WindowExplorer/wndprp.c | 2 +- 8 files changed, 20 insertions(+), 24 deletions(-) diff --git a/plugins/ExtendedServices/other.c b/plugins/ExtendedServices/other.c index 04354d3a312e..309e6644b5a4 100644 --- a/plugins/ExtendedServices/other.c +++ b/plugins/ExtendedServices/other.c @@ -92,7 +92,7 @@ ULONG EspGetServiceSidTypeInteger( )) return integer; else - return -1; + return ULONG_MAX; } PWSTR EspGetServiceLaunchProtectedString( @@ -126,7 +126,7 @@ ULONG EspGetServiceLaunchProtectedInteger( )) return integer; else - return -1; + return ULONG_MAX; } NTSTATUS EspLoadOtherInfo( @@ -521,7 +521,7 @@ INT_PTR CALLBACK EspServiceOtherDlgProc( { index = PhFindItemList(context->PrivilegeList, privilegeString); - if (index != -1) + if (index != ULONG_MAX) { PhDereferenceObject(privilegeString); PhRemoveItemList(context->PrivilegeList, index); diff --git a/plugins/ExtendedTools/etwmon.c b/plugins/ExtendedTools/etwmon.c index c9787ceeb6a2..52257066c8fb 100644 --- a/plugins/ExtendedTools/etwmon.c +++ b/plugins/ExtendedTools/etwmon.c @@ -431,7 +431,7 @@ NTSTATUS EtpEtwMonitorThreadStart( // Some error occurred, so sleep for a while before trying again. // Don't sleep if we just successfully started a session, though. if (!EtpEtwActive) - Sleep(250); + PhDelayExecution(250); } return STATUS_SUCCESS; diff --git a/plugins/OnlineChecks/upload.c b/plugins/OnlineChecks/upload.c index 62420af20245..3d7848b64000 100644 --- a/plugins/OnlineChecks/upload.c +++ b/plugins/OnlineChecks/upload.c @@ -176,19 +176,15 @@ NTSTATUS HashFileAndResetPosition( ULONG64 bytesRemaining; FILE_POSITION_INFORMATION positionInfo; LONG priority; - LONG newpriority; IO_PRIORITY_HINT ioPriority; - IO_PRIORITY_HINT newioPriority; UCHAR buffer[PAGE_SIZE]; bytesRemaining = FileSize->QuadPart; - newpriority = THREAD_PRIORITY_LOWEST; - newioPriority = IoPriorityVeryLow; - NtQueryInformationThread(NtCurrentThread(), ThreadBasePriority, &priority, sizeof(LONG), NULL); - NtQueryInformationThread(NtCurrentThread(), ThreadIoPriority, &ioPriority, sizeof(IO_PRIORITY_HINT), NULL); - NtSetInformationThread(NtCurrentThread(), ThreadBasePriority, &newpriority, sizeof(LONG)); - NtSetInformationThread(NtCurrentThread(), ThreadIoPriority, &newioPriority, sizeof(IO_PRIORITY_HINT)); + PhGetThreadBasePriority(NtCurrentThread(), &priority); + PhGetThreadIoPriority(NtCurrentThread(), &ioPriority); + PhSetThreadBasePriority(NtCurrentThread(), THREAD_PRIORITY_LOWEST); + PhSetThreadIoPriority(NtCurrentThread(), IoPriorityVeryLow); PhInitializeHash(&hashContext, Algorithm); diff --git a/plugins/ToolStatus/graph.c b/plugins/ToolStatus/graph.c index 7550714f44fb..c4c54d8e3c10 100644 --- a/plugins/ToolStatus/graph.c +++ b/plugins/ToolStatus/graph.c @@ -398,7 +398,9 @@ static PPH_STRING PhSipGetMaxIoString( // END copied from ProcessHacker/sysinfo.c // -VOID ToolbarUpdateGraphsInfo(LPNMHDR Header) +VOID ToolbarUpdateGraphsInfo( + _In_ LPNMHDR Header + ) { switch (Header->code) { @@ -419,10 +421,8 @@ VOID ToolbarUpdateGraphsInfo(LPNMHDR Header) if (!CpuGraphState.Valid) { - PhCopyCircularBuffer_FLOAT(SystemStatistics.CpuKernelHistory, - CpuGraphState.Data1, drawInfo->LineDataCount); - PhCopyCircularBuffer_FLOAT(SystemStatistics.CpuUserHistory, - CpuGraphState.Data2, drawInfo->LineDataCount); + PhCopyCircularBuffer_FLOAT(SystemStatistics.CpuKernelHistory, CpuGraphState.Data1, drawInfo->LineDataCount); + PhCopyCircularBuffer_FLOAT(SystemStatistics.CpuUserHistory, CpuGraphState.Data2, drawInfo->LineDataCount); CpuGraphState.Valid = TRUE; } diff --git a/plugins/ToolStatus/toolbar.c b/plugins/ToolStatus/toolbar.c index 0b69d9b92846..daba0ce84bbc 100644 --- a/plugins/ToolStatus/toolbar.c +++ b/plugins/ToolStatus/toolbar.c @@ -69,7 +69,7 @@ VOID RebarBandInsert( rebarBandInfo.fStyle |= RBBS_NOGRIPPER; } - if ((index = (UINT)SendMessage(RebarHandle, RB_IDTOINDEX, REBAR_BAND_ID_SEARCHBOX, 0)) != -1) + if ((index = (UINT)SendMessage(RebarHandle, RB_IDTOINDEX, REBAR_BAND_ID_SEARCHBOX, 0)) != UINT_MAX) { SendMessage(RebarHandle, RB_INSERTBAND, (WPARAM)index, (LPARAM)&rebarBandInfo); } @@ -85,7 +85,7 @@ VOID RebarBandRemove( { UINT index = (UINT)SendMessage(RebarHandle, RB_IDTOINDEX, (WPARAM)BandID, 0); - if (index == -1) + if (index == UINT_MAX) return; SendMessage(RebarHandle, RB_DELETEBAND, (WPARAM)index, 0); @@ -97,7 +97,7 @@ BOOLEAN RebarBandExists( { UINT index = (UINT)SendMessage(RebarHandle, RB_IDTOINDEX, (WPARAM)BandID, 0); - if (index != -1) + if (index != UINT_MAX) return TRUE; return FALSE; @@ -784,7 +784,7 @@ VOID ReBarLoadLayoutSettings( PhStringToInteger64(&cxPart, 10, &cxInteger); PhStringToInteger64(&stylePart, 10, &styleInteger); - if ((oldBandIndex = (UINT)SendMessage(RebarHandle, RB_IDTOINDEX, (UINT)idInteger, 0)) == -1) + if ((oldBandIndex = (UINT)SendMessage(RebarHandle, RB_IDTOINDEX, (UINT)idInteger, 0)) == UINT_MAX) break; if (oldBandIndex != index) diff --git a/plugins/Updater/updater.c b/plugins/Updater/updater.c index 8be7e0cbdd87..ed3c6d665336 100644 --- a/plugins/Updater/updater.c +++ b/plugins/Updater/updater.c @@ -378,7 +378,7 @@ NTSTATUS UpdateCheckSilentThread( goto CleanupExit; #endif - Sleep(5 * 1000); + PhDelayExecution(5 * 1000); // Clear the application cache directory. PhClearCacheDirectory(); diff --git a/plugins/UserNotes/main.c b/plugins/UserNotes/main.c index e669d921ad30..79690803cd53 100644 --- a/plugins/UserNotes/main.c +++ b/plugins/UserNotes/main.c @@ -1199,8 +1199,8 @@ VOID ProcessesUpdatedCallback( { priorityClass.Foreground = FALSE; priorityClass.PriorityClass = (UCHAR)object->PriorityClass; - NtSetInformationProcess(processHandle, ProcessPriorityClass, &priorityClass, sizeof(PROCESS_PRIORITY_CLASS)); + PhSetProcessPriority(processHandle, priorityClass); NtClose(processHandle); } } diff --git a/plugins/WindowExplorer/wndprp.c b/plugins/WindowExplorer/wndprp.c index 234540002f4b..e4c5d065fd7f 100644 --- a/plugins/WindowExplorer/wndprp.c +++ b/plugins/WindowExplorer/wndprp.c @@ -367,7 +367,7 @@ static INT CALLBACK WepPropSheetProc( // Set the OK button's text to "Close". PhSetDialogItemText(hwndDlg, IDOK, L"Close"); // Add the Refresh button. - refreshButtonHandle = CreateWindow(L"BUTTON", L"Refresh", WS_CHILD | WS_TABSTOP | WS_VISIBLE, 0, 0, 3, 3, hwndDlg, (HMENU)IDC_REFRESH, + refreshButtonHandle = CreateWindow(WC_BUTTON, L"Refresh", WS_CHILD | WS_TABSTOP | WS_VISIBLE, 0, 0, 3, 3, hwndDlg, (HMENU)IDC_REFRESH, PluginInstance->DllBase, NULL); SendMessage(refreshButtonHandle, WM_SETFONT, (WPARAM)SendMessage(GetDlgItem(hwndDlg, IDOK), WM_GETFONT, 0, 0), FALSE); } From 0be8090394b605cf172660c0fb70af4a6ebd376e Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 7 May 2018 15:15:13 +1000 Subject: [PATCH 0937/2058] OnlineChecks: Fix crash, Improve VirusTotal column sorting --- plugins/OnlineChecks/main.c | 11 +++++++---- plugins/OnlineChecks/onlnchk.h | 2 -- plugins/OnlineChecks/upload.c | 22 ++++++++-------------- 3 files changed, 15 insertions(+), 20 deletions(-) diff --git a/plugins/OnlineChecks/main.c b/plugins/OnlineChecks/main.c index 69c5bd2dc4fc..13d74b3da80e 100644 --- a/plugins/OnlineChecks/main.c +++ b/plugins/OnlineChecks/main.c @@ -433,7 +433,7 @@ LONG NTAPI VirusTotalProcessNodeSortFunction( PPROCESS_EXTENSION extension1 = PhPluginGetObjectExtension(PluginInstance, node1->ProcessItem, EmProcessItemType); PPROCESS_EXTENSION extension2 = PhPluginGetObjectExtension(PluginInstance, node2->ProcessItem, EmProcessItemType); - return PhCompareStringWithNull(extension1->VirusTotalResult, extension2->VirusTotalResult, TRUE); + return PhCompareStringWithNullSortOrder(extension1->VirusTotalResult, extension2->VirusTotalResult, SortOrder, TRUE); } LONG NTAPI VirusTotalModuleNodeSortFunction( @@ -449,7 +449,7 @@ LONG NTAPI VirusTotalModuleNodeSortFunction( PPROCESS_EXTENSION extension1 = PhPluginGetObjectExtension(PluginInstance, node1->ModuleItem, EmModuleItemType); PPROCESS_EXTENSION extension2 = PhPluginGetObjectExtension(PluginInstance, node2->ModuleItem, EmModuleItemType); - return PhCompareStringWithNull(extension1->VirusTotalResult, extension2->VirusTotalResult, TRUE); + return PhCompareStringWithNullSortOrder(extension1->VirusTotalResult, extension2->VirusTotalResult, SortOrder, TRUE); } LONG NTAPI VirusTotalServiceNodeSortFunction( @@ -465,7 +465,7 @@ LONG NTAPI VirusTotalServiceNodeSortFunction( PPROCESS_EXTENSION extension1 = PhPluginGetObjectExtension(PluginInstance, node1->ServiceItem, EmServiceItemType); PPROCESS_EXTENSION extension2 = PhPluginGetObjectExtension(PluginInstance, node2->ServiceItem, EmServiceItemType); - return PhCompareStringWithNull(extension1->VirusTotalResult, extension2->VirusTotalResult, TRUE); + return PhCompareStringWithNullSortOrder(extension1->VirusTotalResult, extension2->VirusTotalResult, SortOrder, TRUE); } VOID NTAPI ProcessTreeNewInitializingCallback( @@ -613,11 +613,14 @@ VOID NTAPI TreeNewMessageCallback( if (!extension) break; + //if (extension->Positives > 0) + // SetTextColor(customDraw->Dc, RGB(0xff, 0x0, 0x0)); + text = PhGetStringRef(extension->VirusTotalResult); DrawText( customDraw->Dc, text.Buffer, - (ULONG)text.Length / 2, + (ULONG)text.Length / sizeof(WCHAR), &customDraw->CellRect, DT_CENTER | DT_VCENTER | DT_END_ELLIPSIS | DT_SINGLELINE ); diff --git a/plugins/OnlineChecks/onlnchk.h b/plugins/OnlineChecks/onlnchk.h index 668c03f63600..10b1c6ed7fe8 100644 --- a/plugins/OnlineChecks/onlnchk.h +++ b/plugins/OnlineChecks/onlnchk.h @@ -51,7 +51,6 @@ #define UM_LAUNCH (WM_APP + 3) #define UM_ERROR (WM_APP + 4) #define UM_SHOWDIALOG (WM_APP + 5) -#define UM_EXITDIALOG (WM_APP + 6) extern PPH_PLUGIN PluginInstance; @@ -134,7 +133,6 @@ typedef struct _UPLOAD_CONTEXT PPH_STRING ErrorString; PPH_STRING FileName; PPH_STRING BaseFileName; - PPH_STRING WindowFileName; PPH_STRING LaunchCommand; PPH_STRING Detected; PPH_STRING MaxDetected; diff --git a/plugins/OnlineChecks/upload.c b/plugins/OnlineChecks/upload.c index 3d7848b64000..291518c681d4 100644 --- a/plugins/OnlineChecks/upload.c +++ b/plugins/OnlineChecks/upload.c @@ -104,7 +104,6 @@ VOID UploadContextDeleteProcedure( PhClearReference(&context->ErrorString); PhClearReference(&context->FileName); PhClearReference(&context->BaseFileName); - PhClearReference(&context->WindowFileName); PhClearReference(&context->LaunchCommand); PhClearReference(&context->Detected); PhClearReference(&context->MaxDetected); @@ -960,7 +959,7 @@ NTSTATUS UploadCheckThreadStart( if (!NT_SUCCESS(status = PhCreateFileWin32( &fileHandle, - context->FileName->Buffer, + PhGetString(context->FileName), FILE_GENERIC_READ, 0, FILE_SHARE_READ | FILE_SHARE_DELETE, @@ -1054,8 +1053,8 @@ NTSTATUS UploadCheckThreadStart( detectedMax = PhGetJsonArrayLong64(detectionRatio, 1); } - context->Detected = PhFormatString(L"%I64d", detected); - context->MaxDetected = PhFormatString(L"%I64d", detectedMax); + context->Detected = PhFormatUInt64(detected, FALSE); + context->MaxDetected = PhFormatUInt64(detectedMax, FALSE); context->UploadUrl = PhGetJsonValueAsString(rootJsonObject, "upload_url"); context->ReAnalyseUrl = PhGetJsonValueAsString(rootJsonObject, "reanalyse_url"); context->LastAnalysisUrl = PhGetJsonValueAsString(rootJsonObject, "last_analysis_url"); @@ -1193,11 +1192,11 @@ NTSTATUS UploadRecheckThreadStart( { if (fileRescan->ResponseCode == 1) { - PhMoveReference(&context->ReAnalyseUrl, fileRescan->PermaLink); + PhSwapReference(&context->ReAnalyseUrl, fileRescan->PermaLink); PhShellExecute(NULL, PhGetString(context->ReAnalyseUrl), NULL); - PostMessage(context->DialogHandle, UM_EXITDIALOG, 0, 0); + SendMessage(context->DialogHandle, TDM_CLICK_BUTTON, IDOK, 0); } else { @@ -1227,11 +1226,11 @@ NTSTATUS ViewReportThreadStart( { if (fileReport->ResponseCode == 1) { - PhMoveReference(&context->LaunchCommand, fileReport->PermaLink); + PhSwapReference(&context->LaunchCommand, fileReport->PermaLink); PhShellExecute(NULL, PhGetString(context->LaunchCommand), NULL); - PostMessage(context->DialogHandle, UM_EXITDIALOG, 0, 0); + SendMessage(context->DialogHandle, TDM_CLICK_BUTTON, IDOK, 0); } else { @@ -1328,7 +1327,7 @@ LRESULT CALLBACK TaskDialogSubclassProc( PhShellExecute(hwndDlg, context->LaunchCommand->Buffer, NULL); } - PostQuitMessage(0); + SendMessage(hwndDlg, TDM_CLICK_BUTTON, IDOK, 0); } break; case UM_ERROR: @@ -1336,11 +1335,6 @@ LRESULT CALLBACK TaskDialogSubclassProc( VirusTotalShowErrorDialog(context); } break; - case UM_EXITDIALOG: - { - PostQuitMessage(0); - } - break; } return CallWindowProc(oldWndProc, hwndDlg, uMsg, wParam, lParam); From fe8e8491ba7f7dac15e00124ac6871a4418c6942 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 7 May 2018 15:21:46 +1000 Subject: [PATCH 0938/2058] Fix services tab post-sorting, Improve service filename memory usage --- ProcessHacker/appsup.c | 31 +++++++++++++++++-------------- ProcessHacker/srvlist.c | 20 +++++++++++++++----- 2 files changed, 32 insertions(+), 19 deletions(-) diff --git a/ProcessHacker/appsup.c b/ProcessHacker/appsup.c index 67f857b27958..76b10a140135 100644 --- a/ProcessHacker/appsup.c +++ b/ProcessHacker/appsup.c @@ -625,24 +625,27 @@ PPH_STRING PhGetServiceRelevantFileName( { PPH_STRING commandLine; - commandLine = PhCreateString(config->lpBinaryPathName); - - if (config->dwServiceType & SERVICE_WIN32) + if (config->lpBinaryPathName[0]) { - PH_STRINGREF dummyFileName; - PH_STRINGREF dummyArguments; + commandLine = PhCreateString(config->lpBinaryPathName); - PhParseCommandLineFuzzy(&commandLine->sr, &dummyFileName, &dummyArguments, &fileName); + if (config->dwServiceType & SERVICE_WIN32) + { + PH_STRINGREF dummyFileName; + PH_STRINGREF dummyArguments; - if (!fileName) - PhSwapReference(&fileName, commandLine); - } - else - { - fileName = PhGetFileName(commandLine); - } + PhParseCommandLineFuzzy(&commandLine->sr, &dummyFileName, &dummyArguments, &fileName); - PhDereferenceObject(commandLine); + if (!fileName) + PhSwapReference(&fileName, commandLine); + } + else + { + fileName = PhGetFileName(commandLine); + } + + PhDereferenceObject(commandLine); + } } PhFree(config); diff --git a/ProcessHacker/srvlist.c b/ProcessHacker/srvlist.c index f6df1fd83a51..76a853ef904e 100644 --- a/ProcessHacker/srvlist.c +++ b/ProcessHacker/srvlist.c @@ -479,6 +479,14 @@ LONG PhpServiceTreeNewPostSortFunction( _In_ PH_SORT_ORDER SortOrder ) { + PPH_SERVICE_NODE node1 = (PPH_SERVICE_NODE)Node1; + PPH_SERVICE_NODE node2 = (PPH_SERVICE_NODE)Node2; + PPH_SERVICE_ITEM serviceItem1 = node1->ServiceItem; + PPH_SERVICE_ITEM serviceItem2 = node2->ServiceItem; + + if (Result == 0) + Result = PhCompareString(serviceItem1->Name, serviceItem2->Name, TRUE); + return PhModifySort(Result, SortOrder); } @@ -527,7 +535,7 @@ BEGIN_SORT_FUNCTION(BinaryPath) { PhpUpdateServiceNodeConfig(node1); PhpUpdateServiceNodeConfig(node2); - sortResult = PhCompareStringWithNull(node1->BinaryPath, node2->BinaryPath, TRUE); + sortResult = PhCompareStringWithNullSortOrder(node1->BinaryPath, node2->BinaryPath, ServiceTreeListSortOrder, TRUE); } END_SORT_FUNCTION @@ -541,7 +549,7 @@ BEGIN_SORT_FUNCTION(Group) { PhpUpdateServiceNodeConfig(node1); PhpUpdateServiceNodeConfig(node2); - sortResult = PhCompareStringWithNull(node1->LoadOrderGroup, node2->LoadOrderGroup, TRUE); + sortResult = PhCompareStringWithNullSortOrder(node1->LoadOrderGroup, node2->LoadOrderGroup, ServiceTreeListSortOrder, TRUE); } END_SORT_FUNCTION @@ -549,7 +557,7 @@ BEGIN_SORT_FUNCTION(Description) { PhpUpdateServiceNodeDescription(node1); PhpUpdateServiceNodeDescription(node2); - sortResult = PhCompareStringWithNull(node1->Description, node2->Description, TRUE); + sortResult = PhCompareStringWithNullSortOrder(node1->Description, node2->Description, ServiceTreeListSortOrder, TRUE); } END_SORT_FUNCTION @@ -569,9 +577,10 @@ END_SORT_FUNCTION BEGIN_SORT_FUNCTION(VerifiedSigner) { - sortResult = PhCompareStringWithNull( + sortResult = PhCompareStringWithNullSortOrder( serviceItem1->VerifySignerName, serviceItem2->VerifySignerName, + ServiceTreeListSortOrder, TRUE ); } @@ -579,9 +588,10 @@ END_SORT_FUNCTION BEGIN_SORT_FUNCTION(FileName) { - sortResult = PhCompareStringWithNull( + sortResult = PhCompareStringWithNullSortOrder( serviceItem1->FileName, serviceItem2->FileName, + ServiceTreeListSortOrder, TRUE ); } From b84be0dd572a42b804f7c153842e8a178206e7bd Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 8 May 2018 21:06:02 +1000 Subject: [PATCH 0939/2058] ExtendedTools: Improve modules tab -> services menu dialog --- plugins/ExtendedTools/ExtendedTools.rc | 2 +- plugins/ExtendedTools/exttools.h | 2 + plugins/ExtendedTools/main.c | 12 +- plugins/ExtendedTools/modsrv.c | 194 +++++++++++++++++-------- 4 files changed, 144 insertions(+), 66 deletions(-) diff --git a/plugins/ExtendedTools/ExtendedTools.rc b/plugins/ExtendedTools/ExtendedTools.rc index 9301a428c85a..012b5a72e03e 100644 --- a/plugins/ExtendedTools/ExtendedTools.rc +++ b/plugins/ExtendedTools/ExtendedTools.rc @@ -116,7 +116,7 @@ BEGIN END IDD_MODSERVICES DIALOGEX 0, 0, 276, 209 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +STYLE DS_SETFONT | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME CAPTION "Services" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN diff --git a/plugins/ExtendedTools/exttools.h b/plugins/ExtendedTools/exttools.h index da6153fae6dc..d902723d9969 100644 --- a/plugins/ExtendedTools/exttools.h +++ b/plugins/ExtendedTools/exttools.h @@ -26,6 +26,8 @@ extern HWND NetworkTreeNewHandle; #define SETTING_NAME_UNLOADED_WINDOW_POSITION (PLUGIN_NAME L".TracertWindowPosition") #define SETTING_NAME_UNLOADED_WINDOW_SIZE (PLUGIN_NAME L".TracertWindowSize") #define SETTING_NAME_UNLOADED_COLUMNS (PLUGIN_NAME L".UnloadedListColumns") +#define SETTING_NAME_MODULE_SERVICES_WINDOW_POSITION (PLUGIN_NAME L".ModuleServiceWindowPosition") +#define SETTING_NAME_MODULE_SERVICES_WINDOW_SIZE (PLUGIN_NAME L".ModuleServiceWindowSize") // Graph update message diff --git a/plugins/ExtendedTools/main.c b/plugins/ExtendedTools/main.c index 0b745fd3e5ac..0f47effe4ea0 100644 --- a/plugins/ExtendedTools/main.c +++ b/plugins/ExtendedTools/main.c @@ -205,8 +205,8 @@ VOID NTAPI ThreadMenuInitializingCallback( else insertIndex = 0; - PhInsertEMenuItem(menuInfo->Menu, menuItem = PhPluginCreateEMenuItem(PluginInstance, 0, ID_THREAD_CANCELIO, - L"Ca&ncel I/O", threadItem), insertIndex); + menuItem = PhPluginCreateEMenuItem(PluginInstance, 0, ID_THREAD_CANCELIO, L"Ca&ncel I/O", threadItem); + PhInsertEMenuItem(menuInfo->Menu, menuItem, insertIndex); if (!threadItem) menuItem->Flags |= PH_EMENU_DISABLED; } @@ -248,8 +248,10 @@ VOID NTAPI ModuleMenuInitializingCallback( ModuleProcessId = menuInfo->u.Module.ProcessId; - PhInsertEMenuItem(menuInfo->Menu, menuItem = PhPluginCreateEMenuItem(PluginInstance, 0, ID_MODULE_SERVICES, - L"Ser&vices", moduleItem), insertIndex); + menuItem = PhPluginCreateEMenuItem(PluginInstance, 0, ID_MODULE_SERVICES, L"Ser&vices", moduleItem); + PhInsertEMenuItem(menuInfo->Menu, PhCreateEMenuSeparator(), insertIndex); + PhInsertEMenuItem(menuInfo->Menu, menuItem, insertIndex + 1); + PhInsertEMenuItem(menuInfo->Menu, PhCreateEMenuSeparator(), insertIndex + 2); if (!moduleItem) menuItem->Flags |= PH_EMENU_DISABLED; } @@ -629,6 +631,8 @@ LOGICAL DllMain( { IntegerPairSettingType, SETTING_NAME_UNLOADED_WINDOW_POSITION, L"0,0" }, { ScalableIntegerPairSettingType, SETTING_NAME_UNLOADED_WINDOW_SIZE, L"@96|350,270" }, { StringSettingType, SETTING_NAME_UNLOADED_COLUMNS, L"" }, + { IntegerPairSettingType, SETTING_NAME_MODULE_SERVICES_WINDOW_POSITION, L"0,0" }, + { ScalableIntegerPairSettingType, SETTING_NAME_MODULE_SERVICES_WINDOW_SIZE, L"@96|850,490" }, }; PhAddSettings(settings, sizeof(settings) / sizeof(PH_SETTING_CREATE)); diff --git a/plugins/ExtendedTools/modsrv.c b/plugins/ExtendedTools/modsrv.c index b53b3133764b..4a756ed6d09b 100644 --- a/plugins/ExtendedTools/modsrv.c +++ b/plugins/ExtendedTools/modsrv.c @@ -3,6 +3,7 @@ * services referencing module * * Copyright (C) 2010-2011 wj32 + * Copyright (C) 2018 dmex * * This file is part of Process Hacker. * @@ -27,6 +28,7 @@ typedef struct _MODULE_SERVICES_CONTEXT { HANDLE ProcessId; PWSTR ModuleName; + PH_LAYOUT_MANAGER LayoutManager; } MODULE_SERVICES_CONTEXT, *PMODULE_SERVICES_CONTEXT; INT_PTR CALLBACK EtpModuleServicesDlgProc( @@ -44,6 +46,7 @@ VOID EtShowModuleServicesDialog( { MODULE_SERVICES_CONTEXT context; + memset(&context, 0, sizeof(MODULE_SERVICES_CONTEXT)); context.ProcessId = ProcessId; context.ModuleName = ModuleName; @@ -56,6 +59,76 @@ VOID EtShowModuleServicesDialog( ); } +PPH_LIST PhpQueryModuleServiceReferences( + _In_ HWND WindowHandle, + _In_ HANDLE ProcessId, + _In_ PWSTR ModuleName + ) +{ + ULONG win32Result; + PQUERY_TAG_INFORMATION I_QueryTagInformation; + TAG_INFO_NAMES_REFERENCING_MODULE namesReferencingModule; + PPH_LIST serviceList; + + if (!(I_QueryTagInformation = PhGetModuleProcAddress(L"advapi32.dll", "I_QueryTagInformation"))) + { + PhShowError(GetParent(WindowHandle), L"Unable to query services because the feature is not supported by the operating system."); + EndDialog(WindowHandle, IDCANCEL); + return NULL; + } + + memset(&namesReferencingModule, 0, sizeof(TAG_INFO_NAMES_REFERENCING_MODULE)); + namesReferencingModule.InParams.dwPid = HandleToUlong(ProcessId); + namesReferencingModule.InParams.pszModule = ModuleName; + + win32Result = I_QueryTagInformation(NULL, eTagInfoLevelNamesReferencingModule, &namesReferencingModule); + + if (win32Result == ERROR_NO_MORE_ITEMS) + win32Result = ERROR_SUCCESS; + + if (win32Result != ERROR_SUCCESS) + { + PhShowStatus(GetParent(WindowHandle), L"Unable to query module references.", 0, win32Result); + EndDialog(WindowHandle, IDCANCEL); + return NULL; + } + + serviceList = PhCreateList(16); + + if (namesReferencingModule.OutParams.pmszNames) + { + PPH_SERVICE_ITEM serviceItem; + PWSTR serviceName; + ULONG nameLength; + + serviceName = namesReferencingModule.OutParams.pmszNames; + + while (TRUE) + { + nameLength = (ULONG)PhCountStringZ(serviceName); + + if (nameLength == 0) + break; + + if (serviceItem = PhReferenceServiceItem(serviceName)) + PhAddItemList(serviceList, serviceItem); + + serviceName += nameLength + 1; + } + + LocalFree(namesReferencingModule.OutParams.pmszNames); + } + + //if (serviceList->Count == 0) + //{ + // PhShowInformation2(GetParent(WindowHandle), L"", L"This module was not referenced by a service."); + // EndDialog(WindowHandle, IDCANCEL); + // return NULL; + //} + + return serviceList; +} + INT_PTR CALLBACK EtpModuleServicesDlgProc( _In_ HWND hwndDlg, _In_ UINT uMsg, @@ -63,97 +136,96 @@ INT_PTR CALLBACK EtpModuleServicesDlgProc( _In_ LPARAM lParam ) { + PMODULE_SERVICES_CONTEXT context; + + if (uMsg == WM_INITDIALOG) + { + context = (PMODULE_SERVICES_CONTEXT)lParam; + PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context); + } + else + { + context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); + + if (uMsg == WM_DESTROY) + { + PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); + } + } + + if (!context) + return FALSE; + switch (uMsg) { case WM_INITDIALOG: { - PMODULE_SERVICES_CONTEXT context = (PMODULE_SERVICES_CONTEXT)lParam; - ULONG win32Result; - PQUERY_TAG_INFORMATION I_QueryTagInformation; - TAG_INFO_NAMES_REFERENCING_MODULE namesReferencingModule; PPH_LIST serviceList; PPH_SERVICE_ITEM *serviceItems; HWND serviceListHandle; RECT rect; - PPH_PROCESS_ITEM processItem; - PPH_STRING message; - - PhCenterWindow(hwndDlg, GetParent(hwndDlg)); - I_QueryTagInformation = PhGetModuleProcAddress(L"advapi32.dll", "I_QueryTagInformation"); - - if (!I_QueryTagInformation) - { - PhShowError(hwndDlg, L"Unable to query services because the feature is not supported by the operating system."); - EndDialog(hwndDlg, IDCANCEL); + if (!(serviceList = PhpQueryModuleServiceReferences(hwndDlg, context->ProcessId, context->ModuleName))) return FALSE; - } - - memset(&namesReferencingModule, 0, sizeof(TAG_INFO_NAMES_REFERENCING_MODULE)); - namesReferencingModule.InParams.dwPid = HandleToUlong(context->ProcessId); - namesReferencingModule.InParams.pszModule = context->ModuleName; - - win32Result = I_QueryTagInformation(NULL, eTagInfoLevelNamesReferencingModule, &namesReferencingModule); - if (win32Result == ERROR_NO_MORE_ITEMS) - win32Result = 0; + SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhInstanceHandle, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); + SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhInstanceHandle, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); - if (win32Result != 0) - { - PhShowStatus(hwndDlg, L"Unable to query services", 0, win32Result); - EndDialog(hwndDlg, IDCANCEL); - return FALSE; - } - - serviceList = PhCreateList(16); + serviceItems = PhAllocateCopy(serviceList->Items, serviceList->Count * sizeof(PPH_SERVICE_ITEM)); + serviceListHandle = PhCreateServiceListControl(hwndDlg, serviceItems, serviceList->Count); + PhDereferenceObject(serviceList); - if (namesReferencingModule.OutParams.pmszNames) { - PPH_SERVICE_ITEM serviceItem; - PWSTR serviceName; - ULONG nameLength; + PPH_PROCESS_ITEM processItem; + PPH_STRING message; - serviceName = namesReferencingModule.OutParams.pmszNames; - - while (TRUE) + if (processItem = PhReferenceProcessItem(context->ProcessId)) { - nameLength = (ULONG)PhCountStringZ(serviceName); - - if (nameLength == 0) - break; - - if (serviceItem = PhReferenceServiceItem(serviceName)) - PhAddItemList(serviceList, serviceItem); - - serviceName += nameLength + 1; + message = PhFormatString(L"Services referencing %s in %s:", context->ModuleName, PhGetStringOrEmpty(processItem->ProcessName)); + PhDereferenceObject(processItem); + } + else + { + message = PhFormatString(L"Services referencing %s:", context->ModuleName); } - LocalFree(namesReferencingModule.OutParams.pmszNames); + PhSetDialogItemText(hwndDlg, IDC_MESSAGE, message->Buffer); + PhDereferenceObject(message); } - serviceItems = PhAllocateCopy(serviceList->Items, serviceList->Count * sizeof(PPH_SERVICE_ITEM)); - PhDereferenceObject(serviceList); - serviceListHandle = PhCreateServiceListControl(hwndDlg, serviceItems, serviceList->Count); - // Position the control. GetWindowRect(GetDlgItem(hwndDlg, IDC_SERVICES_LAYOUT), &rect); MapWindowPoints(NULL, hwndDlg, (POINT *)&rect, 2); MoveWindow(serviceListHandle, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, FALSE); - ShowWindow(serviceListHandle, SW_SHOW); - if (processItem = PhReferenceProcessItem(context->ProcessId)) - { - message = PhFormatString(L"Services referencing %s in %s:", context->ModuleName, processItem->ProcessName->Buffer); - PhDereferenceObject(processItem); - } + PhInitializeLayoutManager(&context->LayoutManager, hwndDlg); + PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_SERVICES_LAYOUT), NULL, PH_ANCHOR_ALL); + PhAddLayoutItem(&context->LayoutManager, serviceListHandle, NULL, PH_ANCHOR_ALL); + PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDOK), NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_RIGHT); + + if (PhGetIntegerPairSetting(SETTING_NAME_MODULE_SERVICES_WINDOW_POSITION).X != 0) + PhLoadWindowPlacementFromSetting(SETTING_NAME_MODULE_SERVICES_WINDOW_POSITION, SETTING_NAME_MODULE_SERVICES_WINDOW_SIZE, hwndDlg); else + PhCenterWindow(hwndDlg, GetParent(hwndDlg)); + } + break; + case WM_DESTROY: + { + if (IsWindowVisible(hwndDlg)) // HACK { - message = PhFormatString(L"Services referencing %s:", context->ModuleName); + PhSaveWindowPlacementToSetting(SETTING_NAME_MODULE_SERVICES_WINDOW_POSITION, SETTING_NAME_MODULE_SERVICES_WINDOW_SIZE, hwndDlg); } - PhSetDialogItemText(hwndDlg, IDC_MESSAGE, message->Buffer); - PhDereferenceObject(message); + if (context->LayoutManager.List) // HACK + { + PhDeleteLayoutManager(&context->LayoutManager); + } + } + break; + case WM_SIZE: + { + PhLayoutManagerLayout(&context->LayoutManager); } break; case WM_COMMAND: From 449d3cf4eb588d7a53335f5ca5fc4dde5ea1672a Mon Sep 17 00:00:00 2001 From: diversenok Date: Thu, 10 May 2018 11:46:15 +0300 Subject: [PATCH 0940/2058] UIAccess field in advanced token properties (#267) --- ProcessHacker/ProcessHacker.rc | 14 ++++++++------ ProcessHacker/resource.h | 3 ++- ProcessHacker/tokprp.c | 8 ++++++++ phlib/include/phnativeinl.h | 34 ++++++++++++++++++++++++++++++++++ 4 files changed, 52 insertions(+), 7 deletions(-) diff --git a/ProcessHacker/ProcessHacker.rc b/ProcessHacker/ProcessHacker.rc index 80f2dc46d03e..861262489dbe 100644 --- a/ProcessHacker/ProcessHacker.rc +++ b/ProcessHacker/ProcessHacker.rc @@ -792,7 +792,7 @@ STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSM CAPTION "General" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN - GROUPBOX "Token",IDC_STATIC,7,7,256,132 + GROUPBOX "Token",IDC_STATIC,7,7,256,149 LTEXT "User:",IDC_STATIC,15,19,18,8 EDITTEXT IDC_USER,71,17,185,12,ES_AUTOHSCROLL | ES_READONLY LTEXT "User SID:",IDC_STATIC,15,36,32,8 @@ -807,12 +807,14 @@ BEGIN EDITTEXT IDC_ELEVATED,71,102,117,12,ES_AUTOHSCROLL | ES_READONLY LTEXT "Virtualization:",IDC_STATIC,15,121,44,8 EDITTEXT IDC_VIRTUALIZATION,71,119,185,12,ES_AUTOHSCROLL | ES_READONLY + LTEXT "UIAccess:",IDC_STATIC,15,138,32,8 + EDITTEXT IDC_UIACCESS,71,136,185,12,ES_AUTOHSCROLL | ES_READONLY PUSHBUTTON "Linked token",IDC_LINKEDTOKEN,193,101,63,14 - GROUPBOX "Source",IDC_STATIC,7,143,256,47 - LTEXT "Name:",IDC_STATIC,15,155,22,8 - EDITTEXT IDC_SOURCENAME,71,153,185,12,ES_AUTOHSCROLL | ES_READONLY - LTEXT "LUID:",IDC_STATIC,15,173,19,8 - EDITTEXT IDC_SOURCELUID,71,171,185,12,ES_AUTOHSCROLL | ES_READONLY + GROUPBOX "Source",IDC_STATIC,7,160,256,47 + LTEXT "Name:",IDC_STATIC,15,172,22,8 + EDITTEXT IDC_SOURCENAME,71,170,185,12,ES_AUTOHSCROLL | ES_READONLY + LTEXT "LUID:",IDC_STATIC,15,190,19,8 + EDITTEXT IDC_SOURCELUID,71,188,185,12,ES_AUTOHSCROLL | ES_READONLY END IDD_TOKADVANCED DIALOGEX 0, 0, 236, 186 diff --git a/ProcessHacker/resource.h b/ProcessHacker/resource.h index e8aa0f5d6a35..8b25c5e044de 100644 --- a/ProcessHacker/resource.h +++ b/ProcessHacker/resource.h @@ -197,6 +197,7 @@ #define IDC_APPCONTAINERSID 1060 #define IDC_LIST 1061 #define IDC_TOKENUSER 1061 +#define IDC_UIACCESS 1061 #define IDC_TOKENSID 1062 #define IDC_PROCESSES 1063 #define IDC_SCAN 1064 @@ -750,7 +751,7 @@ // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 253 +#define _APS_NEXT_RESOURCE_VALUE 254 #define _APS_NEXT_COMMAND_VALUE 40297 #define _APS_NEXT_CONTROL_VALUE 1410 #define _APS_NEXT_SYMED_VALUE 170 diff --git a/ProcessHacker/tokprp.c b/ProcessHacker/tokprp.c index 2aa7a801a922..18e433834982 100644 --- a/ProcessHacker/tokprp.c +++ b/ProcessHacker/tokprp.c @@ -1268,6 +1268,7 @@ INT_PTR CALLBACK PhpTokenGeneralPageProc( PWSTR tokenElevated = L"N/A"; BOOLEAN hasLinkedToken = FALSE; PWSTR tokenVirtualization = L"N/A"; + PWSTR tokenUIAccess = L"Unknown"; WCHAR tokenSourceName[TOKEN_SOURCE_LENGTH + 1] = L"Unknown"; WCHAR tokenSourceLuid[PH_PTR_STR_LEN_1] = L"Unknown"; @@ -1286,6 +1287,7 @@ INT_PTR CALLBACK PhpTokenGeneralPageProc( TOKEN_ELEVATION_TYPE elevationType; BOOLEAN isVirtualizationAllowed; BOOLEAN isVirtualizationEnabled; + BOOLEAN isUIAccessEnabled; if (NT_SUCCESS(PhGetTokenUser(tokenHandle, &tokenUser))) { @@ -1331,6 +1333,11 @@ INT_PTR CALLBACK PhpTokenGeneralPageProc( } } + if (NT_SUCCESS(PhGetTokenIsUIAccessEnabled(tokenHandle, &isUIAccessEnabled))) + { + tokenUIAccess = isUIAccessEnabled ? L"Enabled": L"Disabled"; + } + NtClose(tokenHandle); } @@ -1370,6 +1377,7 @@ INT_PTR CALLBACK PhpTokenGeneralPageProc( PhSetDialogItemText(hwndDlg, IDC_ELEVATED, tokenElevated); PhSetDialogItemText(hwndDlg, IDC_VIRTUALIZATION, tokenVirtualization); + PhSetDialogItemText(hwndDlg, IDC_UIACCESS, tokenUIAccess); PhSetDialogItemText(hwndDlg, IDC_SOURCENAME, tokenSourceName); PhSetDialogItemText(hwndDlg, IDC_SOURCELUID, tokenSourceLuid); diff --git a/phlib/include/phnativeinl.h b/phlib/include/phnativeinl.h index cd136d9d6d49..9213db21ff54 100644 --- a/phlib/include/phnativeinl.h +++ b/phlib/include/phnativeinl.h @@ -1183,6 +1183,40 @@ PhGetTokenIsVirtualizationEnabled( return status; } +/** +* Gets UIAccess flag for a token. +* +* \param TokenHandle A handle to a token. The handle must have TOKEN_QUERY access. +* \param IsUIAccessEnabled A variable which receives a boolean indicating whether +* UIAccess is enabled for the token. +*/ +FORCEINLINE +NTSTATUS +PhGetTokenIsUIAccessEnabled( + _In_ HANDLE TokenHandle, + _Out_ PBOOLEAN IsUIAccessEnabled + ) +{ + NTSTATUS status; + ULONG returnLength; + ULONG uiAccess; + + status = NtQueryInformationToken( + TokenHandle, + TokenUIAccess, + &uiAccess, + sizeof(ULONG), + &returnLength + ); + + if (!NT_SUCCESS(status)) + return status; + + *IsUIAccessEnabled = !!uiAccess; + + return status; +} + FORCEINLINE NTSTATUS PhGetEventBasicInformation( From 2bb521f8ebf891dafa90cad8845864e90c8d72c3 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 18 May 2018 04:07:17 +1000 Subject: [PATCH 0941/2058] Fix PhCreateThread error checking regression --- phlib/basesup.c | 53 +++++++++++++++++++++++++++++++++++++-- phlib/include/phbasesup.h | 9 +++++++ 2 files changed, 60 insertions(+), 2 deletions(-) diff --git a/phlib/basesup.c b/phlib/basesup.c index c960e155950b..6a8a38012d7b 100644 --- a/phlib/basesup.c +++ b/phlib/basesup.c @@ -231,6 +231,7 @@ HANDLE PhCreateThread( _In_opt_ PVOID Parameter ) { + NTSTATUS status; HANDLE threadHandle; PPHP_BASE_THREAD_CONTEXT context; @@ -238,7 +239,7 @@ HANDLE PhCreateThread( context->StartAddress = StartAddress; context->Parameter = Parameter; - if (NT_SUCCESS(RtlCreateUserThread( + status = RtlCreateUserThread( NtCurrentProcess(), NULL, FALSE, @@ -249,7 +250,14 @@ HANDLE PhCreateThread( context, &threadHandle, NULL - ))) + ); + + // NOTE: PhCreateThread previously used CreateThread with callers using GetLastError() + // for checking errors. We need to preserve this behavior for compatibility -dmex + // TODO: Migrate code over to PhCreateThreadEx and remove this function. + RtlSetLastWin32ErrorAndNtStatusFromNtStatus(status); + + if (NT_SUCCESS(status)) { PHLIB_INC_STATISTIC(BaseThreadsCreated); return threadHandle; @@ -262,6 +270,47 @@ HANDLE PhCreateThread( } } +NTSTATUS PhCreateThreadEx( + _Out_ PHANDLE ThreadHandle, + _In_ PUSER_THREAD_START_ROUTINE StartAddress, + _In_opt_ PVOID Parameter + ) +{ + NTSTATUS status; + HANDLE threadHandle; + PPHP_BASE_THREAD_CONTEXT context; + + context = PhAllocateFromFreeList(&PhpBaseThreadContextFreeList); + context->StartAddress = StartAddress; + context->Parameter = Parameter; + + status = RtlCreateUserThread( + NtCurrentProcess(), + NULL, + FALSE, + 0, + 0, + 0, + PhpBaseThreadStart, + context, + &threadHandle, + NULL + ); + + if (NT_SUCCESS(status)) + { + PHLIB_INC_STATISTIC(BaseThreadsCreated); + *ThreadHandle = threadHandle; + } + else + { + PHLIB_INC_STATISTIC(BaseThreadsCreateFailed); + PhFreeToFreeList(&PhpBaseThreadContextFreeList, context); + } + + return status; +} + NTSTATUS PhCreateThread2( _In_ PUSER_THREAD_START_ROUTINE StartAddress, _In_opt_ PVOID Parameter diff --git a/phlib/include/phbasesup.h b/phlib/include/phbasesup.h index e856df089137..d90137dcd178 100644 --- a/phlib/include/phbasesup.h +++ b/phlib/include/phbasesup.h @@ -40,6 +40,15 @@ PhCreateThread( _In_opt_ PVOID Parameter ); +PHLIBAPI +NTSTATUS +NTAPI +PhCreateThreadEx( + _Out_ PHANDLE ThreadHandle, + _In_ PUSER_THREAD_START_ROUTINE StartAddress, + _In_opt_ PVOID Parameter + ); + PHLIBAPI NTSTATUS NTAPI From 6dd1fdb359fe6d7e41e066751bb9e86e31d42911 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 18 May 2018 04:07:42 +1000 Subject: [PATCH 0942/2058] Remove old code, Add comments --- phlib/graph.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/phlib/graph.c b/phlib/graph.c index b0a2d0402db1..350bdf04311b 100644 --- a/phlib/graph.c +++ b/phlib/graph.c @@ -633,8 +633,7 @@ VOID PhSetGraphText( DrawInfo->TextBoxRect = PhRectangleToRect(boxRectangle); } - -static HFONT PhpTrayIconFont( +static HFONT PhpTrayIconFont( // dmex VOID ) { @@ -663,7 +662,7 @@ static HFONT PhpTrayIconFont( return iconTextFont; } -VOID PhDrawTrayIconText( +VOID PhDrawTrayIconText( // dmex _In_ HDC hdc, _In_ PVOID Bits, _Inout_ PPH_GRAPH_DRAW_INFO DrawInfo, @@ -775,13 +774,6 @@ VOID PhpFreeGraphContext( PhFree(Context); } -static PWSTR PhpMakeGraphTooltipContextAtom( - VOID - ) -{ - PH_DEFINE_MAKE_ATOM(L"PhLib_GraphTooltipContext"); -} - static VOID PhpDeleteBufferedContext( _In_ PPHP_GRAPH_CONTEXT Context ) From 7b5bc2f53856a4333d3e0497e4e878e87d0bc5b9 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 18 May 2018 04:08:17 +1000 Subject: [PATCH 0943/2058] Fix PhGetWindowText regression --- phlib/guisup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phlib/guisup.c b/phlib/guisup.c index 8811d69e127f..9b1a1cfb27e6 100644 --- a/phlib/guisup.c +++ b/phlib/guisup.c @@ -347,7 +347,7 @@ ULONG PhGetWindowTextEx( } else { - length = PhGetWindowTextLength(hwnd); + length = GetWindowTextLength(hwnd); if (length == 0 || (Flags & PH_GET_WINDOW_TEXT_LENGTH_ONLY)) { From 9ad3b0be6ef965c4047ba55ccc30d6a8ab51d384 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 18 May 2018 04:11:48 +1000 Subject: [PATCH 0944/2058] Update attribute flags --- phlib/mapimg.c | 2 +- phlib/settings.c | 4 ++-- plugins/UserNotes/db.c | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/phlib/mapimg.c b/phlib/mapimg.c index 78baa8ed7923..947cde2e2d4f 100644 --- a/phlib/mapimg.c +++ b/phlib/mapimg.c @@ -254,7 +254,7 @@ NTSTATUS PhMapViewOfEntireFile( FileName, ((FILE_READ_ATTRIBUTES | FILE_READ_DATA) | (!ReadOnly ? (FILE_APPEND_DATA | FILE_WRITE_ATTRIBUTES | FILE_WRITE_DATA) : 0)) | SYNCHRONIZE, - 0, + FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ, FILE_OPEN, FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT diff --git a/phlib/settings.c b/phlib/settings.c index fd5ce5fd3e2f..8099df3088f1 100644 --- a/phlib/settings.c +++ b/phlib/settings.c @@ -756,7 +756,7 @@ NTSTATUS PhLoadSettings( &fileHandle, FileName, FILE_GENERIC_READ, - 0, + FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_DELETE, FILE_OPEN, FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT @@ -974,7 +974,7 @@ NTSTATUS PhSaveSettings( &fileHandle, FileName, FILE_GENERIC_WRITE, - 0, + FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ, FILE_OVERWRITE_IF, FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT diff --git a/plugins/UserNotes/db.c b/plugins/UserNotes/db.c index 76de395f4e98..70a6982efbcd 100644 --- a/plugins/UserNotes/db.c +++ b/plugins/UserNotes/db.c @@ -197,7 +197,7 @@ NTSTATUS LoadDb( &fileHandle, ObjectDbPath->Buffer, FILE_GENERIC_READ, - 0, + FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_DELETE, FILE_OPEN, FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT @@ -427,7 +427,7 @@ NTSTATUS SaveDb( &fileHandle, ObjectDbPath->Buffer, FILE_GENERIC_WRITE, - 0, + FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ, FILE_OVERWRITE_IF, FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT From 5be5319c069efc4ec4db67f883c0e5b398b7f9e4 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 18 May 2018 04:18:19 +1000 Subject: [PATCH 0945/2058] Fix dbghelp unicode initialization, Add dbghelp secure flag --- phlib/include/symprvp.h | 4 ++-- phlib/symprv.c | 21 +++++++++++---------- tools/peview/pdb.c | 10 +++++----- 3 files changed, 18 insertions(+), 17 deletions(-) diff --git a/phlib/include/symprvp.h b/phlib/include/symprvp.h index 4232e620d44b..322a96126c91 100644 --- a/phlib/include/symprvp.h +++ b/phlib/include/symprvp.h @@ -1,9 +1,9 @@ #ifndef _PH_SYMPRVP_H #define _PH_SYMPRVP_H -typedef BOOL (WINAPI *_SymInitialize)( +typedef BOOL (WINAPI *_SymInitializeW)( _In_ HANDLE hProcess, - _In_opt_ PCSTR UserSearchPath, + _In_opt_ PCWSTR UserSearchPath, _In_ BOOL fInvadeProcess ); diff --git a/phlib/symprv.c b/phlib/symprv.c index c1e3eddb0b90..e4b097167b1f 100644 --- a/phlib/symprv.c +++ b/phlib/symprv.c @@ -68,7 +68,7 @@ static PH_FAST_LOCK PhSymMutex = PH_FAST_LOCK_INIT; #define PH_LOCK_SYMBOLS() PhAcquireFastLockExclusive(&PhSymMutex) #define PH_UNLOCK_SYMBOLS() PhReleaseFastLockExclusive(&PhSymMutex) -_SymInitialize SymInitialize_I; +_SymInitializeW SymInitializeW_I; _SymCleanup SymCleanup_I; _SymEnumSymbolsW SymEnumSymbolsW_I; _SymFromAddrW SymFromAddrW_I; @@ -213,11 +213,11 @@ BOOL CALLBACK PhpSymbolCallbackFunction( { switch (ActionCode) { - case SymbolDeferredSymbolLoadStart: - case SymbolDeferredSymbolLoadComplete: - case SymbolDeferredSymbolLoadFailure: - case SymbolSymbolsUnloaded: - case SymbolDeferredSymbolLoadCancel: + case SymbolDeferredSymbolLoadStart: // CBA_DEFERRED_SYMBOL_LOAD_START + case SymbolDeferredSymbolLoadComplete: // CBA_DEFERRED_SYMBOL_LOAD_COMPLETE + case SymbolDeferredSymbolLoadFailure: // CBA_DEFERRED_SYMBOL_LOAD_FAILURE + case SymbolSymbolsUnloaded: // CBA_SYMBOLS_UNLOADED + case SymbolDeferredSymbolLoadCancel: // CBA_DEFERRED_SYMBOL_LOAD_CANCEL data = PhCreateAlloc(sizeof(PH_SYMBOL_EVENT_DATA)); memset(data, 0, sizeof(PH_SYMBOL_EVENT_DATA)); data->SymbolProvider = symbolProvider; @@ -324,7 +324,7 @@ VOID PhpSymbolProviderCompleteInitialization( if (dbghelpHandle) { - SymInitialize_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymInitialize", 0); + SymInitializeW_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymInitializeW", 0); SymCleanup_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymCleanup", 0); SymEnumSymbolsW_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymEnumSymbolsW", 0); SymFromAddrW_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymFromAddrW", 0); @@ -367,7 +367,8 @@ VOID PhpRegisterSymbolProvider( SymGetOptions_I() | SYMOPT_AUTO_PUBLICS | SYMOPT_CASE_INSENSITIVE | SYMOPT_DEFERRED_LOADS | SYMOPT_FAIL_CRITICAL_ERRORS | SYMOPT_INCLUDE_32BIT_MODULES | - SYMOPT_LOAD_LINES | SYMOPT_OMAP_FIND_NEAREST | SYMOPT_UNDNAME + SYMOPT_LOAD_LINES | SYMOPT_OMAP_FIND_NEAREST | SYMOPT_UNDNAME | + SYMOPT_SECURE // | SYMOPT_DEBUG ); PH_UNLOCK_SYMBOLS(); @@ -381,11 +382,11 @@ VOID PhpRegisterSymbolProvider( if (PhBeginInitOnce(&SymbolProvider->InitOnce)) { - if (SymInitialize_I) + if (SymInitializeW_I) { PH_LOCK_SYMBOLS(); - SymInitialize_I(SymbolProvider->ProcessHandle, NULL, FALSE); + SymInitializeW_I(SymbolProvider->ProcessHandle, NULL, FALSE); if (SymRegisterCallbackW64_I) SymRegisterCallbackW64_I(SymbolProvider->ProcessHandle, PhpSymbolCallbackFunction, (ULONG64)SymbolProvider); diff --git a/tools/peview/pdb.c b/tools/peview/pdb.c index 1e2cb793614b..a5f8e17a348b 100644 --- a/tools/peview/pdb.c +++ b/tools/peview/pdb.c @@ -26,9 +26,9 @@ #include #include -typedef BOOL (WINAPI *_SymInitialize)( +typedef BOOL (WINAPI *_SymInitializeW)( _In_ HANDLE hProcess, - _In_opt_ PCSTR UserSearchPath, + _In_opt_ PCWSTR UserSearchPath, _In_ BOOL fInvadeProcess ); @@ -112,7 +112,7 @@ typedef BOOL (WINAPI *_SymSetContext)( _In_opt_ PIMAGEHLP_CONTEXT Context ); -_SymInitialize SymInitialize_I = NULL; +_SymInitializeW SymInitializeW_I = NULL; _SymCleanup SymCleanup_I = NULL; _SymEnumSymbolsW SymEnumSymbolsW_I = NULL; _SymEnumTypesW SymEnumTypesW_I = NULL; @@ -2344,7 +2344,7 @@ NTSTATUS PeDumpFileSymbols( if (!(symsrvHandle = LoadLibrary(symsrvPath->Buffer))) return 1; - SymInitialize_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymInitialize", 0); + SymInitializeW_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymInitializeW", 0); SymCleanup_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymCleanup", 0); SymEnumSymbolsW_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymEnumSymbolsW", 0); SymEnumTypesW_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymEnumTypesW", 0); @@ -2365,7 +2365,7 @@ NTSTATUS PeDumpFileSymbols( SYMOPT_LOAD_LINES | SYMOPT_OMAP_FIND_NEAREST | SYMOPT_UNDNAME // SYMOPT_DEBUG ); - if (!SymInitialize_I(NtCurrentProcess(), NULL, FALSE)) + if (!SymInitializeW_I(NtCurrentProcess(), NULL, FALSE)) return 1; if (!SymSetSearchPathW_I(NtCurrentProcess(), L"SRV*C:\\symbols*http://msdl.microsoft.com/download/symbols")) From 73cc881868e9ec630c5484b105625cf4f1e5bba5 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 18 May 2018 04:19:28 +1000 Subject: [PATCH 0946/2058] Update PhCreateThread to PhCreateThreadEx --- phlib/provider.c | 7 +------ phlib/workqueue.c | 12 +++++++----- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/phlib/provider.c b/phlib/provider.c index 99d97a85a450..0dc7d50f1b00 100644 --- a/phlib/provider.c +++ b/phlib/provider.c @@ -246,12 +246,7 @@ VOID PhStartProviderThread( PhSetIntervalProviderThread(ProviderThread, ProviderThread->Interval); // Create and start the thread. - ProviderThread->ThreadHandle = PhCreateThread( - 0, - PhpProviderThreadStart, - ProviderThread - ); - + PhCreateThreadEx(&ProviderThread->ThreadHandle, PhpProviderThreadStart, ProviderThread); ProviderThread->State = ProviderThreadRunning; } diff --git a/phlib/workqueue.c b/phlib/workqueue.c index f0e364a9960d..84842c102b40 100644 --- a/phlib/workqueue.c +++ b/phlib/workqueue.c @@ -244,7 +244,7 @@ VOID PhpGetDefaultWorkQueueEnvironment( ) { memset(Environment, 0, sizeof(PH_WORK_QUEUE_ENVIRONMENT)); - Environment->BasePriority = 0; + Environment->BasePriority = THREAD_PRIORITY_NORMAL; Environment->IoPriority = IoPriorityNormal; Environment->PagePriority = MEMORY_PRIORITY_NORMAL; Environment->ForceUpdate = FALSE; @@ -369,14 +369,16 @@ BOOLEAN PhpCreateWorkQueueThread( if (!PhAcquireRundownProtection(&WorkQueue->RundownProtect)) return FALSE; - threadHandle = PhCreateThread(0, PhpWorkQueueThreadStart, WorkQueue); - - if (threadHandle) + if (NT_SUCCESS(PhCreateThreadEx( + &threadHandle, + PhpWorkQueueThreadStart, + WorkQueue + ))) { PHLIB_INC_STATISTIC(WqWorkQueueThreadsCreated); WorkQueue->CurrentThreads++; - NtClose(threadHandle); + NtClose(threadHandle); return TRUE; } else From 24f7ddb668fe02aa24ee03ad3a9effa5cb87e333 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 18 May 2018 04:20:19 +1000 Subject: [PATCH 0947/2058] Improve PhQueryRegistry error checking --- phlib/util.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/phlib/util.c b/phlib/util.c index 629f3d689179..18f11b4e94fe 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -3420,7 +3420,7 @@ ULONG PhQueryRegistryUlong( _In_opt_ PWSTR ValueName ) { - ULONG ulong = 0; + ULONG ulong = ULONG_MAX; PH_STRINGREF valueName; PKEY_VALUE_PARTIAL_INFORMATION buffer; @@ -3448,7 +3448,7 @@ ULONG64 PhQueryRegistryUlong64( _In_opt_ PWSTR ValueName ) { - ULONG64 ulong64 = 0; + ULONG64 ulong64 = ULLONG_MAX; PH_STRINGREF valueName; PKEY_VALUE_PARTIAL_INFORMATION buffer; @@ -3459,9 +3459,9 @@ ULONG64 PhQueryRegistryUlong64( if (NT_SUCCESS(PhQueryValueKey(KeyHandle, &valueName, KeyValuePartialInformation, &buffer))) { - if (buffer->Type == REG_QWORD) + if (buffer->Type == REG_DWORD || buffer->Type == REG_QWORD) { - if (buffer->DataLength == sizeof(ULONG64)) + if (buffer->DataLength == sizeof(ULONG) || buffer->DataLength == sizeof(ULONG64)) ulong64 = *(PULONG64)buffer->Data; } From 83b8f95c7bf9ba83760fc41f9f7a16534c63b25a Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 18 May 2018 04:21:47 +1000 Subject: [PATCH 0948/2058] Update attribute flags --- plugins/NetworkTools/tracert.c | 2 -- plugins/NetworkTools/update.c | 4 ++-- plugins/OnlineChecks/upload.c | 2 +- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/plugins/NetworkTools/tracert.c b/plugins/NetworkTools/tracert.c index 3ed9273c75b6..e4064f43e3a1 100644 --- a/plugins/NetworkTools/tracert.c +++ b/plugins/NetworkTools/tracert.c @@ -621,8 +621,6 @@ INT_PTR CALLBACK TracertDlgProc( SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhInstanceHandle, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhInstanceHandle, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); - PhCenterWindow(hwndDlg, PhMainWndHandle); - Static_SetText(hwndDlg, PhaFormatString(L"Tracing %s...", context->IpAddressString)->Buffer ); diff --git a/plugins/NetworkTools/update.c b/plugins/NetworkTools/update.c index 39c0ee32a5b5..19b39bdb414c 100644 --- a/plugins/NetworkTools/update.c +++ b/plugins/NetworkTools/update.c @@ -222,7 +222,7 @@ NTSTATUS GeoIPUpdateThread( &tempFileHandle, PhGetString(zipFilePath), FILE_GENERIC_READ | FILE_GENERIC_WRITE, - FILE_ATTRIBUTE_NOT_CONTENT_INDEXED | FILE_ATTRIBUTE_TEMPORARY, + FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OVERWRITE_IF, FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT @@ -408,7 +408,7 @@ NTSTATUS GeoIPUpdateThread( &mmdbFileHandle, PhGetStringOrEmpty(dbpath), FILE_GENERIC_READ | FILE_GENERIC_WRITE, - FILE_ATTRIBUTE_NOT_CONTENT_INDEXED | FILE_ATTRIBUTE_TEMPORARY, + FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OVERWRITE_IF, FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT diff --git a/plugins/OnlineChecks/upload.c b/plugins/OnlineChecks/upload.c index 291518c681d4..54235164b075 100644 --- a/plugins/OnlineChecks/upload.c +++ b/plugins/OnlineChecks/upload.c @@ -961,7 +961,7 @@ NTSTATUS UploadCheckThreadStart( &fileHandle, PhGetString(context->FileName), FILE_GENERIC_READ, - 0, + FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_DELETE, FILE_OPEN, FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT From 7f239aebc5f7c8752bfd32fe9d81215f36e2d910 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 18 May 2018 04:34:45 +1000 Subject: [PATCH 0949/2058] Fix service stop highlighting using disabled highlighting color --- ProcessHacker/settings.c | 4 ++ ProcessHacker/srvctl.c | 107 +++++++++++++++++++-------------------- ProcessHacker/srvlist.c | 10 ++-- 3 files changed, 60 insertions(+), 61 deletions(-) diff --git a/ProcessHacker/settings.c b/ProcessHacker/settings.c index 7e47a22c77ef..eee4636b8117 100644 --- a/ProcessHacker/settings.c +++ b/ProcessHacker/settings.c @@ -210,6 +210,8 @@ VOID PhAddDefaultSettings( PhpAddIntegerSetting(L"ColorProtectedHandles", L"777777"); PhpAddIntegerSetting(L"UseColorInheritHandles", L"1"); PhpAddIntegerSetting(L"ColorInheritHandles", L"ffff77"); + PhpAddIntegerSetting(L"UseColorServiceDisabled", L"1"); + PhpAddIntegerSetting(L"ColorServiceDisabled", L"6d6d6d"); // Dark grey PhpAddIntegerSetting(L"UseColorServiceStop", L"1"); PhpAddIntegerSetting(L"ColorServiceStop", L"6d6d6d"); // Dark grey PhpAddIntegerSetting(L"UseColorUnknown", L"1"); @@ -277,6 +279,8 @@ VOID PhUpdateCachedSettings( PH_UPDATE_SETTING(ColorProtectedHandles); PH_UPDATE_SETTING(UseColorInheritHandles); PH_UPDATE_SETTING(ColorInheritHandles); + PH_UPDATE_SETTING(UseColorServiceDisabled); + PH_UPDATE_SETTING(ColorServiceDisabled); PH_UPDATE_SETTING(UseColorServiceStop); PH_UPDATE_SETTING(ColorServiceStop); PH_UPDATE_SETTING(UseColorUnknown); diff --git a/ProcessHacker/srvctl.c b/ProcessHacker/srvctl.c index a3aab1c31363..06e2d0201934 100644 --- a/ProcessHacker/srvctl.c +++ b/ProcessHacker/srvctl.c @@ -29,6 +29,8 @@ #include #include +#include + typedef struct _PH_SERVICES_CONTEXT { PPH_SERVICE_ITEM *Services; @@ -39,6 +41,7 @@ typedef struct _PH_SERVICES_CONTEXT PH_LAYOUT_MANAGER LayoutManager; HWND WindowHandle; + HWND ListViewHandle; } PH_SERVICES_CONTEXT, *PPH_SERVICES_CONTEXT; #define WM_PH_SERVICE_PAGE_MODIFIED (WM_APP + 106) @@ -201,17 +204,16 @@ INT_PTR CALLBACK PhpServicesPageProc( _In_ LPARAM lParam ) { - PPH_SERVICES_CONTEXT servicesContext; - HWND lvHandle; + PPH_SERVICES_CONTEXT context; if (uMsg == WM_INITDIALOG) { - servicesContext = (PPH_SERVICES_CONTEXT)lParam; - PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, servicesContext); + context = (PPH_SERVICES_CONTEXT)lParam; + PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context); } else { - servicesContext = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); + context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); if (uMsg == WM_DESTROY) { @@ -219,11 +221,9 @@ INT_PTR CALLBACK PhpServicesPageProc( } } - if (!servicesContext) + if (!context) return FALSE; - lvHandle = GetDlgItem(hwndDlg, IDC_LIST); - switch (uMsg) { case WM_INITDIALOG: @@ -233,30 +233,31 @@ INT_PTR CALLBACK PhpServicesPageProc( PhRegisterCallback( &PhServiceModifiedEvent, ServiceModifiedHandler, - servicesContext, - &servicesContext->ModifiedEventRegistration + context, + &context->ModifiedEventRegistration ); - servicesContext->WindowHandle = hwndDlg; + context->WindowHandle = hwndDlg; + context->ListViewHandle = GetDlgItem(hwndDlg, IDC_LIST); // Initialize the list. - PhSetListViewStyle(lvHandle, TRUE, TRUE); - PhSetControlTheme(lvHandle, L"explorer"); - PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 120, L"Name"); - PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 220, L"Display name"); - PhAddListViewColumn(lvHandle, 2, 2, 2, LVCFMT_LEFT, 220, L"File name"); + PhSetListViewStyle(context->ListViewHandle, TRUE, TRUE); + PhSetControlTheme(context->ListViewHandle, L"explorer"); + PhAddListViewColumn(context->ListViewHandle, 0, 0, 0, LVCFMT_LEFT, 120, L"Name"); + PhAddListViewColumn(context->ListViewHandle, 1, 1, 1, LVCFMT_LEFT, 220, L"Display name"); + PhAddListViewColumn(context->ListViewHandle, 2, 2, 2, LVCFMT_LEFT, 220, L"File name"); - PhSetExtendedListView(lvHandle); + PhSetExtendedListView(context->ListViewHandle); - for (i = 0; i < servicesContext->NumberOfServices; i++) + for (i = 0; i < context->NumberOfServices; i++) { SC_HANDLE serviceHandle; PPH_SERVICE_ITEM serviceItem; INT lvItemIndex; - serviceItem = servicesContext->Services[i]; - lvItemIndex = PhAddListViewItem(lvHandle, MAXINT, serviceItem->Name->Buffer, serviceItem); - PhSetListViewSubItem(lvHandle, lvItemIndex, 1, serviceItem->DisplayName->Buffer); + serviceItem = context->Services[i]; + lvItemIndex = PhAddListViewItem(context->ListViewHandle, MAXINT, serviceItem->Name->Buffer, serviceItem); + PhSetListViewSubItem(context->ListViewHandle, lvItemIndex, 1, serviceItem->DisplayName->Buffer); if (serviceHandle = PhOpenService(serviceItem->Name->Buffer, SERVICE_QUERY_CONFIG)) { @@ -264,7 +265,7 @@ INT_PTR CALLBACK PhpServicesPageProc( if (fileName = PhGetServiceRelevantFileName(&serviceItem->Name->sr, serviceHandle)) { - PhSetListViewSubItem(lvHandle, lvItemIndex, 2, PhGetStringOrEmpty(fileName)); + PhSetListViewSubItem(context->ListViewHandle, lvItemIndex, 2, PhGetStringOrEmpty(fileName)); PhDereferenceObject(fileName); } @@ -272,52 +273,46 @@ INT_PTR CALLBACK PhpServicesPageProc( } } - ExtendedListView_SortItems(lvHandle); + ExtendedListView_SortItems(context->ListViewHandle); PhpFixProcessServicesControls(hwndDlg, NULL); - PhInitializeLayoutManager(&servicesContext->LayoutManager, hwndDlg); - PhAddLayoutItem(&servicesContext->LayoutManager, GetDlgItem(hwndDlg, IDC_LIST), - NULL, PH_ANCHOR_ALL); - PhAddLayoutItem(&servicesContext->LayoutManager, GetDlgItem(hwndDlg, IDC_DESCRIPTION), - NULL, PH_ANCHOR_LEFT | PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); - PhAddLayoutItem(&servicesContext->LayoutManager, GetDlgItem(hwndDlg, IDC_START), - NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); - PhAddLayoutItem(&servicesContext->LayoutManager, GetDlgItem(hwndDlg, IDC_PAUSE), - NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); + PhInitializeLayoutManager(&context->LayoutManager, hwndDlg); + PhAddLayoutItem(&context->LayoutManager, context->ListViewHandle, NULL, PH_ANCHOR_ALL); + PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_DESCRIPTION), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); + PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_START), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); + PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_PAUSE), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); } break; case WM_DESTROY: { ULONG i; - for (i = 0; i < servicesContext->NumberOfServices; i++) - PhDereferenceObject(servicesContext->Services[i]); + for (i = 0; i < context->NumberOfServices; i++) + PhDereferenceObject(context->Services[i]); - PhFree(servicesContext->Services); + PhFree(context->Services); PhUnregisterCallback( &PhServiceModifiedEvent, - &servicesContext->ModifiedEventRegistration + &context->ModifiedEventRegistration ); - if (servicesContext->ListViewSettingName) - PhSaveListViewColumnsToSetting(servicesContext->ListViewSettingName, lvHandle); + if (context->ListViewSettingName) + PhSaveListViewColumnsToSetting(context->ListViewSettingName, context->ListViewHandle); - PhDeleteLayoutManager(&servicesContext->LayoutManager); + PhDeleteLayoutManager(&context->LayoutManager); - PhFree(servicesContext); + PhFree(context); } break; case WM_COMMAND: { - INT id = LOWORD(wParam); - - switch (id) + switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDC_START: { - PPH_SERVICE_ITEM serviceItem = PhGetSelectedListViewItemParam(lvHandle); + PPH_SERVICE_ITEM serviceItem = PhGetSelectedListViewItemParam(context->ListViewHandle); if (serviceItem) { @@ -338,7 +333,7 @@ INT_PTR CALLBACK PhpServicesPageProc( break; case IDC_PAUSE: { - PPH_SERVICE_ITEM serviceItem = PhGetSelectedListViewItemParam(lvHandle); + PPH_SERVICE_ITEM serviceItem = PhGetSelectedListViewItemParam(context->ListViewHandle); if (serviceItem) { @@ -361,15 +356,15 @@ INT_PTR CALLBACK PhpServicesPageProc( { LPNMHDR header = (LPNMHDR)lParam; - PhHandleListViewNotifyBehaviors(lParam, lvHandle, PH_LIST_VIEW_DEFAULT_1_BEHAVIORS); + PhHandleListViewNotifyBehaviors(lParam, context->ListViewHandle, PH_LIST_VIEW_DEFAULT_1_BEHAVIORS); switch (header->code) { case NM_DBLCLK: { - if (header->hwndFrom == lvHandle) + if (header->hwndFrom == context->ListViewHandle) { - PPH_SERVICE_ITEM serviceItem = PhGetSelectedListViewItemParam(lvHandle); + PPH_SERVICE_ITEM serviceItem = PhGetSelectedListViewItemParam(context->ListViewHandle); if (serviceItem) { @@ -380,13 +375,13 @@ INT_PTR CALLBACK PhpServicesPageProc( break; case LVN_ITEMCHANGED: { - if (header->hwndFrom == lvHandle) + if (header->hwndFrom == context->ListViewHandle) { //LPNMITEMACTIVATE itemActivate = (LPNMITEMACTIVATE)header; PPH_SERVICE_ITEM serviceItem = NULL; - if (ListView_GetSelectedCount(lvHandle) == 1) - serviceItem = PhGetSelectedListViewItemParam(lvHandle); + if (ListView_GetSelectedCount(context->ListViewHandle) == 1) + serviceItem = PhGetSelectedListViewItemParam(context->ListViewHandle); PhpFixProcessServicesControls(hwndDlg, serviceItem); } @@ -397,7 +392,7 @@ INT_PTR CALLBACK PhpServicesPageProc( break; case WM_SIZE: { - PhLayoutManagerLayout(&servicesContext->LayoutManager); + PhLayoutManagerLayout(&context->LayoutManager); } break; case WM_PH_SERVICE_PAGE_MODIFIED: @@ -405,8 +400,8 @@ INT_PTR CALLBACK PhpServicesPageProc( PPH_SERVICE_MODIFIED_DATA serviceModifiedData = (PPH_SERVICE_MODIFIED_DATA)lParam; PPH_SERVICE_ITEM serviceItem = NULL; - if (ListView_GetSelectedCount(lvHandle) == 1) - serviceItem = PhGetSelectedListViewItemParam(lvHandle); + if (ListView_GetSelectedCount(context->ListViewHandle) == 1) + serviceItem = PhGetSelectedListViewItemParam(context->ListViewHandle); if (serviceModifiedData->Service == serviceItem) { @@ -420,8 +415,8 @@ INT_PTR CALLBACK PhpServicesPageProc( { PWSTR settingName = (PWSTR)lParam; - servicesContext->ListViewSettingName = settingName; - PhLoadListViewColumnsFromSetting(settingName, lvHandle); + context->ListViewSettingName = settingName; + PhLoadListViewColumnsFromSetting(settingName, context->ListViewHandle); } break; } diff --git a/ProcessHacker/srvlist.c b/ProcessHacker/srvlist.c index 76a853ef904e..9ab5abe3ab91 100644 --- a/ProcessHacker/srvlist.c +++ b/ProcessHacker/srvlist.c @@ -519,9 +519,9 @@ BEGIN_SORT_FUNCTION(StartType) sortResult = uintcmp(serviceItem1->StartType, serviceItem2->StartType); if (sortResult == 0) - sortResult = uintcmp(serviceItem1->DelayedStart, serviceItem2->DelayedStart); + sortResult = ucharcmp(serviceItem1->DelayedStart, serviceItem2->DelayedStart); if (sortResult == 0) - sortResult = uintcmp(serviceItem1->HasTriggers, serviceItem2->HasTriggers); + sortResult = ucharcmp(serviceItem1->HasTriggers, serviceItem2->HasTriggers); } END_SORT_FUNCTION @@ -682,7 +682,7 @@ BOOLEAN NTAPI PhpServiceTreeNewCallback( getCellText->Text = serviceItem->Name->sr; break; case PHSVTLC_DISPLAYNAME: - getCellText->Text = serviceItem->DisplayName->sr; + getCellText->Text = PhGetStringRef(serviceItem->DisplayName); break; case PHSVTLC_TYPE: PhInitializeStringRefLongHint(&getCellText->Text, PhGetServiceTypeString(serviceItem->Type)); @@ -809,9 +809,9 @@ BOOLEAN NTAPI PhpServiceTreeNewCallback( getNodeColor->BackColor = PhCsColorUnknown; getNodeColor->Flags |= TN_AUTO_FORECOLOR; } - else if (PhCsUseColorServiceStop && serviceItem->State == SERVICE_STOPPED && serviceItem->StartType == SERVICE_DISABLED) + else if (PhCsUseColorServiceDisabled && serviceItem->State == SERVICE_STOPPED && serviceItem->StartType == SERVICE_DISABLED) { - getNodeColor->BackColor = PhCsColorServiceStop; + getNodeColor->BackColor = PhCsColorServiceDisabled; getNodeColor->Flags |= TN_AUTO_FORECOLOR; } else if (PhCsUseColorServiceStop && serviceItem->State == SERVICE_STOPPED) From b6f5915694bbd88e9c93c75ecaa159abd665f6ca Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 18 May 2018 04:35:50 +1000 Subject: [PATCH 0950/2058] Update attribute flags --- ProcessHacker/plugin.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ProcessHacker/plugin.c b/ProcessHacker/plugin.c index ab51dc3fac58..3961261dee05 100644 --- a/ProcessHacker/plugin.c +++ b/ProcessHacker/plugin.c @@ -263,7 +263,7 @@ VOID PhLoadPlugins( &pluginsDirectoryHandle, PluginsDirectory->Buffer, FILE_GENERIC_READ, - 0, + FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ, FILE_OPEN, FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT From 23375aba3390b78da8234b8f6162a712f50e4c7d Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 18 May 2018 04:36:22 +1000 Subject: [PATCH 0951/2058] Fix handle properties file tab focus --- ProcessHacker/ntobjprp.c | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/ProcessHacker/ntobjprp.c b/ProcessHacker/ntobjprp.c index c091ed116d81..8515ea328b7e 100644 --- a/ProcessHacker/ntobjprp.c +++ b/ProcessHacker/ntobjprp.c @@ -410,7 +410,7 @@ static VOID PhpRefreshFilePageInfo( fileHandle, &ioStatusBlock, &deviceInformation, - sizeof(deviceInformation), + sizeof(FILE_FS_DEVICE_INFORMATION), FileFsDeviceInformation ))) { @@ -441,7 +441,7 @@ static VOID PhpRefreshFilePageInfo( fileHandle, &ioStatusBlock, &fileStandardInfo, - sizeof(fileStandardInfo), + sizeof(FILE_STANDARD_INFORMATION), FileStandardInformation ))) { @@ -464,7 +464,7 @@ static VOID PhpRefreshFilePageInfo( fileHandle, &ioStatusBlock, &filePositionInfo, - sizeof(filePositionInfo), + sizeof(FILE_POSITION_INFORMATION), FilePositionInformation ))) { @@ -500,7 +500,7 @@ static VOID PhpRefreshFilePageInfo( fileHandle, &ioStatusBlock, &fileModeInfo, - sizeof(fileModeInfo), + sizeof(FILE_MODE_INFORMATION), FileModeInformation ))) { @@ -575,19 +575,34 @@ INT_PTR CALLBACK PhpFilePageProc( pageContext->Context ))) { - IO_STATUS_BLOCK ioStatusBlock; + IO_STATUS_BLOCK isb; + + status = NtFlushBuffersFile(fileHandle, &isb); - status = NtFlushBuffersFile(fileHandle, &ioStatusBlock); NtClose(fileHandle); } if (!NT_SUCCESS(status)) - PhShowStatus(hwndDlg, L"Unable to flush the file buffer", status, 0); + PhShowStatus(hwndDlg, L"Unable to flush the file.", status, 0); } break; } } break; + case WM_NOTIFY: + { + LPNMHDR header = (LPNMHDR)lParam; + + switch (header->code) + { + case PSN_QUERYINITIALFOCUS: + { + SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, (LONG_PTR)GetDlgItem(hwndDlg, IDC_FLUSH)); + } + return TRUE; + } + } + break; } return FALSE; From a7fce86977d780e9fb2d104c345cdf2e26779007 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 18 May 2018 04:36:34 +1000 Subject: [PATCH 0952/2058] Add comment --- ProcessHacker/options.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ProcessHacker/options.c b/ProcessHacker/options.c index f5eed6009d7f..9a376906c538 100644 --- a/ProcessHacker/options.c +++ b/ProcessHacker/options.c @@ -1648,7 +1648,8 @@ static COLOR_ITEM ColorItems[] = COLOR_ITEM(L"ColorHandleFiltered", L"Filtered processes", L"Processes that are protected by handle object callbacks."), COLOR_ITEM(L"ColorUnknown", L"Untrusted DLLs and Services", L"Services and DLLs which are not digitally signed."), - COLOR_ITEM(L"ColorServiceStop", L"Disabled Services", L"Services which have been disabled.") + COLOR_ITEM(L"ColorServiceDisabled", L"Disabled Services", L"Services which have been disabled."), + //COLOR_ITEM(L"ColorServiceStop", L"Stopped Services", L"Services that are not running.") }; COLORREF NTAPI PhpColorItemColorFunction( From d58fb14b0312e1fe91766ff2e65acd09088a19ad Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 18 May 2018 04:37:41 +1000 Subject: [PATCH 0953/2058] Add missing header from commit 7f239ae --- ProcessHacker/include/phsettings.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ProcessHacker/include/phsettings.h b/ProcessHacker/include/phsettings.h index 6736aca2d197..d65d55d98f3e 100644 --- a/ProcessHacker/include/phsettings.h +++ b/ProcessHacker/include/phsettings.h @@ -70,6 +70,8 @@ EXT ULONG PhCsColorPhysical; EXT ULONG PhCsUseColorUnknown; EXT ULONG PhCsColorUnknown; +EXT ULONG PhCsUseColorServiceDisabled; +EXT ULONG PhCsColorServiceDisabled; EXT ULONG PhCsUseColorServiceStop; EXT ULONG PhCsColorServiceStop; From 832b4b1967eb72ad6d053067445ba94bd16199bf Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 18 May 2018 04:38:03 +1000 Subject: [PATCH 0954/2058] Fix TB_GETITEMRECT error checking --- plugins/ToolStatus/main.c | 72 +++++++++++++++++++-------------------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/plugins/ToolStatus/main.c b/plugins/ToolStatus/main.c index c749951c149e..c8d3a641c4f1 100644 --- a/plugins/ToolStatus/main.c +++ b/plugins/ToolStatus/main.c @@ -206,15 +206,15 @@ VOID ShowCustomizeMenu( GetCursorPos(&cursorPos); menu = PhCreateEMenu(); - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, COMMAND_ID_ENABLE_MENU, L"Main menu (auto-hide)", NULL, NULL), -1); - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, COMMAND_ID_ENABLE_SEARCHBOX, L"Search box", NULL, NULL), -1); - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, COMMAND_ID_ENABLE_CPU_GRAPH, L"CPU history", NULL, NULL), -1); - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, COMMAND_ID_ENABLE_IO_GRAPH, L"I/O history", NULL, NULL), -1); - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, COMMAND_ID_ENABLE_MEMORY_GRAPH, L"Physical memory history", NULL, NULL), -1); - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, COMMAND_ID_ENABLE_COMMIT_GRAPH, L"Commit charge history", NULL, NULL), -1); - PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), -1); - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, COMMAND_ID_TOOLBAR_LOCKUNLOCK, L"Lock the toolbar", NULL, NULL), -1); - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, COMMAND_ID_TOOLBAR_CUSTOMIZE, L"Customize...", NULL, NULL), -1); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, COMMAND_ID_ENABLE_MENU, L"Main menu (auto-hide)", NULL, NULL), ULONG_MAX); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, COMMAND_ID_ENABLE_SEARCHBOX, L"Search box", NULL, NULL), ULONG_MAX); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, COMMAND_ID_ENABLE_CPU_GRAPH, L"CPU history", NULL, NULL), ULONG_MAX); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, COMMAND_ID_ENABLE_IO_GRAPH, L"I/O history", NULL, NULL), ULONG_MAX); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, COMMAND_ID_ENABLE_MEMORY_GRAPH, L"Physical memory history", NULL, NULL), ULONG_MAX); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, COMMAND_ID_ENABLE_COMMIT_GRAPH, L"Commit charge history", NULL, NULL), ULONG_MAX); + PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, COMMAND_ID_TOOLBAR_LOCKUNLOCK, L"Lock the toolbar", NULL, NULL), ULONG_MAX); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, COMMAND_ID_TOOLBAR_CUSTOMIZE, L"Customize...", NULL, NULL), ULONG_MAX); if (ToolStatusConfig.AutoHideMenu) { @@ -260,7 +260,7 @@ VOID ShowCustomizeMenu( cursorPos.y ); - if (selectedItem && selectedItem->Id != -1) + if (selectedItem && selectedItem->Id != ULONG_MAX) { switch (selectedItem->Id) { @@ -795,7 +795,7 @@ LRESULT CALLBACK MainWndSubclassProc( }; // Get the client coordinates of the button. - if (SendMessage(ToolBarHandle, TB_GETITEMRECT, index, (LPARAM)&buttonRect) == -1) + if (SendMessage(ToolBarHandle, TB_GETITEMRECT, index, (LPARAM)&buttonRect) == 0) break; if (buttonRect.right <= toolbarRect.right) @@ -808,7 +808,7 @@ LRESULT CALLBACK MainWndSubclassProc( if (buttonInfo.fsStyle == BTNS_SEP) { // Add separators to menu. - PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), -1); + PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX); } else { @@ -850,16 +850,16 @@ LRESULT CALLBACK MainWndSubclassProc( case TIDC_POWERMENUDROPDOWN: { // Create the sub-menu... - PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, PHAPP_ID_COMPUTER_LOCK, L"&Lock", NULL, NULL), -1); - PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, PHAPP_ID_COMPUTER_LOGOFF, L"Log o&ff", NULL, NULL), -1); - PhInsertEMenuItem(menuItem, PhCreateEMenuSeparator(), -1); - PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, PHAPP_ID_COMPUTER_SLEEP, L"&Sleep", NULL, NULL), -1); - PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, PHAPP_ID_COMPUTER_HIBERNATE, L"&Hibernate", NULL, NULL), -1); - PhInsertEMenuItem(menuItem, PhCreateEMenuSeparator(), -1); - PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, PHAPP_ID_COMPUTER_RESTART, L"R&estart", NULL, NULL), -1); - PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, PHAPP_ID_COMPUTER_RESTARTBOOTOPTIONS, L"Restart to boot &options", NULL, NULL), -1); - PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, PHAPP_ID_COMPUTER_SHUTDOWN, L"Shu&t down", NULL, NULL), -1); - PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, PHAPP_ID_COMPUTER_SHUTDOWNHYBRID, L"H&ybrid shut down", NULL, NULL), -1); + PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, PHAPP_ID_COMPUTER_LOCK, L"&Lock", NULL, NULL), ULONG_MAX); + PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, PHAPP_ID_COMPUTER_LOGOFF, L"Log o&ff", NULL, NULL), ULONG_MAX); + PhInsertEMenuItem(menuItem, PhCreateEMenuSeparator(), ULONG_MAX); + PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, PHAPP_ID_COMPUTER_SLEEP, L"&Sleep", NULL, NULL), ULONG_MAX); + PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, PHAPP_ID_COMPUTER_HIBERNATE, L"&Hibernate", NULL, NULL), ULONG_MAX); + PhInsertEMenuItem(menuItem, PhCreateEMenuSeparator(), ULONG_MAX); + PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, PHAPP_ID_COMPUTER_RESTART, L"R&estart", NULL, NULL), ULONG_MAX); + PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, PHAPP_ID_COMPUTER_RESTARTBOOTOPTIONS, L"Restart to boot &options", NULL, NULL), ULONG_MAX); + PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, PHAPP_ID_COMPUTER_SHUTDOWN, L"Shu&t down", NULL, NULL), ULONG_MAX); + PhInsertEMenuItem(menuItem, PhCreateEMenuItem(0, PHAPP_ID_COMPUTER_SHUTDOWNHYBRID, L"H&ybrid shut down", NULL, NULL), ULONG_MAX); if (WindowsVersion < WINDOWS_8) { @@ -874,7 +874,7 @@ LRESULT CALLBACK MainWndSubclassProc( break; } - PhInsertEMenuItem(menu, menuItem, -1); + PhInsertEMenuItem(menu, menuItem, ULONG_MAX); } } @@ -889,7 +889,7 @@ LRESULT CALLBACK MainWndSubclassProc( rebar->rc.bottom ); - if (selectedItem && selectedItem->Id != -1) + if (selectedItem && selectedItem->Id != ULONG_MAX) { SendMessage(PhMainWndHandle, WM_COMMAND, MAKEWPARAM(selectedItem->Id, BN_CLICKED), 0); } @@ -978,16 +978,16 @@ LRESULT CALLBACK MainWndSubclassProc( break; menu = PhCreateEMenu(); - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, PHAPP_ID_COMPUTER_LOCK, L"&Lock", NULL, NULL), -1); - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, PHAPP_ID_COMPUTER_LOGOFF, L"Log o&ff", NULL, NULL), -1); - PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), -1); - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, PHAPP_ID_COMPUTER_SLEEP, L"&Sleep", NULL, NULL), -1); - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, PHAPP_ID_COMPUTER_HIBERNATE, L"&Hibernate", NULL, NULL), -1); - PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), -1); - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, PHAPP_ID_COMPUTER_RESTART, L"R&estart", NULL, NULL), -1); - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, PHAPP_ID_COMPUTER_RESTARTBOOTOPTIONS, L"Restart to boot &options", NULL, NULL), -1); - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, PHAPP_ID_COMPUTER_SHUTDOWN, L"Shu&t down", NULL, NULL), -1); - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, PHAPP_ID_COMPUTER_SHUTDOWNHYBRID, L"H&ybrid shut down", NULL, NULL), -1); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, PHAPP_ID_COMPUTER_LOCK, L"&Lock", NULL, NULL), ULONG_MAX); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, PHAPP_ID_COMPUTER_LOGOFF, L"Log o&ff", NULL, NULL), ULONG_MAX); + PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, PHAPP_ID_COMPUTER_SLEEP, L"&Sleep", NULL, NULL), ULONG_MAX); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, PHAPP_ID_COMPUTER_HIBERNATE, L"&Hibernate", NULL, NULL), ULONG_MAX); + PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, PHAPP_ID_COMPUTER_RESTART, L"R&estart", NULL, NULL), ULONG_MAX); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, PHAPP_ID_COMPUTER_RESTARTBOOTOPTIONS, L"Restart to boot &options", NULL, NULL), ULONG_MAX); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, PHAPP_ID_COMPUTER_SHUTDOWN, L"Shu&t down", NULL, NULL), ULONG_MAX); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, PHAPP_ID_COMPUTER_SHUTDOWNHYBRID, L"H&ybrid shut down", NULL, NULL), ULONG_MAX); if (WindowsVersion < WINDOWS_8) { @@ -1010,7 +1010,7 @@ LRESULT CALLBACK MainWndSubclassProc( toolbar->rcButton.bottom ); - if (selectedItem && selectedItem->Id != -1) + if (selectedItem && selectedItem->Id != ULONG_MAX) { SendMessage(PhMainWndHandle, WM_COMMAND, MAKEWPARAM(selectedItem->Id, BN_CLICKED), 0); } @@ -1023,7 +1023,7 @@ LRESULT CALLBACK MainWndSubclassProc( LPNMCLICK toolbar = (LPNMCLICK)hdr; ULONG id = (ULONG)toolbar->dwItemSpec; - if (id == -1) + if (id == ULONG_MAX) break; if (id == TIDC_FINDWINDOW || id == TIDC_FINDWINDOWTHREAD || id == TIDC_FINDWINDOWKILL) From e8422af3ed5a8930075f0b040ae4b70d1433d143 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 18 May 2018 04:38:54 +1000 Subject: [PATCH 0955/2058] Add workaround for RS5 insider build version checking --- phlib/global.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phlib/global.c b/phlib/global.c index 73670e07eae7..1100438bd8f5 100644 --- a/phlib/global.c +++ b/phlib/global.c @@ -217,7 +217,7 @@ static VOID PhInitializeWindowsVersion( WindowsVersion = WINDOWS_10_RS4; break; default: - WindowsVersion = WINDOWS_10; + WindowsVersion = WindowsVersion > 17134 ? WINDOWS_10_RS4 : WINDOWS_10; break; } } From 066f00752997adfb3b942eb9c107e9238ce7da0f Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 18 May 2018 04:40:05 +1000 Subject: [PATCH 0956/2058] NetworkTools: Update options window with geoip database path --- plugins/NetworkTools/NetworkTools.rc | 21 +++++++----- plugins/NetworkTools/options.c | 51 +++++++++++++++++++++++++++- plugins/NetworkTools/resource.h | 2 ++ 3 files changed, 64 insertions(+), 10 deletions(-) diff --git a/plugins/NetworkTools/NetworkTools.rc b/plugins/NetworkTools/NetworkTools.rc index 434e4122d907..2210087b200d 100644 --- a/plugins/NetworkTools/NetworkTools.rc +++ b/plugins/NetworkTools/NetworkTools.rc @@ -96,18 +96,21 @@ BEGIN CONTROL "",IDC_NETOUTPUTEDIT,"RICHEDIT50W",WS_VSCROLL | WS_TABSTOP | 0x4,2,2,387,212 END -IDD_OPTIONS DIALOGEX 0, 0, 201, 69 +IDD_OPTIONS DIALOGEX 0, 0, 253, 129 STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Options" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN - LTEXT "Ping packet length:",IDC_STATIC,9,7,62,8 - EDITTEXT IDC_PINGPACKETLENGTH,7,17,89,14,ES_AUTOHSCROLL | ES_NUMBER - EDITTEXT IDC_MAXHOPS,105,17,89,14,ES_AUTOHSCROLL | ES_NUMBER - LTEXT "Max Tracert Hops:",IDC_STATIC,105,7,60,8 + LTEXT "Ping packet length:",IDC_STATIC,9,25,62,8 + EDITTEXT IDC_PINGPACKETLENGTH,7,36,89,14,ES_AUTOHSCROLL | ES_NUMBER + EDITTEXT IDC_MAXHOPS,105,36,81,14,ES_AUTOHSCROLL | ES_NUMBER + LTEXT "Max Tracert Hops:",IDC_STATIC,105,25,60,8 CONTROL "Enable extended TCP statistics",IDC_ENABLE_EXTENDED_TCP, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,39,115,10 - LTEXT "Note: Changes may require an application restart.",IDC_STATIC,7,54,162,8 + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,7,115,10 + LTEXT "GeoIP database location:",IDC_STATIC,7,60,82,8 + EDITTEXT IDC_DATABASE,7,73,180,12,ES_AUTOHSCROLL + PUSHBUTTON "Browse...",IDC_BROWSE,193,72,50,14 + LTEXT "If a relative path is specified, it is relative to Process Hacker's directory. Environment variables can be used. Changes will take place after Process Hacker is restarted.",IDC_STATIC,7,92,235,26 END IDD_PING DIALOGEX 0, 0, 329, 151 @@ -657,9 +660,9 @@ BEGIN IDD_OPTIONS, DIALOG BEGIN LEFTMARGIN, 7 - RIGHTMARGIN, 194 + RIGHTMARGIN, 246 TOPMARGIN, 7 - BOTTOMMARGIN, 62 + BOTTOMMARGIN, 122 END IDD_PING, DIALOG diff --git a/plugins/NetworkTools/options.c b/plugins/NetworkTools/options.c index 1bdf98da77cb..58b3628ccb44 100644 --- a/plugins/NetworkTools/options.c +++ b/plugins/NetworkTools/options.c @@ -3,7 +3,7 @@ * options dialog * * Copyright (C) 2010-2013 wj32 - * Copyright (C) 2012-2013 dmex + * Copyright (C) 2012-2018 dmex * * This file is part of Process Hacker. * @@ -30,6 +30,8 @@ INT_PTR CALLBACK OptionsDlgProc( _In_ LPARAM lParam ) { + static PH_LAYOUT_MANAGER LayoutManager; + switch (uMsg) { case WM_INITDIALOG: @@ -37,6 +39,12 @@ INT_PTR CALLBACK OptionsDlgProc( PhSetDialogItemValue(hwndDlg, IDC_PINGPACKETLENGTH, PhGetIntegerSetting(SETTING_NAME_PING_SIZE), FALSE); PhSetDialogItemValue(hwndDlg, IDC_MAXHOPS, PhGetIntegerSetting(SETTING_NAME_TRACERT_MAX_HOPS), FALSE); Button_SetCheck(GetDlgItem(hwndDlg, IDC_ENABLE_EXTENDED_TCP), PhGetIntegerSetting(SETTING_NAME_EXTENDED_TCP_STATS) ? BST_CHECKED : BST_UNCHECKED); + + PhSetDialogItemText(hwndDlg, IDC_DATABASE, PhaGetStringSetting(SETTING_NAME_DB_LOCATION)->Buffer); + + PhInitializeLayoutManager(&LayoutManager, hwndDlg); + PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDC_DATABASE), NULL, PH_ANCHOR_TOP | PH_ANCHOR_LEFT | PH_ANCHOR_RIGHT); + PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDC_BROWSE), NULL, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); } break; case WM_DESTROY: @@ -44,6 +52,47 @@ INT_PTR CALLBACK OptionsDlgProc( PhSetIntegerSetting(SETTING_NAME_PING_SIZE, PhGetDialogItemValue(hwndDlg, IDC_PINGPACKETLENGTH)); PhSetIntegerSetting(SETTING_NAME_TRACERT_MAX_HOPS, PhGetDialogItemValue(hwndDlg, IDC_MAXHOPS)); PhSetIntegerSetting(SETTING_NAME_EXTENDED_TCP_STATS, Button_GetCheck(GetDlgItem(hwndDlg, IDC_ENABLE_EXTENDED_TCP)) == BST_CHECKED); + + PhSetStringSetting2(SETTING_NAME_DB_LOCATION, &PhaGetDlgItemText(hwndDlg, IDC_DATABASE)->sr); + + PhDeleteLayoutManager(&LayoutManager); + } + break; + case WM_SIZE: + { + PhLayoutManagerLayout(&LayoutManager); + } + break; + case WM_COMMAND: + { + switch (GET_WM_COMMAND_ID(wParam, lParam)) + { + case IDC_BROWSE: + { + static PH_FILETYPE_FILTER filters[] = + { + { L"XML files (*.xml)", L"*.xml" }, + { L"All files (*.*)", L"*.*" } + }; + PVOID fileDialog; + PPH_STRING fileName; + + fileDialog = PhCreateOpenFileDialog(); + PhSetFileDialogFilter(fileDialog, filters, RTL_NUMBER_OF(filters)); + + fileName = PH_AUTO(PhGetFileName(PhaGetDlgItemText(hwndDlg, IDC_DATABASE))); + PhSetFileDialogFileName(fileDialog, fileName->Buffer); + + if (PhShowFileDialog(hwndDlg, fileDialog)) + { + fileName = PH_AUTO(PhGetFileDialogFileName(fileDialog)); + PhSetDialogItemText(hwndDlg, IDC_DATABASE, fileName->Buffer); + } + + PhFreeFileDialog(fileDialog); + } + break; + } } break; } diff --git a/plugins/NetworkTools/resource.h b/plugins/NetworkTools/resource.h index 4c00392ba362..99edb719b85b 100644 --- a/plugins/NetworkTools/resource.h +++ b/plugins/NetworkTools/resource.h @@ -253,6 +253,8 @@ #define ZM_PNG 346 #define ZW_PNG 347 #define HU_PNG 348 +#define IDC_DATABASE 1001 +#define IDC_BROWSE 1002 #define IDC_PINGPACKETLENGTH 1008 #define IDC_NETOUTPUTEDIT 1009 #define IDC_MAXHOPS 1009 From 4ae91a32e1d8865984c49233adab590a7c59a375 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 18 May 2018 04:43:57 +1000 Subject: [PATCH 0957/2058] Improve GDI handle usage by 50% --- ProcessHacker/netlist.c | 2 +- ProcessHacker/procprp.c | 13 ++++++++++++- ProcessHacker/procprv.c | 21 --------------------- ProcessHacker/prpggen.c | 13 +++++++++++-- 4 files changed, 24 insertions(+), 25 deletions(-) diff --git a/ProcessHacker/netlist.c b/ProcessHacker/netlist.c index 8393fccc408b..e6dcdb1118c8 100644 --- a/ProcessHacker/netlist.c +++ b/ProcessHacker/netlist.c @@ -569,7 +569,7 @@ BOOLEAN NTAPI PhpNetworkTreeNewCallback( node = (PPH_NETWORK_NODE)getNodeIcon->Node; - if (node->NetworkItem->ProcessIconValid) + if (node->NetworkItem->ProcessIconValid && node->NetworkItem->ProcessIcon) { // TODO: Check if the icon handle is actually valid, since the process item // might get destroyed while the network node is still valid. diff --git a/ProcessHacker/procprp.c b/ProcessHacker/procprp.c index d5a0d32bc8ac..116930f2e7bd 100644 --- a/ProcessHacker/procprp.c +++ b/ProcessHacker/procprp.c @@ -121,7 +121,18 @@ VOID PhRefreshProcessPropContext( _Inout_ PPH_PROCESS_PROPCONTEXT PropContext ) { - PropContext->PropSheetHeader.hIcon = PropContext->ProcessItem->SmallIcon; + if (PropContext->ProcessItem->SmallIcon) + { + PropContext->PropSheetHeader.hIcon = PropContext->ProcessItem->SmallIcon; + } + else + { + HICON iconSmall; + + PhGetStockApplicationIcon(&iconSmall, NULL); + + PropContext->PropSheetHeader.hIcon = iconSmall; + } } VOID PhSetSelectThreadIdProcessPropContext( diff --git a/ProcessHacker/procprv.c b/ProcessHacker/procprv.c index 1ba88e80eebd..6aa48b122704 100644 --- a/ProcessHacker/procprv.c +++ b/ProcessHacker/procprv.c @@ -753,27 +753,6 @@ VOID PhpProcessQueryStage1( PhInitializeImageVersionInfo(&Data->VersionInfo, processItem->FileName->Buffer); } - // Use the default EXE icon if we didn't get the file's icon. - { - if (!Data->SmallIcon || !Data->LargeIcon) - { - if (Data->SmallIcon) - { - DestroyIcon(Data->SmallIcon); - Data->SmallIcon = NULL; - } - else if (Data->LargeIcon) - { - DestroyIcon(Data->LargeIcon); - Data->LargeIcon = NULL; - } - - PhGetStockApplicationIcon(&Data->SmallIcon, &Data->LargeIcon); - Data->SmallIcon = CopyIcon(Data->SmallIcon); - Data->LargeIcon = CopyIcon(Data->LargeIcon); - } - } - // Debugged if (processHandleLimited) { diff --git a/ProcessHacker/prpggen.c b/ProcessHacker/prpggen.c index 364e9e3e1360..bc94484fde51 100644 --- a/ProcessHacker/prpggen.c +++ b/ProcessHacker/prpggen.c @@ -200,8 +200,17 @@ INT_PTR CALLBACK PhpProcessGeneralDlgProc( // File - SendMessage(GetDlgItem(hwndDlg, IDC_FILEICON), STM_SETICON, - (WPARAM)processItem->LargeIcon, 0); + if (processItem->LargeIcon) + { + SendMessage(GetDlgItem(hwndDlg, IDC_FILEICON), STM_SETICON, (WPARAM)processItem->LargeIcon, 0); + } + else + { + HICON iconLarge; + + PhGetStockApplicationIcon(NULL, &iconLarge); + SendMessage(GetDlgItem(hwndDlg, IDC_FILEICON), STM_SETICON, (WPARAM)iconLarge, 0); + } if (PH_IS_REAL_PROCESS_ID(processItem->ProcessId)) { From 0dcd56928546d423311c613cc4bde984a6191184 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 18 May 2018 04:53:44 +1000 Subject: [PATCH 0958/2058] Update preprocessor definitions for debug builds --- ProcessHacker/ProcessHacker.vcxproj | 4 ++-- plugins/Plugins.props | 4 ++-- tools/peview/peview.vcxproj | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/ProcessHacker/ProcessHacker.vcxproj b/ProcessHacker/ProcessHacker.vcxproj index 66fadf3819d8..8056a72b422a 100644 --- a/ProcessHacker/ProcessHacker.vcxproj +++ b/ProcessHacker/ProcessHacker.vcxproj @@ -93,7 +93,7 @@ Disabled $(SolutionDir)phnt\include;$(SolutionDir)phlib\include;include;%(AdditionalIncludeDirectories) - _PHLIB_;_PHAPP_;_WINDOWS;HAVE_CONFIG_H;WIN32;DEBUG;%(PreprocessorDefinitions);$(ExternalCompilerOptions) + _PHLIB_;_PHAPP_;_WINDOWS;HAVE_CONFIG_H;WIN32;_DEBUG;DEBUG;%(PreprocessorDefinitions);$(ExternalCompilerOptions) EnableFastChecks MultiThreadedDebug Level3 @@ -125,7 +125,7 @@ Disabled $(SolutionDir)phnt\include;$(SolutionDir)phlib\include;include;%(AdditionalIncludeDirectories) - _PHLIB_;_PHAPP_;_WINDOWS;HAVE_CONFIG_H;WIN64;DEBUG;%(PreprocessorDefinitions);$(ExternalCompilerOptions) + _PHLIB_;_PHAPP_;_WINDOWS;HAVE_CONFIG_H;WIN64;_DEBUG;DEBUG;%(PreprocessorDefinitions);$(ExternalCompilerOptions) EnableFastChecks MultiThreadedDebug Level3 diff --git a/plugins/Plugins.props b/plugins/Plugins.props index 5069f7f3deee..47b6fdf83817 100644 --- a/plugins/Plugins.props +++ b/plugins/Plugins.props @@ -92,14 +92,14 @@ - WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions);$(ExternalCompilerOptions) + WIN32;DEBUG;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions);$(ExternalCompilerOptions) - WIN64;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions);$(ExternalCompilerOptions) + WIN64;DEBUG;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions);$(ExternalCompilerOptions) diff --git a/tools/peview/peview.vcxproj b/tools/peview/peview.vcxproj index b0d32756b17c..64ec66da2699 100644 --- a/tools/peview/peview.vcxproj +++ b/tools/peview/peview.vcxproj @@ -85,7 +85,7 @@ Disabled ..\..\phnt\include;..\..\phlib\include;include;%(AdditionalIncludeDirectories) - _PHLIB_;_WINDOWS;WIN32;DEBUG;%(PreprocessorDefinitions);$(ExternalCompilerOptions) + _PHLIB_;_WINDOWS;WIN32;_DEBUG;DEBUG;%(PreprocessorDefinitions);$(ExternalCompilerOptions) EnableFastChecks MultiThreadedDebug Level3 @@ -115,7 +115,7 @@ Disabled ..\..\phnt\include;..\..\phlib\include;include;%(AdditionalIncludeDirectories) - _PHLIB_;_WINDOWS;WIN64;DEBUG;%(PreprocessorDefinitions);$(ExternalCompilerOptions) + _PHLIB_;_WINDOWS;WIN64;_DEBUG;DEBUG;%(PreprocessorDefinitions);$(ExternalCompilerOptions) EnableFastChecks MultiThreadedDebug Level3 @@ -181,7 +181,7 @@ MaxSpeed true ..\..\phnt\include;..\..\phlib\include;include;%(AdditionalIncludeDirectories) - _PHLIB_;_WINDOWS;WIN64;DEBUG;%(PreprocessorDefinitions);$(ExternalCompilerOptions) + _PHLIB_;_WINDOWS;WIN64;NDEBUG;%(PreprocessorDefinitions);$(ExternalCompilerOptions) MultiThreaded true Level3 From b96ad14717e9bea25b74fd840715cbeca7801577 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 18 May 2018 05:25:16 +1000 Subject: [PATCH 0959/2058] Fix typo, Add LdrQueryImageFileExecutionOption --- phnt/include/ntldr.h | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/phnt/include/ntldr.h b/phnt/include/ntldr.h index 6f5a214ef8fd..ff43a541e857 100644 --- a/phnt/include/ntldr.h +++ b/phnt/include/ntldr.h @@ -284,6 +284,21 @@ LdrGetProcedureAddressEx( ); #endif +#if (PHNT_VERSION >= PHNT_THRESHOLD) +// rev +NTSYSAPI +NTSTATUS +NTAPI +LdrGetProcedureAddressForCaller( + _In_ PVOID DllHandle, + _In_opt_ PANSI_STRING ProcedureName, + _In_opt_ ULONG ProcedureNumber, + _Out_ PVOID *ProcedureAddress, + _In_ ULONG Flags, + _In_ PVOID *Callback + ); +#endif + #define LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS 0x00000001 #define LDR_LOCK_LOADER_LOCK_FLAG_TRY_ONLY 0x00000002 @@ -750,7 +765,20 @@ LdrQueryImageFileExecutionOptions( _In_ ULONG ValueSize, _Out_ PVOID Buffer, _In_ ULONG BufferSize, - _Out_opt_ PULONG RetunedLength + _Out_opt_ PULONG ReturnedLength + ); + +NTSYSAPI +NTSTATUS +NTAPI +LdrQueryImageFileExecutionOptionsEx( + _In_ PUNICODE_STRING SubKey, + _In_ PCWSTR ValueName, + _In_ ULONG Type, + _Out_ PVOID Buffer, + _In_ ULONG BufferSize, + _Out_opt_ PULONG ReturnedLength, + _In_ BOOLEAN Wow64 ); #endif // (PHNT_MODE != PHNT_MODE_KERNEL) From 960c49c533ae07524a38e76b6f5469c6fdfd381f Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 18 May 2018 05:25:40 +1000 Subject: [PATCH 0960/2058] Update preprocessor definitions for debug builds --- phlib/phlib.vcxproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/phlib/phlib.vcxproj b/phlib/phlib.vcxproj index c518c7699a96..5ae8a6768d29 100644 --- a/phlib/phlib.vcxproj +++ b/phlib/phlib.vcxproj @@ -77,7 +77,7 @@ Disabled $(SolutionDir)phnt\include;include;%(AdditionalIncludeDirectories) - DEBUG;_PHLIB_;%(PreprocessorDefinitions) + DEBUG;_DEBUG;_PHLIB_;%(PreprocessorDefinitions) true EnableFastChecks MultiThreadedDebug @@ -92,7 +92,7 @@ Disabled $(SolutionDir)phnt\include;include;%(AdditionalIncludeDirectories) - DEBUG;_PHLIB_;%(PreprocessorDefinitions) + DEBUG;_DEBUG;_PHLIB_;%(PreprocessorDefinitions) true EnableFastChecks MultiThreadedDebug From eea67e48a3c4b39cc45ef1f7fa22903f9da21c65 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 21 May 2018 07:45:46 +1000 Subject: [PATCH 0961/2058] Add PhSetWindowAlwaysOnTop --- phlib/guisup.c | 15 +++++++++++++++ phlib/include/guisup.h | 8 ++++++++ 2 files changed, 23 insertions(+) diff --git a/phlib/guisup.c b/phlib/guisup.c index 9b1a1cfb27e6..89cc7bbe54cc 100644 --- a/phlib/guisup.c +++ b/phlib/guisup.c @@ -3,6 +3,7 @@ * GUI support functions * * Copyright (C) 2009-2016 wj32 + * Copyright (C) 2017-2018 dmex * * This file is part of Process Hacker. * @@ -1514,3 +1515,17 @@ VOID PhSetDialogItemText( SendMessage(controlHandle, WM_SETTEXT, 0, (LPARAM)WindowText); // DefWindowProc } } + +VOID PhSetWindowAlwaysOnTop( + _In_ HWND WindowHandle, + _In_ BOOLEAN AlwaysOnTop + ) +{ + SetFocus(WindowHandle); // HACK - SetWindowPos doesn't work properly without this + SetWindowPos( + WindowHandle, + AlwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST, + 0, 0, 0, 0, + SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE + ); +} diff --git a/phlib/include/guisup.h b/phlib/include/guisup.h index fb5c9642e7d7..52255f8bbe41 100644 --- a/phlib/include/guisup.h +++ b/phlib/include/guisup.h @@ -550,6 +550,14 @@ PhSetDialogItemText( _In_ PCWSTR WindowText ); +PHLIBAPI +VOID +NTAPI +PhSetWindowAlwaysOnTop( + _In_ HWND WindowHandle, + _In_ BOOLEAN AlwaysOnTop + ); + FORCEINLINE ULONG PhGetWindowTextLength( _In_ HWND WindowHandle ) From dfcc13932fa138ab41a6462e13915630f45567c6 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 21 May 2018 07:46:35 +1000 Subject: [PATCH 0962/2058] Add PhAllocateZero, Fix PhReAllocate SAL annotation --- phlib/include/phbasesup.h | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/phlib/include/phbasesup.h b/phlib/include/phbasesup.h index d90137dcd178..55846d5ce5d5 100644 --- a/phlib/include/phbasesup.h +++ b/phlib/include/phbasesup.h @@ -218,7 +218,7 @@ PHLIBAPI PVOID NTAPI PhReAllocate( - _Frees_ptr_ PVOID Memory, + _Frees_ptr_opt_ PVOID Memory, _In_ SIZE_T Size ); @@ -262,6 +262,20 @@ PhAllocateCopy( return copy; } +FORCEINLINE +PVOID +PhAllocateZero( + _In_ SIZE_T Size + ) +{ + PVOID buffer; + + buffer = PhAllocate(Size); + memset(buffer, 0, Size); + + return buffer; +} + // Event #define PH_EVENT_SET 0x1 From 87acb83e67a760a3254b567abd87667e6c4b1d67 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 21 May 2018 07:47:02 +1000 Subject: [PATCH 0963/2058] Fix PhQueryRegistryUlong64 type check --- phlib/util.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/phlib/util.c b/phlib/util.c index 18f11b4e94fe..e743ea1ffa84 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -3459,9 +3459,14 @@ ULONG64 PhQueryRegistryUlong64( if (NT_SUCCESS(PhQueryValueKey(KeyHandle, &valueName, KeyValuePartialInformation, &buffer))) { - if (buffer->Type == REG_DWORD || buffer->Type == REG_QWORD) + if (buffer->Type == REG_DWORD) + { + if (buffer->DataLength == sizeof(ULONG)) + ulong64 = *(PULONG)buffer->Data; + } + else if (buffer->Type == REG_QWORD) { - if (buffer->DataLength == sizeof(ULONG) || buffer->DataLength == sizeof(ULONG64)) + if (buffer->DataLength == sizeof(ULONG64)) ulong64 = *(PULONG64)buffer->Data; } From 3d538095fc161237e983a71936053491eb2de654 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 21 May 2018 07:48:04 +1000 Subject: [PATCH 0964/2058] Update RTL types --- phnt/include/ntexapi.h | 2 +- phnt/include/ntrtl.h | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/phnt/include/ntexapi.h b/phnt/include/ntexapi.h index 0a429e566cc1..ad830b677966 100644 --- a/phnt/include/ntexapi.h +++ b/phnt/include/ntexapi.h @@ -3431,7 +3431,7 @@ typedef enum _HARDERROR_RESPONSE ResponseContinue } HARDERROR_RESPONSE; -// HARDERROR_MSG not included +#define HARDERROR_OVERRIDE_ERRORMODE 0x10000000 NTSYSCALLAPI NTSTATUS diff --git a/phnt/include/ntrtl.h b/phnt/include/ntrtl.h index c930b0afb92a..c7f273ccc479 100644 --- a/phnt/include/ntrtl.h +++ b/phnt/include/ntrtl.h @@ -1374,6 +1374,15 @@ RtlUpperString( _In_ PSTRING SourceString ); +FORCEINLINE +BOOLEAN +RtlIsNullOrEmptyUnicodeString( + _In_opt_ PUNICODE_STRING String + ) +{ + return !String || String->Length == 0; +} + FORCEINLINE VOID NTAPI @@ -2629,6 +2638,24 @@ RtlSetThreadIsCritical( _In_ BOOLEAN CheckFlag ); +#if (PHNT_VERSION >= PHNT_REDSTONE3) +// rev +NTSYSAPI +BOOLEAN +NTAPI +RtlIsCurrentProcess( // NtCompareObjects(NtCurrentProcess(), ProcessHandle) + _In_ HANDLE ProcessHandle + ); + +// rev +NTSYSAPI +BOOLEAN +NTAPI +RtlIsCurrentThread( // NtCompareObjects(NtCurrentThread(), ThreadHandle) + _In_ HANDLE ThreadHandle + ); +#endif + // Threads typedef NTSTATUS (NTAPI *PUSER_THREAD_START_ROUTINE)( @@ -6539,6 +6566,17 @@ typedef struct _RTL_UNLOAD_EVENT_TRACE ULONG Version[2]; } RTL_UNLOAD_EVENT_TRACE, *PRTL_UNLOAD_EVENT_TRACE; +typedef struct _RTL_UNLOAD_EVENT_TRACE32 +{ + ULONG BaseAddress; + ULONG SizeOfImage; + ULONG Sequence; + ULONG TimeDateStamp; + ULONG CheckSum; + WCHAR ImageName[32]; + ULONG Version[2]; +} RTL_UNLOAD_EVENT_TRACE32, *PRTL_UNLOAD_EVENT_TRACE32; + NTSYSAPI PRTL_UNLOAD_EVENT_TRACE NTAPI From a07be6999f662ae92de54111305947750bd129ac Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 21 May 2018 07:51:00 +1000 Subject: [PATCH 0965/2058] UserNotes: Fix saved priority getting set multiple times for saved processes --- plugins/UserNotes/main.c | 64 ++++++++++++++++++++++++++++------------ 1 file changed, 45 insertions(+), 19 deletions(-) diff --git a/plugins/UserNotes/main.c b/plugins/UserNotes/main.c index 79690803cd53..29ca7bc1e931 100644 --- a/plugins/UserNotes/main.c +++ b/plugins/UserNotes/main.c @@ -209,7 +209,7 @@ IO_PRIORITY_HINT GetProcessIoPriority( ) { HANDLE processHandle; - IO_PRIORITY_HINT ioPriority = -1; + IO_PRIORITY_HINT ioPriority = ULONG_MAX; if (NT_SUCCESS(PhOpenProcess( &processHandle, @@ -222,7 +222,7 @@ IO_PRIORITY_HINT GetProcessIoPriority( &ioPriority ))) { - ioPriority = -1; + ioPriority = ULONG_MAX; } NtClose(processHandle); @@ -406,8 +406,14 @@ VOID NTAPI MenuItemCallback( } else { + IO_PRIORITY_HINT ioPriority; + object = CreateDbObject(FILE_TAG, &processItem->ProcessName->sr, NULL); - object->IoPriorityPlusOne = GetProcessIoPriority(processItem->ProcessId) + 1; + + if ((ioPriority = GetProcessIoPriority(processItem->ProcessId)) != ULONG_MAX) + { + object->IoPriorityPlusOne = ioPriority + 1; + } } UnlockDb(); @@ -427,8 +433,14 @@ VOID NTAPI MenuItemCallback( } else { + IO_PRIORITY_HINT ioPriority; + object = CreateDbObject(COMMAND_LINE_TAG, &processItem->CommandLine->sr, NULL); - object->IoPriorityPlusOne = GetProcessIoPriority(processItem->ProcessId) + 1; + + if ((ioPriority = GetProcessIoPriority(processItem->ProcessId)) != ULONG_MAX) + { + object->IoPriorityPlusOne = ioPriority + 1; + } } UnlockDb(); @@ -1210,16 +1222,23 @@ VOID ProcessesUpdatedCallback( { if (object->IoPriorityPlusOne != 0) { - HANDLE processHandle; + IO_PRIORITY_HINT ioPriority; - if (NT_SUCCESS(PhOpenProcess( - &processHandle, - PROCESS_SET_INFORMATION, - processItem->ProcessId - ))) + ioPriority = GetProcessIoPriority(processItem->ProcessId); + + if (ioPriority != ULONG_MAX && ioPriority != object->IoPriorityPlusOne - 1) { - PhSetProcessIoPriority(processHandle, object->IoPriorityPlusOne - 1); - NtClose(processHandle); + HANDLE processHandle; + + if (NT_SUCCESS(PhOpenProcess( + &processHandle, + PROCESS_SET_INFORMATION, + processItem->ProcessId + ))) + { + PhSetProcessIoPriority(processHandle, object->IoPriorityPlusOne - 1); + NtClose(processHandle); + } } } } @@ -1228,16 +1247,23 @@ VOID ProcessesUpdatedCallback( { if (object->AffinityMask != 0) { + ULONG_PTR affinityMask; HANDLE processHandle; - if (NT_SUCCESS(PhOpenProcess( - &processHandle, - PROCESS_SET_INFORMATION, - processItem->ProcessId - ))) + if (NT_SUCCESS(GetProcessAffinity(processItem->ProcessId, &affinityMask))) { - PhSetProcessAffinityMask(processHandle, object->AffinityMask); - NtClose(processHandle); + if (affinityMask != object->AffinityMask) + { + if (NT_SUCCESS(PhOpenProcess( + &processHandle, + PROCESS_SET_INFORMATION, + processItem->ProcessId + ))) + { + PhSetProcessAffinityMask(processHandle, object->AffinityMask); + NtClose(processHandle); + } + } } } } From 810b4120ff7f35fcaea74ae818ee0f1d6f44413d Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 21 May 2018 07:51:13 +1000 Subject: [PATCH 0966/2058] Fix typo --- ProcessHacker/findobj.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ProcessHacker/findobj.c b/ProcessHacker/findobj.c index 363249909ca1..2cf013104f62 100644 --- a/ProcessHacker/findobj.c +++ b/ProcessHacker/findobj.c @@ -656,10 +656,10 @@ VOID PhpPopulateObjectTypes( { LONG maxLength; - HDC screenDc; + HDC comboDc; maxLength = 0; - screenDc = GetDC(FilterTypeCombo); + comboDc = GetDC(FilterTypeCombo); SendMessage(FilterTypeCombo, WM_SETFONT, (WPARAM)PhApplicationFont, TRUE); @@ -668,7 +668,7 @@ VOID PhpPopulateObjectTypes( PPH_STRING entry = objectTypeList->Items[i]; SIZE textSize; - if (GetTextExtentPoint32(screenDc, entry->Buffer, (ULONG)entry->Length / sizeof(WCHAR), &textSize)) + if (GetTextExtentPoint32(comboDc, entry->Buffer, (ULONG)entry->Length / sizeof(WCHAR), &textSize)) { if (textSize.cx > maxLength) maxLength = textSize.cx; @@ -678,7 +678,7 @@ VOID PhpPopulateObjectTypes( PhDereferenceObject(objectTypeList->Items[i]); } - ReleaseDC(FilterTypeCombo, screenDc); + ReleaseDC(FilterTypeCombo, comboDc); if (maxLength) { From 49f6e9ac8f59d77424bfbadceb9fe651f4a1750c Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 21 May 2018 07:53:23 +1000 Subject: [PATCH 0967/2058] peview: Disable resource tab hash column due to crashes inspecting vmprotected binaries --- tools/peview/resprp.c | 37 ++++++++++++++++++------------------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/tools/peview/resprp.c b/tools/peview/resprp.c index bf51770ad66b..e731b1a3649f 100644 --- a/tools/peview/resprp.c +++ b/tools/peview/resprp.c @@ -108,7 +108,7 @@ INT_PTR CALLBACK PvpPeResourcesDlgProc( PhAddListViewColumn(lvHandle, 2, 2, 2, LVCFMT_LEFT, 80, L"Name"); PhAddListViewColumn(lvHandle, 3, 3, 3, LVCFMT_LEFT, 100, L"Size"); PhAddListViewColumn(lvHandle, 4, 4, 4, LVCFMT_LEFT, 100, L"Language"); - PhAddListViewColumn(lvHandle, 5, 5, 5, LVCFMT_LEFT, 100, L"Hash"); + //PhAddListViewColumn(lvHandle, 5, 5, 5, LVCFMT_LEFT, 100, L"Hash"); PhSetExtendedListView(lvHandle); PhLoadListViewColumnsFromSetting(L"ImageResourcesListViewColumns", lvHandle); @@ -177,20 +177,21 @@ INT_PTR CALLBACK PvpPeResourcesDlgProc( PhSetListViewSubItem(lvHandle, lvItemIndex, PVE_RESOURCES_COLUMN_INDEX_SIZE, PhaFormatSize(entry.Size, -1)->Buffer); - if (entry.Data && entry.Size) - { - PH_HASH_CONTEXT hashContext; - PPH_STRING hashString; - UCHAR hash[32]; - - PhInitializeHash(&hashContext, PhGetIntegerSetting(L"HashAlgorithm")); - PhUpdateHash(&hashContext, entry.Data, entry.Size); - PhFinalHash(&hashContext, hash, 16, NULL); - - hashString = PhBufferToHexString(hash, 16); - PhSetListViewSubItem(lvHandle, lvItemIndex, PVE_RESOURCES_COLUMN_INDEX_HASH, hashString->Buffer); - PhDereferenceObject(hashString); - } + // dmex: This crashes when enumerating resources of VM protected binaries. + //if (entry.Data && entry.Size) + //{ + // PH_HASH_CONTEXT hashContext; + // PPH_STRING hashString; + // UCHAR hash[32]; + // + // PhInitializeHash(&hashContext, PhGetIntegerSetting(L"HashAlgorithm")); + // PhUpdateHash(&hashContext, entry.Data, entry.Size); + // PhFinalHash(&hashContext, hash, 16, NULL); + // + // hashString = PhBufferToHexString(hash, 16); + // PhSetListViewSubItem(lvHandle, lvItemIndex, PVE_RESOURCES_COLUMN_INDEX_HASH, hashString->Buffer); + // PhDereferenceObject(hashString); + //} } PhFree(resources.ResourceEntries); @@ -212,10 +213,8 @@ INT_PTR CALLBACK PvpPeResourcesDlgProc( { PPH_LAYOUT_ITEM dialogItem; - dialogItem = PvAddPropPageLayoutItem(hwndDlg, hwndDlg, - PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL); - PvAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_LIST), - dialogItem, PH_ANCHOR_ALL); + dialogItem = PvAddPropPageLayoutItem(hwndDlg, hwndDlg, PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL); + PvAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_LIST), dialogItem, PH_ANCHOR_ALL); PvDoPropPageLayout(hwndDlg); From 17d0209c9d50a89dd8817b3acc264843ed796cdf Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 21 May 2018 07:54:03 +1000 Subject: [PATCH 0968/2058] Fix options window styles --- ProcessHacker/ProcessHacker.rc | 1 - 1 file changed, 1 deletion(-) diff --git a/ProcessHacker/ProcessHacker.rc b/ProcessHacker/ProcessHacker.rc index 861262489dbe..de2d3815f662 100644 --- a/ProcessHacker/ProcessHacker.rc +++ b/ProcessHacker/ProcessHacker.rc @@ -1750,7 +1750,6 @@ END IDD_OPTIONS DIALOGEX 0, 0, 423, 247 STYLE DS_SETFONT | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME -EXSTYLE WS_EX_APPWINDOW CAPTION "Options" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN From e4d7f666118a5c52eeded34215dc8689c573d6be Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 21 May 2018 07:54:58 +1000 Subject: [PATCH 0969/2058] Add 'hide guard pages' option to process memory tab --- ProcessHacker/include/memlist.h | 4 +++- ProcessHacker/memlist.c | 7 +++++++ ProcessHacker/prpgmem.c | 35 +++++++++++++++++++++------------ 3 files changed, 32 insertions(+), 14 deletions(-) diff --git a/ProcessHacker/include/memlist.h b/ProcessHacker/include/memlist.h index 4a35acc97de2..dc52e9e53838 100644 --- a/ProcessHacker/include/memlist.h +++ b/ProcessHacker/include/memlist.h @@ -59,6 +59,7 @@ typedef struct _PH_MEMORY_NODE #define PH_MEMORY_FLAGS_SYSTEM_OPTION 4 #define PH_MEMORY_FLAGS_CFG_OPTION 5 #define PH_MEMORY_FLAGS_EXECUTE_OPTION 6 +#define PH_MEMORY_FLAGS_GUARD_OPTION 7 typedef struct _PH_MEMORY_LIST_CONTEXT { @@ -81,7 +82,8 @@ typedef struct _PH_MEMORY_LIST_CONTEXT ULONG HighlightSystemPages : 1; ULONG HighlightCfgPages : 1; ULONG HighlightExecutePages : 1; - ULONG Spare : 26; + ULONG HideGuardRegions : 1; + ULONG Spare : 25; }; }; diff --git a/ProcessHacker/memlist.c b/ProcessHacker/memlist.c index 61604aaeaa4b..e34b74971447 100644 --- a/ProcessHacker/memlist.c +++ b/ProcessHacker/memlist.c @@ -193,6 +193,9 @@ VOID PhSetOptionsMemoryList( case PH_MEMORY_FLAGS_EXECUTE_OPTION: Context->HighlightExecutePages = !Context->HighlightExecutePages; break; + case PH_MEMORY_FLAGS_GUARD_OPTION: + Context->HideGuardRegions = !Context->HideGuardRegions; + break; } } @@ -330,6 +333,8 @@ VOID PhReplaceMemoryList( if (Context->HideFreeRegions && (memoryItem->State & MEM_FREE)) memoryNode->Node.Visible = FALSE; + if (Context->HideGuardRegions && (memoryItem->Protect & PAGE_GUARD)) + memoryNode->Node.Visible = FALSE; if (allocationBaseNode && memoryItem->AllocationBase == allocationBaseNode->MemoryItem->BaseAddress) { @@ -362,6 +367,8 @@ VOID PhReplaceMemoryList( if (Context->HideFreeRegions && (allocationBaseNode->MemoryItem->State & MEM_FREE)) allocationBaseNode->Node.Visible = FALSE; + if (Context->HideGuardRegions && (allocationBaseNode->MemoryItem->State & PAGE_GUARD)) + memoryNode->Node.Visible = FALSE; } else { diff --git a/ProcessHacker/prpgmem.c b/ProcessHacker/prpgmem.c index c6ffe297f24d..581a302042e9 100644 --- a/ProcessHacker/prpgmem.c +++ b/ProcessHacker/prpgmem.c @@ -3,6 +3,7 @@ * Process properties: Memory page * * Copyright (C) 2009-2016 wj32 + * Copyright (C) 2017-2018 dmex * * This file is part of Process Hacker. * @@ -243,6 +244,8 @@ BOOLEAN PhpMemoryTreeFilterCallback( if (memoryContext->ListContext.HideFreeRegions && memoryItem->State & MEM_FREE) return FALSE; + if (memoryContext->ListContext.HideGuardRegions && memoryItem->Protect & PAGE_GUARD) + return FALSE; if (memoryContext->ListContext.HideReservedRegions && (memoryItem->Type & MEM_PRIVATE || memoryItem->Type & MEM_MAPPED || memoryItem->Type & MEM_IMAGE) && @@ -615,6 +618,7 @@ INT_PTR CALLBACK PhpProcessMemoryDlgProc( PPH_EMENU menu; PPH_EMENU_ITEM freeItem; PPH_EMENU_ITEM reservedItem; + PPH_EMENU_ITEM guardItem; PPH_EMENU_ITEM privateItem; PPH_EMENU_ITEM systemItem; PPH_EMENU_ITEM cfgItem; @@ -623,8 +627,6 @@ INT_PTR CALLBACK PhpProcessMemoryDlgProc( GetWindowRect(GetDlgItem(hwndDlg, IDC_FILTEROPTIONS), &rect); - menu = PhCreateEMenu(); - typedef enum _PH_MEMORY_FILTER_MENU_ITEM { PH_MEMORY_FILTER_MENU_HIDE_FREE = 1, @@ -633,26 +635,32 @@ INT_PTR CALLBACK PhpProcessMemoryDlgProc( PH_MEMORY_FILTER_MENU_HIGHLIGHT_SYSTEM, PH_MEMORY_FILTER_MENU_HIGHLIGHT_CFG, PH_MEMORY_FILTER_MENU_HIGHLIGHT_EXECUTE, + PH_MEMORY_FILTER_MENU_HIDE_GUARD, + // Non-standard PH_MEMORY_FLAG options. PH_MEMORY_FILTER_MENU_READ_ADDRESS, PH_MEMORY_FILTER_MENU_STRINGS, } PH_MEMORY_FILTER_MENU_ITEM; - PhInsertEMenuItem(menu, freeItem = PhCreateEMenuItem(0, PH_MEMORY_FILTER_MENU_HIDE_FREE, L"Hide free pages", NULL, NULL), -1); - PhInsertEMenuItem(menu, reservedItem = PhCreateEMenuItem(0, PH_MEMORY_FILTER_MENU_HIDE_RESERVED, L"Hide reserved pages", NULL, NULL), -1); - PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), -1); - PhInsertEMenuItem(menu, privateItem = PhCreateEMenuItem(0, PH_MEMORY_FILTER_MENU_HIGHLIGHT_PRIVATE, L"Highlight private pages", NULL, NULL), -1); - PhInsertEMenuItem(menu, systemItem = PhCreateEMenuItem(0, PH_MEMORY_FILTER_MENU_HIGHLIGHT_SYSTEM, L"Highlight system pages", NULL, NULL), -1); - PhInsertEMenuItem(menu, cfgItem = PhCreateEMenuItem(0, PH_MEMORY_FILTER_MENU_HIGHLIGHT_CFG, L"Highlight CFG pages", NULL, NULL), -1); - PhInsertEMenuItem(menu, typeItem = PhCreateEMenuItem(0, PH_MEMORY_FILTER_MENU_HIGHLIGHT_EXECUTE, L"Highlight executable pages", NULL, NULL), -1); - PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), -1); - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, PH_MEMORY_FILTER_MENU_READ_ADDRESS, L"Read/Write &address...", NULL, NULL), -1); - PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), -1); - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, PH_MEMORY_FILTER_MENU_STRINGS, L"Strings...", NULL, NULL), -1); + menu = PhCreateEMenu(); + PhInsertEMenuItem(menu, freeItem = PhCreateEMenuItem(0, PH_MEMORY_FILTER_MENU_HIDE_FREE, L"Hide free pages", NULL, NULL), ULONG_MAX); + PhInsertEMenuItem(menu, reservedItem = PhCreateEMenuItem(0, PH_MEMORY_FILTER_MENU_HIDE_RESERVED, L"Hide reserved pages", NULL, NULL), ULONG_MAX); + PhInsertEMenuItem(menu, guardItem = PhCreateEMenuItem(0, PH_MEMORY_FILTER_MENU_HIDE_GUARD, L"Hide guard pages", NULL, NULL), ULONG_MAX); + PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX); + PhInsertEMenuItem(menu, privateItem = PhCreateEMenuItem(0, PH_MEMORY_FILTER_MENU_HIGHLIGHT_PRIVATE, L"Highlight private pages", NULL, NULL), ULONG_MAX); + PhInsertEMenuItem(menu, systemItem = PhCreateEMenuItem(0, PH_MEMORY_FILTER_MENU_HIGHLIGHT_SYSTEM, L"Highlight system pages", NULL, NULL), ULONG_MAX); + PhInsertEMenuItem(menu, cfgItem = PhCreateEMenuItem(0, PH_MEMORY_FILTER_MENU_HIGHLIGHT_CFG, L"Highlight CFG pages", NULL, NULL), ULONG_MAX); + PhInsertEMenuItem(menu, typeItem = PhCreateEMenuItem(0, PH_MEMORY_FILTER_MENU_HIGHLIGHT_EXECUTE, L"Highlight executable pages", NULL, NULL), ULONG_MAX); + PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, PH_MEMORY_FILTER_MENU_READ_ADDRESS, L"Read/Write &address...", NULL, NULL), ULONG_MAX); + PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, PH_MEMORY_FILTER_MENU_STRINGS, L"Strings...", NULL, NULL), ULONG_MAX); if (memoryContext->ListContext.HideFreeRegions) freeItem->Flags |= PH_EMENU_CHECKED; if (memoryContext->ListContext.HideReservedRegions) reservedItem->Flags |= PH_EMENU_CHECKED; + if (memoryContext->ListContext.HideGuardRegions) + guardItem->Flags |= PH_EMENU_CHECKED; if (memoryContext->ListContext.HighlightPrivatePages) privateItem->Flags |= PH_EMENU_CHECKED; if (memoryContext->ListContext.HighlightSystemPages) @@ -675,6 +683,7 @@ INT_PTR CALLBACK PhpProcessMemoryDlgProc( { if (selectedItem->Id == PH_MEMORY_FILTER_MENU_HIDE_FREE || selectedItem->Id == PH_MEMORY_FILTER_MENU_HIDE_RESERVED || + selectedItem->Id == PH_MEMORY_FILTER_MENU_HIDE_GUARD || selectedItem->Id == PH_MEMORY_FILTER_MENU_HIGHLIGHT_PRIVATE || selectedItem->Id == PH_MEMORY_FILTER_MENU_HIGHLIGHT_SYSTEM || selectedItem->Id == PH_MEMORY_FILTER_MENU_HIGHLIGHT_CFG || From d86972c2546af4669838b9eb38ee5f9715ff4db7 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 21 May 2018 07:57:59 +1000 Subject: [PATCH 0970/2058] Fix sysinfo window text clipping issues --- ProcessHacker/sysinfo.c | 88 ++++++++++++++++++++++++++++++----------- 1 file changed, 64 insertions(+), 24 deletions(-) diff --git a/ProcessHacker/sysinfo.c b/ProcessHacker/sysinfo.c index 0cd1d6d58f4a..de2c2bfc8a0d 100644 --- a/ProcessHacker/sysinfo.c +++ b/ProcessHacker/sysinfo.c @@ -475,9 +475,9 @@ VOID PhSipOnShowWindow( PhSipEnterSectionView(section); } - AlwaysOnTop = (BOOLEAN)PhGetIntegerSetting(L"SysInfoWindowAlwaysOnTop"); + AlwaysOnTop = !!PhGetIntegerSetting(L"SysInfoWindowAlwaysOnTop"); Button_SetCheck(GetDlgItem(PhSipWindow, IDC_ALWAYSONTOP), AlwaysOnTop ? BST_CHECKED : BST_UNCHECKED); - PhSipSetAlwaysOnTop(); + PhSetWindowAlwaysOnTop(PhSipWindow, AlwaysOnTop); PhSipOnSize(); PhSipOnUserMessage(SI_MSG_SYSINFO_UPDATE, 0, 0); @@ -546,7 +546,8 @@ VOID PhSipOnCommand( case IDC_ALWAYSONTOP: { AlwaysOnTop = Button_GetCheck(GetDlgItem(PhSipWindow, IDC_ALWAYSONTOP)) == BST_CHECKED; - PhSipSetAlwaysOnTop(); + PhSetIntegerSetting(L"SysInfoWindowAlwaysOnTop", AlwaysOnTop); + PhSetWindowAlwaysOnTop(PhSipWindow, AlwaysOnTop); } break; case IDC_RESET: @@ -1406,28 +1407,76 @@ VOID PhSipDefaultDrawPanel( if (DrawPanel->Title) { SelectObject(hdc, CurrentParameters.MediumFont); - DrawText(hdc, DrawPanel->Title->Buffer, (ULONG)DrawPanel->Title->Length / 2, &rect, flags | DT_SINGLELINE); + DrawText(hdc, DrawPanel->Title->Buffer, (ULONG)DrawPanel->Title->Length / sizeof(WCHAR), &rect, flags | DT_SINGLELINE); } if (DrawPanel->SubTitle) { RECT measureRect; + SIZE textSize; + LONG lineHeight; + LONG lineWidth; + LONG rectHeight; + LONG rectWidth; + LONG textHeight; + LONG textWidth; rect.top += CurrentParameters.MediumFontHeight + CurrentParameters.PanelPadding; - SelectObject(hdc, CurrentParameters.Font); - measureRect = rect; - DrawText(hdc, DrawPanel->SubTitle->Buffer, (ULONG)DrawPanel->SubTitle->Length / 2, &measureRect, (flags & ~DT_END_ELLIPSIS) | DT_CALCRECT); - if (measureRect.right <= rect.right || !DrawPanel->SubTitleOverflow) - { - // Text fits; draw normally. - DrawText(hdc, DrawPanel->SubTitle->Buffer, (ULONG)DrawPanel->SubTitle->Length / 2, &rect, flags); - } - else + SelectObject(hdc, CurrentParameters.Font); + GetTextExtentPoint32(hdc, DrawPanel->SubTitle->Buffer, (ULONG)DrawPanel->SubTitle->Length / sizeof(WCHAR), &textSize); + DrawText(hdc, DrawPanel->SubTitle->Buffer, (ULONG)DrawPanel->SubTitle->Length / sizeof(WCHAR), &measureRect, flags | DT_CALCRECT); + + lineHeight = textSize.cy; + lineWidth = textSize.cx; + rectHeight = rect.bottom - rect.top; + rectWidth = rect.right - rect.left; + textHeight = measureRect.bottom - measureRect.top; + textWidth = measureRect.right - measureRect.left; + //dprintf( + // "[rectHeight: %u, rectwidth: %u] [lineHeight: %u, lineWidth: %u] [textHeight: %u, textWidth: %u]\n", + // rectHeight, rectWidth, + // lineHeight, lineWidth, + // textHeight, textWidth + // ); + + if (rectHeight > lineHeight) { - // Text doesn't fit; draw the alternative text. - DrawText(hdc, DrawPanel->SubTitleOverflow->Buffer, (ULONG)DrawPanel->SubTitleOverflow->Length / 2, &rect, flags); + if (rectHeight > textHeight) + { + if (lineWidth < rectWidth || !DrawPanel->SubTitleOverflow) + { + // Text fits; draw normally. + DrawText(hdc, DrawPanel->SubTitle->Buffer, (ULONG)DrawPanel->SubTitle->Length / sizeof(WCHAR), &rect, flags); + } + else + { + // Text doesn't fit; draw the alternative text. + DrawText(hdc, DrawPanel->SubTitleOverflow->Buffer, (ULONG)DrawPanel->SubTitleOverflow->Length / sizeof(WCHAR), &rect, flags); + } + } + else + { + PH_STRINGREF titlePart; + PH_STRINGREF remainingPart; + + // dmex: Multiline text doesn't fit; split the string and draw the first line. + if (DrawPanel->SubTitleOverflow) + { + if (PhSplitStringRefAtChar(&DrawPanel->SubTitleOverflow->sr, '\n', &titlePart, &remainingPart)) + DrawText(hdc, titlePart.Buffer, (ULONG)titlePart.Length / sizeof(WCHAR), &rect, flags); + else + DrawText(hdc, DrawPanel->SubTitleOverflow->Buffer, (ULONG)DrawPanel->SubTitleOverflow->Length / sizeof(WCHAR), &rect, flags); + } + else + { + if (PhSplitStringRefAtChar(&DrawPanel->SubTitle->sr, '\n', &titlePart, &remainingPart)) + DrawText(hdc, titlePart.Buffer, (ULONG)titlePart.Length / sizeof(WCHAR), &rect, flags); + else + DrawText(hdc, DrawPanel->SubTitle->Buffer, (ULONG)DrawPanel->SubTitle->Length / sizeof(WCHAR), &rect, flags); + } + } } } } @@ -2039,15 +2088,6 @@ VOID PhSipUpdateThemeData( } } -VOID PhSipSetAlwaysOnTop( - VOID - ) -{ - SetFocus(PhSipWindow); // HACK - SetWindowPos doesn't work properly without this - SetWindowPos(PhSipWindow, AlwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST, 0, 0, 0, 0, - SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE); -} - VOID PhSipSaveWindowState( VOID ) From 2ccc68825537625eb9b9f49b82ac577e635b065a Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 21 May 2018 07:58:32 +1000 Subject: [PATCH 0971/2058] Remove legacy function --- ProcessHacker/include/sysinfop.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/ProcessHacker/include/sysinfop.h b/ProcessHacker/include/sysinfop.h index 875a38587a07..bf13d42a853a 100644 --- a/ProcessHacker/include/sysinfop.h +++ b/ProcessHacker/include/sysinfop.h @@ -209,10 +209,6 @@ VOID PhSipUpdateThemeData( VOID ); -VOID PhSipSetAlwaysOnTop( - VOID - ); - VOID PhSipSaveWindowState( VOID ); From b8b6af6ce5141e4aa795fc2b247fc85ff5b5c340 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 21 May 2018 08:59:42 +1000 Subject: [PATCH 0972/2058] DotNetTools: Add inspect menu to .NET assembly tab, Add right-click menu to .NET assembly tab column headers --- plugins/DotNetTools/DotNetTools.rc | 25 +++-------- plugins/DotNetTools/asmpage.c | 69 ++++++++++++++++++++++-------- plugins/DotNetTools/counters.c | 4 +- plugins/DotNetTools/resource.h | 12 +++--- 4 files changed, 63 insertions(+), 47 deletions(-) diff --git a/plugins/DotNetTools/DotNetTools.rc b/plugins/DotNetTools/DotNetTools.rc index ded0cbd42baa..b119d818c7a3 100644 --- a/plugins/DotNetTools/DotNetTools.rc +++ b/plugins/DotNetTools/DotNetTools.rc @@ -104,7 +104,7 @@ STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSM CAPTION ".NET assemblies" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN - CONTROL ".NET assemblies",IDC_LIST,"PhTreeNew",WS_CLIPSIBLINGS | WS_CLIPCHILDREN | 0x1a,7,7,246,246,WS_EX_CLIENTEDGE + CONTROL ".NET assemblies",IDC_LIST,"PhTreeNew",WS_CLIPSIBLINGS | WS_CLIPCHILDREN | 0x1a,2,3,256,255,WS_EX_CLIENTEDGE END @@ -126,10 +126,10 @@ BEGIN IDD_PROCDOTNETASM, DIALOG BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 253 - TOPMARGIN, 7 - BOTTOMMARGIN, 253 + LEFTMARGIN, 2 + RIGHTMARGIN, 258 + TOPMARGIN, 3 + BOTTOMMARGIN, 258 END END #endif // APSTUDIO_INVOKED @@ -150,21 +150,6 @@ BEGIN 0 END - -///////////////////////////////////////////////////////////////////////////// -// -// Menu -// - -IDR_ASSEMBLY_MENU MENU -BEGIN - POPUP "CLR" - BEGIN - MENUITEM "Open &file location", ID_CLR_OPENFILELOCATION - MENUITEM "&Copy\aCtrl+C", ID_CLR_COPY - END -END - #endif // English (Australia) resources ///////////////////////////////////////////////////////////////////////////// diff --git a/plugins/DotNetTools/asmpage.c b/plugins/DotNetTools/asmpage.c index b303f2694a98..dc8f62bec3ef 100644 --- a/plugins/DotNetTools/asmpage.c +++ b/plugins/DotNetTools/asmpage.c @@ -3,7 +3,7 @@ * .NET Assemblies property page * * Copyright (C) 2011-2015 wj32 - * Copyright (C) 2016 dmex + * Copyright (C) 2016-2018 dmex * * This file is part of Process Hacker. * @@ -221,8 +221,8 @@ PDNA_NODE AddNode( { PDNA_NODE node; - node = PhAllocate(sizeof(DNA_NODE)); - memset(node, 0, sizeof(DNA_NODE)); + node = PhAllocateZero(sizeof(DNA_NODE)); + PhInitializeTreeNewNode(&node->Node); memset(node->TextCache, 0, sizeof(PH_STRINGREF) * DNATNC_MAXIMUM); @@ -404,11 +404,16 @@ VOID DotNetAsmShowContextMenu( return; menu = PhCreateEMenu(); - PhLoadResourceEMenuItem(menu, PluginInstance->DllBase, MAKEINTRESOURCE(IDR_ASSEMBLY_MENU), 0); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_CLR_INSPECT, L"&Inspect", NULL, NULL), ULONG_MAX); + PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_CLR_OPENFILELOCATION, L"Open &file location", NULL, NULL), ULONG_MAX); + PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_CLR_COPY, L"&Copy", NULL, NULL), ULONG_MAX); PhInsertCopyCellEMenuItem(menu, ID_CLR_COPY, Context->TnHandle, ContextMenuEvent->Column); if (PhIsNullOrEmptyString(node->PathText) || !RtlDoesFileExists_U(node->PathText->Buffer)) { + PhSetFlagsEMenuItem(menu, ID_CLR_INSPECT, PH_EMENU_DISABLED, PH_EMENU_DISABLED); PhSetFlagsEMenuItem(menu, ID_CLR_OPENFILELOCATION, PH_EMENU_DISABLED, PH_EMENU_DISABLED); } @@ -431,6 +436,20 @@ VOID DotNetAsmShowContextMenu( { switch (selectedItem->Id) { + case ID_CLR_INSPECT: + { + if (!PhIsNullOrEmptyString(node->PathText) && RtlDoesFileExists_U(node->PathText->Buffer)) + { + PhShellExecuteUserString( + Context->WindowHandle, + L"ProgramInspectExecutables", + node->PathText->Buffer, + FALSE, + L"Make sure the PE Viewer executable file is present." + ); + } + } + break; case ID_CLR_OPENFILELOCATION: { if (!PhIsNullOrEmptyString(node->PathText) && RtlDoesFileExists_U(node->PathText->Buffer)) @@ -566,6 +585,22 @@ BOOLEAN NTAPI DotNetAsmTreeNewCallback( } } return TRUE; + case TreeNewHeaderRightClick: + { + PH_TN_COLUMN_MENU_DATA data; + + data.TreeNewHandle = hwnd; + data.MouseEvent = Parameter1; + data.DefaultSortColumn = 0; + data.DefaultSortOrder = AscendingSortOrder; + PhInitializeTreeNewColumnMenu(&data); + + data.Selection = PhShowEMenu(data.Menu, hwnd, PH_EMENU_SHOW_LEFTRIGHT, + PH_ALIGN_LEFT | PH_ALIGN_TOP, data.MouseEvent->ScreenLocation.x, data.MouseEvent->ScreenLocation.y); + PhHandleTreeNewColumnMenu(&data); + PhDeleteTreeNewColumnMenu(&data); + } + return TRUE; case TreeNewContextMenu: { PPH_TREENEW_CONTEXT_MENU contextMenuEvent = Parameter1; @@ -589,8 +624,7 @@ ULONG StartDotNetTrace( TRACEHANDLE sessionHandle; bufferSize = sizeof(EVENT_TRACE_PROPERTIES) + DotNetLoggerName.Length + sizeof(WCHAR); - properties = PhAllocate(bufferSize); - memset(properties, 0, sizeof(EVENT_TRACE_PROPERTIES)); + properties = PhAllocateZero(bufferSize); properties->Wnode.BufferSize = bufferSize; properties->Wnode.ClientContext = 2; // System time clock resolution @@ -670,7 +704,7 @@ VOID NTAPI DotNetEventCallback( node->u.Clr.ClrInstanceID = data->ClrInstanceID; node->u.Clr.DisplayName = PhFormatString(L"CLR v%u.%u.%u.%u", data->VMMajorVersion, data->VMMinorVersion, data->VMBuildNumber, data->VMQfeNumber); node->StructureText = node->u.Clr.DisplayName->sr; - node->IdText = PhFormatString(L"%u", data->ClrInstanceID); + node->IdText = PhFormatUInt64(data->ClrInstanceID, FALSE); startupFlagsString = FlagsToString(data->StartupFlags, StartupFlagsMap, sizeof(StartupFlagsMap)); startupModeString = FlagsToString(data->StartupMode, StartupModeMap, sizeof(StartupModeMap)); @@ -707,7 +741,7 @@ VOID NTAPI DotNetEventCallback( PDNA_NODE node; appDomainNameLength = PhCountStringZ(data->AppDomainName) * sizeof(WCHAR); - clrInstanceID = *(PUSHORT)((PCHAR)data + FIELD_OFFSET(AppDomainLoadUnloadRundown_V1, AppDomainName) + appDomainNameLength + sizeof(WCHAR) + sizeof(ULONG)); + clrInstanceID = *(PUSHORT)PTR_ADD_OFFSET(data, FIELD_OFFSET(AppDomainLoadUnloadRundown_V1, AppDomainName) + appDomainNameLength + sizeof(WCHAR) + sizeof(ULONG)); // Find the CLR node to add the AppDomain node to. parentNode = FindClrNode(context, clrInstanceID); @@ -723,7 +757,7 @@ VOID NTAPI DotNetEventCallback( node->u.AppDomain.AppDomainID = data->AppDomainID; node->u.AppDomain.DisplayName = PhConcatStrings2(L"AppDomain: ", data->AppDomainName); node->StructureText = node->u.AppDomain.DisplayName->sr; - node->IdText = PhFormatString(L"%I64u", data->AppDomainID); + node->IdText = PhFormatUInt64(data->AppDomainID, FALSE); node->FlagsText = FlagsToString(data->AppDomainFlags, AppDomainFlagsMap, sizeof(AppDomainFlagsMap)); PhAddItemList(parentNode->Children, node); @@ -740,7 +774,7 @@ VOID NTAPI DotNetEventCallback( PH_STRINGREF remainingPart; fullyQualifiedAssemblyNameLength = PhCountStringZ(data->FullyQualifiedAssemblyName) * sizeof(WCHAR); - clrInstanceID = *(PUSHORT)((PCHAR)data + FIELD_OFFSET(AssemblyLoadUnloadRundown_V1, FullyQualifiedAssemblyName) + fullyQualifiedAssemblyNameLength + sizeof(WCHAR)); + clrInstanceID = *(PUSHORT)PTR_ADD_OFFSET(data, FIELD_OFFSET(AssemblyLoadUnloadRundown_V1, FullyQualifiedAssemblyName) + fullyQualifiedAssemblyNameLength + sizeof(WCHAR)); // Find the AppDomain node to add the Assembly node to. @@ -764,7 +798,7 @@ VOID NTAPI DotNetEventCallback( if (!PhSplitStringRefAtChar(&node->u.Assembly.FullyQualifiedAssemblyName->sr, ',', &node->StructureText, &remainingPart)) node->StructureText = node->u.Assembly.FullyQualifiedAssemblyName->sr; - node->IdText = PhFormatString(L"%I64u", data->AssemblyID); + node->IdText = PhFormatUInt64(data->AssemblyID, FALSE); node->FlagsText = FlagsToString(data->AssemblyFlags, AssemblyFlagsMap, sizeof(AssemblyFlagsMap)); PhAddItemList(parentNode->Children, node); @@ -783,9 +817,9 @@ VOID NTAPI DotNetEventCallback( moduleILPath = data->ModuleILPath; moduleILPathLength = PhCountStringZ(moduleILPath) * sizeof(WCHAR); - moduleNativePath = (PWSTR)((PCHAR)moduleILPath + moduleILPathLength + sizeof(WCHAR)); + moduleNativePath = (PWSTR)PTR_ADD_OFFSET(moduleILPath, moduleILPathLength + sizeof(WCHAR)); moduleNativePathLength = PhCountStringZ(moduleNativePath) * sizeof(WCHAR); - clrInstanceID = *(PUSHORT)((PCHAR)moduleNativePath + moduleNativePathLength + sizeof(WCHAR)); + clrInstanceID = *(PUSHORT)PTR_ADD_OFFSET(moduleNativePath, moduleNativePathLength + sizeof(WCHAR)); // Find the Assembly node to set the path on. @@ -832,7 +866,7 @@ VOID NTAPI DotNetEventCallback( moduleILPath = data->ModuleILPath; moduleILPathLength = PhCountStringZ(moduleILPath) * sizeof(WCHAR); - moduleNativePath = (PWSTR)((PCHAR)moduleILPath + moduleILPathLength + sizeof(WCHAR)); + moduleNativePath = (PWSTR)PTR_ADD_OFFSET(moduleILPath, moduleILPathLength + sizeof(WCHAR)); moduleNativePathLength = PhCountStringZ(moduleNativePath) * sizeof(WCHAR); if (context->ClrV2Node && (moduleILPathLength != 0 || moduleNativePathLength != 0)) @@ -1087,9 +1121,7 @@ VOID CreateDotNetTraceQueryThread( HANDLE threadHandle; PASMPAGE_QUERY_CONTEXT context; - context = PhAllocate(sizeof(ASMPAGE_QUERY_CONTEXT)); - memset(context, 0, sizeof(ASMPAGE_QUERY_CONTEXT)); - + context = PhAllocateZero(sizeof(ASMPAGE_QUERY_CONTEXT)); context->WindowHandle = WindowHandle; context->ClrVersions = ClrVersions; context->ProcessId = ProcessId; @@ -1169,8 +1201,7 @@ INT_PTR CALLBACK DotNetAsmPageDlgProc( PPH_STRING settings; HWND tnHandle; - context = PhAllocate(sizeof(ASMPAGE_CONTEXT)); - memset(context, 0, sizeof(ASMPAGE_CONTEXT)); + context = PhAllocateZero(sizeof(ASMPAGE_CONTEXT)); propPageContext->Context = context; context->WindowHandle = hwndDlg; context->ProcessItem = processItem; diff --git a/plugins/DotNetTools/counters.c b/plugins/DotNetTools/counters.c index c299f2ac18ec..17045bcb7338 100644 --- a/plugins/DotNetTools/counters.c +++ b/plugins/DotNetTools/counters.c @@ -217,7 +217,7 @@ PPH_LIST EnumerateAppDomainIpcBlock( goto CleanupExit; } - appDomainInfoBlock = (AppDomainInfo*)PhAllocate(appDomainInfoBlockLength); + appDomainInfoBlock = PhAllocate(appDomainInfoBlockLength); memset(appDomainInfoBlock, 0, appDomainInfoBlockLength); if (!NT_SUCCESS(NtReadVirtualMemory( @@ -378,7 +378,7 @@ PPH_LIST EnumerateAppDomainIpcBlockWow64( goto CleanupExit; } - appDomainInfoBlock = (AppDomainInfo_Wow64*)PhAllocate(appDomainInfoBlockLength); + appDomainInfoBlock = PhAllocate(appDomainInfoBlockLength); memset(appDomainInfoBlock, 0, appDomainInfoBlockLength); if (!NT_SUCCESS(NtReadVirtualMemory( diff --git a/plugins/DotNetTools/resource.h b/plugins/DotNetTools/resource.h index 62ce099e861b..418ddff76c51 100644 --- a/plugins/DotNetTools/resource.h +++ b/plugins/DotNetTools/resource.h @@ -3,24 +3,24 @@ // Used by DotNetTools.rc // #define IDD_PROCDOTNETPERF 101 -#define ID_COPY 101 #define IDD_PROCDOTNETASM 102 -#define IDR_ASSEMBLY_MENU 104 +#define ID_CLR_OPENFILELOCATION 103 +#define ID_CLR_COPY 104 +#define ID_CLR_INSPECT 105 +#define ID_COPY 106 #define IDC_APPDOMAINS 1001 #define IDC_CATEGORIES 1002 #define IDC_COUNTERS 1003 #define IDC_LIST 1005 #define IDC_DOTNET_PERF_SHOWBYTES 1006 -#define ID_CLR_OPENFILELOCATION 40001 -#define ID_CLR_COPY 40002 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 105 -#define _APS_NEXT_COMMAND_VALUE 40003 +#define _APS_NEXT_COMMAND_VALUE 40004 #define _APS_NEXT_CONTROL_VALUE 1007 -#define _APS_NEXT_SYMED_VALUE 102 +#define _APS_NEXT_SYMED_VALUE 107 #endif #endif From 1c7b2848bcc41d2cbbc6c64606ecef61a98b99c8 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 21 May 2018 09:00:11 +1000 Subject: [PATCH 0973/2058] ExtendedTools: Fix log path check --- plugins/ExtendedNotifications/filelog.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/ExtendedNotifications/filelog.c b/plugins/ExtendedNotifications/filelog.c index e1cc06587719..b6a8dda4826b 100644 --- a/plugins/ExtendedNotifications/filelog.c +++ b/plugins/ExtendedNotifications/filelog.c @@ -41,7 +41,7 @@ VOID FileLogInitialization( fileName = PhaGetStringSetting(SETTING_NAME_LOG_FILENAME); - if (fileName->Length != 0) + if (!PhIsNullOrEmptyString(fileName)) { status = PhCreateFileStream( &LogFileStream, From b7f671f368643955b865724a9eb46280b19c5b6b Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 23 May 2018 13:50:57 +1000 Subject: [PATCH 0974/2058] ExtendedTools: Fix missing disk tab icons --- plugins/ExtendedTools/procicon.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/ExtendedTools/procicon.c b/plugins/ExtendedTools/procicon.c index bfb202f570df..ee520007b270 100644 --- a/plugins/ExtendedTools/procicon.c +++ b/plugins/ExtendedTools/procicon.c @@ -61,7 +61,7 @@ PET_PROCESS_ICON EtProcIconReferenceSmallProcessIcon( smallProcessIcon = Block->SmallProcessIcon; - if (!smallProcessIcon && PhTestEvent(&Block->ProcessItem->Stage1Event)) + if (!smallProcessIcon && PhTestEvent(&Block->ProcessItem->Stage1Event) && Block->ProcessItem->SmallIcon) { smallProcessIcon = EtProcIconCreateProcessIcon(Block->ProcessItem->SmallIcon); From 12926d81b7c15635080eeb383a2d9f6bf3253bea Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 23 May 2018 13:53:57 +1000 Subject: [PATCH 0975/2058] ToolStatus: Fix weird issue with TB_GETIDEALSIZE not retuning valid data in release builds --- plugins/ToolStatus/statusbar.c | 2 +- plugins/ToolStatus/toolbar.c | 22 ++++++++++++---------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/plugins/ToolStatus/statusbar.c b/plugins/ToolStatus/statusbar.c index 7e18a6c56622..961c13242410 100644 --- a/plugins/ToolStatus/statusbar.c +++ b/plugins/ToolStatus/statusbar.c @@ -2,8 +2,8 @@ * Process Hacker ToolStatus - * statusbar main * - * Copyright (C) 2011-2016 dmex * Copyright (C) 2010-2013 wj32 + * Copyright (C) 2011-2016 dmex * * This file is part of Process Hacker. * diff --git a/plugins/ToolStatus/toolbar.c b/plugins/ToolStatus/toolbar.c index daba0ce84bbc..e34c86469804 100644 --- a/plugins/ToolStatus/toolbar.c +++ b/plugins/ToolStatus/toolbar.c @@ -358,19 +358,21 @@ VOID ToolbarLoadSettings( RBBIM_IDEALSIZE }; - index = (UINT)SendMessage(RebarHandle, RB_IDTOINDEX, REBAR_BAND_ID_TOOLBAR, 0); - - // Get settings for Rebar band. - if (SendMessage(RebarHandle, RB_GETBANDINFO, index, (LPARAM)&rebarBandInfo) != -1) + if ((index = (UINT)SendMessage(RebarHandle, RB_IDTOINDEX, REBAR_BAND_ID_TOOLBAR, 0)) != UINT_MAX) { - SIZE idealWidth; - - // Reset the cxIdeal for the Chevron - SendMessage(ToolBarHandle, TB_GETIDEALSIZE, FALSE, (LPARAM)&idealWidth); + // Get settings for Rebar band. + if (SendMessage(RebarHandle, RB_GETBANDINFO, index, (LPARAM)&rebarBandInfo)) + { + SIZE idealWidth = { 0, 0 }; - rebarBandInfo.cxIdeal = idealWidth.cx; + // Reset the cxIdeal for the Chevron + if (SendMessage(ToolBarHandle, TB_GETIDEALSIZE, FALSE, (LPARAM)&idealWidth)) + { + rebarBandInfo.cxIdeal = (UINT)idealWidth.cx; - SendMessage(RebarHandle, RB_SETBANDINFO, index, (LPARAM)&rebarBandInfo); + SendMessage(RebarHandle, RB_SETBANDINFO, index, (LPARAM)&rebarBandInfo); + } + } } } From 7b6366592cdb2b16f8ba0764e8f22a648969b942 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 23 May 2018 13:54:25 +1000 Subject: [PATCH 0976/2058] Add window icon to About window, Fix about window startup location --- ProcessHacker/about.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/ProcessHacker/about.c b/ProcessHacker/about.c index fff2e75d0f23..770874f8227c 100644 --- a/ProcessHacker/about.c +++ b/ProcessHacker/about.c @@ -27,6 +27,7 @@ #include #include +#include #include #include #include @@ -48,7 +49,10 @@ static INT_PTR CALLBACK PhpAboutDlgProc( { PPH_STRING appName; - PhCenterWindow(hwndDlg, GetParent(hwndDlg)); + SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER))); + SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER))); + + PhCenterWindow(hwndDlg, (IsWindowVisible(PhMainWndHandle) && !IsMinimized(PhMainWndHandle)) ? PhMainWndHandle : NULL); #if (PHAPP_VERSION_REVISION != 0) appName = PhFormatString( From 79806c6dcf3c75d873ba25bbe5b3ff0aaee52efa Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 23 May 2018 13:56:30 +1000 Subject: [PATCH 0977/2058] Fix inspect and open file location menus opening invalid locations --- ProcessHacker/mainwnd.c | 5 ++++- ProcessHacker/mwpgproc.c | 5 +++++ ProcessHacker/prpggen.c | 19 +++++++++++++++---- 3 files changed, 24 insertions(+), 5 deletions(-) diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index 58f6344f71c8..b9b9768e7043 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -1227,7 +1227,10 @@ VOID PhMwpOnCommand( { PPH_PROCESS_ITEM processItem = PhGetSelectedProcessItem(); - if (processItem && processItem->FileName) + if (processItem && + !PhIsNullOrEmptyString(processItem->FileName) && + RtlDoesFileExists_U(PhGetString(processItem->FileName) + )) { PhReferenceObject(processItem); PhShellExecuteUserString( diff --git a/ProcessHacker/mwpgproc.c b/ProcessHacker/mwpgproc.c index c437a25c22e4..caf4ec47909a 100644 --- a/ProcessHacker/mwpgproc.c +++ b/ProcessHacker/mwpgproc.c @@ -547,6 +547,11 @@ VOID PhMwpInitializeProcessMenu( PhEnableEMenuItem(Menu, ID_PROCESS_PROPERTIES, TRUE); PhEnableEMenuItem(Menu, ID_PROCESS_SEARCHONLINE, TRUE); } + + if (PhIsNullOrEmptyString(Processes[0]->FileName) || !RtlDoesFileExists_U(PhGetString(Processes[0]->FileName))) + { + PhEnableEMenuItem(Menu, ID_PROCESS_OPENFILELOCATION, FALSE); + } } else { diff --git a/ProcessHacker/prpggen.c b/ProcessHacker/prpggen.c index bc94484fde51..1351145ba36d 100644 --- a/ProcessHacker/prpggen.c +++ b/ProcessHacker/prpggen.c @@ -224,15 +224,26 @@ INT_PTR CALLBACK PhpProcessGeneralDlgProc( PhSetDialogItemText(hwndDlg, IDC_VERSION, PhpGetStringOrNa(processItem->VersionInfo.FileVersion)); PhSetDialogItemText(hwndDlg, IDC_FILENAME, PhpGetStringOrNa(processItem->FileName)); - if (!processItem->FileName) - EnableWindow(GetDlgItem(hwndDlg, IDC_OPENFILENAME), FALSE); - { PPH_STRING inspectExecutables; + if (PhIsNullOrEmptyString(processItem->FileName)) + { + EnableWindow(GetDlgItem(hwndDlg, IDC_OPENFILENAME), FALSE); + EnableWindow(GetDlgItem(hwndDlg, IDC_INSPECT), FALSE); + } + else + { + if (!RtlDoesFileExists_U(PhGetString(processItem->FileName))) + { + EnableWindow(GetDlgItem(hwndDlg, IDC_OPENFILENAME), FALSE); + EnableWindow(GetDlgItem(hwndDlg, IDC_INSPECT), FALSE); + } + } + inspectExecutables = PhaGetStringSetting(L"ProgramInspectExecutables"); - if (!processItem->FileName || inspectExecutables->Length == 0) + if (PhIsNullOrEmptyString(inspectExecutables)) { EnableWindow(GetDlgItem(hwndDlg, IDC_INSPECT), FALSE); } From 78db78b3b3a399d8bdecb1666d1e2e29fc24e44a Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 23 May 2018 13:57:55 +1000 Subject: [PATCH 0978/2058] Fix missing image filename path for linux processes --- ProcessHacker/procprv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ProcessHacker/procprv.c b/ProcessHacker/procprv.c index 6aa48b122704..805605b2340f 100644 --- a/ProcessHacker/procprv.c +++ b/ProcessHacker/procprv.c @@ -1174,7 +1174,7 @@ VOID PhpFillProcessItem( { PPH_STRING fileName; - if (ProcessItem->QueryHandle) + if (ProcessItem->QueryHandle && !ProcessItem->IsSubsystemProcess) { PhGetProcessImageFileNameWin32(ProcessItem->QueryHandle, &ProcessItem->FileName); } From 92e4631ac297960378898e4f8854e0e8fb56cc0b Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 24 May 2018 08:32:22 +1000 Subject: [PATCH 0979/2058] ExtendedTools: Improve GPU calculation, Update GPU nodes window, Add GPU details window (#270) --- plugins/ExtendedTools/ExtendedTools.rc | 53 +- plugins/ExtendedTools/ExtendedTools.vcxproj | 9 +- .../ExtendedTools.vcxproj.filters | 30 +- plugins/ExtendedTools/d3dkmt.h | 1514 ++++++++++++++++- plugins/ExtendedTools/disktab.c | 4 +- plugins/ExtendedTools/etwprprp.c | 4 +- plugins/ExtendedTools/exttools.h | 53 +- plugins/ExtendedTools/gpudetails.c | 395 +++++ plugins/ExtendedTools/gpumon.c | 1061 ++++++++---- plugins/ExtendedTools/gpumon.h | 14 +- plugins/ExtendedTools/gpunodes.c | 288 ++-- plugins/ExtendedTools/gpuprprp.c | 4 +- plugins/ExtendedTools/gpusys.c | 32 +- plugins/ExtendedTools/main.c | 47 +- plugins/ExtendedTools/resource.h | 17 +- 15 files changed, 2908 insertions(+), 617 deletions(-) create mode 100644 plugins/ExtendedTools/gpudetails.c diff --git a/plugins/ExtendedTools/ExtendedTools.rc b/plugins/ExtendedTools/ExtendedTools.rc index 012b5a72e03e..cc9a500b4113 100644 --- a/plugins/ExtendedTools/ExtendedTools.rc +++ b/plugins/ExtendedTools/ExtendedTools.rc @@ -182,29 +182,29 @@ FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN LTEXT "GPU",IDC_TITLE,0,0,72,21 RTEXT "GPU name",IDC_GPUNAME,83,4,232,16,SS_WORDELLIPSIS - LTEXT "Panel layout",IDC_PANEL_LAYOUT,0,130,315,55,NOT WS_VISIBLE - LTEXT "Graph layout",IDC_GRAPH_LAYOUT,0,22,315,102,NOT WS_VISIBLE + LTEXT "Panel layout",IDC_PANEL_LAYOUT,0,146,315,39,NOT WS_VISIBLE + LTEXT "Graph layout",IDC_GRAPH_LAYOUT,0,22,315,121,NOT WS_VISIBLE LTEXT "GPU:",IDC_GPU_L,73,0,17,8 LTEXT "Dedicated memory:",IDC_DEDICATED_L,73,5,63,8 LTEXT "Shared memory:",IDC_SHARED_L,74,11,54,8 END -IDD_SYSINFO_GPUPANEL DIALOGEX 0, 0, 246, 54 +IDD_SYSINFO_GPUPANEL DIALOGEX 0, 0, 297, 38 STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_SYSMENU FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN - GROUPBOX "Dedicated memory",IDC_STATIC,0,0,118,36 + GROUPBOX "Dedicated memory",IDC_STATIC,0,0,118,35 LTEXT "Current",IDC_STATIC,8,11,26,8 LTEXT "Limit",IDC_STATIC,8,22,15,8 - RTEXT "Static",IDC_ZDEDICATEDCURRENT_V,55,11,54,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_ZDEDICATEDLIMIT_V,55,22,54,8,SS_ENDELLIPSIS - GROUPBOX "Shared memory",IDC_STATIC,122,0,124,36 + RTEXT "Static",IDC_ZDEDICATEDCURRENT_V,56,11,54,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_ZDEDICATEDLIMIT_V,56,22,54,8,SS_ENDELLIPSIS + GROUPBOX "Shared memory",IDC_STATIC,122,0,119,35 LTEXT "Current",IDC_STATIC,130,11,26,8 LTEXT "Limit",IDC_STATIC,130,23,15,8 RTEXT "Static",IDC_ZSHAREDCURRENT_V,182,11,54,8,SS_ENDELLIPSIS RTEXT "Static",IDC_ZSHAREDLIMIT_V,182,23,54,8,SS_ENDELLIPSIS - PUSHBUTTON "Nodes",IDC_NODES,152,40,50,14 - LTEXT "Select nodes used for GPU usage calculations:",IDC_STATIC,0,43,148,8 + PUSHBUTTON "Nodes",IDC_NODES,244,4,50,14 + PUSHBUTTON "Details",IDC_DETAILS,244,21,50,14 END IDD_PROCGPU DIALOGEX 0, 0, 369, 237 @@ -254,15 +254,12 @@ BEGIN END IDD_GPUNODES DIALOGEX 0, 0, 317, 183 -STYLE DS_SETFONT | DS_FIXEDSYS | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME +STYLE DS_SETFONT | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME CAPTION "GPU Nodes" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN - LTEXT "Select the nodes that will be included in GPU usage calculations.",IDC_INSTRUCTION,7,7,204,8 - LTEXT "Graph layout",IDC_LAYOUT,7,21,303,137,NOT WS_VISIBLE - CONTROL "Example checkbox",IDC_EXAMPLE,"Button",BS_AUTOCHECKBOX | NOT WS_VISIBLE | WS_TABSTOP,7,166,75,10 - DEFPUSHBUTTON "OK",IDOK,260,162,50,14 - CONTROL "Select/Deselect",IDC_SELECTALL,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,190,165,65,10 + LTEXT "Graph layout",IDC_LAYOUT,3,3,311,161,NOT WS_VISIBLE + DEFPUSHBUTTON "OK",IDOK,265,166,50,14 END IDD_PROCGPU_PANEL DIALOGEX 0, 0, 248, 46 @@ -352,6 +349,15 @@ BEGIN RTEXT "Static",IDC_ZSECTIONRESERVED_V,111,117,54,8,SS_ENDELLIPSIS END +IDD_SYSINFO_GPUDETAILS DIALOGEX 0, 0, 309, 211 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME +CAPTION "GPU Adapter Details" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + DEFPUSHBUTTON "OK",IDOK,258,195,50,14 + CONTROL "",IDC_GPULIST,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,2,2,305,191 +END + ///////////////////////////////////////////////////////////////////////////// // @@ -427,6 +433,7 @@ BEGIN IDD_SYSINFO_GPUPANEL, DIALOG BEGIN + BOTTOMMARGIN, 36 END IDD_PROCGPU, DIALOG @@ -451,10 +458,10 @@ BEGIN IDD_GPUNODES, DIALOG BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 310 - TOPMARGIN, 7 - BOTTOMMARGIN, 176 + LEFTMARGIN, 3 + RIGHTMARGIN, 314 + TOPMARGIN, 3 + BOTTOMMARGIN, 180 END IDD_PROCGPU_PANEL, DIALOG @@ -480,6 +487,14 @@ BEGIN TOPMARGIN, 7 BOTTOMMARGIN, 148 END + + IDD_SYSINFO_GPUDETAILS, DIALOG + BEGIN + LEFTMARGIN, 2 + RIGHTMARGIN, 307 + TOPMARGIN, 2 + BOTTOMMARGIN, 209 + END END #endif // APSTUDIO_INVOKED diff --git a/plugins/ExtendedTools/ExtendedTools.vcxproj b/plugins/ExtendedTools/ExtendedTools.vcxproj index 4dee2ca5e0ec..34eb747e9ab8 100644 --- a/plugins/ExtendedTools/ExtendedTools.vcxproj +++ b/plugins/ExtendedTools/ExtendedTools.vcxproj @@ -53,22 +53,22 @@ - cfgmgr32.lib;%(AdditionalDependencies) + cfgmgr32.lib;uxtheme.lib;%(AdditionalDependencies) - cfgmgr32.lib;%(AdditionalDependencies) + cfgmgr32.lib;uxtheme.lib;%(AdditionalDependencies) - cfgmgr32.lib;%(AdditionalDependencies) + cfgmgr32.lib;uxtheme.lib;%(AdditionalDependencies) - cfgmgr32.lib;%(AdditionalDependencies) + cfgmgr32.lib;uxtheme.lib;%(AdditionalDependencies) @@ -76,6 +76,7 @@ + diff --git a/plugins/ExtendedTools/ExtendedTools.vcxproj.filters b/plugins/ExtendedTools/ExtendedTools.vcxproj.filters index 7938f409aef9..a4f3a75bb578 100644 --- a/plugins/ExtendedTools/ExtendedTools.vcxproj.filters +++ b/plugins/ExtendedTools/ExtendedTools.vcxproj.filters @@ -13,6 +13,9 @@ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav + + {d3096a42-7c1f-4edf-a5d2-d086f5e5b174} + @@ -60,29 +63,32 @@ Source Files - + Source Files - + Source Files - + Source Files - - Source Files + + Source Files\Video - - Source Files + + Source Files\Video - Source Files + Source Files\Video - - Source Files + + Source Files\Video - - Source Files + + Source Files\Video + + + Source Files\Video diff --git a/plugins/ExtendedTools/d3dkmt.h b/plugins/ExtendedTools/d3dkmt.h index 880cd9fd5f33..9d5c984a51c8 100644 --- a/plugins/ExtendedTools/d3dkmt.h +++ b/plugins/ExtendedTools/d3dkmt.h @@ -1,22 +1,945 @@ #ifndef _D3DKMT_H #define _D3DKMT_H -// D3D definitions +// D3D kernel-mode definitions -typedef ULONG D3DKMT_HANDLE; +typedef UINT32 D3DKMT_HANDLE; +typedef enum _KMTQUERYADAPTERINFOTYPE +{ + KMTQAITYPE_UMDRIVERPRIVATE = 0, + KMTQAITYPE_UMDRIVERNAME = 1, // D3DKMT_UMDFILENAMEINFO + KMTQAITYPE_UMOPENGLINFO = 2, // D3DKMT_OPENGLINFO + KMTQAITYPE_GETSEGMENTSIZE = 3, // D3DKMT_SEGMENTSIZEINFO + KMTQAITYPE_ADAPTERGUID = 4, // GUID + KMTQAITYPE_FLIPQUEUEINFO = 5, // D3DKMT_FLIPQUEUEINFO + KMTQAITYPE_ADAPTERADDRESS = 6, // D3DKMT_ADAPTERADDRESS + KMTQAITYPE_SETWORKINGSETINFO = 7, // D3DKMT_WORKINGSETINFO + KMTQAITYPE_ADAPTERREGISTRYINFO = 8, // D3DKMT_ADAPTERREGISTRYINFO + KMTQAITYPE_CURRENTDISPLAYMODE = 9, // D3DKMT_CURRENTDISPLAYMODE + KMTQAITYPE_MODELIST = 10, // D3DKMT_DISPLAYMODE (array) + KMTQAITYPE_CHECKDRIVERUPDATESTATUS = 11, + KMTQAITYPE_VIRTUALADDRESSINFO = 12, // D3DKMT_VIRTUALADDRESSINFO + KMTQAITYPE_DRIVERVERSION = 13, // D3DKMT_DRIVERVERSION + KMTQAITYPE_ADAPTERTYPE = 15, // D3DKMT_ADAPTERTYPE // since WIN8 + KMTQAITYPE_OUTPUTDUPLCONTEXTSCOUNT = 16, // D3DKMT_OUTPUTDUPLCONTEXTSCOUNT + KMTQAITYPE_WDDM_1_2_CAPS = 17, // D3DKMT_WDDM_1_2_CAPS + KMTQAITYPE_UMD_DRIVER_VERSION = 18, // D3DKMT_UMD_DRIVER_VERSION + KMTQAITYPE_DIRECTFLIP_SUPPORT = 19, // D3DKMT_DIRECTFLIP_SUPPORT + KMTQAITYPE_MULTIPLANEOVERLAY_SUPPORT = 20, // D3DKMT_MULTIPLANEOVERLAY_SUPPORT // since WDDM1_3 + KMTQAITYPE_DLIST_DRIVER_NAME = 21, // D3DKMT_DLIST_DRIVER_NAME + KMTQAITYPE_WDDM_1_3_CAPS = 22, // D3DKMT_WDDM_1_3_CAPS + KMTQAITYPE_MULTIPLANEOVERLAY_HUD_SUPPORT = 23, // D3DKMT_MULTIPLANEOVERLAY_HUD_SUPPORT + KMTQAITYPE_WDDM_2_0_CAPS = 24, // D3DKMT_WDDM_2_0_CAPS // since WDDM2_0 + KMTQAITYPE_NODEMETADATA = 25, // D3DKMT_NODEMETADATA + KMTQAITYPE_CPDRIVERNAME = 26, // D3DKMT_CPDRIVERNAME + KMTQAITYPE_XBOX = 27, // D3DKMT_XBOX + KMTQAITYPE_INDEPENDENTFLIP_SUPPORT = 28, // D3DKMT_INDEPENDENTFLIP_SUPPORT + KMTQAITYPE_MIRACASTCOMPANIONDRIVERNAME = 29, // D3DKMT_MIRACASTCOMPANIONDRIVERNAME + KMTQAITYPE_PHYSICALADAPTERCOUNT = 30, // D3DKMT_PHYSICAL_ADAPTER_COUNT + KMTQAITYPE_PHYSICALADAPTERDEVICEIDS = 31, // D3DKMT_QUERY_DEVICE_IDS + KMTQAITYPE_DRIVERCAPS_EXT = 32, // D3DKMT_DRIVERCAPS_EXT + KMTQAITYPE_QUERY_MIRACAST_DRIVER_TYPE = 33, // D3DKMT_QUERY_MIRACAST_DRIVER_TYPE + KMTQAITYPE_QUERY_GPUMMU_CAPS = 34, // D3DKMT_QUERY_GPUMMU_CAPS + KMTQAITYPE_QUERY_MULTIPLANEOVERLAY_DECODE_SUPPORT = 35, // D3DKMT_MULTIPLANEOVERLAY_DECODE_SUPPORT + KMTQAITYPE_QUERY_HW_PROTECTION_TEARDOWN_COUNT = 36, // UINT32 + KMTQAITYPE_QUERY_ISBADDRIVERFORHWPROTECTIONDISABLED = 37, // D3DKMT_ISBADDRIVERFORHWPROTECTIONDISABLED + KMTQAITYPE_MULTIPLANEOVERLAY_SECONDARY_SUPPORT = 38, // D3DKMT_MULTIPLANEOVERLAY_SECONDARY_SUPPORT + KMTQAITYPE_INDEPENDENTFLIP_SECONDARY_SUPPORT = 39, // D3DKMT_INDEPENDENTFLIP_SECONDARY_SUPPORT + KMTQAITYPE_PANELFITTER_SUPPORT = 40, // D3DKMT_PANELFITTER_SUPPORT // since WDDM2_1 + KMTQAITYPE_PHYSICALADAPTERPNPKEY = 41, // D3DKMT_QUERY_PHYSICAL_ADAPTER_PNP_KEY // since WDDM2_2 + KMTQAITYPE_GETSEGMENTGROUPSIZE = 42, // D3DKMT_SEGMENTGROUPSIZEINFO + KMTQAITYPE_MPO3DDI_SUPPORT = 43, // D3DKMT_MPO3DDI_SUPPORT + KMTQAITYPE_HWDRM_SUPPORT = 44, // D3DKMT_HWDRM_SUPPORT + KMTQAITYPE_MPOKERNELCAPS_SUPPORT = 45, // D3DKMT_MPOKERNELCAPS_SUPPORT + KMTQAITYPE_MULTIPLANEOVERLAY_STRETCH_SUPPORT = 46, // D3DKMT_MULTIPLANEOVERLAY_STRETCH_SUPPORT + KMTQAITYPE_GET_DEVICE_VIDPN_OWNERSHIP_INFO = 47, // D3DKMT_GET_DEVICE_VIDPN_OWNERSHIP_INFO + KMTQAITYPE_QUERYREGISTRY = 48, // D3DDDI_QUERYREGISTRY_INFO // since WDDM2_4 + KMTQAITYPE_KMD_DRIVER_VERSION = 49, // D3DKMT_KMD_DRIVER_VERSION + KMTQAITYPE_BLOCKLIST_KERNEL = 50, // D3DKMT_BLOCKLIST_INFO ?? + KMTQAITYPE_BLOCKLIST_RUNTIME = 51, // D3DKMT_BLOCKLIST_INFO ?? + KMTQAITYPE_ADAPTERGUID_RENDER = 52, // GUID + KMTQAITYPE_ADAPTERADDRESS_RENDER = 53, // D3DKMT_ADAPTERADDRESS + KMTQAITYPE_ADAPTERREGISTRYINFO_RENDER = 54, // D3DKMT_ADAPTERREGISTRYINFO + KMTQAITYPE_CHECKDRIVERUPDATESTATUS_RENDER = 55, + KMTQAITYPE_DRIVERVERSION_RENDER = 56, // D3DKMT_DRIVERVERSION + KMTQAITYPE_ADAPTERTYPE_RENDER = 57, // D3DKMT_ADAPTERTYPE + KMTQAITYPE_WDDM_1_2_CAPS_RENDER = 58, // D3DKMT_WDDM_1_2_CAPS + KMTQAITYPE_WDDM_1_3_CAPS_RENDER = 59, // D3DKMT_WDDM_1_3_CAPS + KMTQAITYPE_QUERY_ADAPTER_UNIQUE_GUID = 60, // D3DKMT_QUERY_ADAPTER_UNIQUE_GUID + KMTQAITYPE_NODEPERFDATA = 61, // D3DKMT_NODE_PERFDATA + KMTQAITYPE_ADAPTERPERFDATA = 62, // D3DKMT_ADAPTER_PERFDATA + KMTQAITYPE_ADAPTERPERFDATA_CAPS = 63, // D3DKMT_ADAPTER_PERFDATACAPS + KMTQUITYPE_GPUVERSION = 64, // D3DKMT_GPUVERSION +} KMTQUERYADAPTERINFOTYPE; + +typedef enum _KMTUMDVERSION +{ + KMTUMDVERSION_DX9, + KMTUMDVERSION_DX10, + KMTUMDVERSION_DX11, + KMTUMDVERSION_DX12, + NUM_KMTUMDVERSIONS +} KMTUMDVERSION; + +// The D3DKMT_UMDFILENAMEINFO structure contains the name of an OpenGL ICD that is based on the specified version of the DirectX runtime. +typedef struct _D3DKMT_UMDFILENAMEINFO +{ + _In_ KMTUMDVERSION Version; // A KMTUMDVERSION-typed value that indicates the version of the DirectX runtime to retrieve the name of an OpenGL ICD for. + _Out_ WCHAR UmdFileName[MAX_PATH]; // A string that contains the name of the OpenGL ICD. +} D3DKMT_UMDFILENAMEINFO; + +// The D3DKMT_OPENGLINFO structure describes OpenGL installable client driver (ICD) information. +typedef struct _D3DKMT_OPENGLINFO +{ + _Out_ WCHAR UmdOpenGlIcdFileName[MAX_PATH]; // An array of wide characters that contains the file name of the OpenGL ICD. + _Out_ ULONG Version; // The version of the OpenGL ICD. + _In_ ULONG Flags; // This member is currently unused. +} D3DKMT_OPENGLINFO; + +// The D3DKMT_SEGMENTSIZEINFO structure describes the size, in bytes, of memory and aperture segments. +typedef struct _D3DKMT_SEGMENTSIZEINFO +{ + _Out_ ULONGLONG DedicatedVideoMemorySize; // The size, in bytes, of memory that is dedicated from video memory. + _Out_ ULONGLONG DedicatedSystemMemorySize; // The size, in bytes, of memory that is dedicated from system memory. + _Out_ ULONGLONG SharedSystemMemorySize; // The size, in bytes, of memory from system memory that can be shared by many users. +} D3DKMT_SEGMENTSIZEINFO; + +// The D3DKMT_FLIPINFOFLAGS structure identifies flipping capabilities of the display miniport driver. +typedef struct _D3DKMT_FLIPINFOFLAGS +{ + UINT32 FlipInterval : 1; // A UINT value that specifies whether the display miniport driver natively supports the scheduling of a flip command to take effect after two, three or four vertical syncs occur. + UINT32 Reserved : 31; +} D3DKMT_FLIPINFOFLAGS; + +// The D3DKMT_FLIPQUEUEINFO structure describes information about the graphics adapter's queue of flip operations. +typedef struct _D3DKMT_FLIPQUEUEINFO +{ + _Out_ UINT32 MaxHardwareFlipQueueLength; // The maximum number of flip operations that can be queued for hardware-flip queuing. + _Out_ UINT32 MaxSoftwareFlipQueueLength; // The maximum number of flip operations that can be queued for software-flip queuing on hardware that supports memory mapped I/O (MMIO)-based flips. + _Out_ D3DKMT_FLIPINFOFLAGS FlipFlags; // indicates, in bit-field flags, flipping capabilities. +} D3DKMT_FLIPQUEUEINFO; + +// The D3DKMT_ADAPTERADDRESS structure describes the physical location of the graphics adapter. +typedef struct _D3DKMT_ADAPTERADDRESS +{ + _Out_ UINT32 BusNumber; // The number of the bus that the graphics adapter's physical device is located on. + _Out_ UINT32 DeviceNumber; // The index of the graphics adapter's physical device on the bus. + _Out_ UINT32 FunctionNumber; // The function number of the graphics adapter on the physical device. +} D3DKMT_ADAPTERADDRESS; + +typedef struct _D3DKMT_WORKINGSETFLAGS +{ + UINT32 UseDefault : 1; // A UINT value that specifies whether the display miniport driver uses the default working set. + UINT32 Reserved : 31; // This member is reserved and should be set to zero. +} D3DKMT_WORKINGSETFLAGS; + +// The D3DKMT_WORKINGSETINFO structure describes information about the graphics adapter's working set. +typedef struct _D3DKMT_WORKINGSETINFO +{ + _Out_ D3DKMT_WORKINGSETFLAGS Flags; // A D3DKMT_WORKINGSETFLAGS structure that indicates, in bit-field flags, working-set properties. + _Out_ ULONG MinimumWorkingSetPercentile; // The minimum working-set percentile. + _Out_ ULONG MaximumWorkingSetPercentile; // The maximum working-set percentile. +} D3DKMT_WORKINGSETINFO; + +// The D3DKMT_ADAPTERREGISTRYINFO structure contains registry information about the graphics adapter. +typedef struct _D3DKMT_ADAPTERREGISTRYINFO +{ + _Out_ WCHAR AdapterString[MAX_PATH]; // A string that contains the name of the graphics adapter. + _Out_ WCHAR BiosString[MAX_PATH]; // A string that contains the name of the BIOS for the graphics adapter. + _Out_ WCHAR DacType[MAX_PATH]; // A string that contains the DAC type for the graphics adapter. + _Out_ WCHAR ChipType[MAX_PATH]; // A string that contains the chip type for the graphics adapter. +} D3DKMT_ADAPTERREGISTRYINFO; + +/* Formats +* Most of these names have the following convention: +* A = Alpha +* R = Red +* G = Green +* B = Blue +* X = Unused Bits +* P = Palette +* L = Luminance +* U = dU coordinate for BumpMap +* V = dV coordinate for BumpMap +* S = Stencil +* D = Depth (e.g. Z or W buffer) +* C = Computed from other channels (typically on certain read operations) +* +* Further, the order of the pieces are from MSB first; hence +* D3DFMT_A8L8 indicates that the high byte of this two byte +* format is alpha. +* +* D16 indicates: +* - An integer 16-bit value. +* - An app-lockable surface. +* +* All Depth/Stencil formats except D3DFMT_D16_LOCKABLE indicate: +* - no particular bit ordering per pixel, and +* - are not app lockable, and +* - the driver is allowed to consume more than the indicated +* number of bits per Depth channel (but not Stencil channel). +*/ +#ifndef MAKEFOURCC +#define MAKEFOURCC(ch0, ch1, ch2, ch3) \ + ((ULONG)(BYTE)(ch0) | ((ULONG)(BYTE)(ch1) << 8) | \ + ((ULONG)(BYTE)(ch2) << 16) | ((ULONG)(BYTE)(ch3) << 24 )) +#endif + +typedef enum _D3DDDIFORMAT +{ + D3DDDIFMT_UNKNOWN = 0, + D3DDDIFMT_R8G8B8 = 20, + D3DDDIFMT_A8R8G8B8 = 21, + D3DDDIFMT_X8R8G8B8 = 22, + D3DDDIFMT_R5G6B5 = 23, + D3DDDIFMT_X1R5G5B5 = 24, + D3DDDIFMT_A1R5G5B5 = 25, + D3DDDIFMT_A4R4G4B4 = 26, + D3DDDIFMT_R3G3B2 = 27, + D3DDDIFMT_A8 = 28, + D3DDDIFMT_A8R3G3B2 = 29, + D3DDDIFMT_X4R4G4B4 = 30, + D3DDDIFMT_A2B10G10R10 = 31, + D3DDDIFMT_A8B8G8R8 = 32, + D3DDDIFMT_X8B8G8R8 = 33, + D3DDDIFMT_G16R16 = 34, + D3DDDIFMT_A2R10G10B10 = 35, + D3DDDIFMT_A16B16G16R16 = 36, + D3DDDIFMT_A8P8 = 40, + D3DDDIFMT_P8 = 41, + D3DDDIFMT_L8 = 50, + D3DDDIFMT_A8L8 = 51, + D3DDDIFMT_A4L4 = 52, + D3DDDIFMT_V8U8 = 60, + D3DDDIFMT_L6V5U5 = 61, + D3DDDIFMT_X8L8V8U8 = 62, + D3DDDIFMT_Q8W8V8U8 = 63, + D3DDDIFMT_V16U16 = 64, + D3DDDIFMT_W11V11U10 = 65, + D3DDDIFMT_A2W10V10U10 = 67, + + D3DDDIFMT_UYVY = MAKEFOURCC('U', 'Y', 'V', 'Y'), + D3DDDIFMT_R8G8_B8G8 = MAKEFOURCC('R', 'G', 'B', 'G'), + D3DDDIFMT_YUY2 = MAKEFOURCC('Y', 'U', 'Y', '2'), + D3DDDIFMT_G8R8_G8B8 = MAKEFOURCC('G', 'R', 'G', 'B'), + D3DDDIFMT_DXT1 = MAKEFOURCC('D', 'X', 'T', '1'), + D3DDDIFMT_DXT2 = MAKEFOURCC('D', 'X', 'T', '2'), + D3DDDIFMT_DXT3 = MAKEFOURCC('D', 'X', 'T', '3'), + D3DDDIFMT_DXT4 = MAKEFOURCC('D', 'X', 'T', '4'), + D3DDDIFMT_DXT5 = MAKEFOURCC('D', 'X', 'T', '5'), + + D3DDDIFMT_D16_LOCKABLE = 70, + D3DDDIFMT_D32 = 71, + D3DDDIFMT_D15S1 = 73, + D3DDDIFMT_D24S8 = 75, + D3DDDIFMT_D24X8 = 77, + D3DDDIFMT_D24X4S4 = 79, + D3DDDIFMT_D16 = 80, + D3DDDIFMT_D32F_LOCKABLE = 82, + D3DDDIFMT_D24FS8 = 83, + D3DDDIFMT_D32_LOCKABLE = 84, + D3DDDIFMT_S8_LOCKABLE = 85, + D3DDDIFMT_S1D15 = 72, + D3DDDIFMT_S8D24 = 74, + D3DDDIFMT_X8D24 = 76, + D3DDDIFMT_X4S4D24 = 78, + D3DDDIFMT_L16 = 81, + D3DDDIFMT_G8R8 = 91, // WDDM1_3 + D3DDDIFMT_R8 = 92, // WDDM1_3 + D3DDDIFMT_VERTEXDATA = 100, + D3DDDIFMT_INDEX16 = 101, + D3DDDIFMT_INDEX32 = 102, + D3DDDIFMT_Q16W16V16U16 = 110, + + D3DDDIFMT_MULTI2_ARGB8 = MAKEFOURCC('M', 'E', 'T', '1'), + + // Floating point surface formats + + // s10e5 formats (16-bits per channel) + D3DDDIFMT_R16F = 111, + D3DDDIFMT_G16R16F = 112, + D3DDDIFMT_A16B16G16R16F = 113, + + // IEEE s23e8 formats (32-bits per channel) + D3DDDIFMT_R32F = 114, + D3DDDIFMT_G32R32F = 115, + D3DDDIFMT_A32B32G32R32F = 116, + + D3DDDIFMT_CxV8U8 = 117, + + // Monochrome 1 bit per pixel format + D3DDDIFMT_A1 = 118, + + // 2.8 biased fixed point + D3DDDIFMT_A2B10G10R10_XR_BIAS = 119, + + // Decode compressed buffer formats + D3DDDIFMT_DXVACOMPBUFFER_BASE = 150, + D3DDDIFMT_PICTUREPARAMSDATA = D3DDDIFMT_DXVACOMPBUFFER_BASE + 0, // 150 + D3DDDIFMT_MACROBLOCKDATA = D3DDDIFMT_DXVACOMPBUFFER_BASE + 1, // 151 + D3DDDIFMT_RESIDUALDIFFERENCEDATA = D3DDDIFMT_DXVACOMPBUFFER_BASE + 2, // 152 + D3DDDIFMT_DEBLOCKINGDATA = D3DDDIFMT_DXVACOMPBUFFER_BASE + 3, // 153 + D3DDDIFMT_INVERSEQUANTIZATIONDATA = D3DDDIFMT_DXVACOMPBUFFER_BASE + 4, // 154 + D3DDDIFMT_SLICECONTROLDATA = D3DDDIFMT_DXVACOMPBUFFER_BASE + 5, // 155 + D3DDDIFMT_BITSTREAMDATA = D3DDDIFMT_DXVACOMPBUFFER_BASE + 6, // 156 + D3DDDIFMT_MOTIONVECTORBUFFER = D3DDDIFMT_DXVACOMPBUFFER_BASE + 7, // 157 + D3DDDIFMT_FILMGRAINBUFFER = D3DDDIFMT_DXVACOMPBUFFER_BASE + 8, // 158 + D3DDDIFMT_DXVA_RESERVED9 = D3DDDIFMT_DXVACOMPBUFFER_BASE + 9, // 159 + D3DDDIFMT_DXVA_RESERVED10 = D3DDDIFMT_DXVACOMPBUFFER_BASE + 10, // 160 + D3DDDIFMT_DXVA_RESERVED11 = D3DDDIFMT_DXVACOMPBUFFER_BASE + 11, // 161 + D3DDDIFMT_DXVA_RESERVED12 = D3DDDIFMT_DXVACOMPBUFFER_BASE + 12, // 162 + D3DDDIFMT_DXVA_RESERVED13 = D3DDDIFMT_DXVACOMPBUFFER_BASE + 13, // 163 + D3DDDIFMT_DXVA_RESERVED14 = D3DDDIFMT_DXVACOMPBUFFER_BASE + 14, // 164 + D3DDDIFMT_DXVA_RESERVED15 = D3DDDIFMT_DXVACOMPBUFFER_BASE + 15, // 165 + D3DDDIFMT_DXVA_RESERVED16 = D3DDDIFMT_DXVACOMPBUFFER_BASE + 16, // 166 + D3DDDIFMT_DXVA_RESERVED17 = D3DDDIFMT_DXVACOMPBUFFER_BASE + 17, // 167 + D3DDDIFMT_DXVA_RESERVED18 = D3DDDIFMT_DXVACOMPBUFFER_BASE + 18, // 168 + D3DDDIFMT_DXVA_RESERVED19 = D3DDDIFMT_DXVACOMPBUFFER_BASE + 19, // 169 + D3DDDIFMT_DXVA_RESERVED20 = D3DDDIFMT_DXVACOMPBUFFER_BASE + 20, // 170 + D3DDDIFMT_DXVA_RESERVED21 = D3DDDIFMT_DXVACOMPBUFFER_BASE + 21, // 171 + D3DDDIFMT_DXVA_RESERVED22 = D3DDDIFMT_DXVACOMPBUFFER_BASE + 22, // 172 + D3DDDIFMT_DXVA_RESERVED23 = D3DDDIFMT_DXVACOMPBUFFER_BASE + 23, // 173 + D3DDDIFMT_DXVA_RESERVED24 = D3DDDIFMT_DXVACOMPBUFFER_BASE + 24, // 174 + D3DDDIFMT_DXVA_RESERVED25 = D3DDDIFMT_DXVACOMPBUFFER_BASE + 25, // 175 + D3DDDIFMT_DXVA_RESERVED26 = D3DDDIFMT_DXVACOMPBUFFER_BASE + 26, // 176 + D3DDDIFMT_DXVA_RESERVED27 = D3DDDIFMT_DXVACOMPBUFFER_BASE + 27, // 177 + D3DDDIFMT_DXVA_RESERVED28 = D3DDDIFMT_DXVACOMPBUFFER_BASE + 28, // 178 + D3DDDIFMT_DXVA_RESERVED29 = D3DDDIFMT_DXVACOMPBUFFER_BASE + 29, // 179 + D3DDDIFMT_DXVA_RESERVED30 = D3DDDIFMT_DXVACOMPBUFFER_BASE + 30, // 180 + D3DDDIFMT_DXVA_RESERVED31 = D3DDDIFMT_DXVACOMPBUFFER_BASE + 31, // 181 + D3DDDIFMT_DXVACOMPBUFFER_MAX = D3DDDIFMT_DXVA_RESERVED31, + + D3DDDIFMT_BINARYBUFFER = 199, + + D3DDDIFMT_FORCE_UINT = 0x7fffffff +} D3DDDIFORMAT; + +typedef struct _D3DDDI_RATIONAL +{ + UINT32 Numerator; + UINT32 Denominator; +} D3DDDI_RATIONAL; + +typedef enum _D3DDDI_VIDEO_SIGNAL_SCANLINE_ORDERING +{ + D3DDDI_VSSLO_UNINITIALIZED = 0, + D3DDDI_VSSLO_PROGRESSIVE = 1, + D3DDDI_VSSLO_INTERLACED_UPPERFIELDFIRST = 2, + D3DDDI_VSSLO_INTERLACED_LOWERFIELDFIRST = 3, + D3DDDI_VSSLO_OTHER = 255 +} D3DDDI_VIDEO_SIGNAL_SCANLINE_ORDERING; + +typedef enum _D3DDDI_ROTATION +{ + D3DDDI_ROTATION_IDENTITY = 1, // No rotation. + D3DDDI_ROTATION_90 = 2, // Rotated 90 degrees. + D3DDDI_ROTATION_180 = 3, // Rotated 180 degrees. + D3DDDI_ROTATION_270 = 4 // Rotated 270 degrees. +} D3DDDI_ROTATION; + +typedef enum _D3DKMDT_MODE_PRUNING_REASON +{ + D3DKMDT_MPR_UNINITIALIZED = 0, // mode was pruned or is supported because of: + D3DKMDT_MPR_ALLCAPS = 1, // all of the monitor caps (only used to imply lack of support - for support, specific reason is always indicated) + D3DKMDT_MPR_DESCRIPTOR_MONITOR_SOURCE_MODE = 2, // monitor source mode in the monitor descriptor + D3DKMDT_MPR_DESCRIPTOR_MONITOR_FREQUENCY_RANGE = 3, // monitor frequency range in the monitor descriptor + D3DKMDT_MPR_DESCRIPTOR_OVERRIDE_MONITOR_SOURCE_MODE = 4, // monitor source mode in the monitor descriptor override + D3DKMDT_MPR_DESCRIPTOR_OVERRIDE_MONITOR_FREQUENCY_RANGE = 5, // monitor frequency range in the monitor descriptor override + D3DKMDT_MPR_DEFAULT_PROFILE_MONITOR_SOURCE_MODE = 6, // monitor source mode in the default monitor profile + D3DKMDT_MPR_DRIVER_RECOMMENDED_MONITOR_SOURCE_MODE = 7, // monitor source mode recommended by the driver + D3DKMDT_MPR_MONITOR_FREQUENCY_RANGE_OVERRIDE = 8, // monitor frequency range override + D3DKMDT_MPR_CLONE_PATH_PRUNED = 9, // Mode is pruned because other path(s) in clone cluster has(have) no mode supported by monitor + D3DKMDT_MPR_MAXVALID = 10 +} D3DKMDT_MODE_PRUNING_REASON; + +// This structure takes 8 bytes. +// The unnamed UINT of size 0 forces alignment of the structure to +// make it exactly occupy 8 bytes, see MSDN docs on C++ bitfields +// for more details +typedef struct _D3DKMDT_DISPLAYMODE_FLAGS +{ + UINT32 ValidatedAgainstMonitorCaps : 1; + UINT32 RoundedFakeMode : 1; + UINT32 : 0; + D3DKMDT_MODE_PRUNING_REASON ModePruningReason : 4; + UINT32 Stereo : 1; // since WIN8 + UINT32 AdvancedScanCapable : 1; + UINT32 PreferredTiming : 1; // since WDDM2_0 + UINT32 PhysicalModeSupported : 1; + UINT32 Reserved : 24; +} D3DKMDT_DISPLAYMODE_FLAGS; + +// The D3DKMT_DISPLAYMODE structure describes a display mode. +typedef struct _D3DKMT_DISPLAYMODE +{ + _Out_ UINT32 Width; // The screen width of the display mode, in pixels. + _Out_ UINT32 Height; // The screen height of the display mode, in pixels. + _Out_ D3DDDIFORMAT Format; // A D3DDDIFORMAT-typed value that indicates the pixel format of the display mode. + _Out_ UINT32 IntegerRefreshRate; // A UINT value that indicates the refresh rate of the display mode. + _Out_ D3DDDI_RATIONAL RefreshRate; // A D3DDDI_RATIONAL structure that indicates the refresh rate of the display mode. + _Out_ D3DDDI_VIDEO_SIGNAL_SCANLINE_ORDERING ScanLineOrdering; // A D3DDDI_VIDEO_SIGNAL_SCANLINE_ORDERING-typed value that indicates how scan lines are ordered in the display mode. + _Out_ D3DDDI_ROTATION DisplayOrientation; // A D3DDDI_ROTATION-typed value that identifies the orientation of the display mode. + _Out_ UINT32 DisplayFixedOutput; // The fixed output of the display mode. + _Out_ D3DKMDT_DISPLAYMODE_FLAGS Flags; // A D3DKMDT_DISPLAYMODE_FLAGS structure that indicates information about the display mode. +} D3DKMT_DISPLAYMODE; + +// The D3DKMT_CURRENTDISPLAYMODE structure describes the current display mode of the specified video source. +typedef struct _D3DKMT_CURRENTDISPLAYMODE +{ + _In_ UINT32 VidPnSourceId; // The zero-based identification number of the video present source in a path of a video present network (VidPN) topology that the display mode applies to. + _Out_ D3DKMT_DISPLAYMODE DisplayMode; // A D3DKMT_DISPLAYMODE structure that represents the current display mode. +} D3DKMT_CURRENTDISPLAYMODE; + +// private +typedef struct _D3DKMT_VIRTUALADDRESSFLAGS +{ + UINT32 VirtualAddressSupported : 1; + UINT32 Reserved : 31; +} D3DKMT_VIRTUALADDRESSFLAGS; + +// private +typedef struct _D3DKMT_VIRTUALADDRESSINFO +{ + D3DKMT_VIRTUALADDRESSFLAGS VirtualAddressFlags; +} D3DKMT_VIRTUALADDRESSINFO; + +// The D3DKMT_DRIVERVERSION enumeration type contains values that indicate the version of the display driver model that the display miniport driver supports. +typedef enum D3DKMT_DRIVERVERSION +{ + KMT_DRIVERVERSION_WDDM_1_0 = 1000, // The display miniport driver supports the Windows Vista display driver model (WDDM) without Windows 7 features. + KMT_DRIVERVERSION_WDDM_1_1_PRERELEASE = 1102, // The display miniport driver supports the Windows Vista display driver model with prereleased Windows 7 features. + KMT_DRIVERVERSION_WDDM_1_1 = 1105, // The display miniport driver supports the Windows Vista display driver model with released Windows 7 features. + KMT_DRIVERVERSION_WDDM_1_2 = 1200, // The display miniport driver supports the Windows Vista display driver model with released Windows 8 features. Supported starting with Windows 8. + KMT_DRIVERVERSION_WDDM_1_3 = 1300, // The display miniport driver supports the Windows display driver model with released Windows 8.1 features. Supported starting with Windows 8.1. + KMT_DRIVERVERSION_WDDM_2_0 = 2000, // The display miniport driver supports the Windows display driver model with released Windows 10 features. Supported starting with Windows 10. + KMT_DRIVERVERSION_WDDM_2_1 = 2100, + KMT_DRIVERVERSION_WDDM_2_2 = 2200, + KMT_DRIVERVERSION_WDDM_2_3 = 2300, + KMT_DRIVERVERSION_WDDM_2_4 = 2400, +} D3DKMT_DRIVERVERSION; + +// Specifies the type of display device that the graphics adapter supports. +typedef struct _D3DKMT_ADAPTERTYPE +{ + union + { + struct + { + UINT32 RenderSupported : 1; + UINT32 DisplaySupported : 1; + UINT32 SoftwareDevice : 1; + UINT32 PostDevice : 1; + UINT32 HybridDiscrete : 1; // since WDDM1_3 + UINT32 HybridIntegrated : 1; + UINT32 IndirectDisplayDevice : 1; + UINT32 Paravirtualized : 1; // since WDDM2_3 + UINT32 ACGSupported : 1; + UINT32 SupportSetTimingsFromVidPn : 1; + UINT32 Detachable : 1; + UINT32 Reserved : 21; + }; + UINT32 Value; + }; +} D3DKMT_ADAPTERTYPE; + +// Specifies the number of current Desktop Duplication API (DDA) clients that are attached to a given video present network (VidPN). +typedef struct _D3DKMT_OUTPUTDUPLCONTEXTSCOUNT +{ + UINT32 VidPnSourceId; // The ID of the video present network (VidPN). + UINT32 OutputDuplicationCount; // The number of current DDA clients that are attached to the VidPN specified by the VidPnSourceId member. +} D3DKMT_OUTPUTDUPLCONTEXTSCOUNT; + +typedef enum _D3DKMDT_GRAPHICS_PREEMPTION_GRANULARITY +{ + D3DKMDT_GRAPHICS_PREEMPTION_NONE = 0, + D3DKMDT_GRAPHICS_PREEMPTION_DMA_BUFFER_BOUNDARY = 100, + D3DKMDT_GRAPHICS_PREEMPTION_PRIMITIVE_BOUNDARY = 200, + D3DKMDT_GRAPHICS_PREEMPTION_TRIANGLE_BOUNDARY = 300, + D3DKMDT_GRAPHICS_PREEMPTION_PIXEL_BOUNDARY = 400, + D3DKMDT_GRAPHICS_PREEMPTION_SHADER_BOUNDARY = 500, +} D3DKMDT_GRAPHICS_PREEMPTION_GRANULARITY; + +typedef enum _D3DKMDT_COMPUTE_PREEMPTION_GRANULARITY +{ + D3DKMDT_COMPUTE_PREEMPTION_NONE = 0, + D3DKMDT_COMPUTE_PREEMPTION_DMA_BUFFER_BOUNDARY = 100, + D3DKMDT_COMPUTE_PREEMPTION_DISPATCH_BOUNDARY = 200, + D3DKMDT_COMPUTE_PREEMPTION_THREAD_GROUP_BOUNDARY = 300, + D3DKMDT_COMPUTE_PREEMPTION_THREAD_BOUNDARY = 400, + D3DKMDT_COMPUTE_PREEMPTION_SHADER_BOUNDARY = 500, +} D3DKMDT_COMPUTE_PREEMPTION_GRANULARITY; + +typedef struct _D3DKMDT_PREEMPTION_CAPS +{ + D3DKMDT_GRAPHICS_PREEMPTION_GRANULARITY GraphicsPreemptionGranularity; + D3DKMDT_COMPUTE_PREEMPTION_GRANULARITY ComputePreemptionGranularity; +} D3DKMDT_PREEMPTION_CAPS; + +typedef struct _D3DKMT_WDDM_1_2_CAPS +{ + D3DKMDT_PREEMPTION_CAPS PreemptionCaps; + union + { + struct + { + UINT32 SupportNonVGA : 1; + UINT32 SupportSmoothRotation : 1; + UINT32 SupportPerEngineTDR : 1; + UINT32 SupportKernelModeCommandBuffer : 1; + UINT32 SupportCCD : 1; + UINT32 SupportSoftwareDeviceBitmaps : 1; + UINT32 SupportGammaRamp : 1; + UINT32 SupportHWCursor : 1; + UINT32 SupportHWVSync : 1; + UINT32 SupportSurpriseRemovalInHibernation : 1; + UINT32 Reserved : 22; + }; + UINT32 Value; + }; +} D3DKMT_WDDM_1_2_CAPS; + +// Indicates the version number of the user-mode driver. +typedef struct _D3DKMT_UMD_DRIVER_VERSION +{ + LARGE_INTEGER DriverVersion; // The user-mode driver version. +} D3DKMT_UMD_DRIVER_VERSION; + +// Indicates whether the user-mode driver supports Direct Flip operations, in which video memory is seamlessly flipped between an application's managed primary allocations and the Desktop Window Manager (DWM) managed primary allocations. +typedef struct _D3DKMT_DIRECTFLIP_SUPPORT +{ + BOOL Supported; // If TRUE, the driver supports Direct Flip operations. Otherwise, the driver does not support Direct Flip operations. +} D3DKMT_DIRECTFLIP_SUPPORT; + +typedef struct _D3DKMT_MULTIPLANEOVERLAY_SUPPORT +{ + BOOL Supported; +} D3DKMT_MULTIPLANEOVERLAY_SUPPORT; + +typedef struct _D3DKMT_DLIST_DRIVER_NAME +{ + _Out_ WCHAR DListFileName[MAX_PATH]; // DList driver file name +} D3DKMT_DLIST_DRIVER_NAME; + +typedef struct _D3DKMT_WDDM_1_3_CAPS +{ + union + { + struct + { + UINT32 SupportMiracast : 1; + UINT32 IsHybridIntegratedGPU : 1; + UINT32 IsHybridDiscreteGPU : 1; + UINT32 SupportPowerManagementPStates : 1; + UINT32 SupportVirtualModes : 1; + UINT32 SupportCrossAdapterResource : 1; + UINT32 Reserved : 26; + }; + UINT32 Value; + }; +} D3DKMT_WDDM_1_3_CAPS; + +typedef struct _D3DKMT_MULTIPLANEOVERLAY_HUD_SUPPORT +{ + UINT32 VidPnSourceId; // Not yet used. + BOOL Update; + BOOL KernelSupported; + BOOL HudSupported; +} D3DKMT_MULTIPLANEOVERLAY_HUD_SUPPORT; + +typedef struct _D3DKMT_WDDM_2_0_CAPS +{ + union + { + struct + { + UINT32 Support64BitAtomics : 1; + UINT32 GpuMmuSupported : 1; + UINT32 IoMmuSupported : 1; + UINT32 FlipOverwriteSupported : 1; // since WDDM2_4 + UINT32 SupportContextlessPresent : 1; + UINT32 Reserved : 27; + }; + UINT32 Value; + }; +} D3DKMT_WDDM_2_0_CAPS; + +// Indicates the type of engine on a GPU node. +typedef enum _DXGK_ENGINE_TYPE +{ + DXGK_ENGINE_TYPE_OTHER = 0, // This value is used for proprietary or unique functionality that is not exposed by typical adapters, as well as for an engine that performs work that doesn't fall under another category. + DXGK_ENGINE_TYPE_3D = 1, // The adapter's 3-D processing engine. All adapters that are not a display-only device have one 3-D engine. + DXGK_ENGINE_TYPE_VIDEO_DECODE = 2, // The engine that handles video decoding, including decompression of video frames from an input stream into typical YUV surfaces. The workload packets for an H.264 video codec workload test must appear on either the decode engine or the 3-D engine. + DXGK_ENGINE_TYPE_VIDEO_ENCODE = 3, // The engine that handles video encoding, including compression of typical video frames into an encoded video format. + DXGK_ENGINE_TYPE_VIDEO_PROCESSING = 4, // The engine that is responsible for any video processing that is done after a video input stream is decoded. Such processing can include RGB surface conversion, filtering, stretching, color correction, deinterlacing, or other steps that are required before the final image is rendered to the display screen. The workload packets for workload tests must appear on either the video processing engine or the 3-D engine. + DXGK_ENGINE_TYPE_SCENE_ASSEMBLY = 5, // The engine that performs vertex processing of 3-D workloads as a preliminary pass prior to the remainder of the 3-D rendering. This engine also stores vertices in bins that tile-based rendering engines use. + DXGK_ENGINE_TYPE_COPY = 6, // The engine that is a copy engine used for moving data. This engine can perform subresource updates, blitting, paging, or other similar data handling. The workload packets for calls to CopySubresourceRegion or UpdateSubResource methods of Direct3D 10 and Direct3D 11 must appear on either the copy engine or the 3-D engine. + DXGK_ENGINE_TYPE_OVERLAY = 7, // The virtual engine that is used for synchronized flipping of overlays in Direct3D 9. + DXGK_ENGINE_TYPE_CRYPTO, + DXGK_ENGINE_TYPE_MAX +} DXGK_ENGINE_TYPE; + +#define DXGK_MAX_METADATA_NAME_LENGTH 32 + +#include +typedef struct _D3DKMT_NODEMETADATA +{ + union + { + _In_ UINT32 NodeOrdinalAndAdapterIndex; + struct + { + UINT32 NodeOrdinal : 16; + UINT32 AdapterIndex : 16; + }; + }; + _Out_ DXGK_ENGINE_TYPE EngineType; + _Out_ WCHAR FriendlyName[DXGK_MAX_METADATA_NAME_LENGTH]; + _Out_ UINT32 Reserved; + _Out_ BOOLEAN GpuMmuSupported; // Indicates whether the graphics engines of the node support the GpuMmu model. // since WDDM2_0 + _Out_ BOOLEAN IoMmuSupported; // Indicates whether the graphics engines of the node support the SVM model. +} D3DKMT_NODEMETADATA; +#include + +typedef struct _D3DKMT_CPDRIVERNAME +{ + WCHAR ContentProtectionFileName[MAX_PATH]; +} D3DKMT_CPDRIVERNAME; + +typedef struct _D3DKMT_XBOX +{ + BOOL IsXBOX; +} D3DKMT_XBOX; + +typedef struct _D3DKMT_INDEPENDENTFLIP_SUPPORT +{ + BOOL Supported; +} D3DKMT_INDEPENDENTFLIP_SUPPORT; + +typedef struct _D3DKMT_MIRACASTCOMPANIONDRIVERNAME +{ + WCHAR MiracastCompanionDriverName[MAX_PATH]; +} D3DKMT_MIRACASTCOMPANIONDRIVERNAME; + +typedef struct _D3DKMT_PHYSICAL_ADAPTER_COUNT +{ + UINT32 Count; +} D3DKMT_PHYSICAL_ADAPTER_COUNT; + +typedef struct _D3DKMT_DEVICE_IDS +{ + UINT32 VendorID; + UINT32 DeviceID; + UINT32 SubVendorID; + UINT32 SubSystemID; + UINT32 RevisionID; + UINT32 BusType; +} D3DKMT_DEVICE_IDS; + +typedef struct _D3DKMT_QUERY_DEVICE_IDS +{ + _In_ UINT32 PhysicalAdapterIndex; + _Out_ D3DKMT_DEVICE_IDS DeviceIds; +} D3DKMT_QUERY_DEVICE_IDS; + +typedef struct _D3DKMT_DRIVERCAPS_EXT +{ + union + { + struct + { + UINT32 VirtualModeSupport : 1; + UINT32 Reserved : 31; + }; + UINT32 Value; + }; +} D3DKMT_DRIVERCAPS_EXT; + +typedef enum _D3DKMT_MIRACAST_DRIVER_TYPE +{ + D3DKMT_MIRACAST_DRIVER_NOT_SUPPORTED = 0, + D3DKMT_MIRACAST_DRIVER_IHV = 1, + D3DKMT_MIRACAST_DRIVER_MS = 2, +} D3DKMT_MIRACAST_DRIVER_TYPE; + +typedef struct _D3DKMT_QUERY_MIRACAST_DRIVER_TYPE +{ + D3DKMT_MIRACAST_DRIVER_TYPE MiracastDriverType; +} D3DKMT_QUERY_MIRACAST_DRIVER_TYPE; + +typedef struct _D3DKMT_GPUMMU_CAPS +{ + union + { + struct + { + UINT32 ReadOnlyMemorySupported : 1; + UINT32 NoExecuteMemorySupported : 1; + UINT32 CacheCoherentMemorySupported : 1; + UINT32 Reserved : 29; + }; + UINT32 Value; + } Flags; + UINT32 VirtualAddressBitCount; +} D3DKMT_GPUMMU_CAPS; + +typedef struct _D3DKMT_QUERY_GPUMMU_CAPS +{ + _In_ UINT32 PhysicalAdapterIndex; + _Out_ D3DKMT_GPUMMU_CAPS Caps; +} D3DKMT_QUERY_GPUMMU_CAPS; + +typedef struct _D3DKMT_MULTIPLANEOVERLAY_DECODE_SUPPORT +{ + BOOL Supported; +} D3DKMT_MULTIPLANEOVERLAY_DECODE_SUPPORT; + +typedef struct _D3DKMT_ISBADDRIVERFORHWPROTECTIONDISABLED +{ + BOOL Disabled; +} D3DKMT_ISBADDRIVERFORHWPROTECTIONDISABLED; + +typedef struct _D3DKMT_MULTIPLANEOVERLAY_SECONDARY_SUPPORT +{ + BOOL Supported; +} D3DKMT_MULTIPLANEOVERLAY_SECONDARY_SUPPORT; + +typedef struct _D3DKMT_INDEPENDENTFLIP_SECONDARY_SUPPORT +{ + BOOL Supported; +} D3DKMT_INDEPENDENTFLIP_SECONDARY_SUPPORT; + +typedef struct _D3DKMT_PANELFITTER_SUPPORT +{ + BOOL Supported; +} D3DKMT_PANELFITTER_SUPPORT; + +typedef enum _D3DKMT_PNP_KEY_TYPE +{ + D3DKMT_PNP_KEY_HARDWARE = 1, + D3DKMT_PNP_KEY_SOFTWARE = 2 +} D3DKMT_PNP_KEY_TYPE; + +// A structure that holds information to query the physical adapter PNP key. +typedef struct _D3DKMT_QUERY_PHYSICAL_ADAPTER_PNP_KEY +{ + _In_ UINT32 PhysicalAdapterIndex; // The physical adapter index. + _In_ D3DKMT_PNP_KEY_TYPE PnPKeyType; // The type of the PNP key being queried. + _Field_size_opt_(*pCchDest) WCHAR *pDest; // A WCHAR value respresenting the pDest. + _Inout_ UINT32 *pCchDest; // A UINT value representing the pCchDest. +} D3DKMT_QUERY_PHYSICAL_ADAPTER_PNP_KEY; + +// A structure that holds information about the segment group size. +typedef struct _D3DKMT_SEGMENTGROUPSIZEINFO +{ + _In_ UINT32 PhysicalAdapterIndex; // An index to the physical adapter. + _Out_ D3DKMT_SEGMENTSIZEINFO LegacyInfo; // Legacy segment size info. + _Out_ ULONGLONG LocalMemory; // The size of local memory. + _Out_ ULONGLONG NonLocalMemory; // The size of non-local memory. + _Out_ ULONGLONG NonBudgetMemory; // The size of non-budget memory. +} D3DKMT_SEGMENTGROUPSIZEINFO; + +// A structure that holds the support status. +typedef struct _D3DKMT_MPO3DDI_SUPPORT +{ + BOOL Supported; // Indicates whether support exists. +} D3DKMT_MPO3DDI_SUPPORT; + +typedef struct _D3DKMT_HWDRM_SUPPORT +{ + BOOLEAN Supported; +} D3DKMT_HWDRM_SUPPORT; + +typedef struct _D3DKMT_MPOKERNELCAPS_SUPPORT +{ + BOOL Supported; +} D3DKMT_MPOKERNELCAPS_SUPPORT; + +typedef struct _D3DKMT_MULTIPLANEOVERLAY_STRETCH_SUPPORT +{ + UINT32 VidPnSourceId; + BOOL Update; + BOOL Supported; +} D3DKMT_MULTIPLANEOVERLAY_STRETCH_SUPPORT; + +typedef struct _D3DKMT_GET_DEVICE_VIDPN_OWNERSHIP_INFO +{ + _In_ D3DKMT_HANDLE hDevice; // Indentifies the device + _Out_ BOOLEAN bFailedDwmAcquireVidPn; // True if Dwm Acquire VidPn failed due to another Dwm device having ownership +} D3DKMT_GET_DEVICE_VIDPN_OWNERSHIP_INFO; + +// Contains information to query for registry flags. +typedef struct _D3DDDI_QUERYREGISTRY_FLAGS +{ + union + { + struct + { + UINT32 TranslatePath : 1; + UINT32 MutableValue : 1; + UINT32 Reserved : 30; + }; + UINT32 Value; + }; +} D3DDDI_QUERYREGISTRY_FLAGS; + +typedef enum _D3DDDI_QUERYREGISTRY_TYPE +{ + D3DDDI_QUERYREGISTRY_SERVICEKEY = 0, // HKLM\System\CurrentControlSet\Services\nvlddmkm + D3DDDI_QUERYREGISTRY_ADAPTERKEY = 1, // HKLM\System\CurrentControlSet\Control\Class\{4d36e968-e325-11ce-bfc1-08002be10318}\0000 + D3DDDI_QUERYREGISTRY_DRIVERSTOREPATH = 2, + D3DDDI_QUERYREGISTRY_MAX, +} D3DDDI_QUERYREGISTRY_TYPE; + +typedef enum _D3DDDI_QUERYREGISTRY_STATUS +{ + D3DDDI_QUERYREGISTRY_STATUS_SUCCESS = 0, + D3DDDI_QUERYREGISTRY_STATUS_BUFFER_OVERFLOW = 1, + D3DDDI_QUERYREGISTRY_STATUS_FAIL = 2, + D3DDDI_QUERYREGISTRY_STATUS_MAX, +} D3DDDI_QUERYREGISTRY_STATUS; + +// Contains information about the query registry. +// PrivateDriverSize must be sizeof(D3DDDI_QUERYREGISTRY_INFO) + (size of the the key value in bytes) +typedef struct _D3DDDI_QUERYREGISTRY_INFO +{ + _In_ D3DDDI_QUERYREGISTRY_TYPE QueryType; + _In_ D3DDDI_QUERYREGISTRY_FLAGS QueryFlags; + _In_ WCHAR ValueName[MAX_PATH]; // The name of the registry value. + _In_ ULONG ValueType; // REG_XX types (https://msdn.microsoft.com/en-us/library/windows/desktop/ms724884.aspx) + _In_ ULONG PhysicalAdapterIndex; // The physical adapter index in a LDA chain. + _Out_ ULONG OutputValueSize;// Number of bytes written to the output value or required in case of D3DDDI_QUERYREGISTRY_STATUS_BUFFER_OVERFLOW. + _Out_ D3DDDI_QUERYREGISTRY_STATUS Status; + union + { + _Out_ ULONG OutputDword; + _Out_ UINT64 OutputQword; + _Out_ WCHAR OutputString[1]; + _Out_ BYTE OutputBinary[1]; + }; +} D3DDDI_QUERYREGISTRY_INFO; + +// Contains the kernel mode driver version. +typedef struct _D3DKMT_KMD_DRIVER_VERSION +{ + LARGE_INTEGER DriverVersion; // The driver version. +} D3DKMT_KMD_DRIVER_VERSION; + +typedef struct _D3DKMT_BLOCKLIST_INFO +{ + UINT32 Size; // The size of the block list. + WCHAR BlockList[1]; // The block list. +} D3DKMT_BLOCKLIST_INFO; + +// Used to query for a unique guid. +typedef struct _D3DKMT_QUERY_ADAPTER_UNIQUE_GUID +{ + WCHAR AdapterUniqueGUID[40]; +} D3DKMT_QUERY_ADAPTER_UNIQUE_GUID; + +// Represents performance data collected per engine from an adapter on an interval basis. +typedef struct _D3DKMT_NODE_PERFDATA +{ + _In_ UINT32 NodeOrdinal; // Node ordinal of the requested engine. + _In_ UINT32 PhysicalAdapterIndex; // The physical adapter index in a LDA chain. + _Out_ ULONGLONG Frequency; // Clock frequency of the requested engine, represented in hertz. + _Out_ ULONGLONG MaxFrequency; // The max frequency the engine can normally reach in hertz while not overclocked. + _Out_ ULONGLONG MaxFrequencyOC; // The max frequency the engine can reach with it�s current overclock in hertz. + _Out_ ULONG Voltage; // Voltage of the engine in milli volts mV + _Out_ ULONG VoltageMax; // The max voltage of the engine in milli volts while not overclocked. + _Out_ ULONG VoltageMaxOC; // The max voltage of the engine while overclocked in milli volts. +} D3DKMT_NODE_PERFDATA; + +// Represents performance data collected per adapter on an interval basis. +typedef struct _D3DKMT_ADAPTER_PERFDATA +{ + _In_ UINT32 PhysicalAdapterIndex; // The physical adapter index in a LDA chain. + _Out_ ULONGLONG MemoryFrequency; // Clock frequency of the memory in hertz + _Out_ ULONGLONG MaxMemoryFrequency; // Max clock frequency of the memory while not overclocked, represented in hertz. + _Out_ ULONGLONG MaxMemoryFrequencyOC; // Clock frequency of the memory while overclocked in hertz. + _Out_ ULONGLONG MemoryBandwidth; // Amount of memory transferred in bytes + _Out_ ULONGLONG PCIEBandwidth; // Amount of memory transferred over PCI-E in bytes + _Out_ ULONG FanRPM; // Fan rpm + _Out_ ULONG Power; // Power draw of the adapter in tenths of a percentage + _Out_ ULONG Temperature; // Temperature in deci-Celsius 1 = 0.1C + _Out_ UCHAR PowerStateOverride; // Overrides dxgkrnls power view of linked adapters. +} D3DKMT_ADAPTER_PERFDATA; + +// Represents data capabilities that are static and queried once per GPU during initialization. +typedef struct _D3DKMT_ADAPTER_PERFDATACAPS +{ + _In_ UINT32 PhysicalAdapterIndex; // The physical adapter index in a LDA chain. + _Out_ ULONGLONG MaxMemoryBandwidth; // Max memory bandwidth in bytes for 1 second + _Out_ ULONGLONG MaxPCIEBandwidth; // Max pcie bandwidth in bytes for 1 second + _Out_ ULONG MaxFanRPM; // Max fan rpm + _Out_ ULONG TemperatureMax; // Max temperature before damage levels + _Out_ ULONG TemperatureWarning; // The temperature level where throttling begins. +} D3DKMT_ADAPTER_PERFDATACAPS; + +#define DXGK_MAX_GPUVERSION_NAME_LENGTH 32 + +// Used to collect the bios version and gpu architecture name once during GPU initialization. +typedef struct _D3DKMT_GPUVERSION +{ + _In_ UINT32 PhysicalAdapterIndex; // The physical adapter index in a LDA chain. + _Out_ WCHAR BiosVersion[DXGK_MAX_GPUVERSION_NAME_LENGTH]; // The current bios of the adapter. + _Out_ WCHAR GpuArchitecture[DXGK_MAX_GPUVERSION_NAME_LENGTH]; // The gpu architecture of the adapter. +} D3DKMT_GPUVERSION; + +// Describes the mapping of the given name of a device to a graphics adapter handle and monitor output. typedef struct _D3DKMT_OPENADAPTERFROMDEVICENAME { - _In_ PCWSTR pDeviceName; - _Out_ D3DKMT_HANDLE hAdapter; - _Out_ LUID AdapterLuid; + _In_ PWSTR DeviceName; // A Null-terminated string that contains the name of the device from which to open an adapter instance. + _Out_ D3DKMT_HANDLE AdapterHandle; // A handle to the graphics adapter for the device that DeviceName specifies. + _Out_ LUID AdapterLuid; // The locally unique identifier (LUID) of the graphics adapter for the device that DeviceName specifies. } D3DKMT_OPENADAPTERFROMDEVICENAME; +// Describes the mapping of the given locally unique identifier (LUID) of a device to a graphics adapter handle. +typedef struct _D3DKMT_OPENADAPTERFROMLUID +{ + _In_ LUID AdapterLuid; + _Out_ D3DKMT_HANDLE AdapterHandle; +} D3DKMT_OPENADAPTERFROMLUID; + +// Supplies configuration information about a graphics adapter. +typedef struct _D3DKMT_ADAPTERINFO +{ + D3DKMT_HANDLE AdapterHandle; // A handle to the adapter. + LUID AdapterLuid; // A LUID that serves as an identifier for the adapter. + ULONG NumOfSources; // The number of video present sources supported by the adapter. + BOOL bPresentMoveRegionsPreferred; // If TRUE, the adapter prefers move regions. +} D3DKMT_ADAPTERINFO; + +#define MAX_ENUM_ADAPTERS 16 + +// Supplies information for enumerating all graphics adapters on the system. +typedef struct _D3DKMT_ENUMADAPTERS +{ + _In_ ULONG NumAdapters; // The number of graphics adapters. + _Out_ D3DKMT_ADAPTERINFO Adapters[MAX_ENUM_ADAPTERS]; // An array of D3DKMT_ADAPTERINFO structures that supply configuration information for each adapter. +} D3DKMT_ENUMADAPTERS; + +// Supplies information for enumerating all graphics adapters on the system. +typedef struct _D3DKMT_ENUMADAPTERS2 +{ + _Inout_ ULONG NumAdapters; // On input, the count of the pAdapters array buffer. On output, the number of adapters enumerated. + _Out_ D3DKMT_ADAPTERINFO* Adapters; // Array of enumerated adapters containing NumAdapters elements. +} D3DKMT_ENUMADAPTERS2; + +// The D3DKMT_CLOSEADAPTER structure specifies the graphics adapter to close. typedef struct _D3DKMT_CLOSEADAPTER { - _In_ D3DKMT_HANDLE hAdapter; + _In_ D3DKMT_HANDLE AdapterHandle; // A handle to the graphics adapter to close. } D3DKMT_CLOSEADAPTER; +typedef struct _D3DKMT_QUERYADAPTERINFO +{ + _In_ D3DKMT_HANDLE AdapterHandle; + _In_ KMTQUERYADAPTERINFOTYPE Type; + _Out_ PVOID PrivateDriverData; + _Out_ UINT32 PrivateDriverDataSize; +} D3DKMT_QUERYADAPTERINFO; + typedef enum _D3DKMT_QUERYRESULT_PREEMPTION_ATTEMPT_RESULT { D3DKMT_PreemptionAttempt = 0, @@ -116,6 +1039,7 @@ typedef struct _D3DKMT_QUERYSTATISTICS_NODE_INFORMATION { D3DKMT_QUERYSTATISTICS_PROCESS_NODE_INFORMATION GlobalInformation; // global D3DKMT_QUERYSTATISTICS_PROCESS_NODE_INFORMATION SystemInformation; // system thread + //ULONG NodeId; // Win10 ULONG64 Reserved[8]; } D3DKMT_QUERYSTATISTICS_NODE_INFORMATION; @@ -459,7 +1383,7 @@ typedef struct _D3DKMT_QUERYSTATISTICS { _In_ D3DKMT_QUERYSTATISTICS_TYPE Type; _In_ LUID AdapterLuid; - _In_opt_ HANDLE hProcess; + _In_opt_ HANDLE ProcessHandle; _Out_ D3DKMT_QUERYSTATISTICS_RESULT QueryResult; union @@ -473,24 +1397,584 @@ typedef struct _D3DKMT_QUERYSTATISTICS }; } D3DKMT_QUERYSTATISTICS; +typedef enum _D3DKMT_MEMORY_SEGMENT_GROUP +{ + D3DKMT_MEMORY_SEGMENT_GROUP_LOCAL = 0, + D3DKMT_MEMORY_SEGMENT_GROUP_NON_LOCAL = 1 +} D3DKMT_MEMORY_SEGMENT_GROUP; + +typedef struct _D3DKMT_QUERYVIDEOMEMORYINFO +{ + _In_opt_ HANDLE ProcessHandle; // A handle to a process. If NULL, the current process is used. The process handle must be opened with PROCESS_QUERY_INFORMATION privileges. + _In_ D3DKMT_HANDLE AdapterHandle; // The adapter to query for this process + _In_ D3DKMT_MEMORY_SEGMENT_GROUP MemorySegmentGroup; // The memory segment group to query. + _Out_ UINT64 Budget; // Total memory the application may use + _Out_ UINT64 CurrentUsage; // Current memory usage of the device + _Out_ UINT64 CurrentReservation; // Current reservation of the device + _Out_ UINT64 AvailableForReservation; // Total that the device may reserve + _In_ UINT32 PhysicalAdapterIndex; // Zero based physical adapter index in the LDA configuration. +} D3DKMT_QUERYVIDEOMEMORYINFO; + +typedef enum _D3DKMT_ESCAPETYPE +{ + D3DKMT_ESCAPE_DRIVERPRIVATE = 0, + D3DKMT_ESCAPE_VIDMM = 1, // D3DKMT_VIDMM_ESCAPE + D3DKMT_ESCAPE_TDRDBGCTRL = 2, // D3DKMT_TDRDBGCTRLTYPE + D3DKMT_ESCAPE_VIDSCH = 3, // D3DKMT_VIDSCH_ESCAPE + D3DKMT_ESCAPE_DEVICE = 4, // D3DKMT_DEVICE_ESCAPE + D3DKMT_ESCAPE_DMM = 5, // D3DKMT_DMM_ESCAPE + D3DKMT_ESCAPE_DEBUG_SNAPSHOT = 6, // D3DKMT_DEBUG_SNAPSHOT_ESCAPE + // unused (7 was previously used to set driver update in-progress status, D3DKMT_ESCAPE_SETDRIVERUPDATESTATUS) + D3DKMT_ESCAPE_DRT_TEST = 8, + D3DKMT_ESCAPE_DIAGNOSTICS = 9, // since WIN8 + D3DKMT_ESCAPE_OUTPUTDUPL_SNAPSHOT = 10, + D3DKMT_ESCAPE_OUTPUTDUPL_DIAGNOSTICS = 11, + D3DKMT_ESCAPE_BDD_PNP = 12, + D3DKMT_ESCAPE_BDD_FALLBACK = 13, + D3DKMT_ESCAPE_ACTIVATE_SPECIFIC_DIAG = 14, // D3DKMT_ACTIVATE_SPECIFIC_DIAG_ESCAPE + D3DKMT_ESCAPE_MODES_PRUNED_OUT = 15, + D3DKMT_ESCAPE_WHQL_INFO = 16, // UINT32 ?? + D3DKMT_ESCAPE_BRIGHTNESS = 17, + D3DKMT_ESCAPE_EDID_CACHE = 18, // UINT32 ?? + D3DKMT_ESCAPE_GENERIC_ADAPTER_DIAG_INFO = 19, + D3DKMT_ESCAPE_MIRACAST_DISPLAY_REQUEST = 20, // since WDDM1_3 + D3DKMT_ESCAPE_HISTORY_BUFFER_STATUS = 21, + // 22 can be reused for future needs as it was never exposed for external purposes + D3DKMT_ESCAPE_MIRACAST_ADAPTER_DIAG_INFO = 23, + D3DKMT_ESCAPE_FORCE_BDDFALLBACK_HEADLESS = 24, // since WDDM2_0 + D3DKMT_ESCAPE_REQUEST_MACHINE_CRASH = 25, // D3DKMT_REQUEST_MACHINE_CRASH_ESCAPE + D3DKMT_ESCAPE_HMD_GET_EDID_BASE_BLOCK = 26, + D3DKMT_ESCAPE_SOFTGPU_ENABLE_DISABLE_HMD = 27, + D3DKMT_ESCAPE_PROCESS_VERIFIER_OPTION = 28, + D3DKMT_ESCAPE_ADAPTER_VERIFIER_OPTION = 29, + D3DKMT_ESCAPE_IDD_REQUEST = 30, // since WDDM2_1 + D3DKMT_ESCAPE_DOD_SET_DIRTYRECT_MODE = 31, + D3DKMT_ESCAPE_LOG_CODEPOINT_PACKET = 32, + D3DKMT_ESCAPE_LOG_USERMODE_DAIG_PACKET = 33, // since WDDM2_2 + D3DKMT_ESCAPE_GET_EXTERNAL_DIAGNOSTICS = 34, + // unused (35 previously was D3DKMT_ESCAPE_GET_PREFERRED_MODE) + D3DKMT_ESCAPE_GET_DISPLAY_CONFIGURATIONS = 36, // since WDDM2_3 + D3DKMT_ESCAPE_QUERY_IOMMU_STATUS = 37, // since WDDM2_4 + + D3DKMT_ESCAPE_WIN32K_START = 1024, + D3DKMT_ESCAPE_WIN32K_HIP_DEVICE_INFO = 1024, + D3DKMT_ESCAPE_WIN32K_QUERY_CD_ROTATION_BLOCK = 1025, + D3DKMT_ESCAPE_WIN32K_DPI_INFO = 1026, // Use hContext for the desired hdev // since WDDM1_3 + D3DKMT_ESCAPE_WIN32K_PRESENTER_VIEW_INFO = 1027, + D3DKMT_ESCAPE_WIN32K_SYSTEM_DPI = 1028, + D3DKMT_ESCAPE_WIN32K_BDD_FALLBACK = 1029, // since WDDM2_0 + D3DKMT_ESCAPE_WIN32K_DDA_TEST_CTL = 1030, + D3DKMT_ESCAPE_WIN32K_USER_DETECTED_BLACK_SCREEN = 1031, + D3DKMT_ESCAPE_WIN32K_HMD_ENUM = 1032, + D3DKMT_ESCAPE_WIN32K_HMD_CONTROL = 1033, + D3DKMT_ESCAPE_WIN32K_LPMDISPLAY_CONTROL = 1034, +} D3DKMT_ESCAPETYPE; + +typedef enum _D3DKMT_VIDMMESCAPETYPE +{ + D3DKMT_VIDMMESCAPETYPE_SETFAULT = 0, + D3DKMT_VIDMMESCAPETYPE_RUN_COHERENCY_TEST = 1, + D3DKMT_VIDMMESCAPETYPE_RUN_UNMAP_TO_DUMMY_PAGE_TEST = 2, + D3DKMT_VIDMMESCAPETYPE_APERTURE_CORRUPTION_CHECK = 3, + D3DKMT_VIDMMESCAPETYPE_SUSPEND_CPU_ACCESS_TEST = 4, + D3DKMT_VIDMMESCAPETYPE_EVICT = 5, + D3DKMT_VIDMMESCAPETYPE_EVICT_BY_NT_HANDLE = 6, + D3DKMT_VIDMMESCAPETYPE_GET_VAD_INFO = 7, + D3DKMT_VIDMMESCAPETYPE_SET_BUDGET = 8, + D3DKMT_VIDMMESCAPETYPE_SUSPEND_PROCESS = 9, + D3DKMT_VIDMMESCAPETYPE_RESUME_PROCESS = 10, + D3DKMT_VIDMMESCAPETYPE_GET_BUDGET = 11, + D3DKMT_VIDMMESCAPETYPE_SET_TRIM_INTERVALS = 12, + D3DKMT_VIDMMESCAPETYPE_EVICT_BY_CRITERIA = 13, + D3DKMT_VIDMMESCAPETYPE_WAKE = 14, + D3DKMT_VIDMMESCAPETYPE_DEFRAG = 15, +} D3DKMT_VIDMMESCAPETYPE; + +typedef struct _D3DKMT_VAD_DESC +{ + _In_ UINT32 VadIndex; // 0xFFFFFFFF to use the VAD address + _In_ UINT64 VadAddress; + _Out_ UINT32 NumMappedRanges; + _Out_ UINT32 VadType; // 0 - reserved, 1 - Mapped + _Out_ UINT64 StartAddress; + _Out_ UINT64 EndAddress; +} D3DKMT_VAD_DESC; + +typedef struct _D3DKMT_VA_RANGE_DESC +{ + _In_ UINT64 VadAddress; + _In_ UINT32 VaRangeIndex; + _In_ UINT32 PhysicalAdapterIndex; + _Out_ UINT64 StartAddress; + _Out_ UINT64 EndAddress; + _Out_ UINT64 DriverProtection; + _Out_ UINT32 OwnerType; // VIDMM_VAD_OWNER_TYPE + _Out_ UINT64 pOwner; + _Out_ UINT64 OwnerOffset; + _Out_ UINT32 Protection; // D3DDDIGPUVIRTUALADDRESS_PROTECTION_TYPE +} D3DKMT_VA_RANGE_DESC; + +typedef struct _D3DKMT_PAGE_TABLE_LEVEL_DESC +{ + UINT32 IndexBitCount; + UINT64 IndexMask; + UINT64 IndexShift; + UINT64 LowerLevelsMask; + UINT64 EntryCoverageInPages; +} D3DKMT_PAGE_TABLE_LEVEL_DESC; + +#define DXGK_MAX_PAGE_TABLE_LEVEL_COUNT 6 +#define DXGK_MIN_PAGE_TABLE_LEVEL_COUNT 2 + +typedef struct _DXGK_ESCAPE_GPUMMUCAPS +{ + BOOLEAN ReadOnlyMemorySupported; + BOOLEAN NoExecuteMemorySupported; + BOOLEAN ZeroInPteSupported; + BOOLEAN CacheCoherentMemorySupported; + BOOLEAN LargePageSupported; + BOOLEAN DualPteSupported; + BOOLEAN AllowNonAlignedLargePageAddress; + UINT32 VirtualAddressBitCount; + UINT32 PageTableLevelCount; + D3DKMT_PAGE_TABLE_LEVEL_DESC PageTableLevelDesk[DXGK_MAX_PAGE_TABLE_LEVEL_COUNT]; +} DXGK_ESCAPE_GPUMMUCAPS; + +typedef struct _D3DKMT_GET_GPUMMU_CAPS +{ + UINT32 PhysicalAdapterIndex; // In + DXGK_ESCAPE_GPUMMUCAPS GpuMmuCaps; // Out +} D3DKMT_GET_GPUMMU_CAPS; + +typedef enum _DXGK_PTE_PAGE_SIZE +{ + DXGK_PTE_PAGE_TABLE_PAGE_4KB = 0, + DXGK_PTE_PAGE_TABLE_PAGE_64KB = 1, +} DXGK_PTE_PAGE_SIZE; + +// Page Table Entry structure. Contains segment/physical address pointing to a page +typedef struct _DXGK_PTE +{ + union + { + struct + { + ULONGLONG Valid : 1; + ULONGLONG Zero : 1; + ULONGLONG CacheCoherent : 1; + ULONGLONG ReadOnly : 1; + ULONGLONG NoExecute : 1; + ULONGLONG Segment : 5; + ULONGLONG LargePage : 1; + ULONGLONG PhysicalAdapterIndex : 6; + ULONGLONG PageTablePageSize : 2; // DXGK_PTE_PAGE_SIZE + ULONGLONG SystemReserved0 : 1; + ULONGLONG Reserved : 44; + }; + ULONGLONG Flags; + }; + union + { + ULONGLONG PageAddress; // High 52 bits of 64 bit physical address. Low 12 bits are zero. + ULONGLONG PageTableAddress; // High 52 bits of 64 bit physical address. Low 12 bits are zero. + }; +} DXGK_PTE; + +#define D3DKMT_GET_PTE_MAX 64 + +typedef struct _D3DKMT_GET_PTE +{ + _In_ UINT32 PhysicalAdapterIndex; + _In_ UINT32 PageTableLevel; + _In_ UINT32 PageTableIndex[DXGK_MAX_PAGE_TABLE_LEVEL_COUNT]; + _In_ BOOLEAN b64KBPte; // Valid only when dual PTEs are supported. Out - PT is 64KB. + _In_ UINT32 NumPtes; // Number of PTEs to fill. Out - number of filled PTEs + _Out_ DXGK_PTE Pte[D3DKMT_GET_PTE_MAX]; + _Out_ UINT32 NumValidEntries; +} D3DKMT_GET_PTE; + +#define D3DKMT_MAX_SEGMENT_COUNT 32 + +typedef struct _D3DKMT_SEGMENT_CAPS +{ + UINT64 Size; + UINT32 PageSize; + ULONG SegmentId; + BOOLEAN bAperture; + BOOLEAN bReservedSysMem; + D3DKMT_MEMORY_SEGMENT_GROUP BudgetGroup; +} D3DKMT_SEGMENT_CAPS; + +typedef struct _D3DKMT_GET_SEGMENT_CAPS +{ + _In_ UINT32 PhysicalAdapterIndex; + _Out_ UINT32 NumSegments; + _Out_ D3DKMT_SEGMENT_CAPS SegmentCaps[D3DKMT_MAX_SEGMENT_COUNT]; +} D3DKMT_GET_SEGMENT_CAPS; + +typedef struct _D3DKMT_EVICTION_CRITERIA +{ + UINT64 MinimumSize; + UINT64 MaximumSize; + struct + { + union + { + struct + { + UINT32 Primary : 1; + UINT32 Reserved : 31; + } Flags; + UINT32 Value; + }; + }; +} D3DKMT_EVICTION_CRITERIA; + +typedef enum _D3DKMT_VAD_ESCAPE_COMMAND +{ + D3DKMT_VAD_ESCAPE_GETNUMVADS, + D3DKMT_VAD_ESCAPE_GETVAD, + D3DKMT_VAD_ESCAPE_GETVADRANGE, + D3DKMT_VAD_ESCAPE_GET_PTE, + D3DKMT_VAD_ESCAPE_GET_GPUMMU_CAPS, + D3DKMT_VAD_ESCAPE_GET_SEGMENT_CAPS, +} D3DKMT_VAD_ESCAPE_COMMAND; + +typedef enum _D3DKMT_DEFRAG_ESCAPE_OPERATION +{ + D3DKMT_DEFRAG_ESCAPE_GET_FRAGMENTATION_STATS = 0, + D3DKMT_DEFRAG_ESCAPE_DEFRAG_UPWARD = 1, + D3DKMT_DEFRAG_ESCAPE_DEFRAG_DOWNWARD = 2, + D3DKMT_DEFRAG_ESCAPE_DEFRAG_PASS = 3, + D3DKMT_DEFRAG_ESCAPE_VERIFY_TRANSFER = 4, +} D3DKMT_DEFRAG_ESCAPE_OPERATION; + +typedef struct _D3DKMT_VIDMM_ESCAPE +{ + D3DKMT_VIDMMESCAPETYPE Type; + union + { + struct + { + union + { + struct + { + ULONG ProbeAndLock : 1; + ULONG SplitPoint : 1; + ULONG NoDemotion : 1; + ULONG SwizzlingAperture : 1; + ULONG PagingPathLockSubRange : 1; + ULONG PagingPathLockMinRange : 1; + ULONG ComplexLock : 1; + ULONG FailVARotation : 1; + ULONG NoWriteCombined : 1; + ULONG NoPrePatching : 1; + ULONG AlwaysRepatch : 1; + ULONG ExpectPreparationFailure : 1; + ULONG FailUserModeVAMapping : 1; + ULONG NeverDiscardOfferedAllocation : 1; // since WIN8 + ULONG AlwaysDiscardOfferedAllocation : 1; + ULONG Reserved : 17; + }; + ULONG Value; + }; + } SetFault; + struct + { + D3DKMT_HANDLE ResourceHandle; + D3DKMT_HANDLE AllocationHandle; + HANDLE hProcess; // 0 to evict memory for the current process, otherwise it is a process handle from OpenProcess(PROCESS_ALL_ACCESS, FALSE, ProcessId). + } Evict; + struct + { + UINT64 NtHandle; // Used by D3DKMT_VIDMMESCAPETYPE_EVICT_BY_NT_HANDLE + } EvictByNtHandle; + struct + { + union + { + struct + { + UINT32 NumVads; + } GetNumVads; + D3DKMT_VAD_DESC GetVad; + D3DKMT_VA_RANGE_DESC GetVadRange; + D3DKMT_GET_GPUMMU_CAPS GetGpuMmuCaps; + D3DKMT_GET_PTE GetPte; + D3DKMT_GET_SEGMENT_CAPS GetSegmentCaps; + }; + _In_ D3DKMT_VAD_ESCAPE_COMMAND Command; + _Out_ NTSTATUS Status; + } GetVads; + struct + { + ULONGLONG LocalMemoryBudget; + ULONGLONG SystemMemoryBudget; + } SetBudget; + struct + { + HANDLE hProcess; + BOOL bAllowWakeOnSubmission; + } SuspendProcess; + struct + { + HANDLE hProcess; + } ResumeProcess; + struct + { + UINT64 NumBytesToTrim; + } GetBudget; + struct + { + ULONG MinTrimInterval; // In 100ns units + ULONG MaxTrimInterval; // In 100ns units + ULONG IdleTrimInterval; // In 100ns units + } SetTrimIntervals; + D3DKMT_EVICTION_CRITERIA EvictByCriteria; + struct + { + BOOL bFlush; + } Wake; + struct + { + D3DKMT_DEFRAG_ESCAPE_OPERATION Operation; + UINT32 SegmentId; + ULONGLONG TotalCommitted; + ULONGLONG TotalFree; + ULONGLONG LargestGapBefore; + ULONGLONG LargestGapAfter; + } Defrag; + }; +} D3DKMT_VIDMM_ESCAPE; + +typedef enum _D3DKMT_TDRDBGCTRLTYPE +{ + D3DKMT_TDRDBGCTRLTYPE_FORCETDR = 0, // Simulate a TDR + D3DKMT_TDRDBGCTRLTYPE_DISABLEBREAK = 1, // Disable DebugBreak on timeout + D3DKMT_TDRDBGCTRLTYPE_ENABLEBREAK = 2, // Enable DebugBreak on timeout + D3DKMT_TDRDBGCTRLTYPE_UNCONDITIONAL = 3, // Disables all safety conditions (e.g. check for consecutive recoveries) + D3DKMT_TDRDBGCTRLTYPE_VSYNCTDR = 4, // Simulate a Vsync TDR + D3DKMT_TDRDBGCTRLTYPE_GPUTDR = 5, // Simulate a GPU TDR + D3DKMT_TDRDBGCTRLTYPE_FORCEDODTDR = 6, // Simulate a Display Only Present TDR // since WIN8 + D3DKMT_TDRDBGCTRLTYPE_FORCEDODVSYNCTDR = 7, // Simulate a Display Only Vsync TDR + D3DKMT_TDRDBGCTRLTYPE_ENGINETDR = 8, // Simulate an engine TDR +} D3DKMT_TDRDBGCTRLTYPE; + +typedef enum _D3DKMT_VIDSCHESCAPETYPE +{ + D3DKMT_VIDSCHESCAPETYPE_PREEMPTIONCONTROL = 0, // Enable/Disable preemption + D3DKMT_VIDSCHESCAPETYPE_SUSPENDSCHEDULER = 1, // Suspend/Resume scheduler (obsolate) + D3DKMT_VIDSCHESCAPETYPE_TDRCONTROL = 2, // Tdr control + D3DKMT_VIDSCHESCAPETYPE_SUSPENDRESUME = 3, // Suspend/Resume scheduler + D3DKMT_VIDSCHESCAPETYPE_ENABLECONTEXTDELAY = 4, // Enable/Disable context delay // since WIN8 + D3DKMT_VIDSCHESCAPETYPE_CONFIGURE_TDR_LIMIT = 5, // Configure TdrLimitCount and TdrLimitTime + D3DKMT_VIDSCHESCAPETYPE_VGPU_RESET = 6, // Trigger VGPU reset + D3DKMT_VIDSCHESCAPETYPE_PFN_CONTROL = 7, // Periodic frame notification control +} D3DKMT_VIDSCHESCAPETYPE; + +typedef enum _D3DKMT_ESCAPE_PFN_CONTROL_COMMAND +{ + D3DKMT_ESCAPE_PFN_CONTROL_DEFAULT, + D3DKMT_ESCAPE_PFN_CONTROL_FORCE_CPU, + D3DKMT_ESCAPE_PFN_CONTROL_FORCE_GPU +} D3DKMT_ESCAPE_PFN_CONTROL_COMMAND; + +typedef struct _D3DKMT_VIDSCH_ESCAPE +{ + D3DKMT_VIDSCHESCAPETYPE Type; + union + { + BOOL PreemptionControl; // enable/disable preemption + BOOL EnableContextDelay; // enable/disable context delay // since WIN8 + struct + { + ULONG TdrControl; // control tdr + union + { + ULONG NodeOrdinal; // valid if TdrControl is set to D3DKMT_TDRDBGCTRLTYPE_ENGINETDR + }; + } TdrControl2; + BOOL SuspendScheduler; // suspend/resume scheduler (obsolate) // since Vista + ULONG TdrControl; // control tdr + ULONG SuspendTime; // time period to suspend. + struct + { + UINT Count; + UINT Time; // In seconds + } TdrLimit; + D3DKMT_ESCAPE_PFN_CONTROL_COMMAND PfnControl; // periodic frame notification control + }; +} D3DKMT_VIDSCH_ESCAPE; + +typedef enum _D3DKMT_DEVICEESCAPE_TYPE +{ + D3DKMT_DEVICEESCAPE_VIDPNFROMALLOCATION = 0, + D3DKMT_DEVICEESCAPE_RESTOREGAMMA = 1, +} D3DKMT_DEVICEESCAPE_TYPE; + +typedef struct _D3DKMT_DEVICE_ESCAPE +{ + D3DKMT_DEVICEESCAPE_TYPE Type; + union + { + struct + { + _In_ D3DKMT_HANDLE hPrimaryAllocation; // Primary allocation handle + _Out_ UINT32 VidPnSourceId; // VidPnSoureId of primary allocation + } VidPnFromAllocation; + }; +} D3DKMT_DEVICE_ESCAPE; + +typedef enum _D3DKMT_DMMESCAPETYPE +{ + D3DKMT_DMMESCAPETYPE_UNINITIALIZED = 0, + D3DKMT_DMMESCAPETYPE_GET_SUMMARY_INFO = 1, + D3DKMT_DMMESCAPETYPE_GET_VIDEO_PRESENT_SOURCES_INFO = 2, + D3DKMT_DMMESCAPETYPE_GET_VIDEO_PRESENT_TARGETS_INFO = 3, + D3DKMT_DMMESCAPETYPE_GET_ACTIVEVIDPN_INFO = 4, + D3DKMT_DMMESCAPETYPE_GET_MONITORS_INFO = 5, + D3DKMT_DMMESCAPETYPE_RECENTLY_COMMITTED_VIDPNS_INFO = 6, + D3DKMT_DMMESCAPETYPE_RECENT_MODECHANGE_REQUESTS_INFO = 7, + D3DKMT_DMMESCAPETYPE_RECENTLY_RECOMMENDED_VIDPNS_INFO = 8, + D3DKMT_DMMESCAPETYPE_RECENT_MONITOR_PRESENCE_EVENTS_INFO = 9, + D3DKMT_DMMESCAPETYPE_ACTIVEVIDPN_SOURCEMODESET_INFO = 10, + D3DKMT_DMMESCAPETYPE_ACTIVEVIDPN_COFUNCPATHMODALITY_INFO = 11, + D3DKMT_DMMESCAPETYPE_GET_LASTCLIENTCOMMITTEDVIDPN_INFO = 12, + D3DKMT_DMMESCAPETYPE_GET_VERSION_INFO = 13, + D3DKMT_DMMESCAPETYPE_VIDPN_MGR_DIAGNOSTICS = 14 +} D3DKMT_DMMESCAPETYPE; + +typedef struct _D3DKMT_DMM_ESCAPE +{ + _In_ D3DKMT_DMMESCAPETYPE Type; + _In_ SIZE_T ProvidedBufferSize; // actual size of Data[] array, in bytes. + _Out_ SIZE_T MinRequiredBufferSize; // minimum required size of Data[] array to contain requested data. + _Out_writes_bytes_(ProvidedBufferSize) UCHAR Data[1]; +} D3DKMT_DMM_ESCAPE; + +typedef struct _D3DKMT_DEBUG_SNAPSHOT_ESCAPE +{ + ULONG Length; // out: Actual length of the snapshot written in Buffer + BYTE Buffer[1]; // out: Buffer to place snapshot +} D3DKMT_DEBUG_SNAPSHOT_ESCAPE; + +typedef enum _D3DKMT_ACTIVATE_SPECIFIC_DIAG_TYPE +{ + D3DKMT_ACTIVATE_SPECIFIC_DIAG_TYPE_EXTRA_CCD_DATABASE_INFO = 0, + D3DKMT_ACTIVATE_SPECIFIC_DIAG_TYPE_MODES_PRUNED = 15, +}D3DKMT_ACTIVATE_SPECIFIC_DIAG_TYPE; + +typedef struct _D3DKMT_ACTIVATE_SPECIFIC_DIAG_ESCAPE +{ + D3DKMT_ACTIVATE_SPECIFIC_DIAG_TYPE Type; // The escape type that needs to be (de)activated + BOOL Activate; // FALSE means deactivate +} D3DKMT_ACTIVATE_SPECIFIC_DIAG_ESCAPE; + +typedef struct _D3DKMT_REQUEST_MACHINE_CRASH_ESCAPE +{ + ULONG_PTR Param1; + ULONG_PTR Param2; + ULONG_PTR Param3; +} D3DKMT_REQUEST_MACHINE_CRASH_ESCAPE; + +typedef struct _D3DDDI_ESCAPEFLAGS +{ + union + { + struct + { + UINT32 HardwareAccess : 1; + UINT32 DeviceStatusQuery : 1; // since WDDM1_3 + UINT32 ChangeFrameLatency : 1; + UINT32 NoAdapterSynchronization : 1; // since WDDM2_0 + UINT32 Reserved : 1; // Used internally by DisplayOnly present // since WDDM2_2 + UINT32 VirtualMachineData : 1; // Cannot be set from user mode + UINT32 Reserved2 :26; + }; + UINT32 Value; + }; +} D3DDDI_ESCAPEFLAGS; + +// The D3DKMT_ESCAPE structure describes information that is exchanged with the display miniport driver. +typedef struct _D3DKMT_ESCAPE +{ + _In_ D3DKMT_HANDLE AdapterHandle; + _In_opt_ D3DKMT_HANDLE DeviceHandle; + _In_ D3DKMT_ESCAPETYPE Type; + _In_ D3DDDI_ESCAPEFLAGS Flags; + _Inout_ PVOID PrivateDriverData; + _In_ UINT32 PrivateDriverDataSize; + _In_opt_ D3DKMT_HANDLE ContextHandle; +} D3DKMT_ESCAPE; + // Function pointers -// https://msdn.microsoft.com/en-us/library/ff547033.aspx _Check_return_ -NTSTATUS D3DKMTOpenAdapterFromDeviceName( - _Inout_ D3DKMT_OPENADAPTERFROMDEVICENAME *pData +NTSTATUS +NTAPI +D3DKMTOpenAdapterFromDeviceName( + _Inout_ CONST D3DKMT_OPENADAPTERFROMDEVICENAME *pData + ); + +_Check_return_ +NTSTATUS +NTAPI +D3DKMTOpenAdapterFromLuid( + _Inout_ CONST D3DKMT_OPENADAPTERFROMLUID *pAdapter ); -// https://msdn.microsoft.com/en-us/library/ff546787.aspx _Check_return_ -NTSTATUS D3DKMTCloseAdapter( - _In_ const D3DKMT_CLOSEADAPTER *pData +NTSTATUS +NTAPI +D3DKMTEnumAdapters( + _Inout_ CONST D3DKMT_ENUMADAPTERS *pData + ); + +_Check_return_ +NTSTATUS +NTAPI +D3DKMTEnumAdapters2( + _Inout_ CONST D3DKMT_ENUMADAPTERS2 *pData + ); + +_Check_return_ +NTSTATUS +NTAPI +D3DKMTCloseAdapter( + _In_ CONST D3DKMT_CLOSEADAPTER *pData + ); + +_Check_return_ +NTSTATUS +NTAPI +D3DKMTQueryAdapterInfo( + _Inout_ CONST D3DKMT_QUERYADAPTERINFO *pData ); // rev _Check_return_ -NTSTATUS D3DKMTQueryStatistics( - _Inout_ const D3DKMT_QUERYSTATISTICS *pData +NTSTATUS +NTAPI +D3DKMTQueryStatistics( + _Inout_ CONST D3DKMT_QUERYSTATISTICS *pData + ); + +_Check_return_ +NTSTATUS +NTAPI +D3DKMTQueryVideoMemoryInfo( + _Inout_ CONST D3DKMT_QUERYVIDEOMEMORYINFO *pData ); +_Check_return_ +NTSTATUS +NTAPI +D3DKMTEscape( + _Inout_ CONST D3DKMT_ESCAPE *pData + ); + +//EXTERN_C _Check_return_ NTSTATUS APIENTRY D3DKMTSetProcessSchedulingPriorityClass(_In_ HANDLE, _In_ D3DKMT_SCHEDULINGPRIORITYCLASS); +//EXTERN_C _Check_return_ NTSTATUS APIENTRY D3DKMTGetProcessSchedulingPriorityClass(_In_ HANDLE, _Out_ D3DKMT_SCHEDULINGPRIORITYCLASS*); + #endif diff --git a/plugins/ExtendedTools/disktab.c b/plugins/ExtendedTools/disktab.c index bbd6cb66284e..4ecd3890d376 100644 --- a/plugins/ExtendedTools/disktab.c +++ b/plugins/ExtendedTools/disktab.c @@ -499,10 +499,10 @@ BOOLEAN NTAPI EtpDiskTreeNewCallback( switch (getCellText->Id) { case ETDSTNC_NAME: - getCellText->Text = node->ProcessNameText->sr; + getCellText->Text = PhGetStringRef(node->ProcessNameText); break; case ETDSTNC_FILE: - getCellText->Text = diskItem->FileNameWin32->sr; + getCellText->Text = PhGetStringRef(diskItem->FileNameWin32); break; case ETDSTNC_READRATEAVERAGE: EtFormatRate(diskItem->ReadAverage, &node->ReadRateAverageText, &getCellText->Text); diff --git a/plugins/ExtendedTools/etwprprp.c b/plugins/ExtendedTools/etwprprp.c index 1af87271145b..14e3e9728318 100644 --- a/plugins/ExtendedTools/etwprprp.c +++ b/plugins/ExtendedTools/etwprprp.c @@ -267,7 +267,7 @@ VOID NTAPI EtwDiskNetworkUpdateHandler( if (context->WindowHandle) { - PostMessage(context->WindowHandle, UPDATE_MSG, 0, 0); + PostMessage(context->WindowHandle, ET_WM_UPDATE, 0, 0); } } @@ -585,7 +585,7 @@ INT_PTR CALLBACK EtwDiskNetworkPageDlgProc( } } break; - case UPDATE_MSG: + case ET_WM_UPDATE: { if (context->Enabled) { diff --git a/plugins/ExtendedTools/exttools.h b/plugins/ExtendedTools/exttools.h index d902723d9969..d3646318c0b2 100644 --- a/plugins/ExtendedTools/exttools.h +++ b/plugins/ExtendedTools/exttools.h @@ -9,6 +9,11 @@ #include "resource.h" +#define CINTERFACE +#define COBJMACROS +#include +#include "d3dkmt.h" + extern PPH_PLUGIN PluginInstance; extern LIST_ENTRY EtProcessBlockListHead; extern LIST_ENTRY EtNetworkBlockListHead; @@ -28,10 +33,12 @@ extern HWND NetworkTreeNewHandle; #define SETTING_NAME_UNLOADED_COLUMNS (PLUGIN_NAME L".UnloadedListColumns") #define SETTING_NAME_MODULE_SERVICES_WINDOW_POSITION (PLUGIN_NAME L".ModuleServiceWindowPosition") #define SETTING_NAME_MODULE_SERVICES_WINDOW_SIZE (PLUGIN_NAME L".ModuleServiceWindowSize") +#define SETTING_NAME_GPU_NODES_WINDOW_POSITION (PLUGIN_NAME L".GpuNodesWindowPosition") +#define SETTING_NAME_GPU_NODES_WINDOW_SIZE (PLUGIN_NAME L".GpuNodesWindowSize") -// Graph update message - -#define UPDATE_MSG (WM_APP + 1) +// Window messages +#define ET_WM_SHOWDIALOG (WM_APP + 1) +#define ET_WM_UPDATE (WM_APP + 2) // Process icon @@ -198,6 +205,9 @@ typedef struct _ET_PROCESS_BLOCK PH_UINT64_DELTA NetworkSendRawDelta; PH_UINT64_DELTA GpuRunningTimeDelta; + //PPH_UINT64_DELTA GpuTotalRunningTimeDelta; + //PPH_CIRCULAR_BUFFER_FLOAT GpuTotalNodesHistory; + FLOAT GpuNodeUsage; ULONG64 GpuDedicatedUsage; ULONG64 GpuSharedUsage; @@ -368,17 +378,15 @@ VOID EtSaveSettingsDiskTreeList( // gpumon extern BOOLEAN EtGpuEnabled; +extern PPH_LIST EtpGpuAdapterList; extern ULONG EtGpuTotalNodeCount; extern ULONG EtGpuTotalSegmentCount; extern ULONG64 EtGpuDedicatedLimit; extern ULONG64 EtGpuSharedLimit; -extern RTL_BITMAP EtGpuNodeBitMap; extern PH_UINT64_DELTA EtClockTotalRunningTimeDelta; extern LARGE_INTEGER EtClockTotalRunningTimeFrequency; -extern PH_UINT64_DELTA EtGpuTotalRunningTimeDelta; -extern PH_UINT64_DELTA EtGpuSystemRunningTimeDelta; extern FLOAT EtGpuNodeUsage; extern PH_CIRCULAR_BUFFER_FLOAT EtGpuNodeHistory; extern PH_CIRCULAR_BUFFER_ULONG EtMaxGpuNodeHistory; // ID of max. GPU usage process @@ -396,6 +404,17 @@ VOID EtGpuMonitorInitialization( VOID ); +NTSTATUS EtQueryAdapterInformation( + _In_ D3DKMT_HANDLE AdapterHandle, + _In_ KMTQUERYADAPTERINFOTYPE InformationClass, + _Out_writes_bytes_opt_(InformationLength) PVOID Information, + _In_ UINT32 InformationLength + ); + +BOOLEAN EtCloseAdapterHandle( + _In_ D3DKMT_HANDLE AdapterHandle + ); + typedef struct _ET_PROCESS_GPU_STATISTICS { ULONG SegmentCount; @@ -429,16 +448,13 @@ ULONG EtGetGpuAdapterIndexFromNodeIndex( _In_ ULONG NodeIndex ); -PPH_STRING EtGetGpuAdapterDescription( - _In_ ULONG Index - ); - -VOID EtAllocateGpuNodeBitMap( - _Out_ PRTL_BITMAP BitMap +PPH_STRING EtGetGpuAdapterNodeDescription( + _In_ ULONG Index, + _In_ ULONG NodeIndex ); -VOID EtUpdateGpuNodeBitMap( - _In_ PRTL_BITMAP NewBitMap +PPH_STRING EtGetGpuAdapterDescription( + _In_ ULONG Index ); VOID EtQueryProcessGpuStatistics( @@ -446,6 +462,12 @@ VOID EtQueryProcessGpuStatistics( _Out_ PET_PROCESS_GPU_STATISTICS Statistics ); +// gpudetails + +VOID EtShowGpuDetailsDialog( + _In_ HWND ParentWindowHandle + ); + // gpuprprp VOID EtProcessGpuPropertiesInitializing( @@ -489,8 +511,7 @@ VOID EtEtwMiniInformationInitializing( // gpunodes VOID EtShowGpuNodesDialog( - _In_ HWND ParentWindowHandle, - _In_ PPH_SYSINFO_PARAMETERS Parameters + _In_ HWND ParentWindowHandle ); // gpusys diff --git a/plugins/ExtendedTools/gpudetails.c b/plugins/ExtendedTools/gpudetails.c new file mode 100644 index 000000000000..e13c1d9bc8f5 --- /dev/null +++ b/plugins/ExtendedTools/gpudetails.c @@ -0,0 +1,395 @@ +/* + * Process Hacker Extended Tools - + * GPU details window + * + * Copyright (C) 2018 dmex + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include "exttools.h" +#include "gpumon.h" +#include + +static PH_CALLBACK_REGISTRATION ProcessesUpdatedCallbackRegistration; +static PH_LAYOUT_MANAGER LayoutManager; + +typedef enum _GPUADAPTER_DETAILS_INDEX +{ + GPUADAPTER_DETAILS_INDEX_PHYSICALLOCTION, + GPUADAPTER_DETAILS_INDEX_DRIVERDATE, + GPUADAPTER_DETAILS_INDEX_DRIVERVERSION, + GPUADAPTER_DETAILS_INDEX_WDDMVERSION, + GPUADAPTER_DETAILS_INDEX_TOTALMEMORY, + GPUADAPTER_DETAILS_INDEX_RESERVEDMEMORY, + GPUADAPTER_DETAILS_INDEX_MEMORYFREQUENCY, + GPUADAPTER_DETAILS_INDEX_MEMORYBANDWIDTH, + GPUADAPTER_DETAILS_INDEX_PCIEBANDWIDTH, + GPUADAPTER_DETAILS_INDEX_FANRPM, + GPUADAPTER_DETAILS_INDEX_POWERUSAGE, + GPUADAPTER_DETAILS_INDEX_TEMPERATURE, +} GPUADAPTER_DETAILS_INDEX; + +VOID EtpGpuDetailsAddListViewItemGroups( + _In_ HWND ListViewHandle, + _In_ INT DiskGroupId) +{ + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, GPUADAPTER_DETAILS_INDEX_PHYSICALLOCTION, L"Physical Location", NULL); + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, GPUADAPTER_DETAILS_INDEX_DRIVERDATE, L"Driver Date", NULL); + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, GPUADAPTER_DETAILS_INDEX_DRIVERVERSION, L"Driver Version", NULL); + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, GPUADAPTER_DETAILS_INDEX_WDDMVERSION, L"WDDM Version", NULL); + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, GPUADAPTER_DETAILS_INDEX_TOTALMEMORY, L"Total Memory", NULL); + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, GPUADAPTER_DETAILS_INDEX_RESERVEDMEMORY, L"Reserved Memory", NULL); + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, GPUADAPTER_DETAILS_INDEX_MEMORYFREQUENCY, L"Memory Frequency", NULL); + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, GPUADAPTER_DETAILS_INDEX_MEMORYBANDWIDTH, L"Memory Bandwidth", NULL); + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, GPUADAPTER_DETAILS_INDEX_PCIEBANDWIDTH, L"PCIE Bandwidth", NULL); + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, GPUADAPTER_DETAILS_INDEX_FANRPM, L"Fan RPM", NULL); + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, GPUADAPTER_DETAILS_INDEX_POWERUSAGE, L"Power Usage", NULL); + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, GPUADAPTER_DETAILS_INDEX_TEMPERATURE, L"Temperature", NULL); +} + +VOID EtpQueryAdapterDeviceProperties( + _In_ PWSTR DeviceName, + _In_ HWND ListViewHandle) +{ + PPH_STRING driverDate; + PPH_STRING driverVersion; + PPH_STRING locationInfo; + ULONG64 installedMemory; + + if (EtQueryDeviceProperties(DeviceName, NULL, &driverDate, &driverVersion, &locationInfo, &installedMemory)) + { + PhSetListViewSubItem(ListViewHandle, GPUADAPTER_DETAILS_INDEX_DRIVERDATE, 1, PhGetStringOrEmpty(driverDate)); + PhSetListViewSubItem(ListViewHandle, GPUADAPTER_DETAILS_INDEX_DRIVERVERSION, 1, PhGetStringOrEmpty(driverVersion)); + PhSetListViewSubItem(ListViewHandle, GPUADAPTER_DETAILS_INDEX_PHYSICALLOCTION, 1, PhGetStringOrEmpty(locationInfo)); + + if (installedMemory != ULLONG_MAX) + { + PhSetListViewSubItem(ListViewHandle, GPUADAPTER_DETAILS_INDEX_TOTALMEMORY, 1, PhaFormatSize(installedMemory, ULONG_MAX)->Buffer); + PhSetListViewSubItem(ListViewHandle, GPUADAPTER_DETAILS_INDEX_RESERVEDMEMORY, 1, PhaFormatSize(installedMemory - EtGpuDedicatedLimit, ULONG_MAX)->Buffer); + } + + PhClearReference(&locationInfo); + PhClearReference(&driverVersion); + PhClearReference(&driverDate); + } +} + +VOID EtpQueryAdapterRegistryInfo( + _In_ D3DKMT_HANDLE AdapterHandle, + _In_ HWND ListViewHandle) +{ + D3DKMT_ADAPTERREGISTRYINFO adapterInfo; + + memset(&adapterInfo, 0, sizeof(D3DKMT_ADAPTERREGISTRYINFO)); + + if (NT_SUCCESS(EtQueryAdapterInformation( + AdapterHandle, + KMTQAITYPE_ADAPTERREGISTRYINFO, + &adapterInfo, + sizeof(D3DKMT_ADAPTERREGISTRYINFO) + ))) + { + NOTHING; + } +} + +VOID EtpQueryAdapterDriverModel( + _In_ D3DKMT_HANDLE AdapterHandle, + _In_ HWND ListViewHandle) +{ + D3DKMT_DRIVERVERSION wddmversion; + + memset(&wddmversion, 0, sizeof(D3DKMT_DRIVERVERSION)); + + if (NT_SUCCESS(EtQueryAdapterInformation( + AdapterHandle, + KMTQAITYPE_DRIVERVERSION, + &wddmversion, + sizeof(D3DKMT_DRIVERVERSION) + ))) + { + switch (wddmversion) + { + case KMT_DRIVERVERSION_WDDM_1_0: + PhSetListViewSubItem(ListViewHandle, GPUADAPTER_DETAILS_INDEX_WDDMVERSION, 1, L"WDDM 1.0"); + break; + case KMT_DRIVERVERSION_WDDM_1_1_PRERELEASE: + PhSetListViewSubItem(ListViewHandle, GPUADAPTER_DETAILS_INDEX_WDDMVERSION, 1, L"WDDM 1.1 (pre-release)"); + break; + case KMT_DRIVERVERSION_WDDM_1_1: + PhSetListViewSubItem(ListViewHandle, GPUADAPTER_DETAILS_INDEX_WDDMVERSION, 1, L"WDDM 1.1"); + break; + case KMT_DRIVERVERSION_WDDM_1_2: + PhSetListViewSubItem(ListViewHandle, GPUADAPTER_DETAILS_INDEX_WDDMVERSION, 1, L"WDDM 1.2"); + break; + case KMT_DRIVERVERSION_WDDM_1_3: + PhSetListViewSubItem(ListViewHandle, GPUADAPTER_DETAILS_INDEX_WDDMVERSION, 1, L"WDDM 1.3"); + break; + case KMT_DRIVERVERSION_WDDM_2_0: + PhSetListViewSubItem(ListViewHandle, GPUADAPTER_DETAILS_INDEX_WDDMVERSION, 1, L"WDDM 2.0"); + break; + case KMT_DRIVERVERSION_WDDM_2_1: + PhSetListViewSubItem(ListViewHandle, GPUADAPTER_DETAILS_INDEX_WDDMVERSION, 1, L"WDDM 2.1"); + break; + case KMT_DRIVERVERSION_WDDM_2_2: + PhSetListViewSubItem(ListViewHandle, GPUADAPTER_DETAILS_INDEX_WDDMVERSION, 1, L"WDDM 2.2"); + break; + case KMT_DRIVERVERSION_WDDM_2_3: + PhSetListViewSubItem(ListViewHandle, GPUADAPTER_DETAILS_INDEX_WDDMVERSION, 1, L"WDDM 2.3"); + break; + case KMT_DRIVERVERSION_WDDM_2_4: + PhSetListViewSubItem(ListViewHandle, GPUADAPTER_DETAILS_INDEX_WDDMVERSION, 1, L"WDDM 2.4"); + break; + default: + PhSetListViewSubItem(ListViewHandle, GPUADAPTER_DETAILS_INDEX_WDDMVERSION, 1, L"ERROR"); + break; + } + } +} + +VOID EtpQueryAdapterDriverVersion( + _In_ D3DKMT_HANDLE AdapterHandle, + _In_ HWND ListViewHandle) +{ + D3DKMT_UMD_DRIVER_VERSION driverUserVersion; + D3DKMT_KMD_DRIVER_VERSION driverKernelVersion; + + memset(&driverUserVersion, 0, sizeof(D3DKMT_UMD_DRIVER_VERSION)); + memset(&driverKernelVersion, 0, sizeof(D3DKMT_KMD_DRIVER_VERSION)); + + if (NT_SUCCESS(EtQueryAdapterInformation( + AdapterHandle, + KMTQAITYPE_UMD_DRIVER_VERSION, + &driverUserVersion, + sizeof(D3DKMT_UMD_DRIVER_VERSION) + ))) + { + PPH_STRING driverVersionString = PhFormatString( + L"%hu.%hu.%hu.%hu", + HIWORD(driverUserVersion.DriverVersion.HighPart), + LOWORD(driverUserVersion.DriverVersion.HighPart), + HIWORD(driverUserVersion.DriverVersion.LowPart), + LOWORD(driverUserVersion.DriverVersion.LowPart) + ); + PhDereferenceObject(driverVersionString); + } + + if (NT_SUCCESS(EtQueryAdapterInformation( + AdapterHandle, + KMTQAITYPE_KMD_DRIVER_VERSION, + &driverKernelVersion, + sizeof(D3DKMT_KMD_DRIVER_VERSION) + ))) + { + PPH_STRING driverVersionString = PhFormatString( + L"%hu.%hu.%hu.%hu", + HIWORD(driverKernelVersion.DriverVersion.HighPart), + LOWORD(driverKernelVersion.DriverVersion.HighPart), + HIWORD(driverKernelVersion.DriverVersion.LowPart), + LOWORD(driverKernelVersion.DriverVersion.LowPart) + ); + PhDereferenceObject(driverVersionString); + } +} + +VOID EtpQueryAdapterDeviceIds( + _In_ D3DKMT_HANDLE AdapterHandle, + _In_ HWND ListViewHandle) +{ + D3DKMT_QUERY_DEVICE_IDS adapterDeviceId; + + memset(&adapterDeviceId, 0, sizeof(D3DKMT_QUERY_DEVICE_IDS)); + + if (NT_SUCCESS(EtQueryAdapterInformation( + AdapterHandle, + KMTQAITYPE_PHYSICALADAPTERDEVICEIDS, + &adapterDeviceId, + sizeof(D3DKMT_QUERY_DEVICE_IDS) + ))) + { + //UINT32 VendorID; + //UINT32 DeviceID; + //UINT32 SubVendorID; + //UINT32 SubSystemID; + //UINT32 RevisionID; + //UINT32 BusType; + } +} + +VOID EtpQueryAdapterPerfInfo( + _In_ D3DKMT_HANDLE AdapterHandle, + _In_ HWND ListViewHandle) +{ + D3DKMT_ADAPTER_PERFDATA adapterPerfData; + + memset(&adapterPerfData, 0, sizeof(D3DKMT_ADAPTER_PERFDATA)); + + if (NT_SUCCESS(EtQueryAdapterInformation( + AdapterHandle, + KMTQAITYPE_ADAPTERPERFDATA, + &adapterPerfData, + sizeof(D3DKMT_ADAPTER_PERFDATA) + ))) + { + PhSetListViewSubItem(ListViewHandle, GPUADAPTER_DETAILS_INDEX_MEMORYFREQUENCY, 1, PhaFormatString(L"%lu MHz", adapterPerfData.MemoryFrequency / 1000 / 1000)->Buffer); + PhSetListViewSubItem(ListViewHandle, GPUADAPTER_DETAILS_INDEX_MEMORYBANDWIDTH, 1, PhaFormatSize(adapterPerfData.MemoryBandwidth, ULONG_MAX)->Buffer); + PhSetListViewSubItem(ListViewHandle, GPUADAPTER_DETAILS_INDEX_PCIEBANDWIDTH, 1, PhaFormatSize(adapterPerfData.PCIEBandwidth, ULONG_MAX)->Buffer); + PhSetListViewSubItem(ListViewHandle, GPUADAPTER_DETAILS_INDEX_FANRPM, 1, PhaFormatUInt64(adapterPerfData.FanRPM, FALSE)->Buffer); + PhSetListViewSubItem(ListViewHandle, GPUADAPTER_DETAILS_INDEX_POWERUSAGE, 1, PhaFormatString(L"%lu%%", adapterPerfData.Power * 100 / 1000)->Buffer); + PhSetListViewSubItem(ListViewHandle, GPUADAPTER_DETAILS_INDEX_TEMPERATURE, 1, PhaFormatString(L"%lu\u00b0C", adapterPerfData.Temperature * 100 / 1000)->Buffer); + } +} + +VOID EtpGpuDetailsEnumAdapters( + _In_ HWND ListViewHandle + ) +{ + PETP_GPU_ADAPTER gpuAdapter; + D3DKMT_OPENADAPTERFROMDEVICENAME openAdapterFromDeviceName; + + for (ULONG i = 0; i < EtpGpuAdapterList->Count; i++) + { + gpuAdapter = EtpGpuAdapterList->Items[i]; + + memset(&openAdapterFromDeviceName, 0, sizeof(D3DKMT_OPENADAPTERFROMLUID)); + openAdapterFromDeviceName.DeviceName = PhGetString(gpuAdapter->DeviceInterface); + + if (!NT_SUCCESS(D3DKMTOpenAdapterFromDeviceName(&openAdapterFromDeviceName))) + continue; + + if (!ListView_HasGroup(ListViewHandle, i)) + { + if (PhAddListViewGroup(ListViewHandle, i, PhGetString(gpuAdapter->Description)) == MAXINT) + { + EtCloseAdapterHandle(openAdapterFromDeviceName.AdapterHandle); + continue; + } + + EtpGpuDetailsAddListViewItemGroups(ListViewHandle, i); + } + + EtpQueryAdapterDeviceProperties(openAdapterFromDeviceName.DeviceName, ListViewHandle); + //EtpQueryAdapterRegistryInfo(openAdapterFromDeviceName.AdapterHandle, ListViewHandle); + EtpQueryAdapterDriverModel(openAdapterFromDeviceName.AdapterHandle, ListViewHandle); + //EtpQueryAdapterDriverVersion(openAdapterFromDeviceName.AdapterHandle, ListViewHandle); + //EtpQueryAdapterDeviceIds(openAdapterFromDeviceName.AdapterHandle, ListViewHandle); + //EtQueryAdapterFeatureLevel(openAdapterFromDeviceName.AdapterLuid); + EtpQueryAdapterPerfInfo(openAdapterFromDeviceName.AdapterHandle, ListViewHandle); + + EtCloseAdapterHandle(openAdapterFromDeviceName.AdapterHandle); + } +} + +static VOID ProcessesUpdatedCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + PostMessage((HWND)Context, ET_WM_UPDATE, 0, 0); +} + +INT_PTR CALLBACK EtpGpuDetailsDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + switch (uMsg) + { + case WM_INITDIALOG: + { + HWND listViewHandle = GetDlgItem(hwndDlg, IDC_GPULIST); + + SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhInstanceHandle, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); + SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhInstanceHandle, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); + + PhSetListViewStyle(listViewHandle, FALSE, TRUE); + PhSetControlTheme(listViewHandle, L"explorer"); + PhAddListViewColumn(listViewHandle, 0, 0, 0, LVCFMT_LEFT, 230, L"Property"); + PhAddListViewColumn(listViewHandle, 1, 1, 1, LVCFMT_LEFT, 200, L"Value"); + PhSetExtendedListView(listViewHandle); + ListView_EnableGroupView(listViewHandle, TRUE); + + PhInitializeLayoutManager(&LayoutManager, hwndDlg); + PhAddLayoutItem(&LayoutManager, listViewHandle, NULL, PH_ANCHOR_ALL); + PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDOK), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); + + // Note: This dialog must be centered after all other graphs and controls have been added. + //if (PhGetIntegerPairSetting(SETTING_NAME_GPU_NODES_WINDOW_POSITION).X != 0) + // PhLoadWindowPlacementFromSetting(SETTING_NAME_GPU_NODES_WINDOW_POSITION, SETTING_NAME_GPU_NODES_WINDOW_SIZE, hwndDlg); + //else + PhCenterWindow(hwndDlg, GetParent(hwndDlg)); + + EtpGpuDetailsEnumAdapters(listViewHandle); + + PhRegisterCallback( + &PhProcessesUpdatedEvent, + ProcessesUpdatedCallback, + hwndDlg, + &ProcessesUpdatedCallbackRegistration + ); + + EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); + } + break; + case WM_DESTROY: + { + PhUnregisterCallback(&PhProcessesUpdatedEvent, &ProcessesUpdatedCallbackRegistration); + + PhDeleteLayoutManager(&LayoutManager); + } + break; + case WM_COMMAND: + { + switch (GET_WM_COMMAND_ID(wParam, lParam)) + { + case IDCANCEL: + case IDOK: + { + EndDialog(hwndDlg, IDOK); + } + break; + } + } + break; + case WM_SIZE: + { + PhLayoutManagerLayout(&LayoutManager); + } + break; + case ET_WM_UPDATE: + { + EtpGpuDetailsEnumAdapters(GetDlgItem(hwndDlg, IDC_GPULIST)); + } + break; + } + + return FALSE; +} + +VOID EtShowGpuDetailsDialog( + _In_ HWND ParentWindowHandle + ) +{ + DialogBox( + PluginInstance->DllBase, + MAKEINTRESOURCE(IDD_SYSINFO_GPUDETAILS), + ParentWindowHandle, + EtpGpuDetailsDlgProc + ); +} diff --git a/plugins/ExtendedTools/gpumon.c b/plugins/ExtendedTools/gpumon.c index 62af0e107a56..ba2b817f11d1 100644 --- a/plugins/ExtendedTools/gpumon.c +++ b/plugins/ExtendedTools/gpumon.c @@ -26,28 +26,20 @@ #include #include #include -#include "d3dkmt.h" #include "gpumon.h" BOOLEAN EtGpuEnabled; -static PPH_LIST EtpGpuAdapterList; +PPH_LIST EtpGpuAdapterList; static PH_CALLBACK_REGISTRATION ProcessesUpdatedCallbackRegistration; ULONG EtGpuTotalNodeCount = 0; -ULONG EtGpuTotalSegmentCount; -ULONG64 EtGpuDedicatedLimit; -ULONG64 EtGpuSharedLimit; +ULONG EtGpuTotalSegmentCount = 0; ULONG EtGpuNextNodeIndex = 0; -RTL_BITMAP EtGpuNodeBitMap; -PULONG EtGpuNodeBitMapBuffer; -ULONG EtGpuNodeBitMapBitsSet; -PULONG EtGpuNewNodeBitMapBuffer; PH_UINT64_DELTA EtClockTotalRunningTimeDelta; LARGE_INTEGER EtClockTotalRunningTimeFrequency; -PH_UINT64_DELTA EtGpuTotalRunningTimeDelta; -PH_UINT64_DELTA EtGpuSystemRunningTimeDelta; -FLOAT EtGpuNodeUsage; + +FLOAT EtGpuNodeUsage = 0; PH_CIRCULAR_BUFFER_FLOAT EtGpuNodeHistory; PH_CIRCULAR_BUFFER_ULONG EtMaxGpuNodeHistory; // ID of max. GPU usage process PH_CIRCULAR_BUFFER_FLOAT EtMaxGpuNodeUsageHistory; @@ -55,8 +47,10 @@ PH_CIRCULAR_BUFFER_FLOAT EtMaxGpuNodeUsageHistory; PPH_UINT64_DELTA EtGpuNodesTotalRunningTimeDelta; PPH_CIRCULAR_BUFFER_FLOAT EtGpuNodesHistory; -ULONG64 EtGpuDedicatedUsage; -ULONG64 EtGpuSharedUsage; +ULONG64 EtGpuDedicatedLimit = 0; +ULONG64 EtGpuDedicatedUsage = 0; +ULONG64 EtGpuSharedLimit = 0; +ULONG64 EtGpuSharedUsage = 0; PH_CIRCULAR_BUFFER_ULONG EtGpuDedicatedHistory; PH_CIRCULAR_BUFFER_ULONG EtGpuSharedHistory; @@ -76,9 +70,6 @@ VOID EtGpuMonitorInitialization( { ULONG sampleCount; ULONG i; - ULONG j; - PPH_STRING bitmapString; - D3DKMT_QUERYSTATISTICS queryStatistics; sampleCount = PhGetIntegerSetting(L"SampleCount"); PhInitializeCircularBuffer_FLOAT(&EtGpuNodeHistory, sampleCount); @@ -87,6 +78,8 @@ VOID EtGpuMonitorInitialization( PhInitializeCircularBuffer_ULONG(&EtGpuDedicatedHistory, sampleCount); PhInitializeCircularBuffer_ULONG(&EtGpuSharedHistory, sampleCount); + PhInitializeDelta(&EtClockTotalRunningTimeDelta); + EtGpuNodesTotalRunningTimeDelta = PhAllocate(sizeof(PH_UINT64_DELTA) * EtGpuTotalNodeCount); memset(EtGpuNodesTotalRunningTimeDelta, 0, sizeof(PH_UINT64_DELTA) * EtGpuTotalNodeCount); EtGpuNodesHistory = PhAllocate(sizeof(PH_CIRCULAR_BUFFER_FLOAT) * EtGpuTotalNodeCount); @@ -102,80 +95,471 @@ VOID EtGpuMonitorInitialization( NULL, &ProcessesUpdatedCallbackRegistration ); + } +} - // Load the node bitmap. +NTSTATUS EtQueryAdapterInformation( + _In_ D3DKMT_HANDLE AdapterHandle, + _In_ KMTQUERYADAPTERINFOTYPE InformationClass, + _Out_writes_bytes_opt_(InformationLength) PVOID Information, + _In_ UINT32 InformationLength + ) +{ + D3DKMT_QUERYADAPTERINFO queryAdapterInfo; - bitmapString = PhGetStringSetting(SETTING_NAME_GPU_NODE_BITMAP); + memset(&queryAdapterInfo, 0, sizeof(D3DKMT_QUERYADAPTERINFO)); - if (!(bitmapString->Length & 3) && bitmapString->Length / 4 <= BYTES_NEEDED_FOR_BITS(EtGpuTotalNodeCount)) + queryAdapterInfo.AdapterHandle = AdapterHandle; + queryAdapterInfo.Type = InformationClass; + queryAdapterInfo.PrivateDriverData = Information; + queryAdapterInfo.PrivateDriverDataSize = InformationLength; + + return D3DKMTQueryAdapterInfo(&queryAdapterInfo); +} + +BOOLEAN EtCloseAdapterHandle( + _In_ D3DKMT_HANDLE AdapterHandle + ) +{ + D3DKMT_CLOSEADAPTER closeAdapter; + + memset(&closeAdapter, 0, sizeof(D3DKMT_CLOSEADAPTER)); + closeAdapter.AdapterHandle = AdapterHandle; + + return NT_SUCCESS(D3DKMTCloseAdapter(&closeAdapter)); +} + +BOOLEAN EtpIsGpuSoftwareDevice( + _In_ D3DKMT_HANDLE AdapterHandle + ) +{ + D3DKMT_ADAPTERTYPE adapterType; + + memset(&adapterType, 0, sizeof(D3DKMT_ADAPTERTYPE)); + + if (NT_SUCCESS(EtQueryAdapterInformation( + AdapterHandle, + KMTQAITYPE_ADAPTERTYPE, + &adapterType, + sizeof(D3DKMT_ADAPTERTYPE) + ))) + { + if (adapterType.SoftwareDevice) { - PhHexStringToBuffer(&bitmapString->sr, (PUCHAR)EtGpuNodeBitMapBuffer); - EtGpuNodeBitMapBitsSet = RtlNumberOfSetBits(&EtGpuNodeBitMap); + return TRUE; } + } + + return FALSE; +} + +PPH_STRING EtpGetNodeEngineTypeString( + _In_ D3DKMT_NODEMETADATA NodeMetaData + ) +{ + switch (NodeMetaData.EngineType) + { + case DXGK_ENGINE_TYPE_OTHER: + return PhCreateString(NodeMetaData.FriendlyName); + case DXGK_ENGINE_TYPE_3D: + return PhCreateString(L"3D"); + case DXGK_ENGINE_TYPE_VIDEO_DECODE: + return PhCreateString(L"Video Decode"); + case DXGK_ENGINE_TYPE_VIDEO_ENCODE: + return PhCreateString(L"Video Encode"); + case DXGK_ENGINE_TYPE_VIDEO_PROCESSING: + return PhCreateString(L"Video Processing"); + case DXGK_ENGINE_TYPE_SCENE_ASSEMBLY: + return PhCreateString(L"Scene Assembly"); + case DXGK_ENGINE_TYPE_COPY: + return PhCreateString(L"Copy"); + case DXGK_ENGINE_TYPE_OVERLAY: + return PhCreateString(L"Overlay"); + case DXGK_ENGINE_TYPE_CRYPTO: + return PhCreateString(L"Crypto"); + } - PhDereferenceObject(bitmapString); + return PhFormatString(L"ERROR (%lu)", NodeMetaData.EngineType); +} + +PPH_STRING EtpQueryDeviceProperty( + _In_ DEVINST DeviceHandle, + _In_ CONST DEVPROPKEY *DeviceProperty + ) +{ + CONFIGRET result; + PBYTE buffer; + ULONG bufferSize; + DEVPROPTYPE propertyType; - // Fix up the node bitmap if the current node count differs from what we've seen. - if (EtGpuTotalNodeCount != PhGetIntegerSetting(SETTING_NAME_GPU_LAST_NODE_COUNT)) + bufferSize = 0x80; + buffer = PhAllocate(bufferSize); + propertyType = DEVPROP_TYPE_EMPTY; + + if ((result = CM_Get_DevNode_Property( + DeviceHandle, + DeviceProperty, + &propertyType, + buffer, + &bufferSize, + 0 + )) != CR_SUCCESS) + { + PhFree(buffer); + buffer = PhAllocate(bufferSize); + + result = CM_Get_DevNode_Property( + DeviceHandle, + DeviceProperty, + &propertyType, + buffer, + &bufferSize, + 0 + ); + } + + if (result != CR_SUCCESS) + { + PhFree(buffer); + return NULL; + } + + switch (propertyType) + { + case DEVPROP_TYPE_STRING: { - ULONG maxContextSwitch = 0; - ULONG maxContextSwitchNodeIndex = 0; + PPH_STRING string; - RtlClearAllBits(&EtGpuNodeBitMap); - EtGpuNodeBitMapBitsSet = 0; + string = PhCreateStringEx((PWCHAR)buffer, bufferSize); + PhTrimToNullTerminatorString(string); - for (i = 0; i < EtpGpuAdapterList->Count; i++) - { - PETP_GPU_ADAPTER gpuAdapter = EtpGpuAdapterList->Items[i]; + PhFree(buffer); + return string; + } + break; + case DEVPROP_TYPE_FILETIME: + { + PPH_STRING string; + FILETIME newFileTime; + SYSTEMTIME systemTime; - for (j = 0; j < gpuAdapter->NodeCount; j++) - { - memset(&queryStatistics, 0, sizeof(D3DKMT_QUERYSTATISTICS)); - queryStatistics.Type = D3DKMT_QUERYSTATISTICS_NODE; - queryStatistics.AdapterLuid = gpuAdapter->AdapterLuid; - queryStatistics.QueryNode.NodeId = j; + FileTimeToLocalFileTime((PFILETIME)buffer, &newFileTime); + FileTimeToSystemTime(&newFileTime, &systemTime); - if (NT_SUCCESS(D3DKMTQueryStatistics(&queryStatistics))) - { - // The numbers below are quite arbitrary. - if (queryStatistics.QueryResult.NodeInformation.GlobalInformation.RunningTime.QuadPart != 0 && - queryStatistics.QueryResult.NodeInformation.GlobalInformation.ContextSwitch > 10000) - { - RtlSetBits(&EtGpuNodeBitMap, gpuAdapter->FirstNodeIndex + j, 1); - EtGpuNodeBitMapBitsSet++; - } - - if (maxContextSwitch < queryStatistics.QueryResult.NodeInformation.GlobalInformation.ContextSwitch) - { - maxContextSwitch = queryStatistics.QueryResult.NodeInformation.GlobalInformation.ContextSwitch; - maxContextSwitchNodeIndex = gpuAdapter->FirstNodeIndex + j; - } - } + string = PhFormatDateTime(&systemTime); + + PhFree(buffer); + return string; + } + break; + case DEVPROP_TYPE_UINT32: + { + PPH_STRING string; + + string = PhFormatUInt64(*(PULONG)buffer, FALSE); + + PhFree(buffer); + return string; + } + break; + case DEVPROP_TYPE_UINT64: + { + PPH_STRING string; + + string = PhFormatUInt64(*(PULONG64)buffer, FALSE); + + PhFree(buffer); + return string; + } + break; + } + + return NULL; +} + +PPH_STRING EtpQueryDeviceRegistryProperty( + _In_ DEVINST DeviceHandle, + _In_ ULONG DeviceProperty + ) +{ + CONFIGRET result; + PPH_STRING string; + ULONG bufferSize; + DEVPROPTYPE devicePropertyType; + + bufferSize = 0x80; + string = PhCreateStringEx(NULL, bufferSize); + + if ((result = CM_Get_DevNode_Registry_Property( + DeviceHandle, + DeviceProperty, + &devicePropertyType, + (PBYTE)string->Buffer, + &bufferSize, + 0 + )) != CR_SUCCESS) + { + PhDereferenceObject(string); + string = PhCreateStringEx(NULL, bufferSize); + + result = CM_Get_DevNode_Registry_Property( + DeviceHandle, + DeviceProperty, + &devicePropertyType, + (PBYTE)string->Buffer, + &bufferSize, + 0 + ); + } + + if (result != CR_SUCCESS) + { + PhDereferenceObject(string); + return NULL; + } + + PhTrimToNullTerminatorString(string); + + return string; +} + +// Note: MSDN states this value must be created by video devices BUT Task Manager +// doesn't query this value and I currently don't know where it's querying this information. +// https://docs.microsoft.com/en-us/windows-hardware/drivers/display/registering-hardware-information +ULONG64 EtpQueryGpuInstalledMemory( + _In_ DEVINST DeviceHandle + ) +{ + ULONG64 installedMemory = ULLONG_MAX; + HKEY keyHandle; + + if (CM_Open_DevInst_Key( + DeviceHandle, + KEY_READ, + 0, + RegDisposition_OpenExisting, + &keyHandle, + CM_REGISTRY_SOFTWARE + ) == CR_SUCCESS) + { + installedMemory = PhQueryRegistryUlong64(keyHandle, L"HardwareInformation.qwMemorySize"); + + if (installedMemory == ULLONG_MAX) + installedMemory = PhQueryRegistryUlong(keyHandle, L"HardwareInformation.MemorySize"); + + if (installedMemory == ULONG_MAX) // HACK + installedMemory = ULLONG_MAX; + + NtClose(keyHandle); + } + + return installedMemory; +} + +BOOLEAN EtQueryDeviceProperties( + _In_ PWSTR DeviceInterface, + _Out_ PPH_STRING *Description, + _Out_ PPH_STRING *DriverDate, + _Out_ PPH_STRING *DriverVersion, + _Out_ PPH_STRING *LocationInfo, + _Out_ ULONG64 *InstalledMemory + ) +{ + DEVPROPTYPE devicePropertyType; + DEVINST deviceInstanceHandle; + ULONG deviceInstanceIdLength = MAX_DEVICE_ID_LEN; + WCHAR deviceInstanceId[MAX_DEVICE_ID_LEN]; + + if (CM_Get_Device_Interface_Property( + DeviceInterface, + &DEVPKEY_Device_InstanceId, + &devicePropertyType, + (PBYTE)deviceInstanceId, + &deviceInstanceIdLength, + 0 + ) != CR_SUCCESS) + { + return FALSE; + } + + if (CM_Locate_DevNode( + &deviceInstanceHandle, + deviceInstanceId, + CM_LOCATE_DEVNODE_NORMAL + ) != CR_SUCCESS) + { + return FALSE; + } + + if (Description) + *Description = EtpQueryDeviceProperty(deviceInstanceHandle, &DEVPKEY_Device_DeviceDesc); // DEVPKEY_NAME + if (DriverDate) + *DriverDate = EtpQueryDeviceProperty(deviceInstanceHandle, &DEVPKEY_Device_DriverDate); + if (DriverVersion) + *DriverVersion = EtpQueryDeviceProperty(deviceInstanceHandle, &DEVPKEY_Device_DriverVersion); + if (LocationInfo) + *LocationInfo = EtpQueryDeviceProperty(deviceInstanceHandle, &DEVPKEY_Device_LocationInfo); + if (InstalledMemory) + *InstalledMemory = EtpQueryGpuInstalledMemory(deviceInstanceHandle); + // EtpQueryDeviceProperty(deviceInstanceHandle, &DEVPKEY_Device_Manufacturer); + + // Undocumented device properties (Win10 only) + //DEFINE_DEVPROPKEY(DEVPKEY_Gpu_Luid, 0x60b193cb, 0x5276, 0x4d0f, 0x96, 0xfc, 0xf1, 0x73, 0xab, 0xad, 0x3e, 0xc6, 2); // DEVPROP_TYPE_UINT64 + //DEFINE_DEVPROPKEY(DEVPKEY_Gpu_PhysicalAdapterIndex, 0x60b193cb, 0x5276, 0x4d0f, 0x96, 0xfc, 0xf1, 0x73, 0xab, 0xad, 0x3e, 0xc6, 3); // DEVPROP_TYPE_UINT32 + + return TRUE; +} + +D3D_FEATURE_LEVEL EtQueryAdapterFeatureLevel( + _In_ LUID AdapterLuid + ) +{ + static PH_INITONCE initOnce = PH_INITONCE_INIT; + static PFN_D3D11_CREATE_DEVICE D3D11CreateDevice_I = NULL; + static HRESULT (WINAPI *CreateDXGIFactory1_I)(_In_ REFIID riid, _Out_ PVOID *ppFactory) = NULL; + D3D_FEATURE_LEVEL d3dFeatureLevelResult = 0; + IDXGIFactory1 *dxgiFactory; + IDXGIAdapter* dxgiAdapter; + UINT i = 0; + + if (PhBeginInitOnce(&initOnce)) + { + LoadLibrary(L"dxgi.dll"); + LoadLibrary(L"d3d11.dll"); + CreateDXGIFactory1_I = PhGetModuleProcAddress(L"dxgi.dll", "CreateDXGIFactory1"); + D3D11CreateDevice_I = PhGetModuleProcAddress(L"d3d11.dll", "D3D11CreateDevice"); + + PhEndInitOnce(&initOnce); + } + + if (!CreateDXGIFactory1_I || !SUCCEEDED(CreateDXGIFactory1_I(&IID_IDXGIFactory1, &dxgiFactory))) + return 0; + + for (UINT i = 0; i < 25; i++) + { + DXGI_ADAPTER_DESC dxgiAdapterDescription; + + if (!SUCCEEDED(IDXGIFactory1_EnumAdapters(dxgiFactory, i, &dxgiAdapter))) + break; + + if (SUCCEEDED(IDXGIAdapter_GetDesc(dxgiAdapter, &dxgiAdapterDescription))) + { + if (RtlEqualMemory(&dxgiAdapterDescription.AdapterLuid, &AdapterLuid, sizeof(LUID))) + { + D3D_FEATURE_LEVEL d3dFeatureLevel[] = + { + D3D_FEATURE_LEVEL_12_1, + D3D_FEATURE_LEVEL_12_0, + D3D_FEATURE_LEVEL_11_1, + D3D_FEATURE_LEVEL_11_0, + D3D_FEATURE_LEVEL_10_1, + D3D_FEATURE_LEVEL_10_0, + D3D_FEATURE_LEVEL_9_3, + D3D_FEATURE_LEVEL_9_2, + D3D_FEATURE_LEVEL_9_1 + }; + D3D_FEATURE_LEVEL d3ddeviceFeatureLevel; + ID3D11Device* d3d11device; + + if (D3D11CreateDevice_I && SUCCEEDED(D3D11CreateDevice_I( + dxgiAdapter, + D3D_DRIVER_TYPE_UNKNOWN, + NULL, + 0, + d3dFeatureLevel, + RTL_NUMBER_OF(d3dFeatureLevel), + D3D11_SDK_VERSION, + &d3d11device, + &d3ddeviceFeatureLevel, + NULL + ))) + { + d3dFeatureLevelResult = d3ddeviceFeatureLevel; + ID3D11Device_Release(d3d11device); + break; } } + } + + IDXGIAdapter_Release(dxgiAdapter); + } - // Just in case - if (EtGpuNodeBitMapBitsSet == 0) + IDXGIFactory1_Release(dxgiFactory); + return d3dFeatureLevelResult; +} + +PETP_GPU_ADAPTER EtpAddDisplayAdapter( + _In_ PWSTR DeviceInterface, + _In_ D3DKMT_HANDLE AdapterHandle, + _In_ LUID AdapterLuid, + _In_ ULONG NumberOfSegments, + _In_ ULONG NumberOfNodes + ) +{ + PETP_GPU_ADAPTER adapter; + SIZE_T sizeNeeded; + + sizeNeeded = FIELD_OFFSET(ETP_GPU_ADAPTER, ApertureBitMapBuffer); + sizeNeeded += BYTES_NEEDED_FOR_BITS(NumberOfSegments); + + adapter = PhAllocateZero(sizeNeeded); + adapter->DeviceInterface = PhCreateString(DeviceInterface); + adapter->AdapterLuid = AdapterLuid; + adapter->NodeCount = NumberOfNodes; + adapter->SegmentCount = NumberOfSegments; + RtlInitializeBitMap(&adapter->ApertureBitMap, adapter->ApertureBitMapBuffer, NumberOfSegments); + + { + PPH_STRING description; + + if (EtQueryDeviceProperties(DeviceInterface, &description, NULL, NULL, NULL, NULL)) + { + adapter->Description = description; + } + } + + if (WindowsVersion >= WINDOWS_10) + { + adapter->NodeNameList = PhCreateList(adapter->NodeCount); + + for (ULONG i = 0; i < adapter->NodeCount; i++) + { + D3DKMT_NODEMETADATA metaDataInfo; + + memset(&metaDataInfo, 0, sizeof(D3DKMT_NODEMETADATA)); + metaDataInfo.NodeOrdinal = i; + + if (NT_SUCCESS(EtQueryAdapterInformation( + AdapterHandle, + KMTQAITYPE_NODEMETADATA, + &metaDataInfo, + sizeof(D3DKMT_NODEMETADATA) + ))) { - RtlSetBits(&EtGpuNodeBitMap, maxContextSwitchNodeIndex, 1); - EtGpuNodeBitMapBitsSet = 1; + PhAddItemList(adapter->NodeNameList, EtpGetNodeEngineTypeString(metaDataInfo)); + } + else + { + PhAddItemList(adapter->NodeNameList, PhReferenceEmptyString()); } - - PhSetIntegerSetting(SETTING_NAME_GPU_LAST_NODE_COUNT, EtGpuTotalNodeCount); } } + + PhAddItemList(EtpGpuAdapterList, adapter); + + return adapter; } BOOLEAN EtpInitializeD3DStatistics( VOID ) { + PPH_LIST deviceAdapterList; PWSTR deviceInterfaceList; ULONG deviceInterfaceListLength = 0; PWSTR deviceInterface; D3DKMT_OPENADAPTERFROMDEVICENAME openAdapterFromDeviceName; D3DKMT_QUERYSTATISTICS queryStatistics; - D3DKMT_CLOSEADAPTER closeAdapter; if (CM_Get_Device_Interface_List_Size( &deviceInterfaceListLength, @@ -202,86 +586,115 @@ BOOLEAN EtpInitializeD3DStatistics( return FALSE; } + deviceAdapterList = PhCreateList(10); + for (deviceInterface = deviceInterfaceList; *deviceInterface; deviceInterface += PhCountStringZ(deviceInterface) + 1) + { + PhAddItemList(deviceAdapterList, deviceInterface); + } + + for (ULONG i = 0; i < deviceAdapterList->Count; i++) { memset(&openAdapterFromDeviceName, 0, sizeof(D3DKMT_OPENADAPTERFROMDEVICENAME)); - openAdapterFromDeviceName.pDeviceName = deviceInterface; + openAdapterFromDeviceName.DeviceName = deviceAdapterList->Items[i]; - if (NT_SUCCESS(D3DKMTOpenAdapterFromDeviceName(&openAdapterFromDeviceName))) - { - memset(&queryStatistics, 0, sizeof(D3DKMT_QUERYSTATISTICS)); - queryStatistics.Type = D3DKMT_QUERYSTATISTICS_ADAPTER; - queryStatistics.AdapterLuid = openAdapterFromDeviceName.AdapterLuid; + if (!NT_SUCCESS(D3DKMTOpenAdapterFromDeviceName(&openAdapterFromDeviceName))) + continue; - if (NT_SUCCESS(D3DKMTQueryStatistics(&queryStatistics))) + if (WindowsVersion >= WINDOWS_8 && deviceAdapterList->Count > 1) + { + if (EtpIsGpuSoftwareDevice(openAdapterFromDeviceName.AdapterHandle)) { - PETP_GPU_ADAPTER gpuAdapter; - ULONG i; + EtCloseAdapterHandle(openAdapterFromDeviceName.AdapterHandle); + continue; + } + } + + if (WindowsVersion >= WINDOWS_10_RS3) + { + D3DKMT_SEGMENTSIZEINFO segmentInfo; + + memset(&segmentInfo, 0, sizeof(D3DKMT_SEGMENTSIZEINFO)); - gpuAdapter = EtpAllocateGpuAdapter(queryStatistics.QueryResult.AdapterInformation.NbSegments); - gpuAdapter->AdapterLuid = openAdapterFromDeviceName.AdapterLuid; - gpuAdapter->Description = EtpQueryDeviceDescription(deviceInterface); - gpuAdapter->NodeCount = queryStatistics.QueryResult.AdapterInformation.NodeCount; - gpuAdapter->SegmentCount = queryStatistics.QueryResult.AdapterInformation.NbSegments; - RtlInitializeBitMap(&gpuAdapter->ApertureBitMap, gpuAdapter->ApertureBitMapBuffer, queryStatistics.QueryResult.AdapterInformation.NbSegments); + if (NT_SUCCESS(EtQueryAdapterInformation( + openAdapterFromDeviceName.AdapterHandle, + KMTQAITYPE_GETSEGMENTSIZE, + &segmentInfo, + sizeof(D3DKMT_SEGMENTSIZEINFO) + ))) + { + EtGpuDedicatedLimit += segmentInfo.DedicatedVideoMemorySize; + EtGpuSharedLimit += segmentInfo.SharedSystemMemorySize; + } + } - PhAddItemList(EtpGpuAdapterList, gpuAdapter); - EtGpuTotalNodeCount += gpuAdapter->NodeCount; - EtGpuTotalSegmentCount += gpuAdapter->SegmentCount; + memset(&queryStatistics, 0, sizeof(D3DKMT_QUERYSTATISTICS)); + queryStatistics.Type = D3DKMT_QUERYSTATISTICS_ADAPTER; + queryStatistics.AdapterLuid = openAdapterFromDeviceName.AdapterLuid; - gpuAdapter->FirstNodeIndex = EtGpuNextNodeIndex; - EtGpuNextNodeIndex += gpuAdapter->NodeCount; + if (NT_SUCCESS(D3DKMTQueryStatistics(&queryStatistics))) + { + PETP_GPU_ADAPTER gpuAdapter; + + gpuAdapter = EtpAddDisplayAdapter( + openAdapterFromDeviceName.DeviceName, + openAdapterFromDeviceName.AdapterHandle, + openAdapterFromDeviceName.AdapterLuid, + queryStatistics.QueryResult.AdapterInformation.NbSegments, + queryStatistics.QueryResult.AdapterInformation.NodeCount + ); + + gpuAdapter->FirstNodeIndex = EtGpuNextNodeIndex; + EtGpuTotalNodeCount += gpuAdapter->NodeCount; + EtGpuTotalSegmentCount += gpuAdapter->SegmentCount; + EtGpuNextNodeIndex += gpuAdapter->NodeCount; + + for (ULONG ii = 0; ii < gpuAdapter->SegmentCount; ii++) + { + memset(&queryStatistics, 0, sizeof(D3DKMT_QUERYSTATISTICS)); + queryStatistics.Type = D3DKMT_QUERYSTATISTICS_SEGMENT; + queryStatistics.AdapterLuid = gpuAdapter->AdapterLuid; + queryStatistics.QuerySegment.SegmentId = ii; - for (i = 0; i < gpuAdapter->SegmentCount; i++) + if (NT_SUCCESS(D3DKMTQueryStatistics(&queryStatistics))) { - memset(&queryStatistics, 0, sizeof(D3DKMT_QUERYSTATISTICS)); - queryStatistics.Type = D3DKMT_QUERYSTATISTICS_SEGMENT; - queryStatistics.AdapterLuid = gpuAdapter->AdapterLuid; - queryStatistics.QuerySegment.SegmentId = i; + ULONG64 commitLimit; + ULONG aperture; - if (NT_SUCCESS(D3DKMTQueryStatistics(&queryStatistics))) + if (WindowsVersion >= WINDOWS_8) { - ULONG64 commitLimit; - ULONG aperture; - - if (WindowsVersion >= WINDOWS_8) - { - commitLimit = queryStatistics.QueryResult.SegmentInformation.CommitLimit; - aperture = queryStatistics.QueryResult.SegmentInformation.Aperture; - } - else - { - commitLimit = queryStatistics.QueryResult.SegmentInformationV1.CommitLimit; - aperture = queryStatistics.QueryResult.SegmentInformationV1.Aperture; - } + commitLimit = queryStatistics.QueryResult.SegmentInformation.CommitLimit; + aperture = queryStatistics.QueryResult.SegmentInformation.Aperture; + } + else + { + commitLimit = queryStatistics.QueryResult.SegmentInformationV1.CommitLimit; + aperture = queryStatistics.QueryResult.SegmentInformationV1.Aperture; + } + if (WindowsVersion < WINDOWS_10_RS3) + { if (aperture) EtGpuSharedLimit += commitLimit; else EtGpuDedicatedLimit += commitLimit; - - if (aperture) - RtlSetBits(&gpuAdapter->ApertureBitMap, i, 1); } + + if (aperture) + RtlSetBits(&gpuAdapter->ApertureBitMap, ii, 1); } } - - memset(&closeAdapter, 0, sizeof(D3DKMT_CLOSEADAPTER)); - closeAdapter.hAdapter = openAdapterFromDeviceName.hAdapter; - D3DKMTCloseAdapter(&closeAdapter); } + + EtCloseAdapterHandle(openAdapterFromDeviceName.AdapterHandle); } + PhDereferenceObject(deviceAdapterList); PhFree(deviceInterfaceList); if (EtGpuTotalNodeCount == 0) return FALSE; - EtGpuNodeBitMapBuffer = PhAllocate(BYTES_NEEDED_FOR_BITS(EtGpuTotalNodeCount)); - RtlInitializeBitMap(&EtGpuNodeBitMap, EtGpuNodeBitMapBuffer, EtGpuTotalNodeCount); - RtlSetBits(&EtGpuNodeBitMap, 0, 1); - EtGpuNodeBitMapBitsSet = 1; - return TRUE; } @@ -301,255 +714,171 @@ PETP_GPU_ADAPTER EtpAllocateGpuAdapter( return adapter; } -PPH_STRING EtpQueryDeviceDescription( - _In_ PWSTR DeviceInterface +VOID EtpUpdateProcessSegmentInformation( + _In_ PET_PROCESS_BLOCK Block ) { - CONFIGRET result; - PPH_STRING string; - ULONG bufferSize; - DEVPROPTYPE devicePropertyType; - DEVINST deviceInstanceHandle; - ULONG deviceInstanceIdLength = MAX_DEVICE_ID_LEN; - WCHAR deviceInstanceId[MAX_DEVICE_ID_LEN]; + PETP_GPU_ADAPTER gpuAdapter; + D3DKMT_QUERYSTATISTICS queryStatistics; + ULONG64 dedicatedUsage; + ULONG64 sharedUsage; - if (CM_Get_Device_Interface_Property( - DeviceInterface, - &DEVPKEY_Device_InstanceId, - &devicePropertyType, - (PBYTE)deviceInstanceId, - &deviceInstanceIdLength, - 0 - ) != CR_SUCCESS) - { - return NULL; - } + if (!Block->ProcessItem->QueryHandle) + return; - if (CM_Locate_DevNode( - &deviceInstanceHandle, - deviceInstanceId, - CM_LOCATE_DEVNODE_NORMAL - ) != CR_SUCCESS) + dedicatedUsage = 0; + sharedUsage = 0; + + for (ULONG i = 0; i < EtpGpuAdapterList->Count; i++) { - return NULL; - } + gpuAdapter = EtpGpuAdapterList->Items[i]; - bufferSize = 0x40; - string = PhCreateStringEx(NULL, bufferSize); + for (ULONG j = 0; j < gpuAdapter->SegmentCount; j++) + { + memset(&queryStatistics, 0, sizeof(D3DKMT_QUERYSTATISTICS)); + queryStatistics.Type = D3DKMT_QUERYSTATISTICS_PROCESS_SEGMENT; + queryStatistics.AdapterLuid = gpuAdapter->AdapterLuid; + queryStatistics.ProcessHandle = Block->ProcessItem->QueryHandle; + queryStatistics.QueryProcessSegment.SegmentId = j; - if ((result = CM_Get_DevNode_Property( // CM_Get_DevNode_Registry_Property with CM_DRP_DEVICEDESC?? - deviceInstanceHandle, - &DEVPKEY_Device_DeviceDesc, - &devicePropertyType, - (PBYTE)string->Buffer, - &bufferSize, - 0 - )) != CR_SUCCESS) - { - PhDereferenceObject(string); - string = PhCreateStringEx(NULL, bufferSize); + if (NT_SUCCESS(D3DKMTQueryStatistics(&queryStatistics))) + { + ULONG64 bytesCommitted; - result = CM_Get_DevNode_Property( - deviceInstanceHandle, - &DEVPKEY_Device_DeviceDesc, - &devicePropertyType, - (PBYTE)string->Buffer, - &bufferSize, - 0 - ); - } + if (WindowsVersion >= WINDOWS_8) + bytesCommitted = queryStatistics.QueryResult.ProcessSegmentInformation.BytesCommitted; + else + bytesCommitted = queryStatistics.QueryResult.ProcessSegmentInformation.BytesCommitted; - if (result != CR_SUCCESS) - { - PhDereferenceObject(string); - return NULL; + if (RtlCheckBit(&gpuAdapter->ApertureBitMap, j)) + sharedUsage += bytesCommitted; + else + dedicatedUsage += bytesCommitted; + } + } } - PhTrimToNullTerminatorString(string); - - return string; + Block->GpuDedicatedUsage = dedicatedUsage; + Block->GpuSharedUsage = sharedUsage; } -VOID EtpUpdateSegmentInformation( - _In_opt_ PET_PROCESS_BLOCK Block +VOID EtpUpdateSystemSegmentInformation( + VOID ) { - ULONG i; - ULONG j; PETP_GPU_ADAPTER gpuAdapter; D3DKMT_QUERYSTATISTICS queryStatistics; ULONG64 dedicatedUsage; ULONG64 sharedUsage; - if (Block && !Block->ProcessItem->QueryHandle) - return; - dedicatedUsage = 0; sharedUsage = 0; - for (i = 0; i < EtpGpuAdapterList->Count; i++) + for (ULONG i = 0; i < EtpGpuAdapterList->Count; i++) { gpuAdapter = EtpGpuAdapterList->Items[i]; - for (j = 0; j < gpuAdapter->SegmentCount; j++) + for (ULONG j = 0; j < gpuAdapter->SegmentCount; j++) { memset(&queryStatistics, 0, sizeof(D3DKMT_QUERYSTATISTICS)); - - if (Block) - queryStatistics.Type = D3DKMT_QUERYSTATISTICS_PROCESS_SEGMENT; - else - queryStatistics.Type = D3DKMT_QUERYSTATISTICS_SEGMENT; - + queryStatistics.Type = D3DKMT_QUERYSTATISTICS_SEGMENT; queryStatistics.AdapterLuid = gpuAdapter->AdapterLuid; - - if (Block) - { - queryStatistics.hProcess = Block->ProcessItem->QueryHandle; - queryStatistics.QueryProcessSegment.SegmentId = j; - } - else - { - queryStatistics.QuerySegment.SegmentId = j; - } + queryStatistics.QuerySegment.SegmentId = j; if (NT_SUCCESS(D3DKMTQueryStatistics(&queryStatistics))) { - if (Block) - { - ULONG64 bytesCommitted; - - if (WindowsVersion >= WINDOWS_8) - { - bytesCommitted = queryStatistics.QueryResult.ProcessSegmentInformation.BytesCommitted; - } - else - { - bytesCommitted = (ULONG)queryStatistics.QueryResult.ProcessSegmentInformation.BytesCommitted; - } + ULONG64 bytesCommitted; - if (RtlCheckBit(&gpuAdapter->ApertureBitMap, j)) - sharedUsage += bytesCommitted; - else - dedicatedUsage += bytesCommitted; - } + if (WindowsVersion >= WINDOWS_8) + bytesCommitted = queryStatistics.QueryResult.SegmentInformation.BytesResident; else - { - ULONG64 bytesCommitted; - - if (WindowsVersion >= WINDOWS_8) - { - bytesCommitted = queryStatistics.QueryResult.SegmentInformation.BytesResident; - // TODO: SegmentInformation.CommitLimit - } - else - { - bytesCommitted = queryStatistics.QueryResult.SegmentInformationV1.BytesResident; - // TODO: SegmentInformationV1.CommitLimit - } + bytesCommitted = queryStatistics.QueryResult.SegmentInformationV1.BytesResident; - if (RtlCheckBit(&gpuAdapter->ApertureBitMap, j)) - sharedUsage += bytesCommitted; - else - dedicatedUsage += bytesCommitted; - } + if (RtlCheckBit(&gpuAdapter->ApertureBitMap, j)) + sharedUsage += bytesCommitted; + else + dedicatedUsage += bytesCommitted; } } } - if (Block) - { - Block->GpuDedicatedUsage = dedicatedUsage; - Block->GpuSharedUsage = sharedUsage; - } - else - { - EtGpuDedicatedUsage = dedicatedUsage; - EtGpuSharedUsage = sharedUsage; - } + EtGpuDedicatedUsage = dedicatedUsage; + EtGpuSharedUsage = sharedUsage; } -VOID EtpUpdateNodeInformation( - _In_opt_ PET_PROCESS_BLOCK Block +VOID EtpUpdateProcessNodeInformation( + _In_ PET_PROCESS_BLOCK Block ) { - ULONG i; - ULONG j; PETP_GPU_ADAPTER gpuAdapter; D3DKMT_QUERYSTATISTICS queryStatistics; ULONG64 totalRunningTime; - ULONG64 systemRunningTime; - if (Block && !Block->ProcessItem->QueryHandle) + if (!Block->ProcessItem->QueryHandle) return; totalRunningTime = 0; - systemRunningTime = 0; - for (i = 0; i < EtpGpuAdapterList->Count; i++) + for (ULONG i = 0; i < EtpGpuAdapterList->Count; i++) { gpuAdapter = EtpGpuAdapterList->Items[i]; - for (j = 0; j < gpuAdapter->NodeCount; j++) + for (ULONG j = 0; j < gpuAdapter->NodeCount; j++) { - if (Block && !RtlCheckBit(&EtGpuNodeBitMap, gpuAdapter->FirstNodeIndex + j)) - continue; - memset(&queryStatistics, 0, sizeof(D3DKMT_QUERYSTATISTICS)); - - if (Block) - queryStatistics.Type = D3DKMT_QUERYSTATISTICS_PROCESS_NODE; - else - queryStatistics.Type = D3DKMT_QUERYSTATISTICS_NODE; - + queryStatistics.Type = D3DKMT_QUERYSTATISTICS_PROCESS_NODE; queryStatistics.AdapterLuid = gpuAdapter->AdapterLuid; + queryStatistics.ProcessHandle = Block->ProcessItem->QueryHandle; + queryStatistics.QueryProcessNode.NodeId = j; - if (Block) - { - queryStatistics.hProcess = Block->ProcessItem->QueryHandle; - queryStatistics.QueryProcessNode.NodeId = j; - } - else + if (NT_SUCCESS(D3DKMTQueryStatistics(&queryStatistics))) { - queryStatistics.QueryNode.NodeId = j; + //ULONG64 runningTime; + //runningTime = queryStatistics.QueryResult.ProcessNodeInformation.RunningTime.QuadPart; + //PhUpdateDelta(&Block->GpuTotalRunningTimeDelta[j], runningTime); + + totalRunningTime += queryStatistics.QueryResult.ProcessNodeInformation.RunningTime.QuadPart; } + } + } + + PhUpdateDelta(&Block->GpuRunningTimeDelta, totalRunningTime); +} + +VOID EtpUpdateSystemNodeInformation( + VOID + ) +{ + PETP_GPU_ADAPTER gpuAdapter; + D3DKMT_QUERYSTATISTICS queryStatistics; + LARGE_INTEGER performanceCounter; + + for (ULONG i = 0; i < EtpGpuAdapterList->Count; i++) + { + gpuAdapter = EtpGpuAdapterList->Items[i]; + + for (ULONG j = 0; j < gpuAdapter->NodeCount; j++) + { + memset(&queryStatistics, 0, sizeof(D3DKMT_QUERYSTATISTICS)); + queryStatistics.Type = D3DKMT_QUERYSTATISTICS_NODE; + queryStatistics.AdapterLuid = gpuAdapter->AdapterLuid; + queryStatistics.QueryNode.NodeId = j; if (NT_SUCCESS(D3DKMTQueryStatistics(&queryStatistics))) { - if (Block) - { - totalRunningTime += queryStatistics.QueryResult.ProcessNodeInformation.RunningTime.QuadPart; - } - else - { - ULONG nodeIndex; + ULONG64 runningTime; + //ULONG64 systemRunningTime; - nodeIndex = gpuAdapter->FirstNodeIndex + j; + runningTime = queryStatistics.QueryResult.NodeInformation.GlobalInformation.RunningTime.QuadPart; + //systemRunningTime = queryStatistics.QueryResult.NodeInformation.SystemInformation.RunningTime.QuadPart; - PhUpdateDelta(&EtGpuNodesTotalRunningTimeDelta[nodeIndex], queryStatistics.QueryResult.NodeInformation.GlobalInformation.RunningTime.QuadPart); - - if (RtlCheckBit(&EtGpuNodeBitMap, gpuAdapter->FirstNodeIndex + j)) - { - totalRunningTime += queryStatistics.QueryResult.NodeInformation.GlobalInformation.RunningTime.QuadPart; - systemRunningTime += queryStatistics.QueryResult.NodeInformation.SystemInformation.RunningTime.QuadPart; - } - } + PhUpdateDelta(&EtGpuNodesTotalRunningTimeDelta[gpuAdapter->FirstNodeIndex + j], runningTime); } } } - if (Block) - { - PhUpdateDelta(&Block->GpuRunningTimeDelta, totalRunningTime); - } - else - { - LARGE_INTEGER performanceCounter; - - NtQueryPerformanceCounter(&performanceCounter, &EtClockTotalRunningTimeFrequency); - PhUpdateDelta(&EtClockTotalRunningTimeDelta, performanceCounter.QuadPart); - PhUpdateDelta(&EtGpuTotalRunningTimeDelta, totalRunningTime); - PhUpdateDelta(&EtGpuSystemRunningTimeDelta, systemRunningTime); - } + NtQueryPerformanceCounter(&performanceCounter, &EtClockTotalRunningTimeFrequency); + PhUpdateDelta(&EtClockTotalRunningTimeDelta, performanceCounter.QuadPart); } VOID NTAPI EtGpuProcessesUpdatedCallback( @@ -560,43 +889,40 @@ VOID NTAPI EtGpuProcessesUpdatedCallback( static ULONG runCount = 0; // MUST keep in sync with runCount in process provider DOUBLE elapsedTime; // total GPU node elapsed time in micro-seconds + FLOAT tempGpuUsage; ULONG i; PLIST_ENTRY listEntry; FLOAT maxNodeValue = 0; PET_PROCESS_BLOCK maxNodeBlock = NULL; // Update global statistics. + EtpUpdateSystemSegmentInformation(); + EtpUpdateSystemNodeInformation(); - EtpUpdateSegmentInformation(NULL); - EtpUpdateNodeInformation(NULL); - + // Update global gpu usage. + tempGpuUsage = 0; elapsedTime = (DOUBLE)EtClockTotalRunningTimeDelta.Delta * 10000000 / EtClockTotalRunningTimeFrequency.QuadPart; if (elapsedTime != 0) - EtGpuNodeUsage = (FLOAT)(EtGpuTotalRunningTimeDelta.Delta / (elapsedTime * EtGpuNodeBitMapBitsSet)); - else - EtGpuNodeUsage = 0; - - if (EtGpuNodeUsage > 1) - EtGpuNodeUsage = 1; - - // Do the update of the node bitmap if needed. - if (EtGpuNewNodeBitMapBuffer) { - PULONG newBuffer; + for (i = 0; i < EtGpuTotalNodeCount; i++) + { + FLOAT usage; - newBuffer = _InterlockedExchangePointer(&EtGpuNewNodeBitMapBuffer, NULL); + usage = (FLOAT)(EtGpuNodesTotalRunningTimeDelta[i].Delta / elapsedTime); - if (newBuffer) - { - PhFree(EtGpuNodeBitMap.Buffer); - EtGpuNodeBitMap.Buffer = newBuffer; - EtGpuNodeBitMapBuffer = newBuffer; - EtGpuNodeBitMapBitsSet = RtlNumberOfSetBits(&EtGpuNodeBitMap); - EtSaveGpuMonitorSettings(); + if (usage > tempGpuUsage) + { + tempGpuUsage = usage; + } } + + if (tempGpuUsage > 1) + tempGpuUsage = 1; } + EtGpuNodeUsage = tempGpuUsage; + // Update per-process statistics. // Note: no lock is needed because we only ever modify the list on this same thread. @@ -608,12 +934,26 @@ VOID NTAPI EtGpuProcessesUpdatedCallback( block = CONTAINING_RECORD(listEntry, ET_PROCESS_BLOCK, ListEntry); - EtpUpdateSegmentInformation(block); - EtpUpdateNodeInformation(block); + EtpUpdateProcessSegmentInformation(block); + EtpUpdateProcessNodeInformation(block); if (elapsedTime != 0) { - block->GpuNodeUsage = (FLOAT)(block->GpuRunningTimeDelta.Delta / (elapsedTime * EtGpuNodeBitMapBitsSet)); + block->GpuNodeUsage = (FLOAT)(block->GpuRunningTimeDelta.Delta / elapsedTime); + + // HACK + if (block->GpuNodeUsage > EtGpuNodeUsage) + block->GpuNodeUsage = EtGpuNodeUsage; + + //for (i = 0; i < EtGpuTotalNodeCount; i++) + //{ + // FLOAT usage = (FLOAT)(block->GpuTotalRunningTimeDelta[i].Delta / elapsedTime); + // + // if (usage > block->GpuNodeUsage) + // { + // block->GpuNodeUsage = usage; + // } + //} if (block->GpuNodeUsage > 1) block->GpuNodeUsage = 1; @@ -636,16 +976,24 @@ VOID NTAPI EtGpuProcessesUpdatedCallback( PhAddItemCircularBuffer_ULONG(&EtGpuDedicatedHistory, (ULONG)(EtGpuDedicatedUsage / PAGE_SIZE)); PhAddItemCircularBuffer_ULONG(&EtGpuSharedHistory, (ULONG)(EtGpuSharedUsage / PAGE_SIZE)); - for (i = 0; i < EtGpuTotalNodeCount; i++) + if (elapsedTime != 0) { - FLOAT usage; + for (i = 0; i < EtGpuTotalNodeCount; i++) + { + FLOAT usage; - usage = (FLOAT)(EtGpuNodesTotalRunningTimeDelta[i].Delta / elapsedTime); + usage = (FLOAT)(EtGpuNodesTotalRunningTimeDelta[i].Delta / elapsedTime); - if (usage > 1) - usage = 1; + if (usage > 1) + usage = 1; - PhAddItemCircularBuffer_FLOAT(&EtGpuNodesHistory[i], usage); + PhAddItemCircularBuffer_FLOAT(&EtGpuNodesHistory[i], usage); + } + } + else + { + for (i = 0; i < EtGpuTotalNodeCount; i++) + PhAddItemCircularBuffer_FLOAT(&EtGpuNodesHistory[i], 0); } if (maxNodeBlock) @@ -664,17 +1012,6 @@ VOID NTAPI EtGpuProcessesUpdatedCallback( runCount++; } -VOID EtSaveGpuMonitorSettings( - VOID - ) -{ - PPH_STRING string; - - string = PhBufferToHexString((PUCHAR)EtGpuNodeBitMapBuffer, BYTES_NEEDED_FOR_BITS(EtGpuTotalNodeCount)); - PhSetStringSetting2(SETTING_NAME_GPU_NODE_BITMAP, &string->sr); - PhDereferenceObject(string); -} - ULONG EtGetGpuAdapterCount( VOID ) @@ -700,6 +1037,24 @@ ULONG EtGetGpuAdapterIndexFromNodeIndex( return -1; } +PPH_STRING EtGetGpuAdapterNodeDescription( + _In_ ULONG Index, + _In_ ULONG NodeIndex + ) +{ + PETP_GPU_ADAPTER gpuAdapter; + + if (Index >= EtpGpuAdapterList->Count) + return NULL; + + gpuAdapter = EtpGpuAdapterList->Items[Index]; + + if (!gpuAdapter->NodeNameList) + return NULL; + + return gpuAdapter->NodeNameList->Items[NodeIndex - gpuAdapter->FirstNodeIndex]; +} + PPH_STRING EtGetGpuAdapterDescription( _In_ ULONG Index ) @@ -722,37 +1077,11 @@ PPH_STRING EtGetGpuAdapterDescription( } } -VOID EtAllocateGpuNodeBitMap( - _Out_ PRTL_BITMAP BitMap - ) -{ - SIZE_T numberOfBytes; - - numberOfBytes = BYTES_NEEDED_FOR_BITS(EtGpuTotalNodeCount); - - BitMap->Buffer = PhAllocate(numberOfBytes); - BitMap->SizeOfBitMap = EtGpuTotalNodeCount; - memset(BitMap->Buffer, 0, numberOfBytes); -} - -VOID EtUpdateGpuNodeBitMap( - _In_ PRTL_BITMAP NewBitMap - ) -{ - PULONG buffer; - - buffer = _InterlockedExchangePointer(&EtGpuNewNodeBitMapBuffer, NewBitMap->Buffer); - - if (buffer) - PhFree(buffer); -} - VOID EtQueryProcessGpuStatistics( _In_ HANDLE ProcessHandle, _Out_ PET_PROCESS_GPU_STATISTICS Statistics ) { - NTSTATUS status; ULONG i; ULONG j; PETP_GPU_ADAPTER gpuAdapter; @@ -772,21 +1101,17 @@ VOID EtQueryProcessGpuStatistics( memset(&queryStatistics, 0, sizeof(D3DKMT_QUERYSTATISTICS)); queryStatistics.Type = D3DKMT_QUERYSTATISTICS_PROCESS_SEGMENT; queryStatistics.AdapterLuid = gpuAdapter->AdapterLuid; - queryStatistics.hProcess = ProcessHandle; + queryStatistics.ProcessHandle = ProcessHandle; queryStatistics.QueryProcessSegment.SegmentId = j; - if (NT_SUCCESS(status = D3DKMTQueryStatistics(&queryStatistics))) + if (NT_SUCCESS(D3DKMTQueryStatistics(&queryStatistics))) { ULONG64 bytesCommitted; if (WindowsVersion >= WINDOWS_8) - { bytesCommitted = queryStatistics.QueryResult.ProcessSegmentInformation.BytesCommitted; - } else - { - bytesCommitted = (ULONG)queryStatistics.QueryResult.ProcessSegmentInformation.BytesCommitted; - } + bytesCommitted = queryStatistics.QueryResult.ProcessSegmentInformation.BytesCommitted; if (RtlCheckBit(&gpuAdapter->ApertureBitMap, j)) Statistics->SharedCommitted += bytesCommitted; @@ -800,7 +1125,7 @@ VOID EtQueryProcessGpuStatistics( memset(&queryStatistics, 0, sizeof(D3DKMT_QUERYSTATISTICS)); queryStatistics.Type = D3DKMT_QUERYSTATISTICS_PROCESS_NODE; queryStatistics.AdapterLuid = gpuAdapter->AdapterLuid; - queryStatistics.hProcess = ProcessHandle; + queryStatistics.ProcessHandle = ProcessHandle; queryStatistics.QueryProcessNode.NodeId = j; if (NT_SUCCESS(D3DKMTQueryStatistics(&queryStatistics))) @@ -813,7 +1138,7 @@ VOID EtQueryProcessGpuStatistics( memset(&queryStatistics, 0, sizeof(D3DKMT_QUERYSTATISTICS)); queryStatistics.Type = D3DKMT_QUERYSTATISTICS_PROCESS; queryStatistics.AdapterLuid = gpuAdapter->AdapterLuid; - queryStatistics.hProcess = ProcessHandle; + queryStatistics.ProcessHandle = ProcessHandle; if (NT_SUCCESS(D3DKMTQueryStatistics(&queryStatistics))) { diff --git a/plugins/ExtendedTools/gpumon.h b/plugins/ExtendedTools/gpumon.h index 0ec6f15f23c0..825d2795a0e7 100644 --- a/plugins/ExtendedTools/gpumon.h +++ b/plugins/ExtendedTools/gpumon.h @@ -10,12 +10,13 @@ typedef struct _ETP_GPU_ADAPTER { LUID AdapterLuid; - PPH_STRING Description; ULONG SegmentCount; ULONG NodeCount; ULONG FirstNodeIndex; - BOOLEAN HasActivity; + PPH_STRING DeviceInterface; + PPH_STRING Description; + PPH_LIST NodeNameList; RTL_BITMAP ApertureBitMap; ULONG ApertureBitMapBuffer[1]; @@ -31,8 +32,13 @@ PETP_GPU_ADAPTER EtpAllocateGpuAdapter( _In_ ULONG NumberOfSegments ); -PPH_STRING EtpQueryDeviceDescription( - _In_ PWSTR DeviceInterface +BOOLEAN EtQueryDeviceProperties( + _In_ PWSTR DeviceInterface, + _Out_ PPH_STRING *Description, + _Out_ PPH_STRING *DriverDate, + _Out_ PPH_STRING *DriverVersion, + _Out_ PPH_STRING *LocationInfo, + _Out_ ULONG64 *InstalledMemory ); VOID NTAPI EtGpuProcessesUpdatedCallback( diff --git a/plugins/ExtendedTools/gpunodes.c b/plugins/ExtendedTools/gpunodes.c index 59e15005c172..f2f3891e7bb2 100644 --- a/plugins/ExtendedTools/gpunodes.c +++ b/plugins/ExtendedTools/gpunodes.c @@ -3,6 +3,7 @@ * GPU nodes window * * Copyright (C) 2011-2015 wj32 + * Copyright (C) 2018 dmex * * This file is part of Process Hacker. * @@ -21,9 +22,11 @@ */ #include "exttools.h" +#include #define GRAPH_PADDING 5 -#define CHECKBOX_PADDING 3 +static RECT NormalGraphTextMargin = { 5, 5, 5, 5 }; +static RECT NormalGraphTextPadding = { 3, 3, 3, 3 }; INT_PTR CALLBACK EtpGpuNodesDlgProc( _In_ HWND hwndDlg, @@ -32,79 +35,86 @@ INT_PTR CALLBACK EtpGpuNodesDlgProc( _In_ LPARAM lParam ); -static HWND WindowHandle; static RECT MinimumSize; static PH_LAYOUT_MANAGER LayoutManager; static RECT LayoutMargin; static HWND *GraphHandle; -static HWND *CheckBoxHandle; static PPH_GRAPH_STATE GraphState; -static PPH_SYSINFO_PARAMETERS SysInfoParameters; static PH_CALLBACK_REGISTRATION ProcessesUpdatedCallbackRegistration; -VOID EtShowGpuNodesDialog( - _In_ HWND ParentWindowHandle, - _In_ PPH_SYSINFO_PARAMETERS Parameters +static HANDLE EtGpuNodesThreadHandle = NULL; +static HWND EtGpuNodesWindowHandle = NULL; +static PH_EVENT EtGpuNodesInitializedEvent = PH_EVENT_INIT; + +NTSTATUS EtpGpuNodesDialogThreadStart( + _In_ PVOID Parameter ) { - SysInfoParameters = Parameters; - DialogBox( + BOOL result; + MSG message; + PH_AUTO_POOL autoPool; + + PhInitializeAutoPool(&autoPool); + + EtGpuNodesWindowHandle = CreateDialog( PluginInstance->DllBase, MAKEINTRESOURCE(IDD_GPUNODES), - ParentWindowHandle, + NULL, EtpGpuNodesDlgProc ); -} -static VOID ProcessesUpdatedCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - PostMessage(WindowHandle, UPDATE_MSG, 0, 0); -} + PhSetEvent(&EtGpuNodesInitializedEvent); -VOID EtpLoadNodeBitMap( - _In_ HWND WindowHandle - ) -{ - ULONG i; - BOOLEAN allSelected = TRUE; - - for (i = 0; i < EtGpuTotalNodeCount; i++) + while (result = GetMessage(&message, NULL, 0, 0)) { - BOOLEAN nodeEnabled = RtlCheckBit(&EtGpuNodeBitMap, i); + if (result == -1) + break; - Button_SetCheck(CheckBoxHandle[i], nodeEnabled ? BST_CHECKED : BST_UNCHECKED); + if (!IsDialogMessage(EtGpuNodesWindowHandle, &message)) + { + TranslateMessage(&message); + DispatchMessage(&message); + } - if (!nodeEnabled) allSelected = FALSE; + PhDrainAutoPool(&autoPool); } - if (allSelected) - { - Button_SetCheck(GetDlgItem(WindowHandle, IDC_SELECTALL), BST_CHECKED); - } + PhDeleteAutoPool(&autoPool); + PhResetEvent(&EtGpuNodesInitializedEvent); + + if (EtGpuNodesThreadHandle) + NtClose(EtGpuNodesThreadHandle); + + EtGpuNodesThreadHandle = NULL; + EtGpuNodesWindowHandle = NULL; + + return STATUS_SUCCESS; } -VOID EtpSaveNodeBitMap( - VOID +VOID EtShowGpuNodesDialog( + _In_ HWND ParentWindowHandle ) { - RTL_BITMAP newBitMap; - ULONG i; - - EtAllocateGpuNodeBitMap(&newBitMap); - - for (i = 0; i < EtGpuTotalNodeCount; i++) + if (!EtGpuNodesThreadHandle) { - if (Button_GetCheck(CheckBoxHandle[i]) == BST_CHECKED) - RtlSetBits(&newBitMap, i, 1); + if (!(EtGpuNodesThreadHandle = PhCreateThread(0, EtpGpuNodesDialogThreadStart, ParentWindowHandle))) + { + PhShowStatus(PhMainWndHandle, L"Unable to create the window.", 0, GetLastError()); + return; + } + + PhWaitForEvent(&EtGpuNodesInitializedEvent, NULL); } - if (RtlNumberOfSetBits(&newBitMap) == 0) - RtlSetBits(&newBitMap, 0, 1); + PostMessage(EtGpuNodesWindowHandle, ET_WM_SHOWDIALOG, 0, 0); +} - EtUpdateGpuNodeBitMap(&newBitMap); +static VOID ProcessesUpdatedCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + PostMessage((HWND)Context, ET_WM_UPDATE, 0, 0); } INT_PTR CALLBACK EtpGpuNodesDlgProc( @@ -119,33 +129,21 @@ INT_PTR CALLBACK EtpGpuNodesDlgProc( case WM_INITDIALOG: { ULONG i; - HFONT font; - PPH_STRING nodeString; - RECT labelRect; - RECT tempRect; ULONG numberOfRows; ULONG numberOfColumns; - WindowHandle = hwndDlg; - SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhInstanceHandle, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhInstanceHandle, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); PhInitializeLayoutManager(&LayoutManager, hwndDlg); - PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDC_SELECTALL), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDOK), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); LayoutMargin = PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDC_LAYOUT), NULL, PH_ANCHOR_ALL)->Margin; GraphHandle = PhAllocate(sizeof(HWND) * EtGpuTotalNodeCount); - CheckBoxHandle = PhAllocate(sizeof(HWND) * EtGpuTotalNodeCount); GraphState = PhAllocate(sizeof(PH_GRAPH_STATE) * EtGpuTotalNodeCount); - font = (HFONT)SendMessage(hwndDlg, WM_GETFONT, 0, 0); - for (i = 0; i < EtGpuTotalNodeCount; i++) { - nodeString = PhFormatString(L"Node %lu", i); - GraphHandle[i] = CreateWindow( PH_GRAPH_CLASSNAME, NULL, @@ -160,23 +158,7 @@ INT_PTR CALLBACK EtpGpuNodesDlgProc( NULL ); Graph_SetTooltip(GraphHandle[i], TRUE); - CheckBoxHandle[i] = CreateWindow( - WC_BUTTON, - nodeString->Buffer, - WS_VISIBLE | WS_CHILD | BS_AUTOCHECKBOX, - 0, - 0, - 3, - 3, - hwndDlg, - NULL, - NULL, - NULL - ); - SendMessage(CheckBoxHandle[i], WM_SETFONT, (WPARAM)font, FALSE); PhInitializeGraphState(&GraphState[i]); - - PhDereferenceObject(nodeString); } // Calculate the minimum size. @@ -192,55 +174,47 @@ INT_PTR CALLBACK EtpGpuNodesDlgProc( MinimumSize.right += (MinimumSize.right + GRAPH_PADDING) * numberOfColumns; MinimumSize.bottom += (MinimumSize.bottom + GRAPH_PADDING) * numberOfRows; - GetWindowRect(GetDlgItem(hwndDlg, IDC_INSTRUCTION), &labelRect); - MapWindowPoints(NULL, hwndDlg, (POINT *)&labelRect, 2); - labelRect.right += GetSystemMetrics(SM_CXFRAME) * 2; - - tempRect.left = 0; - tempRect.top = 0; - tempRect.right = 7; - tempRect.bottom = 0; - MapDialogRect(hwndDlg, &tempRect); - labelRect.right += tempRect.right; - - if (MinimumSize.right < labelRect.right) - MinimumSize.right = labelRect.right; - SetWindowPos(hwndDlg, NULL, 0, 0, MinimumSize.right, MinimumSize.bottom, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER); // Note: This dialog must be centered after all other graphs and controls have been added. - PhCenterWindow(hwndDlg, GetParent(hwndDlg)); - - EtpLoadNodeBitMap(hwndDlg); - - PhRegisterCallback(&PhProcessesUpdatedEvent, ProcessesUpdatedCallback, NULL, &ProcessesUpdatedCallbackRegistration); + if (PhGetIntegerPairSetting(SETTING_NAME_GPU_NODES_WINDOW_POSITION).X != 0) + PhLoadWindowPlacementFromSetting(SETTING_NAME_GPU_NODES_WINDOW_POSITION, SETTING_NAME_GPU_NODES_WINDOW_SIZE, hwndDlg); + else + PhCenterWindow(hwndDlg, GetParent(hwndDlg)); + + PhRegisterCallback( + &PhProcessesUpdatedEvent, + ProcessesUpdatedCallback, + hwndDlg, + &ProcessesUpdatedCallbackRegistration + ); + + EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); } break; case WM_DESTROY: { - ULONG i; - - EtpSaveNodeBitMap(); + PhSaveWindowPlacementToSetting(SETTING_NAME_GPU_NODES_WINDOW_POSITION, SETTING_NAME_GPU_NODES_WINDOW_SIZE, hwndDlg); PhUnregisterCallback(&PhProcessesUpdatedEvent, &ProcessesUpdatedCallbackRegistration); - for (i = 0; i < EtGpuTotalNodeCount; i++) + for (ULONG i = 0; i < EtGpuTotalNodeCount; i++) { PhDeleteGraphState(&GraphState[i]); } PhFree(GraphHandle); - PhFree(CheckBoxHandle); PhFree(GraphState); PhDeleteLayoutManager(&LayoutManager); + + PostQuitMessage(0); } break; case WM_SIZE: { HDWP deferHandle; RECT clientRect; - RECT checkBoxRect; ULONG numberOfRows = (ULONG)sqrt(EtGpuTotalNodeCount); ULONG numberOfColumns = (EtGpuTotalNodeCount + numberOfRows - 1) / numberOfRows; ULONG numberOfYPaddings = numberOfRows - 1; @@ -253,10 +227,9 @@ INT_PTR CALLBACK EtpGpuNodesDlgProc( PhLayoutManagerLayout(&LayoutManager); - deferHandle = BeginDeferWindowPos(EtGpuTotalNodeCount * 2); + deferHandle = BeginDeferWindowPos(EtGpuTotalNodeCount); GetClientRect(hwndDlg, &clientRect); - GetClientRect(GetDlgItem(hwndDlg, IDC_EXAMPLE), &checkBoxRect); cellHeight = (clientRect.bottom - LayoutMargin.top - LayoutMargin.bottom - GRAPH_PADDING * numberOfYPaddings) / numberOfRows; y = LayoutMargin.top; i = 0; @@ -287,17 +260,7 @@ INT_PTR CALLBACK EtpGpuNodesDlgProc( x, y, cellWidth, - cellHeight - checkBoxRect.bottom - CHECKBOX_PADDING, - SWP_NOACTIVATE | SWP_NOZORDER - ); - deferHandle = DeferWindowPos( - deferHandle, - CheckBoxHandle[i], - NULL, - x, - y + cellHeight - checkBoxRect.bottom, - cellWidth, - checkBoxRect.bottom, + cellHeight, SWP_NOACTIVATE | SWP_NOZORDER ); i++; @@ -323,17 +286,7 @@ INT_PTR CALLBACK EtpGpuNodesDlgProc( case IDCANCEL: case IDOK: { - EndDialog(hwndDlg, IDOK); - } - break; - case IDC_SELECTALL: - { - BOOLEAN selectAll = Button_GetCheck(GetDlgItem(hwndDlg, IDC_SELECTALL)) == BST_CHECKED; - - for (ULONG i = 0; i < EtGpuTotalNodeCount; i++) - { - Button_SetCheck(CheckBoxHandle[i], selectAll ? BST_CHECKED : BST_UNCHECKED); - } + DestroyWindow(hwndDlg); } break; } @@ -352,12 +305,51 @@ INT_PTR CALLBACK EtpGpuNodesDlgProc( PPH_GRAPH_DRAW_INFO drawInfo = getDrawInfo->DrawInfo; drawInfo->Flags = PH_GRAPH_USE_GRID_X | PH_GRAPH_USE_GRID_Y; - SysInfoParameters->ColorSetupFunction(drawInfo, PhGetIntegerSetting(L"ColorCpuKernel"), 0); + PhSiSetColorsGraphDrawInfo(drawInfo, PhGetIntegerSetting(L"ColorCpuKernel"), 0); for (i = 0; i < EtGpuTotalNodeCount; i++) { if (header->hwndFrom == GraphHandle[i]) { + if (PhGetIntegerSetting(L"GraphShowText")) + { + HDC hdc; + FLOAT gpu; + ULONG adapterIndex; + PPH_STRING engineName = NULL; + + gpu = PhGetItemCircularBuffer_FLOAT(&EtGpuNodesHistory[i], 0); + + if ((adapterIndex = EtGetGpuAdapterIndexFromNodeIndex(i)) != ULONG_MAX) + engineName = EtGetGpuAdapterNodeDescription(adapterIndex, i); + + if (!PhIsNullOrEmptyString(engineName)) + { + PhMoveReference(&GraphState[i].Text, PhFormatString( + L"%.2f%% (%s)", + gpu * 100, + engineName->Buffer + )); + } + else + { + PhMoveReference(&GraphState[i].Text, PhFormatString( + L"%.2f%% (Node %lu)", + gpu * 100, + i + )); + } + + hdc = Graph_GetBufferedContext(GraphHandle[i]); + SelectObject(hdc, PhApplicationFont); + PhSetGraphText(hdc, drawInfo, &GraphState[i].Text->sr, + &NormalGraphTextMargin, &NormalGraphTextPadding, PH_ALIGN_TOP | PH_ALIGN_LEFT); + } + else + { + drawInfo->Text.Buffer = NULL; + } + PhGraphStateGetDrawInfo( &GraphState[i], getDrawInfo, @@ -389,13 +381,15 @@ INT_PTR CALLBACK EtpGpuNodesDlgProc( { FLOAT gpu; ULONG adapterIndex; + PPH_STRING adapterEngineName = NULL; PPH_STRING adapterDescription; gpu = PhGetItemCircularBuffer_FLOAT(&EtGpuNodesHistory[i], getTooltipText->Index); adapterIndex = EtGetGpuAdapterIndexFromNodeIndex(i); - if (adapterIndex != -1) + if (adapterIndex != ULONG_MAX) { + adapterEngineName = EtGetGpuAdapterNodeDescription(adapterIndex, i); adapterDescription = EtGetGpuAdapterDescription(adapterIndex); if (adapterDescription && adapterDescription->Length == 0) @@ -409,13 +403,29 @@ INT_PTR CALLBACK EtpGpuNodesDlgProc( adapterDescription = PhCreateString(L"Unknown Adapter"); } - PhMoveReference(&GraphState[i].TooltipText, PhFormatString( - L"Node %lu on %s\n%.2f%%\n%s", - i, - adapterDescription->Buffer, - gpu * 100, - ((PPH_STRING)PH_AUTO(PhGetStatisticsTimeString(NULL, getTooltipText->Index)))->Buffer - )); + if (adapterEngineName) + { + PhMoveReference(&GraphState[i].TooltipText, PhFormatString( + L"Node %lu (%s) on %s\n%.2f%%\n%s", + i, + adapterEngineName->Buffer, + adapterDescription->Buffer, + gpu * 100, + ((PPH_STRING)PH_AUTO(PhGetStatisticsTimeString(NULL, getTooltipText->Index)))->Buffer + )); + } + else + { + PhMoveReference(&GraphState[i].TooltipText, PhFormatString( + L"Node %lu on %s\n%.2f%%\n%s", + i, + adapterDescription->Buffer, + gpu * 100, + ((PPH_STRING)PH_AUTO(PhGetStatisticsTimeString(NULL, getTooltipText->Index)))->Buffer + )); + } + + PhDereferenceObject(adapterDescription); } @@ -430,11 +440,19 @@ INT_PTR CALLBACK EtpGpuNodesDlgProc( } } break; - case UPDATE_MSG: + case ET_WM_SHOWDIALOG: { - ULONG i; + if (IsMinimized(hwndDlg)) + ShowWindow(hwndDlg, SW_RESTORE); + else + ShowWindow(hwndDlg, SW_SHOW); - for (i = 0; i < EtGpuTotalNodeCount; i++) + SetForegroundWindow(hwndDlg); + } + break; + case ET_WM_UPDATE: + { + for (ULONG i = 0; i < EtGpuTotalNodeCount; i++) { GraphState[i].Valid = FALSE; GraphState[i].TooltipIndex = -1; diff --git a/plugins/ExtendedTools/gpuprprp.c b/plugins/ExtendedTools/gpuprprp.c index 78bfd0a0004d..bfd8decd0229 100644 --- a/plugins/ExtendedTools/gpuprprp.c +++ b/plugins/ExtendedTools/gpuprprp.c @@ -456,7 +456,7 @@ VOID NTAPI ProcessesUpdatedHandler( if (context->WindowHandle) { - PostMessage(context->WindowHandle, UPDATE_MSG, 0, 0); + PostMessage(context->WindowHandle, ET_WM_UPDATE, 0, 0); } } @@ -863,7 +863,7 @@ INT_PTR CALLBACK EtpGpuPageDlgProc( } } break; - case UPDATE_MSG: + case ET_WM_UPDATE: { if (context->Enabled) { diff --git a/plugins/ExtendedTools/gpusys.c b/plugins/ExtendedTools/gpusys.c index fbcca7458959..9289cd843e34 100644 --- a/plugins/ExtendedTools/gpusys.c +++ b/plugins/ExtendedTools/gpusys.c @@ -120,7 +120,17 @@ BOOLEAN EtpGpuSysInfoSectionCallback( PPH_SYSINFO_DRAW_PANEL drawPanel = Parameter1; drawPanel->Title = PhCreateString(L"GPU"); - drawPanel->SubTitle = PhFormatString(L"%.2f%%", EtGpuNodeUsage * 100); + drawPanel->SubTitle = PhFormatString( + L"%.2f%%\n%s / %s", + EtGpuNodeUsage * 100, + PhaFormatSize(EtGpuDedicatedUsage, ULONG_MAX)->Buffer, + PhaFormatSize(EtGpuDedicatedLimit, ULONG_MAX)->Buffer + ); + drawPanel->SubTitleOverflow = PhFormatString( + L"%.2f%%\n%s", + EtGpuNodeUsage * 100, + PhaFormatSize(EtGpuDedicatedUsage, ULONG_MAX)->Buffer + ); } return TRUE; } @@ -239,7 +249,10 @@ INT_PTR CALLBACK EtpGpuPanelDialogProc( switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDC_NODES: - EtShowGpuNodesDialog(GpuDialog, GpuSection->Parameters); + EtShowGpuNodesDialog(GpuDialog); + break; + case IDC_DETAILS: + EtShowGpuDetailsDialog(GpuDialog); break; } } @@ -608,21 +621,21 @@ VOID EtpUpdateGpuGraphs( ) { GpuGraphState.Valid = FALSE; - GpuGraphState.TooltipIndex = -1; + GpuGraphState.TooltipIndex = ULONG_MAX; Graph_MoveGrid(GpuGraphHandle, 1); Graph_Draw(GpuGraphHandle); Graph_UpdateTooltip(GpuGraphHandle); InvalidateRect(GpuGraphHandle, NULL, FALSE); DedicatedGraphState.Valid = FALSE; - DedicatedGraphState.TooltipIndex = -1; + DedicatedGraphState.TooltipIndex = ULONG_MAX; Graph_MoveGrid(DedicatedGraphHandle, 1); Graph_Draw(DedicatedGraphHandle); Graph_UpdateTooltip(DedicatedGraphHandle); InvalidateRect(DedicatedGraphHandle, NULL, FALSE); SharedGraphState.Valid = FALSE; - SharedGraphState.TooltipIndex = -1; + SharedGraphState.TooltipIndex = ULONG_MAX; Graph_MoveGrid(SharedGraphHandle, 1); Graph_Draw(SharedGraphHandle); Graph_UpdateTooltip(SharedGraphHandle); @@ -633,11 +646,10 @@ VOID EtpUpdateGpuPanel( VOID ) { - PhSetDialogItemText(GpuPanel, IDC_ZDEDICATEDCURRENT_V, PhaFormatSize(EtGpuDedicatedUsage, -1)->Buffer); - PhSetDialogItemText(GpuPanel, IDC_ZDEDICATEDLIMIT_V, PhaFormatSize(EtGpuDedicatedLimit, -1)->Buffer); - - PhSetDialogItemText(GpuPanel, IDC_ZSHAREDCURRENT_V, PhaFormatSize(EtGpuSharedUsage, -1)->Buffer); - PhSetDialogItemText(GpuPanel, IDC_ZSHAREDLIMIT_V, PhaFormatSize(EtGpuSharedLimit, -1)->Buffer); + PhSetDialogItemText(GpuPanel, IDC_ZDEDICATEDCURRENT_V, PhaFormatSize(EtGpuDedicatedUsage, ULONG_MAX)->Buffer); + PhSetDialogItemText(GpuPanel, IDC_ZDEDICATEDLIMIT_V, PhaFormatSize(EtGpuDedicatedLimit, ULONG_MAX)->Buffer); + PhSetDialogItemText(GpuPanel, IDC_ZSHAREDCURRENT_V, PhaFormatSize(EtGpuSharedUsage, ULONG_MAX)->Buffer); + PhSetDialogItemText(GpuPanel, IDC_ZSHAREDLIMIT_V, PhaFormatSize(EtGpuSharedLimit, ULONG_MAX)->Buffer); } PPH_PROCESS_RECORD EtpReferenceMaxNodeRecord( diff --git a/plugins/ExtendedTools/main.c b/plugins/ExtendedTools/main.c index 0f47effe4ea0..9983172076ba 100644 --- a/plugins/ExtendedTools/main.c +++ b/plugins/ExtendedTools/main.c @@ -3,6 +3,7 @@ * main program * * Copyright (C) 2010-2015 wj32 + * Copyright (C) 2018 dmex * * This file is part of Process Hacker. * @@ -46,7 +47,7 @@ PH_CALLBACK_REGISTRATION TrayIconsInitializingCallbackRegistration; PH_CALLBACK_REGISTRATION ProcessesUpdatedCallbackRegistration; PH_CALLBACK_REGISTRATION NetworkItemsUpdatedCallbackRegistration; -static HANDLE ModuleProcessId; +static HANDLE ModuleProcessId = NULL; VOID NTAPI LoadCallback( _In_opt_ PVOID Parameter, @@ -386,6 +387,11 @@ VOID EtInitializeProcessBlock( memset(Block, 0, sizeof(ET_PROCESS_BLOCK)); Block->ProcessItem = ProcessItem; PhInitializeQueuedLock(&Block->TextCacheLock); + + //Block->GpuTotalRunningTimeDelta = PhAllocate(sizeof(PH_UINT64_DELTA) * EtGpuTotalNodeCount); + //memset(Block->GpuTotalRunningTimeDelta, 0, sizeof(PH_UINT64_DELTA) * EtGpuTotalNodeCount); + //Block->GpuTotalNodesHistory = PhAllocate(sizeof(PH_CIRCULAR_BUFFER_FLOAT) * EtGpuTotalNodeCount); + InsertTailList(&EtProcessBlockListHead, &Block->ListEntry); } @@ -477,6 +483,23 @@ LOGICAL DllMain( case DLL_PROCESS_ATTACH: { PPH_PLUGIN_INFORMATION info; + PH_SETTING_CREATE settings[] = + { + { StringSettingType, SETTING_NAME_DISK_TREE_LIST_COLUMNS, L"" }, + { IntegerPairSettingType, SETTING_NAME_DISK_TREE_LIST_SORT, L"4,2" }, // 4, DescendingSortOrder + { IntegerSettingType, SETTING_NAME_ENABLE_ETW_MONITOR, L"1" }, + { IntegerSettingType, SETTING_NAME_ENABLE_GPU_MONITOR, L"1" }, + { IntegerSettingType, SETTING_NAME_ENABLE_SYSINFO_GRAPHS, L"1" }, + { StringSettingType, SETTING_NAME_GPU_NODE_BITMAP, L"01000000" }, + { IntegerSettingType, SETTING_NAME_GPU_LAST_NODE_COUNT, L"0" }, + { IntegerPairSettingType, SETTING_NAME_UNLOADED_WINDOW_POSITION, L"0,0" }, + { ScalableIntegerPairSettingType, SETTING_NAME_UNLOADED_WINDOW_SIZE, L"@96|350,270" }, + { StringSettingType, SETTING_NAME_UNLOADED_COLUMNS, L"" }, + { IntegerPairSettingType, SETTING_NAME_MODULE_SERVICES_WINDOW_POSITION, L"0,0" }, + { ScalableIntegerPairSettingType, SETTING_NAME_MODULE_SERVICES_WINDOW_SIZE, L"@96|850,490" }, + { IntegerPairSettingType, SETTING_NAME_GPU_NODES_WINDOW_POSITION, L"0,0" }, + { ScalableIntegerPairSettingType, SETTING_NAME_GPU_NODES_WINDOW_SIZE, L"@96|850,490" }, + }; PluginInstance = PhRegisterPlugin(PLUGIN_NAME, Instance, &info); @@ -484,7 +507,7 @@ LOGICAL DllMain( return FALSE; info->DisplayName = L"Extended Tools"; - info->Author = L"wj32"; + info->Author = L"dmex, wj32"; info->Description = L"Extended functionality for Windows 7 and above, including ETW monitoring, GPU monitoring and a Disk tab."; info->Url = L"https://wj32.org/processhacker/forums/viewtopic.php?t=1114"; @@ -618,25 +641,7 @@ LOGICAL DllMain( NetworkItemDeleteCallback ); - { - static PH_SETTING_CREATE settings[] = - { - { StringSettingType, SETTING_NAME_DISK_TREE_LIST_COLUMNS, L"" }, - { IntegerPairSettingType, SETTING_NAME_DISK_TREE_LIST_SORT, L"4,2" }, // 4, DescendingSortOrder - { IntegerSettingType, SETTING_NAME_ENABLE_ETW_MONITOR, L"1" }, - { IntegerSettingType, SETTING_NAME_ENABLE_GPU_MONITOR, L"1" }, - { IntegerSettingType, SETTING_NAME_ENABLE_SYSINFO_GRAPHS, L"1" }, - { StringSettingType, SETTING_NAME_GPU_NODE_BITMAP, L"01000000" }, - { IntegerSettingType, SETTING_NAME_GPU_LAST_NODE_COUNT, L"0" }, - { IntegerPairSettingType, SETTING_NAME_UNLOADED_WINDOW_POSITION, L"0,0" }, - { ScalableIntegerPairSettingType, SETTING_NAME_UNLOADED_WINDOW_SIZE, L"@96|350,270" }, - { StringSettingType, SETTING_NAME_UNLOADED_COLUMNS, L"" }, - { IntegerPairSettingType, SETTING_NAME_MODULE_SERVICES_WINDOW_POSITION, L"0,0" }, - { ScalableIntegerPairSettingType, SETTING_NAME_MODULE_SERVICES_WINDOW_SIZE, L"@96|850,490" }, - }; - - PhAddSettings(settings, sizeof(settings) / sizeof(PH_SETTING_CREATE)); - } + PhAddSettings(settings, RTL_NUMBER_OF(settings)); } break; } diff --git a/plugins/ExtendedTools/resource.h b/plugins/ExtendedTools/resource.h index 3cbcf4ec25a1..8dbc1268616f 100644 --- a/plugins/ExtendedTools/resource.h +++ b/plugins/ExtendedTools/resource.h @@ -26,10 +26,12 @@ #define IDD_SYSINFO_NETPANEL 124 #define IDD_SYSINFO_NET 125 #define IDD_PROCGPU_PANEL 126 -#define IDD_DISKTABRESTART 127 #define IDD_DISKTABERROR 128 #define IDD_PROCDISKNET_PANEL 129 #define IDD_PROCGPU_DETAILS 131 +#define IDC_UTILIZATION 132 +#define IDC_SPEED 133 +#define IDD_SYSINFO_GPUDETAILS 141 #define IDC_LIST 1001 #define IDC_REFRESH 1002 #define IDC_SEQUENCENUMBER 1003 @@ -55,10 +57,8 @@ #define IDC_WSWATCHENABLED 1037 #define IDC_NODES 1048 #define IDC_ENABLEGPUMONITOR 1049 -#define IDC_EXAMPLE 1050 #define IDC_ENABLESYSINFOGRAPHS 1050 #define IDC_GROUPGPU 1051 -#define IDC_SELECTALL 1051 #define IDC_GROUPMEM 1052 #define IDC_GROUPSHARED 1053 #define IDC_GROUPDEDICATED 1054 @@ -92,13 +92,16 @@ #define IDC_ZSENDSDELTA_V 1081 #define IDC_ZWRITESDELTA_V 1082 #define IDC_ZREADSDELTA_V 1083 -#define IDC_INSTRUCTION 1084 #define IDC_PANEL_LAYOUT 1085 #define IDC_RESTART 1086 #define IDC_ERROR 1087 #define IDC_GROUPDISK 1088 #define IDC_GROUPNETWORK 1089 #define IDC_GPUDETAILS 1090 +#define IDC_BUTTON1 1092 +#define IDC_DETAILS 1092 +#define IDC_LIST1 1093 +#define IDC_GPULIST 1093 #define ID_DISK_GOTOPROCESS 40005 #define ID_DISK_COPY 40006 #define ID_DISK_PROPERTIES 40007 @@ -108,9 +111,9 @@ // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 138 +#define _APS_NEXT_RESOURCE_VALUE 144 #define _APS_NEXT_COMMAND_VALUE 40009 -#define _APS_NEXT_CONTROL_VALUE 1091 -#define _APS_NEXT_SYMED_VALUE 130 +#define _APS_NEXT_CONTROL_VALUE 1094 +#define _APS_NEXT_SYMED_VALUE 134 #endif #endif From 736feb4b9bfaaeaffb33f4bf89cb6eaec65487c5 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 24 May 2018 09:04:51 +1000 Subject: [PATCH 0980/2058] ExtendedTools: Fix gpu text for Intel IGP devices --- plugins/ExtendedTools/gpunodes.c | 2 +- plugins/ExtendedTools/gpusys.c | 33 +++++++++++++++++++++----------- 2 files changed, 23 insertions(+), 12 deletions(-) diff --git a/plugins/ExtendedTools/gpunodes.c b/plugins/ExtendedTools/gpunodes.c index f2f3891e7bb2..1e7adc192f96 100644 --- a/plugins/ExtendedTools/gpunodes.c +++ b/plugins/ExtendedTools/gpunodes.c @@ -403,7 +403,7 @@ INT_PTR CALLBACK EtpGpuNodesDlgProc( adapterDescription = PhCreateString(L"Unknown Adapter"); } - if (adapterEngineName) + if (!PhIsNullOrEmptyString(adapterEngineName)) { PhMoveReference(&GraphState[i].TooltipText, PhFormatString( L"Node %lu (%s) on %s\n%.2f%%\n%s", diff --git a/plugins/ExtendedTools/gpusys.c b/plugins/ExtendedTools/gpusys.c index 9289cd843e34..61dc2d6b2a7a 100644 --- a/plugins/ExtendedTools/gpusys.c +++ b/plugins/ExtendedTools/gpusys.c @@ -120,17 +120,28 @@ BOOLEAN EtpGpuSysInfoSectionCallback( PPH_SYSINFO_DRAW_PANEL drawPanel = Parameter1; drawPanel->Title = PhCreateString(L"GPU"); - drawPanel->SubTitle = PhFormatString( - L"%.2f%%\n%s / %s", - EtGpuNodeUsage * 100, - PhaFormatSize(EtGpuDedicatedUsage, ULONG_MAX)->Buffer, - PhaFormatSize(EtGpuDedicatedLimit, ULONG_MAX)->Buffer - ); - drawPanel->SubTitleOverflow = PhFormatString( - L"%.2f%%\n%s", - EtGpuNodeUsage * 100, - PhaFormatSize(EtGpuDedicatedUsage, ULONG_MAX)->Buffer - ); + + if (EtGpuDedicatedUsage && EtGpuDedicatedLimit) // Required for Intel IGP devices -dmex + { + drawPanel->SubTitle = PhFormatString( + L"%.2f%%\n%s / %s", + EtGpuNodeUsage * 100, + PhaFormatSize(EtGpuDedicatedUsage, ULONG_MAX)->Buffer, + PhaFormatSize(EtGpuDedicatedLimit, ULONG_MAX)->Buffer + ); + drawPanel->SubTitleOverflow = PhFormatString( + L"%.2f%%\n%s", + EtGpuNodeUsage * 100, + PhaFormatSize(EtGpuDedicatedUsage, ULONG_MAX)->Buffer + ); + } + else + { + drawPanel->SubTitle = PhFormatString( + L"%.2f%%\n", + EtGpuNodeUsage * 100 + ); + } } return TRUE; } From b2f639c53f3ce4b982d69685a8b03460057357f0 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 25 May 2018 12:49:42 +1000 Subject: [PATCH 0981/2058] Update json-c to version 0.13.1 --- phlib/json.c | 10 +- phlib/jsonc/arraylist.c | 69 +- phlib/jsonc/arraylist.h | 24 +- phlib/jsonc/bits.h | 28 +- phlib/jsonc/config.h | 153 ++- phlib/jsonc/debug.c | 18 +- phlib/jsonc/debug.h | 4 + phlib/jsonc/json.h | 6 +- phlib/jsonc/json_c_version.h | 26 +- phlib/jsonc/json_inttypes.h | 25 +- phlib/jsonc/json_object.c | 1331 +++++++++++++++++------ phlib/jsonc/json_object.h | 596 ++++++++-- phlib/jsonc/json_object_iterator.c | 11 +- phlib/jsonc/json_object_iterator.h | 9 +- phlib/jsonc/json_object_private.h | 21 +- phlib/jsonc/json_pointer.c | 327 ++++++ phlib/jsonc/json_pointer.h | 120 ++ phlib/jsonc/json_tokener.c | 269 +++-- phlib/jsonc/json_tokener.h | 38 +- phlib/jsonc/json_util.c | 239 ++-- phlib/jsonc/json_util.h | 73 +- phlib/jsonc/json_visit.c | 133 +++ phlib/jsonc/json_visit.h | 95 ++ phlib/jsonc/libjson.c | 2 +- phlib/jsonc/linkhash.c | 446 +++++--- phlib/jsonc/linkhash.h | 248 +++-- phlib/jsonc/math_compat.h | 18 +- phlib/jsonc/printbuf.c | 72 +- phlib/jsonc/printbuf.h | 72 +- phlib/jsonc/random_seed.c | 52 +- phlib/jsonc/random_seed.h | 4 + phlib/jsonc/snprintf_compat.h | 41 + phlib/jsonc/strdup_compat.h | 16 + phlib/jsonc/strerror_override.c | 105 ++ phlib/jsonc/strerror_override.h | 30 + phlib/jsonc/strerror_override_private.h | 12 + phlib/jsonc/vasprintf_compat.h | 51 + 37 files changed, 3690 insertions(+), 1104 deletions(-) create mode 100644 phlib/jsonc/json_pointer.c create mode 100644 phlib/jsonc/json_pointer.h create mode 100644 phlib/jsonc/json_visit.c create mode 100644 phlib/jsonc/json_visit.h create mode 100644 phlib/jsonc/snprintf_compat.h create mode 100644 phlib/jsonc/strdup_compat.h create mode 100644 phlib/jsonc/strerror_override.c create mode 100644 phlib/jsonc/strerror_override.h create mode 100644 phlib/jsonc/strerror_override_private.h create mode 100644 phlib/jsonc/vasprintf_compat.h diff --git a/phlib/json.c b/phlib/json.c index 0eba2c3682a5..f59a479b0614 100644 --- a/phlib/json.c +++ b/phlib/json.c @@ -61,10 +61,10 @@ PPH_STRING PhGetJsonValueAsString( _In_ PSTR Key ) { - PSTR value; + PCSTR value; if (value = json_object_get_string(json_get_object(Object, Key))) - return PhConvertUtf8ToUtf16(value); + return PhConvertUtf8ToUtf16((PSTR)value); else return NULL; } @@ -135,10 +135,10 @@ PPH_STRING PhGetJsonArrayString( _In_ PVOID Object ) { - PSTR value; + PCSTR value; if (value = json_object_to_json_string(Object)) - return PhConvertUtf8ToUtf16(value); + return PhConvertUtf8ToUtf16((PSTR)value); else return NULL; } @@ -204,4 +204,4 @@ VOID PhSaveJsonObjectToFile( ) { json_object_to_file(FileName, Object); -} \ No newline at end of file +} diff --git a/phlib/jsonc/arraylist.c b/phlib/jsonc/arraylist.c index 97f2c921711b..3354671b0f84 100644 --- a/phlib/jsonc/arraylist.c +++ b/phlib/jsonc/arraylist.c @@ -11,6 +11,8 @@ #include "config.h" +#include + #ifdef STDC_HEADERS # include # include @@ -20,7 +22,18 @@ # include #endif /* HAVE_STRINGS_H */ -#include "bits.h" +#ifndef SIZE_T_MAX +#if SIZEOF_SIZE_T == SIZEOF_INT +#define SIZE_T_MAX UINT_MAX +#elif SIZEOF_SIZE_T == SIZEOF_LONG +#define SIZE_T_MAX ULONG_MAX +#elif SIZEOF_SIZE_T == SIZEOF_LONG_LONG +#define SIZE_T_MAX ULLONG_MAX +#else +#error Unable to determine size of size_t +#endif +#endif + #include "arraylist.h" struct array_list* @@ -43,7 +56,7 @@ array_list_new(array_list_free_fn *free_fn) extern void array_list_free(struct array_list *arr) { - int i; + size_t i; for(i = 0; i < arr->length; i++) if(arr->array[i]) arr->free_fn(arr->array[i]); free(arr->array); @@ -51,20 +64,29 @@ array_list_free(struct array_list *arr) } void* -array_list_get_idx(struct array_list *arr, int i) +array_list_get_idx(struct array_list *arr, size_t i) { if(i >= arr->length) return NULL; return arr->array[i]; } -static int array_list_expand_internal(struct array_list *arr, int max) +static int array_list_expand_internal(struct array_list *arr, size_t max) { void *t; - int new_size; + size_t new_size; if(max < arr->size) return 0; - new_size = json_max(arr->size << 1, max); - if(!(t = realloc(arr->array, new_size*sizeof(void*)))) return -1; + /* Avoid undefined behaviour on size_t overflow */ + if( arr->size >= SIZE_T_MAX / 2 ) + new_size = max; + else + { + new_size = arr->size << 1; + if (new_size < max) + new_size = max; + } + if (new_size > (~((size_t)0)) / sizeof(void*)) return -1; + if (!(t = realloc(arr->array, new_size*sizeof(void*)))) return -1; arr->array = (void**)t; (void)memset(arr->array + arr->size, 0, (new_size-arr->size)*sizeof(void*)); arr->size = new_size; @@ -72,10 +94,12 @@ static int array_list_expand_internal(struct array_list *arr, int max) } int -array_list_put_idx(struct array_list *arr, int idx, void *data) +array_list_put_idx(struct array_list *arr, size_t idx, void *data) { + if (idx > SIZE_T_MAX - 1 ) return -1; if(array_list_expand_internal(arr, idx+1)) return -1; - if(arr->array[idx]) arr->free_fn(arr->array[idx]); + if(idx < arr->length && arr->array[idx]) + arr->free_fn(arr->array[idx]); arr->array[idx] = data; if(arr->length <= idx) arr->length = idx + 1; return 0; @@ -90,12 +114,33 @@ array_list_add(struct array_list *arr, void *data) void array_list_sort(struct array_list *arr, int(__cdecl* sort_fn)(const void *, const void *)) { - qsort(arr->array, arr->length, sizeof(arr->array[0]), - (int (__cdecl*)(const void *, const void *))sort_fn); + qsort(arr->array, arr->length, sizeof(arr->array[0]), sort_fn); } -int +void* array_list_bsearch(const void **key, struct array_list *arr, + int (__cdecl* sort_fn)(const void *, const void *)) +{ + return bsearch(key, arr->array, arr->length, sizeof(arr->array[0]), + sort_fn); +} + +size_t array_list_length(struct array_list *arr) { return arr->length; } + +int +array_list_del_idx( struct array_list *arr, size_t idx, size_t count ) +{ + size_t i, stop; + + stop = idx + count; + if ( idx >= arr->length || stop > arr->length ) return -1; + for ( i = idx; i < stop; ++i ) { + if ( arr->array[i] ) arr->free_fn( arr->array[i] ); + } + memmove( arr->array + idx, arr->array + stop, (arr->length - stop) * sizeof(void*) ); + arr->length -= count; + return 0; +} diff --git a/phlib/jsonc/arraylist.h b/phlib/jsonc/arraylist.h index 089be0bd7215..546b375a3ee0 100644 --- a/phlib/jsonc/arraylist.h +++ b/phlib/jsonc/arraylist.h @@ -9,6 +9,12 @@ * */ +/** + * @file + * @brief Internal methods for working with json_type_array objects. + * Although this is exposed by the json_object_get_array() method, + * it is not recommended for direct use. + */ #ifndef _arraylist_h_ #define _arraylist_h_ @@ -23,10 +29,11 @@ typedef void (array_list_free_fn) (void *data); struct array_list { void **array; - int length; - int size; + size_t length; + size_t size; array_list_free_fn *free_fn; }; +typedef struct array_list array_list; extern struct array_list* array_list_new(array_list_free_fn *free_fn); @@ -35,20 +42,27 @@ extern void array_list_free(struct array_list *al); extern void* -array_list_get_idx(struct array_list *al, int i); +array_list_get_idx(struct array_list *al, size_t i); extern int -array_list_put_idx(struct array_list *al, int i, void *data); +array_list_put_idx(struct array_list *al, size_t i, void *data); extern int array_list_add(struct array_list *al, void *data); -extern int +extern size_t array_list_length(struct array_list *al); extern void array_list_sort(struct array_list *arr, int(__cdecl* compar)(const void *, const void *)); +extern void* array_list_bsearch(const void **key, + struct array_list *arr, + int (__cdecl* sort_fn)(const void *, const void *)); + +extern int +array_list_del_idx(struct array_list *arr, size_t idx, size_t count); + #ifdef __cplusplus } #endif diff --git a/phlib/jsonc/bits.h b/phlib/jsonc/bits.h index c8cbbc820d5b..14c1c132d374 100644 --- a/phlib/jsonc/bits.h +++ b/phlib/jsonc/bits.h @@ -1,4 +1,8 @@ -/* +/** + * @file + * @brief Do not use, only contains deprecated defines. + * @deprecated Use json_util.h instead. + * * $Id: bits.h,v 1.10 2006/01/30 23:07:57 mclark Exp $ * * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. @@ -12,17 +16,21 @@ #ifndef _bits_h_ #define _bits_h_ -#ifndef json_min -#define json_min(a,b) ((a) < (b) ? (a) : (b)) -#endif - -#ifndef json_max -#define json_max(a,b) ((a) > (b) ? (a) : (b)) -#endif - +/** + * @deprecated + */ #define hexdigit(x) (((x) <= '9') ? (x) - '0' : ((x) & 7) + 9) +/** + * @deprecated + */ #define error_ptr(error) ((void*)error) -#define error_description(error) (json_tokener_errors[error]) +/** + * @deprecated + */ +#define error_description(error) (json_tokener_get_error(error)) +/** + * @deprecated + */ #define is_error(ptr) (ptr == NULL) #endif diff --git a/phlib/jsonc/config.h b/phlib/jsonc/config.h index df46f0a481a7..b84c3ba26910 100644 --- a/phlib/jsonc/config.h +++ b/phlib/jsonc/config.h @@ -1,20 +1,48 @@ -#define PACKAGE_STRING "JSON C Library 0.12-20140410" -#define PACKAGE_BUGREPORT "json-c@googlegroups.com" -#define PACKAGE_NAME "JSON C Library" -#define PACKAGE_TARNAME "json-c" -#define PACKAGE_VERSION "0.12-20140410" +/* Enable RDRANR Hardware RNG Hash Seed */ +#undef ENABLE_RDRAND +/* Define if .gnu.warning accepts long strings. */ +#undef HAS_GNU_WARNING_LONG -#define HAVE_SETLOCALE 1 -#define HAVE_LOCALE_H 1 - -#define HAVE_DECL_NAN 1 +/* Define to 1 if you have the declaration of `INFINITY', and to 0 if you +don't. */ +#if (defined(_MSC_VER) && _MSC_VER >= 1800) || defined(__MINGW32__) #define HAVE_DECL_INFINITY 1 -//#define HAVE_DECL__ISNAN 1 -//#define HAVE_DECL__FINITE 1 +#endif + +/* Define to 1 if you have the declaration of `isinf', and to 0 if you don't. +*/ +#if (defined(_MSC_VER) && _MSC_VER >= 1800) || defined(__MINGW32__) +#define HAVE_DECL_ISINF 1 +#endif + +/* Define to 1 if you have the declaration of `isnan', and to 0 if you don't. +*/ +#if (defined(_MSC_VER) && _MSC_VER >= 1800) || defined(__MINGW32__) +#define HAVE_DECL_ISNAN 1 +#endif + +/* Define to 1 if you have the declaration of `nan', and to 0 if you don't. */ +#if (defined(_MSC_VER) && _MSC_VER >= 1800) || defined(__MINGW32__) +#define HAVE_DECL_NAN 1 +#endif + +/* Define to 1 if you have the declaration of `_finite', and to 0 if you +don't. */ +#define HAVE_DECL__FINITE 1 + +/* Define to 1 if you have the declaration of `_isnan', and to 0 if you don't. +*/ +#define HAVE_DECL__ISNAN 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_DLFCN_H 1 /* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */ -/* #undef HAVE_DOPRNT */ +#define HAVE_DOPRNT 1 + +/* Define to 1 if you have the header file. */ +#undef HAVE_ENDIAN_H /* Define to 1 if you have the header file. */ #define HAVE_FCNTL_H 1 @@ -25,8 +53,11 @@ /* Define to 1 if you have the header file. */ #define HAVE_LIMITS_H 1 +/* Define to 1 if you have the header file. */ +#define HAVE_LOCALE_H 1 + /* Define to 1 if your system has a GNU libc compatible `malloc' function, and - to 0 otherwise. */ +to 0 otherwise. */ #define HAVE_MALLOC 1 /* Define to 1 if you have the header file. */ @@ -36,20 +67,29 @@ #define HAVE_OPEN 1 /* Define to 1 if your system has a GNU libc compatible `realloc' function, - and to 0 otherwise. */ +and to 0 otherwise. */ #define HAVE_REALLOC 1 +/* Define to 1 if you have the `setlocale' function. */ +#define HAVE_SETLOCALE 1 + +/* Define to 1 if you have the `snprintf' function. */ +#define HAVE_SNPRINTF 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDARG_H 1 + /* Define to 1 if you have the header file. */ #define HAVE_STDINT_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STDLIB_H 1 -/* Define to 1 if you have the `strdup' function. */ -#define HAVE_STRNDUP 1 +/* Define to 1 if you have the `strcasecmp' function. */ +#define HAVE_STRCASECMP 1 -/* Define to 1 if you have the header file. */ -#define HAVE_STDARG_H 1 +/* Define to 1 if you have the `strdup' function. */ +//#define HAVE_STRDUP 1 /* Define to 1 if you have the `strerror' function. */ #define HAVE_STRERROR 1 @@ -60,11 +100,29 @@ /* Define to 1 if you have the header file. */ #define HAVE_STRING_H 1 +/* Define to 1 if you have the `strncasecmp' function. */ +#if defined(__MINGW32__) +#define HAVE_STRNCASECMP 1 +#else +#undef HAVE_STRNCASECMP +#endif + +//#cmakedefine HAVE_STRTOLL +//#cmakedefine strtoll @cmake_strtoll@ +#define HAVE_STRTOLL 1 + /* Define to 1 if you have the header file. */ #undef HAVE_SYSLOG_H +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_CDEFS_H 1 + /* Define to 1 if you have the header file. */ +#if defined(__MINGW32__) +#define HAVE_SYS_PARAM_H 1 +#else #undef HAVE_SYS_PARAM_H +#endif /* Define to 1 if you have the header file. */ #define HAVE_SYS_STAT_H 1 @@ -73,17 +131,70 @@ #define HAVE_SYS_TYPES_H 1 /* Define to 1 if you have the header file. */ +#if defined(__MINGW32__) +#define HAVE_UNISTD_H 1 +#else #undef HAVE_UNISTD_H +#endif + +/* Define to 1 if you have the `vasprintf' function. */ +#if defined(__MINGW32__) +#define HAVE_VASPRINTF 1 +#else +#undef HAVE_VASPRINTF +#endif /* Define to 1 if you have the `vprintf' function. */ -#undef HAVE_VPRINTF +#define HAVE_VPRINTF 1 + +/* Define to 1 if you have the `vsnprintf' function. */ +#define HAVE_VSNPRINTF 1 /* Define to 1 if you have the `vsyslog' function. */ #undef HAVE_VSYSLOG -/* Define to 1 if you have the `strncasecmp' function. */ -#undef HAVE_STRNCASECMP +/* Define to the sub-directory in which libtool stores uninstalled libraries. +*/ +#undef LT_OBJDIR + +/* Define to 1 if your C compiler doesn't accept -c and -o together. */ +/* #undef NO_MINUS_C_MINUS_O */ + +/* Name of package */ +#define PACKAGE "json-c" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "json-c@googlegroups.com" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "JSON C Library" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "JSON C Library 0.13.1" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "json-c" + +/* Define to the home page for this package. */ +#define PACKAGE_URL "https://github.com/json-c/json-c" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "0.13.1" /* Define to 1 if you have the ANSI C header files. */ #define STDC_HEADERS 1 +/* Version number of package */ +#define VERSION "0.13.1" + +/* Define to empty if `const' does not conform to ANSI C. */ +/* #undef const */ + +/* Define to rpl_malloc if the replacement function should be used. */ +/* #undef malloc */ + +/* Define to rpl_realloc if the replacement function should be used. */ +/* #undef realloc */ + +/* Define to `unsigned int' if does not define. */ +/* #undef size_t */ diff --git a/phlib/jsonc/debug.c b/phlib/jsonc/debug.c index 9dff7818bf86..4b5140aec1e2 100644 --- a/phlib/jsonc/debug.c +++ b/phlib/jsonc/debug.c @@ -48,10 +48,10 @@ void mc_debug(const char *msg, ...) va_start(ap, msg); #if HAVE_VSYSLOG if(_syslog) { - vsyslog(LOG_DEBUG, msg, ap); - } else + vsyslog(LOG_DEBUG, msg, ap); + } else #endif - vprintf(msg, ap); + vprintf(msg, ap); va_end(ap); } } @@ -62,10 +62,10 @@ void mc_error(const char *msg, ...) va_start(ap, msg); #if HAVE_VSYSLOG if(_syslog) { - vsyslog(LOG_ERR, msg, ap); - } else + vsyslog(LOG_ERR, msg, ap); + } else #endif - vfprintf(stderr, msg, ap); + vfprintf(stderr, msg, ap); va_end(ap); } @@ -75,9 +75,9 @@ void mc_info(const char *msg, ...) va_start(ap, msg); #if HAVE_VSYSLOG if(_syslog) { - vsyslog(LOG_INFO, msg, ap); - } else + vsyslog(LOG_INFO, msg, ap); + } else #endif - vfprintf(stderr, msg, ap); + vfprintf(stderr, msg, ap); va_end(ap); } diff --git a/phlib/jsonc/debug.h b/phlib/jsonc/debug.h index 80ca3e43042e..07fcc380b3c6 100644 --- a/phlib/jsonc/debug.h +++ b/phlib/jsonc/debug.h @@ -10,6 +10,10 @@ * */ +/** + * @file + * @brief Do not use, json-c internal, may be changed or removed at any time. + */ #ifndef _DEBUG_H_ #define _DEBUG_H_ diff --git a/phlib/jsonc/json.h b/phlib/jsonc/json.h index 4339b20e9060..fc2daddee290 100644 --- a/phlib/jsonc/json.h +++ b/phlib/jsonc/json.h @@ -10,6 +10,10 @@ * */ +/** + * @file + * @brief A convenience header that may be included instead of other individual ones. + */ #ifndef _json_h_ #define _json_h_ @@ -17,12 +21,12 @@ extern "C" { #endif -#include "bits.h" #include "debug.h" #include "linkhash.h" #include "arraylist.h" #include "json_util.h" #include "json_object.h" +#include "json_pointer.h" #include "json_tokener.h" #include "json_object_iterator.h" #include "json_c_version.h" diff --git a/phlib/jsonc/json_c_version.h b/phlib/jsonc/json_c_version.h index eed98a497501..98838be9469a 100644 --- a/phlib/jsonc/json_c_version.h +++ b/phlib/jsonc/json_c_version.h @@ -1,22 +1,40 @@ /* - * Copyright (c) 2012 Eric Haszlakiewicz + * Copyright (c) 2012,2017 Eric Haszlakiewicz * * This library is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See COPYING for details. */ +/** + * @file + * @brief Methods for retrieving the json-c version. + */ #ifndef _json_c_version_h_ #define _json_c_version_h_ #define JSON_C_MAJOR_VERSION 0 -#define JSON_C_MINOR_VERSION 12 -#define JSON_C_MICRO_VERSION 0 +#define JSON_C_MINOR_VERSION 13 +#define JSON_C_MICRO_VERSION 01 #define JSON_C_VERSION_NUM ((JSON_C_MAJOR_VERSION << 16) | \ (JSON_C_MINOR_VERSION << 8) | \ JSON_C_MICRO_VERSION) -#define JSON_C_VERSION "0.12" +#define JSON_C_VERSION "0.13.1" +/** + * @see JSON_C_VERSION + * @return the version of the json-c library as a string + */ const char *json_c_version(void); /* Returns JSON_C_VERSION */ + +/** + * The json-c version encoded into an int, with the low order 8 bits + * being the micro version, the next higher 8 bits being the minor version + * and the next higher 8 bits being the major version. + * For example, 7.12.99 would be 0x00070B63. + * + * @see JSON_C_VERSION_NUM + * @return the version of the json-c library as an int + */ int json_c_version_num(void); /* Returns JSON_C_VERSION_NUM */ #endif diff --git a/phlib/jsonc/json_inttypes.h b/phlib/jsonc/json_inttypes.h index 9de8d246d9dd..3854913fc58a 100644 --- a/phlib/jsonc/json_inttypes.h +++ b/phlib/jsonc/json_inttypes.h @@ -1,27 +1,22 @@ +/** + * @file + * @brief Do not use, json-c internal, may be changed or removed at any time. + */ #ifndef _json_inttypes_h_ #define _json_inttypes_h_ #include "json_config.h" -#if defined(_MSC_VER) && _MSC_VER <= 1700 - -/* Anything less than Visual Studio C++ 10 is missing stdint.h and inttypes.h */ -typedef __int32 int32_t; -#define INT32_MIN ((int32_t)_I32_MIN) -#define INT32_MAX ((int32_t)_I32_MAX) -typedef __int64 int64_t; -#define INT64_MIN ((int64_t)_I64_MIN) -#define INT64_MAX ((int64_t)_I64_MAX) -#define PRId64 "I64d" -#define SCNd64 "I64d" +#ifdef JSON_C_HAVE_INTTYPES_H +/* inttypes.h includes stdint.h */ +#include #else +#include -#ifdef JSON_C_HAVE_INTTYPES_H -#include -#endif -/* inttypes.h includes stdint.h */ +#define PRId64 "I64d" +#define SCNd64 "I64d" #endif diff --git a/phlib/jsonc/json_object.c b/phlib/jsonc/json_object.c index 57f3f0d237d5..5d8155c1f28c 100644 --- a/phlib/jsonc/json_object.c +++ b/phlib/jsonc/json_object.c @@ -10,14 +10,20 @@ * */ +#pragma warning(push) +#pragma warning(disable: 4996) + #include "config.h" +#include "strerror_override.h" + +#include +#include #include #include #include #include #include -#include #include "debug.h" #include "printbuf.h" @@ -28,20 +34,12 @@ #include "json_object_private.h" #include "json_util.h" #include "math_compat.h" +#include "strdup_compat.h" +#include "snprintf_compat.h" -#if !defined(HAVE_STRDUP) && defined(_MSC_VER) - /* MSC has the version as _strdup */ -# define strdup _strdup -#elif !defined(HAVE_STRDUP) -# error You do not have strdup on your system. -#endif /* HAVE_STRDUP */ - -#if !defined(HAVE_SNPRINTF) && defined(_MSC_VER) - /* MSC has the version as _snprintf */ -# define snprintf _snprintf -#elif !defined(HAVE_SNPRINTF) -# error You do not have snprintf on your system. -#endif /* HAVE_SNPRINTF */ +#if SIZEOF_LONG_LONG != SIZEOF_INT64_T +#error "The long long type isn't 64-bits" +#endif // Don't define this. It's not thread-safe. /* #define REFCOUNT_DEBUG 1 */ @@ -54,8 +52,8 @@ static struct json_object* json_object_new(enum json_type o_type); static json_object_to_json_string_fn json_object_object_to_json_string; static json_object_to_json_string_fn json_object_boolean_to_json_string; +static json_object_to_json_string_fn json_object_double_to_json_string_default; static json_object_to_json_string_fn json_object_int_to_json_string; -static json_object_to_json_string_fn json_object_double_to_json_string; static json_object_to_json_string_fn json_object_string_to_json_string; static json_object_to_json_string_fn json_object_array_to_json_string; @@ -68,72 +66,104 @@ static struct lh_table *json_object_table; static void json_object_init(void) __attribute__ ((constructor)); static void json_object_init(void) { - MC_DEBUG("json_object_init: creating object table\n"); - json_object_table = lh_kptr_table_new(128, "json_object_table", NULL); + MC_DEBUG("json_object_init: creating object table\n"); + json_object_table = lh_kptr_table_new(128, NULL); } static void json_object_fini(void) __attribute__ ((destructor)); -static void json_object_fini(void) { - struct lh_entry *ent; - if(MC_GET_DEBUG()) { - if (json_object_table->count) { - MC_DEBUG("json_object_fini: %d referenced objects at exit\n", - json_object_table->count); - lh_foreach(json_object_table, ent) { - struct json_object* obj = (struct json_object*)ent->v; - MC_DEBUG("\t%s:%p\n", json_type_to_name(obj->o_type), obj); - } +static void json_object_fini(void) +{ + struct lh_entry *ent; + if (MC_GET_DEBUG()) + { + if (json_object_table->count) + { + MC_DEBUG("json_object_fini: %d referenced objects at exit\n", + json_object_table->count); + lh_foreach(json_object_table, ent) + { + struct json_object* obj = + (struct json_object*) lh_entry_v(ent); + MC_DEBUG("\t%s:%p\n", + json_type_to_name(obj->o_type), obj); + } + } } - } - MC_DEBUG("json_object_fini: freeing object table\n"); - lh_table_free(json_object_table); + MC_DEBUG("json_object_fini: freeing object table\n"); + lh_table_free(json_object_table); } #endif /* REFCOUNT_DEBUG */ +/* helper for accessing the optimized string data component in json_object + */ +static const char * +get_string_component(const struct json_object *jso) +{ + return (jso->o.c_string.len < LEN_DIRECT_STRING_DATA) ? + jso->o.c_string.str.data : jso->o.c_string.str.ptr; +} + /* string escaping */ -static int json_escape_str(struct printbuf *pb, char *str, size_t len) -{ - int pos = 0, start_offset = 0; - unsigned char c; - while (len--) { - c = str[pos]; - switch(c) { - case '\b': - case '\n': - case '\r': - case '\t': - case '\f': - case '"': - case '\\': - case '/': - if(pos - start_offset > 0) - printbuf_memappend(pb, str + start_offset, pos - start_offset); - if(c == '\b') printbuf_memappend(pb, "\\b", 2); - else if(c == '\n') printbuf_memappend(pb, "\\n", 2); - else if(c == '\r') printbuf_memappend(pb, "\\r", 2); - else if(c == '\t') printbuf_memappend(pb, "\\t", 2); - else if(c == '\f') printbuf_memappend(pb, "\\f", 2); - else if(c == '"') printbuf_memappend(pb, "\\\"", 2); - else if(c == '\\') printbuf_memappend(pb, "\\\\", 2); - else if(c == '/') printbuf_memappend(pb, "\\/", 2); - start_offset = ++pos; - break; - default: - if(c < ' ') { - if(pos - start_offset > 0) - printbuf_memappend(pb, str + start_offset, pos - start_offset); - sprintbuf(pb, "\\u00%c%c", - json_hex_chars[c >> 4], - json_hex_chars[c & 0xf]); - start_offset = ++pos; - } else pos++; +static int json_escape_str(struct printbuf *pb, const char *str, int len, int flags) +{ + int pos = 0, start_offset = 0; + unsigned char c; + while (len--) + { + c = str[pos]; + switch(c) + { + case '\b': + case '\n': + case '\r': + case '\t': + case '\f': + case '"': + case '\\': + case '/': + if((flags & JSON_C_TO_STRING_NOSLASHESCAPE) && c == '/') + { + pos++; + break; + } + + if(pos - start_offset > 0) + printbuf_memappend(pb, str + start_offset, pos - start_offset); + + if(c == '\b') printbuf_memappend(pb, "\\b", 2); + else if(c == '\n') printbuf_memappend(pb, "\\n", 2); + else if(c == '\r') printbuf_memappend(pb, "\\r", 2); + else if(c == '\t') printbuf_memappend(pb, "\\t", 2); + else if(c == '\f') printbuf_memappend(pb, "\\f", 2); + else if(c == '"') printbuf_memappend(pb, "\\\"", 2); + else if(c == '\\') printbuf_memappend(pb, "\\\\", 2); + else if(c == '/') printbuf_memappend(pb, "\\/", 2); + + start_offset = ++pos; + break; + default: + if(c < ' ') + { + char sbuf[7]; + if(pos - start_offset > 0) + printbuf_memappend(pb, + str + start_offset, + pos - start_offset); + snprintf(sbuf, sizeof(sbuf), + "\\u00%c%c", + json_hex_chars[c >> 4], + json_hex_chars[c & 0xf]); + printbuf_memappend_fast(pb, sbuf, (int) sizeof(sbuf) - 1); + start_offset = ++pos; + } else + pos++; + } } - } - if(pos - start_offset > 0) - printbuf_memappend(pb, str + start_offset, pos - start_offset); - return 0; + if (pos - start_offset > 0) + printbuf_memappend(pb, str + start_offset, pos - start_offset); + return 0; } @@ -141,26 +171,42 @@ static int json_escape_str(struct printbuf *pb, char *str, size_t len) extern struct json_object* json_object_get(struct json_object *jso) { - if(jso) { - jso->_ref_count++; - } - return jso; + if (!jso) return jso; + +#if defined(HAVE_ATOMIC_BUILTINS) && defined(ENABLE_THREADING) + __sync_add_and_fetch(&jso->_ref_count, 1); +#else + ++jso->_ref_count; +#endif + + return jso; } int json_object_put(struct json_object *jso) { - if(jso) - { - jso->_ref_count--; - if(!jso->_ref_count) - { - if (jso->_user_delete) - jso->_user_delete(jso, jso->_userdata); - jso->_delete(jso); - return 1; - } - } - return 0; + if(!jso) return 0; + + /* Avoid invalid free and crash explicitly instead of (silently) + * segfaulting. + */ + assert(jso->_ref_count > 0); + +#if defined(HAVE_ATOMIC_BUILTINS) && defined(ENABLE_THREADING) + /* Note: this only allow the refcount to remain correct + * when multiple threads are adjusting it. It is still an error + * for a thread to decrement the refcount if it doesn't "own" it, + * as that can result in the thread that loses the race to 0 + * operating on an already-freed object. + */ + if (__sync_sub_and_fetch(&jso->_ref_count, 1) > 0) return 0; +#else + if (--jso->_ref_count > 0) return 0; +#endif + + if (jso->_user_delete) + jso->_user_delete(jso, jso->_userdata); + jso->_delete(jso); + return 1; } @@ -169,61 +215,74 @@ int json_object_put(struct json_object *jso) static void json_object_generic_delete(struct json_object* jso) { #ifdef REFCOUNT_DEBUG - MC_DEBUG("json_object_delete_%s: %p\n", + MC_DEBUG("json_object_delete_%s: %p\n", json_type_to_name(jso->o_type), jso); - lh_table_delete(json_object_table, jso); + lh_table_delete(json_object_table, jso); #endif /* REFCOUNT_DEBUG */ - printbuf_free(jso->_pb); - free(jso); + printbuf_free(jso->_pb); + free(jso); } static struct json_object* json_object_new(enum json_type o_type) { - struct json_object *jso; + struct json_object *jso; - jso = (struct json_object*)calloc(sizeof(struct json_object), 1); - if(!jso) return NULL; - jso->o_type = o_type; - jso->_ref_count = 1; - jso->_delete = &json_object_generic_delete; + jso = (struct json_object*)calloc(sizeof(struct json_object), 1); + if (!jso) + return NULL; + jso->o_type = o_type; + jso->_ref_count = 1; + jso->_delete = &json_object_generic_delete; #ifdef REFCOUNT_DEBUG - lh_table_insert(json_object_table, jso, jso); - MC_DEBUG("json_object_new_%s: %p\n", json_type_to_name(jso->o_type), jso); + lh_table_insert(json_object_table, jso, jso); + MC_DEBUG("json_object_new_%s: %p\n", json_type_to_name(jso->o_type), jso); #endif /* REFCOUNT_DEBUG */ - return jso; + return jso; } /* type checking functions */ -int json_object_is_type(struct json_object *jso, enum json_type type) +int json_object_is_type(const struct json_object *jso, enum json_type type) { - if (!jso) - return (type == json_type_null); - return (jso->o_type == type); + if (!jso) + return (type == json_type_null); + return (jso->o_type == type); +} + +enum json_type json_object_get_type(const struct json_object *jso) +{ + if (!jso) + return json_type_null; + return jso->o_type; +} + +void* json_object_get_userdata(json_object *jso) { + return jso ? jso->_userdata : NULL; } -enum json_type json_object_get_type(struct json_object *jso) +void json_object_set_userdata(json_object *jso, void *userdata, + json_object_delete_fn *user_delete) { - if (!jso) - return json_type_null; - return jso->o_type; + // Can't return failure, so abort if we can't perform the operation. + assert(jso != NULL); + + // First, clean up any previously existing user info + if (jso->_user_delete) + jso->_user_delete(jso, jso->_userdata); + + jso->_userdata = userdata; + jso->_user_delete = user_delete; } /* set a custom conversion to string */ void json_object_set_serializer(json_object *jso, - json_object_to_json_string_fn to_string_func, + json_object_to_json_string_fn *to_string_func, void *userdata, json_object_delete_fn *user_delete) { - // First, clean up any previously existing user info - if (jso->_user_delete) - { - jso->_user_delete(jso, jso->_userdata); - } - jso->_userdata = NULL; - jso->_user_delete = NULL; + json_object_set_userdata(jso, userdata, user_delete); if (to_string_func == NULL) { @@ -237,7 +296,7 @@ void json_object_set_serializer(json_object *jso, jso->_to_json_string = &json_object_boolean_to_json_string; break; case json_type_double: - jso->_to_json_string = &json_object_double_to_json_string; + jso->_to_json_string = &json_object_double_to_json_string_default; break; case json_type_int: jso->_to_json_string = &json_object_int_to_json_string; @@ -256,32 +315,45 @@ void json_object_set_serializer(json_object *jso, } jso->_to_json_string = to_string_func; - jso->_userdata = userdata; - jso->_user_delete = user_delete; } /* extended conversion to string */ -char* json_object_to_json_string_ext(struct json_object *jso, int flags) +const char* json_object_to_json_string_length(struct json_object *jso, int flags, size_t *length) { - if (!jso) - return "null"; + const char *r = NULL; + size_t s = 0; - if ((!jso->_pb) && !(jso->_pb = printbuf_new())) - return NULL; + if (!jso) + { + s = 4; + r = "null"; + } + else if ((jso->_pb) || (jso->_pb = printbuf_new())) + { + printbuf_reset(jso->_pb); - printbuf_reset(jso->_pb); + if(jso->_to_json_string(jso, jso->_pb, 0, flags) >= 0) + { + s = (size_t)jso->_pb->bpos; + r = jso->_pb->buf; + } + } - if(jso->_to_json_string(jso, jso->_pb, 0, flags) < 0) - return NULL; + if (length) + *length = s; + return r; +} - return jso->_pb->buf; +const char* json_object_to_json_string_ext(struct json_object *jso, int flags) +{ + return json_object_to_json_string_length(jso, flags, NULL); } /* backwards-compatible conversion to string */ -char* json_object_to_json_string(struct json_object *jso) +const char* json_object_to_json_string(struct json_object *jso) { return json_object_to_json_string_ext(jso, JSON_C_TO_STRING_SPACED); } @@ -290,7 +362,14 @@ static void indent(struct printbuf *pb, int level, int flags) { if (flags & JSON_C_TO_STRING_PRETTY) { - printbuf_memset(pb, -1, ' ', level * 2); + if (flags & JSON_C_TO_STRING_PRETTY_TAB) + { + printbuf_memset(pb, -1, '\t', level); + } + else + { + printbuf_memset(pb, -1, ' ', level * 2); + } } } @@ -304,116 +383,156 @@ static int json_object_object_to_json_string(struct json_object* jso, int had_children = 0; struct json_object_iter iter; - sprintbuf(pb, "{" /*}*/); + printbuf_strappend(pb, "{" /*}*/); if (flags & JSON_C_TO_STRING_PRETTY) - sprintbuf(pb, "\n"); + printbuf_strappend(pb, "\n"); json_object_object_foreachC(jso, iter) { if (had_children) { - sprintbuf(pb, ","); + printbuf_strappend(pb, ","); if (flags & JSON_C_TO_STRING_PRETTY) - sprintbuf(pb, "\n"); + printbuf_strappend(pb, "\n"); } had_children = 1; if (flags & JSON_C_TO_STRING_SPACED) - sprintbuf(pb, " "); + printbuf_strappend(pb, " "); indent(pb, level+1, flags); - sprintbuf(pb, "\""); - json_escape_str(pb, iter.key, strlen(iter.key)); + printbuf_strappend(pb, "\""); + json_escape_str(pb, iter.key, (int)strlen(iter.key), flags); if (flags & JSON_C_TO_STRING_SPACED) - sprintbuf(pb, "\": "); + printbuf_strappend(pb, "\": "); else - sprintbuf(pb, "\":"); + printbuf_strappend(pb, "\":"); if(iter.val == NULL) - sprintbuf(pb, "null"); + printbuf_strappend(pb, "null"); else - iter.val->_to_json_string(iter.val, pb, level+1,flags); + if (iter.val->_to_json_string(iter.val, pb, level+1,flags) < 0) + return -1; } if (flags & JSON_C_TO_STRING_PRETTY) { if (had_children) - sprintbuf(pb, "\n"); + printbuf_strappend(pb, "\n"); indent(pb,level,flags); } if (flags & JSON_C_TO_STRING_SPACED) - return sprintbuf(pb, /*{*/ " }"); + return (int)printbuf_strappend(pb, /*{*/ " }"); else - return sprintbuf(pb, /*{*/ "}"); + return (int)printbuf_strappend(pb, /*{*/ "}"); } static void json_object_lh_entry_free(struct lh_entry *ent) { - free(ent->k); - json_object_put((struct json_object*)ent->v); + if (!ent->k_is_constant) + free(lh_entry_k(ent)); + json_object_put((struct json_object*)lh_entry_v(ent)); } static void json_object_object_delete(struct json_object* jso) { - lh_table_free(jso->o.c_object); - json_object_generic_delete(jso); + lh_table_free(jso->o.c_object); + json_object_generic_delete(jso); } struct json_object* json_object_new_object(void) { - struct json_object* jso = json_object_new(json_type_object); - - if (!jso) - { + struct json_object *jso = json_object_new(json_type_object); + if (!jso) return NULL; - } - jso->_delete = &json_object_object_delete; jso->_to_json_string = &json_object_object_to_json_string; - jso->o.c_object = lh_kchar_table_new(JSON_OBJECT_DEF_HASH_ENTRIES, NULL, &json_object_lh_entry_free); - + jso->o.c_object = lh_kchar_table_new(JSON_OBJECT_DEF_HASH_ENTRIES, + &json_object_lh_entry_free); + if (!jso->o.c_object) + { + json_object_generic_delete(jso); + errno = ENOMEM; + return NULL; + } return jso; } -struct lh_table* json_object_get_object(struct json_object *jso) +struct lh_table* json_object_get_object(const struct json_object *jso) { - if(!jso) return NULL; - switch(jso->o_type) { - case json_type_object: - return jso->o.c_object; - default: - return NULL; - } + if (!jso) + return NULL; + switch(jso->o_type) + { + case json_type_object: + return jso->o.c_object; + default: + return NULL; + } } -void json_object_object_add(struct json_object* jso, const char *key, - struct json_object *val) +int json_object_object_add_ex(struct json_object* jso, + const char *const key, + struct json_object *const val, + const unsigned opts) { + struct json_object *existing_value = NULL; + struct lh_entry *existing_entry; + unsigned long hash; + + assert(json_object_get_type(jso) == json_type_object); + // We lookup the entry and replace the value, rather than just deleting // and re-adding it, so the existing key remains valid. - json_object *existing_value = NULL; - struct lh_entry *existing_entry; - existing_entry = lh_table_lookup_entry(jso->o.c_object, (void*)key); + hash = lh_get_hash(jso->o.c_object, (const void *)key); + existing_entry = (opts & JSON_C_OBJECT_ADD_KEY_IS_NEW) ? NULL : + lh_table_lookup_entry_w_hash(jso->o.c_object, + (const void *)key, hash); + + // The caller must avoid creating loops in the object tree, but do a + // quick check anyway to make sure we're not creating a trivial loop. + if (jso == val) + return -1; + if (!existing_entry) { - lh_table_insert(jso->o.c_object, strdup(key), val); - return; + const void *const k = (opts & JSON_C_OBJECT_KEY_IS_CONSTANT) ? + (const void *)key : strdup(key); + if (k == NULL) + return -1; + return lh_table_insert_w_hash(jso->o.c_object, k, val, hash, opts); } - existing_value = (void *)existing_entry->v; + existing_value = (json_object *) lh_entry_v(existing_entry); if (existing_value) json_object_put(existing_value); existing_entry->v = val; + return 0; +} + +int json_object_object_add(struct json_object* jso, const char *key, + struct json_object *val) +{ + return json_object_object_add_ex(jso, key, val, 0); } -int json_object_object_length(struct json_object *jso) + +int json_object_object_length(const struct json_object *jso) { + assert(json_object_get_type(jso) == json_type_object); return lh_table_length(jso->o.c_object); } -struct json_object* json_object_object_get(struct json_object* jso, const char *key) +size_t json_c_object_sizeof(void) +{ + return sizeof(struct json_object); +} + +struct json_object* json_object_object_get(const struct json_object* jso, + const char *key) { struct json_object *result = NULL; json_object_object_get_ex(jso, key, &result); return result; } -json_bool json_object_object_get_ex(struct json_object* jso, const char *key, struct json_object **value) +json_bool json_object_object_get_ex(const struct json_object* jso, const char *key, + struct json_object **value) { if (value != NULL) *value = NULL; @@ -424,7 +543,8 @@ json_bool json_object_object_get_ex(struct json_object* jso, const char *key, st switch(jso->o_type) { case json_type_object: - return lh_table_lookup_ex(jso->o.c_object, (void*)key, (void**)value); + return lh_table_lookup_ex(jso->o.c_object, (const void *) key, + (void**) value); default: if (value != NULL) *value = NULL; @@ -434,6 +554,7 @@ json_bool json_object_object_get_ex(struct json_object* jso, const char *key, st void json_object_object_del(struct json_object* jso, const char *key) { + assert(json_object_get_type(jso) == json_type_object); lh_table_delete(jso->o.c_object, key); } @@ -445,34 +566,45 @@ static int json_object_boolean_to_json_string(struct json_object* jso, int level, int flags) { - if(jso->o.c_boolean) return sprintbuf(pb, "true"); - else return sprintbuf(pb, "false"); + if (jso->o.c_boolean) + return printbuf_strappend(pb, "true"); + return printbuf_strappend(pb, "false"); } struct json_object* json_object_new_boolean(json_bool b) { - struct json_object *jso = json_object_new(json_type_boolean); - if(!jso) return NULL; - jso->_to_json_string = &json_object_boolean_to_json_string; - jso->o.c_boolean = b; - return jso; + struct json_object *jso = json_object_new(json_type_boolean); + if (!jso) + return NULL; + jso->_to_json_string = &json_object_boolean_to_json_string; + jso->o.c_boolean = b; + return jso; } -json_bool json_object_get_boolean(struct json_object *jso) +json_bool json_object_get_boolean(const struct json_object *jso) { - if(!jso) return FALSE; - switch(jso->o_type) { - case json_type_boolean: - return jso->o.c_boolean; - case json_type_int: - return (jso->o.c_int64 != 0); - case json_type_double: - return (jso->o.c_double != 0); - case json_type_string: - return (jso->o.c_string.len != 0); - default: - return FALSE; - } + if (!jso) + return FALSE; + switch(jso->o_type) + { + case json_type_boolean: + return jso->o.c_boolean; + case json_type_int: + return (jso->o.c_int64 != 0); + case json_type_double: + return (jso->o.c_double != 0); + case json_type_string: + return (jso->o.c_string.len != 0); + default: + return FALSE; + } +} + +int json_object_set_boolean(struct json_object *jso,json_bool new_value){ + if (!jso || jso->o_type!=json_type_boolean) + return 0; + jso->o.c_boolean=new_value; + return 1; } @@ -483,19 +615,23 @@ static int json_object_int_to_json_string(struct json_object* jso, int level, int flags) { - return sprintbuf(pb, "%"PRId64, jso->o.c_int64); + /* room for 19 digits, the sign char, and a null term */ + char sbuf[21]; + snprintf(sbuf, sizeof(sbuf), "%" PRId64, jso->o.c_int64); + return printbuf_memappend (pb, sbuf, strlen(sbuf)); } struct json_object* json_object_new_int(int32_t i) { - struct json_object *jso = json_object_new(json_type_int); - if(!jso) return NULL; - jso->_to_json_string = &json_object_int_to_json_string; - jso->o.c_int64 = i; - return jso; + struct json_object *jso = json_object_new(json_type_int); + if (!jso) + return NULL; + jso->_to_json_string = &json_object_int_to_json_string; + jso->o.c_int64 = i; + return jso; } -int32_t json_object_get_int(struct json_object *jso) +int32_t json_object_get_int(const struct json_object *jso) { int64_t cint64; enum json_type o_type; @@ -511,7 +647,7 @@ int32_t json_object_get_int(struct json_object *jso) * Parse strings into 64-bit numbers, then use the * 64-to-32-bit number handling below. */ - if (json_parse_int64(jso->o.c_string.str, &cint64) != 0) + if (json_parse_int64(get_string_component(jso), &cint64) != 0) return 0; /* whoops, it didn't work. */ o_type = json_type_int; } @@ -521,11 +657,14 @@ int32_t json_object_get_int(struct json_object *jso) /* Make sure we return the correct values for out of range numbers. */ if (cint64 <= INT32_MIN) return INT32_MIN; - else if (cint64 >= INT32_MAX) + if (cint64 >= INT32_MAX) return INT32_MAX; - else - return (int32_t)cint64; + return (int32_t) cint64; case json_type_double: + if (jso->o.c_double <= INT32_MIN) + return INT32_MIN; + if (jso->o.c_double >= INT32_MAX) + return INT32_MAX; return (int32_t)jso->o.c_double; case json_type_boolean: return jso->o.c_boolean; @@ -534,76 +673,221 @@ int32_t json_object_get_int(struct json_object *jso) } } +int json_object_set_int(struct json_object *jso,int new_value){ + if (!jso || jso->o_type!=json_type_int) + return 0; + jso->o.c_int64=new_value; + return 1; +} + struct json_object* json_object_new_int64(int64_t i) { - struct json_object *jso = json_object_new(json_type_int); - if(!jso) return NULL; - jso->_to_json_string = &json_object_int_to_json_string; - jso->o.c_int64 = i; - return jso; + struct json_object *jso = json_object_new(json_type_int); + if (!jso) + return NULL; + jso->_to_json_string = &json_object_int_to_json_string; + jso->o.c_int64 = i; + return jso; } -int64_t json_object_get_int64(struct json_object *jso) +int64_t json_object_get_int64(const struct json_object *jso) { - int64_t cint; + int64_t cint; - if(!jso) return 0; - switch(jso->o_type) { - case json_type_int: - return jso->o.c_int64; - case json_type_double: - return (int64_t)jso->o.c_double; - case json_type_boolean: - return jso->o.c_boolean; - case json_type_string: - if (json_parse_int64(jso->o.c_string.str, &cint) == 0) return cint; - default: - return 0; - } + if (!jso) + return 0; + switch(jso->o_type) + { + case json_type_int: + return jso->o.c_int64; + case json_type_double: + if (jso->o.c_double >= INT64_MAX) + return INT64_MAX; + if (jso->o.c_double <= INT64_MIN) + return INT64_MIN; + return (int64_t)jso->o.c_double; + case json_type_boolean: + return jso->o.c_boolean; + case json_type_string: + if (json_parse_int64(get_string_component(jso), &cint) == 0) + return cint; + /* FALLTHRU */ + default: + return 0; + } } +int json_object_set_int64(struct json_object *jso,int64_t new_value){ + if (!jso || jso->o_type!=json_type_int) + return 0; + jso->o.c_int64=new_value; + return 1; +} + +int json_object_int_inc(struct json_object *jso, int64_t val) { + if (!jso || jso->o_type != json_type_int) + return 0; + if (val > 0 && jso->o.c_int64 > INT64_MAX - val) { + jso->o.c_int64 = INT64_MAX; + } else if (val < 0 && jso->o.c_int64 < INT64_MIN - val) { + jso->o.c_int64 = INT64_MIN; + } else { + jso->o.c_int64 += val; + } + return 1; +} /* json_object_double */ -static int json_object_double_to_json_string(struct json_object* jso, - struct printbuf *pb, - int level, - int flags) +#if defined(HAVE___THREAD) +// i.e. __thread or __declspec(thread) +static SPEC___THREAD char *tls_serialization_float_format = NULL; +#endif +static char *global_serialization_float_format = NULL; + +int json_c_set_serialization_double_format(const char *double_format, int global_or_thread) { - char buf[128], *p, *q; - size_t size; - /* Although JSON RFC does not support - NaN or Infinity as numeric values - ECMA 262 section 9.8.1 defines - how to handle these cases as strings */ - if(isnan(jso->o.c_double)) - size = _snprintf_s(buf, sizeof(buf), _TRUNCATE, "NaN"); - else if(isinf(jso->o.c_double)) - if(jso->o.c_double > 0) - size = _snprintf_s(buf, sizeof(buf), _TRUNCATE, "Infinity"); + if (global_or_thread == JSON_C_OPTION_GLOBAL) + { +#if defined(HAVE___THREAD) + if (tls_serialization_float_format) + { + free(tls_serialization_float_format); + tls_serialization_float_format = NULL; + } +#endif + if (global_serialization_float_format) + free(global_serialization_float_format); + global_serialization_float_format = double_format ? strdup(double_format) : NULL; + } + else if (global_or_thread == JSON_C_OPTION_THREAD) + { +#if defined(HAVE___THREAD) + if (tls_serialization_float_format) + { + free(tls_serialization_float_format); + tls_serialization_float_format = NULL; + } + tls_serialization_float_format = double_format ? strdup(double_format) : NULL; +#else + _json_c_set_last_err("json_c_set_option: not compiled with __thread support\n"); + return -1; +#endif + } else - size = _snprintf_s(buf, sizeof(buf), _TRUNCATE, "-Infinity"); - else - size = _snprintf_s(buf, sizeof(buf), _TRUNCATE, "%.17g", jso->o.c_double); - - p = strchr(buf, ','); - if (p) { - *p = '.'; - } else { - p = strchr(buf, '.'); - } - if (p && (flags & JSON_C_TO_STRING_NOZERO)) { - /* last useful digit, always keep 1 zero */ - p++; - for (q=p ; *q ; q++) { - if (*q!='0') p=q; - } - /* drop trailing zeroes */ - *(++p) = 0; - size = p-buf; - } - printbuf_memappend(pb, buf, size); - return (int)size; + { + _json_c_set_last_err("json_c_set_option: invalid global_or_thread value: %d\n", global_or_thread); + return -1; + } + return 0; +} + + +static int json_object_double_to_json_string_format(struct json_object* jso, + struct printbuf *pb, + int level, + int flags, + const char *format) +{ + char buf[128], *p, *q; + size_t size; + /* Although JSON RFC does not support + NaN or Infinity as numeric values + ECMA 262 section 9.8.1 defines + how to handle these cases as strings */ + if (isnan(jso->o.c_double)) + { + size = snprintf(buf, sizeof(buf), "NaN"); + } + else if (isinf(jso->o.c_double)) + { + if(jso->o.c_double > 0) + size = snprintf(buf, sizeof(buf), "Infinity"); + else + size = snprintf(buf, sizeof(buf), "-Infinity"); + } + else + { + const char *std_format = "%.17g"; + int format_drops_decimals = 0; + + if (!format) + { +#if defined(HAVE___THREAD) + if (tls_serialization_float_format) + format = tls_serialization_float_format; + else +#endif + if (global_serialization_float_format) + format = global_serialization_float_format; + else + format = std_format; + } + size = snprintf(buf, sizeof(buf), format, jso->o.c_double); + + if (size < 0) + return -1; + + p = strchr(buf, ','); + if (p) + *p = '.'; + else + p = strchr(buf, '.'); + + if (format == std_format || strstr(format, ".0f") == NULL) + format_drops_decimals = 1; + + if (size < (int)sizeof(buf) - 2 && + isdigit((int)buf[0]) && /* Looks like *some* kind of number */ + !p && /* Has no decimal point */ + strchr(buf, 'e') == NULL && /* Not scientific notation */ + format_drops_decimals) + { + // Ensure it looks like a float, even if snprintf didn't, + // unless a custom format is set to omit the decimal. + strcat(buf, ".0"); + size += 2; + } + if (p && (flags & JSON_C_TO_STRING_NOZERO)) + { + /* last useful digit, always keep 1 zero */ + p++; + for (q=p ; *q ; q++) { + if (*q!='0') p=q; + } + /* drop trailing zeroes */ + *(++p) = 0; + size = p-buf; + } + } + // although unlikely, snprintf can fail + if (size < 0) + return -1; + + if (size >= (int)sizeof(buf)) + // The standard formats are guaranteed not to overrun the buffer, + // but if a custom one happens to do so, just silently truncate. + size = sizeof(buf) - 1; + printbuf_memappend(pb, buf, size); + return (int)size; +} + +static int json_object_double_to_json_string_default(struct json_object* jso, + struct printbuf *pb, + int level, + int flags) +{ + return json_object_double_to_json_string_format(jso, pb, level, flags, + NULL); +} + +int json_object_double_to_json_string(struct json_object* jso, + struct printbuf *pb, + int level, + int flags) +{ + return json_object_double_to_json_string_format(jso, pb, level, flags, + (const char *)jso->_userdata); } struct json_object* json_object_new_double(double d) @@ -611,25 +895,35 @@ struct json_object* json_object_new_double(double d) struct json_object *jso = json_object_new(json_type_double); if (!jso) return NULL; - jso->_to_json_string = &json_object_double_to_json_string; + jso->_to_json_string = &json_object_double_to_json_string_default; jso->o.c_double = d; return jso; } struct json_object* json_object_new_double_s(double d, const char *ds) { + char *new_ds; struct json_object *jso = json_object_new_double(d); if (!jso) return NULL; - json_object_set_serializer(jso, json_object_userdata_to_json_string, strdup(ds), json_object_free_userdata); + new_ds = strdup(ds); + if (!new_ds) + { + json_object_generic_delete(jso); + errno = ENOMEM; + return NULL; + } + json_object_set_serializer(jso, json_object_userdata_to_json_string, + new_ds, json_object_free_userdata); return jso; } -int json_object_userdata_to_json_string(struct json_object *jso, struct printbuf *pb, int level, int flags) +int json_object_userdata_to_json_string(struct json_object *jso, + struct printbuf *pb, int level, int flags) { - size_t userdata_len = strlen(jso->_userdata); - printbuf_memappend(pb, jso->_userdata, userdata_len); + size_t userdata_len = strlen((const char *)jso->_userdata); + printbuf_memappend(pb, (const char *)jso->_userdata, userdata_len); return (int)userdata_len; } @@ -638,7 +932,7 @@ void json_object_free_userdata(struct json_object *jso, void *userdata) free(userdata); } -double json_object_get_double(struct json_object *jso) +double json_object_get_double(const struct json_object *jso) { double cdouble; char *errPtr = NULL; @@ -653,10 +947,10 @@ double json_object_get_double(struct json_object *jso) return jso->o.c_boolean; case json_type_string: errno = 0; - cdouble = strtod(jso->o.c_string.str,&errPtr); + cdouble = strtod(get_string_component(jso), &errPtr); /* if conversion stopped at the first character, return 0.0 */ - if (errPtr == jso->o.c_string.str) + if (errPtr == get_string_component(jso)) return 0.0; /* @@ -687,6 +981,12 @@ double json_object_get_double(struct json_object *jso) } } +int json_object_set_double(struct json_object *jso,double new_value){ + if (!jso || jso->o_type!=json_type_double) + return 0; + jso->o.c_double=new_value; + return 1; +} /* json_object_string */ @@ -695,65 +995,114 @@ static int json_object_string_to_json_string(struct json_object* jso, int level, int flags) { - sprintbuf(pb, "\""); - json_escape_str(pb, jso->o.c_string.str, jso->o.c_string.len); - sprintbuf(pb, "\""); - return 0; + printbuf_strappend(pb, "\""); + json_escape_str(pb, get_string_component(jso), jso->o.c_string.len, flags); + printbuf_strappend(pb, "\""); + return 0; } static void json_object_string_delete(struct json_object* jso) { - free(jso->o.c_string.str); - json_object_generic_delete(jso); + if(jso->o.c_string.len >= LEN_DIRECT_STRING_DATA) + free(jso->o.c_string.str.ptr); + json_object_generic_delete(jso); } struct json_object* json_object_new_string(const char *s) { - struct json_object *jso = json_object_new(json_type_string); - if(!jso) return NULL; - jso->_delete = &json_object_string_delete; - jso->_to_json_string = &json_object_string_to_json_string; - jso->o.c_string.str = strdup(s); - jso->o.c_string.len = (int)strlen(s); - return jso; + struct json_object *jso = json_object_new(json_type_string); + if (!jso) + return NULL; + jso->_delete = &json_object_string_delete; + jso->_to_json_string = &json_object_string_to_json_string; + jso->o.c_string.len = (int)strlen(s); + if(jso->o.c_string.len < LEN_DIRECT_STRING_DATA) { + memcpy(jso->o.c_string.str.data, s, jso->o.c_string.len); + } else { + jso->o.c_string.str.ptr = strdup(s); + if (!jso->o.c_string.str.ptr) + { + json_object_generic_delete(jso); + errno = ENOMEM; + return NULL; + } + } + return jso; } -struct json_object* json_object_new_string_len(const char *s, size_t len) +struct json_object* json_object_new_string_len(const char *s, int len) { - struct json_object *jso = json_object_new(json_type_string); - if(!jso) return NULL; - jso->_delete = &json_object_string_delete; - jso->_to_json_string = &json_object_string_to_json_string; - jso->o.c_string.str = (char*)malloc(len + 1); - memcpy(jso->o.c_string.str, (void *)s, len); - jso->o.c_string.str[len] = '\0'; - jso->o.c_string.len = len; - return jso; + char *dstbuf; + struct json_object *jso = json_object_new(json_type_string); + if (!jso) + return NULL; + jso->_delete = &json_object_string_delete; + jso->_to_json_string = &json_object_string_to_json_string; + if(len < LEN_DIRECT_STRING_DATA) { + dstbuf = jso->o.c_string.str.data; + } else { + jso->o.c_string.str.ptr = (char*)malloc(len + 1); + if (!jso->o.c_string.str.ptr) + { + json_object_generic_delete(jso); + errno = ENOMEM; + return NULL; + } + dstbuf = jso->o.c_string.str.ptr; + } + memcpy(dstbuf, (const void *)s, len); + dstbuf[len] = '\0'; + jso->o.c_string.len = len; + return jso; } -char* json_object_get_string(struct json_object *jso) +const char* json_object_get_string(struct json_object *jso) { - if (!jso) + if (!jso) return NULL; - switch (jso->o_type) + switch(jso->o_type) { case json_type_string: - return jso->o.c_string.str; + return get_string_component(jso); default: return json_object_to_json_string(jso); } } -int json_object_get_string_len(struct json_object *jso) { - if(!jso) return 0; - switch(jso->o_type) { - case json_type_string: - return (int)jso->o.c_string.len; - default: - return 0; - } +int json_object_get_string_len(const struct json_object *jso) +{ + if (!jso) + return 0; + switch(jso->o_type) + { + case json_type_string: + return jso->o.c_string.len; + default: + return 0; + } +} + +int json_object_set_string(json_object* jso, const char* s) { + return json_object_set_string_len(jso, s, (int)(strlen(s))); } +int json_object_set_string_len(json_object* jso, const char* s, int len){ + char *dstbuf; + if (jso==NULL || jso->o_type!=json_type_string) return 0; + if (leno.c_string.str.data; + if (jso->o.c_string.len>=LEN_DIRECT_STRING_DATA) free(jso->o.c_string.str.ptr); + } else { + dstbuf=(char *)malloc(len+1); + if (dstbuf==NULL) return 0; + if (jso->o.c_string.len>=LEN_DIRECT_STRING_DATA) free(jso->o.c_string.str.ptr); + jso->o.c_string.str.ptr=dstbuf; + } + jso->o.c_string.len=len; + memcpy(dstbuf, (const void *)s, len); + dstbuf[len] = '\0'; + return 1; +} /* json_object_array */ @@ -763,98 +1112,386 @@ static int json_object_array_to_json_string(struct json_object* jso, int flags) { int had_children = 0; - int ii; - sprintbuf(pb, "["); + size_t ii; + + printbuf_strappend(pb, "["); if (flags & JSON_C_TO_STRING_PRETTY) - sprintbuf(pb, "\n"); - for(ii=0; ii < json_object_array_length(jso); ii++) + printbuf_strappend(pb, "\n"); + for(ii=0; ii < (size_t)json_object_array_length(jso); ii++) { struct json_object *val; if (had_children) { - sprintbuf(pb, ","); + printbuf_strappend(pb, ","); if (flags & JSON_C_TO_STRING_PRETTY) - sprintbuf(pb, "\n"); + printbuf_strappend(pb, "\n"); } had_children = 1; if (flags & JSON_C_TO_STRING_SPACED) - sprintbuf(pb, " "); + printbuf_strappend(pb, " "); indent(pb, level + 1, flags); val = json_object_array_get_idx(jso, ii); if(val == NULL) - sprintbuf(pb, "null"); + printbuf_strappend(pb, "null"); else - val->_to_json_string(val, pb, level+1, flags); + if (val->_to_json_string(val, pb, level+1, flags) < 0) + return -1; } if (flags & JSON_C_TO_STRING_PRETTY) { if (had_children) - sprintbuf(pb, "\n"); + printbuf_strappend(pb, "\n"); indent(pb,level,flags); } if (flags & JSON_C_TO_STRING_SPACED) - return sprintbuf(pb, " ]"); - else - return sprintbuf(pb, "]"); + return printbuf_strappend(pb, " ]"); + return printbuf_strappend(pb, "]"); } static void json_object_array_entry_free(void *data) { - json_object_put((struct json_object*)data); + json_object_put((struct json_object*)data); } static void json_object_array_delete(struct json_object* jso) { - array_list_free(jso->o.c_array); - json_object_generic_delete(jso); + array_list_free(jso->o.c_array); + json_object_generic_delete(jso); } struct json_object* json_object_new_array(void) { - struct json_object *jso = json_object_new(json_type_array); - if(!jso) return NULL; - jso->_delete = &json_object_array_delete; - jso->_to_json_string = &json_object_array_to_json_string; - jso->o.c_array = array_list_new(&json_object_array_entry_free); - return jso; + struct json_object *jso = json_object_new(json_type_array); + if (!jso) + return NULL; + jso->_delete = &json_object_array_delete; + jso->_to_json_string = &json_object_array_to_json_string; + jso->o.c_array = array_list_new(&json_object_array_entry_free); + if(jso->o.c_array == NULL) + { + free(jso); + return NULL; + } + return jso; +} + +struct array_list* json_object_get_array(const struct json_object *jso) +{ + if (!jso) + return NULL; + switch(jso->o_type) + { + case json_type_array: + return jso->o.c_array; + default: + return NULL; + } } -struct array_list* json_object_get_array(struct json_object *jso) +void json_object_array_sort(struct json_object *jso, + int(__cdecl* sort_fn)(const void *, const void *)) { - if(!jso) return NULL; - switch(jso->o_type) { - case json_type_array: - return jso->o.c_array; - default: - return NULL; - } + assert(json_object_get_type(jso) == json_type_array); + array_list_sort(jso->o.c_array, sort_fn); } -void json_object_array_sort(struct json_object *jso, int(__cdecl* sort_fn)(const void *, const void *)) +struct json_object* json_object_array_bsearch( + const struct json_object *key, + const struct json_object *jso, + int (__cdecl* sort_fn)(const void *, const void *)) { - array_list_sort(jso->o.c_array, sort_fn); + struct json_object **result; + + assert(json_object_get_type(jso) == json_type_array); + result = (struct json_object **)array_list_bsearch( + (const void **)(void *)&key, jso->o.c_array, sort_fn); + + if (!result) + return NULL; + return *result; } -int json_object_array_length(struct json_object *jso) +int json_object_array_length(const struct json_object *jso) { - return array_list_length(jso->o.c_array); + assert(json_object_get_type(jso) == json_type_array); + return (int)array_list_length(jso->o.c_array); } int json_object_array_add(struct json_object *jso,struct json_object *val) { - return array_list_add(jso->o.c_array, val); + assert(json_object_get_type(jso) == json_type_array); + return array_list_add(jso->o.c_array, val); } -int json_object_array_put_idx(struct json_object *jso, int idx, +int json_object_array_put_idx(struct json_object *jso, size_t idx, struct json_object *val) { - return array_list_put_idx(jso->o.c_array, idx, val); + assert(json_object_get_type(jso) == json_type_array); + return array_list_put_idx(jso->o.c_array, idx, val); +} + +int json_object_array_del_idx(struct json_object *jso, size_t idx, size_t count) +{ + assert(json_object_get_type(jso) == json_type_array); + return array_list_del_idx(jso->o.c_array, idx, count); +} + +struct json_object* json_object_array_get_idx(const struct json_object *jso, + size_t idx) +{ + assert(json_object_get_type(jso) == json_type_array); + return (struct json_object*)array_list_get_idx(jso->o.c_array, idx); +} + +static int json_array_equal(struct json_object* jso1, + struct json_object* jso2) +{ + size_t len, i; + + len = json_object_array_length(jso1); + if (len != json_object_array_length(jso2)) + return 0; + + for (i = 0; i < len; i++) { + if (!json_object_equal(json_object_array_get_idx(jso1, i), + json_object_array_get_idx(jso2, i))) + return 0; + } + return 1; +} + +static int json_object_all_values_equal(struct json_object* jso1, + struct json_object* jso2) +{ + struct json_object_iter iter; + struct json_object *sub; + + assert(json_object_get_type(jso1) == json_type_object); + assert(json_object_get_type(jso2) == json_type_object); + /* Iterate over jso1 keys and see if they exist and are equal in jso2 */ + json_object_object_foreachC(jso1, iter) { + if (!lh_table_lookup_ex(jso2->o.c_object, (void*)iter.key, + (void**)(void *)&sub)) + return 0; + if (!json_object_equal(iter.val, sub)) + return 0; + } + + /* Iterate over jso2 keys to see if any exist that are not in jso1 */ + json_object_object_foreachC(jso2, iter) { + if (!lh_table_lookup_ex(jso1->o.c_object, (void*)iter.key, + (void**)(void *)&sub)) + return 0; + } + + return 1; +} + +int json_object_equal(struct json_object* jso1, struct json_object* jso2) +{ + if (jso1 == jso2) + return 1; + + if (!jso1 || !jso2) + return 0; + + if (jso1->o_type != jso2->o_type) + return 0; + + switch(jso1->o_type) { + case json_type_boolean: + return (jso1->o.c_boolean == jso2->o.c_boolean); + + case json_type_double: + return (jso1->o.c_double == jso2->o.c_double); + + case json_type_int: + return (jso1->o.c_int64 == jso2->o.c_int64); + + case json_type_string: + return (jso1->o.c_string.len == jso2->o.c_string.len && + memcmp(get_string_component(jso1), + get_string_component(jso2), + jso1->o.c_string.len) == 0); + + case json_type_object: + return json_object_all_values_equal(jso1, jso2); + + case json_type_array: + return json_array_equal(jso1, jso2); + + case json_type_null: + return 1; + }; + + return 0; +} + +static int json_object_copy_serializer_data(struct json_object *src, struct json_object *dst) +{ + if (!src->_userdata && !src->_user_delete) + return 0; + + if (dst->_to_json_string == json_object_userdata_to_json_string) + { + dst->_userdata = strdup(src->_userdata); + } + // else if ... other supported serializers ... + else + { + _json_c_set_last_err("json_object_deep_copy: unable to copy unknown serializer data: %p\n", dst->_to_json_string); + return -1; + } + dst->_user_delete = src->_user_delete; + return 0; +} + + +/** + * The default shallow copy implementation. Simply creates a new object of the same + * type but does *not* copy over _userdata nor retain any custom serializer. + * If custom serializers are in use, json_object_deep_copy() must be passed a shallow copy + * implementation that is aware of how to copy them. + * + * This always returns -1 or 1. It will never return 2 since it does not copy the serializer. + */ +int json_c_shallow_copy_default(json_object *src, json_object *parent, const char *key, size_t index, json_object **dst) +{ + switch (src->o_type) { + case json_type_boolean: + *dst = json_object_new_boolean(src->o.c_boolean); + break; + + case json_type_double: + *dst = json_object_new_double(src->o.c_double); + break; + + case json_type_int: + *dst = json_object_new_int64(src->o.c_int64); + break; + + case json_type_string: + *dst = json_object_new_string(get_string_component(src)); + break; + + case json_type_object: + *dst = json_object_new_object(); + break; + + case json_type_array: + *dst = json_object_new_array(); + break; + + default: + errno = EINVAL; + return -1; + } + + if (!*dst) { + errno = ENOMEM; + return -1; + } + (*dst)->_to_json_string = src->_to_json_string; + // _userdata and _user_delete are copied later + return 1; +} + +/* + * The actual guts of json_object_deep_copy(), with a few additional args + * needed so we can keep track of where we are within the object tree. + * + * Note: caller is responsible for freeing *dst if this fails and returns -1. + */ +static int json_object_deep_copy_recursive(struct json_object *src, struct json_object *parent, const char *key_in_parent, size_t index_in_parent, struct json_object **dst, json_c_shallow_copy_fn *shallow_copy) +{ + struct json_object_iter iter; + size_t src_array_len, ii; + + int shallow_copy_rc = 0; + shallow_copy_rc = shallow_copy(src, parent, key_in_parent, index_in_parent, dst); + /* -1=error, 1=object created ok, 2=userdata set */ + if (shallow_copy_rc < 1) + { + errno = EINVAL; + return -1; + } + assert(*dst != NULL); + + switch (src->o_type) { + case json_type_object: + json_object_object_foreachC(src, iter) { + struct json_object *jso = NULL; + /* This handles the `json_type_null` case */ + if (!iter.val) + jso = NULL; + else if (json_object_deep_copy_recursive(iter.val, src, iter.key, -1, &jso, shallow_copy) < 0) + { + json_object_put(jso); + return -1; + } + + if (json_object_object_add(*dst, iter.key, jso) < 0) + { + json_object_put(jso); + return -1; + } + } + break; + + case json_type_array: + src_array_len = json_object_array_length(src); + for (ii = 0; ii < src_array_len; ii++) { + struct json_object *jso = NULL; + struct json_object *jso1 = json_object_array_get_idx(src, ii); + /* This handles the `json_type_null` case */ + if (!jso1) + jso = NULL; + else if (json_object_deep_copy_recursive(jso1, src, NULL, ii, &jso, shallow_copy) < 0) + { + json_object_put(jso); + return -1; + } + + if (json_object_array_add(*dst, jso) < 0) + { + json_object_put(jso); + return -1; + } + } + break; + + default: + break; + /* else, nothing to do, shallow_copy already did. */ + } + + if (shallow_copy_rc != 2) + return json_object_copy_serializer_data(src, *dst); + + return 0; } -struct json_object* json_object_array_get_idx(struct json_object *jso, - int idx) +int json_object_deep_copy(struct json_object *src, struct json_object **dst, json_c_shallow_copy_fn *shallow_copy) { - return (struct json_object*)array_list_get_idx(jso->o.c_array, idx); + int rc; + + /* Check if arguments are sane ; *dst must not point to a non-NULL object */ + if (!src || !dst || *dst) { + errno = EINVAL; + return -1; + } + + if (shallow_copy == NULL) + shallow_copy = json_c_shallow_copy_default; + + rc = json_object_deep_copy_recursive(src, NULL, NULL, -1, dst, shallow_copy); + if (rc < 0) { + json_object_put(*dst); + *dst = NULL; + } + + return rc; } +#pragma warning(pop) diff --git a/phlib/jsonc/json_object.h b/phlib/jsonc/json_object.h index c649ab7c7bfb..7abf821591d1 100644 --- a/phlib/jsonc/json_object.h +++ b/phlib/jsonc/json_object.h @@ -10,6 +10,10 @@ * */ +/** + * @file + * @brief Core json-c API. Start here, or with json_tokener.h + */ #ifndef _json_object_h_ #define _json_object_h_ @@ -17,11 +21,27 @@ #define THIS_FUNCTION_IS_DEPRECATED(func) func __attribute__ ((deprecated)) #elif defined(_MSC_VER) #define THIS_FUNCTION_IS_DEPRECATED(func) __declspec(deprecated) func +#elif defined(__clang__) +#define THIS_FUNCTION_IS_DEPRECATED(func) func __deprecated #else #define THIS_FUNCTION_IS_DEPRECATED(func) func #endif +#ifdef __GNUC__ +#define JSON_C_CONST_FUNCTION(func) func __attribute__((const)) +#else +#define JSON_C_CONST_FUNCTION(func) func +#endif + +#if defined(_MSC_VER) +#define JSON_EXPORT __declspec(dllexport) +#else +#define JSON_EXPORT extern +#endif + +#include #include "json_inttypes.h" +#include "printbuf.h" #ifdef __cplusplus extern "C" { @@ -50,37 +70,95 @@ extern "C" { * for an example of the format. */ #define JSON_C_TO_STRING_PRETTY (1<<1) +/** + * A flag for the json_object_to_json_string_ext() and + * json_object_to_file_ext() functions which causes + * the output to be formatted. + * + * Instead of a "Two Space Tab" this gives a single tab character. + */ +#define JSON_C_TO_STRING_PRETTY_TAB (1<<3) /** * A flag to drop trailing zero for float values */ #define JSON_C_TO_STRING_NOZERO (1<<2) +/** + * Don't escape forward slashes. + */ +#define JSON_C_TO_STRING_NOSLASHESCAPE (1<<4) + +/** + * A flag for the json_object_object_add_ex function which + * causes the value to be added without a check if it already exists. + * Note: it is the responsibilty of the caller to ensure that no + * key is added multiple times. If this is done, results are + * unpredictable. While this option is somewhat dangerous, it + * permits potentially large performance savings in code that + * knows for sure the key values are unique (e.g. because the + * code adds a well-known set of constant key values). + */ +#define JSON_C_OBJECT_ADD_KEY_IS_NEW (1<<1) +/** + * A flag for the json_object_object_add_ex function which + * flags the key as being constant memory. This means that + * the key will NOT be copied via strdup(), resulting in a + * potentially huge performance win (malloc, strdup and + * free are usually performance hogs). It is acceptable to + * use this flag for keys in non-constant memory blocks if + * the caller ensure that the memory holding the key lives + * longer than the corresponding json object. However, this + * is somewhat dangerous and should only be done if really + * justified. + * The general use-case for this flag is cases where the + * key is given as a real constant value in the function + * call, e.g. as in + * json_object_object_add_ex(obj, "ip", json, + * JSON_C_OBJECT_KEY_IS_CONSTANT); + */ +#define JSON_C_OBJECT_KEY_IS_CONSTANT (1<<2) + #undef FALSE #define FALSE ((json_bool)0) #undef TRUE #define TRUE ((json_bool)1) -extern const char *json_number_chars; -extern const char *json_hex_chars; +/** + * Set the global value of an option, which will apply to all + * current and future threads that have not set a thread-local value. + * + * @see json_c_set_serialization_double_format + */ +#define JSON_C_OPTION_GLOBAL (0) +/** + * Set a thread-local value of an option, overriding the global value. + * This will fail if json-c is not compiled with threading enabled, and + * with the __thread specifier (or equivalent) available. + * + * @see json_c_set_serialization_double_format + */ +#define JSON_C_OPTION_THREAD (1) -/* CAW: added for ANSI C iteration correctness */ +/** + * A structure to use with json_object_object_foreachC() loops. + * Contains key, val and entry members. + */ struct json_object_iter { char *key; struct json_object *val; struct lh_entry *entry; }; - -/* forward structure definitions */ +typedef struct json_object_iter json_object_iter; typedef int json_bool; -typedef struct printbuf printbuf; -typedef struct lh_table lh_table; -typedef struct array_list array_list; -typedef struct json_object json_object, *json_object_ptr; -typedef struct json_object_iter json_object_iter; -typedef struct json_tokener json_tokener; + +/** + * @brief The core type for all type of JSON objects handled by json-c + */ +typedef struct json_object json_object; +typedef struct json_object *json_object_ptr; /** * Type of custom user delete functions. See json_object_set_serializer. @@ -105,18 +183,18 @@ typedef enum json_type { json_type_int, json_type_object, json_type_array, - json_type_string, + json_type_string } json_type; /* reference counting functions */ /** - * Increment the reference count of json_object, thereby grabbing shared + * Increment the reference count of json_object, thereby grabbing shared * ownership of obj. * * @param obj the json_object instance */ -extern struct json_object* json_object_get(struct json_object *obj); +JSON_EXPORT struct json_object* json_object_get(struct json_object *obj); /** * Decrement the reference count of json_object and free if it reaches zero. @@ -126,7 +204,7 @@ extern struct json_object* json_object_get(struct json_object *obj); * @param obj the json_object instance * @returns 1 if the object was freed. */ -int json_object_put(struct json_object *obj); +JSON_EXPORT int json_object_put(struct json_object *obj); /** * Check if the json_object is of a given type @@ -138,9 +216,9 @@ int json_object_put(struct json_object *obj); json_type_int, json_type_object, json_type_array, - json_type_string, + json_type_string */ -extern int json_object_is_type(struct json_object *obj, enum json_type type); +JSON_EXPORT int json_object_is_type(const struct json_object *obj, enum json_type type); /** * Get the type of the json_object. See also json_type_to_name() to turn this @@ -154,38 +232,90 @@ extern int json_object_is_type(struct json_object *obj, enum json_type type); json_type_int, json_type_object, json_type_array, - json_type_string, + json_type_string */ -extern enum json_type json_object_get_type(struct json_object *obj); +JSON_EXPORT enum json_type json_object_get_type(const struct json_object *obj); /** Stringify object to json format. * Equivalent to json_object_to_json_string_ext(obj, JSON_C_TO_STRING_SPACED) + * The pointer you get is an internal of your json object. You don't + * have to free it, later use of json_object_put() should be sufficient. + * If you can not ensure there's no concurrent access to *obj use + * strdup(). * @param obj the json_object instance * @returns a string in JSON format */ -extern char* json_object_to_json_string(struct json_object *obj); +JSON_EXPORT const char* json_object_to_json_string(struct json_object *obj); /** Stringify object to json format + * @see json_object_to_json_string() for details on how to free string. * @param obj the json_object instance * @param flags formatting options, see JSON_C_TO_STRING_PRETTY and other constants * @returns a string in JSON format */ -extern char* json_object_to_json_string_ext(struct json_object *obj, int flags); +JSON_EXPORT const char* json_object_to_json_string_ext(struct json_object *obj, int +flags); + +/** Stringify object to json format + * @see json_object_to_json_string() for details on how to free string. + * @param obj the json_object instance + * @param flags formatting options, see JSON_C_TO_STRING_PRETTY and other constants + * @param length a pointer where, if not NULL, the length (without null) is stored + * @returns a string in JSON format and the length if not NULL + */ +JSON_EXPORT const char* json_object_to_json_string_length(struct json_object *obj, int +flags, size_t *length); + +/** + * Returns the userdata set by json_object_set_userdata() or + * json_object_set_serializer() + * + * @param jso the object to return the userdata for + */ +JSON_EXPORT void* json_object_get_userdata(json_object *jso); + +/** + * Set an opaque userdata value for an object + * + * The userdata can be retrieved using json_object_get_userdata(). + * + * If custom userdata is already set on this object, any existing user_delete + * function is called before the new one is set. + * + * The user_delete parameter is optional and may be passed as NULL, even if + * the userdata parameter is non-NULL. It will be called just before the + * json_object is deleted, after it's reference count goes to zero + * (see json_object_put()). + * If this is not provided, it is up to the caller to free the userdata at + * an appropriate time. (i.e. after the json_object is deleted) + * + * Note: Objects created by parsing strings may have custom serializers set + * which expect the userdata to contain specific data (due to use of + * json_object_new_double_s()). In this case, json_object_set_serialiser() with + * NULL as to_string_func should be used instead to set the userdata and reset + * the serializer to its default value. + * + * @param jso the object to set the userdata for + * @param userdata an optional opaque cookie + * @param user_delete an optional function from freeing userdata + */ +JSON_EXPORT void json_object_set_userdata(json_object *jso, void *userdata, + json_object_delete_fn *user_delete); /** * Set a custom serialization function to be used when this particular object * is converted to a string by json_object_to_json_string. * - * If a custom serializer is already set on this object, any existing - * user_delete function is called before the new one is set. + * If custom userdata is already set on this object, any existing user_delete + * function is called before the new one is set. * - * If to_string_func is NULL, the other parameters are ignored - * and the default behaviour is reset. + * If to_string_func is NULL the default behaviour is reset (but the userdata + * and user_delete fields are still set). * - * The userdata parameter is optional and may be passed as NULL. If provided, - * it is passed to to_string_func as-is. This parameter may be NULL even - * if user_delete is non-NULL. + * The userdata parameter is optional and may be passed as NULL. It can be used + * to provide additional data for to_string_func to use. This parameter may + * be NULL even if user_delete is non-NULL. * * The user_delete parameter is optional and may be passed as NULL, even if * the userdata parameter is non-NULL. It will be called just before the @@ -194,16 +324,30 @@ extern char* json_object_to_json_string_ext(struct json_object *obj, int flags); * If this is not provided, it is up to the caller to free the userdata at * an appropriate time. (i.e. after the json_object is deleted) * + * Note that the userdata is the same as set by json_object_set_userdata(), so + * care must be taken not to overwrite the value when both a custom serializer + * and json_object_set_userdata() are used. + * * @param jso the object to customize * @param to_string_func the custom serialization function * @param userdata an optional opaque cookie * @param user_delete an optional function from freeing userdata */ -extern void json_object_set_serializer(json_object *jso, - json_object_to_json_string_fn to_string_func, +JSON_EXPORT void json_object_set_serializer(json_object *jso, + json_object_to_json_string_fn *to_string_func, void *userdata, json_object_delete_fn *user_delete); +#ifdef __clang__ +/* + * Clang doesn't pay attention to the parameters defined in the + * function typedefs used here, so turn off spurious doc warnings. + * { + */ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation" +#endif + /** * Simply call free on the userdata pointer. * Can be used with json_object_set_serializer(). @@ -224,6 +368,11 @@ json_object_delete_fn json_object_free_userdata; */ json_object_to_json_string_fn json_object_userdata_to_json_string; +#ifdef __clang__ +/* } */ +#pragma clang diagnostic pop +#endif + /* object type methods */ @@ -237,18 +386,23 @@ json_object_to_json_string_fn json_object_userdata_to_json_string; * * @returns a json_object of type json_type_object */ -extern struct json_object* json_object_new_object(void); +JSON_EXPORT struct json_object* json_object_new_object(void); /** Get the hashtable of a json_object of type json_type_object * @param obj the json_object instance * @returns a linkhash */ -extern struct lh_table* json_object_get_object(struct json_object *obj); +JSON_EXPORT struct lh_table* json_object_get_object(const struct json_object *obj); /** Get the size of an object in terms of the number of fields it has. * @param obj the json_object whose length to return */ -extern int json_object_object_length(struct json_object* obj); +JSON_EXPORT int json_object_object_length(const struct json_object* obj); + +/** Get the sizeof (struct json_object). + * @returns a size_t with the sizeof (struct json_object) + */ +JSON_C_CONST_FUNCTION(JSON_EXPORT size_t json_c_object_sizeof(void)); /** Add an object field to a json_object of type json_type_object * @@ -265,11 +419,37 @@ extern int json_object_object_length(struct json_object* obj); * @param obj the json_object instance * @param key the object field name (a private copy will be duplicated) * @param val a json_object or NULL member to associate with the given field + * + * @return On success, 0 is returned. + * On error, a negative value is returned. */ -extern void json_object_object_add(struct json_object* obj, const char *key, +JSON_EXPORT int json_object_object_add(struct json_object* obj, const char *key, struct json_object *val); -/** Get the json_object associate with a given object field +/** Add an object field to a json_object of type json_type_object + * + * The semantics are identical to json_object_object_add, except that an + * additional flag fields gives you more control over some detail aspects + * of processing. See the description of JSON_C_OBJECT_ADD_* flags for more + * details. + * + * @param obj the json_object instance + * @param key the object field name (a private copy will be duplicated) + * @param val a json_object or NULL member to associate with the given field + * @param opts process-modifying options. To specify multiple options, use + * arithmetic or (OPT1|OPT2) + */ +JSON_EXPORT int json_object_object_add_ex(struct json_object* obj, + const char *const key, + struct json_object *const val, + const unsigned opts); + +/** Get the json_object associate with a given object field. + * Deprecated/discouraged: used json_object_object_get_ex instead. + * + * This returns NULL if the field is found but its value is null, or if + * the field is not found, or if obj is not a json_type_object. If you + * need to distinguis between these cases, use json_object_object_get_ex(). * * *No* reference counts will be changed. There is no need to manually adjust * reference counts through the json_object_put/json_object_get methods unless @@ -284,14 +464,13 @@ extern void json_object_object_add(struct json_object* obj, const char *key, * @param obj the json_object instance * @param key the object field name * @returns the json_object associated with the given field name - * @deprecated Please use json_object_object_get_ex */ -THIS_FUNCTION_IS_DEPRECATED(extern struct json_object* json_object_object_get(struct json_object* obj, - const char *key)); +JSON_EXPORT struct json_object* json_object_object_get(const struct json_object* obj, + const char *key); -/** Get the json_object associated with a given object field. +/** Get the json_object associated with a given object field. * - * This returns true if the key is found, false in all other cases (including + * This returns true if the key is found, false in all other cases (including * if obj isn't a json_type_object). * * *No* reference counts will be changed. There is no need to manually adjust @@ -301,15 +480,15 @@ THIS_FUNCTION_IS_DEPRECATED(extern struct json_object* json_object_object_get(st * * @param obj the json_object instance * @param key the object field name - * @param value a pointer where to store a reference to the json_object + * @param value a pointer where to store a reference to the json_object * associated with the given field name. * * It is safe to pass a NULL value. * @returns whether or not the key exists */ -extern json_bool json_object_object_get_ex(struct json_object* obj, - const char *key, - struct json_object **value); +JSON_EXPORT json_bool json_object_object_get_ex(const struct json_object* obj, + const char *key, + struct json_object **value); /** Delete the given json_object field * @@ -320,7 +499,7 @@ extern json_bool json_object_object_get_ex(struct json_object* obj, * @param obj the json_object instance * @param key the object field name */ -extern void json_object_object_del(struct json_object* obj, const char *key); +JSON_EXPORT void json_object_object_del(struct json_object* obj, const char *key); /** * Iterate through all keys and values of an object. @@ -338,12 +517,12 @@ extern void json_object_object_del(struct json_object* obj, const char *key); #if defined(__GNUC__) && !defined(__STRICT_ANSI__) && __STDC_VERSION__ >= 199901L # define json_object_object_foreach(obj,key,val) \ - char *key; \ - struct json_object *val __attribute__((__unused__)); \ + char *key = NULL; \ + struct json_object *val __attribute__((__unused__)) = NULL; \ for(struct lh_entry *entry ## key = json_object_get_object(obj)->head, *entry_next ## key = NULL; \ ({ if(entry ## key) { \ - key = (char*)entry ## key->k; \ - val = (struct json_object*)entry ## key->v; \ + key = (char*)lh_entry_k(entry ## key); \ + val = (struct json_object*)lh_entry_v(entry ## key); \ entry_next ## key = entry ## key->next; \ } ; entry ## key; }); \ entry ## key = entry_next ## key ) @@ -351,14 +530,14 @@ extern void json_object_object_del(struct json_object* obj, const char *key); #else /* ANSI C or MSC */ # define json_object_object_foreach(obj,key,val) \ - char *key;\ - struct json_object *val; \ + char *key = NULL;\ + struct json_object *val = NULL; \ struct lh_entry *entry ## key; \ struct lh_entry *entry_next ## key = NULL; \ for(entry ## key = json_object_get_object(obj)->head; \ (entry ## key ? ( \ - key = (char*)entry ## key->k, \ - val = (struct json_object*)entry ## key->v, \ + key = (char*)lh_entry_k(entry ## key), \ + val = (struct json_object*)lh_entry_v(entry ## key), \ entry_next ## key = entry ## key->next, \ entry ## key) : 0); \ entry ## key = entry_next ## key) @@ -367,39 +546,60 @@ extern void json_object_object_del(struct json_object* obj, const char *key); /** Iterate through all keys and values of an object (ANSI C Safe) * @param obj the json_object instance - * @param iter the object iterator + * @param iter the object iterator, use type json_object_iter */ #define json_object_object_foreachC(obj,iter) \ - for(iter.entry = json_object_get_object(obj)->head; (iter.entry ? (iter.key = (char*)iter.entry->k, iter.val = (struct json_object*)iter.entry->v, iter.entry) : 0); iter.entry = iter.entry->next) + for(iter.entry = json_object_get_object(obj)->head; \ + (iter.entry ? (iter.key = (char*)lh_entry_k(iter.entry), iter.val = (struct json_object*)lh_entry_v(iter.entry), iter.entry) : 0); \ + iter.entry = iter.entry->next) /* Array type methods */ /** Create a new empty json_object of type json_type_array * @returns a json_object of type json_type_array */ -extern struct json_object* json_object_new_array(void); +JSON_EXPORT struct json_object* json_object_new_array(void); /** Get the arraylist of a json_object of type json_type_array * @param obj the json_object instance * @returns an arraylist */ -extern struct array_list* json_object_get_array(struct json_object *obj); +JSON_EXPORT struct array_list* json_object_get_array(const struct json_object *obj); /** Get the length of a json_object of type json_type_array * @param obj the json_object instance * @returns an int */ -extern int json_object_array_length(struct json_object *obj); +JSON_EXPORT int json_object_array_length(const struct json_object *obj); /** Sorts the elements of jso of type json_type_array * * Pointers to the json_object pointers will be passed as the two arguments -* to @sort_fn +* to sort_fn * -* @param obj the json_object instance +* @param jso the json_object instance * @param sort_fn a sorting function */ -extern void json_object_array_sort(struct json_object *jso, int(__cdecl* sort_fn)(const void *, const void *)); +JSON_EXPORT void json_object_array_sort(struct json_object *jso, int(__cdecl* sort_fn)(const void *, const void *)); + +/** Binary search a sorted array for a specified key object. + * + * It depends on your compare function what's sufficient as a key. + * Usually you create some dummy object with the parameter compared in + * it, to identify the right item you're actually looking for. + * + * @see json_object_array_sort() for hints on the compare function. + * + * @param key a dummy json_object with the right key + * @param jso the array object we're searching + * @param sort_fn the sort/compare function + * + * @return the wanted json_object instance + */ +JSON_EXPORT struct json_object* json_object_array_bsearch( + const struct json_object *key, + const struct json_object *jso, + int (__cdecl* sort_fn)(const void *, const void *)); /** Add an element to the end of a json_object of type json_type_array * @@ -410,7 +610,7 @@ extern void json_object_array_sort(struct json_object *jso, int(__cdecl* sort_fn * @param obj the json_object instance * @param val the json_object to be added */ -extern int json_object_array_add(struct json_object *obj, +JSON_EXPORT int json_object_array_add(struct json_object *obj, struct json_object *val); /** Insert or replace an element at a specified index in an array (a json_object of type json_type_array) @@ -428,7 +628,7 @@ extern int json_object_array_add(struct json_object *obj, * @param idx the index to insert the element at * @param val the json_object to be added */ -extern int json_object_array_put_idx(struct json_object *obj, int idx, +JSON_EXPORT int json_object_array_put_idx(struct json_object *obj, size_t idx, struct json_object *val); /** Get the element at specificed index of the array (a json_object of type json_type_array) @@ -436,16 +636,29 @@ extern int json_object_array_put_idx(struct json_object *obj, int idx, * @param idx the index to get the element at * @returns the json_object at the specified index (or NULL) */ -extern struct json_object* json_object_array_get_idx(struct json_object *obj, - int idx); +JSON_EXPORT struct json_object* json_object_array_get_idx(const struct json_object *obj, + size_t idx); + +/** Delete an elements from a specified index in an array (a json_object of type json_type_array) + * + * The reference count will be decremented for each of the deleted objects. If there + * are no more owners of an element that is being deleted, then the value is + * freed. Otherwise, the reference to the value will remain in memory. + * + * @param obj the json_object instance + * @param idx the index to start deleting elements at + * @param count the number of elements to delete + * @returns 0 if the elements were successfully deleted + */ +JSON_EXPORT int json_object_array_del_idx(struct json_object *obj, size_t idx, size_t count); /* json_bool type methods */ /** Create a new empty json_object of type json_type_boolean - * @param b a json_bool TRUE or FALSE (0 or 1) + * @param b a json_bool TRUE or FALSE (1 or 0) * @returns a json_object of type json_type_boolean */ -extern struct json_object* json_object_new_boolean(json_bool b); +JSON_EXPORT struct json_object* json_object_new_boolean(json_bool b); /** Get the json_bool value of a json_object * @@ -458,7 +671,20 @@ extern struct json_object* json_object_new_boolean(json_bool b); * @param obj the json_object instance * @returns a json_bool */ -extern json_bool json_object_get_boolean(struct json_object *obj); +JSON_EXPORT json_bool json_object_get_boolean(const struct json_object *obj); + + +/** Set the json_bool value of a json_object + * + * The type of obj is checked to be a json_type_boolean and 0 is returned + * if it is not without any further actions. If type of obj is json_type_boolean + * the obect value is chaned to new_value + * + * @param obj the json_object instance + * @param new_value the value to be set + * @returns 1 if value is set correctly, 0 otherwise + */ +JSON_EXPORT int json_object_set_boolean(struct json_object *obj,json_bool new_value); /* int type methods */ @@ -469,14 +695,14 @@ extern json_bool json_object_get_boolean(struct json_object *obj); * @param i the integer * @returns a json_object of type json_type_int */ -extern struct json_object* json_object_new_int(int32_t i); +JSON_EXPORT struct json_object* json_object_new_int(int32_t i); /** Create a new empty json_object of type json_type_int * @param i the integer * @returns a json_object of type json_type_int */ -extern struct json_object* json_object_new_int64(int64_t i); +JSON_EXPORT struct json_object* json_object_new_int64(int64_t i); /** Get the int value of a json_object @@ -493,7 +719,36 @@ extern struct json_object* json_object_new_int64(int64_t i); * @param obj the json_object instance * @returns an int */ -extern int32_t json_object_get_int(struct json_object *obj); +JSON_EXPORT int32_t json_object_get_int(const struct json_object *obj); + +/** Set the int value of a json_object + * + * The type of obj is checked to be a json_type_int and 0 is returned + * if it is not without any further actions. If type of obj is json_type_int + * the obect value is changed to new_value + * + * @param obj the json_object instance + * @param new_value the value to be set + * @returns 1 if value is set correctly, 0 otherwise + */ +JSON_EXPORT int json_object_set_int(struct json_object *obj,int new_value); + +/** Increment a json_type_int object by the given amount, which may be negative. + * + * If the type of obj is not json_type_int then 0 is returned with no further + * action taken. + * If the addition would result in a overflow, the object value + * is set to INT64_MAX. + * If the addition would result in a underflow, the object value + * is set to INT64_MIN. + * Neither overflow nor underflow affect the return value. + * + * @param obj the json_object instance + * @param val the value to add + * @returns 1 if the increment succeded, 0 otherwise + */ +JSON_EXPORT int json_object_int_inc(struct json_object *obj, int64_t val); + /** Get the int value of a json_object * @@ -508,16 +763,31 @@ extern int32_t json_object_get_int(struct json_object *obj); * @param obj the json_object instance * @returns an int64 */ -extern int64_t json_object_get_int64(struct json_object *obj); +JSON_EXPORT int64_t json_object_get_int64(const struct json_object *obj); +/** Set the int64_t value of a json_object + * + * The type of obj is checked to be a json_type_int and 0 is returned + * if it is not without any further actions. If type of obj is json_type_int + * the obect value is chaned to new_value + * + * @param obj the json_object instance + * @param new_value the value to be set + * @returns 1 if value is set correctly, 0 otherwise + */ +JSON_EXPORT int json_object_set_int64(struct json_object *obj,int64_t new_value); + /* double type methods */ /** Create a new empty json_object of type json_type_double + * + * @see json_object_double_to_json_string() for how to set a custom format string. + * * @param d the double * @returns a json_object of type json_type_double */ -extern struct json_object* json_object_new_double(double d); +JSON_EXPORT struct json_object* json_object_new_double(double d); /** * Create a new json_object of type json_type_double, using @@ -527,20 +797,65 @@ extern struct json_object* json_object_new_double(double d); * inefficiently (e.g. 12.3 => "12.300000000000001") to be * serialized with the more convenient form. * - * Note: this is used by json_tokener_parse_ex() to allow for - * an exact re-serialization of a parsed object. + * Notes: + * + * This is used by json_tokener_parse_ex() to allow for + * an exact re-serialization of a parsed object. + * + * The userdata field is used to store the string representation, so it + * can't be used for other data if this function is used. * * An equivalent sequence of calls is: * @code * jso = json_object_new_double(d); - * json_object_set_serializer(d, json_object_userdata_to_json_string, - * strdup(ds), json_object_free_userdata) + * json_object_set_serializer(jso, json_object_userdata_to_json_string, + * strdup(ds), json_object_free_userdata); * @endcode * * @param d the numeric value of the double. * @param ds the string representation of the double. This will be copied. */ -extern struct json_object* json_object_new_double_s(double d, const char *ds); +JSON_EXPORT struct json_object* json_object_new_double_s(double d, const char *ds); + +/** + * Set a global or thread-local json-c option, depending on whether + * JSON_C_OPTION_GLOBAL or JSON_C_OPTION_THREAD is passed. + * Thread-local options default to undefined, and inherit from the global + * value, even if the global value is changed after the thread is created. + * Attempting to set thread-local options when threading is not compiled in + * will result in an error. Be sure to check the return value. + * + * double_format is a "%g" printf format, such as "%.20g" + * + * @return -1 on errors, 0 on success. + */ +int json_c_set_serialization_double_format(const char *double_format, int global_or_thread); + + + +/** Serialize a json_object of type json_type_double to a string. + * + * This function isn't meant to be called directly. Instead, you can set a + * custom format string for the serialization of this double using the + * following call (where "%.17g" actually is the default): + * + * @code + * jso = json_object_new_double(d); + * json_object_set_serializer(jso, json_object_double_to_json_string, + * "%.17g", NULL); + * @endcode + * + * @see printf(3) man page for format strings + * + * @param jso The json_type_double object that is serialized. + * @param pb The destination buffer. + * @param level Ignored. + * @param flags Ignored. + */ +JSON_EXPORT int json_object_double_to_json_string(struct json_object* jso, + struct printbuf *pb, + int level, + int flags); /** Get the double floating point value of a json_object * @@ -565,7 +880,21 @@ extern struct json_object* json_object_new_double_s(double d, const char *ds); * @param obj the json_object instance * @returns a double floating point number */ -extern double json_object_get_double(struct json_object *obj); +JSON_EXPORT double json_object_get_double(const struct json_object *obj); + + +/** Set the double value of a json_object + * + * The type of obj is checked to be a json_type_double and 0 is returned + * if it is not without any further actions. If type of obj is json_type_double + * the obect value is chaned to new_value + * + * @param obj the json_object instance + * @param new_value the value to be set + * @returns 1 if value is set correctly, 0 otherwise + */ +JSON_EXPORT int json_object_set_double(struct json_object *obj,double new_value); + /* string type methods */ @@ -577,22 +906,27 @@ extern double json_object_get_double(struct json_object *obj); * @param s the string * @returns a json_object of type json_type_string */ -extern struct json_object* json_object_new_string(const char *s); +JSON_EXPORT struct json_object* json_object_new_string(const char *s); -extern struct json_object* json_object_new_string_len(const char *s, size_t len); +JSON_EXPORT struct json_object* json_object_new_string_len(const char *s, int len); /** Get the string value of a json_object * - * If the passed object is not of type json_type_string then the JSON - * representation of the object is returned. + * If the passed object is of type json_type_null (i.e. obj == NULL), + * NULL is returned. + * + * If the passed object of type json_type_string, the string contents + * are returned. + * + * Otherwise the JSON representation of the object is returned. * * The returned string memory is managed by the json_object and will * be freed when the reference count of the json_object drops to zero. * * @param obj the json_object instance - * @returns a string + * @returns a string or NULL */ -extern char* json_object_get_string(struct json_object *obj); +JSON_EXPORT const char* json_object_get_string(struct json_object *obj); /** Get the string length of a json_object * @@ -602,8 +936,98 @@ extern char* json_object_get_string(struct json_object *obj); * @param obj the json_object instance * @returns int */ -extern int json_object_get_string_len(struct json_object *obj); +JSON_EXPORT int json_object_get_string_len(const struct json_object *obj); + + +/** Set the string value of a json_object with zero terminated strings + * equivalent to json_object_set_string_len (obj, new_value, strlen(new_value)) + * @returns 1 if value is set correctly, 0 otherwise + */ +JSON_EXPORT int json_object_set_string(json_object* obj, const char* new_value); + +/** Set the string value of a json_object str + * + * The type of obj is checked to be a json_type_string and 0 is returned + * if it is not without any further actions. If type of obj is json_type_string + * the obect value is chaned to new_value + * + * @param obj the json_object instance + * @param new_value the value to be set; Since string legth is given in len this need not be zero terminated + * @param len the length of new_value + * @returns 1 if value is set correctly, 0 otherwise + */ +JSON_EXPORT int json_object_set_string_len(json_object* obj, const char* new_value, int len); + +/** Check if two json_object's are equal + * + * If the passed objects are equal 1 will be returned. + * Equality is defined as follows: + * - json_objects of different types are never equal + * - json_objects of the same primitive type are equal if the + * c-representation of their value is equal + * - json-arrays are considered equal if all values at the same + * indices are equal (same order) + * - Complex json_objects are considered equal if all + * contained objects referenced by their key are equal, + * regardless their order. + * + * @param obj1 the first json_object instance + * @param obj2 the second json_object instance + * @returns whether both objects are equal or not + */ +JSON_EXPORT int json_object_equal(struct json_object *obj1, + struct json_object *obj2); + +/** + * Perform a shallow copy of src into *dst as part of an overall json_object_deep_copy(). + * + * If src is part of a containing object or array, parent will be non-NULL, + * and key or index will be provided. + * When shallow_copy is called *dst will be NULL, and must be non-NULL when it returns. + * src will never be NULL. + * + * If shallow_copy sets the serializer on an object, return 2 to indicate to + * json_object_deep_copy that it should not attempt to use the standard userdata + * copy function. + * + * @return On success 1 or 2, -1 on errors + */ +typedef int (json_c_shallow_copy_fn)(json_object *src, json_object *parent, const char *key, size_t index, json_object **dst); + +/** + * The default shallow copy implementation for use with json_object_deep_copy(). + * This simply calls the appropriate json_object_new_() function and + * copies over the serializer function (_to_json_string internal field of + * the json_object structure) but not any _userdata or _user_delete values. + * + * If you're writing a custom shallow_copy function, perhaps because you're using + * your own custom serializer, you can call this first to create the new object + * before customizing it with json_object_set_serializer(). + * + * @return 1 on success, -1 on errors, but never 2. + */ +json_c_shallow_copy_fn json_c_shallow_copy_default; + +/** + * Copy the contents of the JSON object. + * The destination object must be initialized to NULL, + * to make sure this function won't overwrite an existing JSON object. + * + * This does roughly the same thing as + * `json_tokener_parse(json_object_get_string(src))`. + * + * @param src source JSON object whose contents will be copied + * @param dst pointer to the destination object where the contents of `src`; + * make sure this pointer is initialized to NULL + * @param shallow_copy an optional function to copy individual objects, needed + * when custom serializers are in use. See also + * json_object set_serializer. + * + * @returns 0 if the copy went well, -1 if an error occured during copy + * or if the destination pointer is non-NULL + */ +JSON_EXPORT int json_object_deep_copy(struct json_object *src, struct json_object **dst, json_c_shallow_copy_fn *shallow_copy); #ifdef __cplusplus } #endif diff --git a/phlib/jsonc/json_object_iterator.c b/phlib/jsonc/json_object_iterator.c index 7066649c3bc5..f8d69ab3689a 100644 --- a/phlib/jsonc/json_object_iterator.c +++ b/phlib/jsonc/json_object_iterator.c @@ -7,11 +7,6 @@ * This library is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See COPYING for details. * -* @brief json-c forces clients to use its private data -* structures for JSON Object iteration. This API -* implementation corrects that by abstracting the -* private json-c details. -* ******************************************************************************* */ @@ -105,7 +100,7 @@ json_object_iter_next(struct json_object_iterator* iter) JASSERT(NULL != iter); JASSERT(kObjectEndIterValue != iter->opaque_); - iter->opaque_ = ((struct lh_entry *)iter->opaque_)->next; + iter->opaque_ = ((const struct lh_entry *)iter->opaque_)->next; } @@ -118,7 +113,7 @@ json_object_iter_peek_name(const struct json_object_iterator* iter) JASSERT(NULL != iter); JASSERT(kObjectEndIterValue != iter->opaque_); - return (const char*)(((struct lh_entry *)iter->opaque_)->k); + return (const char*)(((const struct lh_entry *)iter->opaque_)->k); } @@ -131,7 +126,7 @@ json_object_iter_peek_value(const struct json_object_iterator* iter) JASSERT(NULL != iter); JASSERT(kObjectEndIterValue != iter->opaque_); - return (struct json_object*)(((struct lh_entry *)iter->opaque_)->v); + return (struct json_object*)lh_entry_v((const struct lh_entry *)iter->opaque_); } diff --git a/phlib/jsonc/json_object_iterator.h b/phlib/jsonc/json_object_iterator.h index 44c9fb25b6ca..f226cbd524a3 100644 --- a/phlib/jsonc/json_object_iterator.h +++ b/phlib/jsonc/json_object_iterator.h @@ -7,10 +7,11 @@ * This library is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See COPYING for details. * -* @brief json-c forces clients to use its private data -* structures for JSON Object iteration. This API -* corrects that by abstracting the private json-c -* details. +* @brief An API for iterating over json_type_object objects, +* styled to be familiar to C++ programmers. +* Unlike json_object_object_foreach() and +* json_object_object_foreachC(), this avoids the need to expose +* json-c internals like lh_entry. * * API attributes:
    * * Thread-safe: NO
    diff --git a/phlib/jsonc/json_object_private.h b/phlib/jsonc/json_object_private.h index deff7e8df48f..53be70db0898 100644 --- a/phlib/jsonc/json_object_private.h +++ b/phlib/jsonc/json_object_private.h @@ -9,6 +9,10 @@ * */ +/** + * @file + * @brief Do not use, json-c internal, may be changed or removed at any time. + */ #ifndef _json_object_private_h_ #define _json_object_private_h_ @@ -16,6 +20,8 @@ extern "C" { #endif +#define LEN_DIRECT_STRING_DATA 32 /**< how many bytes are directly stored in json_object for strings? */ + typedef void (json_object_private_delete_fn)(struct json_object *o); struct json_object @@ -32,14 +38,25 @@ struct json_object struct lh_table *c_object; struct array_list *c_array; struct { - char *str; - size_t len; + union { + /* optimize: if we have small strings, we can store them + * directly. This saves considerable CPU cycles AND memory. + */ + char *ptr; + char data[LEN_DIRECT_STRING_DATA]; + } str; + int len; } c_string; } o; json_object_delete_fn *_user_delete; void *_userdata; }; +void _json_c_set_last_err(const char *err_fmt, ...); + +extern const char *json_number_chars; +extern const char *json_hex_chars; + #ifdef __cplusplus } #endif diff --git a/phlib/jsonc/json_pointer.c b/phlib/jsonc/json_pointer.c new file mode 100644 index 000000000000..1ce3feed5a83 --- /dev/null +++ b/phlib/jsonc/json_pointer.c @@ -0,0 +1,327 @@ +/* + * Copyright (c) 2016 Alexandru Ardelean. + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See COPYING for details. + * + */ + +#include "config.h" + +#include "strerror_override.h" + +#include +#include +#include +#include +#include + +#include "json_pointer.h" +#include "strdup_compat.h" +#include "vasprintf_compat.h" + +/** + * JavaScript Object Notation (JSON) Pointer + * RFC 6901 - https://tools.ietf.org/html/rfc6901 + */ + +static void string_replace_all_occurrences_with_char(char *s, const char *occur, char repl_char) +{ + int slen = (int)strlen(s); + int skip = (int)strlen(occur) - 1; /* length of the occurence, minus the char we're replacing */ + char *p = s; + while ((p = strstr(p, occur))) { + *p = repl_char; + p++; + slen -= skip; + memmove(p, (p + skip), slen - (p - s) + 1); /* includes null char too */ + } +} + +static int is_valid_index(struct json_object *jo, const char *path, int32_t *idx) +{ + int i, len = (int)strlen(path); + /* this code-path optimizes a bit, for when we reference the 0-9 index range in a JSON array + and because leading zeros not allowed */ + if (len == 1) { + if (isdigit((int)path[0])) { + *idx = (path[0] - '0'); + goto check_oob; + } + errno = EINVAL; + return 0; + } + /* leading zeros not allowed per RFC */ + if (path[0] == '0') { + errno = EINVAL; + return 0; + } + /* RFC states base-10 decimals */ + for (i = 0; i < len; i++) { + if (!isdigit((int)path[i])) { + errno = EINVAL; + return 0; + } + } + + *idx = strtol(path, NULL, 10); + if (*idx < 0) { + errno = EINVAL; + return 0; + } +check_oob: + len = (int)json_object_array_length(jo); + if (*idx >= len) { + errno = ENOENT; + return 0; + } + + return 1; +} + +static int json_pointer_get_single_path(struct json_object *obj, char *path, struct json_object **value) +{ + if (json_object_is_type(obj, json_type_array)) { + int32_t idx; + if (!is_valid_index(obj, path, &idx)) + return -1; + obj = json_object_array_get_idx(obj, idx); + if (obj) { + if (value) + *value = obj; + return 0; + } + /* Entry not found */ + errno = ENOENT; + return -1; + } + + /* RFC states that we first must eval all ~1 then all ~0 */ + string_replace_all_occurrences_with_char(path, "~1", '/'); + string_replace_all_occurrences_with_char(path, "~0", '~'); + + if (!json_object_object_get_ex(obj, path, value)) { + errno = ENOENT; + return -1; + } + + return 0; +} + +static int json_pointer_set_single_path( + struct json_object *parent, + const char *path, + struct json_object *value) +{ + if (json_object_is_type(parent, json_type_array)) { + int32_t idx; + /* RFC (Chapter 4) states that '-' may be used to add new elements to an array */ + if (path[0] == '-' && path[1] == '\0') + return json_object_array_add(parent, value); + if (!is_valid_index(parent, path, &idx)) + return -1; + return json_object_array_put_idx(parent, idx, value); + } + + /* path replacements should have been done in json_pointer_get_single_path(), + and we should still be good here */ + if (json_object_is_type(parent, json_type_object)) + return json_object_object_add(parent, path, value); + + /* Getting here means that we tried to "dereference" a primitive JSON type (like string, int, bool). + i.e. add a sub-object to it */ + errno = ENOENT; + return -1; +} + +static int json_pointer_get_recursive( + struct json_object *obj, + char *path, + struct json_object **value) +{ + char *endp; + int rc; + + /* All paths (on each recursion level must have a leading '/' */ + if (path[0] != '/') { + errno = EINVAL; + return -1; + } + path++; + + endp = strchr(path, '/'); + if (endp) + *endp = '\0'; + + /* If we err-ed here, return here */ + if ((rc = json_pointer_get_single_path(obj, path, &obj))) + return rc; + + if (endp) { + *endp = '/'; /* Put the slash back, so that the sanity check passes on next recursion level */ + return json_pointer_get_recursive(obj, endp, value); + } + + /* We should be at the end of the recursion here */ + if (value) + *value = obj; + + return 0; +} + +int json_pointer_get(struct json_object *obj, const char *path, struct json_object **res) +{ + char *path_copy = NULL; + int rc; + + if (!obj || !path) { + errno = EINVAL; + return -1; + } + + if (path[0] == '\0') { + if (res) + *res = obj; + return 0; + } + + /* pass a working copy to the recursive call */ + if (!(path_copy = _strdup(path))) { + errno = ENOMEM; + return -1; + } + rc = json_pointer_get_recursive(obj, path_copy, res); + free(path_copy); + + return rc; +} + +int json_pointer_getf(struct json_object *obj, struct json_object **res, const char *path_fmt, ...) +{ + char *path_copy = NULL; + int rc = 0; + va_list args; + + if (!obj || !path_fmt) { + errno = EINVAL; + return -1; + } + + va_start(args, path_fmt); + rc = vasprintf(&path_copy, path_fmt, args); + va_end(args); + + if (rc < 0) + return rc; + + if (path_copy[0] == '\0') { + if (res) + *res = obj; + goto out; + } + + rc = json_pointer_get_recursive(obj, path_copy, res); +out: + free(path_copy); + + return rc; +} + +int json_pointer_set(struct json_object **obj, const char *path, struct json_object *value) +{ + const char *endp; + char *path_copy = NULL; + struct json_object *set = NULL; + int rc; + + if (!obj || !path) { + errno = EINVAL; + return -1; + } + + if (path[0] == '\0') { + json_object_put(*obj); + *obj = value; + return 0; + } + + if (path[0] != '/') { + errno = EINVAL; + return -1; + } + + /* If there's only 1 level to set, stop here */ + if ((endp = strrchr(path, '/')) == path) { + path++; + return json_pointer_set_single_path(*obj, path, value); + } + + /* pass a working copy to the recursive call */ + if (!(path_copy = strdup(path))) { + errno = ENOMEM; + return -1; + } + path_copy[endp - path] = '\0'; + rc = json_pointer_get_recursive(*obj, path_copy, &set); + free(path_copy); + + if (rc) + return rc; + + endp++; + return json_pointer_set_single_path(set, endp, value); +} + +int json_pointer_setf(struct json_object **obj, struct json_object *value, const char *path_fmt, ...) +{ + char *endp; + char *path_copy = NULL; + struct json_object *set = NULL; + va_list args; + int rc = 0; + + if (!obj || !path_fmt) { + errno = EINVAL; + return -1; + } + + /* pass a working copy to the recursive call */ + va_start(args, path_fmt); + rc = vasprintf(&path_copy, path_fmt, args); + va_end(args); + + if (rc < 0) + return rc; + + if (path_copy[0] == '\0') { + json_object_put(*obj); + *obj = value; + goto out; + } + + if (path_copy[0] != '/') { + errno = EINVAL; + rc = -1; + goto out; + } + + /* If there's only 1 level to set, stop here */ + if ((endp = strrchr(path_copy, '/')) == path_copy) { + set = *obj; + goto set_single_path; + } + + *endp = '\0'; + rc = json_pointer_get_recursive(*obj, path_copy, &set); + + if (rc) + goto out; + +set_single_path: + endp++; + rc = json_pointer_set_single_path(set, endp, value); +out: + free(path_copy); + return rc; +} + diff --git a/phlib/jsonc/json_pointer.h b/phlib/jsonc/json_pointer.h new file mode 100644 index 000000000000..b8746c0c9707 --- /dev/null +++ b/phlib/jsonc/json_pointer.h @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2016 Alexadru Ardelean. + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See COPYING for details. + * + */ + +/** + * @file + * @brief JSON Pointer (RFC 6901) implementation for retrieving + * objects from a json-c object tree. + */ +#ifndef _json_pointer_h_ +#define _json_pointer_h_ + +#include "json_object.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Retrieves a JSON sub-object from inside another JSON object + * using the JSON pointer notation as defined in RFC 6901 + * https://tools.ietf.org/html/rfc6901 + * + * The returned JSON sub-object is equivalent to parsing manually the + * 'obj' JSON tree ; i.e. it's not a new object that is created, but rather + * a pointer inside the JSON tree. + * + * Internally, this is equivalent to doing a series of 'json_object_object_get()' + * and 'json_object_array_get_idx()' along the given 'path'. + * + * Note that the 'path' string supports 'printf()' type arguments, so, whatever + * is added after the 'res' param will be treated as an argument for 'path' + * Example: json_pointer_get(obj, "/foo/%d/%s", &res, 0, bar) + * This means, that you need to escape '%' with '%%' (just like in printf()) + * + * @param obj the json_object instance/tree from where to retrieve sub-objects + * @param path a (RFC6901) string notation for the sub-object to retrieve + * @param res a pointer where to store a reference to the json_object + * associated with the given path + * + * @return negative if an error (or not found), or 0 if succeeded + */ +int json_pointer_get(struct json_object *obj, const char *path, struct json_object **res); + +/** + * This is a variant of 'json_pointer_get()' that supports printf() style arguments. + * + * Example: json_pointer_getf(obj, res, "/foo/%d/%s", 0, bak) + * This also means that you need to escape '%' with '%%' (just like in printf()) + * + * Please take into consideration all recommended 'printf()' format security + * aspects when using this function. + * + * @param obj the json_object instance/tree to which to add a sub-object + * @param res a pointer where to store a reference to the json_object + * associated with the given path + * @param path_fmt a printf() style format for the path + * + * @return negative if an error (or not found), or 0 if succeeded + */ +int json_pointer_getf(struct json_object *obj, struct json_object **res, const char *path_fmt, ...); + +/** + * Sets JSON object 'value' in the 'obj' tree at the location specified + * by the 'path'. 'path' is JSON pointer notation as defined in RFC 6901 + * https://tools.ietf.org/html/rfc6901 + * + * Note that 'obj' is a double pointer, mostly for the "" (empty string) + * case, where the entire JSON object would be replaced by 'value'. + * In the case of the "" path, the object at '*obj' will have it's refcount + * decremented with 'json_object_put()' and the 'value' object will be assigned to it. + * + * For other cases (JSON sub-objects) ownership of 'value' will be transferred into + * '*obj' via 'json_object_object_add()' & 'json_object_array_put_idx()', so the + * only time the refcount should be decremented for 'value' is when the return value of + * 'json_pointer_set()' is negative (meaning the 'value' object did not get set into '*obj'). + * + * That also implies that 'json_pointer_set()' does not do any refcount incrementing. + * (Just that single decrement that was mentioned above). + * + * Note that the 'path' string supports 'printf()' type arguments, so, whatever + * is added after the 'value' param will be treated as an argument for 'path' + * Example: json_pointer_set(obj, "/foo/%d/%s", value, 0, bak) + * This means, that you need to escape '%' with '%%' (just like in printf()) + * + * @param obj the json_object instance/tree to which to add a sub-object + * @param path a (RFC6901) string notation for the sub-object to set in the tree + * @param value object to set at path + * + * @return negative if an error (or not found), or 0 if succeeded + */ +int json_pointer_set(struct json_object **obj, const char *path, struct json_object *value); + +/** + * This is a variant of 'json_pointer_set()' that supports printf() style arguments. + * + * Example: json_pointer_setf(obj, value, "/foo/%d/%s", 0, bak) + * This also means that you need to escape '%' with '%%' (just like in printf()) + * + * Please take into consideration all recommended 'printf()' format security + * aspects when using this function. + * + * @param obj the json_object instance/tree to which to add a sub-object + * @param value object to set at path + * @param path_fmt a printf() style format for the path + * + * @return negative if an error (or not found), or 0 if succeeded + */ +int json_pointer_setf(struct json_object **obj, struct json_object *value, const char *path_fmt, ...); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/phlib/jsonc/json_tokener.c b/phlib/jsonc/json_tokener.c index 2959cbd6aea2..8ad430d25c31 100644 --- a/phlib/jsonc/json_tokener.c +++ b/phlib/jsonc/json_tokener.c @@ -16,6 +16,7 @@ #include "config.h" #include +#include "math_compat.h" #include #include #include @@ -23,25 +24,24 @@ #include #include -#include "bits.h" #include "debug.h" #include "printbuf.h" #include "arraylist.h" #include "json_inttypes.h" #include "json_object.h" +#include "json_object_private.h" #include "json_tokener.h" #include "json_util.h" +#include "strdup_compat.h" #ifdef HAVE_LOCALE_H #include #endif /* HAVE_LOCALE_H */ +#ifdef HAVE_XLOCALE_H +#include +#endif -#if !HAVE_STRDUP && defined(_MSC_VER) - /* MSC has the version as _strdup */ -# define strdup _strdup -#elif !HAVE_STRDUP -# error You do not have strdup on your system. -#endif /* HAVE_STRDUP */ +#define jt_hexdigit(x) (((x) <= '9') ? (x) - '0' : ((x) & 7) + 9) #if !HAVE_STRNCASECMP && defined(_MSC_VER) /* MSC has the version as _strnicmp */ @@ -58,7 +58,8 @@ static const char json_null_str[] = "null"; static const int json_null_str_len = sizeof(json_null_str) - 1; static const char json_inf_str[] = "Infinity"; -static const int json_inf_str_len = sizeof(json_inf_str) - 1; +static const char json_inf_str_lower[] = "infinity"; +static const unsigned int json_inf_str_len = sizeof(json_inf_str) - 1; static const char json_nan_str[] = "NaN"; static const int json_nan_str_len = sizeof(json_nan_str) - 1; static const char json_true_str[] = "true"; @@ -86,13 +87,15 @@ static const char* json_tokener_errors[] = { const char *json_tokener_error_desc(enum json_tokener_error jerr) { - int jerr_int = (int)jerr; - if (jerr_int < 0 || jerr_int >= (int)(sizeof(json_tokener_errors) / sizeof(json_tokener_errors[0]))) - return "Unknown error, invalid json_tokener_error value passed to json_tokener_error_desc()"; + int jerr_int = (int) jerr; + if (jerr_int < 0 || + jerr_int >= (int)(sizeof(json_tokener_errors) / sizeof(json_tokener_errors[0]))) + return "Unknown error, " + "invalid json_tokener_error value passed to json_tokener_error_desc()"; return json_tokener_errors[jerr]; } -enum json_tokener_error json_tokener_get_error(json_tokener *tok) +enum json_tokener_error json_tokener_get_error(struct json_tokener *tok) { return tok->err; } @@ -109,7 +112,8 @@ struct json_tokener* json_tokener_new_ex(int depth) tok = (struct json_tokener*)calloc(1, sizeof(struct json_tokener)); if (!tok) return NULL; - tok->stack = (struct json_tokener_srec *)calloc(depth, sizeof(struct json_tokener_srec)); + tok->stack = (struct json_tokener_srec *) calloc(depth, + sizeof(struct json_tokener_srec)); if (!tok->stack) { free(tok); return NULL; @@ -129,7 +133,7 @@ void json_tokener_free(struct json_tokener *tok) { json_tokener_reset(tok); if (tok->pb) printbuf_free(tok->pb); - if (tok->stack) free(tok->stack); + free(tok->stack); free(tok); } @@ -163,7 +167,8 @@ struct json_object* json_tokener_parse(const char *str) return obj; } -struct json_object* json_tokener_parse_verbose(const char *str, enum json_tokener_error *error) +struct json_object* json_tokener_parse_verbose(const char *str, + enum json_tokener_error *error) { struct json_tokener* tok; struct json_object* obj; @@ -206,14 +211,17 @@ struct json_object* json_tokener_parse_verbose(const char *str, enum json_tokene * Returns 1 on success, sets tok->err and returns 0 if no more chars. * Implicit inputs: str, len vars */ -#define PEEK_CHAR(dest, tok) \ - (((tok)->char_offset == len) ? \ - (((tok)->depth == 0 && state == json_tokener_state_eatws && saved_state == json_tokener_state_finish) ? \ - (((tok)->err = json_tokener_success), 0) \ - : \ - (((tok)->err = json_tokener_continue), 0) \ - ) : \ - (((dest) = *str), 1) \ +#define PEEK_CHAR(dest, tok) \ + (((tok)->char_offset == len) ? \ + (((tok)->depth == 0 && \ + state == json_tokener_state_eatws && \ + saved_state == json_tokener_state_finish \ + ) ? \ + (((tok)->err = json_tokener_success), 0) \ + : \ + (((tok)->err = json_tokener_continue), 0) \ + ) : \ + (((dest) = *str), 1) \ ) /* ADVANCE_CHAR() macro: @@ -233,12 +241,11 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, { struct json_object *obj = NULL; char c = '\1'; -#ifdef HAVE_SETLOCALE - char *oldlocale=NULL, *tmplocale; - - tmplocale = setlocale(LC_NUMERIC, NULL); - if (tmplocale) oldlocale = strdup(tmplocale); - setlocale(LC_NUMERIC, "C"); +#ifdef HAVE_USELOCALE + locale_t oldlocale = uselocale(NULL); + locale_t newloc; +#elif defined(HAVE_SETLOCALE) + char *oldlocale = NULL; #endif tok->char_offset = 0; @@ -254,6 +261,33 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, return NULL; } +#ifdef HAVE_USELOCALE + { + locale_t duploc = duplocale(oldlocale); + newloc = newlocale(LC_NUMERIC, "C", duploc); + // XXX at least Debian 8.4 has a bug in newlocale where it doesn't + // change the decimal separator unless you set LC_TIME! + if (newloc) + { + duploc = newloc; // original duploc has been freed by newlocale() + newloc = newlocale(LC_TIME, "C", duploc); + } + if (newloc == NULL) + { + freelocale(duploc); + return NULL; + } + uselocale(newloc); + } +#elif defined(HAVE_SETLOCALE) + { + char *tmplocale; + tmplocale = setlocale(LC_NUMERIC, NULL); + if (tmplocale) oldlocale = strdup(tmplocale); + setlocale(LC_NUMERIC, "C"); + } +#endif + while (PEEK_CHAR(c, tok)) { redo_char: @@ -281,11 +315,15 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, state = json_tokener_state_eatws; saved_state = json_tokener_state_object_field_start; current = json_object_new_object(); + if(current == NULL) + goto out; break; case '[': state = json_tokener_state_eatws; saved_state = json_tokener_state_array; current = json_object_new_array(); + if(current == NULL) + goto out; break; case 'I': case 'i': @@ -305,6 +343,7 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, tok->err = json_tokener_error_parse_unexpected; goto out; } + /* FALLTHRU */ case '"': state = json_tokener_state_string; printbuf_reset(tok->pb); @@ -318,9 +357,6 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, printbuf_reset(tok->pb); tok->st_pos = 0; goto redo_char; -#if defined(__GNUC__) - case '0' ... '9': -#else case '0': case '1': case '2': @@ -331,7 +367,6 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, case '7': case '8': case '9': -#endif case '-': state = json_tokener_state_number; printbuf_reset(tok->pb); @@ -350,38 +385,55 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, tok->depth--; goto redo_char; - case json_tokener_state_inf: /* aka starts with 'i' */ + case json_tokener_state_inf: /* aka starts with 'i' (or 'I', or "-i", or "-I") */ { - int size; - int size_inf; + /* If we were guaranteed to have len set, then we could (usually) handle + * the entire "Infinity" check in a single strncmp (strncasecmp), but + * since len might be -1 (i.e. "read until \0"), we need to check it + * a character at a time. + * Trying to handle it both ways would make this code considerably more + * complicated with likely little performance benefit. + */ int is_negative = 0; + const char *_json_inf_str = json_inf_str; + if (!(tok->flags & JSON_TOKENER_STRICT)) + _json_inf_str = json_inf_str_lower; - printbuf_memappend_fast(tok->pb, &c, 1); - size = json_min(tok->st_pos+1, json_null_str_len); - size_inf = json_min(tok->st_pos+1, json_inf_str_len); - char *infbuf = tok->pb->buf; - if (*infbuf == '-') + /* Note: tok->st_pos must be 0 when state is set to json_tokener_state_inf */ + while (tok->st_pos < (int)json_inf_str_len) { - infbuf++; - is_negative = 1; - } - if ((!(tok->flags & JSON_TOKENER_STRICT) && - strncasecmp(json_inf_str, infbuf, size_inf) == 0) || - (strncmp(json_inf_str, infbuf, size_inf) == 0) - ) - { - if (tok->st_pos == json_inf_str_len) + char inf_char = *str; + if (!(tok->flags & JSON_TOKENER_STRICT)) + inf_char = tolower((int)*str); + if (inf_char != _json_inf_str[tok->st_pos]) { - current = json_object_new_double(is_negative ? -INFINITY : INFINITY); - saved_state = json_tokener_state_finish; - state = json_tokener_state_eatws; - goto redo_char; + tok->err = json_tokener_error_parse_unexpected; + goto out; + } + tok->st_pos++; + (void)ADVANCE_CHAR(str, tok); + if (!PEEK_CHAR(c, tok)) + { + /* out of input chars, for now at least */ + goto out; } - } else { - tok->err = json_tokener_error_parse_unexpected; - goto out; } - tok->st_pos++; + /* We checked the full length of "Infinity", so create the object. + * When handling -Infinity, the number parsing code will have dropped + * the "-" into tok->pb for us, so check it now. + */ + if (printbuf_length(tok->pb) > 0 && *(tok->pb->buf) == '-') + { + is_negative = 1; + } + current = json_object_new_double(is_negative + ? -INFINITY : INFINITY); + if (current == NULL) + goto out; + saved_state = json_tokener_state_finish; + state = json_tokener_state_eatws; + goto redo_char; + } break; case json_tokener_state_null: /* aka starts with 'n' */ @@ -410,6 +462,8 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, if (tok->st_pos == json_nan_str_len) { current = json_object_new_double(NAN); + if (current == NULL) + goto out; saved_state = json_tokener_state_finish; state = json_tokener_state_eatws; goto redo_char; @@ -482,7 +536,9 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, while(1) { if(c == tok->quote_char) { printbuf_memappend_fast(tok->pb, case_start, str-case_start); - current = json_object_new_string_len(tok->pb->buf, tok->pb->bpos); + current = json_object_new_string_len(tok->pb->buf, (int)tok->pb->bpos); + if(current == NULL) + goto out; saved_state = json_tokener_state_finish; state = json_tokener_state_eatws; break; @@ -537,8 +593,8 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, /* Handle a 4-byte sequence, or two sequences if a surrogate pair */ while(1) { - if(strchr(json_hex_chars, c)) { - tok->ucs_char += ((unsigned int)hexdigit(c) << ((3-tok->st_pos++)*4)); + if (c && strchr(json_hex_chars, c)) { + tok->ucs_char += ((unsigned int)jt_hexdigit(c) << ((3-tok->st_pos++)*4)); if(tok->st_pos == 4) { unsigned char unescaped_utf[4]; @@ -568,8 +624,8 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, */ got_hi_surrogate = tok->ucs_char; /* Not at end, and the next two chars should be "\u" */ - if ((tok->char_offset+1 != len) && - (tok->char_offset+2 != len) && + if ((len == -1 || len > (tok->char_offset + 2)) && + // str[0] != '0' && // implied by json_hex_chars, above. (str[1] == '\\') && (str[2] == 'u')) { @@ -578,13 +634,15 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, * characters. */ if( !ADVANCE_CHAR(str, tok) || !ADVANCE_CHAR(str, tok) ) { - printbuf_memappend_fast(tok->pb, (char*)utf8_replacement_char, 3); - } + printbuf_memappend_fast(tok->pb, + (char*) utf8_replacement_char, 3); + } /* Advance to the first char of the next sequence and * continue processing with the next sequence. */ if (!ADVANCE_CHAR(str, tok) || !PEEK_CHAR(c, tok)) { - printbuf_memappend_fast(tok->pb, (char*)utf8_replacement_char, 3); + printbuf_memappend_fast(tok->pb, + (char*) utf8_replacement_char, 3); goto out; } tok->ucs_char = 0; @@ -595,7 +653,8 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, * it. Put a replacement char in for the hi surrogate * and pretend we finished. */ - printbuf_memappend_fast(tok->pb, (char*)utf8_replacement_char, 3); + printbuf_memappend_fast(tok->pb, + (char*) utf8_replacement_char, 3); } } else if (IS_LOW_SURROGATE(tok->ucs_char)) { /* Got a low surrogate not preceded by a high */ @@ -643,6 +702,8 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, ) { if(tok->st_pos == json_true_str_len) { current = json_object_new_boolean(1); + if(current == NULL) + goto out; saved_state = json_tokener_state_finish; state = json_tokener_state_eatws; goto redo_char; @@ -652,6 +713,8 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, || (strncmp(json_false_str, tok->pb->buf, size2) == 0)) { if(tok->st_pos == json_false_str_len) { current = json_object_new_boolean(0); + if(current == NULL) + goto out; saved_state = json_tokener_state_finish; state = json_tokener_state_eatws; goto redo_char; @@ -669,10 +732,45 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, /* Advance until we change state */ const char *case_start = str; int case_len=0; + int is_exponent=0; + int negativesign_next_possible_location=1; while(c && strchr(json_number_chars, c)) { ++case_len; - if(c == '.' || c == 'e' || c == 'E') + + /* non-digit characters checks */ + /* note: since the main loop condition to get here was + an input starting with 0-9 or '-', we are + protected from input starting with '.' or + e/E. */ + if (c == '.') { + if (tok->is_double != 0) { + /* '.' can only be found once, and out of the exponent part. + Thus, if the input is already flagged as double, it + is invalid. */ + tok->err = json_tokener_error_parse_number; + goto out; + } + tok->is_double = 1; + } + if (c == 'e' || c == 'E') { + if (is_exponent != 0) { + /* only one exponent possible */ + tok->err = json_tokener_error_parse_number; + goto out; + } + is_exponent = 1; tok->is_double = 1; + /* the exponent part can begin with a negative sign */ + negativesign_next_possible_location = case_len + 1; + } + if (c == '-' && case_len != negativesign_next_possible_location) { + /* If the negative sign is not where expected (ie + start of input or start of exponent part), the + input is invalid. */ + tok->err = json_tokener_error_parse_number; + goto out; + } + if (!ADVANCE_CHAR(str, tok) || !PEEK_CHAR(c, tok)) { printbuf_memappend_fast(tok->pb, case_start, case_len); goto out; @@ -682,10 +780,11 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, printbuf_memappend_fast(tok->pb, case_start, case_len); // Check for -Infinity - if (tok->pb->buf[0] == '-' && case_len == 1 && + if (tok->pb->buf[0] == '-' && case_len <= 1 && (c == 'i' || c == 'I')) { state = json_tokener_state_inf; + tok->st_pos = 0; goto redo_char; } } @@ -693,16 +792,21 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, int64_t num64; double numd; if (!tok->is_double && json_parse_int64(tok->pb->buf, &num64) == 0) { - if (num64 && tok->pb->buf[0]=='0' && (tok->flags & JSON_TOKENER_STRICT)) { + if (num64 && tok->pb->buf[0]=='0' && + (tok->flags & JSON_TOKENER_STRICT)) { /* in strict mode, number must not start with 0 */ tok->err = json_tokener_error_parse_number; goto out; } current = json_object_new_int64(num64); + if(current == NULL) + goto out; } else if(tok->is_double && json_parse_double(tok->pb->buf, &numd) == 0) { current = json_object_new_double_s(numd, tok->pb->buf); + if(current == NULL) + goto out; } else { tok->err = json_tokener_error_parse_number; goto out; @@ -716,12 +820,12 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, case json_tokener_state_array_after_sep: case json_tokener_state_array: if(c == ']') { - if (state == json_tokener_state_array_after_sep && - (tok->flags & JSON_TOKENER_STRICT)) - { - tok->err = json_tokener_error_parse_unexpected; - goto out; - } + if (state == json_tokener_state_array_after_sep && + (tok->flags & JSON_TOKENER_STRICT)) + { + tok->err = json_tokener_error_parse_unexpected; + goto out; + } saved_state = json_tokener_state_finish; state = json_tokener_state_eatws; } else { @@ -737,7 +841,8 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, break; case json_tokener_state_array_add: - json_object_array_add(current, obj); + if( json_object_array_add(current, obj) != 0 ) + goto out; saved_state = json_tokener_state_array_sep; state = json_tokener_state_eatws; goto redo_char; @@ -830,6 +935,7 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, goto redo_char; case json_tokener_state_object_sep: + /* { */ if(c == '}') { saved_state = json_tokener_state_finish; state = json_tokener_state_eatws; @@ -845,7 +951,7 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, } if (!ADVANCE_CHAR(str, tok)) goto out; - } /* while(POP_CHAR) */ + } /* while(PEEK_CHAR) */ out: if (c && @@ -861,9 +967,12 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, tok->err = json_tokener_error_parse_eof; } -#ifdef HAVE_SETLOCALE +#ifdef HAVE_USELOCALE + uselocale(oldlocale); + freelocale(newloc); +#elif defined(HAVE_SETLOCALE) setlocale(LC_NUMERIC, oldlocale); - if (oldlocale) free(oldlocale); + free(oldlocale); #endif if (tok->err == json_tokener_success) diff --git a/phlib/jsonc/json_tokener.h b/phlib/jsonc/json_tokener.h index a72d2bdefe00..ed272b673dfd 100644 --- a/phlib/jsonc/json_tokener.h +++ b/phlib/jsonc/json_tokener.h @@ -9,6 +9,10 @@ * */ +/** + * @file + * @brief Methods to parse an input string into a tree of json_object objects. + */ #ifndef _json_tokener_h_ #define _json_tokener_h_ @@ -86,6 +90,10 @@ struct json_tokener struct json_tokener_srec *stack; int flags; }; +/** + * @deprecated Unused in json-c code + */ +typedef struct json_tokener json_tokener; /** * Be strict when parsing JSON input. Use caution with @@ -116,34 +124,34 @@ const char *json_tokener_error_desc(enum json_tokener_error jerr); * * See also json_tokener_error_desc(). */ -enum json_tokener_error json_tokener_get_error(struct json_tokener *tok); +JSON_EXPORT enum json_tokener_error json_tokener_get_error(struct json_tokener *tok); -extern struct json_tokener* json_tokener_new(void); -extern struct json_tokener* json_tokener_new_ex(int depth); -extern void json_tokener_free(struct json_tokener *tok); -extern void json_tokener_reset(struct json_tokener *tok); -extern struct json_object* json_tokener_parse(const char *str); -extern struct json_object* json_tokener_parse_verbose(const char *str, enum json_tokener_error *error); +JSON_EXPORT struct json_tokener* json_tokener_new(void); +JSON_EXPORT struct json_tokener* json_tokener_new_ex(int depth); +JSON_EXPORT void json_tokener_free(struct json_tokener *tok); +JSON_EXPORT void json_tokener_reset(struct json_tokener *tok); +JSON_EXPORT struct json_object* json_tokener_parse(const char *str); +JSON_EXPORT struct json_object* json_tokener_parse_verbose(const char *str, enum json_tokener_error *error); /** * Set flags that control how parsing will be done. */ -extern void json_tokener_set_flags(struct json_tokener *tok, int flags); +JSON_EXPORT void json_tokener_set_flags(struct json_tokener *tok, int flags); -/** +/** * Parse a string and return a non-NULL json_object if a valid JSON value * is found. The string does not need to be a JSON object or array; * it can also be a string, number or boolean value. * * A partial JSON string can be parsed. If the parsing is incomplete, - * NULL will be returned and json_tokener_get_error() will be return + * NULL will be returned and json_tokener_get_error() will return * json_tokener_continue. * json_tokener_parse_ex() can then be called with additional bytes in str - * to continue the parsing. + * to continue the parsing. * - * If json_tokener_parse_ex() returns NULL and the error anything other than + * If json_tokener_parse_ex() returns NULL and the error is anything other than * json_tokener_continue, a fatal error has occurred and parsing must be - * halted. Then tok object must not be re-used until json_tokener_reset() is + * halted. Then, the tok object must not be reused until json_tokener_reset() is * called. * * When a valid JSON value is parsed, a non-NULL json_object will be @@ -152,7 +160,7 @@ extern void json_tokener_set_flags(struct json_tokener *tok, int flags); * json_object_get_type() before using the object. * * @b XXX this shouldn't use internal fields: - * Trailing characters after the parsed value do not automatically cause an + * Trailing characters after the parsed value do not automatically cause an * error. It is up to the caller to decide whether to treat this as an * error or to handle the additional characters, perhaps by parsing another * json value starting from that point. @@ -198,7 +206,7 @@ if (tok->char_offset < stringlen) // XXX shouldn't access internal fields * @param str an string with any valid JSON expression, or portion of. This does not need to be null terminated. * @param len the length of str */ -extern struct json_object* json_tokener_parse_ex(struct json_tokener *tok, +JSON_EXPORT struct json_object* json_tokener_parse_ex(struct json_tokener *tok, const char *str, int len); #ifdef __cplusplus diff --git a/phlib/jsonc/json_util.c b/phlib/jsonc/json_util.c index 077777afe9e9..79480d5dae8e 100644 --- a/phlib/jsonc/json_util.c +++ b/phlib/jsonc/json_util.c @@ -15,12 +15,14 @@ #include "config.h" #undef realloc +#include "strerror_override.h" + +#include #include #include #include #include #include -#include #include #ifdef HAVE_SYS_TYPES_H @@ -40,6 +42,10 @@ #endif /* HAVE_UNISTD_H */ #ifdef _WIN32 +# if MSC_VER < 1800 +/* strtoll is available only since Visual Studio 2013 */ +# define strtoll _strtoi64 +# endif # define WIN32_LEAN_AND_MEAN # include # include @@ -49,14 +55,8 @@ # define open _open #endif -#if !defined(HAVE_SNPRINTF) && defined(_MSC_VER) - /* MSC has the version as _snprintf */ -# define snprintf _snprintf -#elif !defined(HAVE_SNPRINTF) -# error You do not have snprintf on your system. -#endif /* HAVE_SNPRINTF */ +#include "snprintf_compat.h" -#include "bits.h" #include "debug.h" #include "printbuf.h" #include "json_inttypes.h" @@ -64,11 +64,51 @@ #include "json_tokener.h" #include "json_util.h" -static int sscanf_is_broken = 0; -static int sscanf_is_broken_testdone = 0; -static void sscanf_is_broken_test(void); +static int _json_object_to_fd(int fd, struct json_object *obj, int flags, const char *filename); + +static char _last_err[256] = ""; + +const char *json_util_get_last_err() +{ + if (_last_err[0] == '\0') + return NULL; + return _last_err; +} -struct json_object* json_object_from_file(wchar_t *filename) +void _json_c_set_last_err(const char *err_fmt, ...) +{ + va_list ap; + va_start(ap, err_fmt); + // Ignore (attempted) overruns from snprintf + (void)vsnprintf(_last_err, sizeof(_last_err), err_fmt, ap); + va_end(ap); +} + +struct json_object* json_object_from_fd(int fd) +{ + struct printbuf *pb; + struct json_object *obj; + char buf[JSON_FILE_BUF_SIZE]; + int ret; + + if(!(pb = printbuf_new())) { + _json_c_set_last_err("json_object_from_file: printbuf_new failed\n"); + return NULL; + } + while((ret = _read(fd, buf, JSON_FILE_BUF_SIZE)) > 0) { + printbuf_memappend(pb, buf, ret); + } + if(ret < 0) { + _json_c_set_last_err("json_object_from_fd: error reading fd %d: %s\n", fd, strerror(errno)); + printbuf_free(pb); + return NULL; + } + obj = json_tokener_parse(pb->buf); + printbuf_free(pb); + return obj; +} + +struct json_object* json_object_from_file(wchar_t * filename) { NTSTATUS status; HANDLE fileHandle; @@ -135,14 +175,14 @@ struct json_object* json_object_from_file(wchar_t *filename) /* extended "format and write to file" function */ -int json_object_to_file_ext(wchar_t *filename, struct json_object *obj, int flags) +int json_object_to_file_ext(wchar_t * filename, struct json_object *obj, int flags) { NTSTATUS status; HANDLE fileHandle; IO_STATUS_BLOCK isb; PSTR json_str; - - if (!(json_str = json_object_to_json_string_ext(obj, flags))) + + if (!(json_str = (PSTR)json_object_to_json_string_ext(obj, flags))) return -1; status = PhCreateFileWin32( @@ -159,14 +199,14 @@ int json_object_to_file_ext(wchar_t *filename, struct json_object *obj, int flag return -1; status = NtWriteFile( - fileHandle, - NULL, - NULL, + fileHandle, + NULL, + NULL, NULL, - &isb, - json_str, + &isb, + json_str, (ULONG)strlen(json_str), - NULL, + NULL, NULL ); @@ -180,130 +220,67 @@ int json_object_to_file_ext(wchar_t *filename, struct json_object *obj, int flag return 0; } -// backwards compatible "format and write to file" function - -int json_object_to_file(wchar_t *FileName, struct json_object *obj) +int json_object_to_fd(int fd, struct json_object *obj, int flags) { - return json_object_to_file_ext(FileName, obj, JSON_C_TO_STRING_PRETTY); -} + if (!obj) { + _json_c_set_last_err("json_object_to_fd: object is null\n"); + return -1; + } -int json_parse_double(const char *buf, double *retval) -{ - return (sscanf_s(buf, "%lf", retval)==1 ? 0 : 1); + return _json_object_to_fd(fd, obj, flags, NULL); } - -/* - * Not all implementations of sscanf actually work properly. - * Check whether the one we're currently using does, and if - * it's broken, enable the workaround code. - */ -static void sscanf_is_broken_test() +static int _json_object_to_fd(int fd, struct json_object *obj, int flags, const char *filename) { - int64_t num64; - int ret_errno, is_int64_min, ret_errno2, is_int64_max; + int ret; + const char *json_str; + unsigned int wpos, wsize; - sscanf_s(" -01234567890123456789012345", "%" SCNd64, &num64); - ret_errno = errno; - is_int64_min = (num64 == INT64_MIN); + filename = filename ? filename : "(fd)"; - sscanf_s(" 01234567890123456789012345", "%" SCNd64, &num64); - ret_errno2 = errno; - is_int64_max = (num64 == INT64_MAX); - - if (ret_errno != ERANGE || !is_int64_min || - ret_errno2 != ERANGE || !is_int64_max) - { - MC_DEBUG("sscanf_is_broken_test failed, enabling workaround code\n"); - sscanf_is_broken = 1; + if (!(json_str = json_object_to_json_string_ext(obj,flags))) { + return -1; } -} -int json_parse_int64(const char *buf, int64_t *retval) -{ - int64_t num64; - const char *buf_sig_digits; - int orig_has_neg; - int saved_errno; + wsize = (unsigned int)(strlen(json_str) & UINT_MAX); /* CAW: probably unnecessary, but the most 64bit safe */ + wpos = 0; + while(wpos < wsize) { + if((ret = _write(fd, json_str + wpos, wsize-wpos)) < 0) { + _json_c_set_last_err("json_object_to_file: error writing file %s: %s\n", + filename, strerror(errno)); + return -1; + } - if (!sscanf_is_broken_testdone) - { - sscanf_is_broken_test(); - sscanf_is_broken_testdone = 1; + /* because of the above check for ret < 0, we can safely cast and add */ + wpos += (unsigned int)ret; } - // Skip leading spaces - while (isspace((int)*buf) && *buf) - buf++; - - errno = 0; // sscanf won't always set errno, so initialize + return 0; +} - if (sscanf_s(buf, "%" SCNd64, &num64) != 1) - { - MC_DEBUG("Failed to parse, sscanf != 1\n"); - return 1; - } +// backwards compatible "format and write to file" function - saved_errno = errno; - buf_sig_digits = buf; - orig_has_neg = 0; - if (*buf_sig_digits == '-') - { - buf_sig_digits++; - orig_has_neg = 1; - } +int json_object_to_file(wchar_t *filename, struct json_object *obj) +{ + return json_object_to_file_ext(filename, obj, JSON_C_TO_STRING_PLAIN); +} - // Not all sscanf implementations actually work - if (sscanf_is_broken && saved_errno != ERANGE) - { - char buf_cmp[100]; - char *buf_cmp_start = buf_cmp; - int recheck_has_neg = 0; - int buf_cmp_len; - - // Skip leading zeros, but keep at least one digit - while (buf_sig_digits[0] == '0' && buf_sig_digits[1] != '\0') - buf_sig_digits++; - if (num64 == 0) // assume all sscanf impl's will parse -0 to 0 - orig_has_neg = 0; // "-0" is the same as just plain "0" - - _snprintf_s(buf_cmp_start, sizeof(buf_cmp), _TRUNCATE, "%" PRId64, num64); - if (*buf_cmp_start == '-') - { - recheck_has_neg = 1; - buf_cmp_start++; - } - // No need to skip leading spaces or zeros here. - - buf_cmp_len = (int)strlen(buf_cmp_start); - /** - * If the sign is different, or - * some of the digits are different, or - * there is another digit present in the original string - * then we have NOT successfully parsed the value. - */ - if (orig_has_neg != recheck_has_neg || - strncmp(buf_sig_digits, buf_cmp_start, strlen(buf_cmp_start)) != 0 || - ((int)strlen(buf_sig_digits) != buf_cmp_len && - isdigit((int)buf_sig_digits[buf_cmp_len]) - ) - ) - { - saved_errno = ERANGE; - } - } +int json_parse_double(const char *buf, double *retval) +{ + char *end; + *retval = strtod(buf, &end); + return end == buf ? 1 : 0; +} - // Not all sscanf impl's set the value properly when out of range. - // Always do this, even for properly functioning implementations, - // since it shouldn't slow things down much. - if (saved_errno == ERANGE) - { - if (orig_has_neg) - num64 = INT64_MIN; - else - num64 = INT64_MAX; - } - *retval = num64; - return 0; +int json_parse_int64(const char *buf, int64_t *retval) +{ + char *end = NULL; + int64_t val; + + errno = 0; + val = strtoll(buf, &end, 10); + if (end != buf) + *retval = val; + return ((val == 0 && errno != 0) || (end == buf)) ? 1 : 0; } #ifndef HAVE_REALLOC @@ -334,7 +311,7 @@ const char *json_type_to_name(enum json_type o_type) int o_type_int = (int)o_type; if (o_type_int < 0 || o_type_int >= (int)NELEM(json_type_name)) { - MC_ERROR("json_type_to_name: type %d is out of range [0,%d]\n", o_type, NELEM(json_type_name)); + _json_c_set_last_err("json_type_to_name: type %d is out of range [0,%d]\n", o_type, NELEM(json_type_name)); return NULL; } return json_type_name[o_type]; diff --git a/phlib/jsonc/json_util.h b/phlib/jsonc/json_util.h index e9aea4876a66..83a75b99c6e5 100644 --- a/phlib/jsonc/json_util.h +++ b/phlib/jsonc/json_util.h @@ -9,11 +9,24 @@ * */ +/** + * @file + * @brief Miscllaneous utility functions and macros. + */ #ifndef _json_util_h_ #define _json_util_h_ #include "json_object.h" +#ifndef json_min +#define json_min(a,b) ((a) < (b) ? (a) : (b)) +#endif + +#ifndef json_max +#define json_max(a,b) ((a) > (b) ? (a) : (b)) +#endif + + #ifdef __cplusplus extern "C" { #endif @@ -21,13 +34,65 @@ extern "C" { #define JSON_FILE_BUF_SIZE 4096 /* utility functions */ -extern struct json_object* json_object_from_file(wchar_t *filename); -extern int json_object_to_file(wchar_t *FileName, struct json_object *obj); -extern int json_object_to_file_ext(wchar_t *FileName, struct json_object *obj, int flags); +/** + * Read the full contents of the given file, then convert it to a + * json_object using json_tokener_parse(). + * + * Returns -1 if something fails. See json_util_get_last_err() for details. + */ +extern struct json_object* json_object_from_file(wchar_t * filename); + +/** + * Create a JSON object from already opened file descriptor. + * + * This function can be helpful, when you opened the file already, + * e.g. when you have a temp file. + * Note, that the fd must be readable at the actual position, i.e. + * use lseek(fd, 0, SEEK_SET) before. + * + * Returns -1 if something fails. See json_util_get_last_err() for details. + */ +extern struct json_object* json_object_from_fd(int fd); + +/** + * Equivalent to: + * json_object_to_file_ext(filename, obj, JSON_C_TO_STRING_PLAIN); + * + * Returns -1 if something fails. See json_util_get_last_err() for details. + */ +extern int json_object_to_file(wchar_t *filename, struct json_object *obj); + +/** + * Open and truncate the given file, creating it if necessary, then + * convert the json_object to a string and write it to the file. + * + * Returns -1 if something fails. See json_util_get_last_err() for details. + */ +extern int json_object_to_file_ext(wchar_t *filename, struct json_object *obj, int flags); + +/** + * Convert the json_object to a string and write it to the file descriptor. + * Handles partial writes and will keep writing until done, or an error + * occurs. + * + * @param fd an open, writable file descriptor to write to + * @param obj the object to serializer and write + * @param flags flags to pass to json_object_to_json_string_ext() + * @return -1 if something fails. See json_util_get_last_err() for details. + */ +extern int json_object_to_fd(int fd, struct json_object *obj, int flags); + +/** + * Return the last error from various json-c functions, including: + * json_object_to_file{,_ext}, json_object_to_fd() or + * json_object_from_{file,fd}, or NULL if there is none. + */ +const char *json_util_get_last_err(void); + + extern int json_parse_int64(const char *buf, int64_t *retval); extern int json_parse_double(const char *buf, double *retval); - /** * Return a string describing the type of the object. * e.g. "int", or "object", etc... diff --git a/phlib/jsonc/json_visit.c b/phlib/jsonc/json_visit.c new file mode 100644 index 000000000000..df92fee23007 --- /dev/null +++ b/phlib/jsonc/json_visit.c @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2016 Eric Haszlakiewicz + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See COPYING for details. + */ + +#include + +#include "config.h" +#include "json_inttypes.h" +#include "json_object.h" +#include "json_visit.h" +#include "linkhash.h" + +static int _json_c_visit(json_object *jso, json_object *parent_jso, + const char *jso_key, size_t *jso_index, + json_c_visit_userfunc *userfunc, void *userarg); + +int json_c_visit(json_object *jso, int future_flags, + json_c_visit_userfunc *userfunc, void *userarg) +{ + int ret = _json_c_visit(jso, NULL, NULL, NULL, userfunc, userarg); + switch(ret) + { + case JSON_C_VISIT_RETURN_CONTINUE: + case JSON_C_VISIT_RETURN_SKIP: + case JSON_C_VISIT_RETURN_POP: + case JSON_C_VISIT_RETURN_STOP: + return 0; + default: + return JSON_C_VISIT_RETURN_ERROR; + } +} +static int _json_c_visit(json_object *jso, json_object *parent_jso, + const char *jso_key, size_t *jso_index, + json_c_visit_userfunc *userfunc, void *userarg) +{ + int userret = userfunc(jso, 0, parent_jso, jso_key, jso_index, userarg); + switch(userret) + { + case JSON_C_VISIT_RETURN_CONTINUE: + break; + case JSON_C_VISIT_RETURN_SKIP: + case JSON_C_VISIT_RETURN_POP: + case JSON_C_VISIT_RETURN_STOP: + case JSON_C_VISIT_RETURN_ERROR: + return userret; + default: + fprintf(stderr, "ERROR: invalid return value from json_c_visit userfunc: %d\n", userret); + return JSON_C_VISIT_RETURN_ERROR; + } + + switch(json_object_get_type(jso)) + { + case json_type_null: + case json_type_boolean: + case json_type_double: + case json_type_int: + case json_type_string: + // we already called userfunc above, move on to the next object + return JSON_C_VISIT_RETURN_CONTINUE; + + case json_type_object: + { + json_object_object_foreach(jso, key, child) + { + userret = _json_c_visit(child, jso, key, NULL, userfunc, userarg); + if (userret == JSON_C_VISIT_RETURN_POP) + break; + if (userret == JSON_C_VISIT_RETURN_STOP || + userret == JSON_C_VISIT_RETURN_ERROR) + return userret; + if (userret != JSON_C_VISIT_RETURN_CONTINUE && + userret != JSON_C_VISIT_RETURN_SKIP) + { + fprintf(stderr, "INTERNAL ERROR: _json_c_visit returned %d\n", userret); + return JSON_C_VISIT_RETURN_ERROR; + } + } + break; + } + case json_type_array: + { + size_t array_len = json_object_array_length(jso); + size_t ii; + for (ii = 0; ii < array_len; ii++) + { + json_object *child = json_object_array_get_idx(jso, ii); + userret = _json_c_visit(child, jso, NULL, &ii, userfunc, userarg); + if (userret == JSON_C_VISIT_RETURN_POP) + break; + if (userret == JSON_C_VISIT_RETURN_STOP || + userret == JSON_C_VISIT_RETURN_ERROR) + return userret; + if (userret != JSON_C_VISIT_RETURN_CONTINUE && + userret != JSON_C_VISIT_RETURN_SKIP) + { + fprintf(stderr, "INTERNAL ERROR: _json_c_visit returned %d\n", userret); + return JSON_C_VISIT_RETURN_ERROR; + } + } + break; + } + default: + fprintf(stderr, "INTERNAL ERROR: _json_c_visit found object of unknown type: %d\n", json_object_get_type(jso)); + return JSON_C_VISIT_RETURN_ERROR; + } + + // Call userfunc for the second type on container types, after all + // members of the container have been visited. + // Non-container types will have already returned before this point. + + userret = userfunc(jso, JSON_C_VISIT_SECOND, parent_jso, jso_key, jso_index, userarg); + switch(userret) + { + case JSON_C_VISIT_RETURN_SKIP: + case JSON_C_VISIT_RETURN_POP: + // These are not really sensible during JSON_C_VISIT_SECOND, + // but map them to JSON_C_VISIT_CONTINUE anyway. + // FALLTHROUGH + case JSON_C_VISIT_RETURN_CONTINUE: + return JSON_C_VISIT_RETURN_CONTINUE; + case JSON_C_VISIT_RETURN_STOP: + case JSON_C_VISIT_RETURN_ERROR: + return userret; + default: + fprintf(stderr, "ERROR: invalid return value from json_c_visit userfunc: %d\n", userret); + return JSON_C_VISIT_RETURN_ERROR; + } + // NOTREACHED +} + diff --git a/phlib/jsonc/json_visit.h b/phlib/jsonc/json_visit.h new file mode 100644 index 000000000000..b147d99ebc84 --- /dev/null +++ b/phlib/jsonc/json_visit.h @@ -0,0 +1,95 @@ + +#ifndef _json_c_json_visit_h_ +#define _json_c_json_visit_h_ + +/** + * @file + * @brief Methods for walking a tree of objects. + */ +#include "json_object.h" + +typedef int (json_c_visit_userfunc)(json_object *jso, int flags, + json_object *parent_jso, const char *jso_key, + size_t *jso_index, void *userarg); + +/** + * Visit each object in the JSON hierarchy starting at jso. + * For each object, userfunc is called, passing the object and userarg. + * If the object has a parent (i.e. anything other than jso itself) + * its parent will be passed as parent_jso, and either jso_key or jso_index + * will be set, depending on whether the parent is an object or an array. + * + * Nodes will be visited depth first, but containers (arrays and objects) + * will be visited twice, the second time with JSON_C_VISIT_SECOND set in + * flags. + * + * userfunc must return one of the defined return values, to indicate + * whether and how to continue visiting nodes, or one of various ways to stop. + * + * Returns 0 if nodes were visited successfully, even if some were + * intentionally skipped due to what userfunc returned. + * Returns <0 if an error occurred during iteration, including if + * userfunc returned JSON_C_VISIT_RETURN_ERROR. + */ +int json_c_visit(json_object *jso, int future_flags, + json_c_visit_userfunc *userfunc, void *userarg); + +/** + * Passed to json_c_visit_userfunc as one of the flags values to indicate + * that this is the second time a container (array or object) is being + * called, after all of it's members have been iterated over. + */ +#define JSON_C_VISIT_SECOND 0x02 + +/** + * This json_c_visit_userfunc return value indicates that iteration + * should proceed normally. + */ +#define JSON_C_VISIT_RETURN_CONTINUE 0 + + +/** + * This json_c_visit_userfunc return value indicates that iteration + * over the members of the current object should be skipped. + * If the current object isn't a container (array or object), this + * is no different than JSON_C_VISIT_RETURN_CONTINUE. + */ +#define JSON_C_VISIT_RETURN_SKIP 7547 + +/** + * This json_c_visit_userfunc return value indicates that iteration + * of the fields/elements of the containing object should stop + * and continue "popped up" a level of the object hierarchy. + * For example, returning this when handling arg will result in + * arg3 and any other fields being skipped. The next call to userfunc + * will be the JSON_C_VISIT_SECOND call on "foo", followed by a userfunc + * call on "bar". + *

    + * {
    + *   "foo": {
    + *     "arg1": 1,
    + *     "arg2": 2,
    + *     "arg3": 3,
    + *     ...
    + *   },
    + *   "bar": {
    + *     ...
    + *   }
    + * }
    + * 
    + */ +#define JSON_C_VISIT_RETURN_POP 767 + +/** + * This json_c_visit_userfunc return value indicates that iteration + * should stop immediately, and cause json_c_visit to return success. + */ +#define JSON_C_VISIT_RETURN_STOP 7867 + +/** + * This json_c_visit_userfunc return value indicates that iteration + * should stop immediately, and cause json_c_visit to return an error. + */ +#define JSON_C_VISIT_RETURN_ERROR -1 + +#endif /* _json_c_json_visit_h_ */ diff --git a/phlib/jsonc/libjson.c b/phlib/jsonc/libjson.c index 5284fd0e70b7..b19df42f7298 100644 --- a/phlib/jsonc/libjson.c +++ b/phlib/jsonc/libjson.c @@ -16,7 +16,7 @@ #define __warn_references(sym,msg) /* nothing */ #endif -#endif +#endif #include "json_object.h" diff --git a/phlib/jsonc/linkhash.c b/phlib/jsonc/linkhash.c index 50de485638e7..5497061a8a15 100644 --- a/phlib/jsonc/linkhash.c +++ b/phlib/jsonc/linkhash.c @@ -10,6 +10,8 @@ * */ +#include "config.h" + #include #include #include @@ -17,36 +19,60 @@ #include #include -#include - #ifdef HAVE_ENDIAN_H # include /* attempt to define endianness */ #endif +#if defined(_MSC_VER) || defined(__MINGW32__) +# define WIN32_LEAN_AND_MEAN +# include /* Get InterlockedCompareExchange */ +#endif + #include "random_seed.h" #include "linkhash.h" +/* hash functions */ +static unsigned long lh_char_hash(const void *k); +static unsigned long lh_perllike_str_hash(const void *k); +static lh_hash_fn *char_hash_fn = lh_char_hash; + +int +json_global_set_string_hash(const int h) +{ + switch(h) { + case JSON_C_STR_HASH_DFLT: + char_hash_fn = lh_char_hash; + break; + case JSON_C_STR_HASH_PERLLIKE: + char_hash_fn = lh_perllike_str_hash; + break; + default: + return -1; + } + return 0; +} + void lh_abort(const char *msg, ...) { - va_list ap; - va_start(ap, msg); - vprintf(msg, ap); - va_end(ap); - exit(1); + va_list ap; + va_start(ap, msg); + vprintf(msg, ap); + va_end(ap); + exit(1); } -unsigned long lh_ptr_hash(const void *k) +static unsigned long lh_ptr_hash(const void *k) { - /* CAW: refactored to be 64bit nice */ - return (unsigned long)((((ptrdiff_t)k * LH_PRIME) >> 4) & ULONG_MAX); + /* CAW: refactored to be 64bit nice */ + return (unsigned long)((((ptrdiff_t)k * LH_PRIME) >> 4) & ULONG_MAX); } int lh_ptr_equal(const void *k1, const void *k2) { - return (k1 == k2); + return (k1 == k2); } -/* +/* * hashlittle from lookup3.c, by Bob Jenkins, May 2006, Public Domain. * http://burtleburtle.net/bob/c/lookup3.c * minor modifications to make functions static so no symbols are exported @@ -58,8 +84,8 @@ int lh_ptr_equal(const void *k1, const void *k2) lookup3.c, by Bob Jenkins, May 2006, Public Domain. These are functions for producing 32-bit hashes for hash table lookup. -hashword(), hashlittle(), hashlittle2(), hashbig(), mix(), and final() -are externally useful functions. Routines to test the hash are included +hashword(), hashlittle(), hashlittle2(), hashbig(), mix(), and final() +are externally useful functions. Routines to test the hash are included if SELF_TEST is defined. You can use this free for any purpose. It's in the public domain. It has no warranty. @@ -67,7 +93,7 @@ You probably want to use hashlittle(). hashlittle() and hashbig() hash byte arrays. hashlittle() is is faster than hashbig() on little-endian machines. Intel and AMD are little-endian machines. On second thought, you probably want hashlittle2(), which is identical to -hashlittle() except it returns two 32-bit hashes for the price of one. +hashlittle() except it returns two 32-bit hashes for the price of one. You could implement hashbig2() if you wanted but I haven't bothered here. If you want to find a hash of, say, exactly 7 integers, do @@ -80,9 +106,9 @@ If you want to find a hash of, say, exactly 7 integers, do then use c as the hash value. If you have a variable length array of 4-byte integers to hash, use hashword(). If you have a byte array (like a character string), use hashlittle(). If you have several byte arrays, or -a mix of things, see the comments above hashlittle(). +a mix of things, see the comments above hashlittle(). -Why is this so big? I read 12 bytes at a time into 3 4-byte integers, +Why is this so big? I read 12 bytes at a time into 3 4-byte integers, then mix those integers. This is fast (you can do a lot more thorough mixing with 12*3 instructions on 3 integers than you can with 3 instructions on 1 byte), but shoehorning those bytes into integers efficiently is messy. @@ -131,7 +157,7 @@ This was tested for: the output delta to a Gray code (a^(a>>1)) so a string of 1's (as is commonly produced by subtraction) look like a single 1-bit difference. -* the base values were pseudorandom, all zero but one bit set, or +* the base values were pseudorandom, all zero but one bit set, or all zero plus a counter that starts at zero. Some k values for my "a-=c; a^=rot(c,k); c+=b;" arrangement that @@ -141,7 +167,7 @@ satisfy this are 14 9 3 7 17 3 Well, "9 15 3 18 27 15" didn't quite get 32 bits diffing for "differ" defined as + with a one-bit base and a two-bit delta. I -used http://burtleburtle.net/bob/hash/avalanche.html to choose +used http://burtleburtle.net/bob/hash/avalanche.html to choose the operations, constants, and arrangements of the variables. This does not achieve avalanche. There are input bits of (a,b,c) @@ -180,7 +206,7 @@ produce values of c that look totally different. This was tested for the output delta to a Gray code (a^(a>>1)) so a string of 1's (as is commonly produced by subtraction) look like a single 1-bit difference. -* the base values were pseudorandom, all zero but one bit set, or +* the base values were pseudorandom, all zero but one bit set, or all zero plus a counter that starts at zero. These constants passed: @@ -255,7 +281,7 @@ static uint32_t hashlittle( const void *key, size_t length, uint32_t initval) } /*----------------------------- handle the last (probably partial) block */ - /* + /* * "k[2]&0xffffff" actually reads beyond the end of the string, but * then masks off the part it's not allowed to read. Because the * string is aligned, the masked-off tail is in the same word as the @@ -263,8 +289,19 @@ static uint32_t hashlittle( const void *key, size_t length, uint32_t initval) * does it on word boundaries, so is OK with this. But VALGRIND will * still catch it and complain. The masking trick does make the hash * noticably faster for short strings (like English words). + * AddressSanitizer is similarly picky about overrunning + * the buffer. (http://clang.llvm.org/docs/AddressSanitizer.html */ -#ifndef VALGRIND +#ifdef VALGRIND +# define PRECISE_MEMORY_ACCESS 1 +#elif defined(__SANITIZE_ADDRESS__) /* GCC's ASAN */ +# define PRECISE_MEMORY_ACCESS 1 +#elif defined(__has_feature) +# if __has_feature(address_sanitizer) /* Clang's ASAN */ +# define PRECISE_MEMORY_ACCESS 1 +# endif +#endif +#ifndef PRECISE_MEMORY_ACCESS switch(length) { @@ -378,17 +415,17 @@ static uint32_t hashlittle( const void *key, size_t length, uint32_t initval) /*-------------------------------- last block: affect all 32 bits of (c) */ switch(length) /* all the case statements fall through */ { - case 12: c+=((uint32_t)k[11])<<24; - case 11: c+=((uint32_t)k[10])<<16; - case 10: c+=((uint32_t)k[9])<<8; - case 9 : c+=k[8]; - case 8 : b+=((uint32_t)k[7])<<24; - case 7 : b+=((uint32_t)k[6])<<16; - case 6 : b+=((uint32_t)k[5])<<8; - case 5 : b+=k[4]; - case 4 : a+=((uint32_t)k[3])<<24; - case 3 : a+=((uint32_t)k[2])<<16; - case 2 : a+=((uint32_t)k[1])<<8; + case 12: c+=((uint32_t)k[11])<<24; /* FALLTHRU */ + case 11: c+=((uint32_t)k[10])<<16; /* FALLTHRU */ + case 10: c+=((uint32_t)k[9])<<8; /* FALLTHRU */ + case 9 : c+=k[8]; /* FALLTHRU */ + case 8 : b+=((uint32_t)k[7])<<24; /* FALLTHRU */ + case 7 : b+=((uint32_t)k[6])<<16; /* FALLTHRU */ + case 6 : b+=((uint32_t)k[5])<<8; /* FALLTHRU */ + case 5 : b+=k[4]; /* FALLTHRU */ + case 4 : a+=((uint32_t)k[3])<<24; /* FALLTHRU */ + case 3 : a+=((uint32_t)k[2])<<16; /* FALLTHRU */ + case 2 : a+=((uint32_t)k[1])<<8; /* FALLTHRU */ case 1 : a+=k[0]; break; case 0 : return c; @@ -399,206 +436,255 @@ static uint32_t hashlittle( const void *key, size_t length, uint32_t initval) return c; } -unsigned long lh_char_hash(const void *k) +/* a simple hash function similiar to what perl does for strings. + * for good results, the string should not be excessivly large. + */ +static unsigned long lh_perllike_str_hash(const void *k) { - static volatile int random_seed = -1; - - if (random_seed == -1) { - int seed; - /* we can't use -1 as it is the unitialized sentinel */ - while ((seed = json_c_get_random_seed()) == -1); -#if defined __GNUC__ - __sync_val_compare_and_swap(&random_seed, -1, seed); -#elif defined _MSC_VER - InterlockedCompareExchange(&random_seed, seed, -1); + const char *rkey = (const char *)k; + unsigned hashval = 1; + + while (*rkey) + hashval = hashval * 33 + *rkey++; + + return hashval; +} + +static unsigned long lh_char_hash(const void *k) +{ +#if defined _MSC_VER || defined __MINGW32__ +#define RANDOM_SEED_TYPE LONG #else -#warning "racy random seed initializtion if used by multiple threads" - random_seed = seed; /* potentially racy */ +#define RANDOM_SEED_TYPE int #endif - } + static volatile RANDOM_SEED_TYPE random_seed = -1; + + if (random_seed == -1) { + RANDOM_SEED_TYPE seed; + /* we can't use -1 as it is the unitialized sentinel */ + while ((seed = json_c_get_random_seed()) == -1); +#if SIZEOF_INT == 8 && defined __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8 +#define USE_SYNC_COMPARE_AND_SWAP 1 +#endif +#if SIZEOF_INT == 4 && defined __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 +#define USE_SYNC_COMPARE_AND_SWAP 1 +#endif +#if SIZEOF_INT == 2 && defined __GCC_HAVE_SYNC_COMPARE_AND_SWAP_2 +#define USE_SYNC_COMPARE_AND_SWAP 1 +#endif +#if defined USE_SYNC_COMPARE_AND_SWAP + (void)__sync_val_compare_and_swap(&random_seed, -1, seed); +#elif defined _MSC_VER || defined __MINGW32__ + InterlockedCompareExchange(&random_seed, seed, -1); +#else +//#warning "racy random seed initializtion if used by multiple threads" + random_seed = seed; /* potentially racy */ +#endif + } - return hashlittle((const char*)k, strlen((const char*)k), random_seed); + return hashlittle((const char*)k, strlen((const char*)k), random_seed); } int lh_char_equal(const void *k1, const void *k2) { - return (strcmp((const char*)k1, (const char*)k2) == 0); + return (strcmp((const char*)k1, (const char*)k2) == 0); } -struct lh_table* lh_table_new(int size, const char *name, - lh_entry_free_fn *free_fn, - lh_hash_fn *hash_fn, - lh_equal_fn *equal_fn) +struct lh_table* lh_table_new(int size, + lh_entry_free_fn *free_fn, + lh_hash_fn *hash_fn, + lh_equal_fn *equal_fn) { - int i; - struct lh_table *t; - - t = (struct lh_table*)calloc(1, sizeof(struct lh_table)); - if(!t) lh_abort("lh_table_new: calloc failed\n"); - t->count = 0; - t->size = size; - t->name = name; - t->table = (struct lh_entry*)calloc(size, sizeof(struct lh_entry)); - if(!t->table) lh_abort("lh_table_new: calloc failed\n"); - t->free_fn = free_fn; - t->hash_fn = hash_fn; - t->equal_fn = equal_fn; - for(i = 0; i < size; i++) t->table[i].k = LH_EMPTY; - return t; + int i; + struct lh_table *t; + + t = (struct lh_table*)calloc(1, sizeof(struct lh_table)); + if (!t) + return NULL; + + t->count = 0; + t->size = size; + t->table = (struct lh_entry*)calloc(size, sizeof(struct lh_entry)); + if (!t->table) + { + free(t); + return NULL; + } + t->free_fn = free_fn; + t->hash_fn = hash_fn; + t->equal_fn = equal_fn; + for(i = 0; i < size; i++) t->table[i].k = LH_EMPTY; + return t; } -struct lh_table* lh_kchar_table_new(int size, const char *name, - lh_entry_free_fn *free_fn) +struct lh_table* lh_kchar_table_new(int size, + lh_entry_free_fn *free_fn) { - return lh_table_new(size, name, free_fn, lh_char_hash, lh_char_equal); + return lh_table_new(size, free_fn, char_hash_fn, lh_char_equal); } -struct lh_table* lh_kptr_table_new(int size, const char *name, - lh_entry_free_fn *free_fn) +struct lh_table* lh_kptr_table_new(int size, + lh_entry_free_fn *free_fn) { - return lh_table_new(size, name, free_fn, lh_ptr_hash, lh_ptr_equal); + return lh_table_new(size, free_fn, lh_ptr_hash, lh_ptr_equal); } -void lh_table_resize(struct lh_table *t, int new_size) +int lh_table_resize(struct lh_table *t, int new_size) { - struct lh_table *new_t; - struct lh_entry *ent; - - new_t = lh_table_new(new_size, t->name, NULL, t->hash_fn, t->equal_fn); - ent = t->head; - while(ent) { - lh_table_insert(new_t, ent->k, ent->v); - ent = ent->next; - } - free(t->table); - t->table = new_t->table; - t->size = new_size; - t->head = new_t->head; - t->tail = new_t->tail; - t->resizes++; - free(new_t); + struct lh_table *new_t; + struct lh_entry *ent; + + new_t = lh_table_new(new_size, NULL, t->hash_fn, t->equal_fn); + if (new_t == NULL) + return -1; + + for (ent = t->head; ent != NULL; ent = ent->next) + { + unsigned long h = lh_get_hash(new_t, ent->k); + unsigned int opts = 0; + if (ent->k_is_constant) + opts = JSON_C_OBJECT_KEY_IS_CONSTANT; + if (lh_table_insert_w_hash(new_t, ent->k, ent->v, h, opts) != 0) + { + lh_table_free(new_t); + return -1; + } + } + free(t->table); + t->table = new_t->table; + t->size = new_size; + t->head = new_t->head; + t->tail = new_t->tail; + free(new_t); + + return 0; } void lh_table_free(struct lh_table *t) { - struct lh_entry *c; - for(c = t->head; c != NULL; c = c->next) { - if(t->free_fn) { - t->free_fn(c); - } - } - free(t->table); - free(t); + struct lh_entry *c; + if(t->free_fn) { + for(c = t->head; c != NULL; c = c->next) + t->free_fn(c); + } + free(t->table); + free(t); } -int lh_table_insert(struct lh_table *t, void *k, const void *v) +int lh_table_insert_w_hash(struct lh_table *t, const void *k, const void *v, const unsigned long h, const unsigned opts) { - unsigned long h, n; - - t->inserts++; - if(t->count >= t->size * LH_LOAD_FACTOR) lh_table_resize(t, t->size * 2); - - h = t->hash_fn(k); - n = h % t->size; - - while( 1 ) { - if(t->table[n].k == LH_EMPTY || t->table[n].k == LH_FREED) break; - t->collisions++; - if ((int)++n == t->size) n = 0; - } + unsigned long n; + + if (t->count >= t->size * LH_LOAD_FACTOR) + if (lh_table_resize(t, t->size * 2) != 0) + return -1; + + n = h % t->size; + + while( 1 ) { + if(t->table[n].k == LH_EMPTY || t->table[n].k == LH_FREED) break; + if ((int)++n == t->size) n = 0; + } + + t->table[n].k = k; + t->table[n].k_is_constant = (opts & JSON_C_OBJECT_KEY_IS_CONSTANT); + t->table[n].v = v; + t->count++; + + if(t->head == NULL) { + t->head = t->tail = &t->table[n]; + t->table[n].next = t->table[n].prev = NULL; + } else { + t->tail->next = &t->table[n]; + t->table[n].prev = t->tail; + t->table[n].next = NULL; + t->tail = &t->table[n]; + } + + return 0; +} +int lh_table_insert(struct lh_table *t, const void *k, const void *v) +{ + return lh_table_insert_w_hash(t, k, v, lh_get_hash(t, k), 0); +} - t->table[n].k = k; - t->table[n].v = v; - t->count++; - - if(t->head == NULL) { - t->head = t->tail = &t->table[n]; - t->table[n].next = t->table[n].prev = NULL; - } else { - t->tail->next = &t->table[n]; - t->table[n].prev = t->tail; - t->table[n].next = NULL; - t->tail = &t->table[n]; - } - return 0; +struct lh_entry* lh_table_lookup_entry_w_hash(struct lh_table *t, const void *k, const unsigned long h) +{ + unsigned long n = h % t->size; + int count = 0; + + while( count < t->size ) { + if(t->table[n].k == LH_EMPTY) return NULL; + if(t->table[n].k != LH_FREED && + t->equal_fn(t->table[n].k, k)) return &t->table[n]; + if ((int)++n == t->size) n = 0; + count++; + } + return NULL; } - struct lh_entry* lh_table_lookup_entry(struct lh_table *t, const void *k) { - unsigned long h = t->hash_fn(k); - unsigned long n = h % t->size; - int count = 0; - - t->lookups++; - while( count < t->size ) { - if(t->table[n].k == LH_EMPTY) return NULL; - if(t->table[n].k != LH_FREED && - t->equal_fn(t->table[n].k, k)) return &t->table[n]; - if ((int)++n == t->size) n = 0; - count++; - } - return NULL; + return lh_table_lookup_entry_w_hash(t, k, lh_get_hash(t, k)); } - const void* lh_table_lookup(struct lh_table *t, const void *k) { - void *result; - lh_table_lookup_ex(t, k, &result); - return result; + void *result; + lh_table_lookup_ex(t, k, &result); + return result; } json_bool lh_table_lookup_ex(struct lh_table* t, const void* k, void **v) { - struct lh_entry *e = lh_table_lookup_entry(t, k); - if (e != NULL) { - if (v != NULL) *v = (void *)e->v; - return TRUE; /* key found */ - } - if (v != NULL) *v = NULL; - return FALSE; /* key not found */ + struct lh_entry *e = lh_table_lookup_entry(t, k); + if (e != NULL) { + if (v != NULL) *v = lh_entry_v(e); + return TRUE; /* key found */ + } + if (v != NULL) *v = NULL; + return FALSE; /* key not found */ } int lh_table_delete_entry(struct lh_table *t, struct lh_entry *e) { - ptrdiff_t n = (ptrdiff_t)(e - t->table); /* CAW: fixed to be 64bit nice, still need the crazy negative case... */ - - /* CAW: this is bad, really bad, maybe stack goes other direction on this machine... */ - if(n < 0) { return -2; } - - if(t->table[n].k == LH_EMPTY || t->table[n].k == LH_FREED) return -1; - t->count--; - if(t->free_fn) t->free_fn(e); - t->table[n].v = NULL; - t->table[n].k = LH_FREED; - if(t->tail == &t->table[n] && t->head == &t->table[n]) { - t->head = t->tail = NULL; - } else if (t->head == &t->table[n]) { - t->head->next->prev = NULL; - t->head = t->head->next; - } else if (t->tail == &t->table[n]) { - t->tail->prev->next = NULL; - t->tail = t->tail->prev; - } else { - t->table[n].prev->next = t->table[n].next; - t->table[n].next->prev = t->table[n].prev; - } - t->table[n].next = t->table[n].prev = NULL; - return 0; + ptrdiff_t n = (ptrdiff_t)(e - t->table); /* CAW: fixed to be 64bit nice, still need the crazy negative case... */ + + /* CAW: this is bad, really bad, maybe stack goes other direction on this machine... */ + if(n < 0) { return -2; } + + if(t->table[n].k == LH_EMPTY || t->table[n].k == LH_FREED) return -1; + t->count--; + if(t->free_fn) t->free_fn(e); + t->table[n].v = NULL; + t->table[n].k = LH_FREED; + if(t->tail == &t->table[n] && t->head == &t->table[n]) { + t->head = t->tail = NULL; + } else if (t->head == &t->table[n]) { + t->head->next->prev = NULL; + t->head = t->head->next; + } else if (t->tail == &t->table[n]) { + t->tail->prev->next = NULL; + t->tail = t->tail->prev; + } else { + t->table[n].prev->next = t->table[n].next; + t->table[n].next->prev = t->table[n].prev; + } + t->table[n].next = t->table[n].prev = NULL; + return 0; } int lh_table_delete(struct lh_table *t, const void *k) { - struct lh_entry *e = lh_table_lookup_entry(t, k); - if(!e) return -1; - return lh_table_delete_entry(t, e); + struct lh_entry *e = lh_table_lookup_entry(t, k); + if(!e) return -1; + return lh_table_delete_entry(t, e); } int lh_table_length(struct lh_table *t) { - return t->count; + return t->count; } diff --git a/phlib/jsonc/linkhash.h b/phlib/jsonc/linkhash.h index 950d09f35d70..9c2f5c1b2581 100644 --- a/phlib/jsonc/linkhash.h +++ b/phlib/jsonc/linkhash.h @@ -9,7 +9,13 @@ * it under the terms of the MIT license. See COPYING for details. * */ - + +/** + * @file + * @brief Internal methods for working with json_type_object objects. Although + * this is exposed by the json_object_get_object() function and within the + * json_object_iter type, it is not recommended for direct use. + */ #ifndef _linkhash_h_ #define _linkhash_h_ @@ -26,7 +32,7 @@ extern "C" { /** * The fraction of filled hash buckets until an insert will cause the table - * to be resized. + * to be resized. * This can range from just above 0 up to 1.0. */ #define LH_LOAD_FACTOR 0.66 @@ -41,6 +47,23 @@ extern "C" { */ #define LH_FREED (void*)-2 +/** + * default string hash function + */ +#define JSON_C_STR_HASH_DFLT 0 + +/** + * perl-like string hash function + */ +#define JSON_C_STR_HASH_PERLLIKE 1 + +/** + * This function sets the hash function to be used for strings. + * Must be one of the JSON_C_STR_HASH_* values. + * @returns 0 - ok, -1 if parameter was invalid + */ +int json_global_set_string_hash(const int h); + struct lh_entry; /** @@ -61,11 +84,16 @@ typedef int (lh_equal_fn) (const void *k1, const void *k2); */ struct lh_entry { /** - * The key. + * The key. Use lh_entry_k() instead of accessing this directly. + */ + const void *k; + /** + * A flag for users of linkhash to know whether or not they + * need to free k. */ - void *k; + int k_is_constant; /** - * The value. + * The value. Use lh_entry_v() instead of accessing this directly. */ const void *v; /** @@ -92,36 +120,6 @@ struct lh_table { */ int count; - /** - * Number of collisions. - */ - int collisions; - - /** - * Number of resizes. - */ - int resizes; - - /** - * Number of lookups. - */ - int lookups; - - /** - * Number of inserts. - */ - int inserts; - - /** - * Number of deletes. - */ - int deletes; - - /** - * Name of the hash table. - */ - const char *name; - /** * The first entry. */ @@ -141,16 +139,7 @@ struct lh_table { lh_hash_fn *hash_fn; lh_equal_fn *equal_fn; }; - - -/** - * Pre-defined hash and equality functions - */ -extern unsigned long lh_ptr_hash(const void *k); -extern int lh_ptr_equal(const void *k1, const void *k2); - -extern unsigned long lh_char_hash(const void *k); -extern int lh_char_equal(const void *k1, const void *k2); +typedef struct lh_table lh_table; /** @@ -161,6 +150,10 @@ for(entry = table->head; entry; entry = entry->next) /** * lh_foreach_safe allows calling of deletion routine while iterating. + * + * @param table a struct lh_table * to iterate over + * @param entry a struct lh_entry * variable to hold each element + * @param tmp a struct lh_entry * variable to hold a temporary pointer to the next element */ #define lh_foreach_safe(table, entry, tmp) \ for(entry = table->head; entry && ((tmp = entry->next) || 1); entry = tmp) @@ -169,9 +162,9 @@ for(entry = table->head; entry && ((tmp = entry->next) || 1); entry = tmp) /** * Create a new linkhash table. + * * @param size initial table size. The table is automatically resized * although this incurs a performance penalty. - * @param name the table name. * @param free_fn callback function used to free memory for entries * when lh_table_free or lh_table_delete is called. * If NULL is provided, then memory for keys and values @@ -182,41 +175,44 @@ for(entry = table->head; entry && ((tmp = entry->next) || 1); entry = tmp) * @param equal_fn comparison function to compare keys. 2 standard ones defined: * lh_ptr_hash and lh_char_hash for comparing pointer values * and C strings respectively. - * @return a pointer onto the linkhash table. + * @return On success, a pointer to the new linkhash table is returned. + * On error, a null pointer is returned. */ -extern struct lh_table* lh_table_new(int size, const char *name, +extern struct lh_table* lh_table_new(int size, lh_entry_free_fn *free_fn, lh_hash_fn *hash_fn, lh_equal_fn *equal_fn); /** - * Convenience function to create a new linkhash - * table with char keys. + * Convenience function to create a new linkhash table with char keys. + * * @param size initial table size. - * @param name table name. * @param free_fn callback function used to free memory for entries. - * @return a pointer onto the linkhash table. + * @return On success, a pointer to the new linkhash table is returned. + * On error, a null pointer is returned. */ -extern struct lh_table* lh_kchar_table_new(int size, const char *name, +extern struct lh_table* lh_kchar_table_new(int size, lh_entry_free_fn *free_fn); /** - * Convenience function to create a new linkhash - * table with ptr keys. + * Convenience function to create a new linkhash table with ptr keys. + * * @param size initial table size. - * @param name table name. * @param free_fn callback function used to free memory for entries. - * @return a pointer onto the linkhash table. + * @return On success, a pointer to the new linkhash table is returned. + * On error, a null pointer is returned. */ -extern struct lh_table* lh_kptr_table_new(int size, const char *name, +extern struct lh_table* lh_kptr_table_new(int size, lh_entry_free_fn *free_fn); /** * Free a linkhash table. - * If a callback free function is provided then it is called for all - * entries in the table. + * + * If a lh_entry_free_fn callback free function was provided then it is + * called for all entries in the table. + * * @param t table to free. */ extern void lh_table_free(struct lh_table *t); @@ -224,15 +220,37 @@ extern void lh_table_free(struct lh_table *t); /** * Insert a record into the table. + * * @param t the table to insert into. * @param k a pointer to the key to insert. * @param v a pointer to the value to insert. + * + * @return On success, 0 is returned. + * On error, a negative value is returned. */ -extern int lh_table_insert(struct lh_table *t, void *k, const void *v); +extern int lh_table_insert(struct lh_table *t, const void *k, const void *v); /** - * Lookup a record into the table. + * Insert a record into the table using a precalculated key hash. + * + * The hash h, which should be calculated with lh_get_hash() on k, is provided by + * the caller, to allow for optimization when multiple operations with the same + * key are known to be needed. + * + * @param t the table to insert into. + * @param k a pointer to the key to insert. + * @param v a pointer to the value to insert. + * @param h hash value of the key to insert + * @param opts if set to JSON_C_OBJECT_KEY_IS_CONSTANT, sets lh_entry.k_is_constant + * so t's free function knows to avoid freeing the key. + */ +extern int lh_table_insert_w_hash(struct lh_table *t, const void *k, const void *v, const unsigned long h, const unsigned opts); + + +/** + * Lookup a record in the table. + * * @param t the table to lookup * @param k a pointer to the key to lookup * @return a pointer to the record structure of the value or NULL if it does not exist. @@ -240,16 +258,32 @@ extern int lh_table_insert(struct lh_table *t, void *k, const void *v); extern struct lh_entry* lh_table_lookup_entry(struct lh_table *t, const void *k); /** - * Lookup a record into the table + * Lookup a record in the table using a precalculated key hash. + * + * The hash h, which should be calculated with lh_get_hash() on k, is provided by + * the caller, to allow for optimization when multiple operations with the same + * key are known to be needed. + * + * @param t the table to lookup + * @param k a pointer to the key to lookup + * @param h hash value of the key to lookup + * @return a pointer to the record structure of the value or NULL if it does not exist. + */ +extern struct lh_entry* lh_table_lookup_entry_w_hash(struct lh_table *t, const void *k, const unsigned long h); + +/** + * Lookup a record into the table. + * * @param t the table to lookup * @param k a pointer to the key to lookup * @return a pointer to the found value or NULL if it does not exist. - * @deprecated Use lh_table_lookup_ex instead. + * @deprecated Use lh_table_lookup_ex() instead. */ THIS_FUNCTION_IS_DEPRECATED(extern const void* lh_table_lookup(struct lh_table *t, const void *k)); /** - * Lookup a record in the table + * Lookup a record in the table. + * * @param t the table to lookup * @param k a pointer to the key to lookup * @param v a pointer to a where to store the found value (set to NULL if it doesn't exist). @@ -259,6 +293,7 @@ extern json_bool lh_table_lookup_ex(struct lh_table *t, const void *k, void **v) /** * Delete a record from the table. + * * If a callback free function is provided then it is called for the * for the item being deleted. * @param t the table to delete from. @@ -271,6 +306,7 @@ extern int lh_table_delete_entry(struct lh_table *t, struct lh_entry *e); /** * Delete a record from the table. + * * If a callback free function is provided then it is called for the * for the item being deleted. * @param t the table to delete from. @@ -282,8 +318,86 @@ extern int lh_table_delete(struct lh_table *t, const void *k); extern int lh_table_length(struct lh_table *t); -void lh_abort(const char *msg, ...); -void lh_table_resize(struct lh_table *t, int new_size); +/** + * Prints a message to stdout, + * then exits the program with an exit code of 1. + * + * @param msg Message format string, like for printf. + * @param ... Format args. + * + * @deprecated Since it is not a good idea to exit the entire program + * because of an internal library failure, json-c will no longer + * use this function internally. + * However, because its interface is public, it will remain part of + * the API on the off chance of legacy software using it externally. + */ +THIS_FUNCTION_IS_DEPRECATED(void lh_abort(const char *msg, ...)); + +/** + * Resizes the specified table. + * + * @param t Pointer to table to resize. + * @param new_size New table size. Must be positive. + * + * @return On success, 0 is returned. + * On error, a negative value is returned. + */ +int lh_table_resize(struct lh_table *t, int new_size); + + +/** + * @deprecated Don't use this outside of linkhash.h: + */ +#if !defined(_MSC_VER) || (_MSC_VER > 1800) +/* VS2010 can't handle inline funcs, so skip it there */ +#define _LH_INLINE inline +#else +#define _LH_INLINE +#endif + +/** + * Calculate the hash of a key for a given table. + * + * This is an exension to support functions that need to calculate + * the hash several times and allows them to do it just once and then pass + * in the hash to all utility functions. Depending on use case, this can be a + * considerable performance improvement. + * @param t the table (used to obtain hash function) + * @param k a pointer to the key to lookup + * @return the key's hash + */ +static _LH_INLINE unsigned long lh_get_hash(const struct lh_table *t, const void *k) +{ + return t->hash_fn(k); +} + +#undef _LH_INLINE + +/** + * @deprecated Don't use this outside of linkhash.h: + */ +#ifdef __UNCONST +#define _LH_UNCONST(a) __UNCONST(a) +#else +#define _LH_UNCONST(a) ((void *)(uintptr_t)(const void *)(a)) +#endif + +/** + * Return a non-const version of lh_entry.k. + * + * lh_entry.k is const to indicate and help ensure that linkhash itself doesn't modify + * it, but callers are allowed to do what they want with it. + * See also lh_entry.k_is_constant + */ +#define lh_entry_k(entry) _LH_UNCONST((entry)->k) + +/** + * Return a non-const version of lh_entry.v. + * + * v is const to indicate and help ensure that linkhash itself doesn't modify + * it, but callers are allowed to do what they want with it. + */ +#define lh_entry_v(entry) _LH_UNCONST((entry)->v) #ifdef __cplusplus } diff --git a/phlib/jsonc/math_compat.h b/phlib/jsonc/math_compat.h index f40b8faf8fd4..d530537b94f9 100644 --- a/phlib/jsonc/math_compat.h +++ b/phlib/jsonc/math_compat.h @@ -1,7 +1,12 @@ #ifndef __math_compat_h #define __math_compat_h -/* Define isnan and isinf on Windows/MSVC */ +/** + * @file + * @brief Do not use, json-c internal, may be changed or removed at any time. + */ + +/* Define isnan, isinf, infinity and nan on Windows/MSVC */ #ifndef HAVE_DECL_ISNAN # ifdef HAVE_DECL__ISNAN @@ -17,12 +22,15 @@ # endif #endif -#ifndef HAVE_DECL_NAN -#error This platform does not have nan() +#ifndef HAVE_DECL_INFINITY +#include +#define INFINITY (DBL_MAX + DBL_MAX) +#define HAVE_DECL_INFINITY #endif -#ifndef HAVE_DECL_INFINITY -#error This platform does not have INFINITY +#ifndef HAVE_DECL_NAN +#define NAN (INFINITY - INFINITY) +#define HAVE_DECL_NAN #endif #endif diff --git a/phlib/jsonc/printbuf.c b/phlib/jsonc/printbuf.c index 94d41b0d6a5e..b57275e9b5f9 100644 --- a/phlib/jsonc/printbuf.c +++ b/phlib/jsonc/printbuf.c @@ -25,9 +25,10 @@ # error Not enough var arg support! #endif /* HAVE_STDARG_H */ -#include "bits.h" #include "debug.h" #include "printbuf.h" +#include "snprintf_compat.h" +#include "vasprintf_compat.h" static int printbuf_extend(struct printbuf *p, size_t min_size); @@ -43,6 +44,7 @@ struct printbuf* printbuf_new(void) free(p); return NULL; } + p->buf[0]= '\0'; return p; } @@ -63,7 +65,9 @@ static int printbuf_extend(struct printbuf *p, size_t min_size) if (p->size >= min_size) return 0; - new_size = json_max(p->size * 2, min_size + 8); + new_size = p->size * 2; + if (new_size < min_size + 8) + new_size = min_size + 8; #ifdef PRINTBUF_DEBUG MC_DEBUG("printbuf_memappend: realloc " "bpos=%d min_size=%d old_size=%d new_size=%d\n", @@ -76,7 +80,7 @@ static int printbuf_extend(struct printbuf *p, size_t min_size) return 0; } -size_t printbuf_memappend(struct printbuf *p, const char *buf, size_t size) +int printbuf_memappend(struct printbuf *p, const char *buf, size_t size) { if (p->size <= p->bpos + size + 1) { if (printbuf_extend(p, p->bpos + size + 1) < 0) @@ -85,7 +89,22 @@ size_t printbuf_memappend(struct printbuf *p, const char *buf, size_t size) memcpy(p->buf + p->bpos, buf, size); p->bpos += size; p->buf[p->bpos]= '\0'; - return size; + return (int)size; +} + +// modified by dmex +void printbuf_memappend_fast(struct printbuf *p, const char *bufptr, size_t bufsize) +{ + if ((p->size - p->bpos) > bufsize) + { + memcpy(p->buf + p->bpos, (bufptr), bufsize); + p->bpos += (int)bufsize; + p->buf[p->bpos] = '\0'; + } + else + { + printbuf_memappend(p, (bufptr), bufsize); + } } int printbuf_memset(struct printbuf *pb, size_t offset, int charvalue, size_t len) @@ -108,49 +127,6 @@ int printbuf_memset(struct printbuf *pb, size_t offset, int charvalue, size_t le return 0; } -#if !defined(HAVE_VSNPRINTF) && defined(_MSC_VER) -# define vsnprintf _vsnprintf -#elif !defined(HAVE_VSNPRINTF) /* !HAVE_VSNPRINTF */ -# error Need vsnprintf! -#endif /* !HAVE_VSNPRINTF && defined(_WIN32) */ - -#if !defined(HAVE_VASPRINTF) -/* CAW: compliant version of vasprintf */ -static int vasprintf(char **buf, const char *fmt, va_list ap) -{ -#ifndef _WIN32 - static char _T_emptybuffer = '\0'; -#endif /* !defined(_WIN32) */ - int chars; - char *b; - - if(!buf) { return -1; } - -#ifdef _WIN32 - chars = _vscprintf(fmt, ap)+1; -#else /* !defined(_WIN32) */ - /* CAW: RAWR! We have to hope to god here that vsnprintf doesn't overwrite - our buffer like on some 64bit sun systems.... but hey, its time to move on */ - chars = vsnprintf(&_T_emptybuffer, 0, fmt, ap)+1; - if(chars < 0) { chars *= -1; } /* CAW: old glibc versions have this problem */ -#endif /* defined(_WIN32) */ - - b = (char*)malloc(sizeof(char) * chars); - if(!b) { return -1; } - - if ((chars = vsprintf_s(b, sizeof(char), fmt, ap)) < 0) - { - free(b); - } - else - { - *buf = b; - } - - return chars; -} -#endif /* !HAVE_VASPRINTF */ - int sprintbuf(struct printbuf *p, const char *msg, ...) { va_list ap; @@ -160,7 +136,7 @@ int sprintbuf(struct printbuf *p, const char *msg, ...) /* user stack buffer first */ va_start(ap, msg); - size = _vsnprintf_s(buf, sizeof(buf), _TRUNCATE, msg, ap); + size = vsnprintf(buf, 128, msg, ap); va_end(ap); /* if string is greater than stack buffer, then use dynamic string with vasprintf. Note: some implementation of vsnprintf return -1 diff --git a/phlib/jsonc/printbuf.h b/phlib/jsonc/printbuf.h index ed003b61f3c2..e653cba7b3d3 100644 --- a/phlib/jsonc/printbuf.h +++ b/phlib/jsonc/printbuf.h @@ -13,6 +13,13 @@ * (http://www.opensource.org/licenses/mit-license.php) */ +/** + * @file + * @brief Internal string buffer handing. Unless you're writing a + * json_object_to_json_string_fn implementation for use with + * json_object_set_serializer() direct use of this is not + * recommended. + */ #ifndef _printbuf_h_ #define _printbuf_h_ @@ -25,35 +32,50 @@ struct printbuf { size_t bpos; size_t size; }; +typedef struct printbuf printbuf; extern struct printbuf* printbuf_new(void); -/* As an optimization, printbuf_memappend_fast is defined as a macro +/* As an optimization, printbuf_memappend_fast() is defined as a macro * that handles copying data if the buffer is large enough; otherwise - * it invokes printbuf_memappend_real() which performs the heavy + * it invokes printbuf_memappend() which performs the heavy * lifting of realloc()ing the buffer and copying data. - * Your code should not use printbuf_memappend directly--use - * printbuf_memappend_fast instead. + * + * Your code should not use printbuf_memappend() directly unless it + * checks the return code. Use printbuf_memappend_fast() instead. */ -extern size_t printbuf_memappend(struct printbuf *p, const char *buf, size_t size); +extern int +printbuf_memappend(struct printbuf *p, const char *buf, size_t size); -__inline void printbuf_memappend_fast(struct printbuf *p, const char *bufptr, size_t bufsize) -{ - if ((p->size - p->bpos) > bufsize) - { - memcpy(p->buf + p->bpos, (bufptr), bufsize); - p->bpos += (int)bufsize; - p->buf[p->bpos] = '\0'; - } - else - { - printbuf_memappend(p, (bufptr), bufsize); - } -} +// printbuf_memappend_fast(p, bufptr, bufsize) +// Modified by dmex. +void printbuf_memappend_fast(struct printbuf *p, const char *bufptr, size_t bufsize); #define printbuf_length(p) ((p)->bpos) +/** + * Results in a compile error if the argument is not a string literal. + */ +#define _printbuf_check_literal(mystr) ("" mystr) + +/** + * This is an optimization wrapper around printbuf_memappend() that is useful + * for appending string literals. Since the size of string constants is known + * at compile time, using this macro can avoid a costly strlen() call. This is + * especially helpful when a constant string must be appended many times. If + * you got here because of a compilation error caused by passing something + * other than a string literal, use printbuf_memappend_fast() in conjunction + * with strlen(). + * + * See also: + * printbuf_memappend_fast() + * printbuf_memappend() + * sprintbuf() + */ +#define printbuf_strappend(pb, str) \ + printbuf_memappend ((pb), _printbuf_check_literal(str), sizeof(str) - 1) + /** * Set len bytes of the buffer to charvalue, starting at offset offset. * Similar to calling memset(x, charvalue, len); @@ -65,6 +87,20 @@ __inline void printbuf_memappend_fast(struct printbuf *p, const char *bufptr, si extern int printbuf_memset(struct printbuf *pb, size_t offset, int charvalue, size_t len); +/** + * Formatted print to printbuf. + * + * This function is the most expensive of the available functions for appending + * string data to a printbuf and should be used only where convenience is more + * important than speed. Avoid using this function in high performance code or + * tight loops; in these scenarios, consider using snprintf() with a static + * buffer in conjunction with one of the printbuf_*append() functions. + * + * See also: + * printbuf_memappend_fast() + * printbuf_memappend() + * printbuf_strappend() + */ extern int sprintbuf(struct printbuf *p, const char *msg, ...); diff --git a/phlib/jsonc/random_seed.c b/phlib/jsonc/random_seed.c index ece374e5b74e..9901515b2b8f 100644 --- a/phlib/jsonc/random_seed.c +++ b/phlib/jsonc/random_seed.c @@ -9,8 +9,10 @@ * */ +#include "strerror_override.h" #include #include "config.h" +#include "random_seed.h" #define DEBUG_SEED(s) @@ -104,14 +106,14 @@ static int get_rdrand_seed() static int get_rdrand_seed() { - DEBUG_SEED("get_rdrand_seed"); - int _eax; + DEBUG_SEED("get_rdrand_seed"); + int _eax; retry: - // rdrand eax - __asm _emit 0x0F __asm _emit 0xC7 __asm _emit 0xF0 - __asm jnc retry - __asm mov _eax, eax - return _eax; + // rdrand eax + __asm _emit 0x0F __asm _emit 0xC7 __asm _emit 0xF0 + __asm jnc retry + __asm mov _eax, eax + return _eax; } #endif @@ -127,7 +129,6 @@ static int get_rdrand_seed() #include #include #include -#include #include #include @@ -150,23 +151,20 @@ static int has_dev_urandom() static int get_dev_random_seed() { DEBUG_SEED("get_dev_random_seed"); - + int fd = open(dev_random_file, O_RDONLY); if (fd < 0) { fprintf(stderr, "error opening %s: %s", dev_random_file, strerror(errno)); exit(1); } - + int r; ssize_t nread = read(fd, &r, sizeof(r)); if (nread != sizeof(r)) { - fprintf(stderr, "error read %s: %s", dev_random_file, strerror(errno)); - exit(1); - } - else if (nread != sizeof(r)) { - fprintf(stderr, "error short read %s", dev_random_file); + fprintf(stderr, "error short read %s: %s", dev_random_file, strerror(errno)); exit(1); } + close(fd); return r; } @@ -181,28 +179,30 @@ static int get_dev_random_seed() #define HAVE_CRYPTGENRANDOM 1 #include +#include +#ifndef __GNUC__ +#pragma comment(lib, "advapi32.lib") +#endif static int get_cryptgenrandom_seed() { - DEBUG_SEED("get_cryptgenrandom_seed"); - HCRYPTPROV hProvider = 0; int r; - - if (!CryptAcquireContextW(&hProvider, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) - { + + DEBUG_SEED("get_cryptgenrandom_seed"); + + if (!CryptAcquireContextW(&hProvider, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) { fprintf(stderr, "error CryptAcquireContextW"); exit(1); } - - if (!CryptGenRandom(hProvider, sizeof(r), (BYTE*)&r)) - { + + if (!CryptGenRandom(hProvider, sizeof(r), (BYTE*)&r)) { fprintf(stderr, "error CryptGenRandom"); exit(1); } - + CryptReleaseContext(hProvider, 0); - + return r; } @@ -216,7 +216,7 @@ static int get_cryptgenrandom_seed() static int get_time_seed() { DEBUG_SEED("get_time_seed"); - + return (int)time(NULL) * 433494437; } diff --git a/phlib/jsonc/random_seed.h b/phlib/jsonc/random_seed.h index 7362d67d9cd5..2f43dad1f35f 100644 --- a/phlib/jsonc/random_seed.h +++ b/phlib/jsonc/random_seed.h @@ -9,6 +9,10 @@ * */ +/** + * @file + * @brief Do not use, json-c internal, may be changed or removed at any time. + */ #ifndef seed_h #define seed_h diff --git a/phlib/jsonc/snprintf_compat.h b/phlib/jsonc/snprintf_compat.h new file mode 100644 index 000000000000..69b11d94e94e --- /dev/null +++ b/phlib/jsonc/snprintf_compat.h @@ -0,0 +1,41 @@ +#ifndef __snprintf_compat_h +#define __snprintf_compat_h + +/** + * @file + * @brief Do not use, json-c internal, may be changed or removed at any time. + */ + +/* + * Microsoft's _vsnprintf and _snprint don't always terminate + * the string, so use wrappers that ensure that. + */ + +#include + +#if !defined(HAVE_SNPRINTF) && defined(_MSC_VER) +static int json_c_vsnprintf(char *str, size_t size, const char *format, va_list ap) +{ + int ret; + ret = _vsnprintf(str, size, format, ap); + str[size - 1] = '\0'; + return ret; +} +#define vsnprintf json_c_vsnprintf + +static int json_c_snprintf(char *str, size_t size, const char *format, ...) +{ + va_list ap; + int ret; + va_start(ap, format); + ret = json_c_vsnprintf(str, size, format, ap); + va_end(ap); + return ret; +} +#define snprintf json_c_snprintf + +#elif !defined(HAVE_SNPRINTF) /* !HAVE_SNPRINTF */ +# error Need vsnprintf! +#endif /* !HAVE_SNPRINTF && defined(_WIN32) */ + +#endif /* __snprintf_compat_h */ diff --git a/phlib/jsonc/strdup_compat.h b/phlib/jsonc/strdup_compat.h new file mode 100644 index 000000000000..9c523596e36a --- /dev/null +++ b/phlib/jsonc/strdup_compat.h @@ -0,0 +1,16 @@ +#ifndef __strdup_compat_h +#define __strdup_compat_h + +/** + * @file + * @brief Do not use, json-c internal, may be changed or removed at any time. + */ + +#if !defined(HAVE_STRDUP) && defined(_MSC_VER) + /* MSC has the version as _strdup */ +# define strdup _strdup +#elif !defined(HAVE_STRDUP) +# error You do not have strdup on your system. +#endif /* HAVE_STRDUP */ + +#endif diff --git a/phlib/jsonc/strerror_override.c b/phlib/jsonc/strerror_override.c new file mode 100644 index 000000000000..b87cb494c93e --- /dev/null +++ b/phlib/jsonc/strerror_override.c @@ -0,0 +1,105 @@ +#define STRERROR_OVERRIDE_IMPL 1 +#include "strerror_override.h" + +#pragma warning(push) +#pragma warning(disable: 4996) + +/* + * Override strerror() to get consistent output across platforms. + */ + +static struct { + int errno_value; + const char *errno_str; +} errno_list[] = { +#define STRINGIFY(x) #x +#define ENTRY(x) {x, &STRINGIFY(undef_ ## x)[6]} + ENTRY(EPERM), + ENTRY(ENOENT), + ENTRY(ESRCH), + ENTRY(EINTR), + ENTRY(EIO), + ENTRY(ENXIO), + ENTRY(E2BIG), + ENTRY(ENOEXEC), + ENTRY(EBADF), + ENTRY(ECHILD), + ENTRY(EDEADLK), + ENTRY(ENOMEM), + ENTRY(EACCES), + ENTRY(EFAULT), +#ifdef ENOTBLK + ENTRY(ENOTBLK), +#endif + ENTRY(EBUSY), + ENTRY(EEXIST), + ENTRY(EXDEV), + ENTRY(ENODEV), + ENTRY(ENOTDIR), + ENTRY(EISDIR), + ENTRY(EINVAL), + ENTRY(ENFILE), + ENTRY(EMFILE), + ENTRY(ENOTTY), +#ifdef ETXTBSY + ENTRY(ETXTBSY), +#endif + ENTRY(EFBIG), + ENTRY(ENOSPC), + ENTRY(ESPIPE), + ENTRY(EROFS), + ENTRY(EMLINK), + ENTRY(EPIPE), + ENTRY(EDOM), + ENTRY(ERANGE), + ENTRY(EAGAIN), + { 0, (char *)0 } +}; + +// Enabled during tests +int _json_c_strerror_enable = 0; + +#define PREFIX "ERRNO=" +static char errno_buf[128] = PREFIX; +char *_json_c_strerror(int errno_in) +{ + int start_idx; + char digbuf[20]; + int ii, jj; + + if (!_json_c_strerror_enable) + return strerror(errno_in); + + // Avoid standard functions, so we don't need to include any + // headers, or guess at signatures. + + for (ii = 0; errno_list[ii].errno_str != (char *)0; ii++) + { + const char *errno_str = errno_list[ii].errno_str; + if (errno_list[ii].errno_value != errno_in) + continue; + + for (start_idx = sizeof(PREFIX) - 1, jj = 0; errno_str[jj] != '\0'; jj++, start_idx++) + { + errno_buf[start_idx] = errno_str[jj]; + } + errno_buf[start_idx] = '\0'; + return errno_buf; + } + + // It's not one of the known errno values, return the numeric value. + for (ii = 0; errno_in > 10; errno_in /= 10, ii++) + { + digbuf[ii] = "0123456789"[(errno_in % 10)]; + } + digbuf[ii] = "0123456789"[(errno_in % 10)]; + + // Reverse the digits + for (start_idx = sizeof(PREFIX) - 1 ; ii >= 0; ii--, start_idx++) + { + errno_buf[start_idx] = digbuf[ii]; + } + return errno_buf; +} + +#pragma warning(pop) diff --git a/phlib/jsonc/strerror_override.h b/phlib/jsonc/strerror_override.h new file mode 100644 index 000000000000..567438180439 --- /dev/null +++ b/phlib/jsonc/strerror_override.h @@ -0,0 +1,30 @@ +#ifndef _json_strerror_override_h_ +#define _json_strerror_override_h_ + +/** + * @file + * @brief Do not use, json-c internal, may be changed or removed at any time. + */ + +#include "config.h" +#include + +#include "json_object.h" /* for JSON_EXPORT */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +JSON_EXPORT char *_json_c_strerror(int errno_in); + +#ifndef STRERROR_OVERRIDE_IMPL +#define strerror _json_c_strerror +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* _json_strerror_override_h_ */ diff --git a/phlib/jsonc/strerror_override_private.h b/phlib/jsonc/strerror_override_private.h new file mode 100644 index 000000000000..5180b4f30764 --- /dev/null +++ b/phlib/jsonc/strerror_override_private.h @@ -0,0 +1,12 @@ +#ifndef __json_strerror_override_private_h__ +#define __json_strerror_override_private_h__ + +/** + * @file + * @brief Do not use, json-c internal, may be changed or removed at any time. + */ + +/* Used by tests to get consistent output */ +extern int _json_c_strerror_enable; + +#endif diff --git a/phlib/jsonc/vasprintf_compat.h b/phlib/jsonc/vasprintf_compat.h new file mode 100644 index 000000000000..b1d12e9b143d --- /dev/null +++ b/phlib/jsonc/vasprintf_compat.h @@ -0,0 +1,51 @@ +#ifndef __vasprintf_compat_h +#define __vasprintf_compat_h + +#pragma warning(push) +#pragma warning(disable: 4996) + +/** + * @file + * @brief Do not use, json-c internal, may be changed or removed at any time. + */ + +#include "snprintf_compat.h" + +#if !defined(HAVE_VASPRINTF) +/* CAW: compliant version of vasprintf */ +static int vasprintf(char **buf, const char *fmt, va_list ap) +{ +#ifndef _WIN32 + static char _T_emptybuffer = '\0'; +#endif /* !defined(_WIN32) */ + int chars; + char *b; + + if(!buf) { return -1; } + +#ifdef _WIN32 + chars = _vscprintf(fmt, ap)+1; +#else /* !defined(_WIN32) */ + /* CAW: RAWR! We have to hope to god here that vsnprintf doesn't overwrite + our buffer like on some 64bit sun systems.... but hey, its time to move on */ + chars = vsnprintf(&_T_emptybuffer, 0, fmt, ap)+1; + if(chars < 0) { chars *= -1; } /* CAW: old glibc versions have this problem */ +#endif /* defined(_WIN32) */ + + b = (char*)malloc(sizeof(char)*chars); + if(!b) { return -1; } + + if((chars = vsprintf(b, fmt, ap)) < 0) + { + free(b); + } else { + *buf = b; + } + + return chars; +} +#endif /* !HAVE_VASPRINTF */ + +#pragma warning(pop) + +#endif /* __vasprintf_compat_h */ From 7b3e25701f2aee173e7fe05313fd97db127b5f9d Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 25 May 2018 13:57:21 +1000 Subject: [PATCH 0982/2058] Fix jsonc tabspace, Fix jsonc header include path --- phlib/jsonc/json_util.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/phlib/jsonc/json_util.c b/phlib/jsonc/json_util.c index 79480d5dae8e..58c3e2f11c79 100644 --- a/phlib/jsonc/json_util.c +++ b/phlib/jsonc/json_util.c @@ -9,8 +9,8 @@ * */ -#include "..\include\phbase.h" -#include "..\include\phnative.h" +#include +#include #include "config.h" #undef realloc From 4684829956e01f217da5012ca4e8e5207af68ba0 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 25 May 2018 14:00:39 +1000 Subject: [PATCH 0983/2058] Fix jsonc tabspace --- phlib/jsonc/debug.c | 18 +- phlib/jsonc/json_object_private.h | 14 +- phlib/jsonc/linkhash.c | 344 +++++++++++++++--------------- phlib/jsonc/random_seed.c | 14 +- 4 files changed, 195 insertions(+), 195 deletions(-) diff --git a/phlib/jsonc/debug.c b/phlib/jsonc/debug.c index 4b5140aec1e2..8504d0f59512 100644 --- a/phlib/jsonc/debug.c +++ b/phlib/jsonc/debug.c @@ -48,10 +48,10 @@ void mc_debug(const char *msg, ...) va_start(ap, msg); #if HAVE_VSYSLOG if(_syslog) { - vsyslog(LOG_DEBUG, msg, ap); - } else + vsyslog(LOG_DEBUG, msg, ap); + } else #endif - vprintf(msg, ap); + vprintf(msg, ap); va_end(ap); } } @@ -62,10 +62,10 @@ void mc_error(const char *msg, ...) va_start(ap, msg); #if HAVE_VSYSLOG if(_syslog) { - vsyslog(LOG_ERR, msg, ap); - } else + vsyslog(LOG_ERR, msg, ap); + } else #endif - vfprintf(stderr, msg, ap); + vfprintf(stderr, msg, ap); va_end(ap); } @@ -75,9 +75,9 @@ void mc_info(const char *msg, ...) va_start(ap, msg); #if HAVE_VSYSLOG if(_syslog) { - vsyslog(LOG_INFO, msg, ap); - } else + vsyslog(LOG_INFO, msg, ap); + } else #endif - vfprintf(stderr, msg, ap); + vfprintf(stderr, msg, ap); va_end(ap); } diff --git a/phlib/jsonc/json_object_private.h b/phlib/jsonc/json_object_private.h index 53be70db0898..dfe9ce6a174b 100644 --- a/phlib/jsonc/json_object_private.h +++ b/phlib/jsonc/json_object_private.h @@ -38,13 +38,13 @@ struct json_object struct lh_table *c_object; struct array_list *c_array; struct { - union { - /* optimize: if we have small strings, we can store them - * directly. This saves considerable CPU cycles AND memory. - */ - char *ptr; - char data[LEN_DIRECT_STRING_DATA]; - } str; + union { + /* optimize: if we have small strings, we can store them + * directly. This saves considerable CPU cycles AND memory. + */ + char *ptr; + char data[LEN_DIRECT_STRING_DATA]; + } str; int len; } c_string; } o; diff --git a/phlib/jsonc/linkhash.c b/phlib/jsonc/linkhash.c index 5497061a8a15..a8c78ca44baa 100644 --- a/phlib/jsonc/linkhash.c +++ b/phlib/jsonc/linkhash.c @@ -39,37 +39,37 @@ static lh_hash_fn *char_hash_fn = lh_char_hash; int json_global_set_string_hash(const int h) { - switch(h) { - case JSON_C_STR_HASH_DFLT: - char_hash_fn = lh_char_hash; - break; - case JSON_C_STR_HASH_PERLLIKE: - char_hash_fn = lh_perllike_str_hash; - break; - default: - return -1; - } - return 0; + switch(h) { + case JSON_C_STR_HASH_DFLT: + char_hash_fn = lh_char_hash; + break; + case JSON_C_STR_HASH_PERLLIKE: + char_hash_fn = lh_perllike_str_hash; + break; + default: + return -1; + } + return 0; } void lh_abort(const char *msg, ...) { - va_list ap; - va_start(ap, msg); - vprintf(msg, ap); - va_end(ap); - exit(1); + va_list ap; + va_start(ap, msg); + vprintf(msg, ap); + va_end(ap); + exit(1); } static unsigned long lh_ptr_hash(const void *k) { - /* CAW: refactored to be 64bit nice */ - return (unsigned long)((((ptrdiff_t)k * LH_PRIME) >> 4) & ULONG_MAX); + /* CAW: refactored to be 64bit nice */ + return (unsigned long)((((ptrdiff_t)k * LH_PRIME) >> 4) & ULONG_MAX); } int lh_ptr_equal(const void *k1, const void *k2) { - return (k1 == k2); + return (k1 == k2); } /* @@ -290,7 +290,7 @@ static uint32_t hashlittle( const void *key, size_t length, uint32_t initval) * still catch it and complain. The masking trick does make the hash * noticably faster for short strings (like English words). * AddressSanitizer is similarly picky about overrunning - * the buffer. (http://clang.llvm.org/docs/AddressSanitizer.html + * the buffer. (http://clang.llvm.org/docs/AddressSanitizer.html */ #ifdef VALGRIND # define PRECISE_MEMORY_ACCESS 1 @@ -457,12 +457,12 @@ static unsigned long lh_char_hash(const void *k) #else #define RANDOM_SEED_TYPE int #endif - static volatile RANDOM_SEED_TYPE random_seed = -1; + static volatile RANDOM_SEED_TYPE random_seed = -1; - if (random_seed == -1) { - RANDOM_SEED_TYPE seed; - /* we can't use -1 as it is the unitialized sentinel */ - while ((seed = json_c_get_random_seed()) == -1); + if (random_seed == -1) { + RANDOM_SEED_TYPE seed; + /* we can't use -1 as it is the unitialized sentinel */ + while ((seed = json_c_get_random_seed()) == -1); #if SIZEOF_INT == 8 && defined __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8 #define USE_SYNC_COMPARE_AND_SWAP 1 #endif @@ -473,218 +473,218 @@ static unsigned long lh_char_hash(const void *k) #define USE_SYNC_COMPARE_AND_SWAP 1 #endif #if defined USE_SYNC_COMPARE_AND_SWAP - (void)__sync_val_compare_and_swap(&random_seed, -1, seed); + (void)__sync_val_compare_and_swap(&random_seed, -1, seed); #elif defined _MSC_VER || defined __MINGW32__ - InterlockedCompareExchange(&random_seed, seed, -1); + InterlockedCompareExchange(&random_seed, seed, -1); #else //#warning "racy random seed initializtion if used by multiple threads" - random_seed = seed; /* potentially racy */ + random_seed = seed; /* potentially racy */ #endif - } + } - return hashlittle((const char*)k, strlen((const char*)k), random_seed); + return hashlittle((const char*)k, strlen((const char*)k), random_seed); } int lh_char_equal(const void *k1, const void *k2) { - return (strcmp((const char*)k1, (const char*)k2) == 0); + return (strcmp((const char*)k1, (const char*)k2) == 0); } struct lh_table* lh_table_new(int size, - lh_entry_free_fn *free_fn, - lh_hash_fn *hash_fn, - lh_equal_fn *equal_fn) + lh_entry_free_fn *free_fn, + lh_hash_fn *hash_fn, + lh_equal_fn *equal_fn) { - int i; - struct lh_table *t; - - t = (struct lh_table*)calloc(1, sizeof(struct lh_table)); - if (!t) - return NULL; - - t->count = 0; - t->size = size; - t->table = (struct lh_entry*)calloc(size, sizeof(struct lh_entry)); - if (!t->table) - { - free(t); - return NULL; - } - t->free_fn = free_fn; - t->hash_fn = hash_fn; - t->equal_fn = equal_fn; - for(i = 0; i < size; i++) t->table[i].k = LH_EMPTY; - return t; + int i; + struct lh_table *t; + + t = (struct lh_table*)calloc(1, sizeof(struct lh_table)); + if (!t) + return NULL; + + t->count = 0; + t->size = size; + t->table = (struct lh_entry*)calloc(size, sizeof(struct lh_entry)); + if (!t->table) + { + free(t); + return NULL; + } + t->free_fn = free_fn; + t->hash_fn = hash_fn; + t->equal_fn = equal_fn; + for(i = 0; i < size; i++) t->table[i].k = LH_EMPTY; + return t; } struct lh_table* lh_kchar_table_new(int size, - lh_entry_free_fn *free_fn) + lh_entry_free_fn *free_fn) { - return lh_table_new(size, free_fn, char_hash_fn, lh_char_equal); + return lh_table_new(size, free_fn, char_hash_fn, lh_char_equal); } struct lh_table* lh_kptr_table_new(int size, - lh_entry_free_fn *free_fn) + lh_entry_free_fn *free_fn) { - return lh_table_new(size, free_fn, lh_ptr_hash, lh_ptr_equal); + return lh_table_new(size, free_fn, lh_ptr_hash, lh_ptr_equal); } int lh_table_resize(struct lh_table *t, int new_size) { - struct lh_table *new_t; - struct lh_entry *ent; - - new_t = lh_table_new(new_size, NULL, t->hash_fn, t->equal_fn); - if (new_t == NULL) - return -1; - - for (ent = t->head; ent != NULL; ent = ent->next) - { - unsigned long h = lh_get_hash(new_t, ent->k); - unsigned int opts = 0; - if (ent->k_is_constant) - opts = JSON_C_OBJECT_KEY_IS_CONSTANT; - if (lh_table_insert_w_hash(new_t, ent->k, ent->v, h, opts) != 0) - { - lh_table_free(new_t); - return -1; - } - } - free(t->table); - t->table = new_t->table; - t->size = new_size; - t->head = new_t->head; - t->tail = new_t->tail; - free(new_t); - - return 0; + struct lh_table *new_t; + struct lh_entry *ent; + + new_t = lh_table_new(new_size, NULL, t->hash_fn, t->equal_fn); + if (new_t == NULL) + return -1; + + for (ent = t->head; ent != NULL; ent = ent->next) + { + unsigned long h = lh_get_hash(new_t, ent->k); + unsigned int opts = 0; + if (ent->k_is_constant) + opts = JSON_C_OBJECT_KEY_IS_CONSTANT; + if (lh_table_insert_w_hash(new_t, ent->k, ent->v, h, opts) != 0) + { + lh_table_free(new_t); + return -1; + } + } + free(t->table); + t->table = new_t->table; + t->size = new_size; + t->head = new_t->head; + t->tail = new_t->tail; + free(new_t); + + return 0; } void lh_table_free(struct lh_table *t) { - struct lh_entry *c; - if(t->free_fn) { - for(c = t->head; c != NULL; c = c->next) - t->free_fn(c); - } - free(t->table); - free(t); + struct lh_entry *c; + if(t->free_fn) { + for(c = t->head; c != NULL; c = c->next) + t->free_fn(c); + } + free(t->table); + free(t); } int lh_table_insert_w_hash(struct lh_table *t, const void *k, const void *v, const unsigned long h, const unsigned opts) { - unsigned long n; - - if (t->count >= t->size * LH_LOAD_FACTOR) - if (lh_table_resize(t, t->size * 2) != 0) - return -1; - - n = h % t->size; - - while( 1 ) { - if(t->table[n].k == LH_EMPTY || t->table[n].k == LH_FREED) break; - if ((int)++n == t->size) n = 0; - } - - t->table[n].k = k; - t->table[n].k_is_constant = (opts & JSON_C_OBJECT_KEY_IS_CONSTANT); - t->table[n].v = v; - t->count++; - - if(t->head == NULL) { - t->head = t->tail = &t->table[n]; - t->table[n].next = t->table[n].prev = NULL; - } else { - t->tail->next = &t->table[n]; - t->table[n].prev = t->tail; - t->table[n].next = NULL; - t->tail = &t->table[n]; - } - - return 0; + unsigned long n; + + if (t->count >= t->size * LH_LOAD_FACTOR) + if (lh_table_resize(t, t->size * 2) != 0) + return -1; + + n = h % t->size; + + while( 1 ) { + if(t->table[n].k == LH_EMPTY || t->table[n].k == LH_FREED) break; + if ((int)++n == t->size) n = 0; + } + + t->table[n].k = k; + t->table[n].k_is_constant = (opts & JSON_C_OBJECT_KEY_IS_CONSTANT); + t->table[n].v = v; + t->count++; + + if(t->head == NULL) { + t->head = t->tail = &t->table[n]; + t->table[n].next = t->table[n].prev = NULL; + } else { + t->tail->next = &t->table[n]; + t->table[n].prev = t->tail; + t->table[n].next = NULL; + t->tail = &t->table[n]; + } + + return 0; } int lh_table_insert(struct lh_table *t, const void *k, const void *v) { - return lh_table_insert_w_hash(t, k, v, lh_get_hash(t, k), 0); + return lh_table_insert_w_hash(t, k, v, lh_get_hash(t, k), 0); } struct lh_entry* lh_table_lookup_entry_w_hash(struct lh_table *t, const void *k, const unsigned long h) { - unsigned long n = h % t->size; - int count = 0; - - while( count < t->size ) { - if(t->table[n].k == LH_EMPTY) return NULL; - if(t->table[n].k != LH_FREED && - t->equal_fn(t->table[n].k, k)) return &t->table[n]; - if ((int)++n == t->size) n = 0; - count++; - } - return NULL; + unsigned long n = h % t->size; + int count = 0; + + while( count < t->size ) { + if(t->table[n].k == LH_EMPTY) return NULL; + if(t->table[n].k != LH_FREED && + t->equal_fn(t->table[n].k, k)) return &t->table[n]; + if ((int)++n == t->size) n = 0; + count++; + } + return NULL; } struct lh_entry* lh_table_lookup_entry(struct lh_table *t, const void *k) { - return lh_table_lookup_entry_w_hash(t, k, lh_get_hash(t, k)); + return lh_table_lookup_entry_w_hash(t, k, lh_get_hash(t, k)); } const void* lh_table_lookup(struct lh_table *t, const void *k) { - void *result; - lh_table_lookup_ex(t, k, &result); - return result; + void *result; + lh_table_lookup_ex(t, k, &result); + return result; } json_bool lh_table_lookup_ex(struct lh_table* t, const void* k, void **v) { - struct lh_entry *e = lh_table_lookup_entry(t, k); - if (e != NULL) { - if (v != NULL) *v = lh_entry_v(e); - return TRUE; /* key found */ - } - if (v != NULL) *v = NULL; - return FALSE; /* key not found */ + struct lh_entry *e = lh_table_lookup_entry(t, k); + if (e != NULL) { + if (v != NULL) *v = lh_entry_v(e); + return TRUE; /* key found */ + } + if (v != NULL) *v = NULL; + return FALSE; /* key not found */ } int lh_table_delete_entry(struct lh_table *t, struct lh_entry *e) { - ptrdiff_t n = (ptrdiff_t)(e - t->table); /* CAW: fixed to be 64bit nice, still need the crazy negative case... */ - - /* CAW: this is bad, really bad, maybe stack goes other direction on this machine... */ - if(n < 0) { return -2; } - - if(t->table[n].k == LH_EMPTY || t->table[n].k == LH_FREED) return -1; - t->count--; - if(t->free_fn) t->free_fn(e); - t->table[n].v = NULL; - t->table[n].k = LH_FREED; - if(t->tail == &t->table[n] && t->head == &t->table[n]) { - t->head = t->tail = NULL; - } else if (t->head == &t->table[n]) { - t->head->next->prev = NULL; - t->head = t->head->next; - } else if (t->tail == &t->table[n]) { - t->tail->prev->next = NULL; - t->tail = t->tail->prev; - } else { - t->table[n].prev->next = t->table[n].next; - t->table[n].next->prev = t->table[n].prev; - } - t->table[n].next = t->table[n].prev = NULL; - return 0; + ptrdiff_t n = (ptrdiff_t)(e - t->table); /* CAW: fixed to be 64bit nice, still need the crazy negative case... */ + + /* CAW: this is bad, really bad, maybe stack goes other direction on this machine... */ + if(n < 0) { return -2; } + + if(t->table[n].k == LH_EMPTY || t->table[n].k == LH_FREED) return -1; + t->count--; + if(t->free_fn) t->free_fn(e); + t->table[n].v = NULL; + t->table[n].k = LH_FREED; + if(t->tail == &t->table[n] && t->head == &t->table[n]) { + t->head = t->tail = NULL; + } else if (t->head == &t->table[n]) { + t->head->next->prev = NULL; + t->head = t->head->next; + } else if (t->tail == &t->table[n]) { + t->tail->prev->next = NULL; + t->tail = t->tail->prev; + } else { + t->table[n].prev->next = t->table[n].next; + t->table[n].next->prev = t->table[n].prev; + } + t->table[n].next = t->table[n].prev = NULL; + return 0; } int lh_table_delete(struct lh_table *t, const void *k) { - struct lh_entry *e = lh_table_lookup_entry(t, k); - if(!e) return -1; - return lh_table_delete_entry(t, e); + struct lh_entry *e = lh_table_lookup_entry(t, k); + if(!e) return -1; + return lh_table_delete_entry(t, e); } int lh_table_length(struct lh_table *t) { - return t->count; + return t->count; } diff --git a/phlib/jsonc/random_seed.c b/phlib/jsonc/random_seed.c index 9901515b2b8f..f0b92b9fd3a7 100644 --- a/phlib/jsonc/random_seed.c +++ b/phlib/jsonc/random_seed.c @@ -106,14 +106,14 @@ static int get_rdrand_seed() static int get_rdrand_seed() { - DEBUG_SEED("get_rdrand_seed"); - int _eax; + DEBUG_SEED("get_rdrand_seed"); + int _eax; retry: - // rdrand eax - __asm _emit 0x0F __asm _emit 0xC7 __asm _emit 0xF0 - __asm jnc retry - __asm mov _eax, eax - return _eax; + // rdrand eax + __asm _emit 0x0F __asm _emit 0xC7 __asm _emit 0xF0 + __asm jnc retry + __asm mov _eax, eax + return _eax; } #endif From 5b1c7982ea9f62b3c69d29abdf549e2fcd49b55b Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 25 May 2018 14:07:49 +1000 Subject: [PATCH 0984/2058] Update mxml to 2.11 --- phlib/mxml/config.h | 32 ++++-- phlib/mxml/mxml-attr.c | 89 +++++++++++------ phlib/mxml/mxml-entity.c | 18 +--- phlib/mxml/mxml-file.c | 181 +++++++++++++++++----------------- phlib/mxml/mxml-get.c | 43 ++++----- phlib/mxml/mxml-index.c | 82 ++++++++-------- phlib/mxml/mxml-node.c | 198 ++++++++++++++++++++++---------------- phlib/mxml/mxml-private.c | 13 +-- phlib/mxml/mxml-private.h | 13 +-- phlib/mxml/mxml-search.c | 46 ++++----- phlib/mxml/mxml-set.c | 67 ++++++++++--- phlib/mxml/mxml-string.c | 118 ++++++++++++++++++++--- phlib/mxml/mxml.h | 35 ++++--- 13 files changed, 555 insertions(+), 380 deletions(-) diff --git a/phlib/mxml/config.h b/phlib/mxml/config.h index e059e56d2b7a..cf6bdf528f76 100644 --- a/phlib/mxml/config.h +++ b/phlib/mxml/config.h @@ -1,9 +1,7 @@ /* - * "$Id: config.h 451 2014-01-04 21:50:06Z msweet $" + * Configuration file for Mini-XML, a small XML file parsing library. * - * Configuration file for Mini-XML, a small XML-like file parsing library. - * - * Copyright 2003-2014 by Michael R Sweet. + * Copyright 2003-2017 by Michael R Sweet. * * These coded instructions, statements, and computer programs are the * property of Michael R Sweet and are protected by Federal copyright @@ -11,7 +9,7 @@ * which should have been included with this file. If this file is * missing or damaged, see the license at: * - * http://www.msweet.org/projects.php/Mini-XML + * https://michaelrsweet.github.io/mxml */ /* @@ -29,7 +27,7 @@ * Version number... */ -#define MXML_VERSION "Mini-XML v2.10" +#define MXML_VERSION "Mini-XML v2.11" /* @@ -45,12 +43,18 @@ #define HAVE_LONG_LONG 1 + /* + * Do we have ? + */ + +#undef HAVE_ZLIB_H /* * Do we have the snprintf() and vsnprintf() functions? */ #define HAVE_SNPRINTF 1 +#undef HAVE_VASPRINTF #define HAVE_VSNPRINTF 1 @@ -59,7 +63,8 @@ */ #define HAVE_STRDUP 1 - +#undef HAVE_STRLCAT +#undef HAVE_STRLCPY /* * Do we have threading support? @@ -77,6 +82,16 @@ extern char *_mxml_strdup(const char *); # define strdup _mxml_strdup # endif /* !HAVE_STRDUP */ +# ifndef HAVE_STRLCAT +extern size_t _mxml_strlcat(char *, const char *, size_t); +# define strlcat _mxml_strlcat +# endif /* !HAVE_STRLCAT */ + +# ifndef HAVE_STRLCPY +extern size_t _mxml_strlcpy(char *, const char *, size_t); +# define strlcpy _mxml_strlcpy +# endif /* !HAVE_STRLCPY */ + extern char *_mxml_strdupf(const char *, ...); extern char *_mxml_vstrdupf(const char *, va_list); @@ -90,6 +105,3 @@ extern int _mxml_vsnprintf(char *, size_t, const char *, va_list); # define vsnprintf _mxml_vsnprintf # endif /* !HAVE_VSNPRINTF */ -/* - * End of "$Id: config.h 451 2014-01-04 21:50:06Z msweet $". - */ diff --git a/phlib/mxml/mxml-attr.c b/phlib/mxml/mxml-attr.c index 53b7cd0e86af..beb0b3f36118 100644 --- a/phlib/mxml/mxml-attr.c +++ b/phlib/mxml/mxml-attr.c @@ -1,9 +1,7 @@ /* - * "$Id: mxml-attr.c 451 2014-01-04 21:50:06Z msweet $" + * Attribute support code for Mini-XML, a small XML file parsing library. * - * Attribute support code for Mini-XML, a small XML-like file parsing library. - * - * Copyright 2003-2014 by Michael R Sweet. + * Copyright 2003-2017 by Michael R Sweet. * * These coded instructions, statements, and computer programs are the * property of Michael R Sweet and are protected by Federal copyright @@ -11,7 +9,7 @@ * which should have been included with this file. If this file is * missing or damaged, see the license at: * - * http://www.msweet.org/projects.php/Mini-XML + * https://michaelrsweet.github.io/mxml */ /* @@ -45,7 +43,7 @@ mxmlElementDeleteAttr(mxml_node_t *node,/* I - Element */ mxml_attr_t *attr; /* Cirrent attribute */ -#if DEBUG > 1 +#ifdef DEBUG fprintf(stderr, "mxmlElementDeleteAttr(node=%p, name=\"%s\")\n", node, name ? name : "(null)"); #endif /* DEBUG */ @@ -65,7 +63,7 @@ mxmlElementDeleteAttr(mxml_node_t *node,/* I - Element */ i > 0; i --, attr ++) { -#if DEBUG > 1 +#ifdef DEBUG printf(" %s=\"%s\"\n", attr->name, attr->value); #endif /* DEBUG */ @@ -75,8 +73,8 @@ mxmlElementDeleteAttr(mxml_node_t *node,/* I - Element */ * Delete this attribute... */ - PhFree(attr->name); - PhFree(attr->value); + PhFree(attr->name); + PhFree(attr->value); i --; if (i > 0) @@ -85,7 +83,7 @@ mxmlElementDeleteAttr(mxml_node_t *node,/* I - Element */ node->value.element.num_attrs --; if (node->value.element.num_attrs == 0) - PhFree(node->value.element.attrs); + PhFree(node->value.element.attrs); return; } } @@ -95,11 +93,11 @@ mxmlElementDeleteAttr(mxml_node_t *node,/* I - Element */ /* * 'mxmlElementGetAttr()' - Get an attribute. * - * This function returns NULL if the node is not an element or the + * This function returns @code NULL@ if the node is not an element or the * named attribute does not exist. */ -const char * /* O - Attribute value or NULL */ +const char * /* O - Attribute value or @code NULL@ */ mxmlElementGetAttr(mxml_node_t *node, /* I - Element node */ const char *name) /* I - Name of attribute */ { @@ -107,7 +105,7 @@ mxmlElementGetAttr(mxml_node_t *node, /* I - Element node */ mxml_attr_t *attr; /* Cirrent attribute */ -#if DEBUG > 1 +#ifdef DEBUG fprintf(stderr, "mxmlElementGetAttr(node=%p, name=\"%s\")\n", node, name ? name : "(null)"); #endif /* DEBUG */ @@ -127,13 +125,13 @@ mxmlElementGetAttr(mxml_node_t *node, /* I - Element node */ i > 0; i --, attr ++) { -#if DEBUG > 1 +#ifdef DEBUG printf(" %s=\"%s\"\n", attr->name, attr->value); #endif /* DEBUG */ if (!strcmp(attr->name, name)) { -#if DEBUG > 1 +#ifdef DEBUG printf(" Returning \"%s\"!\n", attr->value); #endif /* DEBUG */ return (attr->value); @@ -144,7 +142,7 @@ mxmlElementGetAttr(mxml_node_t *node, /* I - Element node */ * Didn't find attribute, so return NULL... */ -#if DEBUG > 1 +#ifdef DEBUG puts(" Returning NULL!\n"); #endif /* DEBUG */ @@ -152,6 +150,48 @@ mxmlElementGetAttr(mxml_node_t *node, /* I - Element node */ } +/* + * 'mxmlElementGetAttrByIndex()' - Get an element attribute by index. + * + * The index ("idx") is 0-based. @code NULL@ is returned if the specified index + * is out of range. + * + * @since Mini-XML 2.11@ + */ + +const char * /* O - Attribute value */ +mxmlElementGetAttrByIndex( + mxml_node_t *node, /* I - Node */ + int idx, /* I - Attribute index, starting at 0 */ + const char **name) /* O - Attribute name */ +{ + if (!node || node->type != MXML_ELEMENT || idx < 0 || idx >= node->value.element.num_attrs) + return (NULL); + + if (name) + *name = node->value.element.attrs[idx].name; + + return (node->value.element.attrs[idx].value); +} + + +/* + * 'mxmlElementGetAttrCount()' - Get the number of element attributes. + * + * @since Mini-XML 2.11@ + */ + +int /* O - Number of attributes */ +mxmlElementGetAttrCount( + mxml_node_t *node) /* I - Node */ +{ + if (node && node->type == MXML_ELEMENT) + return (node->value.element.num_attrs); + else + return (0); +} + + /* * 'mxmlElementSetAttr()' - Set an attribute. * @@ -169,7 +209,7 @@ mxmlElementSetAttr(mxml_node_t *node, /* I - Element node */ char *valuec; /* Copy of value */ -#if DEBUG > 1 +#ifdef DEBUG fprintf(stderr, "mxmlElementSetAttr(node=%p, name=\"%s\", value=\"%s\")\n", node, name ? name : "(null)", value ? value : "(null)"); #endif /* DEBUG */ @@ -182,12 +222,12 @@ mxmlElementSetAttr(mxml_node_t *node, /* I - Element node */ return; if (value) - valuec = PhDuplicateBytesZSafe((char *)value); + valuec = PhDuplicateBytesZSafe((char *)value); else valuec = NULL; if (mxml_set_attr(node, name, valuec)) - PhFree(valuec); + PhFree(valuec); } @@ -212,7 +252,7 @@ mxmlElementSetAttrf(mxml_node_t *node, /* I - Element node */ char *value; /* Value */ -#if DEBUG > 1 +#ifdef DEBUG fprintf(stderr, "mxmlElementSetAttrf(node=%p, name=\"%s\", format=\"%s\", ...)\n", node, name ? name : "(null)", format ? format : "(null)"); @@ -237,7 +277,7 @@ mxmlElementSetAttrf(mxml_node_t *node, /* I - Element node */ mxml_error("Unable to allocate memory for attribute '%s' in element %s!", name, node->value.element.name); else if (mxml_set_attr(node, name, value)) - PhFree(value); + PhFree(value); } @@ -268,7 +308,7 @@ mxml_set_attr(mxml_node_t *node, /* I - Element node */ */ if (attr->value) - PhFree(attr->value); + PhFree(attr->value); attr->value = value; @@ -308,8 +348,3 @@ mxml_set_attr(mxml_node_t *node, /* I - Element node */ return (0); } - - -/* - * End of "$Id: mxml-attr.c 451 2014-01-04 21:50:06Z msweet $". - */ diff --git a/phlib/mxml/mxml-entity.c b/phlib/mxml/mxml-entity.c index b32e8a91ffef..d4845084b83b 100644 --- a/phlib/mxml/mxml-entity.c +++ b/phlib/mxml/mxml-entity.c @@ -1,10 +1,7 @@ /* - * "$Id: mxml-entity.c 451 2014-01-04 21:50:06Z msweet $" + * Character entity support code for Mini-XML, a small XML file parsing library. * - * Character entity support code for Mini-XML, a small XML-like - * file parsing library. - * - * Copyright 2003-2014 by Michael R Sweet. + * Copyright 2003-2017 by Michael R Sweet. * * These coded instructions, statements, and computer programs are the * property of Michael R Sweet and are protected by Federal copyright @@ -12,7 +9,7 @@ * which should have been included with this file. If this file is * missing or damaged, see the license at: * - * http://www.msweet.org/projects.php/Mini-XML + * https://michaelrsweet.github.io/mxml */ /* @@ -53,10 +50,10 @@ mxmlEntityAddCallback( /* * 'mxmlEntityGetName()' - Get the name that corresponds to the character value. * - * If val does not need to be represented by a named entity, NULL is returned. + * If val does not need to be represented by a named entity, @code NULL@ is returned. */ -const char * /* O - Entity name or NULL */ +const char * /* O - Entity name or @code NULL@ */ mxmlEntityGetName(int val) /* I - Character value */ { switch (val) @@ -442,8 +439,3 @@ _mxml_entity_cb(const char *name) /* I - Entity name */ else return (-1); } - - -/* - * End of "$Id: mxml-entity.c 451 2014-01-04 21:50:06Z msweet $". - */ diff --git a/phlib/mxml/mxml-file.c b/phlib/mxml/mxml-file.c index d6306cb999d6..3eff0b3ad3b3 100644 --- a/phlib/mxml/mxml-file.c +++ b/phlib/mxml/mxml-file.c @@ -1,9 +1,7 @@ /* - * "$Id: mxml-file.c 467 2016-06-13 00:51:16Z msweet $" + * File loading code for Mini-XML, a small XML file parsing library. * - * File loading code for Mini-XML, a small XML-like file parsing library. - * - * Copyright 2003-2016 by Michael R Sweet. + * Copyright 2003-2017 by Michael R Sweet. * * These coded instructions, statements, and computer programs are the * property of Michael R Sweet and are protected by Federal copyright @@ -11,7 +9,7 @@ * which should have been included with this file. If this file is * missing or damaged, see the license at: * - * http://www.msweet.org/projects.php/Mini-XML + * https://michaelrsweet.github.io/mxml */ /* @@ -106,18 +104,15 @@ static int mxml_write_ws(mxml_node_t *node, void *p, * If no top node is provided, the XML file MUST be well-formed with a * single parent node like for the entire file. The callback * function returns the value type that should be used for child nodes. - * If MXML_NO_CALLBACK is specified then all child nodes will be either - * MXML_ELEMENT or MXML_TEXT nodes. - * - * The constants MXML_INTEGER_CALLBACK, MXML_OPAQUE_CALLBACK, - * MXML_REAL_CALLBACK, and MXML_TEXT_CALLBACK are defined for loading - * child nodes of the specified type. + * The constants @code MXML_INTEGER_CALLBACK@, @code MXML_OPAQUE_CALLBACK@, + * @code MXML_REAL_CALLBACK@, and @code MXML_TEXT_CALLBACK@ are defined for + * loading child (data) nodes of the specified type. */ -mxml_node_t * /* O - First node or NULL if the file could not be read. */ +mxml_node_t * /* O - First node or @code NULL@ if the file could not be read. */ mxmlLoadFd(mxml_node_t *top, /* I - Top node */ HANDLE fd, /* I - File descriptor to read from */ - mxml_load_cb_t cb) /* I - Callback function or MXML_NO_CALLBACK */ + mxml_load_cb_t cb) /* I - Callback function or constant */ { _mxml_fdbuf_t buf; /* File descriptor buffer */ @@ -145,18 +140,15 @@ mxmlLoadFd(mxml_node_t *top, /* I - Top node */ * If no top node is provided, the XML file MUST be well-formed with a * single parent node like for the entire file. The callback * function returns the value type that should be used for child nodes. - * If MXML_NO_CALLBACK is specified then all child nodes will be either - * MXML_ELEMENT or MXML_TEXT nodes. - * - * The constants MXML_INTEGER_CALLBACK, MXML_OPAQUE_CALLBACK, - * MXML_REAL_CALLBACK, and MXML_TEXT_CALLBACK are defined for loading - * child nodes of the specified type. + * The constants @code MXML_INTEGER_CALLBACK@, @code MXML_OPAQUE_CALLBACK@, + * @code MXML_REAL_CALLBACK@, and @code MXML_TEXT_CALLBACK@ are defined for + * loading child (data) nodes of the specified type. */ -mxml_node_t * /* O - First node or NULL if the file could not be read. */ +mxml_node_t * /* O - First node or @code NULL@ if the file could not be read. */ mxmlLoadFile(mxml_node_t *top, /* I - Top node */ FILE *fp, /* I - File to read from */ - mxml_load_cb_t cb) /* I - Callback function or MXML_NO_CALLBACK */ + mxml_load_cb_t cb) /* I - Callback function or constant */ { /* * Read the XML data... @@ -173,18 +165,15 @@ mxmlLoadFile(mxml_node_t *top, /* I - Top node */ * If no top node is provided, the XML string MUST be well-formed with a * single parent node like for the entire string. The callback * function returns the value type that should be used for child nodes. - * If MXML_NO_CALLBACK is specified then all child nodes will be either - * MXML_ELEMENT or MXML_TEXT nodes. - * - * The constants MXML_INTEGER_CALLBACK, MXML_OPAQUE_CALLBACK, - * MXML_REAL_CALLBACK, and MXML_TEXT_CALLBACK are defined for loading - * child nodes of the specified type. + * The constants @code MXML_INTEGER_CALLBACK@, @code MXML_OPAQUE_CALLBACK@, + * @code MXML_REAL_CALLBACK@, and @code MXML_TEXT_CALLBACK@ are defined for + * loading child (data) nodes of the specified type. */ -mxml_node_t * /* O - First node or NULL if the string has errors. */ +mxml_node_t * /* O - First node or @code NULL@ if the string has errors. */ mxmlLoadString(mxml_node_t *top, /* I - Top node */ const char *s, /* I - String to load */ - mxml_load_cb_t cb) /* I - Callback function or MXML_NO_CALLBACK */ + mxml_load_cb_t cb) /* I - Callback function or constant */ { /* * Read the XML data... @@ -200,21 +189,21 @@ mxmlLoadString(mxml_node_t *top, /* I - Top node */ * * This function returns a pointer to a string containing the textual * representation of the XML node tree. The string should be freed - * using the free() function when you are done with it. NULL is returned + * using the free() function when you are done with it. @code NULL@ is returned * if the node would produce an empty string or if the string cannot be * allocated. * * The callback argument specifies a function that returns a whitespace - * string or NULL before and after each element. If MXML_NO_CALLBACK - * is specified, whitespace will only be added before MXML_TEXT nodes + * string or NULL before and after each element. If @code MXML_NO_CALLBACK@ + * is specified, whitespace will only be added before @code MXML_TEXT@ nodes * with leading whitespace and before attribute names inside opening * element tags. */ -char * /* O - Allocated string or NULL */ +char * /* O - Allocated string or @code NULL@ */ mxmlSaveAllocString( mxml_node_t *node, /* I - Node to write */ - mxml_save_cb_t cb) /* I - Whitespace callback or MXML_NO_CALLBACK */ + mxml_save_cb_t cb) /* I - Whitespace callback or @code MXML_NO_CALLBACK@ */ { int bytes; /* Required bytes */ char buffer[8192]; /* Temporary buffer */ @@ -262,16 +251,16 @@ mxmlSaveAllocString( * 'mxmlSaveFd()' - Save an XML tree to a file descriptor. * * The callback argument specifies a function that returns a whitespace - * string or NULL before and after each element. If MXML_NO_CALLBACK - * is specified, whitespace will only be added before MXML_TEXT nodes + * string or NULL before and after each element. If @code MXML_NO_CALLBACK@ + * is specified, whitespace will only be added before @code MXML_TEXT@ nodes * with leading whitespace and before attribute names inside opening * element tags. */ int /* O - 0 on success, -1 on error. */ mxmlSaveFd(mxml_node_t *node, /* I - Node to write */ - HANDLE fd, /* I - File descriptor to write to */ - mxml_save_cb_t cb) /* I - Whitespace callback or MXML_NO_CALLBACK */ + HANDLE fd, /* I - File descriptor to write to */ + mxml_save_cb_t cb) /* I - Whitespace callback or @code MXML_NO_CALLBACK@ */ { int col; /* Final column */ _mxml_fdbuf_t buf; /* File descriptor buffer */ @@ -310,8 +299,8 @@ mxmlSaveFd(mxml_node_t *node, /* I - Node to write */ * 'mxmlSaveFile()' - Save an XML tree to a file. * * The callback argument specifies a function that returns a whitespace - * string or NULL before and after each element. If MXML_NO_CALLBACK - * is specified, whitespace will only be added before MXML_TEXT nodes + * string or NULL before and after each element. If @code MXML_NO_CALLBACK@ + * is specified, whitespace will only be added before @code MXML_TEXT@ nodes * with leading whitespace and before attribute names inside opening * element tags. */ @@ -319,7 +308,7 @@ mxmlSaveFd(mxml_node_t *node, /* I - Node to write */ int /* O - 0 on success, -1 on error. */ mxmlSaveFile(mxml_node_t *node, /* I - Node to write */ FILE *fp, /* I - File to write to */ - mxml_save_cb_t cb) /* I - Whitespace callback or MXML_NO_CALLBACK */ + mxml_save_cb_t cb) /* I - Whitespace callback or @code MXML_NO_CALLBACK@ */ { int col; /* Final column */ _mxml_global_t *global = _mxml_global(); @@ -353,8 +342,8 @@ mxmlSaveFile(mxml_node_t *node, /* I - Node to write */ * into the specified buffer. * * The callback argument specifies a function that returns a whitespace - * string or NULL before and after each element. If MXML_NO_CALLBACK - * is specified, whitespace will only be added before MXML_TEXT nodes + * string or NULL before and after each element. If @code MXML_NO_CALLBACK@ + * is specified, whitespace will only be added before @code MXML_TEXT@ nodes * with leading whitespace and before attribute names inside opening * element tags. */ @@ -363,7 +352,7 @@ int /* O - Size of string */ mxmlSaveString(mxml_node_t *node, /* I - Node to write */ char *buffer, /* I - String buffer */ int bufsize, /* I - Size of string buffer */ - mxml_save_cb_t cb) /* I - Whitespace callback or MXML_NO_CALLBACK */ + mxml_save_cb_t cb) /* I - Whitespace callback or @code MXML_NO_CALLBACK@ */ { int col; /* Final column */ char *ptr[2]; /* Pointers for putc_cb */ @@ -397,7 +386,7 @@ mxmlSaveString(mxml_node_t *node, /* I - Node to write */ * Return the number of characters... */ - return (int)(ptr[0] - buffer); + return ((int)(ptr[0] - buffer)); } @@ -409,25 +398,22 @@ mxmlSaveString(mxml_node_t *node, /* I - Node to write */ * If no top node is provided, the XML file MUST be well-formed with a * single parent node like for the entire file. The callback * function returns the value type that should be used for child nodes. - * If MXML_NO_CALLBACK is specified then all child nodes will be either - * MXML_ELEMENT or MXML_TEXT nodes. + * The constants @code MXML_INTEGER_CALLBACK@, @code MXML_OPAQUE_CALLBACK@, + * @code MXML_REAL_CALLBACK@, and @code MXML_TEXT_CALLBACK@ are defined for + * loading child nodes of the specified type. * - * The constants MXML_INTEGER_CALLBACK, MXML_OPAQUE_CALLBACK, - * MXML_REAL_CALLBACK, and MXML_TEXT_CALLBACK are defined for loading - * child nodes of the specified type. - * - * The SAX callback must call mxmlRetain() for any nodes that need to + * The SAX callback must call @link mxmlRetain@ for any nodes that need to * be kept for later use. Otherwise, nodes are deleted when the parent * node is closed or after each data, comment, CDATA, or directive node. * * @since Mini-XML 2.3@ */ -mxml_node_t * /* O - First node or NULL if the file could not be read. */ +mxml_node_t * /* O - First node or @code NULL@ if the file could not be read. */ mxmlSAXLoadFd(mxml_node_t *top, /* I - Top node */ HANDLE fd, /* I - File descriptor to read from */ - mxml_load_cb_t cb, /* I - Callback function or MXML_NO_CALLBACK */ - mxml_sax_cb_t sax_cb, /* I - SAX callback or MXML_NO_CALLBACK */ + mxml_load_cb_t cb, /* I - Callback function or constant */ + mxml_sax_cb_t sax_cb, /* I - SAX callback or @code MXML_NO_CALLBACK@ */ void *sax_data) /* I - SAX user data */ { _mxml_fdbuf_t buf; /* File descriptor buffer */ @@ -457,26 +443,23 @@ mxmlSAXLoadFd(mxml_node_t *top, /* I - Top node */ * If no top node is provided, the XML file MUST be well-formed with a * single parent node like for the entire file. The callback * function returns the value type that should be used for child nodes. - * If MXML_NO_CALLBACK is specified then all child nodes will be either - * MXML_ELEMENT or MXML_TEXT nodes. - * - * The constants MXML_INTEGER_CALLBACK, MXML_OPAQUE_CALLBACK, - * MXML_REAL_CALLBACK, and MXML_TEXT_CALLBACK are defined for loading - * child nodes of the specified type. + * The constants @code MXML_INTEGER_CALLBACK@, @code MXML_OPAQUE_CALLBACK@, + * @code MXML_REAL_CALLBACK@, and @code MXML_TEXT_CALLBACK@ are defined for + * loading child nodes of the specified type. * - * The SAX callback must call mxmlRetain() for any nodes that need to + * The SAX callback must call @link mxmlRetain@ for any nodes that need to * be kept for later use. Otherwise, nodes are deleted when the parent * node is closed or after each data, comment, CDATA, or directive node. * * @since Mini-XML 2.3@ */ -mxml_node_t * /* O - First node or NULL if the file could not be read. */ +mxml_node_t * /* O - First node or @code NULL@ if the file could not be read. */ mxmlSAXLoadFile( mxml_node_t *top, /* I - Top node */ FILE *fp, /* I - File to read from */ - mxml_load_cb_t cb, /* I - Callback function or MXML_NO_CALLBACK */ - mxml_sax_cb_t sax_cb, /* I - SAX callback or MXML_NO_CALLBACK */ + mxml_load_cb_t cb, /* I - Callback function or constant */ + mxml_sax_cb_t sax_cb, /* I - SAX callback or @code MXML_NO_CALLBACK@ */ void *sax_data) /* I - SAX user data */ { /* @@ -495,26 +478,23 @@ mxmlSAXLoadFile( * If no top node is provided, the XML string MUST be well-formed with a * single parent node like for the entire string. The callback * function returns the value type that should be used for child nodes. - * If MXML_NO_CALLBACK is specified then all child nodes will be either - * MXML_ELEMENT or MXML_TEXT nodes. - * - * The constants MXML_INTEGER_CALLBACK, MXML_OPAQUE_CALLBACK, - * MXML_REAL_CALLBACK, and MXML_TEXT_CALLBACK are defined for loading - * child nodes of the specified type. + * The constants @code MXML_INTEGER_CALLBACK@, @code MXML_OPAQUE_CALLBACK@, + * @code MXML_REAL_CALLBACK@, and @code MXML_TEXT_CALLBACK@ are defined for + * loading child nodes of the specified type. * - * The SAX callback must call mxmlRetain() for any nodes that need to + * The SAX callback must call @link mxmlRetain@ for any nodes that need to * be kept for later use. Otherwise, nodes are deleted when the parent * node is closed or after each data, comment, CDATA, or directive node. * * @since Mini-XML 2.3@ */ -mxml_node_t * /* O - First node or NULL if the string has errors. */ +mxml_node_t * /* O - First node or @code NULL@ if the string has errors. */ mxmlSAXLoadString( mxml_node_t *top, /* I - Top node */ const char *s, /* I - String to load */ - mxml_load_cb_t cb, /* I - Callback function or MXML_NO_CALLBACK */ - mxml_sax_cb_t sax_cb, /* I - SAX callback or MXML_NO_CALLBACK */ + mxml_load_cb_t cb, /* I - Callback function or constant */ + mxml_sax_cb_t sax_cb, /* I - SAX callback or @code MXML_NO_CALLBACK@ */ void *sax_data) /* I - SAX user data */ { /* @@ -532,7 +512,7 @@ mxmlSAXLoadString( * return 0 on success and non-zero on error. * * The save function accepts a node pointer and must return a malloc'd - * string on success and NULL on error. + * string on success and @code NULL@ on error. * */ @@ -1035,7 +1015,7 @@ mxml_fd_write(_mxml_fdbuf_t *buf) /* I - File descriptor buffer */ IO_STATUS_BLOCK isb; if (!buf) - return 1; + return -1; if (buf->current == buf->buffer) return 0; @@ -1320,9 +1300,9 @@ mxml_get_entity(mxml_node_t *parent, /* I - Parent node */ if (entity[0] == '#') { if (entity[1] == 'x') - ch = strtol(entity + 2, NULL, 16); + ch = (int)strtol(entity + 2, NULL, 16); else - ch = strtol(entity + 1, NULL, 10); + ch = (int)strtol(entity + 1, NULL, 10); } else if ((ch = mxmlEntityGetValue(entity)) < 0) mxml_error("Entity name \"%s;\" not supported under parent <%s>!", @@ -1414,7 +1394,7 @@ mxml_load_data( switch (type) { case MXML_INTEGER : - node = mxmlNewInteger(parent, strtol(buffer, &bufptr, 0)); + node = mxmlNewInteger(parent, (int)strtol(buffer, &bufptr, 0)); break; case MXML_OPAQUE : @@ -1632,7 +1612,14 @@ mxml_load_data( while ((ch = (*getc_cb)(p, &encoding)) != EOF) { if (ch == '>' && !strncmp(bufptr - 2, "]]", 2)) + { + /* + * Drop terminator from CDATA string... + */ + + bufptr[-2] = '\0'; break; + } else if (mxml_add_char(ch, &bufptr, &buffer, &bufsize)) goto error; } @@ -2085,7 +2072,7 @@ mxml_parse_element( if ((value = PhAllocateSafe(64)) == NULL) { - PhFree(name); + PhFree(name); mxml_error("Unable to allocate memory for value!"); return (EOF); } @@ -2706,12 +2693,24 @@ mxml_write_node(mxml_node_t *node, /* I - Node to write */ if ((*putc_cb)('<', p) < 0) return (-1); if (current->value.element.name[0] == '?' || - !strncmp(current->value.element.name, "!--", 3) || - !strncmp(current->value.element.name, "![CDATA[", 8)) + !strncmp(current->value.element.name, "!--", 3)) + { + /* + * Comments and processing instructions do not use character + * entities. + */ + + const char *ptr; /* Pointer into name */ + + for (ptr = current->value.element.name; *ptr; ptr ++) + if ((*putc_cb)(*ptr, p) < 0) + return (-1); + } + else if (!strncmp(current->value.element.name, "![CDATA[", 8)) { /* - * Comments, CDATA, and processing instructions do not - * use character entities. + * CDATA elements do not use character entities, but also need the + * "]]" terminator added at the end. */ const char *ptr; /* Pointer into name */ @@ -2719,6 +2718,11 @@ mxml_write_node(mxml_node_t *node, /* I - Node to write */ for (ptr = current->value.element.name; *ptr; ptr ++) if ((*putc_cb)(*ptr, p) < 0) return (-1); + + if ((*putc_cb)(']', p) < 0) + return (-1); + if ((*putc_cb)(']', p) < 0) + return (-1); } else if (mxml_write_name(current->value.element.name, p, putc_cb) < 0) return (-1); @@ -2891,7 +2895,7 @@ mxml_write_node(mxml_node_t *node, /* I - Node to write */ const char *newline; /* Last newline in string */ - if ((data = (*global->custom_save_cb)(node)) == NULL) + if ((data = (*global->custom_save_cb)(current)) == NULL) return (-1); if (mxml_write_string(data, p, putc_cb) < 0) @@ -3030,8 +3034,3 @@ mxml_write_ws(mxml_node_t *node, /* I - Current node */ return (col); } - - -/* - * End of "$Id: mxml-file.c 467 2016-06-13 00:51:16Z msweet $". - */ diff --git a/phlib/mxml/mxml-get.c b/phlib/mxml/mxml-get.c index 40ed3d0839b4..e572fb1abb2d 100644 --- a/phlib/mxml/mxml-get.c +++ b/phlib/mxml/mxml-get.c @@ -1,9 +1,7 @@ /* - * "$Id: mxml-get.c 451 2014-01-04 21:50:06Z msweet $" + * Node get functions for Mini-XML, a small XML file parsing library. * - * Node get functions for Mini-XML, a small XML-like file parsing library. - * - * Copyright 2014 by Michael R Sweet. + * Copyright 2014-2017 by Michael R Sweet. * * These coded instructions, statements, and computer programs are the * property of Michael R Sweet and are protected by Federal copyright @@ -11,7 +9,7 @@ * which should have been included with this file. If this file is * missing or damaged, see the license at: * - * http://www.msweet.org/projects.php/Mini-XML + * https://michaelrsweet.github.io/mxml */ /* @@ -30,7 +28,7 @@ * @since Mini-XML 2.7@ */ -const char * /* O - CDATA value or NULL */ +const char * /* O - CDATA value or @code NULL@ */ mxmlGetCDATA(mxml_node_t *node) /* I - Node to get */ { /* @@ -58,7 +56,7 @@ mxmlGetCDATA(mxml_node_t *node) /* I - Node to get */ * @since Mini-XML 2.7@ */ -const void * /* O - Custom value or NULL */ +const void * /* O - Custom value or @code NULL@ */ mxmlGetCustom(mxml_node_t *node) /* I - Node to get */ { /* @@ -76,7 +74,7 @@ mxmlGetCustom(mxml_node_t *node) /* I - Node to get */ return (node->value.custom.data); else if (node->type == MXML_ELEMENT && node->child && - node->child->type == MXML_CUSTOM) + node->child->type == MXML_CUSTOM) return (node->child->value.custom.data); else return (NULL); @@ -91,7 +89,7 @@ mxmlGetCustom(mxml_node_t *node) /* I - Node to get */ * @since Mini-XML 2.7@ */ -const char * /* O - Element name or NULL */ +const char * /* O - Element name or @code NULL@ */ mxmlGetElement(mxml_node_t *node) /* I - Node to get */ { /* @@ -118,7 +116,7 @@ mxmlGetElement(mxml_node_t *node) /* I - Node to get */ * @since Mini-XML 2.7@ */ -mxml_node_t * /* O - First child or NULL */ +mxml_node_t * /* O - First child or @code NULL@ */ mxmlGetFirstChild(mxml_node_t *node) /* I - Node to get */ { /* @@ -163,7 +161,7 @@ mxmlGetInteger(mxml_node_t *node) /* I - Node to get */ return (node->value.integer); else if (node->type == MXML_ELEMENT && node->child && - node->child->type == MXML_INTEGER) + node->child->type == MXML_INTEGER) return (node->child->value.integer); else return (0); @@ -179,7 +177,7 @@ mxmlGetInteger(mxml_node_t *node) /* I - Node to get */ * @since Mini-XML 2.7@ */ -mxml_node_t * /* O - Last child or NULL */ +mxml_node_t * /* O - Last child or @code NULL@ */ mxmlGetLastChild(mxml_node_t *node) /* I - Node to get */ { /* @@ -232,7 +230,7 @@ mxmlGetNextSibling(mxml_node_t *node) /* I - Node to get */ * @since Mini-XML 2.7@ */ -const char * /* O - Opaque string or NULL */ +const char * /* O - Opaque string or @code NULL@ */ mxmlGetOpaque(mxml_node_t *node) /* I - Node to get */ { /* @@ -250,7 +248,7 @@ mxmlGetOpaque(mxml_node_t *node) /* I - Node to get */ return (node->value.opaque); else if (node->type == MXML_ELEMENT && node->child && - node->child->type == MXML_OPAQUE) + node->child->type == MXML_OPAQUE) return (node->child->value.opaque); else return (NULL); @@ -265,7 +263,7 @@ mxmlGetOpaque(mxml_node_t *node) /* I - Node to get */ * @since Mini-XML 2.7@ */ -mxml_node_t * /* O - Parent node or NULL */ +mxml_node_t * /* O - Parent node or @code NULL@ */ mxmlGetParent(mxml_node_t *node) /* I - Node to get */ { /* @@ -291,7 +289,7 @@ mxmlGetParent(mxml_node_t *node) /* I - Node to get */ * @since Mini-XML 2.7@ */ -mxml_node_t * /* O - Previous node or NULL */ +mxml_node_t * /* O - Previous node or @code NULL@ */ mxmlGetPrevSibling(mxml_node_t *node) /* I - Node to get */ { /* @@ -335,7 +333,7 @@ mxmlGetReal(mxml_node_t *node) /* I - Node to get */ return (node->value.real); else if (node->type == MXML_ELEMENT && node->child && - node->child->type == MXML_REAL) + node->child->type == MXML_REAL) return (node->child->value.real); else return (0.0); @@ -346,12 +344,12 @@ mxmlGetReal(mxml_node_t *node) /* I - Node to get */ * 'mxmlGetText()' - Get the text value for a node or its first child. * * @code NULL@ is returned if the node (or its first child) is not a text node. - * The "whitespace" argument can be NULL. + * The "whitespace" argument can be @code NULL@. * * @since Mini-XML 2.7@ */ -const char * /* O - Text string or NULL */ +const char * /* O - Text string or @code NULL@ */ mxmlGetText(mxml_node_t *node, /* I - Node to get */ int *whitespace) /* O - 1 if string is preceded by whitespace, 0 otherwise */ { @@ -380,7 +378,7 @@ mxmlGetText(mxml_node_t *node, /* I - Node to get */ } else if (node->type == MXML_ELEMENT && node->child && - node->child->type == MXML_TEXT) + node->child->type == MXML_TEXT) { if (whitespace) *whitespace = node->child->value.text.whitespace; @@ -445,8 +443,3 @@ mxmlGetUserData(mxml_node_t *node) /* I - Node to get */ return (node->user_data); } - - -/* - * End of "$Id: mxml-get.c 451 2014-01-04 21:50:06Z msweet $". - */ diff --git a/phlib/mxml/mxml-index.c b/phlib/mxml/mxml-index.c index 2db94eabd7de..366107ff003f 100644 --- a/phlib/mxml/mxml-index.c +++ b/phlib/mxml/mxml-index.c @@ -1,9 +1,7 @@ /* - * "$Id: mxml-index.c 451 2014-01-04 21:50:06Z msweet $" + * Index support code for Mini-XML, a small XML file parsing library. * - * Index support code for Mini-XML, a small XML-like file parsing library. - * - * Copyright 2003-2014 by Michael R Sweet. + * Copyright 2003-2017 by Michael R Sweet. * * These coded instructions, statements, and computer programs are the * property of Michael R Sweet and are protected by Federal copyright @@ -11,7 +9,7 @@ * which should have been included with this file. If this file is * missing or damaged, see the license at: * - * http://www.msweet.org/projects.php/Mini-XML + * https://michaelrsweet.github.io/mxml */ /* @@ -53,10 +51,10 @@ mxmlIndexDelete(mxml_index_t *ind) /* I - Index to delete */ */ if (ind->attr) - PhFree(ind->attr); + PhFree(ind->attr); if (ind->alloc_nodes) - PhFree(ind->nodes); + PhFree(ind->nodes); PhFree(ind); } @@ -65,10 +63,12 @@ mxmlIndexDelete(mxml_index_t *ind) /* I - Index to delete */ /* * 'mxmlIndexEnum()' - Return the next node in the index. * - * Nodes are returned in the sorted order of the index. + * You should call @link mxmlIndexReset@ prior to using this function to get + * the first node in the index. Nodes are returned in the sorted order of the + * index. */ -mxml_node_t * /* O - Next node or NULL if there is none */ +mxml_node_t * /* O - Next node or @code NULL@ if there is none */ mxmlIndexEnum(mxml_index_t *ind) /* I - Index to enumerate */ { /* @@ -92,13 +92,13 @@ mxmlIndexEnum(mxml_index_t *ind) /* I - Index to enumerate */ /* * 'mxmlIndexFind()' - Find the next matching node. * - * You should call mxmlIndexReset() prior to using this function for + * You should call @link mxmlIndexReset@ prior to using this function for * the first time with a particular set of "element" and "value" - * strings. Passing NULL for both "element" and "value" is equivalent - * to calling mxmlIndexEnum(). + * strings. Passing @code NULL@ for both "element" and "value" is equivalent + * to calling @link mxmlIndexEnum@. */ -mxml_node_t * /* O - Node or NULL if none found */ +mxml_node_t * /* O - Node or @code NULL@ if none found */ mxmlIndexFind(mxml_index_t *ind, /* I - Index to search */ const char *element, /* I - Element name to find, if any */ const char *value) /* I - Attribute value, if any */ @@ -109,7 +109,7 @@ mxmlIndexFind(mxml_index_t *ind, /* I - Index to search */ last; /* Last entity in search */ -#if DEBUG > 1 +#ifdef DEBUG printf("mxmlIndexFind(ind=%p, element=\"%s\", value=\"%s\")\n", ind, element ? element : "(null)", value ? value : "(null)"); #endif /* DEBUG */ @@ -120,9 +120,10 @@ mxmlIndexFind(mxml_index_t *ind, /* I - Index to search */ if (!ind || (!ind->attr && value)) { -#if DEBUG > 1 +#ifdef DEBUG puts(" returning NULL..."); - printf(" ind->attr=\"%s\"\n", ind->attr ? ind->attr : "(null)"); + if (ind) + printf(" ind->attr=\"%s\"\n", ind->attr ? ind->attr : "(null)"); #endif /* DEBUG */ return (NULL); @@ -142,7 +143,7 @@ mxmlIndexFind(mxml_index_t *ind, /* I - Index to search */ if (!ind->num_nodes) { -#if DEBUG > 1 +#ifdef DEBUG puts(" returning NULL..."); puts(" no nodes!"); #endif /* DEBUG */ @@ -163,7 +164,7 @@ mxmlIndexFind(mxml_index_t *ind, /* I - Index to search */ first = 0; last = ind->num_nodes - 1; -#if DEBUG > 1 +#ifdef DEBUG printf(" find first time, num_nodes=%d...\n", ind->num_nodes); #endif /* DEBUG */ @@ -171,7 +172,7 @@ mxmlIndexFind(mxml_index_t *ind, /* I - Index to search */ { current = (first + last) / 2; -#if DEBUG > 1 +#ifdef DEBUG printf(" first=%d, last=%d, current=%d\n", first, last, current); #endif /* DEBUG */ @@ -181,7 +182,7 @@ mxmlIndexFind(mxml_index_t *ind, /* I - Index to search */ * Found a match, move back to find the first... */ -#if DEBUG > 1 +#ifdef DEBUG puts(" match!"); #endif /* DEBUG */ @@ -189,7 +190,7 @@ mxmlIndexFind(mxml_index_t *ind, /* I - Index to search */ !index_find(ind, element, value, ind->nodes[current - 1])) current --; -#if DEBUG > 1 +#ifdef DEBUG printf(" returning first match=%d\n", current); #endif /* DEBUG */ @@ -206,7 +207,7 @@ mxmlIndexFind(mxml_index_t *ind, /* I - Index to search */ else first = current; -#if DEBUG > 1 +#ifdef DEBUG printf(" diff=%d\n", diff); #endif /* DEBUG */ } @@ -222,7 +223,7 @@ mxmlIndexFind(mxml_index_t *ind, /* I - Index to search */ * Found exactly one (or possibly two) match... */ -#if DEBUG > 1 +#ifdef DEBUG printf(" returning only match %d...\n", current); #endif /* DEBUG */ @@ -237,7 +238,7 @@ mxmlIndexFind(mxml_index_t *ind, /* I - Index to search */ ind->cur_node = ind->num_nodes; -#if DEBUG > 1 +#ifdef DEBUG puts(" returning NULL..."); #endif /* DEBUG */ @@ -250,7 +251,7 @@ mxmlIndexFind(mxml_index_t *ind, /* I - Index to search */ * Return the next matching node... */ -#if DEBUG > 1 +#ifdef DEBUG printf(" returning next match %d...\n", ind->cur_node); #endif /* DEBUG */ @@ -263,7 +264,7 @@ mxmlIndexFind(mxml_index_t *ind, /* I - Index to search */ ind->cur_node = ind->num_nodes; -#if DEBUG > 1 +#ifdef DEBUG puts(" returning NULL..."); #endif /* DEBUG */ @@ -299,7 +300,7 @@ mxmlIndexGetCount(mxml_index_t *ind) /* I - Index of nodes */ * 'mxmlIndexNew()' - Create a new index. * * The index will contain all nodes that contain the named element and/or - * attribute. If both "element" and "attr" are NULL, then the index will + * attribute. If both "element" and "attr" are @code NULL@, then the index will * contain a sorted list of the elements in the node tree. Nodes are * sorted by element name and optionally by attribute value if the "attr" * argument is not NULL. @@ -307,8 +308,8 @@ mxmlIndexGetCount(mxml_index_t *ind) /* I - Index of nodes */ mxml_index_t * /* O - New index */ mxmlIndexNew(mxml_node_t *node, /* I - XML node tree */ - const char *element, /* I - Element to index or NULL for all */ - const char *attr) /* I - Attribute to index or NULL for none */ + const char *element, /* I - Element to index or @code NULL@ for all */ + const char *attr) /* I - Attribute to index or @code NULL@ for none */ { mxml_index_t *ind; /* New index */ mxml_node_t *current, /* Current node in index */ @@ -319,7 +320,7 @@ mxmlIndexNew(mxml_node_t *node, /* I - XML node tree */ * Range check input... */ -#if DEBUG > 1 +#ifdef DEBUG printf("mxmlIndexNew(node=%p, element=\"%s\", attr=\"%s\")\n", node, element ? element : "(null)", attr ? attr : "(null)"); #endif /* DEBUG */ @@ -382,7 +383,7 @@ mxmlIndexNew(mxml_node_t *node, /* I - XML node tree */ * Sort nodes based upon the search criteria... */ -#if DEBUG > 1 +#ifdef DEBUG { int i; /* Looping var */ @@ -416,7 +417,7 @@ mxmlIndexNew(mxml_node_t *node, /* I - XML node tree */ if (ind->num_nodes > 1) index_sort(ind, 0, ind->num_nodes - 1); -#if DEBUG > 1 +#ifdef DEBUG { int i; /* Looping var */ @@ -459,14 +460,14 @@ mxmlIndexNew(mxml_node_t *node, /* I - XML node tree */ * 'mxmlIndexReset()' - Reset the enumeration/find pointer in the index and * return the first node in the index. * - * This function should be called prior to using mxmlIndexEnum() or - * mxmlIndexFind() for the first time. + * This function should be called prior to using @link mxmlIndexEnum@ or + * @link mxmlIndexFind@ for the first time. */ -mxml_node_t * /* O - First node or NULL if there is none */ +mxml_node_t * /* O - First node or @code NULL@ if there is none */ mxmlIndexReset(mxml_index_t *ind) /* I - Index to reset */ { -#if DEBUG > 1 +#ifdef DEBUG printf("mxmlIndexReset(ind=%p)\n", ind); #endif /* DEBUG */ @@ -539,8 +540,8 @@ index_compare(mxml_index_t *ind, /* I - Index */ static int /* O - Result of comparison */ index_find(mxml_index_t *ind, /* I - Index */ - const char *element, /* I - Element name or NULL */ - const char *value, /* I - Attribute value or NULL */ + const char *element, /* I - Element name or @code NULL@ */ + const char *value, /* I - Attribute value or @code NULL@ */ mxml_node_t *node) /* I - Node */ { int diff; /* Difference */ @@ -653,8 +654,3 @@ index_sort(mxml_index_t *ind, /* I - Index to sort */ } while (right > (left = tempr + 1)); } - - -/* - * End of "$Id: mxml-index.c 451 2014-01-04 21:50:06Z msweet $". - */ diff --git a/phlib/mxml/mxml-node.c b/phlib/mxml/mxml-node.c index 62d35aea3a47..3f32e47c4d12 100644 --- a/phlib/mxml/mxml-node.c +++ b/phlib/mxml/mxml-node.c @@ -1,9 +1,7 @@ /* - * "$Id: mxml-node.c 462 2016-06-11 20:51:49Z msweet $" + * Node support code for Mini-XML, a small XML file parsing library. * - * Node support code for Mini-XML, a small XML-like file parsing library. - * - * Copyright 2003-2016 by Michael R Sweet. + * Copyright 2003-2017 by Michael R Sweet. * * These coded instructions, statements, and computer programs are the * property of Michael R Sweet and are protected by Federal copyright @@ -11,7 +9,7 @@ * which should have been included with this file. If this file is * missing or damaged, see the license at: * - * http://www.msweet.org/projects.php/Mini-XML + * https://michaelrsweet.github.io/mxml */ /* @@ -34,21 +32,21 @@ static mxml_node_t *mxml_new(mxml_node_t *parent, mxml_type_t type); /* * 'mxmlAdd()' - Add a node to a tree. * - * Adds the specified node to the parent. If the child argument is not - * NULL, puts the new node before or after the specified child depending - * on the value of the where argument. If the child argument is NULL, - * puts the new node at the beginning of the child list (MXML_ADD_BEFORE) - * or at the end of the child list (MXML_ADD_AFTER). The constant - * MXML_ADD_TO_PARENT can be used to specify a NULL child pointer. + * Adds the specified node to the parent. If the child argument is not + * @code NULL@, puts the new node before or after the specified child depending + * on the value of the where argument. If the child argument is @code NULL@, + * puts the new node at the beginning of the child list (@code MXML_ADD_BEFORE@) + * or at the end of the child list (@code MXML_ADD_AFTER@). The constant + * @code MXML_ADD_TO_PARENT@ can be used to specify a @code NULL@ child pointer. */ void mxmlAdd(mxml_node_t *parent, /* I - Parent node */ - int where, /* I - Where to add, MXML_ADD_BEFORE or MXML_ADD_AFTER */ - mxml_node_t *child, /* I - Child node for where or MXML_ADD_TO_PARENT */ + int where, /* I - Where to add, @code MXML_ADD_BEFORE@ or @code MXML_ADD_AFTER@ */ + mxml_node_t *child, /* I - Child node for where or @code MXML_ADD_TO_PARENT@ */ mxml_node_t *node) /* I - Node to add */ { -#if DEBUG > 1 +#ifdef DEBUG fprintf(stderr, "mxmlAdd(parent=%p, where=%d, child=%p, node=%p)\n", parent, where, child, node); #endif /* DEBUG */ @@ -173,7 +171,7 @@ mxmlAdd(mxml_node_t *parent, /* I - Parent node */ * 'mxmlDelete()' - Delete a node and all of its children. * * If the specified node has a parent, this function first removes the - * node from its parent using the mxmlRemove() function. + * node from its parent using the @link mxmlRemove@ function. */ void @@ -183,7 +181,7 @@ mxmlDelete(mxml_node_t *node) /* I - Node to delete */ *next; /* Next node */ -#if DEBUG > 1 +#ifdef DEBUG fprintf(stderr, "mxmlDelete(node=%p)\n", node); #endif /* DEBUG */ @@ -222,29 +220,23 @@ mxmlDelete(mxml_node_t *node) /* I - Node to delete */ if ((next = current->next) == NULL) { - mxml_node_t *temp = current->parent; - /* Pointer to parent node */ - - if (temp == node) - { - /* - * Got back to the top node... - */ + /* + * Next node is the parent, which we'll free as needed... + */ + if ((next = current->parent) == node) next = NULL; - } - else if ((next = temp->next) == NULL) - { - if ((next = temp->parent) == node) - next = NULL; - } } + /* + * Free child... + */ + mxml_free(current); } /* - * Then free the memory used by this node... + * Then free the memory used by the parent node... */ mxml_free(node); @@ -283,21 +275,22 @@ mxmlGetRefCount(mxml_node_t *node) /* I - Node */ * 'mxmlNewCDATA()' - Create a new CDATA node. * * The new CDATA node is added to the end of the specified parent's child - * list. The constant MXML_NO_PARENT can be used to specify that the new - * CDATA node has no parent. The data string must be nul-terminated and - * is copied into the new node. CDATA nodes use the MXML_ELEMENT type. + * list. The constant @code MXML_NO_PARENT@ can be used to specify that the new + * CDATA node has no parent. The data string must be nul-terminated and + * is copied into the new node. CDATA nodes currently use the + * @code MXML_ELEMENT@ type. * * @since Mini-XML 2.3@ */ mxml_node_t * /* O - New node */ -mxmlNewCDATA(mxml_node_t *parent, /* I - Parent node or MXML_NO_PARENT */ +mxmlNewCDATA(mxml_node_t *parent, /* I - Parent node or @code MXML_NO_PARENT@ */ const char *data) /* I - Data string */ { mxml_node_t *node; /* New node */ -#if DEBUG > 1 +#ifdef DEBUG fprintf(stderr, "mxmlNewCDATA(parent=%p, data=\"%s\")\n", parent, data ? data : "(null)"); #endif /* DEBUG */ @@ -324,8 +317,8 @@ mxmlNewCDATA(mxml_node_t *parent, /* I - Parent node or MXML_NO_PARENT */ * 'mxmlNewCustom()' - Create a new custom data node. * * The new custom node is added to the end of the specified parent's child - * list. The constant MXML_NO_PARENT can be used to specify that the new - * element node has no parent. NULL can be passed when the data in the + * list. The constant @code MXML_NO_PARENT@ can be used to specify that the new + * element node has no parent. @code NULL@ can be passed when the data in the * node is not dynamically allocated or is separately managed. * * @since Mini-XML 2.1@ @@ -333,14 +326,14 @@ mxmlNewCDATA(mxml_node_t *parent, /* I - Parent node or MXML_NO_PARENT */ mxml_node_t * /* O - New node */ mxmlNewCustom( - mxml_node_t *parent, /* I - Parent node or MXML_NO_PARENT */ + mxml_node_t *parent, /* I - Parent node or @code MXML_NO_PARENT@ */ void *data, /* I - Pointer to data */ mxml_custom_destroy_cb_t destroy) /* I - Function to destroy data */ { mxml_node_t *node; /* New node */ -#if DEBUG > 1 +#ifdef DEBUG fprintf(stderr, "mxmlNewCustom(parent=%p, data=%p, destroy=%p)\n", parent, data, destroy); #endif /* DEBUG */ @@ -363,18 +356,18 @@ mxmlNewCustom( * 'mxmlNewElement()' - Create a new element node. * * The new element node is added to the end of the specified parent's child - * list. The constant MXML_NO_PARENT can be used to specify that the new + * list. The constant @code MXML_NO_PARENT@ can be used to specify that the new * element node has no parent. */ mxml_node_t * /* O - New node */ -mxmlNewElement(mxml_node_t *parent, /* I - Parent node or MXML_NO_PARENT */ +mxmlNewElement(mxml_node_t *parent, /* I - Parent node or @code MXML_NO_PARENT@ */ const char *name) /* I - Name of element */ { mxml_node_t *node; /* New node */ -#if DEBUG > 1 +#ifdef DEBUG fprintf(stderr, "mxmlNewElement(parent=%p, name=\"%s\")\n", parent, name ? name : "(null)"); #endif /* DEBUG */ @@ -401,18 +394,18 @@ mxmlNewElement(mxml_node_t *parent, /* I - Parent node or MXML_NO_PARENT */ * 'mxmlNewInteger()' - Create a new integer node. * * The new integer node is added to the end of the specified parent's child - * list. The constant MXML_NO_PARENT can be used to specify that the new + * list. The constant @code MXML_NO_PARENT@ can be used to specify that the new * integer node has no parent. */ mxml_node_t * /* O - New node */ -mxmlNewInteger(mxml_node_t *parent, /* I - Parent node or MXML_NO_PARENT */ +mxmlNewInteger(mxml_node_t *parent, /* I - Parent node or @code MXML_NO_PARENT@ */ int integer) /* I - Integer value */ { mxml_node_t *node; /* New node */ -#if DEBUG > 1 +#ifdef DEBUG fprintf(stderr, "mxmlNewInteger(parent=%p, integer=%d)\n", parent, integer); #endif /* DEBUG */ @@ -430,20 +423,20 @@ mxmlNewInteger(mxml_node_t *parent, /* I - Parent node or MXML_NO_PARENT */ /* * 'mxmlNewOpaque()' - Create a new opaque string. * - * The new opaque node is added to the end of the specified parent's child - * list. The constant MXML_NO_PARENT can be used to specify that the new - * opaque node has no parent. The opaque string must be nul-terminated and - * is copied into the new node. + * The new opaque string node is added to the end of the specified parent's + * child list. The constant @code MXML_NO_PARENT@ can be used to specify that + * the new opaque string node has no parent. The opaque string must be nul- + * terminated and is copied into the new node. */ mxml_node_t * /* O - New node */ -mxmlNewOpaque(mxml_node_t *parent, /* I - Parent node or MXML_NO_PARENT */ +mxmlNewOpaque(mxml_node_t *parent, /* I - Parent node or @code MXML_NO_PARENT@ */ const char *opaque) /* I - Opaque string */ { mxml_node_t *node; /* New node */ -#if DEBUG > 1 +#ifdef DEBUG fprintf(stderr, "mxmlNewOpaque(parent=%p, opaque=\"%s\")\n", parent, opaque ? opaque : "(null)"); #endif /* DEBUG */ @@ -466,22 +459,68 @@ mxmlNewOpaque(mxml_node_t *parent, /* I - Parent node or MXML_NO_PARENT */ } +/* + * 'mxmlNewOpaquef()' - Create a new formatted opaque string node. + * + * The new opaque string node is added to the end of the specified parent's + * child list. The constant @code MXML_NO_PARENT@ can be used to specify that + * the new opaque string node has no parent. The format string must be + * nul-terminated and is formatted into the new node. + */ + +mxml_node_t * /* O - New node */ +mxmlNewOpaquef(mxml_node_t *parent, /* I - Parent node or @code MXML_NO_PARENT@ */ + const char *format, /* I - Printf-style format string */ + ...) /* I - Additional args as needed */ +{ + mxml_node_t *node; /* New node */ + va_list ap; /* Pointer to arguments */ + + +#ifdef DEBUG + fprintf(stderr, "mxmlNewOpaquef(parent=%p, format=\"%s\", ...)\n", parent, format ? format : "(null)"); +#endif /* DEBUG */ + + /* + * Range check input... + */ + + if (!format) + return (NULL); + + /* + * Create the node and set the text value... + */ + + if ((node = mxml_new(parent, MXML_OPAQUE)) != NULL) + { + va_start(ap, format); + + node->value.opaque = _mxml_vstrdupf(format, ap); + + va_end(ap); + } + + return (node); +} + + /* * 'mxmlNewReal()' - Create a new real number node. * * The new real number node is added to the end of the specified parent's - * child list. The constant MXML_NO_PARENT can be used to specify that + * child list. The constant @code MXML_NO_PARENT@ can be used to specify that * the new real number node has no parent. */ mxml_node_t * /* O - New node */ -mxmlNewReal(mxml_node_t *parent, /* I - Parent node or MXML_NO_PARENT */ +mxmlNewReal(mxml_node_t *parent, /* I - Parent node or @code MXML_NO_PARENT@ */ double real) /* I - Real number value */ { mxml_node_t *node; /* New node */ -#if DEBUG > 1 +#ifdef DEBUG fprintf(stderr, "mxmlNewReal(parent=%p, real=%g)\n", parent, real); #endif /* DEBUG */ @@ -500,21 +539,21 @@ mxmlNewReal(mxml_node_t *parent, /* I - Parent node or MXML_NO_PARENT */ * 'mxmlNewText()' - Create a new text fragment node. * * The new text node is added to the end of the specified parent's child - * list. The constant MXML_NO_PARENT can be used to specify that the new - * text node has no parent. The whitespace parameter is used to specify - * whether leading whitespace is present before the node. The text + * list. The constant @code MXML_NO_PARENT@ can be used to specify that the new + * text node has no parent. The whitespace parameter is used to specify + * whether leading whitespace is present before the node. The text * string must be nul-terminated and is copied into the new node. */ mxml_node_t * /* O - New node */ -mxmlNewText(mxml_node_t *parent, /* I - Parent node or MXML_NO_PARENT */ +mxmlNewText(mxml_node_t *parent, /* I - Parent node or @code MXML_NO_PARENT@ */ int whitespace, /* I - 1 = leading whitespace, 0 = no whitespace */ const char *string) /* I - String */ { mxml_node_t *node; /* New node */ -#if DEBUG > 1 +#ifdef DEBUG fprintf(stderr, "mxmlNewText(parent=%p, whitespace=%d, string=\"%s\")\n", parent, whitespace, string ? string : "(null)"); #endif /* DEBUG */ @@ -544,23 +583,23 @@ mxmlNewText(mxml_node_t *parent, /* I - Parent node or MXML_NO_PARENT */ * 'mxmlNewTextf()' - Create a new formatted text fragment node. * * The new text node is added to the end of the specified parent's child - * list. The constant MXML_NO_PARENT can be used to specify that the new - * text node has no parent. The whitespace parameter is used to specify - * whether leading whitespace is present before the node. The format + * list. The constant @code MXML_NO_PARENT@ can be used to specify that the new + * text node has no parent. The whitespace parameter is used to specify + * whether leading whitespace is present before the node. The format * string must be nul-terminated and is formatted into the new node. */ mxml_node_t * /* O - New node */ -mxmlNewTextf(mxml_node_t *parent, /* I - Parent node or MXML_NO_PARENT */ +mxmlNewTextf(mxml_node_t *parent, /* I - Parent node or @code MXML_NO_PARENT@ */ int whitespace, /* I - 1 = leading whitespace, 0 = no whitespace */ - const char *format, /* I - Printf-style frmat string */ + const char *format, /* I - Printf-style format string */ ...) /* I - Additional args as needed */ { mxml_node_t *node; /* New node */ va_list ap; /* Pointer to arguments */ -#if DEBUG > 1 +#ifdef DEBUG fprintf(stderr, "mxmlNewTextf(parent=%p, whitespace=%d, format=\"%s\", ...)\n", parent, whitespace, format ? format : "(null)"); #endif /* DEBUG */ @@ -593,14 +632,14 @@ mxmlNewTextf(mxml_node_t *parent, /* I - Parent node or MXML_NO_PARENT */ /* * 'mxmlRemove()' - Remove a node from its parent. * - * Does not free memory used by the node - use mxmlDelete() for that. - * This function does nothing if the node has no parent. + * This function does not free memory used by the node - use @link mxmlDelete@ + * for that. This function does nothing if the node has no parent. */ void mxmlRemove(mxml_node_t *node) /* I - Node to remove */ { -#if DEBUG > 1 +#ifdef DEBUG fprintf(stderr, "mxmlRemove(node=%p)\n", node); #endif /* DEBUG */ @@ -661,7 +700,7 @@ mxmlRemove(mxml_node_t *node) /* I - Node to remove */ * 'mxmlNewXML()' - Create a new XML document tree. * * The "version" argument specifies the version number to put in the - * ?xml element node. If NULL, version 1.0 is assumed. + * ?xml element node. If @code NULL@, version "1.0" is assumed. * * @since Mini-XML 2.3@ */ @@ -683,7 +722,7 @@ mxmlNewXML(const char *version) /* I - Version number to use */ * 'mxmlRelease()' - Release a node. * * When the reference count reaches zero, the node (and any children) - * is deleted via mxmlDelete(). + * is deleted via @link mxmlDelete@. * * @since Mini-XML 2.3@ */ @@ -738,19 +777,19 @@ mxml_free(mxml_node_t *node) /* I - Node */ { case MXML_ELEMENT : if (node->value.element.name) - PhFree(node->value.element.name); + PhFree(node->value.element.name); if (node->value.element.num_attrs) { for (i = 0; i < node->value.element.num_attrs; i ++) { if (node->value.element.attrs[i].name) - PhFree(node->value.element.attrs[i].name); + PhFree(node->value.element.attrs[i].name); if (node->value.element.attrs[i].value) - PhFree(node->value.element.attrs[i].value); + PhFree(node->value.element.attrs[i].value); } - PhFree(node->value.element.attrs); + PhFree(node->value.element.attrs); } break; case MXML_INTEGER : @@ -758,14 +797,14 @@ mxml_free(mxml_node_t *node) /* I - Node */ break; case MXML_OPAQUE : if (node->value.opaque) - PhFree(node->value.opaque); + PhFree(node->value.opaque); break; case MXML_REAL : /* Nothing to do */ break; case MXML_TEXT : if (node->value.text.string) - PhFree(node->value.text.string); + PhFree(node->value.text.string); break; case MXML_CUSTOM : if (node->value.custom.data && @@ -836,8 +875,3 @@ mxml_new(mxml_node_t *parent, /* I - Parent node */ return (node); } - - -/* - * End of "$Id: mxml-node.c 462 2016-06-11 20:51:49Z msweet $". - */ diff --git a/phlib/mxml/mxml-private.c b/phlib/mxml/mxml-private.c index 6f6e480c2d61..0a0d787d02c5 100644 --- a/phlib/mxml/mxml-private.c +++ b/phlib/mxml/mxml-private.c @@ -1,9 +1,7 @@ /* - * "$Id: mxml-private.c 451 2014-01-04 21:50:06Z msweet $" + * Private functions for Mini-XML, a small XML file parsing library. * - * Private functions for Mini-XML, a small XML-like file parsing library. - * - * Copyright 2003-2014 by Michael R Sweet. + * Copyright 2003-2017 by Michael R Sweet. * * These coded instructions, statements, and computer programs are the * property of Michael R Sweet and are protected by Federal copyright @@ -11,7 +9,7 @@ * which should have been included with this file. If this file is * missing or damaged, see the license at: * - * http://www.msweet.org/projects.php/Mini-XML + * https://michaelrsweet.github.io/mxml */ /* @@ -316,8 +314,3 @@ _mxml_global(void) return (&global); } #endif /* HAVE_PTHREAD_H */ - - -/* - * End of "$Id: mxml-private.c 451 2014-01-04 21:50:06Z msweet $". - */ diff --git a/phlib/mxml/mxml-private.h b/phlib/mxml/mxml-private.h index c5e4e6b6f27a..a78dcde16971 100644 --- a/phlib/mxml/mxml-private.h +++ b/phlib/mxml/mxml-private.h @@ -1,9 +1,7 @@ /* - * "$Id: mxml-private.h 451 2014-01-04 21:50:06Z msweet $" + * Private definitions for Mini-XML, a small XML file parsing library. * - * Private definitions for Mini-XML, a small XML-like file parsing library. - * - * Copyright 2003-2014 by Michael R Sweet. + * Copyright 2003-2017 by Michael R Sweet. * * These coded instructions, statements, and computer programs are the * property of Michael R Sweet and are protected by Federal copyright @@ -11,7 +9,7 @@ * which should have been included with this file. If this file is * missing or damaged, see the license at: * - * http://www.msweet.org/projects.php/Mini-XML + * https://michaelrsweet.github.io/mxml */ /* @@ -43,8 +41,3 @@ typedef struct _mxml_global_s extern _mxml_global_t *_mxml_global(void); extern int _mxml_entity_cb(const char *name); - - -/* - * End of "$Id: mxml-private.h 451 2014-01-04 21:50:06Z msweet $". - */ diff --git a/phlib/mxml/mxml-search.c b/phlib/mxml/mxml-search.c index ec7ef3f357c4..9c6c7745ce16 100644 --- a/phlib/mxml/mxml-search.c +++ b/phlib/mxml/mxml-search.c @@ -1,10 +1,7 @@ /* - * "$Id: mxml-search.c 451 2014-01-04 21:50:06Z msweet $" + * Search/navigation functions for Mini-XML, a small XML file parsing library. * - * Search/navigation functions for Mini-XML, a small XML-like file - * parsing library. - * - * Copyright 2003-2014 by Michael R Sweet. + * Copyright 2003-2017 by Michael R Sweet. * * These coded instructions, statements, and computer programs are the * property of Michael R Sweet and are protected by Federal copyright @@ -12,7 +9,7 @@ * which should have been included with this file. If this file is * missing or damaged, see the license at: * - * http://www.msweet.org/projects.php/Mini-XML + * https://michaelrsweet.github.io/mxml */ /* @@ -27,22 +24,22 @@ * 'mxmlFindElement()' - Find the named element. * * The search is constrained by the name, attribute name, and value; any - * NULL names or values are treated as wildcards, so different kinds of + * @code NULL@ names or values are treated as wildcards, so different kinds of * searches can be implemented by looking for all elements of a given name * or all elements with a specific attribute. The descend argument determines * whether the search descends into child nodes; normally you will use - * MXML_DESCEND_FIRST for the initial search and MXML_NO_DESCEND to find - * additional direct descendents of the node. The top node argument + * @code MXML_DESCEND_FIRST@ for the initial search and @code MXML_NO_DESCEND@ + * to find additional direct descendents of the node. The top node argument * constrains the search to a particular node's children. */ -mxml_node_t * /* O - Element node or NULL */ +mxml_node_t * /* O - Element node or @code NULL@ */ mxmlFindElement(mxml_node_t *node, /* I - Current node */ mxml_node_t *top, /* I - Top node */ - const char *name, /* I - Element name or NULL for any */ - const char *attr, /* I - Attribute name, or NULL for none */ - const char *value, /* I - Attribute value, or NULL for any */ - int descend) /* I - Descend into tree - MXML_DESCEND, MXML_NO_DESCEND, or MXML_DESCEND_FIRST */ + const char *element, /* I - Element name or @code NULL@ for any */ + const char *attr, /* I - Attribute name, or @code NULL@ for none */ + const char *value, /* I - Attribute value, or @code NULL@ for any */ + int descend) /* I - Descend into tree - @code MXML_DESCEND@, @code MXML_NO_DESCEND@, or @code MXML_DESCEND_FIRST@ */ { const char *temp; /* Current attribute value */ @@ -72,7 +69,7 @@ mxmlFindElement(mxml_node_t *node, /* I - Current node */ if (node->type == MXML_ELEMENT && node->value.element.name && - (!name || !strcmp(node->value.element.name, name))) + (!element || !strcmp(node->value.element.name, element))) { /* * See if we need to check for an attribute... @@ -123,7 +120,7 @@ mxmlFindElement(mxml_node_t *node, /* I - Current node */ * @since Mini-XML 2.7@ */ -mxml_node_t * /* O - Found node or NULL */ +mxml_node_t * /* O - Found node or @code NULL@ */ mxmlFindPath(mxml_node_t *top, /* I - Top node */ const char *path) /* I - Path to element */ { @@ -201,14 +198,14 @@ mxmlFindPath(mxml_node_t *top, /* I - Top node */ * 'mxmlWalkNext()' - Walk to the next logical node in the tree. * * The descend argument controls whether the first child is considered - * to be the next node. The top node argument constrains the walk to + * to be the next node. The top node argument constrains the walk to * the node's children. */ -mxml_node_t * /* O - Next node or NULL */ +mxml_node_t * /* O - Next node or @code NULL@ */ mxmlWalkNext(mxml_node_t *node, /* I - Current node */ mxml_node_t *top, /* I - Top node */ - int descend) /* I - Descend into tree - MXML_DESCEND, MXML_NO_DESCEND, or MXML_DESCEND_FIRST */ + int descend) /* I - Descend into tree - @code MXML_DESCEND@, @code MXML_NO_DESCEND@, or @code MXML_DESCEND_FIRST@ */ { if (!node) return (NULL); @@ -239,14 +236,14 @@ mxmlWalkNext(mxml_node_t *node, /* I - Current node */ * 'mxmlWalkPrev()' - Walk to the previous logical node in the tree. * * The descend argument controls whether the previous node's last child - * is considered to be the previous node. The top node argument constrains + * is considered to be the previous node. The top node argument constrains * the walk to the node's children. */ -mxml_node_t * /* O - Previous node or NULL */ +mxml_node_t * /* O - Previous node or @code NULL@ */ mxmlWalkPrev(mxml_node_t *node, /* I - Current node */ mxml_node_t *top, /* I - Top node */ - int descend) /* I - Descend into tree - MXML_DESCEND, MXML_NO_DESCEND, or MXML_DESCEND_FIRST */ + int descend) /* I - Descend into tree - @code MXML_DESCEND@, @code MXML_NO_DESCEND@, or @code MXML_DESCEND_FIRST@ */ { if (!node || node == top) return (NULL); @@ -273,8 +270,3 @@ mxmlWalkPrev(mxml_node_t *node, /* I - Current node */ else return (NULL); } - - -/* - * End of "$Id: mxml-search.c 451 2014-01-04 21:50:06Z msweet $". - */ diff --git a/phlib/mxml/mxml-set.c b/phlib/mxml/mxml-set.c index be7593f4e661..ffc5228b0d67 100644 --- a/phlib/mxml/mxml-set.c +++ b/phlib/mxml/mxml-set.c @@ -1,9 +1,7 @@ /* - * "$Id: mxml-set.c 451 2014-01-04 21:50:06Z msweet $" + * Node set functions for Mini-XML, a small XML file parsing library. * - * Node set functions for Mini-XML, a small XML-like file parsing library. - * - * Copyright 2003-2014 by Michael R Sweet. + * Copyright 2003-2017 by Michael R Sweet. * * These coded instructions, statements, and computer programs are the * property of Michael R Sweet and are protected by Federal copyright @@ -11,7 +9,7 @@ * which should have been included with this file. If this file is * missing or damaged, see the license at: * - * http://www.msweet.org/projects.php/Mini-XML + * https://michaelrsweet.github.io/mxml */ /* @@ -54,7 +52,7 @@ mxmlSetCDATA(mxml_node_t *node, /* I - Node to set */ */ if (node->value.element.name) - PhFree(node->value.element.name); + PhFree(node->value.element.name); node->value.element.name = _mxml_strdupf("![CDATA[%s]]", data); @@ -123,7 +121,7 @@ mxmlSetElement(mxml_node_t *node, /* I - Node to set */ */ if (node->value.element.name) - PhFree(node->value.element.name); + PhFree(node->value.element.name); node->value.element.name = PhDuplicateBytesZSafe((char *)name); @@ -188,7 +186,7 @@ mxmlSetOpaque(mxml_node_t *node, /* I - Node to set */ */ if (node->value.opaque) - PhFree(node->value.opaque); + PhFree(node->value.opaque); node->value.opaque = PhDuplicateBytesZSafe((char *)opaque); @@ -196,6 +194,50 @@ mxmlSetOpaque(mxml_node_t *node, /* I - Node to set */ } +/* + * 'mxmlSetOpaquef()' - Set the value of an opaque string node to a formatted string. + * + * The node is not changed if it (or its first child) is not an opaque node. + * + * @since Mini-XML 2.11@ + */ + +int /* O - 0 on success, -1 on failure */ +mxmlSetOpaquef(mxml_node_t *node, /* I - Node to set */ + const char *format, /* I - Printf-style format string */ + ...) /* I - Additional arguments as needed */ +{ + va_list ap; /* Pointer to arguments */ + + + /* + * Range check input... + */ + + if (node && node->type == MXML_ELEMENT && + node->child && node->child->type == MXML_OPAQUE) + node = node->child; + + if (!node || node->type != MXML_OPAQUE || !format) + return (-1); + + /* + * Free any old string value and set the new value... + */ + + if (node->value.opaque) + PhFree(node->value.opaque); + + va_start(ap, format); + + node->value.opaque = _mxml_strdupf(format, ap); + + va_end(ap); + + return (0); +} + + /* * 'mxmlSetReal()' - Set the value of a real number node. * @@ -254,7 +296,7 @@ mxmlSetText(mxml_node_t *node, /* I - Node to set */ */ if (node->value.text.string) - PhFree(node->value.text.string); + PhFree(node->value.text.string); node->value.text.whitespace = whitespace; node->value.text.string = PhDuplicateBytesZSafe((char *)string); @@ -294,7 +336,7 @@ mxmlSetTextf(mxml_node_t *node, /* I - Node to set */ */ if (node->value.text.string) - PhFree(node->value.text.string); + PhFree(node->value.text.string); va_start(ap, format); @@ -331,8 +373,3 @@ mxmlSetUserData(mxml_node_t *node, /* I - Node to set */ node->user_data = data; return (0); } - - -/* - * End of "$Id: mxml-set.c 451 2014-01-04 21:50:06Z msweet $". - */ diff --git a/phlib/mxml/mxml-string.c b/phlib/mxml/mxml-string.c index ee4efc200436..0341a2d8a6dd 100644 --- a/phlib/mxml/mxml-string.c +++ b/phlib/mxml/mxml-string.c @@ -1,9 +1,7 @@ /* - * "$Id: mxml-string.c 454 2014-01-05 03:25:07Z msweet $" + * String functions for Mini-XML, a small XML file parsing library. * - * String functions for Mini-XML, a small XML-like file parsing library. - * - * Copyright 2003-2014 by Michael R Sweet. + * Copyright 2003-2017 by Michael R Sweet. * * These coded instructions, statements, and computer programs are the * property of Michael R Sweet and are protected by Federal copyright @@ -11,7 +9,7 @@ * which should have been included with this file. If this file is * missing or damaged, see the license at: * - * http://www.msweet.org/projects.php/Mini-XML + * https://michaelrsweet.github.io/mxml */ /* @@ -100,13 +98,100 @@ _mxml_strdupf(const char *format, /* I - Printf-style format string */ */ va_start(ap, format); +#ifdef HAVE_VASPRINTF + if (vasprintf(&s, format, ap) < 0) + s = NULL; +#else s = _mxml_vstrdupf(format, ap); +#endif /* HAVE_VASPRINTF */ va_end(ap); return (s); } +#ifndef HAVE_STRLCAT +/* + * '_mxml_strlcat()' - Safely concatenate a string. + */ + +size_t /* O - Number of bytes copied */ +_mxml_strlcat(char *dst, /* I - Destination buffer */ + const char *src, /* I - Source string */ + size_t dstsize) /* I - Size of destinatipon buffer */ +{ + size_t srclen; /* Length of source string */ + size_t dstlen; /* Length of destination string */ + + + /* + * Figure out how much room is left... + */ + + dstlen = strlen(dst); + + if (dstsize <= (dstlen + 1)) + return (dstlen); /* No room, return immediately... */ + + dstsize -= dstlen + 1; + + /* + * Figure out how much room is needed... + */ + + srclen = strlen(src); + + /* + * Copy the appropriate amount... + */ + + if (srclen > dstsize) + srclen = dstsize; + + memmove(dst + dstlen, src, srclen); + dst[dstlen + srclen] = '\0'; + + return (dstlen + srclen); +} +#endif /* !HAVE_STRLCAT */ + + +#ifndef HAVE_STRLCPY +/* + * '_mxml_strlcpy()' - Safely copy a string. + */ + +size_t /* O - Number of bytes copied */ +_mxml_strlcpy(char *dst, /* I - Destination buffer */ + const char *src, /* I - Source string */ + size_t dstsize) /* I - Size of destinatipon buffer */ +{ + size_t srclen; /* Length of source string */ + + + /* + * Figure out how much room is needed... + */ + + dstsize --; + + srclen = strlen(src); + + /* + * Copy the appropriate amount... + */ + + if (srclen > dstsize) + srclen = dstsize; + + memmove(dst, src, srclen); + dst[srclen] = '\0'; + + return (srclen); +} +#endif /* !HAVE_STRLCPY */ + + #ifndef HAVE_VSNPRINTF /* * '_mxml_vsnprintf()' - Format a string into a fixed size buffer. @@ -426,10 +511,18 @@ char * /* O - New string pointer */ _mxml_vstrdupf(const char *format, /* I - Printf-style format string */ va_list ap) /* I - Pointer to additional arguments */ { +#ifdef HAVE_VASPRINTF + char *s; /* String */ + + if (vasprintf(&s, format, ap) < 0) + s = NULL; + + return (s); + +#else int bytes; /* Number of bytes required */ char *buffer, /* String buffer */ temp[256]; /* Small buffer for first vsnprintf */ - va_list apcopy; /* Copy of argument list */ /* @@ -437,8 +530,15 @@ _mxml_vstrdupf(const char *format, /* I - Printf-style format string */ * needed... */ +# ifdef WIN32 + bytes = _vscprintf(format, ap); + +# else + va_list apcopy; /* Copy of argument list */ + va_copy(apcopy, ap); bytes = vsnprintf(temp, sizeof(temp), format, apcopy); +# endif /* WIN32 */ if (bytes < sizeof(temp)) { @@ -462,9 +562,5 @@ _mxml_vstrdupf(const char *format, /* I - Printf-style format string */ */ return (buffer); +#endif /* HAVE_VASPRINTF */ } - - -/* - * End of "$Id: mxml-string.c 454 2014-01-05 03:25:07Z msweet $". - */ diff --git a/phlib/mxml/mxml.h b/phlib/mxml/mxml.h index 91c382291be7..e1922c75cd65 100644 --- a/phlib/mxml/mxml.h +++ b/phlib/mxml/mxml.h @@ -1,9 +1,7 @@ /* - * "$Id: mxml.h 464 2016-06-12 21:16:14Z msweet $" + * Header file for Mini-XML, a small XML file parsing library. * - * Header file for Mini-XML, a small XML-like file parsing library. - * - * Copyright 2003-2016 by Michael R Sweet. + * Copyright 2003-2017 by Michael R Sweet. * * These coded instructions, statements, and computer programs are the * property of Michael R Sweet and are protected by Federal copyright @@ -11,7 +9,7 @@ * which should have been included with this file. If this file is * missing or damaged, see the license at: * - * http://www.msweet.org/projects.php/Mini-XML + * https://michaelrsweet.github.io/mxml */ /* @@ -43,7 +41,7 @@ */ # define MXML_MAJOR_VERSION 2 /* Major version number */ -# define MXML_MINOR_VERSION 10 /* Minor version number */ +# define MXML_MINOR_VERSION 11 /* Minor version number */ # define MXML_TAB 8 /* Tabs every N columns */ @@ -204,6 +202,8 @@ PHMXMLAPI extern void mxmlDelete(mxml_node_t *node); PHMXMLAPI extern void mxmlElementDeleteAttr(mxml_node_t *node, const char *name); PHMXMLAPI extern const char *mxmlElementGetAttr(mxml_node_t *node, const char *name); +extern const char *mxmlElementGetAttrByIndex(mxml_node_t *node, int idx, const char **name); +extern int mxmlElementGetAttrCount(mxml_node_t *node); PHMXMLAPI extern void mxmlElementSetAttr(mxml_node_t *node, const char *name, const char *value); extern void mxmlElementSetAttrf(mxml_node_t *node, const char *name, @@ -217,7 +217,7 @@ extern const char *mxmlEntityGetName(int val); extern int mxmlEntityGetValue(const char *name); extern void mxmlEntityRemoveCallback(mxml_entity_cb_t cb); PHMXMLAPI extern mxml_node_t *mxmlFindElement(mxml_node_t *node, mxml_node_t *top, - const char *name, const char *attr, + const char *element, const char *attr, const char *value, int descend); extern mxml_node_t *mxmlFindPath(mxml_node_t *node, const char *path); extern const char *mxmlGetCDATA(mxml_node_t *node); @@ -256,11 +256,14 @@ PHMXMLAPI extern mxml_node_t *mxmlNewCustom(mxml_node_t *parent, void *data, PHMXMLAPI extern mxml_node_t *mxmlNewElement(mxml_node_t *parent, const char *name); PHMXMLAPI extern mxml_node_t *mxmlNewInteger(mxml_node_t *parent, int integer); PHMXMLAPI extern mxml_node_t *mxmlNewOpaque(mxml_node_t *parent, const char *opaque); +extern mxml_node_t *mxmlNewOpaquef(mxml_node_t *parent, const char *format, ...) +# ifdef __GNUC__ +__attribute__((__format__(__printf__, 2, 3))) +# endif /* __GNUC__ */ +; PHMXMLAPI extern mxml_node_t *mxmlNewReal(mxml_node_t *parent, double real); -PHMXMLAPI extern mxml_node_t *mxmlNewText(mxml_node_t *parent, int whitespace, - const char *string); -extern mxml_node_t *mxmlNewTextf(mxml_node_t *parent, int whitespace, - const char *format, ...) +PHMXMLAPI extern mxml_node_t *mxmlNewText(mxml_node_t *parent, int whitespace, const char *string); +extern mxml_node_t *mxmlNewTextf(mxml_node_t *parent, int whitespace, const char *format, ...) # ifdef __GNUC__ __attribute__ ((__format__ (__printf__, 3, 4))) # endif /* __GNUC__ */ @@ -295,6 +298,11 @@ PHMXMLAPI extern int mxmlSetElement(mxml_node_t *node, const char *name); PHMXMLAPI extern void mxmlSetErrorCallback(mxml_error_cb_t cb); extern int mxmlSetInteger(mxml_node_t *node, int integer); PHMXMLAPI extern int mxmlSetOpaque(mxml_node_t *node, const char *opaque); +extern int mxmlSetOpaquef(mxml_node_t *node, const char *format, ...) +# ifdef __GNUC__ +__attribute__((__format__(__printf__, 2, 3))) +# endif /* __GNUC__ */ +; extern int mxmlSetReal(mxml_node_t *node, double real); PHMXMLAPI extern int mxmlSetText(mxml_node_t *node, int whitespace, const char *string); @@ -331,8 +339,3 @@ PHMXMLAPI extern mxml_type_t mxml_real_cb(mxml_node_t *node); } # endif /* __cplusplus */ #endif /* !_mxml_h_ */ - - -/* - * End of "$Id: mxml.h 464 2016-06-12 21:16:14Z msweet $". - */ From 0578e3627741e81b0e249c0099c86b75c09ea889 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 25 May 2018 14:08:51 +1000 Subject: [PATCH 0985/2058] Update phlib includes --- phlib/phlib.vcxproj | 11 +++++++++++ phlib/phlib.vcxproj.filters | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/phlib/phlib.vcxproj b/phlib/phlib.vcxproj index 5ae8a6768d29..bc91f196de4c 100644 --- a/phlib/phlib.vcxproj +++ b/phlib/phlib.vcxproj @@ -168,12 +168,15 @@ + + + @@ -184,6 +187,7 @@ + @@ -265,12 +269,19 @@ + + + + + + + diff --git a/phlib/phlib.vcxproj.filters b/phlib/phlib.vcxproj.filters index 146a23ef377e..975dbd7fe210 100644 --- a/phlib/phlib.vcxproj.filters +++ b/phlib/phlib.vcxproj.filters @@ -224,6 +224,18 @@ Source Files + + Json-C + + + Json-C + + + Mini-XML + + + Json-C + @@ -475,5 +487,26 @@ Header Files + + Json-C\Headers + + + Json-C\Headers + + + Json-C\Headers + + + Json-C\Headers + + + Json-C\Headers + + + Json-C\Headers + + + Json-C\Headers + \ No newline at end of file From 16db20cbaf791cf6381d500ad7b386b06b0c8dcb Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 28 May 2018 16:40:52 +1000 Subject: [PATCH 0986/2058] NetworkTools: cache country column icons --- plugins/NetworkTools/country.c | 27 ++++++++++++++++++++++++--- plugins/NetworkTools/main.c | 28 +++++++++------------------- plugins/NetworkTools/nettools.h | 2 +- plugins/NetworkTools/tracetree.c | 23 +++++------------------ 4 files changed, 39 insertions(+), 41 deletions(-) diff --git a/plugins/NetworkTools/country.c b/plugins/NetworkTools/country.c index 9ab6f6ea8203..f8598e0fb50a 100644 --- a/plugins/NetworkTools/country.c +++ b/plugins/NetworkTools/country.c @@ -2,7 +2,7 @@ * Process Hacker Network Tools - * IP Country support * - * Copyright (C) 2016-2017 dmex + * Copyright (C) 2016-2018 dmex * * This file is part of Process Hacker. * @@ -21,6 +21,7 @@ */ #include "nettools.h" +#include #include "maxminddb\maxminddb.h" BOOLEAN GeoDbLoaded = FALSE; @@ -375,6 +376,7 @@ struct { PWSTR CountryCode; INT ResourceID; + HICON IconHandle; } CountryResourceTable[] = { @@ -450,7 +452,7 @@ CountryResourceTable[] = { L"ZA", ZA_PNG }, { L"ZM", ZM_PNG }, { L"ZW", ZW_PNG } }; -INT LookupResourceCode( +HICON LookupCountryIcon( _In_ PPH_STRING Name ) { @@ -458,7 +460,26 @@ INT LookupResourceCode( { if (PhEqualString2(Name, CountryResourceTable[i].CountryCode, TRUE)) { - return CountryResourceTable[i].ResourceID; + if (!CountryResourceTable[i].IconHandle) + { + HBITMAP countryBitmap; + + countryBitmap = PhLoadPngImageFromResource( + PluginInstance->DllBase, + 16, + 11, + MAKEINTRESOURCE(CountryResourceTable[i].ResourceID), + TRUE + ); + + if (countryBitmap) + { + CountryResourceTable[i].IconHandle = CommonBitmapToIcon(countryBitmap, 16, 11); + DeleteObject(countryBitmap); + } + } + + return CountryResourceTable[i].IconHandle; } } diff --git a/plugins/NetworkTools/main.c b/plugins/NetworkTools/main.c index a2e8bb24db43..591acadf8da4 100644 --- a/plugins/NetworkTools/main.c +++ b/plugins/NetworkTools/main.c @@ -3,7 +3,7 @@ * Main program * * Copyright (C) 2010-2011 wj32 - * Copyright (C) 2013-2017 dmex + * Copyright (C) 2013-2018 dmex * * This file is part of Process Hacker. * @@ -22,7 +22,6 @@ */ #include "nettools.h" -#include PPH_PLUGIN PluginInstance; PH_CALLBACK_REGISTRATION PluginLoadCallbackRegistration; @@ -467,8 +466,8 @@ VOID NTAPI NetworkItemDeleteCallback( if (extension->LatencyText) PhDereferenceObject(extension->LatencyText); - if (extension->CountryIcon) - DestroyIcon(extension->CountryIcon); + //if (extension->CountryIcon) + // DestroyIcon(extension->CountryIcon); } FORCEINLINE VOID PhpNetworkItemToRow( @@ -714,22 +713,10 @@ VOID NTAPI TreeNewMessageCallback( rect.left += 5; // Draw the column data - if (GeoDbLoaded && extension->RemoteCountryCode && extension->RemoteCountryName) + if (GeoDbLoaded && !GeoDbExpired && extension->RemoteCountryCode && extension->RemoteCountryName) { if (!extension->CountryIcon) - { - INT resourceCode; - HBITMAP countryBitmap; - - if ((resourceCode = LookupResourceCode(extension->RemoteCountryCode)) != 0) - { - if (countryBitmap = PhLoadPngImageFromResource(PluginInstance->DllBase, 16, 11, MAKEINTRESOURCE(resourceCode), TRUE)) - { - extension->CountryIcon = CommonBitmapToIcon(countryBitmap, 16, 11); - DeleteObject(countryBitmap); - } - } - } + extension->CountryIcon = LookupCountryIcon(extension->RemoteCountryCode); if (extension->CountryIcon) { @@ -757,7 +744,7 @@ VOID NTAPI TreeNewMessageCallback( ); } - if (GeoDbExpired && !extension->CountryIcon) + if (GeoDbExpired) { DrawText(hdc, L"Geoip database expired.", -1, &rect, DT_LEFT | DT_VCENTER | DT_END_ELLIPSIS | DT_SINGLELINE); } @@ -888,6 +875,9 @@ VOID ProcessesUpdatedCallback( { extension->NumberOfLostPackets = pathRod.FastRetran + pathRod.PktsRetrans; extension->SampleRtt = pathRod.SampleRtt; + + if (extension->SampleRtt == ULONG_MAX) // HACK + extension->SampleRtt = 0; } } } diff --git a/plugins/NetworkTools/nettools.h b/plugins/NetworkTools/nettools.h index eda0819c7553..d1bac10f2ec7 100644 --- a/plugins/NetworkTools/nettools.h +++ b/plugins/NetworkTools/nettools.h @@ -280,7 +280,7 @@ BOOLEAN LookupSockInAddr6CountryCode( _Out_ PPH_STRING *CountryName ); -INT LookupResourceCode( +HICON LookupCountryIcon( _In_ PPH_STRING Name ); diff --git a/plugins/NetworkTools/tracetree.c b/plugins/NetworkTools/tracetree.c index 919e7074f906..bd18a98fc385 100644 --- a/plugins/NetworkTools/tracetree.c +++ b/plugins/NetworkTools/tracetree.c @@ -52,8 +52,8 @@ VOID NTAPI TracertTreeNodeItemDeleteProcedure( PhDereferenceObject(tracertNode->PingString[i]); } - if (tracertNode->CountryIcon) - DestroyIcon(tracertNode->CountryIcon); + //if (tracertNode->CountryIcon) + // DestroyIcon(tracertNode->CountryIcon); } PTRACERT_ROOT_NODE TracertTreeCreateNode( @@ -467,23 +467,10 @@ BOOLEAN NTAPI TracertTreeNewCallback( rect.left += 5; // Draw the column data - if (GeoDbLoaded && node->RemoteCountryCode && node->RemoteCountryName) + if (GeoDbLoaded && !GeoDbExpired && node->RemoteCountryCode && node->RemoteCountryName) { if (!node->CountryIcon) - { - INT resourceCode; - - if ((resourceCode = LookupResourceCode(node->RemoteCountryCode)) != 0) - { - HBITMAP countryBitmap; - - if (countryBitmap = PhLoadPngImageFromResource(PluginInstance->DllBase, 16, 11, MAKEINTRESOURCE(resourceCode), TRUE)) - { - node->CountryIcon = CommonBitmapToIcon(countryBitmap, 16, 11); - DeleteObject(countryBitmap); - } - } - } + node->CountryIcon = LookupCountryIcon(node->RemoteCountryCode); if (node->CountryIcon) { @@ -511,7 +498,7 @@ BOOLEAN NTAPI TracertTreeNewCallback( ); } - if (GeoDbExpired && !node->CountryIcon) + if (GeoDbExpired) { DrawText(hdc, L"Geoip database expired.", -1, &rect, DT_LEFT | DT_VCENTER | DT_SINGLELINE); } From 0dff2a5cda5e34547c02700540e8731c6c7a421d Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 28 May 2018 16:41:26 +1000 Subject: [PATCH 0987/2058] Update RS4 types --- phnt/include/ntmmapi.h | 5 +++-- phnt/include/ntwow64.h | 8 +++++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/phnt/include/ntmmapi.h b/phnt/include/ntmmapi.h index aa2a9bf01392..93b23a555dd6 100644 --- a/phnt/include/ntmmapi.h +++ b/phnt/include/ntmmapi.h @@ -127,9 +127,10 @@ typedef struct _MEMORY_REGION_INFORMATION ULONG MappedPageFile : 1; ULONG MappedPhysical : 1; ULONG DirectMapped : 1; - ULONG SoftwareEnclave : 1; //REDSTONE3 + ULONG SoftwareEnclave : 1; // REDSTONE3 ULONG PageSize64K : 1; - ULONG Reserved : 24; + ULONG PlaceholderReservation : 1; // REDSTONE4 + ULONG Reserved : 23; }; }; SIZE_T RegionSize; diff --git a/phnt/include/ntwow64.h b/phnt/include/ntwow64.h index 4317ab0fbe9a..6f8bcdca32e2 100644 --- a/phnt/include/ntwow64.h +++ b/phnt/include/ntwow64.h @@ -363,6 +363,11 @@ typedef struct _PEB32 WOW64_POINTER(PVOID) TppWorkerpListLock; LIST_ENTRY32 TppWorkerpList; WOW64_POINTER(PVOID) WaitOnAddressHashTable[128]; + WOW64_POINTER(PVOID) TelemetryCoverageHeader; // REDSTONE3 + ULONG CloudFileFlags; + ULONG CloudFileDiagFlags; // REDSTONE4 + CHAR PlaceholderCompatibilityMode; + CHAR PlaceholderCompatibilityModeReserved[7]; } PEB32, *PPEB32; C_ASSERT(FIELD_OFFSET(PEB32, IFEOKey) == 0x024); @@ -370,7 +375,8 @@ C_ASSERT(FIELD_OFFSET(PEB32, UnicodeCaseTableData) == 0x060); C_ASSERT(FIELD_OFFSET(PEB32, SystemAssemblyStorageMap) == 0x204); C_ASSERT(FIELD_OFFSET(PEB32, pImageHeaderHash) == 0x23c); C_ASSERT(FIELD_OFFSET(PEB32, WaitOnAddressHashTable) == 0x25c); -C_ASSERT(sizeof(PEB32) == 0x460); +//C_ASSERT(sizeof(PEB32) == 0x460); // REDSTONE3 +C_ASSERT(sizeof(PEB32) == 0x470); #define GDI_BATCH_BUFFER_SIZE 310 From 5fa30342b158bd0080db48f902cbbd2d7e5deaca Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 28 May 2018 21:55:07 +1000 Subject: [PATCH 0988/2058] Update maxminddb to 1.3.2, Improve country icon caching --- plugins/NetworkTools/NetworkTools.vcxproj | 2 + .../NetworkTools/NetworkTools.vcxproj.filters | 6 + plugins/NetworkTools/country.c | 192 +++--- plugins/NetworkTools/main.c | 21 +- plugins/NetworkTools/maxminddb/data-pool.c | 180 ++++++ plugins/NetworkTools/maxminddb/data-pool.h | 52 ++ plugins/NetworkTools/maxminddb/maxminddb.c | 589 ++++++++++-------- plugins/NetworkTools/maxminddb/maxminddb.h | 17 +- plugins/NetworkTools/nettools.h | 10 +- plugins/NetworkTools/tracert.h | 2 +- plugins/NetworkTools/tracetree.c | 30 +- 11 files changed, 713 insertions(+), 388 deletions(-) create mode 100644 plugins/NetworkTools/maxminddb/data-pool.c create mode 100644 plugins/NetworkTools/maxminddb/data-pool.h diff --git a/plugins/NetworkTools/NetworkTools.vcxproj b/plugins/NetworkTools/NetworkTools.vcxproj index 2df98cd00960..1816eb38bb39 100644 --- a/plugins/NetworkTools/NetworkTools.vcxproj +++ b/plugins/NetworkTools/NetworkTools.vcxproj @@ -82,6 +82,7 @@ + @@ -115,6 +116,7 @@ + diff --git a/plugins/NetworkTools/NetworkTools.vcxproj.filters b/plugins/NetworkTools/NetworkTools.vcxproj.filters index eadc9f23f169..316ed1bfa90e 100644 --- a/plugins/NetworkTools/NetworkTools.vcxproj.filters +++ b/plugins/NetworkTools/NetworkTools.vcxproj.filters @@ -129,6 +129,9 @@ Source Files + + Source Files\maxmind + @@ -200,6 +203,9 @@ Header Files + + Header Files\maxminddb + diff --git a/plugins/NetworkTools/country.c b/plugins/NetworkTools/country.c index f8598e0fb50a..52cf51900e6b 100644 --- a/plugins/NetworkTools/country.c +++ b/plugins/NetworkTools/country.c @@ -26,6 +26,7 @@ BOOLEAN GeoDbLoaded = FALSE; BOOLEAN GeoDbExpired = FALSE; +HIMAGELIST GeoImageList = NULL; static MMDB_s GeoDb = { 0 }; VOID LoadGeoLiteDb( @@ -60,6 +61,11 @@ VOID LoadGeoLiteDb( GeoDbLoaded = TRUE; } + if (GeoDbLoaded) + { + GeoImageList = ImageList_Create(16, 11, ILC_COLOR32, 20, 20); + } + PhDereferenceObject(dbpath); } @@ -67,6 +73,12 @@ VOID FreeGeoLiteDb( VOID ) { + if (GeoImageList) + { + ImageList_RemoveAll(GeoImageList); + ImageList_Destroy(GeoImageList); + } + if (GeoDbLoaded) { MMDB_close(&GeoDb); @@ -376,91 +388,94 @@ struct { PWSTR CountryCode; INT ResourceID; - HICON IconHandle; + INT IconIndex; } CountryResourceTable[] = { - { L"AD", AD_PNG }, { L"AE", AE_PNG }, { L"AF", AF_PNG }, { L"AG", AG_PNG }, - { L"AI", AI_PNG }, { L"AL", AL_PNG }, { L"AM", AM_PNG }, { L"AN", AN_PNG }, - { L"AO", AO_PNG }, { L"AR", AR_PNG }, { L"AS", AS_PNG }, { L"AT", AT_PNG }, - { L"AU", AU_PNG }, { L"AW", AW_PNG }, { L"AX", AX_PNG }, { L"AZ", AZ_PNG }, - { L"BA", BA_PNG }, { L"BB", BB_PNG }, { L"BD", BD_PNG }, { L"BE", BE_PNG }, - { L"BF", BF_PNG }, { L"BG", BG_PNG }, { L"BH", BH_PNG }, { L"BI", BI__PNG }, - { L"BJ", BJ_PNG }, { L"BM", BM_PNG }, { L"BN", BN_PNG }, { L"BO", BO_PNG }, - { L"BR", BR_PNG }, { L"BS", BS_PNG }, { L"BT", BT_PNG }, { L"BV", BV_PNG }, - { L"BW", BW_PNG }, { L"BY", BY_PNG }, { L"BZ", BZ_PNG }, - { L"CA", CA_PNG }, { L"CC", CC_PNG }, { L"CD", CD_PNG }, { L"CF", CF_PNG }, - { L"CG", CG_PNG }, { L"CH", CH_PNG }, { L"CI", CI_PNG }, { L"CK", CK_PNG }, - { L"CL", CL_PNG }, { L"CM", CM_PNG }, { L"CN", CN_PNG }, { L"CO", CO_PNG }, - { L"CR", CR_PNG }, { L"CS", CS_PNG }, { L"CU", CU_PNG }, { L"CV", CV_PNG }, - { L"CX", CX_PNG }, { L"CY", CY_PNG }, { L"CZ", CZ_PNG }, { L"DE", DE_PNG }, - { L"DJ", DJ_PNG }, { L"DK", DK_PNG }, { L"DM", DM_PNG }, { L"DO", DO_PNG }, - { L"DZ", DZ_PNG }, - { L"EC", EC_PNG }, { L"EE", EE_PNG }, { L"EG", EG_PNG }, { L"EH", EH_PNG }, - { L"ER", ER_PNG }, { L"ES", ES_PNG }, { L"ET", ET_PNG }, - { L"FI", FI_PNG }, { L"FJ", FJ_PNG }, { L"FK", FK_PNG }, { L"FO", FO_PNG }, - { L"FR", FR_PNG }, - { L"GA", GA_PNG }, { L"GB", GB_PNG }, { L"GD", GD_PNG }, { L"GE", GE_PNG }, - { L"GF", GF_PNG }, { L"GH", GH_PNG }, { L"GI", GI_PNG }, { L"GL", GL_PNG }, - { L"GM", GM_PNG }, { L"GN", GN_PNG }, { L"GP", GP_PNG }, { L"GQ", GQ_PNG }, - { L"GR", GR_PNG }, { L"GS", GS_PNG }, { L"GT", GT_PNG }, { L"GU", GU_PNG }, - { L"GW", GW_PNG }, { L"GY", GY_PNG }, - { L"HK", HK_PNG }, { L"HM", HM_PNG }, { L"HN", HN_PNG }, { L"HR", HR_PNG }, - { L"HT", HT_PNG }, { L"HU", HU_PNG }, - { L"ID", ID_PNG }, { L"IE", IE_PNG }, { L"IL", IL_PNG }, { L"IN", IN_PNG }, - { L"IO", IO_PNG }, { L"IQ", IQ_PNG }, { L"IR", IR_PNG }, { L"IS", IS_PNG }, - { L"IT", IT_PNG }, - { L"JM", JM_PNG }, { L"JO", JO_PNG }, { L"JP", JP_PNG }, - { L"KE", KE_PNG }, { L"KG", KG_PNG }, { L"KH", KH_PNG }, { L"KI", KI_PNG }, - { L"KM", KM_PNG }, { L"KN", KN_PNG }, { L"KP", KP_PNG }, { L"KR", KR_PNG }, - { L"KW", KW_PNG }, { L"KY", KY_PNG }, { L"KZ", KZ_PNG }, - { L"LA", LA_PNG }, { L"LB", LB_PNG }, { L"LC", LC_PNG }, { L"LI", LI_PNG }, - { L"LK", LK_PNG }, { L"LR", LR_PNG }, { L"LS", LS_PNG }, { L"LT", LT_PNG }, - { L"LU", LU_PNG }, { L"LV", LV_PNG }, { L"LY", LY_PNG }, - { L"MA", MA_PNG }, { L"MC", MC_PNG }, { L"MD", MD_PNG }, { L"ME", ME_PNG }, - { L"MG", MG_PNG }, { L"MH", MH_PNG }, { L"MK", MK_PNG }, { L"ML", ML_PNG }, - { L"MM", MM_PNG }, { L"MN", MN_PNG }, { L"MO", MO_PNG }, { L"MP", MP_PNG }, - { L"MQ", MQ_PNG }, { L"MR", MR_PNG }, { L"MS", MS_PNG }, { L"MT", MT_PNG }, - { L"MU", MU_PNG }, { L"MV", MV_PNG }, { L"MW", MW_PNG }, { L"MX", MX_PNG }, - { L"MY", MY_PNG }, { L"MZ", MZ_PNG }, - { L"NA", NA_PNG }, { L"NC", NC_PNG }, { L"NE", NE_PNG }, { L"NF", NF_PNG }, - { L"NG", NG_PNG }, { L"NI", NI_PNG }, { L"NL", NL_PNG }, { L"NO", NO_PNG }, - { L"NP", NP_PNG }, { L"NR", NR_PNG }, { L"NU", NU_PNG }, { L"NZ", NZ_PNG }, - { L"OM", OM_PNG }, - { L"PA", PA_PNG }, { L"PE", PE_PNG }, { L"PF", PF_PNG }, { L"PG", PG_PNG }, - { L"PH", PH_PNG }, { L"PK", PK_PNG }, { L"PL", PL_PNG }, { L"PM", PM_PNG }, - { L"PN", PN_PNG }, { L"PR", PR_PNG }, { L"PS", PS_PNG }, { L"PT", PT_PNG }, - { L"PW", PW_PNG }, { L"PY", PY_PNG }, - { L"QA", QA_PNG }, - { L"RE", RE_PNG }, { L"RO", RO_PNG }, { L"RS", RS_PNG }, { L"RU", RU_PNG }, - { L"RW", RW_PNG }, - { L"SA", SA_PNG }, { L"SB", SB_PNG }, { L"SC", SC_PNG }, { L"SD", SD_PNG }, - { L"SE", SE_PNG }, { L"SG", SG_PNG }, { L"SH", SH_PNG }, { L"SI", SI_PNG }, - { L"SJ", SJ_PNG }, { L"SK", SK_PNG }, { L"SL", SL_PNG }, { L"SM", SM_PNG }, - { L"SN", SN_PNG }, { L"SO", SO_PNG }, { L"SR", SR_PNG }, { L"ST", ST_PNG }, - { L"SV", SV_PNG }, { L"SY", SY_PNG }, { L"SZ", SZ_PNG }, - { L"TC", TC_PNG }, { L"TD", TD_PNG }, { L"TF", TF_PNG }, { L"TG", TG_PNG }, - { L"TH", TH_PNG }, { L"TJ", TJ_PNG }, { L"TK", TK_PNG }, { L"TL", TL_PNG }, - { L"TM", TM_PNG }, { L"TN", TN_PNG }, { L"TO", TO_PNG }, { L"TR", TR_PNG }, - { L"TT", TT_PNG }, { L"TV", TV_PNG }, { L"TW", TW_PNG }, { L"TZ", TZ_PNG }, - { L"UA", UA_PNG }, { L"UG", UG_PNG }, { L"UM", UM_PNG }, { L"US", US_PNG }, - { L"UY", UY_PNG }, { L"UZ", UZ_PNG }, - { L"VA", VA_PNG }, { L"VC", VC_PNG }, { L"VE", VE_PNG }, { L"VG", VG_PNG }, - { L"VI", VI_PNG }, { L"VN", VN_PNG }, { L"VU", VU_PNG }, - { L"WF", WF_PNG }, { L"WS", WS_PNG }, - { L"YE", YE_PNG }, { L"YT", YT_PNG }, - { L"ZA", ZA_PNG }, { L"ZM", ZM_PNG }, { L"ZW", ZW_PNG } + { L"AD", AD_PNG, INT_MAX }, { L"AE", AE_PNG, INT_MAX }, { L"AF", AF_PNG, INT_MAX }, { L"AG", AG_PNG, INT_MAX }, + { L"AI", AI_PNG, INT_MAX }, { L"AL", AL_PNG, INT_MAX }, { L"AM", AM_PNG, INT_MAX }, { L"AN", AN_PNG, INT_MAX }, + { L"AO", AO_PNG, INT_MAX }, { L"AR", AR_PNG, INT_MAX }, { L"AS", AS_PNG, INT_MAX }, { L"AT", AT_PNG, INT_MAX }, + { L"AU", AU_PNG, INT_MAX }, { L"AW", AW_PNG, INT_MAX }, { L"AX", AX_PNG, INT_MAX }, { L"AZ", AZ_PNG, INT_MAX }, + { L"BA", BA_PNG, INT_MAX }, { L"BB", BB_PNG, INT_MAX }, { L"BD", BD_PNG, INT_MAX }, { L"BE", BE_PNG, INT_MAX }, + { L"BF", BF_PNG, INT_MAX }, { L"BG", BG_PNG, INT_MAX }, { L"BH", BH_PNG, INT_MAX }, { L"BI", BI__PNG, INT_MAX }, + { L"BJ", BJ_PNG, INT_MAX }, { L"BM", BM_PNG, INT_MAX }, { L"BN", BN_PNG, INT_MAX }, { L"BO", BO_PNG, INT_MAX }, + { L"BR", BR_PNG, INT_MAX }, { L"BS", BS_PNG, INT_MAX }, { L"BT", BT_PNG, INT_MAX }, { L"BV", BV_PNG, INT_MAX }, + { L"BW", BW_PNG, INT_MAX }, { L"BY", BY_PNG, INT_MAX }, { L"BZ", BZ_PNG, INT_MAX }, + { L"CA", CA_PNG, INT_MAX }, { L"CC", CC_PNG, INT_MAX }, { L"CD", CD_PNG, INT_MAX }, { L"CF", CF_PNG, INT_MAX }, + { L"CG", CG_PNG, INT_MAX }, { L"CH", CH_PNG, INT_MAX }, { L"CI", CI_PNG, INT_MAX }, { L"CK", CK_PNG, INT_MAX }, + { L"CL", CL_PNG, INT_MAX }, { L"CM", CM_PNG, INT_MAX }, { L"CN", CN_PNG, INT_MAX }, { L"CO", CO_PNG, INT_MAX }, + { L"CR", CR_PNG, INT_MAX }, { L"CS", CS_PNG, INT_MAX }, { L"CU", CU_PNG, INT_MAX }, { L"CV", CV_PNG, INT_MAX }, + { L"CX", CX_PNG, INT_MAX }, { L"CY", CY_PNG, INT_MAX }, { L"CZ", CZ_PNG, INT_MAX }, { L"DE", DE_PNG, INT_MAX }, + { L"DJ", DJ_PNG, INT_MAX }, { L"DK", DK_PNG, INT_MAX }, { L"DM", DM_PNG, INT_MAX }, { L"DO", DO_PNG, INT_MAX }, + { L"DZ", DZ_PNG, INT_MAX }, + { L"EC", EC_PNG, INT_MAX }, { L"EE", EE_PNG, INT_MAX }, { L"EG", EG_PNG, INT_MAX }, { L"EH", EH_PNG, INT_MAX }, + { L"ER", ER_PNG, INT_MAX }, { L"ES", ES_PNG, INT_MAX }, { L"ET", ET_PNG, INT_MAX }, + { L"FI", FI_PNG, INT_MAX }, { L"FJ", FJ_PNG, INT_MAX }, { L"FK", FK_PNG, INT_MAX }, { L"FO", FO_PNG, INT_MAX }, + { L"FR", FR_PNG, INT_MAX }, + { L"GA", GA_PNG, INT_MAX }, { L"GB", GB_PNG, INT_MAX }, { L"GD", GD_PNG, INT_MAX }, { L"GE", GE_PNG, INT_MAX }, + { L"GF", GF_PNG, INT_MAX }, { L"GH", GH_PNG, INT_MAX }, { L"GI", GI_PNG, INT_MAX }, { L"GL", GL_PNG, INT_MAX }, + { L"GM", GM_PNG, INT_MAX }, { L"GN", GN_PNG, INT_MAX }, { L"GP", GP_PNG, INT_MAX }, { L"GQ", GQ_PNG, INT_MAX }, + { L"GR", GR_PNG, INT_MAX }, { L"GS", GS_PNG, INT_MAX }, { L"GT", GT_PNG, INT_MAX }, { L"GU", GU_PNG, INT_MAX }, + { L"GW", GW_PNG, INT_MAX }, { L"GY", GY_PNG, INT_MAX }, + { L"HK", HK_PNG, INT_MAX }, { L"HM", HM_PNG, INT_MAX }, { L"HN", HN_PNG, INT_MAX }, { L"HR", HR_PNG, INT_MAX }, + { L"HT", HT_PNG, INT_MAX }, { L"HU", HU_PNG, INT_MAX }, + { L"ID", ID_PNG, INT_MAX }, { L"IE", IE_PNG, INT_MAX }, { L"IL", IL_PNG, INT_MAX }, { L"IN", IN_PNG, INT_MAX }, + { L"IO", IO_PNG, INT_MAX }, { L"IQ", IQ_PNG, INT_MAX }, { L"IR", IR_PNG, INT_MAX }, { L"IS", IS_PNG, INT_MAX }, + { L"IT", IT_PNG, INT_MAX }, + { L"JM", JM_PNG, INT_MAX }, { L"JO", JO_PNG, INT_MAX }, { L"JP", JP_PNG, INT_MAX }, + { L"KE", KE_PNG, INT_MAX }, { L"KG", KG_PNG, INT_MAX }, { L"KH", KH_PNG, INT_MAX }, { L"KI", KI_PNG, INT_MAX }, + { L"KM", KM_PNG, INT_MAX }, { L"KN", KN_PNG, INT_MAX }, { L"KP", KP_PNG, INT_MAX }, { L"KR", KR_PNG, INT_MAX }, + { L"KW", KW_PNG, INT_MAX }, { L"KY", KY_PNG, INT_MAX }, { L"KZ", KZ_PNG, INT_MAX }, + { L"LA", LA_PNG, INT_MAX }, { L"LB", LB_PNG, INT_MAX }, { L"LC", LC_PNG, INT_MAX }, { L"LI", LI_PNG, INT_MAX }, + { L"LK", LK_PNG, INT_MAX }, { L"LR", LR_PNG, INT_MAX }, { L"LS", LS_PNG, INT_MAX }, { L"LT", LT_PNG, INT_MAX }, + { L"LU", LU_PNG, INT_MAX }, { L"LV", LV_PNG, INT_MAX }, { L"LY", LY_PNG, INT_MAX }, + { L"MA", MA_PNG, INT_MAX }, { L"MC", MC_PNG, INT_MAX }, { L"MD", MD_PNG, INT_MAX }, { L"ME", ME_PNG, INT_MAX }, + { L"MG", MG_PNG, INT_MAX }, { L"MH", MH_PNG, INT_MAX }, { L"MK", MK_PNG, INT_MAX }, { L"ML", ML_PNG, INT_MAX }, + { L"MM", MM_PNG, INT_MAX }, { L"MN", MN_PNG, INT_MAX }, { L"MO", MO_PNG, INT_MAX }, { L"MP", MP_PNG, INT_MAX }, + { L"MQ", MQ_PNG, INT_MAX }, { L"MR", MR_PNG, INT_MAX }, { L"MS", MS_PNG, INT_MAX }, { L"MT", MT_PNG, INT_MAX }, + { L"MU", MU_PNG, INT_MAX }, { L"MV", MV_PNG, INT_MAX }, { L"MW", MW_PNG, INT_MAX }, { L"MX", MX_PNG, INT_MAX }, + { L"MY", MY_PNG, INT_MAX }, { L"MZ", MZ_PNG, INT_MAX }, + { L"NA", NA_PNG, INT_MAX }, { L"NC", NC_PNG, INT_MAX }, { L"NE", NE_PNG, INT_MAX }, { L"NF", NF_PNG, INT_MAX }, + { L"NG", NG_PNG, INT_MAX }, { L"NI", NI_PNG, INT_MAX }, { L"NL", NL_PNG, INT_MAX }, { L"NO", NO_PNG, INT_MAX }, + { L"NP", NP_PNG, INT_MAX }, { L"NR", NR_PNG, INT_MAX }, { L"NU", NU_PNG, INT_MAX }, { L"NZ", NZ_PNG, INT_MAX }, + { L"OM", OM_PNG, INT_MAX }, + { L"PA", PA_PNG, INT_MAX }, { L"PE", PE_PNG, INT_MAX }, { L"PF", PF_PNG, INT_MAX }, { L"PG", PG_PNG, INT_MAX }, + { L"PH", PH_PNG, INT_MAX }, { L"PK", PK_PNG, INT_MAX }, { L"PL", PL_PNG, INT_MAX }, { L"PM", PM_PNG, INT_MAX }, + { L"PN", PN_PNG, INT_MAX }, { L"PR", PR_PNG, INT_MAX }, { L"PS", PS_PNG, INT_MAX }, { L"PT", PT_PNG, INT_MAX }, + { L"PW", PW_PNG, INT_MAX }, { L"PY", PY_PNG, INT_MAX }, + { L"QA", QA_PNG, INT_MAX }, + { L"RE", RE_PNG, INT_MAX }, { L"RO", RO_PNG, INT_MAX }, { L"RS", RS_PNG, INT_MAX }, { L"RU", RU_PNG, INT_MAX }, + { L"RW", RW_PNG, INT_MAX }, + { L"SA", SA_PNG, INT_MAX }, { L"SB", SB_PNG, INT_MAX }, { L"SC", SC_PNG, INT_MAX }, { L"SD", SD_PNG, INT_MAX }, + { L"SE", SE_PNG, INT_MAX }, { L"SG", SG_PNG, INT_MAX }, { L"SH", SH_PNG, INT_MAX }, { L"SI", SI_PNG, INT_MAX }, + { L"SJ", SJ_PNG, INT_MAX }, { L"SK", SK_PNG, INT_MAX }, { L"SL", SL_PNG, INT_MAX }, { L"SM", SM_PNG, INT_MAX }, + { L"SN", SN_PNG, INT_MAX }, { L"SO", SO_PNG, INT_MAX }, { L"SR", SR_PNG, INT_MAX }, { L"ST", ST_PNG, INT_MAX }, + { L"SV", SV_PNG, INT_MAX }, { L"SY", SY_PNG, INT_MAX }, { L"SZ", SZ_PNG, INT_MAX }, + { L"TC", TC_PNG, INT_MAX }, { L"TD", TD_PNG, INT_MAX }, { L"TF", TF_PNG, INT_MAX }, { L"TG", TG_PNG, INT_MAX }, + { L"TH", TH_PNG, INT_MAX }, { L"TJ", TJ_PNG, INT_MAX }, { L"TK", TK_PNG, INT_MAX }, { L"TL", TL_PNG, INT_MAX }, + { L"TM", TM_PNG, INT_MAX }, { L"TN", TN_PNG, INT_MAX }, { L"TO", TO_PNG, INT_MAX }, { L"TR", TR_PNG, INT_MAX }, + { L"TT", TT_PNG, INT_MAX }, { L"TV", TV_PNG, INT_MAX }, { L"TW", TW_PNG, INT_MAX }, { L"TZ", TZ_PNG, INT_MAX }, + { L"UA", UA_PNG, INT_MAX }, { L"UG", UG_PNG, INT_MAX }, { L"UM", UM_PNG, INT_MAX }, { L"US", US_PNG, INT_MAX }, + { L"UY", UY_PNG, INT_MAX }, { L"UZ", UZ_PNG, INT_MAX }, + { L"VA", VA_PNG, INT_MAX }, { L"VC", VC_PNG, INT_MAX }, { L"VE", VE_PNG, INT_MAX }, { L"VG", VG_PNG, INT_MAX }, + { L"VI", VI_PNG, INT_MAX }, { L"VN", VN_PNG, INT_MAX }, { L"VU", VU_PNG, INT_MAX }, + { L"WF", WF_PNG, INT_MAX }, { L"WS", WS_PNG, INT_MAX }, + { L"YE", YE_PNG, INT_MAX }, { L"YT", YT_PNG, INT_MAX }, + { L"ZA", ZA_PNG, INT_MAX }, { L"ZM", ZM_PNG, INT_MAX }, { L"ZW", ZW_PNG, INT_MAX } }; -HICON LookupCountryIcon( +INT LookupCountryIcon( _In_ PPH_STRING Name ) { + if (!GeoImageList) + return INT_MAX; + for (INT i = 0; i < ARRAYSIZE(CountryResourceTable); i++) { if (PhEqualString2(Name, CountryResourceTable[i].CountryCode, TRUE)) { - if (!CountryResourceTable[i].IconHandle) + if (CountryResourceTable[i].IconIndex == INT_MAX) { HBITMAP countryBitmap; @@ -474,14 +489,37 @@ HICON LookupCountryIcon( if (countryBitmap) { - CountryResourceTable[i].IconHandle = CommonBitmapToIcon(countryBitmap, 16, 11); + CountryResourceTable[i].IconIndex = ImageList_Add( + GeoImageList, + countryBitmap, + NULL + ); DeleteObject(countryBitmap); } } - return CountryResourceTable[i].IconHandle; + return CountryResourceTable[i].IconIndex; } } - return 0; -} \ No newline at end of file + return INT_MAX; +} + +VOID DrawCountryIcon( + _In_ HDC hdc, + _In_ RECT rect, + _In_ INT Index + ) +{ + if (!GeoImageList) + return; + + ImageList_Draw( + GeoImageList, + Index, + hdc, + rect.left, + rect.top + ((rect.bottom - rect.top) - 11) / 2, + ILD_NORMAL + ); +} diff --git a/plugins/NetworkTools/main.c b/plugins/NetworkTools/main.c index 591acadf8da4..7a9b2c9a6d08 100644 --- a/plugins/NetworkTools/main.c +++ b/plugins/NetworkTools/main.c @@ -424,6 +424,7 @@ VOID NTAPI NetworkItemCreateCallback( memset(extension, 0, sizeof(NETWORK_EXTENSION)); extension->NetworkItem = networkItem; + extension->CountryIconIndex = INT_MAX; if (NetworkExtensionEnabled) { @@ -715,22 +716,12 @@ VOID NTAPI TreeNewMessageCallback( // Draw the column data if (GeoDbLoaded && !GeoDbExpired && extension->RemoteCountryCode && extension->RemoteCountryName) { - if (!extension->CountryIcon) - extension->CountryIcon = LookupCountryIcon(extension->RemoteCountryCode); + if (extension->CountryIconIndex == INT_MAX) + extension->CountryIconIndex = LookupCountryIcon(extension->RemoteCountryCode); - if (extension->CountryIcon) + if (extension->CountryIconIndex != INT_MAX) { - DrawIconEx( - hdc, - rect.left, - rect.top + ((rect.bottom - rect.top) - 11) / 2, - extension->CountryIcon, - 16, - 11, - 0, - NULL, - DI_NORMAL - ); + DrawCountryIcon(hdc, rect, extension->CountryIconIndex); rect.left += 16 + 2; } @@ -738,7 +729,7 @@ VOID NTAPI TreeNewMessageCallback( DrawText( hdc, extension->RemoteCountryName->Buffer, - (INT)extension->RemoteCountryName->Length / 2, + (INT)extension->RemoteCountryName->Length / sizeof(WCHAR), &rect, DT_LEFT | DT_VCENTER | DT_END_ELLIPSIS | DT_SINGLELINE ); diff --git a/plugins/NetworkTools/maxminddb/data-pool.c b/plugins/NetworkTools/maxminddb/data-pool.c new file mode 100644 index 000000000000..48521b64dec3 --- /dev/null +++ b/plugins/NetworkTools/maxminddb/data-pool.c @@ -0,0 +1,180 @@ +#include "data-pool.h" +#include "maxminddb.h" + +#include +#include +#include + +static bool can_multiply(size_t const, size_t const, size_t const); + +// Allocate an MMDB_data_pool_s. It initially has space for size +// MMDB_entry_data_list_s structs. +MMDB_data_pool_s *data_pool_new(size_t const size) +{ + MMDB_data_pool_s *const pool = calloc(1, sizeof(MMDB_data_pool_s)); + if (!pool) { + return NULL; + } + + if (size == 0 || + !can_multiply(SIZE_MAX, size, sizeof(MMDB_entry_data_list_s))) { + data_pool_destroy(pool); + return NULL; + } + pool->size = size; + pool->blocks[0] = calloc(pool->size, sizeof(MMDB_entry_data_list_s)); + if (!pool->blocks[0]) { + data_pool_destroy(pool); + return NULL; + } + pool->blocks[0]->pool = pool; + + pool->sizes[0] = size; + + pool->block = pool->blocks[0]; + + return pool; +} + +// Determine if we can multiply m*n. We can do this if the result will be below +// the given max. max will typically be SIZE_MAX. +// +// We want to know if we'll wrap around. +static bool can_multiply(size_t const max, size_t const m, size_t const n) +{ + if (m == 0) { + return false; + } + + return n <= max / m; +} + +// Clean up the data pool. +void data_pool_destroy(MMDB_data_pool_s *const pool) +{ + if (!pool) { + return; + } + + for (size_t i = 0; i <= pool->index; i++) { + free(pool->blocks[i]); + } + + free(pool); +} + +// Claim a new struct from the pool. Doing this may cause the pool's size to +// grow. +MMDB_entry_data_list_s *data_pool_alloc(MMDB_data_pool_s *const pool) +{ + if (!pool) { + return NULL; + } + + if (pool->used < pool->size) { + MMDB_entry_data_list_s *const element = pool->block + pool->used; + pool->used++; + return element; + } + + // Take it from a new block of memory. + + size_t const new_index = pool->index + 1; + if (new_index == DATA_POOL_NUM_BLOCKS) { + // See the comment about not growing this on DATA_POOL_NUM_BLOCKS. + return NULL; + } + + if (!can_multiply(SIZE_MAX, pool->size, 2)) { + return NULL; + } + size_t const new_size = pool->size * 2; + + if (!can_multiply(SIZE_MAX, new_size, sizeof(MMDB_entry_data_list_s))) { + return NULL; + } + pool->blocks[new_index] = calloc(new_size, sizeof(MMDB_entry_data_list_s)); + if (!pool->blocks[new_index]) { + return NULL; + } + + // We don't need to set this, but it's useful for introspection in tests. + pool->blocks[new_index]->pool = pool; + + pool->index = new_index; + pool->block = pool->blocks[pool->index]; + + pool->size = new_size; + pool->sizes[pool->index] = pool->size; + + MMDB_entry_data_list_s *const element = pool->block; + pool->used = 1; + return element; +} + +// Turn the structs in the array-like pool into a linked list. +// +// Before calling this function, the list isn't linked up. +MMDB_entry_data_list_s *data_pool_to_list(MMDB_data_pool_s *const pool) +{ + if (!pool) { + return NULL; + } + + if (pool->index == 0 && pool->used == 0) { + return NULL; + } + + for (size_t i = 0; i <= pool->index; i++) { + MMDB_entry_data_list_s *const block = pool->blocks[i]; + + size_t size = pool->sizes[i]; + if (i == pool->index) { + size = pool->used; + } + + for (size_t j = 0; j < size - 1; j++) { + MMDB_entry_data_list_s *const cur = block + j; + cur->next = block + j + 1; + } + + if (i < pool->index) { + MMDB_entry_data_list_s *const last = block + size - 1; + last->next = pool->blocks[i + 1]; + } + } + + return pool->blocks[0]; +} + +#ifdef TEST_DATA_POOL + +#include +#include + +static void test_can_multiply(void); + +int main(void) +{ + plan(NO_PLAN); + test_can_multiply(); + done_testing(); +} + +static void test_can_multiply(void) +{ + { + ok(can_multiply(SIZE_MAX, 1, SIZE_MAX), "1*SIZE_MAX is ok"); + } + + { + ok(!can_multiply(SIZE_MAX, 2, SIZE_MAX), "2*SIZE_MAX is not ok"); + } + + { + ok(can_multiply(SIZE_MAX, 10240, sizeof(MMDB_entry_data_list_s)), + "1024 entry_data_list_s's are okay"); + } +} + +#endif diff --git a/plugins/NetworkTools/maxminddb/data-pool.h b/plugins/NetworkTools/maxminddb/data-pool.h new file mode 100644 index 000000000000..25d09923e0cc --- /dev/null +++ b/plugins/NetworkTools/maxminddb/data-pool.h @@ -0,0 +1,52 @@ +#ifndef DATA_POOL_H +#define DATA_POOL_H + +#include "maxminddb.h" + +#include +#include + +// This should be large enough that we never need to grow the array of pointers +// to blocks. 32 is enough. Even starting out of with size 1 (1 struct), the +// 32nd element alone will provide 2**32 structs as we exponentially increase +// the number in each block. Being confident that we do not have to grow the +// array lets us avoid writing code to do that. That code would be risky as it +// would rarely be hit and likely not be well tested. +#define DATA_POOL_NUM_BLOCKS 32 + +// A pool of memory for MMDB_entry_data_list_s structs. This is so we can +// allocate multiple up front rather than one at a time for performance +// reasons. +// +// The order you add elements to it (by calling data_pool_alloc()) ends up as +// the order of the list. +// +// The memory only grows. There is no support for releasing an element you take +// back to the pool. +typedef struct MMDB_data_pool_s { + // Index of the current block we're allocating out of. + size_t index; + + // The size of the current block, counting by structs. + size_t size; + + // How many used in the current block, counting by structs. + size_t used; + + // The current block we're allocating out of. + MMDB_entry_data_list_s *block; + + // The size of each block. + size_t sizes[DATA_POOL_NUM_BLOCKS]; + + // An array of pointers to blocks of memory holding space for list + // elements. + MMDB_entry_data_list_s *blocks[DATA_POOL_NUM_BLOCKS]; +} MMDB_data_pool_s; + +MMDB_data_pool_s *data_pool_new(size_t const); +void data_pool_destroy(MMDB_data_pool_s *const); +MMDB_entry_data_list_s *data_pool_alloc(MMDB_data_pool_s *const); +MMDB_entry_data_list_s *data_pool_to_list(MMDB_data_pool_s *const); + +#endif diff --git a/plugins/NetworkTools/maxminddb/maxminddb.c b/plugins/NetworkTools/maxminddb/maxminddb.c index 24979674a53f..a6dbdb5f3a5d 100644 --- a/plugins/NetworkTools/maxminddb/maxminddb.c +++ b/plugins/NetworkTools/maxminddb/maxminddb.c @@ -1,9 +1,7 @@ -#pragma warning(push) -#pragma warning(disable : 4244) - #if HAVE_CONFIG_H #include #endif +#include "data-pool.h" #include "maxminddb.h" #include "maxminddb-compat-util.h" #include @@ -111,8 +109,8 @@ DEBUG_FUNC char *type_num_to_name(uint8_t num) #endif /* None of the values we check on the lhs are bigger than uint32_t, so on - * platforms where SIZE_MAX is a 64-bit integer, this would be a no-op, and it - * makes the compiler complain if we do the check anyway. */ +* platforms where SIZE_MAX is a 64-bit integer, this would be a no-op, and it +* makes the compiler complain if we do the check anyway. */ #if SIZE_MAX == UINT32_MAX #define MAYBE_CHECK_SIZE_OVERFLOW(lhs, rhs, error) \ if ((lhs) > (rhs)) { \ @@ -133,54 +131,60 @@ typedef struct record_info_s { /* This is 128kb */ #define METADATA_BLOCK_MAX_SIZE 131072 +// 64 leads us to allocating 4 KiB on a 64bit system. +#define MMDB_POOL_INIT_SIZE 64 + /* *INDENT-OFF* */ /* --prototypes automatically generated by dev-bin/regen-prototypes.pl - don't remove this comment */ LOCAL int map_file(MMDB_s *const mmdb); LOCAL const uint8_t *find_metadata(const uint8_t *file_content, - ssize_t file_size, uint32_t *metadata_size); + ssize_t file_size, uint32_t *metadata_size); LOCAL int read_metadata(MMDB_s *mmdb); LOCAL MMDB_s make_fake_metadata_db(MMDB_s *mmdb); LOCAL int value_for_key_as_uint16(MMDB_entry_s *start, char *key, - uint16_t *value); + uint16_t *value); LOCAL int value_for_key_as_uint32(MMDB_entry_s *start, char *key, - uint32_t *value); + uint32_t *value); LOCAL int value_for_key_as_uint64(MMDB_entry_s *start, char *key, - uint64_t *value); + uint64_t *value); LOCAL int value_for_key_as_string(MMDB_entry_s *start, char *key, - char const **value); + char const **value); LOCAL int populate_languages_metadata(MMDB_s *mmdb, MMDB_s *metadata_db, - MMDB_entry_s *metadata_start); + MMDB_entry_s *metadata_start); LOCAL int populate_description_metadata(MMDB_s *mmdb, MMDB_s *metadata_db, - MMDB_entry_s *metadata_start); + MMDB_entry_s *metadata_start); LOCAL int resolve_any_address(const char *ipstr, struct addrinfo **addresses); LOCAL int find_address_in_search_tree(MMDB_s *mmdb, uint8_t *address, - sa_family_t address_family, - MMDB_lookup_result_s *result); + sa_family_t address_family, + MMDB_lookup_result_s *result); LOCAL record_info_s record_info_for_database(MMDB_s *mmdb); LOCAL int find_ipv4_start_node(MMDB_s *mmdb); -LOCAL int maybe_populate_result(MMDB_s *mmdb, uint32_t record, - uint16_t netmask, MMDB_lookup_result_s *result); +LOCAL uint8_t maybe_populate_result(MMDB_s *mmdb, uint32_t record, + uint16_t netmask, + MMDB_lookup_result_s *result); LOCAL uint8_t record_type(MMDB_s *const mmdb, uint64_t record); LOCAL uint32_t get_left_28_bit_record(const uint8_t *record); LOCAL uint32_t get_right_28_bit_record(const uint8_t *record); LOCAL uint32_t data_section_offset_for_record(MMDB_s *const mmdb, - uint64_t record); + uint64_t record); LOCAL int path_length(va_list va_path); LOCAL int lookup_path_in_array(const char *path_elem, MMDB_s *mmdb, - MMDB_entry_data_s *entry_data); + MMDB_entry_data_s *entry_data); LOCAL int lookup_path_in_map(const char *path_elem, MMDB_s *mmdb, - MMDB_entry_data_s *entry_data); + MMDB_entry_data_s *entry_data); LOCAL int skip_map_or_array(MMDB_s *mmdb, MMDB_entry_data_s *entry_data); LOCAL int decode_one_follow(MMDB_s *mmdb, uint32_t offset, - MMDB_entry_data_s *entry_data); + MMDB_entry_data_s *entry_data); LOCAL int decode_one(MMDB_s *mmdb, uint32_t offset, - MMDB_entry_data_s *entry_data); + MMDB_entry_data_s *entry_data); LOCAL int get_ext_type(int raw_ext_type); LOCAL uint32_t get_ptr_from(uint8_t ctrl, uint8_t const *const ptr, - int ptr_size); -LOCAL int get_entry_data_list(MMDB_s *mmdb, uint32_t offset, - MMDB_entry_data_list_s *const entry_data_list, - int depth); + int ptr_size); +LOCAL int get_entry_data_list(MMDB_s *mmdb, + uint32_t offset, + MMDB_entry_data_list_s *const entry_data_list, + MMDB_data_pool_s *const pool, + int depth); LOCAL float get_ieee754_float(const uint8_t *restrict p); LOCAL double get_ieee754_double(const uint8_t *restrict p); LOCAL uint32_t get_uint32(const uint8_t *p); @@ -188,7 +192,6 @@ LOCAL uint32_t get_uint24(const uint8_t *p); LOCAL uint32_t get_uint16(const uint8_t *p); LOCAL uint64_t get_uintX(const uint8_t *p, int length); LOCAL int32_t get_sintX(const uint8_t *p, int length); -LOCAL MMDB_entry_data_list_s *new_entry_data_list(void); LOCAL void free_mmdb_struct(MMDB_s *const mmdb); LOCAL void free_languages_metadata(MMDB_s *mmdb); LOCAL void free_descriptions_metadata(MMDB_s *mmdb); @@ -222,7 +225,7 @@ LOCAL char *bytes_to_hex(uint8_t *bytes, uint32_t size); #define FREE_AND_SET_NULL(p) { free((void *)(p)); (p) = NULL; } -int MMDB_open(const wchar_t* const filename, uint32_t flags, MMDB_s *const mmdb) +int MMDB_open(const wchar_t *const filename, uint32_t flags, MMDB_s *const mmdb) { int status = MMDB_SUCCESS; @@ -243,7 +246,7 @@ int MMDB_open(const wchar_t* const filename, uint32_t flags, MMDB_s *const mmdb) } mmdb->flags = flags; - if (MMDB_SUCCESS != (status = map_file(mmdb)) ) { + if (MMDB_SUCCESS != (status = map_file(mmdb))) { goto cleanup; } @@ -254,7 +257,7 @@ int MMDB_open(const wchar_t* const filename, uint32_t flags, MMDB_s *const mmdb) uint32_t metadata_size = 0; const uint8_t *metadata = find_metadata(mmdb->file_content, mmdb->file_size, - &metadata_size); + &metadata_size); if (NULL == metadata) { status = MMDB_INVALID_METADATA_ERROR; goto cleanup; @@ -274,22 +277,41 @@ int MMDB_open(const wchar_t* const filename, uint32_t flags, MMDB_s *const mmdb) } uint32_t search_tree_size = mmdb->metadata.node_count * - mmdb->full_record_byte_size; + mmdb->full_record_byte_size; mmdb->data_section = mmdb->file_content + search_tree_size - + MMDB_DATA_SECTION_SEPARATOR; + + MMDB_DATA_SECTION_SEPARATOR; if (search_tree_size + MMDB_DATA_SECTION_SEPARATOR > (uint32_t)mmdb->file_size) { status = MMDB_INVALID_METADATA_ERROR; goto cleanup; } - mmdb->data_section_size = mmdb->file_size - search_tree_size - - MMDB_DATA_SECTION_SEPARATOR; + mmdb->data_section_size = (uint32_t)mmdb->file_size - search_tree_size - + MMDB_DATA_SECTION_SEPARATOR; + + // Although it is likely not possible to construct a database with valid + // valid metadata, as parsed above, and a data_section_size less than 3, + // we do this check as later we assume it is at least three when doing + // bound checks. + if (mmdb->data_section_size < 3) { + status = MMDB_INVALID_DATA_ERROR; + goto cleanup; + } + mmdb->metadata_section = metadata; mmdb->ipv4_start_node.node_value = 0; mmdb->ipv4_start_node.netmask = 0; - cleanup: + // We do this immediately as otherwise there is a race to set + // ipv4_start_node.node_value and ipv4_start_node.netmask. + if (mmdb->metadata.ip_version == 6) { + status = find_ipv4_start_node(mmdb); + if (status != MMDB_SUCCESS) { + goto cleanup; + } + } + +cleanup: if (MMDB_SUCCESS != status) { int saved_errno = errno; free_mmdb_struct(mmdb); @@ -302,11 +324,11 @@ int MMDB_open(const wchar_t* const filename, uint32_t flags, MMDB_s *const mmdb) LOCAL int map_file(MMDB_s *const mmdb) { - ssize_t size; + DWORD size; int status = MMDB_SUCCESS; HANDLE mmh = NULL; - HANDLE fd = CreateFileW(mmdb->filename, GENERIC_READ, FILE_SHARE_READ, NULL, // dmex: modified for wchar_t - OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + HANDLE fd = CreateFileW(mmdb->filename, GENERIC_READ, FILE_SHARE_READ, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (fd == INVALID_HANDLE_VALUE) { status = MMDB_FILE_OPEN_ERROR; goto cleanup; @@ -318,7 +340,7 @@ LOCAL int map_file(MMDB_s *const mmdb) } mmh = CreateFileMappingA(fd, NULL, PAGE_READONLY, 0, size, NULL); /* Microsoft documentation for CreateFileMapping indicates this returns - NULL not INVALID_HANDLE_VALUE on error */ + NULL not INVALID_HANDLE_VALUE on error */ if (NULL == mmh) { status = MMDB_IO_ERROR; goto cleanup; @@ -333,7 +355,7 @@ LOCAL int map_file(MMDB_s *const mmdb) mmdb->file_size = size; mmdb->file_content = file_content; - cleanup:; +cleanup:; int saved_errno = errno; if (INVALID_HANDLE_VALUE != fd) { CloseHandle(fd); @@ -353,7 +375,11 @@ LOCAL int map_file(MMDB_s *const mmdb) ssize_t size; int status = MMDB_SUCCESS; - int fd = open(mmdb->filename, O_RDONLY); + int flags = O_RDONLY; +#ifdef O_CLOEXEC + flags |= O_CLOEXEC; +#endif + int fd = open(mmdb->filename, flags); struct stat s; if (fd < 0 || fstat(fd, &s)) { status = MMDB_FILE_OPEN_ERROR; @@ -371,7 +397,8 @@ LOCAL int map_file(MMDB_s *const mmdb) if (MAP_FAILED == file_content) { if (ENOMEM == errno) { status = MMDB_OUT_OF_MEMORY_ERROR; - } else { + } + else { status = MMDB_IO_ERROR; } goto cleanup; @@ -380,7 +407,7 @@ LOCAL int map_file(MMDB_s *const mmdb) mmdb->file_size = size; mmdb->file_content = file_content; - cleanup:; +cleanup:; int saved_errno = errno; if (fd >= 0) { close(fd); @@ -393,27 +420,27 @@ LOCAL int map_file(MMDB_s *const mmdb) #endif LOCAL const uint8_t *find_metadata(const uint8_t *file_content, - ssize_t file_size, uint32_t *metadata_size) + ssize_t file_size, uint32_t *metadata_size) { const ssize_t marker_len = sizeof(METADATA_MARKER) - 1; ssize_t max_size = file_size > - METADATA_BLOCK_MAX_SIZE ? METADATA_BLOCK_MAX_SIZE : - file_size; + METADATA_BLOCK_MAX_SIZE ? METADATA_BLOCK_MAX_SIZE : + file_size; uint8_t *search_area = (uint8_t *)(file_content + (file_size - max_size)); uint8_t *start = search_area; uint8_t *tmp; do { tmp = mmdb_memmem(search_area, max_size, - METADATA_MARKER, marker_len); + METADATA_MARKER, marker_len); if (NULL != tmp) { max_size -= tmp - search_area; search_area = tmp; /* Continue searching just after the marker we just read, in case - * there are multiple markers in the same file. This would be odd - * but is certainly not impossible. */ + * there are multiple markers in the same file. This would be odd + * but is certainly not impossible. */ max_size -= marker_len; search_area += marker_len; } @@ -423,7 +450,7 @@ LOCAL const uint8_t *find_metadata(const uint8_t *file_content, return NULL; } - *metadata_size = max_size; + *metadata_size = (uint32_t)max_size; return search_area; } @@ -431,19 +458,19 @@ LOCAL const uint8_t *find_metadata(const uint8_t *file_content, LOCAL int read_metadata(MMDB_s *mmdb) { /* We need to create a fake MMDB_s struct in order to decode values from - the metadata. The metadata is basically just like the data section, so we - want to use the same functions we use for the data section to get metadata - values. */ + the metadata. The metadata is basically just like the data section, so we + want to use the same functions we use for the data section to get metadata + values. */ MMDB_s metadata_db = make_fake_metadata_db(mmdb); MMDB_entry_s metadata_start = { - .mmdb = &metadata_db, + .mmdb = &metadata_db, .offset = 0 }; int status = value_for_key_as_uint32(&metadata_start, "node_count", - &mmdb->metadata.node_count); + &mmdb->metadata.node_count); if (MMDB_SUCCESS != status) { return status; } @@ -453,7 +480,7 @@ LOCAL int read_metadata(MMDB_s *mmdb) } status = value_for_key_as_uint16(&metadata_start, "record_size", - &mmdb->metadata.record_size); + &mmdb->metadata.record_size); if (MMDB_SUCCESS != status) { return status; } @@ -465,12 +492,12 @@ LOCAL int read_metadata(MMDB_s *mmdb) if (mmdb->metadata.record_size != 24 && mmdb->metadata.record_size != 28 && mmdb->metadata.record_size != 32) { DEBUG_MSGF("bad record size in metadata: %i", - mmdb->metadata.record_size); + mmdb->metadata.record_size); return MMDB_UNKNOWN_DATABASE_FORMAT_ERROR; } status = value_for_key_as_uint16(&metadata_start, "ip_version", - &mmdb->metadata.ip_version); + &mmdb->metadata.ip_version); if (MMDB_SUCCESS != status) { return status; } @@ -480,12 +507,12 @@ LOCAL int read_metadata(MMDB_s *mmdb) } if (!(mmdb->metadata.ip_version == 4 || mmdb->metadata.ip_version == 6)) { DEBUG_MSGF("ip_version value in metadata is not 4 or 6 - it was %i", - mmdb->metadata.ip_version); + mmdb->metadata.ip_version); return MMDB_INVALID_METADATA_ERROR; } status = value_for_key_as_string(&metadata_start, "database_type", - &mmdb->metadata.database_type); + &mmdb->metadata.database_type); if (MMDB_SUCCESS != status) { DEBUG_MSG("error finding database_type value in metadata"); return status; @@ -518,7 +545,7 @@ LOCAL int read_metadata(MMDB_s *mmdb) } status = value_for_key_as_uint64(&metadata_start, "build_epoch", - &mmdb->metadata.build_epoch); + &mmdb->metadata.build_epoch); if (MMDB_SUCCESS != status) { return status; } @@ -543,7 +570,7 @@ LOCAL int read_metadata(MMDB_s *mmdb) LOCAL MMDB_s make_fake_metadata_db(MMDB_s *mmdb) { MMDB_s fake_metadata_db = { - .data_section = mmdb->metadata_section, + .data_section = mmdb->metadata_section, .data_section_size = mmdb->metadata_section_size }; @@ -551,7 +578,7 @@ LOCAL MMDB_s make_fake_metadata_db(MMDB_s *mmdb) } LOCAL int value_for_key_as_uint16(MMDB_entry_s *start, char *key, - uint16_t *value) + uint16_t *value) { MMDB_entry_data_s entry_data; const char *path[] = { key, NULL }; @@ -561,8 +588,8 @@ LOCAL int value_for_key_as_uint16(MMDB_entry_s *start, char *key, } if (MMDB_DATA_TYPE_UINT16 != entry_data.type) { DEBUG_MSGF("expect uint16 for %s but received %s", key, - type_num_to_name( - entry_data.type)); + type_num_to_name( + entry_data.type)); return MMDB_INVALID_METADATA_ERROR; } *value = entry_data.uint16; @@ -570,7 +597,7 @@ LOCAL int value_for_key_as_uint16(MMDB_entry_s *start, char *key, } LOCAL int value_for_key_as_uint32(MMDB_entry_s *start, char *key, - uint32_t *value) + uint32_t *value) { MMDB_entry_data_s entry_data; const char *path[] = { key, NULL }; @@ -580,8 +607,8 @@ LOCAL int value_for_key_as_uint32(MMDB_entry_s *start, char *key, } if (MMDB_DATA_TYPE_UINT32 != entry_data.type) { DEBUG_MSGF("expect uint32 for %s but received %s", key, - type_num_to_name( - entry_data.type)); + type_num_to_name( + entry_data.type)); return MMDB_INVALID_METADATA_ERROR; } *value = entry_data.uint32; @@ -589,7 +616,7 @@ LOCAL int value_for_key_as_uint32(MMDB_entry_s *start, char *key, } LOCAL int value_for_key_as_uint64(MMDB_entry_s *start, char *key, - uint64_t *value) + uint64_t *value) { MMDB_entry_data_s entry_data; const char *path[] = { key, NULL }; @@ -599,8 +626,8 @@ LOCAL int value_for_key_as_uint64(MMDB_entry_s *start, char *key, } if (MMDB_DATA_TYPE_UINT64 != entry_data.type) { DEBUG_MSGF("expect uint64 for %s but received %s", key, - type_num_to_name( - entry_data.type)); + type_num_to_name( + entry_data.type)); return MMDB_INVALID_METADATA_ERROR; } *value = entry_data.uint64; @@ -608,7 +635,7 @@ LOCAL int value_for_key_as_uint64(MMDB_entry_s *start, char *key, } LOCAL int value_for_key_as_string(MMDB_entry_s *start, char *key, - char const **value) + char const **value) { MMDB_entry_data_s entry_data; const char *path[] = { key, NULL }; @@ -618,8 +645,8 @@ LOCAL int value_for_key_as_string(MMDB_entry_s *start, char *key, } if (MMDB_DATA_TYPE_UTF8_STRING != entry_data.type) { DEBUG_MSGF("expect string for %s but received %s", key, - type_num_to_name( - entry_data.type)); + type_num_to_name( + entry_data.type)); return MMDB_INVALID_METADATA_ERROR; } *value = mmdb_strndup((char *)entry_data.utf8_string, entry_data.data_size); @@ -630,7 +657,7 @@ LOCAL int value_for_key_as_string(MMDB_entry_s *start, char *key, } LOCAL int populate_languages_metadata(MMDB_s *mmdb, MMDB_s *metadata_db, - MMDB_entry_s *metadata_start) + MMDB_entry_s *metadata_start) { MMDB_entry_data_s entry_data; @@ -644,7 +671,7 @@ LOCAL int populate_languages_metadata(MMDB_s *mmdb, MMDB_s *metadata_db, } MMDB_entry_s array_start = { - .mmdb = metadata_db, + .mmdb = metadata_db, .offset = entry_data.offset }; @@ -658,7 +685,7 @@ LOCAL int populate_languages_metadata(MMDB_s *mmdb, MMDB_s *metadata_db, uint32_t array_size = member->entry_data.data_size; MAYBE_CHECK_SIZE_OVERFLOW(array_size, SIZE_MAX / sizeof(char *), - MMDB_INVALID_METADATA_ERROR); + MMDB_INVALID_METADATA_ERROR); mmdb->metadata.languages.count = 0; mmdb->metadata.languages.names = malloc(array_size * sizeof(char *)); @@ -674,7 +701,7 @@ LOCAL int populate_languages_metadata(MMDB_s *mmdb, MMDB_s *metadata_db, mmdb->metadata.languages.names[i] = mmdb_strndup((char *)member->entry_data.utf8_string, - member->entry_data.data_size); + member->entry_data.data_size); if (NULL == mmdb->metadata.languages.names[i]) { return MMDB_OUT_OF_MEMORY_ERROR; @@ -690,7 +717,7 @@ LOCAL int populate_languages_metadata(MMDB_s *mmdb, MMDB_s *metadata_db, } LOCAL int populate_description_metadata(MMDB_s *mmdb, MMDB_s *metadata_db, - MMDB_entry_s *metadata_start) + MMDB_entry_s *metadata_start) { MMDB_entry_data_s entry_data; @@ -706,7 +733,7 @@ LOCAL int populate_description_metadata(MMDB_s *mmdb, MMDB_s *metadata_db, } MMDB_entry_s map_start = { - .mmdb = metadata_db, + .mmdb = metadata_db, .offset = entry_data.offset }; @@ -728,7 +755,7 @@ LOCAL int populate_description_metadata(MMDB_s *mmdb, MMDB_s *metadata_db, goto cleanup; } MAYBE_CHECK_SIZE_OVERFLOW(map_size, SIZE_MAX / sizeof(MMDB_description_s *), - MMDB_INVALID_METADATA_ERROR); + MMDB_INVALID_METADATA_ERROR); mmdb->metadata.description.descriptions = malloc(map_size * sizeof(MMDB_description_s *)); @@ -758,7 +785,7 @@ LOCAL int populate_description_metadata(MMDB_s *mmdb, MMDB_s *metadata_db, mmdb->metadata.description.descriptions[i]->language = mmdb_strndup((char *)member->entry_data.utf8_string, - member->entry_data.data_size); + member->entry_data.data_size); if (NULL == mmdb->metadata.description.descriptions[i]->language) { status = MMDB_OUT_OF_MEMORY_ERROR; @@ -774,7 +801,7 @@ LOCAL int populate_description_metadata(MMDB_s *mmdb, MMDB_s *metadata_db, mmdb->metadata.description.descriptions[i]->description = mmdb_strndup((char *)member->entry_data.utf8_string, - member->entry_data.data_size); + member->entry_data.data_size); if (NULL == mmdb->metadata.description.descriptions[i]->description) { status = MMDB_OUT_OF_MEMORY_ERROR; @@ -782,24 +809,24 @@ LOCAL int populate_description_metadata(MMDB_s *mmdb, MMDB_s *metadata_db, } } - cleanup: +cleanup: MMDB_free_entry_data_list(first_member); return status; } MMDB_lookup_result_s MMDB_lookup_string(MMDB_s *const mmdb, - const char *const ipstr, - int *const gai_error, - int *const mmdb_error) + const char *const ipstr, + int *const gai_error, + int *const mmdb_error) { MMDB_lookup_result_s result = { .found_entry = false, - .netmask = 0, - .entry = { - .mmdb = mmdb, - .offset = 0 - } + .netmask = 0, + .entry = { + .mmdb = mmdb, + .offset = 0 + } }; struct addrinfo *addresses = NULL; @@ -819,8 +846,8 @@ MMDB_lookup_result_s MMDB_lookup_string(MMDB_s *const mmdb, LOCAL int resolve_any_address(const char *ipstr, struct addrinfo **addresses) { struct addrinfo hints = { - .ai_family = AF_UNSPEC, - .ai_flags = AI_NUMERICHOST, + .ai_family = AF_UNSPEC, + .ai_flags = AI_NUMERICHOST, // We set ai_socktype so that we only get one result back .ai_socktype = SOCK_STREAM }; @@ -840,11 +867,11 @@ MMDB_lookup_result_s MMDB_lookup_sockaddr( { MMDB_lookup_result_s result = { .found_entry = false, - .netmask = 0, - .entry = { - .mmdb = mmdb, - .offset = 0 - } + .netmask = 0, + .entry = { + .mmdb = mmdb, + .offset = 0 + } }; uint8_t mapped_address[16], *address; @@ -854,29 +881,31 @@ MMDB_lookup_result_s MMDB_lookup_sockaddr( return result; } address = (uint8_t *)&((struct sockaddr_in *)sockaddr)->sin_addr.s_addr; - } else { + } + else { if (sockaddr->sa_family == AF_INET6) { address = (uint8_t *)&((struct sockaddr_in6 *)sockaddr)->sin6_addr. s6_addr; - } else { + } + else { address = mapped_address; memset(address, 0, 12); memcpy(address + 12, - &((struct sockaddr_in *)sockaddr)->sin_addr.s_addr, 4); + &((struct sockaddr_in *)sockaddr)->sin_addr.s_addr, 4); } } *mmdb_error = find_address_in_search_tree(mmdb, address, sockaddr->sa_family, - &result); + &result); return result; } LOCAL int find_address_in_search_tree(MMDB_s *mmdb, uint8_t *address, - sa_family_t address_family, - MMDB_lookup_result_s *result) + sa_family_t address_family, + MMDB_lookup_result_s *result) { record_info_s record_info = record_info_for_database(mmdb); if (0 == record_info.right_record_offset) { @@ -896,13 +925,13 @@ LOCAL int find_address_in_search_tree(MMDB_s *mmdb, uint8_t *address, return mmdb_error; } DEBUG_MSGF("IPv4 start node is %u (netmask %u)", - mmdb->ipv4_start_node.node_value, - mmdb->ipv4_start_node.netmask); + mmdb->ipv4_start_node.node_value, + mmdb->ipv4_start_node.netmask); uint8_t type = maybe_populate_result(mmdb, - mmdb->ipv4_start_node.node_value, - mmdb->ipv4_start_node.netmask, - result); + mmdb->ipv4_start_node.node_value, + mmdb->ipv4_start_node.netmask, + result); if (MMDB_RECORD_TYPE_INVALID == type) { return MMDB_CORRUPT_SEARCH_TREE_ERROR; } @@ -924,7 +953,7 @@ LOCAL int find_address_in_search_tree(MMDB_s *mmdb, uint8_t *address, & (1U << (~(max_depth0 - current_bit) & 7)) ? 1 : 0; DEBUG_MSGF("Looking at bit %i - bit's value is %i", current_bit, - bit_is_true); + bit_is_true); DEBUG_MSGF(" current node = %u", value); record_pointer = &search_tree[value * record_info.record_length]; @@ -934,11 +963,13 @@ LOCAL int find_address_in_search_tree(MMDB_s *mmdb, uint8_t *address, if (bit_is_true) { record_pointer += record_info.right_record_offset; value = record_info.right_record_getter(record_pointer); - } else { + } + else { value = record_info.left_record_getter(record_pointer); } - uint8_t type = maybe_populate_result(mmdb, value, current_bit, result); + uint8_t type = maybe_populate_result(mmdb, value, (uint16_t)current_bit, + result); if (MMDB_RECORD_TYPE_INVALID == type) { return MMDB_CORRUPT_SEARCH_TREE_ERROR; } @@ -960,7 +991,7 @@ LOCAL int find_address_in_search_tree(MMDB_s *mmdb, uint8_t *address, LOCAL record_info_s record_info_for_database(MMDB_s *mmdb) { record_info_s record_info = { - .record_length = mmdb->full_record_byte_size, + .record_length = mmdb->full_record_byte_size, .right_record_offset = 0 }; @@ -968,15 +999,18 @@ LOCAL record_info_s record_info_for_database(MMDB_s *mmdb) record_info.left_record_getter = &get_uint24; record_info.right_record_getter = &get_uint24; record_info.right_record_offset = 3; - } else if (record_info.record_length == 7) { + } + else if (record_info.record_length == 7) { record_info.left_record_getter = &get_left_28_bit_record; record_info.right_record_getter = &get_right_28_bit_record; record_info.right_record_offset = 3; - } else if (record_info.record_length == 8) { + } + else if (record_info.record_length == 8) { record_info.left_record_getter = &get_uint32; record_info.right_record_getter = &get_uint32; record_info.right_record_offset = 4; - } else { + } + else { assert(false); } @@ -986,8 +1020,8 @@ LOCAL record_info_s record_info_for_database(MMDB_s *mmdb) LOCAL int find_ipv4_start_node(MMDB_s *mmdb) { /* In a pathological case of a database with a single node search tree, - * this check will be true even after we've found the IPv4 start node, but - * that doesn't seem worth trying to fix. */ + * this check will be true even after we've found the IPv4 start node, but + * that doesn't seem worth trying to fix. */ if (mmdb->ipv4_start_node.node_value != 0) { return MMDB_SUCCESS; } @@ -997,7 +1031,7 @@ LOCAL int find_ipv4_start_node(MMDB_s *mmdb) const uint8_t *search_tree = mmdb->file_content; uint32_t node_value = 0; const uint8_t *record_pointer; - uint32_t netmask; + uint16_t netmask; for (netmask = 0; netmask < 96; netmask++) { record_pointer = &search_tree[node_value * record_info.record_length]; if (record_pointer + record_info.record_length > mmdb->data_section) { @@ -1005,7 +1039,7 @@ LOCAL int find_ipv4_start_node(MMDB_s *mmdb) } node_value = record_info.left_record_getter(record_pointer); /* This can happen if there's no IPv4 data _or_ if there is a subnet - * with data that contains the entire IPv4 range (like ::/64) */ + * with data that contains the entire IPv4 range (like ::/64) */ if (node_value >= mmdb->metadata.node_count) { break; } @@ -1017,8 +1051,9 @@ LOCAL int find_ipv4_start_node(MMDB_s *mmdb) return MMDB_SUCCESS; } -LOCAL int maybe_populate_result(MMDB_s *mmdb, uint32_t record, - uint16_t netmask, MMDB_lookup_result_s *result) +LOCAL uint8_t maybe_populate_result(MMDB_s *mmdb, uint32_t record, + uint16_t netmask, + MMDB_lookup_result_s *result) { uint8_t type = record_type(mmdb, record); @@ -1043,8 +1078,8 @@ LOCAL uint8_t record_type(MMDB_s *const mmdb, uint64_t record) uint32_t node_count = mmdb->metadata.node_count; /* Ideally we'd check to make sure that a record never points to a - * previously seen value, but that's more complicated. For now, we can - * at least check that we don't end up at the top of the tree again. */ + * previously seen value, but that's more complicated. For now, we can + * at least check that we don't end up at the top of the tree again. */ if (record == 0) { DEBUG_MSG("record has a value of 0"); return MMDB_RECORD_TYPE_INVALID; @@ -1069,7 +1104,7 @@ LOCAL uint8_t record_type(MMDB_s *const mmdb, uint64_t record) LOCAL uint32_t get_left_28_bit_record(const uint8_t *record) { return record[0] * 65536 + record[1] * 256 + record[2] + - ((record[3] & 0xf0) << 20); + ((record[3] & 0xf0) << 20); } LOCAL uint32_t get_right_28_bit_record(const uint8_t *record) @@ -1079,7 +1114,7 @@ LOCAL uint32_t get_right_28_bit_record(const uint8_t *record) } int MMDB_read_node(MMDB_s *const mmdb, uint32_t node_number, - MMDB_search_node_s *const node) + MMDB_search_node_s *const node) { record_info_s record_info = record_info_for_database(mmdb); if (0 == record_info.right_record_offset) { @@ -1105,25 +1140,26 @@ int MMDB_read_node(MMDB_s *const mmdb, uint32_t node_number, // for other data types is a programming error. node->left_record_entry = (struct MMDB_entry_s) { .mmdb = mmdb, - .offset = data_section_offset_for_record(mmdb, node->left_record), + .offset = data_section_offset_for_record(mmdb, node->left_record), }; node->right_record_entry = (struct MMDB_entry_s) { .mmdb = mmdb, - .offset = data_section_offset_for_record(mmdb, node->right_record), + .offset = data_section_offset_for_record(mmdb, node->right_record), }; return MMDB_SUCCESS; } LOCAL uint32_t data_section_offset_for_record(MMDB_s *const mmdb, - uint64_t record) + uint64_t record) { - return record - mmdb->metadata.node_count - MMDB_DATA_SECTION_SEPARATOR; + return (uint32_t)record - mmdb->metadata.node_count - + MMDB_DATA_SECTION_SEPARATOR; } int MMDB_get_value(MMDB_entry_s *const start, - MMDB_entry_data_s *const entry_data, - ...) + MMDB_entry_data_s *const entry_data, + ...) { va_list path; va_start(path, entry_data); @@ -1133,15 +1169,15 @@ int MMDB_get_value(MMDB_entry_s *const start, } int MMDB_vget_value(MMDB_entry_s *const start, - MMDB_entry_data_s *const entry_data, - va_list va_path) + MMDB_entry_data_s *const entry_data, + va_list va_path) { int length = path_length(va_path); const char *path_elem; int i = 0; MAYBE_CHECK_SIZE_OVERFLOW(length, SIZE_MAX / sizeof(const char *) - 1, - MMDB_INVALID_METADATA_ERROR); + MMDB_INVALID_METADATA_ERROR); const char **path = malloc((length + 1) * sizeof(const char *)); if (NULL == path) { @@ -1178,8 +1214,8 @@ LOCAL int path_length(va_list va_path) } int MMDB_aget_value(MMDB_entry_s *const start, - MMDB_entry_data_s *const entry_data, - const char *const *const path) + MMDB_entry_data_s *const entry_data, + const char *const *const path) { MMDB_s *mmdb = start->mmdb; uint32_t offset = start->offset; @@ -1194,8 +1230,8 @@ int MMDB_aget_value(MMDB_entry_s *const start, DEBUG_MSGF("top level element is a %s", type_num_to_name(entry_data->type)); /* Can this happen? It'd probably represent a pathological case under - * normal use, but there's nothing preventing someone from passing an - * invalid MMDB_entry_s struct to this function */ + * normal use, but there's nothing preventing someone from passing an + * invalid MMDB_entry_s struct to this function */ if (!entry_data->has_data) { return MMDB_INVALID_LOOKUP_PATH_ERROR; } @@ -1207,25 +1243,27 @@ int MMDB_aget_value(MMDB_entry_s *const start, DEBUG_MSGF("path elem = %s", path_elem); /* XXX - it'd be good to find a quicker way to skip through these - entries that doesn't involve decoding them - completely. Basically we need to just use the size from the - control byte to advance our pointer rather than calling - decode_one(). */ + entries that doesn't involve decoding them + completely. Basically we need to just use the size from the + control byte to advance our pointer rather than calling + decode_one(). */ if (entry_data->type == MMDB_DATA_TYPE_ARRAY) { int status = lookup_path_in_array(path_elem, mmdb, entry_data); if (MMDB_SUCCESS != status) { memset(entry_data, 0, sizeof(MMDB_entry_data_s)); return status; } - } else if (entry_data->type == MMDB_DATA_TYPE_MAP) { + } + else if (entry_data->type == MMDB_DATA_TYPE_MAP) { int status = lookup_path_in_map(path_elem, mmdb, entry_data); if (MMDB_SUCCESS != status) { memset(entry_data, 0, sizeof(MMDB_entry_data_s)); return status; } - } else { + } + else { /* Once we make the code traverse maps & arrays without calling - * decode_one() we can get rid of this. */ + * decode_one() we can get rid of this. */ memset(entry_data, 0, sizeof(MMDB_entry_data_s)); return MMDB_LOOKUP_PATH_DOES_NOT_MATCH_DATA_ERROR; } @@ -1235,7 +1273,7 @@ int MMDB_aget_value(MMDB_entry_s *const start, } LOCAL int lookup_path_in_array(const char *path_elem, MMDB_s *mmdb, - MMDB_entry_data_s *entry_data) + MMDB_entry_data_s *entry_data) { uint32_t size = entry_data->data_size; char *first_invalid; @@ -1255,7 +1293,7 @@ LOCAL int lookup_path_in_array(const char *path_elem, MMDB_s *mmdb, for (int i = 0; i < array_index; i++) { /* We don't want to follow a pointer here. If the next element is a - * pointer we simply skip it and keep going */ + * pointer we simply skip it and keep going */ CHECKED_DECODE_ONE(mmdb, entry_data->offset_to_next, entry_data); int status = skip_map_or_array(mmdb, entry_data); if (MMDB_SUCCESS != status) { @@ -1271,7 +1309,7 @@ LOCAL int lookup_path_in_array(const char *path_elem, MMDB_s *mmdb, } LOCAL int lookup_path_in_map(const char *path_elem, MMDB_s *mmdb, - MMDB_entry_data_s *entry_data) + MMDB_entry_data_s *entry_data) { uint32_t size = entry_data->data_size; uint32_t offset = entry_data->offset_to_next; @@ -1295,9 +1333,10 @@ LOCAL int lookup_path_in_map(const char *path_elem, MMDB_s *mmdb, CHECKED_DECODE_ONE_FOLLOW(mmdb, offset_to_value, &value); memcpy(entry_data, &value, sizeof(MMDB_entry_data_s)); return MMDB_SUCCESS; - } else { + } + else { /* We don't want to follow a pointer here. If the next element is - * a pointer we simply skip it and keep going */ + * a pointer we simply skip it and keep going */ CHECKED_DECODE_ONE(mmdb, offset_to_value, &value); int status = skip_map_or_array(mmdb, &value); if (MMDB_SUCCESS != status) { @@ -1323,7 +1362,8 @@ LOCAL int skip_map_or_array(MMDB_s *mmdb, MMDB_entry_data_s *entry_data) return status; } } - } else if (entry_data->type == MMDB_DATA_TYPE_ARRAY) { + } + else if (entry_data->type == MMDB_DATA_TYPE_ARRAY) { uint32_t size = entry_data->data_size; while (size-- > 0) { CHECKED_DECODE_ONE(mmdb, entry_data->offset_to_next, entry_data); // value @@ -1338,7 +1378,7 @@ LOCAL int skip_map_or_array(MMDB_s *mmdb, MMDB_entry_data_s *entry_data) } LOCAL int decode_one_follow(MMDB_s *mmdb, uint32_t offset, - MMDB_entry_data_s *entry_data) + MMDB_entry_data_s *entry_data) { CHECKED_DECODE_ONE(mmdb, offset, entry_data); if (entry_data->type == MMDB_DATA_TYPE_POINTER) { @@ -1351,11 +1391,11 @@ LOCAL int decode_one_follow(MMDB_s *mmdb, uint32_t offset, } /* The pointer could point to any part of the data section but the - * next entry for this particular offset may be the one after the - * pointer, not the one after whatever the pointer points to. This - * depends on whether the pointer points to something that is a simple - * value or a compound value. For a compound value, the next one is - * the one after the pointer result, not the one after the pointer. */ + * next entry for this particular offset may be the one after the + * pointer, not the one after whatever the pointer points to. This + * depends on whether the pointer points to something that is a simple + * value or a compound value. For a compound value, the next one is + * the one after the pointer result, not the one after the pointer. */ if (entry_data->type != MMDB_DATA_TYPE_MAP && entry_data->type != MMDB_DATA_TYPE_ARRAY) { @@ -1379,13 +1419,16 @@ NO_PROTO mmdb_uint128_t get_uint128(const uint8_t *p, int length) #endif LOCAL int decode_one(MMDB_s *mmdb, uint32_t offset, - MMDB_entry_data_s *entry_data) + MMDB_entry_data_s *entry_data) { const uint8_t *mem = mmdb->data_section; - if (offset + 1 > mmdb->data_section_size) { + // We subtract rather than add as it possible that offset + 1 + // could overflow for a corrupt database while an underflow + // from data_section_size - 1 should not be possible. + if (offset > mmdb->data_section_size - 1) { DEBUG_MSGF("Offset (%d) past data section (%d)", offset, - mmdb->data_section_size); + mmdb->data_section_size); return MMDB_INVALID_DATA_ERROR; } @@ -1402,10 +1445,11 @@ LOCAL int decode_one(MMDB_s *mmdb, uint32_t offset, DEBUG_MSGF("Type: %i (%s)", type, type_num_to_name(type)); if (type == MMDB_DATA_TYPE_EXTENDED) { - if (offset + 1 > mmdb->data_section_size) { + // Subtracting 1 to avoid possible overflow on offset + 1 + if (offset > mmdb->data_section_size - 1) { DEBUG_MSGF("Extended type offset (%d) past data section (%d)", - offset, - mmdb->data_section_size); + offset, + mmdb->data_section_size); return MMDB_INVALID_DATA_ERROR; } type = get_ext_type(mem[offset++]); @@ -1415,13 +1459,16 @@ LOCAL int decode_one(MMDB_s *mmdb, uint32_t offset, entry_data->type = type; if (type == MMDB_DATA_TYPE_POINTER) { - int psize = ((ctrl >> 3) & 3) + 1; + uint8_t psize = ((ctrl >> 3) & 3) + 1; DEBUG_MSGF("Pointer size: %i", psize); - if (offset + psize > mmdb->data_section_size) { + // We check that the offset does not extend past the end of the + // database and that the subtraction of psize did not underflow. + if (offset > mmdb->data_section_size - psize || + mmdb->data_section_size < psize) { DEBUG_MSGF("Pointer offset (%d) past data section (%d)", offset + - psize, - mmdb->data_section_size); + psize, + mmdb->data_section_size); return MMDB_INVALID_DATA_ERROR; } entry_data->pointer = get_ptr_from(ctrl, &mem[offset], psize); @@ -1435,29 +1482,32 @@ LOCAL int decode_one(MMDB_s *mmdb, uint32_t offset, uint32_t size = ctrl & 31; switch (size) { case 29: - if (offset + 1 > mmdb->data_section_size) { + // We subtract when checking offset to avoid possible overflow + if (offset > mmdb->data_section_size - 1) { DEBUG_MSGF("String end (%d, case 29) past data section (%d)", - offset, - mmdb->data_section_size); + offset, + mmdb->data_section_size); return MMDB_INVALID_DATA_ERROR; } size = 29 + mem[offset++]; break; case 30: - if (offset + 2 > mmdb->data_section_size) { + // We subtract when checking offset to avoid possible overflow + if (offset > mmdb->data_section_size - 2) { DEBUG_MSGF("String end (%d, case 30) past data section (%d)", - offset, - mmdb->data_section_size); + offset, + mmdb->data_section_size); return MMDB_INVALID_DATA_ERROR; } size = 285 + get_uint16(&mem[offset]); offset += 2; break; case 31: - if (offset + 3 > mmdb->data_section_size) { + // We subtract when checking offset to avoid possible overflow + if (offset > mmdb->data_section_size - 3) { DEBUG_MSGF("String end (%d, case 31) past data section (%d)", - offset, - mmdb->data_section_size); + offset, + mmdb->data_section_size); return MMDB_INVALID_DATA_ERROR; } size = 65821 + get_uint24(&mem[offset]); @@ -1482,11 +1532,12 @@ LOCAL int decode_one(MMDB_s *mmdb, uint32_t offset, return MMDB_SUCCESS; } - // check that the data doesn't extend past the end of the memory - // buffer - if (offset + size > mmdb->data_section_size) { + // Check that the data doesn't extend past the end of the memory + // buffer and that the calculation in doing this did not underflow. + if (offset > mmdb->data_section_size - size || + mmdb->data_section_size < size) { DEBUG_MSGF("Data end (%d) past data section (%d)", offset + size, - mmdb->data_section_size); + mmdb->data_section_size); return MMDB_INVALID_DATA_ERROR; } @@ -1497,28 +1548,32 @@ LOCAL int decode_one(MMDB_s *mmdb, uint32_t offset, } entry_data->uint16 = (uint16_t)get_uintX(&mem[offset], size); DEBUG_MSGF("uint16 value: %u", entry_data->uint16); - } else if (type == MMDB_DATA_TYPE_UINT32) { + } + else if (type == MMDB_DATA_TYPE_UINT32) { if (size > 4) { DEBUG_MSGF("uint32 of size %d", size); return MMDB_INVALID_DATA_ERROR; } entry_data->uint32 = (uint32_t)get_uintX(&mem[offset], size); DEBUG_MSGF("uint32 value: %u", entry_data->uint32); - } else if (type == MMDB_DATA_TYPE_INT32) { + } + else if (type == MMDB_DATA_TYPE_INT32) { if (size > 4) { DEBUG_MSGF("int32 of size %d", size); return MMDB_INVALID_DATA_ERROR; } entry_data->int32 = get_sintX(&mem[offset], size); DEBUG_MSGF("int32 value: %i", entry_data->int32); - } else if (type == MMDB_DATA_TYPE_UINT64) { + } + else if (type == MMDB_DATA_TYPE_UINT64) { if (size > 8) { DEBUG_MSGF("uint64 of size %d", size); return MMDB_INVALID_DATA_ERROR; } entry_data->uint64 = get_uintX(&mem[offset], size); DEBUG_MSGF("uint64 value: %" PRIu64, entry_data->uint64); - } else if (type == MMDB_DATA_TYPE_UINT128) { + } + else if (type == MMDB_DATA_TYPE_UINT128) { if (size > 16) { DEBUG_MSGF("uint128 of size %d", size); return MMDB_INVALID_DATA_ERROR; @@ -1531,7 +1586,8 @@ LOCAL int decode_one(MMDB_s *mmdb, uint32_t offset, #else entry_data->uint128 = get_uint128(&mem[offset], size); #endif - } else if (type == MMDB_DATA_TYPE_FLOAT) { + } + else if (type == MMDB_DATA_TYPE_FLOAT) { if (size != 4) { DEBUG_MSGF("float of size %d", size); return MMDB_INVALID_DATA_ERROR; @@ -1539,7 +1595,8 @@ LOCAL int decode_one(MMDB_s *mmdb, uint32_t offset, size = 4; entry_data->float_value = get_ieee754_float(&mem[offset]); DEBUG_MSGF("float value: %f", entry_data->float_value); - } else if (type == MMDB_DATA_TYPE_DOUBLE) { + } + else if (type == MMDB_DATA_TYPE_DOUBLE) { if (size != 8) { DEBUG_MSGF("double of size %d", size); return MMDB_INVALID_DATA_ERROR; @@ -1547,19 +1604,21 @@ LOCAL int decode_one(MMDB_s *mmdb, uint32_t offset, size = 8; entry_data->double_value = get_ieee754_double(&mem[offset]); DEBUG_MSGF("double value: %f", entry_data->double_value); - } else if (type == MMDB_DATA_TYPE_UTF8_STRING) { + } + else if (type == MMDB_DATA_TYPE_UTF8_STRING) { entry_data->utf8_string = size == 0 ? "" : (char *)&mem[offset]; entry_data->data_size = size; #ifdef MMDB_DEBUG char *string = mmdb_strndup(entry_data->utf8_string, - size > 50 ? 50 : size); + size > 50 ? 50 : size); if (NULL == string) { abort(); } DEBUG_MSGF("string value: %s", string); free(string); #endif - } else if (type == MMDB_DATA_TYPE_BYTES) { + } + else if (type == MMDB_DATA_TYPE_BYTES) { entry_data->bytes = &mem[offset]; entry_data->data_size = size; } @@ -1575,18 +1634,18 @@ LOCAL int get_ext_type(int raw_ext_type) } LOCAL uint32_t get_ptr_from(uint8_t ctrl, uint8_t const *const ptr, - int ptr_size) + int ptr_size) { uint32_t new_offset; switch (ptr_size) { case 1: - new_offset = ( (ctrl & 7) << 8) + ptr[0]; + new_offset = ((ctrl & 7) << 8) + ptr[0]; break; case 2: - new_offset = 2048 + ( (ctrl & 7) << 16 ) + ( ptr[0] << 8) + ptr[1]; + new_offset = 2048 + ((ctrl & 7) << 16) + (ptr[0] << 8) + ptr[1]; break; case 3: - new_offset = 2048 + 524288 + ( (ctrl & 7) << 24 ) + get_uint24(ptr); + new_offset = 2048 + 524288 + ((ctrl & 7) << 24) + get_uint24(ptr); break; case 4: default: @@ -1602,7 +1661,7 @@ int MMDB_get_metadata_as_entry_data_list( MMDB_s metadata_db = make_fake_metadata_db(mmdb); MMDB_entry_s metadata_start = { - .mmdb = &metadata_db, + .mmdb = &metadata_db, .offset = 0 }; @@ -1612,16 +1671,34 @@ int MMDB_get_metadata_as_entry_data_list( int MMDB_get_entry_data_list( MMDB_entry_s *start, MMDB_entry_data_list_s **const entry_data_list) { - *entry_data_list = new_entry_data_list(); - if (NULL == *entry_data_list) { + MMDB_data_pool_s *const pool = data_pool_new(MMDB_POOL_INIT_SIZE); + if (!pool) { + return MMDB_OUT_OF_MEMORY_ERROR; + } + + MMDB_entry_data_list_s *const list = data_pool_alloc(pool); + if (!list) { + data_pool_destroy(pool); + return MMDB_OUT_OF_MEMORY_ERROR; + } + + int const status = get_entry_data_list(start->mmdb, start->offset, list, + pool, 0); + + *entry_data_list = data_pool_to_list(pool); + if (!*entry_data_list) { + data_pool_destroy(pool); return MMDB_OUT_OF_MEMORY_ERROR; } - return get_entry_data_list(start->mmdb, start->offset, *entry_data_list, 0); + + return status; } -LOCAL int get_entry_data_list(MMDB_s *mmdb, uint32_t offset, - MMDB_entry_data_list_s *const entry_data_list, - int depth) +LOCAL int get_entry_data_list(MMDB_s *mmdb, + uint32_t offset, + MMDB_entry_data_list_s *const entry_data_list, + MMDB_data_pool_s *const pool, + int depth) { if (depth >= MAXIMUM_DATA_STRUCTURE_DEPTH) { DEBUG_MSG("reached the maximum data structure depth"); @@ -1636,8 +1713,8 @@ LOCAL int get_entry_data_list(MMDB_s *mmdb, uint32_t offset, uint32_t next_offset = entry_data_list->entry_data.offset_to_next; uint32_t last_offset; CHECKED_DECODE_ONE(mmdb, last_offset = - entry_data_list->entry_data.pointer, - &entry_data_list->entry_data); + entry_data_list->entry_data.pointer, + &entry_data_list->entry_data); /* Pointers to pointers are illegal under the spec */ if (entry_data_list->entry_data.type == MMDB_DATA_TYPE_POINTER) { @@ -1650,7 +1727,7 @@ LOCAL int get_entry_data_list(MMDB_s *mmdb, uint32_t offset, int status = get_entry_data_list(mmdb, last_offset, entry_data_list, - depth); + pool, depth); if (MMDB_SUCCESS != status) { DEBUG_MSG("get_entry_data_list on pointer failed."); return status; @@ -1663,26 +1740,22 @@ LOCAL int get_entry_data_list(MMDB_s *mmdb, uint32_t offset, { uint32_t array_size = entry_data_list->entry_data.data_size; uint32_t array_offset = entry_data_list->entry_data.offset_to_next; - MMDB_entry_data_list_s *previous = entry_data_list; while (array_size-- > 0) { - MMDB_entry_data_list_s *entry_data_list_to = previous->next = - new_entry_data_list(); - if (NULL == entry_data_list_to) { + MMDB_entry_data_list_s *entry_data_list_to = + data_pool_alloc(pool); + if (!entry_data_list_to) { return MMDB_OUT_OF_MEMORY_ERROR; } int status = get_entry_data_list(mmdb, array_offset, entry_data_list_to, - depth); + pool, depth); if (MMDB_SUCCESS != status) { DEBUG_MSG("get_entry_data_list on array element failed."); return status; } array_offset = entry_data_list_to->entry_data.offset_to_next; - while (previous->next) { - previous = previous->next; - } } entry_data_list->entry_data.offset_to_next = array_offset; @@ -1693,45 +1766,33 @@ LOCAL int get_entry_data_list(MMDB_s *mmdb, uint32_t offset, uint32_t size = entry_data_list->entry_data.data_size; offset = entry_data_list->entry_data.offset_to_next; - MMDB_entry_data_list_s *previous = entry_data_list; while (size-- > 0) { - MMDB_entry_data_list_s *entry_data_list_to = previous->next = - new_entry_data_list(); - if (NULL == entry_data_list_to) { + MMDB_entry_data_list_s *list_key = data_pool_alloc(pool); + if (!list_key) { return MMDB_OUT_OF_MEMORY_ERROR; } int status = - get_entry_data_list(mmdb, offset, entry_data_list_to, - depth); + get_entry_data_list(mmdb, offset, list_key, pool, depth); if (MMDB_SUCCESS != status) { DEBUG_MSG("get_entry_data_list on map key failed."); return status; } - while (previous->next) { - previous = previous->next; - } - - offset = entry_data_list_to->entry_data.offset_to_next; - entry_data_list_to = previous->next = - new_entry_data_list(); + offset = list_key->entry_data.offset_to_next; - if (NULL == entry_data_list_to) { + MMDB_entry_data_list_s *list_value = data_pool_alloc(pool); + if (!list_value) { return MMDB_OUT_OF_MEMORY_ERROR; } - status = get_entry_data_list(mmdb, offset, entry_data_list_to, - depth); + status = get_entry_data_list(mmdb, offset, list_value, pool, + depth); if (MMDB_SUCCESS != status) { DEBUG_MSG("get_entry_data_list on map element failed."); return status; } - - while (previous->next) { - previous = previous->next; - } - offset = entry_data_list_to->entry_data.offset_to_next; + offset = list_value->entry_data.offset_to_next; } entry_data_list->entry_data.offset_to_next = offset; } @@ -1747,7 +1808,9 @@ LOCAL float get_ieee754_float(const uint8_t *restrict p) { volatile float f; uint8_t *q = (void *)&f; -#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + /* Windows builds don't use autoconf but we can assume they're all + * little-endian. */ +#if MMDB_LITTLE_ENDIAN || _WIN32 q[3] = p[0]; q[2] = p[1]; q[1] = p[2]; @@ -1762,7 +1825,7 @@ LOCAL double get_ieee754_double(const uint8_t *restrict p) { volatile double d; uint8_t *q = (void *)&d; -#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +#if MMDB_LITTLE_ENDIAN || _WIN32 q[7] = p[0]; q[6] = p[1]; q[5] = p[2]; @@ -1808,22 +1871,12 @@ LOCAL int32_t get_sintX(const uint8_t *p, int length) return (int32_t)get_uintX(p, length); } -LOCAL MMDB_entry_data_list_s *new_entry_data_list(void) -{ - /* We need calloc here in order to ensure that the ->next pointer in the - * struct doesn't point to some random address. */ - return calloc(1, sizeof(MMDB_entry_data_list_s)); -} - void MMDB_free_entry_data_list(MMDB_entry_data_list_s *const entry_data_list) { if (entry_data_list == NULL) { return; } - if (entry_data_list->next) { - MMDB_free_entry_data_list(entry_data_list->next); - } - free(entry_data_list); + data_pool_destroy(entry_data_list->pool); } void MMDB_close(MMDB_s *const mmdb) @@ -1844,7 +1897,7 @@ LOCAL void free_mmdb_struct(MMDB_s *const mmdb) #ifdef _WIN32 UnmapViewOfFile(mmdb->file_content); /* Winsock is only initialized if open was successful so we only have - * to cleanup then. */ + * to cleanup then. */ //WSACleanup(); // dmex: disabled since hostname lookup is not used. #else munmap((void *)mmdb->file_content, mmdb->file_size); @@ -1903,8 +1956,8 @@ const char *MMDB_lib_version(void) } int MMDB_dump_entry_data_list(FILE *const stream, - MMDB_entry_data_list_s *const entry_data_list, - int indent) + MMDB_entry_data_list_s *const entry_data_list, + int indent) { int status; dump_entry_data_list(stream, entry_data_list, indent, &status); @@ -1925,7 +1978,7 @@ LOCAL MMDB_entry_data_list_s *dump_entry_data_list( indent += 2; for (entry_data_list = entry_data_list->next; - size && entry_data_list; size--) { + size && entry_data_list; size--) { if (MMDB_DATA_TYPE_UTF8_STRING != entry_data_list->entry_data.type) { @@ -1934,7 +1987,7 @@ LOCAL MMDB_entry_data_list_s *dump_entry_data_list( } char *key = mmdb_strndup( - (char *)entry_data_list->entry_data.utf8_string, + (char *)entry_data_list->entry_data.utf8_string, entry_data_list->entry_data.data_size); if (NULL == key) { *status = MMDB_OUT_OF_MEMORY_ERROR; @@ -1948,7 +2001,7 @@ LOCAL MMDB_entry_data_list_s *dump_entry_data_list( entry_data_list = entry_data_list->next; entry_data_list = dump_entry_data_list(stream, entry_data_list, indent + 2, - status); + status); if (MMDB_SUCCESS != *status) { return NULL; @@ -1969,10 +2022,10 @@ LOCAL MMDB_entry_data_list_s *dump_entry_data_list( indent += 2; for (entry_data_list = entry_data_list->next; - size && entry_data_list; size--) { + size && entry_data_list; size--) { entry_data_list = dump_entry_data_list(stream, entry_data_list, indent, - status); + status); if (MMDB_SUCCESS != *status) { return NULL; } @@ -1987,7 +2040,7 @@ LOCAL MMDB_entry_data_list_s *dump_entry_data_list( { char *string = mmdb_strndup((char *)entry_data_list->entry_data.utf8_string, - entry_data_list->entry_data.data_size); + entry_data_list->entry_data.data_size); if (NULL == string) { *status = MMDB_OUT_OF_MEMORY_ERROR; return NULL; @@ -2002,7 +2055,7 @@ LOCAL MMDB_entry_data_list_s *dump_entry_data_list( { char *hex_string = bytes_to_hex((uint8_t *)entry_data_list->entry_data.bytes, - entry_data_list->entry_data.data_size); + entry_data_list->entry_data.data_size); if (NULL == hex_string) { *status = MMDB_OUT_OF_MEMORY_ERROR; return NULL; @@ -2018,13 +2071,13 @@ LOCAL MMDB_entry_data_list_s *dump_entry_data_list( case MMDB_DATA_TYPE_DOUBLE: print_indentation(stream, indent); fprintf(stream, "%f \n", - entry_data_list->entry_data.double_value); + entry_data_list->entry_data.double_value); entry_data_list = entry_data_list->next; break; case MMDB_DATA_TYPE_FLOAT: print_indentation(stream, indent); fprintf(stream, "%f \n", - entry_data_list->entry_data.float_value); + entry_data_list->entry_data.float_value); entry_data_list = entry_data_list->next; break; case MMDB_DATA_TYPE_UINT16: @@ -2040,13 +2093,13 @@ LOCAL MMDB_entry_data_list_s *dump_entry_data_list( case MMDB_DATA_TYPE_BOOLEAN: print_indentation(stream, indent); fprintf(stream, "%s \n", - entry_data_list->entry_data.boolean ? "true" : "false"); + entry_data_list->entry_data.boolean ? "true" : "false"); entry_data_list = entry_data_list->next; break; case MMDB_DATA_TYPE_UINT64: print_indentation(stream, indent); fprintf(stream, "%" PRIu64 " \n", - entry_data_list->entry_data.uint64); + entry_data_list->entry_data.uint64); entry_data_list = entry_data_list->next; break; case MMDB_DATA_TYPE_UINT128: @@ -2064,7 +2117,7 @@ LOCAL MMDB_entry_data_list_s *dump_entry_data_list( uint64_t high = entry_data_list->entry_data.uint128 >> 64; uint64_t low = (uint64_t)entry_data_list->entry_data.uint128; fprintf(stream, "0x%016" PRIX64 "%016" PRIX64 " \n", high, - low); + low); #endif entry_data_list = entry_data_list->next; break; @@ -2091,6 +2144,8 @@ LOCAL void print_indentation(FILE *stream, int i) fputs(buffer, stream); } +#pragma warning(push) +#pragma warning(disable : 4996) LOCAL char *bytes_to_hex(uint8_t *bytes, uint32_t size) { char *hex_string; @@ -2101,17 +2156,13 @@ LOCAL char *bytes_to_hex(uint8_t *bytes, uint32_t size) return NULL; } - for (uint32_t i = 0; i < size; i++) - { - sprintf_s( - hex_string + (2 * i), - (size * 2) + 1, - "%02X", bytes[i] - ); + for (uint32_t i = 0; i < size; i++) { + sprintf(hex_string + (2 * i), "%02X", bytes[i]); } return hex_string; } +#pragma warning(pop) const char *MMDB_strerror(int error_code) { @@ -2150,5 +2201,3 @@ const char *MMDB_strerror(int error_code) return "Unknown error code"; } } - -#pragma warning(pop) \ No newline at end of file diff --git a/plugins/NetworkTools/maxminddb/maxminddb.h b/plugins/NetworkTools/maxminddb/maxminddb.h index 1dc6e37d5869..0978b05b5d95 100644 --- a/plugins/NetworkTools/maxminddb/maxminddb.h +++ b/plugins/NetworkTools/maxminddb/maxminddb.h @@ -5,8 +5,16 @@ extern "C" { #ifndef MAXMINDDB_H #define MAXMINDDB_H +/* Request POSIX.1-2008. However, we want to remain compatible with + * POSIX.1-2001 (since we have been historically and see no reason to drop + * compatibility). By requesting POSIX.1-2008, we can conditionally use + * features provided by that standard if the implementation provides it. We can + * check for what the implementation provides by checking the _POSIX_VERSION + * macro after including unistd.h. If a feature is in POSIX.1-2008 but not + * POSIX.1-2001, check that macro before using the feature (or check for the + * feature directly if possible). */ #ifndef _POSIX_C_SOURCE -#define _POSIX_C_SOURCE 200112L +#define _POSIX_C_SOURCE 200809L #endif #include "maxminddb_config.h" @@ -20,13 +28,13 @@ extern "C" { #include #include /* libmaxminddb package version from configure */ -#define PACKAGE_VERSION "1.2.0" +#define PACKAGE_VERSION "1.3.2" typedef ADDRESS_FAMILY sa_family_t; #if defined(_MSC_VER) /* MSVC doesn't define signed size_t, copy it from configure */ -#define ssize_t int +#define ssize_t SSIZE_T /* MSVC doesn't support restricted pointers */ #define restrict @@ -135,6 +143,7 @@ typedef struct MMDB_entry_data_s { typedef struct MMDB_entry_data_list_s { MMDB_entry_data_s entry_data; struct MMDB_entry_data_list_s *next; + void *pool; } MMDB_entry_data_list_s; typedef struct MMDB_description_s { @@ -167,7 +176,7 @@ typedef struct MMDB_ipv4_start_node_s { typedef struct MMDB_s { uint32_t flags; - const wchar_t* filename; + const wchar_t *filename; ssize_t file_size; const uint8_t *file_content; const uint8_t *data_section; diff --git a/plugins/NetworkTools/nettools.h b/plugins/NetworkTools/nettools.h index d1bac10f2ec7..6a93a587b751 100644 --- a/plugins/NetworkTools/nettools.h +++ b/plugins/NetworkTools/nettools.h @@ -229,7 +229,7 @@ typedef struct _NETWORK_EXTENSION }; }; - HICON CountryIcon; + INT CountryIconIndex; PPH_STRING LocalServiceName; PPH_STRING RemoteServiceName; PPH_STRING RemoteCountryCode; @@ -280,10 +280,16 @@ BOOLEAN LookupSockInAddr6CountryCode( _Out_ PPH_STRING *CountryName ); -HICON LookupCountryIcon( +INT LookupCountryIcon( _In_ PPH_STRING Name ); +VOID DrawCountryIcon( + _In_ HDC hdc, + _In_ RECT rect, + _In_ INT Index + ); + typedef struct _PH_UPDATER_CONTEXT { BOOLEAN FixedWindowStyles; diff --git a/plugins/NetworkTools/tracert.h b/plugins/NetworkTools/tracert.h index 843ef15ad83f..44bfb38c1783 100644 --- a/plugins/NetworkTools/tracert.h +++ b/plugins/NetworkTools/tracert.h @@ -53,7 +53,7 @@ typedef struct _TRACERT_ROOT_NODE ULONG PingList[DEFAULT_MAXIMUM_PINGS]; PPH_STRING PingString[DEFAULT_MAXIMUM_PINGS]; - HICON CountryIcon; + INT CountryIconIndex; PPH_STRING TtlString; PPH_STRING CountryString; diff --git a/plugins/NetworkTools/tracetree.c b/plugins/NetworkTools/tracetree.c index bd18a98fc385..aafa7a7664b0 100644 --- a/plugins/NetworkTools/tracetree.c +++ b/plugins/NetworkTools/tracetree.c @@ -67,6 +67,8 @@ PTRACERT_ROOT_NODE TracertTreeCreateNode( PhInitializeTreeNewNode(&tracertNode->Node); + tracertNode->CountryIconIndex = INT_MAX; + return tracertNode; } @@ -469,43 +471,33 @@ BOOLEAN NTAPI TracertTreeNewCallback( // Draw the column data if (GeoDbLoaded && !GeoDbExpired && node->RemoteCountryCode && node->RemoteCountryName) { - if (!node->CountryIcon) - node->CountryIcon = LookupCountryIcon(node->RemoteCountryCode); + if (node->CountryIconIndex == INT_MAX) + node->CountryIconIndex = LookupCountryIcon(node->RemoteCountryCode); - if (node->CountryIcon) + if (node->CountryIconIndex != INT_MAX) { - DrawIconEx( - hdc, - rect.left, - rect.top + ((rect.bottom - rect.top) - 11) / 2, - node->CountryIcon, - 16, - 11, - 0, - NULL, - DI_NORMAL - ); + DrawCountryIcon(hdc, rect, node->CountryIconIndex); rect.left += 16 + 2; } DrawText( hdc, - PhGetStringOrEmpty(node->RemoteCountryName), - -1, + node->RemoteCountryName->Buffer, + (INT)node->RemoteCountryName->Length / sizeof(WCHAR), &rect, - DT_LEFT | DT_VCENTER | DT_SINGLELINE + DT_LEFT | DT_VCENTER | DT_END_ELLIPSIS | DT_SINGLELINE ); } if (GeoDbExpired) { - DrawText(hdc, L"Geoip database expired.", -1, &rect, DT_LEFT | DT_VCENTER | DT_SINGLELINE); + DrawText(hdc, L"Geoip database expired.", -1, &rect, DT_LEFT | DT_VCENTER | DT_END_ELLIPSIS | DT_SINGLELINE); } if (!GeoDbLoaded) { - DrawText(hdc, L"Geoip database error.", -1, &rect, DT_LEFT | DT_VCENTER | DT_SINGLELINE); + DrawText(hdc, L"Geoip database error.", -1, &rect, DT_LEFT | DT_VCENTER | DT_END_ELLIPSIS | DT_SINGLELINE); } } break; From 78a7892b63d29698c777c4a13b24492f916f32ff Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 29 May 2018 01:46:31 +1000 Subject: [PATCH 0989/2058] Ignore copying text from empty columns --- phlib/cpysave.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/phlib/cpysave.c b/phlib/cpysave.c index 9c250999ef65..167f4215a3ae 100644 --- a/phlib/cpysave.c +++ b/phlib/cpysave.c @@ -320,8 +320,12 @@ PPH_STRING PhGetTreeNewText( PhInitializeEmptyStringRef(&getCellText.Text); TreeNew_GetCellText(TreeNewHandle, &getCellText); - PhAppendStringBuilder(&stringBuilder, &getCellText.Text); - PhAppendStringBuilder2(&stringBuilder, L", "); + // Ignore empty columns. -dmex + if (getCellText.Text.Length != 0) + { + PhAppendStringBuilder(&stringBuilder, &getCellText.Text); + PhAppendStringBuilder2(&stringBuilder, L", "); + } } // Remove the trailing comma and space. From aa60c3c77b19369587811fcd42b846e15e46d627 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 29 May 2018 01:49:09 +1000 Subject: [PATCH 0990/2058] NetworkTools: Fix tracert country sorting --- plugins/NetworkTools/country.c | 288 ++++++++++++++----------------- plugins/NetworkTools/tracert.c | 6 +- plugins/NetworkTools/tracert.h | 3 - plugins/NetworkTools/tracetree.c | 24 ++- 4 files changed, 146 insertions(+), 175 deletions(-) diff --git a/plugins/NetworkTools/country.c b/plugins/NetworkTools/country.c index 52cf51900e6b..b1db05f2f499 100644 --- a/plugins/NetworkTools/country.c +++ b/plugins/NetworkTools/country.c @@ -85,15 +85,128 @@ VOID FreeGeoLiteDb( } } -BOOLEAN LookupCountryCode( - _In_ PH_IP_ADDRESS RemoteAddress, +BOOLEAN GeoDbGetCityData( + _In_ MMDB_entry_s* GeoDbEntry, + _Out_ DOUBLE *CityLatitude, + _Out_ DOUBLE *CityLongitude + ) +{ + MMDB_entry_data_s mmdb_entry; + DOUBLE cityLatitude = 0.0; + DOUBLE cityLongitude = 0.0; + + if (MMDB_get_value(GeoDbEntry, &mmdb_entry, "location", "latitude", NULL) == MMDB_SUCCESS) + { + if (mmdb_entry.has_data && mmdb_entry.type == MMDB_DATA_TYPE_DOUBLE) + { + cityLatitude = mmdb_entry.double_value; + } + } + + if (MMDB_get_value(GeoDbEntry, &mmdb_entry, "location", "longitude", NULL) == MMDB_SUCCESS) + { + if (mmdb_entry.has_data && mmdb_entry.type == MMDB_DATA_TYPE_DOUBLE) + { + cityLongitude = mmdb_entry.double_value; + } + } + + if (cityLatitude && cityLongitude) + { + *CityLatitude = cityLatitude; + *CityLongitude = cityLongitude; + return TRUE; + } + + return FALSE; +} + +BOOLEAN GeoDbGetCountryData( + _In_ MMDB_entry_s* GeoDbEntry, _Out_ PPH_STRING *CountryCode, _Out_ PPH_STRING *CountryName ) { + MMDB_entry_data_s mmdb_entry; PPH_STRING countryCode = NULL; PPH_STRING countryName = NULL; + + if (MMDB_get_value(GeoDbEntry, &mmdb_entry, "country", "iso_code", NULL) == MMDB_SUCCESS) + { + if (mmdb_entry.has_data && mmdb_entry.type == MMDB_DATA_TYPE_UTF8_STRING) + { + countryCode = PhConvertUtf8ToUtf16Ex((PCHAR)mmdb_entry.utf8_string, mmdb_entry.data_size); + } + } + + if (MMDB_get_value(GeoDbEntry, &mmdb_entry, "country", "names", "en", NULL) == MMDB_SUCCESS) + { + if (mmdb_entry.has_data && mmdb_entry.type == MMDB_DATA_TYPE_UTF8_STRING) + { + countryName = PhConvertUtf8ToUtf16Ex((PCHAR)mmdb_entry.utf8_string, mmdb_entry.data_size); + } + } + + if (countryCode && countryName) + { + *CountryCode = countryCode; + *CountryName = countryName; + return TRUE; + } + + if (countryCode) + PhDereferenceObject(countryCode); + if (countryName) + PhDereferenceObject(countryName); + return FALSE; +} + +BOOLEAN GeoDbGetContinentData( + _In_ MMDB_entry_s* GeoDbEntry, + _Out_ PPH_STRING *ContinentCode, + _Out_ PPH_STRING *ContinentName + ) +{ MMDB_entry_data_s mmdb_entry; + PPH_STRING continentCode = NULL; + PPH_STRING continentName = NULL; + + if (MMDB_get_value(GeoDbEntry, &mmdb_entry, "continent", "code", NULL) == MMDB_SUCCESS) + { + if (mmdb_entry.has_data && mmdb_entry.type == MMDB_DATA_TYPE_UTF8_STRING) + { + continentCode = PhConvertUtf8ToUtf16Ex((PCHAR)mmdb_entry.utf8_string, mmdb_entry.data_size); + } + } + + if (MMDB_get_value(GeoDbEntry, &mmdb_entry, "country", "names", "en", NULL) == MMDB_SUCCESS) + { + if (mmdb_entry.has_data && mmdb_entry.type == MMDB_DATA_TYPE_UTF8_STRING) + { + continentName = PhConvertUtf8ToUtf16Ex((PCHAR)mmdb_entry.utf8_string, mmdb_entry.data_size); + } + } + + if (continentCode && continentName) + { + *ContinentCode = continentCode; + *ContinentName = continentName; + return TRUE; + } + + if (continentCode) + PhDereferenceObject(continentCode); + if (continentName) + PhDereferenceObject(continentName); + return FALSE; +} + +BOOLEAN LookupCountryCode( + _In_ PH_IP_ADDRESS RemoteAddress, + _Out_ PPH_STRING *CountryCode, + _Out_ PPH_STRING *CountryName + ) +{ MMDB_lookup_result_s mmdb_result; INT mmdb_error = 0; @@ -147,56 +260,13 @@ BOOLEAN LookupCountryCode( if (mmdb_error == 0 && mmdb_result.found_entry) { - memset(&mmdb_entry, 0, sizeof(MMDB_entry_data_s)); - - if (MMDB_get_value(&mmdb_result.entry, &mmdb_entry, "country", "iso_code", NULL) == MMDB_SUCCESS) - { - if (mmdb_entry.has_data && mmdb_entry.type == MMDB_DATA_TYPE_UTF8_STRING) - { - countryCode = PhConvertUtf8ToUtf16Ex((PCHAR)mmdb_entry.utf8_string, mmdb_entry.data_size); - } - } - - if (MMDB_get_value(&mmdb_result.entry, &mmdb_entry, "country", "names", "en", NULL) == MMDB_SUCCESS) - { - if (mmdb_entry.has_data && mmdb_entry.type == MMDB_DATA_TYPE_UTF8_STRING) - { - countryName = PhConvertUtf8ToUtf16Ex((PCHAR)mmdb_entry.utf8_string, mmdb_entry.data_size); - } - } - - //if (MMDB_get_value(&mmdb_result.entry, &mmdb_entry, "location", "latitude", NULL) == MMDB_SUCCESS) - //{ - // if (mmdb_entry.has_data && mmdb_entry.type == MMDB_DATA_TYPE_DOUBLE) - // { - // *CityLatitude = mmdb_entry.double_value; - // } - //} - - //if (MMDB_get_value(&mmdb_result.entry, &mmdb_entry, "location", "longitude", NULL) == MMDB_SUCCESS) - //{ - // if (mmdb_entry.has_data && mmdb_entry.type == MMDB_DATA_TYPE_DOUBLE) - // { - // *CityLongitude = mmdb_entry.double_value; - // } - //} - } - - if (countryCode && countryName) - { - *CountryCode = countryCode; - *CountryName = countryName; - return TRUE; - } - - if (countryCode) - { - PhDereferenceObject(countryCode); - } + if (GeoDbGetCountryData(&mmdb_result.entry, CountryCode, CountryName)) + return TRUE; - if (countryName) - { - PhDereferenceObject(countryName); + // HACK + // We can sometimes get the continent even when the address doesn't have a country. + if (GeoDbGetContinentData(&mmdb_result.entry, CountryCode, CountryName)) + return TRUE; } return FALSE; @@ -208,9 +278,6 @@ BOOLEAN LookupSockInAddr4CountryCode( _Out_ PPH_STRING *CountryName ) { - PPH_STRING countryCode = NULL; - PPH_STRING countryName = NULL; - MMDB_entry_data_s mmdb_entry; MMDB_lookup_result_s mmdb_result; SOCKADDR_IN ipv4SockAddr; INT mmdb_error = 0; @@ -238,56 +305,13 @@ BOOLEAN LookupSockInAddr4CountryCode( if (mmdb_error == 0 && mmdb_result.found_entry) { - memset(&mmdb_entry, 0, sizeof(MMDB_entry_data_s)); - - if (MMDB_get_value(&mmdb_result.entry, &mmdb_entry, "country", "iso_code", NULL) == MMDB_SUCCESS) - { - if (mmdb_entry.has_data && mmdb_entry.type == MMDB_DATA_TYPE_UTF8_STRING) - { - countryCode = PhConvertUtf8ToUtf16Ex((PCHAR)mmdb_entry.utf8_string, mmdb_entry.data_size); - } - } - - if (MMDB_get_value(&mmdb_result.entry, &mmdb_entry, "country", "names", "en", NULL) == MMDB_SUCCESS) - { - if (mmdb_entry.has_data && mmdb_entry.type == MMDB_DATA_TYPE_UTF8_STRING) - { - countryName = PhConvertUtf8ToUtf16Ex((PCHAR)mmdb_entry.utf8_string, mmdb_entry.data_size); - } - } - - //if (MMDB_get_value(&mmdb_result.entry, &mmdb_entry, "location", "latitude", NULL) == MMDB_SUCCESS) - //{ - // if (mmdb_entry.has_data && mmdb_entry.type == MMDB_DATA_TYPE_DOUBLE) - // { - // *CityLatitude = mmdb_entry.double_value; - // } - //} - - //if (MMDB_get_value(&mmdb_result.entry, &mmdb_entry, "location", "longitude", NULL) == MMDB_SUCCESS) - //{ - // if (mmdb_entry.has_data && mmdb_entry.type == MMDB_DATA_TYPE_DOUBLE) - // { - // *CityLongitude = mmdb_entry.double_value; - // } - //} - } + if (GeoDbGetCountryData(&mmdb_result.entry, CountryCode, CountryName)) + return TRUE; - if (countryCode && countryName) - { - *CountryCode = countryCode; - *CountryName = countryName; - return TRUE; - } - - if (countryCode) - { - PhDereferenceObject(countryCode); - } - - if (countryName) - { - PhDereferenceObject(countryName); + // HACK + // We can sometimes get the continent even when the address doesn't have a country. + if (GeoDbGetContinentData(&mmdb_result.entry, CountryCode, CountryName)) + return TRUE; } return FALSE; @@ -299,9 +323,6 @@ BOOLEAN LookupSockInAddr6CountryCode( _Out_ PPH_STRING *CountryName ) { - PPH_STRING countryCode = NULL; - PPH_STRING countryName = NULL; - MMDB_entry_data_s mmdb_entry; MMDB_lookup_result_s mmdb_result; SOCKADDR_IN6 ipv6SockAddr; INT mmdb_error = 0; @@ -329,56 +350,13 @@ BOOLEAN LookupSockInAddr6CountryCode( if (mmdb_error == 0 && mmdb_result.found_entry) { - memset(&mmdb_entry, 0, sizeof(MMDB_entry_data_s)); - - if (MMDB_get_value(&mmdb_result.entry, &mmdb_entry, "country", "iso_code", NULL) == MMDB_SUCCESS) - { - if (mmdb_entry.has_data && mmdb_entry.type == MMDB_DATA_TYPE_UTF8_STRING) - { - countryCode = PhConvertUtf8ToUtf16Ex((PCHAR)mmdb_entry.utf8_string, mmdb_entry.data_size); - } - } - - if (MMDB_get_value(&mmdb_result.entry, &mmdb_entry, "country", "names", "en", NULL) == MMDB_SUCCESS) - { - if (mmdb_entry.has_data && mmdb_entry.type == MMDB_DATA_TYPE_UTF8_STRING) - { - countryName = PhConvertUtf8ToUtf16Ex((PCHAR)mmdb_entry.utf8_string, mmdb_entry.data_size); - } - } - - //if (MMDB_get_value(&mmdb_result.entry, &mmdb_entry, "location", "latitude", NULL) == MMDB_SUCCESS) - //{ - // if (mmdb_entry.has_data && mmdb_entry.type == MMDB_DATA_TYPE_DOUBLE) - // { - // *CityLatitude = mmdb_entry.double_value; - // } - //} - - //if (MMDB_get_value(&mmdb_result.entry, &mmdb_entry, "location", "longitude", NULL) == MMDB_SUCCESS) - //{ - // if (mmdb_entry.has_data && mmdb_entry.type == MMDB_DATA_TYPE_DOUBLE) - // { - // *CityLongitude = mmdb_entry.double_value; - // } - //} - } - - if (countryCode && countryName) - { - *CountryCode = countryCode; - *CountryName = countryName; - return TRUE; - } - - if (countryCode) - { - PhDereferenceObject(countryCode); - } + if (GeoDbGetCountryData(&mmdb_result.entry, CountryCode, CountryName)) + return TRUE; - if (countryName) - { - PhDereferenceObject(countryName); + // HACK + // We can sometimes get the continent even when the address doesn't have a country. + if (GeoDbGetContinentData(&mmdb_result.entry, CountryCode, CountryName)) + return TRUE; } return FALSE; diff --git a/plugins/NetworkTools/tracert.c b/plugins/NetworkTools/tracert.c index e4064f43e3a1..9e10f9ee6841 100644 --- a/plugins/NetworkTools/tracert.c +++ b/plugins/NetworkTools/tracert.c @@ -348,8 +348,7 @@ NTSTATUS NetworkTracertThreadStart( if (reply4->Status == IP_HOP_LIMIT_EXCEEDED && reply4->RoundTripTime < MIN_INTERVAL) { - //LARGE_INTEGER interval; - //NtDelayExecution(FALSE, PhTimeoutFromMilliseconds(&interval, MIN_INTERVAL - reply4->RoundTripTime)); + //PhDelayExecution(MIN_INTERVAL - reply4->RoundTripTime); } //if (reply4->Status != IP_REQ_TIMED_OUT) @@ -409,8 +408,7 @@ NTSTATUS NetworkTracertThreadStart( { if (reply6->RoundTripTime < MIN_INTERVAL) { - //LARGE_INTEGER interval; - //NtDelayExecution(FALSE, PhTimeoutFromMilliseconds(&interval, MIN_INTERVAL - reply6->RoundTripTime)); + //PhDelayExecution(MIN_INTERVAL - reply6->RoundTripTime); } } } diff --git a/plugins/NetworkTools/tracert.h b/plugins/NetworkTools/tracert.h index 44bfb38c1783..408b9d56df61 100644 --- a/plugins/NetworkTools/tracert.h +++ b/plugins/NetworkTools/tracert.h @@ -54,14 +54,11 @@ typedef struct _TRACERT_ROOT_NODE PPH_STRING PingString[DEFAULT_MAXIMUM_PINGS]; INT CountryIconIndex; - PPH_STRING TtlString; - PPH_STRING CountryString; PPH_STRING HostnameString; PPH_STRING IpAddressString; PPH_STRING RemoteCountryCode; PPH_STRING RemoteCountryName; - PPH_STRING RemoteCityName; PH_STRINGREF TextCache[TREE_COLUMN_ITEM_MAXIMUM]; } TRACERT_ROOT_NODE, *PTRACERT_ROOT_NODE; diff --git a/plugins/NetworkTools/tracetree.c b/plugins/NetworkTools/tracetree.c index aafa7a7664b0..730a4d0bb9be 100644 --- a/plugins/NetworkTools/tracetree.c +++ b/plugins/NetworkTools/tracetree.c @@ -35,8 +35,6 @@ VOID NTAPI TracertTreeNodeItemDeleteProcedure( if (tracertNode->TtlString) PhDereferenceObject(tracertNode->TtlString); - if (tracertNode->CountryString) - PhDereferenceObject(tracertNode->CountryString); if (tracertNode->HostnameString) PhDereferenceObject(tracertNode->HostnameString); if (tracertNode->IpAddressString) @@ -120,12 +118,6 @@ BEGIN_SORT_FUNCTION(Ping4) } END_SORT_FUNCTION -BEGIN_SORT_FUNCTION(Country) -{ - sortResult = PhCompareStringWithNull(node1->CountryString, node2->CountryString, TRUE); -} -END_SORT_FUNCTION - BEGIN_SORT_FUNCTION(IpAddress) { sortResult = PhCompareStringWithNull(node1->IpAddressString, node2->IpAddressString, TRUE); @@ -138,6 +130,12 @@ BEGIN_SORT_FUNCTION(Hostname) } END_SORT_FUNCTION +BEGIN_SORT_FUNCTION(Country) +{ + sortResult = PhCompareStringWithNull(node1->RemoteCountryName, node2->RemoteCountryName, TRUE); +} +END_SORT_FUNCTION + VOID TracertLoadSettingsTreeList( _Inout_ PNETWORK_TRACERT_CONTEXT Context ) @@ -387,15 +385,15 @@ BOOLEAN NTAPI TracertTreeNewCallback( case TREE_COLUMN_ITEM_PING4: UpdateTracertNodePingText(node, getCellText, 3); break; - case TREE_COLUMN_ITEM_COUNTRY: - getCellText->Text = PhGetStringRef(node->CountryString); - break; case TREE_COLUMN_ITEM_IPADDR: getCellText->Text = PhGetStringRef(node->IpAddressString); break; case TREE_COLUMN_ITEM_HOSTNAME: getCellText->Text = PhGetStringRef(node->HostnameString); break; + case TREE_COLUMN_ITEM_COUNTRY: + getCellText->Text = PhGetStringRef(node->RemoteCountryName); + break; default: return FALSE; } @@ -500,7 +498,7 @@ BOOLEAN NTAPI TracertTreeNewCallback( DrawText(hdc, L"Geoip database error.", -1, &rect, DT_LEFT | DT_VCENTER | DT_END_ELLIPSIS | DT_SINGLELINE); } } - break; + return TRUE; } return FALSE; @@ -620,4 +618,4 @@ VOID DeleteTracertTree( PhDereferenceObject(Context->NodeHashtable); PhDereferenceObject(Context->NodeList); -} \ No newline at end of file +} From 2f4f9af046f549b9d511202dcc211bb7cac9b511 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 9 Jun 2018 09:30:15 +1000 Subject: [PATCH 0991/2058] Fix version check for insider builds --- phlib/global.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/phlib/global.c b/phlib/global.c index 1100438bd8f5..49226a018302 100644 --- a/phlib/global.c +++ b/phlib/global.c @@ -3,6 +3,7 @@ * global variables and initialization functions * * Copyright (C) 2010-2013 wj32 + * Copyright (C) 2017-2018 dmex * * This file is part of Process Hacker. * @@ -217,7 +218,7 @@ static VOID PhInitializeWindowsVersion( WindowsVersion = WINDOWS_10_RS4; break; default: - WindowsVersion = WindowsVersion > 17134 ? WINDOWS_10_RS4 : WINDOWS_10; + WindowsVersion = buildVersion > 17134 ? WINDOWS_10_RS4 : WINDOWS_10; break; } } From ef6ce7b618d85fad5d391abe365f73c66f11358c Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 9 Jun 2018 09:33:07 +1000 Subject: [PATCH 0992/2058] Fix PhNtStatusToDosError changing the thread last error status --- phlib/error.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phlib/error.c b/phlib/error.c index b0c27c4e909e..08328b1e2b58 100644 --- a/phlib/error.c +++ b/phlib/error.c @@ -35,7 +35,7 @@ ULONG PhNtStatusToDosError( if (NT_NTWIN32(Status)) // RtlNtStatusToDosError doesn't seem to handle these cases correctly return WIN32_FROM_NTSTATUS(Status); else - return RtlNtStatusToDosError(Status); + return RtlNtStatusToDosErrorNoTeb(Status); } /** From 8fbbafa720963948b09e06cf50e957197c07556f Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 9 Jun 2018 09:36:47 +1000 Subject: [PATCH 0993/2058] Increase handle provider hashtable size --- ProcessHacker/hndlprv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ProcessHacker/hndlprv.c b/ProcessHacker/hndlprv.c index 6cba00801464..5d7c32e15ca9 100644 --- a/ProcessHacker/hndlprv.c +++ b/ProcessHacker/hndlprv.c @@ -90,7 +90,7 @@ PPH_HANDLE_PROVIDER PhCreateHandleProvider( ProcessId ); - handleProvider->TempListHashtable = PhCreateSimpleHashtable(20); + handleProvider->TempListHashtable = PhCreateSimpleHashtable(512); PhEmCallObjectOperation(EmHandleProviderType, handleProvider, EmObjectCreate); From 968ce27bf837eb8d7128992d0660e784288744ab Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 9 Jun 2018 09:39:23 +1000 Subject: [PATCH 0994/2058] Fix DLGTEMPLATEEX packing --- phlib/include/guisup.h | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/phlib/include/guisup.h b/phlib/include/guisup.h index 52255f8bbe41..eb4b748a689b 100644 --- a/phlib/include/guisup.h +++ b/phlib/include/guisup.h @@ -377,19 +377,29 @@ VOID PhSetClipboardString( _In_ PPH_STRINGREF String ); +#include typedef struct _DLGTEMPLATEEX { - WORD dlgVer; - WORD signature; - DWORD helpID; - DWORD exStyle; - DWORD style; - WORD cDlgItems; - short x; - short y; - short cx; - short cy; + USHORT dlgVer; + USHORT signature; + ULONG helpID; + ULONG exStyle; + ULONG style; + USHORT cDlgItems; + SHORT x; + SHORT y; + SHORT cx; + SHORT cy; + //sz_Or_Ord menu; + //sz_Or_Ord windowClass; + //WCHAR title[titleLen]; + //USHORT pointsize; + //USHORT weight; + //BYTE italic; + //BYTE charset; + //WCHAR typeface[stringLen]; } DLGTEMPLATEEX, *PDLGTEMPLATEEX; +#include PHLIBAPI HWND PhCreateDialogFromTemplate( From 56e57e69daded66e190484f3800b9b9343427577 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 9 Jun 2018 09:51:08 +1000 Subject: [PATCH 0995/2058] Partial revert commit 02b2c0a --- ProcessHacker/actions.c | 56 ++++++++++++++ ProcessHacker/include/actions.h | 8 ++ ProcessHacker/prpgmod.c | 57 ++++++++++---- phlib/hndlinfo.c | 2 +- phlib/include/phnative.h | 9 +++ phlib/native.c | 131 ++++++++++++++++++++++++++++++++ 6 files changed, 246 insertions(+), 17 deletions(-) diff --git a/ProcessHacker/actions.c b/ProcessHacker/actions.c index 0eeccd5a2bcd..0b049eefa804 100644 --- a/ProcessHacker/actions.c +++ b/ProcessHacker/actions.c @@ -1656,6 +1656,62 @@ BOOLEAN PhUiDetachFromDebuggerProcess( return TRUE; } +BOOLEAN PhUiLoadDllProcess( + _In_ HWND hWnd, + _In_ PPH_PROCESS_ITEM Process + ) +{ + static PH_FILETYPE_FILTER filters[] = + { + { L"DLL files (*.dll)", L"*.dll" }, + { L"All files (*.*)", L"*.*" } + }; + + NTSTATUS status; + PVOID fileDialog; + PPH_STRING fileName; + HANDLE processHandle; + + fileDialog = PhCreateOpenFileDialog(); + PhSetFileDialogFilter(fileDialog, filters, RTL_NUMBER_OF(filters)); + + if (!PhShowFileDialog(hWnd, fileDialog)) + { + PhFreeFileDialog(fileDialog); + return FALSE; + } + + fileName = PH_AUTO(PhGetFileDialogFileName(fileDialog)); + PhFreeFileDialog(fileDialog); + + if (NT_SUCCESS(status = PhOpenProcess( + &processHandle, + ProcessQueryAccess | PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | + PROCESS_VM_READ | PROCESS_VM_WRITE, + Process->ProcessId + ))) + { + LARGE_INTEGER timeout; + + timeout.QuadPart = -(LONGLONG)UInt32x32To64(5, PH_TIMEOUT_SEC); + status = PhLoadDllProcess( + processHandle, + fileName->Buffer, + &timeout + ); + + NtClose(processHandle); + } + + if (!NT_SUCCESS(status)) + { + PhpShowErrorProcess(hWnd, L"load the DLL into", Process, status, 0); + return FALSE; + } + + return TRUE; +} + BOOLEAN PhUiSetIoPriorityProcesses( _In_ HWND hWnd, _In_ PPH_PROCESS_ITEM *Processes, diff --git a/ProcessHacker/include/actions.h b/ProcessHacker/include/actions.h index 62cb0d758b04..9b18626c6b48 100644 --- a/ProcessHacker/include/actions.h +++ b/ProcessHacker/include/actions.h @@ -188,6 +188,14 @@ PhUiDetachFromDebuggerProcess( _In_ PPH_PROCESS_ITEM Process ); +PHAPPAPI +BOOLEAN +NTAPI +PhUiLoadDllProcess( + _In_ HWND hWnd, + _In_ PPH_PROCESS_ITEM Process + ); + PHAPPAPI BOOLEAN NTAPI diff --git a/ProcessHacker/prpgmod.c b/ProcessHacker/prpgmod.c index ab2cdc1c647e..0ae3be63b3c2 100644 --- a/ProcessHacker/prpgmod.c +++ b/ProcessHacker/prpgmod.c @@ -680,17 +680,19 @@ INT_PTR CALLBACK PhpProcessModulesDlgProc( GetWindowRect(GetDlgItem(hwndDlg, IDC_FILTEROPTIONS), &rect); menu = PhCreateEMenu(); - PhInsertEMenuItem(menu, dynamicItem = PhCreateEMenuItem(0, PH_MODULE_FLAGS_DYNAMIC_OPTION, L"Hide dynamic", NULL, NULL), -1); - PhInsertEMenuItem(menu, mappedItem = PhCreateEMenuItem(0, PH_MODULE_FLAGS_MAPPED_OPTION, L"Hide mapped", NULL, NULL), -1); - PhInsertEMenuItem(menu, staticItem = PhCreateEMenuItem(0, PH_MODULE_FLAGS_STATIC_OPTION, L"Hide static", NULL, NULL), -1); - PhInsertEMenuItem(menu, verifiedItem = PhCreateEMenuItem(0, PH_MODULE_FLAGS_SIGNED_OPTION, L"Hide verified", NULL, NULL), -1); - PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), -1); - PhInsertEMenuItem(menu, dotnetItem = PhCreateEMenuItem(0, PH_MODULE_FLAGS_HIGHLIGHT_DOTNET_OPTION, L"Highlight .NET modules", NULL, NULL), -1); - PhInsertEMenuItem(menu, immersiveItem = PhCreateEMenuItem(0, PH_MODULE_FLAGS_HIGHLIGHT_IMMERSIVE_OPTION, L"Highlight immersive modules", NULL, NULL), -1); - PhInsertEMenuItem(menu, relocatedItem = PhCreateEMenuItem(0, PH_MODULE_FLAGS_HIGHLIGHT_RELOCATED_OPTION, L"Highlight relocated modules", NULL, NULL), -1); - PhInsertEMenuItem(menu, untrustedItem = PhCreateEMenuItem(0, PH_MODULE_FLAGS_HIGHLIGHT_UNSIGNED_OPTION, L"Highlight untrusted modules", NULL, NULL), -1); - PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), -1); - PhInsertEMenuItem(menu, stringsItem = PhCreateEMenuItem(0, PH_MODULE_FLAGS_MODULE_STRINGS_OPTION, L"Strings...", NULL, NULL), -1); + PhInsertEMenuItem(menu, dynamicItem = PhCreateEMenuItem(0, PH_MODULE_FLAGS_DYNAMIC_OPTION, L"Hide dynamic", NULL, NULL), ULONG_MAX); + PhInsertEMenuItem(menu, mappedItem = PhCreateEMenuItem(0, PH_MODULE_FLAGS_MAPPED_OPTION, L"Hide mapped", NULL, NULL), ULONG_MAX); + PhInsertEMenuItem(menu, staticItem = PhCreateEMenuItem(0, PH_MODULE_FLAGS_STATIC_OPTION, L"Hide static", NULL, NULL), ULONG_MAX); + PhInsertEMenuItem(menu, verifiedItem = PhCreateEMenuItem(0, PH_MODULE_FLAGS_SIGNED_OPTION, L"Hide verified", NULL, NULL), ULONG_MAX); + PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX); + PhInsertEMenuItem(menu, dotnetItem = PhCreateEMenuItem(0, PH_MODULE_FLAGS_HIGHLIGHT_DOTNET_OPTION, L"Highlight .NET modules", NULL, NULL), ULONG_MAX); + PhInsertEMenuItem(menu, immersiveItem = PhCreateEMenuItem(0, PH_MODULE_FLAGS_HIGHLIGHT_IMMERSIVE_OPTION, L"Highlight immersive modules", NULL, NULL), ULONG_MAX); + PhInsertEMenuItem(menu, relocatedItem = PhCreateEMenuItem(0, PH_MODULE_FLAGS_HIGHLIGHT_RELOCATED_OPTION, L"Highlight relocated modules", NULL, NULL), ULONG_MAX); + PhInsertEMenuItem(menu, untrustedItem = PhCreateEMenuItem(0, PH_MODULE_FLAGS_HIGHLIGHT_UNSIGNED_OPTION, L"Highlight untrusted modules", NULL, NULL), ULONG_MAX); + PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, PH_MODULE_FLAGS_LOAD_MODULE_OPTION, L"Load module...", NULL, NULL), ULONG_MAX); + PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX); + PhInsertEMenuItem(menu, stringsItem = PhCreateEMenuItem(0, PH_MODULE_FLAGS_MODULE_STRINGS_OPTION, L"Strings...", NULL, NULL), ULONG_MAX); if (modulesContext->ListContext.HideDynamicModules) dynamicItem->Flags |= PH_EMENU_CHECKED; @@ -709,7 +711,7 @@ INT_PTR CALLBACK PhpProcessModulesDlgProc( if (modulesContext->ListContext.HighlightUntrustedModules) untrustedItem->Flags |= PH_EMENU_CHECKED; - stringsItem->Flags |= PH_EMENU_DISABLED; + stringsItem->Flags |= PH_EMENU_DISABLED; // TODO selectedItem = PhShowEMenu( menu, @@ -722,10 +724,33 @@ INT_PTR CALLBACK PhpProcessModulesDlgProc( if (selectedItem && selectedItem->Id) { - PhSetOptionsModuleList(&modulesContext->ListContext, selectedItem->Id); - PhSaveSettingsModuleList(&modulesContext->ListContext); - - PhApplyTreeNewFilters(&modulesContext->ListContext.TreeFilterSupport); + if (selectedItem->Id == PH_MODULE_FLAGS_LOAD_MODULE_OPTION) + { + if (PhGetIntegerSetting(L"EnableWarnings") && !PhShowConfirmMessage( + hwndDlg, + L"load", + L"the module", + L"Some programs may restrict access or ban your account when loading modules into the process.", + FALSE + )) + { + break; + } + + PhReferenceObject(processItem); + PhUiLoadDllProcess(hwndDlg, processItem); + PhDereferenceObject(processItem); + } + else if (selectedItem->Id == PH_MODULE_FLAGS_MODULE_STRINGS_OPTION) + { + // TODO + } + else + { + PhSetOptionsModuleList(&modulesContext->ListContext, selectedItem->Id); + PhSaveSettingsModuleList(&modulesContext->ListContext); + PhApplyTreeNewFilters(&modulesContext->ListContext.TreeFilterSupport); + } } PhDestroyEMenu(menu); diff --git a/phlib/hndlinfo.c b/phlib/hndlinfo.c index 036af4e77a5d..dca956ea18e4 100644 --- a/phlib/hndlinfo.c +++ b/phlib/hndlinfo.c @@ -1713,7 +1713,7 @@ NTSTATUS PhpCommonQueryObjectWithTimeout( NTSTATUS status; LARGE_INTEGER timeout; - timeout.QuadPart = -1 * PH_TIMEOUT_SEC; + timeout.QuadPart = -(LONGLONG)UInt32x32To64(1, PH_TIMEOUT_SEC); status = PhCallWithTimeout(PhpCommonQueryObjectRoutine, Context, NULL, &timeout); if (NT_SUCCESS(status)) diff --git a/phlib/include/phnative.h b/phlib/include/phnative.h index a9f2c0ad4def..a68e096b0017 100644 --- a/phlib/include/phnative.h +++ b/phlib/include/phnative.h @@ -287,6 +287,15 @@ PhGetProcessWsCounters( _Out_ PPH_PROCESS_WS_COUNTERS WsCounters ); +PHLIBAPI +NTSTATUS +NTAPI +PhLoadDllProcess( + _In_ HANDLE ProcessHandle, + _In_ PWSTR FileName, + _In_opt_ PLARGE_INTEGER Timeout + ); + PHLIBAPI NTSTATUS NTAPI diff --git a/phlib/native.c b/phlib/native.c index 40871c88f876..db47ecb41a7e 100644 --- a/phlib/native.c +++ b/phlib/native.c @@ -1336,6 +1336,137 @@ NTSTATUS PhGetProcessUnloadedDlls( return status; } +/** + * Causes a process to load a DLL. + * + * \param ProcessHandle A handle to a process. The handle must have + * PROCESS_QUERY_LIMITED_INFORMATION, PROCESS_CREATE_THREAD, PROCESS_VM_OPERATION, PROCESS_VM_READ + * and PROCESS_VM_WRITE access. + * \param FileName The file name of the DLL to inject. + * \param Timeout The timeout, in milliseconds, for the process to load the DLL. + * + * \remarks If the process does not load the DLL before the timeout expires it may crash. Choose the + * timeout value carefully. + */ +NTSTATUS PhLoadDllProcess( + _In_ HANDLE ProcessHandle, + _In_ PWSTR FileName, + _In_opt_ PLARGE_INTEGER Timeout + ) +{ +#ifdef _WIN64 + static PVOID loadLibraryW32 = NULL; +#endif + NTSTATUS status; +#ifdef _WIN64 + BOOLEAN isWow64 = FALSE; + BOOLEAN isModule32 = FALSE; + PH_MAPPED_IMAGE mappedImage; +#endif + PVOID threadStart; + PH_STRINGREF fileName; + PVOID baseAddress = NULL; + SIZE_T allocSize; + HANDLE threadHandle; + +#ifdef _WIN64 + PhGetProcessIsWow64(ProcessHandle, &isWow64); + + if (isWow64) + { + if (!NT_SUCCESS(status = PhLoadMappedImage(FileName, NULL, TRUE, &mappedImage))) + return status; + + isModule32 = mappedImage.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC; + PhUnloadMappedImage(&mappedImage); + } + + if (!isModule32) + { +#endif + threadStart = PhGetModuleProcAddress(L"kernel32.dll", "LoadLibraryW"); +#ifdef _WIN64 + } + else + { + threadStart = loadLibraryW32; + + if (!threadStart) + { + PPH_STRING kernel32FileName; + + kernel32FileName = PhConcatStrings2(USER_SHARED_DATA->NtSystemRoot, L"\\SysWow64\\kernel32.dll"); + status = PhGetProcedureAddressRemote( + ProcessHandle, + kernel32FileName->Buffer, + "LoadLibraryW", + 0, + &loadLibraryW32, + NULL + ); + PhDereferenceObject(kernel32FileName); + + if (!NT_SUCCESS(status)) + return status; + + threadStart = loadLibraryW32; + } + } +#endif + + PhInitializeStringRefLongHint(&fileName, FileName); + allocSize = fileName.Length + sizeof(WCHAR); + + if (!NT_SUCCESS(status = NtAllocateVirtualMemory( + ProcessHandle, + &baseAddress, + 0, + &allocSize, + MEM_COMMIT, + PAGE_READWRITE + ))) + return status; + + if (!NT_SUCCESS(status = NtWriteVirtualMemory( + ProcessHandle, + baseAddress, + fileName.Buffer, + fileName.Length + sizeof(WCHAR), + NULL + ))) + goto FreeExit; + + if (!NT_SUCCESS(status = RtlCreateUserThread( + ProcessHandle, + NULL, + FALSE, + 0, + 0, + 0, + threadStart, + baseAddress, + &threadHandle, + NULL + ))) + goto FreeExit; + + // Wait for the thread to finish. + status = NtWaitForSingleObject(threadHandle, FALSE, Timeout); + NtClose(threadHandle); + +FreeExit: + // Size needs to be zero if we're freeing. + allocSize = 0; + NtFreeVirtualMemory( + ProcessHandle, + &baseAddress, + &allocSize, + MEM_RELEASE + ); + + return status; +} + /** * Causes a process to unload a DLL. * From 26cf28699d58c4f32a6cd03a92a68df651852850 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 9 Jun 2018 09:58:58 +1000 Subject: [PATCH 0996/2058] Fix winsock header conflicts with the pluginsdk --- phlib/include/phnet.h | 39 +++++++++++++++++++++++---------------- phnt/include/ntrtl.h | 28 ++++++++++++++-------------- 2 files changed, 37 insertions(+), 30 deletions(-) diff --git a/phlib/include/phnet.h b/phlib/include/phnet.h index 50394dfd0258..faa2e19f0dfa 100644 --- a/phlib/include/phnet.h +++ b/phlib/include/phnet.h @@ -1,8 +1,12 @@ #ifndef _PH_PHNET_H #define _PH_PHNET_H -#include -#include +#include +#include +#include +#include +#include +#include #define PH_IPV4_NETWORK_TYPE 0x1 #define PH_IPV6_NETWORK_TYPE 0x2 @@ -24,9 +28,9 @@ typedef struct _PH_IP_ADDRESS union { ULONG Ipv4; - struct in_addr InAddr; + IN_ADDR InAddr; UCHAR Ipv6[16]; - struct in6_addr In6Addr; + IN6_ADDR In6Addr; }; } PH_IP_ADDRESS, *PPH_IP_ADDRESS; @@ -40,23 +44,26 @@ FORCEINLINE BOOLEAN PhEqualIpAddress( if (Address1->Type != Address2->Type) return FALSE; + // TODO: Remove the below commented code if the ADDR_EQUAL macros work -dmex if (Address1->Type == PH_IPV4_NETWORK_TYPE) { - return Address1->Ipv4 == Address2->Ipv4; + return IN4_ADDR_EQUAL(&Address1->InAddr, &Address2->InAddr); + // return Address1->Ipv4 == Address2->Ipv4; } else { -#ifdef _WIN64 - return - *(PULONG64)(Address1->Ipv6) == *(PULONG64)(Address2->Ipv6) && - *(PULONG64)(Address1->Ipv6 + 8) == *(PULONG64)(Address2->Ipv6 + 8); -#else - return - *(PULONG)(Address1->Ipv6) == *(PULONG)(Address2->Ipv6) && - *(PULONG)(Address1->Ipv6 + 4) == *(PULONG)(Address2->Ipv6 + 4) && - *(PULONG)(Address1->Ipv6 + 8) == *(PULONG)(Address2->Ipv6 + 8) && - *(PULONG)(Address1->Ipv6 + 12) == *(PULONG)(Address2->Ipv6 + 12); -#endif + return IN6_ADDR_EQUAL(&Address1->In6Addr, &Address2->In6Addr); +//#ifdef _WIN64 +// return +// *(PULONG64)(Address1->Ipv6) == *(PULONG64)(Address2->Ipv6) && +// *(PULONG64)(Address1->Ipv6 + 8) == *(PULONG64)(Address2->Ipv6 + 8); +//#else +// return +// *(PULONG)(Address1->Ipv6) == *(PULONG)(Address2->Ipv6) && +// *(PULONG)(Address1->Ipv6 + 4) == *(PULONG)(Address2->Ipv6 + 4) && +// *(PULONG)(Address1->Ipv6 + 8) == *(PULONG)(Address2->Ipv6 + 8) && +// *(PULONG)(Address1->Ipv6 + 12) == *(PULONG)(Address2->Ipv6 + 12); +//#endif } } diff --git a/phnt/include/ntrtl.h b/phnt/include/ntrtl.h index c7f273ccc479..1b79bf11b37d 100644 --- a/phnt/include/ntrtl.h +++ b/phnt/include/ntrtl.h @@ -4389,15 +4389,15 @@ NTSYSAPI PWSTR NTAPI RtlIpv4AddressToStringW( - _In_ struct in_addr *Addr, - _Out_writes_(16) PWSTR S + _In_ const struct in_addr *Address, + _Out_writes_(16) PWSTR AddressString ); NTSYSAPI NTSTATUS NTAPI RtlIpv4AddressToStringExW( - _In_ struct in_addr *Address, + _In_ const struct in_addr *Address, _In_ USHORT Port, _Out_writes_to_(*AddressStringLength, *AddressStringLength) PWSTR AddressString, _Inout_ PULONG AddressStringLength @@ -4407,15 +4407,15 @@ NTSYSAPI PWSTR NTAPI RtlIpv6AddressToStringW( - _In_ struct in6_addr *Addr, - _Out_writes_(65) PWSTR S + _In_ const struct in6_addr *Address, + _Out_writes_(46) PWSTR AddressString ); NTSYSAPI NTSTATUS NTAPI RtlIpv6AddressToStringExW( - _In_ struct in6_addr *Address, + _In_ const struct in6_addr *Address, _In_ ULONG ScopeId, _In_ USHORT Port, _Out_writes_to_(*AddressStringLength, *AddressStringLength) PWSTR AddressString, @@ -4426,17 +4426,17 @@ NTSYSAPI NTSTATUS NTAPI RtlIpv4StringToAddressW( - _In_ PWSTR S, + _In_ PCWSTR AddressString, _In_ BOOLEAN Strict, - _Out_ PWSTR *Terminator, - _Out_ struct in_addr *Addr + _Out_ LPCWSTR *Terminator, + _Out_ struct in_addr *Address ); NTSYSAPI NTSTATUS NTAPI RtlIpv4StringToAddressExW( - _In_ PWSTR AddressString, + _In_ PCWSTR AddressString, _In_ BOOLEAN Strict, _Out_ struct in_addr *Address, _Out_ PUSHORT Port @@ -4446,16 +4446,16 @@ NTSYSAPI NTSTATUS NTAPI RtlIpv6StringToAddressW( - _In_ PWSTR S, - _Out_ PWSTR *Terminator, - _Out_ struct in6_addr *Addr + _In_ PCWSTR AddressString, + _Out_ PCWSTR *Terminator, + _Out_ struct in6_addr *Address ); NTSYSAPI NTSTATUS NTAPI RtlIpv6StringToAddressExW( - _In_ PWSTR AddressString, + _In_ PCWSTR AddressString, _Out_ struct in6_addr *Address, _Out_ PULONG ScopeId, _Out_ PUSHORT Port From b5d7f51b1638fb2b4331256918aa7eec3a8e0e90 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 9 Jun 2018 09:59:34 +1000 Subject: [PATCH 0997/2058] Add helper macro --- phlib/include/emenu.h | 47 ++++++++++++++++++++++++++----------------- phlib/include/ref.h | 17 ++++++++++++++++ 2 files changed, 45 insertions(+), 19 deletions(-) diff --git a/phlib/include/emenu.h b/phlib/include/emenu.h index 8bab5f575b8a..4760b56ec7b5 100644 --- a/phlib/include/emenu.h +++ b/phlib/include/emenu.h @@ -174,16 +174,6 @@ PPH_EMENU_ITEM PhShowEMenu( _In_ ULONG Y ); -// Convenience functions - -FORCEINLINE -PPH_EMENU_ITEM PhCreateEMenuSeparator( - VOID - ) -{ - return PhCreateEMenuItem(PH_EMENU_SEPARATOR, 0, NULL, NULL, NULL); -} - PHLIBAPI BOOLEAN PhSetFlagsEMenuItem( _Inout_ PPH_EMENU_ITEM Item, @@ -192,15 +182,6 @@ BOOLEAN PhSetFlagsEMenuItem( _In_ ULONG Value ); -FORCEINLINE BOOLEAN PhEnableEMenuItem( - _Inout_ PPH_EMENU_ITEM Item, - _In_ ULONG Id, - _In_ BOOLEAN Enable - ) -{ - return PhSetFlagsEMenuItem(Item, Id, PH_EMENU_DISABLED, Enable ? 0 : PH_EMENU_DISABLED); -} - PHLIBAPI VOID PhSetFlagsAllEMenuItems( _In_ PPH_EMENU_ITEM Item, @@ -220,6 +201,34 @@ VOID PhModifyEMenuItem( _In_opt_ HBITMAP Bitmap ); +// Convenience functions + +FORCEINLINE +PPH_EMENU_ITEM PhCreateEMenuSeparator( + VOID + ) +{ + return PhCreateEMenuItem(PH_EMENU_SEPARATOR, 0, NULL, NULL, NULL); +} + +FORCEINLINE +BOOLEAN PhEnableEMenuItem( + _Inout_ PPH_EMENU_ITEM Item, + _In_ ULONG Id, + _In_ BOOLEAN Enable + ) +{ + return PhSetFlagsEMenuItem(Item, Id, PH_EMENU_DISABLED, Enable ? 0 : PH_EMENU_DISABLED); +} + +FORCEINLINE +VOID PhSetDisabledEMenuItem( + _In_ PPH_EMENU_ITEM Item + ) +{ + Item->Flags |= PH_EMENU_DISABLED; +} + #ifdef __cplusplus } #endif diff --git a/phlib/include/ref.h b/phlib/include/ref.h index 4f3bb1389ae9..f2d425601ce7 100644 --- a/phlib/include/ref.h +++ b/phlib/include/ref.h @@ -243,6 +243,23 @@ PhClearReference( PhMoveReference(ObjectReference, NULL); } +// Convenience functions + +FORCEINLINE +PVOID +PhCreateObjectZero( + _In_ SIZE_T ObjectSize, + _In_ PPH_OBJECT_TYPE ObjectType + ) +{ + PVOID object; + + object = PhCreateObject(ObjectSize, ObjectType); + memset(object, 0, ObjectSize); + + return object; +} + // Auto-dereference pool /** The size of the static array in an auto-release pool. */ From 95de2dfd6a270b2be43052f4e038040643100db1 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 9 Jun 2018 10:07:37 +1000 Subject: [PATCH 0998/2058] Tidy up --- ProcessHacker/actions.c | 4 ++-- ProcessHacker/anawait.c | 4 ++-- ProcessHacker/cmdmode.c | 2 +- ProcessHacker/prpgenv.c | 4 ++-- ProcessHacker/prpggen.c | 4 ++-- ProcessHacker/runas.c | 4 +++- ProcessHacker/sysinfo.c | 2 +- phlib/provider.c | 2 +- phlib/treenew.c | 2 +- 9 files changed, 15 insertions(+), 13 deletions(-) diff --git a/ProcessHacker/actions.c b/ProcessHacker/actions.c index 0b049eefa804..095923415cb7 100644 --- a/ProcessHacker/actions.c +++ b/ProcessHacker/actions.c @@ -194,7 +194,7 @@ BOOLEAN PhpShowErrorAndElevateAction( &processHandle )) { - timeout.QuadPart = -10 * PH_TIMEOUT_SEC; + timeout.QuadPart = -(LONGLONG)UInt32x32To64(10, PH_TIMEOUT_SEC); status = NtWaitForSingleObject(processHandle, FALSE, &timeout); if ( @@ -2728,7 +2728,7 @@ BOOLEAN PhUiUnloadModule( { LARGE_INTEGER timeout; - timeout.QuadPart = -5 * PH_TIMEOUT_SEC; + timeout.QuadPart = -(LONGLONG)UInt32x32To64(5, PH_TIMEOUT_SEC); status = PhUnloadDllProcess( processHandle, Module->BaseAddress, diff --git a/ProcessHacker/anawait.c b/ProcessHacker/anawait.c index e78569c7cd41..edec34cd8b7f 100644 --- a/ProcessHacker/anawait.c +++ b/ProcessHacker/anawait.c @@ -721,7 +721,7 @@ static NTSTATUS PhpWfsoThreadStart( eventHandle = Parameter; - timeout.QuadPart = -5 * PH_TIMEOUT_SEC; + timeout.QuadPart = -(LONGLONG)UInt32x32To64(5, PH_TIMEOUT_SEC); NtWaitForSingleObject(eventHandle, FALSE, &timeout); return STATUS_SUCCESS; @@ -736,7 +736,7 @@ static NTSTATUS PhpWfmoThreadStart( eventHandle = Parameter; - timeout.QuadPart = -5 * PH_TIMEOUT_SEC; + timeout.QuadPart = -(LONGLONG)UInt32x32To64(5, PH_TIMEOUT_SEC); NtWaitForMultipleObjects(1, &eventHandle, WaitAll, FALSE, &timeout); return STATUS_SUCCESS; diff --git a/ProcessHacker/cmdmode.c b/ProcessHacker/cmdmode.c index d5e6b0d2307f..5599787ab505 100644 --- a/ProcessHacker/cmdmode.c +++ b/ProcessHacker/cmdmode.c @@ -246,7 +246,7 @@ NTSTATUS PhCommandModeStart( // { // LARGE_INTEGER timeout; // - // timeout.QuadPart = -5 * PH_TIMEOUT_SEC; + // timeout.QuadPart = -(LONGLONG)UInt32x32To64(5, PH_TIMEOUT_SEC); // status = PhUnloadDllProcess( // processHandle, // baseAddress, diff --git a/ProcessHacker/prpgenv.c b/ProcessHacker/prpgenv.c index b9230dde9afe..0efd9a49eda6 100644 --- a/ProcessHacker/prpgenv.c +++ b/ProcessHacker/prpgenv.c @@ -327,7 +327,7 @@ INT_PTR CALLBACK PhpProcessEnvironmentDlgProc( processItem->ProcessId ))) { - timeout.QuadPart = -10 * PH_TIMEOUT_SEC; + timeout.QuadPart = -(LONGLONG)UInt32x32To64(10, PH_TIMEOUT_SEC); for (i = 0; i < numberOfIndices; i++) { @@ -551,7 +551,7 @@ INT_PTR CALLBACK PhpEditEnvDlgProc( context->ProcessItem->ProcessId ))) { - timeout.QuadPart = -10 * PH_TIMEOUT_SEC; + timeout.QuadPart = -(LONGLONG)UInt32x32To64(10, PH_TIMEOUT_SEC); // Delete the old environment variable if necessary. if (!PhEqualStringZ(context->Name, L"", FALSE) && diff --git a/ProcessHacker/prpggen.c b/ProcessHacker/prpggen.c index 1351145ba36d..e325ad64bf12 100644 --- a/ProcessHacker/prpggen.c +++ b/ProcessHacker/prpggen.c @@ -202,14 +202,14 @@ INT_PTR CALLBACK PhpProcessGeneralDlgProc( if (processItem->LargeIcon) { - SendMessage(GetDlgItem(hwndDlg, IDC_FILEICON), STM_SETICON, (WPARAM)processItem->LargeIcon, 0); + Static_SetIcon(GetDlgItem(hwndDlg, IDC_FILEICON), processItem->LargeIcon); } else { HICON iconLarge; PhGetStockApplicationIcon(NULL, &iconLarge); - SendMessage(GetDlgItem(hwndDlg, IDC_FILEICON), STM_SETICON, (WPARAM)iconLarge, 0); + Static_SetIcon(GetDlgItem(hwndDlg, IDC_FILEICON), iconLarge); } if (PH_IS_REAL_PROCESS_ID(processItem->ProcessId)) diff --git a/ProcessHacker/runas.c b/ProcessHacker/runas.c index 158a3fa2f507..d0bf0d005626 100644 --- a/ProcessHacker/runas.c +++ b/ProcessHacker/runas.c @@ -1491,13 +1491,15 @@ static VOID WINAPI RunAsServiceMain( LARGE_INTEGER timeout; memset(&RunAsServiceStop, 0, sizeof(PHSVC_STOP)); + RunAsServiceStatusHandle = RegisterServiceCtrlHandlerEx(RunAsServiceName->Buffer, RunAsServiceHandlerEx, NULL); SetRunAsServiceStatus(SERVICE_RUNNING); portName = PhConcatStrings2(L"\\BaseNamedObjects\\", RunAsServiceName->Buffer); PhStringRefToUnicodeString(&portName->sr, &portNameUs); + // Use a shorter timeout value to reduce the time spent running as SYSTEM. - timeout.QuadPart = -5 * PH_TIMEOUT_SEC; + timeout.QuadPart = -(LONGLONG)UInt32x32To64(5, PH_TIMEOUT_SEC); PhSvcMain(&portNameUs, &timeout, &RunAsServiceStop); diff --git a/ProcessHacker/sysinfo.c b/ProcessHacker/sysinfo.c index de2c2bfc8a0d..e868cfd0174e 100644 --- a/ProcessHacker/sysinfo.c +++ b/ProcessHacker/sysinfo.c @@ -2076,7 +2076,7 @@ VOID PhSipUpdateThemeData( ThemeData = NULL; } - ThemeData = OpenThemeData(PhSipWindow, L"TREEVIEW"); + ThemeData = OpenThemeData(PhSipWindow, VSCLASS_TREEVIEW); if (ThemeData) { diff --git a/phlib/provider.c b/phlib/provider.c index 0dc7d50f1b00..9550eba2cda8 100644 --- a/phlib/provider.c +++ b/phlib/provider.c @@ -293,7 +293,7 @@ VOID PhSetIntervalProviderThread( { LARGE_INTEGER interval; - interval.QuadPart = -(LONGLONG)Interval * PH_TIMEOUT_MS; + interval.QuadPart = -(LONGLONG)UInt32x32To64(Interval, PH_TIMEOUT_MS); NtSetTimer(ProviderThread->TimerHandle, &interval, NULL, NULL, FALSE, Interval, NULL); } } diff --git a/phlib/treenew.c b/phlib/treenew.c index fa4818e5461f..39ba1671093f 100644 --- a/phlib/treenew.c +++ b/phlib/treenew.c @@ -2112,7 +2112,7 @@ VOID PhTnpUpdateThemeData( Context->ThemeData = NULL; } - Context->ThemeData = OpenThemeData(Context->Handle, L"TREEVIEW"); + Context->ThemeData = OpenThemeData(Context->Handle, VSCLASS_TREEVIEW); if (Context->ThemeData) { From e85c89b634035d98bed5e362a86ad8b0aebb7e17 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 9 Jun 2018 10:24:48 +1000 Subject: [PATCH 0999/2058] Tidy up flags --- phlib/secedit.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/phlib/secedit.c b/phlib/secedit.c index be964c0fe2fa..22b8203200c9 100644 --- a/phlib/secedit.c +++ b/phlib/secedit.c @@ -268,14 +268,7 @@ HRESULT STDMETHODCALLTYPE PhSecurityInformation_GetObjectInformation( PhSecurityInformation *this = (PhSecurityInformation *)This; memset(ObjectInfo, 0, sizeof(SI_OBJECT_INFO)); - ObjectInfo->dwFlags = - SI_EDIT_AUDITS | - SI_EDIT_OWNER | - SI_EDIT_PERMS | - SI_ADVANCED; - //SI_NO_ACL_PROTECT | - //SI_NO_TREE_APPLY; - ObjectInfo->hInstance = NULL; + ObjectInfo->dwFlags = SI_EDIT_ALL | SI_ADVANCED; ObjectInfo->pszObjectName = this->ObjectName->Buffer; return S_OK; From aa420ac20342e1dfe3ac5297895f6973baea02bb Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 9 Jun 2018 10:33:04 +1000 Subject: [PATCH 1000/2058] Add SetTcpEntry to delayload --- ProcessHacker/actions.c | 20 ++------------------ 1 file changed, 2 insertions(+), 18 deletions(-) diff --git a/ProcessHacker/actions.c b/ProcessHacker/actions.c index 095923415cb7..cb8afdf0d8a6 100644 --- a/ProcessHacker/actions.c +++ b/ProcessHacker/actions.c @@ -48,10 +48,6 @@ #include #include -typedef ULONG (WINAPI *_SetTcpEntry)( - _In_ PMIB_TCPROW pTcpRow - ); - static PWSTR DangerousProcesses[] = { L"csrss.exe", L"dwm.exe", L"logonui.exe", L"lsass.exe", L"lsm.exe", @@ -616,7 +612,7 @@ BOOLEAN PhUiShutdownComputer( } else { - PhShowStatus(hWnd, L"Unable to shut down the computer", 0, GetLastError()); + PhShowStatus(hWnd, L"Unable to shut down the computer.", 0, GetLastError()); } } @@ -2206,20 +2202,8 @@ BOOLEAN PhUiCloseConnections( BOOLEAN cancelled = FALSE; ULONG result; ULONG i; - _SetTcpEntry SetTcpEntry_I; MIB_TCPROW tcpRow; - SetTcpEntry_I = PhGetDllProcedureAddress(L"iphlpapi.dll", "SetTcpEntry", 0); - - if (!SetTcpEntry_I) - { - PhShowError( - hWnd, - L"This feature is not supported by your operating system." - ); - return FALSE; - } - for (i = 0; i < NumberOfConnections; i++) { if ( @@ -2234,7 +2218,7 @@ BOOLEAN PhUiCloseConnections( tcpRow.dwRemoteAddr = Connections[i]->RemoteEndpoint.Address.Ipv4; tcpRow.dwRemotePort = _byteswap_ushort((USHORT)Connections[i]->RemoteEndpoint.Port); - if ((result = SetTcpEntry_I(&tcpRow)) != 0) + if ((result = SetTcpEntry(&tcpRow)) != NO_ERROR) { NTSTATUS status; BOOLEAN connected; From b4830a54655e7d00f59bf16cd276b0f6dccdf904 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 9 Jun 2018 10:34:12 +1000 Subject: [PATCH 1001/2058] Add check for phsvc when showing kph errors --- ProcessHacker/main.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ProcessHacker/main.c b/ProcessHacker/main.c index 95331d4083b2..63190082d52f 100644 --- a/ProcessHacker/main.c +++ b/ProcessHacker/main.c @@ -801,7 +801,7 @@ VOID PhInitializeKph( if (!RtlDoesFileExists_U(kprocesshackerFileName->Buffer)) { - if (PhGetIntegerSetting(L"EnableKphWarnings")) + if (PhGetIntegerSetting(L"EnableKphWarnings") && !PhStartupParameters.PhSvc) PhpShowKphError(L"The Process Hacker kernel driver 'kprocesshacker.sys' was not found in the application directory.", STATUS_NO_SUCH_FILE); return; } @@ -830,7 +830,7 @@ VOID PhInitializeKph( if (!NT_SUCCESS(status)) { - if (PhGetIntegerSetting(L"EnableKphWarnings")) + if (PhGetIntegerSetting(L"EnableKphWarnings") && !PhStartupParameters.PhSvc) PhpShowKphError(L"Unable to verify the kernel driver signature.", status); } @@ -838,13 +838,13 @@ VOID PhInitializeKph( } else { - if (PhGetIntegerSetting(L"EnableKphWarnings")) + if (PhGetIntegerSetting(L"EnableKphWarnings") && !PhStartupParameters.PhSvc) PhpShowKphError(L"Unable to load the kernel driver signature.", status); } } else { - if (PhGetIntegerSetting(L"EnableKphWarnings") && PhGetOwnTokenAttributes().Elevated) + if (PhGetIntegerSetting(L"EnableKphWarnings") && PhGetOwnTokenAttributes().Elevated && !PhStartupParameters.PhSvc) PhpShowKphError(L"Unable to load the kernel driver.", status); } From ae322e7ae3ff5f79757247dbd45f68f521af7751 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 9 Jun 2018 10:34:49 +1000 Subject: [PATCH 1002/2058] Update exports --- ProcessHacker/ProcessHacker.def | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ProcessHacker/ProcessHacker.def b/ProcessHacker/ProcessHacker.def index 1befe9968a7f..27775611f293 100644 --- a/ProcessHacker/ProcessHacker.def +++ b/ProcessHacker/ProcessHacker.def @@ -244,6 +244,7 @@ EXPORTS PhEnumGenericModules PhEnumHandles PhEnumHandlesEx + PhEnumHandlesEx2 PhEnumKernelModules PhEnumPagefiles PhEnumProcessEnvironmentVariables @@ -544,6 +545,7 @@ EXPORTS PhGetMappedImageLoadConfig64 PhInitializeMappedImage PhLoadMappedImage + PhLoadMappedImageEx PhUnloadMappedImage ; settings From de3c0646e700d838a933dd77d2024eae8e8997d5 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 9 Jun 2018 10:35:16 +1000 Subject: [PATCH 1003/2058] Add window icon for services --- ProcessHacker/srvprp.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/ProcessHacker/srvprp.c b/ProcessHacker/srvprp.c index 3f1606aaf83f..302d6f447d83 100644 --- a/ProcessHacker/srvprp.c +++ b/ProcessHacker/srvprp.c @@ -117,6 +117,22 @@ VOID PhShowServiceProperties( propSheetHeader.nPages = 0; propSheetHeader.nStartPage = 0; propSheetHeader.phpage = pages; + + { + if (ServiceItem->SmallIcon) + propSheetHeader.hIcon = ServiceItem->SmallIcon; + else + { + if (ServiceItem->Type == SERVICE_KERNEL_DRIVER || ServiceItem->Type == SERVICE_FILE_SYSTEM_DRIVER) + propSheetHeader.hIcon = PH_LOAD_SHARED_ICON_SMALL(PhInstanceHandle, MAKEINTRESOURCE(IDI_COG)); + else + { + HICON iconSmall; + PhGetStockApplicationIcon(&iconSmall, NULL); + propSheetHeader.hIcon = iconSmall; + } + } + } // General From cd8b43aa9b6b16c874a33921ceb52b211789dbc1 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 9 Jun 2018 10:35:53 +1000 Subject: [PATCH 1004/2058] peview: Fix low-res binary icons --- tools/peview/peprp.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/tools/peview/peprp.c b/tools/peview/peprp.c index 46e753156506..cf971f4186c6 100644 --- a/tools/peview/peprp.c +++ b/tools/peview/peprp.c @@ -45,6 +45,7 @@ INT_PTR CALLBACK PvpPeGeneralDlgProc( PH_MAPPED_IMAGE PvMappedImage; PIMAGE_COR20_HEADER PvImageCor20Header = NULL; PPH_SYMBOL_PROVIDER PvSymbolProvider = NULL; +static HICON PvImageSmallIcon; static HICON PvImageLargeIcon; static PH_IMAGE_VERSION_INFO PvImageVersionInfo; static VERIFY_RESULT PvImageVerifyResult; @@ -374,19 +375,14 @@ VOID PvpSetPeImageVersionInfo( PhInitializeImageVersionInfo(&PvImageVersionInfo, PvFileName->Buffer); - if (!PhExtractIcon( - PvFileName->Buffer, - &PvImageLargeIcon, - NULL - )) + if (!PhExtractIcon(PvFileName->Buffer, &PvImageLargeIcon, &PvImageSmallIcon)) { - PvImageLargeIcon = PhGetFileShellIcon(PvFileName->Buffer, NULL, TRUE); + PhGetStockApplicationIcon(&PvImageSmallIcon, &PvImageLargeIcon); } - if (PvImageLargeIcon) - { - SendMessage(GetDlgItem(WindowHandle, IDC_FILEICON), STM_SETICON, (WPARAM)PvImageLargeIcon, 0); - } + SendMessage(GetParent(WindowHandle), WM_SETICON, ICON_BIG, (LPARAM)PvImageLargeIcon); + SendMessage(GetParent(WindowHandle), WM_SETICON, ICON_SMALL, (LPARAM)PvImageSmallIcon); + Static_SetIcon(GetDlgItem(WindowHandle, IDC_FILEICON), PvImageLargeIcon); string = PhConcatStrings2(L"(Verifying...) ", PvpGetStringOrNa(PvImageVersionInfo.CompanyName)); From f2f761c30bc31d43de52679b14cb8734b2e7bf29 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 9 Jun 2018 10:36:55 +1000 Subject: [PATCH 1005/2058] Tidy up code --- ProcessHacker/plugin.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/ProcessHacker/plugin.c b/ProcessHacker/plugin.c index 3961261dee05..1be39dd73197 100644 --- a/ProcessHacker/plugin.c +++ b/ProcessHacker/plugin.c @@ -475,9 +475,7 @@ PPH_PLUGIN PhRegisterPlugin( if (!fileName) return NULL; - plugin = PhAllocate(sizeof(PH_PLUGIN)); - memset(plugin, 0, sizeof(PH_PLUGIN)); - + plugin = PhAllocateZero(sizeof(PH_PLUGIN)); plugin->Name = pluginName; plugin->DllBase = DllBase; @@ -705,17 +703,15 @@ PPH_EMENU_ITEM PhPluginCreateEMenuItem( _In_opt_ PVOID Context ) { - PPH_EMENU_ITEM item; PPH_PLUGIN_MENU_ITEM pluginMenuItem; + PPH_EMENU_ITEM item; - item = PhCreateEMenuItem(Flags, ID_PLUGIN_MENU_ITEM, Text, NULL, NULL); - - pluginMenuItem = PhAllocate(sizeof(PH_PLUGIN_MENU_ITEM)); - memset(pluginMenuItem, 0, sizeof(PH_PLUGIN_MENU_ITEM)); + pluginMenuItem = PhAllocateZero(sizeof(PH_PLUGIN_MENU_ITEM)); pluginMenuItem->Plugin = Plugin; pluginMenuItem->Id = Id; pluginMenuItem->Context = Context; + item = PhCreateEMenuItem(Flags, ID_PLUGIN_MENU_ITEM, Text, NULL, NULL); item->Context = pluginMenuItem; item->DeleteFunction = PhpPluginEMenuItemDeleteFunction; From ad193e9226b94c471f4330050d23987b87ab5a91 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 9 Jun 2018 10:37:36 +1000 Subject: [PATCH 1006/2058] Tidy up --- ProcessHacker/phsvc/svcmain.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ProcessHacker/phsvc/svcmain.c b/ProcessHacker/phsvc/svcmain.c index 660c55cb3618..ad2482787e4e 100644 --- a/ProcessHacker/phsvc/svcmain.c +++ b/ProcessHacker/phsvc/svcmain.c @@ -48,7 +48,7 @@ NTSTATUS PhSvcMain( if (!Timeout) { - timeout.QuadPart = -15 * PH_TIMEOUT_SEC; + timeout.QuadPart = -(LONGLONG)UInt32x32To64(15, PH_TIMEOUT_SEC); Timeout = &timeout; } From 8cee35c3f1c405566bf52e394032e949cbe631af Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 9 Jun 2018 10:38:08 +1000 Subject: [PATCH 1007/2058] Remove obsolete headers --- ProcessHacker/netprv.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/ProcessHacker/netprv.c b/ProcessHacker/netprv.c index f3dbc170c48b..c3323744add7 100644 --- a/ProcessHacker/netprv.c +++ b/ProcessHacker/netprv.c @@ -23,11 +23,6 @@ #include #include - -#include -#include -#include - #include #include @@ -810,7 +805,7 @@ BOOLEAN PhGetNetworkConnections( GetExtendedTcpTable(NULL, &tableSize, FALSE, AF_INET, TCP_TABLE_OWNER_MODULE_ALL, 0); table = PhAllocate(tableSize); - if (GetExtendedTcpTable(table, &tableSize, FALSE, AF_INET, TCP_TABLE_OWNER_MODULE_ALL, 0) == 0) + if (GetExtendedTcpTable(table, &tableSize, FALSE, AF_INET, TCP_TABLE_OWNER_MODULE_ALL, 0) == NO_ERROR) { tcp4Table = table; count += tcp4Table->dwNumEntries; @@ -828,7 +823,7 @@ BOOLEAN PhGetNetworkConnections( table = PhAllocate(tableSize); - if (GetExtendedTcpTable(table, &tableSize, FALSE, AF_INET6, TCP_TABLE_OWNER_MODULE_ALL, 0) == 0) + if (GetExtendedTcpTable(table, &tableSize, FALSE, AF_INET6, TCP_TABLE_OWNER_MODULE_ALL, 0) == NO_ERROR) { tcp6Table = table; count += tcp6Table->dwNumEntries; @@ -845,7 +840,7 @@ BOOLEAN PhGetNetworkConnections( GetExtendedUdpTable(NULL, &tableSize, FALSE, AF_INET, UDP_TABLE_OWNER_MODULE, 0); table = PhAllocate(tableSize); - if (GetExtendedUdpTable(table, &tableSize, FALSE, AF_INET, UDP_TABLE_OWNER_MODULE, 0) == 0) + if (GetExtendedUdpTable(table, &tableSize, FALSE, AF_INET, UDP_TABLE_OWNER_MODULE, 0) == NO_ERROR) { udp4Table = table; count += udp4Table->dwNumEntries; @@ -862,7 +857,7 @@ BOOLEAN PhGetNetworkConnections( GetExtendedUdpTable(NULL, &tableSize, FALSE, AF_INET6, UDP_TABLE_OWNER_MODULE, 0); table = PhAllocate(tableSize); - if (GetExtendedUdpTable(table, &tableSize, FALSE, AF_INET6, UDP_TABLE_OWNER_MODULE, 0) == 0) + if (GetExtendedUdpTable(table, &tableSize, FALSE, AF_INET6, UDP_TABLE_OWNER_MODULE, 0) == NO_ERROR) { udp6Table = table; count += udp6Table->dwNumEntries; From 6e4620db15964d78fcd317a946b1ab4eeddaa33f Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 9 Jun 2018 10:39:32 +1000 Subject: [PATCH 1008/2058] Update network node UniqueId type --- ProcessHacker/include/netlist.h | 2 +- ProcessHacker/netlist.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ProcessHacker/include/netlist.h b/ProcessHacker/include/netlist.h index 1268df1a3d34..e1ebe044ef1c 100644 --- a/ProcessHacker/include/netlist.h +++ b/ProcessHacker/include/netlist.h @@ -30,7 +30,7 @@ typedef struct _PH_NETWORK_NODE PH_STRINGREF TextCache[PHNETLC_MAXIMUM]; - LONG UniqueId; + ULONG UniqueId; PPH_STRING ProcessNameText; PPH_STRING TimeStampText; diff --git a/ProcessHacker/netlist.c b/ProcessHacker/netlist.c index e6dcdb1118c8..9268608cc7d2 100644 --- a/ProcessHacker/netlist.c +++ b/ProcessHacker/netlist.c @@ -74,7 +74,7 @@ static PH_CM_MANAGER NetworkTreeListCm; static PPH_HASHTABLE NetworkNodeHashtable; // hashtable of all nodes static PPH_LIST NetworkNodeList; // list of all nodes -static LONG NextUniqueId = 1; +static ULONG NextUniqueId = 1; BOOLEAN PhNetworkTreeListStateHighlighting = TRUE; static PPH_POINTER_LIST NetworkNodeStateList = NULL; // list of nodes which need to be processed @@ -345,7 +345,7 @@ VOID PhTickNetworkNodes( #define END_SORT_FUNCTION \ if (sortResult == 0) \ - sortResult = intcmp(node1->UniqueId, node2->UniqueId); \ + sortResult = uintcmp(node1->UniqueId, node2->UniqueId); \ \ return PhModifySort(sortResult, NetworkTreeListSortOrder); \ } @@ -358,7 +358,7 @@ LONG PhpNetworkTreeNewPostSortFunction( ) { if (Result == 0) - Result = intcmp(((PPH_NETWORK_NODE)Node1)->UniqueId, ((PPH_NETWORK_NODE)Node2)->UniqueId); + Result = uintcmp(((PPH_NETWORK_NODE)Node1)->UniqueId, ((PPH_NETWORK_NODE)Node2)->UniqueId); return PhModifySort(Result, SortOrder); } From 75976fddced93d340f0350bbe89942c699fcc3c4 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 9 Jun 2018 10:40:12 +1000 Subject: [PATCH 1009/2058] Fix typo --- ProcessHacker/mainwnd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index b9b9768e7043..0a17687c3e48 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -480,7 +480,7 @@ NTSTATUS PhMwpLoadStage1Worker( { // If the update interval is too large, the user might have to wait a while before seeing some types of // process-related data. We force an update by boosting the provider shortly after the program - // starts up to either make things appear more quickly. + // starts up to make things appear more quickly. if (PhCsUpdateInterval > PH_FLUSH_PROCESS_QUERY_DATA_INTERVAL_LONG_TERM) { From fb129bbf0ee4d3aee0ee2985618f1cf7b490770b Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 9 Jun 2018 10:40:38 +1000 Subject: [PATCH 1010/2058] Remove NtAlpcQueryInformation delayload --- ProcessHacker/anawait.c | 20 ++------------------ 1 file changed, 2 insertions(+), 18 deletions(-) diff --git a/ProcessHacker/anawait.c b/ProcessHacker/anawait.c index edec34cd8b7f..0a18c6653c8b 100644 --- a/ProcessHacker/anawait.c +++ b/ProcessHacker/anawait.c @@ -44,14 +44,6 @@ typedef HWND (WINAPI *_GetSendMessageReceiver)( _In_ HANDLE ThreadId ); -typedef NTSTATUS (NTAPI *_NtAlpcQueryInformation)( - _In_ HANDLE PortHandle, - _In_ ALPC_PORT_INFORMATION_CLASS PortInformationClass, - _Out_writes_bytes_(Length) PVOID PortInformation, - _In_ ULONG Length, - _Out_opt_ PULONG ReturnLength - ); - typedef struct _ANALYZE_WAIT_CONTEXT { BOOLEAN Found; @@ -1012,20 +1004,12 @@ static PPH_STRING PhpaGetAlpcInformation( _In_ HANDLE ThreadId ) { - static _NtAlpcQueryInformation NtAlpcQueryInformation_I; - NTSTATUS status; PPH_STRING string = NULL; HANDLE threadHandle; PALPC_SERVER_INFORMATION serverInfo; ULONG bufferLength; - if (!NtAlpcQueryInformation_I) - NtAlpcQueryInformation_I = PhGetDllProcedureAddress(L"ntdll.dll", "NtAlpcQueryInformation", 0); - - if (!NtAlpcQueryInformation_I) - return NULL; - if (!NT_SUCCESS(PhOpenThread(&threadHandle, THREAD_QUERY_INFORMATION, ThreadId))) return NULL; @@ -1033,7 +1017,7 @@ static PPH_STRING PhpaGetAlpcInformation( serverInfo = PhAllocate(bufferLength); serverInfo->In.ThreadHandle = threadHandle; - status = NtAlpcQueryInformation_I(NULL, AlpcServerInformation, serverInfo, bufferLength, &bufferLength); + status = NtAlpcQueryInformation(NULL, AlpcServerInformation, serverInfo, bufferLength, &bufferLength); if (status == STATUS_INFO_LENGTH_MISMATCH) { @@ -1041,7 +1025,7 @@ static PPH_STRING PhpaGetAlpcInformation( serverInfo = PhAllocate(bufferLength); serverInfo->In.ThreadHandle = threadHandle; - status = NtAlpcQueryInformation_I(NULL, AlpcServerInformation, serverInfo, bufferLength, &bufferLength); + status = NtAlpcQueryInformation(NULL, AlpcServerInformation, serverInfo, bufferLength, &bufferLength); } if (NT_SUCCESS(status) && serverInfo->Out.ThreadBlocked) From 6a296c8ac29090ec9f626e4e0d94a6eeb3cdabab Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 9 Jun 2018 10:44:39 +1000 Subject: [PATCH 1011/2058] Fix treenew custom highlighting regression on win7 https://wj32.org/processhacker/forums/viewtopic.php?f=24&t=2916 --- phlib/treenew.c | 80 +++++++++++++++++++++++++++---------------------- 1 file changed, 44 insertions(+), 36 deletions(-) diff --git a/phlib/treenew.c b/phlib/treenew.c index 39ba1671093f..528e5aaf2f0c 100644 --- a/phlib/treenew.c +++ b/phlib/treenew.c @@ -5065,70 +5065,78 @@ VOID PhTnpPaint( for (i = firstRowToUpdate; i <= lastRowToUpdate; i++) { - INT stateId; - node = Context->FlatList->Items[i]; // Prepare the row for drawing. PhTnpPrepareRowForDraw(Context, hdc, node); - if (node->Selected) - { - if (i == Context->HotNodeIndex) - stateId = TREIS_HOTSELECTED; - else if (!Context->HasFocus) - stateId = TREIS_SELECTEDNOTFOCUS; - else - stateId = TREIS_SELECTED; - } - else + if (node->Selected && (Context->CustomColors || !Context->ThemeHasItemBackground)) { - if (i == Context->HotNodeIndex) - stateId = TREIS_HOT; - else - stateId = -1; - } + // Non-themed background - if (Context->CustomColors || !Context->ThemeHasItemBackground) - { - switch (stateId) + if (Context->HasFocus) { - case TREIS_SELECTED: - case TREIS_SELECTEDNOTFOCUS: + if (Context->CustomColors) { SetTextColor(hdc, Context->CustomTextColor); - SetDCBrushColor(hdc, Context->CustomSelectedColor); + SetDCBrushColor(hdc, Context->CustomFocusColor); + FillRect(hdc, &rowRect, GetStockObject(DC_BRUSH)); } - break; - case TREIS_HOT: - case TREIS_HOTSELECTED: + else + { + SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT)); + FillRect(hdc, &rowRect, GetSysColorBrush(COLOR_HIGHLIGHT)); + } + } + else + { + if (Context->CustomColors) { SetTextColor(hdc, Context->CustomTextColor); - SetDCBrushColor(hdc, Context->CustomFocusColor); + SetDCBrushColor(hdc, Context->CustomSelectedColor); + FillRect(hdc, &rowRect, GetStockObject(DC_BRUSH)); } - break; - default: + else { - SetTextColor(hdc, node->s.DrawForeColor); - SetDCBrushColor(hdc, node->s.DrawBackColor); + SetTextColor(hdc, GetSysColor(COLOR_BTNTEXT)); + FillRect(hdc, &rowRect, GetSysColorBrush(COLOR_BTNFACE)); } - break; } - } + } else { SetTextColor(hdc, node->s.DrawForeColor); SetDCBrushColor(hdc, node->s.DrawBackColor); + FillRect(hdc, &rowRect, GetStockObject(DC_BRUSH)); } - FillRect(hdc, &rowRect, GetStockObject(DC_BRUSH)); - if (!Context->CustomColors && Context->ThemeHasItemBackground) { + INT stateId; + + // Themed background + + if (node->Selected) + { + if (i == Context->HotNodeIndex) + stateId = TREIS_HOTSELECTED; + else if (!Context->HasFocus) + stateId = TREIS_SELECTEDNOTFOCUS; + else + stateId = TREIS_SELECTED; + } + else + { + if (i == Context->HotNodeIndex) + stateId = TREIS_HOT; + else + stateId = INT_MAX; + } + // Themed background - if (stateId != -1) + if (stateId != INT_MAX) { if (!Context->FixedColumnVisible) { From 4da3041db83b14c1d152b1677e1e0735fa9ef455 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 9 Jun 2018 10:45:40 +1000 Subject: [PATCH 1012/2058] CommonUtil: Update http status codes --- plugins/CommonUtil/http.h | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/CommonUtil/http.h b/plugins/CommonUtil/http.h index 52f56dc2db26..8b5ce31f818f 100644 --- a/plugins/CommonUtil/http.h +++ b/plugins/CommonUtil/http.h @@ -100,6 +100,7 @@ PhHttpSocketQueryHeaderString( // status codes #define PH_HTTP_STATUS_OK 200 // request completed +#define PH_HTTP_STATUS_CREATED 201 #define PH_HTTP_STATUS_REDIRECT_METHOD 303 // redirection w/ new access method #define PH_HTTP_STATUS_REDIRECT 302 // object temporarily moved From f0f1194b2de46665719c800a21cf9bec2975737e Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 9 Jun 2018 10:46:05 +1000 Subject: [PATCH 1013/2058] ExtendedNotifications: Fix deprecated winsock warnings --- plugins/ExtendedNotifications/gntp-send/tcp.c | 38 ++++++++++++------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/plugins/ExtendedNotifications/gntp-send/tcp.c b/plugins/ExtendedNotifications/gntp-send/tcp.c index f47fa7f4fdd8..dc9d7377b7fa 100644 --- a/plugins/ExtendedNotifications/gntp-send/tcp.c +++ b/plugins/ExtendedNotifications/gntp-send/tcp.c @@ -95,19 +95,19 @@ SOCKET growl_tcp_open(const char* server) { } if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) { - perror("create socket"); + //perror("create socket"); return INVALID_SOCKET; } if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) == SOCKET_ERROR) { - perror("connect"); + //perror("connect"); closesocket(sock); // dmex: fixed handle leaking on error return INVALID_SOCKET; } on = 1; if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)) == SOCKET_ERROR) { - perror("setsockopt"); + //perror("setsockopt"); closesocket(sock); // dmex: fixed handle leaking on error return INVALID_SOCKET; } @@ -124,31 +124,43 @@ void growl_tcp_close(SOCKET sock) { #endif } +/* dmex: modified to use getaddrinfo */ int growl_tcp_parse_hostname( const char *const server , int default_port , struct sockaddr_in *const sockaddr ) { + struct addrinfo *result = NULL; + struct addrinfo hints = { 0 }; char *hostname = PhDuplicateBytesZSafe((PSTR)server); char *port = strchr( hostname, ':' ); - struct hostent* host_ent; - if( port != NULL ) + + if (port) { *port = '\0'; port++; default_port = atoi(port); } - host_ent = gethostbyname(hostname); - if( host_ent == NULL ) + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + + if (getaddrinfo(hostname, NULL, &hints, &result) != 0) { - perror("gethostbyname"); PhFree(hostname); return -1; } - // dmex: fixed wrong sizeof argument - memset( sockaddr , 0 , sizeof(struct sockaddr_in) ); - sockaddr->sin_family = AF_INET; - memcpy( &sockaddr->sin_addr , host_ent->h_addr , host_ent->h_length ); - sockaddr->sin_port = htons(default_port); + // dmex: Copy the first result. + memset(sockaddr, 0, sizeof(struct sockaddr_in)); + sockaddr->sin_family = result->ai_family; + sockaddr->sin_port = _byteswap_ushort(default_port); + memcpy_s( + &sockaddr->sin_addr, + sizeof(sockaddr->sin_addr), + &((struct sockaddr_in*)result->ai_addr)->sin_addr, + sizeof(((struct sockaddr_in*)result->ai_addr)->sin_addr) + ); + + freeaddrinfo(result); PhFree(hostname); return 0; From c8144c61114115c663aac4fdf16d2a3bd1441bb8 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 9 Jun 2018 11:06:06 +1000 Subject: [PATCH 1014/2058] ExtendedTools: Fix EtpGpuDetailsEnumAdapters using incorrect memset, Tidy up code --- plugins/ExtendedTools/gpudetails.c | 6 +--- plugins/ExtendedTools/gpumon.c | 48 +++++++++++++++++++----------- plugins/ExtendedTools/gpunodes.c | 7 +++-- plugins/ExtendedTools/gpuprprp.c | 8 ++--- plugins/ExtendedTools/gpusys.c | 10 +++---- 5 files changed, 41 insertions(+), 38 deletions(-) diff --git a/plugins/ExtendedTools/gpudetails.c b/plugins/ExtendedTools/gpudetails.c index e13c1d9bc8f5..09c88b5dd140 100644 --- a/plugins/ExtendedTools/gpudetails.c +++ b/plugins/ExtendedTools/gpudetails.c @@ -265,7 +265,7 @@ VOID EtpGpuDetailsEnumAdapters( { gpuAdapter = EtpGpuAdapterList->Items[i]; - memset(&openAdapterFromDeviceName, 0, sizeof(D3DKMT_OPENADAPTERFROMLUID)); + memset(&openAdapterFromDeviceName, 0, sizeof(D3DKMT_OPENADAPTERFROMDEVICENAME)); openAdapterFromDeviceName.DeviceName = PhGetString(gpuAdapter->DeviceInterface); if (!NT_SUCCESS(D3DKMTOpenAdapterFromDeviceName(&openAdapterFromDeviceName))) @@ -329,10 +329,6 @@ INT_PTR CALLBACK EtpGpuDetailsDlgProc( PhAddLayoutItem(&LayoutManager, listViewHandle, NULL, PH_ANCHOR_ALL); PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDOK), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); - // Note: This dialog must be centered after all other graphs and controls have been added. - //if (PhGetIntegerPairSetting(SETTING_NAME_GPU_NODES_WINDOW_POSITION).X != 0) - // PhLoadWindowPlacementFromSetting(SETTING_NAME_GPU_NODES_WINDOW_POSITION, SETTING_NAME_GPU_NODES_WINDOW_SIZE, hwndDlg); - //else PhCenterWindow(hwndDlg, GetParent(hwndDlg)); EtpGpuDetailsEnumAdapters(listViewHandle); diff --git a/plugins/ExtendedTools/gpumon.c b/plugins/ExtendedTools/gpumon.c index ba2b817f11d1..e157cf840b8d 100644 --- a/plugins/ExtendedTools/gpumon.c +++ b/plugins/ExtendedTools/gpumon.c @@ -24,7 +24,6 @@ #define INITGUID #include "exttools.h" #include -#include #include #include "gpumon.h" @@ -78,10 +77,7 @@ VOID EtGpuMonitorInitialization( PhInitializeCircularBuffer_ULONG(&EtGpuDedicatedHistory, sampleCount); PhInitializeCircularBuffer_ULONG(&EtGpuSharedHistory, sampleCount); - PhInitializeDelta(&EtClockTotalRunningTimeDelta); - - EtGpuNodesTotalRunningTimeDelta = PhAllocate(sizeof(PH_UINT64_DELTA) * EtGpuTotalNodeCount); - memset(EtGpuNodesTotalRunningTimeDelta, 0, sizeof(PH_UINT64_DELTA) * EtGpuTotalNodeCount); + EtGpuNodesTotalRunningTimeDelta = PhAllocateZero(sizeof(PH_UINT64_DELTA) * EtGpuTotalNodeCount); EtGpuNodesHistory = PhAllocate(sizeof(PH_CIRCULAR_BUFFER_FLOAT) * EtGpuTotalNodeCount); for (i = 0; i < EtGpuTotalNodeCount; i++) @@ -129,6 +125,27 @@ BOOLEAN EtCloseAdapterHandle( return NT_SUCCESS(D3DKMTCloseAdapter(&closeAdapter)); } +D3DKMT_DRIVERVERSION EtpGetGpuWddmVersion( + _In_ D3DKMT_HANDLE AdapterHandle + ) +{ + D3DKMT_DRIVERVERSION driverVersion; + + memset(&driverVersion, 0, sizeof(D3DKMT_DRIVERVERSION)); + + if (NT_SUCCESS(EtQueryAdapterInformation( + AdapterHandle, + KMTQAITYPE_DRIVERVERSION, + &driverVersion, + sizeof(D3DKMT_ADAPTERTYPE) + ))) + { + return driverVersion; + } + + return KMT_DRIVERVERSION_WDDM_1_0; +} + BOOLEAN EtpIsGpuSoftwareDevice( _In_ D3DKMT_HANDLE AdapterHandle ) @@ -144,7 +161,7 @@ BOOLEAN EtpIsGpuSoftwareDevice( sizeof(D3DKMT_ADAPTERTYPE) ))) { - if (adapterType.SoftwareDevice) + if (adapterType.SoftwareDevice) // adapterType.HybridIntegrated { return TRUE; } @@ -324,7 +341,7 @@ PPH_STRING EtpQueryDeviceRegistryProperty( } // Note: MSDN states this value must be created by video devices BUT Task Manager -// doesn't query this value and I currently don't know where it's querying this information. +// doesn't query this value and I currently don't know where it's getting the gpu memory information. // https://docs.microsoft.com/en-us/windows-hardware/drivers/display/registering-hardware-information ULONG64 EtpQueryGpuInstalledMemory( _In_ DEVINST DeviceHandle @@ -420,7 +437,6 @@ D3D_FEATURE_LEVEL EtQueryAdapterFeatureLevel( D3D_FEATURE_LEVEL d3dFeatureLevelResult = 0; IDXGIFactory1 *dxgiFactory; IDXGIAdapter* dxgiAdapter; - UINT i = 0; if (PhBeginInitOnce(&initOnce)) { @@ -444,7 +460,7 @@ D3D_FEATURE_LEVEL EtQueryAdapterFeatureLevel( if (SUCCEEDED(IDXGIAdapter_GetDesc(dxgiAdapter, &dxgiAdapterDescription))) { - if (RtlEqualMemory(&dxgiAdapterDescription.AdapterLuid, &AdapterLuid, sizeof(LUID))) + if (RtlIsEqualLuid(&dxgiAdapterDescription.AdapterLuid, &AdapterLuid)) { D3D_FEATURE_LEVEL d3dFeatureLevel[] = { @@ -476,6 +492,7 @@ D3D_FEATURE_LEVEL EtQueryAdapterFeatureLevel( { d3dFeatureLevelResult = d3ddeviceFeatureLevel; ID3D11Device_Release(d3d11device); + IDXGIAdapter_Release(dxgiAdapter); break; } } @@ -887,7 +904,6 @@ VOID NTAPI EtGpuProcessesUpdatedCallback( ) { static ULONG runCount = 0; // MUST keep in sync with runCount in process provider - DOUBLE elapsedTime; // total GPU node elapsed time in micro-seconds FLOAT tempGpuUsage; ULONG i; @@ -901,24 +917,20 @@ VOID NTAPI EtGpuProcessesUpdatedCallback( // Update global gpu usage. tempGpuUsage = 0; - elapsedTime = (DOUBLE)EtClockTotalRunningTimeDelta.Delta * 10000000 / EtClockTotalRunningTimeFrequency.QuadPart; + elapsedTime = (DOUBLE)(EtClockTotalRunningTimeDelta.Delta * 10000000ULL / EtClockTotalRunningTimeFrequency.QuadPart); if (elapsedTime != 0) { for (i = 0; i < EtGpuTotalNodeCount; i++) { - FLOAT usage; + FLOAT usage = (FLOAT)(EtGpuNodesTotalRunningTimeDelta[i].Delta / elapsedTime); - usage = (FLOAT)(EtGpuNodesTotalRunningTimeDelta[i].Delta / elapsedTime); + if (usage > 1) + usage = 1; if (usage > tempGpuUsage) - { tempGpuUsage = usage; - } } - - if (tempGpuUsage > 1) - tempGpuUsage = 1; } EtGpuNodeUsage = tempGpuUsage; diff --git a/plugins/ExtendedTools/gpunodes.c b/plugins/ExtendedTools/gpunodes.c index 1e7adc192f96..af860bf08dde 100644 --- a/plugins/ExtendedTools/gpunodes.c +++ b/plugins/ExtendedTools/gpunodes.c @@ -56,11 +56,12 @@ NTSTATUS EtpGpuNodesDialogThreadStart( PhInitializeAutoPool(&autoPool); - EtGpuNodesWindowHandle = CreateDialog( + EtGpuNodesWindowHandle = CreateDialogParam( PluginInstance->DllBase, MAKEINTRESOURCE(IDD_GPUNODES), NULL, - EtpGpuNodesDlgProc + EtpGpuNodesDlgProc, + (LPARAM)Parameter ); PhSetEvent(&EtGpuNodesInitializedEvent); @@ -180,7 +181,7 @@ INT_PTR CALLBACK EtpGpuNodesDlgProc( if (PhGetIntegerPairSetting(SETTING_NAME_GPU_NODES_WINDOW_POSITION).X != 0) PhLoadWindowPlacementFromSetting(SETTING_NAME_GPU_NODES_WINDOW_POSITION, SETTING_NAME_GPU_NODES_WINDOW_SIZE, hwndDlg); else - PhCenterWindow(hwndDlg, GetParent(hwndDlg)); + PhCenterWindow(hwndDlg, (HWND)lParam); PhRegisterCallback( &PhProcessesUpdatedEvent, diff --git a/plugins/ExtendedTools/gpuprprp.c b/plugins/ExtendedTools/gpuprprp.c index bfd8decd0229..a0e460533bd3 100644 --- a/plugins/ExtendedTools/gpuprprp.c +++ b/plugins/ExtendedTools/gpuprprp.c @@ -654,9 +654,7 @@ INT_PTR CALLBACK EtpGpuPageDlgProc( if (!context->MemoryGraphState.Valid) { - ULONG i = 0; - - for (i = 0; i < drawInfo->LineDataCount; i++) + for (ULONG i = 0; i < drawInfo->LineDataCount; i++) { context->MemoryGraphState.Data1[i] = (FLOAT)PhGetItemCircularBuffer_ULONG(&context->MemoryHistory, i); } @@ -704,9 +702,7 @@ INT_PTR CALLBACK EtpGpuPageDlgProc( if (!context->MemorySharedGraphState.Valid) { - ULONG i = 0; - - for (i = 0; i < drawInfo->LineDataCount; i++) + for (ULONG i = 0; i < drawInfo->LineDataCount; i++) { context->MemorySharedGraphState.Data1[i] = (FLOAT)PhGetItemCircularBuffer_ULONG(&context->MemorySharedHistory, i); } diff --git a/plugins/ExtendedTools/gpusys.c b/plugins/ExtendedTools/gpusys.c index 61dc2d6b2a7a..fc9652acd4a1 100644 --- a/plugins/ExtendedTools/gpusys.c +++ b/plugins/ExtendedTools/gpusys.c @@ -514,8 +514,7 @@ VOID EtpNotifyDedicatedGraph( { for (i = 0; i < drawInfo->LineDataCount; i++) { - DedicatedGraphState.Data1[i] = - (FLOAT)PhGetItemCircularBuffer_ULONG(&EtGpuDedicatedHistory, i); + DedicatedGraphState.Data1[i] = (FLOAT)PhGetItemCircularBuffer_ULONG(&EtGpuDedicatedHistory, i); } if (EtGpuDedicatedLimit != 0) @@ -546,7 +545,7 @@ VOID EtpNotifyDedicatedGraph( PhMoveReference(&DedicatedGraphState.TooltipText, PhFormatString( L"Dedicated Memory: %s\n%s", - PhaFormatSize(UInt32x32To64(usedPages, PAGE_SIZE), -1)->Buffer, + PhaFormatSize(UInt32x32To64(usedPages, PAGE_SIZE), ULONG_MAX)->Buffer, ((PPH_STRING)PH_AUTO(PhGetStatisticsTimeString(NULL, getTooltipText->Index)))->Buffer )); } @@ -583,8 +582,7 @@ VOID EtpNotifySharedGraph( { for (i = 0; i < drawInfo->LineDataCount; i++) { - SharedGraphState.Data1[i] = - (FLOAT)PhGetItemCircularBuffer_ULONG(&EtGpuSharedHistory, i); + SharedGraphState.Data1[i] = (FLOAT)PhGetItemCircularBuffer_ULONG(&EtGpuSharedHistory, i); } if (EtGpuSharedLimit != 0) @@ -615,7 +613,7 @@ VOID EtpNotifySharedGraph( PhMoveReference(&SharedGraphState.TooltipText, PhFormatString( L"Shared Memory: %s\n%s", - PhaFormatSize(UInt32x32To64(usedPages, PAGE_SIZE), -1)->Buffer, + PhaFormatSize(UInt32x32To64(usedPages, PAGE_SIZE), ULONG_MAX)->Buffer, ((PPH_STRING)PH_AUTO(PhGetStatisticsTimeString(NULL, getTooltipText->Index)))->Buffer )); } From e2d793289dede80f6e3bda26d6478dc58b20b7f8 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 9 Jun 2018 11:06:51 +1000 Subject: [PATCH 1015/2058] ExtendedServices: Fix progressbar style --- plugins/ExtendedServices/ExtendedServices.rc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/ExtendedServices/ExtendedServices.rc b/plugins/ExtendedServices/ExtendedServices.rc index 8c2bd9083285..b3ffb34c5fca 100644 --- a/plugins/ExtendedServices/ExtendedServices.rc +++ b/plugins/ExtendedServices/ExtendedServices.rc @@ -154,7 +154,7 @@ FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN PUSHBUTTON "Cancel",IDCANCEL,147,40,50,14 LTEXT "Progress",IDC_MESSAGE,7,7,190,8,SS_ENDELLIPSIS - CONTROL "",IDC_PROGRESS,"msctls_progress32",WS_BORDER,7,21,190,14 + CONTROL "",IDC_PROGRESS,"msctls_progress32",0x0,7,21,190,14 END IDD_SRVOTHER DIALOGEX 0, 0, 282, 218 From 6b44c4fb175c819284a4d45d46dfdfa66636e58f Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 9 Jun 2018 11:16:15 +1000 Subject: [PATCH 1016/2058] NetworkTools: Fix tracert hop setting, Fix ipv6 address resolution, Remove windns dependencies, Fix phsdk winsock conflicts --- plugins/NetworkTools/NetworkTools.vcxproj | 16 +-- plugins/NetworkTools/country.c | 3 + plugins/NetworkTools/main.c | 143 ++++++++++++---------- plugins/NetworkTools/nettools.h | 40 ++---- plugins/NetworkTools/tracert.c | 92 +++++++------- plugins/NetworkTools/tracert.h | 2 +- plugins/NetworkTools/tracetree.c | 12 +- 7 files changed, 156 insertions(+), 152 deletions(-) diff --git a/plugins/NetworkTools/NetworkTools.vcxproj b/plugins/NetworkTools/NetworkTools.vcxproj index 1816eb38bb39..fa9d18f8b524 100644 --- a/plugins/NetworkTools/NetworkTools.vcxproj +++ b/plugins/NetworkTools/NetworkTools.vcxproj @@ -56,27 +56,27 @@ - dnsapi.lib;iphlpapi.lib;winhttp.lib;ws2_32.lib;uxtheme.lib;%(AdditionalDependencies) - dnsapi.dll;iphlpapi.dll;winhttp.dll;ws2_32.dll;%(DelayLoadDLLs) + iphlpapi.lib;winhttp.lib;ws2_32.lib;uxtheme.lib;%(AdditionalDependencies) + iphlpapi.dll;winhttp.dll;ws2_32.dll;%(DelayLoadDLLs) - dnsapi.lib;iphlpapi.lib;winhttp.lib;ws2_32.lib;uxtheme.lib;%(AdditionalDependencies) - dnsapi.dll;iphlpapi.dll;winhttp.dll;ws2_32.dll;%(DelayLoadDLLs) + iphlpapi.lib;winhttp.lib;ws2_32.lib;uxtheme.lib;%(AdditionalDependencies) + iphlpapi.dll;winhttp.dll;ws2_32.dll;%(DelayLoadDLLs) - dnsapi.lib;iphlpapi.lib;winhttp.lib;ws2_32.lib;uxtheme.lib;%(AdditionalDependencies) - dnsapi.dll;iphlpapi.dll;winhttp.dll;ws2_32.dll;%(DelayLoadDLLs) + iphlpapi.lib;winhttp.lib;ws2_32.lib;uxtheme.lib;%(AdditionalDependencies) + iphlpapi.dll;winhttp.dll;ws2_32.dll;%(DelayLoadDLLs) - dnsapi.lib;iphlpapi.lib;winhttp.lib;ws2_32.lib;uxtheme.lib;%(AdditionalDependencies) - dnsapi.dll;iphlpapi.dll;winhttp.dll;ws2_32.dll;%(DelayLoadDLLs) + iphlpapi.lib;winhttp.lib;ws2_32.lib;uxtheme.lib;%(AdditionalDependencies) + iphlpapi.dll;winhttp.dll;ws2_32.dll;%(DelayLoadDLLs) diff --git a/plugins/NetworkTools/country.c b/plugins/NetworkTools/country.c index b1db05f2f499..283cfb9d9902 100644 --- a/plugins/NetworkTools/country.c +++ b/plugins/NetworkTools/country.c @@ -223,6 +223,9 @@ BOOLEAN LookupCountryCode( if (IN4_IS_ADDR_LOOPBACK(&RemoteAddress.InAddr)) return FALSE; + if (IN4_IS_ADDR_RFC1918(&RemoteAddress.InAddr)) + return FALSE; + memset(&ipv4SockAddr, 0, sizeof(SOCKADDR_IN)); memset(&mmdb_result, 0, sizeof(MMDB_lookup_result_s)); diff --git a/plugins/NetworkTools/main.c b/plugins/NetworkTools/main.c index 7a9b2c9a6d08..b5a09c71ca74 100644 --- a/plugins/NetworkTools/main.c +++ b/plugins/NetworkTools/main.c @@ -69,14 +69,27 @@ VOID NTAPI ShowOptionsCallback( ); } -static BOOLEAN ValidAddressInfo( - _In_ PPH_IP_ENDPOINT RemoteEndpoint, - _In_ PPH_STRING Name +static BOOLEAN ParseNetworkAddress( + _In_ PWSTR AddressString, + _Out_ PPH_IP_ENDPOINT RemoteEndpoint ) { - PWSTR terminator = NULL; + NET_ADDRESS_INFO addressInfo; - if (DnsValidateName(Name->Buffer, DnsNameValidateTld) == ERROR_SUCCESS) + memset(&addressInfo, 0, sizeof(NET_ADDRESS_INFO)); + + if (ParseNetworkString( + AddressString, + NET_STRING_ANY_ADDRESS | NET_STRING_ANY_SERVICE, + &addressInfo, + NULL, + NULL + ) != ERROR_SUCCESS) + { + return FALSE; + } + + if (addressInfo.Format == NET_ADDRESS_DNS_NAME) { BOOLEAN success = FALSE; PADDRINFOT result; @@ -84,26 +97,27 @@ static BOOLEAN ValidAddressInfo( WSAStartup(WINSOCK_VERSION, &wsaData); - if (GetAddrInfo(Name->Buffer, NULL, NULL, &result) == ERROR_SUCCESS) + if (GetAddrInfo(addressInfo.NamedAddress.Address, addressInfo.NamedAddress.Port, NULL, &result) == ERROR_SUCCESS) { for (PADDRINFOT i = result; i; i = i->ai_next) { if (i->ai_family == AF_INET) { RemoteEndpoint->Address.InAddr.s_addr = ((PSOCKADDR_IN)i->ai_addr)->sin_addr.s_addr; - RemoteEndpoint->Port = ((PSOCKADDR_IN)i->ai_addr)->sin_port; + RemoteEndpoint->Port = _byteswap_ushort(((PSOCKADDR_IN)i->ai_addr)->sin_port); RemoteEndpoint->Address.Type = PH_IPV4_NETWORK_TYPE; success = TRUE; break; } else if (i->ai_family == AF_INET6) { - memcpy( + memcpy_s( RemoteEndpoint->Address.In6Addr.s6_addr, + sizeof(RemoteEndpoint->Address.In6Addr.s6_addr), ((PSOCKADDR_IN6)i->ai_addr)->sin6_addr.s6_addr, - sizeof(RemoteEndpoint->Address.In6Addr.s6_addr) + sizeof(((PSOCKADDR_IN6)i->ai_addr)->sin6_addr.s6_addr) ); - RemoteEndpoint->Port = ((PSOCKADDR_IN6)i->ai_addr)->sin6_port; + RemoteEndpoint->Port = _byteswap_ushort(((PSOCKADDR_IN6)i->ai_addr)->sin6_port); RemoteEndpoint->Address.Type = PH_IPV6_NETWORK_TYPE; success = TRUE; break; @@ -118,28 +132,26 @@ static BOOLEAN ValidAddressInfo( if (success) return TRUE; } - else + + if (addressInfo.Format == NET_ADDRESS_IPV4) { - if (NT_SUCCESS(RtlIpv4StringToAddress( - Name->Buffer, - TRUE, - &terminator, - &RemoteEndpoint->Address.InAddr - ))) - { - RemoteEndpoint->Address.Type = PH_IPV4_NETWORK_TYPE; - return TRUE; - } + RemoteEndpoint->Address.InAddr.s_addr = addressInfo.Ipv4Address.sin_addr.s_addr; + RemoteEndpoint->Port = _byteswap_ushort(addressInfo.Ipv4Address.sin_port); + RemoteEndpoint->Address.Type = PH_IPV4_NETWORK_TYPE; + return TRUE; + } - if (NT_SUCCESS(RtlIpv6StringToAddress( - Name->Buffer, - &terminator, - &RemoteEndpoint->Address.In6Addr - ))) - { - RemoteEndpoint->Address.Type = PH_IPV6_NETWORK_TYPE; - return TRUE; - } + if (addressInfo.Format == NET_ADDRESS_IPV6) + { + memcpy_s( + RemoteEndpoint->Address.In6Addr.s6_addr, + sizeof(RemoteEndpoint->Address.In6Addr.s6_addr), + addressInfo.Ipv6Address.sin6_addr.s6_addr, + sizeof(addressInfo.Ipv6Address.sin6_addr.s6_addr) + ); + RemoteEndpoint->Port = _byteswap_ushort(addressInfo.Ipv6Address.sin6_port); + RemoteEndpoint->Address.Type = PH_IPV6_NETWORK_TYPE; + return TRUE; } return FALSE; @@ -182,7 +194,7 @@ VOID NTAPI MenuItemCallback( SETTING_NAME_ADDRESS_HISTORY )) { - if (ValidAddressInfo(&remoteEndpoint, selectedChoice)) + if (ParseNetworkAddress(selectedChoice->Buffer, &remoteEndpoint)) { ShowPingWindowFromAddress(remoteEndpoint); break; @@ -208,7 +220,7 @@ VOID NTAPI MenuItemCallback( SETTING_NAME_ADDRESS_HISTORY )) { - if (ValidAddressInfo(&remoteEndpoint, selectedChoice)) + if (ParseNetworkAddress(selectedChoice->Buffer, &remoteEndpoint)) { ShowTracertWindowFromAddress(remoteEndpoint); break; @@ -234,7 +246,7 @@ VOID NTAPI MenuItemCallback( SETTING_NAME_ADDRESS_HISTORY )) { - if (ValidAddressInfo(&remoteEndpoint, selectedChoice)) + if (ParseNetworkAddress(selectedChoice->Buffer, &remoteEndpoint)) { ShowWhoisWindowFromAddress(remoteEndpoint); break; @@ -260,12 +272,12 @@ VOID NTAPI MainMenuInitializingCallback( return; networkToolsMenu = PhPluginCreateEMenuItem(PluginInstance, 0, 0, L"&Network Tools", NULL); - PhInsertEMenuItem(networkToolsMenu, PhPluginCreateEMenuItem(PluginInstance, 0, MAINMENU_ACTION_GEOIP_UPDATE, L"&GeoIP database update...", NULL), -1); - PhInsertEMenuItem(networkToolsMenu, PhCreateEMenuSeparator(), -1); - PhInsertEMenuItem(networkToolsMenu, PhPluginCreateEMenuItem(PluginInstance, 0, MAINMENU_ACTION_PING, L"&Ping address...", NULL), -1); - PhInsertEMenuItem(networkToolsMenu, PhPluginCreateEMenuItem(PluginInstance, 0, MAINMENU_ACTION_TRACERT, L"&Traceroute address...", NULL), -1); - PhInsertEMenuItem(networkToolsMenu, PhPluginCreateEMenuItem(PluginInstance, 0, MAINMENU_ACTION_WHOIS, L"&Whois address...", NULL), -1); - PhInsertEMenuItem(menuInfo->Menu, networkToolsMenu, -1); + PhInsertEMenuItem(networkToolsMenu, PhPluginCreateEMenuItem(PluginInstance, 0, MAINMENU_ACTION_GEOIP_UPDATE, L"&GeoIP database update...", NULL), ULONG_MAX); + PhInsertEMenuItem(networkToolsMenu, PhCreateEMenuSeparator(), ULONG_MAX); + PhInsertEMenuItem(networkToolsMenu, PhPluginCreateEMenuItem(PluginInstance, 0, MAINMENU_ACTION_PING, L"&Ping address...", NULL), ULONG_MAX); + PhInsertEMenuItem(networkToolsMenu, PhPluginCreateEMenuItem(PluginInstance, 0, MAINMENU_ACTION_TRACERT, L"&Traceroute address...", NULL), ULONG_MAX); + PhInsertEMenuItem(networkToolsMenu, PhPluginCreateEMenuItem(PluginInstance, 0, MAINMENU_ACTION_WHOIS, L"&Whois address...", NULL), ULONG_MAX); + PhInsertEMenuItem(menuInfo->Menu, networkToolsMenu, ULONG_MAX); } VOID NTAPI NetworkMenuInitializingCallback( @@ -284,43 +296,50 @@ VOID NTAPI NetworkMenuInitializingCallback( else networkItem = NULL; - PhInsertEMenuItem(menuInfo->Menu, PhCreateEMenuSeparator(), 0); - PhInsertEMenuItem(menuInfo->Menu, whoisMenu = PhPluginCreateEMenuItem(PluginInstance, 0, NETWORK_ACTION_WHOIS, L"&Whois", networkItem), 0); - PhInsertEMenuItem(menuInfo->Menu, traceMenu = PhPluginCreateEMenuItem(PluginInstance, 0, NETWORK_ACTION_TRACEROUTE, L"&Traceroute", networkItem), 0); PhInsertEMenuItem(menuInfo->Menu, pingMenu = PhPluginCreateEMenuItem(PluginInstance, 0, NETWORK_ACTION_PING, L"&Ping", networkItem), 0); + PhInsertEMenuItem(menuInfo->Menu, traceMenu = PhPluginCreateEMenuItem(PluginInstance, 0, NETWORK_ACTION_TRACEROUTE, L"&Traceroute", networkItem), 1); + PhInsertEMenuItem(menuInfo->Menu, whoisMenu = PhPluginCreateEMenuItem(PluginInstance, 0, NETWORK_ACTION_WHOIS, L"&Whois", networkItem), 2); + PhInsertEMenuItem(menuInfo->Menu, PhCreateEMenuSeparator(), 3); if (networkItem) { if (PhIsNullIpAddress(&networkItem->RemoteEndpoint.Address)) { - whoisMenu->Flags |= PH_EMENU_DISABLED; - traceMenu->Flags |= PH_EMENU_DISABLED; - pingMenu->Flags |= PH_EMENU_DISABLED; + PhSetDisabledEMenuItem(whoisMenu); + PhSetDisabledEMenuItem(traceMenu); + PhSetDisabledEMenuItem(pingMenu); } else if (networkItem->RemoteEndpoint.Address.Type == PH_IPV4_NETWORK_TYPE) { - if (IN4_IS_ADDR_LOOPBACK(&networkItem->RemoteEndpoint.Address.InAddr)) + if ( + IN4_IS_ADDR_UNSPECIFIED(&networkItem->RemoteEndpoint.Address.InAddr) || + IN4_IS_ADDR_LOOPBACK(&networkItem->RemoteEndpoint.Address.InAddr) || + IN4_IS_ADDR_RFC1918(&networkItem->RemoteEndpoint.Address.InAddr) + ) { - whoisMenu->Flags |= PH_EMENU_DISABLED; - traceMenu->Flags |= PH_EMENU_DISABLED; - pingMenu->Flags |= PH_EMENU_DISABLED; + PhSetDisabledEMenuItem(whoisMenu); + PhSetDisabledEMenuItem(traceMenu); + PhSetDisabledEMenuItem(pingMenu); } } - else + else if (networkItem->RemoteEndpoint.Address.Type == PH_IPV6_NETWORK_TYPE) { - if (IN6_IS_ADDR_LOOPBACK(&networkItem->RemoteEndpoint.Address.In6Addr)) + if ( + IN6_IS_ADDR_UNSPECIFIED(&networkItem->RemoteEndpoint.Address.In6Addr) || + IN6_IS_ADDR_LOOPBACK(&networkItem->RemoteEndpoint.Address.In6Addr) + ) { - whoisMenu->Flags |= PH_EMENU_DISABLED; - traceMenu->Flags |= PH_EMENU_DISABLED; - pingMenu->Flags |= PH_EMENU_DISABLED; + PhSetDisabledEMenuItem(whoisMenu); + PhSetDisabledEMenuItem(traceMenu); + PhSetDisabledEMenuItem(pingMenu); } } } else { - whoisMenu->Flags |= PH_EMENU_DISABLED; - traceMenu->Flags |= PH_EMENU_DISABLED; - pingMenu->Flags |= PH_EMENU_DISABLED; + PhSetDisabledEMenuItem(whoisMenu); + PhSetDisabledEMenuItem(traceMenu); + PhSetDisabledEMenuItem(pingMenu); } } @@ -466,9 +485,6 @@ VOID NTAPI NetworkItemDeleteCallback( PhDereferenceObject(extension->PacketLossText); if (extension->LatencyText) PhDereferenceObject(extension->LatencyText); - - //if (extension->CountryIcon) - // DestroyIcon(extension->CountryIcon); } FORCEINLINE VOID PhpNetworkItemToRow( @@ -609,7 +625,7 @@ VOID UpdateNetworkNode( case NETWORK_COLUMN_ID_BYTES_IN: { if (Extension->NumberOfBytesIn) - PhMoveReference(&Extension->BytesIn, PhFormatSize(Extension->NumberOfBytesIn, -1)); + PhMoveReference(&Extension->BytesIn, PhFormatSize(Extension->NumberOfBytesIn, ULONG_MAX)); if (!NetworkExtensionEnabled && !Extension->BytesIn && PhGetOwnTokenAttributes().Elevated) PhMoveReference(&Extension->BytesIn, PhCreateString(L"Extended TCP statisitics are disabled")); @@ -618,7 +634,7 @@ VOID UpdateNetworkNode( case NETWORK_COLUMN_ID_BYTES_OUT: { if (Extension->NumberOfBytesOut) - PhMoveReference(&Extension->BytesOut, PhFormatSize(Extension->NumberOfBytesOut, -1)); + PhMoveReference(&Extension->BytesOut, PhFormatSize(Extension->NumberOfBytesOut, ULONG_MAX)); if (!NetworkExtensionEnabled && !Extension->BytesOut && PhGetOwnTokenAttributes().Elevated) PhMoveReference(&Extension->BytesOut, PhCreateString(L"Extended TCP statisitics are disabled")); @@ -722,7 +738,6 @@ VOID NTAPI TreeNewMessageCallback( if (extension->CountryIconIndex != INT_MAX) { DrawCountryIcon(hdc, rect, extension->CountryIconIndex); - rect.left += 16 + 2; } @@ -944,7 +959,7 @@ LOGICAL DllMain( &NetworkMenuInitializingCallbackRegistration ); - PhRegisterCallback( + PhRegisterCallback( PhGetGeneralCallback(GeneralCallbackNetworkTreeNewInitializing), NetworkTreeNewInitializingCallback, &NetworkTreeNewHandle, diff --git a/plugins/NetworkTools/nettools.h b/plugins/NetworkTools/nettools.h index 6a93a587b751..25597642a7b1 100644 --- a/plugins/NetworkTools/nettools.h +++ b/plugins/NetworkTools/nettools.h @@ -33,10 +33,6 @@ #include #include -#include -#include -#include -#include #include #include #include @@ -101,12 +97,12 @@ typedef enum _PH_NETWORK_ACTION MENU_ACTION_COPY, } PH_NETWORK_ACTION; -#define NTM_RECEIVEDTRACE (WM_APP + NETWORK_ACTION_TRACEROUTE) -#define NTM_RECEIVEDWHOIS (WM_APP + NETWORK_ACTION_WHOIS) -#define NTM_RECEIVEDFINISH (WM_APP + NETWORK_ACTION_FINISH) -#define WM_TRACERT_UPDATE (WM_APP + NETWORK_ACTION_TRACEROUTE + 1002) -#define WM_TRACERT_HOSTNAME (WM_APP + NETWORK_ACTION_TRACEROUTE + 1003) -#define WM_TRACERT_COUNTRY (WM_APP + NETWORK_ACTION_TRACEROUTE + 1004) +#define NTM_RECEIVEDTRACE (WM_APP + 1) +#define NTM_RECEIVEDWHOIS (WM_APP + 2) +#define NTM_RECEIVEDFINISH (WM_APP + 3) +#define WM_TRACERT_UPDATE (WM_APP + 4) +#define WM_TRACERT_HOSTNAME (WM_APP + 5) +#define WM_TRACERT_COUNTRY (WM_APP + 6) #define UPDATE_MENUITEM 1005 @@ -179,12 +175,14 @@ typedef struct _NETWORK_TRACERT_CONTEXT HWND SearchboxHandle; HWND TreeNewHandle; HFONT FontHandle; + PH_LAYOUT_MANAGER LayoutManager; + ULONG MaximumHops; BOOLEAN Cancel; + PH_WORK_QUEUE WorkQueue; + ULONG TreeNewSortColumn; PH_SORT_ORDER TreeNewSortOrder; - PH_LAYOUT_MANAGER LayoutManager; - PH_WORK_QUEUE WorkQueue; PPH_HASHTABLE NodeHashtable; PPH_LIST NodeList; PPH_LIST NodeRootList; @@ -331,24 +329,6 @@ VOID ShowDbUpdateFailedDialog( _In_ PPH_UPDATER_CONTEXT Context ); -// Copied from mstcpip.h due to PH sdk conflicts -#define INADDR_ANY (ULONG)0x00000000 -#define INADDR_LOOPBACK 0x7f000001 - -FORCEINLINE -BOOLEAN -IN4_IS_ADDR_UNSPECIFIED(_In_ CONST IN_ADDR *a) -{ - return (BOOLEAN)(a->s_addr == INADDR_ANY); -} - -FORCEINLINE -BOOLEAN -IN4_IS_ADDR_LOOPBACK(_In_ CONST IN_ADDR *a) -{ - return (BOOLEAN)(*((PUCHAR)a) == 0x7f); // 127/8 -} - // ports.c typedef struct _RESOLVED_PORT { diff --git a/plugins/NetworkTools/tracert.c b/plugins/NetworkTools/tracert.c index 9e10f9ee6841..41a9b7851de0 100644 --- a/plugins/NetworkTools/tracert.c +++ b/plugins/NetworkTools/tracert.c @@ -72,17 +72,24 @@ NTSTATUS TracertHostnameLookupCallback( NI_NAMEREQD )) { - SendMessage(resolve->WindowHandle, WM_TRACERT_HOSTNAME, resolve->Index, (LPARAM)PhCreateString(resolve->SocketAddressHostname)); + SendMessage( + resolve->WindowHandle, + WM_TRACERT_HOSTNAME, + resolve->Index, + (LPARAM)PhCreateString(resolve->SocketAddressHostname) + ); } else { ULONG errorCode = WSAGetLastError(); - if (errorCode != WSAHOST_NOT_FOUND && errorCode != WSATRY_AGAIN) { - //PPH_STRING errorMessage = PhGetWin32Message(errorCode); - //PhSetListViewSubItem(work->LvHandle, work->LvItemIndex, HOSTNAME_COLUMN, errorMessage->Buffer); - //PhDereferenceObject(errorMessage); + SendMessage( + resolve->WindowHandle, + WM_TRACERT_HOSTNAME, + resolve->Index, + (LPARAM)PhGetWin32Message(errorCode) + ); } PhDereferenceObject(resolve); @@ -100,17 +107,24 @@ NTSTATUS TracertHostnameLookupCallback( NI_NAMEREQD )) { - SendMessage(resolve->WindowHandle, WM_TRACERT_HOSTNAME, resolve->Index, (LPARAM)PhCreateString(resolve->SocketAddressHostname)); + SendMessage( + resolve->WindowHandle, + WM_TRACERT_HOSTNAME, + resolve->Index, + (LPARAM)PhCreateString(resolve->SocketAddressHostname) + ); } else { ULONG errorCode = WSAGetLastError(); - if (errorCode != WSAHOST_NOT_FOUND && errorCode != WSATRY_AGAIN) { - //PPH_STRING errorMessage = PhGetWin32Message(errorCode); - //PhSetListViewSubItem(work->LvHandle, work->LvItemIndex, HOSTNAME_COLUMN, errorMessage->Buffer); - //PhDereferenceObject(errorMessage); + SendMessage( + resolve->WindowHandle, + WM_TRACERT_HOSTNAME, + resolve->Index, + (LPARAM)PhGetWin32Message(errorCode) + ); } PhDereferenceObject(resolve); @@ -128,8 +142,8 @@ VOID TracertQueueHostLookup( { PPH_STRING remoteCountryCode; PPH_STRING remoteCountryName; - ULONG addressStringLength = INET_ADDRSTRLEN; - WCHAR addressString[INET_ADDRSTRLEN] = L""; + ULONG addressStringLength = INET6_ADDRSTRLEN; + WCHAR addressString[INET6_ADDRSTRLEN] = L""; if (Context->RemoteEndpoint.Address.Type == PH_IPV4_NETWORK_TYPE) { @@ -197,7 +211,7 @@ VOID TracertQueueHostLookup( // Make sure we don't append the same address. if (PhFindStringInString(Node->IpAddressString, 0, addressString) == -1) { - // Some routes can return multiple addresses for the same ping or 'hop', + // Some routes can return multiple addresses for the same TTL, // so make sure we don't lose this information (as every other tracert tool does) // and instead append the additional IP address to the node. PhMoveReference(&Node->IpAddressString, @@ -294,7 +308,7 @@ NTSTATUS NetworkTracertThreadStart( //((PSOCKADDR_IN6)&destinationAddress)->sin6_port = (USHORT)context->RemoteEndpoint.Port; } - for (ULONG i = 0; i < DEFAULT_MAXIMUM_HOPS; i++) + for (ULONG i = 0; i < context->MaximumHops; i++) { PTRACERT_ROOT_NODE node; IN_ADDR last4ReplyAddress = in4addr_any; @@ -334,7 +348,7 @@ NTSTATUS NetworkTracertThreadStart( { PICMP_ECHO_REPLY reply4 = (PICMP_ECHO_REPLY)icmpReplyBuffer; - memcpy(&last4ReplyAddress, &reply4->Address, sizeof(IN_ADDR)); + memcpy_s(&last4ReplyAddress, sizeof(IN_ADDR), &reply4->Address, sizeof(IN_ADDR)); TracertQueueHostLookup( context, @@ -426,12 +440,12 @@ NTSTATUS NetworkTracertThreadStart( if (context->RemoteEndpoint.Address.Type == PH_IPV4_NETWORK_TYPE) { - if (!memcmp(&last4ReplyAddress, &((PSOCKADDR_IN)&destinationAddress)->sin_addr, sizeof(IN_ADDR))) + if (RtlEqualMemory(&last4ReplyAddress, &((PSOCKADDR_IN)&destinationAddress)->sin_addr, sizeof(IN_ADDR))) break; } else if (context->RemoteEndpoint.Address.Type == PH_IPV6_NETWORK_TYPE) { - if (!memcmp(&last6ReplyAddress, &((PSOCKADDR_IN6)&destinationAddress)->sin6_addr, sizeof(IN6_ADDR))) + if (RtlEqualMemory(&last6ReplyAddress, &((PSOCKADDR_IN6)&destinationAddress)->sin6_addr, sizeof(IN6_ADDR))) break; } @@ -453,7 +467,7 @@ NTSTATUS NetworkTracertThreadStart( return STATUS_SUCCESS; } -VOID ShowMenu( +VOID TracertMenuActionCallback( _In_ PNETWORK_TRACERT_CONTEXT Context, _In_ ULONG Id ) @@ -693,11 +707,11 @@ INT_PTR CALLBACK TracertDlgProc( if (selectedNode = GetSelectedTracertNode(context)) { menu = PhCreateEMenu(); - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, MAINMENU_ACTION_PING, L"Ping", NULL, NULL), -1); - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, NETWORK_ACTION_TRACEROUTE, L"Traceroute", NULL, NULL), -1); - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, NETWORK_ACTION_WHOIS, L"Whois", NULL, NULL), -1); - PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), -1); - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, MENU_ACTION_COPY, L"Copy", NULL, NULL), -1); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, MAINMENU_ACTION_PING, L"Ping", NULL, NULL), ULONG_MAX); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, NETWORK_ACTION_TRACEROUTE, L"Traceroute", NULL, NULL), ULONG_MAX); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, NETWORK_ACTION_WHOIS, L"Whois", NULL, NULL), ULONG_MAX); + PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, MENU_ACTION_COPY, L"Copy", NULL, NULL), ULONG_MAX); PhInsertCopyCellEMenuItem(menu, MENU_ACTION_COPY, context->TreeNewHandle, contextMenuEvent->Column); selectedItem = PhShowEMenu( @@ -709,15 +723,11 @@ INT_PTR CALLBACK TracertDlgProc( contextMenuEvent->Location.y ); - if (selectedItem && selectedItem->Id != -1) + if (selectedItem && selectedItem->Id != ULONG_MAX) { - BOOLEAN handled = FALSE; - - handled = PhHandleCopyCellEMenuItem(selectedItem); - - if (!handled) + if (!PhHandleCopyCellEMenuItem(selectedItem)) { - ShowMenu(context, selectedItem->Id); + TracertMenuActionCallback(context, selectedItem->Id); } } @@ -764,28 +774,24 @@ INT_PTR CALLBACK TracertDlgProc( // Some routes can return multiple addresses for the same ping or 'hop', // so make sure we don't lose this information (as every other tracert tool does) // and instead append the additional hostname to the node. - PhMoveReference(&traceNode->HostnameString, - PhFormatString(L"%s, %s", PhGetString(traceNode->HostnameString), PhGetString(hostName)) - ); + PhMoveReference(&traceNode->HostnameString, PhFormatString( + L"%s, %s", + PhGetString(traceNode->HostnameString), + PhGetString(hostName) + )); UpdateTracertNode(context, traceNode); } - else - { - PhDereferenceObject(hostName); - } } else { - PhMoveReference(&traceNode->HostnameString, hostName); + PhSwapReference(&traceNode->HostnameString, hostName); UpdateTracertNode(context, traceNode); } } - else - { - PhDereferenceObject(hostName); - } + + PhDereferenceObject(hostName); } break; } @@ -844,6 +850,7 @@ VOID ShowTracertWindow( context = (PNETWORK_TRACERT_CONTEXT)PhCreateAlloc(sizeof(NETWORK_TRACERT_CONTEXT)); memset(context, 0, sizeof(NETWORK_TRACERT_CONTEXT)); + context->MaximumHops = PhGetIntegerSetting(SETTING_NAME_TRACERT_MAX_HOPS); context->RemoteEndpoint = NetworkItem->RemoteEndpoint; if (NetworkItem->RemoteEndpoint.Address.Type == PH_IPV4_NETWORK_TYPE) @@ -867,6 +874,7 @@ VOID ShowTracertWindowFromAddress( context = (PNETWORK_TRACERT_CONTEXT)PhCreateAlloc(sizeof(NETWORK_TRACERT_CONTEXT)); memset(context, 0, sizeof(NETWORK_TRACERT_CONTEXT)); + context->MaximumHops = PhGetIntegerSetting(SETTING_NAME_TRACERT_MAX_HOPS); context->RemoteEndpoint = RemoteEndpoint; if (RemoteEndpoint.Address.Type == PH_IPV4_NETWORK_TYPE) diff --git a/plugins/NetworkTools/tracert.h b/plugins/NetworkTools/tracert.h index 408b9d56df61..980a916108d8 100644 --- a/plugins/NetworkTools/tracert.h +++ b/plugins/NetworkTools/tracert.h @@ -24,7 +24,6 @@ #define _TRACERT_H_ #define DEFAULT_MAXIMUM_PINGS 4 -#define DEFAULT_MAXIMUM_HOPS 40 #define DEFAULT_SEND_SIZE 64 #define DEFAULT_RECEIVE_SIZE ((sizeof(ICMP_ECHO_REPLY) + DEFAULT_SEND_SIZE + MAX_OPT_SIZE)) #define DEFAULT_TIMEOUT 1000 @@ -48,6 +47,7 @@ typedef struct _TRACERT_ROOT_NODE { PH_TREENEW_NODE Node; + ULONG UniqueId; ULONG TTL; ULONG PingStatus[DEFAULT_MAXIMUM_PINGS]; ULONG PingList[DEFAULT_MAXIMUM_PINGS]; diff --git a/plugins/NetworkTools/tracetree.c b/plugins/NetworkTools/tracetree.c index 730a4d0bb9be..9c92c0bb80b0 100644 --- a/plugins/NetworkTools/tracetree.c +++ b/plugins/NetworkTools/tracetree.c @@ -49,15 +49,13 @@ VOID NTAPI TracertTreeNodeItemDeleteProcedure( if (tracertNode->PingString[i]) PhDereferenceObject(tracertNode->PingString[i]); } - - //if (tracertNode->CountryIcon) - // DestroyIcon(tracertNode->CountryIcon); } PTRACERT_ROOT_NODE TracertTreeCreateNode( VOID ) { + static ULONG NextUniqueId = 1; PTRACERT_ROOT_NODE tracertNode; tracertNode = PhCreateObject(sizeof(TRACERT_ROOT_NODE), TracertTreeNodeItemType); @@ -65,6 +63,7 @@ PTRACERT_ROOT_NODE TracertTreeCreateNode( PhInitializeTreeNewNode(&tracertNode->Node); + tracertNode->UniqueId = NextUniqueId++; // used to stabilize sorting tracertNode->CountryIconIndex = INT_MAX; return tracertNode; @@ -83,7 +82,7 @@ PTRACERT_ROOT_NODE TracertTreeCreateNode( #define END_SORT_FUNCTION \ if (sortResult == 0) \ - sortResult = uintptrcmp((ULONG_PTR)node1->Node.Index, (ULONG_PTR)node2->Node.Index); \ + sortResult = uintcmp(node1->UniqueId, node2->UniqueId); \ \ return PhModifySort(sortResult, ((PNETWORK_TRACERT_CONTEXT)_context)->TreeNewSortOrder); \ } @@ -185,7 +184,7 @@ ULONG TracertNodeHashtableHashFunction( _In_ PVOID Entry ) { - return (*(PTRACERT_ROOT_NODE*)Entry)->TTL; + return PhHashInt32((*(PTRACERT_ROOT_NODE*)Entry)->TTL); } VOID DestroyTracertNode( @@ -475,7 +474,6 @@ BOOLEAN NTAPI TracertTreeNewCallback( if (node->CountryIconIndex != INT_MAX) { DrawCountryIcon(hdc, rect, node->CountryIconIndex); - rect.left += 16 + 2; } @@ -495,7 +493,7 @@ BOOLEAN NTAPI TracertTreeNewCallback( if (!GeoDbLoaded) { - DrawText(hdc, L"Geoip database error.", -1, &rect, DT_LEFT | DT_VCENTER | DT_END_ELLIPSIS | DT_SINGLELINE); + DrawText(hdc, L"Geoip database not found.", -1, &rect, DT_LEFT | DT_VCENTER | DT_END_ELLIPSIS | DT_SINGLELINE); } } return TRUE; From 358795b090515919ae5295f7332fe9cebc538e52 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 9 Jun 2018 11:22:41 +1000 Subject: [PATCH 1017/2058] SetupTool: Update window context callbacks --- tools/CustomSetupTool/CustomSetupTool/appsup.c | 3 ++- tools/CustomSetupTool/CustomSetupTool/configpage.c | 6 +++--- tools/CustomSetupTool/CustomSetupTool/downloadpage.c | 6 +++--- tools/CustomSetupTool/CustomSetupTool/errorpage.c | 6 +++--- tools/CustomSetupTool/CustomSetupTool/install.c | 6 +++--- tools/CustomSetupTool/CustomSetupTool/licencepage.c | 6 +++--- tools/CustomSetupTool/CustomSetupTool/main.c | 2 +- tools/CustomSetupTool/CustomSetupTool/startpage.c | 6 +++--- tools/CustomSetupTool/CustomSetupTool/websetuppage.c | 6 +++--- 9 files changed, 24 insertions(+), 23 deletions(-) diff --git a/tools/CustomSetupTool/CustomSetupTool/appsup.c b/tools/CustomSetupTool/CustomSetupTool/appsup.c index d387a3f9a115..d2251da295d3 100644 --- a/tools/CustomSetupTool/CustomSetupTool/appsup.c +++ b/tools/CustomSetupTool/CustomSetupTool/appsup.c @@ -37,7 +37,8 @@ VOID ExtractResourceToFile( if (!PhLoadResource( PhInstanceHandle, - Resource, RT_RCDATA, + Resource, + RT_RCDATA, &resourceLength, &resourceBuffer )) diff --git a/tools/CustomSetupTool/CustomSetupTool/configpage.c b/tools/CustomSetupTool/CustomSetupTool/configpage.c index b4dbe1e2adb2..cbf668443da7 100644 --- a/tools/CustomSetupTool/CustomSetupTool/configpage.c +++ b/tools/CustomSetupTool/CustomSetupTool/configpage.c @@ -33,12 +33,12 @@ INT_PTR CALLBACK SetupPropPage3_WndProc( if (uMsg == WM_INITDIALOG) { - context = GetProp(GetParent(hwndDlg), L"SetupContext"); - SetProp(hwndDlg, L"Context", (HANDLE)context); + context = PhGetWindowContext(GetParent(hwndDlg), ULONG_MAX); + PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context); } else { - context = (PPH_SETUP_CONTEXT)GetProp(hwndDlg, L"Context"); + context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); } if (context == NULL) diff --git a/tools/CustomSetupTool/CustomSetupTool/downloadpage.c b/tools/CustomSetupTool/CustomSetupTool/downloadpage.c index 6779444751ec..76bb0e156d2a 100644 --- a/tools/CustomSetupTool/CustomSetupTool/downloadpage.c +++ b/tools/CustomSetupTool/CustomSetupTool/downloadpage.c @@ -52,12 +52,12 @@ INT_PTR CALLBACK SetupPropPage5_WndProc( if (uMsg == WM_INITDIALOG) { - context = GetProp(GetParent(hwndDlg), L"SetupContext"); - SetProp(hwndDlg, L"Context", (HANDLE)context); + context = PhGetWindowContext(GetParent(hwndDlg), ULONG_MAX); + PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context); } else { - context = (PPH_SETUP_CONTEXT)GetProp(hwndDlg, L"Context"); + context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); } if (context == NULL) diff --git a/tools/CustomSetupTool/CustomSetupTool/errorpage.c b/tools/CustomSetupTool/CustomSetupTool/errorpage.c index 024920e772f7..f1a364360a39 100644 --- a/tools/CustomSetupTool/CustomSetupTool/errorpage.c +++ b/tools/CustomSetupTool/CustomSetupTool/errorpage.c @@ -33,12 +33,12 @@ INT_PTR CALLBACK SetupErrorPage_WndProc( if (uMsg == WM_INITDIALOG) { - context = GetProp(GetParent(hwndDlg), L"SetupContext"); - SetProp(hwndDlg, L"Context", (HANDLE)context); + context = PhGetWindowContext(GetParent(hwndDlg), ULONG_MAX); + PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context); } else { - context = (PPH_SETUP_CONTEXT)GetProp(hwndDlg, L"Context"); + context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); } if (context == NULL) diff --git a/tools/CustomSetupTool/CustomSetupTool/install.c b/tools/CustomSetupTool/CustomSetupTool/install.c index d96bc33004d7..63a1857d63c8 100644 --- a/tools/CustomSetupTool/CustomSetupTool/install.c +++ b/tools/CustomSetupTool/CustomSetupTool/install.c @@ -93,12 +93,12 @@ INT_PTR CALLBACK SetupInstallPropPage_WndProc( if (uMsg == WM_INITDIALOG) { - context = GetProp(GetParent(hwndDlg), L"SetupContext"); - SetProp(hwndDlg, L"Context", (HANDLE)context); + context = PhGetWindowContext(GetParent(hwndDlg), ULONG_MAX); + PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context); } else { - context = (PPH_SETUP_CONTEXT)GetProp(hwndDlg, L"Context"); + context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); } if (context == NULL) diff --git a/tools/CustomSetupTool/CustomSetupTool/licencepage.c b/tools/CustomSetupTool/CustomSetupTool/licencepage.c index aff021b833a9..5a30d86c1596 100644 --- a/tools/CustomSetupTool/CustomSetupTool/licencepage.c +++ b/tools/CustomSetupTool/CustomSetupTool/licencepage.c @@ -31,12 +31,12 @@ INT_PTR CALLBACK SetupPropPage2_WndProc( if (uMsg == WM_INITDIALOG) { - context = GetProp(GetParent(hwndDlg), L"SetupContext"); - SetProp(hwndDlg, L"Context", (HANDLE)context); + context = PhGetWindowContext(GetParent(hwndDlg), ULONG_MAX); + PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context); } else { - context = (PPH_SETUP_CONTEXT)GetProp(hwndDlg, L"Context"); + context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); } if (context == NULL) diff --git a/tools/CustomSetupTool/CustomSetupTool/main.c b/tools/CustomSetupTool/CustomSetupTool/main.c index a5eb7e27a9a5..602904f700f5 100644 --- a/tools/CustomSetupTool/CustomSetupTool/main.c +++ b/tools/CustomSetupTool/CustomSetupTool/main.c @@ -99,7 +99,7 @@ INT CALLBACK MainPropSheet_Callback( SetupInitializeFont(context->PropSheetForwardHandle, -12, FW_NORMAL); SetupInitializeFont(context->PropSheetCancelHandle, -12, FW_NORMAL); - SetProp(hwndDlg, L"SetupContext", (HANDLE)context); + PhSetWindowContext(hwndDlg, ULONG_MAX, context); } break; } diff --git a/tools/CustomSetupTool/CustomSetupTool/startpage.c b/tools/CustomSetupTool/CustomSetupTool/startpage.c index 199161b43be8..a17ec722412f 100644 --- a/tools/CustomSetupTool/CustomSetupTool/startpage.c +++ b/tools/CustomSetupTool/CustomSetupTool/startpage.c @@ -70,12 +70,12 @@ INT_PTR CALLBACK SetupPropPage1_WndProc( if (uMsg == WM_INITDIALOG) { - context = GetProp(GetParent(hwndDlg), L"SetupContext"); - SetProp(hwndDlg, L"Context", (HANDLE)context); + context = PhGetWindowContext(GetParent(hwndDlg), ULONG_MAX); + PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context); } else { - context = (PPH_SETUP_CONTEXT)GetProp(hwndDlg, L"Context"); + context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); } if (context == NULL) diff --git a/tools/CustomSetupTool/CustomSetupTool/websetuppage.c b/tools/CustomSetupTool/CustomSetupTool/websetuppage.c index 30012b3fbef9..2e48dece3f1b 100644 --- a/tools/CustomSetupTool/CustomSetupTool/websetuppage.c +++ b/tools/CustomSetupTool/CustomSetupTool/websetuppage.c @@ -79,12 +79,12 @@ INT_PTR CALLBACK SetupWebSetup_WndProc( if (uMsg == WM_INITDIALOG) { - context = GetProp(GetParent(hwndDlg), L"SetupContext"); - SetProp(hwndDlg, L"Context", (HANDLE)context); + context = PhGetWindowContext(GetParent(hwndDlg), ULONG_MAX); + PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context); } else { - context = (PPH_SETUP_CONTEXT)GetProp(hwndDlg, L"Context"); + context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); } if (context == NULL) From 6051470fdcb5a3fc77693e99cf7a54afbd36c29c Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 9 Jun 2018 12:09:21 +1000 Subject: [PATCH 1018/2058] OnlineChecks: Fix uploading files to hybrid-analysis, Remove legacy API, Add support for uploading WSL binaries --- plugins/OnlineChecks/db.c | 2 +- plugins/OnlineChecks/db.h | 1 - plugins/OnlineChecks/upload.c | 262 ++++++++++++++++++++++------------ 3 files changed, 174 insertions(+), 91 deletions(-) diff --git a/plugins/OnlineChecks/db.c b/plugins/OnlineChecks/db.c index 4029c9091e60..906cf092be13 100644 --- a/plugins/OnlineChecks/db.c +++ b/plugins/OnlineChecks/db.c @@ -25,7 +25,7 @@ PPH_HASHTABLE ProcessObjectDb; PH_QUEUED_LOCK ProcessObjectDbLock = PH_QUEUED_LOCK_INIT; PH_STRINGREF ProcessObjectDbHash = PH_STRINGREF_INIT(L"386f3b6b3f6c35346c69346c6b343d69396b6b3468386b683d383d356b3e383e38356b343f69393b683d3b3a39386b3c6b3a3a3e696835696e686f6b38683e6e"); -PH_STRINGREF ServiceObjectDbHash = PH_STRINGREF_INIT(L"6b396f3b3f6e693b3a6e696c386c393d3c3b3b386f383e3e3e3e343c3e6c3d386f6b3f3f6e69396f3c3a34686b38353a"); +PH_STRINGREF ServiceObjectDbHash = PH_STRINGREF_INIT(L"39666e39663d6e66356e3935666a66626e6e627e6e35623d6a3d6a3d6e6e6e6a6a6a35396a6a3d6e7a357e7e7a35626a663d6e7a3d6a3d6e7a397e3d3d6e6e7e"); PH_STRINGREF NetworkObjectDbHash = PH_STRINGREF_INIT(L"6e61653c676065676b6b7a393d6a66357a396a6e6e66397a35"); BOOLEAN NTAPI ProcessObjectDbEqualFunction( diff --git a/plugins/OnlineChecks/db.h b/plugins/OnlineChecks/db.h index 2232c1d9e6cd..f1f4c0464012 100644 --- a/plugins/OnlineChecks/db.h +++ b/plugins/OnlineChecks/db.h @@ -25,7 +25,6 @@ extern PH_STRINGREF ProcessObjectDbHash; extern PH_STRINGREF ServiceObjectDbHash; -extern PH_STRINGREF NetworkObjectDbHash; typedef struct _PROCESS_DB_OBJECT { diff --git a/plugins/OnlineChecks/upload.c b/plugins/OnlineChecks/upload.c index 54235164b075..7ff310f6eab4 100644 --- a/plugins/OnlineChecks/upload.c +++ b/plugins/OnlineChecks/upload.c @@ -26,8 +26,8 @@ PPH_OBJECT_TYPE UploadContextType = NULL; PH_INITONCE UploadContextTypeInitOnce = PH_INITONCE_INIT; SERVICE_INFO UploadServiceInfo[] = { - { MENUITEM_HYBRIDANALYSIS_UPLOAD, L"www.hybrid-analysis.com", L"/api/submit", L"file" }, - { MENUITEM_HYBRIDANALYSIS_UPLOAD_SERVICE, L"www.hybrid-analysis.com", L"/api/submit", L"file" }, + { MENUITEM_HYBRIDANALYSIS_UPLOAD, L"www.hybrid-analysis.com", L"/api/v2/submit/file", L"file" }, + { MENUITEM_HYBRIDANALYSIS_UPLOAD_SERVICE, L"www.hybrid-analysis.com", L"/api/v2/submit/file", L"file" }, { MENUITEM_VIRUSTOTAL_UPLOAD, L"www.virustotal.com", L"???", L"file" }, { MENUITEM_VIRUSTOTAL_UPLOAD_SERVICE, L"www.virustotal.com", L"???", L"file" }, { MENUITEM_JOTTI_UPLOAD, L"virusscan.jotti.org", L"/en-US/submit-file?isAjax=true", L"sample-file[]" }, @@ -284,6 +284,30 @@ PPH_BYTES PerformSubRequest( goto CleanupExit; } + if ( + Context->Service == MENUITEM_HYBRIDANALYSIS_UPLOAD || + Context->Service == MENUITEM_HYBRIDANALYSIS_UPLOAD_SERVICE + ) + { + PPH_BYTES serviceHash; + PPH_STRING httpHeader; + + serviceHash = VirusTotalGetCachedDbHash(&ServiceObjectDbHash); + httpHeader = PhFormatString( + L"\x0061\x0070\x0069\x002D\x006B\x0065\x0079:%hs", + serviceHash->Buffer + ); + + PhHttpSocketAddRequestHeaders( + httpContext, + httpHeader->Buffer, + (ULONG)httpHeader->Length / sizeof(WCHAR) + ); + + PhClearReference(&httpHeader); + PhClearReference(&serviceHash); + } + if (!PhHttpSocketSendRequest(httpContext, NULL, 0)) { RaiseUploadError(Context, L"Unable to send the request.", GetLastError()); @@ -313,24 +337,6 @@ PPH_BYTES PerformSubRequest( return result; } -BOOLEAN UploadGetFileArchitecture( - _In_ HANDLE FileHandle, - _Out_ PUSHORT FileArchitecture - ) -{ - NTSTATUS status; - PH_MAPPED_IMAGE mappedImage; - - if (!NT_SUCCESS(status = PhLoadMappedImage(NULL, FileHandle, TRUE, &mappedImage))) - return FALSE; - - *FileArchitecture = mappedImage.NtHeaders->FileHeader.Machine; - - PhUnloadMappedImage(&mappedImage); - - return TRUE; -} - NTSTATUS UploadFileThreadStart( _In_ PVOID Parameter ) @@ -436,13 +442,6 @@ NTSTATUS UploadFileThreadStart( (ULONG64)RtlRandomEx(&httpPostSeed) | ((ULONG64)RtlRandomEx(&httpPostSeed) << 31) ); - // HTTP request header string. - PhAppendFormatStringBuilder( - &httpRequestHeaders, - L"Content-Type: multipart/form-data; boundary=%s\r\n", - postBoundary->Buffer - ); - if ( context->Service == MENUITEM_HYBRIDANALYSIS_UPLOAD || context->Service == MENUITEM_HYBRIDANALYSIS_UPLOAD_SERVICE @@ -450,13 +449,27 @@ NTSTATUS UploadFileThreadStart( { USHORT machineType; USHORT environmentId; + PH_MAPPED_IMAGE mappedImage; + PPH_BYTES serviceHash; - if (!UploadGetFileArchitecture(fileHandle, &machineType)) + if (!NT_SUCCESS(status = PhLoadMappedImageEx(NULL, fileHandle, TRUE, &mappedImage))) { - RaiseUploadError(context, L"Unable to create the request.", GetLastError()); + RaiseUploadError(context, L"Unable to load the image.", RtlNtStatusToDosError(status)); goto CleanupExit; } + switch (mappedImage.Signature) + { + case IMAGE_DOS_SIGNATURE: + machineType = mappedImage.NtHeaders->FileHeader.Machine; + break; + case IMAGE_ELF_SIGNATURE: + machineType = USHRT_MAX; // Windows only supports 64bit ELF. (mappedImage.Header->e_machine) + break; + } + + PhUnloadMappedImage(&mappedImage); + switch (machineType) { case IMAGE_FILE_MACHINE_I386: @@ -465,43 +478,43 @@ NTSTATUS UploadFileThreadStart( case IMAGE_FILE_MACHINE_AMD64: environmentId = 120; break; + case USHRT_MAX: // 64bit Linux + environmentId = 300; + break; default: { - RaiseUploadError(context, L"File architecture not supported.", GetLastError()); + RaiseUploadError(context, L"File architecture not supported.", STATUS_IMAGE_SUBSYSTEM_NOT_PRESENT); goto CleanupExit; } } - { - PPH_BYTES serviceHash; - PPH_BYTES networkHash; - PPH_STRING resourceNameString; - PPH_STRING resourceHashString; - - serviceHash = VirusTotalGetCachedDbHash(&ServiceObjectDbHash); - networkHash = VirusTotalGetCachedDbHash(&NetworkObjectDbHash); - - resourceNameString = PhZeroExtendToUtf16(serviceHash->Buffer); - resourceHashString = PhZeroExtendToUtf16(networkHash->Buffer); - PhHttpSocketSetCredentials(httpContext, PhGetString(resourceHashString), PhGetString(resourceNameString)); - PhClearReference(&resourceHashString); - PhClearReference(&resourceNameString); - PhClearReference(&networkHash); - PhClearReference(&serviceHash); - } + // HTTP request headers + PhAppendFormatStringBuilder( + &httpRequestHeaders, + L"accept: application/json\r\n" + ); + + serviceHash = VirusTotalGetCachedDbHash(&ServiceObjectDbHash); + PhAppendFormatStringBuilder( + &httpRequestHeaders, + L"\x0061\x0070\x0069\x002D\x006B\x0065\x0079:%hs\r\n", + serviceHash->Buffer + ); + PhClearReference(&serviceHash); + + PhAppendFormatStringBuilder( + &httpRequestHeaders, + L"Content-Type: multipart/form-data; boundary=%s\r\n", + postBoundary->Buffer + ); // POST boundary header. PhAppendFormatStringBuilder( &httpPostHeader, - L"--%s\r\nContent-Disposition: form-data; name=\"environmentId\"\r\n\r\n%hu\r\n", + L"--%s\r\nContent-Disposition: form-data; name=\"environment_id\"\r\n\r\n%hu\r\n", postBoundary->Buffer, environmentId ); - PhAppendFormatStringBuilder( - &httpPostHeader, - L"--%s\r\nContent-Disposition: form-data; name=\"nosharevt\"\r\n\r\n1\r\n", - postBoundary->Buffer - ); PhAppendFormatStringBuilder( &httpPostHeader, L"--%s\r\nContent-Disposition: form-data; name=\"file\"; filename=\"%s\"\r\n\r\n", @@ -518,6 +531,12 @@ NTSTATUS UploadFileThreadStart( } else if (context->Service == MENUITEM_JOTTI_UPLOAD) { + PhAppendFormatStringBuilder( + &httpRequestHeaders, + L"Content-Type: multipart/form-data; boundary=%s\r\n", + postBoundary->Buffer + ); + // POST boundary header. PhAppendFormatStringBuilder( &httpPostHeader, @@ -553,6 +572,12 @@ NTSTATUS UploadFileThreadStart( } else { + PhAppendFormatStringBuilder( + &httpRequestHeaders, + L"Content-Type: multipart/form-data; boundary=%s\r\n", + postBoundary->Buffer + ); + // POST boundary header PhAppendFormatStringBuilder( &httpPostHeader, @@ -681,9 +706,9 @@ NTSTATUS UploadFileThreadStart( { FLOAT percent = ((FLOAT)totalUploadedLength / context->TotalFileLength * 100); - PPH_STRING totalLength = PhFormatSize(context->TotalFileLength, -1); - PPH_STRING totalUploaded = PhFormatSize(totalUploadedLength, -1); - PPH_STRING totalSpeed = PhFormatSize(timeBitsPerSecond, -1); + PPH_STRING totalLength = PhFormatSize(context->TotalFileLength, ULONG_MAX); + PPH_STRING totalUploaded = PhFormatSize(totalUploadedLength, ULONG_MAX); + PPH_STRING totalSpeed = PhFormatSize(timeBitsPerSecond, ULONG_MAX); PPH_STRING statusMessage = PhFormatString( L"Uploaded: %s of %s (%.0f%%)\r\nSpeed: %s/s", PhGetStringOrEmpty(totalUploaded), @@ -740,7 +765,12 @@ NTSTATUS UploadFileThreadStart( goto CleanupExit; } - if (httpStatus == PH_HTTP_STATUS_OK || httpStatus == PH_HTTP_STATUS_REDIRECT_METHOD || httpStatus == PH_HTTP_STATUS_REDIRECT) + if ( + httpStatus == PH_HTTP_STATUS_OK || + httpStatus == PH_HTTP_STATUS_CREATED || + httpStatus == PH_HTTP_STATUS_REDIRECT_METHOD || + httpStatus == PH_HTTP_STATUS_REDIRECT + ) { switch (context->Service) { @@ -749,6 +779,7 @@ NTSTATUS UploadFileThreadStart( { PPH_BYTES jsonString; PVOID jsonRootObject; + INT64 errorCode; if (!(jsonString = PhHttpSocketDownloadString(httpContext, FALSE))) { @@ -758,25 +789,29 @@ NTSTATUS UploadFileThreadStart( if (jsonRootObject = PhCreateJsonParser(jsonString->Buffer)) { - INT64 errorCode = PhGetJsonValueAsLong64(jsonRootObject, "response_code"); + errorCode = PhGetJsonValueAsLong64(jsonRootObject, "code"); if (errorCode == 0) { - PVOID jsonResponse; - PPH_STRING jsonHashString = NULL; - - if (jsonResponse = PhGetJsonObject(jsonRootObject, "response")) - jsonHashString = PhGetJsonValueAsString(jsonResponse, "sha256"); + PPH_STRING jsonHashString; + //PPH_STRING jsonJobIdString; - if (jsonHashString) + jsonHashString = PhGetJsonValueAsString(jsonRootObject, "sha256"); + //jsonJobIdString = PhGetJsonValueAsString(jsonRootObject, "job_id"); + + if (jsonHashString) // && jsonJobIdString) { PhMoveReference(&context->LaunchCommand, PhFormatString( - L"https://www.hybrid-analysis.com/sample/%s", - context->FileHash ? PhGetString(context->FileHash) : PhGetString(jsonHashString) + L"https://www.hybrid-analysis.com/sample/%s", // /%s + jsonHashString->Buffer//, + //jsonJobIdString->Buffer )); + } + if (jsonHashString) PhDereferenceObject(jsonHashString); - } + //if (jsonJobIdString) + // PhDereferenceObject(jsonJobIdString); } else { @@ -805,7 +840,7 @@ NTSTATUS UploadFileThreadStart( if (!(jsonString = PhHttpSocketDownloadString(httpContext, FALSE))) { - RaiseUploadError(context, L"Unable to complete the request", GetLastError()); + RaiseUploadError(context, L"Unable to complete the request.", GetLastError()); goto CleanupExit; } @@ -887,7 +922,7 @@ NTSTATUS UploadFileThreadStart( } else { - RaiseUploadError(context, L"Unable to complete the request", STATUS_FVE_PARTIAL_METADATA); + RaiseUploadError(context, L"Unable to complete the request.", httpStatus); goto CleanupExit; } @@ -1007,12 +1042,72 @@ NTSTATUS UploadCheckThreadStart( } } - context->FileSize = PhFormatSize(fileSize64.QuadPart, -1); + context->FileSize = PhFormatSize(fileSize64.QuadPart, ULONG_MAX); context->TotalFileLength = fileSize64.LowPart; } switch (context->Service) { + case MENUITEM_HYBRIDANALYSIS_UPLOAD: + case MENUITEM_HYBRIDANALYSIS_UPLOAD_SERVICE: + { + PPH_STRING tempHashString = NULL; + PSTR uploadUrl = NULL; + PSTR quote = NULL; + PVOID rootJsonObject; + + // Create the default upload URL. + context->UploadUrl = PhFormatString( + L"https://%s%s", + serviceInfo->HostName, + serviceInfo->UploadObjectName + ); + + if (!NT_SUCCESS(status = HashFileAndResetPosition(fileHandle, &fileSize64, Sha256HashAlgorithm, &tempHashString))) + { + RaiseUploadError(context, L"Unable to hash the file", RtlNtStatusToDosError(status)); + goto CleanupExit; + } + + context->FileHash = tempHashString; + subObjectName = PhConcatStrings2(L"/api/v2/overview/", PhGetString(context->FileHash)); + + if (!(subRequestBuffer = PerformSubRequest( + context, + serviceInfo->HostName, + subObjectName->Buffer + ))) + { + goto CleanupExit; + } + + if (rootJsonObject = PhCreateJsonParser(subRequestBuffer->Buffer)) + { + PPH_STRING errorMessage = PhGetJsonValueAsString(rootJsonObject, "message"); + + if (context->FileExists = PhIsNullOrEmptyString(errorMessage)) + { + PhMoveReference(&context->LaunchCommand, PhFormatString( + L"https://www.hybrid-analysis.com/sample/%s", + PhGetString(context->FileHash) + )); + + PostMessage(context->DialogHandle, UM_LAUNCH, 0, 0); + } + else + { + PostMessage(context->DialogHandle, UM_UPLOAD, 0, 0); + } + + PhClearReference(&errorMessage); + PhFreeJsonParser(rootJsonObject); + } + else + { + RaiseUploadError(context, L"Unable to parse the response.", RtlNtStatusToDosError(STATUS_FAIL_CHECK)); + } + } + break; case MENUITEM_VIRUSTOTAL_UPLOAD: case MENUITEM_VIRUSTOTAL_UPLOAD_SERVICE: { @@ -1158,14 +1253,6 @@ NTSTATUS UploadCheckThreadStart( PostMessage(context->DialogHandle, UM_UPLOAD, 0, 0); } break; - case MENUITEM_HYBRIDANALYSIS_UPLOAD: - case MENUITEM_HYBRIDANALYSIS_UPLOAD_SERVICE: - { - // Create the default upload URL. - context->UploadUrl = PhFormatString(L"https://%s%s", serviceInfo->HostName, serviceInfo->UploadObjectName); - - PostMessage(context->DialogHandle, UM_UPLOAD, 0, 0); - } } CleanupExit: @@ -1383,7 +1470,7 @@ HRESULT CALLBACK TaskDialogBootstrapCallback( return S_OK; } -NTSTATUS ShowUpdateDialogThread( +NTSTATUS ShowUploadDialogThread( _In_ PVOID Parameter ) { @@ -1421,15 +1508,14 @@ VOID UploadToOnlineService( PhEndInitOnce(&UploadContextTypeInitOnce); } - context = (PUPLOAD_CONTEXT)PhCreateObject(sizeof(UPLOAD_CONTEXT), UploadContextType); - memset(context, 0, sizeof(UPLOAD_CONTEXT)); - PhReferenceObject(FileName); + + context = PhCreateObjectZero(sizeof(UPLOAD_CONTEXT), UploadContextType); context->Service = Service; context->FileName = FileName; context->BaseFileName = PhGetBaseName(context->FileName); - PhCreateThread2(ShowUpdateDialogThread, (PVOID)context); + PhCreateThread2(ShowUploadDialogThread, (PVOID)context); } VOID UploadServiceToOnlineService( @@ -1455,20 +1541,18 @@ VOID UploadServiceToOnlineService( { PUPLOAD_CONTEXT context; - context = (PUPLOAD_CONTEXT)PhCreateObject(sizeof(UPLOAD_CONTEXT), UploadContextType); - memset(context, 0, sizeof(UPLOAD_CONTEXT)); - + context = PhCreateObjectZero(sizeof(UPLOAD_CONTEXT), UploadContextType); context->Service = Service; context->FileName = serviceFileName; context->BaseFileName = PhGetBaseName(context->FileName); - PhCreateThread2(ShowUpdateDialogThread, (PVOID)context); + PhCreateThread2(ShowUploadDialogThread, (PVOID)context); } else { - PhShowStatus(PhMainWndHandle, L"Unable to query the service", status, 0); + PhShowStatus(PhMainWndHandle, L"Unable to query the service.", status, 0); } if (serviceBinaryPath) PhDereferenceObject(serviceBinaryPath); -} \ No newline at end of file +} From f53cf52264426e43b1a0c2fedb7ce757bced6cdb Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 9 Jun 2018 12:11:05 +1000 Subject: [PATCH 1019/2058] HardwareDevices: Remove legacy functions --- plugins/HardwareDevices/devices.h | 19 -- plugins/HardwareDevices/diskdetails.c | 248 +++++++++++++------------- plugins/HardwareDevices/main.c | 70 +------- plugins/HardwareDevices/netdetails.c | 104 +++++------ plugins/HardwareDevices/netoptions.c | 12 +- 5 files changed, 183 insertions(+), 270 deletions(-) diff --git a/plugins/HardwareDevices/devices.h b/plugins/HardwareDevices/devices.h index c871b4f371a1..a38909a6be8d 100644 --- a/plugins/HardwareDevices/devices.h +++ b/plugins/HardwareDevices/devices.h @@ -70,25 +70,6 @@ PPH_STRING TrimString( _In_ PPH_STRING String ); -INT AddListViewGroup( - _In_ HWND ListViewHandle, - _In_ INT Index, - _In_ PWSTR Text - ); - -INT AddListViewItemGroupId( - _In_ HWND ListViewHandle, - _In_ INT GroupId, - _In_ INT Index, - _In_ PWSTR Text, - _In_opt_ PVOID Param - ); - -ULONG64 QueryRegistryUlong64( - _In_ HANDLE KeyHandle, - _In_ PWSTR ValueName - ); - VOID ShowDeviceMenu( _In_ HWND ParentWindow, _In_ PPH_STRING DeviceInstance diff --git a/plugins/HardwareDevices/diskdetails.c b/plugins/HardwareDevices/diskdetails.c index 1a713af152aa..21c86e7cbb89 100644 --- a/plugins/HardwareDevices/diskdetails.c +++ b/plugins/HardwareDevices/diskdetails.c @@ -27,126 +27,126 @@ VOID DiskDriveAddListViewItemGroups( _In_ INT DiskGroupId ) { - AddListViewItemGroupId(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_FS_CREATION_TIME, L"Volume creation time", NULL); - AddListViewItemGroupId(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_SERIAL_NUMBER, L"Volume serial number", NULL); - AddListViewItemGroupId(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_FILE_SYSTEM, L"Volume file system", NULL); - AddListViewItemGroupId(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_FS_VERSION, L"Volume version", NULL); - AddListViewItemGroupId(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_LFS_VERSION, L"LFS version", NULL); - - //AddListViewItemGroupId(Context->ListViewHandle, diskGroupId, MAXINT, L"BytesPerPhysicalSector", NULL); - AddListViewItemGroupId(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_TOTAL_SIZE, L"Total size", NULL); - AddListViewItemGroupId(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_TOTAL_FREE, L"Total free", NULL); - AddListViewItemGroupId(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_TOTAL_SECTORS, L"Total sectors", NULL); - AddListViewItemGroupId(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_TOTAL_CLUSTERS, L"Total clusters", NULL); - AddListViewItemGroupId(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_FREE_CLUSTERS, L"Free clusters", NULL); - AddListViewItemGroupId(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_TOTAL_RESERVED, L"Reserved clusters", NULL); - AddListViewItemGroupId(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_TOTAL_BYTES_PER_SECTOR, L"Bytes per sector", NULL); - AddListViewItemGroupId(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_TOTAL_BYTES_PER_CLUSTER, L"Bytes per cluster", NULL); - AddListViewItemGroupId(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_TOTAL_BYTES_PER_RECORD, L"Bytes per file record segment", NULL); - AddListViewItemGroupId(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_TOTAL_CLUSTERS_PER_RECORD, L"Clusters per File record segment", NULL); - - AddListViewItemGroupId(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_RECORDS, L"MFT records", NULL); - AddListViewItemGroupId(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_SIZE, L"MFT size", NULL); - AddListViewItemGroupId(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_START, L"MFT start", NULL); - AddListViewItemGroupId(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_ZONE, L"MFT Zone clusters", NULL); - AddListViewItemGroupId(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_ZONE_SIZE, L"MFT zone size", NULL); - AddListViewItemGroupId(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_MIRROR_START, L"MFT mirror start", NULL); - - AddListViewItemGroupId(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_FILE_READS, L"File reads", NULL); - AddListViewItemGroupId(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_FILE_WRITES, L"File writes", NULL); - AddListViewItemGroupId(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_DISK_READS, L"Disk reads", NULL); - AddListViewItemGroupId(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_DISK_WRITES, L"Disk writes", NULL); - AddListViewItemGroupId(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_FILE_READ_BYTES, L"File read bytes", NULL); - AddListViewItemGroupId(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_FILE_WRITE_BYTES, L"File write bytes", NULL); - - AddListViewItemGroupId(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_METADATA_READS, L"Metadata reads", NULL); - AddListViewItemGroupId(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_METADATA_WRITES, L"Metadata writes", NULL); - AddListViewItemGroupId(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_METADATA_DISK_READS, L"Metadata disk reads", NULL); - AddListViewItemGroupId(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_METADATA_DISK_WRITES, L"Metadata disk writes", NULL); - AddListViewItemGroupId(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_METADATA_READ_BYTES, L"Metadata read bytes", NULL); - AddListViewItemGroupId(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_METADATA_WRITE_BYTES, L"Metadata write bytes", NULL); - - AddListViewItemGroupId(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_READS, L"Mft reads", NULL); - AddListViewItemGroupId(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_WRITES, L"Mft writes", NULL); - AddListViewItemGroupId(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_READ_BYTES, L"Mft read bytes", NULL); - AddListViewItemGroupId(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_WRITE_BYTES, L"Mft write bytes", NULL); - - AddListViewItemGroupId(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_ROOT_INDEX_READS, L"RootIndex reads", NULL); - AddListViewItemGroupId(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_ROOT_INDEX_WRITES, L"RootIndex writes", NULL); - AddListViewItemGroupId(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_ROOT_INDEX_READ_BYTES, L"RootIndex read bytes", NULL); - AddListViewItemGroupId(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_ROOT_INDEX_WRITE_BYTES, L"RootIndex write bytes", NULL); - - AddListViewItemGroupId(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_BITMAP_READS, L"Bitmap reads", NULL); - AddListViewItemGroupId(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_BITMAP_WRITES, L"Bitmap writes", NULL); - AddListViewItemGroupId(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_BITMAP_READ_BYTES, L"Bitmap read bytes", NULL); - AddListViewItemGroupId(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_BITMAP_WRITE_BYTES, L"Bitmap write bytes", NULL); - - AddListViewItemGroupId(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_BITMAP_READS, L"Mft bitmap reads", NULL); - AddListViewItemGroupId(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_BITMAP_WRITES, L"Mft bitmap writes", NULL); - AddListViewItemGroupId(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_BITMAP_READ_BYTES, L"Mft bitmap read bytes", NULL); - AddListViewItemGroupId(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_BITMAP_WRITE_BYTES, L"Mft bitmap write bytes", NULL); - - AddListViewItemGroupId(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_USER_INDEX_READS, L"User Index reads", NULL); - AddListViewItemGroupId(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_USER_INDEX_WRITES, L"User Index writes", NULL); - AddListViewItemGroupId(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_USER_INDEX_READ_BYTES, L"User Index read bytes", NULL); - AddListViewItemGroupId(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_USER_INDEX_WRITE_BYTES, L"User Index write bytes", NULL); - - AddListViewItemGroupId(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_LOGFILE_READS, L"LogFile reads", NULL); - AddListViewItemGroupId(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_LOGFILE_WRITES, L"LogFile writes", NULL); - AddListViewItemGroupId(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_LOGFILE_READ_BYTES, L"LogFile read bytes", NULL); - AddListViewItemGroupId(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_LOGFILE_WRITE_BYTES, L"LogFile write bytes", NULL); - - AddListViewItemGroupId(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_USER_LEVEL_WRITE, L"MftWritesUserLevel-Write", NULL); - AddListViewItemGroupId(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_USER_LEVEL_CREATE, L"MftWritesUserLevel-Create", NULL); - AddListViewItemGroupId(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_USER_LEVEL_SETINFO, L"MftWritesUserLevel-SetInfo", NULL); - AddListViewItemGroupId(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_USER_LEVEL_FLUSH, L"MftWritesUserLevel-Flush", NULL); - - AddListViewItemGroupId(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_WRITES_FLUSH_LOGFILE, L"MftWritesFlushForLogFileFull", NULL); - AddListViewItemGroupId(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_WRITES_LAZY_WRITER, L"MftWritesLazyWriter", NULL); - AddListViewItemGroupId(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_WRITES_USER_REQUEST, L"MftWritesUserRequest", NULL); - - AddListViewItemGroupId(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT2_WRITES, L"Mft2Writes", NULL); - AddListViewItemGroupId(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT2_WRITE_BYTES, L"Mft2WriteBytes", NULL); - - AddListViewItemGroupId(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT2_USER_LEVEL_WRITE, L"Mft2WritesUserLevel-Write", NULL); - AddListViewItemGroupId(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT2_USER_LEVEL_CREATE, L"Mft2WritesUserLevel-Create", NULL); - AddListViewItemGroupId(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT2_USER_LEVEL_SETINFO, L"Mft2WritesUserLevel-SetInfo", NULL); - AddListViewItemGroupId(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT2_USER_LEVEL_FLUSH, L"Mft2WritesUserLevel-Flush", NULL); - - AddListViewItemGroupId(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT2_WRITES_FLUSH_LOGFILE, L"Mft2WritesFlushForLogFileFull", NULL); - AddListViewItemGroupId(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT2_WRITES_LAZY_WRITER, L"Mft2WritesLazyWriter", NULL); - AddListViewItemGroupId(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT2_WRITES_USER_REQUEST, L"Mft2WritesUserRequest", NULL); - - AddListViewItemGroupId(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_BITMAP_WRITES_FLUSH_LOGFILE, L"BitmapWritesFlushForLogFileFull", NULL); - AddListViewItemGroupId(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_BITMAP_WRITES_LAZY_WRITER, L"BitmapWritesLazyWriter", NULL); - AddListViewItemGroupId(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_BITMAP_WRITES_USER_REQUEST, L"BitmapWritesUserRequest", NULL); - - AddListViewItemGroupId(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_BITMAP_WRITES_WRITE, L"BitmapWritesUserLevel-Write", NULL); - AddListViewItemGroupId(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_BITMAP_WRITES_CREATE, L"BitmapWritesUserLevel-Create", NULL); - AddListViewItemGroupId(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_BITMAP_WRITES_SETINFO, L"BitmapWritesUserLevel-SetInfo", NULL); - - AddListViewItemGroupId(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_BITMAP_FLUSH_LOGFILE, L"MftBitmapWritesFlushForLogFileFull", NULL); - AddListViewItemGroupId(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_BITMAP_LAZY_WRITER, L"MftBitmapWritesLazyWriter", NULL); - AddListViewItemGroupId(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_BITMAP_USER_REQUEST, L"MftBitmapWritesUserRequest", NULL); - - AddListViewItemGroupId(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_BITMAP_USER_LEVEL_WRITE, L"MftBitmapWritesUserLevel-Write", NULL); - AddListViewItemGroupId(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_BITMAP_USER_LEVEL_CREATE, L"MftBitmapWritesUserLevel-Create", NULL); - AddListViewItemGroupId(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_BITMAP_USER_LEVEL_SETINFO, L"MftBitmapWritesUserLevel-SetInfo", NULL); - AddListViewItemGroupId(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_BITMAP_USER_LEVEL_FLUSH, L"MftBitmapWritesUserLevel-Flush", NULL); - - AddListViewItemGroupId(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_ALLOCATE_CALLS, L"Allocate-Calls", NULL); - AddListViewItemGroupId(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_ALLOCATE_CLUSTERS, L"Allocate-Clusters", NULL); - AddListViewItemGroupId(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_ALLOCATE_HINTS, L"Allocate-Hints", NULL); - AddListViewItemGroupId(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_ALLOCATE_RUNS_RETURNED, L"Allocate-RunsReturned", NULL); - AddListViewItemGroupId(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_ALLOCATE_HITS_HONORED, L"Allocate-HintsHonored", NULL); - AddListViewItemGroupId(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_ALLOCATE_HITS_CLUSTERS, L"Allocate-HintsClusters", NULL); - AddListViewItemGroupId(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_ALLOCATE_CACHE, L"Allocate-Cache", NULL); - AddListViewItemGroupId(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_ALLOCATE_CACHE_CLUSTERS, L"Allocate-CacheClusters", NULL); - AddListViewItemGroupId(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_ALLOCATE_CACHE_MISS, L"Allocate-CacheMiss", NULL); - AddListViewItemGroupId(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_ALLOCATE_CACHE_MISS_CLUSTERS, L"Allocate-CacheMissClusters", NULL); - - AddListViewItemGroupId(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_LOGFILE_EXCEPTIONS, L"LogFileFullExceptions", NULL); - AddListViewItemGroupId(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_OTHER_EXCEPTIONS, L"OtherExceptions", NULL); + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_FS_CREATION_TIME, L"Volume creation time", NULL); + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_SERIAL_NUMBER, L"Volume serial number", NULL); + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_FILE_SYSTEM, L"Volume file system", NULL); + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_FS_VERSION, L"Volume version", NULL); + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_LFS_VERSION, L"LFS version", NULL); + + //PhAddListViewGroupItem(Context->ListViewHandle, diskGroupId, MAXINT, L"BytesPerPhysicalSector", NULL); + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_TOTAL_SIZE, L"Total size", NULL); + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_TOTAL_FREE, L"Total free", NULL); + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_TOTAL_SECTORS, L"Total sectors", NULL); + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_TOTAL_CLUSTERS, L"Total clusters", NULL); + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_FREE_CLUSTERS, L"Free clusters", NULL); + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_TOTAL_RESERVED, L"Reserved clusters", NULL); + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_TOTAL_BYTES_PER_SECTOR, L"Bytes per sector", NULL); + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_TOTAL_BYTES_PER_CLUSTER, L"Bytes per cluster", NULL); + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_TOTAL_BYTES_PER_RECORD, L"Bytes per file record segment", NULL); + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_TOTAL_CLUSTERS_PER_RECORD, L"Clusters per File record segment", NULL); + + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_RECORDS, L"MFT records", NULL); + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_SIZE, L"MFT size", NULL); + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_START, L"MFT start", NULL); + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_ZONE, L"MFT Zone clusters", NULL); + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_ZONE_SIZE, L"MFT zone size", NULL); + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_MIRROR_START, L"MFT mirror start", NULL); + + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_FILE_READS, L"File reads", NULL); + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_FILE_WRITES, L"File writes", NULL); + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_DISK_READS, L"Disk reads", NULL); + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_DISK_WRITES, L"Disk writes", NULL); + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_FILE_READ_BYTES, L"File read bytes", NULL); + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_FILE_WRITE_BYTES, L"File write bytes", NULL); + + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_METADATA_READS, L"Metadata reads", NULL); + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_METADATA_WRITES, L"Metadata writes", NULL); + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_METADATA_DISK_READS, L"Metadata disk reads", NULL); + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_METADATA_DISK_WRITES, L"Metadata disk writes", NULL); + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_METADATA_READ_BYTES, L"Metadata read bytes", NULL); + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_METADATA_WRITE_BYTES, L"Metadata write bytes", NULL); + + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_READS, L"Mft reads", NULL); + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_WRITES, L"Mft writes", NULL); + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_READ_BYTES, L"Mft read bytes", NULL); + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_WRITE_BYTES, L"Mft write bytes", NULL); + + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_ROOT_INDEX_READS, L"RootIndex reads", NULL); + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_ROOT_INDEX_WRITES, L"RootIndex writes", NULL); + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_ROOT_INDEX_READ_BYTES, L"RootIndex read bytes", NULL); + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_ROOT_INDEX_WRITE_BYTES, L"RootIndex write bytes", NULL); + + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_BITMAP_READS, L"Bitmap reads", NULL); + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_BITMAP_WRITES, L"Bitmap writes", NULL); + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_BITMAP_READ_BYTES, L"Bitmap read bytes", NULL); + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_BITMAP_WRITE_BYTES, L"Bitmap write bytes", NULL); + + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_BITMAP_READS, L"Mft bitmap reads", NULL); + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_BITMAP_WRITES, L"Mft bitmap writes", NULL); + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_BITMAP_READ_BYTES, L"Mft bitmap read bytes", NULL); + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_BITMAP_WRITE_BYTES, L"Mft bitmap write bytes", NULL); + + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_USER_INDEX_READS, L"User Index reads", NULL); + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_USER_INDEX_WRITES, L"User Index writes", NULL); + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_USER_INDEX_READ_BYTES, L"User Index read bytes", NULL); + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_USER_INDEX_WRITE_BYTES, L"User Index write bytes", NULL); + + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_LOGFILE_READS, L"LogFile reads", NULL); + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_LOGFILE_WRITES, L"LogFile writes", NULL); + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_LOGFILE_READ_BYTES, L"LogFile read bytes", NULL); + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_LOGFILE_WRITE_BYTES, L"LogFile write bytes", NULL); + + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_USER_LEVEL_WRITE, L"MftWritesUserLevel-Write", NULL); + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_USER_LEVEL_CREATE, L"MftWritesUserLevel-Create", NULL); + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_USER_LEVEL_SETINFO, L"MftWritesUserLevel-SetInfo", NULL); + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_USER_LEVEL_FLUSH, L"MftWritesUserLevel-Flush", NULL); + + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_WRITES_FLUSH_LOGFILE, L"MftWritesFlushForLogFileFull", NULL); + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_WRITES_LAZY_WRITER, L"MftWritesLazyWriter", NULL); + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_WRITES_USER_REQUEST, L"MftWritesUserRequest", NULL); + + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT2_WRITES, L"Mft2Writes", NULL); + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT2_WRITE_BYTES, L"Mft2WriteBytes", NULL); + + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT2_USER_LEVEL_WRITE, L"Mft2WritesUserLevel-Write", NULL); + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT2_USER_LEVEL_CREATE, L"Mft2WritesUserLevel-Create", NULL); + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT2_USER_LEVEL_SETINFO, L"Mft2WritesUserLevel-SetInfo", NULL); + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT2_USER_LEVEL_FLUSH, L"Mft2WritesUserLevel-Flush", NULL); + + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT2_WRITES_FLUSH_LOGFILE, L"Mft2WritesFlushForLogFileFull", NULL); + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT2_WRITES_LAZY_WRITER, L"Mft2WritesLazyWriter", NULL); + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT2_WRITES_USER_REQUEST, L"Mft2WritesUserRequest", NULL); + + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_BITMAP_WRITES_FLUSH_LOGFILE, L"BitmapWritesFlushForLogFileFull", NULL); + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_BITMAP_WRITES_LAZY_WRITER, L"BitmapWritesLazyWriter", NULL); + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_BITMAP_WRITES_USER_REQUEST, L"BitmapWritesUserRequest", NULL); + + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_BITMAP_WRITES_WRITE, L"BitmapWritesUserLevel-Write", NULL); + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_BITMAP_WRITES_CREATE, L"BitmapWritesUserLevel-Create", NULL); + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_BITMAP_WRITES_SETINFO, L"BitmapWritesUserLevel-SetInfo", NULL); + + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_BITMAP_FLUSH_LOGFILE, L"MftBitmapWritesFlushForLogFileFull", NULL); + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_BITMAP_LAZY_WRITER, L"MftBitmapWritesLazyWriter", NULL); + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_BITMAP_USER_REQUEST, L"MftBitmapWritesUserRequest", NULL); + + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_BITMAP_USER_LEVEL_WRITE, L"MftBitmapWritesUserLevel-Write", NULL); + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_BITMAP_USER_LEVEL_CREATE, L"MftBitmapWritesUserLevel-Create", NULL); + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_BITMAP_USER_LEVEL_SETINFO, L"MftBitmapWritesUserLevel-SetInfo", NULL); + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_BITMAP_USER_LEVEL_FLUSH, L"MftBitmapWritesUserLevel-Flush", NULL); + + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_ALLOCATE_CALLS, L"Allocate-Calls", NULL); + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_ALLOCATE_CLUSTERS, L"Allocate-Clusters", NULL); + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_ALLOCATE_HINTS, L"Allocate-Hints", NULL); + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_ALLOCATE_RUNS_RETURNED, L"Allocate-RunsReturned", NULL); + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_ALLOCATE_HITS_HONORED, L"Allocate-HintsHonored", NULL); + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_ALLOCATE_HITS_CLUSTERS, L"Allocate-HintsClusters", NULL); + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_ALLOCATE_CACHE, L"Allocate-Cache", NULL); + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_ALLOCATE_CACHE_CLUSTERS, L"Allocate-CacheClusters", NULL); + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_ALLOCATE_CACHE_MISS, L"Allocate-CacheMiss", NULL); + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_ALLOCATE_CACHE_MISS_CLUSTERS, L"Allocate-CacheMissClusters", NULL); + + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_LOGFILE_EXCEPTIONS, L"LogFileFullExceptions", NULL); + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_OTHER_EXCEPTIONS, L"OtherExceptions", NULL); } VOID DiskDriveQuerySmart( @@ -252,12 +252,12 @@ VOID DiskDriveQueryFileSystem( if (volumeInfo->VolumeLabelLength > 0) { - diskGroupId = AddListViewGroup(Context->ListViewHandle, i, + diskGroupId = PhAddListViewGroup(Context->ListViewHandle, i, PhaFormatString(L"Volume %wc: [%s]", diskEntry->DeviceLetter, PhaCreateStringEx(volumeInfo->VolumeLabel, volumeInfo->VolumeLabelLength)->Buffer)->Buffer); } else { - diskGroupId = AddListViewGroup(Context->ListViewHandle, i, + diskGroupId = PhAddListViewGroup(Context->ListViewHandle, i, PhaFormatString(L"Volume %wc:", diskEntry->DeviceLetter)->Buffer); } @@ -268,7 +268,7 @@ VOID DiskDriveQueryFileSystem( } else { - diskGroupId = AddListViewGroup( + diskGroupId = PhAddListViewGroup( Context->ListViewHandle, i, PhaFormatString(L"Volume %wc:", diskEntry->DeviceLetter)->Buffer @@ -583,9 +583,9 @@ INT_PTR CALLBACK DiskDriveFileSystemDetailsDlgProc( if (uMsg == WM_DESTROY) { - PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); PhSaveListViewColumnsToSetting(SETTING_NAME_DISK_COUNTERS_COLUMNS, context->ListViewHandle); + PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); PhFree(context); } } diff --git a/plugins/HardwareDevices/main.c b/plugins/HardwareDevices/main.c index 379add20b60c..62f005c6d51b 100644 --- a/plugins/HardwareDevices/main.c +++ b/plugins/HardwareDevices/main.c @@ -159,74 +159,6 @@ PPH_STRING TrimString( return PhCreateString2(&sr); } -INT AddListViewGroup( - _In_ HWND ListViewHandle, - _In_ INT GroupId, - _In_ PWSTR Text - ) -{ - LVGROUP group; - - memset(&group, 0, sizeof(LVGROUP)); - group.cbSize = sizeof(LVGROUP); - group.mask = LVGF_HEADER | LVGF_ALIGN | LVGF_STATE | LVGF_GROUPID; - group.uAlign = LVGA_HEADER_LEFT; - group.state = LVGS_COLLAPSIBLE; - group.iGroupId = GroupId; - group.pszHeader = Text; - - return (INT)ListView_InsertGroup(ListViewHandle, MAXINT, &group); -} - -INT AddListViewItemGroupId( - _In_ HWND ListViewHandle, - _In_ INT GroupId, - _In_ INT Index, - _In_ PWSTR Text, - _In_opt_ PVOID Param - ) -{ - LVITEM item; - - item.mask = LVIF_TEXT | LVIF_GROUPID; - item.iItem = Index; - item.iSubItem = 0; - item.pszText = Text; - item.iGroupId = GroupId; - - if (Param) - { - item.mask |= LVIF_PARAM; - item.lParam = (LPARAM)Param; - } - - return ListView_InsertItem(ListViewHandle, &item); -} - -ULONG64 QueryRegistryUlong64( - _In_ HANDLE KeyHandle, - _In_ PWSTR ValueName - ) -{ - ULONG64 value = 0; - PH_STRINGREF valueName; - PKEY_VALUE_PARTIAL_INFORMATION buffer; - - PhInitializeStringRef(&valueName, ValueName); - - if (NT_SUCCESS(PhQueryValueKey(KeyHandle, &valueName, KeyValuePartialInformation, &buffer))) - { - if (buffer->Type == REG_DWORD || buffer->Type == REG_QWORD) - { - value = *(ULONG64*)buffer->Data; - } - - PhFree(buffer); - } - - return value; -} - VOID ShowDeviceMenu( _In_ HWND ParentWindow, _In_ PPH_STRING DeviceInstance @@ -273,7 +205,7 @@ VOID ShowDeviceMenu( { if (DeviceProperties_RunDLL_I = PhGetProcedureAddress(devMgrHandle, "DeviceProperties_RunDLLW", 0)) { - // This will sometimes re-throw an RPC error during debugging and can be safely ignored. + // This will sometimes re-throw an RPC error while debugging and can safely be ignored. DeviceProperties_RunDLL_I( GetParent(ParentWindow), NULL, diff --git a/plugins/HardwareDevices/netdetails.c b/plugins/HardwareDevices/netdetails.c index 1485bbcad47d..61107d420d90 100644 --- a/plugins/HardwareDevices/netdetails.c +++ b/plugins/HardwareDevices/netdetails.c @@ -41,58 +41,58 @@ VOID NetAdapterAddListViewItemGroups( ) { ListView_EnableGroupView(ListViewHandle, TRUE); - AddListViewGroup(ListViewHandle, NETADAPTER_DETAILS_CATEGORY_ADAPTER, L"Adapter"); - AddListViewGroup(ListViewHandle, NETADAPTER_DETAILS_CATEGORY_UNICAST, L"Unicast"); - AddListViewGroup(ListViewHandle, NETADAPTER_DETAILS_CATEGORY_BROADCAST, L"Broadcast"); - AddListViewGroup(ListViewHandle, NETADAPTER_DETAILS_CATEGORY_MULTICAST, L"Multicast"); - AddListViewGroup(ListViewHandle, NETADAPTER_DETAILS_CATEGORY_ERRORS, L"Errors"); - - AddListViewItemGroupId(ListViewHandle, NETADAPTER_DETAILS_CATEGORY_ADAPTER, NETADAPTER_DETAILS_INDEX_STATE, L"State", NULL); - //AddListViewItemGroupId(ListViewHandle, NETADAPTER_DETAILS_CATEGORY_ADAPTER, NETADAPTER_DETAILS_INDEX_CONNECTIVITY, L"Connectivity"); - AddListViewItemGroupId(ListViewHandle, NETADAPTER_DETAILS_CATEGORY_ADAPTER, NETADAPTER_DETAILS_INDEX_IPADDRESS, L"IP address", NULL); - AddListViewItemGroupId(ListViewHandle, NETADAPTER_DETAILS_CATEGORY_ADAPTER, NETADAPTER_DETAILS_INDEX_SUBNET, L"Subnet mask", NULL); - AddListViewItemGroupId(ListViewHandle, NETADAPTER_DETAILS_CATEGORY_ADAPTER, NETADAPTER_DETAILS_INDEX_GATEWAY, L"Default gateway", NULL); - AddListViewItemGroupId(ListViewHandle, NETADAPTER_DETAILS_CATEGORY_ADAPTER, NETADAPTER_DETAILS_INDEX_DNS, L"DNS", NULL); - AddListViewItemGroupId(ListViewHandle, NETADAPTER_DETAILS_CATEGORY_ADAPTER, NETADAPTER_DETAILS_INDEX_DOMAIN, L"Domain", NULL); - - AddListViewItemGroupId(ListViewHandle, NETADAPTER_DETAILS_CATEGORY_ADAPTER, NETADAPTER_DETAILS_INDEX_LINKSPEED, L"Link speed", NULL); - AddListViewItemGroupId(ListViewHandle, NETADAPTER_DETAILS_CATEGORY_ADAPTER, NETADAPTER_DETAILS_INDEX_SENT, L"Sent", NULL); - AddListViewItemGroupId(ListViewHandle, NETADAPTER_DETAILS_CATEGORY_ADAPTER, NETADAPTER_DETAILS_INDEX_RECEIVED, L"Received", NULL); - AddListViewItemGroupId(ListViewHandle, NETADAPTER_DETAILS_CATEGORY_ADAPTER, NETADAPTER_DETAILS_INDEX_TOTAL, L"Total", NULL); - AddListViewItemGroupId(ListViewHandle, NETADAPTER_DETAILS_CATEGORY_ADAPTER, NETADAPTER_DETAILS_INDEX_SENDING, L"Sending", NULL); - AddListViewItemGroupId(ListViewHandle, NETADAPTER_DETAILS_CATEGORY_ADAPTER, NETADAPTER_DETAILS_INDEX_RECEIVING, L"Receiving", NULL); - AddListViewItemGroupId(ListViewHandle, NETADAPTER_DETAILS_CATEGORY_ADAPTER, NETADAPTER_DETAILS_INDEX_UTILIZATION, L"Utilization", NULL); - - AddListViewItemGroupId(ListViewHandle, NETADAPTER_DETAILS_CATEGORY_UNICAST, NETADAPTER_DETAILS_INDEX_UNICAST_SENTPKTS, L"Sent packets", NULL); - AddListViewItemGroupId(ListViewHandle, NETADAPTER_DETAILS_CATEGORY_UNICAST, NETADAPTER_DETAILS_INDEX_UNICAST_RECVPKTS, L"Received packets", NULL); - AddListViewItemGroupId(ListViewHandle, NETADAPTER_DETAILS_CATEGORY_UNICAST, NETADAPTER_DETAILS_INDEX_UNICAST_TOTALPKTS, L"Total packets", NULL); - AddListViewItemGroupId(ListViewHandle, NETADAPTER_DETAILS_CATEGORY_UNICAST, NETADAPTER_DETAILS_INDEX_UNICAST_SENT, L"Sent", NULL); - AddListViewItemGroupId(ListViewHandle, NETADAPTER_DETAILS_CATEGORY_UNICAST, NETADAPTER_DETAILS_INDEX_UNICAST_RECEIVED, L"Received", NULL); - AddListViewItemGroupId(ListViewHandle, NETADAPTER_DETAILS_CATEGORY_UNICAST, NETADAPTER_DETAILS_INDEX_UNICAST_TOTAL, L"Total", NULL); - //AddListViewItemGroupId(ListViewHandle, NETADAPTER_DETAILS_CATEGORY_UNICAST, NETADAPTER_DETAILS_INDEX_UNICAST_SENDING, L"Sending"); - //AddListViewItemGroupId(ListViewHandle, NETADAPTER_DETAILS_CATEGORY_UNICAST, NETADAPTER_DETAILS_INDEX_UNICAST_RECEIVING, L"Receiving"); - //AddListViewItemGroupId(ListViewHandle, NETADAPTER_DETAILS_CATEGORY_UNICAST, NETADAPTER_DETAILS_INDEX_UNICAST_UTILIZATION, L"Utilization"); - - AddListViewItemGroupId(ListViewHandle, NETADAPTER_DETAILS_CATEGORY_BROADCAST, NETADAPTER_DETAILS_INDEX_BROADCAST_SENTPKTS, L"Sent packets", NULL); - AddListViewItemGroupId(ListViewHandle, NETADAPTER_DETAILS_CATEGORY_BROADCAST, NETADAPTER_DETAILS_INDEX_BROADCAST_RECVPKTS, L"Received packets", NULL); - AddListViewItemGroupId(ListViewHandle, NETADAPTER_DETAILS_CATEGORY_BROADCAST, NETADAPTER_DETAILS_INDEX_BROADCAST_TOTALPKTS, L"Total packets", NULL); - AddListViewItemGroupId(ListViewHandle, NETADAPTER_DETAILS_CATEGORY_BROADCAST, NETADAPTER_DETAILS_INDEX_BROADCAST_SENT, L"Sent", NULL); - AddListViewItemGroupId(ListViewHandle, NETADAPTER_DETAILS_CATEGORY_BROADCAST, NETADAPTER_DETAILS_INDEX_BROADCAST_RECEIVED, L"Received", NULL); - AddListViewItemGroupId(ListViewHandle, NETADAPTER_DETAILS_CATEGORY_BROADCAST, NETADAPTER_DETAILS_INDEX_BROADCAST_TOTAL, L"Total", NULL); - - AddListViewItemGroupId(ListViewHandle, NETADAPTER_DETAILS_CATEGORY_MULTICAST, NETADAPTER_DETAILS_INDEX_MULTICAST_SENTPKTS, L"Sent packets", NULL); - AddListViewItemGroupId(ListViewHandle, NETADAPTER_DETAILS_CATEGORY_MULTICAST, NETADAPTER_DETAILS_INDEX_MULTICAST_RECVPKTS, L"Received packets", NULL); - AddListViewItemGroupId(ListViewHandle, NETADAPTER_DETAILS_CATEGORY_MULTICAST, NETADAPTER_DETAILS_INDEX_MULTICAST_TOTALPKTS, L"Total packets", NULL); - AddListViewItemGroupId(ListViewHandle, NETADAPTER_DETAILS_CATEGORY_MULTICAST, NETADAPTER_DETAILS_INDEX_MULTICAST_SENT, L"Sent", NULL); - AddListViewItemGroupId(ListViewHandle, NETADAPTER_DETAILS_CATEGORY_MULTICAST, NETADAPTER_DETAILS_INDEX_MULTICAST_RECEIVED, L"Received", NULL); - AddListViewItemGroupId(ListViewHandle, NETADAPTER_DETAILS_CATEGORY_MULTICAST, NETADAPTER_DETAILS_INDEX_MULTICAST_TOTAL, L"Total", NULL); - - AddListViewItemGroupId(ListViewHandle, NETADAPTER_DETAILS_CATEGORY_ERRORS, NETADAPTER_DETAILS_INDEX_ERRORS_SENTPKTS, L"Send errors", NULL); - AddListViewItemGroupId(ListViewHandle, NETADAPTER_DETAILS_CATEGORY_ERRORS, NETADAPTER_DETAILS_INDEX_ERRORS_RECVPKTS, L"Receive errors", NULL); - AddListViewItemGroupId(ListViewHandle, NETADAPTER_DETAILS_CATEGORY_ERRORS, NETADAPTER_DETAILS_INDEX_ERRORS_TOTALPKTS, L"Total errors", NULL); - AddListViewItemGroupId(ListViewHandle, NETADAPTER_DETAILS_CATEGORY_ERRORS, NETADAPTER_DETAILS_INDEX_ERRORS_SENT, L"Send discards", NULL); - AddListViewItemGroupId(ListViewHandle, NETADAPTER_DETAILS_CATEGORY_ERRORS, NETADAPTER_DETAILS_INDEX_ERRORS_RECEIVED, L"Receive discards", NULL); - AddListViewItemGroupId(ListViewHandle, NETADAPTER_DETAILS_CATEGORY_ERRORS, NETADAPTER_DETAILS_INDEX_ERRORS_TOTAL, L"Total discards", NULL); + PhAddListViewGroup(ListViewHandle, NETADAPTER_DETAILS_CATEGORY_ADAPTER, L"Adapter"); + PhAddListViewGroup(ListViewHandle, NETADAPTER_DETAILS_CATEGORY_UNICAST, L"Unicast"); + PhAddListViewGroup(ListViewHandle, NETADAPTER_DETAILS_CATEGORY_BROADCAST, L"Broadcast"); + PhAddListViewGroup(ListViewHandle, NETADAPTER_DETAILS_CATEGORY_MULTICAST, L"Multicast"); + PhAddListViewGroup(ListViewHandle, NETADAPTER_DETAILS_CATEGORY_ERRORS, L"Errors"); + + PhAddListViewGroupItem(ListViewHandle, NETADAPTER_DETAILS_CATEGORY_ADAPTER, NETADAPTER_DETAILS_INDEX_STATE, L"State", NULL); + //PhAddListViewGroupItem(ListViewHandle, NETADAPTER_DETAILS_CATEGORY_ADAPTER, NETADAPTER_DETAILS_INDEX_CONNECTIVITY, L"Connectivity"); + PhAddListViewGroupItem(ListViewHandle, NETADAPTER_DETAILS_CATEGORY_ADAPTER, NETADAPTER_DETAILS_INDEX_IPADDRESS, L"IP address", NULL); + PhAddListViewGroupItem(ListViewHandle, NETADAPTER_DETAILS_CATEGORY_ADAPTER, NETADAPTER_DETAILS_INDEX_SUBNET, L"Subnet mask", NULL); + PhAddListViewGroupItem(ListViewHandle, NETADAPTER_DETAILS_CATEGORY_ADAPTER, NETADAPTER_DETAILS_INDEX_GATEWAY, L"Default gateway", NULL); + PhAddListViewGroupItem(ListViewHandle, NETADAPTER_DETAILS_CATEGORY_ADAPTER, NETADAPTER_DETAILS_INDEX_DNS, L"DNS", NULL); + PhAddListViewGroupItem(ListViewHandle, NETADAPTER_DETAILS_CATEGORY_ADAPTER, NETADAPTER_DETAILS_INDEX_DOMAIN, L"Domain", NULL); + + PhAddListViewGroupItem(ListViewHandle, NETADAPTER_DETAILS_CATEGORY_ADAPTER, NETADAPTER_DETAILS_INDEX_LINKSPEED, L"Link speed", NULL); + PhAddListViewGroupItem(ListViewHandle, NETADAPTER_DETAILS_CATEGORY_ADAPTER, NETADAPTER_DETAILS_INDEX_SENT, L"Sent", NULL); + PhAddListViewGroupItem(ListViewHandle, NETADAPTER_DETAILS_CATEGORY_ADAPTER, NETADAPTER_DETAILS_INDEX_RECEIVED, L"Received", NULL); + PhAddListViewGroupItem(ListViewHandle, NETADAPTER_DETAILS_CATEGORY_ADAPTER, NETADAPTER_DETAILS_INDEX_TOTAL, L"Total", NULL); + PhAddListViewGroupItem(ListViewHandle, NETADAPTER_DETAILS_CATEGORY_ADAPTER, NETADAPTER_DETAILS_INDEX_SENDING, L"Sending", NULL); + PhAddListViewGroupItem(ListViewHandle, NETADAPTER_DETAILS_CATEGORY_ADAPTER, NETADAPTER_DETAILS_INDEX_RECEIVING, L"Receiving", NULL); + PhAddListViewGroupItem(ListViewHandle, NETADAPTER_DETAILS_CATEGORY_ADAPTER, NETADAPTER_DETAILS_INDEX_UTILIZATION, L"Utilization", NULL); + + PhAddListViewGroupItem(ListViewHandle, NETADAPTER_DETAILS_CATEGORY_UNICAST, NETADAPTER_DETAILS_INDEX_UNICAST_SENTPKTS, L"Sent packets", NULL); + PhAddListViewGroupItem(ListViewHandle, NETADAPTER_DETAILS_CATEGORY_UNICAST, NETADAPTER_DETAILS_INDEX_UNICAST_RECVPKTS, L"Received packets", NULL); + PhAddListViewGroupItem(ListViewHandle, NETADAPTER_DETAILS_CATEGORY_UNICAST, NETADAPTER_DETAILS_INDEX_UNICAST_TOTALPKTS, L"Total packets", NULL); + PhAddListViewGroupItem(ListViewHandle, NETADAPTER_DETAILS_CATEGORY_UNICAST, NETADAPTER_DETAILS_INDEX_UNICAST_SENT, L"Sent", NULL); + PhAddListViewGroupItem(ListViewHandle, NETADAPTER_DETAILS_CATEGORY_UNICAST, NETADAPTER_DETAILS_INDEX_UNICAST_RECEIVED, L"Received", NULL); + PhAddListViewGroupItem(ListViewHandle, NETADAPTER_DETAILS_CATEGORY_UNICAST, NETADAPTER_DETAILS_INDEX_UNICAST_TOTAL, L"Total", NULL); + //PhAddListViewGroupItem(ListViewHandle, NETADAPTER_DETAILS_CATEGORY_UNICAST, NETADAPTER_DETAILS_INDEX_UNICAST_SENDING, L"Sending"); + //PhAddListViewGroupItem(ListViewHandle, NETADAPTER_DETAILS_CATEGORY_UNICAST, NETADAPTER_DETAILS_INDEX_UNICAST_RECEIVING, L"Receiving"); + //PhAddListViewGroupItem(ListViewHandle, NETADAPTER_DETAILS_CATEGORY_UNICAST, NETADAPTER_DETAILS_INDEX_UNICAST_UTILIZATION, L"Utilization"); + + PhAddListViewGroupItem(ListViewHandle, NETADAPTER_DETAILS_CATEGORY_BROADCAST, NETADAPTER_DETAILS_INDEX_BROADCAST_SENTPKTS, L"Sent packets", NULL); + PhAddListViewGroupItem(ListViewHandle, NETADAPTER_DETAILS_CATEGORY_BROADCAST, NETADAPTER_DETAILS_INDEX_BROADCAST_RECVPKTS, L"Received packets", NULL); + PhAddListViewGroupItem(ListViewHandle, NETADAPTER_DETAILS_CATEGORY_BROADCAST, NETADAPTER_DETAILS_INDEX_BROADCAST_TOTALPKTS, L"Total packets", NULL); + PhAddListViewGroupItem(ListViewHandle, NETADAPTER_DETAILS_CATEGORY_BROADCAST, NETADAPTER_DETAILS_INDEX_BROADCAST_SENT, L"Sent", NULL); + PhAddListViewGroupItem(ListViewHandle, NETADAPTER_DETAILS_CATEGORY_BROADCAST, NETADAPTER_DETAILS_INDEX_BROADCAST_RECEIVED, L"Received", NULL); + PhAddListViewGroupItem(ListViewHandle, NETADAPTER_DETAILS_CATEGORY_BROADCAST, NETADAPTER_DETAILS_INDEX_BROADCAST_TOTAL, L"Total", NULL); + + PhAddListViewGroupItem(ListViewHandle, NETADAPTER_DETAILS_CATEGORY_MULTICAST, NETADAPTER_DETAILS_INDEX_MULTICAST_SENTPKTS, L"Sent packets", NULL); + PhAddListViewGroupItem(ListViewHandle, NETADAPTER_DETAILS_CATEGORY_MULTICAST, NETADAPTER_DETAILS_INDEX_MULTICAST_RECVPKTS, L"Received packets", NULL); + PhAddListViewGroupItem(ListViewHandle, NETADAPTER_DETAILS_CATEGORY_MULTICAST, NETADAPTER_DETAILS_INDEX_MULTICAST_TOTALPKTS, L"Total packets", NULL); + PhAddListViewGroupItem(ListViewHandle, NETADAPTER_DETAILS_CATEGORY_MULTICAST, NETADAPTER_DETAILS_INDEX_MULTICAST_SENT, L"Sent", NULL); + PhAddListViewGroupItem(ListViewHandle, NETADAPTER_DETAILS_CATEGORY_MULTICAST, NETADAPTER_DETAILS_INDEX_MULTICAST_RECEIVED, L"Received", NULL); + PhAddListViewGroupItem(ListViewHandle, NETADAPTER_DETAILS_CATEGORY_MULTICAST, NETADAPTER_DETAILS_INDEX_MULTICAST_TOTAL, L"Total", NULL); + + PhAddListViewGroupItem(ListViewHandle, NETADAPTER_DETAILS_CATEGORY_ERRORS, NETADAPTER_DETAILS_INDEX_ERRORS_SENTPKTS, L"Send errors", NULL); + PhAddListViewGroupItem(ListViewHandle, NETADAPTER_DETAILS_CATEGORY_ERRORS, NETADAPTER_DETAILS_INDEX_ERRORS_RECVPKTS, L"Receive errors", NULL); + PhAddListViewGroupItem(ListViewHandle, NETADAPTER_DETAILS_CATEGORY_ERRORS, NETADAPTER_DETAILS_INDEX_ERRORS_TOTALPKTS, L"Total errors", NULL); + PhAddListViewGroupItem(ListViewHandle, NETADAPTER_DETAILS_CATEGORY_ERRORS, NETADAPTER_DETAILS_INDEX_ERRORS_SENT, L"Send discards", NULL); + PhAddListViewGroupItem(ListViewHandle, NETADAPTER_DETAILS_CATEGORY_ERRORS, NETADAPTER_DETAILS_INDEX_ERRORS_RECEIVED, L"Receive discards", NULL); + PhAddListViewGroupItem(ListViewHandle, NETADAPTER_DETAILS_CATEGORY_ERRORS, NETADAPTER_DETAILS_INDEX_ERRORS_TOTAL, L"Total discards", NULL); } PVOID NetAdapterGetAddresses( diff --git a/plugins/HardwareDevices/netoptions.c b/plugins/HardwareDevices/netoptions.c index 5df23140da9a..2fe95a8311af 100644 --- a/plugins/HardwareDevices/netoptions.c +++ b/plugins/HardwareDevices/netoptions.c @@ -216,7 +216,7 @@ VOID AddNetworkAdapterToListView( PhMoveReference(&newId->InterfaceGuid, Guid); } - lvItemIndex = AddListViewItemGroupId( + lvItemIndex = PhAddListViewGroupItem( Context->ListViewHandle, AdapterPresent ? 0 : 1, MAXINT, @@ -297,7 +297,7 @@ BOOLEAN QueryNetworkDeviceInterfaceDescription( // We use our NetworkAdapterQueryName function to query the full adapter name // from the NDIS driver directly, if that fails then we use one of the above properties. - if ((result = CM_Get_DevNode_Property( // CM_Get_DevNode_Registry_Property with CM_DRP_DEVICEDESC?? + if ((result = CM_Get_DevNode_Property( deviceInstanceHandle, WindowsVersion >= WINDOWS_8 ? &DEVPKEY_Device_FriendlyName : &DEVPKEY_Device_DeviceDesc, &devicePropertyType, @@ -437,8 +437,8 @@ VOID FindNetworkAdapters( adapterEntry->DeviceGuid = PhQueryRegistryString(keyHandle, L"NetCfgInstanceId"); adapterEntry->DeviceInterface = PhConcatStrings2(L"\\\\.\\", adapterEntry->DeviceGuid->Buffer); - adapterEntry->DeviceLuid.Info.IfType = QueryRegistryUlong64(keyHandle, L"*IfType"); - adapterEntry->DeviceLuid.Info.NetLuidIndex = QueryRegistryUlong64(keyHandle, L"NetLuidIndex"); + adapterEntry->DeviceLuid.Info.IfType = PhQueryRegistryUlong64(keyHandle, L"*IfType"); + adapterEntry->DeviceLuid.Info.NetLuidIndex = PhQueryRegistryUlong64(keyHandle, L"NetLuidIndex"); if (NT_SUCCESS(NetworkAdapterCreateHandle(&deviceHandle, adapterEntry->DeviceInterface))) { @@ -733,8 +733,8 @@ INT_PTR CALLBACK NetworkAdapterOptionsDlgProc( PhSetExtendedListView(context->ListViewHandle); ListView_EnableGroupView(context->ListViewHandle, TRUE); - AddListViewGroup(context->ListViewHandle, 0, L"Connected"); - AddListViewGroup(context->ListViewHandle, 1, L"Disconnected"); + PhAddListViewGroup(context->ListViewHandle, 0, L"Connected"); + PhAddListViewGroup(context->ListViewHandle, 1, L"Disconnected"); PhInitializeLayoutManager(&context->LayoutManager, hwndDlg); PhAddLayoutItem(&context->LayoutManager, context->ListViewHandle, NULL, PH_ANCHOR_ALL); From 78fe700f82204f45ffb122e059163a8690de0173 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 9 Jun 2018 12:11:30 +1000 Subject: [PATCH 1020/2058] HardwareDevices: Remove legacy functions --- plugins/HardwareDevices/diskoptions.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/HardwareDevices/diskoptions.c b/plugins/HardwareDevices/diskoptions.c index b3648a3db728..56813eb16c93 100644 --- a/plugins/HardwareDevices/diskoptions.c +++ b/plugins/HardwareDevices/diskoptions.c @@ -198,7 +198,7 @@ VOID AddDiskDriveToListView( PhMoveReference(&newId->DevicePath, DiskPath); } - lvItemIndex = AddListViewItemGroupId( + lvItemIndex = PhAddListViewGroupItem( Context->ListViewHandle, DiskPresent ? 0 : 1, MAXINT, @@ -630,8 +630,8 @@ INT_PTR CALLBACK DiskDriveOptionsDlgProc( PhSetExtendedListView(context->ListViewHandle); ListView_EnableGroupView(context->ListViewHandle, TRUE); - AddListViewGroup(context->ListViewHandle, 0, L"Connected"); - AddListViewGroup(context->ListViewHandle, 1, L"Disconnected"); + PhAddListViewGroup(context->ListViewHandle, 0, L"Connected"); + PhAddListViewGroup(context->ListViewHandle, 1, L"Disconnected"); PhInitializeLayoutManager(&context->LayoutManager, hwndDlg); PhAddLayoutItem(&context->LayoutManager, context->ListViewHandle, NULL, PH_ANCHOR_ALL); From bfa4c06d133f01120c1a8afbd2f35675a6f153c7 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 9 Jun 2018 12:15:53 +1000 Subject: [PATCH 1021/2058] Fix handles tab showing 'Non-existent process' for newly created handles --- ProcessHacker/procprv.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ProcessHacker/procprv.c b/ProcessHacker/procprv.c index 805605b2340f..3a00afaabfd6 100644 --- a/ProcessHacker/procprv.c +++ b/ProcessHacker/procprv.c @@ -333,7 +333,9 @@ PPH_STRING PhGetClientIdName( } else { - name = PhGetClientIdNameEx(ClientId, NULL); + // HACK + // Workaround race condition with newly created process handles showing as 'Non-existent process' -dmex + name = PhStdGetClientIdName(ClientId); } return name; From 02899f309ca25ea710423f6a4de9a550afe3ef9d Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 9 Jun 2018 12:17:06 +1000 Subject: [PATCH 1022/2058] Ignore WSL processes when querying process information --- ProcessHacker/procprv.c | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/ProcessHacker/procprv.c b/ProcessHacker/procprv.c index 3a00afaabfd6..a588cdac81f9 100644 --- a/ProcessHacker/procprv.c +++ b/ProcessHacker/procprv.c @@ -257,16 +257,12 @@ BOOLEAN PhProcessProviderInitialization( PhProcessRecordList = PhCreateList(40); - PhDpcsProcessInformation = PhAllocate(sizeof(SYSTEM_PROCESS_INFORMATION) + sizeof(SYSTEM_PROCESS_INFORMATION_EXTENSION)); - memset(PhDpcsProcessInformation, 0, sizeof(SYSTEM_PROCESS_INFORMATION) + sizeof(SYSTEM_PROCESS_INFORMATION_EXTENSION)); - - PhInterruptsProcessInformation = PhAllocate(sizeof(SYSTEM_PROCESS_INFORMATION) + sizeof(SYSTEM_PROCESS_INFORMATION_EXTENSION)); - memset(PhInterruptsProcessInformation, 0, sizeof(SYSTEM_PROCESS_INFORMATION) + sizeof(SYSTEM_PROCESS_INFORMATION_EXTENSION)); - + PhDpcsProcessInformation = PhAllocateZero(sizeof(SYSTEM_PROCESS_INFORMATION) + sizeof(SYSTEM_PROCESS_INFORMATION_EXTENSION)); RtlInitUnicodeString(&PhDpcsProcessInformation->ImageName, L"DPCs"); PhDpcsProcessInformation->UniqueProcessId = DPCS_PROCESS_ID; PhDpcsProcessInformation->InheritedFromUniqueProcessId = SYSTEM_IDLE_PROCESS_ID; + PhInterruptsProcessInformation = PhAllocateZero(sizeof(SYSTEM_PROCESS_INFORMATION) + sizeof(SYSTEM_PROCESS_INFORMATION_EXTENSION)); RtlInitUnicodeString(&PhInterruptsProcessInformation->ImageName, L"Interrupts"); PhInterruptsProcessInformation->UniqueProcessId = INTERRUPTS_PROCESS_ID; PhInterruptsProcessInformation->InheritedFromUniqueProcessId = SYSTEM_IDLE_PROCESS_ID; @@ -739,7 +735,7 @@ VOID PhpProcessQueryStage1( HANDLE processId = processItem->ProcessId; HANDLE processHandleLimited = processItem->QueryHandle; - if (processItem->FileName) + if (processItem->FileName && !processItem->IsSubsystemProcess) { if (!PhExtractIcon( processItem->FileName->Buffer, @@ -756,7 +752,7 @@ VOID PhpProcessQueryStage1( } // Debugged - if (processHandleLimited) + if (processHandleLimited && !processItem->IsSubsystemProcess) { BOOLEAN isBeingDebugged; @@ -767,7 +763,7 @@ VOID PhpProcessQueryStage1( } // Command line, .NET - if (processHandleLimited) + if (processHandleLimited && !processItem->IsSubsystemProcess) { BOOLEAN isDotNet = FALSE; HANDLE processHandle = NULL; @@ -866,7 +862,7 @@ VOID PhpProcessQueryStage1( &jobHandle ); - if (NT_SUCCESS(status) && status != STATUS_PROCESS_NOT_IN_JOB && jobHandle) + if (NT_SUCCESS(status) && status != STATUS_PROCESS_NOT_IN_JOB) { JOBOBJECT_BASIC_LIMIT_INFORMATION basicLimits; @@ -875,7 +871,7 @@ VOID PhpProcessQueryStage1( PhGetHandleInformation( NtCurrentProcess(), jobHandle, - -1, + ULONG_MAX, NULL, NULL, NULL, @@ -889,9 +885,10 @@ VOID PhpProcessQueryStage1( Data->IsInSignificantJob = basicLimits.LimitFlags != JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK; } + } + if (jobHandle) NtClose(jobHandle); - } } else { @@ -912,7 +909,7 @@ VOID PhpProcessQueryStage1( } // Immersive - if (processHandleLimited && IsImmersiveProcess_I) + if (processHandleLimited && IsImmersiveProcess_I && !processItem->IsSubsystemProcess) { Data->IsImmersive = !!IsImmersiveProcess_I(processHandleLimited); } @@ -956,7 +953,7 @@ VOID PhpProcessQueryStage2( { PPH_PROCESS_ITEM processItem = Data->Header.ProcessItem; - if (PhEnableProcessQueryStage2 && processItem->FileName) + if (PhEnableProcessQueryStage2 && processItem->FileName && !processItem->IsSubsystemProcess) { NTSTATUS status; From 86b65dd99fa705ffe260dc89769aaa1ab6d64a20 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 9 Jun 2018 12:17:25 +1000 Subject: [PATCH 1023/2058] Remove unused code --- ProcessHacker/procprv.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/ProcessHacker/procprv.c b/ProcessHacker/procprv.c index a588cdac81f9..f54093a7a59e 100644 --- a/ProcessHacker/procprv.c +++ b/ProcessHacker/procprv.c @@ -239,8 +239,6 @@ PH_CIRCULAR_BUFFER_ULONG64 PhMaxIoReadOtherHistory; PH_CIRCULAR_BUFFER_ULONG64 PhMaxIoWriteHistory; #endif -static PTS_ALL_PROCESSES_INFO PhpTsProcesses = NULL; -static ULONG PhpTsNumberOfProcesses; static PPH_HASHTABLE PhpSidFullNameCacheHashtable; BOOLEAN PhProcessProviderInitialization( @@ -2286,12 +2284,6 @@ VOID PhProcessProviderUpdate( PhProcessInformation = processes; - if (PhpTsProcesses) - { - WinStationFreeGAPMemory(0, PhpTsProcesses, PhpTsNumberOfProcesses); - PhpTsProcesses = NULL; - } - PhpFlushSidFullNameCache(); // History cannot be updated on the first run because the deltas are invalid. For example, the From 33f133803b3ac44c7819623365ff3171c40e459e Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 9 Jun 2018 12:22:52 +1000 Subject: [PATCH 1024/2058] Fix typo --- ProcessHacker/ntobjprp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ProcessHacker/ntobjprp.c b/ProcessHacker/ntobjprp.c index 8515ea328b7e..72b67c6e49e5 100644 --- a/ProcessHacker/ntobjprp.c +++ b/ProcessHacker/ntobjprp.c @@ -481,7 +481,7 @@ static VOID PhpRefreshFilePageInfo( PhInitFormatI64U(&format[0], filePositionInfo.CurrentByteOffset.QuadPart); format[0].Type |= FormatGroupDigits; PhInitFormatS(&format[1], L" ("); - PhInitFormatF(&format[2], (double)filePositionInfo.CurrentByteOffset.QuadPart / fileStandardInfo.EndOfFile.QuadPart * 100, 1); + PhInitFormatF(&format[2], (DOUBLE)(filePositionInfo.CurrentByteOffset.QuadPart / fileStandardInfo.EndOfFile.QuadPart * 100), 1); PhInitFormatS(&format[3], L"%)"); filePosStr = PhFormat(format, 4, 18); From 1de068de789605e2212f5128fc198af4cafe0501 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 9 Jun 2018 12:24:39 +1000 Subject: [PATCH 1025/2058] Add advanced thread stack highlighting settings --- ProcessHacker/include/phsettings.h | 5 +++++ ProcessHacker/settings.c | 10 ++++++++++ ProcessHacker/thrdstk.c | 25 ++++++++++++++++++++----- 3 files changed, 35 insertions(+), 5 deletions(-) diff --git a/ProcessHacker/include/phsettings.h b/ProcessHacker/include/phsettings.h index d65d55d98f3e..a457ded4dd4b 100644 --- a/ProcessHacker/include/phsettings.h +++ b/ProcessHacker/include/phsettings.h @@ -75,6 +75,11 @@ EXT ULONG PhCsColorServiceDisabled; EXT ULONG PhCsUseColorServiceStop; EXT ULONG PhCsColorServiceStop; +EXT ULONG PhCsUseColorSystemThreadStack; +EXT ULONG PhCsColorSystemThreadStack; +EXT ULONG PhCsUseColorUserThreadStack; +EXT ULONG PhCsColorUserThreadStack; + #define PH_SET_INTEGER_CACHED_SETTING(Name, Value) (PhSetIntegerSetting(L#Name, PhCs##Name = (Value))) #endif diff --git a/ProcessHacker/settings.c b/ProcessHacker/settings.c index eee4636b8117..fcf2681d6139 100644 --- a/ProcessHacker/settings.c +++ b/ProcessHacker/settings.c @@ -217,6 +217,11 @@ VOID PhAddDefaultSettings( PhpAddIntegerSetting(L"UseColorUnknown", L"1"); PhpAddIntegerSetting(L"ColorUnknown", L"8080ff"); // Light Red + PhpAddIntegerSetting(L"UseColorSystemThreadStack", L"0"); + PhpAddIntegerSetting(L"ColorSystemThreadStack", L"ffccaa"); + PhpAddIntegerSetting(L"UseColorUserThreadStack", L"0"); + PhpAddIntegerSetting(L"ColorUserThreadStack", L"aaffff"); + PhpAddIntegerSetting(L"GraphShowText", L"1"); PhpAddIntegerSetting(L"GraphColorMode", L"0"); PhpAddIntegerSetting(L"ColorCpuKernel", L"00ff00"); @@ -286,6 +291,11 @@ VOID PhUpdateCachedSettings( PH_UPDATE_SETTING(UseColorUnknown); PH_UPDATE_SETTING(ColorUnknown); + PH_UPDATE_SETTING(UseColorSystemThreadStack); + PH_UPDATE_SETTING(ColorSystemThreadStack); + PH_UPDATE_SETTING(UseColorUserThreadStack); + PH_UPDATE_SETTING(ColorUserThreadStack); + PH_UPDATE_SETTING(GraphShowText); PH_UPDATE_SETTING(GraphColorMode); PH_UPDATE_SETTING(ColorCpuKernel); diff --git a/ProcessHacker/thrdstk.c b/ProcessHacker/thrdstk.c index d706eb630796..57af13151de6 100644 --- a/ProcessHacker/thrdstk.c +++ b/ProcessHacker/thrdstk.c @@ -22,6 +22,7 @@ */ #include +#include #include #include @@ -451,6 +452,15 @@ BOOLEAN NTAPI ThreadStackTreeNewCallback( PPH_TREENEW_GET_NODE_COLOR getNodeColor = Parameter1; node = (PPH_STACK_TREE_ROOT_NODE)getNodeColor->Node; + if (PhCsUseColorSystemThreadStack && (ULONG_PTR)node->StackFrame.PcAddress > PhSystemBasicInformation.MaximumUserModeAddress) + { + getNodeColor->BackColor = PhCsColorSystemThreadStack; + } + else if (PhCsUseColorUserThreadStack && (ULONG_PTR)node->StackFrame.PcAddress <= PhSystemBasicInformation.MaximumUserModeAddress) + { + getNodeColor->BackColor = PhCsColorUserThreadStack; + } + getNodeColor->Flags = TN_CACHE | TN_AUTO_FORECOLOR; } return TRUE; @@ -638,7 +648,8 @@ VOID InitializeThreadStackTree( PhAddTreeNewColumn(Context->TreeNewHandle, PH_STACK_TREE_COLUMN_CONTROLADDRESS, FALSE, L"Control address", 100, PH_ALIGN_LEFT, -1, 0); PhAddTreeNewColumn(Context->TreeNewHandle, PH_STACK_TREE_COLUMN_RETURNADDRESS, FALSE, L"Return address", 100, PH_ALIGN_LEFT, -1, 0); - TreeNew_SetTriState(Context->TreeNewHandle, TRUE); + TreeNew_SetTriState(Context->TreeNewHandle, FALSE); + TreeNew_SetSort(Context->TreeNewHandle, PH_STACK_TREE_COLUMN_INDEX, AscendingSortOrder); ThreadStackLoadSettingsTreeList(Context); } @@ -966,8 +977,10 @@ static NTSTATUS PhpRefreshThreadStack( if (!PhIsNullOrEmptyString(item->Symbol)) stackNode->SymbolString = PhReferenceObject(item->Symbol); - PhPrintPointer(stackNode->StackAddressString, item->StackFrame.StackAddress); - PhPrintPointer(stackNode->FrameAddressString, item->StackFrame.FrameAddress); + if (item->StackFrame.StackAddress) + PhPrintPointer(stackNode->StackAddressString, item->StackFrame.StackAddress); + if (item->StackFrame.FrameAddress) + PhPrintPointer(stackNode->FrameAddressString, item->StackFrame.FrameAddress); // There are no params for kernel-mode stack traces. if ((ULONG_PTR)item->StackFrame.PcAddress <= PhSystemBasicInformation.MaximumUserModeAddress) @@ -978,8 +991,10 @@ static NTSTATUS PhpRefreshThreadStack( PhPrintPointer(stackNode->Parameter4String, item->StackFrame.Params[3]); } - PhPrintPointer(stackNode->PcAddressString, item->StackFrame.PcAddress); - PhPrintPointer(stackNode->ReturnAddressString, item->StackFrame.ReturnAddress); + if (item->StackFrame.PcAddress) + PhPrintPointer(stackNode->PcAddressString, item->StackFrame.PcAddress); + if (item->StackFrame.ReturnAddress) + PhPrintPointer(stackNode->ReturnAddressString, item->StackFrame.ReturnAddress); UpdateThreadStackNode(Context, stackNode); } From 1c2a3cc664b327abbe3ef5192dd4ba03b6f0b374 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 9 Jun 2018 12:38:01 +1000 Subject: [PATCH 1026/2058] Fix servive properties propsheet flags --- ProcessHacker/srvprp.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/ProcessHacker/srvprp.c b/ProcessHacker/srvprp.c index 302d6f447d83..8ff2bb4756ea 100644 --- a/ProcessHacker/srvprp.c +++ b/ProcessHacker/srvprp.c @@ -108,12 +108,15 @@ VOID PhShowServiceProperties( SERVICE_PROPERTIES_CONTEXT context; propSheetHeader.dwFlags = + PSH_MODELESS | PSH_NOAPPLYNOW | PSH_NOCONTEXTHELP | - PSH_PROPTITLE; + PSH_PROPTITLE | + //PSH_USECALLBACK | + PSH_USEHICON; propSheetHeader.hInstance = PhInstanceHandle; propSheetHeader.hwndParent = ParentWindowHandle; - propSheetHeader.pszCaption = ServiceItem->Name->Buffer; + propSheetHeader.pszCaption = PhGetString(ServiceItem->Name); propSheetHeader.nPages = 0; propSheetHeader.nStartPage = 0; propSheetHeader.phpage = pages; From 3a601215d3964df52b111cc545af2bfc15dd00da Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 9 Jun 2018 12:47:18 +1000 Subject: [PATCH 1027/2058] Move static reference --- phlib/appresolver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phlib/appresolver.c b/phlib/appresolver.c index 5ca81481bb01..0591fec3dbc9 100644 --- a/phlib/appresolver.c +++ b/phlib/appresolver.c @@ -320,6 +320,7 @@ PPH_STRING PhGetProcessPackageFullName( _In_ HANDLE ProcessHandle ) { + static UNICODE_STRING attributeNameUs = RTL_CONSTANT_STRING(L"WIN://SYSAPPID"); HANDLE tokenHandle; PTOKEN_SECURITY_ATTRIBUTES_INFORMATION info; PPH_STRING packageName = NULL; @@ -335,7 +336,6 @@ PPH_STRING PhGetProcessPackageFullName( { for (ULONG i = 0; i < info->AttributeCount; i++) { - static UNICODE_STRING attributeNameUs = RTL_CONSTANT_STRING(L"WIN://SYSAPPID"); PTOKEN_SECURITY_ATTRIBUTE_V1 attribute = &info->Attribute.pAttributeV1[i]; if (RtlEqualUnicodeString(&attribute->Name, &attributeNameUs, FALSE)) From 076fe5e6fcb919b12cf8ca43be0d3ffa4f725855 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 10 Jun 2018 16:29:22 +1000 Subject: [PATCH 1028/2058] Add PhEnumerateKey function --- phlib/include/phnative.h | 14 ++++++++++ phlib/native.c | 60 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+) diff --git a/phlib/include/phnative.h b/phlib/include/phnative.h index a68e096b0017..cd0563475e0e 100644 --- a/phlib/include/phnative.h +++ b/phlib/include/phnative.h @@ -1001,6 +1001,20 @@ PhQueryValueKey( _Out_ PVOID *Buffer ); +typedef BOOLEAN (NTAPI *PPH_ENUM_KEY_CALLBACK)( + _In_ PKEY_BASIC_INFORMATION Information, + _In_opt_ PVOID Context + ); + +PHLIBAPI +NTSTATUS +NTAPI +PhEnumerateKey( + _In_ HANDLE KeyHandle, + _In_ PPH_ENUM_KEY_CALLBACK Callback, + _In_opt_ PVOID Context + ); + PHLIBAPI NTSTATUS NTAPI diff --git a/phlib/native.c b/phlib/native.c index db47ecb41a7e..21acef2adedc 100644 --- a/phlib/native.c +++ b/phlib/native.c @@ -6320,6 +6320,66 @@ NTSTATUS PhQueryValueKey( return status; } +NTSTATUS PhEnumerateKey( + _In_ HANDLE KeyHandle, + _In_ PPH_ENUM_KEY_CALLBACK Callback, + _In_opt_ PVOID Context + ) +{ + NTSTATUS status; + PVOID buffer; + ULONG bufferSize; + ULONG index = 0; + + bufferSize = 0x100; + buffer = PhAllocate(bufferSize); + + while (TRUE) + { + status = NtEnumerateKey( + KeyHandle, + index, + KeyBasicInformation, + buffer, + bufferSize, + &bufferSize + ); + + if (status == STATUS_NO_MORE_ENTRIES) + { + status = STATUS_SUCCESS; + break; + } + + if (status == STATUS_BUFFER_OVERFLOW || status == STATUS_BUFFER_TOO_SMALL) + { + PhFree(buffer); + buffer = PhAllocate(bufferSize); + + status = NtEnumerateKey( + KeyHandle, + index, + KeyBasicInformation, + buffer, + bufferSize, + &bufferSize + ); + } + + if (!NT_SUCCESS(status)) + break; + + if (!Callback(buffer, Context)) + break; + + index++; + } + + PhFree(buffer); + + return status; +} + /** * Creates or opens a file. * From b66304e5110d3ad47a26ea1358aa1b9d635e6463 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 13 Jun 2018 12:32:25 +1000 Subject: [PATCH 1029/2058] Fix treeview regression during theme changes --- phlib/treenew.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/phlib/treenew.c b/phlib/treenew.c index 528e5aaf2f0c..204c717ad202 100644 --- a/phlib/treenew.c +++ b/phlib/treenew.c @@ -2104,6 +2104,8 @@ VOID PhTnpUpdateThemeData( _In_ PPH_TREENEW_CONTEXT Context ) { + Context->DefaultBackColor = GetSysColor(COLOR_WINDOW); + Context->DefaultForeColor = GetSysColor(COLOR_WINDOWTEXT); Context->ThemeActive = !!IsThemeActive(); if (Context->ThemeData) From 0734257e9c7e7e612eb2475ba7432c3ab9fe200e Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 14 Jun 2018 08:33:26 +1000 Subject: [PATCH 1030/2058] ExtendedTools: Add workaround for BSOD on LTSB versions of Win10 --- plugins/ExtendedTools/gpumon.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/ExtendedTools/gpumon.c b/plugins/ExtendedTools/gpumon.c index e157cf840b8d..be5630bd4756 100644 --- a/plugins/ExtendedTools/gpumon.c +++ b/plugins/ExtendedTools/gpumon.c @@ -535,7 +535,7 @@ PETP_GPU_ADAPTER EtpAddDisplayAdapter( } } - if (WindowsVersion >= WINDOWS_10) + if (WindowsVersion >= WINDOWS_10_RS4) // Note: Changed to RS4 due to reports of BSODs on LTSB versions of RS3 { adapter->NodeNameList = PhCreateList(adapter->NodeCount); @@ -618,7 +618,7 @@ BOOLEAN EtpInitializeD3DStatistics( if (!NT_SUCCESS(D3DKMTOpenAdapterFromDeviceName(&openAdapterFromDeviceName))) continue; - if (WindowsVersion >= WINDOWS_8 && deviceAdapterList->Count > 1) + if (WindowsVersion >= WINDOWS_10_RS4 && deviceAdapterList->Count > 1) // Note: Changed to RS4 due to reports of BSODs on LTSB versions of RS3 { if (EtpIsGpuSoftwareDevice(openAdapterFromDeviceName.AdapterHandle)) { @@ -627,7 +627,7 @@ BOOLEAN EtpInitializeD3DStatistics( } } - if (WindowsVersion >= WINDOWS_10_RS3) + if (WindowsVersion >= WINDOWS_10_RS4) // Note: Changed to RS4 due to reports of BSODs on LTSB versions of RS3 { D3DKMT_SEGMENTSIZEINFO segmentInfo; @@ -689,7 +689,7 @@ BOOLEAN EtpInitializeD3DStatistics( aperture = queryStatistics.QueryResult.SegmentInformationV1.Aperture; } - if (WindowsVersion < WINDOWS_10_RS3) + if (WindowsVersion < WINDOWS_10_RS4) // Note: Changed to RS4 due to reports of BSODs on LTSB versions of RS3 { if (aperture) EtGpuSharedLimit += commitLimit; From f5b004b762cd9a85f5a5210cb5b68bbcbecbd303 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 14 Jun 2018 12:16:42 +1000 Subject: [PATCH 1031/2058] Fix uninitialized variable --- ProcessHacker/proctree.c | 1 + 1 file changed, 1 insertion(+) diff --git a/ProcessHacker/proctree.c b/ProcessHacker/proctree.c index a9f5e39f6bdf..b0e6733c9437 100644 --- a/ProcessHacker/proctree.c +++ b/ProcessHacker/proctree.c @@ -2861,6 +2861,7 @@ BOOLEAN NTAPI PhpProcessTreeNewCallback( getHighlightingColor.Parameter = processItem; getHighlightingColor.BackColor = RGB(0xff, 0xff, 0xff); + getHighlightingColor.ForeColor = RGB(0x00, 0x00, 0x00); getHighlightingColor.Handled = FALSE; getHighlightingColor.Cache = FALSE; From 5ad4acd71e6ed53885c00c6e305f3665018101e9 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 14 Jun 2018 16:17:53 +1000 Subject: [PATCH 1032/2058] Fix SAL annotations --- phnt/include/ntmmapi.h | 2 +- phnt/include/ntobapi.h | 2 +- phnt/include/ntrtl.h | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/phnt/include/ntmmapi.h b/phnt/include/ntmmapi.h index 93b23a555dd6..cb633b0679b6 100644 --- a/phnt/include/ntmmapi.h +++ b/phnt/include/ntmmapi.h @@ -489,7 +489,7 @@ NTSTATUS NTAPI NtQueryVirtualMemory( _In_ HANDLE ProcessHandle, - _In_ PVOID BaseAddress, + _In_opt_ PVOID BaseAddress, _In_ MEMORY_INFORMATION_CLASS MemoryInformationClass, _Out_writes_bytes_(MemoryInformationLength) PVOID MemoryInformation, _In_ SIZE_T MemoryInformationLength, diff --git a/phnt/include/ntobapi.h b/phnt/include/ntobapi.h index cf5cdd016314..e6255ca17145 100644 --- a/phnt/include/ntobapi.h +++ b/phnt/include/ntobapi.h @@ -112,7 +112,7 @@ NTSYSCALLAPI NTSTATUS NTAPI NtQueryObject( - _In_ HANDLE Handle, + _In_opt_ HANDLE Handle, _In_ OBJECT_INFORMATION_CLASS ObjectInformationClass, _Out_writes_bytes_opt_(ObjectInformationLength) PVOID ObjectInformation, _In_ ULONG ObjectInformationLength, diff --git a/phnt/include/ntrtl.h b/phnt/include/ntrtl.h index 1b79bf11b37d..e16a1863a000 100644 --- a/phnt/include/ntrtl.h +++ b/phnt/include/ntrtl.h @@ -6370,9 +6370,9 @@ NTAPI RtlQueueApcWow64Thread( _In_ HANDLE ThreadHandle, _In_ PPS_APC_ROUTINE ApcRoutine, - _In_ PVOID ApcArgument1, - _In_ PVOID ApcArgument2, - _In_ PVOID ApcArgument3 + _In_opt_ PVOID ApcArgument1, + _In_opt_ PVOID ApcArgument2, + _In_opt_ PVOID ApcArgument3 ); NTSYSAPI From cac2533ab4d5cd4b78840b0f264d25cbbd7bf46f Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 14 Jun 2018 16:48:32 +1000 Subject: [PATCH 1033/2058] Add modules tab ParentBaseAddress column --- ProcessHacker/include/modlist.h | 4 +++- ProcessHacker/include/modprv.h | 2 ++ ProcessHacker/modlist.c | 24 +++++++++++++++++++++++- ProcessHacker/modprv.c | 1 + phlib/include/phnative.h | 1 + phlib/native.c | 17 +++++++++++------ 6 files changed, 41 insertions(+), 8 deletions(-) diff --git a/ProcessHacker/include/modlist.h b/ProcessHacker/include/modlist.h index 1faef45ef001..f9f0fb237de6 100644 --- a/ProcessHacker/include/modlist.h +++ b/ProcessHacker/include/modlist.h @@ -27,8 +27,9 @@ #define PHMOTLC_FILEMODIFIEDTIME 16 #define PHMOTLC_FILESIZE 17 #define PHMOTLC_ENTRYPOINT 18 +#define PHMOTLC_PARENTBASEADDRESS 19 -#define PHMOTLC_MAXIMUM 19 +#define PHMOTLC_MAXIMUM 20 // begin_phapppub typedef struct _PH_MODULE_NODE @@ -52,6 +53,7 @@ typedef struct _PH_MODULE_NODE PPH_STRING LoadTimeText; PPH_STRING FileModifiedTimeText; PPH_STRING FileSizeText; + WCHAR ParentBaseAddressString[PH_PTR_STR_LEN_1]; // begin_phapppub } PH_MODULE_NODE, *PPH_MODULE_NODE; // end_phapppub diff --git a/ProcessHacker/include/modprv.h b/ProcessHacker/include/modprv.h index 84a31c62d85d..245c030fcb56 100644 --- a/ProcessHacker/include/modprv.h +++ b/ProcessHacker/include/modprv.h @@ -35,6 +35,8 @@ typedef struct _PH_MODULE_ITEM LARGE_INTEGER FileLastWriteTime; LARGE_INTEGER FileEndOfFile; + + PVOID ParentBaseAddress; } PH_MODULE_ITEM, *PPH_MODULE_ITEM; typedef struct _PH_MODULE_PROVIDER diff --git a/ProcessHacker/modlist.c b/ProcessHacker/modlist.c index c5096e12c5ea..3954c2c3c128 100644 --- a/ProcessHacker/modlist.c +++ b/ProcessHacker/modlist.c @@ -115,6 +115,7 @@ VOID PhInitializeModuleList( PhAddTreeNewColumnEx(hwnd, PHMOTLC_FILEMODIFIEDTIME, FALSE, L"File modified time", 140, PH_ALIGN_LEFT, -1, 0, TRUE); PhAddTreeNewColumnEx(hwnd, PHMOTLC_FILESIZE, FALSE, L"File size", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); PhAddTreeNewColumnEx(hwnd, PHMOTLC_ENTRYPOINT, FALSE, L"Entry point", 70, PH_ALIGN_LEFT, -1, 0, TRUE); + PhAddTreeNewColumnEx(hwnd, PHMOTLC_PARENTBASEADDRESS, FALSE, L"Parent base address", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); TreeNew_SetRedraw(hwnd, TRUE); @@ -574,6 +575,18 @@ BEGIN_SORT_FUNCTION(FileSize) } END_SORT_FUNCTION +BEGIN_SORT_FUNCTION(EntryPoint) +{ + sortResult = uintptrcmp((ULONG_PTR)moduleItem1->EntryPoint, (ULONG_PTR)moduleItem2->EntryPoint); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(ParentBaseAddress) +{ + sortResult = uintptrcmp((ULONG_PTR)moduleItem1->ParentBaseAddress, (ULONG_PTR)moduleItem2->ParentBaseAddress); +} +END_SORT_FUNCTION + BOOLEAN NTAPI PhpModuleTreeNewCallback( _In_ HWND hwnd, _In_ PH_TREENEW_MESSAGE Message, @@ -617,7 +630,9 @@ BOOLEAN NTAPI PhpModuleTreeNewCallback( SORT_FUNCTION(LoadTime), SORT_FUNCTION(LoadReason), SORT_FUNCTION(FileModifiedTime), - SORT_FUNCTION(FileSize) + SORT_FUNCTION(FileSize), + SORT_FUNCTION(EntryPoint), + SORT_FUNCTION(ParentBaseAddress) }; int (__cdecl *sortFunction)(void *, const void *, const void *); @@ -868,6 +883,13 @@ BOOLEAN NTAPI PhpModuleTreeNewCallback( case PHMOTLC_ENTRYPOINT: PhInitializeStringRef(&getCellText->Text, moduleItem->EntryPointAddressString); break; + case PHMOTLC_PARENTBASEADDRESS: + if (moduleItem->ParentBaseAddress != 0) + { + PhPrintPointer(node->ParentBaseAddressString, moduleItem->ParentBaseAddress); + PhInitializeStringRefLongHint(&getCellText->Text, node->ParentBaseAddressString); + } + break; default: return FALSE; } diff --git a/ProcessHacker/modprv.c b/ProcessHacker/modprv.c index c2176e601269..8e420fb4490a 100644 --- a/ProcessHacker/modprv.c +++ b/ProcessHacker/modprv.c @@ -496,6 +496,7 @@ VOID PhModuleProviderUpdate( moduleItem->LoadTime = module->LoadTime; moduleItem->Name = module->Name; moduleItem->FileName = module->FileName; + moduleItem->ParentBaseAddress = module->ParentBaseAddress; PhPrintPointer(moduleItem->BaseAddressString, moduleItem->BaseAddress); diff --git a/phlib/include/phnative.h b/phlib/include/phnative.h index cd0563475e0e..a96d37e8ef98 100644 --- a/phlib/include/phnative.h +++ b/phlib/include/phnative.h @@ -896,6 +896,7 @@ typedef struct _PH_MODULE_INFO { ULONG Type; PVOID BaseAddress; + PVOID ParentBaseAddress; ULONG Size; PVOID EntryPoint; ULONG Flags; diff --git a/phlib/native.c b/phlib/native.c index 21acef2adedc..629f598282f3 100644 --- a/phlib/native.c +++ b/phlib/native.c @@ -3555,6 +3555,7 @@ BOOLEAN NTAPI PhpEnumProcessModules32Callback( nativeEntry.LoadTime = Entry->LoadTime; nativeEntry.BaseNameHashValue = Entry->BaseNameHashValue; nativeEntry.LoadReason = Entry->LoadReason; + nativeEntry.ParentDllBase = UlongToPtr(Entry->ParentDllBase); mappedFileName = NULL; @@ -5407,6 +5408,7 @@ static BOOLEAN EnumGenericProcessModulesCallback( moduleInfo.Flags = Module->Flags; moduleInfo.LoadOrderIndex = (USHORT)(context->LoadOrderIndex++); moduleInfo.LoadCount = Module->ObsoleteLoadCount; + moduleInfo.ParentBaseAddress = Module->ParentDllBase; moduleInfo.Name = PhCreateStringFromUnicodeString(&Module->BaseDllName); moduleInfo.OriginalFileName = PhCreateStringFromUnicodeString(&Module->FullDllName); @@ -5419,7 +5421,7 @@ static BOOLEAN EnumGenericProcessModulesCallback( } else { - moduleInfo.LoadReason = -1; + moduleInfo.LoadReason = USHRT_MAX; moduleInfo.LoadTime.QuadPart = 0; } @@ -5476,8 +5478,9 @@ VOID PhpRtlModulesToGenericModules( moduleInfo.OriginalFileName = fileName; moduleInfo.LoadOrderIndex = module->LoadOrderIndex; moduleInfo.LoadCount = module->LoadCount; - moduleInfo.LoadReason = -1; + moduleInfo.LoadReason = USHRT_MAX; moduleInfo.LoadTime.QuadPart = 0; + moduleInfo.ParentBaseAddress = NULL; if (module->OffsetToFileName == 0) { @@ -5546,8 +5549,9 @@ VOID PhpRtlModulesExToGenericModules( moduleInfo.FileName = PhGetFileName(fileName); // convert to DOS file name moduleInfo.LoadOrderIndex = module->BaseInfo.LoadOrderIndex; moduleInfo.LoadCount = module->BaseInfo.LoadCount; - moduleInfo.LoadReason = -1; + moduleInfo.LoadReason = USHRT_MAX; moduleInfo.LoadTime.QuadPart = 0; + moduleInfo.ParentBaseAddress = NULL; PhDereferenceObject(fileName); @@ -5584,10 +5588,11 @@ BOOLEAN PhpCallbackMappedFileOrImage( moduleInfo.FileName = PhGetFileName(FileName); moduleInfo.OriginalFileName = FileName; moduleInfo.Name = PhGetBaseName(moduleInfo.FileName); - moduleInfo.LoadOrderIndex = -1; - moduleInfo.LoadCount = -1; - moduleInfo.LoadReason = -1; + moduleInfo.LoadOrderIndex = USHRT_MAX; + moduleInfo.LoadCount = USHRT_MAX; + moduleInfo.LoadReason = USHRT_MAX; moduleInfo.LoadTime.QuadPart = 0; + moduleInfo.ParentBaseAddress = NULL; cont = Callback(&moduleInfo, Context); From dc5eacd9ef6fb1a02dd4c3cf22eec62d7cda68b8 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 14 Jun 2018 16:54:24 +1000 Subject: [PATCH 1034/2058] Enable ControlFlowGuard and SpectreMitigation (experimental) --- ProcessHacker/ProcessHacker.vcxproj | 2 ++ phlib/phlib.vcxproj | 4 ++++ tools/peview/peview.vcxproj | 4 ++++ 3 files changed, 10 insertions(+) diff --git a/ProcessHacker/ProcessHacker.vcxproj b/ProcessHacker/ProcessHacker.vcxproj index 8056a72b422a..bb6839544589 100644 --- a/ProcessHacker/ProcessHacker.vcxproj +++ b/ProcessHacker/ProcessHacker.vcxproj @@ -32,6 +32,7 @@ v141 WindowsLocalDebugger $(SolutionDir)bin\$(Configuration)$(PlatformArchitecture)\ + Spectre Application @@ -47,6 +48,7 @@ v141 WindowsLocalDebugger $(SolutionDir)bin\$(Configuration)$(PlatformArchitecture)\ + Spectre Application diff --git a/phlib/phlib.vcxproj b/phlib/phlib.vcxproj index bc91f196de4c..06c3c90020e6 100644 --- a/phlib/phlib.vcxproj +++ b/phlib/phlib.vcxproj @@ -30,6 +30,7 @@ Unicode true v141 + Spectre StaticLibrary @@ -41,6 +42,7 @@ Unicode true v141 + Spectre StaticLibrary @@ -119,6 +121,7 @@ true true StreamingSIMDExtensions + Guard @@ -136,6 +139,7 @@ StdCall true true + Guard diff --git a/tools/peview/peview.vcxproj b/tools/peview/peview.vcxproj index 64ec66da2699..a8358d8ddf51 100644 --- a/tools/peview/peview.vcxproj +++ b/tools/peview/peview.vcxproj @@ -30,6 +30,7 @@ Unicode true v141 + Spectre Application @@ -41,6 +42,7 @@ Unicode true v141 + Spectre Application @@ -157,6 +159,7 @@ true true true + Guard noarg.obj;noenv.obj;phlib.lib;ntdll.lib;uxtheme.lib;windowscodecs.lib;%(AdditionalDependencies) @@ -191,6 +194,7 @@ true true true + Guard noarg.obj;noenv.obj;phlib.lib;ntdll.lib;uxtheme.lib;windowscodecs.lib;%(AdditionalDependencies) From afdf0442235af0abae42b7c1a0b919a9d44df7c8 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 14 Jun 2018 17:14:21 +1000 Subject: [PATCH 1035/2058] Fix searching modules tab parent addresses --- ProcessHacker/include/modlist.h | 1 - ProcessHacker/include/modprv.h | 1 + ProcessHacker/modlist.c | 4 ++-- ProcessHacker/prpgmod.c | 19 +++++++++++++------ 4 files changed, 16 insertions(+), 9 deletions(-) diff --git a/ProcessHacker/include/modlist.h b/ProcessHacker/include/modlist.h index f9f0fb237de6..658511c00fff 100644 --- a/ProcessHacker/include/modlist.h +++ b/ProcessHacker/include/modlist.h @@ -53,7 +53,6 @@ typedef struct _PH_MODULE_NODE PPH_STRING LoadTimeText; PPH_STRING FileModifiedTimeText; PPH_STRING FileSizeText; - WCHAR ParentBaseAddressString[PH_PTR_STR_LEN_1]; // begin_phapppub } PH_MODULE_NODE, *PPH_MODULE_NODE; // end_phapppub diff --git a/ProcessHacker/include/modprv.h b/ProcessHacker/include/modprv.h index 245c030fcb56..413cc97dd829 100644 --- a/ProcessHacker/include/modprv.h +++ b/ProcessHacker/include/modprv.h @@ -37,6 +37,7 @@ typedef struct _PH_MODULE_ITEM LARGE_INTEGER FileEndOfFile; PVOID ParentBaseAddress; + WCHAR ParentBaseAddressString[PH_PTR_STR_LEN_1]; } PH_MODULE_ITEM, *PPH_MODULE_ITEM; typedef struct _PH_MODULE_PROVIDER diff --git a/ProcessHacker/modlist.c b/ProcessHacker/modlist.c index 3954c2c3c128..e9902507bb84 100644 --- a/ProcessHacker/modlist.c +++ b/ProcessHacker/modlist.c @@ -886,8 +886,8 @@ BOOLEAN NTAPI PhpModuleTreeNewCallback( case PHMOTLC_PARENTBASEADDRESS: if (moduleItem->ParentBaseAddress != 0) { - PhPrintPointer(node->ParentBaseAddressString, moduleItem->ParentBaseAddress); - PhInitializeStringRefLongHint(&getCellText->Text, node->ParentBaseAddressString); + PhPrintPointer(moduleItem->ParentBaseAddressString, moduleItem->ParentBaseAddress); + PhInitializeStringRefLongHint(&getCellText->Text, moduleItem->ParentBaseAddressString); } break; default: diff --git a/ProcessHacker/prpgmod.c b/ProcessHacker/prpgmod.c index 0ae3be63b3c2..d64629e4d8c2 100644 --- a/ProcessHacker/prpgmod.c +++ b/ProcessHacker/prpgmod.c @@ -260,16 +260,11 @@ BOOLEAN PhpModulesTreeFilterCallback( if (PhIsNullOrEmptyString(Context->SearchboxText)) return TRUE; - //PVOID BaseAddress; - //ULONG Size; + // (dmex) TODO: Add search support for the following fields: //ULONG Flags; //ULONG Type; - //ULONG ImageTimeDateStamp; //USHORT ImageCharacteristics; //USHORT ImageDllCharacteristics; - //LARGE_INTEGER LoadTime; - //LARGE_INTEGER FileLastWriteTime; - //LARGE_INTEGER FileEndOfFile; // module properties @@ -321,6 +316,18 @@ BOOLEAN PhpModulesTreeFilterCallback( return TRUE; } + if (moduleItem->EntryPointAddressString[0]) + { + if (PhpWordMatchHandleStringZ(Context->SearchboxText, moduleItem->EntryPointAddressString)) + return TRUE; + } + + if (moduleItem->ParentBaseAddressString[0]) + { + if (PhpWordMatchHandleStringZ(Context->SearchboxText, moduleItem->ParentBaseAddressString)) + return TRUE; + } + switch (moduleItem->LoadReason) { case LoadReasonStaticDependency: From 73508bc31c14ab28a2c1e842079f7b5caf428ce9 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 14 Jun 2018 20:15:12 +1000 Subject: [PATCH 1036/2058] Fix SAL warnings --- ProcessHacker/runas.c | 2 +- phlib/guisup.c | 2 +- phlib/include/phutil.h | 2 +- phlib/util.c | 5 ++--- 4 files changed, 5 insertions(+), 6 deletions(-) diff --git a/ProcessHacker/runas.c b/ProcessHacker/runas.c index d0bf0d005626..128be1be13c8 100644 --- a/ProcessHacker/runas.c +++ b/ProcessHacker/runas.c @@ -305,7 +305,7 @@ BOOLEAN PhpInitializeMRUList(VOID) FreeMRUList_I = PhGetDllBaseProcedureAddress(comctl32ModuleHandle, "FreeMRUList", 0); } - if (!CreateMRUList_I && !AddMRUString_I && !EnumMRUList_I && !FreeMRUList_I) + if (!CreateMRUList_I && !AddMRUString_I && !EnumMRUList_I && !FreeMRUList_I && comctl32ModuleHandle) { FreeLibrary(comctl32ModuleHandle); comctl32ModuleHandle = NULL; diff --git a/phlib/guisup.c b/phlib/guisup.c index 89cc7bbe54cc..40d4a2e0b49c 100644 --- a/phlib/guisup.c +++ b/phlib/guisup.c @@ -466,7 +466,7 @@ PPH_STRING PhGetListBoxString( { Index = ListBox_GetCurSel(hwnd); - if (Index == -1) + if (Index == LB_ERR) return NULL; } diff --git a/phlib/include/phutil.h b/phlib/include/phutil.h index 6bddc0d3d6ac..b453303e5800 100644 --- a/phlib/include/phutil.h +++ b/phlib/include/phutil.h @@ -1185,7 +1185,7 @@ PHLIBAPI PVOID NTAPI PhGetLoaderEntryDllBase( - _In_opt_ PWSTR DllName + _In_ PWSTR DllName ); PHLIBAPI diff --git a/phlib/util.c b/phlib/util.c index e743ea1ffa84..ec23b662bcb7 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -2027,7 +2027,6 @@ VOID PhGetSystemRoot( ) { static PH_STRINGREF systemRoot; - PH_STRINGREF localSystemRoot; SIZE_T count; @@ -3201,7 +3200,7 @@ BOOLEAN PhShellExecuteEx( if (ProcessHandle) *ProcessHandle = info.hProcess; - else + else if (info.hProcess) NtClose(info.hProcess); return TRUE; @@ -5387,7 +5386,7 @@ PPH_STRING PhGetDllFileName( } PVOID PhGetLoaderEntryDllBase( - _In_opt_ PWSTR BaseDllName + _In_ PWSTR BaseDllName ) { PH_STRINGREF entryNameSr; From 7f8b43aacdcbba2d54639976af050665bb33194d Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 14 Jun 2018 20:21:18 +1000 Subject: [PATCH 1037/2058] Use PhGetSystemRoot instead of NtSystemRoot --- ProcessHacker/mtgndlg.c | 9 ++++----- phlib/basesup.c | 12 ++++++++++-- phlib/include/phbasesup.h | 14 ++++++++++++++ phlib/native.c | 24 ++++++++++++++++++------ 4 files changed, 46 insertions(+), 13 deletions(-) diff --git a/ProcessHacker/mtgndlg.c b/ProcessHacker/mtgndlg.c index ec27742c7a2a..cadc9916b29c 100644 --- a/ProcessHacker/mtgndlg.c +++ b/ProcessHacker/mtgndlg.c @@ -3,7 +3,7 @@ * process mitigation policy details * * Copyright (C) 2016 wj32 - * Copyright (C) 2016-2017 dmex + * Copyright (C) 2016-2018 dmex * * This file is part of Process Hacker. * @@ -52,14 +52,13 @@ NTSTATUS PhpGetProcessSystemDllInitBlock( ) { NTSTATUS status; - PPS_SYSTEM_DLL_INIT_BLOCK ldrInitBlock = NULL; + PH_STRINGREF systemRoot; PVOID ldrInitBlockBaseAddress = NULL; PPH_STRING ntdllFileName; - ldrInitBlock = PhAllocate(sizeof(PS_SYSTEM_DLL_INIT_BLOCK)); - memset(ldrInitBlock, 0, sizeof(PS_SYSTEM_DLL_INIT_BLOCK)); + PhGetSystemRoot(&systemRoot); + ntdllFileName = PhConcatStringRefZ(&systemRoot, L"\\System32\\ntdll.dll"); - ntdllFileName = PhConcatStrings2(USER_SHARED_DATA->NtSystemRoot, L"\\System32\\ntdll.dll"); status = PhGetProcedureAddressRemote( ProcessHandle, ntdllFileName->Buffer, diff --git a/phlib/basesup.c b/phlib/basesup.c index 6a8a38012d7b..2c71d0a0a958 100644 --- a/phlib/basesup.c +++ b/phlib/basesup.c @@ -2368,8 +2368,16 @@ PPH_STRING PhConcatStringRef2( assert(!(String2->Length & 1)); string = PhCreateStringEx(NULL, String1->Length + String2->Length); - memcpy(string->Buffer, String1->Buffer, String1->Length); - memcpy(PTR_ADD_OFFSET(string->Buffer, String1->Length), String2->Buffer, String2->Length); + memcpy( + string->Buffer, + String1->Buffer, + String1->Length + ); + memcpy( + PTR_ADD_OFFSET(string->Buffer, String1->Length), + String2->Buffer, + String2->Length + ); return string; } diff --git a/phlib/include/phbasesup.h b/phlib/include/phbasesup.h index 55846d5ce5d5..196ceeb930b9 100644 --- a/phlib/include/phbasesup.h +++ b/phlib/include/phbasesup.h @@ -1241,6 +1241,20 @@ PhConcatStringRef3( _In_ PPH_STRINGREF String3 ); +FORCEINLINE +PPH_STRING +PhConcatStringRefZ( + _In_ PPH_STRINGREF String1, + _In_ PWSTR String2 + ) +{ + PH_STRINGREF string; + + PhInitializeStringRef(&string, String2); + + return PhConcatStringRef2(String1, &string); +} + PHLIBAPI PPH_STRING NTAPI diff --git a/phlib/native.c b/phlib/native.c index 629f598282f3..10f57c3b8d37 100644 --- a/phlib/native.c +++ b/phlib/native.c @@ -1393,9 +1393,12 @@ NTSTATUS PhLoadDllProcess( if (!threadStart) { + PH_STRINGREF systemRoot; PPH_STRING kernel32FileName; - kernel32FileName = PhConcatStrings2(USER_SHARED_DATA->NtSystemRoot, L"\\SysWow64\\kernel32.dll"); + PhGetSystemRoot(&systemRoot); + kernel32FileName = PhConcatStringRefZ(&systemRoot, L"\\SysWow64\\kernel32.dll"); + status = PhGetProcedureAddressRemote( ProcessHandle, kernel32FileName->Buffer, @@ -1541,9 +1544,12 @@ NTSTATUS PhUnloadDllProcess( if (!threadStart) { + PH_STRINGREF systemRoot; PPH_STRING ntdll32FileName; - ntdll32FileName = PhConcatStrings2(USER_SHARED_DATA->NtSystemRoot, L"\\SysWow64\\ntdll.dll"); + PhGetSystemRoot(&systemRoot); + ntdll32FileName = PhConcatStringRefZ(&systemRoot, L"\\SysWow64\\ntdll.dll"); + status = PhGetProcedureAddressRemote( ProcessHandle, ntdll32FileName->Buffer, @@ -1637,14 +1643,20 @@ NTSTATUS PhSetEnvironmentVariableRemote( if (isWow64) { - ntdllFileName = PhConcatStrings2(USER_SHARED_DATA->NtSystemRoot, L"\\SysWow64\\ntdll.dll"); - kernel32FileName = PhConcatStrings2(USER_SHARED_DATA->NtSystemRoot, L"\\SysWow64\\kernel32.dll"); + PH_STRINGREF systemRoot; + + PhGetSystemRoot(&systemRoot); + ntdllFileName = PhConcatStringRefZ(&systemRoot, L"\\SysWow64\\ntdll.dll"); + kernel32FileName = PhConcatStringRefZ(&systemRoot, L"\\SysWow64\\kernel32.dll"); } else { #endif - ntdllFileName = PhConcatStrings2(USER_SHARED_DATA->NtSystemRoot, L"\\System32\\ntdll.dll"); - kernel32FileName = PhConcatStrings2(USER_SHARED_DATA->NtSystemRoot, L"\\System32\\kernel32.dll"); + PH_STRINGREF systemRoot; + + PhGetSystemRoot(&systemRoot); + ntdllFileName = PhConcatStringRefZ(&systemRoot, L"\\System32\\ntdll.dll"); + kernel32FileName = PhConcatStringRefZ(&systemRoot, L"\\System32\\kernel32.dll"); #ifdef _WIN64 } #endif From e3e58bfbd3ed3a7bf8f7cb87ec01954981b2ebf8 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 14 Jun 2018 20:23:09 +1000 Subject: [PATCH 1038/2058] Move PhLookupPolicyHandle --- phlib/lsasup.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/phlib/lsasup.c b/phlib/lsasup.c index c60102ae79f0..3b329e1ba6d6 100644 --- a/phlib/lsasup.c +++ b/phlib/lsasup.c @@ -30,8 +30,6 @@ #include #include -static LSA_HANDLE PhLookupPolicyHandle = NULL; - NTSTATUS PhOpenLsaPolicy( _Out_ PLSA_HANDLE PolicyHandle, _In_ ACCESS_MASK DesiredAccess, @@ -59,10 +57,13 @@ LSA_HANDLE PhGetLookupPolicyHandle( VOID ) { + static LSA_HANDLE cachedLookupPolicyHandle = NULL; LSA_HANDLE lookupPolicyHandle; LSA_HANDLE newLookupPolicyHandle; - lookupPolicyHandle = PhLookupPolicyHandle; + // Use the cached value if possible. + + lookupPolicyHandle = cachedLookupPolicyHandle; // If there is no cached handle, open one. @@ -78,7 +79,7 @@ LSA_HANDLE PhGetLookupPolicyHandle( // before, we will now store it. lookupPolicyHandle = _InterlockedCompareExchangePointer( - &PhLookupPolicyHandle, + &cachedLookupPolicyHandle, newLookupPolicyHandle, NULL ); From 5bd886cd772a1d7be2d46d485a0032c7bb67f6d9 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 14 Jun 2018 20:24:44 +1000 Subject: [PATCH 1039/2058] Use INET6_ADDRSTRLEN definition --- ProcessHacker/include/netprv.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ProcessHacker/include/netprv.h b/ProcessHacker/include/netprv.h index 06398f6d988e..a314f07430b2 100644 --- a/ProcessHacker/include/netprv.h +++ b/ProcessHacker/include/netprv.h @@ -27,9 +27,9 @@ typedef struct _PH_NETWORK_ITEM ULONG JustResolved; - WCHAR LocalAddressString[65]; + WCHAR LocalAddressString[INET6_ADDRSTRLEN]; WCHAR LocalPortString[PH_INT32_STR_LEN_1]; - WCHAR RemoteAddressString[65]; + WCHAR RemoteAddressString[INET6_ADDRSTRLEN]; WCHAR RemotePortString[PH_INT32_STR_LEN_1]; PPH_STRING LocalHostString; PPH_STRING RemoteHostString; From 0a20ea2af2ac0eb5d6f877601bd02eefe1d39e3a Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 14 Jun 2018 20:26:04 +1000 Subject: [PATCH 1040/2058] Add modules tab LoadReason for enclaves --- ProcessHacker/modlist.c | 12 +++++++++++- ProcessHacker/modprv.c | 3 --- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/ProcessHacker/modlist.c b/ProcessHacker/modlist.c index e9902507bb84..3914cfe554e8 100644 --- a/ProcessHacker/modlist.c +++ b/ProcessHacker/modlist.c @@ -851,6 +851,12 @@ BOOLEAN NTAPI PhpModuleTreeNewCallback( case LoadReasonAsDataLoad: string = L"As data"; break; + case LoadReasonEnclavePrimary: + string = L"Enclave"; + break; + case LoadReasonEnclaveDependency: + string = L"Enclave dependency"; + break; default: if (WindowsVersion >= WINDOWS_8) string = L"Unknown"; @@ -881,7 +887,11 @@ BOOLEAN NTAPI PhpModuleTreeNewCallback( } break; case PHMOTLC_ENTRYPOINT: - PhInitializeStringRef(&getCellText->Text, moduleItem->EntryPointAddressString); + if (moduleItem->EntryPoint != 0) + { + PhPrintPointer(moduleItem->EntryPointAddressString, moduleItem->EntryPoint); + PhInitializeStringRef(&getCellText->Text, moduleItem->EntryPointAddressString); + } break; case PHMOTLC_PARENTBASEADDRESS: if (moduleItem->ParentBaseAddress != 0) diff --git a/ProcessHacker/modprv.c b/ProcessHacker/modprv.c index 8e420fb4490a..1aee24561daa 100644 --- a/ProcessHacker/modprv.c +++ b/ProcessHacker/modprv.c @@ -578,9 +578,6 @@ VOID PhModuleProviderUpdate( } } - if (moduleItem->EntryPoint) - PhPrintPointer(moduleItem->EntryPointAddressString, moduleItem->EntryPoint); - // remove CF Guard flag if CFG mitigation is not enabled for the process if (!moduleProvider->ControlFlowGuardEnabled) moduleItem->ImageDllCharacteristics &= ~IMAGE_DLLCHARACTERISTICS_GUARD_CF; From 07054f30a7a42a63055f7fae0de6027aee438b3b Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 14 Jun 2018 20:27:03 +1000 Subject: [PATCH 1041/2058] Add INDIRECT_BRANCH_PREDICTION to process mitigation dialog --- ProcessHacker/mtgndlg.c | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/ProcessHacker/mtgndlg.c b/ProcessHacker/mtgndlg.c index cadc9916b29c..c15d0c4f32bf 100644 --- a/ProcessHacker/mtgndlg.c +++ b/ProcessHacker/mtgndlg.c @@ -72,6 +72,11 @@ NTSTATUS PhpGetProcessSystemDllInitBlock( if (NT_SUCCESS(status) && ldrInitBlockBaseAddress) { + PPS_SYSTEM_DLL_INIT_BLOCK ldrInitBlock; + + ldrInitBlock = PhAllocate(sizeof(PS_SYSTEM_DLL_INIT_BLOCK)); + memset(ldrInitBlock, 0, sizeof(PS_SYSTEM_DLL_INIT_BLOCK)); + status = NtReadVirtualMemory( ProcessHandle, ldrInitBlockBaseAddress, @@ -79,11 +84,11 @@ NTSTATUS PhpGetProcessSystemDllInitBlock( sizeof(PS_SYSTEM_DLL_INIT_BLOCK), NULL ); - } - if (NT_SUCCESS(status)) - { - *SystemDllInitBlock = ldrInitBlock; + if (NT_SUCCESS(status)) + *SystemDllInitBlock = ldrInitBlock; + else + PhFree(ldrInitBlock); } return status; @@ -245,6 +250,18 @@ INT_PTR CALLBACK PhpProcessMitigationPolicyDlgProc( PhAddListViewItem(lvHandle, MAXINT, entry->ShortDescription->Buffer, entry); } + + if (context->SystemDllInitBlock->MitigationOptionsMap.Map[1] & PROCESS_CREATION_MITIGATION_POLICY2_RESTRICT_INDIRECT_BRANCH_PREDICTION_ALWAYS_ON) + { + PMITIGATION_POLICY_ENTRY entry; + + entry = PhAllocate(sizeof(MITIGATION_POLICY_ENTRY)); + entry->NonStandard = TRUE; + entry->ShortDescription = PhCreateString(L"Indirect branch prediction"); + entry->LongDescription = PhCreateString(L"Protects against sibling hardware threads (hyperthreads) from interfering with indirect branch predictions."); + + PhAddListViewItem(lvHandle, MAXINT, entry->ShortDescription->Buffer, entry); + } } ExtendedListView_SortItems(lvHandle); From 6495557f7fe970d8ab6d9f33e91d12c4290188a8 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 14 Jun 2018 21:51:05 +1000 Subject: [PATCH 1042/2058] Fix #276 --- ProcessHacker/mtgndlg.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/ProcessHacker/mtgndlg.c b/ProcessHacker/mtgndlg.c index c15d0c4f32bf..a161a58d6ab5 100644 --- a/ProcessHacker/mtgndlg.c +++ b/ProcessHacker/mtgndlg.c @@ -251,17 +251,18 @@ INT_PTR CALLBACK PhpProcessMitigationPolicyDlgProc( PhAddListViewItem(lvHandle, MAXINT, entry->ShortDescription->Buffer, entry); } - if (context->SystemDllInitBlock->MitigationOptionsMap.Map[1] & PROCESS_CREATION_MITIGATION_POLICY2_RESTRICT_INDIRECT_BRANCH_PREDICTION_ALWAYS_ON) - { - PMITIGATION_POLICY_ENTRY entry; - - entry = PhAllocate(sizeof(MITIGATION_POLICY_ENTRY)); - entry->NonStandard = TRUE; - entry->ShortDescription = PhCreateString(L"Indirect branch prediction"); - entry->LongDescription = PhCreateString(L"Protects against sibling hardware threads (hyperthreads) from interfering with indirect branch predictions."); - - PhAddListViewItem(lvHandle, MAXINT, entry->ShortDescription->Buffer, entry); - } + // Note: This value doesn't appear to be available via the MitigationOptionsMap. + //if (context->SystemDllInitBlock->MitigationOptionsMap.Map[1] & PROCESS_CREATION_MITIGATION_POLICY2_RESTRICT_INDIRECT_BRANCH_PREDICTION_ALWAYS_ON) + //{ + // PMITIGATION_POLICY_ENTRY entry; + // + // entry = PhAllocate(sizeof(MITIGATION_POLICY_ENTRY)); + // entry->NonStandard = TRUE; + // entry->ShortDescription = PhCreateString(L"Indirect branch prediction"); + // entry->LongDescription = PhCreateString(L"Protects against sibling hardware threads (hyperthreads) from interfering with indirect branch predictions."); + // + // PhAddListViewItem(lvHandle, MAXINT, entry->ShortDescription->Buffer, entry); + //} } ExtendedListView_SortItems(lvHandle); From aeea09d30d489fe85d1ff8bb1415383a24b4bcb4 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 15 Jun 2018 18:42:12 +1000 Subject: [PATCH 1043/2058] ExtendedTools: Add gpu VendorID to details window --- plugins/ExtendedTools/gpudetails.c | 24 +++++++++++++++++------- plugins/ExtendedTools/gpumon.c | 6 +++--- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/plugins/ExtendedTools/gpudetails.c b/plugins/ExtendedTools/gpudetails.c index 09c88b5dd140..f9c25c2b5aa6 100644 --- a/plugins/ExtendedTools/gpudetails.c +++ b/plugins/ExtendedTools/gpudetails.c @@ -33,6 +33,8 @@ typedef enum _GPUADAPTER_DETAILS_INDEX GPUADAPTER_DETAILS_INDEX_DRIVERDATE, GPUADAPTER_DETAILS_INDEX_DRIVERVERSION, GPUADAPTER_DETAILS_INDEX_WDDMVERSION, + GPUADAPTER_DETAILS_INDEX_VENDORID, + GPUADAPTER_DETAILS_INDEX_DEVICEID, GPUADAPTER_DETAILS_INDEX_TOTALMEMORY, GPUADAPTER_DETAILS_INDEX_RESERVEDMEMORY, GPUADAPTER_DETAILS_INDEX_MEMORYFREQUENCY, @@ -51,6 +53,8 @@ VOID EtpGpuDetailsAddListViewItemGroups( PhAddListViewGroupItem(ListViewHandle, DiskGroupId, GPUADAPTER_DETAILS_INDEX_DRIVERDATE, L"Driver Date", NULL); PhAddListViewGroupItem(ListViewHandle, DiskGroupId, GPUADAPTER_DETAILS_INDEX_DRIVERVERSION, L"Driver Version", NULL); PhAddListViewGroupItem(ListViewHandle, DiskGroupId, GPUADAPTER_DETAILS_INDEX_WDDMVERSION, L"WDDM Version", NULL); + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, GPUADAPTER_DETAILS_INDEX_VENDORID, L"Vendor ID", NULL); + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, GPUADAPTER_DETAILS_INDEX_DEVICEID, L"Device ID", NULL); PhAddListViewGroupItem(ListViewHandle, DiskGroupId, GPUADAPTER_DETAILS_INDEX_TOTALMEMORY, L"Total Memory", NULL); PhAddListViewGroupItem(ListViewHandle, DiskGroupId, GPUADAPTER_DETAILS_INDEX_RESERVEDMEMORY, L"Reserved Memory", NULL); PhAddListViewGroupItem(ListViewHandle, DiskGroupId, GPUADAPTER_DETAILS_INDEX_MEMORYFREQUENCY, L"Memory Frequency", NULL); @@ -221,12 +225,18 @@ VOID EtpQueryAdapterDeviceIds( sizeof(D3DKMT_QUERY_DEVICE_IDS) ))) { - //UINT32 VendorID; - //UINT32 DeviceID; - //UINT32 SubVendorID; - //UINT32 SubSystemID; - //UINT32 RevisionID; - //UINT32 BusType; + WCHAR value[PH_PTR_STR_LEN_1]; + + PhPrintPointer(value, UlongToPtr(adapterDeviceId.DeviceIds.VendorID)); + PhSetListViewSubItem(ListViewHandle, GPUADAPTER_DETAILS_INDEX_VENDORID, 1, value); + + PhPrintPointer(value, UlongToPtr(adapterDeviceId.DeviceIds.DeviceID)); + PhSetListViewSubItem(ListViewHandle, GPUADAPTER_DETAILS_INDEX_DEVICEID, 1, value); + + //PhPrintPointer(value, UlongToPtr(adapterDeviceId.DeviceIds.SubVendorID)); + //PhPrintPointer(value, UlongToPtr(adapterDeviceId.DeviceIds.SubSystemID)); + //PhPrintPointer(value, UlongToPtr(adapterDeviceId.DeviceIds.RevisionID)); + //PhPrintPointer(value, UlongToPtr(adapterDeviceId.DeviceIds.BusType)); } } @@ -286,7 +296,7 @@ VOID EtpGpuDetailsEnumAdapters( //EtpQueryAdapterRegistryInfo(openAdapterFromDeviceName.AdapterHandle, ListViewHandle); EtpQueryAdapterDriverModel(openAdapterFromDeviceName.AdapterHandle, ListViewHandle); //EtpQueryAdapterDriverVersion(openAdapterFromDeviceName.AdapterHandle, ListViewHandle); - //EtpQueryAdapterDeviceIds(openAdapterFromDeviceName.AdapterHandle, ListViewHandle); + EtpQueryAdapterDeviceIds(openAdapterFromDeviceName.AdapterHandle, ListViewHandle); //EtQueryAdapterFeatureLevel(openAdapterFromDeviceName.AdapterLuid); EtpQueryAdapterPerfInfo(openAdapterFromDeviceName.AdapterHandle, ListViewHandle); diff --git a/plugins/ExtendedTools/gpumon.c b/plugins/ExtendedTools/gpumon.c index be5630bd4756..04dc0cfaccb0 100644 --- a/plugins/ExtendedTools/gpumon.c +++ b/plugins/ExtendedTools/gpumon.c @@ -35,8 +35,8 @@ ULONG EtGpuTotalNodeCount = 0; ULONG EtGpuTotalSegmentCount = 0; ULONG EtGpuNextNodeIndex = 0; -PH_UINT64_DELTA EtClockTotalRunningTimeDelta; -LARGE_INTEGER EtClockTotalRunningTimeFrequency; +PH_UINT64_DELTA EtClockTotalRunningTimeDelta = { 0, 0 }; +LARGE_INTEGER EtClockTotalRunningTimeFrequency = { 0 }; FLOAT EtGpuNodeUsage = 0; PH_CIRCULAR_BUFFER_FLOAT EtGpuNodeHistory; @@ -1046,7 +1046,7 @@ ULONG EtGetGpuAdapterIndexFromNodeIndex( return i; } - return -1; + return ULONG_MAX; } PPH_STRING EtGetGpuAdapterNodeDescription( From cc06c312962c9213d20dd23b3ac8bff390ed2bdb Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 15 Jun 2018 18:42:52 +1000 Subject: [PATCH 1044/2058] Add SUBSYSTEM_INFORMATION_TYPE --- phnt/include/ntpsapi.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/phnt/include/ntpsapi.h b/phnt/include/ntpsapi.h index 7de4443d8214..feb7fb06dd0a 100644 --- a/phnt/include/ntpsapi.h +++ b/phnt/include/ntpsapi.h @@ -987,6 +987,14 @@ typedef struct _THREAD_NAME_INFORMATION UNICODE_STRING ThreadName; } THREAD_NAME_INFORMATION, *PTHREAD_NAME_INFORMATION; +// private +typedef enum _SUBSYSTEM_INFORMATION_TYPE +{ + SubsystemInformationTypeWin32, + SubsystemInformationTypeWSL, + MaxSubsystemInformationType +} SUBSYSTEM_INFORMATION_TYPE; + // Processes #if (PHNT_MODE != PHNT_MODE_KERNEL) @@ -1297,6 +1305,9 @@ NtQueueApcThread( ); #if (PHNT_VERSION >= PHNT_WIN7) + +#define APC_FORCE_THREAD_SIGNAL ((HANDLE)1) // UserApcReserveHandle + NTSYSCALLAPI NTSTATUS NTAPI From 8c1bf4ad1ddbdcb155836c6b90ae49fcac6086d3 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 15 Jun 2018 18:47:51 +1000 Subject: [PATCH 1045/2058] peview: Improve ELF import/export enumeration --- phlib/mapexlf.c | 89 ++++++++++++++++++++++++------------------------- 1 file changed, 43 insertions(+), 46 deletions(-) diff --git a/phlib/mapexlf.c b/phlib/mapexlf.c index a4c8f8a36cd5..59a3c5d63de9 100644 --- a/phlib/mapexlf.c +++ b/phlib/mapexlf.c @@ -211,8 +211,6 @@ PELF64_IMAGE_SECTION_HEADER PhGetMappedWslImageSectionByType( return NULL; } -// TODO: Check this is actually correct. -// https://stackoverflow.com/questions/18296276/base-address-of-elf ULONG64 PhGetMappedWslImageBaseAddress( _In_ PPH_MAPPED_IMAGE MappedWslImage ) @@ -320,8 +318,7 @@ static PPH_LIST PhpParseMappedWslImageVersionRecords( { PPH_ELF_VERSION_RECORD versionInfo; - versionInfo = PhAllocate(sizeof(PH_ELF_VERSION_RECORD)); - memset(versionInfo, 0, sizeof(PH_ELF_VERSION_RECORD)); + versionInfo = PhAllocateZero(sizeof(PH_ELF_VERSION_RECORD)); versionInfo->Version = versionAux->vna_other; versionInfo->Name = PTR_ADD_OFFSET(SymbolStringTable, versionAux->vna_name); versionInfo->FileName = PTR_ADD_OFFSET(SymbolStringTable, version->vn_file); @@ -370,30 +367,34 @@ static PSTR PhpFindWslImageVersionRecordName( return NULL; } -// TODO: Optimize this function. BOOLEAN PhGetMappedWslImageSymbols( _In_ PPH_MAPPED_IMAGE MappedWslImage, _Out_ PPH_LIST *ImageSymbols ) { + PELF64_IMAGE_SECTION_HEADER sectionHeader; PELF64_IMAGE_SECTION_HEADER section; - PPH_LIST symbols = PhCreateList(2000); + PPH_LIST sectionSymbols; + USHORT i; - if (section = PhGetMappedWslImageSectionByType(MappedWslImage, SHT_SYMTAB)) - { - // TODO: Need to find a WSL binary with a symbol table. - // SHT_SYMTAB should be parsed idential to SHT_DYNSYM? - } - - if (section = PhGetMappedWslImageSectionByType(MappedWslImage, SHT_DYNSYM)) + sectionSymbols = PhCreateList(0x800); + sectionHeader = IMAGE_FIRST_ELF64_SECTION(MappedWslImage); + + for (i = 0; i < MappedWslImage->Headers64->e_shnum; i++) { ULONGLONG count; - ULONGLONG i; + ULONGLONG ii; PELF_IMAGE_SYMBOL_ENTRY entry; PVOID stringTable; PELF_VERSION_TABLE versionTable; PPH_LIST versionRecords; + section = IMAGE_ELF64_SECTION_BY_INDEX(sectionHeader, i); + + // NOTE: The below code needs some improvements for SHT_DYNSYM -dmex + if (section->sh_type != SHT_SYMTAB && section->sh_type != SHT_DYNSYM) + continue; + if (section->sh_entsize != sizeof(ELF_IMAGE_SYMBOL_ENTRY)) return FALSE; @@ -401,26 +402,26 @@ BOOLEAN PhGetMappedWslImageSymbols( entry = PTR_ADD_OFFSET(MappedWslImage->Header, section->sh_offset); stringTable = PhGetMappedWslImageSectionData(MappedWslImage, NULL, section->sh_link); + // NOTE: Some entries include the version in the symbol name (e.g. NAME@VERSION) + // instead of using a version record entry from SHT_SUNW_versym -dmex versionTable = PhGetMappedWslImageSectionDataByType(MappedWslImage, SHT_SUNW_versym); versionRecords = PhpParseMappedWslImageVersionRecords(MappedWslImage, stringTable); - for (i = 1; i < count; i++) + for (ii = 1; ii < count; ii++) { - if (entry[i].st_shndx == SHN_UNDEF) + if (entry[ii].st_shndx == SHN_UNDEF) { PPH_ELF_IMAGE_SYMBOL_ENTRY import; - import = PhAllocate(sizeof(PH_ELF_IMAGE_SYMBOL_ENTRY)); - memset(import, 0, sizeof(PH_ELF_IMAGE_SYMBOL_ENTRY)); - + import = PhAllocateZero(sizeof(PH_ELF_IMAGE_SYMBOL_ENTRY)); import->ImportSymbol = TRUE; - import->Address = entry[i].st_value; - import->Size = entry[i].st_size; - import->TypeInfo = entry[i].st_info; + import->Address = entry[ii].st_value; + import->Size = entry[ii].st_size; + import->TypeInfo = entry[ii].st_info; // function name PhCopyStringZFromBytes( - PTR_ADD_OFFSET(stringTable, entry[i].st_name), + PTR_ADD_OFFSET(stringTable, entry[ii].st_name), -1, import->Name, sizeof(import->Name), @@ -432,7 +433,7 @@ BOOLEAN PhGetMappedWslImageSymbols( { PSTR moduleName; - if (moduleName = PhpFindWslImageVersionRecordName(versionRecords, versionTable[i].vs_vers)) + if (moduleName = PhpFindWslImageVersionRecordName(versionRecords, versionTable[ii].vs_vers)) { PhCopyStringZFromBytes( moduleName, @@ -444,56 +445,52 @@ BOOLEAN PhGetMappedWslImageSymbols( } } - PhAddItemList(symbols, import); + PhAddItemList(sectionSymbols, import); } - else if (entry[i].st_shndx != SHN_UNDEF && entry[i].st_value != 0) + else if (entry[ii].st_shndx != SHN_UNDEF && entry[ii].st_value != 0) { PPH_ELF_IMAGE_SYMBOL_ENTRY export; - if (ELF_ST_TYPE(entry[i].st_info) == STT_SECTION) // Ignore section symbol types. + if (ELF_ST_TYPE(entry[ii].st_info) == STT_SECTION) // Ignore section symbol types. continue; - export = PhAllocate(sizeof(PH_ELF_IMAGE_SYMBOL_ENTRY)); - memset(export, 0, sizeof(PH_ELF_IMAGE_SYMBOL_ENTRY)); - + export = PhAllocateZero(sizeof(PH_ELF_IMAGE_SYMBOL_ENTRY)); export->ExportSymbol = TRUE; - export->Address = entry[i].st_value; - export->Size = entry[i].st_size; - export->TypeInfo = entry[i].st_info; + export->Address = entry[ii].st_value; + export->Size = entry[ii].st_size; + export->TypeInfo = entry[ii].st_info; // function name PhCopyStringZFromBytes( - PTR_ADD_OFFSET(stringTable, entry[i].st_name), + PTR_ADD_OFFSET(stringTable, entry[ii].st_name), -1, export->Name, sizeof(export->Name), NULL ); - PhAddItemList(symbols, export); + PhAddItemList(sectionSymbols, export); } else - { + { PPH_ELF_IMAGE_SYMBOL_ENTRY export; - export = PhAllocate(sizeof(PH_ELF_IMAGE_SYMBOL_ENTRY)); - memset(export, 0, sizeof(PH_ELF_IMAGE_SYMBOL_ENTRY)); - + export = PhAllocateZero(sizeof(PH_ELF_IMAGE_SYMBOL_ENTRY)); export->UnknownSymbol = TRUE; - export->Address = entry[i].st_value; - export->Size = entry[i].st_size; - export->TypeInfo = entry[i].st_info; + export->Address = entry[ii].st_value; + export->Size = entry[ii].st_size; + export->TypeInfo = entry[ii].st_info; // function name PhCopyStringZFromBytes( - PTR_ADD_OFFSET(stringTable, entry[i].st_name), + PTR_ADD_OFFSET(stringTable, entry[ii].st_name), -1, export->Name, sizeof(export->Name), NULL ); - PhAddItemList(symbols, export); + PhAddItemList(sectionSymbols, export); } } @@ -501,7 +498,7 @@ BOOLEAN PhGetMappedWslImageSymbols( PhpFreeMappedWslImageVersionRecords(versionRecords); } - *ImageSymbols = symbols; + *ImageSymbols = sectionSymbols; return TRUE; } @@ -514,4 +511,4 @@ VOID PhFreeMappedWslImageSymbols( PhFree(ImageSymbols->Items[i]); PhDereferenceObject(ImageSymbols); -} \ No newline at end of file +} From 9cf3ea5cae5da5e33aa000a8bcdb0fad70468959 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 15 Jun 2018 18:48:14 +1000 Subject: [PATCH 1046/2058] Fix typo --- ProcessHacker/prpgmod.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ProcessHacker/prpgmod.c b/ProcessHacker/prpgmod.c index d64629e4d8c2..0593ee29aa66 100644 --- a/ProcessHacker/prpgmod.c +++ b/ProcessHacker/prpgmod.c @@ -736,7 +736,7 @@ INT_PTR CALLBACK PhpProcessModulesDlgProc( if (PhGetIntegerSetting(L"EnableWarnings") && !PhShowConfirmMessage( hwndDlg, L"load", - L"the module", + L"a module", L"Some programs may restrict access or ban your account when loading modules into the process.", FALSE )) From d6a5c8df084adca6bfef7e59169ad757b2efd6b6 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 18 Jun 2018 22:44:09 +1000 Subject: [PATCH 1047/2058] Add contributors link to About window, Make About single-instance window --- ProcessHacker/ProcessHacker.rc | 10 ++++----- ProcessHacker/about.c | 40 ++++++++++++++++++++++++++-------- 2 files changed, 36 insertions(+), 14 deletions(-) diff --git a/ProcessHacker/ProcessHacker.rc b/ProcessHacker/ProcessHacker.rc index de2d3815f662..ca6e672bcd94 100644 --- a/ProcessHacker/ProcessHacker.rc +++ b/ProcessHacker/ProcessHacker.rc @@ -608,11 +608,11 @@ STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTI CAPTION "About" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN - ICON IDI_PROCESSHACKER,IDC_STATIC,16,15,20,20 - LTEXT "Process Hacker",IDC_ABOUT_NAME,45,14,192,8 - LTEXT "Licensed under the GNU GPL, v3.",IDC_STATIC,45,27,193,8 - LTEXT "Copyright (c) 2008-2018",IDC_STATIC,45,40,80,8 - CONTROL "Credits.",IDC_CREDITS,"SysLink",WS_TABSTOP,15,55,248,115 + ICON IDI_PROCESSHACKER,IDC_STATIC,16,11,21,20 + LTEXT "Process Hacker",IDC_ABOUT_NAME,45,10,192,8 + LTEXT "Licensed under the GNU GPL, v3.",IDC_STATIC,45,23,193,8 + LTEXT "Copyright (c) 2008-2018",IDC_STATIC,45,36,80,8 + CONTROL "Credits.",IDC_CREDITS,"SysLink",WS_TABSTOP,15,49,248,121 CONTROL "Process Hacker on SourceForge.net",IDC_LINK_SF, "SysLink",WS_TABSTOP,7,177,130,11 PUSHBUTTON "Diagnostics",IDC_DIAGNOSTICS,160,174,50,14 diff --git a/ProcessHacker/about.c b/ProcessHacker/about.c index 770874f8227c..8c7cf704c7bc 100644 --- a/ProcessHacker/about.c +++ b/ProcessHacker/about.c @@ -22,8 +22,6 @@ */ #include - -#include #include #include @@ -36,6 +34,11 @@ #include #include +#include +#include + +static HWND PhAboutWindowHandle = NULL; + static INT_PTR CALLBACK PhpAboutDlgProc( _In_ HWND hwndDlg, _In_ UINT uMsg, @@ -78,6 +81,7 @@ static INT_PTR CALLBACK PhpAboutDlgProc( L" wj32 - Wen Jia Liu\n" L" dmex - Steven G\n" L" XhmikosR\n" + L" Contributors - thank you for your additions!\n" L" Donors - thank you for your support!\n\n" L"Process Hacker uses the following components:\n" L" Mini-XML by Michael Sweet\n" @@ -90,6 +94,14 @@ static INT_PTR CALLBACK PhpAboutDlgProc( ); PhSetDialogFocus(hwndDlg, GetDlgItem(hwndDlg, IDOK)); + + EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); + } + break; + case WM_DESTROY: + { + PhUnregisterDialog(PhAboutWindowHandle); + PhAboutWindowHandle = NULL; } break; case WM_COMMAND: @@ -98,7 +110,7 @@ static INT_PTR CALLBACK PhpAboutDlgProc( { case IDCANCEL: case IDOK: - EndDialog(hwndDlg, IDOK); + DestroyWindow(hwndDlg); break; case IDC_DIAGNOSTICS: { @@ -137,12 +149,22 @@ VOID PhShowAboutDialog( VOID ) { - DialogBox( - PhInstanceHandle, - MAKEINTRESOURCE(IDD_ABOUT), - NULL, - PhpAboutDlgProc - ); + if (!PhAboutWindowHandle) + { + PhAboutWindowHandle = CreateDialog( + PhInstanceHandle, + MAKEINTRESOURCE(IDD_ABOUT), + NULL, + PhpAboutDlgProc + ); + PhRegisterDialog(PhAboutWindowHandle); + ShowWindow(PhAboutWindowHandle, SW_SHOW); + } + + if (IsIconic(PhAboutWindowHandle)) + ShowWindow(PhAboutWindowHandle, SW_RESTORE); + else + SetForegroundWindow(PhAboutWindowHandle); } FORCEINLINE ULONG PhpGetObjectTypeObjectCount( From 009e1922acae884c519994bcf6516c108ff08e33 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 27 Jun 2018 15:51:51 +1000 Subject: [PATCH 1048/2058] Revert 3980408 (log window exit status for linux processes) --- ProcessHacker/log.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/ProcessHacker/log.c b/ProcessHacker/log.c index 36fc243b5307..a57862b1c614 100644 --- a/ProcessHacker/log.c +++ b/ProcessHacker/log.c @@ -102,15 +102,11 @@ PPH_LOG_ENTRY PhpCreateProcessLogEntry( if (QueryHandle && entry->Type == PH_LOG_ENTRY_PROCESS_DELETE) { - PROCESS_EXTENDED_BASIC_INFORMATION basicInfo; + PROCESS_BASIC_INFORMATION basicInfo; - if (NT_SUCCESS(PhGetProcessExtendedBasicInformation(QueryHandle, &basicInfo))) + if (NT_SUCCESS(PhGetProcessBasicInformation(QueryHandle, &basicInfo))) { - // The exit code for Linux processes is located in the lower 8-bits. - if (basicInfo.IsSubsystemProcess) - entry->Process.ExitStatus = basicInfo.BasicInfo.ExitStatus >> 8; - else - entry->Process.ExitStatus = basicInfo.BasicInfo.ExitStatus; + entry->Process.ExitStatus = basicInfo.ExitStatus; } } From 2bb718f36a702fde6cb346e9179696bb8c758d1f Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 27 Jun 2018 16:01:52 +1000 Subject: [PATCH 1049/2058] Fix SAL warning C26451 --- phlib/basesup.c | 2 +- phlib/include/phbasesup.h | 4 ++-- phlib/include/phnative.h | 2 +- phlib/include/refp.h | 2 +- phlib/util.c | 8 ++++---- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/phlib/basesup.c b/phlib/basesup.c index 2c71d0a0a958..9dcb13081fbf 100644 --- a/phlib/basesup.c +++ b/phlib/basesup.c @@ -4738,7 +4738,7 @@ VOID PhpResizeHashtable( Hashtable->Buckets[index] = i; } - entry = (PPH_HASHTABLE_ENTRY)((ULONG_PTR)entry + PH_HASHTABLE_ENTRY_SIZE(Hashtable->EntrySize)); + entry = PTR_ADD_OFFSET(entry, PH_HASHTABLE_ENTRY_SIZE(Hashtable->EntrySize)); } } diff --git a/phlib/include/phbasesup.h b/phlib/include/phbasesup.h index 196ceeb930b9..28d2b1796d5c 100644 --- a/phlib/include/phbasesup.h +++ b/phlib/include/phbasesup.h @@ -2922,7 +2922,7 @@ typedef struct _PH_HASHTABLE ULONG NextEntry; } PH_HASHTABLE, *PPH_HASHTABLE; -#define PH_HASHTABLE_ENTRY_SIZE(InnerSize) (FIELD_OFFSET(PH_HASHTABLE_ENTRY, Body) + (InnerSize)) +#define PH_HASHTABLE_ENTRY_SIZE(InnerSize) (UFIELD_OFFSET(PH_HASHTABLE_ENTRY, Body) + (InnerSize)) #define PH_HASHTABLE_GET_ENTRY(Hashtable, Index) \ ((PPH_HASHTABLE_ENTRY)PTR_ADD_OFFSET((Hashtable)->Entries, \ PH_HASHTABLE_ENTRY_SIZE((Hashtable)->EntrySize) * (Index))) @@ -3006,7 +3006,7 @@ PhBeginEnumHashtable( ) { Context->Current = (ULONG_PTR)Hashtable->Entries; - Context->Step = PH_HASHTABLE_ENTRY_SIZE(Hashtable->EntrySize); + Context->Step = PH_HASHTABLE_ENTRY_SIZE((ULONG_PTR)Hashtable->EntrySize); Context->End = Context->Current + (ULONG_PTR)Hashtable->NextEntry * Context->Step; } diff --git a/phlib/include/phnative.h b/phlib/include/phnative.h index a96d37e8ef98..8a5a1c927502 100644 --- a/phlib/include/phnative.h +++ b/phlib/include/phnative.h @@ -676,7 +676,7 @@ PhGetKernelFileName( #define PH_PROCESS_EXTENSION(Process) \ ((PSYSTEM_PROCESS_INFORMATION_EXTENSION)PTR_ADD_OFFSET((Process), \ - FIELD_OFFSET(SYSTEM_PROCESS_INFORMATION, Threads) + \ + UFIELD_OFFSET(SYSTEM_PROCESS_INFORMATION, Threads) + \ sizeof(SYSTEM_THREAD_INFORMATION) * \ ((PSYSTEM_PROCESS_INFORMATION)(Process))->NumberOfThreads)) diff --git a/phlib/include/refp.h b/phlib/include/refp.h index dfa9478f9768..71becfa13964 100644 --- a/phlib/include/refp.h +++ b/phlib/include/refp.h @@ -121,7 +121,7 @@ C_ASSERT(FIELD_OFFSET(PH_OBJECT_HEADER, Body) == 0x8); * * \return The new size, including space for the object header. */ -#define PhAddObjectHeaderSize(Size) ((Size) + FIELD_OFFSET(PH_OBJECT_HEADER, Body)) +#define PhAddObjectHeaderSize(Size) ((Size) + UFIELD_OFFSET(PH_OBJECT_HEADER, Body)) /** An object type specifies a kind of object and its delete procedure. */ typedef struct _PH_OBJECT_TYPE diff --git a/phlib/util.c b/phlib/util.c index ec23b662bcb7..3927893332a5 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -1689,13 +1689,13 @@ BOOLEAN PhInitializeImageVersionInfo( // The version information is language-independent and must be read from the root block. if (VerQueryValue(versionInfo, L"\\", &rootBlock, &rootBlockLength) && rootBlockLength != 0) { - PhInitFormatU(&fileVersionFormat[0], rootBlock->dwFileVersionMS >> 16); + PhInitFormatU(&fileVersionFormat[0], HIWORD(rootBlock->dwFileVersionMS)); PhInitFormatC(&fileVersionFormat[1], '.'); - PhInitFormatU(&fileVersionFormat[2], rootBlock->dwFileVersionMS & 0xffff); + PhInitFormatU(&fileVersionFormat[2], LOWORD(rootBlock->dwFileVersionMS)); PhInitFormatC(&fileVersionFormat[3], '.'); - PhInitFormatU(&fileVersionFormat[4], rootBlock->dwFileVersionLS >> 16); + PhInitFormatU(&fileVersionFormat[4], HIWORD(rootBlock->dwFileVersionLS)); PhInitFormatC(&fileVersionFormat[5], '.'); - PhInitFormatU(&fileVersionFormat[6], rootBlock->dwFileVersionLS & 0xffff); + PhInitFormatU(&fileVersionFormat[6], LOWORD(rootBlock->dwFileVersionLS)); ImageVersionInfo->FileVersion = PhFormat(fileVersionFormat, 7, 30); } From 391a2d456db3cf04119863141b374c7e2f869e79 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 27 Jun 2018 16:13:05 +1000 Subject: [PATCH 1050/2058] Update PCRE heap --- ProcessHacker/pcre/pcre2_context.c | 7 ++++--- ProcessHacker/pcre/pcre2_maketables.c | 3 ++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/ProcessHacker/pcre/pcre2_context.c b/ProcessHacker/pcre/pcre2_context.c index 2c14df00805b..88909136efe6 100644 --- a/ProcessHacker/pcre/pcre2_context.c +++ b/ProcessHacker/pcre/pcre2_context.c @@ -38,6 +38,7 @@ POSSIBILITY OF SUCH DAMAGE. ----------------------------------------------------------------------------- */ +#include #ifdef HAVE_CONFIG_H #include "config.h" @@ -56,14 +57,14 @@ POSSIBILITY OF SUCH DAMAGE. static void *default_malloc(size_t size, void *data) { (void)data; -return malloc(size); +return PhAllocateSafe(size); } static void default_free(void *block, void *data) { (void)data; -free(block); +PhFree(block); } @@ -86,7 +87,7 @@ extern void * PRIV(memctl_malloc)(size_t size, pcre2_memctl *memctl) { pcre2_memctl *newmemctl; -void *yield = (memctl == NULL)? malloc(size) : +void *yield = (memctl == NULL)? PhAllocateSafe(size) : memctl->malloc(size, memctl->memory_data); if (yield == NULL) return NULL; newmemctl = (pcre2_memctl *)yield; diff --git a/ProcessHacker/pcre/pcre2_maketables.c b/ProcessHacker/pcre/pcre2_maketables.c index 2c7ae84d864d..467e4c533c84 100644 --- a/ProcessHacker/pcre/pcre2_maketables.c +++ b/ProcessHacker/pcre/pcre2_maketables.c @@ -38,6 +38,7 @@ POSSIBILITY OF SUCH DAMAGE. ----------------------------------------------------------------------------- */ +#include /* This module contains the external function pcre2_maketables(), which builds character tables for PCRE2 in the current locale. The file is compiled on its @@ -81,7 +82,7 @@ pcre2_maketables(pcre2_general_context *gcontext) { uint8_t *yield = (uint8_t *)((gcontext != NULL)? gcontext->memctl.malloc(tables_length, gcontext->memctl.memory_data) : - malloc(tables_length)); + PhAllocateSafe(tables_length)); #endif /* DFTABLES */ int i; From dbbc9ded875ad7e7998078bc927f0c66e209ffc6 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 27 Jun 2018 17:09:54 +1000 Subject: [PATCH 1051/2058] HardwareDevices: Add right-click menu to options window > disk/network tabs --- phlib/include/phbasesup.h | 2 +- plugins/HardwareDevices/adapter.c | 44 +++++++---- plugins/HardwareDevices/devices.h | 13 +--- plugins/HardwareDevices/diskoptions.c | 3 +- plugins/HardwareDevices/main.c | 103 ++++++++++++++++++++++++-- plugins/HardwareDevices/ndis.c | 62 +++++++++------- plugins/HardwareDevices/netdetails.c | 17 +++-- plugins/HardwareDevices/netgraph.c | 55 +++++++------- plugins/HardwareDevices/netoptions.c | 53 ++++++++----- 9 files changed, 241 insertions(+), 111 deletions(-) diff --git a/phlib/include/phbasesup.h b/phlib/include/phbasesup.h index 28d2b1796d5c..4be0557be0bd 100644 --- a/phlib/include/phbasesup.h +++ b/phlib/include/phbasesup.h @@ -172,7 +172,7 @@ PhDelayExecution( { LARGE_INTEGER interval; - interval.QuadPart = -Interval * PH_TIMEOUT_MS; + interval.QuadPart = -Interval; return NtDelayExecution(FALSE, &interval); } diff --git a/plugins/HardwareDevices/adapter.c b/plugins/HardwareDevices/adapter.c index 4cd3c0daf0c8..0b1f97d0a4c1 100644 --- a/plugins/HardwareDevices/adapter.c +++ b/plugins/HardwareDevices/adapter.c @@ -34,7 +34,7 @@ VOID AdapterEntryDeleteProcedure( PhRemoveItemList(NetworkAdaptersList, PhFindItemList(NetworkAdaptersList, entry)); PhReleaseQueuedLockExclusive(&NetworkAdaptersListLock); - DeleteNetAdapterId(&entry->Id); + DeleteNetAdapterId(&entry->AdapterId); PhClearReference(&entry->AdapterName); PhDeleteCircularBuffer_ULONG64(&entry->InboundBuffer); @@ -74,7 +74,15 @@ VOID NetAdaptersUpdate( if (PhGetIntegerSetting(SETTING_NAME_ENABLE_NDIS)) { - if (NT_SUCCESS(NetworkAdapterCreateHandle(&deviceHandle, entry->Id.InterfaceDevice))) + if (NT_SUCCESS(PhCreateFileWin32( + &deviceHandle, + PhGetString(entry->AdapterId.InterfaceDevice), + FILE_GENERIC_READ, + FILE_ATTRIBUTE_NORMAL, + FILE_SHARE_READ | FILE_SHARE_WRITE, + FILE_OPEN, + FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT + ))) { if (!entry->CheckedDeviceSupport) { @@ -103,31 +111,35 @@ VOID NetAdaptersUpdate( memset(&interfaceStats, 0, sizeof(NDIS_STATISTICS_INFO)); - NetworkAdapterQueryStatistics(deviceHandle, &interfaceStats); - if (NT_SUCCESS(NetworkAdapterQueryLinkState(deviceHandle, &interfaceState))) { mediaState = interfaceState.MediaConnectState; } - if (!(interfaceStats.SupportedStatistics & NDIS_STATISTICS_FLAGS_VALID_BYTES_RCV)) - networkInOctets = NetworkAdapterQueryValue(deviceHandle, OID_GEN_BYTES_RCV); + if (NT_SUCCESS(NetworkAdapterQueryStatistics(deviceHandle, &interfaceStats))) + { + if (!(interfaceStats.SupportedStatistics & NDIS_STATISTICS_FLAGS_VALID_BYTES_RCV)) + networkInOctets = NetworkAdapterQueryValue(deviceHandle, OID_GEN_BYTES_RCV); + else + networkInOctets = interfaceStats.ifHCInOctets; + + if (!(interfaceStats.SupportedStatistics & NDIS_STATISTICS_FLAGS_VALID_BYTES_XMIT)) + networkOutOctets = NetworkAdapterQueryValue(deviceHandle, OID_GEN_BYTES_XMIT); + else + networkOutOctets = interfaceStats.ifHCOutOctets; + } else - networkInOctets = interfaceStats.ifHCInOctets; - - if (!(interfaceStats.SupportedStatistics & NDIS_STATISTICS_FLAGS_VALID_BYTES_XMIT)) + { + networkInOctets = NetworkAdapterQueryValue(deviceHandle, OID_GEN_BYTES_RCV); networkOutOctets = NetworkAdapterQueryValue(deviceHandle, OID_GEN_BYTES_XMIT); - else - networkOutOctets = interfaceStats.ifHCOutOctets; + } networkRcvSpeed = networkInOctets - entry->LastInboundValue; networkXmitSpeed = networkOutOctets - entry->LastOutboundValue; // HACK: Pull the Adapter name from the current query. if (!entry->AdapterName) - { - entry->AdapterName = NetworkAdapterQueryName(deviceHandle, entry->Id.InterfaceGuid); - } + entry->AdapterName = NetworkAdapterQueryName(deviceHandle, entry->AdapterId.InterfaceGuid); entry->DevicePresent = TRUE; @@ -137,7 +149,7 @@ VOID NetAdaptersUpdate( { MIB_IF_ROW2 interfaceRow; - if (QueryInterfaceRow(&entry->Id, &interfaceRow)) + if (QueryInterfaceRow(&entry->AdapterId, &interfaceRow)) { networkInOctets = interfaceRow.InOctets; networkOutOctets = interfaceRow.OutOctets; @@ -248,7 +260,7 @@ PDV_NETADAPTER_ENTRY CreateNetAdapterEntry( entry = PhCreateObject(sizeof(DV_NETADAPTER_ENTRY), NetAdapterEntryType); memset(entry, 0, sizeof(DV_NETADAPTER_ENTRY)); - CopyNetAdapterId(&entry->Id, Id); + CopyNetAdapterId(&entry->AdapterId, Id); PhInitializeCircularBuffer_ULONG64(&entry->InboundBuffer, PhGetIntegerSetting(L"SampleCount")); PhInitializeCircularBuffer_ULONG64(&entry->OutboundBuffer, PhGetIntegerSetting(L"SampleCount")); diff --git a/plugins/HardwareDevices/devices.h b/plugins/HardwareDevices/devices.h index a38909a6be8d..610ace5a1e6e 100644 --- a/plugins/HardwareDevices/devices.h +++ b/plugins/HardwareDevices/devices.h @@ -41,10 +41,8 @@ #include #include -#include -#include -#include -#include + +#include #include #include @@ -87,7 +85,7 @@ typedef struct _DV_NETADAPTER_ID typedef struct _DV_NETADAPTER_ENTRY { - DV_NETADAPTER_ID Id; + DV_NETADAPTER_ID AdapterId; PPH_STRING AdapterName; union @@ -286,11 +284,6 @@ typedef ULONG (WINAPI* _GetInterfaceDescriptionFromGuid)( PVOID Unknown2 ); -NTSTATUS NetworkAdapterCreateHandle( - _Out_ PHANDLE DeviceHandle, - _In_ PPH_STRING DeviceInterface - ); - BOOLEAN NetworkAdapterQuerySupported( _In_ HANDLE DeviceHandle ); diff --git a/plugins/HardwareDevices/diskoptions.c b/plugins/HardwareDevices/diskoptions.c index 56813eb16c93..8d20bd017028 100644 --- a/plugins/HardwareDevices/diskoptions.c +++ b/plugins/HardwareDevices/diskoptions.c @@ -21,7 +21,6 @@ */ #include "devices.h" -#include typedef struct _DISK_ENUM_ENTRY { @@ -272,7 +271,7 @@ BOOLEAN QueryDiskDeviceInterfaceDescription( bufferSize = 0x40; deviceDescription = PhCreateStringEx(NULL, bufferSize); - if ((result = CM_Get_DevNode_Property( // CM_Get_DevNode_Registry_Property with CM_DRP_DEVICEDESC?? + if ((result = CM_Get_DevNode_Property( deviceInstanceHandle, &DEVPKEY_Device_FriendlyName, &devicePropertyType, diff --git a/plugins/HardwareDevices/main.c b/plugins/HardwareDevices/main.c index 62f005c6d51b..7cc3482b8984 100644 --- a/plugins/HardwareDevices/main.c +++ b/plugins/HardwareDevices/main.c @@ -159,6 +159,89 @@ PPH_STRING TrimString( return PhCreateString2(&sr); } +BOOLEAN HardwareDeviceEnableDisable( + _In_ HWND ParentWindow, + _In_ PPH_STRING DeviceInstance, + _In_ BOOLEAN Enable + ) +{ + CONFIGRET result; + DEVINST deviceInstanceHandle; + + result = CM_Locate_DevNode( + &deviceInstanceHandle, + DeviceInstance->Buffer, + CM_LOCATE_DEVNODE_PHANTOM + ); + + if (result != CR_SUCCESS) + { + PhShowStatus(ParentWindow, L"Failed to change the device state.", 0, CM_MapCrToWin32Err(result, ERROR_INVALID_HANDLE_STATE)); + return FALSE; + } + + if (Enable) + result = CM_Enable_DevInst(deviceInstanceHandle, 0); // CM_DISABLE_PERSIST + else + result = CM_Disable_DevInst(deviceInstanceHandle, 0); // CM_DISABLE_PERSIST + + if (result != CR_SUCCESS) + { + PhShowStatus(ParentWindow, L"Failed to change the device state.", 0, CM_MapCrToWin32Err(result, ERROR_INVALID_HANDLE_STATE)); + return FALSE; + } + + return TRUE; +} + +BOOLEAN HardwareDeviceRestart( + _In_ HWND ParentWindow, + _In_ PPH_STRING DeviceInstance + ) +{ + CONFIGRET result; + DEVINST deviceInstanceHandle; + + result = CM_Locate_DevNode( + &deviceInstanceHandle, + DeviceInstance->Buffer, + CM_LOCATE_DEVNODE_PHANTOM + ); + + if (result != CR_SUCCESS) + { + PhShowStatus(ParentWindow, L"Failed to restart the device.", 0, CM_MapCrToWin32Err(result, ERROR_UNKNOWN_PROPERTY)); + return FALSE; + } + + result = CM_Query_And_Remove_SubTree( + deviceInstanceHandle, + NULL, + NULL, + 0, + CM_REMOVE_NO_RESTART + ); + + if (result != CR_SUCCESS) + { + PhShowStatus(ParentWindow, L"Failed to restart the device.", 0, CM_MapCrToWin32Err(result, ERROR_UNKNOWN_PROPERTY)); + return FALSE; + } + + result = CM_Setup_DevInst( + deviceInstanceHandle, + CM_SETUP_DEVNODE_READY + ); + + if (result != CR_SUCCESS) + { + PhShowStatus(ParentWindow, L"Failed to restart the device.", 0, CM_MapCrToWin32Err(result, ERROR_UNKNOWN_PROPERTY)); + return FALSE; + } + + return TRUE; +} + VOID ShowDeviceMenu( _In_ HWND ParentWindow, _In_ PPH_STRING DeviceInstance @@ -171,25 +254,33 @@ VOID ShowDeviceMenu( GetCursorPos(&cursorPos); menu = PhCreateEMenu(); - //PhInsertEMenuItem(menu, PhCreateEMenuItem(0, 0, L"Enable", NULL, NULL), -1); - //PhInsertEMenuItem(menu, PhCreateEMenuItem(0, 1, L"Disable", NULL, NULL), -1); - //PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), -1); - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, 1, L"Properties", NULL, NULL), -1); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, 0, L"Enable", NULL, NULL), ULONG_MAX); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, 1, L"Disable", NULL, NULL), ULONG_MAX); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, 2, L"Restart", NULL, NULL), ULONG_MAX); + PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, 3, L"Properties", NULL, NULL), ULONG_MAX); selectedItem = PhShowEMenu( menu, - PhMainWndHandle, + ParentWindow, PH_EMENU_SHOW_LEFTRIGHT, PH_ALIGN_LEFT | PH_ALIGN_TOP, cursorPos.x, cursorPos.y ); - if (selectedItem && selectedItem->Id != -1) + if (selectedItem && selectedItem->Id != ULONG_MAX) { switch (selectedItem->Id) { + case 0: case 1: + HardwareDeviceEnableDisable(ParentWindow, DeviceInstance, selectedItem->Id == 0); + break; + case 2: + HardwareDeviceRestart(ParentWindow, DeviceInstance); + break; + case 3: { HMODULE devMgrHandle; diff --git a/plugins/HardwareDevices/ndis.c b/plugins/HardwareDevices/ndis.c index 59909af53787..512527d787b9 100644 --- a/plugins/HardwareDevices/ndis.c +++ b/plugins/HardwareDevices/ndis.c @@ -26,26 +26,11 @@ PVOID IphlpHandle = NULL; _GetInterfaceDescriptionFromGuid GetInterfaceDescriptionFromGuid_I = NULL; -NTSTATUS NetworkAdapterCreateHandle( - _Out_ PHANDLE DeviceHandle, - _In_ PPH_STRING DeviceInterface - ) -{ - return PhCreateFileWin32( - DeviceHandle, - PhGetString(DeviceInterface), - FILE_GENERIC_READ, - FILE_ATTRIBUTE_NORMAL, - FILE_SHARE_READ | FILE_SHARE_WRITE, - FILE_OPEN, - FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT - ); -} - BOOLEAN NetworkAdapterQuerySupported( _In_ HANDLE DeviceHandle ) { + NTSTATUS status; NDIS_OID opcode; IO_STATUS_BLOCK isb; BOOLEAN ndisQuerySupported = FALSE; @@ -53,15 +38,16 @@ BOOLEAN NetworkAdapterQuerySupported( BOOLEAN adapterStatsSupported = FALSE; BOOLEAN adapterLinkStateSupported = FALSE; BOOLEAN adapterLinkSpeedSupported = FALSE; - PNDIS_OID ndisObjectIdentifiers; + PNDIS_OID objectIdBuffer; + ULONG objectIdBufferLength; + ULONG attempts = 0; opcode = OID_GEN_SUPPORTED_LIST; - // TODO: 4096 objects might be too small... - ndisObjectIdentifiers = PhAllocate(PAGE_SIZE * sizeof(NDIS_OID)); - memset(ndisObjectIdentifiers, 0, PAGE_SIZE * sizeof(NDIS_OID)); + objectIdBufferLength = 2048 * sizeof(NDIS_OID); + objectIdBuffer = PhAllocateZero(objectIdBufferLength); - if (NT_SUCCESS(NtDeviceIoControlFile( + status = NtDeviceIoControlFile( DeviceHandle, NULL, NULL, @@ -70,15 +56,38 @@ BOOLEAN NetworkAdapterQuerySupported( IOCTL_NDIS_QUERY_GLOBAL_STATS, &opcode, sizeof(NDIS_OID), - ndisObjectIdentifiers, - PAGE_SIZE * sizeof(NDIS_OID) - ))) + objectIdBuffer, + objectIdBufferLength + ); + + while (status == STATUS_BUFFER_OVERFLOW && attempts < 8) + { + PhFree(objectIdBuffer); + objectIdBufferLength *= 2; + objectIdBuffer = PhAllocateZero(objectIdBufferLength); + + status = NtDeviceIoControlFile( + DeviceHandle, + NULL, + NULL, + NULL, + &isb, + IOCTL_NDIS_QUERY_GLOBAL_STATS, + &opcode, + sizeof(NDIS_OID), + objectIdBuffer, + objectIdBufferLength + ); + attempts++; + } + + if (NT_SUCCESS(status)) { ndisQuerySupported = TRUE; for (ULONG i = 0; i < (ULONG)isb.Information / sizeof(NDIS_OID); i++) { - NDIS_OID objectId = ndisObjectIdentifiers[i]; + NDIS_OID objectId = objectIdBuffer[i]; switch (objectId) { @@ -98,7 +107,7 @@ BOOLEAN NetworkAdapterQuerySupported( } } - PhFree(ndisObjectIdentifiers); + PhFree(objectIdBuffer); if (!adapterNameSupported) ndisQuerySupported = FALSE; @@ -465,7 +474,6 @@ BOOLEAN QueryInterfaceRow( return result; } - PWSTR MediumTypeToString( _In_ NDIS_PHYSICAL_MEDIUM MediumType ) diff --git a/plugins/HardwareDevices/netdetails.c b/plugins/HardwareDevices/netdetails.c index 61107d420d90..6bbb13460d46 100644 --- a/plugins/HardwareDevices/netdetails.c +++ b/plugins/HardwareDevices/netdetails.c @@ -353,7 +353,15 @@ VOID NetAdapterUpdateDetails( if (PhGetIntegerSetting(SETTING_NAME_ENABLE_NDIS)) { - if (NT_SUCCESS(NetworkAdapterCreateHandle(&deviceHandle, Context->AdapterId.InterfaceDevice))) + if (NT_SUCCESS(PhCreateFileWin32( + &deviceHandle, + PhGetString(Context->AdapterId.InterfaceDevice), + FILE_GENERIC_READ, + FILE_ATTRIBUTE_NORMAL, + FILE_SHARE_READ | FILE_SHARE_WRITE, + FILE_OPEN, + FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT + ))) { if (!Context->CheckedDeviceSupport) { @@ -655,12 +663,11 @@ VOID ShowNetAdapterDetailsDialog( { PDV_NETADAPTER_DETAILS_CONTEXT context; - context = PhAllocate(sizeof(DV_NETADAPTER_DETAILS_CONTEXT)); - memset(context, 0, sizeof(DV_NETADAPTER_DETAILS_CONTEXT)); - + context = PhAllocateZero(sizeof(DV_NETADAPTER_DETAILS_CONTEXT)); context->ParentHandle = Context->WindowHandle; + PhSetReference(&context->AdapterName, Context->AdapterEntry->AdapterName); - CopyNetAdapterId(&context->AdapterId, &Context->AdapterEntry->Id); + CopyNetAdapterId(&context->AdapterId, &Context->AdapterEntry->AdapterId); PhCreateThread2(ShowNetAdapterDetailsDialogThread, context); } \ No newline at end of file diff --git a/plugins/HardwareDevices/netgraph.c b/plugins/HardwareDevices/netgraph.c index 2ed5ad71f9a7..46dfeed8762f 100644 --- a/plugins/HardwareDevices/netgraph.c +++ b/plugins/HardwareDevices/netgraph.c @@ -47,8 +47,15 @@ VOID NetAdapterUpdatePanel( if (PhGetIntegerSetting(SETTING_NAME_ENABLE_NDIS)) { - // Create the handle to the network device - if (NT_SUCCESS(NetworkAdapterCreateHandle(&deviceHandle, Context->AdapterEntry->Id.InterfaceDevice))) + if (NT_SUCCESS(PhCreateFileWin32( + &deviceHandle, + PhGetString(Context->AdapterEntry->AdapterId.InterfaceDevice), + FILE_GENERIC_READ, + FILE_ATTRIBUTE_NORMAL, + FILE_SHARE_READ | FILE_SHARE_WRITE, + FILE_OPEN, + FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT + ))) { if (!Context->AdapterEntry->CheckedDeviceSupport) { @@ -63,7 +70,7 @@ VOID NetAdapterUpdatePanel( if (!Context->AdapterEntry->DeviceSupported) { - // Device is faulty. Close the handle so we can fallback to GetIfEntry. + // Close the handle and fallback to GetIfEntry. NtClose(deviceHandle); deviceHandle = NULL; } @@ -115,7 +122,7 @@ VOID NetAdapterUpdatePanel( { MIB_IF_ROW2 interfaceRow; - if (QueryInterfaceRow(&Context->AdapterEntry->Id, &interfaceRow)) + if (QueryInterfaceRow(&Context->AdapterEntry->AdapterId, &interfaceRow)) { inOctetsValue = interfaceRow.InOctets; outOctetsValue = interfaceRow.OutOctets; @@ -210,7 +217,6 @@ INT_PTR CALLBACK NetAdapterDialogProc( if (uMsg == WM_INITDIALOG) { context = (PDV_NETADAPTER_SYSINFO_CONTEXT)lParam; - PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context); } else @@ -219,15 +225,6 @@ INT_PTR CALLBACK NetAdapterDialogProc( if (uMsg == WM_DESTROY) { - PhDeleteLayoutManager(&context->LayoutManager); - PhDeleteGraphState(&context->GraphState); - - if (context->GraphHandle) - DestroyWindow(context->GraphHandle); - - if (context->PanelWindowHandle) - DestroyWindow(context->PanelWindowHandle); - PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); } } @@ -252,11 +249,7 @@ INT_PTR CALLBACK NetAdapterDialogProc( panelItem = PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_LAYOUT), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); SendMessage(GetDlgItem(hwndDlg, IDC_ADAPTERNAME), WM_SETFONT, (WPARAM)context->SysinfoSection->Parameters->LargeFont, FALSE); - - if (context->AdapterEntry->AdapterName) - PhSetDialogItemText(hwndDlg, IDC_ADAPTERNAME, context->AdapterEntry->AdapterName->Buffer); - else - PhSetDialogItemText(hwndDlg, IDC_ADAPTERNAME, L"Unknown network adapter"); + PhSetDialogItemText(hwndDlg, IDC_ADAPTERNAME, PhGetStringOrDefault(context->AdapterEntry->AdapterName, L"Unknown network adapter")); context->PanelWindowHandle = CreateDialogParam(PluginInstance->DllBase, MAKEINTRESOURCE(IDD_NETADAPTER_PANEL), hwndDlg, NetAdapterPanelDialogProc, (LPARAM)context); ShowWindow(context->PanelWindowHandle, SW_SHOW); @@ -282,6 +275,18 @@ INT_PTR CALLBACK NetAdapterDialogProc( UpdateNetAdapterDialog(context); } break; + case WM_DESTROY: + { + PhDeleteLayoutManager(&context->LayoutManager); + PhDeleteGraphState(&context->GraphState); + + if (context->GraphHandle) + DestroyWindow(context->GraphHandle); + + if (context->PanelWindowHandle) + DestroyWindow(context->PanelWindowHandle); + } + break; case WM_SIZE: PhLayoutManagerLayout(&context->LayoutManager); break; @@ -526,16 +531,14 @@ VOID NetAdapterSysInfoInitializing( PH_SYSINFO_SECTION section; PDV_NETADAPTER_SYSINFO_CONTEXT context; - context = (PDV_NETADAPTER_SYSINFO_CONTEXT)PhAllocate(sizeof(DV_NETADAPTER_SYSINFO_CONTEXT)); - memset(context, 0, sizeof(DV_NETADAPTER_SYSINFO_CONTEXT)); - memset(§ion, 0, sizeof(PH_SYSINFO_SECTION)); - + context = PhAllocateZero(sizeof(DV_NETADAPTER_SYSINFO_CONTEXT)); context->AdapterEntry = AdapterEntry; - context->SectionName = PhConcatStrings2(L"NetAdapter ", AdapterEntry->Id.InterfaceGuid->Buffer); - + context->SectionName = PhConcatStrings2(L"NetAdapter ", PhGetStringOrEmpty(AdapterEntry->AdapterId.InterfaceGuid)); + + memset(§ion, 0, sizeof(PH_SYSINFO_SECTION)); section.Context = context; section.Callback = NetAdapterSectionCallback; - section.Name = context->SectionName->sr; + section.Name = PhGetStringRef(context->SectionName); context->SysinfoSection = Pointers->CreateSection(§ion); } \ No newline at end of file diff --git a/plugins/HardwareDevices/netoptions.c b/plugins/HardwareDevices/netoptions.c index 2fe95a8311af..4794cdd33d99 100644 --- a/plugins/HardwareDevices/netoptions.c +++ b/plugins/HardwareDevices/netoptions.c @@ -23,7 +23,6 @@ #define INITGUID #include "devices.h" -#include #include typedef struct _NET_ENUM_ENTRY @@ -109,9 +108,9 @@ VOID NetAdaptersSaveList( PhAppendFormatStringBuilder( &stringBuilder, L"%lu,%I64u,%s,", - entry->Id.InterfaceIndex, // This value is UNSAFE and may change after reboot. - entry->Id.InterfaceLuid.Value, // This value is SAFE and does not change (Vista+). - entry->Id.InterfaceGuid->Buffer + entry->AdapterId.InterfaceIndex, // This value is UNSAFE and will change after reboot. + entry->AdapterId.InterfaceLuid.Value, // This value is SAFE and does not change (Vista+). + entry->AdapterId.InterfaceGuid->Buffer ); } @@ -143,7 +142,7 @@ BOOLEAN FindAdapterEntry( if (!currentEntry) continue; - found = EquivalentNetAdapterId(¤tEntry->Id, Id); + found = EquivalentNetAdapterId(¤tEntry->AdapterId, Id); if (found) { @@ -194,10 +193,10 @@ VOID AddNetworkAdapterToListView( if (!entry) continue; - if (EquivalentNetAdapterId(&entry->Id, &adapterId)) + if (EquivalentNetAdapterId(&entry->AdapterId, &adapterId)) { newId = PhAllocate(sizeof(DV_NETADAPTER_ID)); - CopyNetAdapterId(newId, &entry->Id); + CopyNetAdapterId(newId, &entry->AdapterId); if (entry->UserReference) found = TRUE; @@ -440,7 +439,15 @@ VOID FindNetworkAdapters( adapterEntry->DeviceLuid.Info.IfType = PhQueryRegistryUlong64(keyHandle, L"*IfType"); adapterEntry->DeviceLuid.Info.NetLuidIndex = PhQueryRegistryUlong64(keyHandle, L"NetLuidIndex"); - if (NT_SUCCESS(NetworkAdapterCreateHandle(&deviceHandle, adapterEntry->DeviceInterface))) + if (NT_SUCCESS(PhCreateFileWin32( + &deviceHandle, + PhGetString(adapterEntry->DeviceInterface), + FILE_GENERIC_READ, + FILE_ATTRIBUTE_NORMAL, + FILE_SHARE_READ | FILE_SHARE_WRITE, + FILE_OPEN, + FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT + ))) { PPH_STRING adapterName; @@ -501,7 +508,7 @@ VOID FindNetworkAdapters( for (ULONG i = 0; i < NetworkAdaptersList->Count; i++) { - ULONG index = -1; + ULONG index = ULONG_MAX; BOOLEAN found = FALSE; PDV_NETADAPTER_ENTRY entry = PhReferenceObjectSafe(NetworkAdaptersList->Items[i]); @@ -512,13 +519,13 @@ VOID FindNetworkAdapters( Context->ListViewHandle, index, LVNI_ALL - )) != -1) + )) != ULONG_MAX) { PDV_NETADAPTER_ID param; if (PhGetListViewItemParam(Context->ListViewHandle, index, ¶m)) { - if (EquivalentNetAdapterId(param, &entry->Id)) + if (EquivalentNetAdapterId(param, &entry->AdapterId)) { found = TRUE; } @@ -528,15 +535,26 @@ VOID FindNetworkAdapters( if (!found) { PPH_STRING description; + MIB_IF_ROW2 interfaceRow; - if (description = PhCreateString(L"Unknown network adapter")) + memset(&interfaceRow, 0, sizeof(MIB_IF_ROW2)); + interfaceRow.InterfaceLuid = entry->AdapterId.InterfaceLuid; + interfaceRow.InterfaceIndex = entry->AdapterId.InterfaceIndex; + + // HACK: Try query the description from the interface entry (if it exists). + if (GetIfEntry2(&interfaceRow) == NO_ERROR) + description = PhCreateString(interfaceRow.Description); + else + description = PhCreateString(L"Unknown network adapter"); + + if (description) { AddNetworkAdapterToListView( Context, FALSE, - entry->Id.InterfaceIndex, - entry->Id.InterfaceLuid, - entry->Id.InterfaceGuid, + entry->AdapterId.InterfaceIndex, + entry->AdapterId.InterfaceLuid, + entry->AdapterId.InterfaceGuid, description ); @@ -695,8 +713,7 @@ INT_PTR CALLBACK NetworkAdapterOptionsDlgProc( if (uMsg == WM_INITDIALOG) { - context = (PDV_NETADAPTER_CONTEXT)PhAllocate(sizeof(DV_NETADAPTER_CONTEXT)); - memset(context, 0, sizeof(DV_NETADAPTER_CONTEXT)); + context = PhAllocateZero(sizeof(DV_NETADAPTER_CONTEXT)); PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context); } @@ -829,7 +846,7 @@ INT_PTR CALLBACK NetworkAdapterOptionsDlgProc( if (param = PhGetSelectedListViewItemParam(context->ListViewHandle)) { - if (deviceInstance = FindNetworkDeviceInstance(param->Id.InterfaceGuid)) + if (deviceInstance = FindNetworkDeviceInstance(param->AdapterId.InterfaceGuid)) { ShowDeviceMenu(hwndDlg, deviceInstance); PhDereferenceObject(deviceInstance); From eec9ff3f1442782ea19a4db9787affb71d1d940d Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 27 Jun 2018 17:12:54 +1000 Subject: [PATCH 1052/2058] ExtendedTools: Aggregate collapsed process GPU/Disk/Network columns --- plugins/ExtendedTools/exttools.h | 4 +- plugins/ExtendedTools/gpumon.c | 14 +- plugins/ExtendedTools/gpusys.c | 20 +-- plugins/ExtendedTools/treeext.c | 227 ++++++++++++++++++++++++++----- 4 files changed, 215 insertions(+), 50 deletions(-) diff --git a/plugins/ExtendedTools/exttools.h b/plugins/ExtendedTools/exttools.h index d3646318c0b2..deed500a2461 100644 --- a/plugins/ExtendedTools/exttools.h +++ b/plugins/ExtendedTools/exttools.h @@ -397,8 +397,8 @@ extern PPH_CIRCULAR_BUFFER_FLOAT EtGpuNodesHistory; extern ULONG64 EtGpuDedicatedUsage; extern ULONG64 EtGpuSharedUsage; -extern PH_CIRCULAR_BUFFER_ULONG EtGpuDedicatedHistory; -extern PH_CIRCULAR_BUFFER_ULONG EtGpuSharedHistory; +extern PH_CIRCULAR_BUFFER_ULONG64 EtGpuDedicatedHistory; +extern PH_CIRCULAR_BUFFER_ULONG64 EtGpuSharedHistory; VOID EtGpuMonitorInitialization( VOID diff --git a/plugins/ExtendedTools/gpumon.c b/plugins/ExtendedTools/gpumon.c index 04dc0cfaccb0..d6b686e172e1 100644 --- a/plugins/ExtendedTools/gpumon.c +++ b/plugins/ExtendedTools/gpumon.c @@ -50,8 +50,8 @@ ULONG64 EtGpuDedicatedLimit = 0; ULONG64 EtGpuDedicatedUsage = 0; ULONG64 EtGpuSharedLimit = 0; ULONG64 EtGpuSharedUsage = 0; -PH_CIRCULAR_BUFFER_ULONG EtGpuDedicatedHistory; -PH_CIRCULAR_BUFFER_ULONG EtGpuSharedHistory; +PH_CIRCULAR_BUFFER_ULONG64 EtGpuDedicatedHistory; +PH_CIRCULAR_BUFFER_ULONG64 EtGpuSharedHistory; VOID EtGpuMonitorInitialization( VOID @@ -74,8 +74,8 @@ VOID EtGpuMonitorInitialization( PhInitializeCircularBuffer_FLOAT(&EtGpuNodeHistory, sampleCount); PhInitializeCircularBuffer_ULONG(&EtMaxGpuNodeHistory, sampleCount); PhInitializeCircularBuffer_FLOAT(&EtMaxGpuNodeUsageHistory, sampleCount); - PhInitializeCircularBuffer_ULONG(&EtGpuDedicatedHistory, sampleCount); - PhInitializeCircularBuffer_ULONG(&EtGpuSharedHistory, sampleCount); + PhInitializeCircularBuffer_ULONG64(&EtGpuDedicatedHistory, sampleCount); + PhInitializeCircularBuffer_ULONG64(&EtGpuSharedHistory, sampleCount); EtGpuNodesTotalRunningTimeDelta = PhAllocateZero(sizeof(PH_UINT64_DELTA) * EtGpuTotalNodeCount); EtGpuNodesHistory = PhAllocate(sizeof(PH_CIRCULAR_BUFFER_FLOAT) * EtGpuTotalNodeCount); @@ -409,7 +409,7 @@ BOOLEAN EtQueryDeviceProperties( } if (Description) - *Description = EtpQueryDeviceProperty(deviceInstanceHandle, &DEVPKEY_Device_DeviceDesc); // DEVPKEY_NAME + *Description = EtpQueryDeviceProperty(deviceInstanceHandle, &DEVPKEY_Device_DeviceDesc); if (DriverDate) *DriverDate = EtpQueryDeviceProperty(deviceInstanceHandle, &DEVPKEY_Device_DriverDate); if (DriverVersion) @@ -985,8 +985,8 @@ VOID NTAPI EtGpuProcessesUpdatedCallback( if (runCount != 0) { PhAddItemCircularBuffer_FLOAT(&EtGpuNodeHistory, EtGpuNodeUsage); - PhAddItemCircularBuffer_ULONG(&EtGpuDedicatedHistory, (ULONG)(EtGpuDedicatedUsage / PAGE_SIZE)); - PhAddItemCircularBuffer_ULONG(&EtGpuSharedHistory, (ULONG)(EtGpuSharedUsage / PAGE_SIZE)); + PhAddItemCircularBuffer_ULONG64(&EtGpuDedicatedHistory, EtGpuDedicatedUsage); + PhAddItemCircularBuffer_ULONG64(&EtGpuSharedHistory, EtGpuSharedUsage); if (elapsedTime != 0) { diff --git a/plugins/ExtendedTools/gpusys.c b/plugins/ExtendedTools/gpusys.c index fc9652acd4a1..290d699bc766 100644 --- a/plugins/ExtendedTools/gpusys.c +++ b/plugins/ExtendedTools/gpusys.c @@ -514,7 +514,7 @@ VOID EtpNotifyDedicatedGraph( { for (i = 0; i < drawInfo->LineDataCount; i++) { - DedicatedGraphState.Data1[i] = (FLOAT)PhGetItemCircularBuffer_ULONG(&EtGpuDedicatedHistory, i); + DedicatedGraphState.Data1[i] = (FLOAT)PhGetItemCircularBuffer_ULONG64(&EtGpuDedicatedHistory, i); } if (EtGpuDedicatedLimit != 0) @@ -522,7 +522,7 @@ VOID EtpNotifyDedicatedGraph( // Scale the data. PhDivideSinglesBySingle( DedicatedGraphState.Data1, - (FLOAT)EtGpuDedicatedLimit / PAGE_SIZE, + (FLOAT)EtGpuDedicatedLimit, drawInfo->LineDataCount ); } @@ -539,13 +539,13 @@ VOID EtpNotifyDedicatedGraph( { if (DedicatedGraphState.TooltipIndex != getTooltipText->Index) { - ULONG usedPages; + ULONG64 usedPages; - usedPages = PhGetItemCircularBuffer_ULONG(&EtGpuDedicatedHistory, getTooltipText->Index); + usedPages = PhGetItemCircularBuffer_ULONG64(&EtGpuDedicatedHistory, getTooltipText->Index); PhMoveReference(&DedicatedGraphState.TooltipText, PhFormatString( L"Dedicated Memory: %s\n%s", - PhaFormatSize(UInt32x32To64(usedPages, PAGE_SIZE), ULONG_MAX)->Buffer, + PhaFormatSize(usedPages, ULONG_MAX)->Buffer, ((PPH_STRING)PH_AUTO(PhGetStatisticsTimeString(NULL, getTooltipText->Index)))->Buffer )); } @@ -582,7 +582,7 @@ VOID EtpNotifySharedGraph( { for (i = 0; i < drawInfo->LineDataCount; i++) { - SharedGraphState.Data1[i] = (FLOAT)PhGetItemCircularBuffer_ULONG(&EtGpuSharedHistory, i); + SharedGraphState.Data1[i] = (FLOAT)PhGetItemCircularBuffer_ULONG64(&EtGpuSharedHistory, i); } if (EtGpuSharedLimit != 0) @@ -590,7 +590,7 @@ VOID EtpNotifySharedGraph( // Scale the data. PhDivideSinglesBySingle( SharedGraphState.Data1, - (FLOAT)EtGpuSharedLimit / PAGE_SIZE, + (FLOAT)EtGpuSharedLimit, drawInfo->LineDataCount ); } @@ -607,13 +607,13 @@ VOID EtpNotifySharedGraph( { if (SharedGraphState.TooltipIndex != getTooltipText->Index) { - ULONG usedPages; + ULONG64 usedPages; - usedPages = PhGetItemCircularBuffer_ULONG(&EtGpuSharedHistory, getTooltipText->Index); + usedPages = PhGetItemCircularBuffer_ULONG64(&EtGpuSharedHistory, getTooltipText->Index); PhMoveReference(&SharedGraphState.TooltipText, PhFormatString( L"Shared Memory: %s\n%s", - PhaFormatSize(UInt32x32To64(usedPages, PAGE_SIZE), ULONG_MAX)->Buffer, + PhaFormatSize(usedPages, ULONG_MAX)->Buffer, ((PPH_STRING)PH_AUTO(PhGetStatisticsTimeString(NULL, getTooltipText->Index)))->Buffer )); } diff --git a/plugins/ExtendedTools/treeext.c b/plugins/ExtendedTools/treeext.c index cad709645797..345019c24c8f 100644 --- a/plugins/ExtendedTools/treeext.c +++ b/plugins/ExtendedTools/treeext.c @@ -51,6 +51,20 @@ typedef struct _COLUMN_INFO BOOLEAN SortDescending; } COLUMN_INFO, *PCOLUMN_INFO; +typedef enum _PHP_AGGREGATE_TYPE +{ + AggregateTypeFloat, + AggregateTypeInt32, + AggregateTypeInt64, + AggregateTypeIntPtr +} PHP_AGGREGATE_TYPE; + +typedef enum _PHP_AGGREGATE_LOCATION +{ + AggregateLocationProcessNode, + AggregateLocationProcessItem +} PHP_AGGREGATE_LOCATION; + static ULONG ProcessTreeListSortColumn; static PH_SORT_ORDER ProcessTreeListSortOrder; @@ -139,21 +153,90 @@ VOID EtProcessTreeNewInitializing( PhPluginEnableTreeNewNotify(PluginInstance, treeNewInfo->CmData); } -FLOAT EtpCalculateInclusiveGpuUsage( - _In_ PPH_PROCESS_NODE ProcessNode +// Copied from ProcessHacker\proctree.c +FORCEINLINE PVOID PhpFieldForAggregate( + _In_ PPH_PROCESS_NODE ProcessNode, + _In_ PHP_AGGREGATE_LOCATION Location, + _In_ SIZE_T FieldOffset + ) +{ + PVOID object; + + switch (Location) + { + case AggregateLocationProcessNode: + object = PhPluginGetObjectExtension(PluginInstance, ProcessNode->ProcessItem, EmProcessNodeType); + break; + case AggregateLocationProcessItem: + object = PhPluginGetObjectExtension(PluginInstance, ProcessNode->ProcessItem, EmProcessItemType); + break; + default: + PhRaiseStatus(STATUS_INVALID_PARAMETER); + } + + return PTR_ADD_OFFSET(object, FieldOffset); +} + +// Copied from ProcessHacker\proctree.c +FORCEINLINE VOID PhpAccumulateField( + _Inout_ PVOID Accumulator, + _In_ PVOID Value, + _In_ PHP_AGGREGATE_TYPE Type + ) +{ + switch (Type) + { + case AggregateTypeFloat: + *(PFLOAT)Accumulator += *(PFLOAT)Value; + break; + case AggregateTypeInt32: + *(PULONG)Accumulator += *(PULONG)Value; + break; + case AggregateTypeInt64: + *(PULONG64)Accumulator += *(PULONG64)Value; + break; + case AggregateTypeIntPtr: + *(PULONG_PTR)Accumulator += *(PULONG_PTR)Value; + break; + } +} + +// Copied from ProcessHacker\proctree.c +static VOID PhpAggregateField( + _In_ PPH_PROCESS_NODE ProcessNode, + _In_ PHP_AGGREGATE_TYPE Type, + _In_ PHP_AGGREGATE_LOCATION Location, + _In_ SIZE_T FieldOffset, + _Inout_ PVOID AggregatedValue ) { - FLOAT gpuUsage; ULONG i; - gpuUsage = EtGetProcessBlock(ProcessNode->ProcessItem)->GpuNodeUsage; + PhpAccumulateField(AggregatedValue, PhpFieldForAggregate(ProcessNode, Location, FieldOffset), Type); for (i = 0; i < ProcessNode->Children->Count; i++) { - gpuUsage += EtpCalculateInclusiveGpuUsage(ProcessNode->Children->Items[i]); + PhpAggregateField(ProcessNode->Children->Items[i], Type, Location, FieldOffset, AggregatedValue); } +} - return gpuUsage; +// Copied from ProcessHacker\proctree.c +static VOID PhpAggregateFieldIfNeeded( + _In_ PPH_PROCESS_NODE ProcessNode, + _In_ PHP_AGGREGATE_TYPE Type, + _In_ PHP_AGGREGATE_LOCATION Location, + _In_ SIZE_T FieldOffset, + _Inout_ PVOID AggregatedValue + ) +{ + if (!PhGetIntegerSetting(L"PropagateCpuUsage") || ProcessNode->Node.Expanded || ProcessTreeListSortOrder != NoSortOrder) + { + PhpAccumulateField(AggregatedValue, PhpFieldForAggregate(ProcessNode, Location, FieldOffset), Type); + } + else + { + PhpAggregateField(ProcessNode, Type, Location, FieldOffset, AggregatedValue); + } } VOID EtProcessTreeNewMessage( @@ -202,8 +285,15 @@ VOID EtProcessTreeNewMessage( text = PhFormatSize(block->DiskWriteRaw, -1); break; case ETPRTNC_DISKTOTALBYTES: - if (block->DiskReadRaw + block->DiskWriteRaw != 0) - text = PhFormatSize(block->DiskReadRaw + block->DiskWriteRaw, -1); + { + ULONG64 number = 0; + + PhpAggregateFieldIfNeeded(processNode, AggregateTypeInt64, AggregateLocationProcessItem, FIELD_OFFSET(ET_PROCESS_BLOCK, DiskReadRaw), &number); + PhpAggregateFieldIfNeeded(processNode, AggregateTypeInt64, AggregateLocationProcessItem, FIELD_OFFSET(ET_PROCESS_BLOCK, DiskWriteRaw), &number); + + if (number != 0) + text = PhFormatSize(number, ULONG_MAX); + } break; case ETPRTNC_DISKREADSDELTA: if (block->DiskReadDelta.Delta != 0) @@ -222,8 +312,15 @@ VOID EtProcessTreeNewMessage( text = PhFormatSize(block->DiskWriteRawDelta.Delta, -1); break; case ETPRTNC_DISKTOTALBYTESDELTA: - if (block->DiskReadRawDelta.Delta + block->DiskWriteRawDelta.Delta != 0) - text = PhFormatSize(block->DiskReadRawDelta.Delta + block->DiskWriteRawDelta.Delta, -1); + { + ULONG64 number = 0; + + PhpAggregateFieldIfNeeded(processNode, AggregateTypeInt64, AggregateLocationProcessItem, FIELD_OFFSET(ET_PROCESS_BLOCK, DiskReadRawDelta), &number); + PhpAggregateFieldIfNeeded(processNode, AggregateTypeInt64, AggregateLocationProcessItem, FIELD_OFFSET(ET_PROCESS_BLOCK, DiskWriteRawDelta), &number); + + if (number != 0) + text = PhFormatSize(number, ULONG_MAX); + } break; case ETPRTNC_NETWORKRECEIVES: if (block->NetworkReceiveCount != 0) @@ -242,8 +339,15 @@ VOID EtProcessTreeNewMessage( text = PhFormatSize(block->NetworkSendRaw, -1); break; case ETPRTNC_NETWORKTOTALBYTES: - if (block->NetworkReceiveRaw + block->NetworkSendRaw != 0) - text = PhFormatSize(block->NetworkReceiveRaw + block->NetworkSendRaw, -1); + { + ULONG64 number = 0; + + PhpAggregateFieldIfNeeded(processNode, AggregateTypeInt64, AggregateLocationProcessItem, FIELD_OFFSET(ET_PROCESS_BLOCK, NetworkReceiveRaw), &number); + PhpAggregateFieldIfNeeded(processNode, AggregateTypeInt64, AggregateLocationProcessItem, FIELD_OFFSET(ET_PROCESS_BLOCK, NetworkSendRaw), &number); + + if (number != 0) + text = PhFormatSize(number, ULONG_MAX); + } break; case ETPRTNC_NETWORKRECEIVESDELTA: if (block->NetworkReceiveDelta.Delta != 0) @@ -262,8 +366,15 @@ VOID EtProcessTreeNewMessage( text = PhFormatSize(block->NetworkSendRawDelta.Delta, -1); break; case ETPRTNC_NETWORKTOTALBYTESDELTA: - if (block->NetworkReceiveRawDelta.Delta + block->NetworkSendRawDelta.Delta != 0) - text = PhFormatSize(block->NetworkReceiveRawDelta.Delta + block->NetworkSendRawDelta.Delta, -1); + { + ULONG64 number = 0; + + PhpAggregateFieldIfNeeded(processNode, AggregateTypeInt64, AggregateLocationProcessItem, FIELD_OFFSET(ET_PROCESS_BLOCK, NetworkReceiveRawDelta.Delta), &number); + PhpAggregateFieldIfNeeded(processNode, AggregateTypeInt64, AggregateLocationProcessItem, FIELD_OFFSET(ET_PROCESS_BLOCK, NetworkSendRawDelta.Delta), &number); + + if (number != 0) + text = PhFormatSize(number, ULONG_MAX); + } break; case ETPRTNC_HARDFAULTS: text = PhFormatUInt64(block->HardFaultsDelta.Value, TRUE); @@ -277,16 +388,16 @@ VOID EtProcessTreeNewMessage( break; case ETPRTNC_GPU: { - FLOAT gpuUsage; + FLOAT gpuUsage = 0; - if (!PhGetIntegerSetting(L"PropagateCpuUsage") || processNode->Node.Expanded || ProcessTreeListSortOrder != NoSortOrder) - { - gpuUsage = block->GpuNodeUsage * 100; - } - else - { - gpuUsage = EtpCalculateInclusiveGpuUsage(processNode) * 100; - } + PhpAggregateFieldIfNeeded( + processNode, + AggregateTypeFloat, + AggregateLocationProcessItem, + FIELD_OFFSET(ET_PROCESS_BLOCK, GpuNodeUsage), + &gpuUsage + ); + gpuUsage *= 100; if (gpuUsage >= 0.01) { @@ -298,12 +409,36 @@ VOID EtProcessTreeNewMessage( } break; case ETPRTNC_GPUDEDICATEDBYTES: - if (block->GpuDedicatedUsage != 0) - text = PhFormatSize(block->GpuDedicatedUsage, -1); + { + ULONG64 gpuDedicatedUsage = 0; + + PhpAggregateFieldIfNeeded( + processNode, + AggregateTypeInt64, + AggregateLocationProcessItem, + FIELD_OFFSET(ET_PROCESS_BLOCK, GpuDedicatedUsage), + &gpuDedicatedUsage + ); + + if (gpuDedicatedUsage != 0) + text = PhFormatSize(gpuDedicatedUsage, ULONG_MAX); + } break; case ETPRTNC_GPUSHAREDBYTES: - if (block->GpuSharedUsage != 0) - text = PhFormatSize(block->GpuSharedUsage, -1); + { + ULONG64 gpuSharedUsage = 0; + + PhpAggregateFieldIfNeeded( + processNode, + AggregateTypeInt64, + AggregateLocationProcessItem, + FIELD_OFFSET(ET_PROCESS_BLOCK, GpuSharedUsage), + &gpuSharedUsage + ); + + if (gpuSharedUsage != 0) + text = PhFormatSize(gpuSharedUsage, ULONG_MAX); + } break; case ETPRTNC_DISKREADRATE: if (block->DiskReadRawDelta.Delta != 0) @@ -314,8 +449,15 @@ VOID EtProcessTreeNewMessage( EtFormatRate(block->DiskWriteRawDelta.Delta, &text, NULL); break; case ETPRTNC_DISKTOTALRATE: - if (block->DiskReadRawDelta.Delta + block->DiskWriteRawDelta.Delta != 0) - EtFormatRate(block->DiskReadRawDelta.Delta + block->DiskWriteRawDelta.Delta, &text, NULL); + { + ULONG64 number = 0; + + PhpAggregateFieldIfNeeded(processNode, AggregateTypeInt64, AggregateLocationProcessItem, FIELD_OFFSET(ET_PROCESS_BLOCK, DiskReadRawDelta.Delta), &number); + PhpAggregateFieldIfNeeded(processNode, AggregateTypeInt64, AggregateLocationProcessItem, FIELD_OFFSET(ET_PROCESS_BLOCK, DiskWriteRawDelta.Delta), &number); + + if (number != 0) + EtFormatRate(number, &text, NULL); + } break; case ETPRTNC_NETWORKRECEIVERATE: if (block->NetworkReceiveRawDelta.Delta != 0) @@ -326,8 +468,15 @@ VOID EtProcessTreeNewMessage( EtFormatRate(block->NetworkSendRawDelta.Delta, &text, NULL); break; case ETPRTNC_NETWORKTOTALRATE: - if (block->NetworkReceiveRawDelta.Delta + block->NetworkSendRawDelta.Delta != 0) - EtFormatRate(block->NetworkReceiveRawDelta.Delta + block->NetworkSendRawDelta.Delta, &text, NULL); + { + ULONG64 number = 0; + + PhpAggregateFieldIfNeeded(processNode, AggregateTypeInt64, AggregateLocationProcessItem, FIELD_OFFSET(ET_PROCESS_BLOCK, NetworkReceiveRawDelta.Delta), &number); + PhpAggregateFieldIfNeeded(processNode, AggregateTypeInt64, AggregateLocationProcessItem, FIELD_OFFSET(ET_PROCESS_BLOCK, NetworkSendRawDelta.Delta), &number); + + if (number != 0) + EtFormatRate(number, &text, NULL); + } break; } @@ -352,7 +501,20 @@ VOID EtProcessTreeNewMessage( block = EtGetProcessBlock(processNode->ProcessItem); if (PhGetIntegerSetting(L"PropagateCpuUsage")) + { + block->TextCacheValid[ETPRTNC_DISKTOTALBYTES] = FALSE; + block->TextCacheValid[ETPRTNC_NETWORKTOTALBYTES] = FALSE; + + block->TextCacheValid[ETPRTNC_DISKTOTALBYTESDELTA] = FALSE; + block->TextCacheValid[ETPRTNC_NETWORKTOTALBYTESDELTA] = FALSE; + block->TextCacheValid[ETPRTNC_GPU] = FALSE; + block->TextCacheValid[ETPRTNC_GPUDEDICATEDBYTES] = FALSE; + block->TextCacheValid[ETPRTNC_GPUSHAREDBYTES] = FALSE; + + block->TextCacheValid[ETPRTNC_DISKTOTALRATE] = FALSE; + block->TextCacheValid[ETPRTNC_NETWORKTOTALRATE] = FALSE; + } } } @@ -748,6 +910,9 @@ ET_FIREWALL_STATUS EtQueryFirewallStatus( if (!PhIsNullIpAddress(&NetworkItem->LocalEndpoint.Address)) localAddressBStr = SysAllocString(NetworkItem->LocalAddressString); + memset(&allowed, 0, sizeof(VARIANT)); // VariantInit + memset(&restricted, 0, sizeof(VARIANT)); // VariantInit + if (SUCCEEDED(INetFwMgr_IsPortAllowed( manager, imageFileNameBStr, From 2b2204945bc6a326f16bd8b3ca9c39559ac6e6e4 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 27 Jun 2018 17:46:37 +1000 Subject: [PATCH 1053/2058] Fix sleep regression --- ProcessHacker/actions.c | 3 ++- ProcessHacker/runas.c | 3 ++- phlib/include/phbasesup.h | 13 ++++++++++--- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/ProcessHacker/actions.c b/ProcessHacker/actions.c index cb8afdf0d8a6..7dd823dfafe4 100644 --- a/ProcessHacker/actions.c +++ b/ProcessHacker/actions.c @@ -458,7 +458,8 @@ BOOLEAN PhUiConnectToPhSvcEx( if (NT_SUCCESS(status)) break; - PhDelayExecution(50); + PhDelayExecution(5 * 1000); + } while (--attempts != 0); // Increment the reference count even if we failed. diff --git a/ProcessHacker/runas.c b/ProcessHacker/runas.c index 128be1be13c8..48c72951137f 100644 --- a/ProcessHacker/runas.c +++ b/ProcessHacker/runas.c @@ -1276,7 +1276,8 @@ NTSTATUS PhExecuteRunAsCommand( if (NT_SUCCESS(status)) break; - PhDelayExecution(50); + PhDelayExecution(5 * 1000); + } while (--attempts != 0); PhDereferenceObject(portName); diff --git a/phlib/include/phbasesup.h b/phlib/include/phbasesup.h index 4be0557be0bd..facc021ce6d0 100644 --- a/phlib/include/phbasesup.h +++ b/phlib/include/phbasesup.h @@ -170,11 +170,18 @@ PhDelayExecution( _In_ LONGLONG Interval ) { - LARGE_INTEGER interval; + if (Interval == INFINITE) + { + return NtDelayExecution(FALSE, NULL) + } + else + { + LARGE_INTEGER interval; - interval.QuadPart = -Interval; + interval.QuadPart = Interval * -10000LL; - return NtDelayExecution(FALSE, &interval); + return NtDelayExecution(FALSE, &interval); + } } // Heap From a2f52f68a989002b06556238f9a05bf20df20931 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 27 Jun 2018 17:47:11 +1000 Subject: [PATCH 1054/2058] Fix typo --- phlib/include/phbasesup.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phlib/include/phbasesup.h b/phlib/include/phbasesup.h index facc021ce6d0..c52802b63c02 100644 --- a/phlib/include/phbasesup.h +++ b/phlib/include/phbasesup.h @@ -172,7 +172,7 @@ PhDelayExecution( { if (Interval == INFINITE) { - return NtDelayExecution(FALSE, NULL) + return NtDelayExecution(FALSE, NULL); } else { From baca10d58e42904532258a9739585b5af42393cc Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 27 Jun 2018 18:16:28 +1000 Subject: [PATCH 1055/2058] Fix PhSvc UI timeouts --- ProcessHacker/actions.c | 4 ++-- ProcessHacker/anawait.c | 2 +- ProcessHacker/runas.c | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/ProcessHacker/actions.c b/ProcessHacker/actions.c index 7dd823dfafe4..ef81dd378eab 100644 --- a/ProcessHacker/actions.c +++ b/ProcessHacker/actions.c @@ -447,7 +447,7 @@ BOOLEAN PhUiConnectToPhSvcEx( if (started) { - ULONG attempts = 10; + ULONG attempts = 50; // Try to connect several times because the server may take // a while to initialize. @@ -458,7 +458,7 @@ BOOLEAN PhUiConnectToPhSvcEx( if (NT_SUCCESS(status)) break; - PhDelayExecution(5 * 1000); + PhDelayExecution(100); } while (--attempts != 0); diff --git a/ProcessHacker/anawait.c b/ProcessHacker/anawait.c index 0a18c6653c8b..f29fb8589f01 100644 --- a/ProcessHacker/anawait.c +++ b/ProcessHacker/anawait.c @@ -650,7 +650,7 @@ static BOOLEAN PhpWaitUntilThreadIsWaiting( if (!NT_SUCCESS(PhGetThreadBasicInformation(ThreadHandle, &basicInfo))) return FALSE; - for (attempts = 0; attempts < 5; attempts++) + for (attempts = 0; attempts < 20; attempts++) { PVOID processes; PSYSTEM_PROCESS_INFORMATION processInfo; diff --git a/ProcessHacker/runas.c b/ProcessHacker/runas.c index 48c72951137f..53ff6c85996c 100644 --- a/ProcessHacker/runas.c +++ b/ProcessHacker/runas.c @@ -1265,7 +1265,7 @@ NTSTATUS PhExecuteRunAsCommand( portName = PhConcatStrings2(L"\\BaseNamedObjects\\", Parameters->ServiceName); PhStringRefToUnicodeString(&portName->sr, &portNameUs); - attempts = 10; + attempts = 50; // Try to connect several times because the server may take // a while to initialize. @@ -1276,7 +1276,7 @@ NTSTATUS PhExecuteRunAsCommand( if (NT_SUCCESS(status)) break; - PhDelayExecution(5 * 1000); + PhDelayExecution(100); } while (--attempts != 0); From aeb69549906e65edbfedfb33d5e389bc033b3e94 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 28 Jun 2018 09:48:48 +1000 Subject: [PATCH 1056/2058] PHNT: Fix macro usage, Update headers --- ProcessHacker/memsrch.c | 2 +- phlib/include/phbasesup.h | 2 +- phlib/include/symprvp.h | 2 +- phlib/lsasup.c | 2 +- phlib/mapexlf.c | 4 +-- phlib/native.c | 55 +++++++++++++++++++-------------------- phnt/include/ntdbg.h | 20 ++++++++++++++ phnt/include/ntexapi.h | 20 ++++++++++++++ phnt/include/ntgdi.h | 20 ++++++++++++++ phnt/include/ntioapi.h | 20 ++++++++++++++ phnt/include/ntldr.h | 20 ++++++++++++++ phnt/include/ntnls.h | 20 ++++++++++++++ phnt/include/ntrtl.h | 20 ++++++++++++++ phnt/include/ntseapi.h | 20 ++++++++++++++ 14 files changed, 193 insertions(+), 34 deletions(-) diff --git a/ProcessHacker/memsrch.c b/ProcessHacker/memsrch.c index 9b39bc3dab8d..bd0e9258ec96 100644 --- a/ProcessHacker/memsrch.c +++ b/ProcessHacker/memsrch.c @@ -459,7 +459,7 @@ VOID PhSearchMemoryString( if (result->Display.Buffer = PhAllocateForMemorySearch(displayLength + sizeof(WCHAR))) { memcpy(result->Display.Buffer, displayBuffer, displayLength); - result->Display.Buffer[displayLength / sizeof(WCHAR)] = 0; + result->Display.Buffer[displayLength / sizeof(WCHAR)] = UNICODE_NULL; result->Display.Length = displayLength; } diff --git a/phlib/include/phbasesup.h b/phlib/include/phbasesup.h index c52802b63c02..7abab1f53e8c 100644 --- a/phlib/include/phbasesup.h +++ b/phlib/include/phbasesup.h @@ -178,7 +178,7 @@ PhDelayExecution( { LARGE_INTEGER interval; - interval.QuadPart = Interval * -10000LL; + interval.QuadPart = Interval * -PH_TIMEOUT_MS; return NtDelayExecution(FALSE, &interval); } diff --git a/phlib/include/symprvp.h b/phlib/include/symprvp.h index 322a96126c91..84fbc5528305 100644 --- a/phlib/include/symprvp.h +++ b/phlib/include/symprvp.h @@ -61,7 +61,7 @@ typedef BOOL (WINAPI *_SymGetLineFromAddrW64)( typedef ULONG64 (WINAPI *_SymLoadModuleExW)( _In_ HANDLE hProcess, - _In_ HANDLE hFile, + _In_opt_ HANDLE hFile, _In_ PCWSTR ImageName, _In_ PCWSTR ModuleName, _In_ ULONG64 BaseOfDll, diff --git a/phlib/lsasup.c b/phlib/lsasup.c index 3b329e1ba6d6..f150f2657dd1 100644 --- a/phlib/lsasup.c +++ b/phlib/lsasup.c @@ -472,7 +472,7 @@ PPH_STRING PhSidToStringSid( ))) { string->Length = us.Length; - string->Buffer[us.Length / sizeof(WCHAR)] = 0; + string->Buffer[us.Length / sizeof(WCHAR)] = UNICODE_NULL; return string; } diff --git a/phlib/mapexlf.c b/phlib/mapexlf.c index 59a3c5d63de9..c619bfc709c5 100644 --- a/phlib/mapexlf.c +++ b/phlib/mapexlf.c @@ -402,8 +402,8 @@ BOOLEAN PhGetMappedWslImageSymbols( entry = PTR_ADD_OFFSET(MappedWslImage->Header, section->sh_offset); stringTable = PhGetMappedWslImageSectionData(MappedWslImage, NULL, section->sh_link); - // NOTE: Some entries include the version in the symbol name (e.g. NAME@VERSION) - // instead of using a version record entry from SHT_SUNW_versym -dmex + // NOTE: SHT_DYNSYM entries include the version in the symbol name (e.g. printf@GLIBC_2.2.5) + // instead of using a version record entry from the SHT_SUNW_versym section -dmex versionTable = PhGetMappedWslImageSectionDataByType(MappedWslImage, SHT_SUNW_versym); versionRecords = PhpParseMappedWslImageVersionRecords(MappedWslImage, stringTable); diff --git a/phlib/native.c b/phlib/native.c index 10f57c3b8d37..781623374e79 100644 --- a/phlib/native.c +++ b/phlib/native.c @@ -1100,10 +1100,9 @@ NTSTATUS PhGetProcessMappedFileName( ) { NTSTATUS status; - PVOID buffer; SIZE_T bufferSize; SIZE_T returnLength; - PUNICODE_STRING unicodeString; + PUNICODE_STRING buffer; bufferSize = 0x100; buffer = PhAllocate(bufferSize); @@ -1139,8 +1138,7 @@ NTSTATUS PhGetProcessMappedFileName( return status; } - unicodeString = (PUNICODE_STRING)buffer; - *FileName = PhCreateStringFromUnicodeString(unicodeString); + *FileName = PhCreateStringFromUnicodeString(buffer); PhFree(buffer); return status; @@ -2980,7 +2978,7 @@ NTSTATUS PhpUnloadDriver( // Use a bogus name. RtlInitUnicodeString(&valueName, L"ImagePath"); - NtSetValueKey(serviceKeyHandle, &valueName, 0, REG_SZ, imagePath.Buffer, imagePath.Length + 2); + NtSetValueKey(serviceKeyHandle, &valueName, 0, REG_SZ, imagePath.Buffer, imagePath.Length + sizeof(WCHAR)); } status = NtUnloadDriver(&fullServiceKeyNameUs); @@ -3203,8 +3201,8 @@ BOOLEAN NTAPI PhpEnumProcessModulesCallback( if (indexOfLastBackslash != -1) { - Entry->BaseDllName.Buffer = Entry->FullDllName.Buffer + indexOfLastBackslash + 1; - Entry->BaseDllName.Length = Entry->FullDllName.Length - (USHORT)indexOfLastBackslash * 2 - 2; + Entry->BaseDllName.Buffer = PTR_ADD_OFFSET(Entry->FullDllName.Buffer, PTR_ADD_OFFSET(indexOfLastBackslash * sizeof(WCHAR), sizeof(WCHAR))); + Entry->BaseDllName.Length = Entry->FullDllName.Length - (USHORT)indexOfLastBackslash * sizeof(WCHAR) - sizeof(WCHAR); Entry->BaseDllName.MaximumLength = Entry->BaseDllName.Length; } else @@ -3217,7 +3215,7 @@ BOOLEAN NTAPI PhpEnumProcessModulesCallback( // Read the full DLL name string and add a null terminator. fullDllNameOriginal = Entry->FullDllName.Buffer; - fullDllNameBuffer = PhAllocate(Entry->FullDllName.Length + 2); + fullDllNameBuffer = PhAllocate(Entry->FullDllName.Length + sizeof(WCHAR)); Entry->FullDllName.Buffer = fullDllNameBuffer; if (NT_SUCCESS(status = NtReadVirtualMemory( @@ -3228,11 +3226,11 @@ BOOLEAN NTAPI PhpEnumProcessModulesCallback( NULL ))) { - fullDllNameBuffer[Entry->FullDllName.Length / sizeof(WCHAR)] = 0; + fullDllNameBuffer[Entry->FullDllName.Length / sizeof(WCHAR)] = UNICODE_NULL; } else { - fullDllNameBuffer[0] = 0; + fullDllNameBuffer[0] = UNICODE_NULL; Entry->FullDllName.Length = 0; } @@ -3242,20 +3240,19 @@ BOOLEAN NTAPI PhpEnumProcessModulesCallback( if ( NT_SUCCESS(status) && (ULONG_PTR)baseDllNameOriginal >= (ULONG_PTR)fullDllNameOriginal && - (ULONG_PTR)baseDllNameOriginal + Entry->BaseDllName.Length >= (ULONG_PTR)baseDllNameOriginal && - (ULONG_PTR)baseDllNameOriginal + Entry->BaseDllName.Length <= (ULONG_PTR)fullDllNameOriginal + Entry->FullDllName.Length + (ULONG_PTR)PTR_ADD_OFFSET(baseDllNameOriginal, Entry->BaseDllName.Length) >= (ULONG_PTR)baseDllNameOriginal && + (ULONG_PTR)PTR_ADD_OFFSET(baseDllNameOriginal, Entry->BaseDllName.Length) <= (ULONG_PTR)PTR_ADD_OFFSET(fullDllNameOriginal, Entry->FullDllName.Length) ) { baseDllNameBuffer = NULL; - Entry->BaseDllName.Buffer = (PWCHAR)((ULONG_PTR)Entry->FullDllName.Buffer + - ((ULONG_PTR)baseDllNameOriginal - (ULONG_PTR)fullDllNameOriginal)); + Entry->BaseDllName.Buffer = PTR_ADD_OFFSET(Entry->FullDllName.Buffer, PTR_SUB_OFFSET(baseDllNameOriginal, fullDllNameOriginal)); } else { // Read the base DLL name string and add a null terminator. - baseDllNameBuffer = PhAllocate(Entry->BaseDllName.Length + 2); + baseDllNameBuffer = PhAllocate(Entry->BaseDllName.Length + sizeof(WCHAR)); Entry->BaseDllName.Buffer = baseDllNameBuffer; if (NT_SUCCESS(NtReadVirtualMemory( @@ -3266,11 +3263,11 @@ BOOLEAN NTAPI PhpEnumProcessModulesCallback( NULL ))) { - baseDllNameBuffer[Entry->BaseDllName.Length / sizeof(WCHAR)] = 0; + baseDllNameBuffer[Entry->BaseDllName.Length / sizeof(WCHAR)] = UNICODE_NULL; } else { - baseDllNameBuffer[0] = 0; + baseDllNameBuffer[0] = UNICODE_NULL; Entry->BaseDllName.Length = 0; } } @@ -3278,7 +3275,9 @@ BOOLEAN NTAPI PhpEnumProcessModulesCallback( if (WindowsVersion >= WINDOWS_8) { - LDR_DDAG_NODE ldrDagNode = { 0 }; + LDR_DDAG_NODE ldrDagNode; + + memset(&ldrDagNode, 0, sizeof(LDR_DDAG_NODE)); if (NT_SUCCESS(NtReadVirtualMemory( ProcessHandle, @@ -3585,8 +3584,8 @@ BOOLEAN NTAPI PhpEnumProcessModules32Callback( if (indexOfLastBackslash != -1) { - nativeEntry.BaseDllName.Buffer = nativeEntry.FullDllName.Buffer + indexOfLastBackslash + 1; - nativeEntry.BaseDllName.Length = nativeEntry.FullDllName.Length - (USHORT)indexOfLastBackslash * 2 - 2; + nativeEntry.BaseDllName.Buffer = PTR_ADD_OFFSET(nativeEntry.FullDllName.Buffer, PTR_ADD_OFFSET(indexOfLastBackslash * sizeof(WCHAR), sizeof(WCHAR))); + nativeEntry.BaseDllName.Length = nativeEntry.FullDllName.Length - (USHORT)indexOfLastBackslash * sizeof(WCHAR) - sizeof(WCHAR); nativeEntry.BaseDllName.MaximumLength = nativeEntry.BaseDllName.Length; } else @@ -3598,7 +3597,7 @@ BOOLEAN NTAPI PhpEnumProcessModules32Callback( { // Read the base DLL name string and add a null terminator. - baseDllNameBuffer = PhAllocate(nativeEntry.BaseDllName.Length + 2); + baseDllNameBuffer = PhAllocate(nativeEntry.BaseDllName.Length + sizeof(WCHAR)); if (NT_SUCCESS(NtReadVirtualMemory( ProcessHandle, @@ -3608,11 +3607,11 @@ BOOLEAN NTAPI PhpEnumProcessModules32Callback( NULL ))) { - baseDllNameBuffer[nativeEntry.BaseDllName.Length / sizeof(WCHAR)] = 0; + baseDllNameBuffer[nativeEntry.BaseDllName.Length / sizeof(WCHAR)] = UNICODE_NULL; } else { - baseDllNameBuffer[0] = 0; + baseDllNameBuffer[0] = UNICODE_NULL; nativeEntry.BaseDllName.Length = 0; } @@ -3620,7 +3619,7 @@ BOOLEAN NTAPI PhpEnumProcessModules32Callback( // Read the full DLL name string and add a null terminator. - fullDllNameBuffer = PhAllocate(nativeEntry.FullDllName.Length + 2); + fullDllNameBuffer = PhAllocate(nativeEntry.FullDllName.Length + sizeof(WCHAR)); if (NT_SUCCESS(NtReadVirtualMemory( ProcessHandle, @@ -3630,7 +3629,7 @@ BOOLEAN NTAPI PhpEnumProcessModules32Callback( NULL ))) { - fullDllNameBuffer[nativeEntry.FullDllName.Length / sizeof(WCHAR)] = 0; + fullDllNameBuffer[nativeEntry.FullDllName.Length / sizeof(WCHAR)] = UNICODE_NULL; if (!(parameters->Flags & PH_ENUM_PROCESS_MODULES_DONT_RESOLVE_WOW64_FS)) { @@ -5341,10 +5340,10 @@ PPH_STRING PhGetFileName( PH_STRINGREF systemRoot; PhGetSystemRoot(&systemRoot); - newFileName = PhCreateStringEx(NULL, systemRoot.Length + 2 + FileName->Length); + newFileName = PhCreateStringEx(NULL, systemRoot.Length + sizeof(WCHAR) + FileName->Length); memcpy(newFileName->Buffer, systemRoot.Buffer, systemRoot.Length); newFileName->Buffer[systemRoot.Length / sizeof(WCHAR)] = OBJ_NAME_PATH_SEPARATOR; - memcpy(PTR_ADD_OFFSET(newFileName->Buffer, systemRoot.Length + 2), FileName->Buffer, FileName->Length); + memcpy(PTR_ADD_OFFSET(newFileName->Buffer, systemRoot.Length + sizeof(WCHAR)), FileName->Buffer, FileName->Length); } else if (FileName->Length != 0 && FileName->Buffer[0] == OBJ_NAME_PATH_SEPARATOR) { @@ -5362,7 +5361,7 @@ PPH_STRING PhGetFileName( // If the file name starts with "\Windows", prepend the system drive. if (PhStartsWithString2(newFileName, L"\\Windows", TRUE)) { - newFileName = PhCreateStringEx(NULL, FileName->Length + 2 * sizeof(WCHAR)); + newFileName = PhCreateStringEx(NULL, FileName->Length + sizeof(WCHAR) * sizeof(WCHAR)); newFileName->Buffer[0] = USER_SHARED_DATA->NtSystemRoot[0]; newFileName->Buffer[1] = ':'; memcpy(&newFileName->Buffer[2], FileName->Buffer, FileName->Length); diff --git a/phnt/include/ntdbg.h b/phnt/include/ntdbg.h index ff1c0601aad0..33228664fb95 100644 --- a/phnt/include/ntdbg.h +++ b/phnt/include/ntdbg.h @@ -1,3 +1,23 @@ +/* + * Process Hacker - + * Debugger support functions + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + #ifndef _NTDBG_H #define _NTDBG_H diff --git a/phnt/include/ntexapi.h b/phnt/include/ntexapi.h index ad830b677966..2ce271561639 100644 --- a/phnt/include/ntexapi.h +++ b/phnt/include/ntexapi.h @@ -1,3 +1,23 @@ +/* + * Process Hacker - + * Executive support library functions + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + #ifndef _NTEXAPI_H #define _NTEXAPI_H diff --git a/phnt/include/ntgdi.h b/phnt/include/ntgdi.h index d7b47cda4a85..5e85bfab3039 100644 --- a/phnt/include/ntgdi.h +++ b/phnt/include/ntgdi.h @@ -1,3 +1,23 @@ +/* + * Process Hacker - + * Graphics device interface support + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + #ifndef _NTGDI_H #define _NTGDI_H diff --git a/phnt/include/ntioapi.h b/phnt/include/ntioapi.h index 7bc7ae41b53a..a4b6471f49de 100644 --- a/phnt/include/ntioapi.h +++ b/phnt/include/ntioapi.h @@ -1,3 +1,23 @@ +/* + * Process Hacker - + * File management support + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + #ifndef _NTIOAPI_H #define _NTIOAPI_H diff --git a/phnt/include/ntldr.h b/phnt/include/ntldr.h index ff43a541e857..d2963786de77 100644 --- a/phnt/include/ntldr.h +++ b/phnt/include/ntldr.h @@ -1,3 +1,23 @@ +/* + * Process Hacker - + * Loader support functions + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + #ifndef _NTLDR_H #define _NTLDR_H diff --git a/phnt/include/ntnls.h b/phnt/include/ntnls.h index c50b5d1ff100..390933a7c077 100644 --- a/phnt/include/ntnls.h +++ b/phnt/include/ntnls.h @@ -1,3 +1,23 @@ +/* + * Process Hacker - + * National Language Support functions + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + #ifndef _NTNLS_H #define _NTNLS_H diff --git a/phnt/include/ntrtl.h b/phnt/include/ntrtl.h index e16a1863a000..e0940837d151 100644 --- a/phnt/include/ntrtl.h +++ b/phnt/include/ntrtl.h @@ -1,3 +1,23 @@ +/* + * Process Hacker - + * RTL support functions + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + #ifndef _NTRTL_H #define _NTRTL_H diff --git a/phnt/include/ntseapi.h b/phnt/include/ntseapi.h index 4d93eb5c91f7..cc0e056ed6ab 100644 --- a/phnt/include/ntseapi.h +++ b/phnt/include/ntseapi.h @@ -1,3 +1,23 @@ +/* + * Process Hacker - + * Authorization functions + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + #ifndef _NTSEAPI_H #define _NTSEAPI_H From c9a4340457f6767f9c671f2bc4eadfa26f1b3b78 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 29 Jun 2018 03:53:24 +1000 Subject: [PATCH 1057/2058] Fix SAL warning --- ProcessHacker/prpghndl.c | 4 ++-- ProcessHacker/prpgmem.c | 4 ++-- ProcessHacker/prpgmod.c | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/ProcessHacker/prpghndl.c b/ProcessHacker/prpghndl.c index 855c069953cb..a28983797cb2 100644 --- a/ProcessHacker/prpghndl.c +++ b/ProcessHacker/prpghndl.c @@ -489,12 +489,12 @@ INT_PTR CALLBACK PhpProcessHandlesDlgProc( if (GET_WM_COMMAND_HWND(wParam, lParam) != handlesContext->SearchboxHandle) break; - newSearchboxText = PhGetWindowText(handlesContext->SearchboxHandle); + newSearchboxText = PH_AUTO(PhGetWindowText(handlesContext->SearchboxHandle)); if (!PhEqualString(handlesContext->SearchboxText, newSearchboxText, FALSE)) { // Cache the current search text for our callback. - PhMoveReference(&handlesContext->SearchboxText, newSearchboxText); + PhSwapReference(&handlesContext->SearchboxText, newSearchboxText); if (!PhIsNullOrEmptyString(handlesContext->SearchboxText)) { diff --git a/ProcessHacker/prpgmem.c b/ProcessHacker/prpgmem.c index 581a302042e9..39d1df21be55 100644 --- a/ProcessHacker/prpgmem.c +++ b/ProcessHacker/prpgmem.c @@ -416,7 +416,7 @@ INT_PTR CALLBACK PhpProcessMemoryDlgProc( if (GET_WM_COMMAND_HWND(wParam, lParam) != memoryContext->SearchboxHandle) break; - newSearchboxText = PhGetWindowText(memoryContext->SearchboxHandle); + newSearchboxText = PH_AUTO(PhGetWindowText(memoryContext->SearchboxHandle)); if (!PhEqualString(memoryContext->SearchboxText, newSearchboxText, FALSE)) { @@ -424,7 +424,7 @@ INT_PTR CALLBACK PhpProcessMemoryDlgProc( memoryContext->UseSearchPointer = PhStringToInteger64(&newSearchboxText->sr, 0, &memoryContext->SearchPointer); // Cache the current search text for our callback. - PhMoveReference(&memoryContext->SearchboxText, newSearchboxText); + PhSwapReference(&memoryContext->SearchboxText, newSearchboxText); // Expand any hidden nodes to make search results visible. PhExpandAllMemoryNodes(&memoryContext->ListContext, TRUE); diff --git a/ProcessHacker/prpgmod.c b/ProcessHacker/prpgmod.c index 0593ee29aa66..e570936d77b4 100644 --- a/ProcessHacker/prpgmod.c +++ b/ProcessHacker/prpgmod.c @@ -570,12 +570,12 @@ INT_PTR CALLBACK PhpProcessModulesDlgProc( if (GET_WM_COMMAND_HWND(wParam, lParam) != modulesContext->SearchboxHandle) break; - newSearchboxText = PhGetWindowText(modulesContext->SearchboxHandle); + newSearchboxText = PH_AUTO(PhGetWindowText(modulesContext->SearchboxHandle)); if (!PhEqualString(modulesContext->SearchboxText, newSearchboxText, FALSE)) { // Cache the current search text for our callback. - PhMoveReference(&modulesContext->SearchboxText, newSearchboxText); + PhSwapReference(&modulesContext->SearchboxText, newSearchboxText); // Expand any hidden nodes to make search results visible. PhExpandAllModuleNodes(&modulesContext->ListContext, TRUE); From 4f07de98240903ba629813180b73dc5723c2ebb7 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 29 Jun 2018 04:21:52 +1000 Subject: [PATCH 1058/2058] Update SDK 10.0.17134 --- ProcessHacker/ProcessHacker.vcxproj | 18 +++++++++--------- phlib/phlib.vcxproj | 16 +++++++++++++--- phlib/util.c | 27 +++++---------------------- tools/peview/peview.vcxproj | 2 +- 4 files changed, 28 insertions(+), 35 deletions(-) diff --git a/ProcessHacker/ProcessHacker.vcxproj b/ProcessHacker/ProcessHacker.vcxproj index bb6839544589..fa3f4a316964 100644 --- a/ProcessHacker/ProcessHacker.vcxproj +++ b/ProcessHacker/ProcessHacker.vcxproj @@ -22,7 +22,7 @@ {0271DD27-6707-4290-8DFE-285702B7115D} ProcessHacker Win32Proj - 10.0.16299.0 + 10.0.17134.0 @@ -106,14 +106,14 @@ true - aclui.lib;comctl32.lib;iphlpapi.lib;noarg.obj;noenv.obj;ntdll.lib;phlib.lib;uxtheme.lib;version.lib;wbemuuid.lib;windowscodecs.lib;winsta.lib;ws2_32.lib;%(AdditionalDependencies) + aclui.lib;comctl32.lib;iphlpapi.lib;noarg.obj;noenv.obj;ntdll.lib;phlib.lib;userenv.lib;uxtheme.lib;version.lib;wbemuuid.lib;windowscodecs.lib;winsta.lib;ws2_32.lib;%(AdditionalDependencies) true Windows MachineX86 6.01 $(SolutionDir)phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) ProcessHacker.def - aclui.dll;comdlg32.dll;iphlpapi.dll;winsta.dll;ws2_32.dll;%(DelayLoadDLLs) + aclui.dll;comdlg32.dll;iphlpapi.dll;userenv.dll;winsta.dll;ws2_32.dll;%(DelayLoadDLLs) _UNICODE;UNICODE;%(PreprocessorDefinitions);$(ExternalCompilerOptions) @@ -138,14 +138,14 @@ true - aclui.lib;comctl32.lib;iphlpapi.lib;noarg.obj;noenv.obj;ntdll.lib;phlib.lib;uxtheme.lib;version.lib;wbemuuid.lib;windowscodecs.lib;winsta.lib;ws2_32.lib;%(AdditionalDependencies) + aclui.lib;comctl32.lib;iphlpapi.lib;noarg.obj;noenv.obj;ntdll.lib;phlib.lib;userenv.lib;uxtheme.lib;version.lib;wbemuuid.lib;windowscodecs.lib;winsta.lib;ws2_32.lib;%(AdditionalDependencies) true Windows MachineX64 6.01 $(SolutionDir)phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) ProcessHacker.def - aclui.dll;comdlg32.dll;iphlpapi.dll;winsta.dll;ws2_32.dll;%(DelayLoadDLLs) + aclui.dll;comdlg32.dll;iphlpapi.dll;userenv.dll;winsta.dll;ws2_32.dll;%(DelayLoadDLLs) _UNICODE;UNICODE;%(PreprocessorDefinitions);$(ExternalCompilerOptions) @@ -175,7 +175,7 @@ Guard - aclui.lib;comctl32.lib;iphlpapi.lib;noarg.obj;noenv.obj;ntdll.lib;phlib.lib;uxtheme.lib;version.lib;wbemuuid.lib;windowscodecs.lib;winsta.lib;ws2_32.lib;%(AdditionalDependencies) + aclui.lib;comctl32.lib;iphlpapi.lib;noarg.obj;noenv.obj;ntdll.lib;phlib.lib;userenv.lib;uxtheme.lib;version.lib;wbemuuid.lib;windowscodecs.lib;winsta.lib;ws2_32.lib;%(AdditionalDependencies) Windows true true @@ -184,7 +184,7 @@ 6.01 $(SolutionDir)phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) ProcessHacker.def - aclui.dll;comdlg32.dll;iphlpapi.dll;winsta.dll;ws2_32.dll;%(DelayLoadDLLs) + aclui.dll;comdlg32.dll;iphlpapi.dll;userenv.dll;winsta.dll;ws2_32.dll;%(DelayLoadDLLs) $(ExternalDebugOptions) @@ -213,7 +213,7 @@ Guard - aclui.lib;comctl32.lib;iphlpapi.lib;noarg.obj;noenv.obj;ntdll.lib;phlib.lib;uxtheme.lib;version.lib;wbemuuid.lib;windowscodecs.lib;winsta.lib;ws2_32.lib;%(AdditionalDependencies) + aclui.lib;comctl32.lib;iphlpapi.lib;noarg.obj;noenv.obj;ntdll.lib;phlib.lib;userenv.lib;uxtheme.lib;version.lib;wbemuuid.lib;windowscodecs.lib;winsta.lib;ws2_32.lib;%(AdditionalDependencies) Windows true true @@ -222,7 +222,7 @@ 6.01 $(SolutionDir)phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) ProcessHacker.def - aclui.dll;comdlg32.dll;iphlpapi.dll;winsta.dll;ws2_32.dll;%(DelayLoadDLLs) + aclui.dll;comdlg32.dll;iphlpapi.dll;userenv.dll;winsta.dll;ws2_32.dll;%(DelayLoadDLLs) $(ExternalDebugOptions) diff --git a/phlib/phlib.vcxproj b/phlib/phlib.vcxproj index 06c3c90020e6..12755d5d85a7 100644 --- a/phlib/phlib.vcxproj +++ b/phlib/phlib.vcxproj @@ -22,7 +22,7 @@ {477D0215-F252-41A1-874B-F27E3EA1ED17} phlib Win32Proj - 10.0.16299.0 + 10.0.17134.0 @@ -89,6 +89,9 @@ true true + + MachineX86 + @@ -104,6 +107,9 @@ true true + + MachineX64 + @@ -113,7 +119,6 @@ WIN32;NDEBUG;_WINDOWS;_PHLIB_;%(PreprocessorDefinitions) true MultiThreaded - false true Level3 ProgramDatabase @@ -123,6 +128,9 @@ StreamingSIMDExtensions Guard + + MachineX86 + @@ -132,7 +140,6 @@ WIN64;NDEBUG;_WINDOWS;_PHLIB_;%(PreprocessorDefinitions) true MultiThreaded - false true Level3 ProgramDatabase @@ -141,6 +148,9 @@ true Guard + + MachineX64 + diff --git a/phlib/util.c b/phlib/util.c index 3927893332a5..d53f15b28c70 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -31,6 +31,7 @@ #include #undef CINTERFACE #undef COBJMACROS +#include #include #include @@ -51,16 +52,6 @@ typedef BOOLEAN (NTAPI *_WinStationQueryInformationW)( _Out_ PULONG ReturnLength ); -typedef BOOL (WINAPI *_CreateEnvironmentBlock)( - _Out_ LPVOID *lpEnvironment, - _In_opt_ HANDLE hToken, - _In_ BOOL bInherit - ); - -typedef BOOL (WINAPI *_DestroyEnvironmentBlock)( - _In_ LPVOID lpEnvironment - ); - DECLSPEC_SELECTANY WCHAR *PhSizeUnitNames[7] = { L"B", L"kB", L"MB", L"GB", L"TB", L"PB", L"EB" }; DECLSPEC_SELECTANY ULONG PhMaxSizeUnit = MAXULONG32; @@ -2583,9 +2574,6 @@ NTSTATUS PhCreateProcessAsUser( { static PH_INITONCE initOnce = PH_INITONCE_INIT; static _WinStationQueryInformationW WinStationQueryInformationW_I = NULL; - static _CreateEnvironmentBlock CreateEnvironmentBlock_I = NULL; - static _DestroyEnvironmentBlock DestroyEnvironmentBlock_I = NULL; - NTSTATUS status; HANDLE tokenHandle; PVOID defaultEnvironment = NULL; @@ -2595,15 +2583,10 @@ NTSTATUS PhCreateProcessAsUser( if (PhBeginInitOnce(&initOnce)) { HMODULE winsta; - HMODULE userEnv; winsta = LoadLibrary(L"winsta.dll"); WinStationQueryInformationW_I = PhGetDllBaseProcedureAddress(winsta, "WinStationQueryInformationW", 0); - userEnv = LoadLibrary(L"userenv.dll"); - CreateEnvironmentBlock_I = PhGetDllBaseProcedureAddress(userEnv, "CreateEnvironmentBlock", 0); - DestroyEnvironmentBlock_I = PhGetDllBaseProcedureAddress(userEnv, "DestroyEnvironmentBlock", 0); - PhEndInitOnce(&initOnce); } @@ -2846,9 +2829,9 @@ NTSTATUS PhCreateProcessAsUser( if (!Information->Environment) { - if (CreateEnvironmentBlock_I) + if (CreateEnvironmentBlock) { - CreateEnvironmentBlock_I(&defaultEnvironment, tokenHandle, FALSE); + CreateEnvironmentBlock(&defaultEnvironment, tokenHandle, FALSE); if (defaultEnvironment) Flags |= PH_CREATE_PROCESS_UNICODE_ENVIRONMENT; @@ -2870,8 +2853,8 @@ NTSTATUS PhCreateProcessAsUser( if (defaultEnvironment) { - if (DestroyEnvironmentBlock_I) - DestroyEnvironmentBlock_I(defaultEnvironment); + if (DestroyEnvironmentBlock) + DestroyEnvironmentBlock(defaultEnvironment); } NtClose(tokenHandle); diff --git a/tools/peview/peview.vcxproj b/tools/peview/peview.vcxproj index a8358d8ddf51..961198d78f6d 100644 --- a/tools/peview/peview.vcxproj +++ b/tools/peview/peview.vcxproj @@ -22,7 +22,7 @@ {72C124A2-3C80-41C6-ABA1-C4948B713204} peview Win32Proj - 10.0.16299.0 + 10.0.17134.0 From 0950ee247df55c215cbe2f2493cd6b2755a5322a Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 29 Jun 2018 11:42:25 +1000 Subject: [PATCH 1059/2058] Fix RS4 mitigation policy --- ProcessHacker/include/procmtgn.h | 5 ++ ProcessHacker/mtgndlg.c | 101 +++++++++---------------------- ProcessHacker/procmtgn.c | 51 +++++++++++++++- 3 files changed, 81 insertions(+), 76 deletions(-) diff --git a/ProcessHacker/include/procmtgn.h b/ProcessHacker/include/procmtgn.h index 20522d78764b..53adeaaf112c 100644 --- a/ProcessHacker/include/procmtgn.h +++ b/ProcessHacker/include/procmtgn.h @@ -25,6 +25,11 @@ NTSTATUS PhGetProcessMitigationPolicy( _Out_ PPH_PROCESS_MITIGATION_POLICY_ALL_INFORMATION Information ); +NTSTATUS PhGetProcessSystemDllInitBlock( + _In_ HANDLE ProcessHandle, + _Out_ PPS_SYSTEM_DLL_INIT_BLOCK *SystemDllInitBlock + ); + BOOLEAN PhDescribeProcessMitigationPolicy( _In_ PROCESS_MITIGATION_POLICY Policy, _In_ PVOID Data, diff --git a/ProcessHacker/mtgndlg.c b/ProcessHacker/mtgndlg.c index a161a58d6ab5..31127ad8f5ec 100644 --- a/ProcessHacker/mtgndlg.c +++ b/ProcessHacker/mtgndlg.c @@ -46,54 +46,6 @@ INT_PTR CALLBACK PhpProcessMitigationPolicyDlgProc( _In_ LPARAM lParam ); -NTSTATUS PhpGetProcessSystemDllInitBlock( - _In_ HANDLE ProcessHandle, - _Out_ PPS_SYSTEM_DLL_INIT_BLOCK *SystemDllInitBlock - ) -{ - NTSTATUS status; - PH_STRINGREF systemRoot; - PVOID ldrInitBlockBaseAddress = NULL; - PPH_STRING ntdllFileName; - - PhGetSystemRoot(&systemRoot); - ntdllFileName = PhConcatStringRefZ(&systemRoot, L"\\System32\\ntdll.dll"); - - status = PhGetProcedureAddressRemote( - ProcessHandle, - ntdllFileName->Buffer, - "LdrSystemDllInitBlock", - 0, - &ldrInitBlockBaseAddress, - NULL - ); - - PhDereferenceObject(ntdllFileName); - - if (NT_SUCCESS(status) && ldrInitBlockBaseAddress) - { - PPS_SYSTEM_DLL_INIT_BLOCK ldrInitBlock; - - ldrInitBlock = PhAllocate(sizeof(PS_SYSTEM_DLL_INIT_BLOCK)); - memset(ldrInitBlock, 0, sizeof(PS_SYSTEM_DLL_INIT_BLOCK)); - - status = NtReadVirtualMemory( - ProcessHandle, - ldrInitBlockBaseAddress, - ldrInitBlock, - sizeof(PS_SYSTEM_DLL_INIT_BLOCK), - NULL - ); - - if (NT_SUCCESS(status)) - *SystemDllInitBlock = ldrInitBlock; - else - PhFree(ldrInitBlock); - } - - return status; -} - VOID PhShowProcessMitigationPolicyDialog( _In_ HWND ParentWindowHandle, _In_ HANDLE ProcessId @@ -110,28 +62,30 @@ VOID PhShowProcessMitigationPolicyDialog( memset(&context, 0, sizeof(MITIGATION_POLICY_CONTEXT)); memset(&context.Entries, 0, sizeof(context.Entries)); - if (NT_SUCCESS(status = PhOpenProcess( + // Try to get a handle with query information + vm read access. + if (!NT_SUCCESS(status = PhOpenProcess( &processHandle, PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, ProcessId ))) + { + // Try to get a handle with query information. + status = PhOpenProcess( + &processHandle, + PROCESS_QUERY_INFORMATION, + ProcessId + ); + } + + if (NT_SUCCESS(status)) { PPS_SYSTEM_DLL_INIT_BLOCK dllInitBlock; - if (NT_SUCCESS(PhpGetProcessSystemDllInitBlock(processHandle, &dllInitBlock))) + if (NT_SUCCESS(PhGetProcessSystemDllInitBlock(processHandle, &dllInitBlock))) { context.SystemDllInitBlock = dllInitBlock; } - NtClose(processHandle); - } - - if (NT_SUCCESS(status = PhOpenProcess( - &processHandle, - PROCESS_QUERY_INFORMATION, - ProcessId - ))) - { if (NT_SUCCESS(PhGetProcessMitigationPolicy(processHandle, &information))) { for (policy = 0; policy < MaxProcessMitigationPolicy; policy++) @@ -170,7 +124,7 @@ VOID PhShowProcessMitigationPolicyDialog( } else { - PhShowStatus(ParentWindowHandle, L"Unable to open the process", status, 0); + PhShowStatus(ParentWindowHandle, L"Unable to open the process.", status, 0); } } @@ -227,7 +181,7 @@ INT_PTR CALLBACK PhpProcessMitigationPolicyDlgProc( if (context->SystemDllInitBlock && RTL_CONTAINS_FIELD(context->SystemDllInitBlock, context->SystemDllInitBlock->Size, MitigationOptionsMap)) { - if (context->SystemDllInitBlock->MitigationOptionsMap.Map[1] & PROCESS_CREATION_MITIGATION_POLICY2_LOADER_INTEGRITY_CONTINUITY_ALWAYS_ON) + if (context->SystemDllInitBlock->MitigationOptionsMap.Map[0] & PROCESS_CREATION_MITIGATION_POLICY2_LOADER_INTEGRITY_CONTINUITY_ALWAYS_ON) { PMITIGATION_POLICY_ENTRY entry; @@ -239,7 +193,7 @@ INT_PTR CALLBACK PhpProcessMitigationPolicyDlgProc( PhAddListViewItem(lvHandle, MAXINT, entry->ShortDescription->Buffer, entry); } - if (context->SystemDllInitBlock->MitigationOptionsMap.Map[1] & PROCESS_CREATION_MITIGATION_POLICY2_MODULE_TAMPERING_PROTECTION_ALWAYS_ON) + if (context->SystemDllInitBlock->MitigationOptionsMap.Map[0] & PROCESS_CREATION_MITIGATION_POLICY2_MODULE_TAMPERING_PROTECTION_ALWAYS_ON) { PMITIGATION_POLICY_ENTRY entry; @@ -251,18 +205,17 @@ INT_PTR CALLBACK PhpProcessMitigationPolicyDlgProc( PhAddListViewItem(lvHandle, MAXINT, entry->ShortDescription->Buffer, entry); } - // Note: This value doesn't appear to be available via the MitigationOptionsMap. - //if (context->SystemDllInitBlock->MitigationOptionsMap.Map[1] & PROCESS_CREATION_MITIGATION_POLICY2_RESTRICT_INDIRECT_BRANCH_PREDICTION_ALWAYS_ON) - //{ - // PMITIGATION_POLICY_ENTRY entry; - // - // entry = PhAllocate(sizeof(MITIGATION_POLICY_ENTRY)); - // entry->NonStandard = TRUE; - // entry->ShortDescription = PhCreateString(L"Indirect branch prediction"); - // entry->LongDescription = PhCreateString(L"Protects against sibling hardware threads (hyperthreads) from interfering with indirect branch predictions."); - // - // PhAddListViewItem(lvHandle, MAXINT, entry->ShortDescription->Buffer, entry); - //} + if (context->SystemDllInitBlock->MitigationOptionsMap.Map[0] & PROCESS_CREATION_MITIGATION_POLICY2_RESTRICT_INDIRECT_BRANCH_PREDICTION_ALWAYS_ON) + { + PMITIGATION_POLICY_ENTRY entry; + + entry = PhAllocate(sizeof(MITIGATION_POLICY_ENTRY)); + entry->NonStandard = TRUE; + entry->ShortDescription = PhCreateString(L"Indirect branch prediction"); + entry->LongDescription = PhCreateString(L"Protects against sibling hardware threads (hyperthreads) from interfering with indirect branch predictions."); + + PhAddListViewItem(lvHandle, MAXINT, entry->ShortDescription->Buffer, entry); + } } ExtendedListView_SortItems(lvHandle); diff --git a/ProcessHacker/procmtgn.c b/ProcessHacker/procmtgn.c index 1f07687c9bea..1016a27e0acc 100644 --- a/ProcessHacker/procmtgn.c +++ b/ProcessHacker/procmtgn.c @@ -100,7 +100,7 @@ NTSTATUS PhGetProcessMitigationPolicy( #define COPY_PROCESS_MITIGATION_POLICY(PolicyName, StructName) \ if (NT_SUCCESS(PhpCopyProcessMitigationPolicy(&status, ProcessHandle, Process##PolicyName##Policy, \ - FIELD_OFFSET(PROCESS_MITIGATION_POLICY_INFORMATION, PolicyName##Policy), \ + UFIELD_OFFSET(PROCESS_MITIGATION_POLICY_INFORMATION, PolicyName##Policy), \ sizeof(StructName), \ &Information->PolicyName##Policy))) \ { \ @@ -434,7 +434,6 @@ BOOLEAN PhDescribeProcessMitigationPolicy( } } break; - case ProcessPayloadRestrictionPolicy: { PPROCESS_MITIGATION_PAYLOAD_RESTRICTION_POLICY data = Data; @@ -485,3 +484,51 @@ BOOLEAN PhDescribeProcessMitigationPolicy( return result; } + +NTSTATUS PhGetProcessSystemDllInitBlock( + _In_ HANDLE ProcessHandle, + _Out_ PPS_SYSTEM_DLL_INIT_BLOCK *SystemDllInitBlock + ) +{ + NTSTATUS status; + PH_STRINGREF systemRoot; + PVOID ldrInitBlockBaseAddress = NULL; + PPH_STRING ntdllFileName; + + PhGetSystemRoot(&systemRoot); + ntdllFileName = PhConcatStringRefZ(&systemRoot, L"\\System32\\ntdll.dll"); + + status = PhGetProcedureAddressRemote( + ProcessHandle, + ntdllFileName->Buffer, + "LdrSystemDllInitBlock", + 0, + &ldrInitBlockBaseAddress, + NULL + ); + + PhDereferenceObject(ntdllFileName); + + if (NT_SUCCESS(status) && ldrInitBlockBaseAddress) + { + PPS_SYSTEM_DLL_INIT_BLOCK ldrInitBlock; + + ldrInitBlock = PhAllocate(sizeof(PS_SYSTEM_DLL_INIT_BLOCK)); + memset(ldrInitBlock, 0, sizeof(PS_SYSTEM_DLL_INIT_BLOCK)); + + status = NtReadVirtualMemory( + ProcessHandle, + ldrInitBlockBaseAddress, + ldrInitBlock, + sizeof(PS_SYSTEM_DLL_INIT_BLOCK), + NULL + ); + + if (NT_SUCCESS(status)) + *SystemDllInitBlock = ldrInitBlock; + else + PhFree(ldrInitBlock); + } + + return status; +} From 25aba47bdc09ae9a5081d5c82e1a2631b81f39d8 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 29 Jun 2018 11:59:30 +1000 Subject: [PATCH 1060/2058] peview: Update DelayLoadDLLs --- tools/peview/peview.vcxproj | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/tools/peview/peview.vcxproj b/tools/peview/peview.vcxproj index 961198d78f6d..ed172609dcf7 100644 --- a/tools/peview/peview.vcxproj +++ b/tools/peview/peview.vcxproj @@ -99,7 +99,7 @@ true - noarg.obj;noenv.obj;phlib.lib;ntdll.lib;uxtheme.lib;windowscodecs.lib;%(AdditionalDependencies) + noarg.obj;noenv.obj;phlib.lib;ntdll.lib;uxtheme.lib;userenv.lib;windowscodecs.lib;%(AdditionalDependencies) ..\..\phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) @@ -107,6 +107,7 @@ Windows MachineX86 6.01 + %(DelayLoadDLLs) ..\..\phnt\include;..\..\phlib\include;include;%(AdditionalIncludeDirectories) @@ -129,7 +130,7 @@ true - noarg.obj;noenv.obj;phlib.lib;ntdll.lib;uxtheme.lib;windowscodecs.lib;%(AdditionalDependencies) + noarg.obj;noenv.obj;phlib.lib;ntdll.lib;uxtheme.lib;userenv.lib;windowscodecs.lib;%(AdditionalDependencies) ..\..\phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) @@ -137,6 +138,7 @@ Windows MachineX64 6.01 + %(DelayLoadDLLs) ..\..\phnt\include;..\..\phlib\include;include;%(AdditionalIncludeDirectories) @@ -162,7 +164,7 @@ Guard - noarg.obj;noenv.obj;phlib.lib;ntdll.lib;uxtheme.lib;windowscodecs.lib;%(AdditionalDependencies) + noarg.obj;noenv.obj;phlib.lib;ntdll.lib;uxtheme.lib;userenv.lib;windowscodecs.lib;%(AdditionalDependencies) ..\..\phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) @@ -173,6 +175,7 @@ MachineX86 true 6.01 + %(DelayLoadDLLs) ..\..\phnt\include;..\..\phlib\include;include;%(AdditionalIncludeDirectories) @@ -197,7 +200,7 @@ Guard - noarg.obj;noenv.obj;phlib.lib;ntdll.lib;uxtheme.lib;windowscodecs.lib;%(AdditionalDependencies) + noarg.obj;noenv.obj;phlib.lib;ntdll.lib;uxtheme.lib;userenv.lib;windowscodecs.lib;%(AdditionalDependencies) ..\..\phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) @@ -208,6 +211,7 @@ MachineX64 true 6.01 + %(DelayLoadDLLs) ..\..\phnt\include;..\..\phlib\include;include;%(AdditionalIncludeDirectories) From b354aa5bde25633381d166c6b99da52881254220 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 29 Jun 2018 12:20:39 +1000 Subject: [PATCH 1061/2058] SetupTool: Update DelayLoadDLLs --- .../CustomSetupTool/CustomSetupTool.vcxproj | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj b/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj index ada56f42b999..9d38d024a4c5 100644 --- a/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj +++ b/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj @@ -13,7 +13,7 @@ {5C00734F-F50A-49FC-9D2A-F6EE51ECB00F} CustomSetupTool - 10.0.16299.0 + 10.0.17134.0 CustomSetupTool @@ -29,6 +29,7 @@ v141 true Unicode + Spectre @@ -64,11 +65,12 @@ true - uxtheme.lib;winhttp.lib;phlib.lib;ntdll.lib;%(AdditionalDependencies) + uxtheme.lib;winhttp.lib;phlib.lib;ntdll.lib;userenv.lib;%(AdditionalDependencies) $(SolutionDir)..\..\phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) Windows RequireAdministrator 6.01 + %(DelayLoadDLLs) _UNICODE;UNICODE;%(PreprocessorDefinitions);$(ExternalCompilerOptions) @@ -90,17 +92,19 @@ AnySuitable true StreamingSIMDExtensions + Guard true true true - uxtheme.lib;winhttp.lib;phlib.lib;ntdll.lib;%(AdditionalDependencies) + uxtheme.lib;winhttp.lib;phlib.lib;ntdll.lib;userenv.lib;%(AdditionalDependencies) $(SolutionDir)..\..\phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) Windows 6.01 true RequireAdministrator + %(DelayLoadDLLs) _UNICODE;UNICODE;%(PreprocessorDefinitions);$(ExternalCompilerOptions) From 61c559c450bae475e76da2ba2366f42298568779 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 29 Jun 2018 13:17:56 +1000 Subject: [PATCH 1062/2058] ToolStatus: Update statusbar text cache --- plugins/ToolStatus/statusbar.c | 261 +++++++++++++++++++-------------- 1 file changed, 154 insertions(+), 107 deletions(-) diff --git a/plugins/ToolStatus/statusbar.c b/plugins/ToolStatus/statusbar.c index 961c13242410..a7bc74f4766f 100644 --- a/plugins/ToolStatus/statusbar.c +++ b/plugins/ToolStatus/statusbar.c @@ -3,7 +3,7 @@ * statusbar main * * Copyright (C) 2010-2013 wj32 - * Copyright (C) 2011-2016 dmex + * Copyright (C) 2011-2018 dmex * * This file is part of Process Hacker. * @@ -235,8 +235,8 @@ VOID StatusBarUpdate( ULONG i; HDC hdc; BOOLEAN resetMaxWidths = FALSE; - PPH_STRING text[MAX_STATUSBAR_ITEMS]; ULONG widths[MAX_STATUSBAR_ITEMS]; + WCHAR text[MAX_STATUSBAR_ITEMS][0x80]; if (ProcessesUpdatedCount < 2) return; @@ -270,6 +270,7 @@ VOID StatusBarUpdate( } count = 0; + memset(text, 0, sizeof(text)); for (i = 0; i < StatusBarItemList->Count; i++) { @@ -280,86 +281,109 @@ VOID StatusBarUpdate( { case ID_STATUS_CPUUSAGE: { - text[count] = PhFormatString( - L"CPU Usage: %.2f%%", - (SystemStatistics.CpuKernelUsage + SystemStatistics.CpuUserUsage) * 100 - ); + FLOAT cpuUsage = SystemStatistics.CpuKernelUsage + SystemStatistics.CpuUserUsage; + PH_FORMAT format[3]; + + PhInitFormatS(&format[0], L"CPU Usage: "); + PhInitFormatF(&format[1], cpuUsage * 100, 2); + PhInitFormatS(&format[2], L"%"); + + PhFormatToBuffer(format, RTL_NUMBER_OF(format), text[count], sizeof(text[count]), NULL); } break; case ID_STATUS_COMMITCHARGE: { ULONG commitUsage = SystemStatistics.Performance->CommittedPages; FLOAT commitFraction = (FLOAT)commitUsage / SystemStatistics.Performance->CommitLimit * 100; + PH_FORMAT format[5]; + + PhInitFormatS(&format[0], L"Commit charge: "); + PhInitFormatSize(&format[1], UInt32x32To64(commitUsage, PAGE_SIZE)); + PhInitFormatS(&format[2], L" ("); + PhInitFormatF(&format[3], commitFraction, 2); + PhInitFormatS(&format[4], L"%)"); - text[count] = PhFormatString( - L"Commit charge: %s (%.2f%%)", - PhaFormatSize(UInt32x32To64(commitUsage, PAGE_SIZE), -1)->Buffer, - commitFraction - ); + PhFormatToBuffer(format, RTL_NUMBER_OF(format), text[count], sizeof(text[count]), NULL); } break; case ID_STATUS_PHYSICALMEMORY: { ULONG physicalUsage = PhSystemBasicInformation.NumberOfPhysicalPages - SystemStatistics.Performance->AvailablePages; FLOAT physicalFraction = (FLOAT)physicalUsage / PhSystemBasicInformation.NumberOfPhysicalPages * 100; + PH_FORMAT format[5]; - text[count] = PhFormatString( - L"Physical memory: %s (%.2f%%)", - PhaFormatSize(UInt32x32To64(physicalUsage, PAGE_SIZE), -1)->Buffer, - physicalFraction - ); + PhInitFormatS(&format[0], L"Physical memory: "); + PhInitFormatSize(&format[1], UInt32x32To64(physicalUsage, PAGE_SIZE)); + PhInitFormatS(&format[2], L" ("); + PhInitFormatF(&format[3], physicalFraction, 2); + PhInitFormatS(&format[4], L"%)"); + + PhFormatToBuffer(format, RTL_NUMBER_OF(format), text[count], sizeof(text[count]), NULL); } break; case ID_STATUS_FREEMEMORY: { ULONG physicalFree = SystemStatistics.Performance->AvailablePages; FLOAT physicalFreeFraction = (FLOAT)physicalFree / PhSystemBasicInformation.NumberOfPhysicalPages * 100; + PH_FORMAT format[5]; + + PhInitFormatS(&format[0], L"Free memory: "); + PhInitFormatSize(&format[1], UInt32x32To64(physicalFree, PAGE_SIZE)); + PhInitFormatS(&format[2], L" ("); + PhInitFormatF(&format[3], physicalFreeFraction, 2); + PhInitFormatS(&format[4], L"%)"); - text[count] = PhFormatString( - L"Free memory: %s (%.2f%%)", - PhaFormatSize(UInt32x32To64(physicalFree, PAGE_SIZE), -1)->Buffer, - physicalFreeFraction - ); + PhFormatToBuffer(format, RTL_NUMBER_OF(format), text[count], sizeof(text[count]), NULL); } break; case ID_STATUS_NUMBEROFPROCESSES: { - text[count] = PhConcatStrings2( - L"Processes: ", - PhaFormatUInt64(SystemStatistics.NumberOfProcesses, TRUE)->Buffer - ); + PH_FORMAT format[2]; + + PhInitFormatS(&format[0], L"Processes: "); + PhInitFormatI64UGroupDigits(&format[1], SystemStatistics.NumberOfProcesses); + + PhFormatToBuffer(format, RTL_NUMBER_OF(format), text[count], sizeof(text[count]), NULL); } break; case ID_STATUS_NUMBEROFTHREADS: { - text[count] = PhConcatStrings2( - L"Threads: ", - PhaFormatUInt64(SystemStatistics.NumberOfThreads, TRUE)->Buffer - ); + PH_FORMAT format[2]; + + PhInitFormatS(&format[0], L"Threads: "); + PhInitFormatI64UGroupDigits(&format[1], SystemStatistics.NumberOfThreads); + + PhFormatToBuffer(format, RTL_NUMBER_OF(format), text[count], sizeof(text[count]), NULL); } break; case ID_STATUS_NUMBEROFHANDLES: { - text[count] = PhConcatStrings2( - L"Handles: ", - PhaFormatUInt64(SystemStatistics.NumberOfHandles, TRUE)->Buffer - ); + PH_FORMAT format[2]; + + PhInitFormatS(&format[0], L"Handles: "); + PhInitFormatI64UGroupDigits(&format[1], SystemStatistics.NumberOfHandles); + + PhFormatToBuffer(format, RTL_NUMBER_OF(format), text[count], sizeof(text[count]), NULL); } break; case ID_STATUS_IO_RO: { - text[count] = PhConcatStrings2( - L"I/O R+O: ", - PhaFormatSize(SystemStatistics.IoReadDelta.Delta + SystemStatistics.IoOtherDelta.Delta, -1)->Buffer - ); + PH_FORMAT format[2]; + + PhInitFormatS(&format[0], L"I/O R+O: "); + PhInitFormatSize(&format[1], (SystemStatistics.IoReadDelta.Delta + SystemStatistics.IoOtherDelta.Delta)); + + PhFormatToBuffer(format, RTL_NUMBER_OF(format), text[count], sizeof(text[count]), NULL); } break; case ID_STATUS_IO_W: { - text[count] = PhConcatStrings2( - L"I/O W: ", - PhaFormatSize(SystemStatistics.IoWriteDelta.Delta, -1)->Buffer - ); + PH_FORMAT format[2]; + + PhInitFormatS(&format[0], L"I/O W: "); + PhInitFormatSize(&format[1], SystemStatistics.IoWriteDelta.Delta); + + PhFormatToBuffer(format, RTL_NUMBER_OF(format), text[count], sizeof(text[count]), NULL); } break; case ID_STATUS_MAX_CPU_PROCESS: @@ -370,27 +394,38 @@ VOID StatusBarUpdate( { if (!PH_IS_FAKE_PROCESS_ID(processItem->ProcessId)) { - text[count] = PhFormatString( - L"%s (%lu): %.2f%%", - processItem->ProcessName->Buffer, - HandleToUlong(processItem->ProcessId), - processItem->CpuUsage * 100 - ); + PH_FORMAT format[6]; + + PhInitFormatSR(&format[0], processItem->ProcessName->sr); + PhInitFormatS(&format[1], L" ("); + PhInitFormatI64U(&format[2], HandleToUlong(processItem->ProcessId)); + PhInitFormatS(&format[3], L"): "); + PhInitFormatF(&format[4], processItem->CpuUsage * 100, 2); + PhInitFormatS(&format[5], L"%"); + + PhFormatToBuffer(format, RTL_NUMBER_OF(format), text[count], sizeof(text[count]), NULL); } else { - text[count] = PhFormatString( - L"%s: %.2f%%", - processItem->ProcessName->Buffer, - processItem->CpuUsage * 100 - ); + PH_FORMAT format[4]; + + PhInitFormatSR(&format[0], processItem->ProcessName->sr); + PhInitFormatS(&format[1], L": "); + PhInitFormatF(&format[2], processItem->CpuUsage * 100, 2); + PhInitFormatS(&format[3], L"%)"); + + PhFormatToBuffer(format, RTL_NUMBER_OF(format), text[count], sizeof(text[count]), NULL); } PhDereferenceObject(processItem); } else { - text[count] = PhCreateString(L"-"); + PH_FORMAT format[1]; + + PhInitFormatS(&format[0], L"-"); + + PhFormatToBuffer(format, RTL_NUMBER_OF(format), text[count], sizeof(text[count]), NULL); } } break; @@ -402,126 +437,140 @@ VOID StatusBarUpdate( { if (!PH_IS_FAKE_PROCESS_ID(processItem->ProcessId)) { - text[count] = PhFormatString( - L"%s (%lu): %s", - processItem->ProcessName->Buffer, - HandleToUlong(processItem->ProcessId), - PhaFormatSize(processItem->IoReadDelta.Delta + processItem->IoWriteDelta.Delta + processItem->IoOtherDelta.Delta, -1)->Buffer - ); + PH_FORMAT format[5]; + + PhInitFormatSR(&format[0], processItem->ProcessName->sr); + PhInitFormatS(&format[1], L" ("); + PhInitFormatI64U(&format[2], HandleToUlong(processItem->ProcessId)); + PhInitFormatS(&format[3], L"): "); + PhInitFormatSize(&format[4], processItem->IoReadDelta.Delta + processItem->IoWriteDelta.Delta + processItem->IoOtherDelta.Delta); + + PhFormatToBuffer(format, RTL_NUMBER_OF(format), text[count], sizeof(text[count]), NULL); } else { - text[count] = PhFormatString( - L"%s: %s", - processItem->ProcessName->Buffer, - PhaFormatSize(processItem->IoReadDelta.Delta + processItem->IoWriteDelta.Delta + processItem->IoOtherDelta.Delta, -1)->Buffer - ); + PH_FORMAT format[3]; + + PhInitFormatSR(&format[0], processItem->ProcessName->sr); + PhInitFormatS(&format[1], L": "); + PhInitFormatSize(&format[2], processItem->IoReadDelta.Delta + processItem->IoWriteDelta.Delta + processItem->IoOtherDelta.Delta); + + PhFormatToBuffer(format, RTL_NUMBER_OF(format), text[count], sizeof(text[count]), NULL); } PhDereferenceObject(processItem); } else { - text[count] = PhCreateString(L"-"); + PH_FORMAT format[1]; + + PhInitFormatS(&format[0], L"-"); + + PhFormatToBuffer(format, RTL_NUMBER_OF(format), text[count], sizeof(text[count]), NULL); } } break; case ID_STATUS_NUMBEROFVISIBLEITEMS: { - HWND tnHandle = NULL; + HWND tnHandle; tnHandle = GetCurrentTreeNewHandle(); if (tnHandle) { - ULONG visibleCount = 0; + PH_FORMAT format[2]; - visibleCount = TreeNew_GetFlatNodeCount(tnHandle); + PhInitFormatS(&format[0], L"Visible: "); + PhInitFormatI64UGroupDigits(&format[1], TreeNew_GetFlatNodeCount(tnHandle)); - text[count] = PhFormatString( - L"Visible: %lu", - visibleCount - ); + PhFormatToBuffer(format, RTL_NUMBER_OF(format), text[count], sizeof(text[count]), NULL); } else { - text[count] = PhCreateString( - L"Visible: N/A" - ); + PH_FORMAT format[1]; + + PhInitFormatS(&format[0], L"Visible: N/A"); + + PhFormatToBuffer(format, RTL_NUMBER_OF(format), text[count], sizeof(text[count]), NULL); } } break; case ID_STATUS_NUMBEROFSELECTEDITEMS: { - HWND tnHandle = NULL; + HWND tnHandle; tnHandle = GetCurrentTreeNewHandle(); if (tnHandle) { - ULONG visibleCount = 0; - ULONG selectedCount = 0; + ULONG i; + ULONG visibleCount; + ULONG selectedCount; + PH_FORMAT format[2]; visibleCount = TreeNew_GetFlatNodeCount(tnHandle); + selectedCount = 0; - for (ULONG i = 0; i < visibleCount; i++) + for (i = 0; i < visibleCount; i++) { if (TreeNew_GetFlatNode(tnHandle, i)->Selected) selectedCount++; } - text[count] = PhFormatString( - L"Selected: %lu", - selectedCount - ); + PhInitFormatS(&format[0], L"Selected: "); + PhInitFormatI64UGroupDigits(&format[1], selectedCount); + + PhFormatToBuffer(format, RTL_NUMBER_OF(format), text[count], sizeof(text[count]), NULL); } else { - text[count] = PhCreateString( - L"Selected: N/A" - ); + PH_FORMAT format[1]; + + PhInitFormatS(&format[0], L"Selected: N/A"); + + PhFormatToBuffer(format, RTL_NUMBER_OF(format), text[count], sizeof(text[count]), NULL); } } break; case ID_STATUS_INTERVALSTATUS: { - ULONG interval; - - interval = PhGetIntegerSetting(L"UpdateInterval"); + PH_FORMAT format[1]; if (UpdateAutomatically) { - switch (interval) + switch (PhGetIntegerSetting(L"UpdateInterval")) { case 500: - text[count] = PhCreateString(L"Interval: Fast"); + PhInitFormatS(&format[0], L"Interval: Fast"); break; case 1000: - text[count] = PhCreateString(L"Interval: Normal"); + PhInitFormatS(&format[0], L"Interval: Normal"); break; case 2000: - text[count] = PhCreateString(L"Interval: Below normal"); + PhInitFormatS(&format[0], L"Interval: Below normal"); break; case 5000: - text[count] = PhCreateString(L"Interval: Slow"); + PhInitFormatS(&format[0], L"Interval: Slow"); break; case 10000: - text[count] = PhCreateString(L"Interval: Very slow"); + PhInitFormatS(&format[0], L"Interval: Very slow"); + break; + default: + PhInitFormatS(&format[0], L"Interval: N/A"); break; } } else { - text[count] = PhCreateString(L"Interval: Paused"); + PhInitFormatS(&format[0], L"Interval: Paused"); } + + PhFormatToBuffer(format, RTL_NUMBER_OF(format), text[count], sizeof(text[count]), NULL); } break; } - if (resetMaxWidths) - StatusBarMaxWidths[count] = 0; - - if (!GetTextExtentPoint32(hdc, text[count]->Buffer, (ULONG)text[count]->Length / sizeof(WCHAR), &size)) + if (!GetTextExtentPoint32(hdc, text[count], (INT)PhCountStringZ(text[count]), &size)) size.cx = 200; if (count != 0) @@ -531,14 +580,13 @@ VOID StatusBarUpdate( width = size.cx + 10; + if (resetMaxWidths) + StatusBarMaxWidths[count] = 0; + if (width <= StatusBarMaxWidths[count]) - { width = StatusBarMaxWidths[count]; - } else - { StatusBarMaxWidths[count] = width; - } widths[count] += width; @@ -551,7 +599,6 @@ VOID StatusBarUpdate( for (i = 0; i < count; i++) { - SendMessage(StatusBarHandle, SB_SETTEXT, i, (LPARAM)text[i]->Buffer); - PhDereferenceObject(text[i]); + SendMessage(StatusBarHandle, SB_SETTEXT, i, (LPARAM)text[i]); } -} \ No newline at end of file +} From 3857152b6e299f44e0877dfb5848202f1ec97cd6 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 29 Jun 2018 16:43:33 +1000 Subject: [PATCH 1063/2058] Update mxml debug macro --- phlib/mxml/mxml-attr.c | 16 ++++++++-------- phlib/mxml/mxml-node.c | 24 ++++++++++++------------ 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/phlib/mxml/mxml-attr.c b/phlib/mxml/mxml-attr.c index beb0b3f36118..8b9a0b0c27d7 100644 --- a/phlib/mxml/mxml-attr.c +++ b/phlib/mxml/mxml-attr.c @@ -43,7 +43,7 @@ mxmlElementDeleteAttr(mxml_node_t *node,/* I - Element */ mxml_attr_t *attr; /* Cirrent attribute */ -#ifdef DEBUG +#ifdef MXMLDEBUG fprintf(stderr, "mxmlElementDeleteAttr(node=%p, name=\"%s\")\n", node, name ? name : "(null)"); #endif /* DEBUG */ @@ -63,7 +63,7 @@ mxmlElementDeleteAttr(mxml_node_t *node,/* I - Element */ i > 0; i --, attr ++) { -#ifdef DEBUG +#ifdef MXMLDEBUG printf(" %s=\"%s\"\n", attr->name, attr->value); #endif /* DEBUG */ @@ -105,7 +105,7 @@ mxmlElementGetAttr(mxml_node_t *node, /* I - Element node */ mxml_attr_t *attr; /* Cirrent attribute */ -#ifdef DEBUG +#ifdef MXMLDEBUG fprintf(stderr, "mxmlElementGetAttr(node=%p, name=\"%s\")\n", node, name ? name : "(null)"); #endif /* DEBUG */ @@ -125,13 +125,13 @@ mxmlElementGetAttr(mxml_node_t *node, /* I - Element node */ i > 0; i --, attr ++) { -#ifdef DEBUG +#ifdef MXMLDEBUG printf(" %s=\"%s\"\n", attr->name, attr->value); #endif /* DEBUG */ if (!strcmp(attr->name, name)) { -#ifdef DEBUG +#ifdef MXMLDEBUG printf(" Returning \"%s\"!\n", attr->value); #endif /* DEBUG */ return (attr->value); @@ -142,7 +142,7 @@ mxmlElementGetAttr(mxml_node_t *node, /* I - Element node */ * Didn't find attribute, so return NULL... */ -#ifdef DEBUG +#ifdef MXMLDEBUG puts(" Returning NULL!\n"); #endif /* DEBUG */ @@ -209,7 +209,7 @@ mxmlElementSetAttr(mxml_node_t *node, /* I - Element node */ char *valuec; /* Copy of value */ -#ifdef DEBUG +#ifdef MXMLDEBUG fprintf(stderr, "mxmlElementSetAttr(node=%p, name=\"%s\", value=\"%s\")\n", node, name ? name : "(null)", value ? value : "(null)"); #endif /* DEBUG */ @@ -252,7 +252,7 @@ mxmlElementSetAttrf(mxml_node_t *node, /* I - Element node */ char *value; /* Value */ -#ifdef DEBUG +#ifdef MXMLDEBUG fprintf(stderr, "mxmlElementSetAttrf(node=%p, name=\"%s\", format=\"%s\", ...)\n", node, name ? name : "(null)", format ? format : "(null)"); diff --git a/phlib/mxml/mxml-node.c b/phlib/mxml/mxml-node.c index 3f32e47c4d12..73266adb0619 100644 --- a/phlib/mxml/mxml-node.c +++ b/phlib/mxml/mxml-node.c @@ -46,7 +46,7 @@ mxmlAdd(mxml_node_t *parent, /* I - Parent node */ mxml_node_t *child, /* I - Child node for where or @code MXML_ADD_TO_PARENT@ */ mxml_node_t *node) /* I - Node to add */ { -#ifdef DEBUG +#ifdef MXMLDEBUG fprintf(stderr, "mxmlAdd(parent=%p, where=%d, child=%p, node=%p)\n", parent, where, child, node); #endif /* DEBUG */ @@ -181,7 +181,7 @@ mxmlDelete(mxml_node_t *node) /* I - Node to delete */ *next; /* Next node */ -#ifdef DEBUG +#ifdef MXMLDEBUG fprintf(stderr, "mxmlDelete(node=%p)\n", node); #endif /* DEBUG */ @@ -290,7 +290,7 @@ mxmlNewCDATA(mxml_node_t *parent, /* I - Parent node or @code MXML_NO_PARENT@ */ mxml_node_t *node; /* New node */ -#ifdef DEBUG +#ifdef MXMLDEBUG fprintf(stderr, "mxmlNewCDATA(parent=%p, data=\"%s\")\n", parent, data ? data : "(null)"); #endif /* DEBUG */ @@ -333,7 +333,7 @@ mxmlNewCustom( mxml_node_t *node; /* New node */ -#ifdef DEBUG +#ifdef MXMLDEBUG fprintf(stderr, "mxmlNewCustom(parent=%p, data=%p, destroy=%p)\n", parent, data, destroy); #endif /* DEBUG */ @@ -367,7 +367,7 @@ mxmlNewElement(mxml_node_t *parent, /* I - Parent node or @code MXML_NO_PARENT@ mxml_node_t *node; /* New node */ -#ifdef DEBUG +#ifdef MXMLDEBUG fprintf(stderr, "mxmlNewElement(parent=%p, name=\"%s\")\n", parent, name ? name : "(null)"); #endif /* DEBUG */ @@ -405,7 +405,7 @@ mxmlNewInteger(mxml_node_t *parent, /* I - Parent node or @code MXML_NO_PARENT@ mxml_node_t *node; /* New node */ -#ifdef DEBUG +#ifdef MXMLDEBUG fprintf(stderr, "mxmlNewInteger(parent=%p, integer=%d)\n", parent, integer); #endif /* DEBUG */ @@ -436,7 +436,7 @@ mxmlNewOpaque(mxml_node_t *parent, /* I - Parent node or @code MXML_NO_PARENT@ * mxml_node_t *node; /* New node */ -#ifdef DEBUG +#ifdef MXMLDEBUG fprintf(stderr, "mxmlNewOpaque(parent=%p, opaque=\"%s\")\n", parent, opaque ? opaque : "(null)"); #endif /* DEBUG */ @@ -477,7 +477,7 @@ mxmlNewOpaquef(mxml_node_t *parent, /* I - Parent node or @code MXML_NO_PARENT@ va_list ap; /* Pointer to arguments */ -#ifdef DEBUG +#ifdef MXMLDEBUG fprintf(stderr, "mxmlNewOpaquef(parent=%p, format=\"%s\", ...)\n", parent, format ? format : "(null)"); #endif /* DEBUG */ @@ -520,7 +520,7 @@ mxmlNewReal(mxml_node_t *parent, /* I - Parent node or @code MXML_NO_PARENT@ */ mxml_node_t *node; /* New node */ -#ifdef DEBUG +#ifdef MXMLDEBUG fprintf(stderr, "mxmlNewReal(parent=%p, real=%g)\n", parent, real); #endif /* DEBUG */ @@ -553,7 +553,7 @@ mxmlNewText(mxml_node_t *parent, /* I - Parent node or @code MXML_NO_PARENT@ */ mxml_node_t *node; /* New node */ -#ifdef DEBUG +#ifdef MXMLDEBUG fprintf(stderr, "mxmlNewText(parent=%p, whitespace=%d, string=\"%s\")\n", parent, whitespace, string ? string : "(null)"); #endif /* DEBUG */ @@ -599,7 +599,7 @@ mxmlNewTextf(mxml_node_t *parent, /* I - Parent node or @code MXML_NO_PARENT@ */ va_list ap; /* Pointer to arguments */ -#ifdef DEBUG +#ifdef MXMLDEBUG fprintf(stderr, "mxmlNewTextf(parent=%p, whitespace=%d, format=\"%s\", ...)\n", parent, whitespace, format ? format : "(null)"); #endif /* DEBUG */ @@ -639,7 +639,7 @@ mxmlNewTextf(mxml_node_t *parent, /* I - Parent node or @code MXML_NO_PARENT@ */ void mxmlRemove(mxml_node_t *node) /* I - Node to remove */ { -#ifdef DEBUG +#ifdef MXMLDEBUG fprintf(stderr, "mxmlRemove(node=%p)\n", node); #endif /* DEBUG */ From a349a42c751fa9c3304b50a3cfc5f16e1c7f4148 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 29 Jun 2018 16:56:18 +1000 Subject: [PATCH 1064/2058] PHNT: Update Win10-RS4 apiset definitions --- phlib/include/phnative.h | 8 + phlib/include/phnativeinl.h | 71 ++ phlib/native.c | 12 + phnt/include/ntdbg.h | 104 ++- phnt/include/ntexapi.h | 36 +- phnt/include/ntldr.h | 185 +++- phnt/include/ntnls.h | 4 + phnt/include/ntrtl.h | 1609 +++++++++++++++++++++++++++++++---- phnt/include/ntseapi.h | 30 +- phnt/include/ntxcapi.h | 20 + 10 files changed, 1837 insertions(+), 242 deletions(-) diff --git a/phlib/include/phnative.h b/phlib/include/phnative.h index 8a5a1c927502..8bd3282528d9 100644 --- a/phlib/include/phnative.h +++ b/phlib/include/phnative.h @@ -390,6 +390,14 @@ PhGetTokenPrivileges( _Out_ PTOKEN_PRIVILEGES *Privileges ); +PHLIBAPI +NTSTATUS +NTAPI +PhGetTokenTrustLevel( + _In_ HANDLE TokenHandle, + _Out_ PTOKEN_PROCESS_TRUST_LEVEL *TrustLevel + ); + PHLIBAPI NTSTATUS NTAPI diff --git a/phlib/include/phnativeinl.h b/phlib/include/phnativeinl.h index 9213db21ff54..c84eb1a4675b 100644 --- a/phlib/include/phnativeinl.h +++ b/phlib/include/phnativeinl.h @@ -1217,6 +1217,77 @@ PhGetTokenIsUIAccessEnabled( return status; } +FORCEINLINE +NTSTATUS +PhSetTokenUIAccessEnabled( + _In_ HANDLE TokenHandle, + _In_ BOOLEAN IsUIAccessEnabled + ) +{ + ULONG uiAccess; + + uiAccess = IsUIAccessEnabled ? 1 : 0; + + return NtSetInformationToken( + TokenHandle, + TokenUIAccess, + &uiAccess, + sizeof(ULONG) + ); +} + +/** +* Gets SandBoxInert flag for a token. +* +* \param TokenHandle A handle to a token. The handle must have TOKEN_QUERY access. +* \param IsSandBoxInert A variable which receives a boolean indicating whether +* AppLocker rules or Software Restriction Policies are enabled for the token. +*/ +FORCEINLINE +NTSTATUS +PhGetTokenIsSandBoxInert( + _In_ HANDLE TokenHandle, + _Out_ PBOOLEAN IsSandBoxInert + ) +{ + NTSTATUS status; + ULONG returnLength; + ULONG sandBoxInert; + + status = NtQueryInformationToken( + TokenHandle, + TokenSandBoxInert, + &sandBoxInert, + sizeof(ULONG), + &returnLength + ); + + if (!NT_SUCCESS(status)) + return status; + + *IsSandBoxInert = !!sandBoxInert; + + return status; +} + +FORCEINLINE +NTSTATUS +PhGetTokenOrigin( + _In_ HANDLE TokenHandle, + _Out_ PTOKEN_ORIGIN Origin + ) +{ + ULONG returnLength; + + return NtQueryInformationToken( + TokenHandle, + TokenOrigin, + Origin, + sizeof(TOKEN_ORIGIN), + &returnLength + ); +} + FORCEINLINE NTSTATUS PhGetEventBasicInformation( diff --git a/phlib/native.c b/phlib/native.c index 781623374e79..4dd94313f197 100644 --- a/phlib/native.c +++ b/phlib/native.c @@ -2041,6 +2041,18 @@ NTSTATUS PhGetTokenPrivileges( ); } +NTSTATUS PhGetTokenTrustLevel( + _In_ HANDLE TokenHandle, + _Out_ PTOKEN_PROCESS_TRUST_LEVEL *TrustLevel + ) +{ + return PhpQueryTokenVariableSize( + TokenHandle, + TokenProcessTrustLevel, + TrustLevel + ); +} + NTSTATUS PhSetTokenSessionId( _In_ HANDLE TokenHandle, _In_ ULONG SessionId diff --git a/phnt/include/ntdbg.h b/phnt/include/ntdbg.h index 33228664fb95..cc46c761c063 100644 --- a/phnt/include/ntdbg.h +++ b/phnt/include/ntdbg.h @@ -21,6 +21,102 @@ #ifndef _NTDBG_H #define _NTDBG_H +// Debugging + +NTSYSAPI +VOID +NTAPI +DbgUserBreakPoint( + VOID + ); + +NTSYSAPI +VOID +NTAPI +DbgBreakPoint( + VOID + ); + +NTSYSAPI +VOID +NTAPI +DbgBreakPointWithStatus( + _In_ ULONG Status + ); + +#define DBG_STATUS_CONTROL_C 1 +#define DBG_STATUS_SYSRQ 2 +#define DBG_STATUS_BUGCHECK_FIRST 3 +#define DBG_STATUS_BUGCHECK_SECOND 4 +#define DBG_STATUS_FATAL 5 +#define DBG_STATUS_DEBUG_CONTROL 6 +#define DBG_STATUS_WORKER 7 + +NTSYSAPI +ULONG +STDAPIVCALLTYPE +DbgPrint( + _In_z_ _Printf_format_string_ PSTR Format, + ... + ); + +NTSYSAPI +ULONG +STDAPIVCALLTYPE +DbgPrintEx( + _In_ ULONG ComponentId, + _In_ ULONG Level, + _In_z_ _Printf_format_string_ PSTR Format, + ... + ); + +NTSYSAPI +ULONG +NTAPI +vDbgPrintEx( + _In_ ULONG ComponentId, + _In_ ULONG Level, + _In_z_ PCH Format, + _In_ va_list arglist + ); + +NTSYSAPI +ULONG +NTAPI +vDbgPrintExWithPrefix( + _In_z_ PCH Prefix, + _In_ ULONG ComponentId, + _In_ ULONG Level, + _In_z_ PCH Format, + _In_ va_list arglist + ); + +NTSYSAPI +NTSTATUS +NTAPI +DbgQueryDebugFilterState( + _In_ ULONG ComponentId, + _In_ ULONG Level + ); + +NTSYSAPI +NTSTATUS +NTAPI +DbgSetDebugFilterState( + _In_ ULONG ComponentId, + _In_ ULONG Level, + _In_ BOOLEAN State + ); + +NTSYSAPI +ULONG +NTAPI +DbgPrompt( + _In_ PCH Prompt, + _Out_writes_bytes_(Length) PCH Response, + _In_ ULONG Length + ); + // Definitions typedef struct _DBGKM_EXCEPTION @@ -113,8 +209,6 @@ typedef struct _DBGUI_WAIT_STATE_CHANGE } StateInfo; } DBGUI_WAIT_STATE_CHANGE, *PDBGUI_WAIT_STATE_CHANGE; -// System calls - #define DEBUG_READ_EVENT 0x0001 #define DEBUG_PROCESS_ASSIGN 0x0002 #define DEBUG_SET_INFORMATION 0x0004 @@ -132,6 +226,8 @@ typedef enum _DEBUGOBJECTINFOCLASS MaxDebugObjectInfoClass } DEBUGOBJECTINFOCLASS, *PDEBUGOBJECTINFOCLASS; +// System calls + NTSYSCALLAPI NTSTATUS NTAPI @@ -255,14 +351,12 @@ DbgUiIssueRemoteBreakin( _In_ HANDLE Process ); -struct _DEBUG_EVENT; - NTSYSAPI NTSTATUS NTAPI DbgUiConvertStateChangeStructure( _In_ PDBGUI_WAIT_STATE_CHANGE StateChange, - _Out_ struct _DEBUG_EVENT *DebugEvent + _Out_ LPDEBUG_EVENT DebugEvent ); struct _EVENT_FILTER_DESCRIPTOR; diff --git a/phnt/include/ntexapi.h b/phnt/include/ntexapi.h index 2ce271561639..7a793240c52a 100644 --- a/phnt/include/ntexapi.h +++ b/phnt/include/ntexapi.h @@ -265,6 +265,27 @@ NtSetDriverEntryOrder( _In_ ULONG Count ); +typedef enum _FILTER_BOOT_OPTION_OPERATION +{ + FilterBootOptionOperationOpenSystemStore, + FilterBootOptionOperationSetElement, + FilterBootOptionOperationDeleteElement, + FilterBootOptionOperationMax +} FILTER_BOOT_OPTION_OPERATION; + +#if (PHNT_VERSION >= PHNT_THRESHOLD) +NTSYSCALLAPI +NTSTATUS +NTAPI +NtFilterBootOption( + _In_ FILTER_BOOT_OPTION_OPERATION FilterOperation, + _In_ ULONG ObjectType, + _In_ ULONG ElementType, + _In_reads_bytes_opt_(DataSize) PVOID Data, + _In_ ULONG DataSize + ); +#endif + #endif // Event @@ -1386,7 +1407,7 @@ typedef enum _SYSTEM_INFORMATION_CLASS SystemHardwareSecurityTestInterfaceResultsInformation, SystemSingleModuleInformation, // q: SYSTEM_SINGLE_MODULE_INFORMATION SystemAllowedCpuSetsInformation, - SystemDmaProtectionInformation, // q: SYSTEM_DMA_PROTECTION_INFORMATION + SystemVsmProtectionInformation, // q: SYSTEM_VSM_PROTECTION_INFORMATION (previously SystemDmaProtectionInformation) SystemInterruptCpuSetsInformation, // q: SYSTEM_INTERRUPT_CPU_SET_INFORMATION // 170 SystemSecureBootPolicyFullInformation, // q: SYSTEM_SECUREBOOT_POLICY_FULL_INFORMATION SystemCodeIntegrityPolicyFullInformation, @@ -2954,11 +2975,12 @@ typedef struct _SYSTEM_TPM_INFORMATION } SYSTEM_TPM_INFORMATION, *PSYSTEM_TPM_INFORMATION; // private -typedef struct _SYSTEM_DMA_PROTECTION_INFORMATION +typedef struct _SYSTEM_VSM_PROTECTION_INFORMATION { BOOLEAN DmaProtectionsAvailable; BOOLEAN DmaProtectionsInUse; -} SYSTEM_DMA_PROTECTION_INFORMATION, *PSYSTEM_DMA_PROTECTION_INFORMATION; + BOOLEAN HardwareMbecAvailable; // REDSTONE4 (CVE-2018-3639) +} SYSTEM_VSM_PROTECTION_INFORMATION, *PSYSTEM_VSM_PROTECTION_INFORMATION; // private typedef struct _SYSTEM_CODEINTEGRITYPOLICY_INFORMATION @@ -2977,6 +2999,7 @@ typedef struct _SYSTEM_ISOLATED_USER_MODE_INFORMATION BOOLEAN HvciStrictMode : 1; BOOLEAN DebugEnabled : 1; BOOLEAN FirmwarePageProtection : 1; + BOOLEAN EncryptionKeyAvailable : 1; BOOLEAN SpareFlags : 1; BOOLEAN TrustletRunning : 1; BOOLEAN SpareFlags2 : 1; @@ -3204,7 +3227,12 @@ typedef struct _SYSTEM_SPECULATION_CONTROL_INFORMATION ULONG IbrsPresent : 1; ULONG StibpPresent : 1; ULONG SmepPresent : 1; - ULONG Reserved : 24; + ULONG MemoryDisambiguationDisableAvailable : 1; // REDSTONE4 (CVE-2018-3639) + ULONG MemoryDisambiguationDisableSupported : 1; + ULONG MemoryDisambiguationDisabledSystemWide : 1; + ULONG MemoryDisambiguationDisabledKernel : 1; + ULONG MemoryDisambiguationDisableRequired : 1; + ULONG Reserved : 19; }; }; } SYSTEM_SPECULATION_CONTROL_INFORMATION, *PSYSTEM_SPECULATION_CONTROL_INFORMATION; diff --git a/phnt/include/ntldr.h b/phnt/include/ntldr.h index d2963786de77..c9a7dfdc926a 100644 --- a/phnt/include/ntldr.h +++ b/phnt/include/ntldr.h @@ -108,23 +108,33 @@ typedef enum _LDR_DLL_LOAD_REASON } LDR_DLL_LOAD_REASON, *PLDR_DLL_LOAD_REASON; #define LDRP_PACKAGED_BINARY 0x00000001 +#define LDRP_STATIC_LINK 0x00000002 #define LDRP_IMAGE_DLL 0x00000004 #define LDRP_LOAD_IN_PROGRESS 0x00001000 +#define LDRP_UNLOAD_IN_PROGRESS 0x00002000 #define LDRP_ENTRY_PROCESSED 0x00004000 +#define LDRP_ENTRY_INSERTED 0x00008000 +#define LDRP_CURRENT_LOAD 0x00010000 +#define LDRP_FAILED_BUILTIN_LOAD 0x00020000 #define LDRP_DONT_CALL_FOR_THREADS 0x00040000 #define LDRP_PROCESS_ATTACH_CALLED 0x00080000 -#define LDRP_PROCESS_ATTACH_FAILED 0x00100000 +#define LDRP_DEBUG_SYMBOLS_LOADED 0x00100000 #define LDRP_IMAGE_NOT_AT_BASE 0x00200000 // Vista and below #define LDRP_COR_IMAGE 0x00400000 -#define LDRP_DONT_RELOCATE 0x00800000 +#define LDRP_DONT_RELOCATE 0x00800000 // LDR_COR_OWNS_UNMAP +#define LDRP_SYSTEM_MAPPED 0x01000000 +#define LDRP_IMAGE_VERIFYING 0x02000000 +#define LDRP_DRIVER_DEPENDENT_DLL 0x04000000 +#define LDRP_ENTRY_NATIVE 0x08000000 #define LDRP_REDIRECTED 0x10000000 +#define LDRP_NON_PAGED_DEBUG_INFO 0x20000000 +#define LDRP_MM_LOADED 0x40000000 #define LDRP_COMPAT_DATABASE_PROCESSED 0x80000000 -// Use the size of the structure as it was in Windows XP. #define LDR_DATA_TABLE_ENTRY_SIZE_WINXP FIELD_OFFSET(LDR_DATA_TABLE_ENTRY, DdagNode) #define LDR_DATA_TABLE_ENTRY_SIZE_WIN7 FIELD_OFFSET(LDR_DATA_TABLE_ENTRY, BaseNameHashValue) #define LDR_DATA_TABLE_ENTRY_SIZE_WIN8 FIELD_OFFSET(LDR_DATA_TABLE_ENTRY, ImplicitPathOptions) -#define LDR_DATA_TABLE_ENTRY_SIZE sizeof(LDR_DATA_TABLE_ENTRY) +#define LDR_DATA_TABLE_ENTRY_SIZE_WIN10 sizeof(LDR_DATA_TABLE_ENTRY) // symbols typedef struct _LDR_DATA_TABLE_ENTRY @@ -181,7 +191,7 @@ typedef struct _LDR_DATA_TABLE_ENTRY LIST_ENTRY HashLinks; ULONG TimeDateStamp; struct _ACTIVATION_CONTEXT *EntryPointActivationContext; - PVOID Lock; + PVOID Lock; // RtlAcquireSRWLockExclusive PLDR_DDAG_NODE DdagNode; LIST_ENTRY NodeModuleLink; struct _LDRP_LOAD_CONTEXT *LoadContext; @@ -199,9 +209,9 @@ typedef struct _LDR_DATA_TABLE_ENTRY UCHAR SigningLevel; // since REDSTONE2 } LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY; -#define LDR_IS_DATAFILE(DllHandle) (((ULONG_PTR)(DllHandle)) & (ULONG_PTR)1) +#define LDR_IS_DATAFILE(DllHandle) (((ULONG_PTR)(DllHandle)) & (ULONG_PTR)1) #define LDR_IS_IMAGEMAPPING(DllHandle) (((ULONG_PTR)(DllHandle)) & (ULONG_PTR)2) -#define LDR_IS_RESOURCE(DllHandle) (LDR_IS_IMAGEMAPPING(DllHandle) || LDR_IS_DATAFILE(DllHandle)) +#define LDR_IS_RESOURCE(DllHandle) (LDR_IS_IMAGEMAPPING(DllHandle) || LDR_IS_DATAFILE(DllHandle)) NTSYSAPI NTSTATUS @@ -238,7 +248,7 @@ NTSTATUS NTAPI LdrGetDllHandleEx( _In_ ULONG Flags, - _In_opt_ PCWSTR DllPath, + _In_opt_ PWSTR DllPath, _In_opt_ PULONG DllCharacteristics, _In_ PUNICODE_STRING DllName, _Out_opt_ PVOID *DllHandle @@ -250,7 +260,7 @@ NTSYSAPI NTSTATUS NTAPI LdrGetDllHandleByMapping( - _In_ PVOID Base, + _In_ PVOID BaseAddress, _Out_ PVOID *DllHandle ); #endif @@ -267,6 +277,33 @@ LdrGetDllHandleByName( ); #endif +#if (PHNT_VERSION >= PHNT_WIN8) +// rev +NTSYSAPI +NTSTATUS +NTAPI +LdrGetDllFullName( + _In_ PVOID DllHandle, + _Out_ PUNICODE_STRING FullDllName + ); + +// rev +NTSYSAPI +NTSTATUS +NTAPI +LdrGetDllDirectory( + _Out_ PUNICODE_STRING DllDirectory + ); + +// rev +NTSYSAPI +NTSTATUS +NTAPI +LdrSetDllDirectory( + _In_ PUNICODE_STRING DllDirectory + ); +#endif + #define LDR_ADDREF_DLL_PIN 0x00000001 NTSYSAPI @@ -304,6 +341,15 @@ LdrGetProcedureAddressEx( ); #endif +NTSYSAPI +NTSTATUS +NTAPI +LdrGetKnownDllSectionHandle( + _In_ PCWSTR DllName, + _In_ BOOLEAN KnownDlls32, + _Out_ PHANDLE Section + ); + #if (PHNT_VERSION >= PHNT_THRESHOLD) // rev NTSYSAPI @@ -513,17 +559,7 @@ LdrUnregisterDllNotification( // private typedef struct _PS_MITIGATION_OPTIONS_MAP { - union - { - ULONG_PTR Map[2]; // REDSTONE2 - //struct - //{ - // ULONG_PTR Depth : 16; // REDSTONE3 - // ULONG_PTR Sequence : 48; - // ULONG_PTR Reserved : 4; - // ULONG_PTR NextEntry : 60; - //}; - }; + ULONG_PTR Map[2]; } PS_MITIGATION_OPTIONS_MAP, *PPS_MITIGATION_OPTIONS_MAP; // private @@ -617,7 +653,7 @@ NTSYSAPI NTSTATUS NTAPI LdrAccessResource( - _In_ PVOID BaseAddress, + _In_ PVOID DllHandle, _In_ PIMAGE_RESOURCE_DATA_ENTRY ResourceDataEntry, _Out_opt_ PVOID *ResourceBuffer, _Out_opt_ ULONG *ResourceLength @@ -639,7 +675,7 @@ NTSYSAPI NTSTATUS NTAPI LdrFindResource_U( - _In_ PVOID BaseAddress, + _In_ PVOID DllHandle, _In_ PLDR_RESOURCE_INFO ResourceInfo, _In_ ULONG Level, _Out_ PIMAGE_RESOURCE_DATA_ENTRY *ResourceDataEntry @@ -649,7 +685,7 @@ NTSYSAPI NTSTATUS NTAPI LdrFindResourceDirectory_U( - _In_ PVOID BaseAddress, + _In_ PVOID DllHandle, _In_ PLDR_RESOURCE_INFO ResourceInfo, _In_ ULONG Level, _Out_ PIMAGE_RESOURCE_DIRECTORY *ResourceDirectory @@ -680,7 +716,7 @@ NTSYSAPI NTSTATUS NTAPI LdrEnumResources( - _In_ PVOID BaseAddress, + _In_ PVOID DllHandle, _In_ PLDR_RESOURCE_INFO ResourceInfo, _In_ ULONG Level, _Inout_ ULONG *ResourceCount, @@ -691,7 +727,7 @@ NTSYSAPI NTSTATUS NTAPI LdrFindEntryForAddress( - _In_ PVOID BaseAddress, + _In_ PVOID DllHandle, _Out_ PLDR_DATA_TABLE_ENTRY *Entry ); @@ -801,6 +837,105 @@ LdrQueryImageFileExecutionOptionsEx( _In_ BOOLEAN Wow64 ); +// private +typedef struct _DELAYLOAD_PROC_DESCRIPTOR +{ + ULONG ImportDescribedByName; + union + { + PCSTR Name; + ULONG Ordinal; + } Description; +} DELAYLOAD_PROC_DESCRIPTOR, *PDELAYLOAD_PROC_DESCRIPTOR; + +// private +typedef struct _DELAYLOAD_INFO +{ + ULONG Size; + PCIMAGE_DELAYLOAD_DESCRIPTOR DelayloadDescriptor; + PIMAGE_THUNK_DATA ThunkAddress; + PCSTR TargetDllName; + DELAYLOAD_PROC_DESCRIPTOR TargetApiDescriptor; + PVOID TargetModuleBase; + PVOID Unused; + ULONG LastError; +} DELAYLOAD_INFO, *PDELAYLOAD_INFO; + +// private +typedef PVOID (NTAPI *PDELAYLOAD_FAILURE_DLL_CALLBACK)( + _In_ ULONG NotificationReason, + _In_ PDELAYLOAD_INFO DelayloadInfo + ); + +// rev +typedef PVOID (NTAPI *PDELAYLOAD_FAILURE_SYSTEM_ROUTINE)( + _In_ PCSTR DllName, + _In_ PCSTR ProcName + ); + +// rev +NTSYSAPI +PVOID +NTAPI +LdrResolveDelayLoadedAPI( + _In_ PVOID ParentModuleBase, + _In_ PCIMAGE_DELAYLOAD_DESCRIPTOR DelayloadDescriptor, + _In_opt_ PDELAYLOAD_FAILURE_DLL_CALLBACK FailureDllHook, + _In_opt_ PDELAYLOAD_FAILURE_SYSTEM_ROUTINE FailureSystemHook, // kernel32.DelayLoadFailureHook + _Out_ PIMAGE_THUNK_DATA ThunkAddress, + _Reserved_ ULONG Flags + ); + +// rev +NTSYSAPI +NTSTATUS +NTAPI +LdrResolveDelayLoadsFromDll( + _In_ PVOID ParentBase, + _In_ PCSTR TargetDllName, + _Reserved_ ULONG Flags + ); + +// rev +NTSYSAPI +NTSTATUS +NTAPI +LdrSetDefaultDllDirectories( + _In_ ULONG DirectoryFlags + ); + +// rev +NTSYSAPI +NTSTATUS +NTAPI +LdrShutdownProcess( + VOID + ); + +// rev +NTSYSAPI +NTSTATUS +NTAPI +LdrShutdownThread( + VOID + ); + +// rev +NTSYSAPI +NTSTATUS +NTAPI +LdrSetImplicitPathOptions( + _In_ ULONG ImplicitPathOptions + ); + +// rev +NTSYSAPI +BOOLEAN +NTAPI +LdrControlFlowGuardEnforced( + VOID + ); + #endif // (PHNT_MODE != PHNT_MODE_KERNEL) #endif diff --git a/phnt/include/ntnls.h b/phnt/include/ntnls.h index 390933a7c077..8795b3d06f59 100644 --- a/phnt/include/ntnls.h +++ b/phnt/include/ntnls.h @@ -47,4 +47,8 @@ typedef struct _NLSTABLEINFO PUSHORT LowerCaseTable; } NLSTABLEINFO, *PNLSTABLEINFO; +NTSYSAPI USHORT NlsAnsiCodePage; +NTSYSAPI BOOLEAN NlsMbCodePageTag; +NTSYSAPI BOOLEAN NlsMbOemCodePageTag; + #endif diff --git a/phnt/include/ntrtl.h b/phnt/include/ntrtl.h index e0940837d151..3092ca1d9150 100644 --- a/phnt/include/ntrtl.h +++ b/phnt/include/ntrtl.h @@ -967,7 +967,7 @@ NTSYSAPI VOID NTAPI RtlCheckForOrphanedCriticalSections( - _In_ HANDLE hThread + _In_ HANDLE ThreadHandle ); // Resources @@ -1566,8 +1566,8 @@ NTSYSAPI BOOLEAN NTAPI RtlPrefixUnicodeString( - _In_ PCUNICODE_STRING String1, - _In_ PCUNICODE_STRING String2, + _In_ PUNICODE_STRING String1, + _In_ PUNICODE_STRING String2, _In_ BOOLEAN CaseInSensitive ); @@ -1577,8 +1577,20 @@ NTSYSAPI BOOLEAN NTAPI RtlSuffixUnicodeString( - _In_ PCUNICODE_STRING String1, - _In_ PCUNICODE_STRING String2, + _In_ PUNICODE_STRING String1, + _In_ PUNICODE_STRING String2, + _In_ BOOLEAN CaseInSensitive + ); +#endif + +#if (PHNT_VERSION >= PHNT_THRESHOLD) +_Must_inspect_result_ +NTSYSAPI +PWCHAR +NTAPI +RtlFindUnicodeSubstring( + _In_ PUNICODE_STRING FullString, + _In_ PUNICODE_STRING SearchString, _In_ BOOLEAN CaseInSensitive ); #endif @@ -1890,7 +1902,7 @@ RtlInitNlsTables( _In_ PUSHORT AnsiNlsBase, _In_ PUSHORT OemNlsBase, _In_ PUSHORT LanguageNlsBase, - _Out_ PNLSTABLEINFO TableInfo + _Out_ PNLSTABLEINFO TableInfo // PCPTABLEINFO? ); NTSYSAPI @@ -1963,6 +1975,19 @@ RtlIsNameInExpression( ); #endif +#if (PHNT_VERSION >= PHNT_REDSTONE4) +// rev +NTSYSAPI +BOOLEAN +NTAPI +RtlIsNameInUnUpcasedExpression( + _In_ PUNICODE_STRING Expression, + _In_ PUNICODE_STRING Name, + _In_ BOOLEAN IgnoreCase, + _In_opt_ PWCH UpcaseTable + ); +#endif + NTSYSAPI BOOLEAN NTAPI @@ -1984,7 +2009,7 @@ NTSTATUS NTAPI RtlDnsHostNameToComputerName( _Out_ PUNICODE_STRING ComputerNameString, - _In_ PCUNICODE_STRING DnsHostNameString, + _In_ PUNICODE_STRING DnsHostNameString, _In_ BOOLEAN AllocateComputerNameString ); @@ -1996,6 +2021,20 @@ RtlStringFromGUID( _Out_ PUNICODE_STRING GuidString ); +#if (PHNT_VERSION >= PHNT_WINBLUE) + +// rev +NTSYSAPI +NTSTATUS +NTAPI +RtlStringFromGUIDEx( + _In_ PGUID Guid, + _Inout_ PUNICODE_STRING GuidString, + _In_ BOOLEAN AllocateGuidString + ); + +#endif + NTSYSAPI NTSTATUS NTAPI @@ -2005,6 +2044,7 @@ RtlGUIDFromString( ); #if (PHNT_VERSION >= PHNT_VISTA) + NTSYSAPI LONG NTAPI @@ -2012,6 +2052,40 @@ RtlCompareAltitudes( _In_ PUNICODE_STRING Altitude1, _In_ PUNICODE_STRING Altitude2 ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlIdnToAscii( + _In_ ULONG Flags, + _In_ PWSTR SourceString, + _In_ LONG SourceStringLength, + _Out_writes_to_(*DestinationStringLength, *DestinationStringLength) PWSTR DestinationString, + _Inout_ PLONG DestinationStringLength + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlIdnToUnicode( + _In_ ULONG Flags, + _In_ PWSTR SourceString, + _In_ LONG SourceStringLength, + _Out_writes_to_(*DestinationStringLength, *DestinationStringLength) PWSTR DestinationString, + _Inout_ PLONG DestinationStringLength + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlIdnToNameprepUnicode( + _In_ ULONG Flags, + _In_ PWSTR SourceString, + _In_ LONG SourceStringLength, + _Out_writes_to_(*DestinationStringLength, *DestinationStringLength) PWSTR DestinationString, + _Inout_ PLONG DestinationStringLength + ); + #endif // Prefix @@ -2352,6 +2426,13 @@ RtlGetLocaleFileMappingAddress( // PEB +NTSYSAPI +PPEB +NTAPI +RtlGetCurrentPeb( + VOID + ); + NTSYSAPI VOID NTAPI @@ -2658,6 +2739,23 @@ RtlSetThreadIsCritical( _In_ BOOLEAN CheckFlag ); +// rev +NTSYSAPI +BOOLEAN +NTAPI +RtlValidProcessProtection( + _In_ PS_PROTECTION ProcessProtection + ); + +// rev +NTSYSAPI +BOOLEAN +NTAPI +RtlTestProtectedAccess( + _In_ PS_PROTECTION Source, + _In_ PS_PROTECTION Target + ); + #if (PHNT_VERSION >= PHNT_REDSTONE3) // rev NTSYSAPI @@ -2722,6 +2820,18 @@ FORCEINLINE VOID RtlExitUserThread_R( #if (PHNT_VERSION >= PHNT_VISTA) +// rev +NTSYSAPI +BOOLEAN +NTAPI +RtlIsCurrentThreadAttachExempt( + VOID + ); + +#endif + +#if (PHNT_VERSION >= PHNT_VISTA) + // private NTSYSAPI NTSTATUS @@ -2745,6 +2855,29 @@ RtlFreeUserStack( #endif +// Extended thread context + +typedef struct _CONTEXT_CHUNK +{ + LONG Offset; // Offset may be negative. + ULONG Length; +} CONTEXT_CHUNK, *PCONTEXT_CHUNK; + +typedef struct _CONTEXT_EX +{ + CONTEXT_CHUNK All; + CONTEXT_CHUNK Legacy; + CONTEXT_CHUNK XState; +} CONTEXT_EX, *PCONTEXT_EX; + +#define CONTEXT_EX_LENGTH ALIGN_UP_BY(sizeof(CONTEXT_EX), PAGE_SIZE) +#define RTL_CONTEXT_EX_OFFSET(ContextEx, Chunk) ((ContextEx)->Chunk.Offset) +#define RTL_CONTEXT_EX_LENGTH(ContextEx, Chunk) ((ContextEx)->Chunk.Length) +#define RTL_CONTEXT_EX_CHUNK(Base, Layout, Chunk) ((PVOID)((PCHAR)(Base) + RTL_CONTEXT_EX_OFFSET(Layout, Chunk))) +#define RTL_CONTEXT_OFFSET(Context, Chunk) RTL_CONTEXT_EX_OFFSET((PCONTEXT_EX)(Context + 1), Chunk) +#define RTL_CONTEXT_LENGTH(Context, Chunk) RTL_CONTEXT_EX_LENGTH((PCONTEXT_EX)(Context + 1), Chunk) +#define RTL_CONTEXT_CHUNK(Context, Chunk) RTL_CONTEXT_EX_CHUNK((PCONTEXT_EX)(Context + 1), (PCONTEXT_EX)(Context + 1), Chunk) + NTSYSAPI VOID NTAPI @@ -2757,16 +2890,61 @@ RtlInitializeContext( ); NTSYSAPI -NTSTATUS +ULONG NTAPI -RtlRemoteCall( - _In_ HANDLE Process, - _In_ HANDLE Thread, - _In_ PVOID CallSite, - _In_ ULONG ArgumentCount, - _In_opt_ PULONG_PTR Arguments, - _In_ BOOLEAN PassContext, - _In_ BOOLEAN AlreadySuspended +RtlInitializeExtendedContext( + _Out_ PCONTEXT Context, + _In_ ULONG ContextFlags, + _Out_ PCONTEXT_EX* ContextEx + ); + +NTSYSAPI +ULONG +NTAPI +RtlCopyExtendedContext( + _Out_ PCONTEXT_EX Destination, + _In_ ULONG ContextFlags, + _In_ PCONTEXT_EX Source + ); + +NTSYSAPI +ULONG +NTAPI +RtlGetExtendedContextLength( + _In_ ULONG ContextFlags, + _Out_ PULONG ContextLength + ); + +NTSYSAPI +ULONG64 +NTAPI +RtlGetExtendedFeaturesMask( + _In_ PCONTEXT_EX ContextEx + ); + +NTSYSAPI +PVOID +NTAPI +RtlLocateExtendedFeature( + _In_ PCONTEXT_EX ContextEx, + _In_ ULONG FeatureId, + _Out_opt_ PULONG Length + ); + +NTSYSAPI +PCONTEXT +NTAPI +RtlLocateLegacyContext( + _In_ PCONTEXT_EX ContextEx, + _Out_opt_ PULONG Length + ); + +NTSYSAPI +VOID +NTAPI +RtlSetExtendedFeaturesMask( + __out PCONTEXT_EX ContextEx, + _Out_ ULONG64 FeatureMask ); #ifdef _WIN64 @@ -2791,6 +2969,19 @@ RtlWow64SetThreadContext( ); #endif +NTSYSAPI +NTSTATUS +NTAPI +RtlRemoteCall( + _In_ HANDLE Process, + _In_ HANDLE Thread, + _In_ PVOID CallSite, + _In_ ULONG ArgumentCount, + _In_opt_ PULONG_PTR Arguments, + _In_ BOOLEAN PassContext, + _In_ BOOLEAN AlreadySuspended + ); + // Vectored exception handlers NTSYSAPI @@ -2825,6 +3016,42 @@ RtlRemoveVectoredContinueHandler( // Runtime exception handling +typedef ULONG (NTAPI *PRTLP_UNHANDLED_EXCEPTION_FILTER)( + _In_ PEXCEPTION_POINTERS ExceptionInfo + ); + +NTSYSAPI +VOID +NTAPI +RtlSetUnhandledExceptionFilter( + _In_ PRTLP_UNHANDLED_EXCEPTION_FILTER UnhandledExceptionFilter + ); + +// rev +NTSYSAPI +LONG +NTAPI +RtlUnhandledExceptionFilter( + _In_ PEXCEPTION_POINTERS ExceptionPointers + ); + +// rev +NTSYSAPI +LONG +NTAPI +RtlUnhandledExceptionFilter2( + _In_ PEXCEPTION_POINTERS ExceptionPointers, + _In_ ULONG Flags + ); + +// rev +NTSYSAPI +LONG +NTAPI +RtlKnownExceptionFilter( + _In_ PEXCEPTION_POINTERS ExceptionPointers + ); + #ifdef _WIN64 // private @@ -2877,7 +3104,7 @@ NTSYSAPI PIMAGE_NT_HEADERS NTAPI RtlImageNtHeader( - _In_ PVOID Base + _In_ PVOID BaseOfImage ); #define RTL_IMAGE_NT_HEADER_EX_FLAG_NO_RANGE_CHECK 0x00000001 @@ -2887,7 +3114,7 @@ NTSTATUS NTAPI RtlImageNtHeaderEx( _In_ ULONG Flags, - _In_ PVOID Base, + _In_ PVOID BaseOfImage, _In_ ULONG64 Size, _Out_ PIMAGE_NT_HEADERS *OutHeaders ); @@ -2925,7 +3152,7 @@ PIMAGE_SECTION_HEADER NTAPI RtlImageRvaToSection( _In_ PIMAGE_NT_HEADERS NtHeaders, - _In_ PVOID Base, + _In_ PVOID BaseOfImage, _In_ ULONG Rva ); @@ -2934,11 +3161,38 @@ PVOID NTAPI RtlImageRvaToVa( _In_ PIMAGE_NT_HEADERS NtHeaders, - _In_ PVOID Base, + _In_ PVOID BaseOfImage, _In_ ULONG Rva, _Inout_opt_ PIMAGE_SECTION_HEADER *LastRvaSection ); +#if (PHNT_VERSION >= PHNT_THRESHOLD) + +// rev +NTSYSAPI +PVOID +NTAPI +RtlFindExportedRoutineByName( + _In_ PVOID BaseOfImage, + _In_ PSTR RoutineName + ); + +#endif + +#if (PHNT_VERSION >= PHNT_REDSTONE) + +// rev +NTSYSAPI +NTSTATUS +NTAPI +RtlGuardCheckLongJumpTarget( + _In_ PVOID PcValue, + _In_ BOOL IsFastFail, + _Out_ PBOOL IsLongJumpTarget + ); + +#endif + // Memory NTSYSAPI @@ -3091,9 +3345,13 @@ RtlSetEnvironmentStrings( _In_ SIZE_T NewEnvironmentSize ); -// Current directory and paths +// Directory and path support -typedef struct _RTLP_CURDIR_REF *PRTLP_CURDIR_REF; +typedef struct _RTLP_CURDIR_REF +{ + LONG ReferenceCount; + HANDLE DirectoryHandle; +} RTLP_CURDIR_REF, *PRTLP_CURDIR_REF; typedef struct _RTL_RELATIVE_NAME_U { @@ -3114,6 +3372,22 @@ typedef enum _RTL_PATH_TYPE RtlPathTypeRootLocalDevice } RTL_PATH_TYPE; +// Data exports (ntdll.lib/ntdllp.lib) + +NTSYSAPI PWSTR RtlNtdllName; +NTSYSAPI UNICODE_STRING RtlDosPathSeperatorsString; +NTSYSAPI UNICODE_STRING RtlAlternateDosPathSeperatorString; +NTSYSAPI UNICODE_STRING RtlNtPathSeperatorString; + +#ifndef PHNT_INLINE_SEPERATOR_STRINGS +#define RtlNtdllName L"ntdll.dll" +#define RtlDosPathSeperatorsString ((UNICODE_STRING)RTL_CONSTANT_STRING(L"\\/")) +#define RtlAlternateDosPathSeperatorString ((UNICODE_STRING)RTL_CONSTANT_STRING(L"/")) +#define RtlNtPathSeperatorString ((UNICODE_STRING)RTL_CONSTANT_STRING(L"\\")) +#endif + +// Path functions + NTSYSAPI RTL_PATH_TYPE NTAPI @@ -3128,6 +3402,13 @@ RtlIsDosDeviceName_U( _In_ PWSTR DosFileName ); +NTSYSAPI +ULONG +NTAPI +RtlIsDosDeviceName_Ustr( + _In_ PUNICODE_STRING DosFileName + ); + NTSYSAPI ULONG NTAPI @@ -3212,6 +3493,19 @@ RtlDosPathNameToNtPathName_U_WithStatus( ); #endif +#if (PHNT_VERSION >= PHNT_REDSTONE3) +// rev +NTSYSAPI +NTSTATUS +NTAPI +RtlDosLongPathNameToNtPathName_U_WithStatus( + _In_ PWSTR DosFileName, + _Out_ PUNICODE_STRING NtFileName, + _Out_opt_ PWSTR *FilePart, + _Out_opt_ PRTL_RELATIVE_NAME_U RelativeName + ); +#endif + #if (PHNT_VERSION >= PHNT_WS03) NTSYSAPI BOOLEAN @@ -3236,6 +3530,19 @@ RtlDosPathNameToRelativeNtPathName_U_WithStatus( ); #endif +#if (PHNT_VERSION >= PHNT_REDSTONE3) +// rev +NTSYSAPI +NTSTATUS +NTAPI +RtlDosLongPathNameToRelativeNtPathName_U_WithStatus( + _In_ PWSTR DosFileName, + _Out_ PUNICODE_STRING NtFileName, + _Out_opt_ PWSTR *FilePart, + _Out_opt_ PRTL_RELATIVE_NAME_U RelativeName + ); +#endif + #if (PHNT_VERSION >= PHNT_WS03) NTSYSAPI VOID @@ -3283,22 +3590,125 @@ RtlDoesFileExists_U( _In_ PWSTR FileName ); -#if (PHNT_VERSION >= PHNT_REDSTONE2) NTSYSAPI -PCWSTR +NTSTATUS NTAPI -RtlGetNtSystemRoot( - VOID +RtlGetLengthWithoutLastFullDosOrNtPathElement( + _Reserved_ ULONG Flags, + _In_ PUNICODE_STRING PathString, + _Out_ PULONG Length ); -#endif -// Heaps +NTSYSAPI +NTSTATUS +NTAPI +RtlGetLengthWithoutTrailingPathSeperators( + _Reserved_ ULONG Flags, + _In_ PUNICODE_STRING PathString, + _Out_ PULONG Length + ); -typedef struct _RTL_HEAP_ENTRY +typedef struct _GENERATE_NAME_CONTEXT { - SIZE_T Size; - USHORT Flags; - USHORT AllocatorBackTraceIndex; + USHORT Checksum; + BOOLEAN CheckSumInserted; + UCHAR NameLength; + WCHAR NameBuffer[8]; + ULONG ExtensionLength; + WCHAR ExtensionBuffer[4]; + ULONG LastIndexValue; +} GENERATE_NAME_CONTEXT, *PGENERATE_NAME_CONTEXT; + +// private +NTSYSAPI +NTSTATUS +NTAPI +RtlGenerate8dot3Name( + _In_ PUNICODE_STRING Name, + _In_ BOOLEAN AllowExtendedCharacters, + _In_ PGENERATE_NAME_CONTEXT Context, + _Out_ PUNICODE_STRING Name8dot3 + ); + +#if (PHNT_VERSION >= PHNT_WIN8) + +// private +NTSYSAPI +NTSTATUS +NTAPI +RtlComputePrivatizedDllName_U( + _In_ PUNICODE_STRING DllName, + _Out_ PUNICODE_STRING RealName, + _Out_ PUNICODE_STRING LocalName + ); + +// rev +NTSYSAPI +BOOLEAN +NTAPI +RtlGetSearchPath( + _Out_ PWSTR *SearchPath + ); + +// rev +NTSYSAPI +NTSTATUS +NTAPI +RtlSetSearchPathMode( + _In_ ULONG Flags + ); + +// rev +NTSYSAPI +PWSTR +NTAPI +RtlGetExePath( + VOID + ); + +#endif + +#if (PHNT_VERSION >= PHNT_REDSTONE2) + +// private +NTSYSAPI +PWSTR +NTAPI +RtlGetNtSystemRoot( + VOID + ); + +// rev +NTSYSAPI +BOOLEAN +NTAPI +RtlAreLongPathsEnabled( + VOID + ); + +#endif + +NTSYSAPI +BOOLEAN +NTAPI +RtlIsThreadWithinLoaderCallout( + VOID + ); + +NTSYSAPI +BOOLEAN +NTAPI +RtlDllShutdownInProgress( + VOID + ); + +// Heaps + +typedef struct _RTL_HEAP_ENTRY +{ + SIZE_T Size; + USHORT Flags; + USHORT AllocatorBackTraceIndex; union { struct @@ -3780,6 +4190,13 @@ RtlDetectHeapLeaks( ); #endif +NTSYSAPI +VOID +NTAPI +RtlFlushHeaps( + VOID + ); + // Memory zones // begin_private @@ -3950,7 +4367,7 @@ RtlSetCurrentTransaction( // LUIDs -FORCEINLINE BOOLEAN RtlIsEqualLuid( +FORCEINLINE BOOLEAN RtlIsEqualLuid( // RtlEqualLuid _In_ PLUID L1, _In_ PLUID L2 ) @@ -4000,6 +4417,45 @@ RtlCopyLuid( _In_ PLUID SourceLuid ); +// ros +NTSYSAPI +VOID +NTAPI +RtlCopyLuidAndAttributesArray( + _In_ ULONG Count, + _In_ PLUID_AND_ATTRIBUTES Src, + _In_ PLUID_AND_ATTRIBUTES Dest + ); + +// Byte swap routines. + +#ifndef PHNT_RTL_BYTESWAP +#define RtlUshortByteSwap(_x) _byteswap_ushort((USHORT)(_x)) +#define RtlUlongByteSwap(_x) _byteswap_ulong((_x)) +#define RtlUlonglongByteSwap(_x) _byteswap_uint64((_x)) +#else +NTSYSAPI +USHORT +FASTCALL +RtlUshortByteSwap( + _In_ USHORT Source + ); + +NTSYSAPI +ULONG +FASTCALL +RtlUlongByteSwap( + _In_ ULONG Source + ); + +NTSYSAPI +ULONGLONG +FASTCALL +RtlUlonglongByteSwap( + _In_ ULONGLONG Source + ); +#endif + // Debugging // private @@ -4140,11 +4596,7 @@ typedef struct _PARSE_MESSAGE_CONTEXT va_list lpvArgStart; } PARSE_MESSAGE_CONTEXT, *PPARSE_MESSAGE_CONTEXT; -#define INIT_PARSE_MESSAGE_CONTEXT(ctx) \ - { \ - (ctx)->fFlags = 0; \ - } - +#define INIT_PARSE_MESSAGE_CONTEXT(ctx) { (ctx)->fFlags = 0; } #define TEST_PARSE_MESSAGE_CONTEXT_FLAG(ctx, flag) ((ctx)->fFlags & (flag)) #define SET_PARSE_MESSAGE_CONTEXT_FLAG(ctx, flag) ((ctx)->fFlags |= (flag)) #define CLEAR_PARSE_MESSAGE_CONTEXT_FLAG(ctx, flag) ((ctx)->fFlags &= ~(flag)) @@ -4216,6 +4668,7 @@ RtlRestoreLastWin32Error( _In_ LONG Win32Error ); +#define RTL_ERRORMODE_FAILCRITICALERRORS 0x0010 #define RTL_ERRORMODE_NOGPFAULTERRORBOX 0x0020 #define RTL_ERRORMODE_NOOPENFILEERRORBOX 0x0040 @@ -4248,6 +4701,19 @@ RtlReportException( ); #endif +#if (PHNT_VERSION >= PHNT_REDSTONE) +// rev +NTSYSAPI +NTSTATUS +NTAPI +RtlReportExceptionEx( + _In_ PEXCEPTION_RECORD ExceptionRecord, + _In_ PCONTEXT ContextRecord, + _In_ ULONG Flags, + _In_ PLARGE_INTEGER Timeout + ); +#endif + #if (PHNT_VERSION >= PHNT_VISTA) // private NTSYSAPI @@ -4331,7 +4797,7 @@ NTSYSAPI NTSTATUS NTAPI RtlComputeImportTableHash( - _In_ HANDLE hFile, + _In_ HANDLE FileHandle, _Out_writes_bytes_(16) PCHAR Hash, _In_ ULONG ImportTableHashRevision // must be 1 ); @@ -4621,12 +5087,6 @@ typedef struct _RTL_BITMAP PULONG Buffer; } RTL_BITMAP, *PRTL_BITMAP; -typedef struct _RTL_BITMAP_EX -{ - ULONG64 SizeOfBitMap; - PULONG64 Buffer; -} RTL_BITMAP_EX, *PRTL_BITMAP_EX; - NTSYSAPI VOID NTAPI @@ -4739,6 +5199,20 @@ RtlSetBits( _In_range_(0, BitMapHeader->SizeOfBitMap - StartingIndex) ULONG NumberToSet ); +NTSYSAPI +CCHAR +NTAPI +RtlFindMostSignificantBit( + _In_ ULONGLONG Set + ); + +NTSYSAPI +CCHAR +NTAPI +RtlFindLeastSignificantBit( + _In_ ULONGLONG Set + ); + typedef struct _RTL_BITMAP_RUN { ULONG StartingIndex; @@ -4838,6 +5312,17 @@ RtlFindLastBackwardRunClear( _Out_ PULONG StartingRunIndex ); +#if (PHNT_VERSION >= PHNT_VISTA) + +NTSYSAPI +ULONG +NTAPI +RtlNumberOfSetBitsUlongPtr( + _In_ ULONG_PTR Target + ); + +#endif + #if (PHNT_VERSION >= PHNT_WIN7) // rev @@ -4862,6 +5347,126 @@ RtlInterlockedSetBitRun( #endif +#if (PHNT_VERSION >= PHNT_WIN8) + +NTSYSAPI +VOID +NTAPI +RtlCopyBitMap( + _In_ PRTL_BITMAP Source, + _In_ PRTL_BITMAP Destination, + _In_range_(0, Destination->SizeOfBitMap - 1) ULONG TargetBit + ); + +NTSYSAPI +VOID +NTAPI +RtlExtractBitMap( + _In_ PRTL_BITMAP Source, + _In_ PRTL_BITMAP Destination, + _In_range_(0, Source->SizeOfBitMap - 1) ULONG TargetBit, + _In_range_(0, Source->SizeOfBitMap) ULONG NumberOfBits + ); + +NTSYSAPI +ULONG +NTAPI +RtlNumberOfClearBitsInRange( + _In_ PRTL_BITMAP BitMapHeader, + _In_ ULONG StartingIndex, + _In_ ULONG Length + ); + +NTSYSAPI +ULONG +NTAPI +RtlNumberOfSetBitsInRange( + _In_ PRTL_BITMAP BitMapHeader, + _In_ ULONG StartingIndex, + _In_ ULONG Length + ); + +#endif + + +#if (PHNT_VERSION >= PHNT_THRESHOLD) + +// private +typedef struct _RTL_BITMAP_EX +{ + ULONG64 SizeOfBitMap; + PULONG64 Buffer; +} RTL_BITMAP_EX, *PRTL_BITMAP_EX; + +// rev +NTSYSAPI +VOID +NTAPI +RtlInitializeBitMapEx( + _Out_ PRTL_BITMAP_EX BitMapHeader, + _In_ PULONG64 BitMapBuffer, + _In_ ULONG64 SizeOfBitMap + ); + +// rev +_Check_return_ +NTSYSAPI +BOOLEAN +NTAPI +RtlTestBitEx( + _In_ PRTL_BITMAP_EX BitMapHeader, + _In_range_(<, BitMapHeader->SizeOfBitMap) ULONG64 BitNumber + ); + +#if (PHNT_MODE == PHNT_MODE_KERNEL) +// rev +NTSYSAPI +VOID +NTAPI +RtlClearAllBitsEx( + _In_ PRTL_BITMAP_EX BitMapHeader + ); + +// rev +NTSYSAPI +VOID +NTAPI +RtlClearBitEx( + _In_ PRTL_BITMAP_EX BitMapHeader, + _In_range_(<, BitMapHeader->SizeOfBitMap) ULONG64 BitNumber + ); + +// rev +NTSYSAPI +VOID +NTAPI +RtlSetBitEx( + _In_ PRTL_BITMAP_EX BitMapHeader, + _In_range_(<, BitMapHeader->SizeOfBitMap) ULONG64 BitNumber + ); + +// rev +NTSYSAPI +ULONG64 +NTAPI +RtlFindSetBitsEx( + _In_ PRTL_BITMAP_EX BitMapHeader, + _In_ ULONG64 NumberToFind, + _In_ ULONG64 HintIndex + ); + +NTSYSAPI +ULONG64 +NTAPI +RtlFindSetBitsAndClearEx( + _In_ PRTL_BITMAP_EX BitMapHeader, + _In_ ULONG64 NumberToFind, + _In_ ULONG64 HintIndex + ); +#endif + +#endif + // Handle tables typedef struct _RTL_HANDLE_TABLE_ENTRY @@ -5042,6 +5647,14 @@ RtlEqualSid( _In_ PSID Sid2 ); +_Check_return_ +NTSYSAPI +BOOLEAN +RtlEqualPrefixSid( + _In_ PSID Sid1, + _In_ PSID Sid2 + ); + NTSYSAPI ULONG NTAPI @@ -5133,7 +5746,22 @@ RtlCopySid( _In_ PSID SourceSid ); +// ros +NTSYSAPI +NTSTATUS +NTAPI +RtlCopySidAndAttributesArray( + _In_ ULONG Count, + _In_ PSID_AND_ATTRIBUTES Src, + _In_ ULONG SidAreaSize, + _In_ PSID_AND_ATTRIBUTES Dest, + _In_ PSID SidArea, + _Out_ PSID *RemainingSidArea, + _Out_ PULONG RemainingSidAreaSize + ); + #if (PHNT_VERSION >= PHNT_VISTA) + NTSYSAPI NTSTATUS NTAPI @@ -5142,9 +5770,11 @@ RtlCreateServiceSid( _Out_writes_bytes_opt_(*ServiceSidLength) PSID ServiceSid, _Inout_ PULONG ServiceSidLength ); + #endif #if (PHNT_VERSION >= PHNT_VISTA) + // private NTSYSAPI NTSTATUS @@ -5152,8 +5782,23 @@ NTAPI RtlSidDominates( _In_ PSID Sid1, _In_ PSID Sid2, - _Out_ PBOOLEAN pbDominate + _Out_ PBOOLEAN Dominates + ); + +#endif + +#if (PHNT_VERSION >= PHNT_WINBLUE) + +// rev +NTSYSAPI +NTSTATUS +NTAPI +RtlSidDominatesForTrust( + _In_ PSID Sid1, + _In_ PSID Sid2, + _Out_ PBOOLEAN DominatesTrust // TokenProcessTrustLevel ); + #endif #if (PHNT_VERSION >= PHNT_VISTA) @@ -5164,11 +5809,9 @@ NTAPI RtlSidEqualLevel( _In_ PSID Sid1, _In_ PSID Sid2, - _Out_ PBOOLEAN pbEqual + _Out_ PBOOLEAN EqualLevel ); -#endif -#if (PHNT_VERSION >= PHNT_VISTA) // private NTSYSAPI NTSTATUS @@ -5176,7 +5819,7 @@ NTAPI RtlSidIsHigherLevel( _In_ PSID Sid1, _In_ PSID Sid2, - _Out_ PBOOLEAN pbHigher + _Out_ PBOOLEAN HigherLevel ); #endif @@ -5238,9 +5881,20 @@ RtlSidHashLookup( ); #endif -#if (PHNT_VERSION >= PHNT_REDSTONE2) +#if (PHNT_VERSION >= PHNT_VISTA) +// rev NTSYSAPI -NTSTATUS +BOOLEAN +NTAPI +RtlIsElevatedRid( + _In_ PSID_AND_ATTRIBUTES SidAttr + ); +#endif + +#if (PHNT_VERSION >= PHNT_REDSTONE2) +// rev +NTSYSAPI +NTSTATUS NTAPI RtlDeriveCapabilitySidsFromName( _Inout_ PUNICODE_STRING UnicodeString, @@ -5494,13 +6148,6 @@ RtlCreateAcl( _In_ ULONG AclRevision ); -NTSYSAPI -NTSTATUS -NTAPI -RtlDefaultNpAcl( - _Out_ PACL *Acl - ); - NTSYSAPI BOOLEAN NTAPI @@ -5721,6 +6368,15 @@ RtlAddMandatoryAce( ); #endif +// Named pipes + +NTSYSAPI +NTSTATUS +NTAPI +RtlDefaultNpAcl( + _Out_ PACL *Acl + ); + // Security objects NTSYSAPI @@ -5914,7 +6570,7 @@ NTSYSAPI NTSTATUS NTAPI RtlRemovePrivileges( - _In_ HANDLE hToken, + _In_ HANDLE TokenHandle, _In_ PULONG PrivilegesToKeep, _In_ ULONG PrivilegeCount ); @@ -5922,20 +6578,21 @@ RtlRemovePrivileges( #if (PHNT_VERSION >= PHNT_WIN8) +// rev NTSYSAPI NTSTATUS NTAPI RtlIsUntrustedObject( _In_opt_ HANDLE Handle, _In_opt_ PVOID Object, - _Out_ PBOOLEAN UntrustedObject + _Out_ PBOOLEAN IsUntrustedObject ); NTSYSAPI ULONG NTAPI RtlQueryValidationRunlevel( - _In_opt_ PCUNICODE_STRING ComponentName + _In_opt_ PUNICODE_STRING ComponentName ); #endif @@ -6002,8 +6659,31 @@ RtlVerifyVersionInfo( _In_ ULONGLONG ConditionMask ); +// rev +NTSYSAPI +VOID +NTAPI +RtlGetNtVersionNumbers( + _Out_opt_ PULONG NtMajorVersion, + _Out_opt_ PULONG NtMinorVersion, + _Out_opt_ PULONG NtBuildNumber + ); + +// private +NTSYSAPI +BOOLEAN +WINAPI +RtlGetProductInfo( + _In_ ULONG OSMajorVersion, + _In_ ULONG OSMinorVersion, + _In_ ULONG SpMajorVersion, + _In_ ULONG SpMinorVersion, + _Out_ PULONG ReturnedProductType // PRODUCT_PROFESSIONAL + ); + // System information +// rev NTSYSAPI ULONG NTAPI @@ -6011,22 +6691,25 @@ RtlGetNtGlobalFlags( VOID ); +#if (PHNT_VERSION >= PHNT_REDSTONE) +// rev NTSYSAPI BOOLEAN NTAPI RtlGetNtProductType( _Out_ PNT_PRODUCT_TYPE NtProductType ); +#endif -// rev +#if (PHNT_VERSION >= PHNT_REDSTONE2) +// private NTSYSAPI -VOID +ULONG NTAPI -RtlGetNtVersionNumbers( - _Out_opt_ PULONG pNtMajorVersion, - _Out_opt_ PULONG pNtMinorVersion, - _Out_opt_ PULONG pNtBuildNumber +RtlGetSuiteMask( + VOID ); +#endif // Thread pool (old) @@ -6075,6 +6758,42 @@ RtlSetIoCompletionCallback( _In_ ULONG Flags ); +typedef NTSTATUS (NTAPI *PRTL_START_POOL_THREAD)( + _In_ PTHREAD_START_ROUTINE Function, + _In_ PVOID Parameter, + _Out_ PHANDLE ThreadHandle + ); + +typedef NTSTATUS (NTAPI *PRTL_EXIT_POOL_THREAD)( + _In_ NTSTATUS ExitStatus + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlSetThreadPoolStartFunc( + _In_ PRTL_START_POOL_THREAD StartPoolThread, + _In_ PRTL_EXIT_POOL_THREAD ExitPoolThread + ); + +NTSYSAPI +VOID +NTAPI +RtlUserThreadStart( + _In_ PTHREAD_START_ROUTINE Function, + _In_ PVOID Parameter + ); + +NTSYSAPI +VOID +NTAPI +LdrInitializeThunk( + _In_ PCONTEXT ContextRecord, + _In_ PVOID Parameter + ); + +// Timer support + NTSYSAPI NTSTATUS NTAPI @@ -6089,7 +6808,7 @@ RtlCreateTimer( _In_ HANDLE TimerQueueHandle, _Out_ PHANDLE Handle, _In_ WAITORTIMERCALLBACKFUNC Function, - _In_ PVOID Context, + _In_opt_ PVOID Context, _In_ ULONG DueTime, _In_ ULONG Period, _In_ ULONG Flags @@ -6211,6 +6930,18 @@ RtlQueryRegistryValues( _In_opt_ PVOID Environment ); +// rev +NTSYSAPI +NTSTATUS +NTAPI +RtlQueryRegistryValuesEx( + _In_ ULONG RelativeTo, + _In_ PWSTR Path, + _In_ PRTL_QUERY_REGISTRY_TABLE QueryTable, + _In_ PVOID Context, + _In_opt_ PVOID Environment + ); + NTSYSAPI NTSTATUS NTAPI @@ -6232,108 +6963,11 @@ RtlDeleteRegistryValue( _In_ PWSTR ValueName ); -// Debugging - -NTSYSAPI -VOID -NTAPI -DbgUserBreakPoint( - VOID - ); - -NTSYSAPI -VOID -NTAPI -DbgBreakPoint( - VOID - ); - -NTSYSAPI -VOID -NTAPI -DbgBreakPointWithStatus( - _In_ ULONG Status - ); - -#define DBG_STATUS_CONTROL_C 1 -#define DBG_STATUS_SYSRQ 2 -#define DBG_STATUS_BUGCHECK_FIRST 3 -#define DBG_STATUS_BUGCHECK_SECOND 4 -#define DBG_STATUS_FATAL 5 -#define DBG_STATUS_DEBUG_CONTROL 6 -#define DBG_STATUS_WORKER 7 - -NTSYSAPI -ULONG -__cdecl -DbgPrint( - _In_z_ _Printf_format_string_ PSTR Format, - ... - ); - -NTSYSAPI -ULONG -__cdecl -DbgPrintEx( - _In_ ULONG ComponentId, - _In_ ULONG Level, - _In_z_ _Printf_format_string_ PSTR Format, - ... - ); - -NTSYSAPI -ULONG -NTAPI -vDbgPrintEx( - _In_ ULONG ComponentId, - _In_ ULONG Level, - _In_z_ PCH Format, - _In_ va_list arglist - ); - -NTSYSAPI -ULONG -NTAPI -vDbgPrintExWithPrefix( - _In_z_ PCH Prefix, - _In_ ULONG ComponentId, - _In_ ULONG Level, - _In_z_ PCH Format, - _In_ va_list arglist - ); - -NTSYSAPI -NTSTATUS -NTAPI -DbgQueryDebugFilterState( - _In_ ULONG ComponentId, - _In_ ULONG Level - ); - -NTSYSAPI -NTSTATUS -NTAPI -DbgSetDebugFilterState( - _In_ ULONG ComponentId, - _In_ ULONG Level, - _In_ BOOLEAN State - ); - -NTSYSAPI -ULONG -NTAPI -DbgPrompt( - _In_ PCH Prompt, - _Out_writes_bytes_(Length) PCH Response, - _In_ ULONG Length - ); - // Thread profiling #if (PHNT_VERSION >= PHNT_WIN7) -// begin_rev - +// rev NTSYSAPI NTSTATUS NTAPI @@ -6344,6 +6978,7 @@ RtlEnableThreadProfiling( _Out_ PVOID *PerformanceDataHandle ); +// rev NTSYSAPI NTSTATUS NTAPI @@ -6351,6 +6986,7 @@ RtlDisableThreadProfiling( _In_ PVOID PerformanceDataHandle ); +// rev NTSYSAPI NTSTATUS NTAPI @@ -6359,6 +6995,7 @@ RtlQueryThreadProfiling( _Out_ PBOOLEAN Enabled ); +// rev NTSYSAPI NTSTATUS NTAPI @@ -6368,8 +7005,6 @@ RtlReadThreadProfilingData( _Out_ PPERFORMANCE_DATA PerformanceData ); -// end_rev - #endif // WOW64 @@ -6412,13 +7047,6 @@ RtlWow64EnableFsRedirectionEx( // Misc. -NTSYSAPI -ULONG -NTAPI -RtlGetCurrentProcessorNumber( - VOID - ); - NTSYSAPI ULONG32 NTAPI @@ -6456,13 +7084,58 @@ RtlDecodeSystemPointer( _In_ PVOID Ptr ); +#if (PHNT_VERSION >= PHNT_THRESHOLD) +// rev +NTSYSAPI +NTSTATUS +NTAPI +RtlEncodeRemotePointer( + _In_ HANDLE ProcessHandle, + _In_ PVOID Pointer, + _Out_ PVOID *EncodedPointer + ); + +// rev +NTSYSAPI +NTSTATUS +NTAPI +RtlDecodeRemotePointer( + _In_ HANDLE ProcessHandle, + _In_ PVOID Pointer, + _Out_ PVOID *DecodedPointer + ); +#endif + +// rev NTSYSAPI BOOLEAN NTAPI -RtlIsThreadWithinLoaderCallout( +RtlIsProcessorFeaturePresent( + _In_ ULONG ProcessorFeature + ); + +// rev +NTSYSAPI +ULONG +NTAPI +RtlGetCurrentProcessorNumber( VOID ); +#if (PHNT_VERSION >= PHNT_THRESHOLD) + +// rev +NTSYSAPI +VOID +NTAPI +RtlGetCurrentProcessorNumberEx( + _Out_ PPROCESSOR_NUMBER ProcessorNumber + ); + +#endif + +// Stack support + NTSYSAPI VOID NTAPI @@ -6484,19 +7157,63 @@ RtlGetFrame( VOID ); -typedef ULONG (NTAPI *PRTLP_UNHANDLED_EXCEPTION_FILTER)( - struct _EXCEPTION_POINTERS *ExceptionInfo +#define RTL_STACK_WALKING_MODE_FRAMES_TO_SKIP_SHIFT 8 + +// private +NTSYSAPI +ULONG +NTAPI +RtlWalkFrameChain( + _Out_writes_(Count - (Flags >> RTL_STACK_WALKING_MODE_FRAMES_TO_SKIP_SHIFT)) PVOID *Callers, + _In_ ULONG Count, + _In_ ULONG Flags ); +// rev NTSYSAPI VOID NTAPI -RtlSetUnhandledExceptionFilter( - _In_ PRTLP_UNHANDLED_EXCEPTION_FILTER UnhandledExceptionFilter +RtlGetCallersAddress( // Use the intrinsic _ReturnAddress instead. + _Out_ PVOID *CallersAddress, + _Out_ PVOID *CallersCaller ); -// begin_private +#if (PHNT_VERSION >= PHNT_WIN7) + +NTSYSAPI +ULONG64 +NTAPI +RtlGetEnabledExtendedFeatures( + _In_ ULONG64 FeatureMask + ); + +#endif + +#if (PHNT_VERSION >= PHNT_REDSTONE4) + +// msdn +NTSYSAPI +ULONG64 +NTAPI +RtlGetEnabledExtendedAndSupervisorFeatures( + _In_ ULONG64 FeatureMask + ); + +// msdn +_Ret_maybenull_ +_Success_(return != NULL) +NTSYSAPI +PVOID +NTAPI +RtlLocateSupervisorFeature( + _In_ PXSAVE_AREA_HEADER XStateHeader, + _In_range_(XSTATE_AVX, MAXIMUM_XSTATE_FEATURES - 1) ULONG FeatureId, + _Out_opt_ PULONG Length + ); + +#endif +// private typedef union _RTL_ELEVATION_FLAGS { ULONG Flags; @@ -6510,17 +7227,19 @@ typedef union _RTL_ELEVATION_FLAGS } RTL_ELEVATION_FLAGS, *PRTL_ELEVATION_FLAGS; #if (PHNT_VERSION >= PHNT_VISTA) + +// private NTSYSAPI NTSTATUS NTAPI RtlQueryElevationFlags( _Out_ PRTL_ELEVATION_FLAGS Flags ); -#endif -// end_private +#endif #if (PHNT_VERSION >= PHNT_VISTA) + // private NTSYSAPI NTSTATUS @@ -6528,9 +7247,11 @@ NTAPI RtlRegisterThreadWithCsrss( VOID ); + #endif #if (PHNT_VERSION >= PHNT_VISTA) + // private NTSYSAPI NTSTATUS @@ -6538,9 +7259,11 @@ NTAPI RtlLockCurrentThread( VOID ); + #endif #if (PHNT_VERSION >= PHNT_VISTA) + // private NTSYSAPI NTSTATUS @@ -6548,9 +7271,11 @@ NTAPI RtlUnlockCurrentThread( VOID ); + #endif #if (PHNT_VERSION >= PHNT_VISTA) + // private NTSYSAPI NTSTATUS @@ -6558,9 +7283,11 @@ NTAPI RtlLockModuleSection( _In_ PVOID Address ); + #endif #if (PHNT_VERSION >= PHNT_VISTA) + // private NTSYSAPI NTSTATUS @@ -6568,6 +7295,7 @@ NTAPI RtlUnlockModuleSection( _In_ PVOID Address ); + #endif // begin_msdn:"Winternl" @@ -6837,4 +7565,517 @@ RtlSetImageMitigationPolicy( #endif +// session + +// rev +NTSYSAPI +ULONG +NTAPI +RtlGetCurrentServiceSessionId( + VOID + ); + +// private +NTSYSAPI +ULONG +NTAPI +RtlGetActiveConsoleId( + VOID + ); + +#if (PHNT_VERSION >= PHNT_REDSTONE) +// private +NTSYSAPI +ULONGLONG +NTAPI +RtlGetConsoleSessionForegroundProcessId( + VOID + ); +#endif + +// Appcontainer + +// rev +NTSYSAPI +NTSTATUS +NTAPI +RtlGetTokenNamedObjectPath( + _In_ HANDLE Token, + _In_opt_ PSID Sid, + _Out_ PUNICODE_STRING ObjectPath // RtlFreeUnicodeString + ); + +// rev +NTSYSAPI +NTSTATUS +NTAPI +RtlGetAppContainerNamedObjectPath( + _In_opt_ HANDLE Token, + _In_opt_ PSID AppContainerSid, + _In_ BOOLEAN RelativePath, + _Out_ PUNICODE_STRING ObjectPath // RtlFreeUnicodeString + ); + +// rev +NTSYSAPI +NTSTATUS +NTAPI +RtlGetAppContainerParent( + _In_ PSID AppContainerSid, + _Out_ PSID* AppContainerSidParent // RtlFreeSid + ); + +// rev +NTSYSAPI +NTSTATUS +NTAPI +RtlCheckSandboxedToken( + _In_opt_ HANDLE TokenHandle, + _Out_ PBOOLEAN IsSandboxed + ); + +// rev +NTSYSAPI +NTSTATUS +NTAPI +RtlCheckTokenCapability( + _In_opt_ HANDLE TokenHandle, + _In_ PSID CapabilitySidToCheck, + _Out_ PBOOLEAN HasCapability + ); + +// rev +NTSYSAPI +NTSTATUS +NTAPI +RtlCapabilityCheck( + _In_opt_ HANDLE TokenHandle, + _In_ PUNICODE_STRING CapabilityName, + _Out_ PBOOLEAN HasCapability + ); + +// rev +NTSYSAPI +NTSTATUS +NTAPI +RtlCheckTokenMembership( + _In_opt_ HANDLE TokenHandle, + _In_ PSID SidToCheck, + _Out_ PBOOLEAN IsMember + ); + +// rev +NTSYSAPI +NTSTATUS +NTAPI +RtlCheckTokenMembershipEx( + _In_opt_ HANDLE TokenHandle, + _In_ PSID SidToCheck, + _In_ ULONG Flags, // CTMF_VALID_FLAGS + _Out_ PBOOLEAN IsMember + ); + +// rev +NTSYSAPI +NTSTATUS +NTAPI +RtlIsParentOfChildAppContainer( + _In_ PSID ParentAppContainerSid, + _In_ PSID ChildAppContainerSid + ); + +// rev +NTSYSAPI +BOOLEAN +NTAPI +RtlIsCapabilitySid( + _In_ PSID Sid + ); + +// rev +NTSYSAPI +BOOLEAN +NTAPI +RtlIsPackageSid( + _In_ PSID Sid + ); + +// rev +NTSYSAPI +BOOLEAN +NTAPI +RtlIsValidProcessTrustLabelSid( + _In_ PSID Sid + ); + +NTSYSAPI +BOOLEAN +NTAPI +RtlIsStateSeparationEnabled( + VOID + ); + +typedef enum _APPCONTAINER_SID_TYPE +{ + NotAppContainerSidType, + ChildAppContainerSidType, + ParentAppContainerSidType, + InvalidAppContainerSidType, + MaxAppContainerSidType +} APPCONTAINER_SID_TYPE, *PAPPCONTAINER_SID_TYPE; + +// rev +NTSYSAPI +NTSTATUS +NTAPI +RtlGetAppContainerSidType( + _In_ PSID AppContainerSid, + _Out_ PAPPCONTAINER_SID_TYPE AppContainerSidType + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlFlsAlloc( + _In_ PFLS_CALLBACK_FUNCTION Callback, + _Out_ PULONG FlsIndex + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlFlsFree( + _In_ ULONG FlsIndex + ); + +typedef enum _STATE_LOCATION_TYPE +{ + LocationTypeRegistry, + LocationTypeFileSystem, + LocationTypeMaximum +} STATE_LOCATION_TYPE; + +// private +NTSYSAPI +NTSTATUS +NTAPI +RtlGetPersistedStateLocation( + _In_ PCWSTR SourceID, + _In_opt_ PCWSTR CustomValue, + _In_opt_ PCWSTR DefaultPath, + _In_ STATE_LOCATION_TYPE StateLocationType, + _Out_writes_bytes_to_opt_(BufferLengthIn, *BufferLengthOut) PWCHAR TargetPath, + _In_ ULONG BufferLengthIn, + _Out_opt_ PULONG BufferLengthOut + ); + +// msdn +NTSYSAPI +BOOLEAN +NTAPI +RtlIsCloudFilesPlaceholder( + _In_ ULONG FileAttributes, + _In_ ULONG ReparseTag + ); + +// msdn +NTSYSAPI +BOOLEAN +NTAPI +RtlIsPartialPlaceholder( + _In_ ULONG FileAttributes, + _In_ ULONG ReparseTag + ); + +// msdn +NTSYSAPI +NTSTATUS +NTAPI +RtlIsPartialPlaceholderFileHandle( + _In_ HANDLE FileHandle, + _Out_ PBOOLEAN IsPartialPlaceholder + ); + +// msdn +NTSYSAPI +NTSTATUS +NTAPI +RtlIsPartialPlaceholderFileInfo( + _In_ PVOID InfoBuffer, + _In_ FILE_INFORMATION_CLASS InfoClass, + _Out_ PBOOLEAN IsPartialPlaceholder + ); + +// rev +NTSYSAPI +BOOLEAN +NTAPI +RtlIsNonEmptyDirectoryReparsePointAllowed( + _In_ ULONG ReparseTag + ); + +// rev +NTSYSAPI +NTSTATUS +NTAPI +RtlAppxIsFileOwnedByTrustedInstaller( + _In_ HANDLE FileHandle, + _Out_ PBOOLEAN IsFileOwnedByTrustedInstaller + ); + +// rev +typedef struct _PS_PKG_CLAIM +{ + ULONGLONG Flags; + ULONGLONG Origin; +} PS_PKG_CLAIM, *PPS_PKG_CLAIM; + +NTSYSAPI +NTSTATUS +NTAPI +RtlQueryPackageClaims( + _In_ HANDLE TokenHandle, + _Out_writes_bytes_to_opt_(*PackageSize, *PackageSize) PWSTR PackageFullName, + _Inout_opt_ PSIZE_T PackageSize, + _Out_writes_bytes_to_opt_(*AppIdSize, *AppIdSize) PWSTR AppId, + _Inout_opt_ PSIZE_T AppIdSize, + _Out_opt_ PGUID DynamicId, + _Out_opt_ PPS_PKG_CLAIM PkgClaim, + _Out_opt_ PULONG64 AttributesPresent + ); + +// Protected policies + +// rev +NTSYSAPI +NTSTATUS +NTAPI +RtlQueryProtectedPolicy( + _In_ PGUID PolicyGuid, + _Out_ PULONG_PTR PolicyValue + ); + +// rev +NTSYSAPI +NTSTATUS +NTAPI +RtlSetProtectedPolicy( + _In_ PGUID PolicyGuid, + _In_ ULONG_PTR PolicyValue, + _Out_ PULONG_PTR OldPolicyValue + ); + +#if (PHNT_VERSION >= PHNT_REDSTONE) +// private +NTSYSAPI +BOOLEAN +NTAPI +RtlIsMultiSessionSku( + VOID + ); +#endif + +#if (PHNT_VERSION >= PHNT_REDSTONE) +// private +NTSYSAPI +BOOLEAN +NTAPI +RtlIsMultiUsersInSessionSku( + VOID + ); +#endif + +// private +typedef enum _RTL_BSD_ITEM_TYPE +{ + RtlBsdItemVersionNumber, + RtlBsdItemProductType, + RtlBsdItemAabEnabled, + RtlBsdItemAabTimeout, + RtlBsdItemBootGood, + RtlBsdItemBootShutdown, + RtlBsdSleepInProgress, + RtlBsdPowerTransition, + RtlBsdItemBootAttemptCount, + RtlBsdItemBootCheckpoint, + RtlBsdItemBootId, + RtlBsdItemShutdownBootId, + RtlBsdItemReportedAbnormalShutdownBootId, + RtlBsdItemErrorInfo, + RtlBsdItemPowerButtonPressInfo, + RtlBsdItemChecksum, + RtlBsdItemMax +} RTL_BSD_ITEM_TYPE; + +// private +typedef struct _RTL_BSD_ITEM +{ + RTL_BSD_ITEM_TYPE Type; + PVOID DataBuffer; + ULONG DataLength; +} RTL_BSD_ITEM, *PRTL_BSD_ITEM; + +// ros +NTSYSAPI +NTSTATUS +NTAPI +RtlCreateBootStatusDataFile( + VOID + ); + +// ros +NTSYSAPI +NTSTATUS +NTAPI +RtlLockBootStatusData( + _Out_ PHANDLE FileHandle + ); + +// ros +NTSYSAPI +NTSTATUS +NTAPI +RtlUnlockBootStatusData( + _In_ HANDLE FileHandle + ); + +// ros +NTSYSAPI +NTSTATUS +NTAPI +RtlGetSetBootStatusData( + _In_ HANDLE FileHandle, + _In_ BOOLEAN Read, + _In_ RTL_BSD_ITEM_TYPE DataClass, + _In_ PVOID Buffer, + _In_ ULONG BufferSize, + _Out_opt_ PULONG ReturnLength + ); + +// rev +NTSYSAPI +NTSTATUS +NTAPI +RtlCheckBootStatusIntegrity( + _In_ HANDLE FileHandle, + _Out_ PBOOLEAN Verified + ); + +// rev +NTSYSAPI +NTSTATUS +NTAPI +RtlCheckPortableOperatingSystem( + _Out_ PBOOLEAN IsPortable // VOID + ); + +// rev +NTSYSAPI +NTSTATUS +NTAPI +RtlSetPortableOperatingSystem( + _In_ BOOLEAN IsPortable + ); + +#if (PHNT_VERSION >= PHNT_THRESHOLD) + +#define DEVICEFAMILYINFOENUM_UAP 0x00000000 +#define DEVICEFAMILYINFOENUM_WINDOWS_8X 0x00000001 +#define DEVICEFAMILYINFOENUM_WINDOWS_PHONE_8X 0x00000002 +#define DEVICEFAMILYINFOENUM_DESKTOP 0x00000003 +#define DEVICEFAMILYINFOENUM_MOBILE 0x00000004 +#define DEVICEFAMILYINFOENUM_XBOX 0x00000005 +#define DEVICEFAMILYINFOENUM_TEAM 0x00000006 +#define DEVICEFAMILYINFOENUM_IOT 0x00000007 +#define DEVICEFAMILYINFOENUM_IOT_HEADLESS 0x00000008 +#define DEVICEFAMILYINFOENUM_SERVER 0x00000009 +#define DEVICEFAMILYINFOENUM_HOLOGRAPHIC 0x0000000A +#define DEVICEFAMILYINFOENUM_XBOXSRA 0x0000000B +#define DEVICEFAMILYINFOENUM_XBOXERA 0x0000000C +#define DEVICEFAMILYINFOENUM_MAX 0x0000000C +#define DEVICEFAMILYDEVICEFORM_UNKNOWN 0x00000000 +#define DEVICEFAMILYDEVICEFORM_PHONE 0x00000001 +#define DEVICEFAMILYDEVICEFORM_TABLET 0x00000002 +#define DEVICEFAMILYDEVICEFORM_DESKTOP 0x00000003 +#define DEVICEFAMILYDEVICEFORM_NOTEBOOK 0x00000004 +#define DEVICEFAMILYDEVICEFORM_CONVERTIBLE 0x00000005 +#define DEVICEFAMILYDEVICEFORM_DETACHABLE 0x00000006 +#define DEVICEFAMILYDEVICEFORM_ALLINONE 0x00000007 +#define DEVICEFAMILYDEVICEFORM_STICKPC 0x00000008 +#define DEVICEFAMILYDEVICEFORM_PUCK 0x00000009 +#define DEVICEFAMILYDEVICEFORM_LARGESCREEN 0x0000000A +#define DEVICEFAMILYDEVICEFORM_HMD 0x0000000B +#define DEVICEFAMILYDEVICEFORM_MAX 0x0000000B + +NTSYSAPI +VOID +NTAPI +RtlGetDeviceFamilyInfoEnum( + _Out_opt_ ULONGLONG *UAPInfo, + _Out_opt_ PULONG DeviceFamily, + _Out_opt_ PULONG DeviceForm + ); + +NTSYSAPI +ULONG +NTAPI +RtlConvertDeviceFamilyInfoToString( + _Inout_ PULONG DeviceFamilyBufferSize, + _Inout_ PULONG DeviceFormBufferSize, + _Out_writes_bytes_(*DeviceFamilyBufferSize) PWSTR DeviceFamily, + _Out_writes_bytes_(*DeviceFormBufferSize) PWSTR DeviceForm + ); + +#endif + +NTSYSAPI +OS_DEPLOYEMENT_STATE_VALUES +NTAPI +RtlOsDeploymentState( + _Reserved_ _In_ ULONG Flags + ); + +#if (PHNT_VERSION >= PHNT_VISTA) + +NTSYSAPI +NTSTATUS +NTAPI +RtlFindClosestEncodableLength( + _In_ ULONGLONG SourceLength, + _Out_ PULONGLONG TargetLength + ); + +#endif + +// Memory cache + +typedef NTSTATUS (NTAPI *PRTL_SECURE_MEMORY_CACHE_CALLBACK)( + _In_ PVOID Address, + _In_ SIZE_T Length + ); + +// ros +NTSYSAPI +NTSTATUS +NTAPI +RtlRegisterSecureMemoryCacheCallback( + _In_ PRTL_SECURE_MEMORY_CACHE_CALLBACK Callback + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlDeregisterSecureMemoryCacheCallback( + _In_ PRTL_SECURE_MEMORY_CACHE_CALLBACK Callback + ); + +// ros +NTSYSAPI +BOOLEAN +NTAPI +RtlFlushSecureMemoryCache( + _In_ PVOID MemoryCache, + _In_opt_ SIZE_T MemoryLength + ); + #endif diff --git a/phnt/include/ntseapi.h b/phnt/include/ntseapi.h index cc0e056ed6ab..eb23fb867c95 100644 --- a/phnt/include/ntseapi.h +++ b/phnt/include/ntseapi.h @@ -61,7 +61,6 @@ #define SE_CREATE_SYMBOLIC_LINK_PRIVILEGE (35L) #define SE_MAX_WELL_KNOWN_PRIVILEGE SE_CREATE_SYMBOLIC_LINK_PRIVILEGE - // Authz // begin_rev @@ -147,6 +146,12 @@ typedef struct _TOKEN_SECURITY_ATTRIBUTES_INFORMATION } Attribute; } TOKEN_SECURITY_ATTRIBUTES_INFORMATION, *PTOKEN_SECURITY_ATTRIBUTES_INFORMATION; +// rev +typedef struct _TOKEN_PROCESS_TRUST_LEVEL +{ + PSID TrustLevelSid; +} TOKEN_PROCESS_TRUST_LEVEL, *PTOKEN_PROCESS_TRUST_LEVEL; + // Tokens NTSYSCALLAPI @@ -629,27 +634,4 @@ NtPrivilegedServiceAuditAlarm( _In_ BOOLEAN AccessGranted ); -// Misc. - -typedef enum _FILTER_BOOT_OPTION_OPERATION -{ - FilterBootOptionOperationOpenSystemStore, - FilterBootOptionOperationSetElement, - FilterBootOptionOperationDeleteElement, - FilterBootOptionOperationMax -} FILTER_BOOT_OPTION_OPERATION; - -#if (PHNT_VERSION >= PHNT_THRESHOLD) -NTSYSCALLAPI -NTSTATUS -NTAPI -NtFilterBootOption( - _In_ FILTER_BOOT_OPTION_OPERATION FilterOperation, - _In_ ULONG ObjectType, - _In_ ULONG ElementType, - _In_reads_bytes_opt_(DataSize) PVOID Data, - _In_ ULONG DataSize - ); -#endif - #endif diff --git a/phnt/include/ntxcapi.h b/phnt/include/ntxcapi.h index 29cfc73f68d9..59d3ec2cce1c 100644 --- a/phnt/include/ntxcapi.h +++ b/phnt/include/ntxcapi.h @@ -41,4 +41,24 @@ NtRaiseException( _In_ BOOLEAN FirstChance ); +__analysis_noreturn +NTSYSCALLAPI +VOID +NTAPI +RtlAssert( + _In_ PVOID VoidFailedAssertion, + _In_ PVOID VoidFileName, + _In_ ULONG LineNumber, + _In_opt_ PSTR MutableMessage + ); + +#define RTL_ASSERT(exp) \ + ((!(exp)) ? (RtlAssert((PVOID)#exp, (PVOID)__FILE__, __LINE__, NULL), FALSE) : TRUE) +#define RTL_ASSERTMSG(msg, exp) \ + ((!(exp)) ? (RtlAssert((PVOID)#exp, (PVOID)__FILE__, __LINE__, msg), FALSE) : TRUE) +#define RTL_SOFT_ASSERT(_exp) \ + ((!(_exp)) ? (DbgPrint("%s(%d): Soft assertion failed\n Expression: %s\n", __FILE__, __LINE__, #_exp), FALSE) : TRUE) +#define RTL_SOFT_ASSERTMSG(_msg, _exp) \ + ((!(_exp)) ? (DbgPrint("%s(%d): Soft assertion failed\n Expression: %s\n Message: %s\n", __FILE__, __LINE__, #_exp, (_msg)), FALSE) : TRUE) + #endif From 26460a522b970b0aacca616d49a5fd0c66fdba42 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 29 Jun 2018 16:58:47 +1000 Subject: [PATCH 1065/2058] Improve continue message error checking --- ProcessHacker/actions.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/ProcessHacker/actions.c b/ProcessHacker/actions.c index ef81dd378eab..952563823410 100644 --- a/ProcessHacker/actions.c +++ b/ProcessHacker/actions.c @@ -785,9 +785,14 @@ static BOOLEAN PhpShowContinueMessageProcesses( for (i = 0; i < NumberOfProcesses; i++) { HANDLE processHandle; - ULONG breakOnTermination; + ULONG breakOnTermination = 0; - breakOnTermination = 0; + if (PhpIsDangerousProcess(Processes[i]->ProcessId)) + { + critical = TRUE; + dangerous = TRUE; + break; + } if (NT_SUCCESS(PhOpenProcess(&processHandle, PROCESS_QUERY_INFORMATION, Processes[i]->ProcessId))) { @@ -801,12 +806,6 @@ static BOOLEAN PhpShowContinueMessageProcesses( dangerous = TRUE; break; } - - if (PhpIsDangerousProcess(Processes[i]->ProcessId)) - { - dangerous = TRUE; - break; - } } if (WarnOnlyIfDangerous && !dangerous) From 7f304bbfe220693cd648649375818807153d83af Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 29 Jun 2018 17:13:38 +1000 Subject: [PATCH 1066/2058] Add process modules tree --- ProcessHacker/include/modlist.h | 4 + ProcessHacker/include/modprv.h | 24 +++-- ProcessHacker/modlist.c | 170 +++++++++++++++++++++++--------- ProcessHacker/modprv.c | 27 ++++- 4 files changed, 170 insertions(+), 55 deletions(-) diff --git a/ProcessHacker/include/modlist.h b/ProcessHacker/include/modlist.h index 658511c00fff..2d1ca06dd982 100644 --- a/ProcessHacker/include/modlist.h +++ b/ProcessHacker/include/modlist.h @@ -53,6 +53,9 @@ typedef struct _PH_MODULE_NODE PPH_STRING LoadTimeText; PPH_STRING FileModifiedTimeText; PPH_STRING FileSizeText; + + struct _PH_MODULE_NODE *Parent; + PPH_LIST Children; // begin_phapppub } PH_MODULE_NODE, *PPH_MODULE_NODE; // end_phapppub @@ -97,6 +100,7 @@ typedef struct _PH_MODULE_LIST_CONTEXT PPH_HASHTABLE NodeHashtable; PPH_LIST NodeList; + PPH_LIST NodeRootList; PPH_POINTER_LIST NodeStateList; HFONT BoldFont; diff --git a/ProcessHacker/include/modprv.h b/ProcessHacker/include/modprv.h index 413cc97dd829..436058f416b8 100644 --- a/ProcessHacker/include/modprv.h +++ b/ProcessHacker/include/modprv.h @@ -8,6 +8,7 @@ extern PPH_OBJECT_TYPE PhModuleItemType; typedef struct _PH_MODULE_ITEM { PVOID BaseAddress; + PVOID ParentBaseAddress; PVOID EntryPoint; ULONG Size; ULONG Flags; @@ -18,11 +19,16 @@ typedef struct _PH_MODULE_ITEM PPH_STRING FileName; PH_IMAGE_VERSION_INFO VersionInfo; - WCHAR BaseAddressString[PH_PTR_STR_LEN_1]; - WCHAR EntryPointAddressString[PH_PTR_STR_LEN_1]; - - BOOLEAN IsFirst; - BOOLEAN JustProcessed; + union + { + BOOLEAN StateFlags; + struct + { + BOOLEAN JustProcessed : 1; + BOOLEAN IsFirst : 1; + BOOLEAN Spare : 6; + }; + }; enum _VERIFY_RESULT VerifyResult; PPH_STRING VerifySignerName; @@ -32,12 +38,12 @@ typedef struct _PH_MODULE_ITEM USHORT ImageDllCharacteristics; LARGE_INTEGER LoadTime; - LARGE_INTEGER FileLastWriteTime; LARGE_INTEGER FileEndOfFile; - PVOID ParentBaseAddress; + WCHAR BaseAddressString[PH_PTR_STR_LEN_1]; WCHAR ParentBaseAddressString[PH_PTR_STR_LEN_1]; + WCHAR EntryPointAddressString[PH_PTR_STR_LEN_1]; } PH_MODULE_ITEM, *PPH_MODULE_ITEM; typedef struct _PH_MODULE_PROVIDER @@ -51,6 +57,7 @@ typedef struct _PH_MODULE_PROVIDER HANDLE ProcessId; HANDLE ProcessHandle; + PPH_STRING FileName; PPH_STRING PackageFullName; SLIST_HEADER QueryListHead; NTSTATUS RunStatus; @@ -60,9 +67,10 @@ typedef struct _PH_MODULE_PROVIDER BOOLEAN Flags; struct { + BOOLEAN HaveFirst : 1; BOOLEAN ControlFlowGuardEnabled : 1; BOOLEAN IsSubsystemProcess : 1; - BOOLEAN Spare : 7; + BOOLEAN Spare : 5; }; }; } PH_MODULE_PROVIDER, *PPH_MODULE_PROVIDER; diff --git a/ProcessHacker/modlist.c b/ProcessHacker/modlist.c index 3914cfe554e8..89bb1661f9be 100644 --- a/ProcessHacker/modlist.c +++ b/ProcessHacker/modlist.c @@ -42,6 +42,7 @@ ULONG PhpModuleNodeHashtableHashFunction( ); VOID PhpDestroyModuleNode( + _In_ PPH_MODULE_LIST_CONTEXT Context, _In_ PPH_MODULE_NODE ModuleNode ); @@ -71,8 +72,6 @@ VOID PhInitializeModuleList( _Out_ PPH_MODULE_LIST_CONTEXT Context ) { - HWND hwnd; - memset(Context, 0, sizeof(PH_MODULE_LIST_CONTEXT)); Context->EnableStateHighlighting = TRUE; @@ -83,48 +82,49 @@ VOID PhInitializeModuleList( 100 ); Context->NodeList = PhCreateList(100); + Context->NodeRootList = PhCreateList(2); Context->ParentWindowHandle = ParentWindowHandle; Context->TreeNewHandle = TreeNewHandle; - hwnd = TreeNewHandle; - PhSetControlTheme(hwnd, L"explorer"); - TreeNew_SetCallback(hwnd, PhpModuleTreeNewCallback, Context); + PhSetControlTheme(Context->TreeNewHandle, L"explorer"); - TreeNew_SetRedraw(hwnd, FALSE); + TreeNew_SetCallback(Context->TreeNewHandle, PhpModuleTreeNewCallback, Context); + + TreeNew_SetRedraw(Context->TreeNewHandle, FALSE); // Default columns - PhAddTreeNewColumn(hwnd, PHMOTLC_NAME, TRUE, L"Name", 100, PH_ALIGN_LEFT, -2, 0); - PhAddTreeNewColumn(hwnd, PHMOTLC_BASEADDRESS, TRUE, L"Base address", 80, PH_ALIGN_RIGHT, 0, DT_RIGHT); - PhAddTreeNewColumnEx(hwnd, PHMOTLC_SIZE, TRUE, L"Size", 60, PH_ALIGN_RIGHT, 1, DT_RIGHT, TRUE); - PhAddTreeNewColumn(hwnd, PHMOTLC_DESCRIPTION, TRUE, L"Description", 160, PH_ALIGN_LEFT, 2, 0); - - PhAddTreeNewColumn(hwnd, PHMOTLC_COMPANYNAME, FALSE, L"Company name", 180, PH_ALIGN_LEFT, -1, 0); - PhAddTreeNewColumn(hwnd, PHMOTLC_VERSION, FALSE, L"Version", 100, PH_ALIGN_LEFT, -1, 0); - PhAddTreeNewColumn(hwnd, PHMOTLC_FILENAME, FALSE, L"File name", 180, PH_ALIGN_LEFT, -1, DT_PATH_ELLIPSIS); - - PhAddTreeNewColumn(hwnd, PHMOTLC_TYPE, FALSE, L"Type", 80, PH_ALIGN_LEFT, -1, 0); - PhAddTreeNewColumnEx(hwnd, PHMOTLC_LOADCOUNT, FALSE, L"Load count", 40, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); - PhAddTreeNewColumn(hwnd, PHMOTLC_VERIFICATIONSTATUS, FALSE, L"Verification status", 70, PH_ALIGN_LEFT, -1, 0); - PhAddTreeNewColumn(hwnd, PHMOTLC_VERIFIEDSIGNER, FALSE, L"Verified signer", 100, PH_ALIGN_LEFT, -1, 0); - PhAddTreeNewColumnEx(hwnd, PHMOTLC_ASLR, FALSE, L"ASLR", 50, PH_ALIGN_LEFT, -1, 0, TRUE); - PhAddTreeNewColumnEx(hwnd, PHMOTLC_TIMESTAMP, FALSE, L"Time stamp", 100, PH_ALIGN_LEFT, -1, 0, TRUE); - PhAddTreeNewColumnEx(hwnd, PHMOTLC_CFGUARD, FALSE, L"CF Guard", 70, PH_ALIGN_LEFT, -1, 0, TRUE); - PhAddTreeNewColumnEx(hwnd, PHMOTLC_LOADTIME, FALSE, L"Load time", 100, PH_ALIGN_LEFT, -1, 0, TRUE); - PhAddTreeNewColumn(hwnd, PHMOTLC_LOADREASON, FALSE, L"Load reason", 80, PH_ALIGN_LEFT, -1, 0); - PhAddTreeNewColumnEx(hwnd, PHMOTLC_FILEMODIFIEDTIME, FALSE, L"File modified time", 140, PH_ALIGN_LEFT, -1, 0, TRUE); - PhAddTreeNewColumnEx(hwnd, PHMOTLC_FILESIZE, FALSE, L"File size", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); - PhAddTreeNewColumnEx(hwnd, PHMOTLC_ENTRYPOINT, FALSE, L"Entry point", 70, PH_ALIGN_LEFT, -1, 0, TRUE); - PhAddTreeNewColumnEx(hwnd, PHMOTLC_PARENTBASEADDRESS, FALSE, L"Parent base address", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); - - TreeNew_SetRedraw(hwnd, TRUE); - - TreeNew_SetTriState(hwnd, TRUE); - TreeNew_SetSort(hwnd, 0, NoSortOrder); - - PhCmInitializeManager(&Context->Cm, hwnd, PHMOTLC_MAXIMUM, PhpModuleTreeNewPostSortFunction); - - PhInitializeTreeNewFilterSupport(&Context->TreeFilterSupport, hwnd, Context->NodeList); + PhAddTreeNewColumn(Context->TreeNewHandle, PHMOTLC_NAME, TRUE, L"Name", 100, PH_ALIGN_LEFT, -2, 0); + PhAddTreeNewColumn(Context->TreeNewHandle, PHMOTLC_BASEADDRESS, TRUE, L"Base address", 80, PH_ALIGN_RIGHT, 0, DT_RIGHT); + PhAddTreeNewColumnEx(Context->TreeNewHandle, PHMOTLC_SIZE, TRUE, L"Size", 60, PH_ALIGN_RIGHT, 1, DT_RIGHT, TRUE); + PhAddTreeNewColumn(Context->TreeNewHandle, PHMOTLC_DESCRIPTION, TRUE, L"Description", 160, PH_ALIGN_LEFT, 2, 0); + + PhAddTreeNewColumn(Context->TreeNewHandle, PHMOTLC_COMPANYNAME, FALSE, L"Company name", 180, PH_ALIGN_LEFT, -1, 0); + PhAddTreeNewColumn(Context->TreeNewHandle, PHMOTLC_VERSION, FALSE, L"Version", 100, PH_ALIGN_LEFT, -1, 0); + PhAddTreeNewColumn(Context->TreeNewHandle, PHMOTLC_FILENAME, FALSE, L"File name", 180, PH_ALIGN_LEFT, -1, DT_PATH_ELLIPSIS); + + PhAddTreeNewColumn(Context->TreeNewHandle, PHMOTLC_TYPE, FALSE, L"Type", 80, PH_ALIGN_LEFT, -1, 0); + PhAddTreeNewColumnEx(Context->TreeNewHandle, PHMOTLC_LOADCOUNT, FALSE, L"Load count", 40, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); + PhAddTreeNewColumn(Context->TreeNewHandle, PHMOTLC_VERIFICATIONSTATUS, FALSE, L"Verification status", 70, PH_ALIGN_LEFT, -1, 0); + PhAddTreeNewColumn(Context->TreeNewHandle, PHMOTLC_VERIFIEDSIGNER, FALSE, L"Verified signer", 100, PH_ALIGN_LEFT, -1, 0); + PhAddTreeNewColumnEx(Context->TreeNewHandle, PHMOTLC_ASLR, FALSE, L"ASLR", 50, PH_ALIGN_LEFT, -1, 0, TRUE); + PhAddTreeNewColumnEx(Context->TreeNewHandle, PHMOTLC_TIMESTAMP, FALSE, L"Time stamp", 100, PH_ALIGN_LEFT, -1, 0, TRUE); + PhAddTreeNewColumnEx(Context->TreeNewHandle, PHMOTLC_CFGUARD, FALSE, L"CF Guard", 70, PH_ALIGN_LEFT, -1, 0, TRUE); + PhAddTreeNewColumnEx(Context->TreeNewHandle, PHMOTLC_LOADTIME, FALSE, L"Load time", 100, PH_ALIGN_LEFT, -1, 0, TRUE); + PhAddTreeNewColumn(Context->TreeNewHandle, PHMOTLC_LOADREASON, FALSE, L"Load reason", 80, PH_ALIGN_LEFT, -1, 0); + PhAddTreeNewColumnEx(Context->TreeNewHandle, PHMOTLC_FILEMODIFIEDTIME, FALSE, L"File modified time", 140, PH_ALIGN_LEFT, -1, 0, TRUE); + PhAddTreeNewColumnEx(Context->TreeNewHandle, PHMOTLC_FILESIZE, FALSE, L"File size", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); + PhAddTreeNewColumnEx(Context->TreeNewHandle, PHMOTLC_ENTRYPOINT, FALSE, L"Entry point", 70, PH_ALIGN_LEFT, -1, 0, TRUE); + PhAddTreeNewColumnEx(Context->TreeNewHandle, PHMOTLC_PARENTBASEADDRESS, FALSE, L"Parent base address", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); + + TreeNew_SetRedraw(Context->TreeNewHandle, TRUE); + + TreeNew_SetTriState(Context->TreeNewHandle, TRUE); + TreeNew_SetSort(Context->TreeNewHandle, 0, NoSortOrder); + + PhCmInitializeManager(&Context->Cm, Context->TreeNewHandle, PHMOTLC_MAXIMUM, PhpModuleTreeNewPostSortFunction); + + PhInitializeTreeNewFilterSupport(&Context->TreeFilterSupport, Context->TreeNewHandle, Context->NodeList); } VOID PhDeleteModuleList( @@ -141,10 +141,11 @@ VOID PhDeleteModuleList( PhCmDeleteManager(&Context->Cm); for (i = 0; i < Context->NodeList->Count; i++) - PhpDestroyModuleNode(Context->NodeList->Items[i]); + PhpDestroyModuleNode(Context, Context->NodeList->Items[i]); PhDereferenceObject(Context->NodeHashtable); PhDereferenceObject(Context->NodeList); + PhDereferenceObject(Context->NodeRootList); } BOOLEAN PhpModuleNodeHashtableEqualFunction( @@ -235,7 +236,7 @@ VOID PhSetOptionsModuleList( } } -PPH_MODULE_NODE PhAddModuleNode( +PPH_MODULE_NODE PhCreateModuleNode( _Inout_ PPH_MODULE_LIST_CONTEXT Context, _In_ PPH_MODULE_ITEM ModuleItem, _In_ ULONG RunId @@ -247,6 +248,8 @@ PPH_MODULE_NODE PhAddModuleNode( memset(moduleNode, 0, sizeof(PH_MODULE_NODE)); PhInitializeTreeNewNode(&moduleNode->Node); + moduleNode->Children = PhCreateList(1); + if (Context->EnableStateHighlighting && RunId != 1) { PhChangeShStateTn( @@ -259,8 +262,7 @@ PPH_MODULE_NODE PhAddModuleNode( ); } - moduleNode->ModuleItem = ModuleItem; - PhReferenceObject(ModuleItem); + moduleNode->ModuleItem = PhReferenceObject(ModuleItem); memset(moduleNode->TextCache, 0, sizeof(PH_STRINGREF) * PHMOTLC_MAXIMUM); moduleNode->Node.TextCache = moduleNode->TextCache; @@ -279,6 +281,39 @@ PPH_MODULE_NODE PhAddModuleNode( return moduleNode; } +PPH_MODULE_NODE PhAddModuleNode( + _Inout_ PPH_MODULE_LIST_CONTEXT Context, + _In_ PPH_MODULE_ITEM ModuleItem, + _In_ ULONG RunId + ) +{ + PPH_MODULE_NODE moduleNode; + PPH_MODULE_NODE parentNode; + ULONG i; + + moduleNode = PhCreateModuleNode(Context, ModuleItem, RunId); + + for (i = 0; i < Context->NodeList->Count; i++) + { + parentNode = Context->NodeList->Items[i]; + + if (parentNode != moduleNode && parentNode->ModuleItem->BaseAddress == ModuleItem->ParentBaseAddress) + { + moduleNode->Parent = parentNode; + PhAddItemList(parentNode->Children, moduleNode); + break; + } + } + + if (!moduleNode->Parent) + { + moduleNode->Node.Expanded = TRUE; + PhAddItemList(Context->NodeRootList, moduleNode); + } + + return moduleNode; +} + PPH_MODULE_NODE PhFindModuleNode( _In_ PPH_MODULE_LIST_CONTEXT Context, _In_ PPH_MODULE_ITEM ModuleItem @@ -327,11 +362,38 @@ VOID PhRemoveModuleNode( } VOID PhpDestroyModuleNode( + _In_ PPH_MODULE_LIST_CONTEXT Context, _In_ PPH_MODULE_NODE ModuleNode ) { + ULONG index; + PhEmCallObjectOperation(EmModuleNodeType, ModuleNode, EmObjectDelete); + if (ModuleNode->Parent) + { + // Remove the node from its parent. + + if ((index = PhFindItemList(ModuleNode->Parent->Children, ModuleNode)) != -1) + PhRemoveItemList(ModuleNode->Parent->Children, index); + } + else + { + // Remove the node from the root list. + + if ((index = PhFindItemList(Context->NodeRootList, ModuleNode)) != -1) + PhRemoveItemList(Context->NodeRootList, index); + } + + // Move the node's children to the root list. + for (index = 0; index < ModuleNode->Children->Count; index++) + { + PPH_MODULE_NODE node = ModuleNode->Children->Items[index]; + + node->Parent = NULL; + PhAddItemList(Context->NodeRootList, node); + } + PhClearReference(&ModuleNode->TooltipText); PhClearReference(&ModuleNode->SizeText); @@ -357,7 +419,7 @@ VOID PhpRemoveModuleNode( if ((index = PhFindItemList(Context->NodeList, ModuleNode)) != -1) PhRemoveItemList(Context->NodeList, index); - PhpDestroyModuleNode(ModuleNode); + PhpDestroyModuleNode(Context, ModuleNode); TreeNew_NodesStructured(Context->TreeNewHandle); } @@ -608,8 +670,24 @@ BOOLEAN NTAPI PhpModuleTreeNewCallback( case TreeNewGetChildren: { PPH_TREENEW_GET_CHILDREN getChildren = Parameter1; + node = (PPH_MODULE_NODE)getChildren->Node; - if (!getChildren->Node) + if (context->TreeNewSortOrder == NoSortOrder) + { + if (!node) + { + getChildren->Children = (PPH_TREENEW_NODE *)context->NodeRootList->Items; + getChildren->NumberOfChildren = context->NodeRootList->Count; + } + else + { + getChildren->Children = (PPH_TREENEW_NODE *)node->Children->Items; + getChildren->NumberOfChildren = node->Children->Count; + } + + qsort_s(getChildren->Children, getChildren->NumberOfChildren, sizeof(PVOID), SORT_FUNCTION(TriState), context); + } + else { static PVOID sortFunctions[] = { @@ -674,8 +752,12 @@ BOOLEAN NTAPI PhpModuleTreeNewCallback( case TreeNewIsLeaf: { PPH_TREENEW_IS_LEAF isLeaf = Parameter1; + node = (PPH_MODULE_NODE)isLeaf->Node; - isLeaf->IsLeaf = TRUE; + if (context->TreeNewSortOrder == NoSortOrder) + isLeaf->IsLeaf = node->Children->Count == 0; + else + isLeaf->IsLeaf = TRUE; } return TRUE; case TreeNewGetCellText: diff --git a/ProcessHacker/modprv.c b/ProcessHacker/modprv.c index 1aee24561daa..ef6f5f4aee83 100644 --- a/ProcessHacker/modprv.c +++ b/ProcessHacker/modprv.c @@ -148,6 +148,16 @@ PPH_MODULE_PROVIDER PhCreateModuleProvider( { moduleProvider->IsSubsystemProcess = !!basicInfo.IsSubsystemProcess; } + + if (moduleProvider->IsSubsystemProcess) + { + PPH_STRING fileName; + + if (NT_SUCCESS(PhGetProcessImageFileNameByProcessId(ProcessId, &fileName))) + { + PhMoveReference(&moduleProvider->FileName, PhGetFileName(fileName)); + } + } } RtlInitializeSListHead(&moduleProvider->QueryListHead); @@ -386,7 +396,7 @@ VOID PhModuleProviderUpdate( if (!moduleProvider->ProcessHandle && moduleProvider->ProcessId != SYSTEM_PROCESS_ID) goto UpdateExit; - modules = PhCreateList(20); + modules = PhCreateList(100); moduleProvider->RunStatus = PhEnumGenericModules( moduleProvider->ProcessId, @@ -502,15 +512,26 @@ VOID PhModuleProviderUpdate( PhInitializeImageVersionInfo(&moduleItem->VersionInfo, moduleItem->FileName->Buffer); - moduleItem->IsFirst = i == 0; - if (moduleProvider->IsSubsystemProcess) { // HACK: Update the module type. (TODO: Move into PhEnumGenericModules) (dmex) moduleItem->Type = PH_MODULE_TYPE_ELF_MAPPED_IMAGE; + + if (!moduleProvider->HaveFirst) + { + if (PhEqualString(moduleItem->FileName, moduleProvider->FileName, TRUE)) + { + moduleItem->IsFirst = TRUE; + moduleProvider->HaveFirst = TRUE; + } + } } else { + // TODO: Linux process modules are loaded in order of the ELF symbol table dependancy graph + // with the primary executable/shared object as the last entry (dmex) + moduleItem->IsFirst = i == 0; + // Fix up the load count. If this is not an ordinary DLL or kernel module, set the load count to 0. if (moduleItem->Type != PH_MODULE_TYPE_MODULE && moduleItem->Type != PH_MODULE_TYPE_WOW64_MODULE && From 97fdab1d78f0bfa260a1b3695065d4587d5d6f88 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 29 Jun 2018 17:19:35 +1000 Subject: [PATCH 1067/2058] Add PhInitFormatGroupDigits --- phlib/include/phbasesup.h | 1 + 1 file changed, 1 insertion(+) diff --git a/phlib/include/phbasesup.h b/phlib/include/phbasesup.h index 7abab1f53e8c..9aa13276f00e 100644 --- a/phlib/include/phbasesup.h +++ b/phlib/include/phbasesup.h @@ -3647,6 +3647,7 @@ typedef struct _PH_FORMAT #define PhInitFormatX(f, v) do { (f)->Type = UInt32FormatType | FormatUseRadix; (f)->u.UInt32 = (v); (f)->Radix = 16; } while (0) #define PhInitFormatI64D(f, v) do { (f)->Type = Int64FormatType; (f)->u.Int64 = (v); } while (0) #define PhInitFormatI64U(f, v) do { (f)->Type = UInt64FormatType; (f)->u.UInt64 = (v); } while (0) +#define PhInitFormatI64UGroupDigits(f, v) do { (f)->Type = UInt64FormatType | FormatGroupDigits; (f)->u.UInt64 = (v); } while (0) #define PhInitFormatI64X(f, v) do { (f)->Type = UInt64FormatType | FormatUseRadix; (f)->u.UInt64 = (v); (f)->Radix = 16; } while (0) #define PhInitFormatIU(f, v) do { (f)->Type = UIntPtrFormatType; (f)->u.UIntPtr = (v); } while (0) #define PhInitFormatIX(f, v) do { (f)->Type = UIntPtrFormatType | FormatUseRadix; (f)->u.UIntPtr = (v); (f)->Radix = 16; } while (0) From 081ab6fb45e419b1e696077771f58ab060e40567 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 29 Jun 2018 17:39:42 +1000 Subject: [PATCH 1068/2058] Fix options window parenting --- ProcessHacker/options.c | 202 ++++++++++++++++++---------------------- 1 file changed, 90 insertions(+), 112 deletions(-) diff --git a/ProcessHacker/options.c b/ProcessHacker/options.c index 9a376906c538..c48c67308d50 100644 --- a/ProcessHacker/options.c +++ b/ProcessHacker/options.c @@ -128,7 +128,6 @@ VOID PhpSetDefaultTaskManager( static HWND PhOptionsWindowHandle = NULL; static PH_EVENT PhOptionsWindowInitializedEvent = PH_EVENT_INIT; -static PPH_LIST PhOptionsDialogList = NULL; static PH_LAYOUT_MANAGER WindowLayoutManager; static PPH_LIST SectionList = NULL; @@ -166,42 +165,23 @@ VOID PhShowOptionsDialog( } else { - DialogBox( - PhInstanceHandle, - MAKEINTRESOURCE(IDD_OPTIONS), - ParentWindowHandle, - PhOptionsDialogProc - ); - - PhUpdateCachedSettings(); - ProcessHacker_SaveAllSettings(PhMainWndHandle); - PhInvalidateAllProcessNodes(); - PhReloadSettingsProcessTreeList(); - PhSiNotifyChangeSettings(); - - if (RestartRequired) + if (!PhOptionsWindowHandle) { - if (PhShowMessage2( - PhMainWndHandle, - TDCBF_YES_BUTTON | TDCBF_NO_BUTTON, - TD_INFORMATION_ICON, - L"One or more options you have changed requires a restart of Process Hacker.", - L"Do you want to restart Process Hacker now?" - ) == IDYES) - { - ProcessHacker_PrepareForEarlyShutdown(PhMainWndHandle); - PhShellProcessHacker( - PhMainWndHandle, - L"-v", - SW_SHOW, - 0, - PH_SHELL_APP_PROPAGATE_PARAMETERS | PH_SHELL_APP_PROPAGATE_PARAMETERS_IGNORE_VISIBILITY, - 0, - NULL - ); - ProcessHacker_Destroy(PhMainWndHandle); - } + PhOptionsWindowHandle = CreateDialog( + PhInstanceHandle, + MAKEINTRESOURCE(IDD_OPTIONS), + NULL, + PhOptionsDialogProc + ); + + PhRegisterDialog(PhOptionsWindowHandle); + ShowWindow(PhOptionsWindowHandle, SW_SHOW); } + + if (IsIconic(PhOptionsWindowHandle)) + ShowWindow(PhOptionsWindowHandle, SW_RESTORE); + else + SetForegroundWindow(PhOptionsWindowHandle); } } @@ -267,18 +247,18 @@ static PPH_OPTIONS_SECTION PhpTreeViewGetSelectedSection( _In_ HTREEITEM SelectedTreeItem ) { - TVITEM tvItem; + TVITEM item; if (!SelectedTreeItem) return NULL; - tvItem.mask = TVIF_PARAM | TVIF_HANDLE; - tvItem.hItem = SelectedTreeItem; + item.mask = TVIF_PARAM | TVIF_HANDLE; + item.hItem = SelectedTreeItem; - if (!TreeView_GetItem(OptionsTreeControl, &tvItem)) + if (!TreeView_GetItem(OptionsTreeControl, &item)) return NULL; - return (PPH_OPTIONS_SECTION)tvItem.lParam; + return (PPH_OPTIONS_SECTION)item.lParam; } INT_PTR CALLBACK PhOptionsDialogProc( @@ -292,16 +272,12 @@ INT_PTR CALLBACK PhOptionsDialogProc( { case WM_INITDIALOG: { - PhOptionsWindowHandle = hwndDlg; - - SendMessage(PhOptionsWindowHandle, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER))); - SendMessage(PhOptionsWindowHandle, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER))); - - PhCenterWindow(hwndDlg, GetParent(hwndDlg)); + SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER))); + SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER))); OptionsTreeImageList = ImageList_Create(2, 22, ILC_COLOR, 1, 1); - OptionsTreeControl = GetDlgItem(PhOptionsWindowHandle, IDC_SECTIONTREE); - ContainerControl = GetDlgItem(PhOptionsWindowHandle, IDD_CONTAINER); + OptionsTreeControl = GetDlgItem(hwndDlg, IDC_SECTIONTREE); + ContainerControl = GetDlgItem(hwndDlg, IDD_CONTAINER); PhSetWindowStyle(GetDlgItem(hwndDlg, IDC_SEPARATOR), SS_OWNERDRAW, SS_OWNERDRAW); @@ -310,14 +286,14 @@ INT_PTR CALLBACK PhOptionsDialogProc( TreeView_SetImageList(OptionsTreeControl, OptionsTreeImageList, TVSIL_NORMAL); TreeView_SetBkColor(OptionsTreeControl, GetSysColor(COLOR_3DFACE)); - PhInitializeLayoutManager(&WindowLayoutManager, PhOptionsWindowHandle); + PhInitializeLayoutManager(&WindowLayoutManager, hwndDlg); PhAddLayoutItem(&WindowLayoutManager, OptionsTreeControl, NULL, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_BOTTOM); PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDC_SEPARATOR), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_BOTTOM); PhAddLayoutItem(&WindowLayoutManager, ContainerControl, NULL, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); - PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(PhOptionsWindowHandle, IDC_RESET), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_BOTTOM); - PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(PhOptionsWindowHandle, IDC_CLEANUP), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_BOTTOM); - //PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(PhOptionsWindowHandle, IDC_APPLY), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); - PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(PhOptionsWindowHandle, IDOK), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); + PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDC_RESET), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_BOTTOM); + PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDC_CLEANUP), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_BOTTOM); + //PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDC_APPLY), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); + PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDOK), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); { PPH_OPTIONS_SECTION section; @@ -334,7 +310,7 @@ INT_PTR CALLBACK PhOptionsDialogProc( { PH_PLUGIN_OPTIONS_POINTERS pointers; - pointers.WindowHandle = PhOptionsWindowHandle; + pointers.WindowHandle = hwndDlg; pointers.CreateSection = PhOptionsCreateSection; pointers.FindSection = PhOptionsFindSection; pointers.EnterSectionView = PhOptionsEnterSectionView; @@ -344,16 +320,23 @@ INT_PTR CALLBACK PhOptionsDialogProc( PhOptionsEnterSectionView(section); PhOptionsOnSize(); - - EnableThemeDialogTexture(ContainerControl, ETDT_ENABLETAB); } + + PhCenterWindow(hwndDlg, PhMainWndHandle); + PhLoadWindowPlacementFromSetting(L"OptionsWindowPosition", L"OptionsWindowSize", hwndDlg); + + EnableThemeDialogTexture(ContainerControl, ETDT_ENABLETAB); } break; - case WM_NCDESTROY: + case WM_DESTROY: { ULONG i; PPH_OPTIONS_SECTION section; + PhSaveWindowPlacementToSetting(L"OptionsWindowPosition", L"OptionsWindowSize", hwndDlg); + + PhDeleteLayoutManager(&WindowLayoutManager); + for (i = 0; i < SectionList->Count; i++) { section = SectionList->Items[i]; @@ -363,9 +346,10 @@ INT_PTR CALLBACK PhOptionsDialogProc( PhDereferenceObject(SectionList); SectionList = NULL; - ImageList_Destroy(OptionsTreeImageList); + if (OptionsTreeImageList) ImageList_Destroy(OptionsTreeImageList); - PhDeleteLayoutManager(&WindowLayoutManager); + PhUnregisterDialog(PhOptionsWindowHandle); + PhOptionsWindowHandle = NULL; } break; case WM_SIZE: @@ -379,7 +363,9 @@ INT_PTR CALLBACK PhOptionsDialogProc( { case IDCANCEL: case IDOK: - EndDialog(hwndDlg, IDOK); + { + DestroyWindow(hwndDlg); + } break; case IDC_RESET: { @@ -431,7 +417,7 @@ INT_PTR CALLBACK PhOptionsDialogProc( case WM_DRAWITEM: { PDRAWITEMSTRUCT drawInfo = (PDRAWITEMSTRUCT)lParam; - + if (drawInfo->CtlID == IDC_SEPARATOR) { RECT rect; @@ -455,7 +441,7 @@ INT_PTR CALLBACK PhOptionsDialogProc( { LPNMTREEVIEW treeview = (LPNMTREEVIEW)lParam; PPH_OPTIONS_SECTION section; - + if (section = PhpTreeViewGetSelectedSection(treeview->itemNew.hItem)) { PhOptionsEnterSectionView(section); @@ -515,11 +501,8 @@ PPH_OPTIONS_SECTION PhOptionsCreateSection( { PPH_OPTIONS_SECTION section; - section = PhAllocate(sizeof(PH_OPTIONS_SECTION)); - memset(section, 0, sizeof(PH_OPTIONS_SECTION)); - + section = PhAllocateZero(sizeof(PH_OPTIONS_SECTION)); PhInitializeStringRefLongHint(§ion->Name, Name); - section->Instance = Instance; section->Template = Template; section->DialogProc = DialogProc; @@ -541,11 +524,8 @@ PPH_OPTIONS_SECTION PhOptionsCreateSectionAdvanced( { PPH_OPTIONS_SECTION section; - section = PhAllocate(sizeof(PH_OPTIONS_SECTION)); - memset(section, 0, sizeof(PH_OPTIONS_SECTION)); - + section = PhAllocateZero(sizeof(PH_OPTIONS_SECTION)); PhInitializeStringRefLongHint(§ion->Name, Name); - section->Instance = Instance; section->Template = Template; section->DialogProc = DialogProc; @@ -961,8 +941,8 @@ typedef enum _PHP_OPTIONS_INDEX } PHP_OPTIONS_GENERAL_INDEX; VOID PhpSetListViewItemState( - _In_ HWND ListViewHandle, - _In_ INT Index, + _In_ HWND ListViewHandle, + _In_ INT Index, _In_ BOOLEAN Hide ) { @@ -1035,6 +1015,41 @@ static VOID PhpAdvancedPageLoad( } } +static VOID PhpOptionsNotifyChangeCallback( + _In_ PVOID Context + ) +{ + PhUpdateCachedSettings(); + ProcessHacker_SaveAllSettings(PhMainWndHandle); + PhInvalidateAllProcessNodes(); + PhReloadSettingsProcessTreeList(); + PhSiNotifyChangeSettings(); + + if (RestartRequired) + { + if (PhShowMessage2( + PhMainWndHandle, + TDCBF_YES_BUTTON | TDCBF_NO_BUTTON, + TD_INFORMATION_ICON, + L"One or more options you have changed requires a restart of Process Hacker.", + L"Do you want to restart Process Hacker now?" + ) == IDYES) + { + ProcessHacker_PrepareForEarlyShutdown(PhMainWndHandle); + PhShellProcessHacker( + PhMainWndHandle, + L"-v", + SW_SHOW, + 0, + PH_SHELL_APP_PROPAGATE_PARAMETERS | PH_SHELL_APP_PROPAGATE_PARAMETERS_IGNORE_VISIBILITY, + 0, + NULL + ); + ProcessHacker_Destroy(PhMainWndHandle); + } + } +} + static VOID PhpAdvancedPageSave( _In_ HWND hwndDlg ) @@ -1088,6 +1103,8 @@ static VOID PhpAdvancedPageSave( ListView_GetCheckState(listViewHandle, PHP_OPTIONS_INDEX_START_ATLOGON) == BST_CHECKED, ListView_GetCheckState(listViewHandle, PHP_OPTIONS_INDEX_START_HIDDEN) == BST_CHECKED ); + + ProcessHacker_Invoke(PhMainWndHandle, PhpOptionsNotifyChangeCallback, NULL); } static NTSTATUS PhpElevateAdvancedThreadStart( @@ -1267,45 +1284,6 @@ INT_PTR CALLBACK PhpOptionsGeneralDlgProc( { LPNMHDR header = (LPNMHDR)lParam; - //if (header->code == LVN_ITEMCHANGING) - //{ - // LPNM_LISTVIEW listView = (LPNM_LISTVIEW)lParam; - // - // if (listView->uChanged & LVIF_STATE) - // { - // switch (listView->uNewState & LVIS_STATEIMAGEMASK) - // { - // case INDEXTOSTATEIMAGEMASK(2): // checked - // { - // switch (listView->iItem) - // { - // case PHP_OPTIONS_INDEX_SHOW_ADVANCED_OPTIONS: - // { - // if (PhShowMessage2( - // PhOptionsWindowHandle, - // TDCBF_OK_BUTTON | TDCBF_CANCEL_BUTTON, - // TD_WARNING_ICON, - // L"WARNING", - // L"DO NOT change advanced settings unless you know what you're doing..." - // ) == IDOK) - // { - // SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, FALSE); - // return FALSE; - // } - // else - // { - // SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, TRUE); - // return TRUE; - // } - // } - // break; - // } - // } - // break; - // } - // } - //} - switch (header->code) { case NM_CLICK: @@ -1461,7 +1439,7 @@ static INT_PTR CALLBACK PhpOptionsAdvancedEditDlgProc( SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER))); SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER))); - + SetWindowText(hwndDlg, L"Setting Editor"); PhCenterWindow(hwndDlg, GetParent(hwndDlg)); From e4c09aba26967334b9f5abf76cfcf403f5d6341b Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 29 Jun 2018 18:25:11 +1000 Subject: [PATCH 1069/2058] BuildTools: Update appveyor artifacts --- tools/CustomBuildTool/Source Files/Build.cs | 16 ++++++++++++---- .../bin/Release/CustomBuildTool.exe | Bin 163840 -> 164352 bytes .../bin/Release/CustomBuildTool.pdb | Bin 77312 -> 77312 bytes 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/tools/CustomBuildTool/Source Files/Build.cs b/tools/CustomBuildTool/Source Files/Build.cs index c5ad9c99728b..091ddc9b5e15 100644 --- a/tools/CustomBuildTool/Source Files/Build.cs +++ b/tools/CustomBuildTool/Source Files/Build.cs @@ -975,6 +975,14 @@ public static string GetBuildLogString() public static void WebServiceUpdateConfig() { + string accountName = Environment.ExpandEnvironmentVariables("%APPVEYOR_ACCOUNT_NAME%").Replace("%APPVEYOR_ACCOUNT_NAME%", string.Empty); + string projectName = Environment.ExpandEnvironmentVariables("%APPVEYOR_PROJECT_NAME%").Replace("%APPVEYOR_PROJECT_NAME%", string.Empty); + + if (string.IsNullOrEmpty(accountName)) + return; + if (string.IsNullOrEmpty(projectName)) + return; + if (string.IsNullOrEmpty(BuildVersion)) return; if (string.IsNullOrEmpty(BuildSetupHash)) @@ -994,17 +1002,17 @@ public static void WebServiceUpdateConfig() Commit = BuildCommit, Updated = TimeStart.ToString("o"), - BinUrl = "https://ci.appveyor.com/api/projects/processhacker/processhacker2/artifacts/processhacker-" + BuildVersion + "-bin.zip", + BinUrl = $"//ci.appveyor.com/api/projects/{accountName}/{projectName}/artifacts/processhacker-{BuildVersion}-bin.zip", BinLength = BuildBinFileLength.ToString(), BinHash = BuildBinHash, BinSig = BuildBinSig, - SetupUrl = "https://ci.appveyor.com/api/projects/processhacker/processhacker2/artifacts/processhacker-" + BuildVersion + "-setup.exe", + SetupUrl = $"//ci.appveyor.com/api/projects/{accountName}/{projectName}/artifacts/processhacker-{BuildVersion}-setup.exe", SetupLength = BuildSetupFileLength.ToString(), SetupHash = BuildSetupHash, SetupSig = BuildSetupSig, - //WebSetupUrl = "https://ci.appveyor.com/api/projects/processhacker/processhacker2/artifacts/processhacker-websetup.exe", + //WebSetupUrl = "//ci.appveyor.com/api/projects/{accountName}/{projectName}/artifacts/processhacker-websetup.exe", //WebSetupHash = BuildWebSetupHash, //WebSetupVersion = BuildWebSetupVersion, //WebSetupSig = BuildWebSetupSig, @@ -1013,7 +1021,7 @@ public static void WebServiceUpdateConfig() Changelog = buildChangelog, FileLengthDeprecated = BuildSetupFileLength.ToString(), // TODO: Remove after most users have updated. - ForumUrlDeprecated = "https://wj32.org/processhacker/", // TODO: Remove after most users have updated. + ForumUrlDeprecated = "https://wj32.org/processhacker/forums", // TODO: Remove after most users have updated. SetupHashDeprecated = BuildSetupHash, // TODO: Remove after most users have updated. SetupSigDeprecated = BuildSetupSig, // TODO: Remove after most users have updated. BinHashDeprecated = BuildBinHash // TODO: Remove after most users have updated. diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe b/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe index c1aef97483a04a1504eff37b3b1b2594693b6398..ff04c3fc16605648859f89e9c50abe7b79d5a9b6 100644 GIT binary patch delta 13409 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 delta 13252 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 delta 6395 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 From 6beede9afff1f42033f3d6b3d8ea655ee2f8bf72 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 29 Jun 2018 18:35:31 +1000 Subject: [PATCH 1070/2058] Fix previous commit --- tools/CustomBuildTool/Source Files/Build.cs | 7 +++---- .../bin/Release/CustomBuildTool.exe | Bin 164352 -> 164352 bytes .../bin/Release/CustomBuildTool.pdb | Bin 77312 -> 77312 bytes 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/tools/CustomBuildTool/Source Files/Build.cs b/tools/CustomBuildTool/Source Files/Build.cs index 091ddc9b5e15..a5deee31e395 100644 --- a/tools/CustomBuildTool/Source Files/Build.cs +++ b/tools/CustomBuildTool/Source Files/Build.cs @@ -982,7 +982,6 @@ public static void WebServiceUpdateConfig() return; if (string.IsNullOrEmpty(projectName)) return; - if (string.IsNullOrEmpty(BuildVersion)) return; if (string.IsNullOrEmpty(BuildSetupHash)) @@ -1002,17 +1001,17 @@ public static void WebServiceUpdateConfig() Commit = BuildCommit, Updated = TimeStart.ToString("o"), - BinUrl = $"//ci.appveyor.com/api/projects/{accountName}/{projectName}/artifacts/processhacker-{BuildVersion}-bin.zip", + BinUrl = $"https://ci.appveyor.com/api/projects/%7BaccountName%7D/%7BprojectName%7D/artifacts/processhacker-%7BBuildVersion%7D-bin.zip", BinLength = BuildBinFileLength.ToString(), BinHash = BuildBinHash, BinSig = BuildBinSig, - SetupUrl = $"//ci.appveyor.com/api/projects/{accountName}/{projectName}/artifacts/processhacker-{BuildVersion}-setup.exe", + SetupUrl = $"https://ci.appveyor.com/api/projects/%7BaccountName%7D/%7BprojectName%7D/artifacts/processhacker-%7BBuildVersion%7D-setup.exe", SetupLength = BuildSetupFileLength.ToString(), SetupHash = BuildSetupHash, SetupSig = BuildSetupSig, - //WebSetupUrl = "//ci.appveyor.com/api/projects/{accountName}/{projectName}/artifacts/processhacker-websetup.exe", + //WebSetupUrl = "https://ci.appveyor.com/api/projects/%7BaccountName%7D/%7BprojectName%7D/artifacts/processhacker-websetup.exe", //WebSetupHash = BuildWebSetupHash, //WebSetupVersion = BuildWebSetupVersion, //WebSetupSig = BuildWebSetupSig, diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe b/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe index ff04c3fc16605648859f89e9c50abe7b79d5a9b6..7db515a069453fd71e13a3f9d3899b4878617bf7 100644 GIT binary patch delta 4074 zcma)93viUx75?wCSvLDhHk<6@-}i1dyCfS3n~)bFB-ykO66rt;Zv`!2TM9`IT45sW zB8nix7`!|++G)lrbXtV&v5)#h)Ms9S5bw3b5kV1 z*j2dLvdb=u0UY$294_Pz_e3#O150dxmN}Q;O1C)O1$&Y8>Z}tY%W(|6K>cpt1P#1G zFF0+@zh@(KIKt}boy;b>i3Fdww+GcS4culPCKmG!(^PuUT}JMsr`@vuM5WYMkq75c z42SIS9+wVHZycixhh(Uux7>0e&cVC}Pz;A$nB_57d@Rc+k;~08Kv<3?En2u+mfHWG zr5652mb-W!4(;8t40+}yM$ng+KC}4+Q!>ohme(oF*hcp#j4ZZ(y}~#Jvr}PQf;p}* zZoynhWGEe&tFTmhn@4Quqo{4h{#U~pM51R{x9dT%{4>X5@J7Kr6-V(N&P*R!js4+` zWtlR0L{=B0&9@J~vMlozy4~vuufj->z@OeaoYj~QPqEOf3k4x&8KLLBZu=|Dt(7&F zSq-TP=@gDrkI$)^7^7aFtm@~&`hG0kh}<9gWt^siuJQR>?x~jgoV|-MOk)x=GHYRB zhNhkOTFd^ebO|Yi94vYTgc!dW=8OxoaLCE+H!% z=I-LNXAS%)}4KAZ}l@SlG_czEWGjQJ1?nQ@F0|&6(Q&YYWfNk4gs<-@(DT$3a42 z#*TwmGmH*CK>SVLY)SptTKEl>{mnMySPZa~>Fe<`G-@n)bTm}c`3N%E&DPbBTky?H zk5phG_;q1X<0ThGtul&V-%&I=dzUiR4S%40WudN1e7w@UpN@-H+Q{OIQ;QwnE13RG z@nv|H{=H1DIfM>k2Y7M#b;d3(C6fqdauL0Hm$5`-uurG`WhJydJYcGto=z}ogCsp4 zUX~a_D#?yIPx`Ywr(!AD;MZtjpXFOzI^Z)dWl%Tql)=ZP3mUm}!w;EEmS8AvCf0Ab z%?4+=w8LdC9q>7qGN=+WL@+CtE-2&D4NY8nU@n*5e0Wd*9e@CO*d~Ahh6FIeQ2|Ww zrT_(SQGi1DTmUnuo7sfkA}Hn{;k7`ipo*bhfD-5uzzRzQu)#V3?C`h%4%jDv3@-`b zgi`{z;F17t_?m&Fm6ar%F0W}OOTY#JE)#ZWzzqS6U})jXHGwQZ0Yn8Tgcb%8A+H(c3#tfK3SfbC0u)11fD$+$ zfEA7iV1v^F*x|1NIN)Cb;I_8%S)EWMfD1|ma6_X29=Ml-xYr9S1m%N=1@Obu0t8@4 zfFK+ZpcGCC5Q29ED1(pbNcp71*QjptV5L>yYeVQ{(3UQG7gEEUT#Qqi^L|F+PORh7 z4oNO?XStN&XIwhrH7;H77ME`LkV_9-=MpzU8aA;9 zpgg-OS8B}a=dzy<-JHmJceQaM>*Y0-6C0JMn2!@D=&`!BY=Zjze45(&g`8I=i?#?y zwhn$vRB`=$Mi+tphJiwKPQ#$)6STlp`eDNe8BP7EaRDK>Qr@Pu1edgHMiW^@&(3Ih z=!Mx>3ieFaRp=qmkybPj{%)w%z!2luWu>3UFU_c`xO^gX%t1E5I)(cgvY7JXaw+l% z4lrn=<=Wnji15AI-)t?)3^HDJUv^m3@FYFh{4V)b3T9d-kl)fBZH=n@PWnb$0F(Q) z?GX0q?)bcdU?;l(53t_r)Ib9rjr&QETH2S88FXFyT*n6dziY6kTZ-bdybzluIIE|l z9c5GMFYS)?#-DsodKmxqN$aIXiC#Ot&-l}E%(j%_MABb)^vKPI;ESQw-DkI6pER=b zLTcz@lRX-{HVq#KlBB|aE^KhEnMm3%Bx!zkdw1)jr>dFx rVOJ5ljs01Tc>l2~m7Od~O}qX&*=o9R+;oF{wL`TbcHBH)b%Xo|kK_Jc delta 4062 zcma)<3v83u6@dTiB*xf|6Jy7Z-)}okOzfm2b`nVQFi9Yggl;qqkU+ zX>b^6MYnb&-12HSP_vbRRzXv*1yxfwC|xT800hj!x`q;|C*+bOEi}+JTOrv% zdu(Cbi)b~f6K!ZWPBZ2hvqSAH)g5)B-Xba%J;##2&me#wd!k@S+ z;YQj=*B1A=5Xcpq1B_cWQA7Z7IvsS z3dL~H1}C|+s}oH)%WzNz5B}xYBuq)|%1h-GgsghI^Fm@VJW?m1AqJ!=FSou9`a?63Dy@g+Z)xo}Tl#>^oW5 zT-I2|Y)EBIq;RmDdc3mg3ob|(b$cC_H!CI@k;g-?jLVeMN4&mxWmM{MB$nYcHT{^8 zQ3DNWOKC5vZHl@E)uoEsf$C~{)*H}0g2v&X9rexhmUs5t^xhe>c{_w=&sSk> z`@27&pD3FFF30FsULRc$u#h^sGT`=2Em2M-uW-6VVR|57zhi~M^n-vq^NI5^p7`6; zQ0TCjt0uLEDAjV>P$*kRn2R5f0o=ZbS@=e1PodRMsweM_mFvphj8y$!TR1{LDI82z zt^4Gny|70=zoS*v6`etW(^w7lg&G;JTs!cicS}@jjKUy-I zEjDLz!Phc96vjgE&xI))KXMV&N+bC8?L(&{v7D(cc!~BD1=~;a@k;Yvm@=QfhRrWd zEp~h_VEWh1FT-Q><03gWhyh{;cyah+vJaP%NeDAJg;9wWED;%`yJ>Gx0c|ecVzAvk zkzm9M>*=}T70CfK^|PbSJ@HzOs#r=^IDj7ZTE51m9e&HD3|F{xfTouDo#5xv1@|%8 zUw~72(sK=SpA}x=(gwfb(hl!)DZ}SU4i5MimrgL$u}NJ}$fX;qxb#eiRsmY*7NCPo z0`xE-AQ$!tFu+j(d2mWVKD;l$2v-EmfPZjEdQ70NXKQ-Q;1y5+F##566kvrV0&MWG z06T0IAj8uF9B@d06HW_o!DkHmEvzKP6XhM_PAg~|*s4hz_&M02ic1+5aOr?^KfDXVL(6t_6R71Ljr>Ex_}}$OD~tqOn!!HpBpQ!0!<^LgQ0bz=rJ@6_c@tOY0mk~ zh>gC4OB<}`5_gtM8Fq2$fS+>dgx9!q!8=^K;SXHmMqF)_lB|QYplafesRN4uJ%j}0 zLcIV3+$$gt)(Xgn#|0Q+P{0g0B)|l(3oyf30R`}p01J!>u!5#p>S@L0ZQw*gu){0? zGRzl%-6X&Xn*_Mvdkp&Uh{TfZL+v1){0Z(tZ_bqV2QlLoF;~5F<3O2+^qBV#A=&eQ4n)`na!!zB23Ixt%O{H=C{) zI_VqbVX}^XUhcJQPuu5NLwF>qOGya~QEx?@yhvA9%p}L?4=Sq2oAgx0LUN8?i+X4{ zsbK{$jITH6Nxa%9F#-BZ9&;_)Zi!CBM7orKg&5$cFIQye zuuRyB7W!<=6zE6?mjUC@Doi#)N-XKD6ZA~XOSYvKD5foyaWX`AR9+yvX;;--1n*_l zwM&$1SLuUlWA<~I*M|;n$hdbkazn<=tDGBFD_1cuH@rYcsyDI)X7A<8RLx$>?aE@2 zxCms=!M_r-xc+Kd7Zd#oCkoQmIfLqR=z(|XM{_Qdi>Y^NmJsr3%2T_M;3GX#S4$Sr zGj;KGPb|PvuurZwtOM=B2}K>^_l7Dp3@{t}Sm~zmk7h(=E|~`9t!P#57y1lKiMd1y zJ&FVLnn;Nz@m(amulCkkW~2w@UUFTso3dde-CzF!`Ed#wELr4d^r^-g)wNdoR-+%2 z`*Y)A?9-v9#d*3m_5s|-daq3lK6EE9^a6;|RKe}tt^J}_8^PYR?lcATN zuKG#p7a!KzBFC;&;)OtxRQTVCO??&r=Dzw@NxHYAxg)pk);AX#{y2Z|$c>}FKd<{V v<-D#Txv?1-HvaD(T7JVp;;BV9P7)d?w(W+onYW$isL5>$r$+$Kpyg% diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb b/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb index 94d013496f32d9867f0fc3a9fa77eaa00bd02c93..2f5f2baf13c797f4f6eca18d025791f82ed85c04 100644 GIT binary patch delta 1957 zcmZ|Qdr*{B7{~Ev;avu~tBWB*2^un`jhW?if!xSYNlCC0g`f<(2w_GDGS0i|%4O+- zu3RdNiy)X5;Ti~u<>Yvo$pJ@fQa}`e(PWeyv6*U`zNdNr?T?+$d4A8kXU}=}yt}qO z&DN)Vt9b>@yZ!hYlZaS19h)1Szdfe1zVr8!NxO4hAzrgREDs$l4|&pOdBV^4EbGsd zyd3Fpw70Za>rICyc?Nh^WrhXV{d-Im@B5i1?|doLxiCCeyW8tA?m8M?zd*m}F17?_ zzJ!U`i>cU$Y1oe$co{Qs0Q2w)ZpN!vfP+|wLs)^s*oY(UvZs!vn>Dc=Ko2~Ko_NY6 zx=dg&NZ^e((FaG-7st^L?_mJ?xrtcNf>UrB2H_(Zj7u>DSK$4aiqkOi5R50h{{uEr-Y8RIYo z6H!f&WSE9)sn?;J?`@;b!gTUnd<#Fp_1J(J*l2oMB$L5@f-F3S8}KJo6P-ad@j1-F zG0ep~nCJXB<&?gKY6AP!(I0I%2e%@V%Qjqsc1*z?_zo7}hggW}TovIVEJk(zOEf83 z$)}W2Cu0R}#7fM@D%_&(-VG|DF33U&K8C)S4!N2i3s%Pp32I7Bb%&5a~ zR1dk z9zhHCU?7g+6!g(V?!!o&iceuMT2U?d1*2Yup)BAFjG#YY^oNc97)MVcX?UAO9_GSD z_!#OKMP7o@Sc%W#VO)saXvLctgC-A==P?jtd4D{{V==x;{wb=3?KJ92Od^k}Ww4q- zlX1Z}#s#gIOnwAYume-E3)Ao%zU~TpBi5v+n`K87M@w=lFo(PjH{pJx-)!{TaI;y8?x3B%7bm0uAHYJKWs-Nr!A8~dRZ5VLyRa0UScc_h z+17%eQ=i5vRFBghR6q08ID|Dgf_3;8?nU7!?L#+gbgp=_TK}5LljSs{`qgN`X{fdp zYSc5)MZN&P!&q#^~B;zs-tv++1ilyy9?kIGzm&Xtv3*73i8 MzHK4XO+&u_0=z4_JOBUy delta 1957 zcmZ|QeN0tl9KiA4;oeIK0TPfX65&heCas+2R-wW`1vF8ziO5Ta%$kIlCdles5xBf) zL01Lmh?gKB8Ys7fNU4;i{ZYWgnhIjPnM%Z%xt6WQ=Q+nZ zV73mJPn%u+S|^q#Xd>bs`gd%U$IzP6ru!{7dfY}Fb6uA>`%G$XddalyVpsR}rQ;Ew zW%ftng^Rmpr-)`}CoSRp-LceYj>t=es zfpIv1$vB89coTQy5T@fT%*J2wAP!>zj-U<4upGy+0dJe6vX-Gco5k9UkKyMy121W! ziz|&`5|86ObjJzwz(3IwAD|a{IEnb856(h=oQ=<-KSpB!Zo)uJ#vshb`Iv)~fBb7L zFtj<%7g<1|h{QrH!CedEW~(Rira7*Cg2O0h%uOi zai}_oH%!4);xttK?K0vFOe3F#yYK_tjrEw04cbd0Z_{WZu?M>_6EC9b=m$(C?!yB( zh1ocb2kl1_FX`_S&0xM(^u$9Lg1JcNau}m99}}?v-$Wbk$3j&5stDV#7}fe8F-zgA z{L2aA?O1_(@g(lUN_P+25UwpL3j5r8? zH%ndyKA`R}>R%c4Zv2b<5I*F(*(MQ_Me^d%&BDV#4}1eX@m-THGLuFT2`{WdZ)`>% z>_A`a$0ug3_~^GHAc({lBXEJDGa90sywQX8TBch#$pPLPL^37=fCz2=`ijaUJ(>#8@oCt>iyMHLx-xuE1^NLu+Ux z&}cL+XfZB0i;3hrFbO*`1$*#y?86<7pdD*9JxF1VV zjpHLDK8Xj&*J2hn8TD49-i|pIDV)Z9>aOe%8wO$_25a(`ut<68e3g;NK|7Y>F+7gt z7Rfz>r-(0OC931}F{;;mHI8Bpj^iiz5bIFbN)70QjrL8cReB4N3&S~$>aEd+{-~xE zV8jcMM`c}sXK^jI<10q}HS8qbieF%zVG9qz*m=p|_!*yrUr33p`dJl^@g NAK&)5Piv#@{{iQey~_Xq From 3d7dff975e362da6c3ef38700b3e58fd7975c878 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 29 Jun 2018 18:49:04 +1000 Subject: [PATCH 1071/2058] Add settings for options window position --- ProcessHacker/settings.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ProcessHacker/settings.c b/ProcessHacker/settings.c index fcf2681d6139..9ff911ddc241 100644 --- a/ProcessHacker/settings.c +++ b/ProcessHacker/settings.c @@ -122,6 +122,8 @@ VOID PhAddDefaultSettings( PhpAddStringSetting(L"NetworkTreeListColumns", L""); PhpAddStringSetting(L"NetworkTreeListSort", L"0,1"); // 0, AscendingSortOrder PhpAddIntegerSetting(L"NoPurgeProcessRecords", L"0"); + PhpAddIntegerPairSetting(L"OptionsWindowPosition", L"200,200"); + PhpAddScalableIntegerPairSetting(L"OptionsWindowSize", L"@96|900,590"); PhpAddIntegerPairSetting(L"PluginManagerWindowPosition", L"0,0"); PhpAddScalableIntegerPairSetting(L"PluginManagerWindowSize", L"@96|900,590"); PhpAddStringSetting(L"PluginManagerTreeListColumns", L""); From b133e0e108cf81ae9bc4b8c234e13d13958b96a8 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 1 Jul 2018 17:53:41 +1000 Subject: [PATCH 1072/2058] Update process node cache --- ProcessHacker/include/proctree.h | 8 +++---- ProcessHacker/proctree.c | 36 ++++++++++++++++++++++++-------- 2 files changed, 31 insertions(+), 13 deletions(-) diff --git a/ProcessHacker/include/proctree.h b/ProcessHacker/include/proctree.h index 400b33263670..9ba8ccd29a84 100644 --- a/ProcessHacker/include/proctree.h +++ b/ProcessHacker/include/proctree.h @@ -176,13 +176,13 @@ typedef struct _PH_PROCESS_NODE ULONG64 TooltipTextValidToTickCount; // Text buffers - WCHAR CpuUsageText[PH_INT32_STR_LEN_1]; - PPH_STRING IoTotalRateText; - PPH_STRING PrivateBytesText; + WCHAR CpuUsageText[PH_INT32_STR_LEN_1 + 3]; + WCHAR IoTotalRateText[PH_INT32_STR_LEN_1 + 3]; + WCHAR PrivateBytesText[PH_INT32_STR_LEN_1]; PPH_STRING PeakPrivateBytesText; PPH_STRING WorkingSetText; PPH_STRING PeakWorkingSetText; - PPH_STRING PrivateWsText; + WCHAR PrivateWsText[PH_INT32_STR_LEN_1]; PPH_STRING SharedWsText; PPH_STRING ShareableWsText; PPH_STRING VirtualSizeText; diff --git a/ProcessHacker/proctree.c b/ProcessHacker/proctree.c index b0e6733c9437..fd532c581fd1 100644 --- a/ProcessHacker/proctree.c +++ b/ProcessHacker/proctree.c @@ -563,12 +563,9 @@ VOID PhpRemoveProcessNode( PhClearReference(&ProcessNode->TooltipText); - PhClearReference(&ProcessNode->IoTotalRateText); - PhClearReference(&ProcessNode->PrivateBytesText); PhClearReference(&ProcessNode->PeakPrivateBytesText); PhClearReference(&ProcessNode->WorkingSetText); PhClearReference(&ProcessNode->PeakWorkingSetText); - PhClearReference(&ProcessNode->PrivateWsText); PhClearReference(&ProcessNode->SharedWsText); PhClearReference(&ProcessNode->ShareableWsText); PhClearReference(&ProcessNode->VirtualSizeText); @@ -2141,21 +2138,34 @@ BOOLEAN NTAPI PhpProcessTreeNewCallback( if (number != 0) { + SIZE_T returnLength; PH_FORMAT format[2]; PhInitFormatSize(&format[0], number); PhInitFormatS(&format[1], L"/s"); - PhMoveReference(&node->IoTotalRateText, PhFormat(format, 2, 0)); - getCellText->Text = node->IoTotalRateText->sr; + + if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), node->IoTotalRateText, sizeof(node->IoTotalRateText), &returnLength)) + { + getCellText->Text.Buffer = node->IoTotalRateText; + getCellText->Text.Length = returnLength - sizeof(WCHAR); + } } } break; case PHPRTLC_PRIVATEBYTES: { SIZE_T value = 0; + SIZE_T returnLength; + PH_FORMAT format[1]; + PhpAggregateFieldIfNeeded(node, AggregateTypeIntPtr, AggregateLocationProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, VmCounters.PagefileUsage), &value); - PhMoveReference(&node->PrivateBytesText, PhFormatSize(value, -1)); - getCellText->Text = node->PrivateBytesText->sr; + PhInitFormatSize(&format[0], value); + + if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), node->PrivateBytesText, sizeof(node->PrivateBytesText), &returnLength)) + { + getCellText->Text.Buffer = node->PrivateBytesText; + getCellText->Text.Length = returnLength - sizeof(WCHAR); + } } break; case PHPRTLC_USERNAME: @@ -2198,9 +2208,17 @@ BOOLEAN NTAPI PhpProcessTreeNewCallback( case PHPRTLC_PRIVATEWS: { SIZE_T value = 0; + SIZE_T returnLength; + PH_FORMAT format[1]; + PhpAggregateFieldIfNeeded(node, AggregateTypeIntPtr, AggregateLocationProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, WorkingSetPrivateSize), &value); - PhMoveReference(&node->PrivateWsText, PhFormatSize(value, -1)); - getCellText->Text = node->PrivateWsText->sr; + PhInitFormatSize(&format[0], value); + + if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), node->PrivateWsText, sizeof(node->PrivateWsText), &returnLength)) + { + getCellText->Text.Buffer = node->PrivateWsText; + getCellText->Text.Length = returnLength - sizeof(WCHAR); + } } break; case PHPRTLC_SHAREDWS: From ae84053fa5593b45d2f7afdcde8030fd1b2e4f9e Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 1 Jul 2018 17:56:36 +1000 Subject: [PATCH 1073/2058] Fix module cache size, Fix runas ForceNoParent --- ProcessHacker/runas.c | 3 ++- phlib/native.c | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/ProcessHacker/runas.c b/ProcessHacker/runas.c index 53ff6c85996c..c4120d6a5a7c 100644 --- a/ProcessHacker/runas.c +++ b/ProcessHacker/runas.c @@ -73,6 +73,7 @@ #include #include #include +#include #include #include @@ -192,7 +193,7 @@ VOID PhShowRunAsDialog( DialogBoxParam( PhInstanceHandle, MAKEINTRESOURCE(IDD_RUNAS), - !!PhGetIntegerSetting(L"ForceNoParent") ? NULL : ParentWindowHandle, + PhCsForceNoParent ? NULL : ParentWindowHandle, PhpRunAsDlgProc, (LPARAM)ProcessId ); diff --git a/phlib/native.c b/phlib/native.c index 4dd94313f197..eb99e3c02988 100644 --- a/phlib/native.c +++ b/phlib/native.c @@ -5792,7 +5792,7 @@ NTSTATUS PhEnumGenericModules( sizeof(PVOID), PhpBaseAddressHashtableEqualFunction, PhpBaseAddressHashtableHashFunction, - 32 + 100 ); if (ProcessId == SYSTEM_PROCESS_ID) From f91034bf86f5e7c2a8a5ddc37b9eb5d99cbad693 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 1 Jul 2018 17:58:37 +1000 Subject: [PATCH 1074/2058] Add legacy handle enumeration fallback --- ProcessHacker/hndlprv.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/ProcessHacker/hndlprv.c b/ProcessHacker/hndlprv.c index 5d7c32e15ca9..d08c48859b1b 100644 --- a/ProcessHacker/hndlprv.c +++ b/ProcessHacker/hndlprv.c @@ -341,6 +341,41 @@ NTSTATUS PhEnumHandlesGeneric( *Handles = convertedHandles; *FilterNeeded = FALSE; } + else if (KphIsConnected()) + { + PKPH_PROCESS_HANDLE_INFORMATION handles; + PSYSTEM_HANDLE_INFORMATION_EX convertedHandles; + ULONG i; + + // Enumerate handles using KProcessHacker. Unlike with NtQuerySystemInformation, + // this only enumerates handles for a single process and saves a lot of processing. + + if (!NT_SUCCESS(status = KphEnumerateProcessHandles2(ProcessHandle, &handles))) + goto FAILED; + + convertedHandles = PhAllocate( + FIELD_OFFSET(SYSTEM_HANDLE_INFORMATION_EX, Handles) + + sizeof(SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX) * handles->HandleCount + ); + + convertedHandles->NumberOfHandles = handles->HandleCount; + + for (i = 0; i < handles->HandleCount; i++) + { + convertedHandles->Handles[i].Object = handles->Handles[i].Object; + convertedHandles->Handles[i].UniqueProcessId = (ULONG_PTR)ProcessId; + convertedHandles->Handles[i].HandleValue = (ULONG_PTR)handles->Handles[i].Handle; + convertedHandles->Handles[i].GrantedAccess = (ULONG)handles->Handles[i].GrantedAccess; + convertedHandles->Handles[i].CreatorBackTraceIndex = 0; + convertedHandles->Handles[i].ObjectTypeIndex = handles->Handles[i].ObjectTypeIndex; + convertedHandles->Handles[i].HandleAttributes = handles->Handles[i].HandleAttributes; + } + + PhFree(handles); + + *Handles = convertedHandles; + *FilterNeeded = FALSE; + } else { PSYSTEM_HANDLE_INFORMATION_EX handles; From de9cf1eecc4e367b910affffb60e01412987ea5d Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 1 Jul 2018 18:08:23 +1000 Subject: [PATCH 1075/2058] Update provider caching --- ProcessHacker/findobj.c | 4 --- ProcessHacker/hndllist.c | 18 +++++------ ProcessHacker/hndlprp.c | 18 ++++++----- ProcessHacker/hndlprv.c | 6 ---- ProcessHacker/include/modprv.h | 2 +- ProcessHacker/include/phsettings.h | 2 +- ProcessHacker/include/thrdlist.h | 1 + ProcessHacker/include/thrdprv.h | 22 ++++++------- ProcessHacker/mainwnd.c | 1 + ProcessHacker/modlist.c | 2 +- ProcessHacker/modprv.c | 50 ++++++++++++++---------------- ProcessHacker/options.c | 7 +++-- ProcessHacker/procprp.c | 4 --- ProcessHacker/procprv.c | 16 +++++----- ProcessHacker/settings.c | 4 --- ProcessHacker/sysinfo.c | 3 -- ProcessHacker/thrdlist.c | 16 +++++++++- ProcessHacker/thrdprv.c | 5 --- 18 files changed, 86 insertions(+), 95 deletions(-) diff --git a/ProcessHacker/findobj.c b/ProcessHacker/findobj.c index 2cf013104f62..e9b6950f8f95 100644 --- a/ProcessHacker/findobj.c +++ b/ProcessHacker/findobj.c @@ -1192,10 +1192,6 @@ INT_PTR CALLBACK PhpFindObjectsDlgProc( Edit_SetSel(context->SearchWindowHandle, 0, -1); Button_SetCheck(GetDlgItem(hwndDlg, IDC_REGEX), PhGetIntegerSetting(L"FindObjRegex") ? BST_CHECKED : BST_UNCHECKED); - - // HACK HACK HACK - if (WindowsVersion >= WINDOWS_10_RS3 && !!PhGetIntegerSetting(L"EnableExperimentalWindowStyle")) - PhSetWindowStyle(hwndDlg, WS_POPUP, 0); } break; case WM_DESTROY: diff --git a/ProcessHacker/hndllist.c b/ProcessHacker/hndllist.c index bc48a37bb1e9..6a4b70986704 100644 --- a/ProcessHacker/hndllist.c +++ b/ProcessHacker/hndllist.c @@ -529,10 +529,16 @@ BOOLEAN NTAPI PhpHandleTreeNewCallback( getCellText->Text = PhGetStringRef(handleItem->BestObjectName); break; case PHHNTLC_HANDLE: + PhPrintPointer(handleItem->HandleString, (PVOID)handleItem->Handle); PhInitializeStringRefLongHint(&getCellText->Text, handleItem->HandleString); break; case PHHNTLC_OBJECTADDRESS: - PhInitializeStringRefLongHint(&getCellText->Text, handleItem->ObjectString); + { + if (handleItem->Object) + PhPrintPointer(handleItem->ObjectString, handleItem->Object); + + PhInitializeStringRefLongHint(&getCellText->Text, handleItem->ObjectString); + } break; case PHHNTLC_ATTRIBUTES: switch (handleItem->Attributes & (OBJ_PROTECT_CLOSE | OBJ_INHERIT)) @@ -549,6 +555,7 @@ BOOLEAN NTAPI PhpHandleTreeNewCallback( } break; case PHHNTLC_GRANTEDACCESS: + PhPrintPointer(handleItem->GrantedAccessString, UlongToPtr(handleItem->GrantedAccess)); PhInitializeStringRefLongHint(&getCellText->Text, handleItem->GrantedAccessString); break; case PHHNTLC_GRANTEDACCESSSYMBOLIC: @@ -564,16 +571,9 @@ BOOLEAN NTAPI PhpHandleTreeNewCallback( node->GrantedAccessSymbolicText = PhGetAccessString(handleItem->GrantedAccess, accessEntries, numberOfAccessEntries); PhFree(accessEntries); } - else - { - node->GrantedAccessSymbolicText = PhReferenceEmptyString(); - } } - if (node->GrantedAccessSymbolicText->Length != 0) - getCellText->Text = node->GrantedAccessSymbolicText->sr; - else - PhInitializeStringRefLongHint(&getCellText->Text, handleItem->GrantedAccessString); + getCellText->Text = PhGetStringRef(node->GrantedAccessSymbolicText); } break; case PHHNTLC_ORIGINALNAME: diff --git a/ProcessHacker/hndlprp.c b/ProcessHacker/hndlprp.c index ae8953721670..a5d6aecf6636 100644 --- a/ProcessHacker/hndlprp.c +++ b/ProcessHacker/hndlprp.c @@ -279,23 +279,27 @@ INT_PTR CALLBACK PhpHandleGeneralDlgProc( if (accessString->Length != 0) { - grantedAccessString = PhaFormatString( - L"%s (%s)", - context->HandleItem->GrantedAccessString, + grantedAccessString = PH_AUTO(PhFormatString( + L"0x%x (%s)", + context->HandleItem->GrantedAccess, accessString->Buffer - ); + )); PhSetDialogItemText(hwndDlg, IDC_GRANTED_ACCESS, grantedAccessString->Buffer); } else { - PhSetDialogItemText(hwndDlg, IDC_GRANTED_ACCESS, context->HandleItem->GrantedAccessString); + WCHAR grantedAccessString[PH_PTR_STR_LEN]; + PhPrintPointer(grantedAccessString, UlongToPtr(context->HandleItem->GrantedAccess)); + PhSetDialogItemText(hwndDlg, IDC_GRANTED_ACCESS, grantedAccessString); } PhFree(accessEntries); } else { - PhSetDialogItemText(hwndDlg, IDC_GRANTED_ACCESS, context->HandleItem->GrantedAccessString); + WCHAR grantedAccessString[PH_PTR_STR_LEN]; + PhPrintPointer(grantedAccessString, UlongToPtr(context->HandleItem->GrantedAccess)); + PhSetDialogItemText(hwndDlg, IDC_GRANTED_ACCESS, grantedAccessString); } if (NT_SUCCESS(PhOpenProcess( @@ -307,7 +311,7 @@ INT_PTR CALLBACK PhpHandleGeneralDlgProc( if (NT_SUCCESS(PhGetHandleInformation( processHandle, context->HandleItem->Handle, - -1, + ULONG_MAX, &basicInfo, NULL, NULL, diff --git a/ProcessHacker/hndlprv.c b/ProcessHacker/hndlprv.c index d08c48859b1b..fd5a2a24aa2f 100644 --- a/ProcessHacker/hndlprv.c +++ b/ProcessHacker/hndlprv.c @@ -139,12 +139,6 @@ PPH_HANDLE_ITEM PhCreateHandleItem( handleItem->Attributes = Handle->HandleAttributes; handleItem->GrantedAccess = (ACCESS_MASK)Handle->GrantedAccess; handleItem->TypeIndex = Handle->ObjectTypeIndex; - - PhPrintPointer(handleItem->HandleString, (PVOID)handleItem->Handle); - PhPrintPointer(handleItem->GrantedAccessString, UlongToPtr(handleItem->GrantedAccess)); - - if (handleItem->Object) - PhPrintPointer(handleItem->ObjectString, handleItem->Object); } PhEmCallObjectOperation(EmHandleItemType, handleItem, EmObjectCreate); diff --git a/ProcessHacker/include/modprv.h b/ProcessHacker/include/modprv.h index 436058f416b8..bb9efc5146d3 100644 --- a/ProcessHacker/include/modprv.h +++ b/ProcessHacker/include/modprv.h @@ -57,7 +57,7 @@ typedef struct _PH_MODULE_PROVIDER HANDLE ProcessId; HANDLE ProcessHandle; - PPH_STRING FileName; + PPH_STRING ProcessFileName; PPH_STRING PackageFullName; SLIST_HEADER QueryListHead; NTSTATUS RunStatus; diff --git a/ProcessHacker/include/phsettings.h b/ProcessHacker/include/phsettings.h index a457ded4dd4b..1c26890f8660 100644 --- a/ProcessHacker/include/phsettings.h +++ b/ProcessHacker/include/phsettings.h @@ -13,6 +13,7 @@ EXT BOOLEAN PhEnableProcessQueryStage2; EXT BOOLEAN PhEnableServiceQueryStage2; +EXT BOOLEAN PhEnableHexId; EXT ULONG PhCsCollapseServicesOnStart; EXT ULONG PhCsForceNoParent; @@ -20,7 +21,6 @@ EXT ULONG PhCsHighlightingDuration; EXT ULONG PhCsPropagateCpuUsage; EXT ULONG PhCsScrollToNewProcesses; EXT ULONG PhCsShowCpuBelow001; -EXT ULONG PhCsShowHexId; EXT ULONG PhCsUpdateInterval; EXT ULONG PhCsColorNew; diff --git a/ProcessHacker/include/thrdlist.h b/ProcessHacker/include/thrdlist.h index c17f97f69e73..51dceb55a7db 100644 --- a/ProcessHacker/include/thrdlist.h +++ b/ProcessHacker/include/thrdlist.h @@ -31,6 +31,7 @@ typedef struct _PH_THREAD_NODE ULONG ValidMask; + WCHAR ThreadIdText[PH_INT32_STR_LEN_1]; WCHAR CpuUsageText[PH_INT32_STR_LEN_1]; PPH_STRING CyclesDeltaText; // used for Context Switches Delta as well PPH_STRING StartAddressText; diff --git a/ProcessHacker/include/thrdprv.h b/ProcessHacker/include/thrdprv.h index 971f06779e3d..78f7cfc90546 100644 --- a/ProcessHacker/include/thrdprv.h +++ b/ProcessHacker/include/thrdprv.h @@ -12,32 +12,30 @@ typedef struct _PH_THREAD_ITEM LARGE_INTEGER CreateTime; LARGE_INTEGER KernelTime; LARGE_INTEGER UserTime; - - FLOAT CpuUsage; PH_UINT64_DELTA CpuKernelDelta; PH_UINT64_DELTA CpuUserDelta; - PH_UINT32_DELTA ContextSwitchesDelta; PH_UINT64_DELTA CyclesDelta; + + FLOAT CpuUsage; LONG Priority; LONG BasePriority; - ULONG64 StartAddress; - PPH_STRING StartAddressString; - PPH_STRING StartAddressFileName; - enum _PH_SYMBOL_RESOLVE_LEVEL StartAddressResolveLevel; KTHREAD_STATE State; KWAIT_REASON WaitReason; LONG BasePriorityIncrement; - PPH_STRING ServiceName; HANDLE ThreadHandle; - BOOLEAN IsGuiThread; - BOOLEAN JustResolved; + PPH_STRING ServiceName; + PPH_STRING ThreadName; - WCHAR ThreadIdString[PH_INT32_STR_LEN_1]; + ULONG64 StartAddress; + PPH_STRING StartAddressString; + PPH_STRING StartAddressFileName; + enum _PH_SYMBOL_RESOLVE_LEVEL StartAddressResolveLevel; - PPH_STRING ThreadName; + BOOLEAN IsGuiThread; + BOOLEAN JustResolved; } PH_THREAD_ITEM, *PPH_THREAD_ITEM; typedef enum _PH_KNOWN_PROCESS_TYPE PH_KNOWN_PROCESS_TYPE; diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index 0a17687c3e48..9ba16b465d5f 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -2118,6 +2118,7 @@ VOID PhMwpLoadSettings( PhEnableNetworkProviderResolve = !!PhGetIntegerSetting(L"EnableNetworkResolve"); PhEnableProcessQueryStage2 = !!PhGetIntegerSetting(L"EnableStage2"); PhEnableServiceQueryStage2 = !!PhGetIntegerSetting(L"EnableServiceStage2"); + PhEnableHexId = !!PhGetIntegerSetting(L"ShowHexId"); PhMwpNotifyIconNotifyMask = PhGetIntegerSetting(L"IconNotifyMask"); if (PhGetIntegerSetting(L"MainWindowAlwaysOnTop")) diff --git a/ProcessHacker/modlist.c b/ProcessHacker/modlist.c index 89bb1661f9be..0466fcda7817 100644 --- a/ProcessHacker/modlist.c +++ b/ProcessHacker/modlist.c @@ -460,7 +460,6 @@ VOID PhExpandAllModuleNodes( TreeNew_NodesStructured(Context->TreeNewHandle); } - VOID PhTickModuleNodes( _In_ PPH_MODULE_LIST_CONTEXT Context ) @@ -774,6 +773,7 @@ BOOLEAN NTAPI PhpModuleTreeNewCallback( getCellText->Text = PhGetStringRef(moduleItem->Name); break; case PHMOTLC_BASEADDRESS: + PhPrintPointer(moduleItem->BaseAddressString, moduleItem->BaseAddress); PhInitializeStringRefLongHint(&getCellText->Text, moduleItem->BaseAddressString); break; case PHMOTLC_SIZE: diff --git a/ProcessHacker/modprv.c b/ProcessHacker/modprv.c index ef6f5f4aee83..5ab4027a7e76 100644 --- a/ProcessHacker/modprv.c +++ b/ProcessHacker/modprv.c @@ -81,6 +81,7 @@ PPH_MODULE_PROVIDER PhCreateModuleProvider( { NTSTATUS status; PPH_MODULE_PROVIDER moduleProvider; + PPH_STRING fileName; moduleProvider = PhCreateObject( PhEmGetObjectSize(EmModuleProviderType, sizeof(PH_MODULE_PROVIDER)), @@ -125,6 +126,11 @@ PPH_MODULE_PROVIDER PhCreateModuleProvider( moduleProvider->RunStatus = status; } + if (NT_SUCCESS(PhGetProcessImageFileNameByProcessId(ProcessId, &fileName))) + { + PhMoveReference(&moduleProvider->ProcessFileName, PhGetFileName(fileName)); + } + if (WindowsVersion >= WINDOWS_8 && moduleProvider->ProcessHandle) { moduleProvider->PackageFullName = PhGetProcessPackageFullName(moduleProvider->ProcessHandle); @@ -148,16 +154,6 @@ PPH_MODULE_PROVIDER PhCreateModuleProvider( { moduleProvider->IsSubsystemProcess = !!basicInfo.IsSubsystemProcess; } - - if (moduleProvider->IsSubsystemProcess) - { - PPH_STRING fileName; - - if (NT_SUCCESS(PhGetProcessImageFileNameByProcessId(ProcessId, &fileName))) - { - PhMoveReference(&moduleProvider->FileName, PhGetFileName(fileName)); - } - } } RtlInitializeSListHead(&moduleProvider->QueryListHead); @@ -491,11 +487,10 @@ VOID PhModuleProviderUpdate( { FILE_NETWORK_OPEN_INFORMATION networkOpenInfo; - moduleItem = PhCreateModuleItem(); - PhReferenceObject(module->Name); PhReferenceObject(module->FileName); + moduleItem = PhCreateModuleItem(); moduleItem->BaseAddress = module->BaseAddress; moduleItem->EntryPoint = module->EntryPoint; moduleItem->Size = module->Size; @@ -508,30 +503,15 @@ VOID PhModuleProviderUpdate( moduleItem->FileName = module->FileName; moduleItem->ParentBaseAddress = module->ParentBaseAddress; - PhPrintPointer(moduleItem->BaseAddressString, moduleItem->BaseAddress); - PhInitializeImageVersionInfo(&moduleItem->VersionInfo, moduleItem->FileName->Buffer); if (moduleProvider->IsSubsystemProcess) { // HACK: Update the module type. (TODO: Move into PhEnumGenericModules) (dmex) moduleItem->Type = PH_MODULE_TYPE_ELF_MAPPED_IMAGE; - - if (!moduleProvider->HaveFirst) - { - if (PhEqualString(moduleItem->FileName, moduleProvider->FileName, TRUE)) - { - moduleItem->IsFirst = TRUE; - moduleProvider->HaveFirst = TRUE; - } - } } else { - // TODO: Linux process modules are loaded in order of the ELF symbol table dependancy graph - // with the primary executable/shared object as the last entry (dmex) - moduleItem->IsFirst = i == 0; - // Fix up the load count. If this is not an ordinary DLL or kernel module, set the load count to 0. if (moduleItem->Type != PH_MODULE_TYPE_MODULE && moduleItem->Type != PH_MODULE_TYPE_WOW64_MODULE && @@ -541,6 +521,16 @@ VOID PhModuleProviderUpdate( } } + if (!moduleProvider->HaveFirst) + { + // moduleItem->IsFirst = i == 0; + if (PhEqualString(moduleProvider->ProcessFileName, moduleItem->FileName, FALSE)) + { + moduleItem->IsFirst = TRUE; + moduleProvider->HaveFirst = TRUE; + } + } + if (moduleItem->Type == PH_MODULE_TYPE_MODULE || moduleItem->Type == PH_MODULE_TYPE_WOW64_MODULE || moduleItem->Type == PH_MODULE_TYPE_MAPPED_IMAGE || @@ -640,6 +630,12 @@ VOID PhModuleProviderUpdate( moduleItem->JustProcessed = FALSE; + if (moduleItem->LoadCount != module->LoadCount) + { + moduleItem->LoadCount = module->LoadCount; + modified = TRUE; + } + if (modified) PhInvokeCallback(&moduleProvider->ModuleModifiedEvent, moduleItem); diff --git a/ProcessHacker/options.c b/ProcessHacker/options.c index c48c67308d50..242c22c6346b 100644 --- a/ProcessHacker/options.c +++ b/ProcessHacker/options.c @@ -127,7 +127,6 @@ VOID PhpSetDefaultTaskManager( ); static HWND PhOptionsWindowHandle = NULL; -static PH_EVENT PhOptionsWindowInitializedEvent = PH_EVENT_INIT; static PH_LAYOUT_MANAGER WindowLayoutManager; static PPH_LIST SectionList = NULL; @@ -937,6 +936,7 @@ typedef enum _PHP_OPTIONS_INDEX PHP_OPTIONS_INDEX_ICON_SINGLE_CLICK, PHP_OPTIONS_INDEX_ICON_TOGGLE_VISIBILITY, PHP_OPTIONS_INDEX_PROPAGATE_CPU_USAGE, + PHP_OPTIONS_INDEX_SHOW_HEX_ID, PHP_OPTIONS_INDEX_SHOW_ADVANCED_OPTIONS } PHP_OPTIONS_GENERAL_INDEX; @@ -982,6 +982,7 @@ static VOID PhpAdvancedPageLoad( PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_ICON_SINGLE_CLICK, L"Single-click tray icons", NULL); PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_ICON_TOGGLE_VISIBILITY, L"Icon click toggles visibility", NULL); PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_PROPAGATE_CPU_USAGE, L"Include usage of collapsed processes", NULL); + PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_SHOW_HEX_ID, L"Show hexadecimal IDs", NULL); PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_SHOW_ADVANCED_OPTIONS, L"Show advanced options", NULL); SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_SINGLE_INSTANCE, L"AllowOnlyOneInstance"); @@ -1001,6 +1002,7 @@ static VOID PhpAdvancedPageLoad( SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_ICON_SINGLE_CLICK, L"IconSingleClick"); SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_ICON_TOGGLE_VISIBILITY, L"IconTogglesVisibility"); SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_PROPAGATE_CPU_USAGE, L"PropagateCpuUsage"); + SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_SHOW_HEX_ID, L"ShowHexId"); if (CurrentUserRunPresent) { @@ -1098,6 +1100,7 @@ static VOID PhpAdvancedPageSave( SetSettingForLvItemCheck(listViewHandle, PHP_OPTIONS_INDEX_ICON_SINGLE_CLICK, L"IconSingleClick"); SetSettingForLvItemCheck(listViewHandle, PHP_OPTIONS_INDEX_ICON_TOGGLE_VISIBILITY, L"IconTogglesVisibility"); SetSettingForLvItemCheck(listViewHandle, PHP_OPTIONS_INDEX_PROPAGATE_CPU_USAGE, L"PropagateCpuUsage"); + SetSettingForLvItemCheckRestartRequired(listViewHandle, PHP_OPTIONS_INDEX_SHOW_HEX_ID, L"ShowHexId"); WriteCurrentUserRun( ListView_GetCheckState(listViewHandle, PHP_OPTIONS_INDEX_START_ATLOGON) == BST_CHECKED, @@ -1150,7 +1153,7 @@ INT_PTR CALLBACK PhpOptionsGeneralDlgProc( comboBoxHandle = GetDlgItem(hwndDlg, IDC_MAXSIZEUNIT); listviewHandle = GetDlgItem(hwndDlg, IDC_SETTINGS); - GeneralListviewImageList = ImageList_Create(2, 16, ILC_COLOR, 1, 1); + GeneralListviewImageList = ImageList_Create(1, 22, ILC_COLOR, 1, 1); PhInitializeLayoutManager(&LayoutManager, hwndDlg); PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDC_SEARCHENGINE), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); diff --git a/ProcessHacker/procprp.c b/ProcessHacker/procprp.c index 116930f2e7bd..edfa4bc93c74 100644 --- a/ProcessHacker/procprp.c +++ b/ProcessHacker/procprp.c @@ -182,10 +182,6 @@ INT CALLBACK PhpPropSheetProc( PhSetWindowContext(hwndDlg, 0xF, propSheetContext); SetWindowLongPtr(hwndDlg, GWLP_WNDPROC, (LONG_PTR)PhpPropSheetWndProc); - // HACK HACK HACK - if (WindowsVersion >= WINDOWS_10_RS3 && !!PhGetIntegerSetting(L"EnableExperimentalWindowStyle")) - PhSetWindowStyle(hwndDlg, WS_POPUP, 0); - if (MinimumSize.left == -1) { RECT rect; diff --git a/ProcessHacker/procprv.c b/ProcessHacker/procprv.c index f54093a7a59e..93c79a8f7b6b 100644 --- a/ProcessHacker/procprv.c +++ b/ProcessHacker/procprv.c @@ -431,14 +431,6 @@ PPH_PROCESS_ITEM PhCreateProcessItem( processItem->ProcessId = ProcessId; - if (!PH_IS_FAKE_PROCESS_ID(ProcessId)) - { - if (PhCsShowHexId) - _ultow(HandleToUlong(ProcessId), processItem->ProcessIdString, 16); - else - PhPrintUInt32(processItem->ProcessIdString, HandleToUlong(ProcessId)); - } - // Create the statistics buffers. PhInitializeCircularBuffer_FLOAT(&processItem->CpuKernelHistory, PhStatisticsSampleCount); PhInitializeCircularBuffer_FLOAT(&processItem->CpuUserHistory, PhStatisticsSampleCount); @@ -1130,6 +1122,14 @@ VOID PhpFillProcessItem( else ProcessItem->ProcessName = PhCreateString(SYSTEM_IDLE_PROCESS_NAME); + if (PH_IS_REAL_PROCESS_ID(ProcessItem->ProcessId)) + { + if (PhEnableHexId) + PhPrintUInt32Hex(ProcessItem->ProcessIdString, HandleToUlong(ProcessItem->ProcessId)); + else + PhPrintUInt32(ProcessItem->ProcessIdString, HandleToUlong(ProcessItem->ProcessId)); + } + PhPrintUInt32(ProcessItem->ParentProcessIdString, HandleToUlong(ProcessItem->ParentProcessId)); PhPrintUInt32(ProcessItem->SessionIdString, ProcessItem->SessionId); diff --git a/ProcessHacker/settings.c b/ProcessHacker/settings.c index 9ff911ddc241..fc307817e36e 100644 --- a/ProcessHacker/settings.c +++ b/ProcessHacker/settings.c @@ -232,9 +232,6 @@ VOID PhAddDefaultSettings( PhpAddIntegerSetting(L"ColorIoWrite", L"ff0077"); PhpAddIntegerSetting(L"ColorPrivate", L"0077ff"); PhpAddIntegerSetting(L"ColorPhysical", L"ff8000"); // Blue - - // Experimental features - PhpAddIntegerSetting(L"EnableExperimentalWindowStyle", L"0"); } VOID PhUpdateCachedSettings( @@ -247,7 +244,6 @@ VOID PhUpdateCachedSettings( PH_UPDATE_SETTING(PropagateCpuUsage); PH_UPDATE_SETTING(ScrollToNewProcesses); PH_UPDATE_SETTING(ShowCpuBelow001); - PH_UPDATE_SETTING(ShowHexId); PH_UPDATE_SETTING(UpdateInterval); PH_UPDATE_SETTING(ColorNew); diff --git a/ProcessHacker/sysinfo.c b/ProcessHacker/sysinfo.c index e868cfd0174e..1085d5372d33 100644 --- a/ProcessHacker/sysinfo.c +++ b/ProcessHacker/sysinfo.c @@ -308,9 +308,6 @@ VOID PhSipOnInitDialog( PhSetControlTheme(PhSipWindow, L"explorer"); PhSipUpdateThemeData(); - // HACK HACK HACK - if (WindowsVersion >= WINDOWS_10_RS3 && !!PhGetIntegerSetting(L"EnableExperimentalWindowStyle")) - PhSetWindowStyle(PhSipWindow, WS_POPUP, 0); } VOID PhSipOnDestroy( diff --git a/ProcessHacker/thrdlist.c b/ProcessHacker/thrdlist.c index 7d3bcd1d128e..2ed55b84872c 100644 --- a/ProcessHacker/thrdlist.c +++ b/ProcessHacker/thrdlist.c @@ -513,7 +513,21 @@ BOOLEAN NTAPI PhpThreadTreeNewCallback( switch (getCellText->Id) { case PHTHTLC_TID: - PhInitializeStringRefLongHint(&getCellText->Text, threadItem->ThreadIdString); + { + PH_FORMAT format; + SIZE_T returnLength; + + if (PhEnableHexId) + PhInitFormatIX(&format, HandleToUlong(threadItem->ThreadId)); + else + PhInitFormatIU(&format, HandleToUlong(threadItem->ThreadId)); + + if (PhFormatToBuffer(&format, 1, node->ThreadIdText, sizeof(node->ThreadIdText), &returnLength)) + { + getCellText->Text.Buffer = node->ThreadIdText; + getCellText->Text.Length = returnLength - sizeof(WCHAR); // minus null terminator + } + } break; case PHTHTLC_CPU: { diff --git a/ProcessHacker/thrdprv.c b/ProcessHacker/thrdprv.c index d2114f83c154..7404f1137278 100644 --- a/ProcessHacker/thrdprv.c +++ b/ProcessHacker/thrdprv.c @@ -391,11 +391,6 @@ PPH_THREAD_ITEM PhCreateThreadItem( memset(threadItem, 0, sizeof(PH_THREAD_ITEM)); threadItem->ThreadId = ThreadId; - if (PhCsShowHexId) - _ultow(HandleToUlong(ThreadId), threadItem->ThreadIdString, 16); - else - PhPrintUInt32(threadItem->ThreadIdString, HandleToUlong(ThreadId)); - PhEmCallObjectOperation(EmThreadItemType, threadItem, EmObjectCreate); return threadItem; From f2f8c0a542959ecbd15ddb4b61ab9adda3843a35 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 1 Jul 2018 18:09:11 +1000 Subject: [PATCH 1076/2058] Remove PhProcessPropInitialization --- ProcessHacker/include/procprp.h | 4 ---- ProcessHacker/main.c | 2 -- ProcessHacker/procprp.c | 27 +++++++++++---------------- 3 files changed, 11 insertions(+), 22 deletions(-) diff --git a/ProcessHacker/include/procprp.h b/ProcessHacker/include/procprp.h index db5f5d7be97c..a61d01e36604 100644 --- a/ProcessHacker/include/procprp.h +++ b/ProcessHacker/include/procprp.h @@ -24,10 +24,6 @@ typedef struct _PH_PROCESS_PROPPAGECONTEXT } PH_PROCESS_PROPPAGECONTEXT, *PPH_PROCESS_PROPPAGECONTEXT; // end_phapppub -BOOLEAN PhProcessPropInitialization( - VOID - ); - // begin_phapppub PHAPPAPI PPH_PROCESS_PROPCONTEXT diff --git a/ProcessHacker/main.c b/ProcessHacker/main.c index 63190082d52f..0d5b01e01504 100644 --- a/ProcessHacker/main.c +++ b/ProcessHacker/main.c @@ -872,8 +872,6 @@ BOOLEAN PhInitializeAppSystem( return FALSE; if (!PhMemoryProviderInitialization()) return FALSE; - if (!PhProcessPropInitialization()) - return FALSE; PhSetHandleClientIdFunction(PhGetClientIdName); diff --git a/ProcessHacker/procprp.c b/ProcessHacker/procprp.c index edfa4bc93c74..308f772f9ad9 100644 --- a/ProcessHacker/procprp.c +++ b/ProcessHacker/procprp.c @@ -34,34 +34,29 @@ #include #include -PPH_OBJECT_TYPE PhpProcessPropContextType; -PPH_OBJECT_TYPE PhpProcessPropPageContextType; +PPH_OBJECT_TYPE PhpProcessPropContextType = NULL; +PPH_OBJECT_TYPE PhpProcessPropPageContextType = NULL; PH_STRINGREF PhpLoadingText = PH_STRINGREF_INIT(L"Loading..."); - static RECT MinimumSize = { -1, -1, -1, -1 }; -BOOLEAN PhProcessPropInitialization( - VOID - ) -{ - PhpProcessPropContextType = PhCreateObjectType(L"ProcessPropContext", 0, PhpProcessPropContextDeleteProcedure); - PhpProcessPropPageContextType = PhCreateObjectType(L"ProcessPropPageContext", 0, PhpProcessPropPageContextDeleteProcedure); - - return TRUE; -} - PPH_PROCESS_PROPCONTEXT PhCreateProcessPropContext( _In_ HWND ParentWindowHandle, _In_ PPH_PROCESS_ITEM ProcessItem ) { + static PH_INITONCE initOnce = PH_INITONCE_INIT; PPH_PROCESS_PROPCONTEXT propContext; PROPSHEETHEADER propSheetHeader; - propContext = PhCreateObject(sizeof(PH_PROCESS_PROPCONTEXT), PhpProcessPropContextType); - memset(propContext, 0, sizeof(PH_PROCESS_PROPCONTEXT)); + if (PhBeginInitOnce(&initOnce)) + { + PhpProcessPropContextType = PhCreateObjectType(L"ProcessPropContext", 0, PhpProcessPropContextDeleteProcedure); + PhpProcessPropPageContextType = PhCreateObjectType(L"ProcessPropPageContext", 0, PhpProcessPropPageContextDeleteProcedure); + PhEndInitOnce(&initOnce); + } - propContext->PropSheetPages = PhAllocate(sizeof(HPROPSHEETPAGE) * PH_PROCESS_PROPCONTEXT_MAXPAGES); + propContext = PhCreateObjectZero(sizeof(PH_PROCESS_PROPCONTEXT), PhpProcessPropContextType); + propContext->PropSheetPages = PhAllocateZero(sizeof(HPROPSHEETPAGE) * PH_PROCESS_PROPCONTEXT_MAXPAGES); if (!PH_IS_FAKE_PROCESS_ID(ProcessItem->ProcessId)) { From da65c8d3226d3214a19332af4dc7f87d658723a7 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 1 Jul 2018 18:15:00 +1000 Subject: [PATCH 1077/2058] Add PhPrintUInt32Hex --- ProcessHacker/include/mainwnd.h | 11 ----------- phlib/include/phsup.h | 8 ++++++++ 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/ProcessHacker/include/mainwnd.h b/ProcessHacker/include/mainwnd.h index 1ee352a36662..48808da1c56c 100644 --- a/ProcessHacker/include/mainwnd.h +++ b/ProcessHacker/include/mainwnd.h @@ -8,19 +8,8 @@ extern BOOLEAN PhMainWndExiting; #define WM_PH_ACTIVATE (WM_APP + 99) #define PH_ACTIVATE_REPLY 0x1119 -//#define WM_PH_PROCESS_ADDED_DEPRECATED (WM_APP + 101) -//#define WM_PH_PROCESS_MODIFIED_DEPRECATED (WM_APP + 102) -//#define WM_PH_PROCESS_REMOVED_DEPRECATED (WM_APP + 103) #define WM_PH_PROCESSES_UPDATED (WM_APP + 104) - -//#define WM_PH_SERVICE_ADDED_DEPRECATED (WM_APP + 105) -//#define WM_PH_SERVICE_MODIFIED_DEPRECATED (WM_APP + 106) -//#define WM_PH_SERVICE_REMOVED_DEPRECATED (WM_APP + 107) #define WM_PH_SERVICES_UPDATED (WM_APP + 108) - -//#define WM_PH_NETWORK_ITEM_ADDED_DEPRECATED (WM_APP + 109) -//#define WM_PH_NETWORK_ITEM_MODIFIED_DEPRECATED (WM_APP + 110) -//#define WM_PH_NETWORK_ITEM_REMOVED_DEPRECATED (WM_APP + 111) #define WM_PH_NETWORK_ITEMS_UPDATED (WM_APP + 112) // begin_phapppub diff --git a/phlib/include/phsup.h b/phlib/include/phsup.h index 006955251e85..a6c7f11a3e9a 100644 --- a/phlib/include/phsup.h +++ b/phlib/include/phsup.h @@ -411,6 +411,14 @@ FORCEINLINE VOID PhPrintUInt32( _ultow(UInt32, Destination, 10); } +FORCEINLINE VOID PhPrintUInt32Hex( + _Out_writes_(PH_PTR_STR_LEN_1) PWSTR Destination, + _In_ ULONG UInt32 + ) +{ + _ultow(UInt32, Destination, 16); +} + FORCEINLINE VOID PhPrintInt64( _Out_writes_(PH_INT64_STR_LEN_1) PWSTR Destination, _In_ LONG64 Int64 From a2cca0ac3de7cc7a1498f96067cbd7896c6f925c Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 1 Jul 2018 23:18:28 +1000 Subject: [PATCH 1078/2058] Update cache directory path --- ProcessHacker/ProcessHacker.def | 1 - phlib/include/phutil.h | 14 ---------- phlib/util.c | 46 ++++++++++----------------------- plugins/Updater/updater.c | 3 --- 4 files changed, 14 insertions(+), 50 deletions(-) diff --git a/ProcessHacker/ProcessHacker.def b/ProcessHacker/ProcessHacker.def index 27775611f293..3130af7d0e14 100644 --- a/ProcessHacker/ProcessHacker.def +++ b/ProcessHacker/ProcessHacker.def @@ -657,6 +657,5 @@ EXPORTS PhGetJsonArrayIndexObject ; cache - PhClearCacheDirectory PhCreateCacheFile PhDeleteCacheFile diff --git a/phlib/include/phutil.h b/phlib/include/phutil.h index b453303e5800..9f68dda988fa 100644 --- a/phlib/include/phutil.h +++ b/phlib/include/phutil.h @@ -1092,20 +1092,6 @@ PhSearchFilePath( _Out_ PPH_STRING *FilePath ); -PHLIBAPI -PPH_STRING -NTAPI -PhGetCacheDirectory( - VOID - ); - -PHLIBAPI -VOID -NTAPI -PhClearCacheDirectory( - VOID - ); - PHLIBAPI PPH_STRING NTAPI diff --git a/phlib/util.c b/phlib/util.c index d53f15b28c70..997d9765fb01 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -2113,7 +2113,7 @@ PPH_STRING PhGetKnownLocation( else appendPathLength = 0; - path = PhCreateStringEx(NULL, MAX_PATH * 2 + appendPathLength); + path = PhCreateStringEx(NULL, MAX_PATH * sizeof(WCHAR) + appendPathLength); if (SUCCEEDED(SHGetFolderPath( NULL, @@ -2127,7 +2127,7 @@ PPH_STRING PhGetKnownLocation( if (AppendPath) { - memcpy(&path->Buffer[path->Length / sizeof(WCHAR)], AppendPath, appendPathLength + 2); // +2 for null terminator + memcpy(&path->Buffer[path->Length / sizeof(WCHAR)], AppendPath, appendPathLength + sizeof(WCHAR)); // +2 for null terminator path->Length += appendPathLength; } @@ -3311,8 +3311,8 @@ VOID PhShellOpenKey( _In_ PPH_STRING KeyName ) { - static PH_STRINGREF regeditKeyName = PH_STRINGREF_INIT(L"Software\\Microsoft\\Windows\\CurrentVersion\\Applets\\Regedit"); - + static PH_STRINGREF regeditKeyNameSr = PH_STRINGREF_INIT(L"Software\\Microsoft\\Windows\\CurrentVersion\\Applets\\Regedit"); + static PH_STRINGREF regeditFileNameSr = PH_STRINGREF_INIT(L"%SystemRoot%\\regedit.exe"); PPH_STRING lastKey; HANDLE regeditKeyHandle; UNICODE_STRING valueName; @@ -3322,7 +3322,7 @@ VOID PhShellOpenKey( ®editKeyHandle, KEY_WRITE, PH_KEY_CURRENT_USER, - ®editKeyName, + ®editKeyNameSr, 0, 0, NULL @@ -3334,23 +3334,23 @@ VOID PhShellOpenKey( NtSetValueKey(regeditKeyHandle, &valueName, 0, REG_SZ, lastKey->Buffer, (ULONG)lastKey->Length + 2); PhDereferenceObject(lastKey); - NtClose(regeditKeyHandle); + NtClose(regeditKeyHandle); // Start regedit. If we aren't elevated, request that regedit be elevated. This is so we can get // the consent dialog in the center of the specified window. - regeditFileName = PhGetKnownLocation(CSIDL_WINDOWS, L"\\regedit.exe"); + regeditFileName = PhExpandEnvironmentStrings(®editFileNameSr); - if (!regeditFileName) - regeditFileName = PhCreateString(L"regedit.exe"); + if (PhIsNullOrEmptyString(regeditFileName)) + PhMoveReference(®editFileName, PhCreateString(L"regedit.exe")); - if (!PhGetOwnTokenAttributes().Elevated) + if (PhGetOwnTokenAttributes().Elevated) { - PhShellExecuteEx(hWnd, regeditFileName->Buffer, L"", SW_NORMAL, PH_SHELL_EXECUTE_ADMIN, 0, NULL); + PhShellExecute(hWnd, regeditFileName->Buffer, L""); } else { - PhShellExecute(hWnd, regeditFileName->Buffer, L""); + PhShellExecuteEx(hWnd, regeditFileName->Buffer, L"", SW_NORMAL, PH_SHELL_EXECUTE_ADMIN, 0, NULL); } PhDereferenceObject(regeditFileName); @@ -4961,36 +4961,18 @@ BOOLEAN PhSearchFilePath( return TRUE; } -PPH_STRING PhGetCacheDirectory( - VOID - ) -{ - return PhGetKnownLocation(CSIDL_LOCAL_APPDATA, L"\\Process Hacker\\Cache"); -} - -VOID PhClearCacheDirectory( - VOID - ) -{ - PPH_STRING cacheDirectory; - - cacheDirectory = PhGetCacheDirectory(); - PhDeleteDirectory(cacheDirectory); - - PhDereferenceObject(cacheDirectory); -} - PPH_STRING PhCreateCacheFile( _In_ PPH_STRING FileName ) { + static PH_STRINGREF cacheDirectorySr = PH_STRINGREF_INIT(L"%TEMP%"); PPH_STRING cacheDirectory; PPH_STRING cacheFilePath; PPH_STRING cacheFullFilePath = NULL; ULONG indexOfFileName = -1; WCHAR alphastring[16] = L""; - cacheDirectory = PhGetCacheDirectory(); + cacheDirectory = PhExpandEnvironmentStrings(&cacheDirectorySr); PhGenerateRandomAlphaString(alphastring, ARRAYSIZE(alphastring)); cacheFilePath = PhConcatStrings( diff --git a/plugins/Updater/updater.c b/plugins/Updater/updater.c index ed3c6d665336..4ba653d17db1 100644 --- a/plugins/Updater/updater.c +++ b/plugins/Updater/updater.c @@ -380,9 +380,6 @@ NTSTATUS UpdateCheckSilentThread( PhDelayExecution(5 * 1000); - // Clear the application cache directory. - PhClearCacheDirectory(); - // Query latest update information from the server. if (!QueryUpdateData(context)) goto CleanupExit; From aac68881e2a22bf0b261fbcd36f042a6e0cab8aa Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 1 Jul 2018 23:38:17 +1000 Subject: [PATCH 1079/2058] Update to latest phlib --- ProcessHacker/actions.c | 10 ++- ProcessHacker/appsup.c | 22 ++++-- ProcessHacker/chproc.c | 4 +- ProcessHacker/include/phapp.h | 4 -- ProcessHacker/include/phsvc.h | 3 +- ProcessHacker/main.c | 127 ++++++++++++++++----------------- ProcessHacker/mainwnd.c | 11 +-- ProcessHacker/options.c | 87 +++++++++++++++------- ProcessHacker/phsvc/svcmain.c | 22 +++--- ProcessHacker/plugin.c | 24 +++++-- ProcessHacker/procprv.c | 2 +- ProcessHacker/runas.c | 20 +++--- ProcessHacker/sessmsg.c | 8 ++- phlib/global.c | 7 +- phlib/include/phbasesup.h | 2 +- phlib/include/phconfig.h | 1 + phlib/lsasup.c | 2 +- phlib/symprv.c | 46 +++++++----- plugins/NetworkTools/country.c | 5 +- plugins/NetworkTools/update.c | 6 +- tools/peview/main.c | 4 +- tools/peview/pdb.c | 39 +++++----- tools/peview/peprp.c | 6 +- tools/peview/settings.c | 3 +- 24 files changed, 275 insertions(+), 190 deletions(-) diff --git a/ProcessHacker/actions.c b/ProcessHacker/actions.c index 952563823410..5957ee2fe966 100644 --- a/ProcessHacker/actions.c +++ b/ProcessHacker/actions.c @@ -354,12 +354,16 @@ BOOLEAN PhpStartPhSvcProcess( }; ULONG i; + PPH_STRING applicationDirectory; - for (i = 0; i < sizeof(relativeFileNames) / sizeof(PWSTR); i++) + if (!(applicationDirectory = PhGetApplicationDirectory())) + return FALSE; + + for (i = 0; i < RTL_NUMBER_OF(relativeFileNames); i++) { PPH_STRING fileName; - fileName = PhConcatStrings2(PhApplicationDirectory->Buffer, relativeFileNames[i]); + fileName = PhConcatStrings2(applicationDirectory->Buffer, relativeFileNames[i]); PhMoveReference(&fileName, PhGetFullPath(fileName->Buffer, NULL)); if (fileName && RtlDoesFileExists_U(fileName->Buffer)) @@ -376,11 +380,13 @@ BOOLEAN PhpStartPhSvcProcess( )) { PhDereferenceObject(fileName); + PhDereferenceObject(applicationDirectory); return TRUE; } } PhClearReference(&fileName); + PhClearReference(&applicationDirectory); } } break; diff --git a/ProcessHacker/appsup.c b/ProcessHacker/appsup.c index 76b10a140135..a7b53d38a365 100644 --- a/ProcessHacker/appsup.c +++ b/ProcessHacker/appsup.c @@ -738,12 +738,19 @@ VOID PhShellExecuteUserString( ) { static PH_STRINGREF replacementToken = PH_STRINGREF_INIT(L"%s"); - + PPH_STRING applicationDirectory; PPH_STRING executeString; PH_STRINGREF stringBefore; PH_STRINGREF stringAfter; PPH_STRING ntMessage; + if (!(applicationDirectory = PhGetApplicationDirectory())) + { + PhShowStatus(hWnd, L"Unable to locate the application directory.", STATUS_NOT_FOUND, 0); + return; + } + + // Get the execute command. executeString = PhGetStringSetting(Setting); // Expand environment strings. @@ -764,7 +771,7 @@ VOID PhShellExecuteUserString( // Make sure the string is absolute and escape the filename. if (RtlDetermineDosPathNameType_U(fileName->Buffer) == RtlPathTypeRelative) - PhMoveReference(&fileName, PhConcatStrings(4, L"\"", PhApplicationDirectory->Buffer, fileName->Buffer, L"\"")); + PhMoveReference(&fileName, PhConcatStrings(4, L"\"", applicationDirectory->Buffer, fileName->Buffer, L"\"")); else PhMoveReference(&fileName, PhConcatStrings(3, L"\"", fileName->Buffer, L"\"")); @@ -781,7 +788,7 @@ VOID PhShellExecuteUserString( else { if (RtlDetermineDosPathNameType_U(executeString->Buffer) == RtlPathTypeRelative) - PhMoveReference(&executeString, PhConcatStrings(4, L"\"", PhApplicationDirectory->Buffer, executeString->Buffer, L"\"")); + PhMoveReference(&executeString, PhConcatStrings(4, L"\"", applicationDirectory->Buffer, executeString->Buffer, L"\"")); else PhMoveReference(&executeString, PhConcatStrings(3, L"\"", executeString->Buffer, L"\"")); } @@ -832,6 +839,7 @@ VOID PhShellExecuteUserString( } PhDereferenceObject(executeString); + PhDereferenceObject(applicationDirectory); } VOID PhLoadSymbolProviderOptions( @@ -1134,9 +1142,13 @@ BOOLEAN PhShellProcessHackerEx( ) { BOOLEAN result; + PPH_STRING applicationFileName; PH_STRING_BUILDER sb; PWSTR parameters; + if (!(applicationFileName = PhGetApplicationFileName())) + return FALSE; + if (AppFlags & PH_SHELL_APP_PROPAGATE_PARAMETERS) { PhInitializeStringBuilder(&sb, 128); @@ -1243,7 +1255,7 @@ BOOLEAN PhShellProcessHackerEx( result = PhShellExecuteEx( hWnd, - FileName ? FileName : PhApplicationFileName->Buffer, + FileName ? FileName : PhGetString(applicationFileName), parameters, ShowWindowType, Flags, @@ -1254,6 +1266,8 @@ BOOLEAN PhShellProcessHackerEx( if (AppFlags & PH_SHELL_APP_PROPAGATE_PARAMETERS) PhDeleteStringBuilder(&sb); + PhDereferenceObject(applicationFileName); + return result; } diff --git a/ProcessHacker/chproc.c b/ProcessHacker/chproc.c index a4e5692eed3e..cd50853564ca 100644 --- a/ProcessHacker/chproc.c +++ b/ProcessHacker/chproc.c @@ -130,8 +130,8 @@ static VOID PhpRefreshProcessList( NtClose(processHandle); } - if (process->UniqueProcessId == SYSTEM_IDLE_PROCESS_ID && !userName && PhLocalSystemName) - PhSetReference(&userName, PhLocalSystemName); + if (process->UniqueProcessId == SYSTEM_IDLE_PROCESS_ID && !userName) + PhSetReference(&userName, PhCreateString(L"NT AUTHORITY\\SYSTEM")); if (process->UniqueProcessId == SYSTEM_PROCESS_ID) fileName = PhGetKernelFileName(); diff --git a/ProcessHacker/include/phapp.h b/ProcessHacker/include/phapp.h index cb032cf90e01..2d4da158b7db 100644 --- a/ProcessHacker/include/phapp.h +++ b/ProcessHacker/include/phapp.h @@ -72,11 +72,7 @@ typedef struct _PH_STARTUP_PARAMETERS PPH_STRING SysInfo; } PH_STARTUP_PARAMETERS, *PPH_STARTUP_PARAMETERS; -extern PPH_STRING PhApplicationDirectory; -extern PPH_STRING PhApplicationFileName; PHAPPAPI extern HFONT PhApplicationFont; // phapppub -extern PPH_STRING PhCurrentUserName; -extern PPH_STRING PhLocalSystemName; extern BOOLEAN PhPluginsEnabled; extern PPH_STRING PhSettingsFileName; extern PH_INTEGER_PAIR PhSmallIconSize; diff --git a/ProcessHacker/include/phsvc.h b/ProcessHacker/include/phsvc.h index b35b87017bb1..0912248784b5 100644 --- a/ProcessHacker/include/phsvc.h +++ b/ProcessHacker/include/phsvc.h @@ -15,8 +15,7 @@ typedef struct _PHSVC_STOP } PHSVC_STOP, *PPHSVC_STOP; NTSTATUS PhSvcMain( - _In_opt_ PUNICODE_STRING PortName, - _In_opt_ PLARGE_INTEGER Timeout, + _In_opt_ PPH_STRING PortName, _Inout_opt_ PPHSVC_STOP Stop ); diff --git a/ProcessHacker/main.c b/ProcessHacker/main.c index 0d5b01e01504..b8f4d846e430 100644 --- a/ProcessHacker/main.c +++ b/ProcessHacker/main.c @@ -84,11 +84,8 @@ BOOLEAN PhInitializeMitigationPolicy( VOID ); -PPH_STRING PhApplicationDirectory = NULL; -PPH_STRING PhApplicationFileName = NULL; PHAPPAPI HFONT PhApplicationFont = NULL; PPH_STRING PhCurrentUserName = NULL; -PPH_STRING PhLocalSystemName = NULL; BOOLEAN PhPluginsEnabled = FALSE; PPH_STRING PhSettingsFileName = NULL; PH_INTEGER_PAIR PhSmallIconSize = { 16, 16 }; @@ -116,7 +113,7 @@ INT WINAPI wWinMain( CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE); - if (!NT_SUCCESS(PhInitializePhLibEx(ULONG_MAX, Instance, 0, 0))) + if (!NT_SUCCESS(PhInitializePhLibEx(L"Process Hacker", ULONG_MAX, Instance, 0, 0))) return 1; if (!PhInitializeExceptionPolicy()) return 1; @@ -124,22 +121,8 @@ INT WINAPI wWinMain( return 1; if (!PhInitializeRestartPolicy()) return 1; - if (!PhInitializeAppSystem()) - return 1; - - PhInitializeCommonControls(); - - if (!(PhApplicationFileName = PhGetApplicationFileName())) - PhApplicationFileName = PhCreateString(L"ProcessHacker.exe"); - if (!(PhApplicationDirectory = PhGetApplicationDirectory())) - PhApplicationDirectory = PhReferenceEmptyString(); - if (!(PhLocalSystemName = PhGetSidFullName(&PhSeLocalSystemSid, TRUE, NULL))) - PhLocalSystemName = PhCreateString(L"NT AUTHORITY\\SYSTEM"); - if (!(PhCurrentUserName = PhGetTokenUserString(PhGetOwnTokenAttributes().TokenHandle, TRUE))) - PhCurrentUserName = PhReferenceEmptyString(); PhpProcessStartupParameters(); - PhSettingsInitialization(); PhpEnablePrivileges(); if (PhStartupParameters.RunAsServiceMode) @@ -147,9 +130,16 @@ INT WINAPI wWinMain( RtlExitUserProcess(PhRunAsServiceStart(PhStartupParameters.RunAsServiceMode)); } + if (PhStartupParameters.CommandMode && + PhStartupParameters.CommandType && + PhStartupParameters.CommandAction) + { + RtlExitUserProcess(PhCommandModeStart()); + } + + PhSettingsInitialization(); PhpInitializeSettings(); - // Activate a previous instance if required. if (PhGetIntegerSetting(L"AllowOnlyOneInstance") && !PhStartupParameters.NewInstance && !PhStartupParameters.ShowOptions && @@ -159,21 +149,13 @@ INT WINAPI wWinMain( PhActivatePreviousInstance(); } - if (PhGetIntegerSetting(L"EnableKph") && !PhStartupParameters.NoKph && !PhStartupParameters.CommandMode && !PhIsExecutingInWow64()) - PhInitializeKph(); - - if (PhStartupParameters.CommandMode && PhStartupParameters.CommandType && PhStartupParameters.CommandAction) + if (PhGetIntegerSetting(L"EnableKph") && + !PhStartupParameters.NoKph && + !PhStartupParameters.CommandMode && + !PhIsExecutingInWow64() + ) { - NTSTATUS status; - - status = PhCommandModeStart(); - - if (!NT_SUCCESS(status) && !PhStartupParameters.Silent) - { - PhShowStatus(NULL, L"Unable to execute the command.", status, 0); - } - - RtlExitUserProcess(status); + PhInitializeKph(); } #ifdef DEBUG @@ -186,6 +168,9 @@ INT WINAPI wWinMain( PhInitializeAutoPool(&BaseAutoPool); + PhInitializeAppSystem(); + PhInitializeCommonControls(); + PhEmInitialization(); PhGuiSupportInitialization(); PhTreeNewInitialization(); @@ -205,22 +190,7 @@ INT WINAPI wWinMain( RtlExitUserProcess(STATUS_SUCCESS); } -#ifndef DEBUG - if (PhIsExecutingInWow64() && !PhStartupParameters.PhSvc) - { - PhShowWarning( - NULL, - L"You are attempting to run the 32-bit version of Process Hacker on 64-bit Windows. " - L"Most features will not work correctly.\n\n" - L"Please run the 64-bit version of Process Hacker instead." - ); - RtlExitUserProcess(STATUS_IMAGE_SUBSYSTEM_NOT_PRESENT); - } -#endif - - PhPluginsEnabled = PhGetIntegerSetting(L"EnablePlugins") && !PhStartupParameters.NoPlugins; - - if (PhPluginsEnabled) + if (PhPluginsEnabled = PhGetIntegerSetting(L"EnablePlugins") && !PhStartupParameters.NoPlugins) { PhPluginsInitialization(); PhLoadPlugins(); @@ -249,9 +219,22 @@ INT WINAPI wWinMain( PostMessage(NULL, WM_NULL, 0, 0); GetMessage(&message, NULL, 0, 0); - RtlExitUserProcess(PhSvcMain(NULL, NULL, NULL)); + RtlExitUserProcess(PhSvcMain(NULL, NULL)); } +#ifndef DEBUG + if (PhIsExecutingInWow64()) + { + PhShowWarning( + NULL, + L"You are attempting to run the 32-bit version of Process Hacker on 64-bit Windows. " + L"Most features will not work correctly.\n\n" + L"Please run the 64-bit version of Process Hacker instead." + ); + RtlExitUserProcess(STATUS_IMAGE_SUBSYSTEM_NOT_PRESENT); + } +#endif + // Create a mutant for the installer. { HANDLE mutantHandle; @@ -789,15 +772,18 @@ VOID PhInitializeKph( VOID ) { - static PH_STRINGREF kprocesshacker = PH_STRINGREF_INIT(L"kprocesshacker.sys"); - static PH_STRINGREF processhackerSig = PH_STRINGREF_INIT(L"ProcessHacker.sig"); NTSTATUS status; + PPH_STRING applicationDirectory; PPH_STRING kprocesshackerFileName; PPH_STRING processhackerSigFileName; KPH_PARAMETERS parameters; - kprocesshackerFileName = PhConcatStringRef2(&PhApplicationDirectory->sr, &kprocesshacker); - processhackerSigFileName = PhConcatStringRef2(&PhApplicationDirectory->sr, &processhackerSig); + if (!(applicationDirectory = PhGetApplicationDirectory())) + return; + + kprocesshackerFileName = PhConcatStringRefZ(&applicationDirectory->sr, L"kprocesshacker.sys"); + processhackerSigFileName = PhConcatStringRefZ(&applicationDirectory->sr, L"ProcessHacker.sig"); + PhDereferenceObject(applicationDirectory); if (!RtlDoesFileExists_U(kprocesshackerFileName->Buffer)) { @@ -856,8 +842,6 @@ BOOLEAN PhInitializeAppSystem( VOID ) { - PhApplicationName = L"Process Hacker"; - if (!PhProcessProviderInitialization()) return FALSE; if (!PhServiceProviderInitialization()) @@ -886,6 +870,7 @@ VOID PhpInitializeSettings( if (!PhStartupParameters.NoSettings) { + static PH_STRINGREF settingsPath = PH_STRINGREF_INIT(L"%APPDATA%\\Process Hacker\\settings.xml"); static PH_STRINGREF settingsSuffix = PH_STRINGREF_INIT(L".settings.xml"); PPH_STRING settingsFileName; @@ -905,22 +890,29 @@ VOID PhpInitializeSettings( // 2. File in program directory if (!PhSettingsFileName) { - settingsFileName = PhConcatStringRef2(&PhApplicationFileName->sr, &settingsSuffix); + PPH_STRING applicationFileName; - if (RtlDoesFileExists_U(settingsFileName->Buffer)) - { - PhSettingsFileName = settingsFileName; - } - else + if (applicationFileName = PhGetApplicationFileName()) { - PhDereferenceObject(settingsFileName); + settingsFileName = PhConcatStringRef2(&applicationFileName->sr, &settingsSuffix); + + if (RtlDoesFileExists_U(settingsFileName->Buffer)) + { + PhSettingsFileName = settingsFileName; + } + else + { + PhDereferenceObject(settingsFileName); + } + + PhDereferenceObject(applicationFileName); } } // 3. Default location if (!PhSettingsFileName) { - PhSettingsFileName = PhGetKnownLocation(CSIDL_APPDATA, L"\\Process Hacker\\settings.xml"); + PhSettingsFileName = PhExpandEnvironmentStrings(&settingsPath); } if (PhSettingsFileName) @@ -1245,10 +1237,15 @@ VOID PhpProcessStartupParameters( if (PhStartupParameters.InstallKph) { NTSTATUS status; + PPH_STRING applicationDirectory; PPH_STRING kprocesshackerFileName; KPH_PARAMETERS parameters; - kprocesshackerFileName = PhConcatStrings2(PhApplicationDirectory->Buffer, L"\\kprocesshacker.sys"); + if (!(applicationDirectory = PhGetApplicationDirectory())) + return; + + kprocesshackerFileName = PhConcatStringRefZ(&applicationDirectory->sr, L"\\kprocesshacker.sys"); + PhDereferenceObject(applicationDirectory); parameters.SecurityLevel = KphSecuritySignatureCheck; parameters.CreateDynamicConfiguration = TRUE; diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index 9ba16b465d5f..2c5cd6282fe9 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -122,14 +123,17 @@ BOOLEAN PhMainWndInitialization( if (PhGetIntegerSetting(L"EnableWindowText")) { + PPH_STRING currentUserName; + PhAppendStringBuilder2(&stringBuilder, L"Process Hacker"); - if (PhCurrentUserName) + if (currentUserName = PhGetTokenUserString(PhGetOwnTokenAttributes().TokenHandle, TRUE)) { PhAppendStringBuilder2(&stringBuilder, L" ["); - PhAppendStringBuilder(&stringBuilder, &PhCurrentUserName->sr); + PhAppendStringBuilder(&stringBuilder, ¤tUserName->sr); PhAppendCharStringBuilder(&stringBuilder, ']'); if (KphIsConnected()) PhAppendCharStringBuilder(&stringBuilder, '+'); + PhDereferenceObject(currentUserName); } if (PhGetOwnTokenAttributes().ElevationType == TokenElevationTypeFull) @@ -2984,8 +2988,7 @@ VOID PhMwpAddIconProcesses( if ( processItem->CpuUsage == 0 || - !processItem->UserName || - (PhCurrentUserName && !PhEqualString(processItem->UserName, PhCurrentUserName, TRUE)) + processItem->SessionId != NtCurrentPeb()->SessionId ) { PhRemoveItemList(processList, i); diff --git a/ProcessHacker/options.c b/ProcessHacker/options.c index 242c22c6346b..fc972bde1bc7 100644 --- a/ProcessHacker/options.c +++ b/ProcessHacker/options.c @@ -716,6 +716,7 @@ static VOID ReadCurrentUserRun( PH_STRINGREF fileName; PH_STRINGREF arguments; PPH_STRING fullFileName; + PPH_STRING applicationFileName; PH_AUTO(value); @@ -723,10 +724,15 @@ static VOID ReadCurrentUserRun( { PH_AUTO(fullFileName); - if (fullFileName && PhEqualString(fullFileName, PhApplicationFileName, TRUE)) + if (applicationFileName = PhGetApplicationFileName()) { - CurrentUserRunPresent = TRUE; - CurrentUserRunStartHidden = PhEqualStringRef2(&arguments, L"-hide", FALSE); + if (fullFileName && PhEqualString(fullFileName, applicationFileName, TRUE)) + { + CurrentUserRunPresent = TRUE; + CurrentUserRunStartHidden = PhEqualStringRef2(&arguments, L"-hide", FALSE); + } + + PhDereferenceObject(applicationFileName); } } } @@ -760,13 +766,26 @@ static VOID WriteCurrentUserRun( if (Present) { PPH_STRING value; + PPH_STRING fileName; + + if (fileName = PhGetApplicationFileName()) + { + value = PH_AUTO(PhConcatStrings(3, L"\"", PhGetStringOrEmpty(fileName), L"\"")); - value = PH_AUTO(PhConcatStrings(3, L"\"", PhApplicationFileName->Buffer, L"\"")); + if (StartHidden) + value = PhaConcatStrings2(value->Buffer, L" -hide"); - if (StartHidden) - value = PhaConcatStrings2(value->Buffer, L" -hide"); + NtSetValueKey( + keyHandle, + &valueName, + 0, + REG_SZ, + value->Buffer, + (ULONG)value->Length + sizeof(WCHAR) + ); - NtSetValueKey(keyHandle, &valueName, 0, REG_SZ, value->Buffer, (ULONG)value->Length + 2); + PhDereferenceObject(fileName); + } } else { @@ -782,25 +801,31 @@ static BOOLEAN PathMatchesPh( ) { BOOLEAN match = FALSE; + PPH_STRING fileName; - if (PhEqualString(OldTaskMgrDebugger, PhApplicationFileName, TRUE)) - { - match = TRUE; - } - // Allow for a quoted value. - else if ( - OldTaskMgrDebugger->Length == PhApplicationFileName->Length + sizeof(WCHAR) * sizeof(WCHAR) && - OldTaskMgrDebugger->Buffer[0] == '"' && - OldTaskMgrDebugger->Buffer[OldTaskMgrDebugger->Length / sizeof(WCHAR) - 1] == '"' - ) + if (fileName = PhGetApplicationFileName()) { - PH_STRINGREF partInside; + if (PhEqualString(OldTaskMgrDebugger, fileName, TRUE)) + { + match = TRUE; + } + // Allow for a quoted value. + else if ( + OldTaskMgrDebugger->Length == fileName->Length + sizeof(WCHAR) * sizeof(WCHAR) && + OldTaskMgrDebugger->Buffer[0] == '"' && + OldTaskMgrDebugger->Buffer[OldTaskMgrDebugger->Length / sizeof(WCHAR) - 1] == '"' + ) + { + PH_STRINGREF partInside; - partInside.Buffer = &OldTaskMgrDebugger->Buffer[1]; - partInside.Length = OldTaskMgrDebugger->Length - sizeof(WCHAR) * sizeof(WCHAR); + partInside.Buffer = &OldTaskMgrDebugger->Buffer[1]; + partInside.Length = OldTaskMgrDebugger->Length - sizeof(WCHAR) * sizeof(WCHAR); - if (PhEqualStringRef(&partInside, &PhApplicationFileName->sr, TRUE)) - match = TRUE; + if (PhEqualStringRef(&partInside, &fileName->sr, TRUE)) + match = TRUE; + } + + PhDereferenceObject(fileName); } return match; @@ -878,9 +903,23 @@ VOID PhpSetDefaultTaskManager( else { PPH_STRING quotedFileName; + PPH_STRING applicationFileName; - quotedFileName = PH_AUTO(PhConcatStrings(3, L"\"", PhApplicationFileName->Buffer, L"\"")); - status = NtSetValueKey(taskmgrKeyHandle, &valueName, 0, REG_SZ, quotedFileName->Buffer, (ULONG)quotedFileName->Length + 2); + if (applicationFileName = PhGetApplicationFileName()) + { + quotedFileName = PH_AUTO(PhConcatStrings(3, L"\"", PhGetStringOrEmpty(applicationFileName), L"\"")); + + status = NtSetValueKey( + taskmgrKeyHandle, + &valueName, + 0, + REG_SZ, + quotedFileName->Buffer, + (ULONG)quotedFileName->Length + sizeof(WCHAR) + ); + + PhDereferenceObject(applicationFileName); + } } NtClose(taskmgrKeyHandle); diff --git a/ProcessHacker/phsvc/svcmain.c b/ProcessHacker/phsvc/svcmain.c index ad2482787e4e..206b96b48918 100644 --- a/ProcessHacker/phsvc/svcmain.c +++ b/ProcessHacker/phsvc/svcmain.c @@ -3,6 +3,7 @@ * server * * Copyright (C) 2011 wj32 + * Copyright (C) 2018 dmex * * This file is part of Process Hacker. * @@ -27,8 +28,7 @@ HANDLE PhSvcTimeoutStandbyEventHandle; HANDLE PhSvcTimeoutCancelEventHandle; NTSTATUS PhSvcMain( - _In_opt_ PUNICODE_STRING PortName, - _In_opt_ PLARGE_INTEGER Timeout, + _In_opt_ PPH_STRING PortName, _Inout_opt_ PPHSVC_STOP Stop ) { @@ -36,27 +36,23 @@ NTSTATUS PhSvcMain( UNICODE_STRING portName; LARGE_INTEGER timeout; - if (!PortName) + if (PortName) + { + PhStringRefToUnicodeString(&PortName->sr, &portName); + } + else { if (PhIsExecutingInWow64()) RtlInitUnicodeString(&portName, PHSVC_WOW64_PORT_NAME); else RtlInitUnicodeString(&portName, PHSVC_PORT_NAME); - - PortName = &portName; - } - - if (!Timeout) - { - timeout.QuadPart = -(LONGLONG)UInt32x32To64(15, PH_TIMEOUT_SEC); - Timeout = &timeout; } if (!NT_SUCCESS(status = PhSvcClientInitialization())) return status; if (!NT_SUCCESS(status = PhSvcApiInitialization())) return status; - if (!NT_SUCCESS(status = PhSvcApiPortInitialization(PortName))) + if (!NT_SUCCESS(status = PhSvcApiPortInitialization(&portName))) return status; if (!NT_SUCCESS(status = NtCreateEvent(&PhSvcTimeoutStandbyEventHandle, EVENT_ALL_ACCESS, NULL, SynchronizationEvent, TRUE))) @@ -85,7 +81,7 @@ NTSTATUS PhSvcMain( if (Stop && Stop->Stop) break; - status = NtWaitForSingleObject(PhSvcTimeoutCancelEventHandle, FALSE, Timeout); + status = NtWaitForSingleObject(PhSvcTimeoutCancelEventHandle, FALSE, PhTimeoutFromMilliseconds(&timeout, 10 * 1000)); if (Stop && Stop->Stop) break; diff --git a/ProcessHacker/plugin.c b/ProcessHacker/plugin.c index 1be39dd73197..637ee19cfb88 100644 --- a/ProcessHacker/plugin.c +++ b/ProcessHacker/plugin.c @@ -250,18 +250,30 @@ VOID PhLoadPlugins( if (RtlDetermineDosPathNameType_U(pluginsDirectory->Buffer) == RtlPathTypeRelative) { - // Not absolute. Make sure it is. - PluginsDirectory = PhConcatStrings(4, PhApplicationDirectory->Buffer, L"\\", pluginsDirectory->Buffer, L"\\"); - PhDereferenceObject(pluginsDirectory); + PPH_STRING applicationDirectory; + + if (applicationDirectory = PhGetApplicationDirectory()) + { + PhMoveReference(&PluginsDirectory, PhConcatStrings( // Not absolute. Make sure it is. + 4, + applicationDirectory->Buffer, + L"\\", + pluginsDirectory->Buffer, + L"\\" + )); + + PhDereferenceObject(pluginsDirectory); + } } - else + + if (PhIsNullOrEmptyString(PluginsDirectory)) { - PluginsDirectory = pluginsDirectory; + PhMoveReference(&PluginsDirectory, pluginsDirectory); } if (NT_SUCCESS(PhCreateFileWin32( &pluginsDirectoryHandle, - PluginsDirectory->Buffer, + PhGetString(PluginsDirectory), FILE_GENERIC_READ, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ, diff --git a/ProcessHacker/procprv.c b/ProcessHacker/procprv.c index 93c79a8f7b6b..27ad54894fa6 100644 --- a/ProcessHacker/procprv.c +++ b/ProcessHacker/procprv.c @@ -1226,7 +1226,7 @@ VOID PhpFillProcessItem( ProcessItem->ProcessId == SYSTEM_PROCESS_ID // System token can't be opened on XP ) { - PhSetReference(&ProcessItem->UserName, PhLocalSystemName); + PhSetReference(&ProcessItem->UserName, PhCreateString(L"NT AUTHORITY\\SYSTEM")); } } diff --git a/ProcessHacker/runas.c b/ProcessHacker/runas.c index c4120d6a5a7c..70c6566c6f14 100644 --- a/ProcessHacker/runas.c +++ b/ProcessHacker/runas.c @@ -1221,6 +1221,7 @@ NTSTATUS PhExecuteRunAsCommand( { NTSTATUS status; ULONG win32Result; + PPH_STRING applicationFileName; PPH_STRING commandLine; SC_HANDLE scManagerHandle; SC_HANDLE serviceHandle; @@ -1231,7 +1232,10 @@ NTSTATUS PhExecuteRunAsCommand( if (!(scManagerHandle = OpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE))) return PhGetLastWin32ErrorAsNtStatus(); - commandLine = PhFormatString(L"\"%s\" -ras \"%s\"", PhApplicationFileName->Buffer, Parameters->ServiceName); + if (!(applicationFileName = PhGetApplicationFileName())) + return STATUS_FAIL_CHECK; + + commandLine = PhFormatString(L"\"%s\" -ras \"%s\"", applicationFileName->Buffer, Parameters->ServiceName); serviceHandle = CreateService( scManagerHandle, @@ -1251,6 +1255,7 @@ NTSTATUS PhExecuteRunAsCommand( win32Result = GetLastError(); PhDereferenceObject(commandLine); + PhDereferenceObject(applicationFileName); CloseServiceHandle(scManagerHandle); @@ -1489,21 +1494,18 @@ static VOID WINAPI RunAsServiceMain( ) { PPH_STRING portName; - UNICODE_STRING portNameUs; - LARGE_INTEGER timeout; memset(&RunAsServiceStop, 0, sizeof(PHSVC_STOP)); RunAsServiceStatusHandle = RegisterServiceCtrlHandlerEx(RunAsServiceName->Buffer, RunAsServiceHandlerEx, NULL); SetRunAsServiceStatus(SERVICE_RUNNING); - portName = PhConcatStrings2(L"\\BaseNamedObjects\\", RunAsServiceName->Buffer); - PhStringRefToUnicodeString(&portName->sr, &portNameUs); - - // Use a shorter timeout value to reduce the time spent running as SYSTEM. - timeout.QuadPart = -(LONGLONG)UInt32x32To64(5, PH_TIMEOUT_SEC); + portName = PhConcatStrings2( + L"\\BaseNamedObjects\\", + RunAsServiceName->Buffer + ); - PhSvcMain(&portNameUs, &timeout, &RunAsServiceStop); + PhSvcMain(portName, &RunAsServiceStop); SetRunAsServiceStatus(SERVICE_STOPPED); } diff --git a/ProcessHacker/sessmsg.c b/ProcessHacker/sessmsg.c index afbd3f6e2642..e090c21de114 100644 --- a/ProcessHacker/sessmsg.c +++ b/ProcessHacker/sessmsg.c @@ -21,7 +21,7 @@ */ #include - +#include #include #include @@ -69,6 +69,7 @@ INT_PTR CALLBACK PhpSessionSendMessageDlgProc( case WM_INITDIALOG: { HWND iconComboBox; + PPH_STRING currentUserName; PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, UlongToPtr((ULONG)lParam)); @@ -83,13 +84,14 @@ INT_PTR CALLBACK PhpSessionSendMessageDlgProc( ComboBox_AddString(iconComboBox, L"Question"); PhSelectComboBoxString(iconComboBox, L"None", FALSE); - if (PhCurrentUserName) + if (currentUserName = PhGetTokenUserString(PhGetOwnTokenAttributes().TokenHandle, TRUE)) { PhSetDialogItemText( hwndDlg, IDC_TITLE, - PhaFormatString(L"Message from %s", PhCurrentUserName->Buffer)->Buffer + PhaFormatString(L"Message from %s", currentUserName->Buffer)->Buffer ); + PhDereferenceObject(currentUserName); } PhSetDialogFocus(hwndDlg, GetDlgItem(hwndDlg, IDC_TEXT)); diff --git a/phlib/global.c b/phlib/global.c index 49226a018302..0f7c03b11c38 100644 --- a/phlib/global.c +++ b/phlib/global.c @@ -40,7 +40,7 @@ VOID PhInitializeWindowsVersion( ); PHLIBAPI PVOID PhInstanceHandle; -PHLIBAPI PWSTR PhApplicationName = L"Application"; +PHLIBAPI PWSTR PhApplicationName; PHLIBAPI ULONG PhGlobalDpi = 96; PHLIBAPI PVOID PhHeapHandle; PHLIBAPI RTL_OSVERSIONINFOEXW PhOsVersion; @@ -63,7 +63,8 @@ NTSTATUS PhInitializePhLib( ) { return PhInitializePhLibEx( - 0xffffffff, // all possible features + L"Application", + ULONG_MAX, // all possible features NtCurrentPeb()->ImageBaseAddress, 0, 0 @@ -71,12 +72,14 @@ NTSTATUS PhInitializePhLib( } NTSTATUS PhInitializePhLibEx( + _In_ PWSTR ApplicationName, _In_ ULONG Flags, _In_ PVOID ImageBaseAddress, _In_opt_ SIZE_T HeapReserveSize, _In_opt_ SIZE_T HeapCommitSize ) { + PhApplicationName = ApplicationName; PhInstanceHandle = ImageBaseAddress; PhHeapHandle = RtlCreateHeap( HEAP_GROWABLE | HEAP_CLASS_1, diff --git a/phlib/include/phbasesup.h b/phlib/include/phbasesup.h index 9aa13276f00e..c5d6a9fca43d 100644 --- a/phlib/include/phbasesup.h +++ b/phlib/include/phbasesup.h @@ -178,7 +178,7 @@ PhDelayExecution( { LARGE_INTEGER interval; - interval.QuadPart = Interval * -PH_TIMEOUT_MS; + interval.QuadPart = -(LONGLONG)UInt32x32To64(Interval, PH_TIMEOUT_MS); return NtDelayExecution(FALSE, &interval); } diff --git a/phlib/include/phconfig.h b/phlib/include/phconfig.h index bb4f7700a972..4d1d7d8bbe48 100644 --- a/phlib/include/phconfig.h +++ b/phlib/include/phconfig.h @@ -75,6 +75,7 @@ PHLIBAPI NTSTATUS NTAPI PhInitializePhLibEx( + _In_ PWSTR Name, _In_ ULONG Flags, _In_ PVOID ImageBaseAddress, _In_opt_ SIZE_T HeapReserveSize, diff --git a/phlib/lsasup.c b/phlib/lsasup.c index f150f2657dd1..9347cb054a9f 100644 --- a/phlib/lsasup.c +++ b/phlib/lsasup.c @@ -497,4 +497,4 @@ PPH_STRING PhGetTokenUserString( } return tokenUserString; -} \ No newline at end of file +} diff --git a/phlib/symprv.c b/phlib/symprv.c index e4b097167b1f..68565c9ed237 100644 --- a/phlib/symprv.c +++ b/phlib/symprv.c @@ -247,21 +247,37 @@ VOID PhpSymbolProviderCompleteInitialization( { static struct { - ULONG Folder; - PWSTR AppendPath; + PH_STRINGREF AppendPath; } locations[] = { #ifdef _WIN64 - { CSIDL_PROGRAM_FILESX86, L"\\Windows Kits\\10\\Debuggers\\x64\\dbghelp.dll" }, - { CSIDL_PROGRAM_FILES, L"\\Windows Kits\\10\\Debuggers\\x64\\dbghelp.dll" }, - { CSIDL_PROGRAM_FILESX86, L"\\Windows Kits\\8.1\\Debuggers\\x64\\dbghelp.dll" }, - { CSIDL_PROGRAM_FILESX86, L"\\Windows Kits\\8.0\\Debuggers\\x64\\dbghelp.dll" }, - { CSIDL_PROGRAM_FILES, L"\\Debugging Tools for Windows (x64)\\dbghelp.dll" } + PH_STRINGREF_INIT(L"%ProgramFiles(x86)%\\Windows Kits\\10\\Debuggers\\x64\\dbghelp.dll"), + PH_STRINGREF_INIT(L"%ProgramFiles%\\Windows Kits\\10\\Debuggers\\x64\\dbghelp.dll"), + PH_STRINGREF_INIT(L"%ProgramFiles(x86)%\\Windows Kits\\8.1\\Debuggers\\x64\\dbghelp.dll"), + PH_STRINGREF_INIT(L"%ProgramFiles(x86)%\\Windows Kits\\8.0\\Debuggers\\x64\\dbghelp.dll"), + PH_STRINGREF_INIT(L"%ProgramFiles%\\Debugging Tools for Windows (x64)\\dbghelp.dll") #else - { CSIDL_PROGRAM_FILES, L"\\Windows Kits\\10\\Debuggers\\x86\\dbghelp.dll" }, - { CSIDL_PROGRAM_FILES, L"\\Windows Kits\\8.1\\Debuggers\\x86\\dbghelp.dll" }, - { CSIDL_PROGRAM_FILES, L"\\Windows Kits\\8.0\\Debuggers\\x86\\dbghelp.dll" }, - { CSIDL_PROGRAM_FILES, L"\\Debugging Tools for Windows (x86)\\dbghelp.dll" } + PH_STRINGREF_INIT(L"%ProgramFiles%\\Windows Kits\\10\\Debuggers\\x86\\dbghelp.dll"), + PH_STRINGREF_INIT(L"%ProgramFiles%\\Windows Kits\\8.1\\Debuggers\\x86\\dbghelp.dll"), + PH_STRINGREF_INIT(L"%ProgramFiles%\\Windows Kits\\8.0\\Debuggers\\x86\\dbghelp.dll"), + PH_STRINGREF_INIT(L"%ProgramFiles%\\Debugging Tools for Windows (x86)\\dbghelp.dll") +#endif + }; + static struct + { + PH_STRINGREF AppendPath; + } symsrvlocation[] = + { +#ifdef _WIN64 + { PH_STRINGREF_INIT(L"%ProgramFiles(x86)%\\Windows Kits\\10\\Debuggers\\x64\\symsrv.dll") }, + { PH_STRINGREF_INIT(L"%ProgramFiles(x86)%\\Windows Kits\\8.1\\Debuggers\\x64\\symsrv.dll") }, + { PH_STRINGREF_INIT(L"%ProgramFiles(x86)%\\Windows Kits\\8.0\\Debuggers\\x64\\symsrv.dll") }, + { PH_STRINGREF_INIT(L"%ProgramFiles%\\Debugging Tools for Windows (x64)\\symsrv.dll") } +#else + { CSIDL_PROGRAM_FILES, L"%ProgramFiles%\\Windows Kits\\10\\Debuggers\\x86\\symsrv.dll" }, + { CSIDL_PROGRAM_FILES, L"%ProgramFiles%\\Windows Kits\\8.1\\Debuggers\\x86\\symsrv.dll" }, + { CSIDL_PROGRAM_FILES, L"%ProgramFiles%\\Windows Kits\\8.0\\Debuggers\\x86\\symsrv.dll" }, + { CSIDL_PROGRAM_FILES, L"%ProgramFiles%\\Debugging Tools for Windows (x86)\\symsrv.dll" } #endif }; @@ -275,9 +291,9 @@ VOID PhpSymbolProviderCompleteInitialization( if (dbghelpHandle && symsrvHandle) return; - for (ULONG i = 0; i < ARRAYSIZE(locations); i++) + for (ULONG i = 0; i < RTL_NUMBER_OF(locations); i++) { - if (dbghelpPath = PhGetKnownLocation(locations[i].Folder, locations[i].AppendPath)) + if (dbghelpPath = PhExpandEnvironmentStrings(&locations[i].AppendPath)) { if (RtlDoesFileExists_U(dbghelpPath->Buffer)) break; @@ -299,12 +315,10 @@ VOID PhpSymbolProviderCompleteInitialization( { if (indexOfFileName != 0) { - static PH_STRINGREF symsrvString = PH_STRINGREF_INIT(L"\\symsrv.dll"); - dbghelpFolder.Buffer = fullDbghelpPath->Buffer; dbghelpFolder.Length = indexOfFileName * sizeof(WCHAR); - symsrvPath = PhConcatStringRef2(&dbghelpFolder, &symsrvString); + symsrvPath = PhConcatStringRefZ(&dbghelpFolder, L"\\symsrv.dll"); symsrvHandle = LoadLibrary(symsrvPath->Buffer); PhDereferenceObject(symsrvPath); } diff --git a/plugins/NetworkTools/country.c b/plugins/NetworkTools/country.c index 283cfb9d9902..8cbcf4fbd088 100644 --- a/plugins/NetworkTools/country.c +++ b/plugins/NetworkTools/country.c @@ -38,7 +38,10 @@ VOID LoadGeoLiteDb( dbpath = PhGetExpandStringSetting(SETTING_NAME_DB_LOCATION); if (PhIsNullOrEmptyString(dbpath)) - PhMoveReference(&dbpath, PhGetKnownLocation(CSIDL_APPDATA, L"\\Process Hacker\\GeoLite2-Country.mmdb")); + { + PH_STRINGREF defaultDbPathSr = PH_STRINGREF_INIT(L"%APPDATA%\\Process Hacker\\GeoLite2-Country.mmdb"); + PhMoveReference(&dbpath, PhExpandEnvironmentStrings(&defaultDbPathSr)); + } if (MMDB_open(PhGetString(dbpath), MMDB_MODE_MMAP, &GeoDb) == MMDB_SUCCESS) { diff --git a/plugins/NetworkTools/update.c b/plugins/NetworkTools/update.c index 19b39bdb414c..6616e5fb36ef 100644 --- a/plugins/NetworkTools/update.c +++ b/plugins/NetworkTools/update.c @@ -375,7 +375,11 @@ NTSTATUS GeoIPUpdateThread( dbpath = PhGetExpandStringSetting(SETTING_NAME_DB_LOCATION); if (PhIsNullOrEmptyString(dbpath)) - PhMoveReference(&dbpath, PhGetKnownLocation(CSIDL_APPDATA, L"\\Process Hacker\\GeoLite2-Country.mmdb")); + { + PH_STRINGREF defaultDbPathSr = PH_STRINGREF_INIT(L"%APPDATA%\\Process Hacker\\GeoLite2-Country.mmdb"); + + PhMoveReference(&dbpath, PhExpandEnvironmentStrings(&defaultDbPathSr)); + } if (RtlDoesFileExists_U(PhGetString(dbpath))) { diff --git a/tools/peview/main.c b/tools/peview/main.c index 4a31bb982852..ceaf6704fa6e 100644 --- a/tools/peview/main.c +++ b/tools/peview/main.c @@ -52,7 +52,7 @@ INT WINAPI wWinMain( CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE); - if (!NT_SUCCESS(PhInitializePhLib())) + if (!NT_SUCCESS(PhInitializePhLibEx(L"PE Viewer", ULONG_MAX, hInstance, 0, 0))) return 1; // Create a mutant for the installer. @@ -93,8 +93,6 @@ INT WINAPI wWinMain( PvPropInitialization(); PhTreeNewInitialization(); - PhApplicationName = L"PE Viewer"; - if (!NT_SUCCESS(PhGetProcessCommandLine(NtCurrentProcess(), &commandLine))) return 1; diff --git a/tools/peview/pdb.c b/tools/peview/pdb.c index a5f8e17a348b..ee704a7b3fc0 100644 --- a/tools/peview/pdb.c +++ b/tools/peview/pdb.c @@ -2274,28 +2274,27 @@ PPH_STRING PvFindDbghelpPath( static struct { BOOLEAN Type; - ULONG Folder; - PWSTR AppendPath; + PH_STRINGREF AppendPath; } locations[] = { #ifdef _WIN64 - { FALSE, CSIDL_PROGRAM_FILESX86, L"\\Windows Kits\\10\\Debuggers\\x64\\dbghelp.dll" }, - { FALSE, CSIDL_PROGRAM_FILESX86, L"\\Windows Kits\\8.1\\Debuggers\\x64\\dbghelp.dll" }, - { FALSE, CSIDL_PROGRAM_FILESX86, L"\\Windows Kits\\8.0\\Debuggers\\x64\\dbghelp.dll" }, - { FALSE, CSIDL_PROGRAM_FILES, L"\\Debugging Tools for Windows (x64)\\dbghelp.dll" }, - { TRUE, CSIDL_PROGRAM_FILESX86, L"\\Windows Kits\\10\\Debuggers\\x64\\symsrv.dll" }, - { TRUE, CSIDL_PROGRAM_FILESX86, L"\\Windows Kits\\8.1\\Debuggers\\x64\\symsrv.dll" }, - { TRUE, CSIDL_PROGRAM_FILESX86, L"\\Windows Kits\\8.0\\Debuggers\\x64\\symsrv.dll" }, - { TRUE, CSIDL_PROGRAM_FILES, L"\\Debugging Tools for Windows (x64)\\symsrv.dll" } + { FALSE, PH_STRINGREF_INIT(L"%ProgramFiles(x86)%\\Windows Kits\\10\\Debuggers\\x64\\dbghelp.dll") }, + { FALSE, PH_STRINGREF_INIT(L"%ProgramFiles(x86)%\\Windows Kits\\8.1\\Debuggers\\x64\\dbghelp.dll") }, + { FALSE, PH_STRINGREF_INIT(L"%ProgramFiles(x86)%\\Windows Kits\\8.0\\Debuggers\\x64\\dbghelp.dll") }, + { FALSE, PH_STRINGREF_INIT(L"%ProgramFiles%\\Debugging Tools for Windows (x64)\\dbghelp.dll") }, + { TRUE, PH_STRINGREF_INIT(L"%ProgramFiles(x86)%\\Windows Kits\\10\\Debuggers\\x64\\symsrv.dll") }, + { TRUE, PH_STRINGREF_INIT(L"%ProgramFiles(x86)%\\Windows Kits\\8.1\\Debuggers\\x64\\symsrv.dll") }, + { TRUE, PH_STRINGREF_INIT(L"%ProgramFiles(x86)%\\Windows Kits\\8.0\\Debuggers\\x64\\symsrv.dll") }, + { TRUE, PH_STRINGREF_INIT(L"%ProgramFiles%\\Debugging Tools for Windows (x64)\\symsrv.dll") } #else - { FALSE, CSIDL_PROGRAM_FILES, L"\\Windows Kits\\10\\Debuggers\\x86\\dbghelp.dll" }, - { FALSE, CSIDL_PROGRAM_FILES, L"\\Windows Kits\\8.1\\Debuggers\\x86\\dbghelp.dll" }, - { FALSE, CSIDL_PROGRAM_FILES, L"\\Windows Kits\\8.0\\Debuggers\\x86\\dbghelp.dll" }, - { FALSE, CSIDL_PROGRAM_FILES, L"\\Debugging Tools for Windows (x86)\\dbghelp.dll" }, - { TRUE, CSIDL_PROGRAM_FILES, L"\\Windows Kits\\10\\Debuggers\\x86\\symsrv.dll" }, - { TRUE, CSIDL_PROGRAM_FILES, L"\\Windows Kits\\8.1\\Debuggers\\x86\\symsrv.dll" }, - { TRUE, CSIDL_PROGRAM_FILES, L"\\Windows Kits\\8.0\\Debuggers\\x86\\symsrv.dll" }, - { TRUE, CSIDL_PROGRAM_FILES, L"\\Debugging Tools for Windows (x86)\\symsrv.dll" } + { FALSE, PH_STRINGREF_INIT(L"%ProgramFiles%\\Windows Kits\\10\\Debuggers\\x86\\dbghelp.dll") }, + { FALSE, PH_STRINGREF_INIT(L"%ProgramFiles%\\Windows Kits\\8.1\\Debuggers\\x86\\dbghelp.dll") }, + { FALSE, PH_STRINGREF_INIT(L"%ProgramFiles%\\Windows Kits\\8.0\\Debuggers\\x86\\dbghelp.dll") }, + { FALSE, PH_STRINGREF_INIT(L"%ProgramFiles%\\Debugging Tools for Windows (x86)\\dbghelp.dll") }, + { TRUE, PH_STRINGREF_INIT(L"%ProgramFiles%\\Windows Kits\\10\\Debuggers\\x86\\symsrv.dll") }, + { TRUE, PH_STRINGREF_INIT(L"%ProgramFiles%\\Windows Kits\\8.1\\Debuggers\\x86\\symsrv.dll") }, + { TRUE, PH_STRINGREF_INIT(L"%ProgramFiles%\\Windows Kits\\8.0\\Debuggers\\x86\\symsrv.dll") }, + { TRUE, PH_STRINGREF_INIT(L"%ProgramFiles%\\Debugging Tools for Windows (x86)\\symsrv.dll") } #endif }; @@ -2307,9 +2306,7 @@ PPH_STRING PvFindDbghelpPath( if (locations[i].Type != Type) continue; - path = PhGetKnownLocation(locations[i].Folder, locations[i].AppendPath); - - if (path) + if (path = PhExpandEnvironmentStrings(&locations[i].AppendPath)) { if (RtlDoesFileExists_U(path->Buffer)) return path; diff --git a/tools/peview/peprp.c b/tools/peview/peprp.c index cf971f4186c6..3fded8916d2c 100644 --- a/tools/peview/peprp.c +++ b/tools/peview/peprp.c @@ -218,7 +218,7 @@ VERIFY_RESULT PvpVerifyFileWithAdditionalCatalog( ) { static PH_STRINGREF codeIntegrityFileName = PH_STRINGREF_INIT(L"\\AppxMetadata\\CodeIntegrity.cat"); - + static PH_STRINGREF windowsAppsPathSr = PH_STRINGREF_INIT(L"%ProgramFiles%\\WindowsApps\\"); VERIFY_RESULT result; PH_VERIFY_FILE_INFO info; PPH_STRING windowsAppsPath; @@ -231,9 +231,7 @@ VERIFY_RESULT PvpVerifyFileWithAdditionalCatalog( info.Flags = Flags; info.hWnd = hWnd; - windowsAppsPath = PhGetKnownLocation(CSIDL_PROGRAM_FILES, L"\\WindowsApps\\"); - - if (windowsAppsPath) + if (windowsAppsPath = PhExpandEnvironmentStrings(&windowsAppsPathSr)) { if (PhStartsWithStringRef(&FileName->sr, &windowsAppsPath->sr, TRUE)) { diff --git a/tools/peview/settings.c b/tools/peview/settings.c index 7b5fa547709f..28f2082e0720 100644 --- a/tools/peview/settings.c +++ b/tools/peview/settings.c @@ -60,6 +60,7 @@ VOID PeInitializeSettings( VOID ) { + static PH_STRINGREF settingsPath = PH_STRINGREF_INIT(L"%APPDATA%\\Process Hacker\\peview.xml"); static PH_STRINGREF settingsSuffix = PH_STRINGREF_INIT(L".peview.xml"); NTSTATUS status; PPH_STRING appFileName; @@ -88,7 +89,7 @@ VOID PeInitializeSettings( // 2. Default location if (!PeSettingsFileName) { - PeSettingsFileName = PhGetKnownLocation(CSIDL_APPDATA, L"\\Process Hacker\\peview.xml"); + PeSettingsFileName = PhExpandEnvironmentStrings(&settingsPath); } if (PeSettingsFileName) From 9e25e6a4790531281e52ff975d049e44c27c7261 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 3 Jul 2018 16:56:08 +1000 Subject: [PATCH 1080/2058] Fix #285 (TokenSid regression aac6888) --- ProcessHacker/chproc.c | 4 +- ProcessHacker/include/procprv.h | 2 +- ProcessHacker/include/proctree.h | 2 + ProcessHacker/main.c | 78 ++++++++++++++++++-------------- ProcessHacker/mainwnd.c | 3 +- ProcessHacker/mwpgproc.c | 6 +-- ProcessHacker/procgrp.c | 28 ++++++------ ProcessHacker/procprv.c | 76 ++++++++++++++----------------- ProcessHacker/proctree.c | 33 ++++++++++---- ProcessHacker/runas.c | 6 +-- phlib/include/phnative.h | 1 + phlib/lsasup.c | 9 +--- phlib/native.c | 8 ++++ 13 files changed, 141 insertions(+), 115 deletions(-) diff --git a/ProcessHacker/chproc.c b/ProcessHacker/chproc.c index cd50853564ca..b5ca4ce9ba91 100644 --- a/ProcessHacker/chproc.c +++ b/ProcessHacker/chproc.c @@ -131,7 +131,9 @@ static VOID PhpRefreshProcessList( } if (process->UniqueProcessId == SYSTEM_IDLE_PROCESS_ID && !userName) - PhSetReference(&userName, PhCreateString(L"NT AUTHORITY\\SYSTEM")); + { + PhSetReference(&userName, PhGetSidFullName(&PhSeLocalSystemSid, TRUE, NULL)); + } if (process->UniqueProcessId == SYSTEM_PROCESS_ID) fileName = PhGetKernelFileName(); diff --git a/ProcessHacker/include/procprv.h b/ProcessHacker/include/procprv.h index 13fb02dfafef..b47d4dc62a37 100644 --- a/ProcessHacker/include/procprv.h +++ b/ProcessHacker/include/procprv.h @@ -126,7 +126,7 @@ typedef struct _PH_PROCESS_ITEM // Security - PPH_STRING UserName; + PSID Sid; TOKEN_ELEVATION_TYPE ElevationType; MANDATORY_LEVEL IntegrityLevel; PWSTR IntegrityString; diff --git a/ProcessHacker/include/proctree.h b/ProcessHacker/include/proctree.h index 9ba8ccd29a84..cf1950534c47 100644 --- a/ProcessHacker/include/proctree.h +++ b/ProcessHacker/include/proctree.h @@ -110,6 +110,7 @@ #define PHPN_DPIAWARENESS 0x400 #define PHPN_FILEATTRIBUTES 0x800 #define PHPN_DESKTOPINFO 0x1000 +#define PHPN_USERNAME 0x2000 // begin_phapppub typedef struct _PH_PROCESS_NODE @@ -222,6 +223,7 @@ typedef struct _PH_PROCESS_NODE WCHAR JobObjectIdText[PH_INT32_STR_LEN_1]; PPH_STRING ProtectionText; PPH_STRING DesktopInfoText; + PPH_STRING UserName; // Graph buffers PH_GRAPH_BUFFERS CpuGraphBuffers; diff --git a/ProcessHacker/main.c b/ProcessHacker/main.c index b8f4d846e430..aefc7a76445e 100644 --- a/ProcessHacker/main.c +++ b/ProcessHacker/main.c @@ -80,12 +80,15 @@ BOOLEAN PhInitializeExceptionPolicy( VOID ); +BOOLEAN PhInitializeNamespacePolicy( + VOID + ); + BOOLEAN PhInitializeMitigationPolicy( VOID ); PHAPPAPI HFONT PhApplicationFont = NULL; -PPH_STRING PhCurrentUserName = NULL; BOOLEAN PhPluginsEnabled = FALSE; PPH_STRING PhSettingsFileName = NULL; PH_INTEGER_PAIR PhSmallIconSize = { 16, 16 }; @@ -117,6 +120,8 @@ INT WINAPI wWinMain( return 1; if (!PhInitializeExceptionPolicy()) return 1; + if (!PhInitializeNamespacePolicy()) + return 1; if (!PhInitializeMitigationPolicy()) return 1; if (!PhInitializeRestartPolicy()) @@ -235,38 +240,6 @@ INT WINAPI wWinMain( } #endif - // Create a mutant for the installer. - { - HANDLE mutantHandle; - PPH_STRING objectName; - OBJECT_ATTRIBUTES objectAttributes; - UNICODE_STRING objectNameUs; - PH_FORMAT format[2]; - - PhInitFormatS(&format[0], L"PhMutant_"); - PhInitFormatU(&format[1], HandleToUlong(NtCurrentProcessId())); - - objectName = PhFormat(format, 2, 16); - PhStringRefToUnicodeString(&objectName->sr, &objectNameUs); - - InitializeObjectAttributes( - &objectAttributes, - &objectNameUs, - OBJ_CASE_INSENSITIVE, - PhGetNamespaceHandle(), - NULL - ); - - NtCreateMutant( - &mutantHandle, - MUTANT_QUERY_STATE, - &objectAttributes, - TRUE - ); - - PhDereferenceObject(objectName); - } - // Set the default priority. { PROCESS_PRIORITY_CLASS priorityClass; @@ -604,6 +577,45 @@ BOOLEAN PhInitializeExceptionPolicy( return TRUE; } +BOOLEAN PhInitializeNamespacePolicy( + VOID + ) +{ + HANDLE mutantHandle; + PPH_STRING objectName; + OBJECT_ATTRIBUTES objectAttributes; + UNICODE_STRING objectNameUs; + PH_FORMAT format[2]; + + PhInitFormatS(&format[0], L"PhMutant_"); + PhInitFormatU(&format[1], HandleToUlong(NtCurrentProcessId())); + + objectName = PhFormat(format, RTL_NUMBER_OF(format), 16); + PhStringRefToUnicodeString(&objectName->sr, &objectNameUs); + + InitializeObjectAttributes( + &objectAttributes, + &objectNameUs, + OBJ_CASE_INSENSITIVE, + PhGetNamespaceHandle(), + NULL + ); + + if (NT_SUCCESS(NtCreateMutant( + &mutantHandle, + MUTANT_QUERY_STATE, + &objectAttributes, + TRUE + ))) + { + PhDereferenceObject(objectName); + return TRUE; + } + + PhDereferenceObject(objectName); + return FALSE; +} + BOOLEAN PhInitializeMitigationPolicy( VOID ) diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index 2c5cd6282fe9..668f791ce397 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -2988,7 +2988,8 @@ VOID PhMwpAddIconProcesses( if ( processItem->CpuUsage == 0 || - processItem->SessionId != NtCurrentPeb()->SessionId + processItem->SessionId != NtCurrentPeb()->SessionId || + (processItem->Sid && !RtlEqualSid(processItem->Sid, PhGetOwnTokenAttributes().TokenSid)) ) { PhRemoveItemList(processList, i); diff --git a/ProcessHacker/mwpgproc.c b/ProcessHacker/mwpgproc.c index caf4ec47909a..b410279e5f0e 100644 --- a/ProcessHacker/mwpgproc.c +++ b/ProcessHacker/mwpgproc.c @@ -256,13 +256,13 @@ BOOLEAN PhMwpCurrentUserProcessTreeFilter( { PPH_PROCESS_NODE processNode = (PPH_PROCESS_NODE)Node; - if (!processNode->ProcessItem->UserName) + if (processNode->ProcessItem->SessionId != NtCurrentPeb()->SessionId) return FALSE; - if (!PhCurrentUserName) + if (!processNode->ProcessItem->Sid) return FALSE; - if (!PhEqualString(processNode->ProcessItem->UserName, PhCurrentUserName, TRUE)) + if (!RtlEqualSid(processNode->ProcessItem->Sid, PhGetOwnTokenAttributes().TokenSid)) return FALSE; return TRUE; diff --git a/ProcessHacker/procgrp.c b/ProcessHacker/procgrp.c index be3325709507..fa3c40d06f28 100644 --- a/ProcessHacker/procgrp.c +++ b/ProcessHacker/procgrp.c @@ -155,20 +155,20 @@ PPH_STRING PhpGetRelevantFileName( BOOLEAN PhpEqualFileNameAndUserName( _In_ PPH_STRING FileName, - _In_ PPH_STRING UserName, + _In_ PSID UserSid, _In_ PPH_PROCESS_ITEM ProcessItem, _In_ ULONG Flags ) { PPH_STRING otherFileName; - PPH_STRING otherUserName; + PSID otherUserSid; otherFileName = PhpGetRelevantFileName(ProcessItem, Flags); - otherUserName = ProcessItem->UserName; + otherUserSid = ProcessItem->Sid; return otherFileName && PhEqualString(otherFileName, FileName, TRUE) && - otherUserName && PhEqualString(otherUserName, UserName, TRUE); + otherUserSid && RtlEqualSid(otherUserSid, UserSid); } PPHP_PROCESS_DATA PhpFindGroupRoot( @@ -182,12 +182,12 @@ PPHP_PROCESS_DATA PhpFindGroupRoot( PPH_PROCESS_NODE parent; PPHP_PROCESS_DATA processData; PPH_STRING fileName; - PPH_STRING userName; + PPH_STRING userSid; root = ProcessData->Process; rootProcessData = ProcessData; fileName = PhpGetRelevantFileName(ProcessData->Process->ProcessItem, Flags); - userName = ProcessData->Process->ProcessItem->UserName; + userSid = ProcessData->Process->ProcessItem->Sid; if (ProcessData->WindowHandle) return rootProcessData; @@ -195,7 +195,7 @@ PPHP_PROCESS_DATA PhpFindGroupRoot( while (parent = root->Parent) { if ((processData = PhFindItemSimpleHashtable2(ProcessDataHashtable, parent->ProcessId)) && - PhpEqualFileNameAndUserName(fileName, userName, parent->ProcessItem, Flags)) + PhpEqualFileNameAndUserName(fileName, userSid, parent->ProcessItem, Flags)) { root = parent; rootProcessData = processData; @@ -230,12 +230,12 @@ VOID PhpAddGroupMembersFromRoot( ) { PPH_STRING fileName; - PPH_STRING userName; + PSID userSid; ULONG i; PhpAddGroupMember(ProcessData, List); fileName = PhpGetRelevantFileName(ProcessData->Process->ProcessItem, Flags); - userName = ProcessData->Process->ProcessItem->UserName; + userSid = ProcessData->Process->ProcessItem->Sid; for (i = 0; i < ProcessData->Process->Children->Count; i++) { @@ -243,8 +243,8 @@ VOID PhpAddGroupMembersFromRoot( PPHP_PROCESS_DATA processData; if ((processData = PhFindItemSimpleHashtable2(ProcessDataHashtable, node->ProcessId)) && - PhpEqualFileNameAndUserName(fileName, userName, node->ProcessItem, Flags) && - node->ProcessItem->UserName && PhEqualString(node->ProcessItem->UserName, userName, TRUE) && + PhpEqualFileNameAndUserName(fileName, userSid, node->ProcessItem, Flags) && + node->ProcessItem->Sid && RtlEqualSid(node->ProcessItem->Sid, userSid) && !processData->WindowHandle) { PhpAddGroupMembersFromRoot(processData, List, ProcessDataHashtable, Flags); @@ -294,14 +294,14 @@ PPH_LIST PhCreateProcessGroupList( PPHP_PROCESS_DATA processData = CONTAINING_RECORD(processDataListHead.Flink, PHP_PROCESS_DATA, ListEntry); PPH_PROCESS_GROUP processGroup; PPH_STRING fileName; - PPH_STRING userName; + PSID userSid; processGroup = PhAllocate(sizeof(PH_PROCESS_GROUP)); processGroup->Processes = PhCreateList(4); fileName = PhpGetRelevantFileName(processData->Process->ProcessItem, Flags); - userName = processData->Process->ProcessItem->UserName; + userSid = processData->Process->ProcessItem->Sid; - if (!fileName || !userName || (Flags & PH_GROUP_PROCESSES_DONT_GROUP)) + if (!fileName || !userSid || (Flags & PH_GROUP_PROCESSES_DONT_GROUP)) { processGroup->Representative = processData->Process->ProcessItem; PhpAddGroupMember(processData, processGroup->Processes); diff --git a/ProcessHacker/procprv.c b/ProcessHacker/procprv.c index 27ad54894fa6..fb0ed5f028ff 100644 --- a/ProcessHacker/procprv.c +++ b/ProcessHacker/procprv.c @@ -481,7 +481,7 @@ VOID PhpProcessItemDeleteProcedure( if (processItem->SmallIcon) DestroyIcon(processItem->SmallIcon); if (processItem->LargeIcon) DestroyIcon(processItem->LargeIcon); PhDeleteImageVersionInfo(&processItem->VersionInfo); - if (processItem->UserName) PhDereferenceObject(processItem->UserName); + if (processItem->Sid) PhFree(processItem->Sid); if (processItem->JobName) PhDereferenceObject(processItem->JobName); if (processItem->VerifySignerName) PhDereferenceObject(processItem->VerifySignerName); if (processItem->PackageFullName) PhDereferenceObject(processItem->PackageFullName); @@ -812,33 +812,6 @@ VOID PhpProcessQueryStage1( NtClose(processHandle); } - // Token information - if (processHandleLimited) - { - HANDLE tokenHandle; - - if (NT_SUCCESS(PhOpenProcessToken(processHandleLimited, TOKEN_QUERY, &tokenHandle))) - { - // Elevation - if (NT_SUCCESS(PhGetTokenElevationType( - tokenHandle, - &Data->ElevationType - ))) - { - Data->IsElevated = Data->ElevationType == TokenElevationTypeFull; - } - - // Integrity - PhGetTokenIntegrityLevel( - tokenHandle, - &Data->IntegrityLevel, - &Data->IntegrityString - ); - - NtClose(tokenHandle); - } - } - // Job if (processHandleLimited) { @@ -1198,22 +1171,41 @@ VOID PhpFillProcessItem( } } - // Token-related information - if ( - ProcessItem->QueryHandle && - ProcessItem->ProcessId != SYSTEM_PROCESS_ID // Token of System process can't be opened sometimes - ) + // Token information + if (ProcessItem->QueryHandle) { HANDLE tokenHandle; - if (NT_SUCCESS(PhOpenProcessToken(ProcessItem->QueryHandle, TOKEN_QUERY, &tokenHandle))) + if (NT_SUCCESS(PhOpenProcessToken( + ProcessItem->QueryHandle, + TOKEN_QUERY, + &tokenHandle + ))) { - PTOKEN_USER user; + PTOKEN_USER tokenUser; + TOKEN_ELEVATION_TYPE elevationType; + MANDATORY_LEVEL integrityLevel; + PWSTR integrityString; - if (NT_SUCCESS(PhGetTokenUser(tokenHandle, &user))) + // User + if (NT_SUCCESS(PhGetTokenUser(tokenHandle, &tokenUser))) { - ProcessItem->UserName = PhpGetSidFullNameCached(user->User.Sid); - PhFree(user); + ProcessItem->Sid = PhAllocateCopy(tokenUser->User.Sid, RtlLengthSid(tokenUser->User.Sid)); + PhFree(tokenUser); + } + + // Elevation + if (NT_SUCCESS(PhGetTokenElevationType(tokenHandle, &elevationType))) + { + ProcessItem->ElevationType = elevationType; + ProcessItem->IsElevated = elevationType == TokenElevationTypeFull; + } + + // Integrity + if (NT_SUCCESS(PhGetTokenIntegrityLevel(tokenHandle, &integrityLevel, &integrityString))) + { + ProcessItem->IntegrityLevel = integrityLevel; + ProcessItem->IntegrityString = integrityString; } NtClose(tokenHandle); @@ -1221,12 +1213,10 @@ VOID PhpFillProcessItem( } else { - if ( - ProcessItem->ProcessId == SYSTEM_IDLE_PROCESS_ID || - ProcessItem->ProcessId == SYSTEM_PROCESS_ID // System token can't be opened on XP - ) + if (ProcessItem->ProcessId == SYSTEM_IDLE_PROCESS_ID || + ProcessItem->ProcessId == SYSTEM_PROCESS_ID) // System token can't be opened on XP { - PhSetReference(&ProcessItem->UserName, PhCreateString(L"NT AUTHORITY\\SYSTEM")); + ProcessItem->Sid = PhAllocateCopy(&PhSeLocalSystemSid, RtlLengthSid(&PhSeLocalSystemSid)); } } diff --git a/ProcessHacker/proctree.c b/ProcessHacker/proctree.c index fd532c581fd1..d24bc564577b 100644 --- a/ProcessHacker/proctree.c +++ b/ProcessHacker/proctree.c @@ -30,6 +30,7 @@ #include #include +#include #include #include @@ -645,7 +646,7 @@ VOID PhTickProcessNodes( // The name and PID never change, so we don't invalidate that. memset(&node->TextCache[2], 0, sizeof(PH_STRINGREF) * (PHPRTLC_MAXIMUM - 2)); - node->ValidMask &= PHPN_OSCONTEXT | PHPN_IMAGE | PHPN_DPIAWARENESS | PHPN_APPID | PHPN_DESKTOPINFO; // Items that always remain valid + node->ValidMask &= PHPN_OSCONTEXT | PHPN_IMAGE | PHPN_DPIAWARENESS | PHPN_APPID | PHPN_DESKTOPINFO | PHPN_USERNAME; // Items that always remain valid // Invalidate graph buffers. node->CpuGraphBuffers.Valid = FALSE; @@ -827,6 +828,21 @@ static VOID PhpAggregateFieldIfNeeded( } } +static VOID PhpUpdateProcessNodeUserName( + _Inout_ PPH_PROCESS_NODE ProcessNode + ) +{ + if (!(ProcessNode->ValidMask & PHPN_USERNAME)) + { + if (ProcessNode->ProcessItem->Sid) + { + ProcessNode->UserName = PhGetSidFullName(ProcessNode->ProcessItem->Sid, TRUE, NULL); + } + + ProcessNode->ValidMask |= PHPN_USERNAME; + } +} + static VOID PhpUpdateProcessNodeWsCounters( _Inout_ PPH_PROCESS_NODE ProcessNode ) @@ -1350,7 +1366,7 @@ END_SORT_FUNCTION BEGIN_SORT_FUNCTION(UserName) { - sortResult = PhCompareStringWithNull(processItem1->UserName, processItem2->UserName, TRUE); + sortResult = PhCompareStringWithNull(node1->UserName, node2->UserName, TRUE); } END_SORT_FUNCTION @@ -2169,7 +2185,8 @@ BOOLEAN NTAPI PhpProcessTreeNewCallback( } break; case PHPRTLC_USERNAME: - getCellText->Text = PhGetStringRef(processItem->UserName); + PhpUpdateProcessNodeUserName(node); + getCellText->Text = PhGetStringRef(node->UserName); break; case PHPRTLC_DESCRIPTION: if (processItem->VersionInfo.FileDescription) @@ -2928,15 +2945,15 @@ BOOLEAN NTAPI PhpProcessTreeNewCallback( getNodeColor->BackColor = PhCsColorServiceProcesses; else if ( PhCsUseColorSystemProcesses && - processItem->UserName && - PhEqualString(processItem->UserName, PhLocalSystemName, TRUE) + processItem->Sid && + RtlEqualSid(processItem->Sid, &PhSeLocalSystemSid) ) getNodeColor->BackColor = PhCsColorSystemProcesses; else if ( PhCsUseColorOwnProcesses && - processItem->UserName && - PhCurrentUserName && - PhEqualString(processItem->UserName, PhCurrentUserName, TRUE) + processItem->SessionId == NtCurrentPeb()->SessionId && + processItem->Sid && + RtlEqualSid(processItem->Sid, PhGetOwnTokenAttributes().TokenSid) ) getNodeColor->BackColor = PhCsColorOwnProcesses; } diff --git a/ProcessHacker/runas.c b/ProcessHacker/runas.c index 70c6566c6f14..8629153bd3b0 100644 --- a/ProcessHacker/runas.c +++ b/ProcessHacker/runas.c @@ -424,9 +424,9 @@ static VOID PhpAddAccountsToComboBox( ULONG userinfoResumeHandle = 0; ComboBox_ResetContent(ComboBoxHandle); - ComboBox_AddString(ComboBoxHandle, L"NT AUTHORITY\\SYSTEM"); - ComboBox_AddString(ComboBoxHandle, L"NT AUTHORITY\\LOCAL SERVICE"); - ComboBox_AddString(ComboBoxHandle, L"NT AUTHORITY\\NETWORK SERVICE"); + ComboBox_AddString(ComboBoxHandle, PH_AUTO_T(PH_STRING, PhGetSidFullName(&PhSeLocalSystemSid, TRUE, NULL))->Buffer); + ComboBox_AddString(ComboBoxHandle, PH_AUTO_T(PH_STRING, PhGetSidFullName(&PhSeLocalServiceSid, TRUE, NULL))->Buffer); + ComboBox_AddString(ComboBoxHandle, PH_AUTO_T(PH_STRING, PhGetSidFullName(&PhSeNetworkServiceSid, TRUE, NULL))->Buffer); if (!PhpInitializeNetApi()) return; diff --git a/phlib/include/phnative.h b/phlib/include/phnative.h index 8bd3282528d9..3cb2a3e8b949 100644 --- a/phlib/include/phnative.h +++ b/phlib/include/phnative.h @@ -42,6 +42,7 @@ typedef struct _PH_TOKEN_ATTRIBUTES ULONG ReservedBits : 29; }; ULONG Reserved; + PSID TokenSid; } PH_TOKEN_ATTRIBUTES, *PPH_TOKEN_ATTRIBUTES; typedef enum _MANDATORY_LEVEL_RID { diff --git a/phlib/lsasup.c b/phlib/lsasup.c index 9347cb054a9f..db2a0bef12b5 100644 --- a/phlib/lsasup.c +++ b/phlib/lsasup.c @@ -311,14 +311,7 @@ NTSTATUS PhLookupName( { if (Sid) { - PSID sid; - ULONG sidLength; - - sidLength = RtlLengthSid(sids[0].Sid); - sid = PhAllocate(sidLength); - memcpy(sid, sids[0].Sid, sidLength); - - *Sid = sid; + *Sid = PhAllocateCopy(sids[0].Sid, RtlLengthSid(sids[0].Sid)); } if (DomainName) diff --git a/phlib/native.c b/phlib/native.c index eb99e3c02988..53cc2e3a6811 100644 --- a/phlib/native.c +++ b/phlib/native.c @@ -95,8 +95,16 @@ PH_TOKEN_ATTRIBUTES PhGetOwnTokenAttributes( if (attributes.TokenHandle) { + PTOKEN_USER tokenUser; + PhGetTokenIsElevated(attributes.TokenHandle, &elevated); PhGetTokenElevationType(attributes.TokenHandle, &elevationType); + + if (NT_SUCCESS(PhGetTokenUser(attributes.TokenHandle, &tokenUser))) + { + attributes.TokenSid = PhAllocateCopy(tokenUser->User.Sid, RtlLengthSid(tokenUser->User.Sid)); + PhFree(tokenUser); + } } attributes.Elevated = elevated; From 8409c2cf17cbcb98562c5140e2c40553bf6b1d80 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 3 Jul 2018 17:04:10 +1000 Subject: [PATCH 1081/2058] Remove legacy symbol path --- ProcessHacker/dbgcon.c | 27 ++++++++------------------- 1 file changed, 8 insertions(+), 19 deletions(-) diff --git a/ProcessHacker/dbgcon.c b/ProcessHacker/dbgcon.c index a7e65d6ca842..0737c465fed2 100644 --- a/ProcessHacker/dbgcon.c +++ b/ProcessHacker/dbgcon.c @@ -670,25 +670,14 @@ NTSTATUS PhpDebugConsoleThreadStart( PhInitializeAutoPool(&autoPool); DebugConsoleSymbolProvider = PhCreateSymbolProvider(NtCurrentProcessId()); - - { - WCHAR buffer[512]; - UNICODE_STRING name = RTL_CONSTANT_STRING(L"_NT_SYMBOL_PATH"); - UNICODE_STRING var; - PPH_STRING newSearchPath; - - RtlInitEmptyUnicodeString(&var, buffer, sizeof(buffer)); - - if (!NT_SUCCESS(RtlQueryEnvironmentVariable_U(NULL, &name, &var))) - buffer[0] = 0; - - newSearchPath = PhFormatString(L"%s;%s", buffer, PhApplicationDirectory->Buffer); - PhSetSearchPathSymbolProvider(DebugConsoleSymbolProvider, newSearchPath->Buffer); - PhDereferenceObject(newSearchPath); - } - - PhEnumGenericModules(NtCurrentProcessId(), NtCurrentProcess(), - 0, PhpLoadCurrentProcessSymbolsCallback, DebugConsoleSymbolProvider); + PhLoadSymbolProviderOptions(DebugConsoleSymbolProvider); + PhEnumGenericModules( + NtCurrentProcessId(), + NtCurrentProcess(), + 0, + PhpLoadCurrentProcessSymbolsCallback, + DebugConsoleSymbolProvider + ); #ifdef DEBUG PhInitializeQueuedLock(&NewObjectListLock); From db118b735ffb0d414d26b70a2b17975abe94f4db Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 3 Jul 2018 17:28:55 +1000 Subject: [PATCH 1082/2058] Fix build --- plugins/ToolStatus/filter.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/plugins/ToolStatus/filter.c b/plugins/ToolStatus/filter.c index aa7d5f536be2..a82218228d1b 100644 --- a/plugins/ToolStatus/filter.c +++ b/plugins/ToolStatus/filter.c @@ -109,11 +109,11 @@ BOOLEAN ProcessTreeFilterCallback( return TRUE; } - if (!PhIsNullOrEmptyString(processNode->ProcessItem->UserName)) - { - if (WordMatchStringRef(&processNode->ProcessItem->UserName->sr)) - return TRUE; - } + //if (!PhIsNullOrEmptyString(processNode->ProcessItem->UserName)) + //{ + // if (WordMatchStringRef(&processNode->ProcessItem->UserName->sr)) + // return TRUE; + //} if (processNode->ProcessItem->IntegrityString) { From b8e0f890108ed87afdd20d27dfc91eb9a034b664 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 3 Jul 2018 17:49:45 +1000 Subject: [PATCH 1083/2058] SetupTool: Update to latest phlib --- tools/CustomSetupTool/CustomSetupTool/install.c | 2 -- tools/CustomSetupTool/CustomSetupTool/main.c | 3 +-- tools/CustomSetupTool/CustomSetupTool/update.c | 2 -- 3 files changed, 1 insertion(+), 6 deletions(-) diff --git a/tools/CustomSetupTool/CustomSetupTool/install.c b/tools/CustomSetupTool/CustomSetupTool/install.c index 63a1857d63c8..e3c279026340 100644 --- a/tools/CustomSetupTool/CustomSetupTool/install.c +++ b/tools/CustomSetupTool/CustomSetupTool/install.c @@ -72,8 +72,6 @@ NTSTATUS SetupProgressThread( if (Context->SetupInstallKphService) SetupStartKph(Context, TRUE); - PhClearCacheDirectory(); - PostMessage(Context->ExtractPageHandle, WM_END_SETUP, 0, 0); return STATUS_SUCCESS; diff --git a/tools/CustomSetupTool/CustomSetupTool/main.c b/tools/CustomSetupTool/CustomSetupTool/main.c index 602904f700f5..e764c9f09bc0 100644 --- a/tools/CustomSetupTool/CustomSetupTool/main.c +++ b/tools/CustomSetupTool/CustomSetupTool/main.c @@ -256,10 +256,9 @@ INT WINAPI wWinMain( { CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE); - if (!NT_SUCCESS(PhInitializePhLibEx(ULONG_MAX, Instance, 0, 0))) + if (!NT_SUCCESS(PhInitializePhLibEx(L"Process Hacker - Setup", ULONG_MAX, Instance, 0, 0))) return 1; - PhApplicationName = L"Process Hacker - Setup"; PhGuiSupportInitialization(); SetupInitializeDpi(); diff --git a/tools/CustomSetupTool/CustomSetupTool/update.c b/tools/CustomSetupTool/CustomSetupTool/update.c index 2813e29fdace..a1bd7f89fefa 100644 --- a/tools/CustomSetupTool/CustomSetupTool/update.c +++ b/tools/CustomSetupTool/CustomSetupTool/update.c @@ -55,8 +55,6 @@ NTSTATUS SetupUpdateBuild( if (!SetupExecuteProcessHacker(Context)) goto CleanupExit; - PhClearCacheDirectory(); - PostMessage(Context->DialogHandle, WM_QUIT, 0, 0); PhDereferenceObject(Context); return STATUS_SUCCESS; From dab897adbf1b750d1b3bfc092fdea14f1d7627fd Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 4 Jul 2018 14:10:43 +1000 Subject: [PATCH 1084/2058] Update handle properties layout --- ProcessHacker/ProcessHacker.rc | 20 +-- ProcessHacker/hndlprp.c | 221 ++++++++++++++++++++++----------- 2 files changed, 147 insertions(+), 94 deletions(-) diff --git a/ProcessHacker/ProcessHacker.rc b/ProcessHacker/ProcessHacker.rc index ca6e672bcd94..65e6150c04f2 100644 --- a/ProcessHacker/ProcessHacker.rc +++ b/ProcessHacker/ProcessHacker.rc @@ -662,25 +662,7 @@ STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSM CAPTION "General" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN - GROUPBOX "Basic information",IDC_BASICINFORMATION,7,7,246,67 - LTEXT "Name:",IDC_STATIC,14,19,22,8 - EDITTEXT IDC_NAME,40,19,206,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER - LTEXT "Type:",IDC_STATIC,14,32,20,8 - EDITTEXT IDC_TYPE,40,32,206,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER - LTEXT "Object address:",IDC_STATIC,14,44,53,8 - EDITTEXT IDC_ADDRESS,71,44,175,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER - LTEXT "Granted access:",IDC_STATIC,14,56,54,8 - EDITTEXT IDC_GRANTED_ACCESS,71,56,175,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER - GROUPBOX "References",IDC_STATIC,7,78,119,39 - LTEXT "References:",IDC_STATIC,14,90,40,8 - LTEXT "Static",IDC_REFERENCES,58,90,41,8 - LTEXT "Handles:",IDC_STATIC,14,101,29,8 - LTEXT "Static",IDC_HANDLES,58,101,40,8 - GROUPBOX "Quota charges",IDC_STATIC,131,78,122,39 - LTEXT "Paged:",IDC_STATIC,138,89,24,8 - LTEXT "Static",IDC_PAGED,182,89,39,8 - LTEXT "Non-paged:",IDC_STATIC,138,100,39,8 - LTEXT "Static",IDC_NONPAGED,182,100,39,8 + CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_ALIGNLEFT | LVS_NOCOLUMNHEADER | WS_TABSTOP,0,2,260,179 END IDD_INFORMATION DIALOGEX 0, 0, 317, 184 diff --git a/ProcessHacker/hndlprp.c b/ProcessHacker/hndlprp.c index a5d6aecf6636..25f0ae459950 100644 --- a/ProcessHacker/hndlprp.c +++ b/ProcessHacker/hndlprp.c @@ -30,10 +30,14 @@ #include #include +#include + typedef struct _HANDLE_PROPERTIES_CONTEXT { + HWND ListViewHandle; HANDLE ProcessId; PPH_HANDLE_ITEM HandleItem; + PH_LAYOUT_MANAGER LayoutManager; } HANDLE_PROPERTIES_CONTEXT, *PHANDLE_PROPERTIES_CONTEXT; INT_PTR CALLBACK PhpHandleGeneralDlgProc( @@ -221,6 +225,129 @@ VOID PhShowHandleProperties( PhModalPropertySheet(&propSheetHeader); } +typedef enum _PHP_HANDLE_GENERAL_CATEGORY +{ + PH_HANDLE_GENERAL_CATEGORY_BASICINFO, + PH_HANDLE_GENERAL_CATEGORY_REFERENCES, + PH_HANDLE_GENERAL_CATEGORY_QUOTA +} PHP_HANDLE_GENERAL_CATEGORY; + +typedef enum _PHP_HANDLE_GENERAL_INDEX +{ + PH_HANDLE_GENERAL_INDEX_NAME, + PH_HANDLE_GENERAL_INDEX_TYPE, + PH_HANDLE_GENERAL_INDEX_OBJECT, + PH_HANDLE_GENERAL_INDEX_ACCESSMASK, + PH_HANDLE_GENERAL_INDEX_REFERENCES, + PH_HANDLE_GENERAL_INDEX_HANDLES, + PH_HANDLE_GENERAL_INDEX_PAGED, + PH_HANDLE_GENERAL_INDEX_NONPAGED +} PHP_PROCESS_STATISTICS_INDEX; + +VOID PhpUpdateHandleGeneralListViewGroups( + _In_ HWND ListViewHandle + ) +{ + ListView_EnableGroupView(ListViewHandle, TRUE); + PhAddListViewGroup(ListViewHandle, PH_HANDLE_GENERAL_CATEGORY_BASICINFO, L"Basic information"); + PhAddListViewGroup(ListViewHandle, PH_HANDLE_GENERAL_CATEGORY_REFERENCES, L"References"); + PhAddListViewGroup(ListViewHandle, PH_HANDLE_GENERAL_CATEGORY_QUOTA, L"Quota charges"); + PhAddListViewGroupItem(ListViewHandle, PH_HANDLE_GENERAL_CATEGORY_BASICINFO, PH_HANDLE_GENERAL_INDEX_NAME, L"Name", NULL); + PhAddListViewGroupItem(ListViewHandle, PH_HANDLE_GENERAL_CATEGORY_BASICINFO, PH_HANDLE_GENERAL_INDEX_TYPE, L"Type", NULL); + PhAddListViewGroupItem(ListViewHandle, PH_HANDLE_GENERAL_CATEGORY_BASICINFO, PH_HANDLE_GENERAL_INDEX_OBJECT, L"Object address", NULL); + PhAddListViewGroupItem(ListViewHandle, PH_HANDLE_GENERAL_CATEGORY_BASICINFO, PH_HANDLE_GENERAL_INDEX_ACCESSMASK, L"Granted access", NULL); + PhAddListViewGroupItem(ListViewHandle, PH_HANDLE_GENERAL_CATEGORY_REFERENCES, PH_HANDLE_GENERAL_INDEX_REFERENCES, L"References", NULL); + PhAddListViewGroupItem(ListViewHandle, PH_HANDLE_GENERAL_CATEGORY_REFERENCES, PH_HANDLE_GENERAL_INDEX_HANDLES, L"Handles", NULL); + PhAddListViewGroupItem(ListViewHandle, PH_HANDLE_GENERAL_CATEGORY_QUOTA, PH_HANDLE_GENERAL_INDEX_PAGED, L"Paged", NULL); + PhAddListViewGroupItem(ListViewHandle, PH_HANDLE_GENERAL_CATEGORY_QUOTA, PH_HANDLE_GENERAL_INDEX_NONPAGED, L"Virtual size", NULL); +} + +VOID PhpUpdateHandleGeneral( + _In_ PHANDLE_PROPERTIES_CONTEXT Context + ) +{ + HANDLE processHandle; + PPH_ACCESS_ENTRY accessEntries; + ULONG numberOfAccessEntries; + OBJECT_BASIC_INFORMATION basicInfo; + WCHAR string[PH_PTR_STR_LEN]; + + PhSetListViewSubItem(Context->ListViewHandle, PH_HANDLE_GENERAL_INDEX_NAME, 1, PhGetStringOrEmpty(Context->HandleItem->BestObjectName)); + PhSetListViewSubItem(Context->ListViewHandle, PH_HANDLE_GENERAL_INDEX_TYPE, 1, PhGetStringOrEmpty(Context->HandleItem->TypeName)); + PhSetListViewSubItem(Context->ListViewHandle, PH_HANDLE_GENERAL_INDEX_OBJECT, 1, Context->HandleItem->ObjectString); + + if (PhGetAccessEntries( + PhGetStringOrEmpty(Context->HandleItem->TypeName), + &accessEntries, + &numberOfAccessEntries + )) + { + PPH_STRING accessString; + PPH_STRING grantedAccessString; + + accessString = PH_AUTO(PhGetAccessString( + Context->HandleItem->GrantedAccess, + accessEntries, + numberOfAccessEntries + )); + + if (accessString->Length != 0) + { + grantedAccessString = PH_AUTO(PhFormatString( + L"0x%x (%s)", + Context->HandleItem->GrantedAccess, + accessString->Buffer + )); + + PhSetListViewSubItem(Context->ListViewHandle, PH_HANDLE_GENERAL_INDEX_ACCESSMASK, 1, grantedAccessString->Buffer); + } + else + { + PhPrintPointer(string, UlongToPtr(Context->HandleItem->GrantedAccess)); + PhSetListViewSubItem(Context->ListViewHandle, PH_HANDLE_GENERAL_INDEX_ACCESSMASK, 1, string); + } + + PhFree(accessEntries); + } + else + { + PhPrintPointer(string, UlongToPtr(Context->HandleItem->GrantedAccess)); + PhSetListViewSubItem(Context->ListViewHandle, PH_HANDLE_GENERAL_INDEX_ACCESSMASK, 1, string); + } + + if (NT_SUCCESS(PhOpenProcess( + &processHandle, + PROCESS_DUP_HANDLE, + Context->ProcessId + ))) + { + if (NT_SUCCESS(PhGetHandleInformation( + processHandle, + Context->HandleItem->Handle, + ULONG_MAX, + &basicInfo, + NULL, + NULL, + NULL + ))) + { + PhPrintUInt32(string, basicInfo.PointerCount); + PhSetListViewSubItem(Context->ListViewHandle, PH_HANDLE_GENERAL_INDEX_REFERENCES, 1, string); + + PhPrintUInt32(string, basicInfo.HandleCount); + PhSetListViewSubItem(Context->ListViewHandle, PH_HANDLE_GENERAL_INDEX_HANDLES, 1, string); + + PhPrintUInt32(string, basicInfo.PagedPoolCharge); + PhSetListViewSubItem(Context->ListViewHandle, PH_HANDLE_GENERAL_INDEX_PAGED, 1, string); + + PhPrintUInt32(string, basicInfo.NonPagedPoolCharge); + PhSetListViewSubItem(Context->ListViewHandle, PH_HANDLE_GENERAL_INDEX_NONPAGED, 1, string); + } + + NtClose(processHandle); + } +} + INT_PTR CALLBACK PhpHandleGeneralDlgProc( _In_ HWND hwndDlg, _In_ UINT uMsg, @@ -258,84 +385,20 @@ INT_PTR CALLBACK PhpHandleGeneralDlgProc( // HACK PhCenterWindow(GetParent(hwndDlg), GetParent(GetParent(hwndDlg))); - PhSetDialogItemText(hwndDlg, IDC_NAME, PhGetStringOrEmpty(context->HandleItem->BestObjectName)); - PhSetDialogItemText(hwndDlg, IDC_TYPE, PhGetStringOrEmpty(context->HandleItem->TypeName)); - PhSetDialogItemText(hwndDlg, IDC_ADDRESS, context->HandleItem->ObjectString); - - if (PhGetAccessEntries( - PhGetStringOrEmpty(context->HandleItem->TypeName), - &accessEntries, - &numberOfAccessEntries - )) - { - PPH_STRING accessString; - PPH_STRING grantedAccessString; + context->ListViewHandle = GetDlgItem(hwndDlg, IDC_LIST); + PhSetListViewStyle(context->ListViewHandle, FALSE, TRUE); + PhSetControlTheme(context->ListViewHandle, L"explorer"); + PhAddListViewColumn(context->ListViewHandle, 0, 0, 0, LVCFMT_LEFT, 120, L"Name"); + PhAddListViewColumn(context->ListViewHandle, 1, 1, 1, LVCFMT_LEFT, 250, L"Value"); + PhSetExtendedListView(context->ListViewHandle); - accessString = PH_AUTO(PhGetAccessString( - context->HandleItem->GrantedAccess, - accessEntries, - numberOfAccessEntries - )); + PhInitializeLayoutManager(&context->LayoutManager, hwndDlg); + PhAddLayoutItem(&context->LayoutManager, context->ListViewHandle, NULL, PH_ANCHOR_ALL); - if (accessString->Length != 0) - { - grantedAccessString = PH_AUTO(PhFormatString( - L"0x%x (%s)", - context->HandleItem->GrantedAccess, - accessString->Buffer - )); - PhSetDialogItemText(hwndDlg, IDC_GRANTED_ACCESS, grantedAccessString->Buffer); - } - else - { - WCHAR grantedAccessString[PH_PTR_STR_LEN]; - PhPrintPointer(grantedAccessString, UlongToPtr(context->HandleItem->GrantedAccess)); - PhSetDialogItemText(hwndDlg, IDC_GRANTED_ACCESS, grantedAccessString); - } + PhpUpdateHandleGeneralListViewGroups(context->ListViewHandle); + PhpUpdateHandleGeneral(context); - PhFree(accessEntries); - } - else - { - WCHAR grantedAccessString[PH_PTR_STR_LEN]; - PhPrintPointer(grantedAccessString, UlongToPtr(context->HandleItem->GrantedAccess)); - PhSetDialogItemText(hwndDlg, IDC_GRANTED_ACCESS, grantedAccessString); - } - - if (NT_SUCCESS(PhOpenProcess( - &processHandle, - PROCESS_DUP_HANDLE, - context->ProcessId - ))) - { - if (NT_SUCCESS(PhGetHandleInformation( - processHandle, - context->HandleItem->Handle, - ULONG_MAX, - &basicInfo, - NULL, - NULL, - NULL - ))) - { - PhSetDialogItemValue(hwndDlg, IDC_REFERENCES, basicInfo.PointerCount, FALSE); - PhSetDialogItemValue(hwndDlg, IDC_HANDLES, basicInfo.HandleCount, FALSE); - PhSetDialogItemValue(hwndDlg, IDC_PAGED, basicInfo.PagedPoolCharge, FALSE); - PhSetDialogItemValue(hwndDlg, IDC_NONPAGED, basicInfo.NonPagedPoolCharge, FALSE); - - haveBasicInfo = TRUE; - } - - NtClose(processHandle); - } - - if (!haveBasicInfo) - { - PhSetDialogItemText(hwndDlg, IDC_REFERENCES, L"Unknown"); - PhSetDialogItemText(hwndDlg, IDC_HANDLES, L"Unknown"); - PhSetDialogItemText(hwndDlg, IDC_PAGED, L"Unknown"); - PhSetDialogItemText(hwndDlg, IDC_NONPAGED, L"Unknown"); - } + EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); } break; case WM_DESTROY: @@ -343,6 +406,12 @@ INT_PTR CALLBACK PhpHandleGeneralDlgProc( PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); } break; + case WM_SIZE: + { + PhLayoutManagerLayout(&context->LayoutManager); + ExtendedListView_SetColumnWidth(context->ListViewHandle, 0, ELVSCW_AUTOSIZE_REMAININGSPACE); + } + break; case WM_NOTIFY: { LPNMHDR header = (LPNMHDR)lParam; @@ -359,5 +428,7 @@ INT_PTR CALLBACK PhpHandleGeneralDlgProc( break; } + REFLECT_MESSAGE_DLG(hwndDlg, context->ListViewHandle, uMsg, wParam, lParam); + return FALSE; } From 47b9827f2f07932be01131dbcbc07eaed4cf00c9 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 4 Jul 2018 14:32:13 +1000 Subject: [PATCH 1085/2058] Fix build --- ProcessHacker/hndlprp.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/ProcessHacker/hndlprp.c b/ProcessHacker/hndlprp.c index 25f0ae459950..8d9f3b394428 100644 --- a/ProcessHacker/hndlprp.c +++ b/ProcessHacker/hndlprp.c @@ -376,12 +376,6 @@ INT_PTR CALLBACK PhpHandleGeneralDlgProc( { case WM_INITDIALOG: { - PPH_ACCESS_ENTRY accessEntries; - ULONG numberOfAccessEntries; - HANDLE processHandle; - OBJECT_BASIC_INFORMATION basicInfo; - BOOLEAN haveBasicInfo = FALSE; - // HACK PhCenterWindow(GetParent(hwndDlg), GetParent(GetParent(hwndDlg))); From cbb5f3b8ca141a4370715496bc219d54a0923aad Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 4 Jul 2018 14:44:59 +1000 Subject: [PATCH 1086/2058] Update process environment tab layout --- ProcessHacker/ProcessHacker.rc | 26 +- ProcessHacker/include/procprpp.h | 36 +- ProcessHacker/prpgenv.c | 1426 +++++++++++++++++++++++------- ProcessHacker/resource.h | 4 - ProcessHacker/settings.c | 4 +- 5 files changed, 1152 insertions(+), 344 deletions(-) diff --git a/ProcessHacker/ProcessHacker.rc b/ProcessHacker/ProcessHacker.rc index 65e6150c04f2..95756d29683f 100644 --- a/ProcessHacker/ProcessHacker.rc +++ b/ProcessHacker/ProcessHacker.rc @@ -472,16 +472,6 @@ BEGIN END END -IDR_ENVIRONMENT MENU -BEGIN - POPUP "Environment" - BEGIN - MENUITEM "&Edit", ID_ENVIRONMENT_EDIT - MENUITEM "&Delete\aDel", ID_ENVIRONMENT_DELETE - MENUITEM "&Copy\aCtrl+C", ID_ENVIRONMENT_COPY - END -END - ///////////////////////////////////////////////////////////////////////////// // @@ -586,10 +576,10 @@ STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSM CAPTION "Environment" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN - CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,7,246,227 - PUSHBUTTON "New...",IDC_NEW,93,239,50,14 - PUSHBUTTON "Edit...",IDC_EDIT,148,239,50,14 - PUSHBUTTON "Delete",IDC_DELETE,203,239,50,14 + CONTROL "",IDC_LIST,"PhTreeNew",WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP | 0xa,2,19,256,239,WS_EX_CLIENTEDGE + EDITTEXT IDC_SEARCH,114,3,144,14,ES_AUTOHSCROLL + PUSHBUTTON "Refresh",IDC_REFRESH,53,2,50,14 + PUSHBUTTON "Options",IDC_OPTIONS,2,2,50,14 END IDD_THRDSTACK DIALOGEX 0, 0, 273, 228 @@ -1843,10 +1833,10 @@ BEGIN IDD_PROCENVIRONMENT, DIALOG BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 253 - TOPMARGIN, 7 - BOTTOMMARGIN, 253 + LEFTMARGIN, 2 + RIGHTMARGIN, 258 + TOPMARGIN, 2 + BOTTOMMARGIN, 258 END IDD_THRDSTACK, DIALOG diff --git a/ProcessHacker/include/procprpp.h b/ProcessHacker/include/procprpp.h index 9c1846441c34..e9cd1484c987 100644 --- a/ProcessHacker/include/procprpp.h +++ b/ProcessHacker/include/procprpp.h @@ -356,7 +356,41 @@ typedef struct _PH_ENVIRONMENT_ITEM typedef struct _PH_ENVIRONMENT_CONTEXT { - HWND ListViewHandle; + HWND WindowHandle; + HWND TreeNewHandle; + HWND SearchWindowHandle; + + PPH_PROCESS_ITEM ProcessItem; + PPH_STRING SearchboxText; + PPH_STRING StatusMessage; + + PPH_LIST NodeList; + PPH_LIST NodeRootList; + PPH_HASHTABLE NodeHashtable; + PPH_TN_FILTER_ENTRY TreeFilterEntry; + ULONG TreeNewSortColumn; + PH_TN_FILTER_SUPPORT TreeFilterSupport; + PH_SORT_ORDER TreeNewSortOrder; + PH_CM_MANAGER Cm; + + union + { + ULONG Flags; + struct + { + ULONG EnableStateHighlighting : 1; + ULONG HideProcessEnvironment : 1; + ULONG HideUserEnvironment : 1; + ULONG HideSystemEnvironment : 1; + ULONG HighlightProcessEnvironment : 1; + ULONG HighlightUserEnvironment : 1; + ULONG HighlightSystemEnvironment : 1; + ULONG Spare : 25; + }; + }; + + PVOID SystemDefaultEnvironment; + PVOID UserDefaultEnvironment; PH_ARRAY Items; } PH_ENVIRONMENT_CONTEXT, *PPH_ENVIRONMENT_CONTEXT; diff --git a/ProcessHacker/prpgenv.c b/ProcessHacker/prpgenv.c index 0efd9a49eda6..25073a435525 100644 --- a/ProcessHacker/prpgenv.c +++ b/ProcessHacker/prpgenv.c @@ -3,6 +3,7 @@ * Process properties: Environment page * * Copyright (C) 2009-2016 wj32 + * Copyright (C) 2018 dmex * * This file is part of Process Hacker. * @@ -21,23 +22,96 @@ */ #include -#include -#include #include #include #include + +#include +#include +#include #include +#include +#include #include #include +typedef enum _ENVIRONMENT_TREE_MENU_ITEM +{ + ENVIRONMENT_TREE_MENU_ITEM_HIDE_PROCESS_TYPE = 1, + ENVIRONMENT_TREE_MENU_ITEM_HIDE_USER_TYPE, + ENVIRONMENT_TREE_MENU_ITEM_HIDE_SYSTEM_TYPE, + ENVIRONMENT_TREE_MENU_ITEM_HIGHLIGHT_PROCESS_TYPE, + ENVIRONMENT_TREE_MENU_ITEM_HIGHLIGHT_USER_TYPE, + ENVIRONMENT_TREE_MENU_ITEM_HIGHLIGHT_SYSTEM_TYPE, + ENVIRONMENT_TREE_MENU_ITEM_NEW_ENVIRONMENT_VARIABLE, + ENVIRONMENT_TREE_MENU_ITEM_MAXIMUM +} ENVIRONMENT_TREE_MENU_ITEM; + +typedef enum _ENVIRONMENT_TREE_COLUMN_MENU_ITEM +{ + ENVIRONMENT_TREE_COLUMN_MENU_ITEM_EDIT = 1, + ENVIRONMENT_TREE_COLUMN_MENU_ITEM_DELETE, + ENVIRONMENT_TREE_COLUMN_MENU_ITEM_COPY, + ENVIRONMENT_TREE_COLUMN_MENU_ITEM_MAXIMUM +} ENVIRONMENT_TREE_COLUMN_MENU_ITEM; + +typedef enum _ENVIRONMENT_TREE_COLUMN_ITEM_NAME +{ + ENVIRONMENT_COLUMN_ITEM_NAME, + ENVIRONMENT_COLUMN_ITEM_VALUE, + ENVIRONMENT_COLUMN_ITEM_MAXIMUM +} ENVIRONMENT_TREE_COLUMN_ITEM_NAME; + +typedef enum _PROCESS_ENVIRONMENT_TREENODE_TYPE +{ + PROCESS_ENVIRONMENT_TREENODE_TYPE_GROUP, + PROCESS_ENVIRONMENT_TREENODE_TYPE_PROCESS, + PROCESS_ENVIRONMENT_TREENODE_TYPE_USER, + PROCESS_ENVIRONMENT_TREENODE_TYPE_SYSTEM +} PROCESS_ENVIRONMENT_TREENODE_TYPE; + +typedef struct _PHP_PROCESS_ENVIRONMENT_TREENODE +{ + PH_TREENEW_NODE Node; + PH_STRINGREF TextCache[ENVIRONMENT_COLUMN_ITEM_MAXIMUM]; + + struct _PHP_PROCESS_ENVIRONMENT_TREENODE* Parent; + PPH_LIST Children; + BOOLEAN HasChildren; + + ULONG Id; + PROCESS_ENVIRONMENT_TREENODE_TYPE Type; + PPH_STRING NameText; + PPH_STRING ValueText; +} PHP_PROCESS_ENVIRONMENT_TREENODE, *PPHP_PROCESS_ENVIRONMENT_TREENODE; + +PPHP_PROCESS_ENVIRONMENT_TREENODE PhpAddEnvironmentChildNode( + _Inout_ PPH_ENVIRONMENT_CONTEXT Context, + _In_opt_ PPHP_PROCESS_ENVIRONMENT_TREENODE ParentNode, + _In_opt_ PPH_STRING Name, + _In_opt_ PPH_STRING Value + ); + +PPHP_PROCESS_ENVIRONMENT_TREENODE PhpFindEnvironmentNode( + _In_ PPH_ENVIRONMENT_CONTEXT Context, + _In_ PWSTR KeyPath + ); + +VOID PhpClearEnvironmentTree( + _In_ PPH_ENVIRONMENT_CONTEXT Context + ); + +PPHP_PROCESS_ENVIRONMENT_TREENODE PhpGetSelectedEnvironmentNode( + _In_ PPH_ENVIRONMENT_CONTEXT Context + ); + typedef struct _EDIT_ENV_DIALOG_CONTEXT { PPH_PROCESS_ITEM ProcessItem; PWSTR Name; PWSTR Value; BOOLEAN Refresh; - PH_LAYOUT_MANAGER LayoutManager; RECT MinimumSize; } EDIT_ENV_DIALOG_CONTEXT, *PEDIT_ENV_DIALOG_CONTEXT; @@ -57,7 +131,7 @@ INT_PTR CALLBACK PhpEditEnvDlgProc( _In_ LPARAM lParam ); -static VOID PhpClearEnvironmentItems( +VOID PhpClearEnvironmentItems( _Inout_ PPH_ENVIRONMENT_CONTEXT Context ) { @@ -74,24 +148,37 @@ static VOID PhpClearEnvironmentItems( PhClearArray(&Context->Items); } -static VOID PhpRefreshEnvironment( +VOID PhpRefreshEnvironmentList( _In_ HWND hwndDlg, _Inout_ PPH_ENVIRONMENT_CONTEXT Context, _In_ PPH_PROCESS_ITEM ProcessItem ) { - PVOID selectedIndex; HANDLE processHandle; PVOID environment; ULONG environmentLength; ULONG enumerationKey; PH_ENVIRONMENT_VARIABLE variable; + PPH_ENVIRONMENT_ITEM item; + PPHP_PROCESS_ENVIRONMENT_TREENODE processRootNode; + PPHP_PROCESS_ENVIRONMENT_TREENODE userRootNode; + PPHP_PROCESS_ENVIRONMENT_TREENODE systemRootNode; + ULONG i; - ExtendedListView_SetRedraw(Context->ListViewHandle, FALSE); + PhpClearEnvironmentTree(Context); + processRootNode = PhpAddEnvironmentChildNode(Context, NULL, PhaCreateString(L"Process"), NULL); + userRootNode = PhpAddEnvironmentChildNode(Context, NULL, PhaCreateString(L"User"), NULL); + systemRootNode = PhpAddEnvironmentChildNode(Context, NULL, PhaCreateString(L"System"), NULL); - selectedIndex = PhGetSelectedListViewItemParam(Context->ListViewHandle); - ListView_DeleteAllItems(Context->ListViewHandle); - PhpClearEnvironmentItems(Context); + if (DestroyEnvironmentBlock && Context->SystemDefaultEnvironment) + DestroyEnvironmentBlock(Context->SystemDefaultEnvironment); + if (DestroyEnvironmentBlock && Context->UserDefaultEnvironment) + DestroyEnvironmentBlock(Context->UserDefaultEnvironment); + + if (CreateEnvironmentBlock) + CreateEnvironmentBlock(&Context->SystemDefaultEnvironment, NULL, FALSE); + if (CreateEnvironmentBlock) + CreateEnvironmentBlock(&Context->UserDefaultEnvironment, PhGetOwnTokenAttributes().TokenHandle, FALSE); if (NT_SUCCESS(PhOpenProcess( &processHandle, @@ -99,9 +186,7 @@ static VOID PhpRefreshEnvironment( ProcessItem->ProcessId ))) { - ULONG flags; - - flags = 0; + ULONG flags = 0; #ifdef _WIN64 if (ProcessItem->IsWow64) @@ -120,20 +205,14 @@ static VOID PhpRefreshEnvironment( while (PhEnumProcessEnvironmentVariables(environment, environmentLength, &enumerationKey, &variable)) { PH_ENVIRONMENT_ITEM item; - INT lvItemIndex; // Don't display pairs with no name. if (variable.Name.Length == 0) continue; - // The strings are not guaranteed to be null-terminated, so we need to create some temporary strings. item.Name = PhCreateString2(&variable.Name); item.Value = PhCreateString2(&variable.Value); - lvItemIndex = PhAddListViewItem(Context->ListViewHandle, MAXINT, item.Name->Buffer, - UlongToPtr((ULONG)Context->Items.Count + 1)); - PhSetListViewSubItem(Context->ListViewHandle, lvItemIndex, 1, item.Value->Buffer); - PhAddItemArray(&Context->Items, &item); } @@ -143,319 +222,65 @@ static VOID PhpRefreshEnvironment( NtClose(processHandle); } - if (selectedIndex) + for (i = 0; i < Context->Items.Count; i++) { - ListView_SetItemState(Context->ListViewHandle, PtrToUlong(selectedIndex) - 1, - LVIS_FOCUSED | LVIS_SELECTED, LVIS_FOCUSED | LVIS_SELECTED); - ListView_EnsureVisible(Context->ListViewHandle, PtrToUlong(selectedIndex) - 1, FALSE); - } - - ExtendedListView_SetRedraw(Context->ListViewHandle, TRUE); -} - -INT_PTR CALLBACK PhpProcessEnvironmentDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - LPPROPSHEETPAGE propSheetPage; - PPH_PROCESS_PROPPAGECONTEXT propPageContext; - PPH_PROCESS_ITEM processItem; - PPH_ENVIRONMENT_CONTEXT environmentContext; - HWND lvHandle; + UNICODE_STRING variableNameUs; + UNICODE_STRING variableValueUs; + PROCESS_ENVIRONMENT_TREENODE_TYPE variableType; - if (PhpPropPageDlgProcHeader(hwndDlg, uMsg, lParam, &propSheetPage, &propPageContext, &processItem)) - { - environmentContext = propPageContext->Context; + item = PhItemArray(&Context->Items, i); - if (environmentContext) - lvHandle = environmentContext->ListViewHandle; - } - else - { - return FALSE; - } + PhStringRefToUnicodeString(&item->Name->sr, &variableNameUs); + RtlInitUnicodeString(&variableValueUs, UNICODE_NULL); - switch (uMsg) - { - case WM_INITDIALOG: + if (RtlQueryEnvironmentVariable_U( + Context->SystemDefaultEnvironment, + &variableNameUs, + &variableValueUs + ) == STATUS_BUFFER_TOO_SMALL) { - environmentContext = propPageContext->Context = PhAllocate(sizeof(PH_ENVIRONMENT_CONTEXT)); - memset(environmentContext, 0, sizeof(PH_ENVIRONMENT_CONTEXT)); - - environmentContext->ListViewHandle = lvHandle = GetDlgItem(hwndDlg, IDC_LIST); - PhInitializeArray(&environmentContext->Items, sizeof(PH_ENVIRONMENT_ITEM), 100); - - PhSetListViewStyle(lvHandle, TRUE, TRUE); - PhSetControlTheme(lvHandle, L"explorer"); - PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 140, L"Name"); - PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 200, L"Value"); - - PhSetExtendedListView(lvHandle); - PhLoadListViewColumnsFromSetting(L"EnvironmentListViewColumns", lvHandle); - - EnableWindow(GetDlgItem(hwndDlg, IDC_EDIT), FALSE); - EnableWindow(GetDlgItem(hwndDlg, IDC_DELETE), FALSE); - - EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); - - PhpRefreshEnvironment(hwndDlg, environmentContext, processItem); + variableType = PROCESS_ENVIRONMENT_TREENODE_TYPE_SYSTEM; } - break; - case WM_DESTROY: + else if (RtlQueryEnvironmentVariable_U( + Context->UserDefaultEnvironment, + &variableNameUs, + &variableValueUs + ) == STATUS_BUFFER_TOO_SMALL) { - PhSaveListViewColumnsToSetting(L"EnvironmentListViewColumns", lvHandle); - - PhpClearEnvironmentItems(environmentContext); - PhDeleteArray(&environmentContext->Items); - - PhFree(environmentContext); - - PhpPropPageDlgProcDestroy(hwndDlg); + variableType = PROCESS_ENVIRONMENT_TREENODE_TYPE_USER; } - break; - case WM_SHOWWINDOW: + else { - if (!propPageContext->LayoutInitialized) - { - PPH_LAYOUT_ITEM dialogItem; - - dialogItem = PhAddPropPageLayoutItem(hwndDlg, hwndDlg, - PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL); - PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_LIST), - dialogItem, PH_ANCHOR_ALL); - PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_NEW), - dialogItem, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); - PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_EDIT), - dialogItem, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); - PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_DELETE), - dialogItem, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); - - PhDoPropPageLayout(hwndDlg); - - propPageContext->LayoutInitialized = TRUE; - } + variableType = PROCESS_ENVIRONMENT_TREENODE_TYPE_PROCESS; } - break; - case WM_COMMAND: + + switch (variableType) { - switch (GET_WM_COMMAND_ID(wParam, lParam)) + case PROCESS_ENVIRONMENT_TREENODE_TYPE_PROCESS: { - case IDC_NEW: - { - BOOLEAN refresh; - - if (PhGetIntegerSetting(L"EnableWarnings") && !PhShowConfirmMessage( - hwndDlg, - L"create", - L"environment variable", - L"Some programs may restrict access or ban your account when creating new environment variable(s).", - FALSE - )) - { - break; - } - - if (PhpShowEditEnvDialog(hwndDlg, processItem, L"", NULL, &refresh) == IDOK && - refresh) - { - PhpRefreshEnvironment(hwndDlg, environmentContext, processItem); - } - } - break; - case IDC_EDIT: - case ID_ENVIRONMENT_EDIT: - { - PVOID index = PhGetSelectedListViewItemParam(lvHandle); - - if (index) - { - PPH_ENVIRONMENT_ITEM item = PhItemArray(&environmentContext->Items, PtrToUlong(index) - 1); - BOOLEAN refresh; - - if (PhGetIntegerSetting(L"EnableWarnings") && !PhShowConfirmMessage( - hwndDlg, - L"edit", - L"the selected environment variable", - L"Some programs may restrict access or ban your account when editing the environment variable(s) of the process.", - FALSE - )) - { - break; - } - - if (PhpShowEditEnvDialog(hwndDlg, processItem, item->Name->Buffer, - item->Value->Buffer, &refresh) == IDOK && refresh) - { - PhpRefreshEnvironment(hwndDlg, environmentContext, processItem); - } - } - } - break; - case IDC_DELETE: - case ID_ENVIRONMENT_DELETE: - { - NTSTATUS status; - PVOID *indices; - ULONG numberOfIndices; - HANDLE processHandle; - LARGE_INTEGER timeout; - ULONG i; - PPH_ENVIRONMENT_ITEM item; - - PhGetSelectedListViewItemParams(lvHandle, &indices, &numberOfIndices); - - if (numberOfIndices != 0) - { - if (PhGetIntegerSetting(L"EnableWarnings") && !PhShowConfirmMessage( - hwndDlg, - L"delete", - numberOfIndices != 1 ? L"the selected environment variables" : L"the selected environment variable", - L"Some programs may restrict access or ban your account when editing the environment variable(s) of the process.", - FALSE - )) - { - break; - } - - if (NT_SUCCESS(status = PhOpenProcess( - &processHandle, - ProcessQueryAccess | PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | - PROCESS_VM_READ | PROCESS_VM_WRITE, - processItem->ProcessId - ))) - { - timeout.QuadPart = -(LONGLONG)UInt32x32To64(10, PH_TIMEOUT_SEC); - - for (i = 0; i < numberOfIndices; i++) - { - item = PhItemArray(&environmentContext->Items, PtrToUlong(indices[i]) - 1); - status = PhSetEnvironmentVariableRemote(processHandle, &item->Name->sr, NULL, &timeout); - } - - NtClose(processHandle); - - PhpRefreshEnvironment(hwndDlg, environmentContext, processItem); - - if (!NT_SUCCESS(status)) - { - PhShowStatus(hwndDlg, L"Unable to delete the environment variable.", status, 0); - } - else if (status == STATUS_TIMEOUT) - { - PhShowStatus(hwndDlg, L"Unable to delete the environment variable.", 0, WAIT_TIMEOUT); - } - } - else - { - PhShowStatus(hwndDlg, L"Unable to open the process.", status, 0); - } - } - - PhFree(indices); - } - break; - case ID_ENVIRONMENT_COPY: - { - PhCopyListView(lvHandle); - } - break; + PPHP_PROCESS_ENVIRONMENT_TREENODE node = PhpAddEnvironmentChildNode(Context, processRootNode, item->Name, item->Value); + node->Id = i; + node->Type = variableType; } - } - break; - case WM_NOTIFY: - { - LPNMHDR header = (LPNMHDR)lParam; - - PhHandleListViewNotifyBehaviors(lParam, lvHandle, PH_LIST_VIEW_DEFAULT_1_BEHAVIORS); - - switch (header->code) + break; + case PROCESS_ENVIRONMENT_TREENODE_TYPE_USER: { - case LVN_ITEMCHANGED: - { - if (header->hwndFrom == lvHandle) - { - ULONG selectedCount; - - selectedCount = ListView_GetSelectedCount(lvHandle); - EnableWindow(GetDlgItem(hwndDlg, IDC_EDIT), selectedCount == 1); - EnableWindow(GetDlgItem(hwndDlg, IDC_DELETE), selectedCount >= 1); - } - } - break; - case NM_DBLCLK: - { - if (header->hwndFrom == lvHandle) - { - SendMessage(hwndDlg, WM_COMMAND, ID_ENVIRONMENT_EDIT, 0); - } - } - break; - case LVN_KEYDOWN: - { - if (header->hwndFrom == lvHandle) - { - LPNMLVKEYDOWN keyDown = (LPNMLVKEYDOWN)header; - - switch (keyDown->wVKey) - { - case VK_DELETE: - SendMessage(hwndDlg, WM_COMMAND, ID_ENVIRONMENT_DELETE, 0); - break; - } - } - } - break; + PPHP_PROCESS_ENVIRONMENT_TREENODE node = PhpAddEnvironmentChildNode(Context, userRootNode, item->Name, item->Value); + node->Id = i; + node->Type = variableType; } - } - break; - case WM_CONTEXTMENU: - { - if ((HWND)wParam == lvHandle) + break; + case PROCESS_ENVIRONMENT_TREENODE_TYPE_SYSTEM: { - POINT point; - PVOID *indices; - ULONG numberOfIndices; - - point.x = GET_X_LPARAM(lParam); - point.y = GET_Y_LPARAM(lParam); - - if (point.x == -1 && point.y == -1) - PhGetListViewContextMenuPoint((HWND)wParam, &point); - - PhGetSelectedListViewItemParams(lvHandle, &indices, &numberOfIndices); - - if (numberOfIndices != 0) - { - PPH_EMENU menu; - - menu = PhCreateEMenu(); - PhLoadResourceEMenuItem(menu, PhInstanceHandle, MAKEINTRESOURCE(IDR_ENVIRONMENT), 0); - PhSetFlagsEMenuItem(menu, ID_ENVIRONMENT_EDIT, PH_EMENU_DEFAULT, PH_EMENU_DEFAULT); - - if (numberOfIndices > 1) - PhEnableEMenuItem(menu, ID_ENVIRONMENT_EDIT, FALSE); - - PhShowEMenu( - menu, - hwndDlg, - PH_EMENU_SHOW_SEND_COMMAND | PH_EMENU_SHOW_LEFTRIGHT, - PH_ALIGN_LEFT | PH_ALIGN_TOP, - point.x, - point.y - ); - PhDestroyEMenu(menu); - } - - PhFree(indices); + PPHP_PROCESS_ENVIRONMENT_TREENODE node = PhpAddEnvironmentChildNode(Context, systemRootNode, item->Name, item->Value); + node->Id = i; + node->Type = variableType; } + break; } - break; } - return FALSE; + PhApplyTreeNewFilters(&Context->TreeFilterSupport); } INT_PTR CALLBACK PhpEditEnvDlgProc( @@ -495,14 +320,10 @@ INT_PTR CALLBACK PhpEditEnvDlgProc( PhCenterWindow(hwndDlg, GetParent(hwndDlg)); PhInitializeLayoutManager(&context->LayoutManager, hwndDlg); - PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_NAME), NULL, - PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); - PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_VALUE), NULL, - PH_ANCHOR_ALL); - PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDOK), NULL, - PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); - PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDCANCEL), NULL, - PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); + PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_NAME), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); + PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_VALUE), NULL, PH_ANCHOR_ALL); + PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDOK), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); + PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDCANCEL), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); PhLayoutManagerLayout(&context->LayoutManager); context->MinimumSize.left = 0; @@ -651,3 +472,968 @@ INT_PTR PhpShowEditEnvDialog( return result; } + +VOID PhpShowEnvironmentNodeContextMenu( + _In_ PPH_ENVIRONMENT_CONTEXT Context, + _In_ PPH_TREENEW_CONTEXT_MENU ContextMenuEvent + ) +{ + PPHP_PROCESS_ENVIRONMENT_TREENODE node; + PPH_EMENU menu; + PPH_EMENU_ITEM selectedItem; + + if (!(node = PhpGetSelectedEnvironmentNode(Context))) + return; + + menu = PhCreateEMenu(); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ENVIRONMENT_TREE_COLUMN_MENU_ITEM_EDIT, L"Edit", NULL, NULL), ULONG_MAX); + PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ENVIRONMENT_TREE_COLUMN_MENU_ITEM_DELETE, L"Delete", NULL, NULL), ULONG_MAX); + PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ENVIRONMENT_TREE_COLUMN_MENU_ITEM_COPY, L"&Copy", NULL, NULL), ULONG_MAX); + PhInsertCopyCellEMenuItem(menu, 3, Context->TreeNewHandle, ContextMenuEvent->Column); + + selectedItem = PhShowEMenu( + menu, + Context->WindowHandle, + PH_EMENU_SHOW_LEFTRIGHT, + PH_ALIGN_LEFT | PH_ALIGN_TOP, + ContextMenuEvent->Location.x, + ContextMenuEvent->Location.y + ); + + if (selectedItem && selectedItem->Id != -1) + { + if (!PhHandleCopyCellEMenuItem(selectedItem)) + { + switch (selectedItem->Id) + { + case ENVIRONMENT_TREE_COLUMN_MENU_ITEM_EDIT: + { + PPH_ENVIRONMENT_ITEM item = PhItemArray(&Context->Items, node->Id); + BOOLEAN refresh; + + if (PhGetIntegerSetting(L"EnableWarnings") && !PhShowConfirmMessage( + Context->WindowHandle, + L"edit", + L"the selected environment variable", + L"Some programs may restrict access or ban your account when editing the environment variable(s) of the process.", + FALSE + )) + { + break; + } + + if (PhpShowEditEnvDialog( + Context->WindowHandle, + Context->ProcessItem, + item->Name->Buffer, + item->Value->Buffer, + &refresh + ) == IDOK && refresh) + { + PhpRefreshEnvironmentList(Context->WindowHandle, Context, Context->ProcessItem); + } + } + break; + case ENVIRONMENT_TREE_COLUMN_MENU_ITEM_DELETE: + { + PPH_ENVIRONMENT_ITEM item = PhItemArray(&Context->Items, node->Id); + NTSTATUS status; + HANDLE processHandle; + + if (PhGetIntegerSetting(L"EnableWarnings") && !PhShowConfirmMessage( + Context->WindowHandle, + L"delete", + L"the selected environment variable", + L"Some programs may restrict access or ban your account when editing the environment variable(s) of the process.", + FALSE + )) + { + break; + } + + if (NT_SUCCESS(status = PhOpenProcess( + &processHandle, + ProcessQueryAccess | PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | + PROCESS_VM_READ | PROCESS_VM_WRITE, + Context->ProcessItem->ProcessId + ))) + { + LARGE_INTEGER timeout; + + timeout.QuadPart = -(LONGLONG)UInt32x32To64(10, PH_TIMEOUT_SEC); + status = PhSetEnvironmentVariableRemote( + processHandle, + &item->Name->sr, + NULL, + &timeout + ); + NtClose(processHandle); + + PhpRefreshEnvironmentList(Context->WindowHandle, Context, Context->ProcessItem); + + if (status == STATUS_TIMEOUT) + { + PhShowStatus(Context->WindowHandle, L"Unable to delete the environment variable.", 0, WAIT_TIMEOUT); + } + else if (!NT_SUCCESS(status)) + { + PhShowStatus(Context->WindowHandle, L"Unable to delete the environment variable.", status, 0); + } + } + else + { + PhShowStatus(Context->WindowHandle, L"Unable to open the process.", status, 0); + } + } + break; + case ENVIRONMENT_TREE_COLUMN_MENU_ITEM_COPY: + { + PPH_STRING text; + + text = PhGetTreeNewText(Context->TreeNewHandle, 0); + PhSetClipboardString(Context->TreeNewHandle, &text->sr); + PhDereferenceObject(text); + } + break; + } + } + } + + PhDestroyEMenu(menu); +} + +static BOOLEAN PhpWordMatchEnvironmentStringRef( + _In_ PPH_STRINGREF SearchText, + _In_ PPH_STRINGREF Text + ) +{ + PH_STRINGREF part; + PH_STRINGREF remainingPart; + + remainingPart = *SearchText; + + while (remainingPart.Length) + { + PhSplitStringRefAtChar(&remainingPart, '|', &part, &remainingPart); + + if (part.Length) + { + if (PhFindStringInStringRef(Text, &part, TRUE) != -1) + return TRUE; + } + } + + return FALSE; +} + +static BOOLEAN PhpWordMatchEnvironmentStringZ( + _In_ PPH_STRING SearchText, + _In_ PWSTR Text + ) +{ + PH_STRINGREF text; + + PhInitializeStringRef(&text, Text); + + return PhpWordMatchEnvironmentStringRef(&SearchText->sr, &text); +} + +VOID PhLoadSettingsEnvironmentList( + _Inout_ PPH_ENVIRONMENT_CONTEXT Context + ) +{ + PPH_STRING settings; + PPH_STRING sortSettings; + + settings = PhGetStringSetting(L"EnvironmentTreeListColumns"); + sortSettings = PhGetStringSetting(L"EnvironmentTreeListSort"); + Context->Flags = PhGetIntegerSetting(L"EnvironmentTreeListFlags"); + + PhCmLoadSettingsEx(Context->TreeNewHandle, &Context->Cm, 0, &settings->sr, &sortSettings->sr); + + PhDereferenceObject(settings); + PhDereferenceObject(sortSettings); +} + +VOID PhSaveSettingsEnvironmentList( + _Inout_ PPH_ENVIRONMENT_CONTEXT Context + ) +{ + PPH_STRING settings; + PPH_STRING sortSettings; + + settings = PhCmSaveSettingsEx(Context->TreeNewHandle, &Context->Cm, 0, &sortSettings); + + PhSetIntegerSetting(L"EnvironmentTreeListFlags", Context->Flags); + PhSetStringSetting2(L"EnvironmentTreeListColumns", &settings->sr); + PhSetStringSetting2(L"EnvironmentTreeListSort", &sortSettings->sr); + + PhDereferenceObject(settings); + PhDereferenceObject(sortSettings); +} + +VOID PhSetOptionsEnvironmentList( + _Inout_ PPH_ENVIRONMENT_CONTEXT Context, + _In_ ULONG Options + ) +{ + switch (Options) + { + case ENVIRONMENT_TREE_MENU_ITEM_HIDE_PROCESS_TYPE: + Context->HideProcessEnvironment = !Context->HideProcessEnvironment; + break; + case ENVIRONMENT_TREE_MENU_ITEM_HIDE_USER_TYPE: + Context->HideUserEnvironment = !Context->HideUserEnvironment; + break; + case ENVIRONMENT_TREE_MENU_ITEM_HIDE_SYSTEM_TYPE: + Context->HideSystemEnvironment = !Context->HideSystemEnvironment; + break; + case ENVIRONMENT_TREE_MENU_ITEM_HIGHLIGHT_PROCESS_TYPE: + Context->HighlightProcessEnvironment = !Context->HighlightProcessEnvironment; + break; + case ENVIRONMENT_TREE_MENU_ITEM_HIGHLIGHT_USER_TYPE: + Context->HighlightUserEnvironment = !Context->HighlightUserEnvironment; + break; + case ENVIRONMENT_TREE_MENU_ITEM_HIGHLIGHT_SYSTEM_TYPE: + Context->HighlightSystemEnvironment = !Context->HighlightSystemEnvironment; + break; + } +} + +BOOLEAN PhpEnvironmentNodeHashtableEqualFunction( + _In_ PVOID Entry1, + _In_ PVOID Entry2 +) +{ + PPHP_PROCESS_ENVIRONMENT_TREENODE poolTagNode1 = *(PPHP_PROCESS_ENVIRONMENT_TREENODE *)Entry1; + PPHP_PROCESS_ENVIRONMENT_TREENODE poolTagNode2 = *(PPHP_PROCESS_ENVIRONMENT_TREENODE *)Entry2; + + return PhEqualStringRef(&poolTagNode1->NameText->sr, &poolTagNode2->NameText->sr, TRUE); +} + +ULONG PhpEnvironmentNodeHashtableHashFunction( + _In_ PVOID Entry +) +{ + return PhHashStringRef(&(*(PPHP_PROCESS_ENVIRONMENT_TREENODE*)Entry)->NameText->sr, TRUE); +} + +VOID PhpDestroyEnvironmentNode( + _In_ PPHP_PROCESS_ENVIRONMENT_TREENODE Node +) +{ + if (Node->NameText) + PhDereferenceObject(Node->NameText); + if (Node->ValueText) + PhDereferenceObject(Node->ValueText); + + PhFree(Node); +} + +PPHP_PROCESS_ENVIRONMENT_TREENODE PhpAddEnvironmentRootNode( + _In_ PPH_ENVIRONMENT_CONTEXT Context, + _In_ PPH_STRING KeyPath, + _In_opt_ PPH_STRING Value + ) +{ + PPHP_PROCESS_ENVIRONMENT_TREENODE node; + + node = PhAllocateZero(sizeof(PHP_PROCESS_ENVIRONMENT_TREENODE)); + PhInitializeTreeNewNode(&node->Node); + + memset(node->TextCache, 0, sizeof(PH_STRINGREF) * ENVIRONMENT_COLUMN_ITEM_MAXIMUM); + node->Node.TextCache = node->TextCache; + node->Node.TextCacheSize = ENVIRONMENT_COLUMN_ITEM_MAXIMUM; + node->Children = PhCreateList(1); + + PhReferenceObject(KeyPath); + node->NameText = KeyPath; + + if (Value) + { + PhReferenceObject(Value); + node->ValueText = Value; + } + + PhAddEntryHashtable(Context->NodeHashtable, &node); + PhAddItemList(Context->NodeList, node); + + if (Context->TreeFilterSupport.FilterList) + node->Node.Visible = PhApplyTreeNewFiltersToNode(&Context->TreeFilterSupport, &node->Node); + + return node; +} + +PPHP_PROCESS_ENVIRONMENT_TREENODE PhpAddEnvironmentChildNode( + _In_ PPH_ENVIRONMENT_CONTEXT Context, + _In_opt_ PPHP_PROCESS_ENVIRONMENT_TREENODE ParentNode, + _In_ PPH_STRING Name, + _In_opt_ PPH_STRING Value + ) +{ + PPHP_PROCESS_ENVIRONMENT_TREENODE node; + + node = PhpAddEnvironmentRootNode(Context, Name, Value); + + if (ParentNode) + { + node->HasChildren = FALSE; + + // This is a child node. + node->Parent = ParentNode; + PhAddItemList(ParentNode->Children, node); + } + else + { + node->HasChildren = TRUE; + node->Node.Expanded = TRUE; + + // This is a root node. + PhAddItemList(Context->NodeRootList, node); + } + + return node; +} + +PPHP_PROCESS_ENVIRONMENT_TREENODE PhpFindEnvironmentNode( + _In_ PPH_ENVIRONMENT_CONTEXT Context, + _In_ PWSTR KeyPath +) +{ + PHP_PROCESS_ENVIRONMENT_TREENODE lookupWindowNode; + PPHP_PROCESS_ENVIRONMENT_TREENODE lookupWindowNodePtr = &lookupWindowNode; + PPHP_PROCESS_ENVIRONMENT_TREENODE *windowNode; + + PhInitializeStringRefLongHint(&lookupWindowNode.NameText->sr, KeyPath); + + windowNode = (PPHP_PROCESS_ENVIRONMENT_TREENODE*)PhFindEntryHashtable( + Context->NodeHashtable, + &lookupWindowNodePtr + ); + + if (windowNode) + return *windowNode; + else + return NULL; +} + +VOID PhpRemoveEnvironmentNode( + _In_ PPH_ENVIRONMENT_CONTEXT Context, + _In_ PPHP_PROCESS_ENVIRONMENT_TREENODE Node +) +{ + ULONG index = 0; + + // Remove from hashtable/list and cleanup. + PhRemoveEntryHashtable(Context->NodeHashtable, &Node); + + if ((index = PhFindItemList(Context->NodeList, Node)) != -1) + { + PhRemoveItemList(Context->NodeList, index); + } + + PhpDestroyEnvironmentNode(Node); + //TreeNew_NodesStructured(Context->TreeNewHandle); +} + +VOID PhpUpdateEnvironmentNode( + _In_ PPH_ENVIRONMENT_CONTEXT Context, + _In_ PPHP_PROCESS_ENVIRONMENT_TREENODE Node + ) +{ + memset(Node->TextCache, 0, sizeof(PH_STRINGREF) * ENVIRONMENT_COLUMN_ITEM_MAXIMUM); + + PhInvalidateTreeNewNode(&Node->Node, TN_CACHE_COLOR); + //TreeNew_NodesStructured(Context->TreeNewHandle); +} + +VOID PhpExpandAllEnvironmentNodes( + _In_ PPH_ENVIRONMENT_CONTEXT Context, + _In_ BOOLEAN Expand + ) +{ + ULONG i; + BOOLEAN needsRestructure = FALSE; + + for (i = 0; i < Context->NodeList->Count; i++) + { + PPH_MODULE_NODE node = Context->NodeList->Items[i]; + + if (node->Node.Expanded != Expand) + { + node->Node.Expanded = Expand; + needsRestructure = TRUE; + } + } + + if (needsRestructure) + TreeNew_NodesStructured(Context->TreeNewHandle); +} + +#define SORT_FUNCTION(Column) PhpEnvironmentTreeNewCompare##Column +#define BEGIN_SORT_FUNCTION(Column) static int __cdecl PhpEnvironmentTreeNewCompare##Column( \ + _In_ void *_context, \ + _In_ const void *_elem1, \ + _In_ const void *_elem2 \ + ) \ +{ \ + PPHP_PROCESS_ENVIRONMENT_TREENODE node1 = *(PPHP_PROCESS_ENVIRONMENT_TREENODE*)_elem1; \ + PPHP_PROCESS_ENVIRONMENT_TREENODE node2 = *(PPHP_PROCESS_ENVIRONMENT_TREENODE*)_elem2; \ + int sortResult = 0; + +#define END_SORT_FUNCTION \ + if (sortResult == 0) \ + sortResult = uintptrcmp((ULONG_PTR)node1->Node.Index, (ULONG_PTR)node2->Node.Index); \ + \ + return PhModifySort(sortResult, ((PPH_ENVIRONMENT_CONTEXT)_context)->TreeNewSortOrder); \ +} + +LONG PhpEnvironmentTreeNewPostSortFunction( + _In_ LONG Result, + _In_ PVOID Node1, + _In_ PVOID Node2, + _In_ PH_SORT_ORDER SortOrder + ) +{ + if (Result == 0) + Result = uintptrcmp((ULONG_PTR)((PPHP_PROCESS_ENVIRONMENT_TREENODE)Node1)->Node.Index, (ULONG_PTR)((PPHP_PROCESS_ENVIRONMENT_TREENODE)Node2)->Node.Index); + + return PhModifySort(Result, SortOrder); +} + +BEGIN_SORT_FUNCTION(Name) +{ + sortResult = PhCompareStringWithNull(node1->NameText, node2->NameText, TRUE); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(Value) +{ + sortResult = PhCompareStringWithNull(node1->ValueText, node2->ValueText, FALSE); +} +END_SORT_FUNCTION + +BOOLEAN NTAPI PhpEnvironmentTreeNewCallback( + _In_ HWND hwnd, + _In_ PH_TREENEW_MESSAGE Message, + _In_opt_ PVOID Parameter1, + _In_opt_ PVOID Parameter2, + _In_opt_ PVOID Context +) +{ + PPH_ENVIRONMENT_CONTEXT context; + PPHP_PROCESS_ENVIRONMENT_TREENODE node; + + context = Context; + + switch (Message) + { + case TreeNewGetChildren: + { + PPH_TREENEW_GET_CHILDREN getChildren = Parameter1; + node = (PPHP_PROCESS_ENVIRONMENT_TREENODE)getChildren->Node; + + if (context->TreeNewSortOrder == NoSortOrder) + { + if (!node) + { + getChildren->Children = (PPH_TREENEW_NODE *)context->NodeRootList->Items; + getChildren->NumberOfChildren = context->NodeRootList->Count; + } + else + { + getChildren->Children = (PPH_TREENEW_NODE *)node->Children->Items; + getChildren->NumberOfChildren = node->Children->Count; + } + } + else + { + if (!node) + { + static PVOID sortFunctions[] = + { + SORT_FUNCTION(Name), + SORT_FUNCTION(Value) + }; + int (__cdecl *sortFunction)(void *, const void *, const void *); + + if (context->TreeNewSortColumn < ENVIRONMENT_COLUMN_ITEM_MAXIMUM) + sortFunction = sortFunctions[context->TreeNewSortColumn]; + else + sortFunction = NULL; + + if (sortFunction) + { + qsort_s(context->NodeList->Items, context->NodeList->Count, sizeof(PVOID), sortFunction, context); + } + + getChildren->Children = (PPH_TREENEW_NODE *)context->NodeList->Items; + getChildren->NumberOfChildren = context->NodeList->Count; + } + } + } + return TRUE; + case TreeNewIsLeaf: + { + PPH_TREENEW_IS_LEAF isLeaf = Parameter1; + node = (PPHP_PROCESS_ENVIRONMENT_TREENODE)isLeaf->Node; + + if (context->TreeNewSortOrder == NoSortOrder) + isLeaf->IsLeaf = !node->HasChildren; + else + isLeaf->IsLeaf = TRUE; + } + return TRUE; + case TreeNewGetCellText: + { + PPH_TREENEW_GET_CELL_TEXT getCellText = (PPH_TREENEW_GET_CELL_TEXT)Parameter1; + node = (PPHP_PROCESS_ENVIRONMENT_TREENODE)getCellText->Node; + + switch (getCellText->Id) + { + case ENVIRONMENT_COLUMN_ITEM_NAME: + getCellText->Text = PhGetStringRef(node->NameText); + break; + case ENVIRONMENT_COLUMN_ITEM_VALUE: + getCellText->Text = PhGetStringRef(node->ValueText); + break; + default: + return FALSE; + } + + getCellText->Flags = TN_CACHE; + } + return TRUE; + case TreeNewGetNodeColor: + { + PPH_TREENEW_GET_NODE_COLOR getNodeColor = (PPH_TREENEW_GET_NODE_COLOR)Parameter1; + node = (PPHP_PROCESS_ENVIRONMENT_TREENODE)getNodeColor->Node; + + if (node->HasChildren) + { + NOTHING; + } + else + { + if (context->HighlightProcessEnvironment && node->Type == PROCESS_ENVIRONMENT_TREENODE_TYPE_PROCESS) + getNodeColor->BackColor = PhCsColorServiceProcesses; + else if (context->HighlightUserEnvironment && node->Type == PROCESS_ENVIRONMENT_TREENODE_TYPE_USER) + getNodeColor->BackColor = PhCsColorOwnProcesses; + else if (context->HighlightSystemEnvironment && node->Type == PROCESS_ENVIRONMENT_TREENODE_TYPE_SYSTEM) + getNodeColor->BackColor = PhCsColorSystemProcesses; + } + + getNodeColor->Flags = TN_AUTO_FORECOLOR; + } + return TRUE; + case TreeNewSortChanged: + { + TreeNew_GetSort(hwnd, &context->TreeNewSortColumn, &context->TreeNewSortOrder); + // Force a rebuild to sort the items. + TreeNew_NodesStructured(hwnd); + + // HACK + if (context->TreeFilterSupport.FilterList) + PhApplyTreeNewFilters(&context->TreeFilterSupport); + } + return TRUE; + case TreeNewContextMenu: + { + PPH_TREENEW_CONTEXT_MENU contextMenuEvent = Parameter1; + + PhpShowEnvironmentNodeContextMenu(context, contextMenuEvent); + } + return TRUE; + case TreeNewHeaderRightClick: + { + PH_TN_COLUMN_MENU_DATA data; + + data.TreeNewHandle = hwnd; + data.MouseEvent = Parameter1; + data.DefaultSortColumn = 0; + data.DefaultSortOrder = AscendingSortOrder; + PhInitializeTreeNewColumnMenu(&data); + + data.Selection = PhShowEMenu( + data.Menu, + hwnd, + PH_EMENU_SHOW_LEFTRIGHT, + PH_ALIGN_LEFT | PH_ALIGN_TOP, + data.MouseEvent->ScreenLocation.x, + data.MouseEvent->ScreenLocation.y + ); + + PhHandleTreeNewColumnMenu(&data); + PhDeleteTreeNewColumnMenu(&data); + } + return TRUE; + } + + return FALSE; +} + +VOID PhpClearEnvironmentTree( + _In_ PPH_ENVIRONMENT_CONTEXT Context +) +{ + ULONG i; + + for (i = 0; i < Context->NodeList->Count; i++) + PhpDestroyEnvironmentNode(Context->NodeList->Items[i]); + + PhClearHashtable(Context->NodeHashtable); + PhClearList(Context->NodeList); + PhClearList(Context->NodeRootList); + + PhpClearEnvironmentItems(Context); +} + +PPHP_PROCESS_ENVIRONMENT_TREENODE PhpGetSelectedEnvironmentNode( + _In_ PPH_ENVIRONMENT_CONTEXT Context + ) +{ + PPHP_PROCESS_ENVIRONMENT_TREENODE windowNode = NULL; + ULONG i; + + for (i = 0; i < Context->NodeList->Count; i++) + { + windowNode = Context->NodeList->Items[i]; + + if (windowNode->Node.Selected) + return windowNode; + } + + return NULL; +} + +VOID PhpGetSelectedEnvironmentNodes( + _In_ PPH_ENVIRONMENT_CONTEXT Context, + _Out_ PPHP_PROCESS_ENVIRONMENT_TREENODE **PoolTags, + _Out_ PULONG NumberOfPoolTags + ) +{ + PPH_LIST list; + ULONG i; + + list = PhCreateList(2); + + for (i = 0; i < Context->NodeList->Count; i++) + { + PPHP_PROCESS_ENVIRONMENT_TREENODE node = (PPHP_PROCESS_ENVIRONMENT_TREENODE)Context->NodeList->Items[i]; + + if (node->Node.Selected) + { + PhAddItemList(list, node); + } + } + + *PoolTags = PhAllocateCopy(list->Items, sizeof(PVOID) * list->Count); + *NumberOfPoolTags = list->Count; + + PhDereferenceObject(list); +} + +VOID PhpInitializeEnvironmentTree( + _Inout_ PPH_ENVIRONMENT_CONTEXT Context + ) +{ + Context->NodeList = PhCreateList(100); + Context->NodeRootList = PhCreateList(30); + Context->NodeHashtable = PhCreateHashtable( + sizeof(PHP_PROCESS_ENVIRONMENT_TREENODE), + PhpEnvironmentNodeHashtableEqualFunction, + PhpEnvironmentNodeHashtableHashFunction, + 100 + ); + + PhSetControlTheme(Context->TreeNewHandle, L"explorer"); + TreeNew_SetCallback(Context->TreeNewHandle, PhpEnvironmentTreeNewCallback, Context); + + PhAddTreeNewColumn(Context->TreeNewHandle, ENVIRONMENT_COLUMN_ITEM_NAME, TRUE, L"Name", 250, PH_ALIGN_LEFT, 0, 0); + PhAddTreeNewColumn(Context->TreeNewHandle, ENVIRONMENT_COLUMN_ITEM_VALUE, TRUE, L"Value", 250, PH_ALIGN_LEFT, 1, 0); + + TreeNew_SetTriState(Context->TreeNewHandle, TRUE); + TreeNew_SetSort(Context->TreeNewHandle, ENVIRONMENT_COLUMN_ITEM_NAME, NoSortOrder); + + PhCmInitializeManager(&Context->Cm, Context->TreeNewHandle, PHMOTLC_MAXIMUM, PhpEnvironmentTreeNewPostSortFunction); + PhInitializeTreeNewFilterSupport(&Context->TreeFilterSupport, Context->TreeNewHandle, Context->NodeList); +} + +VOID PhpDeleteEnvironmentTree( + _In_ PPH_ENVIRONMENT_CONTEXT Context + ) +{ + for (ULONG i = 0; i < Context->NodeList->Count; i++) + { + PhpDestroyEnvironmentNode(Context->NodeList->Items[i]); + } + + PhDereferenceObject(Context->NodeHashtable); + PhDereferenceObject(Context->NodeList); +} + +BOOLEAN PhpProcessEnvironmentTreeFilterCallback( + _In_ PPH_TREENEW_NODE Node, + _In_opt_ PVOID Context + ) +{ + PPH_ENVIRONMENT_CONTEXT context = Context; + PPHP_PROCESS_ENVIRONMENT_TREENODE environmentNode = (PPHP_PROCESS_ENVIRONMENT_TREENODE)Node; + + if (!environmentNode->Parent && environmentNode->Children && environmentNode->Children->Count == 0) + return FALSE; + if (context->TreeNewSortOrder != NoSortOrder && environmentNode->HasChildren) + return FALSE; + + if (context->HideProcessEnvironment && environmentNode->Type == PROCESS_ENVIRONMENT_TREENODE_TYPE_PROCESS) + return FALSE; + if (context->HideUserEnvironment && environmentNode->Type == PROCESS_ENVIRONMENT_TREENODE_TYPE_USER) + return FALSE; + if (context->HideSystemEnvironment && environmentNode->Type == PROCESS_ENVIRONMENT_TREENODE_TYPE_SYSTEM) + return FALSE; + + if (PhIsNullOrEmptyString(context->SearchboxText)) + return TRUE; + + if (!PhIsNullOrEmptyString(environmentNode->NameText)) + { + if (PhpWordMatchEnvironmentStringRef(&context->SearchboxText->sr, &environmentNode->NameText->sr)) + return TRUE; + } + + if (!PhIsNullOrEmptyString(environmentNode->ValueText)) + { + if (PhpWordMatchEnvironmentStringRef(&context->SearchboxText->sr, &environmentNode->ValueText->sr)) + return TRUE; + } + + return FALSE; +} + +INT_PTR CALLBACK PhpProcessEnvironmentDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam +) +{ + LPPROPSHEETPAGE propSheetPage; + PPH_PROCESS_PROPPAGECONTEXT propPageContext; + PPH_PROCESS_ITEM processItem; + PPH_ENVIRONMENT_CONTEXT context; + + if (PhpPropPageDlgProcHeader(hwndDlg, uMsg, lParam, &propSheetPage, &propPageContext, &processItem)) + { + context = propPageContext->Context; + } + else + { + return FALSE; + } + + switch (uMsg) + { + case WM_INITDIALOG: + { + context = propPageContext->Context = PhAllocateZero(sizeof(PH_ENVIRONMENT_CONTEXT)); + context->WindowHandle = hwndDlg; + context->TreeNewHandle = GetDlgItem(hwndDlg, IDC_LIST); + context->SearchWindowHandle = GetDlgItem(hwndDlg, IDC_SEARCH); + context->SearchboxText = PhReferenceEmptyString(); + context->ProcessItem = processItem; + + PhCreateSearchControl(hwndDlg, context->SearchWindowHandle, L"Search Environment (Ctrl+K)"); + Edit_SetSel(context->SearchWindowHandle, 0, -1); + PhpInitializeEnvironmentTree(context); + + PhInitializeArray(&context->Items, sizeof(PH_ENVIRONMENT_ITEM), 100); + context->TreeFilterEntry = PhAddTreeNewFilter(&context->TreeFilterSupport, PhpProcessEnvironmentTreeFilterCallback, context); + + PhMoveReference(&context->StatusMessage, PhCreateString(L"There are no environment variables to display.")); + TreeNew_SetEmptyText(context->TreeNewHandle, &context->StatusMessage->sr, 0); + PhLoadSettingsEnvironmentList(context); + + PhpRefreshEnvironmentList(hwndDlg, context, processItem); + + EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); + } + break; + case WM_DESTROY: + { + PhSaveSettingsEnvironmentList(context); + PhpDeleteEnvironmentTree(context); + + PhpClearEnvironmentItems(context); + PhDeleteArray(&context->Items); + PhClearReference(&context->StatusMessage); + + if (DestroyEnvironmentBlock && context->SystemDefaultEnvironment) + DestroyEnvironmentBlock(context->SystemDefaultEnvironment); + if (DestroyEnvironmentBlock && context->UserDefaultEnvironment) + DestroyEnvironmentBlock(context->UserDefaultEnvironment); + + PhFree(context); + + PhpPropPageDlgProcDestroy(hwndDlg); + } + break; + case WM_SHOWWINDOW: + { + if (!propPageContext->LayoutInitialized) + { + PPH_LAYOUT_ITEM dialogItem; + + dialogItem = PhAddPropPageLayoutItem(hwndDlg, hwndDlg, PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL); + PhAddPropPageLayoutItem(hwndDlg, context->SearchWindowHandle, dialogItem, PH_ANCHOR_RIGHT | PH_ANCHOR_TOP); + PhAddPropPageLayoutItem(hwndDlg, context->TreeNewHandle, dialogItem, PH_ANCHOR_ALL); + + PhDoPropPageLayout(hwndDlg); + + propPageContext->LayoutInitialized = TRUE; + } + } + break; + case WM_COMMAND: + { + switch (GET_WM_COMMAND_CMD(wParam, lParam)) + { + case EN_CHANGE: + { + PPH_STRING newSearchboxText; + + if (GET_WM_COMMAND_HWND(wParam, lParam) != context->SearchWindowHandle) + break; + + newSearchboxText = PH_AUTO(PhGetWindowText(context->SearchWindowHandle)); + + if (!PhEqualString(context->SearchboxText, newSearchboxText, FALSE)) + { + // Cache the current search text for our callback. + PhSwapReference(&context->SearchboxText, newSearchboxText); + + // Expand any hidden nodes to make search results visible. + PhpExpandAllEnvironmentNodes(context, TRUE); + + PhApplyTreeNewFilters(&context->TreeFilterSupport); + } + } + break; + } + + switch (GET_WM_COMMAND_ID(wParam, lParam)) + { + case IDC_OPTIONS: + { + RECT rect; + PPH_EMENU menu; + PPH_EMENU_ITEM processMenuItem; + PPH_EMENU_ITEM userMenuItem; + PPH_EMENU_ITEM systemMenuItem; + PPH_EMENU_ITEM highlightProcessMenuItem; + PPH_EMENU_ITEM highlightUserMenuItem; + PPH_EMENU_ITEM highlightSystemMenuItem; + PPH_EMENU_ITEM newProcessMenuItem; + PPH_EMENU_ITEM selectedItem; + + GetWindowRect(GetDlgItem(hwndDlg, IDC_OPTIONS), &rect); + + processMenuItem = PhCreateEMenuItem(0, ENVIRONMENT_TREE_MENU_ITEM_HIDE_PROCESS_TYPE, L"Hide process", NULL, NULL); + userMenuItem = PhCreateEMenuItem(0, ENVIRONMENT_TREE_MENU_ITEM_HIDE_USER_TYPE, L"Hide user", NULL, NULL); + systemMenuItem = PhCreateEMenuItem(0, ENVIRONMENT_TREE_MENU_ITEM_HIDE_SYSTEM_TYPE, L"Hide system", NULL, NULL); + highlightProcessMenuItem = PhCreateEMenuItem(0, ENVIRONMENT_TREE_MENU_ITEM_HIGHLIGHT_PROCESS_TYPE, L"Highlight process", NULL, NULL); + highlightUserMenuItem = PhCreateEMenuItem(0, ENVIRONMENT_TREE_MENU_ITEM_HIGHLIGHT_USER_TYPE, L"Highlight user", NULL, NULL); + highlightSystemMenuItem = PhCreateEMenuItem(0, ENVIRONMENT_TREE_MENU_ITEM_HIGHLIGHT_SYSTEM_TYPE, L"Highlight system", NULL, NULL); + newProcessMenuItem = PhCreateEMenuItem(0, ENVIRONMENT_TREE_MENU_ITEM_NEW_ENVIRONMENT_VARIABLE, L"New variable...", NULL, NULL); + + menu = PhCreateEMenu(); + PhInsertEMenuItem(menu, processMenuItem, ULONG_MAX); + PhInsertEMenuItem(menu, userMenuItem, ULONG_MAX); + PhInsertEMenuItem(menu, systemMenuItem, ULONG_MAX); + PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX); + PhInsertEMenuItem(menu, highlightProcessMenuItem, ULONG_MAX); + PhInsertEMenuItem(menu, highlightUserMenuItem, ULONG_MAX); + PhInsertEMenuItem(menu, highlightSystemMenuItem, ULONG_MAX); + PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX); + PhInsertEMenuItem(menu, newProcessMenuItem, ULONG_MAX); + + if (context->HideProcessEnvironment) + processMenuItem->Flags |= PH_EMENU_CHECKED; + if (context->HideUserEnvironment) + userMenuItem->Flags |= PH_EMENU_CHECKED; + if (context->HideSystemEnvironment) + systemMenuItem->Flags |= PH_EMENU_CHECKED; + if (context->HighlightProcessEnvironment) + highlightProcessMenuItem->Flags |= PH_EMENU_CHECKED; + if (context->HighlightUserEnvironment) + highlightUserMenuItem->Flags |= PH_EMENU_CHECKED; + if (context->HighlightSystemEnvironment) + highlightSystemMenuItem->Flags |= PH_EMENU_CHECKED; + + selectedItem = PhShowEMenu( + menu, + hwndDlg, + PH_EMENU_SHOW_LEFTRIGHT, + PH_ALIGN_LEFT | PH_ALIGN_TOP, + rect.left, + rect.bottom + ); + + if (selectedItem && selectedItem->Id) + { + if (selectedItem->Id == ENVIRONMENT_TREE_MENU_ITEM_NEW_ENVIRONMENT_VARIABLE) + { + BOOLEAN refresh; + + if (PhGetIntegerSetting(L"EnableWarnings") && !PhShowConfirmMessage( + hwndDlg, + L"create", + L"new environment variable(s)", + L"Some programs may restrict access or ban your account when creating new environment variable(s).", + FALSE + )) + { + break; + } + + if (PhpShowEditEnvDialog(hwndDlg, processItem, L"", NULL, &refresh) == IDOK && refresh) + { + PhpRefreshEnvironmentList(hwndDlg, context, processItem); + } + } + else + { + PhSetOptionsEnvironmentList(context, selectedItem->Id); + PhSaveSettingsEnvironmentList(context); + PhApplyTreeNewFilters(&context->TreeFilterSupport); + } + } + + PhDestroyEMenu(menu); + } + break; + case IDC_REFRESH: + { + PhpRefreshEnvironmentList(hwndDlg, context, processItem); + } + break; + } + } + break; + case WM_NOTIFY: + { + LPNMHDR header = (LPNMHDR)lParam; + + switch (header->code) + { + case PSN_QUERYINITIALFOCUS: + SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, (LPARAM)GetDlgItem(hwndDlg, IDC_REFRESH)); + return TRUE; + } + } + break; + } + + return FALSE; +} diff --git a/ProcessHacker/resource.h b/ProcessHacker/resource.h index 8b25c5e044de..63844a0ebdfc 100644 --- a/ProcessHacker/resource.h +++ b/ProcessHacker/resource.h @@ -111,7 +111,6 @@ #define IDD_MINIINFO_LIST 210 #define IDR_MINIINFO 211 #define IDR_MINIINFO_PROCESS 212 -#define IDR_ENVIRONMENT 214 #define IDD_MITIGATION 215 #define IDI_PIN 216 #define IDI_FOLDER 217 @@ -739,9 +738,6 @@ #define ID_PROCESS_GOTOPROCESS 40287 #define ID_MINIINFO_REFRESH 40288 #define ID_MINIINFO_REFRESHAUTOMATICALLY 40289 -#define ID_ENVIRONMENT_EDIT 40290 -#define ID_ENVIRONMENT_COPY 40291 -#define ID_ENVIRONMENT_DELETE 40292 #define IDC_MAXSCREEN 40293 #define ID_EMPTY_COMBINEMEMORYLISTS 40295 #define IDDYNAMIC 50000 diff --git a/ProcessHacker/settings.c b/ProcessHacker/settings.c index fc307817e36e..f7cd82bcd91d 100644 --- a/ProcessHacker/settings.c +++ b/ProcessHacker/settings.c @@ -53,7 +53,9 @@ VOID PhAddDefaultSettings( PhpAddIntegerSetting(L"EnableWarnings", L"1"); PhpAddIntegerSetting(L"EnableWindowText", L"1"); PhpAddIntegerSetting(L"EnableSecurityAdvancedDialog", L"1"); - PhpAddStringSetting(L"EnvironmentListViewColumns", L""); + PhpAddStringSetting(L"EnvironmentTreeListColumns", L""); + PhpAddStringSetting(L"EnvironmentTreeListSort", L"0,0"); // 0, NoSortOrder + PhpAddIntegerSetting(L"EnvironmentTreeListFlags", L"0"); PhpAddIntegerSetting(L"FindObjRegex", L"0"); PhpAddStringSetting(L"FindObjTreeListColumns", L""); PhpAddIntegerPairSetting(L"FindObjWindowPosition", L"350,350"); From f1dd54168043d14b7c61fab50cabb9c4f76890bb Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 5 Jul 2018 14:46:09 +1000 Subject: [PATCH 1087/2058] Fix #286 (Integrity column) --- ProcessHacker/procprv.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/ProcessHacker/procprv.c b/ProcessHacker/procprv.c index fb0ed5f028ff..a13ba5ba229e 100644 --- a/ProcessHacker/procprv.c +++ b/ProcessHacker/procprv.c @@ -89,10 +89,6 @@ typedef struct _PH_PROCESS_QUERY_S1_DATA HICON LargeIcon; PH_IMAGE_VERSION_INFO VersionInfo; - TOKEN_ELEVATION_TYPE ElevationType; - MANDATORY_LEVEL IntegrityLevel; - PWSTR IntegrityString; - PPH_STRING JobName; HANDLE ConsoleHostProcessId; PPH_STRING PackageFullName; @@ -103,7 +99,7 @@ typedef struct _PH_PROCESS_QUERY_S1_DATA struct { ULONG IsDotNet : 1; - ULONG IsElevated : 1; + ULONG Spare1 : 1; ULONG IsInJob : 1; ULONG IsInSignificantJob : 1; ULONG IsBeingDebugged : 1; @@ -1032,14 +1028,10 @@ VOID PhpFillProcessItemStage1( processItem->SmallIcon = Data->SmallIcon; processItem->LargeIcon = Data->LargeIcon; memcpy(&processItem->VersionInfo, &Data->VersionInfo, sizeof(PH_IMAGE_VERSION_INFO)); - processItem->ElevationType = Data->ElevationType; - processItem->IntegrityLevel = Data->IntegrityLevel; - processItem->IntegrityString = Data->IntegrityString; processItem->JobName = Data->JobName; processItem->ConsoleHostProcessId = Data->ConsoleHostProcessId; processItem->PackageFullName = Data->PackageFullName; processItem->IsDotNet = Data->IsDotNet; - processItem->IsElevated = Data->IsElevated; processItem->IsInJob = Data->IsInJob; processItem->IsInSignificantJob = Data->IsInSignificantJob; processItem->IsBeingDebugged = Data->IsBeingDebugged; From b326d9223cdef19183426f5242a4506a3938b2b1 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 6 Jul 2018 18:18:54 +1000 Subject: [PATCH 1088/2058] Update general handle properties layout --- ProcessHacker/hndlprp.c | 652 +++++++++++++++++++++++++++++++--- ProcessHacker/include/phapp.h | 15 - ProcessHacker/ntobjprp.c | 460 ------------------------ 3 files changed, 595 insertions(+), 532 deletions(-) diff --git a/ProcessHacker/hndlprp.c b/ProcessHacker/hndlprp.c index 8d9f3b394428..e6d73b2d955b 100644 --- a/ProcessHacker/hndlprp.c +++ b/ProcessHacker/hndlprp.c @@ -32,14 +32,76 @@ #include +typedef enum _PHP_HANDLE_GENERAL_CATEGORY +{ + // common + PH_HANDLE_GENERAL_CATEGORY_BASICINFO, + PH_HANDLE_GENERAL_CATEGORY_REFERENCES, + PH_HANDLE_GENERAL_CATEGORY_QUOTA, + // extra + PH_HANDLE_GENERAL_CATEGORY_ALPC, + PH_HANDLE_GENERAL_CATEGORY_FILE, + PH_HANDLE_GENERAL_CATEGORY_SECTION, + PH_HANDLE_GENERAL_CATEGORY_MUTANT, + + PH_HANDLE_GENERAL_CATEGORY_MAXIMUM +} PHP_HANDLE_GENERAL_CATEGORY; + +typedef enum _PHP_HANDLE_GENERAL_INDEX +{ + PH_HANDLE_GENERAL_INDEX_NAME, + PH_HANDLE_GENERAL_INDEX_TYPE, + PH_HANDLE_GENERAL_INDEX_OBJECT, + PH_HANDLE_GENERAL_INDEX_ACCESSMASK, + + PH_HANDLE_GENERAL_INDEX_REFERENCES, + PH_HANDLE_GENERAL_INDEX_HANDLES, + + PH_HANDLE_GENERAL_INDEX_PAGED, + PH_HANDLE_GENERAL_INDEX_NONPAGED, + + PH_HANDLE_GENERAL_INDEX_SEQUENCENUMBER, + PH_HANDLE_GENERAL_INDEX_PORTCONTEXT, + + PH_HANDLE_GENERAL_INDEX_FILETYPE, + PH_HANDLE_GENERAL_INDEX_FILEMODE, + PH_HANDLE_GENERAL_INDEX_FILEPOSITION, + PH_HANDLE_GENERAL_INDEX_FILESIZE, + + PH_HANDLE_GENERAL_INDEX_SECTIONTYPE, + PH_HANDLE_GENERAL_INDEX_SECTIONFILE, + PH_HANDLE_GENERAL_INDEX_SECTIONSIZE, + + PH_HANDLE_GENERAL_INDEX_MUTANTCOUNT, + PH_HANDLE_GENERAL_INDEX_MUTANTABANDONED, + PH_HANDLE_GENERAL_INDEX_MUTANTOWNER, + + PH_HANDLE_GENERAL_INDEX_MAXIMUM +} PHP_PROCESS_STATISTICS_INDEX; + typedef struct _HANDLE_PROPERTIES_CONTEXT { HWND ListViewHandle; HANDLE ProcessId; PPH_HANDLE_ITEM HandleItem; PH_LAYOUT_MANAGER LayoutManager; + ULONG ListViewRowCache[PH_HANDLE_GENERAL_INDEX_MAXIMUM]; } HANDLE_PROPERTIES_CONTEXT, *PHANDLE_PROPERTIES_CONTEXT; +#define PH_FILEMODE_ASYNC 0x01000000 +#define PhFileModeUpdAsyncFlag(mode) \ + (mode & (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT) ? mode &~ PH_FILEMODE_ASYNC: mode | PH_FILEMODE_ASYNC) + +PH_ACCESS_ENTRY FileModeAccessEntries[6] = +{ + { L"FILE_FLAG_OVERLAPPED", PH_FILEMODE_ASYNC, FALSE, FALSE, L"Asynchronous" }, + { L"FILE_FLAG_WRITE_THROUGH", FILE_WRITE_THROUGH, FALSE, FALSE, L"Write through" }, + { L"FILE_FLAG_SEQUENTIAL_SCAN", FILE_SEQUENTIAL_ONLY, FALSE, FALSE, L"Sequental" }, + { L"FILE_FLAG_NO_BUFFERING", FILE_NO_INTERMEDIATE_BUFFERING, FALSE, FALSE, L"No buffering" }, + { L"FILE_SYNCHRONOUS_IO_ALERT", FILE_SYNCHRONOUS_IO_ALERT, FALSE, FALSE, L"Synchronous alert" }, + { L"FILE_SYNCHRONOUS_IO_NONALERT", FILE_SYNCHRONOUS_IO_NONALERT, FALSE, FALSE, L"Synchronous non-alert" }, +}; + INT_PTR CALLBACK PhpHandleGeneralDlgProc( _In_ HWND hwndDlg, _In_ UINT uMsg, @@ -134,13 +196,6 @@ VOID PhShowHandleProperties( &context ); } - else if (PhEqualString2(HandleItem->TypeName, L"File", TRUE)) - { - pages[propSheetHeader.nPages++] = PhCreateFilePage( - PhpDuplicateHandleFromProcess, - &context - ); - } else if (PhEqualString2(HandleItem->TypeName, L"Job", TRUE)) { pages[propSheetHeader.nPages++] = PhCreateJobPage( @@ -149,20 +204,20 @@ VOID PhShowHandleProperties( NULL ); } - else if (PhEqualString2(HandleItem->TypeName, L"Mutant", TRUE)) - { - pages[propSheetHeader.nPages++] = PhCreateMutantPage( - PhpDuplicateHandleFromProcess, - &context - ); - } - else if (PhEqualString2(HandleItem->TypeName, L"Section", TRUE)) - { - pages[propSheetHeader.nPages++] = PhCreateSectionPage( - PhpDuplicateHandleFromProcess, - &context - ); - } + //else if (PhEqualString2(HandleItem->TypeName, L"Mutant", TRUE)) + //{ + // pages[propSheetHeader.nPages++] = PhCreateMutantPage( + // PhpDuplicateHandleFromProcess, + // &context + // ); + //} + //else if (PhEqualString2(HandleItem->TypeName, L"Section", TRUE)) + //{ + // pages[propSheetHeader.nPages++] = PhCreateSectionPage( + // PhpDuplicateHandleFromProcess, + // &context + // ); + //} else if (PhEqualString2(HandleItem->TypeName, L"Semaphore", TRUE)) { pages[propSheetHeader.nPages++] = PhCreateSemaphorePage( @@ -225,41 +280,175 @@ VOID PhShowHandleProperties( PhModalPropertySheet(&propSheetHeader); } -typedef enum _PHP_HANDLE_GENERAL_CATEGORY -{ - PH_HANDLE_GENERAL_CATEGORY_BASICINFO, - PH_HANDLE_GENERAL_CATEGORY_REFERENCES, - PH_HANDLE_GENERAL_CATEGORY_QUOTA -} PHP_HANDLE_GENERAL_CATEGORY; - -typedef enum _PHP_HANDLE_GENERAL_INDEX -{ - PH_HANDLE_GENERAL_INDEX_NAME, - PH_HANDLE_GENERAL_INDEX_TYPE, - PH_HANDLE_GENERAL_INDEX_OBJECT, - PH_HANDLE_GENERAL_INDEX_ACCESSMASK, - PH_HANDLE_GENERAL_INDEX_REFERENCES, - PH_HANDLE_GENERAL_INDEX_HANDLES, - PH_HANDLE_GENERAL_INDEX_PAGED, - PH_HANDLE_GENERAL_INDEX_NONPAGED -} PHP_PROCESS_STATISTICS_INDEX; - VOID PhpUpdateHandleGeneralListViewGroups( - _In_ HWND ListViewHandle + _In_ PHANDLE_PROPERTIES_CONTEXT Context ) { - ListView_EnableGroupView(ListViewHandle, TRUE); - PhAddListViewGroup(ListViewHandle, PH_HANDLE_GENERAL_CATEGORY_BASICINFO, L"Basic information"); - PhAddListViewGroup(ListViewHandle, PH_HANDLE_GENERAL_CATEGORY_REFERENCES, L"References"); - PhAddListViewGroup(ListViewHandle, PH_HANDLE_GENERAL_CATEGORY_QUOTA, L"Quota charges"); - PhAddListViewGroupItem(ListViewHandle, PH_HANDLE_GENERAL_CATEGORY_BASICINFO, PH_HANDLE_GENERAL_INDEX_NAME, L"Name", NULL); - PhAddListViewGroupItem(ListViewHandle, PH_HANDLE_GENERAL_CATEGORY_BASICINFO, PH_HANDLE_GENERAL_INDEX_TYPE, L"Type", NULL); - PhAddListViewGroupItem(ListViewHandle, PH_HANDLE_GENERAL_CATEGORY_BASICINFO, PH_HANDLE_GENERAL_INDEX_OBJECT, L"Object address", NULL); - PhAddListViewGroupItem(ListViewHandle, PH_HANDLE_GENERAL_CATEGORY_BASICINFO, PH_HANDLE_GENERAL_INDEX_ACCESSMASK, L"Granted access", NULL); - PhAddListViewGroupItem(ListViewHandle, PH_HANDLE_GENERAL_CATEGORY_REFERENCES, PH_HANDLE_GENERAL_INDEX_REFERENCES, L"References", NULL); - PhAddListViewGroupItem(ListViewHandle, PH_HANDLE_GENERAL_CATEGORY_REFERENCES, PH_HANDLE_GENERAL_INDEX_HANDLES, L"Handles", NULL); - PhAddListViewGroupItem(ListViewHandle, PH_HANDLE_GENERAL_CATEGORY_QUOTA, PH_HANDLE_GENERAL_INDEX_PAGED, L"Paged", NULL); - PhAddListViewGroupItem(ListViewHandle, PH_HANDLE_GENERAL_CATEGORY_QUOTA, PH_HANDLE_GENERAL_INDEX_NONPAGED, L"Virtual size", NULL); + ListView_EnableGroupView(Context->ListViewHandle, TRUE); + PhAddListViewGroup(Context->ListViewHandle, PH_HANDLE_GENERAL_CATEGORY_BASICINFO, L"Basic information"); + PhAddListViewGroup(Context->ListViewHandle, PH_HANDLE_GENERAL_CATEGORY_REFERENCES, L"References"); + PhAddListViewGroup(Context->ListViewHandle, PH_HANDLE_GENERAL_CATEGORY_QUOTA, L"Quota charges"); + + Context->ListViewRowCache[PH_HANDLE_GENERAL_INDEX_NAME] = PhAddListViewGroupItem( + Context->ListViewHandle, + PH_HANDLE_GENERAL_CATEGORY_BASICINFO, + PH_HANDLE_GENERAL_INDEX_NAME, + L"Name", + NULL + ); + Context->ListViewRowCache[PH_HANDLE_GENERAL_INDEX_TYPE] = PhAddListViewGroupItem( + Context->ListViewHandle, + PH_HANDLE_GENERAL_CATEGORY_BASICINFO, + PH_HANDLE_GENERAL_INDEX_TYPE, + L"Type", + NULL + ); + Context->ListViewRowCache[PH_HANDLE_GENERAL_INDEX_OBJECT] = PhAddListViewGroupItem( + Context->ListViewHandle, + PH_HANDLE_GENERAL_CATEGORY_BASICINFO, + PH_HANDLE_GENERAL_INDEX_OBJECT, + L"Object address", + NULL + ); + Context->ListViewRowCache[PH_HANDLE_GENERAL_INDEX_ACCESSMASK] = PhAddListViewGroupItem( + Context->ListViewHandle, + PH_HANDLE_GENERAL_CATEGORY_BASICINFO, + PH_HANDLE_GENERAL_INDEX_ACCESSMASK, + L"Granted access", + NULL + ); + Context->ListViewRowCache[PH_HANDLE_GENERAL_INDEX_REFERENCES] = PhAddListViewGroupItem( + Context->ListViewHandle, + PH_HANDLE_GENERAL_CATEGORY_REFERENCES, + PH_HANDLE_GENERAL_INDEX_REFERENCES, + L"References", + NULL + ); + Context->ListViewRowCache[PH_HANDLE_GENERAL_INDEX_HANDLES] = PhAddListViewGroupItem( + Context->ListViewHandle, + PH_HANDLE_GENERAL_CATEGORY_REFERENCES, + PH_HANDLE_GENERAL_INDEX_HANDLES, + L"Handles", + NULL + ); + Context->ListViewRowCache[PH_HANDLE_GENERAL_INDEX_PAGED] = PhAddListViewGroupItem( + Context->ListViewHandle, + PH_HANDLE_GENERAL_CATEGORY_QUOTA, + PH_HANDLE_GENERAL_INDEX_PAGED, + L"Paged", + NULL + ); + Context->ListViewRowCache[PH_HANDLE_GENERAL_INDEX_NONPAGED] = PhAddListViewGroupItem( + Context->ListViewHandle, + PH_HANDLE_GENERAL_CATEGORY_QUOTA, + PH_HANDLE_GENERAL_INDEX_NONPAGED, + L"Virtual size", + NULL + ); + + if (PhEqualString2(Context->HandleItem->TypeName, L"ALPC Port", TRUE)) + { + PhAddListViewGroup(Context->ListViewHandle, PH_HANDLE_GENERAL_CATEGORY_ALPC, L"ALPC Port"); + Context->ListViewRowCache[PH_HANDLE_GENERAL_INDEX_SEQUENCENUMBER] = PhAddListViewGroupItem( + Context->ListViewHandle, + PH_HANDLE_GENERAL_CATEGORY_ALPC, + PH_HANDLE_GENERAL_INDEX_SEQUENCENUMBER, + L"Sequence Number", + NULL + ); + Context->ListViewRowCache[PH_HANDLE_GENERAL_INDEX_PORTCONTEXT] = PhAddListViewGroupItem( + Context->ListViewHandle, + PH_HANDLE_GENERAL_CATEGORY_ALPC, + PH_HANDLE_GENERAL_INDEX_PORTCONTEXT, + L"Port Context", + NULL + ); + } + else if (PhEqualStringRef2(&Context->HandleItem->TypeName->sr, L"File", TRUE)) + { + PhAddListViewGroup(Context->ListViewHandle, PH_HANDLE_GENERAL_CATEGORY_FILE, L"File Information"); + + Context->ListViewRowCache[PH_HANDLE_GENERAL_INDEX_FILETYPE] = PhAddListViewGroupItem( + Context->ListViewHandle, + PH_HANDLE_GENERAL_CATEGORY_FILE, + PH_HANDLE_GENERAL_INDEX_FILETYPE, + L"Type", + NULL + ); + Context->ListViewRowCache[PH_HANDLE_GENERAL_INDEX_FILEMODE] = PhAddListViewGroupItem( + Context->ListViewHandle, + PH_HANDLE_GENERAL_CATEGORY_FILE, + PH_HANDLE_GENERAL_INDEX_FILEMODE, + L"Mode", + NULL + ); + Context->ListViewRowCache[PH_HANDLE_GENERAL_INDEX_FILEPOSITION] = PhAddListViewGroupItem( + Context->ListViewHandle, + PH_HANDLE_GENERAL_CATEGORY_FILE, + PH_HANDLE_GENERAL_INDEX_FILEPOSITION, + L"Position", + NULL + ); + Context->ListViewRowCache[PH_HANDLE_GENERAL_INDEX_FILESIZE] = PhAddListViewGroupItem( + Context->ListViewHandle, + PH_HANDLE_GENERAL_CATEGORY_FILE, + PH_HANDLE_GENERAL_INDEX_FILESIZE, + L"Size", + NULL + ); + } + else if (PhEqualStringRef2(&Context->HandleItem->TypeName->sr, L"Section", TRUE)) + { + PhAddListViewGroup(Context->ListViewHandle, PH_HANDLE_GENERAL_CATEGORY_SECTION, L"Section Information"); + + Context->ListViewRowCache[PH_HANDLE_GENERAL_INDEX_SECTIONTYPE] = PhAddListViewGroupItem( + Context->ListViewHandle, + PH_HANDLE_GENERAL_CATEGORY_SECTION, + PH_HANDLE_GENERAL_INDEX_SECTIONTYPE, + L"Type", + NULL + ); + Context->ListViewRowCache[PH_HANDLE_GENERAL_INDEX_SECTIONFILE] = PhAddListViewGroupItem( + Context->ListViewHandle, + PH_HANDLE_GENERAL_CATEGORY_SECTION, + PH_HANDLE_GENERAL_INDEX_SECTIONFILE, + L"File", + NULL + ); + Context->ListViewRowCache[PH_HANDLE_GENERAL_INDEX_SECTIONSIZE] = PhAddListViewGroupItem( + Context->ListViewHandle, + PH_HANDLE_GENERAL_CATEGORY_SECTION, + PH_HANDLE_GENERAL_INDEX_SECTIONSIZE, + L"Size", + NULL + ); + } + else if (PhEqualStringRef2(&Context->HandleItem->TypeName->sr, L"Mutant", TRUE)) + { + PhAddListViewGroup(Context->ListViewHandle, PH_HANDLE_GENERAL_CATEGORY_MUTANT, L"Mutant Information"); + + Context->ListViewRowCache[PH_HANDLE_GENERAL_INDEX_MUTANTCOUNT] = PhAddListViewGroupItem( + Context->ListViewHandle, + PH_HANDLE_GENERAL_CATEGORY_MUTANT, + PH_HANDLE_GENERAL_INDEX_MUTANTCOUNT, + L"Count", + NULL + ); + Context->ListViewRowCache[PH_HANDLE_GENERAL_INDEX_MUTANTABANDONED] = PhAddListViewGroupItem( + Context->ListViewHandle, + PH_HANDLE_GENERAL_CATEGORY_MUTANT, + PH_HANDLE_GENERAL_INDEX_MUTANTABANDONED, + L"Abandoned", + NULL + ); + Context->ListViewRowCache[PH_HANDLE_GENERAL_INDEX_MUTANTOWNER] = PhAddListViewGroupItem( + Context->ListViewHandle, + PH_HANDLE_GENERAL_CATEGORY_MUTANT, + PH_HANDLE_GENERAL_INDEX_MUTANTOWNER, + L"Owner", + NULL + ); + } } VOID PhpUpdateHandleGeneral( @@ -272,9 +461,9 @@ VOID PhpUpdateHandleGeneral( OBJECT_BASIC_INFORMATION basicInfo; WCHAR string[PH_PTR_STR_LEN]; - PhSetListViewSubItem(Context->ListViewHandle, PH_HANDLE_GENERAL_INDEX_NAME, 1, PhGetStringOrEmpty(Context->HandleItem->BestObjectName)); - PhSetListViewSubItem(Context->ListViewHandle, PH_HANDLE_GENERAL_INDEX_TYPE, 1, PhGetStringOrEmpty(Context->HandleItem->TypeName)); - PhSetListViewSubItem(Context->ListViewHandle, PH_HANDLE_GENERAL_INDEX_OBJECT, 1, Context->HandleItem->ObjectString); + PhSetListViewSubItem(Context->ListViewHandle, Context->ListViewRowCache[PH_HANDLE_GENERAL_INDEX_NAME], 1, PhGetStringOrEmpty(Context->HandleItem->BestObjectName)); + PhSetListViewSubItem(Context->ListViewHandle, Context->ListViewRowCache[PH_HANDLE_GENERAL_INDEX_TYPE], 1, PhGetStringOrEmpty(Context->HandleItem->TypeName)); + PhSetListViewSubItem(Context->ListViewHandle, Context->ListViewRowCache[PH_HANDLE_GENERAL_INDEX_OBJECT], 1, Context->HandleItem->ObjectString); if (PhGetAccessEntries( PhGetStringOrEmpty(Context->HandleItem->TypeName), @@ -346,6 +535,353 @@ VOID PhpUpdateHandleGeneral( NtClose(processHandle); } + + if (PhEqualString2(Context->HandleItem->TypeName, L"ALPC Port", TRUE)) + { + PHANDLE_PROPERTIES_CONTEXT context = Context; + NTSTATUS status; + HANDLE processHandle; + HANDLE alpcPortHandle; + + if (NT_SUCCESS(status = PhOpenProcess( + &processHandle, + PROCESS_DUP_HANDLE, + Context->ProcessId + ))) + { + status = NtDuplicateObject( + processHandle, + Context->HandleItem->Handle, + NtCurrentProcess(), + &alpcPortHandle, + READ_CONTROL, + 0, + 0 + ); + NtClose(processHandle); + } + + if (NT_SUCCESS(status)) + { + ALPC_BASIC_INFORMATION basicInfo; + + if (NT_SUCCESS(NtAlpcQueryInformation( + alpcPortHandle, + AlpcBasicInformation, + &basicInfo, + sizeof(ALPC_BASIC_INFORMATION), + NULL + ))) + { + PH_FORMAT format[1]; + PPH_STRING string; + + PhInitFormatI64UGroupDigits(&format[0], basicInfo.SequenceNo); + + string = PhFormat(format, 1, 128); + PhSetListViewSubItem(Context->ListViewHandle, Context->ListViewRowCache[PH_HANDLE_GENERAL_INDEX_SEQUENCENUMBER], 1, string->Buffer); + PhDereferenceObject(string); + + PhSetListViewSubItem(Context->ListViewHandle, Context->ListViewRowCache[PH_HANDLE_GENERAL_INDEX_PORTCONTEXT], 1, + PhaFormatString(L"0x%Ix", basicInfo.PortContext)->Buffer); + } + + NtClose(alpcPortHandle); + } + } + else if (PhEqualStringRef2(&Context->HandleItem->TypeName->sr, L"File", TRUE)) + { + PHANDLE_PROPERTIES_CONTEXT context = Context; + NTSTATUS status; + HANDLE processHandle; + HANDLE fileHandle; + + if (NT_SUCCESS(status = PhOpenProcess( + &processHandle, + PROCESS_DUP_HANDLE, + Context->ProcessId + ))) + { + status = NtDuplicateObject( + processHandle, + Context->HandleItem->Handle, + NtCurrentProcess(), + &fileHandle, + MAXIMUM_ALLOWED, + 0, + 0 + ); + NtClose(processHandle); + } + + if (NT_SUCCESS(status)) + { + BOOLEAN disableFlushButton = FALSE; + BOOLEAN isFileOrDirectory = FALSE; + FILE_FS_DEVICE_INFORMATION fileDeviceInfo; + FILE_MODE_INFORMATION fileModeInfo; + FILE_STANDARD_INFORMATION fileStandardInfo; + FILE_POSITION_INFORMATION filePositionInfo; + IO_STATUS_BLOCK isb; + + if (NT_SUCCESS(NtQueryVolumeInformationFile( + fileHandle, + &isb, + &fileDeviceInfo, + sizeof(FILE_FS_DEVICE_INFORMATION), + FileFsDeviceInformation + ))) + { + switch (fileDeviceInfo.DeviceType) + { + case FILE_DEVICE_NAMED_PIPE: + PhSetListViewSubItem(Context->ListViewHandle, Context->ListViewRowCache[PH_HANDLE_GENERAL_INDEX_FILETYPE], 1, L"Pipe"); + break; + case FILE_DEVICE_CD_ROM: + case FILE_DEVICE_CD_ROM_FILE_SYSTEM: + case FILE_DEVICE_CONTROLLER: + case FILE_DEVICE_DATALINK: + case FILE_DEVICE_DFS: + case FILE_DEVICE_DISK: + case FILE_DEVICE_DISK_FILE_SYSTEM: + case FILE_DEVICE_VIRTUAL_DISK: + isFileOrDirectory = TRUE; + PhSetListViewSubItem(Context->ListViewHandle, Context->ListViewRowCache[PH_HANDLE_GENERAL_INDEX_FILETYPE], 1, L"File or directory"); + break; + default: + PhSetListViewSubItem(Context->ListViewHandle, Context->ListViewRowCache[PH_HANDLE_GENERAL_INDEX_FILETYPE], 1, L"Other"); + break; + } + } + + if (NT_SUCCESS(NtQueryInformationFile( + fileHandle, + &isb, + &fileModeInfo, + sizeof(FILE_MODE_INFORMATION), + FileModeInformation + ))) + { + PH_FORMAT format[5]; + PPH_STRING fileModeAccessStr; + WCHAR fileModeString[MAX_PATH]; + + // Since FILE_MODE_INFORMATION has no flag for asynchronous I/O we should use our own flag and set + // it only if none of synchronous flags are present. That's why we need PhFileModeUpdAsyncFlag. + fileModeAccessStr = PhGetAccessString( + PhFileModeUpdAsyncFlag(fileModeInfo.Mode), + FileModeAccessEntries, + RTL_NUMBER_OF(FileModeAccessEntries) + ); + PhInitFormatS(&format[0], L"0x"); + PhInitFormatX(&format[1], fileModeInfo.Mode); + PhInitFormatS(&format[2], L" ("); + PhInitFormatSR(&format[3], fileModeAccessStr->sr); + PhInitFormatS(&format[4], L")"); + + if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), fileModeString, sizeof(fileModeString), NULL)) + { + PhSetListViewSubItem(Context->ListViewHandle, Context->ListViewRowCache[PH_HANDLE_GENERAL_INDEX_FILEMODE], 1, fileModeString); + } + + PhDereferenceObject(fileModeAccessStr); + } + + if (NT_SUCCESS(NtQueryInformationFile( + fileHandle, + &isb, + &fileStandardInfo, + sizeof(FILE_STANDARD_INFORMATION), + FileStandardInformation + ))) + { + PH_FORMAT format[1]; + WCHAR fileSizeString[PH_INT64_STR_LEN]; + + PhInitFormatSize(&format[0], fileStandardInfo.EndOfFile.QuadPart); + + if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), fileSizeString, sizeof(fileSizeString), NULL)) + { + PhSetListViewSubItem(Context->ListViewHandle, Context->ListViewRowCache[PH_HANDLE_GENERAL_INDEX_FILESIZE], 1, fileSizeString); + } + + if (isFileOrDirectory) + { + PhSetListViewSubItem(Context->ListViewHandle, Context->ListViewRowCache[PH_HANDLE_GENERAL_INDEX_FILETYPE], 1, fileStandardInfo.Directory ? L"Directory" : L"File"); + } + + disableFlushButton |= fileStandardInfo.Directory; + } + + if (NT_SUCCESS(NtQueryInformationFile( + fileHandle, + &isb, + &filePositionInfo, + sizeof(FILE_POSITION_INFORMATION), + FilePositionInformation + ))) + { + if (filePositionInfo.CurrentByteOffset.QuadPart != 0 && + fileStandardInfo.EndOfFile.QuadPart != 0) + { + PH_FORMAT format[4]; + WCHAR filePositionString[PH_INT64_STR_LEN]; + + PhInitFormatI64UGroupDigits(&format[0], filePositionInfo.CurrentByteOffset.QuadPart); + PhInitFormatS(&format[1], L" ("); + PhInitFormatF(&format[2], (DOUBLE)(filePositionInfo.CurrentByteOffset.QuadPart / fileStandardInfo.EndOfFile.QuadPart * 100), 1); + PhInitFormatS(&format[3], L"%)"); + + if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), filePositionString, sizeof(filePositionString), NULL)) + { + PhSetListViewSubItem(Context->ListViewHandle, Context->ListViewRowCache[PH_HANDLE_GENERAL_INDEX_FILEPOSITION], 1, filePositionString); + } + } + else + { + PH_FORMAT format[1]; + WCHAR filePositionString[PH_INT64_STR_LEN]; + + PhInitFormatI64UGroupDigits(&format[0], filePositionInfo.CurrentByteOffset.QuadPart); + + if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), filePositionString, sizeof(filePositionString), NULL)) + { + PhSetListViewSubItem(Context->ListViewHandle, Context->ListViewRowCache[PH_HANDLE_GENERAL_INDEX_FILEPOSITION], 1, filePositionString); + } + } + } + + NtClose(fileHandle); + } + } + else if (PhEqualStringRef2(&Context->HandleItem->TypeName->sr, L"Section", TRUE)) + { + PHANDLE_PROPERTIES_CONTEXT context = Context; + NTSTATUS status; + HANDLE processHandle; + HANDLE sectionHandle; + + if (NT_SUCCESS(status = PhOpenProcess( + &processHandle, + PROCESS_DUP_HANDLE, + Context->ProcessId + ))) + { + status = NtDuplicateObject( + processHandle, + Context->HandleItem->Handle, + NtCurrentProcess(), + §ionHandle, + SECTION_QUERY | SECTION_MAP_READ, + 0, + 0 + ); + + if (!NT_SUCCESS(status)) + { + status = NtDuplicateObject( + processHandle, + Context->HandleItem->Handle, + NtCurrentProcess(), + §ionHandle, + SECTION_QUERY, + 0, + 0 + ); + } + + NtClose(processHandle); + } + + if (NT_SUCCESS(status)) + { + SECTION_BASIC_INFORMATION basicInfo; + PWSTR sectionType = L"Unknown"; + PPH_STRING sectionSize = NULL; + PPH_STRING fileName = NULL; + + if (NT_SUCCESS(PhGetSectionBasicInformation(sectionHandle, &basicInfo))) + { + if (basicInfo.AllocationAttributes & SEC_COMMIT) + sectionType = L"Commit"; + else if (basicInfo.AllocationAttributes & SEC_FILE) + sectionType = L"File"; + else if (basicInfo.AllocationAttributes & SEC_IMAGE) + sectionType = L"Image"; + else if (basicInfo.AllocationAttributes & SEC_RESERVE) + sectionType = L"Reserve"; + + sectionSize = PhaFormatSize(basicInfo.MaximumSize.QuadPart, -1); + } + + if (NT_SUCCESS(PhGetSectionFileName(sectionHandle, &fileName))) + { + PPH_STRING newFileName; + + PH_AUTO(fileName); + + if (newFileName = PhResolveDevicePrefix(fileName)) + fileName = PH_AUTO(newFileName); + } + + PhSetListViewSubItem(Context->ListViewHandle, Context->ListViewRowCache[PH_HANDLE_GENERAL_INDEX_SECTIONTYPE], 1, sectionType); + PhSetListViewSubItem(Context->ListViewHandle, Context->ListViewRowCache[PH_HANDLE_GENERAL_INDEX_SECTIONFILE], 1, PhGetStringOrDefault(fileName, L"N/A")); + PhSetListViewSubItem(Context->ListViewHandle, Context->ListViewRowCache[PH_HANDLE_GENERAL_INDEX_SECTIONSIZE], 1, PhGetStringOrDefault(sectionSize, L"Unknown")); + + NtClose(sectionHandle); + } + } + else if (PhEqualString2(Context->HandleItem->TypeName, L"Mutant", TRUE)) + { + PHANDLE_PROPERTIES_CONTEXT context = Context; + NTSTATUS status; + HANDLE processHandle; + HANDLE mutantHandle; + + if (NT_SUCCESS(status = PhOpenProcess( + &processHandle, + PROCESS_DUP_HANDLE, + Context->ProcessId + ))) + { + status = NtDuplicateObject( + processHandle, + Context->HandleItem->Handle, + NtCurrentProcess(), + &mutantHandle, + SEMAPHORE_QUERY_STATE, + 0, + 0 + ); + NtClose(processHandle); + } + + if (NT_SUCCESS(status)) + { + MUTANT_BASIC_INFORMATION basicInfo; + MUTANT_OWNER_INFORMATION ownerInfo; + + if (NT_SUCCESS(PhGetMutantBasicInformation(mutantHandle, &basicInfo))) + { + PhSetListViewSubItem(Context->ListViewHandle, Context->ListViewRowCache[PH_HANDLE_GENERAL_INDEX_MUTANTCOUNT], 1, PhaFormatUInt64(basicInfo.CurrentCount, TRUE)->Buffer); + PhSetListViewSubItem(Context->ListViewHandle, Context->ListViewRowCache[PH_HANDLE_GENERAL_INDEX_MUTANTABANDONED], 1, basicInfo.AbandonedState ? L"True" : L"False"); + } + + if (NT_SUCCESS(PhGetMutantOwnerInformation(mutantHandle, &ownerInfo))) + { + PPH_STRING name; + + if (ownerInfo.ClientId.UniqueProcess) + { + name = PhStdGetClientIdName(&ownerInfo.ClientId); + PhSetListViewSubItem(Context->ListViewHandle, Context->ListViewRowCache[PH_HANDLE_GENERAL_INDEX_MUTANTOWNER], 1, name->Buffer); + PhDereferenceObject(name); + } + } + + NtClose(mutantHandle); + } + } } INT_PTR CALLBACK PhpHandleGeneralDlgProc( @@ -389,7 +925,7 @@ INT_PTR CALLBACK PhpHandleGeneralDlgProc( PhInitializeLayoutManager(&context->LayoutManager, hwndDlg); PhAddLayoutItem(&context->LayoutManager, context->ListViewHandle, NULL, PH_ANCHOR_ALL); - PhpUpdateHandleGeneralListViewGroups(context->ListViewHandle); + PhpUpdateHandleGeneralListViewGroups(context); PhpUpdateHandleGeneral(context); EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); @@ -397,6 +933,8 @@ INT_PTR CALLBACK PhpHandleGeneralDlgProc( break; case WM_DESTROY: { + PhDeleteLayoutManager(&context->LayoutManager); + PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); } break; diff --git a/ProcessHacker/include/phapp.h b/ProcessHacker/include/phapp.h index 2d4da158b7db..2e2958f9bb30 100644 --- a/ProcessHacker/include/phapp.h +++ b/ProcessHacker/include/phapp.h @@ -500,21 +500,6 @@ HPROPSHEETPAGE PhCreateEventPairPage( _In_opt_ PVOID Context ); -HPROPSHEETPAGE PhCreateFilePage( - _In_ PPH_OPEN_OBJECT OpenObject, - _In_opt_ PVOID Context - ); - -HPROPSHEETPAGE PhCreateMutantPage( - _In_ PPH_OPEN_OBJECT OpenObject, - _In_opt_ PVOID Context - ); - -HPROPSHEETPAGE PhCreateSectionPage( - _In_ PPH_OPEN_OBJECT OpenObject, - _In_opt_ PVOID Context - ); - HPROPSHEETPAGE PhCreateSemaphorePage( _In_ PPH_OPEN_OBJECT OpenObject, _In_opt_ PVOID Context diff --git a/ProcessHacker/ntobjprp.c b/ProcessHacker/ntobjprp.c index 72b67c6e49e5..e74f956951c0 100644 --- a/ProcessHacker/ntobjprp.c +++ b/ProcessHacker/ntobjprp.c @@ -34,20 +34,6 @@ typedef struct _COMMON_PAGE_CONTEXT PVOID Context; } COMMON_PAGE_CONTEXT, *PCOMMON_PAGE_CONTEXT; -#define PH_FILEMODE_ASYNC 0x01000000 -#define PhFileModeUpdAsyncFlag(mode) \ - (mode & (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT) ? mode &~ PH_FILEMODE_ASYNC: mode | PH_FILEMODE_ASYNC) - -PH_ACCESS_ENTRY FileModeAccessEntries[6] = -{ - { L"FILE_FLAG_OVERLAPPED", PH_FILEMODE_ASYNC, FALSE, FALSE, L"Asynchronous" }, - { L"FILE_FLAG_WRITE_THROUGH", FILE_WRITE_THROUGH, FALSE, FALSE, L"Write through" }, - { L"FILE_FLAG_SEQUENTIAL_SCAN", FILE_SEQUENTIAL_ONLY, FALSE, FALSE, L"Sequental" }, - { L"FILE_FLAG_NO_BUFFERING", FILE_NO_INTERMEDIATE_BUFFERING, FALSE, FALSE, L"No buffering" }, - { L"FILE_SYNCHRONOUS_IO_ALERT", FILE_SYNCHRONOUS_IO_ALERT, FALSE, FALSE, L"Synchronous alert" }, - { L"FILE_SYNCHRONOUS_IO_NONALERT", FILE_SYNCHRONOUS_IO_NONALERT, FALSE, FALSE, L"Synchronous non-alert" }, -}; - HPROPSHEETPAGE PhpCommonCreatePage( _In_ PPH_OPEN_OBJECT OpenObject, _In_opt_ PVOID Context, @@ -75,27 +61,6 @@ INT_PTR CALLBACK PhpEventPairPageProc( _In_ LPARAM lParam ); -INT_PTR CALLBACK PhpFilePageProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -INT_PTR CALLBACK PhpMutantPageProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -INT_PTR CALLBACK PhpSectionPageProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - INT_PTR CALLBACK PhpSemaphorePageProc( _In_ HWND hwndDlg, _In_ UINT uMsg, @@ -370,431 +335,6 @@ INT_PTR CALLBACK PhpEventPairPageProc( return FALSE; } -HPROPSHEETPAGE PhCreateFilePage( - _In_ PPH_OPEN_OBJECT OpenObject, - _In_opt_ PVOID Context - ) -{ - return PhpCommonCreatePage( - OpenObject, - Context, - MAKEINTRESOURCE(IDD_OBJFILE), - PhpFilePageProc - ); -} - -static VOID PhpRefreshFilePageInfo( - _In_ HWND hwndDlg, - _In_ PCOMMON_PAGE_CONTEXT PageContext - ) -{ - HANDLE fileHandle; - - if (NT_SUCCESS(PageContext->OpenObject( - &fileHandle, - MAXIMUM_ALLOWED, - PageContext->Context - ))) - { - NTSTATUS statusStandardInfo; - IO_STATUS_BLOCK ioStatusBlock; - FILE_MODE_INFORMATION fileModeInfo; - FILE_STANDARD_INFORMATION fileStandardInfo; - FILE_POSITION_INFORMATION filePositionInfo; - FILE_FS_DEVICE_INFORMATION deviceInformation; - BOOLEAN disableFlushButton = FALSE; - BOOLEAN isFileOrDirectory = FALSE; - - // Obtain the file type - if (NT_SUCCESS(NtQueryVolumeInformationFile( - fileHandle, - &ioStatusBlock, - &deviceInformation, - sizeof(FILE_FS_DEVICE_INFORMATION), - FileFsDeviceInformation - ))) - { - switch (deviceInformation.DeviceType) - { - case FILE_DEVICE_NAMED_PIPE: - PhSetDialogItemText(hwndDlg, IDC_FILETYPE, L"Pipe"); - break; - case FILE_DEVICE_CD_ROM: - case FILE_DEVICE_CD_ROM_FILE_SYSTEM: - case FILE_DEVICE_CONTROLLER: - case FILE_DEVICE_DATALINK: - case FILE_DEVICE_DFS: - case FILE_DEVICE_DISK: - case FILE_DEVICE_DISK_FILE_SYSTEM: - case FILE_DEVICE_VIRTUAL_DISK: - isFileOrDirectory = TRUE; - PhSetDialogItemText(hwndDlg, IDC_FILETYPE, L"File or directory"); - break; - default: - PhSetDialogItemText(hwndDlg, IDC_FILETYPE, L"Other"); - break; - } - } - - // Obtain the file size and distinguish files from directories - if (NT_SUCCESS(statusStandardInfo = NtQueryInformationFile( - fileHandle, - &ioStatusBlock, - &fileStandardInfo, - sizeof(FILE_STANDARD_INFORMATION), - FileStandardInformation - ))) - { - PPH_STRING fileSizeStr; - - disableFlushButton |= fileStandardInfo.Directory; - - fileSizeStr = PhFormatSize(fileStandardInfo.EndOfFile.QuadPart, -1); - PhSetDialogItemText(hwndDlg, IDC_FILESIZE, fileSizeStr->Buffer); - PhDereferenceObject(fileSizeStr); - - if (isFileOrDirectory) - { - PhSetDialogItemText(hwndDlg, IDC_FILETYPE, fileStandardInfo.Directory ? L"Directory" : L"File"); - } - } - - // Obtain current position - if (NT_SUCCESS(NtQueryInformationFile( - fileHandle, - &ioStatusBlock, - &filePositionInfo, - sizeof(FILE_POSITION_INFORMATION), - FilePositionInformation - ))) - { - PPH_STRING filePosStr; - - // If we also know the size of the file, we can calculate the percentage - if (NT_SUCCESS(statusStandardInfo) && - filePositionInfo.CurrentByteOffset.QuadPart != 0 && - fileStandardInfo.EndOfFile.QuadPart != 0 - ) - { - PH_FORMAT format[4]; - - PhInitFormatI64U(&format[0], filePositionInfo.CurrentByteOffset.QuadPart); - format[0].Type |= FormatGroupDigits; - PhInitFormatS(&format[1], L" ("); - PhInitFormatF(&format[2], (DOUBLE)(filePositionInfo.CurrentByteOffset.QuadPart / fileStandardInfo.EndOfFile.QuadPart * 100), 1); - PhInitFormatS(&format[3], L"%)"); - - filePosStr = PhFormat(format, 4, 18); - } - else // or we can't - { - filePosStr = PhFormatUInt64(filePositionInfo.CurrentByteOffset.QuadPart, TRUE); - } - - PhSetDialogItemText(hwndDlg, IDC_POSITION, filePosStr->Buffer); - PhDereferenceObject(filePosStr); - } - - // Obtain the file mode - if (NT_SUCCESS(NtQueryInformationFile( - fileHandle, - &ioStatusBlock, - &fileModeInfo, - sizeof(FILE_MODE_INFORMATION), - FileModeInformation - ))) - { - PH_FORMAT format[5]; - PPH_STRING fileModeStr; - PPH_STRING fileModeAccessStr; - - disableFlushButton |= fileModeInfo.Mode & (FILE_WRITE_THROUGH | FILE_NO_INTERMEDIATE_BUFFERING); - - // Since FILE_MODE_INFORMATION has no flag for asynchronous I/O we should use our own flag and set - // it only if none of synchronous flags are present. That's why we need PhFileModeUpdAsyncFlag. - fileModeAccessStr = PhGetAccessString( - PhFileModeUpdAsyncFlag(fileModeInfo.Mode), - FileModeAccessEntries, - sizeof(FileModeAccessEntries) / sizeof(PH_ACCESS_ENTRY) - ); - - PhInitFormatS(&format[0], L"0x"); - PhInitFormatX(&format[1], fileModeInfo.Mode); - PhInitFormatS(&format[2], L" ("); - PhInitFormatSR(&format[3], fileModeAccessStr->sr); - PhInitFormatS(&format[4], L")"); - - fileModeStr = PhFormat(format, 5, 64); - PhSetDialogItemText(hwndDlg, IDC_FILEMODE, fileModeStr->Buffer); - - PhDereferenceObject(fileModeStr); - PhDereferenceObject(fileModeAccessStr); - } - else - { - PhSetDialogItemText(hwndDlg, IDC_FILEMODE, L"Unknown"); - } - - EnableWindow(GetDlgItem(hwndDlg, IDC_FLUSH), !disableFlushButton); - - NtClose(fileHandle); - } -} - -INT_PTR CALLBACK PhpFilePageProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - PCOMMON_PAGE_CONTEXT pageContext; - - if (!(pageContext = PhpCommonPageHeader(hwndDlg, uMsg, wParam, lParam))) - return FALSE; - - switch (uMsg) - { - case WM_INITDIALOG: - { - PhpRefreshFilePageInfo(hwndDlg, pageContext); - } - break; - case WM_COMMAND: - { - switch (GET_WM_COMMAND_ID(wParam, lParam)) - { - case IDC_FLUSH: - { - NTSTATUS status; - HANDLE fileHandle; - - if (NT_SUCCESS(status = pageContext->OpenObject( - &fileHandle, - GENERIC_WRITE, - pageContext->Context - ))) - { - IO_STATUS_BLOCK isb; - - status = NtFlushBuffersFile(fileHandle, &isb); - - NtClose(fileHandle); - } - - if (!NT_SUCCESS(status)) - PhShowStatus(hwndDlg, L"Unable to flush the file.", status, 0); - } - break; - } - } - break; - case WM_NOTIFY: - { - LPNMHDR header = (LPNMHDR)lParam; - - switch (header->code) - { - case PSN_QUERYINITIALFOCUS: - { - SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, (LONG_PTR)GetDlgItem(hwndDlg, IDC_FLUSH)); - } - return TRUE; - } - } - break; - } - - return FALSE; -} - -HPROPSHEETPAGE PhCreateMutantPage( - _In_ PPH_OPEN_OBJECT OpenObject, - _In_opt_ PVOID Context - ) -{ - return PhpCommonCreatePage( - OpenObject, - Context, - MAKEINTRESOURCE(IDD_OBJMUTANT), - PhpMutantPageProc - ); -} - -static VOID PhpRefreshMutantPageInfo( - _In_ HWND hwndDlg, - _In_ PCOMMON_PAGE_CONTEXT PageContext - ) -{ - HANDLE mutantHandle; - - if (NT_SUCCESS(PageContext->OpenObject( - &mutantHandle, - SEMAPHORE_QUERY_STATE, - PageContext->Context - ))) - { - MUTANT_BASIC_INFORMATION basicInfo; - MUTANT_OWNER_INFORMATION ownerInfo; - - if (NT_SUCCESS(PhGetMutantBasicInformation(mutantHandle, &basicInfo))) - { - PhSetDialogItemValue(hwndDlg, IDC_COUNT, basicInfo.CurrentCount, TRUE); - PhSetDialogItemText(hwndDlg, IDC_ABANDONED, basicInfo.AbandonedState ? L"True" : L"False"); - } - else - { - PhSetDialogItemText(hwndDlg, IDC_COUNT, L"Unknown"); - PhSetDialogItemText(hwndDlg, IDC_ABANDONED, L"Unknown"); - } - - if (NT_SUCCESS(PhGetMutantOwnerInformation(mutantHandle, &ownerInfo))) - { - PPH_STRING name; - - if (ownerInfo.ClientId.UniqueProcess) - { - name = PhGetClientIdName(&ownerInfo.ClientId); - PhSetDialogItemText(hwndDlg, IDC_OWNER, name->Buffer); - PhDereferenceObject(name); - } - else - { - PhSetDialogItemText(hwndDlg, IDC_OWNER, L"N/A"); - } - } - else - { - PhSetDialogItemText(hwndDlg, IDC_OWNER, L"Unknown"); - } - - NtClose(mutantHandle); - } -} - -INT_PTR CALLBACK PhpMutantPageProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - PCOMMON_PAGE_CONTEXT pageContext; - - pageContext = PhpCommonPageHeader(hwndDlg, uMsg, wParam, lParam); - - if (!pageContext) - return FALSE; - - switch (uMsg) - { - case WM_INITDIALOG: - { - PhpRefreshMutantPageInfo(hwndDlg, pageContext); - } - break; - } - - return FALSE; -} - -HPROPSHEETPAGE PhCreateSectionPage( - _In_ PPH_OPEN_OBJECT OpenObject, - _In_opt_ PVOID Context - ) -{ - return PhpCommonCreatePage( - OpenObject, - Context, - MAKEINTRESOURCE(IDD_OBJSECTION), - PhpSectionPageProc - ); -} - -static VOID PhpRefreshSectionPageInfo( - _In_ HWND hwndDlg, - _In_ PCOMMON_PAGE_CONTEXT PageContext - ) -{ - HANDLE sectionHandle; - SECTION_BASIC_INFORMATION basicInfo; - PWSTR sectionType = L"Unknown"; - PPH_STRING sectionSize = NULL; - PPH_STRING fileName = NULL; - - if (!NT_SUCCESS(PageContext->OpenObject( - §ionHandle, - SECTION_QUERY | SECTION_MAP_READ, - PageContext->Context - ))) - { - if (!NT_SUCCESS(PageContext->OpenObject( - §ionHandle, - SECTION_QUERY | SECTION_MAP_READ, - PageContext->Context - ))) - { - return; - } - } - - if (NT_SUCCESS(PhGetSectionBasicInformation(sectionHandle, &basicInfo))) - { - if (basicInfo.AllocationAttributes & SEC_COMMIT) - sectionType = L"Commit"; - else if (basicInfo.AllocationAttributes & SEC_FILE) - sectionType = L"File"; - else if (basicInfo.AllocationAttributes & SEC_IMAGE) - sectionType = L"Image"; - else if (basicInfo.AllocationAttributes & SEC_RESERVE) - sectionType = L"Reserve"; - - sectionSize = PhaFormatSize(basicInfo.MaximumSize.QuadPart, -1); - } - - if (NT_SUCCESS(PhGetSectionFileName(sectionHandle, &fileName))) - { - PPH_STRING newFileName; - - PH_AUTO(fileName); - - if (newFileName = PhResolveDevicePrefix(fileName)) - fileName = PH_AUTO(newFileName); - } - - PhSetDialogItemText(hwndDlg, IDC_TYPE, sectionType); - PhSetDialogItemText(hwndDlg, IDC_SIZE_, PhGetStringOrDefault(sectionSize, L"Unknown")); - PhSetDialogItemText(hwndDlg, IDC_FILE, PhGetStringOrDefault(fileName, L"N/A")); - - NtClose(sectionHandle); -} - -INT_PTR CALLBACK PhpSectionPageProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - PCOMMON_PAGE_CONTEXT pageContext; - - pageContext = PhpCommonPageHeader(hwndDlg, uMsg, wParam, lParam); - - if (!pageContext) - return FALSE; - - switch (uMsg) - { - case WM_INITDIALOG: - { - PhpRefreshSectionPageInfo(hwndDlg, pageContext); - } - break; - } - - return FALSE; -} - HPROPSHEETPAGE PhCreateSemaphorePage( _In_ PPH_OPEN_OBJECT OpenObject, _In_opt_ PVOID Context From e0177ecbc30c89660f3c1264b5757194064ee519 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 6 Jul 2018 18:20:56 +1000 Subject: [PATCH 1089/2058] Remove legacy handle dialog resources --- ProcessHacker/ProcessHacker.rc | 45 ---------------------------------- 1 file changed, 45 deletions(-) diff --git a/ProcessHacker/ProcessHacker.rc b/ProcessHacker/ProcessHacker.rc index 95756d29683f..deb6cdec88aa 100644 --- a/ProcessHacker/ProcessHacker.rc +++ b/ProcessHacker/ProcessHacker.rc @@ -838,22 +838,6 @@ BEGIN PUSHBUTTON "Pulse",IDC_PULSE,115,34,50,14 END -IDD_OBJFILE DIALOGEX 0, 0, 257, 86 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "File" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "Type:",IDC_STATIC,7,7,28,8 - LTEXT "Unknown",IDC_FILETYPE,40,7,210,8 - LTEXT "Position:",IDC_STATIC,7,29,28,8 - LTEXT "Unknown",IDC_POSITION,40,29,210,8 - LTEXT "File size:",IDC_STATIC,7,40,28,8 - LTEXT "Unknown",IDC_FILESIZE,40,40,210,8 - PUSHBUTTON "Flush",IDC_FLUSH,7,56,50,14 - LTEXT "Mode:",IDC_STATIC,7,18,28,8 - EDITTEXT IDC_FILEMODE,40,18,207,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER -END - IDD_OBJMUTANT DIALOGEX 0, 0, 186, 76 STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Mutant" @@ -942,19 +926,6 @@ BEGIN PUSHBUTTON "Set high",IDC_SETHIGH,61,7,50,14 END -IDD_OBJSECTION DIALOGEX 0, 0, 255, 76 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Section" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "Type:",IDC_STATIC,7,7,20,8 - LTEXT "Unknown",IDC_TYPE,43,7,205,8 - LTEXT "Size:",IDC_STATIC,7,18,16,8 - LTEXT "Unknown",IDC_SIZE_,43,18,205,8 - LTEXT "File:",IDC_STATIC,7,29,14,8 - EDITTEXT IDC_FILE,43,29,205,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER -END - IDD_AFFINITY DIALOGEX 0, 0, 279, 227 STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Affinity" @@ -1963,14 +1934,6 @@ BEGIN BOTTOMMARGIN, 69 END - IDD_OBJFILE, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 250 - TOPMARGIN, 7 - BOTTOMMARGIN, 79 - END - IDD_OBJMUTANT, DIALOG BEGIN LEFTMARGIN, 7 @@ -2011,14 +1974,6 @@ BEGIN BOTTOMMARGIN, 69 END - IDD_OBJSECTION, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 248 - TOPMARGIN, 7 - BOTTOMMARGIN, 69 - END - IDD_AFFINITY, DIALOG BEGIN LEFTMARGIN, 7 From ac47d22dfecd5c789bb5b92649e101e6fabb6765 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 6 Jul 2018 18:39:30 +1000 Subject: [PATCH 1090/2058] Fix double-click opening the environment variable editor --- ProcessHacker/prpgenv.c | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/ProcessHacker/prpgenv.c b/ProcessHacker/prpgenv.c index 25073a435525..6b8cb2c42c0c 100644 --- a/ProcessHacker/prpgenv.c +++ b/ProcessHacker/prpgenv.c @@ -485,6 +485,9 @@ VOID PhpShowEnvironmentNodeContextMenu( if (!(node = PhpGetSelectedEnvironmentNode(Context))) return; + if (node->Type == PROCESS_ENVIRONMENT_TREENODE_TYPE_GROUP) + return; + menu = PhCreateEMenu(); PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ENVIRONMENT_TREE_COLUMN_MENU_ITEM_EDIT, L"Edit", NULL, NULL), ULONG_MAX); PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX); @@ -1069,6 +1072,11 @@ BOOLEAN NTAPI PhpEnvironmentTreeNewCallback( PhDeleteTreeNewColumnMenu(&data); } return TRUE; + case TreeNewLeftDoubleClick: + { + SendMessage(context->WindowHandle, WM_COMMAND, WM_PH_SET_LIST_VIEW_SETTINGS, 0); // HACK + } + return TRUE; } return FALSE; @@ -1418,6 +1426,37 @@ INT_PTR CALLBACK PhpProcessEnvironmentDlgProc( PhpRefreshEnvironmentList(hwndDlg, context, processItem); } break; + case WM_PH_SET_LIST_VIEW_SETTINGS: // HACK + { + PPHP_PROCESS_ENVIRONMENT_TREENODE item = PhpGetSelectedEnvironmentNode(context); + BOOLEAN refresh; + + if (!item || item->Type == PROCESS_ENVIRONMENT_TREENODE_TYPE_GROUP) + break; + + if (PhGetIntegerSetting(L"EnableWarnings") && !PhShowConfirmMessage( + hwndDlg, + L"edit", + L"the selected environment variable", + L"Some programs may restrict access or ban your account when editing the environment variable(s) of the process.", + FALSE + )) + { + break; + } + + if (PhpShowEditEnvDialog( + hwndDlg, + context->ProcessItem, + item->NameText->Buffer, + item->ValueText->Buffer, + &refresh + ) == IDOK && refresh) + { + PhpRefreshEnvironmentList(hwndDlg, context, context->ProcessItem); + } + } + break; } } break; From a35f296bc7473b17df5fb5fea8155d44a81a3d89 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 6 Jul 2018 20:36:30 +1000 Subject: [PATCH 1091/2058] ExtendedTools: Remove legacy handle dialog resource --- plugins/ExtendedTools/ExtendedTools.rc | 17 ------- plugins/ExtendedTools/objprp.c | 68 +------------------------- plugins/ExtendedTools/resource.h | 4 -- 3 files changed, 1 insertion(+), 88 deletions(-) diff --git a/plugins/ExtendedTools/ExtendedTools.rc b/plugins/ExtendedTools/ExtendedTools.rc index cc9a500b4113..445ca8fb8fe9 100644 --- a/plugins/ExtendedTools/ExtendedTools.rc +++ b/plugins/ExtendedTools/ExtendedTools.rc @@ -97,15 +97,6 @@ BEGIN DEFPUSHBUTTON "Close",IDOK,285,244,50,14 END -IDD_OBJALPCPORT DIALOGEX 0, 0, 160, 101 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "ALPC Port" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "Sequence number: Unknown",IDC_SEQUENCENUMBER,7,7,146,8 - LTEXT "Port context: Unknown",IDC_PORTCONTEXT,7,19,146,8 -END - IDD_OBJTPWORKERFACTORY DIALOGEX 0, 0, 186, 101 STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Worker Factory" @@ -375,14 +366,6 @@ BEGIN BOTTOMMARGIN, 258 END - IDD_OBJALPCPORT, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 153 - TOPMARGIN, 7 - BOTTOMMARGIN, 94 - END - IDD_OBJTPWORKERFACTORY, DIALOG BEGIN LEFTMARGIN, 7 diff --git a/plugins/ExtendedTools/objprp.c b/plugins/ExtendedTools/objprp.c index 5f65f10badcc..8ac70e6b4788 100644 --- a/plugins/ExtendedTools/objprp.c +++ b/plugins/ExtendedTools/objprp.c @@ -41,13 +41,6 @@ INT CALLBACK EtpCommonPropPageProc( _In_ LPPROPSHEETPAGE ppsp ); -INT_PTR CALLBACK EtpAlpcPortPageDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - INT_PTR CALLBACK EtpTpWorkerFactoryPageDlgProc( _In_ HWND hwndDlg, _In_ UINT uMsg, @@ -69,15 +62,7 @@ VOID EtHandlePropertiesInitializing( { HPROPSHEETPAGE page = NULL; - if (PhEqualString2(context->HandleItem->TypeName, L"ALPC Port", TRUE)) - { - page = EtpCommonCreatePage( - context, - MAKEINTRESOURCE(IDD_OBJALPCPORT), - EtpAlpcPortPageDlgProc - ); - } - else if (PhEqualString2(context->HandleItem->TypeName, L"TpWorkerFactory", TRUE)) + if (PhEqualString2(context->HandleItem->TypeName, L"TpWorkerFactory", TRUE)) { page = EtpCommonCreatePage( context, @@ -180,57 +165,6 @@ static NTSTATUS EtpDuplicateHandleFromProcess( return status; } -INT_PTR CALLBACK EtpAlpcPortPageDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - switch (uMsg) - { - case WM_INITDIALOG: - { - LPPROPSHEETPAGE propSheetPage = (LPPROPSHEETPAGE)lParam; - PCOMMON_PAGE_CONTEXT context = (PCOMMON_PAGE_CONTEXT)propSheetPage->lParam; - HANDLE portHandle; - - if (NT_SUCCESS(EtpDuplicateHandleFromProcess(&portHandle, READ_CONTROL, context))) - { - ALPC_BASIC_INFORMATION basicInfo; - - if (NT_SUCCESS(NtAlpcQueryInformation( - portHandle, - AlpcBasicInformation, - &basicInfo, - sizeof(ALPC_BASIC_INFORMATION), - NULL - ))) - { - PH_FORMAT format[2]; - PPH_STRING string; - - PhInitFormatS(&format[0], L"Sequence Number: "); - PhInitFormatD(&format[1], basicInfo.SequenceNo); - format[1].Type |= FormatGroupDigits; - - string = PhFormat(format, 2, 128); - PhSetDialogItemText(hwndDlg, IDC_SEQUENCENUMBER, string->Buffer); - PhDereferenceObject(string); - - PhSetDialogItemText(hwndDlg, IDC_PORTCONTEXT, - PhaFormatString(L"Port Context: 0x%Ix", basicInfo.PortContext)->Buffer); - } - - NtClose(portHandle); - } - } - break; - } - - return FALSE; -} - static BOOLEAN NTAPI EnumGenericModulesCallback( _In_ PPH_MODULE_INFO Module, _In_opt_ PVOID Context diff --git a/plugins/ExtendedTools/resource.h b/plugins/ExtendedTools/resource.h index 8dbc1268616f..a550c87db3b5 100644 --- a/plugins/ExtendedTools/resource.h +++ b/plugins/ExtendedTools/resource.h @@ -4,7 +4,6 @@ // #define ID_PROCESS_UNLOADEDMODULES 101 #define IDD_UNLOADEDDLLS 102 -#define IDD_OBJALPCPORT 103 #define ID_THREAD_CANCELIO 104 #define IDD_OBJTPWORKERFACTORY 105 #define ID_MODULE_SERVICES 106 @@ -34,8 +33,6 @@ #define IDD_SYSINFO_GPUDETAILS 141 #define IDC_LIST 1001 #define IDC_REFRESH 1002 -#define IDC_SEQUENCENUMBER 1003 -#define IDC_PORTCONTEXT 1004 #define IDC_WORKERTHREADSTART 1005 #define IDC_WORKERTHREADCONTEXT 1006 #define IDC_SERVICES_LAYOUT 1007 @@ -100,7 +97,6 @@ #define IDC_GPUDETAILS 1090 #define IDC_BUTTON1 1092 #define IDC_DETAILS 1092 -#define IDC_LIST1 1093 #define IDC_GPULIST 1093 #define ID_DISK_GOTOPROCESS 40005 #define ID_DISK_COPY 40006 From fd3eb0994640c51c3ecf68035950e129514a456e Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 6 Jul 2018 22:09:54 +1000 Subject: [PATCH 1092/2058] Improve symbol provider initialization --- phlib/symprv.c | 99 +++++++++++++++++++------------------------------- 1 file changed, 37 insertions(+), 62 deletions(-) diff --git a/phlib/symprv.c b/phlib/symprv.c index 68565c9ed237..9a5052e4c3db 100644 --- a/phlib/symprv.c +++ b/phlib/symprv.c @@ -245,89 +245,64 @@ VOID PhpSymbolProviderCompleteInitialization( VOID ) { + static PH_STRINGREF dbghelpFileName = PH_STRINGREF_INIT(L"dbghelp.dll"); + static PH_STRINGREF symsrvFileName = PH_STRINGREF_INIT(L"symsrv.dll"); static struct { PH_STRINGREF AppendPath; } locations[] = { #ifdef _WIN64 - PH_STRINGREF_INIT(L"%ProgramFiles(x86)%\\Windows Kits\\10\\Debuggers\\x64\\dbghelp.dll"), - PH_STRINGREF_INIT(L"%ProgramFiles%\\Windows Kits\\10\\Debuggers\\x64\\dbghelp.dll"), - PH_STRINGREF_INIT(L"%ProgramFiles(x86)%\\Windows Kits\\8.1\\Debuggers\\x64\\dbghelp.dll"), - PH_STRINGREF_INIT(L"%ProgramFiles(x86)%\\Windows Kits\\8.0\\Debuggers\\x64\\dbghelp.dll"), - PH_STRINGREF_INIT(L"%ProgramFiles%\\Debugging Tools for Windows (x64)\\dbghelp.dll") + PH_STRINGREF_INIT(L"%ProgramFiles(x86)%\\Windows Kits\\10\\Debuggers\\x64\\"), + PH_STRINGREF_INIT(L"%ProgramFiles%\\Windows Kits\\10\\Debuggers\\x64\\"), + PH_STRINGREF_INIT(L"%ProgramFiles(x86)%\\Windows Kits\\8.1\\Debuggers\\x64\\"), + PH_STRINGREF_INIT(L"%ProgramFiles(x86)%\\Windows Kits\\8.0\\Debuggers\\x64\\"), + PH_STRINGREF_INIT(L"%ProgramFiles%\\Debugging Tools for Windows (x64)\\") #else - PH_STRINGREF_INIT(L"%ProgramFiles%\\Windows Kits\\10\\Debuggers\\x86\\dbghelp.dll"), - PH_STRINGREF_INIT(L"%ProgramFiles%\\Windows Kits\\8.1\\Debuggers\\x86\\dbghelp.dll"), - PH_STRINGREF_INIT(L"%ProgramFiles%\\Windows Kits\\8.0\\Debuggers\\x86\\dbghelp.dll"), - PH_STRINGREF_INIT(L"%ProgramFiles%\\Debugging Tools for Windows (x86)\\dbghelp.dll") + PH_STRINGREF_INIT(L"%ProgramFiles%\\Windows Kits\\10\\Debuggers\\x86\\"), + PH_STRINGREF_INIT(L"%ProgramFiles%\\Windows Kits\\8.1\\Debuggers\\x86\\"), + PH_STRINGREF_INIT(L"%ProgramFiles%\\Windows Kits\\8.0\\Debuggers\\x86\\"), + PH_STRINGREF_INIT(L"%ProgramFiles%\\Debugging Tools for Windows (x86)\\") #endif }; - static struct - { - PH_STRINGREF AppendPath; - } symsrvlocation[] = + PVOID dbghelpHandle = NULL; + PVOID symsrvHandle = NULL; + ULONG i; + + if (PhFindLoaderEntry(NULL, NULL, &dbghelpFileName) && + PhFindLoaderEntry(NULL, NULL, &symsrvFileName)) { -#ifdef _WIN64 - { PH_STRINGREF_INIT(L"%ProgramFiles(x86)%\\Windows Kits\\10\\Debuggers\\x64\\symsrv.dll") }, - { PH_STRINGREF_INIT(L"%ProgramFiles(x86)%\\Windows Kits\\8.1\\Debuggers\\x64\\symsrv.dll") }, - { PH_STRINGREF_INIT(L"%ProgramFiles(x86)%\\Windows Kits\\8.0\\Debuggers\\x64\\symsrv.dll") }, - { PH_STRINGREF_INIT(L"%ProgramFiles%\\Debugging Tools for Windows (x64)\\symsrv.dll") } -#else - { CSIDL_PROGRAM_FILES, L"%ProgramFiles%\\Windows Kits\\10\\Debuggers\\x86\\symsrv.dll" }, - { CSIDL_PROGRAM_FILES, L"%ProgramFiles%\\Windows Kits\\8.1\\Debuggers\\x86\\symsrv.dll" }, - { CSIDL_PROGRAM_FILES, L"%ProgramFiles%\\Windows Kits\\8.0\\Debuggers\\x86\\symsrv.dll" }, - { CSIDL_PROGRAM_FILES, L"%ProgramFiles%\\Debugging Tools for Windows (x86)\\symsrv.dll" } -#endif - }; + return; + } - PVOID dbghelpHandle; - PVOID symsrvHandle; - PPH_STRING dbghelpPath = NULL; + for (i = 0; i < RTL_NUMBER_OF(locations); i++) + { + PPH_STRING dbghelpPath; + PPH_STRING dbghelpName; + PPH_STRING symsrvName; - dbghelpHandle = PhGetDllHandle(L"dbghelp.dll"); - symsrvHandle = PhGetDllHandle(L"symsrv.dll"); + if (!(dbghelpPath = PhExpandEnvironmentStrings(&locations[i].AppendPath))) + continue; - if (dbghelpHandle && symsrvHandle) - return; + dbghelpName = PhConcatStringRef2(&dbghelpPath->sr, &dbghelpFileName); + symsrvName = PhConcatStringRef2(&dbghelpPath->sr, &symsrvFileName); - for (ULONG i = 0; i < RTL_NUMBER_OF(locations); i++) - { - if (dbghelpPath = PhExpandEnvironmentStrings(&locations[i].AppendPath)) + if (RtlDoesFileExists_U(dbghelpName->Buffer)) { - if (RtlDoesFileExists_U(dbghelpPath->Buffer)) - break; - - PhClearReference(&dbghelpPath); + dbghelpHandle = LoadLibrary(dbghelpName->Buffer); } - } - if (dbghelpPath) - { - if (dbghelpHandle = LoadLibrary(dbghelpPath->Buffer)) + if (RtlDoesFileExists_U(symsrvName->Buffer)) { - PPH_STRING fullDbghelpPath; - ULONG indexOfFileName; - PH_STRINGREF dbghelpFolder; - PPH_STRING symsrvPath; - - if (fullDbghelpPath = PhGetDllFileName(dbghelpHandle, &indexOfFileName)) - { - if (indexOfFileName != 0) - { - dbghelpFolder.Buffer = fullDbghelpPath->Buffer; - dbghelpFolder.Length = indexOfFileName * sizeof(WCHAR); - - symsrvPath = PhConcatStringRefZ(&dbghelpFolder, L"\\symsrv.dll"); - symsrvHandle = LoadLibrary(symsrvPath->Buffer); - PhDereferenceObject(symsrvPath); - } - - PhDereferenceObject(fullDbghelpPath); - } + symsrvHandle = LoadLibrary(symsrvName->Buffer); } + PhDereferenceObject(symsrvName); + PhDereferenceObject(dbghelpName); PhDereferenceObject(dbghelpPath); + + if (dbghelpHandle) + break; } if (!dbghelpHandle) From 5b5372d559caaa41a28e507b714cb130046cabab Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 7 Jul 2018 02:02:13 +1000 Subject: [PATCH 1093/2058] Fix service properties parenting --- ProcessHacker/srvprp.c | 42 +++++++++++++++++++++++++++--------------- 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/ProcessHacker/srvprp.c b/ProcessHacker/srvprp.c index 8ff2bb4756ea..5e9893737aa1 100644 --- a/ProcessHacker/srvprp.c +++ b/ProcessHacker/srvprp.c @@ -97,15 +97,17 @@ static _Callback_ NTSTATUS PhpSetServiceSecurity( return status; } -VOID PhShowServiceProperties( - _In_ HWND ParentWindowHandle, - _In_ PPH_SERVICE_ITEM ServiceItem +NTSTATUS PhpShowServicePropertiesThread( + _In_opt_ PVOID Context ) { PROPSHEETHEADER propSheetHeader = { sizeof(propSheetHeader) }; PROPSHEETPAGE propSheetPage; HPROPSHEETPAGE pages[32]; SERVICE_PROPERTIES_CONTEXT context; + PPH_SERVICE_ITEM serviceItem; + + serviceItem = ((PPH_SERVICE_ITEM)Context); propSheetHeader.dwFlags = PSH_MODELESS | @@ -115,18 +117,18 @@ VOID PhShowServiceProperties( //PSH_USECALLBACK | PSH_USEHICON; propSheetHeader.hInstance = PhInstanceHandle; - propSheetHeader.hwndParent = ParentWindowHandle; - propSheetHeader.pszCaption = PhGetString(ServiceItem->Name); + //propSheetHeader.hwndParent = ParentWindowHandle; + propSheetHeader.pszCaption = PhGetString(serviceItem->Name); propSheetHeader.nPages = 0; propSheetHeader.nStartPage = 0; propSheetHeader.phpage = pages; { - if (ServiceItem->SmallIcon) - propSheetHeader.hIcon = ServiceItem->SmallIcon; + if (serviceItem->SmallIcon) + propSheetHeader.hIcon = serviceItem->SmallIcon; else { - if (ServiceItem->Type == SERVICE_KERNEL_DRIVER || ServiceItem->Type == SERVICE_FILE_SYSTEM_DRIVER) + if (serviceItem->Type == SERVICE_KERNEL_DRIVER || serviceItem->Type == SERVICE_FILE_SYSTEM_DRIVER) propSheetHeader.hIcon = PH_LOAD_SHARED_ICON_SMALL(PhInstanceHandle, MAKEINTRESOURCE(IDI_COG)); else { @@ -140,7 +142,7 @@ VOID PhShowServiceProperties( // General memset(&context, 0, sizeof(SERVICE_PROPERTIES_CONTEXT)); - context.ServiceItem = ServiceItem; + context.ServiceItem = serviceItem; context.Ready = FALSE; context.Dirty = FALSE; @@ -156,7 +158,7 @@ VOID PhShowServiceProperties( { PH_PLUGIN_OBJECT_PROPERTIES objectProperties; - objectProperties.Parameter = ServiceItem; + objectProperties.Parameter = serviceItem; objectProperties.NumberOfPages = propSheetHeader.nPages; objectProperties.MaximumNumberOfPages = sizeof(pages) / sizeof(HPROPSHEETPAGE); objectProperties.Pages = pages; @@ -167,6 +169,16 @@ VOID PhShowServiceProperties( } PhModalPropertySheet(&propSheetHeader); + + return STATUS_SUCCESS; +} + +VOID PhShowServiceProperties( + _In_ HWND ParentWindowHandle, + _In_ PPH_SERVICE_ITEM ServiceItem + ) +{ + PhCreateThread2(PhpShowServicePropertiesThread, ServiceItem); } static VOID PhpRefreshControls( @@ -437,11 +449,11 @@ INT_PTR CALLBACK PhpServiceGeneralDlgProc( SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, (LONG_PTR)GetDlgItem(hwndDlg, IDC_STARTTYPE)); } return TRUE; - case PSN_KILLACTIVE: - { - SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, FALSE); - } - return TRUE; + //case PSN_KILLACTIVE: + // { + // SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, FALSE); + // } + // return TRUE; case PSN_APPLY: { NTSTATUS status; From 6f95d3514f42bda09ed7c94ca8c256027fa0f73c Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 7 Jul 2018 15:07:06 +1000 Subject: [PATCH 1094/2058] BuildTools: Update legacy appveyor support --- tools/CustomBuildTool/Source Files/Build.cs | 62 +++++++++--------- tools/CustomBuildTool/Source Files/Utils.cs | 13 ++-- .../bin/Release/CustomBuildTool.exe | Bin 164352 -> 163328 bytes .../bin/Release/CustomBuildTool.pdb | Bin 77312 -> 75264 bytes 4 files changed, 35 insertions(+), 40 deletions(-) diff --git a/tools/CustomBuildTool/Source Files/Build.cs b/tools/CustomBuildTool/Source Files/Build.cs index a5deee31e395..15197c3679cf 100644 --- a/tools/CustomBuildTool/Source Files/Build.cs +++ b/tools/CustomBuildTool/Source Files/Build.cs @@ -975,13 +975,15 @@ public static string GetBuildLogString() public static void WebServiceUpdateConfig() { - string accountName = Environment.ExpandEnvironmentVariables("%APPVEYOR_ACCOUNT_NAME%").Replace("%APPVEYOR_ACCOUNT_NAME%", string.Empty); - string projectName = Environment.ExpandEnvironmentVariables("%APPVEYOR_PROJECT_NAME%").Replace("%APPVEYOR_PROJECT_NAME%", string.Empty); + string accountName; + string projectName; + string buildPostUrl; + string buildPostApiKey; + string buildChangelog; + string buildSummary; + string buildMessage; + string buildPostString; - if (string.IsNullOrEmpty(accountName)) - return; - if (string.IsNullOrEmpty(projectName)) - return; if (string.IsNullOrEmpty(BuildVersion)) return; if (string.IsNullOrEmpty(BuildSetupHash)) @@ -993,13 +995,30 @@ public static void WebServiceUpdateConfig() if (string.IsNullOrEmpty(BuildBinSig)) return; - string buildChangelog = Win32.ShellExecute(GitExePath, "log -n 30 --date=format:%Y-%m-%d --pretty=format:\"[%cd] %s (%an)\""); - string buildSummary = Win32.ShellExecute(GitExePath, "log -n 5 --date=format:%Y-%m-%d --pretty=format:\"[%cd] %s (%an)\" --abbrev-commit"); - string buildPostString = Json.Serialize(new BuildUpdateRequest + accountName = Environment.ExpandEnvironmentVariables("%APPVEYOR_ACCOUNT_NAME%").Replace("%APPVEYOR_ACCOUNT_NAME%", string.Empty); + projectName = Environment.ExpandEnvironmentVariables("%APPVEYOR_PROJECT_NAME%").Replace("%APPVEYOR_PROJECT_NAME%", string.Empty); + buildPostUrl = Environment.ExpandEnvironmentVariables("%APPVEYOR_BUILD_API%").Replace("%APPVEYOR_BUILD_API%", string.Empty); + buildPostApiKey = Environment.ExpandEnvironmentVariables("%APPVEYOR_BUILD_KEY%").Replace("%APPVEYOR_BUILD_KEY%", string.Empty); + + if (string.IsNullOrEmpty(accountName)) + return; + if (string.IsNullOrEmpty(projectName)) + return; + if (string.IsNullOrEmpty(buildPostUrl)) + return; + if (string.IsNullOrEmpty(buildPostApiKey)) + return; + + buildChangelog = Win32.ShellExecute(GitExePath, "log -n 30 --date=format:%Y-%m-%d --pretty=format:\"[%cd] %s (%an)\""); + buildSummary = Win32.ShellExecute(GitExePath, "log -n 5 --date=format:%Y-%m-%d --pretty=format:\"[%cd] %s (%an)\" --abbrev-commit"); + buildMessage = Win32.ShellExecute(GitExePath, "git log -1 --pretty=%B"); + + buildPostString = Json.Serialize(new BuildUpdateRequest { + Updated = TimeStart.ToString("o"), Version = BuildVersion, Commit = BuildCommit, - Updated = TimeStart.ToString("o"), + CommitMessage = buildMessage, BinUrl = $"https://ci.appveyor.com/api/projects/%7BaccountName%7D/%7BprojectName%7D/artifacts/processhacker-%7BBuildVersion%7D-bin.zip", BinLength = BuildBinFileLength.ToString(), @@ -1011,32 +1030,13 @@ public static void WebServiceUpdateConfig() SetupHash = BuildSetupHash, SetupSig = BuildSetupSig, - //WebSetupUrl = "https://ci.appveyor.com/api/projects/%7BaccountName%7D/%7BprojectName%7D/artifacts/processhacker-websetup.exe", - //WebSetupHash = BuildWebSetupHash, - //WebSetupVersion = BuildWebSetupVersion, - //WebSetupSig = BuildWebSetupSig, - Message = buildSummary, - Changelog = buildChangelog, - - FileLengthDeprecated = BuildSetupFileLength.ToString(), // TODO: Remove after most users have updated. - ForumUrlDeprecated = "https://wj32.org/processhacker/forums", // TODO: Remove after most users have updated. - SetupHashDeprecated = BuildSetupHash, // TODO: Remove after most users have updated. - SetupSigDeprecated = BuildSetupSig, // TODO: Remove after most users have updated. - BinHashDeprecated = BuildBinHash // TODO: Remove after most users have updated. + Changelog = buildChangelog }); if (string.IsNullOrEmpty(buildPostString)) return; - string buildPosturl = Environment.ExpandEnvironmentVariables("%APPVEYOR_BUILD_API%").Replace("%APPVEYOR_BUILD_API%", string.Empty); - string buildPostApiKey = Environment.ExpandEnvironmentVariables("%APPVEYOR_BUILD_KEY%").Replace("%APPVEYOR_BUILD_KEY%", string.Empty); - - if (string.IsNullOrEmpty(buildPosturl)) - return; - if (string.IsNullOrEmpty(buildPostApiKey)) - return; - Program.PrintColorMessage("Updating Build WebService... " + BuildVersion, ConsoleColor.Cyan); try @@ -1047,7 +1047,7 @@ public static void WebServiceUpdateConfig() { client.DefaultRequestHeaders.Add("X-ApiKey", buildPostApiKey); - var httpTask = client.PostAsync(buildPosturl, new StringContent(buildPostString, Encoding.UTF8, "application/json")); + var httpTask = client.PostAsync(buildPostUrl, new StringContent(buildPostString, Encoding.UTF8, "application/json")); httpTask.Wait(); diff --git a/tools/CustomBuildTool/Source Files/Utils.cs b/tools/CustomBuildTool/Source Files/Utils.cs index 2da55499afaf..c86d293a118a 100644 --- a/tools/CustomBuildTool/Source Files/Utils.cs +++ b/tools/CustomBuildTool/Source Files/Utils.cs @@ -359,9 +359,10 @@ public VisualStudioInstance(ISetupInstance2 FromInstance) [DataContract] public class BuildUpdateRequest { - [DataMember(Name = "version")] public string Version { get; set; } - [DataMember(Name = "commit")] public string Commit { get; set; } - [DataMember(Name = "updated")] public string Updated { get; set; } + [DataMember(Name = "build_version")] public string Version { get; set; } + [DataMember(Name = "build_commit")] public string Commit { get; set; } + [DataMember(Name = "build_updated")] public string Updated { get; set; } + [DataMember(Name = "build_message")] public string CommitMessage { get; set; } [DataMember(Name = "bin_url")] public string BinUrl { get; set; } [DataMember(Name = "bin_length")] public string BinLength { get; set; } @@ -381,12 +382,6 @@ public class BuildUpdateRequest [DataMember(Name = "message")] public string Message { get; set; } [DataMember(Name = "changelog")] public string Changelog { get; set; } - - [DataMember(Name = "size")] public string FileLengthDeprecated { get; set; } // TODO: Remove after most users have updated. - [DataMember(Name = "forum_url")] public string ForumUrlDeprecated { get; set; } // TODO: Remove after most users have updated. - [DataMember(Name = "hash_bin")] public string BinHashDeprecated { get; set; } // TODO: Remove after most users have updated. - [DataMember(Name = "hash_setup")] public string SetupHashDeprecated { get; set; } // TODO: Remove after most users have updated. - [DataMember(Name = "sig")] public string SetupSigDeprecated { get; set; } // TODO: Remove after most users have updated. } [Flags] diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe b/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe index 7db515a069453fd71e13a3f9d3899b4878617bf7..06a2deb671d87e4f4d637ad2d0cfdda2fd32721b 100644 GIT binary patch delta 14204 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 delta 15004 zcmbVz349bq_W!HynVu_iWs|89uF8U_EUPObD((+h|F2#*nFRg+_Vd~BnQy)Cd#_%- zs;;i7t{$2$S(=twSKb@#ezw<5p#PnKDA-s5zz?Wc&PaQE;;OA>c^QceuID_$;Mg+F zLgp*5Uw{OZzi}}LtM2b|)yb@r^^Wg(4gCC|-p9JIpVSvwC)T7MXVI)l7?A&s#E$?* zm_HSu>KOp8y%|9I)XczT#z;9WV}(eP`AGr54&YW__V!GavU35fxh%(YMNsE^i=vH2 z0E7HcCzz96jUf^=9?aIcz5aRi_r9Q_U?_w9DpwE3Fm?B$Z>D?zxnydzp)LCwuD*|} z6({E-IA6|rqYHW63KHF1TuGIyI$u@!L8_eCR(Unm@bDV9tsyyy%j>vkse6hS<~r;? zwivJUEa$Q<2jJF1`Ls%f<}@W zvv_ysMWOm0)%C|>7PtnHTSN>Fy2+(ryPnycSKb^REW>aIiZ znBC?&oFP^$#&TsTLS9fl$17{9>`YXpCHPXa%Q4yG32sv^Z(|&4KRq7sSTtXY?v{SV z4|0Ho`6LMm6^n!fK4}0P!lGrWBT!c!>jHD=qRGQh%Fe@Jn=*Zk793qUZkrsp`LDLk zh}!~J+m@-H270hZRafv@#7V)T9`B&H+a{mlm4;$t+2ax9uaU}^$&?-CT0Z}>j)y%7 zav)cIJDBAnk1@HJEcU=4FH(ijjckc}B%I=W2(@WeuSmlpKc-#|M?^{9tVU9j3njUg z*Rf(9Z)#mWZ|h&Epr-34BF&QIU$}>ZNBxzlo65pj>}GX+O0eYRJebqPD8GfprcA&5 zF_i(SZWu<{lo^!!6` z@PA6&{QpnfEdL*gKR{Uo%>Py5EVWcQjREK?wM`Uf*EWqlJ^I8o`lOf`*95g`QXkiZ zG|l~SO<2>s6xXC^no~-f$|}1HaP(~YOqYL$tPvMLgM1hzZF=#$*4EDQ&kmM^v|QQU z4QtVSZ)-mLR-Arm-P@Vk^2ok*GTI`z20=UXsVg~AO~F_0D@?&vGW$jJwOizBY(iEL zXw^W)J-kgmku`a&rUtr?Y@ zG6Tr(S3ivORr|-Rsy{tBeGBQeMS|Z72Q)wG1-}zctJkFmlpZ~K?YLJBacwq`7q6Aw z1yj`ScEMlnFN|FoHIK!uj~l;3wAGfYI*y#jq77Z!1aw=n`(nfhund6uG88>lw^eR8 zsMdCa`kZQw(xBR+G^kkoYEa+P2DLu=>p^vN98^cgL3MN-R0j^~(P%8;%Ah*rUwWz^ zMbg!bn3qjd2gFjNSC4B-FB<>0aUIr6y*}N4!+#psVZ2(qfyKeNG8Rs^v;9~&+l|HV z)qli7-rU|Drj$0i^=c?1IQB3%(c&D#Va-j_Y;kQr)S5yM;P)2G^vZ!g9j|^@;_<70 zxHs=h`hV)nVRc`|O67X2+;PQG;u?L$d9F=kmH&qFZ!HVSef8eamwEeTp6MvH7`XzsE*Fc9Q`TP zkKZ1Dzbalve;!|37&m2x+(W`C> zPb4V&2dMk9ylQ%O|Z##YeIs&UK8x{4oz^#hcv+{|5X!Q^0%7cmJNe>gK3F! z5(&4YdE^XDl_dAogk*WNCV1r=HNhv()&#$NrzQmCHJT8VpVEYoyiXIt@~4`RB41J~ zJ9`wz5Z@RV813<<@YtgCV#F8 z3Gz>xV3!jLsecYRs0mJ4$<-v6T&M|dd7LIB%2k@+k!Nc{lH8;T$?`f)@XFgY!6)z6 z1i$>DCIsZ~H36?<5w#kU6Ez_$XJ|r-+`m+lQsoJnkS14XLPT!Rgmn2nO^C|tH6bQ% z*MtmtpC)9=f7XO7`3to*r?YYi>EcwJZGs#bieiY1zAKY>G^#c&#tpGSh|k7bxDqeK zY%2Y76P0)=sSL_nsSL?`sSL~SQkf#3pfXkdfl9m(=3$`lS!9)i!>HpnIbRbJ;a@-3Qxvq=-e^4*${B0s`~#kf_%A=`oS;xrQf*3vWA#=5_R%b>@|A6)8k zaN$^7i$=F`5ijIEBXBvvb<&y}!$%v^dF4Lp+`LeT>?LjXNZekcZqDn+cB?1z2C!N+ zC4cPL{n&(65*E+Fn3AxFXCnPuI)K{x#e5wT0J=2JL~UlCFRSr36#gykcvpf3luyy?bdRwAQER&QW}m2!cQ0mNs_*njOUE&h zavIaIHQ9dcmAF&l^+Rgco?dluk5u%(xkr?BQk#1C*Z|Z<)jd5DDavSXNn6#)@v4>R zl!Fd8_Uvq*(dLjZ&rnzPOlJ3}&-9G2hdTu7q{ey`vMp*=ulLy>)n2_{XT|Ep-UCbG zo7=o9$!&O~{WfeoDcbFBhmxY*{GRzrvuIO$}rS z3OA+-i$jP1sX`N#W!Wt}c}odyXQr!_Ljw}6B-LuuP~Siq~F zCUG`MSVW77REH0IR^Q~he_`R3W9lDMn7(jDYRD&fDRmnlnP==Q5H! zNR@`?4}Jk3Mq-TskxYQq_=$~gkZWhxpeMi!qX6cYpl;%L$i>G>7wTfyPAndd#|$-wiJs;FSXG7M}J2V2hB2pRM?@;0JGT=zSSEK}CmlBZRL&BE`SGl?7X2RPEN0Hv_+KCZroE#fTQ|%h*k)SegIwHZN zE{;z*t1=~c!_9GMv_bJnFyG#Q_)0J+N^m&93>o2He^P<5)AZmG`YFv z73u)^f}$4+5-<22a6Vm43BoDsCQlGP4060LWs}FDz~Z2ap-=l8e5r6K3_%I}SWSYl z-VZV)7!%=W^Km@q<@%Y14>D5WTKDikDx7x>4>;ff=eV#0`|y%U5DI6cN>CQ;ihAap z>~+9dL!>(maZn#tK{L0{Oh#@j}eD@zA3ZIF3x_G4}?7q63a5@QY;+a8x23SD}m}t>Cpx zglV=Oc#Q|9h!|R>tM$7u4{?mHU!R01_G2rKlLKlJcrQm<`M}m$FZiSILF9tp3llQ= zAlG>>_$5$6yy4}DLAcZE6N2zGVOF#oPR3@sWDjAYscP##Nk})V})nq#YoaMnRV((^Xtd7{>ATb5%X=wgL!aExZI`x(hDgN>>WE!OLXh%U>zXf&J}l^`IPt zZm`tf2yXamY?Ijyzhpdvc)Nw;2T5Fii0}mAF%Q=m!yJ!BITlmhdcxOm1$V>GK8`iX zTQEW*)!LQFH48~|GiffOrW?GNx=k^6gVpKV5bs8mpxoYwtJk|}J5b(|x*K27L^B(4 zOlGBSLwQvi$4~;-%nxyV98>Xv8aZH=q|d}OQ(4n1_BYLCP3xi@pCo+8!{tp5jz;gB z=HBqU@Gi=0gfx><)^ryZWlar;>9AdT#+(je6UVouMx01Lm^hj&96u*b5y@F*uCWph zBiw4_nqQ<%m?HOQa0}rbSc}1K^kGmzxCvu2=*v-o_er&g@D(zQCHx0zA{1gB$sdyb zHo}J}=shHNCwUU#KQIXfc9IXF%tz%2_O-uw6mclwWWq*5WhE6e2rC8dG>R~TG-pVD zisZe7he-2p!UDuA4ZLDMhIPYUj`tWiK1jGRoy&uq$8a|6_kD_ZhvOt(+!UNWy}_yo zUzxqI4*r3-7|tW^V3!f!Vs?uczG5jB{K|~vBi5vKM|_A4v|u%1G+KR7Y8e~BX$@lSl{%6k_nFCK8@REg*Y3Hk1(7~CbnB=LolWZTsfL;NVvvgf{a{^ z-G??a^yE7}taq)F$m#n!okVO-zGnO}$Zbb;#;^%9EG^J%XUI0Go5nsPwpVADY}|8B z56#xe!C6^Pjn#X0fEi}$%;Hhb8qCla-_-GJvM9Hzej58eFw0_wDFZdO*Va<5@$l{Zi^D9Z>PW7&KOGmQ#*DpWw!-S=jiW{u|D;UcI>XyciXYahAN1Ae(Z10 z?4kColMNYef%TwYc-kA!+S{`+9fC^!^(@}Rt^T9!n(txzSbgI9zzy#>KDXdjPmg^u zp$g*6l-!;@f+@yro$TjXoSh1sXTi28dy=kKonr$Ej~#B)^4M|4W5*ef9cMgtoblMW zRi(c}MvTpHx2>~I&c9pmfJJBPaDd~idSdjS?dV`^FmBwM{(U=JnQc9b+Xgt>vy-V8 z+Ig-`QZJ1S_UD%?UV&e(IOCTq&iK`ev$J+}Y-v#87bdP;n|7&P3sNGpMxX+p`S2bA zhquO(4y%c+f%87e8ik7Snr&Gm!5V`viLHTTo8OuN2@^Ei7qQv+pm?v&Hl)R@oxwGc z+t$F-O6Vfwf~!oUr;+8uvpPGBtN@yB&}=`sr$cv0!lyW1@nu`CwI}S*+0O7qp!EQn zU`=G9t%tQAcOzD6?Q8Ad#wx6Z)`4woMTT;%bug4n<{E7k7z~q$t${ldr?J7XTW1Rs zORPh{h0mybEXH_Ct%Wd&*c$kAY?8GIj_K@8WW!++z82t#9=4UjwXj!b=aWkDw;kW< zY+lk11&ZO|6fNjJOS!cep1GN`yUpWpA{4`Ro%O+qPz*2XY#z?vV%Vp%nMs@-(pfj0 z55@4V&U|=J7Q=@+`%8ec<2rj0>nX+Xl}_)aFyHDdALnQ>{G_u2yqSyP-#UBMQH6<` zZ=pnSwX8+rn`hc+tMuS&p4;x*` z(sZ`bTLojFlg_qzUC0V__Iph9I_Rsj$C6#higfnBIODH}Vx37zE@b0$_C#V8?oX8) zb-Fdtg>;(EUcv@TVTR5QVuPj7ptC<1oxOq$j)S{&mWE?E9v;wH9yT~0*68d2 zHaGzu*V((+-UQgJ==2CSI1!%H*-310BJ9@L^EjksuwQ4dlPTP z8&4Zt$Vzo~8Exe-S!c;uu^guA>`Am$z->C)gY_ype2G`;teL*jE1`irRkJT#XRU-k zBE$AobCqKr(ie2&9LFMLdv*3hYzIv35OgXWC0jF8fmxUeJt_hJwAEu;2hV9Rglx^Q z5g%%&!9<fjA z(Aj#n+gb}nQ+YDYkj{2mZ-dFiwA5yFh%y7J$)+?z1P)qfU?m1mrE=Wq<3B4J66B{& zQxO?7N3O;T0q)aYUz5gt95Jrnj|X%joU?Jw(KHre@J&>R2yhNjgoOr8!=Jv#D9OAy z>*silO~A^(_X}A03%?tGGxxNy9VWR8NE62-%$+BW4cvrHUP<%`)H2X84U@p%NTs-3 zBDC0DE`y%5Bg%cYr{VP%U@x8=if}xEt9oM~0oMJW@}JNu=ndSR$Yrh(!AVIt$(ltG z7SkBqLmk^`2o32Gn3+DCofM`Udchfi2@UKVhF*wPuc4VSQKjb^F}9YSgqU?bvxqzi zxA>U79s**rzZBd3y(OP1JPU@|)u)}rCeI~*jW{K_l}6$`%CASb=Iw}CID?)6#BY5u z#DYkUP$Z5_DG<)V(pWE{SS-dJ2XCN1S_=~kQ9mYQJ$8v-+%RE=E{{x^BjjSOwJcX5 zrwn*IvO>s!>4p_T7;&}GlUxT94u_E`ZwjNS!ZP81lg+|1p)heP3?%=7*w_kTAVrvf z{-=aeF(LB|M%Wc=g`N~`vdB}JqFX0MCyDqiPo7G0=AGh9sEuqF8?c#H@eXX}n7EY8 z%XO!mkjbzb@_a)K>vfGk<5t5{x;!QNkl_yMMrWMWE~peoI5|FM$CG_T7bd}byp1}r zjXW#G=kRj80Dn?4RtUA?a>sjy7ckrh2HwA~*$bHU3DorVoiMn?AH#n~9D&oyEqd|c zc?(+^yJUDC8xxGrv-|{$af!$W`D1n_-DUikO-k?@mx+ydUn~*tPjDexar?JK{8n_K z&+%B;xI`FW%|tvMRXQ63;wU?x$=>u{C=U(wM;wB97#k=t9zh&$+$jFpb_+Ih)}4%j zx@T~F0`X(EK3I=U9*?bOAG5TK1;zv7U6v};pTG%tl6_{o-*^TiJZL<}KCrGsY_x7f z+-QB)c#@4vZdK6f-e@bFV}G+gXZ%=D3gBIPlf(=akxI#8*ptx*@k6nXv{5KGBr%Jj zKIL|)GkV@3y)5(%E<@`y)O1756H-4!3DOPUdNxa)4R?8-la>e-zJt<1eXd-ve=U`Y z2V+*#!>r1lW_nm*^;m3yh#`vDj4Ry&_I*aasS*SAL|ow+Xj&%RpE%O=wjQF%dq(JI z*dCp1ItsV5W8zW#z5H6XQFtM3t|=h4B=Ad_9OJ87Vd8l<6U4;DrXs^Pj=M3=zHk-H z#EHDtWX2=t9f(RT7KwNQ&By8aW&>){~cV}u*v zFv`!uyNKK1FNizfn8^ae*$%{!Y!~8awg+)6dkt{{JBT<*VTZAp!ahT+V4ovavD1jt z**AzYsoET>)nAk6khazu80Gm7veB7lt3}c<4J!L;WVf~%?!8?u^!gihQa+9`bl^czO+3F z)8JcMD?ADQgjSTVNjQaAhxiAyii~SS#^o5w4=2P(9)@zOk}!BDiW1eXeDOPw<*;A>3%>o(Bj|5;BQv(g}+QD+!knZX`TFc#@Er z$e*ytq;OJ6WC`I$!UKdS37MHH5EclgkmpLc$8dCc+Jb`w34Ff{XkKD+rqiHxTY8JVA*6afL@FEF`QzRCbw~ zh-@I-Pk4e55~%`VAz=k!6X6EJ{e&k7!9)Ipg@hG^O@tc=_YYj1NeW0!uZM(pv?9r?#u@`IhNbsMI4#T@wA^~4r#s$ zaCuJ>$459SP()5c4P5oU9SrMityp=4=@bnZHNN=5w1abJE8#3;lUikuY_w+Zo%U%0XIJ-sM&=mz>9dswA4F= ztz;F#bYY>eOV}&43P*)cgzLox;?v?D@jdY~@n^BXP-2*G*k;&mFiD?FV@$W07(1fC zLK{BPvcEv7m6snt1(hGciVOyZCjQ9N{*S-8#fPP~zsF5qik!69Z8in*8LFf1ag+8w zyS?AzrptDGti9Utg8ypWX458m>CmzAaD24Cy6zA>643s5+P(0YAO%xP#ZMZ3BKTH| z*T{jR;(53%T!#7rk+CPl%kYh8XBmdeaHGM)xZz%dk8MVIv*A5vG#$aumu#Zx0;_NN zvSzD68DHHnZ_fDIn&H)R9THQJGnilV@`G%IAb7u!z(wDF9)bh8M zY$l0y08Ja!4S3SHrM_@cfC9?IuK9mx1XzpHxSk&wMB z+)8{N?%?XxUCU$mo3Cr|bP-=ywlu%^BmQ&*c5MGwzu4oMMXTOy{-N{f``>T5_oD$! z^q8zI|8wk{gaICY8Z^OSxUODMpp@ZAJIaPeVv;@B@ zXVdWLsLk0>U%RlHPMP$GmRtD%l+TlACbe@jPsgcLKDBnXx1G{T%6dL4o$b_OeQiz4 zqSMLd+$;Z0RKOb`jQ57w&A@yfVBGlO^*B{uF?8$ zxA^VEf5)}<`CP#-OiFC|_PYpEBj0Ukc6|Sm<9l{~nFV`+MO}L@7?%VcNz5J>@-(ASS&Hm@C>eRUNS*z`D zZ0#nsd*TlFP4Et$yx`c12Z1>agH2%{tZsAI@$%4#Yw9w$viiXO-oYbg{_pM0dtW*o z_2%SD--iw#@$P4(uc^W?AKCZgG&QL7ahlt7;})xr@X`5P{o|o0+d?idrNo~FRpzv% zj3|dLrlG=*@}q|948M%Za378;3o(?1YPJihZ)%EuAVv$RJT>2tGiCaW+-Zf9M7L6H z0eqA>wP3)6xl)wmFzM)As*~x_29v?{6!Yf2fb0p=r{_(a!2NNhHk9YGL=T%Wt)O_K z6e@X{W&}%8Fanf7VO@|U@lu3A(T6s;Y}TzIk`w^xXmD$UGy+lsopZGh=?{q&5rIAh^S4>%hUk=K=3Dn5lxNH3^sDkHo>W; z?%h{d{n~P0l62l%L*9nLvz{8e+l@D%dl_kPsh*5I<{KRlPO?c-Tf|DIsvfhA+rY^O zXB{lLkF*37tF|*>kqB5b}25aGe2kRp?9t#}~ORp|%;FRI3_rP#kG3jm&7T zaxQ>_B%~u$nK9maHUeE7`c`#-Ywt^B%(NQ=Fqiev;L=Ov%6!u}5S)B)Mj%QaeVrL+ zybsP;aCnpgvi9nv>QsY+K+++~?KK{I30)ksHBehfy&EFwe6Oh33s63dHRj@m$d+;k zgZDbvX!m<0S1*cJE{ zFavl4m4+3ui4*_ojKLp+Z9s@Q3 zPXm7jo&nwkUIX3(-Uj{x3s)F>?hRf2Ls0rc&tAuQJI8vTSZo7?qgVodKo^OsUDcFCPR z{uO4>whNPHQ|6~ZbSM7+8|L0VAx>U1$>IGzmi%BE#ZF3-0fRpIg+>(g;oXe|i}Zhk z&_XdU+L?v=zBpO`F2;7+`(h`n-PN)KFQA$Z6vhFJrN=Km&;CZalb!k<&>l!HP412H z(aBEA*{5Se>3enDq0p({3HeCME&QX2$B`v(>1TN846;yOk&R9kh8wgvOzJ?9uLP|r z>S`FM24<2sHH{3SoT31@%qvP^BWYdH3i)5j6kFUw{wA4TC{B}aCe!BPWch9~eGYh- zOo3CkpEGjjJH7XT@vVy%s*K}c><8nPi*C*D z7q}Z;&-z9qo1-rJVPqJMT@WC{DKE@Qbm4B}f_Rxb0p|udFh|!N@KP{iAr!MP4sG_r zci3RMx6p~!TAI$DqukOIHilNA&8Op~udz2Mx6FxlZdp3pM0?9p*fzR}b{EBzzb1d( zmG+fKarnGEP5!AXg)T~y?{}r4i(ZEJD~m?KZ_{EM;TJZ9ER_wOE@(0FFP|PwX+N@=}VEKgd*+kSO$$dI?whIiS`)TU?%E{QlPcCOX2Zy+v`6bw zl2{oPDLvVKs#VhEpSsZx$~=Q1S+kX><0K0$tq#I2U01z}rBK$oPH-`I-Ma?OKa=7p zZ%z?lHH4_b6u$%eR&HVg#U$5!I zSUtsTjzgQh`4wiO&o-B`4wSp4liZ;*z54dEbasm$8$wsNq{|~a)5f=ADPyZ28%Nn& z7c(z9w>1Urs<#Ii@8i;odx4aNh?v-0>8uk)z7uC$2_Eh#cqo*lR66(8Vpakx3l+U> zM{m{J&$B9McQRhkNzxoW2znb}nZ(|P_ILxorhNdar=#zjU>)2Q+q@VLx&230;-34r zcNu#~rYSbc*x|sXA#X=I^Q8?tQus{JTFF?O&K#6gYcr%t@wg%5oTj2$^V988#X?P- zFyk-1rxX#75`#L4o26b4D@^fPa;S1= zkbWgR^q?acujF$5DvbNly;>*sY~@Zf%cjJgPFd$gpX>}}xm2{%Y0W^{_~E00+OCG# zXxhHh$>vb^U1prJU+=VAcmEg7HPD<)ZFkwNxaF%yn^t}Z(&?1D%Sm^4S=cVKwO$qU7SWkqakvPS>^8FsGVYFJH>eid& zKc-SYcPw^J-ku=+R)qRlRaoZ^3L7o5Xg#I3pz&)eedLZ})i5zLMr@B05jUW3pzi1g zP|4mP{Wd5D(A+&Xbz?`PZV%Oa)71SsV?XIx^%l;#GL`SQ8wW^(n>oHz3r-)Ye>2Af z9a|vY6Uwrr>}IYtRlWW@4*cGsgAxze{aZV1rz)C?U_VgGX}0gAdga_9cs}B%AI~R6 z^LiFudrG~V**&Q7!0(glN5=Q;lye}MmhBG?oC-J3N`sp9b2T?*@9B)0Qr~9wXsUeA z?%#U;`C4+*VBb34WHmX?ZC!}zn%B+;b;jP(ADg|-qs)VLV}EI2GiMPMfz!HL6{^FT za5zXB+N@WpIlK;seQ`ze6rq}$4%+=&&!+tW>8E{&c|G4UK9vnU={i!*hGn&JU!#d+&X;?G+0u4EA_a82eXy!CP@o>cN zw$oRt#|7}1BMom>#J0y1gXtx(TUY64Rhe^Jr-=>U@koR*1NUN2g|O|9*aAzT*t%{8 z^*O{;26pRZ3*gFD&gHT0VwdqVi@yW#qcipWdrIj^T(Yn8%XT0hYe8K>13{BOWuWz- zJ)pCo??AdByitHsK{=p8&=L^;sBi#u0rV5dCs>jkpbXFm&>YZe&<@Zs&~?!LV0W<;zg{~f(!lEeqcoK`J^5f~aZXY@RE*@|SK60X6_0fE`h72b< zvA>e*L{GMZ=AKBxlXERN#dP(=WF(PwvJ|mSom^qqhgVSkv@n!dRS-=*wT$_=ADo)P zSVwok$N$S>ry~6&p!J}`pbMb8AU`V#0_qPMYpu*&xaN~+TuWm z+MdPkh^8^;eq<{s>-+$NL)Br@EH&xf=a+GJpMJ_+_+PjNrJEO0BIY2o*FpRX%xMt+ zX2Rd@EuhX}m6`9ax#(l6!6m*LHzwSxQ3UnV!$o`KQfwbS8Y0l3)5h;%Cvg5}ly}jb zmI#M@RDrj9j$`n)&v7Km!!godAT}BwFGUwWyP3Yxnzne5-~c6 z7)QheI*6P~EOhYFpeUD6yCUZCK+LOyNcEnD;xESrW{C_dpVA`geQDa|WZzm(6)aSL zIXUo*(E3co+F+qyFUQLIAd0#Y>ng%2#F5=+Ay1^YjvBA@#Ey&n+?;h(XjBM455#z{sQx`+Q!BFkUd+WH@-Yhib5#C$ zC%MW>^`Cc){8}g<6-i}zoQfq_O6&`JX^2>`OkDDK%G-rju4j*l>Sl{66^KQ6TBOh@ zN)ahiA1QFIh<;8iuvL_*KrCu^thb%$fKNG4Gz;EG~p&;+!##r8X|m$2-^v5XmdmCpSFuojRFgVRh@8M zA=KB2@fpv#A@r;wbhf}vf`7`J!mdX2x+(VSdjb=MyGpT$N5uG?aDQCzo5Ttgm}%bC zj-^+G*D+!ln}pd-G2td5UnlBm5|@FtBJB4fyBM+4HwpXiMcB{8Sg)5de0>8XWFhHz zY4PWfLH07GhE5k>kcdvEeuLJbOwUSav zmbo88hO|t3eD{;LadY)3gMS=cg`Ys$A!AxCM=z*&%ScC+>m;3wgggg!W(G3UGI9v6 zYOkgU27Uamb{+xG8@errBSY=$DCqhGc8BI(pKn+Ig=L`E>GAbaQvxhfL480upwYCd zamt!6Ee5>2Nq!&;MSf}PHV3^Wpw*!DplzT%pwplmpgW*PARiPw7~}vYP|=q?Bk!Z9 z!+Zlk;h=V)t{_xV8VDLer@kCUj;}f+z3i{r(}J%CR`xzn|II)HTSD2l}3nW;viO{dzl!L&Tj>yiIhw zK(^j49K2lu+quHJZ*r%kK=8$4#JXcjD!|Jo0Tylk>(= zzoss7-guhFA)j_OCChme+}||)#S0(q`rS)mU1=fOZnO_=GTlO(;*R|VFW;Tr@&CTY zK@t#-B5Lfk8v&a<=@zSCGMkFL9zNXR!cQBnXp0iJZmysrm#n0Y&dOz`_+{F$cFYD z`lqS zUCn1$!NiurYcgSj1@{zwtZKs->pyKYnXt)gK1FEalOXba;!i7|1Q_OJ%k zo3I$qzdC6rN4Ph=_$106juXAPkohg*u_}K$O?lGRr1gc13DBt;g3m}lKMAaw!vYK* zhc~L)GH2Cp7GL!u^RN0&Lu)=R86N+6SVm8BTdPhnyE2@?froWN!DZDRcB8cgmdR6= zXdfkwu`m{`9AV5XkM&WCF|>}wb*DK%t2J7$Y{HKhz1FuDr?hyxtnzu0dr!(Mo;aa! z3ja}7yFO?#ZN7P_`)BFca<9r9pS3mSZgP(u+u^BBRweoq@pw{K@&aMN zzYo9fr7R4D!CqxdAhYQ^cEU@6D%B4~cdXiF^-3Lttb=lf>v$zfQn7Ll9`q&X?ozwV zp+p8jXRXp5pyw|fuPK>9&{=^q&rj_#MXBUESCm?=6M}V1QzC;=fWZn2hTshq@a0>H z2xeh={=qknjurjEC9uIyA`=JzRT4Rvw2@UCIkZtbb)<9-WjZA% zlv!AcChnn$`)T5uW^t}29<7PGn)8{*u3XYnkCY08z^p%C>{7GPTupL^1Zt@cDBzm!`b_bnXk?6{`c(k+dus4 z^|##8FP2U@I6_hSy2!4*6P2V=??fy6@>{kqz(wP-p(NOS$wRHoQs&IO>ax32N=T5V z!27G0s4!%#=En=pKUt52RCU!&=%)H^qx85~Z8*4XR2^4Hec~UYALF{Z=gurC$uFbS~ksF54j~HAqqnyn?z?a$>071?*HH5TaNrON`WW zqqC5Vgd~r4Cz|vX;97-^na&BDG=zQw9=(}7Tff8?Ng!E|TGA+K zNVH<(0xuJ6o~H#vX6rMc*FeH;N{OYYHffN!qLkf~n$lPCnhy#3D;=fmn8Qqs`AicJM1aF(u6<Ftm)6?V?2meP zVZ|~0+a`Jz343?Z{?tjT;{Kn34g@^|IvDhG&?L|=K+{3bf({2g2Ra7yJZLWH1<?RURbJum1|P!r@epglmBgNA}`0SyD)3K|ZomtK+- zJS0U+9+D3jl~UuA5y8vBt^?eGSfO5pHUR@UPlgFOY^1e#!haY`u@?W07>ls}`jpv; zJ+Lk)Sju$jT4B;`O8wZ2f{G5YIo5MUVRBt|ztxk2oZrK+`6W{5sV40~@Ndz$sSkVbJhJ30eUAwJfJ(|Q@uPoC_1CF+nAC@Y zmwK%(8K`Se5;Mt}UMcaS>=Jiog>kI>Ry=ii!k6}!l**b|3Z0fLcaEi}rzOaqv9xts zjBJdh^B_U7?BpsGPB=^%?>mE z7Tr;-59VbHkbq);qtw~a@ zZ4=uA!9(DPS<0L5E+go|a$j13Ccv9v0@ynMYT+8xp2xonIMVC&x^HDq= z!wFKi%ZpagHF#96F|*m$_BD~rC1;SB!#>{|XxLg0teJ6Zqgf%V{pv?7s5u$Sa>pC?)lfo!} zju)l8JPOy6+Lyx^i?Sa0`xM!^1q1bH0)=i0l|e>tnuR5DVv|Yx4&)ZPy(x@YsO#ov z3~%PK|QyI z;h42`DT|>qTg_|?joa2&9@CFjzB+PUSXF2rp(pEHqh6y@(oWMe6KXPABkWOslN$S2b29gEpoc==GttAS|MzWNw@ z3)X%0ts30!wE*nifoC-P2-XEUelcqXzMz(!@3S%1nq5wer`&y$t+iIZ_BxY;;wZG9 zUySnW6Iox{SRc!~fnzf18xmPMWj6Tf28gG?byU(|U|FQy6UaWH{taH#+@L|JNqYjR zezOamo#M87j|S57h6g4|2H8g{G5qtV2!(NXBuQC4FZ zwe9s`o2j-j%vgxg;=fKRQI0RcXD6L%G#R%Dtz+G5q1{8eCX?~vANb;V!1*AhH<_3Z z-EB0mqg0Ldct(3Gc(ir5dY8~@$ zfc66XBaL}N>*%`?+OO!uKIGZw!)_>fHr?+;SN6G4JtTNmwuaFywAvNj<5n-~ZS|2^ zJiTWPrKxDT#FO*>P<}RA4YGSY4c{Mv&fK;dn1QPIn=r?H_8V9r9o=s-t`e0w7WgVk z2&MM@emS-`hOs8a{gG5c<0PqM{PvQICcSu(DCszYv`*%o7$h=GpK&HXy_ zYw%CA`73q&wg0U@sNr?Q7-fsWYZzKQEhB%%@4D|;LqAvhV!*SZ_|+pwt}O^JtCfId2Zbf;Qn_94yhy0nM#4+ZKSyK|6gA#qH6R0%lie-fWitDFO|WA>9um0aqW9oN-2 z1NAx5ID0)8l%SQcdsKSDF8xZavhhug{t+qHF1|r6a33p;w@bdK+mMWu9mBjN9 zFk2dHmoh4w??-uWX?{0EE);xNl{yyb&TTywB7)=MF>qT&>bMjFmALMQHG0RH3x)0P zCnHLUS&f*EV?0QS$)%3HOj2wYL7FAy*n5zs*mCI@yxrTD{V2tDF{F-TkgM2ospA+t zsn{-o)G^y6#gazo1_WWhBo4@<)YHf6 zvRABry9Z09o^J=rsXfK(!$8{b_5}7a-8~jaKF8e9>Ur!DwwGoeo5wCd8i`}~W&`_$ z1~t!PeWoLS$!eilyWvq|2{ls*}a;?Sh|G+}$ zpaUy_?Z9#1BJcq4#+FwckPS@st4m$D`okW0Xzlr77)!TieQ08AB$a)%m>s5{K8nOK z_@n{H_>+CvJ5-G0hqV6WVmUaP0#1b*gQL~g5B{b!5KrB=fDstvOqzJ=CTpb3e~#3p z4^Ru8r4-uu&t*K^$Di>KT|T)CquZav22`P%4Zwb&6}ScPUBDn9&c818?bV;Ucm!b; zx8g~#78&^aSw0y*4K#PfqT^gwy-KfQp>iJkND6JiI^z6kn;o79IbQ^D8jn<*)(HQJ zZYp1l)xzb$T~yj6{GUSwTz*~UY44}K%zZ@88r<%=?i5ZnPIn8MBx-q1)Usa0$`Q2` ziyD%I|89{xUDVXoU5yuy;oxzrZF;pfFDV^QPF&F<6zv}L#Al%)MIuihk>>;!05|I+ z>Zc%BhnmqhLzzVvBpsQjxZ-ER$zD8pIJW0eV~9cXhtURbw_TsnVBI1|7=pvTXI z^@e_mwyL(cI6Yf^Q4s7O`s1*@B1(>PjDc9w_Jg(v8mp%$1^ZZ;Elx z67|0+l?MZCDB|@L9Z45cP$mlYPukW#1>ywB6tqPQWU#36fCzt8gdZp5cg6YJ-i>_EMJ1dTQ9VQ_ zJ`ls1D$ZIa=tQwtu8Xk2zVyVo0CR&F#Y#bY3G@EK?79eFBzUdXCB@a%T|zOEhL1A- z2jPt%1$1V#Qx683G!4Av_35#6%o;I0g?&QC)~G6tS}|@kj zxjd?%pkjJC&(clmrDVGjNH5$NBNxQbvkS7hKxtt85JvU?I zNio)c-+ao6O`_r7#j*lgh+`og#IcCJ#qnut=pAgo#aScnUS@JZe{%g{fLt(uk~xXC zmj4hV>uh~2q~LpgqYJSXTty$_&_|nggCghew|Mi%28Lt3s!ko3xcm;ERz@$}^Tj@N z(mexnr=$1$a4bW66x~ItQCLRyRD~UG%M`gt#kU6>hDOziR7D*=$7OorXJ2-l^gkQq z2Qsbv+1L2MA%1+n4%>m$^0VJ){yCIu<~^6GgNI z1lBu-jP6kLhdNhj2K8+-dZ=v?Vj$8|a9cOp*`}wAHh246Or}$9erz&Tw;9aaabCG9 zTUWV!zXUrA9V()eH8U2UQ(o#^r}z9^{f7X$Mrj|YBce#xp*pL>|9|Vy;lxtyxPM~5e)*VUTY$+*0N(4r4xrc(yXj@Fx2OF7O+s6_ zs*Naj693wuUJ~!vv;DcRY9o9LIw~EAJ2ARy{?iRXTXNM<1i*#I*46n+0Q*_;;l zf7MR-W0l(ck1PJ>KiWxD_L%LfMKu%wp6&?Xf?E_W6t)iheiPAQvQ#_Oe-f^2o?`TH z)=RQ=!Gn2DYnZ=0xXVicY`88h2vYox94KM4om@xp+aP{zo!M=rB#fyEChdvVY%we4B9zpexOQId*ZJvEO!yb z`Q=dj`IBVXq+{LK1~f6D+}Q7=Q{3bA#fTLhupP65z&swfx&(7`06E zvShn4jdl*$gLalhS<1MN#*(84>8uh@l^9hLq>?a|M5$zuN(QTBm`X;dBu61y{_XuA zmO5TpkfnbYgb%Z1ane`iVpJ|!<?P`N28SFUn%Rjyj)YE*8O%B@qm z%__H3<@TuDL6tkIawk;oq{_9b+y#~UO66{--1jQiu5en03rr_VP8VjtXCTYyE*NO{ z4v|5K0y{*ZLc~Ai2**J}#J{fyQJN6(&mBUPD@6RmgAh#;BEI!6L}jXoRa$~QF~n7t zBoHnCqYGzCswbwvsw&>H)N%dCmIkipe>>3C66}Ru#3on*ywHneh+I`shAP5GeO2`+ zRH>FaSTl>I%!~QSnncS=IN{GuEU$U72)TFS8=rfz5l*XJ|NL(W-|+WgKRU^g28*XZ zi;`~*wG0LAc?hp4OK@hV@keL8+@|2!CmS!Zc=C`|0d;`0WrsgA=~tjx3#a x+sV3?qFn~?$IzKT1u(->9l#>>RcKZNi-5&VsSh*$ty7{mJc8JF+PZAF{{qG2_Sygd From fe2fc49a5b8802c667d2cf413e74300ed4ca5369 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 7 Jul 2018 15:47:30 +1000 Subject: [PATCH 1095/2058] BuildTools: Fix log message --- tools/CustomBuildTool/Source Files/Build.cs | 10 +++++----- tools/CustomBuildTool/Source Files/Utils.cs | 8 ++++---- .../bin/Release/CustomBuildTool.exe | Bin 163328 -> 163328 bytes .../bin/Release/CustomBuildTool.pdb | Bin 75264 -> 75264 bytes 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/tools/CustomBuildTool/Source Files/Build.cs b/tools/CustomBuildTool/Source Files/Build.cs index 15197c3679cf..d0cfb0acca5e 100644 --- a/tools/CustomBuildTool/Source Files/Build.cs +++ b/tools/CustomBuildTool/Source Files/Build.cs @@ -1011,14 +1011,14 @@ public static void WebServiceUpdateConfig() buildChangelog = Win32.ShellExecute(GitExePath, "log -n 30 --date=format:%Y-%m-%d --pretty=format:\"[%cd] %s (%an)\""); buildSummary = Win32.ShellExecute(GitExePath, "log -n 5 --date=format:%Y-%m-%d --pretty=format:\"[%cd] %s (%an)\" --abbrev-commit"); - buildMessage = Win32.ShellExecute(GitExePath, "git log -1 --pretty=%B"); + buildMessage = Win32.ShellExecute(GitExePath, "log -1 --pretty=%B"); buildPostString = Json.Serialize(new BuildUpdateRequest { - Updated = TimeStart.ToString("o"), - Version = BuildVersion, - Commit = BuildCommit, - CommitMessage = buildMessage, + BuildUpdated = TimeStart.ToString("o"), + BuildVersion = BuildVersion, + BuildCommit = BuildCommit, + BuildMessage = buildMessage, BinUrl = $"https://ci.appveyor.com/api/projects/%7BaccountName%7D/%7BprojectName%7D/artifacts/processhacker-%7BBuildVersion%7D-bin.zip", BinLength = BuildBinFileLength.ToString(), diff --git a/tools/CustomBuildTool/Source Files/Utils.cs b/tools/CustomBuildTool/Source Files/Utils.cs index c86d293a118a..c530efbb7cb2 100644 --- a/tools/CustomBuildTool/Source Files/Utils.cs +++ b/tools/CustomBuildTool/Source Files/Utils.cs @@ -359,10 +359,10 @@ public VisualStudioInstance(ISetupInstance2 FromInstance) [DataContract] public class BuildUpdateRequest { - [DataMember(Name = "build_version")] public string Version { get; set; } - [DataMember(Name = "build_commit")] public string Commit { get; set; } - [DataMember(Name = "build_updated")] public string Updated { get; set; } - [DataMember(Name = "build_message")] public string CommitMessage { get; set; } + [DataMember(Name = "build_version")] public string BuildVersion { get; set; } + [DataMember(Name = "build_commit")] public string BuildCommit { get; set; } + [DataMember(Name = "build_updated")] public string BuildUpdated { get; set; } + [DataMember(Name = "build_message")] public string BuildMessage { get; set; } [DataMember(Name = "bin_url")] public string BinUrl { get; set; } [DataMember(Name = "bin_length")] public string BinLength { get; set; } diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe b/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe index 06a2deb671d87e4f4d637ad2d0cfdda2fd32721b..a36b2179ed66fa3ac3540c468da96aa90da13858 100644 GIT binary patch delta 10945 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 C9X8|u delta 10926 zcmbVS33yc1^*{H`%$p@MlbK9r-)9n%Kmr6p*dbvN0zn9nK#(mMB-lXUf(t5{@Q12F zT7-uPxB&_U#0rMCfJg;I3yMNP3bulvt)i$C6)?Wn(@(xrR+Y-7Keyy+2%3iHHDBI-4Y9dfKqWeU#TWJB%mxHiRgD$0_s==dz4G=@#J=8n5UiVnYJ*?*f12p zWH%V>`rLAq=yv6oo@{bl+2Lu2_<`rCNxF70t1%5gOS4hREkLjJ+3rRo(F5jCtk3q) zmwD@z8~S6E_1Qk^ZO;sT&5{gUE+5C-BD59gX$6|F>jdr*z~X-q=&u$(4RtpbA0w=E zcc1@OxZ&RyZlM36aGV9K(`)#j3MZk8#32m87pZlhTuy4#-Qn%f>Z9(7u1Sqg?2^i) z#xFE8lA3_ftWIizLUSYiWz-dTpzfGhsiuz)%|1NjV$#xnAjX zeIs*sI@^a?+9`t~(UK0GVV1vPEJo?kgq7M2w0oK0o zO57;OXDBBl-S8HZ9t}kw;aYKnVAsL3!ix`qT?U7gTch5nvxxOgdX;f5wu10_I2xPG z=Y?GXd>R}^`^_`sFp8;Z-C%ZOZZ{lNgxv(^RH5WB*-bQM&P*wDwoEa_{L+O&B`xM- zlZMStChZ+DX>(#foiyu>lV-hf(yTX5niVJQL@aK;K515Zu1NV)B&uY^U8JkhGaicF zJaa$ZG$+|zl;Kg&nEy6)*} z@n`u)JkL!0)*Hvr`I*9&)OJU$-v5gVJb$uX^eTF%uCKi--z%-V;Q3-UmjAj9o>%r} zJ(?)Q&NtprYLXiDhO(?xW1{;|{#RH1x6Fs1DK}sB{%)xjGwsdz9CmTa4xMr&yJ+Yb z)T9omefJv&G@0?_tUI)JZEikJNkKkdrpwXjZ@7)oAl;~xx5+Nw%ljuUfWtS%lY6lE z;=Z>&J3#v}{;%Tu=v?KMHone_(Lt;UpBz3+c1R{G$;C?cpjX3qR)~*&kNwL?f!2*u64zeM#SxSVeBS3N7ry-o{%meT%m~`ZwPCsnm9IZjJRMx4G$7-g@Y(y!Fzfy!FwK5?t`p?|2)ahTbe_kcN00q8)h~Hqrq? zFwxOMNTYQ^Fw;gMSm<&gSm`Dqq|-e@u+gJJu+zT@A%p&d3lqZ*D)(VI!+2;p4N> zm=Nr=NC+A979lw32q9$BDME14`-I@4j|#y}*9*ZzcM8EvPY40mQ3!tewGaYSF6Bvs zG*BU=5G@u$nD!GwgjNY5O6!FXqm4p{(?^AnMb`=;o9+-o8~VC(plx2_4AS`_+-(w- z`l0A&qWk(LZjY+<^8-wm+>Iqni934)Z#{GhZ*eJk>!V9}>!(liHbA%WHc0pLHbhVI z78l~vevn{W#ze0PRT{PR=i@cgm=G+qn-HwDTnOoOvJhqy8H2#qIFTPGP@w+DrhxDlBR-|UllY-q_>jWu}^L( z^LP|H8|WYu?WX%Z*gtnPYWNLZwUsKr?D(T)ICFlCWy+z$l{JO!NR9G(VZ=4RRX@<3 zi?<}XfV8ELDAx*0$TLdsPI+XrGObfFc}01;QyFQyX8#q zjMt&1)0DgVoFb36+}ih#5?QB2`}H87DdYRav8twin{XTE^{+_R4Q1!sDz>$T%G9qk z_m4`tp~}|&)g-LQ19}v6%L0gxnoFn8oQ7K+z=rSCWAW8EUO5Wt6y&Ij52`F1fbG4? zi~+w$811+d@kfST>2m`z46`w8v=#@_L66fQ!|$yzj|}tD8II#vWMeXL^m6>1`#f*0 z#J(nuQSNC-|I99f*0VS)L!WepgRJ^28GdGC_}7R#;gZ2`b|X&o`ZO}sdzjqlV%WoX zC1!#{(O0}O9EOUp37U+rc&)J2ydh+T*Zd5pk_{nDK(1;s;Cr~LSqNX?jZ%g^D9dn> zW1gQy9*jOuz;L{7pW!|k(1)D#CS)ikELjJRUs~Ac6J|CJ4Sul3SqC#^IGf3EOFGj`C?F2xNVKw3M(VU0Ut~;4$SbuJTJq7z`zV^ z0wUgG487Rxc7am$91+UuE7Km*G-~;jf(xS8#p3_TG31K287F9fFmJR_JK` z#wSA!E}0B_eQzLM@%$0>&snZzT4A~M8kS{?v9gLX7#`$vZ0GZxc+13+eI94%=X0=+ zr@7=|nk}fY!rMMa)CAYU2XF~4ANo~-ze z%SQQzflcfehBfXO+#6owcEPuCHpv;zHEtPVK9;xxq7R7CE%_jeC7kti*0u zVh9%bdw+}_mh#E@mQQua#in`y$8;l;3%NX)7qmLgcK)|s7UCO|TPYmuNc>Y@c zY?no_0?uY841#vx)Z!PcD`!=ztvhFxYM4^a9#L&0Is2_y^cx2Yhzn!=6N?~n_`T0 zhlM=hd9|tIzupc^4_3hK$TV1JDS)!CtaBpA-3WG=AA8ndhxPGa zA%3H0c&~%$r*mA$@%{{^+2mt*Pn6+B7eg11FeS$1C%DFxxdkKqhWn4TGkuV2fX8_n zHHAjiH8hKH7w?L&W7IMI9>hw=MNh7V~OF6THP!sHJur*YPA zcfF4oww%XFd{r4%o~Iua?qI~TMVVh7Oq__0Hxl>=ABzB1!k5uYS_vlO*~^$dR%4VP zAJ0L?o{n77>R^Y;!l8q*4)U{wZBMYyr~_>q!CpWnLvD^>e-0m%^>8XzFq@CD@;t$= zCA^I8RO$I3W45-!c-~iM)I%1&F|+gqn9u-4_^p|-Pi>4HRoPX}X5pt=W?O|Z4RAtb z&vCY>qp&UEY;2)mP2L1^-J{ZHOpMLyER2WEj8)<1SQgZku?-ARud=Q7OIibD;+HvQ zJA`E$paj2mF!q>drqKZ1dI{Fkc$d)xMfky&+0J6jG^iaY*x$_u6G*?~beZQz|0Qi2 z9ATgC;X%(8zYJ+`>IPOagxMCrmEirxG+5ipmKe=o!$%Wls|~F+ro-fN#vX*HZFpWW z5i~XtQ!s$nbzjF`G$xXCrTREEq}R%hO2OtKAuRMrsLn_}DRIFQ0tpeNp# z`OoV*SMX2@%MHF`bSlo_?!*J`T1a|r^QN-H##HuDMk-rwPG!Tiscf_BDUyt7bibRD z`K0kZqpP*5zRL5%EtRt@9~!-_x~J1>A<4ElQdw`THfcMY_BBbe2R&aCUu%>Jie-d9 z!6M_!CI5L{$08>gi=1REa+0ygNyZ}MBcvK-f@1{1_gR%4wp=jc`Tec))%a&wp*^+FzGQ7f{ zU<;Jg^$7it5`VKz!q2t6hO-eZgYB7h#wg6j>!xmE<_HninRv5je zEcisVJrtV>xllV=c=iuvneyNwXDeZF!gm$&;bJ8-u7t(N+QXtM!RnE9gz;kpTWza@ zPH;(O<4pyoB3Lq3*ed;3f!_q637<-XrXo{!X5j3op}VO^D?4i_HT7y`h4I8-Qy<8w zW*Twj_kkkLRzlcbOZvbHl?CnProM1dc*3R3k){$T8pryrgu7zZrc&6UvKhz*KoNdY zWVU)!1q^~!DqHEOz~2eJr819WTLQ{p?Re(840;~0UU?N(Ve_Vbm&ewDW4VGgV8m_unA z)M@aHkDfP-UGmYhgHKtE?o`hOE8Hp27`20*Y0( zIm3pmugdx*?6rVvq0(V?8?q598;1!;!dR6}!-ONDMrF5R!cj0?WfL*sD4;6aj|oS^ zeJVSO2}i?1mDOUtN_a$Nv+a0~uY?sUor?*p;7OG&!h}_@L1m-yf*u1esI1P7PucKW zmCeLr#=>5eEx=;N!W$|(gT++CJ1YAUi>ZcFDr>aYCSV+VpweIB=*PhYmDS-=+y<9b zHW!!THuzp;qcP}skS2>|nu0;c-*7fgP}xF$QceIf_f!nKeX~pxV4%wMmb*>46QEqB z4$A{*9Idj)W7}Y2N>C+I<+HI} zp+sO%kYOdBFcO@{cVrFdyiC(3d^4^=t8|0j6k zBEbqo4cw8YK(j^DO9!@>K34 z66D#LKhtR7CEn{L9Jd6A_~;`X+a^qGWQAA@fwtT%!e$7?%VB}E9A7q@rMhqx zZ0BjVLm)N@R!ht9sA!hrG)L5)3r74f)b4&oUblb2dD$u4QEMaINTvk!-4L;TUvmKvZeSNLKa~(`hO%!Wu)-h$&4rqE8Ok5oNfn`5=-hUy#;B z?;>`oG9Ey=Fe8en33rm2Pd7PnS@UkBk9Cc|UXq8b@h?=!>cSISY+GQD=)u*oirvy^@v^DBWwM#7z zVVoL&E!5*iUZpp{RM?K#a_1yjm$+hl6A#2Q7KW1f9mLNZ3>Ui@9!X=^>|r>8>w9zj zh+{u3)6cOSM-=`KM46_A>-QL$Jj%&%KqkZ884M@b89u`G4-e)B9S`>`H$2P@^*sI0 zx%DgFZ8^8@=Rxn_n!UbL7%0bb2JwlOu2To$-!>|VJGy&=CVZSB$Kfb`TO;IMILq5V zL7{T&4ksy6KE5N{`3jzs_!~V2>d!NJ{QHGzj>&8B>FH+68u!h*P5OcOr*}8|ef$%@ zXY}WW^6WN&Y3MDShE1I_r)Jtz-d|{1PR|Zm%q(8jR61vR!%S!~ zC+3+lgf+zxS{`eDRcaZvl;5Fmlv@QNs@3y{cQzAIlyMuX(Nuk2EwF#ZXRstiGr0d?=O0m*|(@``t5xm*Wp)%Hl!8q2;}#uZpJF zu8`=4g~U@B~9nggYQ4n19Kl*XzIbk?PmceJw7TBn+O zx)PMuZJ^1gE9KCGt^_Ti{ncgWI!oDOUTpC4RE1Hh>`sVrmbAxGTWc=2Jmx{@sHb~# z*#FRYk*>WH^-)iPtfs`C?Xrue-ZW5kPm)}qmY$t5foAYoN+G>F-DAw&*zb<}8|G+w8B#`VZj~dzH^;5Bzc4376VC_h* z_sOPUAI2< z3WmTmSOkFz;(`KD3f>;9zxuInOcSPEU>tk{)<8rg!h-_Jo%*Mx-CKwc&@A;!q8?pS z$Jel@j?Fj`=cv=hHZ)6JTY2=?YwIZ#uI?}Kez=deR-XrTzmRIK8{=w_rn-uIMjJEH zQgwZbqt#I7^%S{>=B}qGE$s0Udn{&;$0_cHNfuJ>4P&9g*&Yti{B(F}qnT|F2eE(l zk<313IFDqms*yTw?2RvGtvSvnguT4RV~|3j)6YsXWlpEW)!+)MsaJByC2qtOE~$+g zr?-dPL$g(_B@Q@DQ`67+$8exbk~1dd6z+qn)6ACVFjvKPbv+-%yZ)NiH6A-zp3c_8oW)h%FXn7AIh#3- z-sq?K3BmPMqc*bMFlQO0>BWmH+?e}6(iG!3?L>BTp9;T7F?X|;!f7n=IbY&1-?My- z%P_O`FqhHBYlYLi#A7($i!pM1u`9Qky-cz9G&~t<@>Xu)em*=0dwan9iEI}~^*2rO zE_K{AW+ro+?{cFQZa^A0B+XazeT^Gh!0n=0w(e)W4yvCu`KNJ23w6$>`_BvQu{z!B_8-M;0?g9X{J&)hwSDz-?+RRzI&ysV zoR1wd{RVpW>+1t|s>3#I5{W2Y%Q`@mTk3x0`JO}XeHVGsrIHV|08#sxiVz#c7N-kM zp88TM{xY@+;j(LR+O4}@fA4YGX>ztpciW9?@lLt|K4GXSu;EK?Lp|=5M=k5GNUngI zob9%|?ed*=>jko1o=1gF1vboZ8#eqf;QAYtD_{dnJun^^|DpRQv@|(;HwzKzIvU&y zF2`E6|E(iv%X-iCI(p^d#+WRpiZk;kRI;e%p;6XRnrc}gvA z=^`yZjFO8Kv|@}&!n4blz*<#cuC4G$CW&%ajIxXlu0$ziPCYGBW}4eqD}4ZItEcou zw{)7uR-)uI&94~KgY~XR`z&?Gs-1TrKzWrhnNZ6+b*{0fHUjyj|jal8z{uPcaT-jLoT|w%(cMK5M!A zbZk`YFv`nhb(oaPp1ywVzB_Bw;V{WH8iQsQ%{eyX^LvNU*M=t;ji#?1F^V?lJa91a zd^5(W_|fLbai=Crf9sa&ed&*n;uSrFOhslJ6BgL-HFhx$VL|FKG(nmY c`f&A)y#c>DY7dI=`;deCUwYwGw0y_^zx(LrTmS$7 delta 3606 zcmZ{n4@_0p9mmgk@A2nRup;1nmp{G-J|=Wfp(`qC3ruXGkq9d`8X<)h21HRAxM=1A zEV_-ZY|vjD?LsryXaX51|CLP_Ni=CY>I6Zd)fQ8lXo8t!{KusG-gkeON9RWJdFPz_ z`~N%VT(4Dwma0KZhsDR{d^!1`6hdTt`m=M}HVvoO+5ga-AfmqQ4)uxg3_Nt|+HV)v zW!~NEAAGgW>$2llKPq~+Go@K}txNL^+<*Mv|N2w!F9sw2c<9c<_1XLXGFth2moV7d z+xy?qG8F<%l;D<-YEKoaw#RE#f(U zWFdCaz>xrQwE5fKDEw)8$@t5-YGL__xY{z9oM?7MjIxGR0rmAx}{0g{`s! z^8mVZ!D*T@)0Y>v%P3MicF1Dd*O4S!=>3i))1-xNcWjpq^6%Usb0`D9=P(bThR!HC zM%O!&q>Vhfk|5jNwM#ZqP1i2dgeTqTdKpH3-ANK<;}`XHCz&R^=tj3o(4$#o^l08{ z@H;}+@w=8}??Lk`;x&4+H=1&Ked)bkhdEWG(Z$|qbGpc&uQ6)!XZxbbx6hYS`yA#y zB9n^xqRm-iUpMuocvQZ#R)}VB6^wxy;EU4{1(HDyr~q}K1$+!9fLJGl4ZH~UfMQSu z8bA-Y2_67TfDoZz8^{EQ!D-M4E(M56F@nhy@D3Eh0g}Ofa01kUHgFA0fCUg3Bt#5I z19_kdoCBA@O)vv|*9#E`(!gPG8nl3`U;-=vn*tpr23cWJ41NO|!DTQ49s_Ti5KgcY z?6-BMM98kc=R6a649nA?0bB+nUwXliJs;)gL7w^=_rmo& zp2~)m@B>Iu(+Xe1BigC0&v3K@)H=LbCeZlsX0@6?4+aT;V)oxvDa1y0teVk+sG-n?=qpmc7l|Xx+&7WI82|Y!1)G z5!6yI<&clK5$#4vR5P;G|1&h()fNu;Aq|aevU+f!Xp*CLwG?MT(>ckOA7QSoB_)p9 zvxd0DS>6cA@nU&>lHUvhrz>oEZSkKQ(mp{_|Q{`>7@_n{dIhRMgksom`WjywC z4&Si;03V=qBPXlw`wXvDuA!gD~TvwMn$n;_X*cPO{q}4zJ>FXiY2OCcebm zcc0zQ@^e47vr_dPyZnTj?kLegT&{}StNDoMvU|DBWn4-%P2W+}dQL3<8C|=H&)$6s zA5#wau{4W)6|%2!Zc7%ISIzBfV&AQ7cb~@+_TI_%HB>fcx2l{`27NHLIpq-_%6=Z> zIc7a?=M`QLv5)Kge41NYLe}vl)3idbjc`h$?gr=L{oC6~A=-^I)wC7i+IpSx}@no9~0~f=@qx9vu+0{CPxx$rOdD z{)cOw><}i3`yyA9ch`L}CF3ulwb#H+a2GrPGXS3(!WY;;9M}ocKsL4B+b9QV^xi+I z<;!f392|~fl3#7|oWg9uho1jxxIWXnYvNd7aIlC(tM!z9L{VYIo5lwX{ca|>(hw&@ z#YdE{5(}|jM7vCNS=^R5{B3(tdqwLmPq}O~m;8Z)wPB;n*e1bk)3XxCWm8#!^@@=$ zWTP!^qbZk>7RdccWCYS>Y_rvE6NQ7P7xc7^F4Ju2ud{0o6u4B~br|1GMhIQbArghy z!1Xt;g!t~)lwsFQ;d6>1bQ@!;&L=3Xc?36t8ryj;7}noCxcDh&s61*H7HOyy+!Ky>aY}NQrT7X)2Y? zhsac_omaw6xpX+v>m^02_vjQ2%qy~o#^*zVdsh4Uf!o((Gp$(&Rv)hxtS>1av4URZJbSXzF$yL?@yw=Z#< zI}s}5nr!aONwl!63m;ac1iJ?bm^DV(WNj|pX>SOV^fSyIqCkA zT{=lFE3$ypWxHB{*OCz>{{^>ZGi5E?;kj%XC(euBUf!Tiu2x0+jk29Iup9!X_m-8g zJiM{=TVfn~_ifB0|0fC>5d9=XZE)#vf~#)X809_*kz?H_pZwZfpK0rnlV%xs@f)+W n2masx(OnF+$!tr|1YVz~@%B$enrV1bC*# Date: Sun, 8 Jul 2018 10:52:22 +1000 Subject: [PATCH 1096/2058] Fix service properties window position settings --- ProcessHacker/settings.c | 1 + ProcessHacker/srvprp.c | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/ProcessHacker/settings.c b/ProcessHacker/settings.c index f7cd82bcd91d..736d0d22e476 100644 --- a/ProcessHacker/settings.c +++ b/ProcessHacker/settings.c @@ -145,6 +145,7 @@ VOID PhAddDefaultSettings( PhpAddIntegerSetting(L"SampleCountAutomatic", L"1"); PhpAddIntegerSetting(L"ScrollToNewProcesses", L"0"); PhpAddStringSetting(L"SearchEngine", L"https://www.google.com/search?q=\"%s\""); + PhpAddIntegerPairSetting(L"ServiceWindowPosition", L"0,0"); PhpAddStringSetting(L"ServiceListViewColumns", L""); PhpAddStringSetting(L"ServiceTreeListColumns", L""); PhpAddStringSetting(L"ServiceTreeListSort", L"0,1"); // 0, AscendingSortOrder diff --git a/ProcessHacker/srvprp.c b/ProcessHacker/srvprp.c index 5e9893737aa1..84370ed2e875 100644 --- a/ProcessHacker/srvprp.c +++ b/ProcessHacker/srvprp.c @@ -26,10 +26,12 @@ #include #include +#include #include #include #include +#include #include typedef struct _SERVICE_PROPERTIES_CONTEXT @@ -246,7 +248,10 @@ INT_PTR CALLBACK PhpServiceGeneralDlgProc( PPH_STRING serviceDll; // HACK - PhCenterWindow(GetParent(hwndDlg), GetParent(GetParent(hwndDlg))); + if (PhGetIntegerPairSetting(L"ServiceWindowPosition").X == 0) + PhCenterWindow(GetParent(hwndDlg), PhMainWndHandle); + else + PhLoadWindowPlacementFromSetting(L"ServiceWindowPosition", NULL, GetParent(hwndDlg)); PhAddComboBoxStrings(GetDlgItem(hwndDlg, IDC_TYPE), PhServiceTypeStrings, sizeof(PhServiceTypeStrings) / sizeof(WCHAR *)); @@ -326,6 +331,7 @@ INT_PTR CALLBACK PhpServiceGeneralDlgProc( break; case WM_DESTROY: { + PhSaveWindowPlacementToSetting(L"ServiceWindowPosition", NULL, GetParent(hwndDlg)); PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); } break; From 8cd2217e9ff2170096d85b0fdafd5f1e1a8c925f Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 8 Jul 2018 11:04:29 +1000 Subject: [PATCH 1097/2058] Fix previous commit --- ProcessHacker/srvprp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/ProcessHacker/srvprp.c b/ProcessHacker/srvprp.c index 84370ed2e875..0bd7c7a1772c 100644 --- a/ProcessHacker/srvprp.c +++ b/ProcessHacker/srvprp.c @@ -26,6 +26,7 @@ #include #include +#include #include #include From 740979f888a80adcd599dd7f7f320b0d76892b68 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 14 Jul 2018 07:18:10 +1000 Subject: [PATCH 1098/2058] Fix starting minimized when StartHidden enabled --- ProcessHacker/options.c | 47 ++++------------------------------------- 1 file changed, 4 insertions(+), 43 deletions(-) diff --git a/ProcessHacker/options.c b/ProcessHacker/options.c index fc972bde1bc7..c0dc87fa6bb4 100644 --- a/ProcessHacker/options.c +++ b/ProcessHacker/options.c @@ -141,7 +141,6 @@ static BOOLEAN RestartRequired = FALSE; // General static PH_STRINGREF CurrentUserRunKeyName = PH_STRINGREF_INIT(L"Software\\Microsoft\\Windows\\CurrentVersion\\Run"); static BOOLEAN CurrentUserRunPresent = FALSE; -static BOOLEAN CurrentUserRunStartHidden = FALSE; static HFONT CurrentFontInstance = NULL; static PPH_STRING NewFontSelection = NULL; static HIMAGELIST GeneralListviewImageList = NULL; @@ -701,7 +700,6 @@ static VOID ReadCurrentUserRun( PPH_STRING value; CurrentUserRunPresent = FALSE; - CurrentUserRunStartHidden = FALSE; if (NT_SUCCESS(PhOpenKey( &keyHandle, @@ -729,7 +727,6 @@ static VOID ReadCurrentUserRun( if (fullFileName && PhEqualString(fullFileName, applicationFileName, TRUE)) { CurrentUserRunPresent = TRUE; - CurrentUserRunStartHidden = PhEqualStringRef2(&arguments, L"-hide", FALSE); } PhDereferenceObject(applicationFileName); @@ -748,7 +745,7 @@ static VOID WriteCurrentUserRun( { HANDLE keyHandle; - if (CurrentUserRunPresent == Present && (!Present || CurrentUserRunStartHidden == StartHidden)) + if (CurrentUserRunPresent == Present) return; if (NT_SUCCESS(PhOpenKey( @@ -979,15 +976,6 @@ typedef enum _PHP_OPTIONS_INDEX PHP_OPTIONS_INDEX_SHOW_ADVANCED_OPTIONS } PHP_OPTIONS_GENERAL_INDEX; -VOID PhpSetListViewItemState( - _In_ HWND ListViewHandle, - _In_ INT Index, - _In_ BOOLEAN Hide - ) -{ - ListView_SetItemState(ListViewHandle, Index, INDEXTOSTATEIMAGEMASK(Hide ? 0 : 1), LVIS_STATEIMAGEMASK); -} - static VOID PhpAdvancedPageLoad( _In_ HWND hwndDlg ) @@ -1027,6 +1015,7 @@ static VOID PhpAdvancedPageLoad( SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_SINGLE_INSTANCE, L"AllowOnlyOneInstance"); SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_HIDE_WHENCLOSED, L"HideOnClose"); SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_HIDE_WHENMINIMIZED, L"HideOnMinimize"); + SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_START_HIDDEN, L"StartHidden"); SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_MINIINFO_WINDOW, L"MiniInfoWindowEnabled"); SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_DRIVER, L"EnableKph"); SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_WARNINGS, L"EnableWarnings"); @@ -1044,16 +1033,7 @@ static VOID PhpAdvancedPageLoad( SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_SHOW_HEX_ID, L"ShowHexId"); if (CurrentUserRunPresent) - { ListView_SetCheckState(listViewHandle, PHP_OPTIONS_INDEX_START_ATLOGON, TRUE); - - if (CurrentUserRunStartHidden) - ListView_SetCheckState(listViewHandle, PHP_OPTIONS_INDEX_START_HIDDEN, TRUE); - } - else - { - PhpSetListViewItemState(listViewHandle, PHP_OPTIONS_INDEX_START_HIDDEN, TRUE); - } } static VOID PhpOptionsNotifyChangeCallback( @@ -1124,7 +1104,7 @@ static VOID PhpAdvancedPageSave( SetSettingForLvItemCheck(listViewHandle, PHP_OPTIONS_INDEX_SINGLE_INSTANCE, L"AllowOnlyOneInstance"); SetSettingForLvItemCheck(listViewHandle, PHP_OPTIONS_INDEX_HIDE_WHENCLOSED, L"HideOnClose"); SetSettingForLvItemCheck(listViewHandle, PHP_OPTIONS_INDEX_HIDE_WHENMINIMIZED, L"HideOnMinimize"); - //SetSettingForLvItemCheck(listViewHandle, PHP_OPTIONS_INDEX_START_HIDDEN, L"StartHidden"); + SetSettingForLvItemCheck(listViewHandle, PHP_OPTIONS_INDEX_START_HIDDEN, L"StartHidden"); SetSettingForLvItemCheckRestartRequired(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_MINIINFO_WINDOW, L"MiniInfoWindowEnabled"); SetSettingForLvItemCheckRestartRequired(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_DRIVER, L"EnableKph"); SetSettingForLvItemCheck(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_WARNINGS, L"EnableWarnings"); @@ -1210,7 +1190,7 @@ INT_PTR CALLBACK PhpOptionsGeneralDlgProc( for (i = 0; i < RTL_NUMBER_OF(PhSizeUnitNames); i++) ComboBox_AddString(comboBoxHandle, PhSizeUnitNames[i]); - if (PhMaxSizeUnit != -1) + if (PhMaxSizeUnit != ULONG_MAX) ComboBox_SetCurSel(comboBoxHandle, PhMaxSizeUnit); else ComboBox_SetCurSel(comboBoxHandle, RTL_NUMBER_OF(PhSizeUnitNames) - 1); @@ -1334,15 +1314,6 @@ INT_PTR CALLBACK PhpOptionsGeneralDlgProc( LPNMITEMACTIVATE itemActivate = (LPNMITEMACTIVATE)header; LVHITTESTINFO lvHitInfo; - // HACK: Don't change the checkbox state for the 'Start hidden' item when the 'Start at logon' item hasn't been enabled. - if ( - itemActivate->iItem == PHP_OPTIONS_INDEX_START_HIDDEN && - ListView_GetCheckState(GetDlgItem(hwndDlg, IDC_SETTINGS), PHP_OPTIONS_INDEX_START_ATLOGON) != BST_CHECKED - ) - { - break; - } - lvHitInfo.pt = itemActivate->ptAction; if (ListView_HitTest(GetDlgItem(hwndDlg, IDC_SETTINGS), &lvHitInfo) != -1) @@ -1371,11 +1342,6 @@ INT_PTR CALLBACK PhpOptionsGeneralDlgProc( { switch (listView->iItem) { - case PHP_OPTIONS_INDEX_START_ATLOGON: - { - PhpSetListViewItemState(listView->hdr.hwndFrom, PHP_OPTIONS_INDEX_START_HIDDEN, FALSE); - } - break; case PHP_OPTIONS_INDEX_SHOW_ADVANCED_OPTIONS: { PhpOptionsShowHideTreeViewItem(FALSE); @@ -1388,11 +1354,6 @@ INT_PTR CALLBACK PhpOptionsGeneralDlgProc( { switch (listView->iItem) { - case PHP_OPTIONS_INDEX_START_ATLOGON: - { - PhpSetListViewItemState(listView->hdr.hwndFrom, PHP_OPTIONS_INDEX_START_HIDDEN, TRUE); - } - break; case PHP_OPTIONS_INDEX_SHOW_ADVANCED_OPTIONS: { PhpOptionsShowHideTreeViewItem(TRUE); From 86cc9d941c1eae1b8e9c47df033d80b11859e9ea Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 14 Jul 2018 08:50:58 +1000 Subject: [PATCH 1099/2058] Updater: Fix updating bin releases --- plugins/Updater/page3.c | 11 ++--------- plugins/Updater/page5.c | 6 +++++- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/plugins/Updater/page3.c b/plugins/Updater/page3.c index ced2fcffb38a..162df7d379e4 100644 --- a/plugins/Updater/page3.c +++ b/plugins/Updater/page3.c @@ -46,15 +46,8 @@ HRESULT CALLBACK ShowAvailableCallbackProc( { if ((INT)wParam == IDOK) { - if (UpdaterInstalledUsingSetup()) - { - ShowProgressDialog(context); - return S_FALSE; - } - else - { - PhShellExecute(hwndDlg, L"https://wj32.org/processhacker/nightly.php", NULL); - } + ShowProgressDialog(context); + return S_FALSE; } } break; diff --git a/plugins/Updater/page5.c b/plugins/Updater/page5.c index 3cf00b67ff49..a289f0ca0211 100644 --- a/plugins/Updater/page5.c +++ b/plugins/Updater/page5.c @@ -61,12 +61,16 @@ HRESULT CALLBACK FinalTaskDialogCallbackProc( else if (buttonId == IDYES) { SHELLEXECUTEINFO info = { sizeof(SHELLEXECUTEINFO) }; + PPH_STRING parameters; if (PhIsNullOrEmptyString(context->SetupFilePath)) break; + parameters = PH_AUTO(PhGetApplicationDirectory()); + parameters = PH_AUTO(PhConcatStrings(3, L"-update \"", PhGetStringOrEmpty(parameters), L"\"")); + info.lpFile = PhGetStringOrEmpty(context->SetupFilePath); - info.lpParameters = L"-update"; + info.lpParameters = PhGetString(parameters); info.lpVerb = PhGetOwnTokenAttributes().Elevated ? NULL : L"runas"; info.nShow = SW_SHOW; info.hwnd = hwndDlg; From d4d473180cd4a1b401467965f6b31b181706057a Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 14 Jul 2018 10:38:42 +1000 Subject: [PATCH 1100/2058] Tidy up macro usage --- phlib/basesup.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/phlib/basesup.c b/phlib/basesup.c index 9dcb13081fbf..cf11152f700d 100644 --- a/phlib/basesup.c +++ b/phlib/basesup.c @@ -3008,7 +3008,7 @@ PPH_BYTES PhConvertUtf16ToAsciiEx( } bytes->Length = outLength; - bytes->Buffer[outLength] = 0; + bytes->Buffer[outLength] = ANSI_NULL; return bytes; } @@ -3460,7 +3460,7 @@ VOID PhInitializeStringBuilder( StringBuilder->String->Length = 0; // Write the null terminator. - StringBuilder->String->Buffer[0] = 0; + StringBuilder->String->Buffer[0] = UNICODE_NULL; PHLIB_INC_STATISTIC(BaseStringBuildersCreated); } @@ -3904,7 +3904,7 @@ FORCEINLINE VOID PhpWriteNullTerminatorBytesBuilder( _In_ PPH_BYTES_BUILDER BytesBuilder ) { - BytesBuilder->Bytes->Buffer[BytesBuilder->Bytes->Length] = 0; + BytesBuilder->Bytes->Buffer[BytesBuilder->Bytes->Length] = ANSI_NULL; } /** From 5f797fb3d7313f8acc957d5b494cd54ab9d51cac Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 14 Jul 2018 10:39:54 +1000 Subject: [PATCH 1101/2058] ToolStatus: Fix statusbar redraw issue on win7 classic --- plugins/ToolStatus/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/ToolStatus/main.c b/plugins/ToolStatus/main.c index c8d3a641c4f1..197abf634798 100644 --- a/plugins/ToolStatus/main.c +++ b/plugins/ToolStatus/main.c @@ -547,7 +547,7 @@ VOID NTAPI LayoutPaddingCallback( // Adjust the PH client area and exclude the StatusBar width. layoutPadding->Padding.bottom += statusBarRect.bottom; - //InvalidateRect(StatusBarHandle, NULL, TRUE); + InvalidateRect(StatusBarHandle, NULL, TRUE); } } From 4e76a4e51375c71d2a023ce792c553a6f7aa3296 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 14 Jul 2018 10:40:49 +1000 Subject: [PATCH 1102/2058] Fix find handles window startup location --- ProcessHacker/findobj.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/ProcessHacker/findobj.c b/ProcessHacker/findobj.c index e9b6950f8f95..a43a132ef168 100644 --- a/ProcessHacker/findobj.c +++ b/ProcessHacker/findobj.c @@ -969,7 +969,7 @@ NTSTATUS PhpFindObjectsThreadStart( if (NT_SUCCESS(status = PhEnumHandlesEx(&handles))) { static PH_INITONCE initOnce = PH_INITONCE_INIT; - static ULONG fileObjectTypeIndex = -1; + static ULONG fileObjectTypeIndex = ULONG_MAX; BOOLEAN useWorkQueue = FALSE; PH_WORK_QUEUE workQueue; @@ -1150,13 +1150,9 @@ INT_PTR CALLBACK PhpFindObjectsDlgProc( context->TypeWindowHandle = GetDlgItem(hwndDlg, IDC_FILTERTYPE); context->SearchWindowHandle = GetDlgItem(hwndDlg, IDC_FILTER); - PhCenterWindow(hwndDlg, NULL); PhRegisterDialog(hwndDlg); - PhCreateSearchControl(hwndDlg, context->SearchWindowHandle, L"Find Handles or DLLs"); - PhpPopulateObjectTypes(context->TypeWindowHandle); - InitializeHandleObjectTree(context); PhInitializeLayoutManager(&context->LayoutManager, hwndDlg); @@ -1172,6 +1168,7 @@ INT_PTR CALLBACK PhpFindObjectsDlgProc( context->MinimumSize.bottom = 100; MapDialogRect(hwndDlg, &context->MinimumSize); + PhCenterWindow(hwndDlg, PhMainWndHandle); PhLoadWindowPlacementFromSetting(L"FindObjWindowPosition", L"FindObjWindowSize", hwndDlg); context->SearchResults = PhCreateList(128); From 49313151b0c37677807f232e856ed07bc8b49351 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 14 Jul 2018 10:42:56 +1000 Subject: [PATCH 1103/2058] Update View > Hide signed processes error dialog --- ProcessHacker/mwpgproc.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ProcessHacker/mwpgproc.c b/ProcessHacker/mwpgproc.c index b410279e5f0e..f27f6b17b807 100644 --- a/ProcessHacker/mwpgproc.c +++ b/ProcessHacker/mwpgproc.c @@ -276,11 +276,13 @@ VOID PhMwpToggleSignedProcessTreeFilter( { if (!PhEnableProcessQueryStage2) { - PhShowInformation( + PhShowInformation2( PhMainWndHandle, + NULL, L"This filter cannot function because digital signature checking is not enabled. " L"Enable it in Options > General and restart Process Hacker." ); + return; } SignedFilterEntry = PhAddTreeNewFilter(PhGetFilterSupportProcessTreeList(), PhMwpSignedProcessTreeFilter, NULL); From 83211e15ba6a4914def75f523942b8bd9094b55c Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 14 Jul 2018 10:44:57 +1000 Subject: [PATCH 1104/2058] Fix runas dialog memory leak --- ProcessHacker/runas.c | 157 ++++++++++++++++++++++++++++++++---------- 1 file changed, 121 insertions(+), 36 deletions(-) diff --git a/ProcessHacker/runas.c b/ProcessHacker/runas.c index 8629153bd3b0..d3612349aa89 100644 --- a/ProcessHacker/runas.c +++ b/ProcessHacker/runas.c @@ -86,7 +86,6 @@ typedef struct _RUNAS_DIALOG_CONTEXT HWND SessionEditWindowHandle; HWND DesktopEditWindowHandle; HANDLE ProcessId; - PPH_LIST DesktopList; PPH_STRING CurrentWinStaName; } RUNAS_DIALOG_CONTEXT, *PRUNAS_DIALOG_CONTEXT; @@ -351,10 +350,9 @@ static VOID PhpAddRunMRUListEntry( return; commandString = PhConcatStringRef2(&CommandLine->sr, &prefixSr); - AddMRUString_I(listHandle, commandString->Buffer); - PhDereferenceObject(commandString); + FreeMRUList_I(listHandle); } @@ -412,6 +410,36 @@ static VOID PhpAddProgramsToComboBox( FreeMRUList_I(listHandle); } +VOID PhpFreeProgramsComboBox( + _In_ HWND ComboBoxHandle + ) +{ + ULONG total; + + total = ComboBox_GetCount(ComboBoxHandle); + + for (ULONG i = 0; i < total; i++) + { + ComboBox_DeleteString(ComboBoxHandle, i); + } +} + +static VOID PhpFreeAccountsComboBox( + _In_ HWND ComboBoxHandle + ) +{ + ULONG total; + + total = ComboBox_GetCount(ComboBoxHandle); + + for (ULONG i = 0; i < total; i++) + { + ComboBox_DeleteString(ComboBoxHandle, i); + } + + ComboBox_ResetContent(ComboBoxHandle); +} + static VOID PhpAddAccountsToComboBox( _In_ HWND ComboBoxHandle ) @@ -423,7 +451,8 @@ static VOID PhpAddAccountsToComboBox( ULONG userinfoTotalEntries = 0; ULONG userinfoResumeHandle = 0; - ComboBox_ResetContent(ComboBoxHandle); + PhpFreeAccountsComboBox(ComboBoxHandle); + ComboBox_AddString(ComboBoxHandle, PH_AUTO_T(PH_STRING, PhGetSidFullName(&PhSeLocalSystemSid, TRUE, NULL))->Buffer); ComboBox_AddString(ComboBoxHandle, PH_AUTO_T(PH_STRING, PhGetSidFullName(&PhSeLocalServiceSid, TRUE, NULL))->Buffer); ComboBox_AddString(ComboBoxHandle, PH_AUTO_T(PH_STRING, PhGetSidFullName(&PhSeNetworkServiceSid, TRUE, NULL))->Buffer); @@ -464,7 +493,7 @@ static VOID PhpAddAccountsToComboBox( PPH_STRING username; PPH_STRING userDomainName = NULL; - if (username = PhGetTokenUserString(PhGetOwnTokenAttributes().TokenHandle, TRUE)) + if (username = PhGetSidFullName(PhGetOwnTokenAttributes().TokenSid, TRUE, NULL)) { PhpSplitUserName(username->Buffer, &userDomainName, NULL); PhDereferenceObject(username); @@ -538,6 +567,29 @@ static VOID PhpAddAccountsToComboBox( //} } +static VOID PhpFreeSessionsComboBox( + _In_ HWND ComboBoxHandle + ) +{ + PPH_RUNAS_SESSION_ITEM entry; + ULONG total; + ULONG i; + + total = ComboBox_GetCount(ComboBoxHandle); + + for (i = 0; i < total; i++) + { + entry = (PPH_RUNAS_SESSION_ITEM)ComboBox_GetItemData(ComboBoxHandle, i); + + if (entry->SessionName) + PhDereferenceObject(entry->SessionName); + + PhFree(entry); + } + + ComboBox_ResetContent(ComboBoxHandle); +} + static VOID PhpAddSessionsToComboBox( _In_ HWND ComboBoxHandle ) @@ -546,7 +598,7 @@ static VOID PhpAddSessionsToComboBox( ULONG numberOfSessions; ULONG i; - ComboBox_ResetContent(ComboBoxHandle); + PhpFreeSessionsComboBox(ComboBoxHandle); if (WinStationEnumerateW(NULL, &sessions, &numberOfSessions)) { @@ -574,7 +626,7 @@ static VOID PhpAddSessionsToComboBox( sessions[i].WinStationName[0] != UNICODE_NULL ) { - menuString = PhaFormatString(L"%u: %s (%s\\%s)", + menuString = PhFormatString(L"%u: %s (%s\\%s)", sessions[i].SessionId, sessions[i].WinStationName, winStationInfo.Domain, @@ -583,7 +635,7 @@ static VOID PhpAddSessionsToComboBox( } else if (winStationInfo.UserName[0] != UNICODE_NULL) { - menuString = PhaFormatString(L"%u: %s\\%s", + menuString = PhFormatString(L"%u: %s\\%s", sessions[i].SessionId, winStationInfo.Domain, winStationInfo.UserName @@ -591,26 +643,25 @@ static VOID PhpAddSessionsToComboBox( } else if (sessions[i].WinStationName[0] != UNICODE_NULL) { - menuString = PhaFormatString(L"%u: %s", + menuString = PhFormatString(L"%u: %s", sessions[i].SessionId, sessions[i].WinStationName ); } else { - menuString = PhaFormatString(L"%u", sessions[i].SessionId); + menuString = PhFormatString(L"%u", sessions[i].SessionId); } { PPH_RUNAS_SESSION_ITEM entry; + INT itemIndex; entry = PhAllocate(sizeof(PH_RUNAS_SESSION_ITEM)); entry->SessionId = sessions[i].SessionId; entry->SessionName = menuString; - INT itemIndex = ComboBox_AddString(ComboBoxHandle, menuString->Buffer); - - if (itemIndex != CB_ERR) + if ((itemIndex = ComboBox_AddString(ComboBoxHandle, menuString->Buffer)) != CB_ERR) { ComboBox_SetItemData(ComboBoxHandle, itemIndex, entry); } @@ -621,16 +672,22 @@ static VOID PhpAddSessionsToComboBox( } } +typedef struct _RUNAS_DIALOG_DESKTOP_CALLBACK +{ + PPH_LIST DesktopList; + PPH_STRING WinStaName; +} RUNAS_DIALOG_DESKTOP_CALLBACK, *PRUNAS_DIALOG_DESKTOP_CALLBACK; + static BOOL CALLBACK EnumDesktopsCallback( _In_ PWSTR DesktopName, _In_ LPARAM Context ) { - PRUNAS_DIALOG_CONTEXT context = (PRUNAS_DIALOG_CONTEXT)Context; + PRUNAS_DIALOG_DESKTOP_CALLBACK context = (PRUNAS_DIALOG_DESKTOP_CALLBACK)Context; PhAddItemList(context->DesktopList, PhConcatStrings( 3, - context->CurrentWinStaName->Buffer, + PhGetString(context->WinStaName), L"\\", DesktopName )); @@ -638,36 +695,63 @@ static BOOL CALLBACK EnumDesktopsCallback( return TRUE; } -static VOID PhpAddDesktopsToComboBox( - _In_ PRUNAS_DIALOG_CONTEXT Context, +static VOID PhpFreeDesktopsComboBox( _In_ HWND ComboBoxHandle ) { + PPH_RUNAS_DESKTOP_ITEM entry; + ULONG total; ULONG i; - Context->DesktopList = PhCreateList(10); - Context->CurrentWinStaName = GetCurrentWinStaName(); + total = ComboBox_GetCount(ComboBoxHandle); + + for (i = 0; i < total; i++) + { + entry = (PPH_RUNAS_DESKTOP_ITEM)ComboBox_GetItemData(ComboBoxHandle, i); + + if (entry->DesktopName) + PhDereferenceObject(entry->DesktopName); + + PhFree(entry); + } + ComboBox_ResetContent(ComboBoxHandle); +} + +static VOID PhpAddDesktopsToComboBox( + _In_ HWND ComboBoxHandle + ) +{ + ULONG i; + RUNAS_DIALOG_DESKTOP_CALLBACK callback; - EnumDesktops(GetProcessWindowStation(), EnumDesktopsCallback, (LPARAM)Context); + PhpFreeDesktopsComboBox(ComboBoxHandle); - for (i = 0; i < Context->DesktopList->Count; i++) - { - PPH_RUNAS_DESKTOP_ITEM entry; + callback.DesktopList = PhCreateList(10); + callback.WinStaName = GetCurrentWinStaName(); - entry = PhAllocate(sizeof(PH_RUNAS_DESKTOP_ITEM)); - entry->DesktopName = ((PPH_STRING)Context->DesktopList->Items[i]); + EnumDesktops(GetProcessWindowStation(), EnumDesktopsCallback, (LPARAM)&callback); - INT itemIndex = ComboBox_AddString(ComboBoxHandle, entry->DesktopName->Buffer); + for (i = 0; i < callback.DesktopList->Count; i++) + { + INT itemIndex = ComboBox_AddString( + ComboBoxHandle, + PhGetString(callback.DesktopList->Items[i]) + ); if (itemIndex != CB_ERR) { + PPH_RUNAS_DESKTOP_ITEM entry; + + entry = PhAllocateZero(sizeof(PH_RUNAS_DESKTOP_ITEM)); + entry->DesktopName = callback.DesktopList->Items[i]; + ComboBox_SetItemData(ComboBoxHandle, itemIndex, entry); } } - PhClearList(Context->DesktopList); // leak - PhDereferenceObject(Context->CurrentWinStaName); + PhDereferenceObject(callback.DesktopList); + PhDereferenceObject(callback.WinStaName); } VOID SetDefaultProgramEntry( @@ -739,8 +823,7 @@ INT_PTR CALLBACK PhpRunAsDlgProc( if (uMsg == WM_INITDIALOG) { - context = PhAllocate(sizeof(RUNAS_DIALOG_CONTEXT)); - memset(context, 0, sizeof(RUNAS_DIALOG_CONTEXT)); + context = PhAllocateZero(sizeof(RUNAS_DIALOG_CONTEXT)); PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context); } @@ -789,7 +872,7 @@ INT_PTR CALLBACK PhpRunAsDlgProc( PhpAddProgramsToComboBox(context->ProgramComboBoxWindowHandle); PhpAddAccountsToComboBox(context->UserComboBoxWindowHandle); PhpAddSessionsToComboBox(context->SessionEditWindowHandle); - PhpAddDesktopsToComboBox(context, context->DesktopEditWindowHandle); + PhpAddDesktopsToComboBox(context->DesktopEditWindowHandle); SetDefaultProgramEntry(context->ProgramComboBoxWindowHandle); SetDefaultSessionEntry(context->SessionEditWindowHandle); @@ -863,8 +946,10 @@ INT_PTR CALLBACK PhpRunAsDlgProc( break; case WM_DESTROY: { - if (context->DesktopList) - PhDereferenceObject(context->DesktopList); + PhpFreeDesktopsComboBox(context->DesktopEditWindowHandle); + PhpFreeSessionsComboBox(context->SessionEditWindowHandle); + PhpFreeAccountsComboBox(context->UserComboBoxWindowHandle); + PhpFreeProgramsComboBox(context->ProgramComboBoxWindowHandle); PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); PhFree(context); @@ -889,7 +974,7 @@ INT_PTR CALLBACK PhpRunAsDlgProc( if (GET_WM_COMMAND_HWND(wParam, lParam) == context->DesktopEditWindowHandle) { - PhpAddDesktopsToComboBox(context, context->DesktopEditWindowHandle); + PhpAddDesktopsToComboBox(context->DesktopEditWindowHandle); SetDefaultDesktopEntry(context, context->DesktopEditWindowHandle); } } @@ -958,7 +1043,7 @@ INT_PTR CALLBACK PhpRunAsDlgProc( if (NT_SUCCESS(PhLookupName(&username->sr, &sid, NULL, NULL))) { if (newUserName = PH_AUTO(PhGetSidFullName(sid, TRUE, NULL))) - username = newUserName; + PhSwapReference(&username, newUserName); PhFree(sid); } @@ -1439,7 +1524,7 @@ static VOID PhpSplitUserName( PhInitializeStringRefLongHint(&userName, UserName); - if (PhSplitStringRefAtChar(&userName, '\\', &domainPart, &userPart)) + if (PhSplitStringRefAtChar(&userName, OBJ_NAME_PATH_SEPARATOR, &domainPart, &userPart)) { if (DomainPart) *DomainPart = PhCreateString2(&domainPart); From 662436ae4554a6a19b5e8cbf90fbacbab246fbdc Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 14 Jul 2018 11:19:33 +1000 Subject: [PATCH 1105/2058] Fix type --- phlib/util.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/phlib/util.c b/phlib/util.c index 997d9765fb01..313f6106e267 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -5234,7 +5234,13 @@ BOOLEAN PhExtractIcon( ) { static PH_INITONCE initOnce = PH_INITONCE_INIT; - static UINT (WINAPI *PrivateExtractIconExW)(PCWSTR, INT, HICON*, HICON*, UINT) = NULL; + static HRESULT (WINAPI *PrivateExtractIconExW)( + _In_ PCWSTR FileName, + _In_ INT IconIndex, + _Out_opt_ HICON* IconLarge, + _Out_opt_ HICON* IconSmall, + _In_ UINT IconCount + ) = NULL; if (PhBeginInitOnce(&initOnce)) { @@ -5247,7 +5253,7 @@ BOOLEAN PhExtractIcon( if (!PrivateExtractIconExW) return FALSE; - return PrivateExtractIconExW(FileName, 0, IconLarge, IconSmall, 1) > 0; + return SUCCEEDED(PrivateExtractIconExW(FileName, IconIndex, IconLarge, IconSmall, 1)); } /** From 390cee3f93644e767213bc45e674cd898c21e8c8 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 14 Jul 2018 11:32:35 +1000 Subject: [PATCH 1106/2058] Add workaround for setup application directory --- phlib/util.c | 6 ++++++ plugins/Updater/page5.c | 1 + 2 files changed, 7 insertions(+) diff --git a/phlib/util.c b/phlib/util.c index 313f6106e267..8e4a11f49b0c 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -5341,6 +5341,12 @@ PPH_STRING PhGetDllFileName( PhDereferenceObject(fileName); fileName = newFileName; + if (newFileName = PhGetFullPath(fileName->Buffer, NULL)) // HACK PhGetApplicationDirectory (dmex) + { + PhDereferenceObject(fileName); + fileName = newFileName; + } + if (IndexOfFileName) { indexOfFileName = PhFindLastCharInString(fileName, 0, OBJ_NAME_PATH_SEPARATOR); diff --git a/plugins/Updater/page5.c b/plugins/Updater/page5.c index a289f0ca0211..f662a465cf61 100644 --- a/plugins/Updater/page5.c +++ b/plugins/Updater/page5.c @@ -67,6 +67,7 @@ HRESULT CALLBACK FinalTaskDialogCallbackProc( break; parameters = PH_AUTO(PhGetApplicationDirectory()); + parameters = PH_AUTO(PhBufferToHexString((PUCHAR)parameters->Buffer, (ULONG)parameters->Length)); parameters = PH_AUTO(PhConcatStrings(3, L"-update \"", PhGetStringOrEmpty(parameters), L"\"")); info.lpFile = PhGetStringOrEmpty(context->SetupFilePath); From 2bc9ad72a75a0067cde0b17e5285e89a20c79a34 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 15 Jul 2018 04:31:00 +1000 Subject: [PATCH 1107/2058] Fix type #290 --- ProcessHacker/ProcessHacker.def | 2 ++ phlib/include/phutil.h | 10 ++++++++++ phlib/util.c | 10 ++++++++++ 3 files changed, 22 insertions(+) diff --git a/ProcessHacker/ProcessHacker.def b/ProcessHacker/ProcessHacker.def index 3130af7d0e14..a7a0f9e11f07 100644 --- a/ProcessHacker/ProcessHacker.def +++ b/ProcessHacker/ProcessHacker.def @@ -132,6 +132,8 @@ EXPORTS PhEqualStringRef PhExponentiate PhExponentiate64 + PhExtractIcon + PhExtractIconEx PhfAcquireRundownProtection PhfBeginInitOnce PhfEndInitOnce diff --git a/phlib/include/phutil.h b/phlib/include/phutil.h index 9f68dda988fa..71b134fe0176 100644 --- a/phlib/include/phutil.h +++ b/phlib/include/phutil.h @@ -1140,6 +1140,16 @@ PhExtractIcon( _In_ HICON *IconSmall ); +PHLIBAPI +BOOLEAN +NTAPI +PhExtractIconEx( + _In_ PWSTR FileName, + _In_ INT IconIndex, + _In_ HICON *IconLarge, + _In_ HICON *IconSmall + ); + PHLIBAPI PLDR_DATA_TABLE_ENTRY NTAPI diff --git a/phlib/util.c b/phlib/util.c index 8e4a11f49b0c..b63d4b2ab530 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -5232,6 +5232,16 @@ BOOLEAN PhExtractIcon( _In_ HICON *IconLarge, _In_ HICON *IconSmall ) +{ + return PhExtractIconEx(FileName, 0, IconLarge, IconSmall); +} + +BOOLEAN PhExtractIconEx( + _In_ PWSTR FileName, + _In_ INT IconIndex, + _In_ HICON *IconLarge, + _In_ HICON *IconSmall + ) { static PH_INITONCE initOnce = PH_INITONCE_INIT; static HRESULT (WINAPI *PrivateExtractIconExW)( From efc010cbb8f2367b766b237528fbdffc8b28a0a7 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 15 Jul 2018 04:44:26 +1000 Subject: [PATCH 1108/2058] ExtendedTools: Add OpenAdapterFromHdc --- plugins/ExtendedTools/d3dkmt.h | 89 ++++++++++++++++++++++++++-------- 1 file changed, 69 insertions(+), 20 deletions(-) diff --git a/plugins/ExtendedTools/d3dkmt.h b/plugins/ExtendedTools/d3dkmt.h index 9d5c984a51c8..e92cce5ee10c 100644 --- a/plugins/ExtendedTools/d3dkmt.h +++ b/plugins/ExtendedTools/d3dkmt.h @@ -894,6 +894,24 @@ typedef struct _D3DKMT_OPENADAPTERFROMDEVICENAME _Out_ LUID AdapterLuid; // The locally unique identifier (LUID) of the graphics adapter for the device that DeviceName specifies. } D3DKMT_OPENADAPTERFROMDEVICENAME; +// Describes the mapping of the given name of a GDI device to a graphics adapter handle and monitor output. +typedef struct _D3DKMT_OPENADAPTERFROMGDIDISPLAYNAME +{ + _In_ WCHAR DeviceName[32]; // A Unicode string that contains the name of the GDI device from which to open an adapter instance. + _Out_ D3DKMT_HANDLE AdapterHandle; // A handle to the graphics adapter for the GDI device that DeviceName specifies. + _Out_ LUID AdapterLuid; // The locally unique identifier (LUID) of the graphics adapter for the GDI device that DeviceName specifies. + _Out_ ULONG VidPnSourceId; // The zero-based identification number of the video present source. +} D3DKMT_OPENADAPTERFROMGDIDISPLAYNAME; + +// Describes the mapping of a device context handle (HDC) to a graphics adapter handle and monitor output. +typedef struct _D3DKMT_OPENADAPTERFROMHDC +{ + _In_ HDC hDc; // The HDC for the graphics adapter and monitor output that are retrieved. + _Out_ D3DKMT_HANDLE AdapterHandle; // A handle to the graphics adapter for the HDC that hDc specifies. + _Out_ LUID AdapterLuid; // The locally unique identifier (LUID) of the graphics adapter for the HDC that hDc specifies. + _Out_ ULONG VidPnSourceId; // The zero-based identification number of the video present source. +} D3DKMT_OPENADAPTERFROMHDC; + // Describes the mapping of the given locally unique identifier (LUID) of a device to a graphics adapter handle. typedef struct _D3DKMT_OPENADAPTERFROMLUID { @@ -1339,15 +1357,17 @@ typedef struct _D3DKMT_QUERYSTATISTICS_PROCESS_SEGMENT_INFORMATION typedef enum _D3DKMT_QUERYSTATISTICS_TYPE { - D3DKMT_QUERYSTATISTICS_ADAPTER = 0, - D3DKMT_QUERYSTATISTICS_PROCESS = 1, - D3DKMT_QUERYSTATISTICS_PROCESS_ADAPTER = 2, - D3DKMT_QUERYSTATISTICS_SEGMENT = 3, - D3DKMT_QUERYSTATISTICS_PROCESS_SEGMENT = 4, - D3DKMT_QUERYSTATISTICS_NODE = 5, - D3DKMT_QUERYSTATISTICS_PROCESS_NODE = 6, - D3DKMT_QUERYSTATISTICS_VIDPNSOURCE = 7, - D3DKMT_QUERYSTATISTICS_PROCESS_VIDPNSOURCE = 8 + D3DKMT_QUERYSTATISTICS_ADAPTER, + D3DKMT_QUERYSTATISTICS_PROCESS, + D3DKMT_QUERYSTATISTICS_PROCESS_ADAPTER, + D3DKMT_QUERYSTATISTICS_SEGMENT, + D3DKMT_QUERYSTATISTICS_PROCESS_SEGMENT, + D3DKMT_QUERYSTATISTICS_NODE, + D3DKMT_QUERYSTATISTICS_PROCESS_NODE, + D3DKMT_QUERYSTATISTICS_VIDPNSOURCE, + D3DKMT_QUERYSTATISTICS_PROCESS_VIDPNSOURCE, + D3DKMT_QUERYSTATISTICS_PROCESS_SEGMENT_GROUP, + D3DKMT_QUERYSTATISTICS_PHYSICAL_ADAPTER } D3DKMT_QUERYSTATISTICS_TYPE; typedef struct _D3DKMT_QUERYSTATISTICS_QUERY_SEGMENT @@ -1368,6 +1388,7 @@ typedef struct _D3DKMT_QUERYSTATISTICS_QUERY_VIDPNSOURCE typedef union _D3DKMT_QUERYSTATISTICS_RESULT { D3DKMT_QUERYSTATISTICS_ADAPTER_INFORMATION AdapterInformation; + // D3DKMT_QUERYSTATISTICS_PHYSICAL_ADAPTER_INFORMATION PhysAdapterInformation; D3DKMT_QUERYSTATISTICS_SEGMENT_INFORMATION_V1 SegmentInformationV1; // WIN7 D3DKMT_QUERYSTATISTICS_SEGMENT_INFORMATION SegmentInformation; // WIN8 D3DKMT_QUERYSTATISTICS_NODE_INFORMATION NodeInformation; @@ -1377,6 +1398,7 @@ typedef union _D3DKMT_QUERYSTATISTICS_RESULT D3DKMT_QUERYSTATISTICS_PROCESS_SEGMENT_INFORMATION ProcessSegmentInformation; D3DKMT_QUERYSTATISTICS_PROCESS_NODE_INFORMATION ProcessNodeInformation; D3DKMT_QUERYSTATISTICS_PROCESS_VIDPNSOURCE_INFORMATION ProcessVidPnSourceInformation; + // D3DKMT_QUERYSTATISTICS_PROCESS_SEGMENT_GROUP_INFORMATION ProcessSegmentGroupInformation; } D3DKMT_QUERYSTATISTICS_RESULT; typedef struct _D3DKMT_QUERYSTATISTICS @@ -1910,42 +1932,56 @@ typedef struct _D3DKMT_ESCAPE // Function pointers -_Check_return_ +NTSYSAPI NTSTATUS NTAPI D3DKMTOpenAdapterFromDeviceName( _Inout_ CONST D3DKMT_OPENADAPTERFROMDEVICENAME *pData ); -_Check_return_ +NTSYSAPI +NTSTATUS +NTAPI +D3DKMTOpenAdapterFromGdiDisplayName( + _Inout_ CONST D3DKMT_OPENADAPTERFROMGDIDISPLAYNAME *pData + ); + +NTSYSAPI +NTSTATUS +NTAPI +D3DKMTOpenAdapterFromHdc( + _Inout_ CONST D3DKMT_OPENADAPTERFROMHDC *pData + ); + +NTSYSAPI NTSTATUS NTAPI D3DKMTOpenAdapterFromLuid( _Inout_ CONST D3DKMT_OPENADAPTERFROMLUID *pAdapter ); -_Check_return_ +NTSYSAPI NTSTATUS NTAPI D3DKMTEnumAdapters( _Inout_ CONST D3DKMT_ENUMADAPTERS *pData ); -_Check_return_ +NTSYSAPI NTSTATUS NTAPI D3DKMTEnumAdapters2( _Inout_ CONST D3DKMT_ENUMADAPTERS2 *pData ); -_Check_return_ +NTSYSAPI NTSTATUS NTAPI D3DKMTCloseAdapter( _In_ CONST D3DKMT_CLOSEADAPTER *pData ); -_Check_return_ +NTSYSAPI NTSTATUS NTAPI D3DKMTQueryAdapterInfo( @@ -1953,28 +1989,41 @@ D3DKMTQueryAdapterInfo( ); // rev -_Check_return_ +NTSYSAPI NTSTATUS NTAPI D3DKMTQueryStatistics( _Inout_ CONST D3DKMT_QUERYSTATISTICS *pData ); -_Check_return_ +NTSYSAPI NTSTATUS NTAPI D3DKMTQueryVideoMemoryInfo( _Inout_ CONST D3DKMT_QUERYVIDEOMEMORYINFO *pData ); -_Check_return_ +NTSYSAPI NTSTATUS NTAPI D3DKMTEscape( _Inout_ CONST D3DKMT_ESCAPE *pData ); -//EXTERN_C _Check_return_ NTSTATUS APIENTRY D3DKMTSetProcessSchedulingPriorityClass(_In_ HANDLE, _In_ D3DKMT_SCHEDULINGPRIORITYCLASS); -//EXTERN_C _Check_return_ NTSTATUS APIENTRY D3DKMTGetProcessSchedulingPriorityClass(_In_ HANDLE, _Out_ D3DKMT_SCHEDULINGPRIORITYCLASS*); +NTSYSAPI +NTSTATUS +NTAPI +D3DKMTSetProcessSchedulingPriorityClass( + _In_ HANDLE, + _In_ enum D3DKMT_SCHEDULINGPRIORITYCLASS + ); + +NTSYSAPI +NTSTATUS +NTAPI +D3DKMTGetProcessSchedulingPriorityClass( + _In_ HANDLE, + _Out_ enum D3DKMT_SCHEDULINGPRIORITYCLASS* + ); #endif From 0fc851095fce339dffa2e1df5d163f9a296f9718 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 15 Jul 2018 07:30:11 +1000 Subject: [PATCH 1109/2058] SetupTool: Add portable update support --- .../CustomSetupTool/configpage.c | 19 ++-- .../CustomSetupTool/CustomSetupTool/extract.c | 2 +- .../CustomSetupTool/include/setup.h | 7 +- .../CustomSetupTool/CustomSetupTool/install.c | 4 +- tools/CustomSetupTool/CustomSetupTool/main.c | 99 +++++++++++++------ tools/CustomSetupTool/CustomSetupTool/setup.c | 56 ++++------- .../CustomSetupTool/uninstall.c | 4 +- .../CustomSetupTool/CustomSetupTool/update.c | 43 ++++---- 8 files changed, 132 insertions(+), 102 deletions(-) diff --git a/tools/CustomSetupTool/CustomSetupTool/configpage.c b/tools/CustomSetupTool/CustomSetupTool/configpage.c index cbf668443da7..0bfcb04bcea8 100644 --- a/tools/CustomSetupTool/CustomSetupTool/configpage.c +++ b/tools/CustomSetupTool/CustomSetupTool/configpage.c @@ -65,9 +65,10 @@ INT_PTR CALLBACK SetupPropPage3_WndProc( SetupInitializeFont(GetDlgItem(hwndDlg, IDC_DBGTOOLS_CHECK), -12, FW_NORMAL); SetupInitializeFont(GetDlgItem(hwndDlg, IDC_RESET_CHECK), -12, FW_NORMAL); - context->SetupInstallPath = SetupFindInstallDirectory(); + if (PhIsNullOrEmptyString(SetupInstallPath)) + SetupInstallPath = SetupFindInstallDirectory(); - SetDlgItemText(hwndDlg, IDC_INSTALL_DIRECTORY, PhGetString(context->SetupInstallPath)); + SetDlgItemText(hwndDlg, IDC_INSTALL_DIRECTORY, PhGetString(SetupInstallPath)); Button_SetCheck(GetDlgItem(hwndDlg, IDC_SHORTCUT_CHECK), TRUE); Button_SetCheck(GetDlgItem(hwndDlg, IDC_SHORTCUT_ALL_CHECK), TRUE); //Button_SetCheck(GetDlgItem(hwndDlg, IDC_KPH_CHECK), TRUE); @@ -94,12 +95,15 @@ INT_PTR CALLBACK SetupPropPage3_WndProc( fileDialogFolderPath = PH_AUTO(PhGetFileDialogFileName(fileDialog)); PhTrimToNullTerminatorString(fileDialogFolderPath); + PhSwapReference(&SetupInstallPath, fileDialogFolderPath); PhFreeFileDialog(fileDialog); - - PhSwapReference(&context->SetupInstallPath, fileDialogFolderPath); - SetDlgItemText(hwndDlg, IDC_INSTALL_DIRECTORY, PhGetStringOrEmpty(context->SetupInstallPath)); } + + if (PhIsNullOrEmptyString(SetupInstallPath)) + SetupInstallPath = SetupFindInstallDirectory(); + + SetDlgItemText(hwndDlg, IDC_INSTALL_DIRECTORY, PhGetStringOrEmpty(SetupInstallPath)); } break; case IDC_STARTUP_CHECK: @@ -128,7 +132,6 @@ INT_PTR CALLBACK SetupPropPage3_WndProc( { case PSN_WIZNEXT: { - context->SetupInstallPath = PhGetWindowText(GetDlgItem(hwndDlg, IDC_INSTALL_DIRECTORY)); context->SetupCreateDesktopShortcut = Button_GetCheck(GetDlgItem(hwndDlg, IDC_SHORTCUT_CHECK)) == BST_CHECKED; context->SetupCreateDesktopShortcutAllUsers = Button_GetCheck(GetDlgItem(hwndDlg, IDC_SHORTCUT_ALL_CHECK)) == BST_CHECKED; context->SetupCreateDefaultTaskManager = Button_GetCheck(GetDlgItem(hwndDlg, IDC_TASKMANAGER_CHECK)) == BST_CHECKED; @@ -140,6 +143,10 @@ INT_PTR CALLBACK SetupPropPage3_WndProc( context->SetupResetSettings = Button_GetCheck(GetDlgItem(hwndDlg, IDC_RESET_CHECK)) == BST_CHECKED; context->SetupStartAppAfterExit = Button_GetCheck(GetDlgItem(hwndDlg, IDC_PHSTART_CHECK)) == BST_CHECKED; + SetupInstallPath = PhGetWindowText(GetDlgItem(hwndDlg, IDC_INSTALL_DIRECTORY)); + + if (PhIsNullOrEmptyString(SetupInstallPath)) + SetupInstallPath = SetupFindInstallDirectory(); #ifdef PH_BUILD_API SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, (LPARAM)IDD_DIALOG4); return TRUE; diff --git a/tools/CustomSetupTool/CustomSetupTool/extract.c b/tools/CustomSetupTool/CustomSetupTool/extract.c index 2c05c6dd9bf2..36c05dc79559 100644 --- a/tools/CustomSetupTool/CustomSetupTool/extract.c +++ b/tools/CustomSetupTool/CustomSetupTool/extract.c @@ -152,7 +152,7 @@ BOOLEAN SetupExtractBuild( extractPath = PhConcatStrings( 3, - PhGetString(Context->SetupInstallPath), + PhGetString(SetupInstallPath), L"\\", PhGetString(fileName) ); diff --git a/tools/CustomSetupTool/CustomSetupTool/include/setup.h b/tools/CustomSetupTool/CustomSetupTool/include/setup.h index 5b7fdb91efbb..12b68b88549c 100644 --- a/tools/CustomSetupTool/CustomSetupTool/include/setup.h +++ b/tools/CustomSetupTool/CustomSetupTool/include/setup.h @@ -115,9 +115,6 @@ typedef struct _PH_SETUP_CONTEXT }; ULONG ErrorCode; - - PPH_STRING SetupInstallPath; - PPH_STRING FilePath; PPH_STRING RelDate; @@ -127,7 +124,6 @@ typedef struct _PH_SETUP_CONTEXT PPH_STRING BinFileLength; PPH_STRING BinFileHash; PPH_STRING BinFileSignature; - PPH_STRING SetupFileDownloadUrl; PPH_STRING SetupFileLength; PPH_STRING SetupFileHash; @@ -148,8 +144,11 @@ typedef struct _PH_SETUP_CONTEXT ULONG CurrentMajorVersion; ULONG CurrentMinorVersion; ULONG CurrentRevisionVersion; + WNDPROC TaskDialogWndProc; } PH_SETUP_CONTEXT, *PPH_SETUP_CONTEXT; +extern PPH_STRING SetupInstallPath; + VOID SetupLoadImage( _In_ HWND WindowHandle, _In_ PWSTR Name diff --git a/tools/CustomSetupTool/CustomSetupTool/install.c b/tools/CustomSetupTool/CustomSetupTool/install.c index e3c279026340..e25c9db1c155 100644 --- a/tools/CustomSetupTool/CustomSetupTool/install.c +++ b/tools/CustomSetupTool/CustomSetupTool/install.c @@ -39,7 +39,7 @@ NTSTATUS SetupProgressThread( goto CleanupExit; // Create the install folder path. - if (!NT_SUCCESS(PhCreateDirectory(Context->SetupInstallPath))) + if (!NT_SUCCESS(PhCreateDirectory(SetupInstallPath))) goto CleanupExit; // Upgrade the 2.x settings file. @@ -48,7 +48,7 @@ NTSTATUS SetupProgressThread( // Remove the previous installation. if (Context->SetupResetSettings) { - PhDeleteDirectory(Context->SetupInstallPath); + PhDeleteDirectory(SetupInstallPath); } // Create the uninstaller. diff --git a/tools/CustomSetupTool/CustomSetupTool/main.c b/tools/CustomSetupTool/CustomSetupTool/main.c index e764c9f09bc0..85fb5737db2e 100644 --- a/tools/CustomSetupTool/CustomSetupTool/main.c +++ b/tools/CustomSetupTool/CustomSetupTool/main.c @@ -21,6 +21,7 @@ #include SETUP_COMMAND_TYPE SetupMode = SETUP_COMMAND_INSTALL; +PPH_STRING SetupInstallPath = NULL; VOID SetupInitializeDpi( VOID @@ -35,31 +36,6 @@ VOID SetupInitializeDpi( } } -BOOLEAN NTAPI MainPropSheetCommandLineCallback( - _In_opt_ PPH_COMMAND_LINE_OPTION Option, - _In_opt_ PPH_STRING Value, - _In_opt_ PVOID Context - ) -{ - if (Option) - SetupMode = Option->Id; - else - { - // HACK: PhParseCommandLine requires the - symbol for commandline parameters - // and we already support the -silent parameter however we need to maintain - // compatibility with the legacy Inno Setup. - if (!PhIsNullOrEmptyString(Value)) - { - if (PhEqualString2(Value, L"/silent", TRUE)) - { - SetupMode = SETUP_COMMAND_SILENTINSTALL; - } - } - } - - return TRUE; -} - INT CALLBACK MainPropSheet_Callback( _In_ HWND hwndDlg, _In_ UINT uMsg, @@ -184,6 +160,68 @@ VOID SetupShowInstallDialog( PhModalPropertySheet(&propSheetHeader); } +BOOLEAN NTAPI MainPropSheetCommandLineCallback( + _In_opt_ PPH_COMMAND_LINE_OPTION Option, + _In_opt_ PPH_STRING Value, + _In_opt_ PVOID Context + ) +{ + if (Option) + { + SetupMode = Option->Id; + + if (SetupMode == SETUP_COMMAND_UPDATE) + { + PPH_STRING directory; + PPH_STRING string; + + if (PhIsNullOrEmptyString(Value)) + { + SetupInstallPath = SetupFindInstallDirectory(); + return TRUE; + } + + if (string = PhHexStringToBufferEx(&Value->sr)) + { + if (directory = PhGetFullPath(string->Buffer, NULL)) + { + PhSwapReference(&SetupInstallPath, directory); + + if (!PhEndsWithString2(directory, L"\\", FALSE)) // HACK + { + PhMoveReference(&SetupInstallPath, PhConcatStringRefZ(&directory->sr, L"\\")); + } + + PhDereferenceObject(directory); + } + + PhDereferenceObject(string); + } + } + + if (PhIsNullOrEmptyString(SetupInstallPath)) + { + SetupInstallPath = SetupFindInstallDirectory(); + return TRUE; + } + } + else + { + // HACK: PhParseCommandLine requires the - symbol for commandline parameters + // and we already support the -silent parameter however we need to maintain + // compatibility with the legacy Inno Setup. + if (!PhIsNullOrEmptyString(Value)) + { + if (PhEqualString2(Value, L"/silent", TRUE)) + { + SetupMode = SETUP_COMMAND_SILENTINSTALL; + } + } + } + + return TRUE; +} + VOID SetupParseCommandLine( VOID ) @@ -192,7 +230,7 @@ VOID SetupParseCommandLine( { { SETUP_COMMAND_INSTALL, L"install", NoArgumentType }, { SETUP_COMMAND_UNINSTALL, L"uninstall", NoArgumentType }, - { SETUP_COMMAND_UPDATE, L"update", NoArgumentType }, + { SETUP_COMMAND_UPDATE, L"update", OptionalArgumentType }, { SETUP_COMMAND_REPAIR, L"repair", NoArgumentType }, { SETUP_COMMAND_SILENTINSTALL, L"silent", NoArgumentType }, }; @@ -257,12 +295,11 @@ INT WINAPI wWinMain( CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE); if (!NT_SUCCESS(PhInitializePhLibEx(L"Process Hacker - Setup", ULONG_MAX, Instance, 0, 0))) - return 1; + return EXIT_FAILURE; + SetupInitializeMutant(); PhGuiSupportInitialization(); SetupInitializeDpi(); - - SetupInitializeMutant(); SetupParseCommandLine(); switch (SetupMode) @@ -282,5 +319,5 @@ INT WINAPI wWinMain( break; } - return ERROR_SUCCESS; -} \ No newline at end of file + return EXIT_SUCCESS; +} diff --git a/tools/CustomSetupTool/CustomSetupTool/setup.c b/tools/CustomSetupTool/CustomSetupTool/setup.c index 53002aa2e34a..628df65576ba 100644 --- a/tools/CustomSetupTool/CustomSetupTool/setup.c +++ b/tools/CustomSetupTool/CustomSetupTool/setup.c @@ -54,7 +54,7 @@ NTSTATUS SetupCreateUninstallKey( { PPH_STRING tempString; - tempString = PhConcatStrings2(PhGetString(Context->SetupInstallPath), L"\\processhacker.exe,0"); + tempString = PhConcatStrings2(PhGetString(SetupInstallPath), L"\\processhacker.exe,0"); PhStringRefToUnicodeString(&tempString->sr, &value); RtlInitUnicodeString(&name, L"DisplayIcon"); PhStringRefToUnicodeString(&tempString->sr, &value); @@ -74,7 +74,7 @@ NTSTATUS SetupCreateUninstallKey( NtSetValueKey(keyHandle, &name, 0, REG_SZ, value.Buffer, (ULONG)value.MaximumLength); RtlInitUnicodeString(&name, L"InstallLocation"); - RtlInitUnicodeString(&value, PhGetString(Context->SetupInstallPath)); + RtlInitUnicodeString(&value, PhGetString(SetupInstallPath)); NtSetValueKey(keyHandle, &name, 0, REG_SZ, value.Buffer, (ULONG)value.MaximumLength); RtlInitUnicodeString(&name, L"Publisher"); @@ -82,7 +82,7 @@ NTSTATUS SetupCreateUninstallKey( NtSetValueKey(keyHandle, &name, 0, REG_SZ, value.Buffer, (ULONG)value.MaximumLength); RtlInitUnicodeString(&name, L"UninstallString"); - tempString = PhFormatString(L"\"%s\\processhacker-setup.exe\" -uninstall", PhGetString(Context->SetupInstallPath)); + tempString = PhFormatString(L"\"%s\\processhacker-setup.exe\" -uninstall", PhGetString(SetupInstallPath)); PhStringRefToUnicodeString(&tempString->sr, &value); NtSetValueKey(keyHandle, &name, 0, REG_SZ, value.Buffer, (ULONG)value.MaximumLength); PhDereferenceObject(tempString); @@ -135,31 +135,16 @@ PPH_STRING SetupFindInstallDirectory( // Check if the string is valid. if (PhIsNullOrEmptyString(setupInstallPath)) { - static PH_STRINGREF programW6432 = PH_STRINGREF_INIT(L"%ProgramW6432%"); - static PH_STRINGREF programFiles = PH_STRINGREF_INIT(L"%ProgramFiles%"); - static PH_STRINGREF defaultDirectoryName = PH_STRINGREF_INIT(L"\\Process Hacker\\"); + static PH_STRINGREF programW6432 = PH_STRINGREF_INIT(L"%ProgramW6432%\\Process Hacker\\"); + static PH_STRINGREF programFiles = PH_STRINGREF_INIT(L"%ProgramFiles%\\Process Hacker\\"); SYSTEM_INFO info; GetNativeSystemInfo(&info); if (info.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) - { - PPH_STRING expandedString; - - if (expandedString = PH_AUTO(PhExpandEnvironmentStrings(&programW6432))) - { - setupInstallPath = PhConcatStringRef2(&expandedString->sr, &defaultDirectoryName); - } - } + setupInstallPath = PhExpandEnvironmentStrings(&programW6432); else - { - PPH_STRING expandedString; - - if (expandedString = PH_AUTO(PhExpandEnvironmentStrings(&programFiles))) - { - setupInstallPath = PhConcatStringRef2(&expandedString->sr, &defaultDirectoryName); - } - } + setupInstallPath = PhExpandEnvironmentStrings(&programFiles); } if (PhIsNullOrEmptyString(setupInstallPath)) @@ -167,9 +152,6 @@ PPH_STRING SetupFindInstallDirectory( setupInstallPath = PhCreateString(L"C:\\Program Files\\Process Hacker\\"); } - // Remove extra backslashes - PathRemoveBackslash(PhGetString(setupInstallPath)); - return setupInstallPath; } @@ -185,14 +167,14 @@ BOOLEAN SetupCreateUninstallFile( return FALSE; // Check if the user has started the setup from the installation folder. - if (PhStartsWithStringRef2(¤tFilePath->sr, PhGetString(Context->SetupInstallPath), TRUE)) + if (PhStartsWithStringRef2(¤tFilePath->sr, PhGetString(SetupInstallPath), TRUE)) { PhDereferenceObject(currentFilePath); return TRUE; } - backupFilePath = PhConcatStrings2(PhGetString(Context->SetupInstallPath), L"\\processhacker-setup.bak"); - uninstallFilePath = PhConcatStrings2(PhGetString(Context->SetupInstallPath), L"\\processhacker-setup.exe"); + backupFilePath = PhConcatStrings2(PhGetString(SetupInstallPath), L"\\processhacker-setup.bak"); + uninstallFilePath = PhConcatStrings2(PhGetString(SetupInstallPath), L"\\processhacker-setup.exe"); if (RtlDoesFileExists_U(backupFilePath->Buffer)) { @@ -242,7 +224,7 @@ VOID SetupDeleteUninstallFile( { PPH_STRING uninstallFilePath; - uninstallFilePath = PhConcatStrings2(PhGetString(Context->SetupInstallPath), L"\\processhacker-setup.exe"); + uninstallFilePath = PhConcatStrings2(PhGetString(SetupInstallPath), L"\\processhacker-setup.exe"); if (RtlDoesFileExists_U(uninstallFilePath->Buffer)) { @@ -428,7 +410,7 @@ VOID SetupStartKph( { PPH_STRING clientPath; - clientPath = PhConcatStrings2(PhGetString(Context->SetupInstallPath), L"\\ProcessHacker.exe"); + clientPath = PhConcatStrings2(PhGetString(SetupInstallPath), L"\\ProcessHacker.exe"); if (RtlDoesFileExists_U(PhGetString(clientPath))) { @@ -476,7 +458,7 @@ VOID SetupSetWindowsOptions( PPH_STRING clientPathString; PPH_STRING startmenuFolderString; - clientPathString = PhConcatStrings2(PhGetString(Context->SetupInstallPath), L"\\ProcessHacker.exe"); + clientPathString = PhConcatStrings2(PhGetString(SetupInstallPath), L"\\ProcessHacker.exe"); // Create the startmenu shortcut. if (startmenuFolderString = PhGetKnownLocation(CSIDL_COMMON_PROGRAMS, L"\\Process Hacker.lnk")) @@ -485,7 +467,7 @@ VOID SetupSetWindowsOptions( L"ProcessHacker.Desktop.App", PhGetString(startmenuFolderString), PhGetString(clientPathString), - PhGetString(Context->SetupInstallPath) + PhGetString(SetupInstallPath) ); PhDereferenceObject(startmenuFolderString); } @@ -499,7 +481,7 @@ VOID SetupSetWindowsOptions( L"ProcessHacker.Desktop.App", PhGetString(startmenuFolderString), PhGetString(clientPathString), - PhGetString(Context->SetupInstallPath) + PhGetString(SetupInstallPath) ); PhDereferenceObject(startmenuFolderString); } @@ -515,7 +497,7 @@ VOID SetupSetWindowsOptions( L"ProcessHacker.Desktop.App", PhGetString(startmenuFolderString), PhGetString(clientPathString), - PhGetString(Context->SetupInstallPath) + PhGetString(SetupInstallPath) ); PhDereferenceObject(startmenuFolderString); } @@ -525,13 +507,13 @@ VOID SetupSetWindowsOptions( // Create the PE Viewer startmenu shortcut. if (startmenuFolderString = PhGetKnownLocation(CSIDL_COMMON_PROGRAMS, L"\\PE Viewer.lnk")) { - PPH_STRING peviewPathString = PhConcatStrings2(PhGetString(Context->SetupInstallPath), L"\\peview.exe"); + PPH_STRING peviewPathString = PhConcatStrings2(PhGetString(SetupInstallPath), L"\\peview.exe"); SetupCreateLink( L"PeViewer.Desktop.App", PhGetString(startmenuFolderString), PhGetString(peviewPathString), - PhGetString(Context->SetupInstallPath) + PhGetString(SetupInstallPath) ); PhDereferenceObject(peviewPathString); @@ -712,7 +694,7 @@ BOOLEAN SetupExecuteProcessHacker( BOOLEAN success = FALSE; PPH_STRING clientPath; - clientPath = PhConcatStrings2(PhGetString(Context->SetupInstallPath), L"\\ProcessHacker.exe"); + clientPath = PhConcatStrings2(PhGetString(SetupInstallPath), L"\\ProcessHacker.exe"); if (RtlDoesFileExists_U(clientPath->Buffer)) { diff --git a/tools/CustomSetupTool/CustomSetupTool/uninstall.c b/tools/CustomSetupTool/CustomSetupTool/uninstall.c index f78b5cbb6b86..e2c672713fef 100644 --- a/tools/CustomSetupTool/CustomSetupTool/uninstall.c +++ b/tools/CustomSetupTool/CustomSetupTool/uninstall.c @@ -44,7 +44,7 @@ NTSTATUS SetupUninstallBuild( _In_ PPH_SETUP_CONTEXT Context ) { - Context->SetupInstallPath = SetupFindInstallDirectory(); + SetupInstallPath = SetupFindInstallDirectory(); // Stop Process Hacker. if (!ShutdownProcessHacker()) @@ -64,7 +64,7 @@ NTSTATUS SetupUninstallBuild( SetupDeleteUninstallKey(); // Remove the previous installation. - PhDeleteDirectory(Context->SetupInstallPath); + PhDeleteDirectory(SetupInstallPath); ShowUninstallCompleteDialog(Context); return STATUS_SUCCESS; diff --git a/tools/CustomSetupTool/CustomSetupTool/update.c b/tools/CustomSetupTool/CustomSetupTool/update.c index a1bd7f89fefa..dfbfd600ba01 100644 --- a/tools/CustomSetupTool/CustomSetupTool/update.c +++ b/tools/CustomSetupTool/CustomSetupTool/update.c @@ -30,8 +30,6 @@ NTSTATUS SetupUpdateBuild( _In_ PPH_SETUP_CONTEXT Context ) { - Context->SetupInstallPath = SetupFindInstallDirectory(); - if (!ShutdownProcessHacker()) goto CleanupExit; @@ -122,9 +120,6 @@ HRESULT CALLBACK SetupErrorTaskDialogCallbackProc( switch (uMsg) { case TDN_NAVIGATED: - { - - } break; } @@ -132,6 +127,7 @@ HRESULT CALLBACK SetupErrorTaskDialogCallbackProc( } VOID SetupShowUpdatingErrorDialog( + _In_ HWND hwndDlg, _In_ PPH_SETUP_CONTEXT Context ) { @@ -139,7 +135,7 @@ VOID SetupShowUpdatingErrorDialog( memset(&config, 0, sizeof(TASKDIALOGCONFIG)); config.cbSize = sizeof(TASKDIALOGCONFIG); - config.dwFlags = TDF_USE_HICON_MAIN | TDF_ALLOW_DIALOG_CANCELLATION | TDF_SHOW_MARQUEE_PROGRESS_BAR | TDF_CAN_BE_MINIMIZED | TDF_ENABLE_HYPERLINKS; + config.dwFlags = TDF_USE_HICON_MAIN | TDF_ALLOW_DIALOG_CANCELLATION | TDF_CAN_BE_MINIMIZED; config.cxWidth = 200; config.dwCommonButtons = TDCBF_CLOSE_BUTTON; config.hMainIcon = Context->IconLargeHandle; @@ -156,19 +152,23 @@ VOID SetupShowUpdatingErrorDialog( config.pszContent = PhGetString(errorString); } - SendMessage(Context->DialogHandle, TDM_NAVIGATE_PAGE, 0, (LPARAM)&config); + SendMessage(hwndDlg, TDM_NAVIGATE_PAGE, 0, (LPARAM)&config); } LRESULT CALLBACK TaskDialogSubclassProc( _In_ HWND hwndDlg, _In_ UINT uMsg, _In_ WPARAM wParam, - _In_ LPARAM lParam, - _In_ UINT_PTR uIdSubclass, - _In_ ULONG_PTR dwRefData + _In_ LPARAM lParam ) { - PPH_SETUP_CONTEXT context = (PPH_SETUP_CONTEXT)dwRefData; + PPH_SETUP_CONTEXT context; + WNDPROC oldWndProc; + + if (!(context = PhGetWindowContext(hwndDlg, UCHAR_MAX))) + return 0; + + oldWndProc = context->TaskDialogWndProc; switch (uMsg) { @@ -182,19 +182,20 @@ LRESULT CALLBACK TaskDialogSubclassProc( SetForegroundWindow(hwndDlg); } break; - case WM_NCDESTROY: + case WM_DESTROY: { - RemoveWindowSubclass(hwndDlg, TaskDialogSubclassProc, uIdSubclass); + SetWindowLongPtr(hwndDlg, GWLP_WNDPROC, (LONG_PTR)oldWndProc); + PhRemoveWindowContext(hwndDlg, UCHAR_MAX); } break; case WM_APP + IDD_ERROR: { - SetupShowUpdatingErrorDialog(context); + SetupShowUpdatingErrorDialog(hwndDlg, context); } break; } - return DefSubclassProc(hwndDlg, uMsg, wParam, lParam); + return CallWindowProc(oldWndProc, hwndDlg, uMsg, wParam, lParam); } HRESULT CALLBACK SetupUpdatingTaskDialogCallbackProc( @@ -278,13 +279,17 @@ HRESULT CALLBACK TaskDialogBootstrapCallback( // Center the window on the desktop. PhCenterWindow(hwndDlg, NULL); + // Create the Taskdialog icons. TaskDialogCreateIcons(context); + // Subclass the Taskdialog. - SetWindowSubclass(hwndDlg, TaskDialogSubclassProc, 0, (ULONG_PTR)context); + context->TaskDialogWndProc = (WNDPROC)GetWindowLongPtr(hwndDlg, GWLP_WNDPROC); + PhSetWindowContext(hwndDlg, UCHAR_MAX, context); + SetWindowLongPtr(hwndDlg, GWLP_WNDPROC, (LONG_PTR)TaskDialogSubclassProc); + // Navigate to the first page. SetupShowUpdatingDialog(context); - SendMessage(hwndDlg, WM_TASKDIALOGINIT, 0, 0); } break; @@ -305,7 +310,7 @@ VOID SetupShowUpdateDialog( PhInitializeAutoPool(&autoPool); config.cbSize = sizeof(TASKDIALOGCONFIG); - config.dwFlags = TDF_POSITION_RELATIVE_TO_WINDOW; + config.dwFlags = TDF_USE_HICON_MAIN | TDF_ALLOW_DIALOG_CANCELLATION | TDF_SHOW_MARQUEE_PROGRESS_BAR | TDF_CAN_BE_MINIMIZED | TDF_ENABLE_HYPERLINKS | TDF_POSITION_RELATIVE_TO_WINDOW; config.dwCommonButtons = TDCBF_CANCEL_BUTTON; config.pszWindowTitle = PhApplicationName; config.pfCallback = TaskDialogBootstrapCallback; @@ -314,4 +319,4 @@ VOID SetupShowUpdateDialog( TaskDialogIndirect(&config, NULL, NULL, NULL); PhDeleteAutoPool(&autoPool); -} \ No newline at end of file +} From 36e48537a823580dd08439cfaea0cd8b401317cb Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 15 Jul 2018 09:21:41 +1000 Subject: [PATCH 1110/2058] BuildTools: Fix appveyor build exit status --- .../Properties/Resources.Designer.cs | 2 +- tools/CustomBuildTool/Source Files/Build.cs | 160 ++++++++++++------ tools/CustomBuildTool/Source Files/Program.cs | 52 +++--- tools/CustomBuildTool/Source Files/Utils.cs | 30 ++-- .../bin/Release/CustomBuildTool.exe | Bin 163328 -> 164864 bytes .../bin/Release/CustomBuildTool.pdb | Bin 75264 -> 75264 bytes 6 files changed, 147 insertions(+), 97 deletions(-) diff --git a/tools/CustomBuildTool/Properties/Resources.Designer.cs b/tools/CustomBuildTool/Properties/Resources.Designer.cs index 7135019864c9..697eb463ba82 100644 --- a/tools/CustomBuildTool/Properties/Resources.Designer.cs +++ b/tools/CustomBuildTool/Properties/Resources.Designer.cs @@ -19,7 +19,7 @@ namespace CustomBuildTool.Properties { // class via a tool like ResGen or Visual Studio. // To add or remove a member, edit your .ResX file then rerun ResGen // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] internal class Resources { diff --git a/tools/CustomBuildTool/Source Files/Build.cs b/tools/CustomBuildTool/Source Files/Build.cs index d0cfb0acca5e..1ce063ba0004 100644 --- a/tools/CustomBuildTool/Source Files/Build.cs +++ b/tools/CustomBuildTool/Source Files/Build.cs @@ -156,9 +156,9 @@ public static class Build public static bool InitializeBuildEnvironment(bool CheckDependencies) { TimeStart = DateTime.Now; - BuildOutputFolder = "build\\output"; + BuildOutputFolder = "build\\output\\"; MSBuildExePath = VisualStudio.GetMsbuildFilePath(); - GitExePath = VisualStudio.GetFilePathFromPath("git.exe"); + GitExePath = Win32.SearchFile("git.exe"); CustomSignToolPath = "tools\\CustomSignTool\\bin\\Release32\\CustomSignTool.exe"; BuildNightly = !string.Equals(Environment.ExpandEnvironmentVariables("%APPVEYOR_BUILD_API%"), "%APPVEYOR_BUILD_API%", StringComparison.OrdinalIgnoreCase); @@ -269,12 +269,6 @@ public static void ShowBuildEnvironment(string Platform, bool ShowBuildInfo, boo if (ShowBuildInfo && !GitExportBuild) { - if (!string.IsNullOrEmpty(BuildBranch)) - { - Program.PrintColorMessage("Branch: ", ConsoleColor.DarkGray, false); - Program.PrintColorMessage(BuildBranch, ConsoleColor.Green, true); - } - Program.PrintColorMessage("Version: ", ConsoleColor.DarkGray, false); Program.PrintColorMessage(BuildVersion, ConsoleColor.Green, false); @@ -285,6 +279,13 @@ public static void ShowBuildEnvironment(string Platform, bool ShowBuildInfo, boo Program.PrintColorMessage(")", ConsoleColor.DarkGray, false); } + if (!string.IsNullOrEmpty(BuildBranch)) + { + Program.PrintColorMessage(" [", ConsoleColor.DarkGray, false); + Program.PrintColorMessage(BuildBranch, ConsoleColor.DarkBlue, false); + Program.PrintColorMessage("]", ConsoleColor.DarkGray, false); + } + Program.PrintColorMessage(Environment.NewLine, ConsoleColor.DarkGray, true); // TODO: The Win10 RS4 release has issues with the git pretty format. @@ -1041,17 +1042,19 @@ public static void WebServiceUpdateConfig() try { - System.Net.ServicePointManager.Expect100Continue = false; - using (HttpClient client = new HttpClient()) { client.DefaultRequestHeaders.Add("X-ApiKey", buildPostApiKey); var httpTask = client.PostAsync(buildPostUrl, new StringContent(buildPostString, Encoding.UTF8, "application/json")); - httpTask.Wait(); - if (!httpTask.Result.IsSuccessStatusCode) + if (httpTask.Result.IsSuccessStatusCode) + { + // Update Appveyor build version string. + Win32.ShellExecute("appveyor", "UpdateBuild -Version \"" + BuildVersion + "\" "); + } + else { Program.PrintColorMessage("[UpdateBuildWebService] " + httpTask.Result, ConsoleColor.Red); } @@ -1065,81 +1068,126 @@ public static void WebServiceUpdateConfig() public static bool AppveyorUploadBuildFiles() { + string buildPostKey; + string buildPostUrl; string[] buildFileArray = { - //BuildOutputFolder + "\\processhacker-build-websetup.exe", - BuildOutputFolder + "\\processhacker-build-setup.exe", - BuildOutputFolder + "\\processhacker-build-bin.zip", - BuildOutputFolder + "\\processhacker-build-checksums.txt", - BuildOutputFolder + "\\processhacker-build-pdb.zip" + //"\\processhacker-build-websetup.exe", + "\\processhacker-build-setup.exe", + "\\processhacker-build-bin.zip", + "\\processhacker-build-checksums.txt", + "\\processhacker-build-pdb.zip" }; string[] releaseFileArray = { - //BuildOutputFolder + "\\processhacker-websetup.exe", - BuildOutputFolder + "\\processhacker-" + BuildVersion + "-setup.exe", - BuildOutputFolder + "\\processhacker-" + BuildVersion + "-bin.zip", - BuildOutputFolder + "\\processhacker-" + BuildVersion + "-checksums.txt", - BuildOutputFolder + "\\processhacker-" + BuildVersion + "-pdb.zip" + //"\\processhacker-build-websetup.exe", + "\\processhacker-build-setup.exe", + "\\processhacker-build-bin.zip", + "\\processhacker-build-checksums.txt" }; if (!BuildNightly) return false; - // Cleanup existing release files. - foreach (string file in releaseFileArray) + buildPostKey = Environment.ExpandEnvironmentVariables("%APPVEYOR_BUILD_KEY%").Replace("%APPVEYOR_BUILD_KEY%", string.Empty); + buildPostUrl = Environment.ExpandEnvironmentVariables("%APPVEYOR_BUILD_URL%").Replace("%APPVEYOR_BUILD_URL%", string.Empty); + + if (string.IsNullOrEmpty(buildPostKey)) + return false; + if (string.IsNullOrEmpty(buildPostUrl)) + return false; + + try { - if (File.Exists(file)) + foreach (string file in buildFileArray) { - try - { - File.Delete(file); - } - catch (Exception ex) - { - Program.PrintColorMessage("[WebServiceUploadBuild] " + ex, ConsoleColor.Red); - return false; - } + var destinationFile = file.Replace("-build-", $"-{BuildVersion}-"); + + if (File.Exists(BuildOutputFolder + destinationFile)) + File.Delete(BuildOutputFolder + destinationFile); + + if (File.Exists(BuildOutputFolder + file)) + File.Move(BuildOutputFolder + file, BuildOutputFolder + destinationFile); } } + catch (Exception ex) + { + Program.PrintColorMessage("[WebServiceUploadBuild] " + ex, ConsoleColor.Red); + return false; + } - // Rename build files with the current version processhacker-3.1-abc.ext - for (int i = 0; i < buildFileArray.Length; i++) + try { - if (File.Exists(buildFileArray[i])) + foreach (string file in buildFileArray) { - try - { - File.Move(buildFileArray[i], releaseFileArray[i]); - } - catch (Exception ex) + if (File.Exists(BuildOutputFolder + file)) { - Program.PrintColorMessage("[WebServiceUploadBuild] " + ex, ConsoleColor.Red); - return false; + string filename = Path.GetFileName(BuildOutputFolder + file); + + using (HttpClient httpClient = new HttpClient()) + using (FileStream fileStream = File.OpenRead(BuildOutputFolder + file)) + using (HttpContent httpContent = new StreamContent(fileStream)) + using (MultipartFormDataContent httpFormData = new MultipartFormDataContent()) + { + httpClient.DefaultRequestHeaders.Add("X-ApiKey", buildPostKey); + httpContent.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/octet-stream"); + httpContent.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("form-data") + { + Name = "\"file\"", + FileName = $"\"{filename}\"", + }; + httpFormData.Add(httpContent, "file", filename); + + Console.WriteLine($"Uploading {filename}..."); + + var response = httpClient.PostAsync(buildPostUrl, httpFormData); + response.Wait(); + + if (!response.Result.IsSuccessStatusCode) + { + Program.PrintColorMessage("[UploadBuildWebServiceStatusCode]", ConsoleColor.Red); + } + } } } } + catch (Exception) + { + Program.PrintColorMessage("[UploadBuildWebServiceAsync-Exception]", ConsoleColor.Red); + return false; + } - // Upload build files to download server. - foreach (string file in releaseFileArray) + try { - if (File.Exists(file)) + foreach (string file in releaseFileArray) { - Console.WriteLine("Uploading " + file + "..."); + var sourceFile = file.Replace("-build-", $"-{BuildVersion}-"); - try + if (File.Exists(BuildOutputFolder + sourceFile)) { - Win32.ShellExecute("appveyor", "PushArtifact " + file); + Win32.ShellExecute("appveyor", "PushArtifact " + BuildOutputFolder + sourceFile); } - catch (Exception ex) + else { - Program.PrintColorMessage("[WebServicePushArtifact] " + ex, ConsoleColor.Red); - return false; + Program.PrintColorMessage("[Build] missing file: " + sourceFile, ConsoleColor.Yellow); } } } + catch (Exception ex) + { + Program.PrintColorMessage("[WebServiceAppveyorPushArtifact] " + ex, ConsoleColor.Red); + return false; + } - // Update Appveyor build version string. - Win32.ShellExecute("appveyor", "UpdateBuild -Version \"" + BuildLongVersion + "\" "); + try + { + Win32.ShellExecute("appveyor", $"UpdateBuild -Version \"{BuildVersion}\" "); + } + catch (Exception ex) + { + Program.PrintColorMessage("[WebServiceAppveyorUpdateBuild] " + ex, ConsoleColor.Red); + return false; + } return true; } @@ -1389,7 +1437,7 @@ public static bool BuildAppxSignature() string makeCertExePath = Environment.ExpandEnvironmentVariables("%ProgramFiles(x86)%\\Windows Kits\\10\\bin\\" + SdkVersion + "\\x64\\MakeCert.exe"); string pvk2PfxExePath = Environment.ExpandEnvironmentVariables("%ProgramFiles(x86)%\\Windows Kits\\10\\bin\\" + SdkVersion + "\\x64\\Pvk2Pfx.exe"); - string certUtilExePath = VisualStudio.GetFilePathFromPath("certutil.exe"); + string certUtilExePath = Win32.SearchFile("certutil.exe"); try { diff --git a/tools/CustomBuildTool/Source Files/Program.cs b/tools/CustomBuildTool/Source Files/Program.cs index 2d089279e9e2..dbb2b91bad57 100644 --- a/tools/CustomBuildTool/Source Files/Program.cs +++ b/tools/CustomBuildTool/Source Files/Program.cs @@ -198,47 +198,49 @@ public static void Main(string[] args) else if (ProgramArgs.ContainsKey("-appveyor")) { if (!Build.InitializeBuildEnvironment(true)) - return; + Environment.Exit(1); Build.ShowBuildEnvironment("nightly", true, true); Build.CopyKeyFiles(); if (!Build.BuildSolution("ProcessHacker.sln", - BuildFlags.Build32bit | BuildFlags.Build64bit | + BuildFlags.Build32bit | BuildFlags.Build64bit | BuildFlags.BuildVerbose | BuildFlags.BuildApi )) - return; + Environment.Exit(1); if (!Build.CopyKProcessHacker(BuildFlags.Build32bit | BuildFlags.Build64bit | BuildFlags.BuildVerbose)) - return; + Environment.Exit(1); if (!BuildSdk(BuildFlags.Build32bit | BuildFlags.Build64bit | BuildFlags.BuildVerbose)) - return; + Environment.Exit(1); - if (!Build.BuildSolution("plugins\\Plugins.sln", - BuildFlags.Build32bit | BuildFlags.Build64bit | + if (!Build.BuildSolution("plugins\\Plugins.sln", + BuildFlags.Build32bit | BuildFlags.Build64bit | BuildFlags.BuildVerbose | BuildFlags.BuildApi )) - return; + Environment.Exit(1); if (!Build.CopyWow64Files(BuildFlags.None)) - return; + Environment.Exit(1); - if (!Build.BuildBinZip()) - return; //if (!Build.BuildWebSetupExe()) - // return; - //if (!Build.BuildPdbZip()) - // return; + // Environment.Exit(1); if (!Build.BuildSetupExe()) - return; + Environment.Exit(1); + if (!Build.BuildBinZip()) + Environment.Exit(1); + if (!Build.BuildPdbZip()) + Environment.Exit(1); if (!Build.BuildChecksumsFile()) - return; + Environment.Exit(1); if (!Build.BuildUpdateSignature()) - return; + Environment.Exit(1); + + if (!Build.AppveyorUploadBuildFiles()) + Environment.Exit(1); - if (Build.AppveyorUploadBuildFiles()) - Build.WebServiceUpdateConfig(); + Build.WebServiceUpdateConfig(); } else if (ProgramArgs.ContainsKey("-appxbuild")) { @@ -249,7 +251,7 @@ public static void Main(string[] args) Build.CopyKeyFiles(); if (!Build.BuildSolution("ProcessHacker.sln", - BuildFlags.Build32bit | BuildFlags.Build64bit | + BuildFlags.Build32bit | BuildFlags.Build64bit | BuildFlags.BuildVerbose | BuildFlags.BuildApi )) return; @@ -257,8 +259,8 @@ public static void Main(string[] args) if (!BuildSdk(BuildFlags.Build32bit | BuildFlags.Build64bit | BuildFlags.BuildVerbose)) return; - if (!Build.BuildSolution("plugins\\Plugins.sln", - BuildFlags.Build32bit | BuildFlags.Build64bit | + if (!Build.BuildSolution("plugins\\Plugins.sln", + BuildFlags.Build32bit | BuildFlags.Build64bit | BuildFlags.BuildVerbose | BuildFlags.BuildApi )) return; @@ -291,9 +293,9 @@ public static void Main(string[] args) Build.ShowBuildEnvironment("release", true, true); Build.CopyKeyFiles(); - + if (!Build.BuildSolution("ProcessHacker.sln", - BuildFlags.Build32bit | BuildFlags.Build64bit | + BuildFlags.Build32bit | BuildFlags.Build64bit | BuildFlags.BuildVerbose | BuildFlags.BuildApi )) return; @@ -305,7 +307,7 @@ public static void Main(string[] args) return; if (!Build.BuildSolution("plugins\\Plugins.sln", - BuildFlags.Build32bit | BuildFlags.Build64bit | + BuildFlags.Build32bit | BuildFlags.Build64bit | BuildFlags.BuildVerbose | BuildFlags.BuildApi )) return; diff --git a/tools/CustomBuildTool/Source Files/Utils.cs b/tools/CustomBuildTool/Source Files/Utils.cs index c530efbb7cb2..9c2920eed7ec 100644 --- a/tools/CustomBuildTool/Source Files/Utils.cs +++ b/tools/CustomBuildTool/Source Files/Utils.cs @@ -58,6 +58,21 @@ public static string ShellExecute(string FileName, string args) return output; } + public static string SearchFile(string FileName) + { + string where = Environment.ExpandEnvironmentVariables("%SystemRoot%\\System32\\where.exe"); + + if (File.Exists(where)) + { + string whereResult = ShellExecute(where, FileName); + + if (!string.IsNullOrEmpty(whereResult)) + return whereResult; + } + + return null; + } + public static void ImageResizeFile(int size, string FileName, string OutName) { using (var src = System.Drawing.Image.FromFile(FileName)) @@ -205,21 +220,6 @@ public static string HashFile(string FileName) public static class VisualStudio { - public static string GetFilePathFromPath(string FileName) - { - string where = Environment.ExpandEnvironmentVariables("%windir%\\System32\\where.exe"); - - if (File.Exists(where)) - { - string whereResult = Win32.ShellExecute(where, FileName); - - if (!string.IsNullOrEmpty(whereResult)) - return whereResult; - } - - return null; - } - public static string GetMsbuildFilePath() { string vswhere = string.Empty; diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe b/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe index a36b2179ed66fa3ac3540c468da96aa90da13858..d0deb2027d31141a8cb79c26a73efbf76b55017b 100644 GIT binary patch delta 23521 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 bef6;KE9vW1F1(PU`+$YL9^M(3zLWk7jdo`B delta 22522 zcmbt+2VhiH_WphE&Agd;Q!*u)$xO;jDnkko>Agr5Wa(0c2ne{y;0+c;GKuIaii_|R z0Yxdgia$}=Aa(^2cM)BzyRu4F)`}HYvCICybKjeixVyjd59Yh)JLlYUdwFlhG+nPX z{p7g$`qGsX2hCvS&%3OYIi)U)orGeIB(y_v*4;m)_M}H*zak!!*juX&i!i5PpUhm4 zA9G8rP_I8-qfe7MXd}O*9QZw{-yl^>|IqhJ9i*%DR;jeIJjVz!5>}a6nfC(5Htt}I zw6hpf@3TtGYe%FieVkl9zJRf%@doIdtc+QBHE5HKq}#|)#F!?ef_O2+;2Eh&A>)1+ z8=}x?)zxYO711;`Q9{lK^_S%C@lRp5#VeqQx9lIY@;Qb}UErX@j%j@-y zN`Z7xAEv}4tA3$UEDh7IRXRvXeU~yUe>^H(5o~mz!0i4d(;Spo^N4G`3gXM0s4Y(BKk<09wmA@O~Y2uI)HF)4QqV7RUhY#=yBWG z$p$h$lrqX|{FqSr0^{9K?V8E_bMok@n%S#|8a|;cpB%mj=KmBWhwmhhbQG$@320P( zqBpqS-X-}X#qU7<o$}*?&-9HWlby$nC1YWBFzvw<8tk^?ar;bazPpNG4iWH90&G zMyFp6FebtyBni_9{xX@mMod$64}J;B+4*it8TpYclgRgJ%7oct;k5-=Fc$L&(mkHe z0~bJJ9B3qo%A3Q!HfKEEEsJqgD=9F>xaD zzv-9c;U(r>KL*g)B<0 zjAgV!7FuENizX-fQHKaanzkyHtyq*zSviF)az2&OCb=L&EgaGj3`3fl0l%ZHVwyTR z$)R{hD%@U@QIl+{X;KTfcz^PuiEOwM6@63B^C>IcER1%WeV@^as?m+e=*x@&w>?z^ zH`b0Qfyy@43(-tZFZ6epCg^wi!wY`{kE|JOPO*LevJx3BRl>Mp{Qys+Cd*18iK`9W zeA;Yn`5546AY!G{-LCs=INeo!dLUH&F!E$3X-eN(TXaI;F;+vW>&G0|1-T~Zc!-Ho!Pd0eO7K!vR%HgnJ>LoII7wdz!EeJ z?LwLE8Le>l!o6V-`b$&!{b)gAFyu;=e+apeV#PaCXAS}6rEK42`{|y%VriaUn-{`m z_)BMjJ}0kZ&o1TJ-D9IL)EwNqmyjj3frYBXmXxyX)%WG)CNmW@vwWAGC0NzI)uz{g zimbr!qC)xgP#XTvKoYGG^PhmmdDmGv~KMakh6jo!lf0S0J4Ljjj zk(8;OZhc*-R`Ti3hWbf+^q)dAlQXJN33@aTQ!+ipgYl85e8VU}!0xjr&Y`B<246>F zG(?}>?z6?mka8!K4d+5ij0FT7K1Tu%iyD$~q#O^Zjqt<;(gWjn()m+lJg?Btr_%CyaySH2K^Gf4Eir}%9$&qlMzs?2gR=3vLWFlWXD-Xsc+A2CV#2 z?{oOH%>k#+X~Z1O@1?3Z`P0-2+703p0sJ5+|BEmgdmqi-%GSbUz{S5Jwd)sUws!Vu zcxupmm`f<}HX}xd8q8M=zJ*VQlv$~jp(>w>DZ(T?_b~Pzb9~04G%pydkaD_7ruW zrCNPmakx~6d$pC{gM?lVw1_mUCeB8=+bbg6*GV4~3)hb7B-|z=*{qEbI($F!i`kl9-X}5|b5Z*`r+v(QqjN?RG4_^oGnxWJ zGe4s#G&JiBO_Bz#$WT3{wd`W z7mIZ9@e8pGqi1DINp4mI6N7BA4OmPWGf&q^Sj9tR5l)u)gYb1b_`o_W^JxI_*aAg8 zWU*Wgg;9LEUmfBxGe(QFVG8OWuq1sJ-c0!igI0pjIxu?(YGWP!(sukm*hZiA@AEy< z*2XVM(oMIlD_w-oqY7Dl)_{tAvzOQaY44=tkavJbL1HRA`ZS?~ps7o1YA*rppP?6k zj>^!9pc6B6sLzsq(TBEnpf`O!JFVtfaKd2(_xX_G(@wGI;C74t_OE#^_G#sgLd$son!cVkT88!vFDa^2Ll7t@_O!M^Bvv zS4|Bi&PS>y@QICV+Mg#nep~~g{0iv)xUTFwH z-pvp~e54`d^O=Sa=1UDB!W#{tfNwN}LcZ4!iuj*NXbMu7bVyCGkA*SBe-ddjpXUyw zQo}qh(g^P((gHq4q=kH@NQ?MIA}!`kB1M;MHUy2|ZwOBQlp(nID~90a9~y#(e{Bdk zTpc7D>E#g;k`+-OuQ619KEMzHe54`d^67?<$GIT{`Spen;+qX2pFeB}Vg8aKU|0>I zfPZEPh5U>m6!F}_qWEIoNeIbkl=m@IF+SE1O87iODCL(KLK(l_5X$*RL#W^n7(yj~ zhJ+?O+gPfKWxAhf^gI;kVrA1Xuj$9o%KXppTv-f9ng2jy0b@yv97>H$t@bICAki(}M0^ST6f{$Nq2!6iN5CZ%GL&)XN7(yO@%@Bh8V?zk> z9}FR%dxna#!n~A(UKP;@?`5bkfF7H59cUwtD>XnV^-ig2V*<%TDppi=nQO zsw~#T#gHnkD#BASZqcdmWjhsaggsF#hO^6U(mU%Faf4DECo7)E+ugZ z1b45mFaaD1u5asHn)D6F&f5TWO_|MSU4gyO66B;bE+WfdNn8r3?6noSOb=d>&K1k# zB4t*t%P3d%#qtW8KDLT8w#%VtxB?KzB&-goWN|Tz&w56E7@g8^g+8`RaL|=-sBx;s zORp6mD(8fnC`%l}P>pLoDilmy2X!L`%~DYt zs%*pxvYb)(QYEh!{$z=(@Q>R7E5o3aFJ$Dy*k4x=p1o>&X5o%g1}zFCL^ zA^Nlx`4o%Zl8CE=Y0J2Yd~l;`Ce~48Cnm2mzMe#v-RBZHpwOWZi@@3QOc2K;Rsl5c zpa#^SJ`F}kIkMY?dZTZQdfOAX=!?2G$j>NxYuAux1l99aWUT4HM-11MZdJ)?X_Yrf zvres*s^U(hl~s);2*WQ;I}8h@9QZ0IL%}#+xvA09ajaz(D-Tmdt?`;%jm)7=QY+&) z$yD)TD~>NqsAkmL%&7VU-AaSo(nVCJ>%jZ#?{_PSKaw`h%b4hcl3+-b9>)tHwGz&? z-Am?3v!b!2oBnJL5QFQf;nCl~FS-Q$XKe79ip7TVQ;8CsjqA@tH$=HcDf%+`Y>MC1}TeZQy8H!wIb;R7MOn2c7 zE4kC_)}(mfdWTxI-da4nxRX?+#BYbmQe&6Jtf^Mz_#IHhw*acJ0#I4BmSO4m;&(!) zsSS4_aoS=r><)>okZb63)rM`5D&pILi5&!Y6Wl{eIq^G6_;u7fiF+Z(?*mkd&;Q~( ziQlh(+p9`E!&IRvO8mc|^h%2H>e8-={k2*OYHF~qgHltjsG(_z2jJ7V3(zSy!yhDW zQA1NT`L~P2tpVpuwby2s?VDBOC51gS6}t`I+kRrJLi;T2&uAYuCZ9u2y_bpC7 zgitPfDAa(%KywEJmg*Jg{mof#SZe19Mb-aX_6E#Hm0R{AV>JB2Uv```&^Cgtn119DOj+{pzD`E!O5;*a+N?QU4n3i}9fKU9M zMUngeh`VKh{UNTUI1(O1Hfg= z$ZoqM{zvF)19JQjQbl0=MTj-!S)mMDk`lvcPaDt5Yd8#bQ%4*=_>fRxL(oZ4RP+^W zr3LYqU~708pf&sn=u~a;8Zsn~fW=<{*b=zJXo=SVu2hdhe#cH7;59lR)`Mw`=}QJ^ z$rwV5d~)J-xHY^1(At&dw5f?Vp}&VpLeNa7+N+F^J{IjlA&t$n57H9qTmB}xG>+x0 z#k?Kx;`T2TJpL9CA)~RxQHGb;iNAt_dO^Y7CWg9F+eaf%DFP|+zR+rxcmn&pQ;xp_ z=E77uhBVaB3PjH*{)V)*xc%aSGHX6mnUkQ5Ich{7TsE-uoc~nByZ@^q^uG`6F|>@D zF6yYMF@`R0IF2CBhQ9+{c3a{-r1(HU`dUbK66lhPN0j-&~2<70r|j@ z`n~-+^tCXoIaUFU$fm_VK$sdgzkDQm8jA_vVRiDK(nK{rYwMx%%SP$D2j%9LodZ8K z*!(Jn%f`#j(T@%)sA^{j*b~dq*|3`a?$#oF;%ecu&(VtqZ!8wiZ^LiTY22 z@02doZy%y}IDya?In@=PAa&WIu?y@=rn+SZeTPqX3W%4AvG&Qd)4mnvoju^*?*l8LU zAWPPb9J`p>a0(eJn#e-erRu6q4cOzEM1JF!tpK249jHPP0LYtt?$weF3*y}95xUWQ)ORxrsu2dz8u2U0_S>3?ksSmz(S$_tLG-< z?JaPe(DclS_*K>~|GB8jF3usm%+tSIWt+W(MJ2_xUZs&Y&hg$!ji`p?lwBvbEIlGrMTZG=4 zL-Kv{BPjU&0?K=C`PaEB^W+g8%^}TAq5-evMU)_ueXoT)>`$>Jg%PGZmiZ%WcbIT~ z;WED`$)<*vAl!4I;lX0It>A5R>?g>kveLW<%TyMR5*`!s0ij=Pc@ST)3wxva#q3~C zG~dH!duj_*b~A=dW#2^p39Jii(7*1k&hxPSp6Wc64KJl?&Gi%hEc$qq=_qNr=m%+3K%tW` zl1njf%a14?_B$sH*2f{j=~2SP`8043Cf&!1{j9s@iKr}8*oqKK#Ar|J@QzsA3do850=@BY;0WiYOa)jgvn=DW& zQ7{?LFQm#XKt+q$Qw9B_=7SQ9rV-0$#e(e(5-Y$xK=OLo+8D7C91Gj9Fux7W&72G>5yo4_FgrwMEn zc(cG?3#^yP=Ny6MLUTgMcMJI`fiDQn8G&7ZRB4KTlj|t(i(JC%EQIR?UKKl<1j+Fn zMQ5%L9s`bb{~dkvU96GeJ}ZA@53-HyQ{YPWHSl5S4DhhzaRk|iQn5p2$!KTbkm9bu zTc!RE%5^TRAvVD=E`~Y4HZZMprbA-yml&*~^rS^*b8ufGTe5#?y+dX-I4z0(Id;-w zWqV9^UhzTI%4%>kBiq+S3msNwsWjLJVAz7`E(cp6c2Kpkx9~7RY-EJk7~J=Xbrb9{ zlSL5I#=N*~^@*0EAhtbZu)fz19Ble2Pssvlw$*{c=Cfge(dq=Qqx)`?S z1)ExDu*U>@%4C1iDBseqhV6S-lIWCf1|8;qnAzE4lfCUbX|c21o`y{lRU6dXU@zw{ zaoAa}eg<3YxYU6&;B13=+y_-Bn>Wm0C4zk?*t-0lg(ode_A>4wjQu9Ru24-fCwnVH z!3Lc}#%5Mmyu#sRThnZf!^OPx^Z?r(#akUYY|a>BzhN(XRdJnRO!11KCS&XcYgO4p z4!Y{l&kNR*VTlC{0ye7z^Cve=Z*x8F$gpFD+3eofGg-FJ0|&C$OYp=#D}G+Ejx9Qr z#pVWoW1^RpZ%_Ec5a*eZw0qVnP`JUZ)TNb)&Ar;5JI@?4}pIkBKOjZDV><8U_n-jU5{v@)Li^_)osNg9`o zju-!&75^=-ti@QrUr{yJv3GM9I!f45!8WjiL7P^}`b{)!^P+C8jO`a}1N+Dk*2>w( zrtRs{B`nV7O)@-J6qjoq*=K@nU`@%$kF17$HkphY*mGc=*fmoOb~jiTHuF4#{n5LS zoyAU?>_)9t>&DhhHEcH({K&-0XH9HFY>d`T>rDp1Bu8(J-Uk@W>lm!{OS1)K$&uOs z)?pfHjP*W%brWm@8|#}V4PdvJY>aP=HjsU0c(Q2T1Z@!OHl6ZqVEcq|-&1 z7fr@6Lr1aKOx6W!c@+Dr$=15(qoVH{4Ey3mV1GQ{sCEvDKZm_yvRKFqcGP5>O6K8> z%5jtJEb+3@N%o0Jcc6$d>>noEWATFhXtLdy#^*9+wo$}$*dxznE|WFn&0}L(uE`qn zykJEpt4AY##VSme$n}DCGTBR54C7d`he_Y^dqD@9>=NHRhH*35RX#7+IFqeLffLwN zlWjnO6Ii{;R-(X(Y>~-sLV*(*H`yr^IEh_pvVWqyNo-Zpq&feCY1;*j|%uL1m`0XH51mDl?V+!DMa>_B3{6cGBq5 z;(!KUF3@Ux1& zDQ(s+V0M$8lzykpZ4-1J^P09PtVNs0=9ugb>2Ym7J8H5LsYSbxof6Eb+5#g=(zsZ# z1?*?jHO3BVcvXb^bh3!>njpP0jf8PuVEus-!~f~k4qwB&0J)8RNHO_*R6_doF3NjA zBh5p_QcPk8OXQf$UIZo;cBREo(Q{ukm+-|9VMvpa`J#}F%+H2=USzXm@bZAKi_oO; z@&JobpHZ}06q%~%m7=-^o^nuyzA5l}6?U!5>$NO0YkdM)CAJ#1mf3AMycPB^E*lcF zBM>U_ALUzMm6=h%R3FKtQP^>j>p0qt{|`gcT{GfIkLbWD=oX1>5!u!WS3_e2YOj$* zIEmHUDc5n_&;HMt{Qt4n)*Zy)m#l@Hdzk1C~ zEm>D6;R%pdU>K<3nYXUcizh(B-U0^;93^nPz-a>Ofq86^kS`IqT;OV81P2(!+$6AG zBKZ=ZpvuQ$J4(!WzvPorQShM^h9*|edTccCh zZc)r`HlcJj+a&M9nYLQ~A-0fhlfQ~BVLRn;d4teg0i0jn2#uk4ls7|`J?o)g5;Srp z?*N%qzC>i$4!p>JKMGs!dKd+d&VPdKXNA!Ncq}~+yV-u$TzG)(mlpY6Mqz!+s6u1y zly|uOG&Cd1egw*%2B6zV@-yyS>2diwHy)gYWYF4x#OAp=Nz{UF z(l$oL>;#U3MlG2v9TEk*#P#D<`6KT|(yO9NUu7d=3F)}J(9)fqkR|z2=@de*fHi2j zMv{~zcs|Hw@04tmjVVR>}(N)dv0H9o|I8a?xx>_)DqUc?+mw5jY_MD< zn$Z!n+RN&dd=Fv5r3&<-64c@cL<1fWp7lyIhGP%AJz2I^UZkAwe#No};r?u)_I)Pp zL9LHNV-Fs;_>@-)P5|>Ut$fOeV%;qR{!@6izW;wmU4`PI0C|>wHT3TdnmOr&u0{4|9tE^$A&_y%(RI~@=qDWt01b7Gq zjIq87oMhdm+^x+unra}OlpG`HjcJ0-1kJZwFx{KNMo3_pAKTerz4 z%HFbmFD(rJ4OoYpjU*P2B;OhQ5Y~yVlh&Q=&fquJ<7hqJH%ZI!`J)3q9qZA-_^`spOMyEGvXO$6o^M8$C-UpI&P6l;SQKpnk7(^N&?apqiwHv1(_klBI9- z0@Y#B%X$I-tn^a1$+IoFlEX5#@N%^yJXflZ%YpC>unvHx4w|iMZ=lLbEc^WTsU0on z`5#uB<+FkZ)#uH*a>(_WI$qgQ>a=Z=dbnb?O-X4OlASDODFe>LPPbe-T-MoEk3ijl zbNu~n*r0r)Y%iH1Cggo0_qMDqnQnW7T_zn>-oW3!*(hz3*A{bISh?0oL-_@kBCV0H zrN!(`Z=-FnVt<+6(L_Jqa8n?E?;# z4gyCer5BNmky?S{r1yZ6q>q79rO$ygMYcI2+dPqNp~$va|Um<+15>S7wg?@&> zxvUr0Z-!=7N0Tnk(d0kn`QEguDat5cdut@01R(YR>^^7P}7!%^_%pdESF& zgZn+9IRVZ29z~wZ_PG_Aigd^a*cG0R!1bQ9`pY;9!CE z0-FVH6S!aCaeAb$uWV01kMrIByekvo`iXyAnyufUXelI9Dz*&w+h@R@Lhq-Cp-lX z5;#X-lfbP4_X&JgAoB}0;yE$D{Ye=llDvBOCEWIyh^@ZmX$r0{g$sSovj0` z7h9XGhpcC;9n@j!LUo}{dJB&vJw}-IK zbp#m6C44SK_>+@xe?H-w0O4YR0pT;mLYnRF*Ma52e^&`<9uxW(93)?zN7x|zPxz1E zF9xwSK2kj)437#!HxcwTp?_59?-t?q2y3aZ?ibcmBIvDtittV3E#MS)EAZ9Q_qCQD z3x`U{DS5M`byB^&NM0fDm7kWMm*14%k;f@lD!)^nR9;b9mG6~0%NWaY%Pz~~7Q6bM zI@UJZCgCPIM#F=j^g5Fql)lNlBK-?nP$n@;6FpUA|IjCGcpORp+-3Vf0ZFz|-e)_F zXRh{+!|_ntUUvkKdhKBB{1l@%w=^#rCbVOh0~6R60wS zejSs}YAOBoEKR@R(nnfGUbb9ndG&IarD76aK4Si|DfNplozE^4*f4+D>|s|doj-S3 zU6(FrCzdQ*w4^0^)t_Y7@I{N~kE>s{a5zs~-10%=0ZYrXs}izn;(UJDqPg?OB^E7N z)>8Q!$*Om~v7+VIHwGlf#N`dk=3m@t?EIFi*2E;$_?kq^p_{&v@b}7|S)1ST*4iVA z*EfW5ytG(?b7&#!!(#e9daUJ${`*R$ZU)nfpAPEpJ`t9p`nKN}pC{$f$CvZjGIl9j ziZ`zF*%kPee6{QXJl-vV=1QbXnN(CO!p#T%8aXb-wV?slW$<4n{Fmab%LOTaz5kQl zy5vnp#>Fgwy37;77SJlgkxc)XuO8N=__TCBzVVtsjhVjosY0o%KIqBd`lpL@{fTZZ zw>`bIKp$~*nWtw3yIh2zKwK|6S|vBF(g*)FqTjdQ)AGU5hh*$)R-jso1Uh`*L2VtlO>NwkmlYFo5erPKTGz{!qoLmwlJ9NOp!ev zU-KwkIkrqXu3vF%kg767_&|U9*toIqkz{L(`I|4c;>+jFm)c{BQ|4R5d zP+4E|t-j_>MuoSCg0~^6e>uTQD?@7vt<=JmVVfn--_$JmT}ZB_#MiVMiQi>2^^}sq z5o5v@U^dgoX_HMU>31QV9AFeQz#=xg$m|hWJ!oOmI&_kMnJlA;D9uC3wMKFiKHWrU zatScf!2tzTG6;1M-YjgXrf}&YM`TnL`QJHPBhw2XH zJtE6a;vx^##bBuhnsqmuj4?F){H};MRh$G>R;k63Ril80r{Co%G(0yY(W8PlGW zF{@*oF{6P2^nBZxo~&FRys{&|=1dcFKzF6X`dvv^rVzi&^f&v05{rfjq>2vrSZtDS zAq_A(#pAJAQxeT>D=m&kG)$sAfAiz06(%__AYmTgauJeWbE$fteHrzs{{P-uyc4wunY{vKC5d{?{0P&CiN zmR6O}>tA`Hqx5r}O;UwZWQ@0BNSlKlP51=UXuW2s|8WKA8gT{0FtO`(2H z%tZ1fyWM8-HNEU~XtIimqE|Gl4Xv&dH47WvdNrlkc$&K_Hi?EE%@6?<+CUV{3E8hu zK(WLes1xL7eZ>34($1C(-|s*p;jtTg7M48;oAkRr2q)_-Dg{;jR|w@US&-ua`V(fF&QSbg1TsUbmU z$qI&EY+PbcjBN;-RK;8|6rCb)MVZEqvQxk9qas_K)lTtRp8QBvq(S;~pY)Jz-CBP9 zWr2qf` diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb b/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb index e83604e4eb02d91185c7500eae0101db8ce00525..932964c2b9e89a17d28d0ac623fd2c60ca636087 100644 GIT binary patch delta 16669 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 Date: Sun, 15 Jul 2018 09:32:59 +1000 Subject: [PATCH 1111/2058] Add PhHexStringToBufferEx --- ProcessHacker/ProcessHacker.def | 1 + phlib/basesup.c | 26 +++++++++++++++++++++++++- phlib/include/phbasesup.h | 7 +++++++ 3 files changed, 33 insertions(+), 1 deletion(-) diff --git a/ProcessHacker/ProcessHacker.def b/ProcessHacker/ProcessHacker.def index a7a0f9e11f07..c9e4f11ae616 100644 --- a/ProcessHacker/ProcessHacker.def +++ b/ProcessHacker/ProcessHacker.def @@ -170,6 +170,7 @@ EXPORTS PhHashBytes PhHashStringRef PhHexStringToBuffer + PhHexStringToBufferEx PhInitializeArray PhInitializeAvlTree PhInitializeBytesBuilder diff --git a/phlib/basesup.c b/phlib/basesup.c index cf11152f700d..35387098bef1 100644 --- a/phlib/basesup.c +++ b/phlib/basesup.c @@ -5549,6 +5549,30 @@ BOOLEAN PhHexStringToBuffer( return TRUE; } +PPH_STRING PhHexStringToBufferEx( + _In_ PPH_STRINGREF String + ) +{ + PPH_STRING string; + SIZE_T length; + SIZE_T i; + + if ((String->Length / sizeof(WCHAR)) & 1) + return FALSE; + + length = String->Length / sizeof(WCHAR) / 2; + string = PhCreateStringEx(NULL, length); + + for (i = 0; i < length; i++) + { + ((PUCHAR)string->Buffer)[i] = + (UCHAR)(PhCharToInteger[(UCHAR)String->Buffer[i * sizeof(WCHAR)]] << 4) + + (UCHAR)PhCharToInteger[(UCHAR)String->Buffer[i * sizeof(WCHAR) + 1]]; + } + + return string; +} + /** * Converts a byte array into a sequence of hexadecimal digits. * @@ -5580,8 +5604,8 @@ PPH_STRING PhBufferToHexStringEx( _In_ BOOLEAN UpperCase ) { - PCHAR table; PPH_STRING string; + PCHAR table; ULONG i; if (UpperCase) diff --git a/phlib/include/phbasesup.h b/phlib/include/phbasesup.h index c5d6a9fca43d..2611547ab384 100644 --- a/phlib/include/phbasesup.h +++ b/phlib/include/phbasesup.h @@ -3347,6 +3347,13 @@ PhHexStringToBuffer( _Out_writes_bytes_(String->Length / sizeof(WCHAR) / 2) PUCHAR Buffer ); +PHLIBAPI +PPH_STRING +NTAPI +PhHexStringToBufferEx( + _In_ PPH_STRINGREF String + ); + PHLIBAPI PPH_STRING NTAPI From 585e729a4784df84259c528a590de9bd8428f267 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 15 Jul 2018 10:02:09 +1000 Subject: [PATCH 1112/2058] BuildTools: Fix build error --- tools/CustomBuildTool/Source Files/Program.cs | 9 +++++---- .../bin/Release/CustomBuildTool.exe | Bin 164864 -> 164864 bytes .../bin/Release/CustomBuildTool.pdb | Bin 75264 -> 75264 bytes 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/tools/CustomBuildTool/Source Files/Program.cs b/tools/CustomBuildTool/Source Files/Program.cs index dbb2b91bad57..ce29ceb0e980 100644 --- a/tools/CustomBuildTool/Source Files/Program.cs +++ b/tools/CustomBuildTool/Source Files/Program.cs @@ -224,14 +224,15 @@ public static void Main(string[] args) if (!Build.CopyWow64Files(BuildFlags.None)) Environment.Exit(1); - //if (!Build.BuildWebSetupExe()) - // Environment.Exit(1); - if (!Build.BuildSetupExe()) - Environment.Exit(1); if (!Build.BuildBinZip()) Environment.Exit(1); if (!Build.BuildPdbZip()) Environment.Exit(1); + //if (!Build.BuildWebSetupExe()) + // Environment.Exit(1); + if (!Build.BuildSetupExe()) + Environment.Exit(1); + if (!Build.BuildChecksumsFile()) Environment.Exit(1); if (!Build.BuildUpdateSignature()) diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe b/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe index d0deb2027d31141a8cb79c26a73efbf76b55017b..c7def83e792fa1d5b95abc3ca6f0442d46616e32 100644 GIT binary patch delta 104 zcmZqZ;A-gLn$W>?yKiIH1JlXnW>S;0%y>6XG-F;Su*|A+`u6rt*S&QNn^}29j5ja2 zVi(7Lhffhi;Z;^wldjFS%nQ zp_AY070mzyOh7Ed$iVPJh>_vP7Y2r)V3*)0JM?Nd#?AKLU680cM|1{XGtbxUJYN~V G^Z@{bz9sqq diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb b/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb index 932964c2b9e89a17d28d0ac623fd2c60ca636087..fecb3f8a5a396e265ddf0cd45b1f635a2902fcc3 100644 GIT binary patch delta 933 zcmZ|OT}YEr9LMqVxS2XLTwA`ijnZNzD;kwhXgSvsgUZ=rQe?AkGMG5cMOy7~668y- zqg28>?+nx)D!R&>y2-34%J8Bns}VKPEPAoo_X)e~>hu5oIfwHuK>l>z_bffMcVd#*kCh#)8!ybGesg7iZ zK9LmCXS{6B1%MMVQ74Y{!+@fmZCoRoIL94A_rr$=7im-b6dz!u5C;H{dW9uznOblOJIr zzQ7_J!>#zLkfNC4H9GJEmS7Z}7{hHigD(7ur8tLWiv3EBq|X;i#A=}z|FkLnS5u_W zPFAJzpmt#zmZKhHlX2NFpR=%nz7;)a$Gx}(z39M7bRw@)-i`-wH&&q=58@s?gg!is zem>LRg90?vgOB5ph^xC{lb^JJREtSihw69%Ovidu$2x`wsb4puJbNIhM-))mgnn?KrgB#3U delta 933 zcmZ|OTS${(9LMqJZOg;bYR&1)%|a`&X12mWGIOphI-tu@&|z)egps&m2P$QoB9&R7 zFXg1V^G+|amrit%-H3rDw7_*$7b{2Q%0m=J+4l{*?CSIX{dpdq|I7P4!4Yk6M0;1O zGc~mBJ}e0#Vvp8054dmbdE)b~zHJOIR?Ir9E@NyW63d!O6km%DJ-gmt6L}>M4-eRT zrF)qvX(^#D+p*_4ucdCkPBL`XSmcVlUTyMd=Q<^x=kaB~7b4iPK!^|6h2z+RaoH

    adu@aY|0}bdxBYH3sy=cNZ%*Knt%{1DOzacV>_kL2Ap`bd5xF0W@jhL(T;Jf!~{BU2DjrZR^c4(QfxQsB)wG_MWN7(wf|K5Zl+3s zy{uZqh1!SdSdDs2eEA(T%x4oi=@(!v+R%mNcmVBq5FL03tMCX`<56^?8*9;v9z2fq z{GPuD`Dv&JpTiUKj&Nh?DN+)t9+R;F)$x3|6#b}<)rh%x8uRgtJQ?2UJWo=0UqE$N v6E4SQG^6@)77R(EO&#(QeRasoxPM+3wv*l1p Date: Sun, 15 Jul 2018 10:32:23 +1000 Subject: [PATCH 1113/2058] BuildTools: Fix version string --- tools/CustomBuildTool/Source Files/Build.cs | 8 +++++--- .../bin/Release/CustomBuildTool.exe | Bin 164864 -> 164864 bytes .../bin/Release/CustomBuildTool.pdb | Bin 75264 -> 75264 bytes 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/tools/CustomBuildTool/Source Files/Build.cs b/tools/CustomBuildTool/Source Files/Build.cs index 1ce063ba0004..1deba1db34b1 100644 --- a/tools/CustomBuildTool/Source Files/Build.cs +++ b/tools/CustomBuildTool/Source Files/Build.cs @@ -1120,12 +1120,14 @@ public static bool AppveyorUploadBuildFiles() { foreach (string file in buildFileArray) { - if (File.Exists(BuildOutputFolder + file)) + var sourceFile = file.Replace("-build-", $"-{BuildVersion}-"); + + if (File.Exists(BuildOutputFolder + sourceFile)) { - string filename = Path.GetFileName(BuildOutputFolder + file); + string filename = Path.GetFileName(BuildOutputFolder + sourceFile); using (HttpClient httpClient = new HttpClient()) - using (FileStream fileStream = File.OpenRead(BuildOutputFolder + file)) + using (FileStream fileStream = File.OpenRead(BuildOutputFolder + sourceFile)) using (HttpContent httpContent = new StreamContent(fileStream)) using (MultipartFormDataContent httpFormData = new MultipartFormDataContent()) { diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe b/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe index c7def83e792fa1d5b95abc3ca6f0442d46616e32..6aa453a32e7cfcc177e48e3c7bb15f166b568883 100644 GIT binary patch delta 6104 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 delta 6122 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 F_J8%#HrxOJ diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb b/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb index fecb3f8a5a396e265ddf0cd45b1f635a2902fcc3..42caff8fcff3014e0967704ce7c810d20b5ca778 100644 GIT binary patch delta 5794 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 OtKwJclS248_5T8@^F(X_ delta 5700 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 NE|gbm?Mvsi{|~P5I Date: Mon, 16 Jul 2018 05:33:54 +1000 Subject: [PATCH 1114/2058] BuildTools: Fix appveyor error message --- tools/CustomBuildTool/Source Files/Build.cs | 2 +- .../bin/Release/CustomBuildTool.exe | Bin 164864 -> 164864 bytes .../bin/Release/CustomBuildTool.pdb | Bin 75264 -> 75264 bytes 3 files changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/CustomBuildTool/Source Files/Build.cs b/tools/CustomBuildTool/Source Files/Build.cs index 1deba1db34b1..6ce39d7b47a3 100644 --- a/tools/CustomBuildTool/Source Files/Build.cs +++ b/tools/CustomBuildTool/Source Files/Build.cs @@ -1147,7 +1147,7 @@ public static bool AppveyorUploadBuildFiles() if (!response.Result.IsSuccessStatusCode) { - Program.PrintColorMessage("[UploadBuildWebServiceStatusCode]", ConsoleColor.Red); + Program.PrintColorMessage("[UploadBuildWebServiceStatusCode] " + response.Result, ConsoleColor.Red); } } } diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe b/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe index 6aa453a32e7cfcc177e48e3c7bb15f166b568883..ac93ee318ce823de299a3c037c1b1791b4b875f2 100644 GIT binary patch delta 5539 zcma)=33Qaz702&4B*V-%*(Q_Bmf4cYBtw{BfFuM+AuA9zg|H^71CPGg@ zEebviD6~ilvREq^D}qs3)CvgV!l_lHpjF)PpcMpdq4zD>Kx=c(%>DoFyWhL_yYGEV zrhd6zzg%Cryvq$6hpl?Rt3AAG+jy;nXtE|n)7%k7EW@LynaEP6Nx3+tn(!<(4F6r6X?r}@c zo9&)7={eKx@ko!YXIn0>^bCx)xpbUM+HZ0Abt=TOHw9DKr*nq}|nFcp&>M-Iu+OX2K8XYknWf8gIsr`P8(@ zW28f7DQCGEUT2ry6jn-MS=Jc*OPAIXY;18xnl@8>AK~BjKKZR%PekLbZc4J59nMHE z*+xTY^XVej`_)rDRueY2d2$yJzTA#82oJYoHQ{j<2?j0yAZJs^MSOM$0UnUNzJ#<#iX zkIihox@9)A?AfhsLZ+`{&-4yGv#h9kmU)3t-LYu{&H+qHzwT}$ZP zwS>-HOQ5bz2nFL>yOw~pg{(H1&bEf^+D`Uz$d`U~hwdsA4HhTDJG6ma4!M4@K^s_6 zR;M#g>~O|kvUyo)_T_y#?F`weH`#_Pw-QaRYfae*$Jmk%)y-B;imgtT;`IWV}s?sNaV5 z(v^a%rAWoCQrPi1DI9o63MZbF!iC>T;YKJCS<}!hg$IkI@Ztn6>g~KG*{$upMGQJ{ zv9M7mHVWaw?ZUdTMc6bvDy#=j3hTwMg!Q4JROB=X5e@mR_-E-##=TP5@Q@TKctVO){7wox>SZFm13gkWv6mDs94Q4Ys}yNC zPYMs#OX0;vDSWs?h;qLlTcj(1$D~NdPo>Dfi&6wpFBe%e(Je&?dq|OmC2VkRx99}I zMLz1Z0T*(a#-*dR>05d5B6^jJF|=>aJz@r0TVb7eLReZ^Vclq~;5pOKDXa%`g!N*v zus*y&SlXL)6%gecPscl@%Yyey5r^xgh{tE7NWj;mNW}N0NWybcSTUwjoMke)rLbWS zDN?XRic}mUg&l8^!hs7(45jo=Tq#{H+$4n?_eepzNeT~sB!w3*aIuKqYp7*$gQ#VG zA^SH!-y>Vo7&~=c3VolyE@0m>nC>P~x|>7-U9GYA(CsG1j$4|$=hYjuUF=W2283VW z5$h?!g!@QZ^?RHY6rM&N@rI|yUSP?+uf!kZ!5jH>*?5ro^1Evvu%Y<@`}b}BN=KM( zNyc0)2V+@%eu?H{`|`VKLH1>Sq1K0G6jW)YEYQc!mK3DeZywS*-K6%ze$CPg?QDO6 zj{;8@WcZf02K9ZN-f&c$(GhN8-;KsZv_sD5*Kf_`g6n!=*-!rz`OQX&JZ zsAuB&kSDlX8_S7$(?lWmMgNt?QX0X*tiHHZ8^QJ$|6N}>;Wkxwf6X>(biGN|oi z6_s0QgPyG%mAGs;fAVeSn{Jp9f6qn?O4pXL`Gab-jqK2%k**WN0fJ+z;nX7lNwh

    %@men})kY>%tSFb>kbNO~=o8+iRoD zo{V7X+KD`e9cPHvfvZI8L=C4Ry~Q?26(F5O(( zgR_2(M?XOyYa;dV?tD+Apv4uf10$#KYP7VXO~Wywbzz-o-8f6M>9|I;8Ms}vv=V!! zi0$ez@TfFd@Fgi?@sbpAcuR_S{8Wkr)EmUvS#Ce(&WT9rAWi~q;TO~DcopG6;;zQgNrBVb&RI0ob(f3Ay+pJZZ7d@ z_6v>lJlaKfzM|~t#HhzNlGBD48reXp$9^^B^M-v_8wcMl4e0tG8rjOR6XV|JF+ZmM zX8dy_dtq#v{(d9-_1JIXKj#kmPQfV3#LpYq+vPcWL=*e6+++7N1wB*k{z$r47i$Gr z+{8-8P0}Yfv957`y|sxQ9yd;3-o*ZETyhkDSG2J=$7itUiX?q~6LVGM+xtUVmV~n$ zYho)aQ(0F<1`pd;k?DCM7*_Q^^yP+%G}-+x@|*q7dAOT>QsLv_DdUgYuLi@57KXF_ zk%wg(%hgaR^l#(+Id?*#V~}hAYVsFp1-8&RS(;g0rAJS1rtV|qxHH)K$|k+InSEV( zRezv)@U5zOnm)0a9iEUg*ith_%bM6slT%KED=sx9MjpoY5PJnLZXP^5!KX#9Cp&gF zvtLiF)*o$V5w$nZF*}f`_Ys(S8FSs(Na3-;tfPR?tMc}gZFsA*|Hnz3Jt8Z&# z2U`~E{cY^8Eeq4$Yy-%iI~&d&0-zU3$ZncDt%2H$hXy-ZAC3uZp_hJu{cs}F7j1!@ zv67CsI2}~9OHd?j5+2#>;l6c>7P(^#3+$+nzTc297WRyn6p_TKvQkotpx7!&sgyGo zP6QNY3fxsAoiT!bFhSDSX*{%OqNJxRoIa_QbT*FDA0|nfn7mz!g?oyU(h`hVI9M-z z*QtCwESajZWO3Tm+$k~2uo>|XXqI$|k|w|&LH&+x>C2)L;N@2C>vKGku0aA^96|o+ z-1j{=;BgxXuq#Bxh86B9(!G<7WN03oJTE;WkTZ*S=!f5?#u&M z^!=yzjFAU1^EuI^8$UJtP%5Y&w&m=GB6v~JZO>(+7|QA6Dv!M3Is~OqzEG0QeF)0n zO-1*}R}LpC7fEMj)>}peSjAVu`{BjJjZg_E6g67*LN(k}RAISc)W8;&x@c-3VJYt| z=VdCm1?`8aNxAw|*r8}j(qD~6xFI7U&-SI!1nye?KzG{X@^ONm;+O}9Ee_;#u~ z19}xTq-@t_!kiV{*AIU&M_Xn>WniU1u`DxTi=h4Rtl1Ym6P{AEz_FXY!Tvx|p=CEb z2o3aIVlYiR_~_nA%W3|ZQKGfO7)7_@IaMh7+HwWjp;l2%3a7@^0ok#@!EuIi9*gBP zPtot4oR%s2zUbJYXuhC_72OrIRnd+}-mgc|iuhPdJM5A~`!11a(;DFQ`^*(oeim$5 zBL~yuuo69?Xm<7$m<``ov^v{Lv{%s`DlrH4D}pF1(J@6W#ub=AWzXV zRB$PjC^|p|mqMkY7pUMes8e)-3NC|bL894S4();heden)-OFK-axxms3RtD+Bn@T- zY*Z9Q>$?)V71>g(L^~9npuwzyrxcy1!K{Mk6qV6ZtcD*ds->k^4M!yf%#YI#&4}C6S~x3w`=KJqZdnVjhbZ0hkc!+XZe;7>bO)b9W^Qz6Th_yEMW4jw6MdxU zUR(*$XNm$(=WN$Dj3~GP%=8r$z)si;pTh=tNRYfkY#b4}5xQ06Z=k}m5q2y33Dj6N zLBFC;waJ#va70mzKHc&#oKTb#&=*=dMyDz}?`=8_f&T*5M!%S~eGM>ccEjvKld*p9xfzW=KL6PA zzqcKn^m3hM)~x%~4`qDJ1Edf9WP3CgxHD1@h+O5An;niQ1 IYIn8&2VsjYHvj+t diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb b/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb index ff3e72f4401443b8ea9deb313344deeb0d412759..470b4d2d21ab8be80bb869270503fc4fa7983ec6 100644 GIT binary patch delta 8407 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 delta 8388 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 HgZ}>m%v)!p From 4626f909337a522f79cbc6d85af90df0866ff281 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 3 Aug 2018 17:33:52 +1000 Subject: [PATCH 1246/2058] ExtendedTools: Fix viewing unloaded modules for 32bit processes --- plugins/ExtendedTools/ExtendedTools.vcxproj | 1 + .../ExtendedTools.vcxproj.filters | 3 + plugins/ExtendedTools/exttools.h | 29 +++ plugins/ExtendedTools/main.c | 17 +- plugins/ExtendedTools/svcext.c | 137 ++++++++++++ plugins/ExtendedTools/unldll.c | 196 +++++++++++++----- 6 files changed, 326 insertions(+), 57 deletions(-) create mode 100644 plugins/ExtendedTools/svcext.c diff --git a/plugins/ExtendedTools/ExtendedTools.vcxproj b/plugins/ExtendedTools/ExtendedTools.vcxproj index 31f1688029db..9fd33f94cc8f 100644 --- a/plugins/ExtendedTools/ExtendedTools.vcxproj +++ b/plugins/ExtendedTools/ExtendedTools.vcxproj @@ -88,6 +88,7 @@ + diff --git a/plugins/ExtendedTools/ExtendedTools.vcxproj.filters b/plugins/ExtendedTools/ExtendedTools.vcxproj.filters index a4f3a75bb578..346bc9a0b5c8 100644 --- a/plugins/ExtendedTools/ExtendedTools.vcxproj.filters +++ b/plugins/ExtendedTools/ExtendedTools.vcxproj.filters @@ -90,6 +90,9 @@ Source Files\Video + + Source Files + diff --git a/plugins/ExtendedTools/exttools.h b/plugins/ExtendedTools/exttools.h index f92e234f60f7..bbc9b0659a48 100644 --- a/plugins/ExtendedTools/exttools.h +++ b/plugins/ExtendedTools/exttools.h @@ -37,6 +37,35 @@ extern HWND NetworkTreeNewHandle; #define ET_WM_SHOWDIALOG (WM_APP + 1) #define ET_WM_UPDATE (WM_APP + 2) +// phsvc extensions + +typedef enum _ET_PHSVC_API_NUMBER +{ + EtPhSvcGetProcessUnloadedDllsApiNumber = 1 +} ET_PHSVC_API_NUMBER; + +typedef union _ET_PHSVC_API_GETWOW64THREADAPPDOMAIN +{ + struct + { + ULONG ProcessId; + PH_RELATIVE_STRINGREF Data; // out + } i; + struct + { + ULONG DataLength; + } o; +} ET_PHSVC_API_GETWOW64THREADAPPDOMAIN, *PET_PHSVC_API_GETWOW64THREADAPPDOMAIN; + +VOID DispatchPhSvcRequest( + _In_ PVOID Parameter + ); + +NTSTATUS CallGetProcessUnloadedDlls( + _In_ HANDLE ProcessId, + _Out_ PPH_STRING *UnloadedDlls + ); + // Process icon typedef struct _ET_PROCESS_ICON diff --git a/plugins/ExtendedTools/main.c b/plugins/ExtendedTools/main.c index 0ec016639a2b..f7ecba22e6f3 100644 --- a/plugins/ExtendedTools/main.c +++ b/plugins/ExtendedTools/main.c @@ -33,6 +33,7 @@ PH_CALLBACK_REGISTRATION PluginUnloadCallbackRegistration; PH_CALLBACK_REGISTRATION PluginShowOptionsCallbackRegistration; PH_CALLBACK_REGISTRATION PluginMenuItemCallbackRegistration; PH_CALLBACK_REGISTRATION PluginTreeNewMessageCallbackRegistration; +PH_CALLBACK_REGISTRATION PluginPhSvcRequestCallbackRegistration; PH_CALLBACK_REGISTRATION MainWindowShowingCallbackRegistration; PH_CALLBACK_REGISTRATION ProcessPropertiesInitializingCallbackRegistration; PH_CALLBACK_REGISTRATION HandlePropertiesInitializingCallbackRegistration; @@ -132,6 +133,14 @@ VOID NTAPI TreeNewMessageCallback( EtNetworkTreeNewMessage(Parameter); } +VOID NTAPI PhSvcRequestCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + DispatchPhSvcRequest(Parameter); +} + VOID NTAPI MainWindowShowingCallback( _In_opt_ PVOID Parameter, _In_opt_ PVOID Context @@ -541,6 +550,12 @@ LOGICAL DllMain( NULL, &PluginTreeNewMessageCallbackRegistration ); + PhRegisterCallback( + PhGetPluginCallback(PluginInstance, PluginCallbackPhSvcRequest), + PhSvcRequestCallback, + NULL, + &PluginPhSvcRequestCallbackRegistration + ); PhRegisterCallback( PhGetGeneralCallback(GeneralCallbackMainWindowShowing), @@ -647,4 +662,4 @@ LOGICAL DllMain( } return TRUE; -} \ No newline at end of file +} diff --git a/plugins/ExtendedTools/svcext.c b/plugins/ExtendedTools/svcext.c new file mode 100644 index 000000000000..ee129fd13dcb --- /dev/null +++ b/plugins/ExtendedTools/svcext.c @@ -0,0 +1,137 @@ +/* + * Process Hacker Extended Tools - + * phsvc extensions + * + * Copyright (C) 2018 dmex + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include "exttools.h" + +NTSTATUS CallGetProcessUnloadedDlls( + _In_ HANDLE ProcessId, + _Out_ PPH_STRING *UnloadedDlls + ) +{ + NTSTATUS status; + PH_PLUGIN_PHSVC_CLIENT client; + ET_PHSVC_API_GETWOW64THREADAPPDOMAIN in; + ET_PHSVC_API_GETWOW64THREADAPPDOMAIN out; + ULONG bufferSize; + PVOID buffer; + + if (!PhPluginQueryPhSvc(&client)) + return STATUS_FAIL_CHECK; + + in.i.ProcessId = HandleToUlong(ProcessId); + bufferSize = 0x1000; + + if (!(buffer = client.CreateString(NULL, bufferSize, &in.i.Data))) + return STATUS_FAIL_CHECK; + + status = PhPluginCallPhSvc(PluginInstance, EtPhSvcGetProcessUnloadedDllsApiNumber, &in, sizeof(in), &out, sizeof(out)); + + if (status == STATUS_BUFFER_OVERFLOW) + { + client.FreeHeap(buffer); + bufferSize = out.o.DataLength; + + if (!(buffer = client.CreateString(NULL, bufferSize, &in.i.Data))) + return STATUS_FAIL_CHECK; + + status = PhPluginCallPhSvc(PluginInstance, EtPhSvcGetProcessUnloadedDllsApiNumber, &in, sizeof(in), &out, sizeof(out)); + } + + if (NT_SUCCESS(status)) + { + *UnloadedDlls = PhCreateStringEx(buffer, out.o.DataLength); + } + + client.FreeHeap(buffer); + + return status; +} + +NTSTATUS DispatchGetProcessUnloadedDlls( + _In_ PPH_PLUGIN_PHSVC_REQUEST Request, + _In_ PET_PHSVC_API_GETWOW64THREADAPPDOMAIN In, + _Out_ PET_PHSVC_API_GETWOW64THREADAPPDOMAIN Out + ) +{ + NTSTATUS status; + PVOID dataBuffer; + ULONG capturedElementSize; + ULONG capturedElementCount; + PVOID capturedEventTrace = NULL; + PPH_STRING eventHexBufferText = NULL; + + if (!NT_SUCCESS(status = Request->ProbeBuffer(&In->i.Data, sizeof(WCHAR), FALSE, &dataBuffer))) + return status; + + status = PhGetProcessUnloadedDlls( + UlongToHandle(In->i.ProcessId), + &capturedEventTrace, + &capturedElementSize, + &capturedElementCount + ); + + if (!NT_SUCCESS(status)) + goto CleanupExit; + + eventHexBufferText = PhBufferToHexString( + capturedEventTrace, + capturedElementSize * capturedElementCount + ); + + if (!eventHexBufferText) + { + status = STATUS_UNSUCCESSFUL; + goto CleanupExit; + } + + memcpy(dataBuffer, eventHexBufferText->Buffer, min(eventHexBufferText->Length, In->i.Data.Length)); + Out->o.DataLength = (ULONG)eventHexBufferText->Length; + + if (In->i.Data.Length < eventHexBufferText->Length) + status = STATUS_BUFFER_OVERFLOW; + +CleanupExit: + if (eventHexBufferText) + PhDereferenceObject(eventHexBufferText); + + return status; +} + +VOID DispatchPhSvcRequest( + _In_ PVOID Parameter + ) +{ + PPH_PLUGIN_PHSVC_REQUEST request = Parameter; + PVOID inBuffer; + + // InBuffer can alias OutBuffer, so make a copy of InBuffer. + inBuffer = PhAllocateCopy(request->InBuffer, request->InLength); + + switch (request->SubId) + { + case EtPhSvcGetProcessUnloadedDllsApiNumber: + request->ReturnStatus = DispatchGetProcessUnloadedDlls(request, inBuffer, request->OutBuffer); + break; + } + + PhFree(inBuffer); +} diff --git a/plugins/ExtendedTools/unldll.c b/plugins/ExtendedTools/unldll.c index 5a0657fffa8f..89ebcbede233 100644 --- a/plugins/ExtendedTools/unldll.c +++ b/plugins/ExtendedTools/unldll.c @@ -24,8 +24,8 @@ typedef struct _UNLOADED_DLLS_CONTEXT { - PPH_PROCESS_ITEM ProcessItem; HWND ListViewHandle; + PPH_PROCESS_ITEM ProcessItem; PH_LAYOUT_MANAGER LayoutManager; PVOID CapturedEventTrace; } UNLOADED_DLLS_CONTEXT, *PUNLOADED_DLLS_CONTEXT; @@ -58,85 +58,167 @@ VOID EtShowUnloadedDllsDialog( PhFree(context.CapturedEventTrace); } -BOOLEAN EtpRefreshUnloadedDlls( +NTSTATUS EtpRefreshUnloadedDlls( _In_ HWND hwndDlg, _In_ PUNLOADED_DLLS_CONTEXT Context ) { NTSTATUS status; +#ifdef _WIN64 + BOOLEAN isWow64; +#endif ULONG capturedElementSize; ULONG capturedElementCount; PVOID capturedEventTrace = NULL; ULONG i; PVOID currentEvent; - HWND lvHandle; - status = PhGetProcessUnloadedDlls( - Context->ProcessItem->ProcessId, - &capturedEventTrace, - &capturedElementSize, - &capturedElementCount - ); +#ifdef _WIN64 + if (!Context->ProcessItem->QueryHandle) + return STATUS_FAIL_CHECK; - if (!NT_SUCCESS(status)) + if (!NT_SUCCESS(status = PhGetProcessIsWow64(Context->ProcessItem->QueryHandle, &isWow64))) + return status; + + if (isWow64) { - PhShowStatus(NULL, L"Unable to retrieve unload event trace information.", status, 0); - return FALSE; - } + PPH_STRING eventTraceString; + RTL_UNLOAD_EVENT_TRACE32 eventTrace[RTL_UNLOAD_EVENT_TRACE_NUMBER]; + + memset(eventTrace, 0, sizeof(eventTrace)); + + if (!PhUiConnectToPhSvcEx(hwndDlg, Wow64PhSvcMode, FALSE)) + return STATUS_FAIL_CHECK; + + if (!NT_SUCCESS(status = CallGetProcessUnloadedDlls(Context->ProcessItem->ProcessId, &eventTraceString))) + return status; + + if (!PhHexStringToBuffer(&eventTraceString->sr, (PUCHAR)eventTrace)) + return STATUS_FAIL_CHECK; + + ExtendedListView_SetRedraw(Context->ListViewHandle, FALSE); + ListView_DeleteAllItems(Context->ListViewHandle); + + for (i = 0; i < RTL_NUMBER_OF(eventTrace); i++) + { + PRTL_UNLOAD_EVENT_TRACE32 rtlEvent = &eventTrace[i]; + INT lvItemIndex; + WCHAR buffer[128]; + PPH_STRING string; + LARGE_INTEGER time; + SYSTEMTIME systemTime; + + if (!rtlEvent->BaseAddress) + break; + + PhPrintUInt32(buffer, rtlEvent->Sequence); + lvItemIndex = PhAddListViewItem(Context->ListViewHandle, MAXINT, buffer, rtlEvent); + + // Name + if (PhCopyStringZ(rtlEvent->ImageName, sizeof(rtlEvent->ImageName) / sizeof(WCHAR), + buffer, sizeof(buffer) / sizeof(WCHAR), NULL)) + { + PhSetListViewSubItem(Context->ListViewHandle, lvItemIndex, 1, buffer); + } - lvHandle = GetDlgItem(hwndDlg, IDC_LIST); - ExtendedListView_SetRedraw(lvHandle, FALSE); - ListView_DeleteAllItems(lvHandle); + // Base Address + PhPrintPointer(buffer, (PVOID)(ULONG_PTR)rtlEvent->BaseAddress); + PhSetListViewSubItem(Context->ListViewHandle, lvItemIndex, 2, buffer); + + // Size + string = PhFormatSize(rtlEvent->SizeOfImage, -1); + PhSetListViewSubItem(Context->ListViewHandle, lvItemIndex, 3, string->Buffer); + PhDereferenceObject(string); + + // Time Stamp + RtlSecondsSince1970ToTime(rtlEvent->TimeDateStamp, &time); + PhLargeIntegerToLocalSystemTime(&systemTime, &time); + string = PhFormatDateTime(&systemTime); + PhSetListViewSubItem(Context->ListViewHandle, lvItemIndex, 4, string->Buffer); + PhDereferenceObject(string); + + // Checksum + PhPrintPointer(buffer, UlongToPtr(rtlEvent->CheckSum)); + PhSetListViewSubItem(Context->ListViewHandle, lvItemIndex, 5, buffer); + } - currentEvent = capturedEventTrace; + ExtendedListView_SortItems(Context->ListViewHandle); + ExtendedListView_SetRedraw(Context->ListViewHandle, TRUE); - for (i = 0; i < capturedElementCount; i++) + PhDereferenceObject(eventTraceString); + } + else { - PRTL_UNLOAD_EVENT_TRACE rtlEvent = currentEvent; - INT lvItemIndex; - WCHAR buffer[128]; - PPH_STRING string; - LARGE_INTEGER time; - SYSTEMTIME systemTime; - - if (!rtlEvent->BaseAddress) - break; - - PhPrintUInt32(buffer, rtlEvent->Sequence); - lvItemIndex = PhAddListViewItem(lvHandle, MAXINT, buffer, rtlEvent); - - // Name - if (PhCopyStringZ(rtlEvent->ImageName, sizeof(rtlEvent->ImageName) / sizeof(WCHAR), - buffer, sizeof(buffer) / sizeof(WCHAR), NULL)) +#endif + status = PhGetProcessUnloadedDlls( + Context->ProcessItem->ProcessId, + &capturedEventTrace, + &capturedElementSize, + &capturedElementCount + ); + + if (!NT_SUCCESS(status)) { - PhSetListViewSubItem(lvHandle, lvItemIndex, 1, buffer); + PhShowStatus(NULL, L"Unable to retrieve unload event trace information.", status, 0); + return FALSE; } - // Base Address - PhPrintPointer(buffer, rtlEvent->BaseAddress); - PhSetListViewSubItem(lvHandle, lvItemIndex, 2, buffer); + currentEvent = capturedEventTrace; - // Size - string = PhFormatSize(rtlEvent->SizeOfImage, -1); - PhSetListViewSubItem(lvHandle, lvItemIndex, 3, string->Buffer); - PhDereferenceObject(string); + ExtendedListView_SetRedraw(Context->ListViewHandle, FALSE); + ListView_DeleteAllItems(Context->ListViewHandle); - // Time Stamp - RtlSecondsSince1970ToTime(rtlEvent->TimeDateStamp, &time); - PhLargeIntegerToLocalSystemTime(&systemTime, &time); - string = PhFormatDateTime(&systemTime); - PhSetListViewSubItem(lvHandle, lvItemIndex, 4, string->Buffer); - PhDereferenceObject(string); + for (i = 0; i < capturedElementCount; i++) + { + PRTL_UNLOAD_EVENT_TRACE rtlEvent = currentEvent; + INT lvItemIndex; + WCHAR buffer[128]; + PPH_STRING string; + LARGE_INTEGER time; + SYSTEMTIME systemTime; + + if (!rtlEvent->BaseAddress) + break; - // Checksum - PhPrintPointer(buffer, UlongToPtr(rtlEvent->CheckSum)); - PhSetListViewSubItem(lvHandle, lvItemIndex, 5, buffer); + PhPrintUInt32(buffer, rtlEvent->Sequence); + lvItemIndex = PhAddListViewItem(Context->ListViewHandle, MAXINT, buffer, rtlEvent); - currentEvent = PTR_ADD_OFFSET(currentEvent, capturedElementSize); - } + // Name + if (PhCopyStringZ(rtlEvent->ImageName, sizeof(rtlEvent->ImageName) / sizeof(WCHAR), + buffer, sizeof(buffer) / sizeof(WCHAR), NULL)) + { + PhSetListViewSubItem(Context->ListViewHandle, lvItemIndex, 1, buffer); + } - ExtendedListView_SortItems(lvHandle); - ExtendedListView_SetRedraw(lvHandle, TRUE); + // Base Address + PhPrintPointer(buffer, rtlEvent->BaseAddress); + PhSetListViewSubItem(Context->ListViewHandle, lvItemIndex, 2, buffer); + + // Size + string = PhFormatSize(rtlEvent->SizeOfImage, -1); + PhSetListViewSubItem(Context->ListViewHandle, lvItemIndex, 3, string->Buffer); + PhDereferenceObject(string); + + // Time Stamp + RtlSecondsSince1970ToTime(rtlEvent->TimeDateStamp, &time); + PhLargeIntegerToLocalSystemTime(&systemTime, &time); + string = PhFormatDateTime(&systemTime); + PhSetListViewSubItem(Context->ListViewHandle, lvItemIndex, 4, string->Buffer); + PhDereferenceObject(string); + + // Checksum + PhPrintPointer(buffer, UlongToPtr(rtlEvent->CheckSum)); + PhSetListViewSubItem(Context->ListViewHandle, lvItemIndex, 5, buffer); + + currentEvent = PTR_ADD_OFFSET(currentEvent, capturedElementSize); + } + + ExtendedListView_SortItems(Context->ListViewHandle); + ExtendedListView_SetRedraw(Context->ListViewHandle, TRUE); + +#ifdef _WIN64 + } +#endif if (Context->CapturedEventTrace) PhFree(Context->CapturedEventTrace); @@ -235,6 +317,7 @@ INT_PTR CALLBACK EtpUnloadedDllsDlgProc( { case WM_INITDIALOG: { + NTSTATUS status; HWND lvHandle; SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhInstanceHandle, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); @@ -271,8 +354,9 @@ INT_PTR CALLBACK EtpUnloadedDllsDlgProc( else PhCenterWindow(hwndDlg, PhMainWndHandle); - if (!EtpRefreshUnloadedDlls(hwndDlg, context)) + if (!NT_SUCCESS(status = EtpRefreshUnloadedDlls(hwndDlg, context))) { + PhShowStatus(NULL, L"Unable to retrieve unload event trace information.", status, 0); EndDialog(hwndDlg, IDCANCEL); return FALSE; } From 67b0ca19007458d6ea7fdab649f1c8012bc8a381 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 4 Aug 2018 10:19:51 +1000 Subject: [PATCH 1247/2058] ExtendedTools: Fix phsvc leak --- plugins/ExtendedTools/unldll.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/plugins/ExtendedTools/unldll.c b/plugins/ExtendedTools/unldll.c index 89ebcbede233..4bbe4aa9a268 100644 --- a/plugins/ExtendedTools/unldll.c +++ b/plugins/ExtendedTools/unldll.c @@ -91,10 +91,16 @@ NTSTATUS EtpRefreshUnloadedDlls( return STATUS_FAIL_CHECK; if (!NT_SUCCESS(status = CallGetProcessUnloadedDlls(Context->ProcessItem->ProcessId, &eventTraceString))) + { + PhUiDisconnectFromPhSvc(); return status; + } if (!PhHexStringToBuffer(&eventTraceString->sr, (PUCHAR)eventTrace)) + { + PhUiDisconnectFromPhSvc(); return STATUS_FAIL_CHECK; + } ExtendedListView_SetRedraw(Context->ListViewHandle, FALSE); ListView_DeleteAllItems(Context->ListViewHandle); @@ -146,6 +152,7 @@ NTSTATUS EtpRefreshUnloadedDlls( ExtendedListView_SetRedraw(Context->ListViewHandle, TRUE); PhDereferenceObject(eventTraceString); + PhUiDisconnectFromPhSvc(); } else { From 50551c56454afa1cd3d686d382ee3d0a2703a920 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 4 Aug 2018 18:08:58 +1000 Subject: [PATCH 1248/2058] peview: Show names for module ordinal imports --- tools/peview/impprp.c | 60 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 56 insertions(+), 4 deletions(-) diff --git a/tools/peview/impprp.c b/tools/peview/impprp.c index a8dee5ca0b34..d52da3f75849 100644 --- a/tools/peview/impprp.c +++ b/tools/peview/impprp.c @@ -3,7 +3,7 @@ * PE viewer * * Copyright (C) 2010-2011 wj32 - * Copyright (C) 2017 dmex + * Copyright (C) 2017-2018 dmex * * This file is part of Process Hacker. * @@ -80,9 +80,61 @@ VOID PvpProcessImports( } else { - name = PhFormatString(L"(Ordinal %u)", importEntry.Ordinal); - PhSetListViewSubItem(ListViewHandle, lvItemIndex, 2, name->Buffer); - PhDereferenceObject(name); + PPH_STRING exportName = NULL; + PPH_STRING baseDirectory; + PVOID importModule; + PLDR_DATA_TABLE_ENTRY impportEntry; + PVOID moduleExportAddress; + + if (baseDirectory = PhGetBaseDirectory(PvFileName)) + AddDllDirectory(baseDirectory->Buffer); + + if (importModule = LoadLibrary(name->Buffer)) + { + impportEntry = PhFindLoaderEntry(importModule, NULL, NULL); + moduleExportAddress = PhGetDllBaseProcedureAddress(importModule, NULL, importEntry.Ordinal); + } + + if (impportEntry && moduleExportAddress) + { + if (PhLoadModuleSymbolProvider(PvSymbolProvider, impportEntry->FullDllName.Buffer, (ULONG64)importModule, impportEntry->SizeOfImage)) + { + exportName = PhGetSymbolFromAddress( + PvSymbolProvider, + (ULONG64)moduleExportAddress, + NULL, + NULL, + NULL, + NULL + ); + } + } + + if (exportName) + { + PH_STRINGREF firstPart; + PH_STRINGREF secondPart; + + if (PhSplitStringRefAtLastChar(&exportName->sr, L'!', &firstPart, &secondPart)) + name = PhFormatString(L"(Ordinal %u) [%s]", importEntry.Ordinal, secondPart.Buffer); + else + name = PhFormatString(L"(Ordinal %u) [%s]", importEntry.Ordinal, exportName->Buffer); + + PhSetListViewSubItem(ListViewHandle, lvItemIndex, 2, name->Buffer); + PhDereferenceObject(name); + PhDereferenceObject(exportName); + } + else + { + name = PhFormatString(L"(Ordinal %u)", importEntry.Ordinal); + PhSetListViewSubItem(ListViewHandle, lvItemIndex, 2, name->Buffer); + PhDereferenceObject(name); + } + + if (baseDirectory) + { + PhDereferenceObject(baseDirectory); + } } } } From d2af19887c46c741a31035db8d37b447db1b4926 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 4 Aug 2018 18:16:00 +1000 Subject: [PATCH 1249/2058] Fix build --- tools/peview/impprp.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/tools/peview/impprp.c b/tools/peview/impprp.c index d52da3f75849..d5cfd1701899 100644 --- a/tools/peview/impprp.c +++ b/tools/peview/impprp.c @@ -80,10 +80,10 @@ VOID PvpProcessImports( } else { + PLDR_DATA_TABLE_ENTRY impportEntry = NULL; PPH_STRING exportName = NULL; PPH_STRING baseDirectory; PVOID importModule; - PLDR_DATA_TABLE_ENTRY impportEntry; PVOID moduleExportAddress; if (baseDirectory = PhGetBaseDirectory(PvFileName)) @@ -97,7 +97,13 @@ VOID PvpProcessImports( if (impportEntry && moduleExportAddress) { - if (PhLoadModuleSymbolProvider(PvSymbolProvider, impportEntry->FullDllName.Buffer, (ULONG64)importModule, impportEntry->SizeOfImage)) + // TODO: Lookup name from export address table. + if (PhLoadModuleSymbolProvider( + PvSymbolProvider, + impportEntry->FullDllName.Buffer, + (ULONG64)importModule, + impportEntry->SizeOfImage + )) { exportName = PhGetSymbolFromAddress( PvSymbolProvider, From 287cf5eb430947ab36cbb9709b54b708ba910613 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 4 Aug 2018 18:24:13 +1000 Subject: [PATCH 1250/2058] Fix build typo --- tools/peview/impprp.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/tools/peview/impprp.c b/tools/peview/impprp.c index d5cfd1701899..96c1cb746f95 100644 --- a/tools/peview/impprp.c +++ b/tools/peview/impprp.c @@ -80,32 +80,32 @@ VOID PvpProcessImports( } else { - PLDR_DATA_TABLE_ENTRY impportEntry = NULL; - PPH_STRING exportName = NULL; + PLDR_DATA_TABLE_ENTRY moduleLdrEntry = NULL; + PVOID moduleExportAddress = NULL; + PVOID importModuleDllBase = NULL; + PPH_STRING ordinalName = NULL; PPH_STRING baseDirectory; - PVOID importModule; - PVOID moduleExportAddress; if (baseDirectory = PhGetBaseDirectory(PvFileName)) AddDllDirectory(baseDirectory->Buffer); - if (importModule = LoadLibrary(name->Buffer)) + if (importModuleDllBase = LoadLibrary(name->Buffer)) { - impportEntry = PhFindLoaderEntry(importModule, NULL, NULL); - moduleExportAddress = PhGetDllBaseProcedureAddress(importModule, NULL, importEntry.Ordinal); + moduleLdrEntry = PhFindLoaderEntry(importModuleDllBase, NULL, NULL); + moduleExportAddress = PhGetDllBaseProcedureAddress(importModuleDllBase, NULL, importEntry.Ordinal); } - if (impportEntry && moduleExportAddress) + if (moduleLdrEntry && moduleExportAddress) { // TODO: Lookup name from export address table. if (PhLoadModuleSymbolProvider( PvSymbolProvider, - impportEntry->FullDllName.Buffer, - (ULONG64)importModule, - impportEntry->SizeOfImage + moduleLdrEntry->FullDllName.Buffer, + (ULONG64)importModuleDllBase, + moduleLdrEntry->SizeOfImage )) { - exportName = PhGetSymbolFromAddress( + ordinalName = PhGetSymbolFromAddress( PvSymbolProvider, (ULONG64)moduleExportAddress, NULL, @@ -116,19 +116,19 @@ VOID PvpProcessImports( } } - if (exportName) + if (ordinalName) { PH_STRINGREF firstPart; PH_STRINGREF secondPart; - if (PhSplitStringRefAtLastChar(&exportName->sr, L'!', &firstPart, &secondPart)) + if (PhSplitStringRefAtLastChar(&ordinalName->sr, L'!', &firstPart, &secondPart)) name = PhFormatString(L"(Ordinal %u) [%s]", importEntry.Ordinal, secondPart.Buffer); else - name = PhFormatString(L"(Ordinal %u) [%s]", importEntry.Ordinal, exportName->Buffer); + name = PhFormatString(L"(Ordinal %u) [%s]", importEntry.Ordinal, ordinalName->Buffer); PhSetListViewSubItem(ListViewHandle, lvItemIndex, 2, name->Buffer); PhDereferenceObject(name); - PhDereferenceObject(exportName); + PhDereferenceObject(ordinalName); } else { From 15e544b0c67f651fe12edfe59e7b046eea750beb Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 5 Aug 2018 08:22:42 +1000 Subject: [PATCH 1251/2058] Fix #295 --- ProcessHacker/about.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ProcessHacker/about.c b/ProcessHacker/about.c index a22f52282131..599aaedee7fc 100644 --- a/ProcessHacker/about.c +++ b/ProcessHacker/about.c @@ -173,7 +173,8 @@ FORCEINLINE ULONG PhpGetObjectTypeObjectCount( { PH_OBJECT_TYPE_INFORMATION info; - PhGetObjectTypeInformation(ObjectType, &info); + memset(&info, 0, sizeof(PH_OBJECT_TYPE_INFORMATION)); + if (ObjectType) PhGetObjectTypeInformation(ObjectType, &info); return info.NumberOfObjects; } From 563ae3f1e5b41dd34ae6eac8ccfdcb3449bfd62b Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 5 Aug 2018 08:23:03 +1000 Subject: [PATCH 1252/2058] Add PhGetExportNameFromOrdinal --- phlib/include/phutil.h | 8 ++++++++ phlib/util.c | 41 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+) diff --git a/phlib/include/phutil.h b/phlib/include/phutil.h index 9936413e5115..5ff483d69a44 100644 --- a/phlib/include/phutil.h +++ b/phlib/include/phutil.h @@ -1244,6 +1244,14 @@ PhLoadPluginImage( _Out_opt_ PVOID *BaseAddress ); +PHLIBAPI +PPH_STRING +NTAPI +PhGetExportNameFromOrdinal( + _In_ PVOID DllBase, + _In_opt_ USHORT ProcedureNumber + ); + #ifdef __cplusplus } #endif diff --git a/phlib/util.c b/phlib/util.c index 1fc4a59216b3..bdc1875d192b 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -5898,3 +5898,44 @@ NTSTATUS PhLoadPluginImage( return status; } + +PPH_STRING PhGetExportNameFromOrdinal( + _In_ PVOID DllBase, + _In_opt_ USHORT ProcedureNumber + ) +{ + PIMAGE_NT_HEADERS imageNtHeader; + PIMAGE_DATA_DIRECTORY dataDirectory; + PIMAGE_EXPORT_DIRECTORY exportDirectory; + PULONG exportNameTable; + PUSHORT exportOrdinalTable; + + if (!NT_SUCCESS(PhGetLoaderEntryImageNtHeaders(DllBase, &imageNtHeader))) + return NULL; + + if (!NT_SUCCESS(PhGetLoaderEntryImageDirectory( + DllBase, + imageNtHeader, + IMAGE_DIRECTORY_ENTRY_EXPORT, + &dataDirectory, + &exportDirectory, + NULL + ))) + return NULL; + + exportNameTable = PTR_ADD_OFFSET(DllBase, exportDirectory->AddressOfNames); + exportOrdinalTable = PTR_ADD_OFFSET(DllBase, exportDirectory->AddressOfNameOrdinals); + + if (ProcedureNumber > exportDirectory->Base + exportDirectory->NumberOfFunctions) + return NULL; + + for (ULONG i = 0; i < exportDirectory->NumberOfNames; i++) + { + if ((exportOrdinalTable[i] + exportDirectory->Base) == ProcedureNumber) + { + return PhZeroExtendToUtf16(PTR_ADD_OFFSET(DllBase, exportNameTable[i])); + } + } + + return NULL; +} From 698ba188ff629cf1e69ad6d5269be184c39874ae Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 5 Aug 2018 08:27:37 +1000 Subject: [PATCH 1253/2058] peview: Improve import ordinal name lookup --- tools/peview/impprp.c | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/tools/peview/impprp.c b/tools/peview/impprp.c index 96c1cb746f95..91fba3939bc3 100644 --- a/tools/peview/impprp.c +++ b/tools/peview/impprp.c @@ -83,16 +83,18 @@ VOID PvpProcessImports( PLDR_DATA_TABLE_ENTRY moduleLdrEntry = NULL; PVOID moduleExportAddress = NULL; PVOID importModuleDllBase = NULL; - PPH_STRING ordinalName = NULL; + PPH_STRING exportOrdinalName = NULL; + PPH_STRING exportSymbolName = NULL; PPH_STRING baseDirectory; if (baseDirectory = PhGetBaseDirectory(PvFileName)) AddDllDirectory(baseDirectory->Buffer); - if (importModuleDllBase = LoadLibrary(name->Buffer)) + if (importModuleDllBase = LoadLibraryA(importDll.Name)) { moduleLdrEntry = PhFindLoaderEntry(importModuleDllBase, NULL, NULL); moduleExportAddress = PhGetDllBaseProcedureAddress(importModuleDllBase, NULL, importEntry.Ordinal); + exportOrdinalName = PhGetExportNameFromOrdinal(importModuleDllBase, importEntry.Ordinal); } if (moduleLdrEntry && moduleExportAddress) @@ -105,7 +107,7 @@ VOID PvpProcessImports( moduleLdrEntry->SizeOfImage )) { - ordinalName = PhGetSymbolFromAddress( + exportSymbolName = PhGetSymbolFromAddress( PvSymbolProvider, (ULONG64)moduleExportAddress, NULL, @@ -116,31 +118,33 @@ VOID PvpProcessImports( } } - if (ordinalName) + if (exportSymbolName) { PH_STRINGREF firstPart; PH_STRINGREF secondPart; - if (PhSplitStringRefAtLastChar(&ordinalName->sr, L'!', &firstPart, &secondPart)) + if (PhSplitStringRefAtLastChar(&exportSymbolName->sr, L'!', &firstPart, &secondPart)) name = PhFormatString(L"(Ordinal %u) [%s]", importEntry.Ordinal, secondPart.Buffer); else - name = PhFormatString(L"(Ordinal %u) [%s]", importEntry.Ordinal, ordinalName->Buffer); + name = PhFormatString(L"(Ordinal %u) [%s]", importEntry.Ordinal, exportSymbolName->Buffer); PhSetListViewSubItem(ListViewHandle, lvItemIndex, 2, name->Buffer); PhDereferenceObject(name); - PhDereferenceObject(ordinalName); + PhDereferenceObject(exportSymbolName); } else { - name = PhFormatString(L"(Ordinal %u)", importEntry.Ordinal); + if (exportOrdinalName) + name = PhFormatString(L"(Ordinal %u) [%s]", importEntry.Ordinal, exportOrdinalName->Buffer); + else + name = PhFormatString(L"(Ordinal %u)", importEntry.Ordinal); + PhSetListViewSubItem(ListViewHandle, lvItemIndex, 2, name->Buffer); PhDereferenceObject(name); } - if (baseDirectory) - { - PhDereferenceObject(baseDirectory); - } + PhClearReference(&exportOrdinalName); + PhClearReference(&baseDirectory); } } } From 376e01466ccc33aa7e14c7b43918db7eb8a329b6 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 6 Aug 2018 08:50:48 +1000 Subject: [PATCH 1254/2058] Fix commit 662436ae --- phlib/util.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/phlib/util.c b/phlib/util.c index bdc1875d192b..27b7c84cb795 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -5269,7 +5269,7 @@ BOOLEAN PhExtractIconEx( ) { static PH_INITONCE initOnce = PH_INITONCE_INIT; - static HRESULT (WINAPI *PrivateExtractIconExW)( + static UINT (WINAPI *PrivateExtractIconExW)( _In_ PCWSTR FileName, _In_ INT IconIndex, _Out_opt_ HICON* IconLarge, @@ -5288,7 +5288,7 @@ BOOLEAN PhExtractIconEx( if (!PrivateExtractIconExW) return FALSE; - return SUCCEEDED(PrivateExtractIconExW(FileName, IconIndex, IconLarge, IconSmall, 1)); + return PrivateExtractIconExW(FileName, IconIndex, IconLarge, IconSmall, 1) > 0; // -1 on error or the number of icons. } /** From f295ed0ceceec74a6ec13739a29c303add5e213f Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 6 Aug 2018 09:01:42 +1000 Subject: [PATCH 1255/2058] peview: Remove export tab filter --- tools/peview/expprp.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tools/peview/expprp.c b/tools/peview/expprp.c index bcf48bde8d20..e37d38df8a4e 100644 --- a/tools/peview/expprp.c +++ b/tools/peview/expprp.c @@ -70,10 +70,6 @@ INT_PTR CALLBACK PvpPeExportsDlgProc( WCHAR number[PH_INT32_STR_LEN_1]; WCHAR pointer[PH_PTR_STR_LEN_1]; - // HACK: Skip exports with an empty RVA (TODO: make optional) -dmex - if (!exportFunction.Function) - continue; - PhPrintUInt64(number, i + 1); lvItemIndex = PhAddListViewItem(lvHandle, MAXINT, number, NULL); From d4097e34d9d674f334487d6a0f1a839135d22a80 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 6 Aug 2018 09:45:45 +1000 Subject: [PATCH 1256/2058] Add PhGetWindowStyle --- phlib/include/guisup.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/phlib/include/guisup.h b/phlib/include/guisup.h index d68db82f5361..ea8e1806972d 100644 --- a/phlib/include/guisup.h +++ b/phlib/include/guisup.h @@ -75,6 +75,13 @@ VOID PhSetControlTheme( _In_ PWSTR Theme ); +FORCEINLINE LONG_PTR PhGetWindowStyle( + _In_ HWND WindowHandle + ) +{ + return GetWindowLongPtr(WindowHandle, GWL_STYLE); +} + FORCEINLINE VOID PhSetWindowStyle( _In_ HWND Handle, _In_ LONG_PTR Mask, From ca33e5fed86fd6d84ef19bb94dcb8d107c1ed617 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 6 Aug 2018 09:46:52 +1000 Subject: [PATCH 1257/2058] Update default button theme, Add initial RS5 dark theme support --- phlib/theme.c | 62 ++++++++++++++++++++++++++++++++++----------------- 1 file changed, 42 insertions(+), 20 deletions(-) diff --git a/phlib/theme.c b/phlib/theme.c index 422722a33200..508948487111 100644 --- a/phlib/theme.c +++ b/phlib/theme.c @@ -315,9 +315,7 @@ BOOLEAN CALLBACK PhpThemeWindowEnumChildWindows( } else if (PhEqualStringZ(windowClassName, L"Button", FALSE)) { - ULONG buttonWindowStyle = (ULONG)GetWindowLongPtr(WindowHandle, GWL_STYLE); - - if ((buttonWindowStyle & BS_GROUPBOX) == BS_GROUPBOX) + if (PhGetWindowStyle(WindowHandle) & BS_GROUPBOX) { PhInitializeThemeWindowGroupBox(WindowHandle); } @@ -336,7 +334,18 @@ BOOLEAN CALLBACK PhpThemeWindowEnumChildWindows( } else if (PhEqualStringZ(windowClassName, L"ScrollBar", FALSE)) { - NOTHING; + if (WindowsVersion > WINDOWS_10_RS4) + { + switch (PhpThemeColorMode) + { + case 0: // New colors + PhSetControlTheme(WindowHandle, L""); + break; + case 1: // Old colors + PhSetControlTheme(WindowHandle, L"DarkMode_Explorer"); + break; + } + } } else if (PhEqualStringZ(windowClassName, L"SysHeader32", TRUE)) { @@ -367,7 +376,7 @@ BOOLEAN CALLBACK PhpThemeWindowEnumChildWindows( case 1: // Old colors ListView_SetBkColor(WindowHandle, RGB(30, 30, 30)); ListView_SetTextBkColor(WindowHandle, RGB(30, 30, 30)); - ListView_SetTextColor(WindowHandle, RGB(0xff, 0xff, 0xff)); + ListView_SetTextColor(WindowHandle, PhpThemeWindowTextColor); break; } @@ -382,7 +391,7 @@ BOOLEAN CALLBACK PhpThemeWindowEnumChildWindows( case 1: // Old colors TreeView_SetBkColor(WindowHandle, RGB(30, 30, 30)); //TreeView_SetTextBkColor(WindowHandle, RGB(30, 30, 30)); - TreeView_SetTextColor(WindowHandle, RGB(0xff, 0xff, 0xff)); + TreeView_SetTextColor(WindowHandle, PhpThemeWindowTextColor); break; } @@ -466,10 +475,25 @@ BOOLEAN CALLBACK PhpReInitializeThemeWindowEnumChildWindows( case 1: // Old colors ListView_SetBkColor(WindowHandle, RGB(30, 30, 30)); ListView_SetTextBkColor(WindowHandle, RGB(30, 30, 30)); - ListView_SetTextColor(WindowHandle, RGB(0xff, 0xff, 0xff)); + ListView_SetTextColor(WindowHandle, PhpThemeWindowTextColor); break; } } + else if (PhEqualStringZ(windowClassName, L"ScrollBar", FALSE)) + { + if (WindowsVersion > WINDOWS_10_RS4) + { + switch (PhpThemeColorMode) + { + case 0: // New colors + PhSetControlTheme(WindowHandle, L""); + break; + case 1: // Old colors + PhSetControlTheme(WindowHandle, L"DarkMode_Explorer"); + break; + } + } + } else if (PhEqualStringZ(windowClassName, L"PhTreeNew", FALSE)) { switch (PhpThemeColorMode) @@ -575,7 +599,7 @@ BOOLEAN PhThemeWindowDrawItem( SetDCBrushColor(DrawInfo->hDC, PhpThemeWindowBackgroundColor); break; case 1: // Old colors - SetTextColor(DrawInfo->hDC, RGB(0xff, 0xff, 0xff)); + SetTextColor(DrawInfo->hDC, PhpThemeWindowTextColor); SetDCBrushColor(DrawInfo->hDC, RGB(128, 128, 128)); break; } @@ -624,9 +648,9 @@ BOOLEAN PhThemeWindowDrawItem( oldTextColor = SetTextColor(DrawInfo->hDC, GetSysColor(COLOR_WINDOWTEXT)); break; case 1: // Old colors - oldTextColor = SetTextColor(DrawInfo->hDC, RGB(0xff, 0xff, 0xff)); + oldTextColor = SetTextColor(DrawInfo->hDC, PhpThemeWindowTextColor); //FillRect(DrawInfo->hDC, &DrawInfo->rcItem, GetStockObject(DC_BRUSH)); - //SetTextColor(DrawInfo->hDC, RGB(0xff, 0xff, 0xff)); + //SetTextColor(DrawInfo->hDC, PhpThemeWindowTextColor); break; } @@ -844,7 +868,6 @@ LRESULT CALLBACK PhpThemeWindowDrawButton( SetDCBrushColor(DrawInfo->hdc, RGB(78, 78, 78)); break; } - FillRect(DrawInfo->hdc, &DrawInfo->rc, GetStockObject(DC_BRUSH)); } else if (isHighlighted) @@ -860,7 +883,6 @@ LRESULT CALLBACK PhpThemeWindowDrawButton( SetDCBrushColor(DrawInfo->hdc, RGB(65, 65, 65)); break; } - FillRect(DrawInfo->hdc, &DrawInfo->rc, GetStockObject(DC_BRUSH)); } else @@ -876,11 +898,10 @@ LRESULT CALLBACK PhpThemeWindowDrawButton( SetDCBrushColor(DrawInfo->hdc, RGB(42, 42, 42)); // WindowForegroundColor break; } - FillRect(DrawInfo->hdc, &DrawInfo->rc, GetStockObject(DC_BRUSH)); } - if ((GetWindowLongPtr(DrawInfo->hdr.hwndFrom, GWL_STYLE) & BS_CHECKBOX) != 0) + if (PhGetWindowStyle(DrawInfo->hdr.hwndFrom) & BS_CHECKBOX) { HFONT newFont = PhDuplicateFontWithNewHeight(PhApplicationFont, 22); oldFont = SelectFont(DrawInfo->hdc, newFont); @@ -929,10 +950,11 @@ LRESULT CALLBACK PhpThemeWindowDrawButton( }; HICON buttonIcon; + SetDCBrushColor(DrawInfo->hdc, RGB(65, 65, 65)); + FrameRect(DrawInfo->hdc, &DrawInfo->rc, GetStockObject(DC_BRUSH)); + if (!(buttonIcon = Static_GetIcon(DrawInfo->hdr.hwndFrom, 0))) - { buttonIcon = (HICON)SendMessage(DrawInfo->hdr.hwndFrom, BM_GETIMAGE, IMAGE_ICON, 0); - } if (buttonIcon) { @@ -1000,7 +1022,7 @@ LRESULT CALLBACK PhThemeWindowDrawRebar( SetTextColor(DrawInfo->hdc, RGB(0x0, 0x0, 0x0)); SetDCBrushColor(DrawInfo->hdc, GetSysColor(COLOR_3DFACE)); // RGB(0x0, 0x0, 0x0)); case 1: // Old colors - SetTextColor(DrawInfo->hdc, RGB(0xff, 0xff, 0xff)); + SetTextColor(DrawInfo->hdc, PhpThemeWindowTextColor); SetDCBrushColor(DrawInfo->hdc, RGB(65, 65, 65)); break; } @@ -1062,7 +1084,7 @@ LRESULT CALLBACK PhThemeWindowDrawToolbar( //if (isMouseDown) //{ - // SetTextColor(DrawInfo->nmcd.hdc, RGB(0xff, 0xff, 0xff)); + // SetTextColor(DrawInfo->nmcd.hdc, PhpThemeWindowTextColor); // SetDCBrushColor(DrawInfo->nmcd.hdc, RGB(0xff, 0xff, 0xff)); // FillRect(DrawInfo->nmcd.hdc, &DrawInfo->nmcd.rc, GetStockObject(DC_BRUSH)); //} @@ -1109,7 +1131,7 @@ LRESULT CALLBACK PhThemeWindowDrawToolbar( FillRect(DrawInfo->nmcd.hdc, &DrawInfo->nmcd.rc, GetStockObject(DC_BRUSH)); break; case 1: // Old colors - SetTextColor(DrawInfo->nmcd.hdc, RGB(0xff, 0xff, 0xff)); + SetTextColor(DrawInfo->nmcd.hdc, PhpThemeWindowTextColor); SetDCBrushColor(DrawInfo->nmcd.hdc, RGB(128, 128, 128)); FillRect(DrawInfo->nmcd.hdc, &DrawInfo->nmcd.rc, GetStockObject(DC_BRUSH)); break; @@ -1125,7 +1147,7 @@ LRESULT CALLBACK PhThemeWindowDrawToolbar( FillRect(DrawInfo->nmcd.hdc, &DrawInfo->nmcd.rc, GetStockObject(DC_BRUSH)); break; case 1: // Old colors - SetTextColor(DrawInfo->nmcd.hdc, RGB(0xff, 0xff, 0xff)); + SetTextColor(DrawInfo->nmcd.hdc, PhpThemeWindowTextColor); SetDCBrushColor(DrawInfo->nmcd.hdc, RGB(65, 65, 65)); //RGB(28, 28, 28)); // RGB(65, 65, 65)); FillRect(DrawInfo->nmcd.hdc, &DrawInfo->nmcd.rc, GetStockObject(DC_BRUSH)); break; From 1304979565eb42ad1340880350fa076162dcba74 Mon Sep 17 00:00:00 2001 From: zeffy Date: Sun, 5 Aug 2018 17:09:58 -0700 Subject: [PATCH 1258/2058] Fix RtlOsDeploymentState declaration (#296) --- phnt/include/ntrtl.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/phnt/include/ntrtl.h b/phnt/include/ntrtl.h index 98a95b1f9fbf..eace0c002ec4 100644 --- a/phnt/include/ntrtl.h +++ b/phnt/include/ntrtl.h @@ -8026,8 +8026,6 @@ RtlConvertDeviceFamilyInfoToString( _Out_writes_bytes_(*DeviceFormBufferSize) PWSTR DeviceForm ); -#endif - NTSYSAPI OS_DEPLOYEMENT_STATE_VALUES NTAPI @@ -8035,6 +8033,8 @@ RtlOsDeploymentState( _Reserved_ _In_ ULONG Flags ); +#endif + #if (PHNT_VERSION >= PHNT_VISTA) NTSYSAPI From bf5a1cd865e0ae4aad472556782875a456d158f9 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 6 Aug 2018 10:18:46 +1000 Subject: [PATCH 1259/2058] Fix regression from commit d4097e3 --- phlib/theme.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/phlib/theme.c b/phlib/theme.c index 508948487111..df7a1a9c9314 100644 --- a/phlib/theme.c +++ b/phlib/theme.c @@ -315,7 +315,7 @@ BOOLEAN CALLBACK PhpThemeWindowEnumChildWindows( } else if (PhEqualStringZ(windowClassName, L"Button", FALSE)) { - if (PhGetWindowStyle(WindowHandle) & BS_GROUPBOX) + if ((PhGetWindowStyle(WindowHandle) & BS_GROUPBOX) == BS_GROUPBOX) { PhInitializeThemeWindowGroupBox(WindowHandle); } @@ -901,7 +901,7 @@ LRESULT CALLBACK PhpThemeWindowDrawButton( FillRect(DrawInfo->hdc, &DrawInfo->rc, GetStockObject(DC_BRUSH)); } - if (PhGetWindowStyle(DrawInfo->hdr.hwndFrom) & BS_CHECKBOX) + if ((PhGetWindowStyle(DrawInfo->hdr.hwndFrom) & BS_CHECKBOX) == BS_CHECKBOX) { HFONT newFont = PhDuplicateFontWithNewHeight(PhApplicationFont, 22); oldFont = SelectFont(DrawInfo->hdc, newFont); From 28e94e28c4d848180cdde5d770e448c8cc003613 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 6 Aug 2018 10:20:33 +1000 Subject: [PATCH 1260/2058] Update todo list (Added commit 698ba18) --- tools/peview/impprp.c | 1 - 1 file changed, 1 deletion(-) diff --git a/tools/peview/impprp.c b/tools/peview/impprp.c index 91fba3939bc3..76f006f72769 100644 --- a/tools/peview/impprp.c +++ b/tools/peview/impprp.c @@ -99,7 +99,6 @@ VOID PvpProcessImports( if (moduleLdrEntry && moduleExportAddress) { - // TODO: Lookup name from export address table. if (PhLoadModuleSymbolProvider( PvSymbolProvider, moduleLdrEntry->FullDllName.Buffer, From e2bbbdbf3262c964b0d19accdf22e5bc9542a80b Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 6 Aug 2018 11:18:11 +1000 Subject: [PATCH 1261/2058] Fix peview import forwarder name --- phlib/util.c | 23 ++++++++++--- tools/peview/impprp.c | 75 +++++++++++++++++++++++-------------------- 2 files changed, 58 insertions(+), 40 deletions(-) diff --git a/phlib/util.c b/phlib/util.c index 27b7c84cb795..a2d5d42f5f24 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -5907,8 +5907,10 @@ PPH_STRING PhGetExportNameFromOrdinal( PIMAGE_NT_HEADERS imageNtHeader; PIMAGE_DATA_DIRECTORY dataDirectory; PIMAGE_EXPORT_DIRECTORY exportDirectory; + PULONG exportAddressTable; PULONG exportNameTable; PUSHORT exportOrdinalTable; + ULONG i; if (!NT_SUCCESS(PhGetLoaderEntryImageNtHeaders(DllBase, &imageNtHeader))) return NULL; @@ -5923,17 +5925,28 @@ PPH_STRING PhGetExportNameFromOrdinal( ))) return NULL; + exportAddressTable = PTR_ADD_OFFSET(DllBase, exportDirectory->AddressOfFunctions); exportNameTable = PTR_ADD_OFFSET(DllBase, exportDirectory->AddressOfNames); exportOrdinalTable = PTR_ADD_OFFSET(DllBase, exportDirectory->AddressOfNameOrdinals); - if (ProcedureNumber > exportDirectory->Base + exportDirectory->NumberOfFunctions) - return NULL; - - for (ULONG i = 0; i < exportDirectory->NumberOfNames; i++) + for (i = 0; i < exportDirectory->NumberOfNames; i++) { if ((exportOrdinalTable[i] + exportDirectory->Base) == ProcedureNumber) { - return PhZeroExtendToUtf16(PTR_ADD_OFFSET(DllBase, exportNameTable[i])); + PVOID baseAddress = PTR_ADD_OFFSET(DllBase, exportAddressTable[exportOrdinalTable[i]]); + + if ( + ((ULONG_PTR)baseAddress >= (ULONG_PTR)exportDirectory) && + ((ULONG_PTR)baseAddress < (ULONG_PTR)PTR_ADD_OFFSET(exportDirectory, dataDirectory->Size)) + ) + { + // This is a forwarder RVA. + return PhZeroExtendToUtf16((PSTR)baseAddress); + } + else + { + return PhZeroExtendToUtf16(PTR_ADD_OFFSET(DllBase, exportNameTable[i])); + } } } diff --git a/tools/peview/impprp.c b/tools/peview/impprp.c index 76f006f72769..53c25b1c1adf 100644 --- a/tools/peview/impprp.c +++ b/tools/peview/impprp.c @@ -97,51 +97,56 @@ VOID PvpProcessImports( exportOrdinalName = PhGetExportNameFromOrdinal(importModuleDllBase, importEntry.Ordinal); } - if (moduleLdrEntry && moduleExportAddress) + if (exportOrdinalName) { - if (PhLoadModuleSymbolProvider( - PvSymbolProvider, - moduleLdrEntry->FullDllName.Buffer, - (ULONG64)importModuleDllBase, - moduleLdrEntry->SizeOfImage - )) - { - exportSymbolName = PhGetSymbolFromAddress( - PvSymbolProvider, - (ULONG64)moduleExportAddress, - NULL, - NULL, - NULL, - NULL - ); - } - } - - if (exportSymbolName) - { - PH_STRINGREF firstPart; - PH_STRINGREF secondPart; - - if (PhSplitStringRefAtLastChar(&exportSymbolName->sr, L'!', &firstPart, &secondPart)) - name = PhFormatString(L"(Ordinal %u) [%s]", importEntry.Ordinal, secondPart.Buffer); - else - name = PhFormatString(L"(Ordinal %u) [%s]", importEntry.Ordinal, exportSymbolName->Buffer); - + name = PhFormatString(L"(Ordinal %u) [%s]", importEntry.Ordinal, exportOrdinalName->Buffer); PhSetListViewSubItem(ListViewHandle, lvItemIndex, 2, name->Buffer); PhDereferenceObject(name); - PhDereferenceObject(exportSymbolName); } else { - if (exportOrdinalName) - name = PhFormatString(L"(Ordinal %u) [%s]", importEntry.Ordinal, exportOrdinalName->Buffer); + if (moduleLdrEntry && moduleExportAddress) + { + if (PhLoadModuleSymbolProvider( + PvSymbolProvider, + PhGetUnicodeString(&moduleLdrEntry->FullDllName), + (ULONG64)importModuleDllBase, + moduleLdrEntry->SizeOfImage + )) + { + exportSymbolName = PhGetSymbolFromAddress( + PvSymbolProvider, + (ULONG64)moduleExportAddress, + NULL, + NULL, + NULL, + NULL + ); + } + } + + if (exportSymbolName) + { + PH_STRINGREF firstPart; + PH_STRINGREF secondPart; + + if (PhSplitStringRefAtLastChar(&exportSymbolName->sr, L'!', &firstPart, &secondPart)) + name = PhFormatString(L"(Ordinal %u) [%s]", importEntry.Ordinal, secondPart.Buffer); + else + name = PhFormatString(L"(Ordinal %u) [%s]", importEntry.Ordinal, exportSymbolName->Buffer); + + PhSetListViewSubItem(ListViewHandle, lvItemIndex, 2, name->Buffer); + PhDereferenceObject(name); + } else + { name = PhFormatString(L"(Ordinal %u)", importEntry.Ordinal); - - PhSetListViewSubItem(ListViewHandle, lvItemIndex, 2, name->Buffer); - PhDereferenceObject(name); + PhSetListViewSubItem(ListViewHandle, lvItemIndex, 2, name->Buffer); + PhDereferenceObject(name); + } } + PhClearReference(&exportSymbolName); PhClearReference(&exportOrdinalName); PhClearReference(&baseDirectory); } From 8c6ae009c682dd0bb49c84899ac770ec4cd45aaa Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 6 Aug 2018 11:20:56 +1000 Subject: [PATCH 1262/2058] Fix typo --- tools/peview/impprp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/peview/impprp.c b/tools/peview/impprp.c index 53c25b1c1adf..078b4cdc11e8 100644 --- a/tools/peview/impprp.c +++ b/tools/peview/impprp.c @@ -109,7 +109,7 @@ VOID PvpProcessImports( { if (PhLoadModuleSymbolProvider( PvSymbolProvider, - PhGetUnicodeString(&moduleLdrEntry->FullDllName), + moduleLdrEntry->FullDllName.Buffer, (ULONG64)importModuleDllBase, moduleLdrEntry->SizeOfImage )) From 5cd62bffffc5977e0c313121e102f8d5fdba6edd Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 7 Aug 2018 10:02:57 +1000 Subject: [PATCH 1263/2058] Add PhEnumFileExtendedAttributes --- phlib/include/phnative.h | 22 +++++++++++ phlib/native.c | 84 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 106 insertions(+) diff --git a/phlib/include/phnative.h b/phlib/include/phnative.h index 4d74d0376a29..15ee8bf01388 100644 --- a/phlib/include/phnative.h +++ b/phlib/include/phnative.h @@ -854,6 +854,28 @@ PhEnumDirectoryFile( _In_opt_ PVOID Context ); +#define PH_FIRST_FILE_EA(Information) \ + ((PFILE_FULL_EA_INFORMATION)(Information)) +#define PH_NEXT_FILE_EA(Information) \ + (((PFILE_FULL_EA_INFORMATION)(Information))->NextEntryOffset ? \ + (PTR_ADD_OFFSET((Information), ((PFILE_FULL_EA_INFORMATION)(Information))->NextEntryOffset)) : \ + NULL \ + ) + +typedef BOOLEAN (NTAPI *PPH_ENUM_FILE_EA)( + _In_ PFILE_FULL_EA_INFORMATION Information, + _In_opt_ PVOID Context + ); + +PHLIBAPI +NTSTATUS +NTAPI +PhEnumFileExtendedAttributes( + _In_ HANDLE FileHandle, + _In_ PPH_ENUM_FILE_EA Callback, + _In_opt_ PVOID Context + ); + #define PH_FIRST_STREAM(Streams) ((PFILE_STREAM_INFORMATION)(Streams)) #define PH_NEXT_STREAM(Stream) ( \ ((PFILE_STREAM_INFORMATION)(Stream))->NextEntryOffset ? \ diff --git a/phlib/native.c b/phlib/native.c index 53cc2e3a6811..a3ffe304ddca 100644 --- a/phlib/native.c +++ b/phlib/native.c @@ -4999,6 +4999,90 @@ NTSTATUS PhEnumDirectoryFile( return status; } +NTSTATUS PhEnumFileExtendedAttributes( + _In_ HANDLE FileHandle, + _In_ PPH_ENUM_FILE_EA Callback, + _In_opt_ PVOID Context + ) +{ + NTSTATUS status; + BOOLEAN firstTime = TRUE; + BOOLEAN success = FALSE; + IO_STATUS_BLOCK isb; + ULONG bufferSize; + PVOID buffer; + PFILE_FULL_EA_INFORMATION i; + + bufferSize = 0x400; + buffer = PhAllocate(bufferSize); + + while (TRUE) + { + while (TRUE) + { + status = NtQueryEaFile( + FileHandle, + &isb, + buffer, + bufferSize, + FALSE, + NULL, + 0, + NULL, + firstTime + ); + + if (status == STATUS_PENDING) + { + status = NtWaitForSingleObject(FileHandle, FALSE, NULL); + + if (NT_SUCCESS(status)) + status = isb.Status; + } + + if (status == STATUS_BUFFER_OVERFLOW || status == STATUS_INFO_LENGTH_MISMATCH) + { + PhFree(buffer); + bufferSize *= 2; + buffer = PhAllocate(bufferSize); + } + else + { + break; + } + } + + if (status == STATUS_NO_MORE_FILES) + { + status = STATUS_SUCCESS; + break; + } + + if (!NT_SUCCESS(status)) + break; + + success = TRUE; + + for (i = PH_FIRST_FILE_EA(buffer); i; i = PH_NEXT_FILE_EA(i)) + { + if (!Callback(i, Context)) + { + success = FALSE; + break; + } + } + + if (!success) + break; + + firstTime = FALSE; + } + + PhFree(buffer); + + return status; +} + NTSTATUS PhEnumFileStreams( _In_ HANDLE FileHandle, _Out_ PVOID *Streams From 806d17bd8d93ff08476354e4e2febd4eeabfed0b Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 7 Aug 2018 10:09:23 +1000 Subject: [PATCH 1264/2058] Fix propsheet layout macro usage --- ProcessHacker/include/procprpp.h | 16 +++--- ProcessHacker/procprp.c | 34 ++++++++++--- ProcessHacker/prpgenv.c | 65 +++++++----------------- ProcessHacker/prpggen.c | 87 ++++++++++---------------------- ProcessHacker/prpghndl.c | 29 ++++------- ProcessHacker/prpgmem.c | 20 +++----- ProcessHacker/prpgmod.c | 23 +++------ ProcessHacker/prpgperf.c | 22 +++----- ProcessHacker/prpgsrv.c | 26 +++------- ProcessHacker/prpgstat.c | 13 ++--- ProcessHacker/prpgthrd.c | 23 +++------ ProcessHacker/prpgwmi.c | 16 ++---- plugins/DotNetTools/asmpage.c | 2 - plugins/DotNetTools/perfpage.c | 1 - plugins/DotNetTools/svcext.c | 2 +- plugins/ExtendedTools/etwprprp.c | 4 +- plugins/ExtendedTools/gpuprprp.c | 4 +- plugins/UserNotes/main.c | 4 +- plugins/WindowExplorer/wnddlg.c | 3 +- 19 files changed, 138 insertions(+), 256 deletions(-) diff --git a/ProcessHacker/include/procprpp.h b/ProcessHacker/include/procprpp.h index 6f8ceccf2b03..e92aab5dcd61 100644 --- a/ProcessHacker/include/procprpp.h +++ b/ProcessHacker/include/procprpp.h @@ -70,18 +70,18 @@ FORCEINLINE BOOLEAN PhpPropPageDlgProcHeader( if (!propSheetPage) return FALSE; + propPageContext = (PPH_PROCESS_PROPPAGECONTEXT)propSheetPage->lParam;; + *PropSheetPage = propSheetPage; - *PropPageContext = propPageContext = (PPH_PROCESS_PROPPAGECONTEXT)propSheetPage->lParam; + *PropPageContext = propPageContext; *ProcessItem = propPageContext->PropContext->ProcessItem; - return TRUE; -} + if (uMsg == WM_NCDESTROY) + { + PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); + } -FORCEINLINE VOID PhpPropPageDlgProcDestroy( - _In_ HWND hwndDlg - ) -{ - PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); + return TRUE; } #define SET_BUTTON_ICON(Id, Icon) \ diff --git a/ProcessHacker/procprp.c b/ProcessHacker/procprp.c index 233050654d01..d99f8af00f56 100644 --- a/ProcessHacker/procprp.c +++ b/ProcessHacker/procprp.c @@ -463,14 +463,34 @@ BOOLEAN PhPropPageDlgProcHeader( _Out_ PPH_PROCESS_ITEM *ProcessItem ) { - return PhpPropPageDlgProcHeader(hwndDlg, uMsg, lParam, PropSheetPage, PropPageContext, ProcessItem); -} + LPPROPSHEETPAGE propSheetPage; + PPH_PROCESS_PROPPAGECONTEXT propPageContext; -VOID PhPropPageDlgProcDestroy( - _In_ HWND hwndDlg - ) -{ - PhpPropPageDlgProcDestroy(hwndDlg); + if (uMsg == WM_INITDIALOG) + { + PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, (PVOID)lParam); + } + + propSheetPage = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); + + if (!propSheetPage) + return FALSE; + + propPageContext = (PPH_PROCESS_PROPPAGECONTEXT)propSheetPage->lParam; + + if (PropSheetPage) + *PropSheetPage = propSheetPage; + if (PropPageContext) + *PropPageContext = propPageContext; + if (ProcessItem) + *ProcessItem = propPageContext->PropContext->ProcessItem; + + if (uMsg == WM_NCDESTROY) + { + PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); + } + + return TRUE; } PPH_LAYOUT_ITEM PhAddPropPageLayoutItem( diff --git a/ProcessHacker/prpgenv.c b/ProcessHacker/prpgenv.c index c0231f9861ed..76c33c1e19a6 100644 --- a/ProcessHacker/prpgenv.c +++ b/ProcessHacker/prpgenv.c @@ -84,9 +84,11 @@ typedef struct _PHP_PROCESS_ENVIRONMENT_TREENODE } PHP_PROCESS_ENVIRONMENT_TREENODE, *PPHP_PROCESS_ENVIRONMENT_TREENODE; PPHP_PROCESS_ENVIRONMENT_TREENODE PhpAddEnvironmentChildNode( - _Inout_ PPH_ENVIRONMENT_CONTEXT Context, + _In_ PPH_ENVIRONMENT_CONTEXT Context, _In_opt_ PPHP_PROCESS_ENVIRONMENT_TREENODE ParentNode, - _In_opt_ PPH_STRING Name, + _In_ ULONG Id, + _In_ PROCESS_ENVIRONMENT_TREENODE_TYPE Type, + _In_ PPH_STRING Name, _In_opt_ PPH_STRING Value ); @@ -163,9 +165,9 @@ VOID PhpRefreshEnvironmentList( ULONG i; PhpClearEnvironmentTree(Context); - processRootNode = PhpAddEnvironmentChildNode(Context, NULL, PhaCreateString(L"Process"), NULL); - userRootNode = PhpAddEnvironmentChildNode(Context, NULL, PhaCreateString(L"User"), NULL); - systemRootNode = PhpAddEnvironmentChildNode(Context, NULL, PhaCreateString(L"System"), NULL); + processRootNode = PhpAddEnvironmentChildNode(Context, NULL, 0, 0, PhaCreateString(L"Process"), NULL); + userRootNode = PhpAddEnvironmentChildNode(Context, NULL, 0, 0, PhaCreateString(L"User"), NULL); + systemRootNode = PhpAddEnvironmentChildNode(Context, NULL, 0, 0, PhaCreateString(L"System"), NULL); if (DestroyEnvironmentBlock && Context->SystemDefaultEnvironment) DestroyEnvironmentBlock(Context->SystemDefaultEnvironment); @@ -223,7 +225,6 @@ VOID PhpRefreshEnvironmentList( { UNICODE_STRING variableNameUs; UNICODE_STRING variableValueUs; - PROCESS_ENVIRONMENT_TREENODE_TYPE variableType; item = PhItemArray(&Context->Items, i); @@ -236,7 +237,7 @@ VOID PhpRefreshEnvironmentList( &variableValueUs ) == STATUS_BUFFER_TOO_SMALL) { - variableType = PROCESS_ENVIRONMENT_TREENODE_TYPE_SYSTEM; + PhpAddEnvironmentChildNode(Context, systemRootNode, i, PROCESS_ENVIRONMENT_TREENODE_TYPE_SYSTEM, item->Name, item->Value); } else if (RtlQueryEnvironmentVariable_U( Context->UserDefaultEnvironment, @@ -244,36 +245,11 @@ VOID PhpRefreshEnvironmentList( &variableValueUs ) == STATUS_BUFFER_TOO_SMALL) { - variableType = PROCESS_ENVIRONMENT_TREENODE_TYPE_USER; + PhpAddEnvironmentChildNode(Context, userRootNode, i, PROCESS_ENVIRONMENT_TREENODE_TYPE_USER, item->Name, item->Value); } else { - variableType = PROCESS_ENVIRONMENT_TREENODE_TYPE_PROCESS; - } - - switch (variableType) - { - case PROCESS_ENVIRONMENT_TREENODE_TYPE_PROCESS: - { - PPHP_PROCESS_ENVIRONMENT_TREENODE node = PhpAddEnvironmentChildNode(Context, processRootNode, item->Name, item->Value); - node->Id = i; - node->Type = variableType; - } - break; - case PROCESS_ENVIRONMENT_TREENODE_TYPE_USER: - { - PPHP_PROCESS_ENVIRONMENT_TREENODE node = PhpAddEnvironmentChildNode(Context, userRootNode, item->Name, item->Value); - node->Id = i; - node->Type = variableType; - } - break; - case PROCESS_ENVIRONMENT_TREENODE_TYPE_SYSTEM: - { - PPHP_PROCESS_ENVIRONMENT_TREENODE node = PhpAddEnvironmentChildNode(Context, systemRootNode, item->Name, item->Value); - node->Id = i; - node->Type = variableType; - } - break; + PhpAddEnvironmentChildNode(Context, processRootNode, i, PROCESS_ENVIRONMENT_TREENODE_TYPE_PROCESS, item->Name, item->Value); } } @@ -771,6 +747,8 @@ PPHP_PROCESS_ENVIRONMENT_TREENODE PhpAddEnvironmentRootNode( PPHP_PROCESS_ENVIRONMENT_TREENODE PhpAddEnvironmentChildNode( _In_ PPH_ENVIRONMENT_CONTEXT Context, _In_opt_ PPHP_PROCESS_ENVIRONMENT_TREENODE ParentNode, + _In_ ULONG Id, + _In_ PROCESS_ENVIRONMENT_TREENODE_TYPE Type, _In_ PPH_STRING Name, _In_opt_ PPH_STRING Value ) @@ -1224,14 +1202,13 @@ INT_PTR CALLBACK PhpProcessEnvironmentDlgProc( _In_ UINT uMsg, _In_ WPARAM wParam, _In_ LPARAM lParam -) + ) { - LPPROPSHEETPAGE propSheetPage; PPH_PROCESS_PROPPAGECONTEXT propPageContext; PPH_PROCESS_ITEM processItem; PPH_ENVIRONMENT_CONTEXT context; - if (PhpPropPageDlgProcHeader(hwndDlg, uMsg, lParam, &propSheetPage, &propPageContext, &processItem)) + if (PhPropPageDlgProcHeader(hwndDlg, uMsg, lParam, NULL, &propPageContext, &processItem)) { context = propPageContext->Context; } @@ -1282,23 +1259,17 @@ INT_PTR CALLBACK PhpProcessEnvironmentDlgProc( DestroyEnvironmentBlock(context->UserDefaultEnvironment); PhFree(context); - - PhpPropPageDlgProcDestroy(hwndDlg); } break; case WM_SHOWWINDOW: { - if (!propPageContext->LayoutInitialized) - { - PPH_LAYOUT_ITEM dialogItem; + PPH_LAYOUT_ITEM dialogItem; - dialogItem = PhAddPropPageLayoutItem(hwndDlg, hwndDlg, PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL); + if (dialogItem = PhBeginPropPageLayout(hwndDlg, propPageContext)) + { PhAddPropPageLayoutItem(hwndDlg, context->SearchWindowHandle, dialogItem, PH_ANCHOR_RIGHT | PH_ANCHOR_TOP); PhAddPropPageLayoutItem(hwndDlg, context->TreeNewHandle, dialogItem, PH_ANCHOR_ALL); - - PhDoPropPageLayout(hwndDlg); - - propPageContext->LayoutInitialized = TRUE; + PhEndPropPageLayout(hwndDlg, propPageContext); } } break; diff --git a/ProcessHacker/prpggen.c b/ProcessHacker/prpggen.c index 5912ce10c777..cea7c5852bf8 100644 --- a/ProcessHacker/prpggen.c +++ b/ProcessHacker/prpggen.c @@ -170,8 +170,7 @@ INT_PTR CALLBACK PhpProcessGeneralDlgProc( PPH_PROCESS_PROPPAGECONTEXT propPageContext; PPH_PROCESS_ITEM processItem; - if (!PhpPropPageDlgProcHeader(hwndDlg, uMsg, lParam, - &propSheetPage, &propPageContext, &processItem)) + if (!PhPropPageDlgProcHeader(hwndDlg, uMsg, lParam, &propSheetPage, &propPageContext, &processItem)) return FALSE; switch (uMsg) @@ -421,67 +420,35 @@ INT_PTR CALLBACK PhpProcessGeneralDlgProc( PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport); } break; - case WM_DESTROY: - { - PhpPropPageDlgProcDestroy(hwndDlg); - } - break; case WM_SHOWWINDOW: { - if (!propPageContext->LayoutInitialized) + PPH_LAYOUT_ITEM dialogItem; + + if (dialogItem = PhBeginPropPageLayout(hwndDlg, propPageContext)) { - PPH_LAYOUT_ITEM dialogItem; - - dialogItem = PhAddPropPageLayoutItem(hwndDlg, hwndDlg, - PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL); - PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_FILE), - dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); - PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_NAME), - dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); - PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_COMPANYNAME), - dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); - PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_COMPANYNAME_LINK), - dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); - PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_VERSION), - dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); - PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_PROCESSTYPELABEL), - dialogItem, PH_ANCHOR_RIGHT | PH_ANCHOR_TOP); - PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_PROCESSTYPETEXT), - dialogItem, PH_ANCHOR_RIGHT | PH_ANCHOR_TOP); - PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_FILENAME), - dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); - PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_INSPECT), - dialogItem, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); - PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_OPENFILENAME), - dialogItem, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); - PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_CMDLINE), - dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); - PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_VIEWCOMMANDLINE), - dialogItem, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); - PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_CURDIR), - dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); - PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_STARTED), - dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); - PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_PEBADDRESS), - dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); - PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_PARENTPROCESS), - dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); - PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_VIEWPARENTPROCESS), - dialogItem, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); - PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_MITIGATION), - dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); - PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_VIEWMITIGATION), - dialogItem, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); - PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_TERMINATE), - dialogItem, PH_ANCHOR_RIGHT | PH_ANCHOR_TOP); - PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_PERMISSIONS), - dialogItem, PH_ANCHOR_RIGHT | PH_ANCHOR_TOP); - PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_PROCESS), - dialogItem, PH_ANCHOR_ALL); - - PhDoPropPageLayout(hwndDlg); - - propPageContext->LayoutInitialized = TRUE; + PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_FILE), dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); + PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_NAME), dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); + PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_COMPANYNAME), dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); + PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_COMPANYNAME_LINK), dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); + PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_VERSION), dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); + PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_PROCESSTYPELABEL), dialogItem, PH_ANCHOR_RIGHT | PH_ANCHOR_TOP); + PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_PROCESSTYPETEXT), dialogItem, PH_ANCHOR_RIGHT | PH_ANCHOR_TOP); + PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_FILENAME), dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); + PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_INSPECT), dialogItem, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); + PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_OPENFILENAME), dialogItem, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); + PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_CMDLINE), dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); + PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_VIEWCOMMANDLINE), dialogItem, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); + PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_CURDIR), dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); + PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_STARTED), dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); + PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_PEBADDRESS), dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); + PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_PARENTPROCESS), dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); + PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_VIEWPARENTPROCESS), dialogItem, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); + PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_MITIGATION), dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); + PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_VIEWMITIGATION), dialogItem, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); + PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_TERMINATE), dialogItem, PH_ANCHOR_RIGHT | PH_ANCHOR_TOP); + PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_PERMISSIONS), dialogItem, PH_ANCHOR_RIGHT | PH_ANCHOR_TOP); + PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_PROCESS), dialogItem, PH_ANCHOR_ALL); + PhEndPropPageLayout(hwndDlg, propPageContext); } } break; diff --git a/ProcessHacker/prpghndl.c b/ProcessHacker/prpghndl.c index b86429b4f99f..4de7eb9ae26a 100644 --- a/ProcessHacker/prpghndl.c +++ b/ProcessHacker/prpghndl.c @@ -323,16 +323,14 @@ INT_PTR CALLBACK PhpProcessHandlesDlgProc( _In_ LPARAM lParam ) { - LPPROPSHEETPAGE propSheetPage; PPH_PROCESS_PROPPAGECONTEXT propPageContext; PPH_PROCESS_ITEM processItem; PPH_HANDLES_CONTEXT handlesContext; HWND tnHandle; - if (PhpPropPageDlgProcHeader(hwndDlg, uMsg, lParam, - &propSheetPage, &propPageContext, &processItem)) + if (PhPropPageDlgProcHeader(hwndDlg, uMsg, lParam, NULL, &propPageContext, &processItem)) { - handlesContext = (PPH_HANDLES_CONTEXT)propPageContext->Context; + handlesContext = propPageContext->Context; if (handlesContext) tnHandle = handlesContext->ListContext.TreeNewHandle; @@ -346,8 +344,8 @@ INT_PTR CALLBACK PhpProcessHandlesDlgProc( { case WM_INITDIALOG: { - handlesContext = propPageContext->Context = - PhAllocate(PhEmGetObjectSize(EmHandlesContextType, sizeof(PH_HANDLES_CONTEXT))); + handlesContext = propPageContext->Context = PhAllocate(PhEmGetObjectSize(EmHandlesContextType, sizeof(PH_HANDLES_CONTEXT))); + memset(handlesContext, 0, sizeof(PH_HANDLES_CONTEXT)); handlesContext->Provider = PhCreateHandleProvider( processItem->ProcessId @@ -382,13 +380,14 @@ INT_PTR CALLBACK PhpProcessHandlesDlgProc( handlesContext, &handlesContext->UpdatedEventRegistration ); - handlesContext->WindowHandle = hwndDlg; + handlesContext->WindowHandle = hwndDlg; handlesContext->SearchboxHandle = GetDlgItem(hwndDlg, IDC_HANDLESEARCH); + tnHandle = GetDlgItem(hwndDlg, IDC_LIST); + PhCreateSearchControl(hwndDlg, handlesContext->SearchboxHandle, L"Search Handles (Ctrl+K)"); // Initialize the list. - tnHandle = GetDlgItem(hwndDlg, IDC_LIST); BringWindowToTop(tnHandle); PhInitializeHandleList(hwndDlg, tnHandle, &handlesContext->ListContext); TreeNew_SetEmptyText(tnHandle, &PhpLoadingText, 0); @@ -459,23 +458,17 @@ INT_PTR CALLBACK PhpProcessHandlesDlgProc( PhDeleteHandleList(&handlesContext->ListContext); PhFree(handlesContext); - - PhpPropPageDlgProcDestroy(hwndDlg); } break; case WM_SHOWWINDOW: { - if (!propPageContext->LayoutInitialized) + PPH_LAYOUT_ITEM dialogItem; + + if (dialogItem = PhBeginPropPageLayout(hwndDlg, propPageContext)) { - PPH_LAYOUT_ITEM dialogItem; - - dialogItem = PhAddPropPageLayoutItem(hwndDlg, hwndDlg, PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL); PhAddPropPageLayoutItem(hwndDlg, handlesContext->SearchboxHandle, dialogItem, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_LIST), dialogItem, PH_ANCHOR_ALL); - - PhDoPropPageLayout(hwndDlg); - - propPageContext->LayoutInitialized = TRUE; + PhEndPropPageLayout(hwndDlg, propPageContext); } } break; diff --git a/ProcessHacker/prpgmem.c b/ProcessHacker/prpgmem.c index 509016ff2758..59b7fe33db3e 100644 --- a/ProcessHacker/prpgmem.c +++ b/ProcessHacker/prpgmem.c @@ -310,8 +310,7 @@ INT_PTR CALLBACK PhpProcessMemoryDlgProc( PPH_MEMORY_CONTEXT memoryContext; HWND tnHandle; - if (PhpPropPageDlgProcHeader(hwndDlg, uMsg, lParam, - &propSheetPage, &propPageContext, &processItem)) + if (PhPropPageDlgProcHeader(hwndDlg, uMsg, lParam, &propSheetPage, &propPageContext, &processItem)) { memoryContext = (PPH_MEMORY_CONTEXT)propPageContext->Context; @@ -327,8 +326,7 @@ INT_PTR CALLBACK PhpProcessMemoryDlgProc( { case WM_INITDIALOG: { - memoryContext = propPageContext->Context = - PhAllocate(PhEmGetObjectSize(EmMemoryContextType, sizeof(PH_MEMORY_CONTEXT))); + memoryContext = propPageContext->Context = PhAllocate(PhEmGetObjectSize(EmMemoryContextType, sizeof(PH_MEMORY_CONTEXT))); memset(memoryContext, 0, sizeof(PH_MEMORY_CONTEXT)); memoryContext->ProcessId = processItem->ProcessId; @@ -386,23 +384,17 @@ INT_PTR CALLBACK PhpProcessMemoryDlgProc( PhClearReference(&memoryContext->ErrorMessage); PhFree(memoryContext); - - PhpPropPageDlgProcDestroy(hwndDlg); } break; case WM_SHOWWINDOW: { - if (!propPageContext->LayoutInitialized) - { - PPH_LAYOUT_ITEM dialogItem; + PPH_LAYOUT_ITEM dialogItem; - dialogItem = PhAddPropPageLayoutItem(hwndDlg, hwndDlg, PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL); + if (dialogItem = PhBeginPropPageLayout(hwndDlg, propPageContext)) + { PhAddPropPageLayoutItem(hwndDlg, memoryContext->SearchboxHandle, dialogItem, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); PhAddPropPageLayoutItem(hwndDlg, memoryContext->ListContext.TreeNewHandle, dialogItem, PH_ANCHOR_ALL); - - PhDoPropPageLayout(hwndDlg); - - propPageContext->LayoutInitialized = TRUE; + PhEndPropPageLayout(hwndDlg, propPageContext); } } break; diff --git a/ProcessHacker/prpgmod.c b/ProcessHacker/prpgmod.c index 5fcdc255bd59..b69956dc4647 100644 --- a/ProcessHacker/prpgmod.c +++ b/ProcessHacker/prpgmod.c @@ -408,8 +408,7 @@ INT_PTR CALLBACK PhpProcessModulesDlgProc( PPH_MODULES_CONTEXT modulesContext; HWND tnHandle; - if (PhpPropPageDlgProcHeader(hwndDlg, uMsg, lParam, - &propSheetPage, &propPageContext, &processItem)) + if (PhPropPageDlgProcHeader(hwndDlg, uMsg, lParam, &propSheetPage, &propPageContext, &processItem)) { modulesContext = (PPH_MODULES_CONTEXT)propPageContext->Context; @@ -425,10 +424,8 @@ INT_PTR CALLBACK PhpProcessModulesDlgProc( { case WM_INITDIALOG: { - // Lots of boilerplate code... - - modulesContext = propPageContext->Context = - PhAllocate(PhEmGetObjectSize(EmModulesContextType, sizeof(PH_MODULES_CONTEXT))); + modulesContext = propPageContext->Context = PhAllocate(PhEmGetObjectSize(EmModulesContextType, sizeof(PH_MODULES_CONTEXT))); + memset(modulesContext, 0, sizeof(PH_MODULES_CONTEXT)); modulesContext->Provider = PhCreateModuleProvider( processItem->ProcessId @@ -537,23 +534,17 @@ INT_PTR CALLBACK PhpProcessModulesDlgProc( PhClearReference(&modulesContext->ErrorMessage); PhFree(modulesContext); - - PhpPropPageDlgProcDestroy(hwndDlg); } break; case WM_SHOWWINDOW: { - if (!propPageContext->LayoutInitialized) - { - PPH_LAYOUT_ITEM dialogItem; + PPH_LAYOUT_ITEM dialogItem; - dialogItem = PhAddPropPageLayoutItem(hwndDlg, hwndDlg, PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL); + if (dialogItem = PhBeginPropPageLayout(hwndDlg, propPageContext)) + { PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_SEARCH), dialogItem, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); PhAddPropPageLayoutItem(hwndDlg, modulesContext->ListContext.TreeNewHandle, dialogItem, PH_ANCHOR_ALL); - - PhDoPropPageLayout(hwndDlg); - - propPageContext->LayoutInitialized = TRUE; + PhEndPropPageLayout(hwndDlg, propPageContext); } } break; diff --git a/ProcessHacker/prpgperf.c b/ProcessHacker/prpgperf.c index ea689c1806db..ad3fb7760088 100644 --- a/ProcessHacker/prpgperf.c +++ b/ProcessHacker/prpgperf.c @@ -55,8 +55,7 @@ INT_PTR CALLBACK PhpProcessPerformanceDlgProc( PPH_PROCESS_ITEM processItem; PPH_PERFORMANCE_CONTEXT performanceContext; - if (PhpPropPageDlgProcHeader(hwndDlg, uMsg, lParam, - &propSheetPage, &propPageContext, &processItem)) + if (PhPropPageDlgProcHeader(hwndDlg, uMsg, lParam, &propSheetPage, &propPageContext, &processItem)) { performanceContext = (PPH_PERFORMANCE_CONTEXT)propPageContext->Context; } @@ -69,8 +68,8 @@ INT_PTR CALLBACK PhpProcessPerformanceDlgProc( { case WM_INITDIALOG: { - performanceContext = propPageContext->Context = - PhAllocate(sizeof(PH_PERFORMANCE_CONTEXT)); + performanceContext = propPageContext->Context = PhAllocate(sizeof(PH_PERFORMANCE_CONTEXT)); + memset(performanceContext, 0, sizeof(PH_PERFORMANCE_CONTEXT)); performanceContext->WindowHandle = hwndDlg; @@ -120,22 +119,15 @@ INT_PTR CALLBACK PhpProcessPerformanceDlgProc( &performanceContext->ProcessesUpdatedRegistration ); PhFree(performanceContext); - - PhpPropPageDlgProcDestroy(hwndDlg); } break; case WM_SHOWWINDOW: { - if (!propPageContext->LayoutInitialized) - { - PPH_LAYOUT_ITEM dialogItem; - - dialogItem = PhAddPropPageLayoutItem(hwndDlg, hwndDlg, - PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL); + PPH_LAYOUT_ITEM dialogItem; - PhDoPropPageLayout(hwndDlg); - - propPageContext->LayoutInitialized = TRUE; + if (dialogItem = PhBeginPropPageLayout(hwndDlg, propPageContext)) + { + PhEndPropPageLayout(hwndDlg, propPageContext); } } break; diff --git a/ProcessHacker/prpgsrv.c b/ProcessHacker/prpgsrv.c index cfac35ff7a17..e62e6c3d548c 100644 --- a/ProcessHacker/prpgsrv.c +++ b/ProcessHacker/prpgsrv.c @@ -53,15 +53,11 @@ INT_PTR CALLBACK PhpProcessServicesDlgProc( _In_ LPARAM lParam ) { - LPPROPSHEETPAGE propSheetPage; PPH_PROCESS_PROPPAGECONTEXT propPageContext; PPH_PROCESS_ITEM processItem; - if (!PhpPropPageDlgProcHeader(hwndDlg, uMsg, lParam, - &propSheetPage, &propPageContext, &processItem)) - { + if (!PhPropPageDlgProcHeader(hwndDlg, uMsg, lParam, NULL, &propPageContext, &processItem)) return FALSE; - } switch (uMsg) { @@ -107,26 +103,16 @@ INT_PTR CALLBACK PhpProcessServicesDlgProc( PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport); } break; - case WM_DESTROY: - { - PhpPropPageDlgProcDestroy(hwndDlg); - } - break; case WM_SHOWWINDOW: { - if (!propPageContext->LayoutInitialized) - { - PPH_LAYOUT_ITEM dialogItem; + PPH_LAYOUT_ITEM dialogItem; - dialogItem = PhAddPropPageLayoutItem(hwndDlg, hwndDlg, - PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL); - PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_SERVICES_LAYOUT), - dialogItem, PH_ANCHOR_ALL); + if (dialogItem = PhBeginPropPageLayout(hwndDlg, propPageContext)) + { + PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_SERVICES_LAYOUT), dialogItem, PH_ANCHOR_ALL); + PhEndPropPageLayout(hwndDlg, propPageContext); - PhDoPropPageLayout(hwndDlg); PhpLayoutServiceListControl(hwndDlg, (HWND)propPageContext->Context); - - propPageContext->LayoutInitialized = TRUE; } } break; diff --git a/ProcessHacker/prpgstat.c b/ProcessHacker/prpgstat.c index 215e139570fc..6bfb23260910 100644 --- a/ProcessHacker/prpgstat.c +++ b/ProcessHacker/prpgstat.c @@ -342,22 +342,17 @@ INT_PTR CALLBACK PhpProcessStatisticsDlgProc( if (statisticsContext->ProcessHandle) NtClose(statisticsContext->ProcessHandle); - PhpPropPageDlgProcDestroy(hwndDlg); PhFree(statisticsContext); } break; case WM_SHOWWINDOW: { - if (!propPageContext->LayoutInitialized) - { - PPH_LAYOUT_ITEM dialogItem; + PPH_LAYOUT_ITEM dialogItem; - dialogItem = PhAddPropPageLayoutItem(hwndDlg, hwndDlg, PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL); + if (dialogItem = PhBeginPropPageLayout(hwndDlg, propPageContext)) + { PhAddPropPageLayoutItem(hwndDlg, statisticsContext->ListViewHandle, dialogItem, PH_ANCHOR_ALL); - - PhDoPropPageLayout(hwndDlg); - - propPageContext->LayoutInitialized = TRUE; + PhEndPropPageLayout(hwndDlg, propPageContext); } ExtendedListView_SetColumnWidth(statisticsContext->ListViewHandle, 0, ELVSCW_AUTOSIZE_REMAININGSPACE); diff --git a/ProcessHacker/prpgthrd.c b/ProcessHacker/prpgthrd.c index 82352767a5ca..68eb971ab1d1 100644 --- a/ProcessHacker/prpgthrd.c +++ b/ProcessHacker/prpgthrd.c @@ -657,20 +657,15 @@ INT_PTR CALLBACK PhpProcessThreadsDlgProc( PhDeleteThreadList(&threadsContext->ListContext); PhFree(threadsContext); - - PhpPropPageDlgProcDestroy(hwndDlg); } break; case WM_SHOWWINDOW: { - if (!propPageContext->LayoutInitialized) - { - PPH_LAYOUT_ITEM dialogItem; + PPH_LAYOUT_ITEM dialogItem; - dialogItem = PhAddPropPageLayoutItem(hwndDlg, hwndDlg, - PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL); - PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_LIST), - dialogItem, PH_ANCHOR_ALL); + if (dialogItem = PhBeginPropPageLayout(hwndDlg, propPageContext)) + { + PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_LIST), dialogItem, PH_ANCHOR_ALL); #define ADD_BL_ITEM(Id) \ PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, Id), dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_BOTTOM) @@ -686,10 +681,8 @@ INT_PTR CALLBACK PhpProcessThreadsDlgProc( ADD_BL_ITEM(IDC_STATICBL12); } - PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_STARTMODULE), - dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); - PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_OPENSTARTMODULE), - dialogItem, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); + PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_STARTMODULE), dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); + PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_OPENSTARTMODULE), dialogItem, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); ADD_BL_ITEM(IDC_STARTED); ADD_BL_ITEM(IDC_KERNELTIME); ADD_BL_ITEM(IDC_USERTIME); @@ -702,9 +695,7 @@ INT_PTR CALLBACK PhpProcessThreadsDlgProc( ADD_BL_ITEM(IDC_PAGEPRIORITY); ADD_BL_ITEM(IDC_IDEALPROCESSOR); - PhDoPropPageLayout(hwndDlg); - - propPageContext->LayoutInitialized = TRUE; + PhEndPropPageLayout(hwndDlg, propPageContext); } } break; diff --git a/ProcessHacker/prpgwmi.c b/ProcessHacker/prpgwmi.c index 5566c294eaaa..60613650a053 100644 --- a/ProcessHacker/prpgwmi.c +++ b/ProcessHacker/prpgwmi.c @@ -566,7 +566,7 @@ INT_PTR CALLBACK PhpProcessWmiProvidersDlgProc( PPH_PROCESS_ITEM processItem; PPH_WMI_CONTEXT context; - if (PhpPropPageDlgProcHeader(hwndDlg, uMsg, lParam, &propSheetPage, &propPageContext, &processItem)) + if (PhPropPageDlgProcHeader(hwndDlg, uMsg, lParam, &propSheetPage, &propPageContext, &processItem)) { context = (PPH_WMI_CONTEXT)propPageContext->Context; } @@ -618,22 +618,16 @@ INT_PTR CALLBACK PhpProcessWmiProvidersDlgProc( PhDereferenceObject(context->WmiProviderList); PhFree(context); - - PhpPropPageDlgProcDestroy(hwndDlg); } break; case WM_SHOWWINDOW: { - if (!propPageContext->LayoutInitialized) - { - PPH_LAYOUT_ITEM dialogItem; + PPH_LAYOUT_ITEM dialogItem; - dialogItem = PhAddPropPageLayoutItem(hwndDlg, hwndDlg, PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL); + if (dialogItem = PhBeginPropPageLayout(hwndDlg, propPageContext)) + { PhAddPropPageLayoutItem(hwndDlg, context->ListViewHandle, dialogItem, PH_ANCHOR_ALL); - - PhDoPropPageLayout(hwndDlg); - - propPageContext->LayoutInitialized = TRUE; + PhEndPropPageLayout(hwndDlg, propPageContext); } } break; diff --git a/plugins/DotNetTools/asmpage.c b/plugins/DotNetTools/asmpage.c index 013c40b6756e..2b6af0ec28f9 100644 --- a/plugins/DotNetTools/asmpage.c +++ b/plugins/DotNetTools/asmpage.c @@ -1273,8 +1273,6 @@ INT_PTR CALLBACK DotNetAsmPageDlgProc( PhClearReference(&context->TnErrorMessage); PhFree(context); - - PhPropPageDlgProcDestroy(hwndDlg); } break; case WM_SHOWWINDOW: diff --git a/plugins/DotNetTools/perfpage.c b/plugins/DotNetTools/perfpage.c index d60689fad10f..3e386461a489 100644 --- a/plugins/DotNetTools/perfpage.c +++ b/plugins/DotNetTools/perfpage.c @@ -858,7 +858,6 @@ INT_PTR CALLBACK DotNetPerfPageDlgProc( PhSaveListViewColumnsToSetting(SETTING_NAME_DOT_NET_COUNTERS_COLUMNS, context->CountersLv); PhFree(context); - PhPropPageDlgProcDestroy(hwndDlg); } break; case WM_SHOWWINDOW: diff --git a/plugins/DotNetTools/svcext.c b/plugins/DotNetTools/svcext.c index 1acf9566e8c9..0a0f2fb13bf4 100644 --- a/plugins/DotNetTools/svcext.c +++ b/plugins/DotNetTools/svcext.c @@ -82,7 +82,7 @@ NTSTATUS DispatchGetRuntimeNameByAddress( _Out_ PDN_API_GETRUNTIMENAMEBYADDRESS Out ) { - NTSTATUS status = STATUS_SUCCESS; + NTSTATUS status; PVOID nameBuffer; PCLR_PROCESS_SUPPORT support; PPH_STRING name; diff --git a/plugins/ExtendedTools/etwprprp.c b/plugins/ExtendedTools/etwprprp.c index ffe4f3f12d0b..efde863af805 100644 --- a/plugins/ExtendedTools/etwprprp.c +++ b/plugins/ExtendedTools/etwprprp.c @@ -360,8 +360,6 @@ INT_PTR CALLBACK EtwDiskNetworkPageDlgProc( PhUnregisterCallback(PhGetGeneralCallback(GeneralCallbackProcessProviderUpdatedEvent), &context->ProcessesUpdatedRegistration); PhFree(context); - - PhPropPageDlgProcDestroy(hwndDlg); } break; case WM_SHOWWINDOW: @@ -618,4 +616,4 @@ VOID EtProcessEtwPropertiesInitializing( PhCreateProcessPropPageContextEx(PluginInstance->DllBase, MAKEINTRESOURCE(IDD_PROCDISKNET), EtwDiskNetworkPageDlgProc, NULL) ); } -} \ No newline at end of file +} diff --git a/plugins/ExtendedTools/gpuprprp.c b/plugins/ExtendedTools/gpuprprp.c index 4b4f8b5e1e1c..bf3c30fd3bc3 100644 --- a/plugins/ExtendedTools/gpuprprp.c +++ b/plugins/ExtendedTools/gpuprprp.c @@ -563,8 +563,6 @@ INT_PTR CALLBACK EtpGpuPageDlgProc( PhUnregisterCallback(PhGetGeneralCallback(GeneralCallbackProcessProviderUpdatedEvent), &context->ProcessesUpdatedRegistration); PhFree(context); - - PhPropPageDlgProcDestroy(hwndDlg); } break; case WM_SHOWWINDOW: @@ -896,4 +894,4 @@ VOID EtProcessGpuPropertiesInitializing( PhCreateProcessPropPageContextEx(PluginInstance->DllBase, MAKEINTRESOURCE(IDD_PROCGPU), EtpGpuPageDlgProc, NULL) ); } -} \ No newline at end of file +} diff --git a/plugins/UserNotes/main.c b/plugins/UserNotes/main.c index 72cd99506a4b..5deffe4ab3c4 100644 --- a/plugins/UserNotes/main.c +++ b/plugins/UserNotes/main.c @@ -1760,8 +1760,6 @@ INT_PTR CALLBACK ProcessCommentPageDlgProc( PhDereferenceObject(context->OriginalComment); PhFree(context); - PhPropPageDlgProcDestroy(hwndDlg); - SaveDb(); InvalidateProcessComments(); } @@ -1967,4 +1965,4 @@ UINT_PTR CALLBACK ColorDlgHookProc( } return FALSE; -} \ No newline at end of file +} diff --git a/plugins/WindowExplorer/wnddlg.c b/plugins/WindowExplorer/wnddlg.c index 784332a1ac81..4b7744f88588 100644 --- a/plugins/WindowExplorer/wnddlg.c +++ b/plugins/WindowExplorer/wnddlg.c @@ -787,11 +787,10 @@ INT_PTR CALLBACK WepWindowsPageProc( ) { PWINDOWS_CONTEXT context; - LPPROPSHEETPAGE propSheetPage; PPH_PROCESS_PROPPAGECONTEXT propPageContext; PPH_PROCESS_ITEM processItem; - if (PhPropPageDlgProcHeader(hwndDlg, uMsg, lParam, &propSheetPage, &propPageContext, &processItem)) + if (PhPropPageDlgProcHeader(hwndDlg, uMsg, lParam, NULL, &propPageContext, &processItem)) { context = propPageContext->Context; } From bd91255e1f0fdbf49a74d955e95b6b552527ebcf Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 7 Aug 2018 10:25:01 +1000 Subject: [PATCH 1265/2058] Remove unused code --- ProcessHacker/main.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/ProcessHacker/main.c b/ProcessHacker/main.c index 88697f765a63..64eb11d1cec3 100644 --- a/ProcessHacker/main.c +++ b/ProcessHacker/main.c @@ -182,7 +182,6 @@ INT WINAPI wWinMain( if (PhStartupParameters.ShowOptions) { - // Elevated options dialog for changing the value of Replace Task Manager with Process Hacker. PhShowOptionsDialog(PhStartupParameters.WindowHandle); RtlExitUserProcess(STATUS_SUCCESS); } @@ -427,20 +426,17 @@ static BOOLEAN NTAPI PhpPreviousInstancesCallback( HWND hwnd; HANDLE processHandle = NULL; HANDLE tokenHandle = NULL; - PTOKEN_USER tokenCurrent = NULL; PTOKEN_USER tokenUser = NULL; if (objectInfo.ClientId.UniqueProcess == NtCurrentProcessId()) goto CleanupExit; - if (!NT_SUCCESS(PhOpenProcess(&processHandle, ProcessQueryAccess, objectInfo.ClientId.UniqueProcess))) + if (!NT_SUCCESS(PhOpenProcess(&processHandle, PROCESS_QUERY_LIMITED_INFORMATION, objectInfo.ClientId.UniqueProcess))) goto CleanupExit; if (!NT_SUCCESS(PhOpenProcessToken(processHandle, TOKEN_QUERY, &tokenHandle))) goto CleanupExit; if (!NT_SUCCESS(PhGetTokenUser(tokenHandle, &tokenUser))) goto CleanupExit; - if (!NT_SUCCESS(PhGetTokenUser(PhGetOwnTokenAttributes().TokenHandle, &tokenCurrent))) - goto CleanupExit; - if (!RtlEqualSid(tokenUser->User.Sid, tokenCurrent->User.Sid)) + if (!RtlEqualSid(tokenUser->User.Sid, PhGetOwnTokenAttributes().TokenSid)) goto CleanupExit; hwnd = PhGetProcessMainWindowEx( @@ -464,7 +460,6 @@ static BOOLEAN NTAPI PhpPreviousInstancesCallback( CleanupExit: if (tokenUser) PhFree(tokenUser); - if (tokenCurrent) PhFree(tokenCurrent); if (tokenHandle) NtClose(tokenHandle); if (processHandle) NtClose(processHandle); } From 9a7b141953c7837e272d79f7fb0e8044c8a47f02 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 7 Aug 2018 18:17:19 +1000 Subject: [PATCH 1266/2058] Fix classic theme regression --- phlib/theme.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/phlib/theme.c b/phlib/theme.c index df7a1a9c9314..5d590f9ae624 100644 --- a/phlib/theme.c +++ b/phlib/theme.c @@ -91,6 +91,7 @@ LRESULT CALLBACK PhpThemeWindowStatusbarWndSubclassProc( ); ULONG PhpThemeColorMode = 0; +BOOLEAN PhpThemeEnable = FALSE; BOOLEAN PhpThemeBorderEnable = TRUE; HBRUSH PhMenuBackgroundBrush = NULL; COLORREF PhpThemeWindowForegroundColor = RGB(28, 28, 28); @@ -110,6 +111,7 @@ VOID PhInitializeWindowTheme( ) { PhpThemeColorMode = PhGetIntegerSetting(L"GraphColorMode"); + PhpThemeEnable = !!PhGetIntegerSetting(L"EnableThemeSupport"); PhpThemeBorderEnable = !!PhGetIntegerSetting(L"TreeListBorderEnable"); if (!PhMenuBackgroundBrush) // HACK @@ -154,6 +156,9 @@ VOID PhReInitializeWindowTheme( { HWND currentWindow = NULL; + if (!PhpThemeEnable) + return; + // HACK { if (PhMenuBackgroundBrush) From df1f8f036db115a57fba05c89697c82c5f63aa36 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 8 Aug 2018 22:20:17 +1000 Subject: [PATCH 1267/2058] Fix process environment highlighting regression --- ProcessHacker/prpgenv.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ProcessHacker/prpgenv.c b/ProcessHacker/prpgenv.c index 76c33c1e19a6..5478525a1694 100644 --- a/ProcessHacker/prpgenv.c +++ b/ProcessHacker/prpgenv.c @@ -712,6 +712,7 @@ VOID PhpDestroyEnvironmentNode( PPHP_PROCESS_ENVIRONMENT_TREENODE PhpAddEnvironmentRootNode( _In_ PPH_ENVIRONMENT_CONTEXT Context, + _In_ PROCESS_ENVIRONMENT_TREENODE_TYPE Type, _In_ PPH_STRING KeyPath, _In_opt_ PPH_STRING Value ) @@ -727,6 +728,7 @@ PPHP_PROCESS_ENVIRONMENT_TREENODE PhpAddEnvironmentRootNode( node->Children = PhCreateList(1); PhReferenceObject(KeyPath); + node->Type = Type; node->NameText = KeyPath; if (Value) @@ -755,7 +757,7 @@ PPHP_PROCESS_ENVIRONMENT_TREENODE PhpAddEnvironmentChildNode( { PPHP_PROCESS_ENVIRONMENT_TREENODE node; - node = PhpAddEnvironmentRootNode(Context, Name, Value); + node = PhpAddEnvironmentRootNode(Context, Type, Name, Value); if (ParentNode) { From 79eed5b0ff28dcc40af8bce8760dc848f2bbde53 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 8 Aug 2018 22:25:05 +1000 Subject: [PATCH 1268/2058] Fix process environment menu --- ProcessHacker/prpgenv.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ProcessHacker/prpgenv.c b/ProcessHacker/prpgenv.c index 5478525a1694..f6141f954580 100644 --- a/ProcessHacker/prpgenv.c +++ b/ProcessHacker/prpgenv.c @@ -488,7 +488,7 @@ VOID PhpShowEnvironmentNodeContextMenu( { case ENVIRONMENT_TREE_COLUMN_MENU_ITEM_EDIT: { - PPH_ENVIRONMENT_ITEM item = PhItemArray(&Context->Items, node->Id); + //PPH_ENVIRONMENT_ITEM item = PhItemArray(&Context->Items, node->Id); BOOLEAN refresh; if (PhGetIntegerSetting(L"EnableWarnings") && !PhShowConfirmMessage( @@ -505,8 +505,8 @@ VOID PhpShowEnvironmentNodeContextMenu( if (PhpShowEditEnvDialog( Context->WindowHandle, Context->ProcessItem, - item->Name->Buffer, - item->Value->Buffer, + node->NameText->Buffer, + node->ValueText->Buffer, &refresh ) == IDOK && refresh) { @@ -516,7 +516,7 @@ VOID PhpShowEnvironmentNodeContextMenu( break; case ENVIRONMENT_TREE_COLUMN_MENU_ITEM_DELETE: { - PPH_ENVIRONMENT_ITEM item = PhItemArray(&Context->Items, node->Id); + //PPH_ENVIRONMENT_ITEM item = PhItemArray(&Context->Items, node->Id); NTSTATUS status; HANDLE processHandle; @@ -543,7 +543,7 @@ VOID PhpShowEnvironmentNodeContextMenu( timeout.QuadPart = -(LONGLONG)UInt32x32To64(10, PH_TIMEOUT_SEC); status = PhSetEnvironmentVariableRemote( processHandle, - &item->Name->sr, + &node->NameText->sr, NULL, &timeout ); From f0183434da2dab50b49d7f3c4081d3ab1da039a3 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 8 Aug 2018 22:33:54 +1000 Subject: [PATCH 1269/2058] Tidy up PhSetEnvironmentVariableRemote --- phlib/native.c | 33 ++++++++++++++++++++------------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/phlib/native.c b/phlib/native.c index a3ffe304ddca..5a694d11d318 100644 --- a/phlib/native.c +++ b/phlib/native.c @@ -1605,7 +1605,6 @@ NTSTATUS PhUnloadDllProcess( return status; } -// Contributed by dmex /** * Sets an environment variable in a process. * @@ -1649,20 +1648,20 @@ NTSTATUS PhSetEnvironmentVariableRemote( if (isWow64) { - PH_STRINGREF systemRoot; + PH_STRINGREF systemRootSr; - PhGetSystemRoot(&systemRoot); - ntdllFileName = PhConcatStringRefZ(&systemRoot, L"\\SysWow64\\ntdll.dll"); - kernel32FileName = PhConcatStringRefZ(&systemRoot, L"\\SysWow64\\kernel32.dll"); + PhGetSystemRoot(&systemRootSr); + ntdllFileName = PhConcatStringRefZ(&systemRootSr, L"\\SysWow64\\ntdll.dll"); + kernel32FileName = PhConcatStringRefZ(&systemRootSr, L"\\SysWow64\\kernel32.dll"); } else { #endif - PH_STRINGREF systemRoot; + PH_STRINGREF systemRootSr; - PhGetSystemRoot(&systemRoot); - ntdllFileName = PhConcatStringRefZ(&systemRoot, L"\\System32\\ntdll.dll"); - kernel32FileName = PhConcatStringRefZ(&systemRoot, L"\\System32\\kernel32.dll"); + PhGetSystemRoot(&systemRootSr); + ntdllFileName = PhConcatStringRefZ(&systemRootSr, L"\\System32\\ntdll.dll"); + kernel32FileName = PhConcatStringRefZ(&systemRootSr, L"\\System32\\kernel32.dll"); #ifdef _WIN64 } #endif @@ -1689,6 +1688,7 @@ NTSTATUS PhSetEnvironmentVariableRemote( { goto CleanupExit; } + if (!NT_SUCCESS(status = NtAllocateVirtualMemory( ProcessHandle, &nameBaseAddress, @@ -1755,8 +1755,6 @@ NTSTATUS PhSetEnvironmentVariableRemote( #ifdef _WIN64 if (isWow64) { - // NtQueueApcThread doesn't work for WOW64 processes - we need to use RtlQueueApcWow64Thread - // instead. if (!NT_SUCCESS(status = RtlQueueApcWow64Thread( threadHandle, setEnvironmentVariableW, @@ -1786,13 +1784,20 @@ NTSTATUS PhSetEnvironmentVariableRemote( } #endif - // This causes our APC to be executed. - NtResumeThread(threadHandle, NULL); + status = NtAlertResumeThread(threadHandle, NULL); + + if (!NT_SUCCESS(status)) + goto CleanupExit; + status = NtWaitForSingleObject(threadHandle, FALSE, Timeout); CleanupExit: + if (threadHandle) + { NtClose(threadHandle); + } + if (nameBaseAddress) { nameAllocationSize = 0; @@ -1803,6 +1808,7 @@ NTSTATUS PhSetEnvironmentVariableRemote( MEM_RELEASE ); } + if (valueBaseAddress) { valueAllocationSize = 0; @@ -1813,6 +1819,7 @@ NTSTATUS PhSetEnvironmentVariableRemote( MEM_RELEASE ); } + PhClearReference(&ntdllFileName); PhClearReference(&kernel32FileName); From 983c407cdf79ce0387a5e9ce130714e870475a42 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 8 Aug 2018 22:34:48 +1000 Subject: [PATCH 1270/2058] Fix typo --- ProcessHacker/findobj.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/ProcessHacker/findobj.c b/ProcessHacker/findobj.c index fd1490fc4664..294b71ef0114 100644 --- a/ProcessHacker/findobj.c +++ b/ProcessHacker/findobj.c @@ -107,7 +107,7 @@ typedef enum _PH_HANDLE_OBJECT_TREE_COLUMN_ITEM_NAME PH_OBJECT_SEARCH_TREE_COLUMN_HANDLE, PH_OBJECT_SEARCH_TREE_COLUMN_OBJECTADDRESS, PH_OBJECT_SEARCH_TREE_COLUMN_ORIGINALNAME, - TREE_COLUMN_ITEM_MAXIMUM + PH_OBJECT_SEARCH_TREE_COLUMN_MAXIMUM } PH_HANDLE_OBJECT_TREE_COLUMN_ITEM_NAME; typedef struct _PH_HANDLE_OBJECT_TREE_ROOT_NODE @@ -127,7 +127,7 @@ typedef struct _PH_HANDLE_OBJECT_TREE_ROOT_NODE SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX HandleInfo; - PH_STRINGREF TextCache[TREE_COLUMN_ITEM_MAXIMUM]; + PH_STRINGREF TextCache[PH_OBJECT_SEARCH_TREE_COLUMN_MAXIMUM]; } PH_HANDLE_OBJECT_TREE_ROOT_NODE, *PPH_HANDLE_OBJECT_TREE_ROOT_NODE; #define SORT_FUNCTION(Column) HandleObjectTreeNewCompare##Column @@ -248,9 +248,9 @@ PPH_HANDLE_OBJECT_TREE_ROOT_NODE AddHandleObjectNode( PhInitializeTreeNewNode(&handleObjectNode->Node); - memset(handleObjectNode->TextCache, 0, sizeof(PH_STRINGREF) * TREE_COLUMN_ITEM_MAXIMUM); + memset(handleObjectNode->TextCache, 0, sizeof(PH_STRINGREF) * PH_OBJECT_SEARCH_TREE_COLUMN_MAXIMUM); handleObjectNode->Node.TextCache = handleObjectNode->TextCache; - handleObjectNode->Node.TextCacheSize = TREE_COLUMN_ITEM_MAXIMUM; + handleObjectNode->Node.TextCacheSize = PH_OBJECT_SEARCH_TREE_COLUMN_MAXIMUM; handleObjectNode->Handle = Handle; @@ -307,7 +307,7 @@ VOID UpdateHandleObjectNode( _In_ PPH_HANDLE_OBJECT_TREE_ROOT_NODE Node ) { - memset(Node->TextCache, 0, sizeof(PH_STRINGREF) * TREE_COLUMN_ITEM_MAXIMUM); + memset(Node->TextCache, 0, sizeof(PH_STRINGREF) * PH_OBJECT_SEARCH_TREE_COLUMN_MAXIMUM); PhInvalidateTreeNewNode(&Node->Node, TN_CACHE_COLOR); TreeNew_NodesStructured(Context->TreeNewHandle); @@ -344,7 +344,7 @@ BOOLEAN NTAPI HandleObjectTreeNewCallback( }; int (__cdecl *sortFunction)(void *, const void *, const void *); - if (context->TreeNewSortColumn < TREE_COLUMN_ITEM_MAXIMUM) + if (context->TreeNewSortColumn < PH_OBJECT_SEARCH_TREE_COLUMN_MAXIMUM) sortFunction = sortFunctions[context->TreeNewSortColumn]; else sortFunction = NULL; From 7090590a5d355c1497c633114e4212619c035472 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 8 Aug 2018 22:36:22 +1000 Subject: [PATCH 1271/2058] Remove unused code --- ProcessHacker/include/phapp.h | 1 - ProcessHacker/prpgstat.c | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ProcessHacker/include/phapp.h b/ProcessHacker/include/phapp.h index a067dd739c59..431098df41f8 100644 --- a/ProcessHacker/include/phapp.h +++ b/ProcessHacker/include/phapp.h @@ -203,7 +203,6 @@ typedef struct _PH_LOG_ENTRY } PH_LOG_ENTRY, *PPH_LOG_ENTRY; extern PH_CIRCULAR_BUFFER_PVOID PhLogBuffer; -PHAPPAPI extern PH_CALLBACK PhLoggedCallback; // phapppub VOID PhLogInitialization( VOID diff --git a/ProcessHacker/prpgstat.c b/ProcessHacker/prpgstat.c index 6bfb23260910..13e7bdc12e7f 100644 --- a/ProcessHacker/prpgstat.c +++ b/ProcessHacker/prpgstat.c @@ -282,7 +282,7 @@ INT_PTR CALLBACK PhpProcessStatisticsDlgProc( PPH_PROCESS_ITEM processItem; PPH_STATISTICS_CONTEXT statisticsContext; - if (PhpPropPageDlgProcHeader(hwndDlg, uMsg, lParam, &propSheetPage, &propPageContext, &processItem)) + if (PhPropPageDlgProcHeader(hwndDlg, uMsg, lParam, &propSheetPage, &propPageContext, &processItem)) { statisticsContext = (PPH_STATISTICS_CONTEXT)propPageContext->Context; } @@ -296,6 +296,7 @@ INT_PTR CALLBACK PhpProcessStatisticsDlgProc( case WM_INITDIALOG: { statisticsContext = propPageContext->Context = PhAllocate(sizeof(PH_STATISTICS_CONTEXT)); + memset(statisticsContext, 0, sizeof(PH_STATISTICS_CONTEXT)); statisticsContext->WindowHandle = hwndDlg; statisticsContext->ListViewHandle = GetDlgItem(hwndDlg, IDC_STATISTICS_LIST); From a6f287eb6e3a8cfa25ba58503ebd54e63bd8692e Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 8 Aug 2018 22:52:37 +1000 Subject: [PATCH 1272/2058] Add dynamic type initialization --- ProcessHacker/hndlprv.c | 22 ++++++++++------------ ProcessHacker/include/hndlprv.h | 4 ---- ProcessHacker/include/memprv.h | 4 ---- ProcessHacker/include/modprv.h | 4 ---- ProcessHacker/include/thrdprv.h | 4 ---- ProcessHacker/main.c | 8 -------- ProcessHacker/memprv.c | 18 ++++++++---------- ProcessHacker/modprv.c | 22 ++++++++++------------ ProcessHacker/prpgthrd.c | 17 +++++++---------- ProcessHacker/thrdprv.c | 23 ++++++++++------------- 10 files changed, 45 insertions(+), 81 deletions(-) diff --git a/ProcessHacker/hndlprv.c b/ProcessHacker/hndlprv.c index afb96c5fcdc8..2bf73a250bb5 100644 --- a/ProcessHacker/hndlprv.c +++ b/ProcessHacker/hndlprv.c @@ -47,25 +47,23 @@ VOID NTAPI PhpHandleItemDeleteProcedure( _In_ ULONG Flags ); -PPH_OBJECT_TYPE PhHandleProviderType; -PPH_OBJECT_TYPE PhHandleItemType; - -BOOLEAN PhHandleProviderInitialization( - VOID - ) -{ - PhHandleProviderType = PhCreateObjectType(L"HandleProvider", 0, PhpHandleProviderDeleteProcedure); - PhHandleItemType = PhCreateObjectType(L"HandleItem", 0, PhpHandleItemDeleteProcedure); - - return TRUE; -} +PPH_OBJECT_TYPE PhHandleProviderType = NULL; +PPH_OBJECT_TYPE PhHandleItemType = NULL; PPH_HANDLE_PROVIDER PhCreateHandleProvider( _In_ HANDLE ProcessId ) { + static PH_INITONCE initOnce = PH_INITONCE_INIT; PPH_HANDLE_PROVIDER handleProvider; + if (PhBeginInitOnce(&initOnce)) + { + PhHandleProviderType = PhCreateObjectType(L"HandleProvider", 0, PhpHandleProviderDeleteProcedure); + PhHandleItemType = PhCreateObjectType(L"HandleItem", 0, PhpHandleItemDeleteProcedure); + PhEndInitOnce(&initOnce); + } + handleProvider = PhCreateObject( PhEmGetObjectSize(EmHandleProviderType, sizeof(PH_HANDLE_PROVIDER)), PhHandleProviderType diff --git a/ProcessHacker/include/hndlprv.h b/ProcessHacker/include/hndlprv.h index d2bb0afd9677..05cdb782c18c 100644 --- a/ProcessHacker/include/hndlprv.h +++ b/ProcessHacker/include/hndlprv.h @@ -50,10 +50,6 @@ typedef struct _PH_HANDLE_PROVIDER } PH_HANDLE_PROVIDER, *PPH_HANDLE_PROVIDER; // end_phapppub -BOOLEAN PhHandleProviderInitialization( - VOID - ); - PPH_HANDLE_PROVIDER PhCreateHandleProvider( _In_ HANDLE ProcessId ); diff --git a/ProcessHacker/include/memprv.h b/ProcessHacker/include/memprv.h index 1dc3b161141e..79ecaa694f5b 100644 --- a/ProcessHacker/include/memprv.h +++ b/ProcessHacker/include/memprv.h @@ -98,10 +98,6 @@ typedef struct _PH_MEMORY_ITEM_LIST } PH_MEMORY_ITEM_LIST, *PPH_MEMORY_ITEM_LIST; // end_phapppub -BOOLEAN PhMemoryProviderInitialization( - VOID - ); - VOID PhGetMemoryProtectionString( _In_ ULONG Protection, _Out_writes_(17) PWSTR String diff --git a/ProcessHacker/include/modprv.h b/ProcessHacker/include/modprv.h index bb9efc5146d3..1779bcd827e0 100644 --- a/ProcessHacker/include/modprv.h +++ b/ProcessHacker/include/modprv.h @@ -76,10 +76,6 @@ typedef struct _PH_MODULE_PROVIDER } PH_MODULE_PROVIDER, *PPH_MODULE_PROVIDER; // end_phapppub -BOOLEAN PhModuleProviderInitialization( - VOID - ); - PPH_MODULE_PROVIDER PhCreateModuleProvider( _In_ HANDLE ProcessId ); diff --git a/ProcessHacker/include/thrdprv.h b/ProcessHacker/include/thrdprv.h index 78f7cfc90546..47922f93cb45 100644 --- a/ProcessHacker/include/thrdprv.h +++ b/ProcessHacker/include/thrdprv.h @@ -65,10 +65,6 @@ typedef struct _PH_THREAD_PROVIDER } PH_THREAD_PROVIDER, *PPH_THREAD_PROVIDER; // end_phapppub -BOOLEAN PhThreadProviderInitialization( - VOID - ); - PPH_THREAD_PROVIDER PhCreateThreadProvider( _In_ HANDLE ProcessId ); diff --git a/ProcessHacker/main.c b/ProcessHacker/main.c index 64eb11d1cec3..225bf4a49480 100644 --- a/ProcessHacker/main.c +++ b/ProcessHacker/main.c @@ -847,14 +847,6 @@ BOOLEAN PhInitializeAppSystem( return FALSE; if (!PhNetworkProviderInitialization()) return FALSE; - if (!PhModuleProviderInitialization()) - return FALSE; - if (!PhThreadProviderInitialization()) - return FALSE; - if (!PhHandleProviderInitialization()) - return FALSE; - if (!PhMemoryProviderInitialization()) - return FALSE; PhSetHandleClientIdFunction(PhGetClientIdName); diff --git a/ProcessHacker/memprv.c b/ProcessHacker/memprv.c index 4a04f712de9b..b49267f95291 100644 --- a/ProcessHacker/memprv.c +++ b/ProcessHacker/memprv.c @@ -34,16 +34,7 @@ VOID PhpMemoryItemDeleteProcedure( _In_ ULONG Flags ); -PPH_OBJECT_TYPE PhMemoryItemType; - -BOOLEAN PhMemoryProviderInitialization( - VOID - ) -{ - PhMemoryItemType = PhCreateObjectType(L"MemoryItem", 0, PhpMemoryItemDeleteProcedure); - - return TRUE; -} +PPH_OBJECT_TYPE PhMemoryItemType = NULL; VOID PhGetMemoryProtectionString( _In_ ULONG Protection, @@ -136,8 +127,15 @@ PPH_MEMORY_ITEM PhCreateMemoryItem( VOID ) { + static PH_INITONCE initOnce = PH_INITONCE_INIT; PPH_MEMORY_ITEM memoryItem; + if (PhBeginInitOnce(&initOnce)) + { + PhMemoryItemType = PhCreateObjectType(L"MemoryItem", 0, PhpMemoryItemDeleteProcedure); + PhEndInitOnce(&initOnce); + } + memoryItem = PhCreateObject(sizeof(PH_MEMORY_ITEM), PhMemoryItemType); memset(memoryItem, 0, sizeof(PH_MEMORY_ITEM)); diff --git a/ProcessHacker/modprv.c b/ProcessHacker/modprv.c index 5ab4027a7e76..99e3fba20010 100644 --- a/ProcessHacker/modprv.c +++ b/ProcessHacker/modprv.c @@ -62,27 +62,25 @@ ULONG NTAPI PhpModuleHashtableHashFunction( _In_ PVOID Entry ); -PPH_OBJECT_TYPE PhModuleProviderType; -PPH_OBJECT_TYPE PhModuleItemType; - -BOOLEAN PhModuleProviderInitialization( - VOID - ) -{ - PhModuleProviderType = PhCreateObjectType(L"ModuleProvider", 0, PhpModuleProviderDeleteProcedure); - PhModuleItemType = PhCreateObjectType(L"ModuleItem", 0, PhpModuleItemDeleteProcedure); - - return TRUE; -} +PPH_OBJECT_TYPE PhModuleProviderType = NULL; +PPH_OBJECT_TYPE PhModuleItemType = NULL; PPH_MODULE_PROVIDER PhCreateModuleProvider( _In_ HANDLE ProcessId ) { + static PH_INITONCE initOnce = PH_INITONCE_INIT; NTSTATUS status; PPH_MODULE_PROVIDER moduleProvider; PPH_STRING fileName; + if (PhBeginInitOnce(&initOnce)) + { + PhModuleProviderType = PhCreateObjectType(L"ModuleProvider", 0, PhpModuleProviderDeleteProcedure); + PhModuleItemType = PhCreateObjectType(L"ModuleItem", 0, PhpModuleItemDeleteProcedure); + PhEndInitOnce(&initOnce); + } + moduleProvider = PhCreateObject( PhEmGetObjectSize(EmModuleProviderType, sizeof(PH_MODULE_PROVIDER)), PhModuleProviderType diff --git a/ProcessHacker/prpgthrd.c b/ProcessHacker/prpgthrd.c index 68eb971ab1d1..00f3a3d61d1b 100644 --- a/ProcessHacker/prpgthrd.c +++ b/ProcessHacker/prpgthrd.c @@ -495,8 +495,7 @@ INT_PTR CALLBACK PhpProcessThreadsDlgProc( PPH_THREADS_CONTEXT threadsContext; HWND tnHandle; - if (PhpPropPageDlgProcHeader(hwndDlg, uMsg, lParam, - &propSheetPage, &propPageContext, &processItem)) + if (PhPropPageDlgProcHeader(hwndDlg, uMsg, lParam, &propSheetPage, &propPageContext, &processItem)) { threadsContext = (PPH_THREADS_CONTEXT)propPageContext->Context; @@ -512,8 +511,8 @@ INT_PTR CALLBACK PhpProcessThreadsDlgProc( { case WM_INITDIALOG: { - threadsContext = propPageContext->Context = - PhAllocate(PhEmGetObjectSize(EmThreadsContextType, sizeof(PH_THREADS_CONTEXT))); + threadsContext = propPageContext->Context = PhAllocate(PhEmGetObjectSize(EmThreadsContextType, sizeof(PH_THREADS_CONTEXT))); + memset(threadsContext, 0, sizeof(PH_THREADS_CONTEXT)); // The thread provider has a special registration mechanism. threadsContext->Provider = PhCreateThreadProvider( @@ -701,9 +700,7 @@ INT_PTR CALLBACK PhpProcessThreadsDlgProc( break; case WM_COMMAND: { - INT id = LOWORD(wParam); - - switch (id) + switch (GET_WM_COMMAND_ID(wParam, lParam)) { case ID_SHOWCONTEXTMENU: { @@ -856,7 +853,7 @@ INT_PTR CALLBACK PhpProcessThreadsDlgProc( { ULONG threadPriorityWin32; - switch (id) + switch (GET_WM_COMMAND_ID(wParam, lParam)) { case ID_PRIORITY_TIMECRITICAL: threadPriorityWin32 = THREAD_PRIORITY_TIME_CRITICAL; @@ -898,7 +895,7 @@ INT_PTR CALLBACK PhpProcessThreadsDlgProc( { IO_PRIORITY_HINT ioPriority; - switch (id) + switch (GET_WM_COMMAND_ID(wParam, lParam)) { case ID_IOPRIORITY_VERYLOW: ioPriority = IoPriorityVeryLow; @@ -932,7 +929,7 @@ INT_PTR CALLBACK PhpProcessThreadsDlgProc( { ULONG pagePriority; - switch (id) + switch (GET_WM_COMMAND_ID(wParam, lParam)) { case ID_PAGEPRIORITY_VERYLOW: pagePriority = MEMORY_PRIORITY_VERY_LOW; diff --git a/ProcessHacker/thrdprv.c b/ProcessHacker/thrdprv.c index 9ccbe2587a5a..e54320b6ef53 100644 --- a/ProcessHacker/thrdprv.c +++ b/ProcessHacker/thrdprv.c @@ -89,22 +89,11 @@ VOID PhpThreadProviderUpdate( _In_ PVOID ProcessInformation ); -PPH_OBJECT_TYPE PhThreadProviderType; -PPH_OBJECT_TYPE PhThreadItemType; - +PPH_OBJECT_TYPE PhThreadProviderType = NULL; +PPH_OBJECT_TYPE PhThreadItemType = NULL; PH_WORK_QUEUE PhThreadProviderWorkQueue; PH_INITONCE PhThreadProviderWorkQueueInitOnce = PH_INITONCE_INIT; -BOOLEAN PhThreadProviderInitialization( - VOID - ) -{ - PhThreadProviderType = PhCreateObjectType(L"ThreadProvider", 0, PhpThreadProviderDeleteProcedure); - PhThreadItemType = PhCreateObjectType(L"ThreadItem", 0, PhpThreadItemDeleteProcedure); - - return TRUE; -} - VOID PhpQueueThreadWorkQueueItem( _In_ PTHREAD_START_ROUTINE Function, _In_opt_ PVOID Context @@ -123,8 +112,16 @@ PPH_THREAD_PROVIDER PhCreateThreadProvider( _In_ HANDLE ProcessId ) { + static PH_INITONCE initOnce = PH_INITONCE_INIT; PPH_THREAD_PROVIDER threadProvider; + if (PhBeginInitOnce(&initOnce)) + { + PhThreadProviderType = PhCreateObjectType(L"ThreadProvider", 0, PhpThreadProviderDeleteProcedure); + PhThreadItemType = PhCreateObjectType(L"ThreadItem", 0, PhpThreadItemDeleteProcedure); + PhEndInitOnce(&initOnce); + } + threadProvider = PhCreateObject( PhEmGetObjectSize(EmThreadProviderType, sizeof(PH_THREAD_PROVIDER)), PhThreadProviderType From 9c2cc5ffc6079a173417dd62fb0be401b8bb4030 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 8 Aug 2018 23:32:14 +1000 Subject: [PATCH 1273/2058] Update process thread tab layout --- ProcessHacker/ProcessHacker.rc | 27 +-- ProcessHacker/include/thrdlist.h | 44 +++-- ProcessHacker/thrdlist.c | 294 ++++++++++++++++++++++++------- 3 files changed, 261 insertions(+), 104 deletions(-) diff --git a/ProcessHacker/ProcessHacker.rc b/ProcessHacker/ProcessHacker.rc index f8219db5ea13..581433dd68b5 100644 --- a/ProcessHacker/ProcessHacker.rc +++ b/ProcessHacker/ProcessHacker.rc @@ -533,32 +533,7 @@ STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSM CAPTION "Threads" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN - LTEXT "Start module:",IDC_STATICBL1,7,170,44,8 - EDITTEXT IDC_STARTMODULE,55,168,177,12,ES_AUTOHSCROLL | ES_READONLY - PUSHBUTTON "Open",IDC_OPENSTARTMODULE,236,166,17,15,BS_ICON | WS_DISABLED - LTEXT "Started:",IDC_STATICBL2,7,184,28,8 - LTEXT "N/A",IDC_STARTED,75,184,178,8 - LTEXT "Kernel time:",IDC_STATICBL3,7,207,40,8 - LTEXT "N/A",IDC_KERNELTIME,75,207,51,8 - LTEXT "User time:",IDC_STATICBL4,7,217,35,8 - LTEXT "N/A",IDC_USERTIME,75,217,51,8 - LTEXT "Context switches:",IDC_STATICBL5,7,228,60,8 - LTEXT "N/A",IDC_CONTEXTSWITCHES,75,228,51,8,SS_ENDELLIPSIS - LTEXT "Cycles:",IDC_STATICBL6,7,239,24,8 - LTEXT "N/A",IDC_CYCLES,41,239,85,8,SS_ENDELLIPSIS - LTEXT "Base priority:",IDC_STATICBL9,136,205,44,8 - LTEXT "Priority:",IDC_STATICBL8,136,195,26,8 - LTEXT "I/O priority:",IDC_STATICBL10,136,216,39,8 - LTEXT "Page priority:",IDC_STATICBL11,136,227,44,8 - LTEXT "State:",IDC_STATICBL7,7,195,21,8 - LTEXT "N/A",IDC_STATE,41,195,85,8,SS_ENDELLIPSIS - LTEXT "N/A",IDC_PRIORITY,195,195,58,8 - LTEXT "N/A",IDC_BASEPRIORITY,195,205,58,8 - LTEXT "N/A",IDC_IOPRIORITY,195,216,58,8 - LTEXT "N/A",IDC_PAGEPRIORITY,195,227,58,8 - CONTROL "",IDC_LIST,"PhTreeNew",WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP | 0x22,7,7,246,156,WS_EX_CLIENTEDGE - LTEXT "Ideal processor:",IDC_STATICBL12,136,239,53,8 - LTEXT "N/A",IDC_IDEALPROCESSOR,195,239,58,8 + CONTROL "",IDC_LIST,"PhTreeNew",WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP | 0xa,2,2,256,256,WS_EX_CLIENTEDGE END IDD_PROCHANDLES DIALOGEX 0, 0, 260, 260 diff --git a/ProcessHacker/include/thrdlist.h b/ProcessHacker/include/thrdlist.h index 51dceb55a7db..caeff90cf45c 100644 --- a/ProcessHacker/include/thrdlist.h +++ b/ProcessHacker/include/thrdlist.h @@ -6,15 +6,29 @@ // Columns -#define PHTHTLC_TID 0 -#define PHTHTLC_CPU 1 -#define PHTHTLC_CYCLESDELTA 2 -#define PHTHTLC_STARTADDRESS 3 -#define PHTHTLC_PRIORITY 4 -#define PHTHTLC_SERVICE 5 -#define PHTHTLC_NAME 6 - -#define PHTHTLC_MAXIMUM 7 +typedef enum _PH_THREAD_TREELIST_COLUMN +{ + PH_THREAD_TREELIST_COLUMN_TID, + PH_THREAD_TREELIST_COLUMN_CPU, + PH_THREAD_TREELIST_COLUMN_CYCLESDELTA, + PH_THREAD_TREELIST_COLUMN_STARTADDRESS, + PH_THREAD_TREELIST_COLUMN_PRIORITYSYMBOLIC, + PH_THREAD_TREELIST_COLUMN_SERVICE, + PH_THREAD_TREELIST_COLUMN_NAME, + PH_THREAD_TREELIST_COLUMN_STARTED, + PH_THREAD_TREELIST_COLUMN_STARTMODULE, + PH_THREAD_TREELIST_COLUMN_CONTEXTSWITCHES, + PH_THREAD_TREELIST_COLUMN_PRIORITY, + PH_THREAD_TREELIST_COLUMN_BASEPRIORITY, + PH_THREAD_TREELIST_COLUMN_PAGEPRIORITY, + PH_THREAD_TREELIST_COLUMN_IOPRIORITY, + PH_THREAD_TREELIST_COLUMN_CYCLES, + PH_THREAD_TREELIST_COLUMN_STATE, + PH_THREAD_TREELIST_COLUMN_KERNELTIME, + PH_THREAD_TREELIST_COLUMN_USERTIME, + PH_THREAD_TREELIST_COLUMN_IDEALPROCESSOR, + PH_THREAD_TREELIST_COLUMN_MAXIMUM +} PH_THREAD_TREELIST_COLUMN; // begin_phapppub typedef struct _PH_THREAD_NODE @@ -27,7 +41,7 @@ typedef struct _PH_THREAD_NODE PPH_THREAD_ITEM ThreadItem; // end_phapppub - PH_STRINGREF TextCache[PHTHTLC_MAXIMUM]; + PH_STRINGREF TextCache[PH_THREAD_TREELIST_COLUMN_MAXIMUM]; ULONG ValidMask; @@ -35,7 +49,15 @@ typedef struct _PH_THREAD_NODE WCHAR CpuUsageText[PH_INT32_STR_LEN_1]; PPH_STRING CyclesDeltaText; // used for Context Switches Delta as well PPH_STRING StartAddressText; - PPH_STRING PriorityText; + PPH_STRING PrioritySymbolicText; + PPH_STRING CreatedText; + WCHAR ContextSwitchesText[PH_INT64_STR_LEN_1]; + WCHAR PriorityText[PH_INT32_STR_LEN_1]; + WCHAR BasePriorityText[PH_INT32_STR_LEN_1]; + WCHAR CyclesText[PH_INT64_STR_LEN_1]; + WCHAR KernelTimeText[PH_TIMESPAN_STR_LEN_1]; + WCHAR UserTimeText[PH_TIMESPAN_STR_LEN_1]; + WCHAR IdealProcessorText[PH_INT32_STR_LEN + 1 + PH_INT32_STR_LEN + 1]; // begin_phapppub } PH_THREAD_NODE, *PPH_THREAD_NODE; // end_phapppub diff --git a/ProcessHacker/thrdlist.c b/ProcessHacker/thrdlist.c index 2ed55b84872c..41ac879d4aa0 100644 --- a/ProcessHacker/thrdlist.c +++ b/ProcessHacker/thrdlist.c @@ -3,6 +3,7 @@ * thread list * * Copyright (C) 2011-2012 wj32 + * Copyright (C) 2018 dmex * * This file is part of Process Hacker. * @@ -72,8 +73,6 @@ VOID PhInitializeThreadList( _Out_ PPH_THREAD_LIST_CONTEXT Context ) { - HWND hwnd; - memset(Context, 0, sizeof(PH_THREAD_LIST_CONTEXT)); Context->EnableStateHighlighting = TRUE; @@ -87,27 +86,38 @@ VOID PhInitializeThreadList( Context->ParentWindowHandle = ParentWindowHandle; Context->TreeNewHandle = TreeNewHandle; - hwnd = TreeNewHandle; - PhSetControlTheme(hwnd, L"explorer"); - - TreeNew_SetCallback(hwnd, PhpThreadTreeNewCallback, Context); - TreeNew_SetRedraw(hwnd, FALSE); + PhSetControlTheme(TreeNewHandle, L"explorer"); + TreeNew_SetCallback(TreeNewHandle, PhpThreadTreeNewCallback, Context); + TreeNew_SetRedraw(TreeNewHandle, FALSE); // Default columns - PhAddTreeNewColumn(hwnd, PHTHTLC_TID, TRUE, L"TID", 50, PH_ALIGN_RIGHT, 0, DT_RIGHT); - PhAddTreeNewColumnEx(hwnd, PHTHTLC_CPU, TRUE, L"CPU", 45, PH_ALIGN_RIGHT, 1, DT_RIGHT, TRUE); - PhAddTreeNewColumnEx(hwnd, PHTHTLC_CYCLESDELTA, TRUE, L"Cycles delta", 80, PH_ALIGN_RIGHT, 2, DT_RIGHT, TRUE); - PhAddTreeNewColumn(hwnd, PHTHTLC_STARTADDRESS, TRUE, L"Start address", 180, PH_ALIGN_LEFT, 3, 0); - PhAddTreeNewColumnEx(hwnd, PHTHTLC_PRIORITY, TRUE, L"Priority", 80, PH_ALIGN_LEFT, 4, 0, TRUE); - PhAddTreeNewColumn(hwnd, PHTHTLC_SERVICE, FALSE, L"Service", 100, PH_ALIGN_LEFT, -1, 0); - PhAddTreeNewColumn(hwnd, PHTHTLC_NAME, FALSE, L"Name", 100, PH_ALIGN_LEFT, -1, 0); - - TreeNew_SetRedraw(hwnd, TRUE); - - TreeNew_SetSort(hwnd, PHTHTLC_CYCLESDELTA, DescendingSortOrder); - - PhCmInitializeManager(&Context->Cm, hwnd, PHTHTLC_MAXIMUM, PhpThreadTreeNewPostSortFunction); + PhAddTreeNewColumn(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_TID, TRUE, L"TID", 50, PH_ALIGN_RIGHT, 0, DT_RIGHT); + PhAddTreeNewColumnEx(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_CPU, TRUE, L"CPU", 45, PH_ALIGN_RIGHT, 1, DT_RIGHT, TRUE); + PhAddTreeNewColumnEx(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_CYCLESDELTA, TRUE, L"Cycles delta", 80, PH_ALIGN_RIGHT, 2, DT_RIGHT, TRUE); + PhAddTreeNewColumn(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_STARTADDRESS, TRUE, L"Start address", 180, PH_ALIGN_LEFT, 3, 0); + PhAddTreeNewColumnEx(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_PRIORITYSYMBOLIC, TRUE, L"Priority (symbolic)", 80, PH_ALIGN_LEFT, 4, 0, TRUE); + // Available columns + PhAddTreeNewColumn(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_SERVICE, FALSE, L"Service", 100, PH_ALIGN_LEFT, 5, 0); + PhAddTreeNewColumn(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_NAME, FALSE, L"Name", 100, PH_ALIGN_LEFT, 6, 0); + PhAddTreeNewColumn(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_STARTED, FALSE, L"Created", 100, PH_ALIGN_LEFT, 7, 0); + PhAddTreeNewColumn(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_STARTMODULE, FALSE, L"Start module", 100, PH_ALIGN_LEFT, 8, 0); + PhAddTreeNewColumn(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_CONTEXTSWITCHES, FALSE, L"Context switches", 100, PH_ALIGN_LEFT, 9, 0); + PhAddTreeNewColumn(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_PRIORITY, FALSE, L"Priority", 80, PH_ALIGN_LEFT, 10, 0); + PhAddTreeNewColumn(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_BASEPRIORITY, FALSE, L"Base priority", 80, PH_ALIGN_LEFT, 10, 0); + PhAddTreeNewColumn(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_PAGEPRIORITY, FALSE, L"Page priority", 80, PH_ALIGN_LEFT, 10, 0); + PhAddTreeNewColumn(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_IOPRIORITY, FALSE, L"I/O priority", 80, PH_ALIGN_LEFT, 10, 0); + PhAddTreeNewColumn(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_CYCLES, FALSE, L"Cycles", 100, PH_ALIGN_LEFT, 6, 0); + PhAddTreeNewColumn(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_STATE, FALSE, L"State", 100, PH_ALIGN_LEFT, 6, 0); + PhAddTreeNewColumn(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_KERNELTIME, FALSE, L"Kernel time", 100, PH_ALIGN_LEFT, 6, 0); + PhAddTreeNewColumn(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_USERTIME, FALSE, L"User time", 100, PH_ALIGN_LEFT, 6, 0); + PhAddTreeNewColumn(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_IDEALPROCESSOR, FALSE, L"Ideal processor", 100, PH_ALIGN_LEFT, 6, 0); + + TreeNew_SetRedraw(TreeNewHandle, TRUE); + TreeNew_SetTriState(TreeNewHandle, TRUE); + //TreeNew_SetSort(TreeNewHandle, PHTHTLC_CYCLESDELTA, DescendingSortOrder); + + PhCmInitializeManager(&Context->Cm, TreeNewHandle, PH_THREAD_TREELIST_COLUMN_MAXIMUM, PhpThreadTreeNewPostSortFunction); } VOID PhDeleteThreadList( @@ -153,30 +163,9 @@ VOID PhLoadSettingsThreadList( ULONG sortColumn; PH_SORT_ORDER sortOrder; - if (!Context->UseCycleTime) - { - column.Id = PHTHTLC_CYCLESDELTA; - column.Text = L"Context switches delta"; - TreeNew_SetColumn(Context->TreeNewHandle, TN_COLUMN_TEXT, &column); - } - - if (Context->HasServices) - { - column.Id = PHTHTLC_SERVICE; - column.Visible = TRUE; - TreeNew_SetColumn(Context->TreeNewHandle, TN_COLUMN_FLAG_VISIBLE, &column); - } - - if (WindowsVersion >= WINDOWS_10_RS1) - { - column.Id = PHTHTLC_NAME; - column.Visible = TRUE; - TreeNew_SetColumn(Context->TreeNewHandle, TN_COLUMN_FLAG_VISIBLE, &column); - } - settings = PhGetStringSetting(L"ThreadTreeListColumns"); sortSettings = PhGetStringSetting(L"ThreadTreeListSort"); - PhCmLoadSettingsEx(Context->TreeNewHandle, &Context->Cm, PH_CM_COLUMN_WIDTHS_ONLY, &settings->sr, &sortSettings->sr); + PhCmLoadSettingsEx(Context->TreeNewHandle, &Context->Cm, 0, &settings->sr, &sortSettings->sr); PhDereferenceObject(settings); PhDereferenceObject(sortSettings); @@ -185,7 +174,7 @@ VOID PhLoadSettingsThreadList( // Make sure we're not sorting by an invisible column. if (sortOrder != NoSortOrder && !(TreeNew_GetColumn(Context->TreeNewHandle, sortColumn, &column) && column.Visible)) { - TreeNew_SetSort(Context->TreeNewHandle, PHTHTLC_CYCLESDELTA, DescendingSortOrder); + TreeNew_SetSort(Context->TreeNewHandle, PH_THREAD_TREELIST_COLUMN_CYCLESDELTA, DescendingSortOrder); } } @@ -196,7 +185,7 @@ VOID PhSaveSettingsThreadList( PPH_STRING settings; PPH_STRING sortSettings; - settings = PhCmSaveSettingsEx(Context->TreeNewHandle, &Context->Cm, PH_CM_COLUMN_WIDTHS_ONLY, &sortSettings); + settings = PhCmSaveSettingsEx(Context->TreeNewHandle, &Context->Cm, 0, &sortSettings); PhSetStringSetting2(L"ThreadTreeListColumns", &settings->sr); PhSetStringSetting2(L"ThreadTreeListSort", &sortSettings->sr); PhDereferenceObject(settings); @@ -227,13 +216,13 @@ PPH_THREAD_NODE PhAddThreadNode( ); } + PhReferenceObject(ThreadItem); threadNode->ThreadId = ThreadItem->ThreadId; threadNode->ThreadItem = ThreadItem; - PhReferenceObject(ThreadItem); - memset(threadNode->TextCache, 0, sizeof(PH_STRINGREF) * PHTHTLC_MAXIMUM); + memset(threadNode->TextCache, 0, sizeof(PH_STRINGREF) * PH_THREAD_TREELIST_COLUMN_MAXIMUM); threadNode->Node.TextCache = threadNode->TextCache; - threadNode->Node.TextCacheSize = PHTHTLC_MAXIMUM; + threadNode->Node.TextCacheSize = PH_THREAD_TREELIST_COLUMN_MAXIMUM; PhAddEntryHashtable(Context->NodeHashtable, &threadNode); PhAddItemList(Context->NodeList, threadNode); @@ -300,7 +289,7 @@ VOID PhpDestroyThreadNode( if (ThreadNode->CyclesDeltaText) PhDereferenceObject(ThreadNode->CyclesDeltaText); if (ThreadNode->StartAddressText) PhDereferenceObject(ThreadNode->StartAddressText); - if (ThreadNode->PriorityText) PhDereferenceObject(ThreadNode->PriorityText); + if (ThreadNode->PrioritySymbolicText) PhDereferenceObject(ThreadNode->PrioritySymbolicText); PhDereferenceObject(ThreadNode->ThreadItem); @@ -329,7 +318,7 @@ VOID PhUpdateThreadNode( _In_ PPH_THREAD_NODE ThreadNode ) { - memset(ThreadNode->TextCache, 0, sizeof(PH_STRINGREF) * PHTHTLC_MAXIMUM); + memset(ThreadNode->TextCache, 0, sizeof(PH_STRINGREF) * PH_THREAD_TREELIST_COLUMN_MAXIMUM); ThreadNode->ValidMask = 0; PhInvalidateTreeNewNode(&ThreadNode->Node, TN_CACHE_COLOR); @@ -475,7 +464,7 @@ BOOLEAN NTAPI PhpThreadTreeNewCallback( &context->Cm )) { - if (context->TreeNewSortColumn < PHTHTLC_MAXIMUM) + if (context->TreeNewSortColumn < PH_THREAD_TREELIST_COLUMN_MAXIMUM) sortFunction = sortFunctions[context->TreeNewSortColumn]; else sortFunction = NULL; @@ -512,7 +501,7 @@ BOOLEAN NTAPI PhpThreadTreeNewCallback( switch (getCellText->Id) { - case PHTHTLC_TID: + case PH_THREAD_TREELIST_COLUMN_TID: { PH_FORMAT format; SIZE_T returnLength; @@ -529,7 +518,7 @@ BOOLEAN NTAPI PhpThreadTreeNewCallback( } } break; - case PHTHTLC_CPU: + case PH_THREAD_TREELIST_COLUMN_CPU: { FLOAT cpuUsage; @@ -564,7 +553,7 @@ BOOLEAN NTAPI PhpThreadTreeNewCallback( } } break; - case PHTHTLC_CYCLESDELTA: + case PH_THREAD_TREELIST_COLUMN_CYCLESDELTA: if (context->UseCycleTime) { if (threadItem->CyclesDelta.Delta != threadItem->CyclesDelta.Value && threadItem->CyclesDelta.Delta != 0) @@ -582,25 +571,201 @@ BOOLEAN NTAPI PhpThreadTreeNewCallback( } } break; - case PHTHTLC_STARTADDRESS: + case PH_THREAD_TREELIST_COLUMN_STARTADDRESS: PhSwapReference(&node->StartAddressText, threadItem->StartAddressString); getCellText->Text = PhGetStringRef(node->StartAddressText); break; - case PHTHTLC_PRIORITY: - PhMoveReference(&node->PriorityText, PhGetBasePriorityIncrementString(threadItem->BasePriorityIncrement)); - getCellText->Text = PhGetStringRef(node->PriorityText); + case PH_THREAD_TREELIST_COLUMN_PRIORITYSYMBOLIC: + PhMoveReference(&node->PrioritySymbolicText, PhGetBasePriorityIncrementString(threadItem->BasePriorityIncrement)); + getCellText->Text = PhGetStringRef(node->PrioritySymbolicText); break; - case PHTHTLC_SERVICE: + case PH_THREAD_TREELIST_COLUMN_SERVICE: getCellText->Text = PhGetStringRef(threadItem->ServiceName); break; - case PHTHTLC_NAME: + case PH_THREAD_TREELIST_COLUMN_NAME: getCellText->Text = PhGetStringRef(threadItem->ThreadName); break; + case PH_THREAD_TREELIST_COLUMN_STARTED: + { + SYSTEMTIME time; + + PhLargeIntegerToLocalSystemTime(&time, &threadItem->CreateTime); + PhMoveReference(&node->CreatedText, PhFormatDateTime(&time)); + + getCellText->Text = PhGetStringRef(node->CreatedText); + } + break; + case PH_THREAD_TREELIST_COLUMN_STARTMODULE: + getCellText->Text = PhGetStringRef(threadItem->StartAddressFileName); + break; + case PH_THREAD_TREELIST_COLUMN_CONTEXTSWITCHES: + { + SIZE_T returnLength; + PH_FORMAT format[1]; + + PhInitFormatI64UGroupDigits(&format[0], threadItem->ContextSwitchesDelta.Value); + + if (PhFormatToBuffer(format, 1, node->ContextSwitchesText, sizeof(node->ContextSwitchesText), &returnLength)) + { + getCellText->Text.Buffer = node->ContextSwitchesText; + getCellText->Text.Length = returnLength - sizeof(UNICODE_NULL); + } + } + break; + case PH_THREAD_TREELIST_COLUMN_PRIORITY: + { + SIZE_T returnLength; + PH_FORMAT format[1]; + + PhInitFormatD(&format[0], threadItem->Priority); + + if (PhFormatToBuffer(format, 1, node->PriorityText, sizeof(node->PriorityText), &returnLength)) + { + getCellText->Text.Buffer = node->PriorityText; + getCellText->Text.Length = returnLength - sizeof(UNICODE_NULL); + } + } + break; + case PH_THREAD_TREELIST_COLUMN_BASEPRIORITY: + { + SIZE_T returnLength; + PH_FORMAT format[1]; + + PhInitFormatD(&format[0], threadItem->BasePriority); + + if (PhFormatToBuffer(format, 1, node->BasePriorityText, sizeof(node->BasePriorityText), &returnLength)) + { + getCellText->Text.Buffer = node->BasePriorityText; + getCellText->Text.Length = returnLength - sizeof(UNICODE_NULL); + } + } + break; + case PH_THREAD_TREELIST_COLUMN_PAGEPRIORITY: + { + ULONG pagePriorityInteger = MEMORY_PRIORITY_NORMAL + 1; + PWSTR pagePriority = L"N/A"; + + if (threadItem->ThreadHandle) + { + if (NT_SUCCESS(PhGetThreadPagePriority(threadItem->ThreadHandle, &pagePriorityInteger)) && pagePriorityInteger <= MEMORY_PRIORITY_NORMAL) + { + pagePriority = PhPagePriorityNames[pagePriorityInteger]; + } + } + + PhInitializeStringRefLongHint(&getCellText->Text, pagePriority); + } + break; + case PH_THREAD_TREELIST_COLUMN_IOPRIORITY: + { + IO_PRIORITY_HINT ioPriorityInteger = MaxIoPriorityTypes; + PWSTR ioPriority = L"N/A"; + + if (threadItem->ThreadHandle) + { + if (NT_SUCCESS(PhGetThreadIoPriority(threadItem->ThreadHandle, &ioPriorityInteger)) && ioPriorityInteger < MaxIoPriorityTypes) + { + ioPriority = PhIoPriorityHintNames[ioPriorityInteger]; + } + } + + PhInitializeStringRefLongHint(&getCellText->Text, ioPriority); + } + break; + case PH_THREAD_TREELIST_COLUMN_CYCLES: + { + SIZE_T returnLength; + PH_FORMAT format[1]; + + PhInitFormatI64UGroupDigits(&format[0], threadItem->CyclesDelta.Value); + + if (PhFormatToBuffer(format, 1, node->CyclesText, sizeof(node->CyclesText), &returnLength)) + { + getCellText->Text.Buffer = node->CyclesText; + getCellText->Text.Length = returnLength - sizeof(UNICODE_NULL); + } + } + break; + case PH_THREAD_TREELIST_COLUMN_STATE: + { + PPH_STRING state = NULL; + ULONG suspendCount; + + if (threadItem->State != Waiting) + { + if ((ULONG)threadItem->State < MaximumThreadState) + state = PhaCreateString(PhKThreadStateNames[(ULONG)threadItem->State]); + else + state = PhaCreateString(L"Unknown"); + } + else + { + if ((ULONG)threadItem->WaitReason < MaximumWaitReason) + state = PhaConcatStrings2(L"Wait:", PhKWaitReasonNames[(ULONG)threadItem->WaitReason]); + else + state = PhaCreateString(L"Waiting"); + } + + if (threadItem->ThreadHandle) + { + if (threadItem->WaitReason == Suspended && NT_SUCCESS(PhGetThreadSuspendCount(threadItem->ThreadHandle, &suspendCount))) + { + PH_FORMAT format[4]; + + PhInitFormatSR(&format[0], state->sr); + PhInitFormatS(&format[1], L" ("); + PhInitFormatU(&format[2], suspendCount); + PhInitFormatS(&format[3], L")"); + + state = PH_AUTO(PhFormat(format, 4, 30)); + } + } + + getCellText->Text = PhGetStringRef(state); + } + break; + case PH_THREAD_TREELIST_COLUMN_KERNELTIME: + { + PhPrintTimeSpan(node->KernelTimeText, threadItem->KernelTime.QuadPart, PH_TIMESPAN_HMSM); + + PhInitializeStringRefLongHint(&getCellText->Text, node->KernelTimeText); + } + break; + case PH_THREAD_TREELIST_COLUMN_USERTIME: + { + PhPrintTimeSpan(node->UserTimeText, threadItem->UserTime.QuadPart, PH_TIMESPAN_HMSM); + + PhInitializeStringRefLongHint(&getCellText->Text, node->UserTimeText); + } + break; + case PH_THREAD_TREELIST_COLUMN_IDEALPROCESSOR: + { + PROCESSOR_NUMBER idealProcessorNumber; + SIZE_T returnLength; + PH_FORMAT format[3]; + + if (threadItem->ThreadHandle) + { + if (NT_SUCCESS(PhGetThreadIdealProcessor(threadItem->ThreadHandle, &idealProcessorNumber))) + { + PhInitFormatU(&format[0], idealProcessorNumber.Group); + PhInitFormatC(&format[1], ':'); + PhInitFormatU(&format[2], idealProcessorNumber.Number); + + if (PhFormatToBuffer(format, 3, node->IdealProcessorText, sizeof(node->IdealProcessorText), &returnLength)) + { + getCellText->Text.Buffer = node->IdealProcessorText; + getCellText->Text.Length = returnLength - sizeof(UNICODE_NULL); + } + } + } + } + break; default: return FALSE; } - getCellText->Flags = TN_CACHE; + //getCellText->Flags = TN_CACHE; } return TRUE; case TreeNewGetNodeColor: @@ -628,11 +793,6 @@ BOOLEAN NTAPI PhpThreadTreeNewCallback( TreeNew_NodesStructured(hwnd); } return TRUE; - case TreeNewSelectionChanged: - { - SendMessage(context->ParentWindowHandle, WM_PH_THREAD_SELECTION_CHANGED, 0, 0); - } - return TRUE; case TreeNewKeyDown: { PPH_TREENEW_KEY_EVENT keyEvent = Parameter1; @@ -666,9 +826,9 @@ BOOLEAN NTAPI PhpThreadTreeNewCallback( data.TreeNewHandle = hwnd; data.MouseEvent = Parameter1; - data.DefaultSortColumn = PHTHTLC_CYCLESDELTA; + data.DefaultSortColumn = PH_THREAD_TREELIST_COLUMN_CYCLESDELTA; data.DefaultSortOrder = DescendingSortOrder; - PhInitializeTreeNewColumnMenuEx(&data, PH_TN_COLUMN_MENU_NO_VISIBILITY); + PhInitializeTreeNewColumnMenuEx(&data, PH_TN_COLUMN_MENU_SHOW_RESET_SORT); data.Selection = PhShowEMenu(data.Menu, hwnd, PH_EMENU_SHOW_LEFTRIGHT, PH_ALIGN_LEFT | PH_ALIGN_TOP, data.MouseEvent->ScreenLocation.x, data.MouseEvent->ScreenLocation.y); From 04d53024b989e866c3ebfdf9a16d2df835e4e53b Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 8 Aug 2018 23:37:08 +1000 Subject: [PATCH 1274/2058] Remove legacy process thread tab information --- ProcessHacker/prpgthrd.c | 202 ++++----------------------------------- 1 file changed, 16 insertions(+), 186 deletions(-) diff --git a/ProcessHacker/prpgthrd.c b/ProcessHacker/prpgthrd.c index 00f3a3d61d1b..e6d59e853865 100644 --- a/ProcessHacker/prpgthrd.c +++ b/ProcessHacker/prpgthrd.c @@ -287,138 +287,6 @@ static NTSTATUS NTAPI PhpOpenThreadTokenObject( ); } -VOID PhpUpdateThreadDetails( - _In_ HWND hwndDlg, - _In_ PPH_THREADS_CONTEXT Context, - _In_ BOOLEAN Force - ) -{ - PPH_THREAD_ITEM *threads; - ULONG numberOfThreads; - PPH_THREAD_ITEM threadItem; - PPH_STRING startModule = NULL; - PPH_STRING started = NULL; - WCHAR kernelTime[PH_TIMESPAN_STR_LEN_1] = L"N/A"; - WCHAR userTime[PH_TIMESPAN_STR_LEN_1] = L"N/A"; - PPH_STRING contextSwitches = NULL; - PPH_STRING cycles = NULL; - PPH_STRING state = NULL; - WCHAR priority[PH_INT32_STR_LEN_1] = L"N/A"; - WCHAR basePriority[PH_INT32_STR_LEN_1] = L"N/A"; - PWSTR ioPriority = L"N/A"; - PWSTR pagePriority = L"N/A"; - WCHAR idealProcessor[PH_INT32_STR_LEN + 1 + PH_INT32_STR_LEN + 1] = L"N/A"; - HANDLE threadHandle; - SYSTEMTIME time; - IO_PRIORITY_HINT ioPriorityInteger; - ULONG pagePriorityInteger; - PROCESSOR_NUMBER idealProcessorNumber; - ULONG suspendCount; - - PhGetSelectedThreadItems(&Context->ListContext, &threads, &numberOfThreads); - - if (numberOfThreads == 1) - threadItem = threads[0]; - else - threadItem = NULL; - - PhFree(threads); - - if (numberOfThreads != 1 && !Force) - return; - - if (numberOfThreads == 1) - { - startModule = threadItem->StartAddressFileName; - - PhLargeIntegerToLocalSystemTime(&time, &threadItem->CreateTime); - started = PhaFormatDateTime(&time); - - PhPrintTimeSpan(kernelTime, threadItem->KernelTime.QuadPart, PH_TIMESPAN_HMSM); - PhPrintTimeSpan(userTime, threadItem->UserTime.QuadPart, PH_TIMESPAN_HMSM); - - contextSwitches = PhaFormatUInt64(threadItem->ContextSwitchesDelta.Value, TRUE); - cycles = PhaFormatUInt64(threadItem->CyclesDelta.Value, TRUE); - - if (threadItem->State != Waiting) - { - if ((ULONG)threadItem->State < MaximumThreadState) - state = PhaCreateString(PhKThreadStateNames[(ULONG)threadItem->State]); - else - state = PhaCreateString(L"Unknown"); - } - else - { - if ((ULONG)threadItem->WaitReason < MaximumWaitReason) - state = PhaConcatStrings2(L"Wait:", PhKWaitReasonNames[(ULONG)threadItem->WaitReason]); - else - state = PhaCreateString(L"Waiting"); - } - - PhPrintInt32(priority, threadItem->Priority); - PhPrintInt32(basePriority, threadItem->BasePriority); - - if (NT_SUCCESS(PhOpenThread(&threadHandle, ThreadQueryAccess, threadItem->ThreadId))) - { - if (NT_SUCCESS(PhGetThreadIoPriority(threadHandle, &ioPriorityInteger)) && - ioPriorityInteger < MaxIoPriorityTypes) - { - ioPriority = PhIoPriorityHintNames[ioPriorityInteger]; - } - - if (NT_SUCCESS(PhGetThreadPagePriority(threadHandle, &pagePriorityInteger)) && - pagePriorityInteger <= MEMORY_PRIORITY_NORMAL) - { - pagePriority = PhPagePriorityNames[pagePriorityInteger]; - } - - if (NT_SUCCESS(PhGetThreadIdealProcessor(threadHandle, &idealProcessorNumber))) - { - PH_FORMAT format[3]; - - PhInitFormatU(&format[0], idealProcessorNumber.Group); - PhInitFormatC(&format[1], ':'); - PhInitFormatU(&format[2], idealProcessorNumber.Number); - PhFormatToBuffer(format, 3, idealProcessor, sizeof(idealProcessor), NULL); - } - - if (threadItem->WaitReason == Suspended && NT_SUCCESS(PhGetThreadSuspendCount(threadHandle, &suspendCount))) - { - PH_FORMAT format[4]; - - PhInitFormatSR(&format[0], state->sr); - PhInitFormatS(&format[1], L" ("); - PhInitFormatU(&format[2], suspendCount); - PhInitFormatS(&format[3], L")"); - state = PH_AUTO(PhFormat(format, 4, 30)); - } - - NtClose(threadHandle); - } - } - - if (Force) - { - // These don't change... - - PhSetDialogItemText(hwndDlg, IDC_STARTMODULE, PhGetStringOrEmpty(startModule)); - EnableWindow(GetDlgItem(hwndDlg, IDC_OPENSTARTMODULE), !!startModule); - - PhSetDialogItemText(hwndDlg, IDC_STARTED, PhGetStringOrDefault(started, L"N/A")); - } - - PhSetDialogItemText(hwndDlg, IDC_KERNELTIME, kernelTime); - PhSetDialogItemText(hwndDlg, IDC_USERTIME, userTime); - PhSetDialogItemText(hwndDlg, IDC_CONTEXTSWITCHES, PhGetStringOrDefault(contextSwitches, L"N/A")); - PhSetDialogItemText(hwndDlg, IDC_CYCLES, PhGetStringOrDefault(cycles, L"N/A")); - PhSetDialogItemText(hwndDlg, IDC_STATE, PhGetStringOrDefault(state, L"N/A")); - PhSetDialogItemText(hwndDlg, IDC_PRIORITY, priority); - PhSetDialogItemText(hwndDlg, IDC_BASEPRIORITY, basePriority); - PhSetDialogItemText(hwndDlg, IDC_IOPRIORITY, ioPriority); - PhSetDialogItemText(hwndDlg, IDC_PAGEPRIORITY, pagePriority); - PhSetDialogItemText(hwndDlg, IDC_IDEALPROCESSOR, idealProcessor); -} - VOID PhShowThreadContextMenu( _In_ HWND hwndDlg, _In_ PPH_PROCESS_ITEM ProcessItem, @@ -609,8 +477,6 @@ INT_PTR CALLBACK PhpProcessThreadsDlgProc( PhThreadProviderInitialUpdate(threadsContext->Provider); PhRegisterThreadProvider(threadsContext->Provider, &threadsContext->ProviderRegistration); - SET_BUTTON_ICON(IDC_OPENSTARTMODULE, PH_LOAD_SHARED_ICON_SMALL(PhInstanceHandle, MAKEINTRESOURCE(IDI_FOLDER))); - PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport); } break; @@ -665,35 +531,6 @@ INT_PTR CALLBACK PhpProcessThreadsDlgProc( if (dialogItem = PhBeginPropPageLayout(hwndDlg, propPageContext)) { PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_LIST), dialogItem, PH_ANCHOR_ALL); - -#define ADD_BL_ITEM(Id) \ - PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, Id), dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_BOTTOM) - - // Thread details area - { - ULONG id; - - for (id = IDC_STATICBL1; id <= IDC_STATICBL11; id++) - ADD_BL_ITEM(id); - - // Not in sequence - ADD_BL_ITEM(IDC_STATICBL12); - } - - PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_STARTMODULE), dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); - PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_OPENSTARTMODULE), dialogItem, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); - ADD_BL_ITEM(IDC_STARTED); - ADD_BL_ITEM(IDC_KERNELTIME); - ADD_BL_ITEM(IDC_USERTIME); - ADD_BL_ITEM(IDC_CONTEXTSWITCHES); - ADD_BL_ITEM(IDC_CYCLES); - ADD_BL_ITEM(IDC_STATE); - ADD_BL_ITEM(IDC_PRIORITY); - ADD_BL_ITEM(IDC_BASEPRIORITY); - ADD_BL_ITEM(IDC_IOPRIORITY); - ADD_BL_ITEM(IDC_PAGEPRIORITY); - ADD_BL_ITEM(IDC_IDEALPROCESSOR); - PhEndPropPageLayout(hwndDlg, propPageContext); } } @@ -963,22 +800,22 @@ INT_PTR CALLBACK PhpProcessThreadsDlgProc( PhDereferenceObject(text); } break; - case IDC_OPENSTARTMODULE: - { - PPH_THREAD_ITEM threadItem = PhGetSelectedThreadItem(&threadsContext->ListContext); - - if (threadItem && threadItem->StartAddressFileName) - { - PhShellExecuteUserString( - hwndDlg, - L"FileBrowseExecutable", - threadItem->StartAddressFileName->Buffer, - FALSE, - L"Make sure the Explorer executable file is present." - ); - } - } - break; + //case IDC_OPENSTARTMODULE: + // { + // PPH_THREAD_ITEM threadItem = PhGetSelectedThreadItem(&threadsContext->ListContext); + // + // if (threadItem && threadItem->StartAddressFileName) + // { + // PhShellExecuteUserString( + // hwndDlg, + // L"FileBrowseExecutable", + // threadItem->StartAddressFileName->Buffer, + // FALSE, + // L"Make sure the Explorer executable file is present." + // ); + // } + // } + // break; } } break; @@ -1055,13 +892,6 @@ INT_PTR CALLBACK PhpProcessThreadsDlgProc( propPageContext->PropContext->SelectThreadId = NULL; } - - PhpUpdateThreadDetails(hwndDlg, threadsContext, FALSE); - } - break; - case WM_PH_THREAD_SELECTION_CHANGED: - { - PhpUpdateThreadDetails(hwndDlg, threadsContext, TRUE); } break; } From 2240e495ced746657405427eb198fc141a7518c5 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 9 Aug 2018 00:08:54 +1000 Subject: [PATCH 1275/2058] Update process thread tab sorting --- ProcessHacker/include/thrdlist.h | 3 + ProcessHacker/include/thrdprv.h | 1 - ProcessHacker/thrdlist.c | 111 +++++++++++++++++++++++++++++-- ProcessHacker/thrdprv.c | 20 +----- 4 files changed, 111 insertions(+), 24 deletions(-) diff --git a/ProcessHacker/include/thrdlist.h b/ProcessHacker/include/thrdlist.h index caeff90cf45c..458f870419d5 100644 --- a/ProcessHacker/include/thrdlist.h +++ b/ProcessHacker/include/thrdlist.h @@ -45,12 +45,15 @@ typedef struct _PH_THREAD_NODE ULONG ValidMask; + ULONG PagePriority; + IO_PRIORITY_HINT IoPriority; WCHAR ThreadIdText[PH_INT32_STR_LEN_1]; WCHAR CpuUsageText[PH_INT32_STR_LEN_1]; PPH_STRING CyclesDeltaText; // used for Context Switches Delta as well PPH_STRING StartAddressText; PPH_STRING PrioritySymbolicText; PPH_STRING CreatedText; + PPH_STRING NameText; WCHAR ContextSwitchesText[PH_INT64_STR_LEN_1]; WCHAR PriorityText[PH_INT32_STR_LEN_1]; WCHAR BasePriorityText[PH_INT32_STR_LEN_1]; diff --git a/ProcessHacker/include/thrdprv.h b/ProcessHacker/include/thrdprv.h index 47922f93cb45..6eb0b11f8634 100644 --- a/ProcessHacker/include/thrdprv.h +++ b/ProcessHacker/include/thrdprv.h @@ -27,7 +27,6 @@ typedef struct _PH_THREAD_ITEM HANDLE ThreadHandle; PPH_STRING ServiceName; - PPH_STRING ThreadName; ULONG64 StartAddress; PPH_STRING StartAddressString; diff --git a/ProcessHacker/thrdlist.c b/ProcessHacker/thrdlist.c index 41ac879d4aa0..0439fefceb97 100644 --- a/ProcessHacker/thrdlist.c +++ b/ProcessHacker/thrdlist.c @@ -219,6 +219,8 @@ PPH_THREAD_NODE PhAddThreadNode( PhReferenceObject(ThreadItem); threadNode->ThreadId = ThreadItem->ThreadId; threadNode->ThreadItem = ThreadItem; + threadNode->PagePriority = MEMORY_PRIORITY_NORMAL + 1; + threadNode->IoPriority = MaxIoPriorityTypes; memset(threadNode->TextCache, 0, sizeof(PH_STRINGREF) * PH_THREAD_TREELIST_COLUMN_MAXIMUM); threadNode->Node.TextCache = threadNode->TextCache; @@ -402,7 +404,7 @@ BEGIN_SORT_FUNCTION(StartAddress) } END_SORT_FUNCTION -BEGIN_SORT_FUNCTION(Priority) +BEGIN_SORT_FUNCTION(PrioritySymbolic) { sortResult = intcmp(threadItem1->BasePriorityIncrement, threadItem2->BasePriorityIncrement); } @@ -416,7 +418,80 @@ END_SORT_FUNCTION BEGIN_SORT_FUNCTION(Name) { - sortResult = PhCompareStringWithNull(threadItem1->ThreadName, threadItem2->ThreadName, TRUE); + sortResult = PhCompareStringWithNull(node1->NameText, node2->NameText, TRUE); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(Started) +{ + sortResult = uint64cmp(threadItem1->CreateTime.QuadPart, threadItem2->CreateTime.QuadPart); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(StartModule) +{ + sortResult = PhCompareStringWithNull(threadItem1->StartAddressFileName, threadItem2->StartAddressFileName, TRUE); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(ContextSwitches) +{ + sortResult = uint64cmp(threadItem1->ContextSwitchesDelta.Value, threadItem2->ContextSwitchesDelta.Value); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(Priority) +{ + sortResult = intcmp(threadItem1->Priority, threadItem2->Priority); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(BasePriority) +{ + sortResult = intcmp(threadItem1->BasePriority, threadItem2->BasePriority); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(PagePriority) +{ + sortResult = uintcmp(node1->PagePriority, node2->PagePriority); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(IoPriority) +{ + sortResult = uintcmp(node1->IoPriority, node2->IoPriority); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(Cycles) +{ + sortResult = uint64cmp(threadItem1->CyclesDelta.Value, threadItem2->CyclesDelta.Value); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(State) +{ + sortResult = uintcmp(threadItem1->WaitReason, threadItem2->WaitReason); + //sortResult = uintcmp(threadItem1->State, threadItem2->State); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(KernelTime) +{ + sortResult = uint64cmp(threadItem1->KernelTime.QuadPart, threadItem2->KernelTime.QuadPart); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(UserTime) +{ + sortResult = uint64cmp(threadItem1->UserTime.QuadPart, threadItem2->UserTime.QuadPart); +} +END_SORT_FUNCTION + +BEGIN_SORT_FUNCTION(IdealProcessor) +{ + sortResult = PhCompareStringZ(node1->IdealProcessorText, node2->IdealProcessorText, TRUE); } END_SORT_FUNCTION @@ -450,9 +525,21 @@ BOOLEAN NTAPI PhpThreadTreeNewCallback( SORT_FUNCTION(Cpu), SORT_FUNCTION(CyclesDelta), SORT_FUNCTION(StartAddress), - SORT_FUNCTION(Priority), + SORT_FUNCTION(PrioritySymbolic), SORT_FUNCTION(Service), - SORT_FUNCTION(Name) + SORT_FUNCTION(Name), + SORT_FUNCTION(Started), + SORT_FUNCTION(StartModule), + SORT_FUNCTION(ContextSwitches), + SORT_FUNCTION(Priority), + SORT_FUNCTION(BasePriority), + SORT_FUNCTION(PagePriority), + SORT_FUNCTION(IoPriority), + SORT_FUNCTION(Cycles), + SORT_FUNCTION(State), + SORT_FUNCTION(KernelTime), + SORT_FUNCTION(UserTime), + SORT_FUNCTION(IdealProcessor) }; int (__cdecl *sortFunction)(void *, const void *, const void *); @@ -583,7 +670,19 @@ BOOLEAN NTAPI PhpThreadTreeNewCallback( getCellText->Text = PhGetStringRef(threadItem->ServiceName); break; case PH_THREAD_TREELIST_COLUMN_NAME: - getCellText->Text = PhGetStringRef(threadItem->ThreadName); + { + if (threadItem->ThreadHandle && WindowsVersion >= WINDOWS_10_RS1) + { + PPH_STRING threadName; + + if (NT_SUCCESS(PhGetThreadName(threadItem->ThreadHandle, &threadName))) + { + node->NameText = threadName; + } + } + + getCellText->Text = PhGetStringRef(node->NameText); + } break; case PH_THREAD_TREELIST_COLUMN_STARTED: { @@ -649,6 +748,7 @@ BOOLEAN NTAPI PhpThreadTreeNewCallback( { if (NT_SUCCESS(PhGetThreadPagePriority(threadItem->ThreadHandle, &pagePriorityInteger)) && pagePriorityInteger <= MEMORY_PRIORITY_NORMAL) { + node->PagePriority = pagePriorityInteger; pagePriority = PhPagePriorityNames[pagePriorityInteger]; } } @@ -665,6 +765,7 @@ BOOLEAN NTAPI PhpThreadTreeNewCallback( { if (NT_SUCCESS(PhGetThreadIoPriority(threadItem->ThreadHandle, &ioPriorityInteger)) && ioPriorityInteger < MaxIoPriorityTypes) { + node->IoPriority = ioPriorityInteger; ioPriority = PhIoPriorityHintNames[ioPriorityInteger]; } } diff --git a/ProcessHacker/thrdprv.c b/ProcessHacker/thrdprv.c index e54320b6ef53..25b85d6f6344 100644 --- a/ProcessHacker/thrdprv.c +++ b/ProcessHacker/thrdprv.c @@ -50,7 +50,6 @@ typedef struct _PH_THREAD_QUERY_DATA PH_SYMBOL_RESOLVE_LEVEL StartAddressResolveLevel; PPH_STRING ServiceName; - PPH_STRING ThreadName; } PH_THREAD_QUERY_DATA, *PPH_THREAD_QUERY_DATA; typedef struct _PH_THREAD_SYMBOL_LOAD_CONTEXT @@ -195,9 +194,8 @@ VOID PhpThreadProviderDeleteProcedure( data = CONTAINING_RECORD(entry, PH_THREAD_QUERY_DATA, ListEntry); entry = entry->Next; - PhClearReference(&data->StartAddressString); - PhClearReference(&data->ServiceName); - PhClearReference(&data->ThreadName); + PhDereferenceObject(data->StartAddressString); + PhDereferenceObject(data->ServiceName); PhDereferenceObject(data->ThreadItem); PhFree(data); } @@ -407,7 +405,6 @@ VOID PhpThreadItemDeleteProcedure( if (threadItem->StartAddressString) PhDereferenceObject(threadItem->StartAddressString); if (threadItem->StartAddressFileName) PhDereferenceObject(threadItem->StartAddressFileName); if (threadItem->ServiceName) PhDereferenceObject(threadItem->ServiceName); - if (threadItem->ThreadName) PhDereferenceObject(threadItem->ThreadName); } BOOLEAN PhpThreadHashtableEqualFunction( @@ -573,18 +570,6 @@ NTSTATUS PhpThreadQueryWorker( } } - // Get the thread name (Windows 10 only). - - if (data->ThreadItem->ThreadHandle && WindowsVersion >= WINDOWS_10_RS1) - { - PPH_STRING threadName; - - if (NT_SUCCESS(PhGetThreadName(data->ThreadItem->ThreadHandle, &threadName))) - { - data->ThreadName = threadName; - } - } - Done: RtlInterlockedPushEntrySList(&data->ThreadProvider->QueryListHead, &data->ListEntry); PhDereferenceObject(data->ThreadProvider); @@ -834,7 +819,6 @@ VOID PhpThreadProviderUpdate( } PhMoveReference(&data->ThreadItem->ServiceName, data->ServiceName); - PhMoveReference(&data->ThreadItem->ThreadName, data->ThreadName); data->ThreadItem->JustResolved = TRUE; From 47fcef2cd9845b6df855c8b1e3cc11fd908fb332 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 9 Aug 2018 00:59:10 +1000 Subject: [PATCH 1276/2058] Fix process thread tab crash --- ProcessHacker/thrdprv.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ProcessHacker/thrdprv.c b/ProcessHacker/thrdprv.c index 25b85d6f6344..6c1d382248e4 100644 --- a/ProcessHacker/thrdprv.c +++ b/ProcessHacker/thrdprv.c @@ -194,8 +194,8 @@ VOID PhpThreadProviderDeleteProcedure( data = CONTAINING_RECORD(entry, PH_THREAD_QUERY_DATA, ListEntry); entry = entry->Next; - PhDereferenceObject(data->StartAddressString); - PhDereferenceObject(data->ServiceName); + PhClearReference(&data->StartAddressString); + PhClearReference(&data->ServiceName); PhDereferenceObject(data->ThreadItem); PhFree(data); } From 70d32851c978d114bad5b0619592600eaf714e46 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 9 Aug 2018 02:28:58 +1000 Subject: [PATCH 1277/2058] Fix process properties crash --- ProcessHacker/include/procprpp.h | 36 -------------------------------- ProcessHacker/procprp.c | 2 +- 2 files changed, 1 insertion(+), 37 deletions(-) diff --git a/ProcessHacker/include/procprpp.h b/ProcessHacker/include/procprpp.h index e92aab5dcd61..29552546f8ab 100644 --- a/ProcessHacker/include/procprpp.h +++ b/ProcessHacker/include/procprpp.h @@ -48,42 +48,6 @@ INT CALLBACK PhpStandardPropPageProc( _In_ LPPROPSHEETPAGE ppsp ); -FORCEINLINE BOOLEAN PhpPropPageDlgProcHeader( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ LPARAM lParam, - _Out_ LPPROPSHEETPAGE *PropSheetPage, - _Out_ PPH_PROCESS_PROPPAGECONTEXT *PropPageContext, - _Out_ PPH_PROCESS_ITEM *ProcessItem - ) -{ - LPPROPSHEETPAGE propSheetPage; - PPH_PROCESS_PROPPAGECONTEXT propPageContext; - - if (uMsg == WM_INITDIALOG) - { - PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, (PVOID)lParam); - } - - propSheetPage = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); - - if (!propSheetPage) - return FALSE; - - propPageContext = (PPH_PROCESS_PROPPAGECONTEXT)propSheetPage->lParam;; - - *PropSheetPage = propSheetPage; - *PropPageContext = propPageContext; - *ProcessItem = propPageContext->PropContext->ProcessItem; - - if (uMsg == WM_NCDESTROY) - { - PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); - } - - return TRUE; -} - #define SET_BUTTON_ICON(Id, Icon) \ SendMessage(GetDlgItem(hwndDlg, (Id)), BM_SETIMAGE, IMAGE_ICON, (LPARAM)(Icon)) diff --git a/ProcessHacker/procprp.c b/ProcessHacker/procprp.c index d99f8af00f56..64aa7413df8b 100644 --- a/ProcessHacker/procprp.c +++ b/ProcessHacker/procprp.c @@ -485,7 +485,7 @@ BOOLEAN PhPropPageDlgProcHeader( if (ProcessItem) *ProcessItem = propPageContext->PropContext->ProcessItem; - if (uMsg == WM_NCDESTROY) + if (uMsg == WM_DESTROY) { PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); } From 64fb82487ff21f0dfc8983362d66fc1dbff8ad73 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 15 Aug 2018 20:06:38 +1000 Subject: [PATCH 1278/2058] Tidy up --- ProcessHacker/memlist.c | 45 +++++++++++++++------------------ ProcessHacker/netprv.c | 7 +++-- ProcessHacker/phsvc/svcclient.c | 5 ++-- ProcessHacker/procprp.c | 2 +- ProcessHacker/procprv.c | 40 ++++++++++++++--------------- ProcessHacker/srvprv.c | 22 +++++++--------- ProcessHacker/sysscmem.c | 2 +- phlib/basesup.c | 3 +-- phlib/extlv.c | 2 +- phlib/treenew.c | 2 +- plugins/UserNotes/main.c | 3 +-- 11 files changed, 61 insertions(+), 72 deletions(-) diff --git a/ProcessHacker/memlist.c b/ProcessHacker/memlist.c index e34b74971447..2f7f18357300 100644 --- a/ProcessHacker/memlist.c +++ b/ProcessHacker/memlist.c @@ -61,8 +61,6 @@ VOID PhInitializeMemoryList( _Out_ PPH_MEMORY_LIST_CONTEXT Context ) { - HWND hwnd; - memset(Context, 0, sizeof(PH_MEMORY_LIST_CONTEXT)); Context->AllocationBaseNodeList = PhCreateList(100); @@ -70,37 +68,36 @@ VOID PhInitializeMemoryList( Context->ParentWindowHandle = ParentWindowHandle; Context->TreeNewHandle = TreeNewHandle; - hwnd = TreeNewHandle; - PhSetControlTheme(hwnd, L"explorer"); + PhSetControlTheme(TreeNewHandle, L"explorer"); - TreeNew_SetCallback(hwnd, PhpMemoryTreeNewCallback, Context); + TreeNew_SetCallback(TreeNewHandle, PhpMemoryTreeNewCallback, Context); - TreeNew_SetRedraw(hwnd, FALSE); + TreeNew_SetRedraw(TreeNewHandle, FALSE); // Default columns - PhAddTreeNewColumn(hwnd, PHMMTLC_BASEADDRESS, TRUE, L"Base address", 120, PH_ALIGN_LEFT, -2, 0); - PhAddTreeNewColumn(hwnd, PHMMTLC_TYPE, TRUE, L"Type", 90, PH_ALIGN_LEFT, 0, 0); - PhAddTreeNewColumnEx(hwnd, PHMMTLC_SIZE, TRUE, L"Size", 80, PH_ALIGN_RIGHT, 1, DT_RIGHT, TRUE); - PhAddTreeNewColumn(hwnd, PHMMTLC_PROTECTION, TRUE, L"Protection", 60, PH_ALIGN_LEFT, 2, 0); - PhAddTreeNewColumn(hwnd, PHMMTLC_USE, TRUE, L"Use", 200, PH_ALIGN_LEFT, 3, 0); - PhAddTreeNewColumnEx(hwnd, PHMMTLC_TOTALWS, TRUE, L"Total WS", 80, PH_ALIGN_RIGHT, 4, DT_RIGHT, TRUE); - PhAddTreeNewColumnEx(hwnd, PHMMTLC_PRIVATEWS, TRUE, L"Private WS", 80, PH_ALIGN_RIGHT, 5, DT_RIGHT, TRUE); - PhAddTreeNewColumnEx(hwnd, PHMMTLC_SHAREABLEWS, TRUE, L"Shareable WS", 80, PH_ALIGN_RIGHT, 6, DT_RIGHT, TRUE); - PhAddTreeNewColumnEx(hwnd, PHMMTLC_SHAREDWS, TRUE, L"Shared WS", 80, PH_ALIGN_RIGHT, 7, DT_RIGHT, TRUE); - PhAddTreeNewColumnEx(hwnd, PHMMTLC_LOCKEDWS, TRUE, L"Locked WS", 80, PH_ALIGN_RIGHT, 8, DT_RIGHT, TRUE); + PhAddTreeNewColumn(TreeNewHandle, PHMMTLC_BASEADDRESS, TRUE, L"Base address", 120, PH_ALIGN_LEFT, -2, 0); + PhAddTreeNewColumn(TreeNewHandle, PHMMTLC_TYPE, TRUE, L"Type", 90, PH_ALIGN_LEFT, 0, 0); + PhAddTreeNewColumnEx(TreeNewHandle, PHMMTLC_SIZE, TRUE, L"Size", 80, PH_ALIGN_RIGHT, 1, DT_RIGHT, TRUE); + PhAddTreeNewColumn(TreeNewHandle, PHMMTLC_PROTECTION, TRUE, L"Protection", 60, PH_ALIGN_LEFT, 2, 0); + PhAddTreeNewColumn(TreeNewHandle, PHMMTLC_USE, TRUE, L"Use", 200, PH_ALIGN_LEFT, 3, 0); + PhAddTreeNewColumnEx(TreeNewHandle, PHMMTLC_TOTALWS, TRUE, L"Total WS", 80, PH_ALIGN_RIGHT, 4, DT_RIGHT, TRUE); + PhAddTreeNewColumnEx(TreeNewHandle, PHMMTLC_PRIVATEWS, TRUE, L"Private WS", 80, PH_ALIGN_RIGHT, 5, DT_RIGHT, TRUE); + PhAddTreeNewColumnEx(TreeNewHandle, PHMMTLC_SHAREABLEWS, TRUE, L"Shareable WS", 80, PH_ALIGN_RIGHT, 6, DT_RIGHT, TRUE); + PhAddTreeNewColumnEx(TreeNewHandle, PHMMTLC_SHAREDWS, TRUE, L"Shared WS", 80, PH_ALIGN_RIGHT, 7, DT_RIGHT, TRUE); + PhAddTreeNewColumnEx(TreeNewHandle, PHMMTLC_LOCKEDWS, TRUE, L"Locked WS", 80, PH_ALIGN_RIGHT, 8, DT_RIGHT, TRUE); - PhAddTreeNewColumnEx(hwnd, PHMMTLC_COMMITTED, FALSE, L"Committed", 80, PH_ALIGN_RIGHT, 9, DT_RIGHT, TRUE); - PhAddTreeNewColumnEx(hwnd, PHMMTLC_PRIVATE, FALSE, L"Private", 80, PH_ALIGN_RIGHT, 10, DT_RIGHT, TRUE); + PhAddTreeNewColumnEx(TreeNewHandle, PHMMTLC_COMMITTED, FALSE, L"Committed", 80, PH_ALIGN_RIGHT, 9, DT_RIGHT, TRUE); + PhAddTreeNewColumnEx(TreeNewHandle, PHMMTLC_PRIVATE, FALSE, L"Private", 80, PH_ALIGN_RIGHT, 10, DT_RIGHT, TRUE); - TreeNew_SetRedraw(hwnd, TRUE); + TreeNew_SetRedraw(TreeNewHandle, TRUE); - TreeNew_SetTriState(hwnd, TRUE); - TreeNew_SetSort(hwnd, 0, NoSortOrder); + TreeNew_SetTriState(TreeNewHandle, TRUE); + TreeNew_SetSort(TreeNewHandle, 0, NoSortOrder); - PhCmInitializeManager(&Context->Cm, hwnd, PHMMTLC_MAXIMUM, PhpMemoryTreeNewPostSortFunction); + PhCmInitializeManager(&Context->Cm, TreeNewHandle, PHMMTLC_MAXIMUM, PhpMemoryTreeNewPostSortFunction); - PhInitializeTreeNewFilterSupport(&Context->AllocationTreeFilterSupport, hwnd, Context->AllocationBaseNodeList); - PhInitializeTreeNewFilterSupport(&Context->TreeFilterSupport, hwnd, Context->RegionNodeList); + PhInitializeTreeNewFilterSupport(&Context->AllocationTreeFilterSupport, TreeNewHandle, Context->AllocationBaseNodeList); + PhInitializeTreeNewFilterSupport(&Context->TreeFilterSupport, TreeNewHandle, Context->RegionNodeList); } VOID PhpClearMemoryList( diff --git a/ProcessHacker/netprv.c b/ProcessHacker/netprv.c index 1480df59452e..84b2e279f7e9 100644 --- a/ProcessHacker/netprv.c +++ b/ProcessHacker/netprv.c @@ -87,9 +87,8 @@ BOOLEAN PhGetNetworkConnections( _Out_ PULONG NumberOfConnections ); -PPH_OBJECT_TYPE PhNetworkItemType; - -PPH_HASHTABLE PhNetworkHashtable; +PPH_OBJECT_TYPE PhNetworkItemType = NULL; +PPH_HASHTABLE PhNetworkHashtable = NULL; PH_QUEUED_LOCK PhNetworkHashtableLock = PH_QUEUED_LOCK_INIT; PH_INITONCE PhNetworkProviderWorkQueueInitOnce = PH_INITONCE_INIT; @@ -98,7 +97,7 @@ SLIST_HEADER PhNetworkItemQueryListHead; BOOLEAN PhEnableNetworkProviderResolve = TRUE; static BOOLEAN NetworkImportDone = FALSE; -static PPH_HASHTABLE PhpResolveCacheHashtable; +static PPH_HASHTABLE PhpResolveCacheHashtable = NULL; static PH_QUEUED_LOCK PhpResolveCacheHashtableLock = PH_QUEUED_LOCK_INIT; BOOLEAN PhNetworkProviderInitialization( diff --git a/ProcessHacker/phsvc/svcclient.c b/ProcessHacker/phsvc/svcclient.c index 8b6fe4cea657..6c2c0021a542 100644 --- a/ProcessHacker/phsvc/svcclient.c +++ b/ProcessHacker/phsvc/svcclient.c @@ -28,8 +28,8 @@ VOID NTAPI PhSvcpClientDeleteProcedure( _In_ ULONG Flags ); -PPH_OBJECT_TYPE PhSvcClientType; -LIST_ENTRY PhSvcClientListHead; +PPH_OBJECT_TYPE PhSvcClientType = NULL; +LIST_ENTRY PhSvcClientListHead = { &PhSvcClientListHead, &PhSvcClientListHead }; PH_QUEUED_LOCK PhSvcClientListLock = PH_QUEUED_LOCK_INIT; NTSTATUS PhSvcClientInitialization( @@ -37,7 +37,6 @@ NTSTATUS PhSvcClientInitialization( ) { PhSvcClientType = PhCreateObjectType(L"Client", 0, PhSvcpClientDeleteProcedure); - InitializeListHead(&PhSvcClientListHead); return STATUS_SUCCESS; } diff --git a/ProcessHacker/procprp.c b/ProcessHacker/procprp.c index 64aa7413df8b..6ec43e5eb090 100644 --- a/ProcessHacker/procprp.c +++ b/ProcessHacker/procprp.c @@ -714,7 +714,7 @@ NTSTATUS PhpProcessPropertiesThreadStart( PropContext->PropSheetHeader.dwFlags |= PSH_USEPSTARTPAGE; PropContext->PropSheetHeader.pStartPage = startPage->Buffer; - PhModalPropertySheet(&PropContext->PropSheetHeader);; + PhModalPropertySheet(&PropContext->PropSheetHeader); PhDereferenceObject(startPage); PhDereferenceObject(PropContext); diff --git a/ProcessHacker/procprv.c b/ProcessHacker/procprv.c index fd7606d78b09..da9e565d22f0 100644 --- a/ProcessHacker/procprv.c +++ b/ProcessHacker/procprv.c @@ -153,7 +153,7 @@ VOID PhpRemoveProcessRecord( _Inout_ PPH_PROCESS_RECORD ProcessRecord ); -PPH_OBJECT_TYPE PhProcessItemType; +PPH_OBJECT_TYPE PhProcessItemType = NULL; PPH_HASH_ENTRY PhProcessHashSet[256] = PH_HASH_SET_INIT; ULONG PhProcessHashSetCount = 0; @@ -161,43 +161,43 @@ PH_QUEUED_LOCK PhProcessHashSetLock = PH_QUEUED_LOCK_INIT; SLIST_HEADER PhProcessQueryDataListHead; -PPH_LIST PhProcessRecordList; +PPH_LIST PhProcessRecordList = NULL; PH_QUEUED_LOCK PhProcessRecordListLock = PH_QUEUED_LOCK_INIT; ULONG PhStatisticsSampleCount = 512; BOOLEAN PhEnablePurgeProcessRecords = TRUE; BOOLEAN PhEnableCycleCpuUsage = TRUE; -PVOID PhProcessInformation; // only can be used if running on same thread as process provider +PVOID PhProcessInformation = NULL; // only can be used if running on same thread as process provider SYSTEM_PERFORMANCE_INFORMATION PhPerfInformation; -PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION PhCpuInformation; +PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION PhCpuInformation = NULL; SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION PhCpuTotals; -ULONG PhTotalProcesses; -ULONG PhTotalThreads; -ULONG PhTotalHandles; +ULONG PhTotalProcesses = 0; +ULONG PhTotalThreads = 0; +ULONG PhTotalHandles = 0; -PSYSTEM_PROCESS_INFORMATION PhDpcsProcessInformation; -PSYSTEM_PROCESS_INFORMATION PhInterruptsProcessInformation; +PSYSTEM_PROCESS_INFORMATION PhDpcsProcessInformation = NULL; +PSYSTEM_PROCESS_INFORMATION PhInterruptsProcessInformation = NULL; -ULONG64 PhCpuTotalCycleDelta; // real cycle time delta for this period -PLARGE_INTEGER PhCpuIdleCycleTime; // cycle time for Idle -PLARGE_INTEGER PhCpuSystemCycleTime; // cycle time for DPCs and Interrupts +ULONG64 PhCpuTotalCycleDelta = 0; // real cycle time delta for this period +PLARGE_INTEGER PhCpuIdleCycleTime = NULL; // cycle time for Idle +PLARGE_INTEGER PhCpuSystemCycleTime = NULL; // cycle time for DPCs and Interrupts PH_UINT64_DELTA PhCpuIdleCycleDelta; PH_UINT64_DELTA PhCpuSystemCycleDelta; //PPH_UINT64_DELTA PhCpusIdleCycleDelta; -FLOAT PhCpuKernelUsage; -FLOAT PhCpuUserUsage; -PFLOAT PhCpusKernelUsage; -PFLOAT PhCpusUserUsage; +FLOAT PhCpuKernelUsage = 0.0f; +FLOAT PhCpuUserUsage = 0.0f; +PFLOAT PhCpusKernelUsage = NULL; +PFLOAT PhCpusUserUsage = NULL; PH_UINT64_DELTA PhCpuKernelDelta; PH_UINT64_DELTA PhCpuUserDelta; PH_UINT64_DELTA PhCpuIdleDelta; -PPH_UINT64_DELTA PhCpusKernelDelta; -PPH_UINT64_DELTA PhCpusUserDelta; -PPH_UINT64_DELTA PhCpusIdleDelta; +PPH_UINT64_DELTA PhCpusKernelDelta = NULL; +PPH_UINT64_DELTA PhCpusUserDelta = NULL; +PPH_UINT64_DELTA PhCpusIdleDelta = NULL; PH_UINT64_DELTA PhIoReadDelta; PH_UINT64_DELTA PhIoWriteDelta; @@ -230,7 +230,7 @@ PH_CIRCULAR_BUFFER_ULONG64 PhMaxIoReadOtherHistory; PH_CIRCULAR_BUFFER_ULONG64 PhMaxIoWriteHistory; #endif -static PPH_HASHTABLE PhpSidFullNameCacheHashtable; +static PPH_HASHTABLE PhpSidFullNameCacheHashtable = NULL; BOOLEAN PhProcessProviderInitialization( VOID diff --git a/ProcessHacker/srvprv.c b/ProcessHacker/srvprv.c index 9539dea68c57..f238e7a640cc 100644 --- a/ProcessHacker/srvprv.c +++ b/ProcessHacker/srvprv.c @@ -136,22 +136,21 @@ VOID PhpWorkaroundWindows10ServiceTypeBug( _Inout_ LPENUM_SERVICE_STATUS_PROCESS ServieEntry ); -PPH_OBJECT_TYPE PhServiceItemType; -PPH_HASHTABLE PhServiceHashtable; +PPH_OBJECT_TYPE PhServiceItemType = NULL; +PPH_HASHTABLE PhServiceHashtable = NULL; PH_QUEUED_LOCK PhServiceHashtableLock = PH_QUEUED_LOCK_INIT; BOOLEAN PhEnableServiceNonPoll = FALSE; static BOOLEAN PhpNonPollInitialized = FALSE; static BOOLEAN PhpNonPollActive = FALSE; -static ULONG PhpNonPollGate; -static HANDLE PhpNonPollEventHandle; +static ULONG PhpNonPollGate = 0; +static HANDLE PhpNonPollEventHandle = NULL; static PH_QUEUED_LOCK PhpNonPollServiceListLock = PH_QUEUED_LOCK_INIT; -static LIST_ENTRY PhpNonPollServiceListHead; -static LIST_ENTRY PhpNonPollServicePendingListHead; +static LIST_ENTRY PhpNonPollServiceListHead = { &PhpNonPollServiceListHead, &PhpNonPollServiceListHead }; +static LIST_ENTRY PhpNonPollServicePendingListHead = { &PhpNonPollServicePendingListHead, &PhpNonPollServicePendingListHead }; static SLIST_HEADER PhpServiceQueryDataListHead; - -static _SubscribeServiceChangeNotifications SubscribeServiceChangeNotifications_I; -static _UnsubscribeServiceChangeNotifications UnsubscribeServiceChangeNotifications_I; +static _SubscribeServiceChangeNotifications SubscribeServiceChangeNotifications_I = NULL; +static _UnsubscribeServiceChangeNotifications UnsubscribeServiceChangeNotifications_I = NULL; BOOLEAN PhServiceProviderInitialization( VOID @@ -167,7 +166,7 @@ BOOLEAN PhServiceProviderInitialization( RtlInitializeSListHead(&PhpServiceQueryDataListHead); - if (WindowsVersion > WINDOWS_7) + if (WindowsVersion >= WINDOWS_8) { SubscribeServiceChangeNotifications_I = PhGetDllProcedureAddress(L"sechost.dll", "SubscribeServiceChangeNotifications", 0); UnsubscribeServiceChangeNotifications_I = PhGetDllProcedureAddress(L"sechost.dll", "UnsubscribeServiceChangeNotifications", 0); @@ -1173,9 +1172,6 @@ NTSTATUS PhpServiceNonPollThreadStart( if (!scManagerHandle) goto ErrorExit; - InitializeListHead(&PhpNonPollServiceListHead); - InitializeListHead(&PhpNonPollServicePendingListHead); - if (!(services = PhEnumServices(scManagerHandle, 0, 0, &numberOfServices))) goto ErrorExit; diff --git a/ProcessHacker/sysscmem.c b/ProcessHacker/sysscmem.c index 462909ec4968..2fe8b7ae6c13 100644 --- a/ProcessHacker/sysscmem.c +++ b/ProcessHacker/sysscmem.c @@ -296,8 +296,8 @@ INT_PTR CALLBACK PhSipMemoryDialogProc( PhInitializeLayoutManager(&MemoryLayoutManager, hwndDlg); PhAddLayoutItem(&MemoryLayoutManager, GetDlgItem(hwndDlg, IDC_TOTALPHYSICAL), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT | PH_LAYOUT_FORCE_INVALIDATE); graphItem = PhAddLayoutItem(&MemoryLayoutManager, GetDlgItem(hwndDlg, IDC_GRAPH_LAYOUT), NULL, PH_ANCHOR_ALL); - MemoryGraphMargin = graphItem->Margin; panelItem = PhAddLayoutItem(&MemoryLayoutManager, GetDlgItem(hwndDlg, IDC_LAYOUT), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); + MemoryGraphMargin = graphItem->Margin; SendMessage(GetDlgItem(hwndDlg, IDC_TITLE), WM_SETFONT, (WPARAM)MemorySection->Parameters->LargeFont, FALSE); SendMessage(GetDlgItem(hwndDlg, IDC_TOTALPHYSICAL), WM_SETFONT, (WPARAM)MemorySection->Parameters->MediumFont, FALSE); diff --git a/phlib/basesup.c b/phlib/basesup.c index 4a436709e17c..ca03dd5509c1 100644 --- a/phlib/basesup.c +++ b/phlib/basesup.c @@ -111,7 +111,7 @@ static PPH_STRING PhSharedEmptyString = NULL; static PH_FREE_LIST PhpBaseThreadContextFreeList; #ifdef DEBUG ULONG PhDbgThreadDbgTlsIndex; -LIST_ENTRY PhDbgThreadListHead; +LIST_ENTRY PhDbgThreadListHead = { &PhDbgThreadListHead, &PhDbgThreadListHead }; PH_QUEUED_LOCK PhDbgThreadListLock = PH_QUEUED_LOCK_INIT; #endif @@ -163,7 +163,6 @@ BOOLEAN PhBaseInitialization( #ifdef DEBUG PhDbgThreadDbgTlsIndex = TlsAlloc(); - InitializeListHead(&PhDbgThreadListHead); #endif return TRUE; diff --git a/phlib/extlv.c b/phlib/extlv.c index b6076971037d..58616b647778 100644 --- a/phlib/extlv.c +++ b/phlib/extlv.c @@ -107,7 +107,7 @@ VOID PhSetExtendedListView( { PPH_EXTLV_CONTEXT context; - context = PhAllocate(sizeof(PH_EXTLV_CONTEXT)); + context = PhAllocateZero(sizeof(PH_EXTLV_CONTEXT)); context->Handle = hWnd; context->Context = NULL; diff --git a/phlib/treenew.c b/phlib/treenew.c index 965ddaafc145..6ae06f2885f1 100644 --- a/phlib/treenew.c +++ b/phlib/treenew.c @@ -6366,7 +6366,7 @@ LRESULT CALLBACK PhTnpHeaderHookWndProc( break; } - return CallWindowProc(oldWndProc, hwnd, uMsg, wParam, lParam);; + return CallWindowProc(oldWndProc, hwnd, uMsg, wParam, lParam); } BOOLEAN PhTnpDetectDrag( diff --git a/plugins/UserNotes/main.c b/plugins/UserNotes/main.c index 5deffe4ab3c4..b8c7c6a38c34 100644 --- a/plugins/UserNotes/main.c +++ b/plugins/UserNotes/main.c @@ -1642,11 +1642,10 @@ INT_PTR CALLBACK ProcessCommentPageDlgProc( PDB_OBJECT object; PPH_STRING comment; - context = PhAllocate(sizeof(PROCESS_COMMENT_PAGE_CONTEXT)); + context = propPageContext->Context = PhAllocate(sizeof(PROCESS_COMMENT_PAGE_CONTEXT)); context->CommentHandle = GetDlgItem(hwndDlg, IDC_COMMENT); context->RevertHandle = GetDlgItem(hwndDlg, IDC_REVERT); context->MatchCommandlineHandle = GetDlgItem(hwndDlg, IDC_MATCHCOMMANDLINE); - propPageContext->Context = context; // Load the comment. Edit_LimitText(context->CommentHandle, UNICODE_STRING_MAX_CHARS); From 1b586fdeb409f60b96ce4319bb01a47b5bc395b6 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 15 Aug 2018 20:11:27 +1000 Subject: [PATCH 1279/2058] peview: Improve ordinal import name format --- tools/peview/impprp.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/tools/peview/impprp.c b/tools/peview/impprp.c index 078b4cdc11e8..4b59bfe52bbd 100644 --- a/tools/peview/impprp.c +++ b/tools/peview/impprp.c @@ -99,9 +99,8 @@ VOID PvpProcessImports( if (exportOrdinalName) { - name = PhFormatString(L"(Ordinal %u) [%s]", importEntry.Ordinal, exportOrdinalName->Buffer); - PhSetListViewSubItem(ListViewHandle, lvItemIndex, 2, name->Buffer); - PhDereferenceObject(name); + name = PhaFormatString(L"%s (Ordinal %u)", PhGetStringOrEmpty(exportOrdinalName), importEntry.Ordinal); + PhSetListViewSubItem(ListViewHandle, lvItemIndex, 2, PhGetString(name)); } else { @@ -131,18 +130,16 @@ VOID PvpProcessImports( PH_STRINGREF secondPart; if (PhSplitStringRefAtLastChar(&exportSymbolName->sr, L'!', &firstPart, &secondPart)) - name = PhFormatString(L"(Ordinal %u) [%s]", importEntry.Ordinal, secondPart.Buffer); + name = PhaFormatString(L"%s (Ordinal %u)", secondPart.Buffer, importEntry.Ordinal); else - name = PhFormatString(L"(Ordinal %u) [%s]", importEntry.Ordinal, exportSymbolName->Buffer); + name = PhaFormatString(L"%s (Ordinal %u)", exportSymbolName->Buffer, importEntry.Ordinal); PhSetListViewSubItem(ListViewHandle, lvItemIndex, 2, name->Buffer); - PhDereferenceObject(name); } else { - name = PhFormatString(L"(Ordinal %u)", importEntry.Ordinal); + name = PhaFormatString(L"(Ordinal %u) [??]", importEntry.Ordinal); PhSetListViewSubItem(ListViewHandle, lvItemIndex, 2, name->Buffer); - PhDereferenceObject(name); } } From 5c5cc0873b032b1656c66697ac4c073f860faf0b Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 15 Aug 2018 20:28:17 +1000 Subject: [PATCH 1280/2058] Fix property sheet window focus --- ProcessHacker/mainwnd.c | 26 +++++++++++--------------- ProcessHacker/prpghndl.c | 8 +++++--- ProcessHacker/prpgmem.c | 13 ++++++++++++- ProcessHacker/prpgmod.c | 4 +++- ProcessHacker/prpgthrd.c | 4 +++- 5 files changed, 34 insertions(+), 21 deletions(-) diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index 2efa44348977..748ef1634bb6 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -402,6 +402,17 @@ VOID PhMwpInitializeControls( ULONG treelistCustomColors; PH_TREENEW_CREATEPARAMS treelistCreateParams; + thinRows = PhGetIntegerSetting(L"ThinRows") ? TN_STYLE_THIN_ROWS : 0; + treelistBorder = (PhGetIntegerSetting(L"TreeListBorderEnable") && !PhEnableThemeSupport) ? WS_BORDER : 0; + treelistCustomColors = PhGetIntegerSetting(L"TreeListCustomColorsEnable") ? TN_STYLE_CUSTOM_COLORS : 0; + + if (treelistCustomColors) + { + treelistCreateParams.TextColor = PhGetIntegerSetting(L"TreeListCustomColorText"); + treelistCreateParams.FocusColor = PhGetIntegerSetting(L"TreeListCustomColorFocus"); + treelistCreateParams.SelectionColor = PhGetIntegerSetting(L"TreeListCustomColorSelection"); + } + TabControlHandle = CreateWindow( WC_TABCONTROL, NULL, @@ -416,18 +427,6 @@ VOID PhMwpInitializeControls( NULL ); SendMessage(TabControlHandle, WM_SETFONT, (WPARAM)PhApplicationFont, FALSE); - BringWindowToTop(TabControlHandle); - - thinRows = PhGetIntegerSetting(L"ThinRows") ? TN_STYLE_THIN_ROWS : 0; - treelistBorder = (PhGetIntegerSetting(L"TreeListBorderEnable") && !PhEnableThemeSupport) ? WS_BORDER : 0; - treelistCustomColors = PhGetIntegerSetting(L"TreeListCustomColorsEnable") ? TN_STYLE_CUSTOM_COLORS : 0; - - if (treelistCustomColors) - { - treelistCreateParams.TextColor = PhGetIntegerSetting(L"TreeListCustomColorText"); - treelistCreateParams.FocusColor = PhGetIntegerSetting(L"TreeListCustomColorFocus"); - treelistCreateParams.SelectionColor = PhGetIntegerSetting(L"TreeListCustomColorSelection"); - } PhMwpProcessTreeNewHandle = CreateWindow( PH_TREENEW_CLASSNAME, @@ -442,7 +441,6 @@ VOID PhMwpInitializeControls( PhInstanceHandle, &treelistCreateParams ); - BringWindowToTop(PhMwpProcessTreeNewHandle); PhMwpServiceTreeNewHandle = CreateWindow( PH_TREENEW_CLASSNAME, @@ -457,7 +455,6 @@ VOID PhMwpInitializeControls( PhInstanceHandle, &treelistCreateParams ); - BringWindowToTop(PhMwpServiceTreeNewHandle); PhMwpNetworkTreeNewHandle = CreateWindow( PH_TREENEW_CLASSNAME, @@ -472,7 +469,6 @@ VOID PhMwpInitializeControls( PhInstanceHandle, &treelistCreateParams ); - BringWindowToTop(PhMwpNetworkTreeNewHandle); PageList = PhCreateList(10); diff --git a/ProcessHacker/prpghndl.c b/ProcessHacker/prpghndl.c index 4de7eb9ae26a..0de1a58d4547 100644 --- a/ProcessHacker/prpghndl.c +++ b/ProcessHacker/prpghndl.c @@ -3,7 +3,7 @@ * Process properties: Handles page * * Copyright (C) 2009-2016 wj32 - * Copyright (C) 2017 dmex + * Copyright (C) 2017-2018 dmex * * This file is part of Process Hacker. * @@ -383,12 +383,11 @@ INT_PTR CALLBACK PhpProcessHandlesDlgProc( handlesContext->WindowHandle = hwndDlg; handlesContext->SearchboxHandle = GetDlgItem(hwndDlg, IDC_HANDLESEARCH); - tnHandle = GetDlgItem(hwndDlg, IDC_LIST); PhCreateSearchControl(hwndDlg, handlesContext->SearchboxHandle, L"Search Handles (Ctrl+K)"); // Initialize the list. - BringWindowToTop(tnHandle); + tnHandle = GetDlgItem(hwndDlg, IDC_LIST); PhInitializeHandleList(hwndDlg, tnHandle, &handlesContext->ListContext); TreeNew_SetEmptyText(tnHandle, &PhpLoadingText, 0); PhInitializeProviderEventQueue(&handlesContext->EventQueue, 100); @@ -621,6 +620,9 @@ INT_PTR CALLBACK PhpProcessHandlesDlgProc( case PSN_KILLACTIVE: PhSetEnabledProvider(&handlesContext->ProviderRegistration, FALSE); break; + case PSN_QUERYINITIALFOCUS: + SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, (LPARAM)GetDlgItem(hwndDlg, IDC_LIST)); + return TRUE; } } break; diff --git a/ProcessHacker/prpgmem.c b/ProcessHacker/prpgmem.c index 59b7fe33db3e..ed1a23721e48 100644 --- a/ProcessHacker/prpgmem.c +++ b/ProcessHacker/prpgmem.c @@ -335,7 +335,6 @@ INT_PTR CALLBACK PhpProcessMemoryDlgProc( // Initialize the list. tnHandle = GetDlgItem(hwndDlg, IDC_LIST); - BringWindowToTop(tnHandle); PhInitializeMemoryList(hwndDlg, tnHandle, &memoryContext->ListContext); TreeNew_SetEmptyText(tnHandle, &PhpLoadingText, 0); memoryContext->LastRunStatus = -1; @@ -753,6 +752,18 @@ INT_PTR CALLBACK PhpProcessMemoryDlgProc( } } break; + case WM_NOTIFY: + { + LPNMHDR header = (LPNMHDR)lParam; + + switch (header->code) + { + case PSN_QUERYINITIALFOCUS: + SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, (LPARAM)GetDlgItem(hwndDlg, IDC_LIST)); + return TRUE; + } + } + break; } return FALSE; diff --git a/ProcessHacker/prpgmod.c b/ProcessHacker/prpgmod.c index b69956dc4647..2750f7fb3573 100644 --- a/ProcessHacker/prpgmod.c +++ b/ProcessHacker/prpgmod.c @@ -467,7 +467,6 @@ INT_PTR CALLBACK PhpProcessModulesDlgProc( // Initialize the list. tnHandle = GetDlgItem(hwndDlg, IDC_LIST); - BringWindowToTop(tnHandle); PhInitializeModuleList(hwndDlg, tnHandle, &modulesContext->ListContext); TreeNew_SetEmptyText(tnHandle, &PhpLoadingText, 0); PhInitializeProviderEventQueue(&modulesContext->EventQueue, 100); @@ -767,6 +766,9 @@ INT_PTR CALLBACK PhpProcessModulesDlgProc( case PSN_KILLACTIVE: PhSetEnabledProvider(&modulesContext->ProviderRegistration, FALSE); break; + case PSN_QUERYINITIALFOCUS: + SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, (LPARAM)GetDlgItem(hwndDlg, IDC_LIST)); + return TRUE; } } break; diff --git a/ProcessHacker/prpgthrd.c b/ProcessHacker/prpgthrd.c index e6d59e853865..5e97592851ff 100644 --- a/ProcessHacker/prpgthrd.c +++ b/ProcessHacker/prpgthrd.c @@ -420,7 +420,6 @@ INT_PTR CALLBACK PhpProcessThreadsDlgProc( // Initialize the list. tnHandle = GetDlgItem(hwndDlg, IDC_LIST); - BringWindowToTop(tnHandle); PhInitializeThreadList(hwndDlg, tnHandle, &threadsContext->ListContext); TreeNew_SetEmptyText(tnHandle, &EmptyThreadsText, 0); PhInitializeProviderEventQueue(&threadsContext->EventQueue, 100); @@ -830,6 +829,9 @@ INT_PTR CALLBACK PhpProcessThreadsDlgProc( case PSN_KILLACTIVE: // Can't disable, it screws up the deltas. break; + case PSN_QUERYINITIALFOCUS: + SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, (LPARAM)GetDlgItem(hwndDlg, IDC_LIST)); + return TRUE; } } break; From 090a8177a317803361ecac6a5fec2ee26dff1457 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 15 Aug 2018 21:01:22 +1000 Subject: [PATCH 1281/2058] peview: Fix window icon --- tools/peview/peprp.c | 16 +++++++--------- tools/peview/prpsh.c | 7 ++++--- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/tools/peview/peprp.c b/tools/peview/peprp.c index 2aa34aa05fab..085d617089d2 100644 --- a/tools/peview/peprp.c +++ b/tools/peview/peprp.c @@ -45,8 +45,8 @@ INT_PTR CALLBACK PvpPeGeneralDlgProc( PH_MAPPED_IMAGE PvMappedImage; PIMAGE_COR20_HEADER PvImageCor20Header = NULL; PPH_SYMBOL_PROVIDER PvSymbolProvider = NULL; -static HICON PvImageSmallIcon; -static HICON PvImageLargeIcon; +HICON PvImageSmallIcon = NULL; +HICON PvImageLargeIcon = NULL; static PH_IMAGE_VERSION_INFO PvImageVersionInfo; static VERIFY_RESULT PvImageVerifyResult; static PPH_STRING PvImageSignerName; @@ -60,6 +60,11 @@ VOID PvPeProperties( PH_MAPPED_IMAGE_EXPORTS exports; PIMAGE_DATA_DIRECTORY entry; + if (!PhExtractIcon(PvFileName->Buffer, &PvImageLargeIcon, &PvImageSmallIcon)) + { + PhGetStockApplicationIcon(&PvImageSmallIcon, &PvImageLargeIcon); + } + if (PvpLoadDbgHelp(&PvSymbolProvider)) { // Load current PE pdb @@ -373,13 +378,6 @@ VOID PvpSetPeImageVersionInfo( PhInitializeImageVersionInfo(&PvImageVersionInfo, PvFileName->Buffer); - if (!PhExtractIcon(PvFileName->Buffer, &PvImageLargeIcon, &PvImageSmallIcon)) - { - PhGetStockApplicationIcon(&PvImageSmallIcon, &PvImageLargeIcon); - } - - SendMessage(GetParent(WindowHandle), WM_SETICON, ICON_BIG, (LPARAM)PvImageLargeIcon); - SendMessage(GetParent(WindowHandle), WM_SETICON, ICON_SMALL, (LPARAM)PvImageSmallIcon); Static_SetIcon(GetDlgItem(WindowHandle, IDC_FILEICON), PvImageLargeIcon); string = PhConcatStrings2(L"(Verifying...) ", PvpGetStringOrNa(PvImageVersionInfo.CompanyName)); diff --git a/tools/peview/prpsh.c b/tools/peview/prpsh.c index bd6ff160c24e..0db1b41c09bc 100644 --- a/tools/peview/prpsh.c +++ b/tools/peview/prpsh.c @@ -148,9 +148,10 @@ INT CALLBACK PvpPropSheetProc( { PPV_PROPSHEETCONTEXT context; - context = PhAllocate(sizeof(PV_PROPSHEETCONTEXT)); - memset(context, 0, sizeof(PV_PROPSHEETCONTEXT)); + SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PvImageLargeIcon); + SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PvImageSmallIcon); + context = PhAllocateZero(sizeof(PV_PROPSHEETCONTEXT)); PhInitializeLayoutManager(&context->LayoutManager, hwndDlg); context->DefaultWindowProc = (WNDPROC)GetWindowLongPtr(hwndDlg, GWLP_WNDPROC); @@ -506,4 +507,4 @@ VOID PvDoPropPageLayout( parent = GetParent(hwnd); propSheetContext = PvpGetPropSheetContext(parent); PhLayoutManagerLayout(&propSheetContext->LayoutManager); -} \ No newline at end of file +} From 0edf1a62a71cc8a745b6e137f9253b7a08b87b77 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 16 Aug 2018 00:04:43 +1000 Subject: [PATCH 1282/2058] Add default GenerateZw options --- tools/GenerateZw/GenerateZw/zw_options.txt | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 tools/GenerateZw/GenerateZw/zw_options.txt diff --git a/tools/GenerateZw/GenerateZw/zw_options.txt b/tools/GenerateZw/GenerateZw/zw_options.txt new file mode 100644 index 000000000000..9aa13c1ce994 --- /dev/null +++ b/tools/GenerateZw/GenerateZw/zw_options.txt @@ -0,0 +1,5 @@ +base=include +in=ntdbg.h;ntexapi.h;ntgdi.h;ntioapi.h;ntkeapi.h;ntldr.h;ntlpcapi.h;ntmisc.h;ntmmapi.h;ntnls.h;ntobapi.h;ntpebteb.h;ntpfapi.h;ntpnpapi.h;ntpoapi.h;ntpsapi.h;ntregapi.h;ntrtl.h;ntsam.h;ntseapi.h;nttmapi.h;nttp.h;ntwow64.h;ntxcapi.h +out=ntzwapi.h +header=#ifndef _NTZWAPI_H\r\n#define _NTZWAPI_H\r\n\r\n// This file was automatically generated. Do not edit.\r\n\r\n +footer=#endif\r\n From f1dfa33cc52a1ad6a21a9f26877246d3c08b4358 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 16 Aug 2018 00:05:32 +1000 Subject: [PATCH 1283/2058] peview: export image icons --- tools/peview/include/peview.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/peview/include/peview.h b/tools/peview/include/peview.h index 27cfedee9054..9441b1457b09 100644 --- a/tools/peview/include/peview.h +++ b/tools/peview/include/peview.h @@ -44,6 +44,8 @@ extern PPH_STRING PvFileName; extern PH_MAPPED_IMAGE PvMappedImage; extern PIMAGE_COR20_HEADER PvImageCor20Header; extern PPH_SYMBOL_PROVIDER PvSymbolProvider; +extern HICON PvImageSmallIcon; +extern HICON PvImageLargeIcon; // peprp From cb27d84ffd300f793d8ceae40dc32299e59b218b Mon Sep 17 00:00:00 2001 From: yupi2 Date: Wed, 15 Aug 2018 17:15:48 +0000 Subject: [PATCH 1284/2058] Remove extra comma from RtlDeriveCapabilitySidsFromName (#298) --- phnt/include/ntrtl.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phnt/include/ntrtl.h b/phnt/include/ntrtl.h index eace0c002ec4..e12d3fcddc36 100644 --- a/phnt/include/ntrtl.h +++ b/phnt/include/ntrtl.h @@ -5899,7 +5899,7 @@ NTAPI RtlDeriveCapabilitySidsFromName( _Inout_ PUNICODE_STRING UnicodeString, _Out_ PSID CapabilityGroupSid, - _Out_ PSID CapabilitySid, + _Out_ PSID CapabilitySid ); #endif From 73cd50432cb8e9d634b04320dff328c066249dcf Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 16 Aug 2018 05:10:13 +1000 Subject: [PATCH 1285/2058] Fix #297 --- phnt/include/ntrtl.h | 47 -------------------------------------------- 1 file changed, 47 deletions(-) diff --git a/phnt/include/ntrtl.h b/phnt/include/ntrtl.h index e12d3fcddc36..0282611645f0 100644 --- a/phnt/include/ntrtl.h +++ b/phnt/include/ntrtl.h @@ -7979,53 +7979,6 @@ RtlSetPortableOperatingSystem( #if (PHNT_VERSION >= PHNT_THRESHOLD) -#define DEVICEFAMILYINFOENUM_UAP 0x00000000 -#define DEVICEFAMILYINFOENUM_WINDOWS_8X 0x00000001 -#define DEVICEFAMILYINFOENUM_WINDOWS_PHONE_8X 0x00000002 -#define DEVICEFAMILYINFOENUM_DESKTOP 0x00000003 -#define DEVICEFAMILYINFOENUM_MOBILE 0x00000004 -#define DEVICEFAMILYINFOENUM_XBOX 0x00000005 -#define DEVICEFAMILYINFOENUM_TEAM 0x00000006 -#define DEVICEFAMILYINFOENUM_IOT 0x00000007 -#define DEVICEFAMILYINFOENUM_IOT_HEADLESS 0x00000008 -#define DEVICEFAMILYINFOENUM_SERVER 0x00000009 -#define DEVICEFAMILYINFOENUM_HOLOGRAPHIC 0x0000000A -#define DEVICEFAMILYINFOENUM_XBOXSRA 0x0000000B -#define DEVICEFAMILYINFOENUM_XBOXERA 0x0000000C -#define DEVICEFAMILYINFOENUM_MAX 0x0000000C -#define DEVICEFAMILYDEVICEFORM_UNKNOWN 0x00000000 -#define DEVICEFAMILYDEVICEFORM_PHONE 0x00000001 -#define DEVICEFAMILYDEVICEFORM_TABLET 0x00000002 -#define DEVICEFAMILYDEVICEFORM_DESKTOP 0x00000003 -#define DEVICEFAMILYDEVICEFORM_NOTEBOOK 0x00000004 -#define DEVICEFAMILYDEVICEFORM_CONVERTIBLE 0x00000005 -#define DEVICEFAMILYDEVICEFORM_DETACHABLE 0x00000006 -#define DEVICEFAMILYDEVICEFORM_ALLINONE 0x00000007 -#define DEVICEFAMILYDEVICEFORM_STICKPC 0x00000008 -#define DEVICEFAMILYDEVICEFORM_PUCK 0x00000009 -#define DEVICEFAMILYDEVICEFORM_LARGESCREEN 0x0000000A -#define DEVICEFAMILYDEVICEFORM_HMD 0x0000000B -#define DEVICEFAMILYDEVICEFORM_MAX 0x0000000B - -NTSYSAPI -VOID -NTAPI -RtlGetDeviceFamilyInfoEnum( - _Out_opt_ ULONGLONG *UAPInfo, - _Out_opt_ PULONG DeviceFamily, - _Out_opt_ PULONG DeviceForm - ); - -NTSYSAPI -ULONG -NTAPI -RtlConvertDeviceFamilyInfoToString( - _Inout_ PULONG DeviceFamilyBufferSize, - _Inout_ PULONG DeviceFormBufferSize, - _Out_writes_bytes_(*DeviceFamilyBufferSize) PWSTR DeviceFamily, - _Out_writes_bytes_(*DeviceFormBufferSize) PWSTR DeviceForm - ); - NTSYSAPI OS_DEPLOYEMENT_STATE_VALUES NTAPI From 64f9e51087dfedf8fc970cc5e484a32db732aa39 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 17 Aug 2018 11:19:38 +1000 Subject: [PATCH 1286/2058] Add PhSymbolProviderRegisterEventCallback, Add symbol cancel support --- phlib/include/symprv.h | 20 ++++++++++ phlib/include/symprvp.h | 46 ++++++++++----------- phlib/symprv.c | 88 +++++++++++++++++++++++++++-------------- 3 files changed, 102 insertions(+), 52 deletions(-) diff --git a/phlib/include/symprv.h b/phlib/include/symprv.h index 3148e8e842cc..f28404053189 100644 --- a/phlib/include/symprv.h +++ b/phlib/include/symprv.h @@ -16,6 +16,7 @@ typedef struct _PH_SYMBOL_PROVIDER HANDLE ProcessHandle; BOOLEAN IsRealHandle; BOOLEAN IsRegistered; + BOOLEAN Terminating; PH_INITONCE InitOnce; PH_AVL_TREE ModulesSet; @@ -55,6 +56,7 @@ typedef enum _PH_SYMBOL_EVENT_TYPE typedef struct _PH_SYMBOL_EVENT_DATA { + HANDLE ProcessHandle; PPH_SYMBOL_PROVIDER SymbolProvider; PH_SYMBOL_EVENT_TYPE Type; @@ -289,6 +291,24 @@ PhUndecorateSymbolName( _In_ PWSTR DecoratedName ); +PHLIBAPI +VOID +NTAPI +PhSymbolProviderRegisterEventCallback( + _In_ PPH_SYMBOL_PROVIDER SymbolProvider, + _In_ PPH_CALLBACK_FUNCTION Function, + _In_opt_ PVOID Context, + _Out_ PPH_CALLBACK_REGISTRATION Registration + ); + +PHLIBAPI +VOID +NTAPI +PhSymbolProviderUnregisterEventCallback( + _In_ PPH_SYMBOL_PROVIDER SymbolProvider, + _In_ PPH_CALLBACK_REGISTRATION Registration + ); + #ifdef __cplusplus } #endif diff --git a/phlib/include/symprvp.h b/phlib/include/symprvp.h index 84fbc5528305..880e14a00c72 100644 --- a/phlib/include/symprvp.h +++ b/phlib/include/symprvp.h @@ -2,17 +2,17 @@ #define _PH_SYMPRVP_H typedef BOOL (WINAPI *_SymInitializeW)( - _In_ HANDLE hProcess, + _In_ HANDLE ProcessHandle, _In_opt_ PCWSTR UserSearchPath, _In_ BOOL fInvadeProcess ); typedef BOOL (WINAPI *_SymCleanup)( - _In_ HANDLE hProcess + _In_ HANDLE ProcessHandle ); typedef BOOL (WINAPI *_SymEnumSymbolsW)( - _In_ HANDLE hProcess, + _In_ HANDLE ProcessHandle, _In_ ULONG64 BaseOfDll, _In_opt_ PCWSTR Mask, _In_ PSYM_ENUMERATESYMBOLS_CALLBACKW EnumSymbolsCallback, @@ -20,48 +20,48 @@ typedef BOOL (WINAPI *_SymEnumSymbolsW)( ); typedef BOOL (WINAPI *_SymFromAddrW)( - _In_ HANDLE hProcess, + _In_ HANDLE ProcessHandle, _In_ ULONG64 Address, _Out_opt_ PULONG64 Displacement, _Inout_ PSYMBOL_INFOW Symbol ); typedef BOOL (WINAPI *_SymFromNameW)( - _In_ HANDLE hProcess, + _In_ HANDLE ProcessHandle, _In_ PCWSTR Name, _Inout_ PSYMBOL_INFOW Symbol ); typedef BOOL (WINAPI *_SymEnumTypesW)( - _In_ HANDLE hProcess, + _In_ HANDLE ProcessHandle, _In_ ULONG64 BaseOfDll, _In_ PSYM_ENUMERATESYMBOLS_CALLBACKW EnumSymbolsCallback, _In_opt_ PVOID UserContext ); typedef BOOL (WINAPI *_SymGetModuleInfoW64)( - _In_ HANDLE hProcess, + _In_ HANDLE ProcessHandle, _In_ ULONG64 qwAddr, _Out_ PIMAGEHLP_MODULEW64 ModuleInfo ); typedef BOOL(WINAPI *_SymGetTypeFromNameW)( - _In_ HANDLE hProcess, + _In_ HANDLE ProcessHandle, _In_ ULONG64 BaseOfDll, _In_ PCWSTR Name, _Inout_ PSYMBOL_INFOW Symbol ); typedef BOOL (WINAPI *_SymGetLineFromAddrW64)( - _In_ HANDLE hProcess, + _In_ HANDLE ProcessHandle, _In_ ULONG64 dwAddr, _Out_ PULONG pdwDisplacement, _Out_ PIMAGEHLP_LINEW64 Line ); typedef ULONG64 (WINAPI *_SymLoadModuleExW)( - _In_ HANDLE hProcess, - _In_opt_ HANDLE hFile, + _In_ HANDLE ProcessHandle, + _In_opt_ HANDLE FileHandle, _In_ PCWSTR ImageName, _In_ PCWSTR ModuleName, _In_ ULONG64 BaseOfDll, @@ -77,41 +77,41 @@ typedef ULONG (WINAPI *_SymSetOptions)( ); typedef BOOL (WINAPI *_SymGetSearchPathW)( - _In_ HANDLE hProcess, + _In_ HANDLE ProcessHandle, _Out_ PWSTR SearchPath, _In_ ULONG SearchPathLength ); typedef BOOL (WINAPI *_SymSetSearchPathW)( - _In_ HANDLE hProcess, + _In_ HANDLE ProcessHandle, _In_opt_ PCWSTR SearchPath ); typedef BOOL (WINAPI *_SymUnloadModule64)( - _In_ HANDLE hProcess, + _In_ HANDLE ProcessHandle, _In_ ULONG64 BaseOfDll ); typedef PVOID (WINAPI *_SymFunctionTableAccess64)( - _In_ HANDLE hProcess, + _In_ HANDLE ProcessHandle, _In_ ULONG64 AddrBase ); typedef ULONG64 (WINAPI *_SymGetModuleBase64)( - _In_ HANDLE hProcess, + _In_ HANDLE ProcessHandle, _In_ ULONG64 dwAddr ); typedef BOOL (WINAPI *_SymRegisterCallbackW64)( - _In_ HANDLE hProcess, + _In_ HANDLE ProcessHandle, _In_ PSYMBOL_REGISTERED_CALLBACK64 CallbackFunction, - _In_ ULONG64 UserContext + _In_ PVOID UserContext ); typedef BOOL (WINAPI *_StackWalk64)( _In_ ULONG MachineType, - _In_ HANDLE hProcess, - _In_ HANDLE hThread, + _In_ HANDLE ProcessHandle, + _In_ HANDLE ThreadHandle, _Inout_ LPSTACKFRAME64 StackFrame, _Inout_ PVOID ContextRecord, _In_opt_ PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine, @@ -121,9 +121,9 @@ typedef BOOL (WINAPI *_StackWalk64)( ); typedef BOOL (WINAPI *_MiniDumpWriteDump)( - _In_ HANDLE hProcess, + _In_ HANDLE ProcessHandle, _In_ ULONG ProcessId, - _In_ HANDLE hFile, + _In_ HANDLE FileHandle, _In_ MINIDUMP_TYPE DumpType, _In_ PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, _In_ PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam, @@ -146,4 +146,4 @@ typedef ULONG (WINAPI *_UnDecorateSymbolNameW)( _In_ ULONG Flags ); -#endif \ No newline at end of file +#endif diff --git a/phlib/symprv.c b/phlib/symprv.c index f2d676cc28ee..86cce8cdf2c2 100644 --- a/phlib/symprv.c +++ b/phlib/symprv.c @@ -188,52 +188,51 @@ NTSTATUS PhpSymbolCallbackWorker( { PPH_SYMBOL_EVENT_DATA data = Parameter; - dprintf("symbol event %d: %S\n", data->Type, data->FileName->Buffer); + //dprintf("symbol event %d: %S\n", data->Type, data->FileName->Buffer); PhInvokeCallback(&data->SymbolProvider->EventCallback, data); - PhClearReference(&data->FileName); + + if (data->FileName) PhDereferenceObject(data->FileName); PhDereferenceObject(data); return STATUS_SUCCESS; } BOOL CALLBACK PhpSymbolCallbackFunction( - _In_ HANDLE hProcess, + _In_ HANDLE ProcessHandle, _In_ ULONG ActionCode, _In_opt_ ULONG64 CallbackData, _In_opt_ ULONG64 UserContext ) { + PIMAGEHLP_DEFERRED_SYMBOL_LOADW64 callbackData = (PIMAGEHLP_DEFERRED_SYMBOL_LOADW64)CallbackData; PPH_SYMBOL_PROVIDER symbolProvider = (PPH_SYMBOL_PROVIDER)UserContext; - PPH_SYMBOL_EVENT_DATA data; - PIMAGEHLP_DEFERRED_SYMBOL_LOADW64 callbackData; + + assert(ProcessHandle == symbolProvider->ProcessHandle); if (!IsListEmpty(&symbolProvider->EventCallback.ListHead)) { - switch (ActionCode) - { - case SymbolDeferredSymbolLoadStart: // CBA_DEFERRED_SYMBOL_LOAD_START - case SymbolDeferredSymbolLoadComplete: // CBA_DEFERRED_SYMBOL_LOAD_COMPLETE - case SymbolDeferredSymbolLoadFailure: // CBA_DEFERRED_SYMBOL_LOAD_FAILURE - case SymbolSymbolsUnloaded: // CBA_SYMBOLS_UNLOADED - case SymbolDeferredSymbolLoadCancel: // CBA_DEFERRED_SYMBOL_LOAD_CANCEL - data = PhCreateAlloc(sizeof(PH_SYMBOL_EVENT_DATA)); - memset(data, 0, sizeof(PH_SYMBOL_EVENT_DATA)); - data->SymbolProvider = symbolProvider; - data->Type = ActionCode; - - if (ActionCode != SymbolSymbolsUnloaded) - { - callbackData = (PIMAGEHLP_DEFERRED_SYMBOL_LOADW64)CallbackData; - data->BaseAddress = callbackData->BaseOfImage; - data->CheckSum = callbackData->CheckSum; - data->TimeStamp = callbackData->TimeDateStamp; - data->FileName = PhCreateString(callbackData->FileName); - } + PPH_SYMBOL_EVENT_DATA data; - PhQueueItemWorkQueue(PhGetGlobalWorkQueue(), PhpSymbolCallbackWorker, data); + data = PhCreateAlloc(sizeof(PH_SYMBOL_EVENT_DATA)); + memset(data, 0, sizeof(PH_SYMBOL_EVENT_DATA)); - break; - } + data->Type = ActionCode; + data->ProcessHandle = ProcessHandle; + data->SymbolProvider = symbolProvider; + data->BaseAddress = callbackData->BaseOfImage; + data->CheckSum = callbackData->CheckSum; + data->TimeStamp = callbackData->TimeDateStamp; + + if (callbackData->FileName[0]) + data->FileName = PhCreateString(callbackData->FileName); + + PhQueueItemWorkQueue(PhGetGlobalWorkQueue(), PhpSymbolCallbackWorker, data); + } + + if (ActionCode == CBA_DEFERRED_SYMBOL_LOAD_CANCEL) + { + if (symbolProvider->Terminating) // HACK + return TRUE; } return FALSE; @@ -385,7 +384,7 @@ VOID PhpRegisterSymbolProvider( SymInitializeW_I(SymbolProvider->ProcessHandle, NULL, FALSE); if (SymRegisterCallbackW64_I) - SymRegisterCallbackW64_I(SymbolProvider->ProcessHandle, PhpSymbolCallbackFunction, (ULONG64)SymbolProvider); + SymRegisterCallbackW64_I(SymbolProvider->ProcessHandle, PhpSymbolCallbackFunction, SymbolProvider); PH_UNLOCK_SYMBOLS(); @@ -1719,3 +1718,34 @@ PPH_STRING PhUndecorateSymbolName( return undecoratedSymbolName; } + +VOID PhSymbolProviderRegisterEventCallback( + _In_ PPH_SYMBOL_PROVIDER SymbolProvider, + _In_ PPH_CALLBACK_FUNCTION Function, + _In_opt_ PVOID Context, + _Out_ PPH_CALLBACK_REGISTRATION Registration + ) +{ + //PH_LOCK_SYMBOLS(); + + PhRegisterCallback( + &SymbolProvider->EventCallback, + Function, + Context, + Registration + ); + + //PH_UNLOCK_SYMBOLS(); +} + +VOID PhSymbolProviderUnregisterEventCallback( + _In_ PPH_SYMBOL_PROVIDER SymbolProvider, + _In_ PPH_CALLBACK_REGISTRATION Registration + ) +{ + //PH_LOCK_SYMBOLS(); + + PhUnregisterCallback(&SymbolProvider->EventCallback, Registration); + + //PH_UNLOCK_SYMBOLS(); +} From efc980e83fe0bfbd6c45e87eb44a3a35999d8813 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 17 Aug 2018 11:23:41 +1000 Subject: [PATCH 1287/2058] Update thread stack progress dialog to task dialog --- ProcessHacker/thrdstk.c | 599 +++++++++++++++++++++++++++++----------- 1 file changed, 433 insertions(+), 166 deletions(-) diff --git a/ProcessHacker/thrdstk.c b/ProcessHacker/thrdstk.c index 57af13151de6..5a645d64c2d0 100644 --- a/ProcessHacker/thrdstk.c +++ b/ProcessHacker/thrdstk.c @@ -3,7 +3,7 @@ * thread stack viewer * * Copyright (C) 2010-2016 wj32 - * Copyright (C) 2017 dmex + * Copyright (C) 2017-2018 dmex * * This file is part of Process Hacker. * @@ -35,10 +35,13 @@ #include #include +#include + #define WM_PH_COMPLETED (WM_APP + 301) -#define WM_PH_STATUS_UPDATE (WM_APP + 302) +//#define WM_PH_STATUS_UPDATE (WM_APP + 302) #define WM_PH_SHOWSTACKMENU (WM_APP + 303) +static PPH_OBJECT_TYPE PhThreadStackContextType = NULL; static RECT MinimumSize = { -1, -1, -1, -1 }; typedef struct _PH_THREAD_STACK_CONTEXT @@ -48,14 +51,19 @@ typedef struct _PH_THREAD_STACK_CONTEXT HANDLE ThreadHandle; PPH_THREAD_PROVIDER ThreadProvider; PPH_SYMBOL_PROVIDER SymbolProvider; - BOOLEAN CustomWalk; + BOOLEAN CustomWalk; BOOLEAN StopWalk; + BOOLEAN EnableCloseDialog; + PPH_LIST List; PPH_LIST NewList; - HWND ProgressWindowHandle; + + HWND TaskDialogHandle; + NTSTATUS WalkStatus; PPH_STRING StatusMessage; + PPH_STRING StatusContent; PH_QUEUED_LOCK StatusLock; PH_LAYOUT_MANAGER LayoutManager; @@ -67,6 +75,8 @@ typedef struct _PH_THREAD_STACK_CONTEXT PPH_HASHTABLE NodeHashtable; PPH_LIST NodeList; PPH_LIST NodeRootList; + WNDPROC ThreadStackStatusDefaultWindowProc; + PH_CALLBACK_REGISTRATION SymbolProviderEventRegistration; } PH_THREAD_STACK_CONTEXT, *PPH_THREAD_STACK_CONTEXT; typedef struct _THREAD_STACK_ITEM @@ -129,13 +139,6 @@ NTSTATUS PhpRefreshThreadStack( _In_ PPH_THREAD_STACK_CONTEXT ThreadStackContext ); -INT_PTR CALLBACK PhpThreadStackProgressDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - #define SORT_FUNCTION(Column) ThreadStackTreeNewCompare##Column #define BEGIN_SORT_FUNCTION(Column) static int __cdecl ThreadStackTreeNewCompare##Column( \ _In_ void *_context, \ @@ -669,6 +672,164 @@ VOID DeleteThreadStackTree( PhDereferenceObject(Context->NodeList); } +typedef struct _PH_THREAD_SYMBOL_STACK_CONTEXT +{ + HANDLE ProcessId; + PPH_SYMBOL_PROVIDER SymbolProvider; +} PH_THREAD_SYMBOL_STACK_CONTEXT, *PPH_THREAD_SYMBOL_STACK_CONTEXT; + +static BOOLEAN LoadSymbolsEnumGenericModulesCallback( + _In_ PPH_MODULE_INFO Module, + _In_opt_ PVOID Context + ) +{ + PPH_THREAD_SYMBOL_STACK_CONTEXT context = Context; + PPH_SYMBOL_PROVIDER symbolProvider = context->SymbolProvider; + + if (symbolProvider->Terminating) + return FALSE; + + // If we're loading kernel module symbols for a process other than System, ignore modules which + // are in user space. This may happen in Windows 7. + if (context->ProcessId == SYSTEM_PROCESS_ID && + (ULONG_PTR)Module->BaseAddress <= PhSystemBasicInformation.MaximumUserModeAddress) + { + return TRUE; + } + + PhLoadModuleSymbolProvider( + symbolProvider, + Module->FileName->Buffer, + (ULONG64)Module->BaseAddress, + Module->Size + ); + + return TRUE; +} + +static BOOLEAN LoadBasicSymbolsEnumGenericModulesCallback( + _In_ PPH_MODULE_INFO Module, + _In_opt_ PVOID Context + ) +{ + PPH_THREAD_SYMBOL_STACK_CONTEXT context = Context; + PPH_SYMBOL_PROVIDER symbolProvider = context->SymbolProvider; + + if (symbolProvider->Terminating) + return FALSE; + + if (PhEqualString2(Module->Name, L"ntdll.dll", TRUE) || + PhEqualString2(Module->Name, L"kernel32.dll", TRUE)) + { + PhLoadModuleSymbolProvider( + symbolProvider, + Module->FileName->Buffer, + (ULONG64)Module->BaseAddress, + Module->Size + ); + } + + return TRUE; +} + +VOID PhpLoadThreadStackSymbols( + _In_ HANDLE ProcessId, + _In_ PPH_SYMBOL_PROVIDER SymbolProvider + ) +{ + PH_THREAD_SYMBOL_STACK_CONTEXT loadContext; + + loadContext.SymbolProvider = SymbolProvider; + + if (ProcessId != SYSTEM_IDLE_PROCESS_ID) + { + if (SymbolProvider->IsRealHandle || ProcessId == SYSTEM_PROCESS_ID) + { + loadContext.ProcessId = ProcessId; + PhEnumGenericModules( + ProcessId, + SymbolProvider->ProcessHandle, + 0, + LoadSymbolsEnumGenericModulesCallback, + &loadContext + ); + } + else + { + // We can't enumerate the process modules. Load symbols for ntdll.dll and kernel32.dll. + loadContext.ProcessId = NtCurrentProcessId(); + PhEnumGenericModules( + NtCurrentProcessId(), + NtCurrentProcess(), + 0, + LoadBasicSymbolsEnumGenericModulesCallback, + &loadContext + ); + } + + // Load kernel module symbols as well. + if (ProcessId != SYSTEM_PROCESS_ID) + { + loadContext.ProcessId = SYSTEM_PROCESS_ID; + PhEnumGenericModules( + SYSTEM_PROCESS_ID, + NULL, + 0, + LoadSymbolsEnumGenericModulesCallback, + &loadContext + ); + } + } + else + { + // System Idle Process has one thread for each CPU, each having a start address at + // KiIdleLoop. We need to load symbols for the kernel. + + PRTL_PROCESS_MODULES kernelModules; + + if (NT_SUCCESS(PhEnumKernelModules(&kernelModules))) + { + if (kernelModules->NumberOfModules > 0) + { + PPH_STRING fileName; + PPH_STRING newFileName; + + fileName = PhConvertMultiByteToUtf16(kernelModules->Modules[0].FullPathName); + newFileName = PhGetFileName(fileName); + PhDereferenceObject(fileName); + + PhLoadModuleSymbolProvider( + SymbolProvider, + newFileName->Buffer, + (ULONG64)kernelModules->Modules[0].ImageBase, + kernelModules->Modules[0].ImageSize + ); + PhDereferenceObject(newFileName); + } + + PhFree(kernelModules); + } + } +} + +VOID NTAPI PhpThreadStackContextDeleteProcedure( + _In_ PVOID Object, + _In_ ULONG Flags + ) +{ + PPH_THREAD_STACK_CONTEXT context = (PPH_THREAD_STACK_CONTEXT)Object; + + PhDereferenceObject(context->ThreadProvider); + PhDereferenceObject(context->SymbolProvider); + + PhDereferenceObject(context->StatusMessage); + PhDereferenceObject(context->NewList); + PhDereferenceObject(context->List); + + if (context->ThreadHandle) + NtClose(context->ThreadHandle); +} + VOID PhShowThreadStackDialog( _In_ HWND ParentWindowHandle, _In_ HANDLE ProcessId, @@ -676,9 +837,10 @@ VOID PhShowThreadStackDialog( _In_ PPH_THREAD_PROVIDER ThreadProvider ) { + static PH_INITONCE initOnce = PH_INITONCE_INIT; NTSTATUS status; - PH_THREAD_STACK_CONTEXT threadStackContext; - HANDLE threadHandle = NULL; + HANDLE threadHandle; + PPH_THREAD_STACK_CONTEXT context; // If the user is trying to view a system thread stack // but KProcessHacker is not loaded, show an error message. @@ -688,12 +850,6 @@ VOID PhShowThreadStackDialog( return; } - memset(&threadStackContext, 0, sizeof(PH_THREAD_STACK_CONTEXT)); - threadStackContext.ProcessId = ProcessId; - threadStackContext.ThreadId = ThreadId; - threadStackContext.ThreadProvider = ThreadProvider; - threadStackContext.SymbolProvider = ThreadProvider->SymbolProvider; - if (!NT_SUCCESS(status = PhOpenThread( &threadHandle, THREAD_QUERY_INFORMATION | THREAD_GET_CONTEXT | THREAD_SUSPEND_RESUME, @@ -712,32 +868,41 @@ VOID PhShowThreadStackDialog( if (!NT_SUCCESS(status)) { - PhShowStatus(ParentWindowHandle, L"Unable to open the thread", status, 0); + PhShowStatus(ParentWindowHandle, L"Unable to open the thread.", status, 0); return; } - threadStackContext.ThreadHandle = threadHandle; - threadStackContext.List = PhCreateList(10); - threadStackContext.NewList = PhCreateList(10); - PhInitializeQueuedLock(&threadStackContext.StatusLock); + if (PhBeginInitOnce(&initOnce)) + { + PhThreadStackContextType = PhCreateObjectType(L"ThreadStackContext", 0, PhpThreadStackContextDeleteProcedure); + PhEndInitOnce(&initOnce); + } + + context = PhCreateObject(sizeof(PH_THREAD_STACK_CONTEXT), PhThreadStackContextType); + memset(context, 0, sizeof(PH_THREAD_STACK_CONTEXT)); + + context->List = PhCreateList(10); + context->NewList = PhCreateList(10); + PhInitializeQueuedLock(&context->StatusLock); + + context->ThreadHandle = threadHandle; + context->ProcessId = ProcessId; + context->ThreadId = ThreadId; + context->ThreadProvider = PhReferenceObject(ThreadProvider); + context->SymbolProvider = PhReferenceObject(ThreadProvider->SymbolProvider); + //context->SymbolProvider = PhCreateSymbolProvider(ProcessId); + //PhpLoadThreadStackSymbols(ProcessId, context->SymbolProvider); DialogBoxParam( PhInstanceHandle, MAKEINTRESOURCE(IDD_THRDSTACK), ParentWindowHandle, PhpThreadStackDlgProc, - (LPARAM)&threadStackContext + (LPARAM)context ); - - PhClearReference(&threadStackContext.StatusMessage); - PhDereferenceObject(threadStackContext.NewList); - PhDereferenceObject(threadStackContext.List); - - if (threadStackContext.ThreadHandle) - NtClose(threadStackContext.ThreadHandle); } -static INT_PTR CALLBACK PhpThreadStackDlgProc( +INT_PTR CALLBACK PhpThreadStackDlgProc( _In_ HWND hwndDlg, _In_ UINT uMsg, _In_ WPARAM wParam, @@ -847,6 +1012,7 @@ static INT_PTR CALLBACK PhpThreadStackDlgProc( PhSaveWindowPlacementToSetting(NULL, L"ThreadStackWindowSize", hwndDlg); PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); + PhDereferenceObject(context); } break; case WM_COMMAND: @@ -929,93 +1095,15 @@ static INT_PTR CALLBACK PhpThreadStackDlgProc( return FALSE; } -static VOID PhpFreeThreadStackItem( +VOID PhpFreeThreadStackItem( _In_ PTHREAD_STACK_ITEM StackItem ) { - PhClearReference(&StackItem->Symbol); + if (StackItem->Symbol) PhDereferenceObject(StackItem->Symbol); PhFree(StackItem); } -static NTSTATUS PhpRefreshThreadStack( - _In_ HWND hwnd, - _In_ PPH_THREAD_STACK_CONTEXT Context - ) -{ - ULONG i; - - Context->StopWalk = FALSE; - PhMoveReference(&Context->StatusMessage, PhCreateString(L"Loading stack...")); - - DialogBoxParam( - PhInstanceHandle, - MAKEINTRESOURCE(IDD_PROGRESS), - hwnd, - PhpThreadStackProgressDlgProc, - (LPARAM)Context - ); - - if (!Context->StopWalk && NT_SUCCESS(Context->WalkStatus)) - { - for (i = 0; i < Context->List->Count; i++) - PhpFreeThreadStackItem(Context->List->Items[i]); - - PhDereferenceObject(Context->List); - Context->List = Context->NewList; - Context->NewList = PhCreateList(10); - - ClearThreadStackTree(Context); - - for (i = 0; i < Context->List->Count; i++) - { - PTHREAD_STACK_ITEM item = Context->List->Items[i]; - PPH_STACK_TREE_ROOT_NODE stackNode; - - stackNode = AddThreadStackNode(Context, item->Index); - stackNode->StackFrame = item->StackFrame; - - if (!PhIsNullOrEmptyString(item->Symbol)) - stackNode->SymbolString = PhReferenceObject(item->Symbol); - - if (item->StackFrame.StackAddress) - PhPrintPointer(stackNode->StackAddressString, item->StackFrame.StackAddress); - if (item->StackFrame.FrameAddress) - PhPrintPointer(stackNode->FrameAddressString, item->StackFrame.FrameAddress); - - // There are no params for kernel-mode stack traces. - if ((ULONG_PTR)item->StackFrame.PcAddress <= PhSystemBasicInformation.MaximumUserModeAddress) - { - PhPrintPointer(stackNode->Parameter1String, item->StackFrame.Params[0]); - PhPrintPointer(stackNode->Parameter2String, item->StackFrame.Params[1]); - PhPrintPointer(stackNode->Parameter3String, item->StackFrame.Params[2]); - PhPrintPointer(stackNode->Parameter4String, item->StackFrame.Params[3]); - } - - if (item->StackFrame.PcAddress) - PhPrintPointer(stackNode->PcAddressString, item->StackFrame.PcAddress); - if (item->StackFrame.ReturnAddress) - PhPrintPointer(stackNode->ReturnAddressString, item->StackFrame.ReturnAddress); - - UpdateThreadStackNode(Context, stackNode); - } - - TreeNew_NodesStructured(Context->TreeNewHandle); - } - else - { - for (i = 0; i < Context->NewList->Count; i++) - PhpFreeThreadStackItem(Context->NewList->Items[i]); - - PhClearList(Context->NewList); - } - - if (Context->StopWalk) - return STATUS_ABANDONED; - - return Context->WalkStatus; -} - -static BOOLEAN NTAPI PhpWalkThreadStackCallback( +BOOLEAN NTAPI PhpWalkThreadStackCallback( _In_ PPH_THREAD_STACK_FRAME StackFrame, _In_opt_ PVOID Context ) @@ -1028,10 +1116,8 @@ static BOOLEAN NTAPI PhpWalkThreadStackCallback( return FALSE; PhAcquireQueuedLockExclusive(&threadStackContext->StatusLock); - PhMoveReference(&threadStackContext->StatusMessage, - PhFormatString(L"Processing frame %u...", threadStackContext->NewList->Count)); + PhMoveReference(&threadStackContext->StatusMessage, PhFormatString(L"Processing stack frame %u...", threadStackContext->NewList->Count)); PhReleaseQueuedLockExclusive(&threadStackContext->StatusLock); - PostMessage(threadStackContext->ProgressWindowHandle, WM_PH_STATUS_UPDATE, 0, 0); symbol = PhGetSymbolFromAddress( threadStackContext->SymbolProvider, @@ -1049,7 +1135,7 @@ static BOOLEAN NTAPI PhpWalkThreadStackCallback( PhMoveReference(&symbol, PhConcatStrings2(symbol->Buffer, L" (No unwind info)")); } - item = PhAllocate(sizeof(THREAD_STACK_ITEM)); + item = PhAllocateZero(sizeof(THREAD_STACK_ITEM)); item->StackFrame = *StackFrame; item->Index = threadStackContext->NewList->Count; @@ -1072,7 +1158,7 @@ static BOOLEAN NTAPI PhpWalkThreadStackCallback( return TRUE; } -static NTSTATUS PhpRefreshThreadStackThreadStart( +NTSTATUS PhpRefreshThreadStackThreadStart( _In_ PVOID Parameter ) { @@ -1143,14 +1229,16 @@ static NTSTATUS PhpRefreshThreadStackThreadStart( status = STATUS_SUCCESS; threadStackContext->WalkStatus = status; - PostMessage(threadStackContext->ProgressWindowHandle, WM_PH_COMPLETED, 0, 0); + PostMessage(threadStackContext->TaskDialogHandle, WM_PH_COMPLETED, 0, 0); PhDeleteAutoPool(&autoPool); + PhDereferenceObject(threadStackContext); + return STATUS_SUCCESS; } -static INT_PTR CALLBACK PhpThreadStackProgressDlgProc( +LRESULT CALLBACK PhpThreadStackTaskDialogSubclassProc( _In_ HWND hwndDlg, _In_ UINT uMsg, _In_ WPARAM wParam, @@ -1158,83 +1246,262 @@ static INT_PTR CALLBACK PhpThreadStackProgressDlgProc( ) { PPH_THREAD_STACK_CONTEXT context; + WNDPROC oldWndProc; - if (uMsg == WM_INITDIALOG) + if (!(context = PhGetWindowContext(hwndDlg, 0xF))) + return 0; + + oldWndProc = context->ThreadStackStatusDefaultWindowProc; + + switch (uMsg) { - context = (PPH_THREAD_STACK_CONTEXT)lParam; - PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context); + case WM_DESTROY: + { + SetWindowLongPtr(hwndDlg, GWLP_WNDPROC, (LONG_PTR)oldWndProc); + PhRemoveWindowContext(hwndDlg, 0xF); + } + break; + case WM_PH_COMPLETED: + { + context->EnableCloseDialog = TRUE; + + SendMessage(hwndDlg, TDM_CLICK_BUTTON, IDOK, 0); + } + break; } - else + + return CallWindowProc(oldWndProc, hwndDlg, uMsg, wParam, lParam); +} + +VOID PhpSymbolProviderEventCallbackHandler( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + PPH_SYMBOL_EVENT_DATA data = Parameter; + PPH_THREAD_STACK_CONTEXT context = Context; + PPH_STRING statusMessage = NULL; + + switch (data->Type) { - context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); + case CBA_DEFERRED_SYMBOL_LOAD_START: + statusMessage = PhFormatString(L"Loading %s...", PhGetBaseName(data->FileName)->Buffer); + break; + case CBA_DEFERRED_SYMBOL_LOAD_COMPLETE: + statusMessage = PhFormatString(L"Loaded %s...", PhGetBaseName(data->FileName)->Buffer); + break; + case CBA_DEFERRED_SYMBOL_LOAD_FAILURE: + statusMessage = PhFormatString(L"Failed %s...", PhGetBaseName(data->FileName)->Buffer); + break; + case CBA_SYMBOLS_UNLOADED: + statusMessage = PhFormatString(L"Unloaded %s...", data->FileName->Buffer); + break; + case CBA_READ_MEMORY: + //statusMessage = PhFormatString(L"Reading memory: %I64u (FileNameImageAddress: %s)", data->BaseAddress); + break; + case CBA_DEFERRED_SYMBOL_LOAD_CANCEL: + //statusMessage = PhFormatString(L"Canceled: %s", data->FileName->Buffer); + break; + default: + //statusMessage = PhFormatString(L"Unknown: %lu", data->Type); + break; } - if (!context) - return FALSE; + if (statusMessage) + { + PhAcquireQueuedLockExclusive(&context->StatusLock); + PhMoveReference(&context->StatusContent, statusMessage); + PhReleaseQueuedLockExclusive(&context->StatusLock); + //dprintf("SymbolProviderEventCallback: %S\r\n", statusMessage->Buffer); + } +} + +HRESULT CALLBACK PhpThreadStackTaskDialogCallback( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam, + _In_ LONG_PTR dwRefData + ) +{ + PPH_THREAD_STACK_CONTEXT context = (PPH_THREAD_STACK_CONTEXT)dwRefData; switch (uMsg) { - case WM_INITDIALOG: + case TDN_CREATED: { - HANDLE threadHandle; + context->TaskDialogHandle = hwndDlg; + + PhSymbolProviderRegisterEventCallback( + context->SymbolProvider, + PhpSymbolProviderEventCallbackHandler, + context, + &context->SymbolProviderEventRegistration + ); - context->ProgressWindowHandle = hwndDlg; - - if (threadHandle = PhCreateThread(0, PhpRefreshThreadStackThreadStart, context)) - { - NtClose(threadHandle); - } - else - { - context->WalkStatus = STATUS_UNSUCCESSFUL; - EndDialog(hwndDlg, IDOK); - break; - } + SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER))); + SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER))); + SendMessage(hwndDlg, TDM_UPDATE_ICON, TDIE_ICON_MAIN, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER))); - PhCenterWindow(hwndDlg, GetParent(hwndDlg)); + SendMessage(hwndDlg, TDM_SET_MARQUEE_PROGRESS_BAR, TRUE, 0); + SendMessage(hwndDlg, TDM_SET_PROGRESS_BAR_MARQUEE, TRUE, 1); - PhSetWindowStyle(GetDlgItem(hwndDlg, IDC_PROGRESS), PBS_MARQUEE, PBS_MARQUEE); - SendMessage(GetDlgItem(hwndDlg, IDC_PROGRESS), PBM_SETMARQUEE, TRUE, 75); - SetWindowText(hwndDlg, L"Loading stack..."); + context->ThreadStackStatusDefaultWindowProc = (WNDPROC)GetWindowLongPtr(hwndDlg, GWLP_WNDPROC); + PhSetWindowContext(hwndDlg, 0xF, context); + SetWindowLongPtr(hwndDlg, GWLP_WNDPROC, (LONG_PTR)PhpThreadStackTaskDialogSubclassProc); + + PhReferenceObject(context); + PhCreateThread2(PhpRefreshThreadStackThreadStart, context); } break; - case WM_DESTROY: + case TDN_DESTROYED: { - PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); + PhSymbolProviderUnregisterEventCallback(context->SymbolProvider, &context->SymbolProviderEventRegistration); } break; - case WM_COMMAND: + case TDN_BUTTON_CLICKED: { - switch (LOWORD(wParam)) + if ((INT)wParam == IDCANCEL) { - case IDCANCEL: - { - EnableWindow(GetDlgItem(hwndDlg, IDCANCEL), FALSE); - context->StopWalk = TRUE; - } - break; + context->StopWalk = TRUE; + //context->SymbolProvider->Terminating = TRUE; // HACK: Cancel symbol load/download. } + + //if (!context->EnableCloseDialog) + // return S_FALSE; } break; - case WM_PH_COMPLETED: - { - EndDialog(hwndDlg, IDOK); - } - break; - case WM_PH_STATUS_UPDATE: + case TDN_TIMER: { PPH_STRING message; + PPH_STRING content; PhAcquireQueuedLockExclusive(&context->StatusLock); + message = context->StatusMessage; - PhReferenceObject(message); + content = context->StatusContent; + + if (message) PhReferenceObject(message); + if (content) PhReferenceObject(content); + PhReleaseQueuedLockExclusive(&context->StatusLock); - PhSetDialogItemText(hwndDlg, IDC_PROGRESSTEXT, message->Buffer); - PhDereferenceObject(message); + SendMessage( + context->TaskDialogHandle, + TDM_SET_ELEMENT_TEXT, + TDE_MAIN_INSTRUCTION, + (LPARAM)PhGetStringOrDefault(message, L" ") + ); + + SendMessage( + context->TaskDialogHandle, + TDM_SET_ELEMENT_TEXT, + TDE_CONTENT, + (LPARAM)PhGetStringOrDefault(content, L" ") + ); + + if (message) PhDereferenceObject(message); + if (content) PhDereferenceObject(content); } break; } - return FALSE; + return S_OK; +} + +BOOLEAN PhpShowThreadStackWindow( + _In_ PPH_THREAD_STACK_CONTEXT Context + ) +{ + TASKDIALOGCONFIG config; + INT result; + + memset(&config, 0, sizeof(TASKDIALOGCONFIG)); + config.cbSize = sizeof(TASKDIALOGCONFIG); + config.dwFlags = TDF_USE_HICON_MAIN | TDF_ALLOW_DIALOG_CANCELLATION | TDF_POSITION_RELATIVE_TO_WINDOW | TDF_SHOW_MARQUEE_PROGRESS_BAR | TDF_CALLBACK_TIMER; + config.dwCommonButtons = TDCBF_CANCEL_BUTTON; + config.pfCallback = PhpThreadStackTaskDialogCallback; + config.lpCallbackData = (LONG_PTR)Context; + config.hwndParent = Context->WindowHandle; + config.pszWindowTitle = PhApplicationName; + config.pszMainInstruction = L"Processing stack frames..."; + config.pszContent = L" "; + config.cxWidth = 200; + + return SUCCEEDED(TaskDialogIndirect(&config, &result, NULL, NULL)) && result == IDOK; +} + +static NTSTATUS PhpRefreshThreadStack( + _In_ HWND hwnd, + _In_ PPH_THREAD_STACK_CONTEXT Context + ) +{ + ULONG i; + + Context->StopWalk = FALSE; + PhMoveReference(&Context->StatusMessage, PhCreateString(L"Processing stack frames...")); + + if (PhpShowThreadStackWindow(Context)) + { + + } + + if (!Context->StopWalk && NT_SUCCESS(Context->WalkStatus)) + { + for (i = 0; i < Context->List->Count; i++) + PhpFreeThreadStackItem(Context->List->Items[i]); + + PhDereferenceObject(Context->List); + Context->List = Context->NewList; + Context->NewList = PhCreateList(10); + + ClearThreadStackTree(Context); + + for (i = 0; i < Context->List->Count; i++) + { + PTHREAD_STACK_ITEM item = Context->List->Items[i]; + PPH_STACK_TREE_ROOT_NODE stackNode; + + stackNode = AddThreadStackNode(Context, item->Index); + stackNode->StackFrame = item->StackFrame; + + if (!PhIsNullOrEmptyString(item->Symbol)) + stackNode->SymbolString = PhReferenceObject(item->Symbol); + + if (item->StackFrame.StackAddress) + PhPrintPointer(stackNode->StackAddressString, item->StackFrame.StackAddress); + if (item->StackFrame.FrameAddress) + PhPrintPointer(stackNode->FrameAddressString, item->StackFrame.FrameAddress); + + // There are no params for kernel-mode stack traces. + if ((ULONG_PTR)item->StackFrame.PcAddress <= PhSystemBasicInformation.MaximumUserModeAddress) + { + PhPrintPointer(stackNode->Parameter1String, item->StackFrame.Params[0]); + PhPrintPointer(stackNode->Parameter2String, item->StackFrame.Params[1]); + PhPrintPointer(stackNode->Parameter3String, item->StackFrame.Params[2]); + PhPrintPointer(stackNode->Parameter4String, item->StackFrame.Params[3]); + } + + if (item->StackFrame.PcAddress) + PhPrintPointer(stackNode->PcAddressString, item->StackFrame.PcAddress); + if (item->StackFrame.ReturnAddress) + PhPrintPointer(stackNode->ReturnAddressString, item->StackFrame.ReturnAddress); + + UpdateThreadStackNode(Context, stackNode); + } + + TreeNew_NodesStructured(Context->TreeNewHandle); + } + else + { + for (i = 0; i < Context->NewList->Count; i++) + PhpFreeThreadStackItem(Context->NewList->Items[i]); + + PhClearList(Context->NewList); + } + + if (Context->StopWalk) + return STATUS_ABANDONED; + + return Context->WalkStatus; } From e69262b4e922601bd245ab869f95c61f03d07e1a Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 17 Aug 2018 11:53:11 +1000 Subject: [PATCH 1288/2058] Add options button to handles tab --- ProcessHacker/ProcessHacker.rc | 4 +-- ProcessHacker/hndllist.c | 14 ++++++++--- ProcessHacker/hndlprv.c | 1 + ProcessHacker/include/hndllist.h | 26 ++++++++++++++++---- ProcessHacker/prpghndl.c | 42 +++++++++++++++++++++++--------- ProcessHacker/settings.c | 1 + 6 files changed, 67 insertions(+), 21 deletions(-) diff --git a/ProcessHacker/ProcessHacker.rc b/ProcessHacker/ProcessHacker.rc index 581433dd68b5..954be5620a83 100644 --- a/ProcessHacker/ProcessHacker.rc +++ b/ProcessHacker/ProcessHacker.rc @@ -541,9 +541,9 @@ STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSM CAPTION "Handles" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN - CONTROL "Hide unnamed handles",IDC_HIDEUNNAMEDHANDLES,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,3,5,88,10 - CONTROL "",IDC_LIST,"PhTreeNew",WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP | 0x2,2,19,256,239,WS_EX_CLIENTEDGE + PUSHBUTTON "Options",IDC_OPTIONS,2,2,50,14 EDITTEXT IDC_HANDLESEARCH,114,3,144,14,ES_AUTOHSCROLL + CONTROL "",IDC_LIST,"PhTreeNew",WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP | 0x2,2,19,256,239,WS_EX_CLIENTEDGE END IDD_PROCENVIRONMENT DIALOGEX 0, 0, 260, 260 diff --git a/ProcessHacker/hndllist.c b/ProcessHacker/hndllist.c index 6a4b70986704..dc2e3bce667e 100644 --- a/ProcessHacker/hndllist.c +++ b/ProcessHacker/hndllist.c @@ -159,7 +159,10 @@ VOID PhLoadSettingsHandleList( settings = PhGetStringSetting(L"HandleTreeListColumns"); sortSettings = PhGetStringSetting(L"HandleTreeListSort"); + Context->Flags = PhGetIntegerSetting(L"HandleTreeListFlags"); + PhCmLoadSettingsEx(Context->TreeNewHandle, &Context->Cm, 0, &settings->sr, &sortSettings->sr); + PhDereferenceObject(settings); PhDereferenceObject(sortSettings); } @@ -172,20 +175,25 @@ VOID PhSaveSettingsHandleList( PPH_STRING sortSettings; settings = PhCmSaveSettingsEx(Context->TreeNewHandle, &Context->Cm, 0, &sortSettings); + + PhSetIntegerSetting(L"HandleTreeListFlags", Context->Flags); PhSetStringSetting2(L"HandleTreeListColumns", &settings->sr); PhSetStringSetting2(L"HandleTreeListSort", &sortSettings->sr); + PhDereferenceObject(settings); PhDereferenceObject(sortSettings); } VOID PhSetOptionsHandleList( _Inout_ PPH_HANDLE_LIST_CONTEXT Context, - _In_ BOOLEAN HideUnnamedHandles + _In_ ULONG Options ) { - if (Context->HideUnnamedHandles != HideUnnamedHandles) + switch (Options) { - Context->HideUnnamedHandles = HideUnnamedHandles; + case HANDLE_TREE_MENU_ITEM_HIDE_UNNAMED_HANDLES: + Context->HideUnnamedHandles = !Context->HideUnnamedHandles; + break; } } diff --git a/ProcessHacker/hndlprv.c b/ProcessHacker/hndlprv.c index 2bf73a250bb5..f0a77ac6e664 100644 --- a/ProcessHacker/hndlprv.c +++ b/ProcessHacker/hndlprv.c @@ -68,6 +68,7 @@ PPH_HANDLE_PROVIDER PhCreateHandleProvider( PhEmGetObjectSize(EmHandleProviderType, sizeof(PH_HANDLE_PROVIDER)), PhHandleProviderType ); + memset(handleProvider, 0, sizeof(PH_HANDLE_PROVIDER)); handleProvider->HandleHashSetSize = 128; handleProvider->HandleHashSet = PhCreateHashSet(handleProvider->HandleHashSetSize); diff --git a/ProcessHacker/include/hndllist.h b/ProcessHacker/include/hndllist.h index 4d7a1c8a555f..195e9a994640 100644 --- a/ProcessHacker/include/hndllist.h +++ b/ProcessHacker/include/hndllist.h @@ -19,6 +19,14 @@ #define PHHNTLC_MAXIMUM 9 +// begin_phapppub +typedef enum _PH_HANDLE_TREE_MENUITEM +{ + PH_HANDLE_TREE_MENUITEM_HIDEUNNAMEDHANDLES = 1, + PH_HANDLE_TREE_MENUITEM_MAXIMUM +} PH_HANDLE_TREE_MENUITEM; +// end_phapppub + // begin_phapppub typedef struct _PH_HANDLE_NODE { @@ -43,16 +51,24 @@ typedef struct _PH_HANDLE_LIST_CONTEXT HWND ParentWindowHandle; HWND TreeNewHandle; ULONG TreeNewSortColumn; + PH_TN_FILTER_SUPPORT TreeFilterSupport; PH_SORT_ORDER TreeNewSortOrder; PH_CM_MANAGER Cm; + union + { + ULONG Flags; + struct + { + ULONG EnableStateHighlighting : 1; + ULONG HideUnnamedHandles : 1; + ULONG Spare : 23; + }; + }; + PPH_HASHTABLE NodeHashtable; PPH_LIST NodeList; - - BOOLEAN EnableStateHighlighting; - BOOLEAN HideUnnamedHandles; - PPH_POINTER_LIST NodeStateList; } PH_HANDLE_LIST_CONTEXT, *PPH_HANDLE_LIST_CONTEXT; @@ -76,7 +92,7 @@ VOID PhSaveSettingsHandleList( VOID PhSetOptionsHandleList( _Inout_ PPH_HANDLE_LIST_CONTEXT Context, - _In_ BOOLEAN HideUnnamedHandles + _In_ ULONG Options ); PPH_HANDLE_NODE PhAddHandleNode( diff --git a/ProcessHacker/prpghndl.c b/ProcessHacker/prpghndl.c index 0de1a58d4547..608dca76f181 100644 --- a/ProcessHacker/prpghndl.c +++ b/ProcessHacker/prpghndl.c @@ -410,10 +410,6 @@ INT_PTR CALLBACK PhpProcessHandlesDlgProc( PhLoadSettingsHandleList(&handlesContext->ListContext); - PhSetOptionsHandleList(&handlesContext->ListContext, !!PhGetIntegerSetting(L"HideUnnamedHandles")); - Button_SetCheck(GetDlgItem(hwndDlg, IDC_HIDEUNNAMEDHANDLES), - handlesContext->ListContext.HideUnnamedHandles ? BST_CHECKED : BST_UNCHECKED); - PhSetEnabledProvider(&handlesContext->ProviderRegistration, TRUE); PhBoostProvider(&handlesContext->ProviderRegistration, NULL); @@ -594,15 +590,39 @@ INT_PTR CALLBACK PhpProcessHandlesDlgProc( PhDereferenceObject(text); } break; - case IDC_HIDEUNNAMEDHANDLES: + case IDC_OPTIONS: { - BOOLEAN hide; - - hide = Button_GetCheck(GetDlgItem(hwndDlg, IDC_HIDEUNNAMEDHANDLES)) == BST_CHECKED; + RECT rect; + PPH_EMENU menu; + PPH_EMENU_ITEM unnamedMenuItem; + PPH_EMENU_ITEM selectedItem; + + GetWindowRect(GetDlgItem(hwndDlg, IDC_OPTIONS), &rect); + + menu = PhCreateEMenu(); + unnamedMenuItem = PhCreateEMenuItem(0, PH_HANDLE_TREE_MENUITEM_HIDEUNNAMEDHANDLES, L"Hide unnamed handles", NULL, NULL); + PhInsertEMenuItem(menu, unnamedMenuItem, ULONG_MAX); + + if (handlesContext->ListContext.HideUnnamedHandles) + unnamedMenuItem->Flags |= PH_EMENU_CHECKED; + + selectedItem = PhShowEMenu( + menu, + hwndDlg, + PH_EMENU_SHOW_LEFTRIGHT, + PH_ALIGN_LEFT | PH_ALIGN_TOP, + rect.left, + rect.bottom + ); + + if (selectedItem && selectedItem->Id) + { + PhSetOptionsHandleList(&handlesContext->ListContext, selectedItem->Id); + PhSaveSettingsHandleList(&handlesContext->ListContext); + PhApplyTreeNewFilters(&handlesContext->ListContext.TreeFilterSupport); + } - PhSetIntegerSetting(L"HideUnnamedHandles", hide); - PhSetOptionsHandleList(&handlesContext->ListContext, hide); - PhApplyTreeNewFilters(&handlesContext->ListContext.TreeFilterSupport); + PhDestroyEMenu(menu); } break; } diff --git a/ProcessHacker/settings.c b/ProcessHacker/settings.c index ec634ce57035..d9fca2801c7d 100644 --- a/ProcessHacker/settings.c +++ b/ProcessHacker/settings.c @@ -68,6 +68,7 @@ VOID PhAddDefaultSettings( PhpAddIntegerSetting(L"ForceNoParent", L"1"); PhpAddStringSetting(L"HandleTreeListColumns", L""); PhpAddStringSetting(L"HandleTreeListSort", L"0,1"); // 0, AscendingSortOrder + PhpAddIntegerSetting(L"HandleTreeListFlags", L"0"); PhpAddIntegerPairSetting(L"HandlePropertiesWindowPosition", L"0,0"); PhpAddScalableIntegerPairSetting(L"HandlePropertiesWindowSize", L"@96|260,260"); PhpAddIntegerSetting(L"HiddenProcessesMenuEnabled", L"0"); From 102b7dcc55d8b1629d686527de1a7e2113ac1ba9 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 17 Aug 2018 12:09:12 +1000 Subject: [PATCH 1289/2058] Remove old setting --- ProcessHacker/settings.c | 1 - 1 file changed, 1 deletion(-) diff --git a/ProcessHacker/settings.c b/ProcessHacker/settings.c index d9fca2801c7d..00e4de8a9cef 100644 --- a/ProcessHacker/settings.c +++ b/ProcessHacker/settings.c @@ -81,7 +81,6 @@ VOID PhAddDefaultSettings( PhpAddIntegerSetting(L"HideOnMinimize", L"0"); PhpAddIntegerSetting(L"HideOtherUserProcesses", L"0"); PhpAddIntegerSetting(L"HideSignedProcesses", L"0"); - PhpAddIntegerSetting(L"HideUnnamedHandles", L"1"); PhpAddIntegerSetting(L"HighlightingDuration", L"3e8"); // 1000ms PhpAddStringSetting(L"IconSettings", L"1|1"); PhpAddIntegerSetting(L"IconNotifyMask", L"c"); // PH_NOTIFY_SERVICE_CREATE | PH_NOTIFY_SERVICE_DELETE From 0a87c2276a34da9412d129597bb9665a6433e6b9 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 17 Aug 2018 12:11:53 +1000 Subject: [PATCH 1290/2058] Add LSA/SAM security editor support --- phlib/secedit.c | 84 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/phlib/secedit.c b/phlib/secedit.c index 7110cb24d6c9..59351b70cf15 100644 --- a/phlib/secedit.c +++ b/phlib/secedit.c @@ -754,6 +754,59 @@ _Callback_ NTSTATUS PhStdGetObjectSecurity( status = PhpGetObjectSecurityWithTimeout(handle, SecurityInformation, SecurityDescriptor); NtClose(handle); } + if ( + PhEqualString2(this->ObjectType, L"LsaAccount", TRUE) || + PhEqualString2(this->ObjectType, L"LsaPolicy", TRUE) || + PhEqualString2(this->ObjectType, L"LsaSecret", TRUE) || + PhEqualString2(this->ObjectType, L"LsaTrusted", TRUE) + ) + { + PSECURITY_DESCRIPTOR securityDescriptor; + + status = LsaQuerySecurityObject( + handle, + SecurityInformation, + &securityDescriptor + ); + + if (NT_SUCCESS(status)) + { + *SecurityDescriptor = PhAllocateCopy( + securityDescriptor, + RtlLengthSecurityDescriptor(securityDescriptor) + ); + LsaFreeMemory(securityDescriptor); + } + + LsaClose(handle); + } + else if ( + PhEqualString2(this->ObjectType, L"SamAlias", TRUE) || + PhEqualString2(this->ObjectType, L"SamDomain", TRUE) || + PhEqualString2(this->ObjectType, L"SamGroup", TRUE) || + PhEqualString2(this->ObjectType, L"SamServer", TRUE) || + PhEqualString2(this->ObjectType, L"SamUser", TRUE) + ) + { + //PSECURITY_DESCRIPTOR securityDescriptor; + // + //status = SamQuerySecurityObject( + // handle, + // SecurityInformation, + // &securityDescriptor + // ); + // + //if (NT_SUCCESS(status)) + //{ + // *SecurityDescriptor = PhAllocateCopy( + // securityDescriptor, + // RtlLengthSecurityDescriptor(securityDescriptor) + // ); + // SamFreeMemory(securityDescriptor); + //} + // + //SamCloseHandle(handle); + } else { status = PhGetObjectSecurity(handle, SecurityInformation, SecurityDescriptor); @@ -797,6 +850,37 @@ _Callback_ NTSTATUS PhStdSetObjectSecurity( status = PhSetSeObjectSecurity(handle, SE_SERVICE, SecurityInformation, SecurityDescriptor); CloseServiceHandle(handle); } + else if ( + PhEqualString2(this->ObjectType, L"LsaAccount", TRUE) || + PhEqualString2(this->ObjectType, L"LsaPolicy", TRUE) || + PhEqualString2(this->ObjectType, L"LsaSecret", TRUE) || + PhEqualString2(this->ObjectType, L"LsaTrusted", TRUE) + ) + { + status = LsaSetSecurityObject( + handle, + SecurityInformation, + SecurityDescriptor + ); + + LsaClose(handle); + } + else if ( + PhEqualString2(this->ObjectType, L"SamAlias", TRUE) || + PhEqualString2(this->ObjectType, L"SamDomain", TRUE) || + PhEqualString2(this->ObjectType, L"SamGroup", TRUE) || + PhEqualString2(this->ObjectType, L"SamServer", TRUE) || + PhEqualString2(this->ObjectType, L"SamUser", TRUE) + ) + { + //status = SamSetSecurityObject( + // handle, + // SecurityInformation, + // SecurityDescriptor + // ); + // + //SamCloseHandle(handle); + } else { status = PhSetObjectSecurity(handle, SecurityInformation, SecurityDescriptor); From 71a43ff27fb0b0916ebbd4b5de263f38d23947a4 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 17 Aug 2018 12:12:25 +1000 Subject: [PATCH 1291/2058] Fix typo --- ProcessHacker/hndllist.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ProcessHacker/hndllist.c b/ProcessHacker/hndllist.c index dc2e3bce667e..9ac11448b69d 100644 --- a/ProcessHacker/hndllist.c +++ b/ProcessHacker/hndllist.c @@ -191,7 +191,7 @@ VOID PhSetOptionsHandleList( { switch (Options) { - case HANDLE_TREE_MENU_ITEM_HIDE_UNNAMED_HANDLES: + case PH_HANDLE_TREE_MENUITEM_HIDEUNNAMEDHANDLES: Context->HideUnnamedHandles = !Context->HideUnnamedHandles; break; } From 0eb58402a721408351f80c37b8b35279b39e3fe8 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 17 Aug 2018 12:30:54 +1000 Subject: [PATCH 1292/2058] Move process properties memory tab initialization --- ProcessHacker/prpgmem.c | 119 +++++++++++++++++++++++++++++----------- 1 file changed, 88 insertions(+), 31 deletions(-) diff --git a/ProcessHacker/prpgmem.c b/ProcessHacker/prpgmem.c index ed1a23721e48..2fb6a516eddb 100644 --- a/ProcessHacker/prpgmem.c +++ b/ProcessHacker/prpgmem.c @@ -38,20 +38,14 @@ #include #include +static PPH_OBJECT_TYPE PhMemoryContextType = NULL; static PH_STRINGREF EmptyMemoryText = PH_STRINGREF_INIT(L"There are no memory regions to display."); -VOID PhpRefreshProcessMemoryList( - _In_ HWND hwndDlg, - _In_ PPH_PROCESS_PROPPAGECONTEXT PropPageContext +NTSTATUS PhpRefreshProcessMemoryThread( + _In_ PVOID Context ) { - PPH_MEMORY_CONTEXT memoryContext = PropPageContext->Context; - - if (memoryContext->MemoryItemListValid) - { - PhDeleteMemoryItemList(&memoryContext->MemoryItemList); - memoryContext->MemoryItemListValid = FALSE; - } + PPH_MEMORY_CONTEXT memoryContext = Context; memoryContext->LastRunStatus = PhQueryMemoryItemList( memoryContext->ProcessId, @@ -72,20 +66,29 @@ VOID PhpRefreshProcessMemoryList( } memoryContext->MemoryItemListValid = TRUE; - TreeNew_SetEmptyText(memoryContext->ListContext.TreeNewHandle, &EmptyMemoryText, 0); - PhReplaceMemoryList(&memoryContext->ListContext, &memoryContext->MemoryItemList); } - else - { - PPH_STRING message; - message = PhGetStatusMessage(memoryContext->LastRunStatus, 0); - PhMoveReference(&memoryContext->ErrorMessage, PhFormatString(L"Unable to query memory information:\n%s", PhGetStringOrDefault(message, L"Unknown error."))); - PhClearReference(&message); - TreeNew_SetEmptyText(memoryContext->ListContext.TreeNewHandle, &memoryContext->ErrorMessage->sr, 0); + PostMessage(memoryContext->WindowHandle, WM_PH_INVOKE, 0, 0); + + PhDereferenceObject(memoryContext); + + return STATUS_SUCCESS; +} + +VOID PhpRefreshProcessMemoryList( + _In_ PPH_PROCESS_PROPPAGECONTEXT PropPageContext + ) +{ + PPH_MEMORY_CONTEXT memoryContext = PropPageContext->Context; - PhReplaceMemoryList(&memoryContext->ListContext, NULL); + if (memoryContext->MemoryItemListValid) + { + PhDeleteMemoryItemList(&memoryContext->MemoryItemList); + memoryContext->MemoryItemListValid = FALSE; } + + PhReferenceObject(memoryContext); + PhCreateThread2(PhpRefreshProcessMemoryThread, memoryContext); } VOID PhpInitializeMemoryMenu( @@ -297,6 +300,43 @@ BOOLEAN PhpMemoryTreeFilterCallback( return FALSE; } +VOID PhpMemoryContextDeleteProcedure( + _In_ PVOID Object, + _In_ ULONG Flags + ) +{ + PPH_MEMORY_CONTEXT memoryContext = (PPH_MEMORY_CONTEXT)Object; + + PhDeleteMemoryList(&memoryContext->ListContext); + + if (memoryContext->MemoryItemListValid) + PhDeleteMemoryItemList(&memoryContext->MemoryItemList); + + PhClearReference(&memoryContext->ErrorMessage); +} + +PPH_MEMORY_CONTEXT PhCreateMemoryContext( + VOID + ) +{ + static PH_INITONCE initOnce = PH_INITONCE_INIT; + PPH_MEMORY_CONTEXT memoryContext; + + if (PhBeginInitOnce(&initOnce)) + { + PhMemoryContextType = PhCreateObjectType(L"ProcessMemoryContext", 0, PhpMemoryContextDeleteProcedure); + PhEndInitOnce(&initOnce); + } + + memoryContext = PhCreateObject( + PhEmGetObjectSize(EmMemoryContextType, sizeof(PH_MEMORY_CONTEXT)), + PhMemoryContextType + ); + memset(memoryContext, 0, sizeof(PH_MEMORY_CONTEXT)); + + return memoryContext; +} + INT_PTR CALLBACK PhpProcessMemoryDlgProc( _In_ HWND hwndDlg, _In_ UINT uMsg, @@ -326,11 +366,11 @@ INT_PTR CALLBACK PhpProcessMemoryDlgProc( { case WM_INITDIALOG: { - memoryContext = propPageContext->Context = PhAllocate(PhEmGetObjectSize(EmMemoryContextType, sizeof(PH_MEMORY_CONTEXT))); - memset(memoryContext, 0, sizeof(PH_MEMORY_CONTEXT)); + memoryContext = propPageContext->Context = PhCreateMemoryContext(); + memoryContext->WindowHandle = hwndDlg; memoryContext->ProcessId = processItem->ProcessId; - memoryContext->SearchboxHandle = GetDlgItem(hwndDlg, IDC_SEARCH); + PhCreateSearchControl(hwndDlg, memoryContext->SearchboxHandle, L"Search Memory (Ctrl+K)"); // Initialize the list. @@ -357,7 +397,7 @@ INT_PTR CALLBACK PhpProcessMemoryDlgProc( PhLoadSettingsMemoryList(&memoryContext->ListContext); - PhpRefreshProcessMemoryList(hwndDlg, propPageContext); + PhpRefreshProcessMemoryList(propPageContext); PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport); } @@ -376,13 +416,8 @@ INT_PTR CALLBACK PhpProcessMemoryDlgProc( } PhSaveSettingsMemoryList(&memoryContext->ListContext); - PhDeleteMemoryList(&memoryContext->ListContext); - - if (memoryContext->MemoryItemListValid) - PhDeleteMemoryItemList(&memoryContext->MemoryItemList); - PhClearReference(&memoryContext->ErrorMessage); - PhFree(memoryContext); + PhDereferenceObject(memoryContext); } break; case WM_SHOWWINDOW: @@ -602,7 +637,7 @@ INT_PTR CALLBACK PhpProcessMemoryDlgProc( } break; case IDC_REFRESH: - PhpRefreshProcessMemoryList(hwndDlg, propPageContext); + PhpRefreshProcessMemoryList(propPageContext); break; case IDC_FILTEROPTIONS: { @@ -764,6 +799,28 @@ INT_PTR CALLBACK PhpProcessMemoryDlgProc( } } break; + case WM_PH_INVOKE: + { + if (memoryContext->MemoryItemListValid) + { + TreeNew_SetEmptyText(memoryContext->ListContext.TreeNewHandle, &EmptyMemoryText, 0); + + PhReplaceMemoryList(&memoryContext->ListContext, &memoryContext->MemoryItemList); + } + else + { + PPH_STRING message; + + message = PhGetStatusMessage(memoryContext->LastRunStatus, 0); + PhMoveReference(&memoryContext->ErrorMessage, PhFormatString(L"Unable to query memory information:\n%s", PhGetStringOrDefault(message, L"Unknown error."))); + TreeNew_SetEmptyText(memoryContext->ListContext.TreeNewHandle, &memoryContext->ErrorMessage->sr, 0); + + PhReplaceMemoryList(&memoryContext->ListContext, NULL); + + PhClearReference(&message); + } + } + break; } return FALSE; From 1af51caff8faa8346f058fd779d4b9f9eb87e3bb Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 17 Aug 2018 12:52:14 +1000 Subject: [PATCH 1293/2058] Remove WindowExplorer window information triggering Google Chrome showing incompatible application and uninstall --- plugins/WindowExplorer/WindowExplorer.vcxproj | 1 - .../WindowExplorer.vcxproj.filters | 3 - plugins/WindowExplorer/hook.c | 508 ------------------ plugins/WindowExplorer/main.c | 45 +- plugins/WindowExplorer/utils.c | 4 +- plugins/WindowExplorer/wnddlg.c | 24 +- plugins/WindowExplorer/wndexp.h | 53 -- plugins/WindowExplorer/wndprp.c | 71 +-- 8 files changed, 27 insertions(+), 682 deletions(-) delete mode 100644 plugins/WindowExplorer/hook.c diff --git a/plugins/WindowExplorer/WindowExplorer.vcxproj b/plugins/WindowExplorer/WindowExplorer.vcxproj index 9220ad3b18c4..f23170fa9c6f 100644 --- a/plugins/WindowExplorer/WindowExplorer.vcxproj +++ b/plugins/WindowExplorer/WindowExplorer.vcxproj @@ -72,7 +72,6 @@ - diff --git a/plugins/WindowExplorer/WindowExplorer.vcxproj.filters b/plugins/WindowExplorer/WindowExplorer.vcxproj.filters index ab33d0a02f9f..c6ee7a5ebc90 100644 --- a/plugins/WindowExplorer/WindowExplorer.vcxproj.filters +++ b/plugins/WindowExplorer/WindowExplorer.vcxproj.filters @@ -30,9 +30,6 @@ Source Files - - Source Files - diff --git a/plugins/WindowExplorer/hook.c b/plugins/WindowExplorer/hook.c deleted file mode 100644 index 3bd85bd6fa62..000000000000 --- a/plugins/WindowExplorer/hook.c +++ /dev/null @@ -1,508 +0,0 @@ -/* - * Process Hacker Window Explorer - - * hook procedure - * - * Copyright (C) 2011 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -/* - * Window Explorer uses a hook procedure in order to get window procedure - * and other information that can't be retrieved using GetWindowLongPtr. - * Because WindowExplorer.dll needs to be loaded into processes other - * than Process Hacker, both ProcessHacker.exe and comctl32.dll are set as - * delay-loaded DLLs. The other DLLs that we depend on (gdi32.dll, - * kernel32.dll, ntdll.dll, user32.dll) are all guaranteed to be already - * loaded whenever WindowExplorer.dll needs to be loaded. - */ - -#include "wndexp.h" - -BOOLEAN WepCreateServerObjects( - VOID - ); - -BOOLEAN WepOpenServerObjects( - VOID - ); - -VOID WepCloseServerObjects( - VOID - ); - -VOID WepWriteClientData( - _In_ HWND hwnd - ); - -LRESULT CALLBACK WepCallWndProc( - _In_ int nCode, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -// Shared -ULONG WeServerMessage; -HANDLE WeServerSharedSection; -PWE_HOOK_SHARED_DATA WeServerSharedData; -HANDLE WeServerSharedSectionLock; -HANDLE WeServerSharedSectionEvent; -// Server -HHOOK WeHookHandle = NULL; -// The current message ID is used to detect out-of-sync clients. -ULONG WeCurrentMessageId = 0; - -// Server - -VOID WeHookServerInitialization( - VOID - ) -{ - if (WeHookHandle) - return; - - WeServerMessage = RegisterWindowMessage(WE_SERVER_MESSAGE_NAME); - - if (!WepCreateServerObjects()) - return; - - WeHookHandle = SetWindowsHookEx(WH_CALLWNDPROC, WepCallWndProc, PluginInstance->DllBase, 0); -} - -VOID WeHookServerUninitialization( - VOID - ) -{ - if (WeHookHandle) - { - UnhookWindowsHookEx(WeHookHandle); - WeHookHandle = NULL; - } -} - -BOOLEAN WepCreateServerObjects( - VOID - ) -{ - OBJECT_ATTRIBUTES objectAttributes; - WCHAR buffer[256]; - UNICODE_STRING objectName; - SECURITY_DESCRIPTOR securityDescriptor; - UCHAR saclBuffer[sizeof(ACL) + FIELD_OFFSET(SYSTEM_MANDATORY_LABEL_ACE, SidStart) + FIELD_OFFSET(SID, SubAuthority) + sizeof(ULONG)]; - PACL sacl; - UCHAR mandatoryLabelAceBuffer[FIELD_OFFSET(SYSTEM_MANDATORY_LABEL_ACE, SidStart) + FIELD_OFFSET(SID, SubAuthority) + sizeof(ULONG)]; - PSYSTEM_MANDATORY_LABEL_ACE mandatoryLabelAce; - PSID sid; - - if (!WeServerSharedSection) - { - LARGE_INTEGER maximumSize; - - WeFormatLocalObjectName(WE_SERVER_SHARED_SECTION_NAME, buffer, &objectName); - InitializeObjectAttributes(&objectAttributes, &objectName, OBJ_CASE_INSENSITIVE, NULL, NULL); - maximumSize.QuadPart = sizeof(WE_HOOK_SHARED_DATA); - - if (!NT_SUCCESS(NtCreateSection( - &WeServerSharedSection, - SECTION_ALL_ACCESS, - &objectAttributes, - &maximumSize, - PAGE_READWRITE, - SEC_COMMIT, - NULL - ))) - { - return FALSE; - } - } - - if (!WeServerSharedData) - { - PVOID viewBase; - SIZE_T viewSize; - - viewBase = NULL; - viewSize = sizeof(WE_HOOK_SHARED_DATA); - - if (!NT_SUCCESS(NtMapViewOfSection( - WeServerSharedSection, - NtCurrentProcess(), - &viewBase, - 0, - 0, - NULL, - &viewSize, - ViewShare, - 0, - PAGE_READWRITE - ))) - { - WepCloseServerObjects(); - return FALSE; - } - - WeServerSharedData = viewBase; - } - - if (!WeServerSharedSectionLock) - { - WeFormatLocalObjectName(WE_SERVER_SHARED_SECTION_LOCK_NAME, buffer, &objectName); - InitializeObjectAttributes(&objectAttributes, &objectName, OBJ_CASE_INSENSITIVE, NULL, NULL); - - if (!NT_SUCCESS(NtCreateMutant( - &WeServerSharedSectionLock, - MUTANT_ALL_ACCESS, - &objectAttributes, - FALSE - ))) - { - WepCloseServerObjects(); - return FALSE; - } - } - - if (!WeServerSharedSectionEvent) - { - WeFormatLocalObjectName(WE_SERVER_SHARED_SECTION_EVENT_NAME, buffer, &objectName); - InitializeObjectAttributes(&objectAttributes, &objectName, OBJ_CASE_INSENSITIVE, NULL, NULL); - - if (!NT_SUCCESS(NtCreateEvent( - &WeServerSharedSectionEvent, - EVENT_ALL_ACCESS, - &objectAttributes, - NotificationEvent, - FALSE - ))) - { - WepCloseServerObjects(); - return FALSE; - } - } - - // If mandatory labels are supported, set it to the lowest possible level. - { - static SID_IDENTIFIER_AUTHORITY mandatoryLabelAuthority = SECURITY_MANDATORY_LABEL_AUTHORITY; - - RtlCreateSecurityDescriptor(&securityDescriptor, SECURITY_DESCRIPTOR_REVISION); - - sacl = (PACL)saclBuffer; - RtlCreateAcl(sacl, sizeof(saclBuffer), ACL_REVISION); - - mandatoryLabelAce = (PSYSTEM_MANDATORY_LABEL_ACE)mandatoryLabelAceBuffer; - mandatoryLabelAce->Header.AceType = SYSTEM_MANDATORY_LABEL_ACE_TYPE; - mandatoryLabelAce->Header.AceFlags = 0; - mandatoryLabelAce->Header.AceSize = sizeof(mandatoryLabelAceBuffer); - mandatoryLabelAce->Mask = SYSTEM_MANDATORY_LABEL_NO_WRITE_UP; - - sid = (PSID)&mandatoryLabelAce->SidStart; - RtlInitializeSid(sid, &mandatoryLabelAuthority, 1); - *RtlSubAuthoritySid(sid, 0) = SECURITY_MANDATORY_LOW_RID; - - if (NT_SUCCESS(RtlAddAce(sacl, ACL_REVISION, MAXULONG32, mandatoryLabelAce, sizeof(mandatoryLabelAceBuffer)))) - { - if (NT_SUCCESS(RtlSetSaclSecurityDescriptor(&securityDescriptor, TRUE, sacl, FALSE))) - { - NtSetSecurityObject(WeServerSharedSection, LABEL_SECURITY_INFORMATION, &securityDescriptor); - NtSetSecurityObject(WeServerSharedSectionLock, LABEL_SECURITY_INFORMATION, &securityDescriptor); - NtSetSecurityObject(WeServerSharedSectionEvent, LABEL_SECURITY_INFORMATION, &securityDescriptor); - } - } - } - - return TRUE; -} - -BOOLEAN WepOpenServerObjects( - VOID - ) -{ - OBJECT_ATTRIBUTES objectAttributes; - WCHAR buffer[256]; - UNICODE_STRING objectName; - - if (!WeServerSharedSection) - { - WeFormatLocalObjectName(WE_SERVER_SHARED_SECTION_NAME, buffer, &objectName); - InitializeObjectAttributes(&objectAttributes, &objectName, OBJ_CASE_INSENSITIVE, NULL, NULL); - - if (!NT_SUCCESS(NtOpenSection( - &WeServerSharedSection, - SECTION_ALL_ACCESS, - &objectAttributes - ))) - { - return FALSE; - } - } - - if (!WeServerSharedData) - { - PVOID viewBase; - SIZE_T viewSize; - - viewBase = NULL; - viewSize = sizeof(WE_HOOK_SHARED_DATA); - - if (!NT_SUCCESS(NtMapViewOfSection( - WeServerSharedSection, - NtCurrentProcess(), - &viewBase, - 0, - 0, - NULL, - &viewSize, - ViewShare, - 0, - PAGE_READWRITE - ))) - { - WepCloseServerObjects(); - return FALSE; - } - - WeServerSharedData = viewBase; - } - - if (!WeServerSharedSectionLock) - { - WeFormatLocalObjectName(WE_SERVER_SHARED_SECTION_LOCK_NAME, buffer, &objectName); - InitializeObjectAttributes(&objectAttributes, &objectName, OBJ_CASE_INSENSITIVE, NULL, NULL); - - if (!NT_SUCCESS(NtOpenMutant( - &WeServerSharedSectionLock, - MUTANT_ALL_ACCESS, - &objectAttributes - ))) - { - WepCloseServerObjects(); - return FALSE; - } - } - - if (!WeServerSharedSectionEvent) - { - WeFormatLocalObjectName(WE_SERVER_SHARED_SECTION_EVENT_NAME, buffer, &objectName); - InitializeObjectAttributes(&objectAttributes, &objectName, OBJ_CASE_INSENSITIVE, NULL, NULL); - - if (!NT_SUCCESS(NtOpenEvent( - &WeServerSharedSectionEvent, - EVENT_ALL_ACCESS, - &objectAttributes - ))) - { - WepCloseServerObjects(); - return FALSE; - } - } - - return TRUE; -} - -VOID WepCloseServerObjects( - VOID - ) -{ - if (WeServerSharedSection) - { - NtClose(WeServerSharedSection); - WeServerSharedSection = NULL; - } - - if (WeServerSharedData) - { - NtUnmapViewOfSection(NtCurrentProcess(), WeServerSharedData); - WeServerSharedData = NULL; - } - - if (WeServerSharedSectionLock) - { - NtClose(WeServerSharedSectionLock); - WeServerSharedSectionLock = NULL; - } - - if (WeServerSharedSectionEvent) - { - NtClose(WeServerSharedSectionEvent); - WeServerSharedSectionEvent = NULL; - } -} - -BOOLEAN WeIsServerActive( - VOID - ) -{ - if (WepOpenServerObjects()) - { - WepCloseServerObjects(); - - return TRUE; - } - else - { - return FALSE; - } -} - -BOOLEAN WeLockServerSharedData( - _Out_ PWE_HOOK_SHARED_DATA *Data - ) -{ - LARGE_INTEGER timeout; - - if (!WeServerSharedSectionLock) - return FALSE; - - timeout.QuadPart = -WE_CLIENT_MESSAGE_TIMEOUT * PH_TIMEOUT_MS; - - if (NtWaitForSingleObject(WeServerSharedSectionLock, FALSE, &timeout) != WAIT_OBJECT_0) - return FALSE; - - *Data = WeServerSharedData; - - return TRUE; -} - -VOID WeUnlockServerSharedData( - VOID - ) -{ - NtReleaseMutant(WeServerSharedSectionLock, NULL); -} - -BOOLEAN WeSendServerRequest( - _In_ HWND hWnd - ) -{ - ULONG threadId; - ULONG processId; - LARGE_INTEGER timeout; - - if (!WeServerSharedData || !WeServerSharedSectionEvent) - return FALSE; - - threadId = GetWindowThreadProcessId(hWnd, &processId); - - if (UlongToHandle(processId) == NtCurrentProcessId()) - { - // We are trying to get information about the server. Call the procedure directly. - WepWriteClientData(hWnd); - return TRUE; - } - - // Call the client and wait for the client to finish. - - WeCurrentMessageId++; - WeServerSharedData->MessageId = WeCurrentMessageId; - NtResetEvent(WeServerSharedSectionEvent, NULL); - - if (!SendNotifyMessage(hWnd, WeServerMessage, (WPARAM)NtCurrentProcessId(), WeCurrentMessageId)) - return FALSE; - - timeout.QuadPart = -WE_CLIENT_MESSAGE_TIMEOUT * PH_TIMEOUT_MS; - - if (NtWaitForSingleObject(WeServerSharedSectionEvent, FALSE, &timeout) != STATUS_WAIT_0) - return FALSE; - - return TRUE; -} - -// Client - -VOID WeHookClientInitialization( - VOID - ) -{ - WeServerMessage = RegisterWindowMessage(WE_SERVER_MESSAGE_NAME); -} - -VOID WeHookClientUninitialization( - VOID - ) -{ - NOTHING; -} - -VOID WepWriteClientData( - _In_ HWND hwnd - ) -{ - WCHAR className[256]; - LOGICAL isUnicode; - - memset(&WeServerSharedData->c, 0, sizeof(WeServerSharedData->c)); - isUnicode = IsWindowUnicode(hwnd); - - if (isUnicode) - { - WeServerSharedData->c.WndProc = GetWindowLongPtrW(hwnd, GWLP_WNDPROC); - WeServerSharedData->c.DlgProc = GetWindowLongPtrW(hwnd, DWLP_DLGPROC); - } - else - { - WeServerSharedData->c.WndProc = GetWindowLongPtrA(hwnd, GWLP_WNDPROC); - WeServerSharedData->c.DlgProc = GetWindowLongPtrA(hwnd, DWLP_DLGPROC); - } - - if (!GetClassName(hwnd, className, sizeof(className) / sizeof(WCHAR))) - className[0] = 0; - - WeServerSharedData->c.ClassInfo.cbSize = sizeof(WNDCLASSEX); - GetClassInfoEx(NULL, className, &WeServerSharedData->c.ClassInfo); - - if (isUnicode) - WeServerSharedData->c.ClassInfo.lpfnWndProc = (PVOID)GetClassLongPtrW(hwnd, GCLP_WNDPROC); - else - WeServerSharedData->c.ClassInfo.lpfnWndProc = (PVOID)GetClassLongPtrA(hwnd, GCLP_WNDPROC); -} - -LRESULT CALLBACK WepCallWndProc( - _In_ int nCode, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - LRESULT result; - PCWPSTRUCT info; - - result = CallNextHookEx(NULL, nCode, wParam, lParam); - - info = (PCWPSTRUCT)lParam; - - if (info->message == WeServerMessage) - { - HANDLE serverProcessId; - ULONG messageId; - - serverProcessId = (HANDLE)info->wParam; - messageId = (ULONG)info->lParam; - - if (serverProcessId != NtCurrentProcessId()) - { - if (WepOpenServerObjects()) - { - if (WeServerSharedData->MessageId == messageId) - { - WepWriteClientData(info->hwnd); - NtSetEvent(WeServerSharedSectionEvent, NULL); - } - - WepCloseServerObjects(); - } - } - } - - return result; -} diff --git a/plugins/WindowExplorer/main.c b/plugins/WindowExplorer/main.c index ad0658fd76d9..0d2681de03ba 100644 --- a/plugins/WindowExplorer/main.c +++ b/plugins/WindowExplorer/main.c @@ -46,7 +46,7 @@ VOID NTAPI UnloadCallback( _In_opt_ PVOID Context ) { - WeHookServerUninitialization(); + NOTHING; } BOOL CALLBACK WepEnumDesktopProc( @@ -209,7 +209,7 @@ LOGICAL DllMain( { case DLL_PROCESS_ATTACH: { - BOOLEAN isClient; + PPH_PLUGIN_INFORMATION info; PH_SETTING_CREATE settings[] = { @@ -219,30 +219,11 @@ LOGICAL DllMain( { ScalableIntegerPairSettingType, SETTING_NAME_WINDOWS_WINDOW_SIZE, L"@96|690,540" } }; - isClient = FALSE; - - if (!GetModuleHandle(L"ProcessHacker.exe") || !WeGetProcedureAddress("PhInstanceHandle")) - { - isClient = TRUE; - } - else - { - // WindowExplorer appears to be loading within Process Hacker. However, if there is - // already a server instance, the the hook will be active, and our DllMain routine - // will most likely be called before the plugin system is even initialized. Attempting - // to register a plugin would result in an access violation, so load as a client for now. - if (WeIsServerActive()) - isClient = TRUE; - } - - if (isClient) - { - // This DLL is being loaded not as a Process Hacker plugin, but as a hook. - IsHookClient = TRUE; - WeHookClientInitialization(); - - break; - } + //BOOLEAN isClient = FALSE; + //if (!GetModuleHandle(L"ProcessHacker.exe") || !WeGetProcedureAddress("PhInstanceHandle")) + //{ + // isClient = TRUE; + //} PluginInstance = PhRegisterPlugin(PLUGIN_NAME, Instance, &info); @@ -250,7 +231,7 @@ LOGICAL DllMain( return FALSE; info->DisplayName = L"Window Explorer"; - info->Author = L"wj32"; + info->Author = L"dmex, wj32"; info->Description = L"View and manipulate windows."; info->Url = L"https://wj32.org/processhacker/forums/viewtopic.php?t=1116"; info->HasOptions = FALSE; @@ -293,15 +274,7 @@ LOGICAL DllMain( &ThreadMenuInitializingCallbackRegistration ); - PhAddSettings(settings, ARRAYSIZE(settings)); - } - break; - case DLL_PROCESS_DETACH: - { - if (IsHookClient) - { - WeHookClientUninitialization(); - } + PhAddSettings(settings, RTL_NUMBER_OF(settings)); } break; } diff --git a/plugins/WindowExplorer/utils.c b/plugins/WindowExplorer/utils.c index 55baeb6161c1..73aa875696c7 100644 --- a/plugins/WindowExplorer/utils.c +++ b/plugins/WindowExplorer/utils.c @@ -31,9 +31,9 @@ PVOID WeGetProcedureAddress( static PVOID imageBase = NULL; if (!imageBase) - imageBase = GetModuleHandle(L"ProcessHacker.exe"); + imageBase = PhGetDllHandle(L"ProcessHacker.exe"); - return (PVOID)GetProcAddress(imageBase, Name); + return PhGetProcedureAddress(imageBase, Name, 0); } VOID WeFormatLocalObjectName( diff --git a/plugins/WindowExplorer/wnddlg.c b/plugins/WindowExplorer/wnddlg.c index 4b7744f88588..61d850d49fa5 100644 --- a/plugins/WindowExplorer/wnddlg.c +++ b/plugins/WindowExplorer/wnddlg.c @@ -61,8 +61,7 @@ VOID WeShowWindowsDialog( { PWINDOWS_CONTEXT context; - context = PhAllocate(sizeof(WINDOWS_CONTEXT)); - memset(context, 0, sizeof(WINDOWS_CONTEXT)); + context = PhAllocateZero(sizeof(WINDOWS_CONTEXT)); memcpy(&context->Selector, Selector, sizeof(WE_WINDOW_SELECTOR)); ProcessHacker_Invoke(WE_PhMainWndHandle, WepShowWindowsDialogCallback, context); @@ -75,8 +74,7 @@ VOID WeShowWindowsPropPage( { PWINDOWS_CONTEXT context; - context = PhAllocate(sizeof(WINDOWS_CONTEXT)); - memset(context, 0, sizeof(WINDOWS_CONTEXT)); + context = PhAllocateZero(sizeof(WINDOWS_CONTEXT)); memcpy(&context->Selector, Selector, sizeof(WE_WINDOW_SELECTOR)); PhAddProcessPropPage( @@ -810,8 +808,6 @@ INT_PTR CALLBACK WepWindowsPageProc( WeInitializeWindowTree(hwndDlg, context->TreeNewHandle, &context->TreeContext); - PhRegisterDialog(hwndDlg); - PhInitializeLayoutManager(&context->LayoutManager, hwndDlg); PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_SEARCHEDIT), NULL, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_LIST), NULL, PH_ANCHOR_ALL); @@ -821,23 +817,21 @@ INT_PTR CALLBACK WepWindowsPageProc( PhInitializeWindowTheme(hwndDlg, !!PhGetIntegerSetting(L"EnableThemeSupport")); } break; - case WM_SHOWWINDOW: - { - if (PhBeginPropPageLayout(hwndDlg, propPageContext)) - PhEndPropPageLayout(hwndDlg, propPageContext); - } - break; case WM_DESTROY: { PhDeleteLayoutManager(&context->LayoutManager); - PhUnregisterDialog(hwndDlg); - WeDeleteWindowTree(&context->TreeContext); WepDeleteWindowSelector(&context->Selector); PhFree(context); } break; + case WM_SHOWWINDOW: + { + if (PhBeginPropPageLayout(hwndDlg, propPageContext)) + PhEndPropPageLayout(hwndDlg, propPageContext); + } + break; case WM_COMMAND: { switch (GET_WM_COMMAND_CMD(wParam, lParam)) @@ -1224,4 +1218,4 @@ INT_PTR CALLBACK WepWindowsPageProc( } return FALSE; -} \ No newline at end of file +} diff --git a/plugins/WindowExplorer/wndexp.h b/plugins/WindowExplorer/wndexp.h index e77a7c45121e..b2bd9ba1e053 100644 --- a/plugins/WindowExplorer/wndexp.h +++ b/plugins/WindowExplorer/wndexp.h @@ -11,7 +11,6 @@ #include "resource.h" #include "wndtree.h" -extern BOOLEAN IsHookClient; extern PPH_PLUGIN PluginInstance; #define PLUGIN_NAME L"ProcessHacker.WindowExplorer" @@ -20,58 +19,6 @@ extern PPH_PLUGIN PluginInstance; #define SETTING_NAME_WINDOWS_WINDOW_POSITION (PLUGIN_NAME L".WindowsWindowPosition") #define SETTING_NAME_WINDOWS_WINDOW_SIZE (PLUGIN_NAME L".WindowsWindowSize") -// hook - -#define WE_SERVER_MESSAGE_NAME L"WE_ServerMessage" -#define WE_SERVER_SHARED_SECTION_NAME L"\\BaseNamedObjects\\WeSharedSection" -#define WE_SERVER_SHARED_SECTION_LOCK_NAME L"\\BaseNamedObjects\\WeSharedSectionLock" -#define WE_SERVER_SHARED_SECTION_EVENT_NAME L"\\BaseNamedObjects\\WeSharedSectionEvent" -#define WE_CLIENT_MESSAGE_TIMEOUT 2000 - -typedef struct _WE_HOOK_SHARED_DATA -{ - ULONG MessageId; - - struct - { - ULONG_PTR WndProc; - ULONG_PTR DlgProc; - WNDCLASSEX ClassInfo; - } c; -} WE_HOOK_SHARED_DATA, *PWE_HOOK_SHARED_DATA; - -VOID WeHookServerInitialization( - VOID - ); - -VOID WeHookServerUninitialization( - VOID - ); - -BOOLEAN WeIsServerActive( - VOID - ); - -BOOLEAN WeLockServerSharedData( - _Out_ PWE_HOOK_SHARED_DATA *Data - ); - -VOID WeUnlockServerSharedData( - VOID - ); - -BOOLEAN WeSendServerRequest( - _In_ HWND hWnd - ); - -VOID WeHookClientInitialization( - VOID - ); - -VOID WeHookClientUninitialization( - VOID - ); - // wnddlg typedef enum _WE_WINDOW_SELECTOR_TYPE diff --git a/plugins/WindowExplorer/wndprp.c b/plugins/WindowExplorer/wndprp.c index f1ecfbc699cc..d00209b26a3a 100644 --- a/plugins/WindowExplorer/wndprp.c +++ b/plugins/WindowExplorer/wndprp.c @@ -51,8 +51,6 @@ typedef struct _WINDOW_PROPERTIES_CONTEXT PPH_STRING ClassWndProcSymbol; ULONG ClassWndProcResolving; - BOOLEAN HookDataValid; - BOOLEAN HookDataSuccess; ULONG_PTR WndProc; ULONG_PTR DlgProc; WNDCLASSEX ClassInfo; @@ -593,57 +591,6 @@ FORCEINLINE BOOLEAN WepPropPageDlgProcHeader( return TRUE; } -static VOID WepEnsureHookDataValid( - _In_ PWINDOW_PROPERTIES_CONTEXT Context - ) -{ - if (!Context->HookDataValid) - { - PWE_HOOK_SHARED_DATA data; -#ifdef _WIN64 - HANDLE processHandle; - BOOLEAN isWow64 = FALSE; -#endif - - // The desktop window is owned by CSR. The hook will never work on the desktop window. - if (Context->WindowHandle == GetDesktopWindow()) - { - Context->HookDataValid = TRUE; - return; - } - -#ifdef _WIN64 - // We can't use the hook on WOW64 processes. - if (NT_SUCCESS(PhOpenProcess(&processHandle, *(PULONG)WeGetProcedureAddress("ProcessQueryAccess"), Context->ClientId.UniqueProcess))) - { - PhGetProcessIsWow64(processHandle, &isWow64); - NtClose(processHandle); - } - - if (isWow64) - return; -#endif - - WeHookServerInitialization(); - - Context->HookDataSuccess = FALSE; - - if (WeLockServerSharedData(&data)) - { - if (WeSendServerRequest(Context->WindowHandle)) - { - Context->WndProc = data->c.WndProc; - Context->DlgProc = data->c.DlgProc; - memcpy(&Context->ClassInfo, &data->c.ClassInfo, sizeof(WNDCLASSEX)); - Context->HookDataSuccess = TRUE; - } - - WeUnlockServerSharedData(); - } - - Context->HookDataValid = TRUE; - } -} static BOOLEAN NTAPI EnumGenericModulesCallback( _In_ PPH_MODULE_INFO Module, @@ -658,7 +605,7 @@ static BOOLEAN NTAPI EnumGenericModulesCallback( return TRUE; } -static NTSTATUS WepResolveSymbolFunction( +NTSTATUS WepResolveSymbolFunction( _In_ PVOID Parameter ) { @@ -845,7 +792,7 @@ static VOID WepRefreshWindowGeneralInfo( PhSetDialogItemText(hwndDlg, IDC_UNICODE, IsWindowUnicode(Context->WindowHandle) ? L"Yes" : L"No"); PhSetDialogItemText(hwndDlg, IDC_CTRLID, PhaFormatString(L"%lu", windowId)->Buffer); - WepEnsureHookDataValid(Context); + //WepQueryProcessWndProc(Context); if (Context->WndProc != 0) { @@ -889,7 +836,6 @@ INT_PTR CALLBACK WepWindowGeneralDlgProc( switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDC_REFRESH: - context->HookDataValid = FALSE; PhClearReference(&context->WndProcSymbol); WepRefreshWindowGeneralInfo(hwndDlg, context); break; @@ -1061,14 +1007,12 @@ static VOID WepRefreshWindowClassInfo( if (!GetClassName(Context->WindowHandle, className, sizeof(className) / sizeof(WCHAR))) className[0] = 0; - WepEnsureHookDataValid(Context); - - if (!Context->HookDataSuccess) - { - Context->ClassInfo.cbSize = sizeof(WNDCLASSEX); - GetClassInfoEx(NULL, className, &Context->ClassInfo); - } + //WepQueryProcessWndProc(Context); + //if (!Context->HookDataSuccess) + Context->ClassInfo.cbSize = sizeof(WNDCLASSEX); + GetClassInfoEx(NULL, className, &Context->ClassInfo); + instanceHandle = (PVOID)GetClassLongPtr(Context->WindowHandle, GCLP_HMODULE); // TODO: GetWindowLongPtr(Context->WindowHandle, GCLP_WNDPROC); @@ -1169,7 +1113,6 @@ INT_PTR CALLBACK WepWindowClassDlgProc( switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDC_REFRESH: - context->HookDataValid = FALSE; PhClearReference(&context->ClassWndProcSymbol); WepRefreshWindowClassInfo(hwndDlg, context); break; From 6b21e08a81fc13ec7cda595ef02d155a99e51edb Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 17 Aug 2018 13:48:58 +1000 Subject: [PATCH 1294/2058] Add support for viewing the process default token --- ProcessHacker/ProcessHacker.rc | 1 + ProcessHacker/prpgtok.c | 7 ++++++- ProcessHacker/resource.h | 1 + ProcessHacker/tokprp.c | 12 ++++++++++++ 4 files changed, 20 insertions(+), 1 deletion(-) diff --git a/ProcessHacker/ProcessHacker.rc b/ProcessHacker/ProcessHacker.rc index 954be5620a83..584f258c28e7 100644 --- a/ProcessHacker/ProcessHacker.rc +++ b/ProcessHacker/ProcessHacker.rc @@ -672,6 +672,7 @@ BEGIN PUSHBUTTON "Integrity",IDC_INTEGRITY,149,239,50,14 PUSHBUTTON "Advanced",IDC_ADVANCED,203,239,50,14 PUSHBUTTON "Permissions",IDC_PERMISSIONS,95,239,50,14 + PUSHBUTTON "Default token",IDC_DEFAULTPERM,41,239,50,14 END IDD_HIDDENPROCESSES DIALOGEX 0, 0, 337, 221 diff --git a/ProcessHacker/prpgtok.c b/ProcessHacker/prpgtok.c index 060811d57673..cd55d76acb96 100644 --- a/ProcessHacker/prpgtok.c +++ b/ProcessHacker/prpgtok.c @@ -42,7 +42,11 @@ NTSTATUS NTAPI PhpOpenProcessTokenForPage( ))) return status; - status = PhOpenProcessToken(processHandle, DesiredAccess, Handle); + status = PhOpenProcessToken( + processHandle, + DesiredAccess | TOKEN_READ | TOKEN_ADJUST_DEFAULT | READ_CONTROL, // HACK: Add extra access_masks for querying default token. (dmex) + Handle + ); NtClose(processHandle); return status; @@ -76,6 +80,7 @@ INT_PTR CALLBACK PhpProcessTokenHookProc( PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_USERSID), dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_VIRTUALIZED), dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_GROUPS), dialogItem, PH_ANCHOR_ALL); + PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_DEFAULTPERM), dialogItem, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_PERMISSIONS), dialogItem, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_INTEGRITY), dialogItem, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_ADVANCED), dialogItem, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); diff --git a/ProcessHacker/resource.h b/ProcessHacker/resource.h index 63844a0ebdfc..f095f24092b5 100644 --- a/ProcessHacker/resource.h +++ b/ProcessHacker/resource.h @@ -544,6 +544,7 @@ #define IDC_FILESIZE 1408 #define IDC_FILETYPE 1409 #define IDC_FILEMODE 1410 +#define IDC_DEFAULTPERM 1410 #define ID_HACKER_EXIT 40001 #define ID_PROCESS_PROPERTIES 40006 #define ID_PROCESS_TERMINATE 40007 diff --git a/ProcessHacker/tokprp.c b/ProcessHacker/tokprp.c index cdfb98cbac97..8335c897d240 100644 --- a/ProcessHacker/tokprp.c +++ b/ProcessHacker/tokprp.c @@ -891,6 +891,18 @@ INT_PTR CALLBACK PhpTokenPageProc( PhCopyListView(tokenPageContext->ListViewHandle); } break; + case IDC_DEFAULTPERM: + { + PhEditSecurity( + PhCsForceNoParent ? NULL : hwndDlg, + L"Default Token", + L"TokenDefault", + tokenPageContext->OpenObject, + NULL, + tokenPageContext->Context + ); + } + break; case IDC_PERMISSIONS: { PhEditSecurity( From 055a79bb96462b3b4413cad3ec684abb7528eb1b Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 17 Aug 2018 13:50:36 +1000 Subject: [PATCH 1295/2058] Add initial security editor TokenDefaultDacl support --- phlib/secedit.c | 37 ++++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/phlib/secedit.c b/phlib/secedit.c index 59351b70cf15..a6d7f57607aa 100644 --- a/phlib/secedit.c +++ b/phlib/secedit.c @@ -754,7 +754,7 @@ _Callback_ NTSTATUS PhStdGetObjectSecurity( status = PhpGetObjectSecurityWithTimeout(handle, SecurityInformation, SecurityDescriptor); NtClose(handle); } - if ( + else if ( PhEqualString2(this->ObjectType, L"LsaAccount", TRUE) || PhEqualString2(this->ObjectType, L"LsaPolicy", TRUE) || PhEqualString2(this->ObjectType, L"LsaSecret", TRUE) || @@ -807,6 +807,37 @@ _Callback_ NTSTATUS PhStdGetObjectSecurity( // //SamCloseHandle(handle); } + else if (PhEqualString2(this->ObjectType, L"TokenDefault", TRUE)) // HACK: Fake non-system type (dmex) + { + PTOKEN_DEFAULT_DACL defaultDacl; + + status = PhQueryTokenVariableSize( + handle, + TokenDefaultDacl, + &defaultDacl + ); + + if (NT_SUCCESS(status)) + { + PSECURITY_DESCRIPTOR securityDescriptor; + PTOKEN_OWNER tokenOwner; + + securityDescriptor = PhAllocateZero(SECURITY_DESCRIPTOR_MIN_LENGTH); + RtlCreateSecurityDescriptor(securityDescriptor, SECURITY_DESCRIPTOR_REVISION); + RtlSetDaclSecurityDescriptor(securityDescriptor, TRUE, defaultDacl->DefaultDacl, FALSE); + + if (NT_SUCCESS(PhGetTokenOwner(handle, &tokenOwner))) + { + RtlSetOwnerSecurityDescriptor(securityDescriptor, tokenOwner->Owner, FALSE); + PhFree(tokenOwner); + } + + *SecurityDescriptor = securityDescriptor; + PhFree(defaultDacl); + } + + NtClose(handle); + } else { status = PhGetObjectSecurity(handle, SecurityInformation, SecurityDescriptor); @@ -881,6 +912,10 @@ _Callback_ NTSTATUS PhStdSetObjectSecurity( // //SamCloseHandle(handle); } + else if (PhEqualString2(this->ObjectType, L"TokenDefault", TRUE)) + { + // TODO + } else { status = PhSetObjectSecurity(handle, SecurityInformation, SecurityDescriptor); From c653333514f6ab7c4147234b7eb4bd05f1c5b361 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 17 Aug 2018 15:45:49 +1000 Subject: [PATCH 1296/2058] Add hidden process handle scan method --- ProcessHacker/hidnproc.c | 144 ++++++++++++++++++++++++------- ProcessHacker/include/hidnproc.h | 3 +- 2 files changed, 117 insertions(+), 30 deletions(-) diff --git a/ProcessHacker/hidnproc.c b/ProcessHacker/hidnproc.c index 31db1d5e4a62..7526ed4bc346 100644 --- a/ProcessHacker/hidnproc.c +++ b/ProcessHacker/hidnproc.c @@ -111,7 +111,7 @@ VOID PhShowHiddenProcessesDialog( SetForegroundWindow(PhHiddenProcessesWindowHandle); } -static INT_PTR CALLBACK PhpHiddenProcessesDlgProc( +INT_PTR CALLBACK PhpHiddenProcessesDlgProc( _In_ HWND hwndDlg, _In_ UINT uMsg, _In_ WPARAM wParam, @@ -140,16 +140,6 @@ static INT_PTR CALLBACK PhpHiddenProcessesDlgProc( PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDC_SCAN), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDOK), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); - MinimumSize.left = 0; - MinimumSize.top = 0; - MinimumSize.right = 330; - MinimumSize.bottom = 140; - MapDialogRect(hwndDlg, &MinimumSize); - - PhRegisterDialog(hwndDlg); - - PhLoadWindowPlacementFromSetting(L"HiddenProcessesWindowPosition", L"HiddenProcessesWindowSize", hwndDlg); - PhSetListViewStyle(lvHandle, TRUE, TRUE); PhSetControlTheme(lvHandle, L"explorer"); PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 320, L"Process"); @@ -163,7 +153,16 @@ static INT_PTR CALLBACK PhpHiddenProcessesDlgProc( ComboBox_AddString(GetDlgItem(hwndDlg, IDC_METHOD), L"Brute force"); ComboBox_AddString(GetDlgItem(hwndDlg, IDC_METHOD), L"CSR handles"); - PhSelectComboBoxString(GetDlgItem(hwndDlg, IDC_METHOD), L"CSR handles", FALSE); + ComboBox_AddString(GetDlgItem(hwndDlg, IDC_METHOD), L"Process handles"); + PhSelectComboBoxString(GetDlgItem(hwndDlg, IDC_METHOD), L"Process handles", FALSE); + + MinimumSize.left = 0; + MinimumSize.top = 0; + MinimumSize.right = 330; + MinimumSize.bottom = 140; + MapDialogRect(hwndDlg, &MinimumSize); + + PhLoadWindowPlacementFromSetting(L"HiddenProcessesWindowPosition", L"HiddenProcessesWindowSize", hwndDlg); EnableWindow(GetDlgItem(hwndDlg, IDC_TERMINATE), FALSE); } @@ -183,7 +182,7 @@ static INT_PTR CALLBACK PhpHiddenProcessesDlgProc( case IDCANCEL: case IDOK: { - EndDialog(hwndDlg, IDOK); + DestroyWindow(hwndDlg); } break; case IDC_SCAN: @@ -212,10 +211,13 @@ static INT_PTR CALLBACK PhpHiddenProcessesDlgProc( ProcessesList = PhCreateList(40); - ProcessesMethod = - PhEqualString2(method, L"Brute force", TRUE) ? - BruteForceScanMethod : - CsrHandlesScanMethod; + if (PhEqualString2(method, L"Brute force", TRUE)) + ProcessesMethod = BruteForceScanMethod; + else if (PhEqualString2(method, L"CSR handles", TRUE)) + ProcessesMethod = CsrHandlesScanMethod; + else if (PhEqualString2(method, L"Process handles", TRUE)) + ProcessesMethod = ProcessHandleScanMethod; + NumberOfHiddenProcesses = 0; NumberOfTerminatedProcesses = 0; @@ -927,26 +929,110 @@ NTSTATUS PhpEnumHiddenProcessesCsrHandles( return status; } -NTSTATUS PhEnumHiddenProcesses( - _In_ PH_HIDDEN_PROCESS_METHOD Method, +NTSTATUS PhpEnumHiddenProcessHandles( _In_ PPH_ENUM_HIDDEN_PROCESSES_CALLBACK Callback, _In_opt_ PVOID Context ) { - if (Method == BruteForceScanMethod) + NTSTATUS status; + PVOID processes; + HANDLE processHandle; + + if (!NT_SUCCESS(status = PhEnumProcesses(&processes))) + return status; + + if (NT_SUCCESS(NtGetNextProcess( + NULL, + PROCESS_QUERY_LIMITED_INFORMATION, + 0, + 0, + &processHandle + ))) { - return PhpEnumHiddenProcessesBruteForce( - Callback, - Context - ); + while (TRUE) + { + HANDLE newProcessHandle; + PROCESS_EXTENDED_BASIC_INFORMATION basicInfo; + + if (NT_SUCCESS(PhGetProcessExtendedBasicInformation(processHandle, &basicInfo))) + { + if (!PhFindProcessInformation(PhProcessInformation, basicInfo.BasicInfo.UniqueProcessId)) + { + PH_HIDDEN_PROCESS_ENTRY entry; + PPH_STRING fileName; + + entry.ProcessId = basicInfo.BasicInfo.UniqueProcessId; + + if (NT_SUCCESS(status = PhGetProcessImageFileName(processHandle, &fileName))) + { + entry.FileName = PhGetFileName(fileName); + PhDereferenceObject(fileName); + entry.Type = HiddenProcess; + + if (basicInfo.IsProcessDeleting) + entry.Type = TerminatedProcess; + + if (!Callback(&entry, Context)) + break; + + PhDereferenceObject(entry.FileName); + } + + if (!NT_SUCCESS(status)) + { + entry.FileName = NULL; + entry.Type = UnknownProcess; + + if (!Callback(&entry, Context)) + break; + } + } + } + + if (NT_SUCCESS(status = NtGetNextProcess( + processHandle, + PROCESS_QUERY_LIMITED_INFORMATION, + 0, + 0, + &newProcessHandle + ))) + { + NtClose(processHandle); + processHandle = newProcessHandle; + } + else + { + NtClose(processHandle); + break; + } + } } - else + + PhFree(processes); + + if (status == STATUS_NO_MORE_ENTRIES) + status = STATUS_SUCCESS; // HACK + + return status; +} + +NTSTATUS PhEnumHiddenProcesses( + _In_ PH_HIDDEN_PROCESS_METHOD Method, + _In_ PPH_ENUM_HIDDEN_PROCESSES_CALLBACK Callback, + _In_opt_ PVOID Context + ) +{ + switch (Method) { - return PhpEnumHiddenProcessesCsrHandles( - Callback, - Context - ); + case BruteForceScanMethod: + return PhpEnumHiddenProcessesBruteForce(Callback, Context); + case CsrHandlesScanMethod: + return PhpEnumHiddenProcessesCsrHandles(Callback, Context); + case ProcessHandleScanMethod: + return PhpEnumHiddenProcessHandles(Callback, Context); } + + return STATUS_FAIL_CHECK; } NTSTATUS PhpOpenCsrProcesses( diff --git a/ProcessHacker/include/hidnproc.h b/ProcessHacker/include/hidnproc.h index 471f9f9482ce..4cf157f28ab8 100644 --- a/ProcessHacker/include/hidnproc.h +++ b/ProcessHacker/include/hidnproc.h @@ -4,7 +4,8 @@ typedef enum _PH_HIDDEN_PROCESS_METHOD { BruteForceScanMethod, - CsrHandlesScanMethod + CsrHandlesScanMethod, + ProcessHandleScanMethod } PH_HIDDEN_PROCESS_METHOD; typedef enum _PH_HIDDEN_PROCESS_TYPE From 0a68ec3790caf291b7613f2fcc25b500ded2de98 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 17 Aug 2018 15:53:10 +1000 Subject: [PATCH 1297/2058] Fix handle scan error checking --- ProcessHacker/hidnproc.c | 98 ++++++++++++++++++++-------------------- 1 file changed, 49 insertions(+), 49 deletions(-) diff --git a/ProcessHacker/hidnproc.c b/ProcessHacker/hidnproc.c index 7526ed4bc346..b13c0c830d74 100644 --- a/ProcessHacker/hidnproc.c +++ b/ProcessHacker/hidnproc.c @@ -941,78 +941,78 @@ NTSTATUS PhpEnumHiddenProcessHandles( if (!NT_SUCCESS(status = PhEnumProcesses(&processes))) return status; - if (NT_SUCCESS(NtGetNextProcess( + if (!NT_SUCCESS(status = NtGetNextProcess( NULL, - PROCESS_QUERY_LIMITED_INFORMATION, + ProcessQueryAccess, 0, 0, &processHandle ))) + goto CleanupExit; + + while (TRUE) { - while (TRUE) - { - HANDLE newProcessHandle; - PROCESS_EXTENDED_BASIC_INFORMATION basicInfo; + HANDLE enumProcessHandle; + PROCESS_EXTENDED_BASIC_INFORMATION basicInfo; - if (NT_SUCCESS(PhGetProcessExtendedBasicInformation(processHandle, &basicInfo))) + if (NT_SUCCESS(PhGetProcessExtendedBasicInformation(processHandle, &basicInfo))) + { + if (!PhFindProcessInformation(processes, basicInfo.BasicInfo.UniqueProcessId)) { - if (!PhFindProcessInformation(PhProcessInformation, basicInfo.BasicInfo.UniqueProcessId)) - { - PH_HIDDEN_PROCESS_ENTRY entry; - PPH_STRING fileName; + PH_HIDDEN_PROCESS_ENTRY entry; + PPH_STRING fileName; - entry.ProcessId = basicInfo.BasicInfo.UniqueProcessId; + entry.ProcessId = basicInfo.BasicInfo.UniqueProcessId; - if (NT_SUCCESS(status = PhGetProcessImageFileName(processHandle, &fileName))) - { - entry.FileName = PhGetFileName(fileName); - PhDereferenceObject(fileName); - entry.Type = HiddenProcess; + if (NT_SUCCESS(PhGetProcessImageFileName(processHandle, &fileName))) + { + entry.FileName = PhGetFileName(fileName); + PhDereferenceObject(fileName); + entry.Type = HiddenProcess; - if (basicInfo.IsProcessDeleting) - entry.Type = TerminatedProcess; + if (basicInfo.IsProcessDeleting) + entry.Type = TerminatedProcess; - if (!Callback(&entry, Context)) - break; + if (!Callback(&entry, Context)) + break; - PhDereferenceObject(entry.FileName); - } - - if (!NT_SUCCESS(status)) - { - entry.FileName = NULL; - entry.Type = UnknownProcess; + PhDereferenceObject(entry.FileName); + } + else + { + entry.FileName = NULL; + entry.Type = UnknownProcess; - if (!Callback(&entry, Context)) - break; - } + if (!Callback(&entry, Context)) + break; } } + } - if (NT_SUCCESS(status = NtGetNextProcess( - processHandle, - PROCESS_QUERY_LIMITED_INFORMATION, - 0, - 0, - &newProcessHandle - ))) - { - NtClose(processHandle); - processHandle = newProcessHandle; - } - else - { - NtClose(processHandle); - break; - } + if (NT_SUCCESS(status = NtGetNextProcess( + processHandle, + ProcessQueryAccess, + 0, + 0, + &enumProcessHandle + ))) + { + NtClose(processHandle); + processHandle = enumProcessHandle; + } + else + { + NtClose(processHandle); + break; } } - PhFree(processes); - if (status == STATUS_NO_MORE_ENTRIES) status = STATUS_SUCCESS; // HACK +CleanupExit: + PhFree(processes); + return status; } From 06b6f64046f5119d029d935db05c4cd79be2c357 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 17 Aug 2018 17:39:22 +1000 Subject: [PATCH 1298/2058] Fix token default access entries --- phlib/secdata.c | 14 ++++++++++---- phlib/secedit.c | 9 ++++----- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/phlib/secdata.c b/phlib/secdata.c index c4f4706c4f92..f0807e4d61ce 100644 --- a/phlib/secdata.c +++ b/phlib/secdata.c @@ -510,6 +510,14 @@ ACCESS_ENTRIES(Token) { L"Query source", TOKEN_QUERY_SOURCE, FALSE, TRUE } }; +ACCESS_ENTRIES(TokenDefault) +{ + { L"Full control", GENERIC_ALL, TRUE, TRUE }, + { L"Read", GENERIC_READ, TRUE, TRUE }, + { L"Write", GENERIC_WRITE, TRUE, TRUE }, + { L"Execute", GENERIC_EXECUTE, TRUE, TRUE } +}; + ACCESS_ENTRIES(TpWorkerFactory) { { L"Full control", WORKER_FACTORY_ALL_ACCESS, TRUE, TRUE }, @@ -605,6 +613,7 @@ static PH_SPECIFIC_TYPE PhSpecificTypes[] = ACCESS_ENTRY(TmTm, FALSE), ACCESS_ENTRY(TmTx, FALSE), ACCESS_ENTRY(Token, FALSE), + ACCESS_ENTRY(TokenDefault, FALSE), ACCESS_ENTRY(TpWorkerFactory, FALSE), ACCESS_ENTRY(Type, FALSE), ACCESS_ENTRY(WindowStation, FALSE), @@ -698,10 +707,7 @@ BOOLEAN PhGetAccessEntries( } else { - accessEntries = PhAllocate(sizeof(PhStandardAccessEntries)); - memcpy(accessEntries, PhStandardAccessEntries, sizeof(PhStandardAccessEntries)); - - *AccessEntries = accessEntries; + *AccessEntries = PhAllocateCopy(PhStandardAccessEntries, sizeof(PhStandardAccessEntries)); *NumberOfAccessEntries = sizeof(PhStandardAccessEntries) / sizeof(PH_ACCESS_ENTRY); } diff --git a/phlib/secedit.c b/phlib/secedit.c index a6d7f57607aa..65bcdd8af0d3 100644 --- a/phlib/secedit.c +++ b/phlib/secedit.c @@ -165,7 +165,7 @@ ISecurityInformation *PhSecurityInformation_Create( PhSecurityInformation *info; ULONG i; - info = PhAllocate(sizeof(PhSecurityInformation)); + info = PhAllocateZero(sizeof(PhSecurityInformation)); info->VTable = &PhSecurityInformation_VTable; info->RefCount = 1; @@ -179,11 +179,10 @@ ISecurityInformation *PhSecurityInformation_Create( if (PhGetAccessEntries(ObjectType, &info->AccessEntriesArray, &info->NumberOfAccessEntries)) { - info->AccessEntries = PhAllocate(sizeof(SI_ACCESS) * info->NumberOfAccessEntries); + info->AccessEntries = PhAllocateZero(sizeof(SI_ACCESS) * info->NumberOfAccessEntries); for (i = 0; i < info->NumberOfAccessEntries; i++) { - memset(&info->AccessEntries[i], 0, sizeof(SI_ACCESS)); info->AccessEntries[i].pszName = info->AccessEntriesArray[i].Name; info->AccessEntries[i].mask = info->AccessEntriesArray[i].Access; @@ -218,7 +217,7 @@ HRESULT STDMETHODCALLTYPE PhSecurityInformation_QueryInterface( { PhSecurityInformation2 *info; - info = PhAllocate(sizeof(PhSecurityInformation2)); + info = PhAllocateZero(sizeof(PhSecurityInformation2)); info->VTable = &PhSecurityInformation_VTable2; info->RefCount = 1; @@ -462,7 +461,7 @@ HRESULT STDMETHODCALLTYPE PhSecurityInformation2_LookupSids( { PhSecurityIDataObject *dataObject; - dataObject = PhAllocate(sizeof(PhSecurityInformation)); + dataObject = PhAllocateZero(sizeof(PhSecurityInformation)); dataObject->VTable = &PhDataObject_VTable; dataObject->RefCount = 1; From ebd3b1e0835caddd3a2d1acc3bdb851c6116b29e Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 18 Aug 2018 10:45:38 +1000 Subject: [PATCH 1299/2058] Improve symbol event callbacks, Update thread stack progress window --- ProcessHacker/thrdstk.c | 232 ++++++++++------------------------------ phlib/include/symprv.h | 43 +++----- phlib/symprv.c | 73 ++----------- 3 files changed, 82 insertions(+), 266 deletions(-) diff --git a/ProcessHacker/thrdstk.c b/ProcessHacker/thrdstk.c index 5a645d64c2d0..df7a6393f679 100644 --- a/ProcessHacker/thrdstk.c +++ b/ProcessHacker/thrdstk.c @@ -672,146 +672,6 @@ VOID DeleteThreadStackTree( PhDereferenceObject(Context->NodeList); } -typedef struct _PH_THREAD_SYMBOL_STACK_CONTEXT -{ - HANDLE ProcessId; - PPH_SYMBOL_PROVIDER SymbolProvider; -} PH_THREAD_SYMBOL_STACK_CONTEXT, *PPH_THREAD_SYMBOL_STACK_CONTEXT; - -static BOOLEAN LoadSymbolsEnumGenericModulesCallback( - _In_ PPH_MODULE_INFO Module, - _In_opt_ PVOID Context - ) -{ - PPH_THREAD_SYMBOL_STACK_CONTEXT context = Context; - PPH_SYMBOL_PROVIDER symbolProvider = context->SymbolProvider; - - if (symbolProvider->Terminating) - return FALSE; - - // If we're loading kernel module symbols for a process other than System, ignore modules which - // are in user space. This may happen in Windows 7. - if (context->ProcessId == SYSTEM_PROCESS_ID && - (ULONG_PTR)Module->BaseAddress <= PhSystemBasicInformation.MaximumUserModeAddress) - { - return TRUE; - } - - PhLoadModuleSymbolProvider( - symbolProvider, - Module->FileName->Buffer, - (ULONG64)Module->BaseAddress, - Module->Size - ); - - return TRUE; -} - -static BOOLEAN LoadBasicSymbolsEnumGenericModulesCallback( - _In_ PPH_MODULE_INFO Module, - _In_opt_ PVOID Context - ) -{ - PPH_THREAD_SYMBOL_STACK_CONTEXT context = Context; - PPH_SYMBOL_PROVIDER symbolProvider = context->SymbolProvider; - - if (symbolProvider->Terminating) - return FALSE; - - if (PhEqualString2(Module->Name, L"ntdll.dll", TRUE) || - PhEqualString2(Module->Name, L"kernel32.dll", TRUE)) - { - PhLoadModuleSymbolProvider( - symbolProvider, - Module->FileName->Buffer, - (ULONG64)Module->BaseAddress, - Module->Size - ); - } - - return TRUE; -} - -VOID PhpLoadThreadStackSymbols( - _In_ HANDLE ProcessId, - _In_ PPH_SYMBOL_PROVIDER SymbolProvider - ) -{ - PH_THREAD_SYMBOL_STACK_CONTEXT loadContext; - - loadContext.SymbolProvider = SymbolProvider; - - if (ProcessId != SYSTEM_IDLE_PROCESS_ID) - { - if (SymbolProvider->IsRealHandle || ProcessId == SYSTEM_PROCESS_ID) - { - loadContext.ProcessId = ProcessId; - PhEnumGenericModules( - ProcessId, - SymbolProvider->ProcessHandle, - 0, - LoadSymbolsEnumGenericModulesCallback, - &loadContext - ); - } - else - { - // We can't enumerate the process modules. Load symbols for ntdll.dll and kernel32.dll. - loadContext.ProcessId = NtCurrentProcessId(); - PhEnumGenericModules( - NtCurrentProcessId(), - NtCurrentProcess(), - 0, - LoadBasicSymbolsEnumGenericModulesCallback, - &loadContext - ); - } - - // Load kernel module symbols as well. - if (ProcessId != SYSTEM_PROCESS_ID) - { - loadContext.ProcessId = SYSTEM_PROCESS_ID; - PhEnumGenericModules( - SYSTEM_PROCESS_ID, - NULL, - 0, - LoadSymbolsEnumGenericModulesCallback, - &loadContext - ); - } - } - else - { - // System Idle Process has one thread for each CPU, each having a start address at - // KiIdleLoop. We need to load symbols for the kernel. - - PRTL_PROCESS_MODULES kernelModules; - - if (NT_SUCCESS(PhEnumKernelModules(&kernelModules))) - { - if (kernelModules->NumberOfModules > 0) - { - PPH_STRING fileName; - PPH_STRING newFileName; - - fileName = PhConvertMultiByteToUtf16(kernelModules->Modules[0].FullPathName); - newFileName = PhGetFileName(fileName); - PhDereferenceObject(fileName); - - PhLoadModuleSymbolProvider( - SymbolProvider, - newFileName->Buffer, - (ULONG64)kernelModules->Modules[0].ImageBase, - kernelModules->Modules[0].ImageSize - ); - PhDereferenceObject(newFileName); - } - - PhFree(kernelModules); - } - } -} - VOID NTAPI PhpThreadStackContextDeleteProcedure( _In_ PVOID Object, _In_ ULONG Flags @@ -819,9 +679,6 @@ VOID NTAPI PhpThreadStackContextDeleteProcedure( { PPH_THREAD_STACK_CONTEXT context = (PPH_THREAD_STACK_CONTEXT)Object; - PhDereferenceObject(context->ThreadProvider); - PhDereferenceObject(context->SymbolProvider); - PhDereferenceObject(context->StatusMessage); PhDereferenceObject(context->NewList); PhDereferenceObject(context->List); @@ -888,10 +745,8 @@ VOID PhShowThreadStackDialog( context->ThreadHandle = threadHandle; context->ProcessId = ProcessId; context->ThreadId = ThreadId; - context->ThreadProvider = PhReferenceObject(ThreadProvider); - context->SymbolProvider = PhReferenceObject(ThreadProvider->SymbolProvider); - //context->SymbolProvider = PhCreateSymbolProvider(ProcessId); - //PhpLoadThreadStackSymbols(ProcessId, context->SymbolProvider); + context->ThreadProvider = ThreadProvider; + context->SymbolProvider = ThreadProvider->SymbolProvider; DialogBoxParam( PhInstanceHandle, @@ -1017,11 +872,9 @@ INT_PTR CALLBACK PhpThreadStackDlgProc( break; case WM_COMMAND: { - INT id = LOWORD(wParam); - - switch (id) + switch (GET_WM_COMMAND_ID(wParam, lParam)) { - case IDCANCEL: // Esc and X button to close + case IDCANCEL: case IDOK: EndDialog(hwndDlg, IDOK); break; @@ -1120,7 +973,7 @@ BOOLEAN NTAPI PhpWalkThreadStackCallback( PhReleaseQueuedLockExclusive(&threadStackContext->StatusLock); symbol = PhGetSymbolFromAddress( - threadStackContext->SymbolProvider, + threadStackContext->SymbolProvider, (ULONG64)StackFrame->PcAddress, NULL, NULL, @@ -1232,7 +1085,6 @@ NTSTATUS PhpRefreshThreadStackThreadStart( PostMessage(threadStackContext->TaskDialogHandle, WM_PH_COMPLETED, 0, 0); PhDeleteAutoPool(&autoPool); - PhDereferenceObject(threadStackContext); return STATUS_SUCCESS; @@ -1264,7 +1116,6 @@ LRESULT CALLBACK PhpThreadStackTaskDialogSubclassProc( case WM_PH_COMPLETED: { context->EnableCloseDialog = TRUE; - SendMessage(hwndDlg, TDM_CLICK_BUTTON, IDOK, 0); } break; @@ -1278,41 +1129,73 @@ VOID PhpSymbolProviderEventCallbackHandler( _In_opt_ PVOID Context ) { - PPH_SYMBOL_EVENT_DATA data = Parameter; + PPH_SYMBOL_EVENT_DATA event = Parameter; PPH_THREAD_STACK_CONTEXT context = Context; PPH_STRING statusMessage = NULL; - switch (data->Type) + switch (event->ActionCode) { case CBA_DEFERRED_SYMBOL_LOAD_START: - statusMessage = PhFormatString(L"Loading %s...", PhGetBaseName(data->FileName)->Buffer); - break; case CBA_DEFERRED_SYMBOL_LOAD_COMPLETE: - statusMessage = PhFormatString(L"Loaded %s...", PhGetBaseName(data->FileName)->Buffer); - break; case CBA_DEFERRED_SYMBOL_LOAD_FAILURE: - statusMessage = PhFormatString(L"Failed %s...", PhGetBaseName(data->FileName)->Buffer); - break; case CBA_SYMBOLS_UNLOADED: - statusMessage = PhFormatString(L"Unloaded %s...", data->FileName->Buffer); + { + PIMAGEHLP_DEFERRED_SYMBOL_LOADW64 callbackData = (PIMAGEHLP_DEFERRED_SYMBOL_LOADW64)event->EventData; + PPH_STRING fileName; + + fileName = PhCreateString(callbackData->FileName); + PhMoveReference(&fileName, PhGetBaseName(fileName)); + + switch (event->ActionCode) + { + case CBA_DEFERRED_SYMBOL_LOAD_START: + statusMessage = PhFormatString(L"Loading symbols from %s...", PhGetStringOrEmpty(fileName)); + break; + case CBA_DEFERRED_SYMBOL_LOAD_COMPLETE: + statusMessage = PhFormatString(L"Loaded symbols from %s...", PhGetStringOrEmpty(fileName)); + break; + case CBA_DEFERRED_SYMBOL_LOAD_FAILURE: + statusMessage = PhFormatString(L"Failed to load %s...", PhGetStringOrEmpty(fileName)); + break; + case CBA_SYMBOLS_UNLOADED: + statusMessage = PhFormatString(L"Unloading %s...", PhGetStringOrEmpty(fileName)); + break; + } + } break; case CBA_READ_MEMORY: - //statusMessage = PhFormatString(L"Reading memory: %I64u (FileNameImageAddress: %s)", data->BaseAddress); + { + PIMAGEHLP_CBA_READ_MEMORY callbackEvent = (PIMAGEHLP_CBA_READ_MEMORY)event->EventData; + //statusMessage = PhFormatString(L"Reading %lu bytes of memory from %I64u...", callbackEvent->bytes, callbackEvent->addr); + } break; - case CBA_DEFERRED_SYMBOL_LOAD_CANCEL: - //statusMessage = PhFormatString(L"Canceled: %s", data->FileName->Buffer); + case CBA_EVENT: + { + PIMAGEHLP_CBA_EVENTW callbackEvent = (PIMAGEHLP_CBA_EVENTW)event->EventData; + //statusMessage = PhFormatString(L"%s", callbackEvent->desc); + } break; + case CBA_DEBUG_INFO: + { + //statusMessage = PhFormatString(L"%s", event->EventData); + } + break; + case CBA_ENGINE_PRESENT: + case CBA_DEFERRED_SYMBOL_LOAD_PARTIAL: + case CBA_DEFERRED_SYMBOL_LOAD_CANCEL: default: - //statusMessage = PhFormatString(L"Unknown: %lu", data->Type); + { + //statusMessage = PhFormatString(L"Unknown: %lu", event->ActionCode); + } break; } if (statusMessage) { + //dprintf("%S\r\n", statusMessage->Buffer); PhAcquireQueuedLockExclusive(&context->StatusLock); PhMoveReference(&context->StatusContent, statusMessage); PhReleaseQueuedLockExclusive(&context->StatusLock); - //dprintf("SymbolProviderEventCallback: %S\r\n", statusMessage->Buffer); } } @@ -1331,9 +1214,9 @@ HRESULT CALLBACK PhpThreadStackTaskDialogCallback( case TDN_CREATED: { context->TaskDialogHandle = hwndDlg; - - PhSymbolProviderRegisterEventCallback( - context->SymbolProvider, + + PhRegisterCallback( + &PhSymbolEventCallback, PhpSymbolProviderEventCallbackHandler, context, &context->SymbolProviderEventRegistration @@ -1356,7 +1239,7 @@ HRESULT CALLBACK PhpThreadStackTaskDialogCallback( break; case TDN_DESTROYED: { - PhSymbolProviderUnregisterEventCallback(context->SymbolProvider, &context->SymbolProviderEventRegistration); + PhUnregisterCallback(&PhSymbolEventCallback, &context->SymbolProviderEventRegistration); } break; case TDN_BUTTON_CLICKED: @@ -1418,7 +1301,10 @@ BOOLEAN PhpShowThreadStackWindow( memset(&config, 0, sizeof(TASKDIALOGCONFIG)); config.cbSize = sizeof(TASKDIALOGCONFIG); - config.dwFlags = TDF_USE_HICON_MAIN | TDF_ALLOW_DIALOG_CANCELLATION | TDF_POSITION_RELATIVE_TO_WINDOW | TDF_SHOW_MARQUEE_PROGRESS_BAR | TDF_CALLBACK_TIMER; + config.dwFlags = + TDF_USE_HICON_MAIN | TDF_ALLOW_DIALOG_CANCELLATION | + TDF_POSITION_RELATIVE_TO_WINDOW | TDF_SHOW_MARQUEE_PROGRESS_BAR | + TDF_CALLBACK_TIMER; config.dwCommonButtons = TDCBF_CANCEL_BUTTON; config.pfCallback = PhpThreadStackTaskDialogCallback; config.lpCallbackData = (LONG_PTR)Context; diff --git a/phlib/include/symprv.h b/phlib/include/symprv.h index f28404053189..fb90c18386a5 100644 --- a/phlib/include/symprv.h +++ b/phlib/include/symprv.h @@ -6,6 +6,7 @@ extern "C" { #endif extern PPH_OBJECT_TYPE PhSymbolProviderType; +extern PH_CALLBACK PhSymbolEventCallback; #define PH_MAX_SYMBOL_NAME_LEN 128 @@ -14,13 +15,21 @@ typedef struct _PH_SYMBOL_PROVIDER LIST_ENTRY ModulesListHead; PH_QUEUED_LOCK ModulesListLock; HANDLE ProcessHandle; - BOOLEAN IsRealHandle; - BOOLEAN IsRegistered; - BOOLEAN Terminating; + + union + { + BOOLEAN Flags; + struct + { + BOOLEAN IsRealHandle : 1; + BOOLEAN IsRegistered : 1; + BOOLEAN Terminating : 1; + BOOLEAN Spare : 5; + }; + }; PH_INITONCE InitOnce; PH_AVL_TREE ModulesSet; - PH_CALLBACK EventCallback; } PH_SYMBOL_PROVIDER, *PPH_SYMBOL_PROVIDER; typedef enum _PH_SYMBOL_RESOLVE_LEVEL @@ -56,14 +65,10 @@ typedef enum _PH_SYMBOL_EVENT_TYPE typedef struct _PH_SYMBOL_EVENT_DATA { + PH_SYMBOL_EVENT_TYPE ActionCode; HANDLE ProcessHandle; PPH_SYMBOL_PROVIDER SymbolProvider; - PH_SYMBOL_EVENT_TYPE Type; - - ULONG64 BaseAddress; - ULONG CheckSum; - ULONG TimeStamp; - PPH_STRING FileName; + PVOID EventData; } PH_SYMBOL_EVENT_DATA, *PPH_SYMBOL_EVENT_DATA; PHLIBAPI @@ -291,24 +296,6 @@ PhUndecorateSymbolName( _In_ PWSTR DecoratedName ); -PHLIBAPI -VOID -NTAPI -PhSymbolProviderRegisterEventCallback( - _In_ PPH_SYMBOL_PROVIDER SymbolProvider, - _In_ PPH_CALLBACK_FUNCTION Function, - _In_opt_ PVOID Context, - _Out_ PPH_CALLBACK_REGISTRATION Registration - ); - -PHLIBAPI -VOID -NTAPI -PhSymbolProviderUnregisterEventCallback( - _In_ PPH_SYMBOL_PROVIDER SymbolProvider, - _In_ PPH_CALLBACK_REGISTRATION Registration - ); - #ifdef __cplusplus } #endif diff --git a/phlib/symprv.c b/phlib/symprv.c index 86cce8cdf2c2..ed59033f9081 100644 --- a/phlib/symprv.c +++ b/phlib/symprv.c @@ -62,6 +62,7 @@ LONG NTAPI PhpSymbolModuleCompareFunction( ); PPH_OBJECT_TYPE PhSymbolProviderType = NULL; +PH_CALLBACK_DECLARE(PhSymbolEventCallback); static PH_INITONCE PhSymInitOnce = PH_INITONCE_INIT; static HANDLE PhNextFakeHandle = (HANDLE)0; static PH_FAST_LOCK PhSymMutex = PH_FAST_LOCK_INIT; @@ -107,7 +108,6 @@ PPH_SYMBOL_PROVIDER PhCreateSymbolProvider( InitializeListHead(&symbolProvider->ModulesListHead); PhInitializeQueuedLock(&symbolProvider->ModulesListLock); PhInitializeAvlTree(&symbolProvider->ModulesSet, PhpSymbolModuleCompareFunction); - PhInitializeCallback(&symbolProvider->EventCallback); PhInitializeInitOnce(&symbolProvider->InitOnce); if (ProcessId) @@ -155,8 +155,6 @@ VOID NTAPI PhpSymbolProviderDeleteProcedure( PPH_SYMBOL_PROVIDER symbolProvider = (PPH_SYMBOL_PROVIDER)Object; PLIST_ENTRY listEntry; - PhDeleteCallback(&symbolProvider->EventCallback); - if (SymCleanup_I) { PH_LOCK_SYMBOLS(); @@ -182,21 +180,6 @@ VOID NTAPI PhpSymbolProviderDeleteProcedure( if (symbolProvider->IsRealHandle) NtClose(symbolProvider->ProcessHandle); } -NTSTATUS PhpSymbolCallbackWorker( - _In_ PVOID Parameter - ) -{ - PPH_SYMBOL_EVENT_DATA data = Parameter; - - //dprintf("symbol event %d: %S\n", data->Type, data->FileName->Buffer); - PhInvokeCallback(&data->SymbolProvider->EventCallback, data); - - if (data->FileName) PhDereferenceObject(data->FileName); - PhDereferenceObject(data); - - return STATUS_SUCCESS; -} - BOOL CALLBACK PhpSymbolCallbackFunction( _In_ HANDLE ProcessHandle, _In_ ULONG ActionCode, @@ -204,29 +187,21 @@ BOOL CALLBACK PhpSymbolCallbackFunction( _In_opt_ ULONG64 UserContext ) { - PIMAGEHLP_DEFERRED_SYMBOL_LOADW64 callbackData = (PIMAGEHLP_DEFERRED_SYMBOL_LOADW64)CallbackData; PPH_SYMBOL_PROVIDER symbolProvider = (PPH_SYMBOL_PROVIDER)UserContext; - assert(ProcessHandle == symbolProvider->ProcessHandle); - - if (!IsListEmpty(&symbolProvider->EventCallback.ListHead)) + if (!IsListEmpty(&PhSymbolEventCallback.ListHead)) { PPH_SYMBOL_EVENT_DATA data; - data = PhCreateAlloc(sizeof(PH_SYMBOL_EVENT_DATA)); - memset(data, 0, sizeof(PH_SYMBOL_EVENT_DATA)); - - data->Type = ActionCode; + data = PhAllocateZero(sizeof(PH_SYMBOL_EVENT_DATA)); + data->ActionCode = ActionCode; data->ProcessHandle = ProcessHandle; data->SymbolProvider = symbolProvider; - data->BaseAddress = callbackData->BaseOfImage; - data->CheckSum = callbackData->CheckSum; - data->TimeStamp = callbackData->TimeDateStamp; + data->EventData = (PVOID)CallbackData; - if (callbackData->FileName[0]) - data->FileName = PhCreateString(callbackData->FileName); + PhInvokeCallback(&PhSymbolEventCallback, data); - PhQueueItemWorkQueue(PhGetGlobalWorkQueue(), PhpSymbolCallbackWorker, data); + PhFree(data); } if (ActionCode == CBA_DEFERRED_SYMBOL_LOAD_CANCEL) @@ -362,8 +337,7 @@ VOID PhpRegisterSymbolProvider( SymGetOptions_I() | SYMOPT_AUTO_PUBLICS | SYMOPT_CASE_INSENSITIVE | SYMOPT_DEFERRED_LOADS | SYMOPT_FAIL_CRITICAL_ERRORS | SYMOPT_INCLUDE_32BIT_MODULES | - SYMOPT_LOAD_LINES | SYMOPT_OMAP_FIND_NEAREST | SYMOPT_UNDNAME | - SYMOPT_SECURE // | SYMOPT_DEBUG + SYMOPT_LOAD_LINES | SYMOPT_OMAP_FIND_NEAREST | SYMOPT_UNDNAME // | SYMOPT_DEBUG ); PH_UNLOCK_SYMBOLS(); @@ -1718,34 +1692,3 @@ PPH_STRING PhUndecorateSymbolName( return undecoratedSymbolName; } - -VOID PhSymbolProviderRegisterEventCallback( - _In_ PPH_SYMBOL_PROVIDER SymbolProvider, - _In_ PPH_CALLBACK_FUNCTION Function, - _In_opt_ PVOID Context, - _Out_ PPH_CALLBACK_REGISTRATION Registration - ) -{ - //PH_LOCK_SYMBOLS(); - - PhRegisterCallback( - &SymbolProvider->EventCallback, - Function, - Context, - Registration - ); - - //PH_UNLOCK_SYMBOLS(); -} - -VOID PhSymbolProviderUnregisterEventCallback( - _In_ PPH_SYMBOL_PROVIDER SymbolProvider, - _In_ PPH_CALLBACK_REGISTRATION Registration - ) -{ - //PH_LOCK_SYMBOLS(); - - PhUnregisterCallback(&SymbolProvider->EventCallback, Registration); - - //PH_UNLOCK_SYMBOLS(); -} From 7b4c9f96e680f233c6a5aa073bbcd60273ec460a Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 18 Aug 2018 10:46:01 +1000 Subject: [PATCH 1300/2058] Add PhGetTokenIsRestricted --- phlib/include/phnativeinl.h | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/phlib/include/phnativeinl.h b/phlib/include/phnativeinl.h index c84eb1a4675b..bbe6073ce978 100644 --- a/phlib/include/phnativeinl.h +++ b/phlib/include/phnativeinl.h @@ -1115,6 +1115,33 @@ PhGetTokenLinkedToken( return status; } +FORCEINLINE +NTSTATUS +PhGetTokenIsRestricted( + _In_ HANDLE TokenHandle, + _Out_ PBOOLEAN IsRestricted + ) +{ + NTSTATUS status; + ULONG returnLength; + ULONG restricted; + + status = NtQueryInformationToken( + TokenHandle, + TokenIsRestricted, + &restricted, + sizeof(ULONG), + &returnLength + ); + + if (!NT_SUCCESS(status)) + return status; + + *IsRestricted = !!restricted; + + return status; +} + /** * Gets whether virtualization is allowed for a token. * From 3ee4808921ae94e5f3a8749a5827cac2903bc4be Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 18 Aug 2018 10:48:01 +1000 Subject: [PATCH 1301/2058] Update winsta definitions --- phlib/util.c | 26 +-- phnt/include/winsta.h | 424 ++++++++++++++++++++++++++++++++++++------ 2 files changed, 368 insertions(+), 82 deletions(-) diff --git a/phlib/util.c b/phlib/util.c index a2d5d42f5f24..cbacb99dba9e 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -39,15 +39,6 @@ #include "sha.h" #include "sha256.h" -typedef BOOLEAN (NTAPI *_WinStationQueryInformationW)( - _In_opt_ HANDLE ServerHandle, - _In_ ULONG LogonId, - _In_ WINSTATIONINFOCLASS WinStationInformationClass, - _Out_writes_bytes_(WinStationInformationLength) PVOID WinStationInformation, - _In_ ULONG WinStationInformationLength, - _Out_ PULONG ReturnLength - ); - DECLSPEC_SELECTANY WCHAR *PhSizeUnitNames[7] = { L"B", L"kB", L"MB", L"GB", L"TB", L"PB", L"EB" }; DECLSPEC_SELECTANY ULONG PhMaxSizeUnit = MAXULONG32; @@ -2597,24 +2588,12 @@ NTSTATUS PhCreateProcessAsUser( _Out_opt_ PHANDLE ThreadHandle ) { - static PH_INITONCE initOnce = PH_INITONCE_INIT; - static _WinStationQueryInformationW WinStationQueryInformationW_I = NULL; NTSTATUS status; HANDLE tokenHandle; PVOID defaultEnvironment = NULL; STARTUPINFO startupInfo = { sizeof(startupInfo) }; BOOLEAN needsDuplicate = FALSE; - if (PhBeginInitOnce(&initOnce)) - { - HMODULE winsta; - - winsta = LoadLibrary(L"winsta.dll"); - WinStationQueryInformationW_I = PhGetDllBaseProcedureAddress(winsta, "WinStationQueryInformationW", 0); - - PhEndInitOnce(&initOnce); - } - if ((Flags & PH_CREATE_PROCESS_USE_PROCESS_TOKEN) && (Flags & PH_CREATE_PROCESS_USE_SESSION_TOKEN)) return STATUS_INVALID_PARAMETER_2; if (!Information->ApplicationName && !Information->CommandLine) @@ -2722,10 +2701,7 @@ NTSTATUS PhCreateProcessAsUser( WINSTATIONUSERTOKEN userToken; ULONG returnLength; - if (!WinStationQueryInformationW_I) - return STATUS_PROCEDURE_NOT_FOUND; - - if (!WinStationQueryInformationW_I( + if (!WinStationQueryInformationW( NULL, Information->SessionIdWithToken, WinStationUserToken, diff --git a/phnt/include/winsta.h b/phnt/include/winsta.h index 84d7e19e5063..f0cf99d60795 100644 --- a/phnt/include/winsta.h +++ b/phnt/include/winsta.h @@ -1,8 +1,6 @@ #ifndef _WINSTA_H #define _WINSTA_H -// begin_msdn:http://msdn.microsoft.com/en-us/library/cc248779%28PROT.10%29.aspx - // Access rights #define WINSTATION_QUERY 0x00000001 // WinStationQueryInformation @@ -28,6 +26,13 @@ WINSTATION_CONNECT | WINSTATION_DISCONNECT) #define WDPREFIX_LENGTH 12 +#define CALLBACK_LENGTH 50 +#define DLLNAME_LENGTH 32 +#define CDNAME_LENGTH 32 +#define WDNAME_LENGTH 32 +#define PDNAME_LENGTH 32 +#define DEVICENAME_LENGTH 128 +#define MODEMNAME_LENGTH DEVICENAME_LENGTH #define STACK_ADDRESS_LENGTH 128 #define MAX_BR_NAME 65 #define DIRECTORY_LENGTH 256 @@ -104,57 +109,298 @@ typedef struct _SESSIONIDW // private typedef enum _WINSTATIONINFOCLASS { - WinStationCreateData, - WinStationConfiguration, - WinStationPdParams, - WinStationWd, - WinStationPd, - WinStationPrinter, - WinStationClient, + WinStationCreateData, // WINSTATIONCREATE + WinStationConfiguration, // WINSTACONFIGWIRE + USERCONFIG + WinStationPdParams, // PDPARAMS + WinStationWd, // WDCONFIG + WinStationPd, // PDCONFIG2 + PDPARAMS + WinStationPrinter, // Not supported. + WinStationClient, // WINSTATIONCLIENT WinStationModules, - WinStationInformation, + WinStationInformation, // WINSTATIONINFORMATION WinStationTrace, WinStationBeep, WinStationEncryptionOff, WinStationEncryptionPerm, WinStationNtSecurity, - WinStationUserToken, + WinStationUserToken, // WINSTATIONUSERTOKEN WinStationUnused1, - WinStationVideoData, + WinStationVideoData, // WINSTATIONVIDEODATA WinStationInitialProgram, - WinStationCd, + WinStationCd, // CDCONFIG WinStationSystemTrace, WinStationVirtualData, - WinStationClientData, + WinStationClientData, // WINSTATIONCLIENTDATA WinStationSecureDesktopEnter, WinStationSecureDesktopExit, - WinStationLoadBalanceSessionTarget, - WinStationLoadIndicator, - WinStationShadowInfo, - WinStationDigProductId, - WinStationLockedState, - WinStationRemoteAddress, - WinStationIdleTime, - WinStationLastReconnectType, - WinStationDisallowAutoReconnect, + WinStationLoadBalanceSessionTarget, // ULONG + WinStationLoadIndicator, // WINSTATIONLOADINDICATORDATA + WinStationShadowInfo, // WINSTATIONSHADOW + WinStationDigProductId, // WINSTATIONPRODID + WinStationLockedState, // BOOL + WinStationRemoteAddress, // WINSTATIONREMOTEADDRESS + WinStationIdleTime, // ULONG + WinStationLastReconnectType, // ULONG + WinStationDisallowAutoReconnect, // BOOLEAN WinStationMprNotifyInfo, WinStationExecSrvSystemPipe, WinStationSmartCardAutoLogon, WinStationIsAdminLoggedOn, - WinStationReconnectedFromId, - WinStationEffectsPolicy, - WinStationType, - WinStationInformationEx, + WinStationReconnectedFromId, // ULONG + WinStationEffectsPolicy, // ULONG + WinStationType, // ULONG + WinStationInformationEx, // WINSTATIONINFORMATIONEX WinStationValidationInfo } WINSTATIONINFOCLASS; -// WinStationCreateData +// Retrieves general information on the type of terminal server session (protocol) to which the session belongs. typedef struct _WINSTATIONCREATE { ULONG fEnableWinStation : 1; ULONG MaxInstanceCount; } WINSTATIONCREATE, *PWINSTATIONCREATE; +typedef struct _WINSTACONFIGWIRE +{ + WCHAR Comment[61]; // The WinStation descriptive comment. + CHAR OEMId[4]; // Value identifying the OEM implementor of the TermService Listener to which this session (WinStation) belongs. This can be any value defined by the implementer (OEM) of the listener. + VARDATA_WIRE UserConfig; // VARDATA_WIRE structure defining the size and offset of the variable-length user configuration data succeeding it. + VARDATA_WIRE NewFields; // VARDATA_WIRE structure defining the size and offset of the variable-length new data succeeding it. This field is not used and is a placeholder for any new data, if and when added. +} WINSTACONFIGWIRE, *PWINSTACONFIGWIRE; + +typedef enum _CALLBACKCLASS +{ + Callback_Disable, + Callback_Roving, + Callback_Fixed +} CALLBACKCLASS; + +// The SHADOWCLASS enumeration is used to indicate the shadow-related settings for a session running on a terminal server. +typedef enum _SHADOWCLASS +{ + Shadow_Disable, // Shadowing is disabled. + Shadow_EnableInputNotify, // Permission is asked first from the session being shadowed. The shadower is also permitted keyboard and mouse input. + Shadow_EnableInputNoNotify, // Permission is not asked first from the session being shadowed. The shadower is also permitted keyboard and mouse input. + Shadow_EnableNoInputNotify, // Permission is asked first from the session being shadowed. The shadower is not permitted keyboard and mouse input and MUST observe the shadowed session. + Shadow_EnableNoInputNoNotify // Permission is not asked first from the session being shadowed. The shadower is not permitted keyboard and mouse input and MUST observe the shadowed session. +} SHADOWCLASS; + +// For a specific terminal server session, the USERCONFIG structure indicates the user and session configuration. +// https://msdn.microsoft.com/en-us/library/cc248610.aspx +typedef struct _USERCONFIG +{ + ULONG fInheritAutoLogon : 1; + ULONG fInheritResetBroken : 1; + ULONG fInheritReconnectSame : 1; + ULONG fInheritInitialProgram : 1; + ULONG fInheritCallback : 1; + ULONG fInheritCallbackNumber : 1; + ULONG fInheritShadow : 1; + ULONG fInheritMaxSessionTime : 1; + ULONG fInheritMaxDisconnectionTime : 1; + ULONG fInheritMaxIdleTime : 1; + ULONG fInheritAutoClient : 1; + ULONG fInheritSecurity : 1; + ULONG fPromptForPassword : 1; + ULONG fResetBroken : 1; + ULONG fReconnectSame : 1; + ULONG fLogonDisabled : 1; + ULONG fWallPaperDisabled : 1; + ULONG fAutoClientDrives : 1; + ULONG fAutoClientLpts : 1; + ULONG fForceClientLptDef : 1; + ULONG fRequireEncryption : 1; + ULONG fDisableEncryption : 1; + ULONG fUnused1 : 1; + ULONG fHomeDirectoryMapRoot : 1; + ULONG fUseDefaultGina : 1; + ULONG fCursorBlinkDisabled : 1; + ULONG fPublishedApp : 1; + ULONG fHideTitleBar : 1; + ULONG fMaximize : 1; + ULONG fDisableCpm : 1; + ULONG fDisableCdm : 1; + ULONG fDisableCcm : 1; + ULONG fDisableLPT : 1; + ULONG fDisableClip : 1; + ULONG fDisableExe : 1; + ULONG fDisableCam : 1; + ULONG fDisableAutoReconnect : 1; + ULONG ColorDepth : 3; + ULONG fInheritColorDepth : 1; + ULONG fErrorInvalidProfile : 1; + ULONG fPasswordIsScPin : 1; + ULONG fDisablePNPRedir : 1; + WCHAR UserName[USERNAME_LENGTH + 1]; + WCHAR Domain[DOMAIN_LENGTH + 1]; + WCHAR Password[PASSWORD_LENGTH + 1]; + WCHAR WorkDirectory[DIRECTORY_LENGTH + 1]; + WCHAR InitialProgram[INITIALPROGRAM_LENGTH + 1]; + WCHAR CallbackNumber[CALLBACK_LENGTH + 1]; + CALLBACKCLASS Callback; + SHADOWCLASS Shadow; + ULONG MaxConnectionTime; + ULONG MaxDisconnectionTime; + ULONG MaxIdleTime; + ULONG KeyboardLayout; + BYTE MinEncryptionLevel; + WCHAR NWLogonServer[NASIFILESERVER_LENGTH + 1]; + WCHAR PublishedName[MAX_BR_NAME]; + WCHAR WFProfilePath[DIRECTORY_LENGTH + 1]; + WCHAR WFHomeDir[DIRECTORY_LENGTH + 1]; + WCHAR WFHomeDirDrive[4]; +} USERCONFIG, *PUSERCONFIG; + +typedef enum _SDCLASS +{ + SdNone = 0, + SdConsole, + SdNetwork, + SdAsync, + SdOemTransport +} SDCLASS; + +typedef WCHAR DEVICENAME[DEVICENAME_LENGTH + 1]; +typedef WCHAR MODEMNAME[MODEMNAME_LENGTH + 1]; +typedef WCHAR NASISPECIFICNAME[NASISPECIFICNAME_LENGTH + 1]; +typedef WCHAR NASIUSERNAME[NASIUSERNAME_LENGTH + 1]; +typedef WCHAR NASIPASSWORD[NASIPASSWORD_LENGTH + 1]; +typedef WCHAR NASISESIONNAME[NASISESSIONNAME_LENGTH + 1]; +typedef WCHAR NASIFILESERVER[NASIFILESERVER_LENGTH + 1]; +typedef WCHAR WDNAME[WDNAME_LENGTH + 1]; +typedef WCHAR WDPREFIX[WDPREFIX_LENGTH + 1]; +typedef WCHAR CDNAME[CDNAME_LENGTH + 1]; +typedef WCHAR DLLNAME[DLLNAME_LENGTH + 1]; +typedef WCHAR PDNAME[PDNAME_LENGTH + 1]; + +typedef struct _NETWORKCONFIG +{ + LONG LanAdapter; + DEVICENAME NetworkName; + ULONG Flags; +} NETWORKCONFIG, *PNETWORKCONFIG; + +typedef enum _FLOWCONTROLCLASS +{ + FlowControl_None, + FlowControl_Hardware, + FlowControl_Software +} FLOWCONTROLCLASS; + +typedef enum _RECEIVEFLOWCONTROLCLASS +{ + ReceiveFlowControl_None, + ReceiveFlowControl_RTS, + ReceiveFlowControl_DTR, +} RECEIVEFLOWCONTROLCLASS; + +typedef enum _TRANSMITFLOWCONTROLCLASS +{ + TransmitFlowControl_None, + TransmitFlowControl_CTS, + TransmitFlowControl_DSR, +} TRANSMITFLOWCONTROLCLASS; + +typedef enum _ASYNCCONNECTCLASS +{ + Connect_CTS, + Connect_DSR, + Connect_RI, + Connect_DCD, + Connect_FirstChar, + Connect_Perm, +} ASYNCCONNECTCLASS; + +typedef struct _FLOWCONTROLCONFIG +{ + ULONG fEnableSoftwareTx : 1; + ULONG fEnableSoftwareRx : 1; + ULONG fEnableDTR : 1; + ULONG fEnableRTS : 1; + CHAR XonChar; + CHAR XoffChar; + FLOWCONTROLCLASS Type; + RECEIVEFLOWCONTROLCLASS HardwareReceive; + TRANSMITFLOWCONTROLCLASS HardwareTransmit; +} FLOWCONTROLCONFIG, *PFLOWCONTROLCONFIG; + +typedef struct _CONNECTCONFIG +{ + ASYNCCONNECTCLASS Type; + ULONG fEnableBreakDisconnect : 1; +} CONNECTCONFIG, *PCONNECTCONFIG; + +typedef struct _ASYNCCONFIG +{ + DEVICENAME DeviceName; + MODEMNAME ModemName; + ULONG BaudRate; + ULONG Parity; + ULONG StopBits; + ULONG ByteSize; + ULONG fEnableDsrSensitivity : 1; + ULONG fConnectionDriver : 1; + FLOWCONTROLCONFIG FlowControl; + CONNECTCONFIG Connect; +} ASYNCCONFIG, *PASYNCCONFIG; + +typedef struct _NASICONFIG +{ + NASISPECIFICNAME SpecificName; + NASIUSERNAME UserName; + NASIPASSWORD PassWord; + NASISESIONNAME SessionName; + NASIFILESERVER FileServer; + BOOLEAN GlobalSession; +} NASICONFIG, *PNASICONFIG; + +typedef struct _OEMTDCONFIG +{ + LONG Adapter; + DEVICENAME DeviceName; + ULONG Flags; +} OEMTDCONFIG, *POEMTDCONFIG; + +// Retrieves transport protocol driver parameters. +typedef struct _PDPARAMS +{ + SDCLASS SdClass; // Stack driver class. Indicates which one of the union's structures is valid. + union + { + NETWORKCONFIG Network; // Configuration of network drivers. Used if SdClass is SdNetwork. + ASYNCCONFIG Async; // Configuration of async (modem) driver. Used if SdClass is SdAsync. + NASICONFIG Nasi; // Reserved. + OEMTDCONFIG OemTd; // Configuration of OEM transport driver. Used if SdClass is SdOemTransport. + }; +} PDPARAMS, *PPDPARAMS; + +// The WinStation (session) driver configuration. +typedef struct _WDCONFIG +{ + WDNAME WdName; // The descriptive name of the WinStation driver. + DLLNAME WdDLL; // The driver's image name. + DLLNAME WsxDLL; // Used by the Terminal Services service to communicate with the WinStation driver. + ULONG WdFlag; // Driver flags. + ULONG WdInputBufferLength; // Length, in bytes, of the input buffer used by the driver. Defaults to 2048. + DLLNAME CfgDLL; // Configuration DLL used by Terminal Services administrative tools for configuring the driver. + WDPREFIX WdPrefix; // Used as the prefix of the WinStation name generated for the connected sessions with this WinStation driver. +} WDCONFIG, *PWDCONFIG; + +// The protocol driver's software configuration. +typedef struct _PDCONFIG2 +{ + PDNAME PdName; + SDCLASS SdClass; + DLLNAME PdDLL; + ULONG PdFlag; + ULONG OutBufLength; + ULONG OutBufCount; + ULONG OutBufDelay; + ULONG InteractiveDelay; + ULONG PortNumber; + ULONG KeepAliveTimeout; +} PDCONFIG2, *PPDCONFIG2; + // WinStationClient typedef struct _WINSTATIONCLIENT { @@ -275,7 +521,7 @@ typedef struct _PROTOCOLSTATUS ULONG AsyncSignalMask; } PROTOCOLSTATUS, *PPROTOCOLSTATUS; -// WinStationInformation +// Retrieves information on the session. typedef struct _WINSTATIONINFORMATION { WINSTATIONSTATECLASS ConnectState; @@ -291,7 +537,7 @@ typedef struct _WINSTATIONINFORMATION LARGE_INTEGER CurrentTime; } WINSTATIONINFORMATION, *PWINSTATIONINFORMATION; -// WinStationUserToken +// Retrieves the user's token in the session. Caller requires WINSTATION_ALL_ACCESS permission. typedef struct _WINSTATIONUSERTOKEN { HANDLE ProcessId; @@ -299,7 +545,7 @@ typedef struct _WINSTATIONUSERTOKEN HANDLE UserToken; } WINSTATIONUSERTOKEN, *PWINSTATIONUSERTOKEN; -// WinStationVideoData +// Retrieves resolution and color depth of the session. typedef struct _WINSTATIONVIDEODATA { USHORT HResolution; @@ -307,7 +553,73 @@ typedef struct _WINSTATIONVIDEODATA USHORT fColorDepth; } WINSTATIONVIDEODATA, *PWINSTATIONVIDEODATA; -// WinStationDigProductId +typedef enum _CDCLASS +{ + CdNone, // No connection driver. + CdModem, // Connection driver is a modem. + CdClass_Maximum, +} CDCLASS; + +// Connection driver configuration. It is used for connecting via modem to a server. +typedef struct _CDCONFIG +{ + CDCLASS CdClass; // Connection driver type. + CDNAME CdName; // Connection driver descriptive name. + DLLNAME CdDLL; // Connection driver image name. + ULONG CdFlag; // Connection driver flags. Connection driver specific. +} CDCONFIG, *PCDCONFIG; + +// The name has the following form: +// name syntax : xxxyyyy +typedef CHAR CLIENTDATANAME[CLIENTDATANAME_LENGTH + 1]; +typedef CHAR* PCLIENTDATANAME; + +typedef struct _WINSTATIONCLIENTDATA +{ + CLIENTDATANAME DataName; // Identifies the type of data sent in this WINSTATIONCLIENTDATA structure. The definition is dependent on the caller and on the client receiving it. This MUST be a data name following a format similar to that of the CLIENTDATANAME data type. + BOOLEAN fUnicodeData; // TRUE indicates data is in Unicode format; FALSE otherwise. +} WINSTATIONCLIENTDATA, *PWINSTATIONCLIENTDATA; + +typedef enum _LOADFACTORTYPE +{ + ErrorConstraint, // An error occurred while obtaining constraint data. + PagedPoolConstraint, // The amount of paged pool is the constraint. + NonPagedPoolConstraint, // The amount of non-paged pool is the constraint. + AvailablePagesConstraint, // The amount of available pages is the constraint. + SystemPtesConstraint, // The number of system page table entries (PTEs) is the constraint. + CPUConstraint // CPU usage is the constraint. +} LOADFACTORTYPE; + +// The WINSTATIONLOADINDICATORDATA structure defines data used for the load balancing of a server. +typedef struct _WINSTATIONLOADINDICATORDATA +{ + ULONG RemainingSessionCapacity; // The estimated number of additional sessions that can be supported given the CPU constraint. + LOADFACTORTYPE LoadFactor; // Indicates the most constrained current resource. + ULONG TotalSessions; // The total number of sessions. + ULONG DisconnectedSessions; // The number of disconnected sessions. + LARGE_INTEGER IdleCPU; // This is always set to 0. + LARGE_INTEGER TotalCPU; // This is always set to 0. + ULONG RawSessionCapacity; // The raw number of sessions capacity. + ULONG reserved[9]; // Reserved. +} WINSTATIONLOADINDICATORDATA, *PWINSTATIONLOADINDICATORDATA; + +typedef enum _SHADOWSTATECLASS +{ + State_NoShadow, // No shadow operations are currently being performed on this session. + State_Shadowing, // The session is shadowing a different session. The current session is referred to as a shadow client. + State_Shadowed // The session is being shadowed by a different session. The current session is referred to as a shadow target. +} SHADOWSTATECLASS; + +// Retrieves the current shadow state of a session. +typedef struct _WINSTATIONSHADOW +{ + SHADOWSTATECLASS ShadowState; // Specifies the current state of shadowing. + SHADOWCLASS ShadowClass; // Specifies the type of shadowing. + ULONG SessionId; // Specifies the session ID of the session. + ULONG ProtocolType; // Specifies the type of protocol on the session. Can be one of the following values. +} WINSTATIONSHADOW, *PWINSTATIONSHADOW; + +// Retrieves the client product ID and current product ID of the session. typedef struct _WINSTATIONPRODID { WCHAR DigProductId[CLIENT_PRODUCT_ID_LENGTH]; @@ -318,7 +630,7 @@ typedef struct _WINSTATIONPRODID ULONG OuterMostSessionId; } WINSTATIONPRODID, *PWINSTATIONPRODID; -// WinStationRemoteAddress +// Retrieves the remote IP address of the terminal server client in the session. typedef struct _WINSTATIONREMOTEADDRESS { USHORT sin_family; @@ -491,7 +803,7 @@ typedef struct _TS_COUNTER // current session ID. #define LOGONID_CURRENT (-1) -#define SERVERNAME_CURRENT (NULL) +#define SERVERNAME_CURRENT ((PWSTR)NULL) // rev BOOLEAN @@ -511,21 +823,21 @@ WinStationOpenServerW( BOOLEAN WINAPI WinStationCloseServer( - _In_ HANDLE hServer + _In_ HANDLE ServerHandle ); // rev BOOLEAN WINAPI WinStationServerPing( - _In_opt_ HANDLE hServer + _In_opt_ HANDLE ServerHandle ); // rev BOOLEAN WINAPI WinStationGetTermSrvCountersValue( - _In_opt_ HANDLE hServer, + _In_opt_ HANDLE ServerHandle, _In_ ULONG Count, _Inout_ PTS_COUNTER Counters // set counter IDs before calling ); @@ -533,7 +845,7 @@ WinStationGetTermSrvCountersValue( BOOLEAN WINAPI WinStationShutdownSystem( - _In_opt_ HANDLE hServer, + _In_opt_ HANDLE ServerHandle, _In_ ULONG ShutdownFlags // WSD_* ); @@ -541,7 +853,7 @@ WinStationShutdownSystem( BOOLEAN WINAPI WinStationWaitSystemEvent( - _In_opt_ HANDLE hServer, + _In_opt_ HANDLE ServerHandle, _In_ ULONG EventMask, // WEVENT_* _Out_ PULONG EventFlags ); @@ -550,7 +862,7 @@ WinStationWaitSystemEvent( BOOLEAN WINAPI WinStationRegisterConsoleNotification( - _In_opt_ HANDLE hServer, + _In_opt_ HANDLE ServerHandle, _In_ HWND WindowHandle, _In_ ULONG Flags ); @@ -559,7 +871,7 @@ WinStationRegisterConsoleNotification( BOOLEAN WINAPI WinStationUnRegisterConsoleNotification( - _In_opt_ HANDLE hServer, + _In_opt_ HANDLE ServerHandle, _In_ HWND WindowHandle ); @@ -569,7 +881,7 @@ WinStationUnRegisterConsoleNotification( BOOLEAN WINAPI WinStationEnumerateW( - _In_opt_ HANDLE hServer, + _In_opt_ HANDLE ServerHandle, _Out_ PSESSIONIDW *SessionIds, _Out_ PULONG Count ); @@ -577,7 +889,7 @@ WinStationEnumerateW( BOOLEAN WINAPI WinStationQueryInformationW( - _In_opt_ HANDLE hServer, + _In_opt_ HANDLE ServerHandle, _In_ ULONG SessionId, _In_ WINSTATIONINFOCLASS WinStationInformationClass, _Out_writes_bytes_(WinStationInformationLength) PVOID pWinStationInformation, @@ -589,7 +901,7 @@ WinStationQueryInformationW( BOOLEAN WINAPI WinStationSetInformationW( - _In_opt_ HANDLE hServer, + _In_opt_ HANDLE ServerHandle, _In_ ULONG SessionId, _In_ WINSTATIONINFOCLASS WinStationInformationClass, _In_reads_bytes_(WinStationInformationLength) PVOID pWinStationInformation, @@ -599,7 +911,7 @@ WinStationSetInformationW( BOOLEAN WINAPI WinStationNameFromLogonIdW( - _In_opt_ HANDLE hServer, + _In_opt_ HANDLE ServerHandle, _In_ ULONG SessionId, _Out_writes_(WINSTATIONNAME_LENGTH + 1) PWSTR pWinStationName ); @@ -608,7 +920,7 @@ WinStationNameFromLogonIdW( BOOLEAN WINAPI WinStationSendMessageW( - _In_opt_ HANDLE hServer, + _In_opt_ HANDLE ServerHandle, _In_ ULONG SessionId, _In_ PWSTR Title, _In_ ULONG TitleLength, @@ -623,7 +935,7 @@ WinStationSendMessageW( BOOLEAN WINAPI WinStationConnectW( - _In_opt_ HANDLE hServer, + _In_opt_ HANDLE ServerHandle, _In_ ULONG SessionId, _In_ ULONG TargetSessionId, _In_opt_ PWSTR pPassword, @@ -633,7 +945,7 @@ WinStationConnectW( BOOLEAN WINAPI WinStationDisconnect( - _In_opt_ HANDLE hServer, + _In_opt_ HANDLE ServerHandle, _In_ ULONG SessionId, _In_ BOOLEAN bWait ); @@ -642,7 +954,7 @@ WinStationDisconnect( BOOLEAN WINAPI WinStationReset( - _In_opt_ HANDLE hServer, + _In_opt_ HANDLE ServerHandle, _In_ ULONG SessionId, _In_ BOOLEAN bWait ); @@ -651,7 +963,7 @@ WinStationReset( BOOLEAN WINAPI WinStationShadow( - _In_opt_ HANDLE hServer, + _In_opt_ HANDLE ServerHandle, _In_ PWSTR TargetServerName, _In_ ULONG TargetSessionId, _In_ UCHAR HotKeyVk, @@ -662,7 +974,7 @@ WinStationShadow( BOOLEAN WINAPI WinStationShadowStop( - _In_opt_ HANDLE hServer, + _In_opt_ HANDLE ServerHandle, _In_ ULONG SessionId, _In_ BOOLEAN bWait // ignored ); @@ -673,7 +985,7 @@ WinStationShadowStop( BOOLEAN WINAPI WinStationEnumerateProcesses( - _In_opt_ HANDLE hServer, + _In_opt_ HANDLE ServerHandle, _Out_ PVOID *Processes ); @@ -681,7 +993,7 @@ WinStationEnumerateProcesses( BOOLEAN WINAPI WinStationGetAllProcesses( - _In_opt_ HANDLE hServer, + _In_opt_ HANDLE ServerHandle, _In_ ULONG Level, _Out_ PULONG NumberOfProcesses, _Out_ PTS_ALL_PROCESSES_INFO *Processes @@ -700,7 +1012,7 @@ WinStationFreeGAPMemory( BOOLEAN WINAPI WinStationTerminateProcess( - _In_opt_ HANDLE hServer, + _In_opt_ HANDLE ServerHandle, _In_ ULONG ProcessId, _In_ ULONG ExitCode ); @@ -708,7 +1020,7 @@ WinStationTerminateProcess( BOOLEAN WINAPI WinStationGetProcessSid( - _In_opt_ HANDLE hServer, + _In_opt_ HANDLE ServerHandle, _In_ ULONG ProcessId, _In_ FILETIME ProcessStartTime, _Out_ PVOID pProcessUserSid, @@ -743,6 +1055,4 @@ _WinStationWaitForConnect( VOID ); -// end_msdn - #endif From fa6db713986f324617df6f097921f0cb86230ead Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 18 Aug 2018 10:57:01 +1000 Subject: [PATCH 1302/2058] Remove unused code --- ProcessHacker/include/memsrch.h | 2 +- ProcessHacker/include/phsvc.h | 8 -------- ProcessHacker/include/procprp.h | 7 ------- ProcessHacker/include/procprv.h | 1 - ProcessHacker/phsvc/svcclient.c | 16 +++++++--------- ProcessHacker/phsvc/svcmain.c | 8 ++------ phlib/include/guisup.h | 18 ------------------ 7 files changed, 10 insertions(+), 50 deletions(-) diff --git a/ProcessHacker/include/memsrch.h b/ProcessHacker/include/memsrch.h index 74459788d870..5dc8cc52c9e2 100644 --- a/ProcessHacker/include/memsrch.h +++ b/ProcessHacker/include/memsrch.h @@ -37,7 +37,7 @@ typedef struct _PH_MEMORY_STRING_OPTIONS { BOOLEAN DetectUnicode : 1; BOOLEAN ExtendedUnicode : 1; - BOOLEAN Spare : 7; + BOOLEAN Spare : 6; }; }; } PH_MEMORY_STRING_OPTIONS, *PPH_MEMORY_STRING_OPTIONS; diff --git a/ProcessHacker/include/phsvc.h b/ProcessHacker/include/phsvc.h index 0912248784b5..57bb44b88870 100644 --- a/ProcessHacker/include/phsvc.h +++ b/ProcessHacker/include/phsvc.h @@ -36,10 +36,6 @@ typedef struct _PHSVC_CLIENT PVOID ClientViewLimit; } PHSVC_CLIENT, *PPHSVC_CLIENT; -NTSTATUS PhSvcClientInitialization( - VOID - ); - PPHSVC_CLIENT PhSvcCreateClient( _In_opt_ PCLIENT_ID ClientId ); @@ -82,10 +78,6 @@ VOID PhSvcHandleConnectionRequest( // svcapi -NTSTATUS PhSvcApiInitialization( - VOID - ); - typedef NTSTATUS (NTAPI *PPHSVC_API_PROCEDURE)( _In_ PPHSVC_CLIENT Client, _Inout_ PPHSVC_API_PAYLOAD Payload diff --git a/ProcessHacker/include/procprp.h b/ProcessHacker/include/procprp.h index a61d01e36604..15e498643fc6 100644 --- a/ProcessHacker/include/procprp.h +++ b/ProcessHacker/include/procprp.h @@ -94,13 +94,6 @@ PhPropPageDlgProcHeader( _Out_ PPH_PROCESS_ITEM *ProcessItem ); -PHAPPAPI -VOID -NTAPI -PhPropPageDlgProcDestroy( - _In_ HWND hwndDlg - ); - #define PH_PROP_PAGE_TAB_CONTROL_PARENT ((PPH_LAYOUT_ITEM)0x1) PHAPPAPI diff --git a/ProcessHacker/include/procprv.h b/ProcessHacker/include/procprv.h index 40b1de696bcb..522e05e9846e 100644 --- a/ProcessHacker/include/procprv.h +++ b/ProcessHacker/include/procprv.h @@ -162,7 +162,6 @@ typedef struct _PH_PROCESS_ITEM ULONG IsSecureProcess : 1; ULONG IsSubsystemProcess : 1; ULONG IsControlFlowGuardEnabled : 1; - ULONG Spare : 14; }; }; diff --git a/ProcessHacker/phsvc/svcclient.c b/ProcessHacker/phsvc/svcclient.c index 6c2c0021a542..7f351fa5e316 100644 --- a/ProcessHacker/phsvc/svcclient.c +++ b/ProcessHacker/phsvc/svcclient.c @@ -32,21 +32,19 @@ PPH_OBJECT_TYPE PhSvcClientType = NULL; LIST_ENTRY PhSvcClientListHead = { &PhSvcClientListHead, &PhSvcClientListHead }; PH_QUEUED_LOCK PhSvcClientListLock = PH_QUEUED_LOCK_INIT; -NTSTATUS PhSvcClientInitialization( - VOID - ) -{ - PhSvcClientType = PhCreateObjectType(L"Client", 0, PhSvcpClientDeleteProcedure); - - return STATUS_SUCCESS; -} - PPHSVC_CLIENT PhSvcCreateClient( _In_opt_ PCLIENT_ID ClientId ) { + static PH_INITONCE initOnce = PH_INITONCE_INIT; PPHSVC_CLIENT client; + if (PhBeginInitOnce(&initOnce)) + { + PhSvcClientType = PhCreateObjectType(L"Client", 0, PhSvcpClientDeleteProcedure); + PhEndInitOnce(&initOnce); + } + client = PhCreateObject(sizeof(PHSVC_CLIENT), PhSvcClientType); memset(client, 0, sizeof(PHSVC_CLIENT)); PhInitializeEvent(&client->ReadyEvent); diff --git a/ProcessHacker/phsvc/svcmain.c b/ProcessHacker/phsvc/svcmain.c index 206b96b48918..d02c423092a3 100644 --- a/ProcessHacker/phsvc/svcmain.c +++ b/ProcessHacker/phsvc/svcmain.c @@ -24,8 +24,8 @@ #include #include -HANDLE PhSvcTimeoutStandbyEventHandle; -HANDLE PhSvcTimeoutCancelEventHandle; +HANDLE PhSvcTimeoutStandbyEventHandle = NULL; +HANDLE PhSvcTimeoutCancelEventHandle = NULL; NTSTATUS PhSvcMain( _In_opt_ PPH_STRING PortName, @@ -48,10 +48,6 @@ NTSTATUS PhSvcMain( RtlInitUnicodeString(&portName, PHSVC_PORT_NAME); } - if (!NT_SUCCESS(status = PhSvcClientInitialization())) - return status; - if (!NT_SUCCESS(status = PhSvcApiInitialization())) - return status; if (!NT_SUCCESS(status = PhSvcApiPortInitialization(&portName))) return status; diff --git a/phlib/include/guisup.h b/phlib/include/guisup.h index ea8e1806972d..093fd7f0d073 100644 --- a/phlib/include/guisup.h +++ b/phlib/include/guisup.h @@ -149,24 +149,6 @@ FORCEINLINE LRESULT PhReflectMessage( return 0; } -#define PH_DEFINE_MAKE_ATOM(AtomName) \ -do { \ - static UNICODE_STRING atomName = RTL_CONSTANT_STRING(AtomName); \ - static PH_INITONCE initOnce = PH_INITONCE_INIT; \ - static RTL_ATOM atom = 0; \ -\ - if (PhBeginInitOnce(&initOnce)) \ - { \ - NtAddAtom(atomName.Buffer, atomName.Length, &atom); \ - PhEndInitOnce(&initOnce); \ - } \ -\ - if (atom) \ - return (PWSTR)(ULONG_PTR)atom; \ - else \ - return atomName.Buffer; \ -} while (0) - FORCEINLINE VOID PhSetListViewStyle( _In_ HWND Handle, _In_ BOOLEAN AllowDragDrop, From eacfaced9edaeb733fda37dd21125f46cfb05c6c Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 18 Aug 2018 10:57:53 +1000 Subject: [PATCH 1303/2058] Fix process token page regression --- ProcessHacker/prpgtok.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/ProcessHacker/prpgtok.c b/ProcessHacker/prpgtok.c index cd55d76acb96..1a94e21a1664 100644 --- a/ProcessHacker/prpgtok.c +++ b/ProcessHacker/prpgtok.c @@ -3,6 +3,7 @@ * Process properties: Token page * * Copyright (C) 2009-2016 wj32 + * Copyright (C) 2018 dmex * * This file is part of Process Hacker. * @@ -42,11 +43,19 @@ NTSTATUS NTAPI PhpOpenProcessTokenForPage( ))) return status; - status = PhOpenProcessToken( + if (!NT_SUCCESS(status = PhOpenProcessToken( processHandle, DesiredAccess | TOKEN_READ | TOKEN_ADJUST_DEFAULT | READ_CONTROL, // HACK: Add extra access_masks for querying default token. (dmex) Handle - ); + ))) + { + status = PhOpenProcessToken( + processHandle, + DesiredAccess, + Handle + ); + } + NtClose(processHandle); return status; From 6689d93bd8d7d0e1d5ca55b0b45e7855d2dd5010 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 18 Aug 2018 11:14:21 +1000 Subject: [PATCH 1304/2058] peview: Update sdk dependencies --- tools/peview/peview.vcxproj | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tools/peview/peview.vcxproj b/tools/peview/peview.vcxproj index ed172609dcf7..32f9c2deeec1 100644 --- a/tools/peview/peview.vcxproj +++ b/tools/peview/peview.vcxproj @@ -99,7 +99,7 @@ true - noarg.obj;noenv.obj;phlib.lib;ntdll.lib;uxtheme.lib;userenv.lib;windowscodecs.lib;%(AdditionalDependencies) + noarg.obj;noenv.obj;phlib.lib;ntdll.lib;uxtheme.lib;userenv.lib;windowscodecs.lib;winsta.lib;%(AdditionalDependencies) ..\..\phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) @@ -130,7 +130,7 @@ true - noarg.obj;noenv.obj;phlib.lib;ntdll.lib;uxtheme.lib;userenv.lib;windowscodecs.lib;%(AdditionalDependencies) + noarg.obj;noenv.obj;phlib.lib;ntdll.lib;uxtheme.lib;userenv.lib;windowscodecs.lib;winsta.lib;%(AdditionalDependencies) ..\..\phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) @@ -164,7 +164,7 @@ Guard - noarg.obj;noenv.obj;phlib.lib;ntdll.lib;uxtheme.lib;userenv.lib;windowscodecs.lib;%(AdditionalDependencies) + noarg.obj;noenv.obj;phlib.lib;ntdll.lib;uxtheme.lib;userenv.lib;windowscodecs.lib;winsta.lib;%(AdditionalDependencies) ..\..\phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) @@ -200,7 +200,7 @@ Guard - noarg.obj;noenv.obj;phlib.lib;ntdll.lib;uxtheme.lib;userenv.lib;windowscodecs.lib;%(AdditionalDependencies) + noarg.obj;noenv.obj;phlib.lib;ntdll.lib;uxtheme.lib;userenv.lib;windowscodecs.lib;winsta.lib;%(AdditionalDependencies) ..\..\phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) From 0e529711cd78e8fcba03bcd4254bbc03a121f5f1 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 18 Aug 2018 11:23:23 +1000 Subject: [PATCH 1305/2058] CustomSetupTool: Update sdk dependencies --- tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj b/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj index 7a5ea370b908..8e6ea14cbb99 100644 --- a/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj +++ b/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj @@ -65,7 +65,7 @@ true - comctl32.lib;uxtheme.lib;winhttp.lib;ntdll.lib;phlib.lib;shlwapi.lib;userenv.lib;windowscodecs.lib;%(AdditionalDependencies) + comctl32.lib;uxtheme.lib;winhttp.lib;ntdll.lib;phlib.lib;shlwapi.lib;userenv.lib;windowscodecs.lib;winsta.lib;%(AdditionalDependencies) $(SolutionDir)..\..\phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) Windows 6.01 @@ -97,7 +97,7 @@ true true true - comctl32.lib;uxtheme.lib;winhttp.lib;ntdll.lib;phlib.lib;shlwapi.lib;userenv.lib;windowscodecs.lib;%(AdditionalDependencies) + comctl32.lib;uxtheme.lib;winhttp.lib;ntdll.lib;phlib.lib;shlwapi.lib;userenv.lib;windowscodecs.lib;winsta.lib;%(AdditionalDependencies) $(SolutionDir)..\..\phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) Windows 6.01 From 1d318d4af702280c539f84eb8fbcb463877b5064 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 18 Aug 2018 13:34:18 +1000 Subject: [PATCH 1306/2058] Fix handle properties regression --- ProcessHacker/hndlprv.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/ProcessHacker/hndlprv.c b/ProcessHacker/hndlprv.c index f0a77ac6e664..7f5f40b00b5d 100644 --- a/ProcessHacker/hndlprv.c +++ b/ProcessHacker/hndlprv.c @@ -60,7 +60,6 @@ PPH_HANDLE_PROVIDER PhCreateHandleProvider( if (PhBeginInitOnce(&initOnce)) { PhHandleProviderType = PhCreateObjectType(L"HandleProvider", 0, PhpHandleProviderDeleteProcedure); - PhHandleItemType = PhCreateObjectType(L"HandleItem", 0, PhpHandleItemDeleteProcedure); PhEndInitOnce(&initOnce); } @@ -123,8 +122,15 @@ PPH_HANDLE_ITEM PhCreateHandleItem( _In_opt_ PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX Handle ) { + static PH_INITONCE initOnce = PH_INITONCE_INIT; PPH_HANDLE_ITEM handleItem; + if (PhBeginInitOnce(&initOnce)) + { + PhHandleItemType = PhCreateObjectType(L"HandleItem", 0, PhpHandleItemDeleteProcedure); + PhEndInitOnce(&initOnce); + } + handleItem = PhCreateObject( PhEmGetObjectSize(EmHandleItemType, sizeof(PH_HANDLE_ITEM)), PhHandleItemType From 7975ee2be5a825f35b4840d0361d68d53469ff8f Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 20 Aug 2018 15:00:40 +1000 Subject: [PATCH 1307/2058] Add initial locale support --- phlib/util.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 56 insertions(+), 3 deletions(-) diff --git a/phlib/util.c b/phlib/util.c index cbacb99dba9e..1bb13f059a9f 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -202,6 +202,59 @@ VOID PhDereferenceObjects( PhDereferenceObject(Objects[i]); } +// NLS support +// TODO: Move to seperate file. (dmex) + +LCID PhGetSystemDefaultLCID( + VOID + ) +{ + LCID localeId; + + if (NT_SUCCESS(NtQueryDefaultLocale(FALSE, &localeId))) + return localeId; + + return MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), SORT_DEFAULT); +} + +LCID PhGetUserDefaultLCID( + VOID + ) +{ + LCID localeId; + + if (NT_SUCCESS(NtQueryDefaultLocale(TRUE, &localeId))) + return localeId; + + return MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), SORT_DEFAULT); +} + +LANGID PhGetSystemDefaultLangID( + VOID + ) +{ + return LANGIDFROMLCID(PhGetSystemDefaultLCID()); +} + +LANGID PhGetUserDefaultLangID( + VOID + ) +{ + return LANGIDFROMLCID(PhGetUserDefaultLCID()); +} + +LANGID PhGetUserDefaultUILanguage( + VOID + ) +{ + LANGID languageId; + + if (NT_SUCCESS(NtQueryDefaultUILanguage(&languageId))) + return languageId; + + return MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT); +} + /** * Gets a string stored in a DLL's message table. * @@ -237,7 +290,7 @@ PPH_STRING PhGetMessage( status = RtlFindMessage( DllHandle, MessageTableId, - GetSystemDefaultLangID(), + PhGetSystemDefaultLangID(), MessageId, &messageEntry ); @@ -284,7 +337,7 @@ PPH_STRING PhGetNtMessage( PPH_STRING message; if (!NT_NTWIN32(Status)) - message = PhGetMessage(PhGetDllHandle(L"ntdll.dll"), 0xb, GetUserDefaultLangID(), (ULONG)Status); + message = PhGetMessage(PhGetDllHandle(L"ntdll.dll"), 0xb, PhGetUserDefaultLangID(), (ULONG)Status); else message = PhGetWin32Message(WIN32_FROM_NTSTATUS(Status)); @@ -326,7 +379,7 @@ PPH_STRING PhGetWin32Message( { PPH_STRING message; - message = PhGetMessage(PhGetDllHandle(L"kernel32.dll"), 0xb, GetUserDefaultLangID(), Result); + message = PhGetMessage(PhGetDllHandle(L"kernel32.dll"), 0xb, PhGetUserDefaultLangID(), Result); if (message) PhTrimToNullTerminatorString(message); From 6fbad6f06dcc3564f96b3c9db08b25cad843e06e Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 20 Aug 2018 18:57:29 +1000 Subject: [PATCH 1308/2058] Fix process job tab default window focus --- ProcessHacker/jobprp.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/ProcessHacker/jobprp.c b/ProcessHacker/jobprp.c index a754b28f59da..1feeccc90ef3 100644 --- a/ProcessHacker/jobprp.c +++ b/ProcessHacker/jobprp.c @@ -226,9 +226,10 @@ INT_PTR CALLBACK PhpJobPageProc( PhSetListViewStyle(limitsLv, FALSE, TRUE); PhSetControlTheme(processesLv, L"explorer"); PhSetControlTheme(limitsLv, L"explorer"); + PhSetExtendedListView(processesLv); + PhSetExtendedListView(limitsLv); PhAddListViewColumn(processesLv, 0, 0, 0, LVCFMT_LEFT, 240, L"Name"); - PhAddListViewColumn(limitsLv, 0, 0, 0, LVCFMT_LEFT, 120, L"Name"); PhAddListViewColumn(limitsLv, 1, 1, 1, LVCFMT_LEFT, 160, L"Value"); PhLoadListViewColumnsFromSetting(L"JobListViewColumns", limitsLv); @@ -250,7 +251,7 @@ INT_PTR CALLBACK PhpJobPageProc( PhGetHandleInformation( NtCurrentProcess(), jobHandle, - -1, + ULONG_MAX, NULL, NULL, NULL, @@ -390,6 +391,11 @@ INT_PTR CALLBACK PhpJobPageProc( case WM_DESTROY: PhSaveListViewColumnsToSetting(L"JobListViewColumns", GetDlgItem(hwndDlg, IDC_LIMITS)); break; + case WM_SHOWWINDOW: + { + ExtendedListView_SetColumnWidth(GetDlgItem(hwndDlg, IDC_PROCESSES), 0, ELVSCW_AUTOSIZE_REMAININGSPACE); + } + break; case WM_COMMAND: { switch (GET_WM_COMMAND_ID(wParam, lParam)) @@ -478,10 +484,24 @@ INT_PTR CALLBACK PhpJobPageProc( break; case WM_NOTIFY: { + LPNMHDR header = (LPNMHDR)lParam; + + switch (header->code) + { + case PSN_QUERYINITIALFOCUS: + SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, (LPARAM)GetDlgItem(hwndDlg, IDC_PROCESSES)); + return TRUE; + } + PhHandleListViewNotifyBehaviors(lParam, GetDlgItem(hwndDlg, IDC_PROCESSES), PH_LIST_VIEW_DEFAULT_1_BEHAVIORS); PhHandleListViewNotifyBehaviors(lParam, GetDlgItem(hwndDlg, IDC_LIMITS), PH_LIST_VIEW_DEFAULT_1_BEHAVIORS); } break; + case WM_SIZE: + { + ExtendedListView_SetColumnWidth(GetDlgItem(hwndDlg, IDC_PROCESSES), 0, ELVSCW_AUTOSIZE_REMAININGSPACE); + } + break; } return FALSE; From 0a8993be9b5bde8a24918ec18a52ab64cd69d59d Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 20 Aug 2018 19:10:26 +1000 Subject: [PATCH 1309/2058] Disable PE-style job object names --- phlib/hndlinfo.c | 118 ++++++++++++++++++++++++----------------------- 1 file changed, 60 insertions(+), 58 deletions(-) diff --git a/phlib/hndlinfo.c b/phlib/hndlinfo.c index dca956ea18e4..f33ec0c1d667 100644 --- a/phlib/hndlinfo.c +++ b/phlib/hndlinfo.c @@ -712,64 +712,66 @@ NTSTATUS PhpGetBestObjectName( } } } - else if (PhEqualString2(TypeName, L"Job", TRUE)) - { - HANDLE dupHandle; - PJOBOBJECT_BASIC_PROCESS_ID_LIST processIdList; - - // dmex: Don't do anything when we already have a valid job object name. - if (!PhIsNullOrEmptyString(ObjectName)) - goto CleanupExit; - - status = NtDuplicateObject( - ProcessHandle, - Handle, - NtCurrentProcess(), - &dupHandle, - JOB_OBJECT_QUERY, - 0, - 0 - ); - - if (!NT_SUCCESS(status)) - goto CleanupExit; - - if (handleGetClientIdName && NT_SUCCESS(PhGetJobProcessIdList(dupHandle, &processIdList))) - { - PH_STRING_BUILDER sb; - ULONG i; - CLIENT_ID clientId; - PPH_STRING name; - - PhInitializeStringBuilder(&sb, 40); - clientId.UniqueThread = NULL; - - for (i = 0; i < processIdList->NumberOfProcessIdsInList; i++) - { - clientId.UniqueProcess = (HANDLE)processIdList->ProcessIdList[i]; - name = handleGetClientIdName(&clientId); - - if (name) - { - PhAppendStringBuilder(&sb, &name->sr); - PhAppendStringBuilder2(&sb, L"; "); - PhDereferenceObject(name); - } - } - - PhFree(processIdList); - - if (sb.String->Length != 0) - PhRemoveEndStringBuilder(&sb, 2); - - if (sb.String->Length == 0) - PhAppendStringBuilder2(&sb, L"(No processes)"); - - bestObjectName = PhFinalStringBuilderString(&sb); - } - - NtClose(dupHandle); - } + // Note: Uncomment below code if we want to return job names identical to Process Explorer. + // Todo: Should we remove since it's not the actual job name? -dmex + //else if (PhEqualString2(TypeName, L"Job", TRUE)) + //{ + // HANDLE dupHandle; + // PJOBOBJECT_BASIC_PROCESS_ID_LIST processIdList; + // + // // dmex: Don't do anything when we already have a valid job object name. + // if (!PhIsNullOrEmptyString(ObjectName)) + // goto CleanupExit; + // + // status = NtDuplicateObject( + // ProcessHandle, + // Handle, + // NtCurrentProcess(), + // &dupHandle, + // JOB_OBJECT_QUERY, + // 0, + // 0 + // ); + // + // if (!NT_SUCCESS(status)) + // goto CleanupExit; + // + // if (handleGetClientIdName && NT_SUCCESS(PhGetJobProcessIdList(dupHandle, &processIdList))) + // { + // PH_STRING_BUILDER sb; + // ULONG i; + // CLIENT_ID clientId; + // PPH_STRING name; + // + // PhInitializeStringBuilder(&sb, 40); + // clientId.UniqueThread = NULL; + // + // for (i = 0; i < processIdList->NumberOfProcessIdsInList; i++) + // { + // clientId.UniqueProcess = (HANDLE)processIdList->ProcessIdList[i]; + // name = handleGetClientIdName(&clientId); + // + // if (name) + // { + // PhAppendStringBuilder(&sb, &name->sr); + // PhAppendStringBuilder2(&sb, L"; "); + // PhDereferenceObject(name); + // } + // } + // + // PhFree(processIdList); + // + // if (sb.String->Length != 0) + // PhRemoveEndStringBuilder(&sb, 2); + // + // if (sb.String->Length == 0) + // PhAppendStringBuilder2(&sb, L"(No processes)"); + // + // bestObjectName = PhFinalStringBuilderString(&sb); + // } + // + // NtClose(dupHandle); + //} else if (PhEqualString2(TypeName, L"Key", TRUE)) { bestObjectName = PhFormatNativeKeyName(ObjectName); From 83a15bd5220a86c3a813dd7520dd49079a2dff7d Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 20 Aug 2018 19:12:36 +1000 Subject: [PATCH 1310/2058] DotNetTools: Update .NET assembly tab (Add options, refresh and search support), Update .NET performance tab layout --- plugins/DotNetTools/DotNetTools.rc | 20 +- plugins/DotNetTools/asmpage.c | 614 +++++++++++---- plugins/DotNetTools/clrsup.c | 12 +- plugins/DotNetTools/counters.c | 66 +- plugins/DotNetTools/dn.h | 5 + plugins/DotNetTools/main.c | 31 +- plugins/DotNetTools/perfpage.c | 1160 +++++++++++++++------------- plugins/DotNetTools/resource.h | 5 +- 8 files changed, 1181 insertions(+), 732 deletions(-) diff --git a/plugins/DotNetTools/DotNetTools.rc b/plugins/DotNetTools/DotNetTools.rc index b119d818c7a3..e382546b5469 100644 --- a/plugins/DotNetTools/DotNetTools.rc +++ b/plugins/DotNetTools/DotNetTools.rc @@ -92,11 +92,8 @@ STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSM CAPTION ".NET performance" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN - CONTROL "",IDC_APPDOMAINS,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_SORTASCENDING | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,7,246,59 - LTEXT "Categories:",IDC_STATIC,7,72,38,8 - COMBOBOX IDC_CATEGORIES,49,70,204,30,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP - CONTROL "",IDC_COUNTERS,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,88,246,154 - CONTROL "Show sizes in bytes",IDC_DOTNET_PERF_SHOWBYTES,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,244,78,10 + CONTROL "",IDC_APPDOMAINS,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_SORTASCENDING | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,2,3,256,67 + CONTROL "",IDC_COUNTERS,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,2,73,256,185 END IDD_PROCDOTNETASM DIALOGEX 0, 0, 260, 260 @@ -104,7 +101,10 @@ STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSM CAPTION ".NET assemblies" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN - CONTROL ".NET assemblies",IDC_LIST,"PhTreeNew",WS_CLIPSIBLINGS | WS_CLIPCHILDREN | 0x1a,2,3,256,255,WS_EX_CLIENTEDGE + CONTROL ".NET assemblies",IDC_LIST,"PhTreeNew",WS_CLIPSIBLINGS | WS_CLIPCHILDREN | 0x1a,2,19,256,239,WS_EX_CLIENTEDGE + PUSHBUTTON "Options",IDC_OPTIONS,2,2,50,14 + EDITTEXT IDC_SEARCHEDIT,114,3,143,14,ES_AUTOHSCROLL + PUSHBUTTON "Refresh",IDC_REFRESH,53,2,50,14 END @@ -118,10 +118,10 @@ GUIDELINES DESIGNINFO BEGIN IDD_PROCDOTNETPERF, DIALOG BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 253 - TOPMARGIN, 7 - BOTTOMMARGIN, 253 + LEFTMARGIN, 2 + RIGHTMARGIN, 258 + TOPMARGIN, 3 + BOTTOMMARGIN, 258 END IDD_PROCDOTNETASM, DIALOG diff --git a/plugins/DotNetTools/asmpage.c b/plugins/DotNetTools/asmpage.c index 2b6af0ec28f9..dd22db3f7dae 100644 --- a/plugins/DotNetTools/asmpage.c +++ b/plugins/DotNetTools/asmpage.c @@ -36,7 +36,7 @@ #define DNA_TYPE_APPDOMAIN 2 #define DNA_TYPE_ASSEMBLY 3 -#define UPDATE_MSG (WM_APP + 1) +#define DN_ASM_UPDATE_MSG (WM_APP + 1) typedef struct _DNA_NODE { @@ -55,16 +55,19 @@ typedef struct _DNA_NODE struct { USHORT ClrInstanceID; + ULONG StartupFlags; PPH_STRING DisplayName; } Clr; struct { ULONG64 AppDomainID; + ULONG AppDomainFlags; PPH_STRING DisplayName; } AppDomain; struct { ULONG64 AssemblyID; + ULONG AssemblyFlags; PPH_STRING FullyQualifiedAssemblyName; } Assembly; } u; @@ -79,14 +82,31 @@ typedef struct _DNA_NODE typedef struct _ASMPAGE_CONTEXT { HWND WindowHandle; - PPH_PROCESS_ITEM ProcessItem; - ULONG ClrVersions; + HWND SearchBoxHandle; + HWND TreeNewHandle; + + PPH_STRING SearchBoxText; + PPH_STRING TreeErrorMessage; + + PPH_PROCESS_ITEM ProcessItem; PDNA_NODE ClrV2Node; - HWND TnHandle; - PPH_STRING TnErrorMessage; + union + { + ULONG Flags; + struct + { + ULONG EnableStateHighlighting : 1; + ULONG HideDynamicModules : 1; + ULONG HighlightDynamicModules : 1; + ULONG Spare : 29; + }; + }; + PPH_LIST NodeList; PPH_LIST NodeRootList; + PPH_TN_FILTER_ENTRY TreeFilterEntry; + PH_TN_FILTER_SUPPORT TreeFilterSupport; } ASMPAGE_CONTEXT, *PASMPAGE_CONTEXT; typedef struct _ASMPAGE_QUERY_CONTEXT @@ -221,7 +241,6 @@ PDNA_NODE AddNode( PDNA_NODE node; node = PhAllocateZero(sizeof(DNA_NODE)); - PhInitializeTreeNewNode(&node->Node); memset(node->TextCache, 0, sizeof(PH_STRINGREF) * DNATNC_MAXIMUM); @@ -235,11 +254,11 @@ PDNA_NODE AddNode( return node; } -VOID DestroyNode( +VOID DotNetAsmDestroyNode( _In_ PDNA_NODE Node ) { - PhDereferenceObject(Node->Children); + if (Node->Children) PhDereferenceObject(Node->Children); if (Node->Type == DNA_TYPE_CLR) { @@ -286,9 +305,7 @@ PDNA_NODE FindClrNode( _In_ USHORT ClrInstanceID ) { - ULONG i; - - for (i = 0; i < Context->NodeRootList->Count; i++) + for (ULONG i = 0; i < Context->NodeRootList->Count; i++) { PDNA_NODE node = Context->NodeRootList->Items[i]; @@ -304,9 +321,7 @@ PDNA_NODE FindAppDomainNode( _In_ ULONG64 AppDomainID ) { - ULONG i; - - for (i = 0; i < ClrNode->Children->Count; i++) + for (ULONG i = 0; i < ClrNode->Children->Count; i++) { PDNA_NODE node = ClrNode->Children->Items[i]; @@ -322,9 +337,7 @@ PDNA_NODE FindAssemblyNode( _In_ ULONG64 AssemblyID ) { - ULONG i; - - for (i = 0; i < AppDomainNode->Children->Count; i++) + for (ULONG i = 0; i < AppDomainNode->Children->Count; i++) { PDNA_NODE node = AppDomainNode->Children->Items[i]; @@ -340,14 +353,11 @@ PDNA_NODE FindAssemblyNode2( _In_ ULONG64 AssemblyID ) { - ULONG i; - ULONG j; - - for (i = 0; i < ClrNode->Children->Count; i++) + for (ULONG i = 0; i < ClrNode->Children->Count; i++) { PDNA_NODE appDomainNode = ClrNode->Children->Items[i]; - for (j = 0; j < appDomainNode->Children->Count; j++) + for (ULONG j = 0; j < appDomainNode->Children->Count; j++) { PDNA_NODE assemblyNode = appDomainNode->Children->Items[j]; @@ -369,8 +379,66 @@ static int __cdecl AssemblyNodeNameCompareFunction( return PhCompareStringRef(&node1->StructureText, &node2->StructureText, TRUE); } +VOID DotNetAsmExpandAllTreeNodes( + _In_ PASMPAGE_CONTEXT Context, + _In_ BOOLEAN Expand + ) +{ + ULONG i; + BOOLEAN needsRestructure = FALSE; + + for (i = 0; i < Context->NodeList->Count; i++) + { + PPH_MODULE_NODE node = Context->NodeList->Items[i]; + + if (node->Node.Expanded != Expand) + { + node->Node.Expanded = Expand; + needsRestructure = TRUE; + } + } + + if (needsRestructure) + TreeNew_NodesStructured(Context->TreeNewHandle); +} -PDNA_NODE DotNetAsmGetSelectedEntry( +VOID DotNetAsmDestroyTreeNodes( + _In_ PASMPAGE_CONTEXT Context + ) +{ + if (Context->NodeList) + { + for (ULONG i = 0; i < Context->NodeList->Count; i++) + DotNetAsmDestroyNode(Context->NodeList->Items[i]); + + PhDereferenceObject(Context->NodeList); + } + + if (Context->NodeRootList) + PhDereferenceObject(Context->NodeRootList); +} + +VOID DotNetAsmClearTreeNodes( + _In_ PASMPAGE_CONTEXT Context + ) +{ + if (Context->NodeList) + { + for (ULONG i = 0; i < Context->NodeList->Count; i++) + DotNetAsmDestroyNode(Context->NodeList->Items[i]); + + PhClearList(Context->NodeList); + } + + if (Context->NodeRootList) + { + PhClearList(Context->NodeRootList); + } + + TreeNew_NodesStructured(Context->TreeNewHandle); +} + +PDNA_NODE DotNetAsmGetSelectedTreeNode( _In_ PASMPAGE_CONTEXT Context ) { @@ -399,7 +467,7 @@ VOID DotNetAsmShowContextMenu( PPH_EMENU menu; PPH_EMENU_ITEM selectedItem; - if (!(node = DotNetAsmGetSelectedEntry(Context))) + if (!(node = DotNetAsmGetSelectedTreeNode(Context))) return; menu = PhCreateEMenu(); @@ -408,7 +476,7 @@ VOID DotNetAsmShowContextMenu( PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_CLR_OPENFILELOCATION, L"Open &file location", NULL, NULL), ULONG_MAX); PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX); PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_CLR_COPY, L"&Copy", NULL, NULL), ULONG_MAX); - PhInsertCopyCellEMenuItem(menu, ID_CLR_COPY, Context->TnHandle, ContextMenuEvent->Column); + PhInsertCopyCellEMenuItem(menu, ID_CLR_COPY, Context->TreeNewHandle, ContextMenuEvent->Column); if (PhIsNullOrEmptyString(node->PathText) || !RtlDoesFileExists_U(node->PathText->Buffer)) { @@ -461,8 +529,8 @@ VOID DotNetAsmShowContextMenu( { PPH_STRING text; - text = PhGetTreeNewText(Context->TnHandle, 0); - PhSetClipboardString(Context->TnHandle, &text->sr); + text = PhGetTreeNewText(Context->TreeNewHandle, 0); + PhSetClipboardString(Context->TreeNewHandle, &text->sr); PhDereferenceObject(text); } break; @@ -481,18 +549,14 @@ BOOLEAN NTAPI DotNetAsmTreeNewCallback( _In_opt_ PVOID Context ) { - PASMPAGE_CONTEXT context; - PDNA_NODE node; - - context = Context; + PASMPAGE_CONTEXT context = Context; switch (Message) { case TreeNewGetChildren: { PPH_TREENEW_GET_CHILDREN getChildren = Parameter1; - - node = (PDNA_NODE)getChildren->Node; + PDNA_NODE node = (PDNA_NODE)getChildren->Node; if (!node) { @@ -515,8 +579,7 @@ BOOLEAN NTAPI DotNetAsmTreeNewCallback( case TreeNewIsLeaf: { PPH_TREENEW_IS_LEAF isLeaf = Parameter1; - - node = (PDNA_NODE)isLeaf->Node; + PDNA_NODE node = (PDNA_NODE)isLeaf->Node; isLeaf->IsLeaf = node->Children->Count == 0; } @@ -524,8 +587,7 @@ BOOLEAN NTAPI DotNetAsmTreeNewCallback( case TreeNewGetCellText: { PPH_TREENEW_GET_CELL_TEXT getCellText = Parameter1; - - node = (PDNA_NODE)getCellText->Node; + PDNA_NODE node = (PDNA_NODE)getCellText->Node; switch (getCellText->Id) { @@ -551,11 +613,36 @@ BOOLEAN NTAPI DotNetAsmTreeNewCallback( getCellText->Flags = TN_CACHE; } return TRUE; + case TreeNewGetNodeColor: + { + PPH_TREENEW_GET_NODE_COLOR getNodeColor = Parameter1; + PDNA_NODE node = (PDNA_NODE)getNodeColor->Node; + + switch (node->Type) + { + case DNA_TYPE_CLR: + case DNA_TYPE_APPDOMAIN: + //getNodeColor->BackColor = PhGetIntegerSetting(L"ColorDotNet"); + break; + case DNA_TYPE_ASSEMBLY: + { + //getNodeColor->BackColor = PhGetIntegerSetting(L"ColorDotNet"); + + if (context->HighlightDynamicModules && node->u.Assembly.AssemblyFlags == 2) + { + getNodeColor->BackColor = PhGetIntegerSetting(L"ColorPacked"); + } + } + break; + } + + getNodeColor->Flags = TN_AUTO_FORECOLOR; + } + return TRUE; case TreeNewGetCellTooltip: { PPH_TREENEW_GET_CELL_TOOLTIP getCellTooltip = Parameter1; - - node = (PDNA_NODE)getCellTooltip->Node; + PDNA_NODE node = (PDNA_NODE)getCellTooltip->Node; if (getCellTooltip->Column->Id != 0 || node->Type != DNA_TYPE_ASSEMBLY) return FALSE; @@ -612,7 +699,63 @@ BOOLEAN NTAPI DotNetAsmTreeNewCallback( return FALSE; } -ULONG StartDotNetTrace( +VOID DotNetAsmLoadSettingsTreeList( + _Inout_ PASMPAGE_CONTEXT Context + ) +{ + ULONG flags; + PPH_STRING settings; + //PH_INTEGER_PAIR sortSettings; + + flags = PhGetIntegerSetting(SETTING_NAME_ASM_TREE_LIST_FLAGS); + settings = PhGetStringSetting(SETTING_NAME_ASM_TREE_LIST_COLUMNS); + //sortSettings = PhGetIntegerPairSetting(SETTING_NAME_ASM_TREE_LIST_SORT); + + Context->Flags = flags; + PhCmLoadSettings(Context->TreeNewHandle, &settings->sr); + //TreeNew_SetSort(Context->TreeNewHandle, (ULONG)sortSettings.X, (PH_SORT_ORDER)sortSettings.Y); + + PhDereferenceObject(settings); +} + +VOID DotNetAsmSaveSettingsTreeList( + _Inout_ PASMPAGE_CONTEXT Context + ) +{ + PPH_STRING settings; + //PH_INTEGER_PAIR sortSettings; + //ULONG sortColumn; + //PH_SORT_ORDER sortOrder; + + settings = PhCmSaveSettings(Context->TreeNewHandle); + //TreeNew_GetSort(Context->TreeNewHandle, &sortColumn, &sortOrder); + //sortSettings.X = sortColumn; + //sortSettings.Y = sortOrder; + + PhSetIntegerSetting(SETTING_NAME_ASM_TREE_LIST_FLAGS, Context->Flags); + PhSetStringSetting2(SETTING_NAME_ASM_TREE_LIST_COLUMNS, &settings->sr); + //PhSetIntegerPairSetting(SETTING_NAME_ASM_TREE_LIST_SORT, sortSettings); + + PhDereferenceObject(settings); +} + +VOID DotNetAsmSetOptionsTreeList( + _Inout_ PASMPAGE_CONTEXT Context, + _In_ ULONG Options + ) +{ + switch (Options) + { + case DN_ASM_MENU_HIDE_DYNAMIC_OPTION: + Context->HideDynamicModules = !Context->HideDynamicModules; + break; + case DN_ASM_MENU_HIGHLIGHT_DYNAMIC_OPTION: + Context->HighlightDynamicModules = !Context->HighlightDynamicModules; + break; + } +} + +static ULONG StartDotNetTrace( _Out_ PTRACEHANDLE SessionHandle, _Out_ PEVENT_TRACE_PROPERTIES *Properties ) @@ -666,14 +809,14 @@ ULONG StartDotNetTrace( } } -ULONG NTAPI DotNetBufferCallback( +static ULONG NTAPI DotNetBufferCallback( _In_ PEVENT_TRACE_LOGFILE Buffer ) { return TRUE; } -VOID NTAPI DotNetEventCallback( +static VOID NTAPI DotNetEventCallback( _In_ PEVENT_RECORD EventRecord ) { @@ -701,6 +844,7 @@ VOID NTAPI DotNetEventCallback( node = AddNode(context); node->Type = DNA_TYPE_CLR; node->u.Clr.ClrInstanceID = data->ClrInstanceID; + node->u.Clr.StartupFlags = data->StartupFlags; node->u.Clr.DisplayName = PhFormatString(L"CLR v%u.%u.%u.%u", data->VMMajorVersion, data->VMMinorVersion, data->VMBuildNumber, data->VMQfeNumber); node->StructureText = node->u.Clr.DisplayName->sr; node->IdText = PhFormatUInt64(data->ClrInstanceID, FALSE); @@ -754,6 +898,7 @@ VOID NTAPI DotNetEventCallback( node = AddNode(context); node->Type = DNA_TYPE_APPDOMAIN; node->u.AppDomain.AppDomainID = data->AppDomainID; + node->u.AppDomain.AppDomainFlags = data->AppDomainFlags; node->u.AppDomain.DisplayName = PhConcatStrings2(L"AppDomain: ", data->AppDomainName); node->StructureText = node->u.AppDomain.DisplayName->sr; node->IdText = PhFormatUInt64(data->AppDomainID, FALSE); @@ -791,6 +936,7 @@ VOID NTAPI DotNetEventCallback( node = AddNode(context); node->Type = DNA_TYPE_ASSEMBLY; node->u.Assembly.AssemblyID = data->AssemblyID; + node->u.Assembly.AssemblyFlags = data->AssemblyFlags; node->u.Assembly.FullyQualifiedAssemblyName = PhCreateStringEx(data->FullyQualifiedAssemblyName, fullyQualifiedAssemblyNameLength); // Display only the assembly name, not the whole fully qualified name. @@ -919,7 +1065,7 @@ VOID NTAPI DotNetEventCallback( } } -ULONG ProcessDotNetTrace( +static ULONG ProcessDotNetTrace( _In_ PASMPAGE_QUERY_CONTEXT Context ) { @@ -965,10 +1111,10 @@ NTSTATUS UpdateDotNetTraceInfoThreadStart( if (context->TraceResult != 0) return context->TraceResult; - if (!context->TraceClrV2) - guidToEnable = &ClrRundownProviderGuid; - else + if (context->TraceClrV2) guidToEnable = &ClrRuntimeProviderGuid; + else + guidToEnable = &ClrRundownProviderGuid; EnableTraceEx( guidToEnable, @@ -1054,7 +1200,7 @@ NTSTATUS DotNetTraceQueryThreadStart( AddFakeClrNode(context, L"CLR v1.1.4322"); } - timeout.QuadPart = -10 * PH_TIMEOUT_SEC; + timeout.QuadPart = -(LONGLONG)UInt32x32To64(10, PH_TIMEOUT_SEC); if (context->ClrVersions & PH_CLR_VERSION_2_0) { @@ -1096,42 +1242,36 @@ NTSTATUS DotNetTraceQueryThreadStart( result = ERROR_TIMEOUT; } - // If the process properties window has been closed, bail and cleanup. - // IsWindow should be safe from being called on this thread: - // https://blogs.msdn.microsoft.com/oldnewthing/20070717-00/?p=25983 if (IsWindow(context->WindowHandle)) - { - PostMessage(context->WindowHandle, UPDATE_MSG, result, (LPARAM)context); - } + PostMessage(context->WindowHandle, DN_ASM_UPDATE_MSG, result, (LPARAM)context); else - { DestroyDotNetTraceQuery(context); - } return STATUS_SUCCESS; } VOID CreateDotNetTraceQueryThread( - _In_ HWND WindowHandle, - _In_ ULONG ClrVersions, + _In_ PASMPAGE_CONTEXT Context, _In_ HANDLE ProcessId ) { - HANDLE threadHandle; PASMPAGE_QUERY_CONTEXT context; context = PhAllocateZero(sizeof(ASMPAGE_QUERY_CONTEXT)); - context->WindowHandle = WindowHandle; - context->ClrVersions = ClrVersions; + context->WindowHandle = Context->WindowHandle; context->ProcessId = ProcessId; context->NodeList = PhCreateList(64); context->NodeRootList = PhCreateList(2); - if (threadHandle = PhCreateThread(0, DotNetTraceQueryThreadStart, context)) - { - NtClose(threadHandle); - } - else + PhGetProcessIsDotNetEx( + ProcessId, + NULL, + 0, + NULL, + &context->ClrVersions + ); + + if (!NT_SUCCESS(PhCreateThread2(DotNetTraceQueryThreadStart, context))) { DestroyDotNetTraceQuery(context); } @@ -1141,14 +1281,16 @@ VOID DestroyDotNetTraceQuery( _In_ PASMPAGE_QUERY_CONTEXT Context ) { - if (Context->NodeList) + if (Context->NodeRootList) { - PhClearReference(&Context->NodeList); + PhClearList(Context->NodeRootList); + PhDereferenceObject(Context->NodeRootList); } - if (Context->NodeRootList) + if (Context->NodeList) { - PhClearReference(&Context->NodeRootList); + PhClearList(Context->NodeList); + PhDereferenceObject(Context->NodeList); } PhFree(Context); @@ -1172,6 +1314,110 @@ BOOLEAN IsProcessSuspended( return FALSE; } +VOID DotNetAsmRefreshTraceQuery( + _In_ PASMPAGE_CONTEXT Context + ) +{ + PhMoveReference(&Context->TreeErrorMessage, PhCreateString(L"Loading .NET assemblies...")); + TreeNew_SetEmptyText(Context->TreeNewHandle, &Context->TreeErrorMessage->sr, 0); + TreeNew_NodesStructured(Context->TreeNewHandle); + + if (!IsProcessSuspended(Context->ProcessItem->ProcessId) || PhShowMessage( + Context->WindowHandle, + MB_ICONWARNING | MB_YESNO, + L".NET assembly enumeration may not work properly because the process is currently suspended. Do you want to continue?" + ) == IDYES) + { + CreateDotNetTraceQueryThread(Context, Context->ProcessItem->ProcessId); + } + else + { + PhMoveReference( + &Context->TreeErrorMessage, + PhCreateString(L"Unable to start the event tracing session because the process is suspended.") + ); + TreeNew_SetEmptyText(Context->TreeNewHandle, &Context->TreeErrorMessage->sr, 0); + TreeNew_NodesStructured(Context->TreeNewHandle); + } +} + +BOOLEAN WordMatchStringRef( + _Inout_ PASMPAGE_CONTEXT Context, + _In_ PPH_STRINGREF Text + ) +{ + PH_STRINGREF part; + PH_STRINGREF remainingPart; + + remainingPart = PhGetStringRef(Context->SearchBoxText); + + while (remainingPart.Length != 0) + { + PhSplitStringRefAtChar(&remainingPart, '|', &part, &remainingPart); + + if (part.Length != 0) + { + if (PhFindStringInStringRef(Text, &part, TRUE) != -1) + return TRUE; + } + } + + return FALSE; +} + +BOOLEAN WordMatchStringZ( + _Inout_ PASMPAGE_CONTEXT Context, + _In_ PWSTR Text + ) +{ + PH_STRINGREF text; + + PhInitializeStringRef(&text, Text); + + return WordMatchStringRef(Context, &text); +} + +BOOLEAN DotNetAsmTreeFilterCallback( + _In_ PPH_TREENEW_NODE Node, + _In_opt_ PVOID Context + ) +{ + PASMPAGE_CONTEXT context = Context; + PDNA_NODE node = (PDNA_NODE)Node; + + if (context->HideDynamicModules && node->Type == DNA_TYPE_ASSEMBLY && node->u.Assembly.AssemblyFlags == 2) + return FALSE; + + if (PhIsNullOrEmptyString(context->SearchBoxText)) + return TRUE; + + if (!PhIsNullOrEmptyString(node->IdText)) + { + if (WordMatchStringRef(context, &node->IdText->sr)) + return TRUE; + } + + if (!PhIsNullOrEmptyString(node->FlagsText)) + { + if (WordMatchStringRef(context, &node->FlagsText->sr)) + return TRUE; + } + + if (!PhIsNullOrEmptyString(node->PathText)) + { + if (WordMatchStringRef(context, &node->PathText->sr)) + return TRUE; + } + + if (!PhIsNullOrEmptyString(node->NativePathText)) + { + if (WordMatchStringRef(context, &node->NativePathText->sr)) + return TRUE; + } + + return FALSE; +} + INT_PTR CALLBACK DotNetAsmPageDlgProc( _In_ HWND hwndDlg, _In_ UINT uMsg, @@ -1197,81 +1443,56 @@ INT_PTR CALLBACK DotNetAsmPageDlgProc( { case WM_INITDIALOG: { - PPH_STRING settings; - HWND tnHandle; - - context = PhAllocateZero(sizeof(ASMPAGE_CONTEXT)); - propPageContext->Context = context; + context = propPageContext->Context = PhAllocateZero(sizeof(ASMPAGE_CONTEXT)); context->WindowHandle = hwndDlg; context->ProcessItem = processItem; - - context->ClrVersions = 0; - PhGetProcessIsDotNetEx(processItem->ProcessId, NULL, 0, NULL, &context->ClrVersions); - - tnHandle = GetDlgItem(hwndDlg, IDC_LIST); - context->TnHandle = tnHandle; - - TreeNew_SetCallback(tnHandle, DotNetAsmTreeNewCallback, context); - TreeNew_SetExtendedFlags(tnHandle, TN_FLAG_ITEM_DRAG_SELECT, TN_FLAG_ITEM_DRAG_SELECT); - PhSetControlTheme(tnHandle, L"explorer"); - SendMessage(TreeNew_GetTooltips(tnHandle), TTM_SETMAXTIPWIDTH, 0, MAXSHORT); - PhAddTreeNewColumn(tnHandle, DNATNC_STRUCTURE, TRUE, L"Structure", 240, PH_ALIGN_LEFT, -2, 0); - PhAddTreeNewColumn(tnHandle, DNATNC_ID, TRUE, L"ID", 50, PH_ALIGN_RIGHT, 0, DT_RIGHT); - PhAddTreeNewColumn(tnHandle, DNATNC_FLAGS, TRUE, L"Flags", 120, PH_ALIGN_LEFT, 1, 0); - PhAddTreeNewColumn(tnHandle, DNATNC_PATH, TRUE, L"Path", 600, PH_ALIGN_LEFT, 2, 0); // don't use path ellipsis - the user already has the base file name - PhAddTreeNewColumn(tnHandle, DNATNC_NATIVEPATH, TRUE, L"Native image path", 600, PH_ALIGN_LEFT, 3, 0); - - settings = PhGetStringSetting(SETTING_NAME_ASM_TREE_LIST_COLUMNS); - PhCmLoadSettings(tnHandle, &settings->sr); - PhDereferenceObject(settings); - - PhMoveReference(&context->TnErrorMessage, PhCreateString(L"Loading .NET assemblies...")); - TreeNew_SetEmptyText(tnHandle, &context->TnErrorMessage->sr, 0); - - if ( - !IsProcessSuspended(processItem->ProcessId) || - PhShowMessage(hwndDlg, MB_ICONWARNING | MB_YESNO, L".NET assembly enumeration may not work properly because the process is currently suspended. Do you want to continue?") == IDYES - ) - { - CreateDotNetTraceQueryThread( - hwndDlg, - context->ClrVersions, - processItem->ProcessId - ); - } - else - { - PhMoveReference(&context->TnErrorMessage, - PhCreateString(L"Unable to start the event tracing session because the process is suspended.") - ); - TreeNew_SetEmptyText(tnHandle, &context->TnErrorMessage->sr, 0); - InvalidateRect(tnHandle, NULL, FALSE); - } + context->SearchBoxHandle = GetDlgItem(hwndDlg, IDC_SEARCHEDIT); + context->TreeNewHandle = GetDlgItem(hwndDlg, IDC_LIST); + + PhCreateSearchControl(hwndDlg, context->SearchBoxHandle, L"Search Assemblies (Ctrl+K)"); + + context->NodeList = PhCreateList(64); + context->NodeRootList = PhCreateList(2); + TreeNew_SetCallback(context->TreeNewHandle, DotNetAsmTreeNewCallback, context); + TreeNew_SetExtendedFlags(context->TreeNewHandle, TN_FLAG_ITEM_DRAG_SELECT, TN_FLAG_ITEM_DRAG_SELECT); + PhSetControlTheme(context->TreeNewHandle, L"explorer"); + SendMessage(TreeNew_GetTooltips(context->TreeNewHandle), TTM_SETMAXTIPWIDTH, 0, MAXSHORT); + PhAddTreeNewColumn(context->TreeNewHandle, DNATNC_STRUCTURE, TRUE, L"Structure", 240, PH_ALIGN_LEFT, -2, 0); + PhAddTreeNewColumn(context->TreeNewHandle, DNATNC_ID, FALSE, L"ID", 50, PH_ALIGN_RIGHT, 1, DT_RIGHT); + PhAddTreeNewColumn(context->TreeNewHandle, DNATNC_FLAGS, FALSE, L"Flags", 120, PH_ALIGN_LEFT, 2, 0); + PhAddTreeNewColumn(context->TreeNewHandle, DNATNC_PATH, TRUE, L"File name", 600, PH_ALIGN_LEFT, 3, DT_PATH_ELLIPSIS); + PhAddTreeNewColumn(context->TreeNewHandle, DNATNC_NATIVEPATH, FALSE, L"Native image path", 600, PH_ALIGN_LEFT, 4, DT_PATH_ELLIPSIS); + DotNetAsmLoadSettingsTreeList(context); + + context->SearchBoxText = PhReferenceEmptyString(); + + PhInitializeTreeNewFilterSupport( + &context->TreeFilterSupport, + context->TreeNewHandle, + context->NodeList + ); + + context->TreeFilterEntry = PhAddTreeNewFilter( + &context->TreeFilterSupport, + DotNetAsmTreeFilterCallback, + context + ); + + DotNetAsmRefreshTraceQuery(context); PhInitializeWindowTheme(hwndDlg, !!PhGetIntegerSetting(L"EnableThemeSupport")); } break; case WM_DESTROY: { - PPH_STRING settings; - ULONG i; + PhRemoveTreeNewFilter(&context->TreeFilterSupport, context->TreeFilterEntry); + PhDeleteTreeNewFilterSupport(&context->TreeFilterSupport); - settings = PhCmSaveSettings(context->TnHandle); - PhSetStringSetting2(SETTING_NAME_ASM_TREE_LIST_COLUMNS, &settings->sr); - PhDereferenceObject(settings); + DotNetAsmSaveSettingsTreeList(context); + DotNetAsmDestroyTreeNodes(context); - if (context->NodeList) - { - for (i = 0; i < context->NodeList->Count; i++) - DestroyNode(context->NodeList->Items[i]); - - PhDereferenceObject(context->NodeList); - } - - if (context->NodeRootList) - PhDereferenceObject(context->NodeRootList); - - PhClearReference(&context->TnErrorMessage); + PhDereferenceObject(context->TreeErrorMessage); + PhDereferenceObject(context->SearchBoxText); PhFree(context); } break; @@ -1281,52 +1502,155 @@ INT_PTR CALLBACK DotNetAsmPageDlgProc( if (dialogItem = PhBeginPropPageLayout(hwndDlg, propPageContext)) { - PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_LIST), dialogItem, PH_ANCHOR_ALL); + PhAddPropPageLayoutItem(hwndDlg, context->SearchBoxHandle, dialogItem, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); + PhAddPropPageLayoutItem(hwndDlg, context->TreeNewHandle, dialogItem, PH_ANCHOR_ALL); PhEndPropPageLayout(hwndDlg, propPageContext); } } break; + case WM_NOTIFY: + { + LPNMHDR header = (LPNMHDR)lParam; + + switch (header->code) + { + case PSN_QUERYINITIALFOCUS: + SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, (LPARAM)context->TreeNewHandle); + return TRUE; + } + } + break; case WM_COMMAND: { + switch (GET_WM_COMMAND_CMD(wParam, lParam)) + { + case EN_CHANGE: + { + PPH_STRING newSearchboxText; + + if (GET_WM_COMMAND_HWND(wParam, lParam) != context->SearchBoxHandle) + break; + + newSearchboxText = PH_AUTO(PhGetWindowText(context->SearchBoxHandle)); + + if (!PhEqualString(context->SearchBoxText, newSearchboxText, FALSE)) + { + DotNetAsmExpandAllTreeNodes(context, TRUE); + + PhSwapReference(&context->SearchBoxText, newSearchboxText); + PhApplyTreeNewFilters(&context->TreeFilterSupport); + TreeNew_NodesStructured(context->TreeNewHandle); + } + } + break; + } + switch (GET_WM_COMMAND_ID(wParam, lParam)) { case ID_COPY: { PPH_STRING text; - text = PhGetTreeNewText(context->TnHandle, 0); - PhSetClipboardString(context->TnHandle, &text->sr); + text = PhGetTreeNewText(context->TreeNewHandle, 0); + PhSetClipboardString(context->TreeNewHandle, &text->sr); PhDereferenceObject(text); } break; + case IDC_REFRESH: + { + DotNetAsmRefreshTraceQuery(context); + } + break; + case IDC_OPTIONS: + { + RECT rect; + PPH_EMENU menu; + PPH_EMENU_ITEM dynamicItem; + PPH_EMENU_ITEM highlightDynamicItem; + PPH_EMENU_ITEM selectedItem; + + GetWindowRect(GetDlgItem(hwndDlg, IDC_OPTIONS), &rect); + + menu = PhCreateEMenu(); + PhInsertEMenuItem(menu, dynamicItem = PhCreateEMenuItem(0, DN_ASM_MENU_HIDE_DYNAMIC_OPTION, L"Hide dynamic", NULL, NULL), ULONG_MAX); + PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX); + PhInsertEMenuItem(menu, highlightDynamicItem = PhCreateEMenuItem(0, DN_ASM_MENU_HIGHLIGHT_DYNAMIC_OPTION, L"Highlight dynamic", NULL, NULL), ULONG_MAX); + + if (context->HideDynamicModules) + dynamicItem->Flags |= PH_EMENU_CHECKED; + if (context->HighlightDynamicModules) + highlightDynamicItem->Flags |= PH_EMENU_CHECKED; + + selectedItem = PhShowEMenu( + menu, + hwndDlg, + PH_EMENU_SHOW_LEFTRIGHT, + PH_ALIGN_LEFT | PH_ALIGN_TOP, + rect.left, + rect.bottom + ); + + if (selectedItem && selectedItem->Id) + { + DotNetAsmSetOptionsTreeList(context, selectedItem->Id); + PhApplyTreeNewFilters(&context->TreeFilterSupport); + TreeNew_NodesStructured(context->TreeNewHandle); + } + + PhDestroyEMenu(menu); + } + break; } } break; - case UPDATE_MSG: + case DN_ASM_UPDATE_MSG: { ULONG result = (ULONG)wParam; PASMPAGE_QUERY_CONTEXT queryContext = (PASMPAGE_QUERY_CONTEXT)lParam; if (result == 0) { - PhSwapReference(&context->NodeList, queryContext->NodeList); - PhSwapReference(&context->NodeRootList, queryContext->NodeRootList); + DotNetAsmClearTreeNodes(context); + + if (queryContext->NodeRootList) + { + PhAddItemsList( + context->NodeRootList, + queryContext->NodeRootList->Items, + queryContext->NodeRootList->Count + ); + } + + if (queryContext->NodeList) + { + PhAddItemsList( + context->NodeList, + queryContext->NodeList->Items, + queryContext->NodeList->Count + ); + } - DestroyDotNetTraceQuery(queryContext); + PhMoveReference(&context->TreeErrorMessage, PhCreateString(L"There are no assemblies to display.")); + TreeNew_SetEmptyText(context->TreeNewHandle, &context->TreeErrorMessage->sr, 0); - TreeNew_NodesStructured(context->TnHandle); + PhApplyTreeNewFilters(&context->TreeFilterSupport); + TreeNew_NodesStructured(context->TreeNewHandle); } else { - PhMoveReference(&context->TnErrorMessage, + + PhMoveReference(&context->TreeErrorMessage, PhConcatStrings2(L"Unable to start the event tracing session: ", PhGetStringOrDefault(PhGetWin32Message(result), L"Unknown error")) ); - TreeNew_SetEmptyText(context->TnHandle, &context->TnErrorMessage->sr, 0); - InvalidateRect(context->TnHandle, NULL, FALSE); + TreeNew_SetEmptyText(context->TreeNewHandle, &context->TreeErrorMessage->sr, 0); + TreeNew_NodesStructured(context->TreeNewHandle); } + + DestroyDotNetTraceQuery(queryContext); } break; } return FALSE; } + diff --git a/plugins/DotNetTools/clrsup.c b/plugins/DotNetTools/clrsup.c index 3fca660cb6ce..de6a352bab4b 100644 --- a/plugins/DotNetTools/clrsup.c +++ b/plugins/DotNetTools/clrsup.c @@ -90,7 +90,7 @@ PPH_STRING GetRuntimeNameByAddressClrProcess( ULONG64 displacement; bufferLength = 33; - buffer = PhCreateStringEx(NULL, (bufferLength - 1) * 2); + buffer = PhCreateStringEx(NULL, (bufferLength - 1) * sizeof(WCHAR)); returnLength = 0; @@ -113,7 +113,7 @@ PPH_STRING GetRuntimeNameByAddressClrProcess( { PhDereferenceObject(buffer); bufferLength = returnLength; - buffer = PhCreateStringEx(NULL, (bufferLength - 1) * 2); + buffer = PhCreateStringEx(NULL, (bufferLength - 1) * sizeof(WCHAR)); if (!SUCCEEDED(IXCLRDataProcess_GetRuntimeNameByAddress( Support->DataProcess, @@ -133,7 +133,7 @@ PPH_STRING GetRuntimeNameByAddressClrProcess( if (Displacement) *Displacement = displacement; - buffer->Length = (returnLength - 1) * 2; + buffer->Length = (returnLength - 1) * sizeof(WCHAR); return buffer; } @@ -150,7 +150,7 @@ PPH_STRING GetNameXClrDataAppDomain( appDomain = AppDomain; bufferLength = 33; - buffer = PhCreateStringEx(NULL, (bufferLength - 1) * 2); + buffer = PhCreateStringEx(NULL, (bufferLength - 1) * sizeof(WCHAR)); returnLength = 0; @@ -165,7 +165,7 @@ PPH_STRING GetNameXClrDataAppDomain( { PhDereferenceObject(buffer); bufferLength = returnLength; - buffer = PhCreateStringEx(NULL, (bufferLength - 1) * 2); + buffer = PhCreateStringEx(NULL, (bufferLength - 1) * sizeof(WCHAR)); if (!SUCCEEDED(IXCLRDataAppDomain_GetName(appDomain, bufferLength, &returnLength, buffer->Buffer))) { @@ -174,7 +174,7 @@ PPH_STRING GetNameXClrDataAppDomain( } } - buffer->Length = (returnLength - 1) * 2; + buffer->Length = (returnLength - 1) * sizeof(WCHAR); return buffer; } diff --git a/plugins/DotNetTools/counters.c b/plugins/DotNetTools/counters.c index 17045bcb7338..f2b1d8f7e549 100644 --- a/plugins/DotNetTools/counters.c +++ b/plugins/DotNetTools/counters.c @@ -2,7 +2,7 @@ * Process Hacker .NET Tools - * IPC support functions * - * Copyright (C) 2015-2016 dmex + * Copyright (C) 2015-2018 dmex * * This file is part of Process Hacker. * @@ -25,26 +25,6 @@ #include "clr/ipcheader.h" #include "clr/ipcshared.h" -PPH_STRING GeneratePrivateName(_In_ HANDLE ProcessId) -{ - return PhaFormatString(L"\\BaseNamedObjects\\" CorLegacyPrivateIPCBlock, HandleToUlong(ProcessId)); -} - -PPH_STRING GeneratePrivateNameV4(_In_ HANDLE ProcessId) -{ - return PhaFormatString(L"\\BaseNamedObjects\\" CorLegacyPrivateIPCBlockTempV4, HandleToUlong(ProcessId)); -} - -PPH_STRING GenerateLegacyPublicName(_In_ HANDLE ProcessId) -{ - return PhaFormatString(L"\\BaseNamedObjects\\" CorLegacyPublicIPCBlock, HandleToUlong(ProcessId)); -} - -PPH_STRING GenerateBoundaryDescriptorName(_In_ HANDLE ProcessId) -{ - return PhaFormatString(CorSxSBoundaryDescriptor, HandleToUlong(ProcessId)); -} - PVOID GetLegacyBlockTableEntry( _In_ BOOLEAN Wow64, _In_ PVOID IpcBlockAddress, @@ -470,7 +450,7 @@ BOOLEAN OpenDotNetPublicControlBlock_V2( LARGE_INTEGER sectionOffset = { 0 }; SIZE_T viewSize = 0; - if (!PhStringRefToUnicodeString(&GenerateLegacyPublicName(ProcessId)->sr, §ionNameUs)) + if (!PhStringRefToUnicodeString(&PhaFormatString(L"\\BaseNamedObjects\\" CorLegacyPublicIPCBlock, HandleToUlong(ProcessId))->sr, §ionNameUs)) return FALSE; InitializeObjectAttributes( @@ -543,7 +523,7 @@ BOOLEAN OpenDotNetPublicControlBlock_V4( PTOKEN_APPCONTAINER_INFORMATION appContainerInfo = NULL; SID_IDENTIFIER_AUTHORITY SIDWorldAuth = SECURITY_WORLD_SID_AUTHORITY; - if (!PhStringRefToUnicodeString(&GenerateBoundaryDescriptorName(ProcessId)->sr, &boundaryNameUs)) + if (!PhStringRefToUnicodeString(&PhaFormatString(CorSxSBoundaryDescriptor, HandleToUlong(ProcessId))->sr, &boundaryNameUs)) goto CleanupExit; if (!(boundaryDescriptorHandle = RtlCreateBoundaryDescriptor(&boundaryNameUs, 0))) @@ -700,15 +680,21 @@ PPH_LIST QueryDotNetAppDomainsForPid_V2( _In_ HANDLE ProcessId ) { - LARGE_INTEGER sectionOffset = { 0 }; - SIZE_T viewSize = 0; - OBJECT_ATTRIBUTES objectAttributes; - UNICODE_STRING sectionNameUs; + PPH_LIST appDomainsList = NULL; + PPH_STRING legacyPrivateBlockName = NULL; HANDLE legacyPrivateBlockHandle = NULL; PVOID ipcControlBlockTable = NULL; - PPH_LIST appDomainsList = NULL; + OBJECT_ATTRIBUTES objectAttributes; + UNICODE_STRING sectionNameUs; + LARGE_INTEGER sectionOffset; + SIZE_T viewSize; + + legacyPrivateBlockName = PhFormatString( + L"\\BaseNamedObjects\\" CorLegacyPrivateIPCBlock, + HandleToUlong(ProcessId) + ); - if (!PhStringRefToUnicodeString(&GeneratePrivateName(ProcessId)->sr, §ionNameUs)) + if (!PhStringRefToUnicodeString(&legacyPrivateBlockName->sr, §ionNameUs)) goto CleanupExit; InitializeObjectAttributes( @@ -728,6 +714,9 @@ PPH_LIST QueryDotNetAppDomainsForPid_V2( goto CleanupExit; } + viewSize = 0; + sectionOffset.QuadPart = 0; + if (!NT_SUCCESS(NtMapViewOfSection( legacyPrivateBlockHandle, NtCurrentProcess(), @@ -809,6 +798,8 @@ PPH_LIST QueryDotNetAppDomainsForPid_V2( NtClose(legacyPrivateBlockHandle); } + PhDereferenceObject(legacyPrivateBlockName); + return appDomainsList; } @@ -818,15 +809,21 @@ PPH_LIST QueryDotNetAppDomainsForPid_V4( _In_ HANDLE ProcessId ) { + PPH_LIST appDomainsList = NULL; + PPH_STRING legacyPrivateBlockName = NULL; HANDLE legacyPrivateBlockHandle = NULL; PVOID ipcControlBlockTable = NULL; - LARGE_INTEGER sectionOffset = { 0 }; - SIZE_T viewSize = 0; OBJECT_ATTRIBUTES objectAttributes; UNICODE_STRING sectionNameUs; - PPH_LIST appDomainsList = NULL; + LARGE_INTEGER sectionOffset; + SIZE_T viewSize; + + legacyPrivateBlockName = PhaFormatString( + L"\\BaseNamedObjects\\" CorLegacyPrivateIPCBlockTempV4, + HandleToUlong(ProcessId) + ); - if (!PhStringRefToUnicodeString(&GeneratePrivateNameV4(ProcessId)->sr, §ionNameUs)) + if (!PhStringRefToUnicodeString(&legacyPrivateBlockName->sr, §ionNameUs)) goto CleanupExit; InitializeObjectAttributes( @@ -846,6 +843,9 @@ PPH_LIST QueryDotNetAppDomainsForPid_V4( goto CleanupExit; } + viewSize = 0; + sectionOffset.QuadPart = 0; + if (!NT_SUCCESS(NtMapViewOfSection( legacyPrivateBlockHandle, NtCurrentProcess(), diff --git a/plugins/DotNetTools/dn.h b/plugins/DotNetTools/dn.h index 23a3993e09ce..3a6cb15860f6 100644 --- a/plugins/DotNetTools/dn.h +++ b/plugins/DotNetTools/dn.h @@ -30,6 +30,8 @@ #define PLUGIN_NAME L"ProcessHacker.DotNetTools" #define SETTING_NAME_ASM_TREE_LIST_COLUMNS (PLUGIN_NAME L".AsmTreeListColumns") +#define SETTING_NAME_ASM_TREE_LIST_FLAGS (PLUGIN_NAME L".AsmTreeListFlags") +//#define SETTING_NAME_ASM_TREE_LIST_SORT (PLUGIN_NAME L".AsmTreeListSort") #define SETTING_NAME_DOT_NET_CATEGORY_INDEX (PLUGIN_NAME L".DotNetCategoryIndex") #define SETTING_NAME_DOT_NET_COUNTERS_COLUMNS (PLUGIN_NAME L".DotNetListColumns") #define SETTING_NAME_DOT_NET_SHOW_BYTE_SIZE (PLUGIN_NAME L".DotNetShowByteSizes") @@ -38,6 +40,9 @@ extern PPH_PLUGIN PluginInstance; +#define DN_ASM_MENU_HIDE_DYNAMIC_OPTION 1 +#define DN_ASM_MENU_HIGHLIGHT_DYNAMIC_OPTION 2 + typedef struct _DN_THREAD_ITEM { PPH_THREAD_ITEM ThreadItem; diff --git a/plugins/DotNetTools/main.c b/plugins/DotNetTools/main.c index c54131347ba7..9096477917c6 100644 --- a/plugins/DotNetTools/main.c +++ b/plugins/DotNetTools/main.c @@ -24,20 +24,20 @@ #include "dn.h" PPH_PLUGIN PluginInstance; -static PH_CALLBACK_REGISTRATION PluginLoadCallbackRegistration; -static PH_CALLBACK_REGISTRATION PluginUnloadCallbackRegistration; -static PH_CALLBACK_REGISTRATION PluginMenuItemCallbackRegistration; -static PH_CALLBACK_REGISTRATION PluginTreeNewMessageCallbackRegistration; -static PH_CALLBACK_REGISTRATION PluginPhSvcRequestCallbackRegistration; -static PH_CALLBACK_REGISTRATION MainWindowShowingCallbackRegistration; -static PH_CALLBACK_REGISTRATION ProcessPropertiesInitializingCallbackRegistration; -static PH_CALLBACK_REGISTRATION ProcessMenuInitializingCallbackRegistration; -static PH_CALLBACK_REGISTRATION ThreadMenuInitializingCallbackRegistration; -static PH_CALLBACK_REGISTRATION ModuleMenuInitializingCallbackRegistration; -static PH_CALLBACK_REGISTRATION ProcessTreeNewInitializingCallbackRegistration; -static PH_CALLBACK_REGISTRATION ThreadTreeNewInitializingCallbackRegistration; -static PH_CALLBACK_REGISTRATION ThreadTreeNewUninitializingCallbackRegistration; -static PH_CALLBACK_REGISTRATION ThreadStackControlCallbackRegistration; +PH_CALLBACK_REGISTRATION PluginLoadCallbackRegistration; +PH_CALLBACK_REGISTRATION PluginUnloadCallbackRegistration; +PH_CALLBACK_REGISTRATION PluginMenuItemCallbackRegistration; +PH_CALLBACK_REGISTRATION PluginTreeNewMessageCallbackRegistration; +PH_CALLBACK_REGISTRATION PluginPhSvcRequestCallbackRegistration; +PH_CALLBACK_REGISTRATION MainWindowShowingCallbackRegistration; +PH_CALLBACK_REGISTRATION ProcessPropertiesInitializingCallbackRegistration; +PH_CALLBACK_REGISTRATION ProcessMenuInitializingCallbackRegistration; +PH_CALLBACK_REGISTRATION ThreadMenuInitializingCallbackRegistration; +PH_CALLBACK_REGISTRATION ModuleMenuInitializingCallbackRegistration; +PH_CALLBACK_REGISTRATION ProcessTreeNewInitializingCallbackRegistration; +PH_CALLBACK_REGISTRATION ThreadTreeNewInitializingCallbackRegistration; +PH_CALLBACK_REGISTRATION ThreadTreeNewUninitializingCallbackRegistration; +PH_CALLBACK_REGISTRATION ThreadStackControlCallbackRegistration; VOID NTAPI LoadCallback( _In_opt_ PVOID Parameter, @@ -200,6 +200,7 @@ LOGICAL DllMain( PH_SETTING_CREATE settings[] = { { StringSettingType, SETTING_NAME_ASM_TREE_LIST_COLUMNS, L"" }, + { IntegerSettingType, SETTING_NAME_ASM_TREE_LIST_FLAGS, L"0" }, { IntegerSettingType, SETTING_NAME_DOT_NET_CATEGORY_INDEX, L"5" }, { StringSettingType, SETTING_NAME_DOT_NET_COUNTERS_COLUMNS, L"" }, { IntegerSettingType, SETTING_NAME_DOT_NET_SHOW_BYTE_SIZE, L"1" } @@ -311,7 +312,7 @@ LOGICAL DllMain( ); InitializeTreeNewObjectExtensions(); - PhAddSettings(settings, ARRAYSIZE(settings)); + PhAddSettings(settings, RTL_NUMBER_OF(settings)); } break; } diff --git a/plugins/DotNetTools/perfpage.c b/plugins/DotNetTools/perfpage.c index 3e386461a489..15911d040d1c 100644 --- a/plugins/DotNetTools/perfpage.c +++ b/plugins/DotNetTools/perfpage.c @@ -25,56 +25,126 @@ #include "dn.h" #include "clr\perfcounterdefs.h" +typedef struct _PERFPAGE_CONTEXT +{ + HWND WindowHandle; + HWND AppDomainsLv; + HWND CountersLv; + PPH_PROCESS_ITEM ProcessItem; + + union + { + BOOLEAN Flags; + struct + { + BOOLEAN Enabled : 1; + BOOLEAN ControlBlockValid : 1; + BOOLEAN ClrV4 : 1; + BOOLEAN IsWow64 : 1; + BOOLEAN Spare : 4; + }; + }; + + HANDLE ProcessHandle; + HANDLE BlockTableHandle; + PVOID BlockTableAddress; + PH_CALLBACK_REGISTRATION ProcessesUpdatedCallbackRegistration; +} PERFPAGE_CONTEXT, *PPERFPAGE_CONTEXT; + typedef enum _DOTNET_CATEGORY { // .NET CLR Exceptions (Runtime statistics on CLR exception handling) DOTNET_CATEGORY_EXCEPTIONS, - // .NET CLR Interop (Stats for CLR interop) DOTNET_CATEGORY_INTEROP, - // .NET CLR Jit (Stats for CLR Jit) DOTNET_CATEGORY_JIT, - // .NET CLR Loading (Statistics for CLR Class Loader) DOTNET_CATEGORY_LOADING, - // .NET CLR LocksAndThreads (Stats for CLR Locks and Threads) DOTNET_CATEGORY_LOCKSANDTHREADS, - // .NET CLR Memory (Counters for CLR Garbage Collected heap) DOTNET_CATEGORY_MEMORY, - // .NET CLR Remoting (Stats for CLR Remoting) DOTNET_CATEGORY_REMOTING, - // .NET CLR Security (Stats for CLR Security) DOTNET_CATEGORY_SECURITY } DOTNET_CATEGORY; -typedef struct _PERFPAGE_CONTEXT +typedef enum _DOTNET_INDEX { - HWND WindowHandle; - PPH_PROCESS_ITEM ProcessItem; - BOOLEAN Enabled; - - HWND AppDomainsLv; - HWND CountersLv; - HWND CategoriesCb; - - BOOLEAN ControlBlockValid; - BOOLEAN ClrV4; - BOOLEAN IsWow64; - BOOLEAN ShowByteSize; - DOTNET_CATEGORY CategoryIndex; - HANDLE ProcessHandle; - HANDLE BlockTableHandle; - PVOID BlockTableAddress; - - PH_CALLBACK_REGISTRATION ProcessesUpdatedCallbackRegistration; -} PERFPAGE_CONTEXT, *PPERFPAGE_CONTEXT; - -static PWSTR DotNetCategoryStrings[] = + DOTNET_INDEX_EXCEPTIONS_THROWNCOUNT, + DOTNET_INDEX_EXCEPTIONS_FILTERSCOUNT, + DOTNET_INDEX_EXCEPTIONS_FINALLYCOUNT, + + DOTNET_INDEX_INTEROP_CCWCOUNT, + DOTNET_INDEX_INTEROP_STUBCOUNT, + DOTNET_INDEX_INTEROP_MARSHALCOUNT, + DOTNET_INDEX_INTEROP_TLBIMPORTPERSEC, + DOTNET_INDEX_INTEROP_TLBEXPORTPERSEC, + + DOTNET_INDEX_JIT_ILMETHODSJITTED, + DOTNET_INDEX_JIT_ILBYTESJITTED, + DOTNET_INDEX_JIT_ILTOTALBYTESJITTED, + DOTNET_INDEX_JIT_FAILURES, + DOTNET_INDEX_JIT_TIME, + + DOTNET_INDEX_LOADING_CURRENTLOADED, + DOTNET_INDEX_LOADING_TOTALLOADED, + DOTNET_INDEX_LOADING_CURRENTAPPDOMAINS, + DOTNET_INDEX_LOADING_TOTALAPPDOMAINS, + DOTNET_INDEX_LOADING_CURRENTASSEMBLIES, + DOTNET_INDEX_LOADING_TOTALASSEMBLIES, + DOTNET_INDEX_LOADING_ASSEMBLYSEARCHLENGTH, + DOTNET_INDEX_LOADING_TOTALLOADFAILURES, + DOTNET_INDEX_LOADING_BYTESINLOADERHEAP, + DOTNET_INDEX_LOADING_TOTALAPPDOMAINSUNLOADED, + + DOTNET_INDEX_LOCKSANDTHREADS_TOTALLOCKS, + DOTNET_INDEX_LOCKSANDTHREADS_TOTALQUEUELENGTH, + DOTNET_INDEX_LOCKSANDTHREADS_QUEUELENGTHPEAK, + DOTNET_INDEX_LOCKSANDTHREADS_CURRENTLOGICAL, + DOTNET_INDEX_LOCKSANDTHREADS_CURRENTPHYSICAL, + DOTNET_INDEX_LOCKSANDTHREADS_CURRENTRECOGNIZED, + DOTNET_INDEX_LOCKSANDTHREADS_TOTALRECOGNIZED, + + DOTNET_INDEX_MEMORY_GENZEROCOLLECTIONS, + DOTNET_INDEX_MEMORY_GENONECOLLECTIONS, + DOTNET_INDEX_MEMORY_GENTWOCOLLECTIONS, + DOTNET_INDEX_MEMORY_PROMOTEDFROMGENZERO, + DOTNET_INDEX_MEMORY_PROMOTEDFROMGENONE, + DOTNET_INDEX_MEMORY_PROMOTEDFINALFROMGENZERO, + DOTNET_INDEX_MEMORY_PROCESSID, + DOTNET_INDEX_MEMORY_GENZEROHEAPSIZE, + DOTNET_INDEX_MEMORY_GENONEHEAPSIZE, + DOTNET_INDEX_MEMORY_GENTWOHEAPSIZE, + DOTNET_INDEX_MEMORY_LOHSIZE, + DOTNET_INDEX_MEMORY_FINALSURVIVORS, + DOTNET_INDEX_MEMORY_GCHANDLES, + DOTNET_INDEX_MEMORY_INDUCEDGC, + DOTNET_INDEX_MEMORY_TIMEINGC, + DOTNET_INDEX_MEMORY_BYTESINALLHEAPS, + DOTNET_INDEX_MEMORY_TOTALCOMMITTED, + DOTNET_INDEX_MEMORY_TOTALRESERVED, + DOTNET_INDEX_MEMORY_TOTALPINNED, + DOTNET_INDEX_MEMORY_TOTALSINKS, + DOTNET_INDEX_MEMORY_TOTALBYTESSINCESTART, + DOTNET_INDEX_MEMORY_TOTALLOHBYTESSINCESTART, + + DOTNET_INDEX_REMOTING_TOTALREMOTECALLS, + DOTNET_INDEX_REMOTING_CHANNELS, + DOTNET_INDEX_REMOTING_CONTEXTPROXIES, + DOTNET_INDEX_REMOTING_CONTEXTCLASSESLOADED, + DOTNET_INDEX_REMOTING_CONTEXTS, + DOTNET_INDEX_REMOTING_CONTEXTSALLOCATED, + + DOTNET_INDEX_SECURITY_TOTALRUNTIMECHECKS, + DOTNET_INDEX_SECURITY_LINKTIMECHECKS, + DOTNET_INDEX_SECURITY_TIMEINRTCHECKS, + DOTNET_INDEX_SECURITY_STACKWALKDEPTH +} DOTNET_INDEX; + +PWSTR DotNetCategoryStrings[] = { L".NET CLR Exceptions", L".NET CLR Interop", @@ -86,18 +156,7 @@ static PWSTR DotNetCategoryStrings[] = L".NET CLR Security" }; -PPH_STRING FormatByteValue( - _In_ PPERFPAGE_CONTEXT Context, - _In_ ULONG64 Value - ) -{ - if (Context->ShowByteSize) - return PhaFormatUInt64(Value, TRUE); - - return PhaFormatSize(Value, -1); -} - -VOID NTAPI ProcessesUpdatedCallback( +VOID NTAPI DotNetPerfProcessesUpdatedCallback( _In_opt_ PVOID Parameter, _In_opt_ PVOID Context ) @@ -110,295 +169,428 @@ VOID NTAPI ProcessesUpdatedCallback( } } -VOID UpdateCategoryValues( - _In_ HWND hwndDlg, - _In_ PPERFPAGE_CONTEXT Context +VOID DotNetPerfAddListViewGroups( + _In_ HWND ListViewHandle ) { - ListView_DeleteAllItems(Context->CountersLv); - - switch (Context->CategoryIndex) - { - case DOTNET_CATEGORY_EXCEPTIONS: - { - // This counter displays the total number of exceptions thrown since the start of the application. These include both .NET exceptions and unmanaged exceptions that get converted into .NET exceptions e.g. null pointer reference exception in unmanaged code would get re-thrown in managed code as a .NET System.NullReferenceException; this counter includes both handled and unhandled exceptions.Exceptions that are re-thrown would get counted again. Exceptions should only occur in rare situations and not in the normal control flow of the program. - PhAddListViewItem(Context->CountersLv, MAXINT, L"# of Exceps Thrown", NULL); - PhAddListViewItem(Context->CountersLv, MAXINT, L"# of Filters Executed", NULL); - PhAddListViewItem(Context->CountersLv, MAXINT, L"# of Finallys Executed", NULL); - - // Reserved for future use. - //PhAddListViewItem(Context->CountersLv, MAXINT, L" Delta from throw to catch site on stack", NULL); - - // # of Exceps Thrown / sec - // This counter displays the number of exceptions thrown per second.These include both.NET exceptions and unmanaged exceptions that get converted into.NET exceptions e.g.null pointer reference exception in unmanaged code would get re - thrown in managed code as a.NET System.NullReferenceException; this counter includes both handled and unhandled exceptions.Exceptions should only occur in rare situations and not in the normal control flow of the program; this counter was designed as an indicator of potential performance problems due to large(> 100s) rate of exceptions thrown.This counter is not an average over time; it displays the difference between the values observed in the last two samples divided by the duration of the sample interval. - - // # of Filters / sec - // This counter displays the number of.NET exception filters executed per second.An exception filter evaluates whether an exception should be handled or not.This counter tracks the rate of exception filters evaluated; irrespective of whether the exception was handled or not.This counter is not an average over time; it displays the difference between the values observed in the last two samples divided by the duration of the sample interval. - - // # of Finallys / sec - // This counter displays the number of finally blocks executed per second.A finally block is guaranteed to be executed regardless of how the try block was exited.Only the finally blocks that are executed for an exception are counted; finally blocks on normal code paths are not counted by this counter.This counter is not an average over time; it displays the difference between the values observed in the last two samples divided by the duration of the sample interval. - - // Throw To Catch Depth / sec - // This counter displays the number of stack frames traversed from the frame that threw the.NET exception to the frame that handled the exception per second.This counter resets to 0 when an exception handler is entered; so nested exceptions would show the handler to handler stack depth.This counter is not an average over time; it displays the difference between the values observed in the last two samples divided by the duration of the sample interval.* / - } - break; - case DOTNET_CATEGORY_INTEROP: - { - // This counter displays the current number of Com-Callable-Wrappers (CCWs). A CCW is a proxy for the .NET managed object being referenced from unmanaged COM client(s). This counter was designed to indicate the number of managed objects being referenced by unmanaged COM code. - PhAddListViewItem(Context->CountersLv, MAXINT, L"# of CCWs", NULL); - - // This counter displays the current number of stubs created by the CLR. Stubs are responsible for marshalling arguments and return values from managed to unmanaged code and vice versa; during a COM Interop call or PInvoke call. - PhAddListViewItem(Context->CountersLv, MAXINT, L"# of Stubs", NULL); - - // This counter displays the total number of times arguments and return values have been marshaled from managed to unmanaged code and vice versa since the start of the application. This counter is not incremented if the stubs are inlined. (Stubs are responsible for marshalling arguments and return values). Stubs usually get inlined if the marshalling overhead is small. - PhAddListViewItem(Context->CountersLv, MAXINT, L"# of Marshalling", NULL); - - // Reserved for future use. - PhAddListViewItem(Context->CountersLv, MAXINT, L"# of TLB imports / sec", NULL); - - // Reserved for future use. - PhAddListViewItem(Context->CountersLv, MAXINT, L"# of TLB exports / sec", NULL); - } - break; - case DOTNET_CATEGORY_JIT: - { - // This counter displays the total number of methods compiled Just-In-Time (JIT) by the CLR JIT compiler since the start of the application. This counter does not include the pre-jitted methods. - PhAddListViewItem(Context->CountersLv, MAXINT, L"# of Methods Jitted", NULL); - - // This counter displays the total IL bytes jitted since the start of the application. This counter is exactly equivalent to the "Total # of IL Bytes Jitted" counter. - PhAddListViewItem(Context->CountersLv, MAXINT, L"# of IL Bytes Jitted", NULL); - - // This counter displays the total IL bytes jitted since the start of the application. This counter is exactly equivalent to the "# of IL Bytes Jitted" counter. - PhAddListViewItem(Context->CountersLv, MAXINT, L"Total # of IL Bytes Jitted", NULL); - - // This counter displays the peak number of methods the JIT compiler has failed to JIT since the start of the application. This failure can occur if the IL cannot be verified or if there was an internal error in the JIT compiler. - PhAddListViewItem(Context->CountersLv, MAXINT, L"Jit Failures", NULL); - - // This counter displays the percentage of elapsed time spent in JIT compilation since the last JIT compilation phase. This counter is updated at the end of every JIT compilation phase. A JIT compilation phase is the phase when a method and its dependencies are being compiled. - PhAddListViewItem(Context->CountersLv, MAXINT, L"% Time in Jit", NULL); - - // IL Bytes Jitted / sec - // This counter displays the rate at which IL bytes are jitted per second. This counter is not an average over time; it displays the difference between the values observed in the last two samples divided by the duration of the sample interval. - } - break; - case DOTNET_CATEGORY_LOADING: - { - // This counter displays the current number of classes loaded in all Assemblies. - PhAddListViewItem(Context->CountersLv, MAXINT, L"Current Classes Loaded", NULL); - - // This counter displays the cumulative number of classes loaded in all Assemblies since the start of this application. - PhAddListViewItem(Context->CountersLv, MAXINT, L"Total Classes Loaded", NULL); - - // This counter displays the current number of AppDomains loaded in this application. AppDomains (application domains) provide a secure and versatile unit of processing that the CLR can use to provide isolation between applications running in the same process. - PhAddListViewItem(Context->CountersLv, MAXINT, L"Current Appdomains", NULL); - - // This counter displays the peak number of AppDomains loaded since the start of this application. AppDomains (application domains) provide a secure and versatile unit of processing that the CLR can use to provide isolation between applications running in the same process. - PhAddListViewItem(Context->CountersLv, MAXINT, L"Total Appdomains", NULL); - - // This counter displays the current number of Assemblies loaded across all AppDomains in this application. If the Assembly is loaded as domain - neutral from multiple AppDomains then this counter is incremented once only. Assemblies can be loaded as domain - neutral when their code can be shared by all AppDomains or they can be loaded as domain - specific when their code is private to the AppDomain. - PhAddListViewItem(Context->CountersLv, MAXINT, L"Current Assemblies", NULL); - - // This counter displays the total number of Assemblies loaded since the start of this application. If the Assembly is loaded as domain - neutral from multiple AppDomains then this counter is incremented once only. Assemblies can be loaded as domain - neutral when their code can be shared by all AppDomains or they can be loaded as domain - specific when their code is private to the AppDomain. - PhAddListViewItem(Context->CountersLv, MAXINT, L"Total Assemblies", NULL); - - // Reserved for future use. - PhAddListViewItem(Context->CountersLv, MAXINT, L"Assembly Search Length", NULL); - - // This counter displays the peak number of classes that have failed to load since the start of the application.These load failures could be due to many reasons like inadequate security or illegal format.Full details can be found in the profiling services help. - PhAddListViewItem(Context->CountersLv, MAXINT, L"Total # of Load Failures", NULL); - - // This counter displays the current size(in bytes) of the memory committed by the class loader across all AppDomains. (Committed memory is the physical memory for which space has been reserved on the disk paging file.) - PhAddListViewItem(Context->CountersLv, MAXINT, L"Bytes in Loader Heap", NULL); - - // This counter displays the total number of AppDomains unloaded since the start of the application. If an AppDomain is loaded and unloaded multiple times this counter would count each of those unloads as separate. - PhAddListViewItem(Context->CountersLv, MAXINT, L"Total Appdomains Unloaded", NULL); - - // Reserved for future use. - //PhAddListViewItem(Context->CountersLv, MAXINT, L"% Time Loading", NULL); - - // Rate of Load Failures - // This counter displays the number of classes that failed to load per second. This counter is not an average over time; it displays the difference between the values observed in the last two samples divided by the duration of the sample interval. These load failures could be due to many reasons like inadequate security or illegal format. Full details can be found in the profiling services help. - - // Rate of appdomains unloaded - // This counter displays the number of AppDomains unloaded per second.This counter is not an average over time; it displays the difference between the values observed in the last two samples divided by the duration of the sample interval. - - // Rate of Classes Loaded - // This counter displays the number of classes loaded per second in all Assemblies.This counter is not an average over time; it displays the difference between the values observed in the last two samples divided by the duration of the sample interval. - - // Rate of appdomains - // This counter displays the number of AppDomains loaded per second.AppDomains(application domains) provide a secure and versatile unit of processing that the CLR can use to provide isolation between applications running in the same process.This counter is not an average over time; it displays the difference between the values observed in the last two samples divided by the duration of the sample interval. - - // Rate of Assemblies - // This counter displays the number of Assemblies loaded across all AppDomains per second.If the Assembly is loaded as domain - neutral from multiple AppDomains then this counter is incremented once only.Assemblies can be loaded as domain - neutral when their code can be shared by all AppDomains or they can be loaded as domain - specific when their code is private to the AppDomain.This counter is not an average over time; it displays the difference between the values observed in the last two samples divided by the duration of the sample interval. - } - break; - case DOTNET_CATEGORY_LOCKSANDTHREADS: - { - // This counter displays the total number of times threads in the CLR have attempted to acquire a managed lock unsuccessfully. Managed locks can be acquired in many ways; by the "lock" statement in C# or by calling System.Monitor.Enter or by using MethodImplOptions.Synchronized custom attribute. - PhAddListViewItem(Context->CountersLv, MAXINT, L"Total # of Contentions", NULL); - - // This counter displays the total number of threads currently waiting to acquire some managed lock in the application. This counter is not an average over time; it displays the last observed value. - PhAddListViewItem(Context->CountersLv, MAXINT, L"Current Queue Length", NULL); - - // This counter displays the total number of threads that waited to acquire some managed lock since the start of the application. - PhAddListViewItem(Context->CountersLv, MAXINT, L"Queue Length Peak", NULL); - - // This counter displays the number of current.NET thread objects in the application.A.NET thread object is created either by new System.Threading.Thread or when an unmanaged thread enters the managed environment. This counters maintains the count of both running and stopped threads. This counter is not an average over time; it just displays the last observed value. - PhAddListViewItem(Context->CountersLv, MAXINT, L"# of Current Logical Threads", NULL); - - // This counter displays the number of native OS threads created and owned by the CLR to act as underlying threads for .NET thread objects. This counters value does not include the threads used by the CLR in its internal operations; it is a subset of the threads in the OS process. - PhAddListViewItem(Context->CountersLv, MAXINT, L"# of Current Physical Threads", NULL); - - // This counter displays the number of threads that are currently recognized by the CLR; they have a corresponding .NET thread object associated with them. These threads are not created by the CLR; they are created outside the CLR but have since run inside the CLR at least once. Only unique threads are tracked; threads with same thread ID re-entering the CLR or recreated after thread exit are not counted twice. - PhAddListViewItem(Context->CountersLv, MAXINT, L"# of Current Recognized Threads", NULL); - - // This counter displays the total number of threads that have been recognized by the CLR since the start of this application; these threads have a corresponding .NET thread object associated with them. These threads are not created by the CLR; they are created outside the CLR but have since run inside the CLR at least once. Only unique threads are tracked; threads with same thread ID re-entering the CLR or recreated after thread exit are not counted twice. - PhAddListViewItem(Context->CountersLv, MAXINT, L"# of Total Recognized Threads", NULL); - - // Contention Rate / sec - // Rate at which threads in the runtime attempt to acquire a managed lock unsuccessfully.Managed locks can be acquired in many ways; by the "lock" statement in C# or by calling System.Monitor.Enter or by using MethodImplOptions.Synchronized custom attribute. - - // Queue Length / sec - // This counter displays the number of threads per second waiting to acquire some lock in the application. This counter is not an average over time; it displays the difference between the values observed in the last two samples divided by the duration of the sample interval. - - // rate of recognized threads / sec - // This counter displays the number of threads per second that have been recognized by the CLR; these threads have a corresponding .NET thread object associated with them. These threads are not created by the CLR; they are created outside the CLR but have since run inside the CLR at least once. Only unique threads are tracked; threads with same thread ID re-entering the CLR or recreated after thread exit are not counted twice. This counter is not an average over time; it displays the difference between the values observed in the last two samples divided by the duration of the sample interval. - } - break; - case DOTNET_CATEGORY_MEMORY: - { - // This counter displays the number of times the generation 0 objects (youngest; most recently allocated) are garbage collected (Gen 0 GC) since the start of the application. Gen 0 GC occurs when the available memory in generation 0 is not sufficient to satisfy an allocation request. This counter is incremented at the end of a Gen 0 GC. Higher generation GCs include all lower generation GCs.This counter is explicitly incremented when a higher generation (Gen 1 or Gen 2) GC occurs. _Global_ counter value is not accurate and should be ignored. This counter displays the last observed value. - PhAddListViewItem(Context->CountersLv, MAXINT, L"# Gen 0 Collections", NULL); - - // This counter displays the number of times the generation 1 objects are garbage collected since the start of the application. The counter is incremented at the end of a Gen 1 GC. Higher generation GCs include all lower generation GCs. This counter is explicitly incremented when a higher generation (Gen 2) GC occurs. _Global_ counter value is not accurate and should be ignored. This counter displays the last observed value. - PhAddListViewItem(Context->CountersLv, MAXINT, L"# Gen 1 Collections", NULL); - - // This counter displays the number of times the generation 2 objects(older) are garbage collected since the start of the application.The counter is incremented at the end of a Gen 2 GC(also called full GC)._Global_ counter value is not accurate and should be ignored.This counter displays the last observed value. - PhAddListViewItem(Context->CountersLv, MAXINT, L"# Gen 2 Collections", NULL); - - // This counter displays the bytes of memory that survive garbage collection(GC) and are promoted from generation 0 to generation 1; objects that are promoted just because they are waiting to be finalized are not included in this counter.This counter displays the value observed at the end of the last GC; its not a cumulative counter. - PhAddListViewItem(Context->CountersLv, MAXINT, L"Promoted Memory from Gen 0", NULL); - - // This counter displays the bytes of memory that survive garbage collection(GC) and are promoted from generation 1 to generation 2; objects that are promoted just because they are waiting to be finalized are not included in this counter.This counter displays the value observed at the end of the last GC; its not a cumulative counter.This counter is reset to 0 if the last GC was a Gen 0 GC only. - PhAddListViewItem(Context->CountersLv, MAXINT, L"Promoted Memory from Gen 1", NULL); - - // This counter displays the bytes of memory that are promoted from generation 0 to generation 1 just because they are waiting to be finalized.This counter displays the value observed at the end of the last GC; its not a cumulative counter. - PhAddListViewItem(Context->CountersLv, MAXINT, L"Promoted Finalization-Memory from Gen 0", NULL); - - // Reserved for future use. - PhAddListViewItem(Context->CountersLv, MAXINT, L"Process ID", NULL); - - // This counter displays the maximum bytes that can be allocated in generation 0 (Gen 0); its does not indicate the current number of bytes allocated in Gen 0. A Gen 0 GC is triggered when the allocations since the last GC exceed this size.The Gen 0 size is tuned by the Garbage Collector and can change during the execution of the application.At the end of a Gen 0 collection the size of the Gen 0 heap is infact 0 bytes; this counter displays the size(in bytes) of allocations that would trigger the next Gen 0 GC.This counter is updated at the end of a GC; its not updated on every allocation. - PhAddListViewItem(Context->CountersLv, MAXINT, L"Gen 0 Heap Size", NULL); - - // This counter displays the current number of bytes in generation 1 (Gen 1); this counter does not display the maximum size of Gen 1. Objects are not directly allocated in this generation; they are promoted from previous Gen 0 GCs.This counter is updated at the end of a GC; its not updated on every allocation. - PhAddListViewItem(Context->CountersLv, MAXINT, L"Gen 1 Heap Size", NULL); - - // This counter displays the current number of bytes in generation 2 (Gen 2).Objects are not directly allocated in this generation; they are promoted from Gen 1 during previous Gen 1 GCs.This counter is updated at the end of a GC; its not updated on every allocation. - PhAddListViewItem(Context->CountersLv, MAXINT, L"Gen 2 Heap Size", NULL); - - // This counter displays the current size of the Large Object Heap in bytes.Objects greater than 20 KBytes are treated as large objects by the Garbage Collector and are directly allocated in a special heap; they are not promoted through the generations.This counter is updated at the end of a GC; its not updated on every allocation. - PhAddListViewItem(Context->CountersLv, MAXINT, L"Large Object Heap Size", NULL); - - // This counter displays the number of garbage collected objects that survive a collection because they are waiting to be finalized.If these objects hold references to other objects then those objects also survive but are not counted by this counter; the "Promoted Finalization-Memory from Gen 0" and "Promoted Finalization-Memory from Gen 1" counters represent all the memory that survived due to finalization.This counter is not a cumulative counter; its updated at the end of every GC with count of the survivors during that particular GC only.This counter was designed to indicate the extra overhead that the application might incur because of finalization. - PhAddListViewItem(Context->CountersLv, MAXINT, L"Finalization Survivors", NULL); - - // This counter displays the current number of GC Handles in use.GCHandles are handles to resources external to the CLR and the managed environment.Handles occupy small amounts of memory in the GCHeap but potentially expensive unmanaged resources. - PhAddListViewItem(Context->CountersLv, MAXINT, L"# GC Handles", NULL); - - // This counter displays the peak number of times a garbage collection was performed because of an explicit call to GC.Collect. Its a good practice to let the GC tune the frequency of its collections. - PhAddListViewItem(Context->CountersLv, MAXINT, L"# Induced GC", NULL); - - // % Time in GC is the percentage of elapsed time that was spent in performing a garbage collection(GC) since the last GC cycle. This counter is usually an indicator of the work done by the Garbage Collector on behalf of the application to collect and compact memory.This counter is updated only at the end of every GC and the counter value reflects the last observed value; its not an average. - PhAddListViewItem(Context->CountersLv, MAXINT, L"% Time in GC", NULL); - - // This counter is the sum of four other counters; Gen 0 Heap Size; Gen 1 Heap Size; Gen 2 Heap Size and the Large Object Heap Size. This counter indicates the current memory allocated in bytes on the GC Heaps. - PhAddListViewItem(Context->CountersLv, MAXINT, L"# Bytes in all Heaps", NULL); - - // This counter displays the amount of virtual memory(in bytes) currently committed by the Garbage Collector. (Committed memory is the physical memory for which space has been reserved on the disk paging file). - PhAddListViewItem(Context->CountersLv, MAXINT, L"# Total Committed Bytes", NULL); - - // This counter displays the amount of virtual memory(in bytes) currently reserved by the Garbage Collector. (Reserved memory is the virtual memory space reserved for the application but no disk or main memory pages have been used.) - PhAddListViewItem(Context->CountersLv, MAXINT, L"# Total Reserved Bytes", NULL); - - // This counter displays the number of pinned objects encountered in the last GC. This counter tracks the pinned objects only in the heaps that were garbage collected e.g. A Gen 0 GC would cause enumeration of pinned objects in the generation 0 heap only. A pinned object is one that the Garbage Collector cannot move in memory. - PhAddListViewItem(Context->CountersLv, MAXINT, L"# of Pinned Objects", NULL); - - // This counter displays the current number of sync blocks in use. Sync blocks are per-object data structures allocated for storing synchronization information. Sync blocks hold weak references to managed objects and need to be scanned by the Garbage Collector. Sync blocks are not limited to storing synchronization information and can also store COM interop metadata. This counter was designed to indicate performance problems with heavy use of synchronization primitives. - PhAddListViewItem(Context->CountersLv, MAXINT, L"# of Sink Blocks in use", NULL); - - // Reserved for future use. - PhAddListViewItem(Context->CountersLv, MAXINT, L"Total Bytes Allocated (since start)", NULL); - - // Reserved for future use. - PhAddListViewItem(Context->CountersLv, MAXINT, L"Total Bytes Allocated for Large Objects (since start)", NULL); - - // Gen 0 Promoted Bytes / Sec - // This counter displays the bytes per second that are promoted from generation 0 (youngest)to generation 1; objects that are promoted just because they are waiting to be finalized are not included in this counter.Memory is promoted when it survives a garbage collection.This counter was designed as an indicator of relatively long - lived objects being created per sec.This counter displays the difference between the values observed in the last two samples divided by the duration of the sample interval. - - // Gen 1 Promoted Bytes / Sec - // This counter displays the bytes per second that are promoted from generation 1 to generation 2 (oldest); objects that are promoted just because they are waiting to be finalized are not included in this counter.Memory is promoted when it survives a garbage collection.Nothing is promoted from generation 2 since it is the oldest.This counter was designed as an indicator of very long - lived objects being created per sec.This counter displays the difference between the values observed in the last two samples divided by the duration of the sample interval. - - // Promoted Finalization - Memory from Gen 1 - // This counter displays the bytes of memory that are promoted from generation 1 to generation 2 just because they are waiting to be finalized.This counter displays the value observed at the end of the last GC; its not a cumulative counter.This counter is reset to 0 if the last GC was a Gen 0 GC only. - - // Allocated Bytes / sec - // This counter displays the rate of bytes per second allocated on the GC Heap.This counter is updated at the end of every GC; not at each allocation.This counter is not an average over time; it displays the difference between the values observed in the last two samples divided by the duration of the sample interval. - } - break; - case DOTNET_CATEGORY_REMOTING: - { - // This counter displays the total number of remote procedure calls invoked since the start of this application. A remote procedure call is a call on any object outside the callers AppDomain. - PhAddListViewItem(Context->CountersLv, MAXINT, L"Total Remote Calls", NULL); - - // This counter displays the total number of remoting channels registered across all AppDomains since the start of the application. Channels are used to transport messages to and from remote objects. - PhAddListViewItem(Context->CountersLv, MAXINT, L"Channels", NULL); - - // This counter displays the total number of remoting proxy objects created in this process since the start of the process. Proxy object acts as a representative of the remote objects and ensures that all calls made on the proxy are forwarded to the correct remote object instance. - PhAddListViewItem(Context->CountersLv, MAXINT, L"Context Proxies", NULL); - - // This counter displays the current number of context-bound classes loaded. Classes that can be bound to a context are called context-bound classes; context-bound classes are marked with Context Attributes which provide usage rules for synchronization; thread affinity; transactions etc. - PhAddListViewItem(Context->CountersLv, MAXINT, L"Context-Bound Classes Loaded", NULL); - - // This counter displays the current number of remoting contexts in the application. A context is a boundary containing a collection of objects with the same usage rules like synchronization; thread affinity; transactions etc. - PhAddListViewItem(Context->CountersLv, MAXINT, L"Contexts", NULL); - - PhAddListViewItem(Context->CountersLv, MAXINT, L"# of context bound objects allocated", NULL); - - // Remote Calls / sec - // This counter displays the number of remote procedure calls invoked per second. A remote procedure call is a call on any object outside the callers AppDomain. This counter is not an average over time; it displays the difference between the values observed in the last two samples divided by the duration of the sample interval. - - // Context - Bound Objects Alloc / sec - // This counter displays the number of context - bound objects allocated per second. Instances of classes that can be bound to a context are called context - bound objects; context - bound classes are marked with Context Attributes which provide usage rules for synchronization; thread affinity; transactions etc.This counter is not an average over time; it displays the difference between the values observed in the last two samples divided by the duration of the sample interval. - } - break; - case DOTNET_CATEGORY_SECURITY: - { - // This counter displays the total number of runtime Code Access Security(CAS) checks performed since the start of the application. Runtime CAS checks are performed when a caller makes a call to a callee demanding a particular permission; the runtime check is made on every call by the caller; the check is done by examining the current thread stack of the caller. This counter used together with "Stack Walk Depth" is indicative of performance penalty for security checks. - PhAddListViewItem(Context->CountersLv, MAXINT, L"Total Runtime Checks", NULL); - - // This counter displays the total number of linktime Code Access Security(CAS) checks since the start of the application. Linktime CAS checks are performed when a caller makes a call to a callee demanding a particular permission at JIT compile time; linktime check is performed once per caller. This count is not indicative of serious performance issues; its indicative of the security system activity. - PhAddListViewItem(Context->CountersLv, MAXINT, L"# Link Time Checks", NULL); - - // This counter displays the percentage of elapsed time spent in performing runtime Code Access Security(CAS) checks since the last such check. CAS allows code to be trusted to varying degrees and enforces these varying levels of trust depending on code identity. This counter is updated at the end of a runtime security check; it represents the last observed value; its not an average. - PhAddListViewItem(Context->CountersLv, MAXINT, L"% Time in RT checks", NULL); - - // This counter displays the depth of the stack during that last runtime Code Access Security check.Runtime Code Access Security check is performed by crawling the stack. This counter is not an average; it just displays the last observed value. - PhAddListViewItem(Context->CountersLv, MAXINT, L"Stack Walk Depth", NULL); - - // % Time Sig.Authenticating - // Reserved for future use. - } - break; - } + ListView_EnableGroupView(ListViewHandle, TRUE); + PhAddListViewGroup(ListViewHandle, DOTNET_CATEGORY_EXCEPTIONS, L".NET CLR Exceptions"); + PhAddListViewGroup(ListViewHandle, DOTNET_CATEGORY_INTEROP, L".NET CLR Interop"); + PhAddListViewGroup(ListViewHandle, DOTNET_CATEGORY_JIT, L".NET CLR Jit"); + PhAddListViewGroup(ListViewHandle, DOTNET_CATEGORY_LOADING, L".NET CLR Loading"); + PhAddListViewGroup(ListViewHandle, DOTNET_CATEGORY_LOCKSANDTHREADS, L".NET CLR LocksAndThreads"); + PhAddListViewGroup(ListViewHandle, DOTNET_CATEGORY_MEMORY, L".NET CLR Memory"); + PhAddListViewGroup(ListViewHandle, DOTNET_CATEGORY_REMOTING, L".NET CLR Remoting"); + PhAddListViewGroup(ListViewHandle, DOTNET_CATEGORY_SECURITY, L".NET CLR Security"); + + // This counter displays the total number of exceptions thrown since the start of the application. + // These include both .NET exceptions and unmanaged exceptions that get converted into .NET exceptions e.g. null pointer reference exception in unmanaged code + // would get re-thrown in managed code as a .NET System.NullReferenceException; this counter includes both handled and unhandled exceptions.Exceptions + // that are re-thrown would get counted again. Exceptions should only occur in rare situations and not in the normal control flow of the program. + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_EXCEPTIONS, DOTNET_INDEX_EXCEPTIONS_THROWNCOUNT, L"# of Exceps Thrown", NULL); + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_EXCEPTIONS, DOTNET_INDEX_EXCEPTIONS_FILTERSCOUNT, L"# of Filters Executed", NULL); + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_EXCEPTIONS, DOTNET_INDEX_EXCEPTIONS_FINALLYCOUNT, L"# of Finallys Executed", NULL); + + // Reserved for future use. + //PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_EXCEPTIONS, , L"Delta from throw to catch site on stack", NULL); + + // # of Exceps Thrown / sec + // This counter displays the number of exceptions thrown per second. + // These include both .NET exceptions and unmanaged exceptions that get converted into .NET exceptions e.g.null pointer reference exception in unmanaged code would get + // re-thrown in managed code as a .NET System.NullReferenceException; this counter includes both handled and unhandled exceptions. + // Exceptions should only occur in rare situations and not in the normal control flow of the program; + // this counter was designed as an indicator of potential performance problems due to large (> 100s) rate of exceptions thrown. + // This counter is not an average over time; it displays the difference between the values observed in the last two samples divided by the duration of the sample interval. + // TODO: We need to count the delta. + + // # of Filters / sec + // This counter displays the number of.NET exception filters executed per second.An exception filter evaluates whether an exception should be handled or not. + // This counter tracks the rate of exception filters evaluated; irrespective of whether the exception was handled or not. + // This counter is not an average over time; it displays the difference between the values observed in the last two samples divided by the duration of the sample interval. + // TODO: We need to count the delta. + + // # of Finallys / sec + // This counter displays the number of finally blocks executed per second. + // A finally block is guaranteed to be executed regardless of how the try block was exited. + // Only the finally blocks that are executed for an exception are counted; finally blocks on normal code paths are not counted by this counter. + // This counter is not an average over time; it displays the difference between the values observed in the last two samples divided by the duration of the sample interval. + // TODO: We need to count the delta. + + // Throw To Catch Depth / sec + // This counter displays the number of stack frames traversed from the frame that threw the .NET exception to the frame that handled the exception per second. + // This counter resets to 0 when an exception handler is entered; so nested exceptions would show the handler to handler stack depth. + // This counter is not an average over time; it displays the difference between the values observed in the last two samples divided by the duration of the sample interval. + // TODO: We need to count the delta. + + // This counter displays the current number of Com-Callable-Wrappers (CCWs). + // A CCW is a proxy for the .NET managed object being referenced from unmanaged COM client(s). + // This counter was designed to indicate the number of managed objects being referenced by unmanaged COM code. + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_INTEROP, DOTNET_INDEX_INTEROP_CCWCOUNT, L"# of CCWs", NULL); + + // This counter displays the current number of stubs created by the CLR. + // Stubs are responsible for marshalling arguments and return values from managed to unmanaged code and vice versa; during a COM Interop call or PInvoke call. + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_INTEROP, DOTNET_INDEX_INTEROP_STUBCOUNT, L"# of Stubs", NULL); + + // This counter displays the total number of times arguments and return values have been marshaled from managed to unmanaged code + // and vice versa since the start of the application. This counter is not incremented if the stubs are inlined. + // (Stubs are responsible for marshalling arguments and return values). Stubs usually get inlined if the marshalling overhead is small. + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_INTEROP, DOTNET_INDEX_INTEROP_MARSHALCOUNT, L"# of Marshalling", NULL); + + // Reserved for future use. + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_INTEROP, DOTNET_INDEX_INTEROP_TLBIMPORTPERSEC, L"# of TLB imports / sec", NULL); + + // Reserved for future use. + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_INTEROP, DOTNET_INDEX_INTEROP_TLBEXPORTPERSEC, L"# of TLB exports / sec", NULL); + + // This counter displays the total number of methods compiled Just-In-Time (JIT) by the CLR JIT compiler since the start of the application. + // This counter does not include the pre-jitted methods. + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_JIT, DOTNET_INDEX_JIT_ILMETHODSJITTED, L"# of Methods Jitted", NULL); + + // This counter displays the total IL bytes jitted since the start of the application. + // This counter is exactly equivalent to the "Total # of IL Bytes Jitted" counter. + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_JIT, DOTNET_INDEX_JIT_ILBYTESJITTED, L"# of IL Bytes Jitted", NULL); + + // This counter displays the total IL bytes jitted since the start of the application. + // This counter is exactly equivalent to the "# of IL Bytes Jitted" counter. + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_JIT, DOTNET_INDEX_JIT_ILTOTALBYTESJITTED, L"Total # of IL Bytes Jitted", NULL); + + // This counter displays the peak number of methods the JIT compiler has failed to JIT since the start of the application. + // This failure can occur if the IL cannot be verified or if there was an internal error in the JIT compiler. + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_JIT, DOTNET_INDEX_JIT_FAILURES, L"Jit Failures", NULL); + + // This counter displays the percentage of elapsed time spent in JIT compilation since the last JIT compilation phase. + // This counter is updated at the end of every JIT compilation phase. A JIT compilation phase is the phase when a method and its dependencies are being compiled. + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_JIT, DOTNET_INDEX_JIT_TIME, L"% Time in Jit", NULL); + + // IL Bytes Jitted / sec + // This counter displays the rate at which IL bytes are jitted per second. + // This counter is not an average over time; it displays the difference between the values observed in the last two samples divided by the duration of the sample interval. + // TODO: We need to count the delta. + + // This counter displays the current number of classes loaded in all Assemblies. + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_LOADING, DOTNET_INDEX_LOADING_CURRENTLOADED, L"Current Classes Loaded", NULL); + + // This counter displays the cumulative number of classes loaded in all Assemblies since the start of this application. + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_LOADING, DOTNET_INDEX_LOADING_TOTALLOADED, L"Total Classes Loaded", NULL); + + // This counter displays the current number of AppDomains loaded in this application. + // AppDomains (application domains) provide a secure and versatile unit of processing that the CLR can use to provide isolation between applications running in the same process. + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_LOADING, DOTNET_INDEX_LOADING_CURRENTAPPDOMAINS, L"Current Appdomains", NULL); + + // This counter displays the peak number of AppDomains loaded since the start of this application. + // AppDomains (application domains) provide a secure and versatile unit of processing that the CLR can use to provide isolation between applications running in the same process. + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_LOADING, DOTNET_INDEX_LOADING_TOTALAPPDOMAINS, L"Total Appdomains", NULL); + + // This counter displays the current number of Assemblies loaded across all AppDomains in this application. + // If the Assembly is loaded as domain - neutral from multiple AppDomains then this counter is incremented once only. + // Assemblies can be loaded as domain - neutral when their code can be shared by all AppDomains or they can be loaded as domain - specific when their code is private to the AppDomain. + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_LOADING, DOTNET_INDEX_LOADING_CURRENTASSEMBLIES, L"Current Assemblies", NULL); + + // This counter displays the total number of Assemblies loaded since the start of this application. + // If the Assembly is loaded as domain - neutral from multiple AppDomains then this counter is incremented once only. + // Assemblies can be loaded as domain - neutral when their code can be shared by all AppDomains or they can be loaded as domain - specific when their code is private to the AppDomain. + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_LOADING, DOTNET_INDEX_LOADING_TOTALASSEMBLIES, L"Total Assemblies", NULL); + + // Reserved for future use. + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_LOADING, DOTNET_INDEX_LOADING_ASSEMBLYSEARCHLENGTH, L"Assembly Search Length", NULL); + + // This counter displays the peak number of classes that have failed to load since the start of the application. + // These load failures could be due to many reasons like inadequate security or illegal format.Full details can be found in the profiling services help. + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_LOADING, DOTNET_INDEX_LOADING_TOTALLOADFAILURES, L"Total # of Load Failures", NULL); + + // This counter displays the current size(in bytes) of the memory committed by the class loader across all AppDomains. + // (Committed memory is the physical memory for which space has been reserved on the disk paging file.) + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_LOADING, DOTNET_INDEX_LOADING_BYTESINLOADERHEAP, L"Bytes in Loader Heap", NULL); + + // This counter displays the total number of AppDomains unloaded since the start of the application. + //If an AppDomain is loaded and unloaded multiple times this counter would count each of those unloads as separate. + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_LOADING, DOTNET_INDEX_LOADING_TOTALAPPDOMAINSUNLOADED, L"Total Appdomains Unloaded", NULL); + + // Reserved for future use. + //PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_LOADING, , L"% Time Loading", NULL); + + // Rate of Load Failures + // This counter displays the number of classes that failed to load per second. + // This counter is not an average over time; it displays the difference between the values observed in the last two samples divided by the duration of the sample interval. + // These load failures could be due to many reasons like inadequate security or illegal format. Full details can be found in the profiling services help. + // TODO: We need to count the delta. + + // Rate of appdomains unloaded + // This counter displays the number of AppDomains unloaded per second. + // This counter is not an average over time; it displays the difference between the values observed in the last two samples divided by the duration of the sample interval. + // TODO: We need to count the delta. + + // Rate of Classes Loaded + // This counter displays the number of classes loaded per second in all Assemblies. + // This counter is not an average over time; it displays the difference between the values observed in the last two samples divided by the duration of the sample interval. + // TODO: We need to count the delta. + + // Rate of appdomains + // This counter displays the number of AppDomains loaded per second. + // AppDomains(application domains) provide a secure and versatile unit of processing that the CLR can use to provide isolation between applications + // running in the same process. This counter is not an average over time; it displays the difference between the values observed in the last two samples + // divided by the duration of the sample interval. + // TODO: We need to count the delta. + + // Rate of Assemblies + // This counter displays the number of Assemblies loaded across all AppDomains per second. + // If the Assembly is loaded as domain - neutral from multiple AppDomains then this counter is incremented once only.Assemblies can be loaded as + // domain - neutral when their code can be shared by all AppDomains or they can be loaded as domain - specific when their code is private to the AppDomain. + // This counter is not an average over time; it displays the difference between the values observed in the last two samples divided by the duration of the sample interval. + // TODO: We need to count the delta. + + // This counter displays the total number of times threads in the CLR have attempted to acquire a managed lock unsuccessfully. + // Managed locks can be acquired in many ways; by the "lock" statement in C# or by calling System.Monitor.Enter or by using MethodImplOptions.Synchronized custom attribute. + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_LOCKSANDTHREADS, DOTNET_INDEX_LOCKSANDTHREADS_TOTALLOCKS, L"Total # of Contentions", NULL); + + // This counter displays the total number of threads currently waiting to acquire some managed lock in the application. + // This counter is not an average over time; it displays the last observed value. + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_LOCKSANDTHREADS, DOTNET_INDEX_LOCKSANDTHREADS_TOTALQUEUELENGTH, L"Current Queue Length", NULL); + + // This counter displays the total number of threads that waited to acquire some managed lock since the start of the application. + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_LOCKSANDTHREADS, DOTNET_INDEX_LOCKSANDTHREADS_QUEUELENGTHPEAK, L"Queue Length Peak", NULL); + + // This counter displays the number of current.NET thread objects in the application. + // A.NET thread object is created either by new System.Threading.Thread or when an unmanaged thread enters the managed environment. + // This counters maintains the count of both running and stopped threads. This counter is not an average over time; it just displays the last observed value. + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_LOCKSANDTHREADS, DOTNET_INDEX_LOCKSANDTHREADS_CURRENTLOGICAL, L"# of Current Logical Threads", NULL); + + // This counter displays the number of native OS threads created and owned by the CLR to act as underlying threads for .NET thread objects. + // This counters value does not include the threads used by the CLR in its internal operations; it is a subset of the threads in the OS process. + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_LOCKSANDTHREADS, DOTNET_INDEX_LOCKSANDTHREADS_CURRENTPHYSICAL, L"# of Current Physical Threads", NULL); + + // This counter displays the number of threads that are currently recognized by the CLR; they have a corresponding .NET thread object associated with them. + // These threads are not created by the CLR; they are created outside the CLR but have since run inside the CLR at least once. + // Only unique threads are tracked; threads with same thread ID re-entering the CLR or recreated after thread exit are not counted twice. + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_LOCKSANDTHREADS, DOTNET_INDEX_LOCKSANDTHREADS_CURRENTRECOGNIZED, L"# of Current Recognized Threads", NULL); + + // This counter displays the total number of threads that have been recognized by the CLR since the start of this application; + // these threads have a corresponding .NET thread object associated with them. + // These threads are not created by the CLR; they are created outside the CLR but have since run inside the CLR at least once. + // Only unique threads are tracked; threads with same thread ID re-entering the CLR or recreated after thread exit are not counted twice. + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_LOCKSANDTHREADS, DOTNET_INDEX_LOCKSANDTHREADS_TOTALRECOGNIZED, L"# of Total Recognized Threads", NULL); + + // Contention Rate / sec + // Rate at which threads in the runtime attempt to acquire a managed lock unsuccessfully. + // Managed locks can be acquired in many ways; by the "lock" statement in C# or by calling System.Monitor.Enter or by using MethodImplOptions.Synchronized custom attribute. + // TODO: We need to count the delta. + + // Queue Length / sec + // This counter displays the number of threads per second waiting to acquire some lock in the application. + // This counter is not an average over time; it displays the difference between the values observed in the last two samples divided by the duration of the sample interval. + // TODO: We need to count the delta. + + // rate of recognized threads / sec + // This counter displays the number of threads per second that have been recognized by the CLR; these threads have a corresponding .NET thread object associated with them. + // These threads are not created by the CLR; they are created outside the CLR but have since run inside the CLR at least once. + // Only unique threads are tracked; threads with same thread ID re-entering the CLR or recreated after thread exit are not counted twice. + // This counter is not an average over time; it displays the difference between the values observed in the last two samples divided by the duration of the sample interval. + // TODO: We need to count the delta. + + // This counter displays the number of times the generation 0 objects (youngest; most recently allocated) are garbage collected (Gen 0 GC) since the start of the application. + // Gen 0 GC occurs when the available memory in generation 0 is not sufficient to satisfy an allocation request. + // This counter is incremented at the end of a Gen 0 GC. Higher generation GCs include all lower generation GCs. + // This counter is explicitly incremented when a higher generation (Gen 1 or Gen 2) GC occurs. _Global_ counter value is not accurate and should be ignored. + // This counter displays the last observed value. + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_MEMORY, DOTNET_INDEX_MEMORY_GENZEROCOLLECTIONS, L"# Gen 0 Collections", NULL); + + // This counter displays the number of times the generation 1 objects are garbage collected since the start of the application. + // The counter is incremented at the end of a Gen 1 GC. Higher generation GCs include all lower generation GCs. + // This counter is explicitly incremented when a higher generation (Gen 2) GC occurs. _Global_ counter value is not accurate and should be ignored. + // This counter displays the last observed value. + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_MEMORY, DOTNET_INDEX_MEMORY_GENONECOLLECTIONS, L"# Gen 1 Collections", NULL); + + // This counter displays the number of times the generation 2 objects(older) are garbage collected since the start of the application. + // The counter is incremented at the end of a Gen 2 GC(also called full GC)._Global_ counter value is not accurate and should be ignored. + // This counter displays the last observed value. + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_MEMORY, DOTNET_INDEX_MEMORY_GENTWOCOLLECTIONS, L"# Gen 2 Collections", NULL); + + // This counter displays the bytes of memory that survive garbage collection(GC) and are promoted from generation 0 to generation 1; + // objects that are promoted just because they are waiting to be finalized are not included in this counter. + // This counter displays the value observed at the end of the last GC; its not a cumulative counter. + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_MEMORY, DOTNET_INDEX_MEMORY_PROMOTEDFROMGENZERO, L"Promoted Memory from Gen 0", NULL); + + // This counter displays the bytes of memory that survive garbage collection(GC) and are promoted from generation 1 to generation 2; + // objects that are promoted just because they are waiting to be finalized are not included in this counter. + // This counter displays the value observed at the end of the last GC; its not a cumulative counter. + // This counter is reset to 0 if the last GC was a Gen 0 GC only. + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_MEMORY, DOTNET_INDEX_MEMORY_PROMOTEDFROMGENONE, L"Promoted Memory from Gen 1", NULL); + + // This counter displays the bytes of memory that are promoted from generation 0 to generation 1 just because they are waiting to be finalized. + // This counter displays the value observed at the end of the last GC; its not a cumulative counter. + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_MEMORY, DOTNET_INDEX_MEMORY_PROMOTEDFINALFROMGENZERO, L"Promoted Finalization-Memory from Gen 0", NULL); + + // Reserved for future use. + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_MEMORY, DOTNET_INDEX_MEMORY_PROCESSID, L"Process ID", NULL); + + // This counter displays the maximum bytes that can be allocated in generation 0 (Gen 0); + // its does not indicate the current number of bytes allocated in Gen 0. + // A Gen 0 GC is triggered when the allocations since the last GC exceed this size. + // The Gen 0 size is tuned by the Garbage Collector and can change during the execution of the application. + // At the end of a Gen 0 collection the size of the Gen 0 heap is infact 0 bytes; this counter displays the size(in bytes) of allocations that would trigger + // the next Gen 0 GC.This counter is updated at the end of a GC; its not updated on every allocation. + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_MEMORY, DOTNET_INDEX_MEMORY_GENZEROHEAPSIZE, L"Gen 0 Heap Size", NULL); + + // This counter displays the current number of bytes in generation 1 (Gen 1); + // this counter does not display the maximum size of Gen 1. Objects are not directly allocated in this generation; + // they are promoted from previous Gen 0 GCs.This counter is updated at the end of a GC; its not updated on every allocation. + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_MEMORY, DOTNET_INDEX_MEMORY_GENONEHEAPSIZE, L"Gen 1 Heap Size", NULL); + + // This counter displays the current number of bytes in generation 2 (Gen 2). + // Objects are not directly allocated in this generation; they are promoted from Gen 1 during previous Gen 1 GCs. + // This counter is updated at the end of a GC; its not updated on every allocation. + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_MEMORY, DOTNET_INDEX_MEMORY_GENTWOHEAPSIZE, L"Gen 2 Heap Size", NULL); + + // This counter displays the current size of the Large Object Heap in bytes. + // Objects greater than 20 KBytes are treated as large objects by the Garbage Collector and are directly allocated in a special heap; they are not promoted through the generations. + // This counter is updated at the end of a GC; its not updated on every allocation. + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_MEMORY, DOTNET_INDEX_MEMORY_LOHSIZE, L"Large Object Heap Size", NULL); + + // This counter displays the number of garbage collected objects that survive a collection because they are waiting to be finalized. + // If these objects hold references to other objects then those objects also survive but are not counted by this counter; the "Promoted Finalization-Memory from Gen 0" + // and "Promoted Finalization-Memory from Gen 1" counters represent all the memory that survived due to finalization. + // This counter is not a cumulative counter; its updated at the end of every GC with count of the survivors during that particular GC only. + // This counter was designed to indicate the extra overhead that the application might incur because of finalization. + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_MEMORY, DOTNET_INDEX_MEMORY_FINALSURVIVORS, L"Finalization Survivors", NULL); + + // This counter displays the current number of GC Handles in-use. + // GCHandles are handles to resources external to the CLR and the managed environment. + // Handles occupy small amounts of memory in the GCHeap but potentially expensive unmanaged resources. + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_MEMORY, DOTNET_INDEX_MEMORY_GCHANDLES, L"# GC Handles", NULL); + + // This counter displays the peak number of times a garbage collection was performed because of an explicit call to GC.Collect. + // Its a good practice to let the GC tune the frequency of its collections. + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_MEMORY, DOTNET_INDEX_MEMORY_INDUCEDGC, L"# Induced GC", NULL); + + // % Time in GC is the percentage of elapsed time that was spent in performing a garbage collection(GC) since the last GC cycle. + // This counter is usually an indicator of the work done by the Garbage Collector on behalf of the application to collect and compact memory. + // This counter is updated only at the end of every GC and the counter value reflects the last observed value; its not an average. + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_MEMORY, DOTNET_INDEX_MEMORY_TIMEINGC, L"% Time in GC", NULL); + + // This counter is the sum of four other counters; Gen 0 Heap Size; Gen 1 Heap Size; Gen 2 Heap Size and the Large Object Heap Size. + // This counter indicates the current memory allocated in bytes on the GC Heaps. + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_MEMORY, DOTNET_INDEX_MEMORY_BYTESINALLHEAPS, L"# Bytes in all Heaps", NULL); + + // This counter displays the amount of virtual memory(in bytes) currently committed by the Garbage Collector. + // (Committed memory is the physical memory for which space has been reserved on the disk paging file). + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_MEMORY, DOTNET_INDEX_MEMORY_TOTALCOMMITTED, L"# Total Committed Bytes", NULL); + + // This counter displays the amount of virtual memory(in bytes) currently reserved by the Garbage Collector. + // (Reserved memory is the virtual memory space reserved for the application but no disk or main memory pages have been used.) + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_MEMORY, DOTNET_INDEX_MEMORY_TOTALRESERVED, L"# Total Reserved Bytes", NULL); + + // This counter displays the number of pinned objects encountered in the last GC. + // This counter tracks the pinned objects only in the heaps that were garbage collected e.g. A Gen 0 GC would cause enumeration of pinned objects in the generation 0 heap only. + // A pinned object is one that the Garbage Collector cannot move in memory. + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_MEMORY, DOTNET_INDEX_MEMORY_TOTALPINNED, L"# of Pinned Objects", NULL); + + // This counter displays the current number of sync blocks in use. Sync blocks are per-object data structures allocated for storing synchronization information. + // Sync blocks hold weak references to managed objects and need to be scanned by the Garbage Collector. + // Sync blocks are not limited to storing synchronization information and can also store COM interop metadata. + // This counter was designed to indicate performance problems with heavy use of synchronization primitives. + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_MEMORY, DOTNET_INDEX_MEMORY_TOTALSINKS, L"# of Sink Blocks in use", NULL); + + // Reserved for future use. + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_MEMORY, DOTNET_INDEX_MEMORY_TOTALBYTESSINCESTART, L"Total Bytes Allocated (since start)", NULL); + + // Reserved for future use. + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_MEMORY, DOTNET_INDEX_MEMORY_TOTALLOHBYTESSINCESTART, L"Total Bytes Allocated for Large Objects (since start)", NULL); + + // Gen 0 Promoted Bytes / Sec + // This counter displays the bytes per second that are promoted from generation 0 (youngest)to generation 1; + // objects that are promoted just because they are waiting to be finalized are not included in this counter. + // Memory is promoted when it survives a garbage collection.This counter was designed as an indicator of relatively long-lived objects being created per sec. + // This counter displays the difference between the values observed in the last two samples divided by the duration of the sample interval. + // TODO: We need to count the delta. + + // Gen 1 Promoted Bytes / Sec + // This counter displays the bytes per second that are promoted from generation 1 to generation 2 (oldest); + // objects that are promoted just because they are waiting to be finalized are not included in this counter. + // Memory is promoted when it survives a garbage collection. + // Nothing is promoted from generation 2 since it is the oldest. + // This counter was designed as an indicator of very long-lived objects being created per sec. + // This counter displays the difference between the values observed in the last two samples divided by the duration of the sample interval. + // TODO: We need to count the delta. + + // Promoted Finalization - Memory from Gen 1 + // This counter displays the bytes of memory that are promoted from generation 1 to generation 2 just because they are waiting to be finalized. + // This counter displays the value observed at the end of the last GC; its not a cumulative counter.This counter is reset to 0 if the last GC was a Gen 0 GC only. + // TODO: We need to count the delta. + + // Allocated Bytes / sec + // This counter displays the rate of bytes per second allocated on the GC Heap. + // This counter is updated at the end of every GC; not at each allocation. + // This counter is not an average over time; it displays the difference between the values observed in the last two samples divided by the duration of the sample interval. + // TODO: We need to count the delta. + + // This counter displays the total number of remote procedure calls invoked since the start of this application. + // A remote procedure call is a call on any object outside the callers AppDomain. + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_REMOTING, DOTNET_INDEX_REMOTING_TOTALREMOTECALLS, L"Total Remote Calls", NULL); + + // This counter displays the total number of remoting channels registered across all AppDomains since the start of the application. + // Channels are used to transport messages to and from remote objects. + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_REMOTING, DOTNET_INDEX_REMOTING_CHANNELS, L"Channels", NULL); + + // This counter displays the total number of remoting proxy objects created in this process since the start of the process. + // Proxy object acts as a representative of the remote objects and ensures that all calls made on the proxy are forwarded to the correct remote object instance. + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_REMOTING, DOTNET_INDEX_REMOTING_CONTEXTPROXIES, L"Context Proxies", NULL); + + // This counter displays the current number of context-bound classes loaded. + // Classes that can be bound to a context are called context-bound classes; context-bound classes are marked with Context Attributes + // which provide usage rules for synchronization; thread affinity; transactions etc. + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_REMOTING, DOTNET_INDEX_REMOTING_CONTEXTCLASSESLOADED, L"Context-Bound Classes Loaded", NULL); + + // This counter displays the current number of remoting contexts in the application. + // A context is a boundary containing a collection of objects with the same usage rules like synchronization; thread affinity; transactions etc. + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_REMOTING, DOTNET_INDEX_REMOTING_CONTEXTS, L"Contexts", NULL); + + // Reserved for future use. + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_REMOTING, DOTNET_INDEX_REMOTING_CONTEXTSALLOCATED, L"# of context bound objects allocated", NULL); + + // Remote Calls / sec + // This counter displays the number of remote procedure calls invoked per second. + // A remote procedure call is a call on any object outside the callers AppDomain. + // This counter is not an average over time; it displays the difference between the values observed in the last two samples divided by the duration of the sample interval. + // TODO: We need to count the delta. + + // Context - Bound Objects Alloc / sec + // This counter displays the number of context - bound objects allocated per second. + // Instances of classes that can be bound to a context are called context - bound objects; context - bound classes are marked with Context Attributes + // which provide usage rules for synchronization; thread affinity; transactions etc. + // This counter is not an average over time; it displays the difference between the values observed in the last two samples divided by the duration of the sample interval. + // TODO: We need to count the delta. + + // This counter displays the total number of runtime Code Access Security(CAS) checks performed since the start of the application. + // Runtime CAS checks are performed when a caller makes a call to a callee demanding a particular permission; + // the runtime check is made on every call by the caller; the check is done by examining the current thread stack of the caller. + // This counter used together with "Stack Walk Depth" is indicative of performance penalty for security checks. + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_SECURITY, DOTNET_INDEX_SECURITY_TOTALRUNTIMECHECKS, L"Total Runtime Checks", NULL); + + // This counter displays the total number of linktime Code Access Security(CAS) checks since the start of the application. + // Linktime CAS checks are performed when a caller makes a call to a callee demanding a particular permission at JIT compile time; linktime check is performed once per caller. + // This count is not indicative of serious performance issues; its indicative of the security system activity. + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_SECURITY, DOTNET_INDEX_SECURITY_LINKTIMECHECKS, L"# Link Time Checks", NULL); + + // This counter displays the percentage of elapsed time spent in performing runtime Code Access Security(CAS) checks since the last such check. + // CAS allows code to be trusted to varying degrees and enforces these varying levels of trust depending on code identity. + // This counter is updated at the end of a runtime security check; it represents the last observed value; its not an average. + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_SECURITY, DOTNET_INDEX_SECURITY_TIMEINRTCHECKS, L"% Time in RT checks", NULL); + + // This counter displays the depth of the stack during that last runtime Code Access Security check. + // Runtime Code Access Security check is performed by crawling the stack. + // This counter is not an average; it just displays the last observed value. + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_SECURITY, DOTNET_INDEX_SECURITY_STACKWALKDEPTH, L"Stack Walk Depth", NULL); + + // % Time Sig.Authenticating + // Reserved for future use. } -VOID AddProcessAppDomains( +VOID DotNetPerfAddProcessAppDomains( _In_ HWND hwndDlg, _In_ PPERFPAGE_CONTEXT Context ) { - SendMessage(Context->AppDomainsLv, WM_SETREDRAW, FALSE, 0); + ExtendedListView_SetRedraw(Context->AppDomainsLv, FALSE); ListView_DeleteAllItems(Context->AppDomainsLv); if (Context->ClrV4) @@ -440,10 +632,10 @@ VOID AddProcessAppDomains( } } - SendMessage(Context->AppDomainsLv, WM_SETREDRAW, TRUE, 0); + ExtendedListView_SetRedraw(Context->AppDomainsLv, TRUE); } -VOID UpdateCounterData( +VOID DotNetPerfUpdateCounterData( _In_ HWND hwndDlg, _In_ PPERFPAGE_CONTEXT Context ) @@ -548,153 +740,129 @@ VOID UpdateCounterData( dotNetPerfSecurity = perfBlock->Security; } - switch (Context->CategoryIndex) - { - case DOTNET_CATEGORY_EXCEPTIONS: - { - PhSetListViewSubItem(Context->CountersLv, 0, 1, PhaFormatUInt64(dotNetPerfExcep.cThrown.Total, TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, 1, 1, PhaFormatUInt64(dotNetPerfExcep.cFiltersExecuted, TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, 2, 1, PhaFormatUInt64(dotNetPerfExcep.cFinallysExecuted, TRUE)->Buffer); - //PhSetListViewSubItem(Context->CountersLv, 3, 1, PhaFormatUInt64(dotNetPerfExcep.cThrowToCatchStackDepth, TRUE)->Buffer); - } - break; - case DOTNET_CATEGORY_INTEROP: - { - PhSetListViewSubItem(Context->CountersLv, 0, 1, PhaFormatUInt64(dotNetPerfInterop.cCCW, TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, 1, 1, PhaFormatUInt64(dotNetPerfInterop.cStubs, TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, 2, 1, PhaFormatUInt64(dotNetPerfInterop.cMarshalling, TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, 3, 1, PhaFormatUInt64(dotNetPerfInterop.cTLBImports, TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, 4, 1, PhaFormatUInt64(dotNetPerfInterop.cTLBExports, TRUE)->Buffer); - } - break; - case DOTNET_CATEGORY_JIT: - { - PhSetListViewSubItem(Context->CountersLv, 0, 1, PhaFormatUInt64(dotNetPerfJit.cMethodsJitted, TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, 1, 1, FormatByteValue(Context, dotNetPerfJit.cbILJitted.Current)->Buffer); - PhSetListViewSubItem(Context->CountersLv, 2, 1, FormatByteValue(Context, dotNetPerfJit.cbILJitted.Total)->Buffer); - PhSetListViewSubItem(Context->CountersLv, 3, 1, PhaFormatUInt64(dotNetPerfJit.cJitFailures, TRUE)->Buffer); + PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_EXCEPTIONS_THROWNCOUNT, 1, PhaFormatUInt64(dotNetPerfExcep.cThrown.Total, TRUE)->Buffer); + PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_EXCEPTIONS_FILTERSCOUNT, 1, PhaFormatUInt64(dotNetPerfExcep.cFiltersExecuted, TRUE)->Buffer); + PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_EXCEPTIONS_FINALLYCOUNT, 1, PhaFormatUInt64(dotNetPerfExcep.cFinallysExecuted, TRUE)->Buffer); + //PhSetListViewSubItem(Context->CountersLv, , 1, PhaFormatUInt64(dotNetPerfExcep.cThrowToCatchStackDepth, TRUE)->Buffer); - if (dotNetPerfJit.timeInJitBase != 0) - { - PH_FORMAT format; - WCHAR formatBuffer[10]; + PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_INTEROP_CCWCOUNT, 1, PhaFormatUInt64(dotNetPerfInterop.cCCW, TRUE)->Buffer); + PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_INTEROP_STUBCOUNT, 1, PhaFormatUInt64(dotNetPerfInterop.cStubs, TRUE)->Buffer); + PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_INTEROP_MARSHALCOUNT, 1, PhaFormatUInt64(dotNetPerfInterop.cMarshalling, TRUE)->Buffer); + PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_INTEROP_TLBIMPORTPERSEC, 1, PhaFormatUInt64(dotNetPerfInterop.cTLBImports, TRUE)->Buffer); + PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_INTEROP_TLBEXPORTPERSEC, 1, PhaFormatUInt64(dotNetPerfInterop.cTLBExports, TRUE)->Buffer); - // TODO: TimeInJit is always above 100% for some processes ?? - // SeeAlso: https://github.com/dotnet/coreclr/blob/master/src/gc/gcee.cpp#L324 - PhInitFormatF(&format, (dotNetPerfJit.timeInJit << 8) * 100 / (FLOAT)(dotNetPerfJit.timeInJitBase << 8), 2); + PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_JIT_ILMETHODSJITTED, 1, PhaFormatUInt64(dotNetPerfJit.cMethodsJitted, TRUE)->Buffer); + PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_JIT_ILBYTESJITTED, 1, PhaFormatSize(dotNetPerfJit.cbILJitted.Current, ULONG_MAX)->Buffer); + PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_JIT_ILTOTALBYTESJITTED, 1, PhaFormatSize(dotNetPerfJit.cbILJitted.Total, ULONG_MAX)->Buffer); + PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_JIT_FAILURES, 1, PhaFormatUInt64(dotNetPerfJit.cJitFailures, TRUE)->Buffer); - if (PhFormatToBuffer(&format, 1, formatBuffer, sizeof(formatBuffer), NULL)) - PhSetListViewSubItem(Context->CountersLv, 4, 1, formatBuffer); - } - else - { - PhSetListViewSubItem(Context->CountersLv, 4, 1, L"0.00"); - } - } - break; - case DOTNET_CATEGORY_LOADING: - { - PhSetListViewSubItem(Context->CountersLv, 0, 1, PhaFormatUInt64(dotNetPerfLoading.cClassesLoaded.Current, TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, 1, 1, PhaFormatUInt64(dotNetPerfLoading.cClassesLoaded.Total, TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, 2, 1, PhaFormatUInt64(dotNetPerfLoading.cAppDomains.Current, TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, 3, 1, PhaFormatUInt64(dotNetPerfLoading.cAppDomains.Total, TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, 4, 1, PhaFormatUInt64(dotNetPerfLoading.cAssemblies.Current, TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, 5, 1, PhaFormatUInt64(dotNetPerfLoading.cAssemblies.Total, TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, 6, 1, PhaFormatUInt64(dotNetPerfLoading.cAsmSearchLen, TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, 7, 1, PhaFormatUInt64(dotNetPerfLoading.cLoadFailures.Total, TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, 8, 1, FormatByteValue(Context, dotNetPerfLoading.cbLoaderHeapSize)->Buffer); - PhSetListViewSubItem(Context->CountersLv, 9, 1, PhaFormatUInt64(dotNetPerfLoading.cAppDomainsUnloaded.Total, TRUE)->Buffer); - //PhSetListViewSubItem(Context->CountersLv, 10, 1, PhaFormatUInt64(dotNetPerfLoading.timeLoading, TRUE)->Buffer); - } - break; - case DOTNET_CATEGORY_LOCKSANDTHREADS: - { - PhSetListViewSubItem(Context->CountersLv, 0, 1, PhaFormatUInt64(dotNetPerfLocksAndThreads.cContention.Total, TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, 1, 1, PhaFormatUInt64(dotNetPerfLocksAndThreads.cQueueLength.Current, TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, 2, 1, PhaFormatUInt64(dotNetPerfLocksAndThreads.cQueueLength.Total, TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, 3, 1, PhaFormatUInt64(dotNetPerfLocksAndThreads.cCurrentThreadsLogical, TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, 4, 1, PhaFormatUInt64(dotNetPerfLocksAndThreads.cCurrentThreadsPhysical, TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, 5, 1, PhaFormatUInt64(dotNetPerfLocksAndThreads.cRecognizedThreads.Current, TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, 6, 1, PhaFormatUInt64(dotNetPerfLocksAndThreads.cRecognizedThreads.Total, TRUE)->Buffer); - } - break; - case DOTNET_CATEGORY_MEMORY: - { - PhSetListViewSubItem(Context->CountersLv, 0, 1, PhaFormatUInt64(dotNetPerfGC.cGenCollections[0], TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, 1, 1, PhaFormatUInt64(dotNetPerfGC.cGenCollections[1], TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, 2, 1, PhaFormatUInt64(dotNetPerfGC.cGenCollections[2], TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, 3, 1, FormatByteValue(Context, dotNetPerfGC.cbPromotedMem[0])->Buffer); - PhSetListViewSubItem(Context->CountersLv, 4, 1, FormatByteValue(Context, dotNetPerfGC.cbPromotedMem[1])->Buffer); - PhSetListViewSubItem(Context->CountersLv, 5, 1, FormatByteValue(Context, dotNetPerfGC.cbPromotedFinalizationMem)->Buffer); - PhSetListViewSubItem(Context->CountersLv, 6, 1, PhaFormatUInt64(dotNetPerfGC.cProcessID, FALSE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, 7, 1, FormatByteValue(Context, dotNetPerfGC.cGenHeapSize[0])->Buffer); - PhSetListViewSubItem(Context->CountersLv, 8, 1, FormatByteValue(Context, dotNetPerfGC.cGenHeapSize[1])->Buffer); - PhSetListViewSubItem(Context->CountersLv, 9, 1, FormatByteValue(Context, dotNetPerfGC.cGenHeapSize[2])->Buffer); - PhSetListViewSubItem(Context->CountersLv, 10, 1, FormatByteValue(Context, dotNetPerfGC.cLrgObjSize)->Buffer); - PhSetListViewSubItem(Context->CountersLv, 11, 1, PhaFormatUInt64(dotNetPerfGC.cSurviveFinalize, TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, 12, 1, PhaFormatUInt64(dotNetPerfGC.cHandles, TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, 13, 1, PhaFormatUInt64(dotNetPerfGC.cInducedGCs, TRUE)->Buffer); - - if (dotNetPerfGC.timeInGCBase != 0) - { - PH_FORMAT format; - WCHAR formatBuffer[10]; + if (dotNetPerfJit.timeInJitBase != 0) + { + PH_FORMAT format[1]; + WCHAR formatBuffer[10]; - PhInitFormatF(&format, (FLOAT)dotNetPerfGC.timeInGC * 100 / (FLOAT)dotNetPerfGC.timeInGCBase, 2); + // TODO: TimeInJit is always above 100% for some processes ?? + // SeeAlso: https://github.com/dotnet/coreclr/blob/master/src/gc/gcee.cpp#L324 + PhInitFormatF(&format[0], (dotNetPerfJit.timeInJit << 8) * 100 / (FLOAT)(dotNetPerfJit.timeInJitBase << 8), 2); - if (PhFormatToBuffer(&format, 1, formatBuffer, sizeof(formatBuffer), NULL)) - PhSetListViewSubItem(Context->CountersLv, 14, 1, formatBuffer); - } - else - { - PhSetListViewSubItem(Context->CountersLv, 14, 1, L"0.00"); - } + if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), formatBuffer, sizeof(formatBuffer), NULL)) + PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_JIT_TIME, 1, formatBuffer); + } + else + { + PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_JIT_TIME, 1, L"0.00"); + } - // The CLR source says this value should be "Gen 0 Heap Size; Gen 1 Heap Size; Gen 2 Heap Size and the Large Object Heap Size", - // but Perflib only counts Gen 1, Gen 2 and cLrgObjSize... For now, just do what perflib does. - PhSetListViewSubItem(Context->CountersLv, 15, 1, FormatByteValue(Context, dotNetPerfGC.cGenHeapSize[1] + dotNetPerfGC.cGenHeapSize[2] + dotNetPerfGC.cLrgObjSize)->Buffer); - PhSetListViewSubItem(Context->CountersLv, 16, 1, FormatByteValue(Context, dotNetPerfGC.cTotalCommittedBytes)->Buffer); - PhSetListViewSubItem(Context->CountersLv, 17, 1, FormatByteValue(Context, dotNetPerfGC.cTotalReservedBytes)->Buffer); - PhSetListViewSubItem(Context->CountersLv, 18, 1, PhaFormatUInt64(dotNetPerfGC.cPinnedObj, TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, 19, 1, PhaFormatUInt64(dotNetPerfGC.cSinkBlocks, TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, 20, 1, FormatByteValue(Context, dotNetPerfGC.cbAlloc)->Buffer); - PhSetListViewSubItem(Context->CountersLv, 21, 1, FormatByteValue(Context, dotNetPerfGC.cbLargeAlloc)->Buffer); - } - break; - case DOTNET_CATEGORY_REMOTING: - { - PhSetListViewSubItem(Context->CountersLv, 0, 1, PhaFormatUInt64(dotNetPerfContext.cRemoteCalls.Total, TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, 1, 1, PhaFormatUInt64(dotNetPerfContext.cChannels, TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, 2, 1, PhaFormatUInt64(dotNetPerfContext.cProxies, TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, 3, 1, PhaFormatUInt64(dotNetPerfContext.cClasses, TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, 4, 1, PhaFormatUInt64(dotNetPerfContext.cContexts, TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, 5, 1, PhaFormatUInt64(dotNetPerfContext.cObjAlloc, TRUE)->Buffer); - } - break; - case DOTNET_CATEGORY_SECURITY: - { - PhSetListViewSubItem(Context->CountersLv, 0, 1, PhaFormatUInt64(dotNetPerfSecurity.cTotalRTChecks, TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, 1, 1, PhaFormatUInt64(dotNetPerfSecurity.cLinkChecks, TRUE)->Buffer); + PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_LOADING_CURRENTLOADED, 1, PhaFormatUInt64(dotNetPerfLoading.cClassesLoaded.Current, TRUE)->Buffer); + PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_LOADING_TOTALLOADED, 1, PhaFormatUInt64(dotNetPerfLoading.cClassesLoaded.Total, TRUE)->Buffer); + PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_LOADING_CURRENTAPPDOMAINS, 1, PhaFormatUInt64(dotNetPerfLoading.cAppDomains.Current, TRUE)->Buffer); + PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_LOADING_TOTALAPPDOMAINS, 1, PhaFormatUInt64(dotNetPerfLoading.cAppDomains.Total, TRUE)->Buffer); + PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_LOADING_CURRENTASSEMBLIES, 1, PhaFormatUInt64(dotNetPerfLoading.cAssemblies.Current, TRUE)->Buffer); + PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_LOADING_TOTALASSEMBLIES, 1, PhaFormatUInt64(dotNetPerfLoading.cAssemblies.Total, TRUE)->Buffer); + PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_LOADING_ASSEMBLYSEARCHLENGTH, 1, PhaFormatUInt64(dotNetPerfLoading.cAsmSearchLen, TRUE)->Buffer); + PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_LOADING_TOTALLOADFAILURES, 1, PhaFormatUInt64(dotNetPerfLoading.cLoadFailures.Total, TRUE)->Buffer); + PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_LOADING_BYTESINLOADERHEAP, 1, PhaFormatSize(dotNetPerfLoading.cbLoaderHeapSize, ULONG_MAX)->Buffer); + PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_LOADING_TOTALAPPDOMAINSUNLOADED, 1, PhaFormatUInt64(dotNetPerfLoading.cAppDomainsUnloaded.Total, TRUE)->Buffer); + //PhSetListViewSubItem(Context->CountersLv, 10, 1, PhaFormatUInt64(dotNetPerfLoading.timeLoading, TRUE)->Buffer); + + // DOTNET_CATEGORY_LOCKSANDTHREADS + PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_LOCKSANDTHREADS_TOTALLOCKS, 1, PhaFormatUInt64(dotNetPerfLocksAndThreads.cContention.Total, TRUE)->Buffer); + PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_LOCKSANDTHREADS_TOTALQUEUELENGTH, 1, PhaFormatUInt64(dotNetPerfLocksAndThreads.cQueueLength.Current, TRUE)->Buffer); + PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_LOCKSANDTHREADS_QUEUELENGTHPEAK, 1, PhaFormatUInt64(dotNetPerfLocksAndThreads.cQueueLength.Total, TRUE)->Buffer); + PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_LOCKSANDTHREADS_CURRENTLOGICAL, 1, PhaFormatUInt64(dotNetPerfLocksAndThreads.cCurrentThreadsLogical, TRUE)->Buffer); + PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_LOCKSANDTHREADS_CURRENTPHYSICAL, 1, PhaFormatUInt64(dotNetPerfLocksAndThreads.cCurrentThreadsPhysical, TRUE)->Buffer); + PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_LOCKSANDTHREADS_CURRENTRECOGNIZED, 1, PhaFormatUInt64(dotNetPerfLocksAndThreads.cRecognizedThreads.Current, TRUE)->Buffer); + PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_LOCKSANDTHREADS_TOTALRECOGNIZED, 1, PhaFormatUInt64(dotNetPerfLocksAndThreads.cRecognizedThreads.Total, TRUE)->Buffer); + + // DOTNET_CATEGORY_MEMORY + PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_MEMORY_GENZEROCOLLECTIONS, 1, PhaFormatUInt64(dotNetPerfGC.cGenCollections[0], TRUE)->Buffer); + PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_MEMORY_GENONECOLLECTIONS, 1, PhaFormatUInt64(dotNetPerfGC.cGenCollections[1], TRUE)->Buffer); + PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_MEMORY_GENTWOCOLLECTIONS, 1, PhaFormatUInt64(dotNetPerfGC.cGenCollections[2], TRUE)->Buffer); + PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_MEMORY_PROMOTEDFROMGENZERO, 1, PhaFormatSize(dotNetPerfGC.cbPromotedMem[0], ULONG_MAX)->Buffer); + PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_MEMORY_PROMOTEDFROMGENONE, 1, PhaFormatSize(dotNetPerfGC.cbPromotedMem[1], ULONG_MAX)->Buffer); + PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_MEMORY_PROMOTEDFINALFROMGENZERO, 1, PhaFormatSize(dotNetPerfGC.cbPromotedFinalizationMem, ULONG_MAX)->Buffer); + PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_MEMORY_PROCESSID, 1, PhaFormatUInt64(dotNetPerfGC.cProcessID, FALSE)->Buffer); + PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_MEMORY_GENZEROHEAPSIZE, 1, PhaFormatSize(dotNetPerfGC.cGenHeapSize[0], ULONG_MAX)->Buffer); + PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_MEMORY_GENONEHEAPSIZE, 1, PhaFormatSize(dotNetPerfGC.cGenHeapSize[1], ULONG_MAX)->Buffer); + PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_MEMORY_GENTWOHEAPSIZE, 1, PhaFormatSize(dotNetPerfGC.cGenHeapSize[2], ULONG_MAX)->Buffer); + PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_MEMORY_LOHSIZE, 1, PhaFormatSize(dotNetPerfGC.cLrgObjSize, ULONG_MAX)->Buffer); + PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_MEMORY_FINALSURVIVORS, 1, PhaFormatUInt64(dotNetPerfGC.cSurviveFinalize, TRUE)->Buffer); + PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_MEMORY_GCHANDLES, 1, PhaFormatUInt64(dotNetPerfGC.cHandles, TRUE)->Buffer); + PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_MEMORY_INDUCEDGC, 1, PhaFormatUInt64(dotNetPerfGC.cInducedGCs, TRUE)->Buffer); + + if (dotNetPerfGC.timeInGCBase != 0) + { + PH_FORMAT format[1]; + WCHAR formatBuffer[10]; - if (dotNetPerfSecurity.timeRTchecksBase != 0) - { - PH_FORMAT format; - WCHAR formatBuffer[10]; + PhInitFormatF(&format[0], (FLOAT)dotNetPerfGC.timeInGC * 100 / (FLOAT)dotNetPerfGC.timeInGCBase, 2); - PhInitFormatF(&format, (FLOAT)dotNetPerfSecurity.timeRTchecks * 100 / (FLOAT)dotNetPerfSecurity.timeRTchecksBase, 2); + if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), formatBuffer, sizeof(formatBuffer), NULL)) + PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_MEMORY_TIMEINGC, 1, formatBuffer); + } + else + { + PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_MEMORY_TIMEINGC, 1, L"0.00"); + } - if (PhFormatToBuffer(&format, 1, formatBuffer, sizeof(formatBuffer), NULL)) - PhSetListViewSubItem(Context->CountersLv, 2, 1, formatBuffer); - } - else - { - PhSetListViewSubItem(Context->CountersLv, 2, 1, L"0.00"); - } + // The CLR source says this value should be "Gen 0 Heap Size; Gen 1 Heap Size; Gen 2 Heap Size and the Large Object Heap Size", + // but Perflib only counts Gen 1, Gen 2 and cLrgObjSize... For now, just do what perflib does. + PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_MEMORY_BYTESINALLHEAPS, 1, PhaFormatSize(dotNetPerfGC.cGenHeapSize[1] + dotNetPerfGC.cGenHeapSize[2] + dotNetPerfGC.cLrgObjSize, ULONG_MAX)->Buffer); + PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_MEMORY_TOTALCOMMITTED, 1, PhaFormatSize(dotNetPerfGC.cTotalCommittedBytes, ULONG_MAX)->Buffer); + PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_MEMORY_TOTALRESERVED, 1, PhaFormatSize(dotNetPerfGC.cTotalReservedBytes, ULONG_MAX)->Buffer); + PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_MEMORY_TOTALPINNED, 1, PhaFormatUInt64(dotNetPerfGC.cPinnedObj, TRUE)->Buffer); + PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_MEMORY_TOTALSINKS, 1, PhaFormatUInt64(dotNetPerfGC.cSinkBlocks, TRUE)->Buffer); + PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_MEMORY_TOTALBYTESSINCESTART, 1, PhaFormatSize(dotNetPerfGC.cbAlloc, ULONG_MAX)->Buffer); + PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_MEMORY_TOTALLOHBYTESSINCESTART, 1, PhaFormatSize(dotNetPerfGC.cbLargeAlloc, ULONG_MAX)->Buffer); + + // DOTNET_CATEGORY_REMOTING + PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_REMOTING_TOTALREMOTECALLS, 1, PhaFormatUInt64(dotNetPerfContext.cRemoteCalls.Total, TRUE)->Buffer); + PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_REMOTING_CHANNELS, 1, PhaFormatUInt64(dotNetPerfContext.cChannels, TRUE)->Buffer); + PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_REMOTING_CONTEXTPROXIES, 1, PhaFormatUInt64(dotNetPerfContext.cProxies, TRUE)->Buffer); + PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_REMOTING_CONTEXTCLASSESLOADED, 1, PhaFormatUInt64(dotNetPerfContext.cClasses, TRUE)->Buffer); + PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_REMOTING_CONTEXTS, 1, PhaFormatUInt64(dotNetPerfContext.cContexts, TRUE)->Buffer); + PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_REMOTING_CONTEXTSALLOCATED, 1, PhaFormatUInt64(dotNetPerfContext.cObjAlloc, TRUE)->Buffer); + + // DOTNET_CATEGORY_SECURITY + PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_SECURITY_TOTALRUNTIMECHECKS, 1, PhaFormatUInt64(dotNetPerfSecurity.cTotalRTChecks, TRUE)->Buffer); + PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_SECURITY_LINKTIMECHECKS, 1, PhaFormatUInt64(dotNetPerfSecurity.cLinkChecks, TRUE)->Buffer); + + if (dotNetPerfSecurity.timeRTchecksBase != 0) + { + PH_FORMAT format[1]; + WCHAR formatBuffer[10]; - PhSetListViewSubItem(Context->CountersLv, 3, 1, PhaFormatUInt64(dotNetPerfSecurity.stackWalkDepth, TRUE)->Buffer); - } - break; + PhInitFormatF(&format[0], (FLOAT)dotNetPerfSecurity.timeRTchecks * 100 / (FLOAT)dotNetPerfSecurity.timeRTchecksBase, 2); + + if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), formatBuffer, sizeof(formatBuffer), NULL)) + PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_SECURITY_TIMEINRTCHECKS, 1, formatBuffer); } + else + { + PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_SECURITY_TIMEINRTCHECKS, 1, L"0.00"); + } + + PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_SECURITY_STACKWALKDEPTH, 1, PhaFormatUInt64(dotNetPerfSecurity.stackWalkDepth, TRUE)->Buffer); } INT_PTR CALLBACK DotNetPerfPageDlgProc( @@ -722,17 +890,12 @@ INT_PTR CALLBACK DotNetPerfPageDlgProc( { case WM_INITDIALOG: { - context = PhAllocate(sizeof(PERFPAGE_CONTEXT)); - memset(context, 0, sizeof(PERFPAGE_CONTEXT)); - - propPageContext->Context = context; + context = propPageContext->Context = PhAllocateZero(sizeof(PERFPAGE_CONTEXT)); context->WindowHandle = hwndDlg; context->ProcessItem = processItem; - context->Enabled = TRUE; - context->AppDomainsLv = GetDlgItem(hwndDlg, IDC_APPDOMAINS); context->CountersLv = GetDlgItem(hwndDlg, IDC_COUNTERS); - context->CategoriesCb = GetDlgItem(hwndDlg, IDC_CATEGORIES); + context->Enabled = TRUE; PhSetListViewStyle(context->AppDomainsLv, FALSE, TRUE); PhSetControlTheme(context->AppDomainsLv, L"explorer"); @@ -744,17 +907,9 @@ INT_PTR CALLBACK DotNetPerfPageDlgProc( PhAddListViewColumn(context->CountersLv, 0, 0, 0, LVCFMT_LEFT, 250, L"Counter"); PhAddListViewColumn(context->CountersLv, 1, 1, 1, LVCFMT_RIGHT, 140, L"Value"); PhSetExtendedListView(context->CountersLv); - PhLoadListViewColumnsFromSetting(SETTING_NAME_DOT_NET_COUNTERS_COLUMNS, context->CountersLv); - if (PhGetIntegerSetting(SETTING_NAME_DOT_NET_SHOW_BYTE_SIZE)) - { - context->ShowByteSize = TRUE; - Button_SetCheck(GetDlgItem(hwndDlg, IDC_DOTNET_PERF_SHOWBYTES), TRUE); - } - - PhAddComboBoxStrings(context->CategoriesCb, DotNetCategoryStrings, ARRAYSIZE(DotNetCategoryStrings)); - context->CategoryIndex = PhGetIntegerSetting(SETTING_NAME_DOT_NET_CATEGORY_INDEX); - ComboBox_SetCurSel(context->CategoriesCb, context->CategoryIndex); + DotNetPerfAddListViewGroups(context->CountersLv); + PhLoadListViewColumnsFromSetting(SETTING_NAME_DOT_NET_COUNTERS_COLUMNS, context->CountersLv); #ifdef _WIN64 context->IsWow64 = !!context->ProcessItem->IsWow64; @@ -788,7 +943,7 @@ INT_PTR CALLBACK DotNetPerfPageDlgProc( // Skip AppDomain enumeration of 'Modern' .NET applications as they don't expose the CLR 'Private IPC' block. if (!context->ProcessItem->IsImmersive) { - AddProcessAppDomains(hwndDlg, context); + DotNetPerfAddProcessAppDomains(hwndDlg, context); } } @@ -819,13 +974,12 @@ INT_PTR CALLBACK DotNetPerfPageDlgProc( if (context->ControlBlockValid) { - UpdateCategoryValues(hwndDlg, context); - UpdateCounterData(hwndDlg, context); + DotNetPerfUpdateCounterData(hwndDlg, context); } PhRegisterCallback( PhGetGeneralCallback(GeneralCallbackProcessesUpdated), - ProcessesUpdatedCallback, + DotNetPerfProcessesUpdatedCallback, context, &context->ProcessesUpdatedCallbackRegistration ); @@ -867,52 +1021,13 @@ INT_PTR CALLBACK DotNetPerfPageDlgProc( if (dialogItem = PhBeginPropPageLayout(hwndDlg, propPageContext)) { PhAddPropPageLayoutItem(hwndDlg, context->AppDomainsLv, dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); - PhAddPropPageLayoutItem(hwndDlg, context->CategoriesCb, dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); PhAddPropPageLayoutItem(hwndDlg, context->CountersLv, dialogItem, PH_ANCHOR_ALL); - PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_DOTNET_PERF_SHOWBYTES), dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_BOTTOM); PhEndPropPageLayout(hwndDlg, propPageContext); } ExtendedListView_SetColumnWidth(context->AppDomainsLv, 0, ELVSCW_AUTOSIZE_REMAININGSPACE); } break; - case WM_COMMAND: - { - switch (GET_WM_COMMAND_ID(wParam, lParam)) - { - case IDC_CATEGORIES: - { - if (GET_WM_COMMAND_CMD(wParam, lParam) == CBN_SELCHANGE) - { - context->CategoryIndex = ComboBox_GetCurSel(context->CategoriesCb); - PhSetIntegerSetting(SETTING_NAME_DOT_NET_CATEGORY_INDEX, context->CategoryIndex); - - if (context->ControlBlockValid) - { - UpdateCategoryValues(hwndDlg, context); - UpdateCounterData(hwndDlg, context); - } - } - } - break; - case IDC_DOTNET_PERF_SHOWBYTES: - { - if (GET_WM_COMMAND_CMD(wParam, lParam) == BN_CLICKED) - { - context->ShowByteSize = !context->ShowByteSize; - PhSetIntegerSetting(SETTING_NAME_DOT_NET_SHOW_BYTE_SIZE, context->ShowByteSize); - - if (context->ControlBlockValid) - { - UpdateCategoryValues(hwndDlg, context); - UpdateCounterData(hwndDlg, context); - } - } - } - break; - } - } - break; case WM_NOTIFY: { LPNMHDR header = (LPNMHDR)lParam; @@ -925,6 +1040,9 @@ INT_PTR CALLBACK DotNetPerfPageDlgProc( case PSN_KILLACTIVE: context->Enabled = FALSE; break; + case PSN_QUERYINITIALFOCUS: + SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, (LPARAM)context->CountersLv); + return TRUE; } PhHandleListViewNotifyForCopy(lParam, context->AppDomainsLv); @@ -935,7 +1053,7 @@ INT_PTR CALLBACK DotNetPerfPageDlgProc( { if (context->Enabled && context->ControlBlockValid) { - UpdateCounterData(hwndDlg, context); + DotNetPerfUpdateCounterData(hwndDlg, context); } } break; diff --git a/plugins/DotNetTools/resource.h b/plugins/DotNetTools/resource.h index 418ddff76c51..911b6d4e1ddc 100644 --- a/plugins/DotNetTools/resource.h +++ b/plugins/DotNetTools/resource.h @@ -9,10 +9,11 @@ #define ID_CLR_INSPECT 105 #define ID_COPY 106 #define IDC_APPDOMAINS 1001 -#define IDC_CATEGORIES 1002 +#define IDC_OPTIONS 1002 #define IDC_COUNTERS 1003 +#define IDC_REFRESH 1003 #define IDC_LIST 1005 -#define IDC_DOTNET_PERF_SHOWBYTES 1006 +#define IDC_SEARCHEDIT 1035 // Next default values for new objects // From 08415d26e64dad9ff14f9f9b80a7d642e2b9a318 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 21 Aug 2018 09:30:58 +1000 Subject: [PATCH 1311/2058] Don't show module ParentDllBase on unsupported versions --- phlib/native.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/phlib/native.c b/phlib/native.c index 5a694d11d318..b4f8fd3b05bd 100644 --- a/phlib/native.c +++ b/phlib/native.c @@ -5530,7 +5530,6 @@ static BOOLEAN EnumGenericProcessModulesCallback( moduleInfo.Flags = Module->Flags; moduleInfo.LoadOrderIndex = (USHORT)(context->LoadOrderIndex++); moduleInfo.LoadCount = Module->ObsoleteLoadCount; - moduleInfo.ParentBaseAddress = Module->ParentDllBase; moduleInfo.Name = PhCreateStringFromUnicodeString(&Module->BaseDllName); moduleInfo.OriginalFileName = PhCreateStringFromUnicodeString(&Module->FullDllName); @@ -5538,11 +5537,13 @@ static BOOLEAN EnumGenericProcessModulesCallback( if (WindowsVersion >= WINDOWS_8) { + moduleInfo.ParentBaseAddress = Module->ParentDllBase; moduleInfo.LoadReason = (USHORT)Module->LoadReason; moduleInfo.LoadTime = Module->LoadTime; } else { + moduleInfo.ParentBaseAddress = NULL; moduleInfo.LoadReason = USHRT_MAX; moduleInfo.LoadTime.QuadPart = 0; } From 465b57595db309dc519e1972224abafd1b83bd15 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 21 Aug 2018 11:23:53 +1000 Subject: [PATCH 1312/2058] Fix default process properties window theme --- ProcessHacker/procprp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ProcessHacker/procprp.c b/ProcessHacker/procprp.c index 6ec43e5eb090..4bedb5d5e5b9 100644 --- a/ProcessHacker/procprp.c +++ b/ProcessHacker/procprp.c @@ -174,7 +174,8 @@ INT CALLBACK PhpPropSheetProc( PhSetWindowContext(hwndDlg, 0xF, propSheetContext); SetWindowLongPtr(hwndDlg, GWLP_WNDPROC, (LONG_PTR)PhpPropSheetWndProc); - PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport); + if (PhEnableThemeSupport) // NOTE: Required for compatibility. (dmex) + PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport); PhRegisterWindowCallback(hwndDlg, PH_PLUGIN_WINDOW_EVENT_TYPE_TOPMOST, NULL); From 3a4c31dd3fc3a295d10f4b9d301726aadeb0db5c Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 21 Aug 2018 11:57:06 +1000 Subject: [PATCH 1313/2058] Fix default handle properties theme --- ProcessHacker/hndlprp.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ProcessHacker/hndlprp.c b/ProcessHacker/hndlprp.c index 817a5e8b4557..f88c7b721ec6 100644 --- a/ProcessHacker/hndlprp.c +++ b/ProcessHacker/hndlprp.c @@ -942,7 +942,10 @@ INT_PTR CALLBACK PhpHandleGeneralDlgProc( PhpUpdateHandleGeneralListViewGroups(context); PhpUpdateHandleGeneral(context); - PhInitializeWindowTheme(GetParent(hwndDlg), PhEnableThemeSupport); // HACK + if (PhEnableThemeSupport) // TODO: Required for compat (dmex) + PhInitializeWindowTheme(GetParent(hwndDlg), PhEnableThemeSupport); + else + PhInitializeWindowTheme(hwndDlg, FALSE); } break; case WM_DESTROY: From fdc58f2a4cb0ec437dd356acaaa7f54c7577560f Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 21 Aug 2018 12:19:28 +1000 Subject: [PATCH 1314/2058] Improve device change plugin support, Update HardwareDevice device change events --- ProcessHacker/mainwnd.c | 13 ++++ plugins/HardwareDevices/disknotify.c | 92 +++++++++++++--------------- 2 files changed, 56 insertions(+), 49 deletions(-) diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index 748ef1634bb6..3f2266e186aa 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -332,6 +332,19 @@ LRESULT CALLBACK PhMwpWndProc( return result; } break; + case WM_DEVICECHANGE: + { + MSG message; + + memset(&message, 0, sizeof(MSG)); + message.hwnd = hWnd; + message.message = uMsg; + message.wParam = wParam; + message.lParam = lParam; + + PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackWindowNotifyEvent), &message); + } + break; } if (uMsg >= WM_PH_FIRST && uMsg <= WM_PH_LAST) diff --git a/plugins/HardwareDevices/disknotify.c b/plugins/HardwareDevices/disknotify.c index 8330bd2eaf63..24f24f5a0b94 100644 --- a/plugins/HardwareDevices/disknotify.c +++ b/plugins/HardwareDevices/disknotify.c @@ -2,7 +2,7 @@ * Process Hacker Plugins - * Hardware Devices Plugin * - * Copyright (C) 2016 dmex + * Copyright (C) 2016-2018 dmex * * This file is part of Process Hacker. * @@ -21,63 +21,52 @@ */ #include "devices.h" -#include +#include -static WNDPROC SubclassMainWindowProc = NULL; +BOOLEAN MainWndDeviceChangeRegistrationEnabled = FALSE; +PH_CALLBACK_REGISTRATION MainWndDeviceChangeEventRegistration; -LRESULT CALLBACK MainWndDevicesSubclassProc( - _In_ HWND hWnd, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam +VOID NTAPI HardwareDevicesDeviceChangeCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context ) { - if (!SubclassMainWindowProc) - return 0; + PMSG message = Parameter; - switch (uMsg) + switch (message->wParam) { - case WM_DEVICECHANGE: + case DBT_DEVICEARRIVAL: // Drive letter added + case DBT_DEVICEREMOVECOMPLETE: // Drive letter removed { - switch (wParam) - { - case DBT_DEVICEARRIVAL: // Drive letter added - case DBT_DEVICEREMOVECOMPLETE: // Drive letter removed - { - DEV_BROADCAST_HDR* deviceBroadcast = (DEV_BROADCAST_HDR*)lParam; + DEV_BROADCAST_HDR* deviceBroadcast = (DEV_BROADCAST_HDR*)message->lParam; - if (deviceBroadcast->dbch_devicetype == DBT_DEVTYP_VOLUME) - { - //PDEV_BROADCAST_VOLUME deviceVolume = (PDEV_BROADCAST_VOLUME)deviceBroadcast; - - PhAcquireQueuedLockShared(&DiskDrivesListLock); + if (deviceBroadcast->dbch_devicetype == DBT_DEVTYP_VOLUME) + { + //PDEV_BROADCAST_VOLUME deviceVolume = (PDEV_BROADCAST_VOLUME)deviceBroadcast; - for (ULONG i = 0; i < DiskDrivesList->Count; i++) - { - PDV_DISK_ENTRY entry; + PhAcquireQueuedLockShared(&DiskDrivesListLock); - entry = PhReferenceObjectSafe(DiskDrivesList->Items[i]); + for (ULONG i = 0; i < DiskDrivesList->Count; i++) + { + PDV_DISK_ENTRY entry; - if (!entry) - continue; + entry = PhReferenceObjectSafe(DiskDrivesList->Items[i]); - // Reset the DiskIndex so we can re-query the index on the next interval update. - entry->DiskIndex = ULONG_MAX; - // Reset the DiskIndexName so we can re-query the name on the next interval update. - PhClearReference(&entry->DiskIndexName); + if (!entry) + continue; - PhDereferenceObjectDeferDelete(entry); - } + // Reset the DiskIndex so we can re-query the index on the next interval update. + entry->DiskIndex = ULONG_MAX; + // Reset the DiskIndexName so we can re-query the name on the next interval update. + PhClearReference(&entry->DiskIndexName); - PhReleaseQueuedLockShared(&DiskDrivesListLock); - } + PhDereferenceObjectDeferDelete(entry); } + + PhReleaseQueuedLockShared(&DiskDrivesListLock); } } - break; } - - return CallWindowProc(SubclassMainWindowProc, hWnd, uMsg, wParam, lParam); } VOID AddRemoveDeviceChangeCallback( @@ -91,20 +80,25 @@ VOID AddRemoveDeviceChangeCallback( // Add the subclass only when disks are being monitored, remove when no longer needed. if (DiskDrivesList->Count) { - if (!SubclassMainWindowProc) + if (!MainWndDeviceChangeRegistrationEnabled) { - // We have a disk device, subclass the main window to detect drive letter changes. - SubclassMainWindowProc = (WNDPROC)GetWindowLongPtr(PhMainWndHandle, GWLP_WNDPROC); - SetWindowLongPtr(PhMainWndHandle, GWLP_WNDPROC, (LONG_PTR)MainWndDevicesSubclassProc); + // We have a disk device, register for window events needed to detect drive letter changes. + MainWndDeviceChangeRegistrationEnabled = TRUE; + PhRegisterCallback( + PhGetGeneralCallback(GeneralCallbackWindowNotifyEvent), + HardwareDevicesDeviceChangeCallback, + NULL, + &MainWndDeviceChangeEventRegistration + ); } } else { - if (SubclassMainWindowProc) + if (MainWndDeviceChangeRegistrationEnabled) { - // The user has removed the last disk device, remove the subclass. - SetWindowLongPtr(PhMainWndHandle, GWLP_WNDPROC, (LONG_PTR)SubclassMainWindowProc); - SubclassMainWindowProc = NULL; + // Remove the event callback after the user has removed the last disk device. + PhUnregisterCallback(PhGetGeneralCallback(GeneralCallbackWindowNotifyEvent), &MainWndDeviceChangeEventRegistration); + MainWndDeviceChangeRegistrationEnabled = FALSE; } } -} \ No newline at end of file +} From 623e5831cf91ef2383b552370ac81552ffdf7b9a Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 21 Aug 2018 13:30:05 +1000 Subject: [PATCH 1315/2058] peview: Add RtlLcidToLocaleName --- phlib/include/phutil.h | 12 ++++++++++++ tools/peview/resprp.c | 23 ++++++++++++++++++----- 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/phlib/include/phutil.h b/phlib/include/phutil.h index 5ff483d69a44..d12d86f00d74 100644 --- a/phlib/include/phutil.h +++ b/phlib/include/phutil.h @@ -188,6 +188,18 @@ PhDereferenceObjects( _In_ ULONG NumberOfObjects ); +// NLS + +LCID PhGetSystemDefaultLCID( + VOID + ); + +LCID PhGetUserDefaultLCID( + VOID + ); + +// Error messages + PHLIBAPI PPH_STRING NTAPI diff --git a/tools/peview/resprp.c b/tools/peview/resprp.c index e731b1a3649f..23efb382c2ee 100644 --- a/tools/peview/resprp.c +++ b/tools/peview/resprp.c @@ -155,15 +155,28 @@ INT_PTR CALLBACK PvpPeResourcesDlgProc( if (IS_INTRESOURCE(entry.Language)) { - WCHAR name[LOCALE_NAME_MAX_LENGTH]; + NTSTATUS status; + UNICODE_STRING localeNameUs; + WCHAR localeName[LOCALE_NAME_MAX_LENGTH]; - PhPrintUInt32(number, (ULONG)entry.Language); + RtlInitEmptyUnicodeString(&localeNameUs, localeName, sizeof(localeName)); - // TODO: RtlLcidToLocaleName - if (LCIDToLocaleName((ULONG)entry.Language, name, LOCALE_NAME_MAX_LENGTH, LOCALE_ALLOW_NEUTRAL_NAMES)) - PhSetListViewSubItem(lvHandle, lvItemIndex, PVE_RESOURCES_COLUMN_INDEX_LCID, PhaFormatString(L"%s (%s)", number, name)->Buffer); + // Note: Win32 defaults to the current user locale when zero is specified (e.g. LCIDToLocaleName). + if ((ULONG)entry.Language) + status = RtlLcidToLocaleName((ULONG)entry.Language, &localeNameUs, 0, FALSE); else + status = RtlLcidToLocaleName(PhGetUserDefaultLCID(), &localeNameUs, 0, FALSE); + + if (NT_SUCCESS(status)) + { + PhPrintUInt32(number, (ULONG)entry.Language); + PhSetListViewSubItem(lvHandle, lvItemIndex, PVE_RESOURCES_COLUMN_INDEX_LCID, PhaFormatString(L"%s (%s)", number, localeName)->Buffer); + } + else + { + PhPrintUInt32(number, (ULONG)entry.Language); PhSetListViewSubItem(lvHandle, lvItemIndex, PVE_RESOURCES_COLUMN_INDEX_LCID, number); + } } else { From 175f6e42db39bc3941bcd5f8f7bc6d2e63381ae6 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 21 Aug 2018 16:47:15 +1000 Subject: [PATCH 1316/2058] Add PhQueryEnvironmentVariable --- phlib/include/phnative.h | 9 ++++++ phlib/native.c | 59 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+) diff --git a/phlib/include/phnative.h b/phlib/include/phnative.h index 15ee8bf01388..c1e799c83864 100644 --- a/phlib/include/phnative.h +++ b/phlib/include/phnative.h @@ -259,6 +259,15 @@ PhEnumProcessEnvironmentVariables( _Out_ PPH_ENVIRONMENT_VARIABLE Variable ); +PHLIBAPI +NTSTATUS +NTAPI +PhQueryEnvironmentVariable( + _In_opt_ PVOID Environment, + _In_ PPH_STRINGREF Name, + _Out_opt_ PPH_STRING* Value + ); + PHLIBAPI NTSTATUS NTAPI diff --git a/phlib/native.c b/phlib/native.c index b4f8fd3b05bd..f1e43b237f03 100644 --- a/phlib/native.c +++ b/phlib/native.c @@ -1092,6 +1092,65 @@ BOOLEAN PhEnumProcessEnvironmentVariables( return TRUE; } +NTSTATUS PhQueryEnvironmentVariable( + _In_opt_ PVOID Environment, + _In_ PPH_STRINGREF Name, + _Out_opt_ PPH_STRING* Value + ) +{ + NTSTATUS status; + UNICODE_STRING variableNameUs; + UNICODE_STRING variableValueUs; + + PhStringRefToUnicodeString(Name, &variableNameUs); + + if (Value) + { + variableValueUs.Length = 0x100 * sizeof(WCHAR); + variableValueUs.MaximumLength = variableValueUs.Length + sizeof(UNICODE_NULL); + variableValueUs.Buffer = PhAllocateZero(variableValueUs.MaximumLength); + } + else + { + RtlInitUnicodeString(&variableValueUs, UNICODE_NULL); + } + + status = RtlQueryEnvironmentVariable_U( + Environment, + &variableNameUs, + &variableValueUs + ); + + if (Value && status == STATUS_BUFFER_TOO_SMALL) + { + if (variableValueUs.Length + sizeof(UNICODE_NULL) > UNICODE_STRING_MAX_BYTES) + variableValueUs.MaximumLength = variableValueUs.Length; + else + variableValueUs.MaximumLength = variableValueUs.Length + sizeof(UNICODE_NULL); + + PhFree(variableValueUs.Buffer); + variableValueUs.Buffer = PhAllocateZero(variableValueUs.MaximumLength); + + status = RtlQueryEnvironmentVariable_U( + Environment, + &variableNameUs, + &variableValueUs + ); + } + + if (Value && NT_SUCCESS(status)) + { + *Value = PhCreateStringFromUnicodeString(&variableValueUs); + } + + if (Value && variableValueUs.Buffer) + { + PhFree(variableValueUs.Buffer); + } + + return status; +} + /** * Gets the file name of a mapped section. * From 5f075a454982b21f61eda32d47565748686d8b6e Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 21 Aug 2018 16:48:41 +1000 Subject: [PATCH 1317/2058] Add process information to handle properties window --- ProcessHacker/hndlprp.c | 143 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 140 insertions(+), 3 deletions(-) diff --git a/ProcessHacker/hndlprp.c b/ProcessHacker/hndlprp.c index f88c7b721ec6..c25a05ed9796 100644 --- a/ProcessHacker/hndlprp.c +++ b/ProcessHacker/hndlprp.c @@ -42,6 +42,7 @@ typedef enum _PHP_HANDLE_GENERAL_CATEGORY PH_HANDLE_GENERAL_CATEGORY_FILE, PH_HANDLE_GENERAL_CATEGORY_SECTION, PH_HANDLE_GENERAL_CATEGORY_MUTANT, + PH_HANDLE_GENERAL_CATEGORY_PROCESS, PH_HANDLE_GENERAL_CATEGORY_MAXIMUM } PHP_HANDLE_GENERAL_CATEGORY; @@ -75,6 +76,11 @@ typedef enum _PHP_HANDLE_GENERAL_INDEX PH_HANDLE_GENERAL_INDEX_MUTANTABANDONED, PH_HANDLE_GENERAL_INDEX_MUTANTOWNER, + PH_HANDLE_GENERAL_INDEX_PROCESSNAME, + PH_HANDLE_GENERAL_INDEX_PROCESSCREATETIME, + PH_HANDLE_GENERAL_INDEX_PROCESSEXITTIME, + PH_HANDLE_GENERAL_INDEX_PROCESSEXITCODE, + PH_HANDLE_GENERAL_INDEX_MAXIMUM } PHP_PROCESS_STATISTICS_INDEX; @@ -373,7 +379,7 @@ VOID PhpUpdateHandleGeneralListViewGroups( } else if (PhEqualStringRef2(&Context->HandleItem->TypeName->sr, L"File", TRUE)) { - PhAddListViewGroup(Context->ListViewHandle, PH_HANDLE_GENERAL_CATEGORY_FILE, L"File Information"); + PhAddListViewGroup(Context->ListViewHandle, PH_HANDLE_GENERAL_CATEGORY_FILE, L"File information"); Context->ListViewRowCache[PH_HANDLE_GENERAL_INDEX_FILETYPE] = PhAddListViewGroupItem( Context->ListViewHandle, @@ -406,7 +412,7 @@ VOID PhpUpdateHandleGeneralListViewGroups( } else if (PhEqualStringRef2(&Context->HandleItem->TypeName->sr, L"Section", TRUE)) { - PhAddListViewGroup(Context->ListViewHandle, PH_HANDLE_GENERAL_CATEGORY_SECTION, L"Section Information"); + PhAddListViewGroup(Context->ListViewHandle, PH_HANDLE_GENERAL_CATEGORY_SECTION, L"Section information"); Context->ListViewRowCache[PH_HANDLE_GENERAL_INDEX_SECTIONTYPE] = PhAddListViewGroupItem( Context->ListViewHandle, @@ -432,7 +438,7 @@ VOID PhpUpdateHandleGeneralListViewGroups( } else if (PhEqualStringRef2(&Context->HandleItem->TypeName->sr, L"Mutant", TRUE)) { - PhAddListViewGroup(Context->ListViewHandle, PH_HANDLE_GENERAL_CATEGORY_MUTANT, L"Mutant Information"); + PhAddListViewGroup(Context->ListViewHandle, PH_HANDLE_GENERAL_CATEGORY_MUTANT, L"Mutant information"); Context->ListViewRowCache[PH_HANDLE_GENERAL_INDEX_MUTANTCOUNT] = PhAddListViewGroupItem( Context->ListViewHandle, @@ -456,6 +462,39 @@ VOID PhpUpdateHandleGeneralListViewGroups( NULL ); } + else if (PhEqualStringRef2(&Context->HandleItem->TypeName->sr, L"Process", TRUE)) + { + PhAddListViewGroup(Context->ListViewHandle, PH_HANDLE_GENERAL_CATEGORY_PROCESS, L"Process information"); + + Context->ListViewRowCache[PH_HANDLE_GENERAL_INDEX_PROCESSNAME] = PhAddListViewGroupItem( + Context->ListViewHandle, + PH_HANDLE_GENERAL_CATEGORY_PROCESS, + PH_HANDLE_GENERAL_INDEX_PROCESSNAME, + L"Name", + NULL + ); + Context->ListViewRowCache[PH_HANDLE_GENERAL_INDEX_PROCESSCREATETIME] = PhAddListViewGroupItem( + Context->ListViewHandle, + PH_HANDLE_GENERAL_CATEGORY_PROCESS, + PH_HANDLE_GENERAL_INDEX_PROCESSCREATETIME, + L"Created", + NULL + ); + Context->ListViewRowCache[PH_HANDLE_GENERAL_INDEX_PROCESSEXITTIME] = PhAddListViewGroupItem( + Context->ListViewHandle, + PH_HANDLE_GENERAL_CATEGORY_PROCESS, + PH_HANDLE_GENERAL_INDEX_PROCESSEXITTIME, + L"Exited", + NULL + ); + Context->ListViewRowCache[PH_HANDLE_GENERAL_INDEX_PROCESSEXITCODE] = PhAddListViewGroupItem( + Context->ListViewHandle, + PH_HANDLE_GENERAL_CATEGORY_PROCESS, + PH_HANDLE_GENERAL_INDEX_PROCESSEXITCODE, + L"Exit status", + NULL + ); + } } VOID PhpUpdateHandleGeneral( @@ -889,6 +928,104 @@ VOID PhpUpdateHandleGeneral( NtClose(mutantHandle); } } + else if (PhEqualString2(Context->HandleItem->TypeName, L"Process", TRUE)) + { + PHANDLE_PROPERTIES_CONTEXT context = Context; + NTSTATUS status; + HANDLE processHandle; + HANDLE dupHandle; + + if (NT_SUCCESS(status = PhOpenProcess( + &processHandle, + PROCESS_DUP_HANDLE, + Context->ProcessId + ))) + { + status = NtDuplicateObject( + processHandle, + Context->HandleItem->Handle, + NtCurrentProcess(), + &dupHandle, + ProcessQueryAccess, + 0, + 0 + ); + + if (!NT_SUCCESS(status)) + { + status = NtDuplicateObject( + processHandle, + Context->HandleItem->Handle, + NtCurrentProcess(), + &dupHandle, + PROCESS_QUERY_LIMITED_INFORMATION, + 0, + 0 + ); + } + + NtClose(processHandle); + } + + if (NT_SUCCESS(status)) + { + NTSTATUS exitStatus = STATUS_PENDING; + PPH_STRING fileName; + PROCESS_BASIC_INFORMATION basicInfo; + KERNEL_USER_TIMES times; + + if (NT_SUCCESS(PhGetProcessImageFileName(dupHandle, &fileName))) + { + PhMoveReference(&fileName, PhGetFileName(fileName)); + PhSetListViewSubItem(Context->ListViewHandle, Context->ListViewRowCache[PH_HANDLE_GENERAL_INDEX_PROCESSNAME], 1, PhGetStringOrEmpty(fileName)); + PhDereferenceObject(fileName); + } + + if (NT_SUCCESS(PhGetProcessBasicInformation(dupHandle, &basicInfo))) + { + exitStatus = basicInfo.ExitStatus; + } + + if (NT_SUCCESS(PhGetProcessTimes(dupHandle, ×))) + { + SYSTEMTIME time; + + PhLargeIntegerToLocalSystemTime(&time, ×.CreateTime); + PhSetListViewSubItem(Context->ListViewHandle, Context->ListViewRowCache[PH_HANDLE_GENERAL_INDEX_PROCESSCREATETIME], 1, PhaFormatDateTime(&time)->Buffer); + + if (exitStatus != STATUS_PENDING) + { + PhLargeIntegerToLocalSystemTime(&time, ×.ExitTime); + PhSetListViewSubItem(Context->ListViewHandle, Context->ListViewRowCache[PH_HANDLE_GENERAL_INDEX_PROCESSEXITTIME], 1, PhaFormatDateTime(&time)->Buffer); + } + } + + if (exitStatus != STATUS_PENDING) + { + PPH_STRING status; + PPH_STRING exitcode; + + status = PhGetStatusMessage(exitStatus, 0); + exitcode = PhFormatString( + L"0x%x (%s)", + exitStatus, + status->Buffer + ); + + PhSetListViewSubItem( + Context->ListViewHandle, + Context->ListViewRowCache[PH_HANDLE_GENERAL_INDEX_PROCESSEXITCODE], + 1, + PhGetStringOrEmpty(exitcode) + ); + + PhDereferenceObject(exitcode); + PhDereferenceObject(status); + } + + NtClose(dupHandle); + } + } } INT_PTR CALLBACK PhpHandleGeneralDlgProc( From 12120a72899de89dddc9cccada47575697dbd516 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 21 Aug 2018 16:49:19 +1000 Subject: [PATCH 1318/2058] Update phsvc object name --- ProcessHacker/phsvc/svcclient.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ProcessHacker/phsvc/svcclient.c b/ProcessHacker/phsvc/svcclient.c index 7f351fa5e316..a8d7a9fbb98c 100644 --- a/ProcessHacker/phsvc/svcclient.c +++ b/ProcessHacker/phsvc/svcclient.c @@ -41,7 +41,7 @@ PPHSVC_CLIENT PhSvcCreateClient( if (PhBeginInitOnce(&initOnce)) { - PhSvcClientType = PhCreateObjectType(L"Client", 0, PhSvcpClientDeleteProcedure); + PhSvcClientType = PhCreateObjectType(L"PhSvcClient", 0, PhSvcpClientDeleteProcedure); PhEndInitOnce(&initOnce); } From a3449348082862a7482dfb7e84a16ebb4db5db5e Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 21 Aug 2018 16:54:15 +1000 Subject: [PATCH 1319/2058] Fix process variables showing as unmodified system variables --- ProcessHacker/prpgenv.c | 77 +++++++++++++++++++++++++++++++++-------- 1 file changed, 62 insertions(+), 15 deletions(-) diff --git a/ProcessHacker/prpgenv.c b/ProcessHacker/prpgenv.c index f6141f954580..595fdb7ebaa5 100644 --- a/ProcessHacker/prpgenv.c +++ b/ProcessHacker/prpgenv.c @@ -223,34 +223,67 @@ VOID PhpRefreshEnvironmentList( for (i = 0; i < Context->Items.Count; i++) { - UNICODE_STRING variableNameUs; - UNICODE_STRING variableValueUs; + PPHP_PROCESS_ENVIRONMENT_TREENODE parentNode; + PROCESS_ENVIRONMENT_TREENODE_TYPE nodeType; + PPH_STRING variableValue; item = PhItemArray(&Context->Items, i); - PhStringRefToUnicodeString(&item->Name->sr, &variableNameUs); - RtlInitUnicodeString(&variableValueUs, UNICODE_NULL); - - if (RtlQueryEnvironmentVariable_U( + if (PhQueryEnvironmentVariable( Context->SystemDefaultEnvironment, - &variableNameUs, - &variableValueUs + &item->Name->sr, + NULL ) == STATUS_BUFFER_TOO_SMALL) { - PhpAddEnvironmentChildNode(Context, systemRootNode, i, PROCESS_ENVIRONMENT_TREENODE_TYPE_SYSTEM, item->Name, item->Value); + nodeType = PROCESS_ENVIRONMENT_TREENODE_TYPE_SYSTEM; + parentNode = systemRootNode; + + if (NT_SUCCESS(PhQueryEnvironmentVariable( + Context->SystemDefaultEnvironment, + &item->Name->sr, + &variableValue + ))) + { + if (!PhEqualString(variableValue, item->Value, FALSE)) + { + nodeType = PROCESS_ENVIRONMENT_TREENODE_TYPE_PROCESS; + parentNode = processRootNode; + } + + PhDereferenceObject(variableValue); + } } - else if (RtlQueryEnvironmentVariable_U( + else if (PhQueryEnvironmentVariable( Context->UserDefaultEnvironment, - &variableNameUs, - &variableValueUs + &item->Name->sr, + NULL ) == STATUS_BUFFER_TOO_SMALL) { - PhpAddEnvironmentChildNode(Context, userRootNode, i, PROCESS_ENVIRONMENT_TREENODE_TYPE_USER, item->Name, item->Value); + nodeType = PROCESS_ENVIRONMENT_TREENODE_TYPE_USER; + parentNode = userRootNode; + + if (NT_SUCCESS(PhQueryEnvironmentVariable( + Context->UserDefaultEnvironment, + &item->Name->sr, + &variableValue + ))) + { + if (!PhEqualString(variableValue, item->Value, FALSE)) + { + nodeType = PROCESS_ENVIRONMENT_TREENODE_TYPE_PROCESS; + parentNode = processRootNode; + } + + PhDereferenceObject(variableValue); + } } else { - PhpAddEnvironmentChildNode(Context, processRootNode, i, PROCESS_ENVIRONMENT_TREENODE_TYPE_PROCESS, item->Name, item->Value); + nodeType = PROCESS_ENVIRONMENT_TREENODE_TYPE_PROCESS; + parentNode = processRootNode; } + + PhpAddEnvironmentChildNode(Context, parentNode, i, nodeType, item->Name, item->Value); } PhApplyTreeNewFilters(&Context->TreeFilterSupport); @@ -335,6 +368,20 @@ INT_PTR CALLBACK PhpEditEnvDlgProc( HANDLE processHandle; LARGE_INTEGER timeout; + if (PhIsProcessSuspended(context->ProcessItem->ProcessId)) + { + if (PhGetIntegerSetting(L"EnableWarnings") && PhShowMessage2( + hwndDlg, + TDCBF_YES_BUTTON | TDCBF_NO_BUTTON, + TD_WARNING_ICON, + L"The process is suspended.", + L"Editing environment variable(s) of suspended processes is not supported.\n\nAre you sure you want to continue?" + ) == IDNO) + { + break; + } + } + if (!PhIsNullOrEmptyString(name)) { if (!PhEqualString2(name, context->Name, FALSE) || @@ -394,7 +441,7 @@ INT_PTR CALLBACK PhpEditEnvDlgProc( break; case IDC_NAME: { - if (HIWORD(wParam) == EN_CHANGE) + if (GET_WM_COMMAND_CMD(wParam, lParam) == EN_CHANGE) { EnableWindow(GetDlgItem(hwndDlg, IDOK), PhGetWindowTextLength(GetDlgItem(hwndDlg, IDC_NAME)) > 0); } From 307d9d47a2dccb3b7b2058cdd9e84490e2859528 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 21 Aug 2018 21:33:53 +1000 Subject: [PATCH 1320/2058] Fix default process handle tab options --- ProcessHacker/settings.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ProcessHacker/settings.c b/ProcessHacker/settings.c index 00e4de8a9cef..ac74df954478 100644 --- a/ProcessHacker/settings.c +++ b/ProcessHacker/settings.c @@ -68,7 +68,7 @@ VOID PhAddDefaultSettings( PhpAddIntegerSetting(L"ForceNoParent", L"1"); PhpAddStringSetting(L"HandleTreeListColumns", L""); PhpAddStringSetting(L"HandleTreeListSort", L"0,1"); // 0, AscendingSortOrder - PhpAddIntegerSetting(L"HandleTreeListFlags", L"0"); + PhpAddIntegerSetting(L"HandleTreeListFlags", L"3"); PhpAddIntegerPairSetting(L"HandlePropertiesWindowPosition", L"0,0"); PhpAddScalableIntegerPairSetting(L"HandlePropertiesWindowSize", L"@96|260,260"); PhpAddIntegerSetting(L"HiddenProcessesMenuEnabled", L"0"); From 18f0ff4b4ea82740f6dec26ee72bad538361a0cc Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 21 Aug 2018 22:03:25 +1000 Subject: [PATCH 1321/2058] Add 'Hide etw' option to process handles tab --- ProcessHacker/hndllist.c | 3 +++ ProcessHacker/include/hndllist.h | 7 +++++-- ProcessHacker/prpghndl.c | 30 +++++++++++++++++++++++++++--- 3 files changed, 35 insertions(+), 5 deletions(-) diff --git a/ProcessHacker/hndllist.c b/ProcessHacker/hndllist.c index 9ac11448b69d..1bf0b08b34ad 100644 --- a/ProcessHacker/hndllist.c +++ b/ProcessHacker/hndllist.c @@ -194,6 +194,9 @@ VOID PhSetOptionsHandleList( case PH_HANDLE_TREE_MENUITEM_HIDEUNNAMEDHANDLES: Context->HideUnnamedHandles = !Context->HideUnnamedHandles; break; + case PH_HANDLE_TREE_MENUITEM_HIDEETWHANDLES: + Context->HideEtwHandles = !Context->HideEtwHandles; + break; } } diff --git a/ProcessHacker/include/hndllist.h b/ProcessHacker/include/hndllist.h index 195e9a994640..5188d548d52a 100644 --- a/ProcessHacker/include/hndllist.h +++ b/ProcessHacker/include/hndllist.h @@ -22,7 +22,9 @@ // begin_phapppub typedef enum _PH_HANDLE_TREE_MENUITEM { - PH_HANDLE_TREE_MENUITEM_HIDEUNNAMEDHANDLES = 1, + PH_HANDLE_TREE_MENUITEM_NONE, + PH_HANDLE_TREE_MENUITEM_HIDEUNNAMEDHANDLES, + PH_HANDLE_TREE_MENUITEM_HIDEETWHANDLES, PH_HANDLE_TREE_MENUITEM_MAXIMUM } PH_HANDLE_TREE_MENUITEM; // end_phapppub @@ -63,7 +65,8 @@ typedef struct _PH_HANDLE_LIST_CONTEXT { ULONG EnableStateHighlighting : 1; ULONG HideUnnamedHandles : 1; - ULONG Spare : 23; + ULONG HideEtwHandles : 1; + ULONG Spare : 22; }; }; diff --git a/ProcessHacker/prpghndl.c b/ProcessHacker/prpghndl.c index 608dca76f181..90009db99d14 100644 --- a/ProcessHacker/prpghndl.c +++ b/ProcessHacker/prpghndl.c @@ -27,6 +27,7 @@ #include #include +#include #include #include @@ -256,6 +257,25 @@ BOOLEAN PhpHandleTreeFilterCallback( if (handlesContext->ListContext.HideUnnamedHandles && PhIsNullOrEmptyString(handleItem->BestObjectName)) return FALSE; + if (handlesContext->ListContext.HideEtwHandles) + { + static PH_INITONCE initOnce = PH_INITONCE_INIT; + static ULONG eventTraceTypeIndex = ULONG_MAX; + + // HACK: lazy init the etw object type index (dmex) + if (PhBeginInitOnce(&initOnce)) + { + UNICODE_STRING fileTypeName; + + RtlInitUnicodeString(&fileTypeName, L"EtwRegistration"); + eventTraceTypeIndex = PhGetObjectTypeNumber(&fileTypeName); + PhEndInitOnce(&initOnce); + } + + if (handleItem->TypeIndex == eventTraceTypeIndex) + return FALSE; + } + if (PhIsNullOrEmptyString(handlesContext->SearchboxText)) return TRUE; @@ -595,17 +615,21 @@ INT_PTR CALLBACK PhpProcessHandlesDlgProc( RECT rect; PPH_EMENU menu; PPH_EMENU_ITEM unnamedMenuItem; + PPH_EMENU_ITEM etwMenuItem; PPH_EMENU_ITEM selectedItem; GetWindowRect(GetDlgItem(hwndDlg, IDC_OPTIONS), &rect); menu = PhCreateEMenu(); - unnamedMenuItem = PhCreateEMenuItem(0, PH_HANDLE_TREE_MENUITEM_HIDEUNNAMEDHANDLES, L"Hide unnamed handles", NULL, NULL); - PhInsertEMenuItem(menu, unnamedMenuItem, ULONG_MAX); - + PhInsertEMenuItem(menu, unnamedMenuItem = PhCreateEMenuItem(0, PH_HANDLE_TREE_MENUITEM_HIDEUNNAMEDHANDLES, L"Hide unnamed handles", NULL, NULL), ULONG_MAX); + PhInsertEMenuItem(menu, etwMenuItem = PhCreateEMenuItem(0, PH_HANDLE_TREE_MENUITEM_HIDEETWHANDLES, L"Hide etw handles", NULL, NULL), ULONG_MAX); + if (handlesContext->ListContext.HideUnnamedHandles) unnamedMenuItem->Flags |= PH_EMENU_CHECKED; + if (handlesContext->ListContext.HideEtwHandles) + etwMenuItem->Flags |= PH_EMENU_CHECKED; + selectedItem = PhShowEMenu( menu, hwndDlg, From e5d672a2f52f5be5b844dd3298f04dad779b8ac0 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 21 Aug 2018 22:03:38 +1000 Subject: [PATCH 1322/2058] Remove unused code --- ProcessHacker/prpgmod.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/ProcessHacker/prpgmod.c b/ProcessHacker/prpgmod.c index 2750f7fb3573..ab864c3f7c4b 100644 --- a/ProcessHacker/prpgmod.c +++ b/ProcessHacker/prpgmod.c @@ -669,7 +669,6 @@ INT_PTR CALLBACK PhpProcessModulesDlgProc( PPH_EMENU_ITEM dotnetItem; PPH_EMENU_ITEM immersiveItem; PPH_EMENU_ITEM relocatedItem; - PPH_EMENU_ITEM stringsItem; PPH_EMENU_ITEM selectedItem; GetWindowRect(GetDlgItem(hwndDlg, IDC_FILTEROPTIONS), &rect); @@ -686,8 +685,8 @@ INT_PTR CALLBACK PhpProcessModulesDlgProc( PhInsertEMenuItem(menu, untrustedItem = PhCreateEMenuItem(0, PH_MODULE_FLAGS_HIGHLIGHT_UNSIGNED_OPTION, L"Highlight untrusted modules", NULL, NULL), ULONG_MAX); PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX); PhInsertEMenuItem(menu, PhCreateEMenuItem(0, PH_MODULE_FLAGS_LOAD_MODULE_OPTION, L"Load module...", NULL, NULL), ULONG_MAX); - PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX); - PhInsertEMenuItem(menu, stringsItem = PhCreateEMenuItem(0, PH_MODULE_FLAGS_MODULE_STRINGS_OPTION, L"Strings...", NULL, NULL), ULONG_MAX); + //PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX); + //PhInsertEMenuItem(menu, stringsItem = PhCreateEMenuItem(0, PH_MODULE_FLAGS_MODULE_STRINGS_OPTION, L"Strings...", NULL, NULL), ULONG_MAX); if (modulesContext->ListContext.HideDynamicModules) dynamicItem->Flags |= PH_EMENU_CHECKED; @@ -706,8 +705,6 @@ INT_PTR CALLBACK PhpProcessModulesDlgProc( if (modulesContext->ListContext.HighlightUntrustedModules) untrustedItem->Flags |= PH_EMENU_CHECKED; - stringsItem->Flags |= PH_EMENU_DISABLED; // TODO - selectedItem = PhShowEMenu( menu, hwndDlg, From 60fd8f545d08f67b83c1d21e317abdcaa6cce5c3 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 21 Aug 2018 22:09:30 +1000 Subject: [PATCH 1323/2058] Fix type --- phlib/include/appresolverp.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/phlib/include/appresolverp.h b/phlib/include/appresolverp.h index 89d71a8adf39..0cfabc0b1871 100644 --- a/phlib/include/appresolverp.h +++ b/phlib/include/appresolverp.h @@ -294,7 +294,7 @@ DECLARE_INTERFACE_IID(IStartMenuAppItems61, IUnknown) STDMETHOD(EnumItems)(THIS, _In_ ULONG Flags, _In_ REFIID riid, - _Outptr_ IEnumObjects *ppvObject + _Outptr_ IEnumObjects **ppvObject ) PURE; STDMETHOD(GetItem)(THIS, _In_ ULONG Flags, @@ -332,7 +332,7 @@ DECLARE_INTERFACE_IID(IStartMenuAppItems62, IUnknown) STDMETHOD(EnumItems)(THIS, _In_ ULONG Flags, _In_ REFIID riid, - _Outptr_ IEnumObjects *ppvObject + _Outptr_ IEnumObjects **ppvObject ) PURE; STDMETHOD(GetItem)(THIS, _In_ ULONG Flags, From 68728c2aaa85c509d4069b29a91974694b63a405 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 21 Aug 2018 22:10:05 +1000 Subject: [PATCH 1324/2058] Add PhGetUserDefaultLocaleName --- phlib/util.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/phlib/util.c b/phlib/util.c index 1bb13f059a9f..96d4fbcf9fad 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -229,6 +229,20 @@ LCID PhGetUserDefaultLCID( return MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), SORT_DEFAULT); } +LCID PhGetCurrentThreadLCID( + VOID + ) +{ + PTEB currentTeb; + + currentTeb = NtCurrentTeb(); + + if (!currentTeb->CurrentLocale) + currentTeb->CurrentLocale = PhGetUserDefaultLCID(); + + return currentTeb->CurrentLocale; +} + LANGID PhGetSystemDefaultLangID( VOID ) @@ -255,6 +269,23 @@ LANGID PhGetUserDefaultUILanguage( return MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT); } +PPH_STRING PhGetUserDefaultLocaleName( + VOID + ) +{ + UNICODE_STRING localeNameUs; + WCHAR localeName[LOCALE_NAME_MAX_LENGTH]; + + RtlInitEmptyUnicodeString(&localeNameUs, localeName, sizeof(localeName)); + + if (NT_SUCCESS(RtlLcidToLocaleName(PhGetUserDefaultLCID(), &localeNameUs, 0, FALSE))) + { + return PhCreateString(localeName); + } + + return NULL; +} + /** * Gets a string stored in a DLL's message table. * From f34b6f64c1cb25e20150f582c744cd23cf393181 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 21 Aug 2018 22:10:59 +1000 Subject: [PATCH 1325/2058] Update error text, Add PhIsProcessSuspended --- ProcessHacker/appsup.c | 28 ++++++++++++++++++++++++++-- ProcessHacker/include/appsup.h | 7 +++++++ 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/ProcessHacker/appsup.c b/ProcessHacker/appsup.c index a7b53d38a365..6875875f76a9 100644 --- a/ProcessHacker/appsup.c +++ b/ProcessHacker/appsup.c @@ -72,6 +72,24 @@ BOOLEAN PhGetProcessIsSuspended( return Process->NumberOfThreads != 0; } +BOOLEAN PhIsProcessSuspended( + _In_ HANDLE ProcessId + ) +{ + PVOID processes; + PSYSTEM_PROCESS_INFORMATION process; + + if (NT_SUCCESS(PhEnumProcesses(&processes))) + { + if (process = PhFindProcessInformation(processes, ProcessId)) + return PhGetProcessIsSuspended(process); + + PhFree(processes); + } + + return FALSE; +} + /** * Determines the OS compatibility context of a process. * @@ -828,12 +846,18 @@ VOID PhShellExecuteUserString( if (ErrorMessage) { ntMessage = PhGetNtMessage(status); - PhShowError(hWnd, L"Unable to execute the command: %s\n%s", PhGetStringOrDefault(ntMessage, L"An unknown error occurred."), ErrorMessage); + PhShowError2( + hWnd, + L"Unable to execute the command.", + L"%s\n%s", + PhGetStringOrDefault(ntMessage, L"An unknown error occurred."), + ErrorMessage + ); PhDereferenceObject(ntMessage); } else { - PhShowStatus(hWnd, L"Unable to execute the command", status, 0); + PhShowStatus(hWnd, L"Unable to execute the command.", status, 0); } } } diff --git a/ProcessHacker/include/appsup.h b/ProcessHacker/include/appsup.h index 128b3cbe227b..0035b4e37c5b 100644 --- a/ProcessHacker/include/appsup.h +++ b/ProcessHacker/include/appsup.h @@ -15,6 +15,13 @@ NTAPI PhGetProcessIsSuspended( _In_ PSYSTEM_PROCESS_INFORMATION Process ); + +PHAPPAPI +BOOLEAN +NTAPI +PhIsProcessSuspended( + _In_ HANDLE ProcessId + ); // end_phapppub NTSTATUS PhGetProcessSwitchContext( From 440837e373d98f0e11edf5139b8b0007dccd257d Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 24 Aug 2018 09:34:35 +1000 Subject: [PATCH 1326/2058] Add workaround for console '\Device\ConDrv\CurrentIn' handle properties --- ProcessHacker/hndlprp.c | 139 +++++++++++++++++++++++---------------- phlib/hndlinfo.c | 36 +++++++++- phlib/include/hndlinfo.h | 10 +++ 3 files changed, 126 insertions(+), 59 deletions(-) diff --git a/ProcessHacker/hndlprp.c b/ProcessHacker/hndlprp.c index c25a05ed9796..cb38d34bd76c 100644 --- a/ProcessHacker/hndlprp.c +++ b/ProcessHacker/hndlprp.c @@ -664,6 +664,7 @@ VOID PhpUpdateHandleGeneral( { BOOLEAN disableFlushButton = FALSE; BOOLEAN isFileOrDirectory = FALSE; + BOOLEAN isConsoleHandle = FALSE; FILE_FS_DEVICE_INFORMATION fileDeviceInfo; FILE_MODE_INFORMATION fileModeInfo; FILE_STANDARD_INFORMATION fileStandardInfo; @@ -694,19 +695,39 @@ VOID PhpUpdateHandleGeneral( isFileOrDirectory = TRUE; PhSetListViewSubItem(Context->ListViewHandle, Context->ListViewRowCache[PH_HANDLE_GENERAL_INDEX_FILETYPE], 1, L"File or directory"); break; + case FILE_DEVICE_CONSOLE: + isConsoleHandle = TRUE; + PhSetListViewSubItem(Context->ListViewHandle, Context->ListViewRowCache[PH_HANDLE_GENERAL_INDEX_FILETYPE], 1, L"Console"); + break; default: PhSetListViewSubItem(Context->ListViewHandle, Context->ListViewRowCache[PH_HANDLE_GENERAL_INDEX_FILETYPE], 1, L"Other"); break; } } - - if (NT_SUCCESS(NtQueryInformationFile( - fileHandle, - &isb, - &fileModeInfo, - sizeof(FILE_MODE_INFORMATION), - FileModeInformation - ))) + + if (isConsoleHandle) + { + // TODO: We block indefinitely when calling NtQueryInformationFile for '\Device\ConDrv\CurrentIn' + // but we can query other '\Device\ConDrv' console handles (dmex) + status = PhCallNtQueryFileInformationWithTimeout( + fileHandle, + FileModeInformation, + &fileModeInfo, + sizeof(FILE_MODE_INFORMATION) + ); + } + else + { + status = NtQueryInformationFile( + fileHandle, + &isb, + &fileModeInfo, + sizeof(FILE_MODE_INFORMATION), + FileModeInformation + ); + } + + if (NT_SUCCESS(status)) { PH_FORMAT format[5]; PPH_STRING fileModeAccessStr; @@ -732,67 +753,69 @@ VOID PhpUpdateHandleGeneral( PhDereferenceObject(fileModeAccessStr); } - - if (NT_SUCCESS(NtQueryInformationFile( - fileHandle, - &isb, - &fileStandardInfo, - sizeof(FILE_STANDARD_INFORMATION), - FileStandardInformation - ))) - { - PH_FORMAT format[1]; - WCHAR fileSizeString[PH_INT64_STR_LEN]; - PhInitFormatSize(&format[0], fileStandardInfo.EndOfFile.QuadPart); - - if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), fileSizeString, sizeof(fileSizeString), NULL)) - { - PhSetListViewSubItem(Context->ListViewHandle, Context->ListViewRowCache[PH_HANDLE_GENERAL_INDEX_FILESIZE], 1, fileSizeString); - } - - if (isFileOrDirectory) - { - PhSetListViewSubItem(Context->ListViewHandle, Context->ListViewRowCache[PH_HANDLE_GENERAL_INDEX_FILETYPE], 1, fileStandardInfo.Directory ? L"Directory" : L"File"); - } - - disableFlushButton |= fileStandardInfo.Directory; - } - - if (NT_SUCCESS(NtQueryInformationFile( - fileHandle, - &isb, - &filePositionInfo, - sizeof(FILE_POSITION_INFORMATION), - FilePositionInformation - ))) + if (!isConsoleHandle) { - if (filePositionInfo.CurrentByteOffset.QuadPart != 0 && - fileStandardInfo.EndOfFile.QuadPart != 0) + if (NT_SUCCESS(NtQueryInformationFile( + fileHandle, + &isb, + &fileStandardInfo, + sizeof(FILE_STANDARD_INFORMATION), + FileStandardInformation + ))) { - PH_FORMAT format[4]; - WCHAR filePositionString[PH_INT64_STR_LEN]; + PH_FORMAT format[1]; + WCHAR fileSizeString[PH_INT64_STR_LEN]; - PhInitFormatI64UGroupDigits(&format[0], filePositionInfo.CurrentByteOffset.QuadPart); - PhInitFormatS(&format[1], L" ("); - PhInitFormatF(&format[2], (DOUBLE)(filePositionInfo.CurrentByteOffset.QuadPart / fileStandardInfo.EndOfFile.QuadPart * 100), 1); - PhInitFormatS(&format[3], L"%)"); + PhInitFormatSize(&format[0], fileStandardInfo.EndOfFile.QuadPart); - if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), filePositionString, sizeof(filePositionString), NULL)) + if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), fileSizeString, sizeof(fileSizeString), NULL)) { - PhSetListViewSubItem(Context->ListViewHandle, Context->ListViewRowCache[PH_HANDLE_GENERAL_INDEX_FILEPOSITION], 1, filePositionString); + PhSetListViewSubItem(Context->ListViewHandle, Context->ListViewRowCache[PH_HANDLE_GENERAL_INDEX_FILESIZE], 1, fileSizeString); } + + if (isFileOrDirectory) + { + PhSetListViewSubItem(Context->ListViewHandle, Context->ListViewRowCache[PH_HANDLE_GENERAL_INDEX_FILETYPE], 1, fileStandardInfo.Directory ? L"Directory" : L"File"); + } + + disableFlushButton |= fileStandardInfo.Directory; } - else + + if (NT_SUCCESS(NtQueryInformationFile( + fileHandle, + &isb, + &filePositionInfo, + sizeof(FILE_POSITION_INFORMATION), + FilePositionInformation + ))) { - PH_FORMAT format[1]; - WCHAR filePositionString[PH_INT64_STR_LEN]; + if (filePositionInfo.CurrentByteOffset.QuadPart != 0 && fileStandardInfo.EndOfFile.QuadPart != 0) + { + PH_FORMAT format[4]; + WCHAR filePositionString[PH_INT64_STR_LEN]; + + PhInitFormatI64UGroupDigits(&format[0], filePositionInfo.CurrentByteOffset.QuadPart); + PhInitFormatS(&format[1], L" ("); + PhInitFormatF(&format[2], (DOUBLE)(filePositionInfo.CurrentByteOffset.QuadPart / fileStandardInfo.EndOfFile.QuadPart * 100), 1); + PhInitFormatS(&format[3], L"%)"); + + if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), filePositionString, sizeof(filePositionString), NULL)) + { + PhSetListViewSubItem(Context->ListViewHandle, Context->ListViewRowCache[PH_HANDLE_GENERAL_INDEX_FILEPOSITION], 1, filePositionString); + } + } + else if (filePositionInfo.CurrentByteOffset.QuadPart != 0) + { + PH_FORMAT format[1]; + WCHAR filePositionString[PH_INT64_STR_LEN]; - PhInitFormatI64UGroupDigits(&format[0], filePositionInfo.CurrentByteOffset.QuadPart); + PhInitFormatI64UGroupDigits(&format[0], filePositionInfo.CurrentByteOffset.QuadPart); - if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), filePositionString, sizeof(filePositionString), NULL)) - { - PhSetListViewSubItem(Context->ListViewHandle, Context->ListViewRowCache[PH_HANDLE_GENERAL_INDEX_FILEPOSITION], 1, filePositionString); + if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), filePositionString, sizeof(filePositionString), NULL)) + { + PhSetListViewSubItem(Context->ListViewHandle, Context->ListViewRowCache[PH_HANDLE_GENERAL_INDEX_FILEPOSITION], 1, filePositionString); + } } } } diff --git a/phlib/hndlinfo.c b/phlib/hndlinfo.c index f33ec0c1d667..3f88f5b75eb5 100644 --- a/phlib/hndlinfo.c +++ b/phlib/hndlinfo.c @@ -45,7 +45,8 @@ typedef enum _PHP_QUERY_OBJECT_WORK { NtQueryObjectWork, NtQuerySecurityObjectWork, - NtSetSecurityObjectWork + NtSetSecurityObjectWork, + NtQueryFileInformation } PHP_QUERY_OBJECT_WORK; typedef struct _PHP_QUERY_OBJECT_COMMON_CONTEXT @@ -1700,6 +1701,19 @@ NTSTATUS PhpCommonQueryObjectRoutine( context->u.NtSetSecurityObject.SecurityDescriptor ); break; + case NtQueryFileInformation: + { + IO_STATUS_BLOCK isb; + + context->Status = NtQueryInformationFile( + context->u.NtQueryObject.Handle, + &isb, + context->u.NtQueryObject.ObjectInformation, + context->u.NtQueryObject.ObjectInformationLength, + context->u.NtQueryObject.ObjectInformationClass + ); + } + break; default: context->Status = STATUS_INVALID_PARAMETER; break; @@ -1787,3 +1801,23 @@ NTSTATUS PhCallNtSetSecurityObjectWithTimeout( return PhpCommonQueryObjectWithTimeout(context); } + +NTSTATUS PhCallNtQueryFileInformationWithTimeout( + _In_ HANDLE Handle, + _In_ OBJECT_INFORMATION_CLASS ObjectInformationClass, + _Out_writes_bytes_opt_(ObjectInformationLength) PVOID ObjectInformation, + _In_ ULONG ObjectInformationLength + ) +{ + PPHP_QUERY_OBJECT_COMMON_CONTEXT context; + + context = PhAllocate(sizeof(PHP_QUERY_OBJECT_COMMON_CONTEXT)); + context->Work = NtQueryFileInformation; + context->Status = STATUS_UNSUCCESSFUL; + context->u.NtQueryObject.Handle = Handle; + context->u.NtQueryObject.ObjectInformationClass = ObjectInformationClass; + context->u.NtQueryObject.ObjectInformation = ObjectInformation; + context->u.NtQueryObject.ObjectInformationLength = ObjectInformationLength; + + return PhpCommonQueryObjectWithTimeout(context); +} diff --git a/phlib/include/hndlinfo.h b/phlib/include/hndlinfo.h index fb0849f524b9..8c81c27a26cd 100644 --- a/phlib/include/hndlinfo.h +++ b/phlib/include/hndlinfo.h @@ -131,6 +131,16 @@ PhCallNtSetSecurityObjectWithTimeout( _In_ PSECURITY_DESCRIPTOR SecurityDescriptor ); +PHLIBAPI +NTSTATUS +NTAPI +PhCallNtQueryFileInformationWithTimeout( + _In_ HANDLE Handle, + _In_ OBJECT_INFORMATION_CLASS ObjectInformationClass, + _Out_writes_bytes_opt_(ObjectInformationLength) PVOID ObjectInformation, + _In_ ULONG ObjectInformationLength + ); + #ifdef __cplusplus } #endif From a9f06c8c8d04221853ce2dc225a56dda4e87b3f3 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 24 Aug 2018 09:46:20 +1000 Subject: [PATCH 1327/2058] Fix typo --- phlib/hndlinfo.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/phlib/hndlinfo.c b/phlib/hndlinfo.c index 3f88f5b75eb5..2348bf4284eb 100644 --- a/phlib/hndlinfo.c +++ b/phlib/hndlinfo.c @@ -46,7 +46,7 @@ typedef enum _PHP_QUERY_OBJECT_WORK NtQueryObjectWork, NtQuerySecurityObjectWork, NtSetSecurityObjectWork, - NtQueryFileInformation + NtQueryFileInformationWork } PHP_QUERY_OBJECT_WORK; typedef struct _PHP_QUERY_OBJECT_COMMON_CONTEXT @@ -1701,7 +1701,7 @@ NTSTATUS PhpCommonQueryObjectRoutine( context->u.NtSetSecurityObject.SecurityDescriptor ); break; - case NtQueryFileInformation: + case NtQueryFileInformationWork: { IO_STATUS_BLOCK isb; @@ -1812,7 +1812,7 @@ NTSTATUS PhCallNtQueryFileInformationWithTimeout( PPHP_QUERY_OBJECT_COMMON_CONTEXT context; context = PhAllocate(sizeof(PHP_QUERY_OBJECT_COMMON_CONTEXT)); - context->Work = NtQueryFileInformation; + context->Work = NtQueryFileInformationWork; context->Status = STATUS_UNSUCCESSFUL; context->u.NtQueryObject.Handle = Handle; context->u.NtQueryObject.ObjectInformationClass = ObjectInformationClass; From 7c551e31a9008c322bc637d1428f26b36f17b6a0 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 24 Aug 2018 10:23:22 +1000 Subject: [PATCH 1328/2058] Fix find handles window sorting regression --- ProcessHacker/findobj.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/ProcessHacker/findobj.c b/ProcessHacker/findobj.c index 294b71ef0114..908e837960c0 100644 --- a/ProcessHacker/findobj.c +++ b/ProcessHacker/findobj.c @@ -113,7 +113,7 @@ typedef enum _PH_HANDLE_OBJECT_TREE_COLUMN_ITEM_NAME typedef struct _PH_HANDLE_OBJECT_TREE_ROOT_NODE { PH_TREENEW_NODE Node; - + ULONG64 UniqueId; // used to stabilize sorting PHP_OBJECT_RESULT_TYPE ResultType; PVOID HandleObject; HANDLE Handle; @@ -143,7 +143,7 @@ typedef struct _PH_HANDLE_OBJECT_TREE_ROOT_NODE #define END_SORT_FUNCTION \ if (sortResult == 0) \ - sortResult = uintptrcmp((ULONG_PTR)node1->Node.Index, (ULONG_PTR)node2->Node.Index); \ + sortResult = uintptrcmp((ULONG_PTR)node1->UniqueId, (ULONG_PTR)node2->UniqueId); \ \ return PhModifySort(sortResult, ((PPH_HANDLE_SEARCH_CONTEXT)_context)->TreeNewSortOrder); \ } @@ -241,11 +241,11 @@ PPH_HANDLE_OBJECT_TREE_ROOT_NODE AddHandleObjectNode( _In_ HANDLE Handle ) { + static ULONG64 NextUniqueId = 0; PPH_HANDLE_OBJECT_TREE_ROOT_NODE handleObjectNode; handleObjectNode = PhCreateAlloc(sizeof(PH_HANDLE_OBJECT_TREE_ROOT_NODE)); memset(handleObjectNode, 0, sizeof(PH_HANDLE_OBJECT_TREE_ROOT_NODE)); - PhInitializeTreeNewNode(&handleObjectNode->Node); memset(handleObjectNode->TextCache, 0, sizeof(PH_STRINGREF) * PH_OBJECT_SEARCH_TREE_COLUMN_MAXIMUM); @@ -253,6 +253,7 @@ PPH_HANDLE_OBJECT_TREE_ROOT_NODE AddHandleObjectNode( handleObjectNode->Node.TextCacheSize = PH_OBJECT_SEARCH_TREE_COLUMN_MAXIMUM; handleObjectNode->Handle = Handle; + handleObjectNode->UniqueId = ++NextUniqueId; PhAddEntryHashtable(Context->NodeHashtable, &handleObjectNode); PhAddItemList(Context->NodeList, handleObjectNode); From 2d89b0d4f6e6304e11ab5ca04fa6e102bac7749d Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 4 Sep 2018 07:23:24 +1000 Subject: [PATCH 1329/2058] Fix highlighting .NET modules loaded by 3rd party CLR runtimes --- ProcessHacker/modprv.c | 49 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 44 insertions(+), 5 deletions(-) diff --git a/ProcessHacker/modprv.c b/ProcessHacker/modprv.c index 99e3fba20010..af87f1d1fd97 100644 --- a/ProcessHacker/modprv.c +++ b/ProcessHacker/modprv.c @@ -3,6 +3,7 @@ * module provider * * Copyright (C) 2009-2016 wj32 + * Copyright (C) 2017-2018 dmex * * This file is part of Process Hacker. * @@ -41,6 +42,7 @@ typedef struct _PH_MODULE_QUERY_DATA VERIFY_RESULT VerifyResult; PPH_STRING VerifySignerName; + ULONG ImageFlags; } PH_MODULE_QUERY_DATA, *PPH_MODULE_QUERY_DATA; VOID NTAPI PhpModuleProviderDeleteProcedure( @@ -318,6 +320,7 @@ NTSTATUS PhpModuleQueryWorker( ) { PPH_MODULE_QUERY_DATA data = (PPH_MODULE_QUERY_DATA)Parameter; + PH_MAPPED_IMAGE mappedImage = { 0 }; data->VerifyResult = PhVerifyFileCached( data->ModuleItem->FileName, @@ -326,6 +329,42 @@ NTSTATUS PhpModuleQueryWorker( FALSE ); + if (data->ModuleProvider->ProcessId != NtCurrentProcessId()) + { + // HACK HACK HACK + // 3rd party CLR's don't set the LDRP_COR_IMAGE flag so we'll check binaries for a CLR section and set the flag ourselves. + // This is needed to detect standard .NET images loaded by .NET core, Mono and other CLR runtimes. + if (NT_SUCCESS(PhLoadMappedImageEx(PhGetString(data->ModuleItem->FileName), NULL, TRUE, &mappedImage))) + { + if (mappedImage.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) + { + PIMAGE_OPTIONAL_HEADER32 optionalHeader = (PIMAGE_OPTIONAL_HEADER32)&mappedImage.NtHeaders->OptionalHeader; + + if (optionalHeader->NumberOfRvaAndSizes >= IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR) + { + if (optionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress) + { + data->ImageFlags |= LDRP_COR_IMAGE; + } + } + } + else if (mappedImage.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) + { + PIMAGE_OPTIONAL_HEADER64 optionalHeader = (PIMAGE_OPTIONAL_HEADER64)&mappedImage.NtHeaders->OptionalHeader; + + if (optionalHeader->NumberOfRvaAndSizes >= IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR) + { + if (optionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress) + { + data->ImageFlags |= LDRP_COR_IMAGE; + } + } + } + + PhUnloadMappedImage(&mappedImage); + } + } + RtlInterlockedPushEntrySList(&data->ModuleProvider->QueryListHead, &data->ListEntry); PhDereferenceObject(data->ModuleProvider); @@ -341,8 +380,8 @@ VOID PhpQueueModuleQuery( PPH_MODULE_QUERY_DATA data; PH_WORK_QUEUE_ENVIRONMENT environment; - if (!PhEnableProcessQueryStage2) - return; + //if (!PhEnableProcessQueryStage2) // (dmex) + // return; data = PhAllocate(sizeof(PH_MODULE_QUERY_DATA)); memset(data, 0, sizeof(PH_MODULE_QUERY_DATA)); @@ -466,6 +505,7 @@ VOID PhModuleProviderUpdate( data->ModuleItem->VerifyResult = data->VerifyResult; data->ModuleItem->VerifySignerName = data->VerifySignerName; + data->ModuleItem->Flags |= data->ImageFlags; data->ModuleItem->JustProcessed = TRUE; PhDereferenceObject(data->ModuleItem); @@ -604,11 +644,10 @@ VOID PhModuleProviderUpdate( if (moduleItem->Type != PH_MODULE_TYPE_ELF_MAPPED_IMAGE) { // See if the file has already been verified; if not, queue for verification. - moduleItem->VerifyResult = PhVerifyFileCached(moduleItem->FileName, NULL, &moduleItem->VerifySignerName, TRUE); - if (moduleItem->VerifyResult == VrUnknown) - PhpQueueModuleQuery(moduleProvider, moduleItem); + //if (moduleItem->VerifyResult == VrUnknown) // (dmex) + PhpQueueModuleQuery(moduleProvider, moduleItem); } // Add the module item to the hashtable. From 4278b4986ce403005f2864d3ce96ab73284e719b Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 4 Sep 2018 10:26:30 +1000 Subject: [PATCH 1330/2058] Fix previous commit --- ProcessHacker/modprv.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/ProcessHacker/modprv.c b/ProcessHacker/modprv.c index af87f1d1fd97..7bf081799a7a 100644 --- a/ProcessHacker/modprv.c +++ b/ProcessHacker/modprv.c @@ -322,16 +322,19 @@ NTSTATUS PhpModuleQueryWorker( PPH_MODULE_QUERY_DATA data = (PPH_MODULE_QUERY_DATA)Parameter; PH_MAPPED_IMAGE mappedImage = { 0 }; - data->VerifyResult = PhVerifyFileCached( - data->ModuleItem->FileName, - data->ModuleProvider->PackageFullName, - &data->VerifySignerName, - FALSE - ); + if (PhEnableProcessQueryStage2) // HACK (dmex) + { + data->VerifyResult = PhVerifyFileCached( + data->ModuleItem->FileName, + data->ModuleProvider->PackageFullName, + &data->VerifySignerName, + FALSE + ); + } if (data->ModuleProvider->ProcessId != NtCurrentProcessId()) { - // HACK HACK HACK + // HACK HACK HACK (dmex) // 3rd party CLR's don't set the LDRP_COR_IMAGE flag so we'll check binaries for a CLR section and set the flag ourselves. // This is needed to detect standard .NET images loaded by .NET core, Mono and other CLR runtimes. if (NT_SUCCESS(PhLoadMappedImageEx(PhGetString(data->ModuleItem->FileName), NULL, TRUE, &mappedImage))) @@ -380,9 +383,6 @@ VOID PhpQueueModuleQuery( PPH_MODULE_QUERY_DATA data; PH_WORK_QUEUE_ENVIRONMENT environment; - //if (!PhEnableProcessQueryStage2) // (dmex) - // return; - data = PhAllocate(sizeof(PH_MODULE_QUERY_DATA)); memset(data, 0, sizeof(PH_MODULE_QUERY_DATA)); data->ModuleProvider = ModuleProvider; From 761a04d9c528f16025be0e12734e6b9085dc857c Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 4 Sep 2018 10:26:51 +1000 Subject: [PATCH 1331/2058] Improve symbol event memory usage --- phlib/symprv.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/phlib/symprv.c b/phlib/symprv.c index ed59033f9081..ffffff5ce864 100644 --- a/phlib/symprv.c +++ b/phlib/symprv.c @@ -191,17 +191,15 @@ BOOL CALLBACK PhpSymbolCallbackFunction( if (!IsListEmpty(&PhSymbolEventCallback.ListHead)) { - PPH_SYMBOL_EVENT_DATA data; + PH_SYMBOL_EVENT_DATA data; - data = PhAllocateZero(sizeof(PH_SYMBOL_EVENT_DATA)); - data->ActionCode = ActionCode; - data->ProcessHandle = ProcessHandle; - data->SymbolProvider = symbolProvider; - data->EventData = (PVOID)CallbackData; + memset(&data, 0, sizeof(PH_SYMBOL_EVENT_DATA)); + data.ActionCode = ActionCode; + data.ProcessHandle = ProcessHandle; + data.SymbolProvider = symbolProvider; + data.EventData = (PVOID)CallbackData; - PhInvokeCallback(&PhSymbolEventCallback, data); - - PhFree(data); + PhInvokeCallback(&PhSymbolEventCallback, &data); } if (ActionCode == CBA_DEFERRED_SYMBOL_LOAD_CANCEL) From 8b144568e4ed59a14c5d8d6ca2fc9e67d7e0c4a3 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 4 Sep 2018 13:29:40 +1000 Subject: [PATCH 1332/2058] Fix json-c library exporting unused functions --- phlib/jsonc/json_object.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/phlib/jsonc/json_object.h b/phlib/jsonc/json_object.h index 7abf821591d1..fda7c6509862 100644 --- a/phlib/jsonc/json_object.h +++ b/phlib/jsonc/json_object.h @@ -33,11 +33,11 @@ #define JSON_C_CONST_FUNCTION(func) func #endif -#if defined(_MSC_VER) -#define JSON_EXPORT __declspec(dllexport) -#else +//#if defined(_MSC_VER) -- (disable dllexport - dmex) +//#define JSON_EXPORT __declspec(dllexport) +//#else #define JSON_EXPORT extern -#endif +//#endif #include #include "json_inttypes.h" From 213cf46a8c72946a7da9acbe45a195fc43795e85 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 5 Sep 2018 06:12:14 +1000 Subject: [PATCH 1333/2058] Fix PhLoadMappedImageEx memory leak --- ProcessHacker/modprv.c | 1 - phlib/mapimg.c | 24 +++++++++++------------- 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/ProcessHacker/modprv.c b/ProcessHacker/modprv.c index 7bf081799a7a..4590686a9dce 100644 --- a/ProcessHacker/modprv.c +++ b/ProcessHacker/modprv.c @@ -332,7 +332,6 @@ NTSTATUS PhpModuleQueryWorker( ); } - if (data->ModuleProvider->ProcessId != NtCurrentProcessId()) { // HACK HACK HACK (dmex) // 3rd party CLR's don't set the LDRP_COR_IMAGE flag so we'll check binaries for a CLR section and set the flag ourselves. diff --git a/phlib/mapimg.c b/phlib/mapimg.c index 947cde2e2d4f..13d499d8996d 100644 --- a/phlib/mapimg.c +++ b/phlib/mapimg.c @@ -179,18 +179,9 @@ NTSTATUS PhLoadMappedImageEx( if (NT_SUCCESS(status)) { - PUSHORT imageHeaderSignature = viewBase; - - __try - { - PhProbeAddress(imageHeaderSignature, sizeof(USHORT), viewBase, size, 1); - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - return GetExceptionCode(); - } - - MappedImage->Signature = *imageHeaderSignature; + MappedImage->Signature = *(PUSHORT)viewBase; + MappedImage->ViewBase = viewBase; + MappedImage->Size = size; switch (MappedImage->Signature) { @@ -212,6 +203,14 @@ NTSTATUS PhLoadMappedImageEx( ); } break; + default: + status = STATUS_IMAGE_SUBSYSTEM_NOT_PRESENT; + break; + } + + if (!NT_SUCCESS(status)) + { + PhUnloadMappedImage(MappedImage); } } @@ -1709,4 +1708,3 @@ NTSTATUS PhGetMappedImageResources( CleanupExit: return status; } - \ No newline at end of file From bbc9c2554cc0b71e5a725de43b6b5e8cd60d051c Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 6 Sep 2018 16:08:48 +1000 Subject: [PATCH 1334/2058] Fix theme header subclass callback --- phlib/theme.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phlib/theme.c b/phlib/theme.c index 5d590f9ae624..8e418acc28e8 100644 --- a/phlib/theme.c +++ b/phlib/theme.c @@ -1865,7 +1865,7 @@ LRESULT CALLBACK PhpThemeWindowHeaderSubclassProc( break; case WM_CONTEXTMENU: { - LRESULT result = DefSubclassProc(WindowHandle, uMsg, wParam, lParam); + LRESULT result = CallWindowProc(oldWndProc, WindowHandle, uMsg, wParam, lParam); InvalidateRect(WindowHandle, NULL, TRUE); From 0759898766bbf86be6d868f571f691080b2aa20b Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 6 Sep 2018 16:20:16 +1000 Subject: [PATCH 1335/2058] Disable WER restart policy (testing #304) --- ProcessHacker/mainwnd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index 3f2266e186aa..4a1d06bd6472 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -518,7 +518,7 @@ NTSTATUS PhMwpLoadStage1Worker( // Make sure we get closed late in the shutdown process. SetProcessShutdownParameters(0x100, 0); - PhInitializeRestartPolicy(); + //PhInitializeRestartPolicy(); DelayedLoadCompleted = TRUE; //PostMessage(PhMainWndHandle, WM_PH_DELAYED_LOAD_COMPLETED, 0, 0); From adceecbdb72edd1ed16185fcd533a7f85e4b2581 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 12 Sep 2018 15:41:44 +1000 Subject: [PATCH 1336/2058] Update to latest SDK, Fix build warnings, Fix #308 --- KProcessHacker/KProcessHacker.vcxproj | 4 +++- KProcessHacker/verify.c | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/KProcessHacker/KProcessHacker.vcxproj b/KProcessHacker/KProcessHacker.vcxproj index b19957e7dee6..95ecf78472ad 100644 --- a/KProcessHacker/KProcessHacker.vcxproj +++ b/KProcessHacker/KProcessHacker.vcxproj @@ -28,7 +28,7 @@ KProcessHacker $(VCTargetsPath11) - 10.0.16299.0 + 10.0.17134.0 WindowsKernelModeDriver10.0 @@ -97,6 +97,7 @@ Level3 true true + false ksecdd.lib;%(AdditionalDependencies) @@ -123,6 +124,7 @@ Level3 true true + false ksecdd.lib;%(AdditionalDependencies) diff --git a/KProcessHacker/verify.c b/KProcessHacker/verify.c index 3d097c62128d..8756f17f2afb 100644 --- a/KProcessHacker/verify.c +++ b/KProcessHacker/verify.c @@ -347,7 +347,7 @@ NTSTATUS KpiVerifyClient( return GetExceptionCode(); } - KphVerifyClient(Client, CodeAddress, Signature, SignatureSize); + KphVerifyClient(Client, CodeAddress, signature, SignatureSize); ExFreePoolWithTag(signature, 'ThpK'); return Client->VerificationStatus; From 4e59943fea2f4ece58cf369aadbdab4498d0fbaf Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 12 Sep 2018 16:05:09 +1000 Subject: [PATCH 1337/2058] peview: Fix #307 (crash on vanilla Win7 without KB2533623) --- tools/peview/impprp.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/tools/peview/impprp.c b/tools/peview/impprp.c index 4b59bfe52bbd..50265137969b 100644 --- a/tools/peview/impprp.c +++ b/tools/peview/impprp.c @@ -88,7 +88,18 @@ VOID PvpProcessImports( PPH_STRING baseDirectory; if (baseDirectory = PhGetBaseDirectory(PvFileName)) - AddDllDirectory(baseDirectory->Buffer); + { + static DLL_DIRECTORY_COOKIE (WINAPI *AddDllDirectory_I)( + _In_ PCWSTR NewDirectory + ); + + if (AddDllDirectory_I = PhGetDllProcedureAddress(L"kernel32.dll", "AddDllDirectory", 0)) + { + // HACK (dmex) + // Add the parent directory to the search path so we can locate exports from 3rd party binaries. + AddDllDirectory_I(baseDirectory->Buffer); + } + } if (importModuleDllBase = LoadLibraryA(importDll.Name)) { From 403de13535319fecbffbb269a9a91a04b78dabdd Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 12 Sep 2018 16:11:33 +1000 Subject: [PATCH 1338/2058] Fix crash when EnablePlugins disabled (regression) --- ProcessHacker/include/phapp.h | 2 +- ProcessHacker/main.c | 2 +- ProcessHacker/plugin.c | 18 ++++++++---------- 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/ProcessHacker/include/phapp.h b/ProcessHacker/include/phapp.h index 431098df41f8..781535811cfb 100644 --- a/ProcessHacker/include/phapp.h +++ b/ProcessHacker/include/phapp.h @@ -131,7 +131,7 @@ VOID PhInitializeFont( extern PH_AVL_TREE PhPluginsByName; -VOID PhPluginsInitialization( +VOID PhInitializeCallbacks( VOID ); diff --git a/ProcessHacker/main.c b/ProcessHacker/main.c index 225bf4a49480..84a3b94a0415 100644 --- a/ProcessHacker/main.c +++ b/ProcessHacker/main.c @@ -171,6 +171,7 @@ INT WINAPI wWinMain( PhInitializeAutoPool(&BaseAutoPool); PhInitializeAppSystem(); + PhInitializeCallbacks(); PhInitializeCommonControls(); PhEmInitialization(); @@ -188,7 +189,6 @@ INT WINAPI wWinMain( if (PhPluginsEnabled = PhGetIntegerSetting(L"EnablePlugins") && !PhStartupParameters.NoPlugins) { - PhPluginsInitialization(); PhLoadPlugins(); } diff --git a/ProcessHacker/plugin.c b/ProcessHacker/plugin.c index f686d8d7639b..36945e74a491 100644 --- a/ProcessHacker/plugin.c +++ b/ProcessHacker/plugin.c @@ -65,16 +65,6 @@ static PH_CALLBACK GeneralCallbacks[GeneralCallbackMaximum]; static PPH_STRING PluginsDirectory; static ULONG NextPluginId = IDPLUGINS + 1; -VOID PhPluginsInitialization( - VOID - ) -{ - ULONG i; - - for (i = 0; i < GeneralCallbackMaximum; i++) - PhInitializeCallback(&GeneralCallbacks[i]); -} - INT NTAPI PhpPluginsCompareFunction( _In_ PPH_AVL_LINKS Links1, _In_ PPH_AVL_LINKS Links2 @@ -663,6 +653,14 @@ PPH_CALLBACK PhGetPluginCallback( return &Plugin->Callbacks[Callback]; } +VOID PhInitializeCallbacks( // HACK (dmex) + VOID + ) +{ + for (ULONG i = 0; i < GeneralCallbackMaximum; i++) + PhInitializeCallback(&GeneralCallbacks[i]); +} + /** * Retrieves a pointer to a general callback. * From 58d938605494b3b314a8ea0a23f7dfcf0bca51bf Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 12 Sep 2018 16:15:05 +1000 Subject: [PATCH 1339/2058] Fix commit 0759898 --- ProcessHacker/main.c | 4 ++-- ProcessHacker/mainwnd.c | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/ProcessHacker/main.c b/ProcessHacker/main.c index 84a3b94a0415..092c9a75a21e 100644 --- a/ProcessHacker/main.c +++ b/ProcessHacker/main.c @@ -121,8 +121,8 @@ INT WINAPI wWinMain( return 1; if (!PhInitializeMitigationPolicy()) return 1; - if (!PhInitializeRestartPolicy()) - return 1; + //if (!PhInitializeRestartPolicy()) + // return 1; PhpProcessStartupParameters(); PhpEnablePrivileges(); diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index 4a1d06bd6472..f8b594b8cf3f 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -517,8 +517,7 @@ NTSTATUS PhMwpLoadStage1Worker( PhNfLoadStage2(); // Make sure we get closed late in the shutdown process. - SetProcessShutdownParameters(0x100, 0); - //PhInitializeRestartPolicy(); + SetProcessShutdownParameters(0x100, 0); DelayedLoadCompleted = TRUE; //PostMessage(PhMainWndHandle, WM_PH_DELAYED_LOAD_COMPLETED, 0, 0); From 6628635b30960bd262d1b0feb0fca67a7296bd09 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 12 Sep 2018 16:16:21 +1000 Subject: [PATCH 1340/2058] Fix crash when renaming processhacker.exe to avoid malware (regression) --- phlib/util.c | 122 +++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 119 insertions(+), 3 deletions(-) diff --git a/phlib/util.c b/phlib/util.c index 96d4fbcf9fad..1baf782cae30 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -5883,6 +5883,114 @@ static NTSTATUS PhpFixupLoaderEntryImageImports( return status; } +static NTSTATUS PhpFixupLoaderEntryImageDelayImports( + _In_ PVOID BaseAddress, + _In_ PIMAGE_NT_HEADERS ImageNtHeader + ) +{ + NTSTATUS status; + SIZE_T importDirectorySize; + ULONG importDirectoryProtect; + PIMAGE_DATA_DIRECTORY dataDirectory; + PIMAGE_DELAYLOAD_DESCRIPTOR delayImportDirectory; + PIMAGE_SECTION_HEADER importDirectorySection; + + status = PhGetLoaderEntryImageDirectory( + BaseAddress, + ImageNtHeader, + IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT, + &dataDirectory, + &delayImportDirectory, + NULL + ); + + if (!NT_SUCCESS(status)) + { + if (status == STATUS_INVALID_FILE_FOR_SECTION) + status = STATUS_SUCCESS; + + goto CleanupExit; + } + + status = PhGetLoaderEntryImageSection( + BaseAddress, + ImageNtHeader, + delayImportDirectory, + &importDirectorySection, + &importDirectorySize + ); + + if (!NT_SUCCESS(status)) + goto CleanupExit; + + status = NtProtectVirtualMemory( + NtCurrentProcess(), + &importDirectorySection, + &importDirectorySize, + PAGE_READWRITE, + &importDirectoryProtect + ); + + if (!NT_SUCCESS(status)) + goto CleanupExit; + + for (delayImportDirectory = delayImportDirectory; delayImportDirectory->DllNameRVA; delayImportDirectory++) + { + PSTR importName; + PIMAGE_THUNK_DATA importThunk; + PIMAGE_THUNK_DATA originalThunk; + + importName = PTR_ADD_OFFSET(BaseAddress, delayImportDirectory->DllNameRVA); + importThunk = PTR_ADD_OFFSET(BaseAddress, delayImportDirectory->ImportAddressTableRVA); + originalThunk = PTR_ADD_OFFSET(BaseAddress, delayImportDirectory->ImportNameTableRVA); + + if (PhEqualBytesZ(importName, "ProcessHacker.exe", TRUE)) + { + for ( + originalThunk = originalThunk, importThunk = importThunk; + originalThunk->u1.AddressOfData; + originalThunk++, importThunk++ + ) + { + if (IMAGE_SNAP_BY_ORDINAL(originalThunk->u1.Ordinal)) + { + USHORT procedureOrdinal; + PVOID procedureAddress; + + procedureOrdinal = IMAGE_ORDINAL(originalThunk->u1.Ordinal); + procedureAddress = PhGetDllBaseProcedureAddress(PhInstanceHandle, NULL, procedureOrdinal); + + importThunk->u1.Function = (ULONG_PTR)procedureAddress; + } + else + { + PIMAGE_IMPORT_BY_NAME importByName; + PVOID procedureAddress; + + importByName = PTR_ADD_OFFSET(BaseAddress, originalThunk->u1.AddressOfData); + procedureAddress = PhGetDllBaseProcedureAddress(PhInstanceHandle, importByName->Name, 0); + + importThunk->u1.Function = (ULONG_PTR)procedureAddress; + } + } + } + } + + status = NtProtectVirtualMemory( + NtCurrentProcess(), + &importDirectorySection, + &importDirectorySize, + importDirectoryProtect, + &importDirectoryProtect + ); + + if (!NT_SUCCESS(status)) + goto CleanupExit; + +CleanupExit: + return status; +} + // dmex: This function and the other LoaderEntryImage functions don't belong in this file // and should be moved into mapimg.c at some stage. // @@ -5901,15 +6009,15 @@ NTSTATUS PhLoadPluginImage( PVOID imageBaseAddress; PIMAGE_NT_HEADERS imageHeaders; PLDR_INIT_ROUTINE imageEntryRoutine; - UNICODE_STRING fileNameUs; + UNICODE_STRING imageFileNameUs; imageType = IMAGE_FILE_EXECUTABLE_IMAGE; - PhStringRefToUnicodeString(&FileName->sr, &fileNameUs); + PhStringRefToUnicodeString(&FileName->sr, &imageFileNameUs); status = LdrLoadDll( NULL, &imageType, - &fileNameUs, + &imageFileNameUs, &imageBaseAddress ); @@ -5932,6 +6040,14 @@ NTSTATUS PhLoadPluginImage( if (!NT_SUCCESS(status)) goto CleanupExit; + status = PhpFixupLoaderEntryImageDelayImports( + imageBaseAddress, + imageHeaders + ); + + if (!NT_SUCCESS(status)) + goto CleanupExit; + status = PhGetLoaderEntryImageEntryPoint( imageBaseAddress, imageHeaders, From 050a5ac2c665468617eddb5a08825aa8c2e82281 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 12 Sep 2018 19:46:02 +1000 Subject: [PATCH 1341/2058] peview: Block 32bit version from running on 64bit (fixes #307) --- tools/peview/main.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tools/peview/main.c b/tools/peview/main.c index ceaf6704fa6e..deb6e7126985 100644 --- a/tools/peview/main.c +++ b/tools/peview/main.c @@ -87,6 +87,19 @@ INT WINAPI wWinMain( PhDereferenceObject(objectName); } +#ifndef DEBUG + if (PhIsExecutingInWow64()) + { + PhShowWarning( + NULL, + L"You are attempting to run the 32-bit version of PE Viewer on 64-bit Windows. " + L"Most features will not work correctly.\n\n" + L"Please run the 64-bit version of PE Viewer instead." + ); + RtlExitUserProcess(STATUS_IMAGE_SUBSYSTEM_NOT_PRESENT); + } +#endif + PhGuiSupportInitialization(); PhSettingsInitialization(); PeInitializeSettings(); From 74d3fceb1a5b551275e6793a89fd2cdab8292ec3 Mon Sep 17 00:00:00 2001 From: diversenok Date: Wed, 12 Sep 2018 15:04:43 +0300 Subject: [PATCH 1342/2058] Improve coloring and description for tokens groups (#310) --- ProcessHacker/tokprp.c | 60 ++++++++++++++++-------------------------- 1 file changed, 22 insertions(+), 38 deletions(-) diff --git a/ProcessHacker/tokprp.c b/ProcessHacker/tokprp.c index 8335c897d240..033f2d89e529 100644 --- a/ProcessHacker/tokprp.c +++ b/ProcessHacker/tokprp.c @@ -85,6 +85,16 @@ typedef struct _TOKEN_PAGE_CONTEXT ATTRIBUTE_TREE_CONTEXT AuthzTreeContext; } TOKEN_PAGE_CONTEXT, *PTOKEN_PAGE_CONTEXT; +PH_ACCESS_ENTRY GroupDescriptionEntries[6] = +{ +{ NULL, SE_GROUP_INTEGRITY | SE_GROUP_INTEGRITY_ENABLED, FALSE, FALSE, L"Integrity" }, +{ NULL, SE_GROUP_LOGON_ID, FALSE, FALSE, L"Logon Id" }, +{ NULL, SE_GROUP_OWNER, FALSE, FALSE, L"Owner" }, +{ NULL, SE_GROUP_MANDATORY, FALSE, FALSE, L"Mandatory" }, +{ NULL, SE_GROUP_USE_FOR_DENY_ONLY, FALSE, FALSE, L"Use for deny only" }, +{ NULL, SE_GROUP_RESOURCE, FALSE, FALSE, L"Resource" } +}; + INT CALLBACK PhpTokenPropPageProc( _In_ HWND hwnd, _In_ UINT uMsg, @@ -246,7 +256,7 @@ PPH_STRING PhGetGroupAttributesString( if (Attributes & SE_GROUP_ENABLED_BY_DEFAULT) string = PhCreateString(L"Default Enabled"); else if (Attributes & SE_GROUP_ENABLED) - string = PhReferenceEmptyString(); + string = PhCreateString(L"Enabled"); else string = PhCreateString(L"Disabled"); } @@ -261,39 +271,6 @@ PPH_STRING PhGetGroupAttributesString( return string; } -PWSTR PhGetGroupDescriptionString( - _In_ ULONG Attributes - ) -{ - PWSTR baseString; - - if (Attributes & SE_GROUP_INTEGRITY) - { - if (Attributes & SE_GROUP_INTEGRITY_ENABLED) - baseString = L"Integrity"; - else - baseString = NULL; - } - else - { - if (Attributes & SE_GROUP_LOGON_ID) - baseString = L"Logon ID"; - else if (Attributes & SE_GROUP_MANDATORY) - baseString = L"Mandatory"; - else if (Attributes & SE_GROUP_OWNER) - baseString = L"Owner"; - else if (Attributes & SE_GROUP_RESOURCE) - baseString = L"Resource"; - else if (Attributes & SE_GROUP_USE_FOR_DENY_ONLY) - baseString = L"Use for deny only"; - else - baseString = NULL; - } - - return baseString; -} - - COLORREF PhGetGroupAttributesColor( _In_ ULONG Attributes ) @@ -309,7 +286,7 @@ COLORREF PhGetGroupAttributesColor( if (Attributes & SE_GROUP_ENABLED_BY_DEFAULT) return RGB(0xc0, 0xf0, 0xc0); else if (Attributes & SE_GROUP_ENABLED) - return GetSysColor(COLOR_WINDOW); + return RGB(0xe0, 0xf0, 0xe0); else return RGB(0xf0, 0xe0, 0xe0); } @@ -401,7 +378,7 @@ VOID PhpUpdateSidsFromTokenGroups( INT lvItemIndex; PPH_STRING fullName; PPH_STRING attributesString; - PWSTR descriptionString; + PPH_STRING descriptionString; if (!(fullName = PhGetSidFullName(Groups->Groups[i].Sid, TRUE, NULL))) fullName = PhSidToStringSid(Groups->Groups[i].Sid); @@ -430,9 +407,16 @@ VOID PhpUpdateSidsFromTokenGroups( PhDereferenceObject(attributesString); } - if (descriptionString = PhGetGroupDescriptionString(Groups->Groups[i].Attributes)) + descriptionString = PhGetAccessString( + Groups->Groups[i].Attributes, + GroupDescriptionEntries, + RTL_NUMBER_OF(GroupDescriptionEntries) + ); + + if (descriptionString) { - PhSetListViewSubItem(ListViewHandle, lvItemIndex, PH_PROCESS_TOKEN_INDEX_DESCRIPTION, descriptionString); + PhSetListViewSubItem(ListViewHandle, lvItemIndex, PH_PROCESS_TOKEN_INDEX_DESCRIPTION, PhGetString(descriptionString)); + PhDereferenceObject(descriptionString); } PhDereferenceObject(fullName); From 3d0bf79b5aae83a8f414d9d0eac369177aaebbb9 Mon Sep 17 00:00:00 2001 From: diversenok Date: Thu, 13 Sep 2018 02:46:54 +0300 Subject: [PATCH 1343/2058] Highlight modified privileges and groups (#311) --- ProcessHacker/tokprp.c | 98 +++++++++++++++++++++++------------------- 1 file changed, 54 insertions(+), 44 deletions(-) diff --git a/ProcessHacker/tokprp.c b/ProcessHacker/tokprp.c index 033f2d89e529..3755efd30062 100644 --- a/ProcessHacker/tokprp.c +++ b/ProcessHacker/tokprp.c @@ -253,12 +253,20 @@ PPH_STRING PhGetGroupAttributesString( } else { - if (Attributes & SE_GROUP_ENABLED_BY_DEFAULT) - string = PhCreateString(L"Default Enabled"); - else if (Attributes & SE_GROUP_ENABLED) - string = PhCreateString(L"Enabled"); + if (Attributes & SE_GROUP_ENABLED) + { + if (Attributes & SE_GROUP_ENABLED_BY_DEFAULT) + string = PhCreateString(L"Enabled"); + else + string = PhCreateString(L"Enabled (modified)"); + } else - string = PhCreateString(L"Disabled"); + { + if (Attributes & SE_GROUP_ENABLED_BY_DEFAULT) + string = PhCreateString(L"Disabled (modified"); + else + string = PhCreateString(L"Disabled"); + } } if (Restricted) @@ -283,24 +291,40 @@ COLORREF PhGetGroupAttributesColor( return GetSysColor(COLOR_WINDOW); } - if (Attributes & SE_GROUP_ENABLED_BY_DEFAULT) - return RGB(0xc0, 0xf0, 0xc0); - else if (Attributes & SE_GROUP_ENABLED) - return RGB(0xe0, 0xf0, 0xe0); + if (Attributes & SE_GROUP_ENABLED) + { + if (Attributes & SE_GROUP_ENABLED_BY_DEFAULT) + return RGB(0xe0, 0xf0, 0xe0); + else + return RGB(0xc0, 0xf0, 0xc0); + } else - return RGB(0xf0, 0xe0, 0xe0); + { + if (Attributes & SE_GROUP_ENABLED_BY_DEFAULT) + return RGB(0xf0, 0xc0, 0xc0); + else + return RGB(0xf0, 0xe0, 0xe0); + } } COLORREF PhGetPrivilegeAttributesColor( _In_ ULONG Attributes ) { - if (Attributes & SE_PRIVILEGE_ENABLED_BY_DEFAULT) - return RGB(0xc0, 0xf0, 0xc0); - else if (Attributes & SE_PRIVILEGE_ENABLED) - return RGB(0xe0, 0xf0, 0xe0); + if (Attributes & SE_PRIVILEGE_ENABLED) + { + if (Attributes & SE_PRIVILEGE_ENABLED_BY_DEFAULT) + return RGB(0xe0, 0xf0, 0xe0); + else + return RGB(0xc0, 0xf0, 0xc0); + } else - return RGB(0xf0, 0xe0, 0xe0); + { + if (Attributes & SE_PRIVILEGE_ENABLED_BY_DEFAULT) + return RGB(0xf0, 0xc0, 0xc0); + else + return RGB(0xf0, 0xe0, 0xe0); + } } static COLORREF NTAPI PhpTokenGroupColorFunction( @@ -321,12 +345,20 @@ PWSTR PhGetPrivilegeAttributesString( _In_ ULONG Attributes ) { - if (Attributes & SE_PRIVILEGE_ENABLED_BY_DEFAULT) - return L"Default Enabled"; - else if (Attributes & SE_PRIVILEGE_ENABLED) - return L"Enabled"; + if (Attributes & SE_PRIVILEGE_ENABLED) + { + if (Attributes & SE_PRIVILEGE_ENABLED_BY_DEFAULT) + return L"Enabled"; + else + return L"Enabled (modified)"; + } else - return L"Disabled"; + { + if (Attributes & SE_PRIVILEGE_ENABLED_BY_DEFAULT) + return L"Disabled (modified)"; + else + return L"Disabled"; + } } PWSTR PhGetElevationTypeString( @@ -765,38 +797,16 @@ INT_PTR CALLBACK PhpTokenPageProc( switch (LOWORD(wParam)) { case ID_PRIVILEGE_ENABLE: - newAttributes = SE_PRIVILEGE_ENABLED; + newAttributes = listViewItems[i]->TokenPrivilege->Attributes | SE_PRIVILEGE_ENABLED; break; case ID_PRIVILEGE_DISABLE: - newAttributes = 0; + newAttributes = listViewItems[i]->TokenPrivilege->Attributes & ~SE_PRIVILEGE_ENABLED; break; case ID_PRIVILEGE_REMOVE: newAttributes = SE_PRIVILEGE_REMOVED; break; } - // Privileges which are enabled by default cannot be - // modified except to remove them. - - if ( - listViewItems[i]->TokenPrivilege->Attributes & SE_PRIVILEGE_ENABLED_BY_DEFAULT && - LOWORD(wParam) != ID_PRIVILEGE_REMOVE - ) - { - if (LOWORD(wParam) == ID_PRIVILEGE_DISABLE) - { - if (!PhShowContinueStatus( - hwndDlg, - PhaConcatStrings2(L"Unable to disable ", privilegeName->Buffer)->Buffer, - STATUS_UNSUCCESSFUL, - 0 - )) - break; - } - - continue; - } - if (PhSetTokenPrivilege( tokenHandle, NULL, From 77995cd6e3c13179bffdb5ea1c081f836c59e0a5 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 16 Sep 2018 23:03:25 +1000 Subject: [PATCH 1344/2058] Fix #314, Fix tabspace --- ProcessHacker/tokprp.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/ProcessHacker/tokprp.c b/ProcessHacker/tokprp.c index 3755efd30062..c948c515dbe5 100644 --- a/ProcessHacker/tokprp.c +++ b/ProcessHacker/tokprp.c @@ -87,12 +87,12 @@ typedef struct _TOKEN_PAGE_CONTEXT PH_ACCESS_ENTRY GroupDescriptionEntries[6] = { -{ NULL, SE_GROUP_INTEGRITY | SE_GROUP_INTEGRITY_ENABLED, FALSE, FALSE, L"Integrity" }, -{ NULL, SE_GROUP_LOGON_ID, FALSE, FALSE, L"Logon Id" }, -{ NULL, SE_GROUP_OWNER, FALSE, FALSE, L"Owner" }, -{ NULL, SE_GROUP_MANDATORY, FALSE, FALSE, L"Mandatory" }, -{ NULL, SE_GROUP_USE_FOR_DENY_ONLY, FALSE, FALSE, L"Use for deny only" }, -{ NULL, SE_GROUP_RESOURCE, FALSE, FALSE, L"Resource" } + { NULL, SE_GROUP_INTEGRITY | SE_GROUP_INTEGRITY_ENABLED, FALSE, FALSE, L"Integrity" }, + { NULL, SE_GROUP_LOGON_ID, FALSE, FALSE, L"Logon Id" }, + { NULL, SE_GROUP_OWNER, FALSE, FALSE, L"Owner" }, + { NULL, SE_GROUP_MANDATORY, FALSE, FALSE, L"Mandatory" }, + { NULL, SE_GROUP_USE_FOR_DENY_ONLY, FALSE, FALSE, L"Use for deny only" }, + { NULL, SE_GROUP_RESOURCE, FALSE, FALSE, L"Resource" } }; INT CALLBACK PhpTokenPropPageProc( @@ -263,7 +263,7 @@ PPH_STRING PhGetGroupAttributesString( else { if (Attributes & SE_GROUP_ENABLED_BY_DEFAULT) - string = PhCreateString(L"Disabled (modified"); + string = PhCreateString(L"Disabled (modified)"); else string = PhCreateString(L"Disabled"); } @@ -419,9 +419,7 @@ VOID PhpUpdateSidsFromTokenGroups( { PPHP_TOKEN_PAGE_LISTVIEW_ITEM lvitem; - lvitem = PhAllocate(sizeof(PHP_TOKEN_PAGE_LISTVIEW_ITEM)); - memset(lvitem, 0, sizeof(PHP_TOKEN_PAGE_LISTVIEW_ITEM)); - + lvitem = PhAllocateZero(sizeof(PHP_TOKEN_PAGE_LISTVIEW_ITEM)); lvitem->IsTokenGroupEntry = TRUE; lvitem->TokenGroup = &Groups->Groups[i]; @@ -443,7 +441,7 @@ VOID PhpUpdateSidsFromTokenGroups( Groups->Groups[i].Attributes, GroupDescriptionEntries, RTL_NUMBER_OF(GroupDescriptionEntries) - ); + ); if (descriptionString) { From d4e03153199a2cc2135e3fdd51a59fe305706a6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kasper=20Fab=C3=A6ch=20Brandt?= Date: Mon, 17 Sep 2018 11:51:30 +0200 Subject: [PATCH 1345/2058] Invalidate dpi awareness if Unaware as it may change. (#315) --- ProcessHacker/proctree.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/ProcessHacker/proctree.c b/ProcessHacker/proctree.c index d94bcccf304a..155a82cb2040 100644 --- a/ProcessHacker/proctree.c +++ b/ProcessHacker/proctree.c @@ -642,11 +642,19 @@ VOID PhTickProcessNodes( for (i = 0; i < ProcessNodeList->Count; i++) { + ULONG remainsValidMask; PPH_PROCESS_NODE node = ProcessNodeList->Items[i]; // The name and PID never change, so we don't invalidate that. memset(&node->TextCache[2], 0, sizeof(PH_STRINGREF) * (PHPRTLC_MAXIMUM - 2)); - node->ValidMask &= PHPN_OSCONTEXT | PHPN_IMAGE | PHPN_DPIAWARENESS | PHPN_APPID | PHPN_DESKTOPINFO | PHPN_USERNAME; // Items that always remain valid + + remainsValidMask = PHPN_OSCONTEXT | PHPN_IMAGE | PHPN_APPID | PHPN_DESKTOPINFO | PHPN_USERNAME; // Items that always remain valid + // The DPI awareness defaults to unaware if not set or declared in the manifest in which case + // it can be changed once, so we can only be sure that it won't be changed again if it is different + // from Unaware. + if (node->DpiAwareness != 1) + remainsValidMask |= PHPN_DPIAWARENESS; + node->ValidMask &= remainsValidMask; // Invalidate graph buffers. node->CpuGraphBuffers.Valid = FALSE; From cfa5878685b87fe08dae93d262b0126e0879e638 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 17 Sep 2018 19:56:06 +1000 Subject: [PATCH 1346/2058] Fix tabspace, Add author --- ProcessHacker/proctree.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/ProcessHacker/proctree.c b/ProcessHacker/proctree.c index 155a82cb2040..22481d5694d3 100644 --- a/ProcessHacker/proctree.c +++ b/ProcessHacker/proctree.c @@ -642,19 +642,17 @@ VOID PhTickProcessNodes( for (i = 0; i < ProcessNodeList->Count; i++) { - ULONG remainsValidMask; PPH_PROCESS_NODE node = ProcessNodeList->Items[i]; // The name and PID never change, so we don't invalidate that. memset(&node->TextCache[2], 0, sizeof(PH_STRINGREF) * (PHPRTLC_MAXIMUM - 2)); + node->ValidMask &= PHPN_OSCONTEXT | PHPN_IMAGE | PHPN_DPIAWARENESS | PHPN_APPID | PHPN_DESKTOPINFO | PHPN_USERNAME; // Items that always remain valid - remainsValidMask = PHPN_OSCONTEXT | PHPN_IMAGE | PHPN_APPID | PHPN_DESKTOPINFO | PHPN_USERNAME; // Items that always remain valid // The DPI awareness defaults to unaware if not set or declared in the manifest in which case // it can be changed once, so we can only be sure that it won't be changed again if it is different - // from Unaware. + // from Unaware (poizan42). if (node->DpiAwareness != 1) - remainsValidMask |= PHPN_DPIAWARENESS; - node->ValidMask &= remainsValidMask; + node->ValidMask |= PHPN_DPIAWARENESS; // Invalidate graph buffers. node->CpuGraphBuffers.Valid = FALSE; From ded99dbed95bfedacd19d725e6b1416f469304af Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 17 Sep 2018 20:03:10 +1000 Subject: [PATCH 1347/2058] Export PhGetMappedImageExports/PhGetMappedImageExportFunction/PhMappedImageRvaToVa for #316 --- ProcessHacker/ProcessHacker.def | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ProcessHacker/ProcessHacker.def b/ProcessHacker/ProcessHacker.def index b6c57736547b..7883bc7cfbb4 100644 --- a/ProcessHacker/ProcessHacker.def +++ b/ProcessHacker/ProcessHacker.def @@ -553,6 +553,9 @@ EXPORTS PhGetMappedImageCfgEntry PhGetMappedImageLoadConfig32 PhGetMappedImageLoadConfig64 + PhGetMappedImageExports + PhGetMappedImageExportFunction + PhMappedImageRvaToVa PhInitializeMappedImage PhLoadMappedImage PhLoadMappedImageEx From 7c826ded0f8e574d324f2ec494de9926090894e6 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 18 Sep 2018 01:25:32 +1000 Subject: [PATCH 1348/2058] Remove duplicate types #306 --- phnt/include/ntrtl.h | 43 +------------------------------------------ 1 file changed, 1 insertion(+), 42 deletions(-) diff --git a/phnt/include/ntrtl.h b/phnt/include/ntrtl.h index 0282611645f0..555d6d50f119 100644 --- a/phnt/include/ntrtl.h +++ b/phnt/include/ntrtl.h @@ -3092,14 +3092,6 @@ RtlGetFunctionTableListHead( // Images -NTSYSAPI -PVOID -NTAPI -RtlPcToFileHeader( - _In_ PVOID PcValue, - _Out_ PVOID *BaseOfImage - ); - NTSYSAPI PIMAGE_NT_HEADERS NTAPI @@ -5650,6 +5642,7 @@ RtlEqualSid( _Check_return_ NTSYSAPI BOOLEAN +NTAPI RtlEqualPrefixSid( _In_ PSID Sid1, _In_ PSID Sid2 @@ -6669,18 +6662,6 @@ RtlGetNtVersionNumbers( _Out_opt_ PULONG NtBuildNumber ); -// private -NTSYSAPI -BOOLEAN -WINAPI -RtlGetProductInfo( - _In_ ULONG OSMajorVersion, - _In_ ULONG OSMinorVersion, - _In_ ULONG SpMajorVersion, - _In_ ULONG SpMinorVersion, - _Out_ PULONG ReturnedProductType // PRODUCT_PROFESSIONAL - ); - // System information // rev @@ -7365,28 +7346,6 @@ RtlQueryPerformanceFrequency( ); #endif -#if (PHNT_VERSION >= PHNT_WIN8) - -NTSYSAPI -ULONG -NTAPI -RtlCrc32( - _In_reads_bytes_(Size) const void *Buffer, - _In_ size_t Size, - _In_ ULONG InitialCrc - ); - -NTSYSAPI -ULONGLONG -NTAPI -RtlCrc64( - _In_reads_bytes_(Size) const void *Buffer, - _In_ size_t Size, - _In_ ULONGLONG InitialCrc - ); - -#endif - // Image Mitigation // rev From a4a44007b20940aa2e4085fe0ab2d78886579999 Mon Sep 17 00:00:00 2001 From: diversenok Date: Wed, 19 Sep 2018 17:49:22 +0300 Subject: [PATCH 1349/2058] Fix file position in handle properties (#317) --- ProcessHacker/hndlprp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ProcessHacker/hndlprp.c b/ProcessHacker/hndlprp.c index cb38d34bd76c..f09d8f6fa721 100644 --- a/ProcessHacker/hndlprp.c +++ b/ProcessHacker/hndlprp.c @@ -797,7 +797,7 @@ VOID PhpUpdateHandleGeneral( PhInitFormatI64UGroupDigits(&format[0], filePositionInfo.CurrentByteOffset.QuadPart); PhInitFormatS(&format[1], L" ("); - PhInitFormatF(&format[2], (DOUBLE)(filePositionInfo.CurrentByteOffset.QuadPart / fileStandardInfo.EndOfFile.QuadPart * 100), 1); + PhInitFormatF(&format[2], (DOUBLE)filePositionInfo.CurrentByteOffset.QuadPart / (DOUBLE)fileStandardInfo.EndOfFile.QuadPart * 100.0, 1); PhInitFormatS(&format[3], L"%)"); if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), filePositionString, sizeof(filePositionString), NULL)) From 4ce9df58f212d60b70f7433064f7d9de988d18c3 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 25 Sep 2018 04:05:07 +1000 Subject: [PATCH 1350/2058] Add RS5 version, Fix tabspace --- phlib/global.c | 2 +- phlib/include/mapimg.h | 1 - phlib/include/phbase.h | 3 ++- phlib/include/phconfig.h | 1 + 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/phlib/global.c b/phlib/global.c index a58b2736bb38..5ee59077ea5c 100644 --- a/phlib/global.c +++ b/phlib/global.c @@ -197,7 +197,7 @@ VOID PhInitializeWindowsVersion( WindowsVersion = WINDOWS_10_RS4; break; default: - WindowsVersion = buildVersion > 17134 ? WINDOWS_10_RS4 : WINDOWS_10; + WindowsVersion = buildVersion > 17134 ? WINDOWS_10_RS5 : WINDOWS_10; break; } } diff --git a/phlib/include/mapimg.h b/phlib/include/mapimg.h index 32a09d8bd09a..a9476113bca4 100644 --- a/phlib/include/mapimg.h +++ b/phlib/include/mapimg.h @@ -204,7 +204,6 @@ typedef struct _PH_MAPPED_IMAGE_EXPORT_FUNCTION PSTR ForwardedName; } PH_MAPPED_IMAGE_EXPORT_FUNCTION, *PPH_MAPPED_IMAGE_EXPORT_FUNCTION; - PHLIBAPI NTSTATUS NTAPI diff --git a/phlib/include/phbase.h b/phlib/include/phbase.h index 15ad67e42a4d..47ef494ebe1f 100644 --- a/phlib/include/phbase.h +++ b/phlib/include/phbase.h @@ -28,10 +28,11 @@ #include #include #include + #include #include #include #include -#endif \ No newline at end of file +#endif diff --git a/phlib/include/phconfig.h b/phlib/include/phconfig.h index 06917148b91e..a9e0c5edca84 100644 --- a/phlib/include/phconfig.h +++ b/phlib/include/phconfig.h @@ -33,6 +33,7 @@ PHLIBAPI extern ACCESS_MASK ThreadAllAccess; #define WINDOWS_10_RS2 103 #define WINDOWS_10_RS3 104 #define WINDOWS_10_RS4 105 +#define WINDOWS_10_RS5 106 #define WINDOWS_NEW MAXLONG #define WINDOWS_HAS_IMMERSIVE (WindowsVersion >= WINDOWS_8) From 2559b4c9e675408bc0692a58f0dd39a822352bf1 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 25 Sep 2018 04:08:11 +1000 Subject: [PATCH 1351/2058] Update PhShellExploreFile error message --- phlib/util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phlib/util.c b/phlib/util.c index 1baf782cae30..79c71df4e1f3 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -3302,7 +3302,7 @@ VOID PhShellExploreFile( } else { - PhShowError(hWnd, L"The location \"%s\" could not be found.", FileName); + PhShowError2(hWnd, L"The location could not be found.", L"%s", FileName); } } else From 0115140cf59754b15dcc18da5bc00cb00fbad45f Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 25 Sep 2018 04:13:09 +1000 Subject: [PATCH 1352/2058] Fix RS5 dark scrollbar theme, Fix button BS_ICON style drawing --- phlib/theme.c | 75 ++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 71 insertions(+), 4 deletions(-) diff --git a/phlib/theme.c b/phlib/theme.c index 8e418acc28e8..3a2d39cd23ec 100644 --- a/phlib/theme.c +++ b/phlib/theme.c @@ -339,7 +339,7 @@ BOOLEAN CALLBACK PhpThemeWindowEnumChildWindows( } else if (PhEqualStringZ(windowClassName, L"ScrollBar", FALSE)) { - if (WindowsVersion > WINDOWS_10_RS4) + if (WindowsVersion >= WINDOWS_10_RS5) { switch (PhpThemeColorMode) { @@ -486,7 +486,7 @@ BOOLEAN CALLBACK PhpReInitializeThemeWindowEnumChildWindows( } else if (PhEqualStringZ(windowClassName, L"ScrollBar", FALSE)) { - if (WindowsVersion > WINDOWS_10_RS4) + if (WindowsVersion >= WINDOWS_10_RS5) { switch (PhpThemeColorMode) { @@ -856,9 +856,11 @@ LRESULT CALLBACK PhpThemeWindowDrawButton( case CDDS_PREPAINT: { PPH_STRING buttonText; + ULONG_PTR buttonStyle; HFONT oldFont; buttonText = PhGetWindowText(DrawInfo->hdr.hwndFrom); + buttonStyle = PhGetWindowStyle(DrawInfo->hdr.hwndFrom); if (isSelected) { @@ -906,7 +908,72 @@ LRESULT CALLBACK PhpThemeWindowDrawButton( FillRect(DrawInfo->hdc, &DrawInfo->rc, GetStockObject(DC_BRUSH)); } - if ((PhGetWindowStyle(DrawInfo->hdr.hwndFrom) & BS_CHECKBOX) == BS_CHECKBOX) + if ((buttonStyle & BS_ICON) == BS_ICON) + { + RECT bufferRect = + { + 0, 0, + DrawInfo->rc.right - DrawInfo->rc.left, + DrawInfo->rc.bottom - DrawInfo->rc.top + }; + HICON buttonIcon; + + SetDCBrushColor(DrawInfo->hdc, RGB(65, 65, 65)); + FrameRect(DrawInfo->hdc, &DrawInfo->rc, GetStockObject(DC_BRUSH)); + + if (!(buttonIcon = Static_GetIcon(DrawInfo->hdr.hwndFrom, 0))) + buttonIcon = (HICON)SendMessage(DrawInfo->hdr.hwndFrom, BM_GETIMAGE, IMAGE_ICON, 0); + + if (buttonIcon) + { + ICONINFO iconInfo; + BITMAP bmp; + LONG width; + LONG height; + + memset(&iconInfo, 0, sizeof(ICONINFO)); + memset(&bmp, 0, sizeof(BITMAP)); + + GetIconInfo(buttonIcon, &iconInfo); + + if (iconInfo.hbmColor) + { + if (GetObject(iconInfo.hbmColor, sizeof(BITMAP), &bmp)) + { + width = bmp.bmWidth; + height = bmp.bmHeight; + } + + DeleteObject(iconInfo.hbmColor); + } + else if (iconInfo.hbmMask) + { + if (GetObject(iconInfo.hbmMask, sizeof(BITMAP), &bmp)) + { + width = bmp.bmWidth; + height = bmp.bmHeight / 2; + } + + DeleteObject(iconInfo.hbmMask); + } + + bufferRect.left += 1; // HACK + bufferRect.top += 1; // HACK + + DrawIconEx( + DrawInfo->hdc, + bufferRect.left + ((bufferRect.right - bufferRect.left) - width) / 2, + bufferRect.top + ((bufferRect.bottom - bufferRect.top) - height) / 2, + buttonIcon, + width, + height, + 0, + NULL, + DI_NORMAL + ); + } + } + else if ((buttonStyle & BS_CHECKBOX) == BS_CHECKBOX) { HFONT newFont = PhDuplicateFontWithNewHeight(PhApplicationFont, 22); oldFont = SelectFont(DrawInfo->hdc, newFont); @@ -966,7 +1033,7 @@ LRESULT CALLBACK PhpThemeWindowDrawButton( DrawIconEx( DrawInfo->hdc, bufferRect.left + ((bufferRect.right - bufferRect.left) - 16) / 2, - bufferRect.top + ((bufferRect.bottom - bufferRect.top) - 16 ) / 2, + bufferRect.top + ((bufferRect.bottom - bufferRect.top) - 16) / 2, buttonIcon, 16, 16, From f199baef5602fdbfded31c0e6a8ed0ad4def0728 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 25 Sep 2018 04:17:32 +1000 Subject: [PATCH 1353/2058] Add theme support to miniinfo tray window --- ProcessHacker/miniinfo.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ProcessHacker/miniinfo.c b/ProcessHacker/miniinfo.c index b346b0f06a8f..4a3922bb0319 100644 --- a/ProcessHacker/miniinfo.c +++ b/ProcessHacker/miniinfo.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -470,6 +471,8 @@ VOID PhMipOnInitDialog( oldWndProc = (WNDPROC)GetWindowLongPtr(GetDlgItem(PhMipWindow, IDC_SECTION), GWLP_WNDPROC); PhSetWindowContext(GetDlgItem(PhMipWindow, IDC_SECTION), 0xF, oldWndProc); SetWindowLongPtr(GetDlgItem(PhMipWindow, IDC_SECTION), GWLP_WNDPROC, (LONG_PTR)PhMipSectionControlHookWndProc); + + PhInitializeWindowTheme(PhMipWindow, PhEnableThemeSupport); } VOID PhMipOnShowWindow( @@ -882,6 +885,8 @@ VOID PhMipCreateSectionDialog( createDialog.DialogProc, createDialog.Parameter ); + + PhInitializeWindowTheme(Section->DialogHandle, PhEnableThemeSupport); } } } From 27726d62fe61a2359dcedaf1ef4a64466348dfc3 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 25 Sep 2018 04:19:17 +1000 Subject: [PATCH 1354/2058] DotNetTools: Fix .NET performance tab sorting --- plugins/DotNetTools/DotNetTools.rc | 2 +- plugins/DotNetTools/clr/ipcheader.h | 2 +- plugins/DotNetTools/clr/perfcounterdefs.h | 6 +- plugins/DotNetTools/perfpage.c | 1368 ++++++++++++++++----- 4 files changed, 1059 insertions(+), 319 deletions(-) diff --git a/plugins/DotNetTools/DotNetTools.rc b/plugins/DotNetTools/DotNetTools.rc index e382546b5469..4e8ea06e3dc3 100644 --- a/plugins/DotNetTools/DotNetTools.rc +++ b/plugins/DotNetTools/DotNetTools.rc @@ -93,7 +93,7 @@ CAPTION ".NET performance" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN CONTROL "",IDC_APPDOMAINS,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_SORTASCENDING | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,2,3,256,67 - CONTROL "",IDC_COUNTERS,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,2,73,256,185 + CONTROL "",IDC_COUNTERS,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,2,73,256,185 END IDD_PROCDOTNETASM DIALOGEX 0, 0, 260, 260 diff --git a/plugins/DotNetTools/clr/ipcheader.h b/plugins/DotNetTools/clr/ipcheader.h index f565dd9a5154..193586eb3c7d 100644 --- a/plugins/DotNetTools/clr/ipcheader.h +++ b/plugins/DotNetTools/clr/ipcheader.h @@ -542,4 +542,4 @@ typedef struct _LegacyPublicIPCControlBlock_Wow64 // } //}; -#endif // _IPC_HEADER_H_ \ No newline at end of file +#endif // _IPC_HEADER_H_ diff --git a/plugins/DotNetTools/clr/perfcounterdefs.h b/plugins/DotNetTools/clr/perfcounterdefs.h index baf11e2f4dcd..f3249dfc6580 100644 --- a/plugins/DotNetTools/clr/perfcounterdefs.h +++ b/plugins/DotNetTools/clr/perfcounterdefs.h @@ -301,7 +301,7 @@ typedef struct _PerfCounterIPCControlBlock Perf_Contexts Context; Perf_Interop Interop; Perf_Loading Loading; - Perf_Excep Excep; + Perf_Excep Exceptions; Perf_LocksAndThreads LocksAndThreads; Perf_Jit Jit; Perf_Security Security; @@ -322,7 +322,7 @@ typedef struct _PerfCounterIPCControlBlock_Wow64 Perf_Contexts Context; Perf_Interop Interop; Perf_Loading_Wow64 Loading; - Perf_Excep Excep; + Perf_Excep Exceptions; Perf_LocksAndThreads LocksAndThreads; Perf_Jit Jit; Perf_Security_Wow64 Security; @@ -330,4 +330,4 @@ typedef struct _PerfCounterIPCControlBlock_Wow64 #include -#endif _PERF_COUNTERS_H_ \ No newline at end of file +#endif _PERF_COUNTERS_H_ diff --git a/plugins/DotNetTools/perfpage.c b/plugins/DotNetTools/perfpage.c index 15911d040d1c..74d7c13692d1 100644 --- a/plugins/DotNetTools/perfpage.c +++ b/plugins/DotNetTools/perfpage.c @@ -3,7 +3,7 @@ * .NET Performance property page * * Copyright (C) 2011-2015 wj32 - * Copyright (C) 2015 dmex + * Copyright (C) 2015-2018 dmex * * This file is part of Process Hacker. * @@ -21,35 +21,20 @@ * along with Process Hacker. If not, see . */ - #include "dn.h" #include "clr\perfcounterdefs.h" -typedef struct _PERFPAGE_CONTEXT +PWSTR DotNetCategoryStrings[] = { - HWND WindowHandle; - HWND AppDomainsLv; - HWND CountersLv; - PPH_PROCESS_ITEM ProcessItem; - - union - { - BOOLEAN Flags; - struct - { - BOOLEAN Enabled : 1; - BOOLEAN ControlBlockValid : 1; - BOOLEAN ClrV4 : 1; - BOOLEAN IsWow64 : 1; - BOOLEAN Spare : 4; - }; - }; - - HANDLE ProcessHandle; - HANDLE BlockTableHandle; - PVOID BlockTableAddress; - PH_CALLBACK_REGISTRATION ProcessesUpdatedCallbackRegistration; -} PERFPAGE_CONTEXT, *PPERFPAGE_CONTEXT; + L".NET CLR Exceptions", + L".NET CLR Interop", + L".NET CLR Jit", + L".NET CLR Loading", + L".NET CLR LocksAndThreads", + L".NET CLR Memory", + L".NET CLR Remoting", + L".NET CLR Security" +}; typedef enum _DOTNET_CATEGORY { @@ -141,20 +126,44 @@ typedef enum _DOTNET_INDEX DOTNET_INDEX_SECURITY_TOTALRUNTIMECHECKS, DOTNET_INDEX_SECURITY_LINKTIMECHECKS, DOTNET_INDEX_SECURITY_TIMEINRTCHECKS, - DOTNET_INDEX_SECURITY_STACKWALKDEPTH + DOTNET_INDEX_SECURITY_STACKWALKDEPTH, + + DOTNET_INDEX_MAXIMUM } DOTNET_INDEX; -PWSTR DotNetCategoryStrings[] = +typedef struct _PERFPAGE_CONTEXT { - L".NET CLR Exceptions", - L".NET CLR Interop", - L".NET CLR Jit", - L".NET CLR Loading", - L".NET CLR LocksAndThreads", - L".NET CLR Memory", - L".NET CLR Remoting", - L".NET CLR Security" -}; + HWND WindowHandle; + HWND AppDomainsListViewHandle; + HWND CountersListViewHandle; + PPH_PROCESS_ITEM ProcessItem; + + union + { + BOOLEAN Flags; + struct + { + BOOLEAN Enabled : 1; + BOOLEAN ControlBlockValid : 1; + BOOLEAN ClrV4 : 1; + BOOLEAN IsWow64 : 1; + BOOLEAN Spare : 4; + }; + }; + + HANDLE ProcessHandle; + HANDLE BlockTableHandle; + PVOID BlockTableAddress; + PH_CALLBACK_REGISTRATION ProcessesUpdatedCallbackRegistration; + Perf_GC DotNetPerfGC; + Perf_Contexts DotNetPerfContext; + Perf_Interop DotNetPerfInterop; + Perf_Loading DotNetPerfLoading; + Perf_Excep DotNetPerfExceptions; + Perf_LocksAndThreads DotNetPerfLocksAndThreads; + Perf_Jit DotNetPerfJit; + Perf_Security DotNetPerfSecurity; +} PERFPAGE_CONTEXT, *PPERFPAGE_CONTEXT; VOID NTAPI DotNetPerfProcessesUpdatedCallback( _In_opt_ PVOID Parameter, @@ -187,9 +196,9 @@ VOID DotNetPerfAddListViewGroups( // These include both .NET exceptions and unmanaged exceptions that get converted into .NET exceptions e.g. null pointer reference exception in unmanaged code // would get re-thrown in managed code as a .NET System.NullReferenceException; this counter includes both handled and unhandled exceptions.Exceptions // that are re-thrown would get counted again. Exceptions should only occur in rare situations and not in the normal control flow of the program. - PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_EXCEPTIONS, DOTNET_INDEX_EXCEPTIONS_THROWNCOUNT, L"# of Exceps Thrown", NULL); - PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_EXCEPTIONS, DOTNET_INDEX_EXCEPTIONS_FILTERSCOUNT, L"# of Filters Executed", NULL); - PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_EXCEPTIONS, DOTNET_INDEX_EXCEPTIONS_FINALLYCOUNT, L"# of Finallys Executed", NULL); + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_EXCEPTIONS, DOTNET_INDEX_EXCEPTIONS_THROWNCOUNT, L"# of Exceptions Thrown", UlongToPtr(DOTNET_INDEX_EXCEPTIONS_THROWNCOUNT)); + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_EXCEPTIONS, DOTNET_INDEX_EXCEPTIONS_FILTERSCOUNT, L"# of Filters Executed", UlongToPtr(DOTNET_INDEX_EXCEPTIONS_FILTERSCOUNT)); + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_EXCEPTIONS, DOTNET_INDEX_EXCEPTIONS_FINALLYCOUNT, L"# of Finallys Executed", UlongToPtr(DOTNET_INDEX_EXCEPTIONS_FINALLYCOUNT)); // Reserved for future use. //PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_EXCEPTIONS, , L"Delta from throw to catch site on stack", NULL); @@ -225,42 +234,42 @@ VOID DotNetPerfAddListViewGroups( // This counter displays the current number of Com-Callable-Wrappers (CCWs). // A CCW is a proxy for the .NET managed object being referenced from unmanaged COM client(s). // This counter was designed to indicate the number of managed objects being referenced by unmanaged COM code. - PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_INTEROP, DOTNET_INDEX_INTEROP_CCWCOUNT, L"# of CCWs", NULL); + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_INTEROP, DOTNET_INDEX_INTEROP_CCWCOUNT, L"# of CCWs", UlongToPtr(DOTNET_INDEX_INTEROP_CCWCOUNT)); // This counter displays the current number of stubs created by the CLR. // Stubs are responsible for marshalling arguments and return values from managed to unmanaged code and vice versa; during a COM Interop call or PInvoke call. - PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_INTEROP, DOTNET_INDEX_INTEROP_STUBCOUNT, L"# of Stubs", NULL); + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_INTEROP, DOTNET_INDEX_INTEROP_STUBCOUNT, L"# of Stubs", UlongToPtr(DOTNET_INDEX_INTEROP_STUBCOUNT)); // This counter displays the total number of times arguments and return values have been marshaled from managed to unmanaged code // and vice versa since the start of the application. This counter is not incremented if the stubs are inlined. // (Stubs are responsible for marshalling arguments and return values). Stubs usually get inlined if the marshalling overhead is small. - PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_INTEROP, DOTNET_INDEX_INTEROP_MARSHALCOUNT, L"# of Marshalling", NULL); + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_INTEROP, DOTNET_INDEX_INTEROP_MARSHALCOUNT, L"# of Marshalling", UlongToPtr(DOTNET_INDEX_INTEROP_MARSHALCOUNT)); // Reserved for future use. - PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_INTEROP, DOTNET_INDEX_INTEROP_TLBIMPORTPERSEC, L"# of TLB imports / sec", NULL); + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_INTEROP, DOTNET_INDEX_INTEROP_TLBIMPORTPERSEC, L"# of TLB imports / sec", UlongToPtr(DOTNET_INDEX_INTEROP_TLBIMPORTPERSEC)); // Reserved for future use. - PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_INTEROP, DOTNET_INDEX_INTEROP_TLBEXPORTPERSEC, L"# of TLB exports / sec", NULL); + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_INTEROP, DOTNET_INDEX_INTEROP_TLBEXPORTPERSEC, L"# of TLB exports / sec", UlongToPtr(DOTNET_INDEX_INTEROP_TLBEXPORTPERSEC)); // This counter displays the total number of methods compiled Just-In-Time (JIT) by the CLR JIT compiler since the start of the application. // This counter does not include the pre-jitted methods. - PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_JIT, DOTNET_INDEX_JIT_ILMETHODSJITTED, L"# of Methods Jitted", NULL); + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_JIT, DOTNET_INDEX_JIT_ILMETHODSJITTED, L"# of Methods Jitted", UlongToPtr(DOTNET_INDEX_JIT_ILMETHODSJITTED)); // This counter displays the total IL bytes jitted since the start of the application. // This counter is exactly equivalent to the "Total # of IL Bytes Jitted" counter. - PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_JIT, DOTNET_INDEX_JIT_ILBYTESJITTED, L"# of IL Bytes Jitted", NULL); + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_JIT, DOTNET_INDEX_JIT_ILBYTESJITTED, L"# of IL Bytes Jitted", UlongToPtr(DOTNET_INDEX_JIT_ILBYTESJITTED)); // This counter displays the total IL bytes jitted since the start of the application. // This counter is exactly equivalent to the "# of IL Bytes Jitted" counter. - PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_JIT, DOTNET_INDEX_JIT_ILTOTALBYTESJITTED, L"Total # of IL Bytes Jitted", NULL); + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_JIT, DOTNET_INDEX_JIT_ILTOTALBYTESJITTED, L"Total # of IL Bytes Jitted", UlongToPtr(DOTNET_INDEX_JIT_ILTOTALBYTESJITTED)); // This counter displays the peak number of methods the JIT compiler has failed to JIT since the start of the application. // This failure can occur if the IL cannot be verified or if there was an internal error in the JIT compiler. - PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_JIT, DOTNET_INDEX_JIT_FAILURES, L"Jit Failures", NULL); + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_JIT, DOTNET_INDEX_JIT_FAILURES, L"Jit Failures", UlongToPtr(DOTNET_INDEX_JIT_FAILURES)); // This counter displays the percentage of elapsed time spent in JIT compilation since the last JIT compilation phase. // This counter is updated at the end of every JIT compilation phase. A JIT compilation phase is the phase when a method and its dependencies are being compiled. - PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_JIT, DOTNET_INDEX_JIT_TIME, L"% Time in Jit", NULL); + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_JIT, DOTNET_INDEX_JIT_TIME, L"% Time in Jit", UlongToPtr(DOTNET_INDEX_JIT_TIME)); // IL Bytes Jitted / sec // This counter displays the rate at which IL bytes are jitted per second. @@ -268,46 +277,46 @@ VOID DotNetPerfAddListViewGroups( // TODO: We need to count the delta. // This counter displays the current number of classes loaded in all Assemblies. - PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_LOADING, DOTNET_INDEX_LOADING_CURRENTLOADED, L"Current Classes Loaded", NULL); + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_LOADING, DOTNET_INDEX_LOADING_CURRENTLOADED, L"Current Classes Loaded", UlongToPtr(DOTNET_INDEX_LOADING_CURRENTLOADED)); // This counter displays the cumulative number of classes loaded in all Assemblies since the start of this application. - PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_LOADING, DOTNET_INDEX_LOADING_TOTALLOADED, L"Total Classes Loaded", NULL); + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_LOADING, DOTNET_INDEX_LOADING_TOTALLOADED, L"Total Classes Loaded", UlongToPtr(DOTNET_INDEX_LOADING_TOTALLOADED)); // This counter displays the current number of AppDomains loaded in this application. // AppDomains (application domains) provide a secure and versatile unit of processing that the CLR can use to provide isolation between applications running in the same process. - PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_LOADING, DOTNET_INDEX_LOADING_CURRENTAPPDOMAINS, L"Current Appdomains", NULL); + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_LOADING, DOTNET_INDEX_LOADING_CURRENTAPPDOMAINS, L"Current Appdomains", UlongToPtr(DOTNET_INDEX_LOADING_CURRENTAPPDOMAINS)); // This counter displays the peak number of AppDomains loaded since the start of this application. // AppDomains (application domains) provide a secure and versatile unit of processing that the CLR can use to provide isolation between applications running in the same process. - PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_LOADING, DOTNET_INDEX_LOADING_TOTALAPPDOMAINS, L"Total Appdomains", NULL); + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_LOADING, DOTNET_INDEX_LOADING_TOTALAPPDOMAINS, L"Total Appdomains", UlongToPtr(DOTNET_INDEX_LOADING_TOTALAPPDOMAINS)); // This counter displays the current number of Assemblies loaded across all AppDomains in this application. // If the Assembly is loaded as domain - neutral from multiple AppDomains then this counter is incremented once only. // Assemblies can be loaded as domain - neutral when their code can be shared by all AppDomains or they can be loaded as domain - specific when their code is private to the AppDomain. - PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_LOADING, DOTNET_INDEX_LOADING_CURRENTASSEMBLIES, L"Current Assemblies", NULL); + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_LOADING, DOTNET_INDEX_LOADING_CURRENTASSEMBLIES, L"Current Assemblies", UlongToPtr(DOTNET_INDEX_LOADING_CURRENTASSEMBLIES)); // This counter displays the total number of Assemblies loaded since the start of this application. // If the Assembly is loaded as domain - neutral from multiple AppDomains then this counter is incremented once only. // Assemblies can be loaded as domain - neutral when their code can be shared by all AppDomains or they can be loaded as domain - specific when their code is private to the AppDomain. - PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_LOADING, DOTNET_INDEX_LOADING_TOTALASSEMBLIES, L"Total Assemblies", NULL); + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_LOADING, DOTNET_INDEX_LOADING_TOTALASSEMBLIES, L"Total Assemblies", UlongToPtr(DOTNET_INDEX_LOADING_TOTALASSEMBLIES)); // Reserved for future use. - PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_LOADING, DOTNET_INDEX_LOADING_ASSEMBLYSEARCHLENGTH, L"Assembly Search Length", NULL); + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_LOADING, DOTNET_INDEX_LOADING_ASSEMBLYSEARCHLENGTH, L"Assembly Search Length", UlongToPtr(DOTNET_INDEX_LOADING_ASSEMBLYSEARCHLENGTH)); // This counter displays the peak number of classes that have failed to load since the start of the application. // These load failures could be due to many reasons like inadequate security or illegal format.Full details can be found in the profiling services help. - PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_LOADING, DOTNET_INDEX_LOADING_TOTALLOADFAILURES, L"Total # of Load Failures", NULL); + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_LOADING, DOTNET_INDEX_LOADING_TOTALLOADFAILURES, L"Total # of Load Failures", UlongToPtr(DOTNET_INDEX_LOADING_TOTALLOADFAILURES)); // This counter displays the current size(in bytes) of the memory committed by the class loader across all AppDomains. // (Committed memory is the physical memory for which space has been reserved on the disk paging file.) - PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_LOADING, DOTNET_INDEX_LOADING_BYTESINLOADERHEAP, L"Bytes in Loader Heap", NULL); + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_LOADING, DOTNET_INDEX_LOADING_BYTESINLOADERHEAP, L"Bytes in Loader Heap", UlongToPtr(DOTNET_INDEX_LOADING_BYTESINLOADERHEAP)); // This counter displays the total number of AppDomains unloaded since the start of the application. //If an AppDomain is loaded and unloaded multiple times this counter would count each of those unloads as separate. - PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_LOADING, DOTNET_INDEX_LOADING_TOTALAPPDOMAINSUNLOADED, L"Total Appdomains Unloaded", NULL); + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_LOADING, DOTNET_INDEX_LOADING_TOTALAPPDOMAINSUNLOADED, L"Total Appdomains Unloaded", UlongToPtr(DOTNET_INDEX_LOADING_TOTALAPPDOMAINSUNLOADED)); // Reserved for future use. - //PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_LOADING, , L"% Time Loading", NULL); + //PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_LOADING, , L"% Time Loading", UlongToPtr()); // Rate of Load Failures // This counter displays the number of classes that failed to load per second. @@ -341,34 +350,34 @@ VOID DotNetPerfAddListViewGroups( // This counter displays the total number of times threads in the CLR have attempted to acquire a managed lock unsuccessfully. // Managed locks can be acquired in many ways; by the "lock" statement in C# or by calling System.Monitor.Enter or by using MethodImplOptions.Synchronized custom attribute. - PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_LOCKSANDTHREADS, DOTNET_INDEX_LOCKSANDTHREADS_TOTALLOCKS, L"Total # of Contentions", NULL); + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_LOCKSANDTHREADS, DOTNET_INDEX_LOCKSANDTHREADS_TOTALLOCKS, L"Total # of Contentions", UlongToPtr(DOTNET_INDEX_LOCKSANDTHREADS_TOTALLOCKS)); // This counter displays the total number of threads currently waiting to acquire some managed lock in the application. // This counter is not an average over time; it displays the last observed value. - PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_LOCKSANDTHREADS, DOTNET_INDEX_LOCKSANDTHREADS_TOTALQUEUELENGTH, L"Current Queue Length", NULL); + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_LOCKSANDTHREADS, DOTNET_INDEX_LOCKSANDTHREADS_TOTALQUEUELENGTH, L"Current Queue Length", UlongToPtr(DOTNET_INDEX_LOCKSANDTHREADS_TOTALQUEUELENGTH)); // This counter displays the total number of threads that waited to acquire some managed lock since the start of the application. - PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_LOCKSANDTHREADS, DOTNET_INDEX_LOCKSANDTHREADS_QUEUELENGTHPEAK, L"Queue Length Peak", NULL); + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_LOCKSANDTHREADS, DOTNET_INDEX_LOCKSANDTHREADS_QUEUELENGTHPEAK, L"Queue Length Peak", UlongToPtr(DOTNET_INDEX_LOCKSANDTHREADS_QUEUELENGTHPEAK)); // This counter displays the number of current.NET thread objects in the application. // A.NET thread object is created either by new System.Threading.Thread or when an unmanaged thread enters the managed environment. // This counters maintains the count of both running and stopped threads. This counter is not an average over time; it just displays the last observed value. - PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_LOCKSANDTHREADS, DOTNET_INDEX_LOCKSANDTHREADS_CURRENTLOGICAL, L"# of Current Logical Threads", NULL); + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_LOCKSANDTHREADS, DOTNET_INDEX_LOCKSANDTHREADS_CURRENTLOGICAL, L"# of Current Logical Threads", UlongToPtr(DOTNET_INDEX_LOCKSANDTHREADS_CURRENTLOGICAL)); // This counter displays the number of native OS threads created and owned by the CLR to act as underlying threads for .NET thread objects. // This counters value does not include the threads used by the CLR in its internal operations; it is a subset of the threads in the OS process. - PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_LOCKSANDTHREADS, DOTNET_INDEX_LOCKSANDTHREADS_CURRENTPHYSICAL, L"# of Current Physical Threads", NULL); + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_LOCKSANDTHREADS, DOTNET_INDEX_LOCKSANDTHREADS_CURRENTPHYSICAL, L"# of Current Physical Threads", UlongToPtr(DOTNET_INDEX_LOCKSANDTHREADS_CURRENTPHYSICAL)); // This counter displays the number of threads that are currently recognized by the CLR; they have a corresponding .NET thread object associated with them. // These threads are not created by the CLR; they are created outside the CLR but have since run inside the CLR at least once. // Only unique threads are tracked; threads with same thread ID re-entering the CLR or recreated after thread exit are not counted twice. - PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_LOCKSANDTHREADS, DOTNET_INDEX_LOCKSANDTHREADS_CURRENTRECOGNIZED, L"# of Current Recognized Threads", NULL); + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_LOCKSANDTHREADS, DOTNET_INDEX_LOCKSANDTHREADS_CURRENTRECOGNIZED, L"# of Current Recognized Threads", UlongToPtr(DOTNET_INDEX_LOCKSANDTHREADS_CURRENTRECOGNIZED)); // This counter displays the total number of threads that have been recognized by the CLR since the start of this application; // these threads have a corresponding .NET thread object associated with them. // These threads are not created by the CLR; they are created outside the CLR but have since run inside the CLR at least once. // Only unique threads are tracked; threads with same thread ID re-entering the CLR or recreated after thread exit are not counted twice. - PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_LOCKSANDTHREADS, DOTNET_INDEX_LOCKSANDTHREADS_TOTALRECOGNIZED, L"# of Total Recognized Threads", NULL); + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_LOCKSANDTHREADS, DOTNET_INDEX_LOCKSANDTHREADS_TOTALRECOGNIZED, L"# of Total Recognized Threads", UlongToPtr(DOTNET_INDEX_LOCKSANDTHREADS_TOTALRECOGNIZED)); // Contention Rate / sec // Rate at which threads in the runtime attempt to acquire a managed lock unsuccessfully. @@ -392,36 +401,36 @@ VOID DotNetPerfAddListViewGroups( // This counter is incremented at the end of a Gen 0 GC. Higher generation GCs include all lower generation GCs. // This counter is explicitly incremented when a higher generation (Gen 1 or Gen 2) GC occurs. _Global_ counter value is not accurate and should be ignored. // This counter displays the last observed value. - PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_MEMORY, DOTNET_INDEX_MEMORY_GENZEROCOLLECTIONS, L"# Gen 0 Collections", NULL); + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_MEMORY, DOTNET_INDEX_MEMORY_GENZEROCOLLECTIONS, L"# Gen 0 Collections", UlongToPtr(DOTNET_INDEX_MEMORY_GENZEROCOLLECTIONS)); // This counter displays the number of times the generation 1 objects are garbage collected since the start of the application. // The counter is incremented at the end of a Gen 1 GC. Higher generation GCs include all lower generation GCs. // This counter is explicitly incremented when a higher generation (Gen 2) GC occurs. _Global_ counter value is not accurate and should be ignored. // This counter displays the last observed value. - PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_MEMORY, DOTNET_INDEX_MEMORY_GENONECOLLECTIONS, L"# Gen 1 Collections", NULL); + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_MEMORY, DOTNET_INDEX_MEMORY_GENONECOLLECTIONS, L"# Gen 1 Collections", UlongToPtr(DOTNET_INDEX_MEMORY_GENONECOLLECTIONS)); // This counter displays the number of times the generation 2 objects(older) are garbage collected since the start of the application. // The counter is incremented at the end of a Gen 2 GC(also called full GC)._Global_ counter value is not accurate and should be ignored. // This counter displays the last observed value. - PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_MEMORY, DOTNET_INDEX_MEMORY_GENTWOCOLLECTIONS, L"# Gen 2 Collections", NULL); + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_MEMORY, DOTNET_INDEX_MEMORY_GENTWOCOLLECTIONS, L"# Gen 2 Collections", UlongToPtr(DOTNET_INDEX_MEMORY_GENTWOCOLLECTIONS)); // This counter displays the bytes of memory that survive garbage collection(GC) and are promoted from generation 0 to generation 1; // objects that are promoted just because they are waiting to be finalized are not included in this counter. // This counter displays the value observed at the end of the last GC; its not a cumulative counter. - PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_MEMORY, DOTNET_INDEX_MEMORY_PROMOTEDFROMGENZERO, L"Promoted Memory from Gen 0", NULL); + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_MEMORY, DOTNET_INDEX_MEMORY_PROMOTEDFROMGENZERO, L"Promoted Memory from Gen 0", UlongToPtr(DOTNET_INDEX_MEMORY_PROMOTEDFROMGENZERO)); // This counter displays the bytes of memory that survive garbage collection(GC) and are promoted from generation 1 to generation 2; // objects that are promoted just because they are waiting to be finalized are not included in this counter. // This counter displays the value observed at the end of the last GC; its not a cumulative counter. // This counter is reset to 0 if the last GC was a Gen 0 GC only. - PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_MEMORY, DOTNET_INDEX_MEMORY_PROMOTEDFROMGENONE, L"Promoted Memory from Gen 1", NULL); + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_MEMORY, DOTNET_INDEX_MEMORY_PROMOTEDFROMGENONE, L"Promoted Memory from Gen 1", UlongToPtr(DOTNET_INDEX_MEMORY_PROMOTEDFROMGENONE)); // This counter displays the bytes of memory that are promoted from generation 0 to generation 1 just because they are waiting to be finalized. // This counter displays the value observed at the end of the last GC; its not a cumulative counter. - PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_MEMORY, DOTNET_INDEX_MEMORY_PROMOTEDFINALFROMGENZERO, L"Promoted Finalization-Memory from Gen 0", NULL); + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_MEMORY, DOTNET_INDEX_MEMORY_PROMOTEDFINALFROMGENZERO, L"Promoted Finalization-Memory from Gen 0", UlongToPtr(DOTNET_INDEX_MEMORY_PROMOTEDFINALFROMGENZERO)); // Reserved for future use. - PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_MEMORY, DOTNET_INDEX_MEMORY_PROCESSID, L"Process ID", NULL); + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_MEMORY, DOTNET_INDEX_MEMORY_PROCESSID, L"Process ID", UlongToPtr(DOTNET_INDEX_MEMORY_PROCESSID)); // This counter displays the maximum bytes that can be allocated in generation 0 (Gen 0); // its does not indicate the current number of bytes allocated in Gen 0. @@ -429,72 +438,72 @@ VOID DotNetPerfAddListViewGroups( // The Gen 0 size is tuned by the Garbage Collector and can change during the execution of the application. // At the end of a Gen 0 collection the size of the Gen 0 heap is infact 0 bytes; this counter displays the size(in bytes) of allocations that would trigger // the next Gen 0 GC.This counter is updated at the end of a GC; its not updated on every allocation. - PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_MEMORY, DOTNET_INDEX_MEMORY_GENZEROHEAPSIZE, L"Gen 0 Heap Size", NULL); + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_MEMORY, DOTNET_INDEX_MEMORY_GENZEROHEAPSIZE, L"Gen 0 Heap Size", UlongToPtr(DOTNET_INDEX_MEMORY_GENZEROHEAPSIZE)); // This counter displays the current number of bytes in generation 1 (Gen 1); // this counter does not display the maximum size of Gen 1. Objects are not directly allocated in this generation; // they are promoted from previous Gen 0 GCs.This counter is updated at the end of a GC; its not updated on every allocation. - PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_MEMORY, DOTNET_INDEX_MEMORY_GENONEHEAPSIZE, L"Gen 1 Heap Size", NULL); + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_MEMORY, DOTNET_INDEX_MEMORY_GENONEHEAPSIZE, L"Gen 1 Heap Size", UlongToPtr(DOTNET_INDEX_MEMORY_GENONEHEAPSIZE)); // This counter displays the current number of bytes in generation 2 (Gen 2). // Objects are not directly allocated in this generation; they are promoted from Gen 1 during previous Gen 1 GCs. // This counter is updated at the end of a GC; its not updated on every allocation. - PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_MEMORY, DOTNET_INDEX_MEMORY_GENTWOHEAPSIZE, L"Gen 2 Heap Size", NULL); + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_MEMORY, DOTNET_INDEX_MEMORY_GENTWOHEAPSIZE, L"Gen 2 Heap Size", UlongToPtr(DOTNET_INDEX_MEMORY_GENTWOHEAPSIZE)); // This counter displays the current size of the Large Object Heap in bytes. // Objects greater than 20 KBytes are treated as large objects by the Garbage Collector and are directly allocated in a special heap; they are not promoted through the generations. // This counter is updated at the end of a GC; its not updated on every allocation. - PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_MEMORY, DOTNET_INDEX_MEMORY_LOHSIZE, L"Large Object Heap Size", NULL); + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_MEMORY, DOTNET_INDEX_MEMORY_LOHSIZE, L"Large Object Heap Size", UlongToPtr(DOTNET_INDEX_MEMORY_LOHSIZE)); // This counter displays the number of garbage collected objects that survive a collection because they are waiting to be finalized. // If these objects hold references to other objects then those objects also survive but are not counted by this counter; the "Promoted Finalization-Memory from Gen 0" // and "Promoted Finalization-Memory from Gen 1" counters represent all the memory that survived due to finalization. // This counter is not a cumulative counter; its updated at the end of every GC with count of the survivors during that particular GC only. // This counter was designed to indicate the extra overhead that the application might incur because of finalization. - PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_MEMORY, DOTNET_INDEX_MEMORY_FINALSURVIVORS, L"Finalization Survivors", NULL); + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_MEMORY, DOTNET_INDEX_MEMORY_FINALSURVIVORS, L"Finalization Survivors", UlongToPtr(DOTNET_INDEX_MEMORY_FINALSURVIVORS)); // This counter displays the current number of GC Handles in-use. // GCHandles are handles to resources external to the CLR and the managed environment. // Handles occupy small amounts of memory in the GCHeap but potentially expensive unmanaged resources. - PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_MEMORY, DOTNET_INDEX_MEMORY_GCHANDLES, L"# GC Handles", NULL); + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_MEMORY, DOTNET_INDEX_MEMORY_GCHANDLES, L"# GC Handles", UlongToPtr(DOTNET_INDEX_MEMORY_GCHANDLES)); // This counter displays the peak number of times a garbage collection was performed because of an explicit call to GC.Collect. // Its a good practice to let the GC tune the frequency of its collections. - PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_MEMORY, DOTNET_INDEX_MEMORY_INDUCEDGC, L"# Induced GC", NULL); + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_MEMORY, DOTNET_INDEX_MEMORY_INDUCEDGC, L"# Induced GC", UlongToPtr(DOTNET_INDEX_MEMORY_INDUCEDGC)); // % Time in GC is the percentage of elapsed time that was spent in performing a garbage collection(GC) since the last GC cycle. // This counter is usually an indicator of the work done by the Garbage Collector on behalf of the application to collect and compact memory. // This counter is updated only at the end of every GC and the counter value reflects the last observed value; its not an average. - PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_MEMORY, DOTNET_INDEX_MEMORY_TIMEINGC, L"% Time in GC", NULL); + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_MEMORY, DOTNET_INDEX_MEMORY_TIMEINGC, L"% Time in GC", UlongToPtr(DOTNET_INDEX_MEMORY_TIMEINGC)); // This counter is the sum of four other counters; Gen 0 Heap Size; Gen 1 Heap Size; Gen 2 Heap Size and the Large Object Heap Size. // This counter indicates the current memory allocated in bytes on the GC Heaps. - PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_MEMORY, DOTNET_INDEX_MEMORY_BYTESINALLHEAPS, L"# Bytes in all Heaps", NULL); + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_MEMORY, DOTNET_INDEX_MEMORY_BYTESINALLHEAPS, L"# Bytes in all Heaps", UlongToPtr(DOTNET_INDEX_MEMORY_BYTESINALLHEAPS)); // This counter displays the amount of virtual memory(in bytes) currently committed by the Garbage Collector. // (Committed memory is the physical memory for which space has been reserved on the disk paging file). - PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_MEMORY, DOTNET_INDEX_MEMORY_TOTALCOMMITTED, L"# Total Committed Bytes", NULL); + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_MEMORY, DOTNET_INDEX_MEMORY_TOTALCOMMITTED, L"# Total Committed Bytes", UlongToPtr(DOTNET_INDEX_MEMORY_TOTALCOMMITTED)); // This counter displays the amount of virtual memory(in bytes) currently reserved by the Garbage Collector. // (Reserved memory is the virtual memory space reserved for the application but no disk or main memory pages have been used.) - PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_MEMORY, DOTNET_INDEX_MEMORY_TOTALRESERVED, L"# Total Reserved Bytes", NULL); + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_MEMORY, DOTNET_INDEX_MEMORY_TOTALRESERVED, L"# Total Reserved Bytes", UlongToPtr(DOTNET_INDEX_MEMORY_TOTALRESERVED)); // This counter displays the number of pinned objects encountered in the last GC. // This counter tracks the pinned objects only in the heaps that were garbage collected e.g. A Gen 0 GC would cause enumeration of pinned objects in the generation 0 heap only. // A pinned object is one that the Garbage Collector cannot move in memory. - PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_MEMORY, DOTNET_INDEX_MEMORY_TOTALPINNED, L"# of Pinned Objects", NULL); + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_MEMORY, DOTNET_INDEX_MEMORY_TOTALPINNED, L"# of Pinned Objects", UlongToPtr(DOTNET_INDEX_MEMORY_TOTALPINNED)); // This counter displays the current number of sync blocks in use. Sync blocks are per-object data structures allocated for storing synchronization information. // Sync blocks hold weak references to managed objects and need to be scanned by the Garbage Collector. // Sync blocks are not limited to storing synchronization information and can also store COM interop metadata. // This counter was designed to indicate performance problems with heavy use of synchronization primitives. - PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_MEMORY, DOTNET_INDEX_MEMORY_TOTALSINKS, L"# of Sink Blocks in use", NULL); + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_MEMORY, DOTNET_INDEX_MEMORY_TOTALSINKS, L"# of Sink Blocks in use", UlongToPtr(DOTNET_INDEX_MEMORY_TOTALSINKS)); // Reserved for future use. - PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_MEMORY, DOTNET_INDEX_MEMORY_TOTALBYTESSINCESTART, L"Total Bytes Allocated (since start)", NULL); + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_MEMORY, DOTNET_INDEX_MEMORY_TOTALBYTESSINCESTART, L"Total Bytes Allocated (since start)", UlongToPtr(DOTNET_INDEX_MEMORY_TOTALBYTESSINCESTART)); // Reserved for future use. - PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_MEMORY, DOTNET_INDEX_MEMORY_TOTALLOHBYTESSINCESTART, L"Total Bytes Allocated for Large Objects (since start)", NULL); + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_MEMORY, DOTNET_INDEX_MEMORY_TOTALLOHBYTESSINCESTART, L"Total Bytes Allocated for Large Objects (since start)", UlongToPtr(DOTNET_INDEX_MEMORY_TOTALLOHBYTESSINCESTART)); // Gen 0 Promoted Bytes / Sec // This counter displays the bytes per second that are promoted from generation 0 (youngest)to generation 1; @@ -525,27 +534,27 @@ VOID DotNetPerfAddListViewGroups( // This counter displays the total number of remote procedure calls invoked since the start of this application. // A remote procedure call is a call on any object outside the callers AppDomain. - PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_REMOTING, DOTNET_INDEX_REMOTING_TOTALREMOTECALLS, L"Total Remote Calls", NULL); + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_REMOTING, DOTNET_INDEX_REMOTING_TOTALREMOTECALLS, L"Total Remote Calls", UlongToPtr(DOTNET_INDEX_REMOTING_TOTALREMOTECALLS)); // This counter displays the total number of remoting channels registered across all AppDomains since the start of the application. // Channels are used to transport messages to and from remote objects. - PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_REMOTING, DOTNET_INDEX_REMOTING_CHANNELS, L"Channels", NULL); + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_REMOTING, DOTNET_INDEX_REMOTING_CHANNELS, L"Channels", UlongToPtr(DOTNET_INDEX_REMOTING_CHANNELS)); // This counter displays the total number of remoting proxy objects created in this process since the start of the process. // Proxy object acts as a representative of the remote objects and ensures that all calls made on the proxy are forwarded to the correct remote object instance. - PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_REMOTING, DOTNET_INDEX_REMOTING_CONTEXTPROXIES, L"Context Proxies", NULL); + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_REMOTING, DOTNET_INDEX_REMOTING_CONTEXTPROXIES, L"Context Proxies", UlongToPtr(DOTNET_INDEX_REMOTING_CONTEXTPROXIES)); // This counter displays the current number of context-bound classes loaded. // Classes that can be bound to a context are called context-bound classes; context-bound classes are marked with Context Attributes // which provide usage rules for synchronization; thread affinity; transactions etc. - PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_REMOTING, DOTNET_INDEX_REMOTING_CONTEXTCLASSESLOADED, L"Context-Bound Classes Loaded", NULL); + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_REMOTING, DOTNET_INDEX_REMOTING_CONTEXTCLASSESLOADED, L"Context-Bound Classes Loaded", UlongToPtr(DOTNET_INDEX_REMOTING_CONTEXTCLASSESLOADED)); // This counter displays the current number of remoting contexts in the application. // A context is a boundary containing a collection of objects with the same usage rules like synchronization; thread affinity; transactions etc. - PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_REMOTING, DOTNET_INDEX_REMOTING_CONTEXTS, L"Contexts", NULL); + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_REMOTING, DOTNET_INDEX_REMOTING_CONTEXTS, L"Contexts", UlongToPtr(DOTNET_INDEX_REMOTING_CONTEXTS)); // Reserved for future use. - PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_REMOTING, DOTNET_INDEX_REMOTING_CONTEXTSALLOCATED, L"# of context bound objects allocated", NULL); + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_REMOTING, DOTNET_INDEX_REMOTING_CONTEXTSALLOCATED, L"# of context bound objects allocated", UlongToPtr(DOTNET_INDEX_REMOTING_CONTEXTSALLOCATED)); // Remote Calls / sec // This counter displays the number of remote procedure calls invoked per second. @@ -564,22 +573,22 @@ VOID DotNetPerfAddListViewGroups( // Runtime CAS checks are performed when a caller makes a call to a callee demanding a particular permission; // the runtime check is made on every call by the caller; the check is done by examining the current thread stack of the caller. // This counter used together with "Stack Walk Depth" is indicative of performance penalty for security checks. - PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_SECURITY, DOTNET_INDEX_SECURITY_TOTALRUNTIMECHECKS, L"Total Runtime Checks", NULL); + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_SECURITY, DOTNET_INDEX_SECURITY_TOTALRUNTIMECHECKS, L"Total Runtime Checks", UlongToPtr(DOTNET_INDEX_SECURITY_TOTALRUNTIMECHECKS)); // This counter displays the total number of linktime Code Access Security(CAS) checks since the start of the application. // Linktime CAS checks are performed when a caller makes a call to a callee demanding a particular permission at JIT compile time; linktime check is performed once per caller. // This count is not indicative of serious performance issues; its indicative of the security system activity. - PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_SECURITY, DOTNET_INDEX_SECURITY_LINKTIMECHECKS, L"# Link Time Checks", NULL); + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_SECURITY, DOTNET_INDEX_SECURITY_LINKTIMECHECKS, L"# Link Time Checks", UlongToPtr(DOTNET_INDEX_SECURITY_LINKTIMECHECKS)); // This counter displays the percentage of elapsed time spent in performing runtime Code Access Security(CAS) checks since the last such check. // CAS allows code to be trusted to varying degrees and enforces these varying levels of trust depending on code identity. // This counter is updated at the end of a runtime security check; it represents the last observed value; its not an average. - PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_SECURITY, DOTNET_INDEX_SECURITY_TIMEINRTCHECKS, L"% Time in RT checks", NULL); + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_SECURITY, DOTNET_INDEX_SECURITY_TIMEINRTCHECKS, L"% Time in RT checks", UlongToPtr(DOTNET_INDEX_SECURITY_TIMEINRTCHECKS)); // This counter displays the depth of the stack during that last runtime Code Access Security check. // Runtime Code Access Security check is performed by crawling the stack. // This counter is not an average; it just displays the last observed value. - PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_SECURITY, DOTNET_INDEX_SECURITY_STACKWALKDEPTH, L"Stack Walk Depth", NULL); + PhAddListViewGroupItem(ListViewHandle, DOTNET_CATEGORY_SECURITY, DOTNET_INDEX_SECURITY_STACKWALKDEPTH, L"Stack Walk Depth", UlongToPtr(DOTNET_INDEX_SECURITY_STACKWALKDEPTH)); // % Time Sig.Authenticating // Reserved for future use. @@ -590,8 +599,8 @@ VOID DotNetPerfAddProcessAppDomains( _In_ PPERFPAGE_CONTEXT Context ) { - ExtendedListView_SetRedraw(Context->AppDomainsLv, FALSE); - ListView_DeleteAllItems(Context->AppDomainsLv); + ExtendedListView_SetRedraw(Context->AppDomainsListViewHandle, FALSE); + ListView_DeleteAllItems(Context->AppDomainsListViewHandle); if (Context->ClrV4) { @@ -605,7 +614,7 @@ VOID DotNetPerfAddProcessAppDomains( { for (ULONG i = 0; i < processAppDomains->Count; i++) { - PhAddListViewItem(Context->AppDomainsLv, MAXINT, processAppDomains->Items[i], NULL); + PhAddListViewItem(Context->AppDomainsListViewHandle, MAXINT, processAppDomains->Items[i], NULL); PhFree(processAppDomains->Items[i]); } @@ -624,7 +633,7 @@ VOID DotNetPerfAddProcessAppDomains( { for (ULONG i = 0; i < processAppDomains->Count; i++) { - PhAddListViewItem(Context->AppDomainsLv, MAXINT, processAppDomains->Items[i], NULL); + PhAddListViewItem(Context->AppDomainsListViewHandle, MAXINT, processAppDomains->Items[i], NULL); PhFree(processAppDomains->Items[i]); } @@ -632,7 +641,7 @@ VOID DotNetPerfAddProcessAppDomains( } } - ExtendedListView_SetRedraw(Context->AppDomainsLv, TRUE); + ExtendedListView_SetRedraw(Context->AppDomainsListViewHandle, TRUE); } VOID DotNetPerfUpdateCounterData( @@ -640,15 +649,7 @@ VOID DotNetPerfUpdateCounterData( _In_ PPERFPAGE_CONTEXT Context ) { - PVOID perfStatBlock = NULL; - Perf_GC dotNetPerfGC; - Perf_Contexts dotNetPerfContext; - Perf_Interop dotNetPerfInterop; - Perf_Loading dotNetPerfLoading; - Perf_Excep dotNetPerfExcep; - Perf_LocksAndThreads dotNetPerfLocksAndThreads; - Perf_Jit dotNetPerfJit; - Perf_Security dotNetPerfSecurity; + PVOID perfStatBlock; if (Context->ClrV4) { @@ -677,192 +678,72 @@ VOID DotNetPerfUpdateCounterData( // Thunk the Wow64 structures into their 64bit versions (or 32bit version on x86). - dotNetPerfGC.cGenCollections[0] = dotNetPerfGC_Wow64.cGenCollections[0]; - dotNetPerfGC.cGenCollections[1] = dotNetPerfGC_Wow64.cGenCollections[1]; - dotNetPerfGC.cGenCollections[2] = dotNetPerfGC_Wow64.cGenCollections[2]; - dotNetPerfGC.cbPromotedMem[0] = dotNetPerfGC_Wow64.cbPromotedMem[0]; - dotNetPerfGC.cbPromotedMem[1] = dotNetPerfGC_Wow64.cbPromotedMem[1]; - dotNetPerfGC.cbPromotedFinalizationMem = dotNetPerfGC_Wow64.cbPromotedFinalizationMem; - dotNetPerfGC.cProcessID = dotNetPerfGC_Wow64.cProcessID; - dotNetPerfGC.cGenHeapSize[0] = dotNetPerfGC_Wow64.cGenHeapSize[0]; - dotNetPerfGC.cGenHeapSize[1] = dotNetPerfGC_Wow64.cGenHeapSize[1]; - dotNetPerfGC.cGenHeapSize[2] = dotNetPerfGC_Wow64.cGenHeapSize[2]; - dotNetPerfGC.cTotalCommittedBytes = dotNetPerfGC_Wow64.cTotalCommittedBytes; - dotNetPerfGC.cTotalReservedBytes = dotNetPerfGC_Wow64.cTotalReservedBytes; - dotNetPerfGC.cLrgObjSize = dotNetPerfGC_Wow64.cLrgObjSize; - dotNetPerfGC.cSurviveFinalize = dotNetPerfGC_Wow64.cSurviveFinalize; - dotNetPerfGC.cHandles = dotNetPerfGC_Wow64.cHandles; - dotNetPerfGC.cbAlloc = dotNetPerfGC_Wow64.cbAlloc; - dotNetPerfGC.cbLargeAlloc = dotNetPerfGC_Wow64.cbLargeAlloc; - dotNetPerfGC.cInducedGCs = dotNetPerfGC_Wow64.cInducedGCs; - dotNetPerfGC.timeInGC = dotNetPerfGC_Wow64.timeInGC; - dotNetPerfGC.timeInGCBase = dotNetPerfGC_Wow64.timeInGCBase; - dotNetPerfGC.cPinnedObj = dotNetPerfGC_Wow64.cPinnedObj; - dotNetPerfGC.cSinkBlocks = dotNetPerfGC_Wow64.cSinkBlocks; - - dotNetPerfContext = perfBlock->Context; - dotNetPerfInterop = perfBlock->Interop; - - dotNetPerfLoading.cClassesLoaded.Current = dotNetPerfLoading_Wow64.cClassesLoaded.Current; - dotNetPerfLoading.cClassesLoaded.Total = dotNetPerfLoading_Wow64.cClassesLoaded.Total; - dotNetPerfLoading.cAppDomains.Current = dotNetPerfLoading_Wow64.cAppDomains.Current; - dotNetPerfLoading.cAppDomains.Total = dotNetPerfLoading_Wow64.cAppDomains.Total; - dotNetPerfLoading.cAssemblies.Current = dotNetPerfLoading_Wow64.cAssemblies.Current; - dotNetPerfLoading.cAssemblies.Total = dotNetPerfLoading_Wow64.cAssemblies.Total; - dotNetPerfLoading.timeLoading = dotNetPerfLoading_Wow64.timeLoading; - dotNetPerfLoading.cAsmSearchLen = dotNetPerfLoading_Wow64.cAsmSearchLen; - dotNetPerfLoading.cLoadFailures.Total = dotNetPerfLoading_Wow64.cLoadFailures.Total; - dotNetPerfLoading.cbLoaderHeapSize = dotNetPerfLoading_Wow64.cbLoaderHeapSize; - dotNetPerfLoading.cAppDomainsUnloaded = dotNetPerfLoading_Wow64.cAppDomainsUnloaded; - - dotNetPerfExcep = perfBlock->Excep; - dotNetPerfLocksAndThreads = perfBlock->LocksAndThreads; - dotNetPerfJit = perfBlock->Jit; - - dotNetPerfSecurity.cTotalRTChecks = dotNetPerfSecurity_Wow64.cTotalRTChecks; - dotNetPerfSecurity.timeAuthorize = dotNetPerfSecurity_Wow64.timeAuthorize; - dotNetPerfSecurity.cLinkChecks = dotNetPerfSecurity_Wow64.cLinkChecks; - dotNetPerfSecurity.timeRTchecks = dotNetPerfSecurity_Wow64.timeRTchecks; - dotNetPerfSecurity.timeRTchecksBase = dotNetPerfSecurity_Wow64.timeRTchecksBase; - dotNetPerfSecurity.stackWalkDepth = dotNetPerfSecurity_Wow64.stackWalkDepth; + Context->DotNetPerfGC.cGenCollections[0] = dotNetPerfGC_Wow64.cGenCollections[0]; + Context->DotNetPerfGC.cGenCollections[1] = dotNetPerfGC_Wow64.cGenCollections[1]; + Context->DotNetPerfGC.cGenCollections[2] = dotNetPerfGC_Wow64.cGenCollections[2]; + Context->DotNetPerfGC.cbPromotedMem[0] = dotNetPerfGC_Wow64.cbPromotedMem[0]; + Context->DotNetPerfGC.cbPromotedMem[1] = dotNetPerfGC_Wow64.cbPromotedMem[1]; + Context->DotNetPerfGC.cbPromotedFinalizationMem = dotNetPerfGC_Wow64.cbPromotedFinalizationMem; + Context->DotNetPerfGC.cProcessID = dotNetPerfGC_Wow64.cProcessID; + Context->DotNetPerfGC.cGenHeapSize[0] = dotNetPerfGC_Wow64.cGenHeapSize[0]; + Context->DotNetPerfGC.cGenHeapSize[1] = dotNetPerfGC_Wow64.cGenHeapSize[1]; + Context->DotNetPerfGC.cGenHeapSize[2] = dotNetPerfGC_Wow64.cGenHeapSize[2]; + Context->DotNetPerfGC.cTotalCommittedBytes = dotNetPerfGC_Wow64.cTotalCommittedBytes; + Context->DotNetPerfGC.cTotalReservedBytes = dotNetPerfGC_Wow64.cTotalReservedBytes; + Context->DotNetPerfGC.cLrgObjSize = dotNetPerfGC_Wow64.cLrgObjSize; + Context->DotNetPerfGC.cSurviveFinalize = dotNetPerfGC_Wow64.cSurviveFinalize; + Context->DotNetPerfGC.cHandles = dotNetPerfGC_Wow64.cHandles; + Context->DotNetPerfGC.cbAlloc = dotNetPerfGC_Wow64.cbAlloc; + Context->DotNetPerfGC.cbLargeAlloc = dotNetPerfGC_Wow64.cbLargeAlloc; + Context->DotNetPerfGC.cInducedGCs = dotNetPerfGC_Wow64.cInducedGCs; + Context->DotNetPerfGC.timeInGC = dotNetPerfGC_Wow64.timeInGC; + Context->DotNetPerfGC.timeInGCBase = dotNetPerfGC_Wow64.timeInGCBase; + Context->DotNetPerfGC.cPinnedObj = dotNetPerfGC_Wow64.cPinnedObj; + Context->DotNetPerfGC.cSinkBlocks = dotNetPerfGC_Wow64.cSinkBlocks; + + Context->DotNetPerfContext = perfBlock->Context; + Context->DotNetPerfInterop = perfBlock->Interop; + + Context->DotNetPerfLoading.cClassesLoaded.Current = dotNetPerfLoading_Wow64.cClassesLoaded.Current; + Context->DotNetPerfLoading.cClassesLoaded.Total = dotNetPerfLoading_Wow64.cClassesLoaded.Total; + Context->DotNetPerfLoading.cAppDomains.Current = dotNetPerfLoading_Wow64.cAppDomains.Current; + Context->DotNetPerfLoading.cAppDomains.Total = dotNetPerfLoading_Wow64.cAppDomains.Total; + Context->DotNetPerfLoading.cAssemblies.Current = dotNetPerfLoading_Wow64.cAssemblies.Current; + Context->DotNetPerfLoading.cAssemblies.Total = dotNetPerfLoading_Wow64.cAssemblies.Total; + Context->DotNetPerfLoading.timeLoading = dotNetPerfLoading_Wow64.timeLoading; + Context->DotNetPerfLoading.cAsmSearchLen = dotNetPerfLoading_Wow64.cAsmSearchLen; + Context->DotNetPerfLoading.cLoadFailures.Total = dotNetPerfLoading_Wow64.cLoadFailures.Total; + Context->DotNetPerfLoading.cbLoaderHeapSize = dotNetPerfLoading_Wow64.cbLoaderHeapSize; + Context->DotNetPerfLoading.cAppDomainsUnloaded = dotNetPerfLoading_Wow64.cAppDomainsUnloaded; + + Context->DotNetPerfExceptions = perfBlock->Exceptions; + Context->DotNetPerfLocksAndThreads = perfBlock->LocksAndThreads; + Context->DotNetPerfJit = perfBlock->Jit; + + Context->DotNetPerfSecurity.cTotalRTChecks = dotNetPerfSecurity_Wow64.cTotalRTChecks; + Context->DotNetPerfSecurity.timeAuthorize = dotNetPerfSecurity_Wow64.timeAuthorize; + Context->DotNetPerfSecurity.cLinkChecks = dotNetPerfSecurity_Wow64.cLinkChecks; + Context->DotNetPerfSecurity.timeRTchecks = dotNetPerfSecurity_Wow64.timeRTchecks; + Context->DotNetPerfSecurity.timeRTchecksBase = dotNetPerfSecurity_Wow64.timeRTchecksBase; + Context->DotNetPerfSecurity.stackWalkDepth = dotNetPerfSecurity_Wow64.stackWalkDepth; } else { PerfCounterIPCControlBlock* perfBlock = perfStatBlock; - dotNetPerfGC = perfBlock->GC; - dotNetPerfContext = perfBlock->Context; - dotNetPerfInterop = perfBlock->Interop; - dotNetPerfLoading = perfBlock->Loading; - dotNetPerfExcep = perfBlock->Excep; - dotNetPerfLocksAndThreads = perfBlock->LocksAndThreads; - dotNetPerfJit = perfBlock->Jit; - dotNetPerfSecurity = perfBlock->Security; + Context->DotNetPerfGC = perfBlock->GC; + Context->DotNetPerfContext = perfBlock->Context; + Context->DotNetPerfInterop = perfBlock->Interop; + Context->DotNetPerfLoading = perfBlock->Loading; + Context->DotNetPerfExceptions = perfBlock->Exceptions; + Context->DotNetPerfLocksAndThreads = perfBlock->LocksAndThreads; + Context->DotNetPerfJit = perfBlock->Jit; + Context->DotNetPerfSecurity = perfBlock->Security; } - PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_EXCEPTIONS_THROWNCOUNT, 1, PhaFormatUInt64(dotNetPerfExcep.cThrown.Total, TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_EXCEPTIONS_FILTERSCOUNT, 1, PhaFormatUInt64(dotNetPerfExcep.cFiltersExecuted, TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_EXCEPTIONS_FINALLYCOUNT, 1, PhaFormatUInt64(dotNetPerfExcep.cFinallysExecuted, TRUE)->Buffer); - //PhSetListViewSubItem(Context->CountersLv, , 1, PhaFormatUInt64(dotNetPerfExcep.cThrowToCatchStackDepth, TRUE)->Buffer); - - PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_INTEROP_CCWCOUNT, 1, PhaFormatUInt64(dotNetPerfInterop.cCCW, TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_INTEROP_STUBCOUNT, 1, PhaFormatUInt64(dotNetPerfInterop.cStubs, TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_INTEROP_MARSHALCOUNT, 1, PhaFormatUInt64(dotNetPerfInterop.cMarshalling, TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_INTEROP_TLBIMPORTPERSEC, 1, PhaFormatUInt64(dotNetPerfInterop.cTLBImports, TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_INTEROP_TLBEXPORTPERSEC, 1, PhaFormatUInt64(dotNetPerfInterop.cTLBExports, TRUE)->Buffer); - - PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_JIT_ILMETHODSJITTED, 1, PhaFormatUInt64(dotNetPerfJit.cMethodsJitted, TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_JIT_ILBYTESJITTED, 1, PhaFormatSize(dotNetPerfJit.cbILJitted.Current, ULONG_MAX)->Buffer); - PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_JIT_ILTOTALBYTESJITTED, 1, PhaFormatSize(dotNetPerfJit.cbILJitted.Total, ULONG_MAX)->Buffer); - PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_JIT_FAILURES, 1, PhaFormatUInt64(dotNetPerfJit.cJitFailures, TRUE)->Buffer); - - if (dotNetPerfJit.timeInJitBase != 0) - { - PH_FORMAT format[1]; - WCHAR formatBuffer[10]; - - // TODO: TimeInJit is always above 100% for some processes ?? - // SeeAlso: https://github.com/dotnet/coreclr/blob/master/src/gc/gcee.cpp#L324 - PhInitFormatF(&format[0], (dotNetPerfJit.timeInJit << 8) * 100 / (FLOAT)(dotNetPerfJit.timeInJitBase << 8), 2); - - if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), formatBuffer, sizeof(formatBuffer), NULL)) - PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_JIT_TIME, 1, formatBuffer); - } - else - { - PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_JIT_TIME, 1, L"0.00"); - } - - PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_LOADING_CURRENTLOADED, 1, PhaFormatUInt64(dotNetPerfLoading.cClassesLoaded.Current, TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_LOADING_TOTALLOADED, 1, PhaFormatUInt64(dotNetPerfLoading.cClassesLoaded.Total, TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_LOADING_CURRENTAPPDOMAINS, 1, PhaFormatUInt64(dotNetPerfLoading.cAppDomains.Current, TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_LOADING_TOTALAPPDOMAINS, 1, PhaFormatUInt64(dotNetPerfLoading.cAppDomains.Total, TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_LOADING_CURRENTASSEMBLIES, 1, PhaFormatUInt64(dotNetPerfLoading.cAssemblies.Current, TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_LOADING_TOTALASSEMBLIES, 1, PhaFormatUInt64(dotNetPerfLoading.cAssemblies.Total, TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_LOADING_ASSEMBLYSEARCHLENGTH, 1, PhaFormatUInt64(dotNetPerfLoading.cAsmSearchLen, TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_LOADING_TOTALLOADFAILURES, 1, PhaFormatUInt64(dotNetPerfLoading.cLoadFailures.Total, TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_LOADING_BYTESINLOADERHEAP, 1, PhaFormatSize(dotNetPerfLoading.cbLoaderHeapSize, ULONG_MAX)->Buffer); - PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_LOADING_TOTALAPPDOMAINSUNLOADED, 1, PhaFormatUInt64(dotNetPerfLoading.cAppDomainsUnloaded.Total, TRUE)->Buffer); - //PhSetListViewSubItem(Context->CountersLv, 10, 1, PhaFormatUInt64(dotNetPerfLoading.timeLoading, TRUE)->Buffer); - - // DOTNET_CATEGORY_LOCKSANDTHREADS - PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_LOCKSANDTHREADS_TOTALLOCKS, 1, PhaFormatUInt64(dotNetPerfLocksAndThreads.cContention.Total, TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_LOCKSANDTHREADS_TOTALQUEUELENGTH, 1, PhaFormatUInt64(dotNetPerfLocksAndThreads.cQueueLength.Current, TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_LOCKSANDTHREADS_QUEUELENGTHPEAK, 1, PhaFormatUInt64(dotNetPerfLocksAndThreads.cQueueLength.Total, TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_LOCKSANDTHREADS_CURRENTLOGICAL, 1, PhaFormatUInt64(dotNetPerfLocksAndThreads.cCurrentThreadsLogical, TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_LOCKSANDTHREADS_CURRENTPHYSICAL, 1, PhaFormatUInt64(dotNetPerfLocksAndThreads.cCurrentThreadsPhysical, TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_LOCKSANDTHREADS_CURRENTRECOGNIZED, 1, PhaFormatUInt64(dotNetPerfLocksAndThreads.cRecognizedThreads.Current, TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_LOCKSANDTHREADS_TOTALRECOGNIZED, 1, PhaFormatUInt64(dotNetPerfLocksAndThreads.cRecognizedThreads.Total, TRUE)->Buffer); - - // DOTNET_CATEGORY_MEMORY - PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_MEMORY_GENZEROCOLLECTIONS, 1, PhaFormatUInt64(dotNetPerfGC.cGenCollections[0], TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_MEMORY_GENONECOLLECTIONS, 1, PhaFormatUInt64(dotNetPerfGC.cGenCollections[1], TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_MEMORY_GENTWOCOLLECTIONS, 1, PhaFormatUInt64(dotNetPerfGC.cGenCollections[2], TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_MEMORY_PROMOTEDFROMGENZERO, 1, PhaFormatSize(dotNetPerfGC.cbPromotedMem[0], ULONG_MAX)->Buffer); - PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_MEMORY_PROMOTEDFROMGENONE, 1, PhaFormatSize(dotNetPerfGC.cbPromotedMem[1], ULONG_MAX)->Buffer); - PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_MEMORY_PROMOTEDFINALFROMGENZERO, 1, PhaFormatSize(dotNetPerfGC.cbPromotedFinalizationMem, ULONG_MAX)->Buffer); - PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_MEMORY_PROCESSID, 1, PhaFormatUInt64(dotNetPerfGC.cProcessID, FALSE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_MEMORY_GENZEROHEAPSIZE, 1, PhaFormatSize(dotNetPerfGC.cGenHeapSize[0], ULONG_MAX)->Buffer); - PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_MEMORY_GENONEHEAPSIZE, 1, PhaFormatSize(dotNetPerfGC.cGenHeapSize[1], ULONG_MAX)->Buffer); - PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_MEMORY_GENTWOHEAPSIZE, 1, PhaFormatSize(dotNetPerfGC.cGenHeapSize[2], ULONG_MAX)->Buffer); - PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_MEMORY_LOHSIZE, 1, PhaFormatSize(dotNetPerfGC.cLrgObjSize, ULONG_MAX)->Buffer); - PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_MEMORY_FINALSURVIVORS, 1, PhaFormatUInt64(dotNetPerfGC.cSurviveFinalize, TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_MEMORY_GCHANDLES, 1, PhaFormatUInt64(dotNetPerfGC.cHandles, TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_MEMORY_INDUCEDGC, 1, PhaFormatUInt64(dotNetPerfGC.cInducedGCs, TRUE)->Buffer); - - if (dotNetPerfGC.timeInGCBase != 0) - { - PH_FORMAT format[1]; - WCHAR formatBuffer[10]; - - PhInitFormatF(&format[0], (FLOAT)dotNetPerfGC.timeInGC * 100 / (FLOAT)dotNetPerfGC.timeInGCBase, 2); - - if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), formatBuffer, sizeof(formatBuffer), NULL)) - PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_MEMORY_TIMEINGC, 1, formatBuffer); - } - else - { - PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_MEMORY_TIMEINGC, 1, L"0.00"); - } - - // The CLR source says this value should be "Gen 0 Heap Size; Gen 1 Heap Size; Gen 2 Heap Size and the Large Object Heap Size", - // but Perflib only counts Gen 1, Gen 2 and cLrgObjSize... For now, just do what perflib does. - PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_MEMORY_BYTESINALLHEAPS, 1, PhaFormatSize(dotNetPerfGC.cGenHeapSize[1] + dotNetPerfGC.cGenHeapSize[2] + dotNetPerfGC.cLrgObjSize, ULONG_MAX)->Buffer); - PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_MEMORY_TOTALCOMMITTED, 1, PhaFormatSize(dotNetPerfGC.cTotalCommittedBytes, ULONG_MAX)->Buffer); - PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_MEMORY_TOTALRESERVED, 1, PhaFormatSize(dotNetPerfGC.cTotalReservedBytes, ULONG_MAX)->Buffer); - PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_MEMORY_TOTALPINNED, 1, PhaFormatUInt64(dotNetPerfGC.cPinnedObj, TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_MEMORY_TOTALSINKS, 1, PhaFormatUInt64(dotNetPerfGC.cSinkBlocks, TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_MEMORY_TOTALBYTESSINCESTART, 1, PhaFormatSize(dotNetPerfGC.cbAlloc, ULONG_MAX)->Buffer); - PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_MEMORY_TOTALLOHBYTESSINCESTART, 1, PhaFormatSize(dotNetPerfGC.cbLargeAlloc, ULONG_MAX)->Buffer); - - // DOTNET_CATEGORY_REMOTING - PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_REMOTING_TOTALREMOTECALLS, 1, PhaFormatUInt64(dotNetPerfContext.cRemoteCalls.Total, TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_REMOTING_CHANNELS, 1, PhaFormatUInt64(dotNetPerfContext.cChannels, TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_REMOTING_CONTEXTPROXIES, 1, PhaFormatUInt64(dotNetPerfContext.cProxies, TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_REMOTING_CONTEXTCLASSESLOADED, 1, PhaFormatUInt64(dotNetPerfContext.cClasses, TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_REMOTING_CONTEXTS, 1, PhaFormatUInt64(dotNetPerfContext.cContexts, TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_REMOTING_CONTEXTSALLOCATED, 1, PhaFormatUInt64(dotNetPerfContext.cObjAlloc, TRUE)->Buffer); - - // DOTNET_CATEGORY_SECURITY - PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_SECURITY_TOTALRUNTIMECHECKS, 1, PhaFormatUInt64(dotNetPerfSecurity.cTotalRTChecks, TRUE)->Buffer); - PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_SECURITY_LINKTIMECHECKS, 1, PhaFormatUInt64(dotNetPerfSecurity.cLinkChecks, TRUE)->Buffer); - - if (dotNetPerfSecurity.timeRTchecksBase != 0) - { - PH_FORMAT format[1]; - WCHAR formatBuffer[10]; - - PhInitFormatF(&format[0], (FLOAT)dotNetPerfSecurity.timeRTchecks * 100 / (FLOAT)dotNetPerfSecurity.timeRTchecksBase, 2); - - if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), formatBuffer, sizeof(formatBuffer), NULL)) - PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_SECURITY_TIMEINRTCHECKS, 1, formatBuffer); - } - else - { - PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_SECURITY_TIMEINRTCHECKS, 1, L"0.00"); - } - - PhSetListViewSubItem(Context->CountersLv, DOTNET_INDEX_SECURITY_STACKWALKDEPTH, 1, PhaFormatUInt64(dotNetPerfSecurity.stackWalkDepth, TRUE)->Buffer); + // The ListView doesn't send LVN_GETDISPINFO (or redraw properly) when not focused so we'll force a redraw. (dmex) + ListView_RedrawItems(Context->CountersListViewHandle, 0, DOTNET_INDEX_MAXIMUM); + UpdateWindow(Context->CountersListViewHandle); } INT_PTR CALLBACK DotNetPerfPageDlgProc( @@ -893,23 +774,23 @@ INT_PTR CALLBACK DotNetPerfPageDlgProc( context = propPageContext->Context = PhAllocateZero(sizeof(PERFPAGE_CONTEXT)); context->WindowHandle = hwndDlg; context->ProcessItem = processItem; - context->AppDomainsLv = GetDlgItem(hwndDlg, IDC_APPDOMAINS); - context->CountersLv = GetDlgItem(hwndDlg, IDC_COUNTERS); + context->AppDomainsListViewHandle = GetDlgItem(hwndDlg, IDC_APPDOMAINS); + context->CountersListViewHandle = GetDlgItem(hwndDlg, IDC_COUNTERS); context->Enabled = TRUE; - PhSetListViewStyle(context->AppDomainsLv, FALSE, TRUE); - PhSetControlTheme(context->AppDomainsLv, L"explorer"); - PhAddListViewColumn(context->AppDomainsLv, 0, 0, 0, LVCFMT_LEFT, 300, L"Application domain"); - PhSetExtendedListView(context->AppDomainsLv); + PhSetListViewStyle(context->AppDomainsListViewHandle, FALSE, TRUE); + PhSetControlTheme(context->AppDomainsListViewHandle, L"explorer"); + PhAddListViewColumn(context->AppDomainsListViewHandle, 0, 0, 0, LVCFMT_LEFT, 300, L"Application domain"); + PhSetExtendedListView(context->AppDomainsListViewHandle); - PhSetListViewStyle(context->CountersLv, FALSE, TRUE); - PhSetControlTheme(context->CountersLv, L"explorer"); - PhAddListViewColumn(context->CountersLv, 0, 0, 0, LVCFMT_LEFT, 250, L"Counter"); - PhAddListViewColumn(context->CountersLv, 1, 1, 1, LVCFMT_RIGHT, 140, L"Value"); - PhSetExtendedListView(context->CountersLv); + PhSetListViewStyle(context->CountersListViewHandle, FALSE, TRUE); + PhSetControlTheme(context->CountersListViewHandle, L"explorer"); + PhAddListViewColumn(context->CountersListViewHandle, 0, 0, 0, LVCFMT_LEFT, 250, L"Counter"); + PhAddListViewColumn(context->CountersListViewHandle, 1, 1, 1, LVCFMT_RIGHT, 140, L"Value"); + PhSetExtendedListView(context->CountersListViewHandle); - DotNetPerfAddListViewGroups(context->CountersLv); - PhLoadListViewColumnsFromSetting(SETTING_NAME_DOT_NET_COUNTERS_COLUMNS, context->CountersLv); + DotNetPerfAddListViewGroups(context->CountersListViewHandle); + PhLoadListViewColumnsFromSetting(SETTING_NAME_DOT_NET_COUNTERS_COLUMNS, context->CountersListViewHandle); #ifdef _WIN64 context->IsWow64 = !!context->ProcessItem->IsWow64; @@ -1009,7 +890,7 @@ INT_PTR CALLBACK DotNetPerfPageDlgProc( NtClose(context->ProcessHandle); } - PhSaveListViewColumnsToSetting(SETTING_NAME_DOT_NET_COUNTERS_COLUMNS, context->CountersLv); + PhSaveListViewColumnsToSetting(SETTING_NAME_DOT_NET_COUNTERS_COLUMNS, context->CountersListViewHandle); PhFree(context); } @@ -1020,12 +901,12 @@ INT_PTR CALLBACK DotNetPerfPageDlgProc( if (dialogItem = PhBeginPropPageLayout(hwndDlg, propPageContext)) { - PhAddPropPageLayoutItem(hwndDlg, context->AppDomainsLv, dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); - PhAddPropPageLayoutItem(hwndDlg, context->CountersLv, dialogItem, PH_ANCHOR_ALL); + PhAddPropPageLayoutItem(hwndDlg, context->AppDomainsListViewHandle, dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); + PhAddPropPageLayoutItem(hwndDlg, context->CountersListViewHandle, dialogItem, PH_ANCHOR_ALL); PhEndPropPageLayout(hwndDlg, propPageContext); } - ExtendedListView_SetColumnWidth(context->AppDomainsLv, 0, ELVSCW_AUTOSIZE_REMAININGSPACE); + ExtendedListView_SetColumnWidth(context->AppDomainsListViewHandle, 0, ELVSCW_AUTOSIZE_REMAININGSPACE); } break; case WM_NOTIFY: @@ -1041,12 +922,871 @@ INT_PTR CALLBACK DotNetPerfPageDlgProc( context->Enabled = FALSE; break; case PSN_QUERYINITIALFOCUS: - SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, (LPARAM)context->CountersLv); + SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, (LPARAM)context->CountersListViewHandle); return TRUE; + case LVN_GETDISPINFO: + { + NMLVDISPINFO *dispInfo = (NMLVDISPINFO *)header; + + if (dispInfo->item.iSubItem == 1) + { + if (dispInfo->item.mask & LVIF_TEXT) + { + switch (PtrToUlong((PVOID)dispInfo->item.lParam)) + { + case DOTNET_INDEX_EXCEPTIONS_THROWNCOUNT: + { + PH_FORMAT format[1]; + WCHAR formatBuffer[PH_INT64_STR_LEN_1]; + + PhInitFormatI64UGroupDigits(&format[0], context->DotNetPerfExceptions.cThrown.Total); + + if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), formatBuffer, sizeof(formatBuffer), NULL)) + { + wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, formatBuffer, _TRUNCATE); + } + } + break; + case DOTNET_INDEX_EXCEPTIONS_FILTERSCOUNT: + { + PH_FORMAT format[1]; + WCHAR formatBuffer[PH_INT64_STR_LEN_1]; + + PhInitFormatI64UGroupDigits(&format[0], context->DotNetPerfExceptions.cFiltersExecuted); + + if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), formatBuffer, sizeof(formatBuffer), NULL)) + { + wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, formatBuffer, _TRUNCATE); + } + } + break; + case DOTNET_INDEX_EXCEPTIONS_FINALLYCOUNT: + { + PH_FORMAT format[1]; + WCHAR formatBuffer[PH_INT64_STR_LEN_1]; + + PhInitFormatI64UGroupDigits(&format[0], context->DotNetPerfExceptions.cFinallysExecuted); + + if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), formatBuffer, sizeof(formatBuffer), NULL)) + { + wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, formatBuffer, _TRUNCATE); + } + } + break; + + case DOTNET_INDEX_INTEROP_CCWCOUNT: + { + PH_FORMAT format[1]; + WCHAR formatBuffer[PH_INT64_STR_LEN_1]; + + PhInitFormatI64UGroupDigits(&format[0], context->DotNetPerfInterop.cCCW); + + if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), formatBuffer, sizeof(formatBuffer), NULL)) + { + wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, formatBuffer, _TRUNCATE); + } + } + break; + case DOTNET_INDEX_INTEROP_STUBCOUNT: + { + PH_FORMAT format[1]; + WCHAR formatBuffer[PH_INT64_STR_LEN_1]; + + PhInitFormatI64UGroupDigits(&format[0], context->DotNetPerfInterop.cStubs); + + if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), formatBuffer, sizeof(formatBuffer), NULL)) + { + wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, formatBuffer, _TRUNCATE); + } + } + break; + case DOTNET_INDEX_INTEROP_MARSHALCOUNT: + { + PH_FORMAT format[1]; + WCHAR formatBuffer[PH_INT64_STR_LEN_1]; + + PhInitFormatI64UGroupDigits(&format[0], context->DotNetPerfInterop.cMarshalling); + + if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), formatBuffer, sizeof(formatBuffer), NULL)) + { + wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, formatBuffer, _TRUNCATE); + } + } + break; + case DOTNET_INDEX_INTEROP_TLBIMPORTPERSEC: + { + PH_FORMAT format[1]; + WCHAR formatBuffer[PH_INT64_STR_LEN_1]; + + PhInitFormatI64UGroupDigits(&format[0], context->DotNetPerfInterop.cTLBImports); + + if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), formatBuffer, sizeof(formatBuffer), NULL)) + { + wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, formatBuffer, _TRUNCATE); + } + } + break; + case DOTNET_INDEX_INTEROP_TLBEXPORTPERSEC: + { + PH_FORMAT format[1]; + WCHAR formatBuffer[PH_INT64_STR_LEN_1]; + + PhInitFormatI64UGroupDigits(&format[0], context->DotNetPerfInterop.cTLBExports); + + if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), formatBuffer, sizeof(formatBuffer), NULL)) + { + wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, formatBuffer, _TRUNCATE); + } + } + break; + + case DOTNET_INDEX_JIT_ILMETHODSJITTED: + { + PH_FORMAT format[1]; + WCHAR formatBuffer[PH_INT64_STR_LEN_1]; + + PhInitFormatI64UGroupDigits(&format[0], context->DotNetPerfJit.cMethodsJitted); + + if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), formatBuffer, sizeof(formatBuffer), NULL)) + { + wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, formatBuffer, _TRUNCATE); + } + } + break; + case DOTNET_INDEX_JIT_ILBYTESJITTED: + { + PH_FORMAT format[1]; + WCHAR formatBuffer[0x100]; + + PhInitFormatSize(&format[0], context->DotNetPerfJit.cbILJitted.Current); + + if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), formatBuffer, sizeof(formatBuffer), NULL)) + { + wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, formatBuffer, _TRUNCATE); + } + } + break; + case DOTNET_INDEX_JIT_ILTOTALBYTESJITTED: + { + PH_FORMAT format[1]; + WCHAR formatBuffer[0x100]; + + PhInitFormatSize(&format[0], context->DotNetPerfJit.cbILJitted.Total); + + if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), formatBuffer, sizeof(formatBuffer), NULL)) + { + wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, formatBuffer, _TRUNCATE); + } + } + break; + case DOTNET_INDEX_JIT_FAILURES: + { + PH_FORMAT format[1]; + WCHAR formatBuffer[PH_INT64_STR_LEN_1]; + + PhInitFormatI64UGroupDigits(&format[0], context->DotNetPerfJit.cJitFailures); + + if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), formatBuffer, sizeof(formatBuffer), NULL)) + { + wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, formatBuffer, _TRUNCATE); + } + } + break; + case DOTNET_INDEX_JIT_TIME: + { + if (context->DotNetPerfJit.timeInJitBase != 0) + { + PH_FORMAT format[1]; + WCHAR formatBuffer[10]; + + // TODO: perlib never shows the TimeInJit value and it can sometimes show values above 100% ??? + // SeeAlso: https://github.com/dotnet/coreclr/blob/master/src/gc/gcee.cpp#L324 + PhInitFormatF(&format[0], (context->DotNetPerfJit.timeInJit << 8) * 100 / (FLOAT)(context->DotNetPerfJit.timeInJitBase << 8), 2); + + if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), formatBuffer, sizeof(formatBuffer), NULL)) + { + wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, formatBuffer, _TRUNCATE); + } + } + else + { + wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, L"0.00", _TRUNCATE); + } + } + break; + + case DOTNET_INDEX_LOADING_CURRENTLOADED: + { + PH_FORMAT format[1]; + WCHAR formatBuffer[PH_INT64_STR_LEN_1]; + + PhInitFormatI64UGroupDigits(&format[0], context->DotNetPerfLoading.cClassesLoaded.Current); + + if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), formatBuffer, sizeof(formatBuffer), NULL)) + { + wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, formatBuffer, _TRUNCATE); + } + } + break; + case DOTNET_INDEX_LOADING_TOTALLOADED: + { + PH_FORMAT format[1]; + WCHAR formatBuffer[PH_INT64_STR_LEN_1]; + + PhInitFormatI64UGroupDigits(&format[0], context->DotNetPerfLoading.cClassesLoaded.Total); + + if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), formatBuffer, sizeof(formatBuffer), NULL)) + { + wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, formatBuffer, _TRUNCATE); + } + } + break; + case DOTNET_INDEX_LOADING_CURRENTAPPDOMAINS: + { + PH_FORMAT format[1]; + WCHAR formatBuffer[PH_INT64_STR_LEN_1]; + + PhInitFormatI64UGroupDigits(&format[0], context->DotNetPerfLoading.cAppDomains.Current); + + if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), formatBuffer, sizeof(formatBuffer), NULL)) + { + wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, formatBuffer, _TRUNCATE); + } + } + break; + case DOTNET_INDEX_LOADING_TOTALAPPDOMAINS: + { + PH_FORMAT format[1]; + WCHAR formatBuffer[PH_INT64_STR_LEN_1]; + + PhInitFormatI64UGroupDigits(&format[0], context->DotNetPerfLoading.cAppDomains.Total); + + if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), formatBuffer, sizeof(formatBuffer), NULL)) + { + wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, formatBuffer, _TRUNCATE); + } + } + break; + case DOTNET_INDEX_LOADING_CURRENTASSEMBLIES: + { + PH_FORMAT format[1]; + WCHAR formatBuffer[PH_INT64_STR_LEN_1]; + + PhInitFormatI64UGroupDigits(&format[0], context->DotNetPerfLoading.cAssemblies.Current); + + if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), formatBuffer, sizeof(formatBuffer), NULL)) + { + wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, formatBuffer, _TRUNCATE); + } + } + break; + case DOTNET_INDEX_LOADING_TOTALASSEMBLIES: + { + PH_FORMAT format[1]; + WCHAR formatBuffer[PH_INT64_STR_LEN_1]; + + PhInitFormatI64UGroupDigits(&format[0], context->DotNetPerfLoading.cAssemblies.Total); + + if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), formatBuffer, sizeof(formatBuffer), NULL)) + { + wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, formatBuffer, _TRUNCATE); + } + } + break; + case DOTNET_INDEX_LOADING_ASSEMBLYSEARCHLENGTH: + { + PH_FORMAT format[1]; + WCHAR formatBuffer[PH_INT64_STR_LEN_1]; + + PhInitFormatI64UGroupDigits(&format[0], context->DotNetPerfLoading.cAsmSearchLen); + + if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), formatBuffer, sizeof(formatBuffer), NULL)) + { + wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, formatBuffer, _TRUNCATE); + } + } + break; + case DOTNET_INDEX_LOADING_TOTALLOADFAILURES: + { + PH_FORMAT format[1]; + WCHAR formatBuffer[PH_INT64_STR_LEN_1]; + + PhInitFormatI64UGroupDigits(&format[0], context->DotNetPerfLoading.cLoadFailures.Total); + + if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), formatBuffer, sizeof(formatBuffer), NULL)) + { + wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, formatBuffer, _TRUNCATE); + } + } + break; + case DOTNET_INDEX_LOADING_BYTESINLOADERHEAP: + { + PH_FORMAT format[1]; + WCHAR formatBuffer[0x100]; + + PhInitFormatSize(&format[0], context->DotNetPerfLoading.cbLoaderHeapSize); + + if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), formatBuffer, sizeof(formatBuffer), NULL)) + { + wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, formatBuffer, _TRUNCATE); + } + } + break; + case DOTNET_INDEX_LOADING_TOTALAPPDOMAINSUNLOADED: + { + PH_FORMAT format[1]; + WCHAR formatBuffer[PH_INT64_STR_LEN_1]; + + PhInitFormatI64UGroupDigits(&format[0], context->DotNetPerfLoading.cAppDomainsUnloaded.Total); + + if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), formatBuffer, sizeof(formatBuffer), NULL)) + { + wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, formatBuffer, _TRUNCATE); + } + } + break; + + case DOTNET_INDEX_LOCKSANDTHREADS_TOTALLOCKS: + { + PH_FORMAT format[1]; + WCHAR formatBuffer[PH_INT64_STR_LEN_1]; + + PhInitFormatI64UGroupDigits(&format[0], context->DotNetPerfLocksAndThreads.cContention.Total); + + if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), formatBuffer, sizeof(formatBuffer), NULL)) + { + wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, formatBuffer, _TRUNCATE); + } + } + break; + case DOTNET_INDEX_LOCKSANDTHREADS_TOTALQUEUELENGTH: + { + PH_FORMAT format[1]; + WCHAR formatBuffer[PH_INT64_STR_LEN_1]; + + PhInitFormatI64UGroupDigits(&format[0], context->DotNetPerfLocksAndThreads.cQueueLength.Current); + + if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), formatBuffer, sizeof(formatBuffer), NULL)) + { + wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, formatBuffer, _TRUNCATE); + } + } + break; + case DOTNET_INDEX_LOCKSANDTHREADS_QUEUELENGTHPEAK: + { + PH_FORMAT format[1]; + WCHAR formatBuffer[PH_INT64_STR_LEN_1]; + + PhInitFormatI64UGroupDigits(&format[0], context->DotNetPerfLocksAndThreads.cQueueLength.Total); + + if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), formatBuffer, sizeof(formatBuffer), NULL)) + { + wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, formatBuffer, _TRUNCATE); + } + } + break; + case DOTNET_INDEX_LOCKSANDTHREADS_CURRENTLOGICAL: + { + PH_FORMAT format[1]; + WCHAR formatBuffer[PH_INT64_STR_LEN_1]; + + PhInitFormatI64UGroupDigits(&format[0], context->DotNetPerfLocksAndThreads.cCurrentThreadsLogical); + + if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), formatBuffer, sizeof(formatBuffer), NULL)) + { + wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, formatBuffer, _TRUNCATE); + } + } + break; + case DOTNET_INDEX_LOCKSANDTHREADS_CURRENTPHYSICAL: + { + PH_FORMAT format[1]; + WCHAR formatBuffer[PH_INT64_STR_LEN_1]; + + PhInitFormatI64UGroupDigits(&format[0], context->DotNetPerfLocksAndThreads.cCurrentThreadsPhysical); + + if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), formatBuffer, sizeof(formatBuffer), NULL)) + { + wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, formatBuffer, _TRUNCATE); + } + } + break; + case DOTNET_INDEX_LOCKSANDTHREADS_CURRENTRECOGNIZED: + { + PH_FORMAT format[1]; + WCHAR formatBuffer[PH_INT64_STR_LEN_1]; + + PhInitFormatI64UGroupDigits(&format[0], context->DotNetPerfLocksAndThreads.cRecognizedThreads.Current); + + if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), formatBuffer, sizeof(formatBuffer), NULL)) + { + wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, formatBuffer, _TRUNCATE); + } + } + break; + case DOTNET_INDEX_LOCKSANDTHREADS_TOTALRECOGNIZED: + { + PH_FORMAT format[1]; + WCHAR formatBuffer[PH_INT64_STR_LEN_1]; + + PhInitFormatI64UGroupDigits(&format[0], context->DotNetPerfLocksAndThreads.cRecognizedThreads.Total); + + if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), formatBuffer, sizeof(formatBuffer), NULL)) + { + wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, formatBuffer, _TRUNCATE); + } + } + break; + + case DOTNET_INDEX_MEMORY_GENZEROCOLLECTIONS: + { + PH_FORMAT format[1]; + WCHAR formatBuffer[PH_INT64_STR_LEN_1]; + + PhInitFormatI64UGroupDigits(&format[0], context->DotNetPerfGC.cGenCollections[0]); + + if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), formatBuffer, sizeof(formatBuffer), NULL)) + { + wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, formatBuffer, _TRUNCATE); + } + } + break; + case DOTNET_INDEX_MEMORY_GENONECOLLECTIONS: + { + PH_FORMAT format[1]; + WCHAR formatBuffer[PH_INT64_STR_LEN_1]; + + PhInitFormatI64UGroupDigits(&format[0], context->DotNetPerfGC.cGenCollections[1]); + + if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), formatBuffer, sizeof(formatBuffer), NULL)) + { + wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, formatBuffer, _TRUNCATE); + } + } + break; + case DOTNET_INDEX_MEMORY_GENTWOCOLLECTIONS: + { + PH_FORMAT format[1]; + WCHAR formatBuffer[PH_INT64_STR_LEN_1]; + + PhInitFormatI64UGroupDigits(&format[0], context->DotNetPerfGC.cGenCollections[2]); + + if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), formatBuffer, sizeof(formatBuffer), NULL)) + { + wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, formatBuffer, _TRUNCATE); + } + } + break; + case DOTNET_INDEX_MEMORY_PROMOTEDFROMGENZERO: + { + PH_FORMAT format[1]; + WCHAR formatBuffer[0x100]; + + PhInitFormatSize(&format[0], context->DotNetPerfGC.cbPromotedMem[0]); + + if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), formatBuffer, sizeof(formatBuffer), NULL)) + { + wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, formatBuffer, _TRUNCATE); + } + } + break; + case DOTNET_INDEX_MEMORY_PROMOTEDFROMGENONE: + { + PH_FORMAT format[1]; + WCHAR formatBuffer[0x100]; + + PhInitFormatSize(&format[0], context->DotNetPerfGC.cbPromotedMem[1]); + + if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), formatBuffer, sizeof(formatBuffer), NULL)) + { + wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, formatBuffer, _TRUNCATE); + } + } + break; + case DOTNET_INDEX_MEMORY_PROMOTEDFINALFROMGENZERO: + { + PH_FORMAT format[1]; + WCHAR formatBuffer[0x100]; + + PhInitFormatSize(&format[0], context->DotNetPerfGC.cbPromotedFinalizationMem); + + if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), formatBuffer, sizeof(formatBuffer), NULL)) + { + wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, formatBuffer, _TRUNCATE); + } + } + break; + case DOTNET_INDEX_MEMORY_PROCESSID: + { + PH_FORMAT format[1]; + WCHAR formatBuffer[PH_INT64_STR_LEN_1]; + + PhInitFormatI64U(&format[0], context->DotNetPerfGC.cProcessID); + + if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), formatBuffer, sizeof(formatBuffer), NULL)) + { + wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, formatBuffer, _TRUNCATE); + } + } + break; + case DOTNET_INDEX_MEMORY_GENZEROHEAPSIZE: + { + PH_FORMAT format[1]; + WCHAR formatBuffer[0x100]; + + PhInitFormatSize(&format[0], context->DotNetPerfGC.cGenHeapSize[0]); + + if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), formatBuffer, sizeof(formatBuffer), NULL)) + { + wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, formatBuffer, _TRUNCATE); + } + } + break; + case DOTNET_INDEX_MEMORY_GENONEHEAPSIZE: + { + PH_FORMAT format[1]; + WCHAR formatBuffer[0x100]; + + PhInitFormatSize(&format[0], context->DotNetPerfGC.cGenHeapSize[1]); + + if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), formatBuffer, sizeof(formatBuffer), NULL)) + { + wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, formatBuffer, _TRUNCATE); + } + } + break; + case DOTNET_INDEX_MEMORY_GENTWOHEAPSIZE: + { + PH_FORMAT format[1]; + WCHAR formatBuffer[0x100]; + + PhInitFormatSize(&format[0], context->DotNetPerfGC.cGenHeapSize[2]); + + if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), formatBuffer, sizeof(formatBuffer), NULL)) + { + wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, formatBuffer, _TRUNCATE); + } + } + break; + case DOTNET_INDEX_MEMORY_LOHSIZE: + { + PH_FORMAT format[1]; + WCHAR formatBuffer[0x100]; + + PhInitFormatSize(&format[0], context->DotNetPerfGC.cLrgObjSize); + + if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), formatBuffer, sizeof(formatBuffer), NULL)) + { + wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, formatBuffer, _TRUNCATE); + } + } + break; + case DOTNET_INDEX_MEMORY_FINALSURVIVORS: + { + PH_FORMAT format[1]; + WCHAR formatBuffer[PH_INT64_STR_LEN_1]; + + PhInitFormatI64UGroupDigits(&format[0], context->DotNetPerfGC.cSurviveFinalize); + + if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), formatBuffer, sizeof(formatBuffer), NULL)) + { + wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, formatBuffer, _TRUNCATE); + } + } + break; + case DOTNET_INDEX_MEMORY_GCHANDLES: + { + PH_FORMAT format[1]; + WCHAR formatBuffer[PH_INT64_STR_LEN_1]; + + PhInitFormatI64UGroupDigits(&format[0], context->DotNetPerfGC.cHandles); + + if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), formatBuffer, sizeof(formatBuffer), NULL)) + { + wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, formatBuffer, _TRUNCATE); + } + } + break; + case DOTNET_INDEX_MEMORY_INDUCEDGC: + { + PH_FORMAT format[1]; + WCHAR formatBuffer[PH_INT64_STR_LEN_1]; + + PhInitFormatI64UGroupDigits(&format[0], context->DotNetPerfGC.cInducedGCs); + + if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), formatBuffer, sizeof(formatBuffer), NULL)) + { + wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, formatBuffer, _TRUNCATE); + } + } + break; + case DOTNET_INDEX_MEMORY_TIMEINGC: + { + if (context->DotNetPerfGC.timeInGCBase != 0) + { + PH_FORMAT format[1]; + WCHAR formatBuffer[10]; + + PhInitFormatF(&format[0], (FLOAT)context->DotNetPerfGC.timeInGC * 100 / (FLOAT)context->DotNetPerfGC.timeInGCBase, 2); + + if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), formatBuffer, sizeof(formatBuffer), NULL)) + { + wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, formatBuffer, _TRUNCATE); + } + } + else + { + wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, L"0.00", _TRUNCATE); + } + } + break; + case DOTNET_INDEX_MEMORY_BYTESINALLHEAPS: + { + PH_FORMAT format[1]; + WCHAR formatBuffer[0x100]; + + // The CLR source says this value should be "Gen 0 Heap Size; Gen 1 Heap Size; Gen 2 Heap Size and the Large Object Heap Size" + // but perflib only counts the total for Gen 1, Gen 2 and cLrgObjSize ignoring Gen 0 ??? + + PhInitFormatSize( + &format[0], + context->DotNetPerfGC.cGenHeapSize[1] + + context->DotNetPerfGC.cGenHeapSize[2] + + context->DotNetPerfGC.cLrgObjSize + ); + + if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), formatBuffer, sizeof(formatBuffer), NULL)) + { + wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, formatBuffer, _TRUNCATE); + } + } + break; + case DOTNET_INDEX_MEMORY_TOTALCOMMITTED: + { + PH_FORMAT format[1]; + WCHAR formatBuffer[0x100]; + + PhInitFormatSize(&format[0], context->DotNetPerfGC.cTotalCommittedBytes); + + if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), formatBuffer, sizeof(formatBuffer), NULL)) + { + wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, formatBuffer, _TRUNCATE); + } + } + break; + case DOTNET_INDEX_MEMORY_TOTALRESERVED: + { + PH_FORMAT format[1]; + WCHAR formatBuffer[0x100]; + + PhInitFormatSize(&format[0], context->DotNetPerfGC.cTotalReservedBytes); + + if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), formatBuffer, sizeof(formatBuffer), NULL)) + { + wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, formatBuffer, _TRUNCATE); + } + } + break; + case DOTNET_INDEX_MEMORY_TOTALPINNED: + { + PH_FORMAT format[1]; + WCHAR formatBuffer[PH_INT64_STR_LEN_1]; + + PhInitFormatI64UGroupDigits(&format[0], context->DotNetPerfGC.cPinnedObj); + + if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), formatBuffer, sizeof(formatBuffer), NULL)) + { + wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, formatBuffer, _TRUNCATE); + } + } + break; + case DOTNET_INDEX_MEMORY_TOTALSINKS: + { + PH_FORMAT format[1]; + WCHAR formatBuffer[PH_INT64_STR_LEN_1]; + + PhInitFormatI64UGroupDigits(&format[0], context->DotNetPerfGC.cSinkBlocks); + + if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), formatBuffer, sizeof(formatBuffer), NULL)) + { + wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, formatBuffer, _TRUNCATE); + } + } + break; + case DOTNET_INDEX_MEMORY_TOTALBYTESSINCESTART: + { + PH_FORMAT format[1]; + WCHAR formatBuffer[0x100]; + + PhInitFormatSize(&format[0], context->DotNetPerfGC.cbAlloc); + + if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), formatBuffer, sizeof(formatBuffer), NULL)) + { + wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, formatBuffer, _TRUNCATE); + } + } + break; + case DOTNET_INDEX_MEMORY_TOTALLOHBYTESSINCESTART: + { + PH_FORMAT format[1]; + WCHAR formatBuffer[0x100]; + + PhInitFormatSize(&format[0], context->DotNetPerfGC.cbLargeAlloc); + + if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), formatBuffer, sizeof(formatBuffer), NULL)) + { + wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, formatBuffer, _TRUNCATE); + } + } + break; + + case DOTNET_INDEX_REMOTING_TOTALREMOTECALLS: + { + PH_FORMAT format[1]; + WCHAR formatBuffer[PH_INT64_STR_LEN_1]; + + PhInitFormatI64UGroupDigits(&format[0], context->DotNetPerfContext.cRemoteCalls.Total); + + if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), formatBuffer, sizeof(formatBuffer), NULL)) + { + wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, formatBuffer, _TRUNCATE); + } + } + break; + case DOTNET_INDEX_REMOTING_CHANNELS: + { + PH_FORMAT format[1]; + WCHAR formatBuffer[PH_INT64_STR_LEN_1]; + + PhInitFormatI64UGroupDigits(&format[0], context->DotNetPerfContext.cChannels); + + if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), formatBuffer, sizeof(formatBuffer), NULL)) + { + wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, formatBuffer, _TRUNCATE); + } + } + break; + case DOTNET_INDEX_REMOTING_CONTEXTPROXIES: + { + PH_FORMAT format[1]; + WCHAR formatBuffer[PH_INT64_STR_LEN_1]; + + PhInitFormatI64UGroupDigits(&format[0], context->DotNetPerfContext.cProxies); + + if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), formatBuffer, sizeof(formatBuffer), NULL)) + { + wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, formatBuffer, _TRUNCATE); + } + } + break; + case DOTNET_INDEX_REMOTING_CONTEXTCLASSESLOADED: + { + PH_FORMAT format[1]; + WCHAR formatBuffer[PH_INT64_STR_LEN_1]; + + PhInitFormatI64UGroupDigits(&format[0], context->DotNetPerfContext.cClasses); + + if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), formatBuffer, sizeof(formatBuffer), NULL)) + { + wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, formatBuffer, _TRUNCATE); + } + } + break; + case DOTNET_INDEX_REMOTING_CONTEXTS: + { + PH_FORMAT format[1]; + WCHAR formatBuffer[PH_INT64_STR_LEN_1]; + + PhInitFormatI64UGroupDigits(&format[0], context->DotNetPerfContext.cContexts); + + if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), formatBuffer, sizeof(formatBuffer), NULL)) + { + wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, formatBuffer, _TRUNCATE); + } + } + break; + case DOTNET_INDEX_REMOTING_CONTEXTSALLOCATED: + { + PH_FORMAT format[1]; + WCHAR formatBuffer[PH_INT64_STR_LEN_1]; + + PhInitFormatI64UGroupDigits(&format[0], context->DotNetPerfContext.cObjAlloc); + + if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), formatBuffer, sizeof(formatBuffer), NULL)) + { + wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, formatBuffer, _TRUNCATE); + } + } + break; + + case DOTNET_INDEX_SECURITY_TOTALRUNTIMECHECKS: + { + PH_FORMAT format[1]; + WCHAR formatBuffer[PH_INT64_STR_LEN_1]; + + PhInitFormatI64UGroupDigits(&format[0], context->DotNetPerfSecurity.cTotalRTChecks); + + if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), formatBuffer, sizeof(formatBuffer), NULL)) + { + wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, formatBuffer, _TRUNCATE); + } + } + break; + case DOTNET_INDEX_SECURITY_LINKTIMECHECKS: + { + PH_FORMAT format[1]; + WCHAR formatBuffer[PH_INT64_STR_LEN_1]; + + PhInitFormatI64UGroupDigits(&format[0], context->DotNetPerfSecurity.cLinkChecks); + + if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), formatBuffer, sizeof(formatBuffer), NULL)) + { + wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, formatBuffer, _TRUNCATE); + } + } + break; + case DOTNET_INDEX_SECURITY_TIMEINRTCHECKS: + { + if (context->DotNetPerfSecurity.timeRTchecksBase != 0) + { + PH_FORMAT format[1]; + WCHAR formatBuffer[10]; + + PhInitFormatF(&format[0], (FLOAT)context->DotNetPerfSecurity.timeRTchecks * 100 / (FLOAT)context->DotNetPerfSecurity.timeRTchecksBase, 2); + + if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), formatBuffer, sizeof(formatBuffer), NULL)) + { + wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, formatBuffer, _TRUNCATE); + } + } + else + { + wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, L"0.00", _TRUNCATE); + } + } + break; + case DOTNET_INDEX_SECURITY_STACKWALKDEPTH: + { + PH_FORMAT format[1]; + WCHAR formatBuffer[PH_INT64_STR_LEN_1]; + + PhInitFormatI64UGroupDigits(&format[0], context->DotNetPerfSecurity.stackWalkDepth); + + if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), formatBuffer, sizeof(formatBuffer), NULL)) + { + wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, formatBuffer, _TRUNCATE); + } + } + break; + } + } + } + } + break; } - PhHandleListViewNotifyForCopy(lParam, context->AppDomainsLv); - PhHandleListViewNotifyForCopy(lParam, context->CountersLv); + PhHandleListViewNotifyForCopy(lParam, context->AppDomainsListViewHandle); + PhHandleListViewNotifyForCopy(lParam, context->CountersListViewHandle); } break; case MSG_UPDATE: @@ -1059,7 +1799,7 @@ INT_PTR CALLBACK DotNetPerfPageDlgProc( break; case WM_SIZE: { - ExtendedListView_SetColumnWidth(context->AppDomainsLv, 0, ELVSCW_AUTOSIZE_REMAININGSPACE); + ExtendedListView_SetColumnWidth(context->AppDomainsListViewHandle, 0, ELVSCW_AUTOSIZE_REMAININGSPACE); } break; } From ff2f764dd146c21995d1d75e554a65bd185ede63 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 25 Sep 2018 06:36:59 +1000 Subject: [PATCH 1355/2058] Fix token properties column settings, Fix tabspace --- ProcessHacker/tokprp.c | 64 +++++++++++++++--------------------------- 1 file changed, 22 insertions(+), 42 deletions(-) diff --git a/ProcessHacker/tokprp.c b/ProcessHacker/tokprp.c index c948c515dbe5..d68301c8eb82 100644 --- a/ProcessHacker/tokprp.c +++ b/ProcessHacker/tokprp.c @@ -567,7 +567,6 @@ INT_PTR CALLBACK PhpTokenPageProc( PTOKEN_PAGE_CONTEXT tokenPageContext; tokenPageContext = PhpTokenPageHeader(hwndDlg, uMsg, wParam, lParam); - tokenPageContext = PhpGenericPropertyPageHeader(hwndDlg, uMsg, wParam, lParam, 3); if (!tokenPageContext) return FALSE; @@ -713,13 +712,13 @@ INT_PTR CALLBACK PhpTokenPageProc( break; case WM_DESTROY: { + PhSaveListViewColumnsToSetting(L"TokenGroupsListViewColumns", tokenPageContext->ListViewHandle); + if (tokenPageContext->ListViewImageList) ImageList_Destroy(tokenPageContext->ListViewImageList); PhpTokenPageFreeListViewEntries(tokenPageContext); - PhSaveListViewColumnsToSetting(L"TokenGroupsListViewColumns", tokenPageContext->ListViewHandle); - if (tokenPageContext->Groups) PhFree(tokenPageContext->Groups); if (tokenPageContext->RestrictedSids) PhFree(tokenPageContext->RestrictedSids); if (tokenPageContext->Privileges) PhFree(tokenPageContext->Privileges); @@ -727,7 +726,7 @@ INT_PTR CALLBACK PhpTokenPageProc( break; case WM_COMMAND: { - switch (LOWORD(wParam)) + switch (GET_WM_COMMAND_ID(wParam, lParam)) { case ID_PRIVILEGE_ENABLE: case ID_PRIVILEGE_DISABLE: @@ -841,7 +840,7 @@ INT_PTR CALLBACK PhpTokenPageProc( { PWSTR action = L"set"; - switch (LOWORD(wParam)) + switch (GET_WM_COMMAND_ID(wParam, lParam)) { case ID_PRIVILEGE_ENABLE: action = L"enable"; @@ -1079,6 +1078,9 @@ INT_PTR CALLBACK PhpTokenPageProc( if ((HWND)wParam == tokenPageContext->ListViewHandle) { POINT point; + PPH_EMENU menu; + PPHP_TOKEN_PAGE_LISTVIEW_ITEM *listviewItems; + ULONG numberOfItems; point.x = GET_X_LPARAM(lParam); point.y = GET_Y_LPARAM(lParam); @@ -1086,50 +1088,28 @@ INT_PTR CALLBACK PhpTokenPageProc( if (point.x == -1 && point.y == -1) PhGetListViewContextMenuPoint((HWND)wParam, &point); - if (ListView_GetSelectedCount(tokenPageContext->ListViewHandle) != 0) - { - PPH_EMENU menu; - BOOLEAN listViewGroupItemsValid = TRUE; - PPHP_TOKEN_PAGE_LISTVIEW_ITEM *listviewItems; - ULONG numberOfItems; - ULONG i; - - PhGetSelectedListViewItemParams( - tokenPageContext->ListViewHandle, - &listviewItems, - &numberOfItems - ); - - for (i = 0; i < numberOfItems; i++) - { - if (listviewItems[i]->IsTokenGroupEntry) - { - listViewGroupItemsValid = FALSE; - break; - } - } + PhGetSelectedListViewItemParams(tokenPageContext->ListViewHandle, &listviewItems, &numberOfItems); + if (numberOfItems != 0) + { menu = PhCreateEMenu(); - if (listViewGroupItemsValid) - { - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_PRIVILEGE_ENABLE, L"&Enable", NULL, NULL), -1); - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_PRIVILEGE_DISABLE, L"&Disable", NULL, NULL), -1); - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_PRIVILEGE_REMOVE, L"&Remove", NULL, NULL), -1); - PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), -1); - } - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_PRIVILEGE_COPY, L"&Copy", NULL, NULL), -1); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_PRIVILEGE_ENABLE, L"&Enable", NULL, NULL), ULONG_MAX); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_PRIVILEGE_DISABLE, L"&Disable", NULL, NULL), ULONG_MAX); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_PRIVILEGE_REMOVE, L"&Remove", NULL, NULL), ULONG_MAX); + PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_PRIVILEGE_COPY, L"&Copy", NULL, NULL), ULONG_MAX); PhShowEMenu( - menu, - hwndDlg, + menu, + hwndDlg, PH_EMENU_SHOW_SEND_COMMAND | PH_EMENU_SHOW_LEFTRIGHT, - PH_ALIGN_LEFT | PH_ALIGN_TOP, - point.x, + PH_ALIGN_LEFT | PH_ALIGN_TOP, + point.x, point.y ); PhDestroyEMenu(menu); - - PhFree(listviewItems); } + + PhFree(listviewItems); } } break; @@ -1378,7 +1358,7 @@ INT_PTR CALLBACK PhpTokenGeneralPageProc( break; case WM_COMMAND: { - switch (LOWORD(wParam)) + switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDC_LINKEDTOKEN: { From 18d615d1cb87842d498456f8ae63738da41909f2 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 25 Sep 2018 07:01:02 +1000 Subject: [PATCH 1356/2058] Fix previous commit --- ProcessHacker/tokprp.c | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/ProcessHacker/tokprp.c b/ProcessHacker/tokprp.c index d68301c8eb82..d822e198b920 100644 --- a/ProcessHacker/tokprp.c +++ b/ProcessHacker/tokprp.c @@ -1092,12 +1092,28 @@ INT_PTR CALLBACK PhpTokenPageProc( if (numberOfItems != 0) { + BOOLEAN listViewGroupItemsValid = FALSE; + ULONG i; + + for (i = 0; i < numberOfItems; i++) + { + if (listviewItems[i]->IsTokenGroupEntry) + { + listViewGroupItemsValid = TRUE; + break; + } + } + menu = PhCreateEMenu(); - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_PRIVILEGE_ENABLE, L"&Enable", NULL, NULL), ULONG_MAX); - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_PRIVILEGE_DISABLE, L"&Disable", NULL, NULL), ULONG_MAX); - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_PRIVILEGE_REMOVE, L"&Remove", NULL, NULL), ULONG_MAX); - PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX); + if (!listViewGroupItemsValid) + { + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_PRIVILEGE_ENABLE, L"&Enable", NULL, NULL), ULONG_MAX); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_PRIVILEGE_DISABLE, L"&Disable", NULL, NULL), ULONG_MAX); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_PRIVILEGE_REMOVE, L"&Remove", NULL, NULL), ULONG_MAX); + PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX); + } PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_PRIVILEGE_COPY, L"&Copy", NULL, NULL), ULONG_MAX); + PhShowEMenu( menu, hwndDlg, From 81813599e49c9d46cf549117dd188b32c72c96ba Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 30 Sep 2018 05:55:20 +1000 Subject: [PATCH 1357/2058] Add initial exception dialog --- ProcessHacker/main.c | 64 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 58 insertions(+), 6 deletions(-) diff --git a/ProcessHacker/main.c b/ProcessHacker/main.c index 092c9a75a21e..cceb06929279 100644 --- a/ProcessHacker/main.c +++ b/ProcessHacker/main.c @@ -548,6 +548,46 @@ BOOLEAN PhInitializeRestartPolicy( return TRUE; } +#ifndef DEBUG +static ULONG CALLBACK PhpUnhandledExceptionCallback( + _In_ PEXCEPTION_POINTERS ExceptionInfo + ) +{ + PPH_STRING errorMessage; + + if (NT_NTWIN32(ExceptionInfo->ExceptionRecord->ExceptionCode)) + errorMessage = PhGetStatusMessage(0, WIN32_FROM_NTSTATUS(ExceptionInfo->ExceptionRecord->ExceptionCode)); + else + errorMessage = PhGetStatusMessage(ExceptionInfo->ExceptionRecord->ExceptionCode, 0); + + if (PhShowMessage2( + NULL, + TDCBF_RETRY_BUTTON | TDCBF_CANCEL_BUTTON, + TD_ERROR_ICON, + L"Process Hacker has crashed :(", + L"Error code: 0x%08X (%s)", + ExceptionInfo->ExceptionRecord->ExceptionCode, + PhGetStringOrEmpty(errorMessage) + ) == IDRETRY) + { + PhShellProcessHacker( + NULL, + NULL, + SW_SHOW, + 0, + PH_SHELL_APP_PROPAGATE_PARAMETERS | PH_SHELL_APP_PROPAGATE_PARAMETERS_IGNORE_VISIBILITY, + 0, + NULL + ); + } + + RtlExitUserProcess(ExceptionInfo->ExceptionRecord->ExceptionCode); + + PhDereferenceObject(errorMessage); + return EXCEPTION_EXECUTE_HANDLER; +} +#endif + BOOLEAN PhInitializeExceptionPolicy( VOID ) @@ -560,16 +600,21 @@ BOOLEAN PhInitializeExceptionPolicy( errorMode &= ~(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX); PhSetProcessErrorMode(NtCurrentProcess(), errorMode); } + + // NOTE: We really shouldn't be using this function since it can be + // preempted by the Win32 SetUnhandledExceptionFilter function. (dmex) + RtlSetUnhandledExceptionFilter(PhpUnhandledExceptionCallback); #endif + return TRUE; -} +} BOOLEAN PhInitializeNamespacePolicy( VOID ) { HANDLE mutantHandle; - PPH_STRING objectName; + WCHAR objectName[PH_INT64_STR_LEN_1]; OBJECT_ATTRIBUTES objectAttributes; UNICODE_STRING objectNameUs; PH_FORMAT format[2]; @@ -577,9 +622,18 @@ BOOLEAN PhInitializeNamespacePolicy( PhInitFormatS(&format[0], L"PhMutant_"); PhInitFormatU(&format[1], HandleToUlong(NtCurrentProcessId())); - objectName = PhFormat(format, RTL_NUMBER_OF(format), 16); - PhStringRefToUnicodeString(&objectName->sr, &objectNameUs); + if (!PhFormatToBuffer( + format, + RTL_NUMBER_OF(format), + objectName, + sizeof(objectName), + NULL + )) + { + return FALSE; + } + RtlInitUnicodeString(&objectNameUs, objectName); InitializeObjectAttributes( &objectAttributes, &objectNameUs, @@ -595,11 +649,9 @@ BOOLEAN PhInitializeNamespacePolicy( TRUE ))) { - PhDereferenceObject(objectName); return TRUE; } - PhDereferenceObject(objectName); return FALSE; } From bfa14b37f5703d48b9a87f3e874a2868695d3641 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 30 Sep 2018 05:55:56 +1000 Subject: [PATCH 1358/2058] Fix type equality check --- ProcessHacker/memsrch.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ProcessHacker/memsrch.c b/ProcessHacker/memsrch.c index ab64a7e93731..a9a36fabe112 100644 --- a/ProcessHacker/memsrch.c +++ b/ProcessHacker/memsrch.c @@ -301,7 +301,7 @@ VOID PhSearchMemoryString( // ExtendedUnicode option then we'll use iswprint (GetStringTypeW) which does check // every available character by default. if (detectUnicode && extendedUnicode && !iswascii(byte)) - printable = iswprint(byte); + printable = !!iswprint(byte); else printable = PhCharIsPrintable[byte]; From 7824e01d14a06a05e2bddf1602f8f9a46b42c05d Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 30 Sep 2018 06:12:18 +1000 Subject: [PATCH 1359/2058] Add PhSetTokenGroups --- phlib/include/phnative.h | 10 +++++++ phlib/native.c | 58 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+) diff --git a/phlib/include/phnative.h b/phlib/include/phnative.h index c1e799c83864..8988960acac7 100644 --- a/phlib/include/phnative.h +++ b/phlib/include/phnative.h @@ -439,6 +439,16 @@ PhSetTokenPrivilege2( _In_ ULONG Attributes ); +PHLIBAPI +BOOLEAN +NTAPI +PhSetTokenGroups( + _In_ HANDLE TokenHandle, + _In_opt_ PWSTR GroupName, + _In_opt_ PSID GroupSid, + _In_ ULONG Attributes + ); + PHLIBAPI NTSTATUS NTAPI diff --git a/phlib/native.c b/phlib/native.c index f1e43b237f03..d39855534514 100644 --- a/phlib/native.c +++ b/phlib/native.c @@ -2213,6 +2213,64 @@ BOOLEAN PhSetTokenPrivilege2( return PhSetTokenPrivilege(TokenHandle, NULL, &privilegeLuid, Attributes); } +BOOLEAN PhSetTokenGroups( + _In_ HANDLE TokenHandle, + _In_opt_ PWSTR GroupName, + _In_opt_ PSID GroupSid, + _In_ ULONG Attributes + ) +{ + NTSTATUS status; + TOKEN_GROUPS groups; + + groups.GroupCount = 1; + groups.Groups[0].Attributes = Attributes; + + if (GroupSid) + { + groups.Groups[0].Sid = GroupSid; + } + else if (GroupName) + { + PH_STRINGREF groupName; + + PhInitializeStringRef(&groupName, GroupName); + + if (!NT_SUCCESS(status = PhLookupName(&groupName, &groups.Groups[0].Sid, NULL, NULL))) + return FALSE; + } + else + { + return FALSE; + } + + if (!NT_SUCCESS(status = NtAdjustGroupsToken( + TokenHandle, + FALSE, + &groups, + 0, + NULL, + NULL + ))) + { + goto CleanupExit; + } + + if (status == STATUS_NOT_ALL_ASSIGNED) + goto CleanupExit; + + if (GroupName && groups.Groups[0].Sid) + PhFree(groups.Groups[0].Sid); + + return TRUE; + +CleanupExit: + if (GroupName && groups.Groups[0].Sid) + PhFree(groups.Groups[0].Sid); + + return FALSE; +} + /** * Sets whether virtualization is enabled for a token. * From 048f9efa7d8513b5532e0c623eaf73f28daa4511 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 30 Sep 2018 06:19:40 +1000 Subject: [PATCH 1360/2058] Fix null check --- ProcessHacker/tokprp.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/ProcessHacker/tokprp.c b/ProcessHacker/tokprp.c index d822e198b920..bb791c185765 100644 --- a/ProcessHacker/tokprp.c +++ b/ProcessHacker/tokprp.c @@ -788,10 +788,12 @@ INT_PTR CALLBACK PhpTokenPageProc( PPH_STRING privilegeName = NULL; ULONG newAttributes; - PhLookupPrivilegeName(&listViewItems[i]->TokenPrivilege->Luid, &privilegeName); - PH_AUTO(privilegeName); + if (PhLookupPrivilegeName(&listViewItems[i]->TokenPrivilege->Luid, &privilegeName)) + { + PH_AUTO(privilegeName); + } - switch (LOWORD(wParam)) + switch (GET_WM_COMMAND_ID(wParam, lParam)) { case ID_PRIVILEGE_ENABLE: newAttributes = listViewItems[i]->TokenPrivilege->Attributes | SE_PRIVILEGE_ENABLED; @@ -817,7 +819,7 @@ INT_PTR CALLBACK PhpTokenPageProc( listViewItems[i] ); - if (LOWORD(wParam) != ID_PRIVILEGE_REMOVE) + if (GET_WM_COMMAND_ID(wParam, lParam) != ID_PRIVILEGE_REMOVE) { // Refresh the status text (and background color). listViewItems[i]->TokenPrivilege->Attributes = newAttributes; From cb8ee37903a0865ed86c9fa7ccf445250d2115ab Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 30 Sep 2018 06:20:33 +1000 Subject: [PATCH 1361/2058] WindowExplorer: Update DelayLoadDLLs, Fix tabspace --- plugins/WindowExplorer/WindowExplorer.vcxproj | 2 +- plugins/WindowExplorer/wndtree.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/WindowExplorer/WindowExplorer.vcxproj b/plugins/WindowExplorer/WindowExplorer.vcxproj index f23170fa9c6f..7389b4273fd7 100644 --- a/plugins/WindowExplorer/WindowExplorer.vcxproj +++ b/plugins/WindowExplorer/WindowExplorer.vcxproj @@ -58,7 +58,7 @@ - gdi32.dll;ProcessHacker.exe;user32.dll;%(DelayLoadDLLs) + comctl32.dll;gdi32.dll;ProcessHacker.exe;user32.dll;%(DelayLoadDLLs) diff --git a/plugins/WindowExplorer/wndtree.c b/plugins/WindowExplorer/wndtree.c index 8b7c3e56bd09..fd51694e9107 100644 --- a/plugins/WindowExplorer/wndtree.c +++ b/plugins/WindowExplorer/wndtree.c @@ -52,7 +52,7 @@ BOOLEAN WordMatchStringRef( PH_STRINGREF part; PH_STRINGREF remainingPart; - remainingPart = Context->SearchboxText->sr; + remainingPart = PhGetStringRef(Context->SearchboxText); while (remainingPart.Length != 0) { @@ -569,4 +569,4 @@ VOID WeExpandAllWindowNodes( if (needsRestructure) TreeNew_NodesStructured(Context->TreeNewHandle); -} \ No newline at end of file +} From 08a1459df335b2d3e1ecbb6e117cde9c043bf744 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 30 Sep 2018 06:21:39 +1000 Subject: [PATCH 1362/2058] ToolStatus: Fix statusbar text case --- plugins/ToolStatus/statusbar.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/ToolStatus/statusbar.c b/plugins/ToolStatus/statusbar.c index a7bc74f4766f..3b10b2e39071 100644 --- a/plugins/ToolStatus/statusbar.c +++ b/plugins/ToolStatus/statusbar.c @@ -284,7 +284,7 @@ VOID StatusBarUpdate( FLOAT cpuUsage = SystemStatistics.CpuKernelUsage + SystemStatistics.CpuUserUsage; PH_FORMAT format[3]; - PhInitFormatS(&format[0], L"CPU Usage: "); + PhInitFormatS(&format[0], L"CPU usage: "); PhInitFormatF(&format[1], cpuUsage * 100, 2); PhInitFormatS(&format[2], L"%"); From e68fb9c8289e32f3b89c6433d33a19f29f494035 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 30 Sep 2018 06:24:00 +1000 Subject: [PATCH 1363/2058] Add PhAppResolverGetAppIdForWindow --- phlib/appresolver.c | 43 +++++++++++++++++++++++++++++++++++++ phlib/include/appresolver.h | 5 +++++ 2 files changed, 48 insertions(+) diff --git a/phlib/appresolver.c b/phlib/appresolver.c index 6dd5018de2e6..dc9b38d7a0f1 100644 --- a/phlib/appresolver.c +++ b/phlib/appresolver.c @@ -156,6 +156,49 @@ BOOLEAN PhAppResolverGetAppIdForProcess( return FALSE; } +BOOLEAN PhAppResolverGetAppIdForWindow( + _In_ HWND WindowHandle, + _Out_ PPH_STRING *ApplicationUserModelId + ) +{ + PVOID resolverInterface; + PWSTR appIdText = NULL; + + if (!(resolverInterface = PhpQueryAppResolverInterface())) + return FALSE; + + if (WindowsVersion < WINDOWS_8) + { + IApplicationResolver_GetAppIDForWindow( + (IApplicationResolver61*)resolverInterface, + WindowHandle, + &appIdText, + NULL, + NULL, + NULL + ); + } + else + { + IApplicationResolver_GetAppIDForWindow( + (IApplicationResolver62*)resolverInterface, + WindowHandle, + &appIdText, + NULL, + NULL, + NULL + ); + } + + if (appIdText) + { + *ApplicationUserModelId = PhCreateString(appIdText); + return TRUE; + } + + return FALSE; +} + HRESULT PhAppResolverActivateAppId( _In_ PPH_STRING AppUserModelId, _In_opt_ PWSTR CommandLine, diff --git a/phlib/include/appresolver.h b/phlib/include/appresolver.h index 835f414e7380..70633f905b5c 100644 --- a/phlib/include/appresolver.h +++ b/phlib/include/appresolver.h @@ -32,6 +32,11 @@ BOOLEAN PhAppResolverGetAppIdForProcess( _Out_ PPH_STRING *ApplicationUserModelId ); +BOOLEAN PhAppResolverGetAppIdForWindow( + _In_ HWND WindowHandle, + _Out_ PPH_STRING *ApplicationUserModelId + ); + HRESULT PhAppResolverActivateAppId( _In_ PPH_STRING AppUserModelId, _In_opt_ PWSTR CommandLine, From fc3c24b0f2948880d09b7543d1a1fbe2289a00e0 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 30 Sep 2018 08:04:06 +1000 Subject: [PATCH 1364/2058] Add ExtendedListView_GetSort --- phlib/extlv.c | 35 +++++++++++++++++++++++++++-------- phlib/include/guisup.h | 13 ++++++++++++- 2 files changed, 39 insertions(+), 9 deletions(-) diff --git a/phlib/extlv.c b/phlib/extlv.c index 58616b647778..6aad9f6535e6 100644 --- a/phlib/extlv.c +++ b/phlib/extlv.c @@ -104,16 +104,24 @@ INT PhpDefaultCompareListViewItems( VOID PhSetExtendedListView( _In_ HWND hWnd ) +{ + PhSetExtendedListViewEx(hWnd, 0, AscendingSortOrder); +} + +VOID PhSetExtendedListViewEx( + _In_ HWND WindowHandle, + _In_ ULONG SortColumn, + _In_ ULONG SortOrder + ) { PPH_EXTLV_CONTEXT context; context = PhAllocateZero(sizeof(PH_EXTLV_CONTEXT)); - - context->Handle = hWnd; + context->Handle = WindowHandle; context->Context = NULL; context->TriState = FALSE; - context->SortColumn = 0; - context->SortOrder = AscendingSortOrder; + context->SortColumn = SortColumn; + context->SortOrder = SortOrder; context->SortFast = FALSE; context->TriStateCompareFunction = NULL; memset(context->CompareFunctions, 0, sizeof(context->CompareFunctions)); @@ -123,11 +131,11 @@ VOID PhSetExtendedListView( context->EnableRedraw = 1; context->Cursor = NULL; - context->OldWndProc = (WNDPROC)GetWindowLongPtr(hWnd, GWLP_WNDPROC); - PhSetWindowContext(hWnd, MAXCHAR, context); - SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)PhpExtendedListViewWndProc); + context->OldWndProc = (WNDPROC)GetWindowLongPtr(WindowHandle, GWLP_WNDPROC); + PhSetWindowContext(WindowHandle, MAXCHAR, context); + SetWindowLongPtr(WindowHandle, GWLP_WNDPROC, (LONG_PTR)PhpExtendedListViewWndProc); - ExtendedListView_Init(hWnd); + ExtendedListView_Init(WindowHandle); } LRESULT CALLBACK PhpExtendedListViewWndProc( @@ -423,6 +431,17 @@ LRESULT CALLBACK PhpExtendedListViewWndProc( } } return TRUE; + case ELVM_GETSORT: + { + PULONG sortColumn = (PULONG)wParam; + PPH_SORT_ORDER sortOrder = (PPH_SORT_ORDER)lParam; + + if (sortColumn) + *sortColumn = context->SortColumn; + if (sortOrder) + *sortOrder = context->SortOrder; + } + return TRUE; case ELVM_SETSORT: { context->SortColumn = (ULONG)wParam; diff --git a/phlib/include/guisup.h b/phlib/include/guisup.h index 093fd7f0d073..599a841040b3 100644 --- a/phlib/include/guisup.h +++ b/phlib/include/guisup.h @@ -682,6 +682,15 @@ PhSetExtendedListView( _In_ HWND hWnd ); +PHLIBAPI +VOID +NTAPI +PhSetExtendedListViewEx( + _In_ HWND WindowHandle, + _In_ ULONG SortColumn, + _In_ ULONG SortOrder + ); + PHLIBAPI VOID NTAPI @@ -706,7 +715,7 @@ PhSetHeaderSortIcon( #define ELVM_SETITEMFONTFUNCTION (WM_APP + 1117) #define ELVM_RESERVED1 (WM_APP + 1112) #define ELVM_SETREDRAW (WM_APP + 1116) -#define ELVM_RESERVED2 (WM_APP + 1113) +#define ELVM_GETSORT (WM_APP + 1113) #define ELVM_SETSORT (WM_APP + 1108) #define ELVM_SETSORTFAST (WM_APP + 1119) #define ELVM_RESERVED0 (WM_APP + 1110) @@ -735,6 +744,8 @@ PhSetHeaderSortIcon( SendMessage((hWnd), ELVM_SETITEMFONTFUNCTION, 0, (LPARAM)(ItemFontFunction)) #define ExtendedListView_SetRedraw(hWnd, Redraw) \ SendMessage((hWnd), ELVM_SETREDRAW, (WPARAM)(Redraw), 0) +#define ExtendedListView_GetSort(hWnd, Column, Order) \ + SendMessage((hWnd), ELVM_GETSORT, (WPARAM)(Column), (LPARAM)(Order)) #define ExtendedListView_SetSort(hWnd, Column, Order) \ SendMessage((hWnd), ELVM_SETSORT, (WPARAM)(Column), (LPARAM)(Order)) #define ExtendedListView_SetSortFast(hWnd, Fast) \ From 96f8aae6d679211ff7f11cb0d263393e5c680773 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 30 Sep 2018 08:05:46 +1000 Subject: [PATCH 1365/2058] Add listview column sort settings --- phlib/include/settings.h | 14 +++++++++ phlib/settings.c | 67 ++++++++++++++++++++++++++++++++++++++-- 2 files changed, 78 insertions(+), 3 deletions(-) diff --git a/phlib/include/settings.h b/phlib/include/settings.h index ba1b03718fd0..512b4a2558d2 100644 --- a/phlib/include/settings.h +++ b/phlib/include/settings.h @@ -263,6 +263,20 @@ PhSaveListViewColumnsToSetting( _In_ PWSTR Name, _In_ HWND ListViewHandle ); + +VOID +NTAPI +PhLoadListViewSortColumnsFromSetting( + _In_ PWSTR Name, + _In_ HWND ListViewHandle + ); + +VOID +NTAPI +PhSaveListViewSortColumnsToSetting( + _In_ PWSTR Name, + _In_ HWND ListViewHandle + ); // end_phapppub #define PH_SET_INTEGER_CACHED_SETTING(Name, Value) (PhSetIntegerSetting(L#Name, PhCs##Name = (Value))) diff --git a/phlib/settings.c b/phlib/settings.c index 8099df3088f1..19b65ff7fcfa 100644 --- a/phlib/settings.c +++ b/phlib/settings.c @@ -3,7 +3,7 @@ * settings * * Copyright (C) 2010-2016 wj32 - * Copyright (C) 2017 dmex + * Copyright (C) 2017-2018 dmex * * This file is part of Process Hacker. * @@ -38,6 +38,7 @@ #include #include #include +#include #include #include @@ -1149,7 +1150,7 @@ BOOLEAN PhLoadListViewColumnSettings( ULONG maxOrder; ULONG scale; - if (Settings->Length == 0) + if (PhIsNullOrEmptyString(Settings)) return FALSE; remainingPart = Settings->sr; @@ -1285,4 +1286,64 @@ VOID PhSaveListViewColumnsToSetting( string = PhSaveListViewColumnSettings(ListViewHandle); PhSetStringSetting2(Name, &string->sr); PhDereferenceObject(string); -} \ No newline at end of file +} + +VOID PhLoadListViewSortColumnsFromSetting( + _In_ PWSTR Name, + _In_ HWND ListViewHandle + ) +{ + PPH_STRING string; + ULONG sortColumn = 0; + PH_SORT_ORDER sortOrder = AscendingSortOrder; + PH_STRINGREF remainingPart; + + string = PhGetStringSetting(Name); + + if (PhIsNullOrEmptyString(string)) + return; + + remainingPart = string->sr; + + if (remainingPart.Length != 0) + { + PH_STRINGREF orderPart; + PH_STRINGREF widthPart; + ULONG64 integer; + + if (!PhSplitStringRefAtChar(&remainingPart, ',', &orderPart, &widthPart)) + return; + + if (!PhStringToInteger64(&orderPart, 10, &integer)) + return; + + sortColumn = (ULONG)integer; + + if (!PhStringToInteger64(&widthPart, 10, &integer)) + return; + + sortOrder = (ULONG)integer; + } + + ExtendedListView_SetSort(ListViewHandle, sortColumn, sortOrder); + + PhDereferenceObject(string); +} + +VOID PhSaveListViewSortColumnsToSetting( + _In_ PWSTR Name, + _In_ HWND ListViewHandle + ) +{ + PPH_STRING string; + ULONG sortColumn = 0; + PH_SORT_ORDER sortOrder = AscendingSortOrder; + + if (ExtendedListView_GetSort(ListViewHandle, &sortColumn, &sortOrder)) + string = PhFormatString(L"%u,%u", sortColumn, sortOrder); + else + string = PhCreateString(L"0,0"); + + PhSetStringSetting2(Name, &string->sr); + PhDereferenceObject(string); +} From 999c769a4c8480ff76400b19cae12450f4466d35 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 30 Sep 2018 08:10:23 +1000 Subject: [PATCH 1366/2058] Save and restore Token column sort order after closing window --- ProcessHacker/settings.c | 1 + ProcessHacker/tokprp.c | 8 +++++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/ProcessHacker/settings.c b/ProcessHacker/settings.c index ac74df954478..3035484ddafb 100644 --- a/ProcessHacker/settings.c +++ b/ProcessHacker/settings.c @@ -171,6 +171,7 @@ VOID PhAddDefaultSettings( PhpAddStringSetting(L"ThreadStackTreeListColumns", L""); PhpAddScalableIntegerPairSetting(L"ThreadStackWindowSize", L"@96|420,400"); PhpAddStringSetting(L"TokenGroupsListViewColumns", L""); + PhpAddStringSetting(L"TokenGroupsListViewSort", L""); PhpAddIntegerSetting(L"TokenSplitterEnable", L"0"); PhpAddIntegerSetting(L"TokenSplitterPosition", L"150"); PhpAddStringSetting(L"TokenPrivilegesListViewColumns", L""); diff --git a/ProcessHacker/tokprp.c b/ProcessHacker/tokprp.c index bb791c185765..185353a9f96e 100644 --- a/ProcessHacker/tokprp.c +++ b/ProcessHacker/tokprp.c @@ -599,6 +599,7 @@ INT_PTR CALLBACK PhpTokenPageProc( PhAddListViewGroup(tokenPageContext->ListViewHandle, PH_PROCESS_TOKEN_CATEGORY_GROUPS, L"Groups"); ListView_SetImageList(tokenPageContext->ListViewHandle, tokenPageContext->ListViewImageList, LVSIL_SMALL); PhLoadListViewColumnsFromSetting(L"TokenGroupsListViewColumns", tokenPageContext->ListViewHandle); + PhLoadListViewSortColumnsFromSetting(L"TokenGroupsListViewSort", tokenPageContext->ListViewHandle); PhSetDialogItemText(hwndDlg, IDC_USER, L"Unknown"); PhSetDialogItemText(hwndDlg, IDC_USERSID, L"Unknown"); @@ -712,6 +713,7 @@ INT_PTR CALLBACK PhpTokenPageProc( break; case WM_DESTROY: { + PhSaveListViewSortColumnsToSetting(L"TokenGroupsListViewSort", tokenPageContext->ListViewHandle); PhSaveListViewColumnsToSetting(L"TokenGroupsListViewColumns", tokenPageContext->ListViewHandle); if (tokenPageContext->ListViewImageList) @@ -760,7 +762,7 @@ INT_PTR CALLBACK PhpTokenPageProc( break; } - if (LOWORD(wParam) == ID_PRIVILEGE_REMOVE) + if (GET_WM_COMMAND_ID(wParam, lParam) == ID_PRIVILEGE_REMOVE) { if (!PhShowConfirmMessage( hwndDlg, @@ -857,7 +859,7 @@ INT_PTR CALLBACK PhpTokenPageProc( if (!PhShowContinueStatus( hwndDlg, - PhaFormatString(L"Unable to %s %s", action, privilegeName->Buffer)->Buffer, + PhaFormatString(L"Unable to %s %s.", action, PhGetStringOrDefault(privilegeName, L"privilege"))->Buffer, STATUS_UNSUCCESSFUL, 0 )) @@ -871,7 +873,7 @@ INT_PTR CALLBACK PhpTokenPageProc( } else { - PhShowStatus(hwndDlg, L"Unable to open the token", status, 0); + PhShowStatus(hwndDlg, L"Unable to open the token.", status, 0); } PhFree(listViewItems); From 6dcaa1e4e496f4946c6d456bf6343ea31a2094ed Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 30 Sep 2018 09:38:38 +1000 Subject: [PATCH 1367/2058] Add listview group state settings --- phlib/include/settings.h | 14 +++++ phlib/settings.c | 111 +++++++++++++++++++++++++++++++++++++-- 2 files changed, 121 insertions(+), 4 deletions(-) diff --git a/phlib/include/settings.h b/phlib/include/settings.h index 512b4a2558d2..a98f2cc845d9 100644 --- a/phlib/include/settings.h +++ b/phlib/include/settings.h @@ -277,6 +277,20 @@ PhSaveListViewSortColumnsToSetting( _In_ PWSTR Name, _In_ HWND ListViewHandle ); + +VOID +NTAPI +PhLoadListViewGroupStatesFromSetting( + _In_ PWSTR Name, + _In_ HWND ListViewHandle + ); + +VOID +NTAPI +PhSaveListViewGroupStatesToSetting( + _In_ PWSTR Name, + _In_ HWND ListViewHandle + ); // end_phapppub #define PH_SET_INTEGER_CACHED_SETTING(Name, Value) (PhSetIntegerSetting(L#Name, PhCs##Name = (Value))) diff --git a/phlib/settings.c b/phlib/settings.c index 19b65ff7fcfa..51aeb159d1e9 100644 --- a/phlib/settings.c +++ b/phlib/settings.c @@ -1307,19 +1307,19 @@ VOID PhLoadListViewSortColumnsFromSetting( if (remainingPart.Length != 0) { + PH_STRINGREF columnPart; PH_STRINGREF orderPart; - PH_STRINGREF widthPart; ULONG64 integer; - if (!PhSplitStringRefAtChar(&remainingPart, ',', &orderPart, &widthPart)) + if (!PhSplitStringRefAtChar(&remainingPart, ',', &columnPart, &orderPart)) return; - if (!PhStringToInteger64(&orderPart, 10, &integer)) + if (!PhStringToInteger64(&columnPart, 10, &integer)) return; sortColumn = (ULONG)integer; - if (!PhStringToInteger64(&widthPart, 10, &integer)) + if (!PhStringToInteger64(&orderPart, 10, &integer)) return; sortOrder = (ULONG)integer; @@ -1347,3 +1347,106 @@ VOID PhSaveListViewSortColumnsToSetting( PhSetStringSetting2(Name, &string->sr); PhDereferenceObject(string); } + +VOID PhLoadListViewGroupStatesFromSetting( + _In_ PWSTR Name, + _In_ HWND ListViewHandle + ) +{ + ULONG64 countInteger; + PPH_STRING settingsString; + PH_STRINGREF remaining; + PH_STRINGREF part; + + settingsString = PhaGetStringSetting(Name); + remaining = settingsString->sr; + + if (remaining.Length == 0) + return; + + if (!PhSplitStringRefAtChar(&remaining, '|', &part, &remaining)) + return; + + if (!PhStringToInteger64(&part, 10, &countInteger)) + return; + + for (INT index = 0; index < (INT)countInteger; index++) + { + ULONG64 groupId; + ULONG64 stateMask; + PH_STRINGREF groupIdPart; + PH_STRINGREF stateMaskPart; + + if (remaining.Length == 0) + break; + + PhSplitStringRefAtChar(&remaining, '|', &groupIdPart, &remaining); + + if (groupIdPart.Length == 0) + break; + + PhSplitStringRefAtChar(&remaining, '|', &stateMaskPart, &remaining); + + if (stateMaskPart.Length == 0) + break; + + if (!PhStringToInteger64(&groupIdPart, 10, &groupId)) + break; + if (!PhStringToInteger64(&stateMaskPart, 10, &stateMask)) + break; + + ListView_SetGroupState( + ListViewHandle, + (INT)groupId, + LVGS_NORMAL | LVGS_COLLAPSED, + (UINT)stateMask + ); + } +} + +VOID PhSaveListViewGroupStatesToSetting( + _In_ PWSTR Name, + _In_ HWND ListViewHandle + ) +{ + INT index; + INT count; + PPH_STRING settingsString; + PH_STRING_BUILDER stringBuilder; + + PhInitializeStringBuilder(&stringBuilder, 100); + + count = (INT)ListView_GetGroupCount(ListViewHandle); + + PhAppendFormatStringBuilder( + &stringBuilder, + L"%d|", + count + ); + + for (index = 0; index < count; index++) + { + LVGROUP group; + + memset(&group, 0, sizeof(LVGROUP)); + group.cbSize = sizeof(LVGROUP); + group.mask = LVGF_GROUPID | LVGF_STATE; + group.stateMask = LVGS_NORMAL | LVGS_COLLAPSED; + + if (ListView_GetGroupInfoByIndex(ListViewHandle, index, &group) == -1) + continue; + + PhAppendFormatStringBuilder( + &stringBuilder, + L"%d|%u|", + group.iGroupId, + group.state + ); + } + + if (stringBuilder.String->Length != 0) + PhRemoveEndStringBuilder(&stringBuilder, 1); + + settingsString = PH_AUTO(PhFinalStringBuilderString(&stringBuilder)); + PhSetStringSetting2(Name, &settingsString->sr); +} From 43d637b1c8759a12d3ccb3509b183446ad17c035 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 30 Sep 2018 09:40:13 +1000 Subject: [PATCH 1368/2058] Save and restore process Statistics page group states after closing window --- ProcessHacker/prpgstat.c | 4 ++++ ProcessHacker/settings.c | 1 + 2 files changed, 5 insertions(+) diff --git a/ProcessHacker/prpgstat.c b/ProcessHacker/prpgstat.c index 13e7bdc12e7f..8fc3d0b26d66 100644 --- a/ProcessHacker/prpgstat.c +++ b/ProcessHacker/prpgstat.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -320,6 +321,7 @@ INT_PTR CALLBACK PhpProcessStatisticsDlgProc( PhSetExtendedListView(statisticsContext->ListViewHandle); PhpUpdateStatisticsAddListViewGroups(statisticsContext->ListViewHandle); + PhLoadListViewGroupStatesFromSetting(L"ProcStatPropPageGroupStates", statisticsContext->ListViewHandle); PhRegisterCallback( PhGetGeneralCallback(GeneralCallbackProcessProviderUpdatedEvent), @@ -335,6 +337,8 @@ INT_PTR CALLBACK PhpProcessStatisticsDlgProc( break; case WM_DESTROY: { + PhSaveListViewGroupStatesToSetting(L"ProcStatPropPageGroupStates", statisticsContext->ListViewHandle); + PhUnregisterCallback( PhGetGeneralCallback(GeneralCallbackProcessProviderUpdatedEvent), &statisticsContext->ProcessesUpdatedRegistration diff --git a/ProcessHacker/settings.c b/ProcessHacker/settings.c index 3035484ddafb..76d1f892b6c9 100644 --- a/ProcessHacker/settings.c +++ b/ProcessHacker/settings.c @@ -141,6 +141,7 @@ VOID PhAddDefaultSettings( PhpAddStringSetting(L"ProcPropPage", L"General"); PhpAddIntegerPairSetting(L"ProcPropPosition", L"200,200"); PhpAddScalableIntegerPairSetting(L"ProcPropSize", L"@96|460,580"); + PhpAddStringSetting(L"ProcStatPropPageGroupStates", L""); PhpAddStringSetting(L"ProgramInspectExecutables", L"peview.exe \"%s\""); PhpAddIntegerSetting(L"PropagateCpuUsage", L"0"); PhpAddStringSetting(L"RunAsProgram", L""); From 3cb5ffc45c4d91dbc57f8a3d4298a33208218030 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 30 Sep 2018 10:49:44 +1000 Subject: [PATCH 1369/2058] Fix tabspace --- ProcessHacker/ProcessHacker.def | 1242 ++++++++++++++++--------------- 1 file changed, 623 insertions(+), 619 deletions(-) diff --git a/ProcessHacker/ProcessHacker.def b/ProcessHacker/ProcessHacker.def index 7883bc7cfbb4..0c009c10047e 100644 --- a/ProcessHacker/ProcessHacker.def +++ b/ProcessHacker/ProcessHacker.def @@ -5,670 +5,674 @@ EXPORTS ; ; ref - PhAutoDereferenceObject - PhCreateAlloc - PhCreateObject - PhCreateObjectType - PhCreateObjectTypeEx - PhDeleteAutoPool - PhDereferenceObject - PhDereferenceObjectDeferDelete - PhDereferenceObjectEx - PhDrainAutoPool - PhGetObjectType - PhGetObjectTypeInformation - PhInitializeAutoPool - PhReferenceObject - PhReferenceObjectEx - PhReferenceObjectSafe + PhAutoDereferenceObject + PhCreateAlloc + PhCreateObject + PhCreateObjectType + PhCreateObjectTypeEx + PhDeleteAutoPool + PhDereferenceObject + PhDereferenceObjectDeferDelete + PhDereferenceObjectEx + PhDrainAutoPool + PhGetObjectType + PhGetObjectTypeInformation + PhInitializeAutoPool + PhReferenceObject + PhReferenceObjectEx + PhReferenceObjectSafe ; queuedlock - PhfAcquireQueuedLockExclusive - PhfAcquireQueuedLockShared - PhfPulseAllCondition - PhfPulseCondition - PhfQueueWakeEvent - PhfReleaseQueuedLockExclusive - PhfReleaseQueuedLockShared - PhfSetWakeEvent - PhfWaitForCondition - PhfWaitForConditionEx - PhfWaitForWakeEvent - PhfWakeForReleaseQueuedLock + PhfAcquireQueuedLockExclusive + PhfAcquireQueuedLockShared + PhfPulseAllCondition + PhfPulseCondition + PhfQueueWakeEvent + PhfReleaseQueuedLockExclusive + PhfReleaseQueuedLockShared + PhfSetWakeEvent + PhfWaitForCondition + PhfWaitForConditionEx + PhfWaitForWakeEvent + PhfWakeForReleaseQueuedLock ; phconfig - PhGlobalDpi DATA - PhIsExecutingInWow64 - PhInstanceHandle DATA - PhOsVersion DATA - PhSystemBasicInformation DATA - ProcessAllAccess DATA - ProcessQueryAccess DATA - ThreadAllAccess DATA - ThreadQueryAccess DATA - ThreadSetAccess DATA - WindowsVersion DATA + PhGlobalDpi DATA + PhIsExecutingInWow64 + PhInstanceHandle DATA + PhOsVersion DATA + PhSystemBasicInformation DATA + ProcessAllAccess DATA + ProcessQueryAccess DATA + ThreadAllAccess DATA + ThreadQueryAccess DATA + ThreadSetAccess DATA + WindowsVersion DATA ; phbasesup - PhAddElementAvlTree - PhAddEntryHashtable - PhAddEntryHashtableEx - PhAddItemArray - PhAddItemList - PhAddItemPointerList - PhAddItemsArray - PhAddItemSimpleHashtable - PhAddItemsList - PhAllocate - PhAllocateExSafe - PhAllocateFromFreeList - PhAllocatePage - PhAllocateSafe - PhAppendBytesBuilder - PhAppendBytesBuilder2 - PhAppendBytesBuilderEx - PhAppendCharStringBuilder - PhAppendCharStringBuilder2 - PhAppendFormatStringBuilder - PhAppendFormatStringBuilder_V - PhAppendStringBuilder - PhAppendStringBuilder2 - PhAppendStringBuilderEx - PhBufferToHexString - PhBufferToHexStringEx - PhClearArray - PhClearHashtable - PhClearList - PhCompareStringRef - PhCompareStringZNatural - PhConcatStringRef2 - PhConcatStringRef3 - PhConcatStrings - PhConcatStrings_V - PhConcatStrings2 - PhConvertMultiByteToUtf16 - PhConvertMultiByteToUtf16Ex - PhConvertUtf16ToAsciiEx - PhConvertUtf16ToMultiByte - PhConvertUtf16ToMultiByteEx - PhConvertUtf16ToUtf8 - PhConvertUtf16ToUtf8Buffer - PhConvertUtf16ToUtf8Ex - PhConvertUtf16ToUtf8Size - PhConvertUtf8ToUtf16 - PhConvertUtf8ToUtf16Buffer - PhConvertUtf8ToUtf16Ex - PhConvertUtf8ToUtf16Size - PhCopyBytesZ - PhCopyStringZ - PhCopyStringZFromBytes - PhCopyStringZFromMultiByte - PhCountStringZ - PhCreateBytes - PhCreateBytesEx - PhCreateHashtable - PhCreateList - PhCreatePointerList - PhCreateSimpleHashtable - PhCreateString - PhCreateStringEx - PhCreateThread - PhCreateThread2 - PhDecodeUnicodeDecoder - PhDeleteArray - PhDeleteBytesBuilder - PhDeleteCallback - PhDeleteFreeList - PhDeleteStringBuilder - PhDivideSinglesBySingle - PhDosErrorToNtStatus - PhDuplicateBytesZ - PhDuplicateBytesZSafe - PhDuplicateStringZ - PhEncodeUnicode - PhEnumAvlTree - PhEnumHashtable - PhEnumPointerListEx - PhEqualStringRef - PhExponentiate - PhExponentiate64 - PhExtractIcon - PhExtractIconEx - PhfAcquireRundownProtection - PhfBeginInitOnce - PhfEndInitOnce - PhFillMemoryUlong - PhFinalArrayItems - PhFinalBytesBuilderBytes - PhFinalStringBuilderString - PhFindCharInStringRef - PhFindElementAvlTree - PhFindEntryHashtable - PhFindItemList - PhFindItemPointerList - PhFindItemSimpleHashtable - PhFindLastCharInStringRef - PhFindStringInStringRef - PhfInitializeBarrier - PhfInitializeEvent - PhfInitializeInitOnce - PhfInitializeRundownProtection - PhFormat - PhFormatString - PhFormatString_V - PhFormatToBuffer - PhFree - PhFreePage - PhFreeToFreeList - PhfReleaseRundownProtection - PhfResetEvent - PhfSetEvent - PhfWaitForBarrier - PhfWaitForEvent - PhfWaitForRundownProtection - PhGetPrimeNumber - PhHashBytes - PhHashStringRef - PhHexStringToBuffer - PhHexStringToBufferEx - PhInitializeArray - PhInitializeAvlTree - PhInitializeBytesBuilder - PhInitializeCallback - PhInitializeFreeList - PhInitializeStringBuilder - PhInsertItemList - PhInsertItemsList - PhInsertStringBuilder - PhInsertStringBuilder2 - PhInsertStringBuilderEx - PhIntegerToString64 - PhInvokeCallback - PhLoadIndirectString - PhLoadResource - PhLocalTimeToSystemTime - PhLowerBoundElementAvlTree - PhLowerDualBoundElementAvlTree - PhMaximumElementAvlTree - PhMinimumElementAvlTree - PhNtStatusFileNotFound - PhNtStatusToDosError - PhPredecessorElementAvlTree - PhPrintTimeSpan - PhQuerySystemTime - PhQueryTimeZoneBias - PhReAllocate - PhReAllocateSafe - PhReferenceEmptyString - PhRegisterCallback - PhRegisterCallbackEx - PhRemoveElementAvlTree - PhRemoveEntryHashtable - PhRemoveItemArray - PhRemoveItemList - PhRemoveItemPointerList - PhRemoveItemsArray - PhRemoveItemSimpleHashtable - PhRemoveItemsList - PhRemoveStringBuilder - PhResizeArray - PhResizeList - PhRoundUpToPowerOfTwo - PhSplitStringRefAtChar - PhSplitStringRefAtLastChar - PhSplitStringRefAtString - PhSplitStringRefEx - PhStringToDouble - PhStringToInteger64 - PhSuccessorElementAvlTree - PhSystemTimeToLocalTime - PhTrimStringRef - PhUnregisterCallback - PhUpperBoundElementAvlTree - PhUpperDualBoundElementAvlTree - PhWriteUnicodeDecoder - PhZeroExtendToUtf16Buffer - PhZeroExtendToUtf16Ex + PhAddElementAvlTree + PhAddEntryHashtable + PhAddEntryHashtableEx + PhAddItemArray + PhAddItemList + PhAddItemPointerList + PhAddItemsArray + PhAddItemSimpleHashtable + PhAddItemsList + PhAllocate + PhAllocateExSafe + PhAllocateFromFreeList + PhAllocatePage + PhAllocateSafe + PhAppendBytesBuilder + PhAppendBytesBuilder2 + PhAppendBytesBuilderEx + PhAppendCharStringBuilder + PhAppendCharStringBuilder2 + PhAppendFormatStringBuilder + PhAppendFormatStringBuilder_V + PhAppendStringBuilder + PhAppendStringBuilder2 + PhAppendStringBuilderEx + PhBufferToHexString + PhBufferToHexStringEx + PhClearArray + PhClearHashtable + PhClearList + PhCompareStringRef + PhCompareStringZNatural + PhConcatStringRef2 + PhConcatStringRef3 + PhConcatStrings + PhConcatStrings_V + PhConcatStrings2 + PhConvertMultiByteToUtf16 + PhConvertMultiByteToUtf16Ex + PhConvertUtf16ToAsciiEx + PhConvertUtf16ToMultiByte + PhConvertUtf16ToMultiByteEx + PhConvertUtf16ToUtf8 + PhConvertUtf16ToUtf8Buffer + PhConvertUtf16ToUtf8Ex + PhConvertUtf16ToUtf8Size + PhConvertUtf8ToUtf16 + PhConvertUtf8ToUtf16Buffer + PhConvertUtf8ToUtf16Ex + PhConvertUtf8ToUtf16Size + PhCopyBytesZ + PhCopyStringZ + PhCopyStringZFromBytes + PhCopyStringZFromMultiByte + PhCountStringZ + PhCreateBytes + PhCreateBytesEx + PhCreateHashtable + PhCreateList + PhCreatePointerList + PhCreateSimpleHashtable + PhCreateString + PhCreateStringEx + PhCreateThread + PhCreateThread2 + PhDecodeUnicodeDecoder + PhDeleteArray + PhDeleteBytesBuilder + PhDeleteCallback + PhDeleteFreeList + PhDeleteStringBuilder + PhDivideSinglesBySingle + PhDosErrorToNtStatus + PhDuplicateBytesZ + PhDuplicateBytesZSafe + PhDuplicateStringZ + PhEncodeUnicode + PhEnumAvlTree + PhEnumHashtable + PhEnumPointerListEx + PhEqualStringRef + PhExponentiate + PhExponentiate64 + PhExtractIcon + PhExtractIconEx + PhfAcquireRundownProtection + PhfBeginInitOnce + PhfEndInitOnce + PhFillMemoryUlong + PhFinalArrayItems + PhFinalBytesBuilderBytes + PhFinalStringBuilderString + PhFindCharInStringRef + PhFindElementAvlTree + PhFindEntryHashtable + PhFindItemList + PhFindItemPointerList + PhFindItemSimpleHashtable + PhFindLastCharInStringRef + PhFindStringInStringRef + PhfInitializeBarrier + PhfInitializeEvent + PhfInitializeInitOnce + PhfInitializeRundownProtection + PhFormat + PhFormatString + PhFormatString_V + PhFormatToBuffer + PhFree + PhFreePage + PhFreeToFreeList + PhfReleaseRundownProtection + PhfResetEvent + PhfSetEvent + PhfWaitForBarrier + PhfWaitForEvent + PhfWaitForRundownProtection + PhGetPrimeNumber + PhHashBytes + PhHashStringRef + PhHexStringToBuffer + PhHexStringToBufferEx + PhInitializeArray + PhInitializeAvlTree + PhInitializeBytesBuilder + PhInitializeCallback + PhInitializeFreeList + PhInitializeStringBuilder + PhInsertItemList + PhInsertItemsList + PhInsertStringBuilder + PhInsertStringBuilder2 + PhInsertStringBuilderEx + PhIntegerToString64 + PhInvokeCallback + PhLoadIndirectString + PhLoadResource + PhLocalTimeToSystemTime + PhLowerBoundElementAvlTree + PhLowerDualBoundElementAvlTree + PhMaximumElementAvlTree + PhMinimumElementAvlTree + PhNtStatusFileNotFound + PhNtStatusToDosError + PhPredecessorElementAvlTree + PhPrintTimeSpan + PhQuerySystemTime + PhQueryTimeZoneBias + PhReAllocate + PhReAllocateSafe + PhReferenceEmptyString + PhRegisterCallback + PhRegisterCallbackEx + PhRemoveElementAvlTree + PhRemoveEntryHashtable + PhRemoveItemArray + PhRemoveItemList + PhRemoveItemPointerList + PhRemoveItemsArray + PhRemoveItemSimpleHashtable + PhRemoveItemsList + PhRemoveStringBuilder + PhResizeArray + PhResizeList + PhRoundUpToPowerOfTwo + PhSplitStringRefAtChar + PhSplitStringRefAtLastChar + PhSplitStringRefAtString + PhSplitStringRefEx + PhStringToDouble + PhStringToInteger64 + PhSuccessorElementAvlTree + PhSystemTimeToLocalTime + PhTrimStringRef + PhUnregisterCallback + PhUpperBoundElementAvlTree + PhUpperDualBoundElementAvlTree + PhWriteUnicodeDecoder + PhZeroExtendToUtf16Buffer + PhZeroExtendToUtf16Ex ; phnative - PhCreateDirectory - PhCreateFileWin32 - PhCreateFileWin32Ex - PhCreateKey - PhCreateNamedPipe - PhCreatePipe - PhConnectPipe - PhDeleteDirectory - PhDeleteFileWin32 - PhDisconnectNamedPipe - PhEnumDirectoryFile - PhEnumDirectoryObjects - PhEnumFileStreams - PhEnumGenericModules - PhEnumHandles - PhEnumHandlesEx - PhEnumHandlesEx2 - PhEnumKernelModules - PhEnumPagefiles - PhEnumProcessEnvironmentVariables - PhEnumProcesses - PhEnumProcessesEx - PhEnumProcessesForSession - PhEnumProcessModules - PhEnumProcessModules32 - PhEnumProcessModules32Ex - PhEnumProcessModulesEx - PhFindProcessInformation - PhFindProcessInformationByImageName - PhGetFileName - PhGetFileSize - PhGetJobProcessIdList - PhGetKernelFileName - PhGetObjectSecurity - PhGetOwnTokenAttributes - PhGetProcedureAddressRemote - PhGetProcessCommandLine - PhGetProcessDepStatus - PhGetProcessEnvironment - PhGetProcessImageFileName - PhGetProcessImageFileNameByProcessId - PhGetProcessImageFileNameWin32 - PhGetProcessIsDotNet - PhGetProcessIsDotNetEx - PhGetProcessMappedFileName - PhGetProcessPebString - PhGetProcessUnloadedDlls - PhGetProcessWindowTitle - PhGetProcessWorkingSetInformation - PhGetProcessWsCounters - PhGetTokenGroups - PhGetTokenIntegrityLevelRID - PhGetTokenIntegrityLevel - PhGetTokenOwner - PhGetTokenPrimaryGroup - PhGetTokenPrivileges - PhGetTokenUser - PhImpersonateClientOfNamedPipe - PhListenNamedPipe - PhOpenKey - PhLoadAppKey - PhOpenProcess = PhOpenProcessPublic - PhOpenThread = PhOpenThreadPublic - PhOpenThreadProcess - PhPeekNamedPipe - PhQueryFullAttributesFileWin32 - PhQueryKey - PhQueryValueKey - PhResolveDevicePrefix - PhSetFileSize - PhSetObjectSecurity - PhSetTokenIsVirtualizationEnabled - PhSetTokenPrivilege - PhSetTokenPrivilege2 - PhSetTokenSessionId - PhTerminateProcess = PhTerminateProcessPublic - PhTransceiveNamedPipe - PhUnloadDllProcess - PhUnloadDriver - PhUpdateDosDevicePrefixes - PhUpdateMupDevicePrefixes - PhWaitForNamedPipe + PhCreateDirectory + PhCreateFileWin32 + PhCreateFileWin32Ex + PhCreateKey + PhCreateNamedPipe + PhCreatePipe + PhConnectPipe + PhDeleteDirectory + PhDeleteFileWin32 + PhDisconnectNamedPipe + PhEnumDirectoryFile + PhEnumDirectoryObjects + PhEnumFileStreams + PhEnumGenericModules + PhEnumHandles + PhEnumHandlesEx + PhEnumHandlesEx2 + PhEnumKernelModules + PhEnumPagefiles + PhEnumProcessEnvironmentVariables + PhEnumProcesses + PhEnumProcessesEx + PhEnumProcessesForSession + PhEnumProcessModules + PhEnumProcessModules32 + PhEnumProcessModules32Ex + PhEnumProcessModulesEx + PhFindProcessInformation + PhFindProcessInformationByImageName + PhGetFileName + PhGetFileSize + PhGetJobProcessIdList + PhGetKernelFileName + PhGetObjectSecurity + PhGetOwnTokenAttributes + PhGetProcedureAddressRemote + PhGetProcessCommandLine + PhGetProcessDepStatus + PhGetProcessEnvironment + PhGetProcessImageFileName + PhGetProcessImageFileNameByProcessId + PhGetProcessImageFileNameWin32 + PhGetProcessIsDotNet + PhGetProcessIsDotNetEx + PhGetProcessMappedFileName + PhGetProcessPebString + PhGetProcessUnloadedDlls + PhGetProcessWindowTitle + PhGetProcessWorkingSetInformation + PhGetProcessWsCounters + PhGetTokenGroups + PhGetTokenIntegrityLevelRID + PhGetTokenIntegrityLevel + PhGetTokenOwner + PhGetTokenPrimaryGroup + PhGetTokenPrivileges + PhGetTokenUser + PhImpersonateClientOfNamedPipe + PhListenNamedPipe + PhOpenKey + PhLoadAppKey + PhOpenProcess = PhOpenProcessPublic + PhOpenThread = PhOpenThreadPublic + PhOpenThreadProcess + PhPeekNamedPipe + PhQueryFullAttributesFileWin32 + PhQueryKey + PhQueryValueKey + PhResolveDevicePrefix + PhSetFileSize + PhSetObjectSecurity + PhSetTokenIsVirtualizationEnabled + PhSetTokenPrivilege + PhSetTokenPrivilege2 + PhSetTokenSessionId + PhTerminateProcess = PhTerminateProcessPublic + PhTransceiveNamedPipe + PhUnloadDllProcess + PhUnloadDriver + PhUpdateDosDevicePrefixes + PhUpdateMupDevicePrefixes + PhWaitForNamedPipe ; phutil - PhAdjustRectangleToBounds - PhAdjustRectangleToWorkingArea - PhCenterRectangle - PhCenterWindow - PhCompareUnicodeStringZIgnoreMenuPrefix - PhCreateOpenFileDialog - PhCreateProcess - PhCreateProcessAsUser - PhCreateProcessWin32 - PhCreateProcessWin32Ex - PhCreateSaveFileDialog - PhDeleteImageVersionInfo - PhDereferenceObjects - PhEllipsisString - PhEllipsisStringPath - PhEscapeCommandLinePart - PhEscapeStringForMenuPrefix - PhExpandEnvironmentStrings - PhFinalHash - PhFindIntegerSiKeyValuePairs - PhFindLoaderEntry - PhFindStringSiKeyValuePairs - PhFormatDate - PhFormatDateTime - PhFormatDecimal - PhFormatGuid - PhFormatImageVersionInfo - PhFormatSize - PhFormatTime - PhFormatTimeSpan - PhFormatTimeSpanRelative - PhFormatUInt64 - PhFreeFileDialog - PhGenerateGuid - PhGenerateGuidFromName - PhGenerateRandomAlphaString - PhGetApplicationDirectory - PhGetApplicationFileName - PhGetBaseDirectory - PhGetBaseName - PhGetDllFileName - PhGetFileDialogFileName - PhGetFileDialogFilterIndex - PhGetFileDialogOptions - PhGetFileVersionInfo - PhGetFileVersionInfoLangCodePage - PhGetFileVersionInfoString - PhGetFileVersionInfoString2 - PhGetFullPath - PhGetKnownLocation - PhGetMessage - PhGetNtMessage - PhGetStatusMessage - PhGetSystemDirectory - PhGetSystemRoot - PhGetWin32Message - PhInitializeHash - PhInitializeImageVersionInfo - PhIsExecutablePacked - PhMapFlags1 - PhMapFlags2 - PhMatchWildcards - PhParseCommandLine - PhParseCommandLineFuzzy - PhParseCommandLinePart - PhQueryRegistryString - PhQueryRegistryUlong - PhQueryRegistryUlong64 - PhReferenceObjects - PhSetFileDialogFileName - PhSetFileDialogFilter - PhSetFileDialogOptions - PhShellExecute - PhShellExecuteEx - PhShellExploreFile - PhShellOpenKey - PhShellProperties - PhShowConfirmMessage - PhShowContinueStatus - PhShowFileDialog - PhShowMessage - PhShowMessage2 - PhShowStatus - PhUpdateHash + PhAdjustRectangleToBounds + PhAdjustRectangleToWorkingArea + PhCenterRectangle + PhCenterWindow + PhCompareUnicodeStringZIgnoreMenuPrefix + PhCreateOpenFileDialog + PhCreateProcess + PhCreateProcessAsUser + PhCreateProcessWin32 + PhCreateProcessWin32Ex + PhCreateSaveFileDialog + PhDeleteImageVersionInfo + PhDereferenceObjects + PhEllipsisString + PhEllipsisStringPath + PhEscapeCommandLinePart + PhEscapeStringForMenuPrefix + PhExpandEnvironmentStrings + PhFinalHash + PhFindIntegerSiKeyValuePairs + PhFindLoaderEntry + PhFindStringSiKeyValuePairs + PhFormatDate + PhFormatDateTime + PhFormatDecimal + PhFormatGuid + PhFormatImageVersionInfo + PhFormatSize + PhFormatTime + PhFormatTimeSpan + PhFormatTimeSpanRelative + PhFormatUInt64 + PhFreeFileDialog + PhGenerateGuid + PhGenerateGuidFromName + PhGenerateRandomAlphaString + PhGetApplicationDirectory + PhGetApplicationFileName + PhGetBaseDirectory + PhGetBaseName + PhGetDllFileName + PhGetFileDialogFileName + PhGetFileDialogFilterIndex + PhGetFileDialogOptions + PhGetFileVersionInfo + PhGetFileVersionInfoLangCodePage + PhGetFileVersionInfoString + PhGetFileVersionInfoString2 + PhGetFullPath + PhGetKnownLocation + PhGetMessage + PhGetNtMessage + PhGetStatusMessage + PhGetSystemDirectory + PhGetSystemRoot + PhGetWin32Message + PhInitializeHash + PhInitializeImageVersionInfo + PhIsExecutablePacked + PhMapFlags1 + PhMapFlags2 + PhMatchWildcards + PhParseCommandLine + PhParseCommandLineFuzzy + PhParseCommandLinePart + PhQueryRegistryString + PhQueryRegistryUlong + PhQueryRegistryUlong64 + PhReferenceObjects + PhSetFileDialogFileName + PhSetFileDialogFilter + PhSetFileDialogOptions + PhShellExecute + PhShellExecuteEx + PhShellExploreFile + PhShellOpenKey + PhShellProperties + PhShowConfirmMessage + PhShowContinueStatus + PhShowFileDialog + PhShowMessage + PhShowMessage2 + PhShowStatus + PhUpdateHash ; circbuf - PhClearCircularBuffer_FLOAT - PhClearCircularBuffer_PVOID - PhClearCircularBuffer_ULONG - PhClearCircularBuffer_ULONG64 - PhCopyCircularBuffer_FLOAT - PhCopyCircularBuffer_PVOID - PhCopyCircularBuffer_ULONG - PhCopyCircularBuffer_ULONG64 - PhDeleteCircularBuffer_FLOAT - PhDeleteCircularBuffer_PVOID - PhDeleteCircularBuffer_ULONG - PhDeleteCircularBuffer_ULONG64 - PhInitializeCircularBuffer_FLOAT - PhInitializeCircularBuffer_PVOID - PhInitializeCircularBuffer_ULONG - PhInitializeCircularBuffer_ULONG64 - PhResizeCircularBuffer_FLOAT - PhResizeCircularBuffer_PVOID - PhResizeCircularBuffer_ULONG - PhResizeCircularBuffer_ULONG64 + PhClearCircularBuffer_FLOAT + PhClearCircularBuffer_PVOID + PhClearCircularBuffer_ULONG + PhClearCircularBuffer_ULONG64 + PhCopyCircularBuffer_FLOAT + PhCopyCircularBuffer_PVOID + PhCopyCircularBuffer_ULONG + PhCopyCircularBuffer_ULONG64 + PhDeleteCircularBuffer_FLOAT + PhDeleteCircularBuffer_PVOID + PhDeleteCircularBuffer_ULONG + PhDeleteCircularBuffer_ULONG64 + PhInitializeCircularBuffer_FLOAT + PhInitializeCircularBuffer_PVOID + PhInitializeCircularBuffer_ULONG + PhInitializeCircularBuffer_ULONG64 + PhResizeCircularBuffer_FLOAT + PhResizeCircularBuffer_PVOID + PhResizeCircularBuffer_ULONG + PhResizeCircularBuffer_ULONG64 ; cpysave - PhGetGenericTreeNewLines - PhGetTreeNewText + PhGetGenericTreeNewLines + PhGetTreeNewText ; emenu - PhCreateEMenu - PhCreateEMenuItem - PhDestroyEMenu - PhDestroyEMenuItem - PhFindEMenuItem - PhIndexOfEMenuItem - PhInsertEMenuItem - PhLoadResourceEMenuItem - PhModifyEMenuItem - PhRemoveAllEMenuItems - PhRemoveEMenuItem - PhSetFlagsAllEMenuItems - PhSetFlagsEMenuItem - PhShowEMenu + PhCreateEMenu + PhCreateEMenuItem + PhDestroyEMenu + PhDestroyEMenuItem + PhFindEMenuItem + PhIndexOfEMenuItem + PhInsertEMenuItem + PhLoadResourceEMenuItem + PhModifyEMenuItem + PhRemoveAllEMenuItems + PhRemoveEMenuItem + PhSetFlagsAllEMenuItems + PhSetFlagsEMenuItem + PhShowEMenu ; fastlock - PhDeleteFastLock - PhfAcquireFastLockExclusive - PhfAcquireFastLockShared - PhfReleaseFastLockExclusive - PhfReleaseFastLockShared - PhfTryAcquireFastLockExclusive - PhfTryAcquireFastLockShared - PhInitializeFastLock + PhDeleteFastLock + PhfAcquireFastLockExclusive + PhfAcquireFastLockShared + PhfReleaseFastLockExclusive + PhfReleaseFastLockShared + PhfTryAcquireFastLockExclusive + PhfTryAcquireFastLockShared + PhInitializeFastLock ; filestream - PhCreateFileStream - PhCreateFileStream2 - PhFlushFileStream - PhGetPositionFileStream - PhLockFileStream - PhReadFileStream - PhSeekFileStream - PhUnlockFileStream - PhVerifyFileStream - PhWriteFileStream - PhWriteStringAsUtf8FileStream - PhWriteStringAsUtf8FileStream2 - PhWriteStringAsUtf8FileStreamEx - PhWriteStringFormatAsUtf8FileStream - PhWriteStringFormatAsUtf8FileStream_V + PhCreateFileStream + PhCreateFileStream2 + PhFlushFileStream + PhGetPositionFileStream + PhLockFileStream + PhReadFileStream + PhSeekFileStream + PhUnlockFileStream + PhVerifyFileStream + PhWriteFileStream + PhWriteStringAsUtf8FileStream + PhWriteStringAsUtf8FileStream2 + PhWriteStringAsUtf8FileStreamEx + PhWriteStringFormatAsUtf8FileStream + PhWriteStringFormatAsUtf8FileStream_V ; graph - PhDeleteGraphState - PhDrawGraphDirect - PhDrawTrayIconText - PhGetDrawInfoGraphBuffers - PhGraphStateGetDrawInfo - PhInitializeGraphState - PhSetGraphText + PhDeleteGraphState + PhDrawGraphDirect + PhDrawTrayIconText + PhGetDrawInfoGraphBuffers + PhGraphStateGetDrawInfo + PhInitializeGraphState + PhSetGraphText ; guisup - PhAddComboBoxStrings - PhAddLayoutItem - PhAddLayoutItemEx - PhAddListViewColumn - PhAddListViewItem - PhAddTabControlTab - PhDeleteLayoutManager - PhFindListViewItemByFlags - PhFindListViewItemByParam - PhGetComboBoxString - PhGetFileShellIcon - PhGetListBoxString - PhGetListViewItemImageIndex - PhGetListViewItemParam - PhGetSelectedListViewItemParam - PhGetSelectedListViewItemParams - PhGetStockApplicationIcon - PhGetWindowText - PhGetWindowTextEx - PhIconToBitmap - PhInitializeLayoutManager - PhLayoutManagerLayout - PhLoadIcon - PhLoadListViewColumnSettings - PhModalPropertySheet - PhRemoveListViewItem - PhSaveListViewColumnSettings - PhSelectComboBoxString - PhSetClipboardString - PhSetControlTheme - PhSetExtendedListView - PhSetHeaderSortIcon - PhSetImageListBitmap - PhSetListViewItemImageIndex - PhSetListViewSubItem - PhAddListViewGroup - PhAddListViewGroupItem - PhSetStateAllListViewItems - PhGetWindowContext - PhSetWindowContext - PhRemoveWindowContext - PhGetDialogItemValue - PhSetDialogItemValue - PhSetDialogItemText - PhApplicationFont - PhTreeWindowFont - PhRegisterWindowCallback - PhUnregisterWindowCallback - PhInitializeWindowTheme - PhReInitializeWindowTheme - PhInitializeWindowThemeStatusBar + PhAddComboBoxStrings + PhAddLayoutItem + PhAddLayoutItemEx + PhAddListViewColumn + PhAddListViewItem + PhAddTabControlTab + PhDeleteLayoutManager + PhFindListViewItemByFlags + PhFindListViewItemByParam + PhGetComboBoxString + PhGetFileShellIcon + PhGetListBoxString + PhGetListViewItemImageIndex + PhGetListViewItemParam + PhGetSelectedListViewItemParam + PhGetSelectedListViewItemParams + PhGetStockApplicationIcon + PhGetWindowText + PhGetWindowTextEx + PhIconToBitmap + PhInitializeLayoutManager + PhLayoutManagerLayout + PhLoadIcon + PhLoadListViewColumnSettings + PhModalPropertySheet + PhRemoveListViewItem + PhSaveListViewColumnSettings + PhSelectComboBoxString + PhSetClipboardString + PhSetControlTheme + PhSetExtendedListView + PhSetHeaderSortIcon + PhSetImageListBitmap + PhSetListViewItemImageIndex + PhSetListViewSubItem + PhAddListViewGroup + PhAddListViewGroupItem + PhSetStateAllListViewItems + PhGetWindowContext + PhSetWindowContext + PhRemoveWindowContext + PhGetDialogItemValue + PhSetDialogItemValue + PhSetDialogItemText + PhApplicationFont + PhTreeWindowFont + PhRegisterWindowCallback + PhUnregisterWindowCallback + PhInitializeWindowTheme + PhReInitializeWindowTheme + PhInitializeWindowThemeStatusBar ; hndlinfo - PhEnumObjectTypes - PhFormatNativeKeyName - PhGetHandleInformation - PhGetHandleInformationEx - PhStdGetClientIdName + PhEnumObjectTypes + PhFormatNativeKeyName + PhGetHandleInformation + PhGetHandleInformationEx + PhStdGetClientIdName ; lsasup - PhGetSidFullName - PhLookupName - PhLookupPrivilegeDisplayName - PhLookupPrivilegeName - PhLookupPrivilegeValue - PhLookupSid - PhOpenLsaPolicy - PhSidToStringSid + PhGetSidFullName + PhLookupName + PhLookupPrivilegeDisplayName + PhLookupPrivilegeName + PhLookupPrivilegeValue + PhLookupSid + PhOpenLsaPolicy + PhSidToStringSid ; mapimg - PhGetMappedImageCfg - PhGetMappedImageCfgEntry - PhGetMappedImageLoadConfig32 - PhGetMappedImageLoadConfig64 - PhGetMappedImageExports - PhGetMappedImageExportFunction - PhMappedImageRvaToVa - PhInitializeMappedImage - PhLoadMappedImage - PhLoadMappedImageEx - PhUnloadMappedImage + PhGetMappedImageCfg + PhGetMappedImageCfgEntry + PhGetMappedImageLoadConfig32 + PhGetMappedImageLoadConfig64 + PhGetMappedImageExports + PhGetMappedImageExportFunction + PhMappedImageRvaToVa + PhInitializeMappedImage + PhLoadMappedImage + PhLoadMappedImageEx + PhUnloadMappedImage ; settings - PhAddSetting - PhAddSettings - PhClearIgnoredSettings - PhConvertIgnoredSettings - PhGetIntegerSetting - PhGetIntegerPairSetting - PhGetScalableIntegerPairSetting - PhGetStringSetting - PhLoadSettings - PhLoadListViewColumnSettings - PhLoadListViewColumnsFromSetting - PhLoadWindowPlacementFromSetting - PhResetSettings - PhSaveListViewColumnSettings - PhSaveListViewColumnsToSetting - PhSaveWindowPlacementToSetting - PhSettingsInitialization - PhSetIntegerSetting - PhSetIntegerPairSetting - PhSetScalableIntegerPairSetting - PhSetScalableIntegerPairSetting2 - PhSetStringSetting - PhSetStringSetting2 - PhSaveSettings - PhUpdateCachedSettings + PhAddSetting + PhAddSettings + PhClearIgnoredSettings + PhConvertIgnoredSettings + PhGetIntegerSetting + PhGetIntegerPairSetting + PhGetScalableIntegerPairSetting + PhGetStringSetting + PhLoadSettings + PhLoadListViewColumnSettings + PhLoadListViewColumnsFromSetting + PhLoadListViewSortColumnsFromSetting + PhLoadListViewGroupStatesFromSetting + PhLoadWindowPlacementFromSetting + PhResetSettings + PhSaveListViewColumnSettings + PhSaveListViewColumnsToSetting + PhSaveListViewSortColumnsToSetting + PhSaveListViewGroupStatesToSetting + PhSaveWindowPlacementToSetting + PhSettingsInitialization + PhSetIntegerSetting + PhSetIntegerPairSetting + PhSetScalableIntegerPairSetting + PhSetScalableIntegerPairSetting2 + PhSetStringSetting + PhSetStringSetting2 + PhSaveSettings + PhUpdateCachedSettings ; secedit - PhCreateSecurityPage - PhEditSecurity - PhGetAccessEntries - PhGetAccessString - PhGetSeObjectSecurity - PhSetSeObjectSecurity - PhStdGetObjectSecurity - PhStdSetObjectSecurity + PhCreateSecurityPage + PhEditSecurity + PhGetAccessEntries + PhGetAccessString + PhGetSeObjectSecurity + PhSetSeObjectSecurity + PhStdGetObjectSecurity + PhStdSetObjectSecurity ; svcsup - PhEnumServices - PhGetServiceConfig - PhGetServiceDelayedAutoStart - PhGetServiceDescription - PhGetServiceDllParameter - PhGetServiceErrorControlInteger - PhGetServiceErrorControlString - PhGetServiceNameFromTag - PhGetServiceStartTypeInteger - PhGetServiceStartTypeString - PhGetServiceStateString - PhGetServiceTypeInteger - PhGetServiceTypeString - PhGetThreadServiceTag - PhOpenService - PhQueryServiceVariableSize - PhSetServiceDelayedAutoStart + PhEnumServices + PhGetServiceConfig + PhGetServiceDelayedAutoStart + PhGetServiceDescription + PhGetServiceDllParameter + PhGetServiceErrorControlInteger + PhGetServiceErrorControlString + PhGetServiceNameFromTag + PhGetServiceStartTypeInteger + PhGetServiceStartTypeString + PhGetServiceStateString + PhGetServiceTypeInteger + PhGetServiceTypeString + PhGetThreadServiceTag + PhOpenService + PhQueryServiceVariableSize + PhSetServiceDelayedAutoStart ; symprv - PhCreateSymbolProvider - PhGetLineFromAddress - PhGetModuleFromAddress - PhGetSymbolFromAddress - PhGetSymbolFromName - PhLoadModuleSymbolProvider - PhSetOptionsSymbolProvider - PhSetSearchPathSymbolProvider - PhStackWalk - PhWalkThreadStack - PhWriteMiniDumpProcess + PhCreateSymbolProvider + PhGetLineFromAddress + PhGetModuleFromAddress + PhGetSymbolFromAddress + PhGetSymbolFromName + PhLoadModuleSymbolProvider + PhSetOptionsSymbolProvider + PhSetSearchPathSymbolProvider + PhStackWalk + PhWalkThreadStack + PhWriteMiniDumpProcess ; verify - PhVerifyFile + PhVerifyFile ; workqueue - PhDeleteWorkQueue - PhGetGlobalWorkQueue - PhInitializeWorkQueue - PhInitializeWorkQueueEnvironment - PhQueueItemWorkQueue - PhQueueItemWorkQueueEx - PhWaitForWorkQueue + PhDeleteWorkQueue + PhGetGlobalWorkQueue + PhInitializeWorkQueue + PhInitializeWorkQueueEnvironment + PhQueueItemWorkQueue + PhQueueItemWorkQueueEx + PhWaitForWorkQueue ; mxml - mxmlDelete - mxmlElementSetAttr - mxmlLoadFd - mxmlNewOpaque - mxmlNewElement - mxmlSaveFd - mxml_opaque_cb + mxmlDelete + mxmlElementSetAttr + mxmlLoadFd + mxmlNewOpaque + mxmlNewElement + mxmlSaveFd + mxml_opaque_cb ; json - PhCreateJsonParser - PhFreeJsonParser - PhGetJsonValueAsString - PhGetJsonValueAsLong64 - PhCreateJsonObject - PhGetJsonObject - PhGetJsonObjectLength - PhGetJsonObjectBool - PhAddJsonObject - PhGetJsonObjectAsArrayList - PhCreateJsonArray - PhAddJsonArrayObject - PhGetJsonArrayString - PhGetJsonArrayLong64 - PhGetJsonArrayLength - PhGetJsonArrayIndexObject + PhCreateJsonParser + PhFreeJsonParser + PhGetJsonValueAsString + PhGetJsonValueAsLong64 + PhCreateJsonObject + PhGetJsonObject + PhGetJsonObjectLength + PhGetJsonObjectBool + PhAddJsonObject + PhGetJsonObjectAsArrayList + PhCreateJsonArray + PhAddJsonArrayObject + PhGetJsonArrayString + PhGetJsonArrayLong64 + PhGetJsonArrayLength + PhGetJsonArrayIndexObject ; cache - PhCreateCacheFile - PhDeleteCacheFile + PhCreateCacheFile + PhDeleteCacheFile From cfb6ebe8bab0926bd626734fe6a513007b41e9dd Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 30 Sep 2018 10:50:58 +1000 Subject: [PATCH 1370/2058] DotNetTools: Save and restore .NET performance tab sort column and group states --- plugins/DotNetTools/clr/ipcheader.h | 16 ++++++++-------- plugins/DotNetTools/dn.h | 3 ++- plugins/DotNetTools/main.c | 3 ++- plugins/DotNetTools/perfpage.c | 4 ++++ 4 files changed, 16 insertions(+), 10 deletions(-) diff --git a/plugins/DotNetTools/clr/ipcheader.h b/plugins/DotNetTools/clr/ipcheader.h index 193586eb3c7d..f62b87ade0db 100644 --- a/plugins/DotNetTools/clr/ipcheader.h +++ b/plugins/DotNetTools/clr/ipcheader.h @@ -39,10 +39,10 @@ #include "ipcenums.h" // Current version of the IPC Block -const USHORT VER_IPC_BLOCK = 4; +#define VER_IPC_BLOCK 0x4 // Legacy version of the IPC Block -const USHORT VER_LEGACYPRIVATE_IPC_BLOCK = 2; -const USHORT VER_LEGACYPUBLIC_IPC_BLOCK = 3; +#define VER_LEGACYPRIVATE_IPC_BLOCK 0x2 +#define VER_LEGACYPUBLIC_IPC_BLOCK 0x3 //----------------------------------------------------------------------------- // Entry in the IPC Directory. Ensure binary compatibility across versions @@ -60,9 +60,9 @@ typedef struct IPCEntry } IPCEntry; // Newer versions of the CLR use Flags field -const USHORT IPC_FLAG_USES_FLAGS = 0x1; -const USHORT IPC_FLAG_INITIALIZED = 0x2; -const USHORT IPC_FLAG_X86 = 0x4; +#define IPC_FLAG_USES_FLAGS 0x1 +#define IPC_FLAG_INITIALIZED 0x2 +#define IPC_FLAG_X86 0x4 // In hindsight, we should have made the offsets be absolute, but we made them // relative to the end of the FullIPCHeader. @@ -70,8 +70,8 @@ const USHORT IPC_FLAG_X86 = 0x4; // the header size grew. // Thus we make IPCEntry::Offset is relative to IPC_ENTRY_OFFSET_BASE, which // corresponds to sizeof(PrivateIPCHeader) for an v1.0 /v1.1 build. -const ULONG IPC_ENTRY_OFFSET_BASE_X86 = 0x14; -const ULONG IPC_ENTRY_OFFSET_BASE_X64 = 0x0; +#define IPC_ENTRY_OFFSET_BASE_X86 0x14 +#define IPC_ENTRY_OFFSET_BASE_X64 0x0 /****************************************************************************** diff --git a/plugins/DotNetTools/dn.h b/plugins/DotNetTools/dn.h index 3a6cb15860f6..553432ca41fb 100644 --- a/plugins/DotNetTools/dn.h +++ b/plugins/DotNetTools/dn.h @@ -34,7 +34,8 @@ //#define SETTING_NAME_ASM_TREE_LIST_SORT (PLUGIN_NAME L".AsmTreeListSort") #define SETTING_NAME_DOT_NET_CATEGORY_INDEX (PLUGIN_NAME L".DotNetCategoryIndex") #define SETTING_NAME_DOT_NET_COUNTERS_COLUMNS (PLUGIN_NAME L".DotNetListColumns") -#define SETTING_NAME_DOT_NET_SHOW_BYTE_SIZE (PLUGIN_NAME L".DotNetShowByteSizes") +#define SETTING_NAME_DOT_NET_COUNTERS_SORTCOLUMN (PLUGIN_NAME L".DotNetListSort") +#define SETTING_NAME_DOT_NET_COUNTERS_GROUPSTATES (PLUGIN_NAME L".DotNetListGroupStates") #define MSG_UPDATE (WM_APP + 1) diff --git a/plugins/DotNetTools/main.c b/plugins/DotNetTools/main.c index 9096477917c6..593250671dfb 100644 --- a/plugins/DotNetTools/main.c +++ b/plugins/DotNetTools/main.c @@ -203,7 +203,8 @@ LOGICAL DllMain( { IntegerSettingType, SETTING_NAME_ASM_TREE_LIST_FLAGS, L"0" }, { IntegerSettingType, SETTING_NAME_DOT_NET_CATEGORY_INDEX, L"5" }, { StringSettingType, SETTING_NAME_DOT_NET_COUNTERS_COLUMNS, L"" }, - { IntegerSettingType, SETTING_NAME_DOT_NET_SHOW_BYTE_SIZE, L"1" } + { StringSettingType, SETTING_NAME_DOT_NET_COUNTERS_SORTCOLUMN, L"" }, + { StringSettingType, SETTING_NAME_DOT_NET_COUNTERS_GROUPSTATES, L"" } }; PluginInstance = PhRegisterPlugin(PLUGIN_NAME, Instance, &info); diff --git a/plugins/DotNetTools/perfpage.c b/plugins/DotNetTools/perfpage.c index 74d7c13692d1..a60d647313d0 100644 --- a/plugins/DotNetTools/perfpage.c +++ b/plugins/DotNetTools/perfpage.c @@ -791,6 +791,8 @@ INT_PTR CALLBACK DotNetPerfPageDlgProc( DotNetPerfAddListViewGroups(context->CountersListViewHandle); PhLoadListViewColumnsFromSetting(SETTING_NAME_DOT_NET_COUNTERS_COLUMNS, context->CountersListViewHandle); + PhLoadListViewSortColumnsFromSetting(SETTING_NAME_DOT_NET_COUNTERS_SORTCOLUMN, context->CountersListViewHandle); + PhLoadListViewGroupStatesFromSetting(SETTING_NAME_DOT_NET_COUNTERS_GROUPSTATES, context->CountersListViewHandle); #ifdef _WIN64 context->IsWow64 = !!context->ProcessItem->IsWow64; @@ -890,6 +892,8 @@ INT_PTR CALLBACK DotNetPerfPageDlgProc( NtClose(context->ProcessHandle); } + PhSaveListViewGroupStatesToSetting(SETTING_NAME_DOT_NET_COUNTERS_GROUPSTATES, context->CountersListViewHandle); + PhSaveListViewSortColumnsToSetting(SETTING_NAME_DOT_NET_COUNTERS_SORTCOLUMN, context->CountersListViewHandle); PhSaveListViewColumnsToSetting(SETTING_NAME_DOT_NET_COUNTERS_COLUMNS, context->CountersListViewHandle); PhFree(context); From e7634773417ae3fb8ff9f03eb26434512f90d4da Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 1 Oct 2018 06:36:47 +1000 Subject: [PATCH 1371/2058] Fix service properties theme regression, Add missing copyright --- ProcessHacker/srvprp.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/ProcessHacker/srvprp.c b/ProcessHacker/srvprp.c index 3150cefb1be0..69ef4d0ec0db 100644 --- a/ProcessHacker/srvprp.c +++ b/ProcessHacker/srvprp.c @@ -3,6 +3,7 @@ * service properties * * Copyright (C) 2010-2015 wj32 + * Copyright (C) 2017-2018 dmex * * This file is part of Process Hacker. * @@ -338,8 +339,10 @@ INT_PTR CALLBACK PhpServiceGeneralDlgProc( context->Ready = TRUE; - PhInitializeWindowTheme(GetParent(hwndDlg), PhEnableThemeSupport); // HACK - //PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport); + if (PhEnableThemeSupport) // TODO: Required for compat (dmex) + PhInitializeWindowTheme(GetParent(hwndDlg), PhEnableThemeSupport); // HACK (GetParent) + else + PhInitializeWindowTheme(hwndDlg, FALSE); } break; case WM_DESTROY: From 17b31c53e7b838d814341a5752c95b7a9c50d798 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 1 Oct 2018 07:25:41 +1000 Subject: [PATCH 1372/2058] Add service highlighting for LocalService processes --- ProcessHacker/proctree.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ProcessHacker/proctree.c b/ProcessHacker/proctree.c index 22481d5694d3..e8a8be8871e9 100644 --- a/ProcessHacker/proctree.c +++ b/ProcessHacker/proctree.c @@ -2947,7 +2947,10 @@ BOOLEAN NTAPI PhpProcessTreeNewCallback( getNodeColor->BackColor = PhCsColorWow64Processes; else if (PhCsUseColorJobProcesses && processItem->IsInSignificantJob) getNodeColor->BackColor = PhCsColorJobProcesses; - else if (PhCsUseColorServiceProcesses && processItem->ServiceList && processItem->ServiceList->Count != 0) + else if ( + PhCsUseColorServiceProcesses && + (processItem->Sid && RtlEqualSid(processItem->Sid, &PhSeLocalServiceSid) || + processItem->ServiceList && processItem->ServiceList->Count != 0)) getNodeColor->BackColor = PhCsColorServiceProcesses; else if ( PhCsUseColorSystemProcesses && From 827116f892ce6a07e43bbe4bd2c683709fa2ad78 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 2 Oct 2018 05:22:41 +1000 Subject: [PATCH 1373/2058] Fix PH_SERVICE_PAGE_MODIFIED handler sometimes firing without a valid WindowHandle --- ProcessHacker/srvctl.c | 18 ++++++++---------- ProcessHacker/srvlist.c | 2 +- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/ProcessHacker/srvctl.c b/ProcessHacker/srvctl.c index c7c5b9690b1a..71d22b61dc9d 100644 --- a/ProcessHacker/srvctl.c +++ b/ProcessHacker/srvctl.c @@ -227,7 +227,8 @@ INT_PTR CALLBACK PhpServicesPageProc( { case WM_INITDIALOG: { - ULONG i; + context->WindowHandle = hwndDlg; + context->ListViewHandle = GetDlgItem(hwndDlg, IDC_LIST); PhRegisterCallback( PhGetGeneralCallback(GeneralCallbackServiceProviderModifiedEvent), @@ -236,9 +237,6 @@ INT_PTR CALLBACK PhpServicesPageProc( &context->ModifiedEventRegistration ); - context->WindowHandle = hwndDlg; - context->ListViewHandle = GetDlgItem(hwndDlg, IDC_LIST); - // Initialize the list. PhSetListViewStyle(context->ListViewHandle, TRUE, TRUE); PhSetControlTheme(context->ListViewHandle, L"explorer"); @@ -248,7 +246,7 @@ INT_PTR CALLBACK PhpServicesPageProc( PhSetExtendedListView(context->ListViewHandle); - for (i = 0; i < context->NumberOfServices; i++) + for (ULONG i = 0; i < context->NumberOfServices; i++) { SC_HANDLE serviceHandle; PPH_SERVICE_ITEM serviceItem; @@ -299,16 +297,16 @@ INT_PTR CALLBACK PhpServicesPageProc( { ULONG i; - for (i = 0; i < context->NumberOfServices; i++) - PhDereferenceObject(context->Services[i]); - - PhFree(context->Services); - PhUnregisterCallback( PhGetGeneralCallback(GeneralCallbackServiceProviderModifiedEvent), &context->ModifiedEventRegistration ); + for (i = 0; i < context->NumberOfServices; i++) + PhDereferenceObject(context->Services[i]); + + PhFree(context->Services); + if (context->ListViewSettingName) PhSaveListViewColumnsToSetting(context->ListViewSettingName, context->ListViewHandle); diff --git a/ProcessHacker/srvlist.c b/ProcessHacker/srvlist.c index 9ab5abe3ab91..db3910af6ea6 100644 --- a/ProcessHacker/srvlist.c +++ b/ProcessHacker/srvlist.c @@ -404,7 +404,7 @@ static VOID PhpUpdateServiceNodeDescription( ServiceNode->ValidMask |= PHSN_DESCRIPTION; } - // NOTE: Querying the service description via RPC is extremely slow. + // NOTE: Querying the service description via RPC is extremely slow. (dmex) //SC_HANDLE serviceHandle; // //if (serviceHandle = PhOpenService(ServiceNode->ServiceItem->Name->Buffer, SERVICE_QUERY_CONFIG)) From ac6e10cb4c7369eaa3a100942a1e703cc0eaddb4 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 2 Oct 2018 05:26:55 +1000 Subject: [PATCH 1374/2058] Add workaround for 'unknown' network connections created by WSL processes, Add initial highlighting, Fix network connection process icon being destroyed before the connection --- ProcessHacker/include/netprv.h | 13 ++++++++ ProcessHacker/netlist.c | 25 ++++++++++++++ ProcessHacker/netprv.c | 61 ++++++++++++++++++++++++++-------- 3 files changed, 86 insertions(+), 13 deletions(-) diff --git a/ProcessHacker/include/netprv.h b/ProcessHacker/include/netprv.h index c86269ac90ef..c12d10694bd0 100644 --- a/ProcessHacker/include/netprv.h +++ b/ProcessHacker/include/netprv.h @@ -33,6 +33,19 @@ typedef struct _PH_NETWORK_ITEM ULONGLONG OwnerInfo[PH_NETWORK_OWNER_INFO_SIZE]; ULONG LocalScopeId; ULONG RemoteScopeId; + + union + { + ULONG Flags; + struct + { + ULONG UnknownProcess : 1; + ULONG SubsystemProcess : 1; + ULONG Spare : 30; + }; + }; + + PPH_PROCESS_ITEM ProcessItem; } PH_NETWORK_ITEM, *PPH_NETWORK_ITEM; // end_phapppub diff --git a/ProcessHacker/netlist.c b/ProcessHacker/netlist.c index 678fb69a5a2b..cce46d45770d 100644 --- a/ProcessHacker/netlist.c +++ b/ProcessHacker/netlist.c @@ -669,6 +669,31 @@ BOOLEAN NTAPI PhpNetworkTreeNewCallback( PhShowNetworkContextMenu(contextMenu); } return TRUE; + case TreeNewGetNodeColor: + { + PPH_TREENEW_GET_NODE_COLOR getNodeColor = Parameter1; + node = (PPH_NETWORK_NODE)getNodeColor->Node; + + if (!node->NetworkItem) + { + NOTHING; + } + else if (!node->NetworkItem->ProcessId) + { + NOTHING; + } + else if (PhCsUseColorPacked && node->NetworkItem->UnknownProcess) + { + getNodeColor->BackColor = PhCsColorPacked; + } + else if (PhCsUseColorPicoProcesses && node->NetworkItem->SubsystemProcess) + { + getNodeColor->BackColor = PhCsColorPicoProcesses; + } + + getNodeColor->Flags |= TN_AUTO_FORECOLOR; + } + return TRUE; } return FALSE; diff --git a/ProcessHacker/netprv.c b/ProcessHacker/netprv.c index 84b2e279f7e9..fee6cc9a4c38 100644 --- a/ProcessHacker/netprv.c +++ b/ProcessHacker/netprv.c @@ -157,6 +157,10 @@ VOID NTAPI PhpNetworkItemDeleteProcedure( PhDereferenceObject(networkItem->LocalHostString); if (networkItem->RemoteHostString) PhDereferenceObject(networkItem->RemoteHostString); + + // NOTE: Dereferencing the ProcessItem will destroy the NetworkItem->ProcessIcon handle. + if (networkItem->ProcessItem) + PhDereferenceObject(networkItem->ProcessItem); } BOOLEAN PhpNetworkHashtableEqualFunction( @@ -651,8 +655,9 @@ VOID PhNetworkProviderUpdate( // Get process information. if (processItem = PhReferenceProcessItem(networkItem->ProcessId)) { - PhReferenceObject(processItem->ProcessName); - networkItem->ProcessName = processItem->ProcessName; + networkItem->ProcessItem = processItem; + networkItem->ProcessName = PhReferenceObject(processItem->ProcessName); + networkItem->SubsystemProcess = !!processItem->IsSubsystemProcess; PhpUpdateNetworkItemOwner(networkItem, processItem); if (PhTestEvent(&processItem->Stage1Event)) @@ -661,7 +666,35 @@ VOID PhNetworkProviderUpdate( networkItem->ProcessIconValid = TRUE; } - PhDereferenceObject(processItem); + // NOTE: We dereference processItem in PhpNetworkItemDeleteProcedure. (dmex) + } + else + { + HANDLE processHandle; + PPH_STRING fileName; + PROCESS_EXTENDED_BASIC_INFORMATION basicInfo; + + // HACK HACK HACK + // WSL subsystem processes (e.g. nginx) create sockets, clone/fork themselves, duplicate the socket into the child process and then terminate. + // The socket handle remains valid and in-use by the child process BUT the socket continues returning the PID of the exited process??? + // Fixing this causes a major performance problem; If we have 100,000 sockets then on previous versions of Windows we would only need 2 system calls maximum + // (for the process list) to identify the owner of every socket but now we need to make 4 system calls for every_last_socket totaling 400,000 system calls... great. + if (NT_SUCCESS(PhOpenProcess(&processHandle, ProcessQueryAccess, networkItem->ProcessId))) + { + if (NT_SUCCESS(PhGetProcessExtendedBasicInformation(processHandle, &basicInfo))) + { + networkItem->SubsystemProcess = !!basicInfo.IsSubsystemProcess; + } + + if (NT_SUCCESS(PhGetProcessImageFileName(processHandle, &fileName))) + { + PhMoveReference(&networkItem->ProcessName, PhGetBaseName(fileName)); + } + + NtClose(processHandle); + } + + networkItem->UnknownProcess = TRUE; } // Add the network item to the hashtable. @@ -675,7 +708,6 @@ VOID PhNetworkProviderUpdate( else { BOOLEAN modified = FALSE; - PPH_PROCESS_ITEM processItem; if (InterlockedExchange(&networkItem->JustResolved, 0) != 0) modified = TRUE; @@ -686,26 +718,29 @@ VOID PhNetworkProviderUpdate( modified = TRUE; } - if (!networkItem->ProcessName || !networkItem->ProcessIconValid) + if (!networkItem->ProcessIconValid) { - if (processItem = PhReferenceProcessItem(networkItem->ProcessId)) + if (!networkItem->ProcessItem) + { + networkItem->ProcessItem = PhReferenceProcessItem(networkItem->ProcessId); + // NOTE: We dereference processItem in PhpNetworkItemDeleteProcedure. (dmex) + } + + if (networkItem->ProcessItem) { if (!networkItem->ProcessName) { - PhReferenceObject(processItem->ProcessName); - networkItem->ProcessName = processItem->ProcessName; - PhpUpdateNetworkItemOwner(networkItem, processItem); + networkItem->ProcessName = PhReferenceObject(networkItem->ProcessItem->ProcessName); + PhpUpdateNetworkItemOwner(networkItem, networkItem->ProcessItem); modified = TRUE; } - if (!networkItem->ProcessIconValid && PhTestEvent(&processItem->Stage1Event)) + if (!networkItem->ProcessIconValid && PhTestEvent(&networkItem->ProcessItem->Stage1Event)) { - networkItem->ProcessIcon = processItem->SmallIcon; + networkItem->ProcessIcon = networkItem->ProcessItem->SmallIcon; networkItem->ProcessIconValid = TRUE; modified = TRUE; } - - PhDereferenceObject(processItem); } } From 52169ef7a324f88ef893ea2f27f6e2f12d442cb4 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 2 Oct 2018 13:17:56 +1000 Subject: [PATCH 1375/2058] Add PhSetWindowText --- phlib/guisup.c | 14 +++++++++++--- phlib/include/guisup.h | 8 ++++++++ 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/phlib/guisup.c b/phlib/guisup.c index 60089646f1ec..d1e6a766da46 100644 --- a/phlib/guisup.c +++ b/phlib/guisup.c @@ -1546,7 +1546,7 @@ VOID PhSetDialogItemValue( if (controlHandle = GetDlgItem(WindowHandle, ControlID)) { - SendMessage(controlHandle, WM_SETTEXT, 0, (LPARAM)valueString); // DefWindowProc + PhSetWindowText(controlHandle, valueString); } } @@ -1560,16 +1560,24 @@ VOID PhSetDialogItemText( if (controlHandle = GetDlgItem(WindowHandle, ControlID)) { - SendMessage(controlHandle, WM_SETTEXT, 0, (LPARAM)WindowText); // DefWindowProc + PhSetWindowText(controlHandle, WindowText); } } +VOID PhSetWindowText( + _In_ HWND WindowHandle, + _In_ PCWSTR WindowText + ) +{ + SendMessage(WindowHandle, WM_SETTEXT, 0, (LPARAM)WindowText); // TODO: DefWindowProc (dmex) +} + VOID PhSetWindowAlwaysOnTop( _In_ HWND WindowHandle, _In_ BOOLEAN AlwaysOnTop ) { - SetFocus(WindowHandle); // HACK - SetWindowPos doesn't work properly without this + SetFocus(WindowHandle); // HACK - SetWindowPos doesn't work properly without this (wj32) SetWindowPos( WindowHandle, AlwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST, diff --git a/phlib/include/guisup.h b/phlib/include/guisup.h index 599a841040b3..c98adb5497fe 100644 --- a/phlib/include/guisup.h +++ b/phlib/include/guisup.h @@ -563,6 +563,14 @@ PhSetDialogItemText( _In_ PCWSTR WindowText ); +PHLIBAPI +VOID +NTAPI +PhSetWindowText( + _In_ HWND WindowHandle, + _In_ PCWSTR WindowText + ); + PHLIBAPI VOID NTAPI From 77c15de5a2a3b398ce65c9b04cc43e4088650d26 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 2 Oct 2018 15:00:16 +1000 Subject: [PATCH 1376/2058] Move phlib-test solution into tools --- {tests => tools/tests}/phlib-test/main.c | 0 .../tests}/phlib-test/phlib-test.vcxproj | 0 .../phlib-test/phlib-test.vcxproj.filters | 68 +++++++++---------- {tests => tools/tests}/phlib-test/t_avltree.c | 0 {tests => tools/tests}/phlib-test/t_basesup.c | 0 {tests => tools/tests}/phlib-test/t_format.c | 0 {tests => tools/tests}/phlib-test/t_util.c | 0 {tests => tools/tests}/phlib-test/tests.h | 0 8 files changed, 34 insertions(+), 34 deletions(-) rename {tests => tools/tests}/phlib-test/main.c (100%) rename {tests => tools/tests}/phlib-test/phlib-test.vcxproj (100%) rename {tests => tools/tests}/phlib-test/phlib-test.vcxproj.filters (97%) rename {tests => tools/tests}/phlib-test/t_avltree.c (100%) rename {tests => tools/tests}/phlib-test/t_basesup.c (100%) rename {tests => tools/tests}/phlib-test/t_format.c (100%) rename {tests => tools/tests}/phlib-test/t_util.c (100%) rename {tests => tools/tests}/phlib-test/tests.h (100%) diff --git a/tests/phlib-test/main.c b/tools/tests/phlib-test/main.c similarity index 100% rename from tests/phlib-test/main.c rename to tools/tests/phlib-test/main.c diff --git a/tests/phlib-test/phlib-test.vcxproj b/tools/tests/phlib-test/phlib-test.vcxproj similarity index 100% rename from tests/phlib-test/phlib-test.vcxproj rename to tools/tests/phlib-test/phlib-test.vcxproj diff --git a/tests/phlib-test/phlib-test.vcxproj.filters b/tools/tests/phlib-test/phlib-test.vcxproj.filters similarity index 97% rename from tests/phlib-test/phlib-test.vcxproj.filters rename to tools/tests/phlib-test/phlib-test.vcxproj.filters index bcef133e24dd..4e5709ff82b8 100644 --- a/tests/phlib-test/phlib-test.vcxproj.filters +++ b/tools/tests/phlib-test/phlib-test.vcxproj.filters @@ -1,35 +1,35 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hpp;hxx;hm;inl;inc;xsd - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + \ No newline at end of file diff --git a/tests/phlib-test/t_avltree.c b/tools/tests/phlib-test/t_avltree.c similarity index 100% rename from tests/phlib-test/t_avltree.c rename to tools/tests/phlib-test/t_avltree.c diff --git a/tests/phlib-test/t_basesup.c b/tools/tests/phlib-test/t_basesup.c similarity index 100% rename from tests/phlib-test/t_basesup.c rename to tools/tests/phlib-test/t_basesup.c diff --git a/tests/phlib-test/t_format.c b/tools/tests/phlib-test/t_format.c similarity index 100% rename from tests/phlib-test/t_format.c rename to tools/tests/phlib-test/t_format.c diff --git a/tests/phlib-test/t_util.c b/tools/tests/phlib-test/t_util.c similarity index 100% rename from tests/phlib-test/t_util.c rename to tools/tests/phlib-test/t_util.c diff --git a/tests/phlib-test/tests.h b/tools/tests/phlib-test/tests.h similarity index 100% rename from tests/phlib-test/tests.h rename to tools/tests/phlib-test/tests.h From c04e80e714c1d1e47446cedfa618ccbc318e3b37 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 2 Oct 2018 15:03:24 +1000 Subject: [PATCH 1377/2058] Update SetWindowText to PhSetWindowText --- ProcessHacker/chdlg.c | 10 +++++----- ProcessHacker/memedit.c | 4 ++-- ProcessHacker/memrslt.c | 2 +- ProcessHacker/options.c | 2 +- ProcessHacker/plugman.c | 6 +++--- ProcessHacker/procrec.c | 2 +- ProcessHacker/runas.c | 6 +++--- ProcessHacker/srvctl.c | 24 ++++++++++++------------ ProcessHacker/thrdstk.c | 2 +- 9 files changed, 29 insertions(+), 29 deletions(-) diff --git a/ProcessHacker/chdlg.c b/ProcessHacker/chdlg.c index 70f2793ad0cc..4f7567e92077 100644 --- a/ProcessHacker/chdlg.c +++ b/ProcessHacker/chdlg.c @@ -108,8 +108,8 @@ INT_PTR CALLBACK PhpChoiceDlgProc( PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context); PhCenterWindow(hwndDlg, GetParent(hwndDlg)); - SetWindowText(hwndDlg, context->Title); - SetWindowText(GetDlgItem(hwndDlg, IDC_MESSAGE), context->Message); + PhSetWindowText(hwndDlg, context->Title); + PhSetWindowText(GetDlgItem(hwndDlg, IDC_MESSAGE), context->Message); type = context->Flags & PH_CHOICE_DIALOG_TYPE_MASK; @@ -192,7 +192,7 @@ INT_PTR CALLBACK PhpChoiceDlgProc( if (type == PH_CHOICE_DIALOG_PASSWORD) { if (*context->SelectedChoice) - SetWindowText(comboBoxHandle, (*context->SelectedChoice)->Buffer); + PhSetWindowText(comboBoxHandle, (*context->SelectedChoice)->Buffer); Edit_SetSel(comboBoxHandle, 0, -1); } @@ -205,7 +205,7 @@ INT_PTR CALLBACK PhpChoiceDlgProc( { if (type == PH_CHOICE_DIALOG_USER_CHOICE && *context->SelectedChoice) { - SetWindowText(comboBoxHandle, (*context->SelectedChoice)->Buffer); + PhSetWindowText(comboBoxHandle, (*context->SelectedChoice)->Buffer); } else if (type == PH_CHOICE_DIALOG_CHOICE && context->NumberOfChoices != 0) { @@ -219,7 +219,7 @@ INT_PTR CALLBACK PhpChoiceDlgProc( if (context->Option) { - SetWindowText(checkBoxHandle, context->Option); + PhSetWindowText(checkBoxHandle, context->Option); if (context->SelectedOption) Button_SetCheck(checkBoxHandle, *context->SelectedOption ? BST_CHECKED : BST_UNCHECKED); diff --git a/ProcessHacker/memedit.c b/ProcessHacker/memedit.c index ab0a0b3fdf4a..44fdc26963d6 100644 --- a/ProcessHacker/memedit.c +++ b/ProcessHacker/memedit.c @@ -191,7 +191,7 @@ INT_PTR CALLBACK PhpMemoryEditorDlgProc( if (context->Title) { - SetWindowText(hwndDlg, context->Title->Buffer); + PhSetWindowText(hwndDlg, context->Title->Buffer); } else { @@ -199,7 +199,7 @@ INT_PTR CALLBACK PhpMemoryEditorDlgProc( if (processItem = PhReferenceProcessItem(context->ProcessId)) { - SetWindowText(hwndDlg, PhaFormatString(L"%s (%u) (0x%Ix - 0x%Ix)", + PhSetWindowText(hwndDlg, PhaFormatString(L"%s (%u) (0x%Ix - 0x%Ix)", processItem->ProcessName->Buffer, HandleToUlong(context->ProcessId), context->BaseAddress, (ULONG_PTR)context->BaseAddress + context->RegionSize)->Buffer); PhDereferenceObject(processItem); diff --git a/ProcessHacker/memrslt.c b/ProcessHacker/memrslt.c index 655222f6760f..62b6da1802be 100644 --- a/ProcessHacker/memrslt.c +++ b/ProcessHacker/memrslt.c @@ -288,7 +288,7 @@ INT_PTR CALLBACK PhpMemoryResultsDlgProc( if (processItem = PhReferenceProcessItem(context->ProcessId)) { - SetWindowText(hwndDlg, PhaFormatString(L"Results - %s (%u)", + PhSetWindowText(hwndDlg, PhaFormatString(L"Results - %s (%u)", processItem->ProcessName->Buffer, HandleToUlong(processItem->ProcessId))->Buffer); PhDereferenceObject(processItem); } diff --git a/ProcessHacker/options.c b/ProcessHacker/options.c index a8f4ad9ce2ef..546930ba7c57 100644 --- a/ProcessHacker/options.c +++ b/ProcessHacker/options.c @@ -1505,7 +1505,7 @@ static INT_PTR CALLBACK PhpOptionsAdvancedEditDlgProc( SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER))); SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER))); - SetWindowText(hwndDlg, L"Setting Editor"); + PhSetWindowText(hwndDlg, L"Setting Editor"); PhCenterWindow(hwndDlg, GetParent(hwndDlg)); PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, setting); diff --git a/ProcessHacker/plugman.c b/ProcessHacker/plugman.c index 1df304a26bd9..849fab3a9fab 100644 --- a/ProcessHacker/plugman.c +++ b/ProcessHacker/plugman.c @@ -668,7 +668,7 @@ INT_PTR CALLBACK PhpPluginsDlgProc( PhpEnumerateLoadedPlugins(context); TreeNew_AutoSizeColumn(context->TreeNewHandle, PH_PLUGIN_TREE_COLUMN_ITEM_NAME, TN_AUTOSIZE_REMAINING_SPACE); - SetWindowText(GetDlgItem(hwndDlg, IDC_DISABLED), PhaFormatString(L"Disabled Plugins (%lu)", PhpDisabledPluginsCount())->Buffer); + PhSetWindowText(GetDlgItem(hwndDlg, IDC_DISABLED), PhaFormatString(L"Disabled Plugins (%lu)", PhpDisabledPluginsCount())->Buffer); PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport); } @@ -720,7 +720,7 @@ INT_PTR CALLBACK PhpPluginsDlgProc( ClearPluginsTree(context); PhpEnumerateLoadedPlugins(context); TreeNew_AutoSizeColumn(context->TreeNewHandle, PH_PLUGIN_TREE_COLUMN_ITEM_NAME, TN_AUTOSIZE_REMAINING_SPACE); - SetWindowText(GetDlgItem(hwndDlg, IDC_DISABLED), PhaFormatString(L"Disabled Plugins (%lu)", PhpDisabledPluginsCount())->Buffer); + PhSetWindowText(GetDlgItem(hwndDlg, IDC_DISABLED), PhaFormatString(L"Disabled Plugins (%lu)", PhpDisabledPluginsCount())->Buffer); } break; case ID_SHOWCONTEXTMENU: @@ -788,7 +788,7 @@ INT_PTR CALLBACK PhpPluginsDlgProc( RemovePluginsNode(context, selectedNode); - SetWindowText(GetDlgItem(hwndDlg, IDC_DISABLED), PhaFormatString(L"Disabled Plugins (%lu)", PhpDisabledPluginsCount())->Buffer); + PhSetWindowText(GetDlgItem(hwndDlg, IDC_DISABLED), PhaFormatString(L"Disabled Plugins (%lu)", PhpDisabledPluginsCount())->Buffer); } break; case PH_PLUGIN_TREE_ITEM_MENU_PROPERTIES: diff --git a/ProcessHacker/procrec.c b/ProcessHacker/procrec.c index 26fc6d5b5227..534ea05decc1 100644 --- a/ProcessHacker/procrec.c +++ b/ProcessHacker/procrec.c @@ -134,7 +134,7 @@ INT_PTR CALLBACK PhpProcessRecordDlgProc( PhCenterWindow(hwndDlg, GetParent(hwndDlg)); PhSetDialogFocus(hwndDlg, GetDlgItem(hwndDlg, IDOK)); - SetWindowText(hwndDlg, processNameString->Buffer); + PhSetWindowText(hwndDlg, processNameString->Buffer); PhSetDialogItemText(hwndDlg, IDC_PROCESSNAME, processNameString->Buffer); diff --git a/ProcessHacker/runas.c b/ProcessHacker/runas.c index a3e41a348f50..6f4e06d72e13 100644 --- a/ProcessHacker/runas.c +++ b/ProcessHacker/runas.c @@ -918,7 +918,7 @@ INT_PTR CALLBACK PhpRunAsDlgProc( { if (userName = PhGetTokenUserString(tokenHandle, TRUE)) { - SetWindowText(context->UserComboBoxWindowHandle, userName->Buffer); + PhSetWindowText(context->UserComboBoxWindowHandle, userName->Buffer); PhDereferenceObject(userName); } @@ -1050,7 +1050,7 @@ INT_PTR CALLBACK PhpRunAsDlgProc( if (!IsServiceAccount(username)) { password = PhGetWindowText(context->PasswordEditWindowHandle); - SetWindowText(context->PasswordEditWindowHandle, L""); + PhSetWindowText(context->PasswordEditWindowHandle, L""); } //if (IsCurrentUserAccount(username)) @@ -1174,7 +1174,7 @@ INT_PTR CALLBACK PhpRunAsDlgProc( PPH_STRING fileName; fileName = PhGetFileDialogFileName(fileDialog); - SetWindowText(context->ProgramComboBoxWindowHandle, fileName->Buffer); + PhSetWindowText(context->ProgramComboBoxWindowHandle, fileName->Buffer); PhDereferenceObject(fileName); } diff --git a/ProcessHacker/srvctl.c b/ProcessHacker/srvctl.c index 71d22b61dc9d..3c18a81f1350 100644 --- a/ProcessHacker/srvctl.c +++ b/ProcessHacker/srvctl.c @@ -137,24 +137,24 @@ VOID PhpFixProcessServicesControls( { case SERVICE_RUNNING: { - SetWindowText(startButton, L"S&top"); - SetWindowText(pauseButton, L"&Pause"); + PhSetWindowText(startButton, L"S&top"); + PhSetWindowText(pauseButton, L"&Pause"); EnableWindow(startButton, ServiceItem->ControlsAccepted & SERVICE_ACCEPT_STOP); EnableWindow(pauseButton, ServiceItem->ControlsAccepted & SERVICE_ACCEPT_PAUSE_CONTINUE); } break; case SERVICE_PAUSED: { - SetWindowText(startButton, L"S&top"); - SetWindowText(pauseButton, L"C&ontinue"); + PhSetWindowText(startButton, L"S&top"); + PhSetWindowText(pauseButton, L"C&ontinue"); EnableWindow(startButton, ServiceItem->ControlsAccepted & SERVICE_ACCEPT_STOP); EnableWindow(pauseButton, ServiceItem->ControlsAccepted & SERVICE_ACCEPT_PAUSE_CONTINUE); } break; case SERVICE_STOPPED: { - SetWindowText(startButton, L"&Start"); - SetWindowText(pauseButton, L"&Pause"); + PhSetWindowText(startButton, L"&Start"); + PhSetWindowText(pauseButton, L"&Pause"); EnableWindow(startButton, TRUE); EnableWindow(pauseButton, FALSE); } @@ -164,8 +164,8 @@ VOID PhpFixProcessServicesControls( case SERVICE_PAUSE_PENDING: case SERVICE_STOP_PENDING: { - SetWindowText(startButton, L"&Start"); - SetWindowText(pauseButton, L"&Pause"); + PhSetWindowText(startButton, L"&Start"); + PhSetWindowText(pauseButton, L"&Pause"); EnableWindow(startButton, FALSE); EnableWindow(pauseButton, FALSE); } @@ -179,7 +179,7 @@ VOID PhpFixProcessServicesControls( { if (description = PhGetServiceDescription(serviceHandle)) { - SetWindowText(descriptionLabel, description->Buffer); + PhSetWindowText(descriptionLabel, description->Buffer); PhDereferenceObject(description); } @@ -188,11 +188,11 @@ VOID PhpFixProcessServicesControls( } else { - SetWindowText(startButton, L"&Start"); - SetWindowText(pauseButton, L"&Pause"); + PhSetWindowText(startButton, L"&Start"); + PhSetWindowText(pauseButton, L"&Pause"); EnableWindow(startButton, FALSE); EnableWindow(pauseButton, FALSE); - SetWindowText(descriptionLabel, L""); + PhSetWindowText(descriptionLabel, L""); } } diff --git a/ProcessHacker/thrdstk.c b/ProcessHacker/thrdstk.c index df7a6393f679..7659a4f9a70a 100644 --- a/ProcessHacker/thrdstk.c +++ b/ProcessHacker/thrdstk.c @@ -791,7 +791,7 @@ INT_PTR CALLBACK PhpThreadStackDlgProc( SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER))); SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER))); - SetWindowText(hwndDlg, PhaFormatString(L"Stack - thread %u", HandleToUlong(context->ThreadId))->Buffer); + PhSetWindowText(hwndDlg, PhaFormatString(L"Stack - thread %u", HandleToUlong(context->ThreadId))->Buffer); InitializeThreadStackTree(context); From 6ffd33b3b4647bf0cc86f7a15b8bed497eee06b4 Mon Sep 17 00:00:00 2001 From: diversenok Date: Tue, 2 Oct 2018 23:23:46 +0300 Subject: [PATCH 1378/2058] Adjustment of groups for tokens (#326) --- ProcessHacker/resource.h | 4 + ProcessHacker/tokprp.c | 222 +++++++++++++++++++++++++++++++++------ phlib/include/phnative.h | 2 +- phlib/native.c | 20 +++- 4 files changed, 211 insertions(+), 37 deletions(-) diff --git a/ProcessHacker/resource.h b/ProcessHacker/resource.h index f095f24092b5..9370d93ec9ad 100644 --- a/ProcessHacker/resource.h +++ b/ProcessHacker/resource.h @@ -741,6 +741,10 @@ #define ID_MINIINFO_REFRESHAUTOMATICALLY 40289 #define IDC_MAXSCREEN 40293 #define ID_EMPTY_COMBINEMEMORYLISTS 40295 +#define ID_PRIVILEGE_RESET 40296 +#define ID_GROUP_ENABLE 40297 +#define ID_GROUP_DISABLE 40298 +#define ID_GROUP_RESET 40299 #define IDDYNAMIC 50000 #define IDPLUGINS 55000 diff --git a/ProcessHacker/tokprp.c b/ProcessHacker/tokprp.c index 185353a9f96e..a6d12b851945 100644 --- a/ProcessHacker/tokprp.c +++ b/ProcessHacker/tokprp.c @@ -34,7 +34,8 @@ typedef enum _PH_PROCESS_TOKEN_CATEGORY { PH_PROCESS_TOKEN_CATEGORY_PRIVILEGES, - PH_PROCESS_TOKEN_CATEGORY_GROUPS + PH_PROCESS_TOKEN_CATEGORY_GROUPS, + PH_PROCESS_TOKEN_CATEGORY_RESTRICTED } PH_PROCESS_TOKEN_CATEGORY; typedef enum _PH_PROCESS_TOKEN_INDEX @@ -46,7 +47,7 @@ typedef enum _PH_PROCESS_TOKEN_INDEX typedef struct _PHP_TOKEN_PAGE_LISTVIEW_ITEM { - BOOLEAN IsTokenGroupEntry; + PH_PROCESS_TOKEN_CATEGORY ItemCategory; union { PSID_AND_ATTRIBUTES TokenGroup; @@ -244,12 +245,12 @@ PPH_STRING PhGetGroupAttributesString( { PPH_STRING string; - if (Attributes & SE_GROUP_INTEGRITY) + if (Attributes & (SE_GROUP_INTEGRITY | SE_GROUP_INTEGRITY_ENABLED)) { - if (Attributes & SE_GROUP_INTEGRITY_ENABLED) - string = PhReferenceEmptyString(); + if (Attributes & SE_GROUP_ENABLED) + string = PhCreateString(L"Enabled (as a group)"); else - string = PhCreateString(L"Disabled"); + string = PhReferenceEmptyString(); } else { @@ -283,12 +284,10 @@ COLORREF PhGetGroupAttributesColor( _In_ ULONG Attributes ) { - if (Attributes & SE_GROUP_INTEGRITY) + if (Attributes & (SE_GROUP_INTEGRITY | SE_GROUP_INTEGRITY_ENABLED)) { - if (Attributes & SE_GROUP_INTEGRITY_ENABLED) + if (!(Attributes & SE_GROUP_ENABLED)) return RGB(0xe0, 0xf0, 0xe0); - else - return GetSysColor(COLOR_WINDOW); } if (Attributes & SE_GROUP_ENABLED) @@ -335,10 +334,10 @@ static COLORREF NTAPI PhpTokenGroupColorFunction( { PPHP_TOKEN_PAGE_LISTVIEW_ITEM entry = Param; - if (entry->IsTokenGroupEntry) - return PhGetGroupAttributesColor(entry->TokenGroup->Attributes); - else + if (entry->ItemCategory == PH_PROCESS_TOKEN_CATEGORY_PRIVILEGES) return PhGetPrivilegeAttributesColor(entry->TokenPrivilege->Attributes); + else + return PhGetGroupAttributesColor(entry->TokenGroup->Attributes); } PWSTR PhGetPrivilegeAttributesString( @@ -420,12 +419,12 @@ VOID PhpUpdateSidsFromTokenGroups( PPHP_TOKEN_PAGE_LISTVIEW_ITEM lvitem; lvitem = PhAllocateZero(sizeof(PHP_TOKEN_PAGE_LISTVIEW_ITEM)); - lvitem->IsTokenGroupEntry = TRUE; + lvitem->ItemCategory = Restricted ? PH_PROCESS_TOKEN_CATEGORY_RESTRICTED : PH_PROCESS_TOKEN_CATEGORY_GROUPS; lvitem->TokenGroup = &Groups->Groups[i]; lvItemIndex = PhAddListViewGroupItem( ListViewHandle, - PH_PROCESS_TOKEN_CATEGORY_GROUPS, + lvitem->ItemCategory, PH_PROCESS_TOKEN_INDEX_NAME, fullName->Buffer, lvitem @@ -597,6 +596,7 @@ INT_PTR CALLBACK PhpTokenPageProc( ListView_EnableGroupView(tokenPageContext->ListViewHandle, TRUE); PhAddListViewGroup(tokenPageContext->ListViewHandle, PH_PROCESS_TOKEN_CATEGORY_PRIVILEGES, L"Privileges"); PhAddListViewGroup(tokenPageContext->ListViewHandle, PH_PROCESS_TOKEN_CATEGORY_GROUPS, L"Groups"); + PhAddListViewGroup(tokenPageContext->ListViewHandle, PH_PROCESS_TOKEN_CATEGORY_RESTRICTED, L"Restricting SIDs"); ListView_SetImageList(tokenPageContext->ListViewHandle, tokenPageContext->ListViewImageList, LVSIL_SMALL); PhLoadListViewColumnsFromSetting(L"TokenGroupsListViewColumns", tokenPageContext->ListViewHandle); PhLoadListViewSortColumnsFromSetting(L"TokenGroupsListViewSort", tokenPageContext->ListViewHandle); @@ -732,10 +732,11 @@ INT_PTR CALLBACK PhpTokenPageProc( { case ID_PRIVILEGE_ENABLE: case ID_PRIVILEGE_DISABLE: + case ID_PRIVILEGE_RESET: case ID_PRIVILEGE_REMOVE: { NTSTATUS status; - BOOLEAN listViewGroupItemsValid = FALSE; + BOOLEAN listViewGroupItemsValid = TRUE; PPHP_TOKEN_PAGE_LISTVIEW_ITEM *listViewItems; ULONG numberOfItems; HANDLE tokenHandle; @@ -749,14 +750,14 @@ INT_PTR CALLBACK PhpTokenPageProc( for (i = 0; i < numberOfItems; i++) { - if (listViewItems[i]->IsTokenGroupEntry) + if (listViewItems[i]->ItemCategory != PH_PROCESS_TOKEN_CATEGORY_PRIVILEGES) { - listViewGroupItemsValid = TRUE; + listViewGroupItemsValid = FALSE; break; } } - if (listViewGroupItemsValid) + if (!listViewGroupItemsValid) { PhFree(listViewItems); break; @@ -788,7 +789,7 @@ INT_PTR CALLBACK PhpTokenPageProc( for (i = 0; i < numberOfItems; i++) { PPH_STRING privilegeName = NULL; - ULONG newAttributes; + ULONG newAttributes = listViewItems[i]->TokenPrivilege->Attributes; if (PhLookupPrivilegeName(&listViewItems[i]->TokenPrivilege->Luid, &privilegeName)) { @@ -798,10 +799,18 @@ INT_PTR CALLBACK PhpTokenPageProc( switch (GET_WM_COMMAND_ID(wParam, lParam)) { case ID_PRIVILEGE_ENABLE: - newAttributes = listViewItems[i]->TokenPrivilege->Attributes | SE_PRIVILEGE_ENABLED; + newAttributes |= SE_PRIVILEGE_ENABLED; break; case ID_PRIVILEGE_DISABLE: - newAttributes = listViewItems[i]->TokenPrivilege->Attributes & ~SE_PRIVILEGE_ENABLED; + newAttributes &= ~SE_PRIVILEGE_ENABLED; + break; + case ID_PRIVILEGE_RESET: + { + if (newAttributes & SE_PRIVILEGE_ENABLED_BY_DEFAULT) + newAttributes |= SE_PRIVILEGE_ENABLED; + else + newAttributes &= ~SE_PRIVILEGE_ENABLED; + } break; case ID_PRIVILEGE_REMOVE: newAttributes = SE_PRIVILEGE_REMOVED; @@ -852,6 +861,9 @@ INT_PTR CALLBACK PhpTokenPageProc( case ID_PRIVILEGE_DISABLE: action = L"disable"; break; + case ID_PRIVILEGE_RESET: + action = L"reset"; + break; case ID_PRIVILEGE_REMOVE: action = L"remove"; break; @@ -881,6 +893,135 @@ INT_PTR CALLBACK PhpTokenPageProc( ExtendedListView_SortItems(tokenPageContext->ListViewHandle); } break; + case ID_GROUP_ENABLE: + case ID_GROUP_DISABLE: + case ID_GROUP_RESET: + { + NTSTATUS status; + BOOLEAN listViewGroupItemsValid = TRUE; + PPHP_TOKEN_PAGE_LISTVIEW_ITEM *listViewItems; + ULONG numberOfItems; + HANDLE tokenHandle; + ULONG i; + + PhGetSelectedListViewItemParams( + tokenPageContext->ListViewHandle, + &listViewItems, + &numberOfItems + ); + + for (i = 0; i < numberOfItems; i++) + { + if (listViewItems[i]->ItemCategory != PH_PROCESS_TOKEN_CATEGORY_GROUPS) + { + listViewGroupItemsValid = FALSE; + break; + } + } + + if (!listViewGroupItemsValid) + { + PhFree(listViewItems); + break; + } + + status = tokenPageContext->OpenObject( + &tokenHandle, + TOKEN_ADJUST_GROUPS, + tokenPageContext->Context + ); + + if (NT_SUCCESS(status)) + { + ExtendedListView_SetRedraw(tokenPageContext->ListViewHandle, FALSE); + + for (i = 0; i < numberOfItems; i++) + { + ULONG newAttributes = listViewItems[i]->TokenGroup->Attributes; + + switch (GET_WM_COMMAND_ID(wParam, lParam)) + { + case ID_GROUP_ENABLE: + newAttributes |= SE_GROUP_ENABLED; + break; + case ID_GROUP_DISABLE: + newAttributes &= ~SE_GROUP_ENABLED; + break; + case ID_GROUP_RESET: + { + if (newAttributes & SE_GROUP_ENABLED_BY_DEFAULT) + newAttributes |= SE_GROUP_ENABLED; + else + newAttributes &= ~SE_GROUP_ENABLED; + } + break; + } + + if (NT_SUCCESS(status = PhSetTokenGroups( + tokenHandle, + NULL, + listViewItems[i]->TokenGroup->Sid, + newAttributes + ))) + { + PPH_STRING attributesString = PhGetGroupAttributesString(newAttributes, FALSE); + INT lvItemIndex = PhFindListViewItemByParam( + tokenPageContext->ListViewHandle, + -1, + listViewItems[i] + ); + + // Refresh the status text (and background color). + listViewItems[i]->TokenGroup->Attributes = newAttributes; + PhSetListViewSubItem( + tokenPageContext->ListViewHandle, + lvItemIndex, + PH_PROCESS_TOKEN_INDEX_STATUS, + attributesString->Buffer + ); + PhDereferenceObject(attributesString); + } + else + { + PWSTR action = L"set"; + + switch (GET_WM_COMMAND_ID(wParam, lParam)) + { + case ID_GROUP_ENABLE: + action = L"enable"; + break; + case ID_GROUP_DISABLE: + action = L"disable"; + break; + case ID_GROUP_RESET: + action = L"reset"; + break; + } + + if (!PhShowContinueStatus( + hwndDlg, + PhaFormatString(L"Unable to %s %s.", action, L"group")->Buffer, + status, + 0 + )) + break; + } + } + + ExtendedListView_SetRedraw(tokenPageContext->ListViewHandle, TRUE); + + NtClose(tokenHandle); + } + else + { + PhShowStatus(hwndDlg, L"Unable to open the token.", status, 0); + } + + PhFree(listViewItems); + + ExtendedListView_SortItems(tokenPageContext->ListViewHandle); + } + break; case ID_PRIVILEGE_COPY: { PhCopyListView(tokenPageContext->ListViewHandle); @@ -1096,26 +1237,45 @@ INT_PTR CALLBACK PhpTokenPageProc( if (numberOfItems != 0) { - BOOLEAN listViewGroupItemsValid = FALSE; + BOOLEAN hasMixedCategories = FALSE; + PH_PROCESS_TOKEN_CATEGORY currentCategory = listviewItems[0]->ItemCategory; ULONG i; - for (i = 0; i < numberOfItems; i++) + for (i = 1; i < numberOfItems; i++) { - if (listviewItems[i]->IsTokenGroupEntry) + if (listviewItems[i]->ItemCategory != currentCategory) { - listViewGroupItemsValid = TRUE; + hasMixedCategories = TRUE; break; } } menu = PhCreateEMenu(); - if (!listViewGroupItemsValid) + + if (!hasMixedCategories) { - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_PRIVILEGE_ENABLE, L"&Enable", NULL, NULL), ULONG_MAX); - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_PRIVILEGE_DISABLE, L"&Disable", NULL, NULL), ULONG_MAX); - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_PRIVILEGE_REMOVE, L"&Remove", NULL, NULL), ULONG_MAX); - PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX); + switch (currentCategory) + { + case PH_PROCESS_TOKEN_CATEGORY_PRIVILEGES: + { + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_PRIVILEGE_ENABLE, L"&Enable", NULL, NULL), ULONG_MAX); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_PRIVILEGE_DISABLE, L"&Disable", NULL, NULL), ULONG_MAX); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_PRIVILEGE_RESET, L"Re&set", NULL, NULL), ULONG_MAX); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_PRIVILEGE_REMOVE, L"&Remove", NULL, NULL), ULONG_MAX); + PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX); + } + break; + case PH_PROCESS_TOKEN_CATEGORY_GROUPS: + { + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_GROUP_ENABLE, L"&Enable", NULL, NULL), ULONG_MAX); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_GROUP_DISABLE, L"&Disable", NULL, NULL), ULONG_MAX); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_GROUP_RESET, L"Re&set", NULL, NULL), ULONG_MAX); + PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX); + } + break; + } } + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_PRIVILEGE_COPY, L"&Copy", NULL, NULL), ULONG_MAX); PhShowEMenu( diff --git a/phlib/include/phnative.h b/phlib/include/phnative.h index 8988960acac7..67fff5528f50 100644 --- a/phlib/include/phnative.h +++ b/phlib/include/phnative.h @@ -440,7 +440,7 @@ PhSetTokenPrivilege2( ); PHLIBAPI -BOOLEAN +NTSTATUS NTAPI PhSetTokenGroups( _In_ HANDLE TokenHandle, diff --git a/phlib/native.c b/phlib/native.c index d39855534514..62da61e1903b 100644 --- a/phlib/native.c +++ b/phlib/native.c @@ -2213,7 +2213,17 @@ BOOLEAN PhSetTokenPrivilege2( return PhSetTokenPrivilege(TokenHandle, NULL, &privilegeLuid, Attributes); } -BOOLEAN PhSetTokenGroups( +/** +* Modifies a token group. +* +* \param TokenHandle A handle to a token. The handle must have TOKEN_ADJUST_GROUPS access. +* \param GroupName The name of the group to modify. If this parameter is NULL, you must +* specify a PSID in the \a GroupSid parameter. +* \param GroupSid The PSID of the group to modify. If this parameter is NULL, you must +* specify a group name in the \a GroupName parameter. +* \param Attributes The new attributes of the group. +*/ +NTSTATUS PhSetTokenGroups( _In_ HANDLE TokenHandle, _In_opt_ PWSTR GroupName, _In_opt_ PSID GroupSid, @@ -2237,11 +2247,11 @@ BOOLEAN PhSetTokenGroups( PhInitializeStringRef(&groupName, GroupName); if (!NT_SUCCESS(status = PhLookupName(&groupName, &groups.Groups[0].Sid, NULL, NULL))) - return FALSE; + return status; } else { - return FALSE; + return STATUS_INVALID_PARAMETER; } if (!NT_SUCCESS(status = NtAdjustGroupsToken( @@ -2262,13 +2272,13 @@ BOOLEAN PhSetTokenGroups( if (GroupName && groups.Groups[0].Sid) PhFree(groups.Groups[0].Sid); - return TRUE; + return status; CleanupExit: if (GroupName && groups.Groups[0].Sid) PhFree(groups.Groups[0].Sid); - return FALSE; + return status; } /** From 89bae4d07032581980aa2a32b2e4ef85e7da6a81 Mon Sep 17 00:00:00 2001 From: diversenok Date: Wed, 3 Oct 2018 11:24:47 +0300 Subject: [PATCH 1379/2058] Add SCM permissions menu (#327) --- ProcessHacker/ProcessHacker.rc | 1 + ProcessHacker/mainwnd.c | 30 ++++++++++++++++++++++++++++++ ProcessHacker/resource.h | 1 + phlib/secdata.c | 12 ++++++++++++ phlib/secedit.c | 4 ++-- 5 files changed, 46 insertions(+), 2 deletions(-) diff --git a/ProcessHacker/ProcessHacker.rc b/ProcessHacker/ProcessHacker.rc index 584f258c28e7..0aa6533369d1 100644 --- a/ProcessHacker/ProcessHacker.rc +++ b/ProcessHacker/ProcessHacker.rc @@ -138,6 +138,7 @@ BEGIN POPUP "&Tools" BEGIN MENUITEM "&Create service...", ID_TOOLS_CREATESERVICE + MENUITEM "Service Control per&missions",ID_TOOLS_SCM_PERMISSIONS MENUITEM "&Hidden processes", ID_TOOLS_HIDDENPROCESSES MENUITEM "Inspect e&xecutable file...", ID_TOOLS_INSPECTEXECUTABLEFILE MENUITEM "&Pagefiles", ID_TOOLS_PAGEFILES diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index f8b594b8cf3f..62fa66ec6a17 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -48,6 +48,7 @@ #include #include #include +#include #include #include #include @@ -567,6 +568,23 @@ VOID PhMwpOnSettingChange( SendMessage(TabControlHandle, WM_SETFONT, (WPARAM)PhApplicationFont, FALSE); } +static NTSTATUS PhpOpenSCM( + _Out_ PHANDLE Handle, + _In_ ACCESS_MASK DesiredAccess, + _In_opt_ PVOID Context + ) +{ + SC_HANDLE serviceHandle; + + if (serviceHandle = OpenSCManager(NULL, NULL, DesiredAccess)) + { + *Handle = serviceHandle; + return STATUS_SUCCESS; + } + + return PhGetLastWin32ErrorAsNtStatus(); +} + VOID PhMwpOnCommand( _In_ ULONG Id ) @@ -906,6 +924,18 @@ VOID PhMwpOnCommand( } } break; + case ID_TOOLS_SCM_PERMISSIONS: + { + PhEditSecurity( + PhMainWndHandle, + L"Service Control Manager", + L"SCManager", + PhpOpenSCM, + NULL, + NULL + ); + } + break; case ID_USER_CONNECT: { PhUiConnectSession(PhMainWndHandle, SelectedUserSessionId); diff --git a/ProcessHacker/resource.h b/ProcessHacker/resource.h index 9370d93ec9ad..a824fb4f1b83 100644 --- a/ProcessHacker/resource.h +++ b/ProcessHacker/resource.h @@ -745,6 +745,7 @@ #define ID_GROUP_ENABLE 40297 #define ID_GROUP_DISABLE 40298 #define ID_GROUP_RESET 40299 +#define ID_TOOLS_SCM_PERMISSIONS 40300 #define IDDYNAMIC 50000 #define IDPLUGINS 55000 diff --git a/phlib/secdata.c b/phlib/secdata.c index f0807e4d61ce..42d6d3966593 100644 --- a/phlib/secdata.c +++ b/phlib/secdata.c @@ -385,6 +385,17 @@ ACCESS_ENTRIES(Service) { L"User-defined control", SERVICE_USER_DEFINED_CONTROL, TRUE, TRUE } }; +ACCESS_ENTRIES(SCManager) +{ + { L"Full control", SC_MANAGER_ALL_ACCESS, TRUE, TRUE }, + { L"Create service", SC_MANAGER_CREATE_SERVICE, TRUE, TRUE }, + { L"Connect", SC_MANAGER_CONNECT, TRUE, TRUE }, + { L"Enumerate services", SC_MANAGER_ENUMERATE_SERVICE, TRUE, TRUE }, + { L"Lock", SC_MANAGER_LOCK, TRUE, TRUE }, + { L"Modify boot config", SC_MANAGER_MODIFY_BOOT_CONFIG, TRUE, TRUE }, + { L"Query lock status", SC_MANAGER_QUERY_LOCK_STATUS, TRUE, TRUE } +}; + ACCESS_ENTRIES(Session) { { L"Full control", SESSION_ALL_ACCESS, TRUE, TRUE }, @@ -603,6 +614,7 @@ static PH_SPECIFIC_TYPE PhSpecificTypes[] = ACCESS_ENTRY(Section, FALSE), ACCESS_ENTRY(Semaphore, TRUE), ACCESS_ENTRY(Service, FALSE), + ACCESS_ENTRY(SCManager, FALSE), ACCESS_ENTRY(Session, FALSE), ACCESS_ENTRY(SymbolicLink, FALSE), ACCESS_ENTRY(Thread, TRUE), diff --git a/phlib/secedit.c b/phlib/secedit.c index 65bcdd8af0d3..e722e32c07af 100644 --- a/phlib/secedit.c +++ b/phlib/secedit.c @@ -743,7 +743,7 @@ _Callback_ NTSTATUS PhStdGetObjectSecurity( if (!NT_SUCCESS(status)) return status; - if (PhEqualString2(this->ObjectType, L"Service", TRUE)) + if (PhEqualString2(this->ObjectType, L"Service", TRUE) || PhEqualString2(this->ObjectType, L"SCManager", TRUE)) { status = PhGetSeObjectSecurity(handle, SE_SERVICE, SecurityInformation, SecurityDescriptor); CloseServiceHandle(handle); @@ -875,7 +875,7 @@ _Callback_ NTSTATUS PhStdSetObjectSecurity( if (!NT_SUCCESS(status)) return status; - if (PhEqualString2(this->ObjectType, L"Service", TRUE)) + if (PhEqualString2(this->ObjectType, L"Service", TRUE) || PhEqualString2(this->ObjectType, L"SCManager", TRUE)) { status = PhSetSeObjectSecurity(handle, SE_SERVICE, SecurityInformation, SecurityDescriptor); CloseServiceHandle(handle); From 23f204dd5cef6fbe447adfeebfe4244a843ee678 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 3 Oct 2018 18:43:55 +1000 Subject: [PATCH 1380/2058] Remove unused code from PhSetTokenGroups #326 --- phlib/native.c | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/phlib/native.c b/phlib/native.c index 62da61e1903b..1f7e2b921991 100644 --- a/phlib/native.c +++ b/phlib/native.c @@ -2254,27 +2254,15 @@ NTSTATUS PhSetTokenGroups( return STATUS_INVALID_PARAMETER; } - if (!NT_SUCCESS(status = NtAdjustGroupsToken( + status = NtAdjustGroupsToken( TokenHandle, FALSE, &groups, 0, NULL, NULL - ))) - { - goto CleanupExit; - } - - if (status == STATUS_NOT_ALL_ASSIGNED) - goto CleanupExit; - - if (GroupName && groups.Groups[0].Sid) - PhFree(groups.Groups[0].Sid); - - return status; + ); -CleanupExit: if (GroupName && groups.Groups[0].Sid) PhFree(groups.Groups[0].Sid); From 75d5111347818eb7d9bf26f2c893e0bbaf0a5150 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 3 Oct 2018 18:46:11 +1000 Subject: [PATCH 1381/2058] Tidy up #327 --- ProcessHacker/ProcessHacker.rc | 5 ++++- ProcessHacker/mainwnd.c | 6 +++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/ProcessHacker/ProcessHacker.rc b/ProcessHacker/ProcessHacker.rc index 0aa6533369d1..b7230f03ff15 100644 --- a/ProcessHacker/ProcessHacker.rc +++ b/ProcessHacker/ProcessHacker.rc @@ -138,11 +138,14 @@ BEGIN POPUP "&Tools" BEGIN MENUITEM "&Create service...", ID_TOOLS_CREATESERVICE - MENUITEM "Service Control per&missions",ID_TOOLS_SCM_PERMISSIONS MENUITEM "&Hidden processes", ID_TOOLS_HIDDENPROCESSES MENUITEM "Inspect e&xecutable file...", ID_TOOLS_INSPECTEXECUTABLEFILE MENUITEM "&Pagefiles", ID_TOOLS_PAGEFILES MENUITEM "Start &Task Manager", ID_TOOLS_STARTTASKMANAGER + POPUP "&Permissions" + BEGIN + MENUITEM "Service Control Manager", ID_TOOLS_SCM_PERMISSIONS + END END POPUP "&Users" BEGIN diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index 62fa66ec6a17..18c9efa23986 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -568,7 +568,7 @@ VOID PhMwpOnSettingChange( SendMessage(TabControlHandle, WM_SETFONT, (WPARAM)PhApplicationFont, FALSE); } -static NTSTATUS PhpOpenSCM( +static NTSTATUS PhpOpenServiceControlManager( _Out_ PHANDLE Handle, _In_ ACCESS_MASK DesiredAccess, _In_opt_ PVOID Context @@ -927,10 +927,10 @@ VOID PhMwpOnCommand( case ID_TOOLS_SCM_PERMISSIONS: { PhEditSecurity( - PhMainWndHandle, + NULL, L"Service Control Manager", L"SCManager", - PhpOpenSCM, + PhpOpenServiceControlManager, NULL, NULL ); From 55db5745cc1c36c517b599a891f56ca0d7e2df92 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 3 Oct 2018 18:48:58 +1000 Subject: [PATCH 1382/2058] Add workaround for #320 --- ProcessHacker/main.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/ProcessHacker/main.c b/ProcessHacker/main.c index cceb06929279..eb644cf03fa8 100644 --- a/ProcessHacker/main.c +++ b/ProcessHacker/main.c @@ -670,7 +670,8 @@ BOOLEAN PhInitializeMitigationPolicy( PROCESS_CREATION_MITIGATION_POLICY_IMAGE_LOAD_NO_REMOTE_ALWAYS_ON | \ PROCESS_CREATION_MITIGATION_POLICY_IMAGE_LOAD_NO_LOW_LABEL_ALWAYS_ON) - static PH_STRINGREF commandlinePart = PH_STRINGREF_INIT(L" -nomp"); + static PH_STRINGREF nompCommandlinePart = PH_STRINGREF_INIT(L" -nomp"); + static PH_STRINGREF rasCommandlinePart = PH_STRINGREF_INIT(L" -ras"); BOOLEAN success = TRUE; PH_STRINGREF commandlineSr; PPH_STRING commandline = NULL; @@ -683,7 +684,12 @@ BOOLEAN PhInitializeMitigationPolicy( PhUnicodeStringToStringRef(&NtCurrentPeb()->ProcessParameters->CommandLine, &commandlineSr); - if (PhEndsWithStringRef(&commandlineSr, &commandlinePart, FALSE)) + // NOTE: The SCM has a bug where calling CreateProcess with PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY to restart the service with mitigations + // causes the SCM to spew EVENT_SERVICE_DIFFERENT_PID_CONNECTED in the system eventlog and terminate the service. (dmex) + // WARN: This bug makes it impossible to start services with mitigation polices when the service doesn't have an IFEO key... + if (PhFindStringInStringRef(&commandlineSr, &rasCommandlinePart, FALSE) != -1) + return TRUE; + if (PhEndsWithStringRef(&commandlineSr, &nompCommandlinePart, FALSE)) return TRUE; if (!(LdrSystemDllInitBlock_I = PhGetDllProcedureAddress(L"ntdll.dll", "LdrSystemDllInitBlock", 0))) @@ -706,7 +712,7 @@ BOOLEAN PhInitializeMitigationPolicy( if (!UpdateProcThreadAttribute(startupInfo.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY, &(ULONG64){ DEFAULT_MITIGATION_POLICY_FLAGS }, sizeof(ULONG64), NULL, NULL)) goto CleanupExit; - commandline = PhConcatStringRef2(&commandlineSr, &commandlinePart); + commandline = PhConcatStringRef2(&commandlineSr, &nompCommandlinePart); if (NT_SUCCESS(PhCreateProcessWin32Ex( NULL, From 3fd1ee8bd4d0cedcc5a7e7ad26bc78dbb62d4887 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 3 Oct 2018 18:54:18 +1000 Subject: [PATCH 1383/2058] Add Win10 1809 (RS5) support --- ProcessHacker/appsup.c | 13 ++++++++++- phlib/global.c | 5 ++++- phlib/kphdata.c | 4 ++++ phnt/include/ntexapi.h | 13 ++++++++++- phnt/include/ntpsapi.h | 51 ++++++++++++++++++++++++++++++++++++++++-- phnt/include/ntrtl.h | 2 +- phnt/include/phnt.h | 1 + 7 files changed, 83 insertions(+), 6 deletions(-) diff --git a/ProcessHacker/appsup.c b/ProcessHacker/appsup.c index 6875875f76a9..dadbad516034 100644 --- a/ProcessHacker/appsup.c +++ b/ProcessHacker/appsup.c @@ -177,7 +177,18 @@ NTSTATUS PhGetProcessSwitchContext( if (!data) return STATUS_UNSUCCESSFUL; // no compatibility context data - if (WindowsVersion >= WINDOWS_10_RS2) + if (WindowsVersion >= WINDOWS_10_RS5) + { + if (!NT_SUCCESS(status = NtReadVirtualMemory( + ProcessHandle, + PTR_ADD_OFFSET(data, 2040 + 24), // Magic value from SbReadProcContextByHandle + Guid, + sizeof(GUID), + NULL + ))) + return status; + } + else if (WindowsVersion >= WINDOWS_10_RS2) { if (!NT_SUCCESS(status = NtReadVirtualMemory( ProcessHandle, diff --git a/phlib/global.c b/phlib/global.c index 5ee59077ea5c..35e28696be05 100644 --- a/phlib/global.c +++ b/phlib/global.c @@ -196,8 +196,11 @@ VOID PhInitializeWindowsVersion( case 17134: WindowsVersion = WINDOWS_10_RS4; break; + case 17763: + WindowsVersion = WINDOWS_10_RS5; + break; default: - WindowsVersion = buildVersion > 17134 ? WINDOWS_10_RS5 : WINDOWS_10; + WindowsVersion = buildVersion > 17763 ? WINDOWS_10_RS5 : WINDOWS_10; break; } } diff --git a/phlib/kphdata.c b/phlib/kphdata.c index 924d1f7a3c27..836d2ad72c88 100644 --- a/phlib/kphdata.c +++ b/phlib/kphdata.c @@ -153,6 +153,10 @@ NTSTATUS KphInitializeDynamicPackage( Package->BuildNumber = 17134; Package->ResultingNtVersion = PHNT_REDSTONE4; break; + case 17763: + Package->BuildNumber = 17763; + Package->ResultingNtVersion = PHNT_REDSTONE5; + break; default: Package->BuildNumber = USHRT_MAX; Package->ResultingNtVersion = PHNT_THRESHOLD; diff --git a/phnt/include/ntexapi.h b/phnt/include/ntexapi.h index 7a793240c52a..d79ae48eca0d 100644 --- a/phnt/include/ntexapi.h +++ b/phnt/include/ntexapi.h @@ -1442,6 +1442,10 @@ typedef enum _SYSTEM_INFORMATION_CLASS SystemSpeculationControlInformation, // SYSTEM_SPECULATION_CONTROL_INFORMATION // (CVE-2017-5715) REDSTONE3 and above. SystemDmaGuardPolicyInformation, // SYSTEM_DMA_GUARD_POLICY_INFORMATION SystemEnclaveLaunchControlInformation, // SYSTEM_ENCLAVE_LAUNCH_CONTROL_INFORMATION + SystemWorkloadAllowedCpuSetsInformation, // SYSTEM_WORKLOAD_ALLOWED_CPU_SET_INFORMATION // since REDSTONE5 + SystemCodeIntegrityUnlockModeInformation, + SystemLeapSecondInformation, // SYSTEM_LEAP_SECOND_INFORMATION + SystemFlags2Information, MaxSystemInfoClass } SYSTEM_INFORMATION_CLASS; @@ -2824,7 +2828,7 @@ typedef struct _PROCESS_ENERGY_VALUES_EXTENSION { union { - TIMELINE_BITMAP Timelines[14]; // 9 for REDSTONE2, 14 for REDSTONE3 + TIMELINE_BITMAP Timelines[14]; // 9 for REDSTONE2, 14 for REDSTONE3/4/5 struct { TIMELINE_BITMAP CpuTimeline; @@ -3249,6 +3253,13 @@ typedef struct _SYSTEM_ENCLAVE_LAUNCH_CONTROL_INFORMATION UCHAR EnclaveLaunchSigner[32]; } SYSTEM_ENCLAVE_LAUNCH_CONTROL_INFORMATION, *PSYSTEM_ENCLAVE_LAUNCH_CONTROL_INFORMATION; +// private +typedef struct _SYSTEM_WORKLOAD_ALLOWED_CPU_SET_INFORMATION +{ + ULONGLONG WorkloadClass; + ULONGLONG CpuSets[1]; +} SYSTEM_WORKLOAD_ALLOWED_CPU_SET_INFORMATION, *PSYSTEM_WORKLOAD_ALLOWED_CPU_SET_INFORMATION; + #if (PHNT_MODE != PHNT_MODE_KERNEL) NTSYSCALLAPI diff --git a/phnt/include/ntpsapi.h b/phnt/include/ntpsapi.h index 7b41008284ae..87b7f721ab8a 100644 --- a/phnt/include/ntpsapi.h +++ b/phnt/include/ntpsapi.h @@ -177,7 +177,7 @@ typedef enum _PROCESSINFOCLASS ProcessActivityThrottleState, // PROCESS_ACTIVITY_THROTTLE_STATE ProcessActivityThrottlePolicy, // PROCESS_ACTIVITY_THROTTLE_POLICY ProcessWin32kSyscallFilterInformation, - ProcessDisableSystemAllowedCpuSets, + ProcessDisableSystemAllowedCpuSets, // 80 ProcessWakeInformation, // PROCESS_WAKE_INFORMATION ProcessEnergyTrackingState, // PROCESS_ENERGY_TRACKING_STATE ProcessManageWritesToExecutableMemory, // MANAGE_WRITES_TO_EXECUTABLE_MEMORY // since REDSTONE3 @@ -187,9 +187,14 @@ typedef enum _PROCESSINFOCLASS ProcessEnableReadWriteVmLogging, // PROCESS_READWRITEVM_LOGGING_INFORMATION ProcessUptimeInformation, // PROCESS_UPTIME_INFORMATION ProcessImageSection, - ProcessDebugAuthInformation, // since REDSTONE4 + ProcessDebugAuthInformation, // since REDSTONE4 // 90 ProcessSystemResourceManagement, // PROCESS_SYSTEM_RESOURCE_MANAGEMENT ProcessSequenceNumber, // q: ULONGLONG + ProcessLoaderDetour, // since REDSTONE5 + ProcessSecurityDomainInformation, // PROCESS_SECURITY_DOMAIN_INFORMATION + ProcessCombineSecurityDomainsInformation, // PROCESS_COMBINE_SECURITY_DOMAINS_INFORMATION + ProcessEnableLogging, // PROCESS_LOGGING_INFORMATION + ProcessLeapSecondInformation, // PROCESS_LEAP_SECOND_INFORMATION MaxProcessInfoClass } PROCESSINFOCLASS; #endif @@ -247,6 +252,7 @@ typedef enum _THREADINFOCLASS ThreadAttachContainer, ThreadManageWritesToExecutableMemory, // MANAGE_WRITES_TO_EXECUTABLE_MEMORY // since REDSTONE3 ThreadPowerThrottlingState, // THREAD_POWER_THROTTLING_STATE + ThreadWorkloadClass, // THREAD_WORKLOAD_CLASS // since REDSTONE5 // 50 MaxThreadInfoClass } THREADINFOCLASS; #endif @@ -850,6 +856,39 @@ typedef union _PROCESS_SYSTEM_RESOURCE_MANAGEMENT }; } PROCESS_SYSTEM_RESOURCE_MANAGEMENT, *PPROCESS_SYSTEM_RESOURCE_MANAGEMENT; +// private +typedef struct _PROCESS_SECURITY_DOMAIN_INFORMATION +{ + ULONGLONG SecurityDomain; +} PROCESS_SECURITY_DOMAIN_INFORMATION, *PPROCESS_SECURITY_DOMAIN_INFORMATION; + +// private +typedef struct _PROCESS_COMBINE_SECURITY_DOMAINS_INFORMATION +{ + HANDLE ProcessHandle; +} PROCESS_COMBINE_SECURITY_DOMAINS_INFORMATION, *PPROCESS_COMBINE_SECURITY_DOMAINS_INFORMATION; + +// private +typedef struct _PROCESS_LOGGING_INFORMATION +{ + ULONG Flags; + struct + { + ULONG EnableReadVmLogging : 1; + ULONG EnableWriteVmLogging : 1; + ULONG EnableProcessSuspendResumeLogging : 1; + ULONG EnableThreadSuspendResumeLogging : 1; + ULONG Reserved : 28; + }; +} PROCESS_LOGGING_INFORMATION, *PPROCESS_LOGGING_INFORMATION; + +// private +typedef struct _PROCESS_LEAP_SECOND_INFORMATION +{ + ULONG Flags; + ULONG Reserved; +} PROCESS_LEAP_SECOND_INFORMATION, *PPROCESS_LEAP_SECOND_INFORMATION; + // end_private #endif @@ -997,6 +1036,14 @@ typedef enum _SUBSYSTEM_INFORMATION_TYPE } SUBSYSTEM_INFORMATION_TYPE; #endif +// private +typedef enum _THREAD_WORKLOAD_CLASS +{ + ThreadWorkloadClassDefault, + ThreadWorkloadClassGraphics, + MaxThreadWorkloadClass +} THREAD_WORKLOAD_CLASS; + // Processes #if (PHNT_MODE != PHNT_MODE_KERNEL) diff --git a/phnt/include/ntrtl.h b/phnt/include/ntrtl.h index 555d6d50f119..0c232022a6b8 100644 --- a/phnt/include/ntrtl.h +++ b/phnt/include/ntrtl.h @@ -3277,7 +3277,7 @@ NTAPI RtlSetEnvironmentVariable( _In_opt_ PVOID *Environment, _In_ PUNICODE_STRING Name, - _In_ PUNICODE_STRING Value + _In_opt_ PUNICODE_STRING Value ); #if (PHNT_VERSION >= PHNT_VISTA) diff --git a/phnt/include/phnt.h b/phnt/include/phnt.h index f3412176e1a1..677c784ef54e 100644 --- a/phnt/include/phnt.h +++ b/phnt/include/phnt.h @@ -37,6 +37,7 @@ #define PHNT_REDSTONE2 103 #define PHNT_REDSTONE3 104 #define PHNT_REDSTONE4 105 +#define PHNT_REDSTONE5 106 #ifndef PHNT_MODE #define PHNT_MODE PHNT_MODE_USER From 33c989d333c877aea60838aebfae7774b1c3314f Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 4 Oct 2018 12:38:41 +1000 Subject: [PATCH 1384/2058] Implement support for changing process 'default token' security entires --- phlib/secedit.c | 36 +++++++++++++++++++++++++++++++----- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/phlib/secedit.c b/phlib/secedit.c index e722e32c07af..55930bcacfcf 100644 --- a/phlib/secedit.c +++ b/phlib/secedit.c @@ -821,7 +821,8 @@ _Callback_ NTSTATUS PhStdGetObjectSecurity( PSECURITY_DESCRIPTOR securityDescriptor; PTOKEN_OWNER tokenOwner; - securityDescriptor = PhAllocateZero(SECURITY_DESCRIPTOR_MIN_LENGTH); + // Note: We should enumerate the DefaultDacl entires to calculate the length but it's easier to use PAGE_SIZE. (dmex) + securityDescriptor = PhAllocateZero(PAGE_SIZE); RtlCreateSecurityDescriptor(securityDescriptor, SECURITY_DESCRIPTOR_REVISION); RtlSetDaclSecurityDescriptor(securityDescriptor, TRUE, defaultDacl->DefaultDacl, FALSE); @@ -906,14 +907,39 @@ _Callback_ NTSTATUS PhStdSetObjectSecurity( //status = SamSetSecurityObject( // handle, // SecurityInformation, - // SecurityDescriptor - // ); + // SecurityDescriptor + // ); // //SamCloseHandle(handle); } - else if (PhEqualString2(this->ObjectType, L"TokenDefault", TRUE)) + else if (PhEqualString2(this->ObjectType, L"TokenDefault", TRUE)) // HACK: Fake non-system type (dmex) { - // TODO + BOOLEAN present = FALSE; + BOOLEAN defaulted = FALSE; + PACL dacl = NULL; + + status = RtlGetDaclSecurityDescriptor( + SecurityDescriptor, + &present, + &dacl, + &defaulted + ); + + if (NT_SUCCESS(status)) + { + TOKEN_DEFAULT_DACL defaultDacl; + + defaultDacl.DefaultDacl = dacl; + + status = NtSetInformationToken( + handle, + TokenDefaultDacl, + &defaultDacl, + sizeof(TOKEN_DEFAULT_DACL) + ); + } + + NtClose(handle); } else { From 7ac8c2a0d1ba5daed3b2190d7a81d288fb49248b Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 4 Oct 2018 12:40:14 +1000 Subject: [PATCH 1385/2058] Update to latest WinSDK --- ProcessHacker/ProcessHacker.vcxproj | 2 +- phlib/phlib.vcxproj | 2 +- plugins/DotNetTools/DotNetTools.vcxproj | 2 +- plugins/ExtendedNotifications/ExtendedNotifications.vcxproj | 2 +- plugins/ExtendedServices/ExtendedServices.vcxproj | 2 +- plugins/ExtendedTools/ExtendedTools.vcxproj | 2 +- plugins/HardwareDevices/HardwareDevices.vcxproj | 2 +- plugins/NetworkTools/NetworkTools.vcxproj | 2 +- plugins/OnlineChecks/OnlineChecks.vcxproj | 2 +- plugins/ToolStatus/ToolStatus.vcxproj | 2 +- plugins/Updater/Updater.vcxproj | 2 +- plugins/UserNotes/UserNotes.vcxproj | 2 +- plugins/WindowExplorer/WindowExplorer.vcxproj | 2 +- tools/peview/peview.vcxproj | 2 +- 14 files changed, 14 insertions(+), 14 deletions(-) diff --git a/ProcessHacker/ProcessHacker.vcxproj b/ProcessHacker/ProcessHacker.vcxproj index 4a4afd7750bd..7d6bb999e400 100644 --- a/ProcessHacker/ProcessHacker.vcxproj +++ b/ProcessHacker/ProcessHacker.vcxproj @@ -22,7 +22,7 @@ {0271DD27-6707-4290-8DFE-285702B7115D} ProcessHacker Win32Proj - 10.0.17134.0 + 10.0.17763.0 diff --git a/phlib/phlib.vcxproj b/phlib/phlib.vcxproj index bb62d0be9420..40147221b2be 100644 --- a/phlib/phlib.vcxproj +++ b/phlib/phlib.vcxproj @@ -22,7 +22,7 @@ {477D0215-F252-41A1-874B-F27E3EA1ED17} phlib Win32Proj - 10.0.17134.0 + 10.0.17763.0 diff --git a/plugins/DotNetTools/DotNetTools.vcxproj b/plugins/DotNetTools/DotNetTools.vcxproj index 7b5daab17c0c..66df5200d23f 100644 --- a/plugins/DotNetTools/DotNetTools.vcxproj +++ b/plugins/DotNetTools/DotNetTools.vcxproj @@ -23,7 +23,7 @@ DotNetTools Win32Proj DotNetTools - 10.0.17134.0 + 10.0.17763.0 diff --git a/plugins/ExtendedNotifications/ExtendedNotifications.vcxproj b/plugins/ExtendedNotifications/ExtendedNotifications.vcxproj index efc911ed6ee4..41fdf7c61cdd 100644 --- a/plugins/ExtendedNotifications/ExtendedNotifications.vcxproj +++ b/plugins/ExtendedNotifications/ExtendedNotifications.vcxproj @@ -23,7 +23,7 @@ ExtendedNotifications Win32Proj ExtendedNotifications - 10.0.17134.0 + 10.0.17763.0 diff --git a/plugins/ExtendedServices/ExtendedServices.vcxproj b/plugins/ExtendedServices/ExtendedServices.vcxproj index 4d3e69179c81..073a89063451 100644 --- a/plugins/ExtendedServices/ExtendedServices.vcxproj +++ b/plugins/ExtendedServices/ExtendedServices.vcxproj @@ -23,7 +23,7 @@ ExtendedServices Win32Proj ExtendedServices - 10.0.17134.0 + 10.0.17763.0 diff --git a/plugins/ExtendedTools/ExtendedTools.vcxproj b/plugins/ExtendedTools/ExtendedTools.vcxproj index 9fd33f94cc8f..72d6713a4085 100644 --- a/plugins/ExtendedTools/ExtendedTools.vcxproj +++ b/plugins/ExtendedTools/ExtendedTools.vcxproj @@ -23,7 +23,7 @@ ExtendedTools Win32Proj ExtendedTools - 10.0.17134.0 + 10.0.17763.0 diff --git a/plugins/HardwareDevices/HardwareDevices.vcxproj b/plugins/HardwareDevices/HardwareDevices.vcxproj index a606468d867c..39b3efefb8ba 100644 --- a/plugins/HardwareDevices/HardwareDevices.vcxproj +++ b/plugins/HardwareDevices/HardwareDevices.vcxproj @@ -23,7 +23,7 @@ HardwareDevices Win32Proj HardwareDevices - 10.0.17134.0 + 10.0.17763.0 diff --git a/plugins/NetworkTools/NetworkTools.vcxproj b/plugins/NetworkTools/NetworkTools.vcxproj index 9e81f5632366..00a63496d21a 100644 --- a/plugins/NetworkTools/NetworkTools.vcxproj +++ b/plugins/NetworkTools/NetworkTools.vcxproj @@ -23,7 +23,7 @@ NetworkTools Win32Proj NetworkTools - 10.0.17134.0 + 10.0.17763.0 diff --git a/plugins/OnlineChecks/OnlineChecks.vcxproj b/plugins/OnlineChecks/OnlineChecks.vcxproj index ef6144e5ac96..ce8e88b3d4c2 100644 --- a/plugins/OnlineChecks/OnlineChecks.vcxproj +++ b/plugins/OnlineChecks/OnlineChecks.vcxproj @@ -23,7 +23,7 @@ OnlineChecks Win32Proj OnlineChecks - 10.0.17134.0 + 10.0.17763.0 diff --git a/plugins/ToolStatus/ToolStatus.vcxproj b/plugins/ToolStatus/ToolStatus.vcxproj index b60b882c7f35..b31153c1de42 100644 --- a/plugins/ToolStatus/ToolStatus.vcxproj +++ b/plugins/ToolStatus/ToolStatus.vcxproj @@ -23,7 +23,7 @@ ToolStatus Win32Proj ToolStatus - 10.0.17134.0 + 10.0.17763.0 diff --git a/plugins/Updater/Updater.vcxproj b/plugins/Updater/Updater.vcxproj index c9e89da0b5b4..4434a44bdb14 100644 --- a/plugins/Updater/Updater.vcxproj +++ b/plugins/Updater/Updater.vcxproj @@ -23,7 +23,7 @@ Updater Win32Proj Updater - 10.0.17134.0 + 10.0.17763.0 diff --git a/plugins/UserNotes/UserNotes.vcxproj b/plugins/UserNotes/UserNotes.vcxproj index ee6737ebeea7..72732b329e56 100644 --- a/plugins/UserNotes/UserNotes.vcxproj +++ b/plugins/UserNotes/UserNotes.vcxproj @@ -23,7 +23,7 @@ UserNotes Win32Proj UserNotes - 10.0.17134.0 + 10.0.17763.0 diff --git a/plugins/WindowExplorer/WindowExplorer.vcxproj b/plugins/WindowExplorer/WindowExplorer.vcxproj index 7389b4273fd7..422766289ee6 100644 --- a/plugins/WindowExplorer/WindowExplorer.vcxproj +++ b/plugins/WindowExplorer/WindowExplorer.vcxproj @@ -23,7 +23,7 @@ WindowExplorer Win32Proj WindowExplorer - 10.0.17134.0 + 10.0.17763.0 diff --git a/tools/peview/peview.vcxproj b/tools/peview/peview.vcxproj index 32f9c2deeec1..253070db6d5b 100644 --- a/tools/peview/peview.vcxproj +++ b/tools/peview/peview.vcxproj @@ -22,7 +22,7 @@ {72C124A2-3C80-41C6-ABA1-C4948B713204} peview Win32Proj - 10.0.17134.0 + 10.0.17763.0 From d9e9e27de219f15543aa9e7a6fe2b61c0e2b325e Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 4 Oct 2018 18:22:37 +1000 Subject: [PATCH 1386/2058] ExtendedTools: Update wswatch window (resizable, icons, persistent settings) --- plugins/ExtendedTools/ExtendedTools.rc | 6 +-- plugins/ExtendedTools/exttools.h | 3 ++ plugins/ExtendedTools/main.c | 5 ++- plugins/ExtendedTools/unldll.c | 4 +- plugins/ExtendedTools/wswatch.c | 58 ++++++++++++++++++-------- 5 files changed, 52 insertions(+), 24 deletions(-) diff --git a/plugins/ExtendedTools/ExtendedTools.rc b/plugins/ExtendedTools/ExtendedTools.rc index 10fe98326d29..0818d12882ee 100644 --- a/plugins/ExtendedTools/ExtendedTools.rc +++ b/plugins/ExtendedTools/ExtendedTools.rc @@ -154,7 +154,7 @@ BEGIN END IDD_WSWATCH DIALOGEX 0, 0, 325, 266 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +STYLE DS_SETFONT | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME CAPTION "WS Watch" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN @@ -162,8 +162,8 @@ BEGIN PUSHBUTTON "Enable",IDC_ENABLE,7,37,50,14 LTEXT "WS watch is enabled.",IDC_WSWATCHENABLED,63,40,119,8,NOT WS_VISIBLE LTEXT "Page faults:",IDC_STATIC,7,54,40,8 - CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,65,311,175 - DEFPUSHBUTTON "Close",IDOK,268,245,50,14 + CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,65,311,177 + DEFPUSHBUTTON "Close",IDOK,269,245,50,14 END IDD_SYSINFO_GPU DIALOGEX 0, 0, 315, 186 diff --git a/plugins/ExtendedTools/exttools.h b/plugins/ExtendedTools/exttools.h index bbc9b0659a48..227f066d59fb 100644 --- a/plugins/ExtendedTools/exttools.h +++ b/plugins/ExtendedTools/exttools.h @@ -32,6 +32,9 @@ extern HWND NetworkTreeNewHandle; #define SETTING_NAME_MODULE_SERVICES_WINDOW_SIZE (PLUGIN_NAME L".ModuleServiceWindowSize") #define SETTING_NAME_GPU_NODES_WINDOW_POSITION (PLUGIN_NAME L".GpuNodesWindowPosition") #define SETTING_NAME_GPU_NODES_WINDOW_SIZE (PLUGIN_NAME L".GpuNodesWindowSize") +#define SETTING_NAME_WSWATCH_WINDOW_POSITION (PLUGIN_NAME L".WsWatchWindowPosition") +#define SETTING_NAME_WSWATCH_WINDOW_SIZE (PLUGIN_NAME L".WsWatchWindowSize") +#define SETTING_NAME_WSWATCH_COLUMNS (PLUGIN_NAME L".WsWatchListColumns") // Window messages #define ET_WM_SHOWDIALOG (WM_APP + 1) diff --git a/plugins/ExtendedTools/main.c b/plugins/ExtendedTools/main.c index f7ecba22e6f3..20a018f12b17 100644 --- a/plugins/ExtendedTools/main.c +++ b/plugins/ExtendedTools/main.c @@ -100,7 +100,7 @@ VOID NTAPI MenuItemCallback( break; case ID_PROCESS_WSWATCH: { - EtShowWsWatchDialog(PhMainWndHandle, menuItem->Context); + EtShowWsWatchDialog(menuItem->OwnerWindow, menuItem->Context); } break; case ID_THREAD_CANCELIO: @@ -508,6 +508,9 @@ LOGICAL DllMain( { ScalableIntegerPairSettingType, SETTING_NAME_MODULE_SERVICES_WINDOW_SIZE, L"@96|850,490" }, { IntegerPairSettingType, SETTING_NAME_GPU_NODES_WINDOW_POSITION, L"0,0" }, { ScalableIntegerPairSettingType, SETTING_NAME_GPU_NODES_WINDOW_SIZE, L"@96|850,490" }, + { IntegerPairSettingType, SETTING_NAME_WSWATCH_WINDOW_POSITION, L"0,0" }, + { ScalableIntegerPairSettingType, SETTING_NAME_WSWATCH_WINDOW_SIZE, L"@96|325,266" }, + { StringSettingType, SETTING_NAME_WSWATCH_COLUMNS, L"" }, }; PluginInstance = PhRegisterPlugin(PLUGIN_NAME, Instance, &info); diff --git a/plugins/ExtendedTools/unldll.c b/plugins/ExtendedTools/unldll.c index 4bbe4aa9a268..86261ca2beba 100644 --- a/plugins/ExtendedTools/unldll.c +++ b/plugins/ExtendedTools/unldll.c @@ -330,8 +330,6 @@ INT_PTR CALLBACK EtpUnloadedDllsDlgProc( SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhInstanceHandle, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhInstanceHandle, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); - PhCenterWindow(hwndDlg, GetParent(hwndDlg)); - context->ListViewHandle = lvHandle = GetDlgItem(hwndDlg, IDC_LIST); PhSetListViewStyle(lvHandle, FALSE, TRUE); @@ -359,7 +357,7 @@ INT_PTR CALLBACK EtpUnloadedDllsDlgProc( if (PhGetIntegerPairSetting(SETTING_NAME_UNLOADED_WINDOW_POSITION).X != 0) PhLoadWindowPlacementFromSetting(SETTING_NAME_UNLOADED_WINDOW_POSITION, SETTING_NAME_UNLOADED_WINDOW_SIZE, hwndDlg); else - PhCenterWindow(hwndDlg, PhMainWndHandle); + PhCenterWindow(hwndDlg, PhMainWndHandle); // GetParent(hwndDlg) if (!NT_SUCCESS(status = EtpRefreshUnloadedDlls(hwndDlg, context))) { diff --git a/plugins/ExtendedTools/wswatch.c b/plugins/ExtendedTools/wswatch.c index 25d1df502cbf..26029ec1f2b1 100644 --- a/plugins/ExtendedTools/wswatch.c +++ b/plugins/ExtendedTools/wswatch.c @@ -3,6 +3,7 @@ * working set watch * * Copyright (C) 2011 wj32 + * Copyright (C) 2018 dmex * * This file is part of Process Hacker. * @@ -38,6 +39,8 @@ typedef struct _WS_WATCH_CONTEXT PVOID Buffer; ULONG BufferSize; + PH_LAYOUT_MANAGER LayoutManager; + PPH_SYMBOL_PROVIDER SymbolProvider; HANDLE LoadingSymbolsForProcessId; SINGLE_LIST_ENTRY ResultListHead; @@ -74,19 +77,17 @@ VOID EtShowWsWatchDialog( { PWS_WATCH_CONTEXT context; - context = PhAllocate(sizeof(WS_WATCH_CONTEXT)); - memset(context, 0, sizeof(WS_WATCH_CONTEXT)); + context = PhAllocateZero(sizeof(WS_WATCH_CONTEXT)); context->RefCount = 1; - context->ProcessItem = ProcessItem; + context->ProcessItem = PhReferenceObject(ProcessItem); DialogBoxParam( PluginInstance->DllBase, MAKEINTRESOURCE(IDD_WSWATCH), - ParentWindowHandle, + !!PhGetIntegerSetting(L"ForceNoParent") ? NULL : ParentWindowHandle, EtpWsWatchDlgProc, (LPARAM)context ); - EtpDereferenceWsWatchContext(context); } static VOID EtpReferenceWsWatchContext( @@ -125,6 +126,8 @@ static VOID EtpDereferenceWsWatchContext( PhReleaseQueuedLockExclusive(&Context->ResultListLock); + PhDereferenceObject(Context->ProcessItem); + PhFree(Context); } } @@ -199,7 +202,7 @@ static PPH_STRING EtpGetBasicSymbol( if (!fileName) { - symbol = PhCreateStringEx(NULL, PH_PTR_STR_LEN * 2); + symbol = PhCreateStringEx(NULL, PH_PTR_STR_LEN * sizeof(WCHAR)); PhPrintPointer(symbol->Buffer, (PVOID)Address); PhTrimToNullTerminatorString(symbol); } @@ -428,19 +431,28 @@ INT_PTR CALLBACK EtpWsWatchDlgProc( { case WM_INITDIALOG: { - HWND lvHandle; - - PhCenterWindow(hwndDlg, GetParent(hwndDlg)); + SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhInstanceHandle, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); + SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhInstanceHandle, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); context->WindowHandle = hwndDlg; - context->ListViewHandle = lvHandle = GetDlgItem(hwndDlg, IDC_LIST); - - PhSetListViewStyle(lvHandle, FALSE, TRUE); - PhSetControlTheme(lvHandle, L"explorer"); - PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 340, L"Instruction"); - PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 80, L"Count"); - PhSetExtendedListView(lvHandle); - ExtendedListView_SetSort(lvHandle, 1, DescendingSortOrder); + context->ListViewHandle = GetDlgItem(hwndDlg, IDC_LIST); + + PhSetListViewStyle(context->ListViewHandle, FALSE, TRUE); + PhSetControlTheme(context->ListViewHandle, L"explorer"); + PhAddListViewColumn(context->ListViewHandle, 0, 0, 0, LVCFMT_LEFT, 340, L"Instruction"); + PhAddListViewColumn(context->ListViewHandle, 1, 1, 1, LVCFMT_LEFT, 80, L"Count"); + PhSetExtendedListView(context->ListViewHandle); + PhLoadListViewColumnsFromSetting(SETTING_NAME_WSWATCH_COLUMNS, context->ListViewHandle); + ExtendedListView_SetSort(context->ListViewHandle, 1, DescendingSortOrder); + + PhInitializeLayoutManager(&context->LayoutManager, hwndDlg); + PhAddLayoutItem(&context->LayoutManager, context->ListViewHandle, NULL, PH_ANCHOR_ALL); + PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDOK), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); + + if (PhGetIntegerPairSetting(SETTING_NAME_WSWATCH_WINDOW_POSITION).X != 0) + PhLoadWindowPlacementFromSetting(SETTING_NAME_WSWATCH_WINDOW_POSITION, SETTING_NAME_WSWATCH_WINDOW_SIZE, hwndDlg); + else + PhCenterWindow(hwndDlg, GetParent(hwndDlg)); context->Hashtable = PhCreateSimpleHashtable(64); context->BufferSize = 0x2000; @@ -498,6 +510,9 @@ INT_PTR CALLBACK EtpWsWatchDlgProc( { context->Destroying = TRUE; + PhSaveListViewColumnsToSetting(SETTING_NAME_WSWATCH_COLUMNS, context->ListViewHandle); + PhSaveWindowPlacementToSetting(SETTING_NAME_WSWATCH_WINDOW_POSITION, SETTING_NAME_WSWATCH_WINDOW_SIZE, hwndDlg); + PhDereferenceObject(context->Hashtable); if (context->Buffer) @@ -505,6 +520,10 @@ INT_PTR CALLBACK EtpWsWatchDlgProc( PhFree(context->Buffer); context->Buffer = NULL; } + + PhDeleteLayoutManager(&context->LayoutManager); + + EtpDereferenceWsWatchContext(context); } break; case WM_COMMAND: @@ -555,6 +574,11 @@ INT_PTR CALLBACK EtpWsWatchDlgProc( PhHandleListViewNotifyForCopy(lParam, context->ListViewHandle); } break; + case WM_SIZE: + { + PhLayoutManagerLayout(&context->LayoutManager); + } + break; case WM_TIMER: { switch (wParam) From 31126ddeb96fbf3b8109fa5c0de991f1da7e648d Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 4 Oct 2018 19:18:28 +1000 Subject: [PATCH 1387/2058] Add workaround for threads remaining suspended when closing thread stack dialog --- ProcessHacker/thrdstk.c | 34 +++++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/ProcessHacker/thrdstk.c b/ProcessHacker/thrdstk.c index 7659a4f9a70a..d72f50559c9a 100644 --- a/ProcessHacker/thrdstk.c +++ b/ProcessHacker/thrdstk.c @@ -261,9 +261,12 @@ VOID DestroyThreadStackNode( _In_ PPH_STACK_TREE_ROOT_NODE Node ) { - PhClearReference(&Node->TooltipText); - PhClearReference(&Node->IndexString); - PhClearReference(&Node->SymbolString); + if (Node->TooltipText) + PhDereferenceObject(Node->TooltipText); + if (Node->IndexString) + PhDereferenceObject(Node->IndexString); + if (Node->SymbolString) + PhDereferenceObject(Node->SymbolString); PhDereferenceObject(Node); } @@ -849,6 +852,13 @@ INT_PTR CALLBACK PhpThreadStackDlgProc( { context->StopWalk = TRUE; + // HACK HACK HACK + // PhWalkThreadStack will suspend the thread before walking the stack and download symbols but + // we don't wait for the stack walk / symbol downloading to complete when the user closes the progress dialog + // and so the thread can remain suspended for a long time (in some cases)... For now just resume the thread + // when closing the dialog since those results will be discarded and PhWalkThreadStack will cleanup whenever it completes. (dmex) + NtResumeThread(context->ThreadHandle, NULL); + DeleteThreadStackTree(context); PhDeleteLayoutManager(&context->LayoutManager); @@ -1141,10 +1151,13 @@ VOID PhpSymbolProviderEventCallbackHandler( case CBA_SYMBOLS_UNLOADED: { PIMAGEHLP_DEFERRED_SYMBOL_LOADW64 callbackData = (PIMAGEHLP_DEFERRED_SYMBOL_LOADW64)event->EventData; - PPH_STRING fileName; + PPH_STRING fileName = NULL; - fileName = PhCreateString(callbackData->FileName); - PhMoveReference(&fileName, PhGetBaseName(fileName)); + if (callbackData->FileName[0] != UNICODE_NULL) + { + fileName = PhCreateString(callbackData->FileName); + PhMoveReference(&fileName, PhGetBaseName(fileName)); + } switch (event->ActionCode) { @@ -1161,6 +1174,9 @@ VOID PhpSymbolProviderEventCallbackHandler( statusMessage = PhFormatString(L"Unloading %s...", PhGetStringOrEmpty(fileName)); break; } + + if (fileName) + PhDereferenceObject(fileName); } break; case CBA_READ_MEMORY: @@ -1314,7 +1330,7 @@ BOOLEAN PhpShowThreadStackWindow( config.pszContent = L" "; config.cxWidth = 200; - return SUCCEEDED(TaskDialogIndirect(&config, &result, NULL, NULL)) && result == IDOK; + return SUCCEEDED(TaskDialogIndirect(&config, &result, NULL, NULL)) && result != IDCANCEL; } static NTSTATUS PhpRefreshThreadStack( @@ -1327,9 +1343,9 @@ static NTSTATUS PhpRefreshThreadStack( Context->StopWalk = FALSE; PhMoveReference(&Context->StatusMessage, PhCreateString(L"Processing stack frames...")); - if (PhpShowThreadStackWindow(Context)) + if (!PhpShowThreadStackWindow(Context)) { - + return STATUS_ABANDONED; } if (!Context->StopWalk && NT_SUCCESS(Context->WalkStatus)) From 45c3a7f00177a0b9cc39c7ee42f841844e64595c Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 5 Oct 2018 09:47:21 +1000 Subject: [PATCH 1388/2058] Improve TokenDefaultDacl buffer allocations --- phlib/secedit.c | 46 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 36 insertions(+), 10 deletions(-) diff --git a/phlib/secedit.c b/phlib/secedit.c index 55930bcacfcf..2a179754818c 100644 --- a/phlib/secedit.c +++ b/phlib/secedit.c @@ -818,21 +818,47 @@ _Callback_ NTSTATUS PhStdGetObjectSecurity( if (NT_SUCCESS(status)) { - PSECURITY_DESCRIPTOR securityDescriptor; - PTOKEN_OWNER tokenOwner; + ACL_SIZE_INFORMATION aclSizeInfo; - // Note: We should enumerate the DefaultDacl entires to calculate the length but it's easier to use PAGE_SIZE. (dmex) - securityDescriptor = PhAllocateZero(PAGE_SIZE); - RtlCreateSecurityDescriptor(securityDescriptor, SECURITY_DESCRIPTOR_REVISION); - RtlSetDaclSecurityDescriptor(securityDescriptor, TRUE, defaultDacl->DefaultDacl, FALSE); + status = RtlQueryInformationAcl( + defaultDacl->DefaultDacl, + &aclSizeInfo, + sizeof(ACL_SIZE_INFORMATION), + AclSizeInformation + ); - if (NT_SUCCESS(PhGetTokenOwner(handle, &tokenOwner))) + if (NT_SUCCESS(status)) { - RtlSetOwnerSecurityDescriptor(securityDescriptor, tokenOwner->Owner, FALSE); - PhFree(tokenOwner); + ULONG allocationLength; + PSECURITY_DESCRIPTOR securityDescriptor; + PTOKEN_OWNER tokenOwner; + PSID tokenOwnerSid = NULL; + + if (NT_SUCCESS(PhGetTokenOwner(handle, &tokenOwner))) + { + tokenOwnerSid = PhAllocateCopy(tokenOwner->Owner, RtlLengthSid(tokenOwner->Owner)); + PhFree(tokenOwner); + } + + allocationLength = SECURITY_DESCRIPTOR_MIN_LENGTH + + aclSizeInfo.AclBytesInUse + + (tokenOwnerSid ? RtlLengthSid(tokenOwnerSid) : 0); + + securityDescriptor = PhAllocateZero(allocationLength); + RtlCreateSecurityDescriptor(securityDescriptor, SECURITY_DESCRIPTOR_REVISION); + RtlSetDaclSecurityDescriptor(securityDescriptor, TRUE, defaultDacl->DefaultDacl, FALSE); + + if (tokenOwnerSid) + { + RtlSetOwnerSecurityDescriptor(securityDescriptor, tokenOwnerSid, TRUE); + PhFree(tokenOwnerSid); + } + + assert(allocationLength == RtlLengthSecurityDescriptor(securityDescriptor)); + + *SecurityDescriptor = securityDescriptor; } - *SecurityDescriptor = securityDescriptor; PhFree(defaultDacl); } From 039b0be15abe745ba0e2bde1f77076ceb77187e7 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 5 Oct 2018 11:30:21 +1000 Subject: [PATCH 1389/2058] Fix resetting the process TokenDefaultDacl after an error. Prevent changing the TokenDefaultDacl owner since it doesn't exist. --- phlib/secedit.c | 33 ++++++++++++++------------------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/phlib/secedit.c b/phlib/secedit.c index 2a179754818c..d4f65bbc1f7f 100644 --- a/phlib/secedit.c +++ b/phlib/secedit.c @@ -282,6 +282,9 @@ HRESULT STDMETHODCALLTYPE PhSecurityInformation_GetObjectInformation( ObjectInfo->dwFlags = SI_EDIT_ALL | SI_ADVANCED | SI_MAY_WRITE; ObjectInfo->pszObjectName = PhGetString(this->ObjectName); + if (PhEqualString2(this->ObjectType, L"TokenDefault", TRUE)) + ObjectInfo->dwFlags &= ~SI_EDIT_OWNER; + return S_OK; } @@ -806,7 +809,7 @@ _Callback_ NTSTATUS PhStdGetObjectSecurity( // //SamCloseHandle(handle); } - else if (PhEqualString2(this->ObjectType, L"TokenDefault", TRUE)) // HACK: Fake non-system type (dmex) + else if (PhEqualString2(this->ObjectType, L"TokenDefault", TRUE)) { PTOKEN_DEFAULT_DACL defaultDacl; @@ -816,6 +819,10 @@ _Callback_ NTSTATUS PhStdGetObjectSecurity( &defaultDacl ); + // Note: NtQueryInformationToken returns success for processes with a NULL DefaultDacl. (dmex) + if (NT_SUCCESS(status) && !defaultDacl->DefaultDacl) + status = STATUS_INVALID_SECURITY_DESCR; + if (NT_SUCCESS(status)) { ACL_SIZE_INFORMATION aclSizeInfo; @@ -831,29 +838,13 @@ _Callback_ NTSTATUS PhStdGetObjectSecurity( { ULONG allocationLength; PSECURITY_DESCRIPTOR securityDescriptor; - PTOKEN_OWNER tokenOwner; - PSID tokenOwnerSid = NULL; - - if (NT_SUCCESS(PhGetTokenOwner(handle, &tokenOwner))) - { - tokenOwnerSid = PhAllocateCopy(tokenOwner->Owner, RtlLengthSid(tokenOwner->Owner)); - PhFree(tokenOwner); - } - allocationLength = SECURITY_DESCRIPTOR_MIN_LENGTH + - aclSizeInfo.AclBytesInUse + - (tokenOwnerSid ? RtlLengthSid(tokenOwnerSid) : 0); + allocationLength = SECURITY_DESCRIPTOR_MIN_LENGTH + aclSizeInfo.AclBytesInUse; securityDescriptor = PhAllocateZero(allocationLength); RtlCreateSecurityDescriptor(securityDescriptor, SECURITY_DESCRIPTOR_REVISION); RtlSetDaclSecurityDescriptor(securityDescriptor, TRUE, defaultDacl->DefaultDacl, FALSE); - if (tokenOwnerSid) - { - RtlSetOwnerSecurityDescriptor(securityDescriptor, tokenOwnerSid, TRUE); - PhFree(tokenOwnerSid); - } - assert(allocationLength == RtlLengthSecurityDescriptor(securityDescriptor)); *SecurityDescriptor = securityDescriptor; @@ -938,7 +929,7 @@ _Callback_ NTSTATUS PhStdSetObjectSecurity( // //SamCloseHandle(handle); } - else if (PhEqualString2(this->ObjectType, L"TokenDefault", TRUE)) // HACK: Fake non-system type (dmex) + else if (PhEqualString2(this->ObjectType, L"TokenDefault", TRUE)) { BOOLEAN present = FALSE; BOOLEAN defaulted = FALSE; @@ -951,6 +942,10 @@ _Callback_ NTSTATUS PhStdSetObjectSecurity( &defaulted ); + // Note: RtlGetDaclSecurityDescriptor returns success for security descriptors with a NULL dacl. (dmex) + if (NT_SUCCESS(status) && !dacl) + status = STATUS_INVALID_SECURITY_DESCR; + if (NT_SUCCESS(status)) { TOKEN_DEFAULT_DACL defaultDacl; From aa01fc43af36523bd55abb898e1976179b161204 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 5 Oct 2018 13:44:29 +1000 Subject: [PATCH 1390/2058] Add more RS5 types --- phnt/include/ntioapi.h | 24 ++++++++++++++++++++++++ phnt/include/ntmmapi.h | 19 +++++++++++++++++++ phnt/include/ntpebteb.h | 20 +++++++++++++++++--- phnt/include/ntpoapi.h | 2 +- phnt/include/ntpsapi.h | 5 ++++- 5 files changed, 65 insertions(+), 5 deletions(-) diff --git a/phnt/include/ntioapi.h b/phnt/include/ntioapi.h index a4b6471f49de..7edf212f85c4 100644 --- a/phnt/include/ntioapi.h +++ b/phnt/include/ntioapi.h @@ -265,6 +265,10 @@ typedef enum _FILE_INFORMATION_CLASS FileMemoryPartitionInformation, // FILE_MEMORY_PARTITION_INFORMATION // since REDSTONE3 FileStatLxInformation, // FILE_STAT_LX_INFORMATION // since REDSTONE4 FileCaseSensitiveInformation, // FILE_CASE_SENSITIVE_INFORMATION + FileLinkInformationEx, // since REDSTONE5 + FileLinkInformationExBypassAccessCheck, + FileStorageReserveIdInformation, + FileCaseSensitiveInformationForceAccessCheck, FileMaximumInformation } FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS; @@ -947,6 +951,7 @@ typedef enum _FSINFOCLASS FileFsSectorSizeInformation, // FILE_FS_SECTOR_SIZE_INFORMATION // since WIN8 FileFsDataCopyInformation, // FILE_FS_DATA_COPY_INFORMATION FileFsMetadataSizeInformation, // FILE_FS_METADATA_SIZE_INFORMATION // since THRESHOLD + FileFsFullSizeInformationEx, // FILE_FS_FULL_SIZE_INFORMATION_EX // since REDSTONE5 FileFsMaximumInformation } FSINFOCLASS, *PFSINFOCLASS; @@ -1050,6 +1055,7 @@ typedef struct _FILE_FS_DATA_COPY_INFORMATION ULONG NumberOfCopies; } FILE_FS_DATA_COPY_INFORMATION, *PFILE_FS_DATA_COPY_INFORMATION; +// private typedef struct _FILE_FS_METADATA_SIZE_INFORMATION { LARGE_INTEGER TotalMetadataAllocationUnits; @@ -1057,6 +1063,24 @@ typedef struct _FILE_FS_METADATA_SIZE_INFORMATION ULONG BytesPerSector; } FILE_FS_METADATA_SIZE_INFORMATION, *PFILE_FS_METADATA_SIZE_INFORMATION; +// private +typedef struct _FILE_FS_FULL_SIZE_INFORMATION_EX +{ + ULONGLONG ActualTotalAllocationUnits; + ULONGLONG ActualAvailableAllocationUnits; + ULONGLONG ActualPoolUnavailableAllocationUnits; + ULONGLONG CallerTotalAllocationUnits; + ULONGLONG CallerAvailableAllocationUnits; + ULONGLONG CallerPoolUnavailableAllocationUnits; + ULONGLONG UsedAllocationUnits; + ULONGLONG TotalReservedAllocationUnits; + ULONGLONG VolumeStorageReserveAllocationUnits; + ULONGLONG AvailableCommittedAllocationUnits; + ULONGLONG PoolAvailableAllocationUnits; + ULONG SectorsPerAllocationUnit; + ULONG BytesPerSector; +} FILE_FS_FULL_SIZE_INFORMATION_EX, *PFILE_FS_FULL_SIZE_INFORMATION_EX; + // System calls NTSYSCALLAPI diff --git a/phnt/include/ntmmapi.h b/phnt/include/ntmmapi.h index cb633b0679b6..9730f6875d0c 100644 --- a/phnt/include/ntmmapi.h +++ b/phnt/include/ntmmapi.h @@ -520,6 +520,8 @@ typedef struct _CFG_CALL_TARGET_LIST_INFORMATION ULONG Reserved; PULONG NumberOfEntriesProcessed; PCFG_CALL_TARGET_INFO CallTargetInfo; + PVOID Section; // since REDSTONE5 + ULONGLONG FileOffset; } CFG_CALL_TARGET_LIST_INFORMATION, *PCFG_CALL_TARGET_LIST_INFORMATION; #endif // end_private @@ -581,6 +583,23 @@ NtCreateSection( _In_opt_ HANDLE FileHandle ); +#if (PHNT_VERSION >= PHNT_REDSTONE5) +NTSYSCALLAPI +NTSTATUS +NTAPI +NtCreateSectionEx( + _Out_ PHANDLE SectionHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_opt_ PLARGE_INTEGER MaximumSize, + _In_ ULONG SectionPageProtection, + _In_ ULONG AllocationAttributes, + _In_opt_ HANDLE FileHandle, + _In_ PMEM_EXTENDED_PARAMETER ExtendedParameters, + _In_ ULONG ExtendedParameterCount + ); +#endif + NTSYSCALLAPI NTSTATUS NTAPI diff --git a/phnt/include/ntpebteb.h b/phnt/include/ntpebteb.h index 577097e51be2..98424574c298 100644 --- a/phnt/include/ntpebteb.h +++ b/phnt/include/ntpebteb.h @@ -98,7 +98,8 @@ typedef struct _PEB ULONG ProcessUsingFTH : 1; ULONG ProcessPreviouslyThrottled : 1; ULONG ProcessCurrentlyThrottled : 1; - ULONG ReservedBits0 : 25; + ULONG ProcessImagesHotPatched : 1; // REDSTONE5 + ULONG ReservedBits0 : 24; }; }; union @@ -201,16 +202,29 @@ typedef struct _PEB ULONG CloudFileDiagFlags; // REDSTONE4 CHAR PlaceholderCompatibilityMode; CHAR PlaceholderCompatibilityModeReserved[7]; + struct _LEAP_SECOND_DATA *LeapSecondData; // REDSTONE5 + union + { + ULONG LeapSecondFlags; + struct + { + ULONG SixtySecondEnabled : 1; + ULONG Reserved : 31; + }; + }; + ULONG NtGlobalFlag2; } PEB, *PPEB; #ifdef _WIN64 C_ASSERT(FIELD_OFFSET(PEB, SessionId) == 0x2C0); //C_ASSERT(sizeof(PEB) == 0x7B0); // REDSTONE3 -C_ASSERT(sizeof(PEB) == 0x7B8); // REDSTONE4 +//C_ASSERT(sizeof(PEB) == 0x7B8); // REDSTONE4 +C_ASSERT(sizeof(PEB) == 0x7C8); // REDSTONE5 #else C_ASSERT(FIELD_OFFSET(PEB, SessionId) == 0x1D4); //C_ASSERT(sizeof(PEB) == 0x468); // REDSTONE3 -C_ASSERT(sizeof(PEB) == 0x470); +//C_ASSERT(sizeof(PEB) == 0x470); // REDSTONE4 +C_ASSERT(sizeof(PEB) == 0x480); // REDSTONE5 #endif #define GDI_BATCH_BUFFER_SIZE 310 diff --git a/phnt/include/ntpoapi.h b/phnt/include/ntpoapi.h index 1ad5c053132a..0270f61ce02d 100644 --- a/phnt/include/ntpoapi.h +++ b/phnt/include/ntpoapi.h @@ -56,7 +56,7 @@ typedef struct _COUNTED_REASON_CONTEXT /** \endcond */ #endif -typedef enum +typedef enum _POWER_STATE_HANDLER_TYPE { PowerStateSleeping1 = 0, PowerStateSleeping2 = 1, diff --git a/phnt/include/ntpsapi.h b/phnt/include/ntpsapi.h index 87b7f721ab8a..49e74ca3e378 100644 --- a/phnt/include/ntpsapi.h +++ b/phnt/include/ntpsapi.h @@ -1595,7 +1595,10 @@ typedef enum _PS_MITIGATION_OPTION PS_MITIGATION_OPTION_RESTRICT_CHILD_PROCESS_CREATION, PS_MITIGATION_OPTION_IMPORT_ADDRESS_FILTER, PS_MITIGATION_OPTION_MODULE_TAMPERING_PROTECTION, - PS_MITIGATION_OPTION_RESTRICT_INDIRECT_BRANCH_PREDICTION + PS_MITIGATION_OPTION_RESTRICT_INDIRECT_BRANCH_PREDICTION, + PS_MITIGATION_OPTION_SPECULATIVE_STORE_BYPASS_DISABLE, // since REDSTONE5 + PS_MITIGATION_OPTION_ALLOW_DOWNGRADE_DYNAMIC_CODE_POLICY, + PS_MITIGATION_OPTION_CET_SHADOW_STACKS } PS_MITIGATION_OPTION; // windows-internals-book:"Chapter 5" From 89366535f17a6c5f48a36c0c563a3eaf800eddd3 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 5 Oct 2018 14:45:34 +1000 Subject: [PATCH 1391/2058] Add warning dialog to options window when disabling KPH --- ProcessHacker/options.c | 42 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/ProcessHacker/options.c b/ProcessHacker/options.c index 546930ba7c57..8e74476e86f0 100644 --- a/ProcessHacker/options.c +++ b/ProcessHacker/options.c @@ -1213,6 +1213,7 @@ INT_PTR CALLBACK PhpOptionsGeneralDlgProc( ) { static PH_LAYOUT_MANAGER LayoutManager; + static BOOLEAN GeneralListViewStateInitializing = FALSE; switch (uMsg) { @@ -1268,8 +1269,10 @@ INT_PTR CALLBACK PhpOptionsGeneralDlgProc( } } + GeneralListViewStateInitializing = TRUE; PhpAdvancedPageLoad(hwndDlg); PhpRefreshTaskManagerState(hwndDlg); + GeneralListViewStateInitializing = FALSE; } break; case WM_DESTROY: @@ -1342,7 +1345,7 @@ INT_PTR CALLBACK PhpOptionsGeneralDlgProc( PhCreateThread2(PhpElevateAdvancedThreadStart, PhFormatString( L"-showoptions -hwnd %Ix", - (ULONG_PTR)GetParent(GetParent(hwndDlg)) + (ULONG_PTR)PhOptionsWindowHandle // GetParent(GetParent(hwndDlg)) )); } break; @@ -1392,6 +1395,43 @@ INT_PTR CALLBACK PhpOptionsGeneralDlgProc( } } break; + case LVN_ITEMCHANGING: + { + LPNM_LISTVIEW listView = (LPNM_LISTVIEW)lParam; + + if (listView->uChanged & LVIF_STATE) + { + if (GeneralListViewStateInitializing) + break; + + switch (listView->uNewState & LVIS_STATEIMAGEMASK) + { + case INDEXTOSTATEIMAGEMASK(1): // unchecked + { + switch (listView->iItem) + { + case PHP_OPTIONS_INDEX_ENABLE_DRIVER: + { + if (PhShowMessage2( + PhOptionsWindowHandle, + TDCBF_YES_BUTTON | TDCBF_NO_BUTTON, + TD_WARNING_ICON, + L"Are you sure you want to disable the kernel-mode driver?", + L"You will be unable to use more advanced features, view details about system processes or terminate malicious software." + ) == IDNO) + { + SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, TRUE); + return TRUE; + } + } + break; + } + } + break; + } + } + } + break; case LVN_ITEMCHANGED: { LPNM_LISTVIEW listView = (LPNM_LISTVIEW)lParam; From bd77da8c2dfadf250abfc0970e20d68ceb08ce84 Mon Sep 17 00:00:00 2001 From: diversenok Date: Sat, 6 Oct 2018 00:31:07 +0300 Subject: [PATCH 1392/2058] Improve search of memory regions (#328) --- ProcessHacker/prpgmem.c | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/ProcessHacker/prpgmem.c b/ProcessHacker/prpgmem.c index 2fb6a516eddb..86a8f21fa323 100644 --- a/ProcessHacker/prpgmem.c +++ b/ProcessHacker/prpgmem.c @@ -261,13 +261,32 @@ BOOLEAN PhpMemoryTreeFilterCallback( if (PhIsNullOrEmptyString(memoryContext->SearchboxText)) return TRUE; - if ( - memoryContext->UseSearchPointer && - (memoryNode->MemoryItem->BaseAddress == (PVOID)memoryContext->SearchPointer || - memoryNode->MemoryItem->AllocationBase == (PVOID)memoryContext->SearchPointer) - ) + if (memoryContext->UseSearchPointer) { - return TRUE; + // Show all the nodes for which the specified pointer is the allocation base + if ((ULONG64)memoryNode->MemoryItem->AllocationBase == memoryContext->SearchPointer) + { + return TRUE; + } + + // Show the AllocationBaseNode for which the specified pointer is within its range + if ( + memoryNode->IsAllocationBase && + (ULONG64)memoryNode->MemoryItem->AllocationBase <= memoryContext->SearchPointer && + (ULONG64)memoryNode->MemoryItem->AllocationBase + (ULONG64)memoryNode->MemoryItem->RegionSize > memoryContext->SearchPointer + ) + { + return TRUE; + } + + // Show the RegionNode for which the specified pointer is within its range + if ( + (ULONG64)memoryNode->MemoryItem->BaseAddress <= memoryContext->SearchPointer && + (ULONG64)memoryNode->MemoryItem->BaseAddress + (ULONG64)memoryNode->MemoryItem->RegionSize > memoryContext->SearchPointer + ) + { + return TRUE; + } } if (memoryNode->BaseAddressText[0]) From a8e98b82d1db6a11d2afaf6ce65e457f9979d420 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 6 Oct 2018 11:21:50 +1000 Subject: [PATCH 1393/2058] Add native BreakOnTermination wrappers --- phlib/include/phnativeinl.h | 90 +++++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) diff --git a/phlib/include/phnativeinl.h b/phlib/include/phnativeinl.h index bbe6073ce978..1b24695deb15 100644 --- a/phlib/include/phnativeinl.h +++ b/phlib/include/phnativeinl.h @@ -590,6 +590,51 @@ PhGetProcessHandleCount( ); } +FORCEINLINE +NTSTATUS +PhGetProcessBreakOnTermination( + _In_ HANDLE ProcessHandle, + _Out_ PBOOLEAN BreakOnTermination + ) +{ + NTSTATUS status; + ULONG breakOnTermination; + + status = NtQueryInformationProcess( + ProcessHandle, + ProcessBreakOnTermination, + &breakOnTermination, + sizeof(ULONG), + NULL + ); + + if (NT_SUCCESS(status)) + { + *BreakOnTermination = !!breakOnTermination; + } + + return status; +} + +FORCEINLINE +NTSTATUS +PhSetProcessBreakOnTermination( + _In_ HANDLE ProcessHandle, + _In_ BOOLEAN BreakOnTermination + ) +{ + ULONG breakOnTermination; + + breakOnTermination = BreakOnTermination ? 1 : 0; + + return NtSetInformationProcess( + ProcessHandle, + ProcessBreakOnTermination, + &breakOnTermination, + sizeof(ULONG) + ); +} + /** * Gets basic information for a thread. * @@ -866,6 +911,51 @@ PhGetThreadWow64Context( ); } +FORCEINLINE +NTSTATUS +PhGetThreadBreakOnTermination( + _In_ HANDLE ThreadHandle, + _Out_ PBOOLEAN BreakOnTermination + ) +{ + NTSTATUS status; + ULONG breakOnTermination; + + status = NtQueryInformationThread( + ThreadHandle, + ThreadBreakOnTermination, + &breakOnTermination, + sizeof(ULONG), + NULL + ); + + if (NT_SUCCESS(status)) + { + *BreakOnTermination = !!breakOnTermination; + } + + return status; +} + +FORCEINLINE +NTSTATUS +PhSetThreadBreakOnTermination( + _In_ HANDLE ProcessHandle, + _In_ BOOLEAN BreakOnTermination + ) +{ + ULONG breakOnTermination; + + breakOnTermination = BreakOnTermination ? 1 : 0; + + return NtSetInformationThread( + ProcessHandle, + ThreadBreakOnTermination, + &breakOnTermination, + sizeof(ULONG) + ); +} + /** * Sets a thread's affinity mask. * From c0cdad116250c3e799d27a215f87708f70158cdd Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 6 Oct 2018 11:30:09 +1000 Subject: [PATCH 1394/2058] Add process/thread critical columns, Add process/thread miscellaneous > critical menu --- ProcessHacker/ProcessHacker.rc | 3 +- ProcessHacker/actions.c | 58 ++++++++++++++++++++ ProcessHacker/include/actions.h | 8 +++ ProcessHacker/include/proctree.h | 6 ++- ProcessHacker/include/thrdlist.h | 3 ++ ProcessHacker/mainwnd.c | 12 +++++ ProcessHacker/mwpgproc.c | 15 +++--- ProcessHacker/proctree.c | 53 ++++++++++++++++-- ProcessHacker/prpgthrd.c | 93 ++++++++++++++++++++++++++++++-- ProcessHacker/thrdlist.c | 69 +++++++++++++++--------- ProcessHacker/thrdprv.c | 9 ++-- 11 files changed, 283 insertions(+), 46 deletions(-) diff --git a/ProcessHacker/ProcessHacker.rc b/ProcessHacker/ProcessHacker.rc index b7230f03ff15..f743346f0249 100644 --- a/ProcessHacker/ProcessHacker.rc +++ b/ProcessHacker/ProcessHacker.rc @@ -171,6 +171,7 @@ BEGIN MENUITEM SEPARATOR MENUITEM "Analy&ze", ID_ANALYZE_WAIT MENUITEM "&Affinity", ID_THREAD_AFFINITY + MENUITEM "Critical", ID_THREAD_CRITICAL MENUITEM "Per&missions", ID_THREAD_PERMISSIONS MENUITEM "&Token", ID_THREAD_TOKEN POPUP "&Priority" @@ -280,6 +281,7 @@ BEGIN END POPUP "&Miscellaneous" BEGIN + MENUITEM "&Critical", ID_MISCELLANEOUS_SETCRITICAL MENUITEM "&Detach from debugger", ID_MISCELLANEOUS_DETACHFROMDEBUGGER MENUITEM "GDI &handles", ID_MISCELLANEOUS_GDIHANDLES POPUP "Pa&ge priority" @@ -2365,7 +2367,6 @@ IDB_SEARCH_ACTIVE PNG "resources\\active_search.png" IDB_SEARCH_INACTIVE PNG "resources\\inactive_search.png" - #endif // English (Australia) resources ///////////////////////////////////////////////////////////////////////////// diff --git a/ProcessHacker/actions.c b/ProcessHacker/actions.c index 5957ee2fe966..abd1e8e67434 100644 --- a/ProcessHacker/actions.c +++ b/ProcessHacker/actions.c @@ -1603,6 +1603,64 @@ BOOLEAN PhUiSetVirtualizationProcess( return TRUE; } +BOOLEAN PhUiSetCriticalProcess( + _In_ HWND WindowHandle, + _In_ PPH_PROCESS_ITEM Process + ) +{ + NTSTATUS status; + HANDLE processHandle; + BOOLEAN breakOnTermination; + + status = PhOpenProcess( + &processHandle, + PROCESS_QUERY_INFORMATION | PROCESS_SET_INFORMATION, + Process->ProcessId + ); + + if (NT_SUCCESS(status)) + { + status = PhGetProcessBreakOnTermination( + processHandle, + &breakOnTermination + ); + + if (NT_SUCCESS(status)) + { + if (!breakOnTermination && (!PhGetIntegerSetting(L"EnableWarnings") || PhShowConfirmMessage( + WindowHandle, + L"enable", + L"critical status on the process", + L"If the process ends, the operating system will shut down immediately.", + TRUE + ))) + { + status = PhSetProcessBreakOnTermination(processHandle, TRUE); + } + else if (breakOnTermination && (!PhGetIntegerSetting(L"EnableWarnings") || PhShowConfirmMessage( + WindowHandle, + L"disable", + L"critical status on the process", + NULL, + FALSE + ))) + { + status = PhSetProcessBreakOnTermination(processHandle, FALSE); + } + } + + NtClose(processHandle); + } + + if (!NT_SUCCESS(status)) + { + PhpShowErrorProcess(WindowHandle, L"set critical status", Process, status, 0); + return FALSE; + } + + return TRUE; +} + BOOLEAN PhUiDetachFromDebuggerProcess( _In_ HWND hWnd, _In_ PPH_PROCESS_ITEM Process diff --git a/ProcessHacker/include/actions.h b/ProcessHacker/include/actions.h index 9b18626c6b48..9730132fc4a9 100644 --- a/ProcessHacker/include/actions.h +++ b/ProcessHacker/include/actions.h @@ -180,6 +180,14 @@ PhUiSetVirtualizationProcess( _In_ BOOLEAN Enable ); +PHAPPAPI +BOOLEAN +NTAPI +PhUiSetCriticalProcess( + _In_ HWND WindowHandle, + _In_ PPH_PROCESS_ITEM Process + ); + PHAPPAPI BOOLEAN NTAPI diff --git a/ProcessHacker/include/proctree.h b/ProcessHacker/include/proctree.h index cf1950534c47..11b406adb0b9 100644 --- a/ProcessHacker/include/proctree.h +++ b/ProcessHacker/include/proctree.h @@ -93,8 +93,9 @@ #define PHPRTLC_JOBOBJECTID 80 #define PHPRTLC_PROTECTION 81 #define PHPRTLC_DESKTOP 82 +#define PHPRTLC_CRITICAL 83 -#define PHPRTLC_MAXIMUM 83 +#define PHPRTLC_MAXIMUM 84 #define PHPRTLC_IOGROUP_COUNT 9 #define PHPN_WSCOUNTERS 0x1 @@ -111,6 +112,7 @@ #define PHPN_FILEATTRIBUTES 0x800 #define PHPN_DESKTOPINFO 0x1000 #define PHPN_USERNAME 0x2000 +#define PHPN_CRITICAL 0x4000 // begin_phapppub typedef struct _PH_PROCESS_NODE @@ -172,6 +174,8 @@ typedef struct _PH_PROCESS_NODE // File attributes LARGE_INTEGER FileLastWriteTime; LARGE_INTEGER FileEndOfFile; + // Critical + BOOLEAN BreakOnTerminationEnabled; PPH_STRING TooltipText; ULONG64 TooltipTextValidToTickCount; diff --git a/ProcessHacker/include/thrdlist.h b/ProcessHacker/include/thrdlist.h index 458f870419d5..9e0153dde5a7 100644 --- a/ProcessHacker/include/thrdlist.h +++ b/ProcessHacker/include/thrdlist.h @@ -27,6 +27,7 @@ typedef enum _PH_THREAD_TREELIST_COLUMN PH_THREAD_TREELIST_COLUMN_KERNELTIME, PH_THREAD_TREELIST_COLUMN_USERTIME, PH_THREAD_TREELIST_COLUMN_IDEALPROCESSOR, + PH_THREAD_TREELIST_COLUMN_CRITICAL, PH_THREAD_TREELIST_COLUMN_MAXIMUM } PH_THREAD_TREELIST_COLUMN; @@ -47,6 +48,7 @@ typedef struct _PH_THREAD_NODE ULONG PagePriority; IO_PRIORITY_HINT IoPriority; + BOOLEAN BreakOnTermination; WCHAR ThreadIdText[PH_INT32_STR_LEN_1]; WCHAR CpuUsageText[PH_INT32_STR_LEN_1]; PPH_STRING CyclesDeltaText; // used for Context Switches Delta as well @@ -54,6 +56,7 @@ typedef struct _PH_THREAD_NODE PPH_STRING PrioritySymbolicText; PPH_STRING CreatedText; PPH_STRING NameText; + PPH_STRING StateText; WCHAR ContextSwitchesText[PH_INT64_STR_LEN_1]; WCHAR PriorityText[PH_INT32_STR_LEN_1]; WCHAR BasePriorityText[PH_INT32_STR_LEN_1]; diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index 18c9efa23986..f0f0fe3a7e29 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -1107,6 +1107,18 @@ VOID PhMwpOnCommand( } } break; + case ID_MISCELLANEOUS_SETCRITICAL: + { + PPH_PROCESS_ITEM processItem = PhGetSelectedProcessItem(); + + if (processItem) + { + PhReferenceObject(processItem); + PhUiSetCriticalProcess(PhMainWndHandle, processItem); + PhDereferenceObject(processItem); + } + } + break; case ID_MISCELLANEOUS_DETACHFROMDEBUGGER: { PPH_PROCESS_ITEM processItem = PhGetSelectedProcessItem(); diff --git a/ProcessHacker/mwpgproc.c b/ProcessHacker/mwpgproc.c index 6ac15435c197..666561520c0c 100644 --- a/ProcessHacker/mwpgproc.c +++ b/ProcessHacker/mwpgproc.c @@ -386,8 +386,8 @@ VOID PhMwpSetProcessMenuPriorityChecks( { HANDLE processHandle; PROCESS_PRIORITY_CLASS priorityClass = { 0 }; - IO_PRIORITY_HINT ioPriority = -1; - ULONG pagePriority = -1; + IO_PRIORITY_HINT ioPriority = ULONG_MAX; + ULONG pagePriority = ULONG_MAX; ULONG id = 0; if (NT_SUCCESS(PhOpenProcess( @@ -408,7 +408,7 @@ VOID PhMwpSetProcessMenuPriorityChecks( &ioPriority ))) { - ioPriority = -1; + ioPriority = ULONG_MAX; } } @@ -419,7 +419,7 @@ VOID PhMwpSetProcessMenuPriorityChecks( &pagePriority ))) { - pagePriority = -1; + pagePriority = ULONG_MAX; } } @@ -458,7 +458,7 @@ VOID PhMwpSetProcessMenuPriorityChecks( } } - if (SetIoPriority && ioPriority != -1) + if (SetIoPriority && ioPriority != ULONG_MAX) { id = 0; @@ -486,7 +486,7 @@ VOID PhMwpSetProcessMenuPriorityChecks( } } - if (SetPagePriority && pagePriority != -1) + if (SetPagePriority && pagePriority != ULONG_MAX) { id = 0; @@ -534,8 +534,7 @@ VOID PhMwpInitializeProcessMenu( { // All menu items are enabled by default. - // If the user selected a fake process, disable all but - // a few menu items. + // If the user selected a fake process, disable all but a few menu items. if ( PH_IS_FAKE_PROCESS_ID(Processes[0]->ProcessId) || Processes[0]->ProcessId == SYSTEM_IDLE_PROCESS_ID || diff --git a/ProcessHacker/proctree.c b/ProcessHacker/proctree.c index e8a8be8871e9..ee1050c1323f 100644 --- a/ProcessHacker/proctree.c +++ b/ProcessHacker/proctree.c @@ -210,10 +210,11 @@ VOID PhInitializeProcessTreeList( PhAddTreeNewColumnEx(hwnd, PHPRTLC_TIMESTAMP, FALSE, L"Time stamp", 140, PH_ALIGN_LEFT, -1, 0, TRUE); PhAddTreeNewColumnEx(hwnd, PHPRTLC_FILEMODIFIEDTIME, FALSE, L"File modified time", 140, PH_ALIGN_LEFT, -1, 0, TRUE); PhAddTreeNewColumnEx(hwnd, PHPRTLC_FILESIZE, FALSE, L"File size", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_SUBPROCESSCOUNT, FALSE, L"Subprocesses", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_JOBOBJECTID, FALSE, L"Job Object ID", 50, PH_ALIGN_LEFT, -1, 0, TRUE); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_PROTECTION, FALSE, L"Protection", 105, PH_ALIGN_LEFT, -1, 0, TRUE); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_DESKTOP, FALSE, L"Desktop", 80, PH_ALIGN_LEFT, -1, 0, TRUE); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_SUBPROCESSCOUNT, FALSE, L"Subprocesses", 70, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_JOBOBJECTID, FALSE, L"Job Object ID", 50, PH_ALIGN_LEFT, ULONG_MAX, 0, TRUE); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_PROTECTION, FALSE, L"Protection", 105, PH_ALIGN_LEFT, ULONG_MAX, 0, TRUE); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_DESKTOP, FALSE, L"Desktop", 80, PH_ALIGN_LEFT, ULONG_MAX, 0, TRUE); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_CRITICAL, FALSE, L"Critical", 80, PH_ALIGN_LEFT, ULONG_MAX, 0, TRUE); TreeNew_SetRedraw(hwnd, TRUE); @@ -1303,6 +1304,31 @@ static VOID PhpUpdateProcessNodeDesktopInfo( } } +static VOID PhpUpdateProcessBreakOnTermination( + _Inout_ PPH_PROCESS_NODE ProcessNode + ) +{ + if (!(ProcessNode->ValidMask & PHPN_CRITICAL)) + { + ProcessNode->BreakOnTerminationEnabled = FALSE; + + if (ProcessNode->ProcessItem->QueryHandle) + { + BOOLEAN breakOnTermination; + + if (NT_SUCCESS(PhGetProcessBreakOnTermination( + ProcessNode->ProcessItem->QueryHandle, + &breakOnTermination + ))) + { + ProcessNode->BreakOnTerminationEnabled = breakOnTermination; + } + } + + ProcessNode->ValidMask |= PHPN_CRITICAL; + } +} + #define SORT_FUNCTION(Column) PhpProcessTreeNewCompare##Column #define BEGIN_SORT_FUNCTION(Column) static int __cdecl PhpProcessTreeNewCompare##Column( \ @@ -1930,6 +1956,14 @@ BEGIN_SORT_FUNCTION(DesktopInfo) } END_SORT_FUNCTION +BEGIN_SORT_FUNCTION(Critical) +{ + PhpUpdateProcessBreakOnTermination(node1); + PhpUpdateProcessBreakOnTermination(node2); + sortResult = ucharcmp(node1->BreakOnTerminationEnabled, node2->BreakOnTerminationEnabled); +} +END_SORT_FUNCTION + BOOLEAN NTAPI PhpProcessTreeNewCallback( _In_ HWND hwnd, _In_ PH_TREENEW_MESSAGE Message, @@ -2052,7 +2086,8 @@ BOOLEAN NTAPI PhpProcessTreeNewCallback( SORT_FUNCTION(Subprocesses), SORT_FUNCTION(JobObjectId), SORT_FUNCTION(Protection), - SORT_FUNCTION(DesktopInfo) + SORT_FUNCTION(DesktopInfo), + SORT_FUNCTION(Critical), }; int (__cdecl *sortFunction)(const void *, const void *); @@ -2881,6 +2916,14 @@ BOOLEAN NTAPI PhpProcessTreeNewCallback( getCellText->Text = PhGetStringRef(node->DesktopInfoText); } break; + case PHPRTLC_CRITICAL: + { + PhpUpdateProcessBreakOnTermination(node); + + if (node->BreakOnTerminationEnabled) + PhInitializeStringRef(&getCellText->Text, L"Critical"); + } + break; default: return FALSE; } diff --git a/ProcessHacker/prpgthrd.c b/ProcessHacker/prpgthrd.c index 5e97592851ff..956288d903ee 100644 --- a/ProcessHacker/prpgthrd.c +++ b/ProcessHacker/prpgthrd.c @@ -3,6 +3,7 @@ * Process properties: Threads page * * Copyright (C) 2009-2016 wj32 + * Copyright (C) 2018 dmex * * This file is part of Process Hacker. * @@ -27,6 +28,7 @@ #include #include #include +#include #include #include @@ -134,13 +136,39 @@ VOID PhpInitializeThreadMenu( PhEnableEMenuItem(Menu, ID_THREAD_TOKEN, FALSE); + // Critical + if (NumberOfThreads == 1) + { + HANDLE threadHandle; + + if (NT_SUCCESS(PhOpenThread( + &threadHandle, + THREAD_QUERY_INFORMATION, + Threads[0]->ThreadId + ))) + { + BOOLEAN breakOnTermination; + + if (NT_SUCCESS(PhGetThreadBreakOnTermination( + threadHandle, + &breakOnTermination + ))) + { + if (breakOnTermination) + { + PhSetFlagsEMenuItem(Menu, ID_THREAD_CRITICAL, PH_EMENU_CHECKED, PH_EMENU_CHECKED); + } + } + } + } + // Priority if (NumberOfThreads == 1) { HANDLE threadHandle; ULONG threadPriority = THREAD_PRIORITY_ERROR_RETURN; - IO_PRIORITY_HINT ioPriority = -1; - ULONG pagePriority = -1; + IO_PRIORITY_HINT ioPriority = ULONG_MAX; + ULONG pagePriority = ULONG_MAX; ULONG id = 0; if (NT_SUCCESS(PhOpenThread( @@ -203,7 +231,7 @@ VOID PhpInitializeThreadMenu( PH_EMENU_CHECKED | PH_EMENU_RADIOCHECK); } - if (ioPriority != -1) + if (ioPriority != ULONG_MAX) { id = 0; @@ -231,7 +259,7 @@ VOID PhpInitializeThreadMenu( } } - if (pagePriority != -1) + if (pagePriority != ULONG_MAX) { id = 0; @@ -611,6 +639,63 @@ INT_PTR CALLBACK PhpProcessThreadsDlgProc( } } break; + case ID_THREAD_CRITICAL: + { + PPH_THREAD_ITEM threadItem = PhGetSelectedThreadItem(&threadsContext->ListContext); + + if (threadItem) + { + NTSTATUS status; + HANDLE threadHandle; + BOOLEAN breakOnTermination; + + status = PhOpenThread( + &threadHandle, + THREAD_QUERY_INFORMATION | THREAD_SET_INFORMATION, + threadItem->ThreadId + ); + + if (NT_SUCCESS(status)) + { + status = PhGetThreadBreakOnTermination( + threadHandle, + &breakOnTermination + ); + + if (NT_SUCCESS(status)) + { + if (!breakOnTermination && (!PhGetIntegerSetting(L"EnableWarnings") || PhShowConfirmMessage( + hwndDlg, + L"enable", + L"critical status on the thread", + L"If the process ends, the operating system will shut down immediately.", + TRUE + ))) + { + status = PhSetThreadBreakOnTermination(threadHandle, TRUE); + } + else if (breakOnTermination && (!PhGetIntegerSetting(L"EnableWarnings") || PhShowConfirmMessage( + hwndDlg, + L"disable", + L"critical status on the thread", + NULL, + FALSE + ))) + { + status = PhSetThreadBreakOnTermination(threadHandle, FALSE); + } + } + + NtClose(threadHandle); + } + + if (!NT_SUCCESS(status)) + { + PhShowStatus(hwndDlg, L"Unable to change the thread critical status.", status, 0); + } + } + } + break; case ID_THREAD_PERMISSIONS: { PPH_THREAD_ITEM threadItem = PhGetSelectedThreadItem(&threadsContext->ListContext); diff --git a/ProcessHacker/thrdlist.c b/ProcessHacker/thrdlist.c index 0439fefceb97..79ffe74917ad 100644 --- a/ProcessHacker/thrdlist.c +++ b/ProcessHacker/thrdlist.c @@ -98,20 +98,21 @@ VOID PhInitializeThreadList( PhAddTreeNewColumn(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_STARTADDRESS, TRUE, L"Start address", 180, PH_ALIGN_LEFT, 3, 0); PhAddTreeNewColumnEx(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_PRIORITYSYMBOLIC, TRUE, L"Priority (symbolic)", 80, PH_ALIGN_LEFT, 4, 0, TRUE); // Available columns - PhAddTreeNewColumn(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_SERVICE, FALSE, L"Service", 100, PH_ALIGN_LEFT, 5, 0); - PhAddTreeNewColumn(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_NAME, FALSE, L"Name", 100, PH_ALIGN_LEFT, 6, 0); - PhAddTreeNewColumn(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_STARTED, FALSE, L"Created", 100, PH_ALIGN_LEFT, 7, 0); - PhAddTreeNewColumn(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_STARTMODULE, FALSE, L"Start module", 100, PH_ALIGN_LEFT, 8, 0); - PhAddTreeNewColumn(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_CONTEXTSWITCHES, FALSE, L"Context switches", 100, PH_ALIGN_LEFT, 9, 0); - PhAddTreeNewColumn(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_PRIORITY, FALSE, L"Priority", 80, PH_ALIGN_LEFT, 10, 0); - PhAddTreeNewColumn(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_BASEPRIORITY, FALSE, L"Base priority", 80, PH_ALIGN_LEFT, 10, 0); - PhAddTreeNewColumn(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_PAGEPRIORITY, FALSE, L"Page priority", 80, PH_ALIGN_LEFT, 10, 0); - PhAddTreeNewColumn(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_IOPRIORITY, FALSE, L"I/O priority", 80, PH_ALIGN_LEFT, 10, 0); - PhAddTreeNewColumn(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_CYCLES, FALSE, L"Cycles", 100, PH_ALIGN_LEFT, 6, 0); - PhAddTreeNewColumn(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_STATE, FALSE, L"State", 100, PH_ALIGN_LEFT, 6, 0); - PhAddTreeNewColumn(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_KERNELTIME, FALSE, L"Kernel time", 100, PH_ALIGN_LEFT, 6, 0); - PhAddTreeNewColumn(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_USERTIME, FALSE, L"User time", 100, PH_ALIGN_LEFT, 6, 0); - PhAddTreeNewColumn(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_IDEALPROCESSOR, FALSE, L"Ideal processor", 100, PH_ALIGN_LEFT, 6, 0); + PhAddTreeNewColumn(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_SERVICE, FALSE, L"Service", 100, PH_ALIGN_LEFT, ULONG_MAX, 0); + PhAddTreeNewColumn(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_NAME, FALSE, L"Name", 100, PH_ALIGN_LEFT, ULONG_MAX, 0); + PhAddTreeNewColumn(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_STARTED, FALSE, L"Created", 100, PH_ALIGN_LEFT, ULONG_MAX, 0); + PhAddTreeNewColumn(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_STARTMODULE, FALSE, L"Start module", 100, PH_ALIGN_LEFT, ULONG_MAX, 0); + PhAddTreeNewColumn(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_CONTEXTSWITCHES, FALSE, L"Context switches", 100, PH_ALIGN_LEFT, ULONG_MAX, 0); + PhAddTreeNewColumn(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_PRIORITY, FALSE, L"Priority", 80, PH_ALIGN_LEFT, ULONG_MAX, 0); + PhAddTreeNewColumn(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_BASEPRIORITY, FALSE, L"Base priority", 80, PH_ALIGN_LEFT, ULONG_MAX, 0); + PhAddTreeNewColumn(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_PAGEPRIORITY, FALSE, L"Page priority", 80, PH_ALIGN_LEFT, ULONG_MAX, 0); + PhAddTreeNewColumn(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_IOPRIORITY, FALSE, L"I/O priority", 80, PH_ALIGN_LEFT, ULONG_MAX, 0); + PhAddTreeNewColumn(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_CYCLES, FALSE, L"Cycles", 100, PH_ALIGN_LEFT, ULONG_MAX, 0); + PhAddTreeNewColumn(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_STATE, FALSE, L"State", 100, PH_ALIGN_LEFT, ULONG_MAX, 0); + PhAddTreeNewColumn(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_KERNELTIME, FALSE, L"Kernel time", 100, PH_ALIGN_LEFT, ULONG_MAX, 0); + PhAddTreeNewColumn(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_USERTIME, FALSE, L"User time", 100, PH_ALIGN_LEFT, ULONG_MAX, 0); + PhAddTreeNewColumn(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_IDEALPROCESSOR, FALSE, L"Ideal processor", 80, PH_ALIGN_LEFT, ULONG_MAX, 0); + PhAddTreeNewColumn(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_CRITICAL, FALSE, L"Critical", 80, PH_ALIGN_LEFT, ULONG_MAX, 0); TreeNew_SetRedraw(TreeNewHandle, TRUE); TreeNew_SetTriState(TreeNewHandle, TRUE); @@ -495,6 +496,12 @@ BEGIN_SORT_FUNCTION(IdealProcessor) } END_SORT_FUNCTION +BEGIN_SORT_FUNCTION(Critical) +{ + sortResult = ucharcmp(node1->BreakOnTermination, node2->BreakOnTermination); +} +END_SORT_FUNCTION + BOOLEAN NTAPI PhpThreadTreeNewCallback( _In_ HWND hwnd, _In_ PH_TREENEW_MESSAGE Message, @@ -539,7 +546,8 @@ BOOLEAN NTAPI PhpThreadTreeNewCallback( SORT_FUNCTION(State), SORT_FUNCTION(KernelTime), SORT_FUNCTION(UserTime), - SORT_FUNCTION(IdealProcessor) + SORT_FUNCTION(IdealProcessor), + SORT_FUNCTION(Critical) }; int (__cdecl *sortFunction)(void *, const void *, const void *); @@ -789,22 +797,21 @@ BOOLEAN NTAPI PhpThreadTreeNewCallback( break; case PH_THREAD_TREELIST_COLUMN_STATE: { - PPH_STRING state = NULL; ULONG suspendCount; if (threadItem->State != Waiting) { if ((ULONG)threadItem->State < MaximumThreadState) - state = PhaCreateString(PhKThreadStateNames[(ULONG)threadItem->State]); + PhMoveReference(&node->StateText, PhCreateString(PhKThreadStateNames[(ULONG)threadItem->State])); else - state = PhaCreateString(L"Unknown"); + PhMoveReference(&node->StateText, PhCreateString(L"Unknown")); } else { if ((ULONG)threadItem->WaitReason < MaximumWaitReason) - state = PhaConcatStrings2(L"Wait:", PhKWaitReasonNames[(ULONG)threadItem->WaitReason]); + PhMoveReference(&node->StateText, PhConcatStrings2(L"Wait:", PhKWaitReasonNames[(ULONG)threadItem->WaitReason])); else - state = PhaCreateString(L"Waiting"); + PhMoveReference(&node->StateText, PhCreateString(L"Waiting")); } if (threadItem->ThreadHandle) @@ -813,16 +820,16 @@ BOOLEAN NTAPI PhpThreadTreeNewCallback( { PH_FORMAT format[4]; - PhInitFormatSR(&format[0], state->sr); + PhInitFormatSR(&format[0], node->StateText->sr); PhInitFormatS(&format[1], L" ("); PhInitFormatU(&format[2], suspendCount); PhInitFormatS(&format[3], L")"); - state = PH_AUTO(PhFormat(format, 4, 30)); + PhMoveReference(&node->StateText, PhFormat(format, 4, 30)); } } - getCellText->Text = PhGetStringRef(state); + getCellText->Text = PhGetStringRef(node->StateText); } break; case PH_THREAD_TREELIST_COLUMN_KERNELTIME: @@ -862,11 +869,25 @@ BOOLEAN NTAPI PhpThreadTreeNewCallback( } } break; + case PH_THREAD_TREELIST_COLUMN_CRITICAL: + { + BOOLEAN breakOnTermination; + + if (threadItem->ThreadHandle) + { + if (NT_SUCCESS(PhGetThreadBreakOnTermination(threadItem->ThreadHandle, &breakOnTermination))) + { + if (breakOnTermination) + PhInitializeStringRef(&getCellText->Text, L"Critical"); + } + } + } + break; default: return FALSE; } - //getCellText->Flags = TN_CACHE; + getCellText->Flags = TN_CACHE; } return TRUE; case TreeNewGetNodeColor: diff --git a/ProcessHacker/thrdprv.c b/ProcessHacker/thrdprv.c index 6c1d382248e4..842f70f2b5b4 100644 --- a/ProcessHacker/thrdprv.c +++ b/ProcessHacker/thrdprv.c @@ -47,6 +47,7 @@ typedef struct _PH_THREAD_QUERY_DATA ULONG64 RunId; PPH_STRING StartAddressString; + PPH_STRING StartAddressFileName; PH_SYMBOL_RESOLVE_LEVEL StartAddressResolveLevel; PPH_STRING ServiceName; @@ -506,7 +507,7 @@ NTSTATUS PhpThreadQueryWorker( data->ThreadProvider->SymbolProvider, data->ThreadItem->StartAddress, &data->StartAddressResolveLevel, - &data->ThreadItem->StartAddressFileName, + &data->StartAddressFileName, NULL, NULL ); @@ -518,12 +519,12 @@ NTSTATUS PhpThreadQueryWorker( PhLoadSymbolsThreadProvider(data->ThreadProvider); PhClearReference(&data->StartAddressString); - PhClearReference(&data->ThreadItem->StartAddressFileName); + PhClearReference(&data->StartAddressFileName); data->StartAddressString = PhGetSymbolFromAddress( data->ThreadProvider->SymbolProvider, data->ThreadItem->StartAddress, &data->StartAddressResolveLevel, - &data->ThreadItem->StartAddressFileName, + &data->StartAddressFileName, NULL, NULL ); @@ -815,6 +816,7 @@ VOID PhpThreadProviderUpdate( if (data->StartAddressResolveLevel == PhsrlFunction && data->StartAddressString) { PhSwapReference(&data->ThreadItem->StartAddressString, data->StartAddressString); + PhSwapReference(&data->ThreadItem->StartAddressFileName, data->StartAddressFileName); data->ThreadItem->StartAddressResolveLevel = data->StartAddressResolveLevel; } @@ -823,6 +825,7 @@ VOID PhpThreadProviderUpdate( data->ThreadItem->JustResolved = TRUE; if (data->StartAddressString) PhDereferenceObject(data->StartAddressString); + if (data->StartAddressFileName) PhDereferenceObject(data->StartAddressFileName); PhDereferenceObject(data->ThreadItem); PhFree(data); } From ad18348b5b414c9aa63fae83b2340e5ab2d02bc2 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 6 Oct 2018 11:51:18 +1000 Subject: [PATCH 1395/2058] Remove RtlQueryInformationAcl since it doesn't always return the correct ACL length --- phlib/secedit.c | 28 ++++++++-------------------- 1 file changed, 8 insertions(+), 20 deletions(-) diff --git a/phlib/secedit.c b/phlib/secedit.c index d4f65bbc1f7f..bfb2f7c9a987 100644 --- a/phlib/secedit.c +++ b/phlib/secedit.c @@ -825,30 +825,18 @@ _Callback_ NTSTATUS PhStdGetObjectSecurity( if (NT_SUCCESS(status)) { - ACL_SIZE_INFORMATION aclSizeInfo; + ULONG allocationLength; + PSECURITY_DESCRIPTOR securityDescriptor; - status = RtlQueryInformationAcl( - defaultDacl->DefaultDacl, - &aclSizeInfo, - sizeof(ACL_SIZE_INFORMATION), - AclSizeInformation - ); - - if (NT_SUCCESS(status)) - { - ULONG allocationLength; - PSECURITY_DESCRIPTOR securityDescriptor; + allocationLength = SECURITY_DESCRIPTOR_MIN_LENGTH + defaultDacl->DefaultDacl->AclSize; - allocationLength = SECURITY_DESCRIPTOR_MIN_LENGTH + aclSizeInfo.AclBytesInUse; + securityDescriptor = PhAllocateZero(PAGE_SIZE); + RtlCreateSecurityDescriptor(securityDescriptor, SECURITY_DESCRIPTOR_REVISION); + RtlSetDaclSecurityDescriptor(securityDescriptor, TRUE, defaultDacl->DefaultDacl, FALSE); - securityDescriptor = PhAllocateZero(allocationLength); - RtlCreateSecurityDescriptor(securityDescriptor, SECURITY_DESCRIPTOR_REVISION); - RtlSetDaclSecurityDescriptor(securityDescriptor, TRUE, defaultDacl->DefaultDacl, FALSE); + assert(allocationLength == RtlLengthSecurityDescriptor(securityDescriptor)); - assert(allocationLength == RtlLengthSecurityDescriptor(securityDescriptor)); - - *SecurityDescriptor = securityDescriptor; - } + *SecurityDescriptor = securityDescriptor; PhFree(defaultDacl); } From 36002f9ab889b58bc90841fdb54d6d911669e448 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 6 Oct 2018 12:03:54 +1000 Subject: [PATCH 1396/2058] Fix previous commit --- phlib/secedit.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/phlib/secedit.c b/phlib/secedit.c index bfb2f7c9a987..a01b081f706f 100644 --- a/phlib/secedit.c +++ b/phlib/secedit.c @@ -811,7 +811,7 @@ _Callback_ NTSTATUS PhStdGetObjectSecurity( } else if (PhEqualString2(this->ObjectType, L"TokenDefault", TRUE)) { - PTOKEN_DEFAULT_DACL defaultDacl; + PTOKEN_DEFAULT_DACL defaultDacl = NULL; status = PhQueryTokenVariableSize( handle, @@ -837,9 +837,10 @@ _Callback_ NTSTATUS PhStdGetObjectSecurity( assert(allocationLength == RtlLengthSecurityDescriptor(securityDescriptor)); *SecurityDescriptor = securityDescriptor; + } + if (defaultDacl) PhFree(defaultDacl); - } NtClose(handle); } From d054f937cfddfcebcf58a1d287fc8029df39cec5 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 7 Oct 2018 13:12:26 +1100 Subject: [PATCH 1397/2058] Add missing types from commit c0cdad1 --- ProcessHacker/resource.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ProcessHacker/resource.h b/ProcessHacker/resource.h index a824fb4f1b83..8b80d36382a1 100644 --- a/ProcessHacker/resource.h +++ b/ProcessHacker/resource.h @@ -572,6 +572,7 @@ #define ID_PROCESS_VIRTUALIZATION 40034 #define ID_PROCESS_AFFINITY 40035 #define ID_PROCESS_CREATEDUMPFILE 40036 +#define ID_MISCELLANEOUS_SETCRITICAL 40038 #define ID_MISCELLANEOUS_DETACHFROMDEBUGGER 40039 #define ID_PRIORITY_REALTIME 40048 #define ID_PRIORITY_HIGH 40049 @@ -743,6 +744,7 @@ #define ID_EMPTY_COMBINEMEMORYLISTS 40295 #define ID_PRIVILEGE_RESET 40296 #define ID_GROUP_ENABLE 40297 +#define ID_THREAD_CRITICAL 40297 #define ID_GROUP_DISABLE 40298 #define ID_GROUP_RESET 40299 #define ID_TOOLS_SCM_PERMISSIONS 40300 @@ -754,7 +756,7 @@ #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 254 -#define _APS_NEXT_COMMAND_VALUE 40297 +#define _APS_NEXT_COMMAND_VALUE 40298 #define _APS_NEXT_CONTROL_VALUE 1410 #define _APS_NEXT_SYMED_VALUE 170 #endif From 2b4b37e7d3ca243103ae932bbafbfb57c507505b Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 7 Oct 2018 13:23:13 +1100 Subject: [PATCH 1398/2058] Add missing PhGetProcessBreakOnTermination usage --- ProcessHacker/actions.c | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/ProcessHacker/actions.c b/ProcessHacker/actions.c index abd1e8e67434..e2c87313584d 100644 --- a/ProcessHacker/actions.c +++ b/ProcessHacker/actions.c @@ -791,7 +791,7 @@ static BOOLEAN PhpShowContinueMessageProcesses( for (i = 0; i < NumberOfProcesses; i++) { HANDLE processHandle; - ULONG breakOnTermination = 0; + BOOLEAN breakOnTermination = FALSE; if (PhpIsDangerousProcess(Processes[i]->ProcessId)) { @@ -802,11 +802,11 @@ static BOOLEAN PhpShowContinueMessageProcesses( if (NT_SUCCESS(PhOpenProcess(&processHandle, PROCESS_QUERY_INFORMATION, Processes[i]->ProcessId))) { - NtQueryInformationProcess(processHandle, ProcessBreakOnTermination, &breakOnTermination, sizeof(ULONG), NULL); + PhGetProcessBreakOnTermination(processHandle, &breakOnTermination); NtClose(processHandle); } - if (breakOnTermination != 0) + if (breakOnTermination) { critical = TRUE; dangerous = TRUE; @@ -3079,20 +3079,15 @@ BOOLEAN PhUiCloseHandles( if (WindowsVersion >= WINDOWS_10) { - ULONG breakOnTermination; + BOOLEAN breakOnTermination; PROCESS_MITIGATION_POLICY_INFORMATION policyInfo; - breakOnTermination = 0; - - if (NT_SUCCESS(NtQueryInformationProcess( + if (NT_SUCCESS(PhGetProcessBreakOnTermination( processHandle, - ProcessBreakOnTermination, - &breakOnTermination, - sizeof(ULONG), - NULL + &breakOnTermination ))) { - if (breakOnTermination != 0) + if (breakOnTermination) { critical = TRUE; } From 3a2f95566a3fe589787de77376974d667f5ac665 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 7 Oct 2018 13:23:41 +1100 Subject: [PATCH 1399/2058] Update KPH solution to latest WDK --- KProcessHacker/KProcessHacker.vcxproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/KProcessHacker/KProcessHacker.vcxproj b/KProcessHacker/KProcessHacker.vcxproj index 95ecf78472ad..e81758b6c06f 100644 --- a/KProcessHacker/KProcessHacker.vcxproj +++ b/KProcessHacker/KProcessHacker.vcxproj @@ -28,7 +28,7 @@ KProcessHacker $(VCTargetsPath11) - 10.0.17134.0 + 10.0.17763.0 WindowsKernelModeDriver10.0 From c453b3bc09ffa0966b8800a2a88027119a9c357f Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 7 Oct 2018 13:24:29 +1100 Subject: [PATCH 1400/2058] Fix format specifiers --- ProcessHacker/dbgcon.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ProcessHacker/dbgcon.c b/ProcessHacker/dbgcon.c index 684e336645bc..fb3ab9c3d56c 100644 --- a/ProcessHacker/dbgcon.c +++ b/ProcessHacker/dbgcon.c @@ -211,9 +211,9 @@ static VOID PhpPrintObjectInfo( else if (objectType == PhProcessItemType) { wprintf( - L"\t%.28s (%d)", + L"\t%.28s (%lu)", ((PPH_PROCESS_ITEM)object)->ProcessName->Buffer, - HandleToLong(((PPH_PROCESS_ITEM)object)->ProcessId) + HandleToUlong(((PPH_PROCESS_ITEM)object)->ProcessId) ); } else if (objectType == PhServiceItemType) @@ -222,7 +222,7 @@ static VOID PhpPrintObjectInfo( } else if (objectType == PhThreadItemType) { - wprintf(L"\tTID: %u", HandleToUlong(((PPH_THREAD_ITEM)object)->ThreadId)); + wprintf(L"\tTID: %lu", HandleToUlong(((PPH_THREAD_ITEM)object)->ThreadId)); } wprintf(L"\n"); From 9337f6f5f68219e0b2807abd0c2e0468950c8f0a Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 7 Oct 2018 13:25:09 +1100 Subject: [PATCH 1401/2058] Remove unused code --- ProcessHacker/hndlprp.c | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/ProcessHacker/hndlprp.c b/ProcessHacker/hndlprp.c index f09d8f6fa721..a08f5f9a9758 100644 --- a/ProcessHacker/hndlprp.c +++ b/ProcessHacker/hndlprp.c @@ -969,24 +969,11 @@ VOID PhpUpdateHandleGeneral( Context->HandleItem->Handle, NtCurrentProcess(), &dupHandle, - ProcessQueryAccess, + PROCESS_QUERY_LIMITED_INFORMATION, 0, 0 ); - if (!NT_SUCCESS(status)) - { - status = NtDuplicateObject( - processHandle, - Context->HandleItem->Handle, - NtCurrentProcess(), - &dupHandle, - PROCESS_QUERY_LIMITED_INFORMATION, - 0, - 0 - ); - } - NtClose(processHandle); } From d0df65377d9f205766f3d33334f6b4c83cd9b002 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 7 Oct 2018 14:34:08 +1100 Subject: [PATCH 1402/2058] Workaround weird Visual Studio KUSER_SHARED_DATA warning --- phnt/include/ntexapi.h | 20 +------------------- 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/phnt/include/ntexapi.h b/phnt/include/ntexapi.h index d79ae48eca0d..50637f58e152 100644 --- a/phnt/include/ntexapi.h +++ b/phnt/include/ntexapi.h @@ -3682,38 +3682,20 @@ typedef struct _KUSER_SHARED_DATA C_ASSERT(FIELD_OFFSET(KUSER_SHARED_DATA, TickCountMultiplier) == 0x4); C_ASSERT(FIELD_OFFSET(KUSER_SHARED_DATA, InterruptTime) == 0x8); C_ASSERT(FIELD_OFFSET(KUSER_SHARED_DATA, SystemTime) == 0x14); -C_ASSERT(FIELD_OFFSET(KUSER_SHARED_DATA, TimeZoneBias) == 0x20); -C_ASSERT(FIELD_OFFSET(KUSER_SHARED_DATA, ImageNumberLow) == 0x2c); -C_ASSERT(FIELD_OFFSET(KUSER_SHARED_DATA, ImageNumberHigh) == 0x2e); C_ASSERT(FIELD_OFFSET(KUSER_SHARED_DATA, NtSystemRoot) == 0x30); -C_ASSERT(FIELD_OFFSET(KUSER_SHARED_DATA, MaxStackTraceDepth) == 0x238); -C_ASSERT(FIELD_OFFSET(KUSER_SHARED_DATA, CryptoExponent) == 0x23c); -C_ASSERT(FIELD_OFFSET(KUSER_SHARED_DATA, TimeZoneId) == 0x240); C_ASSERT(FIELD_OFFSET(KUSER_SHARED_DATA, LargePageMinimum) == 0x244); C_ASSERT(FIELD_OFFSET(KUSER_SHARED_DATA, NtProductType) == 0x264); -C_ASSERT(FIELD_OFFSET(KUSER_SHARED_DATA, ProductTypeIsValid) == 0x268); C_ASSERT(FIELD_OFFSET(KUSER_SHARED_DATA, NtMajorVersion) == 0x26c); C_ASSERT(FIELD_OFFSET(KUSER_SHARED_DATA, NtMinorVersion) == 0x270); C_ASSERT(FIELD_OFFSET(KUSER_SHARED_DATA, ProcessorFeatures) == 0x274); -C_ASSERT(FIELD_OFFSET(KUSER_SHARED_DATA, Reserved1) == 0x2b4); -C_ASSERT(FIELD_OFFSET(KUSER_SHARED_DATA, Reserved3) == 0x2b8); -C_ASSERT(FIELD_OFFSET(KUSER_SHARED_DATA, TimeSlip) == 0x2bc); -C_ASSERT(FIELD_OFFSET(KUSER_SHARED_DATA, AlternativeArchitecture) == 0x2c0); -C_ASSERT(FIELD_OFFSET(KUSER_SHARED_DATA, SystemExpirationDate) == 0x2c8); -C_ASSERT(FIELD_OFFSET(KUSER_SHARED_DATA, SuiteMask) == 0x2d0); C_ASSERT(FIELD_OFFSET(KUSER_SHARED_DATA, KdDebuggerEnabled) == 0x2d4); C_ASSERT(FIELD_OFFSET(KUSER_SHARED_DATA, ActiveConsoleId) == 0x2d8); -C_ASSERT(FIELD_OFFSET(KUSER_SHARED_DATA, DismountCount) == 0x2dc); -C_ASSERT(FIELD_OFFSET(KUSER_SHARED_DATA, ComPlusPackage) == 0x2e0); -C_ASSERT(FIELD_OFFSET(KUSER_SHARED_DATA, LastSystemRITEventTickCount) == 0x2e4); C_ASSERT(FIELD_OFFSET(KUSER_SHARED_DATA, NumberOfPhysicalPages) == 0x2e8); C_ASSERT(FIELD_OFFSET(KUSER_SHARED_DATA, SafeBootMode) == 0x2ec); -C_ASSERT(FIELD_OFFSET(KUSER_SHARED_DATA, TestRetInstruction) == 0x2f8); -C_ASSERT(FIELD_OFFSET(KUSER_SHARED_DATA, SystemCallPad) == 0x310); C_ASSERT(FIELD_OFFSET(KUSER_SHARED_DATA, TickCount) == 0x320); C_ASSERT(FIELD_OFFSET(KUSER_SHARED_DATA, TickCountQuad) == 0x320); C_ASSERT(FIELD_OFFSET(KUSER_SHARED_DATA, XState) == 0x3d8); -C_ASSERT(sizeof(KUSER_SHARED_DATA) == 0x708); +//C_ASSERT(sizeof(KUSER_SHARED_DATA) == 0x70C); // VS2017 has some weird issue with this. #define USER_SHARED_DATA ((KUSER_SHARED_DATA * const)0x7ffe0000) From b43e2d58ba5a9f31a9321058277d711086ff1ac2 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 7 Oct 2018 14:34:31 +1100 Subject: [PATCH 1403/2058] Add ATOM_FLAG_GLOBAL --- phnt/include/ntexapi.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/phnt/include/ntexapi.h b/phnt/include/ntexapi.h index 50637f58e152..e8304137b0be 100644 --- a/phnt/include/ntexapi.h +++ b/phnt/include/ntexapi.h @@ -3912,6 +3912,9 @@ NtAddAtom( ); #if (PHNT_VERSION >= PHNT_WIN8) + +#define ATOM_FLAG_GLOBAL 0x2 + // rev NTSYSCALLAPI NTSTATUS @@ -3922,6 +3925,7 @@ NtAddAtomEx( _Out_opt_ PRTL_ATOM Atom, _In_ ULONG Flags ); + #endif NTSYSCALLAPI From 4169f1f39b74cde68ddc2ffa93d70230e16a2b50 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 7 Oct 2018 23:47:51 +1100 Subject: [PATCH 1404/2058] Update Microsoft Edge tooltips for RS5 --- ProcessHacker/appsup.c | 7 +++++-- ProcessHacker/itemtips.c | 7 ++++++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/ProcessHacker/appsup.c b/ProcessHacker/appsup.c index dadbad516034..f7d7b524d373 100644 --- a/ProcessHacker/appsup.c +++ b/ProcessHacker/appsup.c @@ -379,11 +379,14 @@ PH_KNOWN_PROCESS_TYPE PhGetProcessKnownTypeEx( knownProcessType = UmdfHostProcessType; else if (PhEqualStringRef2(&name, L"\\wbem\\WmiPrvSE.exe", TRUE)) knownProcessType = WmiProviderHostType; + else if (PhEqualStringRef2(&name, L"\\MicrosoftEdgeCP.exe", TRUE)) // RS5 + knownProcessType = EdgeProcessType; + else if (PhEqualStringRef2(&name, L"\\MicrosoftEdgeSH.exe", TRUE)) // RS5 + knownProcessType = EdgeProcessType; } else { - // Microsoft Edge - if (PhEndsWithStringRef2(&name, L"\\MicrosoftEdgeCP.exe", TRUE)) + if (PhEndsWithStringRef2(&name, L"\\MicrosoftEdgeCP.exe", TRUE)) // RS4 knownProcessType = EdgeProcessType; else if (PhEndsWithStringRef2(&name, L"\\MicrosoftEdge.exe", TRUE)) knownProcessType = EdgeProcessType; diff --git a/ProcessHacker/itemtips.c b/ProcessHacker/itemtips.c index 61e1db6eff6f..a80318aca421 100644 --- a/ProcessHacker/itemtips.c +++ b/ProcessHacker/itemtips.c @@ -709,6 +709,7 @@ VOID PhpFillMicrosoftEdge( if (appContainerSid) { + static PH_STRINGREF managerSid = PH_STRINGREF_INIT(L"S-1-15-2-3624051433-2125758914-1423191267-1740899205-1073925389-3782572162-737981194"); static PH_STRINGREF extensionsSid = PH_STRINGREF_INIT(L"S-1-15-2-3624051433-2125758914-1423191267-1740899205-1073925389-3782572162-737981194-1206159417-1570029349-2913729690-1184509225"); static PH_STRINGREF serviceUiSid = PH_STRINGREF_INIT(L"S-1-15-2-3624051433-2125758914-1423191267-1740899205-1073925389-3782572162-737981194-3513710562-3729412521-1863153555-1462103995"); static PH_STRINGREF chakraJitSid = PH_STRINGREF_INIT(L"S-1-15-2-3624051433-2125758914-1423191267-1740899205-1073925389-3782572162-737981194-1821068571-1793888307-623627345-1529106238"); @@ -717,7 +718,11 @@ VOID PhpFillMicrosoftEdge( static PH_STRINGREF backgroundTabPool2Sid = PH_STRINGREF_INIT(L"S-1-15-2-3624051433-2125758914-1423191267-1740899205-1073925389-3782572162-737981194-2385269614-3243675-834220592-3047885450"); static PH_STRINGREF backgroundTabPool3Sid = PH_STRINGREF_INIT(L"S-1-15-2-3624051433-2125758914-1423191267-1740899205-1073925389-3782572162-737981194-355265979-2879959831-980936148-1241729999"); - if (PhEqualStringRef(&appContainerSid->sr, &extensionsSid, FALSE)) + if (PhEqualStringRef(&appContainerSid->sr, &managerSid, FALSE)) + { + PhAppendStringBuilder2(Containers, L" Microsoft Edge Manager\n"); + } + else if (PhEqualStringRef(&appContainerSid->sr, &extensionsSid, FALSE)) { PhAppendStringBuilder2(Containers, L" Browser Extensions\n"); } From 41afe7034beb7506e18348da6660077e18486f55 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 8 Oct 2018 00:25:12 +1100 Subject: [PATCH 1405/2058] Remove unused (and broken) splitter control --- ProcessHacker/splitter.c | 423 --------------------------------------- 1 file changed, 423 deletions(-) delete mode 100644 ProcessHacker/splitter.c diff --git a/ProcessHacker/splitter.c b/ProcessHacker/splitter.c deleted file mode 100644 index 7ba2d0246737..000000000000 --- a/ProcessHacker/splitter.c +++ /dev/null @@ -1,423 +0,0 @@ -/* - * Process Hacker - - * Splitter control - * - * Copyright (C) 2017 dmex - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - * - */ - -#include -#include -#include - -#define SPLITTER_PADDING 6 - -typedef struct _PH_HSPLITTER_CONTEXT -{ - union - { - ULONG Flags; - struct - { - ULONG Hot : 1; - ULONG HasFocus : 1; - ULONG Spare : 30; - }; - }; - - LONG SplitterOffset; - - HWND WindowHandle; - HWND ParentWindow; - HWND TopWindow; - HWND BottomWindow; - WNDPROC DefaultWindowProc; - - HBRUSH FocusBrush; - HBRUSH HotBrush; - HBRUSH NormalBrush; - - PPH_STRING SettingName; -} PH_HSPLITTER_CONTEXT, *PPH_HSPLITTER_CONTEXT; - -VOID PhDeleteHSplitter( - _Inout_ PPH_HSPLITTER_CONTEXT Context - ); - -VOID PhHSplitterHandleWmSize( - _Inout_ PPH_HSPLITTER_CONTEXT Context, - _In_ INT Width, - _In_ INT Height - ); - -LONG GetWindowWidth(HWND hwnd) -{ - RECT Rect; - - GetWindowRect(hwnd, &Rect); - return (Rect.right - Rect.left); -} - -LONG GetWindowHeight(HWND hwnd) -{ - RECT Rect; - - GetWindowRect(hwnd, &Rect); - return (Rect.bottom - Rect.top); -} - -LONG GetClientWindowWidth(HWND hwnd) -{ - RECT Rect; - - GetClientRect(hwnd, &Rect); - return (Rect.right - Rect.left); -} - -LONG GetClientWindowHeight(HWND hwnd) -{ - RECT Rect; - - GetClientRect(hwnd, &Rect); - return (Rect.bottom - Rect.top); -} - -LRESULT CALLBACK HSplitterWindowProc( - _In_ HWND hwnd, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - PPH_HSPLITTER_CONTEXT context = NULL; - - if (uMsg == WM_CREATE) - { - LPCREATESTRUCT cs = (LPCREATESTRUCT)lParam; - context = cs->lpCreateParams; - PhSetWindowContext(hwnd, PH_WINDOW_CONTEXT_DEFAULT, context); - } - else - { - context = PhGetWindowContext(hwnd, PH_WINDOW_CONTEXT_DEFAULT); - - if (uMsg == WM_DESTROY) - { - PhRemoveWindowContext(hwnd, PH_WINDOW_CONTEXT_DEFAULT); - } - } - - if (!context) - return DefWindowProc(hwnd, uMsg, wParam, lParam); - - switch (uMsg) - { - case WM_PAINT: - { - PAINTSTRUCT paintStruct; - RECT clientRect; - HDC hdc; - - if (hdc = BeginPaint(hwnd, &paintStruct)) - { - GetClientRect(hwnd, &clientRect); - - if (context->HasFocus) - FillRect(hdc, &clientRect, context->FocusBrush); - else if (context->Hot) - FillRect(hdc, &clientRect, context->HotBrush); - else - FillRect(hdc, &clientRect, context->NormalBrush); - - EndPaint(hwnd, &paintStruct); - } - } - return 1; - case WM_ERASEBKGND: - return 1; - case WM_LBUTTONDOWN: - { - context->HasFocus = TRUE; - - SetCapture(hwnd); - - InvalidateRect(hwnd, NULL, TRUE); - } - break; - case WM_LBUTTONUP: - case WM_RBUTTONDOWN: - { - if (GetCapture() == hwnd) - { - ReleaseCapture(); - - context->HasFocus = FALSE; - - InvalidateRect(hwnd, NULL, TRUE); - } - } - break; - case WM_MOUSELEAVE: - { - context->Hot = FALSE; - InvalidateRect(hwnd, NULL, TRUE); - } - break; - case WM_SETFOCUS: - { - context->HasFocus = TRUE; - InvalidateRect(hwnd, NULL, TRUE); - } - return 0; - case WM_KILLFOCUS: - { - context->HasFocus = FALSE; - InvalidateRect(hwnd, NULL, TRUE); - } - return 0; - case WM_MOUSEMOVE: - { - INT width; - INT height; - INT NewPos; - HDWP deferHandle; - POINT cursorPos; - - if (!context->Hot) - { - TRACKMOUSEEVENT trackMouseEvent = { sizeof(trackMouseEvent) }; - context->Hot = TRUE; - InvalidateRect(hwnd, NULL, TRUE); - trackMouseEvent.dwFlags = TME_LEAVE; - trackMouseEvent.hwndTrack = hwnd; - TrackMouseEvent(&trackMouseEvent); - } - - if (!context->HasFocus) - break; - - GetCursorPos(&cursorPos); - ScreenToClient(context->ParentWindow, &cursorPos); - NewPos = cursorPos.y; - width = GetClientWindowWidth(context->ParentWindow); - height = GetClientWindowHeight(context->ParentWindow); - - if (NewPos < 200) - break; - if (NewPos > height - 80) - break; - - context->SplitterOffset = NewPos; - - deferHandle = BeginDeferWindowPos(3); - DeferWindowPos( - deferHandle, - context->TopWindow, - NULL, - SPLITTER_PADDING, - 90, - width - SPLITTER_PADDING * 2, - cursorPos.y - 90, - SWP_NOZORDER | SWP_NOACTIVATE - ); - DeferWindowPos( - deferHandle, - context->WindowHandle, - NULL, - 0, - cursorPos.y, - width, - SPLITTER_PADDING, - SWP_NOZORDER | SWP_NOACTIVATE - ); - DeferWindowPos( - deferHandle, - context->BottomWindow, - NULL, - SPLITTER_PADDING, - cursorPos.y + SPLITTER_PADDING, - width - SPLITTER_PADDING * 2, - height - (cursorPos.y + SPLITTER_PADDING) - 65, - SWP_NOZORDER | SWP_NOACTIVATE - ); - - EndDeferWindowPos(deferHandle); - } - break; - } - - return DefWindowProc(hwnd, uMsg, wParam, lParam); -} - -LRESULT CALLBACK HSplitterParentWindowProc( - _In_ HWND hwnd, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - PPH_HSPLITTER_CONTEXT context; - WNDPROC oldWndProc; - - if (!(context = PhGetWindowContext(hwnd, 0x200))) - return 0; - - oldWndProc = context->DefaultWindowProc; - - switch (uMsg) - { - case WM_DESTROY: - { - SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)oldWndProc); - PhRemoveWindowContext(hwnd, 0x200); - - PhDeleteHSplitter(context); - } - break; - case WM_SIZE: - { - PhHSplitterHandleWmSize(context, LOWORD(lParam), HIWORD(lParam)); - } - break; - } - - return CallWindowProc(oldWndProc, hwnd, uMsg, wParam, lParam); -} - -VOID PhInitializeHSplitter( - _In_ PWSTR SettingName, - _In_ HWND ParentWindow, - _In_ HWND TopWindow, - _In_ HWND BottomWindow - ) -{ - static PH_INITONCE initOnce = PH_INITONCE_INIT; - PPH_HSPLITTER_CONTEXT context; - - context = PhAllocate(sizeof(PH_HSPLITTER_CONTEXT)); - memset(context, 0, sizeof(PH_HSPLITTER_CONTEXT)); - - context->SettingName = PhCreateString(SettingName); - context->ParentWindow = ParentWindow; - context->TopWindow = TopWindow; - context->BottomWindow = BottomWindow; - context->SplitterOffset = PhGetIntegerSetting(SettingName); - context->FocusBrush = CreateSolidBrush(RGB(0x0, 0x0, 0x0)); - context->HotBrush = CreateSolidBrush(RGB(0x44, 0x44, 0x44)); - context->NormalBrush = GetSysColorBrush(COLOR_WINDOW); - - if (PhBeginInitOnce(&initOnce)) - { - WNDCLASSEX c = { sizeof(c) }; - - c.style = CS_GLOBALCLASS; - c.lpfnWndProc = HSplitterWindowProc; - c.cbClsExtra = 0; - c.cbWndExtra = sizeof(PVOID); - c.hInstance = PhInstanceHandle; - c.hIcon = NULL; - c.hCursor = LoadCursor(NULL, IDC_SIZENS); - c.hbrBackground = NULL; - c.lpszMenuName = NULL; - c.lpszClassName = L"PhHSplitter"; - c.hIconSm = NULL; - - RegisterClassEx(&c); - - PhEndInitOnce(&initOnce); - } - - context->WindowHandle = CreateWindowEx( - WS_EX_TRANSPARENT, - L"PhHSplitter", - NULL, - WS_CHILD | WS_VISIBLE, - 5, - 5, - 5, - 5, - ParentWindow, - NULL, - PhInstanceHandle, - context - ); - - ShowWindow(context->WindowHandle, SW_SHOW); - UpdateWindow(context->WindowHandle); - - context->DefaultWindowProc = (WNDPROC)GetWindowLongPtr(ParentWindow, GWLP_WNDPROC); - PhSetWindowContext(ParentWindow, 0x200, context); - SetWindowLongPtr(ParentWindow, GWLP_WNDPROC, (LONG_PTR)HSplitterParentWindowProc); -} - -VOID PhDeleteHSplitter( - _Inout_ PPH_HSPLITTER_CONTEXT Context - ) -{ - PhSetIntegerSetting(PhGetString(Context->SettingName), Context->SplitterOffset); - PhDereferenceObject(Context->SettingName); - - if (Context->FocusBrush) - DeleteObject(Context->FocusBrush); - if (Context->HotBrush) - DeleteObject(Context->HotBrush); -} - -VOID PhHSplitterHandleWmSize( - _Inout_ PPH_HSPLITTER_CONTEXT Context, - _In_ INT Width, - _In_ INT Height - ) -{ - HDWP deferHandle; - - deferHandle = BeginDeferWindowPos(3); - DeferWindowPos( - deferHandle, - Context->TopWindow, - NULL, - SPLITTER_PADDING, - 90, - Width - SPLITTER_PADDING * 2, - Context->SplitterOffset - 90 - 65, - SWP_NOZORDER | SWP_NOACTIVATE - ); - - DeferWindowPos( - deferHandle, - Context->WindowHandle, - NULL, - 0, - Context->SplitterOffset - 65, - Width, - SPLITTER_PADDING, - SWP_NOZORDER | SWP_NOACTIVATE - ); - - DeferWindowPos( - deferHandle, - Context->BottomWindow, - NULL, - SPLITTER_PADDING, - Context->SplitterOffset + SPLITTER_PADDING - 65, - Width - SPLITTER_PADDING * 2, - GetClientWindowHeight(Context->ParentWindow) - (Context->SplitterOffset + SPLITTER_PADDING), - SWP_NOZORDER | SWP_NOACTIVATE - ); - EndDeferWindowPos(deferHandle); -} \ No newline at end of file From 45bf4b9ec525caa46143df09dd9de80ee30a6f10 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 8 Oct 2018 11:21:48 +1100 Subject: [PATCH 1406/2058] Add missing files from previous commit --- ProcessHacker/ProcessHacker.vcxproj | 1 - ProcessHacker/ProcessHacker.vcxproj.filters | 3 --- 2 files changed, 4 deletions(-) diff --git a/ProcessHacker/ProcessHacker.vcxproj b/ProcessHacker/ProcessHacker.vcxproj index 7d6bb999e400..2896a1a4087c 100644 --- a/ProcessHacker/ProcessHacker.vcxproj +++ b/ProcessHacker/ProcessHacker.vcxproj @@ -340,7 +340,6 @@ - diff --git a/ProcessHacker/ProcessHacker.vcxproj.filters b/ProcessHacker/ProcessHacker.vcxproj.filters index dbc7c34f8115..68d8b04b9cfa 100644 --- a/ProcessHacker/ProcessHacker.vcxproj.filters +++ b/ProcessHacker/ProcessHacker.vcxproj.filters @@ -375,9 +375,6 @@ Process Hacker - - Process Hacker - Process Hacker From 131c5b6b523c8479b5300ee677ffb675151406fe Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 8 Oct 2018 11:23:16 +1100 Subject: [PATCH 1407/2058] Use correct PhCallNtQueryFileInformationWithTimeout parameters --- phlib/hndlinfo.c | 30 +++++++++++++++++++----------- phlib/include/hndlinfo.h | 6 +++--- 2 files changed, 22 insertions(+), 14 deletions(-) diff --git a/phlib/hndlinfo.c b/phlib/hndlinfo.c index 2348bf4284eb..5874192d9594 100644 --- a/phlib/hndlinfo.c +++ b/phlib/hndlinfo.c @@ -78,6 +78,14 @@ typedef struct _PHP_QUERY_OBJECT_COMMON_CONTEXT SECURITY_INFORMATION SecurityInformation; PSECURITY_DESCRIPTOR SecurityDescriptor; } NtSetSecurityObject; + struct + { + HANDLE Handle; + FILE_INFORMATION_CLASS FileInformationClass; + PVOID FileInformation; + ULONG FileInformationLength; + PULONG ReturnLength; + } NtQueryFileInformation; } u; } PHP_QUERY_OBJECT_COMMON_CONTEXT, *PPHP_QUERY_OBJECT_COMMON_CONTEXT; @@ -1706,11 +1714,11 @@ NTSTATUS PhpCommonQueryObjectRoutine( IO_STATUS_BLOCK isb; context->Status = NtQueryInformationFile( - context->u.NtQueryObject.Handle, + context->u.NtQueryFileInformation.Handle, &isb, - context->u.NtQueryObject.ObjectInformation, - context->u.NtQueryObject.ObjectInformationLength, - context->u.NtQueryObject.ObjectInformationClass + context->u.NtQueryFileInformation.FileInformation, + context->u.NtQueryFileInformation.FileInformationLength, + context->u.NtQueryFileInformation.FileInformationClass ); } break; @@ -1804,9 +1812,9 @@ NTSTATUS PhCallNtSetSecurityObjectWithTimeout( NTSTATUS PhCallNtQueryFileInformationWithTimeout( _In_ HANDLE Handle, - _In_ OBJECT_INFORMATION_CLASS ObjectInformationClass, - _Out_writes_bytes_opt_(ObjectInformationLength) PVOID ObjectInformation, - _In_ ULONG ObjectInformationLength + _In_ FILE_INFORMATION_CLASS FileInformationClass, + _Out_writes_bytes_opt_(FileInformationLength) PVOID FileInformation, + _In_ ULONG FileInformationLength ) { PPHP_QUERY_OBJECT_COMMON_CONTEXT context; @@ -1814,10 +1822,10 @@ NTSTATUS PhCallNtQueryFileInformationWithTimeout( context = PhAllocate(sizeof(PHP_QUERY_OBJECT_COMMON_CONTEXT)); context->Work = NtQueryFileInformationWork; context->Status = STATUS_UNSUCCESSFUL; - context->u.NtQueryObject.Handle = Handle; - context->u.NtQueryObject.ObjectInformationClass = ObjectInformationClass; - context->u.NtQueryObject.ObjectInformation = ObjectInformation; - context->u.NtQueryObject.ObjectInformationLength = ObjectInformationLength; + context->u.NtQueryFileInformation.Handle = Handle; + context->u.NtQueryFileInformation.FileInformationClass = FileInformationClass; + context->u.NtQueryFileInformation.FileInformation = FileInformation; + context->u.NtQueryFileInformation.FileInformationLength = FileInformationLength; return PhpCommonQueryObjectWithTimeout(context); } diff --git a/phlib/include/hndlinfo.h b/phlib/include/hndlinfo.h index 8c81c27a26cd..48f3312cf48f 100644 --- a/phlib/include/hndlinfo.h +++ b/phlib/include/hndlinfo.h @@ -136,9 +136,9 @@ NTSTATUS NTAPI PhCallNtQueryFileInformationWithTimeout( _In_ HANDLE Handle, - _In_ OBJECT_INFORMATION_CLASS ObjectInformationClass, - _Out_writes_bytes_opt_(ObjectInformationLength) PVOID ObjectInformation, - _In_ ULONG ObjectInformationLength + _In_ FILE_INFORMATION_CLASS FileInformationClass, + _Out_writes_bytes_opt_(FileInformationLength) PVOID FileInformation, + _In_ ULONG FileInformationLength ); #ifdef __cplusplus From 1a6d6df5eebf207ab261ef76af02e17246fc23dd Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 8 Oct 2018 11:28:36 +1100 Subject: [PATCH 1408/2058] Remove unused parameter --- ProcessHacker/hndlprp.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/ProcessHacker/hndlprp.c b/ProcessHacker/hndlprp.c index a08f5f9a9758..af68899ec54a 100644 --- a/ProcessHacker/hndlprp.c +++ b/ProcessHacker/hndlprp.c @@ -584,7 +584,6 @@ VOID PhpUpdateHandleGeneral( if (PhEqualString2(Context->HandleItem->TypeName, L"ALPC Port", TRUE)) { - PHANDLE_PROPERTIES_CONTEXT context = Context; NTSTATUS status; HANDLE processHandle; HANDLE alpcPortHandle; @@ -637,7 +636,6 @@ VOID PhpUpdateHandleGeneral( } else if (PhEqualStringRef2(&Context->HandleItem->TypeName->sr, L"File", TRUE)) { - PHANDLE_PROPERTIES_CONTEXT context = Context; NTSTATUS status; HANDLE processHandle; HANDLE fileHandle; @@ -825,7 +823,6 @@ VOID PhpUpdateHandleGeneral( } else if (PhEqualStringRef2(&Context->HandleItem->TypeName->sr, L"Section", TRUE)) { - PHANDLE_PROPERTIES_CONTEXT context = Context; NTSTATUS status; HANDLE processHandle; HANDLE sectionHandle; @@ -902,7 +899,6 @@ VOID PhpUpdateHandleGeneral( } else if (PhEqualString2(Context->HandleItem->TypeName, L"Mutant", TRUE)) { - PHANDLE_PROPERTIES_CONTEXT context = Context; NTSTATUS status; HANDLE processHandle; HANDLE mutantHandle; @@ -953,7 +949,6 @@ VOID PhpUpdateHandleGeneral( } else if (PhEqualString2(Context->HandleItem->TypeName, L"Process", TRUE)) { - PHANDLE_PROPERTIES_CONTEXT context = Context; NTSTATUS status; HANDLE processHandle; HANDLE dupHandle; From 68d70bc05745f7217a7feb90bcdebcf4142e2d21 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 8 Oct 2018 15:38:55 +1100 Subject: [PATCH 1409/2058] Remove unused handle, Add missing check for critical menu --- ProcessHacker/mwpgproc.c | 36 ++++++++++++++++++++++-------------- ProcessHacker/prpgenv.c | 27 +++++++++++++++++---------- ProcessHacker/thrdprv.c | 2 +- phlib/include/symprv.h | 11 +---------- phlib/phlib.vcxproj | 22 ++++++++++++---------- 5 files changed, 53 insertions(+), 45 deletions(-) diff --git a/ProcessHacker/mwpgproc.c b/ProcessHacker/mwpgproc.c index 666561520c0c..4bddffc164c5 100644 --- a/ProcessHacker/mwpgproc.c +++ b/ProcessHacker/mwpgproc.c @@ -550,6 +550,23 @@ VOID PhMwpInitializeProcessMenu( { PhEnableEMenuItem(Menu, ID_PROCESS_OPENFILELOCATION, FALSE); } + + // Critical + if (Processes[0]->QueryHandle) + { + BOOLEAN breakOnTermination; + + if (NT_SUCCESS(PhGetProcessBreakOnTermination( + Processes[0]->QueryHandle, + &breakOnTermination + ))) + { + if (breakOnTermination) + { + PhSetFlagsEMenuItem(Menu, ID_MISCELLANEOUS_SETCRITICAL, PH_EMENU_CHECKED, PH_EMENU_CHECKED); + } + } + } } else { @@ -607,19 +624,14 @@ VOID PhMwpInitializeProcessMenu( // Virtualization if (NumberOfProcesses == 1) { - HANDLE processHandle; HANDLE tokenHandle; BOOLEAN allowed = FALSE; BOOLEAN enabled = FALSE; - if (NT_SUCCESS(PhOpenProcess( - &processHandle, - ProcessQueryAccess, - Processes[0]->ProcessId - ))) + if (Processes[0]->QueryHandle) { if (NT_SUCCESS(PhOpenProcessToken( - processHandle, + Processes[0]->QueryHandle, TOKEN_QUERY, &tokenHandle ))) @@ -630,8 +642,6 @@ VOID PhMwpInitializeProcessMenu( NtClose(tokenHandle); } - - NtClose(processHandle); } if (!allowed) @@ -646,14 +656,12 @@ VOID PhMwpInitializeProcessMenu( PhMwpSetProcessMenuPriorityChecks(Menu, Processes[0]->ProcessId, TRUE, TRUE, TRUE); } - item = PhFindEMenuItem(Menu, 0, L"Window", 0); - - if (item) + // Window menu + if (item = PhFindEMenuItem(Menu, 0, L"Window", 0)) { - // Window menu if (NumberOfProcesses == 1) { - WINDOWPLACEMENT placement = { sizeof(placement) }; + WINDOWPLACEMENT placement = { sizeof(WINDOWPLACEMENT) }; // Get a handle to the process' top-level window (if any). PhMwpSelectedProcessWindowHandle = PhGetProcessMainWindow(Processes[0]->ProcessId, Processes[0]->QueryHandle); diff --git a/ProcessHacker/prpgenv.c b/ProcessHacker/prpgenv.c index 595fdb7ebaa5..cc97db3c3c10 100644 --- a/ProcessHacker/prpgenv.c +++ b/ProcessHacker/prpgenv.c @@ -169,15 +169,19 @@ VOID PhpRefreshEnvironmentList( userRootNode = PhpAddEnvironmentChildNode(Context, NULL, 0, 0, PhaCreateString(L"User"), NULL); systemRootNode = PhpAddEnvironmentChildNode(Context, NULL, 0, 0, PhaCreateString(L"System"), NULL); - if (DestroyEnvironmentBlock && Context->SystemDefaultEnvironment) - DestroyEnvironmentBlock(Context->SystemDefaultEnvironment); - if (DestroyEnvironmentBlock && Context->UserDefaultEnvironment) - DestroyEnvironmentBlock(Context->UserDefaultEnvironment); + if (DestroyEnvironmentBlock) + { + if (Context->SystemDefaultEnvironment) + DestroyEnvironmentBlock(Context->SystemDefaultEnvironment); + if (Context->UserDefaultEnvironment) + DestroyEnvironmentBlock(Context->UserDefaultEnvironment); + } - if (CreateEnvironmentBlock) + if (CreateEnvironmentBlock) + { CreateEnvironmentBlock(&Context->SystemDefaultEnvironment, NULL, FALSE); - if (CreateEnvironmentBlock) CreateEnvironmentBlock(&Context->UserDefaultEnvironment, PhGetOwnTokenAttributes().TokenHandle, FALSE); + } if (NT_SUCCESS(PhOpenProcess( &processHandle, @@ -1302,10 +1306,13 @@ INT_PTR CALLBACK PhpProcessEnvironmentDlgProc( PhDeleteArray(&context->Items); PhClearReference(&context->StatusMessage); - if (DestroyEnvironmentBlock && context->SystemDefaultEnvironment) - DestroyEnvironmentBlock(context->SystemDefaultEnvironment); - if (DestroyEnvironmentBlock && context->UserDefaultEnvironment) - DestroyEnvironmentBlock(context->UserDefaultEnvironment); + if (DestroyEnvironmentBlock) + { + if (context->SystemDefaultEnvironment) + DestroyEnvironmentBlock(context->SystemDefaultEnvironment); + if (context->UserDefaultEnvironment) + DestroyEnvironmentBlock(context->UserDefaultEnvironment); + } PhFree(context); } diff --git a/ProcessHacker/thrdprv.c b/ProcessHacker/thrdprv.c index 842f70f2b5b4..974e05ca520f 100644 --- a/ProcessHacker/thrdprv.c +++ b/ProcessHacker/thrdprv.c @@ -95,7 +95,7 @@ PH_WORK_QUEUE PhThreadProviderWorkQueue; PH_INITONCE PhThreadProviderWorkQueueInitOnce = PH_INITONCE_INIT; VOID PhpQueueThreadWorkQueueItem( - _In_ PTHREAD_START_ROUTINE Function, + _In_ PUSER_THREAD_START_ROUTINE Function, _In_opt_ PVOID Context ) { diff --git a/phlib/include/symprv.h b/phlib/include/symprv.h index fb90c18386a5..302abe97562a 100644 --- a/phlib/include/symprv.h +++ b/phlib/include/symprv.h @@ -54,18 +54,9 @@ typedef struct _PH_SYMBOL_LINE_INFORMATION ULONG64 Address; } PH_SYMBOL_LINE_INFORMATION, *PPH_SYMBOL_LINE_INFORMATION; -typedef enum _PH_SYMBOL_EVENT_TYPE -{ - SymbolDeferredSymbolLoadStart = 1, - SymbolDeferredSymbolLoadComplete = 2, - SymbolDeferredSymbolLoadFailure = 3, - SymbolSymbolsUnloaded = 4, - SymbolDeferredSymbolLoadCancel = 7 -} PH_SYMBOL_EVENT_TYPE; - typedef struct _PH_SYMBOL_EVENT_DATA { - PH_SYMBOL_EVENT_TYPE ActionCode; + ULONG ActionCode; HANDLE ProcessHandle; PPH_SYMBOL_PROVIDER SymbolProvider; PVOID EventData; diff --git a/phlib/phlib.vcxproj b/phlib/phlib.vcxproj index 40147221b2be..87ed594736f5 100644 --- a/phlib/phlib.vcxproj +++ b/phlib/phlib.vcxproj @@ -29,25 +29,27 @@ StaticLibrary Unicode true - v141 - Spectre + llvm + false StaticLibrary Unicode - v141 + llvm + false StaticLibrary Unicode true - v141 - Spectre + llvm + false StaticLibrary Unicode - v141 + llvm + false @@ -86,7 +88,7 @@ Level3 ProgramDatabase StdCall - true + false true @@ -104,7 +106,7 @@ Level3 ProgramDatabase StdCall - true + false true @@ -123,7 +125,7 @@ Level3 ProgramDatabase StdCall - true + false true StreamingSIMDExtensions Guard @@ -144,7 +146,7 @@ Level3 ProgramDatabase StdCall - true + false true Guard From 3a0803fd248b1d724c6e94824589ee8b6966fa77 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 8 Oct 2018 16:22:41 +1100 Subject: [PATCH 1410/2058] Revert "Remove unused handle, Add missing check for critical menu" This reverts commit 68d70bc05745f7217a7feb90bcdebcf4142e2d21. --- ProcessHacker/mwpgproc.c | 36 ++++++++++++++---------------------- ProcessHacker/prpgenv.c | 27 ++++++++++----------------- ProcessHacker/thrdprv.c | 2 +- phlib/include/symprv.h | 11 ++++++++++- phlib/phlib.vcxproj | 22 ++++++++++------------ 5 files changed, 45 insertions(+), 53 deletions(-) diff --git a/ProcessHacker/mwpgproc.c b/ProcessHacker/mwpgproc.c index 4bddffc164c5..666561520c0c 100644 --- a/ProcessHacker/mwpgproc.c +++ b/ProcessHacker/mwpgproc.c @@ -550,23 +550,6 @@ VOID PhMwpInitializeProcessMenu( { PhEnableEMenuItem(Menu, ID_PROCESS_OPENFILELOCATION, FALSE); } - - // Critical - if (Processes[0]->QueryHandle) - { - BOOLEAN breakOnTermination; - - if (NT_SUCCESS(PhGetProcessBreakOnTermination( - Processes[0]->QueryHandle, - &breakOnTermination - ))) - { - if (breakOnTermination) - { - PhSetFlagsEMenuItem(Menu, ID_MISCELLANEOUS_SETCRITICAL, PH_EMENU_CHECKED, PH_EMENU_CHECKED); - } - } - } } else { @@ -624,14 +607,19 @@ VOID PhMwpInitializeProcessMenu( // Virtualization if (NumberOfProcesses == 1) { + HANDLE processHandle; HANDLE tokenHandle; BOOLEAN allowed = FALSE; BOOLEAN enabled = FALSE; - if (Processes[0]->QueryHandle) + if (NT_SUCCESS(PhOpenProcess( + &processHandle, + ProcessQueryAccess, + Processes[0]->ProcessId + ))) { if (NT_SUCCESS(PhOpenProcessToken( - Processes[0]->QueryHandle, + processHandle, TOKEN_QUERY, &tokenHandle ))) @@ -642,6 +630,8 @@ VOID PhMwpInitializeProcessMenu( NtClose(tokenHandle); } + + NtClose(processHandle); } if (!allowed) @@ -656,12 +646,14 @@ VOID PhMwpInitializeProcessMenu( PhMwpSetProcessMenuPriorityChecks(Menu, Processes[0]->ProcessId, TRUE, TRUE, TRUE); } - // Window menu - if (item = PhFindEMenuItem(Menu, 0, L"Window", 0)) + item = PhFindEMenuItem(Menu, 0, L"Window", 0); + + if (item) { + // Window menu if (NumberOfProcesses == 1) { - WINDOWPLACEMENT placement = { sizeof(WINDOWPLACEMENT) }; + WINDOWPLACEMENT placement = { sizeof(placement) }; // Get a handle to the process' top-level window (if any). PhMwpSelectedProcessWindowHandle = PhGetProcessMainWindow(Processes[0]->ProcessId, Processes[0]->QueryHandle); diff --git a/ProcessHacker/prpgenv.c b/ProcessHacker/prpgenv.c index cc97db3c3c10..595fdb7ebaa5 100644 --- a/ProcessHacker/prpgenv.c +++ b/ProcessHacker/prpgenv.c @@ -169,19 +169,15 @@ VOID PhpRefreshEnvironmentList( userRootNode = PhpAddEnvironmentChildNode(Context, NULL, 0, 0, PhaCreateString(L"User"), NULL); systemRootNode = PhpAddEnvironmentChildNode(Context, NULL, 0, 0, PhaCreateString(L"System"), NULL); - if (DestroyEnvironmentBlock) - { - if (Context->SystemDefaultEnvironment) - DestroyEnvironmentBlock(Context->SystemDefaultEnvironment); - if (Context->UserDefaultEnvironment) - DestroyEnvironmentBlock(Context->UserDefaultEnvironment); - } + if (DestroyEnvironmentBlock && Context->SystemDefaultEnvironment) + DestroyEnvironmentBlock(Context->SystemDefaultEnvironment); + if (DestroyEnvironmentBlock && Context->UserDefaultEnvironment) + DestroyEnvironmentBlock(Context->UserDefaultEnvironment); - if (CreateEnvironmentBlock) - { + if (CreateEnvironmentBlock) CreateEnvironmentBlock(&Context->SystemDefaultEnvironment, NULL, FALSE); + if (CreateEnvironmentBlock) CreateEnvironmentBlock(&Context->UserDefaultEnvironment, PhGetOwnTokenAttributes().TokenHandle, FALSE); - } if (NT_SUCCESS(PhOpenProcess( &processHandle, @@ -1306,13 +1302,10 @@ INT_PTR CALLBACK PhpProcessEnvironmentDlgProc( PhDeleteArray(&context->Items); PhClearReference(&context->StatusMessage); - if (DestroyEnvironmentBlock) - { - if (context->SystemDefaultEnvironment) - DestroyEnvironmentBlock(context->SystemDefaultEnvironment); - if (context->UserDefaultEnvironment) - DestroyEnvironmentBlock(context->UserDefaultEnvironment); - } + if (DestroyEnvironmentBlock && context->SystemDefaultEnvironment) + DestroyEnvironmentBlock(context->SystemDefaultEnvironment); + if (DestroyEnvironmentBlock && context->UserDefaultEnvironment) + DestroyEnvironmentBlock(context->UserDefaultEnvironment); PhFree(context); } diff --git a/ProcessHacker/thrdprv.c b/ProcessHacker/thrdprv.c index 974e05ca520f..842f70f2b5b4 100644 --- a/ProcessHacker/thrdprv.c +++ b/ProcessHacker/thrdprv.c @@ -95,7 +95,7 @@ PH_WORK_QUEUE PhThreadProviderWorkQueue; PH_INITONCE PhThreadProviderWorkQueueInitOnce = PH_INITONCE_INIT; VOID PhpQueueThreadWorkQueueItem( - _In_ PUSER_THREAD_START_ROUTINE Function, + _In_ PTHREAD_START_ROUTINE Function, _In_opt_ PVOID Context ) { diff --git a/phlib/include/symprv.h b/phlib/include/symprv.h index 302abe97562a..fb90c18386a5 100644 --- a/phlib/include/symprv.h +++ b/phlib/include/symprv.h @@ -54,9 +54,18 @@ typedef struct _PH_SYMBOL_LINE_INFORMATION ULONG64 Address; } PH_SYMBOL_LINE_INFORMATION, *PPH_SYMBOL_LINE_INFORMATION; +typedef enum _PH_SYMBOL_EVENT_TYPE +{ + SymbolDeferredSymbolLoadStart = 1, + SymbolDeferredSymbolLoadComplete = 2, + SymbolDeferredSymbolLoadFailure = 3, + SymbolSymbolsUnloaded = 4, + SymbolDeferredSymbolLoadCancel = 7 +} PH_SYMBOL_EVENT_TYPE; + typedef struct _PH_SYMBOL_EVENT_DATA { - ULONG ActionCode; + PH_SYMBOL_EVENT_TYPE ActionCode; HANDLE ProcessHandle; PPH_SYMBOL_PROVIDER SymbolProvider; PVOID EventData; diff --git a/phlib/phlib.vcxproj b/phlib/phlib.vcxproj index 87ed594736f5..40147221b2be 100644 --- a/phlib/phlib.vcxproj +++ b/phlib/phlib.vcxproj @@ -29,27 +29,25 @@ StaticLibrary Unicode true - llvm - false + v141 + Spectre StaticLibrary Unicode - llvm - false + v141 StaticLibrary Unicode true - llvm - false + v141 + Spectre StaticLibrary Unicode - llvm - false + v141 @@ -88,7 +86,7 @@ Level3 ProgramDatabase StdCall - false + true true @@ -106,7 +104,7 @@ Level3 ProgramDatabase StdCall - false + true true @@ -125,7 +123,7 @@ Level3 ProgramDatabase StdCall - false + true true StreamingSIMDExtensions Guard @@ -146,7 +144,7 @@ Level3 ProgramDatabase StdCall - false + true true Guard From b5260e97eaffab478efe433720f69febc8376bf4 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 8 Oct 2018 16:26:22 +1100 Subject: [PATCH 1411/2058] Remove unused handle, Add missing check for critical menu --- ProcessHacker/mwpgproc.c | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/ProcessHacker/mwpgproc.c b/ProcessHacker/mwpgproc.c index 666561520c0c..8f1cf435dda9 100644 --- a/ProcessHacker/mwpgproc.c +++ b/ProcessHacker/mwpgproc.c @@ -3,7 +3,7 @@ * Main window: Processes tab * * Copyright (C) 2009-2016 wj32 - * Copyright (C) 2017 dmex + * Copyright (C) 2017-2018 dmex * * This file is part of Process Hacker. * @@ -550,6 +550,23 @@ VOID PhMwpInitializeProcessMenu( { PhEnableEMenuItem(Menu, ID_PROCESS_OPENFILELOCATION, FALSE); } + + // Critical + if (Processes[0]->QueryHandle) + { + BOOLEAN breakOnTermination; + + if (NT_SUCCESS(PhGetProcessBreakOnTermination( + Processes[0]->QueryHandle, + &breakOnTermination + ))) + { + if (breakOnTermination) + { + PhSetFlagsEMenuItem(Menu, ID_MISCELLANEOUS_SETCRITICAL, PH_EMENU_CHECKED, PH_EMENU_CHECKED); + } + } + } } else { @@ -607,19 +624,14 @@ VOID PhMwpInitializeProcessMenu( // Virtualization if (NumberOfProcesses == 1) { - HANDLE processHandle; HANDLE tokenHandle; BOOLEAN allowed = FALSE; BOOLEAN enabled = FALSE; - if (NT_SUCCESS(PhOpenProcess( - &processHandle, - ProcessQueryAccess, - Processes[0]->ProcessId - ))) + if (Processes[0]->QueryHandle) { if (NT_SUCCESS(PhOpenProcessToken( - processHandle, + Processes[0]->QueryHandle, TOKEN_QUERY, &tokenHandle ))) @@ -630,8 +642,6 @@ VOID PhMwpInitializeProcessMenu( NtClose(tokenHandle); } - - NtClose(processHandle); } if (!allowed) From 54ff103ea7239a0e7eb3f13b48e928916c2f3d7e Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 8 Oct 2018 16:29:59 +1100 Subject: [PATCH 1412/2058] Fix SAL warnings --- ProcessHacker/prpgenv.c | 34 ++++++++++++++++++++++++---------- ProcessHacker/thrdprv.c | 2 +- phlib/include/symprv.h | 11 +---------- 3 files changed, 26 insertions(+), 21 deletions(-) diff --git a/ProcessHacker/prpgenv.c b/ProcessHacker/prpgenv.c index 595fdb7ebaa5..318eee8e3d22 100644 --- a/ProcessHacker/prpgenv.c +++ b/ProcessHacker/prpgenv.c @@ -169,15 +169,26 @@ VOID PhpRefreshEnvironmentList( userRootNode = PhpAddEnvironmentChildNode(Context, NULL, 0, 0, PhaCreateString(L"User"), NULL); systemRootNode = PhpAddEnvironmentChildNode(Context, NULL, 0, 0, PhaCreateString(L"System"), NULL); - if (DestroyEnvironmentBlock && Context->SystemDefaultEnvironment) - DestroyEnvironmentBlock(Context->SystemDefaultEnvironment); - if (DestroyEnvironmentBlock && Context->UserDefaultEnvironment) - DestroyEnvironmentBlock(Context->UserDefaultEnvironment); + if (DestroyEnvironmentBlock) + { + if (Context->SystemDefaultEnvironment) + { + DestroyEnvironmentBlock(Context->SystemDefaultEnvironment); + Context->SystemDefaultEnvironment = NULL; + } - if (CreateEnvironmentBlock) + if (Context->UserDefaultEnvironment) + { + DestroyEnvironmentBlock(Context->UserDefaultEnvironment); + Context->UserDefaultEnvironment = NULL; + } + } + + if (CreateEnvironmentBlock) + { CreateEnvironmentBlock(&Context->SystemDefaultEnvironment, NULL, FALSE); - if (CreateEnvironmentBlock) CreateEnvironmentBlock(&Context->UserDefaultEnvironment, PhGetOwnTokenAttributes().TokenHandle, FALSE); + } if (NT_SUCCESS(PhOpenProcess( &processHandle, @@ -1302,10 +1313,13 @@ INT_PTR CALLBACK PhpProcessEnvironmentDlgProc( PhDeleteArray(&context->Items); PhClearReference(&context->StatusMessage); - if (DestroyEnvironmentBlock && context->SystemDefaultEnvironment) - DestroyEnvironmentBlock(context->SystemDefaultEnvironment); - if (DestroyEnvironmentBlock && context->UserDefaultEnvironment) - DestroyEnvironmentBlock(context->UserDefaultEnvironment); + if (DestroyEnvironmentBlock) + { + if (context->SystemDefaultEnvironment) + DestroyEnvironmentBlock(context->SystemDefaultEnvironment); + if (context->UserDefaultEnvironment) + DestroyEnvironmentBlock(context->UserDefaultEnvironment); + } PhFree(context); } diff --git a/ProcessHacker/thrdprv.c b/ProcessHacker/thrdprv.c index 842f70f2b5b4..974e05ca520f 100644 --- a/ProcessHacker/thrdprv.c +++ b/ProcessHacker/thrdprv.c @@ -95,7 +95,7 @@ PH_WORK_QUEUE PhThreadProviderWorkQueue; PH_INITONCE PhThreadProviderWorkQueueInitOnce = PH_INITONCE_INIT; VOID PhpQueueThreadWorkQueueItem( - _In_ PTHREAD_START_ROUTINE Function, + _In_ PUSER_THREAD_START_ROUTINE Function, _In_opt_ PVOID Context ) { diff --git a/phlib/include/symprv.h b/phlib/include/symprv.h index fb90c18386a5..302abe97562a 100644 --- a/phlib/include/symprv.h +++ b/phlib/include/symprv.h @@ -54,18 +54,9 @@ typedef struct _PH_SYMBOL_LINE_INFORMATION ULONG64 Address; } PH_SYMBOL_LINE_INFORMATION, *PPH_SYMBOL_LINE_INFORMATION; -typedef enum _PH_SYMBOL_EVENT_TYPE -{ - SymbolDeferredSymbolLoadStart = 1, - SymbolDeferredSymbolLoadComplete = 2, - SymbolDeferredSymbolLoadFailure = 3, - SymbolSymbolsUnloaded = 4, - SymbolDeferredSymbolLoadCancel = 7 -} PH_SYMBOL_EVENT_TYPE; - typedef struct _PH_SYMBOL_EVENT_DATA { - PH_SYMBOL_EVENT_TYPE ActionCode; + ULONG ActionCode; HANDLE ProcessHandle; PPH_SYMBOL_PROVIDER SymbolProvider; PVOID EventData; From fcb6ea1cf2422133efd8e7eb8f985a4647d61d0d Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 8 Oct 2018 16:36:23 +1100 Subject: [PATCH 1413/2058] Remove unused type --- ProcessHacker/include/notifico.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/ProcessHacker/include/notifico.h b/ProcessHacker/include/notifico.h index d37459f2d095..a42e7902e65e 100644 --- a/ProcessHacker/include/notifico.h +++ b/ProcessHacker/include/notifico.h @@ -186,8 +186,4 @@ typedef struct _PH_NF_ICON_REGISTRATION_DATA // end_phapppub -VOID PhShowTrayIconCustomizeDialog( - VOID -); - #endif From 3fd931e82493e1bc6d340006b2b3de7481ae823b Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 8 Oct 2018 16:39:51 +1100 Subject: [PATCH 1414/2058] Add network tab > view menu > Hide waiting connections option --- ProcessHacker/include/mainwndp.h | 7 ++--- ProcessHacker/mainwnd.c | 5 ++++ ProcessHacker/mwpgnet.c | 50 +++++++++++++++++++++----------- ProcessHacker/settings.c | 1 + 4 files changed, 42 insertions(+), 21 deletions(-) diff --git a/ProcessHacker/include/mainwndp.h b/ProcessHacker/include/mainwndp.h index cbb1f7a5d9e8..78d8bb56c2a2 100644 --- a/ProcessHacker/include/mainwndp.h +++ b/ProcessHacker/include/mainwndp.h @@ -395,12 +395,11 @@ VOID PhMwpNeedNetworkTreeList( VOID ); -BOOLEAN PhMwpCurrentUserNetworkTreeFilter( - _In_ PPH_TREENEW_NODE Node, - _In_opt_ PVOID Context +VOID PhMwpToggleNetworkWaitingConnectionTreeFilter( + VOID ); -BOOLEAN PhMwpSignedNetworkTreeFilter( +BOOLEAN PhMwpNetworkTreeFilter( _In_ PPH_TREENEW_NODE Node, _In_opt_ PVOID Context ); diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index f0f0fe3a7e29..3f30fa426a75 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -791,6 +791,11 @@ VOID PhMwpOnCommand( PhMwpToggleDriverServiceTreeFilter(); } break; + case ID_VIEW_HIDEWAITINGCONNECTIONS: + { + PhMwpToggleNetworkWaitingConnectionTreeFilter(); + } + break; case ID_VIEW_ALWAYSONTOP: { AlwaysOnTop = !AlwaysOnTop; diff --git a/ProcessHacker/mwpgnet.c b/ProcessHacker/mwpgnet.c index 985bf6346d80..6fdb0f2815ee 100644 --- a/ProcessHacker/mwpgnet.c +++ b/ProcessHacker/mwpgnet.c @@ -49,6 +49,7 @@ static PH_CALLBACK_REGISTRATION NetworkItemsUpdatedRegistration; static BOOLEAN NetworkFirstTime = TRUE; static BOOLEAN NetworkTreeListLoaded = FALSE; +static PPH_TN_FILTER_ENTRY NetworkFilterEntry = NULL; BOOLEAN PhMwpNetworkPageCallback( _In_ struct _PH_MAIN_TAB_PAGE *Page, @@ -118,9 +119,23 @@ BOOLEAN PhMwpNetworkPageCallback( } } break; + case MainTabPageInitializeSectionMenuItems: + { + PPH_MAIN_TAB_PAGE_MENU_INFORMATION menuInfo = Parameter1; + PPH_EMENU menu = menuInfo->Menu; + ULONG startIndex = menuInfo->StartIndex; + PPH_EMENU_ITEM menuItem; + + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_VIEW_HIDEWAITINGCONNECTIONS, L"&Hide waiting connections", NULL, NULL), startIndex); + + if (NetworkFilterEntry && (menuItem = PhFindEMenuItem(menu, 0, NULL, ID_VIEW_HIDEWAITINGCONNECTIONS))) + menuItem->Flags |= PH_EMENU_CHECKED; + } + return TRUE; case MainTabPageLoadSettings: { - // Nothing + if (PhGetIntegerSetting(L"HideWaitingConnections")) + NetworkFilterEntry = PhAddTreeNewFilter(PhGetFilterSupportNetworkTreeList(), PhMwpNetworkTreeFilter, NULL); } return TRUE; case MainTabPageSaveSettings: @@ -168,34 +183,35 @@ VOID PhMwpNeedNetworkTreeList( } } -BOOLEAN PhMwpCurrentUserNetworkTreeFilter( - _In_ PPH_TREENEW_NODE Node, - _In_opt_ PVOID Context +VOID PhMwpToggleNetworkWaitingConnectionTreeFilter( + VOID ) { - PPH_NETWORK_NODE networkNode = (PPH_NETWORK_NODE)Node; - PPH_PROCESS_NODE processNode; - - processNode = PhFindProcessNode(networkNode->NetworkItem->ProcessId); + if (NetworkFilterEntry) + { + PhRemoveTreeNewFilter(PhGetFilterSupportNetworkTreeList(), NetworkFilterEntry); + NetworkFilterEntry = NULL; + } + else + { + NetworkFilterEntry = PhAddTreeNewFilter(PhGetFilterSupportNetworkTreeList(), PhMwpNetworkTreeFilter, NULL); + } - if (processNode) - return PhMwpCurrentUserProcessTreeFilter(&processNode->Node, NULL); + PhApplyTreeNewFilters(PhGetFilterSupportNetworkTreeList()); - return TRUE; + PhSetIntegerSetting(L"HideWaitingConnections", !!NetworkFilterEntry); } -BOOLEAN PhMwpSignedNetworkTreeFilter( +BOOLEAN PhMwpNetworkTreeFilter( _In_ PPH_TREENEW_NODE Node, _In_opt_ PVOID Context ) { PPH_NETWORK_NODE networkNode = (PPH_NETWORK_NODE)Node; - PPH_PROCESS_NODE processNode; - - processNode = PhFindProcessNode(networkNode->NetworkItem->ProcessId); - if (processNode) - return PhMwpSignedProcessTreeFilter(&processNode->Node, NULL); + // Waiting connections don't have a ProcessId. (dmex) + if (!networkNode->NetworkItem->ProcessId) + return FALSE; return TRUE; } diff --git a/ProcessHacker/settings.c b/ProcessHacker/settings.c index 76d1f892b6c9..34a50bc4e4f3 100644 --- a/ProcessHacker/settings.c +++ b/ProcessHacker/settings.c @@ -81,6 +81,7 @@ VOID PhAddDefaultSettings( PhpAddIntegerSetting(L"HideOnMinimize", L"0"); PhpAddIntegerSetting(L"HideOtherUserProcesses", L"0"); PhpAddIntegerSetting(L"HideSignedProcesses", L"0"); + PhpAddIntegerSetting(L"HideWaitingConnections", L"0"); PhpAddIntegerSetting(L"HighlightingDuration", L"3e8"); // 1000ms PhpAddStringSetting(L"IconSettings", L"1|1"); PhpAddIntegerSetting(L"IconNotifyMask", L"c"); // PH_NOTIFY_SERVICE_CREATE | PH_NOTIFY_SERVICE_DELETE From 4b2dcf198a81fa9dc362fa11f099774ba5447a64 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 8 Oct 2018 16:41:04 +1100 Subject: [PATCH 1415/2058] Add missing type from previous commit --- ProcessHacker/resource.h | 1 + 1 file changed, 1 insertion(+) diff --git a/ProcessHacker/resource.h b/ProcessHacker/resource.h index 8b80d36382a1..8b11541840ab 100644 --- a/ProcessHacker/resource.h +++ b/ProcessHacker/resource.h @@ -726,6 +726,7 @@ #define ID_DIGIT7 40269 #define ID_DIGIT8 40270 #define ID_DIGIT9 40271 +#define ID_VIEW_HIDEWAITINGCONNECTIONS 40272 #define ID_VIEW_HIDEDRIVERSERVICES 40273 #define ID_VIEW_SECTIONPLACEHOLDER 40274 #define ID_VIEW_SCROLLTONEWPROCESSES 40275 From 5109ec3b6ec092c53ee983ee04cbe95ffc67a8bf Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 8 Oct 2018 16:45:29 +1100 Subject: [PATCH 1416/2058] ExtendedTools: Add d3dkmt types for RS5 --- ProcessHacker/resource.h | 1 + plugins/ExtendedTools/d3dkmt.h | 2 ++ 2 files changed, 3 insertions(+) diff --git a/ProcessHacker/resource.h b/ProcessHacker/resource.h index 8b11541840ab..d7c69aaaf262 100644 --- a/ProcessHacker/resource.h +++ b/ProcessHacker/resource.h @@ -749,6 +749,7 @@ #define ID_GROUP_DISABLE 40298 #define ID_GROUP_RESET 40299 #define ID_TOOLS_SCM_PERMISSIONS 40300 +#define ID_TOOLS_RDP_PERMISSIONS 40301 #define IDDYNAMIC 50000 #define IDPLUGINS 55000 diff --git a/plugins/ExtendedTools/d3dkmt.h b/plugins/ExtendedTools/d3dkmt.h index e92cce5ee10c..9d8a256b2dc5 100644 --- a/plugins/ExtendedTools/d3dkmt.h +++ b/plugins/ExtendedTools/d3dkmt.h @@ -788,6 +788,7 @@ typedef enum _D3DDDI_QUERYREGISTRY_TYPE D3DDDI_QUERYREGISTRY_SERVICEKEY = 0, // HKLM\System\CurrentControlSet\Services\nvlddmkm D3DDDI_QUERYREGISTRY_ADAPTERKEY = 1, // HKLM\System\CurrentControlSet\Control\Class\{4d36e968-e325-11ce-bfc1-08002be10318}\0000 D3DDDI_QUERYREGISTRY_DRIVERSTOREPATH = 2, + D3DDDI_QUERYREGISTRY_DRIVERIMAGEPATH = 3, // REDSTONE5 D3DDDI_QUERYREGISTRY_MAX, } D3DDDI_QUERYREGISTRY_TYPE; @@ -848,6 +849,7 @@ typedef struct _D3DKMT_NODE_PERFDATA _Out_ ULONG Voltage; // Voltage of the engine in milli volts mV _Out_ ULONG VoltageMax; // The max voltage of the engine in milli volts while not overclocked. _Out_ ULONG VoltageMaxOC; // The max voltage of the engine while overclocked in milli volts. + _Out_ ULONGLONG MaxTransitionLatency; // Max transition latency to change the frequency in 100 nanoseconds // REDSTONE5 } D3DKMT_NODE_PERFDATA; // Represents performance data collected per adapter on an interval basis. From 7daa2cfee8b5d786e15adb95d720256e8637e4b6 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 8 Oct 2018 16:46:38 +1100 Subject: [PATCH 1417/2058] Add username to some comments --- ProcessHacker/procprv.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ProcessHacker/procprv.c b/ProcessHacker/procprv.c index da9e565d22f0..9542696b0976 100644 --- a/ProcessHacker/procprv.c +++ b/ProcessHacker/procprv.c @@ -1125,7 +1125,7 @@ VOID PhpFillProcessItem( // Process information { // If we're dealing with System (PID 4), we need to get the - // kernel file name. Otherwise, get the image file name. + // kernel file name. Otherwise, get the image file name. (wj32) if (ProcessItem->ProcessId != SYSTEM_PROCESS_ID) { @@ -1201,7 +1201,7 @@ VOID PhpFillProcessItem( else { if (ProcessItem->ProcessId == SYSTEM_IDLE_PROCESS_ID || - ProcessItem->ProcessId == SYSTEM_PROCESS_ID) // System token can't be opened on XP + ProcessItem->ProcessId == SYSTEM_PROCESS_ID) // System token can't be opened on XP (wj32) { ProcessItem->Sid = PhAllocateCopy(&PhSeLocalSystemSid, RtlLengthSid(&PhSeLocalSystemSid)); } @@ -1229,7 +1229,7 @@ VOID PhpFillProcessItem( } else { - // HACK: 'emulate' the PS_PROTECTION info for older OSes. + // HACK: 'emulate' the PS_PROTECTION info for older OSes. (ge0rdi) if (ProcessItem->IsProtectedProcess) ProcessItem->Protection.Type = PsProtectedTypeProtected; } @@ -1237,7 +1237,7 @@ VOID PhpFillProcessItem( else { // Signalize that we weren't able to get protection info with a special value. - // Note: We use this value to determine if we should show protection information. + // Note: We use this value to determine if we should show protection information. (ge0rdi) ProcessItem->Protection.Level = UCHAR_MAX; } @@ -1253,7 +1253,7 @@ VOID PhpFillProcessItem( } // On Windows 8.1 and above, processes without threads are reflected processes - // which will not terminate if we have a handle open. + // which will not terminate if we have a handle open. (wj32) if (Process->NumberOfThreads == 0 && ProcessItem->QueryHandle) { NtClose(ProcessItem->QueryHandle); From d5f3b9c847400da070350b17b4cc3c02c54da21f Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 8 Oct 2018 18:09:06 +1100 Subject: [PATCH 1418/2058] ExtendedTools: Fix sorting regression, Fix object reference regression --- plugins/ExtendedTools/unldll.c | 149 +++++++++++++++++++++++++-------- 1 file changed, 114 insertions(+), 35 deletions(-) diff --git a/plugins/ExtendedTools/unldll.c b/plugins/ExtendedTools/unldll.c index 86261ca2beba..e607cc44085d 100644 --- a/plugins/ExtendedTools/unldll.c +++ b/plugins/ExtendedTools/unldll.c @@ -24,6 +24,7 @@ typedef struct _UNLOADED_DLLS_CONTEXT { + BOOLEAN IsWow64; HWND ListViewHandle; PPH_PROCESS_ITEM ProcessItem; PH_LAYOUT_MANAGER LayoutManager; @@ -41,21 +42,15 @@ VOID EtShowUnloadedDllsDialog( _In_ PPH_PROCESS_ITEM ProcessItem ) { - UNLOADED_DLLS_CONTEXT context; - - context.ProcessItem = ProcessItem; - context.CapturedEventTrace = NULL; + PhReferenceObject(ProcessItem); DialogBoxParam( PluginInstance->DllBase, MAKEINTRESOURCE(IDD_UNLOADEDDLLS), NULL, EtpUnloadedDllsDlgProc, - (LPARAM)&context + (LPARAM)ProcessItem ); - - if (context.CapturedEventTrace) - PhFree(context.CapturedEventTrace); } NTSTATUS EtpRefreshUnloadedDlls( @@ -80,12 +75,11 @@ NTSTATUS EtpRefreshUnloadedDlls( if (!NT_SUCCESS(status = PhGetProcessIsWow64(Context->ProcessItem->QueryHandle, &isWow64))) return status; + Context->IsWow64 = isWow64; + if (isWow64) { PPH_STRING eventTraceString; - RTL_UNLOAD_EVENT_TRACE32 eventTrace[RTL_UNLOAD_EVENT_TRACE_NUMBER]; - - memset(eventTrace, 0, sizeof(eventTrace)); if (!PhUiConnectToPhSvcEx(hwndDlg, Wow64PhSvcMode, FALSE)) return STATUS_FAIL_CHECK; @@ -96,18 +90,26 @@ NTSTATUS EtpRefreshUnloadedDlls( return status; } - if (!PhHexStringToBuffer(&eventTraceString->sr, (PUCHAR)eventTrace)) + capturedEventTrace = PhAllocate(sizeof(RTL_UNLOAD_EVENT_TRACE32) * RTL_UNLOAD_EVENT_TRACE_NUMBER); + memset(capturedEventTrace, 0, sizeof(RTL_UNLOAD_EVENT_TRACE32) * RTL_UNLOAD_EVENT_TRACE_NUMBER); + + if (!PhHexStringToBuffer(&eventTraceString->sr, (PUCHAR)capturedEventTrace)) { PhUiDisconnectFromPhSvc(); + + PhFree(capturedEventTrace); + return STATUS_FAIL_CHECK; } + PhUiDisconnectFromPhSvc(); + ExtendedListView_SetRedraw(Context->ListViewHandle, FALSE); ListView_DeleteAllItems(Context->ListViewHandle); - for (i = 0; i < RTL_NUMBER_OF(eventTrace); i++) + for (i = 0; i < RTL_UNLOAD_EVENT_TRACE_NUMBER; i++) { - PRTL_UNLOAD_EVENT_TRACE32 rtlEvent = &eventTrace[i]; + PRTL_UNLOAD_EVENT_TRACE32 rtlEvent = PTR_ADD_OFFSET(capturedEventTrace, sizeof(RTL_UNLOAD_EVENT_TRACE32) * i); INT lvItemIndex; WCHAR buffer[128]; PPH_STRING string; @@ -121,8 +123,7 @@ NTSTATUS EtpRefreshUnloadedDlls( lvItemIndex = PhAddListViewItem(Context->ListViewHandle, MAXINT, buffer, rtlEvent); // Name - if (PhCopyStringZ(rtlEvent->ImageName, sizeof(rtlEvent->ImageName) / sizeof(WCHAR), - buffer, sizeof(buffer) / sizeof(WCHAR), NULL)) + if (PhCopyStringZ(rtlEvent->ImageName, RTL_NUMBER_OF(rtlEvent->ImageName), buffer, RTL_NUMBER_OF(buffer), NULL)) { PhSetListViewSubItem(Context->ListViewHandle, lvItemIndex, 1, buffer); } @@ -152,7 +153,6 @@ NTSTATUS EtpRefreshUnloadedDlls( ExtendedListView_SetRedraw(Context->ListViewHandle, TRUE); PhDereferenceObject(eventTraceString); - PhUiDisconnectFromPhSvc(); } else { @@ -191,8 +191,7 @@ NTSTATUS EtpRefreshUnloadedDlls( lvItemIndex = PhAddListViewItem(Context->ListViewHandle, MAXINT, buffer, rtlEvent); // Name - if (PhCopyStringZ(rtlEvent->ImageName, sizeof(rtlEvent->ImageName) / sizeof(WCHAR), - buffer, sizeof(buffer) / sizeof(WCHAR), NULL)) + if (PhCopyStringZ(rtlEvent->ImageName, RTL_NUMBER_OF(rtlEvent->ImageName), buffer, RTL_NUMBER_OF(buffer), NULL)) { PhSetListViewSubItem(Context->ListViewHandle, lvItemIndex, 1, buffer); } @@ -241,10 +240,24 @@ static INT NTAPI EtpNumberCompareFunction( _In_opt_ PVOID Context ) { - PRTL_UNLOAD_EVENT_TRACE item1 = Item1; - PRTL_UNLOAD_EVENT_TRACE item2 = Item2; +#ifdef _WIN64 + PUNLOADED_DLLS_CONTEXT context = Context; + + if (context->IsWow64) + { + PRTL_UNLOAD_EVENT_TRACE32 item1 = Item1; + PRTL_UNLOAD_EVENT_TRACE32 item2 = Item2; + + return uintcmp(item1->Sequence, item2->Sequence); + } + else + { +#endif + PRTL_UNLOAD_EVENT_TRACE item1 = Item1; + PRTL_UNLOAD_EVENT_TRACE item2 = Item2; - return uintcmp(item1->Sequence, item2->Sequence); + return uintcmp(item1->Sequence, item2->Sequence); + } } static INT NTAPI EtpBaseAddressCompareFunction( @@ -253,10 +266,24 @@ static INT NTAPI EtpBaseAddressCompareFunction( _In_opt_ PVOID Context ) { - PRTL_UNLOAD_EVENT_TRACE item1 = Item1; - PRTL_UNLOAD_EVENT_TRACE item2 = Item2; +#ifdef _WIN64 + PUNLOADED_DLLS_CONTEXT context = Context; + + if (context->IsWow64) + { + PRTL_UNLOAD_EVENT_TRACE32 item1 = Item1; + PRTL_UNLOAD_EVENT_TRACE32 item2 = Item2; - return uintptrcmp((ULONG_PTR)item1->BaseAddress, (ULONG_PTR)item2->BaseAddress); + return uintptrcmp((ULONG_PTR)item1->BaseAddress, (ULONG_PTR)item2->BaseAddress); + } + else + { +#endif + PRTL_UNLOAD_EVENT_TRACE item1 = Item1; + PRTL_UNLOAD_EVENT_TRACE item2 = Item2; + + return uintptrcmp((ULONG_PTR)item1->BaseAddress, (ULONG_PTR)item2->BaseAddress); + } } static INT NTAPI EtpSizeCompareFunction( @@ -265,10 +292,24 @@ static INT NTAPI EtpSizeCompareFunction( _In_opt_ PVOID Context ) { - PRTL_UNLOAD_EVENT_TRACE item1 = Item1; - PRTL_UNLOAD_EVENT_TRACE item2 = Item2; +#ifdef _WIN64 + PUNLOADED_DLLS_CONTEXT context = Context; - return uintptrcmp(item1->SizeOfImage, item2->SizeOfImage); + if (context->IsWow64) + { + PRTL_UNLOAD_EVENT_TRACE32 item1 = Item1; + PRTL_UNLOAD_EVENT_TRACE32 item2 = Item2; + + return uintptrcmp(item1->SizeOfImage, item2->SizeOfImage); + } + else + { +#endif + PRTL_UNLOAD_EVENT_TRACE item1 = Item1; + PRTL_UNLOAD_EVENT_TRACE item2 = Item2; + + return uintptrcmp(item1->SizeOfImage, item2->SizeOfImage); + } } static INT NTAPI EtpTimeStampCompareFunction( @@ -277,10 +318,24 @@ static INT NTAPI EtpTimeStampCompareFunction( _In_opt_ PVOID Context ) { - PRTL_UNLOAD_EVENT_TRACE item1 = Item1; - PRTL_UNLOAD_EVENT_TRACE item2 = Item2; +#ifdef _WIN64 + PUNLOADED_DLLS_CONTEXT context = Context; + + if (context->IsWow64) + { + PRTL_UNLOAD_EVENT_TRACE32 item1 = Item1; + PRTL_UNLOAD_EVENT_TRACE32 item2 = Item2; + + return uintcmp(item1->TimeDateStamp, item2->TimeDateStamp); + } + else + { +#endif + PRTL_UNLOAD_EVENT_TRACE item1 = Item1; + PRTL_UNLOAD_EVENT_TRACE item2 = Item2; - return uintcmp(item1->TimeDateStamp, item2->TimeDateStamp); + return uintcmp(item1->TimeDateStamp, item2->TimeDateStamp); + } } static INT NTAPI EtpCheckSumCompareFunction( @@ -289,10 +344,24 @@ static INT NTAPI EtpCheckSumCompareFunction( _In_opt_ PVOID Context ) { - PRTL_UNLOAD_EVENT_TRACE item1 = Item1; - PRTL_UNLOAD_EVENT_TRACE item2 = Item2; +#ifdef _WIN64 + PUNLOADED_DLLS_CONTEXT context = Context; + + if (context->IsWow64) + { + PRTL_UNLOAD_EVENT_TRACE32 item1 = Item1; + PRTL_UNLOAD_EVENT_TRACE32 item2 = Item2; + + return uintcmp(item1->CheckSum, item2->CheckSum); + } + else + { +#endif + PRTL_UNLOAD_EVENT_TRACE item1 = Item1; + PRTL_UNLOAD_EVENT_TRACE item2 = Item2; - return uintcmp(item1->CheckSum, item2->CheckSum); + return uintcmp(item1->CheckSum, item2->CheckSum); + } } INT_PTR CALLBACK EtpUnloadedDllsDlgProc( @@ -306,7 +375,9 @@ INT_PTR CALLBACK EtpUnloadedDllsDlgProc( if (uMsg == WM_INITDIALOG) { - context = (PUNLOADED_DLLS_CONTEXT)lParam; + context = PhAllocateZero(sizeof(UNLOADED_DLLS_CONTEXT)); + context->ProcessItem = (PPH_PROCESS_ITEM)lParam; + PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context); } else @@ -347,6 +418,7 @@ INT_PTR CALLBACK EtpUnloadedDllsDlgProc( ExtendedListView_SetCompareFunction(lvHandle, 3, EtpSizeCompareFunction); ExtendedListView_SetCompareFunction(lvHandle, 4, EtpTimeStampCompareFunction); ExtendedListView_SetCompareFunction(lvHandle, 5, EtpCheckSumCompareFunction); + ExtendedListView_SetContext(lvHandle, context); PhLoadListViewColumnsFromSetting(SETTING_NAME_UNLOADED_COLUMNS, lvHandle); PhInitializeLayoutManager(&context->LayoutManager, hwndDlg); @@ -375,6 +447,13 @@ INT_PTR CALLBACK EtpUnloadedDllsDlgProc( PhSaveWindowPlacementToSetting(SETTING_NAME_UNLOADED_WINDOW_POSITION, SETTING_NAME_UNLOADED_WINDOW_SIZE, hwndDlg); PhDeleteLayoutManager(&context->LayoutManager); + + if (context->CapturedEventTrace) + PhFree(context->CapturedEventTrace); + + PhDereferenceObject(context->ProcessItem); + + PhFree(context); } break; case WM_COMMAND: From ac01f2c570d7b40228fd2c51802347bd95f99936 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 8 Oct 2018 19:00:44 +1100 Subject: [PATCH 1419/2058] Update Mini-XML to v2.12 --- phlib/mxml/config.h | 65 ++++++++++++++++++--------- phlib/mxml/mxml-attr.c | 19 ++++---- phlib/mxml/mxml-file.c | 88 +++++++++++++++++++++++++----------- phlib/mxml/mxml-get.c | 8 +++- phlib/mxml/mxml-index.c | 1 + phlib/mxml/mxml-node.c | 57 +++++++++++------------ phlib/mxml/mxml-set.c | 5 ++- phlib/mxml/mxml-string.c | 5 ++- phlib/mxml/mxml.h | 97 +++++++++++++++++++++------------------- 9 files changed, 210 insertions(+), 135 deletions(-) diff --git a/phlib/mxml/config.h b/phlib/mxml/config.h index cf6bdf528f76..038ba6eb7d35 100644 --- a/phlib/mxml/config.h +++ b/phlib/mxml/config.h @@ -1,7 +1,8 @@ /* - * Configuration file for Mini-XML, a small XML file parsing library. + * Visual Studio configuration file for Mini-XML, a small XML file parsing + * library. * - * Copyright 2003-2017 by Michael R Sweet. + * Copyright 2003-2018 by Michael R Sweet. * * These coded instructions, statements, and computer programs are the * property of Michael R Sweet and are protected by Federal copyright @@ -12,6 +13,21 @@ * https://michaelrsweet.github.io/mxml */ +/* + * Beginning with VC2005, Microsoft breaks ISO C and POSIX conformance + * by deprecating a number of functions in the name of security, even + * when many of the affected functions are otherwise completely secure. + * The _CRT_SECURE_NO_DEPRECATE definition ensures that we won't get + * warnings from their use... + * + * Then Microsoft decided that they should ignore this in VC2008 and use + * yet another define (_CRT_SECURE_NO_WARNINGS) instead... + */ + +#define _CRT_SECURE_NO_DEPRECATE +#define _CRT_SECURE_NO_WARNINGS + + /* * Include necessary headers... */ @@ -21,20 +37,40 @@ #include #include #include +#include + + +/* + * Microsoft also renames the POSIX functions to _name, and introduces + * a broken compatibility layer using the original names. As a result, + * random crashes can occur when, for example, strdup() allocates memory + * from a different heap than used by malloc() and free(). + * + * To avoid moronic problems like this, we #define the POSIX function + * names to the corresponding non-standard Microsoft names. + */ + +#define close _close +#define open _open +#define read _read +#define snprintf _snprintf +#define strdup _strdup +#define vsnprintf _vsnprintf +#define write _write /* * Version number... */ -#define MXML_VERSION "Mini-XML v2.11" +#define MXML_VERSION "Mini-XML v2.12" /* * Inline function support... */ -#define inline __inline +#define inline _inline /* @@ -43,18 +79,13 @@ #define HAVE_LONG_LONG 1 - /* - * Do we have ? - */ - -#undef HAVE_ZLIB_H /* - * Do we have the snprintf() and vsnprintf() functions? + * Do we have the *printf() functions? */ #define HAVE_SNPRINTF 1 -#undef HAVE_VASPRINTF +/* #undef HAVE_VASPRINTF */ #define HAVE_VSNPRINTF 1 @@ -63,14 +94,14 @@ */ #define HAVE_STRDUP 1 -#undef HAVE_STRLCAT -#undef HAVE_STRLCPY +/* #undef HAVE_STRLCPY */ + /* * Do we have threading support? */ -#undef HAVE_PTHREAD_H +/* #undef HAVE_PTHREAD_H */ /* @@ -82,11 +113,6 @@ extern char *_mxml_strdup(const char *); # define strdup _mxml_strdup # endif /* !HAVE_STRDUP */ -# ifndef HAVE_STRLCAT -extern size_t _mxml_strlcat(char *, const char *, size_t); -# define strlcat _mxml_strlcat -# endif /* !HAVE_STRLCAT */ - # ifndef HAVE_STRLCPY extern size_t _mxml_strlcpy(char *, const char *, size_t); # define strlcpy _mxml_strlcpy @@ -104,4 +130,3 @@ extern int _mxml_snprintf(char *, size_t, const char *, ...); extern int _mxml_vsnprintf(char *, size_t, const char *, va_list); # define vsnprintf _mxml_vsnprintf # endif /* !HAVE_VSNPRINTF */ - diff --git a/phlib/mxml/mxml-attr.c b/phlib/mxml/mxml-attr.c index 8b9a0b0c27d7..88a7a6b8867c 100644 --- a/phlib/mxml/mxml-attr.c +++ b/phlib/mxml/mxml-attr.c @@ -17,6 +17,7 @@ */ #include + #include "config.h" #include "mxml.h" @@ -46,7 +47,7 @@ mxmlElementDeleteAttr(mxml_node_t *node,/* I - Element */ #ifdef MXMLDEBUG fprintf(stderr, "mxmlElementDeleteAttr(node=%p, name=\"%s\")\n", node, name ? name : "(null)"); -#endif /* DEBUG */ +#endif /* MXMLDEBUG */ /* * Range check input... @@ -65,7 +66,7 @@ mxmlElementDeleteAttr(mxml_node_t *node,/* I - Element */ { #ifdef MXMLDEBUG printf(" %s=\"%s\"\n", attr->name, attr->value); -#endif /* DEBUG */ +#endif /* MXMLDEBUG */ if (!strcmp(attr->name, name)) { @@ -108,7 +109,7 @@ mxmlElementGetAttr(mxml_node_t *node, /* I - Element node */ #ifdef MXMLDEBUG fprintf(stderr, "mxmlElementGetAttr(node=%p, name=\"%s\")\n", node, name ? name : "(null)"); -#endif /* DEBUG */ +#endif /* MXMLDEBUG */ /* * Range check input... @@ -127,13 +128,13 @@ mxmlElementGetAttr(mxml_node_t *node, /* I - Element node */ { #ifdef MXMLDEBUG printf(" %s=\"%s\"\n", attr->name, attr->value); -#endif /* DEBUG */ +#endif /* MXMLDEBUG */ if (!strcmp(attr->name, name)) { #ifdef MXMLDEBUG printf(" Returning \"%s\"!\n", attr->value); -#endif /* DEBUG */ +#endif /* MXMLDEBUG */ return (attr->value); } } @@ -144,7 +145,7 @@ mxmlElementGetAttr(mxml_node_t *node, /* I - Element node */ #ifdef MXMLDEBUG puts(" Returning NULL!\n"); -#endif /* DEBUG */ +#endif /* MXMLDEBUG */ return (NULL); } @@ -212,7 +213,7 @@ mxmlElementSetAttr(mxml_node_t *node, /* I - Element node */ #ifdef MXMLDEBUG fprintf(stderr, "mxmlElementSetAttr(node=%p, name=\"%s\", value=\"%s\")\n", node, name ? name : "(null)", value ? value : "(null)"); -#endif /* DEBUG */ +#endif /* MXMLDEBUG */ /* * Range check input... @@ -222,7 +223,7 @@ mxmlElementSetAttr(mxml_node_t *node, /* I - Element node */ return; if (value) - valuec = PhDuplicateBytesZSafe((char *)value); + valuec = PhDuplicateBytesZSafe((char *)value); else valuec = NULL; @@ -256,7 +257,7 @@ mxmlElementSetAttrf(mxml_node_t *node, /* I - Element node */ fprintf(stderr, "mxmlElementSetAttrf(node=%p, name=\"%s\", format=\"%s\", ...)\n", node, name ? name : "(null)", format ? format : "(null)"); -#endif /* DEBUG */ +#endif /* MXMLDEBUG */ /* * Range check input... diff --git a/phlib/mxml/mxml-file.c b/phlib/mxml/mxml-file.c index 3eff0b3ad3b3..86624a5c7be9 100644 --- a/phlib/mxml/mxml-file.c +++ b/phlib/mxml/mxml-file.c @@ -1,7 +1,7 @@ /* * File loading code for Mini-XML, a small XML file parsing library. * - * Copyright 2003-2017 by Michael R Sweet. + * Copyright 2003-2018 by Michael R Sweet. * * These coded instructions, statements, and computer programs are the * property of Michael R Sweet and are protected by Federal copyright @@ -16,8 +16,10 @@ * Include necessary headers... */ + /* dmex: modified to use file handles */ #include -#ifndef WIN32 + +#ifndef _WIN32 # include #endif /* !WIN32 */ #include "mxml-private.h" @@ -107,6 +109,12 @@ static int mxml_write_ws(mxml_node_t *node, void *p, * The constants @code MXML_INTEGER_CALLBACK@, @code MXML_OPAQUE_CALLBACK@, * @code MXML_REAL_CALLBACK@, and @code MXML_TEXT_CALLBACK@ are defined for * loading child (data) nodes of the specified type. + * + * Note: The most common programming error when using the Mini-XML library is + * to load an XML file using the @code MXML_TEXT_CALLBACK@, which returns inline + * text as a series of whitespace-delimited words, instead of using the + * @code MXML_OPAQUE_CALLBACK@ which returns the inline text as a single string + * (including whitespace). */ mxml_node_t * /* O - First node or @code NULL@ if the file could not be read. */ @@ -143,6 +151,12 @@ mxmlLoadFd(mxml_node_t *top, /* I - Top node */ * The constants @code MXML_INTEGER_CALLBACK@, @code MXML_OPAQUE_CALLBACK@, * @code MXML_REAL_CALLBACK@, and @code MXML_TEXT_CALLBACK@ are defined for * loading child (data) nodes of the specified type. + * + * Note: The most common programming error when using the Mini-XML library is + * to load an XML file using the @code MXML_TEXT_CALLBACK@, which returns inline + * text as a series of whitespace-delimited words, instead of using the + * @code MXML_OPAQUE_CALLBACK@ which returns the inline text as a single string + * (including whitespace). */ mxml_node_t * /* O - First node or @code NULL@ if the file could not be read. */ @@ -168,6 +182,12 @@ mxmlLoadFile(mxml_node_t *top, /* I - Top node */ * The constants @code MXML_INTEGER_CALLBACK@, @code MXML_OPAQUE_CALLBACK@, * @code MXML_REAL_CALLBACK@, and @code MXML_TEXT_CALLBACK@ are defined for * loading child (data) nodes of the specified type. + * + * Note: The most common programming error when using the Mini-XML library is + * to load an XML file using the @code MXML_TEXT_CALLBACK@, which returns inline + * text as a series of whitespace-delimited words, instead of using the + * @code MXML_OPAQUE_CALLBACK@ which returns the inline text as a single string + * (including whitespace). */ mxml_node_t * /* O - First node or @code NULL@ if the string has errors. */ @@ -259,7 +279,7 @@ mxmlSaveAllocString( int /* O - 0 on success, -1 on error. */ mxmlSaveFd(mxml_node_t *node, /* I - Node to write */ - HANDLE fd, /* I - File descriptor to write to */ + HANDLE fd, /* I - File descriptor to write to */ mxml_save_cb_t cb) /* I - Whitespace callback or @code MXML_NO_CALLBACK@ */ { int col; /* Final column */ @@ -981,7 +1001,6 @@ mxml_fd_putc(int ch, /* I - Character */ /* * 'mxml_fd_read()' - Read a buffer of data from a file descriptor. */ - /* wj32: modified to use file handles */ static int /* O - 0 on success, -1 on error */ mxml_fd_read(_mxml_fdbuf_t *buf) /* I - File descriptor buffer */ @@ -1007,7 +1026,6 @@ mxml_fd_read(_mxml_fdbuf_t *buf) /* I - File descriptor buffer */ /* * 'mxml_fd_write()' - Write a buffer of data to a file descriptor. */ - /* wj32: modified to use file handles */ static int /* O - 0 on success, -1 on error */ mxml_fd_write(_mxml_fdbuf_t *buf) /* I - File descriptor buffer */ @@ -2072,7 +2090,7 @@ mxml_parse_element( if ((value = PhAllocateSafe(64)) == NULL) { - PhFree(name); + PhFree(name); mxml_error("Unable to allocate memory for value!"); return (EOF); } @@ -2920,34 +2938,52 @@ mxml_write_node(mxml_node_t *node, /* I - Node to write */ if ((next = current->child) == NULL) { - while ((next = current->next) == NULL) + if (current == node) { - if (current == node) - break; - /* - * The ? and ! elements are special-cases and have no end tags... - */ + * Don't traverse to sibling node if we are at the "root" node... + */ - current = current->parent; + next = NULL; + } + else + { + /* + * Try the next sibling, and continue traversing upwards as needed... + */ - if (current->value.element.name[0] != '!' && - current->value.element.name[0] != '?') + while ((next = current->next) == NULL) { - col = mxml_write_ws(current, p, cb, MXML_WS_BEFORE_CLOSE, col, putc_cb); + if (current == node || !current->parent) + break; - if ((*putc_cb)('<', p) < 0) - return (-1); - if ((*putc_cb)('/', p) < 0) - return (-1); - if (mxml_write_string(current->value.element.name, p, putc_cb) < 0) - return (-1); - if ((*putc_cb)('>', p) < 0) - return (-1); + /* + * The ? and ! elements are special-cases and have no end tags... + */ - col += (int)strlen(current->value.element.name) + 3; + current = current->parent; - col = mxml_write_ws(current, p, cb, MXML_WS_AFTER_CLOSE, col, putc_cb); + if (current->value.element.name[0] != '!' && + current->value.element.name[0] != '?') + { + col = mxml_write_ws(current, p, cb, MXML_WS_BEFORE_CLOSE, col, putc_cb); + + if ((*putc_cb)('<', p) < 0) + return (-1); + if ((*putc_cb)('/', p) < 0) + return (-1); + if (mxml_write_string(current->value.element.name, p, putc_cb) < 0) + return (-1); + if ((*putc_cb)('>', p) < 0) + return (-1); + + col += (int)strlen(current->value.element.name) + 3; + + col = mxml_write_ws(current, p, cb, MXML_WS_AFTER_CLOSE, col, putc_cb); + } + + if (current == node) + break; } } } diff --git a/phlib/mxml/mxml-get.c b/phlib/mxml/mxml-get.c index e572fb1abb2d..1f00d7f77b44 100644 --- a/phlib/mxml/mxml-get.c +++ b/phlib/mxml/mxml-get.c @@ -1,7 +1,7 @@ /* * Node get functions for Mini-XML, a small XML file parsing library. * - * Copyright 2014-2017 by Michael R Sweet. + * Copyright 2014-2018 by Michael R Sweet. * * These coded instructions, statements, and computer programs are the * property of Michael R Sweet and are protected by Federal copyright @@ -346,6 +346,12 @@ mxmlGetReal(mxml_node_t *node) /* I - Node to get */ * @code NULL@ is returned if the node (or its first child) is not a text node. * The "whitespace" argument can be @code NULL@. * + * Note: Text nodes consist of whitespace-delimited words. You will only get + * single words of text when reading an XML file with @code MXML_TEXT@ nodes. + * If you want the entire string between elements in the XML file, you MUST read + * the XML file with @code MXML_OPAQUE@ nodes and get the resulting strings + * using the @link mxmlGetOpaque@ function instead. + * * @since Mini-XML 2.7@ */ diff --git a/phlib/mxml/mxml-index.c b/phlib/mxml/mxml-index.c index 366107ff003f..350294cea2b9 100644 --- a/phlib/mxml/mxml-index.c +++ b/phlib/mxml/mxml-index.c @@ -17,6 +17,7 @@ */ #include + #include "config.h" #include "mxml.h" diff --git a/phlib/mxml/mxml-node.c b/phlib/mxml/mxml-node.c index 73266adb0619..977db33007e9 100644 --- a/phlib/mxml/mxml-node.c +++ b/phlib/mxml/mxml-node.c @@ -1,7 +1,7 @@ /* * Node support code for Mini-XML, a small XML file parsing library. * - * Copyright 2003-2017 by Michael R Sweet. + * Copyright 2003-2018 by Michael R Sweet. * * These coded instructions, statements, and computer programs are the * property of Michael R Sweet and are protected by Federal copyright @@ -17,6 +17,7 @@ */ #include + #include "config.h" #include "mxml.h" @@ -49,7 +50,7 @@ mxmlAdd(mxml_node_t *parent, /* I - Parent node */ #ifdef MXMLDEBUG fprintf(stderr, "mxmlAdd(parent=%p, where=%d, child=%p, node=%p)\n", parent, where, child, node); -#endif /* DEBUG */ +#endif /* MXMLDEBUG */ /* * Range check input... @@ -58,7 +59,7 @@ mxmlAdd(mxml_node_t *parent, /* I - Parent node */ if (!parent || !node) return; -#if DEBUG > 1 +#if MXMLDEBUG > 1 fprintf(stderr, " BEFORE: node->parent=%p\n", node->parent); if (parent) { @@ -67,7 +68,7 @@ mxmlAdd(mxml_node_t *parent, /* I - Parent node */ fprintf(stderr, " BEFORE: parent->prev=%p\n", parent->prev); fprintf(stderr, " BEFORE: parent->next=%p\n", parent->next); } -#endif /* DEBUG > 1 */ +#endif /* MXMLDEBUG > 1 */ /* * Remove the node from any existing parent... @@ -154,7 +155,7 @@ mxmlAdd(mxml_node_t *parent, /* I - Parent node */ break; } -#if DEBUG > 1 +#if MXMLDEBUG > 1 fprintf(stderr, " AFTER: node->parent=%p\n", node->parent); if (parent) { @@ -163,7 +164,7 @@ mxmlAdd(mxml_node_t *parent, /* I - Parent node */ fprintf(stderr, " AFTER: parent->prev=%p\n", parent->prev); fprintf(stderr, " AFTER: parent->next=%p\n", parent->next); } -#endif /* DEBUG > 1 */ +#endif /* MXMLDEBUG > 1 */ } @@ -183,7 +184,7 @@ mxmlDelete(mxml_node_t *node) /* I - Node to delete */ #ifdef MXMLDEBUG fprintf(stderr, "mxmlDelete(node=%p)\n", node); -#endif /* DEBUG */ +#endif /* MXMLDEBUG */ /* * Range check input... @@ -293,7 +294,7 @@ mxmlNewCDATA(mxml_node_t *parent, /* I - Parent node or @code MXML_NO_PARENT@ */ #ifdef MXMLDEBUG fprintf(stderr, "mxmlNewCDATA(parent=%p, data=\"%s\")\n", parent, data ? data : "(null)"); -#endif /* DEBUG */ +#endif /* MXMLDEBUG */ /* * Range check input... @@ -307,7 +308,7 @@ mxmlNewCDATA(mxml_node_t *parent, /* I - Parent node or @code MXML_NO_PARENT@ */ */ if ((node = mxml_new(parent, MXML_ELEMENT)) != NULL) - node->value.element.name = _mxml_strdupf("![CDATA[%s]]", data); + node->value.element.name = _mxml_strdupf("![CDATA[%s", data); return (node); } @@ -336,7 +337,7 @@ mxmlNewCustom( #ifdef MXMLDEBUG fprintf(stderr, "mxmlNewCustom(parent=%p, data=%p, destroy=%p)\n", parent, data, destroy); -#endif /* DEBUG */ +#endif /* MXMLDEBUG */ /* * Create the node and set the value... @@ -370,7 +371,7 @@ mxmlNewElement(mxml_node_t *parent, /* I - Parent node or @code MXML_NO_PARENT@ #ifdef MXMLDEBUG fprintf(stderr, "mxmlNewElement(parent=%p, name=\"%s\")\n", parent, name ? name : "(null)"); -#endif /* DEBUG */ +#endif /* MXMLDEBUG */ /* * Range check input... @@ -407,7 +408,7 @@ mxmlNewInteger(mxml_node_t *parent, /* I - Parent node or @code MXML_NO_PARENT@ #ifdef MXMLDEBUG fprintf(stderr, "mxmlNewInteger(parent=%p, integer=%d)\n", parent, integer); -#endif /* DEBUG */ +#endif /* MXMLDEBUG */ /* * Create the node and set the element name... @@ -439,7 +440,7 @@ mxmlNewOpaque(mxml_node_t *parent, /* I - Parent node or @code MXML_NO_PARENT@ * #ifdef MXMLDEBUG fprintf(stderr, "mxmlNewOpaque(parent=%p, opaque=\"%s\")\n", parent, opaque ? opaque : "(null)"); -#endif /* DEBUG */ +#endif /* MXMLDEBUG */ /* * Range check input... @@ -479,7 +480,7 @@ mxmlNewOpaquef(mxml_node_t *parent, /* I - Parent node or @code MXML_NO_PARENT@ #ifdef MXMLDEBUG fprintf(stderr, "mxmlNewOpaquef(parent=%p, format=\"%s\", ...)\n", parent, format ? format : "(null)"); -#endif /* DEBUG */ +#endif /* MXMLDEBUG */ /* * Range check input... @@ -522,7 +523,7 @@ mxmlNewReal(mxml_node_t *parent, /* I - Parent node or @code MXML_NO_PARENT@ */ #ifdef MXMLDEBUG fprintf(stderr, "mxmlNewReal(parent=%p, real=%g)\n", parent, real); -#endif /* DEBUG */ +#endif /* MXMLDEBUG */ /* * Create the node and set the element name... @@ -556,7 +557,7 @@ mxmlNewText(mxml_node_t *parent, /* I - Parent node or @code MXML_NO_PARENT@ */ #ifdef MXMLDEBUG fprintf(stderr, "mxmlNewText(parent=%p, whitespace=%d, string=\"%s\")\n", parent, whitespace, string ? string : "(null)"); -#endif /* DEBUG */ +#endif /* MXMLDEBUG */ /* * Range check input... @@ -602,7 +603,7 @@ mxmlNewTextf(mxml_node_t *parent, /* I - Parent node or @code MXML_NO_PARENT@ */ #ifdef MXMLDEBUG fprintf(stderr, "mxmlNewTextf(parent=%p, whitespace=%d, format=\"%s\", ...)\n", parent, whitespace, format ? format : "(null)"); -#endif /* DEBUG */ +#endif /* MXMLDEBUG */ /* * Range check input... @@ -641,7 +642,7 @@ mxmlRemove(mxml_node_t *node) /* I - Node to remove */ { #ifdef MXMLDEBUG fprintf(stderr, "mxmlRemove(node=%p)\n", node); -#endif /* DEBUG */ +#endif /* MXMLDEBUG */ /* * Range check input... @@ -654,7 +655,7 @@ mxmlRemove(mxml_node_t *node) /* I - Node to remove */ * Remove from parent... */ -#if DEBUG > 1 +#if MXMLDEBUG > 1 fprintf(stderr, " BEFORE: node->parent=%p\n", node->parent); if (node->parent) { @@ -665,7 +666,7 @@ mxmlRemove(mxml_node_t *node) /* I - Node to remove */ fprintf(stderr, " BEFORE: node->last_child=%p\n", node->last_child); fprintf(stderr, " BEFORE: node->prev=%p\n", node->prev); fprintf(stderr, " BEFORE: node->next=%p\n", node->next); -#endif /* DEBUG > 1 */ +#endif /* MXMLDEBUG > 1 */ if (node->prev) node->prev->next = node->next; @@ -681,7 +682,7 @@ mxmlRemove(mxml_node_t *node) /* I - Node to remove */ node->prev = NULL; node->next = NULL; -#if DEBUG > 1 +#if MXMLDEBUG > 1 fprintf(stderr, " AFTER: node->parent=%p\n", node->parent); if (node->parent) { @@ -692,7 +693,7 @@ mxmlRemove(mxml_node_t *node) /* I - Node to remove */ fprintf(stderr, " AFTER: node->last_child=%p\n", node->last_child); fprintf(stderr, " AFTER: node->prev=%p\n", node->prev); fprintf(stderr, " AFTER: node->next=%p\n", node->next); -#endif /* DEBUG > 1 */ +#endif /* MXMLDEBUG > 1 */ } @@ -834,9 +835,9 @@ mxml_new(mxml_node_t *parent, /* I - Parent node */ mxml_node_t *node; /* New node */ -#if DEBUG > 1 +#if MXMLDEBUG > 1 fprintf(stderr, "mxml_new(parent=%p, type=%d)\n", parent, type); -#endif /* DEBUG > 1 */ +#endif /* MXMLDEBUG > 1 */ /* * Allocate memory for the node... @@ -844,16 +845,16 @@ mxml_new(mxml_node_t *parent, /* I - Parent node */ if ((node = PhAllocateExSafe(sizeof(mxml_node_t), HEAP_ZERO_MEMORY)) == NULL) { -#if DEBUG > 1 +#if MXMLDEBUG > 1 fputs(" returning NULL\n", stderr); -#endif /* DEBUG > 1 */ +#endif /* MXMLDEBUG > 1 */ return (NULL); } -#if DEBUG > 1 +#if MXMLDEBUG > 1 fprintf(stderr, " returning %p\n", node); -#endif /* DEBUG > 1 */ +#endif /* MXMLDEBUG > 1 */ /* * Set the node type... diff --git a/phlib/mxml/mxml-set.c b/phlib/mxml/mxml-set.c index ffc5228b0d67..5af723745825 100644 --- a/phlib/mxml/mxml-set.c +++ b/phlib/mxml/mxml-set.c @@ -1,7 +1,7 @@ /* * Node set functions for Mini-XML, a small XML file parsing library. * - * Copyright 2003-2017 by Michael R Sweet. + * Copyright 2003-2018 by Michael R Sweet. * * These coded instructions, statements, and computer programs are the * property of Michael R Sweet and are protected by Federal copyright @@ -17,6 +17,7 @@ */ #include + #include "config.h" #include "mxml.h" @@ -54,7 +55,7 @@ mxmlSetCDATA(mxml_node_t *node, /* I - Node to set */ if (node->value.element.name) PhFree(node->value.element.name); - node->value.element.name = _mxml_strdupf("![CDATA[%s]]", data); + node->value.element.name = _mxml_strdupf("![CDATA[%s", data); return (0); } diff --git a/phlib/mxml/mxml-string.c b/phlib/mxml/mxml-string.c index 0341a2d8a6dd..c09c40dcb9d8 100644 --- a/phlib/mxml/mxml-string.c +++ b/phlib/mxml/mxml-string.c @@ -1,7 +1,7 @@ /* * String functions for Mini-XML, a small XML file parsing library. * - * Copyright 2003-2017 by Michael R Sweet. + * Copyright 2003-2018 by Michael R Sweet. * * These coded instructions, statements, and computer programs are the * property of Michael R Sweet and are protected by Federal copyright @@ -17,6 +17,7 @@ */ #include + #include "config.h" @@ -29,7 +30,7 @@ # ifdef __va_copy # define va_copy(dst,src) __va_copy(dst,src) # else -# define va_copy(dst,src) memcpy(&dst, src, sizeof(va_list)) +# define va_copy(dst,src) memcpy(&dst, &src, sizeof(va_list)) # endif /* __va_copy */ #endif /* va_copy */ diff --git a/phlib/mxml/mxml.h b/phlib/mxml/mxml.h index e1922c75cd65..e608cb863782 100644 --- a/phlib/mxml/mxml.h +++ b/phlib/mxml/mxml.h @@ -28,7 +28,9 @@ # include # include # include -# include + +// dmex: Include custom types. +#include #ifdef _PHAPP_ #define PHMXMLAPI __declspec(dllexport) @@ -36,25 +38,26 @@ #define PHMXMLAPI #endif + /* * Constants... */ # define MXML_MAJOR_VERSION 2 /* Major version number */ -# define MXML_MINOR_VERSION 11 /* Minor version number */ +# define MXML_MINOR_VERSION 12 /* Minor version number */ # define MXML_TAB 8 /* Tabs every N columns */ # define MXML_NO_CALLBACK 0 /* Don't use a type callback */ # define MXML_INTEGER_CALLBACK mxml_integer_cb - /* Treat all data as integers */ + /* Treat all data as integers */ # define MXML_OPAQUE_CALLBACK mxml_opaque_cb - /* Treat all data as opaque */ + /* Treat all data as opaque */ # define MXML_REAL_CALLBACK mxml_real_cb - /* Treat all data as real numbers */ + /* Treat all data as real numbers */ # define MXML_TEXT_CALLBACK 0 /* Treat all data as text */ # define MXML_IGNORE_CALLBACK mxml_ignore_cb - /* Ignore all non-element content */ + /* Ignore all non-element content */ # define MXML_NO_PARENT 0 /* No parent for the node */ @@ -98,10 +101,10 @@ typedef enum mxml_type_e /**** The XML node type. ****/ } mxml_type_t; typedef void (*mxml_custom_destroy_cb_t)(void *); - /**** Custom data destructor ****/ + /**** Custom data destructor ****/ typedef void (*mxml_error_cb_t)(const char *); - /**** Error callback function ****/ + /**** Error callback function ****/ typedef struct mxml_attr_s /**** An XML element attribute value. @private@ ****/ { @@ -163,25 +166,25 @@ struct mxml_index_s /**** An XML node index. @private@ ****/ }; typedef struct mxml_index_s mxml_index_t; - /**** An XML node index. ****/ + /**** An XML node index. ****/ typedef int (*mxml_custom_load_cb_t)(mxml_node_t *, const char *); - /**** Custom data load callback function ****/ + /**** Custom data load callback function ****/ typedef char *(*mxml_custom_save_cb_t)(mxml_node_t *); - /**** Custom data save callback function ****/ + /**** Custom data save callback function ****/ typedef int (*mxml_entity_cb_t)(const char *); - /**** Entity callback function */ + /**** Entity callback function */ typedef mxml_type_t (*mxml_load_cb_t)(mxml_node_t *); - /**** Load callback function ****/ + /**** Load callback function ****/ typedef const char *(*mxml_save_cb_t)(mxml_node_t *, int); - /**** Save callback function ****/ + /**** Save callback function ****/ typedef void (*mxml_sax_cb_t)(mxml_node_t *, mxml_sax_event_t, void *); - /**** SAX callback function ****/ + /**** SAX callback function ****/ /* @@ -197,17 +200,17 @@ extern "C" { */ PHMXMLAPI extern void mxmlAdd(mxml_node_t *parent, int where, - mxml_node_t *child, mxml_node_t *node); + mxml_node_t *child, mxml_node_t *node); PHMXMLAPI extern void mxmlDelete(mxml_node_t *node); PHMXMLAPI extern void mxmlElementDeleteAttr(mxml_node_t *node, - const char *name); + const char *name); PHMXMLAPI extern const char *mxmlElementGetAttr(mxml_node_t *node, const char *name); extern const char *mxmlElementGetAttrByIndex(mxml_node_t *node, int idx, const char **name); extern int mxmlElementGetAttrCount(mxml_node_t *node); PHMXMLAPI extern void mxmlElementSetAttr(mxml_node_t *node, const char *name, - const char *value); + const char *value); extern void mxmlElementSetAttrf(mxml_node_t *node, const char *name, - const char *format, ...) + const char *format, ...) # ifdef __GNUC__ __attribute__ ((__format__ (__printf__, 3, 4))) # endif /* __GNUC__ */ @@ -217,8 +220,8 @@ extern const char *mxmlEntityGetName(int val); extern int mxmlEntityGetValue(const char *name); extern void mxmlEntityRemoveCallback(mxml_entity_cb_t cb); PHMXMLAPI extern mxml_node_t *mxmlFindElement(mxml_node_t *node, mxml_node_t *top, - const char *element, const char *attr, - const char *value, int descend); + const char *element, const char *attr, + const char *value, int descend); extern mxml_node_t *mxmlFindPath(mxml_node_t *node, const char *path); extern const char *mxmlGetCDATA(mxml_node_t *node); extern const void *mxmlGetCustom(mxml_node_t *node); @@ -238,27 +241,27 @@ extern void *mxmlGetUserData(mxml_node_t *node); extern void mxmlIndexDelete(mxml_index_t *ind); extern mxml_node_t *mxmlIndexEnum(mxml_index_t *ind); extern mxml_node_t *mxmlIndexFind(mxml_index_t *ind, - const char *element, - const char *value); + const char *element, + const char *value); extern int mxmlIndexGetCount(mxml_index_t *ind); extern mxml_index_t *mxmlIndexNew(mxml_node_t *node, const char *element, - const char *attr); + const char *attr); extern mxml_node_t *mxmlIndexReset(mxml_index_t *ind); PHMXMLAPI extern mxml_node_t *mxmlLoadFd(mxml_node_t *top, HANDLE fd, - mxml_type_t (*cb)(mxml_node_t *)); + mxml_type_t (*cb)(mxml_node_t *)); extern mxml_node_t *mxmlLoadFile(mxml_node_t *top, FILE *fp, - mxml_type_t (*cb)(mxml_node_t *)); + mxml_type_t (*cb)(mxml_node_t *)); PHMXMLAPI extern mxml_node_t *mxmlLoadString(mxml_node_t *top, const char *s, - mxml_type_t (*cb)(mxml_node_t *)); + mxml_type_t (*cb)(mxml_node_t *)); PHMXMLAPI extern mxml_node_t *mxmlNewCDATA(mxml_node_t *parent, const char *string); PHMXMLAPI extern mxml_node_t *mxmlNewCustom(mxml_node_t *parent, void *data, - mxml_custom_destroy_cb_t destroy); + mxml_custom_destroy_cb_t destroy); PHMXMLAPI extern mxml_node_t *mxmlNewElement(mxml_node_t *parent, const char *name); PHMXMLAPI extern mxml_node_t *mxmlNewInteger(mxml_node_t *parent, int integer); PHMXMLAPI extern mxml_node_t *mxmlNewOpaque(mxml_node_t *parent, const char *opaque); extern mxml_node_t *mxmlNewOpaquef(mxml_node_t *parent, const char *format, ...) # ifdef __GNUC__ -__attribute__((__format__(__printf__, 2, 3))) +__attribute__ ((__format__ (__printf__, 2, 3))) # endif /* __GNUC__ */ ; PHMXMLAPI extern mxml_node_t *mxmlNewReal(mxml_node_t *parent, double real); @@ -273,41 +276,41 @@ PHMXMLAPI extern int mxmlRelease(mxml_node_t *node); PHMXMLAPI extern void mxmlRemove(mxml_node_t *node); PHMXMLAPI extern int mxmlRetain(mxml_node_t *node); PHMXMLAPI extern char *mxmlSaveAllocString(mxml_node_t *node, - mxml_save_cb_t cb); + mxml_save_cb_t cb); PHMXMLAPI extern int mxmlSaveFd(mxml_node_t *node, HANDLE fd, - mxml_save_cb_t cb); + mxml_save_cb_t cb); extern int mxmlSaveFile(mxml_node_t *node, FILE *fp, - mxml_save_cb_t cb); -PHMXMLAPI extern int mxmlSaveString(mxml_node_t *node, char *buffer, - int bufsize, mxml_save_cb_t cb); + mxml_save_cb_t cb); +extern int mxmlSaveString(mxml_node_t *node, char *buffer, + int bufsize, mxml_save_cb_t cb); extern mxml_node_t *mxmlSAXLoadFd(mxml_node_t *top, HANDLE fd, - mxml_type_t (*cb)(mxml_node_t *), - mxml_sax_cb_t sax, void *sax_data); + mxml_type_t (*cb)(mxml_node_t *), + mxml_sax_cb_t sax, void *sax_data); extern mxml_node_t *mxmlSAXLoadFile(mxml_node_t *top, FILE *fp, - mxml_type_t (*cb)(mxml_node_t *), - mxml_sax_cb_t sax, void *sax_data); + mxml_type_t (*cb)(mxml_node_t *), + mxml_sax_cb_t sax, void *sax_data); extern mxml_node_t *mxmlSAXLoadString(mxml_node_t *top, const char *s, - mxml_type_t (*cb)(mxml_node_t *), - mxml_sax_cb_t sax, void *sax_data); + mxml_type_t (*cb)(mxml_node_t *), + mxml_sax_cb_t sax, void *sax_data); PHMXMLAPI extern int mxmlSetCDATA(mxml_node_t *node, const char *data); PHMXMLAPI extern int mxmlSetCustom(mxml_node_t *node, void *data, - mxml_custom_destroy_cb_t destroy); + mxml_custom_destroy_cb_t destroy); PHMXMLAPI extern void mxmlSetCustomHandlers(mxml_custom_load_cb_t load, - mxml_custom_save_cb_t save); + mxml_custom_save_cb_t save); PHMXMLAPI extern int mxmlSetElement(mxml_node_t *node, const char *name); PHMXMLAPI extern void mxmlSetErrorCallback(mxml_error_cb_t cb); extern int mxmlSetInteger(mxml_node_t *node, int integer); PHMXMLAPI extern int mxmlSetOpaque(mxml_node_t *node, const char *opaque); extern int mxmlSetOpaquef(mxml_node_t *node, const char *format, ...) # ifdef __GNUC__ -__attribute__((__format__(__printf__, 2, 3))) +__attribute__ ((__format__ (__printf__, 2, 3))) # endif /* __GNUC__ */ ; extern int mxmlSetReal(mxml_node_t *node, double real); PHMXMLAPI extern int mxmlSetText(mxml_node_t *node, int whitespace, - const char *string); + const char *string); extern int mxmlSetTextf(mxml_node_t *node, int whitespace, - const char *format, ...) + const char *format, ...) # ifdef __GNUC__ __attribute__ ((__format__ (__printf__, 3, 4))) # endif /* __GNUC__ */ @@ -315,9 +318,9 @@ __attribute__ ((__format__ (__printf__, 3, 4))) PHMXMLAPI extern int mxmlSetUserData(mxml_node_t *node, void *data); extern void mxmlSetWrapMargin(int column); PHMXMLAPI extern mxml_node_t *mxmlWalkNext(mxml_node_t *node, mxml_node_t *top, - int descend); + int descend); PHMXMLAPI extern mxml_node_t *mxmlWalkPrev(mxml_node_t *node, mxml_node_t *top, - int descend); + int descend); /* From 06b114db41f47c3bb6140e7ffa98bac907db015e Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 8 Oct 2018 21:35:27 +1100 Subject: [PATCH 1420/2058] Fix #332 --- plugins/ExtendedTools/unldll.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/plugins/ExtendedTools/unldll.c b/plugins/ExtendedTools/unldll.c index e607cc44085d..60cb62ac1453 100644 --- a/plugins/ExtendedTools/unldll.c +++ b/plugins/ExtendedTools/unldll.c @@ -251,8 +251,8 @@ static INT NTAPI EtpNumberCompareFunction( return uintcmp(item1->Sequence, item2->Sequence); } else - { #endif + { PRTL_UNLOAD_EVENT_TRACE item1 = Item1; PRTL_UNLOAD_EVENT_TRACE item2 = Item2; @@ -277,8 +277,8 @@ static INT NTAPI EtpBaseAddressCompareFunction( return uintptrcmp((ULONG_PTR)item1->BaseAddress, (ULONG_PTR)item2->BaseAddress); } else - { #endif + { PRTL_UNLOAD_EVENT_TRACE item1 = Item1; PRTL_UNLOAD_EVENT_TRACE item2 = Item2; @@ -303,8 +303,8 @@ static INT NTAPI EtpSizeCompareFunction( return uintptrcmp(item1->SizeOfImage, item2->SizeOfImage); } else - { #endif + { PRTL_UNLOAD_EVENT_TRACE item1 = Item1; PRTL_UNLOAD_EVENT_TRACE item2 = Item2; @@ -329,8 +329,8 @@ static INT NTAPI EtpTimeStampCompareFunction( return uintcmp(item1->TimeDateStamp, item2->TimeDateStamp); } else - { #endif + { PRTL_UNLOAD_EVENT_TRACE item1 = Item1; PRTL_UNLOAD_EVENT_TRACE item2 = Item2; @@ -355,8 +355,8 @@ static INT NTAPI EtpCheckSumCompareFunction( return uintcmp(item1->CheckSum, item2->CheckSum); } else - { #endif + { PRTL_UNLOAD_EVENT_TRACE item1 = Item1; PRTL_UNLOAD_EVENT_TRACE item2 = Item2; From d4d632666a2d77b9cd84e564aaa412caaca7c57f Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 9 Oct 2018 13:42:06 +1100 Subject: [PATCH 1421/2058] Fix crash when viewing handle properties with an unknown type --- ProcessHacker/hndlprp.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/ProcessHacker/hndlprp.c b/ProcessHacker/hndlprp.c index af68899ec54a..de2cbfa3a68a 100644 --- a/ProcessHacker/hndlprp.c +++ b/ProcessHacker/hndlprp.c @@ -359,7 +359,11 @@ VOID PhpUpdateHandleGeneralListViewGroups( NULL ); - if (PhEqualString2(Context->HandleItem->TypeName, L"ALPC Port", TRUE)) + if (PhIsNullOrEmptyString(Context->HandleItem->TypeName)) + { + NOTHING; + } + else if (PhEqualString2(Context->HandleItem->TypeName, L"ALPC Port", TRUE)) { PhAddListViewGroup(Context->ListViewHandle, PH_HANDLE_GENERAL_CATEGORY_ALPC, L"ALPC Port"); Context->ListViewRowCache[PH_HANDLE_GENERAL_INDEX_SEQUENCENUMBER] = PhAddListViewGroupItem( @@ -582,7 +586,11 @@ VOID PhpUpdateHandleGeneral( NtClose(processHandle); } - if (PhEqualString2(Context->HandleItem->TypeName, L"ALPC Port", TRUE)) + if (PhIsNullOrEmptyString(Context->HandleItem->TypeName)) + { + NOTHING; + } + else if (PhEqualString2(Context->HandleItem->TypeName, L"ALPC Port", TRUE)) { NTSTATUS status; HANDLE processHandle; From 339c6d6d8ba08e9262d2f97563746f08514b9860 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 9 Oct 2018 15:14:29 +1100 Subject: [PATCH 1422/2058] Add PhGetObjectTypeName --- phlib/hndlinfo.c | 41 ++++++++++++++++++++++++++++++++++++++++ phlib/include/hndlinfo.h | 7 +++++++ 2 files changed, 48 insertions(+) diff --git a/phlib/hndlinfo.c b/phlib/hndlinfo.c index 5874192d9594..4c2384fe96ad 100644 --- a/phlib/hndlinfo.c +++ b/phlib/hndlinfo.c @@ -1493,6 +1493,47 @@ ULONG PhGetObjectTypeNumber( return objectIndex; } +PPH_STRING PhGetObjectTypeName( + _In_ ULONG TypeIndex + ) +{ + POBJECT_TYPES_INFORMATION objectTypes; + POBJECT_TYPE_INFORMATION objectType; + PPH_STRING objectTypeName = NULL; + ULONG i; + + if (NT_SUCCESS(PhEnumObjectTypes(&objectTypes))) + { + objectType = PH_FIRST_OBJECT_TYPE(objectTypes); + + for (i = 0; i < objectTypes->NumberOfTypes; i++) + { + if (WindowsVersion >= WINDOWS_8_1) + { + if (TypeIndex == objectType->TypeIndex) + { + objectTypeName = PhCreateStringFromUnicodeString(&objectType->TypeName); + break; + } + } + else + { + if (TypeIndex == (i + 2)) + { + objectTypeName = PhCreateStringFromUnicodeString(&objectType->TypeName); + break; + } + } + + objectType = PH_NEXT_OBJECT_TYPE(objectType); + } + + PhFree(objectTypes); + } + + return objectTypeName; +} + PPHP_CALL_WITH_TIMEOUT_THREAD_CONTEXT PhpAcquireCallWithTimeoutThread( _In_opt_ PLARGE_INTEGER Timeout ) diff --git a/phlib/include/hndlinfo.h b/phlib/include/hndlinfo.h index 48f3312cf48f..292dd01f3497 100644 --- a/phlib/include/hndlinfo.h +++ b/phlib/include/hndlinfo.h @@ -90,6 +90,13 @@ PhGetObjectTypeNumber( _In_ PUNICODE_STRING TypeName ); +PHLIBAPI +PPH_STRING +NTAPI +PhGetObjectTypeName( + _In_ ULONG TypeIndex + ); + PHLIBAPI NTSTATUS NTAPI From aefc62d7c7732e61b869e60e18faf83fa9e35a1a Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 9 Oct 2018 15:16:24 +1100 Subject: [PATCH 1423/2058] Fix missing handle type when NtQueryObject has been hooked by kernel --- ProcessHacker/hndlprv.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/ProcessHacker/hndlprv.c b/ProcessHacker/hndlprv.c index 7f5f40b00b5d..a95a4d33b01f 100644 --- a/ProcessHacker/hndlprv.c +++ b/ProcessHacker/hndlprv.c @@ -625,6 +625,19 @@ VOID PhHandleProviderUpdate( NULL ); + // HACK: Some security products block NtQueryObject with ObjectTypeInformation and return an invalid type + // so we need to lookup the TypeName using the TypeIndex. We should improve PhGetHandleInformationEx for this case + // but for now we'll preserve backwards compat by doing the lookup here. (dmex) + if (PhIsNullOrEmptyString(handleItem->TypeName)) + { + PPH_STRING typeName; + + if (typeName = PhGetObjectTypeName(handleItem->TypeIndex)) + { + PhMoveReference(&handleItem->TypeName, typeName); + } + } + if (handleItem->TypeName && PhEqualString2(handleItem->TypeName, L"File", TRUE) && KphIsConnected()) { KPH_FILE_OBJECT_INFORMATION objectInfo; From 527b5e1173983649f33b7b861a48d9728acc1c40 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 9 Oct 2018 15:23:13 +1100 Subject: [PATCH 1424/2058] Add initial .NET Core support #333 --- ProcessHacker/procprv.c | 8 +++++++- plugins/DotNetTools/asmpage.c | 3 ++- plugins/DotNetTools/main.c | 10 ++++++++-- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/ProcessHacker/procprv.c b/ProcessHacker/procprv.c index 9542696b0976..adfbc912f1ad 100644 --- a/ProcessHacker/procprv.c +++ b/ProcessHacker/procprv.c @@ -2200,10 +2200,16 @@ VOID PhProcessProviderUpdate( if (processItem->UpdateIsDotNet) { BOOLEAN isDotNet; + ULONG flags = 0; - if (NT_SUCCESS(PhGetProcessIsDotNet(processItem->ProcessId, &isDotNet))) + if (NT_SUCCESS(PhGetProcessIsDotNetEx(processItem->ProcessId, NULL, 0, &isDotNet, &flags))) { processItem->IsDotNet = isDotNet; + + // This check is needed for the DotNetTools plugin. (dmex) + if (!isDotNet && (flags & PH_CLR_JIT_PRESENT)) + processItem->IsDotNet = TRUE; + modified = TRUE; } diff --git a/plugins/DotNetTools/asmpage.c b/plugins/DotNetTools/asmpage.c index dd22db3f7dae..0231632ac112 100644 --- a/plugins/DotNetTools/asmpage.c +++ b/plugins/DotNetTools/asmpage.c @@ -1214,7 +1214,7 @@ NTSTATUS DotNetTraceQueryThreadStart( } } - if (context->ClrVersions & PH_CLR_VERSION_4_ABOVE) + if ((context->ClrVersions & PH_CLR_VERSION_4_ABOVE) || (context->ClrVersions & PH_CLR_JIT_PRESENT)) // PH_CLR_JIT_PRESENT CoreCLR support. (dmex) { result = UpdateDotNetTraceInfoWithTimeout(context, FALSE, &timeout); @@ -1224,6 +1224,7 @@ NTSTATUS DotNetTraceQueryThreadStart( result = ERROR_SUCCESS; } } + // If we reached the timeout, check whether we got any data back. if (timeoutReached) { diff --git a/plugins/DotNetTools/main.c b/plugins/DotNetTools/main.c index 593250671dfb..9d8364d9e650 100644 --- a/plugins/DotNetTools/main.c +++ b/plugins/DotNetTools/main.c @@ -108,15 +108,21 @@ VOID NTAPI ProcessPropertiesInitializingCallback( ) { PPH_PLUGIN_PROCESS_PROPCONTEXT propContext = Parameter; - BOOLEAN isDotNet; + BOOLEAN isDotNet = FALSE; + ULONG flags = 0; - if (NT_SUCCESS(PhGetProcessIsDotNet(propContext->ProcessItem->ProcessId, &isDotNet))) + if (NT_SUCCESS(PhGetProcessIsDotNetEx(propContext->ProcessItem->ProcessId, NULL, 0, &isDotNet, &flags))) { if (isDotNet) { AddAsmPageToPropContext(propContext); AddPerfPageToPropContext(propContext); } + else if (flags & PH_CLR_JIT_PRESENT) // CoreCLR support. (dmex) + { + isDotNet = TRUE; + AddAsmPageToPropContext(propContext); + } if (propContext->ProcessItem->IsDotNet != isDotNet) propContext->ProcessItem->UpdateIsDotNet = TRUE; // force a refresh From 1f8916ffe398548273334d1198ca90fcdca76074 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 9 Oct 2018 15:51:28 +1100 Subject: [PATCH 1425/2058] Add highlighting for DPC and Interrupt processes --- ProcessHacker/proctree.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/ProcessHacker/proctree.c b/ProcessHacker/proctree.c index ee1050c1323f..8742b1e2c031 100644 --- a/ProcessHacker/proctree.c +++ b/ProcessHacker/proctree.c @@ -2992,14 +2992,13 @@ BOOLEAN NTAPI PhpProcessTreeNewCallback( getNodeColor->BackColor = PhCsColorJobProcesses; else if ( PhCsUseColorServiceProcesses && - (processItem->Sid && RtlEqualSid(processItem->Sid, &PhSeLocalServiceSid) || + ((processItem->Sid && RtlEqualSid(processItem->Sid, &PhSeLocalServiceSid)) || processItem->ServiceList && processItem->ServiceList->Count != 0)) getNodeColor->BackColor = PhCsColorServiceProcesses; else if ( PhCsUseColorSystemProcesses && - processItem->Sid && - RtlEqualSid(processItem->Sid, &PhSeLocalSystemSid) - ) + ((processItem->Sid && RtlEqualSid(processItem->Sid, &PhSeLocalSystemSid)) || + PH_IS_FAKE_PROCESS_ID(processItem->ProcessId))) getNodeColor->BackColor = PhCsColorSystemProcesses; else if ( PhCsUseColorOwnProcesses && From 619842a8f3af818a3a18f37d264d37a38d5dca53 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 10 Oct 2018 04:22:30 +1100 Subject: [PATCH 1426/2058] Fix typo (Fixes #325) --- phlib/include/symprvp.h | 2 +- phlib/symprv.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/phlib/include/symprvp.h b/phlib/include/symprvp.h index 880e14a00c72..a0c368ea9e85 100644 --- a/phlib/include/symprvp.h +++ b/phlib/include/symprvp.h @@ -105,7 +105,7 @@ typedef ULONG64 (WINAPI *_SymGetModuleBase64)( typedef BOOL (WINAPI *_SymRegisterCallbackW64)( _In_ HANDLE ProcessHandle, _In_ PSYMBOL_REGISTERED_CALLBACK64 CallbackFunction, - _In_ PVOID UserContext + _In_ ULONG64 UserContext ); typedef BOOL (WINAPI *_StackWalk64)( diff --git a/phlib/symprv.c b/phlib/symprv.c index ffffff5ce864..f6932a6d55dd 100644 --- a/phlib/symprv.c +++ b/phlib/symprv.c @@ -356,7 +356,7 @@ VOID PhpRegisterSymbolProvider( SymInitializeW_I(SymbolProvider->ProcessHandle, NULL, FALSE); if (SymRegisterCallbackW64_I) - SymRegisterCallbackW64_I(SymbolProvider->ProcessHandle, PhpSymbolCallbackFunction, SymbolProvider); + SymRegisterCallbackW64_I(SymbolProvider->ProcessHandle, PhpSymbolCallbackFunction, (ULONG64)SymbolProvider); PH_UNLOCK_SYMBOLS(); From b7101892cb64bea42e399d6439a3d8a3760d6f72 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 10 Oct 2018 18:53:59 +1100 Subject: [PATCH 1427/2058] Revert "Update to latest WinSDK" This reverts commit 7ac8c2a0d1ba5daed3b2190d7a81d288fb49248b. --- ProcessHacker/ProcessHacker.vcxproj | 2 +- phlib/phlib.vcxproj | 2 +- plugins/DotNetTools/DotNetTools.vcxproj | 2 +- plugins/ExtendedNotifications/ExtendedNotifications.vcxproj | 2 +- plugins/ExtendedServices/ExtendedServices.vcxproj | 2 +- plugins/ExtendedTools/ExtendedTools.vcxproj | 2 +- plugins/HardwareDevices/HardwareDevices.vcxproj | 2 +- plugins/NetworkTools/NetworkTools.vcxproj | 2 +- plugins/OnlineChecks/OnlineChecks.vcxproj | 2 +- plugins/ToolStatus/ToolStatus.vcxproj | 2 +- plugins/Updater/Updater.vcxproj | 2 +- plugins/UserNotes/UserNotes.vcxproj | 2 +- plugins/WindowExplorer/WindowExplorer.vcxproj | 2 +- tools/peview/peview.vcxproj | 2 +- 14 files changed, 14 insertions(+), 14 deletions(-) diff --git a/ProcessHacker/ProcessHacker.vcxproj b/ProcessHacker/ProcessHacker.vcxproj index 2896a1a4087c..5fbd4fd8b4d3 100644 --- a/ProcessHacker/ProcessHacker.vcxproj +++ b/ProcessHacker/ProcessHacker.vcxproj @@ -22,7 +22,7 @@ {0271DD27-6707-4290-8DFE-285702B7115D} ProcessHacker Win32Proj - 10.0.17763.0 + 10.0.17134.0 diff --git a/phlib/phlib.vcxproj b/phlib/phlib.vcxproj index 40147221b2be..bb62d0be9420 100644 --- a/phlib/phlib.vcxproj +++ b/phlib/phlib.vcxproj @@ -22,7 +22,7 @@ {477D0215-F252-41A1-874B-F27E3EA1ED17} phlib Win32Proj - 10.0.17763.0 + 10.0.17134.0 diff --git a/plugins/DotNetTools/DotNetTools.vcxproj b/plugins/DotNetTools/DotNetTools.vcxproj index 66df5200d23f..7b5daab17c0c 100644 --- a/plugins/DotNetTools/DotNetTools.vcxproj +++ b/plugins/DotNetTools/DotNetTools.vcxproj @@ -23,7 +23,7 @@ DotNetTools Win32Proj DotNetTools - 10.0.17763.0 + 10.0.17134.0 diff --git a/plugins/ExtendedNotifications/ExtendedNotifications.vcxproj b/plugins/ExtendedNotifications/ExtendedNotifications.vcxproj index 41fdf7c61cdd..efc911ed6ee4 100644 --- a/plugins/ExtendedNotifications/ExtendedNotifications.vcxproj +++ b/plugins/ExtendedNotifications/ExtendedNotifications.vcxproj @@ -23,7 +23,7 @@ ExtendedNotifications Win32Proj ExtendedNotifications - 10.0.17763.0 + 10.0.17134.0 diff --git a/plugins/ExtendedServices/ExtendedServices.vcxproj b/plugins/ExtendedServices/ExtendedServices.vcxproj index 073a89063451..4d3e69179c81 100644 --- a/plugins/ExtendedServices/ExtendedServices.vcxproj +++ b/plugins/ExtendedServices/ExtendedServices.vcxproj @@ -23,7 +23,7 @@ ExtendedServices Win32Proj ExtendedServices - 10.0.17763.0 + 10.0.17134.0 diff --git a/plugins/ExtendedTools/ExtendedTools.vcxproj b/plugins/ExtendedTools/ExtendedTools.vcxproj index 72d6713a4085..9fd33f94cc8f 100644 --- a/plugins/ExtendedTools/ExtendedTools.vcxproj +++ b/plugins/ExtendedTools/ExtendedTools.vcxproj @@ -23,7 +23,7 @@ ExtendedTools Win32Proj ExtendedTools - 10.0.17763.0 + 10.0.17134.0 diff --git a/plugins/HardwareDevices/HardwareDevices.vcxproj b/plugins/HardwareDevices/HardwareDevices.vcxproj index 39b3efefb8ba..a606468d867c 100644 --- a/plugins/HardwareDevices/HardwareDevices.vcxproj +++ b/plugins/HardwareDevices/HardwareDevices.vcxproj @@ -23,7 +23,7 @@ HardwareDevices Win32Proj HardwareDevices - 10.0.17763.0 + 10.0.17134.0 diff --git a/plugins/NetworkTools/NetworkTools.vcxproj b/plugins/NetworkTools/NetworkTools.vcxproj index 00a63496d21a..9e81f5632366 100644 --- a/plugins/NetworkTools/NetworkTools.vcxproj +++ b/plugins/NetworkTools/NetworkTools.vcxproj @@ -23,7 +23,7 @@ NetworkTools Win32Proj NetworkTools - 10.0.17763.0 + 10.0.17134.0 diff --git a/plugins/OnlineChecks/OnlineChecks.vcxproj b/plugins/OnlineChecks/OnlineChecks.vcxproj index ce8e88b3d4c2..ef6144e5ac96 100644 --- a/plugins/OnlineChecks/OnlineChecks.vcxproj +++ b/plugins/OnlineChecks/OnlineChecks.vcxproj @@ -23,7 +23,7 @@ OnlineChecks Win32Proj OnlineChecks - 10.0.17763.0 + 10.0.17134.0 diff --git a/plugins/ToolStatus/ToolStatus.vcxproj b/plugins/ToolStatus/ToolStatus.vcxproj index b31153c1de42..b60b882c7f35 100644 --- a/plugins/ToolStatus/ToolStatus.vcxproj +++ b/plugins/ToolStatus/ToolStatus.vcxproj @@ -23,7 +23,7 @@ ToolStatus Win32Proj ToolStatus - 10.0.17763.0 + 10.0.17134.0 diff --git a/plugins/Updater/Updater.vcxproj b/plugins/Updater/Updater.vcxproj index 4434a44bdb14..c9e89da0b5b4 100644 --- a/plugins/Updater/Updater.vcxproj +++ b/plugins/Updater/Updater.vcxproj @@ -23,7 +23,7 @@ Updater Win32Proj Updater - 10.0.17763.0 + 10.0.17134.0 diff --git a/plugins/UserNotes/UserNotes.vcxproj b/plugins/UserNotes/UserNotes.vcxproj index 72732b329e56..ee6737ebeea7 100644 --- a/plugins/UserNotes/UserNotes.vcxproj +++ b/plugins/UserNotes/UserNotes.vcxproj @@ -23,7 +23,7 @@ UserNotes Win32Proj UserNotes - 10.0.17763.0 + 10.0.17134.0 diff --git a/plugins/WindowExplorer/WindowExplorer.vcxproj b/plugins/WindowExplorer/WindowExplorer.vcxproj index 422766289ee6..7389b4273fd7 100644 --- a/plugins/WindowExplorer/WindowExplorer.vcxproj +++ b/plugins/WindowExplorer/WindowExplorer.vcxproj @@ -23,7 +23,7 @@ WindowExplorer Win32Proj WindowExplorer - 10.0.17763.0 + 10.0.17134.0 diff --git a/tools/peview/peview.vcxproj b/tools/peview/peview.vcxproj index 253070db6d5b..32f9c2deeec1 100644 --- a/tools/peview/peview.vcxproj +++ b/tools/peview/peview.vcxproj @@ -22,7 +22,7 @@ {72C124A2-3C80-41C6-ABA1-C4948B713204} peview Win32Proj - 10.0.17763.0 + 10.0.17134.0 From ac3325a7a5c703dfa6ee6233cae4b2375a069fab Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 10 Oct 2018 19:09:04 +1100 Subject: [PATCH 1428/2058] Fix 32bit WinSDK path typo --- phlib/symprv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phlib/symprv.c b/phlib/symprv.c index f6932a6d55dd..9f0638d28c4b 100644 --- a/phlib/symprv.c +++ b/phlib/symprv.c @@ -260,7 +260,7 @@ VOID PhpSymbolProviderCompleteInitialization( #ifdef _WIN64 PhMoveReference(&winsdkPath, PhConcatStringRefZ(&winsdkPath->sr, L"\\Debuggers\\x64\\")); #else - PhMoveReference(&winsdkPath, PhConcatStringRefZ(&winsdkPath->sr, L"\\Debuggers\\x64\\")); + PhMoveReference(&winsdkPath, PhConcatStringRefZ(&winsdkPath->sr, L"\\Debuggers\\x86\\")); #endif } From c3b0da64bd72f3ef5898d940d43bf9bdfb3697c5 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 11 Oct 2018 16:09:31 +1100 Subject: [PATCH 1429/2058] Fix themed tab invalidate --- phlib/theme.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/phlib/theme.c b/phlib/theme.c index 3a2d39cd23ec..2935129fb5a0 100644 --- a/phlib/theme.c +++ b/phlib/theme.c @@ -1042,16 +1042,14 @@ LRESULT CALLBACK PhpThemeWindowDrawButton( DI_NORMAL ); } - else - { - DrawText( - DrawInfo->hdc, - buttonText->Buffer, - (UINT)buttonText->Length / sizeof(WCHAR), - &DrawInfo->rc, - DT_CENTER | DT_SINGLELINE | DT_VCENTER | DT_HIDEPREFIX - ); - } + + DrawText( + DrawInfo->hdc, + buttonText->Buffer, + (UINT)buttonText->Length / sizeof(WCHAR), + &DrawInfo->rc, + DT_CENTER | DT_SINGLELINE | DT_VCENTER | DT_HIDEPREFIX + ); } PhDereferenceObject(buttonText); @@ -1710,11 +1708,15 @@ LRESULT CALLBACK PhpThemeWindowTabControlWndSubclassProc( RECT clientRect; PAINTSTRUCT ps; - BeginPaint(WindowHandle, &ps); + if (!BeginPaint(WindowHandle, &ps)) + break; GetWindowRect(WindowHandle, &windowRect); GetClientRect(WindowHandle, &clientRect); + TabCtrl_AdjustRect(WindowHandle, FALSE, &clientRect); // Make sure we don't paint in the client area. + ExcludeClipRect(ps.hdc, clientRect.left, clientRect.top, clientRect.right, clientRect.bottom); + windowRect.right -= windowRect.left; windowRect.bottom -= windowRect.top; windowRect.left = 0; From 2758840506836a7a07ea7ec55be00ad7a0b99ed0 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 20 Oct 2018 15:10:49 +1100 Subject: [PATCH 1430/2058] Fix typo from commit cfa58786 --- ProcessHacker/proctree.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ProcessHacker/proctree.c b/ProcessHacker/proctree.c index 8742b1e2c031..17f158f37723 100644 --- a/ProcessHacker/proctree.c +++ b/ProcessHacker/proctree.c @@ -653,7 +653,7 @@ VOID PhTickProcessNodes( // it can be changed once, so we can only be sure that it won't be changed again if it is different // from Unaware (poizan42). if (node->DpiAwareness != 1) - node->ValidMask |= PHPN_DPIAWARENESS; + node->ValidMask &= ~PHPN_DPIAWARENESS; // Invalidate graph buffers. node->CpuGraphBuffers.Valid = FALSE; From d05858d920dcffb5882fb29558dd7587fa6d1f89 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 20 Oct 2018 15:23:53 +1100 Subject: [PATCH 1431/2058] peview: Add CFG GuardFlags text --- tools/peview/ldprp.c | 37 +++++++++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/tools/peview/ldprp.c b/tools/peview/ldprp.c index 39516c7b0dae..f7591c0ab35d 100644 --- a/tools/peview/ldprp.c +++ b/tools/peview/ldprp.c @@ -3,7 +3,7 @@ * PE viewer * * Copyright (C) 2010-2011 wj32 - * Copyright (C) 2017 dmex + * Copyright (C) 2017-2018 dmex * * This file is part of Process Hacker. * @@ -23,6 +23,39 @@ #include +PPH_STRING PvpGetPeGuardFlagsText( + _In_ ULONG GuardFlags + ) +{ + PH_STRING_BUILDER stringBuilder; + + PhInitializeStringBuilder(&stringBuilder, 10); + + if (GuardFlags & IMAGE_GUARD_CF_INSTRUMENTED) + PhAppendStringBuilder2(&stringBuilder, L"Instrumented, "); + if (GuardFlags & IMAGE_GUARD_CFW_INSTRUMENTED) + PhAppendStringBuilder2(&stringBuilder, L"Instrumented (Write), "); + if (GuardFlags & IMAGE_GUARD_CF_FUNCTION_TABLE_PRESENT) + PhAppendStringBuilder2(&stringBuilder, L"Function table, "); + if (GuardFlags & IMAGE_GUARD_SECURITY_COOKIE_UNUSED) + PhAppendStringBuilder2(&stringBuilder, L"Unused security cookie, "); + if (GuardFlags & IMAGE_GUARD_PROTECT_DELAYLOAD_IAT) + PhAppendStringBuilder2(&stringBuilder, L"Delay-load IAT protected, "); + if (GuardFlags & IMAGE_GUARD_DELAYLOAD_IAT_IN_ITS_OWN_SECTION) + PhAppendStringBuilder2(&stringBuilder, L"Delay-load private section, "); + if (GuardFlags & IMAGE_GUARD_CF_ENABLE_EXPORT_SUPPRESSION) + PhAppendStringBuilder2(&stringBuilder, L"Export supression, "); + if (GuardFlags & IMAGE_GUARD_CF_EXPORT_SUPPRESSION_INFO_PRESENT) + PhAppendStringBuilder2(&stringBuilder, L"Export information supression, "); + if (GuardFlags & IMAGE_GUARD_CF_LONGJUMP_TABLE_PRESENT) + PhAppendStringBuilder2(&stringBuilder, L"Longjump table, "); + + if (PhEndsWithString2(stringBuilder.String, L", ", FALSE)) + PhRemoveEndStringBuilder(&stringBuilder, 2); + + return PhFinalStringBuilderString(&stringBuilder); +} + INT_PTR CALLBACK PvpPeLoadConfigDlgProc( _In_ HWND hwndDlg, _In_ UINT uMsg, @@ -87,7 +120,7 @@ INT_PTR CALLBACK PvpPeLoadConfigDlgProc( \ if (RTL_CONTAINS_FIELD((Config), (Config)->Size, GuardCFCheckFunctionPointer)) \ { \ - ADD_VALUE(L"CFG GuardFlags", PhaFormatString(L"0x%Ix", (Config)->GuardFlags)->Buffer); \ + ADD_VALUE(L"CFG GuardFlags", PhaFormatString(L"0x%Ix", PH_AUTO_T(PH_STRING, PvpGetPeGuardFlagsText((Config)->GuardFlags))->Buffer, (Config)->GuardFlags)->Buffer); \ ADD_VALUE(L"CFG Check Function pointer", PhaFormatString(L"0x%Ix", (Config)->GuardCFCheckFunctionPointer)->Buffer); \ ADD_VALUE(L"CFG Check Dispatch pointer", PhaFormatString(L"0x%Ix", (Config)->GuardCFDispatchFunctionPointer)->Buffer); \ ADD_VALUE(L"CFG Function table", PhaFormatString(L"0x%Ix", (Config)->GuardCFFunctionTable)->Buffer); \ From baa2a1589a2b5996b54d6678b12c2d123dcc8e11 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 21 Oct 2018 06:55:46 +1100 Subject: [PATCH 1432/2058] Fix some RS4 types, Add NtQueryInformationByName --- phnt/include/ntexapi.h | 18 +++++++++++------- phnt/include/ntioapi.h | 14 ++++++++++++++ phnt/include/ntobapi.h | 2 ++ phnt/include/ntrtl.h | 5 ++++- 4 files changed, 31 insertions(+), 8 deletions(-) diff --git a/phnt/include/ntexapi.h b/phnt/include/ntexapi.h index e8304137b0be..6dafdd2896e3 100644 --- a/phnt/include/ntexapi.h +++ b/phnt/include/ntexapi.h @@ -3196,7 +3196,10 @@ typedef struct _SYSTEM_KERNEL_VA_SHADOW_INFORMATION ULONG KvaShadowInvpcid : 1; ULONG KvaShadowRequired : 1; // REDSTONE4 ULONG KvaShadowRequiredAvailable : 1; - ULONG Reserved : 26; + ULONG InvalidPteBit : 6; + ULONG L1DataCacheFlushSupported : 1; + ULONG L1TerminalFaultMitigationPresent : 1; + ULONG Reserved : 18; }; }; } SYSTEM_KERNEL_VA_SHADOW_INFORMATION, *PSYSTEM_KERNEL_VA_SHADOW_INFORMATION; @@ -3231,12 +3234,13 @@ typedef struct _SYSTEM_SPECULATION_CONTROL_INFORMATION ULONG IbrsPresent : 1; ULONG StibpPresent : 1; ULONG SmepPresent : 1; - ULONG MemoryDisambiguationDisableAvailable : 1; // REDSTONE4 (CVE-2018-3639) - ULONG MemoryDisambiguationDisableSupported : 1; - ULONG MemoryDisambiguationDisabledSystemWide : 1; - ULONG MemoryDisambiguationDisabledKernel : 1; - ULONG MemoryDisambiguationDisableRequired : 1; - ULONG Reserved : 19; + ULONG SpeculativeStoreBypassDisableAvailable : 1; // REDSTONE4 (CVE-2018-3639) + ULONG SpeculativeStoreBypassDisableSupported : 1; + ULONG SpeculativeStoreBypassDisabledSystemWide : 1; + ULONG SpeculativeStoreBypassDisabledKernel : 1; + ULONG SpeculativeStoreBypassDisableRequired : 1; + ULONG BpbDisabledKernelToUser : 1; + ULONG Reserved : 18; }; }; } SYSTEM_SPECULATION_CONTROL_INFORMATION, *PSYSTEM_SPECULATION_CONTROL_INFORMATION; diff --git a/phnt/include/ntioapi.h b/phnt/include/ntioapi.h index 7edf212f85c4..153b6c7d4e48 100644 --- a/phnt/include/ntioapi.h +++ b/phnt/include/ntioapi.h @@ -1163,6 +1163,7 @@ NtFlushBuffersFile( #define FLUSH_FLAGS_FILE_DATA_ONLY 0x00000001 #define FLUSH_FLAGS_NO_SYNC 0x00000002 +#define FLUSH_FLAGS_FILE_DATA_SYNC_ONLY 0x00000004 // REDSTONE1 #if (PHNT_VERSION >= PHNT_WIN8) NTSYSCALLAPI @@ -1188,6 +1189,19 @@ NtQueryInformationFile( _In_ FILE_INFORMATION_CLASS FileInformationClass ); +#if (PHNT_VERSION >= PHNT_REDSTONE2) +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQueryInformationByName( + _In_ POBJECT_ATTRIBUTES ObjectAttributes, + _Out_ PIO_STATUS_BLOCK IoStatusBlock, + _Out_writes_bytes_(Length) PVOID FileInformation, + _In_ ULONG Length, + _In_ FILE_INFORMATION_CLASS FileInformationClass + ); +#endif + NTSYSCALLAPI NTSTATUS NTAPI diff --git a/phnt/include/ntobapi.h b/phnt/include/ntobapi.h index e6255ca17145..2a281844528f 100644 --- a/phnt/include/ntobapi.h +++ b/phnt/include/ntobapi.h @@ -38,10 +38,12 @@ typedef enum _OBJECT_INFORMATION_CLASS MaxObjectInfoClass } OBJECT_INFORMATION_CLASS; #else +#define ObjectBasicInformation 0 #define ObjectNameInformation 1 #define ObjectTypesInformation 3 #define ObjectHandleFlagInformation 4 #define ObjectSessionInformation 5 +#define ObjectSessionObjectInformation 6 #endif typedef struct _OBJECT_BASIC_INFORMATION diff --git a/phnt/include/ntrtl.h b/phnt/include/ntrtl.h index 0c232022a6b8..fde3749e4126 100644 --- a/phnt/include/ntrtl.h +++ b/phnt/include/ntrtl.h @@ -2539,6 +2539,7 @@ typedef struct _RTL_USER_PROCESS_PARAMETERS PVOID PackageDependencyData; ULONG ProcessGroupId; ULONG LoaderThreads; + UNICODE_STRING RedirectionDllName; // REDSTONE4 } RTL_USER_PROCESS_PARAMETERS, *PRTL_USER_PROCESS_PARAMETERS; #define RTL_USER_PROC_PARAMS_NORMALIZED 0x00000001 @@ -7138,7 +7139,9 @@ RtlGetFrame( VOID ); -#define RTL_STACK_WALKING_MODE_FRAMES_TO_SKIP_SHIFT 8 +#define RTL_WALK_USER_MODE_STACK 0x00000001 +#define RTL_WALK_VALID_FLAGS 0x00000001 +#define RTL_STACK_WALKING_MODE_FRAMES_TO_SKIP_SHIFT 0x00000008 // private NTSYSAPI From 2a1d9f911440ea613af7a5f5076100bc5b2811c3 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 21 Oct 2018 06:58:11 +1100 Subject: [PATCH 1433/2058] ExtendedTools: Fix disk/network process property tabs dark theme --- plugins/ExtendedTools/disktab.c | 4 +++- plugins/ExtendedTools/etwprprp.c | 6 +++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/plugins/ExtendedTools/disktab.c b/plugins/ExtendedTools/disktab.c index 4ecd3890d376..b2ec7161685f 100644 --- a/plugins/ExtendedTools/disktab.c +++ b/plugins/ExtendedTools/disktab.c @@ -1131,13 +1131,15 @@ INT_PTR CALLBACK EtpDiskTabErrorDialogProc( { if (!PhGetOwnTokenAttributes().Elevated) { - SendMessage(GetDlgItem(hwndDlg, IDC_RESTART), BCM_SETSHIELD, 0, TRUE); + Button_SetElevationRequiredState(GetDlgItem(hwndDlg, IDC_RESTART), TRUE); } else { PhSetDialogItemText(hwndDlg, IDC_ERROR, L"Unable to start the kernel event tracing session."); ShowWindow(GetDlgItem(hwndDlg, IDC_RESTART), SW_HIDE); } + + PhInitializeWindowTheme(hwndDlg, !!PhGetIntegerSetting(L"EnableThemeSupport")); } break; case WM_COMMAND: diff --git a/plugins/ExtendedTools/etwprprp.c b/plugins/ExtendedTools/etwprprp.c index efde863af805..08a691c7a5ed 100644 --- a/plugins/ExtendedTools/etwprprp.c +++ b/plugins/ExtendedTools/etwprprp.c @@ -306,9 +306,7 @@ INT_PTR CALLBACK EtwDiskNetworkPageDlgProc( sampleCount = PhGetIntegerSetting(L"SampleCount"); - context = PhAllocate(sizeof(ET_DISKNET_CONTEXT)); - memset(context, 0, sizeof(ET_DISKNET_CONTEXT)); - + context = PhAllocateZero(sizeof(ET_DISKNET_CONTEXT)); context->WindowHandle = hwndDlg; context->Block = EtGetProcessBlock(processItem); context->Enabled = TRUE; @@ -337,6 +335,8 @@ INT_PTR CALLBACK EtwDiskNetworkPageDlgProc( context, &context->ProcessesUpdatedRegistration ); + + PhInitializeWindowTheme(hwndDlg, !!PhGetIntegerSetting(L"EnableThemeSupport")); } break; case WM_DESTROY: From 931269d20f75dc4a389e585ab3f58857ed838206 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 23 Oct 2018 13:23:48 +1100 Subject: [PATCH 1434/2058] Fix #334 --- tools/peview/pdb.c | 174 ++++++++++++++++++++++++++-------------- tools/peview/settings.c | 2 + 2 files changed, 114 insertions(+), 62 deletions(-) diff --git a/tools/peview/pdb.c b/tools/peview/pdb.c index f319fcecc395..db06b8833681 100644 --- a/tools/peview/pdb.c +++ b/tools/peview/pdb.c @@ -2267,55 +2267,130 @@ VOID ShowModuleSymbolInfo( //PhaFormatString(L"Public symbols: %s\n", info.Publics ? L"Available" : L"Not available")->Buffer } -PPH_STRING PvFindDbghelpPath( - _In_ ULONG Type +BOOLEAN PepSymbolProviderInitialization( + VOID ) { - static struct - { - BOOLEAN Type; - PH_STRINGREF AppendPath; - } locations[] = - { #ifdef _WIN64 - { FALSE, PH_STRINGREF_INIT(L"%ProgramFiles(x86)%\\Windows Kits\\10\\Debuggers\\x64\\dbghelp.dll") }, - { FALSE, PH_STRINGREF_INIT(L"%ProgramFiles(x86)%\\Windows Kits\\8.1\\Debuggers\\x64\\dbghelp.dll") }, - { FALSE, PH_STRINGREF_INIT(L"%ProgramFiles(x86)%\\Windows Kits\\8.0\\Debuggers\\x64\\dbghelp.dll") }, - { FALSE, PH_STRINGREF_INIT(L"%ProgramFiles%\\Debugging Tools for Windows (x64)\\dbghelp.dll") }, - { TRUE, PH_STRINGREF_INIT(L"%ProgramFiles(x86)%\\Windows Kits\\10\\Debuggers\\x64\\symsrv.dll") }, - { TRUE, PH_STRINGREF_INIT(L"%ProgramFiles(x86)%\\Windows Kits\\8.1\\Debuggers\\x64\\symsrv.dll") }, - { TRUE, PH_STRINGREF_INIT(L"%ProgramFiles(x86)%\\Windows Kits\\8.0\\Debuggers\\x64\\symsrv.dll") }, - { TRUE, PH_STRINGREF_INIT(L"%ProgramFiles%\\Debugging Tools for Windows (x64)\\symsrv.dll") } + static PH_STRINGREF windowsKitsRootKeyName = PH_STRINGREF_INIT(L"Software\\Wow6432Node\\Microsoft\\Windows Kits\\Installed Roots"); #else - { FALSE, PH_STRINGREF_INIT(L"%ProgramFiles%\\Windows Kits\\10\\Debuggers\\x86\\dbghelp.dll") }, - { FALSE, PH_STRINGREF_INIT(L"%ProgramFiles%\\Windows Kits\\8.1\\Debuggers\\x86\\dbghelp.dll") }, - { FALSE, PH_STRINGREF_INIT(L"%ProgramFiles%\\Windows Kits\\8.0\\Debuggers\\x86\\dbghelp.dll") }, - { FALSE, PH_STRINGREF_INIT(L"%ProgramFiles%\\Debugging Tools for Windows (x86)\\dbghelp.dll") }, - { TRUE, PH_STRINGREF_INIT(L"%ProgramFiles%\\Windows Kits\\10\\Debuggers\\x86\\symsrv.dll") }, - { TRUE, PH_STRINGREF_INIT(L"%ProgramFiles%\\Windows Kits\\8.1\\Debuggers\\x86\\symsrv.dll") }, - { TRUE, PH_STRINGREF_INIT(L"%ProgramFiles%\\Windows Kits\\8.0\\Debuggers\\x86\\symsrv.dll") }, - { TRUE, PH_STRINGREF_INIT(L"%ProgramFiles%\\Debugging Tools for Windows (x86)\\symsrv.dll") } + static PH_STRINGREF windowsKitsRootKeyName = PH_STRINGREF_INIT(L"Software\\Microsoft\\Windows Kits\\Installed Roots"); #endif - }; + static PH_STRINGREF dbghelpFileName = PH_STRINGREF_INIT(L"dbghelp.dll"); + static PH_STRINGREF symsrvFileName = PH_STRINGREF_INIT(L"symsrv.dll"); + PVOID dbghelpHandle; + PVOID symsrvHandle; + HANDLE keyHandle; + + if (PhFindLoaderEntry(NULL, NULL, &dbghelpFileName) && + PhFindLoaderEntry(NULL, NULL, &symsrvFileName)) + { + dbghelpHandle = PhGetLoaderEntryDllBase(L"dbghelp.dll"); + SymInitializeW_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymInitializeW", 0); + SymCleanup_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymCleanup", 0); + SymEnumSymbolsW_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymEnumSymbolsW", 0); + SymEnumTypesW_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymEnumTypesW", 0); + SymSetSearchPathW_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymSetSearchPathW", 0); + SymGetOptions_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymGetOptions", 0); + SymSetOptions_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymSetOptions", 0); + SymLoadModuleExW_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymLoadModuleExW", 0); + SymGetModuleInfoW64_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymGetModuleInfoW64", 0); + SymGetTypeFromNameW_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymGetTypeFromNameW", 0); + SymGetTypeInfo_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymGetTypeInfo", 0); + SymSetContext_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymSetContext", 0); + SymSearchW_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymSearchW", 0); + + if (SymInitializeW_I && SymCleanup_I && SymEnumSymbolsW_I && SymEnumTypesW_I && SymSetSearchPathW_I && + SymGetOptions_I && SymSetOptions_I && SymLoadModuleExW_I && SymGetModuleInfoW64_I && + SymGetTypeFromNameW_I && SymGetTypeInfo_I && SymSetContext_I && SymSearchW_I) + { + return TRUE; + } + } - PPH_STRING path; - ULONG i; + dbghelpHandle = NULL; + symsrvHandle = NULL; - for (i = 0; i < sizeof(locations) / sizeof(locations[0]); i++) + if (NT_SUCCESS(PhOpenKey( + &keyHandle, + KEY_READ, + PH_KEY_LOCAL_MACHINE, + &windowsKitsRootKeyName, + 0 + ))) { - if (locations[i].Type != Type) - continue; + PPH_STRING winsdkPath; + PPH_STRING dbghelpName; + PPH_STRING symsrvName; + + winsdkPath = PhQueryRegistryString(keyHandle, L"KitsRoot10"); // Windows 10 SDK - if (path = PhExpandEnvironmentStrings(&locations[i].AppendPath)) + if (PhIsNullOrEmptyString(winsdkPath)) + PhMoveReference(&winsdkPath, PhQueryRegistryString(keyHandle, L"KitsRoot81")); // Windows 8.1 SDK + + if (PhIsNullOrEmptyString(winsdkPath)) + PhMoveReference(&winsdkPath, PhQueryRegistryString(keyHandle, L"KitsRoot")); // Windows 8 SDK + + if (!PhIsNullOrEmptyString(winsdkPath)) + { +#ifdef _WIN64 + PhMoveReference(&winsdkPath, PhConcatStringRefZ(&winsdkPath->sr, L"\\Debuggers\\x64\\")); +#else + PhMoveReference(&winsdkPath, PhConcatStringRefZ(&winsdkPath->sr, L"\\Debuggers\\x86\\")); +#endif + } + + if (winsdkPath) { - if (RtlDoesFileExists_U(path->Buffer)) - return path; + if (dbghelpName = PhConcatStringRef2(&winsdkPath->sr, &dbghelpFileName)) + { + dbghelpHandle = LoadLibrary(dbghelpName->Buffer); + PhDereferenceObject(dbghelpName); + } - PhDereferenceObject(path); + if (symsrvName = PhConcatStringRef2(&winsdkPath->sr, &symsrvFileName)) + { + symsrvHandle = LoadLibrary(symsrvName->Buffer); + PhDereferenceObject(symsrvName); + } + + PhDereferenceObject(winsdkPath); } + + NtClose(keyHandle); + } + + if (!dbghelpHandle) + dbghelpHandle = LoadLibrary(L"dbghelp.dll"); + + if (!symsrvHandle) + symsrvHandle = LoadLibrary(L"symsrv.dll"); + + if (dbghelpHandle) + { + SymInitializeW_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymInitializeW", 0); + SymCleanup_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymCleanup", 0); + SymEnumSymbolsW_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymEnumSymbolsW", 0); + SymEnumTypesW_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymEnumTypesW", 0); + SymSetSearchPathW_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymSetSearchPathW", 0); + SymGetOptions_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymGetOptions", 0); + SymSetOptions_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymSetOptions", 0); + SymLoadModuleExW_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymLoadModuleExW", 0); + SymGetModuleInfoW64_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymGetModuleInfoW64", 0); + SymGetTypeFromNameW_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymGetTypeFromNameW", 0); + SymGetTypeInfo_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymGetTypeInfo", 0); + SymSetContext_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymSetContext", 0); + SymSearchW_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymSearchW", 0); + } + + if (SymInitializeW_I && SymCleanup_I && SymEnumSymbolsW_I && SymEnumTypesW_I && SymSetSearchPathW_I && + SymGetOptions_I && SymSetOptions_I && SymLoadModuleExW_I && SymGetModuleInfoW64_I && + SymGetTypeFromNameW_I && SymGetTypeInfo_I && SymSetContext_I && SymSearchW_I) + { + return TRUE; } - return NULL; + return FALSE; } NTSTATUS PeDumpFileSymbols( @@ -2324,36 +2399,11 @@ NTSTATUS PeDumpFileSymbols( { NTSTATUS status; HANDLE fileHandle = NULL; - HMODULE dbghelpHandle; - HMODULE symsrvHandle; ULONG64 baseAddress = 0; LARGE_INTEGER fileSize; - PPH_STRING dbghelpPath; - PPH_STRING symsrvPath; - - if (!(dbghelpPath = PvFindDbghelpPath(FALSE))) - return 1; - if (!(symsrvPath = PvFindDbghelpPath(TRUE))) - return 1; - - if (!(dbghelpHandle = LoadLibrary(dbghelpPath->Buffer))) - return 1; - if (!(symsrvHandle = LoadLibrary(symsrvPath->Buffer))) - return 1; - SymInitializeW_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymInitializeW", 0); - SymCleanup_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymCleanup", 0); - SymEnumSymbolsW_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymEnumSymbolsW", 0); - SymEnumTypesW_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymEnumTypesW", 0); - SymSetSearchPathW_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymSetSearchPathW", 0); - SymGetOptions_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymGetOptions", 0); - SymSetOptions_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymSetOptions", 0); - SymLoadModuleExW_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymLoadModuleExW", 0); - SymGetModuleInfoW64_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymGetModuleInfoW64", 0); - SymGetTypeFromNameW_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymGetTypeFromNameW", 0); - SymGetTypeInfo_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymGetTypeInfo", 0); - SymSetContext_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymSetContext", 0); - SymSearchW_I = PhGetDllBaseProcedureAddress(dbghelpHandle, "SymSearchW", 0); + if (!PepSymbolProviderInitialization()) + return STATUS_FAIL_CHECK; SymSetOptions_I( SymGetOptions_I() | diff --git a/tools/peview/settings.c b/tools/peview/settings.c index 28f2082e0720..49079b3b84a7 100644 --- a/tools/peview/settings.c +++ b/tools/peview/settings.c @@ -31,6 +31,8 @@ VOID PhAddDefaultSettings( { PhpAddIntegerSetting(L"FirstRun", L"1"); PhpAddStringSetting(L"Font", L""); // null + PhpAddIntegerSetting(L"EnableThemeSupport", L"0"); + PhpAddIntegerSetting(L"GraphColorMode", L"0"); PhpAddIntegerSetting(L"HashAlgorithm", L"0"); PhpAddIntegerSetting(L"MaxSizeUnit", L"6"); PhpAddStringSetting(L"MainWindowPage", L"General"); From 87a5cae3ade8656ab81cfc03d7474c52232c4677 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 23 Oct 2018 19:30:59 +1100 Subject: [PATCH 1435/2058] Remove unused code, Update access_mask usage --- ProcessHacker/actions.c | 2 +- ProcessHacker/affinity.c | 4 ++-- ProcessHacker/anawait.c | 4 ++-- ProcessHacker/hidnproc.c | 2 +- ProcessHacker/hndlmenu.c | 2 +- ProcessHacker/options.c | 2 +- ProcessHacker/prpgthrd.c | 4 ++-- ProcessHacker/runas.c | 2 +- ProcessHacker/srvcr.c | 6 +++--- ProcessHacker/thrdprv.c | 2 +- phlib/apiimport.c | 2 +- phlib/hndlinfo.c | 3 +-- phlib/kphdata.c | 2 ++ phlib/treenew.c | 2 +- phlib/util.c | 4 ++-- plugins/DotNetTools/clrsup.c | 2 +- plugins/DotNetTools/perfpage.c | 2 +- plugins/DotNetTools/stackext.c | 2 +- plugins/DotNetTools/treeext.c | 2 +- plugins/UserNotes/main.c | 4 ++-- 20 files changed, 28 insertions(+), 27 deletions(-) diff --git a/ProcessHacker/actions.c b/ProcessHacker/actions.c index e2c87313584d..c61ea703a928 100644 --- a/ProcessHacker/actions.c +++ b/ProcessHacker/actions.c @@ -2609,7 +2609,7 @@ BOOLEAN PhUiSetPriorityThread( if (NT_SUCCESS(status = PhOpenThread( &threadHandle, - ThreadSetAccess, + THREAD_SET_LIMITED_INFORMATION, Thread->ThreadId ))) { diff --git a/ProcessHacker/affinity.c b/ProcessHacker/affinity.c index 408a5b671f18..51e40efca93f 100644 --- a/ProcessHacker/affinity.c +++ b/ProcessHacker/affinity.c @@ -149,7 +149,7 @@ static INT_PTR CALLBACK PhpProcessAffinityDlgProc( if (NT_SUCCESS(status = PhOpenThread( &threadHandle, - ThreadQueryAccess, + THREAD_QUERY_LIMITED_INFORMATION, context->ThreadItem->ThreadId ))) { @@ -272,7 +272,7 @@ static INT_PTR CALLBACK PhpProcessAffinityDlgProc( if (NT_SUCCESS(status = PhOpenThread( &threadHandle, - ThreadSetAccess, + THREAD_SET_LIMITED_INFORMATION, context->ThreadItem->ThreadId ))) { diff --git a/ProcessHacker/anawait.c b/ProcessHacker/anawait.c index 917147d77510..1223ebb8532e 100644 --- a/ProcessHacker/anawait.c +++ b/ProcessHacker/anawait.c @@ -141,11 +141,11 @@ VOID PhUiAnalyzeWaitThread( if (!NT_SUCCESS(status = PhOpenThread( &threadHandle, - ThreadQueryAccess | THREAD_GET_CONTEXT | THREAD_SUSPEND_RESUME, + THREAD_QUERY_LIMITED_INFORMATION | THREAD_GET_CONTEXT | THREAD_SUSPEND_RESUME, ThreadId ))) { - PhShowStatus(hWnd, L"Unable to open the thread", status, 0); + PhShowStatus(hWnd, L"Unable to open the thread.", status, 0); return; } diff --git a/ProcessHacker/hidnproc.c b/ProcessHacker/hidnproc.c index b13c0c830d74..cca818123369 100644 --- a/ProcessHacker/hidnproc.c +++ b/ProcessHacker/hidnproc.c @@ -1238,7 +1238,7 @@ NTSTATUS PhOpenProcessByCsrHandle( Handle->Handle, NtCurrentProcess(), &threadHandle, - ThreadQueryAccess, + THREAD_QUERY_LIMITED_INFORMATION, 0, 0 ))) diff --git a/ProcessHacker/hndlmenu.c b/ProcessHacker/hndlmenu.c index e5d88120d883..beaddf8b4c86 100644 --- a/ProcessHacker/hndlmenu.c +++ b/ProcessHacker/hndlmenu.c @@ -353,7 +353,7 @@ VOID PhShowHandleObjectProperties1( if (NT_SUCCESS(PhpDuplicateHandleFromProcessItem( &handle, - ThreadQueryAccess, + THREAD_QUERY_LIMITED_INFORMATION, Info->ProcessId, Info->Handle ))) diff --git a/ProcessHacker/options.c b/ProcessHacker/options.c index 8e74476e86f0..9655fd45d7eb 100644 --- a/ProcessHacker/options.c +++ b/ProcessHacker/options.c @@ -962,7 +962,7 @@ VOID PhpRefreshTaskManagerState( { if (!PhGetOwnTokenAttributes().Elevated) { - SendMessage(GetDlgItem(WindowHandle, IDC_REPLACETASKMANAGER), BCM_SETSHIELD, 0, TRUE); + Button_SetElevationRequiredState(GetDlgItem(WindowHandle, IDC_REPLACETASKMANAGER), TRUE); } if (PhpIsDefaultTaskManager()) diff --git a/ProcessHacker/prpgthrd.c b/ProcessHacker/prpgthrd.c index 956288d903ee..87bea2b8d2aa 100644 --- a/ProcessHacker/prpgthrd.c +++ b/ProcessHacker/prpgthrd.c @@ -173,7 +173,7 @@ VOID PhpInitializeThreadMenu( if (NT_SUCCESS(PhOpenThread( &threadHandle, - ThreadQueryAccess, + THREAD_QUERY_LIMITED_INFORMATION, Threads[0]->ThreadId ))) { @@ -723,7 +723,7 @@ INT_PTR CALLBACK PhpProcessThreadsDlgProc( { if (NT_SUCCESS(status = PhOpenThread( &threadHandle, - ThreadQueryAccess, + THREAD_QUERY_LIMITED_INFORMATION, threadItem->ThreadId ))) { diff --git a/ProcessHacker/runas.c b/ProcessHacker/runas.c index 6f4e06d72e13..03d48ea8b2a7 100644 --- a/ProcessHacker/runas.c +++ b/ProcessHacker/runas.c @@ -937,7 +937,7 @@ INT_PTR CALLBACK PhpRunAsDlgProc( Edit_SetSel(context->ProgramComboBoxWindowHandle, -1, -1); //if (!PhGetOwnTokenAttributes().Elevated) - // SendMessage(GetDlgItem(hwndDlg, IDOK), BCM_SETSHIELD, 0, TRUE); + // Button_SetElevationRequiredState(GetDlgItem(hwndDlg, IDOK), TRUE); PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport); } diff --git a/ProcessHacker/srvcr.c b/ProcessHacker/srvcr.c index 3d9cd0dc2b6f..f376ac96ac24 100644 --- a/ProcessHacker/srvcr.c +++ b/ProcessHacker/srvcr.c @@ -41,7 +41,7 @@ VOID PhShowCreateServiceDialog( DialogBox( PhInstanceHandle, MAKEINTRESOURCE(IDD_CREATESERVICE), - ParentWindowHandle, + PhCsForceNoParent ? NULL : ParentWindowHandle, PhpCreateServiceDlgProc ); } @@ -72,7 +72,7 @@ INT_PTR CALLBACK PhpCreateServiceDlgProc( if (!PhGetOwnTokenAttributes().Elevated) { - SendMessage(GetDlgItem(hwndDlg, IDOK), BCM_SETSHIELD, 0, TRUE); + Button_SetElevationRequiredState(GetDlgItem(hwndDlg, IDOK), TRUE); } PhSetDialogFocus(hwndDlg, GetDlgItem(hwndDlg, IDC_NAME)); @@ -81,7 +81,7 @@ INT_PTR CALLBACK PhpCreateServiceDlgProc( break; case WM_COMMAND: { - switch (LOWORD(wParam)) + switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDCANCEL: { diff --git a/ProcessHacker/thrdprv.c b/ProcessHacker/thrdprv.c index 974e05ca520f..a1adc9111d68 100644 --- a/ProcessHacker/thrdprv.c +++ b/ProcessHacker/thrdprv.c @@ -865,7 +865,7 @@ VOID PhpThreadProviderUpdate( { PhOpenThread( &threadItem->ThreadHandle, - ThreadQueryAccess, + THREAD_QUERY_LIMITED_INFORMATION, threadItem->ThreadId ); } diff --git a/phlib/apiimport.c b/phlib/apiimport.c index 13e8d9473ea9..2ac0e9290ea0 100644 --- a/phlib/apiimport.c +++ b/phlib/apiimport.c @@ -36,7 +36,7 @@ PVOID PhpImportProcedure( if (*CacheValid) return *Cache; - module = PhGetDllHandle(ModuleName); + module = PhGetLoaderEntryDllBase(ModuleName); if (!module) return NULL; diff --git a/phlib/hndlinfo.c b/phlib/hndlinfo.c index 4c2384fe96ad..6da6ffa923fd 100644 --- a/phlib/hndlinfo.c +++ b/phlib/hndlinfo.c @@ -84,7 +84,6 @@ typedef struct _PHP_QUERY_OBJECT_COMMON_CONTEXT FILE_INFORMATION_CLASS FileInformationClass; PVOID FileInformation; ULONG FileInformationLength; - PULONG ReturnLength; } NtQueryFileInformation; } u; } PHP_QUERY_OBJECT_COMMON_CONTEXT, *PPHP_QUERY_OBJECT_COMMON_CONTEXT; @@ -927,7 +926,7 @@ NTSTATUS PhpGetBestObjectName( Handle, NtCurrentProcess(), &dupHandle, - ThreadQueryAccess, + THREAD_QUERY_LIMITED_INFORMATION, 0, 0 ); diff --git a/phlib/kphdata.c b/phlib/kphdata.c index 836d2ad72c88..d15072cedbf2 100644 --- a/phlib/kphdata.c +++ b/phlib/kphdata.c @@ -77,9 +77,11 @@ NTSTATUS KphInitializeDynamicPackage( if (servicePack == 0) { + NOTHING; } else if (servicePack == 1) { + NOTHING; } else { diff --git a/phlib/treenew.c b/phlib/treenew.c index 6ae06f2885f1..e9f86950d22c 100644 --- a/phlib/treenew.c +++ b/phlib/treenew.c @@ -75,7 +75,7 @@ BOOLEAN PhTreeNewInitialization( if (!RegisterClassEx(&c)) return FALSE; - ComCtl32Handle = PhGetDllHandle(L"comctl32.dll"); + ComCtl32Handle = PhGetLoaderEntryDllBase(L"comctl32.dll"); SmallIconWidth = GetSystemMetrics(SM_CXSMICON); SmallIconHeight = GetSystemMetrics(SM_CYSMICON); diff --git a/phlib/util.c b/phlib/util.c index 79c71df4e1f3..fca92f3f7615 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -368,7 +368,7 @@ PPH_STRING PhGetNtMessage( PPH_STRING message; if (!NT_NTWIN32(Status)) - message = PhGetMessage(PhGetDllHandle(L"ntdll.dll"), 0xb, PhGetUserDefaultLangID(), (ULONG)Status); + message = PhGetMessage(PhGetLoaderEntryDllBase(L"ntdll.dll"), 0xb, PhGetUserDefaultLangID(), (ULONG)Status); else message = PhGetWin32Message(WIN32_FROM_NTSTATUS(Status)); @@ -410,7 +410,7 @@ PPH_STRING PhGetWin32Message( { PPH_STRING message; - message = PhGetMessage(PhGetDllHandle(L"kernel32.dll"), 0xb, PhGetUserDefaultLangID(), Result); + message = PhGetMessage(PhGetLoaderEntryDllBase(L"kernel32.dll"), 0xb, PhGetUserDefaultLangID(), Result); if (message) PhTrimToNullTerminatorString(message); diff --git a/plugins/DotNetTools/clrsup.c b/plugins/DotNetTools/clrsup.c index de6a352bab4b..32d66fb59ac9 100644 --- a/plugins/DotNetTools/clrsup.c +++ b/plugins/DotNetTools/clrsup.c @@ -283,7 +283,7 @@ ICLRDataTarget *DnCLRDataTarget_Create( HANDLE processHandle; BOOLEAN isWow64; - if (!NT_SUCCESS(PhOpenProcess(&processHandle, ProcessQueryAccess | PROCESS_VM_READ, ProcessId))) + if (!NT_SUCCESS(PhOpenProcess(&processHandle, PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_VM_READ, ProcessId))) return NULL; #ifdef _WIN64 diff --git a/plugins/DotNetTools/perfpage.c b/plugins/DotNetTools/perfpage.c index a60d647313d0..8b2fae6b6073 100644 --- a/plugins/DotNetTools/perfpage.c +++ b/plugins/DotNetTools/perfpage.c @@ -803,7 +803,7 @@ INT_PTR CALLBACK DotNetPerfPageDlgProc( if (NT_SUCCESS(PhOpenProcess( &context->ProcessHandle, - PROCESS_VM_READ | ProcessQueryAccess | PROCESS_DUP_HANDLE | SYNCHRONIZE, + PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_VM_READ | PROCESS_DUP_HANDLE | SYNCHRONIZE, context->ProcessItem->ProcessId ))) { diff --git a/plugins/DotNetTools/stackext.c b/plugins/DotNetTools/stackext.c index 13ef6a3aca5c..626d29d7b2e0 100644 --- a/plugins/DotNetTools/stackext.c +++ b/plugins/DotNetTools/stackext.c @@ -93,7 +93,7 @@ VOID ProcessThreadStackControl( context->ThreadHandle = Control->u.Initializing.ThreadHandle; #if _WIN64 - if (NT_SUCCESS(PhOpenProcess(&processHandle, ProcessQueryAccess, Control->u.Initializing.ProcessId))) + if (NT_SUCCESS(PhOpenProcess(&processHandle, PROCESS_QUERY_LIMITED_INFORMATION, Control->u.Initializing.ProcessId))) { PhGetProcessIsWow64(processHandle, &context->IsWow64); NtClose(processHandle); diff --git a/plugins/DotNetTools/treeext.c b/plugins/DotNetTools/treeext.c index 45f0338aaaa8..5890f60fdebe 100644 --- a/plugins/DotNetTools/treeext.c +++ b/plugins/DotNetTools/treeext.c @@ -236,7 +236,7 @@ VOID ThreadTreeNewInitializing( #if _WIN64 HANDLE processHandle; - if (NT_SUCCESS(PhOpenProcess(&processHandle, ProcessQueryAccess, threadsContext->Provider->ProcessId))) + if (NT_SUCCESS(PhOpenProcess(&processHandle, PROCESS_QUERY_LIMITED_INFORMATION, threadsContext->Provider->ProcessId))) { PhGetProcessIsWow64(processHandle, &context->IsWow64); NtClose(processHandle); diff --git a/plugins/UserNotes/main.c b/plugins/UserNotes/main.c index b8c7c6a38c34..43718883bdc9 100644 --- a/plugins/UserNotes/main.c +++ b/plugins/UserNotes/main.c @@ -183,7 +183,7 @@ NTSTATUS GetProcessAffinity( if (NT_SUCCESS(status = PhOpenProcess( &processHandle, - ProcessQueryAccess, + PROCESS_QUERY_LIMITED_INFORMATION, ProcessId ))) { @@ -213,7 +213,7 @@ IO_PRIORITY_HINT GetProcessIoPriority( if (NT_SUCCESS(PhOpenProcess( &processHandle, - ProcessQueryAccess, + PROCESS_QUERY_LIMITED_INFORMATION, ProcessId ))) { From fee5977e67d6f5cc5d216fca2f6bc5964bbd1049 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 23 Oct 2018 19:48:20 +1100 Subject: [PATCH 1436/2058] CustomBuildTool: Fix appx build --- .../CustomBuildTool/Properties/Resources.resx | 1 + .../CustomBuildTool/Source Files/AppxBuild.cs | 35 ++++++++++-------- tools/CustomBuildTool/Source Files/Utils.cs | 4 +- .../bin/Release/CustomBuildTool.exe | Bin 167424 -> 167936 bytes .../bin/Release/CustomBuildTool.pdb | Bin 83456 -> 83456 bytes 5 files changed, 22 insertions(+), 18 deletions(-) diff --git a/tools/CustomBuildTool/Properties/Resources.resx b/tools/CustomBuildTool/Properties/Resources.resx index 646f2393cb4d..146fd6cbbe91 100644 --- a/tools/CustomBuildTool/Properties/Resources.resx +++ b/tools/CustomBuildTool/Properties/Resources.resx @@ -143,6 +143,7 @@ </Dependencies> <Capabilities> <rescap:Capability Name="runFullTrust"/> + <rescap:Capability Name="allowElevation" /> </Capabilities> <Applications> <Application Id="ProcessHacker" Executable="ProcessHacker.exe" EntryPoint="Windows.FullTrustApplication"> diff --git a/tools/CustomBuildTool/Source Files/AppxBuild.cs b/tools/CustomBuildTool/Source Files/AppxBuild.cs index 62cceb489384..bf55db4a4e71 100644 --- a/tools/CustomBuildTool/Source Files/AppxBuild.cs +++ b/tools/CustomBuildTool/Source Files/AppxBuild.cs @@ -10,6 +10,7 @@ public static class AppxBuild { public static void BuildAppxPackage(string BuildOutputFolder, string BuildLongVersion, BuildFlags Flags) { + string error = string.Empty; string sdkRootPath = string.Empty; string[] cleanupAppxArray = { @@ -27,13 +28,13 @@ public static void BuildAppxPackage(string BuildOutputFolder, string BuildLongVe using (var view32 = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32)) { - using (var kitsroot = view32.OpenSubKey("Microsoft\\Windows Kits\\Installed Roots\\", false)) + using (var kitsroot = view32.OpenSubKey("Software\\Microsoft\\Windows Kits\\Installed Roots", false)) { sdkRootPath = (string)kitsroot.GetValue("WdkBinRootVersioned", string.Empty); } } - if (!string.IsNullOrEmpty(sdkRootPath)) + if (string.IsNullOrEmpty(sdkRootPath)) { Program.PrintColorMessage("[Skipped] Windows SDK", ConsoleColor.Red); return ; @@ -82,20 +83,20 @@ public static void BuildAppxPackage(string BuildOutputFolder, string BuildLongVe File.WriteAllText(BuildOutputFolder + "\\package32.map", packageMap32.ToString()); // create the package - Win32.ShellExecute( + error = Win32.ShellExecute( makeAppxExePath, "pack /o /f " + BuildOutputFolder + "\\package32.map /p " + BuildOutputFolder + "\\processhacker-build-package-x32.appx" ); - //Program.PrintColorMessage(Environment.NewLine + error, ConsoleColor.Gray); + Program.PrintColorMessage(Environment.NewLine + error, ConsoleColor.Gray, true, Flags); // sign the package - Win32.ShellExecute( + error = Win32.ShellExecute( signToolExePath, "sign /v /fd SHA256 /a /f " + BuildOutputFolder + "\\processhacker-appx.pfx /td SHA256 " + BuildOutputFolder + "\\processhacker-build-package-x32.appx" ); - //Program.PrintColorMessage(Environment.NewLine + error, ConsoleColor.Gray); + Program.PrintColorMessage(Environment.NewLine + error, ConsoleColor.Gray, true, Flags); } if ((Flags & BuildFlags.Build64bit) == BuildFlags.Build64bit) @@ -131,20 +132,20 @@ public static void BuildAppxPackage(string BuildOutputFolder, string BuildLongVe File.WriteAllText(BuildOutputFolder + "\\package64.map", packageMap64.ToString()); // create the package - Win32.ShellExecute( + error = Win32.ShellExecute( makeAppxExePath, "pack /o /f " + BuildOutputFolder + "\\package64.map /p " + BuildOutputFolder + "\\processhacker-build-package-x64.appx" ); - //Program.PrintColorMessage(Environment.NewLine + error, ConsoleColor.Gray); + Program.PrintColorMessage(Environment.NewLine + error, ConsoleColor.Gray, true, Flags); // sign the package - Win32.ShellExecute( + error = Win32.ShellExecute( signToolExePath, "sign /v /fd SHA256 /a /f " + BuildOutputFolder + "\\processhacker-appx.pfx /td SHA256 " + BuildOutputFolder + "\\processhacker-build-package-x64.appx" ); - //Program.PrintColorMessage(Environment.NewLine + error, ConsoleColor.Gray); + Program.PrintColorMessage(Environment.NewLine + error, ConsoleColor.Gray, true, Flags); } { @@ -159,20 +160,20 @@ public static void BuildAppxPackage(string BuildOutputFolder, string BuildLongVe File.Delete(BuildOutputFolder + "\\processhacker-build-package.appxbundle"); // create the appx bundle package - Win32.ShellExecute( + error = Win32.ShellExecute( makeAppxExePath, "bundle /f " + BuildOutputFolder + "\\bundle.map /p " + BuildOutputFolder + "\\processhacker-build-package.appxbundle" ); - //Program.PrintColorMessage(Environment.NewLine + error, ConsoleColor.Gray); + Program.PrintColorMessage(Environment.NewLine + error, ConsoleColor.Gray, true, Flags); // sign the appx bundle package - Win32.ShellExecute( + error = Win32.ShellExecute( signToolExePath, "sign /v /fd SHA256 /a /f " + BuildOutputFolder + "\\processhacker-appx.pfx /td SHA256 " + BuildOutputFolder + "\\processhacker-build-package.appxbundle" ); - //Program.PrintColorMessage(Environment.NewLine + error, ConsoleColor.Gray); + Program.PrintColorMessage(Environment.NewLine + error, ConsoleColor.Gray, true, Flags); } foreach (string file in cleanupAppxArray) @@ -201,13 +202,13 @@ public static bool BuildAppxSignature(string BuildOutputFolder) using (var view32 = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32)) { - using (var kitsroot = view32.OpenSubKey("Microsoft\\Windows Kits\\Installed Roots\\", false)) + using (var kitsroot = view32.OpenSubKey("Software\\Microsoft\\Windows Kits\\Installed Roots", false)) { sdkRootPath = (string)kitsroot.GetValue("WdkBinRootVersioned", string.Empty); } } - if (!string.IsNullOrEmpty(sdkRootPath)) + if (string.IsNullOrEmpty(sdkRootPath)) { Program.PrintColorMessage("[Skipped] Windows SDK", ConsoleColor.Red); return false; @@ -262,6 +263,8 @@ public static bool BuildAppxSignature(string BuildOutputFolder) Program.PrintColorMessage("[Certutil] " + output, ConsoleColor.Red); return false; } + + Program.PrintColorMessage("[Pvk2Pfx] " + output, ConsoleColor.Green); } catch (Exception ex) { diff --git a/tools/CustomBuildTool/Source Files/Utils.cs b/tools/CustomBuildTool/Source Files/Utils.cs index 4eb77de7b978..ceb828dc956d 100644 --- a/tools/CustomBuildTool/Source Files/Utils.cs +++ b/tools/CustomBuildTool/Source Files/Utils.cs @@ -67,10 +67,10 @@ public static string ShellExecute(string FileName, string args) process.StartInfo.Arguments = args; process.Start(); - process.WaitForExit(); - output = process.StandardOutput.ReadToEnd(); output = output.Replace("\n\n", "\r\n").Trim(); + + process.WaitForExit(); } return output; diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe b/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe index 7ab91c38d8baad6dfc01fc95cb13ff23652aec69..5150bd98f26bf9dadfc9099c70a27d06c6f19f9b 100644 GIT binary patch delta 20409 zcmbV!34l}O)%JUDlAGivnMo!y$?W?KnT>T=1s(RaEP@DvFl_25a^W2ml_dkXq9S?~ z6|I6`E7T34Qmri_RK*1qtaXC|Y88uC+Pc=|f6lo#%Z&Pc{rc^s=|+CU$G(zZ{MUS_2yKilRinPt-+tud|WB< zB8$NP#ai=-QeNG))QUO+8dbPN_Ju-R@Svaoq8asB7E#0q4~4EZ$E(h4kDG0w6-7em zI-}2=tzN45&9~HI^EPid`;;OUvcV{W&*DkQ;4`1{=AY$`RX|anDf3jZu*4rNj?G31 zwQe~SJXQ=_tP&7#%a(SEu(PCI-UyW{?-vQri;%UXyS&l7!I2lYjNi30I-@hAO~q(w z>k-y8CV^+?#)=U$9VNDuiog#97E zJOPh_xKRg}er;s&%YTuIH4TeEe@M~Upgvd9IuSG{MTdku1vk=YRYkaQ_fTRkGSom8|wt zB_la}SO;-Tk7y_>eXeB5-PGD2&z1D462epo;S)?w6(iZJ8UNc2UwI zbLD@UD*r{4v>hQF3frR`$Hc4#v$lkBs7v}VC-f)V>s5JUva#V*V^w*b$DUcSZirhS zOxJXWCbe?jf+u=jjZ@G6g9-NshxqT7&i~XMRFVHBiYJ^M3FpM?ibC0;oDJbfC}LIG z4T0(!%E1ulgmOaJYg@X%b0jYum6=|#FcgjTfHipr91*nx$5_YGc5GsK_}_nF7^==6FV zY^$IyFwi}ELy=q$g7b^c(_{zZ;5d8?o#QP^?C=kBBx~1wGA-&CEEix|70T}BQ9Zw6 zuKy?F9f^mW@(S3{iDr?np!q?_Mo+3kzWn%S^7NGH(RBL?aHKHox8{Yv{k%Z6kEqew zkPk;y8$oEPcW}{PfhOu=ZGCccjz|%;ce(Jxs4)Hu!f*K068@sYFAJb z61MJ{?QPT^*rs6jDOUTh0~aXWfH!*&m*5oRLiJw4{(t6p1s?v}n_lI={%Ur;=qJ zX>QESQ%0FjW>zaR%ww71PNR^aFk;=X7iXPZq~9&=&nG;Irc z9W}Ry3TunQ5YGW{{<K&qg$! z%|6L8&t};#P0g~Uz7T5pE3$EWJ|h8G+ApuqaPZIqmNeAVDt_4`u<3u~>C+I3j@?d^hg4Y&+ zUjbn6_B|Cb9|-sHa<$x^*f8@%xHNDOt|1q%0r{yJ$?h8W6hh;%HDtA9ju*lfKo4Xg z+64~CYPiZ#0IO;XiEc|$ZpZUUsujUH3}885P4wL)Ei49I42WB1Yxom$s>1}3kCXSO z0L!^^3Fs97iyk0aUYejQAj#uNIu?B;A5U}`4mGcJsA0#$%qua6@)L68J%50#sY(PYu0}hoNb{iNNIvU5K|@3a z&GVzhahk-5oQ>6qoT-e9q2r8xPofH)I^me-iI!f4anL3L-2}N~TV5eMwI$$91X>jn zrZcxwd|M1AK9w@%GmvF<4HUe@=aR&x;c^*dc|2jN>%~v;?edk@Ch~2j=Oa5L=bN1{ zVdgmH7BD*OXy*9MZMj{}I6`*5R*+=9VX30oAho)Lg`||lC##c|YBM*lG;b1k@}Q2? z+HYina;-TbFFJZ(d#jLNLBTV_9lMma=U_c}SAb^mNyM)Jc$m}uX(JdN@jLPcU$hT$ ziO)Vvq}o6)GYSx=L5ufG8s^q0)9TX9BOhIku&FxC3dyM7&R!6eo40ZRY4>k?vmb!kzm%G)g{YZzs+e{mRZa8$*87rHuV}ClJtn9`UuwZcWF6U z=A3=ICQFG+Cah+MWCY8Qq;|kdC@W86pCsA3ugR;@)Fj*L{dgJ0Zm}s`MXUkKl_+=3 z9C;gMP2Gd-DUs50)n0*<)s-p3Jes0Z2W#1J2~@V^rIsu~-ewv_RcXVQV?J6mDE=3C zCMOTy2D#sHbq;icC2_k=&fMY9{wG%xq)MpHphhRjK+4hpK1zb*UEISNNvZSpuQUhx92*z@#!1tnHccl zkhr}(soH|nbsb!;F$>BIE_jg~lg}izIOD@zHSs9DDZ&38bnuVG?Y?y?%GG0-t6Fiy z!H2l~V=p}H$IgL4&IsAXVa3?igRqw93HG*mPkFiWzPYD7dwjVjMQ>Epi%La`4SF<@ zy`Zqh2j7?I)tc;29`vm9W77gM`N>2t*kU#2jLN98!R%a-U-kt|buQ`YLyu^=GQw$| z#;?=pS#7b|Qc*a|y7br!%Te5H-$@+w+Bex)|No`2^k%qyV@n+#X*bvNzc$zN^Ud|h z|Gv3bSk1NGs$0$7URkJSdd*iVqvz2}u#*^9tcQ?%9j?~pfuz(G0q-dKCM+bSEWQr! zF;W)4Y)s~9G{;u0iq9ZUlPYXKb-$NXxa`O9ehCk)^)Yh9_bG9HwelcYrehKqH$xxt ztf0qS<3>xSDP!Eka!4~w7LpI?k0K{Oq{lJz-!jQ_Q#XjyV6a{^-^N+u8Hf`*mkPPv z3QVitxYLqpu^4y#OzaM!$EHI6(h7}b6SrgEYsI4t$k=4bVUjnq9C8_tSc22o&O&Sk zYD7;x)}udeMb^GG6Kc5;C2?QyKAzltTAL{k-V++L$m?BrdE>@x$RV!>k>-&0Q)pY~ zLNahB>h!MBz}FZ@nAkl*9X7enrO_e&Q8f zJZM#P8CpemJAPxQ6w>?GG3uO0RIFY43{@}tgIXBn_p?s122&Hg6Ow~a4QpzWl$vI` zT$r?wl(P8bJxL2m=6^cX#=D}LG3vP$+352?B<$?d8xzbMa&8E_cvrQbM#EZ2qsdA= zukl{p*8@k*erHOr^z_AOv_f;#?Pb4xlvSVwQ7^1)N3=gVOPysIkyi zEJ7;ZgezXneo8g1fg(AAC{%*CwgNDa9%FHmVGKj~(h(EVxWxQNti0!?FfGQNU!kwm z44jI3>GSBx&RrAiII(j11r_EqE`vj?*c?{Vx%2MtfB4}@NjM-22f!5QIKckHn4luI zltwHlFEsC~=~2}Ux$6r^c0EKtrl$PP`(g zD?GVOL2D`cLQeDK4V>o7U&UD{kk4>hDBtC@NM@Wt#YGUSBpGZv=@4u_r@69?(>%G3 z(|oyw(*pTBP7CGpoEFI=oEFQ^I4$u?XA=b~(Peg1oF$)(St`Fg-4X)wOiRd+7g$23 zTxJPDxy}+o@>iCSB_Fqhuzc1MvgO;BkRv~}goyms5~4CVkPFR~l>_;Ezmh!J$5Q3X zVU|!Jn=PSGuCRn6c@GI~7)57Er$qlg%EqYN$7!y7m(x7?8K?PD9YjSH$ZSpvWhJLY zvOA~6azva3^vP^X(518lpS;o%{PGS<2*`&mAwxc837PVMB?RShO9;t-TSAu926HRJ zGH40evfL7KWIs!Y$nk@%{*TJpmMT|XW(j%nR!hLJT0()`X$gh$SxYFA?^;5!{K67S zq&kF4EtL^VD3kS;P%clmgbF#{5-Mf$5Uc;ILQae1Do%^#dQLG~+bltsPg#ObzG?}6dE62L@+(Wokp5xZCz-O;5`waq zC4}UtxFu!DW=jam#g>pQueO97xxo@5@=;5O%4aMgSH58hdGcdRz{O!W7ltWk3562h zKG13_lKn|ojyoi}>`chZOCdsDY0mGGS91mWT5rW}s{0%UHb3287s^s;Bh>?{=JwM0 zra`g7e7H;B(Q&Bjm0G9EXoFPkT3UcuoJ~hI!P$JO!|ArNiP#FbHT>;JMwa+K;u503 zI+GnPW2M=>Yejq&%zEo;pfBQg7*|3F^!XQt-fLV1IqYnG62*sIAy>%B-;XTE7U~SS zmQo_$8i6zIYWUSxxNTj8mDacS*T7=n-LqcZXCp!;a($A_RXQq_jkIamuA^*q7pqHY zF1f3|cdvn>^?E=I6S6L>S(cFNd+qnAVe9o~akofU-2L$Fk7k|sYe6(ro6?BCE@+o; z;P}w-;?nOmZZhX~o35-g_jD^#ZZZGbEkArKYzA(A=!Mr%qTFuQckk44 z2MkqhIJBKH^kp5o1ziy_HbA`sC%Ch!AzHm+K7{YJJyfZ?*q{d8)R1Q> z#g0|Mg-d~vhyQI1zdL>S)ups*<#*_Ebt$c7zGk#yknr87y0jD;x`pD~&1E#DJLxt#u7}A&KQLJ;I;hU#zOSy4AxKTBYEfm>@S?i14Pom!w z@^cO-egy^3T3_$)BRE;@X^R?AgZj1N$3bY5H@!`$cUhv|9^=<$-^LpPnN-0CkfXj# zW|{{ZtF$uKnBO%PLB1_BzRqcv$#FR6wT#I{FMp}}& zsw2r<+suc1mc^DQO>f1EV~H?aciRi^D#;)?~TxhXm`jmm2fqeG5J z%$M+>`4Gd1B(ukG6HgHw(mQ;OhDlOi~1QUsGGMX=mc1hZ7@*Pu`{sd+RSLoghl zB)Xt}YO2>9qkhzDX-!vZ(Q0lc2KgHEU%hK80?1%Zj?R)~dj8R{x2DFf#yq1>Y524s z2TqP)iMg{+L;N?WTkC@WJ=>@HBZ0aZ9{fxLi(HOI-U8zxnCc5@E26pB5P)RuP!EHK zoW8nRH@=;B!;Yss#Hh=+cQD(Xona++{L~}hrQdnnt<~P*DxO)~S&7#=VvoY)toNuf zn!0tG%8xU#?I5*SJ@_WJ8IuLeE)>HfG`if!hHeH)cOnuYx;BDE7E?nIEWQ#KU?euMeT<4pQDws%QR|KPn6UU^pXNYu^|%MXP$Q2*_VCVp&L-_)UwU6~unI$LeHJjv}gkQX)Lk^X0%#^V|> z{)8rCBzZui#k3=(GF#8Ya-JG63YP<-`PlUm-lnUdv z!nlo>;B34M&^37t>L_odisFpY`96U&1_hai26PUXF!0knz7XtYW}F^tIzZV}we=OG z_-^l2Bz{l6fsw8M2R+Wbk-}-fH z{d8->HF#A=H1;NZYt`6WNOT7$KFxR=to0p$-<^^J9&hYj=o-Rm>@ZRXW9$gT`pUFW z>9(`U=t&y8=d}J6nl>y;XDuzvL0FhLWJ0fE>nw;Jg{}1%KyN(`^l5JO1~M4$fyLej zxQ!2h#^1~b&gfQ23f1@!*!mGb?+^sPj4@7_-<{F3$6@N*kKs}p?1Wdee<$bINg!NG zN(~$(y74IhENHQRnDd${qV&4KuepuSkVaci0nrD>Kh1laT9P(g7u(rN22Sfl`E-rn zN3{MMvaj`Xpx@&*zCem^Nxwvb({|IqLGiC3)(7P9(TU-&^U0Tz#Cp$C-%FFj#=xP4 zwu{7DuWbAR{9mLkMhI&Q@uz8Ovug!CwP=1%eXYk>1*xNZ*kcs8*9VRi@lS@j`~o)` z`pHn+pbg5`X2IZI?wL?wH#esY9Q8wdC4Hw=U4#o(>zjN!DtSuc<+aFa^`s$5L( zPHU)gRB!x{NtYDY{_bzAf^(QYH8mm+ql_OPI>pb2-1>7NpG$?*Qz6Z@LzcO}M%h(u zmziaQyC$nYV(2}}<>rS&&DgiFUg*=7euvcWE-9VuSuiD_dSl;%FYkvY9m%LxV?T%; z_YJ#J>4(=SSdH^5tUA9saGE1VDqm97HKFn+RqL9_%WNLebNYK!{rOg&8*WBxV+wND z4U?b1;7!vs%CDjEq-n~fYb<_zkfsUB5HwmsW1bpOkW&QBt0nZLdKC3H@NXydR)<+O zvUYj=nX(ik!+c;= zbq(g4ZUo_BgaEajTd|{SZI>WG?J$RN7A=Fj5ZmZ!emSb=fPZ5zuE4drxmt)e{8da` zEL#?wkMi)3M8*j5`dH}BnkaVSX@=%&#qhI64nevPe2dvK`V1wsW9#TYx#HcuA@Oci zFQD`gZpm)JH$%5EKEilkm^6)rgy&Zf&d4RamhsF=l21hmyX5qxXzafti!_5+(~0Bk zgQlApUDDs%P0VEcsJMR|M3j^2pJn~Mn)uM)f`1f~S=t2oo#GJ~sz7xMChWb%{UIMj zHbrdqk>=M0gioMa5%GHI1h0mpbBTL$+u*=C-pOqZ6@+~lZx53^G=uQvoO8Ur#0TmO z$SL&a>Yx;Od{(<%HF&45l z!qzuk-BHo6p;5$H@Ki*1=oQhzcr)w!62`?+WL89oaVr}pG2Y6W8pge>iE^MtEI-2f z!HnZMXfxyqZ6(gW-U)40jCqW8KEaT;QdQH!{W_<76M>y^Oc1uZ@f)^wXL&B;QPv2;19|@zS0);;yBAEArFK+ zz7*43tQRi*6o%kY9Gt}V1=a|sXvQu=>@R^rw@dsREY8M?ue~mDE%p^+f32A0(uBXk zVqaE#j{@JvQ9-tT1qX3-6n3%LCFPS`Ua`eye<&$*dxgKNWos>Q>0a@^&H97sVoG<* zwxz7l?Gv6xusDL=T|jghQLt;7ePpvX1oeqAJuTZgg)ZGEntNO9McDjeVIPY*vWOM- zwOBT@&uo^1n0|3B4hJfsjM@DD#Nz9Pm+55#EaP|iy88T?939A$cQ z?vkQOu1w+m1-V|GyQoMJnIgL#TZWxYh?U~@l3YDgyqjb-dQglRXW7)!0eV>6J>DEN zxl$Qpo&hcYpDDX>3>V{4{pI^8o*I z1gnJia?@Eu!GU<1@fJPZ_;5I#EeWKvJKF{QA=;>X48ru_OersW(E6|~Oj z^QXqU$x(tb%#Tz*;y-GaDY`r)c-J(~EH_x_gFO+W6JBf3r zaQW*+oBp^S6IV{Lj7uul&}C|>#g3Ki(Hq3I%+`z73pR+Z;@We_wq8UEH;C?{behG! zf~`?}WwSozFX+9*-07C>!O(osM|@?oVZNJ0KT&@!w|~9p<$F~>O+0_D<@z#$@;)Ql z#QM^c`d{=WGBDfVeODitWLv%O>w}YQMAhH*p<>PqQdm0%zC2*IUJT7DP=|_FZ8kXT zANnvsuT{|gn?{HgHoI3Rer0F5TDuXTrfPoG+VX_sP|a$y3K}UAH+Y)eP9;Z zZWbSV9KLblhS|(`!x|@^XSQBk?puscw9nW1)`;<9BT+ld1hHx^ zv8z3Qz(kxN*4XTAOvDM|7Mp$NJ0K>A4K_Os6LEsL&t|oldK1Jpo8610HbFdQv%`7B zo@5rk+H)0We8x7O&Flr6eZlOY&6Z&zP7rU~tU1Hun;_n|7`Eg9*z@zOYWG6%XNp&C zHas^7_Lj{iRvf@}{g}n#o;ejk(2s57KTyOZ@lTrxR}kz!HXDT{bCz(NXB9CG`}$eJ zZ?mP517fnsw%OH@AXt&j&c;eVTU6O>UQQ6Kv(4iBu<)jcUN(I-90WVVW*1}~z#I zJXc(Av)fVNx#Cuv{RRcj5O>?`_b70NxIe+r-802QHhTr#JySexGZU3*7JszauTYt0 z@tnO2m%FGr=ZMGAYnJrG(tUHEcjyPqr(=ilt#5XouiWbfl z>iO0%U55tFZFg|b6F#6}f=8wXURj5pUBw-tjyUBoE_fF*5}10F%F}@N9__ghzJjruK^y)cq7i{cYqaTl&!Yx z3$X{G-O3*EVKf9>RGOPPfvZY)i!uk*{gim2Xty|_G-utd>{m0Zs6SrtP&>X1Z4fmMDze5=ne!J| zZ_0Q_>E@vRdyTEsTZ-uG$jH43eYVZBQ5@s=17~n(Kc7M&$BB$L#MkWlwRp3vOr7A^ z>Fg<{I(n*|)LAH?LH%0HcJ@*iIb!&MOtx5GF;?{|^SzBqU&m?wo5bagn=&p@SHiO= zGFIC1oT3A2 zJ$ijCkove%)Rvu8E5%OdNwpC8PqmRf`!fy^bBbylW7r>4CFcut(6^x_aiu?J=#RlV zsrKg(laOJMW0T`V)d)wU7*V+!w*v~d)j`Efx2+$S|IRVjmPPe($9%D^G{dz2<+INC7Mq+Z{~XzI{uc#<>J>kgCXmssFn`~0bPk24OLV9! zQUcP*IN#aCaELr4+8Hk zC+z18!e>$CO4lCsO79w1U&lcV@g{Xu*=>*)6>I=50G>kR-?+X8?r@!Qoa6f=;@=<2 zL4>JQIfxK{D*q6QS%h{gYAfcAf^fTG{%a+fU#dKc@3%L44hXM0&-bM(q%JD@-j$~o z>rO3Cea;&Ie(cTGylOs{v{x;v*e&wZm|mdOI6uy+hW^D+y|!Qdq-wBMraqKE3V0Dt zof^c!f>8eyk4}Ku8gOeg;ramXJ+xHziuvM+&;^g#N9<1JG1Q9UhOkL=*xq2WE-oEU#p|iZ$16Foc##PDJBwD)54cne_sGBB9sIgnceb68%jTof0-46J6d8HVQqn_1qfyeQtu*bB|6 zz+TquhvxH)_n;{NQqU97WMn$ji^R|jhe{eOHWACLfX2wEU`-7)gEB_~Cuh!4e~+rS zK)yKhI^e3z&8jKlWuC1d>ofNQAIv-f{8Oga@uGM)vj+Ij%#lD}aE=4d&Yl*?vEXV4 zb?v&v6&<1oYPj9Zr(H&i61J6(q+! zHB1JxVGiSJ#$zsWRW!mf#(|8p7*{fGV%)=cj8Sp3KjT2gS&ScM6I_0X&3wr z#NS~24HXUE;i8LoBvKDv>0j#^gj>>ouq91XE>e~&>y-7%X63iaAC!H{0p+-ILOG>; zqfAt{s7KYW)MiK6RppxETI>3y>m}D)uD`kd?rPLpv|F_JquL?ub1lnV>R#Y(bKmNI z)P2bPo;x4!&4#~;0*RZzk)PQ7vapfPRW`GVGCzC7AARh7U46je~9(<9CSbHceDNwhug;1e763M zt!p^ujT~oG;Wdck&$tnIeWmGB@#?@KRM93}z?EXh3k!NFJ+jrI>L1l-)i>2_M}ec< z(ZkWt@rdIshs&Ao?BX2YoZ?*P{EhQXr{9(9YSsF=pK!lm_E2ZRA1blSQ z#rPVty)Nt-SbYqACRwJrKfrLK%+;v%JHv6L^reOm9DC&gRamw2=5g} ziZS?g(tsV;zLM`yMw_D#jnaezFZ6$5etYm2$^_u)=GvFDcKqv5U!^4HEU^$rxPgM^ z;yG}EIG<*lyR)GGi7Ip4pDTA<{^#bP(qO**L4A=@G#&?itGEE)OGs3(1=XB|2k6Df zRlcM5-!hfpE8hElefXA_MsHj&`1aQdyiMkm4+lA`-MJa&FF(9NbqKT5M_bL;KU$uj z=MH4ppRD;=%X6~YRw`L-SE*U&?zr^CQWxe%Mn>U|&pr)$l>w&m)nVn>j=z3&nbWNK zt{^yT{(NJ}(E0N&owc~dSWsTNW5RcP)gJaBB>oF_DmeYOb&ldcEq4@)>CA~kCjPz0 zYeVnqF30`W(deu@bywbRn-q@{tSp6_{W%@-?c4jSxoX$a+ohu1z3bJk${1x=hN{d_ zl|j3tQ(2-ZBX)hPD_^S0=v~JH%9o1ri(PMLD!mnD+^(z;e3f%|y-=d;@+jx+S`}0N zqA3^eI;V@W#HGk<4mK*g4mPTL-O3fa*7sL;RVf>Hjh(IT3M$)oX|3w*UggPM_bgMF rIF;SEM^>sYD!X?bU#Z^fQ1|yr`cabsgVz*PgD*7s~$wN@~$_ delta 20108 zcmb7s2Y^)N+3t7F%$%7yQ+8%&cV>IvW!OURb(gAu6s3!RfJ)P0zePonoki3LB8rEg z5~6?@OY9JlL{W|pfK%tVOe>iXB~>dt}t zI8wp=t<`202@g(RP=yylphyt~cTP~0T4S2hLEmzgLdd~bqm;W5EY{#pHJ(&ATb zD#c^`T`h{+gLb)I5lh0c5?DfxphKPjWxrS{R7)o!Qg6)(I%=IkN30C0cY}7wc2m}( z*#Q{s2vs}%)vS;I+;HN52^ei}labsFF8>OMM60QMSI`x5 zheLXwd(pa}JE(68d4eAKH+ba7YT(hYg$y2fGO4L+jDvrc;&VX1PtglN9gakN-LRlD z|5h5q$}l%>TV*8Z*;bh&GvKqWG8f(vNYPqqR2^VjWuEC6?L;cGWAw<>kRH^7?sW?W zPmZ5GdsdYblD+DTb%rN*tt(kpPtHD~Qc>rbMM2J!O(b*HQOsGb%AJgOJ}u&_{}N%3 z=gi8fPt5^u&}+_t{#s%VkSc8scvXqPwB~@f{T%QGed%++XU&13$Sr*iB=lF?;=gQY zKL-*4?dO1jjML|UKj;r-ghK&y4rBxan?k{0@Mm)%n4AM~thYvZw3!3JwsRoZb`JQG zy-X9F=0Grg4g}@n)Y|_(2LhM_fnXq*5vNJOb0C)NRp0+@4je)Om~K1=z9RYmYYw!D zh-2EMt>MgIX8QPLTH`m^*>;!``ghyvRe5W&5t*q*sPY;Y;(7nVS)kVjQku9P?FvNm=~=wX=PMGZYGkvT6#0p4B`cT} z46R$x?VZ-#P*|Qtp}}yp8)}%`j$1`_!x;1Y_&xTMT>KrtpBI1hp>t(3{(9i=F#ZyH zh$0(%f_`Z$8Cku^rdcj~G9B0rRlAs&i;l@7dqV7lyP;Wgo zKz z=xsZID7{sUR0loPMwWL#d?*H`7@c2W4hY7>F0O`b!*~?tH1$NLx)zD`LaN1j17m#v zo|>-CSYHTUSF9fr`6X&#Ho7(6WS2LS3ucgAeoY3t5wMgW9Skx2lhT6L z*kzGlENQBTMz5*SVhto{u_5GK220v%^l5R{M~A{#lWqFe`plFA>t1Lr@W^uz=4{uM z-uE6xSIJG3Bh4O6zCDmrBVFB0O-R_vGTPdxJ+Mv1o>1D%jhh1xKFs*mWHzY;6V)>fSG6^` zlZFj#3_5!!kCAs_!~)mo6j6h`qM9ksarG|EgVRuHd<21E|e1o&_>;&Cv{#CwWgD4K8MU6m~DOOrqxWN)9=?b4f+{l16BRU zBBP?Pd3SB5E(jOJ&P7atrIQoW9jKw^wYP(uYCImujn7OoM@J#BC~*-MBGknuYEcxT zf^rTVqqKCIY3W2qL((&ayp+^qK;%-AIzp-rVNqX)ILw$}`w%WeUQ52za${t$RM}uG z2v%J980n}6Y)Dpvb_nDz(6*p_2|n^&a$JlFA^$@(oSC5gAj$I+v^7_k5=6tanoyi& z{16b%0MmMuXi;8*N=R~FUTK2o<%2H- zuy@7R1CflUi{HzLtp-p5Ihupp`&y$_n;&Uf5l2KvYmD3@mm9$7q(uJ|dyPT4 zod^G!>=odWB=h}8C8#b>CoLqUEFKxINyLPWM{-M)VaB1{$lPXVljnW7+U&O4fZW+u zFXTs1@XT;VuR^~_oDxf92|zRXFyadVF6MLvyB&Y~^h&oh~4heH`vf69uQAVzTQ+vY&Ftpu@3XRPCiUs+dsLaH{NM#lW+ZQ?s zK0hxsrEOPe%0Pvh6`9n@c%it$nL0MY#_{~>PDY#3=`v)xA54~bDcYaVwaX&=j*={6 zZ9zD0>zv+(zF=nW=#piwo{^?ynYC=6j9SK~P{*+$Nn34ItytEdrbV*MksZ4vONmP+ ztY(K~4yGYVtqd=rP+kQdNwRt8lUJsxNw(Ddl8Hm6auu-@Ojn}ZGxOw)6#BDSk``MBl6lA2K5P}iYb zTJ7XTU}lbUA(_2(S#omCHJ&f7Oq-sVTh$YP%NeBK_2qlXSl*wl^_S9e3vkD?%hW1h z&myzzNk(%?VLUYe>9(Y{32*rH=p;akA6Z$E$tA%tx$U)hV$@nPlkUmP%%xztn_7D1 z8D;+r_%}@h)iqh(J@MvLld~W^Nz5S}yR?}mY@LnLvaBg>8;NPx*dr|@T;0BpsOR9dtDP60 z&Pvb3{OE10Ez9ww_|?YaW%(6xunTQsFSSzP0@l9$M2=aIB2;dzq(5eGv`+dQvvi z<8ka(7TqM?Mq*Hl8I;PW;jKBNGsz!M#>j+rlISd2`msAXiq>uHZWaS1{)PiD>Yoby zEeB$HBaq_ou#JLgTZnCCF+}2hB;w1Y$2qmfou0C-WOIlh89k`7o+s&Lom}R@7OKC2u87B&8;dM`{BT zLE1p$OtdyW3T=vB3~0_mm-)gWd!KHY5$>RUQ^>(Pob~WXUzSA|!4Vy=@kZI#21m_$ z`AJuBeQ6mgNqy{eHC+xKy8;k&$zCWm7GpU(wuIA2tdY{uu1HK;iYBD89LmhGEOxc=b;q)v%V1iHySYMNj>WD4EBPPvVW%z$_CB#P zIfu&e#IA({wzARHoq`8`I(xRYIOLP-$mGK@zoxoCdDnQLx_c#U?X?BLU~~lyRaAxt zVK+*Aff){YTZhVtgN(D)m9Cp$31%X=wk9Vo8ZfjNFHwu0LLJ2bq}Hgi9$)J6`<_wl z^z*>$;lDji4=T`bF$TJQ_$!7?lY;bTfEXJw4~1d=uzpmtv9G3koQ_Gned8MgZO(M6 z;hnamdlBtnbQ#`OnJ?+yvaN+CLE`;9Uq^lx+L8^IqQr}Bx>S?PD`+<5{ywL<@+VI7 zWKMjrnSBpV3*=Z%3uOzXEn(zUoXqUcY>UWNPIKg!oaRckp7O|(VNUa9HKzr#AE$+K zJf}r+4yVO#d6g;X@}~MYg%*3{CR62=Pnd#F9xw&JeA^T<@@7*gmG_uJnS8<& z%H=*&sE|j8nf+fWKQL8Q@;ee*a?r`uMQU_8)^#=3O9)5wG+s$qudG#NV7OSa0*lP9 z${r+QUD?%0Vqj)NwQWTq=~5F|k`kkJJ*PQx!*DJi!_SI5xrftyd6?4z`97zG@@r0u zq-zBCiCY$!f-XCmf=3Q91+ScF3O>2e6#TN;6f)!;rVx-1nnF-M8#kp)dDIj_@&i-I zlHZv^w)BqVQp2*$6e6;RDdfm=Od(g!FoirRO#xHR6bj@fQz(>=k+1?!is-TfkXMvI zg#4AUq)To`Y=yesgbh^p*ka8{yfwj0HA-i;Pt}}mI?FUDT8yW<^zF71>RP4R?ucCv zsmifDA9-<@jxfPt9@S=dnqdNAgAf13*cw1ppDoBT z5j86rRT58ykv1*t77DAmTwP8R$65K4b1f82xM%56%)XkCW?F)dpR_-rhG`ZYx#dNTb^rzS7amgZ*|84eg*b?5zm|9mbSy0cE{0zuSy4cTme zsO>*#&r|jrV6AK+OBCO7)U3b>Y}b|(#x}x4S2=Xt5wtSX7QM>|bT3x!HoA20kh6&c zaiZI!4yrf$G3W@#HXE_-Im&O1o4Xg~ZH7xT&iM2~_fetu8ZUG&QMMW5RsW>K+C07UWg;cB?<(pS4bvZ3bi7#K4sLN@g^21Qm zHaL4->hcn3==zB7C26*W+oM5ddkPDppfwnOWZO*C%zvv>`}puRkpvYHMJUm#)Y z)7Fmz;g?4R{Eo8rU`l$T50L0}1-+ad6b~9d_Q+9MjBw8qCso81d&n5rbFFVB75Oj} zwWV^U@kY-|&0vk8^vVxEo-_`RMD6I1I;C1ZXLRe;CH#AYL|sr-<7GBle#DGg)~jOH zJISc3a59R%wk*y!-?u5%#U8q6YgOqve3lHGmkOg-IpIiDgL5=U5pt99eXla*j8W9P zI$Am^QTZ9E`gMjf(k^64ZwfJbm&N-hLi&D+5wN1PNc0i3M~?e>Xj-)`FVr2^C#^0; zsVNC6&!8EJhFUJ+s3+kOr*6ZoCFvgxr4t;uDGTmDDT3Qcir~md5loR3!CFocOi8U@ z9Tv0MJQ}GQ4Arbe7t~Hm_1cv`Z@SUiCx<&aZ20<~Jn#IO5ed`uHivDSO44`LuRBzZ<}YSyH5-4oZp&#p09UUo5@~u70zEI)EJufIO8X5~-8@#L{S5B{R;2v~ zYX~dSeu>wW6=}c4D`CZg02bww{^sMPL^rb8xi&Fa@Y;(-EZj zlI$oFuPZP1I#O3*>=-3lIP8r56_PXd1~B#}iT3DQB>&C0cJK`I3qPe=mBW$0`3uh4 z88-73q+7K`qHn{uT8+MgM7MF`(PHm{HN6M$I#aUG<&L&OR~J&Fe@AL#j2?$rTalJk zx@`&>T}flN?4}dYv|th1t7#by!7{`t6FeNjvW&hDThmE^-t-TkM{}xc$q@S|So8yc zGxi}c_L1>Oeb)+7sIgPPrjG%7yG-!=l-R!vrJ-l{an!e;z@;S60j~vdKInS%-$1w& zm&87U6#EkF6=;Yy2dXI znodLZG<^&7x}34^kmBXt86-Gv?;kRx<9{I5`sD89@Yi_cpfPE4f$Y6B`HT@5nw@pY zd9V~g#Uohjb;?W5Gx`qA@6yf?a?yKsK8mXg%Xi==KLx1#-h^KO;%7p-q%6(fQ4|gp zqM}0NV$Aq0(*K@M<=CI+a~^b7KDd!oR2Z9vUxzA2Mx>aS9xin8OekvAy)RA_Z|aXH$C&*6p(ZBbHr zlBzBVl{cxny`H>`#pm{%v4Cp4*o;}b9u4GPs2L%fU~s2tddN65t~5=VyagI(nkFFc zghoqfj33X<&%O_u!#G@3UIsC|_R^c|M%}0?&!@07FGPD{4rAu1+&JAJZRWL6qef}j z-Emr}{0yP-Po{ZWX}%mGX_s*vP+F4{0hKLeiTZFEuI|)?!%J(S>w5KMThtA6oyS&O z(n+%wcm7GKj#L-f_^w)AZHwu!X8knI23^bpnNrf>mq9i`gI$M7qb`@oEOl$P@r4DZAN!D*yxb!`B)S8 z7S%&OiZDgo=ON7l`GmVst*|&&GRdvss9out+%nWR(>=MRuAHzBDC>5NZq*^Oj!%Y(pP;uLCHDt_hY=PniBFy8MV%^{8OxRdZttm)$-`7G;C zG8V8k%+|LYy-?9J&?sUOJQdLmdPOW?T+jNxgmJMP!HNhnKE#HJj2l?fk#Rq3BAihp z%a5~uDC2m}bT;G(EyebM?g=fGjJb?8K^MO|}-pUw%ijxD3_cH!kC8uV_ zsjMkve2ejO#{aOj8_V+`CkhzqTa4I$WD~w_Cv0W(m63ehzZmmlcVr3B?!OX4{8YSb zzUULt{-fI=zQ!^o_V@Cc z4oxh>Dkb)9xvFboJPs3L{qmP7ZgI24t}L7BaEm}^)An3(mD4SjS*)qpt-Hl|+&w97 z0GKWgV6GF}URve!h^5^@;-H)JiGD;B>}F;Yaa|GKt;X$7ET|X7n{#HuCg}uPs)}?5+M}i*FQervDgVy8f6)uGbAT*$p0I0|uMy zadewkbgnnqz|b0;U>GGjM%g1n9QMvb-(zF$u7dk zR5>%myG+;TTwOTRks%z|!GyRer?F5G86wbzEjy2FE5)6~1$u^fE6M8gfH-HYX;VuY z^pLn~oH2Gvg)-h~n$j^oUC$vKJ})_X6s5BfWwX+3Z)D9&W99J7HNy~hf6>A;wyS7K z8oS?qh=0*+Zil-Ux(9?~Nh0@v8zI1kXn@rC}IxDHlEYGMbq2jyKJTFDHQ=T;1DMq86Vi@f-MuQETS^i57 z8ts%TjdqIBXr~yBc8a}Kd{0_so(SRZE_#i8{v3pS9bTKL6i2^Sa7g=l-3cOHUYOzx&Z-%(SV&BG5 z;0$rKMc1Ifi$vUFccQ?H#LX7_JqnyDZnxNk2XNj#A`wO~zmU!4=1}ZaK zJY})pp)#|@pDgCciXRdei~SZ2X9d7sv)Fc2W{x;!v7M;Q9PysTx?w2hiho*c5Qbu| z__xKDqlNRtX^X8!1Lw6lxGxcB*@k7G8Hsx?5#CE_42c$cF0))$@fp8Be8)D!HKL&0 zvp{scj64n3C%%qgeJu8!uQOP^#eP+>Oj+2bz=dKe+g6En;tR1*>|$o_5b;HATo;M` zmg}q7lopAat}i}WUbN^W4OCUMI0ED_5*P2&4B&!ufVmnJ<&iDf$$ z&0cPc&lg+Oon?!}L*iGJjlk)(hY zDKDjf>e4U7USz5&d&P$lFR-yBq$swzg}KT>5veFr+_u)TL-^rdrLP>;AA%jB|4#+} z4WsB;IZ&Z|hA5|yLqMDo-ipymuI(!9Zb#Ibsv|%u_=uWcHC{P_;%CGE*O5aaPOV=E zGAAUJy=rIQGGupc?n>ng)OQW=`jS1O)JApxLcCJAN1Re-XZ}VxsAg1Bf4t(N)_fbh zTXeKh!5wWC*>AvloBwU4tBv~a2wSPQ6w%k_&sm2)d)P&N_Cnbi<-|fRhDbzh;9|Ud zA_Z-y&_!oB?2LG;v__p^+iCA9rrCO`UDb))o9D&yP_ z0zbtWu$9X#V63p@xrJ}3wHSw~KAsZDl!?J!{w$C=t zl10@gw#DM%k{tU|6jNuv4#f{h_a2IAM7tHW3G+rlc6(s{dj*+atN0k-I&X0u z5^nVpkD>+D#zL2ts}|{g;LGj^@MCw8=2r8tyxnSH`5uw0M)gXqqy6K|F3`Uk?4=!4 zKdn4ZD^(xOn+RNl6R0Ed!QxO~j7Khn+3mYTJ0V_-EYiB#X&2e55}CtO$fi8cW~@h>%+^S7$g@O9fK8m)y*>NGC0(f&-x@4Uu7E);g| zRi{O&oCmDA68D|w+-jRrvDmp+`NX>t_&xB1SZu!mI1qc!O8b+pJDgjUzf|7iT#4Ma z1E+=_ac)&7W@NUmnbd3r4$tx%Q);h4r}4C8#rt& zXMH8^fNelum7o)v%g@LU1i~Gdg-u?I);5P3`@q6(a zaFICUwJD24xzDETfVCX*86e3+A)n_P%JN*uSNrC&ybAJG-zsHC98ULvyz0A;4G$@= ziog5!L-UPqKWh#`bH;xXnqnYjdJ3A%44b-0oa?u#q`@*1wHf8mH2KR}(-E2x8Rr70 zXUtXqgsLxq+?cT%cvHrGDmCUI$ni}X2a!CHaSC`a!)<$29M9+oJe_eaFe5P6wx5C_ z*9KPEsC!pKJ|}RWjWT@*@|?hamJdQ+9yn=xUHsO6()JFlCvCq0o`U|ifXz;_+kO(m zQOS4AT%Wo%%)m~kcJR>r-ICm0nc`!hB$Ud*_XaVz6q#uJQ+ zi~QrIoHQ_A%(#+qE8||q6O4+R3t((uyqIw%<5tGw8RR1Zge8pijI$YA7`HIKz<4~) zi3oB4V?ARF;}*sj7>_fGO!j1~XTUtn^a zQDkudV?E<+#ummcj4v=AXB64&&sfhmo3Vv)3*!rn#~DSK{TXM6J#nggn5I=nQR}V| zo!oUuJL9hbe?##%Ty%Ah6y4qDB6Z=#{#w@%@vb;6x+{~FOO@-C+mv4`+mxNkv&w$u zka9x#Ncmhjt6Zc$rhcrdwuQDrM`yr}Itcht52_NzWHP{P4E~SMR-gvqy+lKjDYo>w$r6!Y^_NpJI)cNAl_{ z!Uc?O_E~2qO_Lx0=N0(6gXGJ~3GEKTSvujG`C&>HaKMQW$*VF6_p$y_*4J{T2U-6- z>tE;W9%gGETc2U;8qV}q&SzA?Ey%~~Uk|*c;?5n<$3`mMi_~%I|EP!6_thd>rLERB z&^FAr+ji2HVXv_FwU4yVv2U{f!T!EI>?m`r(1tmmbN<=r+c-4a@9Ju&M-c`R@bMe# z8$$ylu50;v}41uK1zA%B(VgCbqo*7^TYyig}4m!%FL>hp#O;)<6nQR zu*&nladANDZ7lhqHd(6@p>!}hznK#(L7fwIFTsxjE;RPM5iyQ^@O7pT>-Jn5Tj_aW z*mDa;hwm73<2vK54~N()oe`txqqW9kA3b2V(Qr*VwW87?RKLF<;`I8hPv(m3%$Ai( zX3LFg=0%#Y!CJ86lT*tbJ1+k$!>xFY72mz5Jh9`#Gt2Bd>_0uH)+YY1*;I^hfr4Mw zL{qwluNwPJh2Zl*@l$NY5boe|@I4Ralt)9#hudl{B~;Pe^8P11itCKAOp zA#=BoqFQW^G#QP**EtZfIhO)$8x2RBIp3oFHjiQ8EALOBjOg2@i)KaPl6=r!gj2UR z7J1Q3*{h>yTARPiHvV+0jZ?niPu8{$8C8$6+ZM?5dUUp}!e4P6zhm1K%8)>+ZfCQG1lHzi@KcnYxWf>yOCZIz&zB!Yq#yL^IRdGq;5?#UX848M@Dyr$9@iAf5LA7PwU{aKaxKj|VnkwQGL|YOG zgK1cYNK@B_nx8t}h}K!rA;?;z;S5)ze;(tGL(HxX>0}4De4`=xJMv8nYvOG-icnhX zu!PlUINn-+MY)eV0P(ia8ApOBLyl8LB~4F=u~zDF*>f>E=Qi#%c-9N1!wF8=KbU?= zaEf)*Au&mOPp{#3E3HbLDk`X1$7uX^={QlWp-(za6^E&#GX}rIolS&;9wm*WYtB&F zJA{68+87Z@A>yu2zc?vW`Zb~LNj9rrliH>^-at_-Xm#$!kxhIZ)IT{?dYVvPvd!vw z%5x^XPV1fx!>BYlU&e)zJ;i2?Lu4Mrz8*re&&9n6;a9^bH^nJ_r&TFaWw@0hTsCXC zwbnNg%`go&=bdk*p{{(P(iK-snEI5{V>qOuzlS1+?bNJOf@~O0{W>A@a5~#*f+?h# z-hV-65ln+qyENR2xlnU8RTN`PGuoaS6~XEl-I+^zypf_LH&&EvB%Iicen=f)WN}Ue zWv49&y8l!n;Yj2vJxYu7W9?OMYj>P5M@DJ+T4{cIFpWzOtskvxB9zD=fBGOjA!xC# z34w-3LPKg1--FJjnW$ZcDYOWQ)m$i-@tE$dmYJ~_jLHZwvd6I~%Fie;c0kd3w4^5) zvBnsPeOrkTLT(QpTzd0vieO(9u%GOsnw%IYpIdMmO%6TIN8?s{IV^-lg< z4`I%$&yj@Ej^+;zrfc0Sn12ttO*CsOgHU=>#pz(0_Ut%b462{Kjw$Xv+dWUnQ5LVe z=N*B`**bfT}&x0MofnW+a4D1BvfT`d_Fb$j!y1^A- zI=C6k1P_6o!8719;1w{-pg26gLg)fT2>Q1x*a7T@0u+ON5ncp72W|rUgQaw42$`=o z*V_I*z4p>qg`u!5fvp9&6l@7D2it=mf?dE>U{7!jI28N{d<$F$dcX}J=eZHw0R9Wy z3~mOufYskW@$A*P4=jbg4BTQ+?4APSUtgtZ};49c#f;T`O-M2t)`LDrDkTdV8vzN}^ItS_Gr}#JUe+~Q=d%sfr#~`P-Lt~+5r>@uso`u7wU~@mka}10GPk>S2b+9FP2eg3?z&0TFU|aAvkQ06a z#v*J&r8(>mayST#2b+Tqunm~#_ng+{PAJl$NCLCKRPaTR6L=Zq1YQNx!PmeHa5UH% zh0k-x)skK#Ug!i2txb3LQ*fes#zL#?@7-ywM<1Cyz ziy0760v5+WL@5f!*|`*~`8PBu35yRQqBJaqkGF7%V#nLLM68(v4NAr0N{A>Ki>D!? zbl2f`Bh~9a!7AmoB(hD4VsxM6l=qWp#-sunkxX*3%^HzhTl7%$z)IXM6dmTylN~ZH znWjw6GuNncm_z7YWnA4Be6$gg2M0{1@by3@XXb zlM^#2aB7~Mo^@g$ZbJii7`>M1jf5PO zOtu0WBfDUoT$oHh7DO?ug)X@)nFbU(gdpC;F{oPWT6HC9m8)40ft!;XK z*!IVrg{J>JmK^UD$afsH{k&=-vqAp^1Pm&budv;*~oV?i|T#|Bp3fUIh>yO8aDl$^6cyCZ>{^AgtxHw3bq|mIz zZuxl%9bN2_{w|VB@@2G(3YIuTG<{sUraljhpRgdzL)_=-#VsxC_d)0}?tExoqW89} zH%7u|e2Uk-%q9@)#I~kh&+@fG&dDHKiH(t6QX)^I?-2q*RygG24C=ljU#4Wz(G~sJ z#k#UH+lH>pF{fm5QH9ckXSMgn$}AygB#>>jjgh^2mb{rjmsS^u->713D2-jyME;gQ z#p}A$xitZ@MIv2a zuHH|Wy3e9Q|K;ehH1DGTykjDXz_~Cy#2p2rsUu~t&85_Jp)#{04Or)76t5c~U+KuP z0xue{Yr^j2P56%ONF^WHsN4DgIfbK*@c#kYgSb(N!|RWt%-*66=&lQiRQz!jQu5|+ z+$iL4F0ySJA;UXS(WVg%yTZTbnuhl|dnbCb$rizCd#BoA#4~spZhq^1t`pw4`_ZsX zCR)DP@~0H0BZYCDsC;vTFNJYWrEm_h`SH&wEU8Ul$PyC`DGimoI$=oIXnAP>iyKQz z8a^eM`fTmV6)4$iH*2L7N>{4b+PrNvQb##GZNcFn zFP0-gH~4q3Gx#c)MPb|G%v$+4Zr^QM+zGI8T)ZXu;!XxR?i7&Yz6EB{l5KG)rT65v zK~io=BijzQ+>%B)!0t3!2b8DL9pETzJKgdOY{2KR0oPyyZo{_ADZfjjp}>FAXwfd0 z|1W7;lPeRcWS5m5?+TUDO@X^z((I=0K#-ee?RLsgH`5dSroUNyUb3DkA&0AG7C2yFVtJhETWt$4m5>ipc`cY+=|s@ zcI=Z`nOJV&hGfrSYvcJZB0c^jT+R`#?Uu!vuLO3MKQWgH0L zR?R+O=T^-J(5mcq@PNe}>MONSOuh&HLAXDJI~w{4{Ls+$gLZCcb{}`pVs`$?ecV9< ztvndOZC?sMw0$LjwrBUqLl$%YKedSiJ-Xl)iG9Df4pku*Y!X6NDwu@;f`n z;Zg>`ibeEFXyZ5W;NcV(f;B1D=M>3s#X=7+H^TWBr?dw?liker6 zdLG%=To8@ujhxDez+s5!feV|VT2NUYh~1=e8AaeG?p2qDUbO{|LhvGPZr7pky6ULU zUfmFJ07`nBDy~M?zXpdaXt<#F$?sa6FQsYF;2=dwHB;wnBdoV^ipSR*8hpQ~obe?y zm0ydp?Sc1JxUl&poWF51@FwIZ=--5XfKN}xFKvMq1SjF{09C%3TwmJjv)3l5tWfQw z@n61NSThXyxo3ifufe$cp!9sAb1)mZB6Yt>IV&MKt&m*arL=i~;>oyLMnW7!M|ZsEwyPh+*i# z)0SJ@!(%lGoCIP^;F%4kfQvvp(>)tNJoS9LTueyc`2#jxICm(-<`KdpIAnrmiA^NP zX9rne0@wv~fm{c2ks@3&Fk!U)Jr{b^AT=Ip`Ji9C~D?14OHOx`0Cw<|#1} z;W>p6av<>Bcnw?z=7Oc*Xs`?%1AYePfmgxT!Mor%P(e412SY)u51x2%B8Wp1WimJj zoB|F9xdJ?|I6M}73k50M2Vn*jzv~Wu7^Cc90cV2I;B1I5f^!ib1HO;&3UDF9JQbIK z<=|5A6u1oh8e9(k3VsMS#2{J$wgOjziQpRa|I8c+8=!a#{1+151a3w60O$oj1-axr zvpIYg+zEaG?gFpt_S?GsKDY;Zp6H)|55aw)9|re+ur62z)>qnMa0kWVrvdJ9N+UFM zs4|&W+-NEiXy1*A<}pfRjPu6I7>c_&@Tt)3n=PLTz5jJHI({>>Z#ep#XAsY%nzaOj zSg}CQ*CAwzvM7fY8EASS`O?F!ke+S-#{xJxf=U3e>FzVUg41S|1@1}y^Bg}ibM<5Q5 z3Y8xqjECa?&^KE_MD~0F{sx`}pMV!YBsPPeEPi-p1qXSWv(opatYjSuofSYy>{lKQH{Hf2MvtTm(^C@8;B}zd>SgeDbxm(26)FR1WKf zrvVrNHq|TJOb@pLBcbOmhywox;;LSx$1^Es#5$wCipZ zqY}zvP71s?Ltb^#f_rvG`MnUvrF*gRmXnNCv9b#Bs%FT{B-&eLvu2_eXmj5a;2dV~ zyMBt&9pTrK=$EQ0c@8HZ-*q=X?5K^(Y;0eGsptK_b0N0hcbj{{74`Rwpr7xjnA1>? z4BXMw=|Pxzhf|9b?b{5Ed(hKYo(JbS>jl-<&F6es3njp}zn%O2#W*oc9o}5D3>$`m z2qoSb&li^ID5Z4}GE(-aAHpp5>^{_7^peH~#jTWnqtr%GqL2A5<_%wCc8`q`%j!C7 zo2F1aVM`E-l zUWJ&Wi9Gb**F+wQ0Y1@n4Ps|~Wbk5JbMfHe)526;@mJfRWVM>JT?n5Z>Lbqft6I^X zf_dW8;vh;L8V|>47guC>JRJGhpt)MXVt6OKDQO~~8FbY|J_69hMGj#QmwZ|rtg7w~ zXgJcS&UJ_YwOa?lC#q^`2hmjM4qJ5Y(pi?OMmTECr*!psomVva@wx7Cbz27!s!n%` zPU<{|2o>dOheS++qiJffLs-QbE%><}yru%s4|;D7YsFIrH#eR2KFc#|@z^Boui zLAr`Jwz?`(S4G#V;&c`7XLT>PuIf^&>ZPlA8>@Q_(N!aBRikwk?_PDUd|kx{3A*Y% zUB$arUA0(Ot*BM4*Hye()xCDQ06uA4fLvsUrBJhi^evY6;O-li``_f@EQr_@hR7 bvglgp|NTeE?(kGG#vsQv*jzoO(>K$EiEmWLi$c2Eoqac1raJ%-ZCf%hzJF0<#oLU+t3lz z@)%&Lr$wxQfQV2YQNRwAmjj3hl;QFc5Ew;Z0Ck381Rrz%>zq`a`M!G(ocz{ad#(N6 z`<%T`{qsZo^FuZnLZe^$*E3HFMNt}7RqUv|H@T#ysd`arX2;qT z^{-y-&wP0#`knqA-kh4Vxp0-((x#88ZS&Zkcm6cvK=`t;AMD%p>dG0ehd+8ti;OeL z(6K%wifgQIn~>s`*wWEtG@f1hV)G9Uim88*;*rkwP_j9katDkZUU@f^7CI_Skq-nj*(};qa*8#kMZw-(S}Dpb+#BGXN&`|} zk>|tcY)Yvx)5EFB_??_uCFg|GtyH^hPWb&?4Izrs4|fdwJ`AVyvQeQBlW!}lM+FCT6+j8{HZQL1f`^ZX%vb^$&l|r2rrdDnA#MKQ( z5lyR{mY5a|`>jIX+`t_Mzj*rGnJrRDWX}|R>80!xTi>8BTh^juzQXN+Wknm>o9&YO z+R(jhmuN>>-Ezc8ntz0Faqvf|zRF-SE zeft~Bmtl1{XgNEY8geUSeKa|G*lqRE_tW#CLFeOs6BRlcO{G0tqKsDbm?`JQP`ul2 zn}^ZD!<{SN4Gl31HxHm|F*MR$A&hj!of2cT-8Z@ogM4)NNO&buhrDb#JC+9KA@f)| zk~hUPCr-Cjt!5EPPv$?|W(j6O%N46A#-(wzB|j;i)k}lMocqDHijvz-Q3{aoyK(fl z{Gmn`|Js2{JWH(0ev=5CjH&d!CnJQlsey;Q86rF}QP0<=bhMgibU|`>m!Kvd8Z*67 zkZr9CYNDV)Co63zG4oM6<}p#K&lEl9H(7K*76*gY>P|D3g7LmEBU>CyqzYf9F;!r) zCDAXwbfX>Oz$9`O4m7rcI6aAK3Z3$F5;YZKtw^Ffg+(&H6S<3e%bHG9UF4LXccQJp ziB5FA$SYGjlcQ&a>9Nkih7+M^xLrMm$fr9~RIf5w+L`9|Di%Eh&ApBav%by<$I#Z(@uF_73?)nDyZ&l$+E{D9966&H5k{%1ml5iKL6eW(i|p#P13O zkD2=6*X5izs(I33)<=U-me9^8pRRfb9b`8s{*S<9@H4QhL3yPM+SrM3CfE(^4R#0n zfIYwgU>^7cm=BHxJzzEH1s8z@U_Dp}ZUKwHCa@=X2<&B0oc?bhJPgIpU~e!Iz264~ zC9fWTk;+nyw;Ge-|;Cb+E@E_m`@F(zH zFal|<2D^f5z)Wy0=mpn-!@v)~5#R>!Y4Fy!zxYdooCr2RKN;L;P#pf}A#8@?WpE4l z8u$_T2DlAW!A7u-z8`titPgpi%%M-8K3Zi#p}s_1Ja`f0F@G6!gMR_@LC*YFBP-zZ_fE*43GeH~Z1UrGT)9KTp6kV8{d05WaxdA($1{45FO%6h`9@`RTvCzQ&wUb+rk^3u@Kp`1cPsmrXp3MGvaUx{2Yv77mXmX=VA z+A7k2qJ{k$N^LZ2VjTM}ome9)^TaNsJ22h|4*&)$fwma_AQD9TJ+B@P+1YNHmP=99ZrLN323F7IjLudM z=Nw$WZ{$?|2H0~04KL3SraQqgtfIQH^vGPRyyMm1yXP*07_hw(Dx@=w?5`#v+P%Ga~VQBxuBWzm|NG8ylr zsCh{Y_q@5B?B01Rk!)bx{4uTJ5jaFruj7c@dK8FMJVEc9yEMoQbd0Q zZ{x0j>UTY;X5$(oPvObA0q1fb8{lMoE3WY(nQF1Vp{#lvfI< z_?-%w;-mfV3}h4A@*<8KxqO^CMH^>AY0uL-aB+DrAuF9^UukEQteh*)JL%-gO4D6u zaMbOI#HgG0u0`H;(!w>xbnM+Q*&&-Qyz7<^WmElXJNZ_H$@FY0SygR1njQ2KZSijW z&sA1=G@HF5xS~H`3in0L{?6X%v}kph{E<^|3Ijd1Y9i&Yi54DeUKLG~*Ca?!H#iOz zqiOW&jPMf%?4z(>c@gdt=-MCTyz3=TuF#|Pg(OaDH``3|7 zpkm!RA@BAe`}#35+D$d<$I#XNVa8c_v$MPDm-Y7eLb%&8MbXyU`!CPhQMmd2x7dxh z^no;Ly@{4>u(V;*mg^;?@SK~PHpFWwJolRvj=?(`b>M6)1Wpv6nyqs&bP^W7d?D4`_K=oyjJe^WoMK>a3%Sud?n z3aNQhLf0hZg7W(D;;4)U9|E5N;jQ3V>*r0(b6^3*Y|b$2?uWzW)stP~GMXxz-&xw0XFcOY_P8p;xZRr*Xjh`LqVuluuWH?TGuxD|aCdIDk0d z2;zW~h}-It=ksYK@O3`Dxz!zdBVTWNWh&KgwbAXZ(eidaMQn4+AM>dgXyu`~+gvi# zLrp*%58Z(>#zW5SZkgzzvh7~k#X}81riX4pnd2eH$8K5Rp>aTO53K}BJapk>uN>l` z_(rcB;h~X@MWJI+KlByqt|r7{Z?~)QAvwuIR~o&hslh0D%*hv&yHxh7WwXQ%Z(ng?M$Nn<#9A@Cmu)nRJzk4 z-lqZOv9xKY#k@&t1)-R<2kxew2D-R2Ol;TUO-&YVPg|2i9MBY_nk?oc|K>2N$v}&m zco=bl+u?vlJ_LuaHHBrD#jLk;OAeM@2J-C+6SuYa@w+VC+7-JT+}ixy*uBdlLTS&= zSV#u?ZdVvL{4cv4B1Tj8+HK*sXUp>47STmhmhU#u^4($F4Gp^;B1co+h9!D}Ej#Y9 zh~ApA;~oR`-xJ22GIEbY4AGRU_E@-I*zy=G$7;%BdkjnVhH~)B#nr`r33wH(^ z`uAEywWjp%HP9wlqFU{eSbVdJLs9)jh5|y%5<@dK19^ScWPUCDK@LQd^UTMjxH7Y>%m1zoA+Q>T2RD^-8$mXQu>`gEPFb5QA_B*wx+ z74l~Xg?^SUjVa{*%q!ccQpIOZS)ED^P@YMp3!jy85sMF3azPFquHpQKe!dbp1nzx~ zeO#R*P9MJ{Z2AmQ!h@xhcEADK+-nG#1>+30E0r#!1Y zjd~%)v9Mu3bV$S5rU*Y&JMcW@25&Y}#TWJnKJeR)n_KxZtiEuDvsEe_3sKPVbn}bk za6a?v0u9%ooD$DvXeo_?CJvepOf>S`7;%vHoNI47j8i$Tpt>SKv`^6rvJ7^wu+q=!2t}!R352JghZoA~=YfP%RsRQIM{qBg2z~o4f2<%eOiX*@g;Iq(=1IL4t!3m(h3PLG_KY$a# z72srW16T$&g3p7;!E*3A_yQ;m7~P-^oCc=|5kBGbATrM$2=Rz(qSPT6G5R=nC16&F&1m6PJfarh!POu(43cdq=39f{{6@z9S z*c03WeP56Z#&ed#1Hli`|NbW-;8e*!CTK7|XiyGrgP!N`c5oWl2)+jX5u69^0K+jt z!j%Vcmn&_RNlG-@ubnbRu_|pan*RL?$IP^1ideBagroh!6-v4^7F(Q*OHbhU+e@AB z8+*C?01Nt0UlPQxO9k(I4bbzo8yO>iWsjoF!N5}vBK$CT2-IdE_$NrAZE9C^Z9{eA$0Xz-v0?&XvSI&axzzg7IklXF6VEC`#Md)vXm%txEju%3=H-oT! zRXYwsJa53h11AW~weKOk00o?1=Hr}u2!9Oz1Reo@2Ki77YeDr55c5zwo-u;_CfyqB z03s8A0vHM=f?=Qw3F$jl=44dGgWE@WH)G73y6aBK+HR)&W5bZ^z zy4WFN@l8%`U?VdgSF^O35I$+|r;Gf>ZHFe}m|cxefgyi3o2#eBpTdUehWvS}L>Kvs zRc~G7Pg4KXZGCMO<$FylveZi{A~u8%;J4~_{N-q-F7l_Ljk*gTz~9uheDWSN;Ey=9 zK?98DZ*&9xT+@!lXal4r>ZMfFmd~)4=^~#9&(THxK+#6`dK%&bnrJMA*rAm=(jlTk zUP;CQhI&2?N$}fqp}GemUQ^YkG-1Pgs(KbQ)?rzzlj?;ucsSE=@~S?T4zn?7YI-`% zW@o9zV932J%p5H$Bp!V~O1G+Xs`VVp2NfsP6>tpU(}yx$^k95$)I`h`H6jCsZj8Pe zsxkZXh7n5Q;miC?342GySg`B|PC?-a3yJUnXD!Yt8A zt#t}Z$O=^4q%L-%!`{zV7dlY`-oXY{+k>iI_f-diD&DpRtxg72=kKe&4yt&s8nn6{ zRQ>p?O0-fJphzNAy~Jpvhhp?lq8{p^hcfk0jvgw|L%sD-i5?oFheqh3v3h8d9-69$ zX6m78JyfHI7VDupJ+xd4sq>v8--YEuyZAG6%f;hmH(mrU1{MDqx7@4Va-k9VAU;j~ z-i5yBBY2}G;_O|Iy#!S|J(dqj2hj`bBh^JY!Vtp8#O>7P9Qcid*jf{D@T(rlL8{OH zstTFWB1Rh^6{>}~=)$G~)td{u6dyJRnkv2sqPEDQz%7KRJsbx4)FrvXA@SD~O}V0X YtN-)QHnzp(i%AA~J7QanPs|AUU)Iyr2><{9 From a5f61569f2c78b29770c894c44f8f580d91618e8 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 23 Oct 2018 19:49:49 +1100 Subject: [PATCH 1437/2058] Remove unused code --- ProcessHacker/findobj.c | 4 ++-- ProcessHacker/hndlprv.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ProcessHacker/findobj.c b/ProcessHacker/findobj.c index 908e837960c0..53793bb208da 100644 --- a/ProcessHacker/findobj.c +++ b/ProcessHacker/findobj.c @@ -981,10 +981,10 @@ NTSTATUS PhpFindObjectsThreadStart( if (PhBeginInitOnce(&initOnce)) { - UNICODE_STRING fileTypeName; + UNICODE_STRING fileTypeName = RTL_CONSTANT_STRING(L"File"); - RtlInitUnicodeString(&fileTypeName, L"File"); fileObjectTypeIndex = PhGetObjectTypeNumber(&fileTypeName); + PhEndInitOnce(&initOnce); } } diff --git a/ProcessHacker/hndlprv.c b/ProcessHacker/hndlprv.c index a95a4d33b01f..6d9437065568 100644 --- a/ProcessHacker/hndlprv.c +++ b/ProcessHacker/hndlprv.c @@ -467,10 +467,10 @@ VOID PhHandleProviderUpdate( if (PhBeginInitOnce(&initOnce)) { - UNICODE_STRING fileTypeName; + UNICODE_STRING fileTypeName = RTL_CONSTANT_STRING(L"File"); - RtlInitUnicodeString(&fileTypeName, L"File"); fileObjectTypeIndex = PhGetObjectTypeNumber(&fileTypeName); + PhEndInitOnce(&initOnce); } } From 866a8020c4ee5268d887962a2b3e9dfb706ebb4b Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 23 Oct 2018 19:50:29 +1100 Subject: [PATCH 1438/2058] Add column chooser dialog dark theme support --- ProcessHacker/chcol.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ProcessHacker/chcol.c b/ProcessHacker/chcol.c index bbe58a5f8f68..515b8a66f7b0 100644 --- a/ProcessHacker/chcol.c +++ b/ProcessHacker/chcol.c @@ -3,6 +3,7 @@ * column chooser * * Copyright (C) 2010 wj32 + * Copyright (C) 2017-2018 dmex * * This file is part of Process Hacker. * @@ -23,6 +24,8 @@ #include #include +#include + typedef struct _COLUMNS_DIALOG_CONTEXT { HWND ControlHandle; @@ -190,6 +193,8 @@ INT_PTR CALLBACK PhpColumnsDlgProc( SendMessage(hwndDlg, WM_COMMAND, MAKEWPARAM(IDC_INACTIVE, LBN_SELCHANGE), (LPARAM)context->InactiveList); SendMessage(hwndDlg, WM_COMMAND, MAKEWPARAM(IDC_ACTIVE, LBN_SELCHANGE), (LPARAM)context->ActiveList); + + PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport); } break; case WM_DESTROY: From e86b520e1feb60ddc1e0c4368b2ab74d64445623 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 23 Oct 2018 19:57:26 +1100 Subject: [PATCH 1439/2058] DotNetTools: Add native module highlighting --- plugins/DotNetTools/asmpage.c | 38 ++++++++++++++++++++++++++++------- plugins/DotNetTools/dn.h | 2 ++ 2 files changed, 33 insertions(+), 7 deletions(-) diff --git a/plugins/DotNetTools/asmpage.c b/plugins/DotNetTools/asmpage.c index 0231632ac112..22876ba89eec 100644 --- a/plugins/DotNetTools/asmpage.c +++ b/plugins/DotNetTools/asmpage.c @@ -99,7 +99,9 @@ typedef struct _ASMPAGE_CONTEXT ULONG EnableStateHighlighting : 1; ULONG HideDynamicModules : 1; ULONG HighlightDynamicModules : 1; - ULONG Spare : 29; + ULONG HideNativeModules : 1; + ULONG HighlightNativeModules : 1; + ULONG Spare : 27; }; }; @@ -626,12 +628,18 @@ BOOLEAN NTAPI DotNetAsmTreeNewCallback( break; case DNA_TYPE_ASSEMBLY: { - //getNodeColor->BackColor = PhGetIntegerSetting(L"ColorDotNet"); - - if (context->HighlightDynamicModules && node->u.Assembly.AssemblyFlags == 2) + if (context->HighlightDynamicModules && (node->u.Assembly.AssemblyFlags & 0x2) == 0x2) { getNodeColor->BackColor = PhGetIntegerSetting(L"ColorPacked"); - } + } + else if (context->HighlightNativeModules && (node->u.Assembly.AssemblyFlags & 0x4) == 0x4) + { + getNodeColor->BackColor = PhGetIntegerSetting(L"ColorSystemProcesses"); + } + else + { + //getNodeColor->BackColor = PhGetIntegerSetting(L"ColorDotNet"); + } } break; } @@ -752,6 +760,12 @@ VOID DotNetAsmSetOptionsTreeList( case DN_ASM_MENU_HIGHLIGHT_DYNAMIC_OPTION: Context->HighlightDynamicModules = !Context->HighlightDynamicModules; break; + case DN_ASM_MENU_HIDE_NATIVE_OPTION: + Context->HideNativeModules = !Context->HideNativeModules; + break; + case DN_ASM_MENU_HIGHLIGHT_NATIVE_OPTION: + Context->HighlightNativeModules = !Context->HighlightNativeModules; + break; } } @@ -1386,7 +1400,9 @@ BOOLEAN DotNetAsmTreeFilterCallback( PASMPAGE_CONTEXT context = Context; PDNA_NODE node = (PDNA_NODE)Node; - if (context->HideDynamicModules && node->Type == DNA_TYPE_ASSEMBLY && node->u.Assembly.AssemblyFlags == 2) + if (context->HideDynamicModules && node->Type == DNA_TYPE_ASSEMBLY && (node->u.Assembly.AssemblyFlags & 0x2) == 0x2) + return FALSE; + if (context->HideNativeModules && node->Type == DNA_TYPE_ASSEMBLY && (node->u.Assembly.AssemblyFlags & 0x4) == 0x4) return FALSE; if (PhIsNullOrEmptyString(context->SearchBoxText)) @@ -1567,21 +1583,29 @@ INT_PTR CALLBACK DotNetAsmPageDlgProc( RECT rect; PPH_EMENU menu; PPH_EMENU_ITEM dynamicItem; + PPH_EMENU_ITEM nativeItem; PPH_EMENU_ITEM highlightDynamicItem; + PPH_EMENU_ITEM highlightNativeItem; PPH_EMENU_ITEM selectedItem; GetWindowRect(GetDlgItem(hwndDlg, IDC_OPTIONS), &rect); menu = PhCreateEMenu(); PhInsertEMenuItem(menu, dynamicItem = PhCreateEMenuItem(0, DN_ASM_MENU_HIDE_DYNAMIC_OPTION, L"Hide dynamic", NULL, NULL), ULONG_MAX); + PhInsertEMenuItem(menu, nativeItem = PhCreateEMenuItem(0, DN_ASM_MENU_HIDE_NATIVE_OPTION, L"Hide native", NULL, NULL), ULONG_MAX); PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX); PhInsertEMenuItem(menu, highlightDynamicItem = PhCreateEMenuItem(0, DN_ASM_MENU_HIGHLIGHT_DYNAMIC_OPTION, L"Highlight dynamic", NULL, NULL), ULONG_MAX); + PhInsertEMenuItem(menu, highlightNativeItem = PhCreateEMenuItem(0, DN_ASM_MENU_HIGHLIGHT_NATIVE_OPTION, L"Highlight native", NULL, NULL), ULONG_MAX); if (context->HideDynamicModules) dynamicItem->Flags |= PH_EMENU_CHECKED; if (context->HighlightDynamicModules) highlightDynamicItem->Flags |= PH_EMENU_CHECKED; - + if (context->HideNativeModules) + nativeItem->Flags |= PH_EMENU_CHECKED; + if (context->HighlightNativeModules) + highlightNativeItem->Flags |= PH_EMENU_CHECKED; + selectedItem = PhShowEMenu( menu, hwndDlg, diff --git a/plugins/DotNetTools/dn.h b/plugins/DotNetTools/dn.h index 553432ca41fb..c334dd6be301 100644 --- a/plugins/DotNetTools/dn.h +++ b/plugins/DotNetTools/dn.h @@ -43,6 +43,8 @@ extern PPH_PLUGIN PluginInstance; #define DN_ASM_MENU_HIDE_DYNAMIC_OPTION 1 #define DN_ASM_MENU_HIGHLIGHT_DYNAMIC_OPTION 2 +#define DN_ASM_MENU_HIDE_NATIVE_OPTION 3 +#define DN_ASM_MENU_HIGHLIGHT_NATIVE_OPTION 4 typedef struct _DN_THREAD_ITEM { From 1f5d7827a5d9e846b9fc619cf278511d63711336 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 24 Oct 2018 23:51:03 +1100 Subject: [PATCH 1440/2058] peview: Add file property store and extended attribute information --- tools/peview/eaprp.c | 145 ++++++++++++++++++++++++++ tools/peview/exlfprp.c | 16 +++ tools/peview/include/peview.h | 14 +++ tools/peview/peprp.c | 20 ++++ tools/peview/peview.rc | 46 +++++++-- tools/peview/peview.vcxproj | 10 +- tools/peview/peview.vcxproj.filters | 6 ++ tools/peview/propstore.c | 152 ++++++++++++++++++++++++++++ tools/peview/resource.h | 4 +- tools/peview/settings.c | 2 + 10 files changed, 403 insertions(+), 12 deletions(-) create mode 100644 tools/peview/eaprp.c create mode 100644 tools/peview/propstore.c diff --git a/tools/peview/eaprp.c b/tools/peview/eaprp.c new file mode 100644 index 000000000000..837f138ad0d9 --- /dev/null +++ b/tools/peview/eaprp.c @@ -0,0 +1,145 @@ +/* + * Process Hacker - + * PE viewer + * + * Copyright (C) 2018 dmex + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include + +typedef struct _PV_EA_CALLBACK +{ + HWND ListViewHandle; + ULONG Count; +} PV_EA_CALLBACK, *PPV_EA_CALLBACK; + +BOOLEAN NTAPI PvpEnumFileAttributesCallback( + _In_ PFILE_FULL_EA_INFORMATION Information, + _In_opt_ PVOID Context + ) +{ + PPV_EA_CALLBACK context = Context; + PPH_STRING attributeName; + INT lvItemIndex; + WCHAR number[PH_INT32_STR_LEN_1]; + + PhPrintUInt32(number, context->Count); + lvItemIndex = PhAddListViewItem(context->ListViewHandle, MAXINT, number, NULL); + + attributeName = PhZeroExtendToUtf16(Information->EaName); + PhSetListViewSubItem( + context->ListViewHandle, + lvItemIndex, + 1, + attributeName->Buffer + ); + PhDereferenceObject(attributeName); + + PhSetListViewSubItem( + context->ListViewHandle, + lvItemIndex, + 2, + PhaFormatSize(Information->EaValueLength, ULONG_MAX)->Buffer + ); + + context->Count++; + + return TRUE; +} + +INT_PTR CALLBACK PvpPeExtendedAttributesDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + LPPROPSHEETPAGE propSheetPage; + PPV_PROPPAGECONTEXT propPageContext; + + if (!PvPropPageDlgProcHeader(hwndDlg, uMsg, lParam, &propSheetPage, &propPageContext)) + return FALSE; + + switch (uMsg) + { + case WM_INITDIALOG: + { + HANDLE fileHandle; + HWND lvHandle; + + lvHandle = GetDlgItem(hwndDlg, IDC_LIST); + PhSetListViewStyle(lvHandle, TRUE, TRUE); + PhSetControlTheme(lvHandle, L"explorer"); + PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 40, L"#"); + PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 150, L"Name"); + PhAddListViewColumn(lvHandle, 2, 2, 2, LVCFMT_LEFT, 200, L"Value"); + PhSetExtendedListView(lvHandle); + PhLoadListViewColumnsFromSetting(L"ImageAttributesListViewColumns", lvHandle); + + if (NT_SUCCESS(PhCreateFileWin32( + &fileHandle, + PhGetString(PvFileName), + FILE_READ_ATTRIBUTES | FILE_READ_DATA | FILE_READ_EA | SYNCHRONIZE, + FILE_ATTRIBUTE_NORMAL, + FILE_SHARE_READ, + FILE_OPEN, + FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT + ))) + { + PV_EA_CALLBACK context; + + context.ListViewHandle = lvHandle; + context.Count = 0; + + PhEnumFileExtendedAttributes(fileHandle, PvpEnumFileAttributesCallback, &context); + + NtClose(lvHandle); + } + + EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); + } + break; + case WM_DESTROY: + { + PhSaveListViewColumnsToSetting(L"ImageAttributesListViewColumns", GetDlgItem(hwndDlg, IDC_LIST)); + } + break; + case WM_SHOWWINDOW: + { + if (!propPageContext->LayoutInitialized) + { + PPH_LAYOUT_ITEM dialogItem; + + dialogItem = PvAddPropPageLayoutItem(hwndDlg, hwndDlg, PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL); + PvAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_LIST), dialogItem, PH_ANCHOR_ALL); + + PvDoPropPageLayout(hwndDlg); + + propPageContext->LayoutInitialized = TRUE; + } + } + break; + case WM_NOTIFY: + { + PvHandleListViewNotifyForCopy(lParam, GetDlgItem(hwndDlg, IDC_LIST)); + } + break; + } + + return FALSE; +} diff --git a/tools/peview/exlfprp.c b/tools/peview/exlfprp.c index 96deadeae353..14d62b6af5a8 100644 --- a/tools/peview/exlfprp.c +++ b/tools/peview/exlfprp.c @@ -104,6 +104,22 @@ VOID PvExlfProperties( ); PvAddPropPage(propContext, newPage); + // Properties page + newPage = PvCreatePropPageContext( + MAKEINTRESOURCE(IDD_PEPROPSTORAGE), + PvpPePropStoreDlgProc, + NULL + ); + PvAddPropPage(propContext, newPage); + + // Extended attributes page + newPage = PvCreatePropPageContext( + MAKEINTRESOURCE(IDD_PEATTR), + PvpPeExtendedAttributesDlgProc, + NULL + ); + PvAddPropPage(propContext, newPage); + PhModalPropertySheet(&propContext->PropSheetHeader); PhDereferenceObject(propContext); diff --git a/tools/peview/include/peview.h b/tools/peview/include/peview.h index 9441b1457b09..dd9129373a9b 100644 --- a/tools/peview/include/peview.h +++ b/tools/peview/include/peview.h @@ -329,6 +329,20 @@ INT_PTR CALLBACK PvpPeResourcesDlgProc( _In_ LPARAM lParam ); +INT_PTR CALLBACK PvpPePropStoreDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +INT_PTR CALLBACK PvpPeExtendedAttributesDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + // ELF PWSTR PvpGetSymbolTypeName( diff --git a/tools/peview/peprp.c b/tools/peview/peprp.c index 085d617089d2..a25580571440 100644 --- a/tools/peview/peprp.c +++ b/tools/peview/peprp.c @@ -178,6 +178,26 @@ VOID PvPeProperties( PvAddPropPage(propContext, newPage); } + // Properties page + { + newPage = PvCreatePropPageContext( + MAKEINTRESOURCE(IDD_PEPROPSTORAGE), + PvpPePropStoreDlgProc, + NULL + ); + PvAddPropPage(propContext, newPage); + } + + // Extended attributes page + { + newPage = PvCreatePropPageContext( + MAKEINTRESOURCE(IDD_PEATTR), + PvpPeExtendedAttributesDlgProc, + NULL + ); + PvAddPropPage(propContext, newPage); + } + // Symbols page if (NT_SUCCESS(PhGetMappedImageDataEntry(&PvMappedImage, IMAGE_DIRECTORY_ENTRY_DEBUG, &entry)) && entry->VirtualAddress) { diff --git a/tools/peview/peview.rc b/tools/peview/peview.rc index c762a3799c3a..8efb020f33f0 100644 --- a/tools/peview/peview.rc +++ b/tools/peview/peview.rc @@ -132,6 +132,22 @@ BEGIN TOPMARGIN, 7 BOTTOMMARGIN, 273 END + + IDD_PEPROPSTORAGE, DIALOG + BEGIN + LEFTMARGIN, 3 + RIGHTMARGIN, 298 + TOPMARGIN, 3 + BOTTOMMARGIN, 277 + END + + IDD_PEATTR, DIALOG + BEGIN + LEFTMARGIN, 3 + RIGHTMARGIN, 297 + TOPMARGIN, 3 + BOTTOMMARGIN, 277 + END END #endif // APSTUDIO_INVOKED @@ -142,8 +158,7 @@ END // IDD_PEGENERAL DIALOGEX 0, 0, 300, 280 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "General" +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN LTEXT "Target machine:",IDC_STATIC,7,57,53,8 @@ -164,7 +179,7 @@ BEGIN LTEXT "Static",IDC_ENTRYPOINT,78,90,215,8 LTEXT "Image base:",IDC_STATIC,7,79,41,8 LTEXT "Static",IDC_IMAGEBASE,78,79,215,8 - ICON "",IDC_FILEICON,14,18,20,20 + ICON "",IDC_FILEICON,14,18,21,20 GROUPBOX "File",IDC_FILE,7,7,286,48 EDITTEXT IDC_NAME,44,17,242,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER EDITTEXT IDC_COMPANYNAME,44,29,242,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER @@ -208,13 +223,14 @@ BEGIN EDITTEXT IDC_FLAGS,76,19,217,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER LTEXT "Version String:",IDC_STATIC,7,31,48,8 LTEXT "Static",IDC_VERSIONSTRING,78,31,215,8 - CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,57,286,216 - LTEXT "Sections:",IDC_STATIC,7,47,30,8 + CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,67,286,206 + LTEXT "Sections:",IDC_STATIC,7,57,30,8 + LTEXT "Guid:",IDC_STATIC,7,43,18,8 + EDITTEXT IDC_GUIDSTRING,76,43,217,13,ES_MULTILINE | ES_READONLY | NOT WS_BORDER END IDD_PELOADCONFIG DIALOGEX 0, 0, 300, 280 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Load config" +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,3,3,294,274 @@ -262,6 +278,22 @@ BEGIN LTEXT "Static",IDC_IMAGETYPE,78,20,215,8 END +IDD_PEPROPSTORAGE DIALOGEX 0, 0, 301, 280 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Properties" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,3,3,295,274 +END + +IDD_PEATTR DIALOGEX 0, 0, 300, 280 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Attributes" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,3,3,294,274 +END + ///////////////////////////////////////////////////////////////////////////// // diff --git a/tools/peview/peview.vcxproj b/tools/peview/peview.vcxproj index 32f9c2deeec1..a8c2cd2738e4 100644 --- a/tools/peview/peview.vcxproj +++ b/tools/peview/peview.vcxproj @@ -99,7 +99,7 @@ true - noarg.obj;noenv.obj;phlib.lib;ntdll.lib;uxtheme.lib;userenv.lib;windowscodecs.lib;winsta.lib;%(AdditionalDependencies) + noarg.obj;noenv.obj;propsys.lib;phlib.lib;ntdll.lib;uxtheme.lib;userenv.lib;windowscodecs.lib;winsta.lib;%(AdditionalDependencies) ..\..\phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) @@ -130,7 +130,7 @@ true - noarg.obj;noenv.obj;phlib.lib;ntdll.lib;uxtheme.lib;userenv.lib;windowscodecs.lib;winsta.lib;%(AdditionalDependencies) + noarg.obj;noenv.obj;propsys.lib;phlib.lib;ntdll.lib;uxtheme.lib;userenv.lib;windowscodecs.lib;winsta.lib;%(AdditionalDependencies) ..\..\phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) @@ -164,7 +164,7 @@ Guard - noarg.obj;noenv.obj;phlib.lib;ntdll.lib;uxtheme.lib;userenv.lib;windowscodecs.lib;winsta.lib;%(AdditionalDependencies) + noarg.obj;noenv.obj;propsys.lib;phlib.lib;ntdll.lib;uxtheme.lib;userenv.lib;windowscodecs.lib;winsta.lib;%(AdditionalDependencies) ..\..\phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) @@ -200,7 +200,7 @@ Guard - noarg.obj;noenv.obj;phlib.lib;ntdll.lib;uxtheme.lib;userenv.lib;windowscodecs.lib;winsta.lib;%(AdditionalDependencies) + noarg.obj;noenv.obj;propsys.lib;phlib.lib;ntdll.lib;uxtheme.lib;userenv.lib;windowscodecs.lib;winsta.lib;%(AdditionalDependencies) ..\..\phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) @@ -222,6 +222,7 @@ + @@ -234,6 +235,7 @@ + diff --git a/tools/peview/peview.vcxproj.filters b/tools/peview/peview.vcxproj.filters index 9058c1d666c7..b2364f637c3c 100644 --- a/tools/peview/peview.vcxproj.filters +++ b/tools/peview/peview.vcxproj.filters @@ -81,6 +81,12 @@ Source Files\Pages\Linux + + Source Files\Pages + + + Source Files\Pages + diff --git a/tools/peview/propstore.c b/tools/peview/propstore.c new file mode 100644 index 000000000000..828f6605ec7a --- /dev/null +++ b/tools/peview/propstore.c @@ -0,0 +1,152 @@ +/* + * Process Hacker - + * PE viewer + * + * Copyright (C) 2018 dmex + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include + +VOID PvpPeEnumerateFilePropStore( + _In_ HWND ListViewHandle + ) +{ + IPropertyStore *propstore; + ULONG count; + ULONG i; + + if (SUCCEEDED(SHGetPropertyStoreFromParsingName( + PvFileName->Buffer, + NULL, + GPS_DEFAULT, + &IID_IPropertyStore, + &propstore + ))) + { + if (SUCCEEDED(IPropertyStore_GetCount(propstore, &count))) + { + for (i = 0; i < count; i++) + { + PROPERTYKEY propkey; + + if (SUCCEEDED(IPropertyStore_GetAt(propstore, i, &propkey))) + { + INT lvItemIndex; + PROPVARIANT propKeyVariant = { 0 }; + PWSTR propKeyName; + WCHAR number[PH_INT32_STR_LEN_1]; + + PhPrintUInt32(number, i); + lvItemIndex = PhAddListViewItem(ListViewHandle, MAXINT, number, NULL); + + if (SUCCEEDED(PSGetNameFromPropertyKey(&propkey, &propKeyName))) + { + PhSetListViewSubItem(ListViewHandle, lvItemIndex, 1, propKeyName); + CoTaskMemFree(propKeyName); + } + else + { + WCHAR propKeyString[PKEYSTR_MAX]; + + if (SUCCEEDED(PSStringFromPropertyKey(&propkey, propKeyString, RTL_NUMBER_OF(propKeyString)))) + PhSetListViewSubItem(ListViewHandle, lvItemIndex, 1, propKeyString); + else + PhSetListViewSubItem(ListViewHandle, lvItemIndex, 1, L"Unknown"); + } + + if (SUCCEEDED(IPropertyStore_GetValue(propstore, &propkey, &propKeyVariant))) + { + if (SUCCEEDED(PSFormatForDisplayAlloc(&propkey, &propKeyVariant, PDFF_DEFAULT, &propKeyName))) + { + PhSetListViewSubItem(ListViewHandle, lvItemIndex, 2, propKeyName); + CoTaskMemFree(propKeyName); + } + + PropVariantClear(&propKeyVariant); + } + } + } + } + + IPropertyStore_Release(propstore); + } +} + +INT_PTR CALLBACK PvpPePropStoreDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + LPPROPSHEETPAGE propSheetPage; + PPV_PROPPAGECONTEXT propPageContext; + + if (!PvPropPageDlgProcHeader(hwndDlg, uMsg, lParam, &propSheetPage, &propPageContext)) + return FALSE; + + switch (uMsg) + { + case WM_INITDIALOG: + { + HWND lvHandle; + + lvHandle = GetDlgItem(hwndDlg, IDC_LIST); + PhSetListViewStyle(lvHandle, TRUE, TRUE); + PhSetControlTheme(lvHandle, L"explorer"); + PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 40, L"#"); + PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 150, L"Name"); + PhAddListViewColumn(lvHandle, 2, 2, 2, LVCFMT_LEFT, 250, L"Value"); + PhSetExtendedListView(lvHandle); + PhLoadListViewColumnsFromSetting(L"ImagePropertiesListViewColumns", lvHandle); + + PvpPeEnumerateFilePropStore(lvHandle); + //ExtendedListView_SortItems(lvHandle); + + EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); + } + break; + case WM_DESTROY: + { + PhSaveListViewColumnsToSetting(L"ImagePropertiesListViewColumns", GetDlgItem(hwndDlg, IDC_LIST)); + } + break; + case WM_SHOWWINDOW: + { + if (!propPageContext->LayoutInitialized) + { + PPH_LAYOUT_ITEM dialogItem; + + dialogItem = PvAddPropPageLayoutItem(hwndDlg, hwndDlg, PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL); + PvAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_LIST), dialogItem, PH_ANCHOR_ALL); + + PvDoPropPageLayout(hwndDlg); + + propPageContext->LayoutInitialized = TRUE; + } + } + break; + case WM_NOTIFY: + { + PvHandleListViewNotifyForCopy(lParam, GetDlgItem(hwndDlg, IDC_LIST)); + } + break; + } + + return FALSE; +} diff --git a/tools/peview/resource.h b/tools/peview/resource.h index 7c67918dd9ab..439cb4bafb0c 100644 --- a/tools/peview/resource.h +++ b/tools/peview/resource.h @@ -14,7 +14,9 @@ #define IDB_SEARCH_ACTIVE 110 #define IDD_ELFGENERAL 110 #define IDB_SEARCH_INACTIVE 111 +#define IDD_PEPROPSTORAGE 111 #define IDB_SEARCH_ACTIVE_BMP 112 +#define IDD_PEATTR 112 #define IDB_SEARCH_INACTIVE_BMP 113 #define IDC_SYMBOLTREE 119 #define IDC_TARGETMACHINE 1003 @@ -42,7 +44,7 @@ // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 119 +#define _APS_NEXT_RESOURCE_VALUE 121 #define _APS_NEXT_COMMAND_VALUE 40001 #define _APS_NEXT_CONTROL_VALUE 1023 #define _APS_NEXT_SYMED_VALUE 115 diff --git a/tools/peview/settings.c b/tools/peview/settings.c index 49079b3b84a7..a3504728dae9 100644 --- a/tools/peview/settings.c +++ b/tools/peview/settings.c @@ -44,6 +44,8 @@ VOID PhAddDefaultSettings( PhpAddStringSetting(L"ImageImportsListViewColumns", L""); PhpAddStringSetting(L"ImageCfgListViewColumns", L""); PhpAddStringSetting(L"ImageResourcesListViewColumns", L""); + PhpAddStringSetting(L"ImageAttributesListViewColumns", L""); + PhpAddStringSetting(L"ImagePropertiesListViewColumns", L""); PhpAddStringSetting(L"LibListViewColumns", L""); PhpAddStringSetting(L"PdbTreeListColumns", L""); From 8c00a53d5597bcfa2c3b1459824fec006941e3b4 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 24 Oct 2018 23:53:17 +1100 Subject: [PATCH 1441/2058] WindowExplorer: Update window properties dialog layout, Add window property storage tab, Add window module name column to treelist --- plugins/WindowExplorer/WindowExplorer.rc | 107 +- plugins/WindowExplorer/WindowExplorer.vcxproj | 2 + .../WindowExplorer.vcxproj.filters | 6 + plugins/WindowExplorer/main.c | 16 +- plugins/WindowExplorer/prpsh.c | 442 +++++++ plugins/WindowExplorer/prpsh.h | 132 ++ plugins/WindowExplorer/resource.h | 41 +- plugins/WindowExplorer/wnddlg.c | 39 +- plugins/WindowExplorer/wndexp.h | 13 +- plugins/WindowExplorer/wndprp.c | 1172 ++++++++--------- plugins/WindowExplorer/wndtree.c | 38 +- plugins/WindowExplorer/wndtree.h | 4 +- 12 files changed, 1264 insertions(+), 748 deletions(-) create mode 100644 plugins/WindowExplorer/prpsh.c create mode 100644 plugins/WindowExplorer/prpsh.h diff --git a/plugins/WindowExplorer/WindowExplorer.rc b/plugins/WindowExplorer/WindowExplorer.rc index 0511d3ff6a8f..b452a777cb34 100644 --- a/plugins/WindowExplorer/WindowExplorer.rc +++ b/plugins/WindowExplorer/WindowExplorer.rc @@ -98,84 +98,28 @@ BEGIN EDITTEXT IDC_SEARCHEDIT,302,3,143,14,ES_AUTOHSCROLL END -IDD_WNDPROPS DIALOGEX 0, 0, 233, 152 +IDD_WNDPROPSTORAGE DIALOGEX 0, 0, 271, 224 STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Properties" +CAPTION "Property Storage" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN - LTEXT "Property list for the window:",IDC_STATIC,7,7,92,8 - CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,20,219,125 + CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_TABSTOP,0,0,271,224 END -IDD_WNDGENERAL DIALOGEX 0, 0, 233, 147 +IDD_WNDGENERAL DIALOGEX 0, 0, 271, 224 STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "General" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN - LTEXT "Text:",IDC_STATIC,7,8,18,8 - EDITTEXT IDC_TEXT,33,7,193,12,ES_AUTOHSCROLL | ES_READONLY - LTEXT "Thread:",IDC_STATIC,7,22,26,8 - LTEXT "Static",IDC_THREAD,77,22,149,8,SS_ENDELLIPSIS - LTEXT "Rectangle:",IDC_STATIC,7,33,36,8 - LTEXT "Static",IDC_RECTANGLE,77,33,149,8,SS_ENDELLIPSIS - LTEXT "Normal rectangle:",IDC_STATIC,7,44,60,8 - LTEXT "Static",IDC_NORMALRECTANGLE,77,44,149,8,SS_ENDELLIPSIS - LTEXT "Client rectangle:",IDC_STATIC,7,55,56,8 - LTEXT "Static",IDC_CLIENTRECTANGLE,77,55,149,8,SS_ENDELLIPSIS - LTEXT "Instance handle:",IDC_STATIC,7,66,56,8 - LTEXT "Static",IDC_INSTANCEHANDLE,77,66,149,8,SS_ENDELLIPSIS - LTEXT "Menu handle:",IDC_STATIC,7,77,45,8 - LTEXT "Static",IDC_MENUHANDLE,77,77,149,8,SS_ENDELLIPSIS - LTEXT "User data:",IDC_STATIC,7,88,36,8 - LTEXT "Static",IDC_USERDATA,77,88,149,8,SS_ENDELLIPSIS - LTEXT "Unicode:",IDC_STATIC,7,99,29,8 - LTEXT "Static",IDC_UNICODE,77,99,149,8 - LTEXT "Window proc:",IDC_STATIC,7,110,45,8 - EDITTEXT IDC_WINDOWPROC,75,110,151,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER - LTEXT "Dialog proc:",IDC_STATIC,7,121,39,8 - EDITTEXT IDC_DIALOGPROC,75,121,151,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER - LTEXT "Dialog control ID:",IDC_STATIC,7,132,61,8 - LTEXT "Static",IDC_CTRLID,77,132,149,8 + CONTROL "",IDC_WINDOWINFO,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_ALIGNLEFT | WS_TABSTOP,0,0,271,224 END -IDD_WNDSTYLES DIALOGEX 0, 0, 233, 140 +IDD_WNDPROPLIST DIALOGEX 0, 0, 271, 224 STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Styles" +CAPTION "Property List" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN - LTEXT "Styles:",IDC_STATIC,7,7,23,8 - LTEXT "Static",IDC_STYLES,67,7,159,8 - LISTBOX IDC_STYLESLIST,7,19,219,46,LBS_SORT | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP - LTEXT "Extended styles:",IDC_STATIC,7,69,56,8 - LTEXT "Static",IDC_EXTENDEDSTYLES,67,69,159,8 - LISTBOX IDC_EXTENDEDSTYLESLIST,7,81,219,46,LBS_SORT | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP -END - -IDD_WNDCLASS DIALOGEX 0, 0, 233, 132 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Class" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "Name:",IDC_STATIC,7,8,22,8 - EDITTEXT IDC_NAME,33,7,193,12,ES_AUTOHSCROLL | ES_READONLY - LTEXT "Atom:",IDC_STATIC,7,22,20,8 - LTEXT "Static",IDC_ATOM,77,22,149,8,SS_ENDELLIPSIS - LTEXT "Styles:",IDC_STATIC,7,33,23,8 - EDITTEXT IDC_STYLES,75,33,150,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER - LTEXT "Instance handle:",IDC_STATIC,7,44,56,8 - LTEXT "Static",IDC_INSTANCEHANDLE,77,44,149,8,SS_ENDELLIPSIS - LTEXT "Icon handle:",IDC_STATIC,7,55,42,8 - LTEXT "Static",IDC_ICONHANDLE,77,55,149,8,SS_ENDELLIPSIS - LTEXT "Small icon handle:",IDC_STATIC,7,66,60,8 - LTEXT "Static",IDC_SMALLICONHANDLE,77,66,149,8,SS_ENDELLIPSIS - LTEXT "Cursor handle:",IDC_STATIC,7,77,49,8 - LTEXT "Static",IDC_CURSORHANDLE,77,77,149,8,SS_ENDELLIPSIS - LTEXT "Background brush:",IDC_STATIC,7,88,61,8 - LTEXT "Static",IDC_BACKGROUNDBRUSH,77,88,149,8,SS_ENDELLIPSIS - LTEXT "Menu name:",IDC_STATIC,7,99,41,8 - LTEXT "Static",IDC_MENUNAME,77,99,149,8,SS_ENDELLIPSIS - LTEXT "Window proc:",IDC_STATIC,7,110,45,8 - EDITTEXT IDC_WINDOWPROC,75,110,151,14,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_TABSTOP,0,0,271,224 END @@ -195,36 +139,20 @@ BEGIN BOTTOMMARGIN, 307 END - IDD_WNDPROPS, DIALOG + IDD_WNDPROPSTORAGE, DIALOG BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 226 - TOPMARGIN, 7 - BOTTOMMARGIN, 145 + BOTTOMMARGIN, 218 END IDD_WNDGENERAL, DIALOG BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 226 - TOPMARGIN, 7 - BOTTOMMARGIN, 140 - END - - IDD_WNDSTYLES, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 226 - TOPMARGIN, 7 - BOTTOMMARGIN, 133 + RIGHTMARGIN, 233 + BOTTOMMARGIN, 147 END - IDD_WNDCLASS, DIALOG + IDD_WNDPROPLIST, DIALOG BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 226 - TOPMARGIN, 7 - BOTTOMMARGIN, 125 + BOTTOMMARGIN, 218 END END #endif // APSTUDIO_INVOKED @@ -286,7 +214,12 @@ BEGIN 0 END -IDD_WNDCLASS AFX_DIALOG_LAYOUT +IDD_WNDPROPSTORAGE AFX_DIALOG_LAYOUT +BEGIN + 0 +END + +IDD_WNDPROPLIST AFX_DIALOG_LAYOUT BEGIN 0 END diff --git a/plugins/WindowExplorer/WindowExplorer.vcxproj b/plugins/WindowExplorer/WindowExplorer.vcxproj index 7389b4273fd7..0fb65dfd0d0a 100644 --- a/plugins/WindowExplorer/WindowExplorer.vcxproj +++ b/plugins/WindowExplorer/WindowExplorer.vcxproj @@ -73,12 +73,14 @@ + + diff --git a/plugins/WindowExplorer/WindowExplorer.vcxproj.filters b/plugins/WindowExplorer/WindowExplorer.vcxproj.filters index c6ee7a5ebc90..248506128b16 100644 --- a/plugins/WindowExplorer/WindowExplorer.vcxproj.filters +++ b/plugins/WindowExplorer/WindowExplorer.vcxproj.filters @@ -30,6 +30,9 @@ Source Files + + Source Files + @@ -41,6 +44,9 @@ Header Files + + Header Files + diff --git a/plugins/WindowExplorer/main.c b/plugins/WindowExplorer/main.c index 0d2681de03ba..e90c8652e3cd 100644 --- a/plugins/WindowExplorer/main.c +++ b/plugins/WindowExplorer/main.c @@ -209,22 +209,20 @@ LOGICAL DllMain( { case DLL_PROCESS_ATTACH: { - PPH_PLUGIN_INFORMATION info; PH_SETTING_CREATE settings[] = { { IntegerSettingType, SETTING_NAME_SHOW_DESKTOP_WINDOWS, L"0" }, { StringSettingType, SETTING_NAME_WINDOW_TREE_LIST_COLUMNS, L"" }, - { IntegerPairSettingType, SETTING_NAME_WINDOWS_WINDOW_POSITION, L"100,100" }, - { ScalableIntegerPairSettingType, SETTING_NAME_WINDOWS_WINDOW_SIZE, L"@96|690,540" } + { IntegerPairSettingType, SETTING_NAME_WINDOWS_WINDOW_POSITION, L"0,0" }, + { ScalableIntegerPairSettingType, SETTING_NAME_WINDOWS_WINDOW_SIZE, L"@96|690,540" }, + { StringSettingType, SETTING_NAME_WINDOWS_PROPERTY_COLUMNS, L"" }, + { IntegerPairSettingType, SETTING_NAME_WINDOWS_PROPERTY_POSITION, L"0,0" }, + { ScalableIntegerPairSettingType, SETTING_NAME_WINDOWS_PROPERTY_SIZE, L"@96|690,540" }, + { StringSettingType, SETTING_NAME_WINDOWS_PROPLIST_COLUMNS, L"" }, + { StringSettingType, SETTING_NAME_WINDOWS_PROPSTORAGE_COLUMNS, L"" }, }; - //BOOLEAN isClient = FALSE; - //if (!GetModuleHandle(L"ProcessHacker.exe") || !WeGetProcedureAddress("PhInstanceHandle")) - //{ - // isClient = TRUE; - //} - PluginInstance = PhRegisterPlugin(PLUGIN_NAME, Instance, &info); if (!PluginInstance) diff --git a/plugins/WindowExplorer/prpsh.c b/plugins/WindowExplorer/prpsh.c new file mode 100644 index 000000000000..5115cff2062d --- /dev/null +++ b/plugins/WindowExplorer/prpsh.c @@ -0,0 +1,442 @@ +/* + * Process Hacker - + * property sheet + * + * Copyright (C) 2017 dmex + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include "wndexp.h" + +BOOLEAN HdPropContextInit = FALSE; +PPH_OBJECT_TYPE PvpPropContextType = NULL; +PPH_OBJECT_TYPE PvpPropPageContextType = NULL; +static RECT MinimumSize = { -1, -1, -1, -1 }; + +VOID NTAPI PvpPropContextDeleteProcedure( + _In_ PVOID Object, + _In_ ULONG Flags + ); + +VOID NTAPI PvpPropPageContextDeleteProcedure( + _In_ PVOID Object, + _In_ ULONG Flags + ); + +INT CALLBACK PvpPropSheetProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ LPARAM lParam + ); + +LRESULT CALLBACK PvpPropSheetWndProc( + _In_ HWND hWnd, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +INT CALLBACK PvpStandardPropPageProc( + _In_ HWND hwnd, + _In_ UINT uMsg, + _In_ LPPROPSHEETPAGE ppsp + ); + +PPV_PROPCONTEXT HdCreatePropContext( + _In_ PWSTR Caption + ) +{ + PPV_PROPCONTEXT propContext; + PROPSHEETHEADER propSheetHeader; + + if (!PvpPropContextType) + PvpPropContextType = PhCreateObjectType(L"HdPropContext2", 0, PvpPropContextDeleteProcedure); + + propContext = PhCreateObject(sizeof(PV_PROPCONTEXT), PvpPropContextType); + memset(propContext, 0, sizeof(PV_PROPCONTEXT)); + + propContext->PropSheetPages = PhAllocate(sizeof(HPROPSHEETPAGE) * PV_PROPCONTEXT_MAXPAGES); + memset(propContext->PropSheetPages, 0, sizeof(HPROPSHEETPAGE) * PV_PROPCONTEXT_MAXPAGES); + + memset(&propSheetHeader, 0, sizeof(PROPSHEETHEADER)); + propSheetHeader.dwSize = sizeof(PROPSHEETHEADER); + propSheetHeader.dwFlags = + PSH_MODELESS | + PSH_NOAPPLYNOW | + PSH_NOCONTEXTHELP | + PSH_PROPTITLE | + PSH_USECALLBACK; + propSheetHeader.hInstance = PluginInstance->DllBase; + propSheetHeader.hwndParent = NULL; + propSheetHeader.pszCaption = Caption; + propSheetHeader.pfnCallback = PvpPropSheetProc; + propSheetHeader.nPages = 0; + propSheetHeader.nStartPage = 0; + propSheetHeader.phpage = propContext->PropSheetPages; + + memcpy(&propContext->PropSheetHeader, &propSheetHeader, sizeof(PROPSHEETHEADER)); + + return propContext; +} + +VOID NTAPI PvpPropContextDeleteProcedure( + _In_ PVOID Object, + _In_ ULONG Flags + ) +{ + PPV_PROPCONTEXT propContext = (PPV_PROPCONTEXT)Object; + + PhFree(propContext->PropSheetPages); +} + +INT CALLBACK PvpPropSheetProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ LPARAM lParam + ) +{ +#define PROPSHEET_ADD_STYLE (WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_THICKFRAME); + + switch (uMsg) + { + case PSCB_PRECREATE: + { + if (lParam) + { + if (((DLGTEMPLATEEX *)lParam)->signature == USHRT_MAX) + { + ((DLGTEMPLATEEX *)lParam)->style |= PROPSHEET_ADD_STYLE; + } + else + { + ((DLGTEMPLATE *)lParam)->style |= PROPSHEET_ADD_STYLE; + } + } + } + break; + case PSCB_INITIALIZED: + { + PPV_PROPSHEETCONTEXT context; + + context = PhAllocate(sizeof(PV_PROPSHEETCONTEXT)); + memset(context, 0, sizeof(PV_PROPSHEETCONTEXT)); + + PhInitializeLayoutManager(&context->LayoutManager, hwndDlg); + + context->DefaultWindowProc = (WNDPROC)GetWindowLongPtr(hwndDlg, GWLP_WNDPROC); + PhSetWindowContext(hwndDlg, ULONG_MAX, context); + SetWindowLongPtr(hwndDlg, GWLP_WNDPROC, (LONG_PTR)PvpPropSheetWndProc); + + if (MinimumSize.left == -1) + { + RECT rect; + + rect.left = 0; + rect.top = 0; + rect.right = 271; + rect.bottom = 224; + MapDialogRect(hwndDlg, &rect); + MinimumSize = rect; + MinimumSize.left = 0; + } + } + break; + } + + return 0; +} + +PPV_PROPSHEETCONTEXT PvpGetPropSheetContext( + _In_ HWND hwnd + ) +{ + return PhGetWindowContext(hwnd, ULONG_MAX); +} + +LRESULT CALLBACK PvpPropSheetWndProc( + _In_ HWND hWnd, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + PPV_PROPSHEETCONTEXT context; + WNDPROC oldWndProc; + + if (!(context = PhGetWindowContext(hWnd, ULONG_MAX))) + return 0; + + oldWndProc = context->DefaultWindowProc; + + switch (uMsg) + { + case WM_DESTROY: + { + SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)oldWndProc); + PhRemoveWindowContext(hWnd, ULONG_MAX); + + PhSaveWindowPlacementToSetting(SETTING_NAME_WINDOWS_PROPERTY_POSITION, SETTING_NAME_WINDOWS_PROPERTY_SIZE, hWnd); + PhDeleteLayoutManager(&context->LayoutManager); + + PhFree(context); + } + break; + case WM_COMMAND: + { + switch (GET_WM_COMMAND_ID(wParam, lParam)) + { + case IDOK: + // Prevent the OK button from working (even though + // it's already hidden). This prevents the Enter + // key from closing the dialog box. + return 0; + } + } + break; + case WM_SIZE: + { + if (!IsIconic(hWnd)) + { + PhLayoutManagerLayout(&context->LayoutManager); + } + } + break; + case WM_SIZING: + { + PhResizingMinimumSize((PRECT)lParam, wParam, MinimumSize.right, MinimumSize.bottom); + } + break; + } + + return CallWindowProc(oldWndProc, hWnd, uMsg, wParam, lParam); +} + +BOOLEAN PhpInitializePropSheetLayoutStage1( + _In_ PPV_PROPSHEETCONTEXT PropSheetContext, + _In_ HWND hwnd + ) +{ + if (!PropSheetContext->LayoutInitialized) + { + HWND tabControlHandle; + PPH_LAYOUT_ITEM tabControlItem; + PPH_LAYOUT_ITEM tabPageItem; + + tabControlHandle = PropSheet_GetTabControl(hwnd); + tabControlItem = PhAddLayoutItem(&PropSheetContext->LayoutManager, tabControlHandle, + NULL, PH_ANCHOR_ALL | PH_LAYOUT_IMMEDIATE_RESIZE); + tabPageItem = PhAddLayoutItem(&PropSheetContext->LayoutManager, tabControlHandle, + NULL, PH_LAYOUT_TAB_CONTROL); // dummy item to fix multiline tab control + + PropSheetContext->TabPageItem = tabPageItem; + + PhAddLayoutItem(&PropSheetContext->LayoutManager, GetDlgItem(hwnd, IDCANCEL), + NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); + + // Hide the OK button. + ShowWindow(GetDlgItem(hwnd, IDOK), SW_HIDE); + // Set the Cancel button's text to "Close". + PhSetDialogItemText(hwnd, IDCANCEL, L"Close"); + + PhLoadWindowPlacementFromSetting(SETTING_NAME_WINDOWS_PROPERTY_POSITION, SETTING_NAME_WINDOWS_PROPERTY_SIZE, hwnd); + + PropSheetContext->LayoutInitialized = TRUE; + + return TRUE; + } + + return FALSE; +} + +BOOLEAN PvAddPropPage( + _Inout_ PPV_PROPCONTEXT PropContext, + _In_ _Assume_refs_(1) PPV_PROPPAGECONTEXT PropPageContext + ) +{ + HPROPSHEETPAGE propSheetPageHandle; + + if (PropContext->PropSheetHeader.nPages == PV_PROPCONTEXT_MAXPAGES) + return FALSE; + + propSheetPageHandle = CreatePropertySheetPage( + &PropPageContext->PropSheetPage + ); + // CreatePropertySheetPage would have sent PSPCB_ADDREF, + // which would have added a reference. + PhDereferenceObject(PropPageContext); + + PropPageContext->PropContext = PropContext; + PhReferenceObject(PropContext); + + PropContext->PropSheetPages[PropContext->PropSheetHeader.nPages] = + propSheetPageHandle; + PropContext->PropSheetHeader.nPages++; + + return TRUE; +} + +BOOLEAN PvAddPropPage2( + _Inout_ PPV_PROPCONTEXT PropContext, + _In_ HPROPSHEETPAGE PropSheetPageHandle + ) +{ + if (PropContext->PropSheetHeader.nPages == PV_PROPCONTEXT_MAXPAGES) + return FALSE; + + PropContext->PropSheetPages[PropContext->PropSheetHeader.nPages] = PropSheetPageHandle; + PropContext->PropSheetHeader.nPages++; + + return TRUE; +} + +PPV_PROPPAGECONTEXT PvCreatePropPageContext( + _In_ LPCWSTR Template, + _In_ DLGPROC DlgProc, + _In_opt_ PVOID Context + ) +{ + return PvCreatePropPageContextEx(PluginInstance->DllBase, Template, DlgProc, Context); +} + +PPV_PROPPAGECONTEXT PvCreatePropPageContextEx( + _In_opt_ PVOID InstanceHandle, + _In_ LPCWSTR Template, + _In_ DLGPROC DlgProc, + _In_opt_ PVOID Context + ) +{ + PPV_PROPPAGECONTEXT propPageContext; + + if (!PvpPropPageContextType) + PvpPropPageContextType = PhCreateObjectType(L"HdPropPageContext2", 0, PvpPropPageContextDeleteProcedure); + + propPageContext = PhCreateObject(sizeof(PV_PROPPAGECONTEXT), PvpPropPageContextType); + memset(propPageContext, 0, sizeof(PV_PROPPAGECONTEXT)); + + propPageContext->PropSheetPage.dwSize = sizeof(PROPSHEETPAGE); + propPageContext->PropSheetPage.dwFlags = PSP_USECALLBACK; + propPageContext->PropSheetPage.hInstance = PluginInstance->DllBase; + propPageContext->PropSheetPage.pszTemplate = Template; + propPageContext->PropSheetPage.pfnDlgProc = DlgProc; + propPageContext->PropSheetPage.lParam = (LPARAM)propPageContext; + propPageContext->PropSheetPage.pfnCallback = PvpStandardPropPageProc; + + propPageContext->Context = Context; + + return propPageContext; +} + +VOID NTAPI PvpPropPageContextDeleteProcedure( + _In_ PVOID Object, + _In_ ULONG Flags + ) +{ + PPV_PROPPAGECONTEXT propPageContext = (PPV_PROPPAGECONTEXT)Object; + + if (propPageContext->PropContext) + PhDereferenceObject(propPageContext->PropContext); +} + +INT CALLBACK PvpStandardPropPageProc( + _In_ HWND hwnd, + _In_ UINT uMsg, + _In_ LPPROPSHEETPAGE ppsp + ) +{ + PPV_PROPPAGECONTEXT propPageContext; + + propPageContext = (PPV_PROPPAGECONTEXT)ppsp->lParam; + + if (uMsg == PSPCB_ADDREF) + PhReferenceObject(propPageContext); + else if (uMsg == PSPCB_RELEASE) + PhDereferenceObject(propPageContext); + + return 1; +} + +PPH_LAYOUT_ITEM PvAddPropPageLayoutItem( + _In_ HWND hwnd, + _In_ HWND Handle, + _In_ PPH_LAYOUT_ITEM ParentItem, + _In_ ULONG Anchor + ) +{ + HWND parent; + PPV_PROPSHEETCONTEXT propSheetContext; + PPH_LAYOUT_MANAGER layoutManager; + PPH_LAYOUT_ITEM realParentItem; + PPH_LAYOUT_ITEM item; + + parent = GetParent(hwnd); + propSheetContext = PvpGetPropSheetContext(parent); + layoutManager = &propSheetContext->LayoutManager; + + PhpInitializePropSheetLayoutStage1(propSheetContext, parent); + + if (ParentItem != PH_PROP_PAGE_TAB_CONTROL_PARENT) + realParentItem = ParentItem; + else + realParentItem = propSheetContext->TabPageItem; + + // Use the HACK if the control is a direct child of the dialog. + if (ParentItem && ParentItem != PH_PROP_PAGE_TAB_CONTROL_PARENT && + // We detect if ParentItem is the layout item for the dialog + // by looking at its parent. + (ParentItem->ParentItem == &layoutManager->RootItem || + (ParentItem->ParentItem->Anchor & PH_LAYOUT_TAB_CONTROL))) + { + RECT dialogRect; + RECT dialogSize; + RECT margin; + + // MAKE SURE THESE NUMBERS ARE CORRECT. + dialogSize.right = 271; + dialogSize.bottom = 224; + MapDialogRect(hwnd, &dialogSize); + + // Get the original dialog rectangle. + GetWindowRect(hwnd, &dialogRect); + dialogRect.right = dialogRect.left + dialogSize.right; + dialogRect.bottom = dialogRect.top + dialogSize.bottom; + + // Calculate the margin from the original rectangle. + GetWindowRect(Handle, &margin); + margin = PhMapRect(margin, dialogRect); + PhConvertRect(&margin, &dialogRect); + + item = PhAddLayoutItemEx(layoutManager, Handle, realParentItem, Anchor, margin); + } + else + { + item = PhAddLayoutItem(layoutManager, Handle, realParentItem, Anchor); + } + + return item; +} + +VOID PvDoPropPageLayout( + _In_ HWND hwnd + ) +{ + HWND parent; + PPV_PROPSHEETCONTEXT propSheetContext; + + parent = GetParent(hwnd); + propSheetContext = PvpGetPropSheetContext(parent); + PhLayoutManagerLayout(&propSheetContext->LayoutManager); +} diff --git a/plugins/WindowExplorer/prpsh.h b/plugins/WindowExplorer/prpsh.h new file mode 100644 index 000000000000..f3f0e6d3e7b5 --- /dev/null +++ b/plugins/WindowExplorer/prpsh.h @@ -0,0 +1,132 @@ +/* + * Process Hacker - + * property sheet + * + * Copyright (C) 2017 dmex + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +// NOTE: Copied from processhacker2\ProcessHacker\procprp.h + +#ifndef PV_PRP_H +#define PV_PRP_H + +#define PV_PROPCONTEXT_MAXPAGES 20 + +typedef struct _PV_PROPSHEETCONTEXT +{ + BOOLEAN LayoutInitialized; + WNDPROC DefaultWindowProc; + PH_LAYOUT_MANAGER LayoutManager; + PPH_LAYOUT_ITEM TabPageItem; +} PV_PROPSHEETCONTEXT, *PPV_PROPSHEETCONTEXT; + +typedef struct _PV_PROPCONTEXT +{ + PROPSHEETHEADER PropSheetHeader; + HPROPSHEETPAGE *PropSheetPages; +} PV_PROPCONTEXT, *PPV_PROPCONTEXT; + +typedef struct _PV_PROPPAGECONTEXT +{ + PPV_PROPCONTEXT PropContext; + PVOID Context; + PROPSHEETPAGE PropSheetPage; + + BOOLEAN LayoutInitialized; +} PV_PROPPAGECONTEXT, *PPV_PROPPAGECONTEXT; + +VOID HdPropInitialization( + VOID + ); + +PPV_PROPCONTEXT HdCreatePropContext( + _In_ PWSTR Caption + ); + +BOOLEAN PvAddPropPage( + _Inout_ PPV_PROPCONTEXT PropContext, + _In_ _Assume_refs_(1) PPV_PROPPAGECONTEXT PropPageContext + ); + +BOOLEAN PvAddPropPage2( + _Inout_ PPV_PROPCONTEXT PropContext, + _In_ HPROPSHEETPAGE PropSheetPageHandle + ); + +PPV_PROPPAGECONTEXT PvCreatePropPageContext( + _In_ LPCWSTR Template, + _In_ DLGPROC DlgProc, + _In_opt_ PVOID Context + ); + +PPV_PROPPAGECONTEXT PvCreatePropPageContextEx( + _In_opt_ PVOID InstanceHandle, + _In_ LPCWSTR Template, + _In_ DLGPROC DlgProc, + _In_opt_ PVOID Context + ); + +BOOLEAN PvPropPageDlgProcHeader( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ LPARAM lParam, + _Out_ LPPROPSHEETPAGE *PropSheetPage, + _Out_ PPV_PROPPAGECONTEXT *PropPageContext + ); + +#define PH_PROP_PAGE_TAB_CONTROL_PARENT ((PPH_LAYOUT_ITEM)0x1) + +PPH_LAYOUT_ITEM PvAddPropPageLayoutItem( + _In_ HWND hwnd, + _In_ HWND Handle, + _In_ PPH_LAYOUT_ITEM ParentItem, + _In_ ULONG Anchor + ); + +VOID PvDoPropPageLayout( + _In_ HWND hwnd + ); + +FORCEINLINE BOOLEAN PvPropPageDlgProcHeader( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ LPARAM lParam, + _Out_ LPPROPSHEETPAGE *PropSheetPage, + _Out_ PPV_PROPPAGECONTEXT *PropPageContext + ) +{ + LPPROPSHEETPAGE propSheetPage; + + if (uMsg == WM_INITDIALOG) + { + // Save the context. + PhSetWindowContext(hwndDlg, ULONG_MAX, (HANDLE)lParam); + } + + propSheetPage = PhGetWindowContext(hwndDlg, ULONG_MAX); + + if (!propSheetPage) + return FALSE; + + *PropSheetPage = propSheetPage; + *PropPageContext = (PPV_PROPPAGECONTEXT)propSheetPage->lParam; + + return TRUE; +} + +#endif diff --git a/plugins/WindowExplorer/resource.h b/plugins/WindowExplorer/resource.h index 29511b8b8ae5..ad622a387a8a 100644 --- a/plugins/WindowExplorer/resource.h +++ b/plugins/WindowExplorer/resource.h @@ -2,7 +2,7 @@ // Microsoft Visual C++ generated include file. // Used by WindowExplorer.rc // -#define IDD_WNDPROPS 9 +#define IDD_WNDPROPSTORAGE 9 #define IDD_WNDLIST 101 #define ID_VIEW_WINDOWS 101 #define ID_THREAD_WINDOWS 102 @@ -11,37 +11,11 @@ #define ID_SHOWCONTEXTMENU 104 #define IDD_WNDGENERAL 104 #define ID_VIEW_DESKTOPWINDOWS 105 -#define IDD_WNDSTYLES 105 -#define IDD_WNDCLASS 106 -#define IDD_WNDGENERAL1 106 +#define IDD_WNDPROPLIST 105 #define IDC_LIST 1001 #define IDC_REFRESH 1002 -#define IDC_TEXT 1009 -#define IDC_RECTANGLE 1010 -#define IDC_NORMALRECTANGLE 1011 -#define IDC_CLIENTRECTANGLE 1012 -#define IDC_THREAD 1016 -#define IDC_STYLESLIST 1017 -#define IDC_STYLES 1018 -#define IDC_EXTENDEDSTYLES 1019 -#define IDC_EXTENDEDSTYLESLIST 1020 -#define IDC_INSTANCEHANDLE 1021 -#define IDC_MENUHANDLE 1022 -#define IDC_WINDOWPROC 1023 -#define IDC_WINDOWPROC2 1024 -#define IDC_DIALOGPROC 1024 -#define IDC_USERDATA 1025 -#define IDC_NAME 1026 -#define IDC_ATOM 1028 -#define IDC_CURSORHANDLE 1029 -#define IDC_ICONHANDLE 1030 -#define IDC_ICONHANDLE2 1031 -#define IDC_SMALLICONHANDLE 1031 -#define IDC_BACKGROUNDBRUSH 1032 -#define IDC_MENUNAME 1033 -#define IDC_UNICODE 1034 -#define IDC_CTRLID 1035 #define IDC_SEARCHEDIT 1035 +#define IDC_WINDOWINFO 1036 #define ID_WINDOW_GOTOTHREAD 40001 #define ID_WINDOW_COPY 40002 #define ID_WINDOW_PROPERTIES 40003 @@ -50,13 +24,8 @@ #define ID_WINDOW_MINIMIZE 40006 #define ID_WINDOW_MAXIMIZE 40007 #define ID_WINDOW_CLOSE 40008 -#define ID_WINDOW_SHOW 40009 #define ID_WINDOW_HIGHLIGHT 40010 -#define ID_WINDOW_SHOWHIDE 40011 -#define ID_WINDOW_ENABLE 40012 -#define ID_WINDOW_ENABLEDISABLE 40013 #define ID_WINDOW_ALWAYSONTOP 40014 -#define ID_WINDOW_OPACITY 40015 #define ID_OPACITY_10 40016 #define ID_OPACITY_20 40017 #define ID_OPACITY_30 40018 @@ -74,9 +43,9 @@ // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 108 +#define _APS_NEXT_RESOURCE_VALUE 110 #define _APS_NEXT_COMMAND_VALUE 40028 -#define _APS_NEXT_CONTROL_VALUE 1036 +#define _APS_NEXT_CONTROL_VALUE 1037 #define _APS_NEXT_SYMED_VALUE 106 #endif #endif diff --git a/plugins/WindowExplorer/wnddlg.c b/plugins/WindowExplorer/wnddlg.c index 61d850d49fa5..7e0c02be7823 100644 --- a/plugins/WindowExplorer/wnddlg.c +++ b/plugins/WindowExplorer/wnddlg.c @@ -2,8 +2,8 @@ * Process Hacker Window Explorer - * window tree dialog * - * Copyright (C) 2016 dmex * Copyright (C) 2011 wj32 + * Copyright (C) 2016-2018 dmex * * This file is part of Process Hacker. * @@ -134,6 +134,34 @@ VOID WepFillWindowInfo( Node->WindowVisible = !!IsWindowVisible(hwnd); Node->HasChildren = !!FindWindowEx(hwnd, NULL, NULL, NULL); + + if (processId) + { + HANDLE processHandle; + PVOID instanceHandle; + PPH_STRING fileName; + + if (NT_SUCCESS(PhOpenProcess(&processHandle, PROCESS_QUERY_LIMITED_INFORMATION, UlongToHandle(processId)))) + { + if (!(instanceHandle = (PVOID)GetWindowLongPtr(hwnd, GWLP_HINSTANCE))) + { + instanceHandle = (PVOID)GetClassLongPtr(hwnd, GCLP_HMODULE); + } + + if (instanceHandle) + { + if (NT_SUCCESS(PhGetProcessMappedFileName(processHandle, instanceHandle, &fileName))) + { + PhMoveReference(&fileName, PhResolveDevicePrefix(fileName)); + PhMoveReference(&fileName, PhGetBaseName(fileName)); + + PhMoveReference(&Node->ModuleString, fileName); + } + } + + NtClose(processHandle); + } + } } PWE_WINDOW_NODE WepAddChildWindowNode( @@ -343,8 +371,9 @@ INT_PTR CALLBACK WepWindowsDlgProc( { PH_RECTANGLE windowRectangle; - SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL((*(PVOID *)WeGetProcedureAddress("PhInstanceHandle")), MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); - SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE((*(PVOID *)WeGetProcedureAddress("PhInstanceHandle")), MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); + HINSTANCE phInstanceHandle = *(HINSTANCE*)WeGetProcedureAddress("PhInstanceHandle"); + SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(phInstanceHandle, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); + SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(phInstanceHandle, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); context->TreeNewHandle = GetDlgItem(hwndDlg, IDC_LIST); context->SearchBoxHandle = GetDlgItem(hwndDlg, IDC_SEARCHEDIT); @@ -352,7 +381,6 @@ INT_PTR CALLBACK WepWindowsDlgProc( SetWindowText(hwndDlg, PH_AUTO_T(PH_STRING, WepGetWindowTitleForSelector(&context->Selector))->Buffer); PhCreateSearchControl(hwndDlg, context->SearchBoxHandle, L"Search Windows (Ctrl+K)"); - WeInitializeWindowTree(hwndDlg, context->TreeNewHandle, &context->TreeContext); PhRegisterDialog(hwndDlg); @@ -376,7 +404,8 @@ INT_PTR CALLBACK WepWindowsDlgProc( WepRefreshWindows(context); // HACK - PhSetDialogFocus(GetParent(hwndDlg), GetDlgItem(GetParent(hwndDlg), IDCANCEL)); + //PhSetDialogFocus(GetParent(hwndDlg), GetDlgItem(GetParent(hwndDlg), IDCANCEL)); + PhSetDialogFocus(hwndDlg, context->TreeNewHandle); PhInitializeWindowTheme(hwndDlg, !!PhGetIntegerSetting(L"EnableThemeSupport")); } diff --git a/plugins/WindowExplorer/wndexp.h b/plugins/WindowExplorer/wndexp.h index b2bd9ba1e053..0f3293e2acf5 100644 --- a/plugins/WindowExplorer/wndexp.h +++ b/plugins/WindowExplorer/wndexp.h @@ -10,6 +10,7 @@ #include "resource.h" #include "wndtree.h" +#include "prpsh.h" extern PPH_PLUGIN PluginInstance; @@ -18,7 +19,11 @@ extern PPH_PLUGIN PluginInstance; #define SETTING_NAME_WINDOW_TREE_LIST_COLUMNS (PLUGIN_NAME L".WindowTreeListColumns") #define SETTING_NAME_WINDOWS_WINDOW_POSITION (PLUGIN_NAME L".WindowsWindowPosition") #define SETTING_NAME_WINDOWS_WINDOW_SIZE (PLUGIN_NAME L".WindowsWindowSize") - +#define SETTING_NAME_WINDOWS_PROPERTY_COLUMNS (PLUGIN_NAME L".WindowsPropertyColumns") +#define SETTING_NAME_WINDOWS_PROPERTY_POSITION (PLUGIN_NAME L".WindowsPropertyPosition") +#define SETTING_NAME_WINDOWS_PROPERTY_SIZE (PLUGIN_NAME L".WindowsPropertySize") +#define SETTING_NAME_WINDOWS_PROPLIST_COLUMNS (PLUGIN_NAME L".WindowsPropListColumns") +#define SETTING_NAME_WINDOWS_PROPSTORAGE_COLUMNS (PLUGIN_NAME L".WindowsPropStorageColumns") // wnddlg typedef enum _WE_WINDOW_SELECTOR_TYPE @@ -75,12 +80,6 @@ PVOID WeGetProcedureAddress( _In_ PSTR Name ); -VOID WeFormatLocalObjectName( - _In_ PWSTR OriginalName, - _Inout_updates_(256) PWCHAR Buffer, - _Out_ PUNICODE_STRING ObjectName - ); - VOID WeInvertWindowBorder( _In_ HWND hWnd ); diff --git a/plugins/WindowExplorer/wndprp.c b/plugins/WindowExplorer/wndprp.c index d00209b26a3a..c19624f86e60 100644 --- a/plugins/WindowExplorer/wndprp.c +++ b/plugins/WindowExplorer/wndprp.c @@ -3,6 +3,7 @@ * window properties * * Copyright (C) 2011 wj32 + * Copyright (C) 2018 dmex * * This file is part of Process Hacker. * @@ -20,23 +21,17 @@ * along with Process Hacker. If not, see . */ -// Since the main message loop doesn't support property sheets, we need a separate thread to run -// property sheets on. - #include "wndexp.h" #include "resource.h" #include #include -#define NUMBER_OF_PAGES 4 #define WEM_RESOLVE_DONE (WM_APP + 1234) typedef struct _WINDOW_PROPERTIES_CONTEXT { LONG RefCount; - HWND ParentWindowHandle; - HWND WindowHandle; CLIENT_ID ClientId; PH_INITONCE SymbolProviderInitOnce; @@ -73,6 +68,42 @@ typedef struct _STRING_INTEGER_PAIR ULONG Integer; } STRING_INTEGER_PAIR, *PSTRING_INTEGER_PAIR; +typedef enum _WINDOW_PROPERTIES_CATEGORY +{ + WINDOW_PROPERTIES_CATEGORY_GENERAL, + WINDOW_PROPERTIES_CATEGORY_CLASS +} WINDOW_PROPERTIES_CATEGORY; + +typedef enum _NETADAPTER_DETAILS_INDEX +{ + WINDOW_PROPERTIES_INDEX_TEXT, + WINDOW_PROPERTIES_INDEX_THREAD, + WINDOW_PROPERTIES_INDEX_RECT, + WINDOW_PROPERTIES_INDEX_NORMALRECT, + WINDOW_PROPERTIES_INDEX_CLIENTRECT, + WINDOW_PROPERTIES_INDEX_INSTANCE, + WINDOW_PROPERTIES_INDEX_MENUHANDLE, + WINDOW_PROPERTIES_INDEX_USERDATA, + WINDOW_PROPERTIES_INDEX_UNICODE, + WINDOW_PROPERTIES_INDEX_WNDPROC, + WINDOW_PROPERTIES_INDEX_DLGPROC, + WINDOW_PROPERTIES_INDEX_DLGCTLID, + WINDOW_PROPERTIES_INDEX_STYLES, + WINDOW_PROPERTIES_INDEX_EXSTYLES, + + WINDOW_PROPERTIES_INDEX_CLASS_NAME, + WINDOW_PROPERTIES_INDEX_CLASS_ATOM, + WINDOW_PROPERTIES_INDEX_CLASS_STYLES, + WINDOW_PROPERTIES_INDEX_CLASS_INSTANCE, + WINDOW_PROPERTIES_INDEX_CLASS_LARGEICON, + WINDOW_PROPERTIES_INDEX_CLASS_SMALLICON, + WINDOW_PROPERTIES_INDEX_CLASS_CURSOR, + WINDOW_PROPERTIES_INDEX_CLASS_BACKBRUSH, + WINDOW_PROPERTIES_INDEX_CLASS_MENUNAME, + WINDOW_PROPERTIES_INDEX_CLASS_WNDPROC +} NETADAPTER_DETAILS_INDEX; + + VOID WepReferenceWindowPropertiesContext( _Inout_ PWINDOW_PROPERTIES_CONTEXT Context ); @@ -81,35 +112,6 @@ VOID WepDereferenceWindowPropertiesContext( _Inout_ PWINDOW_PROPERTIES_CONTEXT Context ); -HWND WepCreateWindowProperties( - _In_ PWINDOW_PROPERTIES_CONTEXT Context - ); - -INT CALLBACK WepPropSheetProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ LPARAM lParam - ); - -LRESULT CALLBACK WepPropSheetWndProc( - _In_ HWND hwnd, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -HPROPSHEETPAGE WepCommonCreatePage( - _In_ PWINDOW_PROPERTIES_CONTEXT Context, - _In_ PWSTR Template, - _In_ DLGPROC DlgProc - ); - -INT CALLBACK WepCommonPropPageProc( - _In_ HWND hwnd, - _In_ UINT uMsg, - _In_ LPPROPSHEETPAGE ppsp - ); - NTSTATUS WepPropertiesThreadStart( _In_ PVOID Parameter ); @@ -121,21 +123,14 @@ INT_PTR CALLBACK WepWindowGeneralDlgProc( _In_ LPARAM lParam ); -INT_PTR CALLBACK WepWindowStylesDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ); - -INT_PTR CALLBACK WepWindowClassDlgProc( +INT_PTR CALLBACK WepWindowPropertiesDlgProc( _In_ HWND hwndDlg, _In_ UINT uMsg, _In_ WPARAM wParam, _In_ LPARAM lParam ); -INT_PTR CALLBACK WepWindowPropertiesDlgProc( +INT_PTR CALLBACK WepWindowPropStoreDlgProc( _In_ HWND hwndDlg, _In_ UINT uMsg, _In_ WPARAM wParam, @@ -208,13 +203,6 @@ static STRING_INTEGER_PAIR WepClassStylePairs[] = DEFINE_PAIR(CS_DROPSHADOW) }; -HANDLE WePropertiesThreadHandle = NULL; -CLIENT_ID WePropertiesThreadClientId; -PH_EVENT WePropertiesThreadReadyEvent = PH_EVENT_INIT; -PPH_LIST WePropertiesCreateList; -PPH_LIST WePropertiesWindowList; -PH_QUEUED_LOCK WePropertiesCreateLock = PH_QUEUED_LOCK_INIT; - VOID WeShowWindowProperties( _In_ HWND ParentWindowHandle, _In_ HWND WindowHandle @@ -224,19 +212,7 @@ VOID WeShowWindowProperties( ULONG threadId; ULONG processId; - if (!WePropertiesCreateList) - WePropertiesCreateList = PhCreateList(4); - if (!WePropertiesWindowList) - WePropertiesWindowList = PhCreateList(4); - - if (!WePropertiesThreadHandle) - { - WePropertiesThreadHandle = PhCreateThread(0, WepPropertiesThreadStart, NULL); - PhWaitForEvent(&WePropertiesThreadReadyEvent, NULL); - } - - context = PhAllocate(sizeof(WINDOW_PROPERTIES_CONTEXT)); - memset(context, 0, sizeof(WINDOW_PROPERTIES_CONTEXT)); + context = PhAllocateZero(sizeof(WINDOW_PROPERTIES_CONTEXT)); context->RefCount = 1; context->ParentWindowHandle = ParentWindowHandle; context->WindowHandle = WindowHandle; @@ -249,11 +225,7 @@ VOID WeShowWindowProperties( InitializeListHead(&context->ResolveListHead); PhInitializeQueuedLock(&context->ResolveListLock); - // Queue the window for creation and wake up the host thread. - PhAcquireQueuedLockExclusive(&WePropertiesCreateLock); - PhAddItemList(WePropertiesCreateList, context); - PhReleaseQueuedLockExclusive(&WePropertiesCreateLock); - PostThreadMessage(HandleToUlong(WePropertiesThreadClientId.UniqueThread), WM_NULL, 0, 0); + PhCreateThread2(WepPropertiesThreadStart, context); } VOID WepReferenceWindowPropertiesContext( @@ -296,259 +268,43 @@ VOID WepDereferenceWindowPropertiesContext( } } -static HWND WepCreateWindowProperties( - _In_ PWINDOW_PROPERTIES_CONTEXT Context - ) -{ - PROPSHEETHEADER propSheetHeader = { sizeof(propSheetHeader) }; - HPROPSHEETPAGE pages[NUMBER_OF_PAGES]; - - propSheetHeader.dwFlags = - PSH_MODELESS | - PSH_NOAPPLYNOW | - PSH_NOCONTEXTHELP | - PSH_PROPTITLE | - PSH_USECALLBACK; - propSheetHeader.hwndParent = Context->ParentWindowHandle; - propSheetHeader.pszCaption = PhaFormatString(L"Window %Ix", Context->WindowHandle)->Buffer; - propSheetHeader.nPages = 0; - propSheetHeader.nStartPage = 0; - propSheetHeader.phpage = pages; - propSheetHeader.pfnCallback = WepPropSheetProc; - - // General - pages[propSheetHeader.nPages++] = WepCommonCreatePage( - Context, - MAKEINTRESOURCE(IDD_WNDGENERAL), - WepWindowGeneralDlgProc - ); - // Styles - pages[propSheetHeader.nPages++] = WepCommonCreatePage( - Context, - MAKEINTRESOURCE(IDD_WNDSTYLES), - WepWindowStylesDlgProc - ); - // Class - pages[propSheetHeader.nPages++] = WepCommonCreatePage( - Context, - MAKEINTRESOURCE(IDD_WNDCLASS), - WepWindowClassDlgProc - ); - // Properties - pages[propSheetHeader.nPages++] = WepCommonCreatePage( - Context, - MAKEINTRESOURCE(IDD_WNDPROPS), - WepWindowPropertiesDlgProc - ); - - return (HWND)PropertySheet(&propSheetHeader); -} - -static INT CALLBACK WepPropSheetProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ LPARAM lParam - ) -{ - switch (uMsg) - { - case PSCB_INITIALIZED: - { - HWND refreshButtonHandle; - - PhSetWindowContext(hwndDlg, 0xF, (WNDPROC)GetWindowLongPtr(hwndDlg, GWLP_WNDPROC)); - SetWindowLongPtr(hwndDlg, GWLP_WNDPROC, (LONG_PTR)WepPropSheetWndProc); - - // Hide the Cancel button. - ShowWindow(GetDlgItem(hwndDlg, IDCANCEL), SW_HIDE); - // Set the OK button's text to "Close". - PhSetDialogItemText(hwndDlg, IDOK, L"Close"); - // Add the Refresh button. - refreshButtonHandle = CreateWindow(WC_BUTTON, L"Refresh", WS_CHILD | WS_TABSTOP | WS_VISIBLE, 0, 0, 3, 3, hwndDlg, (HMENU)IDC_REFRESH, - PluginInstance->DllBase, NULL); - SendMessage(refreshButtonHandle, WM_SETFONT, (WPARAM)SendMessage(GetDlgItem(hwndDlg, IDOK), WM_GETFONT, 0, 0), FALSE); - } - break; - } - - return 0; -} - -LRESULT CALLBACK WepPropSheetWndProc( - _In_ HWND hwnd, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - WNDPROC oldWndProc; - - if (!(oldWndProc = PhGetWindowContext(hwnd, 0xF))) - return 0; - - switch (uMsg) - { - case WM_DESTROY: - { - SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)oldWndProc); - PhRemoveWindowContext(hwnd, 0xF); - - if (PhGetWindowContext(hwnd, 1)) - PhRemoveWindowContext(hwnd, 1); - } - break; - case WM_SHOWWINDOW: - { - if (!PhGetWindowContext(hwnd, 1)) - { - // Move the Refresh button to where the OK button is, and move the OK button to - // where the Cancel button is. - // This must be done here because in the prop sheet callback the buttons are not - // in the right places. - PhCopyControlRectangle(hwnd, GetDlgItem(hwnd, IDOK), GetDlgItem(hwnd, IDC_REFRESH)); - PhCopyControlRectangle(hwnd, GetDlgItem(hwnd, IDCANCEL), GetDlgItem(hwnd, IDOK)); - - PhSetWindowContext(hwnd, 1, UlongToPtr(1)); - } - } - break; - case WM_COMMAND: - { - switch (GET_WM_COMMAND_ID(wParam, lParam)) - { - case IDC_REFRESH: - { - ULONG i; - HWND pageHandle; - - // Broadcast the message to all property pages. - for (i = 0; i < NUMBER_OF_PAGES; i++) - { - if (pageHandle = PropSheet_IndexToHwnd(hwnd, i)) - SendMessage(pageHandle, WM_COMMAND, IDC_REFRESH, 0); - } - } - break; - } - } - break; - } - - return CallWindowProc(oldWndProc, hwnd, uMsg, wParam, lParam); -} - -static HPROPSHEETPAGE WepCommonCreatePage( - _In_ PWINDOW_PROPERTIES_CONTEXT Context, - _In_ PWSTR Template, - _In_ DLGPROC DlgProc - ) -{ - HPROPSHEETPAGE propSheetPageHandle; - PROPSHEETPAGE propSheetPage; - - memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); - propSheetPage.dwSize = sizeof(PROPSHEETPAGE); - propSheetPage.dwFlags = PSP_USECALLBACK; - propSheetPage.hInstance = PluginInstance->DllBase; - propSheetPage.pszTemplate = Template; - propSheetPage.pfnDlgProc = DlgProc; - propSheetPage.lParam = (LPARAM)Context; - propSheetPage.pfnCallback = WepCommonPropPageProc; - - propSheetPageHandle = CreatePropertySheetPage(&propSheetPage); - - return propSheetPageHandle; -} - -static INT CALLBACK WepCommonPropPageProc( - _In_ HWND hwnd, - _In_ UINT uMsg, - _In_ LPPROPSHEETPAGE ppsp - ) -{ - PWINDOW_PROPERTIES_CONTEXT context; - - context = (PWINDOW_PROPERTIES_CONTEXT)ppsp->lParam; - - if (uMsg == PSPCB_ADDREF) - WepReferenceWindowPropertiesContext(context); - else if (uMsg == PSPCB_RELEASE) - WepDereferenceWindowPropertiesContext(context); - - return 1; -} - NTSTATUS WepPropertiesThreadStart( _In_ PVOID Parameter ) { + PWINDOW_PROPERTIES_CONTEXT context = Parameter; + PPV_PROPCONTEXT propContext; PH_AUTO_POOL autoPool; - BOOL result; - MSG message; - BOOLEAN processed; - ULONG i; PhInitializeAutoPool(&autoPool); - WePropertiesThreadClientId = NtCurrentTeb()->ClientId; - - // Force the creation of the message queue so PostThreadMessage works. - PeekMessage(&message, NULL, WM_USER, WM_USER, PM_NOREMOVE); - PhSetEvent(&WePropertiesThreadReadyEvent); - - while (result = GetMessage(&message, NULL, 0, 0)) + if (propContext = HdCreatePropContext(PhaFormatString(L"Window %Ix", context->WindowHandle)->Buffer)) { - if (result == -1) - break; - - if (WePropertiesCreateList->Count != 0) - { - PhAcquireQueuedLockExclusive(&WePropertiesCreateLock); - - for (i = 0; i < WePropertiesCreateList->Count; i++) - { - PWINDOW_PROPERTIES_CONTEXT context; - HWND hwnd; - - context = WePropertiesCreateList->Items[i]; - hwnd = WepCreateWindowProperties(context); - WepDereferenceWindowPropertiesContext(context); - PhAddItemList(WePropertiesWindowList, hwnd); - } - - PhClearList(WePropertiesCreateList); - PhReleaseQueuedLockExclusive(&WePropertiesCreateLock); - } - - processed = FALSE; - - for (i = 0; i < WePropertiesWindowList->Count; i++) - { - if (PropSheet_IsDialogMessage(WePropertiesWindowList->Items[i], &message)) - { - processed = TRUE; - break; - } - } - - if (!processed) - { - TranslateMessage(&message); - DispatchMessage(&message); - } - - // Destroy properties windows when necessary. - for (i = 0; i < WePropertiesWindowList->Count; i++) - { - if (!PropSheet_GetCurrentPageHwnd(WePropertiesWindowList->Items[i])) - { - DestroyWindow(WePropertiesWindowList->Items[i]); - PhRemoveItemList(WePropertiesWindowList, i); - i--; - } - } - - PhDrainAutoPool(&autoPool); + PPV_PROPPAGECONTEXT newPage; + + // General + newPage = PvCreatePropPageContext( + MAKEINTRESOURCE(IDD_WNDGENERAL), + WepWindowGeneralDlgProc, + context); + PvAddPropPage(propContext, newPage); + + // Properties + newPage = PvCreatePropPageContext( + MAKEINTRESOURCE(IDD_WNDPROPLIST), + WepWindowPropertiesDlgProc, + context); + PvAddPropPage(propContext, newPage); + + // Property store + newPage = PvCreatePropPageContext( + MAKEINTRESOURCE(IDD_WNDPROPSTORAGE), + WepWindowPropStoreDlgProc, + context); + PvAddPropPage(propContext, newPage); + + PhModalPropertySheet(&propContext->PropSheetHeader); + PhDereferenceObject(propContext); } PhDeleteAutoPool(&autoPool); @@ -556,43 +312,7 @@ NTSTATUS WepPropertiesThreadStart( return STATUS_SUCCESS; } -FORCEINLINE BOOLEAN WepPropPageDlgProcHeader( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ LPARAM lParam, - _Out_opt_ LPPROPSHEETPAGE *PropSheetPage, - _Out_opt_ PWINDOW_PROPERTIES_CONTEXT *Context - ) -{ - LPPROPSHEETPAGE propSheetPage; - - if (uMsg == WM_INITDIALOG) - { - propSheetPage = (LPPROPSHEETPAGE)lParam; - - PhSetWindowContext(hwndDlg, ULONG_MAX, (HANDLE)lParam); - } - else - { - propSheetPage = PhGetWindowContext(hwndDlg, ULONG_MAX); - - if (uMsg == WM_DESTROY) - PhRemoveWindowContext(hwndDlg, ULONG_MAX); - } - - if (!propSheetPage) - return FALSE; - - if (PropSheetPage) - *PropSheetPage = propSheetPage; - if (Context) - *Context = (PWINDOW_PROPERTIES_CONTEXT)propSheetPage->lParam; - - return TRUE; -} - - -static BOOLEAN NTAPI EnumGenericModulesCallback( +BOOLEAN NTAPI EnumGenericModulesCallback( _In_ PPH_MODULE_INFO Module, _In_opt_ PVOID Context ) @@ -645,7 +365,7 @@ NTSTATUS WepResolveSymbolFunction( return STATUS_SUCCESS; } -static VOID WepQueueResolveSymbol( +VOID WepQueueResolveSymbol( _In_ PWINDOW_PROPERTIES_CONTEXT Context, _In_ HWND NotifyWindow, _In_ ULONG64 Address, @@ -660,55 +380,75 @@ static VOID WepQueueResolveSymbol( PhLoadSymbolProviderOptions(Context->SymbolProvider); } - resolveContext = PhAllocate(sizeof(SYMBOL_RESOLVE_CONTEXT)); + WepReferenceWindowPropertiesContext(Context); + + resolveContext = PhAllocateZero(sizeof(SYMBOL_RESOLVE_CONTEXT)); resolveContext->Address = Address; resolveContext->Symbol = NULL; resolveContext->ResolveLevel = PhsrlInvalid; resolveContext->NotifyWindow = NotifyWindow; resolveContext->Context = Context; - WepReferenceWindowPropertiesContext(Context); resolveContext->Id = Id; PhQueueItemWorkQueue(PhGetGlobalWorkQueue(), WepResolveSymbolFunction, resolveContext); } -static PPH_STRING WepFormatRect( +HICON WepGetWindowIcon( + _In_ HWND WindowHandle + ) +{ + static HICON (WINAPI *InternalGetWindowIcon_I)( + _In_ HWND hwnd, + _In_ UINT iconType + ) = NULL; + + if (!InternalGetWindowIcon_I) + InternalGetWindowIcon_I = PhGetModuleProcAddress(L"user32.dll", "InternalGetWindowIcon"); + + if (!InternalGetWindowIcon_I) + return NULL; + + return InternalGetWindowIcon_I(WindowHandle, ICON_BIG); +} + +PPH_STRING WepFormatRect( _In_ PRECT Rect ) { - return PhaFormatString(L"(%d, %d) - (%d, %d) [%dx%d]", + return PhaFormatString(L"(%ld, %ld) - (%ld, %ld) [%ldx%ld]", Rect->left, Rect->top, Rect->right, Rect->bottom, Rect->right - Rect->left, Rect->bottom - Rect->top); } -static VOID WepRefreshWindowGeneralInfoSymbols( - _In_ HWND hwndDlg, +VOID WepRefreshWindowGeneralInfoSymbols( + _In_ HWND ListViewHandle, _In_ PWINDOW_PROPERTIES_CONTEXT Context ) { if (Context->WndProcResolving != 0) - PhSetDialogItemText(hwndDlg, IDC_WINDOWPROC, PhaFormatString(L"0x%Ix (resolving...)", Context->WndProc)->Buffer); + PhSetListViewSubItem(ListViewHandle, WINDOW_PROPERTIES_INDEX_WNDPROC, 1, PhaFormatString(L"0x%Ix (resolving...)", Context->WndProc)->Buffer); else if (Context->WndProcSymbol) - PhSetDialogItemText(hwndDlg, IDC_WINDOWPROC, PhaFormatString(L"0x%Ix (%s)", Context->WndProc, Context->WndProcSymbol->Buffer)->Buffer); + PhSetListViewSubItem(ListViewHandle, WINDOW_PROPERTIES_INDEX_WNDPROC, 1, PhaFormatString(L"0x%Ix (%s)", Context->WndProc, Context->WndProcSymbol->Buffer)->Buffer); else if (Context->WndProc != 0) - PhSetDialogItemText(hwndDlg, IDC_WINDOWPROC, PhaFormatString(L"0x%Ix", Context->WndProc)->Buffer); + PhSetListViewSubItem(ListViewHandle, WINDOW_PROPERTIES_INDEX_WNDPROC, 1, PhaFormatString(L"0x%Ix", Context->WndProc)->Buffer); else - PhSetDialogItemText(hwndDlg, IDC_WINDOWPROC, L"Unknown"); + PhSetListViewSubItem(ListViewHandle, WINDOW_PROPERTIES_INDEX_WNDPROC, 1, L"Unknown"); if (Context->DlgProcResolving != 0) - PhSetDialogItemText(hwndDlg, IDC_DIALOGPROC, PhaFormatString(L"0x%Ix (resolving...)", Context->DlgProc)->Buffer); + PhSetListViewSubItem(ListViewHandle, WINDOW_PROPERTIES_INDEX_DLGPROC, 1, PhaFormatString(L"0x%Ix (resolving...)", Context->DlgProc)->Buffer); else if (Context->DlgProcSymbol) - PhSetDialogItemText(hwndDlg, IDC_DIALOGPROC, PhaFormatString(L"0x%Ix (%s)", Context->DlgProc, Context->DlgProcSymbol->Buffer)->Buffer); + PhSetListViewSubItem(ListViewHandle, WINDOW_PROPERTIES_INDEX_DLGPROC, 1, PhaFormatString(L"0x%Ix (%s)", Context->DlgProc, Context->DlgProcSymbol->Buffer)->Buffer); else if (Context->DlgProc != 0) - PhSetDialogItemText(hwndDlg, IDC_DIALOGPROC, PhaFormatString(L"0x%Ix", Context->DlgProc)->Buffer); + PhSetListViewSubItem(ListViewHandle, WINDOW_PROPERTIES_INDEX_DLGPROC, 1, PhaFormatString(L"0x%Ix", Context->DlgProc)->Buffer); else if (Context->WndProc != 0) - PhSetDialogItemText(hwndDlg, IDC_DIALOGPROC, L"N/A"); + PhSetListViewSubItem(ListViewHandle, WINDOW_PROPERTIES_INDEX_DLGPROC, 1, L"N/A"); else - PhSetDialogItemText(hwndDlg, IDC_DIALOGPROC, L"Unknown"); + PhSetListViewSubItem(ListViewHandle, WINDOW_PROPERTIES_INDEX_DLGPROC, 1, L"Unknown"); } -static VOID WepRefreshWindowGeneralInfo( +VOID WepRefreshWindowGeneralInfo( _In_ HWND hwndDlg, + _In_ HWND ListViewHandle, _In_ PWINDOW_PROPERTIES_CONTEXT Context ) { @@ -726,19 +466,20 @@ static VOID WepRefreshWindowGeneralInfo( instanceHandle = (PVOID)GetWindowLongPtr(Context->WindowHandle, GWLP_HINSTANCE); userdataHandle = (PVOID)GetWindowLongPtr(Context->WindowHandle, GWLP_USERDATA); windowId = (ULONG)GetWindowLongPtr(Context->WindowHandle, GWLP_ID); + // TODO: GetWindowLongPtr(Context->WindowHandle, GCLP_WNDPROC); - PhSetDialogItemText(hwndDlg, IDC_THREAD, PH_AUTO_T(PH_STRING, PhGetClientIdName(&Context->ClientId))->Buffer); - PhSetDialogItemText(hwndDlg, IDC_TEXT, PhGetStringOrEmpty(PH_AUTO(PhGetWindowText(Context->WindowHandle)))); + PhSetListViewSubItem(ListViewHandle, WINDOW_PROPERTIES_INDEX_TEXT, 1, PhGetStringOrEmpty(PH_AUTO(PhGetWindowText(Context->WindowHandle)))); + PhSetListViewSubItem(ListViewHandle, WINDOW_PROPERTIES_INDEX_THREAD, 1, PH_AUTO_T(PH_STRING, PhGetClientIdName(&Context->ClientId))->Buffer); if (GetWindowInfo(Context->WindowHandle, &windowInfo)) { - PhSetDialogItemText(hwndDlg, IDC_RECTANGLE, WepFormatRect(&windowInfo.rcWindow)->Buffer); - PhSetDialogItemText(hwndDlg, IDC_CLIENTRECTANGLE, WepFormatRect(&windowInfo.rcClient)->Buffer); + PhSetListViewSubItem(ListViewHandle, WINDOW_PROPERTIES_INDEX_RECT, 1, WepFormatRect(&windowInfo.rcWindow)->Buffer); + PhSetListViewSubItem(ListViewHandle, WINDOW_PROPERTIES_INDEX_CLIENTRECT, 1, WepFormatRect(&windowInfo.rcClient)->Buffer); } else { - PhSetDialogItemText(hwndDlg, IDC_RECTANGLE, L"N/A"); - PhSetDialogItemText(hwndDlg, IDC_CLIENTRECTANGLE, L"N/A"); + PhSetListViewSubItem(ListViewHandle, WINDOW_PROPERTIES_INDEX_RECT, 1, L"N/A"); + PhSetListViewSubItem(ListViewHandle, WINDOW_PROPERTIES_INDEX_CLIENTRECT, 1, L"N/A"); } if (GetWindowPlacement(Context->WindowHandle, &windowPlacement)) @@ -752,14 +493,14 @@ static VOID WepRefreshWindowGeneralInfo( windowPlacement.rcNormalPosition.bottom += monitorInfo.rcWork.top; } - PhSetDialogItemText(hwndDlg, IDC_NORMALRECTANGLE, WepFormatRect(&windowPlacement.rcNormalPosition)->Buffer); + PhSetListViewSubItem(ListViewHandle, WINDOW_PROPERTIES_INDEX_NORMALRECT, 1, WepFormatRect(&windowPlacement.rcNormalPosition)->Buffer); } else { - PhSetDialogItemText(hwndDlg, IDC_NORMALRECTANGLE, L"N/A"); + PhSetListViewSubItem(ListViewHandle, WINDOW_PROPERTIES_INDEX_NORMALRECT, 1, L"N/A"); } - if (NT_SUCCESS(PhOpenProcess(&processHandle, *(PULONG)WeGetProcedureAddress("ProcessQueryAccess"), Context->ClientId.UniqueProcess))) + if (NT_SUCCESS(PhOpenProcess(&processHandle, PROCESS_QUERY_LIMITED_INFORMATION, Context->ClientId.UniqueProcess))) { if (NT_SUCCESS(PhGetProcessMappedFileName(processHandle, instanceHandle, &fileName))) { @@ -772,7 +513,7 @@ static VOID WepRefreshWindowGeneralInfo( if (fileName) { - PhSetDialogItemText(hwndDlg, IDC_INSTANCEHANDLE, PhaFormatString( + PhSetListViewSubItem(ListViewHandle, WINDOW_PROPERTIES_INDEX_INSTANCE, 1, PhaFormatString( L"0x%Ix (%s)", instanceHandle, PhGetStringOrEmpty(fileName) @@ -781,17 +522,19 @@ static VOID WepRefreshWindowGeneralInfo( } else { - PhSetDialogItemText(hwndDlg, IDC_INSTANCEHANDLE, PhaFormatString( + PhSetListViewSubItem(ListViewHandle, WINDOW_PROPERTIES_INDEX_INSTANCE, 1, PhaFormatString( L"0x%Ix", instanceHandle )->Buffer); } - PhSetDialogItemText(hwndDlg, IDC_MENUHANDLE, PhaFormatString(L"0x%Ix", menuHandle)->Buffer); - PhSetDialogItemText(hwndDlg, IDC_USERDATA, PhaFormatString(L"0x%Ix", userdataHandle)->Buffer); - PhSetDialogItemText(hwndDlg, IDC_UNICODE, IsWindowUnicode(Context->WindowHandle) ? L"Yes" : L"No"); - PhSetDialogItemText(hwndDlg, IDC_CTRLID, PhaFormatString(L"%lu", windowId)->Buffer); + PhSetListViewSubItem(ListViewHandle, WINDOW_PROPERTIES_INDEX_MENUHANDLE, 1, PhaFormatString(L"0x%Ix", menuHandle)->Buffer); + PhSetListViewSubItem(ListViewHandle, WINDOW_PROPERTIES_INDEX_USERDATA, 1, PhaFormatString(L"0x%Ix", userdataHandle)->Buffer); + PhSetListViewSubItem(ListViewHandle, WINDOW_PROPERTIES_INDEX_UNICODE, 1, IsWindowUnicode(Context->WindowHandle) ? L"Yes" : L"No"); + PhSetListViewSubItem(ListViewHandle, WINDOW_PROPERTIES_INDEX_DLGCTLID, 1, PhaFormatString(L"%lu", windowId)->Buffer); + //ULONG version; + //if (SendMessageTimeout(Context->WindowHandle, CCM_GETVERSION, 0, 0, SMTO_ABORTIFHUNG, 5000, &version)) //WepQueryProcessWndProc(Context); if (Context->WndProc != 0) @@ -806,217 +549,138 @@ static VOID WepRefreshWindowGeneralInfo( WepQueueResolveSymbol(Context, hwndDlg, Context->DlgProc, 2); } - WepRefreshWindowGeneralInfoSymbols(hwndDlg, Context); + WepRefreshWindowGeneralInfoSymbols(ListViewHandle, Context); } -INT_PTR CALLBACK WepWindowGeneralDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam +VOID WepRefreshWindowStyles( + _In_ HWND ListViewHandle, + _In_ PWINDOW_PROPERTIES_CONTEXT Context ) { - PWINDOW_PROPERTIES_CONTEXT context; - - if (!WepPropPageDlgProcHeader(hwndDlg, uMsg, lParam, NULL, &context)) - return FALSE; + WINDOWINFO windowInfo = { sizeof(WINDOWINFO) }; + PH_STRING_BUILDER styleStringBuilder; + PH_STRING_BUILDER styleExStringBuilder; + ULONG i; - switch (uMsg) + if (GetWindowInfo(Context->WindowHandle, &windowInfo)) { - case WM_INITDIALOG: - { - // HACK - PhCenterWindow(GetParent(hwndDlg), GetParent(GetParent(hwndDlg))); + PhInitializeStringBuilder(&styleStringBuilder, 100); + PhInitializeStringBuilder(&styleExStringBuilder, 100); - WepRefreshWindowGeneralInfo(hwndDlg, context); - } - break; - case WM_COMMAND: + PhAppendFormatStringBuilder(&styleStringBuilder, L"0x%x (", windowInfo.dwStyle); + PhAppendFormatStringBuilder(&styleExStringBuilder, L"0x%x (", windowInfo.dwExStyle); + + for (i = 0; i < RTL_NUMBER_OF(WepStylePairs); i++) { - switch (GET_WM_COMMAND_ID(wParam, lParam)) + if (windowInfo.dwStyle & WepStylePairs[i].Integer) { - case IDC_REFRESH: - PhClearReference(&context->WndProcSymbol); - WepRefreshWindowGeneralInfo(hwndDlg, context); - break; + // Skip irrelevant styles. + if (WepStylePairs[i].Integer == WS_MAXIMIZEBOX || + WepStylePairs[i].Integer == WS_MINIMIZEBOX) + { + if (windowInfo.dwStyle & WS_CHILD) + continue; + } + + if (WepStylePairs[i].Integer == WS_TABSTOP || + WepStylePairs[i].Integer == WS_GROUP) + { + if (!(windowInfo.dwStyle & WS_CHILD)) + continue; + } + + PhAppendStringBuilder2(&styleStringBuilder, WepStylePairs[i].String); + PhAppendStringBuilder2(&styleStringBuilder, L", "); } } - break; - case WEM_RESOLVE_DONE: + + if (PhEndsWithString2(styleStringBuilder.String, L", ", FALSE)) { - PSYMBOL_RESOLVE_CONTEXT resolveContext = (PSYMBOL_RESOLVE_CONTEXT)lParam; + PhRemoveEndStringBuilder(&styleStringBuilder, 2); + PhAppendCharStringBuilder(&styleStringBuilder, ')'); + } + else + { + PhRemoveEndStringBuilder(&styleStringBuilder, 1); + } - if (resolveContext->Id == 1) + for (i = 0; i < RTL_NUMBER_OF(WepExtendedStylePairs); i++) + { + if (windowInfo.dwExStyle & WepExtendedStylePairs[i].Integer) { - PhAcquireQueuedLockExclusive(&context->ResolveListLock); - RemoveEntryList(&resolveContext->ListEntry); - PhReleaseQueuedLockExclusive(&context->ResolveListLock); + PhAppendStringBuilder2(&styleExStringBuilder, WepExtendedStylePairs[i].String); + PhAppendStringBuilder2(&styleExStringBuilder, L", "); + } + } - if (resolveContext->ResolveLevel != PhsrlModule && resolveContext->ResolveLevel != PhsrlFunction) - PhClearReference(&resolveContext->Symbol); + if (PhEndsWithString2(styleExStringBuilder.String, L", ", FALSE)) + { + PhRemoveEndStringBuilder(&styleExStringBuilder, 2); + PhAppendCharStringBuilder(&styleExStringBuilder, ')'); + } + else + { + PhRemoveEndStringBuilder(&styleExStringBuilder, 1); + } - PhMoveReference(&context->WndProcSymbol, resolveContext->Symbol); - PhFree(resolveContext); + PhSetListViewSubItem(ListViewHandle, WINDOW_PROPERTIES_INDEX_STYLES, 1, PhFinalStringBuilderString(&styleStringBuilder)->Buffer); + PhSetListViewSubItem(ListViewHandle, WINDOW_PROPERTIES_INDEX_EXSTYLES, 1, PhFinalStringBuilderString(&styleExStringBuilder)->Buffer); - context->WndProcResolving--; - } - else if (resolveContext->Id == 2) - { - PhAcquireQueuedLockExclusive(&context->ResolveListLock); - RemoveEntryList(&resolveContext->ListEntry); - PhReleaseQueuedLockExclusive(&context->ResolveListLock); - - if (resolveContext->ResolveLevel != PhsrlModule && resolveContext->ResolveLevel != PhsrlFunction) - PhClearReference(&resolveContext->Symbol); - - PhMoveReference(&context->DlgProcSymbol, resolveContext->Symbol); - PhFree(resolveContext); - - context->DlgProcResolving--; - } - - WepRefreshWindowGeneralInfoSymbols(hwndDlg, context); - } - break; + PhDeleteStringBuilder(&styleStringBuilder); + PhDeleteStringBuilder(&styleExStringBuilder); + } + else + { + PhSetListViewSubItem(ListViewHandle, WINDOW_PROPERTIES_INDEX_STYLES, 1, L"N/A"); + PhSetListViewSubItem(ListViewHandle, WINDOW_PROPERTIES_INDEX_EXSTYLES, 1, L"N/A"); } - - return FALSE; } -static VOID WepRefreshWindowStyles( - _In_ HWND hwndDlg, +VOID WepRefreshClassStyles( + _In_ HWND ListViewHandle, _In_ PWINDOW_PROPERTIES_CONTEXT Context ) { - WINDOWINFO windowInfo = { sizeof(WINDOWINFO) }; - HWND stylesListBox; - HWND extendedStylesListBox; + PH_STRING_BUILDER stringBuilder; ULONG i; - stylesListBox = GetDlgItem(hwndDlg, IDC_STYLESLIST); - extendedStylesListBox = GetDlgItem(hwndDlg, IDC_EXTENDEDSTYLESLIST); - - ListBox_ResetContent(stylesListBox); - ListBox_ResetContent(extendedStylesListBox); + PhInitializeStringBuilder(&stringBuilder, 100); + PhAppendFormatStringBuilder(&stringBuilder, L"0x%x (", Context->ClassInfo.style); - if (GetWindowInfo(Context->WindowHandle, &windowInfo)) + for (i = 0; i < RTL_NUMBER_OF(WepClassStylePairs); i++) { - PhSetDialogItemText(hwndDlg, IDC_STYLES, PhaFormatString(L"0x%x", windowInfo.dwStyle)->Buffer); - PhSetDialogItemText(hwndDlg, IDC_EXTENDEDSTYLES, PhaFormatString(L"0x%x", windowInfo.dwExStyle)->Buffer); - - for (i = 0; i < sizeof(WepStylePairs) / sizeof(STRING_INTEGER_PAIR); i++) - { - if (windowInfo.dwStyle & WepStylePairs[i].Integer) - { - // Skip irrelevant styles. - - if (WepStylePairs[i].Integer == WS_MAXIMIZEBOX || - WepStylePairs[i].Integer == WS_MINIMIZEBOX) - { - if (windowInfo.dwStyle & WS_CHILD) - continue; - } - - if (WepStylePairs[i].Integer == WS_TABSTOP || - WepStylePairs[i].Integer == WS_GROUP) - { - if (!(windowInfo.dwStyle & WS_CHILD)) - continue; - } - - ListBox_AddString(stylesListBox, WepStylePairs[i].String); - } - } - - for (i = 0; i < sizeof(WepExtendedStylePairs) / sizeof(STRING_INTEGER_PAIR); i++) + if (Context->ClassInfo.style & WepClassStylePairs[i].Integer) { - if (windowInfo.dwExStyle & WepExtendedStylePairs[i].Integer) - { - ListBox_AddString(extendedStylesListBox, WepExtendedStylePairs[i].String); - } + PhAppendStringBuilder2(&stringBuilder, WepClassStylePairs[i].String); + PhAppendStringBuilder2(&stringBuilder, L", "); } } - else + + if (PhEndsWithString2(stringBuilder.String, L", ", FALSE)) { - PhSetDialogItemText(hwndDlg, IDC_STYLES, L"N/A"); - PhSetDialogItemText(hwndDlg, IDC_EXTENDEDSTYLES, L"N/A"); + PhRemoveEndStringBuilder(&stringBuilder, 2); + PhAppendCharStringBuilder(&stringBuilder, ')'); } -} - -INT_PTR CALLBACK WepWindowStylesDlgProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - PWINDOW_PROPERTIES_CONTEXT context; - - if (!WepPropPageDlgProcHeader(hwndDlg, uMsg, lParam, NULL, &context)) - return FALSE; - - switch (uMsg) + else { - case WM_INITDIALOG: - { - WepRefreshWindowStyles(hwndDlg, context); - } - break; - case WM_COMMAND: - { - switch (GET_WM_COMMAND_ID(wParam, lParam)) - { - case IDC_REFRESH: - WepRefreshWindowStyles(hwndDlg, context); - break; - } - } - break; + // No styles. Remove the brackets. + PhRemoveEndStringBuilder(&stringBuilder, 1); } - return FALSE; -} - -static VOID WepRefreshWindowClassInfoSymbols( - _In_ HWND hwndDlg, - _In_ PWINDOW_PROPERTIES_CONTEXT Context - ) -{ - if (Context->ClassWndProcResolving != 0) - PhSetDialogItemText(hwndDlg, IDC_WINDOWPROC, PhaFormatString(L"0x%Ix (resolving...)", Context->ClassInfo.lpfnWndProc)->Buffer); - else if (Context->ClassWndProcSymbol) - PhSetDialogItemText(hwndDlg, IDC_WINDOWPROC, PhaFormatString(L"0x%Ix (%s)", Context->ClassInfo.lpfnWndProc, Context->ClassWndProcSymbol->Buffer)->Buffer); - else if (Context->ClassInfo.lpfnWndProc) - PhSetDialogItemText(hwndDlg, IDC_WINDOWPROC, PhaFormatString(L"0x%Ix", Context->ClassInfo.lpfnWndProc)->Buffer); - else - PhSetDialogItemText(hwndDlg, IDC_WINDOWPROC, L"Unknown"); + PhSetListViewSubItem(ListViewHandle, WINDOW_PROPERTIES_INDEX_CLASS_STYLES, 1, PhFinalStringBuilderString(&stringBuilder)->Buffer); + PhDeleteStringBuilder(&stringBuilder); } -static VOID WepRefreshWindowClassInfo( - _In_ HWND hwndDlg, +VOID WepRefreshClassModule( + _In_ HWND ListViewHandle, _In_ PWINDOW_PROPERTIES_CONTEXT Context ) { - WCHAR className[256]; - PH_STRING_BUILDER stringBuilder; HANDLE processHandle; PPH_STRING fileName = NULL; - PVOID instanceHandle; - ULONG i; - - if (!GetClassName(Context->WindowHandle, className, sizeof(className) / sizeof(WCHAR))) - className[0] = 0; - - //WepQueryProcessWndProc(Context); - - //if (!Context->HookDataSuccess) - Context->ClassInfo.cbSize = sizeof(WNDCLASSEX); - GetClassInfoEx(NULL, className, &Context->ClassInfo); - - instanceHandle = (PVOID)GetClassLongPtr(Context->WindowHandle, GCLP_HMODULE); - // TODO: GetWindowLongPtr(Context->WindowHandle, GCLP_WNDPROC); + PVOID instanceHandle = (PVOID)GetClassLongPtr(Context->WindowHandle, GCLP_HMODULE); - if (NT_SUCCESS(PhOpenProcess(&processHandle, *(PULONG)WeGetProcedureAddress("ProcessQueryAccess"), Context->ClientId.UniqueProcess))) + if (NT_SUCCESS(PhOpenProcess(&processHandle, PROCESS_QUERY_LIMITED_INFORMATION, Context->ClientId.UniqueProcess))) { if (NT_SUCCESS(PhGetProcessMappedFileName(processHandle, instanceHandle, &fileName))) { @@ -1029,7 +693,7 @@ static VOID WepRefreshWindowClassInfo( if (fileName) { - PhSetDialogItemText(hwndDlg, IDC_INSTANCEHANDLE, PhaFormatString( + PhSetListViewSubItem(ListViewHandle, WINDOW_PROPERTIES_INDEX_CLASS_INSTANCE, 1, PhaFormatString( L"0x%Ix (%s)", instanceHandle, PhGetStringOrEmpty(fileName) @@ -1038,58 +702,115 @@ static VOID WepRefreshWindowClassInfo( } else { - PhSetDialogItemText(hwndDlg, IDC_INSTANCEHANDLE, PhaFormatString( + PhSetListViewSubItem(ListViewHandle, WINDOW_PROPERTIES_INDEX_CLASS_INSTANCE, 1, PhaFormatString( L"0x%Ix", instanceHandle )->Buffer); } +} - PhSetDialogItemText(hwndDlg, IDC_NAME, className); - PhSetDialogItemText(hwndDlg, IDC_ATOM, PhaFormatString(L"0x%x", GetClassWord(Context->WindowHandle, GCW_ATOM))->Buffer); - PhSetDialogItemText(hwndDlg, IDC_ICONHANDLE, PhaFormatString(L"0x%Ix", Context->ClassInfo.hIcon)->Buffer); - PhSetDialogItemText(hwndDlg, IDC_SMALLICONHANDLE, PhaFormatString(L"0x%Ix", Context->ClassInfo.hIconSm)->Buffer); - PhSetDialogItemText(hwndDlg, IDC_MENUNAME, PhaFormatString(L"0x%Ix", Context->ClassInfo.lpszMenuName)->Buffer); - - PhInitializeStringBuilder(&stringBuilder, 100); - PhAppendFormatStringBuilder(&stringBuilder, L"0x%x (", Context->ClassInfo.style); - - for (i = 0; i < sizeof(WepClassStylePairs) / sizeof(STRING_INTEGER_PAIR); i++) +VOID WepRefreshWindowClassInfoSymbols( + _In_ HWND ListViewHandle, + _In_ PWINDOW_PROPERTIES_CONTEXT Context + ) +{ + if (Context->ClassWndProcResolving != 0) { - if (Context->ClassInfo.style & WepClassStylePairs[i].Integer) - { - PhAppendStringBuilder2(&stringBuilder, WepClassStylePairs[i].String); - PhAppendStringBuilder2(&stringBuilder, L" | "); - } + PhSetListViewSubItem(ListViewHandle, WINDOW_PROPERTIES_INDEX_CLASS_WNDPROC, 1, PhaFormatString( + L"0x%Ix (resolving...)", + Context->ClassInfo.lpfnWndProc + )->Buffer); } - - if (PhEndsWithString2(stringBuilder.String, L" | ", FALSE)) + else if (Context->ClassWndProcSymbol) { - PhRemoveEndStringBuilder(&stringBuilder, 3); - PhAppendCharStringBuilder(&stringBuilder, ')'); + PhSetListViewSubItem(ListViewHandle, WINDOW_PROPERTIES_INDEX_CLASS_WNDPROC, 1, PhaFormatString( + L"0x%Ix (%s)", + Context->ClassInfo.lpfnWndProc, + Context->ClassWndProcSymbol->Buffer + )->Buffer); + } + else if (Context->ClassInfo.lpfnWndProc) + { + PhSetListViewSubItem(ListViewHandle, WINDOW_PROPERTIES_INDEX_CLASS_WNDPROC, 1, PhaFormatString( + L"0x%Ix", + Context->ClassInfo.lpfnWndProc + )->Buffer); } else { - // No styles. Remove the brackets. - PhRemoveEndStringBuilder(&stringBuilder, 1); + PhSetListViewSubItem(ListViewHandle, WINDOW_PROPERTIES_INDEX_CLASS_WNDPROC, 1, L"Unknown"); } +} - PhSetDialogItemText(hwndDlg, IDC_STYLES, stringBuilder.String->Buffer); - PhDeleteStringBuilder(&stringBuilder); +VOID WepRefreshWindowClassInfo( + _In_ HWND hwndDlg, + _In_ HWND ListViewHandle, + _In_ PWINDOW_PROPERTIES_CONTEXT Context + ) +{ + WCHAR className[256]; + + if (!GetClassName(Context->WindowHandle, className, RTL_NUMBER_OF(className))) + className[0] = 0; - // TODO: Add symbols for these values. - PhSetDialogItemText(hwndDlg, IDC_CURSORHANDLE, PhaFormatString(L"0x%Ix", Context->ClassInfo.hCursor)->Buffer); - PhSetDialogItemText(hwndDlg, IDC_BACKGROUNDBRUSH, PhaFormatString(L"0x%Ix", Context->ClassInfo.hbrBackground)->Buffer); + Context->ClassInfo.cbSize = sizeof(WNDCLASSEX); + GetClassInfoEx(NULL, className, &Context->ClassInfo); + + PhSetListViewSubItem(ListViewHandle, WINDOW_PROPERTIES_INDEX_CLASS_NAME, 1, className); + PhSetListViewSubItem(ListViewHandle, WINDOW_PROPERTIES_INDEX_CLASS_ATOM, 1, PhaFormatString(L"0x%x", GetClassWord(Context->WindowHandle, GCW_ATOM))->Buffer); + PhSetListViewSubItem(ListViewHandle, WINDOW_PROPERTIES_INDEX_CLASS_LARGEICON, 1, PhaFormatString(L"0x%Ix", Context->ClassInfo.hIcon)->Buffer); + PhSetListViewSubItem(ListViewHandle, WINDOW_PROPERTIES_INDEX_CLASS_SMALLICON, 1, PhaFormatString(L"0x%Ix", Context->ClassInfo.hIconSm)->Buffer); + PhSetListViewSubItem(ListViewHandle, WINDOW_PROPERTIES_INDEX_CLASS_MENUNAME, 1, PhaFormatString(L"0x%Ix", Context->ClassInfo.lpszMenuName)->Buffer); + PhSetListViewSubItem(ListViewHandle, WINDOW_PROPERTIES_INDEX_CLASS_CURSOR, 1, PhaFormatString(L"0x%Ix", Context->ClassInfo.hCursor)->Buffer); + PhSetListViewSubItem(ListViewHandle, WINDOW_PROPERTIES_INDEX_CLASS_BACKBRUSH, 1, PhaFormatString(L"0x%Ix", Context->ClassInfo.hbrBackground)->Buffer); + + WepRefreshClassStyles(ListViewHandle, Context); + WepRefreshClassModule(ListViewHandle, Context); if (Context->ClassInfo.lpfnWndProc) { Context->ClassWndProcResolving++; - WepQueueResolveSymbol(Context, hwndDlg, (ULONG_PTR)Context->ClassInfo.lpfnWndProc, 0); + WepQueueResolveSymbol(Context, hwndDlg, (ULONG_PTR)Context->ClassInfo.lpfnWndProc, 3); } - WepRefreshWindowClassInfoSymbols(hwndDlg, Context); + WepRefreshWindowClassInfoSymbols(ListViewHandle, Context); +} + +VOID WepGeneralAddListViewItemGroups( + _In_ HWND ListViewHandle + ) +{ + ListView_EnableGroupView(ListViewHandle, TRUE); + PhAddListViewGroup(ListViewHandle, WINDOW_PROPERTIES_CATEGORY_GENERAL, L"General"); + PhAddListViewGroup(ListViewHandle, WINDOW_PROPERTIES_CATEGORY_CLASS, L"Class"); + + PhAddListViewGroupItem(ListViewHandle, WINDOW_PROPERTIES_CATEGORY_GENERAL, WINDOW_PROPERTIES_INDEX_TEXT, L"Text", NULL); + PhAddListViewGroupItem(ListViewHandle, WINDOW_PROPERTIES_CATEGORY_GENERAL, WINDOW_PROPERTIES_INDEX_THREAD, L"Thread", NULL); + PhAddListViewGroupItem(ListViewHandle, WINDOW_PROPERTIES_CATEGORY_GENERAL, WINDOW_PROPERTIES_INDEX_RECT, L"Rectangle", NULL); + PhAddListViewGroupItem(ListViewHandle, WINDOW_PROPERTIES_CATEGORY_GENERAL, WINDOW_PROPERTIES_INDEX_NORMALRECT, L"Normal rectangle", NULL); + PhAddListViewGroupItem(ListViewHandle, WINDOW_PROPERTIES_CATEGORY_GENERAL, WINDOW_PROPERTIES_INDEX_CLIENTRECT, L"Client rectangle", NULL); + PhAddListViewGroupItem(ListViewHandle, WINDOW_PROPERTIES_CATEGORY_GENERAL, WINDOW_PROPERTIES_INDEX_INSTANCE, L"Instance handle", NULL); + PhAddListViewGroupItem(ListViewHandle, WINDOW_PROPERTIES_CATEGORY_GENERAL, WINDOW_PROPERTIES_INDEX_MENUHANDLE, L"Menu handle", NULL); + PhAddListViewGroupItem(ListViewHandle, WINDOW_PROPERTIES_CATEGORY_GENERAL, WINDOW_PROPERTIES_INDEX_USERDATA, L"User data", NULL); + PhAddListViewGroupItem(ListViewHandle, WINDOW_PROPERTIES_CATEGORY_GENERAL, WINDOW_PROPERTIES_INDEX_UNICODE, L"Unicode", NULL); + PhAddListViewGroupItem(ListViewHandle, WINDOW_PROPERTIES_CATEGORY_GENERAL, WINDOW_PROPERTIES_INDEX_WNDPROC, L"Window procedure", NULL); + PhAddListViewGroupItem(ListViewHandle, WINDOW_PROPERTIES_CATEGORY_GENERAL, WINDOW_PROPERTIES_INDEX_DLGPROC, L"Dialog procedure", NULL); + PhAddListViewGroupItem(ListViewHandle, WINDOW_PROPERTIES_CATEGORY_GENERAL, WINDOW_PROPERTIES_INDEX_DLGCTLID, L"Dialog control ID", NULL); + PhAddListViewGroupItem(ListViewHandle, WINDOW_PROPERTIES_CATEGORY_GENERAL, WINDOW_PROPERTIES_INDEX_STYLES, L"Styles", NULL); + PhAddListViewGroupItem(ListViewHandle, WINDOW_PROPERTIES_CATEGORY_GENERAL, WINDOW_PROPERTIES_INDEX_EXSTYLES, L"Extended styles", NULL); + PhAddListViewGroupItem(ListViewHandle, WINDOW_PROPERTIES_CATEGORY_CLASS, WINDOW_PROPERTIES_INDEX_CLASS_NAME, L"Name", NULL); + PhAddListViewGroupItem(ListViewHandle, WINDOW_PROPERTIES_CATEGORY_CLASS, WINDOW_PROPERTIES_INDEX_CLASS_ATOM, L"Atom", NULL); + PhAddListViewGroupItem(ListViewHandle, WINDOW_PROPERTIES_CATEGORY_CLASS, WINDOW_PROPERTIES_INDEX_CLASS_STYLES, L"Styles", NULL); + PhAddListViewGroupItem(ListViewHandle, WINDOW_PROPERTIES_CATEGORY_CLASS, WINDOW_PROPERTIES_INDEX_CLASS_INSTANCE, L"Instance handle", NULL); + PhAddListViewGroupItem(ListViewHandle, WINDOW_PROPERTIES_CATEGORY_CLASS, WINDOW_PROPERTIES_INDEX_CLASS_LARGEICON, L"Large icon handle", NULL); + PhAddListViewGroupItem(ListViewHandle, WINDOW_PROPERTIES_CATEGORY_CLASS, WINDOW_PROPERTIES_INDEX_CLASS_SMALLICON, L"Small icon handle", NULL); + PhAddListViewGroupItem(ListViewHandle, WINDOW_PROPERTIES_CATEGORY_CLASS, WINDOW_PROPERTIES_INDEX_CLASS_CURSOR, L"Cursor handle", NULL); + PhAddListViewGroupItem(ListViewHandle, WINDOW_PROPERTIES_CATEGORY_CLASS, WINDOW_PROPERTIES_INDEX_CLASS_BACKBRUSH, L"Background brush", NULL); + PhAddListViewGroupItem(ListViewHandle, WINDOW_PROPERTIES_CATEGORY_CLASS, WINDOW_PROPERTIES_INDEX_CLASS_MENUNAME, L"Menu name", NULL); + PhAddListViewGroupItem(ListViewHandle, WINDOW_PROPERTIES_CATEGORY_CLASS, WINDOW_PROPERTIES_INDEX_CLASS_WNDPROC, L"Window procedure", NULL); } -INT_PTR CALLBACK WepWindowClassDlgProc( +INT_PTR CALLBACK WepWindowGeneralDlgProc( _In_ HWND hwndDlg, _In_ UINT uMsg, _In_ WPARAM wParam, @@ -1097,25 +818,63 @@ INT_PTR CALLBACK WepWindowClassDlgProc( ) { PWINDOW_PROPERTIES_CONTEXT context; + LPPROPSHEETPAGE propSheetPage; + PPV_PROPPAGECONTEXT propPageContext; - if (!WepPropPageDlgProcHeader(hwndDlg, uMsg, lParam, NULL, &context)) + if (!PvPropPageDlgProcHeader(hwndDlg, uMsg, lParam, &propSheetPage, &propPageContext)) + return FALSE; + + context = (PWINDOW_PROPERTIES_CONTEXT)propPageContext->Context; + + if (!context) return FALSE; switch (uMsg) { case WM_INITDIALOG: { - WepRefreshWindowClassInfo(hwndDlg, context); + HWND listViewHandle = GetDlgItem(hwndDlg, IDC_WINDOWINFO); + + // HACK + HINSTANCE phInstanceHandle = *(HINSTANCE*)WeGetProcedureAddress("PhInstanceHandle"); + SendMessage(GetParent(hwndDlg), WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(phInstanceHandle, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); + SendMessage(GetParent(hwndDlg), WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(phInstanceHandle, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); + PhCenterWindow(GetParent(hwndDlg), context->ParentWindowHandle); + + PhSetListViewStyle(listViewHandle, FALSE, TRUE); + PhSetControlTheme(listViewHandle, L"explorer"); + PhAddListViewColumn(listViewHandle, 0, 0, 0, LVCFMT_LEFT, 180, L"Name"); + PhAddListViewColumn(listViewHandle, 1, 1, 1, LVCFMT_LEFT, 200, L"Value"); + PhSetExtendedListView(listViewHandle); + PhLoadListViewColumnsFromSetting(SETTING_NAME_WINDOWS_PROPERTY_COLUMNS, listViewHandle); + + WepGeneralAddListViewItemGroups(listViewHandle); + WepRefreshWindowGeneralInfo(hwndDlg, listViewHandle, context); + WepRefreshWindowStyles(listViewHandle, context); + WepRefreshWindowClassInfo(hwndDlg, listViewHandle, context); + + if (!!PhGetIntegerSetting(L"EnableThemeSupport")) // TODO: Required for compat (dmex) + PhInitializeWindowTheme(GetParent(hwndDlg), !!PhGetIntegerSetting(L"EnableThemeSupport")); + else + PhInitializeWindowTheme(hwndDlg, FALSE); } break; - case WM_COMMAND: + case WM_DESTROY: { - switch (GET_WM_COMMAND_ID(wParam, lParam)) + PhSaveListViewColumnsToSetting(SETTING_NAME_WINDOWS_PROPERTY_COLUMNS, GetDlgItem(hwndDlg, IDC_WINDOWINFO)); + } + break; + case WM_SHOWWINDOW: + { + if (!propPageContext->LayoutInitialized) { - case IDC_REFRESH: - PhClearReference(&context->ClassWndProcSymbol); - WepRefreshWindowClassInfo(hwndDlg, context); - break; + PPH_LAYOUT_ITEM dialogItem; + + dialogItem = PvAddPropPageLayoutItem(hwndDlg, hwndDlg, PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL); + PvAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_WINDOWINFO), dialogItem, PH_ANCHOR_ALL); + PvDoPropPageLayout(hwndDlg); + + propPageContext->LayoutInitialized = TRUE; } } break; @@ -1123,18 +882,51 @@ INT_PTR CALLBACK WepWindowClassDlgProc( { PSYMBOL_RESOLVE_CONTEXT resolveContext = (PSYMBOL_RESOLVE_CONTEXT)lParam; - PhAcquireQueuedLockExclusive(&context->ResolveListLock); - RemoveEntryList(&resolveContext->ListEntry); - PhReleaseQueuedLockExclusive(&context->ResolveListLock); + if (resolveContext->Id == 1) + { + PhAcquireQueuedLockExclusive(&context->ResolveListLock); + RemoveEntryList(&resolveContext->ListEntry); + PhReleaseQueuedLockExclusive(&context->ResolveListLock); + + if (resolveContext->ResolveLevel != PhsrlModule && resolveContext->ResolveLevel != PhsrlFunction) + PhClearReference(&resolveContext->Symbol); - if (resolveContext->ResolveLevel != PhsrlModule && resolveContext->ResolveLevel != PhsrlFunction) - PhClearReference(&resolveContext->Symbol); + PhMoveReference(&context->WndProcSymbol, resolveContext->Symbol); + PhFree(resolveContext); - PhMoveReference(&context->ClassWndProcSymbol, resolveContext->Symbol); - PhFree(resolveContext); + context->WndProcResolving--; + } + else if (resolveContext->Id == 2) + { + PhAcquireQueuedLockExclusive(&context->ResolveListLock); + RemoveEntryList(&resolveContext->ListEntry); + PhReleaseQueuedLockExclusive(&context->ResolveListLock); + + if (resolveContext->ResolveLevel != PhsrlModule && resolveContext->ResolveLevel != PhsrlFunction) + PhClearReference(&resolveContext->Symbol); - context->ClassWndProcResolving--; - WepRefreshWindowClassInfoSymbols(hwndDlg, context); + PhMoveReference(&context->DlgProcSymbol, resolveContext->Symbol); + PhFree(resolveContext); + + context->DlgProcResolving--; + } + else if (resolveContext->Id == 3) + { + PhAcquireQueuedLockExclusive(&context->ResolveListLock); + RemoveEntryList(&resolveContext->ListEntry); + PhReleaseQueuedLockExclusive(&context->ResolveListLock); + + if (resolveContext->ResolveLevel != PhsrlModule && resolveContext->ResolveLevel != PhsrlFunction) + PhClearReference(&resolveContext->Symbol); + + PhMoveReference(&context->ClassWndProcSymbol, resolveContext->Symbol); + PhFree(resolveContext); + + context->ClassWndProcResolving--; + } + + WepRefreshWindowGeneralInfoSymbols(GetDlgItem(hwndDlg, IDC_WINDOWINFO), context); + WepRefreshWindowClassInfoSymbols(GetDlgItem(hwndDlg, IDC_WINDOWINFO), context); } break; } @@ -1142,7 +934,7 @@ INT_PTR CALLBACK WepWindowClassDlgProc( return FALSE; } -static BOOL CALLBACK EnumPropsExCallback( +BOOL CALLBACK EnumPropsExCallback( _In_ HWND hwnd, _In_ LPTSTR lpszString, _In_ HANDLE hData, @@ -1169,7 +961,7 @@ static BOOL CALLBACK EnumPropsExCallback( return TRUE; } -static VOID WepRefreshWindowProps( +VOID WepRefreshWindowProps( _In_ HWND hwndDlg, _In_ HWND ListViewHandle, _In_ PWINDOW_PROPERTIES_CONTEXT Context @@ -1190,8 +982,15 @@ INT_PTR CALLBACK WepWindowPropertiesDlgProc( ) { PWINDOW_PROPERTIES_CONTEXT context; + LPPROPSHEETPAGE propSheetPage; + PPV_PROPPAGECONTEXT propPageContext; - if (!WepPropPageDlgProcHeader(hwndDlg, uMsg, lParam, NULL, &context)) + if (!PvPropPageDlgProcHeader(hwndDlg, uMsg, lParam, &propSheetPage, &propPageContext)) + return FALSE; + + context = (PWINDOW_PROPERTIES_CONTEXT)propPageContext->Context; + + if (!context) return FALSE; switch (uMsg) @@ -1207,8 +1006,16 @@ INT_PTR CALLBACK WepWindowPropertiesDlgProc( PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 160, L"Name"); PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 100, L"Value"); PhSetExtendedListView(lvHandle); + PhLoadListViewColumnsFromSetting(SETTING_NAME_WINDOWS_PROPLIST_COLUMNS, lvHandle); WepRefreshWindowProps(hwndDlg, lvHandle, context); + + PhInitializeWindowTheme(hwndDlg, !!PhGetIntegerSetting(L"EnableThemeSupport")); + } + break; + case WM_DESTROY: + { + PhSaveListViewColumnsToSetting(SETTING_NAME_WINDOWS_PROPLIST_COLUMNS, GetDlgItem(hwndDlg, IDC_LIST)); } break; case WM_COMMAND: @@ -1221,6 +1028,169 @@ INT_PTR CALLBACK WepWindowPropertiesDlgProc( } } break; + case WM_SHOWWINDOW: + { + if (!propPageContext->LayoutInitialized) + { + PPH_LAYOUT_ITEM dialogItem; + + dialogItem = PvAddPropPageLayoutItem(hwndDlg, hwndDlg, PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL); + PvAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_LIST), dialogItem, PH_ANCHOR_ALL); + PvDoPropPageLayout(hwndDlg); + + propPageContext->LayoutInitialized = TRUE; + } + } + break; + } + + return FALSE; +} + + +#pragma comment(lib, "propsys.lib") +#include +#include +#include +//#include // remove + +INT_PTR CALLBACK WepWindowPropStoreDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + PWINDOW_PROPERTIES_CONTEXT context; + LPPROPSHEETPAGE propSheetPage; + PPV_PROPPAGECONTEXT propPageContext; + + if (!PvPropPageDlgProcHeader(hwndDlg, uMsg, lParam, &propSheetPage, &propPageContext)) + return FALSE; + + context = (PWINDOW_PROPERTIES_CONTEXT)propPageContext->Context; + + if (!context) + return FALSE; + + switch (uMsg) + { + case WM_INITDIALOG: + { + HWND lvHandle; + + lvHandle = GetDlgItem(hwndDlg, IDC_LIST); + PhSetListViewStyle(lvHandle, FALSE, TRUE); + PhSetControlTheme(lvHandle, L"explorer"); + + PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 160, L"Name"); + PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 100, L"Value"); + PhSetExtendedListView(lvHandle); + PhLoadListViewColumnsFromSetting(SETTING_NAME_WINDOWS_PROPSTORAGE_COLUMNS, lvHandle); + + { + IPropertyStore *propstore; + ULONG count; + ULONG i; + + if (SUCCEEDED(SHGetPropertyStoreForWindow(context->WindowHandle, &IID_IPropertyStore, &propstore))) + { + if (SUCCEEDED(IPropertyStore_GetCount(propstore, &count))) + { + for (i = 0; i < count; i++) + { + PROPERTYKEY propkey; + + if (SUCCEEDED(IPropertyStore_GetAt(propstore, i, &propkey))) + { + INT lvItemIndex; + PROPVARIANT propKeyVariant = { 0 }; + PWSTR propKeyName; + WCHAR propKeyString[PKEYSTR_MAX]; + + if (SUCCEEDED(PSGetNameFromPropertyKey(&propkey, &propKeyName))) + { + lvItemIndex = PhAddListViewItem(lvHandle, MAXINT, propKeyName, NULL); + CoTaskMemFree(propKeyName); + } + else + { + lvItemIndex = PhAddListViewItem(lvHandle, MAXINT, L"Unknown", NULL); + } + + if (SUCCEEDED(PSStringFromPropertyKey(&propkey, propKeyString, RTL_NUMBER_OF(propKeyString)))) + { + //PhSetListViewSubItem(lvHandle, lvItemIndex, 1, propKeyString); + } + + if (SUCCEEDED(IPropertyStore_GetValue(propstore, &propkey, &propKeyVariant))) + { + if (SUCCEEDED(PSFormatForDisplayAlloc(&propkey, &propKeyVariant, PDFF_DEFAULT, &propKeyName))) + { + PhSetListViewSubItem(lvHandle, lvItemIndex, 1, propKeyName); + CoTaskMemFree(propKeyName); + } + + //if (SUCCEEDED(PropVariantToStringAlloc(&propKeyVariant, &propKeyName))) + //{ + // PhSetListViewSubItem(lvHandle, lvItemIndex, 1, propKeyName); + // CoTaskMemFree(propKeyName); + //} + + PropVariantClear(&propKeyVariant); + } + + + // IPropertyDescription *propstoreDesc; + //if (SUCCEEDED(PSGetPropertyDescription(&propkey, &IID_IPropertyDescription, &propstoreDesc))) + //{ + // if (SUCCEEDED(IPropertyDescription_GetCanonicalName(propstoreDesc, &propKeyName))) + // { + // CoTaskMemFree(propKeyName); + // } + // + // IPropertyDescription_Release(propstoreDesc); + //} + } + } + } + + IPropertyStore_Release(propstore); + } + } + + PhInitializeWindowTheme(hwndDlg, !!PhGetIntegerSetting(L"EnableThemeSupport")); + } + break; + case WM_DESTROY: + { + PhSaveListViewColumnsToSetting(SETTING_NAME_WINDOWS_PROPSTORAGE_COLUMNS, GetDlgItem(hwndDlg, IDC_LIST)); + } + break; + case WM_COMMAND: + { + switch (GET_WM_COMMAND_ID(wParam, lParam)) + { + case IDC_REFRESH: + //WepRefreshWindowProps(hwndDlg, GetDlgItem(hwndDlg, IDC_LIST), context); + break; + } + } + break; + case WM_SHOWWINDOW: + { + if (!propPageContext->LayoutInitialized) + { + PPH_LAYOUT_ITEM dialogItem; + + dialogItem = PvAddPropPageLayoutItem(hwndDlg, hwndDlg, PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL); + PvAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_LIST), dialogItem, PH_ANCHOR_ALL); + PvDoPropPageLayout(hwndDlg); + + propPageContext->LayoutInitialized = TRUE; + } + } + break; } return FALSE; diff --git a/plugins/WindowExplorer/wndtree.c b/plugins/WindowExplorer/wndtree.c index fd51694e9107..e8e7834da237 100644 --- a/plugins/WindowExplorer/wndtree.c +++ b/plugins/WindowExplorer/wndtree.c @@ -3,6 +3,7 @@ * window treelist * * Copyright (C) 2011 wj32 + * Copyright (C) 2017-2018 dmex * * This file is part of Process Hacker. * @@ -115,6 +116,12 @@ BOOLEAN WeWindowTreeFilterCallback( return TRUE; } + if (!PhIsNullOrEmptyString(windowNode->ModuleString)) + { + if (WordMatchStringRef(context, &windowNode->ModuleString->sr)) + return TRUE; + } + return FALSE; } @@ -149,6 +156,7 @@ VOID WeInitializeWindowTree( PhAddTreeNewColumn(hwnd, WEWNTLC_HANDLE, TRUE, L"Handle", 70, PH_ALIGN_LEFT, 1, 0); PhAddTreeNewColumn(hwnd, WEWNTLC_TEXT, TRUE, L"Text", 220, PH_ALIGN_LEFT, 2, 0); PhAddTreeNewColumn(hwnd, WEWNTLC_THREAD, TRUE, L"Thread", 150, PH_ALIGN_LEFT, 3, 0); + PhAddTreeNewColumn(hwnd, WEWNTLC_MODULE, TRUE, L"Module", 150, PH_ALIGN_LEFT, 4, 0); TreeNew_SetTriState(hwnd, TRUE); TreeNew_SetSort(hwnd, WEWNTLC_CLASS, NoSortOrder); @@ -286,8 +294,8 @@ VOID WepDestroyWindowNode( PhDereferenceObject(WindowNode->Children); if (WindowNode->WindowText) PhDereferenceObject(WindowNode->WindowText); - if (WindowNode->ThreadString) PhDereferenceObject(WindowNode->ThreadString); + if (WindowNode->ModuleString) PhDereferenceObject(WindowNode->ModuleString); PhFree(WindowNode); } @@ -335,6 +343,12 @@ BEGIN_SORT_FUNCTION(Thread) } END_SORT_FUNCTION +BEGIN_SORT_FUNCTION(Module) +{ + sortResult = PhCompareString(node1->ModuleString, node2->ModuleString, TRUE); +} +END_SORT_FUNCTION + BOOLEAN NTAPI WepWindowTreeNewCallback( _In_ HWND hwnd, _In_ PH_TREENEW_MESSAGE Message, @@ -378,7 +392,8 @@ BOOLEAN NTAPI WepWindowTreeNewCallback( SORT_FUNCTION(Class), SORT_FUNCTION(Handle), SORT_FUNCTION(Text), - SORT_FUNCTION(Thread) + SORT_FUNCTION(Thread), + SORT_FUNCTION(Module) }; int (__cdecl *sortFunction)(void *, const void *, const void *); @@ -433,6 +448,9 @@ BOOLEAN NTAPI WepWindowTreeNewCallback( node->ThreadString = PhGetClientIdName(&node->ClientId); getCellText->Text = PhGetStringRef(node->ThreadString); break; + case WEWNTLC_MODULE: + getCellText->Text = PhGetStringRef(node->ModuleString); + break; default: return FALSE; } @@ -484,6 +502,22 @@ BOOLEAN NTAPI WepWindowTreeNewCallback( SendMessage(context->ParentWindowHandle, WM_COMMAND, ID_SHOWCONTEXTMENU, (LPARAM)contextMenuEvent); } return TRUE; + case TreeNewHeaderRightClick: + { + PH_TN_COLUMN_MENU_DATA data; + + data.TreeNewHandle = hwnd; + data.MouseEvent = Parameter1; + data.DefaultSortColumn = 0; + data.DefaultSortOrder = AscendingSortOrder; + PhInitializeTreeNewColumnMenu(&data); + + data.Selection = PhShowEMenu(data.Menu, hwnd, PH_EMENU_SHOW_LEFTRIGHT, + PH_ALIGN_LEFT | PH_ALIGN_TOP, data.MouseEvent->ScreenLocation.x, data.MouseEvent->ScreenLocation.y); + PhHandleTreeNewColumnMenu(&data); + PhDeleteTreeNewColumnMenu(&data); + } + return TRUE; } return FALSE; diff --git a/plugins/WindowExplorer/wndtree.h b/plugins/WindowExplorer/wndtree.h index e1d3882174f6..d3b418037e2d 100644 --- a/plugins/WindowExplorer/wndtree.h +++ b/plugins/WindowExplorer/wndtree.h @@ -5,7 +5,8 @@ #define WEWNTLC_HANDLE 1 #define WEWNTLC_TEXT 2 #define WEWNTLC_THREAD 3 -#define WEWNTLC_MAXIMUM 4 +#define WEWNTLC_MODULE 4 +#define WEWNTLC_MAXIMUM 5 typedef struct _WE_WINDOW_NODE { @@ -34,6 +35,7 @@ typedef struct _WE_WINDOW_NODE WCHAR WindowHandleString[PH_PTR_STR_LEN_1]; PPH_STRING ThreadString; + PPH_STRING ModuleString; } WE_WINDOW_NODE, *PWE_WINDOW_NODE; typedef struct _WE_WINDOW_TREE_CONTEXT From 52985c1c86f275cedfab0736c2ae1e5b637805b1 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 25 Oct 2018 00:00:23 +1100 Subject: [PATCH 1442/2058] peview: Remove unused code --- tools/peview/peview.rc | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/tools/peview/peview.rc b/tools/peview/peview.rc index 8efb020f33f0..475a44b658f9 100644 --- a/tools/peview/peview.rc +++ b/tools/peview/peview.rc @@ -223,10 +223,8 @@ BEGIN EDITTEXT IDC_FLAGS,76,19,217,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER LTEXT "Version String:",IDC_STATIC,7,31,48,8 LTEXT "Static",IDC_VERSIONSTRING,78,31,215,8 - CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,67,286,206 - LTEXT "Sections:",IDC_STATIC,7,57,30,8 - LTEXT "Guid:",IDC_STATIC,7,43,18,8 - EDITTEXT IDC_GUIDSTRING,76,43,217,13,ES_MULTILINE | ES_READONLY | NOT WS_BORDER + CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,57,286,216 + LTEXT "Sections:",IDC_STATIC,7,47,30,8 END IDD_PELOADCONFIG DIALOGEX 0, 0, 300, 280 From 0551c48fc3057cbc4a5ce64d6b2198f02c7617d3 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 25 Oct 2018 00:10:39 +1100 Subject: [PATCH 1443/2058] WindowExplorer: Fix missing imports, Update DelayLoadDLLs --- plugins/WindowExplorer/WindowExplorer.vcxproj | 12 +- plugins/WindowExplorer/wndprp.c | 157 ++++++++---------- 2 files changed, 80 insertions(+), 89 deletions(-) diff --git a/plugins/WindowExplorer/WindowExplorer.vcxproj b/plugins/WindowExplorer/WindowExplorer.vcxproj index 0fb65dfd0d0a..4744654723c0 100644 --- a/plugins/WindowExplorer/WindowExplorer.vcxproj +++ b/plugins/WindowExplorer/WindowExplorer.vcxproj @@ -53,22 +53,26 @@ - gdi32.dll;ProcessHacker.exe;user32.dll;%(DelayLoadDLLs) + comctl32.dll;gdi32.dll;ole32.dll;ProcessHacker.exe;propsys.dll;shell32.dll;user32.dll;%(DelayLoadDLLs) + ProcessHacker.lib;ntdll.lib;propsys.lib;%(AdditionalDependencies) - comctl32.dll;gdi32.dll;ProcessHacker.exe;user32.dll;%(DelayLoadDLLs) + comctl32.dll;gdi32.dll;ole32.dll;ProcessHacker.exe;propsys.dll;shell32.dll;user32.dll;%(DelayLoadDLLs) + ProcessHacker.lib;ntdll.lib;propsys.lib;%(AdditionalDependencies) - gdi32.dll;ProcessHacker.exe;user32.dll;%(DelayLoadDLLs) + comctl32.dll;gdi32.dll;ole32.dll;ProcessHacker.exe;propsys.dll;shell32.dll;user32.dll;%(DelayLoadDLLs) + ProcessHacker.lib;ntdll.lib;propsys.lib;%(AdditionalDependencies) - gdi32.dll;ProcessHacker.exe;user32.dll;%(DelayLoadDLLs) + comctl32.dll;gdi32.dll;ole32.dll;ProcessHacker.exe;propsys.dll;shell32.dll;user32.dll;%(DelayLoadDLLs) + ProcessHacker.lib;ntdll.lib;propsys.lib;%(AdditionalDependencies) diff --git a/plugins/WindowExplorer/wndprp.c b/plugins/WindowExplorer/wndprp.c index c19624f86e60..7c3c2124edb3 100644 --- a/plugins/WindowExplorer/wndprp.c +++ b/plugins/WindowExplorer/wndprp.c @@ -26,6 +26,10 @@ #include #include +#include +#include +#include + #define WEM_RESOLVE_DONE (WM_APP + 1234) typedef struct _WINDOW_PROPERTIES_CONTEXT @@ -1047,12 +1051,74 @@ INT_PTR CALLBACK WepWindowPropertiesDlgProc( return FALSE; } +VOID WepRefreshWindowPropertyStorage( + _In_ HWND hwndDlg, + _In_ HWND ListViewHandle, + _In_ PWINDOW_PROPERTIES_CONTEXT Context + ) +{ + IPropertyStore *propstore; + ULONG count; + ULONG i; + + ExtendedListView_SetRedraw(ListViewHandle, FALSE); + ListView_DeleteAllItems(ListViewHandle); -#pragma comment(lib, "propsys.lib") -#include -#include -#include -//#include // remove + if (SUCCEEDED(SHGetPropertyStoreForWindow(Context->WindowHandle, &IID_IPropertyStore, &propstore))) + { + if (SUCCEEDED(IPropertyStore_GetCount(propstore, &count))) + { + for (i = 0; i < count; i++) + { + PROPERTYKEY propkey; + + if (SUCCEEDED(IPropertyStore_GetAt(propstore, i, &propkey))) + { + INT lvItemIndex; + PROPVARIANT propKeyVariant = { 0 }; + PWSTR propKeyName; + + if (SUCCEEDED(PSGetNameFromPropertyKey(&propkey, &propKeyName))) + { + lvItemIndex = PhAddListViewItem(ListViewHandle, MAXINT, propKeyName, NULL); + CoTaskMemFree(propKeyName); + } + else + { + WCHAR propKeyString[PKEYSTR_MAX]; + + if (SUCCEEDED(PSStringFromPropertyKey(&propkey, propKeyString, RTL_NUMBER_OF(propKeyString)))) + lvItemIndex = PhAddListViewItem(ListViewHandle, MAXINT, propKeyString, NULL); + else + lvItemIndex = PhAddListViewItem(ListViewHandle, MAXINT, L"Unknown", NULL); + } + + if (SUCCEEDED(IPropertyStore_GetValue(propstore, &propkey, &propKeyVariant))) + { + if (SUCCEEDED(PSFormatForDisplayAlloc(&propkey, &propKeyVariant, PDFF_DEFAULT, &propKeyName))) + { + PhSetListViewSubItem(ListViewHandle, lvItemIndex, 1, propKeyName); + CoTaskMemFree(propKeyName); + } + + //if (SUCCEEDED(PropVariantToStringAlloc(&propKeyVariant, &propKeyName))) + //{ + // PhSetListViewSubItem(ListViewHandle, lvItemIndex, 1, propKeyName); + // CoTaskMemFree(propKeyName); + //} + + PropVariantClear(&propKeyVariant); + } + } + } + } + + IPropertyStore_Release(propstore); + } + + ExtendedListView_SortItems(ListViewHandle); + ExtendedListView_SetRedraw(ListViewHandle, TRUE); +} INT_PTR CALLBACK WepWindowPropStoreDlgProc( _In_ HWND hwndDlg, @@ -1088,76 +1154,7 @@ INT_PTR CALLBACK WepWindowPropStoreDlgProc( PhSetExtendedListView(lvHandle); PhLoadListViewColumnsFromSetting(SETTING_NAME_WINDOWS_PROPSTORAGE_COLUMNS, lvHandle); - { - IPropertyStore *propstore; - ULONG count; - ULONG i; - - if (SUCCEEDED(SHGetPropertyStoreForWindow(context->WindowHandle, &IID_IPropertyStore, &propstore))) - { - if (SUCCEEDED(IPropertyStore_GetCount(propstore, &count))) - { - for (i = 0; i < count; i++) - { - PROPERTYKEY propkey; - - if (SUCCEEDED(IPropertyStore_GetAt(propstore, i, &propkey))) - { - INT lvItemIndex; - PROPVARIANT propKeyVariant = { 0 }; - PWSTR propKeyName; - WCHAR propKeyString[PKEYSTR_MAX]; - - if (SUCCEEDED(PSGetNameFromPropertyKey(&propkey, &propKeyName))) - { - lvItemIndex = PhAddListViewItem(lvHandle, MAXINT, propKeyName, NULL); - CoTaskMemFree(propKeyName); - } - else - { - lvItemIndex = PhAddListViewItem(lvHandle, MAXINT, L"Unknown", NULL); - } - - if (SUCCEEDED(PSStringFromPropertyKey(&propkey, propKeyString, RTL_NUMBER_OF(propKeyString)))) - { - //PhSetListViewSubItem(lvHandle, lvItemIndex, 1, propKeyString); - } - - if (SUCCEEDED(IPropertyStore_GetValue(propstore, &propkey, &propKeyVariant))) - { - if (SUCCEEDED(PSFormatForDisplayAlloc(&propkey, &propKeyVariant, PDFF_DEFAULT, &propKeyName))) - { - PhSetListViewSubItem(lvHandle, lvItemIndex, 1, propKeyName); - CoTaskMemFree(propKeyName); - } - - //if (SUCCEEDED(PropVariantToStringAlloc(&propKeyVariant, &propKeyName))) - //{ - // PhSetListViewSubItem(lvHandle, lvItemIndex, 1, propKeyName); - // CoTaskMemFree(propKeyName); - //} - - PropVariantClear(&propKeyVariant); - } - - - // IPropertyDescription *propstoreDesc; - //if (SUCCEEDED(PSGetPropertyDescription(&propkey, &IID_IPropertyDescription, &propstoreDesc))) - //{ - // if (SUCCEEDED(IPropertyDescription_GetCanonicalName(propstoreDesc, &propKeyName))) - // { - // CoTaskMemFree(propKeyName); - // } - // - // IPropertyDescription_Release(propstoreDesc); - //} - } - } - } - - IPropertyStore_Release(propstore); - } - } + WepRefreshWindowPropertyStorage(hwndDlg, lvHandle, context); PhInitializeWindowTheme(hwndDlg, !!PhGetIntegerSetting(L"EnableThemeSupport")); } @@ -1167,16 +1164,6 @@ INT_PTR CALLBACK WepWindowPropStoreDlgProc( PhSaveListViewColumnsToSetting(SETTING_NAME_WINDOWS_PROPSTORAGE_COLUMNS, GetDlgItem(hwndDlg, IDC_LIST)); } break; - case WM_COMMAND: - { - switch (GET_WM_COMMAND_ID(wParam, lParam)) - { - case IDC_REFRESH: - //WepRefreshWindowProps(hwndDlg, GetDlgItem(hwndDlg, IDC_LIST), context); - break; - } - } - break; case WM_SHOWWINDOW: { if (!propPageContext->LayoutInitialized) From 52350c1b99a3b1af3428948f1a321190ccef5701 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 25 Oct 2018 00:25:25 +1100 Subject: [PATCH 1444/2058] peview: Fix missing tab text, Update propstore enumeration flags --- tools/peview/peview.rc | 6 ++++-- tools/peview/propstore.c | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/tools/peview/peview.rc b/tools/peview/peview.rc index 475a44b658f9..458b0aef4899 100644 --- a/tools/peview/peview.rc +++ b/tools/peview/peview.rc @@ -158,7 +158,8 @@ END // IDD_PEGENERAL DIALOGEX 0, 0, 300, 280 -STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "General" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN LTEXT "Target machine:",IDC_STATIC,7,57,53,8 @@ -228,7 +229,8 @@ BEGIN END IDD_PELOADCONFIG DIALOGEX 0, 0, 300, 280 -STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Load config" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,3,3,294,274 diff --git a/tools/peview/propstore.c b/tools/peview/propstore.c index 828f6605ec7a..8cabc7d033c1 100644 --- a/tools/peview/propstore.c +++ b/tools/peview/propstore.c @@ -33,7 +33,7 @@ VOID PvpPeEnumerateFilePropStore( if (SUCCEEDED(SHGetPropertyStoreFromParsingName( PvFileName->Buffer, NULL, - GPS_DEFAULT, + GPS_DEFAULT | GPS_EXTRINSICPROPERTIES | GPS_VOLATILEPROPERTIES, &IID_IPropertyStore, &propstore ))) From a8a5b3d9979d3d96fd203a17469313ec149e7a8d Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 25 Oct 2018 11:13:41 +1100 Subject: [PATCH 1445/2058] peview: Add file stream information, Fix listview indexes --- tools/peview/exlfexports.c | 2 +- tools/peview/exlfprp.c | 10 ++- tools/peview/include/peview.h | 7 ++ tools/peview/peprp.c | 10 +++ tools/peview/peview.rc | 16 ++++ tools/peview/peview.vcxproj | 3 +- tools/peview/peview.vcxproj.filters | 7 +- tools/peview/propstore.c | 2 +- tools/peview/resource.h | 1 + tools/peview/settings.c | 1 + tools/peview/{eaprp.c => streams.c} | 114 +++++++++++++--------------- 11 files changed, 106 insertions(+), 67 deletions(-) rename tools/peview/{eaprp.c => streams.c} (56%) diff --git a/tools/peview/exlfexports.c b/tools/peview/exlfexports.c index fda3971a57f0..36d65bd21539 100644 --- a/tools/peview/exlfexports.c +++ b/tools/peview/exlfexports.c @@ -41,7 +41,7 @@ VOID PvpProcessElfExports( if (!export->ExportSymbol) continue; - PhPrintUInt64(number, ++count); + PhPrintUInt32(number, ++count); lvItemIndex = PhAddListViewItem(ListViewHandle, MAXINT, number, NULL); PhPrintPointer(pointer, (PVOID)export->Address); diff --git a/tools/peview/exlfprp.c b/tools/peview/exlfprp.c index 14d62b6af5a8..40680502a4ca 100644 --- a/tools/peview/exlfprp.c +++ b/tools/peview/exlfprp.c @@ -119,7 +119,15 @@ VOID PvExlfProperties( NULL ); PvAddPropPage(propContext, newPage); - + + // Streams page + newPage = PvCreatePropPageContext( + MAKEINTRESOURCE(IDD_PESTREAMS), + PvpPeStreamsDlgProc, + NULL + ); + PvAddPropPage(propContext, newPage); + PhModalPropertySheet(&propContext->PropSheetHeader); PhDereferenceObject(propContext); diff --git a/tools/peview/include/peview.h b/tools/peview/include/peview.h index dd9129373a9b..53277e2eafb2 100644 --- a/tools/peview/include/peview.h +++ b/tools/peview/include/peview.h @@ -343,6 +343,13 @@ INT_PTR CALLBACK PvpPeExtendedAttributesDlgProc( _In_ LPARAM lParam ); +INT_PTR CALLBACK PvpPeStreamsDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + // ELF PWSTR PvpGetSymbolTypeName( diff --git a/tools/peview/peprp.c b/tools/peview/peprp.c index a25580571440..4f69c27024f8 100644 --- a/tools/peview/peprp.c +++ b/tools/peview/peprp.c @@ -198,6 +198,16 @@ VOID PvPeProperties( PvAddPropPage(propContext, newPage); } + // Streams page + { + newPage = PvCreatePropPageContext( + MAKEINTRESOURCE(IDD_PESTREAMS), + PvpPeStreamsDlgProc, + NULL + ); + PvAddPropPage(propContext, newPage); + } + // Symbols page if (NT_SUCCESS(PhGetMappedImageDataEntry(&PvMappedImage, IMAGE_DIRECTORY_ENTRY_DEBUG, &entry)) && entry->VirtualAddress) { diff --git a/tools/peview/peview.rc b/tools/peview/peview.rc index 458b0aef4899..2d918540ed14 100644 --- a/tools/peview/peview.rc +++ b/tools/peview/peview.rc @@ -148,6 +148,14 @@ BEGIN TOPMARGIN, 3 BOTTOMMARGIN, 277 END + + IDD_PESTREAMS, DIALOG + BEGIN + LEFTMARGIN, 3 + RIGHTMARGIN, 297 + TOPMARGIN, 3 + BOTTOMMARGIN, 277 + END END #endif // APSTUDIO_INVOKED @@ -294,6 +302,14 @@ BEGIN CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,3,3,294,274 END +IDD_PESTREAMS DIALOGEX 0, 0, 300, 280 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Streams" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,3,3,294,274 +END + ///////////////////////////////////////////////////////////////////////////// // diff --git a/tools/peview/peview.vcxproj b/tools/peview/peview.vcxproj index a8c2cd2738e4..7a93c1ab5dd0 100644 --- a/tools/peview/peview.vcxproj +++ b/tools/peview/peview.vcxproj @@ -222,7 +222,7 @@ - + @@ -240,6 +240,7 @@ + diff --git a/tools/peview/peview.vcxproj.filters b/tools/peview/peview.vcxproj.filters index b2364f637c3c..ab6017350727 100644 --- a/tools/peview/peview.vcxproj.filters +++ b/tools/peview/peview.vcxproj.filters @@ -81,10 +81,13 @@ Source Files\Pages\Linux - + Source Files\Pages - + + Source Files\Pages + + Source Files\Pages diff --git a/tools/peview/propstore.c b/tools/peview/propstore.c index 8cabc7d033c1..b187226bd561 100644 --- a/tools/peview/propstore.c +++ b/tools/peview/propstore.c @@ -51,7 +51,7 @@ VOID PvpPeEnumerateFilePropStore( PWSTR propKeyName; WCHAR number[PH_INT32_STR_LEN_1]; - PhPrintUInt32(number, i); + PhPrintUInt32(number, i + 1); lvItemIndex = PhAddListViewItem(ListViewHandle, MAXINT, number, NULL); if (SUCCEEDED(PSGetNameFromPropertyKey(&propkey, &propKeyName))) diff --git a/tools/peview/resource.h b/tools/peview/resource.h index 439cb4bafb0c..5d9e91897c41 100644 --- a/tools/peview/resource.h +++ b/tools/peview/resource.h @@ -18,6 +18,7 @@ #define IDB_SEARCH_ACTIVE_BMP 112 #define IDD_PEATTR 112 #define IDB_SEARCH_INACTIVE_BMP 113 +#define IDD_PESTREAMS 113 #define IDC_SYMBOLTREE 119 #define IDC_TARGETMACHINE 1003 #define IDC_CHECKSUM 1004 diff --git a/tools/peview/settings.c b/tools/peview/settings.c index a3504728dae9..a1e3fb706567 100644 --- a/tools/peview/settings.c +++ b/tools/peview/settings.c @@ -46,6 +46,7 @@ VOID PhAddDefaultSettings( PhpAddStringSetting(L"ImageResourcesListViewColumns", L""); PhpAddStringSetting(L"ImageAttributesListViewColumns", L""); PhpAddStringSetting(L"ImagePropertiesListViewColumns", L""); + PhpAddStringSetting(L"ImageStreamsListViewColumns", L""); PhpAddStringSetting(L"LibListViewColumns", L""); PhpAddStringSetting(L"PdbTreeListColumns", L""); diff --git a/tools/peview/eaprp.c b/tools/peview/streams.c similarity index 56% rename from tools/peview/eaprp.c rename to tools/peview/streams.c index 837f138ad0d9..3f0234b85349 100644 --- a/tools/peview/eaprp.c +++ b/tools/peview/streams.c @@ -22,47 +22,57 @@ #include -typedef struct _PV_EA_CALLBACK -{ - HWND ListViewHandle; - ULONG Count; -} PV_EA_CALLBACK, *PPV_EA_CALLBACK; - -BOOLEAN NTAPI PvpEnumFileAttributesCallback( - _In_ PFILE_FULL_EA_INFORMATION Information, - _In_opt_ PVOID Context +VOID PvpPeEnumerateFileStreams( + _In_ HWND ListViewHandle ) { - PPV_EA_CALLBACK context = Context; - PPH_STRING attributeName; - INT lvItemIndex; - WCHAR number[PH_INT32_STR_LEN_1]; - - PhPrintUInt32(number, context->Count); - lvItemIndex = PhAddListViewItem(context->ListViewHandle, MAXINT, number, NULL); - - attributeName = PhZeroExtendToUtf16(Information->EaName); - PhSetListViewSubItem( - context->ListViewHandle, - lvItemIndex, - 1, - attributeName->Buffer - ); - PhDereferenceObject(attributeName); - - PhSetListViewSubItem( - context->ListViewHandle, - lvItemIndex, - 2, - PhaFormatSize(Information->EaValueLength, ULONG_MAX)->Buffer - ); - - context->Count++; - - return TRUE; + HANDLE fileHandle; + + if (NT_SUCCESS(PhCreateFileWin32( + &fileHandle, + PhGetString(PvFileName), + FILE_READ_ATTRIBUTES | FILE_READ_DATA | SYNCHRONIZE, + FILE_ATTRIBUTE_NORMAL, + FILE_SHARE_READ, + FILE_OPEN, + FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT + ))) + { + ULONG count = 0; + PVOID buffer; + PFILE_STREAM_INFORMATION i; + + if (NT_SUCCESS(PhEnumFileStreams(fileHandle, &buffer))) + { + for (i = PH_FIRST_STREAM(buffer); i; i = PH_NEXT_STREAM(i)) + { + INT lvItemIndex; + PPH_STRING attributeName; + WCHAR number[PH_INT32_STR_LEN_1]; + + PhPrintUInt32(number, ++count); + lvItemIndex = PhAddListViewItem(ListViewHandle, MAXINT, number, NULL); + + attributeName = PhCreateStringEx(i->StreamName, i->StreamNameLength); + PhSetListViewSubItem(ListViewHandle, lvItemIndex, 1, attributeName->Buffer); + PhDereferenceObject(attributeName); + + PhSetListViewSubItem( + ListViewHandle, + lvItemIndex, + 2, + PhaFormatSize(i->StreamSize.QuadPart, ULONG_MAX)->Buffer + ); + } + + PhFree(buffer); + } + + NtClose(fileHandle); + } } -INT_PTR CALLBACK PvpPeExtendedAttributesDlgProc( +INT_PTR CALLBACK PvpPeStreamsDlgProc( _In_ HWND hwndDlg, _In_ UINT uMsg, _In_ WPARAM wParam, @@ -79,7 +89,6 @@ INT_PTR CALLBACK PvpPeExtendedAttributesDlgProc( { case WM_INITDIALOG: { - HANDLE fileHandle; HWND lvHandle; lvHandle = GetDlgItem(hwndDlg, IDC_LIST); @@ -87,36 +96,19 @@ INT_PTR CALLBACK PvpPeExtendedAttributesDlgProc( PhSetControlTheme(lvHandle, L"explorer"); PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 40, L"#"); PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 150, L"Name"); - PhAddListViewColumn(lvHandle, 2, 2, 2, LVCFMT_LEFT, 200, L"Value"); + PhAddListViewColumn(lvHandle, 2, 2, 2, LVCFMT_LEFT, 150, L"Size"); PhSetExtendedListView(lvHandle); - PhLoadListViewColumnsFromSetting(L"ImageAttributesListViewColumns", lvHandle); - - if (NT_SUCCESS(PhCreateFileWin32( - &fileHandle, - PhGetString(PvFileName), - FILE_READ_ATTRIBUTES | FILE_READ_DATA | FILE_READ_EA | SYNCHRONIZE, - FILE_ATTRIBUTE_NORMAL, - FILE_SHARE_READ, - FILE_OPEN, - FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT - ))) - { - PV_EA_CALLBACK context; - - context.ListViewHandle = lvHandle; - context.Count = 0; - - PhEnumFileExtendedAttributes(fileHandle, PvpEnumFileAttributesCallback, &context); - - NtClose(lvHandle); - } + PhLoadListViewColumnsFromSetting(L"ImageStreamsListViewColumns", lvHandle); + PvpPeEnumerateFileStreams(lvHandle); + //ExtendedListView_SortItems(lvHandle); + EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); } break; case WM_DESTROY: { - PhSaveListViewColumnsToSetting(L"ImageAttributesListViewColumns", GetDlgItem(hwndDlg, IDC_LIST)); + PhSaveListViewColumnsToSetting(L"ImageStreamsListViewColumns", GetDlgItem(hwndDlg, IDC_LIST)); } break; case WM_SHOWWINDOW: From 903ef7479e0c733b52ebc881c9172b802b07c588 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 25 Oct 2018 11:28:09 +1100 Subject: [PATCH 1446/2058] WindowExplorer: Fix window properties window placement --- plugins/WindowExplorer/prpsh.c | 3 ++- plugins/WindowExplorer/wndprp.c | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/plugins/WindowExplorer/prpsh.c b/plugins/WindowExplorer/prpsh.c index 5115cff2062d..5e972623f6cd 100644 --- a/plugins/WindowExplorer/prpsh.c +++ b/plugins/WindowExplorer/prpsh.c @@ -252,7 +252,8 @@ BOOLEAN PhpInitializePropSheetLayoutStage1( // Set the Cancel button's text to "Close". PhSetDialogItemText(hwnd, IDCANCEL, L"Close"); - PhLoadWindowPlacementFromSetting(SETTING_NAME_WINDOWS_PROPERTY_POSITION, SETTING_NAME_WINDOWS_PROPERTY_SIZE, hwnd); + if (PhGetIntegerPairSetting(SETTING_NAME_WINDOWS_PROPERTY_POSITION).X != 0) // HACK + PhLoadWindowPlacementFromSetting(SETTING_NAME_WINDOWS_PROPERTY_POSITION, SETTING_NAME_WINDOWS_PROPERTY_SIZE, hwnd); PropSheetContext->LayoutInitialized = TRUE; diff --git a/plugins/WindowExplorer/wndprp.c b/plugins/WindowExplorer/wndprp.c index 7c3c2124edb3..6d0f71b85a5a 100644 --- a/plugins/WindowExplorer/wndprp.c +++ b/plugins/WindowExplorer/wndprp.c @@ -843,7 +843,9 @@ INT_PTR CALLBACK WepWindowGeneralDlgProc( HINSTANCE phInstanceHandle = *(HINSTANCE*)WeGetProcedureAddress("PhInstanceHandle"); SendMessage(GetParent(hwndDlg), WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(phInstanceHandle, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); SendMessage(GetParent(hwndDlg), WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(phInstanceHandle, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); - PhCenterWindow(GetParent(hwndDlg), context->ParentWindowHandle); + + if (PhGetIntegerPairSetting(SETTING_NAME_WINDOWS_PROPERTY_POSITION).X == 0) // HACK + PhCenterWindow(GetParent(hwndDlg), context->ParentWindowHandle); PhSetListViewStyle(listViewHandle, FALSE, TRUE); PhSetControlTheme(listViewHandle, L"explorer"); From 2f1d4fcc794cb71036d862aae834c4eaf4cf0f6b Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 25 Oct 2018 11:34:38 +1100 Subject: [PATCH 1447/2058] peview: Add missing file from commit a8a5b3d --- tools/peview/attributes.c | 143 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 143 insertions(+) create mode 100644 tools/peview/attributes.c diff --git a/tools/peview/attributes.c b/tools/peview/attributes.c new file mode 100644 index 000000000000..996545483c37 --- /dev/null +++ b/tools/peview/attributes.c @@ -0,0 +1,143 @@ +/* + * Process Hacker - + * PE viewer + * + * Copyright (C) 2018 dmex + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include + +typedef struct _PV_EA_CALLBACK +{ + HWND ListViewHandle; + ULONG Count; +} PV_EA_CALLBACK, *PPV_EA_CALLBACK; + +BOOLEAN NTAPI PvpEnumFileAttributesCallback( + _In_ PFILE_FULL_EA_INFORMATION Information, + _In_opt_ PVOID Context + ) +{ + PPV_EA_CALLBACK context = Context; + PPH_STRING attributeName; + INT lvItemIndex; + WCHAR number[PH_INT32_STR_LEN_1]; + + PhPrintUInt32(number, ++context->Count); + lvItemIndex = PhAddListViewItem(context->ListViewHandle, MAXINT, number, NULL); + + attributeName = PhZeroExtendToUtf16(Information->EaName); + PhSetListViewSubItem( + context->ListViewHandle, + lvItemIndex, + 1, + attributeName->Buffer + ); + PhDereferenceObject(attributeName); + + PhSetListViewSubItem( + context->ListViewHandle, + lvItemIndex, + 2, + PhaFormatSize(Information->EaValueLength, ULONG_MAX)->Buffer + ); + + return TRUE; +} + +INT_PTR CALLBACK PvpPeExtendedAttributesDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + LPPROPSHEETPAGE propSheetPage; + PPV_PROPPAGECONTEXT propPageContext; + + if (!PvPropPageDlgProcHeader(hwndDlg, uMsg, lParam, &propSheetPage, &propPageContext)) + return FALSE; + + switch (uMsg) + { + case WM_INITDIALOG: + { + HANDLE fileHandle; + HWND lvHandle; + + lvHandle = GetDlgItem(hwndDlg, IDC_LIST); + PhSetListViewStyle(lvHandle, TRUE, TRUE); + PhSetControlTheme(lvHandle, L"explorer"); + PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 40, L"#"); + PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 150, L"Name"); + PhAddListViewColumn(lvHandle, 2, 2, 2, LVCFMT_LEFT, 200, L"Value"); + PhSetExtendedListView(lvHandle); + PhLoadListViewColumnsFromSetting(L"ImageAttributesListViewColumns", lvHandle); + + if (NT_SUCCESS(PhCreateFileWin32( + &fileHandle, + PhGetString(PvFileName), + FILE_READ_ATTRIBUTES | FILE_READ_DATA | FILE_READ_EA | SYNCHRONIZE, + FILE_ATTRIBUTE_NORMAL, + FILE_SHARE_READ, + FILE_OPEN, + FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT + ))) + { + PV_EA_CALLBACK context; + + context.ListViewHandle = lvHandle; + context.Count = 0; + + PhEnumFileExtendedAttributes(fileHandle, PvpEnumFileAttributesCallback, &context); + + NtClose(fileHandle); + } + + EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); + } + break; + case WM_DESTROY: + { + PhSaveListViewColumnsToSetting(L"ImageAttributesListViewColumns", GetDlgItem(hwndDlg, IDC_LIST)); + } + break; + case WM_SHOWWINDOW: + { + if (!propPageContext->LayoutInitialized) + { + PPH_LAYOUT_ITEM dialogItem; + + dialogItem = PvAddPropPageLayoutItem(hwndDlg, hwndDlg, PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL); + PvAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_LIST), dialogItem, PH_ANCHOR_ALL); + + PvDoPropPageLayout(hwndDlg); + + propPageContext->LayoutInitialized = TRUE; + } + } + break; + case WM_NOTIFY: + { + PvHandleListViewNotifyForCopy(lParam, GetDlgItem(hwndDlg, IDC_LIST)); + } + break; + } + + return FALSE; +} From f8e9589233265672a077c904c430b10494d782fb Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 26 Oct 2018 10:03:36 +1100 Subject: [PATCH 1448/2058] Remove unused code --- ProcessHacker/prpghndl.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ProcessHacker/prpghndl.c b/ProcessHacker/prpghndl.c index 90009db99d14..6086e33eb5ae 100644 --- a/ProcessHacker/prpghndl.c +++ b/ProcessHacker/prpghndl.c @@ -265,10 +265,10 @@ BOOLEAN PhpHandleTreeFilterCallback( // HACK: lazy init the etw object type index (dmex) if (PhBeginInitOnce(&initOnce)) { - UNICODE_STRING fileTypeName; + UNICODE_STRING etwTypeName = RTL_CONSTANT_STRING(L"EtwRegistration"); + + eventTraceTypeIndex = PhGetObjectTypeNumber(&etwTypeName); - RtlInitUnicodeString(&fileTypeName, L"EtwRegistration"); - eventTraceTypeIndex = PhGetObjectTypeNumber(&fileTypeName); PhEndInitOnce(&initOnce); } From 83c52fb8da8ebc9c941a1c5aa526d0022e533b74 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 26 Oct 2018 10:06:44 +1100 Subject: [PATCH 1449/2058] CustomSetupTool: Fix resetting kph state after updates --- tools/CustomSetupTool/CustomSetupTool/setup.c | 26 ++++++++++++++++--- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/tools/CustomSetupTool/CustomSetupTool/setup.c b/tools/CustomSetupTool/CustomSetupTool/setup.c index 16a48d216494..85983a568337 100644 --- a/tools/CustomSetupTool/CustomSetupTool/setup.c +++ b/tools/CustomSetupTool/CustomSetupTool/setup.c @@ -458,13 +458,31 @@ BOOLEAN SetupUninstallKph( _In_ PPH_SETUP_CONTEXT Context ) { + PPH_STRING clientPath; + // Query the current KPH installation state. Context->SetupKphInstallRequired = SetupKphCheckInstallState(); // Stop and uninstall the current installation. - if (SetupMode == SETUP_COMMAND_UPDATE) - { - SetupStopService(L"KProcessHacker3", FALSE); + clientPath = PhConcatStrings2(PhGetString(SetupInstallPath), L"\\ProcessHacker.exe"); + + if (RtlDoesFileExists_U(PhGetString(clientPath))) + { + HANDLE processHandle; + + if (PhShellExecuteEx( + NULL, + PhGetString(clientPath), + L"-uninstallkph -s", + SW_NORMAL, + 0, + 0, + &processHandle + )) + { + NtWaitForSingleObject(processHandle, FALSE, NULL); + NtClose(processHandle); + } } else { @@ -851,4 +869,4 @@ VOID SetupCreateImageFileExecutionOptions( NtClose(keyHandle); } } -} \ No newline at end of file +} From e0c6d4263071e0df9093ea6d0abd01a0435b358d Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 26 Oct 2018 10:40:39 +1100 Subject: [PATCH 1450/2058] CustomSetupTool: Fix updating kph from portable install when not elevated --- tools/CustomSetupTool/CustomSetupTool/setup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/CustomSetupTool/CustomSetupTool/setup.c b/tools/CustomSetupTool/CustomSetupTool/setup.c index 85983a568337..7da59e7801db 100644 --- a/tools/CustomSetupTool/CustomSetupTool/setup.c +++ b/tools/CustomSetupTool/CustomSetupTool/setup.c @@ -438,7 +438,7 @@ VOID SetupStartKph( PhGetString(clientPath), L"-installkph -s", SW_NORMAL, - 0, + PhGetOwnTokenAttributes().Elevated ? 0 : PH_SHELL_EXECUTE_ADMIN, 0, &processHandle )) From b9ac3ff7c87efe9ff9b67d25a35804c418e64244 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 26 Oct 2018 11:06:48 +1100 Subject: [PATCH 1451/2058] Updater: Fix updating kph from portable install when not elevated --- plugins/Updater/page5.c | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/plugins/Updater/page5.c b/plugins/Updater/page5.c index 728bc94936ba..92098a29c7bd 100644 --- a/plugins/Updater/page5.c +++ b/plugins/Updater/page5.c @@ -29,6 +29,34 @@ static TASKDIALOG_BUTTON TaskDialogButtonArray[] = { IDYES, L"Install" } }; +BOOLEAN UpdaterCheckKphInstallState( + VOID + ) +{ + static PH_STRINGREF kph3ServiceKeyName = PH_STRINGREF_INIT(L"System\\CurrentControlSet\\Services\\KProcessHacker3"); + BOOLEAN kphInstallRequired = FALSE; + HANDLE runKeyHandle; + + if (NT_SUCCESS(PhOpenKey( + &runKeyHandle, + KEY_READ, + PH_KEY_LOCAL_MACHINE, + &kph3ServiceKeyName, + 0 + ))) + { + // Make sure we re-install the driver when KPH was installed as a service. + if (PhQueryRegistryUlong(runKeyHandle, L"Start") == SERVICE_SYSTEM_START) + { + kphInstallRequired = TRUE; + } + + NtClose(runKeyHandle); + } + + return kphInstallRequired; +} + BOOLEAN UpdaterCheckApplicationDirectory( VOID ) @@ -37,6 +65,9 @@ BOOLEAN UpdaterCheckApplicationDirectory( PPH_STRING directory; PPH_STRING file; + if (UpdaterCheckKphInstallState()) + return FALSE; + directory = PH_AUTO(PhGetApplicationDirectory()); file = PH_AUTO(PhConcatStrings(2, PhGetStringOrEmpty(directory), L"\\processhacker.update")); @@ -283,4 +314,4 @@ VOID ShowUpdateFailedDialog( config.lpCallbackData = (LONG_PTR)Context; SendMessage(Context->DialogHandle, TDM_NAVIGATE_PAGE, 0, (LPARAM)&config); -} \ No newline at end of file +} From 8ade7d949761dcf0feca9b35464bc6399c21e467 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 26 Oct 2018 11:29:15 +1100 Subject: [PATCH 1452/2058] Add PhEnumFileStreamsEx --- phlib/include/phnative.h | 18 ++++++++++++++++-- phlib/native.c | 30 ++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 2 deletions(-) diff --git a/phlib/include/phnative.h b/phlib/include/phnative.h index 67fff5528f50..0c0666ce3271 100644 --- a/phlib/include/phnative.h +++ b/phlib/include/phnative.h @@ -898,8 +898,8 @@ PhEnumFileExtendedAttributes( #define PH_FIRST_STREAM(Streams) ((PFILE_STREAM_INFORMATION)(Streams)) #define PH_NEXT_STREAM(Stream) ( \ ((PFILE_STREAM_INFORMATION)(Stream))->NextEntryOffset ? \ - (PFILE_STREAM_INFORMATION)((PCHAR)(Stream) + \ - ((PFILE_STREAM_INFORMATION)(Stream))->NextEntryOffset) : \ + (PFILE_STREAM_INFORMATION)(PTR_ADD_OFFSET((Stream), \ + ((PFILE_STREAM_INFORMATION)(Stream))->NextEntryOffset)) : \ NULL \ ) @@ -911,6 +911,20 @@ PhEnumFileStreams( _Out_ PVOID *Streams ); +typedef BOOLEAN (NTAPI *PPH_ENUM_FILE_STREAMS)( + _In_ PFILE_STREAM_INFORMATION Information, + _In_opt_ PVOID Context + ); + +PHLIBAPI +NTSTATUS +NTAPI +PhEnumFileStreamsEx( + _In_ HANDLE FileHandle, + _In_ PPH_ENUM_FILE_STREAMS Callback, + _In_opt_ PVOID Context + ); + PHLIBAPI VOID NTAPI diff --git a/phlib/native.c b/phlib/native.c index 1f7e2b921991..9bd40c76adfe 100644 --- a/phlib/native.c +++ b/phlib/native.c @@ -5217,6 +5217,36 @@ NTSTATUS PhEnumFileStreams( ); } +NTSTATUS PhEnumFileStreamsEx( + _In_ HANDLE FileHandle, + _In_ PPH_ENUM_FILE_STREAMS Callback, + _In_opt_ PVOID Context + ) +{ + NTSTATUS status; + PVOID buffer; + PFILE_STREAM_INFORMATION i; + + status = PhpQueryFileVariableSize( + FileHandle, + FileStreamInformation, + &buffer + ); + + if (NT_SUCCESS(status)) + { + for (i = PH_FIRST_STREAM(buffer); i; i = PH_NEXT_STREAM(i)) + { + if (!Callback(i, Context)) + break; + } + + PhFree(buffer); + } + + return status; +} + /** * Initializes the device prefixes module. */ From 9aa5e02f34393c99eba21ab99a44a2539709a7f5 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 26 Oct 2018 11:30:49 +1100 Subject: [PATCH 1453/2058] peview: Fix missing properties for some files --- tools/peview/propstore.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/tools/peview/propstore.c b/tools/peview/propstore.c index b187226bd561..6e3ee9b365ae 100644 --- a/tools/peview/propstore.c +++ b/tools/peview/propstore.c @@ -26,17 +26,31 @@ VOID PvpPeEnumerateFilePropStore( _In_ HWND ListViewHandle ) { + HRESULT status; IPropertyStore *propstore; ULONG count; ULONG i; - if (SUCCEEDED(SHGetPropertyStoreFromParsingName( + status = SHGetPropertyStoreFromParsingName( PvFileName->Buffer, NULL, GPS_DEFAULT | GPS_EXTRINSICPROPERTIES | GPS_VOLATILEPROPERTIES, &IID_IPropertyStore, &propstore - ))) + ); + + if (status == HRESULT_FROM_WIN32(ERROR_RESOURCE_TYPE_NOT_FOUND)) + { + status = SHGetPropertyStoreFromParsingName( + PvFileName->Buffer, + NULL, + GPS_FASTPROPERTIESONLY, + &IID_IPropertyStore, + &propstore + ); + } + + if (SUCCEEDED(status)) { if (SUCCEEDED(IPropertyStore_GetCount(propstore, &count))) { From df06a5b7a97a9b8c5e5b49f88bb307fd09cb37cc Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 26 Oct 2018 11:32:34 +1100 Subject: [PATCH 1454/2058] WindowExplorer: Update properties text --- plugins/WindowExplorer/WindowExplorer.rc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/WindowExplorer/WindowExplorer.rc b/plugins/WindowExplorer/WindowExplorer.rc index b452a777cb34..67f9e673eb70 100644 --- a/plugins/WindowExplorer/WindowExplorer.rc +++ b/plugins/WindowExplorer/WindowExplorer.rc @@ -116,7 +116,7 @@ END IDD_WNDPROPLIST DIALOGEX 0, 0, 271, 224 STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Property List" +CAPTION "Properties" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_TABSTOP,0,0,271,224 From f2187b7734d62c7ea6f708c9ca096503d884c0ee Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 26 Oct 2018 21:53:06 +1100 Subject: [PATCH 1455/2058] Fix thread name leak --- ProcessHacker/thrdlist.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ProcessHacker/thrdlist.c b/ProcessHacker/thrdlist.c index 79ffe74917ad..c6ea3c32ffe0 100644 --- a/ProcessHacker/thrdlist.c +++ b/ProcessHacker/thrdlist.c @@ -293,6 +293,9 @@ VOID PhpDestroyThreadNode( if (ThreadNode->CyclesDeltaText) PhDereferenceObject(ThreadNode->CyclesDeltaText); if (ThreadNode->StartAddressText) PhDereferenceObject(ThreadNode->StartAddressText); if (ThreadNode->PrioritySymbolicText) PhDereferenceObject(ThreadNode->PrioritySymbolicText); + if (ThreadNode->CreatedText) PhDereferenceObject(ThreadNode->CreatedText); + if (ThreadNode->NameText) PhDereferenceObject(ThreadNode->NameText); + if (ThreadNode->StateText) PhDereferenceObject(ThreadNode->StateText); PhDereferenceObject(ThreadNode->ThreadItem); @@ -685,7 +688,7 @@ BOOLEAN NTAPI PhpThreadTreeNewCallback( if (NT_SUCCESS(PhGetThreadName(threadItem->ThreadHandle, &threadName))) { - node->NameText = threadName; + PhMoveReference(&node->NameText, threadName); } } From 029578e107690f99c07909ad469a28014566bc92 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 26 Oct 2018 21:54:33 +1100 Subject: [PATCH 1456/2058] Remove token capabilities highlighting --- ProcessHacker/tokprp.c | 42 +++++++++++++++++++----------------------- 1 file changed, 19 insertions(+), 23 deletions(-) diff --git a/ProcessHacker/tokprp.c b/ProcessHacker/tokprp.c index a6d12b851945..0558b5c95b00 100644 --- a/ProcessHacker/tokprp.c +++ b/ProcessHacker/tokprp.c @@ -512,9 +512,7 @@ BOOLEAN PhpUpdateTokenPrivileges( { PPHP_TOKEN_PAGE_LISTVIEW_ITEM lvitem; - lvitem = PhAllocate(sizeof(PHP_TOKEN_PAGE_LISTVIEW_ITEM)); - memset(lvitem, 0, sizeof(PHP_TOKEN_PAGE_LISTVIEW_ITEM)); - + lvitem = PhAllocateZero(sizeof(PHP_TOKEN_PAGE_LISTVIEW_ITEM)); lvitem->TokenPrivilege = &privileges->Privileges[i]; privilegeDisplayName = NULL; @@ -1677,16 +1675,16 @@ INT_PTR CALLBACK PhpTokenAdvancedPageProc( return FALSE; } -static COLORREF NTAPI PhpTokenCapabilitiesColorFunction( - _In_ INT Index, - _In_ PVOID Param, - _In_opt_ PVOID Context - ) -{ - PSID_AND_ATTRIBUTES sidAndAttributes = Param; - - return PhGetGroupAttributesColor(sidAndAttributes->Attributes); -} +//static COLORREF NTAPI PhpTokenCapabilitiesColorFunction( +// _In_ INT Index, +// _In_ PVOID Param, +// _In_opt_ PVOID Context +// ) +//{ +// PSID_AND_ATTRIBUTES sidAndAttributes = Param; +// +// return PhGetGroupAttributesColor(sidAndAttributes->Attributes); +//} INT_PTR CALLBACK PhpTokenCapabilitiesPageProc( _In_ HWND hwndDlg, @@ -1715,9 +1713,9 @@ INT_PTR CALLBACK PhpTokenCapabilitiesPageProc( PhSetListViewStyle(lvHandle, FALSE, TRUE); PhSetControlTheme(lvHandle, L"explorer"); PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 160, L"Name"); - PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 200, L"Flags"); + //PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 200, L"Flags"); PhSetExtendedListView(lvHandle); - ExtendedListView_SetItemColorFunction(lvHandle, PhpTokenCapabilitiesColorFunction); + //ExtendedListView_SetItemColorFunction(lvHandle, PhpTokenCapabilitiesColorFunction); if (NT_SUCCESS(tokenPageContext->OpenObject( &tokenHandle, @@ -1731,7 +1729,7 @@ INT_PTR CALLBACK PhpTokenCapabilitiesPageProc( { INT lvItemIndex; PPH_STRING name; - PPH_STRING attributesString; + //PPH_STRING attributesString; name = PhGetSidFullName(tokenPageContext->Capabilities->Groups[i].Sid, TRUE, NULL); @@ -1740,13 +1738,11 @@ INT_PTR CALLBACK PhpTokenCapabilitiesPageProc( if (name) { - lvItemIndex = PhAddListViewItem(lvHandle, MAXINT, name->Buffer, - &tokenPageContext->Capabilities->Groups[i]); - attributesString = PhGetGroupAttributesString( - tokenPageContext->Capabilities->Groups[i].Attributes, FALSE); - PhSetListViewSubItem(lvHandle, lvItemIndex, 1, attributesString->Buffer); - - PhDereferenceObject(attributesString); + lvItemIndex = PhAddListViewItem(lvHandle, MAXINT, name->Buffer, &tokenPageContext->Capabilities->Groups[i]); + //attributesString = PhGetGroupAttributesString(tokenPageContext->Capabilities->Groups[i].Attributes, FALSE); + //PhSetListViewSubItem(lvHandle, lvItemIndex, 1, attributesString->Buffer); + // + //PhDereferenceObject(attributesString); PhDereferenceObject(name); } } From 01398fb4e6f84c7009077b421ed61fe130b80b9a Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 28 Oct 2018 19:59:24 +1100 Subject: [PATCH 1457/2058] Fix #335 --- phnt/include/ntioapi.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phnt/include/ntioapi.h b/phnt/include/ntioapi.h index 153b6c7d4e48..3e0935650fec 100644 --- a/phnt/include/ntioapi.h +++ b/phnt/include/ntioapi.h @@ -1537,7 +1537,7 @@ NTAPI NtQueryIoCompletion( _In_ HANDLE IoCompletionHandle, _In_ IO_COMPLETION_INFORMATION_CLASS IoCompletionInformationClass, - _Out_writes_bytes_(IoCompletionInformation) PVOID IoCompletionInformation, + _Out_writes_bytes_(IoCompletionInformationLength) PVOID IoCompletionInformation, _In_ ULONG IoCompletionInformationLength, _Out_opt_ PULONG ReturnLength ); From 180c21e58e02375e32fcf269e3fc1095b685aa37 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 13 Nov 2018 12:55:13 +0100 Subject: [PATCH 1458/2058] BuildTool: Fix copying KPH to build directory, Fix spurious build output generated by where.exe during build --- tools/CustomBuildTool/Source Files/Build.cs | 8 ++---- tools/CustomBuildTool/Source Files/Utils.cs | 26 +++++++++++++++--- .../bin/Release/CustomBuildTool.exe | Bin 167936 -> 167936 bytes .../bin/Release/CustomBuildTool.pdb | Bin 83456 -> 85504 bytes 4 files changed, 24 insertions(+), 10 deletions(-) diff --git a/tools/CustomBuildTool/Source Files/Build.cs b/tools/CustomBuildTool/Source Files/Build.cs index ee51c0070995..b24423555afd 100644 --- a/tools/CustomBuildTool/Source Files/Build.cs +++ b/tools/CustomBuildTool/Source Files/Build.cs @@ -581,8 +581,8 @@ public static bool CopyKProcessHacker(BuildFlags Flags) { if (!File.Exists(CustomSignToolPath)) return true; - if (!File.Exists("build\\kph.key")) - return true; + //if (!File.Exists("build\\kph.key")) + // return true; if ((Flags & BuildFlags.Build32bit) == BuildFlags.Build32bit) { @@ -594,7 +594,6 @@ public static bool CopyKProcessHacker(BuildFlags Flags) if (!string.IsNullOrEmpty(output)) { Program.PrintColorMessage("[WARN] (Debug32) " + output, ConsoleColor.Yellow, true, Flags); - return false; } } @@ -606,7 +605,6 @@ public static bool CopyKProcessHacker(BuildFlags Flags) if (!string.IsNullOrEmpty(output)) { Program.PrintColorMessage("[WARN] (Debug64) " + output, ConsoleColor.Yellow, true, Flags); - return false; } } } @@ -621,7 +619,6 @@ public static bool CopyKProcessHacker(BuildFlags Flags) if (!string.IsNullOrEmpty(output)) { Program.PrintColorMessage("[WARN] (Release32) " + output, ConsoleColor.Yellow, true, Flags); - return false; } } @@ -633,7 +630,6 @@ public static bool CopyKProcessHacker(BuildFlags Flags) if (!string.IsNullOrEmpty(output)) { Program.PrintColorMessage("[WARN] (Release64) " + output, ConsoleColor.Yellow, true, Flags); - return false; } } } diff --git a/tools/CustomBuildTool/Source Files/Utils.cs b/tools/CustomBuildTool/Source Files/Utils.cs index ceb828dc956d..0cf2f1fbbf0d 100644 --- a/tools/CustomBuildTool/Source Files/Utils.cs +++ b/tools/CustomBuildTool/Source Files/Utils.cs @@ -78,19 +78,37 @@ public static string ShellExecute(string FileName, string args) public static string SearchFile(string FileName) { - string where = Environment.ExpandEnvironmentVariables("%SystemRoot%\\System32\\where.exe"); + if (File.Exists(FileName)) + return Path.GetFullPath(FileName); - if (File.Exists(where)) + string values = Environment.GetEnvironmentVariable("PATH"); + + foreach (string path in values.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries)) { - string whereResult = ShellExecute(where, FileName); + string whereResult = Path.Combine(path, FileName); - if (!string.IsNullOrEmpty(whereResult)) + if (File.Exists(whereResult)) return whereResult; } return null; } + //public static string SearchFile(string FileName) + //{ + // string where = Environment.ExpandEnvironmentVariables("%SystemRoot%\\System32\\where.exe"); + // + // if (File.Exists(where)) + // { + // string whereResult = ShellExecute(where, FileName); + // + // if (!string.IsNullOrEmpty(whereResult)) + // return whereResult; + // } + // + // return null; + //} + public static void ImageResizeFile(int size, string FileName, string OutName) { using (var src = System.Drawing.Image.FromFile(FileName)) diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe b/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe index 5150bd98f26bf9dadfc9099c70a27d06c6f19f9b..bd048642fc1edc36f33b52e4782c388ea1abe4eb 100644 GIT binary patch delta 11209 zcmcJVd3;l4_W#dwZ*r5|EKQm=X}YFOTSD2PGHfy}I~0MkD2uWqR4RqE;-F|+3ZpEt z80i3_wu7TEEMJ+T=!^>pgW!TJBf{Vy2s#6}fFsP{h<-oM$%Pibzu))2Z+P*(=X1_^ z&hy;oxogtudcC?{U-`JY`cD^DEzJ)064LTrrHh-mggG?t$M_^*(e+TTZ1zlBJ8ClYCg8ncyl$>L0`)Snzx{1f~| z%Mpp(mqfF}9f+gP5?PMC za9?RBL|%X$(Obe%E~jIFv^dm1G7)xU-;GeK&XEJA=#8k+&{S}v;RdZK#0~r12%Spz znj()wc}(F>a_$}eOrCq6*L+Ix7kJDCSWn>w=yp-NOQicD)7qQpGCVFKPvmV`D;I4$ zv&nN&kq50uF5C#Q)fBNu^j1crh#uP#2#PMT4+8%75qPos#s~`HYtY&q*?6m;BA>t! z`L0!CQtB7EQ8V3%v1DN^N_y z85Zk0r%eeThW45;1$?Zj9#etUKiXlnEHCT$wM|MIS-*p@xshf{IdkR93Ns zJNyM(hc&h0BW$f1702X8^Z6_lAH%X#90w~-NYfPltF%wX9{S}p@l5RWFa6O^;3!bS zf5S#sd1KcqPC-?E3OFoHw$o}0pN6lER|%iNR%M1igV{P)QT<_~)X!tqo3W0`m1mJ% zjU6%-q_tP67j-7e!9E?rqNat$C^rBpauaOdTw;-zgMka?Zfk?>;R^UL=E4~Gw+;R2K zSXptagzw<d-{+2Cr#o=S_63wkRTuQrQuZS+ z5&5SAx@_v{+b4^YD*t~;t77iHtz-3l=b{ULKXlPJq+b^i#>H5_&#pZzuyt6nf|ISY zMmrT-Sb=_|8y5SND_;q#qH$aQg`%4YUR^22Rabrv6^~QH(q+HtYJbD!xanG1B(q}W z18*C*RSvE^-ey@0r&QRC)~)(Qb|PSF<|&Nqfydg+lN0$69!oQiJ8}{p&G5v27?_^? zcQ_8=TvqsStk6)r(h_SkDBs>;2rjg^{g^7OvGId)g)LS)sC}u9guLqe;SM{AS{1ad zd;@b@jq9bU;7&E{K)8)v%?h^F)U0+tiUNN@ruuL|MhnymC!$F|s&G}fV9KpCW-4hZ z5@Kyje8L^;Taxc{Bcf}O5_F$du~i;WC0b-stfnL_#eNqC0S_ z9RlB|5p?=#B6$rC^&d5`54M+}Uy402xP@39duFg-B*$JJJTO|EC~wQCPDSpvnHpVW zMm^GgCgHOTFYU(BtNGt=a;=yZ#85o4f#10X z`C8f#RimH$Yy2*{9;!;y=sQZyc2T)rm8R1txxGUgnfyakod&w3-B$EBB~mW<8(M{j z3XQ&?{w9rl@I*CwKV6oa5Ak1g2CLl2Nr@B@PoVUDLUuWY=}M5ZQtOoa_Y2;?wLBoZ zM|vXczry}clztfW&C-d%}1ODEg3Bj^!JVT!M05h)cTk^vRXn zZNXIE={k1ykWgmu+85mH9(?=GL&?i-+DlS^7`G z?;m5p@ z&vm&>3o_QB!UiB&dCJH2Xa9mt{a+0oVkAJyi| zC8+YX#_@cD53Vnm+tOsAt=Vh*sq~($L`kKunb&esaXcU4)y>4dW>Slcd1$+b=WG`* z%5%IZe`cPr$p!iY+ZTCoqmpFhA9Ozc{rU1lx{N~dMC_$V3jC|VBUFvG&R1%vBwA-E z6FhEOWS6l3WwWxTNR^Izvv9jWrB8^!96&Um|fhT$vsJBBn`>!qb7~W(~4+pe0Oils7$dq^muMOQ@p^m$+`hA+WWqJ8gnW^UJWa?`95y zeI5CN{%Dt;BWaT7Ff1Sa6r5nwG>>VK<<9EK&Kb5lt7nEJ=Q3aMN_(nH^54lbY@O+I zr5yIVN|tQ!nj*Oo>`Y0?WjG=qGxxD&(-m`{*y<78MN#bVhzFznZKc(DCdmM^6)3x` zK%rS`1f0u!g82vLUgmSm)r!n{lsTF`8O-C%OU&;%+L7(4uy53#?3^1#;{@Ma@Tf`h z6tg5p+CRDGV%pF79|A+JC}!?bP8ptbdnyZUK6;xLgD=vP;5o4#{7Gy9QCXND zJeqYFJRnYDZh9&g5%tq0w!ep63_Ch3D9`LVGV4EK30}f;tyE{7OUOhMJFr`wew_YCw0;!rnOHWfzyxy^GfLi>JPwBh{9H zab?znx{Ka2)L9fwp!Zp=O8ITZNOJ;R87wn@ow7bdPy!L2wwlxoJa-Y*(A!!0dIIgg zseYlmsmoB3{nt>NV2SRf$A@u4I)sP8Bx#cBju(w9qJ8FGd1Lh^H8IVM11kR6XC4(2 zlyXy*JE!VRYC>jnwJ@jbMyx%GisV^0B-9Y3;(>=h`^<+jtD33LG9QXvzAKR63LL~O z=0?uwSYUM8zz@95eRa;}YOSfcDo805O|4%@sczQ8v-+agBclVOR=Aeycq-%1KJz-q zL26Q8B{f$crZiXk9DAB&woTnbcu+N}Y>ZtTofegqgExJ$a+8vko0P2Fq-5nLB`arB z{Ik!zF=?s5>o0%yna{hP(v7zw%;%NNhnlG_BSUMO$qvZ}abLU9aAeN2&0@RtLeUhv z?rN@jW^HJexhQsGOj=jDC{6jJ)0(R%_2x=0Ra0hNtj*Z8s9cmLpBmiQto}*QRy~)d zj*#PAMZ)LR^JopLI`XIdLC>eXcg15@g0Jc=Xy9n6>Zn@ZtK*9&R;%bwxl5=ueQ791 z@I$=~RgH;f{uE7HNA0OqR%!I$QLDUVKw-vVE)fzNwbwUDNwg zbi8!LPx-#Ij8z>?O-xhz(wBysoOoUDM|~!6CJpzg_WrbtRUK{0)$IewF;T|qr~#^k zmKkb>eMJ<{7nckDj3=_G{}KIJ8RX1w&oKp%pEqZH7$3DN#zV7-}p|iBfvg zP@`~4l+r#!y~3FX4P{N0v15jMp4*)=)Ld3y7%Ce_eJOoysQI`!lt$^QA)_vzy_9Gg zj}+I`G^lfNWu1iXhtrpailn%qt{Cb!p@TGnt{dvbkQ++7H@?5$po@{@G8CEJP<}%V z!l^NeqFIIxLR;L>80vdW z_XIj(s5dc~iS$=P9mZfL(pf|0Vlb2FqM>fXU?$ObhT4O{Or{?Ubrge{Oy=o)AO5wq zBi3RHIj6@5(-TWEg?xruhbf&(nTFbkDV=)Dop&0w;8-1vO3b!Tqr#i2g?+k_S{C|p zE5yuOGH237BlA5fvd<)eZ|jI^X*>0`my=DZDCF0o#C|{FnVy3-reyc}tZ_@^CC#i<{d5dnJXM zrB>aNT4kix(ja73p`gIqi~KdG5f2(FeG|Ol!Fy_!w2$H8M4=_AGP)HMMov64&R*~< z^i7l-$6ZIc@#i5KnC_H~SK4LcqM!&0+7nWO3hf6~+GmP;koHv!xy95?u~xQij{D(pab4Z8CDs z;La~773~%BVLnuPge!amD)fv0)tYCes|Y=P_%TtH4xR3ko{HTr8x$77WrRum!y))<-ki(isj+ zQe?P{IS0Ir=CQpN>`o2JpYVF#pnRKCPMhexya>1}?-B5%XCb|&Jcw_Z8+t#P(fHEO(9j+>J_qJ09XFXSVfetI5W^ILiE;+gro1w{Xfi>Pe9Nte2Gz-_( z-AX^_5tO)?vjqIsb&R7Y!6DhQ)u`;Nv>T-@VmBq?3v1ZH6d}~*8JXe$jmr%Qo0^V$ zut)9T3?rJB*cSetd4=K(&CBa0WS#y|aULbybe@Lg4if?O2|Pg@Rx0w3fwJSn%7pw; z;xM|Oh6cO*2YC<`uxq>zqR{UG3&dp%cPY3v_!ecWa_E=oO2%7sUPKeuiv!AtJUJil zTIFu|64y~nRrc6Y9h&^Hh#pY3xlW1>s+_>X9G251sH@sFWd$bf_tttk!yOcJX$L>z zc~on{F}lW?*T|QXt(2-eOt;Y(^){u2G6@~DQLfQsQ)gw4dT&U+zWp^cM6ro-TcPNx z4tK1edFnRT14>O4saR>XXZCz$p1RZOhHc6-lSf?jC4-hk$9oW2ty0LTJ(zuHc}7chFgIvWzDmA|2~10TQ1n3Nmr4(;rKBt|68XK<2DMH80JV^o z<-Ua{b6IVZD!aMch=xP2s#6WSPyT0WIeip#nW|`cG$Ul1k8Zk{7IJu*k+d*vy6Gt@ z^*?7?Z+Ncf?lV1a*zH1B&`NetiurKUb}WZv5B%&R>Bb=B9&h0t*ut6H)j3$=9rSVD zmx??jkKq7+GZYP)UsF4|3e7uEx|><<>rN!?F!hCJtiP|>qjt}@1H2n=_J_sv+)3sW z=yE#vfqj}GN!=jGfQ^KN`ow8Y$1 zJ&z**hjaGoD8%}-b>Ld?GD>eYUjrM>m(@A;H_^dfPclk8lb4JVe@{J%ZeGqU6hhgF z!%CpsTZo1@>drfD_L%Ce2XXKoOj?2cJE+TUR)xMn{ozhLSt#@EX3c{uibD%1nR=oY z4Jhx}(jYF_ax|OL7gqwCGA{HM1(dMfQtN86c?;pc;OV9vP&(w7YT3&1)X`ua9tB&X z5KbiJl79lCL1&qEhA#Olv|^LI;53N#_JvvpWO_e%QY$mPnztR)O_Hx= zT+&LBb5)b)LakC}+60e0M^-9hxXT*T$KFKCV$&>dss)qpFR<)2j-h9rrIrRY`gHDW z%Wk1M7lDc387enD4%XlbwaT>JT4!lce#}{KX%OE0jg}e|-3C7BeFgr?#J4T)8|4=H z2B-m3P3WlQFZ6rS#q<}tO$<>mE5VD%{1Vqec?RvFayst$mt~V_n~SUsiYc0L5Ux_c z$7-bqr~sS?CekBp*Dx2cXEEC=nNLwWWUiq?a6NSe>!~OBJoUCJxF%hlzIJNKpum7G1%+MNe>|=nYO44}&vA zHCQedfwRRDu!>v#id)U+R@K~UA-7t_l~;1kQ=GE~Iab^Y3!-Seo>S|^3b-1O+Jcs1 z|JstB>80P<+fo{B14Hxy*b2Ybw53kW?(`Mx-tA+Dym5nWQ>ZF_YSWjR=QetIiPHy;x<|H!-Pv8M%Gq74M&G01?hUFex(R`D_a3$nz+U7&s~)8nU1!yk zh@MrS2G7I4)~%YPZ8M$4a)j7!$#!qHr!Z@oXUsBFXp-5?V&)`fjrMdDfd&@4nP-^7 z!VQ?k%t_1|W&?9K^9)m1IiFd~oW!hQHZXTH&oG6J^TB94YcY#S%o=6`^K^ntBDZ9a zS;U;ktY+3TcQH>h$;0`~B4#zSp1F&8nn{Vsj9P*z${`;WL7ilnY);$ndIYq=0u-7psJZI zsk5yWb+NU=yiw6^{c*h0Tz5(S=vW4JPnJv%NFHEMhg4~A zOp<(@S;#rdP15tEOTIlWPLcNJ5EvzsS&9j|%eLVk@C)>KzE6wHwQ>^pii8qq4O|ee7@iPPu`^i`!(%*eu%(VQ3|9<5| zOAF~f#JDl-9V;M2KysT>I?8Zy6kA(`+xOer{{8-`^Z*24CoLI$fEjIeiVzv+M*JAB< zyBn9h@sK6<$Jf&vO@FSlaP2>rtr)R&QLOR! z-@h<>troK@!)0~3Y(XW%m7#hTcw&3L3TG#4K_NT~0(#Ia5^Ky>e9T0N3o_vizi|K jW_wR1MJ(Kzr-;?!F_%f~beWXz7c0-V-?_V^xGMe|dRFeO delta 11161 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%0DMf#5yjB_OR6ZjlI#q)R( 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 HpX&brl*`_r From d444d219c1e1379d6543c25a57860f190b8f0c0a Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 13 Nov 2018 12:57:34 +0100 Subject: [PATCH 1459/2058] Update KPH error message format --- ProcessHacker/actions.c | 2 +- ProcessHacker/include/actions.h | 1 + ProcessHacker/thrdstk.c | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/ProcessHacker/actions.c b/ProcessHacker/actions.c index c61ea703a928..fcd88756e83a 100644 --- a/ProcessHacker/actions.c +++ b/ProcessHacker/actions.c @@ -3175,7 +3175,7 @@ BOOLEAN PhUiSetAttributesHandle( if (!KphIsConnected()) { - PhShowError(hWnd, PH_KPH_ERROR_MESSAGE); + PhShowError2(hWnd, PH_KPH_ERROR_TITLE, PH_KPH_ERROR_MESSAGE); return FALSE; } diff --git a/ProcessHacker/include/actions.h b/ProcessHacker/include/actions.h index 9730132fc4a9..a14ea1a52387 100644 --- a/ProcessHacker/include/actions.h +++ b/ProcessHacker/include/actions.h @@ -1,6 +1,7 @@ #ifndef PH_ACTIONS_H #define PH_ACTIONS_H +#define PH_KPH_ERROR_TITLE (L"KProcessHacker could not be loaded.") #define PH_KPH_ERROR_MESSAGE (L"KProcessHacker does not support your operating system " \ L"or could not be loaded. Make sure Process Hacker is running " \ L"with administrative privileges.") diff --git a/ProcessHacker/thrdstk.c b/ProcessHacker/thrdstk.c index d72f50559c9a..6b055893c5d6 100644 --- a/ProcessHacker/thrdstk.c +++ b/ProcessHacker/thrdstk.c @@ -706,7 +706,7 @@ VOID PhShowThreadStackDialog( // but KProcessHacker is not loaded, show an error message. if (ProcessId == SYSTEM_PROCESS_ID && !KphIsConnected()) { - PhShowError(ParentWindowHandle, PH_KPH_ERROR_MESSAGE); + PhShowError2(ParentWindowHandle, PH_KPH_ERROR_TITLE, PH_KPH_ERROR_MESSAGE); return; } From 9a08c7ee16a4bf192e0adf13965e5413617be1e0 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 13 Nov 2018 13:07:57 +0100 Subject: [PATCH 1460/2058] Fix #337 (suspended process job association) --- ProcessHacker/procprv.c | 121 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 120 insertions(+), 1 deletion(-) diff --git a/ProcessHacker/procprv.c b/ProcessHacker/procprv.c index adfbc912f1ad..14b2ade00de7 100644 --- a/ProcessHacker/procprv.c +++ b/ProcessHacker/procprv.c @@ -1159,7 +1159,10 @@ VOID PhpFillProcessItem( } // Token information - if (ProcessItem->QueryHandle) + if ( + ProcessItem->QueryHandle && + ProcessItem->ProcessId != SYSTEM_PROCESS_ID // System token can't be opened (dmex) + ) { HANDLE tokenHandle; @@ -2172,6 +2175,122 @@ VOID PhProcessProviderUpdate( } } + // Token information + if ( + processItem->QueryHandle && + processItem->ProcessId != SYSTEM_PROCESS_ID // System token can't be opened (dmex) + ) + { + HANDLE tokenHandle; + + if (NT_SUCCESS(PhOpenProcessToken( + processItem->QueryHandle, + TOKEN_QUERY, + &tokenHandle + ))) + { + PTOKEN_USER tokenUser; + TOKEN_ELEVATION_TYPE elevationType; + MANDATORY_LEVEL integrityLevel; + PWSTR integrityString; + + // User + if (NT_SUCCESS(PhGetTokenUser(tokenHandle, &tokenUser))) + { + PSID processSid = processItem->Sid; + + processItem->Sid = PhAllocateCopy(tokenUser->User.Sid, RtlLengthSid(tokenUser->User.Sid)); + + PhFree(processSid); + PhFree(tokenUser); + modified = TRUE; + } + + // Elevation + if (NT_SUCCESS(PhGetTokenElevationType(tokenHandle, &elevationType))) + { + if (processItem->ElevationType != elevationType) + { + processItem->ElevationType = elevationType; + processItem->IsElevated = elevationType == TokenElevationTypeFull; + modified = TRUE; + } + } + + // Integrity + if (NT_SUCCESS(PhGetTokenIntegrityLevel(tokenHandle, &integrityLevel, &integrityString))) + { + if (processItem->IntegrityLevel != integrityLevel) + { + processItem->IntegrityLevel = integrityLevel; + processItem->IntegrityString = integrityString; + modified = TRUE; + } + } + + NtClose(tokenHandle); + } + } + + // Job + if (processItem->QueryHandle) + { + NTSTATUS status; + + if (KphIsConnected()) + { + HANDLE jobHandle = NULL; + + status = KphOpenProcessJob( + processItem->QueryHandle, + JOB_OBJECT_QUERY, + &jobHandle + ); + + if (NT_SUCCESS(status) && status != STATUS_PROCESS_NOT_IN_JOB) + { + JOBOBJECT_BASIC_LIMIT_INFORMATION basicLimits; + PPH_STRING jobName = NULL; + + processItem->IsInJob = TRUE; + + PhGetHandleInformation( + NtCurrentProcess(), + jobHandle, + ULONG_MAX, + NULL, + NULL, + NULL, + &jobName + ); + + if (jobName) + PhMoveReference(&processItem->JobName, jobName); + + // Process Explorer only recognizes processes as being in jobs if they don't have + // the silent-breakaway-OK limit as their only limit. Emulate this behaviour. (wj32) + if (NT_SUCCESS(PhGetJobBasicLimits(jobHandle, &basicLimits))) + { + processItem->IsInSignificantJob = + basicLimits.LimitFlags != JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK; + } + } + + if (jobHandle) + NtClose(jobHandle); + } + else + { + // KProcessHacker is not available. We can determine if the process is in a job, but we + // can't get a handle to the job. (wj32) + + status = NtIsProcessInJob(processItem->QueryHandle, NULL); + + if (NT_SUCCESS(status)) + processItem->IsInJob = status == STATUS_PROCESS_IN_JOB; + } + } + // Debugged if (processItem->QueryHandle) { From 9220b5073aaef0808567361ebc189f746ee734bc Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 13 Nov 2018 13:08:49 +0100 Subject: [PATCH 1461/2058] Fix processes tab 'desktop' column handle leak --- ProcessHacker/proctree.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ProcessHacker/proctree.c b/ProcessHacker/proctree.c index 17f158f37723..b315ae497629 100644 --- a/ProcessHacker/proctree.c +++ b/ProcessHacker/proctree.c @@ -1298,6 +1298,8 @@ static VOID PhpUpdateProcessNodeDesktopInfo( { ProcessNode->DesktopInfoText = desktopinfo; } + + NtClose(processHandle); } ProcessNode->ValidMask |= PHPN_DESKTOPINFO; From 7d1767a549f05c8cd227446d36855db2cb60d334 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 13 Nov 2018 13:34:59 +0100 Subject: [PATCH 1462/2058] BuildTool: Fix appveyor search path --- tools/CustomBuildTool/Source Files/Utils.cs | 26 +++++++++--------- .../bin/Release/CustomBuildTool.exe | Bin 167936 -> 167936 bytes .../bin/Release/CustomBuildTool.pdb | Bin 85504 -> 85504 bytes 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/tools/CustomBuildTool/Source Files/Utils.cs b/tools/CustomBuildTool/Source Files/Utils.cs index 0cf2f1fbbf0d..649e69eaa3ab 100644 --- a/tools/CustomBuildTool/Source Files/Utils.cs +++ b/tools/CustomBuildTool/Source Files/Utils.cs @@ -78,18 +78,22 @@ public static string ShellExecute(string FileName, string args) public static string SearchFile(string FileName) { - if (File.Exists(FileName)) - return Path.GetFullPath(FileName); + try + { + if (File.Exists(FileName)) + return Path.GetFullPath(FileName); - string values = Environment.GetEnvironmentVariable("PATH"); + string values = Environment.GetEnvironmentVariable("PATH"); - foreach (string path in values.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries)) - { - string whereResult = Path.Combine(path, FileName); + foreach (string path in values.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries)) + { + string whereResult = Path.Combine(path, FileName); - if (File.Exists(whereResult)) - return whereResult; + if (File.Exists(whereResult)) + return whereResult; + } } + catch (Exception) { } return null; } @@ -347,11 +351,7 @@ public static class AppVeyor static AppVeyor() { - try - { - AppVeyorPath = Win32.SearchFile("appveyor"); - } - catch (Exception) { } + AppVeyorPath = Win32.SearchFile("appveyor.exe"); } public static bool AppVeyorNightlyBuild() diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe b/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe index bd048642fc1edc36f33b52e4782c388ea1abe4eb..0cc374d2c8dc5450c95fe29c9068f94d3e70cb75 100644 GIT binary patch delta 5234 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 diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb b/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb index c49ea70cb5857be11ff09c57371bffb9df5cab57..567bd9aca888a8b3a771ec58e8a5da4795b28729 100644 GIT binary patch delta 4160 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 X3{{Qq(sZ2=E3n_Z(^m61y*%>&O=W4O delta 4172 zcmaKwe^gaf7RS$i@DNb!5ePn?pgaXep1+764|w7O(a|jOM@mKNf(%3v!9=G31r&7% zO>LJ~3>00msuigCR1ihMACrG%fX>i3D>G-nL<7wwD=ls2d+tU1tGR34{n=;lea=01 zpL6zoP*kBWs?Z;Hb|3oj$=h#|5Mtn*;w_hFz5mMIgHNhf?c9FWG2DHu!8^VoGxk4G zyMJ1JJ>97*q<2zqNmXfG`~f;L+*RjR7LR_o${e2lKM&A9x;6dSboL1P!ugT+{CdZ! zpbWd~QiRCS6;Ds{=b7m~wA7KBZX;UCl}k)Cl}{|mq%S!zV+7>1jBNUvk7Z0Ser?yf z`3NV^zoYv|j4=}Y2S3Ru)ctDbbxW5Kare?pa^?BUUPI^FWmY$>8;Nlou-WUw%y73~ z)p1C;@V-nho}Fnxr_@XTnha@Usz$+J(|QW+5W~ylYXDHx04V@afe{in>aT6Bpx;= z$Hd+_20Tz|anKylEO@AF??Ssp)y_k^sA~71wKA==U;;8`#!3SwA+=m+ovKy^?GD!= z=Dyl~xYB?LIo#hFrqlIVIVjgGF*7%k^jw@(S?|VDo@48~3c2RQ^*iFd zXedw3d!06NWnMOIVUPT5+R1AnE4e5CHOj$qn>eMwfQXd^7DQA+?u2gQPFO3Y<}j@F zCR)XT>w+N@*L_O0+_!ENq_NOOM|pmsl}_?j$g_N*aGUO76eks#CGv`5bpMUw<3*9= z!aYS+^5DSYZIr;ribp|SEw<529Njzu$W(jdR^U7#HACMd_d1e! zT;<20TvfTs3H_W3{w5r{jb?K7i~D^wO+0;*r_L{qU)gWwf=w0V=P+&_=t=K$;4TZ~ zoLym5&l`8ysh2P8vSC|Lc|OJQ+VU{Sy7EJ`f>U=-pf$W>_ZNtd{lrwLCsE{r=M4a5 z7G1$%pgR}{dVu4==SXanyU+)1>^$KM%J~|>`QR`x6&wyO2Ic#_4Vuwj295@^z#y;$ z3x~T*}%; zw}LX&(cl=+295!b#V{$E*`Qs49DQbz42tNiiIWzp<1Vxt)OPeK3pI1vDH}e| z`ygBS8e|6>n?~WyW1B2^^OhzPmoyo4ZLz#AXBZ!DG9U#la9!sf$eU_F_-TW#R|`lv zZ9pzop0>zb>^U8RTm+m!6-UIN$?6b>GX^9j;EV-HNrW`30Uw<)=t8uBW(0(CJ6zHH z1TszynA&X6&CmjJnhi)(akB+!s)byn20TDOx)w09#ejT;wpfs_g^&emz=0Nnu0#uH zLqHkdfQ#AVtOZGvlbmY{ewP3_%3H5($VEXe;0W;J7NC__B7SbA-BzgAH%dArg<>^8p+AG%^qXX z+=6=wOio;SJJa}34;9xo4XRv@dXUT>cT9n8h&_)8=}lIDo#5c&X|Av}Zbv*MHA4LbyL<) z*^U5T2PcEc;B@d!P(E75y#mTO`Id`74-q^WEA`0_7BQK_74p=m-7<91Xq)MuYj_G_ZiL^;&5y z54k&?l6m1>Q(-YY@@3b9ZeR)M3vL2s75*z243>g&W?Mj+gsosC_yH)_Ya1wEc83rf zT+#-xADnaxSdqEFj;h*nLqi&A9XQF+MH|~8(J7&LpV!Fk5Ril z*4O`HrX(l#6#4DPb>2x?F`CTv1wr&SQAPcYU|QlvNs4DE`RZlP(=}CYuWg#z4Rw&J z`pKWf^5x~#KcK41b7WQ8L&-#|lpa7Yf4IG*{3J(}zqvG(5|sEC5c9sW5YWqSe20?y z0%GLnXN1xYl_Hcn8Izz~k|0O7i8ihEjoMPa4<~13dpHfHo0_{W5FJ1 Date: Tue, 13 Nov 2018 16:19:51 +0100 Subject: [PATCH 1463/2058] Disable Sandboxie support #233 --- ProcessHacker/plugin.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ProcessHacker/plugin.c b/ProcessHacker/plugin.c index 36945e74a491..769fd7b78c47 100644 --- a/ProcessHacker/plugin.c +++ b/ProcessHacker/plugin.c @@ -190,7 +190,8 @@ static BOOLEAN EnumPluginsDirectoryCallback( static PWSTR PhpPluginBlocklist[] = { L"CommonUtil.dll", - L"ExtraPlugins.dll" + L"ExtraPlugins.dll", + L"SbieSupport.dll" }; BOOLEAN blacklistedPlugin = FALSE; PH_STRINGREF baseName; From 1bb7c1753abc6d6debd951bde99002313e330368 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 14 Nov 2018 16:43:49 +0100 Subject: [PATCH 1464/2058] Fix typo --- ProcessHacker/plugin.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ProcessHacker/plugin.c b/ProcessHacker/plugin.c index 769fd7b78c47..501e6eb6dfe2 100644 --- a/ProcessHacker/plugin.c +++ b/ProcessHacker/plugin.c @@ -193,7 +193,7 @@ static BOOLEAN EnumPluginsDirectoryCallback( L"ExtraPlugins.dll", L"SbieSupport.dll" }; - BOOLEAN blacklistedPlugin = FALSE; + BOOLEAN blocklistedPlugin = FALSE; PH_STRINGREF baseName; PPH_STRING fileName; @@ -208,14 +208,14 @@ static BOOLEAN EnumPluginsDirectoryCallback( { if (PhEndsWithStringRef2(&baseName, PhpPluginBlocklist[i], TRUE)) { - blacklistedPlugin = TRUE; + blocklistedPlugin = TRUE; break; } } fileName = PhConcatStringRef2(&PluginsDirectory->sr, &baseName); - if (blacklistedPlugin) + if (blocklistedPlugin) { PhDeleteFileWin32(fileName->Buffer); } @@ -231,7 +231,7 @@ static BOOLEAN EnumPluginsDirectoryCallback( PPHP_PLUGIN_LOAD_ERROR loadError; PPH_STRING errorMessage; - loadError = PhAllocate(sizeof(PHP_PLUGIN_LOAD_ERROR)); + loadError = PhAllocateZero(sizeof(PHP_PLUGIN_LOAD_ERROR)); PhSetReference(&loadError->FileName, fileName); if (errorMessage = PhGetNtMessage(status)) From 1bca2c12e5dc517d185a331957be4694066b293f Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 14 Nov 2018 16:44:46 +0100 Subject: [PATCH 1465/2058] ExtendedTools: Fix GPU details WDDM version on Win10-1809 --- plugins/ExtendedTools/d3dkmt.h | 9 +++++---- plugins/ExtendedTools/gpudetails.c | 3 +++ 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/plugins/ExtendedTools/d3dkmt.h b/plugins/ExtendedTools/d3dkmt.h index 9d8a256b2dc5..84c26a8a7351 100644 --- a/plugins/ExtendedTools/d3dkmt.h +++ b/plugins/ExtendedTools/d3dkmt.h @@ -413,10 +413,11 @@ typedef enum D3DKMT_DRIVERVERSION KMT_DRIVERVERSION_WDDM_1_2 = 1200, // The display miniport driver supports the Windows Vista display driver model with released Windows 8 features. Supported starting with Windows 8. KMT_DRIVERVERSION_WDDM_1_3 = 1300, // The display miniport driver supports the Windows display driver model with released Windows 8.1 features. Supported starting with Windows 8.1. KMT_DRIVERVERSION_WDDM_2_0 = 2000, // The display miniport driver supports the Windows display driver model with released Windows 10 features. Supported starting with Windows 10. - KMT_DRIVERVERSION_WDDM_2_1 = 2100, - KMT_DRIVERVERSION_WDDM_2_2 = 2200, - KMT_DRIVERVERSION_WDDM_2_3 = 2300, - KMT_DRIVERVERSION_WDDM_2_4 = 2400, + KMT_DRIVERVERSION_WDDM_2_1 = 2100, // 1607 + KMT_DRIVERVERSION_WDDM_2_2 = 2200, // 1703 + KMT_DRIVERVERSION_WDDM_2_3 = 2300, // 1709 + KMT_DRIVERVERSION_WDDM_2_4 = 2400, // 1803 + KMT_DRIVERVERSION_WDDM_2_5 = 2500, // 1809 } D3DKMT_DRIVERVERSION; // Specifies the type of display device that the graphics adapter supports. diff --git a/plugins/ExtendedTools/gpudetails.c b/plugins/ExtendedTools/gpudetails.c index dc6cc4ee201f..a8ba6dd0adcd 100644 --- a/plugins/ExtendedTools/gpudetails.c +++ b/plugins/ExtendedTools/gpudetails.c @@ -157,6 +157,9 @@ VOID EtpQueryAdapterDriverModel( case KMT_DRIVERVERSION_WDDM_2_4: PhSetListViewSubItem(ListViewHandle, GPUADAPTER_DETAILS_INDEX_WDDMVERSION, 1, L"WDDM 2.4"); break; + case KMT_DRIVERVERSION_WDDM_2_5: + PhSetListViewSubItem(ListViewHandle, GPUADAPTER_DETAILS_INDEX_WDDMVERSION, 1, L"WDDM 2.5"); + break; default: PhSetListViewSubItem(ListViewHandle, GPUADAPTER_DETAILS_INDEX_WDDMVERSION, 1, L"ERROR"); break; From 9e0da12eb362e6061d1d6350eceae8f3711775a0 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 15 Nov 2018 10:53:01 +0100 Subject: [PATCH 1466/2058] Update to latest WinSDK --- ProcessHacker/ProcessHacker.vcxproj | 2 +- phlib/phlib.vcxproj | 2 +- plugins/DotNetTools/DotNetTools.vcxproj | 2 +- plugins/ExtendedNotifications/ExtendedNotifications.vcxproj | 2 +- plugins/ExtendedServices/ExtendedServices.vcxproj | 2 +- plugins/ExtendedTools/ExtendedTools.vcxproj | 2 +- plugins/HardwareDevices/HardwareDevices.vcxproj | 2 +- plugins/NetworkTools/NetworkTools.vcxproj | 2 +- plugins/OnlineChecks/OnlineChecks.vcxproj | 2 +- plugins/ToolStatus/ToolStatus.vcxproj | 2 +- plugins/Updater/Updater.vcxproj | 2 +- plugins/UserNotes/UserNotes.vcxproj | 2 +- plugins/WindowExplorer/WindowExplorer.vcxproj | 2 +- tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj | 2 +- tools/peview/peview.vcxproj | 2 +- 15 files changed, 15 insertions(+), 15 deletions(-) diff --git a/ProcessHacker/ProcessHacker.vcxproj b/ProcessHacker/ProcessHacker.vcxproj index 5fbd4fd8b4d3..2896a1a4087c 100644 --- a/ProcessHacker/ProcessHacker.vcxproj +++ b/ProcessHacker/ProcessHacker.vcxproj @@ -22,7 +22,7 @@ {0271DD27-6707-4290-8DFE-285702B7115D} ProcessHacker Win32Proj - 10.0.17134.0 + 10.0.17763.0 diff --git a/phlib/phlib.vcxproj b/phlib/phlib.vcxproj index bb62d0be9420..40147221b2be 100644 --- a/phlib/phlib.vcxproj +++ b/phlib/phlib.vcxproj @@ -22,7 +22,7 @@ {477D0215-F252-41A1-874B-F27E3EA1ED17} phlib Win32Proj - 10.0.17134.0 + 10.0.17763.0 diff --git a/plugins/DotNetTools/DotNetTools.vcxproj b/plugins/DotNetTools/DotNetTools.vcxproj index 7b5daab17c0c..66df5200d23f 100644 --- a/plugins/DotNetTools/DotNetTools.vcxproj +++ b/plugins/DotNetTools/DotNetTools.vcxproj @@ -23,7 +23,7 @@ DotNetTools Win32Proj DotNetTools - 10.0.17134.0 + 10.0.17763.0 diff --git a/plugins/ExtendedNotifications/ExtendedNotifications.vcxproj b/plugins/ExtendedNotifications/ExtendedNotifications.vcxproj index efc911ed6ee4..41fdf7c61cdd 100644 --- a/plugins/ExtendedNotifications/ExtendedNotifications.vcxproj +++ b/plugins/ExtendedNotifications/ExtendedNotifications.vcxproj @@ -23,7 +23,7 @@ ExtendedNotifications Win32Proj ExtendedNotifications - 10.0.17134.0 + 10.0.17763.0 diff --git a/plugins/ExtendedServices/ExtendedServices.vcxproj b/plugins/ExtendedServices/ExtendedServices.vcxproj index 4d3e69179c81..073a89063451 100644 --- a/plugins/ExtendedServices/ExtendedServices.vcxproj +++ b/plugins/ExtendedServices/ExtendedServices.vcxproj @@ -23,7 +23,7 @@ ExtendedServices Win32Proj ExtendedServices - 10.0.17134.0 + 10.0.17763.0 diff --git a/plugins/ExtendedTools/ExtendedTools.vcxproj b/plugins/ExtendedTools/ExtendedTools.vcxproj index 9fd33f94cc8f..72d6713a4085 100644 --- a/plugins/ExtendedTools/ExtendedTools.vcxproj +++ b/plugins/ExtendedTools/ExtendedTools.vcxproj @@ -23,7 +23,7 @@ ExtendedTools Win32Proj ExtendedTools - 10.0.17134.0 + 10.0.17763.0 diff --git a/plugins/HardwareDevices/HardwareDevices.vcxproj b/plugins/HardwareDevices/HardwareDevices.vcxproj index a606468d867c..39b3efefb8ba 100644 --- a/plugins/HardwareDevices/HardwareDevices.vcxproj +++ b/plugins/HardwareDevices/HardwareDevices.vcxproj @@ -23,7 +23,7 @@ HardwareDevices Win32Proj HardwareDevices - 10.0.17134.0 + 10.0.17763.0 diff --git a/plugins/NetworkTools/NetworkTools.vcxproj b/plugins/NetworkTools/NetworkTools.vcxproj index 9e81f5632366..00a63496d21a 100644 --- a/plugins/NetworkTools/NetworkTools.vcxproj +++ b/plugins/NetworkTools/NetworkTools.vcxproj @@ -23,7 +23,7 @@ NetworkTools Win32Proj NetworkTools - 10.0.17134.0 + 10.0.17763.0 diff --git a/plugins/OnlineChecks/OnlineChecks.vcxproj b/plugins/OnlineChecks/OnlineChecks.vcxproj index ef6144e5ac96..ce8e88b3d4c2 100644 --- a/plugins/OnlineChecks/OnlineChecks.vcxproj +++ b/plugins/OnlineChecks/OnlineChecks.vcxproj @@ -23,7 +23,7 @@ OnlineChecks Win32Proj OnlineChecks - 10.0.17134.0 + 10.0.17763.0 diff --git a/plugins/ToolStatus/ToolStatus.vcxproj b/plugins/ToolStatus/ToolStatus.vcxproj index b60b882c7f35..b31153c1de42 100644 --- a/plugins/ToolStatus/ToolStatus.vcxproj +++ b/plugins/ToolStatus/ToolStatus.vcxproj @@ -23,7 +23,7 @@ ToolStatus Win32Proj ToolStatus - 10.0.17134.0 + 10.0.17763.0 diff --git a/plugins/Updater/Updater.vcxproj b/plugins/Updater/Updater.vcxproj index c9e89da0b5b4..4434a44bdb14 100644 --- a/plugins/Updater/Updater.vcxproj +++ b/plugins/Updater/Updater.vcxproj @@ -23,7 +23,7 @@ Updater Win32Proj Updater - 10.0.17134.0 + 10.0.17763.0 diff --git a/plugins/UserNotes/UserNotes.vcxproj b/plugins/UserNotes/UserNotes.vcxproj index ee6737ebeea7..72732b329e56 100644 --- a/plugins/UserNotes/UserNotes.vcxproj +++ b/plugins/UserNotes/UserNotes.vcxproj @@ -23,7 +23,7 @@ UserNotes Win32Proj UserNotes - 10.0.17134.0 + 10.0.17763.0 diff --git a/plugins/WindowExplorer/WindowExplorer.vcxproj b/plugins/WindowExplorer/WindowExplorer.vcxproj index 4744654723c0..4183ef6b9d99 100644 --- a/plugins/WindowExplorer/WindowExplorer.vcxproj +++ b/plugins/WindowExplorer/WindowExplorer.vcxproj @@ -23,7 +23,7 @@ WindowExplorer Win32Proj WindowExplorer - 10.0.17134.0 + 10.0.17763.0 diff --git a/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj b/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj index 8e6ea14cbb99..47be456378f5 100644 --- a/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj +++ b/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj @@ -13,7 +13,7 @@ {5C00734F-F50A-49FC-9D2A-F6EE51ECB00F} CustomSetupTool - 10.0.17134.0 + 10.0.17763.0 CustomSetupTool diff --git a/tools/peview/peview.vcxproj b/tools/peview/peview.vcxproj index 7a93c1ab5dd0..f8a3a1fc5dc2 100644 --- a/tools/peview/peview.vcxproj +++ b/tools/peview/peview.vcxproj @@ -22,7 +22,7 @@ {72C124A2-3C80-41C6-ABA1-C4948B713204} peview Win32Proj - 10.0.17134.0 + 10.0.17763.0 From e968ee184db88eb3419eb7e1f6feaab70e42d142 Mon Sep 17 00:00:00 2001 From: diversenok Date: Fri, 16 Nov 2018 20:00:17 +0300 Subject: [PATCH 1467/2058] Show dangerous flags for tokens (#338) * Show dangerous flags for tokens * Fix end-of-line spacing * Fix typo --- ProcessHacker/resource.h | 1 + ProcessHacker/tokprp.c | 235 ++++++++++++++++++++++++++++++++++-- phlib/include/phnativeinl.h | 35 ++++++ 3 files changed, 259 insertions(+), 12 deletions(-) diff --git a/ProcessHacker/resource.h b/ProcessHacker/resource.h index d7c69aaaf262..90d10d033f56 100644 --- a/ProcessHacker/resource.h +++ b/ProcessHacker/resource.h @@ -750,6 +750,7 @@ #define ID_GROUP_RESET 40299 #define ID_TOOLS_SCM_PERMISSIONS 40300 #define ID_TOOLS_RDP_PERMISSIONS 40301 +#define ID_UIACCESS_REMOVE 40302 #define IDDYNAMIC 50000 #define IDPLUGINS 55000 diff --git a/ProcessHacker/tokprp.c b/ProcessHacker/tokprp.c index 0558b5c95b00..700f63caf7c2 100644 --- a/ProcessHacker/tokprp.c +++ b/ProcessHacker/tokprp.c @@ -35,9 +35,17 @@ typedef enum _PH_PROCESS_TOKEN_CATEGORY { PH_PROCESS_TOKEN_CATEGORY_PRIVILEGES, PH_PROCESS_TOKEN_CATEGORY_GROUPS, - PH_PROCESS_TOKEN_CATEGORY_RESTRICTED + PH_PROCESS_TOKEN_CATEGORY_RESTRICTED, + PH_PROCESS_TOKEN_CATEGORY_DANGEROUS_FLAGS } PH_PROCESS_TOKEN_CATEGORY; +typedef enum _PH_PROCESS_TOKEN_FLAG +{ + PH_PROCESS_TOKEN_FLAG_NO_WRITE_UP, + PH_PROCESS_TOKEN_FLAG_SANDBOX_INERT, + PH_PROCESS_TOKEN_FLAG_UIACCESS +} PH_PROCESS_TOKEN_FLAG; + typedef enum _PH_PROCESS_TOKEN_INDEX { PH_PROCESS_TOKEN_INDEX_NAME, @@ -52,6 +60,11 @@ typedef struct _PHP_TOKEN_PAGE_LISTVIEW_ITEM { PSID_AND_ATTRIBUTES TokenGroup; PLUID_AND_ATTRIBUTES TokenPrivilege; + struct + { + PH_PROCESS_TOKEN_FLAG ItemFlag; + BOOLEAN ItemFlagState; + }; }; } PHP_TOKEN_PAGE_LISTVIEW_ITEM, *PPHP_TOKEN_PAGE_LISTVIEW_ITEM; @@ -326,6 +339,16 @@ COLORREF PhGetPrivilegeAttributesColor( } } +COLORREF PhGetDangerousFlagColor( + _In_ BOOLEAN FlagState +) +{ + if (FlagState) + return RGB(0xc0, 0xf0, 0xc0); + else + return RGB(0xf0, 0xc0, 0xc0); +} + static COLORREF NTAPI PhpTokenGroupColorFunction( _In_ INT Index, _In_ PVOID Param, @@ -334,7 +357,9 @@ static COLORREF NTAPI PhpTokenGroupColorFunction( { PPHP_TOKEN_PAGE_LISTVIEW_ITEM entry = Param; - if (entry->ItemCategory == PH_PROCESS_TOKEN_CATEGORY_PRIVILEGES) + if (entry->ItemCategory == PH_PROCESS_TOKEN_CATEGORY_DANGEROUS_FLAGS) + return PhGetDangerousFlagColor(entry->ItemFlagState); + else if (entry->ItemCategory == PH_PROCESS_TOKEN_CATEGORY_PRIVILEGES) return PhGetPrivilegeAttributesColor(entry->TokenPrivilege->Attributes); else return PhGetGroupAttributesColor(entry->TokenGroup->Attributes); @@ -423,10 +448,10 @@ VOID PhpUpdateSidsFromTokenGroups( lvitem->TokenGroup = &Groups->Groups[i]; lvItemIndex = PhAddListViewGroupItem( - ListViewHandle, + ListViewHandle, lvitem->ItemCategory, - PH_PROCESS_TOKEN_INDEX_NAME, - fullName->Buffer, + PH_PROCESS_TOKEN_INDEX_NAME, + fullName->Buffer, lvitem ); @@ -447,7 +472,7 @@ VOID PhpUpdateSidsFromTokenGroups( PhSetListViewSubItem(ListViewHandle, lvItemIndex, PH_PROCESS_TOKEN_INDEX_DESCRIPTION, PhGetString(descriptionString)); PhDereferenceObject(descriptionString); } - + PhDereferenceObject(fullName); } } @@ -513,6 +538,7 @@ BOOLEAN PhpUpdateTokenPrivileges( PPHP_TOKEN_PAGE_LISTVIEW_ITEM lvitem; lvitem = PhAllocateZero(sizeof(PHP_TOKEN_PAGE_LISTVIEW_ITEM)); + lvitem->ItemCategory = PH_PROCESS_TOKEN_CATEGORY_PRIVILEGES; lvitem->TokenPrivilege = &privileges->Privileges[i]; privilegeDisplayName = NULL; @@ -544,6 +570,103 @@ BOOLEAN PhpUpdateTokenPrivileges( return TRUE; } +VOID PhpUpdateTokenDangerousFlagItem( + _In_ HWND ListViewHandle, + _In_ PH_PROCESS_TOKEN_FLAG Flag, + _In_ BOOLEAN State, + _In_ PWSTR Name, + _In_ PWSTR Description + ) +{ + INT lvItemIndex; + PPHP_TOKEN_PAGE_LISTVIEW_ITEM lvitem; + + lvitem = PhAllocateZero(sizeof(PHP_TOKEN_PAGE_LISTVIEW_ITEM)); + lvitem->ItemCategory = PH_PROCESS_TOKEN_CATEGORY_DANGEROUS_FLAGS; + lvitem->ItemFlag = Flag; + lvitem->ItemFlagState = State; + + lvItemIndex = PhAddListViewGroupItem( + ListViewHandle, + lvitem->ItemCategory, + PH_PROCESS_TOKEN_INDEX_NAME, + Name, + lvitem + ); + + PhSetListViewSubItem(ListViewHandle, + lvItemIndex, + PH_PROCESS_TOKEN_INDEX_STATUS, + State ? L"Enabled (modified)" : L"Disabled (modified)" + ); + + PhSetListViewSubItem( + ListViewHandle, + lvItemIndex, + PH_PROCESS_TOKEN_INDEX_DESCRIPTION, + Description + ); +} + +BOOLEAN PhpUpdateTokenDangerousFlags( + _In_ HWND hwndDlg, + _In_ PTOKEN_PAGE_CONTEXT TokenPageContext, + _In_ HWND ListViewHandle, + _In_ HANDLE TokenHandle + ) +{ + TOKEN_MANDATORY_POLICY mandatoryPolicy; + BOOLEAN isSandboxInert; + BOOLEAN isUIAccess; + + if (NT_SUCCESS(PhGetTokenMandatoryPolicy(TokenHandle, &mandatoryPolicy))) + { + // The disabled no-write-up policy is considered to be dangerous (diversenok) + if ((mandatoryPolicy.Policy & TOKEN_MANDATORY_POLICY_NO_WRITE_UP) == 0) + { + PhpUpdateTokenDangerousFlagItem( + ListViewHandle, + PH_PROCESS_TOKEN_FLAG_NO_WRITE_UP, + FALSE, + L"No-Write-Up Policy", + L"Prevents the process from modifying objects with a higher integrity" + ); + } + } + + if (NT_SUCCESS(PhGetTokenIsSandBoxInert(TokenHandle, &isSandboxInert))) + { + // The presence of SandboxInert flag is considered dangerous (diversenok) + if (isSandboxInert) + { + PhpUpdateTokenDangerousFlagItem( + ListViewHandle, + PH_PROCESS_TOKEN_FLAG_SANDBOX_INERT, + TRUE, + L"Sandbox Inert", + L"Ignore AppLocker rules and Software Restriction Policies" + ); + } + } + + if (NT_SUCCESS(PhGetTokenIsUIAccessEnabled(TokenHandle, &isUIAccess))) + { + // The presence of UIAccess flag is considered dangerous (diversenok) + if (isUIAccess) + { + PhpUpdateTokenDangerousFlagItem( + ListViewHandle, + PH_PROCESS_TOKEN_FLAG_UIACCESS, + TRUE, + L"UIAccess", + L"Ignore User Interface Privilege Isolation" + ); + } + } + + return TRUE; +} + FORCEINLINE PTOKEN_PAGE_CONTEXT PhpTokenPageHeader( _In_ HWND hwndDlg, _In_ UINT uMsg, @@ -592,6 +715,7 @@ INT_PTR CALLBACK PhpTokenPageProc( PhSetExtendedListView(tokenPageContext->ListViewHandle); ExtendedListView_SetItemColorFunction(tokenPageContext->ListViewHandle, PhpTokenGroupColorFunction); ListView_EnableGroupView(tokenPageContext->ListViewHandle, TRUE); + PhAddListViewGroup(tokenPageContext->ListViewHandle, PH_PROCESS_TOKEN_CATEGORY_DANGEROUS_FLAGS, L"Dangerous Flags"); PhAddListViewGroup(tokenPageContext->ListViewHandle, PH_PROCESS_TOKEN_CATEGORY_PRIVILEGES, L"Privileges"); PhAddListViewGroup(tokenPageContext->ListViewHandle, PH_PROCESS_TOKEN_CATEGORY_GROUPS, L"Groups"); PhAddListViewGroup(tokenPageContext->ListViewHandle, PH_PROCESS_TOKEN_CATEGORY_RESTRICTED, L"Restricting SIDs"); @@ -671,7 +795,7 @@ INT_PTR CALLBACK PhpTokenPageProc( if (appContainerInfo->TokenAppContainer) { appContainerName = PhGetAppContainerName(appContainerInfo->TokenAppContainer); - appContainerSid = PhSidToStringSid(appContainerInfo->TokenAppContainer); + appContainerSid = PhSidToStringSid(appContainerInfo->TokenAppContainer); } PhFree(appContainerInfo); @@ -698,6 +822,7 @@ INT_PTR CALLBACK PhpTokenPageProc( ExtendedListView_SetRedraw(tokenPageContext->ListViewHandle, FALSE); PhpTokenPageFreeListViewEntries(tokenPageContext); ListView_DeleteAllItems(tokenPageContext->ListViewHandle); + PhpUpdateTokenDangerousFlags(hwndDlg, tokenPageContext, tokenPageContext->ListViewHandle, tokenHandle); PhpUpdateTokenGroups(hwndDlg, tokenPageContext, tokenPageContext->ListViewHandle, tokenHandle); PhpUpdateTokenPrivileges(hwndDlg, tokenPageContext, tokenPageContext->ListViewHandle, tokenHandle); ExtendedListView_SortItems(tokenPageContext->ListViewHandle); @@ -771,7 +896,10 @@ INT_PTR CALLBACK PhpTokenPageProc( L"and is permanent for the lifetime of the process.", FALSE )) + { + PhFree(listViewItems); break; + } } status = tokenPageContext->OpenObject( @@ -877,6 +1005,7 @@ INT_PTR CALLBACK PhpTokenPageProc( } } + ExtendedListView_SortItems(tokenPageContext->ListViewHandle); ExtendedListView_SetRedraw(tokenPageContext->ListViewHandle, TRUE); NtClose(tokenHandle); @@ -887,8 +1016,6 @@ INT_PTR CALLBACK PhpTokenPageProc( } PhFree(listViewItems); - - ExtendedListView_SortItems(tokenPageContext->ListViewHandle); } break; case ID_GROUP_ENABLE: @@ -967,7 +1094,7 @@ INT_PTR CALLBACK PhpTokenPageProc( tokenPageContext->ListViewHandle, -1, listViewItems[i] - ); + ); // Refresh the status text (and background color). listViewItems[i]->TokenGroup->Attributes = newAttributes; @@ -1006,6 +1133,7 @@ INT_PTR CALLBACK PhpTokenPageProc( } } + ExtendedListView_SortItems(tokenPageContext->ListViewHandle); ExtendedListView_SetRedraw(tokenPageContext->ListViewHandle, TRUE); NtClose(tokenHandle); @@ -1016,8 +1144,85 @@ INT_PTR CALLBACK PhpTokenPageProc( } PhFree(listViewItems); + } + break; + case ID_UIACCESS_REMOVE: + { + NTSTATUS status; + PPHP_TOKEN_PAGE_LISTVIEW_ITEM *listViewItems; + ULONG numberOfItems; + HANDLE tokenHandle; + + PhGetSelectedListViewItemParams( + tokenPageContext->ListViewHandle, + &listViewItems, + &numberOfItems + ); + + if (numberOfItems != 1) + { + PhFree(listViewItems); + break; + } + + if ((listViewItems[0]->ItemCategory != PH_PROCESS_TOKEN_CATEGORY_DANGEROUS_FLAGS) || + (listViewItems[0]->ItemFlag != PH_PROCESS_TOKEN_FLAG_UIACCESS)) + { + PhFree(listViewItems); + break; + } + + if (!PhShowConfirmMessage( + hwndDlg, + L"remove", + L"the UIAccess flag", + L"Removing this flag may reduce the functionality of the process " + L"provided it is an accessibility application.", + FALSE + )) + { + PhFree(listViewItems); + break; + } - ExtendedListView_SortItems(tokenPageContext->ListViewHandle); + status = tokenPageContext->OpenObject( + &tokenHandle, + TOKEN_ADJUST_DEFAULT, + tokenPageContext->Context + ); + + if (NT_SUCCESS(status)) + { + ExtendedListView_SetRedraw(tokenPageContext->ListViewHandle, FALSE); + + status = PhSetTokenUIAccessEnabled(tokenHandle, FALSE); + + if (NT_SUCCESS(status)) + { + INT lvItemIndex = PhFindListViewItemByParam( + tokenPageContext->ListViewHandle, + -1, + listViewItems[0] + ); + + ListView_DeleteItem(tokenPageContext->ListViewHandle, lvItemIndex); + } + else + { + PhShowStatus(hwndDlg, L"Unable to disable UIAccess flag.", status, 0); + } + + ExtendedListView_SortItems(tokenPageContext->ListViewHandle); + ExtendedListView_SetRedraw(tokenPageContext->ListViewHandle, TRUE); + + NtClose(tokenHandle); + } + else + { + PhShowStatus(hwndDlg, L"Unable to open the token.", status, 0); + } + + PhFree(listViewItems); } break; case ID_PRIVILEGE_COPY: @@ -1106,7 +1311,7 @@ INT_PTR CALLBACK PhpTokenPageProc( if (customLevelPosition) { PPH_EMENU_ITEM unknownIntegrityItem; - + unknownIntegrityItem = PhCreateEMenuItem(0, (ULONG)integrityLevelRID, L"Intermediate level", NULL, NULL); unknownIntegrityItem->Flags |= PH_EMENU_CHECKED | PH_EMENU_RADIOCHECK; PhInsertEMenuItem(menu, unknownIntegrityItem, customLevelPosition); @@ -1271,6 +1476,12 @@ INT_PTR CALLBACK PhpTokenPageProc( PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX); } break; + case PH_PROCESS_TOKEN_CATEGORY_DANGEROUS_FLAGS: + { + if ((numberOfItems == 1) && (listviewItems[0]->ItemFlag == PH_PROCESS_TOKEN_FLAG_UIACCESS)) + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_UIACCESS_REMOVE, L"&Remove", NULL, NULL), ULONG_MAX); + } + break; } } diff --git a/phlib/include/phnativeinl.h b/phlib/include/phnativeinl.h index 1b24695deb15..87a4c48ffda4 100644 --- a/phlib/include/phnativeinl.h +++ b/phlib/include/phnativeinl.h @@ -1334,6 +1334,13 @@ PhGetTokenIsUIAccessEnabled( return status; } +/** +* Sets UIAccess flag for a token. +* +* \param TokenHandle A handle to a token. The handle must have TOKEN_ADJUST_DEFAULT access. +* \param IsUIAccessEnabled The new flag state. +* \remarks Enabling UIAccess requires SeTcbPrivilege. +*/ FORCEINLINE NTSTATUS PhSetTokenUIAccessEnabled( @@ -1387,6 +1394,34 @@ PhGetTokenIsSandBoxInert( return status; } +/** +* Gets Mandatory Policy for a token. +* +* \param TokenHandle A handle to a token. The handle must have TOKEN_QUERY access. +* \param MandatoryPolicy A variable which receives a set of mandatory integrity +* policies enforced for the token. +*/ +FORCEINLINE +NTSTATUS +PhGetTokenMandatoryPolicy( + _In_ HANDLE TokenHandle, + _Out_ PTOKEN_MANDATORY_POLICY MandatoryPolicy + ) +{ + NTSTATUS status; + ULONG returnLength; + + status = NtQueryInformationToken( + TokenHandle, + TokenMandatoryPolicy, + MandatoryPolicy, + sizeof(TOKEN_MANDATORY_POLICY), + &returnLength + ); + + return status; +} + FORCEINLINE NTSTATUS PhGetTokenOrigin( From 9113d230bfe7dc5edffe6067b4faf9bd0385f65b Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 26 Nov 2018 21:44:53 +0100 Subject: [PATCH 1468/2058] Remove legacy ProcessQueryAccess usage --- ProcessHacker/actions.c | 10 +++++----- ProcessHacker/affinity.c | 4 ++-- ProcessHacker/anawait.c | 2 +- ProcessHacker/chproc.c | 2 +- ProcessHacker/hidnproc.c | 16 ++++++++-------- ProcessHacker/hndlmenu.c | 6 +++--- ProcessHacker/mwpgproc.c | 2 +- ProcessHacker/netprv.c | 2 +- ProcessHacker/procprv.c | 2 +- ProcessHacker/proctree.c | 6 +++--- ProcessHacker/prpgenv.c | 4 ++-- ProcessHacker/prpggen.c | 4 ++-- ProcessHacker/prpgjob.c | 2 +- ProcessHacker/prpgtok.c | 2 +- ProcessHacker/runas.c | 2 +- ProcessHacker/thrdstk.c | 2 +- phlib/guisup.c | 2 +- phlib/hndlinfo.c | 2 +- phlib/native.c | 4 ++-- phlib/util.c | 2 +- 20 files changed, 39 insertions(+), 39 deletions(-) diff --git a/ProcessHacker/actions.c b/ProcessHacker/actions.c index fcd88756e83a..14dc68242a30 100644 --- a/ProcessHacker/actions.c +++ b/ProcessHacker/actions.c @@ -1336,7 +1336,7 @@ BOOLEAN PhUiRestartProcess( if (!NT_SUCCESS(status = PhOpenProcess( &processHandle, - ProcessQueryAccess | PROCESS_VM_READ, + PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_VM_READ, Process->ProcessId ))) goto ErrorExit; @@ -1577,7 +1577,7 @@ BOOLEAN PhUiSetVirtualizationProcess( if (NT_SUCCESS(status = PhOpenProcess( &processHandle, - ProcessQueryAccess, + PROCESS_QUERY_LIMITED_INFORMATION, Process->ProcessId ))) { @@ -1746,7 +1746,7 @@ BOOLEAN PhUiLoadDllProcess( if (NT_SUCCESS(status = PhOpenProcess( &processHandle, - ProcessQueryAccess | PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | + PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE, Process->ProcessId ))) @@ -2769,7 +2769,7 @@ BOOLEAN PhUiUnloadModule( case PH_MODULE_TYPE_WOW64_MODULE: if (NT_SUCCESS(status = PhOpenProcess( &processHandle, - ProcessQueryAccess | PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | + PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE, ProcessId ))) @@ -3181,7 +3181,7 @@ BOOLEAN PhUiSetAttributesHandle( if (NT_SUCCESS(status = PhOpenProcess( &processHandle, - ProcessQueryAccess, + PROCESS_QUERY_LIMITED_INFORMATION, ProcessId ))) { diff --git a/ProcessHacker/affinity.c b/ProcessHacker/affinity.c index 51e40efca93f..e3f121299122 100644 --- a/ProcessHacker/affinity.c +++ b/ProcessHacker/affinity.c @@ -128,7 +128,7 @@ static INT_PTR CALLBACK PhpProcessAffinityDlgProc( if (NT_SUCCESS(status = PhOpenProcess( &processHandle, - ProcessQueryAccess, + PROCESS_QUERY_LIMITED_INFORMATION, context->ProcessItem->ProcessId ))) { @@ -164,7 +164,7 @@ static INT_PTR CALLBACK PhpProcessAffinityDlgProc( if (NT_SUCCESS(PhOpenProcess( &processHandle, - ProcessQueryAccess, + PROCESS_QUERY_LIMITED_INFORMATION, basicInfo.ClientId.UniqueProcess ))) { diff --git a/ProcessHacker/anawait.c b/ProcessHacker/anawait.c index 1223ebb8532e..95a4c4e9a641 100644 --- a/ProcessHacker/anawait.c +++ b/ProcessHacker/anawait.c @@ -124,7 +124,7 @@ VOID PhUiAnalyzeWaitThread( #ifdef _WIN64 // Determine if the process is WOW64. If not, we use the passive method. - if (!NT_SUCCESS(status = PhOpenProcess(&processHandle, ProcessQueryAccess, ProcessId))) + if (!NT_SUCCESS(status = PhOpenProcess(&processHandle, PROCESS_QUERY_LIMITED_INFORMATION, ProcessId))) { PhShowStatus(hWnd, L"Unable to open the process", status, 0); return; diff --git a/ProcessHacker/chproc.c b/ProcessHacker/chproc.c index 8dac71dd0d94..c1eae2d61438 100644 --- a/ProcessHacker/chproc.c +++ b/ProcessHacker/chproc.c @@ -111,7 +111,7 @@ static VOID PhpRefreshProcessList( lvItemIndex = PhAddListViewItem(Context->ListViewHandle, MAXINT, name->Buffer, process->UniqueProcessId); PhDereferenceObject(name); - if (NT_SUCCESS(PhOpenProcess(&processHandle, ProcessQueryAccess, process->UniqueProcessId))) + if (NT_SUCCESS(PhOpenProcess(&processHandle, PROCESS_QUERY_LIMITED_INFORMATION, process->UniqueProcessId))) { HANDLE tokenHandle; PTOKEN_USER user; diff --git a/ProcessHacker/hidnproc.c b/ProcessHacker/hidnproc.c index cca818123369..05bb15d90559 100644 --- a/ProcessHacker/hidnproc.c +++ b/ProcessHacker/hidnproc.c @@ -583,7 +583,7 @@ static PPH_PROCESS_ITEM PhpCreateProcessItemForHiddenProcess( { status = PhOpenProcess( &processHandle, - ProcessQueryAccess, + PROCESS_QUERY_LIMITED_INFORMATION, Entry->ProcessId ); } @@ -591,7 +591,7 @@ static PPH_PROCESS_ITEM PhpCreateProcessItemForHiddenProcess( { status = PhOpenProcessByCsrHandles( &processHandle, - ProcessQueryAccess, + PROCESS_QUERY_LIMITED_INFORMATION, Entry->ProcessId ); } @@ -674,7 +674,7 @@ static PPH_PROCESS_ITEM PhpCreateProcessItemForHiddenProcess( status = PhOpenProcess( &processHandle2, - ProcessQueryAccess | PROCESS_VM_READ, + PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_VM_READ, Entry->ProcessId ); @@ -746,7 +746,7 @@ NTSTATUS PhpEnumHiddenProcessesBruteForce( status2 = PhOpenProcess( &processHandle, - ProcessQueryAccess, + PROCESS_QUERY_LIMITED_INFORMATION, UlongToHandle(pid) ); @@ -849,7 +849,7 @@ static BOOLEAN NTAPI PhpCsrProcessHandlesCallback( if (NT_SUCCESS(status = PhOpenProcessByCsrHandle( &processHandle, - ProcessQueryAccess, + PROCESS_QUERY_LIMITED_INFORMATION, Handle ))) { @@ -943,7 +943,7 @@ NTSTATUS PhpEnumHiddenProcessHandles( if (!NT_SUCCESS(status = NtGetNextProcess( NULL, - ProcessQueryAccess, + PROCESS_QUERY_LIMITED_INFORMATION, 0, 0, &processHandle @@ -991,7 +991,7 @@ NTSTATUS PhpEnumHiddenProcessHandles( if (NT_SUCCESS(status = NtGetNextProcess( processHandle, - ProcessQueryAccess, + PROCESS_QUERY_LIMITED_INFORMATION, 0, 0, &enumProcessHandle @@ -1059,7 +1059,7 @@ NTSTATUS PhpOpenCsrProcesses( if (NT_SUCCESS(PhOpenProcess( &processHandle, - ProcessQueryAccess | PROCESS_DUP_HANDLE, + PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_DUP_HANDLE, process->UniqueProcessId ))) { diff --git a/ProcessHacker/hndlmenu.c b/ProcessHacker/hndlmenu.c index beaddf8b4c86..6f317ed61656 100644 --- a/ProcessHacker/hndlmenu.c +++ b/ProcessHacker/hndlmenu.c @@ -155,7 +155,7 @@ VOID PhShowHandleObjectProperties1( { if (NT_SUCCESS(PhOpenProcess( &processHandle, - ProcessQueryAccess, + PROCESS_QUERY_LIMITED_INFORMATION, Info->ProcessId ))) { @@ -183,7 +183,7 @@ VOID PhShowHandleObjectProperties1( if (NT_SUCCESS(PhpDuplicateHandleFromProcessItem( &handle, - ProcessQueryAccess, + PROCESS_QUERY_LIMITED_INFORMATION, Info->ProcessId, Info->Handle ))) @@ -325,7 +325,7 @@ VOID PhShowHandleObjectProperties1( { if (NT_SUCCESS(PhOpenProcess( &processHandle, - ProcessQueryAccess, + PROCESS_QUERY_LIMITED_INFORMATION, Info->ProcessId ))) { diff --git a/ProcessHacker/mwpgproc.c b/ProcessHacker/mwpgproc.c index 8f1cf435dda9..8fe568514eef 100644 --- a/ProcessHacker/mwpgproc.c +++ b/ProcessHacker/mwpgproc.c @@ -392,7 +392,7 @@ VOID PhMwpSetProcessMenuPriorityChecks( if (NT_SUCCESS(PhOpenProcess( &processHandle, - ProcessQueryAccess, + PROCESS_QUERY_LIMITED_INFORMATION, ProcessId ))) { diff --git a/ProcessHacker/netprv.c b/ProcessHacker/netprv.c index fee6cc9a4c38..3b1cafec2370 100644 --- a/ProcessHacker/netprv.c +++ b/ProcessHacker/netprv.c @@ -679,7 +679,7 @@ VOID PhNetworkProviderUpdate( // The socket handle remains valid and in-use by the child process BUT the socket continues returning the PID of the exited process??? // Fixing this causes a major performance problem; If we have 100,000 sockets then on previous versions of Windows we would only need 2 system calls maximum // (for the process list) to identify the owner of every socket but now we need to make 4 system calls for every_last_socket totaling 400,000 system calls... great. - if (NT_SUCCESS(PhOpenProcess(&processHandle, ProcessQueryAccess, networkItem->ProcessId))) + if (NT_SUCCESS(PhOpenProcess(&processHandle, PROCESS_QUERY_LIMITED_INFORMATION, networkItem->ProcessId))) { if (NT_SUCCESS(PhGetProcessExtendedBasicInformation(processHandle, &basicInfo))) { diff --git a/ProcessHacker/procprv.c b/ProcessHacker/procprv.c index 14b2ade00de7..e785498cabaa 100644 --- a/ProcessHacker/procprv.c +++ b/ProcessHacker/procprv.c @@ -760,7 +760,7 @@ VOID PhpProcessQueryStage1( { status = PhOpenProcess( &processHandle, - ProcessQueryAccess | PROCESS_VM_READ, + PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_VM_READ, processId ); } diff --git a/ProcessHacker/proctree.c b/ProcessHacker/proctree.c index b315ae497629..ccd285724be0 100644 --- a/ProcessHacker/proctree.c +++ b/ProcessHacker/proctree.c @@ -1024,7 +1024,7 @@ static VOID PhpUpdateProcessOsContext( { HANDLE processHandle; - if (NT_SUCCESS(PhOpenProcess(&processHandle, ProcessQueryAccess | PROCESS_VM_READ, ProcessNode->ProcessId))) + if (NT_SUCCESS(PhOpenProcess(&processHandle, PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_VM_READ, ProcessNode->ProcessId))) { if (NT_SUCCESS(PhGetProcessSwitchContext(processHandle, &ProcessNode->OsContextGuid))) { @@ -1092,7 +1092,7 @@ static VOID PhpUpdateProcessNodeImage( PVOID imageBaseAddress; PH_REMOTE_MAPPED_IMAGE mappedImage; - if (NT_SUCCESS(PhOpenProcess(&processHandle, ProcessQueryAccess | PROCESS_VM_READ, ProcessNode->ProcessId))) + if (NT_SUCCESS(PhOpenProcess(&processHandle, PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_VM_READ, ProcessNode->ProcessId))) { if (NT_SUCCESS(PhGetProcessBasicInformation(processHandle, &basicInfo)) && basicInfo.PebBaseAddress != 0) { @@ -1288,7 +1288,7 @@ static VOID PhpUpdateProcessNodeDesktopInfo( if (NT_SUCCESS(PhOpenProcess( &processHandle, - ProcessQueryAccess | PROCESS_VM_READ, + PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_VM_READ, ProcessNode->ProcessId ))) { diff --git a/ProcessHacker/prpgenv.c b/ProcessHacker/prpgenv.c index 318eee8e3d22..1c10acd44745 100644 --- a/ProcessHacker/prpgenv.c +++ b/ProcessHacker/prpgenv.c @@ -400,7 +400,7 @@ INT_PTR CALLBACK PhpEditEnvDlgProc( { if (NT_SUCCESS(status = PhOpenProcess( &processHandle, - ProcessQueryAccess | PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | + PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE, context->ProcessItem->ProcessId ))) @@ -591,7 +591,7 @@ VOID PhpShowEnvironmentNodeContextMenu( if (NT_SUCCESS(status = PhOpenProcess( &processHandle, - ProcessQueryAccess | PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | + PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE, Context->ProcessItem->ProcessId ))) diff --git a/ProcessHacker/prpggen.c b/ProcessHacker/prpggen.c index cea7c5852bf8..ff776ebe4b34 100644 --- a/ProcessHacker/prpggen.c +++ b/ProcessHacker/prpggen.c @@ -290,7 +290,7 @@ INT_PTR CALLBACK PhpProcessGeneralDlgProc( if (NT_SUCCESS(PhOpenProcess( &processHandle, - ProcessQueryAccess | PROCESS_VM_READ, + PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_VM_READ, processItem->ProcessId ))) { @@ -372,7 +372,7 @@ INT_PTR CALLBACK PhpProcessGeneralDlgProc( if (NT_SUCCESS(PhOpenProcess( &processHandle, - ProcessQueryAccess, + PROCESS_QUERY_LIMITED_INFORMATION, processItem->ProcessId ))) { diff --git a/ProcessHacker/prpgjob.c b/ProcessHacker/prpgjob.c index fcbe8ae1e249..6cdf17d9f82d 100644 --- a/ProcessHacker/prpgjob.c +++ b/ProcessHacker/prpgjob.c @@ -38,7 +38,7 @@ NTSTATUS NTAPI PhpOpenProcessJobForPage( if (!NT_SUCCESS(status = PhOpenProcess( &processHandle, - ProcessQueryAccess, + PROCESS_QUERY_LIMITED_INFORMATION, (HANDLE)Context ))) return status; diff --git a/ProcessHacker/prpgtok.c b/ProcessHacker/prpgtok.c index 1a94e21a1664..3baa10d2733f 100644 --- a/ProcessHacker/prpgtok.c +++ b/ProcessHacker/prpgtok.c @@ -38,7 +38,7 @@ NTSTATUS NTAPI PhpOpenProcessTokenForPage( if (!NT_SUCCESS(status = PhOpenProcess( &processHandle, - ProcessQueryAccess, + PROCESS_QUERY_LIMITED_INFORMATION, (HANDLE)Context ))) return status; diff --git a/ProcessHacker/runas.c b/ProcessHacker/runas.c index 03d48ea8b2a7..5571d2bf7efd 100644 --- a/ProcessHacker/runas.c +++ b/ProcessHacker/runas.c @@ -906,7 +906,7 @@ INT_PTR CALLBACK PhpRunAsDlgProc( if (NT_SUCCESS(PhOpenProcess( &processHandle, - ProcessQueryAccess, + PROCESS_QUERY_LIMITED_INFORMATION, context->ProcessId ))) { diff --git a/ProcessHacker/thrdstk.c b/ProcessHacker/thrdstk.c index 6b055893c5d6..34c694a530af 100644 --- a/ProcessHacker/thrdstk.c +++ b/ProcessHacker/thrdstk.c @@ -720,7 +720,7 @@ VOID PhShowThreadStackDialog( { status = PhOpenThread( &threadHandle, - ThreadQueryAccess, + THREAD_QUERY_LIMITED_INFORMATION, ThreadId ); } diff --git a/phlib/guisup.c b/phlib/guisup.c index d1e6a766da46..cc3a8fa26d88 100644 --- a/phlib/guisup.c +++ b/phlib/guisup.c @@ -1495,7 +1495,7 @@ HWND PhGetProcessMainWindowEx( if (ProcessHandle) processHandle = ProcessHandle; else - PhOpenProcess(&processHandle, ProcessQueryAccess, ProcessId); + PhOpenProcess(&processHandle, PROCESS_QUERY_LIMITED_INFORMATION, ProcessId); if (processHandle && IsImmersiveProcess_I) context.IsImmersive = IsImmersiveProcess_I(processHandle); diff --git a/phlib/hndlinfo.c b/phlib/hndlinfo.c index 6da6ffa923fd..38290ad64f65 100644 --- a/phlib/hndlinfo.c +++ b/phlib/hndlinfo.c @@ -818,7 +818,7 @@ NTSTATUS PhpGetBestObjectName( Handle, NtCurrentProcess(), &dupHandle, - ProcessQueryAccess, + PROCESS_QUERY_LIMITED_INFORMATION, 0, 0 ); diff --git a/phlib/native.c b/phlib/native.c index 9bd40c76adfe..e054dba0bf95 100644 --- a/phlib/native.c +++ b/phlib/native.c @@ -4871,7 +4871,7 @@ NTSTATUS PhGetProcessIsDotNetEx( if (!ProcessHandle) { - if (!NT_SUCCESS(status = PhOpenProcess(&processHandle, ProcessQueryAccess | PROCESS_VM_READ, ProcessId))) + if (!NT_SUCCESS(status = PhOpenProcess(&processHandle, PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_VM_READ, ProcessId))) return status; ProcessHandle = processHandle; @@ -6078,7 +6078,7 @@ NTSTATUS PhEnumGenericModules( { if (!NT_SUCCESS(status = PhOpenProcess( &ProcessHandle, - ProcessQueryAccess | PROCESS_VM_READ, + PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_VM_READ, ProcessId ))) { diff --git a/phlib/util.c b/phlib/util.c index fca92f3f7615..7c7dba75a8a1 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -2762,7 +2762,7 @@ NTSTATUS PhCreateProcessAsUser( if (!NT_SUCCESS(status = PhOpenProcess( &processHandle, - ProcessQueryAccess, + PROCESS_QUERY_LIMITED_INFORMATION, Information->ProcessIdWithToken ))) return status; From 44a3b3b59c2c8af681a73d58c8bda55375a6f383 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 26 Nov 2018 21:53:55 +0100 Subject: [PATCH 1469/2058] Add workaround for some dark-theme issues --- ProcessHacker/mainwnd.c | 5 ++++- phlib/include/guisup.h | 2 +- phlib/theme.c | 27 +++++++++++++++++++-------- 3 files changed, 24 insertions(+), 10 deletions(-) diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index 3f30fa426a75..c2615db78b08 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -2740,11 +2740,14 @@ VOID PhMwpSelectionChangedTabControl( { CurrentPage = page; - // Create the tab page window if it doesn't exist. + // Create the tab page window if it doesn't exist. (wj32) if (!page->WindowHandle && !page->CreateWindowCalled) { if (page->Callback(page, MainTabPageCreateWindow, &page->WindowHandle, NULL)) + { page->CreateWindowCalled = TRUE; + PhInitializeWindowTheme(PhMainWndHandle, PhEnableThemeSupport); // TODO: Remove PhMainWndHandle enumeration (dmex) + } if (page->WindowHandle) BringWindowToTop(page->WindowHandle); diff --git a/phlib/include/guisup.h b/phlib/include/guisup.h index c98adb5497fe..37dfea2a3b28 100644 --- a/phlib/include/guisup.h +++ b/phlib/include/guisup.h @@ -958,7 +958,7 @@ PhDuplicateFontWithNewHeight( if (GetObject(Font, sizeof(LOGFONT), &logFont)) { - logFont.lfHeight = NewHeight; + logFont.lfHeight = PhMultiplyDivide(NewHeight, PhGlobalDpi, 96); return CreateFontIndirect(&logFont); } diff --git a/phlib/theme.c b/phlib/theme.c index 2935129fb5a0..ce079ebaa150 100644 --- a/phlib/theme.c +++ b/phlib/theme.c @@ -114,17 +114,24 @@ VOID PhInitializeWindowTheme( PhpThemeEnable = !!PhGetIntegerSetting(L"EnableThemeSupport"); PhpThemeBorderEnable = !!PhGetIntegerSetting(L"TreeListBorderEnable"); - if (!PhMenuBackgroundBrush) // HACK + switch (PhpThemeColorMode) { - switch (PhpThemeColorMode) // HACK + case 0: // New colors { - case 0: // New colors + if (PhMenuBackgroundBrush) + DeleteBrush(PhMenuBackgroundBrush); + PhMenuBackgroundBrush = CreateSolidBrush(PhpThemeWindowTextColor); - break; - case 1: // Old colors + } + break; + case 1: // Old colors + { + if (PhMenuBackgroundBrush) + DeleteBrush(PhMenuBackgroundBrush); + PhMenuBackgroundBrush = CreateSolidBrush(PhpThemeWindowForegroundColor); - break; } + break; } if (EnableThemeSupport) @@ -132,8 +139,12 @@ VOID PhInitializeWindowTheme( WNDPROC defaultWindowProc; defaultWindowProc = (WNDPROC)GetWindowLongPtr(WindowHandle, GWLP_WNDPROC); - PhSetWindowContext(WindowHandle, SHRT_MAX, defaultWindowProc); - SetWindowLongPtr(WindowHandle, GWLP_WNDPROC, (LONG_PTR)PhpThemeWindowSubclassProc); + + if (defaultWindowProc != PhpThemeWindowSubclassProc) + { + PhSetWindowContext(WindowHandle, SHRT_MAX, defaultWindowProc); + SetWindowLongPtr(WindowHandle, GWLP_WNDPROC, (LONG_PTR)PhpThemeWindowSubclassProc); + } PhEnumChildWindows( WindowHandle, From b7055cd505c6e01a1e3127b567c224aaaf41c413 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 28 Nov 2018 15:32:28 +0100 Subject: [PATCH 1470/2058] peview: Fix flags (reported by @TheEragon) --- tools/peview/ldprp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/peview/ldprp.c b/tools/peview/ldprp.c index f7591c0ab35d..391f33edadaa 100644 --- a/tools/peview/ldprp.c +++ b/tools/peview/ldprp.c @@ -120,7 +120,7 @@ INT_PTR CALLBACK PvpPeLoadConfigDlgProc( \ if (RTL_CONTAINS_FIELD((Config), (Config)->Size, GuardCFCheckFunctionPointer)) \ { \ - ADD_VALUE(L"CFG GuardFlags", PhaFormatString(L"0x%Ix", PH_AUTO_T(PH_STRING, PvpGetPeGuardFlagsText((Config)->GuardFlags))->Buffer, (Config)->GuardFlags)->Buffer); \ + ADD_VALUE(L"CFG GuardFlags", PhaFormatString(L"%s (0x%Ix)", PH_AUTO_T(PH_STRING, PvpGetPeGuardFlagsText((Config)->GuardFlags))->Buffer, (Config)->GuardFlags)->Buffer); \ ADD_VALUE(L"CFG Check Function pointer", PhaFormatString(L"0x%Ix", (Config)->GuardCFCheckFunctionPointer)->Buffer); \ ADD_VALUE(L"CFG Check Dispatch pointer", PhaFormatString(L"0x%Ix", (Config)->GuardCFDispatchFunctionPointer)->Buffer); \ ADD_VALUE(L"CFG Function table", PhaFormatString(L"0x%Ix", (Config)->GuardCFFunctionTable)->Buffer); \ From 38c3b3d9ff25db32a703844bce08a96bd44040cd Mon Sep 17 00:00:00 2001 From: TheEragon Date: Thu, 29 Nov 2018 10:29:27 +0100 Subject: [PATCH 1471/2058] Retpoline support (#343) * peview: Add retpoline flag support * peview: Use proper format specifier for GuardFlags --- tools/peview/ldprp.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tools/peview/ldprp.c b/tools/peview/ldprp.c index 391f33edadaa..b71348a3df28 100644 --- a/tools/peview/ldprp.c +++ b/tools/peview/ldprp.c @@ -49,6 +49,8 @@ PPH_STRING PvpGetPeGuardFlagsText( PhAppendStringBuilder2(&stringBuilder, L"Export information supression, "); if (GuardFlags & IMAGE_GUARD_CF_LONGJUMP_TABLE_PRESENT) PhAppendStringBuilder2(&stringBuilder, L"Longjump table, "); + if (GuardFlags & IMAGE_GUARD_RETPOLINE_PRESENT) + PhAppendStringBuilder2(&stringBuilder, L"Retpoline present, "); if (PhEndsWithString2(stringBuilder.String, L", ", FALSE)) PhRemoveEndStringBuilder(&stringBuilder, 2); @@ -120,7 +122,7 @@ INT_PTR CALLBACK PvpPeLoadConfigDlgProc( \ if (RTL_CONTAINS_FIELD((Config), (Config)->Size, GuardCFCheckFunctionPointer)) \ { \ - ADD_VALUE(L"CFG GuardFlags", PhaFormatString(L"%s (0x%Ix)", PH_AUTO_T(PH_STRING, PvpGetPeGuardFlagsText((Config)->GuardFlags))->Buffer, (Config)->GuardFlags)->Buffer); \ + ADD_VALUE(L"CFG GuardFlags", PhaFormatString(L"%s (0x%x)", PH_AUTO_T(PH_STRING, PvpGetPeGuardFlagsText((Config)->GuardFlags))->Buffer, (Config)->GuardFlags)->Buffer); \ ADD_VALUE(L"CFG Check Function pointer", PhaFormatString(L"0x%Ix", (Config)->GuardCFCheckFunctionPointer)->Buffer); \ ADD_VALUE(L"CFG Check Dispatch pointer", PhaFormatString(L"0x%Ix", (Config)->GuardCFDispatchFunctionPointer)->Buffer); \ ADD_VALUE(L"CFG Function table", PhaFormatString(L"0x%Ix", (Config)->GuardCFFunctionTable)->Buffer); \ From aa6fd10b5c68f16801bfcea331d019b6a1b05885 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 6 Dec 2018 19:14:53 +0100 Subject: [PATCH 1472/2058] Partial revert 77f43a80 (re-add strict version checking for KPH on Win10), Add missing 32bit KPH offsets --- phlib/kphdata.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/phlib/kphdata.c b/phlib/kphdata.c index d15072cedbf2..61e4e6a9dbfd 100644 --- a/phlib/kphdata.c +++ b/phlib/kphdata.c @@ -160,9 +160,7 @@ NTSTATUS KphInitializeDynamicPackage( Package->ResultingNtVersion = PHNT_REDSTONE5; break; default: - Package->BuildNumber = USHRT_MAX; - Package->ResultingNtVersion = PHNT_THRESHOLD; - break; + return STATUS_NOT_SUPPORTED; } Package->StructData.EgeGuid = 0x18; @@ -291,10 +289,16 @@ NTSTATUS KphInitializeDynamicPackage( Package->BuildNumber = 16299; Package->ResultingNtVersion = PHNT_REDSTONE3; break; - default: - Package->BuildNumber = USHRT_MAX; - Package->ResultingNtVersion = PHNT_THRESHOLD; + case 17134: + Package->BuildNumber = 17134; + Package->ResultingNtVersion = PHNT_REDSTONE4; break; + case 17763: + Package->BuildNumber = 17763; + Package->ResultingNtVersion = PHNT_REDSTONE5; + break; + default: + return STATUS_NOT_SUPPORTED; } Package->StructData.EgeGuid = 0xc; From ad4bc71f345e4c3437bd6e24ffaa66b0276cac41 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 6 Dec 2018 20:03:30 +0100 Subject: [PATCH 1473/2058] Update retpoline types --- phnt/include/ntexapi.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/phnt/include/ntexapi.h b/phnt/include/ntexapi.h index 6dafdd2896e3..0ba0dbcd6526 100644 --- a/phnt/include/ntexapi.h +++ b/phnt/include/ntexapi.h @@ -3240,7 +3240,9 @@ typedef struct _SYSTEM_SPECULATION_CONTROL_INFORMATION ULONG SpeculativeStoreBypassDisabledKernel : 1; ULONG SpeculativeStoreBypassDisableRequired : 1; ULONG BpbDisabledKernelToUser : 1; - ULONG Reserved : 18; + ULONG SpecCtrlRetpolineEnabled : 1; + ULONG SpecCtrlImportOptimizationEnabled : 1; + ULONG Reserved : 16; }; }; } SYSTEM_SPECULATION_CONTROL_INFORMATION, *PSYSTEM_SPECULATION_CONTROL_INFORMATION; From ace90c8c386a8b2bdb8b1df0ddb9625f8db9ed9c Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 14 Dec 2018 00:49:22 +0100 Subject: [PATCH 1474/2058] NetworkTools: Fix disabling ping/tracert for LAN addresses --- plugins/NetworkTools/main.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/plugins/NetworkTools/main.c b/plugins/NetworkTools/main.c index b5a09c71ca74..cb30a4edfb6e 100644 --- a/plugins/NetworkTools/main.c +++ b/plugins/NetworkTools/main.c @@ -313,14 +313,18 @@ VOID NTAPI NetworkMenuInitializingCallback( { if ( IN4_IS_ADDR_UNSPECIFIED(&networkItem->RemoteEndpoint.Address.InAddr) || - IN4_IS_ADDR_LOOPBACK(&networkItem->RemoteEndpoint.Address.InAddr) || - IN4_IS_ADDR_RFC1918(&networkItem->RemoteEndpoint.Address.InAddr) + IN4_IS_ADDR_LOOPBACK(&networkItem->RemoteEndpoint.Address.InAddr) ) { PhSetDisabledEMenuItem(whoisMenu); PhSetDisabledEMenuItem(traceMenu); PhSetDisabledEMenuItem(pingMenu); } + + if (IN4_IS_ADDR_RFC1918(&networkItem->RemoteEndpoint.Address.InAddr)) + { + PhSetDisabledEMenuItem(whoisMenu); + } } else if (networkItem->RemoteEndpoint.Address.Type == PH_IPV6_NETWORK_TYPE) { @@ -1000,4 +1004,4 @@ LOGICAL DllMain( } return TRUE; -} \ No newline at end of file +} From 931bfb9480d9ff37d279d3f8e1a27bb5ac30e333 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 14 Dec 2018 01:10:09 +0100 Subject: [PATCH 1475/2058] Partially fix process username caching --- ProcessHacker/proctree.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ProcessHacker/proctree.c b/ProcessHacker/proctree.c index ccd285724be0..2a595a95d5e0 100644 --- a/ProcessHacker/proctree.c +++ b/ProcessHacker/proctree.c @@ -843,7 +843,7 @@ static VOID PhpUpdateProcessNodeUserName( { if (ProcessNode->ProcessItem->Sid) { - ProcessNode->UserName = PhGetSidFullName(ProcessNode->ProcessItem->Sid, TRUE, NULL); + PhMoveReference(&ProcessNode->UserName, PhGetSidFullName(ProcessNode->ProcessItem->Sid, TRUE, NULL)); } ProcessNode->ValidMask |= PHPN_USERNAME; From 3c85582b174730eb99e7c2ab8261b61169aa269f Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 14 Dec 2018 01:15:08 +0100 Subject: [PATCH 1476/2058] Add prototypes for RS5 uxtheme dark theme support --- phlib/theme.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/phlib/theme.c b/phlib/theme.c index ce079ebaa150..65767bf15381 100644 --- a/phlib/theme.c +++ b/phlib/theme.c @@ -90,6 +90,20 @@ LRESULT CALLBACK PhpThemeWindowStatusbarWndSubclassProc( _In_ LPARAM lParam ); +// rev // Win10-RS5 (uxtheme.dll ordinal 132) +BOOLEAN (WINAPI *ShouldAppsUseDarkMode_I)( + VOID + ) = NULL; +// rev // Win10-RS5 (uxtheme.dll ordinal 133) +BOOLEAN (WINAPI *AllowDarkModeForWindow_I)( + _In_ HWND WindowHandle, + _In_ BOOL Enabled + ) = NULL; +// rev // Win10-RS5 (uxtheme.dll ordinal 137) +BOOLEAN (WINAPI *IsDarkModeAllowedForWindow_I)( + _In_ HWND WindowHandle + ) = NULL; + ULONG PhpThemeColorMode = 0; BOOLEAN PhpThemeEnable = FALSE; BOOLEAN PhpThemeBorderEnable = TRUE; From f382dbc76380137c9230892962b1ac25997f999e Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 14 Dec 2018 02:17:32 +0100 Subject: [PATCH 1477/2058] Fix incorrect variable name --- phlib/util.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/phlib/util.c b/phlib/util.c index 7c7dba75a8a1..60458c2cadd7 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -5636,7 +5636,7 @@ PVOID PhGetLoaderEntryImageExportFunction( _In_opt_ USHORT ExportOrdinal ) { - PVOID baseAddress = NULL; + PVOID exportAddress = NULL; PULONG exportAddressTable; PULONG exportNameTable; PUSHORT exportOrdinalTable; @@ -5650,7 +5650,7 @@ PVOID PhGetLoaderEntryImageExportFunction( if (ExportOrdinal > ExportDirectory->Base + ExportDirectory->NumberOfFunctions) return NULL; - baseAddress = PTR_ADD_OFFSET(BaseAddress, exportAddressTable[ExportOrdinal - ExportDirectory->Base]); + exportAddress = PTR_ADD_OFFSET(BaseAddress, exportAddressTable[ExportOrdinal - ExportDirectory->Base]); } else if (ExportName) { @@ -5658,18 +5658,18 @@ PVOID PhGetLoaderEntryImageExportFunction( { if (PhEqualBytesZ(ExportName, PTR_ADD_OFFSET(BaseAddress, exportNameTable[i]), FALSE)) { - baseAddress = PTR_ADD_OFFSET(BaseAddress, exportAddressTable[exportOrdinalTable[i]]); + exportAddress = PTR_ADD_OFFSET(BaseAddress, exportAddressTable[exportOrdinalTable[i]]); break; } } } - if (!baseAddress) + if (!exportAddress) return NULL; if ( - ((ULONG_PTR)baseAddress >= (ULONG_PTR)ExportDirectory) && - ((ULONG_PTR)baseAddress < (ULONG_PTR)PTR_ADD_OFFSET(ExportDirectory, DataDirectory->Size)) + ((ULONG_PTR)exportAddress >= (ULONG_PTR)ExportDirectory) && + ((ULONG_PTR)exportAddress < (ULONG_PTR)PTR_ADD_OFFSET(ExportDirectory, DataDirectory->Size)) ) { PPH_STRING dllForwarderString; @@ -5678,7 +5678,7 @@ PVOID PhGetLoaderEntryImageExportFunction( // This is a forwarder RVA. - dllForwarderString = PhZeroExtendToUtf16((PSTR)baseAddress); + dllForwarderString = PhZeroExtendToUtf16((PSTR)exportAddress); if (PhSplitStringRefAtChar(&dllForwarderString->sr, L'.', &dllNameRef, &dllProcedureRef)) { @@ -5691,7 +5691,7 @@ PVOID PhGetLoaderEntryImageExportFunction( if (libraryModule = LoadLibrary(libraryNameString->Buffer)) { - baseAddress = PhGetDllBaseProcedureAddress(libraryModule, libraryFunctionString->Buffer, 0); + exportAddress = PhGetDllBaseProcedureAddress(libraryModule, libraryFunctionString->Buffer, 0); } PhDereferenceObject(libraryFunctionString); @@ -5701,7 +5701,7 @@ PVOID PhGetLoaderEntryImageExportFunction( PhDereferenceObject(dllForwarderString); } - return baseAddress; + return exportAddress; } static NTSTATUS PhpFixupLoaderEntryImageImports( From d5018507eb964a070219918e141f73a26c23c3a4 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 15 Dec 2018 01:51:58 +0100 Subject: [PATCH 1478/2058] WindowExplorer: Fix search after selecting refresh --- plugins/WindowExplorer/wnddlg.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/plugins/WindowExplorer/wnddlg.c b/plugins/WindowExplorer/wnddlg.c index 7e0c02be7823..6d8554431898 100644 --- a/plugins/WindowExplorer/wnddlg.c +++ b/plugins/WindowExplorer/wnddlg.c @@ -458,7 +458,13 @@ INT_PTR CALLBACK WepWindowsDlgProc( DestroyWindow(hwndDlg); break; case IDC_REFRESH: - WepRefreshWindows(context); + { + WepRefreshWindows(context); + + PhApplyTreeNewFilters(&context->TreeContext.FilterSupport); + + TreeNew_NodesStructured(context->TreeNewHandle); + } break; case ID_SHOWCONTEXTMENU: { From 804bccaea1350aba14708f7747d72c39b272f2a4 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 15 Dec 2018 05:16:04 +0100 Subject: [PATCH 1479/2058] Fix symbol name length --- phlib/symprv.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/phlib/symprv.c b/phlib/symprv.c index 9f0638d28c4b..fd902eebedf6 100644 --- a/phlib/symprv.c +++ b/phlib/symprv.c @@ -558,8 +558,7 @@ PPH_STRING PhGetSymbolFromAddress( if (!SymFromAddrW_I) return NULL; - symbolInfo = PhAllocate(FIELD_OFFSET(SYMBOL_INFOW, Name) + PH_MAX_SYMBOL_NAME_LEN * 2); - memset(symbolInfo, 0, sizeof(SYMBOL_INFOW)); + symbolInfo = PhAllocateZero(FIELD_OFFSET(SYMBOL_INFOW, Name) + PH_MAX_SYMBOL_NAME_LEN * sizeof(WCHAR)); symbolInfo->SizeOfStruct = sizeof(SYMBOL_INFOW); symbolInfo->MaxNameLen = PH_MAX_SYMBOL_NAME_LEN; @@ -582,8 +581,7 @@ PPH_STRING PhGetSymbolFromAddress( if (nameLength + 1 > PH_MAX_SYMBOL_NAME_LEN) { PhFree(symbolInfo); - symbolInfo = PhAllocate(FIELD_OFFSET(SYMBOL_INFOW, Name) + nameLength * 2 + 2); - memset(symbolInfo, 0, sizeof(SYMBOL_INFOW)); + symbolInfo = PhAllocateZero(FIELD_OFFSET(SYMBOL_INFOW, Name) + nameLength * sizeof(WCHAR) + sizeof(UNICODE_NULL)); symbolInfo->SizeOfStruct = sizeof(SYMBOL_INFOW); symbolInfo->MaxNameLen = nameLength + 1; @@ -632,7 +630,7 @@ PPH_STRING PhGetSymbolFromAddress( if (!modFileName) { resolveLevel = PhsrlAddress; - symbol = PhCreateStringEx(NULL, PH_PTR_STR_LEN * 2); + symbol = PhCreateStringEx(NULL, PH_PTR_STR_LEN * sizeof(WCHAR)); PhPrintPointer(symbol->Buffer, (PVOID)Address); PhTrimToNullTerminatorString(symbol); @@ -660,7 +658,8 @@ PPH_STRING PhGetSymbolFromAddress( // If we have everything, return the full symbol name: module!symbol+offset. - symbolName = PhCreateStringEx(symbolInfo->Name, symbolInfo->NameLen * 2); + symbolName = PhCreateStringEx(symbolInfo->Name, symbolInfo->NameLen * sizeof(WCHAR)); + PhTrimToNullTerminatorString(symbolName); // SymFromAddr doesn't give us the correct name length for vm protected binaries (dmex) resolveLevel = PhsrlFunction; if (displacement == 0) @@ -712,7 +711,7 @@ BOOLEAN PhGetSymbolFromName( ) { PSYMBOL_INFOW symbolInfo; - UCHAR symbolInfoBuffer[FIELD_OFFSET(SYMBOL_INFOW, Name) + PH_MAX_SYMBOL_NAME_LEN * 2]; + UCHAR symbolInfoBuffer[FIELD_OFFSET(SYMBOL_INFOW, Name) + PH_MAX_SYMBOL_NAME_LEN * sizeof(WCHAR)]; BOOL result; PhpRegisterSymbolProvider(SymbolProvider); From eac4ea18fa7c3d95c8bd84a4528a1f822d7e1dd3 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 15 Dec 2018 05:16:25 +0100 Subject: [PATCH 1480/2058] Fix definition --- phlib/util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phlib/util.c b/phlib/util.c index 60458c2cadd7..c231df47e9bc 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -2227,7 +2227,7 @@ PPH_STRING PhGetKnownLocation( if (AppendPath) { - memcpy(&path->Buffer[path->Length / sizeof(WCHAR)], AppendPath, appendPathLength + sizeof(WCHAR)); // +2 for null terminator + memcpy(&path->Buffer[path->Length / sizeof(WCHAR)], AppendPath, appendPathLength + sizeof(UNICODE_NULL)); // +2 for null terminator path->Length += appendPathLength; } From f7f125f477be68443015e1314950447657de556e Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 15 Dec 2018 05:18:42 +0100 Subject: [PATCH 1481/2058] WindowExplorer: Fix crash, Fix search filter after refreshing --- plugins/WindowExplorer/utils.c | 8 ++------ plugins/WindowExplorer/wnddlg.c | 13 +++++++++---- plugins/WindowExplorer/wndexp.h | 1 + plugins/WindowExplorer/wndprp.c | 5 ++--- 4 files changed, 14 insertions(+), 13 deletions(-) diff --git a/plugins/WindowExplorer/utils.c b/plugins/WindowExplorer/utils.c index 73aa875696c7..66d84f30007a 100644 --- a/plugins/WindowExplorer/utils.c +++ b/plugins/WindowExplorer/utils.c @@ -3,6 +3,7 @@ * utility functions * * Copyright (C) 2011 wj32 + * Copyright (C) 2017-2018 dmex * * This file is part of Process Hacker. * @@ -28,12 +29,7 @@ PVOID WeGetProcedureAddress( _In_ PSTR Name ) { - static PVOID imageBase = NULL; - - if (!imageBase) - imageBase = PhGetDllHandle(L"ProcessHacker.exe"); - - return PhGetProcedureAddress(imageBase, Name, 0); + return PhGetProcedureAddress(NtCurrentPeb()->ImageBaseAddress, Name, 0); } VOID WeFormatLocalObjectName( diff --git a/plugins/WindowExplorer/wnddlg.c b/plugins/WindowExplorer/wnddlg.c index 6d8554431898..aa9cd4ed7b0f 100644 --- a/plugins/WindowExplorer/wnddlg.c +++ b/plugins/WindowExplorer/wnddlg.c @@ -371,9 +371,8 @@ INT_PTR CALLBACK WepWindowsDlgProc( { PH_RECTANGLE windowRectangle; - HINSTANCE phInstanceHandle = *(HINSTANCE*)WeGetProcedureAddress("PhInstanceHandle"); - SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(phInstanceHandle, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); - SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(phInstanceHandle, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); + SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(WE_PhInstanceHandle, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); + SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(WE_PhInstanceHandle, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); context->TreeNewHandle = GetDlgItem(hwndDlg, IDC_LIST); context->SearchBoxHandle = GetDlgItem(hwndDlg, IDC_SEARCHEDIT); @@ -899,7 +898,13 @@ INT_PTR CALLBACK WepWindowsPageProc( switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDC_REFRESH: - WepRefreshWindows(context); + { + WepRefreshWindows(context); + + PhApplyTreeNewFilters(&context->TreeContext.FilterSupport); + + TreeNew_NodesStructured(context->TreeNewHandle); + } break; case ID_SHOWCONTEXTMENU: { diff --git a/plugins/WindowExplorer/wndexp.h b/plugins/WindowExplorer/wndexp.h index 0f3293e2acf5..ba56d60c6004 100644 --- a/plugins/WindowExplorer/wndexp.h +++ b/plugins/WindowExplorer/wndexp.h @@ -75,6 +75,7 @@ VOID WeShowWindowProperties( #define WE_PhMainWndHandle (*(HWND *)WeGetProcedureAddress("PhMainWndHandle")) #define WE_WindowsVersion (*(ULONG *)WeGetProcedureAddress("WindowsVersion")) +#define WE_PhInstanceHandle (*(HINSTANCE *)WeGetProcedureAddress("PhInstanceHandle")) PVOID WeGetProcedureAddress( _In_ PSTR Name diff --git a/plugins/WindowExplorer/wndprp.c b/plugins/WindowExplorer/wndprp.c index 6d0f71b85a5a..5029f73f0130 100644 --- a/plugins/WindowExplorer/wndprp.c +++ b/plugins/WindowExplorer/wndprp.c @@ -840,9 +840,8 @@ INT_PTR CALLBACK WepWindowGeneralDlgProc( HWND listViewHandle = GetDlgItem(hwndDlg, IDC_WINDOWINFO); // HACK - HINSTANCE phInstanceHandle = *(HINSTANCE*)WeGetProcedureAddress("PhInstanceHandle"); - SendMessage(GetParent(hwndDlg), WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(phInstanceHandle, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); - SendMessage(GetParent(hwndDlg), WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(phInstanceHandle, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); + SendMessage(GetParent(hwndDlg), WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(WE_PhInstanceHandle, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); + SendMessage(GetParent(hwndDlg), WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(WE_PhInstanceHandle, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); if (PhGetIntegerPairSetting(SETTING_NAME_WINDOWS_PROPERTY_POSITION).X == 0) // HACK PhCenterWindow(GetParent(hwndDlg), context->ParentWindowHandle); From 9c3a553463fc87bff9776e7072361a2e8278f352 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 15 Dec 2018 05:19:28 +0100 Subject: [PATCH 1482/2058] HardwareDevices: Fix macro usage --- plugins/HardwareDevices/storage.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/plugins/HardwareDevices/storage.c b/plugins/HardwareDevices/storage.c index 2296febe33ea..a483d500529b 100644 --- a/plugins/HardwareDevices/storage.c +++ b/plugins/HardwareDevices/storage.c @@ -494,7 +494,7 @@ BOOLEAN DiskDriveQueryDeviceInformation( { PPH_STRING diskVendor; - diskVendor = PH_AUTO(PhConvertMultiByteToUtf16((PBYTE)deviceDescriptor + deviceDescriptor->VendorIdOffset)); + diskVendor = PH_AUTO(PhConvertMultiByteToUtf16(PTR_ADD_OFFSET(deviceDescriptor, deviceDescriptor->VendorIdOffset))); *DiskVendor = TrimString(diskVendor); } @@ -503,7 +503,7 @@ BOOLEAN DiskDriveQueryDeviceInformation( { PPH_STRING diskModel; - diskModel = PH_AUTO(PhConvertMultiByteToUtf16((PBYTE)deviceDescriptor + deviceDescriptor->ProductIdOffset)); + diskModel = PH_AUTO(PhConvertMultiByteToUtf16(PTR_ADD_OFFSET(deviceDescriptor, deviceDescriptor->ProductIdOffset))); *DiskModel = TrimString(diskModel); } @@ -512,7 +512,7 @@ BOOLEAN DiskDriveQueryDeviceInformation( { PPH_STRING diskRevision; - diskRevision = PH_AUTO(PhConvertMultiByteToUtf16((PBYTE)deviceDescriptor + deviceDescriptor->ProductRevisionOffset)); + diskRevision = PH_AUTO(PhConvertMultiByteToUtf16(PTR_ADD_OFFSET(deviceDescriptor, deviceDescriptor->ProductRevisionOffset))); *DiskRevision = TrimString(diskRevision); } @@ -521,7 +521,7 @@ BOOLEAN DiskDriveQueryDeviceInformation( { PPH_STRING diskSerial; - diskSerial = PH_AUTO(PhConvertMultiByteToUtf16((PBYTE)deviceDescriptor + deviceDescriptor->SerialNumberOffset)); + diskSerial = PH_AUTO(PhConvertMultiByteToUtf16(PTR_ADD_OFFSET(deviceDescriptor, deviceDescriptor->SerialNumberOffset))); *DiskSerial = TrimString(diskSerial); } @@ -1504,4 +1504,4 @@ PWSTR SmartAttributeGetText( } return L"BUG BUG BUG"; -} \ No newline at end of file +} From 73689b10d58198b0ac48e74da1c37125af7dc5ff Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 15 Dec 2018 05:25:33 +0100 Subject: [PATCH 1483/2058] Fix memory leak --- ProcessHacker/modprv.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/ProcessHacker/modprv.c b/ProcessHacker/modprv.c index 4590686a9dce..c2dc28dade51 100644 --- a/ProcessHacker/modprv.c +++ b/ProcessHacker/modprv.c @@ -104,6 +104,7 @@ PPH_MODULE_PROVIDER PhCreateModuleProvider( moduleProvider->ProcessId = ProcessId; moduleProvider->ProcessHandle = NULL; + moduleProvider->ProcessFileName = NULL; moduleProvider->PackageFullName = NULL; moduleProvider->RunStatus = STATUS_SUCCESS; @@ -201,6 +202,7 @@ VOID PhpModuleProviderDeleteProcedure( } } + if (moduleProvider->ProcessFileName) PhDereferenceObject(moduleProvider->ProcessFileName); if (moduleProvider->PackageFullName) PhDereferenceObject(moduleProvider->PackageFullName); if (moduleProvider->ProcessHandle) NtClose(moduleProvider->ProcessHandle); } @@ -560,12 +562,15 @@ VOID PhModuleProviderUpdate( if (!moduleProvider->HaveFirst) { - // moduleItem->IsFirst = i == 0; - if (PhEqualString(moduleProvider->ProcessFileName, moduleItem->FileName, FALSE)) + if (moduleProvider->ProcessFileName && PhEqualString(moduleProvider->ProcessFileName, moduleItem->FileName, FALSE)) { moduleItem->IsFirst = TRUE; moduleProvider->HaveFirst = TRUE; } + else + { + moduleItem->IsFirst = i == 0; + } } if (moduleItem->Type == PH_MODULE_TYPE_MODULE || From 1acc31b0e39bc112af809b51623aaebbb26ca627 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 15 Dec 2018 05:38:44 +0100 Subject: [PATCH 1484/2058] BuildTools: Add VS2019 support #347 --- tools/CustomBuildTool/Source Files/Utils.cs | 20 ++++++++++++++---- .../bin/Release/CustomBuildTool.exe | Bin 167936 -> 167936 bytes .../bin/Release/CustomBuildTool.pdb | Bin 85504 -> 85504 bytes 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/tools/CustomBuildTool/Source Files/Utils.cs b/tools/CustomBuildTool/Source Files/Utils.cs index 649e69eaa3ab..3b1d24f81f65 100644 --- a/tools/CustomBuildTool/Source Files/Utils.cs +++ b/tools/CustomBuildTool/Source Files/Utils.cs @@ -262,6 +262,11 @@ public static class VisualStudio { public static string GetMsbuildFilePath() { + string[] MsBuildPathArray = + { + "\\MSBuild\\Current\\Bin\\MSBuild.exe", + "\\MSBuild\\15.0\\Bin\\MSBuild.exe" + }; string vswhere = string.Empty; if (Environment.Is64BitOperatingSystem) @@ -274,6 +279,7 @@ public static string GetMsbuildFilePath() { string vswhereResult = Win32.ShellExecute(vswhere, "-latest " + + "-prerelease " + "-products * " + "-requires Microsoft.Component.MSBuild " + "-property installationPath " @@ -282,8 +288,11 @@ public static string GetMsbuildFilePath() if (string.IsNullOrEmpty(vswhereResult)) return null; - if (File.Exists(vswhereResult + "\\MSBuild\\15.0\\Bin\\MSBuild.exe")) - return vswhereResult + "\\MSBuild\\15.0\\Bin\\MSBuild.exe"; + foreach (string path in MsBuildPathArray) + { + if (File.Exists(vswhereResult + path)) + return vswhereResult + path; + } return null; } @@ -295,8 +304,11 @@ public static string GetMsbuildFilePath() if (instance != null) { - if (File.Exists(instance.Path + "\\MSBuild\\15.0\\Bin\\MSBuild.exe")) - return instance.Path + "\\MSBuild\\15.0\\Bin\\MSBuild.exe"; + foreach (string path in MsBuildPathArray) + { + if (File.Exists(instance.Path + path)) + return instance.Path + path; + } } } catch (Exception ex) diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe b/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe index 0cc374d2c8dc5450c95fe29c9068f94d3e70cb75..2a23efab24ca42b604d99293f585ff45091dffdb 100644 GIT binary patch delta 5135 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 Nywmf5r(L+q{sXc$IMe_D diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb b/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb index 567bd9aca888a8b3a771ec58e8a5da4795b28729..14b58b7258fa5183ce4dd3f0094231dc48c90f24 100644 GIT binary patch delta 4577 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 From 6380ba3c67eb5908c62a53bf92b1745bb54bd291 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 17 Dec 2018 13:30:14 +0100 Subject: [PATCH 1485/2058] Fix module image highlighting regression 73689b1 --- ProcessHacker/modprv.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/ProcessHacker/modprv.c b/ProcessHacker/modprv.c index c2dc28dade51..1b942fa75c1f 100644 --- a/ProcessHacker/modprv.c +++ b/ProcessHacker/modprv.c @@ -562,14 +562,19 @@ VOID PhModuleProviderUpdate( if (!moduleProvider->HaveFirst) { - if (moduleProvider->ProcessFileName && PhEqualString(moduleProvider->ProcessFileName, moduleItem->FileName, FALSE)) + if (WindowsVersion < WINDOWS_10) { - moduleItem->IsFirst = TRUE; + moduleItem->IsFirst = i == 0; moduleProvider->HaveFirst = TRUE; } else { - moduleItem->IsFirst = i == 0; + // Windows loads the PE image first and WSL loads the ELF image last (dmex) + if (moduleProvider->ProcessFileName && PhEqualString(moduleProvider->ProcessFileName, moduleItem->FileName, FALSE)) + { + moduleItem->IsFirst = TRUE; + moduleProvider->HaveFirst = TRUE; + } } } @@ -684,6 +689,9 @@ VOID PhModuleProviderUpdate( } } + if (!moduleProvider->HaveFirst) // Some processes don't have a primary image (e.g. System/Registry/Secure System) (dmex) + moduleProvider->HaveFirst = TRUE; + // Free the modules list. for (i = 0; i < modules->Count; i++) From f182c34407d5b5679a601811ac6b7114cfccdd0e Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 19 Dec 2018 20:21:35 +0100 Subject: [PATCH 1486/2058] HardwareDevices: Fix memory leak --- plugins/HardwareDevices/diskoptions.c | 9 +++++++-- plugins/HardwareDevices/netoptions.c | 9 +++++++-- plugins/HardwareDevices/storage.c | 4 ++-- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/plugins/HardwareDevices/diskoptions.c b/plugins/HardwareDevices/diskoptions.c index 3a6bb4d0fd7c..8af567c6522c 100644 --- a/plugins/HardwareDevices/diskoptions.c +++ b/plugins/HardwareDevices/diskoptions.c @@ -2,7 +2,7 @@ * Process Hacker Plugins - * Hardware Devices Plugin * - * Copyright (C) 2015-2016 dmex + * Copyright (C) 2015-2018 dmex * * This file is part of Process Hacker. * @@ -413,6 +413,9 @@ VOID FindDiskDrives( PhDereferenceObject(deviceDescription); } + // Cleanup. + PhFree(deviceInterfaceList); + // Sort the entries qsort(deviceList->Items, deviceList->Count, sizeof(PVOID), DiskEntryCompareFunction); @@ -547,6 +550,8 @@ PPH_STRING FindDiskDeviceInstance( } } + PhFree(deviceInterfaceList); + return deviceInstanceString; } @@ -741,4 +746,4 @@ INT_PTR CALLBACK DiskDriveOptionsDlgProc( } return FALSE; -} \ No newline at end of file +} diff --git a/plugins/HardwareDevices/netoptions.c b/plugins/HardwareDevices/netoptions.c index 6e09056252f6..b142ec6484dd 100644 --- a/plugins/HardwareDevices/netoptions.c +++ b/plugins/HardwareDevices/netoptions.c @@ -2,8 +2,8 @@ * Process Hacker Plugins - * Hardware Devices Plugin * - * Copyright (C) 2015-2016 dmex * Copyright (C) 2016 wj32 + * Copyright (C) 2015-2018 dmex * * This file is part of Process Hacker. * @@ -474,6 +474,9 @@ VOID FindNetworkAdapters( PhClearReference(&deviceDescription); } + // Cleanup. + PhFree(deviceInterfaceList); + // Sort the entries qsort(deviceList->Items, deviceList->Count, sizeof(PVOID), AdapterEntryCompareFunction); @@ -661,6 +664,8 @@ PPH_STRING FindNetworkDeviceInstance( } } + PhFree(deviceInterfaceList); + return deviceInstanceString; } @@ -900,4 +905,4 @@ INT_PTR CALLBACK NetworkAdapterOptionsDlgProc( } return FALSE; -} \ No newline at end of file +} diff --git a/plugins/HardwareDevices/storage.c b/plugins/HardwareDevices/storage.c index a483d500529b..f2a48c403b53 100644 --- a/plugins/HardwareDevices/storage.c +++ b/plugins/HardwareDevices/storage.c @@ -708,9 +708,9 @@ NTSTATUS DiskDriveQueryImminentFailure( attribute->Id != 0xFF ) { - PSMART_ATTRIBUTES info = PhAllocate(sizeof(SMART_ATTRIBUTES)); - memset(info, 0, sizeof(SMART_ATTRIBUTES)); + PSMART_ATTRIBUTES info; + info = PhAllocateZero(sizeof(SMART_ATTRIBUTES)); info->AttributeId = attribute->Id; info->CurrentValue = attribute->CurrentValue; info->WorstValue = attribute->WorstValue; From 73d3eef06aa52592a339b3dcb24851e335629dfb Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 19 Dec 2018 20:22:53 +0100 Subject: [PATCH 1487/2058] Update includes --- ProcessHacker/ProcessHacker.vcxproj | 1 - ProcessHacker/ProcessHacker.vcxproj.filters | 3 --- ProcessHacker/include/splitter.h | 11 ----------- 3 files changed, 15 deletions(-) delete mode 100644 ProcessHacker/include/splitter.h diff --git a/ProcessHacker/ProcessHacker.vcxproj b/ProcessHacker/ProcessHacker.vcxproj index 2896a1a4087c..72077726060d 100644 --- a/ProcessHacker/ProcessHacker.vcxproj +++ b/ProcessHacker/ProcessHacker.vcxproj @@ -383,7 +383,6 @@ - diff --git a/ProcessHacker/ProcessHacker.vcxproj.filters b/ProcessHacker/ProcessHacker.vcxproj.filters index 68d8b04b9cfa..8019809825fb 100644 --- a/ProcessHacker/ProcessHacker.vcxproj.filters +++ b/ProcessHacker/ProcessHacker.vcxproj.filters @@ -542,9 +542,6 @@ Headers - - Headers - Headers diff --git a/ProcessHacker/include/splitter.h b/ProcessHacker/include/splitter.h deleted file mode 100644 index 9901b2ea6fcc..000000000000 --- a/ProcessHacker/include/splitter.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef PH_HSPLITTER_H -#define PH_HSPLITTER_H - -VOID PhInitializeHSplitter( - _In_ PWSTR SettingName, - _In_ HWND ParentWindow, - _In_ HWND TopWindow, - _In_ HWND BottomWindow - ); - -#endif From 3446afc6b7c1b33951893e75f14f33a975e66829 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 19 Dec 2018 20:23:21 +0100 Subject: [PATCH 1488/2058] Fix boosting network provider --- ProcessHacker/mainwnd.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index c2615db78b08..1a2a15fc851e 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -828,6 +828,12 @@ VOID PhMwpOnCommand( { PhBoostProvider(&PhMwpProcessProviderRegistration, NULL); PhBoostProvider(&PhMwpServiceProviderRegistration, NULL); + + // Note: Don't boost the network provider unless it's currently enabled. (dmex) + if (PhGetEnabledProvider(&PhMwpNetworkProviderRegistration)) + { + PhBoostProvider(&PhMwpNetworkProviderRegistration, NULL); + } } break; case ID_UPDATEINTERVAL_FAST: From 8bd9624b7eeca4845b2f6a3c1c9830fa0c75159f Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 19 Dec 2018 20:23:51 +0100 Subject: [PATCH 1489/2058] Fix options window classic theme --- ProcessHacker/options.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ProcessHacker/options.c b/ProcessHacker/options.c index 9655fd45d7eb..bdbe0ee4e7a1 100644 --- a/ProcessHacker/options.c +++ b/ProcessHacker/options.c @@ -291,7 +291,8 @@ INT_PTR CALLBACK PhOptionsDialogProc( //PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDC_APPLY), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDOK), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); - PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport); + if (PhEnableThemeSupport) // TODO: fix options dialog theme (dmex) + PhInitializeWindowTheme(hwndDlg, TRUE); { PPH_OPTIONS_SECTION section; From 6b2a6394c98e0106725fad34c2d1aefe0b2ba18b Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 19 Dec 2018 20:25:06 +0100 Subject: [PATCH 1490/2058] peview: Disable unnecessary file dialog path validation --- tools/peview/main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/peview/main.c b/tools/peview/main.c index deb6e7126985..2d8b137395a6 100644 --- a/tools/peview/main.c +++ b/tools/peview/main.c @@ -131,7 +131,8 @@ INT WINAPI wWinMain( CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE); fileDialog = PhCreateOpenFileDialog(); - PhSetFileDialogFilter(fileDialog, filters, ARRAYSIZE(filters)); + PhSetFileDialogOptions(fileDialog, PH_FILEDIALOG_NOPATHVALIDATE); + PhSetFileDialogFilter(fileDialog, filters, RTL_NUMBER_OF(filters)); if (PhShowFileDialog(NULL, fileDialog)) { From 4997d6aa831b41ca3f57b9af4672a32e859faa8f Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 19 Dec 2018 20:30:09 +0100 Subject: [PATCH 1491/2058] Fix commit 73d3eef --- ProcessHacker/tokprp.c | 1 - 1 file changed, 1 deletion(-) diff --git a/ProcessHacker/tokprp.c b/ProcessHacker/tokprp.c index 700f63caf7c2..a5ac69360949 100644 --- a/ProcessHacker/tokprp.c +++ b/ProcessHacker/tokprp.c @@ -28,7 +28,6 @@ #include #include #include -#include #include typedef enum _PH_PROCESS_TOKEN_CATEGORY From c1348da9002b0bc5d94e5eeb0ed150f7f2ebc275 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 19 Dec 2018 21:06:18 +0100 Subject: [PATCH 1492/2058] WindowExplorer: Fix deadlock querying window text, Fix search after selecting refresh --- plugins/WindowExplorer/wnddlg.c | 32 +++++++++++++++++++------------- plugins/WindowExplorer/wndtree.c | 9 +++------ 2 files changed, 22 insertions(+), 19 deletions(-) diff --git a/plugins/WindowExplorer/wnddlg.c b/plugins/WindowExplorer/wnddlg.c index aa9cd4ed7b0f..5a13d14169d0 100644 --- a/plugins/WindowExplorer/wnddlg.c +++ b/plugins/WindowExplorer/wnddlg.c @@ -113,27 +113,30 @@ VOID WepDeleteWindowSelector( } VOID WepFillWindowInfo( + _In_ PWE_WINDOW_TREE_CONTEXT Context, _In_ PWE_WINDOW_NODE Node ) { - HWND hwnd; + PPH_STRING windowText; ULONG threadId; ULONG processId; - hwnd = Node->WindowHandle; + PhPrintPointer(Node->WindowHandleString, Node->WindowHandle); + GetClassName(Node->WindowHandle, Node->WindowClass, sizeof(Node->WindowClass) / sizeof(WCHAR)); - GetClassName(hwnd, Node->WindowClass, sizeof(Node->WindowClass) / sizeof(WCHAR)); - Node->WindowText = PhGetWindowText(hwnd); + if (PhGetWindowTextEx(Node->WindowHandle, PH_GET_WINDOW_TEXT_INTERNAL, &windowText) > 0) + PhMoveReference(&Node->WindowText, windowText); - if (!Node->WindowText) - Node->WindowText = PhReferenceEmptyString(); + if (PhIsNullOrEmptyString(Node->WindowText)) + PhMoveReference(&Node->WindowText, PhReferenceEmptyString()); - threadId = GetWindowThreadProcessId(hwnd, &processId); + threadId = GetWindowThreadProcessId(Node->WindowHandle, &processId); Node->ClientId.UniqueProcess = UlongToHandle(processId); Node->ClientId.UniqueThread = UlongToHandle(threadId); + Node->ThreadString = PhGetClientIdName(&Node->ClientId); - Node->WindowVisible = !!IsWindowVisible(hwnd); - Node->HasChildren = !!FindWindowEx(hwnd, NULL, NULL, NULL); + Node->WindowVisible = !!IsWindowVisible(Node->WindowHandle); + Node->HasChildren = !!FindWindowEx(Node->WindowHandle, NULL, NULL, NULL); if (processId) { @@ -143,9 +146,9 @@ VOID WepFillWindowInfo( if (NT_SUCCESS(PhOpenProcess(&processHandle, PROCESS_QUERY_LIMITED_INFORMATION, UlongToHandle(processId)))) { - if (!(instanceHandle = (PVOID)GetWindowLongPtr(hwnd, GWLP_HINSTANCE))) + if (!(instanceHandle = (PVOID)GetWindowLongPtr(Node->WindowHandle, GWLP_HINSTANCE))) { - instanceHandle = (PVOID)GetClassLongPtr(hwnd, GCLP_HMODULE); + instanceHandle = (PVOID)GetClassLongPtr(Node->WindowHandle, GCLP_HMODULE); } if (instanceHandle) @@ -162,6 +165,9 @@ VOID WepFillWindowInfo( NtClose(processHandle); } } + + if (Context->FilterSupport.FilterList) // Note: Apply filter after filling window node data. (dmex) + Node->Node.Visible = PhApplyTreeNewFiltersToNode(&Context->FilterSupport, &Node->Node); } PWE_WINDOW_NODE WepAddChildWindowNode( @@ -175,7 +181,7 @@ PWE_WINDOW_NODE WepAddChildWindowNode( childNode = WeAddWindowNode(Context); childNode->WindowHandle = hwnd; - WepFillWindowInfo(childNode); + WepFillWindowInfo(Context, childNode); if (ParentNode) { @@ -274,7 +280,7 @@ VOID WepRefreshWindows( desktopNode = WeAddWindowNode(&Context->TreeContext); desktopNode->WindowHandle = GetDesktopWindow(); - WepFillWindowInfo(desktopNode); + WepFillWindowInfo(&Context->TreeContext, desktopNode); PhAddItemList(Context->TreeContext.NodeRootList, desktopNode); diff --git a/plugins/WindowExplorer/wndtree.c b/plugins/WindowExplorer/wndtree.c index e8e7834da237..55c942fe41c1 100644 --- a/plugins/WindowExplorer/wndtree.c +++ b/plugins/WindowExplorer/wndtree.c @@ -238,9 +238,9 @@ PWE_WINDOW_NODE WeAddWindowNode( PhAddEntryHashtable(Context->NodeHashtable, &windowNode); PhAddItemList(Context->NodeList, windowNode); - if (Context->FilterSupport.FilterList) - windowNode->Node.Visible = PhApplyTreeNewFiltersToNode(&Context->FilterSupport, &windowNode->Node); - + //if (Context->FilterSupport.FilterList) + // windowNode->Node.Visible = PhApplyTreeNewFiltersToNode(&Context->FilterSupport, &windowNode->Node); + // //TreeNew_NodesStructured(Context->TreeNewHandle); return windowNode; @@ -437,15 +437,12 @@ BOOLEAN NTAPI WepWindowTreeNewCallback( PhInitializeStringRef(&getCellText->Text, node->WindowClass); break; case WEWNTLC_HANDLE: - PhPrintPointer(node->WindowHandleString, node->WindowHandle); PhInitializeStringRef(&getCellText->Text, node->WindowHandleString); break; case WEWNTLC_TEXT: getCellText->Text = PhGetStringRef(node->WindowText); break; case WEWNTLC_THREAD: - if (!node->ThreadString) - node->ThreadString = PhGetClientIdName(&node->ClientId); getCellText->Text = PhGetStringRef(node->ThreadString); break; case WEWNTLC_MODULE: From 90267742c01d600fafdc86f58c8b8429520d06e4 Mon Sep 17 00:00:00 2001 From: "Force.Charlie-I" Date: Fri, 21 Dec 2018 08:20:39 +0800 Subject: [PATCH 1493/2058] peview: Add PE Image Machine Type support ARM64 and Hybrid PE (#353) --- tools/peview/peprp.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tools/peview/peprp.c b/tools/peview/peprp.c index 4f69c27024f8..146342f68870 100644 --- a/tools/peview/peprp.c +++ b/tools/peview/peprp.c @@ -421,6 +421,16 @@ VOID PvpSetPeImageVersionInfo( PhDereferenceObject(string); } + +#ifndef IMAGE_FILE_MACHINE_ARM64 +#define IMAGE_FILE_MACHINE_ARM64 0xAA64 // ARM64 Little-Endian +#endif + +#ifndef IMAGE_FILE_MACHINE_CHPE_X86 +#define IMAGE_FILE_MACHINE_CHPE_X86 0x3A64 /// defined in ntimage.h +#endif + + VOID PvpSetPeImageMachineType( _In_ HWND WindowHandle ) @@ -441,6 +451,12 @@ VOID PvpSetPeImageMachineType( case IMAGE_FILE_MACHINE_ARMNT: type = L"ARM Thumb-2"; break; + case IMAGE_FILE_MACHINE_ARM64: + type = L"ARM64"; + break; + case IMAGE_FILE_MACHINE_CHPE_X86: + type = L"Hybrid PE"; + break; default: type = L"Unknown"; break; From b0079131e5fcbda296d2e51f9a5b4e03c9064176 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 22 Dec 2018 21:36:06 +0100 Subject: [PATCH 1494/2058] peview: Add missing load config field, Tidy up #353 --- tools/peview/ldprp.c | 1 + tools/peview/peprp.c | 8 +------- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/tools/peview/ldprp.c b/tools/peview/ldprp.c index b71348a3df28..3c554472262f 100644 --- a/tools/peview/ldprp.c +++ b/tools/peview/ldprp.c @@ -115,6 +115,7 @@ INT_PTR CALLBACK PvpPeLoadConfigDlgProc( ADD_VALUE(L"Process affinity mask", PhaFormatString(L"0x%Ix", (Config)->ProcessAffinityMask)->Buffer); \ ADD_VALUE(L"Process heap flags", PhaFormatString(L"0x%Ix", (Config)->ProcessHeapFlags)->Buffer); \ ADD_VALUE(L"CSD version", PhaFormatString(L"%u", (Config)->CSDVersion)->Buffer); \ + ADD_VALUE(L"Dependent load flags", PhaFormatString(L"0x%x", (Config)->DependentLoadFlags)->Buffer); \ ADD_VALUE(L"Edit list", PhaFormatString(L"0x%Ix", (Config)->EditList)->Buffer); \ ADD_VALUE(L"Security cookie", PhaFormatString(L"0x%Ix", (Config)->SecurityCookie)->Buffer); \ ADD_VALUE(L"SEH handler table", PhaFormatString(L"0x%Ix", (Config)->SEHandlerTable)->Buffer); \ diff --git a/tools/peview/peprp.c b/tools/peview/peprp.c index 146342f68870..2dd57f159ec4 100644 --- a/tools/peview/peprp.c +++ b/tools/peview/peprp.c @@ -421,16 +421,10 @@ VOID PvpSetPeImageVersionInfo( PhDereferenceObject(string); } - -#ifndef IMAGE_FILE_MACHINE_ARM64 -#define IMAGE_FILE_MACHINE_ARM64 0xAA64 // ARM64 Little-Endian -#endif - #ifndef IMAGE_FILE_MACHINE_CHPE_X86 -#define IMAGE_FILE_MACHINE_CHPE_X86 0x3A64 /// defined in ntimage.h +#define IMAGE_FILE_MACHINE_CHPE_X86 0x3A64 // defined in ntimage.h #endif - VOID PvpSetPeImageMachineType( _In_ HWND WindowHandle ) From 353e2a324bbc6c77668532b3b6908fd65b467fe2 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 26 Dec 2018 16:53:23 +0100 Subject: [PATCH 1495/2058] Fix typo --- ProcessHacker/mtgndlg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ProcessHacker/mtgndlg.c b/ProcessHacker/mtgndlg.c index b939477723e2..dc37d6e7d7e2 100644 --- a/ProcessHacker/mtgndlg.c +++ b/ProcessHacker/mtgndlg.c @@ -188,7 +188,7 @@ INT_PTR CALLBACK PhpProcessMitigationPolicyDlgProc( entry = PhAllocate(sizeof(MITIGATION_POLICY_ENTRY)); entry->NonStandard = TRUE; entry->ShortDescription = PhCreateString(L"Loader Integrity"); - entry->LongDescription = PhCreateString(L"OS signing levels for depenedent module loads are enabled."); + entry->LongDescription = PhCreateString(L"OS signing levels for dependent module loads are enabled."); PhAddListViewItem(lvHandle, MAXINT, entry->ShortDescription->Buffer, entry); } From 752827c83325487e8dd6f2f00fec3e37627edaac Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 26 Dec 2018 16:54:10 +0100 Subject: [PATCH 1496/2058] Remove spacing --- ProcessHacker/findobj.c | 1 + ProcessHacker/plugin.c | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/ProcessHacker/findobj.c b/ProcessHacker/findobj.c index 53793bb208da..1b59d0a5117e 100644 --- a/ProcessHacker/findobj.c +++ b/ProcessHacker/findobj.c @@ -1045,6 +1045,7 @@ NTSTATUS PhpFindObjectsThreadStart( else { SEARCH_HANDLE_CONTEXT searchHandleContext; + searchHandleContext.WindowContext = context; searchHandleContext.NeedToFree = FALSE; searchHandleContext.HandleInfo = handleInfo; diff --git a/ProcessHacker/plugin.c b/ProcessHacker/plugin.c index 501e6eb6dfe2..1ae54aba15e6 100644 --- a/ProcessHacker/plugin.c +++ b/ProcessHacker/plugin.c @@ -556,7 +556,6 @@ PPH_PLUGIN PhRegisterPlugin( plugin = PhAllocateZero(sizeof(PH_PLUGIN)); plugin->Name = pluginName; plugin->DllBase = DllBase; - plugin->FileName = fileName; existingLinks = PhAddElementAvlTree(&PhPluginsByName, &plugin->Links); From d2736ce7679398c36e04337f991d9a107220028c Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 26 Dec 2018 16:55:20 +0100 Subject: [PATCH 1497/2058] Fix missing image filename for protected processes --- ProcessHacker/procprv.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/ProcessHacker/procprv.c b/ProcessHacker/procprv.c index e785498cabaa..acb65c4be4b5 100644 --- a/ProcessHacker/procprv.c +++ b/ProcessHacker/procprv.c @@ -1129,19 +1129,23 @@ VOID PhpFillProcessItem( if (ProcessItem->ProcessId != SYSTEM_PROCESS_ID) { + NTSTATUS status = STATUS_UNSUCCESSFUL; PPH_STRING fileName; if (ProcessItem->QueryHandle && !ProcessItem->IsSubsystemProcess) { - PhGetProcessImageFileNameWin32(ProcessItem->QueryHandle, &ProcessItem->FileName); + status = PhGetProcessImageFileNameWin32(ProcessItem->QueryHandle, &fileName); } - else + + if (!NT_SUCCESS(status)) { - if (NT_SUCCESS(PhGetProcessImageFileNameByProcessId(ProcessItem->ProcessId, &fileName))) - { - ProcessItem->FileName = PhGetFileName(fileName); - PhDereferenceObject(fileName); - } + status = PhGetProcessImageFileNameByProcessId(ProcessItem->ProcessId, &fileName); + } + + if (NT_SUCCESS(status)) + { + ProcessItem->FileName = PhGetFileName(fileName); + PhDereferenceObject(fileName); } } else From 32b4d0096d2792d01595aa5842b5f444a7923759 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 26 Dec 2018 23:15:09 +0100 Subject: [PATCH 1498/2058] Updater: Fix crash #355 --- plugins/Updater/updater.c | 50 +++++++++++++++++++++++---------------- 1 file changed, 29 insertions(+), 21 deletions(-) diff --git a/plugins/Updater/updater.c b/plugins/Updater/updater.c index 4023bf7d0fcb..8c2eea682a86 100644 --- a/plugins/Updater/updater.c +++ b/plugins/Updater/updater.c @@ -25,6 +25,25 @@ HWND UpdateDialogHandle = NULL; HANDLE UpdateDialogThreadHandle = NULL; PH_EVENT InitializedEvent = PH_EVENT_INIT; +PPH_OBJECT_TYPE UpdateContextType = NULL; +PH_INITONCE UpdateContextTypeInitOnce = PH_INITONCE_INIT; + +VOID UpdateContextDeleteProcedure( + _In_ PVOID Object, + _In_ ULONG Flags + ) +{ + PPH_UPDATER_CONTEXT context = Object; + + PhClearReference(&context->CurrentVersionString); + PhClearReference(&context->Version); + PhClearReference(&context->RelDate); + PhClearReference(&context->SetupFileDownloadUrl); + PhClearReference(&context->SetupFileLength); + PhClearReference(&context->SetupFileHash); + PhClearReference(&context->SetupFileSignature); + PhClearReference(&context->BuildMessage); +} PPH_UPDATER_CONTEXT CreateUpdateContext( _In_ BOOLEAN StartupCheck @@ -32,7 +51,13 @@ PPH_UPDATER_CONTEXT CreateUpdateContext( { PPH_UPDATER_CONTEXT context; - context = (PPH_UPDATER_CONTEXT)PhCreateAlloc(sizeof(PH_UPDATER_CONTEXT)); + if (PhBeginInitOnce(&UpdateContextTypeInitOnce)) + { + UpdateContextType = PhCreateObjectType(L"UpdaterContextObjectType", 0, UpdateContextDeleteProcedure); + PhEndInitOnce(&UpdateContextTypeInitOnce); + } + + context = PhCreateObjectZero(sizeof(PH_UPDATER_CONTEXT), UpdateContextType); memset(context, 0, sizeof(PH_UPDATER_CONTEXT)); context->CurrentVersionString = PhGetPhVersion(); @@ -41,23 +66,6 @@ PPH_UPDATER_CONTEXT CreateUpdateContext( return context; } -VOID FreeUpdateContext( - _In_ _Post_invalid_ PPH_UPDATER_CONTEXT Context - ) -{ - PhClearReference(&Context->CurrentVersionString); - - PhClearReference(&Context->Version); - PhClearReference(&Context->RelDate); - PhClearReference(&Context->SetupFileDownloadUrl); - PhClearReference(&Context->SetupFileLength); - PhClearReference(&Context->SetupFileHash); - PhClearReference(&Context->SetupFileSignature); - PhClearReference(&Context->BuildMessage); - - PhDereferenceObject(Context); -} - VOID TaskDialogCreateIcons( _In_ PPH_UPDATER_CONTEXT Context ) @@ -402,7 +410,7 @@ NTSTATUS UpdateCheckSilentThread( CleanupExit: if (!context->HaveData) - FreeUpdateContext(context); + PhDereferenceObject(context); return STATUS_SUCCESS; } @@ -869,7 +877,7 @@ NTSTATUS ShowUpdateDialogThread( config.pfCallback = TaskDialogBootstrapCallback; TaskDialogIndirect(&config, NULL, NULL, NULL); - FreeUpdateContext(context); + PhDereferenceObject(context); PhDeleteAutoPool(&autoPool); if (UpdateDialogThreadHandle) @@ -906,4 +914,4 @@ VOID StartInitialCheck( ) { PhCreateThread2(UpdateCheckSilentThread, NULL); -} \ No newline at end of file +} From 85d2b4b3b6eb67781c8fb8eee1f0e5e02aacc560 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 27 Dec 2018 19:01:58 +0100 Subject: [PATCH 1499/2058] Cache object types --- phlib/hndlinfo.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/phlib/hndlinfo.c b/phlib/hndlinfo.c index 38290ad64f65..3b58a4ff5dd7 100644 --- a/phlib/hndlinfo.c +++ b/phlib/hndlinfo.c @@ -1496,12 +1496,15 @@ PPH_STRING PhGetObjectTypeName( _In_ ULONG TypeIndex ) { - POBJECT_TYPES_INFORMATION objectTypes; + static POBJECT_TYPES_INFORMATION objectTypes = NULL; POBJECT_TYPE_INFORMATION objectType; PPH_STRING objectTypeName = NULL; ULONG i; - if (NT_SUCCESS(PhEnumObjectTypes(&objectTypes))) + if (!objectTypes) // HACK (dmex) + PhEnumObjectTypes(&objectTypes); + + if (objectTypes) { objectType = PH_FIRST_OBJECT_TYPE(objectTypes); @@ -1526,8 +1529,6 @@ PPH_STRING PhGetObjectTypeName( objectType = PH_NEXT_OBJECT_TYPE(objectType); } - - PhFree(objectTypes); } return objectTypeName; From ef7bac7d8fb28266792dabeaa0e9a4b5833bfdeb Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 27 Dec 2018 19:03:01 +0100 Subject: [PATCH 1500/2058] Add extra file information wrappers --- phlib/include/phnative.h | 54 +++++++++++++++++++ phlib/native.c | 114 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 168 insertions(+) diff --git a/phlib/include/phnative.h b/phlib/include/phnative.h index 0c0666ce3271..2a4c14b9fde7 100644 --- a/phlib/include/phnative.h +++ b/phlib/include/phnative.h @@ -491,6 +491,30 @@ PhSetFileSize( _In_ PLARGE_INTEGER Size ); +PHLIBAPI +NTSTATUS +NTAPI +PhGetFileHandleName( + _In_ HANDLE FileHandle, + _Out_ PPH_STRING *FileName + ); + +PHLIBAPI +NTSTATUS +NTAPI +PhGetFileAllInformation( + _In_ HANDLE FileHandle, + _Out_ PFILE_ALL_INFORMATION *FileId + ); + +PHLIBAPI +NTSTATUS +NTAPI +PhGetFileId( + _In_ HANDLE FileHandle, + _Out_ PFILE_ID_INFORMATION *FileId + ); + PHLIBAPI NTSTATUS NTAPI @@ -925,6 +949,36 @@ PhEnumFileStreamsEx( _In_opt_ PVOID Context ); +#define PH_FIRST_LINK(Links) ((PFILE_LINK_ENTRY_INFORMATION)(Links)) +#define PH_NEXT_LINK(Links) ( \ + ((PFILE_LINK_ENTRY_INFORMATION)(Links))->NextEntryOffset ? \ + (PFILE_LINK_ENTRY_INFORMATION)(PTR_ADD_OFFSET((Links), \ + ((PFILE_LINK_ENTRY_INFORMATION)(Links))->NextEntryOffset)) : \ + NULL \ + ) + +typedef BOOLEAN (NTAPI *PPH_ENUM_FILE_HARDLINKS)( + _In_ PFILE_LINK_ENTRY_INFORMATION Information, + _In_opt_ PVOID Context + ); + +PHLIBAPI +NTSTATUS +NTAPI +PhEnumFileHardLinks( + _In_ HANDLE FileHandle, + _Out_ PVOID *HardLinks + ); + +PHLIBAPI +NTSTATUS +NTAPI +PhEnumFileHardLinksEx( + _In_ HANDLE FileHandle, + _In_ PPH_ENUM_FILE_HARDLINKS Callback, + _In_opt_ PVOID Context + ); + PHLIBAPI VOID NTAPI diff --git a/phlib/native.c b/phlib/native.c index e054dba0bf95..3fdc29fb3de9 100644 --- a/phlib/native.c +++ b/phlib/native.c @@ -2506,6 +2506,78 @@ NTSTATUS PhSetFileSize( ); } +NTSTATUS PhGetFileHandleName( + _In_ HANDLE FileHandle, + _Out_ PPH_STRING *FileName + ) +{ + NTSTATUS status; + ULONG bufferSize; + PFILE_NAME_INFORMATION buffer; + IO_STATUS_BLOCK isb; + + bufferSize = sizeof(FILE_NAME_INFORMATION) + MAX_PATH; + buffer = PhAllocateZero(bufferSize); + + status = NtQueryInformationFile( + FileHandle, + &isb, + buffer, + bufferSize, + FileNameInformation + ); + + if (status == STATUS_BUFFER_OVERFLOW) + { + bufferSize = sizeof(FILE_NAME_INFORMATION) + buffer->FileNameLength + sizeof(UNICODE_NULL); + PhFree(buffer); + buffer = PhAllocateZero(bufferSize); + + status = NtQueryInformationFile( + FileHandle, + &isb, + buffer, + bufferSize, + FileNameInformation + ); + } + + if (!NT_SUCCESS(status)) + { + PhFree(buffer); + return status; + } + + *FileName = PhCreateStringEx(buffer->FileName, buffer->FileNameLength); + PhFree(buffer); + + return status; +} + +NTSTATUS PhGetFileAllInformation( + _In_ HANDLE FileHandle, + _Out_ PFILE_ALL_INFORMATION *FileInformation + ) +{ + return PhpQueryFileVariableSize( + FileHandle, + FileAllInformation, + FileInformation + ); +} + +NTSTATUS PhGetFileId( + _In_ HANDLE FileHandle, + _Out_ PFILE_ID_INFORMATION *FileId + ) +{ + return PhpQueryFileVariableSize( + FileHandle, + FileIdInformation, + FileId + ); +} + NTSTATUS PhpQueryTransactionManagerVariableSize( _In_ HANDLE TransactionManagerHandle, _In_ TRANSACTIONMANAGER_INFORMATION_CLASS TransactionManagerInformationClass, @@ -5247,6 +5319,48 @@ NTSTATUS PhEnumFileStreamsEx( return status; } +NTSTATUS PhEnumFileHardLinks( + _In_ HANDLE FileHandle, + _Out_ PVOID *HardLinks + ) +{ + return PhpQueryFileVariableSize( + FileHandle, + FileHardLinkInformation, + HardLinks + ); +} + +NTSTATUS PhEnumFileHardLinksEx( + _In_ HANDLE FileHandle, + _In_ PPH_ENUM_FILE_HARDLINKS Callback, + _In_opt_ PVOID Context + ) +{ + NTSTATUS status; + PFILE_LINKS_INFORMATION buffer; + PFILE_LINK_ENTRY_INFORMATION i; + + status = PhpQueryFileVariableSize( + FileHandle, + FileHardLinkInformation, + &buffer + ); + + if (NT_SUCCESS(status)) + { + for (i = PH_FIRST_LINK(&buffer->Entry); i; i = PH_NEXT_LINK(i)) + { + if (!Callback(i, Context)) + break; + } + + PhFree(buffer); + } + + return status; +} + /** * Initializes the device prefixes module. */ From ae74e141a7360b3babc29768fd2090ac1d3f1b0e Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 27 Dec 2018 22:33:17 +0100 Subject: [PATCH 1501/2058] Add file ProcessIds wrapper --- phlib/include/phnative.h | 8 ++++++++ phlib/native.c | 12 ++++++++++++ 2 files changed, 20 insertions(+) diff --git a/phlib/include/phnative.h b/phlib/include/phnative.h index 2a4c14b9fde7..fe5ba277f882 100644 --- a/phlib/include/phnative.h +++ b/phlib/include/phnative.h @@ -515,6 +515,14 @@ PhGetFileId( _Out_ PFILE_ID_INFORMATION *FileId ); +PHLIBAPI +NTSTATUS +NTAPI +PhGetProcessIdsUsingFile( + _In_ HANDLE FileHandle, + _Out_ PFILE_PROCESS_IDS_USING_FILE_INFORMATION *ProcessIdsUsingFile + ); + PHLIBAPI NTSTATUS NTAPI diff --git a/phlib/native.c b/phlib/native.c index 3fdc29fb3de9..deca2148b34e 100644 --- a/phlib/native.c +++ b/phlib/native.c @@ -2578,6 +2578,18 @@ NTSTATUS PhGetFileId( ); } +NTSTATUS PhGetProcessIdsUsingFile( + _In_ HANDLE FileHandle, + _Out_ PFILE_PROCESS_IDS_USING_FILE_INFORMATION *ProcessIdsUsingFile + ) +{ + return PhpQueryFileVariableSize( + FileHandle, + FileProcessIdsUsingFileInformation, + ProcessIdsUsingFile + ); +} + NTSTATUS PhpQueryTransactionManagerVariableSize( _In_ HANDLE TransactionManagerHandle, _In_ TRANSACTIONMANAGER_INFORMATION_CLASS TransactionManagerInformationClass, From 6353811473d17f5b715e309212d6574ff97bd720 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 29 Dec 2018 20:55:26 +0100 Subject: [PATCH 1502/2058] Fix incorrect default options window setting --- ProcessHacker/settings.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ProcessHacker/settings.c b/ProcessHacker/settings.c index 34a50bc4e4f3..01ac6d28917d 100644 --- a/ProcessHacker/settings.c +++ b/ProcessHacker/settings.c @@ -129,7 +129,7 @@ VOID PhAddDefaultSettings( PhpAddStringSetting(L"NetworkTreeListColumns", L""); PhpAddStringSetting(L"NetworkTreeListSort", L"0,1"); // 0, AscendingSortOrder PhpAddIntegerSetting(L"NoPurgeProcessRecords", L"0"); - PhpAddIntegerPairSetting(L"OptionsWindowPosition", L"200,200"); + PhpAddIntegerPairSetting(L"OptionsWindowPosition", L"0,0"); PhpAddScalableIntegerPairSetting(L"OptionsWindowSize", L"@96|900,590"); PhpAddIntegerPairSetting(L"PluginManagerWindowPosition", L"0,0"); PhpAddScalableIntegerPairSetting(L"PluginManagerWindowSize", L"@96|900,590"); From 89130edbd73a6bb15fc42f8ee451b529d6c4a2e5 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 29 Dec 2018 21:06:14 +0100 Subject: [PATCH 1503/2058] Fix options dpi scaling --- ProcessHacker/options.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ProcessHacker/options.c b/ProcessHacker/options.c index bdbe0ee4e7a1..45c528148901 100644 --- a/ProcessHacker/options.c +++ b/ProcessHacker/options.c @@ -271,7 +271,7 @@ INT_PTR CALLBACK PhOptionsDialogProc( SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER))); SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER))); - OptionsTreeImageList = ImageList_Create(2, 22, ILC_COLOR, 1, 1); + OptionsTreeImageList = ImageList_Create(2, PH_SCALE_DPI(22), ILC_COLOR, 1, 1); OptionsTreeControl = GetDlgItem(hwndDlg, IDC_SECTIONTREE); ContainerControl = GetDlgItem(hwndDlg, IDD_CONTAINER); @@ -1227,7 +1227,7 @@ INT_PTR CALLBACK PhpOptionsGeneralDlgProc( comboBoxHandle = GetDlgItem(hwndDlg, IDC_MAXSIZEUNIT); listviewHandle = GetDlgItem(hwndDlg, IDC_SETTINGS); - GeneralListviewImageList = ImageList_Create(1, 22, ILC_COLOR, 1, 1); + GeneralListviewImageList = ImageList_Create(1, PH_SCALE_DPI(22), ILC_COLOR, 1, 1); PhInitializeLayoutManager(&LayoutManager, hwndDlg); PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDC_SEARCHENGINE), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); From 3b59f9e122d81dd6599d842ec24c7ac2e56b28f9 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 30 Dec 2018 03:10:23 +0100 Subject: [PATCH 1504/2058] Redefine dll import macros --- ProcessHacker/ProcessHacker.def | 3 ++ phlib/include/phbasesup.h | 74 --------------------------------- phlib/include/phnative.h | 24 +++++++++++ phlib/native.c | 66 +++++++++++++++++++++++++++++ 4 files changed, 93 insertions(+), 74 deletions(-) diff --git a/ProcessHacker/ProcessHacker.def b/ProcessHacker/ProcessHacker.def index 0c009c10047e..c4127b3316b3 100644 --- a/ProcessHacker/ProcessHacker.def +++ b/ProcessHacker/ProcessHacker.def @@ -266,6 +266,9 @@ EXPORTS PhGetKernelFileName PhGetObjectSecurity PhGetOwnTokenAttributes + PhGetDllHandle + PhGetModuleProcAddress + PhGetProcedureAddress PhGetProcedureAddressRemote PhGetProcessCommandLine PhGetProcessDepStatus diff --git a/phlib/include/phbasesup.h b/phlib/include/phbasesup.h index 2611547ab384..37c48466f80b 100644 --- a/phlib/include/phbasesup.h +++ b/phlib/include/phbasesup.h @@ -57,80 +57,6 @@ PhCreateThread2( _In_opt_ PVOID Parameter ); -// DLLs - -FORCEINLINE -PVOID -PhGetDllHandle( - _In_ PWSTR DllName - ) -{ - UNICODE_STRING dllName; - PVOID dllHandle; - - RtlInitUnicodeString(&dllName, DllName); - - if (NT_SUCCESS(LdrGetDllHandle(NULL, NULL, &dllName, &dllHandle))) - return dllHandle; - else - return NULL; -} - -FORCEINLINE -PVOID -PhGetProcedureAddress( - _In_ PVOID DllHandle, - _In_opt_ PSTR ProcedureName, - _In_opt_ ULONG ProcedureNumber - ) -{ - NTSTATUS status; - ANSI_STRING procedureName; - PVOID procedureAddress; - - if (ProcedureName) - { - RtlInitAnsiString(&procedureName, ProcedureName); - status = LdrGetProcedureAddress( - DllHandle, - &procedureName, - 0, - &procedureAddress - ); - } - else - { - status = LdrGetProcedureAddress( - DllHandle, - NULL, - ProcedureNumber, - &procedureAddress - ); - } - - if (!NT_SUCCESS(status)) - return NULL; - - return procedureAddress; -} - -FORCEINLINE -PVOID -PhGetModuleProcAddress( - _In_ PWSTR ModuleName, - _In_ PSTR ProcName - ) -{ - PVOID module; - - module = PhGetDllHandle(ModuleName); - - if (module) - return PhGetProcedureAddress(module, ProcName, 0); - else - return NULL; -} - // Misc. system PHLIBAPI diff --git a/phlib/include/phnative.h b/phlib/include/phnative.h index fe5ba277f882..5ba30eb1bcb6 100644 --- a/phlib/include/phnative.h +++ b/phlib/include/phnative.h @@ -683,6 +683,30 @@ PhSetProcessModuleLoadCount32( _In_ ULONG LoadCount ); +PHLIBAPI +PVOID +NTAPI +PhGetDllHandle( + _In_ PWSTR DllName + ); + +PHLIBAPI +PVOID +NTAPI +PhGetModuleProcAddress( + _In_ PWSTR ModuleName, + _In_ PSTR ProcName + ); + +PHLIBAPI +PVOID +NTAPI +PhGetProcedureAddress( + _In_ PVOID DllHandle, + _In_opt_ PSTR ProcedureName, + _In_opt_ ULONG ProcedureNumber + ); + PHLIBAPI NTSTATUS NTAPI diff --git a/phlib/native.c b/phlib/native.c index deca2148b34e..492418ca87cf 100644 --- a/phlib/native.c +++ b/phlib/native.c @@ -4045,6 +4045,72 @@ NTSTATUS PhSetProcessModuleLoadCount32( return context.Status; } +PVOID PhGetDllHandle( + _In_ PWSTR DllName + ) +{ + UNICODE_STRING dllName; + PVOID dllHandle; + + RtlInitUnicodeString(&dllName, DllName); + + if (NT_SUCCESS(LdrGetDllHandle(NULL, NULL, &dllName, &dllHandle))) + return dllHandle; + else + return NULL; +} + +PVOID PhGetModuleProcAddress( + _In_ PWSTR ModuleName, + _In_ PSTR ProcName + ) +{ + PVOID module; + + module = PhGetDllHandle(ModuleName); + + if (module) + return PhGetProcedureAddress(module, ProcName, 0); + else + return NULL; +} + +PVOID PhGetProcedureAddress( + _In_ PVOID DllHandle, + _In_opt_ PSTR ProcedureName, + _In_opt_ ULONG ProcedureNumber + ) +{ + NTSTATUS status; + ANSI_STRING procedureName; + PVOID procedureAddress; + + if (ProcedureName) + { + RtlInitAnsiString(&procedureName, ProcedureName); + status = LdrGetProcedureAddress( + DllHandle, + &procedureName, + 0, + &procedureAddress + ); + } + else + { + status = LdrGetProcedureAddress( + DllHandle, + NULL, + ProcedureNumber, + &procedureAddress + ); + } + + if (!NT_SUCCESS(status)) + return NULL; + + return procedureAddress; +} + typedef struct _GET_PROCEDURE_ADDRESS_REMOTE_CONTEXT { PH_STRINGREF FileName; From 43b707369638a84e41dc4bef5b50962d3951417d Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 30 Dec 2018 17:55:45 +0100 Subject: [PATCH 1505/2058] Add RS5 mitigation policies --- ProcessHacker/mtgndlg.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/ProcessHacker/mtgndlg.c b/ProcessHacker/mtgndlg.c index dc37d6e7d7e2..85bd4aa4fb69 100644 --- a/ProcessHacker/mtgndlg.c +++ b/ProcessHacker/mtgndlg.c @@ -216,6 +216,30 @@ INT_PTR CALLBACK PhpProcessMitigationPolicyDlgProc( PhAddListViewItem(lvHandle, MAXINT, entry->ShortDescription->Buffer, entry); } + + if (context->SystemDllInitBlock->MitigationOptionsMap.Map[0] & PROCESS_CREATION_MITIGATION_POLICY2_ALLOW_DOWNGRADE_DYNAMIC_CODE_POLICY_ALWAYS_ON) + { + PMITIGATION_POLICY_ENTRY entry; + + entry = PhAllocate(sizeof(MITIGATION_POLICY_ENTRY)); + entry->NonStandard = TRUE; + entry->ShortDescription = PhCreateString(L"Dynamic code (downgrade)"); + entry->LongDescription = PhCreateString(L"Allows a broker to downgrade the dynamic code policy for a process."); + + PhAddListViewItem(lvHandle, MAXINT, entry->ShortDescription->Buffer, entry); + } + + if (context->SystemDllInitBlock->MitigationOptionsMap.Map[0] & PROCESS_CREATION_MITIGATION_POLICY2_SPECULATIVE_STORE_BYPASS_DISABLE_ALWAYS_ON) + { + PMITIGATION_POLICY_ENTRY entry; + + entry = PhAllocate(sizeof(MITIGATION_POLICY_ENTRY)); + entry->NonStandard = TRUE; + entry->ShortDescription = PhCreateString(L"Speculative store bypass"); + entry->LongDescription = PhCreateString(L"Disables spectre mitigations for the process."); + + PhAddListViewItem(lvHandle, MAXINT, entry->ShortDescription->Buffer, entry); + } } ExtendedListView_SortItems(lvHandle); From 1786b69c325f74bb9d6a0b2d2b6f9fa31c5bd136 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 30 Dec 2018 20:17:34 +0100 Subject: [PATCH 1506/2058] Update macro usage --- ProcessHacker/proctree.c | 198 +++++++++++++++++++-------------------- 1 file changed, 99 insertions(+), 99 deletions(-) diff --git a/ProcessHacker/proctree.c b/ProcessHacker/proctree.c index 2a595a95d5e0..6044a08111d2 100644 --- a/ProcessHacker/proctree.c +++ b/ProcessHacker/proctree.c @@ -132,84 +132,84 @@ VOID PhInitializeProcessTreeList( PhAddTreeNewColumn(hwnd, PHPRTLC_DESCRIPTION, TRUE, L"Description", 180, PH_ALIGN_LEFT, 5, 0); // Customizable columns (1) - PhAddTreeNewColumn(hwnd, PHPRTLC_COMPANYNAME, FALSE, L"Company name", 180, PH_ALIGN_LEFT, -1, 0); - PhAddTreeNewColumn(hwnd, PHPRTLC_VERSION, FALSE, L"Version", 100, PH_ALIGN_LEFT, -1, 0); - PhAddTreeNewColumn(hwnd, PHPRTLC_FILENAME, FALSE, L"File name", 180, PH_ALIGN_LEFT, -1, DT_PATH_ELLIPSIS); - PhAddTreeNewColumn(hwnd, PHPRTLC_COMMANDLINE, FALSE, L"Command line", 180, PH_ALIGN_LEFT, -1, 0); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_PEAKPRIVATEBYTES, FALSE, L"Peak private bytes", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_WORKINGSET, FALSE, L"Working set", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_PEAKWORKINGSET, FALSE, L"Peak working set", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_PRIVATEWS, FALSE, L"Private WS", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_SHAREDWS, FALSE, L"Shared WS", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_SHAREABLEWS, FALSE, L"Shareable WS", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_VIRTUALSIZE, FALSE, L"Virtual size", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_PEAKVIRTUALSIZE, FALSE, L"Peak virtual size", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_PAGEFAULTS, FALSE, L"Page faults", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); - PhAddTreeNewColumn(hwnd, PHPRTLC_SESSIONID, FALSE, L"Session ID", 45, PH_ALIGN_RIGHT, -1, DT_RIGHT); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_PRIORITYCLASS, FALSE, L"Priority class", 100, PH_ALIGN_LEFT, -1, 0, TRUE); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_BASEPRIORITY, FALSE, L"Base priority", 45, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); + PhAddTreeNewColumn(hwnd, PHPRTLC_COMPANYNAME, FALSE, L"Company name", 180, PH_ALIGN_LEFT, ULONG_MAX, 0); + PhAddTreeNewColumn(hwnd, PHPRTLC_VERSION, FALSE, L"Version", 100, PH_ALIGN_LEFT, ULONG_MAX, 0); + PhAddTreeNewColumn(hwnd, PHPRTLC_FILENAME, FALSE, L"File name", 180, PH_ALIGN_LEFT, ULONG_MAX, DT_PATH_ELLIPSIS); + PhAddTreeNewColumn(hwnd, PHPRTLC_COMMANDLINE, FALSE, L"Command line", 180, PH_ALIGN_LEFT, ULONG_MAX, 0); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_PEAKPRIVATEBYTES, FALSE, L"Peak private bytes", 70, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_WORKINGSET, FALSE, L"Working set", 70, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_PEAKWORKINGSET, FALSE, L"Peak working set", 70, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_PRIVATEWS, FALSE, L"Private WS", 70, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_SHAREDWS, FALSE, L"Shared WS", 70, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_SHAREABLEWS, FALSE, L"Shareable WS", 70, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_VIRTUALSIZE, FALSE, L"Virtual size", 70, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_PEAKVIRTUALSIZE, FALSE, L"Peak virtual size", 70, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_PAGEFAULTS, FALSE, L"Page faults", 70, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE); + PhAddTreeNewColumn(hwnd, PHPRTLC_SESSIONID, FALSE, L"Session ID", 45, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_PRIORITYCLASS, FALSE, L"Priority class", 100, PH_ALIGN_LEFT, ULONG_MAX, 0, TRUE); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_BASEPRIORITY, FALSE, L"Base priority", 45, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE); // Customizable columns (2) - PhAddTreeNewColumnEx(hwnd, PHPRTLC_THREADS, FALSE, L"Threads", 45, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_HANDLES, FALSE, L"Handles", 45, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_GDIHANDLES, FALSE, L"GDI handles", 45, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_USERHANDLES, FALSE, L"USER handles", 45, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_IORORATE, FALSE, L"I/O read+other rate", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_IOWRATE, FALSE, L"I/O write rate", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); - PhAddTreeNewColumn(hwnd, PHPRTLC_INTEGRITY, FALSE, L"Integrity", 100, PH_ALIGN_LEFT, -1, 0); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_IOPRIORITY, FALSE, L"I/O priority", 70, PH_ALIGN_LEFT, -1, 0, TRUE); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_PAGEPRIORITY, FALSE, L"Page priority", 45, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_STARTTIME, FALSE, L"Start time", 100, PH_ALIGN_LEFT, -1, 0, TRUE); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_TOTALCPUTIME, FALSE, L"Total CPU time", 90, PH_ALIGN_LEFT, -1, 0, TRUE); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_KERNELCPUTIME, FALSE, L"Kernel CPU time", 90, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_USERCPUTIME, FALSE, L"User CPU time", 90, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); - PhAddTreeNewColumn(hwnd, PHPRTLC_VERIFICATIONSTATUS, FALSE, L"Verification status", 70, PH_ALIGN_LEFT, -1, 0); - PhAddTreeNewColumn(hwnd, PHPRTLC_VERIFIEDSIGNER, FALSE, L"Verified signer", 100, PH_ALIGN_LEFT, -1, 0); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_ASLR, FALSE, L"ASLR", 50, PH_ALIGN_LEFT, -1, 0, TRUE); - PhAddTreeNewColumn(hwnd, PHPRTLC_RELATIVESTARTTIME, FALSE, L"Relative start time", 180, PH_ALIGN_LEFT, -1, 0); - PhAddTreeNewColumn(hwnd, PHPRTLC_BITS, FALSE, L"Bits", 50, PH_ALIGN_LEFT, -1, 0); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_ELEVATION, FALSE, L"Elevation", 60, PH_ALIGN_LEFT, -1, 0, TRUE); - PhAddTreeNewColumn(hwnd, PHPRTLC_WINDOWTITLE, FALSE, L"Window title", 120, PH_ALIGN_LEFT, -1, 0); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_WINDOWSTATUS, FALSE, L"Window status", 60, PH_ALIGN_LEFT, -1, 0, TRUE); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_CYCLES, FALSE, L"Cycles", 110, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_CYCLESDELTA, FALSE, L"Cycles delta", 90, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); - PhAddTreeNewColumnEx2(hwnd, PHPRTLC_CPUHISTORY, FALSE, L"CPU history", 100, PH_ALIGN_LEFT, -1, 0, TN_COLUMN_FLAG_CUSTOMDRAW | TN_COLUMN_FLAG_SORTDESCENDING); - PhAddTreeNewColumnEx2(hwnd, PHPRTLC_PRIVATEBYTESHISTORY, FALSE, L"Private bytes history", 100, PH_ALIGN_LEFT, -1, 0, TN_COLUMN_FLAG_CUSTOMDRAW | TN_COLUMN_FLAG_SORTDESCENDING); - PhAddTreeNewColumnEx2(hwnd, PHPRTLC_IOHISTORY, FALSE, L"I/O history", 100, PH_ALIGN_LEFT, -1, 0, TN_COLUMN_FLAG_CUSTOMDRAW | TN_COLUMN_FLAG_SORTDESCENDING); - PhAddTreeNewColumn(hwnd, PHPRTLC_DEP, FALSE, L"DEP", 100, PH_ALIGN_LEFT, -1, 0); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_VIRTUALIZED, FALSE, L"Virtualized", 80, PH_ALIGN_LEFT, -1, 0, TRUE); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_CONTEXTSWITCHES, FALSE, L"Context switches", 100, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_CONTEXTSWITCHESDELTA, FALSE, L"Context switches delta", 80, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_PAGEFAULTSDELTA, FALSE, L"Page faults delta", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_THREADS, FALSE, L"Threads", 45, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_HANDLES, FALSE, L"Handles", 45, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_GDIHANDLES, FALSE, L"GDI handles", 45, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_USERHANDLES, FALSE, L"USER handles", 45, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_IORORATE, FALSE, L"I/O read+other rate", 70, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_IOWRATE, FALSE, L"I/O write rate", 70, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE); + PhAddTreeNewColumn(hwnd, PHPRTLC_INTEGRITY, FALSE, L"Integrity", 100, PH_ALIGN_LEFT, ULONG_MAX, 0); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_IOPRIORITY, FALSE, L"I/O priority", 70, PH_ALIGN_LEFT, ULONG_MAX, 0, TRUE); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_PAGEPRIORITY, FALSE, L"Page priority", 45, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_STARTTIME, FALSE, L"Start time", 100, PH_ALIGN_LEFT, ULONG_MAX, 0, TRUE); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_TOTALCPUTIME, FALSE, L"Total CPU time", 90, PH_ALIGN_LEFT, ULONG_MAX, 0, TRUE); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_KERNELCPUTIME, FALSE, L"Kernel CPU time", 90, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_USERCPUTIME, FALSE, L"User CPU time", 90, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE); + PhAddTreeNewColumn(hwnd, PHPRTLC_VERIFICATIONSTATUS, FALSE, L"Verification status", 70, PH_ALIGN_LEFT, ULONG_MAX, 0); + PhAddTreeNewColumn(hwnd, PHPRTLC_VERIFIEDSIGNER, FALSE, L"Verified signer", 100, PH_ALIGN_LEFT, ULONG_MAX, 0); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_ASLR, FALSE, L"ASLR", 50, PH_ALIGN_LEFT, ULONG_MAX, 0, TRUE); + PhAddTreeNewColumn(hwnd, PHPRTLC_RELATIVESTARTTIME, FALSE, L"Relative start time", 180, PH_ALIGN_LEFT, ULONG_MAX, 0); + PhAddTreeNewColumn(hwnd, PHPRTLC_BITS, FALSE, L"Bits", 50, PH_ALIGN_LEFT, ULONG_MAX, 0); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_ELEVATION, FALSE, L"Elevation", 60, PH_ALIGN_LEFT, ULONG_MAX, 0, TRUE); + PhAddTreeNewColumn(hwnd, PHPRTLC_WINDOWTITLE, FALSE, L"Window title", 120, PH_ALIGN_LEFT, ULONG_MAX, 0); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_WINDOWSTATUS, FALSE, L"Window status", 60, PH_ALIGN_LEFT, ULONG_MAX, 0, TRUE); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_CYCLES, FALSE, L"Cycles", 110, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_CYCLESDELTA, FALSE, L"Cycles delta", 90, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE); + PhAddTreeNewColumnEx2(hwnd, PHPRTLC_CPUHISTORY, FALSE, L"CPU history", 100, PH_ALIGN_LEFT, ULONG_MAX, 0, TN_COLUMN_FLAG_CUSTOMDRAW | TN_COLUMN_FLAG_SORTDESCENDING); + PhAddTreeNewColumnEx2(hwnd, PHPRTLC_PRIVATEBYTESHISTORY, FALSE, L"Private bytes history", 100, PH_ALIGN_LEFT, ULONG_MAX, 0, TN_COLUMN_FLAG_CUSTOMDRAW | TN_COLUMN_FLAG_SORTDESCENDING); + PhAddTreeNewColumnEx2(hwnd, PHPRTLC_IOHISTORY, FALSE, L"I/O history", 100, PH_ALIGN_LEFT, ULONG_MAX, 0, TN_COLUMN_FLAG_CUSTOMDRAW | TN_COLUMN_FLAG_SORTDESCENDING); + PhAddTreeNewColumn(hwnd, PHPRTLC_DEP, FALSE, L"DEP", 100, PH_ALIGN_LEFT, ULONG_MAX, 0); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_VIRTUALIZED, FALSE, L"Virtualized", 80, PH_ALIGN_LEFT, ULONG_MAX, 0, TRUE); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_CONTEXTSWITCHES, FALSE, L"Context switches", 100, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_CONTEXTSWITCHESDELTA, FALSE, L"Context switches delta", 80, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_PAGEFAULTSDELTA, FALSE, L"Page faults delta", 70, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE); // I/O group columns - PhAddTreeNewColumnEx(hwnd, PHPRTLC_IOREADS, FALSE, L"I/O reads", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_IOWRITES, FALSE, L"I/O writes", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_IOOTHER, FALSE, L"I/O other", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_IOREADBYTES, FALSE, L"I/O read bytes", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_IOWRITEBYTES, FALSE, L"I/O write bytes", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_IOOTHERBYTES, FALSE, L"I/O other bytes", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_IOREADSDELTA, FALSE, L"I/O reads delta", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_IOWRITESDELTA, FALSE, L"I/O writes delta", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_IOOTHERDELTA, FALSE, L"I/O other delta", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_IOREADS, FALSE, L"I/O reads", 70, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_IOWRITES, FALSE, L"I/O writes", 70, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_IOOTHER, FALSE, L"I/O other", 70, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_IOREADBYTES, FALSE, L"I/O read bytes", 70, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_IOWRITEBYTES, FALSE, L"I/O write bytes", 70, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_IOOTHERBYTES, FALSE, L"I/O other bytes", 70, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_IOREADSDELTA, FALSE, L"I/O reads delta", 70, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_IOWRITESDELTA, FALSE, L"I/O writes delta", 70, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_IOOTHERDELTA, FALSE, L"I/O other delta", 70, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE); // Customizable columns (3) - PhAddTreeNewColumn(hwnd, PHPRTLC_OSCONTEXT, FALSE, L"OS context", 100, PH_ALIGN_LEFT, -1, 0); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_PAGEDPOOL, FALSE, L"Paged pool", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_PEAKPAGEDPOOL, FALSE, L"Peak paged pool", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_NONPAGEDPOOL, FALSE, L"Non-paged pool", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_PEAKNONPAGEDPOOL, FALSE, L"Peak non-paged pool", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_MINIMUMWORKINGSET, FALSE, L"Minimum working set", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_MAXIMUMWORKINGSET, FALSE, L"Maximum working set", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_PRIVATEBYTESDELTA, FALSE, L"Private bytes delta", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); - PhAddTreeNewColumn(hwnd, PHPRTLC_SUBSYSTEM, FALSE, L"Subsystem", 110, PH_ALIGN_LEFT, -1, 0); - PhAddTreeNewColumn(hwnd, PHPRTLC_PACKAGENAME, FALSE, L"Package name", 160, PH_ALIGN_LEFT, -1, 0); - PhAddTreeNewColumn(hwnd, PHPRTLC_APPID, FALSE, L"App ID", 160, PH_ALIGN_LEFT, -1, 0); - PhAddTreeNewColumn(hwnd, PHPRTLC_DPIAWARENESS, FALSE, L"DPI awareness", 110, PH_ALIGN_LEFT, -1, 0); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_CFGUARD, FALSE, L"CF Guard", 70, PH_ALIGN_LEFT, -1, 0, TRUE); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_TIMESTAMP, FALSE, L"Time stamp", 140, PH_ALIGN_LEFT, -1, 0, TRUE); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_FILEMODIFIEDTIME, FALSE, L"File modified time", 140, PH_ALIGN_LEFT, -1, 0, TRUE); - PhAddTreeNewColumnEx(hwnd, PHPRTLC_FILESIZE, FALSE, L"File size", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); + PhAddTreeNewColumn(hwnd, PHPRTLC_OSCONTEXT, FALSE, L"OS context", 100, PH_ALIGN_LEFT, ULONG_MAX, 0); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_PAGEDPOOL, FALSE, L"Paged pool", 70, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_PEAKPAGEDPOOL, FALSE, L"Peak paged pool", 70, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_NONPAGEDPOOL, FALSE, L"Non-paged pool", 70, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_PEAKNONPAGEDPOOL, FALSE, L"Peak non-paged pool", 70, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_MINIMUMWORKINGSET, FALSE, L"Minimum working set", 70, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_MAXIMUMWORKINGSET, FALSE, L"Maximum working set", 70, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_PRIVATEBYTESDELTA, FALSE, L"Private bytes delta", 70, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE); + PhAddTreeNewColumn(hwnd, PHPRTLC_SUBSYSTEM, FALSE, L"Subsystem", 110, PH_ALIGN_LEFT, ULONG_MAX, 0); + PhAddTreeNewColumn(hwnd, PHPRTLC_PACKAGENAME, FALSE, L"Package name", 160, PH_ALIGN_LEFT, ULONG_MAX, 0); + PhAddTreeNewColumn(hwnd, PHPRTLC_APPID, FALSE, L"App ID", 160, PH_ALIGN_LEFT, ULONG_MAX, 0); + PhAddTreeNewColumn(hwnd, PHPRTLC_DPIAWARENESS, FALSE, L"DPI awareness", 110, PH_ALIGN_LEFT, ULONG_MAX, 0); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_CFGUARD, FALSE, L"CF Guard", 70, PH_ALIGN_LEFT, ULONG_MAX, 0, TRUE); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_TIMESTAMP, FALSE, L"Time stamp", 140, PH_ALIGN_LEFT, ULONG_MAX, 0, TRUE); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_FILEMODIFIEDTIME, FALSE, L"File modified time", 140, PH_ALIGN_LEFT, ULONG_MAX, 0, TRUE); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_FILESIZE, FALSE, L"File size", 70, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE); PhAddTreeNewColumnEx(hwnd, PHPRTLC_SUBPROCESSCOUNT, FALSE, L"Subprocesses", 70, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE); PhAddTreeNewColumnEx(hwnd, PHPRTLC_JOBOBJECTID, FALSE, L"Job Object ID", 50, PH_ALIGN_LEFT, ULONG_MAX, 0, TRUE); PhAddTreeNewColumnEx(hwnd, PHPRTLC_PROTECTION, FALSE, L"Protection", 105, PH_ALIGN_LEFT, ULONG_MAX, 0, TRUE); @@ -533,14 +533,14 @@ VOID PhpRemoveProcessNode( { // Remove the node from its parent. - if ((index = PhFindItemList(ProcessNode->Parent->Children, ProcessNode)) != -1) + if ((index = PhFindItemList(ProcessNode->Parent->Children, ProcessNode)) != ULONG_MAX) PhRemoveItemList(ProcessNode->Parent->Children, index); } else { // Remove the node from the root list. - if ((index = PhFindItemList(ProcessNodeRootList, ProcessNode)) != -1) + if ((index = PhFindItemList(ProcessNodeRootList, ProcessNode)) != ULONG_MAX) PhRemoveItemList(ProcessNodeRootList, index); } @@ -555,7 +555,7 @@ VOID PhpRemoveProcessNode( // Remove from list and cleanup. - if ((index = PhFindItemList(ProcessNodeList, ProcessNode)) != -1) + if ((index = PhFindItemList(ProcessNodeList, ProcessNode)) != ULONG_MAX) PhRemoveItemList(ProcessNodeList, index); PhDereferenceObject(ProcessNode->Children); @@ -907,14 +907,14 @@ static VOID PhpUpdateProcessNodeIoPagePriority( if (ProcessNode->ProcessItem->QueryHandle) { if (!NT_SUCCESS(PhGetProcessIoPriority(ProcessNode->ProcessItem->QueryHandle, &ProcessNode->IoPriority))) - ProcessNode->IoPriority = -1; + ProcessNode->IoPriority = ULONG_MAX; if (!NT_SUCCESS(PhGetProcessPagePriority(ProcessNode->ProcessItem->QueryHandle, &ProcessNode->PagePriority))) - ProcessNode->PagePriority = -1; + ProcessNode->PagePriority = ULONG_MAX; } else { - ProcessNode->IoPriority = -1; - ProcessNode->PagePriority = -1; + ProcessNode->IoPriority = ULONG_MAX; + ProcessNode->PagePriority = ULONG_MAX; } ProcessNode->ValidMask |= PHPN_IOPAGEPRIORITY; @@ -2250,19 +2250,19 @@ BOOLEAN NTAPI PhpProcessTreeNewCallback( getCellText->Text = PhGetStringRef(processItem->CommandLine); break; case PHPRTLC_PEAKPRIVATEBYTES: - PhMoveReference(&node->PeakPrivateBytesText, PhFormatSize(processItem->VmCounters.PeakPagefileUsage, -1)); + PhMoveReference(&node->PeakPrivateBytesText, PhFormatSize(processItem->VmCounters.PeakPagefileUsage, ULONG_MAX)); getCellText->Text = node->PeakPrivateBytesText->sr; break; case PHPRTLC_WORKINGSET: { SIZE_T value = 0; PhpAggregateFieldIfNeeded(node, AggregateTypeIntPtr, AggregateLocationProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, VmCounters.WorkingSetSize), &value); - PhMoveReference(&node->WorkingSetText, PhFormatSize(value, -1)); + PhMoveReference(&node->WorkingSetText, PhFormatSize(value, ULONG_MAX)); getCellText->Text = node->WorkingSetText->sr; } break; case PHPRTLC_PEAKWORKINGSET: - PhMoveReference(&node->PeakWorkingSetText, PhFormatSize(processItem->VmCounters.PeakWorkingSetSize, -1)); + PhMoveReference(&node->PeakWorkingSetText, PhFormatSize(processItem->VmCounters.PeakWorkingSetSize, ULONG_MAX)); getCellText->Text = node->PeakWorkingSetText->sr; break; case PHPRTLC_PRIVATEWS: @@ -2283,24 +2283,24 @@ BOOLEAN NTAPI PhpProcessTreeNewCallback( break; case PHPRTLC_SHAREDWS: PhpUpdateProcessNodeWsCounters(node); - PhMoveReference(&node->SharedWsText, PhFormatSize((ULONG64)node->WsCounters.NumberOfSharedPages * PAGE_SIZE, -1)); + PhMoveReference(&node->SharedWsText, PhFormatSize((ULONG64)node->WsCounters.NumberOfSharedPages * PAGE_SIZE, ULONG_MAX)); getCellText->Text = node->SharedWsText->sr; break; case PHPRTLC_SHAREABLEWS: PhpUpdateProcessNodeWsCounters(node); - PhMoveReference(&node->ShareableWsText, PhFormatSize((ULONG64)node->WsCounters.NumberOfShareablePages * PAGE_SIZE, -1)); + PhMoveReference(&node->ShareableWsText, PhFormatSize((ULONG64)node->WsCounters.NumberOfShareablePages * PAGE_SIZE, ULONG_MAX)); getCellText->Text = node->ShareableWsText->sr; break; case PHPRTLC_VIRTUALSIZE: { SIZE_T value = 0; PhpAggregateFieldIfNeeded(node, AggregateTypeIntPtr, AggregateLocationProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, VmCounters.VirtualSize), &value); - PhMoveReference(&node->VirtualSizeText, PhFormatSize(value, -1)); + PhMoveReference(&node->VirtualSizeText, PhFormatSize(value, ULONG_MAX)); getCellText->Text = node->VirtualSizeText->sr; } break; case PHPRTLC_PEAKVIRTUALSIZE: - PhMoveReference(&node->PeakVirtualSizeText, PhFormatSize(processItem->VmCounters.PeakVirtualSize, -1)); + PhMoveReference(&node->PeakVirtualSizeText, PhFormatSize(processItem->VmCounters.PeakVirtualSize, ULONG_MAX)); getCellText->Text = node->PeakVirtualSizeText->sr; break; case PHPRTLC_PAGEFAULTS: @@ -2404,12 +2404,12 @@ BOOLEAN NTAPI PhpProcessTreeNewCallback( break; case PHPRTLC_IOPRIORITY: PhpUpdateProcessNodeIoPagePriority(node); - if (node->IoPriority != -1 && node->IoPriority < MaxIoPriorityTypes) + if (node->IoPriority != ULONG_MAX && node->IoPriority < MaxIoPriorityTypes) PhInitializeStringRefLongHint(&getCellText->Text, PhIoPriorityHintNames[node->IoPriority]); break; case PHPRTLC_PAGEPRIORITY: PhpUpdateProcessNodeIoPagePriority(node); - if (node->PagePriority != -1 && node->PagePriority <= MEMORY_PRIORITY_NORMAL) + if (node->PagePriority != ULONG_MAX && node->PagePriority <= MEMORY_PRIORITY_NORMAL) PhInitializeStringRefLongHint(&getCellText->Text, PhPagePriorityNames[node->PagePriority]); break; case PHPRTLC_STARTTIME: @@ -2636,7 +2636,7 @@ BOOLEAN NTAPI PhpProcessTreeNewCallback( if (value != 0) { - PhMoveReference(&node->IoGroupText[3], PhFormatSize(value, -1)); + PhMoveReference(&node->IoGroupText[3], PhFormatSize(value, ULONG_MAX)); getCellText->Text = node->IoGroupText[3]->sr; } } @@ -2648,7 +2648,7 @@ BOOLEAN NTAPI PhpProcessTreeNewCallback( if (value != 0) { - PhMoveReference(&node->IoGroupText[4], PhFormatSize(value, -1)); + PhMoveReference(&node->IoGroupText[4], PhFormatSize(value, ULONG_MAX)); getCellText->Text = node->IoGroupText[4]->sr; } } @@ -2660,7 +2660,7 @@ BOOLEAN NTAPI PhpProcessTreeNewCallback( if (value != 0) { - PhMoveReference(&node->IoGroupText[5], PhFormatSize(value, -1)); + PhMoveReference(&node->IoGroupText[5], PhFormatSize(value, ULONG_MAX)); getCellText->Text = node->IoGroupText[5]->sr; } } @@ -2729,24 +2729,24 @@ BOOLEAN NTAPI PhpProcessTreeNewCallback( { SIZE_T value = 0; PhpAggregateFieldIfNeeded(node, AggregateTypeIntPtr, AggregateLocationProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, VmCounters.QuotaPagedPoolUsage), &value); - PhMoveReference(&node->PagedPoolText, PhFormatSize(value, -1)); + PhMoveReference(&node->PagedPoolText, PhFormatSize(value, ULONG_MAX)); getCellText->Text = node->PagedPoolText->sr; } break; case PHPRTLC_PEAKPAGEDPOOL: - PhMoveReference(&node->PeakPagedPoolText, PhFormatSize(processItem->VmCounters.QuotaPeakPagedPoolUsage, -1)); + PhMoveReference(&node->PeakPagedPoolText, PhFormatSize(processItem->VmCounters.QuotaPeakPagedPoolUsage, ULONG_MAX)); getCellText->Text = node->PeakPagedPoolText->sr; break; case PHPRTLC_NONPAGEDPOOL: { SIZE_T value = 0; PhpAggregateFieldIfNeeded(node, AggregateTypeIntPtr, AggregateLocationProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, VmCounters.QuotaNonPagedPoolUsage), &value); - PhMoveReference(&node->NonPagedPoolText, PhFormatSize(value, -1)); + PhMoveReference(&node->NonPagedPoolText, PhFormatSize(value, ULONG_MAX)); getCellText->Text = node->NonPagedPoolText->sr; } break; case PHPRTLC_PEAKNONPAGEDPOOL: - PhMoveReference(&node->PeakNonPagedPoolText, PhFormatSize(processItem->VmCounters.QuotaPeakNonPagedPoolUsage, -1)); + PhMoveReference(&node->PeakNonPagedPoolText, PhFormatSize(processItem->VmCounters.QuotaPeakNonPagedPoolUsage, ULONG_MAX)); getCellText->Text = node->PeakNonPagedPoolText->sr; break; case PHPRTLC_MINIMUMWORKINGSET: @@ -2754,7 +2754,7 @@ BOOLEAN NTAPI PhpProcessTreeNewCallback( PhpUpdateProcessNodeQuotaLimits(node); SIZE_T value = 0; PhpAggregateFieldIfNeeded(node, AggregateTypeIntPtr, AggregateLocationProcessNode, FIELD_OFFSET(PH_PROCESS_NODE, MinimumWorkingSetSize), &value); - PhMoveReference(&node->MinimumWorkingSetText, PhFormatSize(value, -1)); + PhMoveReference(&node->MinimumWorkingSetText, PhFormatSize(value, ULONG_MAX)); getCellText->Text = node->MinimumWorkingSetText->sr; } break; @@ -2763,7 +2763,7 @@ BOOLEAN NTAPI PhpProcessTreeNewCallback( PhpUpdateProcessNodeQuotaLimits(node); SIZE_T value = 0; PhpAggregateFieldIfNeeded(node, AggregateTypeIntPtr, AggregateLocationProcessNode, FIELD_OFFSET(PH_PROCESS_NODE, MaximumWorkingSetSize), &value); - PhMoveReference(&node->MaximumWorkingSetText, PhFormatSize(value, -1)); + PhMoveReference(&node->MaximumWorkingSetText, PhFormatSize(value, ULONG_MAX)); getCellText->Text = node->MaximumWorkingSetText->sr; } break; @@ -2884,7 +2884,7 @@ BOOLEAN NTAPI PhpProcessTreeNewCallback( if (node->FileEndOfFile.QuadPart != -1) { - PhMoveReference(&node->FileSizeText, PhFormatSize(node->FileEndOfFile.QuadPart, -1)); + PhMoveReference(&node->FileSizeText, PhFormatSize(node->FileEndOfFile.QuadPart, ULONG_MAX)); getCellText->Text = node->FileSizeText->sr; } break; @@ -3050,7 +3050,7 @@ BOOLEAN NTAPI PhpProcessTreeNewCallback( { getCellTooltip->Text = node->TooltipText->sr; getCellTooltip->Unfolding = FALSE; - getCellTooltip->MaximumWidth = -1; + getCellTooltip->MaximumWidth = ULONG_MAX; } else { From 0a4a1175495375938e80d55083b5a40bad542790 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 30 Dec 2018 20:18:36 +0100 Subject: [PATCH 1507/2058] Add deltas to process statistics window --- ProcessHacker/prpgstat.c | 170 +++++++++++++++++++++++++++++++-------- 1 file changed, 138 insertions(+), 32 deletions(-) diff --git a/ProcessHacker/prpgstat.c b/ProcessHacker/prpgstat.c index 8fc3d0b26d66..1fe0c4fc7b57 100644 --- a/ProcessHacker/prpgstat.c +++ b/ProcessHacker/prpgstat.c @@ -42,15 +42,21 @@ typedef enum _PH_PROCESS_STATISTICS_INDEX { PH_PROCESS_STATISTICS_INDEX_PRIORITY, PH_PROCESS_STATISTICS_INDEX_CYCLES, + PH_PROCESS_STATISTICS_INDEX_CYCLESDELTA, PH_PROCESS_STATISTICS_INDEX_KERNELTIME, + PH_PROCESS_STATISTICS_INDEX_KERNELDELTA, PH_PROCESS_STATISTICS_INDEX_USERTIME, + PH_PROCESS_STATISTICS_INDEX_USERDELTA, PH_PROCESS_STATISTICS_INDEX_TOTALTIME, - + PH_PROCESS_STATISTICS_INDEX_TOTALDELTA, PH_PROCESS_STATISTICS_INDEX_PRIVATEBYTES, + PH_PROCESS_STATISTICS_INDEX_PRIVATEBYTESDELTA, + PH_PROCESS_STATISTICS_INDEX_PEAKPRIVATEBYTES, PH_PROCESS_STATISTICS_INDEX_VIRTUALSIZE, PH_PROCESS_STATISTICS_INDEX_PEAKVIRTUALSIZE, PH_PROCESS_STATISTICS_INDEX_PAGEFAULTS, + PH_PROCESS_STATISTICS_INDEX_PAGEFAULTSDELTA, PH_PROCESS_STATISTICS_INDEX_WORKINGSET, PH_PROCESS_STATISTICS_INDEX_PEAKWORKINGSET, PH_PROCESS_STATISTICS_INDEX_PRIVATEWS, @@ -59,11 +65,17 @@ typedef enum _PH_PROCESS_STATISTICS_INDEX PH_PROCESS_STATISTICS_INDEX_PAGEPRIORITY, PH_PROCESS_STATISTICS_INDEX_READS, + PH_PROCESS_STATISTICS_INDEX_READSDELTA, PH_PROCESS_STATISTICS_INDEX_READBYTES, + PH_PROCESS_STATISTICS_INDEX_READBYTESDELTA, PH_PROCESS_STATISTICS_INDEX_WRITES, + PH_PROCESS_STATISTICS_INDEX_WRITESDELTA, PH_PROCESS_STATISTICS_INDEX_WRITEBYTES, + PH_PROCESS_STATISTICS_INDEX_WRITEBYTESDELTA, PH_PROCESS_STATISTICS_INDEX_OTHER, + PH_PROCESS_STATISTICS_INDEX_OTHERDELTA, PH_PROCESS_STATISTICS_INDEX_OTHERBYTES, + PH_PROCESS_STATISTICS_INDEX_OTHERBYTESDELTA, PH_PROCESS_STATISTICS_INDEX_IOPRIORITY, PH_PROCESS_STATISTICS_INDEX_HANDLES, @@ -92,26 +104,42 @@ VOID PhpUpdateStatisticsAddListViewGroups( PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_CPU, PH_PROCESS_STATISTICS_INDEX_PRIORITY, L"Priority", NULL); PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_CPU, PH_PROCESS_STATISTICS_INDEX_CYCLES, L"Cycles", NULL); + PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_CPU, PH_PROCESS_STATISTICS_INDEX_CYCLESDELTA, L"Cycles delta", NULL); PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_CPU, PH_PROCESS_STATISTICS_INDEX_KERNELTIME, L"Kernel time", NULL); + PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_CPU, PH_PROCESS_STATISTICS_INDEX_KERNELDELTA, L"Kernel delta", NULL); PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_CPU, PH_PROCESS_STATISTICS_INDEX_USERTIME, L"User time", NULL); + PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_CPU, PH_PROCESS_STATISTICS_INDEX_USERDELTA, L"User delta", NULL); PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_CPU, PH_PROCESS_STATISTICS_INDEX_TOTALTIME, L"Total time", NULL); + PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_CPU, PH_PROCESS_STATISTICS_INDEX_TOTALDELTA, L"Total delta", NULL); + PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_MEMORY, PH_PROCESS_STATISTICS_INDEX_PRIVATEBYTES, L"Private bytes", NULL); + PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_MEMORY, PH_PROCESS_STATISTICS_INDEX_PRIVATEBYTESDELTA, L"Private bytes delta", NULL); PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_MEMORY, PH_PROCESS_STATISTICS_INDEX_PEAKPRIVATEBYTES, L"Peak private bytes", NULL); PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_MEMORY, PH_PROCESS_STATISTICS_INDEX_VIRTUALSIZE, L"Virtual size", NULL); PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_MEMORY, PH_PROCESS_STATISTICS_INDEX_PEAKVIRTUALSIZE, L"Peak virtual size", NULL); PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_MEMORY, PH_PROCESS_STATISTICS_INDEX_PAGEFAULTS, L"Page faults", NULL); + PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_MEMORY, PH_PROCESS_STATISTICS_INDEX_PAGEFAULTSDELTA, L"Page faults delta", NULL); + PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_MEMORY, PH_PROCESS_STATISTICS_INDEX_WORKINGSET, L"Working set", NULL); PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_MEMORY, PH_PROCESS_STATISTICS_INDEX_PEAKWORKINGSET, L"Peak working set", NULL); PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_MEMORY, PH_PROCESS_STATISTICS_INDEX_PRIVATEWS, L"Private WS", NULL); PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_MEMORY, PH_PROCESS_STATISTICS_INDEX_SHAREABLEWS, L"Shareable WS", NULL); PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_MEMORY, PH_PROCESS_STATISTICS_INDEX_SHAREDWS, L"Shared WS", NULL); PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_MEMORY, PH_PROCESS_STATISTICS_INDEX_PAGEPRIORITY, L"Page priority", NULL); + PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_IO, PH_PROCESS_STATISTICS_INDEX_READS, L"Reads", NULL); + PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_IO, PH_PROCESS_STATISTICS_INDEX_READSDELTA, L"Reads delta", NULL); PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_IO, PH_PROCESS_STATISTICS_INDEX_READBYTES, L"Read bytes", NULL); + PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_IO, PH_PROCESS_STATISTICS_INDEX_READBYTESDELTA, L"Read bytes delta", NULL); PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_IO, PH_PROCESS_STATISTICS_INDEX_WRITES, L"Writes", NULL); + PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_IO, PH_PROCESS_STATISTICS_INDEX_WRITESDELTA, L"Writes delta", NULL); PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_IO, PH_PROCESS_STATISTICS_INDEX_WRITEBYTES, L"Write bytes", NULL); + PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_IO, PH_PROCESS_STATISTICS_INDEX_WRITEBYTESDELTA, L"Write bytes delta", NULL); PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_IO, PH_PROCESS_STATISTICS_INDEX_OTHER, L"Other", NULL); + PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_IO, PH_PROCESS_STATISTICS_INDEX_OTHERDELTA, L"Other delta", NULL); PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_IO, PH_PROCESS_STATISTICS_INDEX_OTHERBYTES, L"Other bytes", NULL); + PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_IO, PH_PROCESS_STATISTICS_INDEX_OTHERBYTESDELTA, L"Other bytes delta", NULL); + PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_IO, PH_PROCESS_STATISTICS_INDEX_IOPRIORITY, L"I/O priority", NULL); PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_OTHER, PH_PROCESS_STATISTICS_INDEX_HANDLES, L"Handles", NULL); PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_OTHER, PH_PROCESS_STATISTICS_INDEX_PEAKHANDLES, L"Peak handles", NULL); @@ -128,6 +156,69 @@ VOID PhpUpdateStatisticsAddListViewGroups( } } +VOID PhpUpdateProcessStatisticDelta( + _In_ PPH_STATISTICS_CONTEXT Context, + _In_ INT Index, + _In_ ULONG_PTR Delta + ) +{ + LONG_PTR delta = (LONG_PTR)Delta; + + if (delta != 0) + { + PH_FORMAT format[2]; + + if (delta > 0) + { + PhInitFormatC(&format[0], '+'); + } + else + { + PhInitFormatC(&format[0], '-'); + delta = -delta; + } + + format[1].Type = SizeFormatType | FormatUseRadix; + format[1].Radix = (UCHAR)PhMaxSizeUnit; + format[1].u.Size = delta; + + PhSetListViewSubItem(Context->ListViewHandle, Index, 1, PH_AUTO_T(PH_STRING, PhFormat(format, 2, 0))->Buffer); + } + else + { + PhSetListViewSubItem(Context->ListViewHandle, Index, 1, L"0"); + } +} + +VOID PhpUpdateProcessStatisticDeltaBytes( + _In_ PPH_STATISTICS_CONTEXT Context, + _In_ INT Index, + _In_ PH_UINT64_DELTA DeltaBuffer + ) +{ + ULONG64 number = 0; + + if (DeltaBuffer.Delta != DeltaBuffer.Value) + { + number = DeltaBuffer.Delta; + number *= 1000; + number /= PhCsUpdateInterval; + } + + if (number != 0) + { + PH_FORMAT format[2]; + + PhInitFormatSize(&format[0], number); + PhInitFormatS(&format[1], L"/s"); + PhSetListViewSubItem(Context->ListViewHandle, Index, 1, PH_AUTO_T(PH_STRING, PhFormat(format, 2, 0))->Buffer); + } + else + { + PhSetListViewSubItem(Context->ListViewHandle, Index, 1, L"0"); + } +} + VOID PhpUpdateProcessStatistics( _In_ PPH_PROCESS_ITEM ProcessItem, _In_ PPH_STATISTICS_CONTEXT Context @@ -144,19 +235,34 @@ VOID PhpUpdateProcessStatistics( PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_USERTIME, 1, timeSpan); PhPrintTimeSpan(timeSpan, ProcessItem->KernelTime.QuadPart + ProcessItem->UserTime.QuadPart, PH_TIMESPAN_HMSM); PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_TOTALTIME, 1, timeSpan); - PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_PRIVATEBYTES, 1, PhaFormatSize(ProcessItem->VmCounters.PagefileUsage, -1)->Buffer); - PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_PEAKPRIVATEBYTES, 1, PhaFormatSize(ProcessItem->VmCounters.PeakPagefileUsage, -1)->Buffer); - PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_VIRTUALSIZE, 1, PhaFormatSize(ProcessItem->VmCounters.VirtualSize, -1)->Buffer); - PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_PEAKVIRTUALSIZE, 1, PhaFormatSize(ProcessItem->VmCounters.PeakVirtualSize, -1)->Buffer); + + PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_CYCLESDELTA, 1, PhaFormatUInt64(ProcessItem->CycleTimeDelta.Delta, TRUE)->Buffer); + PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_KERNELDELTA, 1, PhaFormatUInt64(ProcessItem->CpuKernelDelta.Delta, TRUE)->Buffer); + PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_USERDELTA, 1, PhaFormatUInt64(ProcessItem->CpuUserDelta.Delta, TRUE)->Buffer); + PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_TOTALDELTA, 1, PhaFormatUInt64(ProcessItem->CpuKernelDelta.Delta + ProcessItem->CpuUserDelta.Delta, TRUE)->Buffer); + + PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_PRIVATEBYTES, 1, PhaFormatSize(ProcessItem->VmCounters.PagefileUsage, ULONG_MAX)->Buffer); + PhpUpdateProcessStatisticDelta(Context, PH_PROCESS_STATISTICS_INDEX_PRIVATEBYTESDELTA, ProcessItem->PrivateBytesDelta.Delta); + PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_PEAKPRIVATEBYTES, 1, PhaFormatSize(ProcessItem->VmCounters.PeakPagefileUsage, ULONG_MAX)->Buffer); + PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_VIRTUALSIZE, 1, PhaFormatSize(ProcessItem->VmCounters.VirtualSize, ULONG_MAX)->Buffer); + PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_PEAKVIRTUALSIZE, 1, PhaFormatSize(ProcessItem->VmCounters.PeakVirtualSize, ULONG_MAX)->Buffer); PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_PAGEFAULTS, 1, PhaFormatUInt64(ProcessItem->VmCounters.PageFaultCount, TRUE)->Buffer); - PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_WORKINGSET, 1, PhaFormatSize(ProcessItem->VmCounters.WorkingSetSize, -1)->Buffer); - PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_PEAKWORKINGSET, 1, PhaFormatSize(ProcessItem->VmCounters.PeakWorkingSetSize, -1)->Buffer); + PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_PAGEFAULTSDELTA, 1, PhaFormatUInt64(ProcessItem->PageFaultsDelta.Delta, TRUE)->Buffer); + PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_WORKINGSET, 1, PhaFormatSize(ProcessItem->VmCounters.WorkingSetSize, ULONG_MAX)->Buffer); + PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_PEAKWORKINGSET, 1, PhaFormatSize(ProcessItem->VmCounters.PeakWorkingSetSize, ULONG_MAX)->Buffer); + PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_READS, 1, PhaFormatUInt64(ProcessItem->IoCounters.ReadOperationCount, TRUE)->Buffer); - PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_READBYTES, 1, PhaFormatSize(ProcessItem->IoCounters.ReadTransferCount, -1)->Buffer); + PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_READSDELTA, 1, PhaFormatUInt64(ProcessItem->IoReadCountDelta.Delta, TRUE)->Buffer); + PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_READBYTES, 1, PhaFormatSize(ProcessItem->IoCounters.ReadTransferCount, ULONG_MAX)->Buffer); + PhpUpdateProcessStatisticDeltaBytes(Context, PH_PROCESS_STATISTICS_INDEX_READBYTESDELTA, ProcessItem->IoReadDelta); PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_WRITES, 1, PhaFormatUInt64(ProcessItem->IoCounters.WriteOperationCount, TRUE)->Buffer); - PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_WRITEBYTES, 1, PhaFormatSize(ProcessItem->IoCounters.WriteTransferCount, -1)->Buffer); + PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_WRITESDELTA, 1, PhaFormatUInt64(ProcessItem->IoWriteCountDelta.Delta, TRUE)->Buffer); + PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_WRITEBYTES, 1, PhaFormatSize(ProcessItem->IoCounters.WriteTransferCount, ULONG_MAX)->Buffer); + PhpUpdateProcessStatisticDeltaBytes(Context, PH_PROCESS_STATISTICS_INDEX_WRITEBYTESDELTA, ProcessItem->IoWriteDelta); PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_OTHER, 1, PhaFormatUInt64(ProcessItem->IoCounters.OtherOperationCount, TRUE)->Buffer); - PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_OTHERBYTES, 1, PhaFormatSize(ProcessItem->IoCounters.OtherTransferCount, -1)->Buffer); + PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_OTHERDELTA, 1, PhaFormatUInt64(ProcessItem->IoOtherCountDelta.Delta, TRUE)->Buffer); + PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_OTHERBYTES, 1, PhaFormatSize(ProcessItem->IoCounters.OtherTransferCount, ULONG_MAX)->Buffer); + PhpUpdateProcessStatisticDeltaBytes(Context, PH_PROCESS_STATISTICS_INDEX_OTHERBYTESDELTA, ProcessItem->IoOtherDelta); PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_HANDLES, 1, PhaFormatUInt64(ProcessItem->NumberOfHandles, TRUE)->Buffer); // Optional information @@ -166,8 +272,8 @@ VOID PhpUpdateProcessStatistics( PPH_STRING gdiHandles = NULL; PPH_STRING userHandles = NULL; PPH_STRING cycles = NULL; - ULONG pagePriority = -1; - IO_PRIORITY_HINT ioPriority = -1; + ULONG pagePriority = ULONG_MAX; + IO_PRIORITY_HINT ioPriority = ULONG_MAX; PPH_STRING privateWs = NULL; PPH_STRING shareableWs = NULL; PPH_STRING sharedWs = NULL; @@ -203,9 +309,9 @@ VOID PhpUpdateProcessStatistics( if (NT_SUCCESS(PhGetProcessWsCounters(Context->ProcessHandle, &wsCounters))) { - privateWs = PhaFormatSize((ULONG64)wsCounters.NumberOfPrivatePages * PAGE_SIZE, -1); - shareableWs = PhaFormatSize((ULONG64)wsCounters.NumberOfShareablePages * PAGE_SIZE, -1); - sharedWs = PhaFormatSize((ULONG64)wsCounters.NumberOfSharedPages * PAGE_SIZE, -1); + privateWs = PhaFormatSize((ULONG64)wsCounters.NumberOfPrivatePages * PAGE_SIZE, ULONG_MAX); + shareableWs = PhaFormatSize((ULONG64)wsCounters.NumberOfShareablePages * PAGE_SIZE, ULONG_MAX); + sharedWs = PhaFormatSize((ULONG64)wsCounters.NumberOfSharedPages * PAGE_SIZE, ULONG_MAX); gotWsCounters = TRUE; } } @@ -213,27 +319,27 @@ VOID PhpUpdateProcessStatistics( if (!gotCycles) cycles = PhaFormatUInt64(ProcessItem->CycleTimeDelta.Value, TRUE); if (!gotWsCounters) - privateWs = PhaFormatSize(ProcessItem->WorkingSetPrivateSize, -1); + privateWs = PhaFormatSize(ProcessItem->WorkingSetPrivateSize, ULONG_MAX); - PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_CYCLES, 1, PhGetStringOrEmpty(cycles)); + PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_CYCLES, 1, PhGetStringOrDefault(cycles, L"N/A")); - if (pagePriority != -1 && pagePriority <= MEMORY_PRIORITY_NORMAL) + if (pagePriority != ULONG_MAX && pagePriority <= MEMORY_PRIORITY_NORMAL) PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_PAGEPRIORITY, 1, PhPagePriorityNames[pagePriority]); else - PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_PAGEPRIORITY, 1, L""); + PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_PAGEPRIORITY, 1, L"N/A"); - if (ioPriority != -1 && ioPriority < MaxIoPriorityTypes) + if (ioPriority != ULONG_MAX && ioPriority < MaxIoPriorityTypes) PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_IOPRIORITY, 1, PhIoPriorityHintNames[ioPriority]); else - PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_IOPRIORITY, 1, L""); + PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_IOPRIORITY, 1, L"N/A"); - PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_PRIVATEWS, 1, PhGetStringOrEmpty(privateWs)); - PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_SHAREABLEWS, 1, PhGetStringOrEmpty(shareableWs)); - PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_SHAREDWS, 1, PhGetStringOrEmpty(sharedWs)); + PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_PRIVATEWS, 1, PhGetStringOrDefault(privateWs, L"N/A")); + PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_SHAREABLEWS, 1, PhGetStringOrDefault(shareableWs, L"N/A")); + PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_SHAREDWS, 1, PhGetStringOrDefault(sharedWs, L"N/A")); - PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_PEAKHANDLES, 1, PhGetStringOrEmpty(peakHandles)); - PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_GDIHANDLES, 1, PhGetStringOrEmpty(gdiHandles)); - PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_USERHANDLES, 1, PhGetStringOrEmpty(userHandles)); + PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_PEAKHANDLES, 1, PhGetStringOrDefault(peakHandles, L"N/A")); + PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_GDIHANDLES, 1, PhGetStringOrDefault(gdiHandles, L"N/A")); + PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_USERHANDLES, 1, PhGetStringOrDefault(userHandles, L"N/A")); } if (WindowsVersion >= WINDOWS_10_RS3 && !PhIsExecutingInWow64()) @@ -248,11 +354,11 @@ VOID PhpUpdateProcessStatistics( if (processInfo && (processExtension = PH_PROCESS_EXTENSION(processInfo))) { - PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_CONTEXTSWITCHES, 1, PhaFormatUInt64(processExtension->ContextSwitches, TRUE)->Buffer); - PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_DISKREAD, 1, PhaFormatSize(processExtension->DiskCounters.BytesRead, -1)->Buffer); - PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_DISKWRITE, 1, PhaFormatSize(processExtension->DiskCounters.BytesWritten, -1)->Buffer); - PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_NETWORKTXRXBYTES, 1, PhaFormatSize(processExtension->EnergyValues.NetworkTxRxBytes, -1)->Buffer); - PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_MBBTXRXBYTES, 1, PhaFormatSize(processExtension->EnergyValues.MBBTxRxBytes, -1)->Buffer); + PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_CONTEXTSWITCHES, 1, PhaFormatUInt64(processExtension->ContextSwitches, TRUE)->Buffer); // TODO: ContextSwitchesDelta + PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_DISKREAD, 1, PhaFormatSize(processExtension->DiskCounters.BytesRead, ULONG_MAX)->Buffer); + PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_DISKWRITE, 1, PhaFormatSize(processExtension->DiskCounters.BytesWritten, ULONG_MAX)->Buffer); + PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_NETWORKTXRXBYTES, 1, PhaFormatSize(processExtension->EnergyValues.NetworkTxRxBytes, ULONG_MAX)->Buffer); + PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_MBBTXRXBYTES, 1, PhaFormatSize(processExtension->EnergyValues.MBBTxRxBytes, ULONG_MAX)->Buffer); } PhFree(processes); From 663c3c321b83d2797e5f764cc7a1d062c0e35ce8 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 30 Dec 2018 20:40:50 +0100 Subject: [PATCH 1508/2058] peview: Add workaround for 'access flags are incompatible' error dialog when viewing some binary types --- tools/peview/main.c | 54 +++++++++++++++++++++++++++++---------------- 1 file changed, 35 insertions(+), 19 deletions(-) diff --git a/tools/peview/main.c b/tools/peview/main.c index 2d8b137395a6..21d062c724b0 100644 --- a/tools/peview/main.c +++ b/tools/peview/main.c @@ -162,33 +162,49 @@ INT WINAPI wWinMain( else { NTSTATUS status; - - status = PhLoadMappedImageEx( - PvFileName->Buffer, - NULL, - TRUE, - &PvMappedImage + HANDLE fileHandle; + + status = PhCreateFileWin32( + &fileHandle, + PvFileName->Buffer, + FILE_READ_ATTRIBUTES | FILE_READ_DATA | SYNCHRONIZE, + FILE_ATTRIBUTE_NORMAL, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + FILE_OPEN, + FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT ); if (NT_SUCCESS(status)) { - switch (PvMappedImage.Signature) + status = PhLoadMappedImageEx( + PvFileName->Buffer, + fileHandle, + TRUE, + &PvMappedImage + ); + NtClose(fileHandle); + + if (NT_SUCCESS(status)) { - case IMAGE_DOS_SIGNATURE: - PvPeProperties(); - break; - case IMAGE_ELF_SIGNATURE: - PvExlfProperties(); - break; - default: - status = STATUS_IMAGE_SUBSYSTEM_NOT_PRESENT; - break; + switch (PvMappedImage.Signature) + { + case IMAGE_DOS_SIGNATURE: + PvPeProperties(); + break; + case IMAGE_ELF_SIGNATURE: + PvExlfProperties(); + break; + default: + status = STATUS_IMAGE_SUBSYSTEM_NOT_PRESENT; + break; + } } + + if (NT_SUCCESS(status)) + PhUnloadMappedImage(&PvMappedImage); } - if (NT_SUCCESS(status)) - PhUnloadMappedImage(&PvMappedImage); - else + if (!NT_SUCCESS(status)) PhShowStatus(NULL, L"Unable to load the file.", status, 0); } From 05eb80a5131e35b20c793b18c3010d13ce1ff3c7 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 30 Dec 2018 21:51:55 +0100 Subject: [PATCH 1509/2058] Fix default find window location --- ProcessHacker/findobj.c | 6 ++++-- ProcessHacker/settings.c | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/ProcessHacker/findobj.c b/ProcessHacker/findobj.c index 1b59d0a5117e..9f5dca981a6e 100644 --- a/ProcessHacker/findobj.c +++ b/ProcessHacker/findobj.c @@ -1168,8 +1168,10 @@ INT_PTR CALLBACK PhpFindObjectsDlgProc( context->MinimumSize.bottom = 100; MapDialogRect(hwndDlg, &context->MinimumSize); - PhCenterWindow(hwndDlg, PhMainWndHandle); - PhLoadWindowPlacementFromSetting(L"FindObjWindowPosition", L"FindObjWindowSize", hwndDlg); + if (PhGetIntegerPairSetting(L"FindObjWindowPosition").X) + PhLoadWindowPlacementFromSetting(L"FindObjWindowPosition", L"FindObjWindowSize", hwndDlg); + else + PhCenterWindow(hwndDlg, PhMainWndHandle); context->SearchResults = PhCreateList(128); context->SearchResultsAddIndex = 0; diff --git a/ProcessHacker/settings.c b/ProcessHacker/settings.c index 01ac6d28917d..49cd32ba100f 100644 --- a/ProcessHacker/settings.c +++ b/ProcessHacker/settings.c @@ -60,7 +60,7 @@ VOID PhAddDefaultSettings( PhpAddIntegerSetting(L"EnvironmentTreeListFlags", L"0"); PhpAddIntegerSetting(L"FindObjRegex", L"0"); PhpAddStringSetting(L"FindObjTreeListColumns", L""); - PhpAddIntegerPairSetting(L"FindObjWindowPosition", L"350,350"); + PhpAddIntegerPairSetting(L"FindObjWindowPosition", L"0,0"); PhpAddScalableIntegerPairSetting(L"FindObjWindowSize", L"@96|550,420"); PhpAddStringSetting(L"FileBrowseExecutable", L"%SystemRoot%\\explorer.exe /select,\"%s\""); PhpAddIntegerSetting(L"FirstRun", L"1"); From 6d0993d4b1984c6eb324a2fba4317d1e5f0b5216 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 30 Dec 2018 21:53:50 +0100 Subject: [PATCH 1510/2058] Fix default log window location --- ProcessHacker/logwnd.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ProcessHacker/logwnd.c b/ProcessHacker/logwnd.c index 4618c35c7456..c917b31c0f6a 100644 --- a/ProcessHacker/logwnd.c +++ b/ProcessHacker/logwnd.c @@ -179,7 +179,10 @@ INT_PTR CALLBACK PhpLogDlgProc( MinimumSize.bottom = 150; MapDialogRect(hwndDlg, &MinimumSize); - PhLoadWindowPlacementFromSetting(L"LogWindowPosition", L"LogWindowSize", hwndDlg); + if (PhGetIntegerPairSetting(L"LogWindowPosition").X) + PhLoadWindowPlacementFromSetting(L"LogWindowPosition", L"LogWindowSize", hwndDlg); + else + PhCenterWindow(hwndDlg, PhMainWndHandle); Button_SetCheck(GetDlgItem(hwndDlg, IDC_AUTOSCROLL), BST_CHECKED); From bde9755cacc368cfeb17dc3d7cd75d55d404787e Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 30 Dec 2018 22:04:16 +0100 Subject: [PATCH 1511/2058] Fix previous commit --- ProcessHacker/settings.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ProcessHacker/settings.c b/ProcessHacker/settings.c index 49cd32ba100f..efe250240565 100644 --- a/ProcessHacker/settings.c +++ b/ProcessHacker/settings.c @@ -92,7 +92,7 @@ VOID PhAddDefaultSettings( //PhpAddIntegerSetting(L"KphUnloadOnShutdown", L"0"); PhpAddIntegerSetting(L"LogEntries", L"200"); // 512 PhpAddStringSetting(L"LogListViewColumns", L""); - PhpAddIntegerPairSetting(L"LogWindowPosition", L"300,300"); + PhpAddIntegerPairSetting(L"LogWindowPosition", L"0,0"); PhpAddScalableIntegerPairSetting(L"LogWindowSize", L"@96|450,500"); PhpAddIntegerSetting(L"MainWindowAlwaysOnTop", L"0"); PhpAddStringSetting(L"MainWindowClassName", L"MainWindowClassName"); From 2da2ce619a9e7566bdf352fd94e6d54568bd38ad Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 4 Jan 2019 22:56:24 +0100 Subject: [PATCH 1512/2058] Add minidump option to crash dialog --- ProcessHacker/main.c | 117 +++++++++++++++++++++++++++++++++++++------ 1 file changed, 102 insertions(+), 15 deletions(-) diff --git a/ProcessHacker/main.c b/ProcessHacker/main.c index eb644cf03fa8..fe6b12cb9bee 100644 --- a/ProcessHacker/main.c +++ b/ProcessHacker/main.c @@ -549,41 +549,128 @@ BOOLEAN PhInitializeRestartPolicy( } #ifndef DEBUG +#include +#include + static ULONG CALLBACK PhpUnhandledExceptionCallback( _In_ PEXCEPTION_POINTERS ExceptionInfo ) { PPH_STRING errorMessage; + INT result; + PPH_STRING message; + TASKDIALOGCONFIG config = { sizeof(TASKDIALOGCONFIG) }; + TASKDIALOG_BUTTON buttons[2]; if (NT_NTWIN32(ExceptionInfo->ExceptionRecord->ExceptionCode)) errorMessage = PhGetStatusMessage(0, WIN32_FROM_NTSTATUS(ExceptionInfo->ExceptionRecord->ExceptionCode)); else errorMessage = PhGetStatusMessage(ExceptionInfo->ExceptionRecord->ExceptionCode, 0); - if (PhShowMessage2( - NULL, - TDCBF_RETRY_BUTTON | TDCBF_CANCEL_BUTTON, - TD_ERROR_ICON, - L"Process Hacker has crashed :(", + message = PhFormatString( L"Error code: 0x%08X (%s)", ExceptionInfo->ExceptionRecord->ExceptionCode, PhGetStringOrEmpty(errorMessage) - ) == IDRETRY) + ); + + config.dwFlags = TDF_ALLOW_DIALOG_CANCELLATION; + config.dwCommonButtons = TDCBF_CLOSE_BUTTON; + config.pszWindowTitle = PhApplicationName; + config.pszMainIcon = TD_ERROR_ICON; + config.pszMainInstruction = L"Process Hacker has crashed :("; + config.pszContent = message->Buffer; + + buttons[0].nButtonID = IDYES; + buttons[0].pszButtonText = L"Minidump"; + buttons[1].nButtonID = IDRETRY; + buttons[1].pszButtonText = L"Restart"; + + config.cButtons = RTL_NUMBER_OF(buttons); + config.pButtons = buttons; + config.nDefaultButton = IDCLOSE; + + if (TaskDialogIndirect( + &config, + &result, + NULL, + NULL + ) == S_OK) { - PhShellProcessHacker( - NULL, - NULL, - SW_SHOW, - 0, - PH_SHELL_APP_PROPAGATE_PARAMETERS | PH_SHELL_APP_PROPAGATE_PARAMETERS_IGNORE_VISIBILITY, - 0, - NULL - ); + switch (result) + { + case IDRETRY: + { + PhShellProcessHacker( + NULL, + NULL, + SW_SHOW, + 0, + PH_SHELL_APP_PROPAGATE_PARAMETERS | PH_SHELL_APP_PROPAGATE_PARAMETERS_IGNORE_VISIBILITY, + 0, + NULL + ); + } + break; + case IDYES: + { + static PH_STRINGREF dumpFilePath = PH_STRINGREF_INIT(L"%USERPROFILE%\\Desktop\\"); + HANDLE fileHandle; + PPH_STRING dumpDirectory; + PPH_STRING dumpFileName; + WCHAR alphastring[16] = L""; + + dumpDirectory = PhExpandEnvironmentStrings(&dumpFilePath); + PhGenerateRandomAlphaString(alphastring, RTL_NUMBER_OF(alphastring)); + + dumpFileName = PhConcatStrings( + 4, + PhGetString(dumpDirectory), + L"\\ProcessHacker_", + alphastring, + L"_DumpFile.dmp" + ); + + if (NT_SUCCESS(PhCreateFileWin32( + &fileHandle, + dumpFileName->Buffer, + FILE_GENERIC_WRITE, + FILE_ATTRIBUTE_NORMAL, + FILE_SHARE_READ | FILE_SHARE_DELETE, + FILE_OVERWRITE_IF, + FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT + ))) + { + MINIDUMP_EXCEPTION_INFORMATION exceptionInfo; + + exceptionInfo.ThreadId = HandleToUlong(NtCurrentThreadId()); + exceptionInfo.ExceptionPointers = ExceptionInfo; + exceptionInfo.ClientPointers = FALSE; + + PhWriteMiniDumpProcess( + NtCurrentProcess(), + NtCurrentProcessId(), + fileHandle, + MiniDumpNormal, + &exceptionInfo, + NULL, + NULL + ); + + NtClose(fileHandle); + } + + PhDereferenceObject(dumpFileName); + PhDereferenceObject(dumpDirectory); + } + break; + } } RtlExitUserProcess(ExceptionInfo->ExceptionRecord->ExceptionCode); + PhDereferenceObject(message); PhDereferenceObject(errorMessage); + return EXCEPTION_EXECUTE_HANDLER; } #endif From e9a948e21ecd0db134cc03b40d1f860a955f7736 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 4 Jan 2019 22:57:14 +0100 Subject: [PATCH 1513/2058] Fix options window restart dialog location --- ProcessHacker/options.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ProcessHacker/options.c b/ProcessHacker/options.c index 45c528148901..4eab9afc3213 100644 --- a/ProcessHacker/options.c +++ b/ProcessHacker/options.c @@ -1081,7 +1081,7 @@ static VOID PhpOptionsNotifyChangeCallback( if (RestartRequired) { if (PhShowMessage2( - PhMainWndHandle, + (IsWindowVisible(PhMainWndHandle) && !IsMinimized(PhMainWndHandle)) ? PhMainWndHandle : NULL, TDCBF_YES_BUTTON | TDCBF_NO_BUTTON, TD_INFORMATION_ICON, L"One or more options you have changed requires a restart of Process Hacker.", From 9268765b116171d8d203e1cf2d21de54fd4937d6 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 5 Jan 2019 00:24:13 +0100 Subject: [PATCH 1514/2058] Add listview copy handlers --- ProcessHacker/appsup.c | 108 +++++++++++++++++++++++++++++++++ ProcessHacker/include/appsup.h | 25 ++++++++ 2 files changed, 133 insertions(+) diff --git a/ProcessHacker/appsup.c b/ProcessHacker/appsup.c index f7d7b524d373..ec2517298e78 100644 --- a/ProcessHacker/appsup.c +++ b/ProcessHacker/appsup.c @@ -1796,6 +1796,114 @@ BOOLEAN PhHandleCopyCellEMenuItem( return TRUE; } +BOOLEAN PhInsertCopyListViewEMenuItem( + _In_ struct _PH_EMENU_ITEM *Menu, + _In_ ULONG InsertAfterId, + _In_ HWND ListViewHandle + ) +{ + PPH_EMENU_ITEM parentItem; + ULONG indexInParent; + PPH_COPY_ITEM_CONTEXT context; + PPH_STRING columnText = NULL; + PPH_STRING escapedText; + PPH_STRING menuItemText; + PPH_EMENU_ITEM copyMenuItem; + POINT location; + LVHITTESTINFO lvHitInfo; + HDITEM headerItem; + WCHAR headerText[MAX_PATH]; + + GetCursorPos(&location); + ScreenToClient(ListViewHandle, &location); + + memset(&lvHitInfo, 0, sizeof(LVHITTESTINFO)); + lvHitInfo.pt = location; + + if (ListView_SubItemHitTest(ListViewHandle, &lvHitInfo) == -1) + return FALSE; + + memset(headerText, 0, sizeof(headerText)); + memset(&headerItem, 0, sizeof(HDITEM)); + headerItem.mask = HDI_TEXT; + headerItem.cchTextMax = RTL_NUMBER_OF(headerText); + headerItem.pszText = headerText; + + if (!Header_GetItem(ListView_GetHeader(ListViewHandle), lvHitInfo.iSubItem, &headerItem)) + return FALSE; + + columnText = PhaCreateString(headerText); + + if (PhIsNullOrEmptyString(columnText)) + return FALSE; + + if (!PhFindEMenuItemEx(Menu, 0, NULL, InsertAfterId, &parentItem, &indexInParent)) + return FALSE; + + indexInParent++; + + context = PhAllocate(sizeof(PH_COPY_ITEM_CONTEXT)); + context->ListViewHandle = ListViewHandle; + context->Id = lvHitInfo.iItem; + context->SubId = lvHitInfo.iSubItem; + + escapedText = PhEscapeStringForMenuPrefix(&columnText->sr); + menuItemText = PhFormatString(L"Copy \"%s\"", escapedText->Buffer); + PhDereferenceObject(escapedText); + + copyMenuItem = PhCreateEMenuItem(0, ID_COPY_CELL, menuItemText->Buffer, NULL, context); + copyMenuItem->DeleteFunction = PhpCopyCellEMenuItemDeleteFunction; + context->MenuItemText = menuItemText; + + PhInsertEMenuItem(parentItem, copyMenuItem, indexInParent); + + return TRUE; +} + +BOOLEAN PhHandleCopyListViewEMenuItem( + _In_ struct _PH_EMENU_ITEM *SelectedItem + ) +{ + PPH_COPY_ITEM_CONTEXT context; + PH_STRING_BUILDER stringBuilder; + ULONG count; + ULONG selectedCount; + ULONG i; + PPH_STRING getItemText; + + if (!SelectedItem) + return FALSE; + if (SelectedItem->Id != ID_COPY_CELL) + return FALSE; + + context = SelectedItem->Context; + + PhInitializeStringBuilder(&stringBuilder, 0x100); + count = ListView_GetItemCount(context->ListViewHandle); + selectedCount = 0; + + for (i = 0; i < count; i++) + { + if (!(ListView_GetItemState(context->ListViewHandle, i, LVIS_SELECTED) & LVIS_SELECTED)) + continue; + + getItemText = PhaGetListViewItemText(context->ListViewHandle, i, context->SubId); + + PhAppendStringBuilder(&stringBuilder, &getItemText->sr); + PhAppendStringBuilder2(&stringBuilder, L"\r\n"); + + selectedCount++; + } + + if (stringBuilder.String->Length != 0 && selectedCount == 1) + PhRemoveEndStringBuilder(&stringBuilder, 2); + + PhSetClipboardString(context->ListViewHandle, &stringBuilder.String->sr); + PhDeleteStringBuilder(&stringBuilder); + + return TRUE; +} + BOOLEAN PhpSelectFavoriteInRegedit( _In_ HWND RegeditWindow, _In_ PPH_STRINGREF FavoriteName, diff --git a/ProcessHacker/include/appsup.h b/ProcessHacker/include/appsup.h index 0035b4e37c5b..4a7ff94d3293 100644 --- a/ProcessHacker/include/appsup.h +++ b/ProcessHacker/include/appsup.h @@ -391,6 +391,31 @@ NTAPI PhHandleCopyCellEMenuItem( _In_ struct _PH_EMENU_ITEM *SelectedItem ); + +typedef struct _PH_COPY_ITEM_CONTEXT +{ + HWND ListViewHandle; + ULONG Id; + ULONG SubId; + PPH_STRING MenuItemText; +} PH_COPY_ITEM_CONTEXT, *PPH_COPY_ITEM_CONTEXT; + +PHAPPAPI +BOOLEAN +NTAPI +PhInsertCopyListViewEMenuItem( + _In_ struct _PH_EMENU_ITEM *Menu, + _In_ ULONG InsertAfterId, + _In_ HWND ListViewHandle + ); + +PHAPPAPI +BOOLEAN +NTAPI +PhHandleCopyListViewEMenuItem( + _In_ struct _PH_EMENU_ITEM *SelectedItem + ); + // end_phapppub BOOLEAN PhShellOpenKey2( From d21f8299e84efb745b03fc8fd2cde2af12c8b691 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 5 Jan 2019 00:26:38 +0100 Subject: [PATCH 1515/2058] Update copyrights --- ProcessHacker/ProcessHacker.rc | 2 +- ProcessHacker/appsup.c | 2 +- ProcessHacker/main.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ProcessHacker/ProcessHacker.rc b/ProcessHacker/ProcessHacker.rc index f743346f0249..2144f36c0113 100644 --- a/ProcessHacker/ProcessHacker.rc +++ b/ProcessHacker/ProcessHacker.rc @@ -582,7 +582,7 @@ BEGIN ICON IDI_PROCESSHACKER,IDC_STATIC,16,11,21,20 LTEXT "Process Hacker",IDC_ABOUT_NAME,45,10,192,8 LTEXT "Licensed under the GNU GPL, v3.",IDC_STATIC,45,23,193,8 - LTEXT "Copyright (c) 2008-2018",IDC_STATIC,45,36,80,8 + LTEXT "Copyright (c) 2008-2019",IDC_STATIC,45,36,80,8 CONTROL "Credits.",IDC_CREDITS,"SysLink",WS_TABSTOP,15,49,248,121 CONTROL "Process Hacker on SourceForge.net",IDC_LINK_SF, "SysLink",WS_TABSTOP,7,177,130,11 diff --git a/ProcessHacker/appsup.c b/ProcessHacker/appsup.c index ec2517298e78..e702c9a5c7b3 100644 --- a/ProcessHacker/appsup.c +++ b/ProcessHacker/appsup.c @@ -3,7 +3,7 @@ * application support functions * * Copyright (C) 2010-2016 wj32 - * Copyright (C) 2017 dmex + * Copyright (C) 2017-2019 dmex * * This file is part of Process Hacker. * diff --git a/ProcessHacker/main.c b/ProcessHacker/main.c index fe6b12cb9bee..feca4726cd63 100644 --- a/ProcessHacker/main.c +++ b/ProcessHacker/main.c @@ -3,7 +3,7 @@ * main program * * Copyright (C) 2009-2016 wj32 - * Copyright (C) 2017-2018 dmex + * Copyright (C) 2017-2019 dmex * * This file is part of Process Hacker. * From 9c6d5453149eec978628b49522b45e8578139dff Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 5 Jan 2019 00:53:56 +0100 Subject: [PATCH 1516/2058] Export PhHandleListViewNotifyBehaviors --- ProcessHacker/include/appsup.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/ProcessHacker/include/appsup.h b/ProcessHacker/include/appsup.h index 4a7ff94d3293..d5d3b2a38dcc 100644 --- a/ProcessHacker/include/appsup.h +++ b/ProcessHacker/include/appsup.h @@ -164,19 +164,20 @@ PhHandleListViewNotifyForCopy( _In_ LPARAM lParam, _In_ HWND ListViewHandle ); -// end_phapppub #define PH_LIST_VIEW_CTRL_C_BEHAVIOR 0x1 #define PH_LIST_VIEW_CTRL_A_BEHAVIOR 0x2 #define PH_LIST_VIEW_DEFAULT_1_BEHAVIORS (PH_LIST_VIEW_CTRL_C_BEHAVIOR | PH_LIST_VIEW_CTRL_A_BEHAVIOR) -VOID PhHandleListViewNotifyBehaviors( +PHAPPAPI +VOID +NTAPI +PhHandleListViewNotifyBehaviors( _In_ LPARAM lParam, _In_ HWND ListViewHandle, _In_ ULONG Behaviors ); -// begin_phapppub PHAPPAPI BOOLEAN NTAPI From 4c02c412da13d6fc3aaa9a4fbcde588bfbbc2084 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 5 Jan 2019 00:58:07 +0100 Subject: [PATCH 1517/2058] Add copy menu to statistics/handle properties pages --- ProcessHacker/ProcessHacker.rc | 2 +- ProcessHacker/hndlprp.c | 76 +++++++++++++++++++++++++++++++--- ProcessHacker/prpgstat.c | 69 +++++++++++++++++++++++++++++- 3 files changed, 140 insertions(+), 7 deletions(-) diff --git a/ProcessHacker/ProcessHacker.rc b/ProcessHacker/ProcessHacker.rc index 2144f36c0113..ae0e1aef3e56 100644 --- a/ProcessHacker/ProcessHacker.rc +++ b/ProcessHacker/ProcessHacker.rc @@ -1171,7 +1171,7 @@ STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSM CAPTION "Statistics" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN - CONTROL "",IDC_STATISTICS_LIST,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_ALIGNLEFT | LVS_NOCOLUMNHEADER | WS_BORDER | WS_TABSTOP,2,3,255,255 + CONTROL "",IDC_STATISTICS_LIST,"SysListView32",LVS_REPORT | LVS_ALIGNLEFT | LVS_NOCOLUMNHEADER | WS_BORDER | WS_TABSTOP,2,3,255,255 END IDD_OPTADVANCED DIALOGEX 0, 0, 317, 225 diff --git a/ProcessHacker/hndlprp.c b/ProcessHacker/hndlprp.c index de2cbfa3a68a..b303bcffd632 100644 --- a/ProcessHacker/hndlprp.c +++ b/ProcessHacker/hndlprp.c @@ -3,7 +3,7 @@ * handle properties * * Copyright (C) 2010-2013 wj32 - * Copyright (C) 2018 dmex + * Copyright (C) 2018-2019 dmex * * This file is part of Process Hacker. * @@ -22,15 +22,16 @@ */ #include +#include +#include +#include + +#include #include #include #include #include -#include -#include -#include - typedef enum _PHP_HANDLE_GENERAL_CATEGORY { // common @@ -1117,6 +1118,8 @@ INT_PTR CALLBACK PhpHandleGeneralDlgProc( { LPNMHDR header = (LPNMHDR)lParam; + PhHandleListViewNotifyBehaviors(lParam, context->ListViewHandle, PH_LIST_VIEW_DEFAULT_1_BEHAVIORS); + switch (header->code) { case PSN_QUERYINITIALFOCUS: @@ -1127,6 +1130,69 @@ INT_PTR CALLBACK PhpHandleGeneralDlgProc( } } break; + case WM_CONTEXTMENU: + { + if ((HWND)wParam == context->ListViewHandle) + { + POINT point; + PPH_EMENU menu; + PPH_EMENU item; + PVOID *listviewItems; + ULONG numberOfItems; + + point.x = GET_X_LPARAM(lParam); + point.y = GET_Y_LPARAM(lParam); + + if (point.x == -1 && point.y == -1) + PhGetListViewContextMenuPoint((HWND)wParam, &point); + + PhGetSelectedListViewItemParams(context->ListViewHandle, &listviewItems, &numberOfItems); + + if (numberOfItems != 0) + { + menu = PhCreateEMenu(); + + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, IDC_COPY, L"&Copy", NULL, NULL), ULONG_MAX); + PhInsertCopyListViewEMenuItem(menu, IDC_COPY, context->ListViewHandle); + + item = PhShowEMenu( + menu, + hwndDlg, + PH_EMENU_SHOW_SEND_COMMAND | PH_EMENU_SHOW_LEFTRIGHT, + PH_ALIGN_LEFT | PH_ALIGN_TOP, + point.x, + point.y + ); + + if (item) + { + BOOLEAN handled = FALSE; + + handled = PhHandleCopyListViewEMenuItem(item); + + //if (!handled && PhPluginsEnabled) + // handled = PhPluginTriggerEMenuItem(&menuInfo, item); + + if (!handled) + { + switch (item->Id) + { + case IDC_COPY: + { + PhCopyListView(context->ListViewHandle); + } + break; + } + } + } + + PhDestroyEMenu(menu); + } + + PhFree(listviewItems); + } + } + break; } REFLECT_MESSAGE_DLG(hwndDlg, context->ListViewHandle, uMsg, wParam, lParam); diff --git a/ProcessHacker/prpgstat.c b/ProcessHacker/prpgstat.c index 1fe0c4fc7b57..a5484f5552b9 100644 --- a/ProcessHacker/prpgstat.c +++ b/ProcessHacker/prpgstat.c @@ -24,11 +24,13 @@ #include #include #include -#include #include #include #include +#include +#include + typedef enum _PH_PROCESS_STATISTICS_CATEGORY { PH_PROCESS_STATISTICS_CATEGORY_CPU, @@ -473,6 +475,8 @@ INT_PTR CALLBACK PhpProcessStatisticsDlgProc( { LPNMHDR header = (LPNMHDR)lParam; + PhHandleListViewNotifyBehaviors(lParam, statisticsContext->ListViewHandle, PH_LIST_VIEW_DEFAULT_1_BEHAVIORS); + switch (header->code) { case PSN_SETACTIVE: @@ -494,6 +498,69 @@ INT_PTR CALLBACK PhpProcessStatisticsDlgProc( ExtendedListView_SetColumnWidth(statisticsContext->ListViewHandle, 0, ELVSCW_AUTOSIZE_REMAININGSPACE); } break; + case WM_CONTEXTMENU: + { + if ((HWND)wParam == statisticsContext->ListViewHandle) + { + POINT point; + PPH_EMENU menu; + PPH_EMENU item; + PVOID *listviewItems; + ULONG numberOfItems; + + point.x = GET_X_LPARAM(lParam); + point.y = GET_Y_LPARAM(lParam); + + if (point.x == -1 && point.y == -1) + PhGetListViewContextMenuPoint((HWND)wParam, &point); + + PhGetSelectedListViewItemParams(statisticsContext->ListViewHandle, &listviewItems, &numberOfItems); + + if (numberOfItems != 0) + { + menu = PhCreateEMenu(); + + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, IDC_COPY, L"&Copy", NULL, NULL), ULONG_MAX); + PhInsertCopyListViewEMenuItem(menu, IDC_COPY, statisticsContext->ListViewHandle); + + item = PhShowEMenu( + menu, + hwndDlg, + PH_EMENU_SHOW_SEND_COMMAND | PH_EMENU_SHOW_LEFTRIGHT, + PH_ALIGN_LEFT | PH_ALIGN_TOP, + point.x, + point.y + ); + + if (item) + { + BOOLEAN handled = FALSE; + + handled = PhHandleCopyListViewEMenuItem(item); + + //if (!handled && PhPluginsEnabled) + // handled = PhPluginTriggerEMenuItem(&menuInfo, item); + + if (!handled) + { + switch (item->Id) + { + case IDC_COPY: + { + PhCopyListView(statisticsContext->ListViewHandle); + } + break; + } + } + } + + PhDestroyEMenu(menu); + } + + PhFree(listviewItems); + } + } + break; } return FALSE; From 3282d79cecee04474826d13d75d4228a6bc584d9 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 5 Jan 2019 00:58:56 +0100 Subject: [PATCH 1518/2058] DotNetTools: Add copy menu to .NET performance page --- plugins/DotNetTools/DotNetTools.rc | 2 +- plugins/DotNetTools/perfpage.c | 78 ++++++++++++++++++++++++++++-- 2 files changed, 75 insertions(+), 5 deletions(-) diff --git a/plugins/DotNetTools/DotNetTools.rc b/plugins/DotNetTools/DotNetTools.rc index 4e8ea06e3dc3..e382546b5469 100644 --- a/plugins/DotNetTools/DotNetTools.rc +++ b/plugins/DotNetTools/DotNetTools.rc @@ -93,7 +93,7 @@ CAPTION ".NET performance" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN CONTROL "",IDC_APPDOMAINS,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_SORTASCENDING | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,2,3,256,67 - CONTROL "",IDC_COUNTERS,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,2,73,256,185 + CONTROL "",IDC_COUNTERS,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,2,73,256,185 END IDD_PROCDOTNETASM DIALOGEX 0, 0, 260, 260 diff --git a/plugins/DotNetTools/perfpage.c b/plugins/DotNetTools/perfpage.c index 8b2fae6b6073..bcba2179e3cb 100644 --- a/plugins/DotNetTools/perfpage.c +++ b/plugins/DotNetTools/perfpage.c @@ -3,7 +3,7 @@ * .NET Performance property page * * Copyright (C) 2011-2015 wj32 - * Copyright (C) 2015-2018 dmex + * Copyright (C) 2015-2019 dmex * * This file is part of Process Hacker. * @@ -917,6 +917,9 @@ INT_PTR CALLBACK DotNetPerfPageDlgProc( { LPNMHDR header = (LPNMHDR)lParam; + PhHandleListViewNotifyBehaviors(lParam, context->AppDomainsListViewHandle, PH_LIST_VIEW_DEFAULT_1_BEHAVIORS); + PhHandleListViewNotifyBehaviors(lParam, context->CountersListViewHandle, PH_LIST_VIEW_DEFAULT_1_BEHAVIORS); + switch (header->code) { case PSN_SETACTIVE: @@ -1788,9 +1791,6 @@ INT_PTR CALLBACK DotNetPerfPageDlgProc( } break; } - - PhHandleListViewNotifyForCopy(lParam, context->AppDomainsListViewHandle); - PhHandleListViewNotifyForCopy(lParam, context->CountersListViewHandle); } break; case MSG_UPDATE: @@ -1806,6 +1806,76 @@ INT_PTR CALLBACK DotNetPerfPageDlgProc( ExtendedListView_SetColumnWidth(context->AppDomainsListViewHandle, 0, ELVSCW_AUTOSIZE_REMAININGSPACE); } break; + case WM_CONTEXTMENU: + { + HWND listViewHandle = NULL; + + if ((HWND)wParam == context->AppDomainsListViewHandle) + listViewHandle = context->AppDomainsListViewHandle; + else if ((HWND)wParam == context->CountersListViewHandle) + listViewHandle = context->CountersListViewHandle; + + if (listViewHandle) + { + POINT point; + PPH_EMENU menu; + PPH_EMENU item; + PVOID *listviewItems; + ULONG numberOfItems; + + point.x = GET_X_LPARAM(lParam); + point.y = GET_Y_LPARAM(lParam); + + if (point.x == -1 && point.y == -1) + PhGetListViewContextMenuPoint((HWND)wParam, &point); + + PhGetSelectedListViewItemParams(listViewHandle, &listviewItems, &numberOfItems); + + if (numberOfItems != 0) + { + menu = PhCreateEMenu(); + + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_CLR_COPY, L"&Copy", NULL, NULL), ULONG_MAX); + PhInsertCopyListViewEMenuItem(menu, ID_CLR_COPY, listViewHandle); + + item = PhShowEMenu( + menu, + hwndDlg, + PH_EMENU_SHOW_SEND_COMMAND | PH_EMENU_SHOW_LEFTRIGHT, + PH_ALIGN_LEFT | PH_ALIGN_TOP, + point.x, + point.y + ); + + if (item) + { + BOOLEAN handled = FALSE; + + handled = PhHandleCopyListViewEMenuItem(item); + + //if (!handled && PhPluginsEnabled) + // handled = PhPluginTriggerEMenuItem(&menuInfo, item); + + if (!handled) + { + switch (item->Id) + { + case ID_CLR_COPY: + { + PhCopyListView(listViewHandle); + } + break; + } + } + } + + PhDestroyEMenu(menu); + } + + PhFree(listviewItems); + } + } + break; } return FALSE; From f40bb58faef8a77111a5f128b95ac67e8089fc4e Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 5 Jan 2019 02:07:33 +0100 Subject: [PATCH 1519/2058] Add copy menu to Job properties page --- ProcessHacker/ProcessHacker.rc | 2 +- ProcessHacker/jobprp.c | 120 +++++++++++++++++++++++++++++---- 2 files changed, 107 insertions(+), 15 deletions(-) diff --git a/ProcessHacker/ProcessHacker.rc b/ProcessHacker/ProcessHacker.rc index ae0e1aef3e56..fa2e827a0cbc 100644 --- a/ProcessHacker/ProcessHacker.rc +++ b/ProcessHacker/ProcessHacker.rc @@ -799,7 +799,7 @@ BEGIN EDITTEXT IDC_NAME,35,8,164,12,ES_AUTOHSCROLL PUSHBUTTON "Terminate",IDC_TERMINATE,203,7,50,14 LTEXT "Processes in job:",IDC_STATIC,7,25,55,8 - CONTROL "",IDC_PROCESSES,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_SORTASCENDING | LVS_ALIGNLEFT | LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,7,38,246,62 + CONTROL "",IDC_PROCESSES,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_SORTASCENDING | LVS_ALIGNLEFT | LVS_NOCOLUMNHEADER | LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,7,38,246,62 PUSHBUTTON "Add...",IDC_ADD,203,103,50,14 LTEXT "Limits:",IDC_STATIC,7,117,21,8 CONTROL "",IDC_LIMITS,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_SORTASCENDING | LVS_ALIGNLEFT | LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,7,129,246,107 diff --git a/ProcessHacker/jobprp.c b/ProcessHacker/jobprp.c index 1feeccc90ef3..62e559713e5e 100644 --- a/ProcessHacker/jobprp.c +++ b/ProcessHacker/jobprp.c @@ -3,6 +3,7 @@ * job properties * * Copyright (C) 2010 wj32 + * Copyright (C) 2018-2019 dmex * * This file is part of Process Hacker. * @@ -21,17 +22,23 @@ */ #include +#include #include +#include + +#include #include #include -#include #include +#define MSG_UPDATE (WM_APP + 1) + typedef struct _JOB_PAGE_CONTEXT { PPH_OPEN_OBJECT OpenObject; PVOID Context; DLGPROC HookProc; + PH_CALLBACK_REGISTRATION ProcessesUpdatedRegistration; } JOB_PAGE_CONTEXT, *PJOB_PAGE_CONTEXT; INT CALLBACK PhpJobPropPageProc( @@ -502,6 +509,76 @@ INT_PTR CALLBACK PhpJobPageProc( ExtendedListView_SetColumnWidth(GetDlgItem(hwndDlg, IDC_PROCESSES), 0, ELVSCW_AUTOSIZE_REMAININGSPACE); } break; + case WM_CONTEXTMENU: + { + HWND listViewHandle = NULL; + + if ((HWND)wParam == GetDlgItem(hwndDlg, IDC_PROCESSES)) + listViewHandle = GetDlgItem(hwndDlg, IDC_PROCESSES); + else if ((HWND)wParam == GetDlgItem(hwndDlg, IDC_LIMITS)) + listViewHandle = GetDlgItem(hwndDlg, IDC_LIMITS); + + if (listViewHandle) + { + POINT point; + PPH_EMENU menu; + PPH_EMENU item; + PVOID *listviewItems; + ULONG numberOfItems; + + point.x = GET_X_LPARAM(lParam); + point.y = GET_Y_LPARAM(lParam); + + if (point.x == -1 && point.y == -1) + PhGetListViewContextMenuPoint((HWND)wParam, &point); + + PhGetSelectedListViewItemParams(listViewHandle, &listviewItems, &numberOfItems); + + if (numberOfItems != 0) + { + menu = PhCreateEMenu(); + + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, IDC_COPY, L"&Copy", NULL, NULL), ULONG_MAX); + PhInsertCopyListViewEMenuItem(menu, IDC_COPY, listViewHandle); + + item = PhShowEMenu( + menu, + hwndDlg, + PH_EMENU_SHOW_SEND_COMMAND | PH_EMENU_SHOW_LEFTRIGHT, + PH_ALIGN_LEFT | PH_ALIGN_TOP, + point.x, + point.y + ); + + if (item) + { + BOOLEAN handled = FALSE; + + handled = PhHandleCopyListViewEMenuItem(item); + + //if (!handled && PhPluginsEnabled) + // handled = PhPluginTriggerEMenuItem(&menuInfo, item); + + if (!handled) + { + switch (item->Id) + { + case IDC_COPY: + { + PhCopyListView(listViewHandle); + } + break; + } + } + } + + PhDestroyEMenu(menu); + } + + PhFree(listviewItems); + } + } + break; } return FALSE; @@ -588,11 +665,11 @@ static VOID PhpRefreshJobStatisticsInfo( PhSetDialogItemText(hwndDlg, IDC_ZPAGEFAULTS_V, PhaFormatUInt64(basicAndIo.BasicInfo.TotalPageFaultCount, TRUE)->Buffer); PhSetDialogItemText(hwndDlg, IDC_ZIOREADS_V, PhaFormatUInt64(basicAndIo.IoInfo.ReadOperationCount, TRUE)->Buffer); - PhSetDialogItemText(hwndDlg, IDC_ZIOREADBYTES_V, PhaFormatSize(basicAndIo.IoInfo.ReadTransferCount, -1)->Buffer); + PhSetDialogItemText(hwndDlg, IDC_ZIOREADBYTES_V, PhaFormatSize(basicAndIo.IoInfo.ReadTransferCount, ULONG_MAX)->Buffer); PhSetDialogItemText(hwndDlg, IDC_ZIOWRITES_V, PhaFormatUInt64(basicAndIo.IoInfo.WriteOperationCount, TRUE)->Buffer); - PhSetDialogItemText(hwndDlg, IDC_ZIOWRITEBYTES_V, PhaFormatSize(basicAndIo.IoInfo.WriteTransferCount, -1)->Buffer); + PhSetDialogItemText(hwndDlg, IDC_ZIOWRITEBYTES_V, PhaFormatSize(basicAndIo.IoInfo.WriteTransferCount, ULONG_MAX)->Buffer); PhSetDialogItemText(hwndDlg, IDC_ZIOOTHER_V, PhaFormatUInt64(basicAndIo.IoInfo.OtherOperationCount, TRUE)->Buffer); - PhSetDialogItemText(hwndDlg, IDC_ZIOOTHERBYTES_V, PhaFormatSize(basicAndIo.IoInfo.OtherTransferCount, -1)->Buffer); + PhSetDialogItemText(hwndDlg, IDC_ZIOOTHERBYTES_V, PhaFormatSize(basicAndIo.IoInfo.OtherTransferCount, ULONG_MAX)->Buffer); } else { @@ -620,8 +697,8 @@ static VOID PhpRefreshJobStatisticsInfo( &extendedLimitInfo ))) { - PhSetDialogItemText(hwndDlg, IDC_ZPEAKPROCESSUSAGE_V, PhaFormatSize(extendedLimitInfo.PeakProcessMemoryUsed, -1)->Buffer); - PhSetDialogItemText(hwndDlg, IDC_ZPEAKJOBUSAGE_V, PhaFormatSize(extendedLimitInfo.PeakJobMemoryUsed, -1)->Buffer); + PhSetDialogItemText(hwndDlg, IDC_ZPEAKPROCESSUSAGE_V, PhaFormatSize(extendedLimitInfo.PeakProcessMemoryUsed, ULONG_MAX)->Buffer); + PhSetDialogItemText(hwndDlg, IDC_ZPEAKJOBUSAGE_V, PhaFormatSize(extendedLimitInfo.PeakJobMemoryUsed, ULONG_MAX)->Buffer); } else { @@ -633,6 +710,14 @@ static VOID PhpRefreshJobStatisticsInfo( NtClose(jobHandle); } +static VOID NTAPI ProcessesUpdatedCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + PostMessage(Context, MSG_UPDATE, 0, 0); +} + INT_PTR CALLBACK PhpJobStatisticsPageProc( _In_ HWND hwndDlg, _In_ UINT uMsg, @@ -651,21 +736,28 @@ INT_PTR CALLBACK PhpJobStatisticsPageProc( { case WM_INITDIALOG: { - // HACK - PhCenterWindow(GetParent(hwndDlg), GetParent(GetParent(hwndDlg))); + PhCenterWindow(GetParent(hwndDlg), GetParent(GetParent(hwndDlg))); // HACK PhpRefreshJobStatisticsInfo(hwndDlg, jobPageContext); - SetTimer(hwndDlg, 1, PhGetIntegerSetting(L"UpdateInterval"), NULL); + + PhRegisterCallback( + PhGetGeneralCallback(GeneralCallbackProcessProviderUpdatedEvent), + ProcessesUpdatedCallback, + hwndDlg, + &jobPageContext->ProcessesUpdatedRegistration + ); PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport); } break; - case WM_TIMER: + case WM_DESTROY: { - if (wParam == 1) - { - PhpRefreshJobStatisticsInfo(hwndDlg, jobPageContext); - } + PhUnregisterCallback(PhGetGeneralCallback(GeneralCallbackProcessProviderUpdatedEvent), &jobPageContext->ProcessesUpdatedRegistration); + } + break; + case MSG_UPDATE: + { + PhpRefreshJobStatisticsInfo(hwndDlg, jobPageContext); } break; } From 82411147dfa5b6582bb9c1da9857396a7e32a3ff Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 5 Jan 2019 02:32:40 +0100 Subject: [PATCH 1520/2058] Add copy menu to Token properties page --- ProcessHacker/resource.h | 1 - ProcessHacker/tokprp.c | 36 ++++++++++++++++++++++++++++-------- 2 files changed, 28 insertions(+), 9 deletions(-) diff --git a/ProcessHacker/resource.h b/ProcessHacker/resource.h index 90d10d033f56..5db3122f8be5 100644 --- a/ProcessHacker/resource.h +++ b/ProcessHacker/resource.h @@ -673,7 +673,6 @@ #define ID_ESC_EXIT 40190 #define ID_PROCESS_COPY 40194 #define ID_THREAD_COPY 40195 -#define ID_PRIVILEGE_COPY 40196 #define ID_NETWORK_COPY 40197 #define ID_SERVICE_COPY 40198 #define ID_MODULE_COPY 40199 diff --git a/ProcessHacker/tokprp.c b/ProcessHacker/tokprp.c index a5ac69360949..807486008eaa 100644 --- a/ProcessHacker/tokprp.c +++ b/ProcessHacker/tokprp.c @@ -3,7 +3,7 @@ * token properties * * Copyright (C) 2010-2012 wj32 - * Copyright (C) 2017-2018 dmex + * Copyright (C) 2017-2019 dmex * * This file is part of Process Hacker. * @@ -1224,11 +1224,6 @@ INT_PTR CALLBACK PhpTokenPageProc( PhFree(listViewItems); } break; - case ID_PRIVILEGE_COPY: - { - PhCopyListView(tokenPageContext->ListViewHandle); - } - break; case IDC_DEFAULTPERM: { PhEditSecurity( @@ -1426,6 +1421,7 @@ INT_PTR CALLBACK PhpTokenPageProc( { POINT point; PPH_EMENU menu; + PPH_EMENU item; PPHP_TOKEN_PAGE_LISTVIEW_ITEM *listviewItems; ULONG numberOfItems; @@ -1484,9 +1480,10 @@ INT_PTR CALLBACK PhpTokenPageProc( } } - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_PRIVILEGE_COPY, L"&Copy", NULL, NULL), ULONG_MAX); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, IDC_COPY, L"&Copy", NULL, NULL), ULONG_MAX); + PhInsertCopyListViewEMenuItem(menu, IDC_COPY, tokenPageContext->ListViewHandle); - PhShowEMenu( + item = PhShowEMenu( menu, hwndDlg, PH_EMENU_SHOW_SEND_COMMAND | PH_EMENU_SHOW_LEFTRIGHT, @@ -1494,6 +1491,29 @@ INT_PTR CALLBACK PhpTokenPageProc( point.x, point.y ); + + if (item) + { + BOOLEAN handled = FALSE; + + handled = PhHandleCopyListViewEMenuItem(item); + + //if (!handled && PhPluginsEnabled) + // handled = PhPluginTriggerEMenuItem(&menuInfo, item); + + if (!handled) + { + switch (item->Id) + { + case IDC_COPY: + { + PhCopyListView(tokenPageContext->ListViewHandle); + } + break; + } + } + } + PhDestroyEMenu(menu); } From 38300215e98c9ac7600df05d55db3b79a3899fc0 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 5 Jan 2019 02:33:48 +0100 Subject: [PATCH 1521/2058] Fix default token security page options --- phlib/secedit.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/phlib/secedit.c b/phlib/secedit.c index a01b081f706f..3b24bb2ac07a 100644 --- a/phlib/secedit.c +++ b/phlib/secedit.c @@ -283,7 +283,9 @@ HRESULT STDMETHODCALLTYPE PhSecurityInformation_GetObjectInformation( ObjectInfo->pszObjectName = PhGetString(this->ObjectName); if (PhEqualString2(this->ObjectType, L"TokenDefault", TRUE)) - ObjectInfo->dwFlags &= ~SI_EDIT_OWNER; + { + ObjectInfo->dwFlags &= ~(SI_EDIT_OWNER | SI_EDIT_AUDITS); + } return S_OK; } From d40f22fc30accf9efd9ae1e7773e330214d2f7a8 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 5 Jan 2019 04:15:34 +0100 Subject: [PATCH 1522/2058] ExtendedTools: Add theme to module services dialog, Fix regression saving module services window settings --- plugins/ExtendedTools/ExtendedTools.rc | 30 ------------ plugins/ExtendedTools/exttools.h | 3 +- plugins/ExtendedTools/main.c | 5 +- plugins/ExtendedTools/modsrv.c | 64 +++++++++++++------------- 4 files changed, 38 insertions(+), 64 deletions(-) diff --git a/plugins/ExtendedTools/ExtendedTools.rc b/plugins/ExtendedTools/ExtendedTools.rc index 0818d12882ee..d449814ffe2b 100644 --- a/plugins/ExtendedTools/ExtendedTools.rc +++ b/plugins/ExtendedTools/ExtendedTools.rc @@ -494,36 +494,6 @@ BEGIN END -///////////////////////////////////////////////////////////////////////////// -// -// AFX_DIALOG_LAYOUT -// - -IDD_OBJTPWORKERFACTORY AFX_DIALOG_LAYOUT -BEGIN - 0 -END - -IDD_PROCGPU_DETAILS AFX_DIALOG_LAYOUT -BEGIN - 0 -END - -IDD_PROCGPU_PANEL AFX_DIALOG_LAYOUT -BEGIN - 0 -END - -IDD_OPTIONS AFX_DIALOG_LAYOUT -BEGIN - 0 -END - -IDD_UNLOADEDDLLS AFX_DIALOG_LAYOUT -BEGIN - 0 -END - #endif // English (Australia) resources ///////////////////////////////////////////////////////////////////////////// diff --git a/plugins/ExtendedTools/exttools.h b/plugins/ExtendedTools/exttools.h index 227f066d59fb..780da9c6923f 100644 --- a/plugins/ExtendedTools/exttools.h +++ b/plugins/ExtendedTools/exttools.h @@ -30,6 +30,7 @@ extern HWND NetworkTreeNewHandle; #define SETTING_NAME_UNLOADED_COLUMNS (PLUGIN_NAME L".UnloadedListColumns") #define SETTING_NAME_MODULE_SERVICES_WINDOW_POSITION (PLUGIN_NAME L".ModuleServiceWindowPosition") #define SETTING_NAME_MODULE_SERVICES_WINDOW_SIZE (PLUGIN_NAME L".ModuleServiceWindowSize") +#define SETTING_NAME_MODULE_SERVICES_COLUMNS (PLUGIN_NAME L".ModuleServiceListColumns") #define SETTING_NAME_GPU_NODES_WINDOW_POSITION (PLUGIN_NAME L".GpuNodesWindowPosition") #define SETTING_NAME_GPU_NODES_WINDOW_SIZE (PLUGIN_NAME L".GpuNodesWindowSize") #define SETTING_NAME_WSWATCH_WINDOW_POSITION (PLUGIN_NAME L".WsWatchWindowPosition") @@ -566,7 +567,7 @@ VOID EtRegisterNotifyIcons( VOID EtShowModuleServicesDialog( _In_ HWND ParentWindowHandle, _In_ HANDLE ProcessId, - _In_ PWSTR ModuleName + _In_ PPH_STRING ModuleName ); // objprp diff --git a/plugins/ExtendedTools/main.c b/plugins/ExtendedTools/main.c index 20a018f12b17..7629ebbd3131 100644 --- a/plugins/ExtendedTools/main.c +++ b/plugins/ExtendedTools/main.c @@ -111,9 +111,9 @@ VOID NTAPI MenuItemCallback( case ID_MODULE_SERVICES: { EtShowModuleServicesDialog( - menuItem->OwnerWindow, + !!PhGetIntegerSetting(L"ForceNoParent") ? NULL : menuItem->OwnerWindow, ModuleProcessId, - ((PPH_MODULE_ITEM)menuItem->Context)->Name->Buffer + ((PPH_MODULE_ITEM)menuItem->Context)->Name ); } break; @@ -506,6 +506,7 @@ LOGICAL DllMain( { StringSettingType, SETTING_NAME_UNLOADED_COLUMNS, L"" }, { IntegerPairSettingType, SETTING_NAME_MODULE_SERVICES_WINDOW_POSITION, L"0,0" }, { ScalableIntegerPairSettingType, SETTING_NAME_MODULE_SERVICES_WINDOW_SIZE, L"@96|850,490" }, + { StringSettingType, SETTING_NAME_MODULE_SERVICES_COLUMNS, L"" }, { IntegerPairSettingType, SETTING_NAME_GPU_NODES_WINDOW_POSITION, L"0,0" }, { ScalableIntegerPairSettingType, SETTING_NAME_GPU_NODES_WINDOW_SIZE, L"@96|850,490" }, { IntegerPairSettingType, SETTING_NAME_WSWATCH_WINDOW_POSITION, L"0,0" }, diff --git a/plugins/ExtendedTools/modsrv.c b/plugins/ExtendedTools/modsrv.c index 4a756ed6d09b..f05d676fc417 100644 --- a/plugins/ExtendedTools/modsrv.c +++ b/plugins/ExtendedTools/modsrv.c @@ -3,7 +3,7 @@ * services referencing module * * Copyright (C) 2010-2011 wj32 - * Copyright (C) 2018 dmex + * Copyright (C) 2018-2019 dmex * * This file is part of Process Hacker. * @@ -26,8 +26,9 @@ typedef struct _MODULE_SERVICES_CONTEXT { + HWND ServiceListHandle; HANDLE ProcessId; - PWSTR ModuleName; + PPH_STRING ModuleName; PH_LAYOUT_MANAGER LayoutManager; } MODULE_SERVICES_CONTEXT, *PMODULE_SERVICES_CONTEXT; @@ -41,21 +42,21 @@ INT_PTR CALLBACK EtpModuleServicesDlgProc( VOID EtShowModuleServicesDialog( _In_ HWND ParentWindowHandle, _In_ HANDLE ProcessId, - _In_ PWSTR ModuleName + _In_ PPH_STRING ModuleName ) { - MODULE_SERVICES_CONTEXT context; + PMODULE_SERVICES_CONTEXT context; - memset(&context, 0, sizeof(MODULE_SERVICES_CONTEXT)); - context.ProcessId = ProcessId; - context.ModuleName = ModuleName; + context = PhAllocateZero(sizeof(MODULE_SERVICES_CONTEXT)); + context->ProcessId = ProcessId; + context->ModuleName = PhReferenceObject(ModuleName); DialogBoxParam( PluginInstance->DllBase, MAKEINTRESOURCE(IDD_MODSERVICES), ParentWindowHandle, EtpModuleServicesDlgProc, - (LPARAM)&context + (LPARAM)context ); } @@ -73,7 +74,6 @@ PPH_LIST PhpQueryModuleServiceReferences( if (!(I_QueryTagInformation = PhGetModuleProcAddress(L"advapi32.dll", "I_QueryTagInformation"))) { PhShowError(GetParent(WindowHandle), L"Unable to query services because the feature is not supported by the operating system."); - EndDialog(WindowHandle, IDCANCEL); return NULL; } @@ -89,7 +89,6 @@ PPH_LIST PhpQueryModuleServiceReferences( if (win32Result != ERROR_SUCCESS) { PhShowStatus(GetParent(WindowHandle), L"Unable to query module references.", 0, win32Result); - EndDialog(WindowHandle, IDCANCEL); return NULL; } @@ -150,6 +149,12 @@ INT_PTR CALLBACK EtpModuleServicesDlgProc( if (uMsg == WM_DESTROY) { PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); + + if (context->LayoutManager.List) // HACK (dmex) + PhDeleteLayoutManager(&context->LayoutManager); + + PhDereferenceObject(context->ModuleName); + PhFree(context); } } @@ -162,17 +167,20 @@ INT_PTR CALLBACK EtpModuleServicesDlgProc( { PPH_LIST serviceList; PPH_SERVICE_ITEM *serviceItems; - HWND serviceListHandle; RECT rect; - if (!(serviceList = PhpQueryModuleServiceReferences(hwndDlg, context->ProcessId, context->ModuleName))) + if (!(serviceList = PhpQueryModuleServiceReferences(hwndDlg, context->ProcessId, PhGetString(context->ModuleName)))) + { + EndDialog(hwndDlg, IDCANCEL); return FALSE; + } SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhInstanceHandle, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhInstanceHandle, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); serviceItems = PhAllocateCopy(serviceList->Items, serviceList->Count * sizeof(PPH_SERVICE_ITEM)); - serviceListHandle = PhCreateServiceListControl(hwndDlg, serviceItems, serviceList->Count); + context->ServiceListHandle = PhCreateServiceListControl(hwndDlg, serviceItems, serviceList->Count); + SendMessage(context->ServiceListHandle, WM_PH_SET_LIST_VIEW_SETTINGS, 0, (LPARAM)SETTING_NAME_MODULE_SERVICES_COLUMNS); PhDereferenceObject(serviceList); { @@ -181,12 +189,12 @@ INT_PTR CALLBACK EtpModuleServicesDlgProc( if (processItem = PhReferenceProcessItem(context->ProcessId)) { - message = PhFormatString(L"Services referencing %s in %s:", context->ModuleName, PhGetStringOrEmpty(processItem->ProcessName)); + message = PhFormatString(L"Services referencing %s in %s:", PhGetString(context->ModuleName), PhGetStringOrEmpty(processItem->ProcessName)); PhDereferenceObject(processItem); } else { - message = PhFormatString(L"Services referencing %s:", context->ModuleName); + message = PhFormatString(L"Services referencing %s:", PhGetString(context->ModuleName)); } PhSetDialogItemText(hwndDlg, IDC_MESSAGE, message->Buffer); @@ -196,31 +204,20 @@ INT_PTR CALLBACK EtpModuleServicesDlgProc( // Position the control. GetWindowRect(GetDlgItem(hwndDlg, IDC_SERVICES_LAYOUT), &rect); MapWindowPoints(NULL, hwndDlg, (POINT *)&rect, 2); - MoveWindow(serviceListHandle, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, FALSE); - ShowWindow(serviceListHandle, SW_SHOW); + MoveWindow(context->ServiceListHandle, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, FALSE); + ShowWindow(context->ServiceListHandle, SW_SHOW); PhInitializeLayoutManager(&context->LayoutManager, hwndDlg); PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_SERVICES_LAYOUT), NULL, PH_ANCHOR_ALL); - PhAddLayoutItem(&context->LayoutManager, serviceListHandle, NULL, PH_ANCHOR_ALL); + PhAddLayoutItem(&context->LayoutManager, context->ServiceListHandle, NULL, PH_ANCHOR_ALL); PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDOK), NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_RIGHT); if (PhGetIntegerPairSetting(SETTING_NAME_MODULE_SERVICES_WINDOW_POSITION).X != 0) PhLoadWindowPlacementFromSetting(SETTING_NAME_MODULE_SERVICES_WINDOW_POSITION, SETTING_NAME_MODULE_SERVICES_WINDOW_SIZE, hwndDlg); else PhCenterWindow(hwndDlg, GetParent(hwndDlg)); - } - break; - case WM_DESTROY: - { - if (IsWindowVisible(hwndDlg)) // HACK - { - PhSaveWindowPlacementToSetting(SETTING_NAME_MODULE_SERVICES_WINDOW_POSITION, SETTING_NAME_MODULE_SERVICES_WINDOW_SIZE, hwndDlg); - } - if (context->LayoutManager.List) // HACK - { - PhDeleteLayoutManager(&context->LayoutManager); - } + PhInitializeWindowTheme(hwndDlg, !!PhGetIntegerSetting(L"EnableThemeSupport")); } break; case WM_SIZE: @@ -234,7 +231,12 @@ INT_PTR CALLBACK EtpModuleServicesDlgProc( { case IDCANCEL: case IDOK: - EndDialog(hwndDlg, IDOK); + { + // NOTE: Don't save placement during WM_DESTROY since the dialog won't be created after an error querying service references. (dmex) + PhSaveWindowPlacementToSetting(SETTING_NAME_MODULE_SERVICES_WINDOW_POSITION, SETTING_NAME_MODULE_SERVICES_WINDOW_SIZE, hwndDlg); + + EndDialog(hwndDlg, IDOK); + } break; } } From 8942a3b9e61c032c458eda51f86f024d01d58ea0 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 5 Jan 2019 05:15:20 +0100 Subject: [PATCH 1523/2058] WindowExplorer: Add copy menu to Window properties pages --- plugins/WindowExplorer/WindowExplorer.rc | 17 +- plugins/WindowExplorer/resource.h | 3 +- plugins/WindowExplorer/wndprp.c | 191 ++++++++++++++++++++++- 3 files changed, 193 insertions(+), 18 deletions(-) diff --git a/plugins/WindowExplorer/WindowExplorer.rc b/plugins/WindowExplorer/WindowExplorer.rc index 67f9e673eb70..3e531eb86ff0 100644 --- a/plugins/WindowExplorer/WindowExplorer.rc +++ b/plugins/WindowExplorer/WindowExplorer.rc @@ -111,7 +111,7 @@ STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSM CAPTION "General" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN - CONTROL "",IDC_WINDOWINFO,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_ALIGNLEFT | WS_TABSTOP,0,0,271,224 + CONTROL "",IDC_WINDOWINFO,"SysListView32",LVS_REPORT | LVS_ALIGNLEFT | WS_TABSTOP,0,0,271,224 END IDD_WNDPROPLIST DIALOGEX 0, 0, 271, 224 @@ -209,21 +209,6 @@ BEGIN 0 END -IDD_WNDLIST AFX_DIALOG_LAYOUT -BEGIN - 0 -END - -IDD_WNDPROPSTORAGE AFX_DIALOG_LAYOUT -BEGIN - 0 -END - -IDD_WNDPROPLIST AFX_DIALOG_LAYOUT -BEGIN - 0 -END - #endif // English (Australia) resources ///////////////////////////////////////////////////////////////////////////// diff --git a/plugins/WindowExplorer/resource.h b/plugins/WindowExplorer/resource.h index ad622a387a8a..290c8f6f3502 100644 --- a/plugins/WindowExplorer/resource.h +++ b/plugins/WindowExplorer/resource.h @@ -12,6 +12,7 @@ #define IDD_WNDGENERAL 104 #define ID_VIEW_DESKTOPWINDOWS 105 #define IDD_WNDPROPLIST 105 +#define IDC_COPY 106 #define IDC_LIST 1001 #define IDC_REFRESH 1002 #define IDC_SEARCHEDIT 1035 @@ -46,6 +47,6 @@ #define _APS_NEXT_RESOURCE_VALUE 110 #define _APS_NEXT_COMMAND_VALUE 40028 #define _APS_NEXT_CONTROL_VALUE 1037 -#define _APS_NEXT_SYMED_VALUE 106 +#define _APS_NEXT_SYMED_VALUE 107 #endif #endif diff --git a/plugins/WindowExplorer/wndprp.c b/plugins/WindowExplorer/wndprp.c index 5029f73f0130..27b037b1b7b4 100644 --- a/plugins/WindowExplorer/wndprp.c +++ b/plugins/WindowExplorer/wndprp.c @@ -3,7 +3,7 @@ * window properties * * Copyright (C) 2011 wj32 - * Copyright (C) 2018 dmex + * Copyright (C) 2018-2019 dmex * * This file is part of Process Hacker. * @@ -883,6 +883,69 @@ INT_PTR CALLBACK WepWindowGeneralDlgProc( } } break; + case WM_NOTIFY: + { + PhHandleListViewNotifyBehaviors(lParam, GetDlgItem(hwndDlg, IDC_WINDOWINFO), PH_LIST_VIEW_DEFAULT_1_BEHAVIORS); + } + break; + case WM_CONTEXTMENU: + { + HWND listViewHandle = GetDlgItem(hwndDlg, IDC_WINDOWINFO); + + if ((HWND)wParam == listViewHandle) + { + POINT point; + PPH_EMENU menu; + PPH_EMENU item; + PVOID *listviewItems; + ULONG numberOfItems; + + point.x = GET_X_LPARAM(lParam); + point.y = GET_Y_LPARAM(lParam); + + if (point.x == -1 && point.y == -1) + PhGetListViewContextMenuPoint((HWND)wParam, &point); + + PhGetSelectedListViewItemParams(listViewHandle, &listviewItems, &numberOfItems); + + if (numberOfItems != 0) + { + menu = PhCreateEMenu(); + + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, IDC_COPY, L"&Copy", NULL, NULL), ULONG_MAX); + PhInsertCopyListViewEMenuItem(menu, IDC_COPY, listViewHandle); + + item = PhShowEMenu( + menu, + hwndDlg, + PH_EMENU_SHOW_SEND_COMMAND | PH_EMENU_SHOW_LEFTRIGHT, + PH_ALIGN_LEFT | PH_ALIGN_TOP, + point.x, + point.y + ); + + if (item) + { + if (!PhHandleCopyListViewEMenuItem(item)) + { + switch (item->Id) + { + case IDC_COPY: + { + PhCopyListView(listViewHandle); + } + break; + } + } + } + + PhDestroyEMenu(menu); + } + + PhFree(listviewItems); + } + } + break; case WEM_RESOLVE_DONE: { PSYMBOL_RESOLVE_CONTEXT resolveContext = (PSYMBOL_RESOLVE_CONTEXT)lParam; @@ -1047,6 +1110,69 @@ INT_PTR CALLBACK WepWindowPropertiesDlgProc( } } break; + case WM_NOTIFY: + { + PhHandleListViewNotifyBehaviors(lParam, GetDlgItem(hwndDlg, IDC_LIST), PH_LIST_VIEW_DEFAULT_1_BEHAVIORS); + } + break; + case WM_CONTEXTMENU: + { + HWND listViewHandle = GetDlgItem(hwndDlg, IDC_LIST); + + if ((HWND)wParam == listViewHandle) + { + POINT point; + PPH_EMENU menu; + PPH_EMENU item; + PVOID *listviewItems; + ULONG numberOfItems; + + point.x = GET_X_LPARAM(lParam); + point.y = GET_Y_LPARAM(lParam); + + if (point.x == -1 && point.y == -1) + PhGetListViewContextMenuPoint((HWND)wParam, &point); + + PhGetSelectedListViewItemParams(listViewHandle, &listviewItems, &numberOfItems); + + if (numberOfItems != 0) + { + menu = PhCreateEMenu(); + + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, IDC_COPY, L"&Copy", NULL, NULL), ULONG_MAX); + PhInsertCopyListViewEMenuItem(menu, IDC_COPY, listViewHandle); + + item = PhShowEMenu( + menu, + hwndDlg, + PH_EMENU_SHOW_SEND_COMMAND | PH_EMENU_SHOW_LEFTRIGHT, + PH_ALIGN_LEFT | PH_ALIGN_TOP, + point.x, + point.y + ); + + if (item) + { + if (!PhHandleCopyListViewEMenuItem(item)) + { + switch (item->Id) + { + case IDC_COPY: + { + PhCopyListView(listViewHandle); + } + break; + } + } + } + + PhDestroyEMenu(menu); + } + + PhFree(listviewItems); + } + } + break; } return FALSE; @@ -1179,6 +1305,69 @@ INT_PTR CALLBACK WepWindowPropStoreDlgProc( } } break; + case WM_NOTIFY: + { + PhHandleListViewNotifyBehaviors(lParam, GetDlgItem(hwndDlg, IDC_LIST), PH_LIST_VIEW_DEFAULT_1_BEHAVIORS); + } + break; + case WM_CONTEXTMENU: + { + HWND listViewHandle = GetDlgItem(hwndDlg, IDC_LIST); + + if ((HWND)wParam == listViewHandle) + { + POINT point; + PPH_EMENU menu; + PPH_EMENU item; + PVOID *listviewItems; + ULONG numberOfItems; + + point.x = GET_X_LPARAM(lParam); + point.y = GET_Y_LPARAM(lParam); + + if (point.x == -1 && point.y == -1) + PhGetListViewContextMenuPoint((HWND)wParam, &point); + + PhGetSelectedListViewItemParams(listViewHandle, &listviewItems, &numberOfItems); + + if (numberOfItems != 0) + { + menu = PhCreateEMenu(); + + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, IDC_COPY, L"&Copy", NULL, NULL), ULONG_MAX); + PhInsertCopyListViewEMenuItem(menu, IDC_COPY, listViewHandle); + + item = PhShowEMenu( + menu, + hwndDlg, + PH_EMENU_SHOW_SEND_COMMAND | PH_EMENU_SHOW_LEFTRIGHT, + PH_ALIGN_LEFT | PH_ALIGN_TOP, + point.x, + point.y + ); + + if (item) + { + if (!PhHandleCopyListViewEMenuItem(item)) + { + switch (item->Id) + { + case IDC_COPY: + { + PhCopyListView(listViewHandle); + } + break; + } + } + } + + PhDestroyEMenu(menu); + } + + PhFree(listviewItems); + } + } + break; } return FALSE; From 78f1c5571319e93069c2eb19e358224fb02c9fc5 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 5 Jan 2019 05:17:34 +0100 Subject: [PATCH 1524/2058] Update copyright --- ProcessHacker/prpgstat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ProcessHacker/prpgstat.c b/ProcessHacker/prpgstat.c index a5484f5552b9..cc4a68c41979 100644 --- a/ProcessHacker/prpgstat.c +++ b/ProcessHacker/prpgstat.c @@ -3,7 +3,7 @@ * Process properties: Statistics page * * Copyright (C) 2009-2016 wj32 - * Copyright (C) 2017-2018 dmex + * Copyright (C) 2017-2019 dmex * * This file is part of Process Hacker. * From be5184bb445d9b11eaf696d9196f19f95ec6455f Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 5 Jan 2019 05:49:29 +0100 Subject: [PATCH 1525/2058] HardwareDevices: Add copy menu to Disk/Network property pages --- plugins/HardwareDevices/HardwareDevices.rc | 50 ----- plugins/HardwareDevices/devices.h | 14 +- plugins/HardwareDevices/diskdetails.c | 232 ++++++++++++++++----- plugins/HardwareDevices/main.c | 2 +- plugins/HardwareDevices/netdetails.c | 69 +++++- 5 files changed, 251 insertions(+), 116 deletions(-) diff --git a/plugins/HardwareDevices/HardwareDevices.rc b/plugins/HardwareDevices/HardwareDevices.rc index a4ed0eff794d..54bb4cf44fe9 100644 --- a/plugins/HardwareDevices/HardwareDevices.rc +++ b/plugins/HardwareDevices/HardwareDevices.rc @@ -252,56 +252,6 @@ END #endif // APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// AFX_DIALOG_LAYOUT -// - -IDD_NETADAPTER_PANEL AFX_DIALOG_LAYOUT -BEGIN - 0 -END - -IDD_NETADAPTER_DETAILS AFX_DIALOG_LAYOUT -BEGIN - 0 -END - -IDD_NETADAPTER_OPTIONS AFX_DIALOG_LAYOUT -BEGIN - 0 -END - -IDD_NETADAPTER_DIALOG AFX_DIALOG_LAYOUT -BEGIN - 0 -END - -IDD_DISKDRIVE_OPTIONS AFX_DIALOG_LAYOUT -BEGIN - 0 -END - -IDD_DISKDRIVE_DIALOG AFX_DIALOG_LAYOUT -BEGIN - 0 -END - -IDD_DISKDRIVE_PANEL AFX_DIALOG_LAYOUT -BEGIN - 0 -END - -IDD_DISKDRIVE_DETAILS_SMART AFX_DIALOG_LAYOUT -BEGIN - 0 -END - -IDD_DISKDRIVE_DETAILS_FILESYSTEM AFX_DIALOG_LAYOUT -BEGIN - 0 -END - #endif // English (Australia) resources ///////////////////////////////////////////////////////////////////////////// diff --git a/plugins/HardwareDevices/devices.h b/plugins/HardwareDevices/devices.h index d29381554152..b89644816b91 100644 --- a/plugins/HardwareDevices/devices.h +++ b/plugins/HardwareDevices/devices.h @@ -507,10 +507,10 @@ typedef enum _DISKDRIVE_DETAILS_INDEX DISKDRIVE_DETAILS_INDEX_MFT_READ_BYTES, DISKDRIVE_DETAILS_INDEX_MFT_WRITE_BYTES, - DISKDRIVE_DETAILS_INDEX_ROOT_INDEX_READS, - DISKDRIVE_DETAILS_INDEX_ROOT_INDEX_WRITES, - DISKDRIVE_DETAILS_INDEX_ROOT_INDEX_READ_BYTES, - DISKDRIVE_DETAILS_INDEX_ROOT_INDEX_WRITE_BYTES, + //DISKDRIVE_DETAILS_INDEX_ROOT_INDEX_READS, + //DISKDRIVE_DETAILS_INDEX_ROOT_INDEX_WRITES, + //DISKDRIVE_DETAILS_INDEX_ROOT_INDEX_READ_BYTES, + //DISKDRIVE_DETAILS_INDEX_ROOT_INDEX_WRITE_BYTES, DISKDRIVE_DETAILS_INDEX_BITMAP_READS, DISKDRIVE_DETAILS_INDEX_BITMAP_WRITES, @@ -532,7 +532,7 @@ typedef enum _DISKDRIVE_DETAILS_INDEX DISKDRIVE_DETAILS_INDEX_LOGFILE_READ_BYTES, DISKDRIVE_DETAILS_INDEX_LOGFILE_WRITE_BYTES, - DISKDRIVE_DETAILS_INDEX_MFT_USER_LEVEL_WRITE, + /*DISKDRIVE_DETAILS_INDEX_MFT_USER_LEVEL_WRITE, DISKDRIVE_DETAILS_INDEX_MFT_USER_LEVEL_CREATE, DISKDRIVE_DETAILS_INDEX_MFT_USER_LEVEL_SETINFO, DISKDRIVE_DETAILS_INDEX_MFT_USER_LEVEL_FLUSH, @@ -568,7 +568,7 @@ typedef enum _DISKDRIVE_DETAILS_INDEX DISKDRIVE_DETAILS_INDEX_MFT_BITMAP_USER_LEVEL_WRITE, DISKDRIVE_DETAILS_INDEX_MFT_BITMAP_USER_LEVEL_CREATE, DISKDRIVE_DETAILS_INDEX_MFT_BITMAP_USER_LEVEL_SETINFO, - DISKDRIVE_DETAILS_INDEX_MFT_BITMAP_USER_LEVEL_FLUSH, + DISKDRIVE_DETAILS_INDEX_MFT_BITMAP_USER_LEVEL_FLUSH,*/ DISKDRIVE_DETAILS_INDEX_ALLOCATE_CALLS, DISKDRIVE_DETAILS_INDEX_ALLOCATE_CLUSTERS, @@ -837,4 +837,4 @@ VOID NetAdapterSysInfoInitializing( _In_ _Assume_refs_(1) PDV_NETADAPTER_ENTRY AdapterEntry ); -#endif _DEVICES_H_ \ No newline at end of file +#endif _DEVICES_H_ diff --git a/plugins/HardwareDevices/diskdetails.c b/plugins/HardwareDevices/diskdetails.c index 30d251588615..23472e632ec8 100644 --- a/plugins/HardwareDevices/diskdetails.c +++ b/plugins/HardwareDevices/diskdetails.c @@ -2,7 +2,7 @@ * Process Hacker Plugins - * Hardware Devices Plugin * - * Copyright (C) 2016-2017 dmex + * Copyright (C) 2016-2019 dmex * * This file is part of Process Hacker. * @@ -71,10 +71,10 @@ VOID DiskDriveAddListViewItemGroups( PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_READ_BYTES, L"Mft read bytes", NULL); PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_WRITE_BYTES, L"Mft write bytes", NULL); - PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_ROOT_INDEX_READS, L"RootIndex reads", NULL); - PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_ROOT_INDEX_WRITES, L"RootIndex writes", NULL); - PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_ROOT_INDEX_READ_BYTES, L"RootIndex read bytes", NULL); - PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_ROOT_INDEX_WRITE_BYTES, L"RootIndex write bytes", NULL); + //PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_ROOT_INDEX_READS, L"RootIndex reads", NULL); + //PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_ROOT_INDEX_WRITES, L"RootIndex writes", NULL); + //PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_ROOT_INDEX_READ_BYTES, L"RootIndex read bytes", NULL); + //PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_ROOT_INDEX_WRITE_BYTES, L"RootIndex write bytes", NULL); PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_BITMAP_READS, L"Bitmap reads", NULL); PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_BITMAP_WRITES, L"Bitmap writes", NULL); @@ -96,43 +96,43 @@ VOID DiskDriveAddListViewItemGroups( PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_LOGFILE_READ_BYTES, L"LogFile read bytes", NULL); PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_LOGFILE_WRITE_BYTES, L"LogFile write bytes", NULL); - PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_USER_LEVEL_WRITE, L"MftWritesUserLevel-Write", NULL); - PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_USER_LEVEL_CREATE, L"MftWritesUserLevel-Create", NULL); - PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_USER_LEVEL_SETINFO, L"MftWritesUserLevel-SetInfo", NULL); - PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_USER_LEVEL_FLUSH, L"MftWritesUserLevel-Flush", NULL); + //PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_USER_LEVEL_WRITE, L"MftWritesUserLevel-Write", NULL); + //PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_USER_LEVEL_CREATE, L"MftWritesUserLevel-Create", NULL); + //PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_USER_LEVEL_SETINFO, L"MftWritesUserLevel-SetInfo", NULL); + //PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_USER_LEVEL_FLUSH, L"MftWritesUserLevel-Flush", NULL); - PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_WRITES_FLUSH_LOGFILE, L"MftWritesFlushForLogFileFull", NULL); - PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_WRITES_LAZY_WRITER, L"MftWritesLazyWriter", NULL); - PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_WRITES_USER_REQUEST, L"MftWritesUserRequest", NULL); + //PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_WRITES_FLUSH_LOGFILE, L"MftWritesFlushForLogFileFull", NULL); + //PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_WRITES_LAZY_WRITER, L"MftWritesLazyWriter", NULL); + //PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_WRITES_USER_REQUEST, L"MftWritesUserRequest", NULL); - PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT2_WRITES, L"Mft2Writes", NULL); - PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT2_WRITE_BYTES, L"Mft2WriteBytes", NULL); + //PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT2_WRITES, L"Mft2Writes", NULL); + //PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT2_WRITE_BYTES, L"Mft2WriteBytes", NULL); - PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT2_USER_LEVEL_WRITE, L"Mft2WritesUserLevel-Write", NULL); - PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT2_USER_LEVEL_CREATE, L"Mft2WritesUserLevel-Create", NULL); - PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT2_USER_LEVEL_SETINFO, L"Mft2WritesUserLevel-SetInfo", NULL); - PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT2_USER_LEVEL_FLUSH, L"Mft2WritesUserLevel-Flush", NULL); + //PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT2_USER_LEVEL_WRITE, L"Mft2WritesUserLevel-Write", NULL); + //PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT2_USER_LEVEL_CREATE, L"Mft2WritesUserLevel-Create", NULL); + //PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT2_USER_LEVEL_SETINFO, L"Mft2WritesUserLevel-SetInfo", NULL); + //PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT2_USER_LEVEL_FLUSH, L"Mft2WritesUserLevel-Flush", NULL); - PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT2_WRITES_FLUSH_LOGFILE, L"Mft2WritesFlushForLogFileFull", NULL); - PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT2_WRITES_LAZY_WRITER, L"Mft2WritesLazyWriter", NULL); - PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT2_WRITES_USER_REQUEST, L"Mft2WritesUserRequest", NULL); + //PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT2_WRITES_FLUSH_LOGFILE, L"Mft2WritesFlushForLogFileFull", NULL); + //PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT2_WRITES_LAZY_WRITER, L"Mft2WritesLazyWriter", NULL); + //PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT2_WRITES_USER_REQUEST, L"Mft2WritesUserRequest", NULL); - PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_BITMAP_WRITES_FLUSH_LOGFILE, L"BitmapWritesFlushForLogFileFull", NULL); - PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_BITMAP_WRITES_LAZY_WRITER, L"BitmapWritesLazyWriter", NULL); - PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_BITMAP_WRITES_USER_REQUEST, L"BitmapWritesUserRequest", NULL); + //PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_BITMAP_WRITES_FLUSH_LOGFILE, L"BitmapWritesFlushForLogFileFull", NULL); + //PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_BITMAP_WRITES_LAZY_WRITER, L"BitmapWritesLazyWriter", NULL); + //PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_BITMAP_WRITES_USER_REQUEST, L"BitmapWritesUserRequest", NULL); - PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_BITMAP_WRITES_WRITE, L"BitmapWritesUserLevel-Write", NULL); - PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_BITMAP_WRITES_CREATE, L"BitmapWritesUserLevel-Create", NULL); - PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_BITMAP_WRITES_SETINFO, L"BitmapWritesUserLevel-SetInfo", NULL); + //PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_BITMAP_WRITES_WRITE, L"BitmapWritesUserLevel-Write", NULL); + //PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_BITMAP_WRITES_CREATE, L"BitmapWritesUserLevel-Create", NULL); + //PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_BITMAP_WRITES_SETINFO, L"BitmapWritesUserLevel-SetInfo", NULL); - PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_BITMAP_FLUSH_LOGFILE, L"MftBitmapWritesFlushForLogFileFull", NULL); - PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_BITMAP_LAZY_WRITER, L"MftBitmapWritesLazyWriter", NULL); - PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_BITMAP_USER_REQUEST, L"MftBitmapWritesUserRequest", NULL); + //PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_BITMAP_FLUSH_LOGFILE, L"MftBitmapWritesFlushForLogFileFull", NULL); + //PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_BITMAP_LAZY_WRITER, L"MftBitmapWritesLazyWriter", NULL); + //PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_BITMAP_USER_REQUEST, L"MftBitmapWritesUserRequest", NULL); - PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_BITMAP_USER_LEVEL_WRITE, L"MftBitmapWritesUserLevel-Write", NULL); - PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_BITMAP_USER_LEVEL_CREATE, L"MftBitmapWritesUserLevel-Create", NULL); - PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_BITMAP_USER_LEVEL_SETINFO, L"MftBitmapWritesUserLevel-SetInfo", NULL); - PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_BITMAP_USER_LEVEL_FLUSH, L"MftBitmapWritesUserLevel-Flush", NULL); + //PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_BITMAP_USER_LEVEL_WRITE, L"MftBitmapWritesUserLevel-Write", NULL); + //PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_BITMAP_USER_LEVEL_CREATE, L"MftBitmapWritesUserLevel-Create", NULL); + //PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_BITMAP_USER_LEVEL_SETINFO, L"MftBitmapWritesUserLevel-SetInfo", NULL); + //PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_BITMAP_USER_LEVEL_FLUSH, L"MftBitmapWritesUserLevel-Flush", NULL); PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_ALLOCATE_CALLS, L"Allocate-Calls", NULL); PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_ALLOCATE_CLUSTERS, L"Allocate-Clusters", NULL); @@ -416,14 +416,14 @@ VOID DiskDriveQueryFileSystem( PhaFormatSize(buffer->NtfsStatistics.MftReadBytes, -1)->Buffer); PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_MFT_WRITE_BYTES, 1, PhaFormatSize(buffer->NtfsStatistics.MftWriteBytes, -1)->Buffer); - PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_ROOT_INDEX_READS, 1, - PhaFormatUInt64(buffer->NtfsStatistics.RootIndexReads, TRUE)->Buffer); - PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_ROOT_INDEX_WRITES, 1, - PhaFormatUInt64(buffer->NtfsStatistics.RootIndexWrites, TRUE)->Buffer); - PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_ROOT_INDEX_READ_BYTES, 1, - PhaFormatSize(buffer->NtfsStatistics.RootIndexReadBytes, -1)->Buffer); - PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_ROOT_INDEX_WRITE_BYTES, 1, - PhaFormatSize(buffer->NtfsStatistics.RootIndexWriteBytes, -1)->Buffer); + //PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_ROOT_INDEX_READS, 1, + // PhaFormatUInt64(buffer->NtfsStatistics.RootIndexReads, TRUE)->Buffer); + //PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_ROOT_INDEX_WRITES, 1, + // PhaFormatUInt64(buffer->NtfsStatistics.RootIndexWrites, TRUE)->Buffer); + //PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_ROOT_INDEX_READ_BYTES, 1, + // PhaFormatSize(buffer->NtfsStatistics.RootIndexReadBytes, -1)->Buffer); + //PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_ROOT_INDEX_WRITE_BYTES, 1, + // PhaFormatSize(buffer->NtfsStatistics.RootIndexWriteBytes, -1)->Buffer); PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_BITMAP_READS, 1, PhaFormatUInt64(buffer->NtfsStatistics.BitmapReads, TRUE)->Buffer); PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_BITMAP_WRITES, 1, @@ -456,7 +456,7 @@ VOID DiskDriveQueryFileSystem( PhaFormatSize(buffer->NtfsStatistics.LogFileReadBytes, -1)->Buffer); PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_LOGFILE_WRITE_BYTES, 1, PhaFormatSize(buffer->NtfsStatistics.LogFileWriteBytes, -1)->Buffer); - PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_MFT_USER_LEVEL_WRITE, 1, + /*PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_MFT_USER_LEVEL_WRITE, 1, PhaFormatUInt64(buffer->NtfsStatistics.MftWritesUserLevel.Write, TRUE)->Buffer); PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_MFT_USER_LEVEL_CREATE, 1, PhaFormatUInt64(buffer->NtfsStatistics.MftWritesUserLevel.Create, TRUE)->Buffer); @@ -513,7 +513,7 @@ VOID DiskDriveQueryFileSystem( PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_MFT_BITMAP_USER_LEVEL_SETINFO, 1, PhaFormatUInt64(buffer->NtfsStatistics.MftBitmapWritesUserLevel.SetInfo, TRUE)->Buffer); PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_MFT_BITMAP_USER_LEVEL_FLUSH, 1, - PhaFormatUInt64(buffer->NtfsStatistics.MftBitmapWritesUserLevel.Flush, TRUE)->Buffer); + PhaFormatUInt64(buffer->NtfsStatistics.MftBitmapWritesUserLevel.Flush, TRUE)->Buffer);*/ PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_ALLOCATE_CALLS, 1, PhaFormatUInt64(buffer->NtfsStatistics.Allocate.Calls, TRUE)->Buffer); PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_ALLOCATE_CLUSTERS, 1, @@ -578,9 +578,7 @@ INT_PTR CALLBACK DiskDriveFileSystemDetailsDlgProc( if (uMsg == WM_INITDIALOG) { - context = PhAllocate(sizeof(DV_DISK_PAGE_CONTEXT)); - memset(context, 0, sizeof(DV_DISK_PAGE_CONTEXT)); - + context = PhAllocateZero(sizeof(DV_DISK_PAGE_CONTEXT)); context->PageContext = (PCOMMON_PAGE_CONTEXT)propPageContext->Context; PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context); @@ -608,8 +606,12 @@ INT_PTR CALLBACK DiskDriveFileSystemDetailsDlgProc( context->WindowHandle = hwndDlg; context->ListViewHandle = GetDlgItem(hwndDlg, IDC_DETAILS_LIST); - PhCenterWindow(GetParent(hwndDlg), NULL); // HACK - PhInitializeWindowTheme(GetParent(hwndDlg), !!PhGetIntegerSetting(L"EnableThemeSupport")); // HACK + PhCenterWindow(GetParent(hwndDlg), NULL); // HACK (dmex) + + if (!!PhGetIntegerSetting(L"EnableThemeSupport")) // TODO: Required for compat (dmex) + PhInitializeWindowTheme(GetParent(hwndDlg), !!PhGetIntegerSetting(L"EnableThemeSupport")); + else + PhInitializeWindowTheme(hwndDlg, FALSE); PhSetListViewStyle(context->ListViewHandle, FALSE, TRUE); PhSetControlTheme(context->ListViewHandle, L"explorer"); @@ -636,6 +638,67 @@ INT_PTR CALLBACK DiskDriveFileSystemDetailsDlgProc( } } break; + case WM_NOTIFY: + { + PhHandleListViewNotifyBehaviors(lParam, context->ListViewHandle, PH_LIST_VIEW_DEFAULT_1_BEHAVIORS); + } + break; + case WM_CONTEXTMENU: + { + if ((HWND)wParam == context->ListViewHandle) + { + POINT point; + PPH_EMENU menu; + PPH_EMENU item; + PVOID *listviewItems; + ULONG numberOfItems; + + point.x = GET_X_LPARAM(lParam); + point.y = GET_Y_LPARAM(lParam); + + if (point.x == -1 && point.y == -1) + PhGetListViewContextMenuPoint((HWND)wParam, &point); + + PhGetSelectedListViewItemParams(context->ListViewHandle, &listviewItems, &numberOfItems); + + if (numberOfItems != 0) + { + menu = PhCreateEMenu(); + + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, PHAPP_IDC_COPY, L"&Copy", NULL, NULL), ULONG_MAX); + PhInsertCopyListViewEMenuItem(menu, PHAPP_IDC_COPY, context->ListViewHandle); + + item = PhShowEMenu( + menu, + hwndDlg, + PH_EMENU_SHOW_SEND_COMMAND | PH_EMENU_SHOW_LEFTRIGHT, + PH_ALIGN_LEFT | PH_ALIGN_TOP, + point.x, + point.y + ); + + if (item) + { + if (!PhHandleCopyListViewEMenuItem(item)) + { + switch (item->Id) + { + case PHAPP_IDC_COPY: + { + PhCopyListView(context->ListViewHandle); + } + break; + } + } + } + + PhDestroyEMenu(menu); + } + + PhFree(listviewItems); + } + } + break; } return FALSE; @@ -657,9 +720,7 @@ INT_PTR CALLBACK DiskDriveSmartDetailsDlgProc( if (uMsg == WM_INITDIALOG) { - context = PhAllocate(sizeof(DV_DISK_PAGE_CONTEXT)); - memset(context, 0, sizeof(DV_DISK_PAGE_CONTEXT)); - + context = PhAllocateZero(sizeof(DV_DISK_PAGE_CONTEXT)); context->PageContext = (PCOMMON_PAGE_CONTEXT)propPageContext->Context; PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context); @@ -717,6 +778,67 @@ INT_PTR CALLBACK DiskDriveSmartDetailsDlgProc( } } break; + case WM_NOTIFY: + { + PhHandleListViewNotifyBehaviors(lParam, context->ListViewHandle, PH_LIST_VIEW_DEFAULT_1_BEHAVIORS); + } + break; + case WM_CONTEXTMENU: + { + if ((HWND)wParam == context->ListViewHandle) + { + POINT point; + PPH_EMENU menu; + PPH_EMENU item; + PVOID *listviewItems; + ULONG numberOfItems; + + point.x = GET_X_LPARAM(lParam); + point.y = GET_Y_LPARAM(lParam); + + if (point.x == -1 && point.y == -1) + PhGetListViewContextMenuPoint((HWND)wParam, &point); + + PhGetSelectedListViewItemParams(context->ListViewHandle, &listviewItems, &numberOfItems); + + if (numberOfItems != 0) + { + menu = PhCreateEMenu(); + + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, PHAPP_IDC_COPY, L"&Copy", NULL, NULL), ULONG_MAX); + PhInsertCopyListViewEMenuItem(menu, PHAPP_IDC_COPY, context->ListViewHandle); + + item = PhShowEMenu( + menu, + hwndDlg, + PH_EMENU_SHOW_SEND_COMMAND | PH_EMENU_SHOW_LEFTRIGHT, + PH_ALIGN_LEFT | PH_ALIGN_TOP, + point.x, + point.y + ); + + if (item) + { + if (!PhHandleCopyListViewEMenuItem(item)) + { + switch (item->Id) + { + case PHAPP_IDC_COPY: + { + PhCopyListView(context->ListViewHandle); + } + break; + } + } + } + + PhDestroyEMenu(menu); + } + + PhFree(listviewItems); + } + } + break; } return FALSE; @@ -772,9 +894,7 @@ VOID ShowDiskDriveDetailsDialog( { PCOMMON_PAGE_CONTEXT pageContext; - pageContext = PhAllocate(sizeof(COMMON_PAGE_CONTEXT)); - memset(pageContext, 0, sizeof(COMMON_PAGE_CONTEXT)); - + pageContext = PhAllocateZero(sizeof(COMMON_PAGE_CONTEXT)); pageContext->ParentHandle = GetParent(GetParent(Context->WindowHandle)); pageContext->DiskIndex = Context->DiskEntry->DiskIndex; //pageContext->Length = Context->DiskEntry->DiskLength; @@ -783,4 +903,4 @@ VOID ShowDiskDriveDetailsDialog( CopyDiskId(&pageContext->DiskId, &Context->DiskEntry->Id); PhCreateThread2(ShowDiskDriveDetailsDialogThread, pageContext); -} \ No newline at end of file +} diff --git a/plugins/HardwareDevices/main.c b/plugins/HardwareDevices/main.c index 9de149b19435..680f34912ce8 100644 --- a/plugins/HardwareDevices/main.c +++ b/plugins/HardwareDevices/main.c @@ -392,4 +392,4 @@ LOGICAL DllMain( } return TRUE; -} \ No newline at end of file +} diff --git a/plugins/HardwareDevices/netdetails.c b/plugins/HardwareDevices/netdetails.c index db01f6d41656..97f1f5b58f69 100644 --- a/plugins/HardwareDevices/netdetails.c +++ b/plugins/HardwareDevices/netdetails.c @@ -2,8 +2,8 @@ * Process Hacker Plugins - * Hardware Devices Plugin * - * Copyright (C) 2015-2016 dmex * Copyright (C) 2016 wj32 + * Copyright (C) 2015-2019 dmex * * This file is part of Process Hacker. * @@ -599,6 +599,71 @@ INT_PTR CALLBACK NetAdapterDetailsDlgProc( case UPDATE_MSG: NetAdapterUpdateDetails(context); break; + case WM_NOTIFY: + { + PhHandleListViewNotifyBehaviors(lParam, context->ListViewHandle, PH_LIST_VIEW_DEFAULT_1_BEHAVIORS); + } + break; + case WM_CONTEXTMENU: + { + if ((HWND)wParam == context->ListViewHandle) + { + POINT point; + PPH_EMENU menu; + PPH_EMENU item; + PVOID *listviewItems; + ULONG numberOfItems; + + point.x = GET_X_LPARAM(lParam); + point.y = GET_Y_LPARAM(lParam); + + if (point.x == -1 && point.y == -1) + PhGetListViewContextMenuPoint((HWND)wParam, &point); + + PhGetSelectedListViewItemParams(context->ListViewHandle, &listviewItems, &numberOfItems); + + if (numberOfItems != 0) + { + menu = PhCreateEMenu(); + + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, PHAPP_IDC_COPY, L"&Copy", NULL, NULL), ULONG_MAX); + PhInsertCopyListViewEMenuItem(menu, PHAPP_IDC_COPY, context->ListViewHandle); + + item = PhShowEMenu( + menu, + hwndDlg, + PH_EMENU_SHOW_SEND_COMMAND | PH_EMENU_SHOW_LEFTRIGHT, + PH_ALIGN_LEFT | PH_ALIGN_TOP, + point.x, + point.y + ); + + if (item) + { + BOOLEAN handled = FALSE; + + handled = PhHandleCopyListViewEMenuItem(item); + + if (!handled) + { + switch (item->Id) + { + case PHAPP_IDC_COPY: + { + PhCopyListView(context->ListViewHandle); + } + break; + } + } + } + + PhDestroyEMenu(menu); + } + + PhFree(listviewItems); + } + } + break; } return FALSE; @@ -669,4 +734,4 @@ VOID ShowNetAdapterDetailsDialog( CopyNetAdapterId(&context->AdapterId, &Context->AdapterEntry->AdapterId); PhCreateThread2(ShowNetAdapterDetailsDialogThread, context); -} \ No newline at end of file +} From baac3f23fc513cf1d81f67d71424e5238527602a Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 8 Jan 2019 22:28:10 +0100 Subject: [PATCH 1526/2058] Fix copy menu crash --- ProcessHacker/appsup.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/ProcessHacker/appsup.c b/ProcessHacker/appsup.c index e702c9a5c7b3..2bdb02dd0205 100644 --- a/ProcessHacker/appsup.c +++ b/ProcessHacker/appsup.c @@ -1796,6 +1796,17 @@ BOOLEAN PhHandleCopyCellEMenuItem( return TRUE; } +VOID NTAPI PhpCopyListViewEMenuItemDeleteFunction( + _In_ struct _PH_EMENU_ITEM *Item + ) +{ + PPH_COPY_ITEM_CONTEXT context; + + context = Item->Context; + PhDereferenceObject(context->MenuItemText); + PhFree(context); +} + BOOLEAN PhInsertCopyListViewEMenuItem( _In_ struct _PH_EMENU_ITEM *Menu, _In_ ULONG InsertAfterId, @@ -1814,8 +1825,10 @@ BOOLEAN PhInsertCopyListViewEMenuItem( HDITEM headerItem; WCHAR headerText[MAX_PATH]; - GetCursorPos(&location); - ScreenToClient(ListViewHandle, &location); + if (!GetCursorPos(&location)) + return FALSE; + if (!ScreenToClient(ListViewHandle, &location)) + return FALSE; memset(&lvHitInfo, 0, sizeof(LVHITTESTINFO)); lvHitInfo.pt = location; @@ -1852,7 +1865,7 @@ BOOLEAN PhInsertCopyListViewEMenuItem( PhDereferenceObject(escapedText); copyMenuItem = PhCreateEMenuItem(0, ID_COPY_CELL, menuItemText->Buffer, NULL, context); - copyMenuItem->DeleteFunction = PhpCopyCellEMenuItemDeleteFunction; + copyMenuItem->DeleteFunction = PhpCopyListViewEMenuItemDeleteFunction; context->MenuItemText = menuItemText; PhInsertEMenuItem(parentItem, copyMenuItem, indexInParent); From d211b278e3ec4cc50a3e9555d8b5a3587981364b Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 8 Jan 2019 22:32:52 +0100 Subject: [PATCH 1527/2058] Update some format specifiers, Update macro usage --- ProcessHacker/about.c | 6 +++--- ProcessHacker/actions.c | 12 ++++++------ ProcessHacker/anawait.c | 12 ++++++------ ProcessHacker/appsup.c | 6 +++--- ProcessHacker/colmgr.c | 14 +++++++------- ProcessHacker/hndlprp.c | 1 + ProcessHacker/hndlstat.c | 2 +- ProcessHacker/include/mainwnd.h | 4 ---- ProcessHacker/itemtips.c | 2 +- ProcessHacker/log.c | 4 ++-- ProcessHacker/mainwnd.c | 2 +- ProcessHacker/memlist.c | 8 ++++---- ProcessHacker/mwpgproc.c | 4 ++-- ProcessHacker/prpgmod.c | 3 +-- ProcessHacker/prpgwmi.c | 4 +--- ProcessHacker/runas.c | 8 ++++---- ProcessHacker/srvctl.c | 4 +--- ProcessHacker/srvprv.c | 2 +- ProcessHacker/syssccpu.c | 2 +- ProcessHacker/thrdstk.c | 4 ++-- phlib/cpysave.c | 2 +- phlib/hndlinfo.c | 8 ++++---- phlib/native.c | 6 +++--- phlib/settings.c | 4 ++-- phlib/util.c | 10 +++++----- tools/peview/colmgr.c | 12 ++++++------ 26 files changed, 69 insertions(+), 77 deletions(-) diff --git a/ProcessHacker/about.c b/ProcessHacker/about.c index 599aaedee7fc..0a8adc946709 100644 --- a/ProcessHacker/about.c +++ b/ProcessHacker/about.c @@ -59,7 +59,7 @@ static INT_PTR CALLBACK PhpAboutDlgProc( #if (PHAPP_VERSION_REVISION != 0) appName = PhFormatString( - L"Process Hacker %u.%u.%u (%hs)", + L"Process Hacker %lu.%lu.%lu (%hs)", PHAPP_VERSION_MAJOR, PHAPP_VERSION_MINOR, PHAPP_VERSION_REVISION, @@ -67,7 +67,7 @@ static INT_PTR CALLBACK PhpAboutDlgProc( ); #else appName = PhFormatString( - L"Process Hacker %u.%u", + L"Process Hacker %lu.%lu", PHAPP_VERSION_MAJOR, PHAPP_VERSION_MINOR ); @@ -190,7 +190,7 @@ PPH_STRING PhGetDiagnosticsString( PhAppendFormatStringBuilder(&stringBuilder, L"OBJECT INFORMATION\r\n"); #define OBJECT_TYPE_COUNT(Type) PhAppendFormatStringBuilder(&stringBuilder, \ - L#Type L": %u objects\r\n", PhpGetObjectTypeObjectCount(Type)) + L#Type L": %lu objects\r\n", PhpGetObjectTypeObjectCount(Type)) // ref OBJECT_TYPE_COUNT(PhObjectTypeObject); diff --git a/ProcessHacker/actions.c b/ProcessHacker/actions.c index 14dc68242a30..96cbc4de87c6 100644 --- a/ProcessHacker/actions.c +++ b/ProcessHacker/actions.c @@ -933,7 +933,7 @@ static BOOLEAN PhpShowErrorProcess( return PhShowContinueStatus( hWnd, PhaFormatString( - L"Unable to %s %s (PID %u)", + L"Unable to %s %s (PID %lu)", Verb, Process->ProcessName->Buffer, HandleToUlong(Process->ProcessId) @@ -2384,7 +2384,7 @@ static BOOLEAN PhpShowErrorThread( return PhShowContinueStatus( hWnd, PhaFormatString( - L"Unable to %s thread %u", + L"Unable to %s thread %lu", Verb, HandleToUlong(Thread->ThreadId) )->Buffer, @@ -2436,7 +2436,7 @@ BOOLEAN PhUiTerminateThreads( if (!cancelled && PhpShowErrorAndConnectToPhSvc( hWnd, - PhaFormatString(L"Unable to terminate thread %u", HandleToUlong(Threads[i]->ThreadId))->Buffer, + PhaFormatString(L"Unable to terminate thread %lu", HandleToUlong(Threads[i]->ThreadId))->Buffer, status, &connected )) @@ -2499,7 +2499,7 @@ BOOLEAN PhUiSuspendThreads( if (!cancelled && PhpShowErrorAndConnectToPhSvc( hWnd, - PhaFormatString(L"Unable to suspend thread %u", HandleToUlong(Threads[i]->ThreadId))->Buffer, + PhaFormatString(L"Unable to suspend thread %lu", HandleToUlong(Threads[i]->ThreadId))->Buffer, status, &connected )) @@ -2562,7 +2562,7 @@ BOOLEAN PhUiResumeThreads( if (!cancelled && PhpShowErrorAndConnectToPhSvc( hWnd, - PhaFormatString(L"Unable to resume thread %u", HandleToUlong(Threads[i]->ThreadId))->Buffer, + PhaFormatString(L"Unable to resume thread %lu", HandleToUlong(Threads[i]->ThreadId))->Buffer, status, &connected )) @@ -2655,7 +2655,7 @@ BOOLEAN PhUiSetIoPriorityThread( // The operation may have failed due to the lack of SeIncreaseBasePriorityPrivilege. if (PhpShowErrorAndConnectToPhSvc( hWnd, - PhaFormatString(L"Unable to set the I/O priority of thread %u", HandleToUlong(Thread->ThreadId))->Buffer, + PhaFormatString(L"Unable to set the I/O priority of thread %lu", HandleToUlong(Thread->ThreadId))->Buffer, status, &connected )) diff --git a/ProcessHacker/anawait.c b/ProcessHacker/anawait.c index 95a4c4e9a641..a9b49dfe5366 100644 --- a/ProcessHacker/anawait.c +++ b/ProcessHacker/anawait.c @@ -202,7 +202,7 @@ VOID PhpAnalyzeWaitPassive( if (!NT_SUCCESS(status = PhOpenThread(&threadHandle, THREAD_GET_CONTEXT, ThreadId))) { - PhShowStatus(hWnd, L"Unable to open the thread", status, 0); + PhShowStatus(hWnd, L"Unable to open the thread.", status, 0); return; } @@ -216,7 +216,7 @@ VOID PhpAnalyzeWaitPassive( if (!NT_SUCCESS(status = PhOpenProcess(&processHandle, PROCESS_DUP_HANDLE, ProcessId))) { NtClose(threadHandle); - PhShowStatus(hWnd, L"Unable to open the process", status, 0); + PhShowStatus(hWnd, L"Unable to open the process.", status, 0); return; } @@ -231,7 +231,7 @@ VOID PhpAnalyzeWaitPassive( } else if (lastSystemCall.SystemCallNumber == NumberForWfmo) { - PhAppendFormatStringBuilder(&stringBuilder, L"Thread is waiting for multiple (%u) objects.", PtrToUlong(lastSystemCall.FirstArgument)); + PhAppendFormatStringBuilder(&stringBuilder, L"Thread is waiting for multiple (%lu) objects.", PtrToUlong(lastSystemCall.FirstArgument)); } else if (lastSystemCall.SystemCallNumber == NumberForRf) { @@ -307,7 +307,7 @@ static BOOLEAN NTAPI PhpWalkThreadStackAnalyzeCallback( { PhAppendFormatStringBuilder( &context->StringBuilder, - L"Thread is sleeping. Timeout: %u milliseconds.", + L"Thread is sleeping. Timeout: %lu milliseconds.", PtrToUlong(StackFrame->Params[0]) ); } @@ -994,7 +994,7 @@ static PPH_STRING PhpaGetSendMessageReceiver( clientIdName = PH_AUTO(PhGetClientIdName(&clientId)); if (!GetClassName(windowHandle, windowClass, sizeof(windowClass) / sizeof(WCHAR))) - windowClass[0] = 0; + windowClass[0] = UNICODE_NULL; windowText = PH_AUTO(PhGetWindowText(windowHandle)); @@ -1038,7 +1038,7 @@ static PPH_STRING PhpaGetAlpcInformation( clientId.UniqueThread = NULL; clientIdName = PH_AUTO(PhGetClientIdName(&clientId)); - string = PhaFormatString(L"ALPC Port: %.*s (%s)", serverInfo->Out.ConnectionPortName.Length / 2, serverInfo->Out.ConnectionPortName.Buffer, clientIdName->Buffer); + string = PhaFormatString(L"ALPC Port: %.*s (%s)", serverInfo->Out.ConnectionPortName.Length / sizeof(WCHAR), serverInfo->Out.ConnectionPortName.Buffer, clientIdName->Buffer); } PhFree(serverInfo); diff --git a/ProcessHacker/appsup.c b/ProcessHacker/appsup.c index 2bdb02dd0205..717baec1e489 100644 --- a/ProcessHacker/appsup.c +++ b/ProcessHacker/appsup.c @@ -1108,9 +1108,9 @@ VOID PhWritePhTextHeader( PhDereferenceObject(version); } - PhWriteStringFormatAsUtf8FileStream(FileStream, L"\r\nWindows NT %u.%u", PhOsVersion.dwMajorVersion, PhOsVersion.dwMinorVersion); + PhWriteStringFormatAsUtf8FileStream(FileStream, L"\r\nWindows NT %lu.%lu", PhOsVersion.dwMajorVersion, PhOsVersion.dwMinorVersion); - if (PhOsVersion.szCSDVersion[0] != 0) + if (PhOsVersion.szCSDVersion[0] != UNICODE_NULL) PhWriteStringFormatAsUtf8FileStream(FileStream, L" %s", PhOsVersion.szCSDVersion); #ifdef _WIN64 @@ -1223,7 +1223,7 @@ BOOLEAN PhShellProcessHackerEx( PhAppendStringBuilder2(&sb, L" -newinstance"); if (PhStartupParameters.SelectPid != 0) - PhAppendFormatStringBuilder(&sb, L" -selectpid %u", PhStartupParameters.SelectPid); + PhAppendFormatStringBuilder(&sb, L" -selectpid %lu", PhStartupParameters.SelectPid); if (PhStartupParameters.PriorityClass != 0) { diff --git a/ProcessHacker/colmgr.c b/ProcessHacker/colmgr.c index fd2765d1467a..bfbbd792dc4f 100644 --- a/ProcessHacker/colmgr.c +++ b/ProcessHacker/colmgr.c @@ -595,7 +595,7 @@ PPH_STRING PhCmSaveSettingsEx( PhInitializeStringBuilder(&stringBuilder, 100); - PhAppendFormatStringBuilder(&stringBuilder, L"@%u|", PhGlobalDpi); + PhAppendFormatStringBuilder(&stringBuilder, L"@%lu|", PhGlobalDpi); while (count < total) { @@ -609,7 +609,7 @@ PPH_STRING PhCmSaveSettingsEx( { PhAppendFormatStringBuilder( &stringBuilder, - L"%u,%u,%u|", + L"%lu,%lu,%ld|", i, column.Fixed ? 0 : column.DisplayIndex + increment, column.Width @@ -622,7 +622,7 @@ PPH_STRING PhCmSaveSettingsEx( cmColumn = column.Context; PhAppendFormatStringBuilder( &stringBuilder, - L"+%s+%u,%u,%u|", + L"+%s+%lu,%lu,%ld|", cmColumn->Plugin->Name.Buffer, cmColumn->SubId, column.DisplayIndex + increment, @@ -637,7 +637,7 @@ PPH_STRING PhCmSaveSettingsEx( { PhAppendFormatStringBuilder( &stringBuilder, - L"%u,,%u|", + L"%lu,,%ld|", i, column.Width ); @@ -649,7 +649,7 @@ PPH_STRING PhCmSaveSettingsEx( cmColumn = column.Context; PhAppendFormatStringBuilder( &stringBuilder, - L"+%s+%u,,%u|", + L"+%s+%lu,,%ld|", cmColumn->Plugin->Name.Buffer, cmColumn->SubId, column.Width @@ -677,7 +677,7 @@ PPH_STRING PhCmSaveSettingsEx( { if (!Manager || sortColumn < Manager->MinId) { - *SortSettings = PhFormatString(L"%u,%u", sortColumn, sortOrder); + *SortSettings = PhFormatString(L"%lu,%lu", sortColumn, sortOrder); } else { @@ -687,7 +687,7 @@ PPH_STRING PhCmSaveSettingsEx( if (TreeNew_GetColumn(TreeNewHandle, sortColumn, &column)) { cmColumn = column.Context; - *SortSettings = PhFormatString(L"+%s+%u,%u", cmColumn->Plugin->Name.Buffer, cmColumn->SubId, sortOrder); + *SortSettings = PhFormatString(L"+%s+%lu,%lu", cmColumn->Plugin->Name.Buffer, cmColumn->SubId, sortOrder); } else { diff --git a/ProcessHacker/hndlprp.c b/ProcessHacker/hndlprp.c index b303bcffd632..d67fb3e061d3 100644 --- a/ProcessHacker/hndlprp.c +++ b/ProcessHacker/hndlprp.c @@ -747,6 +747,7 @@ VOID PhpUpdateHandleGeneral( FileModeAccessEntries, RTL_NUMBER_OF(FileModeAccessEntries) ); + PhInitFormatS(&format[0], L"0x"); PhInitFormatX(&format[1], fileModeInfo.Mode); PhInitFormatS(&format[2], L" ("); diff --git a/ProcessHacker/hndlstat.c b/ProcessHacker/hndlstat.c index 72d5b9501f66..ce783cfb42d3 100644 --- a/ProcessHacker/hndlstat.c +++ b/ProcessHacker/hndlstat.c @@ -191,7 +191,7 @@ INT_PTR CALLBACK PhpHandleStatisticsDlgProc( unknownType = NULL; if (!entry->Name) - unknownType = PhFormatString(L"(unknown: %u)", i); + unknownType = PhFormatString(L"(unknown: %lu)", i); countString = PhFormatUInt64(entry->Count, TRUE); diff --git a/ProcessHacker/include/mainwnd.h b/ProcessHacker/include/mainwnd.h index aa5fb72bfa7b..63766d28b4f4 100644 --- a/ProcessHacker/include/mainwnd.h +++ b/ProcessHacker/include/mainwnd.h @@ -196,10 +196,6 @@ BOOLEAN PhMainWndInitialization( _In_ INT ShowCommand ); -BOOLEAN PhInitializeRestartPolicy( - VOID - ); - VOID PhAddMiniProcessMenuItems( _Inout_ struct _PH_EMENU_ITEM *Menu, _In_ HANDLE ProcessId diff --git a/ProcessHacker/itemtips.c b/ProcessHacker/itemtips.c index a80318aca421..b82229aed72d 100644 --- a/ProcessHacker/itemtips.c +++ b/ProcessHacker/itemtips.c @@ -420,7 +420,7 @@ PPH_STRING PhGetProcessTooltipText( { PhAppendFormatStringBuilder( ¬es, - L" Image is probably packed (%u imports over %u modules).\n", + L" Image is probably packed (%lu imports over %lu modules).\n", Process->ImportFunctions, Process->ImportModules ); diff --git a/ProcessHacker/log.c b/ProcessHacker/log.c index b5334c064109..8b183142e93d 100644 --- a/ProcessHacker/log.c +++ b/ProcessHacker/log.c @@ -210,14 +210,14 @@ PPH_STRING PhFormatLogEntry( { case PH_LOG_ENTRY_PROCESS_CREATE: return PhFormatString( - L"Process created: %s (%u) started by %s (%u)", + L"Process created: %s (%lu) started by %s (%lu)", Entry->Process.Name->Buffer, HandleToUlong(Entry->Process.ProcessId), PhGetStringOrDefault(Entry->Process.ParentName, L"Unknown process"), HandleToUlong(Entry->Process.ParentProcessId) ); case PH_LOG_ENTRY_PROCESS_DELETE: - return PhFormatString(L"Process terminated: %s (%u); exit status 0x%x", Entry->Process.Name->Buffer, HandleToUlong(Entry->Process.ProcessId), Entry->Process.ExitStatus); + return PhFormatString(L"Process terminated: %s (%lu); exit status 0x%x", Entry->Process.Name->Buffer, HandleToUlong(Entry->Process.ProcessId), Entry->Process.ExitStatus); case PH_LOG_ENTRY_SERVICE_CREATE: return PhFormatString(L"Service created: %s (%s)", Entry->Service.Name->Buffer, Entry->Service.DisplayName->Buffer); case PH_LOG_ENTRY_SERVICE_DELETE: diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index 1a2a15fc851e..f7343e693a4f 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -3420,7 +3420,7 @@ VOID PhMwpUpdateUsersMenu( } menuText = PhFormatString( - L"%u: %s\\%s", + L"%lu: %s\\%s", sessions[i].SessionId, winStationInfo.Domain, winStationInfo.UserName diff --git a/ProcessHacker/memlist.c b/ProcessHacker/memlist.c index 2f7f18357300..f2748348cc8b 100644 --- a/ProcessHacker/memlist.c +++ b/ProcessHacker/memlist.c @@ -478,19 +478,19 @@ PPH_STRING PhGetMemoryRegionUseText( return PhFormatString(L"PEB%s", type == Peb32Region ? L" 32-bit" : L""); case TebRegion: case Teb32Region: - return PhFormatString(L"TEB%s (thread %u)", + return PhFormatString(L"TEB%s (thread %lu)", type == Teb32Region ? L" 32-bit" : L"", HandleToUlong(MemoryItem->u.Teb.ThreadId)); case StackRegion: case Stack32Region: - return PhFormatString(L"Stack%s (thread %u)", + return PhFormatString(L"Stack%s (thread %lu)", type == Stack32Region ? L" 32-bit" : L"", HandleToUlong(MemoryItem->u.Stack.ThreadId)); case HeapRegion: case Heap32Region: - return PhFormatString(L"Heap%s (ID %u)", + return PhFormatString(L"Heap%s (ID %lu)", type == Heap32Region ? L" 32-bit" : L"", (ULONG)MemoryItem->u.Heap.Index + 1); case HeapSegmentRegion: case HeapSegment32Region: - return PhFormatString(L"Heap segment%s (ID %u)", + return PhFormatString(L"Heap segment%s (ID %lu)", type == HeapSegment32Region ? L" 32-bit" : L"", (ULONG)MemoryItem->u.HeapSegment.HeapItem->u.Heap.Index + 1); case CfgBitmapRegion: case CfgBitmap32Region: diff --git a/ProcessHacker/mwpgproc.c b/ProcessHacker/mwpgproc.c index 8fe568514eef..8380a3ffd6d4 100644 --- a/ProcessHacker/mwpgproc.c +++ b/ProcessHacker/mwpgproc.c @@ -828,7 +828,7 @@ VOID PhMwpOnProcessAdded( PhMwpLastNotificationDetails.ProcessId = ProcessItem->ProcessId; PhShowIconNotification(L"Process Created", PhaFormatString( - L"The process %s (%u) was created by %s (%u)", + L"The process %s (%lu) was created by %s (%lu)", ProcessItem->ProcessName->Buffer, HandleToUlong(ProcessItem->ProcessId), PhGetStringOrDefault(parentName, L"Unknown process"), @@ -883,7 +883,7 @@ VOID PhMwpOnProcessRemoved( PhMwpLastNotificationDetails.ProcessId = ProcessItem->ProcessId; PhShowIconNotification(L"Process Terminated", PhaFormatString( - L"The process %s (%u) was terminated.", + L"The process %s (%lu) was terminated.", ProcessItem->ProcessName->Buffer, HandleToUlong(ProcessItem->ProcessId) )->Buffer, NIIF_INFO); diff --git a/ProcessHacker/prpgmod.c b/ProcessHacker/prpgmod.c index ab864c3f7c4b..988901eb16a9 100644 --- a/ProcessHacker/prpgmod.c +++ b/ProcessHacker/prpgmod.c @@ -178,7 +178,6 @@ VOID PhShowModuleContextMenu( PhFree(modules); } - static BOOLEAN PhpWordMatchHandleStringRef( _In_ PPH_STRING SearchText, _In_ PPH_STRINGREF Text @@ -541,7 +540,7 @@ INT_PTR CALLBACK PhpProcessModulesDlgProc( if (dialogItem = PhBeginPropPageLayout(hwndDlg, propPageContext)) { - PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_SEARCH), dialogItem, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); + PhAddPropPageLayoutItem(hwndDlg, modulesContext->SearchboxHandle, dialogItem, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); PhAddPropPageLayoutItem(hwndDlg, modulesContext->ListContext.TreeNewHandle, dialogItem, PH_ANCHOR_ALL); PhEndPropPageLayout(hwndDlg, propPageContext); } diff --git a/ProcessHacker/prpgwmi.c b/ProcessHacker/prpgwmi.c index 60613650a053..2300e26d90ab 100644 --- a/ProcessHacker/prpgwmi.c +++ b/ProcessHacker/prpgwmi.c @@ -579,9 +579,7 @@ INT_PTR CALLBACK PhpProcessWmiProvidersDlgProc( { case WM_INITDIALOG: { - context = propPageContext->Context = PhAllocate(sizeof(PH_WMI_CONTEXT)); - memset(context, 0, sizeof(PH_WMI_CONTEXT)); - + context = propPageContext->Context = PhAllocateZero(sizeof(PH_WMI_CONTEXT)); context->WindowHandle = hwndDlg; context->ListViewHandle = GetDlgItem(hwndDlg, IDC_LIST); context->Enabled = TRUE; diff --git a/ProcessHacker/runas.c b/ProcessHacker/runas.c index 5571d2bf7efd..02a4902c3ba4 100644 --- a/ProcessHacker/runas.c +++ b/ProcessHacker/runas.c @@ -624,7 +624,7 @@ static VOID PhpAddSessionsToComboBox( sessions[i].WinStationName[0] != UNICODE_NULL ) { - menuString = PhFormatString(L"%u: %s (%s\\%s)", + menuString = PhFormatString(L"%lu: %s (%s\\%s)", sessions[i].SessionId, sessions[i].WinStationName, winStationInfo.Domain, @@ -633,7 +633,7 @@ static VOID PhpAddSessionsToComboBox( } else if (winStationInfo.UserName[0] != UNICODE_NULL) { - menuString = PhFormatString(L"%u: %s\\%s", + menuString = PhFormatString(L"%lu: %s\\%s", sessions[i].SessionId, winStationInfo.Domain, winStationInfo.UserName @@ -641,14 +641,14 @@ static VOID PhpAddSessionsToComboBox( } else if (sessions[i].WinStationName[0] != UNICODE_NULL) { - menuString = PhFormatString(L"%u: %s", + menuString = PhFormatString(L"%lu: %s", sessions[i].SessionId, sessions[i].WinStationName ); } else { - menuString = PhFormatString(L"%u", sessions[i].SessionId); + menuString = PhFormatString(L"%lu", sessions[i].SessionId); } { diff --git a/ProcessHacker/srvctl.c b/ProcessHacker/srvctl.c index 3c18a81f1350..14a233483a27 100644 --- a/ProcessHacker/srvctl.c +++ b/ProcessHacker/srvctl.c @@ -78,9 +78,7 @@ HWND PhCreateServiceListControl( HWND windowHandle; PPH_SERVICES_CONTEXT servicesContext; - servicesContext = PhAllocate(sizeof(PH_SERVICES_CONTEXT)); - - memset(servicesContext, 0, sizeof(PH_SERVICES_CONTEXT)); + servicesContext = PhAllocateZero(sizeof(PH_SERVICES_CONTEXT)); servicesContext->Services = Services; servicesContext->NumberOfServices = NumberOfServices; diff --git a/ProcessHacker/srvprv.c b/ProcessHacker/srvprv.c index f238e7a640cc..41763e684262 100644 --- a/ProcessHacker/srvprv.c +++ b/ProcessHacker/srvprv.c @@ -948,7 +948,7 @@ VOID PhServiceProviderUpdate( if (serviceItem->ProcessId) PhPrintUInt32(serviceItem->ProcessIdString, HandleToUlong(serviceItem->ProcessId)); else - serviceItem->ProcessIdString[0] = 0; + serviceItem->ProcessIdString[0] = UNICODE_NULL; // Add/remove the service from its process. diff --git a/ProcessHacker/syssccpu.c b/ProcessHacker/syssccpu.c index 645db6ce55af..4b800884af0b 100644 --- a/ProcessHacker/syssccpu.c +++ b/ProcessHacker/syssccpu.c @@ -795,7 +795,7 @@ PPH_STRING PhSipGetMaxCpuString( if (!PH_IS_FAKE_PROCESS_ID(maxProcessRecord->ProcessId)) { maxUsageString = PhaFormatString( - L"\n%s (%u): %.2f%%", + L"\n%s (%lu): %.2f%%", maxProcessRecord->ProcessName->Buffer, HandleToUlong(maxProcessRecord->ProcessId), maxCpuUsage * 100 diff --git a/ProcessHacker/thrdstk.c b/ProcessHacker/thrdstk.c index 34c694a530af..92fd9978c50b 100644 --- a/ProcessHacker/thrdstk.c +++ b/ProcessHacker/thrdstk.c @@ -531,7 +531,7 @@ BOOLEAN NTAPI ThreadStackTreeNewCallback( { PhAppendFormatStringBuilder( &stringBuilder, - L"File: %s: line %u\n", + L"File: %s: line %lu\n", fileName->Buffer, lineInfo.LineNumber ); @@ -794,7 +794,7 @@ INT_PTR CALLBACK PhpThreadStackDlgProc( SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER))); SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER))); - PhSetWindowText(hwndDlg, PhaFormatString(L"Stack - thread %u", HandleToUlong(context->ThreadId))->Buffer); + PhSetWindowText(hwndDlg, PhaFormatString(L"Stack - thread %lu", HandleToUlong(context->ThreadId))->Buffer); InitializeThreadStackTree(context); diff --git a/phlib/cpysave.c b/phlib/cpysave.c index 167f4215a3ae..5c39206e0a1d 100644 --- a/phlib/cpysave.c +++ b/phlib/cpysave.c @@ -475,7 +475,7 @@ PPH_STRING PhaGetListViewItemText( allocatedCount *= 2; buffer = PhCreateStringEx(NULL, allocatedCount * sizeof(WCHAR)); - buffer->Buffer[0] = 0; + buffer->Buffer[0] = UNICODE_NULL; lvItem.iSubItem = SubItemIndex; lvItem.cchTextMax = (INT)allocatedCount + 1; diff --git a/phlib/hndlinfo.c b/phlib/hndlinfo.c index 3b58a4ff5dd7..2ed2307ce4cb 100644 --- a/phlib/hndlinfo.c +++ b/phlib/hndlinfo.c @@ -568,7 +568,7 @@ _Callback_ PPH_STRING PhStdGetClientIdName( if (processInfo) { name = PhFormatString( - L"%.*s (%u): %u", + L"%.*s (%lu): %lu", processInfo->ImageName.Length / sizeof(WCHAR), processInfo->ImageName.Buffer, HandleToUlong(ClientId->UniqueProcess), @@ -578,7 +578,7 @@ _Callback_ PPH_STRING PhStdGetClientIdName( else { name = PhFormatString( - L"Non-existent process (%u): %u", + L"Non-existent process (%lu): %lu", HandleToUlong(ClientId->UniqueProcess), HandleToUlong(ClientId->UniqueThread) ); @@ -589,7 +589,7 @@ _Callback_ PPH_STRING PhStdGetClientIdName( if (processInfo) { name = PhFormatString( - L"%.*s (%u)", + L"%.*s (%lu)", processInfo->ImageName.Length / sizeof(WCHAR), processInfo->ImageName.Buffer, HandleToUlong(ClientId->UniqueProcess) @@ -597,7 +597,7 @@ _Callback_ PPH_STRING PhStdGetClientIdName( } else { - name = PhFormatString(L"Non-existent process (%u)", HandleToUlong(ClientId->UniqueProcess)); + name = PhFormatString(L"Non-existent process (%lu)", HandleToUlong(ClientId->UniqueProcess)); } } diff --git a/phlib/native.c b/phlib/native.c index 492418ca87cf..f1f3395f80ac 100644 --- a/phlib/native.c +++ b/phlib/native.c @@ -3441,7 +3441,7 @@ BOOLEAN NTAPI PhpEnumProcessModulesCallback( // Read the full DLL name string and add a null terminator. fullDllNameOriginal = Entry->FullDllName.Buffer; - fullDllNameBuffer = PhAllocate(Entry->FullDllName.Length + sizeof(WCHAR)); + fullDllNameBuffer = PhAllocate(Entry->FullDllName.Length + sizeof(UNICODE_NULL)); Entry->FullDllName.Buffer = fullDllNameBuffer; if (NT_SUCCESS(status = NtReadVirtualMemory( @@ -3478,7 +3478,7 @@ BOOLEAN NTAPI PhpEnumProcessModulesCallback( { // Read the base DLL name string and add a null terminator. - baseDllNameBuffer = PhAllocate(Entry->BaseDllName.Length + sizeof(WCHAR)); + baseDllNameBuffer = PhAllocate(Entry->BaseDllName.Length + sizeof(UNICODE_NULL)); Entry->BaseDllName.Buffer = baseDllNameBuffer; if (NT_SUCCESS(NtReadVirtualMemory( @@ -3886,7 +3886,7 @@ BOOLEAN NTAPI PhpEnumProcessModules32Callback( } else { - fullDllNameBuffer[0] = 0; + fullDllNameBuffer[0] = UNICODE_NULL; nativeEntry.FullDllName.Length = 0; } diff --git a/phlib/settings.c b/phlib/settings.c index 51aeb159d1e9..ad653a438a21 100644 --- a/phlib/settings.c +++ b/phlib/settings.c @@ -1243,7 +1243,7 @@ PPH_STRING PhSaveListViewColumnSettings( PhInitializeStringBuilder(&stringBuilder, 20); - PhAppendFormatStringBuilder(&stringBuilder, L"@%u|", PhGlobalDpi); + PhAppendFormatStringBuilder(&stringBuilder, L"@%lu|", PhGlobalDpi); lvColumn.mask = LVCF_WIDTH | LVCF_ORDER; @@ -1340,7 +1340,7 @@ VOID PhSaveListViewSortColumnsToSetting( PH_SORT_ORDER sortOrder = AscendingSortOrder; if (ExtendedListView_GetSort(ListViewHandle, &sortColumn, &sortOrder)) - string = PhFormatString(L"%u,%u", sortColumn, sortOrder); + string = PhFormatString(L"%lu,%lu", sortColumn, sortOrder); else string = PhCreateString(L"0,0"); diff --git a/phlib/util.c b/phlib/util.c index c231df47e9bc..a84e2fd2229a 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -5215,7 +5215,7 @@ PPH_STRING PhLoadString( PPH_STRING string = NULL; ULONG resourceLength; PVOID resourceBuffer; - ULONG stringCount; + ULONG stringIndex; PWSTR stringBuffer; ULONG i; @@ -5231,9 +5231,9 @@ PPH_STRING PhLoadString( } stringBuffer = resourceBuffer; - stringCount = ResourceId & 0x000F; + stringIndex = ResourceId & 0x000F; - for (i = 0; i < stringCount; i++) // dmex: Copied from ReactOS. + for (i = 0; i < stringIndex; i++) // dmex: Copied from ReactOS. { stringBuffer += *stringBuffer + 1; } @@ -5807,7 +5807,7 @@ static NTSTATUS PhpFixupLoaderEntryImageImports( if (NT_SUCCESS(PhGetProcessMappedFileName(NtCurrentProcess(), BaseAddress, &fileName))) { - PhMoveReference(&fileName, PhResolveDevicePrefix(fileName)); + PhMoveReference(&fileName, PhGetFileName(fileName)); PhMoveReference(&fileName, PhGetBaseName(fileName)); PhShowError( @@ -5844,7 +5844,7 @@ static NTSTATUS PhpFixupLoaderEntryImageImports( if (NT_SUCCESS(PhGetProcessMappedFileName(NtCurrentProcess(), BaseAddress, &fileName))) { - PhMoveReference(&fileName, PhResolveDevicePrefix(fileName)); + PhMoveReference(&fileName, PhGetFileName(fileName)); PhMoveReference(&fileName, PhGetBaseName(fileName)); PhShowError( diff --git a/tools/peview/colmgr.c b/tools/peview/colmgr.c index dc4b4c963cc4..286f4f9ee564 100644 --- a/tools/peview/colmgr.c +++ b/tools/peview/colmgr.c @@ -494,7 +494,7 @@ PPH_STRING PhCmSaveSettingsEx( { PhAppendFormatStringBuilder( &stringBuilder, - L"%u,%u,%u|", + L"%lu,%lu,%lu|", i, column.Fixed ? 0 : column.DisplayIndex + increment, column.Width @@ -507,7 +507,7 @@ PPH_STRING PhCmSaveSettingsEx( cmColumn = column.Context; PhAppendFormatStringBuilder( &stringBuilder, - L"+%u,%u,%u|", + L"+%lu,%lu,%ld|", cmColumn->SubId, column.DisplayIndex + increment, column.Width @@ -521,7 +521,7 @@ PPH_STRING PhCmSaveSettingsEx( { PhAppendFormatStringBuilder( &stringBuilder, - L"%u,,%u|", + L"%lu,,%ld|", i, column.Width ); @@ -533,7 +533,7 @@ PPH_STRING PhCmSaveSettingsEx( cmColumn = column.Context; PhAppendFormatStringBuilder( &stringBuilder, - L"+%u,,%u|", + L"+%lu,,%ld|", cmColumn->SubId, column.Width ); @@ -560,7 +560,7 @@ PPH_STRING PhCmSaveSettingsEx( { if (!Manager || sortColumn < Manager->MinId) { - *SortSettings = PhFormatString(L"%u,%u", sortColumn, sortOrder); + *SortSettings = PhFormatString(L"%lu,%lu", sortColumn, sortOrder); } else { @@ -570,7 +570,7 @@ PPH_STRING PhCmSaveSettingsEx( if (TreeNew_GetColumn(TreeNewHandle, sortColumn, &column)) { cmColumn = column.Context; - *SortSettings = PhFormatString(L"+%u,%u", cmColumn->SubId, sortOrder); + *SortSettings = PhFormatString(L"+%lu,%lu", cmColumn->SubId, sortOrder); } else { From 9cc584fa8f456354e3b458918f984589270a48eb Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 8 Jan 2019 22:34:39 +0100 Subject: [PATCH 1528/2058] Fix network connection hashtable hash --- ProcessHacker/netprv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ProcessHacker/netprv.c b/ProcessHacker/netprv.c index 3b1cafec2370..63a6c9ac7a2b 100644 --- a/ProcessHacker/netprv.c +++ b/ProcessHacker/netprv.c @@ -188,7 +188,7 @@ ULONG NTAPI PhpNetworkHashtableHashFunction( networkItem->ProtocolType ^ PhHashIpEndpoint(&networkItem->LocalEndpoint) ^ PhHashIpEndpoint(&networkItem->RemoteEndpoint) ^ - HandleToUlong(networkItem->ProcessId); + (HandleToUlong(networkItem->ProcessId) / 4); } PPH_NETWORK_ITEM PhReferenceNetworkItem( From 4ec3f51f114706ededa07b84e58633e7d1bd9961 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 8 Jan 2019 23:13:46 +0100 Subject: [PATCH 1529/2058] peview: Add copy menu to properties pages --- tools/peview/cfgprp.c | 5 + tools/peview/expprp.c | 5 + tools/peview/impprp.c | 5 + tools/peview/include/peview.h | 7 + tools/peview/ldprp.c | 11 +- tools/peview/misc.c | 233 ++++++++++++++++++++++++++++++++++ tools/peview/peprp.c | 5 + tools/peview/propstore.c | 5 + tools/peview/resprp.c | 5 + tools/peview/searchbox.c | 2 +- tools/peview/streams.c | 5 + 11 files changed, 283 insertions(+), 5 deletions(-) diff --git a/tools/peview/cfgprp.c b/tools/peview/cfgprp.c index eafb3d8bea3f..91f283e53723 100644 --- a/tools/peview/cfgprp.c +++ b/tools/peview/cfgprp.c @@ -167,6 +167,11 @@ INT_PTR CALLBACK PvpPeCgfDlgProc( PvHandleListViewNotifyForCopy(lParam, GetDlgItem(hwndDlg, IDC_LIST)); } break; + case WM_CONTEXTMENU: + { + PvHandleListViewCommandCopy(hwndDlg, lParam, wParam, GetDlgItem(hwndDlg, IDC_LIST)); + } + break; } return FALSE; diff --git a/tools/peview/expprp.c b/tools/peview/expprp.c index e37d38df8a4e..368828a583ec 100644 --- a/tools/peview/expprp.c +++ b/tools/peview/expprp.c @@ -199,6 +199,11 @@ INT_PTR CALLBACK PvpPeExportsDlgProc( PvHandleListViewNotifyForCopy(lParam, GetDlgItem(hwndDlg, IDC_LIST)); } break; + case WM_CONTEXTMENU: + { + PvHandleListViewCommandCopy(hwndDlg, lParam, wParam, GetDlgItem(hwndDlg, IDC_LIST)); + } + break; } return FALSE; diff --git a/tools/peview/impprp.c b/tools/peview/impprp.c index 50265137969b..167d08c47a5b 100644 --- a/tools/peview/impprp.c +++ b/tools/peview/impprp.c @@ -239,6 +239,11 @@ INT_PTR CALLBACK PvpPeImportsDlgProc( PvHandleListViewNotifyForCopy(lParam, GetDlgItem(hwndDlg, IDC_LIST)); } break; + case WM_CONTEXTMENU: + { + PvHandleListViewCommandCopy(hwndDlg, lParam, wParam, GetDlgItem(hwndDlg, IDC_LIST)); + } + break; } return FALSE; diff --git a/tools/peview/include/peview.h b/tools/peview/include/peview.h index 53277e2eafb2..cc336b00f720 100644 --- a/tools/peview/include/peview.h +++ b/tools/peview/include/peview.h @@ -80,6 +80,13 @@ VOID PvHandleListViewNotifyForCopy( _In_ HWND ListViewHandle ); +VOID PvHandleListViewCommandCopy( + _In_ HWND WindowHandle, + _In_ LPARAM lParam, + _In_ WPARAM wParam, + _In_ HWND ListViewHandle + ); + // settings VOID PeInitializeSettings( diff --git a/tools/peview/ldprp.c b/tools/peview/ldprp.c index 3c554472262f..d5f85aaba41c 100644 --- a/tools/peview/ldprp.c +++ b/tools/peview/ldprp.c @@ -170,10 +170,8 @@ INT_PTR CALLBACK PvpPeLoadConfigDlgProc( { PPH_LAYOUT_ITEM dialogItem; - dialogItem = PvAddPropPageLayoutItem(hwndDlg, hwndDlg, - PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL); - PvAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_LIST), - dialogItem, PH_ANCHOR_ALL); + dialogItem = PvAddPropPageLayoutItem(hwndDlg, hwndDlg, PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL); + PvAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_LIST), dialogItem, PH_ANCHOR_ALL); PvDoPropPageLayout(hwndDlg); @@ -186,6 +184,11 @@ INT_PTR CALLBACK PvpPeLoadConfigDlgProc( PvHandleListViewNotifyForCopy(lParam, GetDlgItem(hwndDlg, IDC_LIST)); } break; + case WM_CONTEXTMENU: + { + PvHandleListViewCommandCopy(hwndDlg, lParam, wParam, GetDlgItem(hwndDlg, IDC_LIST)); + } + break; } return FALSE; diff --git a/tools/peview/misc.c b/tools/peview/misc.c index 5551683d9201..bbf37fd8e56e 100644 --- a/tools/peview/misc.c +++ b/tools/peview/misc.c @@ -3,6 +3,7 @@ * PE viewer * * Copyright (C) 2011 wj32 + * Copyright (C) 2019 dmex * * This file is part of Process Hacker. * @@ -21,6 +22,7 @@ */ #include +#include #include @@ -98,3 +100,234 @@ VOID PvHandleListViewNotifyForCopy( } } } + +typedef struct _PH_COPY_ITEM_CONTEXT +{ + HWND ListViewHandle; + ULONG Id; + ULONG SubId; + PPH_STRING MenuItemText; +} PH_COPY_ITEM_CONTEXT, *PPH_COPY_ITEM_CONTEXT; + +VOID NTAPI PhpCopyListViewEMenuItemDeleteFunction( + _In_ struct _PH_EMENU_ITEM *Item + ) +{ + PPH_COPY_ITEM_CONTEXT context; + + context = Item->Context; + PhDereferenceObject(context->MenuItemText); + PhFree(context); +} + +BOOLEAN PvInsertCopyListViewEMenuItem( + _In_ struct _PH_EMENU_ITEM *Menu, + _In_ ULONG InsertAfterId, + _In_ HWND ListViewHandle + ) +{ + PPH_EMENU_ITEM parentItem; + ULONG indexInParent; + PPH_COPY_ITEM_CONTEXT context; + PPH_STRING columnText = NULL; + PPH_STRING escapedText; + PPH_STRING menuItemText; + PPH_EMENU_ITEM copyMenuItem; + POINT location; + LVHITTESTINFO lvHitInfo; + HDITEM headerItem; + WCHAR headerText[MAX_PATH]; + + if (!GetCursorPos(&location)) + return FALSE; + if (!ScreenToClient(ListViewHandle, &location)) + return FALSE; + + memset(&lvHitInfo, 0, sizeof(LVHITTESTINFO)); + lvHitInfo.pt = location; + + if (ListView_SubItemHitTest(ListViewHandle, &lvHitInfo) == -1) + return FALSE; + + memset(headerText, 0, sizeof(headerText)); + memset(&headerItem, 0, sizeof(HDITEM)); + headerItem.mask = HDI_TEXT; + headerItem.cchTextMax = RTL_NUMBER_OF(headerText); + headerItem.pszText = headerText; + + if (!Header_GetItem(ListView_GetHeader(ListViewHandle), lvHitInfo.iSubItem, &headerItem)) + return FALSE; + + columnText = PhaCreateString(headerText); + + if (PhIsNullOrEmptyString(columnText)) + return FALSE; + + if (!PhFindEMenuItemEx(Menu, 0, NULL, InsertAfterId, &parentItem, &indexInParent)) + return FALSE; + + indexInParent++; + + context = PhAllocate(sizeof(PH_COPY_ITEM_CONTEXT)); + context->ListViewHandle = ListViewHandle; + context->Id = lvHitInfo.iItem; + context->SubId = lvHitInfo.iSubItem; + + escapedText = PhEscapeStringForMenuPrefix(&columnText->sr); + menuItemText = PhFormatString(L"Copy \"%s\"", escapedText->Buffer); + PhDereferenceObject(escapedText); + + copyMenuItem = PhCreateEMenuItem(0, INT_MAX, menuItemText->Buffer, NULL, context); + copyMenuItem->DeleteFunction = PhpCopyListViewEMenuItemDeleteFunction; + context->MenuItemText = menuItemText; + + PhInsertEMenuItem(parentItem, copyMenuItem, indexInParent); + + return TRUE; +} + +BOOLEAN PvHandleCopyListViewEMenuItem( + _In_ struct _PH_EMENU_ITEM *SelectedItem + ) +{ + PPH_COPY_ITEM_CONTEXT context; + PH_STRING_BUILDER stringBuilder; + ULONG count; + ULONG selectedCount; + ULONG i; + PPH_STRING getItemText; + + if (!SelectedItem) + return FALSE; + if (SelectedItem->Id != INT_MAX) + return FALSE; + + context = SelectedItem->Context; + + PhInitializeStringBuilder(&stringBuilder, 0x100); + count = ListView_GetItemCount(context->ListViewHandle); + selectedCount = 0; + + for (i = 0; i < count; i++) + { + if (!(ListView_GetItemState(context->ListViewHandle, i, LVIS_SELECTED) & LVIS_SELECTED)) + continue; + + getItemText = PhaGetListViewItemText(context->ListViewHandle, i, context->SubId); + + PhAppendStringBuilder(&stringBuilder, &getItemText->sr); + PhAppendStringBuilder2(&stringBuilder, L"\r\n"); + + selectedCount++; + } + + if (stringBuilder.String->Length != 0 && selectedCount == 1) + PhRemoveEndStringBuilder(&stringBuilder, 2); + + PhSetClipboardString(context->ListViewHandle, &stringBuilder.String->sr); + PhDeleteStringBuilder(&stringBuilder); + + return TRUE; +} + +BOOLEAN PvGetListViewContextMenuPoint( + _In_ HWND ListViewHandle, + _Out_ PPOINT Point + ) +{ + INT selectedIndex; + RECT bounds; + RECT clientRect; + + // The user pressed a key to display the context menu. + // Suggest where the context menu should display. + + if ((selectedIndex = ListView_GetNextItem(ListViewHandle, -1, LVNI_SELECTED)) != -1) + { + if (ListView_GetItemRect(ListViewHandle, selectedIndex, &bounds, LVIR_BOUNDS)) + { + Point->x = bounds.left + PhSmallIconSize.X / 2; + Point->y = bounds.top + PhSmallIconSize.Y / 2; + + GetClientRect(ListViewHandle, &clientRect); + + if (Point->x < 0 || Point->y < 0 || Point->x >= clientRect.right || Point->y >= clientRect.bottom) + { + // The menu is going to be outside of the control. Just put it at the top-left. + Point->x = 0; + Point->y = 0; + } + + ClientToScreen(ListViewHandle, Point); + + return TRUE; + } + } + + Point->x = 0; + Point->y = 0; + ClientToScreen(ListViewHandle, Point); + + return FALSE; +} + +VOID PvHandleListViewCommandCopy( + _In_ HWND WindowHandle, + _In_ LPARAM lParam, + _In_ WPARAM wParam, + _In_ HWND ListViewHandle + ) +{ + if ((HWND)wParam == ListViewHandle) + { + POINT point; + PPH_EMENU menu; + PPH_EMENU item; + PVOID *listviewItems; + ULONG numberOfItems; + + point.x = GET_X_LPARAM(lParam); + point.y = GET_Y_LPARAM(lParam); + + if (point.x == -1 && point.y == -1) + PvGetListViewContextMenuPoint((HWND)wParam, &point); + + PhGetSelectedListViewItemParams(ListViewHandle, &listviewItems, &numberOfItems); + + if (numberOfItems != 0) + { + menu = PhCreateEMenu(); + + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, USHRT_MAX, L"&Copy", NULL, NULL), ULONG_MAX); + PvInsertCopyListViewEMenuItem(menu, USHRT_MAX, ListViewHandle); + + item = PhShowEMenu( + menu, + WindowHandle, + PH_EMENU_SHOW_SEND_COMMAND | PH_EMENU_SHOW_LEFTRIGHT, + PH_ALIGN_LEFT | PH_ALIGN_TOP, + point.x, + point.y + ); + + if (item) + { + if (!PvHandleCopyListViewEMenuItem(item)) + { + switch (item->Id) + { + case USHRT_MAX: + { + PvCopyListView(ListViewHandle); + } + break; + } + } + } + + PhDestroyEMenu(menu); + } + + PhFree(listviewItems); + } +} diff --git a/tools/peview/peprp.c b/tools/peview/peprp.c index 2dd57f159ec4..19785556c797 100644 --- a/tools/peview/peprp.c +++ b/tools/peview/peprp.c @@ -820,6 +820,11 @@ INT_PTR CALLBACK PvpPeGeneralDlgProc( PvHandleListViewNotifyForCopy(lParam, GetDlgItem(hwndDlg, IDC_LIST)); } break; + case WM_CONTEXTMENU: + { + PvHandleListViewCommandCopy(hwndDlg, lParam, wParam, GetDlgItem(hwndDlg, IDC_LIST)); + } + break; } return FALSE; diff --git a/tools/peview/propstore.c b/tools/peview/propstore.c index 6e3ee9b365ae..f5b1aebc1ce0 100644 --- a/tools/peview/propstore.c +++ b/tools/peview/propstore.c @@ -160,6 +160,11 @@ INT_PTR CALLBACK PvpPePropStoreDlgProc( PvHandleListViewNotifyForCopy(lParam, GetDlgItem(hwndDlg, IDC_LIST)); } break; + case WM_CONTEXTMENU: + { + PvHandleListViewCommandCopy(hwndDlg, lParam, wParam, GetDlgItem(hwndDlg, IDC_LIST)); + } + break; } return FALSE; diff --git a/tools/peview/resprp.c b/tools/peview/resprp.c index 23efb382c2ee..9fe4f4d1ebad 100644 --- a/tools/peview/resprp.c +++ b/tools/peview/resprp.c @@ -240,6 +240,11 @@ INT_PTR CALLBACK PvpPeResourcesDlgProc( PvHandleListViewNotifyForCopy(lParam, GetDlgItem(hwndDlg, IDC_LIST)); } break; + case WM_CONTEXTMENU: + { + PvHandleListViewCommandCopy(hwndDlg, lParam, wParam, GetDlgItem(hwndDlg, IDC_LIST)); + } + break; } return FALSE; diff --git a/tools/peview/searchbox.c b/tools/peview/searchbox.c index 5ebf3afed508..bb3a20dbf82d 100644 --- a/tools/peview/searchbox.c +++ b/tools/peview/searchbox.c @@ -109,7 +109,7 @@ VOID PhpSearchInitializeTheme( _Inout_ PEDIT_CONTEXT Context ) { - Context->CXWidth = 20;// PH_SCALE_DPI(20); + Context->CXWidth = PhMultiplyDivideSigned(20, PhGlobalDpi, 96);// PH_SCALE_DPI(20); Context->BrushNormal = GetSysColorBrush(COLOR_WINDOW); Context->BrushHot = CreateSolidBrush(RGB(205, 232, 255)); Context->BrushPushed = CreateSolidBrush(RGB(153, 209, 255)); diff --git a/tools/peview/streams.c b/tools/peview/streams.c index 3f0234b85349..7d25426e4c6b 100644 --- a/tools/peview/streams.c +++ b/tools/peview/streams.c @@ -131,6 +131,11 @@ INT_PTR CALLBACK PvpPeStreamsDlgProc( PvHandleListViewNotifyForCopy(lParam, GetDlgItem(hwndDlg, IDC_LIST)); } break; + case WM_CONTEXTMENU: + { + PvHandleListViewCommandCopy(hwndDlg, lParam, wParam, GetDlgItem(hwndDlg, IDC_LIST)); + } + break; } return FALSE; From b3d96c8b1de6823962a0871ffdd68826ce4c8699 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 11 Jan 2019 21:25:27 +0100 Subject: [PATCH 1530/2058] Add PhEnumDirectoryFileEx --- phlib/include/phnative.h | 14 +++++++++++++- phlib/native.c | 42 +++++++++++++++++++++++++++------------- 2 files changed, 42 insertions(+), 14 deletions(-) diff --git a/phlib/include/phnative.h b/phlib/include/phnative.h index 5ba30eb1bcb6..7ffc0db643a6 100644 --- a/phlib/include/phnative.h +++ b/phlib/include/phnative.h @@ -915,7 +915,7 @@ PhEnumDirectoryObjects( ); typedef BOOLEAN (NTAPI *PPH_ENUM_DIRECTORY_FILE)( - _In_ PFILE_DIRECTORY_INFORMATION Information, + _In_ PVOID Information, _In_opt_ PVOID Context ); @@ -929,6 +929,18 @@ PhEnumDirectoryFile( _In_opt_ PVOID Context ); +PHLIBAPI +NTSTATUS +NTAPI +PhEnumDirectoryFileEx( + _In_ HANDLE FileHandle, + _In_ FILE_INFORMATION_CLASS FileInformationClass, + _In_ BOOLEAN ReturnSingleEntry, + _In_opt_ PUNICODE_STRING SearchPattern, + _In_ PPH_ENUM_DIRECTORY_FILE Callback, + _In_opt_ PVOID Context + ); + #define PH_FIRST_FILE_EA(Information) \ ((PFILE_FULL_EA_INFORMATION)(Information)) #define PH_NEXT_FILE_EA(Information) \ diff --git a/phlib/native.c b/phlib/native.c index f1f3395f80ac..57a40669b501 100644 --- a/phlib/native.c +++ b/phlib/native.c @@ -5172,6 +5172,25 @@ NTSTATUS PhEnumDirectoryFile( _In_ PPH_ENUM_DIRECTORY_FILE Callback, _In_opt_ PVOID Context ) +{ + return PhEnumDirectoryFileEx( + FileHandle, + FileDirectoryInformation, + FALSE, + SearchPattern, + Callback, + Context + ); +} + +NTSTATUS PhEnumDirectoryFileEx( + _In_ HANDLE FileHandle, + _In_ FILE_INFORMATION_CLASS FileInformationClass, + _In_ BOOLEAN ReturnSingleEntry, + _In_opt_ PUNICODE_STRING SearchPattern, + _In_ PPH_ENUM_DIRECTORY_FILE Callback, + _In_opt_ PVOID Context + ) { NTSTATUS status; IO_STATUS_BLOCK isb; @@ -5185,7 +5204,7 @@ NTSTATUS PhEnumDirectoryFile( while (TRUE) { - // Query the directory, doubling the buffer each time NtQueryDirectoryFile fails. + // Query the directory, doubling the buffer each time NtQueryDirectoryFile fails. (wj32) while (TRUE) { status = NtQueryDirectoryFile( @@ -5196,14 +5215,13 @@ NTSTATUS PhEnumDirectoryFile( &isb, buffer, bufferSize, - FileDirectoryInformation, - FALSE, + FileInformationClass, + ReturnSingleEntry, SearchPattern, firstTime ); - // Our ISB is on the stack, so we have to wait for the operation to complete before - // continuing. + // Our ISB is on the stack, so we have to wait for the operation to complete before continuing. (wj32) if (status == STATUS_PENDING) { status = NtWaitForSingleObject(FileHandle, FALSE, NULL); @@ -5224,7 +5242,7 @@ NTSTATUS PhEnumDirectoryFile( } } - // If we don't have any entries to read, exit. + // If we don't have any entries to read, exit. (wj32) if (status == STATUS_NO_MORE_FILES) { status = STATUS_SUCCESS; @@ -5234,21 +5252,19 @@ NTSTATUS PhEnumDirectoryFile( if (!NT_SUCCESS(status)) break; - // Read the batch and execute the callback function for each file. + // Read the batch and execute the callback function for each file. (wj32) i = 0; cont = TRUE; while (TRUE) { - PFILE_DIRECTORY_INFORMATION information; + PFILE_NAMES_INFORMATION information; - information = (PFILE_DIRECTORY_INFORMATION)PTR_ADD_OFFSET(buffer, i); + // HACK: Use the wrong structure for the NextEntryOffset. (dmex) + information = PTR_ADD_OFFSET(buffer, i); - if (!Callback( - information, - Context - )) + if (!Callback(information, Context)) { cont = FALSE; break; From 31747073a366494e1e463597dfb5508429948043 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 11 Jan 2019 23:46:44 +0100 Subject: [PATCH 1531/2058] Add PhOpenFileWin32/PhOpenFileWin32Ex --- phlib/include/phnative.h | 23 +++++++++++++ phlib/native.c | 73 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 95 insertions(+), 1 deletion(-) diff --git a/phlib/include/phnative.h b/phlib/include/phnative.h index 7ffc0db643a6..e4b8cb912886 100644 --- a/phlib/include/phnative.h +++ b/phlib/include/phnative.h @@ -1209,6 +1209,29 @@ PhCreateFileWin32Ex( _Out_opt_ PULONG CreateStatus ); +PHLIBAPI +NTSTATUS +NTAPI +PhOpenFileWin32( + _Out_ PHANDLE FileHandle, + _In_ PWSTR FileName, + _In_ ACCESS_MASK DesiredAccess, + _In_ ULONG ShareAccess, + _In_ ULONG CreateOptions + ); + +PHLIBAPI +NTSTATUS +NTAPI +PhOpenFileWin32Ex( + _Out_ PHANDLE FileHandle, + _In_ PWSTR FileName, + _In_ ACCESS_MASK DesiredAccess, + _In_ ULONG ShareAccess, + _In_ ULONG OpenOptions, + _Out_opt_ PULONG OpenStatus + ); + PHLIBAPI NTSTATUS NTAPI diff --git a/phlib/native.c b/phlib/native.c index 57a40669b501..fbc2f23a4149 100644 --- a/phlib/native.c +++ b/phlib/native.c @@ -3,7 +3,7 @@ * native wrapper and support functions * * Copyright (C) 2009-2016 wj32 - * Copyright (C) 2017 dmex + * Copyright (C) 2017-2019 dmex * * This file is part of Process Hacker. * @@ -6999,6 +6999,77 @@ NTSTATUS PhCreateFileWin32Ex( return status; } +NTSTATUS PhOpenFileWin32( + _Out_ PHANDLE FileHandle, + _In_ PWSTR FileName, + _In_ ACCESS_MASK DesiredAccess, + _In_ ULONG ShareAccess, + _In_ ULONG OpenOptions + ) +{ + return PhOpenFileWin32Ex( + FileHandle, + FileName, + DesiredAccess, + ShareAccess, + OpenOptions, + NULL + ); +} + +NTSTATUS PhOpenFileWin32Ex( + _Out_ PHANDLE FileHandle, + _In_ PWSTR FileName, + _In_ ACCESS_MASK DesiredAccess, + _In_ ULONG ShareAccess, + _In_ ULONG OpenOptions, + _Out_opt_ PULONG OpenStatus + ) +{ + NTSTATUS status; + HANDLE fileHandle; + UNICODE_STRING fileNameUs; + OBJECT_ATTRIBUTES objectAttributes; + IO_STATUS_BLOCK isb; + + if (!NT_SUCCESS(status = RtlDosPathNameToNtPathName_U_WithStatus( + FileName, + &fileNameUs, + NULL, + NULL + ))) + return status; + + InitializeObjectAttributes( + &objectAttributes, + &fileNameUs, + OBJ_CASE_INSENSITIVE, + NULL, + NULL + ); + + status = NtOpenFile( + &fileHandle, + DesiredAccess, + &objectAttributes, + &isb, + ShareAccess, + OpenOptions + ); + + RtlFreeUnicodeString(&fileNameUs); + + if (NT_SUCCESS(status)) + { + *FileHandle = fileHandle; + } + + if (OpenStatus) + *OpenStatus = (ULONG)isb.Information; + + return status; +} + /** * Queries file attributes. * From fdbd2bd5b3452e7818eeb3800db6d6237a5f8d51 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 11 Jan 2019 23:53:32 +0100 Subject: [PATCH 1532/2058] Update ACL editor with ISecurityInformation3 support --- phlib/include/seceditp.h | 42 +++++++++++++++ phlib/secedit.c | 110 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 150 insertions(+), 2 deletions(-) diff --git a/phlib/include/seceditp.h b/phlib/include/seceditp.h index f0a8db0b1c9c..84982aec14f5 100644 --- a/phlib/include/seceditp.h +++ b/phlib/include/seceditp.h @@ -27,9 +27,18 @@ typedef struct { ISecurityInformation2Vtbl *VTable; + PhSecurityInformation *Context; ULONG RefCount; } PhSecurityInformation2; +typedef struct +{ + ISecurityInformation3Vtbl *VTable; + + PhSecurityInformation *Context; + ULONG RefCount; +} PhSecurityInformation3; + typedef struct { IDataObjectVtbl *VTable; @@ -42,6 +51,8 @@ typedef struct PPH_LIST NameCache; } PhSecurityIDataObject; +// ISecurityInformation + ISecurityInformation *PhSecurityInformation_Create( _In_ HWND WindowHandle, _In_ PWSTR ObjectName, @@ -113,6 +124,8 @@ HRESULT STDMETHODCALLTYPE PhSecurityInformation_PropertySheetPageCallback( _In_ SI_PAGE_TYPE uPage ); +// ISecurityInformation2 + HRESULT STDMETHODCALLTYPE PhSecurityInformation2_QueryInterface( _In_ ISecurityInformation2 *This, _In_ REFIID Riid, @@ -139,6 +152,35 @@ HRESULT STDMETHODCALLTYPE PhSecurityInformation2_LookupSids( _Out_ LPDATAOBJECT *ppdo ); +// ISecurityInformation3 + +HRESULT STDMETHODCALLTYPE PhSecurityInformation3_QueryInterface( + _In_ ISecurityInformation3 *This, + _In_ REFIID Riid, + _Out_ PVOID *Object + ); + +ULONG STDMETHODCALLTYPE PhSecurityInformation3_AddRef( + _In_ ISecurityInformation3 *This + ); + +ULONG STDMETHODCALLTYPE PhSecurityInformation3_Release( + _In_ ISecurityInformation3 *This + ); + +BOOL STDMETHODCALLTYPE PhSecurityInformation3_GetFullResourceName( + _In_ ISecurityInformation3 *This, + _Outptr_ PWSTR *ppszResourceName + ); + +HRESULT STDMETHODCALLTYPE PhSecurityInformation3_OpenElevatedEditor( + _In_ ISecurityInformation3 *This, + _In_ HWND hWnd, + _In_ SI_PAGE_TYPE uPage + ); + +// IDataObject + HRESULT STDMETHODCALLTYPE PhSecurityDataObject_QueryInterface( _In_ IDataObject *This, _In_ REFIID Riid, diff --git a/phlib/secedit.c b/phlib/secedit.c index 3b24bb2ac07a..83f482696cc8 100644 --- a/phlib/secedit.c +++ b/phlib/secedit.c @@ -3,7 +3,7 @@ * object security editor * * Copyright (C) 2010-2016 wj32 - * Copyright (C) 2017-2018 dmex + * Copyright (C) 2017-2019 dmex * * This file is part of Process Hacker. * @@ -54,6 +54,15 @@ static ISecurityInformation2Vtbl PhSecurityInformation_VTable2 = PhSecurityInformation2_LookupSids }; +static ISecurityInformation3Vtbl PhSecurityInformation_VTable3 = +{ + PhSecurityInformation3_QueryInterface, + PhSecurityInformation3_AddRef, + PhSecurityInformation3_Release, + PhSecurityInformation3_GetFullResourceName, + PhSecurityInformation3_OpenElevatedEditor +}; + static IDataObjectVtbl PhDataObject_VTable = { PhSecurityDataObject_QueryInterface, @@ -111,6 +120,8 @@ static NTSTATUS PhpEditSecurityInformationThread( { PhSecurityInformation *this = (PhSecurityInformation *)Context; + // The EditSecurityAdvanced function on Windows 7 doesn't handle the SI_PAGE_TYPE + // parameter correctly and also doesn't show the Audit and Owner tabs... (dmex) if (WindowsVersion >= WINDOWS_8 && PhGetIntegerSetting(L"EnableSecurityAdvancedDialog")) EditSecurityAdvanced(this->WindowHandle, Context, COMBINE_PAGE_ACTIVATION(SI_PAGE_PERM, SI_SHOW_PERM_ACTIVATED)); else @@ -202,6 +213,8 @@ HRESULT STDMETHODCALLTYPE PhSecurityInformation_QueryInterface( _Out_ PVOID *Object ) { + PhSecurityInformation *this = (PhSecurityInformation *)This; + if ( IsEqualIID(Riid, &IID_IUnknown) || IsEqualIID(Riid, &IID_ISecurityInformation) @@ -219,6 +232,22 @@ HRESULT STDMETHODCALLTYPE PhSecurityInformation_QueryInterface( info = PhAllocateZero(sizeof(PhSecurityInformation2)); info->VTable = &PhSecurityInformation_VTable2; + info->Context = this; + info->RefCount = 1; + + *Object = info; + return S_OK; + } + } + else if (IsEqualGUID(Riid, &IID_ISecurityInformation3)) + { + if (WindowsVersion >= WINDOWS_8) + { + PhSecurityInformation3 *info; + + info = PhAllocateZero(sizeof(PhSecurityInformation3)); + info->VTable = &PhSecurityInformation_VTable3; + info->Context = this; info->RefCount = 1; *Object = info; @@ -279,7 +308,7 @@ HRESULT STDMETHODCALLTYPE PhSecurityInformation_GetObjectInformation( PhSecurityInformation *this = (PhSecurityInformation *)This; memset(ObjectInfo, 0, sizeof(SI_OBJECT_INFO)); - ObjectInfo->dwFlags = SI_EDIT_ALL | SI_ADVANCED | SI_MAY_WRITE; + ObjectInfo->dwFlags = SI_EDIT_ALL | SI_ADVANCED | (WindowsVersion >= WINDOWS_8 ? SI_VIEW_ONLY : 0); ObjectInfo->pszObjectName = PhGetString(this->ObjectName); if (PhEqualString2(this->ObjectType, L"TokenDefault", TRUE)) @@ -401,6 +430,8 @@ HRESULT STDMETHODCALLTYPE PhSecurityInformation_PropertySheetPageCallback( return E_NOTIMPL; } +// ISecurityInformation2 + HRESULT STDMETHODCALLTYPE PhSecurityInformation2_QueryInterface( _In_ ISecurityInformation2 *This, _In_ REFIID Riid, @@ -479,6 +510,81 @@ HRESULT STDMETHODCALLTYPE PhSecurityInformation2_LookupSids( return S_OK; } +// ISecurityInformation3 + +HRESULT STDMETHODCALLTYPE PhSecurityInformation3_QueryInterface( + _In_ ISecurityInformation3 *This, + _In_ REFIID Riid, + _Out_ PVOID *Object + ) +{ + if ( + IsEqualIID(Riid, &IID_IUnknown) || + IsEqualIID(Riid, &IID_ISecurityInformation3) + ) + { + PhSecurityInformation3_AddRef(This); + *Object = This; + return S_OK; + } + + *Object = NULL; + return E_NOINTERFACE; +} + +ULONG STDMETHODCALLTYPE PhSecurityInformation3_AddRef( + _In_ ISecurityInformation3 *This + ) +{ + PhSecurityInformation3 *this = (PhSecurityInformation3 *)This; + + this->RefCount++; + + return this->RefCount; +} + +ULONG STDMETHODCALLTYPE PhSecurityInformation3_Release( + _In_ ISecurityInformation3 *This + ) +{ + PhSecurityInformation3 *this = (PhSecurityInformation3 *)This; + + this->RefCount--; + + if (this->RefCount == 0) + { + PhFree(this); + return 0; + } + + return this->RefCount; +} + +BOOL STDMETHODCALLTYPE PhSecurityInformation3_GetFullResourceName( + _In_ ISecurityInformation3 *This, + _Outptr_ PWSTR *ppszResourceName + ) +{ + PhSecurityInformation3 *this = (PhSecurityInformation3 *)This; + + *ppszResourceName = PhGetString(this->Context->ObjectName); + + return TRUE; +} + +HRESULT STDMETHODCALLTYPE PhSecurityInformation3_OpenElevatedEditor( + _In_ ISecurityInformation3 *This, + _In_ HWND hWnd, + _In_ SI_PAGE_TYPE uPage + ) +{ + PhSecurityInformation3 *this = (PhSecurityInformation3 *)This; + + return E_NOTIMPL; +} + +// IDataObject + HRESULT STDMETHODCALLTYPE PhSecurityDataObject_QueryInterface( _In_ IDataObject *This, _In_ REFIID Riid, From 422e450fd6af251f4f49c172b625d32a7149bdb8 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 12 Jan 2019 00:30:35 +0100 Subject: [PATCH 1533/2058] WindowExplorer: Fix window placement settings --- plugins/WindowExplorer/resource.h | 1 - plugins/WindowExplorer/wnddlg.c | 125 ++++++++++++++++++++---------- plugins/WindowExplorer/wndprp.c | 18 ++--- 3 files changed, 93 insertions(+), 51 deletions(-) diff --git a/plugins/WindowExplorer/resource.h b/plugins/WindowExplorer/resource.h index 290c8f6f3502..4aff5e6f63cc 100644 --- a/plugins/WindowExplorer/resource.h +++ b/plugins/WindowExplorer/resource.h @@ -12,7 +12,6 @@ #define IDD_WNDGENERAL 104 #define ID_VIEW_DESKTOPWINDOWS 105 #define IDD_WNDPROPLIST 105 -#define IDC_COPY 106 #define IDC_LIST 1001 #define IDC_REFRESH 1002 #define IDC_SEARCHEDIT 1035 diff --git a/plugins/WindowExplorer/wnddlg.c b/plugins/WindowExplorer/wnddlg.c index 5a13d14169d0..281e248cb24e 100644 --- a/plugins/WindowExplorer/wnddlg.c +++ b/plugins/WindowExplorer/wnddlg.c @@ -36,10 +36,6 @@ typedef struct _WINDOWS_CONTEXT ULONG HighlightingWindowCount; } WINDOWS_CONTEXT, *PWINDOWS_CONTEXT; -VOID WepShowWindowsDialogCallback( - _In_ PVOID Parameter - ); - INT_PTR CALLBACK WepWindowsDlgProc( _In_ HWND hwndDlg, _In_ UINT uMsg, @@ -54,17 +50,79 @@ INT_PTR CALLBACK WepWindowsPageProc( _In_ LPARAM lParam ); +HWND WepWindowsDialogHandle = NULL; +HANDLE WepWindowsDialogThreadHandle = NULL; +PH_EVENT WepWindowsInitializedEvent = PH_EVENT_INIT; +PH_STRINGREF WepEmptyWindowsText = PH_STRINGREF_INIT(L"There are no windows to display."); +#define PH_SHOWDIALOG (WM_APP + 501) + +NTSTATUS WepShowWindowsDialogThread( + _In_ PVOID Parameter + ) +{ + BOOL result; + MSG message; + PH_AUTO_POOL autoPool; + + PhInitializeAutoPool(&autoPool); + + WepWindowsDialogHandle = CreateDialogParam( + PluginInstance->DllBase, + MAKEINTRESOURCE(IDD_WNDLIST), + NULL, + WepWindowsDlgProc, + (LPARAM)Parameter + ); + + PhSetEvent(&WepWindowsInitializedEvent); + + while (result = GetMessage(&message, NULL, 0, 0)) + { + if (result == -1) + break; + + if (!IsDialogMessage(WepWindowsDialogHandle, &message)) + { + TranslateMessage(&message); + DispatchMessage(&message); + } + + PhDrainAutoPool(&autoPool); + } + + PhDeleteAutoPool(&autoPool); + PhResetEvent(&WepWindowsInitializedEvent); + + NtClose(WepWindowsDialogThreadHandle); + WepWindowsDialogThreadHandle = NULL; + WepWindowsDialogHandle = NULL; + + return STATUS_SUCCESS; +} + VOID WeShowWindowsDialog( _In_ HWND ParentWindowHandle, _In_ PWE_WINDOW_SELECTOR Selector ) { - PWINDOWS_CONTEXT context; + if (!WepWindowsDialogThreadHandle) + { + PWINDOWS_CONTEXT context; - context = PhAllocateZero(sizeof(WINDOWS_CONTEXT)); - memcpy(&context->Selector, Selector, sizeof(WE_WINDOW_SELECTOR)); + context = PhAllocateZero(sizeof(WINDOWS_CONTEXT)); + memcpy(&context->Selector, Selector, sizeof(WE_WINDOW_SELECTOR)); + + if (!(WepWindowsDialogThreadHandle = PhCreateThread(0, WepShowWindowsDialogThread, context))) + { + PhFree(context); + PhShowStatus(NULL, L"Unable to create the window.", 0, GetLastError()); + return; + } + + PhWaitForEvent(&WepWindowsInitializedEvent, NULL); + } - ProcessHacker_Invoke(WE_PhMainWndHandle, WepShowWindowsDialogCallback, context); + PostMessage(WepWindowsDialogHandle, PH_SHOWDIALOG, 0, 0); } VOID WeShowWindowsPropPage( @@ -83,23 +141,6 @@ VOID WeShowWindowsPropPage( ); } -VOID WepShowWindowsDialogCallback( - _In_ PVOID Parameter - ) -{ - HWND hwnd; - PWINDOWS_CONTEXT context = Parameter; - - hwnd = CreateDialogParam( - PluginInstance->DllBase, - MAKEINTRESOURCE(IDD_WNDLIST), - NULL, - WepWindowsDlgProc, - (LPARAM)context - ); - ShowWindow(hwnd, SW_SHOW); -} - VOID WepDeleteWindowSelector( _In_ PWE_WINDOW_SELECTOR Selector ) @@ -375,8 +416,6 @@ INT_PTR CALLBACK WepWindowsDlgProc( { case WM_INITDIALOG: { - PH_RECTANGLE windowRectangle; - SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(WE_PhInstanceHandle, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(WE_PhInstanceHandle, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); @@ -387,6 +426,7 @@ INT_PTR CALLBACK WepWindowsDlgProc( PhCreateSearchControl(hwndDlg, context->SearchBoxHandle, L"Search Windows (Ctrl+K)"); WeInitializeWindowTree(hwndDlg, context->TreeNewHandle, &context->TreeContext); + TreeNew_SetEmptyText(context->TreeNewHandle, &WepEmptyWindowsText, 0); PhRegisterDialog(hwndDlg); @@ -394,22 +434,13 @@ INT_PTR CALLBACK WepWindowsDlgProc( PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_SEARCHEDIT), NULL, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_LIST), NULL, PH_ANCHOR_ALL); - // Set up the window position and size. - windowRectangle.Position = PhGetIntegerPairSetting(SETTING_NAME_WINDOWS_WINDOW_POSITION); - windowRectangle.Size = PhGetScalableIntegerPairSetting(SETTING_NAME_WINDOWS_WINDOW_SIZE, TRUE).Pair; - PhAdjustRectangleToWorkingArea(NULL, &windowRectangle); - - MoveWindow(hwndDlg, windowRectangle.Left, windowRectangle.Top, windowRectangle.Width, windowRectangle.Height, FALSE); - - // Implement cascading by saving an offsetted rectangle. - windowRectangle.Left += 20; - windowRectangle.Top += 20; - PhSetIntegerPairSetting(SETTING_NAME_WINDOWS_WINDOW_POSITION, windowRectangle.Position); + if (PhGetIntegerPairSetting(SETTING_NAME_WINDOWS_WINDOW_POSITION).X != 0) + PhLoadWindowPlacementFromSetting(SETTING_NAME_WINDOWS_WINDOW_POSITION, SETTING_NAME_WINDOWS_WINDOW_SIZE, hwndDlg); + else + PhCenterWindow(hwndDlg, WE_PhMainWndHandle); WepRefreshWindows(context); - // HACK - //PhSetDialogFocus(GetParent(hwndDlg), GetDlgItem(GetParent(hwndDlg), IDCANCEL)); PhSetDialogFocus(hwndDlg, context->TreeNewHandle); PhInitializeWindowTheme(hwndDlg, !!PhGetIntegerSetting(L"EnableThemeSupport")); @@ -426,6 +457,18 @@ INT_PTR CALLBACK WepWindowsDlgProc( WeDeleteWindowTree(&context->TreeContext); WepDeleteWindowSelector(&context->Selector); PhFree(context); + + PostQuitMessage(0); + } + break; + case PH_SHOWDIALOG: + { + if (IsMinimized(hwndDlg)) + ShowWindow(hwndDlg, SW_RESTORE); + else + ShowWindow(hwndDlg, SW_SHOW); + + SetForegroundWindow(hwndDlg); } break; case WM_COMMAND: @@ -845,8 +888,8 @@ INT_PTR CALLBACK WepWindowsPageProc( context->SearchBoxHandle = GetDlgItem(hwndDlg, IDC_SEARCHEDIT); PhCreateSearchControl(hwndDlg, context->SearchBoxHandle, L"Search Windows (Ctrl+K)"); - WeInitializeWindowTree(hwndDlg, context->TreeNewHandle, &context->TreeContext); + TreeNew_SetEmptyText(context->TreeNewHandle, &WepEmptyWindowsText, 0); PhInitializeLayoutManager(&context->LayoutManager, hwndDlg); PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_SEARCHEDIT), NULL, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); diff --git a/plugins/WindowExplorer/wndprp.c b/plugins/WindowExplorer/wndprp.c index 27b037b1b7b4..ba92075ae634 100644 --- a/plugins/WindowExplorer/wndprp.c +++ b/plugins/WindowExplorer/wndprp.c @@ -912,8 +912,8 @@ INT_PTR CALLBACK WepWindowGeneralDlgProc( { menu = PhCreateEMenu(); - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, IDC_COPY, L"&Copy", NULL, NULL), ULONG_MAX); - PhInsertCopyListViewEMenuItem(menu, IDC_COPY, listViewHandle); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, PHAPP_IDC_COPY, L"&Copy", NULL, NULL), ULONG_MAX); + PhInsertCopyListViewEMenuItem(menu, PHAPP_IDC_COPY, listViewHandle); item = PhShowEMenu( menu, @@ -930,7 +930,7 @@ INT_PTR CALLBACK WepWindowGeneralDlgProc( { switch (item->Id) { - case IDC_COPY: + case PHAPP_IDC_COPY: { PhCopyListView(listViewHandle); } @@ -1139,8 +1139,8 @@ INT_PTR CALLBACK WepWindowPropertiesDlgProc( { menu = PhCreateEMenu(); - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, IDC_COPY, L"&Copy", NULL, NULL), ULONG_MAX); - PhInsertCopyListViewEMenuItem(menu, IDC_COPY, listViewHandle); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, PHAPP_IDC_COPY, L"&Copy", NULL, NULL), ULONG_MAX); + PhInsertCopyListViewEMenuItem(menu, PHAPP_IDC_COPY, listViewHandle); item = PhShowEMenu( menu, @@ -1157,7 +1157,7 @@ INT_PTR CALLBACK WepWindowPropertiesDlgProc( { switch (item->Id) { - case IDC_COPY: + case PHAPP_IDC_COPY: { PhCopyListView(listViewHandle); } @@ -1334,8 +1334,8 @@ INT_PTR CALLBACK WepWindowPropStoreDlgProc( { menu = PhCreateEMenu(); - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, IDC_COPY, L"&Copy", NULL, NULL), ULONG_MAX); - PhInsertCopyListViewEMenuItem(menu, IDC_COPY, listViewHandle); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, PHAPP_IDC_COPY, L"&Copy", NULL, NULL), ULONG_MAX); + PhInsertCopyListViewEMenuItem(menu, PHAPP_IDC_COPY, listViewHandle); item = PhShowEMenu( menu, @@ -1352,7 +1352,7 @@ INT_PTR CALLBACK WepWindowPropStoreDlgProc( { switch (item->Id) { - case IDC_COPY: + case PHAPP_IDC_COPY: { PhCopyListView(listViewHandle); } From 6032f8896777e209b6139cf76b2456eafb07bb56 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 12 Jan 2019 06:05:06 +0100 Subject: [PATCH 1534/2058] Add dark window frame support for dark theme (RS5 and above) --- phlib/theme.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/phlib/theme.c b/phlib/theme.c index 65767bf15381..173b7e7d0ed7 100644 --- a/phlib/theme.c +++ b/phlib/theme.c @@ -160,6 +160,19 @@ VOID PhInitializeWindowTheme( SetWindowLongPtr(WindowHandle, GWLP_WNDPROC, (LONG_PTR)PhpThemeWindowSubclassProc); } + // Enable dark window frame support (undocumented RS5 feature). + switch (PhpThemeColorMode) + { + case 0: // New colors + if (WindowsVersion >= WINDOWS_10_RS5) + RemoveProp(WindowHandle, L"UseImmersiveDarkModeColors"); + break; + case 1: // Old colors + if (WindowsVersion >= WINDOWS_10_RS5) + SetProp(WindowHandle, L"UseImmersiveDarkModeColors", (HANDLE)TRUE); + break; + } + PhEnumChildWindows( WindowHandle, 0x1000, @@ -198,9 +211,13 @@ VOID PhReInitializeWindowTheme( { case 0: // New colors PhMenuBackgroundBrush = CreateSolidBrush(PhpThemeWindowTextColor); + if (WindowsVersion >= WINDOWS_10_RS5) + RemoveProp(WindowHandle, L"UseImmersiveDarkModeColors"); break; case 1: // Old colors PhMenuBackgroundBrush = CreateSolidBrush(PhpThemeWindowForegroundColor); + if (WindowsVersion >= WINDOWS_10_RS5) + SetProp(WindowHandle, L"UseImmersiveDarkModeColors", (HANDLE)TRUE); break; } } From e19a5a41164e5220608eca26940cc21e5c5f5de5 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 13 Jan 2019 15:45:09 +0100 Subject: [PATCH 1535/2058] Fix environment tab memory leak --- ProcessHacker/appsup.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/ProcessHacker/appsup.c b/ProcessHacker/appsup.c index 717baec1e489..3de62015cd66 100644 --- a/ProcessHacker/appsup.c +++ b/ProcessHacker/appsup.c @@ -76,18 +76,21 @@ BOOLEAN PhIsProcessSuspended( _In_ HANDLE ProcessId ) { + BOOLEAN suspended = FALSE; PVOID processes; PSYSTEM_PROCESS_INFORMATION process; if (NT_SUCCESS(PhEnumProcesses(&processes))) { if (process = PhFindProcessInformation(processes, ProcessId)) - return PhGetProcessIsSuspended(process); + { + suspended = PhGetProcessIsSuspended(process); + } PhFree(processes); } - return FALSE; + return suspended; } /** From da9c09a87d7bf4659ea2782012f0a4c3b6261d15 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 13 Jan 2019 15:45:51 +0100 Subject: [PATCH 1536/2058] Update find handle regex error dialog --- ProcessHacker/findobj.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ProcessHacker/findobj.c b/ProcessHacker/findobj.c index 9f5dca981a6e..c58da2edebbd 100644 --- a/ProcessHacker/findobj.c +++ b/ProcessHacker/findobj.c @@ -1331,7 +1331,7 @@ INT_PTR CALLBACK PhpFindObjectsDlgProc( if (!context->SearchRegexCompiledExpression) { - PhShowError(hwndDlg, L"Unable to compile the regular expression: \"%s\" at position %zu.", + PhShowError2(hwndDlg, L"Unable to compile the regular expression.", L"\"%s\" at position %zu.", PhGetStringOrDefault(PH_AUTO(PhPcre2GetErrorMessage(errorCode)), L"Unknown error"), errorOffset ); From e19868c1804c593d31ac542747ee3a23a88296df Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 13 Jan 2019 18:15:16 +0100 Subject: [PATCH 1537/2058] ToolStatus: Add toolbar graph plugin support --- plugins/ToolStatus/ToolStatus.rc | 21 - plugins/ToolStatus/graph.c | 868 +++++++++++++++++++------------ plugins/ToolStatus/main.c | 118 ++--- plugins/ToolStatus/statusbar.c | 1 - plugins/ToolStatus/toolbar.c | 8 +- plugins/ToolStatus/toolstatus.h | 94 +++- 6 files changed, 648 insertions(+), 462 deletions(-) diff --git a/plugins/ToolStatus/ToolStatus.rc b/plugins/ToolStatus/ToolStatus.rc index 70c45351bb40..44efe09f0530 100644 --- a/plugins/ToolStatus/ToolStatus.rc +++ b/plugins/ToolStatus/ToolStatus.rc @@ -213,27 +213,6 @@ IDB_FIND_MODERN PNG "resources\\find_modern.png" IDB_POWER_MODERN PNG "resources\\lightbulb_off_modern.png" -///////////////////////////////////////////////////////////////////////////// -// -// AFX_DIALOG_LAYOUT -// - -IDD_OPTIONS AFX_DIALOG_LAYOUT -BEGIN - 0 -END - -IDD_CUSTOMIZE_TB AFX_DIALOG_LAYOUT -BEGIN - 0 -END - -IDD_CUSTOMIZE_SB AFX_DIALOG_LAYOUT -BEGIN - 0 -END - - ///////////////////////////////////////////////////////////////////////////// // // Icon diff --git a/plugins/ToolStatus/graph.c b/plugins/ToolStatus/graph.c index c4c54d8e3c10..964705aad56b 100644 --- a/plugins/ToolStatus/graph.c +++ b/plugins/ToolStatus/graph.c @@ -2,7 +2,7 @@ * Process Hacker ToolStatus - * Toolbar Graph Bands * - * Copyright (C) 2015-2016 dmex + * Copyright (C) 2015-2019 dmex * * This file is part of Process Hacker. * @@ -22,82 +22,183 @@ #include "toolstatus.h" -HWND CpuGraphHandle = NULL; -HWND MemGraphHandle = NULL; -HWND CommitGraphHandle = NULL; -HWND IoGraphHandle = NULL; -static PH_GRAPH_STATE CpuGraphState; -static PH_GRAPH_STATE MemGraphState; -static PH_GRAPH_STATE CommitGraphState; -static PH_GRAPH_STATE IoGraphState; +PPH_LIST PhpToolbarGraphList = NULL; +PPH_HASHTABLE PhpToolbarGraphHashtable = NULL; -VOID ToolbarCreateGraphs(VOID) +TOOLSTATUS_GRAPH_MESSAGE_CALLBACK_DECLARE(CpuHistoryGraphMessageCallback); +TOOLSTATUS_GRAPH_MESSAGE_CALLBACK_DECLARE(PhysicalHistoryGraphMessageCallback); +TOOLSTATUS_GRAPH_MESSAGE_CALLBACK_DECLARE(CommitHistoryGraphMessageCallback); +TOOLSTATUS_GRAPH_MESSAGE_CALLBACK_DECLARE(IoHistoryGraphMessageCallback); + +VOID ToolbarGraphLoadSettings( + VOID + ) { - UINT height = (UINT)SendMessage(RebarHandle, RB_GETROWHEIGHT, 0, 0); + PPH_STRING settingsString; + PH_STRINGREF remaining; - if (ToolStatusConfig.CpuGraphEnabled && !CpuGraphHandle) - { - CpuGraphHandle = CreateWindow( - PH_GRAPH_CLASSNAME, - NULL, - WS_VISIBLE | WS_CHILD | WS_BORDER, - 0, - 0, - 0, - 0, - PhMainWndHandle, - NULL, - NULL, - NULL - ); - Graph_SetTooltip(CpuGraphHandle, TRUE); + settingsString = PhGetStringSetting(SETTING_NAME_TOOLBAR_GRAPH_CONFIG); + remaining = settingsString->sr; - PhInitializeGraphState(&CpuGraphState); - } + if (remaining.Length == 0) + return; - if (ToolStatusConfig.MemGraphEnabled && !MemGraphHandle) + while (remaining.Length != 0) { - MemGraphHandle = CreateWindow( - PH_GRAPH_CLASSNAME, - NULL, - WS_VISIBLE | WS_CHILD | WS_BORDER, - 0, - 0, - 0, - 0, - PhMainWndHandle, - NULL, - NULL, - NULL - ); - Graph_SetTooltip(MemGraphHandle, TRUE); + PH_STRINGREF idPart; + PH_STRINGREF flagsPart; + PH_STRINGREF pluginNamePart; + ULONG64 idInteger; + ULONG64 flagsInteger; + + PhSplitStringRefAtChar(&remaining, '|', &idPart, &remaining); + PhSplitStringRefAtChar(&remaining, '|', &flagsPart, &remaining); + PhSplitStringRefAtChar(&remaining, '|', &pluginNamePart, &remaining); + + if (!PhStringToInteger64(&idPart, 10, &idInteger)) + break; + if (!PhStringToInteger64(&flagsPart, 10, &flagsInteger)) + break; + + if (flagsInteger) + { + PPH_TOOLBAR_GRAPH graph; - PhInitializeGraphState(&MemGraphState); + if (pluginNamePart.Length) + { + if (graph = ToolbarGraphFindByName(&pluginNamePart, (ULONG)idInteger)) + graph->Flags |= TOOLSTATUS_GRAPH_ENABLED; + } + else + { + if (graph = ToolbarGraphFindById((ULONG)idInteger)) + graph->Flags |= TOOLSTATUS_GRAPH_ENABLED; + } + } } - if (ToolStatusConfig.CommitGraphEnabled && !CommitGraphHandle) + PhDereferenceObject(settingsString); +} + +VOID ToolbarGraphSaveSettings( + VOID + ) +{ + PPH_STRING settingsString; + PH_STRING_BUILDER graphListBuilder; + + PhInitializeStringBuilder(&graphListBuilder, 100); + + for (ULONG i = 0; i < PhpToolbarGraphList->Count; i++) { - CommitGraphHandle = CreateWindow( - PH_GRAPH_CLASSNAME, - NULL, - WS_VISIBLE | WS_CHILD | WS_BORDER, - 0, - 0, - 0, - 0, - PhMainWndHandle, - NULL, - NULL, - NULL + PPH_TOOLBAR_GRAPH graph = PhpToolbarGraphList->Items[i]; + PPH_STRING pluginName; + + if (!(graph->Flags & TOOLSTATUS_GRAPH_ENABLED)) + continue; + + pluginName = PhGetPluginName(graph->Plugin); + PhAppendFormatStringBuilder( + &graphListBuilder, + L"%lu|%lu|%s|", + graph->GraphId, + graph->Flags & TOOLSTATUS_GRAPH_ENABLED ? 1 : 0, + graph->Plugin ? pluginName->Buffer : L"" ); - Graph_SetTooltip(CommitGraphHandle, TRUE); + PhDereferenceObject(pluginName); + } - PhInitializeGraphState(&CommitGraphState); + if (graphListBuilder.String->Length != 0) + PhRemoveEndStringBuilder(&graphListBuilder, 1); + + settingsString = PhFinalStringBuilderString(&graphListBuilder); + PhSetStringSetting2(SETTING_NAME_TOOLBAR_GRAPH_CONFIG, &settingsString->sr); + PhDereferenceObject(settingsString); +} + +VOID ToolbarGraphsInitialize( + VOID + ) +{ + if (!PhpToolbarGraphList) + { + PhpToolbarGraphList = PhCreateList(10); + PhpToolbarGraphHashtable = PhCreateSimpleHashtable(10); } - if (ToolStatusConfig.IoGraphEnabled && !IoGraphHandle) + ToolbarRegisterGraph( + PluginInstance, + 1, + L"CPU history", + 0, + NULL, + CpuHistoryGraphMessageCallback + ); + + ToolbarRegisterGraph( + PluginInstance, + 2, + L"Physical memory history", + 0, + NULL, + PhysicalHistoryGraphMessageCallback + ); + + ToolbarRegisterGraph( + PluginInstance, + 3, + L"Commit charge history", + 0, + NULL, + CommitHistoryGraphMessageCallback + ); + + ToolbarRegisterGraph( + PluginInstance, + 4, + L"I/O history", + 0, + NULL, + IoHistoryGraphMessageCallback + ); +} + +VOID ToolbarRegisterGraph( + _In_ struct _PH_PLUGIN *Plugin, + _In_ ULONG Id, + _In_ PWSTR Text, + _In_ ULONG Flags, + _In_opt_ PVOID Context, + _In_opt_ PTOOLSTATUS_GRAPH_MESSAGE_CALLBACK MessageCallback + ) +{ + PPH_TOOLBAR_GRAPH graph; + //PPH_STRING pluginName; + + graph = PhAllocateZero(sizeof(PH_TOOLBAR_GRAPH)); + graph->Plugin = Plugin; + graph->Text = Text; + graph->Flags = Flags; + graph->Context = Context; + graph->MessageCallback = MessageCallback; + graph->GraphId = 1000 + Id; + + //pluginName = PhGetPluginName(graph->Plugin); + //graph->GraphId = (PhHashStringRef(&pluginName->sr, TRUE) & 0xFFFF) + Id; + //PhDereferenceObject(pluginName); + + PhAddItemList(PhpToolbarGraphList, graph); +} + +BOOLEAN ToolbarAddGraph( + _In_ PPH_TOOLBAR_GRAPH Graph + ) +{ + if (!Graph->GraphHandle) { - IoGraphHandle = CreateWindow( + UINT rebarHeight = (UINT)SendMessage(RebarHandle, RB_GETROWHEIGHT, 0, 0); + + if (Graph->GraphHandle = CreateWindow( PH_GRAPH_CLASSNAME, NULL, WS_VISIBLE | WS_CHILD | WS_BORDER, @@ -105,151 +206,219 @@ VOID ToolbarCreateGraphs(VOID) 0, 0, 0, - PhMainWndHandle, + RebarHandle, NULL, NULL, NULL - ); - Graph_SetTooltip(IoGraphHandle, TRUE); + )) + { + Graph_SetTooltip(Graph->GraphHandle, TRUE); + PhInitializeGraphState(&Graph->GraphState); + + PhAddItemSimpleHashtable(PhpToolbarGraphHashtable, Graph->GraphHandle, Graph); - PhInitializeGraphState(&IoGraphState); + if (!RebarBandExists(Graph->GraphId)) + RebarBandInsert(Graph->GraphId, Graph->GraphHandle, 145, rebarHeight); // height: 85 + + if (!IsWindowVisible(Graph->GraphHandle)) + ShowWindow(Graph->GraphHandle, SW_SHOW); + } } - if (ToolStatusConfig.CpuGraphEnabled) + return TRUE; +} + +BOOLEAN ToolbarRemoveGraph( + _In_ PPH_TOOLBAR_GRAPH Graph + ) +{ + if (RebarBandExists(Graph->GraphId)) + RebarBandRemove(Graph->GraphId); + + if (Graph->GraphHandle) { - if (!RebarBandExists(REBAR_BAND_ID_CPUGRAPH)) - RebarBandInsert(REBAR_BAND_ID_CPUGRAPH, CpuGraphHandle, 145, height); // 85 + PhRemoveItemSimpleHashtable(PhpToolbarGraphHashtable, Graph->GraphHandle); + + PhDeleteGraphState(&Graph->GraphState); - if (CpuGraphHandle && !IsWindowVisible(CpuGraphHandle)) - ShowWindow(CpuGraphHandle, SW_SHOW); + DestroyWindow(Graph->GraphHandle); + Graph->GraphHandle = NULL; } - else + + return TRUE; +} + +VOID ToolbarCreateGraphs( + VOID + ) +{ + ToolbarGraphLoadSettings(); + + for (ULONG i = 0; i < PhpToolbarGraphList->Count; i++) { - if (RebarBandExists(REBAR_BAND_ID_CPUGRAPH)) - RebarBandRemove(REBAR_BAND_ID_CPUGRAPH); + PPH_TOOLBAR_GRAPH graph = PhpToolbarGraphList->Items[i]; - if (CpuGraphHandle) - { - PhDeleteGraphState(&CpuGraphState); + if (!(graph->Flags & TOOLSTATUS_GRAPH_ENABLED)) + continue; - DestroyWindow(CpuGraphHandle); - CpuGraphHandle = NULL; - } + ToolbarAddGraph(graph); } +} - if (ToolStatusConfig.MemGraphEnabled) +VOID ToolbarUpdateGraphs( + VOID + ) +{ + for (ULONG i = 0; i < PhpToolbarGraphList->Count; i++) { - if (!RebarBandExists(REBAR_BAND_ID_MEMGRAPH)) - RebarBandInsert(REBAR_BAND_ID_MEMGRAPH, MemGraphHandle, 145, height); // 85 + PPH_TOOLBAR_GRAPH graph = PhpToolbarGraphList->Items[i]; - if (MemGraphHandle && !IsWindowVisible(MemGraphHandle)) - { - ShowWindow(MemGraphHandle, SW_SHOW); - } + if (!(graph->Flags & TOOLSTATUS_GRAPH_ENABLED)) + continue; + + graph->GraphState.Valid = FALSE; + graph->GraphState.TooltipIndex = ULONG_MAX; + Graph_MoveGrid(graph->GraphHandle, 1); + Graph_Draw(graph->GraphHandle); + Graph_UpdateTooltip(graph->GraphHandle); + InvalidateRect(graph->GraphHandle, NULL, FALSE); } - else - { - if (RebarBandExists(REBAR_BAND_ID_MEMGRAPH)) - RebarBandRemove(REBAR_BAND_ID_MEMGRAPH); +} - if (MemGraphHandle) +BOOLEAN ToolbarUpdateGraphsInfo( + _In_ LPNMHDR Header + ) +{ + PPH_TOOLBAR_GRAPH graph; + + if (graph = PhFindItemSimpleHashtable2(PhpToolbarGraphHashtable, Header->hwndFrom)) + { + if (Header->code == GCN_MOUSEEVENT) // HACK { - PhDeleteGraphState(&MemGraphState); + PPH_GRAPH_MOUSEEVENT mouseEvent = (PPH_GRAPH_MOUSEEVENT)Header; - DestroyWindow(MemGraphHandle); - MemGraphHandle = NULL; + if (mouseEvent->Message == WM_RBUTTONUP) + { + ShowCustomizeMenu(); + } } + + graph->MessageCallback(graph, graph->GraphHandle, &graph->GraphState, Header, NULL); + return TRUE; } - if (ToolStatusConfig.CommitGraphEnabled) - { - if (!RebarBandExists(REBAR_BAND_ID_COMMITGRAPH)) - RebarBandInsert(REBAR_BAND_ID_COMMITGRAPH, CommitGraphHandle, 145, height); // 85 + return FALSE; +} - if (CommitGraphHandle && !IsWindowVisible(CommitGraphHandle)) - { - ShowWindow(CommitGraphHandle, SW_SHOW); - } +VOID ToolbarSetVisibleGraph( + _In_ PPH_TOOLBAR_GRAPH Graph, + _In_ BOOLEAN Visible + ) +{ + if (Visible) + { + Graph->Flags |= TOOLSTATUS_GRAPH_ENABLED; + ToolbarAddGraph(Graph); } else { - if (RebarBandExists(REBAR_BAND_ID_COMMITGRAPH)) - RebarBandRemove(REBAR_BAND_ID_COMMITGRAPH); + Graph->Flags &= ~TOOLSTATUS_GRAPH_ENABLED; + ToolbarRemoveGraph(Graph); + } +} - if (CommitGraphHandle) - { - PhDeleteGraphState(&CommitGraphState); +BOOLEAN ToolbarGraphsEnabled( + VOID + ) +{ + BOOLEAN enabled = FALSE; - DestroyWindow(CommitGraphHandle); - CommitGraphHandle = NULL; + for (ULONG i = 0; i < PhpToolbarGraphList->Count; i++) + { + PPH_TOOLBAR_GRAPH graph = PhpToolbarGraphList->Items[i]; + + if (graph->Flags & TOOLSTATUS_GRAPH_ENABLED) + { + enabled = TRUE; + break; } } - if (ToolStatusConfig.IoGraphEnabled) + return enabled; +} + +PPH_TOOLBAR_GRAPH ToolbarGraphFindById( + _In_ ULONG GraphId + ) +{ + for (ULONG i = 0; i < PhpToolbarGraphList->Count; i++) { - if (!RebarBandExists(REBAR_BAND_ID_IOGRAPH)) - RebarBandInsert(REBAR_BAND_ID_IOGRAPH, IoGraphHandle, 145, height); // 85 + PPH_TOOLBAR_GRAPH graph = PhpToolbarGraphList->Items[i]; - if (IoGraphHandle && !IsWindowVisible(IoGraphHandle)) - { - ShowWindow(IoGraphHandle, SW_SHOW); - } + if (graph->GraphId == GraphId) + return graph; } - else + + return NULL; +} + +PPH_TOOLBAR_GRAPH ToolbarGraphFindByName( + _In_ PPH_STRINGREF PluginName, + _In_ ULONG GraphId + ) +{ + for (ULONG i = 0; i < PhpToolbarGraphList->Count; i++) { - if (RebarBandExists(REBAR_BAND_ID_IOGRAPH)) - RebarBandRemove(REBAR_BAND_ID_IOGRAPH); + PPH_TOOLBAR_GRAPH graph = PhpToolbarGraphList->Items[i]; - if (IoGraphHandle) + if (graph->Plugin) { - PhDeleteGraphState(&IoGraphState); + PPH_STRING pluginName; + + pluginName = PhGetPluginName(graph->Plugin); - DestroyWindow(IoGraphHandle); - IoGraphHandle = NULL; + if (graph->GraphId == GraphId && + PhEqualStringRef(PluginName, &pluginName->sr, TRUE)) + { + PhDereferenceObject(pluginName); + return graph; + } + + PhDereferenceObject(pluginName); } } + + return NULL; } -VOID ToolbarUpdateGraphs(VOID) +VOID ToolbarGraphCreateMenu( + _In_ PPH_EMENU ParentMenu, + _In_ ULONG MenuId + ) { - if (ToolStatusConfig.CpuGraphEnabled && CpuGraphHandle) + for (ULONG i = 0; i < PhpToolbarGraphList->Count; i++) { - CpuGraphState.Valid = FALSE; - CpuGraphState.TooltipIndex = -1; - Graph_MoveGrid(CpuGraphHandle, 1); - Graph_Draw(CpuGraphHandle); - Graph_UpdateTooltip(CpuGraphHandle); - InvalidateRect(CpuGraphHandle, NULL, FALSE); - } + PPH_TOOLBAR_GRAPH graph; + PPH_EMENU menuItem; - if (ToolStatusConfig.MemGraphEnabled && MemGraphHandle) - { - MemGraphState.Valid = FALSE; - MemGraphState.TooltipIndex = -1; - Graph_MoveGrid(MemGraphHandle, 1); - Graph_Draw(MemGraphHandle); - Graph_UpdateTooltip(MemGraphHandle); - InvalidateRect(MemGraphHandle, NULL, FALSE); - } + graph = PhpToolbarGraphList->Items[i]; + menuItem = PhCreateEMenuItem(0, MenuId, graph->Text, NULL, graph); - if (ToolStatusConfig.CommitGraphEnabled && CommitGraphHandle) - { - CommitGraphState.Valid = FALSE; - CommitGraphState.TooltipIndex = -1; - Graph_MoveGrid(CommitGraphHandle, 1); - Graph_Draw(CommitGraphHandle); - Graph_UpdateTooltip(CommitGraphHandle); - InvalidateRect(CommitGraphHandle, NULL, FALSE); - } + if (graph->Flags & TOOLSTATUS_GRAPH_ENABLED) + { + menuItem->Flags |= PH_EMENU_CHECKED; + } - if (ToolStatusConfig.IoGraphEnabled && IoGraphHandle) - { - IoGraphState.Valid = FALSE; - IoGraphState.TooltipIndex = -1; - Graph_MoveGrid(IoGraphHandle, 1); - Graph_Draw(IoGraphHandle); - Graph_UpdateTooltip(IoGraphHandle); - InvalidateRect(IoGraphHandle, NULL, FALSE); + if (graph->Flags & TOOLSTATUS_GRAPH_UNAVAILABLE) + { + PPH_STRING newText; + + newText = PhaConcatStrings2(graph->Text, L" (Unavailable)"); + PhModifyEMenuItem(menuItem, PH_EMENU_MODIFY_TEXT, PH_EMENU_TEXT_OWNED, + PhAllocateCopy(newText->Buffer, newText->Length + sizeof(UNICODE_NULL)), NULL); + } + + PhInsertEMenuItem(ParentMenu, menuItem, ULONG_MAX); } } @@ -398,127 +567,109 @@ static PPH_STRING PhSipGetMaxIoString( // END copied from ProcessHacker/sysinfo.c // -VOID ToolbarUpdateGraphsInfo( - _In_ LPNMHDR Header - ) +TOOLSTATUS_GRAPH_MESSAGE_CALLBACK_DECLARE(CpuHistoryGraphMessageCallback) { switch (Header->code) { case GCN_GETDRAWINFO: { - if (ToolStatusConfig.CpuGraphEnabled && Header->hwndFrom == CpuGraphHandle) - { - PPH_GRAPH_GETDRAWINFO getDrawInfo = (PPH_GRAPH_GETDRAWINFO)Header; - PPH_GRAPH_DRAW_INFO drawInfo = getDrawInfo->DrawInfo; + PPH_GRAPH_GETDRAWINFO getDrawInfo = (PPH_GRAPH_GETDRAWINFO)Header; + PPH_GRAPH_DRAW_INFO drawInfo = getDrawInfo->DrawInfo; - drawInfo->Flags = PH_GRAPH_USE_GRID_X | PH_GRAPH_USE_LINE_2; - PhSiSetColorsGraphDrawInfo(drawInfo, PhGetIntegerSetting(L"ColorCpuKernel"), PhGetIntegerSetting(L"ColorCpuUser")); + drawInfo->Flags = PH_GRAPH_USE_GRID_X | PH_GRAPH_USE_LINE_2; + PhSiSetColorsGraphDrawInfo(drawInfo, PhGetIntegerSetting(L"ColorCpuKernel"), PhGetIntegerSetting(L"ColorCpuUser")); - if (ProcessesUpdatedCount < 2) - return; + if (ProcessesUpdatedCount < 2) + return; - PhGraphStateGetDrawInfo(&CpuGraphState, getDrawInfo, SystemStatistics.CpuUserHistory->Count); + PhGraphStateGetDrawInfo(GraphState, getDrawInfo, SystemStatistics.CpuUserHistory->Count); - if (!CpuGraphState.Valid) - { - PhCopyCircularBuffer_FLOAT(SystemStatistics.CpuKernelHistory, CpuGraphState.Data1, drawInfo->LineDataCount); - PhCopyCircularBuffer_FLOAT(SystemStatistics.CpuUserHistory, CpuGraphState.Data2, drawInfo->LineDataCount); - - CpuGraphState.Valid = TRUE; - } - } - else if (ToolStatusConfig.MemGraphEnabled && Header->hwndFrom == MemGraphHandle) + if (!GraphState->Valid) { - PPH_GRAPH_GETDRAWINFO getDrawInfo = (PPH_GRAPH_GETDRAWINFO)Header; - PPH_GRAPH_DRAW_INFO drawInfo = getDrawInfo->DrawInfo; + PhCopyCircularBuffer_FLOAT(SystemStatistics.CpuKernelHistory, GraphState->Data1, drawInfo->LineDataCount); + PhCopyCircularBuffer_FLOAT(SystemStatistics.CpuUserHistory, GraphState->Data2, drawInfo->LineDataCount); - drawInfo->Flags = PH_GRAPH_USE_GRID_X; - PhSiSetColorsGraphDrawInfo(drawInfo, PhGetIntegerSetting(L"ColorPhysical"), 0); - - if (ProcessesUpdatedCount < 2) - return; - - PhGraphStateGetDrawInfo(&MemGraphState, getDrawInfo, SystemStatistics.PhysicalHistory->Count); - - if (!MemGraphState.Valid) - { - for (ULONG i = 0; i < drawInfo->LineDataCount; i++) - { - MemGraphState.Data1[i] = (FLOAT)PhGetItemCircularBuffer_ULONG(SystemStatistics.PhysicalHistory, i); - } - - PhDivideSinglesBySingle( - MemGraphState.Data1, - (FLOAT)PhSystemBasicInformation.NumberOfPhysicalPages, - drawInfo->LineDataCount - ); - - MemGraphState.Valid = TRUE; - } + GraphState->Valid = TRUE; } - else if (ToolStatusConfig.CommitGraphEnabled && Header->hwndFrom == CommitGraphHandle) - { - PPH_GRAPH_GETDRAWINFO getDrawInfo = (PPH_GRAPH_GETDRAWINFO)Header; - PPH_GRAPH_DRAW_INFO drawInfo = getDrawInfo->DrawInfo; - - drawInfo->Flags = PH_GRAPH_USE_GRID_X; - PhSiSetColorsGraphDrawInfo(drawInfo, PhGetIntegerSetting(L"ColorPrivate"), 0); + } + break; + case GCN_GETTOOLTIPTEXT: + { + PPH_GRAPH_GETTOOLTIPTEXT getTooltipText = (PPH_GRAPH_GETTOOLTIPTEXT)Header; - if (ProcessesUpdatedCount < 2) - return; + if (getTooltipText->Index < getTooltipText->TotalCount) + { + if (GraphState->TooltipIndex != getTooltipText->Index) + { + FLOAT cpuKernel; + FLOAT cpuUser; - PhGraphStateGetDrawInfo(&CommitGraphState, getDrawInfo, SystemStatistics.CommitHistory->Count); + cpuKernel = PhGetItemCircularBuffer_FLOAT(SystemStatistics.CpuKernelHistory, getTooltipText->Index); + cpuUser = PhGetItemCircularBuffer_FLOAT(SystemStatistics.CpuUserHistory, getTooltipText->Index); - if (!CommitGraphState.Valid) - { - for (ULONG i = 0; i < drawInfo->LineDataCount; i++) - { - CommitGraphState.Data1[i] = (FLOAT)PhGetItemCircularBuffer_ULONG(SystemStatistics.CommitHistory, i); - } - - PhDivideSinglesBySingle( - CommitGraphState.Data1, - (FLOAT)SystemStatistics.Performance->CommitLimit, - drawInfo->LineDataCount - ); - - CommitGraphState.Valid = TRUE; + PhMoveReference(&GraphState->TooltipText, PhFormatString( + L"%.2f%%%s\n%s", + (cpuKernel + cpuUser) * 100, + PhGetStringOrEmpty(PhSipGetMaxCpuString(getTooltipText->Index)), + PH_AUTO_T(PH_STRING, PhGetStatisticsTimeString(NULL, getTooltipText->Index))->Buffer + )); } + + getTooltipText->Text = PhGetStringRef(GraphState->TooltipText); } - else if (ToolStatusConfig.IoGraphEnabled && Header->hwndFrom == IoGraphHandle) + } + break; + case GCN_MOUSEEVENT: + { + PPH_GRAPH_MOUSEEVENT mouseEvent = (PPH_GRAPH_MOUSEEVENT)Header; + PPH_PROCESS_RECORD record = NULL; + + if (mouseEvent->Message == WM_LBUTTONDBLCLK && mouseEvent->Index < mouseEvent->TotalCount) { - PPH_GRAPH_GETDRAWINFO getDrawInfo = (PPH_GRAPH_GETDRAWINFO)Header; - PPH_GRAPH_DRAW_INFO drawInfo = getDrawInfo->DrawInfo; + record = PhSipReferenceMaxCpuRecord(mouseEvent->Index); + } - drawInfo->Flags = PH_GRAPH_USE_GRID_X | PH_GRAPH_USE_LINE_2; - PhSiSetColorsGraphDrawInfo(drawInfo, PhGetIntegerSetting(L"ColorIoReadOther"), PhGetIntegerSetting(L"ColorIoWrite")); + if (record) + { + PhShowProcessRecordDialog(PhMainWndHandle, record); + PhDereferenceProcessRecord(record); + } + } + break; + } +} - if (ProcessesUpdatedCount < 2) - return; +TOOLSTATUS_GRAPH_MESSAGE_CALLBACK_DECLARE(PhysicalHistoryGraphMessageCallback) +{ + switch (Header->code) + { + case GCN_GETDRAWINFO: + { + PPH_GRAPH_GETDRAWINFO getDrawInfo = (PPH_GRAPH_GETDRAWINFO)Header; + PPH_GRAPH_DRAW_INFO drawInfo = getDrawInfo->DrawInfo; - PhGraphStateGetDrawInfo(&IoGraphState, getDrawInfo, SystemStatistics.IoReadHistory->Count); + drawInfo->Flags = PH_GRAPH_USE_GRID_X; + PhSiSetColorsGraphDrawInfo(drawInfo, PhGetIntegerSetting(L"ColorPhysical"), 0); - if (!IoGraphState.Valid) - { - FLOAT max = 1024 * 1024; // minimum scaling of 1 MB. + if (ProcessesUpdatedCount < 2) + return; - for (ULONG i = 0; i < drawInfo->LineDataCount; i++) - { - IoGraphState.Data1[i] = - (FLOAT)PhGetItemCircularBuffer_ULONG64(SystemStatistics.IoReadHistory, i) + - (FLOAT)PhGetItemCircularBuffer_ULONG64(SystemStatistics.IoOtherHistory, i); - IoGraphState.Data2[i] = - (FLOAT)PhGetItemCircularBuffer_ULONG64(SystemStatistics.IoWriteHistory, i); + PhGraphStateGetDrawInfo(GraphState, getDrawInfo, SystemStatistics.PhysicalHistory->Count); - if (max < IoGraphState.Data1[i] + IoGraphState.Data2[i]) - max = IoGraphState.Data1[i] + IoGraphState.Data2[i]; - } + if (!GraphState->Valid) + { + for (ULONG i = 0; i < drawInfo->LineDataCount; i++) + { + GraphState->Data1[i] = (FLOAT)PhGetItemCircularBuffer_ULONG(SystemStatistics.PhysicalHistory, i); + } - PhDivideSinglesBySingle(IoGraphState.Data1, max, drawInfo->LineDataCount); - PhDivideSinglesBySingle(IoGraphState.Data2, max, drawInfo->LineDataCount); + PhDivideSinglesBySingle( + GraphState->Data1, + (FLOAT)PhSystemBasicInformation.NumberOfPhysicalPages, + drawInfo->LineDataCount + ); - IoGraphState.Valid = TRUE; - } + GraphState->Valid = TRUE; } } break; @@ -528,53 +679,143 @@ VOID ToolbarUpdateGraphsInfo( if (getTooltipText->Index < getTooltipText->TotalCount) { - if (ToolStatusConfig.CpuGraphEnabled && Header->hwndFrom == CpuGraphHandle) - { - if (CpuGraphState.TooltipIndex != getTooltipText->Index) - { - FLOAT cpuKernel; - FLOAT cpuUser; - - cpuKernel = PhGetItemCircularBuffer_FLOAT(SystemStatistics.CpuKernelHistory, getTooltipText->Index); - cpuUser = PhGetItemCircularBuffer_FLOAT(SystemStatistics.CpuUserHistory, getTooltipText->Index); - - PhMoveReference(&CpuGraphState.TooltipText, PhFormatString( - L"%.2f%%%s\n%s", - (cpuKernel + cpuUser) * 100, - PhGetStringOrEmpty(PhSipGetMaxCpuString(getTooltipText->Index)), - PH_AUTO_T(PH_STRING, PhGetStatisticsTimeString(NULL, getTooltipText->Index))->Buffer - )); - } - - getTooltipText->Text = CpuGraphState.TooltipText->sr; - } - else if (ToolStatusConfig.MemGraphEnabled && Header->hwndFrom == MemGraphHandle) + if (GraphState->TooltipIndex != getTooltipText->Index) { ULONG physicalUsage; physicalUsage = PhGetItemCircularBuffer_ULONG(SystemStatistics.PhysicalHistory, getTooltipText->Index); - PhMoveReference(&MemGraphState.TooltipText, PhFormatString( + PhMoveReference(&GraphState->TooltipText, PhFormatString( L"Physical memory: %s\n%s", PhaFormatSize(UInt32x32To64(physicalUsage, PAGE_SIZE), -1)->Buffer, PH_AUTO_T(PH_STRING, PhGetStatisticsTimeString(NULL, getTooltipText->Index))->Buffer - )); - getTooltipText->Text = MemGraphState.TooltipText->sr; + )); + } + + getTooltipText->Text = PhGetStringRef(GraphState->TooltipText); + } + } + break; + case GCN_MOUSEEVENT: + { + NOTHING; + } + break; + } +} + +TOOLSTATUS_GRAPH_MESSAGE_CALLBACK_DECLARE(CommitHistoryGraphMessageCallback) +{ + switch (Header->code) + { + case GCN_GETDRAWINFO: + { + PPH_GRAPH_GETDRAWINFO getDrawInfo = (PPH_GRAPH_GETDRAWINFO)Header; + PPH_GRAPH_DRAW_INFO drawInfo = getDrawInfo->DrawInfo; + + drawInfo->Flags = PH_GRAPH_USE_GRID_X; + PhSiSetColorsGraphDrawInfo(drawInfo, PhGetIntegerSetting(L"ColorPrivate"), 0); + + if (ProcessesUpdatedCount < 2) + return; + + PhGraphStateGetDrawInfo(GraphState, getDrawInfo, SystemStatistics.CommitHistory->Count); + + if (!GraphState->Valid) + { + for (ULONG i = 0; i < drawInfo->LineDataCount; i++) + { + GraphState->Data1[i] = (FLOAT)PhGetItemCircularBuffer_ULONG(SystemStatistics.CommitHistory, i); } - else if (ToolStatusConfig.CommitGraphEnabled && Header->hwndFrom == CommitGraphHandle) + + PhDivideSinglesBySingle( + GraphState->Data1, + (FLOAT)SystemStatistics.Performance->CommitLimit, + drawInfo->LineDataCount + ); + + GraphState->Valid = TRUE; + } + } + break; + case GCN_GETTOOLTIPTEXT: + { + PPH_GRAPH_GETTOOLTIPTEXT getTooltipText = (PPH_GRAPH_GETTOOLTIPTEXT)Header; + + if (getTooltipText->Index < getTooltipText->TotalCount) + { + if (GraphState->TooltipIndex != getTooltipText->Index) { ULONG commitUsage; commitUsage = PhGetItemCircularBuffer_ULONG(SystemStatistics.CommitHistory, getTooltipText->Index); - PhMoveReference(&CommitGraphState.TooltipText, PhFormatString( + PhMoveReference(&GraphState->TooltipText, PhFormatString( L"Commit charge: %s\n%s", PhaFormatSize(UInt32x32To64(commitUsage, PAGE_SIZE), -1)->Buffer, PH_AUTO_T(PH_STRING, PhGetStatisticsTimeString(NULL, getTooltipText->Index))->Buffer )); - getTooltipText->Text = CommitGraphState.TooltipText->sr; } - else if (ToolStatusConfig.IoGraphEnabled && Header->hwndFrom == IoGraphHandle) + + getTooltipText->Text = PhGetStringRef(GraphState->TooltipText); + } + } + break; + case GCN_MOUSEEVENT: + { + NOTHING; + } + break; + } +} + +TOOLSTATUS_GRAPH_MESSAGE_CALLBACK_DECLARE(IoHistoryGraphMessageCallback) +{ + switch (Header->code) + { + case GCN_GETDRAWINFO: + { + PPH_GRAPH_GETDRAWINFO getDrawInfo = (PPH_GRAPH_GETDRAWINFO)Header; + PPH_GRAPH_DRAW_INFO drawInfo = getDrawInfo->DrawInfo; + + drawInfo->Flags = PH_GRAPH_USE_GRID_X | PH_GRAPH_USE_LINE_2; + PhSiSetColorsGraphDrawInfo(drawInfo, PhGetIntegerSetting(L"ColorIoReadOther"), PhGetIntegerSetting(L"ColorIoWrite")); + + if (ProcessesUpdatedCount < 2) + return; + + PhGraphStateGetDrawInfo(GraphState, getDrawInfo, SystemStatistics.IoReadHistory->Count); + + if (!GraphState->Valid) + { + FLOAT max = 1024 * 1024; // minimum scaling of 1 MB. + + for (ULONG i = 0; i < drawInfo->LineDataCount; i++) + { + GraphState->Data1[i] = + (FLOAT)PhGetItemCircularBuffer_ULONG64(SystemStatistics.IoReadHistory, i) + + (FLOAT)PhGetItemCircularBuffer_ULONG64(SystemStatistics.IoOtherHistory, i); + GraphState->Data2[i] = + (FLOAT)PhGetItemCircularBuffer_ULONG64(SystemStatistics.IoWriteHistory, i); + + if (max < GraphState->Data1[i] + GraphState->Data2[i]) + max = GraphState->Data1[i] + GraphState->Data2[i]; + } + + PhDivideSinglesBySingle(GraphState->Data1, max, drawInfo->LineDataCount); + PhDivideSinglesBySingle(GraphState->Data2, max, drawInfo->LineDataCount); + + GraphState->Valid = TRUE; + } + } + break; + case GCN_GETTOOLTIPTEXT: + { + PPH_GRAPH_GETTOOLTIPTEXT getTooltipText = (PPH_GRAPH_GETTOOLTIPTEXT)Header; + + if (getTooltipText->Index < getTooltipText->TotalCount) + { + if (GraphState->TooltipIndex != getTooltipText->Index) { ULONG64 ioRead; ULONG64 ioWrite; @@ -584,7 +825,7 @@ VOID ToolbarUpdateGraphsInfo( ioWrite = PhGetItemCircularBuffer_ULONG64(SystemStatistics.IoWriteHistory, getTooltipText->Index); ioOther = PhGetItemCircularBuffer_ULONG64(SystemStatistics.IoOtherHistory, getTooltipText->Index); - PhMoveReference(&IoGraphState.TooltipText, PhFormatString( + PhMoveReference(&GraphState->TooltipText, PhFormatString( L"R: %s\nW: %s\nO: %s%s\n%s", PhaFormatSize(ioRead, -1)->Buffer, PhaFormatSize(ioWrite, -1)->Buffer, @@ -592,8 +833,9 @@ VOID ToolbarUpdateGraphsInfo( PhGetStringOrEmpty(PhSipGetMaxIoString(getTooltipText->Index)), PH_AUTO_T(PH_STRING, PhGetStatisticsTimeString(NULL, getTooltipText->Index))->Buffer )); - getTooltipText->Text = IoGraphState.TooltipText->sr; } + + getTooltipText->Text = PhGetStringRef(GraphState->TooltipText); } } break; @@ -602,61 +844,17 @@ VOID ToolbarUpdateGraphsInfo( PPH_GRAPH_MOUSEEVENT mouseEvent = (PPH_GRAPH_MOUSEEVENT)Header; PPH_PROCESS_RECORD record = NULL; - if (ToolStatusConfig.CpuGraphEnabled && Header->hwndFrom == CpuGraphHandle) + if (mouseEvent->Message == WM_LBUTTONDBLCLK && mouseEvent->Index < mouseEvent->TotalCount) { - if (mouseEvent->Message == WM_RBUTTONUP) - { - ShowCustomizeMenu(); - } - else - { - if (mouseEvent->Message == WM_LBUTTONDBLCLK && mouseEvent->Index < mouseEvent->TotalCount) - { - record = PhSipReferenceMaxCpuRecord(mouseEvent->Index); - } - - if (record) - { - PhShowProcessRecordDialog(PhMainWndHandle, record); - PhDereferenceProcessRecord(record); - } - } - } - else if (ToolStatusConfig.MemGraphEnabled && Header->hwndFrom == MemGraphHandle) - { - if (mouseEvent->Message == WM_RBUTTONUP) - { - ShowCustomizeMenu(); - } - } - else if (ToolStatusConfig.CommitGraphEnabled && Header->hwndFrom == CommitGraphHandle) - { - if (mouseEvent->Message == WM_RBUTTONUP) - { - ShowCustomizeMenu(); - } + record = PhSipReferenceMaxIoRecord(mouseEvent->Index); } - else if (ToolStatusConfig.IoGraphEnabled && Header->hwndFrom == IoGraphHandle) + + if (record) { - if (mouseEvent->Message == WM_RBUTTONUP) - { - ShowCustomizeMenu(); - } - else - { - if (mouseEvent->Message == WM_LBUTTONDBLCLK && mouseEvent->Index < mouseEvent->TotalCount) - { - record = PhSipReferenceMaxIoRecord(mouseEvent->Index); - } - - if (record) - { - PhShowProcessRecordDialog(PhMainWndHandle, record); - PhDereferenceProcessRecord(record); - } - } + PhShowProcessRecordDialog(PhMainWndHandle, record); + PhDereferenceProcessRecord(record); } } break; } -} \ No newline at end of file +} diff --git a/plugins/ToolStatus/main.c b/plugins/ToolStatus/main.c index def71184d29a..fac5856bda76 100644 --- a/plugins/ToolStatus/main.c +++ b/plugins/ToolStatus/main.c @@ -3,7 +3,7 @@ * main program * * Copyright (C) 2010-2016 wj32 - * Copyright (C) 2011-2017 dmex + * Copyright (C) 2011-2019 dmex * * This file is part of Process Hacker. * @@ -40,7 +40,8 @@ TOOLSTATUS_CONFIG ToolStatusConfig = { 0 }; HWND ProcessTreeNewHandle = NULL; HWND ServiceTreeNewHandle = NULL; HWND NetworkTreeNewHandle = NULL; -INT SelectedTabIndex; +INT SelectedTabIndex = 0; +ULONG ProcessesUpdatedCount = 0; BOOLEAN UpdateAutomatically = TRUE; BOOLEAN UpdateGraphs = TRUE; TOOLBAR_DISPLAY_STYLE DisplayStyle = TOOLBAR_DISPLAY_STYLE_SELECTIVETEXT; @@ -67,7 +68,8 @@ TOOLSTATUS_INTERFACE PluginInterface = WordMatchStringRef, RegisterTabSearch, &SearchChangedEvent, - RegisterTabInfo + RegisterTabInfo, + ToolbarRegisterGraph }; static ULONG TargetingMode = 0; @@ -97,10 +99,11 @@ VOID NTAPI ProcessesUpdatedCallback( _In_opt_ PVOID Context ) { - ProcessesUpdatedCount++; - if (ProcessesUpdatedCount < 2) + { + ProcessesUpdatedCount++; return; + } PhPluginGetSystemStatistics(&SystemStatistics); @@ -208,10 +211,8 @@ VOID ShowCustomizeMenu( menu = PhCreateEMenu(); PhInsertEMenuItem(menu, PhCreateEMenuItem(0, COMMAND_ID_ENABLE_MENU, L"Main menu (auto-hide)", NULL, NULL), ULONG_MAX); PhInsertEMenuItem(menu, PhCreateEMenuItem(0, COMMAND_ID_ENABLE_SEARCHBOX, L"Search box", NULL, NULL), ULONG_MAX); - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, COMMAND_ID_ENABLE_CPU_GRAPH, L"CPU history", NULL, NULL), ULONG_MAX); - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, COMMAND_ID_ENABLE_IO_GRAPH, L"I/O history", NULL, NULL), ULONG_MAX); - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, COMMAND_ID_ENABLE_MEMORY_GRAPH, L"Physical memory history", NULL, NULL), ULONG_MAX); - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, COMMAND_ID_ENABLE_COMMIT_GRAPH, L"Commit charge history", NULL, NULL), ULONG_MAX); + PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX); + ToolbarGraphCreateMenu(menu, COMMAND_ID_GRAPHS_CUSTOMIZE); PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX); PhInsertEMenuItem(menu, PhCreateEMenuItem(0, COMMAND_ID_TOOLBAR_LOCKUNLOCK, L"Lock the toolbar", NULL, NULL), ULONG_MAX); PhInsertEMenuItem(menu, PhCreateEMenuItem(0, COMMAND_ID_TOOLBAR_CUSTOMIZE, L"Customize...", NULL, NULL), ULONG_MAX); @@ -226,26 +227,6 @@ VOID ShowCustomizeMenu( PhSetFlagsEMenuItem(menu, COMMAND_ID_ENABLE_SEARCHBOX, PH_EMENU_CHECKED, PH_EMENU_CHECKED); } - if (ToolStatusConfig.CpuGraphEnabled) - { - PhSetFlagsEMenuItem(menu, COMMAND_ID_ENABLE_CPU_GRAPH, PH_EMENU_CHECKED, PH_EMENU_CHECKED); - } - - if (ToolStatusConfig.MemGraphEnabled) - { - PhSetFlagsEMenuItem(menu, COMMAND_ID_ENABLE_MEMORY_GRAPH, PH_EMENU_CHECKED, PH_EMENU_CHECKED); - } - - if (ToolStatusConfig.CommitGraphEnabled) - { - PhSetFlagsEMenuItem(menu, COMMAND_ID_ENABLE_COMMIT_GRAPH, PH_EMENU_CHECKED, PH_EMENU_CHECKED); - } - - if (ToolStatusConfig.IoGraphEnabled) - { - PhSetFlagsEMenuItem(menu, COMMAND_ID_ENABLE_IO_GRAPH, PH_EMENU_CHECKED, PH_EMENU_CHECKED); - } - if (ToolStatusConfig.ToolBarLocked) { PhSetFlagsEMenuItem(menu, COMMAND_ID_TOOLBAR_LOCKUNLOCK, PH_EMENU_CHECKED, PH_EMENU_CHECKED); @@ -298,46 +279,6 @@ VOID ShowCustomizeMenu( } } break; - case COMMAND_ID_ENABLE_CPU_GRAPH: - { - ToolStatusConfig.CpuGraphEnabled = !ToolStatusConfig.CpuGraphEnabled; - - PhSetIntegerSetting(SETTING_NAME_TOOLSTATUS_CONFIG, ToolStatusConfig.Flags); - - ToolbarLoadSettings(); - ReBarSaveLayoutSettings(); - } - break; - case COMMAND_ID_ENABLE_MEMORY_GRAPH: - { - ToolStatusConfig.MemGraphEnabled = !ToolStatusConfig.MemGraphEnabled; - - PhSetIntegerSetting(SETTING_NAME_TOOLSTATUS_CONFIG, ToolStatusConfig.Flags); - - ToolbarLoadSettings(); - ReBarSaveLayoutSettings(); - } - break; - case COMMAND_ID_ENABLE_COMMIT_GRAPH: - { - ToolStatusConfig.CommitGraphEnabled = !ToolStatusConfig.CommitGraphEnabled; - - PhSetIntegerSetting(SETTING_NAME_TOOLSTATUS_CONFIG, ToolStatusConfig.Flags); - - ToolbarLoadSettings(); - ReBarSaveLayoutSettings(); - } - break; - case COMMAND_ID_ENABLE_IO_GRAPH: - { - ToolStatusConfig.IoGraphEnabled = !ToolStatusConfig.IoGraphEnabled; - - PhSetIntegerSetting(SETTING_NAME_TOOLSTATUS_CONFIG, ToolStatusConfig.Flags); - - ToolbarLoadSettings(); - ReBarSaveLayoutSettings(); - } - break; case COMMAND_ID_TOOLBAR_LOCKUNLOCK: { UINT bandCount; @@ -391,6 +332,20 @@ VOID ShowCustomizeMenu( ToolBarShowCustomizeDialog(); } break; + case COMMAND_ID_GRAPHS_CUSTOMIZE: + { + PPH_TOOLBAR_GRAPH icon; + + if (!selectedItem->Context) + break; + + icon = selectedItem->Context; + ToolbarSetVisibleGraph(icon, !(icon->Flags & PH_NF_ICON_ENABLED)); + + ToolbarGraphSaveSettings(); + ReBarSaveLayoutSettings(); + } + break; } } @@ -1017,7 +972,7 @@ LRESULT CALLBACK MainWndSubclassProc( PhInsertEMenuItem(menu, PhCreateEMenuItem(0, PHAPP_ID_COMPUTER_RESTARTBOOTOPTIONS, L"Restart to boot &options", NULL, NULL), ULONG_MAX); PhInsertEMenuItem(menu, PhCreateEMenuItem(0, PHAPP_ID_COMPUTER_SHUTDOWN, L"Shu&t down", NULL, NULL), ULONG_MAX); PhInsertEMenuItem(menu, PhCreateEMenuItem(0, PHAPP_ID_COMPUTER_SHUTDOWNHYBRID, L"H&ybrid shut down", NULL, NULL), ULONG_MAX); - + if (WindowsVersion < WINDOWS_8) { PPH_EMENU_ITEM menuItemRemove; @@ -1100,16 +1055,12 @@ LRESULT CALLBACK MainWndSubclassProc( goto DefaultWndProc; } - else if ( - CpuGraphHandle && hdr->hwndFrom == CpuGraphHandle || - MemGraphHandle && hdr->hwndFrom == MemGraphHandle || - CommitGraphHandle && hdr->hwndFrom == CommitGraphHandle || - IoGraphHandle && hdr->hwndFrom == IoGraphHandle - ) + else { - ToolbarUpdateGraphsInfo(hdr); - - goto DefaultWndProc; + if (ToolbarUpdateGraphsInfo(hdr)) + { + goto DefaultWndProc; + } } } break; @@ -1326,6 +1277,9 @@ LRESULT CALLBACK MainWndSubclassProc( else if ((wParam & 0xFFF0) == SC_RESTORE) { UpdateGraphs = TRUE; + + // TODO: The graphs don't redraw when updating is disabled (e.g. F6) and you maximize then restore the main window. + RedrawWindow(hWnd, NULL, NULL, RDW_ERASE | RDW_INVALIDATE | RDW_FRAME | RDW_ALLCHILDREN); } } break; @@ -1385,6 +1339,7 @@ VOID NTAPI MainWindowShowingCallback( SetWindowLongPtr(PhMainWndHandle, GWLP_WNDPROC, (LONG_PTR)MainWndSubclassProc); ToolbarLoadSettings(); + ToolbarCreateGraphs(); ReBarLoadLayoutSettings(); StatusBarLoadSettings(); @@ -1404,6 +1359,8 @@ VOID NTAPI LoadCallback( DisplayStyle = (TOOLBAR_DISPLAY_STYLE)PhGetIntegerSetting(SETTING_NAME_TOOLBARDISPLAYSTYLE); SearchBoxDisplayMode = (SEARCHBOX_DISPLAY_MODE)PhGetIntegerSetting(SETTING_NAME_SEARCHBOXDISPLAYMODE); UpdateGraphs = !PhGetIntegerSetting(L"StartHidden"); + + ToolbarGraphsInitialize(); } VOID NTAPI ShowOptionsCallback( @@ -1441,7 +1398,8 @@ LOGICAL DllMain( { IntegerSettingType, SETTING_NAME_SEARCHBOXDISPLAYMODE, L"0" }, { StringSettingType, SETTING_NAME_REBAR_CONFIG, L"" }, { StringSettingType, SETTING_NAME_TOOLBAR_CONFIG, L"" }, - { StringSettingType, SETTING_NAME_STATUSBAR_CONFIG, L"" } + { StringSettingType, SETTING_NAME_STATUSBAR_CONFIG, L"" }, + { StringSettingType, SETTING_NAME_TOOLBAR_GRAPH_CONFIG, L"" } }; PluginInstance = PhRegisterPlugin(PLUGIN_NAME, Instance, &info); diff --git a/plugins/ToolStatus/statusbar.c b/plugins/ToolStatus/statusbar.c index 3b10b2e39071..43c540d580e2 100644 --- a/plugins/ToolStatus/statusbar.c +++ b/plugins/ToolStatus/statusbar.c @@ -24,7 +24,6 @@ #include "toolstatus.h" HWND StatusBarHandle = NULL; -ULONG ProcessesUpdatedCount = 0; ULONG StatusBarMaxWidths[MAX_STATUSBAR_ITEMS]; // Note: no lock is needed because we only ever modify the list on this same thread. PPH_LIST StatusBarItemList = NULL; diff --git a/plugins/ToolStatus/toolbar.c b/plugins/ToolStatus/toolbar.c index d59a091ba407..a07ac0e1df47 100644 --- a/plugins/ToolStatus/toolbar.c +++ b/plugins/ToolStatus/toolbar.c @@ -2,7 +2,7 @@ * Process Hacker ToolStatus - * main toolbar * - * Copyright (C) 2011-2017 dmex + * Copyright (C) 2011-2019 dmex * * This file is part of Process Hacker. * @@ -267,8 +267,6 @@ VOID RebarLoadSettings( if (StatusBarHandle && IsWindowVisible(StatusBarHandle)) ShowWindow(StatusBarHandle, SW_HIDE); } - - ToolbarCreateGraphs(); } VOID ToolbarLoadSettings( @@ -802,7 +800,7 @@ VOID ReBarLoadLayoutSettings( PhStringToInteger64(&stylePart, 10, &styleInteger); if ((oldBandIndex = (UINT)SendMessage(RebarHandle, RB_IDTOINDEX, (UINT)idInteger, 0)) == UINT_MAX) - break; + continue; if (oldBandIndex != index) { @@ -871,4 +869,4 @@ VOID ReBarSaveLayoutSettings( settingsString = PH_AUTO(PhFinalStringBuilderString(&stringBuilder)); PhSetStringSetting2(SETTING_NAME_REBAR_CONFIG, &settingsString->sr); -} \ No newline at end of file +} diff --git a/plugins/ToolStatus/toolstatus.h b/plugins/ToolStatus/toolstatus.h index 6ea6bcdd7092..cc9165b06bdd 100644 --- a/plugins/ToolStatus/toolstatus.h +++ b/plugins/ToolStatus/toolstatus.h @@ -3,7 +3,7 @@ * toolstatus header * * Copyright (C) 2010-2013 wj32 - * Copyright (C) 2011-2016 dmex + * Copyright (C) 2011-2019 dmex * * This file is part of Process Hacker. * @@ -39,6 +39,7 @@ #define SETTING_NAME_TOOLSTATUS_CONFIG (PLUGIN_NAME L".Config") #define SETTING_NAME_REBAR_CONFIG (PLUGIN_NAME L".RebarConfig") #define SETTING_NAME_TOOLBAR_CONFIG (PLUGIN_NAME L".ToolbarButtonConfig") +#define SETTING_NAME_TOOLBAR_GRAPH_CONFIG (PLUGIN_NAME L".ToolbarGraphConfig") #define SETTING_NAME_STATUSBAR_CONFIG (PLUGIN_NAME L".StatusbarConfig") #define SETTING_NAME_TOOLBAR_THEME (PLUGIN_NAME L".ToolbarTheme") #define SETTING_NAME_TOOLBARDISPLAYSTYLE (PLUGIN_NAME L".ToolbarDisplayStyle") @@ -65,12 +66,9 @@ typedef enum _TOOLBAR_COMMAND_ID { COMMAND_ID_ENABLE_MENU = 1, COMMAND_ID_ENABLE_SEARCHBOX, - COMMAND_ID_ENABLE_CPU_GRAPH, - COMMAND_ID_ENABLE_MEMORY_GRAPH, - COMMAND_ID_ENABLE_COMMIT_GRAPH, - COMMAND_ID_ENABLE_IO_GRAPH, COMMAND_ID_TOOLBAR_LOCKUNLOCK, COMMAND_ID_TOOLBAR_CUSTOMIZE, + COMMAND_ID_GRAPHS_CUSTOMIZE, } TOOLBAR_COMMAND_ID; //typedef enum _TOOLBAR_THEME @@ -115,15 +113,9 @@ typedef union _TOOLSTATUS_CONFIG ULONG StatusBarEnabled : 1; ULONG ToolBarLocked : 1; ULONG ResolveGhostWindows : 1; - ULONG ModernIcons : 1; ULONG AutoHideMenu : 1; - ULONG CpuGraphEnabled : 1; - ULONG MemGraphEnabled : 1; - ULONG CommitGraphEnabled : 1; - ULONG IoGraphEnabled : 1; - - ULONG Spare : 21; + ULONG Spare : 25; }; } TOOLSTATUS_CONFIG; @@ -258,14 +250,76 @@ NTSTATUS QueryServiceFileName( // graph.c -extern HWND CpuGraphHandle; -extern HWND MemGraphHandle; -extern HWND CommitGraphHandle; -extern HWND IoGraphHandle; +typedef struct _PH_TOOLBAR_GRAPH +{ + struct _PH_PLUGIN *Plugin; + + ULONG Flags; + ULONG GraphId; + + HWND GraphHandle; + PVOID Context; + PWSTR Text; + + PTOOLSTATUS_GRAPH_MESSAGE_CALLBACK MessageCallback; + PH_GRAPH_STATE GraphState; +} PH_TOOLBAR_GRAPH, *PPH_TOOLBAR_GRAPH; + +VOID ToolbarGraphLoadSettings( + VOID + ); + +VOID ToolbarGraphSaveSettings( + VOID + ); + +VOID ToolbarGraphsInitialize( + VOID + ); + +VOID ToolbarRegisterGraph( + _In_ struct _PH_PLUGIN *Plugin, + _In_ ULONG Id, + _In_ PWSTR Text, + _In_ ULONG Flags, + _In_opt_ PVOID Context, + _In_opt_ PTOOLSTATUS_GRAPH_MESSAGE_CALLBACK MessageCallback + ); + +VOID ToolbarCreateGraphs( + VOID + ); + +VOID ToolbarUpdateGraphs( + VOID + ); + +BOOLEAN ToolbarUpdateGraphsInfo( + _In_ LPNMHDR Header + ); + +VOID ToolbarSetVisibleGraph( + _In_ PPH_TOOLBAR_GRAPH Icon, + _In_ BOOLEAN Visible + ); -VOID ToolbarCreateGraphs(VOID); -VOID ToolbarUpdateGraphs(VOID); -VOID ToolbarUpdateGraphsInfo(LPNMHDR Header); +BOOLEAN ToolbarGraphsEnabled( + VOID + ); + +PPH_TOOLBAR_GRAPH ToolbarGraphFindById( + _In_ ULONG SubId + ); + +PPH_TOOLBAR_GRAPH ToolbarGraphFindByName( + _In_ PPH_STRINGREF PluginName, + _In_ ULONG SubId + ); + +VOID ToolbarGraphCreateMenu( + _In_ PPH_EMENU ParentMenu, + _In_ ULONG MenuId + ); // statusbar.c @@ -383,4 +437,4 @@ BOOLEAN CreateSearchboxControl( extern HFONT ToolStatusWindowFont; #define PHAPP_WM_PLUGIN_UPDATE_FONT (WM_APP + 136) -#endif \ No newline at end of file +#endif From aa6966067cbf882f1e580c190ff07f6f367899f4 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 13 Jan 2019 18:17:31 +0100 Subject: [PATCH 1538/2058] ExtendedTools: Add gpu, disk and network toolbar graphs --- plugins/ExtendedTools/etwdisk.c | 4 +- plugins/ExtendedTools/exttools.h | 5 + plugins/ExtendedTools/iconext.c | 341 +++++++++++++++++++++++++++++++ plugins/ExtendedTools/main.c | 30 ++- 4 files changed, 374 insertions(+), 6 deletions(-) diff --git a/plugins/ExtendedTools/etwdisk.c b/plugins/ExtendedTools/etwdisk.c index f0d3c4215d1d..4023ddb74768 100644 --- a/plugins/ExtendedTools/etwdisk.c +++ b/plugins/ExtendedTools/etwdisk.c @@ -66,7 +66,7 @@ PPH_HASHTABLE EtFileNameHashtable; PH_QUEUED_LOCK EtFileNameHashtableLock = PH_QUEUED_LOCK_INIT; static LARGE_INTEGER EtpPerformanceFrequency; -static PH_CALLBACK_REGISTRATION ProcessesUpdatedCallbackRegistration; +static PH_CALLBACK_REGISTRATION EtpProcessesUpdatedCallbackRegistration; VOID EtInitializeDiskInformation( VOID @@ -98,7 +98,7 @@ VOID EtInitializeDiskInformation( PhGetGeneralCallback(GeneralCallbackProcessProviderUpdatedEvent), EtpDiskProcessesUpdatedCallback, NULL, - &ProcessesUpdatedCallbackRegistration + &EtpProcessesUpdatedCallbackRegistration ); } diff --git a/plugins/ExtendedTools/exttools.h b/plugins/ExtendedTools/exttools.h index 780da9c6923f..e156b03f86c4 100644 --- a/plugins/ExtendedTools/exttools.h +++ b/plugins/ExtendedTools/exttools.h @@ -16,6 +16,7 @@ extern LIST_ENTRY EtProcessBlockListHead; extern LIST_ENTRY EtNetworkBlockListHead; extern HWND ProcessTreeNewHandle; extern HWND NetworkTreeNewHandle; +extern ULONG ProcessesUpdatedCount; #define PLUGIN_NAME L"ProcessHacker.ExtendedTools" #define SETTING_NAME_DISK_TREE_LIST_COLUMNS (PLUGIN_NAME L".DiskTreeListColumns") @@ -562,6 +563,10 @@ VOID EtRegisterNotifyIcons( _In_ PPH_TRAY_ICON_POINTERS Pointers ); +VOID EtRegisterToolbarGraphs( + VOID + ); + // modsrv VOID EtShowModuleServicesDialog( diff --git a/plugins/ExtendedTools/iconext.c b/plugins/ExtendedTools/iconext.c index 921e86d94f71..20d32010a919 100644 --- a/plugins/ExtendedTools/iconext.c +++ b/plugins/ExtendedTools/iconext.c @@ -3,6 +3,7 @@ * notification icon extensions * * Copyright (C) 2011 wj32 + * Copyright (C) 2016-2019 dmex * * This file is part of Process Hacker. * @@ -21,6 +22,9 @@ */ #include "exttools.h" +#include "etwsys.h" +#include "gpusys.h" +#include #define GPU_ICON_ID 1 #define DISK_ICON_ID 2 @@ -758,3 +762,340 @@ VOID EtpNetworkTextIconUpdateCallback( *NewText = PhFormat(format, maxNetworkProcessItem ? 6 : 4, 128); if (maxNetworkProcessItem) PhDereferenceObject(maxNetworkProcessItem); } + +// Toolbar graphs + +TOOLSTATUS_GRAPH_MESSAGE_CALLBACK_DECLARE(EtpToolbarGpuHistoryGraphMessageCallback) +{ + switch (Header->code) + { + case GCN_GETDRAWINFO: + { + PPH_GRAPH_GETDRAWINFO getDrawInfo = (PPH_GRAPH_GETDRAWINFO)Header; + PPH_GRAPH_DRAW_INFO drawInfo = getDrawInfo->DrawInfo; + + drawInfo->Flags = PH_GRAPH_USE_GRID_X; + PhSiSetColorsGraphDrawInfo(drawInfo, PhGetIntegerSetting(L"ColorCpuKernel"), 0); + + if (ProcessesUpdatedCount < 2) + return; + + PhGraphStateGetDrawInfo(GraphState, getDrawInfo, EtGpuNodeHistory.Count); + + if (!GraphState->Valid) + { + PhCopyCircularBuffer_FLOAT(&EtGpuNodeHistory, GraphState->Data1, drawInfo->LineDataCount); + + GraphState->Valid = TRUE; + } + } + break; + case GCN_GETTOOLTIPTEXT: + { + PPH_GRAPH_GETTOOLTIPTEXT getTooltipText = (PPH_GRAPH_GETTOOLTIPTEXT)Header; + + if (getTooltipText->Index < getTooltipText->TotalCount) + { + if (GraphState->TooltipIndex != getTooltipText->Index) + { + FLOAT gpu; + + gpu = PhGetItemCircularBuffer_FLOAT(&EtGpuNodeHistory, getTooltipText->Index); + + PhMoveReference(&GraphState->TooltipText, PhFormatString( + L"%.2f%%%s\n%s", + gpu * 100, + PhGetStringOrEmpty(EtpGetMaxNodeString(getTooltipText->Index)), + ((PPH_STRING)PH_AUTO(PhGetStatisticsTimeString(NULL, getTooltipText->Index)))->Buffer + )); + } + + getTooltipText->Text = PhGetStringRef(GraphState->TooltipText); + } + } + break; + case GCN_MOUSEEVENT: + { + PPH_GRAPH_MOUSEEVENT mouseEvent = (PPH_GRAPH_MOUSEEVENT)Header; + PPH_PROCESS_RECORD record; + + record = NULL; + + if (mouseEvent->Message == WM_LBUTTONDBLCLK && mouseEvent->Index < mouseEvent->TotalCount) + { + record = EtpReferenceMaxNodeRecord(mouseEvent->Index); + } + + if (record) + { + PhShowProcessRecordDialog(PhMainWndHandle, record); + PhDereferenceProcessRecord(record); + } + } + break; + } +} + +TOOLSTATUS_GRAPH_MESSAGE_CALLBACK_DECLARE(EtpToolbarDiskHistoryGraphMessageCallback) +{ + switch (Header->code) + { + case GCN_GETDRAWINFO: + { + PPH_GRAPH_GETDRAWINFO getDrawInfo = (PPH_GRAPH_GETDRAWINFO)Header; + PPH_GRAPH_DRAW_INFO drawInfo = getDrawInfo->DrawInfo; + + drawInfo->Flags = PH_GRAPH_USE_GRID_X | PH_GRAPH_USE_LINE_2; + PhSiSetColorsGraphDrawInfo(drawInfo, PhGetIntegerSetting(L"ColorIoReadOther"), PhGetIntegerSetting(L"ColorIoWrite")); + + if (ProcessesUpdatedCount < 2) + return; + + PhGraphStateGetDrawInfo( + GraphState, + getDrawInfo, + EtDiskReadHistory.Count + ); + + if (!GraphState->Valid) + { + ULONG i; + FLOAT max = 1024 * 1024; // Minimum scaling of 1 MB + + for (i = 0; i < drawInfo->LineDataCount; i++) + { + FLOAT data1; + FLOAT data2; + + GraphState->Data1[i] = data1 = + (FLOAT)PhGetItemCircularBuffer_ULONG(&EtDiskReadHistory, i); + GraphState->Data2[i] = data2 = + (FLOAT)PhGetItemCircularBuffer_ULONG(&EtDiskWriteHistory, i); + + if (max < data1 + data2) + max = data1 + data2; + } + + if (max != 0) + { + // Scale the data. + + PhDivideSinglesBySingle( + GraphState->Data1, + max, + drawInfo->LineDataCount + ); + PhDivideSinglesBySingle( + GraphState->Data2, + max, + drawInfo->LineDataCount + ); + } + + GraphState->Valid = TRUE; + } + } + break; + case GCN_GETTOOLTIPTEXT: + { + PPH_GRAPH_GETTOOLTIPTEXT getTooltipText = (PPH_GRAPH_GETTOOLTIPTEXT)Header; + + if (getTooltipText->Index < getTooltipText->TotalCount) + { + if (GraphState->TooltipIndex != getTooltipText->Index) + { + ULONG64 diskRead; + ULONG64 diskWrite; + + diskRead = PhGetItemCircularBuffer_ULONG(&EtDiskReadHistory, getTooltipText->Index); + diskWrite = PhGetItemCircularBuffer_ULONG(&EtDiskWriteHistory, getTooltipText->Index); + + PhMoveReference(&GraphState->TooltipText, PhFormatString( + L"R: %s\nW: %s%s\n%s", + PhaFormatSize(diskRead, ULONG_MAX)->Buffer, + PhaFormatSize(diskWrite, ULONG_MAX)->Buffer, + PhGetStringOrEmpty(EtpGetMaxDiskString(getTooltipText->Index)), + ((PPH_STRING)PH_AUTO(PhGetStatisticsTimeString(NULL, getTooltipText->Index)))->Buffer + )); + } + + getTooltipText->Text = PhGetStringRef(GraphState->TooltipText); + } + } + break; + case GCN_MOUSEEVENT: + { + PPH_GRAPH_MOUSEEVENT mouseEvent = (PPH_GRAPH_MOUSEEVENT)Header; + PPH_PROCESS_RECORD record; + + record = NULL; + + if (mouseEvent->Message == WM_LBUTTONDBLCLK && mouseEvent->Index < mouseEvent->TotalCount) + { + record = EtpReferenceMaxDiskRecord(mouseEvent->Index); + } + + if (record) + { + PhShowProcessRecordDialog(PhMainWndHandle, record); + PhDereferenceProcessRecord(record); + } + } + break; + } +} + +TOOLSTATUS_GRAPH_MESSAGE_CALLBACK_DECLARE(EtpToolbarNetworkHistoryGraphMessageCallback) +{ + switch (Header->code) + { + case GCN_GETDRAWINFO: + { + PPH_GRAPH_GETDRAWINFO getDrawInfo = (PPH_GRAPH_GETDRAWINFO)Header; + PPH_GRAPH_DRAW_INFO drawInfo = getDrawInfo->DrawInfo; + + drawInfo->Flags = PH_GRAPH_USE_GRID_X | PH_GRAPH_USE_LINE_2; + PhSiSetColorsGraphDrawInfo(drawInfo, PhGetIntegerSetting(L"ColorIoReadOther"), PhGetIntegerSetting(L"ColorIoWrite")); + + if (ProcessesUpdatedCount < 2) + return; + + PhGraphStateGetDrawInfo( + GraphState, + getDrawInfo, + EtNetworkReceiveHistory.Count + ); + + if (!GraphState->Valid) + { + ULONG i; + FLOAT max = 1024 * 1024; // Minimum scaling of 1 MB + + for (i = 0; i < drawInfo->LineDataCount; i++) + { + FLOAT data1; + FLOAT data2; + + GraphState->Data1[i] = data1 = + (FLOAT)PhGetItemCircularBuffer_ULONG(&EtNetworkReceiveHistory, i); + GraphState->Data2[i] = data2 = + (FLOAT)PhGetItemCircularBuffer_ULONG(&EtNetworkSendHistory, i); + + if (max < data1 + data2) + max = data1 + data2; + } + + if (max != 0) + { + // Scale the data. + + PhDivideSinglesBySingle( + GraphState->Data1, + max, + drawInfo->LineDataCount + ); + PhDivideSinglesBySingle( + GraphState->Data2, + max, + drawInfo->LineDataCount + ); + } + + GraphState->Valid = TRUE; + } + } + break; + case GCN_GETTOOLTIPTEXT: + { + PPH_GRAPH_GETTOOLTIPTEXT getTooltipText = (PPH_GRAPH_GETTOOLTIPTEXT)Header; + + if (getTooltipText->Index < getTooltipText->TotalCount) + { + if (GraphState->TooltipIndex != getTooltipText->Index) + { + ULONG64 networkReceive; + ULONG64 networkSend; + + networkReceive = PhGetItemCircularBuffer_ULONG(&EtNetworkReceiveHistory, getTooltipText->Index); + networkSend = PhGetItemCircularBuffer_ULONG(&EtNetworkSendHistory, getTooltipText->Index); + + PhMoveReference(&GraphState->TooltipText, PhFormatString( + L"R: %s\nS: %s%s\n%s", + PhaFormatSize(networkReceive, ULONG_MAX)->Buffer, + PhaFormatSize(networkSend, ULONG_MAX)->Buffer, + PhGetStringOrEmpty(EtpGetMaxNetworkString(getTooltipText->Index)), + ((PPH_STRING)PH_AUTO(PhGetStatisticsTimeString(NULL, getTooltipText->Index)))->Buffer + )); + } + + getTooltipText->Text = PhGetStringRef(GraphState->TooltipText); + } + } + break; + case GCN_MOUSEEVENT: + { + PPH_GRAPH_MOUSEEVENT mouseEvent = (PPH_GRAPH_MOUSEEVENT)Header; + PPH_PROCESS_RECORD record; + + record = NULL; + + if (mouseEvent->Message == WM_LBUTTONDBLCLK && mouseEvent->Index < mouseEvent->TotalCount) + { + record = EtpReferenceMaxNetworkRecord(mouseEvent->Index); + } + + if (record) + { + PhShowProcessRecordDialog(PhMainWndHandle, record); + PhDereferenceProcessRecord(record); + } + } + break; + } +} + +VOID EtRegisterToolbarGraphs( + VOID + ) +{ + PPH_PLUGIN toolStatusPlugin; + PTOOLSTATUS_INTERFACE ToolStatusInterface = NULL; + + if (toolStatusPlugin = PhFindPlugin(TOOLSTATUS_PLUGIN_NAME)) + { + ToolStatusInterface = PhGetPluginInformation(toolStatusPlugin)->Interface; + + if (ToolStatusInterface->Version < TOOLSTATUS_INTERFACE_VERSION) + ToolStatusInterface = NULL; + } + + if (ToolStatusInterface) + { + ToolStatusInterface->RegisterToolbarGraph( + PluginInstance, + 5, + L"GPU history", + EtGpuEnabled ? 0 : TOOLSTATUS_GRAPH_UNAVAILABLE, + NULL, + EtpToolbarGpuHistoryGraphMessageCallback + ); + + ToolStatusInterface->RegisterToolbarGraph( + PluginInstance, + 6, + L"Disk history", + EtEtwEnabled ? 0 : TOOLSTATUS_GRAPH_UNAVAILABLE, + NULL, + EtpToolbarDiskHistoryGraphMessageCallback + ); + + ToolStatusInterface->RegisterToolbarGraph( + PluginInstance, + 7, + L"Network history", + EtEtwEnabled ? 0 : TOOLSTATUS_GRAPH_UNAVAILABLE, + NULL, + EtpToolbarNetworkHistoryGraphMessageCallback + ); + } +} diff --git a/plugins/ExtendedTools/main.c b/plugins/ExtendedTools/main.c index 7629ebbd3131..d0bf94cc42e5 100644 --- a/plugins/ExtendedTools/main.c +++ b/plugins/ExtendedTools/main.c @@ -35,6 +35,7 @@ PH_CALLBACK_REGISTRATION PluginMenuItemCallbackRegistration; PH_CALLBACK_REGISTRATION PluginTreeNewMessageCallbackRegistration; PH_CALLBACK_REGISTRATION PluginPhSvcRequestCallbackRegistration; PH_CALLBACK_REGISTRATION MainWindowShowingCallbackRegistration; +PH_CALLBACK_REGISTRATION ProcessesUpdatedCallbackRegistration; PH_CALLBACK_REGISTRATION ProcessPropertiesInitializingCallbackRegistration; PH_CALLBACK_REGISTRATION HandlePropertiesInitializingCallbackRegistration; PH_CALLBACK_REGISTRATION ProcessMenuInitializingCallbackRegistration; @@ -45,9 +46,10 @@ PH_CALLBACK_REGISTRATION NetworkTreeNewInitializingCallbackRegistration; PH_CALLBACK_REGISTRATION SystemInformationInitializingCallbackRegistration; PH_CALLBACK_REGISTRATION MiniInformationInitializingCallbackRegistration; PH_CALLBACK_REGISTRATION TrayIconsInitializingCallbackRegistration; -PH_CALLBACK_REGISTRATION ProcessesUpdatedCallbackRegistration; +PH_CALLBACK_REGISTRATION ProcessItemsUpdatedCallbackRegistration; PH_CALLBACK_REGISTRATION NetworkItemsUpdatedCallbackRegistration; +ULONG ProcessesUpdatedCount = 0; static HANDLE ModuleProcessId = NULL; VOID NTAPI LoadCallback( @@ -147,6 +149,19 @@ VOID NTAPI MainWindowShowingCallback( ) { EtInitializeDiskTab(); + EtRegisterToolbarGraphs(); +} + +VOID NTAPI ProcessesUpdatedCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + if (ProcessesUpdatedCount < 2) + { + ProcessesUpdatedCount++; + return; + } } VOID NTAPI ProcessPropertiesInitializingCallback( @@ -318,7 +333,7 @@ VOID NTAPI TrayIconsInitializingCallback( EtRegisterNotifyIcons(Parameter); } -VOID NTAPI ProcessesUpdatedCallback( +VOID NTAPI ProcessItemsUpdatedCallback( _In_opt_ PVOID Parameter, _In_opt_ PVOID Context ) @@ -567,6 +582,13 @@ LOGICAL DllMain( NULL, &MainWindowShowingCallbackRegistration ); + PhRegisterCallback( + PhGetGeneralCallback(GeneralCallbackProcessesUpdated), + ProcessesUpdatedCallback, + NULL, + &ProcessesUpdatedCallbackRegistration + ); + PhRegisterCallback( PhGetGeneralCallback(GeneralCallbackProcessPropertiesInitializing), ProcessPropertiesInitializingCallback, @@ -631,9 +653,9 @@ LOGICAL DllMain( PhRegisterCallback( PhGetGeneralCallback(GeneralCallbackProcessProviderUpdatedEvent), - ProcessesUpdatedCallback, + ProcessItemsUpdatedCallback, NULL, - &ProcessesUpdatedCallbackRegistration + &ProcessItemsUpdatedCallbackRegistration ); PhRegisterCallback( PhGetGeneralCallback(GeneralCallbackNetworkProviderUpdatedEvent), From ad8a98741c61eeb39806a119c8863ce88391d082 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 13 Jan 2019 18:22:47 +0100 Subject: [PATCH 1539/2058] Plugins: Update ToolStatus plugin interface --- plugins/include/toolstatusintf.h | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/plugins/include/toolstatusintf.h b/plugins/include/toolstatusintf.h index 9f366f928e30..f68a12f6fb7a 100644 --- a/plugins/include/toolstatusintf.h +++ b/plugins/include/toolstatusintf.h @@ -36,6 +36,35 @@ typedef PTOOLSTATUS_TAB_INFO (NTAPI *PTOOLSTATUS_REGISTER_TAB_INFO)( _In_ INT TabIndex ); +#define TOOLSTATUS_GRAPH_ENABLED 0x1 +#define TOOLSTATUS_GRAPH_UNAVAILABLE 0x2 + +#define TOOLSTATUS_GRAPH_MESSAGE_CALLBACK_DECLARE(ToolStatusGraphCallbackName) \ +VOID ToolStatusGraphCallbackName( \ + _In_ struct _PH_TOOLBAR_GRAPH *Graph, \ + _In_ HWND GraphHandle, \ + _In_ PPH_GRAPH_STATE GraphState, \ + _In_ LPNMHDR Header, \ + _In_opt_ PVOID Context \ + ) + +typedef VOID (NTAPI *PTOOLSTATUS_GRAPH_MESSAGE_CALLBACK)( + _In_ struct _PH_TOOLBAR_GRAPH *Graph, + _In_ HWND GraphHandle, + _In_ PPH_GRAPH_STATE GraphState, + _In_ LPNMHDR Header, + _In_opt_ PVOID Context + ); + +typedef VOID (NTAPI *PTOOLSTATUS_REGISTER_TOOLBAR_GRAPH)( + _In_ struct _PH_PLUGIN *Plugin, + _In_ ULONG Id, + _In_ PWSTR Text, + _In_ ULONG Flags, + _In_opt_ PVOID Context, + _In_opt_ PTOOLSTATUS_GRAPH_MESSAGE_CALLBACK MessageCallback + ); + typedef struct _TOOLSTATUS_INTERFACE { ULONG Version; @@ -44,6 +73,7 @@ typedef struct _TOOLSTATUS_INTERFACE PTOOLSTATUS_REGISTER_TAB_SEARCH RegisterTabSearchDeprecated; PPH_CALLBACK SearchChangedEvent; PTOOLSTATUS_REGISTER_TAB_INFO RegisterTabInfo; + PTOOLSTATUS_REGISTER_TOOLBAR_GRAPH RegisterToolbarGraph; } TOOLSTATUS_INTERFACE, *PTOOLSTATUS_INTERFACE; #endif From d099dcad73019d10837066a7c7c43cc01dfe3cb0 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 13 Jan 2019 18:24:29 +0100 Subject: [PATCH 1540/2058] ToolStatus: Add reserved bits --- plugins/ToolStatus/toolstatus.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/ToolStatus/toolstatus.h b/plugins/ToolStatus/toolstatus.h index cc9165b06bdd..46e92337cd5a 100644 --- a/plugins/ToolStatus/toolstatus.h +++ b/plugins/ToolStatus/toolstatus.h @@ -115,7 +115,8 @@ typedef union _TOOLSTATUS_CONFIG ULONG ResolveGhostWindows : 1; ULONG ModernIcons : 1; ULONG AutoHideMenu : 1; - ULONG Spare : 25; + ULONG Reserved : 4; + ULONG Spare : 21; }; } TOOLSTATUS_CONFIG; From abf9ff8633a26ae0abb69f618aecf21f217d79fa Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 13 Jan 2019 18:36:15 +0100 Subject: [PATCH 1541/2058] Export PhGetPluginName --- ProcessHacker/include/phplug.h | 8 ++++++++ ProcessHacker/plugin.c | 7 +++++++ 2 files changed, 15 insertions(+) diff --git a/ProcessHacker/include/phplug.h b/ProcessHacker/include/phplug.h index a353e7bb6e50..61ac7df6a68c 100644 --- a/ProcessHacker/include/phplug.h +++ b/ProcessHacker/include/phplug.h @@ -738,6 +738,14 @@ PhPluginCallPhSvc( _Out_writes_bytes_opt_(OutLength) PVOID OutBuffer, _In_ ULONG OutLength ); + +PHAPPAPI +PPH_STRING +NTAPI +PhGetPluginName( + _In_ PPH_PLUGIN Plugin + ); + // end_phapppub #endif diff --git a/ProcessHacker/plugin.c b/ProcessHacker/plugin.c index 1ae54aba15e6..003a67b106bc 100644 --- a/ProcessHacker/plugin.c +++ b/ProcessHacker/plugin.c @@ -1034,3 +1034,10 @@ NTSTATUS PhPluginCallPhSvc( return status; } + +PPH_STRING PhGetPluginName( + _In_ PPH_PLUGIN Plugin + ) +{ + return PhCreateString2(&Plugin->Name); +} From 1d4e85545f55d5b44bd603d25f4cb47054f3ea76 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 15 Jan 2019 16:32:38 +0100 Subject: [PATCH 1542/2058] SetupTool: Fix #361 --- .../CustomSetupTool/CustomSetupTool/appsup.c | 21 ++++++++++++++++++- .../CustomSetupTool/include/setupsup.h | 5 +++++ tools/CustomSetupTool/CustomSetupTool/setup.c | 10 ++++----- 3 files changed, 30 insertions(+), 6 deletions(-) diff --git a/tools/CustomSetupTool/CustomSetupTool/appsup.c b/tools/CustomSetupTool/CustomSetupTool/appsup.c index 54655f40f367..83a26b81e022 100644 --- a/tools/CustomSetupTool/CustomSetupTool/appsup.c +++ b/tools/CustomSetupTool/CustomSetupTool/appsup.c @@ -391,7 +391,7 @@ BOOLEAN CheckProcessHackerInstalled( if (!PhIsNullOrEmptyString(installPath)) { - exePath = PhConcatStrings2(installPath->Buffer, L"\\ProcessHacker.exe"); + exePath = SetupCreateFullPath(installPath, L"\\ProcessHacker.exe"); // Check if the value has a valid file path. installed = GetFileAttributes(PhGetString(exePath)) != INVALID_FILE_ATTRIBUTES; @@ -556,3 +556,22 @@ NTSTATUS QueryProcessesUsingVolumeOrFile( return status; } + +PPH_STRING SetupCreateFullPath( + _In_ PPH_STRING Path, + _In_ PWSTR FileName + ) +{ + PPH_STRING pathString; + PPH_STRING tempString; + + pathString = PhConcatStrings2(PhGetString(Path), FileName); + + if (NT_SUCCESS(PhGetFullPathEx(pathString->Buffer, NULL, &tempString))) + { + PhMoveReference(&pathString, tempString); + return pathString; + } + + return pathString; +} diff --git a/tools/CustomSetupTool/CustomSetupTool/include/setupsup.h b/tools/CustomSetupTool/CustomSetupTool/include/setupsup.h index 876bc9cbe89e..a766ce646206 100644 --- a/tools/CustomSetupTool/CustomSetupTool/include/setupsup.h +++ b/tools/CustomSetupTool/CustomSetupTool/include/setupsup.h @@ -79,4 +79,9 @@ QueryProcessesUsingVolumeOrFile( _Out_ PFILE_PROCESS_IDS_USING_FILE_INFORMATION *Information ); +PPH_STRING SetupCreateFullPath( + _In_ PPH_STRING Path, + _In_ PWSTR FileName + ); + #endif diff --git a/tools/CustomSetupTool/CustomSetupTool/setup.c b/tools/CustomSetupTool/CustomSetupTool/setup.c index 7da59e7801db..b0d506746ee9 100644 --- a/tools/CustomSetupTool/CustomSetupTool/setup.c +++ b/tools/CustomSetupTool/CustomSetupTool/setup.c @@ -54,7 +54,7 @@ NTSTATUS SetupCreateUninstallKey( { PPH_STRING tempString; - tempString = PhConcatStrings2(PhGetString(SetupInstallPath), L"\\processhacker.exe,0"); + tempString = SetupCreateFullPath(SetupInstallPath, L"\\processhacker.exe,0"); PhStringRefToUnicodeString(&tempString->sr, &value); RtlInitUnicodeString(&name, L"DisplayIcon"); PhStringRefToUnicodeString(&tempString->sr, &value); @@ -427,7 +427,7 @@ VOID SetupStartKph( { PPH_STRING clientPath; - clientPath = PhConcatStrings2(PhGetString(SetupInstallPath), L"\\ProcessHacker.exe"); + clientPath = SetupCreateFullPath(SetupInstallPath, L"\\ProcessHacker.exe"); if (RtlDoesFileExists_U(PhGetString(clientPath))) { @@ -464,7 +464,7 @@ BOOLEAN SetupUninstallKph( Context->SetupKphInstallRequired = SetupKphCheckInstallState(); // Stop and uninstall the current installation. - clientPath = PhConcatStrings2(PhGetString(SetupInstallPath), L"\\ProcessHacker.exe"); + clientPath = SetupCreateFullPath(SetupInstallPath, L"\\ProcessHacker.exe"); if (RtlDoesFileExists_U(PhGetString(clientPath))) { @@ -503,7 +503,7 @@ VOID SetupSetWindowsOptions( PPH_STRING clientPathString; PPH_STRING startmenuFolderString; - clientPathString = PhConcatStrings2(PhGetString(SetupInstallPath), L"\\ProcessHacker.exe"); + clientPathString = SetupCreateFullPath(SetupInstallPath, L"\\ProcessHacker.exe"); // Create the startmenu shortcut. // PhGetKnownLocation(CSIDL_COMMON_PROGRAMS, L"\\Process Hacker.lnk")) @@ -758,7 +758,7 @@ BOOLEAN SetupExecuteProcessHacker( BOOLEAN success = FALSE; PPH_STRING clientPath; - clientPath = PhConcatStrings2(PhGetString(SetupInstallPath), L"\\ProcessHacker.exe"); + clientPath = SetupCreateFullPath(SetupInstallPath, L"\\ProcessHacker.exe"); if (RtlDoesFileExists_U(clientPath->Buffer)) { From 9d46983cda9e3d21ae241754ec161194241c938a Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 15 Jan 2019 21:33:01 +0100 Subject: [PATCH 1543/2058] Update macro usage, Remove deprecated ChangeWindowMessageFilter --- ProcessHacker/mainwnd.c | 46 ++++++++++++++++++++--------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index f7343e693a4f..b80d6abee86b 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -192,7 +192,7 @@ BOOLEAN PhMainWndInitialization( UpdateWindow(PhMainWndHandle); // Allow WM_PH_ACTIVATE to pass through UIPI. - ChangeWindowMessageFilter(WM_PH_ACTIVATE, MSGFLT_ADD); + ChangeWindowMessageFilterEx(PhMainWndHandle, WM_PH_ACTIVATE, MSGFLT_ADD, NULL); PhMwpOnSettingChange(); @@ -211,7 +211,7 @@ BOOLEAN PhMainWndInitialization( PhQueueItemWorkQueue(PhGetGlobalWorkQueue(), PhMwpLoadStage1Worker, NULL); // Perform a layout. - PhMwpSelectionChangedTabControl(-1); + PhMwpSelectionChangedTabControl(ULONG_MAX); PhMwpOnSize(); if ((PhStartupParameters.ShowHidden || PhGetIntegerSetting(L"StartHidden")) && PhNfIconsEnabled()) @@ -2579,7 +2579,7 @@ VOID PhMwpInitializeSubMenu( PPH_NF_ICON icon = PhTrayIconItemList->Items[i]; menuItem = PhCreateEMenuItem(0, ID_TRAYICONS_REGISTERED, icon->Text, NULL, icon); - PhInsertEMenuItem(trayIconsMenuItem, menuItem, -1); + PhInsertEMenuItem(trayIconsMenuItem, menuItem, ULONG_MAX); // Update the text and check marks on the menu items. @@ -2631,11 +2631,11 @@ VOID PhMwpInitializeSubMenu( id = ID_UPDATEINTERVAL_VERYSLOW; break; default: - id = -1; + id = ULONG_MAX; break; } - if (id != -1 && (menuItem = PhFindEMenuItem(Menu, PH_EMENU_FIND_DESCEND, NULL, id))) + if (id != ULONG_MAX && (menuItem = PhFindEMenuItem(Menu, PH_EMENU_FIND_DESCEND, NULL, id))) menuItem->Flags |= PH_EMENU_CHECKED | PH_EMENU_RADIOCHECK; if (PhMwpUpdateAutomatically && (menuItem = PhFindEMenuItem(Menu, 0, NULL, ID_VIEW_UPDATEAUTOMATICALLY))) @@ -2917,25 +2917,25 @@ VOID PhAddMiniProcessMenuItems( priorityMenu = PhCreateEMenuItem(0, 0, L"&Priority", NULL, ProcessId); - PhInsertEMenuItem(priorityMenu, PhCreateEMenuItem(0, ID_PRIORITY_REALTIME, L"&Real time", NULL, ProcessId), -1); - PhInsertEMenuItem(priorityMenu, PhCreateEMenuItem(0, ID_PRIORITY_HIGH, L"&High", NULL, ProcessId), -1); - PhInsertEMenuItem(priorityMenu, PhCreateEMenuItem(0, ID_PRIORITY_ABOVENORMAL, L"&Above normal", NULL, ProcessId), -1); - PhInsertEMenuItem(priorityMenu, PhCreateEMenuItem(0, ID_PRIORITY_NORMAL, L"&Normal", NULL, ProcessId), -1); - PhInsertEMenuItem(priorityMenu, PhCreateEMenuItem(0, ID_PRIORITY_BELOWNORMAL, L"&Below normal", NULL, ProcessId), -1); - PhInsertEMenuItem(priorityMenu, PhCreateEMenuItem(0, ID_PRIORITY_IDLE, L"&Idle", NULL, ProcessId), -1); + PhInsertEMenuItem(priorityMenu, PhCreateEMenuItem(0, ID_PRIORITY_REALTIME, L"&Real time", NULL, ProcessId), ULONG_MAX); + PhInsertEMenuItem(priorityMenu, PhCreateEMenuItem(0, ID_PRIORITY_HIGH, L"&High", NULL, ProcessId), ULONG_MAX); + PhInsertEMenuItem(priorityMenu, PhCreateEMenuItem(0, ID_PRIORITY_ABOVENORMAL, L"&Above normal", NULL, ProcessId), ULONG_MAX); + PhInsertEMenuItem(priorityMenu, PhCreateEMenuItem(0, ID_PRIORITY_NORMAL, L"&Normal", NULL, ProcessId), ULONG_MAX); + PhInsertEMenuItem(priorityMenu, PhCreateEMenuItem(0, ID_PRIORITY_BELOWNORMAL, L"&Below normal", NULL, ProcessId), ULONG_MAX); + PhInsertEMenuItem(priorityMenu, PhCreateEMenuItem(0, ID_PRIORITY_IDLE, L"&Idle", NULL, ProcessId), ULONG_MAX); // I/O priority ioPriorityMenu = PhCreateEMenuItem(0, 0, L"&I/O priority", NULL, ProcessId); - PhInsertEMenuItem(ioPriorityMenu, PhCreateEMenuItem(0, ID_IOPRIORITY_HIGH, L"&High", NULL, ProcessId), -1); - PhInsertEMenuItem(ioPriorityMenu, PhCreateEMenuItem(0, ID_IOPRIORITY_NORMAL, L"&Normal", NULL, ProcessId), -1); - PhInsertEMenuItem(ioPriorityMenu, PhCreateEMenuItem(0, ID_IOPRIORITY_LOW, L"&Low", NULL, ProcessId), -1); - PhInsertEMenuItem(ioPriorityMenu, PhCreateEMenuItem(0, ID_IOPRIORITY_VERYLOW, L"&Very low", NULL, ProcessId), -1); + PhInsertEMenuItem(ioPriorityMenu, PhCreateEMenuItem(0, ID_IOPRIORITY_HIGH, L"&High", NULL, ProcessId), ULONG_MAX); + PhInsertEMenuItem(ioPriorityMenu, PhCreateEMenuItem(0, ID_IOPRIORITY_NORMAL, L"&Normal", NULL, ProcessId), ULONG_MAX); + PhInsertEMenuItem(ioPriorityMenu, PhCreateEMenuItem(0, ID_IOPRIORITY_LOW, L"&Low", NULL, ProcessId), ULONG_MAX); + PhInsertEMenuItem(ioPriorityMenu, PhCreateEMenuItem(0, ID_IOPRIORITY_VERYLOW, L"&Very low", NULL, ProcessId), ULONG_MAX); // Menu - PhInsertEMenuItem(Menu, PhCreateEMenuItem(0, ID_PROCESS_TERMINATE, L"T&erminate", NULL, ProcessId), -1); + PhInsertEMenuItem(Menu, PhCreateEMenuItem(0, ID_PROCESS_TERMINATE, L"T&erminate", NULL, ProcessId), ULONG_MAX); if (processItem = PhReferenceProcessItem(ProcessId)) { @@ -2945,18 +2945,18 @@ VOID PhAddMiniProcessMenuItems( } if (!isSuspended) - PhInsertEMenuItem(Menu, PhCreateEMenuItem(0, ID_PROCESS_SUSPEND, L"&Suspend", NULL, ProcessId), -1); + PhInsertEMenuItem(Menu, PhCreateEMenuItem(0, ID_PROCESS_SUSPEND, L"&Suspend", NULL, ProcessId), ULONG_MAX); if (isPartiallySuspended) - PhInsertEMenuItem(Menu, PhCreateEMenuItem(0, ID_PROCESS_RESUME, L"Res&ume", NULL, ProcessId), -1); + PhInsertEMenuItem(Menu, PhCreateEMenuItem(0, ID_PROCESS_RESUME, L"Res&ume", NULL, ProcessId), ULONG_MAX); - PhInsertEMenuItem(Menu, priorityMenu, -1); + PhInsertEMenuItem(Menu, priorityMenu, ULONG_MAX); if (ioPriorityMenu) - PhInsertEMenuItem(Menu, ioPriorityMenu, -1); + PhInsertEMenuItem(Menu, ioPriorityMenu, ULONG_MAX); PhMwpSetProcessMenuPriorityChecks(Menu, ProcessId, TRUE, TRUE, FALSE); - PhInsertEMenuItem(Menu, PhCreateEMenuItem(0, ID_PROCESS_PROPERTIES, L"P&roperties", NULL, ProcessId), -1); + PhInsertEMenuItem(Menu, PhCreateEMenuItem(0, ID_PROCESS_PROPERTIES, L"P&roperties", NULL, ProcessId), ULONG_MAX); } BOOLEAN PhHandleMiniProcessMenuItem( @@ -3144,7 +3144,7 @@ VOID PhMwpAddIconProcesses( subMenu->Flags |= PH_EMENU_BITMAP_OWNED; // automatically destroy the bitmap when necessary PhAddMiniProcessMenuItems(subMenu, processItem->ProcessId); - PhInsertEMenuItem(Menu, subMenu, -1); + PhInsertEMenuItem(Menu, subMenu, ULONG_MAX); } PhDereferenceObject(processList); @@ -3436,7 +3436,7 @@ VOID PhMwpUpdateUsersMenu( UlongToPtr(sessions[i].SessionId) ); PhLoadResourceEMenuItem(userMenu, PhInstanceHandle, MAKEINTRESOURCE(IDR_USER), 0); - PhInsertEMenuItem(UsersMenu, userMenu, -1); + PhInsertEMenuItem(UsersMenu, userMenu, ULONG_MAX); PhDereferenceObject(escapedMenuText); } From e5763f8e7c404c0f1767162444a2904bfd5fb38b Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 15 Jan 2019 21:35:54 +0100 Subject: [PATCH 1544/2058] peview: Add dynamic properties tab for ELF binaries, Add more copy menus --- tools/peview/attributes.c | 10 +- tools/peview/clrprp.c | 15 +- tools/peview/exlfdynamic.c | 231 ++++++++++++++++++++++++++++ tools/peview/exlfexports.c | 11 +- tools/peview/exlfimports.c | 15 +- tools/peview/exlfprp.c | 13 ++ tools/peview/include/peview.h | 7 + tools/peview/libprp.c | 5 + tools/peview/peview.rc | 8 + tools/peview/peview.vcxproj | 1 + tools/peview/peview.vcxproj.filters | 3 + tools/peview/resource.h | 3 +- tools/peview/settings.c | 5 + 13 files changed, 311 insertions(+), 16 deletions(-) create mode 100644 tools/peview/exlfdynamic.c diff --git a/tools/peview/attributes.c b/tools/peview/attributes.c index 996545483c37..31c663c76e17 100644 --- a/tools/peview/attributes.c +++ b/tools/peview/attributes.c @@ -38,10 +38,13 @@ BOOLEAN NTAPI PvpEnumFileAttributesCallback( INT lvItemIndex; WCHAR number[PH_INT32_STR_LEN_1]; + if (Information->EaNameLength == 0) + return TRUE; + PhPrintUInt32(number, ++context->Count); lvItemIndex = PhAddListViewItem(context->ListViewHandle, MAXINT, number, NULL); - attributeName = PhZeroExtendToUtf16(Information->EaName); + attributeName = PhZeroExtendToUtf16Ex(Information->EaName, Information->EaNameLength); PhSetListViewSubItem( context->ListViewHandle, lvItemIndex, @@ -137,6 +140,11 @@ INT_PTR CALLBACK PvpPeExtendedAttributesDlgProc( PvHandleListViewNotifyForCopy(lParam, GetDlgItem(hwndDlg, IDC_LIST)); } break; + case WM_CONTEXTMENU: + { + PvHandleListViewCommandCopy(hwndDlg, lParam, wParam, GetDlgItem(hwndDlg, IDC_LIST)); + } + break; } return FALSE; diff --git a/tools/peview/clrprp.c b/tools/peview/clrprp.c index 7ef8491697a1..2846ed89727a 100644 --- a/tools/peview/clrprp.c +++ b/tools/peview/clrprp.c @@ -185,10 +185,8 @@ INT_PTR CALLBACK PvpPeClrDlgProc( { PPH_LAYOUT_ITEM dialogItem; - dialogItem = PvAddPropPageLayoutItem(hwndDlg, hwndDlg, - PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL); - PvAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_LIST), - dialogItem, PH_ANCHOR_ALL); + dialogItem = PvAddPropPageLayoutItem(hwndDlg, hwndDlg, PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL); + PvAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_LIST), dialogItem, PH_ANCHOR_ALL); PvDoPropPageLayout(hwndDlg); @@ -208,9 +206,16 @@ INT_PTR CALLBACK PvpPeClrDlgProc( } return TRUE; } + + PvHandleListViewNotifyForCopy(lParam, GetDlgItem(hwndDlg, IDC_LIST)); + } + break; + case WM_CONTEXTMENU: + { + PvHandleListViewCommandCopy(hwndDlg, lParam, wParam, GetDlgItem(hwndDlg, IDC_LIST)); } break; } return FALSE; -} \ No newline at end of file +} diff --git a/tools/peview/exlfdynamic.c b/tools/peview/exlfdynamic.c new file mode 100644 index 000000000000..44c84f324d28 --- /dev/null +++ b/tools/peview/exlfdynamic.c @@ -0,0 +1,231 @@ +/* + * Process Hacker - + * PE viewer + * + * Copyright (C) 2019 dmex + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include + +PWSTR PvpGetDynamicTagName( + _In_ LONGLONG Tag + ) +{ + switch (Tag) + { + case DT_NULL: + return L"NULL"; + case DT_NEEDED: + return L"NEEDED"; + case DT_PLTRELSZ: + return L"PLTRELSZ"; + case DT_PLTGOT: + return L"PLTGOT"; + case DT_HASH: + return L"HASH"; + case DT_STRTAB: + return L"STRTAB"; + case DT_SYMTAB: + return L"SYMTAB"; + case DT_RELA: + return L"RELA"; + case DT_RELASZ: + return L"RELASZ"; + case DT_RELAENT: + return L"RELAENT"; + case DT_STRSZ: + return L"STRSZ"; + case DT_SYMENT: + return L"SYMENT"; + case DT_INIT: + return L"INIT"; + case DT_FINI: + return L"FINI"; + case DT_SONAME: + return L"SONAME"; + case DT_RPATH: + return L"RPATH"; + case DT_SYMBOLIC: + return L"SYMBOLIC"; + case DT_REL: + return L"REL"; + case DT_RELSZ: + return L"RELSZ"; + case DT_RELENT: + return L"RELENT"; + case DT_PLTREL: + return L"PLTREL"; + case DT_DEBUG: + return L"DEBUG"; + case DT_TEXTREL: + return L"TEXTREL"; + case DT_JMPREL: + return L"JMPREL"; + case DT_INIT_ARRAY: + return L"INIT_ARRAY"; + case DT_FINI_ARRAY: + return L"FINI_ARRAY"; + case DT_INIT_ARRAYSZ: + return L"INIT_ARRAYSZ"; + case DT_FINI_ARRAYSZ: + return L"FINI_ARRAYSZ"; + case DT_FLAGS: + return L"FLAGS"; + case DT_PREINIT_ARRAY: + return L"PREINIT_ARRAY"; + case DT_PREINIT_ARRAYSZ: + return L"PREINIT_ARRAYSZ"; + case OLD_DT_LOOS: + return L"OLD_DT_LOOS"; + case DT_LOOS: + return L"LOOS"; + case DT_HIOS: + return L"HIOS"; + case DT_VALRNGLO: + return L"VALRNGLO"; + case DT_VALRNGHI: + return L"VALRNGHI"; + case DT_ADDRRNGLO: + return L"ADDRRNGLO"; + case DT_ADDRRNGHI: + return L"ADDRRNGHI"; + case DT_GNU_HASH: + return L"GNU_HASH"; + case DT_VERSYM: + return L"VERSYM"; + case DT_RELACOUNT: + return L"RELACOUNT"; + case DT_RELCOUNT: + return L"RELCOUNT"; + case DT_FLAGS_1: + return L"FLAGS_1"; + case DT_VERDEF: + return L"VERDEF"; + case DT_VERDEFNUM: + return L"VERDEFNUM"; + case DT_VERNEED: + return L"VERNEED"; + case DT_VERNEEDNUM: + return L"VERNEEDNUM"; + case DT_LOPROC: + return L"LOPROC"; + case DT_HIPROC: + return L"HIPROC"; + } + + return L"***ERROR***"; +} + +VOID PvpProcessElfDynamic( + _In_ HWND ListViewHandle + ) +{ + PPH_LIST dynamics; + ULONG count = 0; + + PhGetMappedWslImageDynamic(&PvMappedImage, &dynamics); + + for (ULONG i = 0; i < dynamics->Count; i++) + { + PPH_ELF_IMAGE_DYNAMIC_ENTRY dynamic = dynamics->Items[i]; + INT lvItemIndex; + WCHAR number[PH_INT32_STR_LEN_1]; + WCHAR pointer[PH_PTR_STR_LEN_1]; + + PhPrintUInt32(number, ++count); + lvItemIndex = PhAddListViewItem(ListViewHandle, MAXINT, number, NULL); + + PhPrintPointer(pointer, (PVOID)dynamic->Tag); + PhSetListViewSubItem(ListViewHandle, lvItemIndex, 1, pointer); + //PhSetListViewSubItem(ListViewHandle, lvItemIndex, 1, PhaFormatString(L"0x%016llx", (PVOID)dynamic->Tag)->Buffer); + PhSetListViewSubItem(ListViewHandle, lvItemIndex, 2, PvpGetDynamicTagName(dynamic->Tag)); + PhSetListViewSubItem(ListViewHandle, lvItemIndex, 3, PhGetStringOrEmpty(dynamic->Value)); + } + + PhFreeMappedWslImageDynamic(dynamics); +} + +INT_PTR CALLBACK PvpExlfDynamicDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + LPPROPSHEETPAGE propSheetPage; + PPV_PROPPAGECONTEXT propPageContext; + + if (!PvPropPageDlgProcHeader(hwndDlg, uMsg, lParam, &propSheetPage, &propPageContext)) + return FALSE; + + switch (uMsg) + { + case WM_INITDIALOG: + { + HWND lvHandle; + + lvHandle = GetDlgItem(hwndDlg, IDC_LIST); + PhSetListViewStyle(lvHandle, TRUE, TRUE); + PhSetControlTheme(lvHandle, L"explorer"); + PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 40, L"#"); + PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_RIGHT, 80, L"Tag"); + PhAddListViewColumn(lvHandle, 2, 2, 2, LVCFMT_LEFT, 150, L"Type"); + PhAddListViewColumn(lvHandle, 3, 3, 3, LVCFMT_LEFT, 250, L"Value"); + PhSetExtendedListView(lvHandle); + PhLoadListViewColumnsFromSetting(L"DynamicWslListViewColumns", lvHandle); + + PvpProcessElfDynamic(lvHandle); + ExtendedListView_SortItems(lvHandle); + + EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); + } + break; + case WM_DESTROY: + { + PhSaveListViewColumnsToSetting(L"DynamicWslListViewColumns", GetDlgItem(hwndDlg, IDC_LIST)); + } + break; + case WM_SHOWWINDOW: + { + if (!propPageContext->LayoutInitialized) + { + PPH_LAYOUT_ITEM dialogItem; + + dialogItem = PvAddPropPageLayoutItem(hwndDlg, hwndDlg, PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL); + PvAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_LIST), dialogItem, PH_ANCHOR_ALL); + + PvDoPropPageLayout(hwndDlg); + + propPageContext->LayoutInitialized = TRUE; + } + } + break; + case WM_NOTIFY: + { + PvHandleListViewNotifyForCopy(lParam, GetDlgItem(hwndDlg, IDC_LIST)); + } + break; + case WM_CONTEXTMENU: + { + PvHandleListViewCommandCopy(hwndDlg, lParam, wParam, GetDlgItem(hwndDlg, IDC_LIST)); + } + break; + } + + return FALSE; +} diff --git a/tools/peview/exlfexports.c b/tools/peview/exlfexports.c index 36d65bd21539..1ac15f790432 100644 --- a/tools/peview/exlfexports.c +++ b/tools/peview/exlfexports.c @@ -81,11 +81,11 @@ INT_PTR CALLBACK PvpExlfExportsDlgProc( PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 40, L"#"); PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_RIGHT, 80, L"RVA"); PhAddListViewColumn(lvHandle, 2, 2, 2, LVCFMT_LEFT, 250, L"Name"); - PhAddListViewColumn(lvHandle, 3, 3, 3, LVCFMT_LEFT, 250, L"Size"); + PhAddListViewColumn(lvHandle, 3, 3, 3, LVCFMT_LEFT, 80, L"Size"); PhAddListViewColumn(lvHandle, 4, 4, 4, LVCFMT_LEFT, 80, L"Type"); PhAddListViewColumn(lvHandle, 5, 5, 5, LVCFMT_LEFT, 80, L"Binding"); PhSetExtendedListView(lvHandle); - PhLoadListViewColumnsFromSetting(L"ImageExportsListViewColumns", lvHandle); + PhLoadListViewColumnsFromSetting(L"ExportsWslListViewColumns", lvHandle); PvpProcessElfExports(lvHandle); ExtendedListView_SortItems(lvHandle); @@ -95,7 +95,7 @@ INT_PTR CALLBACK PvpExlfExportsDlgProc( break; case WM_DESTROY: { - PhSaveListViewColumnsToSetting(L"ImageExportsListViewColumns", GetDlgItem(hwndDlg, IDC_LIST)); + PhSaveListViewColumnsToSetting(L"ExportsWslListViewColumns", GetDlgItem(hwndDlg, IDC_LIST)); } break; case WM_SHOWWINDOW: @@ -120,6 +120,11 @@ INT_PTR CALLBACK PvpExlfExportsDlgProc( PvHandleListViewNotifyForCopy(lParam, GetDlgItem(hwndDlg, IDC_LIST)); } break; + case WM_CONTEXTMENU: + { + PvHandleListViewCommandCopy(hwndDlg, lParam, wParam, GetDlgItem(hwndDlg, IDC_LIST)); + } + break; } return FALSE; diff --git a/tools/peview/exlfimports.c b/tools/peview/exlfimports.c index 9e6368e40968..7f214e1d61c7 100644 --- a/tools/peview/exlfimports.c +++ b/tools/peview/exlfimports.c @@ -80,7 +80,7 @@ INT_PTR CALLBACK PvpExlfImportsDlgProc( PhAddListViewColumn(lvHandle, 3, 3, 3, LVCFMT_LEFT, 100, L"Type"); PhAddListViewColumn(lvHandle, 4, 4, 4, LVCFMT_LEFT, 80, L"Binding"); PhSetExtendedListView(lvHandle); - PhLoadListViewColumnsFromSetting(L"ImageImportsListViewColumns", lvHandle); + PhLoadListViewColumnsFromSetting(L"ImportsWslListViewColumns", lvHandle); PvpProcessElfImports(lvHandle); ExtendedListView_SortItems(lvHandle); @@ -90,7 +90,7 @@ INT_PTR CALLBACK PvpExlfImportsDlgProc( break; case WM_DESTROY: { - PhSaveListViewColumnsToSetting(L"ImageImportsListViewColumns", GetDlgItem(hwndDlg, IDC_LIST)); + PhSaveListViewColumnsToSetting(L"ImportsWslListViewColumns", GetDlgItem(hwndDlg, IDC_LIST)); } break; case WM_SHOWWINDOW: @@ -99,10 +99,8 @@ INT_PTR CALLBACK PvpExlfImportsDlgProc( { PPH_LAYOUT_ITEM dialogItem; - dialogItem = PvAddPropPageLayoutItem(hwndDlg, hwndDlg, - PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL); - PvAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_LIST), - dialogItem, PH_ANCHOR_ALL); + dialogItem = PvAddPropPageLayoutItem(hwndDlg, hwndDlg, PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL); + PvAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_LIST), dialogItem, PH_ANCHOR_ALL); PvDoPropPageLayout(hwndDlg); @@ -115,6 +113,11 @@ INT_PTR CALLBACK PvpExlfImportsDlgProc( PvHandleListViewNotifyForCopy(lParam, GetDlgItem(hwndDlg, IDC_LIST)); } break; + case WM_CONTEXTMENU: + { + PvHandleListViewCommandCopy(hwndDlg, lParam, wParam, GetDlgItem(hwndDlg, IDC_LIST)); + } + break; } return FALSE; diff --git a/tools/peview/exlfprp.c b/tools/peview/exlfprp.c index 40680502a4ca..fac891449606 100644 --- a/tools/peview/exlfprp.c +++ b/tools/peview/exlfprp.c @@ -88,6 +88,14 @@ VOID PvExlfProperties( ); PvAddPropPage(propContext, newPage); + // Dynamic + newPage = PvCreatePropPageContext( + MAKEINTRESOURCE(IDD_ELFDYNAMIC), + PvpExlfDynamicDlgProc, + NULL + ); + PvAddPropPage(propContext, newPage); + // Imports newPage = PvCreatePropPageContext( MAKEINTRESOURCE(IDD_PEIMPORTS), @@ -410,6 +418,11 @@ INT_PTR CALLBACK PvpExlfGeneralDlgProc( PvHandleListViewNotifyForCopy(lParam, GetDlgItem(hwndDlg, IDC_LIST)); } break; + case WM_CONTEXTMENU: + { + PvHandleListViewCommandCopy(hwndDlg, lParam, wParam, GetDlgItem(hwndDlg, IDC_LIST)); + } + break; } return FALSE; diff --git a/tools/peview/include/peview.h b/tools/peview/include/peview.h index cc336b00f720..705ab2bd921c 100644 --- a/tools/peview/include/peview.h +++ b/tools/peview/include/peview.h @@ -388,4 +388,11 @@ INT_PTR CALLBACK PvpExlfExportsDlgProc( _In_ LPARAM lParam ); +INT_PTR CALLBACK PvpExlfDynamicDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam +); + #endif diff --git a/tools/peview/libprp.c b/tools/peview/libprp.c index 6f8b89a1b1ef..e75e0acb58f5 100644 --- a/tools/peview/libprp.c +++ b/tools/peview/libprp.c @@ -198,6 +198,11 @@ INT_PTR CALLBACK PvpLibExportsDlgProc( PvHandleListViewNotifyForCopy(lParam, GetDlgItem(hwndDlg, IDC_LIST)); } break; + case WM_CONTEXTMENU: + { + PvHandleListViewCommandCopy(hwndDlg, lParam, wParam, GetDlgItem(hwndDlg, IDC_LIST)); + } + break; } return FALSE; diff --git a/tools/peview/peview.rc b/tools/peview/peview.rc index 2d918540ed14..a5d6b1c488cd 100644 --- a/tools/peview/peview.rc +++ b/tools/peview/peview.rc @@ -310,6 +310,14 @@ BEGIN CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,3,3,294,274 END +IDD_ELFDYNAMIC DIALOGEX 0, 0, 300, 280 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Dynamic" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,3,3,294,274 +END + ///////////////////////////////////////////////////////////////////////////// // diff --git a/tools/peview/peview.vcxproj b/tools/peview/peview.vcxproj index f8a3a1fc5dc2..cb2b87ceb425 100644 --- a/tools/peview/peview.vcxproj +++ b/tools/peview/peview.vcxproj @@ -223,6 +223,7 @@ + diff --git a/tools/peview/peview.vcxproj.filters b/tools/peview/peview.vcxproj.filters index ab6017350727..eef3cad98d3b 100644 --- a/tools/peview/peview.vcxproj.filters +++ b/tools/peview/peview.vcxproj.filters @@ -90,6 +90,9 @@ Source Files\Pages + + Source Files\Pages\Linux + diff --git a/tools/peview/resource.h b/tools/peview/resource.h index 5d9e91897c41..7203b0fb9b41 100644 --- a/tools/peview/resource.h +++ b/tools/peview/resource.h @@ -19,6 +19,7 @@ #define IDD_PEATTR 112 #define IDB_SEARCH_INACTIVE_BMP 113 #define IDD_PESTREAMS 113 +#define IDD_ELFDYNAMIC 116 #define IDC_SYMBOLTREE 119 #define IDC_TARGETMACHINE 1003 #define IDC_CHECKSUM 1004 @@ -45,7 +46,7 @@ // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 121 +#define _APS_NEXT_RESOURCE_VALUE 122 #define _APS_NEXT_COMMAND_VALUE 40001 #define _APS_NEXT_CONTROL_VALUE 1023 #define _APS_NEXT_SYMED_VALUE 115 diff --git a/tools/peview/settings.c b/tools/peview/settings.c index a1e3fb706567..4062287774e7 100644 --- a/tools/peview/settings.c +++ b/tools/peview/settings.c @@ -47,11 +47,16 @@ VOID PhAddDefaultSettings( PhpAddStringSetting(L"ImageAttributesListViewColumns", L""); PhpAddStringSetting(L"ImagePropertiesListViewColumns", L""); PhpAddStringSetting(L"ImageStreamsListViewColumns", L""); + PhpAddStringSetting(L"ImageHardLinksListViewColumns", L""); + PhpAddStringSetting(L"ImagePidsListViewColumns", L""); PhpAddStringSetting(L"LibListViewColumns", L""); PhpAddStringSetting(L"PdbTreeListColumns", L""); // Wsl properties PhpAddStringSetting(L"GeneralWslTreeListColumns", L""); + PhpAddStringSetting(L"DynamicWslListViewColumns", L""); + PhpAddStringSetting(L"ImportsWslListViewColumns", L""); + PhpAddStringSetting(L"ExportsWslListViewColumns", L""); } VOID PhUpdateCachedSettings( From 3327d87f599d113142382e8fb5712e94fc26d841 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 15 Jan 2019 22:38:23 +0100 Subject: [PATCH 1545/2058] Add PhGetMappedWslImageDynamic --- phlib/include/exlf.h | 58 +++++++++++++++++++------- phlib/include/mapimg.h | 20 ++++++++- phlib/mapexlf.c | 94 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 154 insertions(+), 18 deletions(-) diff --git a/phlib/include/exlf.h b/phlib/include/exlf.h index 35ad1c93b7a1..143a6a60fe11 100644 --- a/phlib/include/exlf.h +++ b/phlib/include/exlf.h @@ -157,32 +157,39 @@ #define DT_SONAME 14 #define DT_RPATH 15 #define DT_SYMBOLIC 16 -#define DT_REL 17 +#define DT_REL 17 #define DT_RELSZ 18 #define DT_RELENT 19 #define DT_PLTREL 20 #define DT_DEBUG 21 #define DT_TEXTREL 22 #define DT_JMPREL 23 -#define DT_ENCODING 32 +#define DT_INIT_ARRAY 25 +#define DT_FINI_ARRAY 26 +#define DT_INIT_ARRAYSZ 27 +#define DT_FINI_ARRAYSZ 28 +#define DT_FLAGS 30 +#define DT_PREINIT_ARRAY 32 // DT_ENCODING +#define DT_PREINIT_ARRAYSZ 33 #define OLD_DT_LOOS 0x60000000 -#define DT_LOOS 0x6000000d -#define DT_HIOS 0x6ffff000 +#define DT_LOOS 0x6000000d +#define DT_HIOS 0x6ffff000 #define DT_VALRNGLO 0x6ffffd00 #define DT_VALRNGHI 0x6ffffdff -#define DT_ADDRRNGLO 0x6ffffe00 -#define DT_ADDRRNGHI 0x6ffffeff -#define DT_VERSYM 0x6ffffff0 -#define DT_RELACOUNT 0x6ffffff9 +#define DT_ADDRRNGLO 0x6ffffe00 +#define DT_ADDRRNGHI 0x6ffffeff +#define DT_GNU_HASH 0x6ffffef5 +#define DT_VERSYM 0x6ffffff0 +#define DT_RELACOUNT 0x6ffffff9 #define DT_RELCOUNT 0x6ffffffa -#define DT_FLAGS_1 0x6ffffffb -#define DT_VERDEF 0x6ffffffc -#define DT_VERDEFNUM 0x6ffffffd -#define DT_VERNEED 0x6ffffffe -#define DT_VERNEEDNUM 0x6fffffff -#define OLD_DT_HIOS 0x6fffffff -#define DT_LOPROC 0x70000000 -#define DT_HIPROC 0x7fffffff +#define DT_FLAGS_1 0x6ffffffb +#define DT_VERDEF 0x6ffffffc +#define DT_VERDEFNUM 0x6ffffffd +#define DT_VERNEED 0x6ffffffe +#define DT_VERNEEDNUM 0x6fffffff +#define OLD_DT_HIOS 0x6fffffff +#define DT_LOPROC 0x70000000 +#define DT_HIPROC 0x7fffffff // symbol table section #define STB_LOCAL 0 /* Local symbol */ @@ -423,4 +430,23 @@ typedef struct _ELF_VERSION_AUX // Elf_Vernaux unsigned int vna_next; } ELF_VERSION_AUX, *PELF_VERSION_AUX; +typedef struct _ELF_EXTERNAL_NOTE // Elf_External_Note +{ + unsigned char namesz[4]; /* Size of entry's owner string */ + unsigned char descsz[4]; /* Size of the note descriptor */ + unsigned char type[4]; /* Interpretation of the descriptor */ + char name[1]; /* Start of the name+desc data */ + //char desc[1]; +} ELF_EXTERNAL_NOTE, *PELF_EXTERNAL_NOTE; + +typedef struct elf_internal_note { + unsigned long namesz; /* Size of entry's owner string */ + unsigned long descsz; /* Size of the note descriptor */ + unsigned long type; /* Interpretation of the descriptor */ + char * namedata; /* Start of the name+desc data */ + char * descdata; /* Start of the desc data */ + unsigned long descpos; /* File offset of the descdata */ +} Elf_Internal_Note; + + #endif diff --git a/phlib/include/mapimg.h b/phlib/include/mapimg.h index a9476113bca4..10720a7ae369 100644 --- a/phlib/include/mapimg.h +++ b/phlib/include/mapimg.h @@ -571,8 +571,8 @@ typedef struct _PH_ELF_IMAGE_SYMBOL_ENTRY UCHAR TypeInfo; ULONGLONG Address; ULONGLONG Size; - WCHAR Name[0x80]; - WCHAR Module[0x80]; + WCHAR Name[MAX_PATH * 2]; + WCHAR Module[MAX_PATH * 2]; } PH_ELF_IMAGE_SYMBOL_ENTRY, *PPH_ELF_IMAGE_SYMBOL_ENTRY; BOOLEAN PhGetMappedWslImageSymbols( @@ -584,6 +584,22 @@ VOID PhFreeMappedWslImageSymbols( _In_ PPH_LIST ImageSymbols ); +typedef struct _PH_ELF_IMAGE_DYNAMIC_ENTRY +{ + LONGLONG Tag; + PWSTR Type; + PPH_STRING Value; +} PH_ELF_IMAGE_DYNAMIC_ENTRY, *PPH_ELF_IMAGE_DYNAMIC_ENTRY; + +BOOLEAN PhGetMappedWslImageDynamic( + _In_ PPH_MAPPED_IMAGE MappedWslImage, + _Out_ PPH_LIST *DynamicSymbols + ); + +VOID PhFreeMappedWslImageDynamic( + _In_ PPH_LIST ImageDynamic + ); + #ifdef __cplusplus } #endif diff --git a/phlib/mapexlf.c b/phlib/mapexlf.c index c619bfc709c5..5dad85b04f91 100644 --- a/phlib/mapexlf.c +++ b/phlib/mapexlf.c @@ -512,3 +512,97 @@ VOID PhFreeMappedWslImageSymbols( PhDereferenceObject(ImageSymbols); } + +BOOLEAN PhGetMappedWslImageDynamic( + _In_ PPH_MAPPED_IMAGE MappedWslImage, + _Out_ PPH_LIST *ImageDynamic + ) +{ + PELF64_IMAGE_SECTION_HEADER sectionHeader; + PELF64_IMAGE_SECTION_HEADER section; + PPH_LIST dynamicSymbols; + USHORT i; + + dynamicSymbols = PhCreateList(0x40); + sectionHeader = IMAGE_FIRST_ELF64_SECTION(MappedWslImage); + + for (i = 0; i < MappedWslImage->Headers64->e_shnum; i++) + { + ULONGLONG count; + ULONGLONG ii; + PELF64_IMAGE_DYNAMIC_ENTRY entry; + PVOID stringTable; + + section = IMAGE_ELF64_SECTION_BY_INDEX(sectionHeader, i); + + if (section->sh_type != SHT_DYNAMIC) + continue; + + if (section->sh_entsize != sizeof(ELF64_IMAGE_DYNAMIC_ENTRY)) + return FALSE; + + count = section->sh_size / sizeof(ELF64_IMAGE_DYNAMIC_ENTRY); + entry = PTR_ADD_OFFSET(MappedWslImage->Header, section->sh_offset); + stringTable = PhGetMappedWslImageSectionData(MappedWslImage, NULL, section->sh_link); + + for (ii = 0; ii < count; ii++) + { + PPH_ELF_IMAGE_DYNAMIC_ENTRY dynamic; + + dynamic = PhAllocateZero(sizeof(PH_ELF_IMAGE_DYNAMIC_ENTRY)); + dynamic->Tag = entry[ii].d_tag; + + switch (dynamic->Tag) + { + case DT_NEEDED: + dynamic->Value = PhConvertUtf8ToUtf16(PTR_ADD_OFFSET(stringTable, entry[ii].d_val)); + break; + case DT_PLTRELSZ: + case DT_RELASZ: + case DT_RELAENT: + case DT_STRSZ: + case DT_SYMENT: + case DT_RELSZ: + case DT_RELENT: + case DT_INIT_ARRAYSZ: + case DT_FINI_ARRAYSZ: + case DT_PREINIT_ARRAYSZ: + dynamic->Value = PhFormatSize(entry[ii].d_val, ULONG_MAX); + break; + case DT_RELACOUNT: + case DT_RELCOUNT: + case DT_VERDEFNUM: + case DT_VERNEEDNUM: + dynamic->Value = PhFormatUInt64(entry[ii].d_val, TRUE); + break; + default: + dynamic->Value = PhFormatString(L"0x%llx", entry[ii].d_val); + break; + } + + PhAddItemList(dynamicSymbols, dynamic); + + if (entry[ii].d_tag == DT_NULL) + break; + } + } + + *ImageDynamic = dynamicSymbols; + + return TRUE; +} + +VOID PhFreeMappedWslImageDynamic( + _In_ PPH_LIST ImageDynamic + ) +{ + for (ULONG i = 0; i < ImageDynamic->Count; i++) + { + PPH_ELF_IMAGE_DYNAMIC_ENTRY dynamic = ImageDynamic->Items[i]; + + PhDereferenceObject(dynamic->Value); + PhFree(dynamic); + } + + PhDereferenceObject(ImageDynamic); +} From 3bd60e388a29b115c5cf257c61eb76c4b3dd9c56 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 15 Jan 2019 22:44:15 +0100 Subject: [PATCH 1546/2058] Remove junk --- phlib/include/exlf.h | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/phlib/include/exlf.h b/phlib/include/exlf.h index 143a6a60fe11..7de3b8ecd8dd 100644 --- a/phlib/include/exlf.h +++ b/phlib/include/exlf.h @@ -430,23 +430,4 @@ typedef struct _ELF_VERSION_AUX // Elf_Vernaux unsigned int vna_next; } ELF_VERSION_AUX, *PELF_VERSION_AUX; -typedef struct _ELF_EXTERNAL_NOTE // Elf_External_Note -{ - unsigned char namesz[4]; /* Size of entry's owner string */ - unsigned char descsz[4]; /* Size of the note descriptor */ - unsigned char type[4]; /* Interpretation of the descriptor */ - char name[1]; /* Start of the name+desc data */ - //char desc[1]; -} ELF_EXTERNAL_NOTE, *PELF_EXTERNAL_NOTE; - -typedef struct elf_internal_note { - unsigned long namesz; /* Size of entry's owner string */ - unsigned long descsz; /* Size of the note descriptor */ - unsigned long type; /* Interpretation of the descriptor */ - char * namedata; /* Start of the name+desc data */ - char * descdata; /* Start of the desc data */ - unsigned long descpos; /* File offset of the descdata */ -} Elf_Internal_Note; - - #endif From f5c034d7259a7c43f1581081d0792c518f805258 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 15 Jan 2019 22:53:47 +0100 Subject: [PATCH 1547/2058] Update macro usage --- ProcessHacker/main.c | 3 ++- phlib/guisup.c | 2 +- phlib/include/appresolverp.h | 10 +++++----- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/ProcessHacker/main.c b/ProcessHacker/main.c index feca4726cd63..519784f7b3be 100644 --- a/ProcessHacker/main.c +++ b/ProcessHacker/main.c @@ -187,7 +187,7 @@ INT WINAPI wWinMain( RtlExitUserProcess(STATUS_SUCCESS); } - if (PhPluginsEnabled = PhGetIntegerSetting(L"EnablePlugins") && !PhStartupParameters.NoPlugins) + if (PhPluginsEnabled && !PhStartupParameters.NoPlugins) { PhLoadPlugins(); } @@ -1100,6 +1100,7 @@ VOID PhpInitializeSettings( } // Apply basic global settings. + PhPluginsEnabled = !!PhGetIntegerSetting(L"EnablePlugins"); PhMaxSizeUnit = PhGetIntegerSetting(L"MaxSizeUnit"); if (PhGetIntegerSetting(L"SampleCountAutomatic")) diff --git a/phlib/guisup.c b/phlib/guisup.c index cc3a8fa26d88..dea378acb44f 100644 --- a/phlib/guisup.c +++ b/phlib/guisup.c @@ -937,7 +937,7 @@ VOID PhSetClipboardString( memory = GlobalLock(data); memcpy(memory, String->Buffer, String->Length); - *(PWCHAR)PTR_ADD_OFFSET(memory, String->Length) = 0; + *(PWCHAR)PTR_ADD_OFFSET(memory, String->Length) = UNICODE_NULL; GlobalUnlock(memory); diff --git a/phlib/include/appresolverp.h b/phlib/include/appresolverp.h index 0cfabc0b1871..04cf9d2a49ec 100644 --- a/phlib/include/appresolverp.h +++ b/phlib/include/appresolverp.h @@ -148,7 +148,7 @@ DECLARE_INTERFACE_IID(IApplicationResolver61, IUnknown) #define IApplicationResolver_QueryInterface(This, riid, ppvObject) \ ((This)->lpVtbl->QueryInterface(This, riid, ppvObject)) -#define IApplicationResolver_AddRef(This) \ +#define IApplicationResolver_AddRef(This) \ ((This)->lpVtbl->AddRef(This)) #define IApplicationResolver_Release(This) \ ((This)->lpVtbl->Release(This)) @@ -250,7 +250,7 @@ DECLARE_INTERFACE_IID(IApplicationResolver62, IUnknown) #define IApplicationResolver2_QueryInterface(This, riid, ppvObject) \ ((This)->lpVtbl->QueryInterface(This, riid, ppvObject)) -#define IApplicationResolver2_AddRef(This) \ +#define IApplicationResolver2_AddRef(This) \ ((This)->lpVtbl->AddRef(This)) #define IApplicationResolver2_Release(This) \ ((This)->lpVtbl->Release(This)) @@ -348,7 +348,7 @@ DECLARE_INTERFACE_IID(IStartMenuAppItems62, IUnknown) #define IStartMenuAppItems2_QueryInterface(This, riid, ppvObject) \ ((This)->lpVtbl->QueryInterface(This, riid, ppvObject)) -#define IStartMenuAppItems2_AddRef(This) \ +#define IStartMenuAppItems2_AddRef(This) \ ((This)->lpVtbl->AddRef(This)) #define IStartMenuAppItems2_Release(This) \ ((This)->lpVtbl->Release(This)) @@ -384,7 +384,7 @@ DECLARE_INTERFACE_IID(IMrtResourceManager, IUnknown) #define IMrtResourceManager_QueryInterface(This, riid, ppvObject) \ ((This)->lpVtbl->QueryInterface(This, riid, ppvObject)) -#define IMrtResourceManager_AddRef(This) \ +#define IMrtResourceManager_AddRef(This) \ ((This)->lpVtbl->AddRef(This)) #define IMrtResourceManager_Release(This) \ ((This)->lpVtbl->Release(This)) @@ -474,7 +474,7 @@ DECLARE_INTERFACE_IID(IResourceMap, IUnknown) #define IResourceMap_QueryInterface(This, riid, ppvObject) \ ((This)->lpVtbl->QueryInterface(This, riid, ppvObject)) -#define IResourceMap_AddRef(This) \ +#define IResourceMap_AddRef(This) \ ((This)->lpVtbl->AddRef(This)) #define IResourceMap_Release(This) \ ((This)->lpVtbl->Release(This)) From 4d2ef88b462404a15604270b561e0220f050824b Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 15 Jan 2019 22:56:55 +0100 Subject: [PATCH 1548/2058] peview: Add image hardlinks tab --- tools/peview/links.c | 231 ++++++++++++++++++++++++++++ tools/peview/peprp.c | 10 ++ tools/peview/peview.rc | 17 ++ tools/peview/peview.vcxproj | 1 + tools/peview/peview.vcxproj.filters | 3 + tools/peview/resource.h | 1 + 6 files changed, 263 insertions(+) create mode 100644 tools/peview/links.c diff --git a/tools/peview/links.c b/tools/peview/links.c new file mode 100644 index 000000000000..9892cbafdf85 --- /dev/null +++ b/tools/peview/links.c @@ -0,0 +1,231 @@ +/* + * Process Hacker - + * PE viewer + * + * Copyright (C) 2019 dmex + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include + +VOID PvpPeEnumerateFileLinks( + _In_ HWND ListViewHandle + ) +{ + HANDLE fileHandle; + ULONG count = 0; + + if (NT_SUCCESS(PhCreateFileWin32( + &fileHandle, + PhGetString(PvFileName), + FILE_READ_ATTRIBUTES | FILE_READ_DATA | SYNCHRONIZE, + FILE_ATTRIBUTE_NORMAL, + FILE_SHARE_READ, + FILE_OPEN, + FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_REPARSE_POINT + ))) + { + PFILE_LINKS_INFORMATION hardlinks; + PFILE_LINK_ENTRY_INFORMATION i; + + if (NT_SUCCESS(PhEnumFileHardLinks( + fileHandle, + &hardlinks + ))) + { + for (i = PH_FIRST_LINK(&hardlinks->Entry); i; i = PH_NEXT_LINK(i)) + { + NTSTATUS status; + HANDLE linkHandle; + UNICODE_STRING fileNameUs; + OBJECT_ATTRIBUTES oa; + IO_STATUS_BLOCK isb; + + fileNameUs.Length = sizeof(LONGLONG); + fileNameUs.MaximumLength = sizeof(LONGLONG); + fileNameUs.Buffer = (PWSTR)&i->ParentFileId; + + InitializeObjectAttributes( + &oa, + &fileNameUs, + OBJ_CASE_INSENSITIVE, + fileHandle, + NULL + ); + + status = NtCreateFile( + &linkHandle, + FILE_READ_ATTRIBUTES | SYNCHRONIZE, + &oa, + &isb, + NULL, + FILE_ATTRIBUTE_NORMAL, + 0, + FILE_OPEN, + FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_BY_FILE_ID, + NULL, + 0 + ); + + if (NT_SUCCESS(status)) + { + INT lvItemIndex; + PPH_STRING parentName; + WCHAR number[PH_PTR_STR_LEN_1]; + + PhPrintUInt32(number, ++count); + lvItemIndex = PhAddListViewItem(ListViewHandle, MAXINT, number, NULL); + + if (NT_SUCCESS(PhGetFileHandleName(linkHandle, &parentName))) + { + PPH_STRING fileName = NULL; + PPH_STRING baseName; + PH_STRINGREF pathPart; + PH_STRINGREF baseNamePart; + + baseName = PhGetBaseName(PvFileName); + + if (PhSplitStringRefAtChar(&PvFileName->sr, OBJ_NAME_PATH_SEPARATOR, &pathPart, &baseNamePart)) + { + PhMoveReference(&fileName, PhCreateString2(&pathPart)); + PhMoveReference(&fileName, PhConcatStringRef2(&fileName->sr, &parentName->sr)); + PhMoveReference(&fileName, PhConcatStrings(3, fileName->Buffer, L"\\", baseName->Buffer)); + } + + //if (!PhIsNullOrEmptyString(fileName)) + //{ + // HANDLE filePathHandle; + // + // if (NT_SUCCESS(PhCreateFileWin32( + // &filePathHandle, + // PhGetString(fileName), + // FILE_READ_ATTRIBUTES | SYNCHRONIZE, + // FILE_ATTRIBUTE_NORMAL, + // FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + // FILE_OPEN, + // FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT + // ))) + // { + // PFILE_ALL_INFORMATION fileAllInformation; + // //PFILE_ID_INFORMATION fileIdInformation; + // + // if (NT_SUCCESS(PhGetFileAllInformation(filePathHandle, &fileAllInformation))) + // { + // PhPrintPointer(number, (PVOID)fileAllInformation->InternalInformation.IndexNumber.QuadPart); + // PhSetListViewSubItem(ListViewHandle, lvItemIndex, 1, number); + // } + // + // //if (NT_SUCCESS(PhGetFileId(filePathHandle, &fileIdInformation))) + // //{ + // // PPH_STRING fileIdString = PhBufferToHexString( + // // fileIdInformation->FileId.Identifier, + // // sizeof(fileIdInformation->FileId.Identifier) + // // ); + // // + // // PhSetListViewSubItem(ListViewHandle, lvItemIndex, 2, fileIdString->Buffer); + // // PhDereferenceObject(fileIdString); + // //} + // + // NtClose(filePathHandle); + // } + //} + + PhSetListViewSubItem(ListViewHandle, lvItemIndex, 1, PhGetStringOrEmpty(fileName)); + + if (fileName) PhDereferenceObject(fileName); + PhDereferenceObject(baseName); + PhDereferenceObject(parentName); + } + + NtClose(linkHandle); + } + } + + PhFree(hardlinks); + } + + NtClose(fileHandle); + } +} + +INT_PTR CALLBACK PvpPeLinksDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + LPPROPSHEETPAGE propSheetPage; + PPV_PROPPAGECONTEXT propPageContext; + + if (!PvPropPageDlgProcHeader(hwndDlg, uMsg, lParam, &propSheetPage, &propPageContext)) + return FALSE; + + switch (uMsg) + { + case WM_INITDIALOG: + { + HWND lvHandle; + + lvHandle = GetDlgItem(hwndDlg, IDC_LIST); + PhSetListViewStyle(lvHandle, TRUE, TRUE); + PhSetControlTheme(lvHandle, L"explorer"); + PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 40, L"#"); + PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 250, L"Name"); + PhSetExtendedListView(lvHandle); + PhLoadListViewColumnsFromSetting(L"ImageHardLinksListViewColumns", lvHandle); + + PvpPeEnumerateFileLinks(lvHandle); + //ExtendedListView_SortItems(lvHandle); + + EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); + } + break; + case WM_DESTROY: + { + PhSaveListViewColumnsToSetting(L"ImageHardLinksListViewColumns", GetDlgItem(hwndDlg, IDC_LIST)); + } + break; + case WM_SHOWWINDOW: + { + if (!propPageContext->LayoutInitialized) + { + PPH_LAYOUT_ITEM dialogItem; + + dialogItem = PvAddPropPageLayoutItem(hwndDlg, hwndDlg, PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL); + PvAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_LIST), dialogItem, PH_ANCHOR_ALL); + + PvDoPropPageLayout(hwndDlg); + + propPageContext->LayoutInitialized = TRUE; + } + } + break; + case WM_NOTIFY: + { + PvHandleListViewNotifyForCopy(lParam, GetDlgItem(hwndDlg, IDC_LIST)); + } + break; + case WM_CONTEXTMENU: + { + PvHandleListViewCommandCopy(hwndDlg, lParam, wParam, GetDlgItem(hwndDlg, IDC_LIST)); + } + break; + } + + return FALSE; +} diff --git a/tools/peview/peprp.c b/tools/peview/peprp.c index 19785556c797..94ee9d583a48 100644 --- a/tools/peview/peprp.c +++ b/tools/peview/peprp.c @@ -208,6 +208,16 @@ VOID PvPeProperties( PvAddPropPage(propContext, newPage); } + // Links page + { + newPage = PvCreatePropPageContext( + MAKEINTRESOURCE(IDD_PELINKS), + PvpPeLinksDlgProc, + NULL + ); + PvAddPropPage(propContext, newPage); + } + // Symbols page if (NT_SUCCESS(PhGetMappedImageDataEntry(&PvMappedImage, IMAGE_DIRECTORY_ENTRY_DEBUG, &entry)) && entry->VirtualAddress) { diff --git a/tools/peview/peview.rc b/tools/peview/peview.rc index a5d6b1c488cd..24ac2bb65465 100644 --- a/tools/peview/peview.rc +++ b/tools/peview/peview.rc @@ -156,6 +156,15 @@ BEGIN TOPMARGIN, 3 BOTTOMMARGIN, 277 END + + IDD_PELINKS, DIALOG + BEGIN + LEFTMARGIN, 3 + RIGHTMARGIN, 297 + TOPMARGIN, 3 + BOTTOMMARGIN, 277 + END + END #endif // APSTUDIO_INVOKED @@ -310,6 +319,14 @@ BEGIN CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,3,3,294,274 END +IDD_PELINKS DIALOGEX 0, 0, 300, 280 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Links" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,3,3,294,274 +END + IDD_ELFDYNAMIC DIALOGEX 0, 0, 300, 280 STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Dynamic" diff --git a/tools/peview/peview.vcxproj b/tools/peview/peview.vcxproj index cb2b87ceb425..3c8d52349f93 100644 --- a/tools/peview/peview.vcxproj +++ b/tools/peview/peview.vcxproj @@ -231,6 +231,7 @@ + diff --git a/tools/peview/peview.vcxproj.filters b/tools/peview/peview.vcxproj.filters index eef3cad98d3b..845edd253013 100644 --- a/tools/peview/peview.vcxproj.filters +++ b/tools/peview/peview.vcxproj.filters @@ -90,6 +90,9 @@ Source Files\Pages + + Source Files\Pages\Windows + Source Files\Pages\Linux diff --git a/tools/peview/resource.h b/tools/peview/resource.h index 7203b0fb9b41..91fb013ec773 100644 --- a/tools/peview/resource.h +++ b/tools/peview/resource.h @@ -19,6 +19,7 @@ #define IDD_PEATTR 112 #define IDB_SEARCH_INACTIVE_BMP 113 #define IDD_PESTREAMS 113 +#define IDD_PELINKS 114 #define IDD_ELFDYNAMIC 116 #define IDC_SYMBOLTREE 119 #define IDC_TARGETMACHINE 1003 From e0e1313aec07b41682bf83d2ee0c6dddec3fdd0c Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 15 Jan 2019 23:03:38 +0100 Subject: [PATCH 1549/2058] Update peview.h --- tools/peview/include/peview.h | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tools/peview/include/peview.h b/tools/peview/include/peview.h index 705ab2bd921c..0e2d794c9c9b 100644 --- a/tools/peview/include/peview.h +++ b/tools/peview/include/peview.h @@ -357,6 +357,13 @@ INT_PTR CALLBACK PvpPeStreamsDlgProc( _In_ LPARAM lParam ); +INT_PTR CALLBACK PvpPeLinksDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + // ELF PWSTR PvpGetSymbolTypeName( @@ -393,6 +400,6 @@ INT_PTR CALLBACK PvpExlfDynamicDlgProc( _In_ UINT uMsg, _In_ WPARAM wParam, _In_ LPARAM lParam -); + ); #endif From 0e53a25ad54ba0d56785d17e0e577bfd2536f6c6 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 16 Jan 2019 15:08:04 +0100 Subject: [PATCH 1550/2058] peview: Add missing ELF dynamic tags --- phlib/include/exlf.h | 1 + phlib/mapexlf.c | 3 +++ tools/peview/exlfdynamic.c | 2 ++ 3 files changed, 6 insertions(+) diff --git a/phlib/include/exlf.h b/phlib/include/exlf.h index 7de3b8ecd8dd..e80542b70c99 100644 --- a/phlib/include/exlf.h +++ b/phlib/include/exlf.h @@ -168,6 +168,7 @@ #define DT_FINI_ARRAY 26 #define DT_INIT_ARRAYSZ 27 #define DT_FINI_ARRAYSZ 28 +#define DT_RUNPATH 29 #define DT_FLAGS 30 #define DT_PREINIT_ARRAY 32 // DT_ENCODING #define DT_PREINIT_ARRAYSZ 33 diff --git a/phlib/mapexlf.c b/phlib/mapexlf.c index 5dad85b04f91..b24abc50564b 100644 --- a/phlib/mapexlf.c +++ b/phlib/mapexlf.c @@ -555,6 +555,9 @@ BOOLEAN PhGetMappedWslImageDynamic( switch (dynamic->Tag) { case DT_NEEDED: + case DT_SONAME: + case DT_RPATH: + case DT_RUNPATH: dynamic->Value = PhConvertUtf8ToUtf16(PTR_ADD_OFFSET(stringTable, entry[ii].d_val)); break; case DT_PLTRELSZ: diff --git a/tools/peview/exlfdynamic.c b/tools/peview/exlfdynamic.c index 44c84f324d28..995c2821685c 100644 --- a/tools/peview/exlfdynamic.c +++ b/tools/peview/exlfdynamic.c @@ -84,6 +84,8 @@ PWSTR PvpGetDynamicTagName( return L"INIT_ARRAYSZ"; case DT_FINI_ARRAYSZ: return L"FINI_ARRAYSZ"; + case DT_RUNPATH: + return L"RUNPATH"; case DT_FLAGS: return L"FLAGS"; case DT_PREINIT_ARRAY: From d498d6afe1aae360028bfad52fad2ba4af71fdcc Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 16 Jan 2019 17:11:17 +0100 Subject: [PATCH 1551/2058] peview: Add ELF import/export symbol visibility --- phlib/include/mapimg.h | 1 + phlib/mapexlf.c | 7 +++++-- tools/peview/exlfexports.c | 2 ++ tools/peview/exlfimports.c | 2 ++ tools/peview/exlfprp.c | 22 ++++++++++++++++++++++ tools/peview/include/peview.h | 4 ++++ 6 files changed, 36 insertions(+), 2 deletions(-) diff --git a/phlib/include/mapimg.h b/phlib/include/mapimg.h index 10720a7ae369..ff759722b832 100644 --- a/phlib/include/mapimg.h +++ b/phlib/include/mapimg.h @@ -569,6 +569,7 @@ typedef struct _PH_ELF_IMAGE_SYMBOL_ENTRY }; }; UCHAR TypeInfo; + UCHAR OtherInfo; ULONGLONG Address; ULONGLONG Size; WCHAR Name[MAX_PATH * 2]; diff --git a/phlib/mapexlf.c b/phlib/mapexlf.c index b24abc50564b..500c2577b0fb 100644 --- a/phlib/mapexlf.c +++ b/phlib/mapexlf.c @@ -80,8 +80,8 @@ NTSTATUS PhInitializeMappedWslImage( return STATUS_IMAGE_SUBSYSTEM_NOT_PRESENT; } - if (MappedWslImage->Headers64->e_phentsize != sizeof(ELF64_IMAGE_SEGMENT_HEADER)) - return STATUS_FAIL_CHECK; + //if (MappedWslImage->Headers64->e_phentsize != sizeof(ELF64_IMAGE_SEGMENT_HEADER)) + // return STATUS_FAIL_CHECK; if (MappedWslImage->Headers64->e_shentsize != sizeof(ELF64_IMAGE_SECTION_HEADER)) return STATUS_FAIL_CHECK; @@ -418,6 +418,7 @@ BOOLEAN PhGetMappedWslImageSymbols( import->Address = entry[ii].st_value; import->Size = entry[ii].st_size; import->TypeInfo = entry[ii].st_info; + import->OtherInfo = entry[ii].st_other; // function name PhCopyStringZFromBytes( @@ -459,6 +460,7 @@ BOOLEAN PhGetMappedWslImageSymbols( export->Address = entry[ii].st_value; export->Size = entry[ii].st_size; export->TypeInfo = entry[ii].st_info; + export->OtherInfo = entry[ii].st_other; // function name PhCopyStringZFromBytes( @@ -480,6 +482,7 @@ BOOLEAN PhGetMappedWslImageSymbols( export->Address = entry[ii].st_value; export->Size = entry[ii].st_size; export->TypeInfo = entry[ii].st_info; + export->OtherInfo = entry[ii].st_other; // function name PhCopyStringZFromBytes( diff --git a/tools/peview/exlfexports.c b/tools/peview/exlfexports.c index 1ac15f790432..6ef3c8bfaaeb 100644 --- a/tools/peview/exlfexports.c +++ b/tools/peview/exlfexports.c @@ -51,6 +51,7 @@ VOID PvpProcessElfExports( PhSetListViewSubItem(ListViewHandle, lvItemIndex, 3, PhaFormatSize(export->Size, -1)->Buffer); PhSetListViewSubItem(ListViewHandle, lvItemIndex, 4, PvpGetSymbolTypeName(export->TypeInfo)); PhSetListViewSubItem(ListViewHandle, lvItemIndex, 5, PvpGetSymbolBindingName(export->TypeInfo)); + PhSetListViewSubItem(ListViewHandle, lvItemIndex, 6, PvpGetSymbolVisibility(export->OtherInfo)); } PhFreeMappedWslImageSymbols(exports); @@ -84,6 +85,7 @@ INT_PTR CALLBACK PvpExlfExportsDlgProc( PhAddListViewColumn(lvHandle, 3, 3, 3, LVCFMT_LEFT, 80, L"Size"); PhAddListViewColumn(lvHandle, 4, 4, 4, LVCFMT_LEFT, 80, L"Type"); PhAddListViewColumn(lvHandle, 5, 5, 5, LVCFMT_LEFT, 80, L"Binding"); + PhAddListViewColumn(lvHandle, 6, 6, 6, LVCFMT_LEFT, 80, L"Visibility"); PhSetExtendedListView(lvHandle); PhLoadListViewColumnsFromSetting(L"ExportsWslListViewColumns", lvHandle); diff --git a/tools/peview/exlfimports.c b/tools/peview/exlfimports.c index 7f214e1d61c7..b82f51e0ae21 100644 --- a/tools/peview/exlfimports.c +++ b/tools/peview/exlfimports.c @@ -47,6 +47,7 @@ VOID PvpProcessElfImports( PhSetListViewSubItem(ListViewHandle, lvItemIndex, 2, import->Name); PhSetListViewSubItem(ListViewHandle, lvItemIndex, 3, PvpGetSymbolTypeName(import->TypeInfo)); PhSetListViewSubItem(ListViewHandle, lvItemIndex, 4, PvpGetSymbolBindingName(import->TypeInfo)); + PhSetListViewSubItem(ListViewHandle, lvItemIndex, 5, PvpGetSymbolVisibility(import->OtherInfo)); } PhFreeMappedWslImageSymbols(imports); @@ -79,6 +80,7 @@ INT_PTR CALLBACK PvpExlfImportsDlgProc( PhAddListViewColumn(lvHandle, 2, 2, 2, LVCFMT_LEFT, 210, L"Name"); PhAddListViewColumn(lvHandle, 3, 3, 3, LVCFMT_LEFT, 100, L"Type"); PhAddListViewColumn(lvHandle, 4, 4, 4, LVCFMT_LEFT, 80, L"Binding"); + PhAddListViewColumn(lvHandle, 5, 5, 5, LVCFMT_LEFT, 80, L"Visibility"); PhSetExtendedListView(lvHandle); PhLoadListViewColumnsFromSetting(L"ImportsWslListViewColumns", lvHandle); diff --git a/tools/peview/exlfprp.c b/tools/peview/exlfprp.c index fac891449606..40cdc69779f6 100644 --- a/tools/peview/exlfprp.c +++ b/tools/peview/exlfprp.c @@ -70,6 +70,25 @@ PWSTR PvpGetSymbolBindingName( return L"***ERROR***"; } +PWSTR PvpGetSymbolVisibility( + _In_ UCHAR OtherInfo + ) +{ + switch (ELF_ST_VISIBILITY(OtherInfo)) + { + case STV_DEFAULT: + return L"Default"; + case STV_INTERNAL: + return L"Internal"; + case STV_HIDDEN: + return L"Hidden"; + case STV_PROTECTED: + return L"Protected"; + } + + return L"***ERROR***"; +} + VOID PvExlfProperties( VOID ) @@ -150,6 +169,9 @@ VOID PvpSetWslImageType( switch (PvMappedImage.Header->e_type) { + case ET_REL: + type = L"Relocatable"; + break; case ET_DYN: type = L"Dynamic"; break; diff --git a/tools/peview/include/peview.h b/tools/peview/include/peview.h index 0e2d794c9c9b..b33cc1c6fc3c 100644 --- a/tools/peview/include/peview.h +++ b/tools/peview/include/peview.h @@ -374,6 +374,10 @@ PWSTR PvpGetSymbolBindingName( _In_ UCHAR TypeInfo ); +PWSTR PvpGetSymbolVisibility( + _In_ UCHAR OtherInfo + ); + INT_PTR CALLBACK PvpExlfGeneralDlgProc( _In_ HWND hwndDlg, _In_ UINT uMsg, From d297f4cfbf65aab111b45e91a0e40122d8ae668c Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 16 Jan 2019 19:20:19 +0100 Subject: [PATCH 1552/2058] Update headers Co-Authored-By: Biswapriyo Nath --- phnt/include/ntexapi.h | 12 +++++++++++- phnt/include/ntpsapi.h | 2 +- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/phnt/include/ntexapi.h b/phnt/include/ntexapi.h index 0ba0dbcd6526..9b50295a8e33 100644 --- a/phnt/include/ntexapi.h +++ b/phnt/include/ntexapi.h @@ -1980,11 +1980,21 @@ typedef struct _EVENT_TRACE_PROFILE_COUNTER_INFORMATION ULONG ProfileSource[1]; } EVENT_TRACE_PROFILE_COUNTER_INFORMATION, *PEVENT_TRACE_PROFILE_COUNTER_INFORMATION; +typedef struct _PROFILE_SOURCE_INFO +{ + ULONG NextEntryOffset; + ULONG Source; + ULONG MinInterval; + ULONG MaxInterval; + PVOID Reserved; + WCHAR Description[1]; +} PROFILE_SOURCE_INFO, *PPROFILE_SOURCE_INFO; + typedef struct _EVENT_TRACE_PROFILE_LIST_INFORMATION { EVENT_TRACE_INFORMATION_CLASS EventTraceInformationClass; ULONG Spare; - struct _PROFILE_SOURCE_INFO* Profile[1]; + PROFILE_SOURCE_INFO Profile[1]; } EVENT_TRACE_PROFILE_LIST_INFORMATION, *PEVENT_TRACE_PROFILE_LIST_INFORMATION; typedef struct _EVENT_TRACE_STACK_CACHING_INFORMATION diff --git a/phnt/include/ntpsapi.h b/phnt/include/ntpsapi.h index 49e74ca3e378..74433d05009a 100644 --- a/phnt/include/ntpsapi.h +++ b/phnt/include/ntpsapi.h @@ -245,7 +245,7 @@ typedef enum _THREADINFOCLASS ThreadSystemThreadInformation, // q: SYSTEM_THREAD_INFORMATION // 40 ThreadActualGroupAffinity, // since THRESHOLD2 ThreadDynamicCodePolicyInfo, - ThreadExplicitCaseSensitivity, + ThreadExplicitCaseSensitivity, // qs: ULONG; s: 0 disables, otherwise enables ThreadWorkOnBehalfTicket, ThreadSubsystemInformation, // q: SUBSYSTEM_INFORMATION_TYPE // since REDSTONE2 ThreadDbgkWerReportActive, From 5f1db39c17910841ac93263fec8df9549bdf3a27 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 16 Jan 2019 19:20:54 +0100 Subject: [PATCH 1553/2058] Update ntpsapi.h --- phnt/include/ntpsapi.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phnt/include/ntpsapi.h b/phnt/include/ntpsapi.h index 74433d05009a..c7b4d4b02687 100644 --- a/phnt/include/ntpsapi.h +++ b/phnt/include/ntpsapi.h @@ -151,7 +151,7 @@ typedef enum _PROCESSINFOCLASS ProcessHandleInformation, // q: PROCESS_HANDLE_SNAPSHOT_INFORMATION // since WIN8 ProcessMitigationPolicy, // s: PROCESS_MITIGATION_POLICY_INFORMATION ProcessDynamicFunctionTableInformation, - ProcessHandleCheckingMode, + ProcessHandleCheckingMode, // qs: ULONG; s: 0 disables, otherwise enables ProcessKeepAliveCount, // q: PROCESS_KEEPALIVE_COUNT_INFORMATION ProcessRevokeFileHandles, // s: PROCESS_REVOKE_FILE_HANDLES_INFORMATION ProcessWorkingSetControl, // s: PROCESS_WORKING_SET_CONTROL From e4015ecfbf90dfab37e5a4245e1ed9c89aa0552e Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 16 Jan 2019 21:49:16 +0100 Subject: [PATCH 1554/2058] BuildTools: Fix warning --- tools/CustomBuildTool/Source Files/Build.cs | 4 ++-- .../bin/Release/CustomBuildTool.exe | Bin 167936 -> 167936 bytes .../bin/Release/CustomBuildTool.pdb | Bin 85504 -> 85504 bytes 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/CustomBuildTool/Source Files/Build.cs b/tools/CustomBuildTool/Source Files/Build.cs index b24423555afd..91bd22420419 100644 --- a/tools/CustomBuildTool/Source Files/Build.cs +++ b/tools/CustomBuildTool/Source Files/Build.cs @@ -581,8 +581,8 @@ public static bool CopyKProcessHacker(BuildFlags Flags) { if (!File.Exists(CustomSignToolPath)) return true; - //if (!File.Exists("build\\kph.key")) - // return true; + if (!File.Exists("build\\kph.key")) + return true; if ((Flags & BuildFlags.Build32bit) == BuildFlags.Build32bit) { diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe b/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe index 2a23efab24ca42b604d99293f585ff45091dffdb..57c0967834855b311643a3c73c0a9a3377ec31c1 100644 GIT binary patch delta 2594 zcmZYBdrVVT90&04Ed{Rk)>5F*0tE`xQW2vdD&k}Kz{h+bXnpWdo+`q$UYLIaL#4ZIEXsSjwrsz1@2P?#p*f%PJ?H$+ zJ*T;8;E)tJB<><$>XMvO%Z@m zNpZpFX`ne$geQY~hg+3C>Wc8B5K_%HgQtc<m$I>R!9e{{i)SirB+MDHo}&xQ9|l6MN1&*3zOGN-MRMJE3UU7^Tk`3i&)|R%qV4 z5zixSUQH;v?T9rh-K1!vXB0bAlj=!`sSqr5SC}od1qFwVZZ2u05s#?H3`8rp*<=?D z)>_(gt{p;@l!#%WgteY0vf_T0xYd0L&V+?zy1x|d{^GOrYst1KyVPq5Hv8uTQz%cU zgT5&rCvKbIUow{MtrL$^M@O2lDqmN643l-7u2GuqaTO-9EKs0lb2QaW(3PjjH&K^I zlQ>D&TQZyX)l0g9gPG3x3w2h+UWW-cxh5vMBop>b)w4%b-i+?)x-OpCTpA{s zahdBbEgFSyHFenENnRKp1z|25*=|3OEFcP|0cx2yl!cpdF*Qeu!p(UhO_3~^R;+8d zbCDE_H+oJiP7d??7O>6^2=OV>5Oizmgw1|la^vb^J^RCXNy>zG2~#Hm(iO>rR!to^ z=h}{JJmE4qZ%M-uSgMcwH)%gcB2cDlvSUATVK3K}LCV9!e9rahccn3?sL;d9(M`z5 zL#|4BHwxgZ)U&zrPttgp)VA^>|IuZvPd}IckFlbYw9Kx!Ua8X<|3m6nQ)5L#%tgObPC5Y8TH-c|r+(iBUj%HX$rCblF#6pyDA>2Z$<$75P!iz?( za{BUm(Zcm!d=QJ!N}~Gh;>mam@iiW9p{H1kom_k3ETm4ZyRktm!9lJEu@=%%uB|aa zEX4_~y)hQjS*}m0U>SP3`lwzR`k4Gw{vZ`B$2A@vr-J3U#U;`KSKtm;ywyVbnd=x8 ztiS5i{^t6I3NC|jrGBD6Qo&^y91@-Oa>Qx!w~J5dxR)b^hZkrwRd91%qs>%d z1ec38Q;o4)qiHkMDCD|Co2kJ}t{b$O8kBJ5(pA)ADc2;ridxj@@{9ZFNb9hghwsyo z)(v<+)uUO zFT1W|^?-t_@wFDVVHX}#Hmrdys=px`2aIgQSS@SAWz3cvF_-Hk=F3g+a{VeSl3zg; z*C0cUyaubdTz=eQV7FR%u2h zAL+zSxfyHwjcn;RGF(6lDtj(f^;8H+s{Co98n|FphaXQ@qb^3MPcBTRwnx44nWZP| z!iLD6-Y<+9mJQAm6TG>Pi+1%!7i|0|_i)e6dtyR1{dCh_wg%dtgZ&V5(uYAn>4Iqs zj@&q3IB)QqQ{T>d^}DcA_4_lTK@f$#2C=I!OfVXk(a*WAlamZ~VSd-RFrja&*(jVb S8x2oiH~4bSL{}Le3;zM#iU;NZ delta 2578 zcmZYBYfKbZ6bJDCEDH=X>$1YaF0ed=6<2{46)g2twW8t!MC6US!m6NF*MS(DHY`Ys zR#O!x0gI-!)mlu|#;nl~3RTMCxmc)tAoq9Ax#!$_ zXR?{5y;9R&X~*Uu;eBh{)_9@1?O>^3Q3YW{@Q;ZC939O;Lb_Tmj1X$oX2I9t2ol7Y zSpW2Y+xC6uiZ9# z8_l|M*K$k!QFAtuVI<;@tyOWbfo z8kNoJsF;Ms^e8O!EHFuEIU_i1#JEf&9@C5&7^<9QOPsU~ZKR!M?Qo)`+s(XfSgc{Z9-FJFY@)6#O`b`*T$-M9?UvcPQ*Y?8z!0Xd zd{cB*MP7vo7r7?IIwcd{dsB}+ruJs+nxX4#GSi_vUBObCWX5T(n^ZI$-)d^Je-^(m zI2=#svdmWdo_GP_z`TK~%^%6wjI)WOrEpx#@7FZRf}8?f8A&BlBsTj`mc|G9JVk7> z4MKE+G#tA$wZmrbmQwLesUCZpbWR$9yfUVCG)b2wdc8EY;iPj5(s7^5l=QQdfrfHD z^Pjj*WTK%$*HlL*#=ummD}|JWTREKTlW$7nFuzI<_6}W*9NgksByY!fcoylgdGcLp z0-$cM%=PW2mytHFT}&>zG_}JM5ogGSxJ1vdju7P;aBFJAf@rfm6J0!Z&>1Dqg3GOE zeoC5yF0NYYnh(=bJyv7AiUP3rkzLk3(IFQ=^3`b6+81EBrgm%>Bhxr8pLv*Eh$*`0#Y-hQmxJ|h6_--`1xR16 zw^!^IQZ`pdN&rQe#Pvmrg*1cfA+=bDd@clANTpn}r2vYtgsYNX-eS~p9f%H~1YQ#L zZxxS5TZnJ-;6^${DVn))UX1_ zxGqt@3Uo91sQt&(uoCBa@CY@mM1V`A3$DU7u4t=;^efjvYPbk@xQ$@jT$b- zpIo=8;bI6Y^!vR{x4i^mntZL|GrI02h~U8<+Kd~qTvuo_ZlrKIX){Za#+6N*S&A&K zbF`UiOyv5WHdBpUt}*l|YA}y$GChhKl<4w_ophxhEat&3x>C=e-=}3*p~c!!9FZIYS+MKvi7uOT|JbNMtSWq;*$Xws? zL+Ixdr|20;`oIm6hOnf|wc#vMl|8|>^8&eSnKNa$(HG;J~)g%f6@ Q;n@cU&*&3F-G)BlUmd;>Y5)KL diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb b/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb index 14b58b7258fa5183ce4dd3f0094231dc48c90f24..410cc91c8b6013f8b010a85d359157ce3fe3d091 100644 GIT binary patch delta 4505 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 delta 4497 zcmZ`-3s6*7w!Qlb*hDamfY5vdgH7w}r-U@nfkv8EtPG|)fdmQ+Vq_e@NWdtG+9nM# z28m(RY^{rqWJDyG7*V{VMzJFpd44hB4VuB<43(Hf4RNqEqg8P->-056>Qz0e?pkM` zz0T+EbI!h}soLgSwas^*&tu`VCS)c_k~DIu(mT94J*%m6>x{F@`+icR9{X=yNXrw0 zzZ{#jc0(?$X+OCAUvJ#+O5NJ#*h%|Ce&-kB__y(vR8Z%~%)z zWdF+!bc(;rYS5T}4fk_pkGz(!iATnN?6d!u2L*gI{u7^3MSrVnT5JlSelD|E$MjkS^U6arA?feWTnfz5V(~alU&r!(a9#@wB)5! z$A^<$^a&@Yn1LlJVRF=Ho;30Id?h8EQu$tr2^eh+lmAz%uD6EMZEmxg47W!Q4Swoz zNz&^j$$-I~JZN>%A})K{6tO65Nb@%Q=N@T(4(HaVSCWAzq?&-asbQ4M3sbFhgBw#_ zr)|;^mM2sJ%?svcrd+)D%m-?iMn`jvW2=-V@3keW1Mfd zP!QMJ?erF(w!3s~PiS2zog9Wm zsT9DeQ=XyaTs_5t1vmga&NrsmDS{_Vb?I!zM}5*r3g%-|^U2AfS>= zUICs7t_2r^H-cXVH-rBGZUxT+9|11_p9U`i_kl~n{gULC%22q6iX~ve{FZ|C;7V{T z_%-l&@N#fE_{ZD-u9^&X!_EO$gT)bBElaCQ!L_ho2d{(u4tN9XwO|Hs0&hlr6ZlWC z_mV@B8c^{WDw7VM|>?9rJ>TiQNGw)Lzf(LmDEmAk;|3YL?Hx>*de{IK-&^f_Y!z zDymi|&Oj#yE_>+~cHoR6Gli;aigpt=R$}qXGPS82U!FP)`{ly#tyt~AIc6$UQ|FwN zH|B)DKX07wu;bB|2nwb#Jbm71I;@t=vk@KUhWRxV#>NFPz-bH0;Xbe+!7wIsXlwUk z9YoAy!A5?#z)jEc8w*Qu)@}d`Ie$?B+Ln|?@~K5p{#r|tCi2*t;P*?D{Gau9MUo$v z6a{lmsU8hWO08(PrF5NqFP-BTXUIRN^Ss4rG>jV;TX9VKfI%EoW}|R+mf0zW>wxjx z4V=h{WV5maH;E(g6GxfZ<Kcc zMrEp@W&}|z8`s7Gv)ArL*ALdl7;+{Jg;R%6=HbagIFE5+t((fZtu_vLq4q^&-3jly z=zDH{w;aE>AD*9*14_;lbHM7oZ(cip5|c$Rre-01*p!=U&*AfvEB^KtuMk? za8JEWzMslB>(j6)ja#hvx)pD+(d)cri%Yi|D~Sn6O513PWb4)-+RWKo_tNM5U~2-M zXrqOSIlIwCJGiUyMd6OvF$Ip| z9rOKnIK&_%;oubotN+-MMYNcWJ5506&KitzVW(U7o#oL?I>WFzmNo0;?=1YsUDNr? z<^USOB`paY@L>Q}tf9rknJ7iE^TXBT;hqnzvL{JM1MlNYaUX{$8*kK)CN_Ls8(J)M z2hvhb-xW?~&fjGP*6k{gpHJp%&65IqeUO@c@t{!wkNwC(v$>~bj{hCl9e5UV=SL^$ zJGJ&>#M#4jyKj+MUGd3ol1pv)NKN4dt+BL*Yg?BR^TSrNfpH-bF%@?dabRZS5nu76 z?AYs~KKAU51NQF?ljU?=JYL}0tvb%z7psd&|LtNZ`+|^5KH9ezNpeP80!~_O+iw3- zZ|5XM@Yo&5Q2WPY=oS0T7`l1C8{HaJH^r#Us#``ijPjk25kg>&DW3G z>89{0*J5ZmXL`oTcQSaMCxae%TO9V7iTJw5PC7PzW+y$*{mh13-Uy80tH5|R9E-zS zPd;YGTX!CdX5iH`<>X@LSqrV^>a+NYv*+w?s^Nv_;(&GMTy%^5yA$NQW=`wQ5XrgQLKVEH zJAqE})$UTvCi}b_gPlIV4g=(W(L^QcgD=X7YSe{2?J`Z`jlE%<-kV2OluW?GyfD?X5K#XSq^<4YIYMRf1117_K>rijw zkYcXj5m(Xm>>Riy|71n_n2rgp`O%H3_}*^9BtE+RcXU_#&%dIJ;=#W|q-NZCKZ%YW z>WQbzI_g)(CQz7fJFf79O4}p~qfeCn1d8+(_qBuG8ej1{#ibR+&yl^}CS*`@pM*}_ z*d95>Plj4AH_?|O@5QxX&5bQ&dTgtwJn zA&Sw%lv$H#v~T5jNt&TtO~mBRD~%A+{i9A%=Q zawQw&`#tXO;}qvp=paC;7LLVAgK&tC#6_hM4qs1_B)#G-l35uPnoCNc1)A|#!q=1_ z3p8Ri=Xi@mN{Mia6QXR5xY92uR!xPi(X0nv zOD4PW#}tYnoidn8kw{XS8K#*rUNh2bL{G9ylK-Pc3iv;ZWmS685T7u`VMA!e^?sr< zn1+QA7kfW%k#aR>A!dhl_f3rZV0qANy6z)QY& zA#*5>bjXsG$>|txheMJuG-{&7kC-4y`}>uJC3e&qWn(&->GB~@Iz2P&|NRHcp{Pt6 O??V-bre#sP|9=1hf_OFn From 12098ac7a7c1c6c56ac2a6f6bdbb21d9ea0581f7 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 16 Jan 2019 21:49:39 +0100 Subject: [PATCH 1555/2058] Fix build error #364 --- phnt/include/ntexapi.h | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/phnt/include/ntexapi.h b/phnt/include/ntexapi.h index 9b50295a8e33..7507efaba63e 100644 --- a/phnt/include/ntexapi.h +++ b/phnt/include/ntexapi.h @@ -1980,21 +1980,21 @@ typedef struct _EVENT_TRACE_PROFILE_COUNTER_INFORMATION ULONG ProfileSource[1]; } EVENT_TRACE_PROFILE_COUNTER_INFORMATION, *PEVENT_TRACE_PROFILE_COUNTER_INFORMATION; -typedef struct _PROFILE_SOURCE_INFO -{ - ULONG NextEntryOffset; - ULONG Source; - ULONG MinInterval; - ULONG MaxInterval; - PVOID Reserved; - WCHAR Description[1]; -} PROFILE_SOURCE_INFO, *PPROFILE_SOURCE_INFO; +//typedef struct _PROFILE_SOURCE_INFO +//{ +// ULONG NextEntryOffset; +// ULONG Source; +// ULONG MinInterval; +// ULONG MaxInterval; +// PVOID Reserved; +// WCHAR Description[1]; +//} PROFILE_SOURCE_INFO, *PPROFILE_SOURCE_INFO; typedef struct _EVENT_TRACE_PROFILE_LIST_INFORMATION { EVENT_TRACE_INFORMATION_CLASS EventTraceInformationClass; ULONG Spare; - PROFILE_SOURCE_INFO Profile[1]; + struct _PROFILE_SOURCE_INFO* Profile[1]; } EVENT_TRACE_PROFILE_LIST_INFORMATION, *PEVENT_TRACE_PROFILE_LIST_INFORMATION; typedef struct _EVENT_TRACE_STACK_CACHING_INFORMATION From cc5770ffcda2e338d37636bf75f23959056a45d3 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 20 Jan 2019 08:31:54 +0100 Subject: [PATCH 1556/2058] Improve PEB string caching, Update macro usage --- phlib/include/phbasesup.h | 2 +- phlib/jsonc/json_util.c | 4 ++-- phlib/mapexlf.c | 2 +- phlib/native.c | 16 ++++++++++++++-- 4 files changed, 18 insertions(+), 6 deletions(-) diff --git a/phlib/include/phbasesup.h b/phlib/include/phbasesup.h index 37c48466f80b..1eda2180e15c 100644 --- a/phlib/include/phbasesup.h +++ b/phlib/include/phbasesup.h @@ -2956,7 +2956,7 @@ PhNextEnumHashtable( entry = (PPH_HASHTABLE_ENTRY)Context->Current; Context->Current += Context->Step; - if (entry->HashCode != -1) + if (entry->HashCode != ULONG_MAX) return &entry->Body; } diff --git a/phlib/jsonc/json_util.c b/phlib/jsonc/json_util.c index 58c3e2f11c79..79e2bd4b77ae 100644 --- a/phlib/jsonc/json_util.c +++ b/phlib/jsonc/json_util.c @@ -118,7 +118,7 @@ struct json_object* json_object_from_file(wchar_t * filename) status = PhCreateFileWin32( &fileHandle, filename, - FILE_GENERIC_WRITE, + FILE_GENERIC_READ, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ, FILE_OPEN, @@ -163,7 +163,7 @@ struct json_object* json_object_from_file(wchar_t * filename) data = (PSTR)PhReAllocate(data, allocatedLength); } - data[dataLength] = 0; + data[dataLength] = ANSI_NULL; obj = json_tokener_parse(data); diff --git a/phlib/mapexlf.c b/phlib/mapexlf.c index 500c2577b0fb..5326ba030565 100644 --- a/phlib/mapexlf.c +++ b/phlib/mapexlf.c @@ -391,7 +391,7 @@ BOOLEAN PhGetMappedWslImageSymbols( section = IMAGE_ELF64_SECTION_BY_INDEX(sectionHeader, i); - // NOTE: The below code needs some improvements for SHT_DYNSYM -dmex + // NOTE: The below code needs some improvements for SHT_SYMTAB -dmex if (section->sh_type != SHT_SYMTAB && section->sh_type != SHT_DYNSYM) continue; diff --git a/phlib/native.c b/phlib/native.c index fbc2f23a4149..cf38471762e7 100644 --- a/phlib/native.c +++ b/phlib/native.c @@ -646,6 +646,12 @@ NTSTATUS PhGetProcessPebString( ))) return status; + if (unicodeString.Length == 0) + { + *String = PhReferenceEmptyString(); + return status; + } + string = PhCreateStringEx(NULL, unicodeString.Length); // Read the string contents. @@ -688,6 +694,12 @@ NTSTATUS PhGetProcessPebString( ))) return status; + if (unicodeString32.Length == 0) + { + *String = PhReferenceEmptyString(); + return status; + } + string = PhCreateStringEx(NULL, unicodeString32.Length); // Read the string contents. @@ -3427,8 +3439,8 @@ BOOLEAN NTAPI PhpEnumProcessModulesCallback( if (indexOfLastBackslash != -1) { - Entry->BaseDllName.Buffer = PTR_ADD_OFFSET(Entry->FullDllName.Buffer, PTR_ADD_OFFSET(indexOfLastBackslash * sizeof(WCHAR), sizeof(WCHAR))); - Entry->BaseDllName.Length = Entry->FullDllName.Length - (USHORT)indexOfLastBackslash * sizeof(WCHAR) - sizeof(WCHAR); + Entry->BaseDllName.Buffer = PTR_ADD_OFFSET(Entry->FullDllName.Buffer, PTR_ADD_OFFSET(indexOfLastBackslash * sizeof(WCHAR), sizeof(UNICODE_NULL))); + Entry->BaseDllName.Length = Entry->FullDllName.Length - (USHORT)indexOfLastBackslash * sizeof(WCHAR) - sizeof(UNICODE_NULL); Entry->BaseDllName.MaximumLength = Entry->BaseDllName.Length; } else From a5216da75332e303894fa1aaac0a8273f384f77b Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 20 Jan 2019 08:48:57 +0100 Subject: [PATCH 1557/2058] peview: Fix properties tab on Win7 --- tools/peview/propstore.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tools/peview/propstore.c b/tools/peview/propstore.c index f5b1aebc1ce0..7a54cdc477f3 100644 --- a/tools/peview/propstore.c +++ b/tools/peview/propstore.c @@ -50,6 +50,17 @@ VOID PvpPeEnumerateFilePropStore( ); } + if (FAILED(status)) + { + status = SHGetPropertyStoreFromParsingName( + PvFileName->Buffer, + NULL, + GPS_DEFAULT, // required for Windows 7 (dmex) + &IID_IPropertyStore, + &propstore + ); + } + if (SUCCEEDED(status)) { if (SUCCEEDED(IPropertyStore_GetCount(propstore, &count))) From 3b645a59b2a058cb203402a3deb01a6338217c93 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 20 Jan 2019 10:00:32 +0100 Subject: [PATCH 1558/2058] Remove typedef --- ProcessHacker/anawait.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/ProcessHacker/anawait.c b/ProcessHacker/anawait.c index a9b49dfe5366..f53a012e01f5 100644 --- a/ProcessHacker/anawait.c +++ b/ProcessHacker/anawait.c @@ -40,10 +40,6 @@ #include -typedef HWND (WINAPI *_GetSendMessageReceiver)( - _In_ HANDLE ThreadId - ); - typedef struct _ANALYZE_WAIT_CONTEXT { BOOLEAN Found; @@ -962,7 +958,9 @@ static PPH_STRING PhpaGetSendMessageReceiver( _In_ HANDLE ThreadId ) { - static _GetSendMessageReceiver GetSendMessageReceiver_I; + static HWND (WINAPI *GetSendMessageReceiver_I)( + _In_ HANDLE ThreadId + ); HWND windowHandle; ULONG threadId; From fdb78f5fd1fb00a8f9fb7ebd7529f2f75b704a33 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 20 Jan 2019 10:01:25 +0100 Subject: [PATCH 1559/2058] Improve string caching, Fix memory leak --- ProcessHacker/proctree.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ProcessHacker/proctree.c b/ProcessHacker/proctree.c index 6044a08111d2..cd26f000fa67 100644 --- a/ProcessHacker/proctree.c +++ b/ProcessHacker/proctree.c @@ -602,6 +602,8 @@ VOID PhpRemoveProcessNode( PhClearReference(&ProcessNode->FileSizeText); PhClearReference(&ProcessNode->SubprocessCountText); PhClearReference(&ProcessNode->ProtectionText); + PhClearReference(&ProcessNode->DesktopInfoText); + PhClearReference(&ProcessNode->UserName); PhDeleteGraphBuffers(&ProcessNode->CpuGraphBuffers); PhDeleteGraphBuffers(&ProcessNode->PrivateGraphBuffers); @@ -3530,7 +3532,10 @@ VOID PhpPopulateTableWithProcessNodes( if (i != 0) { - text = PhaCreateStringEx(getCellText.Text.Buffer, getCellText.Text.Length); + if (getCellText.Text.Length == 0) + text = PhReferenceEmptyString(); + else + text = PhaCreateStringEx(getCellText.Text.Buffer, getCellText.Text.Length); } else { From 97e04b7519cccfffafdda1111af617d5583bd54f Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 20 Jan 2019 10:28:14 +0100 Subject: [PATCH 1560/2058] Add PhFileReadAllText --- phlib/include/phutil.h | 7 +++++ phlib/util.c | 71 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+) diff --git a/phlib/include/phutil.h b/phlib/include/phutil.h index d12d86f00d74..9695d7c18ffc 100644 --- a/phlib/include/phutil.h +++ b/phlib/include/phutil.h @@ -1264,6 +1264,13 @@ PhGetExportNameFromOrdinal( _In_opt_ USHORT ProcedureNumber ); +PHLIBAPI +PPH_STRING +NTAPI +PhFileReadAllText( + _In_ PWSTR FileName + ); + #ifdef __cplusplus } #endif diff --git a/phlib/util.c b/phlib/util.c index a84e2fd2229a..6700f6390722 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -6128,3 +6128,74 @@ PPH_STRING PhGetExportNameFromOrdinal( return NULL; } + +PPH_STRING PhFileReadAllText( + _In_ PWSTR FileName + ) +{ + PPH_STRING string = NULL; + HANDLE fileHandle; + IO_STATUS_BLOCK isb; + + if (NT_SUCCESS(PhCreateFileWin32( + &fileHandle, + FileName, + FILE_GENERIC_READ, + FILE_ATTRIBUTE_NORMAL, + FILE_SHARE_READ, + FILE_OPEN, + FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT + ))) + { + PSTR data; + ULONG allocatedLength; + ULONG dataLength; + ULONG returnLength; + BYTE buffer[PAGE_SIZE]; + + allocatedLength = sizeof(buffer); + data = PhAllocate(allocatedLength); + dataLength = 0; + + while (NT_SUCCESS(NtReadFile( + fileHandle, + NULL, + NULL, + NULL, + &isb, + buffer, + PAGE_SIZE, + NULL, + NULL + ))) + { + returnLength = (ULONG)isb.Information; + + if (returnLength == 0) + break; + + if (allocatedLength < dataLength + returnLength) + { + allocatedLength *= 2; + data = PhReAllocate(data, allocatedLength); + } + + memcpy(data + dataLength, buffer, returnLength); + + dataLength += returnLength; + } + + if (allocatedLength < dataLength + sizeof(ANSI_NULL)) + { + allocatedLength++; + data = PhReAllocate(data, allocatedLength); + } + + data[dataLength] = ANSI_NULL; + + string = PhConvertUtf8ToUtf16Ex(data, dataLength); + PhFree(data); + } + + return string; +} From bdd884cda0bcd04274183c890537caf4e24bdd6c Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 20 Jan 2019 10:48:08 +0100 Subject: [PATCH 1561/2058] Improve handle string caching --- phlib/native.c | 31 +++++++++++++++++++++++-------- plugins/Updater/updater.c | 11 ++++++++--- 2 files changed, 31 insertions(+), 11 deletions(-) diff --git a/phlib/native.c b/phlib/native.c index cf38471762e7..9957ba713867 100644 --- a/phlib/native.c +++ b/phlib/native.c @@ -2693,10 +2693,18 @@ NTSTATUS PhGetTransactionManagerLogFileName( if (!NT_SUCCESS(status)) return status; - *LogFileName = PhCreateStringEx( - logPathInfo->LogPath, - logPathInfo->LogPathLength - ); + if (logPathInfo->LogPathLength == 0) + { + *LogFileName = PhReferenceEmptyString(); + } + else + { + *LogFileName = PhCreateStringEx( + logPathInfo->LogPath, + logPathInfo->LogPathLength + ); + } + PhFree(logPathInfo); return status; @@ -2896,10 +2904,17 @@ NTSTATUS PhGetResourceManagerBasicInformation( if (Description) { - *Description = PhCreateStringEx( - basicInfo->Description, - basicInfo->DescriptionLength - ); + if (basicInfo->DescriptionLength == 0) + { + *Description = PhReferenceEmptyString(); + } + else + { + *Description = PhCreateStringEx( + basicInfo->Description, + basicInfo->DescriptionLength + ); + } } PhFree(basicInfo); diff --git a/plugins/Updater/updater.c b/plugins/Updater/updater.c index 8c2eea682a86..002807879708 100644 --- a/plugins/Updater/updater.c +++ b/plugins/Updater/updater.c @@ -135,20 +135,25 @@ BOOLEAN LastUpdateCheckExpired( VOID ) { - ULONG64 lastUpdateTimeTicks = 0; + ULONG64 lastUpdateTimeTicks; LARGE_INTEGER currentUpdateTimeTicks; PPH_STRING lastUpdateTimeString; PhQuerySystemTime(¤tUpdateTimeTicks); lastUpdateTimeString = PhGetStringSetting(SETTING_NAME_LAST_CHECK); - PhStringToInteger64(&lastUpdateTimeString->sr, 0, &lastUpdateTimeTicks); + + if (PhIsNullOrEmptyString(lastUpdateTimeString)) + return TRUE; + + if (!PhStringToInteger64(&lastUpdateTimeString->sr, 0, &lastUpdateTimeTicks)) + return TRUE; if (currentUpdateTimeTicks.QuadPart - lastUpdateTimeTicks >= 7 * PH_TICKS_PER_DAY) { PPH_STRING currentUpdateTimeString; - currentUpdateTimeString = PhFormatUInt64(currentUpdateTimeTicks.QuadPart, FALSE); + currentUpdateTimeString = PhIntegerToString64(currentUpdateTimeTicks.QuadPart, 0, FALSE); PhSetStringSetting2(SETTING_NAME_LAST_CHECK, ¤tUpdateTimeString->sr); PhDereferenceObject(currentUpdateTimeString); From 295d73246beac61547ddafd8c2feed1356ee0982 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 20 Jan 2019 11:01:20 +0100 Subject: [PATCH 1562/2058] BuildTool: Add caps file support --- ProcessHacker/resources/capslist.txt | 788 ++++++++++++++++++ tools/CustomBuildTool/Source Files/Build.cs | 52 ++ tools/CustomBuildTool/Source Files/Program.cs | 12 + .../bin/Release/CustomBuildTool.exe | Bin 167936 -> 168448 bytes .../bin/Release/CustomBuildTool.pdb | Bin 85504 -> 85504 bytes 5 files changed, 852 insertions(+) create mode 100644 ProcessHacker/resources/capslist.txt diff --git a/ProcessHacker/resources/capslist.txt b/ProcessHacker/resources/capslist.txt new file mode 100644 index 000000000000..3ff44204740c --- /dev/null +++ b/ProcessHacker/resources/capslist.txt @@ -0,0 +1,788 @@ +ID_CAP_ACCESSIBILITY_CLIENT +ID_CAP_ACCESS_FAMILY_NOTES_API +ID_CAP_ACCESS_REMINDER_IMAGES +ID_CAP_ACC_MGR_ADMIN +ID_CAP_ADAPTIVE_BRIGHTNESS_CONTROL +ID_CAP_ADVERTISING_CONFIG +ID_CAP_AIS_TOKEN_MANAGER +ID_CAP_APPCONTAINER_PACKAGE_CERTIFICATES +ID_CAP_APPOINTMENTS +ID_CAP_APPPREINSTALL_DIRECTORY +ID_CAP_APPPREINSTALL_EVENTS +ID_CAP_APPRESOLVER +ID_CAP_APPX_EXECUTION +ID_CAP_APP_STORE_PURCHASE_HISTORY +ID_CAP_AUDIO_EVENTSND +ID_CAP_AUDIO_INTERNAL +ID_CAP_AUDIO_ROUTING_CONTROLLER +ID_CAP_AUDIO_SETTINGS +ID_CAP_AUTHHOST +ID_CAP_BACKGROUND_EXECUTION_MANAGEMENT +ID_CAP_BACKGROUND_SETTINGS_MANAGEMENT +ID_CAP_BACKGROUND_WORKER +ID_CAP_BACKUPROAMRESTORE +ID_CAP_BASEOS_UPDATEAPI +ID_CAP_BINGCLIENT_BINGCONFIGURATION +ID_CAP_BINGCLIENT_CA_INTERESTEXTRACTION +ID_CAP_BINGCLIENT_DDC +ID_CAP_BINGCLIENT_IDENTITY +ID_CAP_BINGCLIENT_OSS +ID_CAP_BINGCLIENT_SUGGESTSHIGHLIGHTS +ID_CAP_BINGCLIENT_TEE +ID_CAP_BLUETOOTH +ID_CAP_BLUETOOTH_ADMIN +ID_CAP_BMR2_MONITOR_SERVICE +ID_CAP_BMR_CONFIGURATION +ID_CAP_BMR_SYNC +ID_CAP_BROKER_NAVIGATION +ID_CAP_BROWSER_ACCESSIBILITY_SETTINGS +ID_CAP_BROWSER_FEATURE_CONTROL_KEYS +ID_CAP_BSS_AIM_INTERFACE +ID_CAP_BSS_NABSYNC_INTERFACE +ID_CAP_BSS_PUSH_INTERFACE +ID_CAP_BSS_REMINDER_INTERFACE +ID_CAP_BUILTIN_BASEPRIORITY +ID_CAP_BUILTIN_CREATEGLOBAL +ID_CAP_BUILTIN_CREATEPERMANENT +ID_CAP_BUILTIN_DEFAULT +ID_CAP_BUILTIN_IMPERSONATE +ID_CAP_BUILTIN_PROFILE +ID_CAP_BUILTIN_SETTIME +ID_CAP_BUILTIN_SHUTDOWN +ID_CAP_BUILTIN_SYMBOLICLINK +ID_CAP_BUILTIN_TCB +ID_CAP_BUTTONS +ID_CAP_CALLMESSAGING_FILTER +ID_CAP_CAMERA +ID_CAP_CA_ACTIONURI_TEST_EVENT +ID_CAP_CA_ADMIN +ID_CAP_CA_BACKGROUND_PROCESSOR +ID_CAP_CA_BACKGROUND_PROCESSOR_ADMIN +ID_CAP_CA_CONTEXT +ID_CAP_CA_DND_MANAGER +ID_CAP_CA_ENABLED +ID_CAP_CA_HISTORY +ID_CAP_CA_RULES +ID_CAP_CA_SIGNALS_GENERIC +ID_CAP_CA_SIGNALS_MANAGER +ID_CAP_CA_SIGNALS_MANAGER_ADMIN +ID_CAP_CA_UPLOAD_FOLDER +ID_CAP_CELLUX_CONFIG_READ +ID_CAP_CELL_API_ADMIN +ID_CAP_CELL_API_COMMON +ID_CAP_CELL_API_LOCATION +ID_CAP_CELL_API_MESSAGING +ID_CAP_CELL_API_MODEMLOGGING +ID_CAP_CELL_API_OEM_PASSTHROUGH +ID_CAP_CELL_API_TELEPHONY +ID_CAP_CELL_API_UICC +ID_CAP_CELL_API_UICC_LOWLEVEL +ID_CAP_CELL_CELLMGR +ID_CAP_CELL_CMCSPWWAN_PLUS +ID_CAP_CELL_MSFT_UICC_DATASTORE +ID_CAP_CELL_OEM_UICC_DATASTORE +ID_CAP_CELL_RCSPRESENCE +ID_CAP_CELL_VIDEOTELEPHONY +ID_CAP_CELL_WNF +ID_CAP_CELL_WNF_ADMIN +ID_CAP_CELL_WNF_PII +ID_CAP_CHAMBER_PROFILE_CODE_INSTALLTEMP_RWD +ID_CAP_CHAMBER_PROFILE_CODE_NITEMP_RW +ID_CAP_CHAMBER_PROFILE_CODE_R +ID_CAP_CHAMBER_PROFILE_CODE_RW +ID_CAP_CHAMBER_PROFILE_DATA_LIVETILES_RWD +ID_CAP_CHAMBER_PROFILE_DATA_MEDIA_RWD +ID_CAP_CHAMBER_PROFILE_DATA_PLATFORMDATA_ALL +ID_CAP_CHAMBER_PROFILE_DATA_R +ID_CAP_CHAMBER_PROFILE_DATA_RW +ID_CAP_CHAMBER_PROFILE_DATA_SHELLCONTENT_R +ID_CAP_CHAMBER_PROFILE_DATA_SHELLCONTENT_RWD +ID_CAP_CLIPBOARD +ID_CAP_COMMANDCHANNEL +ID_CAP_COMMS_APPLICATIONS +ID_CAP_COMMS_COMMON +ID_CAP_COMMS_SERVICES +ID_CAP_COMMS_SETTINGS +ID_CAP_CONTACTS +ID_CAP_CONTENTSHARING +ID_CAP_CORTANA_RULES_DB +ID_CAP_CREATE_PROCESS_IN_CHAMBER +ID_CAP_CREDENTIAL_COLLECTION_UI +ID_CAP_CRITICAL_DATA +ID_CAP_CSP_BMR_PROVISION +ID_CAP_CSP_DMCLIENT +ID_CAP_CSP_FOUNDATION +ID_CAP_CSP_LOCATION +ID_CAP_CSP_MAIL +ID_CAP_CSP_NODECACHE +ID_CAP_CSP_OEM +ID_CAP_CSP_PHONE +ID_CAP_CSP_W4_APPLICATION +ID_CAP_CSP_WIFI_HOTSPOT +ID_CAP_DATACOLLECTION_ACTIVITY +ID_CAP_DATACOLLECTION_COLLECTOR +ID_CAP_DATACOLLECTION_RAWETW +ID_CAP_DATAPLANUSAGE +ID_CAP_DATAPLANUSAGE_ADMIN +ID_CAP_DCP +ID_CAP_DEBUG +ID_CAP_DEBUG_FOLDERS +ID_CAP_DEBUG_NAVIGATION +ID_CAP_DEVELOPERUNLOCK +ID_CAP_DEVELOPERUNLOCK_API +ID_CAP_DEVELOPERUNLOCK_CODEDUI +ID_CAP_DEVICE_LOCK +ID_CAP_DEVICE_LOCK_ADMIN +ID_CAP_DEVICE_MANAGEMENT +ID_CAP_DEVICE_MANAGEMENT_ADMIN +ID_CAP_DEVICE_MANAGEMENT_BOOTSTRAP +ID_CAP_DEVICE_MANAGEMENT_SECURITY_POLICIES +ID_CAP_DIAGNOSTIC_CLIENT +ID_CAP_DISPLAY_CONTROL +ID_CAP_DMCLIENT_APPMGMT +ID_CAP_DO_NOT_DISTURB +ID_CAP_DRIVE_MODE_ADMIN +ID_CAP_DUASVC +ID_CAP_DU_AGENT +ID_CAP_DU_CORE_API +ID_CAP_DU_CSP +ID_CAP_DU_MIGRATION_MANAGER_STATUS +ID_CAP_DU_MIGRATION_WNF_EVENTS +ID_CAP_DU_MIGRATOR_PROVISIONING_STATUS_MICROSOFT +ID_CAP_DU_MIGRATOR_PROVISIONING_STATUS_OEM +ID_CAP_DU_MIGRATOR_STATUS_MICROSOFT +ID_CAP_DU_MIGRATOR_STATUS_OEM +ID_CAP_DU_PROVISIONING +ID_CAP_DU_SHARED_DATA +ID_CAP_DU_USS +ID_CAP_DU_UX +ID_CAP_DU_UX_FEATURE_DISCOVERY +ID_CAP_EAS_CREDENTIALS +ID_CAP_EDM_CACHE_RWDELETE +ID_CAP_EDM_CACHE_WRITE +ID_CAP_ENDPOINTDISCOVERY +ID_CAP_ENROLLMENT +ID_CAP_ENROLLMENT_ADMIN +ID_CAP_ENROLLMENT_POLL +ID_CAP_ENROLLMENT_RENEW +ID_CAP_ENTERPRISERESOURCESTORE +ID_CAP_ENTERPRISE_AUTHENTICATION +ID_CAP_ENTERPRISE_ENROLLMENT +ID_CAP_ENTERPRISE_SERVICE +ID_CAP_ENTERPRISE_SHARED_DATA +ID_CAP_ETW_PROFILER +ID_CAP_EVERYONE +ID_CAP_EVERYONE_INROM +ID_CAP_EXTERNAL_DISPLAY +ID_CAP_FAILURE_REPORT_CONTENT_PROVIDER +ID_CAP_FINDMYPHONE +ID_CAP_FOREGROUND_TASK_MANAGER +ID_CAP_GAMERSERVICES +ID_CAP_GLOBALIZATION_SETTINGS +ID_CAP_HTTP_ACCEPT_LANGUAGE_HEADER +ID_CAP_ICS_RO +ID_CAP_ICS_RW +ID_CAP_IDENTITY_DEVICE +ID_CAP_IDENTITY_DEVICE_1ST_PARTY +ID_CAP_IDENTITY_USER +ID_CAP_IDENTITY_USER_1ST_PARTY +ID_CAP_IDM_IMAGE_CACHE +ID_CAP_IMMERSIVE_SHELL +ID_CAP_INPUT_CORE +ID_CAP_INPUT_FEATURES +ID_CAP_INPUT_INJECTION +ID_CAP_INPUT_LOCALES +ID_CAP_INPUT_SERVICE +ID_CAP_INSTALL_CERTIFICATES +ID_CAP_INTENTTEXTRACTION_OPTIN +ID_CAP_INTERNAL_DEPLOYMENT +ID_CAP_INTERNET_EXPLORER_BROWSER_HISTORY +ID_CAP_INTERNET_EXPLORER_DATA_OPTIMIZATION +ID_CAP_INTERNET_EXPLORER_FAVORITES +ID_CAP_INTERNET_EXPLORER_HKCU_WRITE +ID_CAP_INTERNET_EXPLORER_HKLM_SECURITY_SETTINGS +ID_CAP_INTERNET_EXPLORER_INTRANET_ZONE_SETTINGS +ID_CAP_INTERNET_EXPLORER_REMOTEDEBUGGING +ID_CAP_INTERNET_EXPLORER_ROAMING +ID_CAP_INTERNET_EXPLORER_SEARCH_PROVIDER_KEYS_HKCU +ID_CAP_INTEROPSERVICES +ID_CAP_ISV_CAMERA +ID_CAP_KEYBOARD +ID_CAP_KIDZONE_ADMIN +ID_CAP_KIDZONE_CUSTOMIZATION +ID_CAP_LANGUAGEUNDERSTANDING +ID_CAP_LASS_ADMIN +ID_CAP_LASS_REMOTELOCK +ID_CAP_LEGACY_VOICEMAIL_HANDLER +ID_CAP_LEXICONUPDATE +ID_CAP_LIVEID +ID_CAP_LIVETOKEN_WNF_EVENTS +ID_CAP_LOCATION +ID_CAP_LOCATION_ADMIN +ID_CAP_LOCATION_BTPOLICY +ID_CAP_LOCATION_GNSSDRIVER +ID_CAP_MAP +ID_CAP_MAP_ADMIN +ID_CAP_MAP_WRITE +ID_CAP_MEDIALIB +ID_CAP_MEDIALIB_AUDIO +ID_CAP_MEDIALIB_INT +ID_CAP_MEDIALIB_PHOTO +ID_CAP_MEDIALIB_PHOTO_FULL +ID_CAP_MEDIALIB_PLAYBACK +ID_CAP_MEDIALIB_VIDEO +ID_CAP_MEDIASERVICE_VOLUMELIMIT_INT +ID_CAP_MICMUTEPOLICY_BYPASS +ID_CAP_MICROPHONE +ID_CAP_MONITOR_NAVIGATION +ID_CAP_MOUSE +ID_CAP_MO_CLOUDMESSAGING +ID_CAP_MSS_BYTESTREAM_RPC +ID_CAP_MULTIMEDIA_ENCODER_HARDWARE +ID_CAP_MULTIVARIANT +ID_CAP_MULTIVARIANT_INSTALL_DATA +ID_CAP_NARRATOR_SETTINGS +ID_CAP_NATIVE_NETWORK_REPLACEMENT +ID_CAP_NAVIGATIONBAR_ADMIN +ID_CAP_NETWORKING +ID_CAP_NETWORKING_ADMIN +ID_CAP_NETWORKING_INTERNET_CLIENT +ID_CAP_NETWORKING_INTERNET_CLIENT_SERVER +ID_CAP_NETWORKING_PRIVATE_NETWORK_CLIENT_SERVER +ID_CAP_NETWORKING_VPN_ADMIN +ID_CAP_NETWORKING_VPN_PROVIDER +ID_CAP_NETWORKING_VPN_SERVICES +ID_CAP_NFC_ADMIN +ID_CAP_NOCENTER_SOUNDS +ID_CAP_NTSERVICES +ID_CAP_NVREAD +ID_CAP_NVREADWRITE +ID_CAP_O365_DISCOVERY +ID_CAP_OEMPUBLICDIRECTORY +ID_CAP_OEM_ADC +ID_CAP_OEM_CUSTOM +ID_CAP_OEM_DEPLOYMENT +ID_CAP_OFFICE_LAUNCH_URL +ID_CAP_OFFICE_MSDRM_HKCU +ID_CAP_ONENOTE_EVENTS +ID_CAP_OOBE_PRIVATE +ID_CAP_ORIENTATION_LOCK +ID_CAP_PEOPLE_EXTENSION +ID_CAP_PEOPLE_EXTENSION_IM +ID_CAP_PEOPLE_EXTENSION_MOBILE +ID_CAP_PERSONA +ID_CAP_PERSONAL_INFORMATION_IMPORT +ID_CAP_PHONEBROKER_INTERFACE +ID_CAP_PHONEDIALER +ID_CAP_PHONEPROVISIONER_DEVICEUPDATE +ID_CAP_PHONEPROVISIONER_EVENTS +ID_CAP_PHONE_2ND_PARTY +ID_CAP_PHONE_ADMIN +ID_CAP_PHONE_INTERNAL +ID_CAP_PHOTOS_SETTINGS_R +ID_CAP_PHOTOS_SETTINGS_RW +ID_CAP_PICKER_CONTRACT_UI +ID_CAP_PLATFORM_EXTENSIBILITY +ID_CAP_PLAYREADY +ID_CAP_PLAYREADY_ADMIN +ID_CAP_PM_1ST_PARTY +ID_CAP_PM_BSS +ID_CAP_PM_INSTALL +ID_CAP_POIDATASTORE +ID_CAP_POIDATASTORE_ADMIN +ID_CAP_POLICY_MANAGER +ID_CAP_POLICY_MANAGER_READONLY +ID_CAP_POWERNOTIF_USER +ID_CAP_PRESERVED_DATA +ID_CAP_PRIV_ABOUTCPL +ID_CAP_PRIV_ACCESSIBILITYCPL +ID_CAP_PRIV_ACCESSORIESCPL +ID_CAP_PRIV_ACCESSORYMGRSVC +ID_CAP_PRIV_ACCOUNTPROVSVC +ID_CAP_PRIV_ACTIONURIHOST +ID_CAP_PRIV_ADVERTISINGIDCPL +ID_CAP_PRIV_ALARMS +ID_CAP_PRIV_APHCHECK +ID_CAP_PRIV_APMUX +ID_CAP_PRIV_APPCORNER +ID_CAP_PRIV_APPPREINSTALLER +ID_CAP_PRIV_APPRESOLVERUI +ID_CAP_PRIV_APPSDATAMIGRATOR +ID_CAP_PRIV_APPXEXECUTIONSVC +ID_CAP_PRIV_AUTHHOST_MSA +ID_CAP_PRIV_AUTHHOST_WAB_A +ID_CAP_PRIV_AUTHHOST_WAB_B +ID_CAP_PRIV_AUTHHOST_WAB_C +ID_CAP_PRIV_AUTHHOST_WAB_ENTERPRISE +ID_CAP_PRIV_AUTHHOST_WAB_SSO +ID_CAP_PRIV_AUTHHOST_WAB_SSO_ENTERPRISE +ID_CAP_PRIV_AUTOTIMEUPDATE +ID_CAP_PRIV_BATTERYSAVERCPL +ID_CAP_PRIV_BLUETOOTHPBAPSVC +ID_CAP_PRIV_BMR2MONITORSVC +ID_CAP_PRIV_BMR2SCHEDULETRIGGER +ID_CAP_PRIV_BMRCPL +ID_CAP_PRIV_BMRSCHEDULETRIGGER +ID_CAP_PRIV_BRIGHTNESSCPL +ID_CAP_PRIV_BSSVC +ID_CAP_PRIV_BTAGSERVICE +ID_CAP_PRIV_BTCONNMGR +ID_CAP_PRIV_BTHAVCTPSVC +ID_CAP_PRIV_BTSERV +ID_CAP_PRIV_BTUXCPL +ID_CAP_PRIV_CALC7 +ID_CAP_PRIV_CAPTURESVC +ID_CAP_PRIV_CASVCSHARED3 +ID_CAP_PRIV_CELLMANAGER +ID_CAP_PRIV_CELLULARDATACOLLECTOR +ID_CAP_PRIV_CELLUX +ID_CAP_PRIV_CERTINSTALLER +ID_CAP_PRIV_CFMSVC +ID_CAP_PRIV_CGSVC +ID_CAP_PRIV_CLOUDSTORAGECPL +ID_CAP_PRIV_CMSERVICE +ID_CAP_PRIV_COMMANDCHANNEL +ID_CAP_PRIV_COMMSAPHOST +ID_CAP_PRIV_COMMSAPPLICATIONS +ID_CAP_PRIV_COMMSCERTINSTSVC +ID_CAP_PRIV_COMMSMESSAGESVC +ID_CAP_PRIV_COMMSMMSTRANSPORT +ID_CAP_PRIV_CONTACTSTOKENSVC +ID_CAP_PRIV_CONTENTSHARESVC +ID_CAP_PRIV_CONTENTSHARINGAPP +ID_CAP_PRIV_COREUIREGISTRAR +ID_CAP_PRIV_DACCERTINSTSVC +ID_CAP_PRIV_DATACOLLECTION +ID_CAP_PRIV_DATASENSESVC +ID_CAP_PRIV_DATASMART +ID_CAP_PRIV_DATETIMECPL +ID_CAP_PRIV_DCPSVC +ID_CAP_PRIV_DEBUGGERMUXNOTIFY +ID_CAP_PRIV_DIAGNOSTICSVC +ID_CAP_PRIV_DMCFGHOST +ID_CAP_PRIV_DMOMACPNETWMO +ID_CAP_PRIV_DMOMACPUSERMO +ID_CAP_PRIV_DMWAPPUSHSVC +ID_CAP_PRIV_DRIVINGMODEMANAGER +ID_CAP_PRIV_DRIVINGMODESETTINGS +ID_CAP_PRIV_DSSVC +ID_CAP_PRIV_DSTOKENCLEAN +ID_CAP_PRIV_DUACALLBACK +ID_CAP_PRIV_DUACLIENT +ID_CAP_PRIV_DUCLEANUPMIGRATOR +ID_CAP_PRIV_DUFEATUREDISCOVERY +ID_CAP_PRIV_DUMIGRATIONMANAGER +ID_CAP_PRIV_DUMIGRATIONPROVISIONERMICROSOFT +ID_CAP_PRIV_DUMIGRATIONPROVISIONEROEM +ID_CAP_PRIV_DUPOSTUPDATEUX +ID_CAP_PRIV_DUSTARTINGMIGRATOR +ID_CAP_PRIV_DUSVC +ID_CAP_PRIV_ENROLLMENTCLIENT +ID_CAP_PRIV_ENTAPPSERVICE +ID_CAP_PRIV_ENTERPRISEINSTALL +ID_CAP_PRIV_ENTERPRISEMGMSVC +ID_CAP_PRIV_ENTERPRISERING +ID_CAP_PRIV_ENTERPRISEVALIDATION +ID_CAP_PRIV_EXECMANSERVICE +ID_CAP_PRIV_FINDMYPHONE +ID_CAP_PRIV_FLYOUTDATAMIGRATOR +ID_CAP_PRIV_GROVELER +ID_CAP_PRIV_GWPCENROLLSVC +ID_CAP_PRIV_HFA +ID_CAP_PRIV_HOTSPOTHOST +ID_CAP_PRIV_HUBTILERESTOREHOST +ID_CAP_PRIV_ICSENTITLEMENTHOST +ID_CAP_PRIV_ICSSVC +ID_CAP_PRIV_INPUTSERVICE +ID_CAP_PRIV_INSTALLERWORKER +ID_CAP_PRIV_INTERNETEXPLORER +ID_CAP_PRIV_IPOVERUSB +ID_CAP_PRIV_KEYBOARDCPL +ID_CAP_PRIV_KIDZONECONFIGURATION +ID_CAP_PRIV_KIDZONECUSTOMIZATION +ID_CAP_PRIV_LASSCREDENTIALEXPIRATIONCHECK +ID_CAP_PRIV_LAUNCHAPPSVC +ID_CAP_PRIV_LEXICONUPDATE +ID_CAP_PRIV_LFSVC +ID_CAP_PRIV_LIVETOKEN +ID_CAP_PRIV_LOCATIONUXCPL +ID_CAP_PRIV_LOCKANDWALLPAPER +ID_CAP_PRIV_MEDIA +ID_CAP_PRIV_MEDIASERVICE +ID_CAP_PRIV_MIRRORCPL +ID_CAP_PRIV_MOBILEUI +ID_CAP_PRIV_MOSHOST +ID_CAP_PRIV_MSATICKETSVC +ID_CAP_PRIV_MSGIMTRANSPORT +ID_CAP_PRIV_MSGSMSTRANSPORT +ID_CAP_PRIV_MTP +ID_CAP_PRIV_MVPROVISIONHOST +ID_CAP_PRIV_MVUX +ID_CAP_PRIV_NABSYNC +ID_CAP_PRIV_NOCENTERSETTINGSCPL +ID_CAP_PRIV_NOTIFICATIONPLATFORMMIGRATOR +ID_CAP_PRIV_NOTIFSVC +ID_CAP_PRIV_OFFICE +ID_CAP_PRIV_OMADMCLIENT_ENTERPRISE +ID_CAP_PRIV_OMADMCLIENT_MOBILE_OPERATOR +ID_CAP_PRIV_OMADMPRC +ID_CAP_PRIV_OOBE +ID_CAP_PRIV_ORIENTSRV +ID_CAP_PRIV_PACMANSERVICE +ID_CAP_PRIV_PHONEAUDIOSRV +ID_CAP_PRIV_PHONEPROVISIONER +ID_CAP_PRIV_PHONEPROVISIONER_OEM +ID_CAP_PRIV_PHONESVCSG +ID_CAP_PRIV_PHOTOS +ID_CAP_PRIV_PHOTOSSVC +ID_CAP_PRIV_PIMIDXMAINT +ID_CAP_PRIV_PLACESSVC +ID_CAP_PRIV_POSTDUAPPMIGRATOR +ID_CAP_PRIV_POWERNOTIF +ID_CAP_PRIV_PROXIMITYSVC +ID_CAP_PRIV_PROXYSVC +ID_CAP_PRIV_REALWORLD-BINGCLIENT +ID_CAP_PRIV_REALWORLD-INTERESTEXTRACTION +ID_CAP_PRIV_REBOOTDEVICE +ID_CAP_PRIV_REGIONCPL +ID_CAP_PRIV_REMEMBER +ID_CAP_PRIV_RETAILDEMO +ID_CAP_PRIV_RETAILDEMOERROR +ID_CAP_PRIV_RETAILDEMOGLOB +ID_CAP_PRIV_RETAILDEMOUI +ID_CAP_PRIV_RILADAPTATION +ID_CAP_PRIV_RINGTONESANDSOUNDS +ID_CAP_PRIV_ROAMINGCPL +ID_CAP_PRIV_ROTATIONLOCKCPL +ID_CAP_PRIV_SAPISVR +ID_CAP_PRIV_SECMIGRATOR +ID_CAP_PRIV_SEMGRSVC +ID_CAP_PRIV_SETTINGS +ID_CAP_PRIV_SHELLDATAMIGRATOR +ID_CAP_PRIV_SIREPSVC +ID_CAP_PRIV_SOFTAPUX +ID_CAP_PRIV_SPEECHCPL +ID_CAP_PRIV_SPEECHUPDATE +ID_CAP_PRIV_START +ID_CAP_PRIV_STORAGESENSE +ID_CAP_PRIV_STORAGESVC +ID_CAP_PRIV_STOREDATAMIGRATOR +ID_CAP_PRIV_TASKSCHEDULERSVC +ID_CAP_PRIV_TELCPL +ID_CAP_PRIV_TELREPSVC +ID_CAP_PRIV_THEMECPL +ID_CAP_PRIV_TILEMIGRATOR +ID_CAP_PRIV_TIMEBROKER +ID_CAP_PRIV_UPDATEMGRSVC +ID_CAP_PRIV_USBCPL +ID_CAP_PRIV_USERDATASERVICE +ID_CAP_PRIV_USSREPORTING +ID_CAP_PRIV_UTKSERVICE +ID_CAP_PRIV_UTKUX +ID_CAP_PRIV_VPNUX +ID_CAP_PRIV_WALLET +ID_CAP_PRIV_WALLETSVC +ID_CAP_PRIV_WEHCSPHELPER +ID_CAP_PRIV_WEHSTART +ID_CAP_PRIV_WIFICONNSVC +ID_CAP_PRIV_WIFICPASSIST +ID_CAP_PRIV_WIFICPBROWSERUX +ID_CAP_PRIV_WIFIUDPTEST +ID_CAP_PRIV_WIFIUXBLUE +ID_CAP_PRIV_WLID2MSA +ID_CAP_PRIV_WPABSVC +ID_CAP_PRIV_WPNARRATOR +ID_CAP_PRIV_WPNCERTINSTSVC +ID_CAP_PRIV_WPTOOLS +ID_CAP_PRIV_WPTPMVSCMGRSVC +ID_CAP_PRIV_WPUITESTTOOLS +ID_CAP_PRIV_ZMEDIAQUEUESVC +ID_CAP_PRIV_ZMF +ID_CAP_PRIV_ZMF_SERVICE +ID_CAP_PROVISIONWPCERTIFICATE +ID_CAP_PROXIMITY +ID_CAP_PUBLIC_FOLDER_FULL +ID_CAP_PUBLISH_ALARM_STATE +ID_CAP_PUBLISH_OOBE_STATE +ID_CAP_PUSHROUTER +ID_CAP_PUSH_NOTIFICATION +ID_CAP_PUSH_SERVER +ID_CAP_QUICK_SETTINGS +ID_CAP_READGWPCERTIFICATE +ID_CAP_REBOOT_FLASHING_MODE +ID_CAP_REMEMBER_ADMIN +ID_CAP_REMEMBER_API +ID_CAP_REMOVABLE_STORAGE +ID_CAP_RESET_PHONE +ID_CAP_RESOURCE_MANAGER +ID_CAP_RETAILDEMO_BACKGROUNDIMAGE +ID_CAP_RETAILDEMO_CLIENT +ID_CAP_RETAILDEMO_GLOB_REGISTRY +ID_CAP_RETAILDEMO_OFFLINECONTENT +ID_CAP_RINGTONE_ADD +ID_CAP_ROAMING_CONFIGURATION +ID_CAP_ROTATION_MANAGER +ID_CAP_RUNTIME_CONFIG +ID_CAP_SCREENCAPTURE +ID_CAP_SCREEN_RECORDER +ID_CAP_SCREEN_RECORDER_BKG +ID_CAP_SEARCHMAPS_SHAREDCONFIG +ID_CAP_SEND_TO_ONENOTE +ID_CAP_SENSORS +ID_CAP_SETDEVICENAME +ID_CAP_SETTINGSYNC +ID_CAP_SETTINGSYNC_CONFIGURATION +ID_CAP_SETTINGS_MANAGEMENT_PROVIDER +ID_CAP_SHARED_OBJECT_DIRECTORY +ID_CAP_SHARED_USER_CERTIFICATES +ID_CAP_SHARE_DELEGATE +ID_CAP_SHELL_DEVICE_LOCK_UI_API +ID_CAP_SHELL_LAUNCH_SESSION +ID_CAP_SHELL_NAVIGATION +ID_CAP_SHELL_NOTIFICATION_CLIENT +ID_CAP_SHELL_OEM_ADMIN +ID_CAP_SHELL_RESET_NAVIGATION +ID_CAP_SHELL_TEST_CLIENT +ID_CAP_SHOW_VOLUME_CONTROL +ID_CAP_SMS +ID_CAP_SMS_COMPANION +ID_CAP_SMS_INTERCEPT_AGENT +ID_CAP_SMS_INTERCEPT_RECIPIENT +ID_CAP_SOUND_CONTROL +ID_CAP_SPEECH_GRAMMARS +ID_CAP_SPEECH_RECOGNITION +ID_CAP_SPEECH_RECOGNITION_SYSTEM +ID_CAP_SPEECH_SETTINGS +ID_CAP_SPEECH_UPDATE +ID_CAP_SPLASH_CONFIG +ID_CAP_STARTMENU_CONFIG +ID_CAP_STORAGE_MANAGEMENT +ID_CAP_SUPPRESS_MSA_CONNECT_ARD +ID_CAP_SYNC_EXTENSION +ID_CAP_SYSTEMTRAY_ADMIN +ID_CAP_SYSTEM_ALLOC_WINDOWID +ID_CAP_SYSTEM_COMPOSITOR +ID_CAP_SYSTEM_COUNTERS +ID_CAP_SYSTEM_REGISTRAR +ID_CAP_SYSTEM_WAITCURSOR +ID_CAP_TELEMETRY_ADMIN +ID_CAP_TELEMETRY_CONFIGURE +ID_CAP_TELEMETRY_STUDY +ID_CAP_TEST_NAVIGATION +ID_CAP_TILERESTOREDATA +ID_CAP_TOUCH +ID_CAP_TOUCH_TEST +ID_CAP_TPM_VSCMANAGER +ID_CAP_TS_SCHEDULES_ALL +ID_CAP_USB +ID_CAP_USER_ACTIVITY +ID_CAP_VIDEOSINK_INTERNAL +ID_CAP_VOICEMAIL +ID_CAP_VOIP +ID_CAP_VOIP_CALL_CONTROLLER +ID_CAP_VSTEST_INSTALL_FOLDER +ID_CAP_W32TIME_API +ID_CAP_WAB_RESOURCES +ID_CAP_WALLET +ID_CAP_WALLET_ADMIN +ID_CAP_WALLET_DEALS +ID_CAP_WALLET_PAYMENTINSTRUMENTS +ID_CAP_WALLET_SECUREELEMENT +ID_CAP_WALLPAPER_ADMIN +ID_CAP_WBOEXT +ID_CAP_WEBBROWSERCOMPONENT +ID_CAP_WEB_CREDENTIALS +ID_CAP_WIFI_ADMIN +ID_CAP_WIFI_BASIC +ID_CAP_WIFI_BROWSER +ID_CAP_WIFI_HOTSPOT_HOST +ID_CAP_WIFI_PROFILE_ADMIN +ID_CAP_WIFI_TILE_MANAGER +ID_CAP_WPN_PLATFORM +ID_CAP_WPN_PLATFORM_REG_KEY +ID_CAP_WPTOOLS_INSTALL_FOLDER +ID_CAP_ZMFSERVICES +ID_CAP_ZTRACE +accessoryManager +activateAsUser +activitySystem +allJoyn +appBroadcast +appBroadcastServices +appBroadcastSettings +appCaptureServices +appCaptureSettings +appLicensing +applicationDefaults +applicationViewActivation +appointments +appointmentsSystem +audioDeviceConfiguration +backgroundMediaPlayback +biometricSystem +blockedChatMessages +cellularDeviceControl +cellularDeviceIdentity +cellularMessaging +chat +chatSystem +childWebContent +cloudExperienceHost +cloudStore +codeGeneration +confirmAppClose +constrainedImpersonation +contacts +contactsSystem +contentDeliveryManagerSettings +contentRestrictions +coreShell +cortanaPermissions +cortanaSettings +cortanaSpeechAccessory +curatedTileCollections +developerSettings +developmentModeNetwork +deviceManagementAdministrator +deviceManagementDeviceLockPolicies +deviceManagementDmAccount +deviceManagementEmailAccount +deviceManagementFoundation +deviceManagementWapSecurityPolicies +deviceUnlock +documentsLibrary +dualSimTiles +email +emailSystem +enterpriseAuthentication +enterpriseDataPolicy +enterpriseDeviceLockdown +eraApplication +exclusiveResource +extendedExecutionBackgroundAudio +extendedExecutionCritical +extendedExecutionUnconstrained +featureStagingInfo +feedbackLogCollection +firstSignInSettings +flashPlayerSupport +gameBarServices +gameConfigStoreManagement +gameList +hevcPlayback +hfxSystem +hidTelephony +holographicCompositor +holographicCompositorSystem +indexedContent +inputForegroundObservation +inputInjection +inputInjectionBrokered +inputObservation +inputSuppression +internetClient +internetClientServer +interopServices +kinectAudio +kinectGamechat +liveIdService +locationHistory +locationSystem +lockScreenCreatives +lowLevelDevices +lpacAppExperience +lpacClipboard +lpacCom +lpacCryptoServices +lpacEnterprisePolicyChangeNotifications +lpacIdentityServices +lpacInstrumentation +lpacMedia +lpacPayments +lpacPnPNotifications +lpacPrinting +lpacServicesManagement +lpacSessionManagement +lpacWebPlatform +microsoftEdgeRemoteDebugging +multiplaneOverlay +muma +musicLibrary +networkConnectionManagerProvisioning +networkDataPlanProvisioning +networkDiagnostics +networkingVpnProvider +objects3D +oemDeployment +oemPublicDirectory +offlineMapsManagement +packageContents +packageManagement +packagePolicySystem +packageQuery +perceptionMonitoring +perceptionSystem +phoneCall +phoneCallHistory +phoneCallHistoryPublic +phoneCallHistorySystem +picturesLibrary +previewHfx +previewPenWorkspace +previewStore +previewUiComposition +privateNetworkClientServer +recordedCallsFolder +registryRead +relatedPackages +remotePassportAuthentication +remoteSystem +removableStorage +runFullTrust +screenDuplication +secondaryAuthenticationFactor +secureAssessment +sessionImpersonation +settingSyncConfiguration +sharedUserCertificates +shellExperience +shellExperienceComposer +slapiQueryLicenseValue +smsSend +smsSystem +spatialPerception +startScreenManagement +storeAppInstall +storeAppInstallation +storeConfiguration +storeLicenseManagement +systemManagement +systemRegistrar +targetedContent +targetedContentSubscription +teamEditionExperience +uiAutomationSystem +unzipFile +userAccountInformation +userDataAccountSetup +userDataAccountsProvider +userDataSystem +userDataTasks +userDataTasksSystem +userNotificationListener +userPrincipalName +userSigninSupport +userSystemId +userWebAccounts +videosLibrary +visualElementsSystem +visualVoiceMail +voipCall +walletSystem +windowsHelloCredentialAccess +xboxAccessoryManagement +xboxBroadcaster +xboxGameSpeechWindow +xboxLiveAuthenticationProvider +xboxSystemApplicationClipQuery +xboxTrackingStream diff --git a/tools/CustomBuildTool/Source Files/Build.cs b/tools/CustomBuildTool/Source Files/Build.cs index 91bd22420419..564b2532b288 100644 --- a/tools/CustomBuildTool/Source Files/Build.cs +++ b/tools/CustomBuildTool/Source Files/Build.cs @@ -536,6 +536,58 @@ public static bool CopyVersionHeader() return true; } + public static bool CopySidCapsFile(BuildFlags Flags) + { + //Program.PrintColorMessage("Copying capability sid support file...", ConsoleColor.Cyan); + + try + { + if (Flags.HasFlag(BuildFlags.BuildDebug)) + { + if (Flags.HasFlag(BuildFlags.Build32bit)) + { + Win32.CopyIfNewer( + "ProcessHacker\\resources\\capslist.txt", + "bin\\Debug32\\capslist.txt" + ); + } + + if (Flags.HasFlag(BuildFlags.Build64bit)) + { + Win32.CopyIfNewer( + "ProcessHacker\\resources\\capslist.txt", + "bin\\Debug64\\capslist.txt" + ); + } + } + else + { + if (Flags.HasFlag(BuildFlags.Build32bit)) + { + Win32.CopyIfNewer( + "ProcessHacker\\resources\\capslist.txt", + "bin\\Release32\\capslist.txt" + ); + } + + if (Flags.HasFlag(BuildFlags.Build64bit)) + { + Win32.CopyIfNewer( + "ProcessHacker\\resources\\capslist.txt", + "bin\\Release64\\capslist.txt" + ); + } + } + } + catch (Exception ex) + { + Program.PrintColorMessage("[ERROR] " + ex, ConsoleColor.Red); + return false; + } + + return true; + } + public static bool FixupResourceHeader() { try diff --git a/tools/CustomBuildTool/Source Files/Program.cs b/tools/CustomBuildTool/Source Files/Program.cs index dd7074721c65..82cd1a9a00ef 100644 --- a/tools/CustomBuildTool/Source Files/Program.cs +++ b/tools/CustomBuildTool/Source Files/Program.cs @@ -145,6 +145,8 @@ public static void Main(string[] args) if (!Build.CopyWow64Files(BuildFlags.None)) return; + if (!Build.CopySidCapsFile(BuildFlags.Build32bit | BuildFlags.Build64bit | BuildFlags.BuildVerbose)) + return; if (!Build.BuildBinZip()) return; @@ -190,6 +192,10 @@ public static void Main(string[] args) if (!Build.CopyWow64Files(BuildFlags.BuildDebug)) return; + if (!Build.CopySidCapsFile( + BuildFlags.Build32bit | BuildFlags.Build64bit | + BuildFlags.BuildDebug | BuildFlags.BuildVerbose)) + return; Build.ShowBuildStats(); } @@ -221,6 +227,8 @@ public static void Main(string[] args) if (!Build.CopyWow64Files(BuildFlags.None)) Environment.Exit(1); + if (!Build.CopySidCapsFile(BuildFlags.Build32bit | BuildFlags.Build64bit | BuildFlags.BuildVerbose)) + Environment.Exit(1); if (!Build.BuildBinZip()) Environment.Exit(1); @@ -270,6 +278,8 @@ public static void Main(string[] args) if (!Build.CopyWow64Files(BuildFlags.None)) return; + if (!Build.CopySidCapsFile(BuildFlags.Build32bit | BuildFlags.Build64bit | BuildFlags.BuildVerbose)) + return; Build.BuildAppxPackage(BuildFlags.Build32bit | BuildFlags.Build64bit | BuildFlags.BuildVerbose); @@ -317,6 +327,8 @@ public static void Main(string[] args) if (!Build.CopyWow64Files(BuildFlags.None)) return; + if (!Build.CopySidCapsFile(BuildFlags.Build32bit | BuildFlags.Build64bit | BuildFlags.BuildVerbose)) + return; if (!Build.BuildBinZip()) return; diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe b/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe index 57c0967834855b311643a3c73c0a9a3377ec31c1..e9aa76deb40f409e2638f385e7a8458234e49218 100644 GIT binary patch delta 16834 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 delta 16244 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 Date: Sun, 20 Jan 2019 11:21:47 +0100 Subject: [PATCH 1563/2058] Update Save textheader datetime format --- ProcessHacker/appsup.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/ProcessHacker/appsup.c b/ProcessHacker/appsup.c index 3de62015cd66..29bc0036a85f 100644 --- a/ProcessHacker/appsup.c +++ b/ProcessHacker/appsup.c @@ -1100,7 +1100,6 @@ VOID PhWritePhTextHeader( PPH_STRING version; LARGE_INTEGER time; SYSTEMTIME systemTime; - PPH_STRING dateString; PPH_STRING timeString; PhWriteStringAsUtf8FileStream2(FileStream, L"Process Hacker "); @@ -1125,10 +1124,8 @@ VOID PhWritePhTextHeader( PhQuerySystemTime(&time); PhLargeIntegerToLocalSystemTime(&systemTime, &time); - dateString = PhFormatDate(&systemTime, NULL); - timeString = PhFormatTime(&systemTime, NULL); - PhWriteStringFormatAsUtf8FileStream(FileStream, L"\r\n%s %s\r\n\r\n", dateString->Buffer, timeString->Buffer); - PhDereferenceObject(dateString); + timeString = PhFormatDateTime(&systemTime); + PhWriteStringFormatAsUtf8FileStream(FileStream, L"\r\n%s\r\n\r\n", timeString->Buffer); PhDereferenceObject(timeString); } From 697da280fe4983f029dad61ebbdbdb6fd80aa3ad Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 20 Jan 2019 11:24:07 +0100 Subject: [PATCH 1564/2058] Improve PhCreateProcessIgnoreIfeoDebugger handle usage, Remove legacy win32 debug wrappers --- ProcessHacker/appsup.c | 35 ++++++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/ProcessHacker/appsup.c b/ProcessHacker/appsup.c index 29bc0036a85f..57eae47c214d 100644 --- a/ProcessHacker/appsup.c +++ b/ProcessHacker/appsup.c @@ -1314,16 +1314,10 @@ BOOLEAN PhCreateProcessIgnoreIfeoDebugger( ) { BOOLEAN result; - BOOL (NTAPI *debugSetProcessKillOnExit)(BOOL); - BOOL (NTAPI *debugActiveProcessStop)(ULONG); BOOLEAN originalValue; STARTUPINFO startupInfo; PROCESS_INFORMATION processInfo; - if (!(debugSetProcessKillOnExit = PhGetDllProcedureAddress(L"kernel32.dll", "DebugSetProcessKillOnExit", 0)) || - !(debugActiveProcessStop = PhGetDllProcedureAddress(L"kernel32.dll", "DebugActiveProcessStop", 0))) - return FALSE; - result = FALSE; RtlEnterCriticalSection(NtCurrentPeb()->FastPebLock); @@ -1339,9 +1333,31 @@ BOOLEAN PhCreateProcessIgnoreIfeoDebugger( // allows us to skip the Debugger IFEO value. if (CreateProcess(FileName, NULL, NULL, NULL, FALSE, DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS, NULL, NULL, &startupInfo, &processInfo)) { - // Stop debugging the process now. - debugSetProcessKillOnExit(FALSE); - debugActiveProcessStop(processInfo.dwProcessId); + HANDLE debugObjectHandle; + + if (NT_SUCCESS(PhGetProcessDebugObject( + processInfo.hProcess, + &debugObjectHandle + ))) + { + ULONG killProcessOnExit; + + // Disable kill-on-close. + killProcessOnExit = 0; + NtSetInformationDebugObject( + debugObjectHandle, + DebugObjectKillProcessOnExitInformation, + &killProcessOnExit, + sizeof(ULONG), + NULL + ); + + // Stop debugging the process now. + NtRemoveProcessDebug(processInfo.hProcess, debugObjectHandle); + + NtClose(debugObjectHandle); + } + result = TRUE; } @@ -2126,3 +2142,4 @@ HBITMAP PhGetShieldBitmap( return shieldBitmap; } + From a8730caa2f73e34b017ba37fdab8ae02fc855f66 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 20 Jan 2019 11:26:36 +0100 Subject: [PATCH 1565/2058] Improve PhPluginCreateEMenuItem context usage --- ProcessHacker/plugin.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ProcessHacker/plugin.c b/ProcessHacker/plugin.c index 003a67b106bc..d70d69d403e2 100644 --- a/ProcessHacker/plugin.c +++ b/ProcessHacker/plugin.c @@ -796,8 +796,7 @@ PPH_EMENU_ITEM PhPluginCreateEMenuItem( pluginMenuItem->Id = Id; pluginMenuItem->Context = Context; - item = PhCreateEMenuItem(Flags, ID_PLUGIN_MENU_ITEM, Text, NULL, NULL); - item->Context = pluginMenuItem; + item = PhCreateEMenuItem(Flags, ID_PLUGIN_MENU_ITEM, Text, NULL, pluginMenuItem); item->DeleteFunction = PhpPluginEMenuItemDeleteFunction; return item; From 2bd2b7aa0106e5e7091d3c76cc28efff96478842 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 20 Jan 2019 11:38:49 +0100 Subject: [PATCH 1566/2058] Fix plugins not loading from Virtualbox and Vmware network shares --- ProcessHacker/plugin.c | 33 +++++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/ProcessHacker/plugin.c b/ProcessHacker/plugin.c index d70d69d403e2..5d25f22ffb8d 100644 --- a/ProcessHacker/plugin.c +++ b/ProcessHacker/plugin.c @@ -3,7 +3,7 @@ * plugin support * * Copyright (C) 2010-2015 wj32 - * Copyright (C) 2017-2018 dmex + * Copyright (C) 2017-2019 dmex * * This file is part of Process Hacker. * @@ -183,7 +183,7 @@ VOID PhSetPluginDisabled( } static BOOLEAN EnumPluginsDirectoryCallback( - _In_ PFILE_DIRECTORY_INFORMATION Information, + _In_ PFILE_NAMES_INFORMATION Information, _In_opt_ PVOID Context ) { @@ -290,16 +290,37 @@ VOID PhLoadPlugins( if (NT_SUCCESS(PhCreateFileWin32( &pluginsDirectoryHandle, PhGetString(PluginsDirectory), - FILE_GENERIC_READ, - FILE_ATTRIBUTE_NORMAL, - FILE_SHARE_READ, + FILE_LIST_DIRECTORY | SYNCHRONIZE, + FILE_ATTRIBUTE_DIRECTORY, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN, FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT ))) { UNICODE_STRING pattern = RTL_CONSTANT_STRING(L"*.dll"); - PhEnumDirectoryFile(pluginsDirectoryHandle, &pattern, EnumPluginsDirectoryCallback, pluginLoadErrors); + if (!NT_SUCCESS(PhEnumDirectoryFileEx( + pluginsDirectoryHandle, + FileNamesInformation, + FALSE, + &pattern, + EnumPluginsDirectoryCallback, + pluginLoadErrors + ))) + { + // Note: The MUP devices for Virtualbox and VMware improperly truncate + // data returned by NtQueryDirectoryFile when ReturnSingleEntry=FALSE and also have + // various other bugs and issues for information classes other than FileNamesInformation. (dmex) + PhEnumDirectoryFileEx( + pluginsDirectoryHandle, + FileNamesInformation, + TRUE, + &pattern, + EnumPluginsDirectoryCallback, + pluginLoadErrors + ); + } + NtClose(pluginsDirectoryHandle); } From 5059607e78c40c1a4e3cf3189b816fbc20cb42bb Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 20 Jan 2019 11:42:18 +0100 Subject: [PATCH 1567/2058] Add support for APP_CAPABILITY sid names on Win10 --- ProcessHacker/tokprp.c | 5 +- phlib/include/lsasup.h | 7 +++ phlib/lsasup.c | 113 +++++++++++++++++++++++++++++++++++++++++ phlib/secedit.c | 7 ++- 4 files changed, 130 insertions(+), 2 deletions(-) diff --git a/ProcessHacker/tokprp.c b/ProcessHacker/tokprp.c index 807486008eaa..7d426acb9e97 100644 --- a/ProcessHacker/tokprp.c +++ b/ProcessHacker/tokprp.c @@ -1961,7 +1961,10 @@ INT_PTR CALLBACK PhpTokenCapabilitiesPageProc( PPH_STRING name; //PPH_STRING attributesString; - name = PhGetSidFullName(tokenPageContext->Capabilities->Groups[i].Sid, TRUE, NULL); + name = PhGetCapabilitySidName(tokenPageContext->Capabilities->Groups[i].Sid); + + if (!name) + name = PhGetSidFullName(tokenPageContext->Capabilities->Groups[i].Sid, TRUE, NULL); if (!name) name = PhSidToStringSid(tokenPageContext->Capabilities->Groups[i].Sid); diff --git a/phlib/include/lsasup.h b/phlib/include/lsasup.h index dd16247d3a34..e9a1050fadac 100644 --- a/phlib/include/lsasup.h +++ b/phlib/include/lsasup.h @@ -89,6 +89,13 @@ PhGetTokenUserString( _In_ BOOLEAN IncludeDomain ); +PHLIBAPI +PPH_STRING +NTAPI +PhGetCapabilitySidName( + _In_ PSID CapabilitySid + ); + #ifdef __cplusplus } #endif diff --git a/phlib/lsasup.c b/phlib/lsasup.c index db2a0bef12b5..e37219e223c0 100644 --- a/phlib/lsasup.c +++ b/phlib/lsasup.c @@ -3,6 +3,7 @@ * LSA support functions * * Copyright (C) 2010-2011 wj32 + * Copyright (C) 2019 dmex * * This file is part of Process Hacker. * @@ -491,3 +492,115 @@ PPH_STRING PhGetTokenUserString( return tokenUserString; } + +typedef struct _PH_CAPABILITY_ENTRY +{ + PPH_STRING Name; + PSID CapabilityGroupSid; + PSID CapabilitySid; +} PH_CAPABILITY_ENTRY, *PPH_CAPABILITY_ENTRY; + +PH_ARRAY PhpSidCapArrayList; + +VOID PhInitializeCapabilitySidCache( + VOID + ) +{ + NTSTATUS (NTAPI *RtlDeriveCapabilitySidsFromName_I)( + _Inout_ PUNICODE_STRING UnicodeString, + _Out_ PSID CapabilityGroupSid, + _Out_ PSID CapabilitySid + ); + PPH_STRING applicationDirectory; + PPH_STRING capabilityListFileName; + PPH_STRING capabilityListString; + PH_STRINGREF namePart; + PH_STRINGREF remainingPart; + + if (!(RtlDeriveCapabilitySidsFromName_I = PhGetDllProcedureAddress(L"ntdll.dll", "RtlDeriveCapabilitySidsFromName", 0))) + return; + + if (applicationDirectory = PhGetApplicationDirectory()) + { + capabilityListFileName = PhConcatStringRefZ(&applicationDirectory->sr, L"capslist.txt"); + PhDereferenceObject(applicationDirectory); + + capabilityListString = PhFileReadAllText(capabilityListFileName->Buffer); + PhDereferenceObject(capabilityListFileName); + } + + if (PhIsNullOrEmptyString(capabilityListString)) + return; + + PhInitializeArray(&PhpSidCapArrayList, sizeof(PH_CAPABILITY_ENTRY), 800); + remainingPart = capabilityListString->sr; + + while (remainingPart.Length != 0) + { + PhSplitStringRefAtChar(&remainingPart, '\n', &namePart, &remainingPart); + + if (namePart.Length != 0) + { + BYTE capabilityGroupSidBuffer[SECURITY_MAX_SID_SIZE]; + BYTE capabilitySidBuffer[SECURITY_MAX_SID_SIZE]; + PSID capabilityGroupSid = (PSID)capabilityGroupSidBuffer; + PSID capabilitySid = (PSID)capabilitySidBuffer; + UNICODE_STRING capabilityNameUs; + + if (!PhStringRefToUnicodeString(&namePart, &capabilityNameUs)) + continue; + + if (NT_SUCCESS(RtlDeriveCapabilitySidsFromName_I( + &capabilityNameUs, + capabilityGroupSid, + capabilitySid + ))) + { + PH_CAPABILITY_ENTRY entry; + + entry.Name = PhCreateStringFromUnicodeString(&capabilityNameUs); + entry.CapabilityGroupSid = PhAllocateCopy(capabilityGroupSid, RtlLengthSid(capabilityGroupSid)); + entry.CapabilitySid = PhAllocateCopy(capabilitySid, RtlLengthSid(capabilitySid)); + + PhAddItemArray(&PhpSidCapArrayList, &entry); + } + } + } + + PhDereferenceObject(capabilityListString); +} + +PPH_STRING PhGetCapabilitySidName( + _In_ PSID CapabilitySid + ) +{ + static PH_INITONCE initOnce = PH_INITONCE_INIT; + PPH_CAPABILITY_ENTRY entry; + ULONG i; + + if (WindowsVersion < WINDOWS_8) + return NULL; + + if (PhBeginInitOnce(&initOnce)) + { + PhInitializeCapabilitySidCache(); + PhEndInitOnce(&initOnce); + } + + for (i = 0; i < PhpSidCapArrayList.Count; i++) + { + entry = PhItemArray(&PhpSidCapArrayList, i); + + if (RtlEqualSid(entry->CapabilitySid, CapabilitySid)) + { + return entry->Name; + } + + if (RtlEqualSid(entry->CapabilityGroupSid, CapabilitySid)) + { + return entry->Name; + } + } + + return NULL; +} diff --git a/phlib/secedit.c b/phlib/secedit.c index 83f482696cc8..c370278beda7 100644 --- a/phlib/secedit.c +++ b/phlib/secedit.c @@ -657,7 +657,6 @@ HRESULT STDMETHODCALLTYPE PhSecurityDataObject_GetData( SID_NAME_USE sidNameUse; memset(&sidInfo, 0, sizeof(SID_INFO)); - sidInfo.pSid = this->Sids[i]; if (sidString = PhGetSidFullName(sidInfo.pSid, FALSE, &sidNameUse)) @@ -692,6 +691,12 @@ HRESULT STDMETHODCALLTYPE PhSecurityDataObject_GetData( sidInfo.pwzCommonName = PhGetString(sidString); PhAddItemList(this->NameCache, sidString); } + else if (sidString = PhGetCapabilitySidName(sidInfo.pSid)) + { + PhMoveReference(&sidString, PhFormatString(L"%s (APP_CAPABILITY)", PhGetString(sidString))); + sidInfo.pwzCommonName = PhGetString(sidString); + PhAddItemList(this->NameCache, sidString); + } sidInfoList->aSidInfo[i] = sidInfo; } From 226678c2dde0bc6513a6107ce6e11f985caa71bd Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 20 Jan 2019 11:44:55 +0100 Subject: [PATCH 1568/2058] Update copyrights --- phlib/util.c | 2 +- plugins/ExtendedTools/gpumon.c | 2 +- plugins/ExtendedTools/gpuprprp.c | 2 +- tools/peview/propstore.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/phlib/util.c b/phlib/util.c index 6700f6390722..7d17e9dfaa9f 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -3,7 +3,7 @@ * general support functions * * Copyright (C) 2009-2016 wj32 - * Copyright (C) 2017 dmex + * Copyright (C) 2017-2019 dmex * * This file is part of Process Hacker. * diff --git a/plugins/ExtendedTools/gpumon.c b/plugins/ExtendedTools/gpumon.c index 36ccc352daa9..fe07f98847cb 100644 --- a/plugins/ExtendedTools/gpumon.c +++ b/plugins/ExtendedTools/gpumon.c @@ -3,7 +3,7 @@ * GPU monitoring * * Copyright (C) 2011-2015 wj32 - * Copyright (C) 2016 dmex + * Copyright (C) 2016-2018 dmex * * This file is part of Process Hacker. * diff --git a/plugins/ExtendedTools/gpuprprp.c b/plugins/ExtendedTools/gpuprprp.c index bf3c30fd3bc3..26675da073ad 100644 --- a/plugins/ExtendedTools/gpuprprp.c +++ b/plugins/ExtendedTools/gpuprprp.c @@ -3,7 +3,7 @@ * GPU process properties page * * Copyright (C) 2011 wj32 - * Copyright (C) 2015-2016 dmex + * Copyright (C) 2015-2018 dmex * * This file is part of Process Hacker. * diff --git a/tools/peview/propstore.c b/tools/peview/propstore.c index 7a54cdc477f3..328d1e756dd9 100644 --- a/tools/peview/propstore.c +++ b/tools/peview/propstore.c @@ -2,7 +2,7 @@ * Process Hacker - * PE viewer * - * Copyright (C) 2018 dmex + * Copyright (C) 2018-2019 dmex * * This file is part of Process Hacker. * From 5c2c0c146dc98eabc8bd449bdaceaa7f5152fcbf Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 20 Jan 2019 11:46:46 +0100 Subject: [PATCH 1569/2058] ToolStatus: Fix toolbar graph plugin name check --- plugins/ToolStatus/graph.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/plugins/ToolStatus/graph.c b/plugins/ToolStatus/graph.c index 964705aad56b..4e107af47920 100644 --- a/plugins/ToolStatus/graph.c +++ b/plugins/ToolStatus/graph.c @@ -97,15 +97,18 @@ VOID ToolbarGraphSaveSettings( if (!(graph->Flags & TOOLSTATUS_GRAPH_ENABLED)) continue; - pluginName = PhGetPluginName(graph->Plugin); + pluginName = graph->Plugin ? PhGetPluginName(graph->Plugin) : NULL; + PhAppendFormatStringBuilder( &graphListBuilder, L"%lu|%lu|%s|", graph->GraphId, graph->Flags & TOOLSTATUS_GRAPH_ENABLED ? 1 : 0, - graph->Plugin ? pluginName->Buffer : L"" + PhGetStringOrEmpty(pluginName) ); - PhDereferenceObject(pluginName); + + if (pluginName) + PhDereferenceObject(pluginName); } if (graphListBuilder.String->Length != 0) From 8d8251439db6ee3a9df960c89fbad3d56970ed9f Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 20 Jan 2019 11:59:53 +0100 Subject: [PATCH 1570/2058] Fix PhGetCapabilitySidName assert --- phlib/lsasup.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/phlib/lsasup.c b/phlib/lsasup.c index e37219e223c0..d8c16fc6df15 100644 --- a/phlib/lsasup.c +++ b/phlib/lsasup.c @@ -593,12 +593,12 @@ PPH_STRING PhGetCapabilitySidName( if (RtlEqualSid(entry->CapabilitySid, CapabilitySid)) { - return entry->Name; + return PhReferenceObject(entry->Name); } if (RtlEqualSid(entry->CapabilityGroupSid, CapabilitySid)) { - return entry->Name; + return PhReferenceObject(entry->Name); } } From 5248bf203c1163812c1be270275702d05279a4c6 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 20 Jan 2019 12:00:28 +0100 Subject: [PATCH 1571/2058] Fix token capabilities tab listview autosize --- ProcessHacker/tokprp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ProcessHacker/tokprp.c b/ProcessHacker/tokprp.c index 7d426acb9e97..09239a49879a 100644 --- a/ProcessHacker/tokprp.c +++ b/ProcessHacker/tokprp.c @@ -1982,8 +1982,8 @@ INT_PTR CALLBACK PhpTokenCapabilitiesPageProc( if (ListView_GetItemCount(lvHandle) != 0) { - ListView_SetColumnWidth(lvHandle, 0, LVSCW_AUTOSIZE); - ExtendedListView_SetColumnWidth(lvHandle, 1, ELVSCW_AUTOSIZE_REMAININGSPACE); + //ListView_SetColumnWidth(lvHandle, 0, LVSCW_AUTOSIZE); + ExtendedListView_SetColumnWidth(lvHandle, 0, ELVSCW_AUTOSIZE_REMAININGSPACE); } ExtendedListView_SortItems(lvHandle); From 10a654dd463478d66e8e2215cf5513f1d6e31c90 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 20 Jan 2019 12:43:39 +0100 Subject: [PATCH 1572/2058] Fix showing security editor for unnamed objects --- phlib/secedit.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/phlib/secedit.c b/phlib/secedit.c index c370278beda7..7519bbad0f78 100644 --- a/phlib/secedit.c +++ b/phlib/secedit.c @@ -567,7 +567,10 @@ BOOL STDMETHODCALLTYPE PhSecurityInformation3_GetFullResourceName( { PhSecurityInformation3 *this = (PhSecurityInformation3 *)This; - *ppszResourceName = PhGetString(this->Context->ObjectName); + if (PhIsNullOrEmptyString(this->Context->ObjectName)) + *ppszResourceName = PhGetString(this->Context->ObjectType); + else + *ppszResourceName = PhGetString(this->Context->ObjectName); return TRUE; } From d9f376ca1946e5d57bbba06d27a23415dcd29161 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 20 Jan 2019 14:39:53 +0100 Subject: [PATCH 1573/2058] Fix capslist parser line endings for CRLF and LF --- phlib/lsasup.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/phlib/lsasup.c b/phlib/lsasup.c index d8c16fc6df15..a07a0fbb2316 100644 --- a/phlib/lsasup.c +++ b/phlib/lsasup.c @@ -547,6 +547,9 @@ VOID PhInitializeCapabilitySidCache( PSID capabilitySid = (PSID)capabilitySidBuffer; UNICODE_STRING capabilityNameUs; + if (PhEndsWithStringRef2(&namePart, L"\r", FALSE)) + namePart.Length -= sizeof(WCHAR); + if (!PhStringRefToUnicodeString(&namePart, &capabilityNameUs)) continue; From 6a5f452a5123d96fe948206c20c952c8b1deacb7 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 20 Jan 2019 15:58:18 +0100 Subject: [PATCH 1574/2058] ExtendedTools: Fix gpu driver datetime --- plugins/ExtendedTools/gpumon.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/ExtendedTools/gpumon.c b/plugins/ExtendedTools/gpumon.c index fe07f98847cb..9e0fdc642acd 100644 --- a/plugins/ExtendedTools/gpumon.c +++ b/plugins/ExtendedTools/gpumon.c @@ -262,7 +262,7 @@ PPH_STRING EtpQueryDeviceProperty( FileTimeToLocalFileTime((PFILETIME)buffer, &newFileTime); FileTimeToSystemTime(&newFileTime, &systemTime); - string = PhFormatDateTime(&systemTime); + string = PhFormatDate(&systemTime, NULL); PhFree(buffer); return string; From 2c606ed0488052b7a0329ad356d815c5157c9fb7 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 20 Jan 2019 16:00:06 +0100 Subject: [PATCH 1575/2058] Fix find window menu memory leak --- ProcessHacker/findobj.c | 76 ++++++++++++++++++++++------------------- 1 file changed, 40 insertions(+), 36 deletions(-) diff --git a/ProcessHacker/findobj.c b/ProcessHacker/findobj.c index c58da2edebbd..ab56e38afba4 100644 --- a/ProcessHacker/findobj.c +++ b/ProcessHacker/findobj.c @@ -3,7 +3,7 @@ * object search * * Copyright (C) 2010-2016 wj32 - * Copyright (C) 2017-2018 dmex + * Copyright (C) 2017-2019 dmex * * This file is part of Process Hacker. * @@ -130,8 +130,8 @@ typedef struct _PH_HANDLE_OBJECT_TREE_ROOT_NODE PH_STRINGREF TextCache[PH_OBJECT_SEARCH_TREE_COLUMN_MAXIMUM]; } PH_HANDLE_OBJECT_TREE_ROOT_NODE, *PPH_HANDLE_OBJECT_TREE_ROOT_NODE; -#define SORT_FUNCTION(Column) HandleObjectTreeNewCompare##Column -#define BEGIN_SORT_FUNCTION(Column) static int __cdecl HandleObjectTreeNewCompare##Column( \ +#define SORT_FUNCTION(Column) PhpHandleObjectTreeNewCompare##Column +#define BEGIN_SORT_FUNCTION(Column) static int __cdecl PhpHandleObjectTreeNewCompare##Column( \ _In_ void *_context, \ _In_ const void *_elem1, \ _In_ const void *_elem2 \ @@ -184,7 +184,7 @@ BEGIN_SORT_FUNCTION(OriginalName) } END_SORT_FUNCTION -VOID HandleObjectLoadSettingsTreeList( +VOID PhpHandleObjectLoadSettingsTreeList( _Inout_ PPH_HANDLE_SEARCH_CONTEXT Context ) { @@ -195,7 +195,7 @@ VOID HandleObjectLoadSettingsTreeList( PhDereferenceObject(settings); } -VOID HandleObjectSaveSettingsTreeList( +VOID PhpHandleObjectSaveSettingsTreeList( _Inout_ PPH_HANDLE_SEARCH_CONTEXT Context ) { @@ -206,7 +206,7 @@ VOID HandleObjectSaveSettingsTreeList( PhDereferenceObject(settings); } -BOOLEAN HandleObjectNodeHashtableEqualFunction( +BOOLEAN PhpHandleObjectNodeHashtableEqualFunction( _In_ PVOID Entry1, _In_ PVOID Entry2 ) @@ -217,14 +217,14 @@ BOOLEAN HandleObjectNodeHashtableEqualFunction( return node1->HandleObject == node2->HandleObject; } -ULONG HandleObjectNodeHashtableHashFunction( +ULONG PhpHandleObjectNodeHashtableHashFunction( _In_ PVOID Entry ) { return PhHashIntPtr((ULONG_PTR)(*(PPH_HANDLE_OBJECT_TREE_ROOT_NODE*)Entry)->Handle); } -VOID DestroyHandleObjectNode( +VOID PhpDestroyHandleObjectNode( _In_ PPH_HANDLE_OBJECT_TREE_ROOT_NODE Node ) { @@ -236,7 +236,7 @@ VOID DestroyHandleObjectNode( PhDereferenceObject(Node); } -PPH_HANDLE_OBJECT_TREE_ROOT_NODE AddHandleObjectNode( +PPH_HANDLE_OBJECT_TREE_ROOT_NODE PhpAddHandleObjectNode( _Inout_ PPH_HANDLE_SEARCH_CONTEXT Context, _In_ HANDLE Handle ) @@ -263,7 +263,7 @@ PPH_HANDLE_OBJECT_TREE_ROOT_NODE AddHandleObjectNode( return handleObjectNode; } -PPH_HANDLE_OBJECT_TREE_ROOT_NODE FindHandleObjectNode( +PPH_HANDLE_OBJECT_TREE_ROOT_NODE PhpFindHandleObjectNode( _In_ PPH_HANDLE_SEARCH_CONTEXT Context, _In_ HANDLE Handle ) @@ -285,7 +285,7 @@ PPH_HANDLE_OBJECT_TREE_ROOT_NODE FindHandleObjectNode( return NULL; } -VOID RemoveHandleObjectNode( +VOID PhpRemoveHandleObjectNode( _In_ PPH_HANDLE_SEARCH_CONTEXT Context, _In_ PPH_HANDLE_OBJECT_TREE_ROOT_NODE Node ) @@ -299,11 +299,11 @@ VOID RemoveHandleObjectNode( PhRemoveItemList(Context->NodeList, index); } - DestroyHandleObjectNode(Node); + PhpDestroyHandleObjectNode(Node); TreeNew_NodesStructured(Context->TreeNewHandle); } -VOID UpdateHandleObjectNode( +VOID PhpUpdateHandleObjectNode( _In_ PPH_HANDLE_SEARCH_CONTEXT Context, _In_ PPH_HANDLE_OBJECT_TREE_ROOT_NODE Node ) @@ -314,7 +314,7 @@ VOID UpdateHandleObjectNode( TreeNew_NodesStructured(Context->TreeNewHandle); } -BOOLEAN NTAPI HandleObjectTreeNewCallback( +BOOLEAN NTAPI PhpHandleObjectTreeNewCallback( _In_ HWND hwnd, _In_ PH_TREENEW_MESSAGE Message, _In_opt_ PVOID Parameter1, @@ -473,12 +473,12 @@ BOOLEAN NTAPI HandleObjectTreeNewCallback( return FALSE; } -VOID ClearHandleObjectTree( +VOID PhpClearHandleObjectTree( _In_ PPH_HANDLE_SEARCH_CONTEXT Context ) { for (ULONG i = 0; i < Context->NodeList->Count; i++) - DestroyHandleObjectNode(Context->NodeList->Items[i]); + PhpDestroyHandleObjectNode(Context->NodeList->Items[i]); PhClearHashtable(Context->NodeHashtable); PhClearList(Context->NodeList); @@ -486,7 +486,7 @@ VOID ClearHandleObjectTree( TreeNew_NodesStructured(Context->TreeNewHandle); } -PPH_HANDLE_OBJECT_TREE_ROOT_NODE GetSelectedHandleObjectNode( +PPH_HANDLE_OBJECT_TREE_ROOT_NODE PhpGetSelectedHandleObjectNode( _In_ PPH_HANDLE_SEARCH_CONTEXT Context ) { @@ -503,7 +503,7 @@ PPH_HANDLE_OBJECT_TREE_ROOT_NODE GetSelectedHandleObjectNode( return NULL; } -VOID GetSelectedHandleObjectNodes( +VOID PhpGetSelectedHandleObjectNodes( _In_ PPH_HANDLE_SEARCH_CONTEXT Context, _Out_ PPH_HANDLE_OBJECT_TREE_ROOT_NODE **HandleObjectNodes, _Out_ PULONG NumberOfHandleObjectNodes @@ -529,21 +529,21 @@ VOID GetSelectedHandleObjectNodes( PhDereferenceObject(list); } -VOID InitializeHandleObjectTree( +VOID PhpInitializeHandleObjectTree( _Inout_ PPH_HANDLE_SEARCH_CONTEXT Context ) { Context->NodeList = PhCreateList(100); Context->NodeHashtable = PhCreateHashtable( sizeof(PPH_HANDLE_OBJECT_TREE_ROOT_NODE), - HandleObjectNodeHashtableEqualFunction, - HandleObjectNodeHashtableHashFunction, + PhpHandleObjectNodeHashtableEqualFunction, + PhpHandleObjectNodeHashtableHashFunction, 100 ); PhSetControlTheme(Context->TreeNewHandle, L"explorer"); - TreeNew_SetCallback(Context->TreeNewHandle, HandleObjectTreeNewCallback, Context); + TreeNew_SetCallback(Context->TreeNewHandle, PhpHandleObjectTreeNewCallback, Context); // Default columns PhAddTreeNewColumn(Context->TreeNewHandle, PH_OBJECT_SEARCH_TREE_COLUMN_PROCESS, TRUE, L"Process", 100, PH_ALIGN_LEFT, 0, 0); @@ -556,18 +556,18 @@ VOID InitializeHandleObjectTree( TreeNew_SetTriState(Context->TreeNewHandle, TRUE); - HandleObjectLoadSettingsTreeList(Context); + PhpHandleObjectLoadSettingsTreeList(Context); } -VOID DeleteHandleObjectTree( +VOID PhpDeleteHandleObjectTree( _In_ PPH_HANDLE_SEARCH_CONTEXT Context ) { - HandleObjectSaveSettingsTreeList(Context); + PhpHandleObjectSaveSettingsTreeList(Context); for (ULONG i = 0; i < Context->NodeList->Count; i++) { - DestroyHandleObjectNode(Context->NodeList->Items[i]); + PhpDestroyHandleObjectNode(Context->NodeList->Items[i]); } PhDereferenceObject(Context->NodeHashtable); @@ -710,7 +710,7 @@ VOID PhpFindObjectAddResultEntries( processItem = PhReferenceProcessItem(clientId.UniqueProcess); - objectNode = AddHandleObjectNode(Context, searchResult->Handle); + objectNode = PhpAddHandleObjectNode(Context, searchResult->Handle); objectNode->ProcessId = searchResult->ProcessId; objectNode->ResultType = searchResult->ResultType; objectNode->ClientIdName = PhGetClientIdNameEx(&clientId, processItem ? processItem->ProcessName : NULL); @@ -741,7 +741,7 @@ VOID PhpFindObjectClearResultEntries( _In_ PPH_HANDLE_SEARCH_CONTEXT Context ) { - ClearHandleObjectTree(Context); + PhpClearHandleObjectTree(Context); Context->SearchResultsAddIndex = 0; @@ -1153,7 +1153,7 @@ INT_PTR CALLBACK PhpFindObjectsDlgProc( PhRegisterDialog(hwndDlg); PhCreateSearchControl(hwndDlg, context->SearchWindowHandle, L"Find Handles or DLLs"); PhpPopulateObjectTypes(context->TypeWindowHandle); - InitializeHandleObjectTree(context); + PhpInitializeHandleObjectTree(context); PhInitializeLayoutManager(&context->LayoutManager, hwndDlg); PhAddLayoutItem(&context->LayoutManager, context->TypeWindowHandle, NULL, PH_ANCHOR_LEFT | PH_ANCHOR_TOP); @@ -1238,7 +1238,7 @@ INT_PTR CALLBACK PhpFindObjectsDlgProc( PhDeleteLayoutManager(&context->LayoutManager); - DeleteHandleObjectTree(context); + PhpDeleteHandleObjectTree(context); if (context->SearchResults) { @@ -1377,7 +1377,7 @@ INT_PTR CALLBACK PhpFindObjectsDlgProc( PPH_HANDLE_OBJECT_TREE_ROOT_NODE *handleObjectNodes = NULL; ULONG numberOfHandleObjectNodes = 0; - GetSelectedHandleObjectNodes(context, &handleObjectNodes, &numberOfHandleObjectNodes); + PhpGetSelectedHandleObjectNodes(context, &handleObjectNodes, &numberOfHandleObjectNodes); if (numberOfHandleObjectNodes != 0) { @@ -1405,6 +1405,8 @@ INT_PTR CALLBACK PhpFindObjectsDlgProc( PhDestroyEMenu(menu); } + + PhFree(handleObjectNodes); } break; case ID_OBJECT_CLOSE: @@ -1412,7 +1414,7 @@ INT_PTR CALLBACK PhpFindObjectsDlgProc( PPH_HANDLE_OBJECT_TREE_ROOT_NODE *handleObjectNodes = NULL; ULONG numberOfHandleObjectNodes = 0; - GetSelectedHandleObjectNodes(context, &handleObjectNodes, &numberOfHandleObjectNodes); + PhpGetSelectedHandleObjectNodes(context, &handleObjectNodes, &numberOfHandleObjectNodes); if (numberOfHandleObjectNodes != 0 && PhShowConfirmMessage( hwndDlg, @@ -1446,7 +1448,7 @@ INT_PTR CALLBACK PhpFindObjectsDlgProc( DUPLICATE_CLOSE_SOURCE ))) { - RemoveHandleObjectNode(context, handleObjectNodes[i]); + PhpRemoveHandleObjectNode(context, handleObjectNodes[i]); } NtClose(processHandle); @@ -1463,6 +1465,8 @@ INT_PTR CALLBACK PhpFindObjectsDlgProc( } } } + + PhFree(handleObjectNodes); } break; case ID_HANDLE_OBJECTPROPERTIES1: @@ -1470,7 +1474,7 @@ INT_PTR CALLBACK PhpFindObjectsDlgProc( { PPH_HANDLE_OBJECT_TREE_ROOT_NODE handleObjectNode; - if (handleObjectNode = GetSelectedHandleObjectNode(context)) + if (handleObjectNode = PhpGetSelectedHandleObjectNode(context)) { PH_HANDLE_ITEM_INFO info; @@ -1490,7 +1494,7 @@ INT_PTR CALLBACK PhpFindObjectsDlgProc( { PPH_HANDLE_OBJECT_TREE_ROOT_NODE handleObjectNode; - if (handleObjectNode = GetSelectedHandleObjectNode(context)) + if (handleObjectNode = PhpGetSelectedHandleObjectNode(context)) { PPH_PROCESS_NODE processNode; @@ -1507,7 +1511,7 @@ INT_PTR CALLBACK PhpFindObjectsDlgProc( { PPH_HANDLE_OBJECT_TREE_ROOT_NODE handleObjectNode; - if (handleObjectNode = GetSelectedHandleObjectNode(context)) + if (handleObjectNode = PhpGetSelectedHandleObjectNode(context)) { if (handleObjectNode->ResultType == HandleSearchResult) { From 6beb67784ca310a2fe981e861fd1d6bc9b827265 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 20 Jan 2019 16:12:38 +0100 Subject: [PATCH 1576/2058] peview: Add ProcessId tab --- tools/peview/include/peview.h | 7 ++ tools/peview/peprp.c | 10 ++ tools/peview/peview.rc | 23 +++++ tools/peview/peview.vcxproj | 1 + tools/peview/peview.vcxproj.filters | 3 + tools/peview/processes.c | 146 ++++++++++++++++++++++++++++ tools/peview/resource.h | 1 + 7 files changed, 191 insertions(+) create mode 100644 tools/peview/processes.c diff --git a/tools/peview/include/peview.h b/tools/peview/include/peview.h index b33cc1c6fc3c..f6ec483da514 100644 --- a/tools/peview/include/peview.h +++ b/tools/peview/include/peview.h @@ -364,6 +364,13 @@ INT_PTR CALLBACK PvpPeLinksDlgProc( _In_ LPARAM lParam ); +INT_PTR CALLBACK PvpPeProcessesDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + // ELF PWSTR PvpGetSymbolTypeName( diff --git a/tools/peview/peprp.c b/tools/peview/peprp.c index 94ee9d583a48..04fbd85449d2 100644 --- a/tools/peview/peprp.c +++ b/tools/peview/peprp.c @@ -218,6 +218,16 @@ VOID PvPeProperties( PvAddPropPage(propContext, newPage); } + // Processes page + { + newPage = PvCreatePropPageContext( + MAKEINTRESOURCE(IDD_PIDS), + PvpPeProcessesDlgProc, + NULL + ); + PvAddPropPage(propContext, newPage); + } + // Symbols page if (NT_SUCCESS(PhGetMappedImageDataEntry(&PvMappedImage, IMAGE_DIRECTORY_ENTRY_DEBUG, &entry)) && entry->VirtualAddress) { diff --git a/tools/peview/peview.rc b/tools/peview/peview.rc index 24ac2bb65465..e5cdfad0d13b 100644 --- a/tools/peview/peview.rc +++ b/tools/peview/peview.rc @@ -165,6 +165,21 @@ BEGIN BOTTOMMARGIN, 277 END + IDD_PIDS, DIALOG + BEGIN + LEFTMARGIN, 3 + RIGHTMARGIN, 297 + TOPMARGIN, 3 + BOTTOMMARGIN, 277 + END + + IDD_ELFDYNAMIC, DIALOG + BEGIN + LEFTMARGIN, 3 + RIGHTMARGIN, 297 + TOPMARGIN, 3 + BOTTOMMARGIN, 277 + END END #endif // APSTUDIO_INVOKED @@ -327,6 +342,14 @@ BEGIN CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,3,3,294,274 END +IDD_PIDS DIALOGEX 0, 0, 300, 280 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Pids" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,3,3,294,274 +END + IDD_ELFDYNAMIC DIALOGEX 0, 0, 300, 280 STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Dynamic" diff --git a/tools/peview/peview.vcxproj b/tools/peview/peview.vcxproj index 3c8d52349f93..a1ed0800c9f8 100644 --- a/tools/peview/peview.vcxproj +++ b/tools/peview/peview.vcxproj @@ -237,6 +237,7 @@ + diff --git a/tools/peview/peview.vcxproj.filters b/tools/peview/peview.vcxproj.filters index 845edd253013..c62e52a0acac 100644 --- a/tools/peview/peview.vcxproj.filters +++ b/tools/peview/peview.vcxproj.filters @@ -93,6 +93,9 @@ Source Files\Pages\Windows + + Source Files + Source Files\Pages\Linux diff --git a/tools/peview/processes.c b/tools/peview/processes.c new file mode 100644 index 000000000000..6cf6c10e439f --- /dev/null +++ b/tools/peview/processes.c @@ -0,0 +1,146 @@ +/* + * Process Hacker - + * PE viewer + * + * Copyright (C) 2019 dmex + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include + +VOID PvpPeEnumerateProcessIds( + _In_ HWND ListViewHandle + ) +{ + HANDLE fileHandle; + + if (NT_SUCCESS(PhCreateFileWin32( + &fileHandle, + PhGetString(PvFileName), + FILE_READ_ATTRIBUTES | SYNCHRONIZE, + FILE_ATTRIBUTE_NORMAL, + FILE_SHARE_READ, + FILE_OPEN, + FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT + ))) + { + PFILE_PROCESS_IDS_USING_FILE_INFORMATION processIds; + ULONG count = 0; + ULONG i; + + if (NT_SUCCESS(PhGetProcessIdsUsingFile( + fileHandle, + &processIds + ))) + { + for (i = 0; i < processIds->NumberOfProcessIdsInList; i++) + { + INT lvItemIndex; + HANDLE processId; + PPH_STRING fileName = NULL; + WCHAR number[PH_INT32_STR_LEN_1]; + + processId = (HANDLE)processIds->ProcessIdList[i]; + + if (processId == SYSTEM_PROCESS_ID) + fileName = PhGetKernelFileName(); + else + PhGetProcessImageFileNameByProcessId(processId, &fileName); + + if (fileName) + PhMoveReference(&fileName, PhGetFileName(fileName)); + + PhPrintUInt32(number, ++count); + lvItemIndex = PhAddListViewItem(ListViewHandle, MAXINT, number, NULL); + + PhPrintUInt32(number, HandleToUlong(processId)); + PhSetListViewSubItem(ListViewHandle, lvItemIndex, 1, number); + + PhSetListViewSubItem(ListViewHandle, lvItemIndex, 2, fileName->Buffer); + PhDereferenceObject(fileName); + } + + PhFree(processIds); + } + + NtClose(fileHandle); + } +} + +INT_PTR CALLBACK PvpPeProcessesDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + LPPROPSHEETPAGE propSheetPage; + PPV_PROPPAGECONTEXT propPageContext; + + if (!PvPropPageDlgProcHeader(hwndDlg, uMsg, lParam, &propSheetPage, &propPageContext)) + return FALSE; + + switch (uMsg) + { + case WM_INITDIALOG: + { + HWND lvHandle; + + lvHandle = GetDlgItem(hwndDlg, IDC_LIST); + PhSetListViewStyle(lvHandle, TRUE, TRUE); + PhSetControlTheme(lvHandle, L"explorer"); + PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 40, L"#"); + PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 150, L"PID"); + PhAddListViewColumn(lvHandle, 2, 2, 2, LVCFMT_LEFT, 150, L"Name"); + PhSetExtendedListView(lvHandle); + PhLoadListViewColumnsFromSetting(L"ImagePidsListViewColumns", lvHandle); + + PvpPeEnumerateProcessIds(lvHandle); + //ExtendedListView_SortItems(lvHandle); + + EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); + } + break; + case WM_DESTROY: + { + PhSaveListViewColumnsToSetting(L"ImagePidsListViewColumns", GetDlgItem(hwndDlg, IDC_LIST)); + } + break; + case WM_SHOWWINDOW: + { + if (!propPageContext->LayoutInitialized) + { + PPH_LAYOUT_ITEM dialogItem; + + dialogItem = PvAddPropPageLayoutItem(hwndDlg, hwndDlg, PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL); + PvAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_LIST), dialogItem, PH_ANCHOR_ALL); + + PvDoPropPageLayout(hwndDlg); + + propPageContext->LayoutInitialized = TRUE; + } + } + break; + case WM_NOTIFY: + { + PvHandleListViewNotifyForCopy(lParam, GetDlgItem(hwndDlg, IDC_LIST)); + } + break; + } + + return FALSE; +} diff --git a/tools/peview/resource.h b/tools/peview/resource.h index 91fb013ec773..b2ea897b6f19 100644 --- a/tools/peview/resource.h +++ b/tools/peview/resource.h @@ -20,6 +20,7 @@ #define IDB_SEARCH_INACTIVE_BMP 113 #define IDD_PESTREAMS 113 #define IDD_PELINKS 114 +#define IDD_PIDS 115 #define IDD_ELFDYNAMIC 116 #define IDC_SYMBOLTREE 119 #define IDC_TARGETMACHINE 1003 From bef51ca3c88e195a613cb9dffb20c9e59579ad71 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 20 Jan 2019 16:15:00 +0100 Subject: [PATCH 1577/2058] Add copy menus to token properties window --- ProcessHacker/tokprp.c | 251 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 225 insertions(+), 26 deletions(-) diff --git a/ProcessHacker/tokprp.c b/ProcessHacker/tokprp.c index 09239a49879a..f030874a5e6e 100644 --- a/ProcessHacker/tokprp.c +++ b/ProcessHacker/tokprp.c @@ -76,6 +76,7 @@ typedef struct _ATTRIBUTE_NODE typedef struct _ATTRIBUTE_TREE_CONTEXT { + HWND WindowHandle; PPH_LIST RootList; PPH_LIST NodeList; } ATTRIBUTE_TREE_CONTEXT, *PATTRIBUTE_TREE_CONTEXT; @@ -403,13 +404,13 @@ VOID PhpTokenPageFreeListViewEntries( _In_ PTOKEN_PAGE_CONTEXT TokenPageContext ) { - ULONG index = -1; + ULONG index = ULONG_MAX; while ((index = PhFindListViewItemByFlags( TokenPageContext->ListViewHandle, index, LVNI_ALL - )) != -1) + )) != ULONG_MAX) { PPHP_TOKEN_PAGE_LISTVIEW_ITEM entry; @@ -1260,14 +1261,14 @@ INT_PTR CALLBACK PhpTokenPageProc( GetWindowRect(GetDlgItem(hwndDlg, IDC_INTEGRITY), &rect); menu = PhCreateEMenu(); - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, MandatorySecureProcessRID, L"Protected", NULL, NULL), -1); - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, MandatorySystemRID, L"System", NULL, NULL), -1); - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, MandatoryHighRID, L"High", NULL, NULL), -1); - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, MandatoryMediumRID, L"Medium", NULL, NULL), -1); - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, MandatoryLowRID, L"Low", NULL, NULL), -1); - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, MandatoryUntrustedRID, L"Untrusted", NULL, NULL), -1); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, MandatorySecureProcessRID, L"Protected", NULL, NULL), ULONG_MAX); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, MandatorySystemRID, L"System", NULL, NULL), ULONG_MAX); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, MandatoryHighRID, L"High", NULL, NULL), ULONG_MAX); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, MandatoryMediumRID, L"Medium", NULL, NULL), ULONG_MAX); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, MandatoryLowRID, L"Low", NULL, NULL), ULONG_MAX); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, MandatoryUntrustedRID, L"Untrusted", NULL, NULL), ULONG_MAX); - integrityLevelRID = -1; + integrityLevelRID = ULONG_MAX; // Put a radio check on the menu item that corresponds with the current integrity level. // Also disable menu items which correspond to higher integrity levels since @@ -1643,7 +1644,7 @@ INT_PTR CALLBACK PhpTokenGeneralPageProc( PPH_STRING tokenUserSid = NULL; PPH_STRING tokenOwnerName = NULL; PPH_STRING tokenPrimaryGroupName = NULL; - ULONG tokenSessionId = -1; + ULONG tokenSessionId = ULONG_MAX; PWSTR tokenElevated = L"N/A"; BOOLEAN hasLinkedToken = FALSE; PWSTR tokenVirtualization = L"N/A"; @@ -1749,7 +1750,7 @@ INT_PTR CALLBACK PhpTokenGeneralPageProc( PhSetDialogItemText(hwndDlg, IDC_OWNER, PhGetStringOrDefault(tokenOwnerName, L"Unknown")); PhSetDialogItemText(hwndDlg, IDC_PRIMARYGROUP, PhGetStringOrDefault(tokenPrimaryGroupName, L"Unknown")); - if (tokenSessionId != -1) + if (tokenSessionId != ULONG_MAX) PhSetDialogItemValue(hwndDlg, IDC_SESSIONID, tokenSessionId, FALSE); else PhSetDialogItemText(hwndDlg, IDC_SESSIONID, L"Unknown"); @@ -1885,8 +1886,8 @@ INT_PTR CALLBACK PhpTokenAdvancedPageProc( // DynamicCharged contains the number of bytes allocated. // DynamicAvailable contains the number of bytes free. - memoryUsed = PhaFormatSize(statistics.DynamicCharged - statistics.DynamicAvailable, -1); - memoryAvailable = PhaFormatSize(statistics.DynamicCharged, -1); + memoryUsed = PhaFormatSize(statistics.DynamicCharged - statistics.DynamicAvailable, ULONG_MAX); + memoryAvailable = PhaFormatSize(statistics.DynamicCharged, ULONG_MAX); } NtClose(tokenHandle); @@ -1974,24 +1975,19 @@ INT_PTR CALLBACK PhpTokenCapabilitiesPageProc( lvItemIndex = PhAddListViewItem(lvHandle, MAXINT, name->Buffer, &tokenPageContext->Capabilities->Groups[i]); //attributesString = PhGetGroupAttributesString(tokenPageContext->Capabilities->Groups[i].Attributes, FALSE); //PhSetListViewSubItem(lvHandle, lvItemIndex, 1, attributesString->Buffer); - // //PhDereferenceObject(attributesString); PhDereferenceObject(name); } } - if (ListView_GetItemCount(lvHandle) != 0) - { - //ListView_SetColumnWidth(lvHandle, 0, LVSCW_AUTOSIZE); - ExtendedListView_SetColumnWidth(lvHandle, 0, ELVSCW_AUTOSIZE_REMAININGSPACE); - } - ExtendedListView_SortItems(lvHandle); } NtClose(tokenHandle); } + ExtendedListView_SetColumnWidth(lvHandle, 0, ELVSCW_AUTOSIZE_REMAININGSPACE); + PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport); } break; @@ -2006,6 +2002,61 @@ INT_PTR CALLBACK PhpTokenCapabilitiesPageProc( PhHandleListViewNotifyBehaviors(lParam, lvHandle, PH_LIST_VIEW_DEFAULT_1_BEHAVIORS); } break; + case WM_CONTEXTMENU: + { + if ((HWND)wParam == lvHandle) + { + POINT point; + PPH_EMENU menu; + PPH_EMENU item; + PVOID *listviewItems; + ULONG numberOfItems; + + point.x = GET_X_LPARAM(lParam); + point.y = GET_Y_LPARAM(lParam); + + if (point.x == -1 && point.y == -1) + PhGetListViewContextMenuPoint((HWND)wParam, &point); + + PhGetSelectedListViewItemParams(lvHandle, &listviewItems, &numberOfItems); + + if (numberOfItems != 0) + { + menu = PhCreateEMenu(); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, IDC_COPY, L"&Copy", NULL, NULL), ULONG_MAX); + PhInsertCopyListViewEMenuItem(menu, IDC_COPY, lvHandle); + + item = PhShowEMenu( + menu, + hwndDlg, + PH_EMENU_SHOW_SEND_COMMAND | PH_EMENU_SHOW_LEFTRIGHT, + PH_ALIGN_LEFT | PH_ALIGN_TOP, + point.x, + point.y + ); + + if (item && item->Id != ULONG_MAX) + { + if (!PhHandleCopyListViewEMenuItem(item)) + { + switch (item->Id) + { + case IDC_COPY: + { + PhCopyListView(lvHandle); + } + break; + } + } + } + + PhDestroyEMenu(menu); + } + + PhFree(listviewItems); + } + } + break; } REFLECT_MESSAGE_DLG(hwndDlg, lvHandle, uMsg, wParam, lParam); @@ -2086,6 +2137,18 @@ BOOLEAN NTAPI PhpAttributeTreeNewCallback( } } return TRUE; + case TreeNewContextMenu: + { + PPH_TREENEW_CONTEXT_MENU contextMenuEvent = Parameter1; + + SendMessage( + context->WindowHandle, + WM_CONTEXTMENU, + 0, + (LPARAM)contextMenuEvent + ); + } + return TRUE; } return FALSE; @@ -2126,20 +2189,46 @@ VOID PhpDestroyAttributeNode( PhFree(Node); } +VOID PhpGetSelectedAttributeTreeNodes( + _Inout_ PATTRIBUTE_TREE_CONTEXT Context, + _Out_ PATTRIBUTE_NODE **AttributeNodes, + _Out_ PULONG NumberOfAttributeNodes + ) +{ + PPH_LIST list; + + list = PhCreateList(2); + + for (ULONG i = 0; i < Context->NodeList->Count; i++) + { + PATTRIBUTE_NODE node = (PATTRIBUTE_NODE)Context->NodeList->Items[i]; + + if (node->Node.Selected) + { + PhAddItemList(list, node); + } + } + + *AttributeNodes = PhAllocateCopy(list->Items, sizeof(PVOID) * list->Count); + *NumberOfAttributeNodes = list->Count; + + PhDereferenceObject(list); +} + VOID PhpInitializeAttributeTreeContext( _Out_ PATTRIBUTE_TREE_CONTEXT Context, + _In_ HWND WindowHandle, _In_ HWND TreeNewHandle ) { - PH_TREENEW_VIEW_PARTS parts; - + Context->WindowHandle = WindowHandle; Context->NodeList = PhCreateList(10); Context->RootList = PhCreateList(10); PhSetControlTheme(TreeNewHandle, L"explorer"); TreeNew_SetCallback(TreeNewHandle, PhpAttributeTreeNewCallback, Context); - TreeNew_GetViewParts(TreeNewHandle, &parts); - PhAddTreeNewColumnEx2(TreeNewHandle, 0, TRUE, L"Attributes", parts.ClientRect.right - parts.VScrollWidth, PH_ALIGN_LEFT, 0, 0, TN_COLUMN_FLAG_NODPISCALEONADD); + //TreeNew_GetViewParts(TreeNewHandle, &parts); // column width = (parts.ClientRect.right - parts.VScrollWidth) // TODO: VScrollWidth not set during INITDIALOG. (dmex) + PhAddTreeNewColumnEx2(TreeNewHandle, 0, TRUE, L"Attributes", 200, PH_ALIGN_LEFT, 0, 0, TN_COLUMN_FLAG_NODPISCALEONADD); } VOID PhpDeleteAttributeTreeContext( @@ -2394,7 +2483,7 @@ INT_PTR CALLBACK PhpTokenClaimsPageProc( PATTRIBUTE_NODE userNode; PATTRIBUTE_NODE deviceNode; - PhpInitializeAttributeTreeContext(&tokenPageContext->ClaimsTreeContext, tnHandle); + PhpInitializeAttributeTreeContext(&tokenPageContext->ClaimsTreeContext, hwndDlg, tnHandle); TreeNew_SetRedraw(tnHandle, FALSE); @@ -2419,6 +2508,61 @@ INT_PTR CALLBACK PhpTokenClaimsPageProc( PhpDeleteAttributeTreeContext(&tokenPageContext->ClaimsTreeContext); } break; + case WM_SHOWWINDOW: + { + TreeNew_AutoSizeColumn(tnHandle, 0, TN_AUTOSIZE_REMAINING_SPACE); + } + break; + case WM_CONTEXTMENU: + { + PPH_TREENEW_CONTEXT_MENU contextMenuEvent = (PPH_TREENEW_CONTEXT_MENU)lParam; + PPH_EMENU menu; + PPH_EMENU_ITEM selectedItem; + PATTRIBUTE_NODE *attributeObjectNodes = NULL; + ULONG numberOfAttributeObjectNodes = 0; + + PhpGetSelectedAttributeTreeNodes(&tokenPageContext->ClaimsTreeContext, &attributeObjectNodes, &numberOfAttributeObjectNodes); + + if (numberOfAttributeObjectNodes != 0) + { + menu = PhCreateEMenu(); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, IDC_COPY, L"Copy", NULL, NULL), ULONG_MAX); + PhInsertCopyCellEMenuItem(menu, IDC_COPY, tnHandle, contextMenuEvent->Column); + + selectedItem = PhShowEMenu( + menu, + hwndDlg, + PH_EMENU_SHOW_SEND_COMMAND | PH_EMENU_SHOW_LEFTRIGHT, + PH_ALIGN_LEFT | PH_ALIGN_TOP, + contextMenuEvent->Location.x, + contextMenuEvent->Location.y + ); + + if (selectedItem && selectedItem->Id != ULONG_MAX) + { + if (!PhHandleCopyCellEMenuItem(selectedItem)) + { + switch (selectedItem->Id) + { + case IDC_COPY: + { + PPH_STRING text; + + text = PhGetTreeNewText(tnHandle, 0); + PhSetClipboardString(tnHandle, &text->sr); + PhDereferenceObject(text); + } + break; + } + } + } + + PhDestroyEMenu(menu); + } + + PhFree(attributeObjectNodes); + } + break; } return FALSE; @@ -2502,7 +2646,7 @@ INT_PTR CALLBACK PhpTokenAttributesPageProc( { case WM_INITDIALOG: { - PhpInitializeAttributeTreeContext(&tokenPageContext->AuthzTreeContext, tnHandle); + PhpInitializeAttributeTreeContext(&tokenPageContext->AuthzTreeContext, hwndDlg, tnHandle); TreeNew_SetRedraw(tnHandle, FALSE); @@ -2522,6 +2666,61 @@ INT_PTR CALLBACK PhpTokenAttributesPageProc( PhpDeleteAttributeTreeContext(&tokenPageContext->AuthzTreeContext); } break; + case WM_SHOWWINDOW: + { + TreeNew_AutoSizeColumn(tnHandle, 0, TN_AUTOSIZE_REMAINING_SPACE); + } + break; + case WM_CONTEXTMENU: + { + PPH_TREENEW_CONTEXT_MENU contextMenuEvent = (PPH_TREENEW_CONTEXT_MENU)lParam; + PPH_EMENU menu; + PPH_EMENU_ITEM selectedItem; + PATTRIBUTE_NODE *attributeObjectNodes = NULL; + ULONG numberOfAttributeObjectNodes = 0; + + PhpGetSelectedAttributeTreeNodes(&tokenPageContext->AuthzTreeContext, &attributeObjectNodes, &numberOfAttributeObjectNodes); + + if (numberOfAttributeObjectNodes != 0) + { + menu = PhCreateEMenu(); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, IDC_COPY, L"Copy", NULL, NULL), ULONG_MAX); + PhInsertCopyCellEMenuItem(menu, IDC_COPY, tnHandle, contextMenuEvent->Column); + + selectedItem = PhShowEMenu( + menu, + hwndDlg, + PH_EMENU_SHOW_SEND_COMMAND | PH_EMENU_SHOW_LEFTRIGHT, + PH_ALIGN_LEFT | PH_ALIGN_TOP, + contextMenuEvent->Location.x, + contextMenuEvent->Location.y + ); + + if (selectedItem && selectedItem->Id != ULONG_MAX) + { + if (!PhHandleCopyCellEMenuItem(selectedItem)) + { + switch (selectedItem->Id) + { + case IDC_COPY: + { + PPH_STRING text; + + text = PhGetTreeNewText(tnHandle, 0); + PhSetClipboardString(tnHandle, &text->sr); + PhDereferenceObject(text); + } + break; + } + } + } + + PhDestroyEMenu(menu); + } + + PhFree(attributeObjectNodes); + } + break; } return FALSE; From e8aea792f096fd33629b94fa132389c58ae13474 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 20 Jan 2019 16:39:30 +0100 Subject: [PATCH 1578/2058] Fix memory leak --- ProcessHacker/ProcessHacker.vcxproj | 1 - ProcessHacker/ProcessHacker.vcxproj.filters | 3 --- 2 files changed, 4 deletions(-) diff --git a/ProcessHacker/ProcessHacker.vcxproj b/ProcessHacker/ProcessHacker.vcxproj index 72077726060d..cb239e9a62fe 100644 --- a/ProcessHacker/ProcessHacker.vcxproj +++ b/ProcessHacker/ProcessHacker.vcxproj @@ -421,7 +421,6 @@ - diff --git a/ProcessHacker/ProcessHacker.vcxproj.filters b/ProcessHacker/ProcessHacker.vcxproj.filters index 8019809825fb..a7ddace7b009 100644 --- a/ProcessHacker/ProcessHacker.vcxproj.filters +++ b/ProcessHacker/ProcessHacker.vcxproj.filters @@ -576,9 +576,6 @@ Resources - - Resources - From 8ee242f8a22be875fa565bb0dd8908252aa3a25f Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 20 Jan 2019 16:40:02 +0100 Subject: [PATCH 1579/2058] Fix size check --- ProcessHacker/memprv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ProcessHacker/memprv.c b/ProcessHacker/memprv.c index b49267f95291..108b7335bdb9 100644 --- a/ProcessHacker/memprv.c +++ b/ProcessHacker/memprv.c @@ -545,7 +545,7 @@ NTSTATUS PhpUpdateMemoryRegionTypes( PhDereferenceObject(ntdllFileName); - if (NT_SUCCESS(status) && ldrInitBlock.Size) + if (NT_SUCCESS(status) && ldrInitBlock.Size != 0) { PVOID cfgBitmapAddress = NULL; PVOID cfgBitmapWow64Address = NULL; From 208154f5b178c166fed20c58a013c64ae2c0f146 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 20 Jan 2019 16:43:36 +0100 Subject: [PATCH 1580/2058] Merge wj32's HexPidPlugin; Add PID (Hex) column, Add TID (Hex) column, Remove ShowHexId options --- ProcessHacker/include/phsettings.h | 1 - ProcessHacker/include/proctree.h | 4 +++- ProcessHacker/include/thrdlist.h | 2 ++ ProcessHacker/options.c | 4 ---- ProcessHacker/procprv.c | 10 +++------- ProcessHacker/proctree.c | 17 +++++++++++++++++ ProcessHacker/thrdlist.c | 19 +++++++++++++++---- 7 files changed, 40 insertions(+), 17 deletions(-) diff --git a/ProcessHacker/include/phsettings.h b/ProcessHacker/include/phsettings.h index bae52f79a88f..44efb3517bb7 100644 --- a/ProcessHacker/include/phsettings.h +++ b/ProcessHacker/include/phsettings.h @@ -15,7 +15,6 @@ EXT BOOLEAN PhEnableProcessQueryStage2; EXT BOOLEAN PhEnableServiceQueryStage2; EXT BOOLEAN PhEnableThemeSupport; EXT BOOLEAN PhEnableTooltipSupport; -EXT BOOLEAN PhEnableHexId; EXT ULONG PhCsCollapseServicesOnStart; EXT ULONG PhCsForceNoParent; diff --git a/ProcessHacker/include/proctree.h b/ProcessHacker/include/proctree.h index 11b406adb0b9..1b07fe8bb18f 100644 --- a/ProcessHacker/include/proctree.h +++ b/ProcessHacker/include/proctree.h @@ -94,8 +94,9 @@ #define PHPRTLC_PROTECTION 81 #define PHPRTLC_DESKTOP 82 #define PHPRTLC_CRITICAL 83 +#define PHPRTLC_PIDHEX 84 -#define PHPRTLC_MAXIMUM 84 +#define PHPRTLC_MAXIMUM 85 #define PHPRTLC_IOGROUP_COUNT 9 #define PHPN_WSCOUNTERS 0x1 @@ -228,6 +229,7 @@ typedef struct _PH_PROCESS_NODE PPH_STRING ProtectionText; PPH_STRING DesktopInfoText; PPH_STRING UserName; + WCHAR PidHexText[PH_PTR_STR_LEN_1]; // Graph buffers PH_GRAPH_BUFFERS CpuGraphBuffers; diff --git a/ProcessHacker/include/thrdlist.h b/ProcessHacker/include/thrdlist.h index 9e0153dde5a7..2a876e5d8a75 100644 --- a/ProcessHacker/include/thrdlist.h +++ b/ProcessHacker/include/thrdlist.h @@ -28,6 +28,7 @@ typedef enum _PH_THREAD_TREELIST_COLUMN PH_THREAD_TREELIST_COLUMN_USERTIME, PH_THREAD_TREELIST_COLUMN_IDEALPROCESSOR, PH_THREAD_TREELIST_COLUMN_CRITICAL, + PH_THREAD_TREELIST_COLUMN_TIDHEX, PH_THREAD_TREELIST_COLUMN_MAXIMUM } PH_THREAD_TREELIST_COLUMN; @@ -64,6 +65,7 @@ typedef struct _PH_THREAD_NODE WCHAR KernelTimeText[PH_TIMESPAN_STR_LEN_1]; WCHAR UserTimeText[PH_TIMESPAN_STR_LEN_1]; WCHAR IdealProcessorText[PH_INT32_STR_LEN + 1 + PH_INT32_STR_LEN + 1]; + WCHAR ThreadIdHexText[PH_INT32_STR_LEN_1]; // begin_phapppub } PH_THREAD_NODE, *PPH_THREAD_NODE; // end_phapppub diff --git a/ProcessHacker/options.c b/ProcessHacker/options.c index 4eab9afc3213..14d9b697b741 100644 --- a/ProcessHacker/options.c +++ b/ProcessHacker/options.c @@ -1000,7 +1000,6 @@ typedef enum _PHP_OPTIONS_INDEX PHP_OPTIONS_INDEX_ICON_SINGLE_CLICK, PHP_OPTIONS_INDEX_ICON_TOGGLE_VISIBILITY, PHP_OPTIONS_INDEX_PROPAGATE_CPU_USAGE, - PHP_OPTIONS_INDEX_SHOW_HEX_ID, PHP_OPTIONS_INDEX_SHOW_ADVANCED_OPTIONS } PHP_OPTIONS_GENERAL_INDEX; @@ -1038,7 +1037,6 @@ static VOID PhpAdvancedPageLoad( PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_ICON_SINGLE_CLICK, L"Single-click tray icons", NULL); PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_ICON_TOGGLE_VISIBILITY, L"Icon click toggles visibility", NULL); PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_PROPAGATE_CPU_USAGE, L"Include usage of collapsed processes", NULL); - PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_SHOW_HEX_ID, L"Show hexadecimal IDs (experimental)", NULL); PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_SHOW_ADVANCED_OPTIONS, L"Show advanced options (experimental)", NULL); SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_SINGLE_INSTANCE, L"AllowOnlyOneInstance"); @@ -1060,7 +1058,6 @@ static VOID PhpAdvancedPageLoad( SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_ICON_SINGLE_CLICK, L"IconSingleClick"); SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_ICON_TOGGLE_VISIBILITY, L"IconTogglesVisibility"); SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_PROPAGATE_CPU_USAGE, L"PropagateCpuUsage"); - SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_SHOW_HEX_ID, L"ShowHexId"); if (CurrentUserRunPresent) ListView_SetCheckState(listViewHandle, PHP_OPTIONS_INDEX_START_ATLOGON, TRUE); @@ -1152,7 +1149,6 @@ static VOID PhpAdvancedPageSave( SetSettingForLvItemCheck(listViewHandle, PHP_OPTIONS_INDEX_ICON_SINGLE_CLICK, L"IconSingleClick"); SetSettingForLvItemCheck(listViewHandle, PHP_OPTIONS_INDEX_ICON_TOGGLE_VISIBILITY, L"IconTogglesVisibility"); SetSettingForLvItemCheck(listViewHandle, PHP_OPTIONS_INDEX_PROPAGATE_CPU_USAGE, L"PropagateCpuUsage"); - SetSettingForLvItemCheckRestartRequired(listViewHandle, PHP_OPTIONS_INDEX_SHOW_HEX_ID, L"ShowHexId"); WriteCurrentUserRun( ListView_GetCheckState(listViewHandle, PHP_OPTIONS_INDEX_START_ATLOGON) == BST_CHECKED, diff --git a/ProcessHacker/procprv.c b/ProcessHacker/procprv.c index acb65c4be4b5..cf72a04c0718 100644 --- a/ProcessHacker/procprv.c +++ b/ProcessHacker/procprv.c @@ -1084,15 +1084,11 @@ VOID PhpFillProcessItem( if (PH_IS_REAL_PROCESS_ID(ProcessItem->ProcessId)) { - if (PhEnableHexId) - PhPrintUInt32Hex(ProcessItem->ProcessIdString, HandleToUlong(ProcessItem->ProcessId)); - else - PhPrintUInt32(ProcessItem->ProcessIdString, HandleToUlong(ProcessItem->ProcessId)); + PhPrintUInt32(ProcessItem->ProcessIdString, HandleToUlong(ProcessItem->ProcessId)); + PhPrintUInt32(ProcessItem->ParentProcessIdString, HandleToUlong(ProcessItem->ParentProcessId)); + PhPrintUInt32(ProcessItem->SessionIdString, ProcessItem->SessionId); } - PhPrintUInt32(ProcessItem->ParentProcessIdString, HandleToUlong(ProcessItem->ParentProcessId)); - PhPrintUInt32(ProcessItem->SessionIdString, ProcessItem->SessionId); - // Open a handle to the process for later usage. if (PH_IS_REAL_PROCESS_ID(ProcessItem->ProcessId)) { diff --git a/ProcessHacker/proctree.c b/ProcessHacker/proctree.c index cd26f000fa67..782775328281 100644 --- a/ProcessHacker/proctree.c +++ b/ProcessHacker/proctree.c @@ -215,6 +215,7 @@ VOID PhInitializeProcessTreeList( PhAddTreeNewColumnEx(hwnd, PHPRTLC_PROTECTION, FALSE, L"Protection", 105, PH_ALIGN_LEFT, ULONG_MAX, 0, TRUE); PhAddTreeNewColumnEx(hwnd, PHPRTLC_DESKTOP, FALSE, L"Desktop", 80, PH_ALIGN_LEFT, ULONG_MAX, 0, TRUE); PhAddTreeNewColumnEx(hwnd, PHPRTLC_CRITICAL, FALSE, L"Critical", 80, PH_ALIGN_LEFT, ULONG_MAX, 0, TRUE); + PhAddTreeNewColumnEx(hwnd, PHPRTLC_PIDHEX, FALSE, L"PID (Hex)", 50, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE); TreeNew_SetRedraw(hwnd, TRUE); @@ -1968,6 +1969,12 @@ BEGIN_SORT_FUNCTION(Critical) } END_SORT_FUNCTION +BEGIN_SORT_FUNCTION(HexPid) +{ + sortResult = intptrcmp((LONG_PTR)processItem1->ProcessId, (LONG_PTR)processItem2->ProcessId); +} +END_SORT_FUNCTION + BOOLEAN NTAPI PhpProcessTreeNewCallback( _In_ HWND hwnd, _In_ PH_TREENEW_MESSAGE Message, @@ -2092,6 +2099,7 @@ BOOLEAN NTAPI PhpProcessTreeNewCallback( SORT_FUNCTION(Protection), SORT_FUNCTION(DesktopInfo), SORT_FUNCTION(Critical), + SORT_FUNCTION(HexPid), }; int (__cdecl *sortFunction)(const void *, const void *); @@ -2928,6 +2936,15 @@ BOOLEAN NTAPI PhpProcessTreeNewCallback( PhInitializeStringRef(&getCellText->Text, L"Critical"); } break; + case PHPRTLC_PIDHEX: + { + if (PH_IS_REAL_PROCESS_ID(processItem->ProcessId)) + { + PhPrintUInt32Hex(node->PidHexText, HandleToUlong(processItem->ProcessId)); + PhInitializeStringRefLongHint(&getCellText->Text, node->PidHexText); + } + } + break; default: return FALSE; } diff --git a/ProcessHacker/thrdlist.c b/ProcessHacker/thrdlist.c index c6ea3c32ffe0..c3510a7f7b0f 100644 --- a/ProcessHacker/thrdlist.c +++ b/ProcessHacker/thrdlist.c @@ -604,10 +604,7 @@ BOOLEAN NTAPI PhpThreadTreeNewCallback( PH_FORMAT format; SIZE_T returnLength; - if (PhEnableHexId) - PhInitFormatIX(&format, HandleToUlong(threadItem->ThreadId)); - else - PhInitFormatIU(&format, HandleToUlong(threadItem->ThreadId)); + PhInitFormatIU(&format, HandleToUlong(threadItem->ThreadId)); if (PhFormatToBuffer(&format, 1, node->ThreadIdText, sizeof(node->ThreadIdText), &returnLength)) { @@ -886,6 +883,20 @@ BOOLEAN NTAPI PhpThreadTreeNewCallback( } } break; + case PH_THREAD_TREELIST_COLUMN_TIDHEX: + { + PH_FORMAT format; + SIZE_T returnLength; + + PhInitFormatIX(&format, HandleToUlong(threadItem->ThreadId)); + + if (PhFormatToBuffer(&format, 1, node->ThreadIdHexText, sizeof(node->ThreadIdHexText), &returnLength)) + { + getCellText->Text.Buffer = node->ThreadIdHexText; + getCellText->Text.Length = returnLength - sizeof(WCHAR); // minus null terminator + } + } + break; default: return FALSE; } From 6b3508ee528512e005303f25a492a08e5cb5972b Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 20 Jan 2019 16:50:50 +0100 Subject: [PATCH 1581/2058] Add missing line from previous commit --- ProcessHacker/thrdlist.c | 1 + 1 file changed, 1 insertion(+) diff --git a/ProcessHacker/thrdlist.c b/ProcessHacker/thrdlist.c index c3510a7f7b0f..1bd51861e9a9 100644 --- a/ProcessHacker/thrdlist.c +++ b/ProcessHacker/thrdlist.c @@ -113,6 +113,7 @@ VOID PhInitializeThreadList( PhAddTreeNewColumn(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_USERTIME, FALSE, L"User time", 100, PH_ALIGN_LEFT, ULONG_MAX, 0); PhAddTreeNewColumn(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_IDEALPROCESSOR, FALSE, L"Ideal processor", 80, PH_ALIGN_LEFT, ULONG_MAX, 0); PhAddTreeNewColumn(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_CRITICAL, FALSE, L"Critical", 80, PH_ALIGN_LEFT, ULONG_MAX, 0); + PhAddTreeNewColumn(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_TIDHEX, FALSE, L"TID (Hex)", 50, PH_ALIGN_RIGHT, 0, DT_RIGHT); TreeNew_SetRedraw(TreeNewHandle, TRUE); TreeNew_SetTriState(TreeNewHandle, TRUE); From 5ec0e23d09120e972c9c0e983a53c721cf982f55 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 20 Jan 2019 16:57:59 +0100 Subject: [PATCH 1582/2058] Fix PhFileReadAllText handle leak --- phlib/util.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/phlib/util.c b/phlib/util.c index 7d17e9dfaa9f..aae32b318fc4 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -6194,7 +6194,9 @@ PPH_STRING PhFileReadAllText( data[dataLength] = ANSI_NULL; string = PhConvertUtf8ToUtf16Ex(data, dataLength); + PhFree(data); + NtClose(fileHandle); } return string; From 979657dee54bab92b79a41b54814ab6ba39c4484 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 20 Jan 2019 17:04:17 +0100 Subject: [PATCH 1583/2058] Update known capability sid names --- ProcessHacker/resources/capslist.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ProcessHacker/resources/capslist.txt b/ProcessHacker/resources/capslist.txt index 3ff44204740c..d16ef623433d 100644 --- a/ProcessHacker/resources/capslist.txt +++ b/ProcessHacker/resources/capslist.txt @@ -686,6 +686,7 @@ interopServices kinectAudio kinectGamechat liveIdService +location locationHistory locationSystem lockScreenCreatives @@ -704,6 +705,7 @@ lpacPrinting lpacServicesManagement lpacSessionManagement lpacWebPlatform +microphone microsoftEdgeRemoteDebugging multiplaneOverlay muma @@ -779,6 +781,7 @@ visualElementsSystem visualVoiceMail voipCall walletSystem +webcam windowsHelloCredentialAccess xboxAccessoryManagement xboxBroadcaster From 9765297574590fd7e4f8ad4b15032d8d2d0e626f Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 20 Jan 2019 20:22:38 +0100 Subject: [PATCH 1584/2058] Fix build --- ProcessHacker/mainwnd.c | 1 - 1 file changed, 1 deletion(-) diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index b80d6abee86b..7ec8bf1857fe 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -2207,7 +2207,6 @@ VOID PhMwpLoadSettings( PhEnableServiceQueryStage2 = !!PhGetIntegerSetting(L"EnableServiceStage2"); PhEnableThemeSupport = !!PhGetIntegerSetting(L"EnableThemeSupport"); PhEnableTooltipSupport = !!PhGetIntegerSetting(L"EnableTooltipSupport"); - PhEnableHexId = !!PhGetIntegerSetting(L"ShowHexId"); PhMwpNotifyIconNotifyMask = PhGetIntegerSetting(L"IconNotifyMask"); if (PhGetIntegerSetting(L"MainWindowAlwaysOnTop")) From 0bfcb231fb6b8e2b00e0ff4dca63cdf7c2166e7a Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 20 Jan 2019 23:11:58 +0100 Subject: [PATCH 1585/2058] Add token capability guids --- ProcessHacker/tokprp.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/ProcessHacker/tokprp.c b/ProcessHacker/tokprp.c index f030874a5e6e..5bb422be56ed 100644 --- a/ProcessHacker/tokprp.c +++ b/ProcessHacker/tokprp.c @@ -1964,6 +1964,41 @@ INT_PTR CALLBACK PhpTokenCapabilitiesPageProc( name = PhGetCapabilitySidName(tokenPageContext->Capabilities->Groups[i].Sid); + if (!name) + { + ULONG ridCount; + ULONG subAuthority; + + ridCount = *(PULONG)RtlSubAuthorityCountSid(tokenPageContext->Capabilities->Groups[i].Sid); + subAuthority = *(PULONG)RtlSubAuthoritySid(tokenPageContext->Capabilities->Groups[i].Sid, 0); + + //memcmp((BYTE[])SECURITY_APP_PACKAGE_AUTHORITY, RtlIdentifierAuthoritySid(tokenPageContext->Capabilities->Groups[i].Sid), sizeof((BYTE[])SECURITY_APP_PACKAGE_AUTHORITY)) + if ( + ridCount == SECURITY_CAPABILITY_RID_COUNT && + subAuthority == SECURITY_CAPABILITY_BASE_RID + ) + { + GUID capabilityGuid; + ULONG firstPart; + ULONG secondPart; + ULONG thirdPart; + ULONG lastPart; + + firstPart = *(PULONG)RtlSubAuthoritySid(tokenPageContext->Capabilities->Groups[i].Sid, 1); + secondPart = *(PULONG)RtlSubAuthoritySid(tokenPageContext->Capabilities->Groups[i].Sid, 2); + thirdPart = *(PULONG)RtlSubAuthoritySid(tokenPageContext->Capabilities->Groups[i].Sid, 3); + lastPart = *(PULONG)RtlSubAuthoritySid(tokenPageContext->Capabilities->Groups[i].Sid, 4); + + capabilityGuid.Data1 = firstPart; + capabilityGuid.Data2 = LOWORD(secondPart); + capabilityGuid.Data3 = HIWORD(secondPart); + memcpy(capabilityGuid.Data4, &thirdPart, sizeof(ULONG)); + memcpy(capabilityGuid.Data4 + sizeof(ULONG), &lastPart, sizeof(ULONG)); + + name = PhFormatGuid(&capabilityGuid); + } + } + if (!name) name = PhGetSidFullName(tokenPageContext->Capabilities->Groups[i].Sid, TRUE, NULL); From fa546403250965b067490ac7c915723246402053 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 22 Jan 2019 21:29:18 +0100 Subject: [PATCH 1586/2058] Move PhReferenceObjects --- phlib/include/phutil.h | 16 ---------------- phlib/include/ref.h | 16 ++++++++++++++++ phlib/ref.c | 34 ++++++++++++++++++++++++++++++++++ phlib/util.c | 34 ---------------------------------- 4 files changed, 50 insertions(+), 50 deletions(-) diff --git a/phlib/include/phutil.h b/phlib/include/phutil.h index 9695d7c18ffc..bcbdd4bc6894 100644 --- a/phlib/include/phutil.h +++ b/phlib/include/phutil.h @@ -172,22 +172,6 @@ PhLargeIntegerToLocalSystemTime( FileTimeToSystemTime(&newFileTime, SystemTime); } -PHLIBAPI -VOID -NTAPI -PhReferenceObjects( - _In_reads_(NumberOfObjects) PVOID *Objects, - _In_ ULONG NumberOfObjects - ); - -PHLIBAPI -VOID -NTAPI -PhDereferenceObjects( - _In_reads_(NumberOfObjects) PVOID *Objects, - _In_ ULONG NumberOfObjects - ); - // NLS LCID PhGetSystemDefaultLCID( diff --git a/phlib/include/ref.h b/phlib/include/ref.h index f2d425601ce7..24162dd978e3 100644 --- a/phlib/include/ref.h +++ b/phlib/include/ref.h @@ -148,6 +148,22 @@ PhDereferenceObjectEx( _In_ BOOLEAN DeferDelete ); +PHLIBAPI +VOID +NTAPI +PhReferenceObjects( + _In_reads_(NumberOfObjects) PVOID *Objects, + _In_ ULONG NumberOfObjects + ); + +PHLIBAPI +VOID +NTAPI +PhDereferenceObjects( + _In_reads_(NumberOfObjects) PVOID *Objects, + _In_ ULONG NumberOfObjects + ); + PHLIBAPI PPH_OBJECT_TYPE NTAPI diff --git a/phlib/ref.c b/phlib/ref.c index 53af1c79c325..0c80254fc886 100644 --- a/phlib/ref.c +++ b/phlib/ref.c @@ -308,6 +308,40 @@ _May_raise_ VOID PhDereferenceObjectEx( } } +/** + * References an array of objects. + * + * \param Objects An array of objects. + * \param NumberOfObjects The number of elements in \a Objects. + */ +VOID PhReferenceObjects( + _In_reads_(NumberOfObjects) PVOID *Objects, + _In_ ULONG NumberOfObjects + ) +{ + ULONG i; + + for (i = 0; i < NumberOfObjects; i++) + PhReferenceObject(Objects[i]); +} + +/** + * Dereferences an array of objects. + * + * \param Objects An array of objects. + * \param NumberOfObjects The number of elements in \a Objects. + */ +VOID PhDereferenceObjects( + _In_reads_(NumberOfObjects) PVOID *Objects, + _In_ ULONG NumberOfObjects + ) +{ + ULONG i; + + for (i = 0; i < NumberOfObjects; i++) + PhDereferenceObject(Objects[i]); +} + /** * Gets an object's type. * diff --git a/phlib/util.c b/phlib/util.c index aae32b318fc4..83432e775048 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -168,40 +168,6 @@ VOID PhCenterWindow( } } -/** - * References an array of objects. - * - * \param Objects An array of objects. - * \param NumberOfObjects The number of elements in \a Objects. - */ -VOID PhReferenceObjects( - _In_reads_(NumberOfObjects) PVOID *Objects, - _In_ ULONG NumberOfObjects - ) -{ - ULONG i; - - for (i = 0; i < NumberOfObjects; i++) - PhReferenceObject(Objects[i]); -} - -/** - * Dereferences an array of objects. - * - * \param Objects An array of objects. - * \param NumberOfObjects The number of elements in \a Objects. - */ -VOID PhDereferenceObjects( - _In_reads_(NumberOfObjects) PVOID *Objects, - _In_ ULONG NumberOfObjects - ) -{ - ULONG i; - - for (i = 0; i < NumberOfObjects; i++) - PhDereferenceObject(Objects[i]); -} - // NLS support // TODO: Move to seperate file. (dmex) From 04828e5bc362f878ddec7aec6a89fd3aa6240d1d Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 22 Jan 2019 21:29:53 +0100 Subject: [PATCH 1587/2058] Add comments for some reversed functions --- phlib/include/phutil.h | 16 ++++++++++++++++ phlib/util.c | 7 +++++++ 2 files changed, 23 insertions(+) diff --git a/phlib/include/phutil.h b/phlib/include/phutil.h index bcbdd4bc6894..da2e66197de0 100644 --- a/phlib/include/phutil.h +++ b/phlib/include/phutil.h @@ -550,6 +550,22 @@ PhFormatImageVersionInfo( _In_opt_ ULONG LineLimit ); +PHLIBAPI +BOOLEAN +NTAPI +PhInitializeImageVersionInfoCached( + _Out_ PPH_IMAGE_VERSION_INFO ImageVersionInfo, + _In_ PPH_STRING FileName, + _In_ BOOLEAN IsSubsystemProcess + ); + +PHLIBAPI +VOID +NTAPI +PhFlushImageVersionInfoCache( + VOID + ); + PHLIBAPI PPH_STRING NTAPI diff --git a/phlib/util.c b/phlib/util.c index 83432e775048..e6ca7dc529d9 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -171,6 +171,7 @@ VOID PhCenterWindow( // NLS support // TODO: Move to seperate file. (dmex) +// rev from GetSystemDefaultLCID LCID PhGetSystemDefaultLCID( VOID ) @@ -183,6 +184,7 @@ LCID PhGetSystemDefaultLCID( return MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), SORT_DEFAULT); } +// rev from GetUserDefaultLCID LCID PhGetUserDefaultLCID( VOID ) @@ -195,6 +197,7 @@ LCID PhGetUserDefaultLCID( return MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), SORT_DEFAULT); } +// rev from GetThreadLocale LCID PhGetCurrentThreadLCID( VOID ) @@ -209,6 +212,7 @@ LCID PhGetCurrentThreadLCID( return currentTeb->CurrentLocale; } +// rev from GetSystemDefaultLangID LANGID PhGetSystemDefaultLangID( VOID ) @@ -216,6 +220,7 @@ LANGID PhGetSystemDefaultLangID( return LANGIDFROMLCID(PhGetSystemDefaultLCID()); } +// rev from GetUserDefaultLangID LANGID PhGetUserDefaultLangID( VOID ) @@ -223,6 +228,7 @@ LANGID PhGetUserDefaultLangID( return LANGIDFROMLCID(PhGetUserDefaultLCID()); } +// rev from GetUserDefaultUILanguage LANGID PhGetUserDefaultUILanguage( VOID ) @@ -235,6 +241,7 @@ LANGID PhGetUserDefaultUILanguage( return MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT); } +// rev from GetUserDefaultLocaleName PPH_STRING PhGetUserDefaultLocaleName( VOID ) From 3997d4c1a66cc33fc2bca48fdeec6dd23e479910 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 22 Jan 2019 21:31:30 +0100 Subject: [PATCH 1588/2058] Update macro usage --- ProcessHacker/proctree.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/ProcessHacker/proctree.c b/ProcessHacker/proctree.c index 782775328281..2d3fe76f9e40 100644 --- a/ProcessHacker/proctree.c +++ b/ProcessHacker/proctree.c @@ -745,7 +745,7 @@ static BOOLEAN PhpFormatInt32GroupDigits( if (String) { String->Buffer = Buffer; - String->Length = returnLength - sizeof(WCHAR); + String->Length = returnLength - sizeof(UNICODE_NULL); } return TRUE; @@ -2173,7 +2173,7 @@ BOOLEAN NTAPI PhpProcessTreeNewCallback( if (PhFormatToBuffer(&format, 1, node->CpuUsageText, sizeof(node->CpuUsageText), &returnLength)) { getCellText->Text.Buffer = node->CpuUsageText; - getCellText->Text.Length = returnLength - sizeof(WCHAR); // minus null terminator + getCellText->Text.Length = returnLength - sizeof(UNICODE_NULL); // minus null terminator } } else if (cpuUsage != 0 && PhCsShowCpuBelow001) @@ -2187,7 +2187,7 @@ BOOLEAN NTAPI PhpProcessTreeNewCallback( if (PhFormatToBuffer(format, 2, node->CpuUsageText, sizeof(node->CpuUsageText), &returnLength)) { getCellText->Text.Buffer = node->CpuUsageText; - getCellText->Text.Length = returnLength - sizeof(WCHAR); + getCellText->Text.Length = returnLength - sizeof(UNICODE_NULL); } } } @@ -2216,7 +2216,7 @@ BOOLEAN NTAPI PhpProcessTreeNewCallback( if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), node->IoTotalRateText, sizeof(node->IoTotalRateText), &returnLength)) { getCellText->Text.Buffer = node->IoTotalRateText; - getCellText->Text.Length = returnLength - sizeof(WCHAR); + getCellText->Text.Length = returnLength - sizeof(UNICODE_NULL); } } } @@ -2233,7 +2233,7 @@ BOOLEAN NTAPI PhpProcessTreeNewCallback( if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), node->PrivateBytesText, sizeof(node->PrivateBytesText), &returnLength)) { getCellText->Text.Buffer = node->PrivateBytesText; - getCellText->Text.Length = returnLength - sizeof(WCHAR); + getCellText->Text.Length = returnLength - sizeof(UNICODE_NULL); } } break; @@ -2287,7 +2287,7 @@ BOOLEAN NTAPI PhpProcessTreeNewCallback( if (PhFormatToBuffer(format, RTL_NUMBER_OF(format), node->PrivateWsText, sizeof(node->PrivateWsText), &returnLength)) { getCellText->Text.Buffer = node->PrivateWsText; - getCellText->Text.Length = returnLength - sizeof(WCHAR); + getCellText->Text.Length = returnLength - sizeof(UNICODE_NULL); } } break; @@ -2940,8 +2940,16 @@ BOOLEAN NTAPI PhpProcessTreeNewCallback( { if (PH_IS_REAL_PROCESS_ID(processItem->ProcessId)) { - PhPrintUInt32Hex(node->PidHexText, HandleToUlong(processItem->ProcessId)); - PhInitializeStringRefLongHint(&getCellText->Text, node->PidHexText); + PH_FORMAT format; + SIZE_T returnLength; + + PhInitFormatIX(&format, HandleToUlong(processItem->ProcessId)); + + if (PhFormatToBuffer(&format, 1, node->PidHexText, sizeof(node->PidHexText), &returnLength)) + { + getCellText->Text.Buffer = node->PidHexText; + getCellText->Text.Length = returnLength - sizeof(UNICODE_NULL); + } } } break; From 0fe27cbbf551cab2313998fb1f7c161ddec34c56 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 22 Jan 2019 21:32:19 +0100 Subject: [PATCH 1589/2058] Fix typo --- ProcessHacker/tokprp.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ProcessHacker/tokprp.c b/ProcessHacker/tokprp.c index 5bb422be56ed..acf1cda1ea48 100644 --- a/ProcessHacker/tokprp.c +++ b/ProcessHacker/tokprp.c @@ -1966,15 +1966,15 @@ INT_PTR CALLBACK PhpTokenCapabilitiesPageProc( if (!name) { - ULONG ridCount; + ULONG subAuthoritiesCount; ULONG subAuthority; - ridCount = *(PULONG)RtlSubAuthorityCountSid(tokenPageContext->Capabilities->Groups[i].Sid); + subAuthoritiesCount = *(PULONG)RtlSubAuthorityCountSid(tokenPageContext->Capabilities->Groups[i].Sid); subAuthority = *(PULONG)RtlSubAuthoritySid(tokenPageContext->Capabilities->Groups[i].Sid, 0); //memcmp((BYTE[])SECURITY_APP_PACKAGE_AUTHORITY, RtlIdentifierAuthoritySid(tokenPageContext->Capabilities->Groups[i].Sid), sizeof((BYTE[])SECURITY_APP_PACKAGE_AUTHORITY)) if ( - ridCount == SECURITY_CAPABILITY_RID_COUNT && + subAuthoritiesCount == SECURITY_CAPABILITY_RID_COUNT && subAuthority == SECURITY_CAPABILITY_BASE_RID ) { From c0b2d23bf8df7ed615596e6bb6c1fbbe6900136a Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 22 Jan 2019 23:07:20 +0100 Subject: [PATCH 1590/2058] Fix PhCreatePipe creating a null named pipe instead of anonymous pipes --- phlib/native.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/phlib/native.c b/phlib/native.c index 9957ba713867..e5854ed465de 100644 --- a/phlib/native.c +++ b/phlib/native.c @@ -7433,7 +7433,7 @@ NTSTATUS PhCreatePipe( if (!NT_SUCCESS(status)) return status; - RtlInitUnicodeString(&pipeNameUs, UNICODE_NULL); + RtlInitEmptyUnicodeString(&pipeNameUs, NULL, 0); InitializeObjectAttributes( &oa, &pipeNameUs, @@ -7463,10 +7463,10 @@ NTSTATUS PhCreatePipe( FILE_PIPE_BYTE_STREAM_TYPE, FILE_PIPE_BYTE_STREAM_MODE, FILE_PIPE_QUEUE_OPERATION, - ULONG_MAX, + 1, PAGE_SIZE, PAGE_SIZE, - PhTimeoutFromMilliseconds(&pipeTimeout, 500) + PhTimeoutFromMilliseconds(&pipeTimeout, 120000) ); if (!NT_SUCCESS(status)) @@ -7478,7 +7478,7 @@ NTSTATUS PhCreatePipe( return status; } - RtlInitUnicodeString(&pipeNameUs, UNICODE_NULL); + RtlInitEmptyUnicodeString(&pipeNameUs, NULL, 0); InitializeObjectAttributes( &oa, &pipeNameUs, From 07e1d0e216516ce6de1635fa2c91e0b5c7dae141 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 25 Jan 2019 22:27:39 +0100 Subject: [PATCH 1591/2058] Fix newline --- phlib/include/phsup.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/phlib/include/phsup.h b/phlib/include/phsup.h index a6c7f11a3e9a..7ce52597ebbe 100644 --- a/phlib/include/phsup.h +++ b/phlib/include/phsup.h @@ -530,7 +530,9 @@ FORCEINLINE PLARGE_INTEGER PhTimeoutFromMilliseconds( return Timeout; } -FORCEINLINE NTSTATUS PhGetLastWin32ErrorAsNtStatus() +FORCEINLINE NTSTATUS PhGetLastWin32ErrorAsNtStatus( + VOID + ) { ULONG win32Result; From 04f18ea9a98374fb5aa4fc0d8c51b93a708eafc4 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 25 Jan 2019 22:28:26 +0100 Subject: [PATCH 1592/2058] Add PhCreatePipeEx --- phlib/include/phnative.h | 10 +++++++++ phlib/native.c | 45 +++++++++++++++++++++++++++------------- 2 files changed, 41 insertions(+), 14 deletions(-) diff --git a/phlib/include/phnative.h b/phlib/include/phnative.h index e4b8cb912886..8f3c24951718 100644 --- a/phlib/include/phnative.h +++ b/phlib/include/phnative.h @@ -1269,6 +1269,16 @@ PhCreatePipe( _Out_ PHANDLE PipeWriteHandle ); +PHLIBAPI +NTSTATUS +NTAPI +PhCreatePipeEx( + _Out_ PHANDLE PipeReadHandle, + _Out_ PHANDLE PipeWriteHandle, + _In_ BOOLEAN InheritHandles, + _In_ PSECURITY_DESCRIPTOR SecurityDescriptor + ); + PHLIBAPI NTSTATUS NTAPI diff --git a/phlib/native.c b/phlib/native.c index e5854ed465de..28a5555e86ce 100644 --- a/phlib/native.c +++ b/phlib/native.c @@ -7401,6 +7401,16 @@ NTSTATUS PhCreatePipe( _Out_ PHANDLE PipeReadHandle, _Out_ PHANDLE PipeWriteHandle ) +{ + return PhCreatePipeEx(PipeReadHandle, PipeWriteHandle, FALSE, NULL); +} + +NTSTATUS PhCreatePipeEx( + _Out_ PHANDLE PipeReadHandle, + _Out_ PHANDLE PipeWriteHandle, + _In_ BOOLEAN InheritHandles, + _In_ PSECURITY_DESCRIPTOR SecurityDescriptor + ) { NTSTATUS status; PACL pipeAcl = NULL; @@ -7409,12 +7419,12 @@ NTSTATUS PhCreatePipe( HANDLE pipeWriteHandle; LARGE_INTEGER pipeTimeout; UNICODE_STRING pipeNameUs; - OBJECT_ATTRIBUTES oa; + OBJECT_ATTRIBUTES objectAttributes; IO_STATUS_BLOCK isb; RtlInitUnicodeString(&pipeNameUs, DEVICE_NAMED_PIPE); InitializeObjectAttributes( - &oa, + &objectAttributes, &pipeNameUs, OBJ_CASE_INSENSITIVE, NULL, @@ -7424,7 +7434,7 @@ NTSTATUS PhCreatePipe( status = NtOpenFile( &pipeDirectoryHandle, GENERIC_READ | SYNCHRONIZE, - &oa, + &objectAttributes, &isb, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_SYNCHRONOUS_IO_NONALERT @@ -7435,27 +7445,34 @@ NTSTATUS PhCreatePipe( RtlInitEmptyUnicodeString(&pipeNameUs, NULL, 0); InitializeObjectAttributes( - &oa, + &objectAttributes, &pipeNameUs, - OBJ_CASE_INSENSITIVE, + OBJ_CASE_INSENSITIVE | (InheritHandles ? OBJ_INHERIT : 0), pipeDirectoryHandle, NULL ); - if (NT_SUCCESS(RtlDefaultNpAcl(&pipeAcl))) + if (SecurityDescriptor) { - SECURITY_DESCRIPTOR securityDescriptor; + objectAttributes.SecurityDescriptor = SecurityDescriptor; + } + else + { + if (NT_SUCCESS(RtlDefaultNpAcl(&pipeAcl))) + { + SECURITY_DESCRIPTOR securityDescriptor; - RtlCreateSecurityDescriptor(&securityDescriptor, SECURITY_DESCRIPTOR_REVISION); - RtlSetDaclSecurityDescriptor(&securityDescriptor, TRUE, pipeAcl, FALSE); + RtlCreateSecurityDescriptor(&securityDescriptor, SECURITY_DESCRIPTOR_REVISION); + RtlSetDaclSecurityDescriptor(&securityDescriptor, TRUE, pipeAcl, FALSE); - oa.SecurityDescriptor = &securityDescriptor; + objectAttributes.SecurityDescriptor = &securityDescriptor; + } } status = NtCreateNamedPipeFile( &pipeReadHandle, FILE_WRITE_ATTRIBUTES | GENERIC_READ | SYNCHRONIZE, - &oa, + &objectAttributes, &isb, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_CREATE, @@ -7480,9 +7497,9 @@ NTSTATUS PhCreatePipe( RtlInitEmptyUnicodeString(&pipeNameUs, NULL, 0); InitializeObjectAttributes( - &oa, + &objectAttributes, &pipeNameUs, - OBJ_CASE_INSENSITIVE, + OBJ_CASE_INSENSITIVE | (InheritHandles ? OBJ_INHERIT : 0), pipeReadHandle, NULL ); @@ -7490,7 +7507,7 @@ NTSTATUS PhCreatePipe( status = NtOpenFile( &pipeWriteHandle, FILE_READ_ATTRIBUTES | GENERIC_WRITE | SYNCHRONIZE, - &oa, + &objectAttributes, &isb, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT From fd069c541831a65f8dc11dfdc27ebebfa792d9b7 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 25 Jan 2019 22:29:08 +0100 Subject: [PATCH 1593/2058] Add PhGetFileText --- phlib/include/phutil.h | 7 +++ phlib/util.c | 110 +++++++++++++++++++++++------------------ 2 files changed, 68 insertions(+), 49 deletions(-) diff --git a/phlib/include/phutil.h b/phlib/include/phutil.h index da2e66197de0..d16f07b17d52 100644 --- a/phlib/include/phutil.h +++ b/phlib/include/phutil.h @@ -1264,6 +1264,13 @@ PhGetExportNameFromOrdinal( _In_opt_ USHORT ProcedureNumber ); +PHLIBAPI +PPH_STRING +NTAPI +PhGetFileText( + _In_ HANDLE FileHandle + ); + PHLIBAPI PPH_STRING NTAPI diff --git a/phlib/util.c b/phlib/util.c index e6ca7dc529d9..0cf2ca511dd3 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -6102,73 +6102,85 @@ PPH_STRING PhGetExportNameFromOrdinal( return NULL; } -PPH_STRING PhFileReadAllText( - _In_ PWSTR FileName +PPH_STRING PhGetFileText( + _In_ HANDLE FileHandle ) { PPH_STRING string = NULL; - HANDLE fileHandle; + PSTR data; + ULONG allocatedLength; + ULONG dataLength; + ULONG returnLength; IO_STATUS_BLOCK isb; + BYTE buffer[PAGE_SIZE]; - if (NT_SUCCESS(PhCreateFileWin32( - &fileHandle, - FileName, - FILE_GENERIC_READ, - FILE_ATTRIBUTE_NORMAL, - FILE_SHARE_READ, - FILE_OPEN, - FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT + allocatedLength = sizeof(buffer); + data = PhAllocate(allocatedLength); + dataLength = 0; + + while (NT_SUCCESS(NtReadFile( + FileHandle, + NULL, + NULL, + NULL, + &isb, + buffer, + PAGE_SIZE, + NULL, + NULL ))) { - PSTR data; - ULONG allocatedLength; - ULONG dataLength; - ULONG returnLength; - BYTE buffer[PAGE_SIZE]; + returnLength = (ULONG)isb.Information; - allocatedLength = sizeof(buffer); - data = PhAllocate(allocatedLength); - dataLength = 0; + if (returnLength == 0) + break; - while (NT_SUCCESS(NtReadFile( - fileHandle, - NULL, - NULL, - NULL, - &isb, - buffer, - PAGE_SIZE, - NULL, - NULL - ))) + if (allocatedLength < dataLength + returnLength) { - returnLength = (ULONG)isb.Information; + allocatedLength *= 2; + data = PhReAllocate(data, allocatedLength); + } - if (returnLength == 0) - break; + memcpy(data + dataLength, buffer, returnLength); - if (allocatedLength < dataLength + returnLength) - { - allocatedLength *= 2; - data = PhReAllocate(data, allocatedLength); - } + dataLength += returnLength; + } - memcpy(data + dataLength, buffer, returnLength); + if (allocatedLength < dataLength + sizeof(ANSI_NULL)) + { + allocatedLength++; + data = PhReAllocate(data, allocatedLength); + } - dataLength += returnLength; - } + if (dataLength > 0) + { + data[dataLength] = ANSI_NULL; + string = PhConvertUtf8ToUtf16Ex(data, dataLength); + } - if (allocatedLength < dataLength + sizeof(ANSI_NULL)) - { - allocatedLength++; - data = PhReAllocate(data, allocatedLength); - } + PhFree(data); - data[dataLength] = ANSI_NULL; + return string; +} - string = PhConvertUtf8ToUtf16Ex(data, dataLength); +PPH_STRING PhFileReadAllText( + _In_ PWSTR FileName + ) +{ + PPH_STRING string = NULL; + HANDLE fileHandle; - PhFree(data); + if (NT_SUCCESS(PhCreateFileWin32( + &fileHandle, + FileName, + FILE_GENERIC_READ, + FILE_ATTRIBUTE_NORMAL, + FILE_SHARE_READ, + FILE_OPEN, + FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT + ))) + { + string = PhGetFileText(fileHandle); NtClose(fileHandle); } From f029274a32e930aecfc147bde3619374952b7623 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 25 Jan 2019 22:29:29 +0100 Subject: [PATCH 1594/2058] Fix macro usage --- phlib/util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phlib/util.c b/phlib/util.c index 0cf2ca511dd3..bcff69f151ce 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -1626,7 +1626,7 @@ PPH_STRING PhGetFileVersionInfoString( PPH_STRING string; // Check if the string has a valid length. - if (length <= sizeof(WCHAR)) + if (length <= sizeof(UNICODE_NULL)) return NULL; string = PhCreateStringEx((PWCHAR)buffer, length * sizeof(WCHAR)); From 5caf0f49099cf6d5c45d30f0d03660da7a5f04c8 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 26 Jan 2019 00:29:23 +0100 Subject: [PATCH 1595/2058] Don't query some Windows types for lxss processes --- ProcessHacker/proctree.c | 34 ++++++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/ProcessHacker/proctree.c b/ProcessHacker/proctree.c index 2d3fe76f9e40..25eb284d4004 100644 --- a/ProcessHacker/proctree.c +++ b/ProcessHacker/proctree.c @@ -3,7 +3,7 @@ * process tree list * * Copyright (C) 2010-2016 wj32 - * Copyright (C) 2016-2017 dmex + * Copyright (C) 2016-2019 dmex * * This file is part of Process Hacker. * @@ -930,14 +930,24 @@ static VOID PhpUpdateProcessNodeWindow( { if (!(ProcessNode->ValidMask & PHPN_WINDOW)) { - ProcessNode->WindowHandle = PhGetProcessMainWindow(ProcessNode->ProcessId, ProcessNode->ProcessItem->QueryHandle); - PhClearReference(&ProcessNode->WindowText); - if (ProcessNode->WindowHandle) + if (ProcessNode->ProcessItem->IsSubsystemProcess) { - PhGetWindowTextEx(ProcessNode->WindowHandle, PH_GET_WINDOW_TEXT_INTERNAL, &ProcessNode->WindowText); - ProcessNode->WindowHung = !!IsHungAppWindow(ProcessNode->WindowHandle); + NOTHING; + } + else + { + ProcessNode->WindowHandle = PhGetProcessMainWindow( + ProcessNode->ProcessId, + ProcessNode->ProcessItem->QueryHandle + ); + + if (ProcessNode->WindowHandle) + { + PhGetWindowTextEx(ProcessNode->WindowHandle, PH_GET_WINDOW_TEXT_INTERNAL, &ProcessNode->WindowText); + ProcessNode->WindowHung = !!IsHungAppWindow(ProcessNode->WindowHandle); + } } ProcessNode->ValidMask |= PHPN_WINDOW; @@ -1027,7 +1037,11 @@ static VOID PhpUpdateProcessOsContext( { HANDLE processHandle; - if (NT_SUCCESS(PhOpenProcess(&processHandle, PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_VM_READ, ProcessNode->ProcessId))) + if (ProcessNode->ProcessItem->IsSubsystemProcess) + { + NOTHING; + } + else if (NT_SUCCESS(PhOpenProcess(&processHandle, PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_VM_READ, ProcessNode->ProcessId))) { if (NT_SUCCESS(PhGetProcessSwitchContext(processHandle, &ProcessNode->OsContextGuid))) { @@ -1147,7 +1161,11 @@ static VOID PhpUpdateProcessNodeAppId( PhClearReference(&ProcessNode->AppIdText); - if (PhAppResolverGetAppIdForProcess(ProcessNode->ProcessItem->ProcessId, &applicationUserModelId)) + if (ProcessNode->ProcessItem->IsSubsystemProcess) + { + NOTHING; + } + else if (PhAppResolverGetAppIdForProcess(ProcessNode->ProcessItem->ProcessId, &applicationUserModelId)) { ProcessNode->AppIdText = applicationUserModelId; } From 830487082dc3b09cb2cf67caaa732b9279da2dfc Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 26 Jan 2019 00:35:12 +0100 Subject: [PATCH 1596/2058] Add inital lxss support wrappers --- phlib/include/wslsup.h | 47 +++++ phlib/phlib.vcxproj | 2 + phlib/phlib.vcxproj.filters | 6 + phlib/wslsup.c | 394 ++++++++++++++++++++++++++++++++++++ 4 files changed, 449 insertions(+) create mode 100644 phlib/include/wslsup.h create mode 100644 phlib/wslsup.c diff --git a/phlib/include/wslsup.h b/phlib/include/wslsup.h new file mode 100644 index 000000000000..c6a3d6578bfd --- /dev/null +++ b/phlib/include/wslsup.h @@ -0,0 +1,47 @@ +/* + * Process Hacker - + * LXSS support helpers + * + * Copyright (C) 2019 dmex + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#ifndef _PH_WSLSUP_H +#define _PH_WSLSUP_H + +#ifdef __cplusplus +extern "C" { +#endif + +BOOLEAN PhInitializeLxssImageVersionInfo( + _Out_ PPH_IMAGE_VERSION_INFO ImageVersionInfo, + _In_ PPH_STRING FileName + ); + +ULONG PhCreateProcessLxss( + _In_ PWSTR LxssDistribution, + _In_ PWSTR LxssCommandLine, + _In_opt_ PWSTR LxssCurrentDirectory, + _Out_ PPH_STRING *Result, + _Out_opt_ PHANDLE ProcessHandle + ); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/phlib/phlib.vcxproj b/phlib/phlib.vcxproj index 40147221b2be..dceab869782f 100644 --- a/phlib/phlib.vcxproj +++ b/phlib/phlib.vcxproj @@ -225,6 +225,7 @@ + @@ -273,6 +274,7 @@ + diff --git a/phlib/phlib.vcxproj.filters b/phlib/phlib.vcxproj.filters index f8e72caf3f65..bc73d8f38594 100644 --- a/phlib/phlib.vcxproj.filters +++ b/phlib/phlib.vcxproj.filters @@ -239,6 +239,9 @@ Source Files + + Source Files + @@ -511,5 +514,8 @@ Json-C\Headers + + Header Files + \ No newline at end of file diff --git a/phlib/wslsup.c b/phlib/wslsup.c new file mode 100644 index 000000000000..6842f4521799 --- /dev/null +++ b/phlib/wslsup.c @@ -0,0 +1,394 @@ +/* + * Process Hacker - + * LXSS support helpers + * + * Copyright (C) 2019 dmex + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include +#include + +BOOLEAN NTAPI PhpWslDistributionNamesCallback( + _In_ PKEY_BASIC_INFORMATION Information, + _In_opt_ PVOID Context + ) +{ + PhAddItemList(Context, PhCreateStringEx(Information->Name, Information->NameLength)); + return TRUE; +} + +PPH_STRING PhGetWslDistributionFromPath( + _In_ PPH_STRING FileName, + _Out_opt_ PPH_STRING *LxssDistroPath, + _Out_opt_ PPH_STRING *LxssFileName + ) +{ + static PH_STRINGREF lxssKeyPath = PH_STRINGREF_INIT(L"Software\\Microsoft\\Windows\\CurrentVersion\\Lxss"); + PPH_STRING lxssDistributionName = NULL; + PPH_STRING lxssDistroPath = NULL; + PPH_STRING lxssFileName = NULL; + HANDLE keyHandle; + ULONG i; + + if (NT_SUCCESS(PhOpenKey( + &keyHandle, + KEY_READ, + PH_KEY_CURRENT_USER, + &lxssKeyPath, + 0 + ))) + { + PPH_LIST distributionGuidList; + + distributionGuidList = PhCreateList(1); + PhEnumerateKey(keyHandle, PhpWslDistributionNamesCallback, distributionGuidList); + + for (i = 0; i < distributionGuidList->Count; i++) + { + HANDLE subKeyHandle; + PPH_STRING subKeyName; + + subKeyName = distributionGuidList->Items[i]; + + if (NT_SUCCESS(PhOpenKey( + &subKeyHandle, + KEY_READ, + keyHandle, + &subKeyName->sr, + 0 + ))) + { + PPH_STRING basePathName = PhQueryRegistryString(subKeyHandle, L"BasePath"); + + if (PhStartsWithString(FileName, basePathName, TRUE)) + { + lxssDistributionName = PhQueryRegistryString(subKeyHandle, L"DistributionName"); + + if (LxssDistroPath) + { + PhSetReference(&lxssDistroPath, basePathName); + } + + if (LxssFileName) + { + lxssFileName = PhDuplicateString(FileName); + PhSkipStringRef(&lxssFileName->sr, basePathName->Length); + PhSkipStringRef(&lxssFileName->sr, sizeof(L"rootfs")); + } + } + + PhDereferenceObject(basePathName); + NtClose(subKeyHandle); + } + + if (lxssDistributionName) + break; + } + + for (i = 0; i < distributionGuidList->Count; i++) + PhDereferenceObject(distributionGuidList->Items[i]); + PhDereferenceObject(distributionGuidList); + + NtClose(keyHandle); + } + + if (LxssDistroPath) + { + *LxssDistroPath = lxssDistroPath; + } + + if (LxssFileName) + { + if (lxssFileName) + { + for (i = 0; i < lxssFileName->Length / sizeof(WCHAR); i++) + { + if (lxssFileName->Buffer[i] == OBJ_NAME_PATH_SEPARATOR) // RtlNtPathSeperatorString + lxssFileName->Buffer[i] = L'/'; // RtlAlternateDosPathSeperatorString + } + } + + *LxssFileName = lxssFileName; + } + + return lxssDistributionName; +} + +BOOLEAN PhInitializeLxssImageVersionInfo( + _Out_ PPH_IMAGE_VERSION_INFO ImageVersionInfo, + _In_ PPH_STRING FileName + ) +{ + ULONG status; + PPH_STRING lxssCommandLine = NULL; + PPH_STRING lxssPackageName = NULL; + PPH_STRING lxssDistroName; + PPH_STRING lxssDistroPath; + PPH_STRING lxssFileName; + PPH_STRING lxssBaseFileName; + PPH_STRING result; + + lxssBaseFileName = PhGetBaseName(FileName); + lxssDistroName = PhGetWslDistributionFromPath( + FileName, + &lxssDistroPath, + &lxssFileName + ); + + if (!(lxssDistroName && lxssFileName && lxssBaseFileName)) + { + if (lxssDistroName) PhDereferenceObject(lxssDistroName); + if (lxssDistroPath) PhDereferenceObject(lxssDistroPath); + if (lxssFileName) PhDereferenceObject(lxssFileName); + if (lxssBaseFileName) PhDereferenceObject(lxssBaseFileName); + return FALSE; + } + + if (PhEqualString2(lxssFileName, L"/init", FALSE)) + { + PhMoveReference(&lxssFileName, PhCreateString(L"/sbin/init")); + } + + PhMoveReference(&lxssCommandLine, PhFormatString( + L"rpm -qf %s --queryformat \"%%{VERSION}|%%{VENDOR}|%%{SUMMARY}\"", + lxssFileName->Buffer + )); + + status = PhCreateProcessLxss( + lxssDistroName->Buffer, + lxssCommandLine->Buffer, + NULL, + &result, + NULL + ); + + if (status == 0) + { + goto ParseResult; + } + + PhMoveReference(&lxssCommandLine, PhFormatString( + L"dpkg -S %s", + lxssFileName->Buffer + )); + + status = PhCreateProcessLxss( + lxssDistroName->Buffer, + lxssCommandLine->Buffer, + NULL, + &result, + NULL + ); + + if (status != 0) + { + PhDereferenceObject(lxssCommandLine); + PhDereferenceObject(lxssDistroName); + PhDereferenceObject(lxssFileName); + PhDereferenceObject(lxssBaseFileName); + return FALSE; + } + else + { + PH_STRINGREF remainingPart; + PH_STRINGREF packagePart; + + if (PhSplitStringRefAtChar(&result->sr, ':', &packagePart, &remainingPart)) + { + lxssPackageName = PhCreateString2(&packagePart); + } + + PhDereferenceObject(result); + } + + PhMoveReference(&lxssCommandLine, PhFormatString( + L"dpkg-query -W -f=${Version}|${Maintainer}|${binary:Summary} %s", + lxssPackageName ? lxssPackageName->Buffer : lxssBaseFileName->Buffer + )); + + status = PhCreateProcessLxss( + lxssDistroName->Buffer, + lxssCommandLine->Buffer, + NULL, + &result, + NULL + ); + + if (status != 0) + { + PhDereferenceObject(lxssCommandLine); + PhDereferenceObject(lxssDistroName); + PhDereferenceObject(lxssFileName); + PhDereferenceObject(lxssBaseFileName); + return FALSE; + } + +ParseResult: + if ( + !ImageVersionInfo->FileVersion && + !ImageVersionInfo->CompanyName && + !ImageVersionInfo->FileDescription + ) + { + PH_STRINGREF remainingPart; + PH_STRINGREF companyPart; + PH_STRINGREF descriptionPart; + PH_STRINGREF versionPart; + + remainingPart = result->sr; + PhSplitStringRefAtChar(&remainingPart, '|', &versionPart, &remainingPart); + PhSplitStringRefAtChar(&remainingPart, '|', &companyPart, &remainingPart); + PhSplitStringRefAtChar(&remainingPart, '|', &descriptionPart, &remainingPart); + + if (versionPart.Length != 0) + ImageVersionInfo->FileVersion = PhCreateString2(&versionPart); + if (companyPart.Length != 0) + ImageVersionInfo->CompanyName = PhCreateString2(&companyPart); + if (descriptionPart.Length != 0) + ImageVersionInfo->FileDescription = PhCreateString2(&descriptionPart); + } + + if (result) PhDereferenceObject(result); + if (lxssCommandLine) PhDereferenceObject(lxssCommandLine); + if (lxssPackageName) PhDereferenceObject(lxssPackageName); + if (lxssDistroName) PhDereferenceObject(lxssDistroName); + if (lxssFileName) PhDereferenceObject(lxssFileName); + if (lxssBaseFileName) PhDereferenceObject(lxssBaseFileName); + + return TRUE; +} + +ULONG PhCreateProcessLxss( + _In_ PWSTR LxssDistribution, + _In_ PWSTR LxssCommandLine, + _In_opt_ PWSTR LxssCurrentDirectory, + _Out_ PPH_STRING *Result, + _Out_opt_ PHANDLE ProcessHandle + ) +{ + NTSTATUS status; + PPH_STRING lxssOutputString; + PPH_STRING lxssCommandLine; + PPH_STRING systemDirectory; + HANDLE processHandle; + HANDLE outputReadHandle, outputWriteHandle; + HANDLE inputReadHandle, inputWriteHandle; + PROCESS_BASIC_INFORMATION basicInfo; + STARTUPINFO startupInfo; + + lxssCommandLine = PhFormatString( + L"wsl.exe -d %s -e %s", + LxssDistribution, + LxssCommandLine + ); + + if (systemDirectory = PhGetSystemDirectory()) + { + PhMoveReference(&lxssCommandLine, PhConcatStrings( + 3, + systemDirectory->Buffer, + L"\\", + lxssCommandLine->Buffer + )); + PhDereferenceObject(systemDirectory); + } + + status = PhCreatePipeEx( + &outputReadHandle, + &outputWriteHandle, + TRUE, + NULL + ); + + if (!NT_SUCCESS(status)) + return status; + + status = PhCreatePipeEx( + &inputReadHandle, + &inputWriteHandle, + TRUE, + NULL + ); + + if (!NT_SUCCESS(status)) + { + NtClose(outputWriteHandle); + NtClose(outputReadHandle); + return status; + } + + memset(&startupInfo, 0, sizeof(STARTUPINFO)); + startupInfo.cb = sizeof(STARTUPINFO); + startupInfo.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES; + startupInfo.wShowWindow = SW_HIDE; + startupInfo.hStdInput = inputReadHandle; + startupInfo.hStdOutput = outputWriteHandle; + startupInfo.hStdError = outputWriteHandle; + + status = PhCreateProcessWin32Ex( + NULL, + lxssCommandLine->Buffer, + NULL, + LxssCurrentDirectory, + &startupInfo, + PH_CREATE_PROCESS_INHERIT_HANDLES | PH_CREATE_PROCESS_NEW_CONSOLE, + NULL, + NULL, + &processHandle, + NULL + ); + + if (!NT_SUCCESS(status)) + { + NtClose(outputWriteHandle); + NtClose(outputReadHandle); + NtClose(inputReadHandle); + NtClose(inputWriteHandle); + return status; + } + + // Note: Close the write handles or the child process + // won't exit and ReadFile will block indefinitely. (dmex) + NtClose(inputReadHandle); + NtClose(outputWriteHandle); + + // Read the pipe data. (dmex) + lxssOutputString = PhGetFileText(outputReadHandle); + + // Get the exit code after we finish reading the data from the pipe. (dmex) + if (NT_SUCCESS(status = PhGetProcessBasicInformation(processHandle, &basicInfo))) + { + status = basicInfo.ExitStatus; + } + + // Note: Don't use NTSTATUS now that we have the lxss exit code. (dmex) + if (status == 0) + { + *Result = lxssOutputString; + } + else + { + PhSetReference(&lxssOutputString, NULL); + } + + NtClose(processHandle); + NtClose(outputReadHandle); + NtClose(inputWriteHandle); + + return status; +} From 9ee2ac5af3853124cc40a53bfb8551bc10f563f5 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 26 Jan 2019 00:40:42 +0100 Subject: [PATCH 1597/2058] Add support for lxss versioninfo #153, Add caching for file versioninfo --- ProcessHacker/procprv.c | 18 +++++- phlib/util.c | 121 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 137 insertions(+), 2 deletions(-) diff --git a/ProcessHacker/procprv.c b/ProcessHacker/procprv.c index cf72a04c0718..4b624a46f88c 100644 --- a/ProcessHacker/procprv.c +++ b/ProcessHacker/procprv.c @@ -3,7 +3,7 @@ * process provider * * Copyright (C) 2009-2016 wj32 - * Copyright (C) 2017-2018 dmex + * Copyright (C) 2017-2019 dmex * * This file is part of Process Hacker. * @@ -120,6 +120,7 @@ typedef struct _PH_PROCESS_QUERY_S2_DATA BOOLEAN IsPacked; ULONG ImportFunctions; ULONG ImportModules; + PH_IMAGE_VERSION_INFO VersionInfo; // LXSS only } PH_PROCESS_QUERY_S2_DATA, *PPH_PROCESS_QUERY_S2_DATA; typedef struct _PH_SID_FULL_NAME_CACHE_ENTRY @@ -729,7 +730,7 @@ VOID PhpProcessQueryStage1( } // Version info. - PhInitializeImageVersionInfo(&Data->VersionInfo, processItem->FileName->Buffer); + PhInitializeImageVersionInfoCached(&Data->VersionInfo, processItem->FileName, FALSE); } // Debugged @@ -937,6 +938,11 @@ VOID PhpProcessQueryStage2( Data->ImportFunctions = -1; } } + + if (PhEnableProcessQueryStage2 && processItem->FileName && processItem->IsSubsystemProcess) + { + PhInitializeImageVersionInfoCached(&Data->VersionInfo, processItem->FileName, TRUE); + } } NTSTATUS PhpProcessQueryStage1Worker( @@ -1050,6 +1056,12 @@ VOID PhpFillProcessItemStage2( processItem->IsPacked = Data->IsPacked; processItem->ImportFunctions = Data->ImportFunctions; processItem->ImportModules = Data->ImportModules; + + // Note: We query Win32 processes in stage1 so don't overwrite the previous data. + if (processItem->IsSubsystemProcess) + { + memcpy(&processItem->VersionInfo, &Data->VersionInfo, sizeof(PH_IMAGE_VERSION_INFO)); + } } VOID PhpFillProcessItemExtension( @@ -1753,6 +1765,8 @@ VOID PhProcessProviderUpdate( { if (PhEnablePurgeProcessRecords) PhPurgeProcessRecords(); + + PhFlushImageVersionInfoCache(); } if (!PhProcessStatisticsInitialized) diff --git a/phlib/util.c b/phlib/util.c index bcff69f151ce..9872a238a833 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -35,6 +35,8 @@ #include #include +#include + #include "md5.h" #include "sha.h" #include "sha256.h" @@ -1868,6 +1870,125 @@ PPH_STRING PhFormatImageVersionInfo( return PhFinalStringBuilderString(&stringBuilder); } +typedef struct _PH_FILE_VERSIONINFO_CACHE_ENTRY +{ + PPH_STRING FileName; + PPH_STRING CompanyName; + PPH_STRING FileDescription; + PPH_STRING FileVersion; + PPH_STRING ProductName; +} PH_FILE_VERSIONINFO_CACHE_ENTRY, *PPH_FILE_VERSIONINFO_CACHE_ENTRY; + +static PPH_HASHTABLE PhpImageVersionInfoCacheHashtable = NULL; + +static BOOLEAN PhpImageVersionInfoCacheHashtableEqualFunction( + _In_ PVOID Entry1, + _In_ PVOID Entry2 + ) +{ + PPH_FILE_VERSIONINFO_CACHE_ENTRY entry1 = Entry1; + PPH_FILE_VERSIONINFO_CACHE_ENTRY entry2 = Entry2; + + return PhEqualString(entry1->FileName, entry2->FileName, TRUE); +} + +static ULONG PhpImageVersionInfoCacheHashtableHashFunction( + _In_ PVOID Entry + ) +{ + PPH_FILE_VERSIONINFO_CACHE_ENTRY entry = Entry; + + return PhHashStringRef(&entry->FileName->sr, TRUE); +} + +BOOLEAN PhInitializeImageVersionInfoCached( + _Out_ PPH_IMAGE_VERSION_INFO ImageVersionInfo, + _In_ PPH_STRING FileName, + _In_ BOOLEAN IsSubsystemProcess + ) +{ + PH_IMAGE_VERSION_INFO versionInfo = { 0 }; + PH_FILE_VERSIONINFO_CACHE_ENTRY newEntry; + + if (PhpImageVersionInfoCacheHashtable) + { + PPH_FILE_VERSIONINFO_CACHE_ENTRY entry; + PH_FILE_VERSIONINFO_CACHE_ENTRY lookupEntry; + + lookupEntry.FileName = FileName; + entry = PhFindEntryHashtable(PhpImageVersionInfoCacheHashtable, &lookupEntry); + + if (entry) + { + PhSetReference(&ImageVersionInfo->CompanyName, entry->CompanyName); + PhSetReference(&ImageVersionInfo->FileDescription, entry->FileDescription); + PhSetReference(&ImageVersionInfo->FileVersion, entry->FileVersion); + PhSetReference(&ImageVersionInfo->ProductName, entry->ProductName); + + return TRUE; + } + } + + if (IsSubsystemProcess) + { + if (!PhInitializeLxssImageVersionInfo(&versionInfo, FileName)) + return FALSE; + } + else + { + if (!PhInitializeImageVersionInfo(&versionInfo, FileName->Buffer)) + return FALSE; + } + + if (!PhpImageVersionInfoCacheHashtable) + { + PhpImageVersionInfoCacheHashtable = PhCreateHashtable( + sizeof(PH_FILE_VERSIONINFO_CACHE_ENTRY), + PhpImageVersionInfoCacheHashtableEqualFunction, + PhpImageVersionInfoCacheHashtableHashFunction, + 100 + ); + } + + PhSetReference(&newEntry.FileName, FileName); + PhSetReference(&newEntry.CompanyName, versionInfo.CompanyName); + PhSetReference(&newEntry.FileDescription, versionInfo.FileDescription); + PhSetReference(&newEntry.FileVersion, versionInfo.FileVersion); + PhSetReference(&newEntry.ProductName, versionInfo.ProductName); + + PhAddEntryHashtable(PhpImageVersionInfoCacheHashtable, &newEntry); + + ImageVersionInfo->CompanyName = versionInfo.CompanyName; + ImageVersionInfo->FileDescription = versionInfo.FileDescription; + ImageVersionInfo->FileVersion = versionInfo.FileVersion; + ImageVersionInfo->ProductName = versionInfo.ProductName; + return TRUE; +} + +VOID PhFlushImageVersionInfoCache( + VOID + ) +{ + PH_HASHTABLE_ENUM_CONTEXT enumContext; + PPH_FILE_VERSIONINFO_CACHE_ENTRY entry; + + if (!PhpImageVersionInfoCacheHashtable) + return; + + PhBeginEnumHashtable(PhpImageVersionInfoCacheHashtable, &enumContext); + + while (entry = PhNextEnumHashtable(&enumContext)) + { + if (entry->FileName) PhDereferenceObject(entry->FileName); + if (entry->CompanyName) PhDereferenceObject(entry->CompanyName); + if (entry->FileDescription) PhDereferenceObject(entry->FileDescription); + if (entry->FileVersion) PhDereferenceObject(entry->FileVersion); + if (entry->ProductName) PhDereferenceObject(entry->ProductName); + } + + PhClearReference(&PhpImageVersionInfoCacheHashtable); +} + /** * Gets an absolute file name. * From f72e6ace4e5698a055466deb96fc43bd8f826a6d Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 26 Jan 2019 00:41:43 +0100 Subject: [PATCH 1598/2058] Fix comment typo --- ProcessHacker/procprv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ProcessHacker/procprv.c b/ProcessHacker/procprv.c index 4b624a46f88c..0891dba0c2fb 100644 --- a/ProcessHacker/procprv.c +++ b/ProcessHacker/procprv.c @@ -1057,7 +1057,7 @@ VOID PhpFillProcessItemStage2( processItem->ImportFunctions = Data->ImportFunctions; processItem->ImportModules = Data->ImportModules; - // Note: We query Win32 processes in stage1 so don't overwrite the previous data. + // Note: We query Win32 processes in stage1 so don't overwrite the previous data. (dmex) if (processItem->IsSubsystemProcess) { memcpy(&processItem->VersionInfo, &Data->VersionInfo, sizeof(PH_IMAGE_VERSION_INFO)); From ffd1c2e545e6dea10240059c878dd86b8f320983 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 26 Jan 2019 00:45:41 +0100 Subject: [PATCH 1599/2058] Improve lxss cleanup --- phlib/wslsup.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/phlib/wslsup.c b/phlib/wslsup.c index 6842f4521799..21faa1019825 100644 --- a/phlib/wslsup.c +++ b/phlib/wslsup.c @@ -100,8 +100,7 @@ PPH_STRING PhGetWslDistributionFromPath( break; } - for (i = 0; i < distributionGuidList->Count; i++) - PhDereferenceObject(distributionGuidList->Items[i]); + PhDereferenceObjects(distributionGuidList->Items, distributionGuidList->Count); PhDereferenceObject(distributionGuidList); NtClose(keyHandle); From 2dd7d20d6f2dfca9d3e47830ee900ece466055a7 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 26 Jan 2019 01:07:43 +0100 Subject: [PATCH 1600/2058] SetupTool: Add extra error logging --- .../CustomSetupTool/CustomSetupTool/extract.c | 19 +++++++++++++++++++ tools/CustomSetupTool/CustomSetupTool/setup.c | 6 +++++- .../CustomSetupTool/CustomSetupTool/update.c | 3 +++ 3 files changed, 27 insertions(+), 1 deletion(-) diff --git a/tools/CustomSetupTool/CustomSetupTool/extract.c b/tools/CustomSetupTool/CustomSetupTool/extract.c index 36c05dc79559..f2f6421c2b22 100644 --- a/tools/CustomSetupTool/CustomSetupTool/extract.c +++ b/tools/CustomSetupTool/CustomSetupTool/extract.c @@ -48,12 +48,18 @@ BOOLEAN SetupExtractBuild( PPH_BYTES zipPathUtf8; if (PhIsNullOrEmptyString(Context->FilePath)) + { + Context->ErrorCode = ERROR_PATH_NOT_FOUND; goto CleanupExit; + } zipPathUtf8 = PhConvertUtf16ToUtf8(PhGetString(Context->FilePath)); if (!(status = mz_zip_reader_init_file(&zip_archive, zipPathUtf8->Buffer, 0))) + { + Context->ErrorCode = ERROR_FILE_CORRUPT; goto CleanupExit; + } PhDereferenceObject(zipPathUtf8); #endif @@ -144,11 +150,15 @@ BOOLEAN SetupExtractBuild( 0 ))) { + Context->ErrorCode = ERROR_FILE_INVALID; goto CleanupExit; } if ((zipFileCrc32 = mz_crc32(zipFileCrc32, buffer, bufferLength)) != zipFileStat.m_crc32) + { + Context->ErrorCode = ERROR_CRC; goto CleanupExit; + } extractPath = PhConcatStrings( 3, @@ -162,12 +172,16 @@ BOOLEAN SetupExtractBuild( PPH_STRING directoryPath; if (indexOfFileName == -1) + { + Context->ErrorCode = ERROR_FILE_CORRUPT; goto CleanupExit; + } if (directoryPath = PhSubstring(fullSetupPath, 0, indexOfFileName)) { if (!NT_SUCCESS(PhCreateDirectory(directoryPath))) { + Context->ErrorCode = ERROR_DIRECTORY_NOT_SUPPORTED; PhDereferenceObject(directoryPath); PhDereferenceObject(fullSetupPath); goto CleanupExit; @@ -206,6 +220,7 @@ BOOLEAN SetupExtractBuild( FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT ))) { + Context->ErrorCode = ERROR_FILE_CORRUPT; goto CleanupExit; } @@ -221,11 +236,15 @@ BOOLEAN SetupExtractBuild( NULL ))) { + Context->ErrorCode = ERROR_FILE_CORRUPT; goto CleanupExit; } if (isb.Information != bufferLength) + { + Context->ErrorCode = ERROR_FILE_CORRUPT; goto CleanupExit; + } currentLength += bufferLength; diff --git a/tools/CustomSetupTool/CustomSetupTool/setup.c b/tools/CustomSetupTool/CustomSetupTool/setup.c index b0d506746ee9..95fb8f681f46 100644 --- a/tools/CustomSetupTool/CustomSetupTool/setup.c +++ b/tools/CustomSetupTool/CustomSetupTool/setup.c @@ -159,12 +159,16 @@ BOOLEAN SetupCreateUninstallFile( _In_ PPH_SETUP_CONTEXT Context ) { + NTSTATUS status; PPH_STRING currentFilePath; PPH_STRING backupFilePath; PPH_STRING uninstallFilePath; - if (!NT_SUCCESS(PhGetProcessImageFileNameWin32(NtCurrentProcess(), ¤tFilePath))) + if (!NT_SUCCESS(status = PhGetProcessImageFileNameWin32(NtCurrentProcess(), ¤tFilePath))) + { + Context->ErrorCode = WIN32_FROM_NTSTATUS(status); return FALSE; + } // Check if the user has started the setup from the installation folder. if (PhStartsWithStringRef2(¤tFilePath->sr, PhGetString(SetupInstallPath), TRUE)) diff --git a/tools/CustomSetupTool/CustomSetupTool/update.c b/tools/CustomSetupTool/CustomSetupTool/update.c index f1826fd71af1..0766d1c9fef6 100644 --- a/tools/CustomSetupTool/CustomSetupTool/update.c +++ b/tools/CustomSetupTool/CustomSetupTool/update.c @@ -31,7 +31,10 @@ NTSTATUS SetupUpdateBuild( ) { if (!ShutdownProcessHacker()) + { + Context->ErrorCode = ERROR_INVALID_FUNCTION; goto CleanupExit; + } if (!SetupCreateUninstallFile(Context)) goto CleanupExit; From 339dfa7be9c8a079a04a815e70d214c6d7d69bba Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 26 Jan 2019 01:27:34 +0100 Subject: [PATCH 1601/2058] Fix versioninfo cache threading issues --- phlib/util.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/phlib/util.c b/phlib/util.c index 9872a238a833..2b987b1bcf90 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -1880,6 +1880,7 @@ typedef struct _PH_FILE_VERSIONINFO_CACHE_ENTRY } PH_FILE_VERSIONINFO_CACHE_ENTRY, *PPH_FILE_VERSIONINFO_CACHE_ENTRY; static PPH_HASHTABLE PhpImageVersionInfoCacheHashtable = NULL; +static PH_QUEUED_LOCK PhpImageVersionInfoCacheLock = PH_QUEUED_LOCK_INIT; static BOOLEAN PhpImageVersionInfoCacheHashtableEqualFunction( _In_ PVOID Entry1, @@ -1916,7 +1917,10 @@ BOOLEAN PhInitializeImageVersionInfoCached( PH_FILE_VERSIONINFO_CACHE_ENTRY lookupEntry; lookupEntry.FileName = FileName; + + PhAcquireQueuedLockShared(&PhpImageVersionInfoCacheLock); entry = PhFindEntryHashtable(PhpImageVersionInfoCacheHashtable, &lookupEntry); + PhReleaseQueuedLockShared(&PhpImageVersionInfoCacheLock); if (entry) { @@ -1956,7 +1960,9 @@ BOOLEAN PhInitializeImageVersionInfoCached( PhSetReference(&newEntry.FileVersion, versionInfo.FileVersion); PhSetReference(&newEntry.ProductName, versionInfo.ProductName); + PhAcquireQueuedLockExclusive(&PhpImageVersionInfoCacheLock); PhAddEntryHashtable(PhpImageVersionInfoCacheHashtable, &newEntry); + PhReleaseQueuedLockExclusive(&PhpImageVersionInfoCacheLock); ImageVersionInfo->CompanyName = versionInfo.CompanyName; ImageVersionInfo->FileDescription = versionInfo.FileDescription; @@ -1975,6 +1981,8 @@ VOID PhFlushImageVersionInfoCache( if (!PhpImageVersionInfoCacheHashtable) return; + PhAcquireQueuedLockExclusive(&PhpImageVersionInfoCacheLock); + PhBeginEnumHashtable(PhpImageVersionInfoCacheHashtable, &enumContext); while (entry = PhNextEnumHashtable(&enumContext)) @@ -1987,6 +1995,15 @@ VOID PhFlushImageVersionInfoCache( } PhClearReference(&PhpImageVersionInfoCacheHashtable); + + PhpImageVersionInfoCacheHashtable = PhCreateHashtable( + sizeof(PH_FILE_VERSIONINFO_CACHE_ENTRY), + PhpImageVersionInfoCacheHashtableEqualFunction, + PhpImageVersionInfoCacheHashtableHashFunction, + 100 + ); + + PhReleaseQueuedLockExclusive(&PhpImageVersionInfoCacheLock); } /** From 1c399b3e527947008a5a39ea2dee2eb1d7606fdd Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 26 Jan 2019 03:10:56 +0100 Subject: [PATCH 1602/2058] Updater: Remove old code --- plugins/Updater/Updater.rc | 15 -------------- plugins/Updater/page2.c | 4 ++-- plugins/Updater/page4.c | 2 +- plugins/Updater/page5.c | 9 +++++++-- plugins/Updater/updater.c | 40 +++++++++++++++++++++++++------------- 5 files changed, 36 insertions(+), 34 deletions(-) diff --git a/plugins/Updater/Updater.rc b/plugins/Updater/Updater.rc index 2f67ad44e332..9310b0b5c26c 100644 --- a/plugins/Updater/Updater.rc +++ b/plugins/Updater/Updater.rc @@ -135,21 +135,6 @@ END #endif // APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// AFX_DIALOG_LAYOUT -// - -IDD_OPTIONS AFX_DIALOG_LAYOUT -BEGIN - 0 -END - -IDD_TEXT AFX_DIALOG_LAYOUT -BEGIN - 0 -END - #endif // English (Australia) resources ///////////////////////////////////////////////////////////////////////////// diff --git a/plugins/Updater/page2.c b/plugins/Updater/page2.c index 57fc49df0d40..c08ba0c50531 100644 --- a/plugins/Updater/page2.c +++ b/plugins/Updater/page2.c @@ -40,7 +40,7 @@ HRESULT CALLBACK CheckingForUpdatesCallbackProc( SendMessage(hwndDlg, TDM_SET_PROGRESS_BAR_MARQUEE, TRUE, 1); PhReferenceObject(context); - PhCreateThread2(UpdateCheckThread, context); + PhQueueItemWorkQueue(PhGetGlobalWorkQueue(), UpdateCheckThread, context); } break; } @@ -67,4 +67,4 @@ VOID ShowCheckingForUpdatesDialog( config.pszMainInstruction = L"Checking for new releases..."; SendMessage(Context->DialogHandle, TDM_NAVIGATE_PAGE, 0, (LPARAM)&config); -} \ No newline at end of file +} diff --git a/plugins/Updater/page4.c b/plugins/Updater/page4.c index 8c29f12be712..1dbe904257cc 100644 --- a/plugins/Updater/page4.c +++ b/plugins/Updater/page4.c @@ -74,4 +74,4 @@ VOID ShowProgressDialog( config.pszContent = L"Downloaded: ~ of ~ (0%)\r\nSpeed: ~ KB/s"; SendMessage(Context->DialogHandle, TDM_NAVIGATE_PAGE, 0, (LPARAM)&config); -} \ No newline at end of file +} diff --git a/plugins/Updater/page5.c b/plugins/Updater/page5.c index 92098a29c7bd..1feda530db5a 100644 --- a/plugins/Updater/page5.c +++ b/plugins/Updater/page5.c @@ -68,8 +68,8 @@ BOOLEAN UpdaterCheckApplicationDirectory( if (UpdaterCheckKphInstallState()) return FALSE; - directory = PH_AUTO(PhGetApplicationDirectory()); - file = PH_AUTO(PhConcatStrings(2, PhGetStringOrEmpty(directory), L"\\processhacker.update")); + directory = PhGetApplicationDirectory(); + file = PhConcatStrings(2, PhGetStringOrEmpty(directory), L"\\processhacker.update"); if (NT_SUCCESS(PhCreateFileWin32( &fileHandle, @@ -81,10 +81,15 @@ BOOLEAN UpdaterCheckApplicationDirectory( FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_DELETE_ON_CLOSE ))) { + PhDereferenceObject(file); + PhDereferenceObject(directory); + NtClose(fileHandle); return TRUE; } + PhDereferenceObject(file); + PhDereferenceObject(directory); return FALSE; } diff --git a/plugins/Updater/updater.c b/plugins/Updater/updater.c index 002807879708..c458b4c64104 100644 --- a/plugins/Updater/updater.c +++ b/plugins/Updater/updater.c @@ -35,14 +35,22 @@ VOID UpdateContextDeleteProcedure( { PPH_UPDATER_CONTEXT context = Object; - PhClearReference(&context->CurrentVersionString); - PhClearReference(&context->Version); - PhClearReference(&context->RelDate); - PhClearReference(&context->SetupFileDownloadUrl); - PhClearReference(&context->SetupFileLength); - PhClearReference(&context->SetupFileHash); - PhClearReference(&context->SetupFileSignature); - PhClearReference(&context->BuildMessage); + if (context->CurrentVersionString) + PhDereferenceObject(context->CurrentVersionString); + if (context->Version) + PhDereferenceObject(context->Version); + if (context->RelDate) + PhDereferenceObject(context->RelDate); + if (context->SetupFileDownloadUrl) + PhDereferenceObject(context->SetupFileDownloadUrl); + if (context->SetupFileLength) + PhDereferenceObject(context->SetupFileLength); + if (context->SetupFileHash) + PhDereferenceObject(context->SetupFileHash); + if (context->SetupFileSignature) + PhDereferenceObject(context->SetupFileSignature); + if (context->BuildMessage) + PhDereferenceObject(context->BuildMessage); } PPH_UPDATER_CONTEXT CreateUpdateContext( @@ -57,7 +65,7 @@ PPH_UPDATER_CONTEXT CreateUpdateContext( PhEndInitOnce(&UpdateContextTypeInitOnce); } - context = PhCreateObjectZero(sizeof(PH_UPDATER_CONTEXT), UpdateContextType); + context = PhCreateObject(sizeof(PH_UPDATER_CONTEXT), UpdateContextType); memset(context, 0, sizeof(PH_UPDATER_CONTEXT)); context->CurrentVersionString = PhGetPhVersion(); @@ -330,7 +338,11 @@ BOOLEAN QueryUpdateData( Context->BuildMessage = PhGetJsonValueAsString(jsonObject, "changelog"); Context->CurrentVersion = ParseVersionString(Context->CurrentVersionString); +#ifdef FORCE_LATEST_VERSION + Context->LatestVersion = ParseVersionString(Context->CurrentVersionString); +#else Context->LatestVersion = ParseVersionString(Context->Version); +#endif PhFreeJsonParser(jsonObject); @@ -491,6 +503,7 @@ NTSTATUS UpdateDownloadThread( _In_ PVOID Parameter ) { + PPH_UPDATER_CONTEXT context = (PPH_UPDATER_CONTEXT)Parameter; BOOLEAN downloadSuccess = FALSE; BOOLEAN hashSuccess = FALSE; BOOLEAN signatureSuccess = FALSE; @@ -504,7 +517,6 @@ NTSTATUS UpdateDownloadThread( LARGE_INTEGER timeStart; ULONG64 timeTicks = 0; ULONG64 timeBitsPerSecond = 0; - PPH_UPDATER_CONTEXT context = (PPH_UPDATER_CONTEXT)Parameter; SendMessage(context->DialogHandle, TDM_UPDATE_ELEMENT_TEXT, TDE_MAIN_INSTRUCTION, (LPARAM)L"Initializing download request..."); @@ -663,9 +675,9 @@ NTSTATUS UpdateDownloadThread( // TODO: Update on timer callback. { FLOAT percent = ((FLOAT)downloadedBytes / contentLength * 100); - PPH_STRING totalLength = PhFormatSize(contentLength, -1); - PPH_STRING totalDownloaded = PhFormatSize(downloadedBytes, -1); - PPH_STRING totalSpeed = PhFormatSize(timeBitsPerSecond, -1); + PPH_STRING totalLength = PhFormatSize(contentLength, ULONG_MAX); + PPH_STRING totalDownloaded = PhFormatSize(downloadedBytes, ULONG_MAX); + PPH_STRING totalSpeed = PhFormatSize(timeBitsPerSecond, ULONG_MAX); PPH_STRING statusMessage = PhFormatString( L"Downloaded: %s of %s (%.0f%%)\r\nSpeed: %s/s", @@ -918,5 +930,5 @@ VOID StartInitialCheck( VOID ) { - PhCreateThread2(UpdateCheckSilentThread, NULL); + PhQueueItemWorkQueue(PhGetGlobalWorkQueue(), UpdateCheckSilentThread, NULL); } From b6564f3c7d926c1bbc6b49f311b686414e57be27 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 26 Jan 2019 03:45:23 +0100 Subject: [PATCH 1603/2058] peview: Add image version information for WSL binaries on Windows 10 --- tools/peview/exlfprp.c | 26 ++++++++++++++++++++++++-- tools/peview/include/peview.h | 11 +++++++++++ tools/peview/peprp.c | 12 +----------- tools/peview/peview.rc | 26 ++++++++++++++++---------- 4 files changed, 52 insertions(+), 23 deletions(-) diff --git a/tools/peview/exlfprp.c b/tools/peview/exlfprp.c index 40cdc69779f6..8f5d74300e05 100644 --- a/tools/peview/exlfprp.c +++ b/tools/peview/exlfprp.c @@ -2,7 +2,7 @@ * Process Hacker - * PE viewer * - * Copyright (C) 2017 dmex + * Copyright (C) 2017-2019 dmex * * This file is part of Process Hacker. * @@ -22,7 +22,7 @@ #include #include -#include +#include PWSTR PvpGetSymbolTypeName( _In_ UCHAR TypeInfo @@ -95,6 +95,11 @@ VOID PvExlfProperties( { PPV_PROPCONTEXT propContext; + if (!PhExtractIcon(PvFileName->Buffer, &PvImageLargeIcon, &PvImageSmallIcon)) + { + PhGetStockApplicationIcon(&PvImageSmallIcon, &PvImageLargeIcon); + } + if (propContext = PvCreatePropContext(PvFileName)) { PPV_PROPPAGECONTEXT newPage; @@ -161,6 +166,19 @@ VOID PvExlfProperties( } } +VOID PvpSetWslmageVersionInfo( + _In_ HWND WindowHandle + ) +{ + PhInitializeLxssImageVersionInfo(&PvImageVersionInfo, PvFileName); + + Static_SetIcon(GetDlgItem(WindowHandle, IDC_FILEICON), PvImageLargeIcon); + + PhSetDialogItemText(WindowHandle, IDC_NAME, PvpGetStringOrNa(PvImageVersionInfo.FileDescription)); + PhSetDialogItemText(WindowHandle, IDC_COMPANYNAME, PvpGetStringOrNa(PvImageVersionInfo.CompanyName)); + PhSetDialogItemText(WindowHandle, IDC_VERSION, PvpGetStringOrNa(PvImageVersionInfo.FileVersion)); +} + VOID PvpSetWslImageType( _In_ HWND hwndDlg ) @@ -405,6 +423,7 @@ INT_PTR CALLBACK PvpExlfGeneralDlgProc( PhSetExtendedListView(lvHandle); PhLoadListViewColumnsFromSetting(L"GeneralWslTreeListColumns", lvHandle); + PvpSetWslmageVersionInfo(hwndDlg); PvpSetWslImageType(hwndDlg); PvpSetWslImageMachineType(hwndDlg); PvpSetWslImageBase(hwndDlg); @@ -427,6 +446,9 @@ INT_PTR CALLBACK PvpExlfGeneralDlgProc( PPH_LAYOUT_ITEM dialogItem; dialogItem = PvAddPropPageLayoutItem(hwndDlg, hwndDlg, PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL); + PvAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_FILE), dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); + PvAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_NAME), dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); + PvAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_COMPANYNAME), dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); PvAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_LIST), dialogItem, PH_ANCHOR_ALL); PvDoPropPageLayout(hwndDlg); diff --git a/tools/peview/include/peview.h b/tools/peview/include/peview.h index f6ec483da514..ecd62d571566 100644 --- a/tools/peview/include/peview.h +++ b/tools/peview/include/peview.h @@ -46,6 +46,17 @@ extern PIMAGE_COR20_HEADER PvImageCor20Header; extern PPH_SYMBOL_PROVIDER PvSymbolProvider; extern HICON PvImageSmallIcon; extern HICON PvImageLargeIcon; +extern PH_IMAGE_VERSION_INFO PvImageVersionInfo; + +FORCEINLINE PWSTR PvpGetStringOrNa( + _In_ PPH_STRING String + ) +{ + if (!PhIsNullOrEmptyString(String)) + return String->Buffer; + else + return L"N/A"; +} // peprp diff --git a/tools/peview/peprp.c b/tools/peview/peprp.c index 04fbd85449d2..1c7a4e693b8a 100644 --- a/tools/peview/peprp.c +++ b/tools/peview/peprp.c @@ -47,7 +47,7 @@ PIMAGE_COR20_HEADER PvImageCor20Header = NULL; PPH_SYMBOL_PROVIDER PvSymbolProvider = NULL; HICON PvImageSmallIcon = NULL; HICON PvImageLargeIcon = NULL; -static PH_IMAGE_VERSION_INFO PvImageVersionInfo; +PH_IMAGE_VERSION_INFO PvImageVersionInfo; static VERIFY_RESULT PvImageVerifyResult; static PPH_STRING PvImageSignerName; @@ -351,16 +351,6 @@ static NTSTATUS VerifyImageThreadStart( return STATUS_SUCCESS; } -FORCEINLINE PWSTR PvpGetStringOrNa( - _In_ PPH_STRING String - ) -{ - if (!PhIsNullOrEmptyString(String)) - return String->Buffer; - else - return L"N/A"; -} - FORCEINLINE PPH_STRING PvpGetSectionCharacteristics( _In_ ULONG Characteristics ) diff --git a/tools/peview/peview.rc b/tools/peview/peview.rc index e5cdfad0d13b..9a8f4766ccb8 100644 --- a/tools/peview/peview.rc +++ b/tools/peview/peview.rc @@ -298,16 +298,22 @@ STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSM CAPTION "General" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN - LTEXT "Target machine:",IDC_STATIC,7,7,53,8 - LTEXT "Static",IDC_TARGETMACHINE,78,7,215,8 - CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,75,286,197 - LTEXT "Sections:",IDC_STATIC,7,64,30,8 - LTEXT "Entry point:",IDC_STATIC,7,47,39,8 - LTEXT "Static",IDC_ENTRYPOINT,78,47,215,8 - LTEXT "Image base:",IDC_STATIC,7,34,41,8 - LTEXT "Static",IDC_IMAGEBASE,78,34,215,8 - LTEXT "Image type:",IDC_STATIC,7,20,40,8 - LTEXT "Static",IDC_IMAGETYPE,78,20,215,8 + LTEXT "Target machine:",IDC_STATIC,7,60,53,8 + LTEXT "Static",IDC_TARGETMACHINE,78,60,215,8 + CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,128,286,144 + LTEXT "Sections:",IDC_STATIC,7,115,30,8 + LTEXT "Entry point:",IDC_STATIC,7,100,39,8 + LTEXT "Static",IDC_ENTRYPOINT,78,100,215,8 + LTEXT "Image base:",IDC_STATIC,7,87,41,8 + LTEXT "Static",IDC_IMAGEBASE,78,87,215,8 + LTEXT "Image type:",IDC_STATIC,7,73,40,8 + LTEXT "Static",IDC_IMAGETYPE,78,73,215,8 + ICON "",IDC_FILEICON,14,18,20,20 + GROUPBOX "File",IDC_FILE,7,7,286,48 + EDITTEXT IDC_NAME,44,17,242,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + LTEXT "Version:",IDC_STATIC,15,41,27,8 + EDITTEXT IDC_VERSION,44,41,242,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + EDITTEXT IDC_COMPANYNAME,44,29,242,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER END IDD_PEPROPSTORAGE DIALOGEX 0, 0, 301, 280 From 5f3a5f8f0262ab38d56dd794a0a407513fd23c73 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 26 Jan 2019 03:54:16 +0100 Subject: [PATCH 1604/2058] peview: Query versioninfo asynchronously --- tools/peview/exlfprp.c | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/tools/peview/exlfprp.c b/tools/peview/exlfprp.c index 8f5d74300e05..ba47db808f21 100644 --- a/tools/peview/exlfprp.c +++ b/tools/peview/exlfprp.c @@ -166,17 +166,32 @@ VOID PvExlfProperties( } } +static NTSTATUS PvpQueryWslImageThreadStart( + _In_ PVOID Parameter + ) +{ + HWND windowHandle = Parameter; + + PhInitializeLxssImageVersionInfo(&PvImageVersionInfo, PvFileName); + + PhSetDialogItemText(windowHandle, IDC_NAME, PvpGetStringOrNa(PvImageVersionInfo.FileDescription)); + PhSetDialogItemText(windowHandle, IDC_COMPANYNAME, PvpGetStringOrNa(PvImageVersionInfo.CompanyName)); + PhSetDialogItemText(windowHandle, IDC_VERSION, PvpGetStringOrNa(PvImageVersionInfo.FileVersion)); + + return STATUS_SUCCESS; +} + VOID PvpSetWslmageVersionInfo( _In_ HWND WindowHandle ) { - PhInitializeLxssImageVersionInfo(&PvImageVersionInfo, PvFileName); + PhSetDialogItemText(WindowHandle, IDC_NAME, L"Loading..."); + PhSetDialogItemText(WindowHandle, IDC_COMPANYNAME, L"Loading..."); + PhSetDialogItemText(WindowHandle, IDC_VERSION, L"Loading..."); - Static_SetIcon(GetDlgItem(WindowHandle, IDC_FILEICON), PvImageLargeIcon); + PhQueueItemWorkQueue(PhGetGlobalWorkQueue(), PvpQueryWslImageThreadStart, WindowHandle); - PhSetDialogItemText(WindowHandle, IDC_NAME, PvpGetStringOrNa(PvImageVersionInfo.FileDescription)); - PhSetDialogItemText(WindowHandle, IDC_COMPANYNAME, PvpGetStringOrNa(PvImageVersionInfo.CompanyName)); - PhSetDialogItemText(WindowHandle, IDC_VERSION, PvpGetStringOrNa(PvImageVersionInfo.FileVersion)); + Static_SetIcon(GetDlgItem(WindowHandle, IDC_FILEICON), PvImageLargeIcon); } VOID PvpSetWslImageType( From 745125192d162a7ab0f4034dba57ebbc4a821e85 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 28 Jan 2019 09:04:25 +0100 Subject: [PATCH 1605/2058] Update some comments --- ProcessHacker/srvprv.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/ProcessHacker/srvprv.c b/ProcessHacker/srvprv.c index 41763e684262..0a797abee6b8 100644 --- a/ProcessHacker/srvprv.c +++ b/ProcessHacker/srvprv.c @@ -529,7 +529,7 @@ VOID PhpServiceQueryStage1( //PhInitializeImageVersionInfo(&Data->VersionInfo, Data->FileName->Buffer); } - PhpResetServiceNonPollGate(); // HACK + PhpResetServiceNonPollGate(); // HACK (dmex) } VOID PhpServiceQueryStage2( @@ -548,7 +548,7 @@ VOID PhpServiceQueryStage2( ); } - PhpResetServiceNonPollGate(); // HACK + PhpResetServiceNonPollGate(); // HACK (dmex) } NTSTATUS PhpServiceQueryStage1Worker( @@ -733,7 +733,7 @@ VOID PhServiceProviderUpdate( // This has caused a massive decrease in background CPU usage, and // is certainly much better than the quadratic-time string comparisons - // we were doing before (in the "Look for dead services" section). + // we were doing before (in the "Look for dead services" section). (wj32) nameEntriesCount = 0; @@ -885,14 +885,14 @@ VOID PhServiceProviderUpdate( { // The process doesn't exist yet (to us). Set the pending // flag and when the process is added this will be - // fixed. + // fixed. (wj32) serviceItem->PendingProcess = TRUE; } } // If this is the first run of the provider, queue the // process query tasks. Otherwise, perform stage 1 - // processing now and queue stage 2 processing. + // processing now and queue stage 2 processing. (wj32) if (runCount > 0) { PH_SERVICE_QUERY_S1_DATA data; @@ -992,7 +992,7 @@ VOID PhServiceProviderUpdate( PPH_PROCESS_ITEM processItem; // The service stopped and started, and the only change we have detected - // is in the process ID. + // is in the process ID. (wj32) if (processItem = PhReferenceProcessItem(serviceModifiedData.OldService.ProcessId)) { @@ -1018,7 +1018,7 @@ VOID PhServiceProviderUpdate( serviceItem->NeedsConfigUpdate = FALSE; } - if (serviceItem->JustProcessed) // HACK + if (serviceItem->JustProcessed) // HACK (dmex) serviceItem->JustProcessed = FALSE; // Raise the service modified event. @@ -1125,7 +1125,7 @@ VOID CALLBACK PhpServicePropertyChangeNotifyCallback( PPH_SERVICE_ITEM serviceItem; // Note: Ignore deleted nofications since we handle this elsewhere and our - // notify context gets destroyed before services.exe invokes this callback. + // notify context gets destroyed before services.exe invokes this callback. (dmex) if (ServiceNotifyFlags == SERVICE_NOTIFY_DELETED) return; @@ -1245,7 +1245,7 @@ NTSTATUS PhpServiceNonPollThreadStart( if (SubscribeServiceChangeNotifications_I( notifyContext->ServiceHandle, - SC_EVENT_PROPERTY_CHANGE, // TODO: SC_EVENT_STATUS_CHANGE + SC_EVENT_PROPERTY_CHANGE, // TODO: SC_EVENT_STATUS_CHANGE (dmex) PhpServicePropertyChangeNotifyCallback, notifyContext, &serviceNotifyRegistration @@ -1279,7 +1279,7 @@ NTSTATUS PhpServiceNonPollThreadStart( InsertTailList(&PhpNonPollServiceListHead, ¬ifyContext->ListEntry); break; case ERROR_SERVICE_NOTIFY_CLIENT_LAGGING: - // We are lagging behind. Re-open the handle to the SCM as soon as possible. + // We are lagging behind. Re-open the handle to the SCM as soon as possible. (wj32) lagging = TRUE; break; case ERROR_SERVICE_MARKED_FOR_DELETE: @@ -1340,7 +1340,7 @@ VOID PhpInitializeServiceNonPoll( ) { PhpNonPollActive = TRUE; - PhpNonPollGate = 1; // initially the gate should be open since we only just initialized everything + PhpNonPollGate = 1; // initially the gate should be open since we only just initialized everything (wj32) PhCreateThread2(PhpServiceNonPollThreadStart, NULL); } @@ -1349,7 +1349,7 @@ VOID PhpWorkaroundWindows10ServiceTypeBug( _Inout_ LPENUM_SERVICE_STATUS_PROCESS ServieEntry ) { - // https://github.com/processhacker2/processhacker/issues/120 + // https://github.com/processhacker2/processhacker/issues/120 (dmex) if (ServieEntry->ServiceStatusProcess.dwServiceType == SERVICE_WIN32) ServieEntry->ServiceStatusProcess.dwServiceType = SERVICE_WIN32_SHARE_PROCESS; if (ServieEntry->ServiceStatusProcess.dwServiceType == (SERVICE_WIN32 | SERVICE_USER_SHARE_PROCESS | SERVICE_USERSERVICE_INSTANCE)) From bff436f309f6e35c3748b655ea8b7764a6d246bb Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 28 Jan 2019 09:06:35 +0100 Subject: [PATCH 1606/2058] Fix service handle leak #369 --- ProcessHacker/srvprv.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/ProcessHacker/srvprv.c b/ProcessHacker/srvprv.c index 0a797abee6b8..4dff916637bc 100644 --- a/ProcessHacker/srvprv.c +++ b/ProcessHacker/srvprv.c @@ -1221,11 +1221,20 @@ NTSTATUS PhpServiceNonPollThreadStart( break; case SnAdding: { - notifyContext->ServiceHandle = - OpenService(scManagerHandle, notifyContext->ServiceName->Buffer, SERVICE_QUERY_STATUS | SERVICE_QUERY_CONFIG); + notifyContext->ServiceHandle = OpenService( + scManagerHandle, + notifyContext->ServiceName->Buffer, + SERVICE_QUERY_STATUS | SERVICE_QUERY_CONFIG + ); if (!notifyContext->ServiceHandle) - OpenService(scManagerHandle, notifyContext->ServiceName->Buffer, SERVICE_QUERY_STATUS); + { + notifyContext->ServiceHandle = OpenService( + scManagerHandle, + notifyContext->ServiceName->Buffer, + SERVICE_QUERY_STATUS + ); + } if (!notifyContext->ServiceHandle) { From f68c0a0b420eb571a8a3767ca9915777cd5e9e37 Mon Sep 17 00:00:00 2001 From: diversenok Date: Mon, 28 Jan 2019 22:22:13 +0300 Subject: [PATCH 1607/2058] Correct token mandatory label interpretation (#371) --- phlib/native.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/phlib/native.c b/phlib/native.c index 28a5555e86ce..5177bdacbddb 100644 --- a/phlib/native.c +++ b/phlib/native.c @@ -2321,6 +2321,7 @@ NTSTATUS PhGetTokenIntegrityLevelRID( { NTSTATUS status; PTOKEN_MANDATORY_LABEL mandatoryLabel; + ULONG subAuthoritiesCount; ULONG subAuthority; PWSTR integrityString; @@ -2329,7 +2330,17 @@ NTSTATUS PhGetTokenIntegrityLevelRID( if (!NT_SUCCESS(status)) return status; - subAuthority = *RtlSubAuthoritySid(mandatoryLabel->Label.Sid, 0); + subAuthoritiesCount = *RtlSubAuthorityCountSid(mandatoryLabel->Label.Sid); + + if (subAuthoritiesCount > 0) + { + subAuthority = *RtlSubAuthoritySid(mandatoryLabel->Label.Sid, subAuthoritiesCount - 1); + } + else + { + subAuthority = SECURITY_MANDATORY_UNTRUSTED_RID; + } + PhFree(mandatoryLabel); if (IntegrityString) From 3e4f1018a60d289658648693f968d4bf971f9e04 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 28 Jan 2019 21:54:31 +0100 Subject: [PATCH 1608/2058] Update known token caps Co-Authored-By: James Forshaw --- ProcessHacker/resources/capslist.txt | 103 +++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) diff --git a/ProcessHacker/resources/capslist.txt b/ProcessHacker/resources/capslist.txt index d16ef623433d..f0a95a9af18f 100644 --- a/ProcessHacker/resources/capslist.txt +++ b/ProcessHacker/resources/capslist.txt @@ -603,24 +603,46 @@ ID_CAP_WPN_PLATFORM_REG_KEY ID_CAP_WPTOOLS_INSTALL_FOLDER ID_CAP_ZMFSERVICES ID_CAP_ZTRACE +Microsoft.firmwareRead_cw5n1h2txyewy +Microsoft.firmwareWrite_cw5n1h2txyewy accessoryManager activateAsUser +activity +activityData activitySystem +allAppMods allJoyn +allowElevation appBroadcast appBroadcastServices appBroadcastSettings appCaptureServices appCaptureSettings +appDiagnostics appLicensing +appManagementSystem applicationDefaults applicationViewActivation appointments appointmentsSystem audioDeviceConfiguration backgroundMediaPlayback +backgroundMediaRecording +backgroundVoIP biometricSystem blockedChatMessages +bluetooth +bluetooth.genericAttributeProfile +bluetooth.rfcomm +bluetoothAdapter +bluetoothDeviceSettings +bluetoothSync +broadFileSystemAccess +browserAppList +browserCredentials +cameraProcessingExtension +capabilityAccessConsentDeviceSettings +cellularData cellularDeviceControl cellularDeviceIdentity cellularMessaging @@ -630,6 +652,8 @@ childWebContent cloudExperienceHost cloudStore codeGeneration +comPort +componentUiInWebContent confirmAppClose constrainedImpersonation contacts @@ -640,25 +664,38 @@ coreShell cortanaPermissions cortanaSettings cortanaSpeechAccessory +cortanaSurface curatedTileCollections +dateAndTimeDeviceSettings developerSettings developmentModeNetwork +deviceEncryptionManagement +deviceIdentityManagement +deviceLockManagement deviceManagementAdministrator deviceManagementDeviceLockPolicies deviceManagementDmAccount deviceManagementEmailAccount deviceManagementFoundation +deviceManagementRegistration deviceManagementWapSecurityPolicies +devicePortalProvider +deviceProvisioningAdministrator deviceUnlock +diagnostics +displayDeviceSettings documentsLibrary dualSimTiles email emailSystem enterpriseAuthentication +enterpriseCloudSSO enterpriseDataPolicy enterpriseDeviceLockdown eraApplication exclusiveResource +expandedResources +extendedBackgroundTaskTime extendedExecutionBackgroundAudio extendedExecutionCritical extendedExecutionUnconstrained @@ -666,39 +703,60 @@ featureStagingInfo feedbackLogCollection firstSignInSettings flashPlayerSupport +fullFileSystemAccess gameBarServices gameConfigStoreManagement gameList +gameMonitor +gazeInput +globalMediaControl +graphicsCapture hevcPlayback hfxSystem hidTelephony holographicCompositor holographicCompositorSystem +humanInterfaceDevice +imeSystem +inProcessMediaExtension indexedContent inputForegroundObservation inputInjection inputInjectionBrokered inputObservation +inputSettings inputSuppression internetClient internetClientServer interopServices +keyboardDeviceSettings kinectAudio +kinectExpressions +kinectFace kinectGamechat +kinectRequired +kinectVideo +kinectVision +languageAndRegionDeviceSettings +languageSettings liveIdService +localExperienceInternal location locationHistory locationSystem lockScreenCreatives +lowLevel lowLevelDevices lpacAppExperience lpacClipboard lpacCom lpacCryptoServices lpacEnterprisePolicyChangeNotifications +lpacIME lpacIdentityServices lpacInstrumentation lpacMedia +lpacPackageManagerOperation lpacPayments lpacPnPNotifications lpacPrinting @@ -707,70 +765,108 @@ lpacSessionManagement lpacWebPlatform microphone microsoftEdgeRemoteDebugging +mixedRealityEnvironmentInternal +mmsTransportSystem multiplaneOverlay muma musicLibrary networkConnectionManagerProvisioning networkDataPlanProvisioning +networkDataUsageManagement +networkDeviceSettings networkDiagnostics networkingVpnProvider +nfcSystem +notificationsDeviceSettings objects3D oemDeployment oemPublicDirectory offlineMapsManagement +oneProcessVoIP +optical packageContents packageManagement packagePolicySystem packageQuery perceptionMonitoring +perceptionSensorsExperimental perceptionSystem +personalizationDeviceSettings phoneCall phoneCallHistory phoneCallHistoryPublic phoneCallHistorySystem +phoneCallSystem picturesLibrary +pointOfService +powerDeviceSettings +preemptiveCamera previewHfx +previewInkWorkspace previewPenWorkspace previewStore previewUiComposition privateNetworkClientServer +projectionDeviceSettings +protectedApp +proximity +radios recordedCallsFolder +regionSettings registryRead relatedPackages +remoteFileAccess remotePassportAuthentication remoteSystem removableStorage +resetPhone runFullTrust screenDuplication secondaryAuthenticationFactor secureAssessment +sensors.custom +serialCommunication sessionImpersonation settingSyncConfiguration sharedUserCertificates +shellDisplayManagement shellExperience shellExperienceComposer slapiQueryLicenseValue +smbios +sms smsSend smsSystem +smsTransportSystem spatialPerception startScreenManagement storeAppInstall storeAppInstallation storeConfiguration storeLicenseManagement +storeOptionalPackageInstallManagement +systemDialog +systemDialogEmergency systemManagement systemRegistrar targetedContent targetedContentSubscription teamEditionExperience +telemetryData +terminalPowerManagement +thumbnailCache +timezone uiAutomationSystem unzipFile +updateAndSecurityDeviceSettings +usb userAccountInformation userDataAccountSetup userDataAccountsProvider userDataSystem userDataTasks userDataTasksSystem +userManagementSystem userNotificationListener userPrincipalName userSigninSupport @@ -779,10 +875,17 @@ userWebAccounts videosLibrary visualElementsSystem visualVoiceMail +vmWorkerProcess voipCall walletSystem +webPlatformMediaExtension webcam +wiFiControl +wiFiDirect +windowManagement +windowManagementSystem windowsHelloCredentialAccess +windowsPerformanceCounters xboxAccessoryManagement xboxBroadcaster xboxGameSpeechWindow From 3f4206f45c1dcbcdb16abc2ee29ddc3dbf3c8aea Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 28 Jan 2019 22:04:38 +0100 Subject: [PATCH 1609/2058] Fix PhGetProcessPackageFullName string comparison --- phlib/appresolver.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/phlib/appresolver.c b/phlib/appresolver.c index dc9b38d7a0f1..7c8267bf560e 100644 --- a/phlib/appresolver.c +++ b/phlib/appresolver.c @@ -379,9 +379,9 @@ PPH_STRING PhGetProcessPackageFullName( { PTOKEN_SECURITY_ATTRIBUTE_V1 attribute = &info->Attribute.pAttributeV1[i]; - if (RtlEqualUnicodeString(&attribute->Name, &attributeNameUs, FALSE)) + if (attribute->ValueType == TOKEN_SECURITY_ATTRIBUTE_TYPE_STRING) { - if (attribute->ValueType == TOKEN_SECURITY_ATTRIBUTE_TYPE_STRING) + if (RtlEqualUnicodeString(&attribute->Name, &attributeNameUs, FALSE)) { packageName = PhCreateStringFromUnicodeString(&attribute->Values.pString[0]); break; From fb553c75bbc0b8fa65876947bc7d3b1755d0da36 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 28 Jan 2019 22:05:44 +0100 Subject: [PATCH 1610/2058] Improve IDataObject caching --- phlib/secedit.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/phlib/secedit.c b/phlib/secedit.c index 7519bbad0f78..5d9d7f4c2505 100644 --- a/phlib/secedit.c +++ b/phlib/secedit.c @@ -629,8 +629,7 @@ ULONG STDMETHODCALLTYPE PhSecurityDataObject_Release( if (this->RefCount == 0) { - for (ULONG i = 0; i < this->NameCache->Count; i++) - PhDereferenceObject(this->NameCache->Items[i]); + PhDereferenceObjects(this->NameCache->Items, this->NameCache->Count); PhDereferenceObject(this->NameCache); PhFree(this); From 02d7b8303c7c8f93f6c7a1a19f3d4587140e8c06 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 28 Jan 2019 22:06:17 +0100 Subject: [PATCH 1611/2058] Add RtlDetermineDosPathNameType_Ustr --- phnt/include/ntrtl.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/phnt/include/ntrtl.h b/phnt/include/ntrtl.h index fde3749e4126..fd9bf57340b6 100644 --- a/phnt/include/ntrtl.h +++ b/phnt/include/ntrtl.h @@ -3388,6 +3388,13 @@ RtlDetermineDosPathNameType_U( _In_ PWSTR DosFileName ); +NTSYSAPI +RTL_PATH_TYPE +NTAPI +RtlDetermineDosPathNameType_Ustr( + _In_ PCUNICODE_STRING DosFileName + ); + NTSYSAPI ULONG NTAPI From 276b256d01a359418bd80462de5ec77f9010e3af Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 28 Jan 2019 22:06:45 +0100 Subject: [PATCH 1612/2058] Update token security attributes --- phnt/include/ntseapi.h | 1 + 1 file changed, 1 insertion(+) diff --git a/phnt/include/ntseapi.h b/phnt/include/ntseapi.h index eb23fb867c95..2f0b2f8888a3 100644 --- a/phnt/include/ntseapi.h +++ b/phnt/include/ntseapi.h @@ -84,6 +84,7 @@ #define TOKEN_SECURITY_ATTRIBUTE_DISABLED_BY_DEFAULT 0x0008 #define TOKEN_SECURITY_ATTRIBUTE_DISABLED 0x0010 #define TOKEN_SECURITY_ATTRIBUTE_MANDATORY 0x0020 +#define TOKEN_SECURITY_ATTRIBUTE_COMPARE_IGNORE 0x0040 #define TOKEN_SECURITY_ATTRIBUTE_VALID_FLAGS ( \ TOKEN_SECURITY_ATTRIBUTE_NON_INHERITABLE | \ From b5213bbe2312a840588c47704f7302cdefa012ca Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 28 Jan 2019 22:17:04 +0100 Subject: [PATCH 1613/2058] Show current package capability name --- ProcessHacker/tokprp.c | 98 ++++++++++++++++++++++++++++++------------ 1 file changed, 70 insertions(+), 28 deletions(-) diff --git a/ProcessHacker/tokprp.c b/ProcessHacker/tokprp.c index acf1cda1ea48..b8fd6de0c0a6 100644 --- a/ProcessHacker/tokprp.c +++ b/ProcessHacker/tokprp.c @@ -1969,33 +1969,73 @@ INT_PTR CALLBACK PhpTokenCapabilitiesPageProc( ULONG subAuthoritiesCount; ULONG subAuthority; - subAuthoritiesCount = *(PULONG)RtlSubAuthorityCountSid(tokenPageContext->Capabilities->Groups[i].Sid); - subAuthority = *(PULONG)RtlSubAuthoritySid(tokenPageContext->Capabilities->Groups[i].Sid, 0); - - //memcmp((BYTE[])SECURITY_APP_PACKAGE_AUTHORITY, RtlIdentifierAuthoritySid(tokenPageContext->Capabilities->Groups[i].Sid), sizeof((BYTE[])SECURITY_APP_PACKAGE_AUTHORITY)) - if ( - subAuthoritiesCount == SECURITY_CAPABILITY_RID_COUNT && - subAuthority == SECURITY_CAPABILITY_BASE_RID - ) + subAuthoritiesCount = *RtlSubAuthorityCountSid(tokenPageContext->Capabilities->Groups[i].Sid); + subAuthority = *RtlSubAuthoritySid(tokenPageContext->Capabilities->Groups[i].Sid, 0); + + // RtlIdentifierAuthoritySid(tokenPageContext->Capabilities->Groups[i].Sid) == (BYTE[])SECURITY_APP_PACKAGE_AUTHORITY + if (subAuthority == SECURITY_CAPABILITY_BASE_RID) { - GUID capabilityGuid; - ULONG firstPart; - ULONG secondPart; - ULONG thirdPart; - ULONG lastPart; - - firstPart = *(PULONG)RtlSubAuthoritySid(tokenPageContext->Capabilities->Groups[i].Sid, 1); - secondPart = *(PULONG)RtlSubAuthoritySid(tokenPageContext->Capabilities->Groups[i].Sid, 2); - thirdPart = *(PULONG)RtlSubAuthoritySid(tokenPageContext->Capabilities->Groups[i].Sid, 3); - lastPart = *(PULONG)RtlSubAuthoritySid(tokenPageContext->Capabilities->Groups[i].Sid, 4); - - capabilityGuid.Data1 = firstPart; - capabilityGuid.Data2 = LOWORD(secondPart); - capabilityGuid.Data3 = HIWORD(secondPart); - memcpy(capabilityGuid.Data4, &thirdPart, sizeof(ULONG)); - memcpy(capabilityGuid.Data4 + sizeof(ULONG), &lastPart, sizeof(ULONG)); - - name = PhFormatGuid(&capabilityGuid); + if (subAuthoritiesCount == SECURITY_APP_PACKAGE_RID_COUNT) + { + PTOKEN_APPCONTAINER_INFORMATION appContainerInfo; + + //if (*RtlSubAuthoritySid(tokenPageContext->Capabilities->Groups[i].Sid, 1) == SECURITY_CAPABILITY_APP_RID) + // continue; + + if (NT_SUCCESS(PhQueryTokenVariableSize(tokenHandle, TokenAppContainerSid, &appContainerInfo))) + { + if (appContainerInfo->TokenAppContainer) + { + BOOLEAN isPackageCapability = TRUE; + + for (ULONG ii = 1; ii < subAuthoritiesCount - 1; ii++) + { + if ( + *RtlSubAuthoritySid(appContainerInfo->TokenAppContainer, ii) != + *RtlSubAuthoritySid(tokenPageContext->Capabilities->Groups[i].Sid, ii) + ) + { + isPackageCapability = FALSE; + break; + } + } + + if (isPackageCapability) + { + HANDLE processHandle; + + if (NT_SUCCESS(PhOpenProcess(&processHandle, PROCESS_QUERY_LIMITED_INFORMATION, (HANDLE)tokenPageContext->Context))) + { + name = PhGetProcessPackageFullName(processHandle); + NtClose(processHandle); + } + } + } + + PhFree(appContainerInfo); + } + } + else if (subAuthoritiesCount == SECURITY_CAPABILITY_RID_COUNT) + { + GUID capabilityGuid; + ULONG firstPart; + ULONG secondPart; + ULONG thirdPart; + ULONG lastPart; + + firstPart = *RtlSubAuthoritySid(tokenPageContext->Capabilities->Groups[i].Sid, 1); + secondPart = *RtlSubAuthoritySid(tokenPageContext->Capabilities->Groups[i].Sid, 2); + thirdPart = *RtlSubAuthoritySid(tokenPageContext->Capabilities->Groups[i].Sid, 3); + lastPart = *RtlSubAuthoritySid(tokenPageContext->Capabilities->Groups[i].Sid, 4); + + capabilityGuid.Data1 = firstPart; + capabilityGuid.Data2 = LOWORD(secondPart); + capabilityGuid.Data3 = HIWORD(secondPart); + *((PULONG)&capabilityGuid.Data4[0]) = thirdPart; + *((PULONG)&capabilityGuid.Data4[4]) = lastPart; + + name = PhFormatGuid(&capabilityGuid); + } } } @@ -2330,6 +2370,8 @@ PPH_STRING PhGetSecurityAttributeFlagsString( PhAppendStringBuilder2(&sb, L"Case-sensitive, "); if (Flags & TOKEN_SECURITY_ATTRIBUTE_NON_INHERITABLE) PhAppendStringBuilder2(&sb, L"Non-inheritable, "); + if (Flags & TOKEN_SECURITY_ATTRIBUTE_COMPARE_IGNORE) + PhAppendStringBuilder2(&sb, L"Compare-Ignore, "); if (sb.String->Length != 0) PhRemoveEndStringBuilder(&sb, 2); @@ -2471,7 +2513,7 @@ BOOLEAN PhpAddTokenClaimAttributes( // Flags temp = PhGetSecurityAttributeFlagsString(attribute->Flags); PhpAddAttributeNode(&TokenPageContext->ClaimsTreeContext, node, - PhFormatString(L"Flags: %s", temp->Buffer)); + PhFormatString(L"Flags: %s (0x%lx)", temp->Buffer, attribute->Flags)); PhDereferenceObject(temp); // Values @@ -2637,7 +2679,7 @@ BOOLEAN PhpAddTokenAttributes( // Flags temp = PhGetSecurityAttributeFlagsString(attribute->Flags); PhpAddAttributeNode(&TokenPageContext->AuthzTreeContext, node, - PhFormatString(L"Flags: %s", temp->Buffer)); + PhFormatString(L"Flags: %s (0x%lx)", temp->Buffer, attribute->Flags)); PhDereferenceObject(temp); // Values From 511916386b88620e3cd01730b6e0dbcf452eebd4 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 28 Jan 2019 22:18:50 +0100 Subject: [PATCH 1614/2058] Remove legacy menu resources --- ProcessHacker/ProcessHacker.rc | 23 ----------------------- ProcessHacker/memlists.c | 6 +++++- ProcessHacker/memrslt.c | 5 ++++- 3 files changed, 9 insertions(+), 25 deletions(-) diff --git a/ProcessHacker/ProcessHacker.rc b/ProcessHacker/ProcessHacker.rc index fa2e827a0cbc..df4282cdfe69 100644 --- a/ProcessHacker/ProcessHacker.rc +++ b/ProcessHacker/ProcessHacker.rc @@ -423,29 +423,6 @@ BEGIN END END -IDR_MEMFILTER MENU -BEGIN - POPUP "Filter" - BEGIN - MENUITEM "Contains...", ID_FILTER_CONTAINS - MENUITEM "Contains (case-insensitive)...", ID_FILTER_CONTAINS_CASEINSENSITIVE - MENUITEM "Regex...", ID_FILTER_REGEX - MENUITEM "Regex (case-insensitive)...", ID_FILTER_REGEX_CASEINSENSITIVE - END -END - -IDR_EMPTYMEMLISTS MENU -BEGIN - POPUP "Empty" - BEGIN - MENUITEM "&Combine memory lists", ID_EMPTY_COMBINEMEMORYLISTS - MENUITEM "Empty &working sets", ID_EMPTY_EMPTYWORKINGSETS - MENUITEM "Empty &modified page list", ID_EMPTY_EMPTYMODIFIEDPAGELIST - MENUITEM "Empty &standby list", ID_EMPTY_EMPTYSTANDBYLIST - MENUITEM "Empty &priority 0 standby list", ID_EMPTY_EMPTYPRIORITY0STANDBYLIST - END -END - IDR_MINIINFO MENU BEGIN POPUP "Mini Info" diff --git a/ProcessHacker/memlists.c b/ProcessHacker/memlists.c index 303ea92b70ff..61948f7cb774 100644 --- a/ProcessHacker/memlists.c +++ b/ProcessHacker/memlists.c @@ -216,7 +216,11 @@ INT_PTR CALLBACK PhpMemoryListsDlgProc( SYSTEM_MEMORY_LIST_COMMAND command = -1; menu = PhCreateEMenu(); - PhLoadResourceEMenuItem(menu, PhInstanceHandle, MAKEINTRESOURCE(IDR_EMPTYMEMLISTS), 0); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_EMPTY_COMBINEMEMORYLISTS, L"&Combine memory lists", NULL, NULL), ULONG_MAX); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_EMPTY_EMPTYWORKINGSETS, L"Empty &working sets", NULL, NULL), ULONG_MAX); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_EMPTY_EMPTYMODIFIEDPAGELIST, L"Empty &modified page list", NULL, NULL), ULONG_MAX); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_EMPTY_EMPTYSTANDBYLIST, L"Empty &standby list", NULL, NULL), ULONG_MAX); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_EMPTY_EMPTYPRIORITY0STANDBYLIST, L"Empty &priority 0 standby list", NULL, NULL), ULONG_MAX); GetClientRect(GetDlgItem(hwndDlg, IDC_EMPTY), &buttonRect); point.x = 0; diff --git a/ProcessHacker/memrslt.c b/ProcessHacker/memrslt.c index 62b6da1802be..20e97d60992a 100644 --- a/ProcessHacker/memrslt.c +++ b/ProcessHacker/memrslt.c @@ -459,7 +459,10 @@ INT_PTR CALLBACK PhpMemoryResultsDlgProc( ULONG filterType = 0; menu = PhCreateEMenu(); - PhLoadResourceEMenuItem(menu, PhInstanceHandle, MAKEINTRESOURCE(IDR_MEMFILTER), 0); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_FILTER_CONTAINS, L"Contains...", NULL, NULL), ULONG_MAX); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_FILTER_CONTAINS_CASEINSENSITIVE, L"Contains (case-insensitive)...", NULL, NULL), ULONG_MAX); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_FILTER_REGEX, L"Regex...", NULL, NULL), ULONG_MAX); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_FILTER_REGEX_CASEINSENSITIVE, L"Regex (case-insensitive)...", NULL, NULL), ULONG_MAX); GetClientRect(GetDlgItem(hwndDlg, IDC_FILTER), &buttonRect); point.x = 0; From 385b2c781149f2336d01bac5868e091b365b8ee6 Mon Sep 17 00:00:00 2001 From: diversenok Date: Tue, 29 Jan 2019 13:54:46 +0300 Subject: [PATCH 1615/2058] Fix user-related environments (#372) --- ProcessHacker/prpgenv.c | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/ProcessHacker/prpgenv.c b/ProcessHacker/prpgenv.c index 1c10acd44745..225bdfe41c89 100644 --- a/ProcessHacker/prpgenv.c +++ b/ProcessHacker/prpgenv.c @@ -184,20 +184,30 @@ VOID PhpRefreshEnvironmentList( } } - if (CreateEnvironmentBlock) - { - CreateEnvironmentBlock(&Context->SystemDefaultEnvironment, NULL, FALSE); - CreateEnvironmentBlock(&Context->UserDefaultEnvironment, PhGetOwnTokenAttributes().TokenHandle, FALSE); - } - if (NT_SUCCESS(PhOpenProcess( &processHandle, PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, ProcessItem->ProcessId ))) { + HANDLE tokenHandle; ULONG flags = 0; + if (CreateEnvironmentBlock) + { + CreateEnvironmentBlock(&Context->SystemDefaultEnvironment, NULL, FALSE); + + if (NT_SUCCESS(PhOpenProcessToken( + processHandle, + TOKEN_QUERY | TOKEN_DUPLICATE, + &tokenHandle + ))) + { + CreateEnvironmentBlock(&Context->UserDefaultEnvironment, tokenHandle, FALSE); + NtClose(tokenHandle); + } + } + #ifdef _WIN64 if (ProcessItem->IsWow64) flags |= PH_GET_PROCESS_ENVIRONMENT_WOW64; @@ -240,7 +250,7 @@ VOID PhpRefreshEnvironmentList( item = PhItemArray(&Context->Items, i); - if (PhQueryEnvironmentVariable( + if (Context->SystemDefaultEnvironment && PhQueryEnvironmentVariable( Context->SystemDefaultEnvironment, &item->Name->sr, NULL @@ -264,7 +274,7 @@ VOID PhpRefreshEnvironmentList( PhDereferenceObject(variableValue); } } - else if (PhQueryEnvironmentVariable( + else if (Context->UserDefaultEnvironment && PhQueryEnvironmentVariable( Context->UserDefaultEnvironment, &item->Name->sr, NULL From 1bd7b5588c576113c417d875c4bf72817a9fe585 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 29 Jan 2019 22:08:33 +0100 Subject: [PATCH 1616/2058] Add PhGetCapabilityGuidName --- phlib/include/lsasup.h | 7 ++ phlib/lsasup.c | 169 +++++++++++++++++++++++++++++++++++++++++ phlib/ref.c | 1 + 3 files changed, 177 insertions(+) diff --git a/phlib/include/lsasup.h b/phlib/include/lsasup.h index e9a1050fadac..7b45bf110551 100644 --- a/phlib/include/lsasup.h +++ b/phlib/include/lsasup.h @@ -96,6 +96,13 @@ PhGetCapabilitySidName( _In_ PSID CapabilitySid ); +PHLIBAPI +PPH_STRING +NTAPI +PhGetCapabilityGuidName( + _In_ PPH_STRING GuidString + ); + #ifdef __cplusplus } #endif diff --git a/phlib/lsasup.c b/phlib/lsasup.c index a07a0fbb2316..38606d291eaa 100644 --- a/phlib/lsasup.c +++ b/phlib/lsasup.c @@ -607,3 +607,172 @@ PPH_STRING PhGetCapabilitySidName( return NULL; } + +typedef struct _PH_CAPABILITY_GUID_ENTRY +{ + PPH_STRING Name; + PPH_STRING CapabilityGuid; +} PH_CAPABILITY_GUID_ENTRY, *PPH_CAPABILITY_GUID_ENTRY; + +PH_ARRAY PhpCapGuidArrayList; + +BOOLEAN NTAPI PhpTokenEnumerateKeyCallback( + _In_ PKEY_BASIC_INFORMATION Information, + _In_opt_ PVOID Context + ) +{ + PhAddItemList(Context, PhCreateStringEx(Information->Name, Information->NameLength)); + return TRUE; +} + +VOID PhInitializeCapabilityGuidCache( + VOID + ) +{ + static PH_STRINGREF accessManagerKeyPath = PH_STRINGREF_INIT(L"Software\\Microsoft\\Windows\\CurrentVersion\\CapabilityAccessManager\\Capabilities"); + static PH_STRINGREF deviceAccessKeyPath = PH_STRINGREF_INIT(L"Software\\Microsoft\\Windows\\CurrentVersion\\DeviceAccess\\CapabilityMappings"); + HANDLE keyHandle; + ULONG i; + + PhInitializeArray(&PhpCapGuidArrayList, sizeof(PH_CAPABILITY_GUID_ENTRY), 100); + + if (NT_SUCCESS(PhOpenKey( + &keyHandle, + KEY_READ, + PH_KEY_LOCAL_MACHINE, + &accessManagerKeyPath, + 0 + ))) + { + PPH_LIST capabilityNameList; + + capabilityNameList = PhCreateList(1); + PhEnumerateKey(keyHandle, PhpTokenEnumerateKeyCallback, capabilityNameList); + + for (i = 0; i < capabilityNameList->Count; i++) + { + HANDLE subKeyHandle; + PPH_STRING subKeyName; + PPH_STRING guidString; + + subKeyName = capabilityNameList->Items[i]; + + if (NT_SUCCESS(PhOpenKey( + &subKeyHandle, + KEY_READ, + keyHandle, + &subKeyName->sr, + 0 + ))) + { + if (guidString = PhQueryRegistryString(subKeyHandle, L"LegacyInterfaceClassGuid")) + { + PH_CAPABILITY_GUID_ENTRY entry; + + PhSetReference(&entry.Name, subKeyName); + PhSetReference(&entry.CapabilityGuid, guidString); + PhAddItemArray(&PhpCapGuidArrayList, &entry); + + PhDereferenceObject(guidString); + } + + NtClose(subKeyHandle); + } + } + + PhDereferenceObjects(capabilityNameList->Items, capabilityNameList->Count); + PhDereferenceObject(capabilityNameList); + + NtClose(keyHandle); + } + + if (NT_SUCCESS(PhOpenKey( + &keyHandle, + KEY_READ, + PH_KEY_LOCAL_MACHINE, + &deviceAccessKeyPath, + 0 + ))) + { + PPH_LIST capabilityNameList; + + capabilityNameList = PhCreateList(1); + PhEnumerateKey(keyHandle, PhpTokenEnumerateKeyCallback, capabilityNameList); + + for (i = 0; i < capabilityNameList->Count; i++) + { + HANDLE subKeyHandle; + PPH_STRING subKeyName; + + subKeyName = capabilityNameList->Items[i]; + + if (NT_SUCCESS(PhOpenKey( + &subKeyHandle, + KEY_READ, + keyHandle, + &subKeyName->sr, + 0 + ))) + { + PPH_LIST capabilityGuidList; + ULONG ii; + + capabilityGuidList = PhCreateList(1); + PhEnumerateKey(subKeyHandle, PhpTokenEnumerateKeyCallback, capabilityGuidList); + + for (ii = 0; ii < capabilityGuidList->Count; ii++) + { + PPH_STRING guidString; + PH_CAPABILITY_GUID_ENTRY entry; + + guidString = capabilityGuidList->Items[ii]; + + PhSetReference(&entry.Name, subKeyName); + entry.CapabilityGuid = guidString; + + PhAddItemArray(&PhpCapGuidArrayList, &entry); + } + + PhDereferenceObjects(capabilityGuidList->Items, capabilityGuidList->Count); + PhDereferenceObject(capabilityGuidList); + + NtClose(subKeyHandle); + } + } + + PhDereferenceObjects(capabilityNameList->Items, capabilityNameList->Count); + PhDereferenceObject(capabilityNameList); + + NtClose(keyHandle); + } +} + +PPH_STRING PhGetCapabilityGuidName( + _In_ PPH_STRING GuidString + ) +{ + static PH_INITONCE initOnce = PH_INITONCE_INIT; + PPH_CAPABILITY_GUID_ENTRY entry; + ULONG i; + + if (WindowsVersion < WINDOWS_8) + return NULL; + + if (PhBeginInitOnce(&initOnce)) + { + PhInitializeCapabilityGuidCache(); + PhEndInitOnce(&initOnce); + } + + for (i = 0; i < PhpCapGuidArrayList.Count; i++) + { + entry = PhItemArray(&PhpCapGuidArrayList, i); + + if (PhEqualString(entry->CapabilityGuid, GuidString, TRUE)) + { + return PhReferenceObject(entry->Name); + } + } + + return NULL; +} diff --git a/phlib/ref.c b/phlib/ref.c index 0c80254fc886..03ba320ed0ad 100644 --- a/phlib/ref.c +++ b/phlib/ref.c @@ -242,6 +242,7 @@ VOID PhDereferenceObject( // Decrement the reference count. newRefCount = _InterlockedDecrement(&objectHeader->RefCount); ASSUME_ASSERT(newRefCount >= 0); + assert(!(newRefCount < 0)); // Free the object if it has 0 references. if (newRefCount == 0) From 4457f18c5f9b0f9e606d667951eb492f2fad21c3 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 29 Jan 2019 22:09:06 +0100 Subject: [PATCH 1617/2058] Rename variable --- phlib/wslsup.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/phlib/wslsup.c b/phlib/wslsup.c index 21faa1019825..06953b8e0363 100644 --- a/phlib/wslsup.c +++ b/phlib/wslsup.c @@ -73,26 +73,26 @@ PPH_STRING PhGetWslDistributionFromPath( 0 ))) { - PPH_STRING basePathName = PhQueryRegistryString(subKeyHandle, L"BasePath"); + PPH_STRING lxssBasePathName = PhQueryRegistryString(subKeyHandle, L"BasePath"); - if (PhStartsWithString(FileName, basePathName, TRUE)) + if (PhStartsWithString(FileName, lxssBasePathName, TRUE)) { lxssDistributionName = PhQueryRegistryString(subKeyHandle, L"DistributionName"); if (LxssDistroPath) { - PhSetReference(&lxssDistroPath, basePathName); + PhSetReference(&lxssDistroPath, lxssBasePathName); } if (LxssFileName) { lxssFileName = PhDuplicateString(FileName); - PhSkipStringRef(&lxssFileName->sr, basePathName->Length); + PhSkipStringRef(&lxssFileName->sr, lxssBasePathName->Length); PhSkipStringRef(&lxssFileName->sr, sizeof(L"rootfs")); } } - PhDereferenceObject(basePathName); + PhDereferenceObject(lxssBasePathName); NtClose(subKeyHandle); } From 92eb909d7b474898b72ee72acc52360de78ec764 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 29 Jan 2019 22:11:13 +0100 Subject: [PATCH 1618/2058] Update token capabilities page with capability guid name --- ProcessHacker/tokprp.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/ProcessHacker/tokprp.c b/ProcessHacker/tokprp.c index b8fd6de0c0a6..b5d463f2478a 100644 --- a/ProcessHacker/tokprp.c +++ b/ProcessHacker/tokprp.c @@ -2017,6 +2017,7 @@ INT_PTR CALLBACK PhpTokenCapabilitiesPageProc( } else if (subAuthoritiesCount == SECURITY_CAPABILITY_RID_COUNT) { + PPH_STRING capabilityName; GUID capabilityGuid; ULONG firstPart; ULONG secondPart; @@ -2034,7 +2035,13 @@ INT_PTR CALLBACK PhpTokenCapabilitiesPageProc( *((PULONG)&capabilityGuid.Data4[0]) = thirdPart; *((PULONG)&capabilityGuid.Data4[4]) = lastPart; - name = PhFormatGuid(&capabilityGuid); + if (name = PhFormatGuid(&capabilityGuid)) + { + if (capabilityName = PhGetCapabilityGuidName(name)) + { + PhMoveReference(&name, capabilityName); + } + } } } } From 3f447c029c4064cc4c119b05a5f5991f808db872 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 29 Jan 2019 22:21:46 +0100 Subject: [PATCH 1619/2058] Update string formats --- ProcessHacker/plugin.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/ProcessHacker/plugin.c b/ProcessHacker/plugin.c index 5d25f22ffb8d..1af19b6397f5 100644 --- a/ProcessHacker/plugin.c +++ b/ProcessHacker/plugin.c @@ -187,11 +187,13 @@ static BOOLEAN EnumPluginsDirectoryCallback( _In_opt_ PVOID Context ) { - static PWSTR PhpPluginBlocklist[] = + static PH_STRINGREF PhpPluginExtension = PH_STRINGREF_INIT(L".dll"); + static PH_STRINGREF PhpPluginBlocklist[] = { - L"CommonUtil.dll", - L"ExtraPlugins.dll", - L"SbieSupport.dll" + PH_STRINGREF_INIT(L"CommonUtil.dll"), + PH_STRINGREF_INIT(L"ExtraPlugins.dll"), + PH_STRINGREF_INIT(L"SbieSupport.dll"), + PH_STRINGREF_INIT(L"HexPidPlugin.dll") }; BOOLEAN blocklistedPlugin = FALSE; PH_STRINGREF baseName; @@ -201,12 +203,12 @@ static BOOLEAN EnumPluginsDirectoryCallback( baseName.Length = Information->FileNameLength; // Note: The *.dll pattern passed to NtQueryDirectoryFile includes extensions other than dll (For example: *.dll* or .dllmanifest). (dmex) - if (!PhEndsWithStringRef2(&baseName, L".dll", FALSE)) + if (!PhEndsWithStringRef(&baseName, &PhpPluginExtension, FALSE)) return TRUE; for (ULONG i = 0; i < RTL_NUMBER_OF(PhpPluginBlocklist); i++) { - if (PhEndsWithStringRef2(&baseName, PhpPluginBlocklist[i], TRUE)) + if (PhEndsWithStringRef(&baseName, &PhpPluginBlocklist[i], TRUE)) { blocklistedPlugin = TRUE; break; From 2d9367e8671d46ee48771016f1eba211dd458357 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 29 Jan 2019 23:15:21 +0100 Subject: [PATCH 1620/2058] Fix PhInitializeMappedArchive bug when viewing llvm compiled lib files --- phlib/maplib.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/phlib/maplib.c b/phlib/maplib.c index c46477a3a5aa..2a24acae8911 100644 --- a/phlib/maplib.c +++ b/phlib/maplib.c @@ -3,6 +3,7 @@ * mapped library * * Copyright (C) 2010 wj32 + * Copyright (C) 2019 dmex * * This file is part of Process Hacker. * @@ -100,7 +101,10 @@ NTSTATUS PhInitializeMappedArchive( if (!NT_SUCCESS(status)) return status; - if (MappedArchive->SecondLinkerMember.Type != LinkerArchiveMemberType) + if ( + MappedArchive->SecondLinkerMember.Type != LinkerArchiveMemberType && + MappedArchive->SecondLinkerMember.Type != NormalArchiveMemberType // NormalArchiveMemberType might not be correct here but set by LLVM compiled libs (dmex) + ) return STATUS_INVALID_PARAMETER; // Longnames member @@ -155,7 +159,7 @@ NTSTATUS PhLoadMappedArchive( if (!NT_SUCCESS(status)) { - NtUnmapViewOfSection(NtCurrentProcess(), MappedArchive->ViewBase); + PhUnloadMappedArchive(MappedArchive); } } From 9c7864631e0067490751ab8961ea78367d07066a Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 29 Jan 2019 23:29:38 +0100 Subject: [PATCH 1621/2058] Fix reference bug from commit 1bd7b55 --- phlib/lsasup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phlib/lsasup.c b/phlib/lsasup.c index 38606d291eaa..a412d7fa003e 100644 --- a/phlib/lsasup.c +++ b/phlib/lsasup.c @@ -728,7 +728,7 @@ VOID PhInitializeCapabilityGuidCache( guidString = capabilityGuidList->Items[ii]; PhSetReference(&entry.Name, subKeyName); - entry.CapabilityGuid = guidString; + PhSetReference(&entry.CapabilityGuid, guidString); PhAddItemArray(&PhpCapGuidArrayList, &entry); } From 38d98a21408b79a4541e58c99307c0784cef2793 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 1 Feb 2019 20:38:19 +0100 Subject: [PATCH 1622/2058] Fix parsing DOS1.0 environment variables (patch by diversenok) Co-Authored-By: diversenok --- phlib/native.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/phlib/native.c b/phlib/native.c index 5177bdacbddb..a826bac8dfa2 100644 --- a/phlib/native.c +++ b/phlib/native.c @@ -1063,8 +1063,8 @@ BOOLEAN PhEnumProcessEnvironmentVariables( { if (currentIndex >= length) return FALSE; - if (*currentChar == '=') - break; + if ((*currentChar == '=') && (startIndex != currentIndex)) + break; // equality sign is considered as a delimiter unless it is the first character (diversenok) if (*currentChar == 0) return FALSE; // no more variables From 19e235daa4513f1df5b1f9ed99ab8ec70e89ca3c Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 1 Feb 2019 20:43:37 +0100 Subject: [PATCH 1623/2058] Add support for undocumented CMD environment variables (modified patch by diversenok) #374 Co-Authored-By: diversenok --- ProcessHacker/prpgenv.c | 157 ++++++++++++++++++++-------------------- 1 file changed, 80 insertions(+), 77 deletions(-) diff --git a/ProcessHacker/prpgenv.c b/ProcessHacker/prpgenv.c index 225bdfe41c89..06ebc431371d 100644 --- a/ProcessHacker/prpgenv.c +++ b/ProcessHacker/prpgenv.c @@ -3,7 +3,7 @@ * Process properties: Environment page * * Copyright (C) 2009-2016 wj32 - * Copyright (C) 2018 dmex + * Copyright (C) 2018-2019 dmex * * This file is part of Process Hacker. * @@ -38,9 +38,11 @@ typedef enum _ENVIRONMENT_TREE_MENU_ITEM ENVIRONMENT_TREE_MENU_ITEM_HIDE_PROCESS_TYPE = 1, ENVIRONMENT_TREE_MENU_ITEM_HIDE_USER_TYPE, ENVIRONMENT_TREE_MENU_ITEM_HIDE_SYSTEM_TYPE, + ENVIRONMENT_TREE_MENU_ITEM_HIDE_CMD_TYPE, ENVIRONMENT_TREE_MENU_ITEM_HIGHLIGHT_PROCESS_TYPE, ENVIRONMENT_TREE_MENU_ITEM_HIGHLIGHT_USER_TYPE, ENVIRONMENT_TREE_MENU_ITEM_HIGHLIGHT_SYSTEM_TYPE, + ENVIRONMENT_TREE_MENU_ITEM_HIGHLIGHT_CMD_TYPE, ENVIRONMENT_TREE_MENU_ITEM_NEW_ENVIRONMENT_VARIABLE, ENVIRONMENT_TREE_MENU_ITEM_MAXIMUM } ENVIRONMENT_TREE_MENU_ITEM; @@ -81,12 +83,20 @@ typedef struct _PHP_PROCESS_ENVIRONMENT_TREENODE PROCESS_ENVIRONMENT_TREENODE_TYPE Type; PPH_STRING NameText; PPH_STRING ValueText; + union + { + BOOLEAN Flags; + struct + { + BOOLEAN IsCmdVariable : 1; + BOOLEAN Spare : 7; + }; + }; } PHP_PROCESS_ENVIRONMENT_TREENODE, *PPHP_PROCESS_ENVIRONMENT_TREENODE; -PPHP_PROCESS_ENVIRONMENT_TREENODE PhpAddEnvironmentChildNode( +PPHP_PROCESS_ENVIRONMENT_TREENODE PhpAddEnvironmentNode( _In_ PPH_ENVIRONMENT_CONTEXT Context, _In_opt_ PPHP_PROCESS_ENVIRONMENT_TREENODE ParentNode, - _In_ ULONG Id, _In_ PROCESS_ENVIRONMENT_TREENODE_TYPE Type, _In_ PPH_STRING Name, _In_opt_ PPH_STRING Value @@ -140,8 +150,11 @@ VOID PhpClearEnvironmentItems( for (i = 0; i < Context->Items.Count; i++) { item = PhItemArray(&Context->Items, i); - PhDereferenceObject(item->Name); - PhDereferenceObject(item->Value); + + if (item->Name) + PhDereferenceObject(item->Name); + if (item->Value) + PhDereferenceObject(item->Value); } PhClearArray(&Context->Items); @@ -165,9 +178,9 @@ VOID PhpRefreshEnvironmentList( ULONG i; PhpClearEnvironmentTree(Context); - processRootNode = PhpAddEnvironmentChildNode(Context, NULL, 0, 0, PhaCreateString(L"Process"), NULL); - userRootNode = PhpAddEnvironmentChildNode(Context, NULL, 0, 0, PhaCreateString(L"User"), NULL); - systemRootNode = PhpAddEnvironmentChildNode(Context, NULL, 0, 0, PhaCreateString(L"System"), NULL); + processRootNode = PhpAddEnvironmentNode(Context, NULL, PROCESS_ENVIRONMENT_TREENODE_TYPE_GROUP, PhaCreateString(L"Process"), NULL); + userRootNode = PhpAddEnvironmentNode(Context, NULL, PROCESS_ENVIRONMENT_TREENODE_TYPE_GROUP, PhaCreateString(L"User"), NULL); + systemRootNode = PhpAddEnvironmentNode(Context, NULL, PROCESS_ENVIRONMENT_TREENODE_TYPE_GROUP, PhaCreateString(L"System"), NULL); if (DestroyEnvironmentBlock) { @@ -226,9 +239,10 @@ VOID PhpRefreshEnvironmentList( { PH_ENVIRONMENT_ITEM item; - // Don't display pairs with no name. - if (variable.Name.Length == 0) - continue; + // Remove the most confusing item. Some say it's just a weird per-drive current directory + // with a colon used as a drive letter for some reason. It should not be here. (diversenok) + //if (PhEqualStringRef2(&variable.Name, L"=::", FALSE)) + // continue; item.Name = PhCreateString2(&variable.Name); item.Value = PhCreateString2(&variable.Value); @@ -244,6 +258,7 @@ VOID PhpRefreshEnvironmentList( for (i = 0; i < Context->Items.Count; i++) { + PPHP_PROCESS_ENVIRONMENT_TREENODE node; PPHP_PROCESS_ENVIRONMENT_TREENODE parentNode; PROCESS_ENVIRONMENT_TREENODE_TYPE nodeType; PPH_STRING variableValue; @@ -304,7 +319,18 @@ VOID PhpRefreshEnvironmentList( parentNode = processRootNode; } - PhpAddEnvironmentChildNode(Context, parentNode, i, nodeType, item->Name, item->Value); + node = PhpAddEnvironmentNode( + Context, + parentNode, + nodeType, + item->Name, + item->Value + ); + + if (item->Name && item->Name->Buffer[0] == L'=') + { + node->IsCmdVariable = TRUE; + } } PhApplyTreeNewFilters(&Context->TreeFilterSupport); @@ -389,6 +415,17 @@ INT_PTR CALLBACK PhpEditEnvDlgProc( HANDLE processHandle; LARGE_INTEGER timeout; + if (PhGetIntegerSetting(L"EnableWarnings") && !PhShowConfirmMessage( + hwndDlg, + L"edit", + L"the selected environment variable", + L"Some programs may restrict access or ban your account when editing the environment variable(s) of the process.", + FALSE + )) + { + break; + } + if (PhIsProcessSuspended(context->ProcessItem->ProcessId)) { if (PhGetIntegerSetting(L"EnableWarnings") && PhShowMessage2( @@ -559,17 +596,6 @@ VOID PhpShowEnvironmentNodeContextMenu( //PPH_ENVIRONMENT_ITEM item = PhItemArray(&Context->Items, node->Id); BOOLEAN refresh; - if (PhGetIntegerSetting(L"EnableWarnings") && !PhShowConfirmMessage( - Context->WindowHandle, - L"edit", - L"the selected environment variable", - L"Some programs may restrict access or ban your account when editing the environment variable(s) of the process.", - FALSE - )) - { - break; - } - if (PhpShowEditEnvDialog( Context->WindowHandle, Context->ProcessItem, @@ -736,6 +762,9 @@ VOID PhSetOptionsEnvironmentList( case ENVIRONMENT_TREE_MENU_ITEM_HIDE_SYSTEM_TYPE: Context->HideSystemEnvironment = !Context->HideSystemEnvironment; break; + case ENVIRONMENT_TREE_MENU_ITEM_HIDE_CMD_TYPE: + Context->HideCmdTypeEnvironment = !Context->HideCmdTypeEnvironment; + break; case ENVIRONMENT_TREE_MENU_ITEM_HIGHLIGHT_PROCESS_TYPE: Context->HighlightProcessEnvironment = !Context->HighlightProcessEnvironment; break; @@ -745,13 +774,16 @@ VOID PhSetOptionsEnvironmentList( case ENVIRONMENT_TREE_MENU_ITEM_HIGHLIGHT_SYSTEM_TYPE: Context->HighlightSystemEnvironment = !Context->HighlightSystemEnvironment; break; + case ENVIRONMENT_TREE_MENU_ITEM_HIGHLIGHT_CMD_TYPE: + Context->HighlightCmdEnvironment = !Context->HighlightCmdEnvironment; + break; } } BOOLEAN PhpEnvironmentNodeHashtableEqualFunction( _In_ PVOID Entry1, _In_ PVOID Entry2 -) + ) { PPHP_PROCESS_ENVIRONMENT_TREENODE poolTagNode1 = *(PPHP_PROCESS_ENVIRONMENT_TREENODE *)Entry1; PPHP_PROCESS_ENVIRONMENT_TREENODE poolTagNode2 = *(PPHP_PROCESS_ENVIRONMENT_TREENODE *)Entry2; @@ -761,14 +793,14 @@ BOOLEAN PhpEnvironmentNodeHashtableEqualFunction( ULONG PhpEnvironmentNodeHashtableHashFunction( _In_ PVOID Entry -) + ) { return PhHashStringRef(&(*(PPHP_PROCESS_ENVIRONMENT_TREENODE*)Entry)->NameText->sr, TRUE); } VOID PhpDestroyEnvironmentNode( _In_ PPHP_PROCESS_ENVIRONMENT_TREENODE Node -) + ) { if (Node->NameText) PhDereferenceObject(Node->NameText); @@ -778,10 +810,11 @@ VOID PhpDestroyEnvironmentNode( PhFree(Node); } -PPHP_PROCESS_ENVIRONMENT_TREENODE PhpAddEnvironmentRootNode( +PPHP_PROCESS_ENVIRONMENT_TREENODE PhpAddEnvironmentNode( _In_ PPH_ENVIRONMENT_CONTEXT Context, + _In_opt_ PPHP_PROCESS_ENVIRONMENT_TREENODE ParentNode, _In_ PROCESS_ENVIRONMENT_TREENODE_TYPE Type, - _In_ PPH_STRING KeyPath, + _In_ PPH_STRING Name, _In_opt_ PPH_STRING Value ) { @@ -795,15 +828,9 @@ PPHP_PROCESS_ENVIRONMENT_TREENODE PhpAddEnvironmentRootNode( node->Node.TextCacheSize = ENVIRONMENT_COLUMN_ITEM_MAXIMUM; node->Children = PhCreateList(1); - PhReferenceObject(KeyPath); node->Type = Type; - node->NameText = KeyPath; - - if (Value) - { - PhReferenceObject(Value); - node->ValueText = Value; - } + PhSetReference(&node->NameText, Name); + if (Value) PhSetReference(&node->ValueText, Value); PhAddEntryHashtable(Context->NodeHashtable, &node); PhAddItemList(Context->NodeList, node); @@ -811,22 +838,6 @@ PPHP_PROCESS_ENVIRONMENT_TREENODE PhpAddEnvironmentRootNode( if (Context->TreeFilterSupport.FilterList) node->Node.Visible = PhApplyTreeNewFiltersToNode(&Context->TreeFilterSupport, &node->Node); - return node; -} - -PPHP_PROCESS_ENVIRONMENT_TREENODE PhpAddEnvironmentChildNode( - _In_ PPH_ENVIRONMENT_CONTEXT Context, - _In_opt_ PPHP_PROCESS_ENVIRONMENT_TREENODE ParentNode, - _In_ ULONG Id, - _In_ PROCESS_ENVIRONMENT_TREENODE_TYPE Type, - _In_ PPH_STRING Name, - _In_opt_ PPH_STRING Value - ) -{ - PPHP_PROCESS_ENVIRONMENT_TREENODE node; - - node = PhpAddEnvironmentRootNode(Context, Type, Name, Value); - if (ParentNode) { node->HasChildren = FALSE; @@ -850,7 +861,7 @@ PPHP_PROCESS_ENVIRONMENT_TREENODE PhpAddEnvironmentChildNode( PPHP_PROCESS_ENVIRONMENT_TREENODE PhpFindEnvironmentNode( _In_ PPH_ENVIRONMENT_CONTEXT Context, _In_ PWSTR KeyPath -) + ) { PHP_PROCESS_ENVIRONMENT_TREENODE lookupWindowNode; PPHP_PROCESS_ENVIRONMENT_TREENODE lookupWindowNodePtr = &lookupWindowNode; @@ -872,7 +883,7 @@ PPHP_PROCESS_ENVIRONMENT_TREENODE PhpFindEnvironmentNode( VOID PhpRemoveEnvironmentNode( _In_ PPH_ENVIRONMENT_CONTEXT Context, _In_ PPHP_PROCESS_ENVIRONMENT_TREENODE Node -) + ) { ULONG index = 0; @@ -1067,7 +1078,9 @@ BOOLEAN NTAPI PhpEnvironmentTreeNewCallback( } else { - if (context->HighlightProcessEnvironment && node->Type == PROCESS_ENVIRONMENT_TREENODE_TYPE_PROCESS) + if (context->HighlightCmdEnvironment && node->IsCmdVariable) + getNodeColor->BackColor = PhCsColorDebuggedProcesses; + else if (context->HighlightProcessEnvironment && node->Type == PROCESS_ENVIRONMENT_TREENODE_TYPE_PROCESS) getNodeColor->BackColor = PhCsColorServiceProcesses; else if (context->HighlightUserEnvironment && node->Type == PROCESS_ENVIRONMENT_TREENODE_TYPE_USER) getNodeColor->BackColor = PhCsColorOwnProcesses; @@ -1248,6 +1261,8 @@ BOOLEAN PhpProcessEnvironmentTreeFilterCallback( return FALSE; if (context->HideSystemEnvironment && environmentNode->Type == PROCESS_ENVIRONMENT_TREENODE_TYPE_SYSTEM) return FALSE; + if (context->HideCmdTypeEnvironment && environmentNode->IsCmdVariable) + return FALSE; if (PhIsNullOrEmptyString(context->SearchboxText)) return TRUE; @@ -1382,9 +1397,11 @@ INT_PTR CALLBACK PhpProcessEnvironmentDlgProc( PPH_EMENU_ITEM processMenuItem; PPH_EMENU_ITEM userMenuItem; PPH_EMENU_ITEM systemMenuItem; + PPH_EMENU_ITEM cmdMenuItem; PPH_EMENU_ITEM highlightProcessMenuItem; PPH_EMENU_ITEM highlightUserMenuItem; PPH_EMENU_ITEM highlightSystemMenuItem; + PPH_EMENU_ITEM highlightCmdMenuItem; PPH_EMENU_ITEM newProcessMenuItem; PPH_EMENU_ITEM selectedItem; @@ -1393,19 +1410,23 @@ INT_PTR CALLBACK PhpProcessEnvironmentDlgProc( processMenuItem = PhCreateEMenuItem(0, ENVIRONMENT_TREE_MENU_ITEM_HIDE_PROCESS_TYPE, L"Hide process", NULL, NULL); userMenuItem = PhCreateEMenuItem(0, ENVIRONMENT_TREE_MENU_ITEM_HIDE_USER_TYPE, L"Hide user", NULL, NULL); systemMenuItem = PhCreateEMenuItem(0, ENVIRONMENT_TREE_MENU_ITEM_HIDE_SYSTEM_TYPE, L"Hide system", NULL, NULL); + cmdMenuItem = PhCreateEMenuItem(0, ENVIRONMENT_TREE_MENU_ITEM_HIDE_CMD_TYPE, L"Hide cmd", NULL, NULL); highlightProcessMenuItem = PhCreateEMenuItem(0, ENVIRONMENT_TREE_MENU_ITEM_HIGHLIGHT_PROCESS_TYPE, L"Highlight process", NULL, NULL); highlightUserMenuItem = PhCreateEMenuItem(0, ENVIRONMENT_TREE_MENU_ITEM_HIGHLIGHT_USER_TYPE, L"Highlight user", NULL, NULL); highlightSystemMenuItem = PhCreateEMenuItem(0, ENVIRONMENT_TREE_MENU_ITEM_HIGHLIGHT_SYSTEM_TYPE, L"Highlight system", NULL, NULL); + highlightCmdMenuItem = PhCreateEMenuItem(0, ENVIRONMENT_TREE_MENU_ITEM_HIGHLIGHT_CMD_TYPE, L"Highlight cmd", NULL, NULL); newProcessMenuItem = PhCreateEMenuItem(0, ENVIRONMENT_TREE_MENU_ITEM_NEW_ENVIRONMENT_VARIABLE, L"New variable...", NULL, NULL); menu = PhCreateEMenu(); PhInsertEMenuItem(menu, processMenuItem, ULONG_MAX); PhInsertEMenuItem(menu, userMenuItem, ULONG_MAX); PhInsertEMenuItem(menu, systemMenuItem, ULONG_MAX); + PhInsertEMenuItem(menu, cmdMenuItem, ULONG_MAX); PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX); PhInsertEMenuItem(menu, highlightProcessMenuItem, ULONG_MAX); PhInsertEMenuItem(menu, highlightUserMenuItem, ULONG_MAX); PhInsertEMenuItem(menu, highlightSystemMenuItem, ULONG_MAX); + PhInsertEMenuItem(menu, highlightCmdMenuItem, ULONG_MAX); PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX); PhInsertEMenuItem(menu, newProcessMenuItem, ULONG_MAX); @@ -1415,12 +1436,16 @@ INT_PTR CALLBACK PhpProcessEnvironmentDlgProc( userMenuItem->Flags |= PH_EMENU_CHECKED; if (context->HideSystemEnvironment) systemMenuItem->Flags |= PH_EMENU_CHECKED; + if (context->HideCmdTypeEnvironment) + cmdMenuItem->Flags |= PH_EMENU_CHECKED; if (context->HighlightProcessEnvironment) highlightProcessMenuItem->Flags |= PH_EMENU_CHECKED; if (context->HighlightUserEnvironment) highlightUserMenuItem->Flags |= PH_EMENU_CHECKED; if (context->HighlightSystemEnvironment) highlightSystemMenuItem->Flags |= PH_EMENU_CHECKED; + if (context->HighlightCmdEnvironment) + highlightCmdMenuItem->Flags |= PH_EMENU_CHECKED; selectedItem = PhShowEMenu( menu, @@ -1437,17 +1462,6 @@ INT_PTR CALLBACK PhpProcessEnvironmentDlgProc( { BOOLEAN refresh; - if (PhGetIntegerSetting(L"EnableWarnings") && !PhShowConfirmMessage( - hwndDlg, - L"create", - L"new environment variable(s)", - L"Some programs may restrict access or ban your account when creating new environment variable(s).", - FALSE - )) - { - break; - } - if (PhpShowEditEnvDialog(hwndDlg, processItem, L"", NULL, &refresh) == IDOK && refresh) { PhpRefreshEnvironmentList(hwndDlg, context, processItem); @@ -1477,17 +1491,6 @@ INT_PTR CALLBACK PhpProcessEnvironmentDlgProc( if (!item || item->Type == PROCESS_ENVIRONMENT_TREENODE_TYPE_GROUP) break; - if (PhGetIntegerSetting(L"EnableWarnings") && !PhShowConfirmMessage( - hwndDlg, - L"edit", - L"the selected environment variable", - L"Some programs may restrict access or ban your account when editing the environment variable(s) of the process.", - FALSE - )) - { - break; - } - if (PhpShowEditEnvDialog( hwndDlg, context->ProcessItem, From e7680a8c5047c40b54b4bea8bbaea83fa734527a Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 1 Feb 2019 21:43:02 +0100 Subject: [PATCH 1624/2058] Add missing header --- ProcessHacker/include/procprpp.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ProcessHacker/include/procprpp.h b/ProcessHacker/include/procprpp.h index 29552546f8ab..26956ce8950d 100644 --- a/ProcessHacker/include/procprpp.h +++ b/ProcessHacker/include/procprpp.h @@ -347,7 +347,9 @@ typedef struct _PH_ENVIRONMENT_CONTEXT ULONG HighlightProcessEnvironment : 1; ULONG HighlightUserEnvironment : 1; ULONG HighlightSystemEnvironment : 1; - ULONG Spare : 25; + ULONG HideCmdTypeEnvironment : 1; + ULONG HighlightCmdEnvironment : 1; + ULONG Spare : 23; }; }; From a647310b4ddbcc971d98b476bdbe8feaaaeef5de Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 1 Feb 2019 21:50:36 +0100 Subject: [PATCH 1625/2058] Improve PhEnumerateKey callback and CapabilitySid lookup --- phlib/include/phnative.h | 1 + phlib/lsasup.c | 215 +++++++++++++++++++++------------------ phlib/native.c | 6 +- phlib/wslsup.c | 1 + 4 files changed, 119 insertions(+), 104 deletions(-) diff --git a/phlib/include/phnative.h b/phlib/include/phnative.h index 8f3c24951718..30b7ce4a7ef6 100644 --- a/phlib/include/phnative.h +++ b/phlib/include/phnative.h @@ -1169,6 +1169,7 @@ PhQueryValueKey( ); typedef BOOLEAN (NTAPI *PPH_ENUM_KEY_CALLBACK)( + _In_ HANDLE RootDirectory, _In_ PKEY_BASIC_INFORMATION Information, _In_opt_ PVOID Context ); diff --git a/phlib/lsasup.c b/phlib/lsasup.c index a412d7fa003e..9807db5751fa 100644 --- a/phlib/lsasup.c +++ b/phlib/lsasup.c @@ -500,10 +500,8 @@ typedef struct _PH_CAPABILITY_ENTRY PSID CapabilitySid; } PH_CAPABILITY_ENTRY, *PPH_CAPABILITY_ENTRY; -PH_ARRAY PhpSidCapArrayList; - VOID PhInitializeCapabilitySidCache( - VOID + _Inout_ PPH_ARRAY CapabilitySidArrayList ) { NTSTATUS (NTAPI *RtlDeriveCapabilitySidsFromName_I)( @@ -532,7 +530,7 @@ VOID PhInitializeCapabilitySidCache( if (PhIsNullOrEmptyString(capabilityListString)) return; - PhInitializeArray(&PhpSidCapArrayList, sizeof(PH_CAPABILITY_ENTRY), 800); + PhInitializeArray(CapabilitySidArrayList, sizeof(PH_CAPABILITY_ENTRY), 800); remainingPart = capabilityListString->sr; while (remainingPart.Length != 0) @@ -565,7 +563,7 @@ VOID PhInitializeCapabilitySidCache( entry.CapabilityGroupSid = PhAllocateCopy(capabilityGroupSid, RtlLengthSid(capabilityGroupSid)); entry.CapabilitySid = PhAllocateCopy(capabilitySid, RtlLengthSid(capabilitySid)); - PhAddItemArray(&PhpSidCapArrayList, &entry); + PhAddItemArray(CapabilitySidArrayList, &entry); } } } @@ -578,21 +576,22 @@ PPH_STRING PhGetCapabilitySidName( ) { static PH_INITONCE initOnce = PH_INITONCE_INIT; + static PH_ARRAY capabilitySidArrayList; PPH_CAPABILITY_ENTRY entry; - ULONG i; + SIZE_T i; if (WindowsVersion < WINDOWS_8) return NULL; if (PhBeginInitOnce(&initOnce)) { - PhInitializeCapabilitySidCache(); + PhInitializeCapabilitySidCache(&capabilitySidArrayList); PhEndInitOnce(&initOnce); } - for (i = 0; i < PhpSidCapArrayList.Count; i++) + for (i = 0; i < capabilitySidArrayList.Count; i++) { - entry = PhItemArray(&PhpSidCapArrayList, i); + entry = PhItemArray(&capabilitySidArrayList, i); if (RtlEqualSid(entry->CapabilitySid, CapabilitySid)) { @@ -614,135 +613,148 @@ typedef struct _PH_CAPABILITY_GUID_ENTRY PPH_STRING CapabilityGuid; } PH_CAPABILITY_GUID_ENTRY, *PPH_CAPABILITY_GUID_ENTRY; -PH_ARRAY PhpCapGuidArrayList; +typedef struct _PH_CAPABILITY_KEY_CALLBACK +{ + PPH_STRING KeyName; + PVOID Context; +} PH_CAPABILITY_KEY_CALLBACK, *PPH_CAPABILITY_KEY_CALLBACK; -BOOLEAN NTAPI PhpTokenEnumerateKeyCallback( +BOOLEAN NTAPI PhpAccessManagerEnumerateKeyCallback( + _In_ HANDLE RootDirectory, _In_ PKEY_BASIC_INFORMATION Information, _In_opt_ PVOID Context ) { - PhAddItemList(Context, PhCreateStringEx(Information->Name, Information->NameLength)); - return TRUE; -} - -VOID PhInitializeCapabilityGuidCache( - VOID - ) -{ - static PH_STRINGREF accessManagerKeyPath = PH_STRINGREF_INIT(L"Software\\Microsoft\\Windows\\CurrentVersion\\CapabilityAccessManager\\Capabilities"); - static PH_STRINGREF deviceAccessKeyPath = PH_STRINGREF_INIT(L"Software\\Microsoft\\Windows\\CurrentVersion\\DeviceAccess\\CapabilityMappings"); HANDLE keyHandle; - ULONG i; + PPH_STRING guidString; + PH_STRINGREF keyName; - PhInitializeArray(&PhpCapGuidArrayList, sizeof(PH_CAPABILITY_GUID_ENTRY), 100); + keyName.Buffer = Information->Name; + keyName.Length = Information->NameLength; if (NT_SUCCESS(PhOpenKey( &keyHandle, KEY_READ, - PH_KEY_LOCAL_MACHINE, - &accessManagerKeyPath, + RootDirectory, + &keyName, 0 ))) { - PPH_LIST capabilityNameList; - - capabilityNameList = PhCreateList(1); - PhEnumerateKey(keyHandle, PhpTokenEnumerateKeyCallback, capabilityNameList); - - for (i = 0; i < capabilityNameList->Count; i++) + if (guidString = PhQueryRegistryString(keyHandle, L"LegacyInterfaceClassGuid")) { - HANDLE subKeyHandle; - PPH_STRING subKeyName; - PPH_STRING guidString; - - subKeyName = capabilityNameList->Items[i]; - - if (NT_SUCCESS(PhOpenKey( - &subKeyHandle, - KEY_READ, - keyHandle, - &subKeyName->sr, - 0 - ))) - { - if (guidString = PhQueryRegistryString(subKeyHandle, L"LegacyInterfaceClassGuid")) - { - PH_CAPABILITY_GUID_ENTRY entry; + PH_CAPABILITY_GUID_ENTRY entry; - PhSetReference(&entry.Name, subKeyName); - PhSetReference(&entry.CapabilityGuid, guidString); - PhAddItemArray(&PhpCapGuidArrayList, &entry); + PhSetReference(&entry.Name, PhCreateString2(&keyName)); + PhSetReference(&entry.CapabilityGuid, guidString); + PhAddItemArray(Context, &entry); - PhDereferenceObject(guidString); - } - - NtClose(subKeyHandle); - } + PhDereferenceObject(guidString); } - PhDereferenceObjects(capabilityNameList->Items, capabilityNameList->Count); - PhDereferenceObject(capabilityNameList); - NtClose(keyHandle); } + return TRUE; +} + +BOOLEAN NTAPI PhpDeviceAccessSubKeyEnumerateKeyCallback( + _In_ HANDLE RootDirectory, + _In_ PKEY_BASIC_INFORMATION Information, + _In_opt_ PVOID Context + ) +{ + PPH_CAPABILITY_KEY_CALLBACK context = Context; + HANDLE keyHandle; + PH_STRINGREF keyName; + + keyName.Buffer = Information->Name; + keyName.Length = Information->NameLength; + if (NT_SUCCESS(PhOpenKey( &keyHandle, KEY_READ, - PH_KEY_LOCAL_MACHINE, - &deviceAccessKeyPath, + RootDirectory, + &keyName, 0 ))) { - PPH_LIST capabilityNameList; + PH_CAPABILITY_GUID_ENTRY entry; - capabilityNameList = PhCreateList(1); - PhEnumerateKey(keyHandle, PhpTokenEnumerateKeyCallback, capabilityNameList); + PhSetReference(&entry.Name, context->KeyName); + PhSetReference(&entry.CapabilityGuid, PhCreateString2(&keyName)); + PhAddItemArray(context->Context, &entry); - for (i = 0; i < capabilityNameList->Count; i++) - { - HANDLE subKeyHandle; - PPH_STRING subKeyName; + NtClose(keyHandle); + } - subKeyName = capabilityNameList->Items[i]; + return TRUE; +} - if (NT_SUCCESS(PhOpenKey( - &subKeyHandle, - KEY_READ, - keyHandle, - &subKeyName->sr, - 0 - ))) - { - PPH_LIST capabilityGuidList; - ULONG ii; +BOOLEAN NTAPI PhpDeviceAccessEnumerateKeyCallback( + _In_ HANDLE RootDirectory, + _In_ PKEY_BASIC_INFORMATION Information, + _In_opt_ PVOID Context + ) +{ + HANDLE keyHandle; + PH_STRINGREF keyName; - capabilityGuidList = PhCreateList(1); - PhEnumerateKey(subKeyHandle, PhpTokenEnumerateKeyCallback, capabilityGuidList); + keyName.Buffer = Information->Name; + keyName.Length = Information->NameLength; - for (ii = 0; ii < capabilityGuidList->Count; ii++) - { - PPH_STRING guidString; - PH_CAPABILITY_GUID_ENTRY entry; + if (NT_SUCCESS(PhOpenKey( + &keyHandle, + KEY_READ, + RootDirectory, + &keyName, + 0 + ))) + { + PH_CAPABILITY_KEY_CALLBACK entry; - guidString = capabilityGuidList->Items[ii]; + entry.KeyName = PhCreateString2(&keyName); + entry.Context = Context; - PhSetReference(&entry.Name, subKeyName); - PhSetReference(&entry.CapabilityGuid, guidString); + PhEnumerateKey(keyHandle, PhpDeviceAccessSubKeyEnumerateKeyCallback, &entry); - PhAddItemArray(&PhpCapGuidArrayList, &entry); - } + PhDereferenceObject(entry.KeyName); + NtClose(keyHandle); + } - PhDereferenceObjects(capabilityGuidList->Items, capabilityGuidList->Count); - PhDereferenceObject(capabilityGuidList); + return TRUE; +} - NtClose(subKeyHandle); - } - } +VOID PhInitializeCapabilityGuidCache( + _Inout_ PPH_ARRAY CapabilityGuidArrayList + ) +{ + static PH_STRINGREF accessManagerKeyPath = PH_STRINGREF_INIT(L"Software\\Microsoft\\Windows\\CurrentVersion\\CapabilityAccessManager\\Capabilities"); + static PH_STRINGREF deviceAccessKeyPath = PH_STRINGREF_INIT(L"Software\\Microsoft\\Windows\\CurrentVersion\\DeviceAccess\\CapabilityMappings"); + HANDLE keyHandle; - PhDereferenceObjects(capabilityNameList->Items, capabilityNameList->Count); - PhDereferenceObject(capabilityNameList); + PhInitializeArray(CapabilityGuidArrayList, sizeof(PH_CAPABILITY_GUID_ENTRY), 100); + if (NT_SUCCESS(PhOpenKey( + &keyHandle, + KEY_READ, + PH_KEY_LOCAL_MACHINE, + &accessManagerKeyPath, + 0 + ))) + { + PhEnumerateKey(keyHandle, PhpAccessManagerEnumerateKeyCallback, CapabilityGuidArrayList); + NtClose(keyHandle); + } + + if (NT_SUCCESS(PhOpenKey( + &keyHandle, + KEY_READ, + PH_KEY_LOCAL_MACHINE, + &deviceAccessKeyPath, + 0 + ))) + { + PhEnumerateKey(keyHandle, PhpDeviceAccessEnumerateKeyCallback, CapabilityGuidArrayList); NtClose(keyHandle); } } @@ -752,21 +764,22 @@ PPH_STRING PhGetCapabilityGuidName( ) { static PH_INITONCE initOnce = PH_INITONCE_INIT; + static PH_ARRAY capabilityGuidArrayList; PPH_CAPABILITY_GUID_ENTRY entry; - ULONG i; + SIZE_T i; if (WindowsVersion < WINDOWS_8) return NULL; if (PhBeginInitOnce(&initOnce)) { - PhInitializeCapabilityGuidCache(); + PhInitializeCapabilityGuidCache(&capabilityGuidArrayList); PhEndInitOnce(&initOnce); } - for (i = 0; i < PhpCapGuidArrayList.Count; i++) + for (i = 0; i < capabilityGuidArrayList.Count; i++) { - entry = PhItemArray(&PhpCapGuidArrayList, i); + entry = PhItemArray(&capabilityGuidArrayList, i); if (PhEqualString(entry->CapabilityGuid, GuidString, TRUE)) { diff --git a/phlib/native.c b/phlib/native.c index a826bac8dfa2..d9caddc479d5 100644 --- a/phlib/native.c +++ b/phlib/native.c @@ -6853,7 +6853,7 @@ NTSTATUS PhEnumerateKey( bufferSize = 0x100; buffer = PhAllocate(bufferSize); - while (TRUE) + do { status = NtEnumerateKey( KeyHandle, @@ -6888,11 +6888,11 @@ NTSTATUS PhEnumerateKey( if (!NT_SUCCESS(status)) break; - if (!Callback(buffer, Context)) + if (!Callback(KeyHandle, buffer, Context)) break; index++; - } + } while (TRUE); PhFree(buffer); diff --git a/phlib/wslsup.c b/phlib/wslsup.c index 06953b8e0363..a1e557316492 100644 --- a/phlib/wslsup.c +++ b/phlib/wslsup.c @@ -24,6 +24,7 @@ #include BOOLEAN NTAPI PhpWslDistributionNamesCallback( + _In_ HANDLE RootDirectory, _In_ PKEY_BASIC_INFORMATION Information, _In_opt_ PVOID Context ) From 2db562a34e099acd798d50875e9613a240f17c5c Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 1 Feb 2019 21:50:56 +0100 Subject: [PATCH 1626/2058] Add PhIsPackageCapabilitySid --- phlib/appresolver.c | 22 ++++++++++++++++++++++ phlib/include/appresolver.h | 5 +++++ 2 files changed, 27 insertions(+) diff --git a/phlib/appresolver.c b/phlib/appresolver.c index 7c8267bf560e..a700532fed89 100644 --- a/phlib/appresolver.c +++ b/phlib/appresolver.c @@ -398,6 +398,28 @@ PPH_STRING PhGetProcessPackageFullName( return packageName; } +BOOLEAN PhIsPackageCapabilitySid( + _In_ PSID AppContainerSid, + _In_ PSID Sid + ) +{ + BOOLEAN isPackageCapability = TRUE; + + for (ULONG i = 1; i < SECURITY_APP_PACKAGE_RID_COUNT - 1; i++) + { + if ( + *RtlSubAuthoritySid(AppContainerSid, i) != + *RtlSubAuthoritySid(Sid, i) + ) + { + isPackageCapability = FALSE; + break; + } + } + + return isPackageCapability; +} + BOOLEAN PhGetAppWindowingModel( _In_ HANDLE ProcessTokenHandle, _Out_ AppPolicyWindowingModel *ProcessWindowingModelPolicy diff --git a/phlib/include/appresolver.h b/phlib/include/appresolver.h index 70633f905b5c..d61188f1c85d 100644 --- a/phlib/include/appresolver.h +++ b/phlib/include/appresolver.h @@ -59,6 +59,11 @@ PPH_STRING PhGetProcessPackageFullName( _In_ HANDLE ProcessHandle ); +BOOLEAN PhIsPackageCapabilitySid( + _In_ PSID AppContainerSid, + _In_ PSID Sid + ); + PPH_STRING PhGetPackagePath( _In_ PPH_STRING PackageFullName ); From ea407b3d3633df9ba717c68f4cfbbcbe7145cd53 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 1 Feb 2019 21:51:47 +0100 Subject: [PATCH 1627/2058] Update macro usage --- ProcessHacker/dbgcon.c | 6 +----- ProcessHacker/findobj.c | 4 +--- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/ProcessHacker/dbgcon.c b/ProcessHacker/dbgcon.c index fb3ab9c3d56c..de27117ce759 100644 --- a/ProcessHacker/dbgcon.c +++ b/ProcessHacker/dbgcon.c @@ -366,11 +366,7 @@ static VOID PhpDeleteNewObjectList( { if (NewObjectList) { - ULONG i; - - for (i = 0; i < NewObjectList->Count; i++) - PhDereferenceObject(NewObjectList->Items[i]); - + PhDereferenceObjects(NewObjectList->Items, NewObjectList->Count); PhDereferenceObject(NewObjectList); NewObjectList = NULL; } diff --git a/ProcessHacker/findobj.c b/ProcessHacker/findobj.c index ab56e38afba4..c9d86d3f2fec 100644 --- a/ProcessHacker/findobj.c +++ b/ProcessHacker/findobj.c @@ -848,9 +848,7 @@ static NTSTATUS NTAPI SearchHandleFunction( { PPHP_OBJECT_SEARCH_RESULT searchResult; - searchResult = PhAllocate(sizeof(PHP_OBJECT_SEARCH_RESULT)); - memset(searchResult, 0, sizeof(PHP_OBJECT_SEARCH_RESULT)); - + searchResult = PhAllocateZero(sizeof(PHP_OBJECT_SEARCH_RESULT)); searchResult->ProcessId = (HANDLE)handleContext->HandleInfo->UniqueProcessId; searchResult->ResultType = HandleSearchResult; searchResult->Object = handleContext->HandleInfo->Object; From 3eadbaee705bd8bbaad7e2c3a2d5307c54a64a82 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 1 Feb 2019 21:52:41 +0100 Subject: [PATCH 1628/2058] Fix find window/handle properties not showing when topmost --- ProcessHacker/findobj.c | 4 ++++ ProcessHacker/hndlprp.c | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/ProcessHacker/findobj.c b/ProcessHacker/findobj.c index c9d86d3f2fec..7551d9fcfb1e 100644 --- a/ProcessHacker/findobj.c +++ b/ProcessHacker/findobj.c @@ -1171,6 +1171,8 @@ INT_PTR CALLBACK PhpFindObjectsDlgProc( else PhCenterWindow(hwndDlg, PhMainWndHandle); + PhRegisterWindowCallback(hwndDlg, PH_PLUGIN_WINDOW_EVENT_TYPE_TOPMOST, NULL); + context->SearchResults = PhCreateList(128); context->SearchResultsAddIndex = 0; @@ -1234,6 +1236,8 @@ INT_PTR CALLBACK PhpFindObjectsDlgProc( PhSetIntegerSetting(L"FindObjRegex", Button_GetCheck(GetDlgItem(hwndDlg, IDC_REGEX)) == BST_CHECKED); PhSaveWindowPlacementToSetting(L"FindObjWindowPosition", L"FindObjWindowSize", hwndDlg); + PhUnregisterWindowCallback(hwndDlg); + PhDeleteLayoutManager(&context->LayoutManager); PhpDeleteHandleObjectTree(context); diff --git a/ProcessHacker/hndlprp.c b/ProcessHacker/hndlprp.c index d67fb3e061d3..e38df6a530c8 100644 --- a/ProcessHacker/hndlprp.c +++ b/ProcessHacker/hndlprp.c @@ -1094,6 +1094,8 @@ INT_PTR CALLBACK PhpHandleGeneralDlgProc( PhpUpdateHandleGeneralListViewGroups(context); PhpUpdateHandleGeneral(context); + PhRegisterWindowCallback(GetParent(hwndDlg), PH_PLUGIN_WINDOW_EVENT_TYPE_TOPMOST, NULL); + if (PhEnableThemeSupport) // TODO: Required for compat (dmex) PhInitializeWindowTheme(GetParent(hwndDlg), PhEnableThemeSupport); else @@ -1102,6 +1104,8 @@ INT_PTR CALLBACK PhpHandleGeneralDlgProc( break; case WM_DESTROY: { + PhUnregisterWindowCallback(GetParent(hwndDlg)); + PhSaveWindowPlacementToSetting(L"HandlePropertiesWindowPosition", NULL, GetParent(hwndDlg)); // HACK PhDeleteLayoutManager(&context->LayoutManager); From 558821cb96756abb95e3aa02b9e068dc6aa5da70 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 1 Feb 2019 21:53:08 +0100 Subject: [PATCH 1629/2058] Remove duplicate topmost --- ProcessHacker/sysinfo.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/ProcessHacker/sysinfo.c b/ProcessHacker/sysinfo.c index 7c0253af6292..6d27ffd48b15 100644 --- a/ProcessHacker/sysinfo.c +++ b/ProcessHacker/sysinfo.c @@ -463,8 +463,6 @@ VOID PhSipOnInitDialog( PhSipEnterSectionView(section); } - if (PhGetIntegerSetting(L"MainWindowAlwaysOnTop")) - PhSetWindowAlwaysOnTop(PhSipWindow, TRUE); PhRegisterWindowCallback(PhSipWindow, PH_PLUGIN_WINDOW_EVENT_TYPE_TOPMOST, NULL); PhSipOnSize(); From e73aa9a5e0a88a7e9d3d333f424e97900f52e126 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 1 Feb 2019 22:59:08 +0100 Subject: [PATCH 1630/2058] NetworkTools: Fix relative db paths --- plugins/NetworkTools/country.c | 38 +++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/plugins/NetworkTools/country.c b/plugins/NetworkTools/country.c index e8611b915e23..f4ba9e28b469 100644 --- a/plugins/NetworkTools/country.c +++ b/plugins/NetworkTools/country.c @@ -29,13 +29,49 @@ BOOLEAN GeoDbExpired = FALSE; HIMAGELIST GeoImageList = NULL; static MMDB_s GeoDb = { 0 }; +PPH_STRING NetToolsGetGeoLiteDbPath( + VOID + ) +{ + PPH_STRING databaseFile; + PPH_STRING directory; + PPH_STRING path; + + if (!(databaseFile = PhGetExpandStringSetting(SETTING_NAME_DB_LOCATION))) + return NULL; + + PhMoveReference(&databaseFile, PhGetBaseName(databaseFile)); + directory = PH_AUTO(PhGetApplicationDirectory()); + path = PH_AUTO(PhConcatStringRef2(&directory->sr, &databaseFile->sr)); + + if (RtlDoesFileExists_U(path->Buffer)) + { + return PhReferenceObject(path); + } + else + { + path = PhaGetStringSetting(SETTING_NAME_DB_LOCATION); + path = PH_AUTO(PhExpandEnvironmentStrings(&path->sr)); + + if (RtlDetermineDosPathNameType_U(path->Buffer) == RtlPathTypeRelative) + { + directory = PH_AUTO(PhGetApplicationDirectory()); + path = PH_AUTO(PhConcatStringRef2(&directory->sr, &path->sr)); + } + + return PhReferenceObject(path); + } + + return NULL; +} + VOID LoadGeoLiteDb( VOID ) { PPH_STRING dbpath; - dbpath = PhGetExpandStringSetting(SETTING_NAME_DB_LOCATION); + dbpath = NetToolsGetGeoLiteDbPath(); if (PhIsNullOrEmptyString(dbpath)) return; From 2e37fb2f067fdf1634ddcb0048a1ec4416fbd0fa Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 1 Feb 2019 22:59:59 +0100 Subject: [PATCH 1631/2058] Remove spaces --- plugins/DotNetTools/perfpage.c | 3 +-- plugins/HardwareDevices/diskdetails.c | 2 -- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/plugins/DotNetTools/perfpage.c b/plugins/DotNetTools/perfpage.c index bcba2179e3cb..128030e9b643 100644 --- a/plugins/DotNetTools/perfpage.c +++ b/plugins/DotNetTools/perfpage.c @@ -1834,7 +1834,6 @@ INT_PTR CALLBACK DotNetPerfPageDlgProc( if (numberOfItems != 0) { menu = PhCreateEMenu(); - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_CLR_COPY, L"&Copy", NULL, NULL), ULONG_MAX); PhInsertCopyListViewEMenuItem(menu, ID_CLR_COPY, listViewHandle); @@ -1845,7 +1844,7 @@ INT_PTR CALLBACK DotNetPerfPageDlgProc( PH_ALIGN_LEFT | PH_ALIGN_TOP, point.x, point.y - ); + ); if (item) { diff --git a/plugins/HardwareDevices/diskdetails.c b/plugins/HardwareDevices/diskdetails.c index 23472e632ec8..24551f71c568 100644 --- a/plugins/HardwareDevices/diskdetails.c +++ b/plugins/HardwareDevices/diskdetails.c @@ -664,7 +664,6 @@ INT_PTR CALLBACK DiskDriveFileSystemDetailsDlgProc( if (numberOfItems != 0) { menu = PhCreateEMenu(); - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, PHAPP_IDC_COPY, L"&Copy", NULL, NULL), ULONG_MAX); PhInsertCopyListViewEMenuItem(menu, PHAPP_IDC_COPY, context->ListViewHandle); @@ -804,7 +803,6 @@ INT_PTR CALLBACK DiskDriveSmartDetailsDlgProc( if (numberOfItems != 0) { menu = PhCreateEMenu(); - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, PHAPP_IDC_COPY, L"&Copy", NULL, NULL), ULONG_MAX); PhInsertCopyListViewEMenuItem(menu, PHAPP_IDC_COPY, context->ListViewHandle); From f84c0e7be0c23ae4867ceb776c2a0cbe9a7cafc7 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 1 Feb 2019 23:01:17 +0100 Subject: [PATCH 1632/2058] Fix macro usage --- ProcessHacker/tokprp.c | 18 +++--------------- phlib/ref.c | 2 +- 2 files changed, 4 insertions(+), 16 deletions(-) diff --git a/ProcessHacker/tokprp.c b/ProcessHacker/tokprp.c index b5d463f2478a..8b4c481314f7 100644 --- a/ProcessHacker/tokprp.c +++ b/ProcessHacker/tokprp.c @@ -743,6 +743,8 @@ INT_PTR CALLBACK PhpTokenPageProc( PPH_STRING appContainerName; PPH_STRING appContainerSid; + // TOKEN_BNO_ISOLATION_INFORMATION + if (NT_SUCCESS(PhGetTokenUser(tokenHandle, &tokenUser))) { if (fullUserName = PhGetSidFullName(tokenUser->User.Sid, TRUE, NULL)) @@ -1986,21 +1988,7 @@ INT_PTR CALLBACK PhpTokenCapabilitiesPageProc( { if (appContainerInfo->TokenAppContainer) { - BOOLEAN isPackageCapability = TRUE; - - for (ULONG ii = 1; ii < subAuthoritiesCount - 1; ii++) - { - if ( - *RtlSubAuthoritySid(appContainerInfo->TokenAppContainer, ii) != - *RtlSubAuthoritySid(tokenPageContext->Capabilities->Groups[i].Sid, ii) - ) - { - isPackageCapability = FALSE; - break; - } - } - - if (isPackageCapability) + if (PhIsPackageCapabilitySid(appContainerInfo->TokenAppContainer, tokenPageContext->Capabilities->Groups[i].Sid)) { HANDLE processHandle; diff --git a/phlib/ref.c b/phlib/ref.c index 03ba320ed0ad..c14cc3614b24 100644 --- a/phlib/ref.c +++ b/phlib/ref.c @@ -242,7 +242,7 @@ VOID PhDereferenceObject( // Decrement the reference count. newRefCount = _InterlockedDecrement(&objectHeader->RefCount); ASSUME_ASSERT(newRefCount >= 0); - assert(!(newRefCount < 0)); + ASSUME_ASSERT(!(newRefCount < 0)); // Free the object if it has 0 references. if (newRefCount == 0) From 5dbf44baa1283cf90dda022beb4e5718193e5f6c Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 1 Feb 2019 23:01:56 +0100 Subject: [PATCH 1633/2058] Add missing context --- phlib/include/seceditp.h | 3 +-- phlib/secedit.c | 2 ++ 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/phlib/include/seceditp.h b/phlib/include/seceditp.h index 84982aec14f5..7aaf0de070ad 100644 --- a/phlib/include/seceditp.h +++ b/phlib/include/seceditp.h @@ -43,11 +43,10 @@ typedef struct { IDataObjectVtbl *VTable; + PhSecurityInformation *Context; ULONG RefCount; - ULONG SidCount; PSID *Sids; - PPH_LIST NameCache; } PhSecurityIDataObject; diff --git a/phlib/secedit.c b/phlib/secedit.c index 5d9d7f4c2505..0be5a0975882 100644 --- a/phlib/secedit.c +++ b/phlib/secedit.c @@ -495,10 +495,12 @@ HRESULT STDMETHODCALLTYPE PhSecurityInformation2_LookupSids( _Out_ LPDATAOBJECT *ppdo ) { + PhSecurityInformation2 *this = (PhSecurityInformation2 *)This; PhSecurityIDataObject *dataObject; dataObject = PhAllocateZero(sizeof(PhSecurityInformation)); dataObject->VTable = &PhDataObject_VTable; + dataObject->Context = this->Context; dataObject->RefCount = 1; dataObject->SidCount = cSids; From a0258eb86189acea52b2736a4e5fe70426972317 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 8 Feb 2019 00:13:56 +0100 Subject: [PATCH 1634/2058] Updater: Fix updater window not showing when topmost --- plugins/Updater/updater.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/plugins/Updater/updater.c b/plugins/Updater/updater.c index c458b4c64104..c5608851a44e 100644 --- a/plugins/Updater/updater.c +++ b/plugins/Updater/updater.c @@ -776,6 +776,8 @@ LRESULT CALLBACK TaskDialogSubclassProc( { SetWindowLongPtr(hwndDlg, GWLP_WNDPROC, (LONG_PTR)oldWndProc); PhRemoveWindowContext(hwndDlg, UCHAR_MAX); + + PhUnregisterWindowCallback(hwndDlg); } break; case PH_SHOWDIALOG: @@ -855,6 +857,8 @@ HRESULT CALLBACK TaskDialogBootstrapCallback( // Create the Taskdialog icons. TaskDialogCreateIcons(context); + PhRegisterWindowCallback(hwndDlg, PH_PLUGIN_WINDOW_EVENT_TYPE_TOPMOST, NULL); + // Subclass the Taskdialog. context->DefaultWindowProc = (WNDPROC)GetWindowLongPtr(hwndDlg, GWLP_WNDPROC); PhSetWindowContext(hwndDlg, UCHAR_MAX, context); From 717dac4332e3c409b34e5098a17ab9c072eb6533 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 8 Feb 2019 00:14:20 +0100 Subject: [PATCH 1635/2058] Update error message format --- ProcessHacker/anawait.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ProcessHacker/anawait.c b/ProcessHacker/anawait.c index f53a012e01f5..815742f042b0 100644 --- a/ProcessHacker/anawait.c +++ b/ProcessHacker/anawait.c @@ -175,7 +175,7 @@ VOID PhUiAnalyzeWaitThread( } else { - PhShowInformation(hWnd, L"The thread does not appear to be waiting."); + PhShowInformation2(hWnd, L"The thread does not appear to be waiting.", L""); } PhDeleteStringBuilder(&context.StringBuilder); From 29d09bd5498a059e5e28a16a66f5ad40d1d4036b Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 8 Feb 2019 00:15:31 +0100 Subject: [PATCH 1636/2058] NetworkTools: Fix geolite db path, Fix tracert error messages, Fix ipv6 ping error handling --- plugins/NetworkTools/NetworkTools.rc | 24 ------------------------ plugins/NetworkTools/nettools.h | 14 +++++++++++--- plugins/NetworkTools/ping.c | 4 ++-- plugins/NetworkTools/tracert.c | 17 +++++++++++------ plugins/NetworkTools/tracert.h | 7 ++++++- plugins/NetworkTools/tracetree.c | 5 ++++- plugins/NetworkTools/update.c | 4 ++-- 7 files changed, 36 insertions(+), 39 deletions(-) diff --git a/plugins/NetworkTools/NetworkTools.rc b/plugins/NetworkTools/NetworkTools.rc index 2210087b200d..af7943c956f7 100644 --- a/plugins/NetworkTools/NetworkTools.rc +++ b/plugins/NetworkTools/NetworkTools.rc @@ -684,30 +684,6 @@ END #endif // APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// AFX_DIALOG_LAYOUT -// - -IDD_WHOIS AFX_DIALOG_LAYOUT -BEGIN - 0 -END - -IDD_OPTIONS AFX_DIALOG_LAYOUT -BEGIN - 0 -END - -IDD_TRACERT AFX_DIALOG_LAYOUT -BEGIN - 0 -END - -IDD_PING AFX_DIALOG_LAYOUT -BEGIN - 0 -END #endif // English (Australia) resources ///////////////////////////////////////////////////////////////////////////// diff --git a/plugins/NetworkTools/nettools.h b/plugins/NetworkTools/nettools.h index 2cea48acc746..8795746a2a4b 100644 --- a/plugins/NetworkTools/nettools.h +++ b/plugins/NetworkTools/nettools.h @@ -253,8 +253,16 @@ typedef enum _NETWORK_COLUMN_ID } NETWORK_COLUMN_ID; // country.c -VOID LoadGeoLiteDb(VOID); -VOID FreeGeoLiteDb(VOID); + +PPH_STRING NetToolsGetGeoLiteDbPath( + VOID + ); +VOID LoadGeoLiteDb( + VOID + ); +VOID FreeGeoLiteDb( + VOID + ); BOOLEAN LookupCountryCode( _In_ PH_IP_ADDRESS RemoteAddress, @@ -334,4 +342,4 @@ typedef struct _RESOLVED_PORT RESOLVED_PORT ResolvedPortsTable[6265]; -#endif \ No newline at end of file +#endif diff --git a/plugins/NetworkTools/ping.c b/plugins/NetworkTools/ping.c index d0d722780921..633f613086ba 100644 --- a/plugins/NetworkTools/ping.c +++ b/plugins/NetworkTools/ping.c @@ -100,7 +100,7 @@ NTSTATUS NetworkPingThreadStart( icmp6ReplyStruct = (PICMPV6_ECHO_REPLY2)icmpReplyBuffer; - if (icmp6ReplyStruct->Status == IP_SUCCESS) + if (icmpReplyCount > 0 && icmp6ReplyStruct->Status == IP_SUCCESS) { BOOLEAN icmpPacketSignature = FALSE; @@ -173,7 +173,7 @@ NTSTATUS NetworkPingThreadStart( icmpReplyStruct = (PICMP_ECHO_REPLY)icmpReplyBuffer; - if (icmpReplyStruct->Status == IP_SUCCESS) + if (icmpReplyCount > 0 && icmpReplyStruct->Status == IP_SUCCESS) { if (icmpReplyStruct->Address != context->RemoteEndpoint.Address.InAddr.s_addr) { diff --git a/plugins/NetworkTools/tracert.c b/plugins/NetworkTools/tracert.c index df92a503dc60..95faab401753 100644 --- a/plugins/NetworkTools/tracert.c +++ b/plugins/NetworkTools/tracert.c @@ -257,6 +257,7 @@ NTSTATUS NetworkTracertThreadStart( HANDLE icmpHandle = INVALID_HANDLE_VALUE; SOCKADDR_STORAGE sourceAddress = { 0 }; SOCKADDR_STORAGE destinationAddress = { 0 }; + ULONG icmpReplyCount = 0; ULONG icmpReplyLength = 0; PVOID icmpReplyBuffer = NULL; PPH_BYTES icmpEchoBuffer = NULL; @@ -331,7 +332,7 @@ NTSTATUS NetworkTracertThreadStart( icmpReplyBuffer = PhAllocate(icmpReplyLength); memset(icmpReplyBuffer, 0, icmpReplyLength); - if (IcmpSendEcho2Ex( + icmpReplyCount = IcmpSendEcho2Ex( icmpHandle, 0, NULL, @@ -344,7 +345,9 @@ NTSTATUS NetworkTracertThreadStart( icmpReplyBuffer, icmpReplyLength, DEFAULT_TIMEOUT - )) + ); + + if (icmpReplyCount > 0) { PICMP_ECHO_REPLY reply4 = (PICMP_ECHO_REPLY)icmpReplyBuffer; @@ -377,7 +380,7 @@ NTSTATUS NetworkTracertThreadStart( } else { - node->PingStatus[ii] = IP_REQ_TIMED_OUT; + node->PingStatus[ii] = GetLastError(); // IP_REQ_TIMED_OUT; UpdateTracertNode(context, node); } @@ -389,7 +392,7 @@ NTSTATUS NetworkTracertThreadStart( icmpReplyBuffer = PhAllocate(icmpReplyLength); memset(icmpReplyBuffer, 0, icmpReplyLength); - if (Icmp6SendEcho2( + icmpReplyCount = Icmp6SendEcho2( icmpHandle, 0, NULL, @@ -402,7 +405,9 @@ NTSTATUS NetworkTracertThreadStart( icmpReplyBuffer, icmpReplyLength, DEFAULT_TIMEOUT - )) + ); + + if (icmpReplyCount > 0) { PICMPV6_ECHO_REPLY reply6 = (PICMPV6_ECHO_REPLY)icmpReplyBuffer; @@ -428,7 +433,7 @@ NTSTATUS NetworkTracertThreadStart( } else { - node->PingStatus[ii] = IP_REQ_TIMED_OUT; + node->PingStatus[ii] = GetLastError(); // IP_REQ_TIMED_OUT; UpdateTracertNode(context, node); } diff --git a/plugins/NetworkTools/tracert.h b/plugins/NetworkTools/tracert.h index 980a916108d8..c73913b2c381 100644 --- a/plugins/NetworkTools/tracert.h +++ b/plugins/NetworkTools/tracert.h @@ -52,6 +52,7 @@ typedef struct _TRACERT_ROOT_NODE ULONG PingStatus[DEFAULT_MAXIMUM_PINGS]; ULONG PingList[DEFAULT_MAXIMUM_PINGS]; PPH_STRING PingString[DEFAULT_MAXIMUM_PINGS]; + PPH_STRING PingMessage[DEFAULT_MAXIMUM_PINGS]; INT CountryIconIndex; PPH_STRING TtlString; @@ -109,4 +110,8 @@ PTRACERT_ROOT_NODE GetSelectedTracertNode( _In_ PNETWORK_TRACERT_CONTEXT Context ); -#endif \ No newline at end of file +PPH_STRING TracertGetErrorMessage( + _In_ IP_STATUS Result + ); + +#endif diff --git a/plugins/NetworkTools/tracetree.c b/plugins/NetworkTools/tracetree.c index 9c92c0bb80b0..002147ff504c 100644 --- a/plugins/NetworkTools/tracetree.c +++ b/plugins/NetworkTools/tracetree.c @@ -48,6 +48,8 @@ VOID NTAPI TracertTreeNodeItemDeleteProcedure( { if (tracertNode->PingString[i]) PhDereferenceObject(tracertNode->PingString[i]); + if (tracertNode->PingMessage[i]) + PhDereferenceObject(tracertNode->PingMessage[i]); } } @@ -298,7 +300,8 @@ VOID UpdateTracertNodePingText( } else { - PhInitializeEmptyStringRef(&CellText->Text); + Node->PingMessage[Index] = TracertGetErrorMessage(Node->PingStatus[Index]); + CellText->Text = PhGetStringRef(Node->PingMessage[Index]); } } diff --git a/plugins/NetworkTools/update.c b/plugins/NetworkTools/update.c index fca4731661d3..d2d2b5bee767 100644 --- a/plugins/NetworkTools/update.c +++ b/plugins/NetworkTools/update.c @@ -372,7 +372,7 @@ NTSTATUS GeoIPUpdateThread( } { - dbpath = PhGetExpandStringSetting(SETTING_NAME_DB_LOCATION); + dbpath = NetToolsGetGeoLiteDbPath(); if (PhIsNullOrEmptyString(dbpath)) goto CleanupExit; @@ -390,7 +390,7 @@ NTSTATUS GeoIPUpdateThread( // Create the directory if it does not exist. if (fullPath = PhGetFullPath(dbpath->Buffer, &indexOfFileName)) { - if (indexOfFileName != -1) + if (indexOfFileName != ULONG_MAX) PhCreateDirectory(PhaSubstring(fullPath, 0, indexOfFileName)); PhDereferenceObject(fullPath); From 0be7abed9ebe43dc1ea33dd0e489ca9eba735080 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 8 Feb 2019 00:15:58 +0100 Subject: [PATCH 1637/2058] Add RtlCreateUserProcessEx #373 --- phnt/include/ntrtl.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/phnt/include/ntrtl.h b/phnt/include/ntrtl.h index fd9bf57340b6..3ee1381be445 100644 --- a/phnt/include/ntrtl.h +++ b/phnt/include/ntrtl.h @@ -2638,6 +2638,17 @@ RtlCreateUserProcess( _Out_ PRTL_USER_PROCESS_INFORMATION ProcessInformation ); +NTSYSAPI +NTSTATUS +NTAPI +RtlCreateUserProcessEx( + _In_ PUNICODE_STRING NtImagePathName, + _In_ PRTL_USER_PROCESS_PARAMETERS ProcessParameters, + _In_ BOOLEAN InheritHandles, + _Reserved_ ULONG Flags, + _Out_ PRTL_USER_PROCESS_INFORMATION ProcessInformation + ); + #if (PHNT_VERSION >= PHNT_VISTA) DECLSPEC_NORETURN NTSYSAPI From 20e9d2ee571b13d579c114c60fa2dd882e0ac587 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 8 Feb 2019 00:33:12 +0100 Subject: [PATCH 1638/2058] Remove dpkg-query filename lookup --- phlib/wslsup.c | 43 +++++++++++++++++++++++++++++++------------ 1 file changed, 31 insertions(+), 12 deletions(-) diff --git a/phlib/wslsup.c b/phlib/wslsup.c index a1e557316492..27e388f53bca 100644 --- a/phlib/wslsup.c +++ b/phlib/wslsup.c @@ -33,8 +33,9 @@ BOOLEAN NTAPI PhpWslDistributionNamesCallback( return TRUE; } -PPH_STRING PhGetWslDistributionFromPath( +BOOLEAN PhGetWslDistributionFromPath( _In_ PPH_STRING FileName, + _Out_opt_ PPH_STRING *LxssDistroName, _Out_opt_ PPH_STRING *LxssDistroPath, _Out_opt_ PPH_STRING *LxssFileName ) @@ -79,7 +80,7 @@ PPH_STRING PhGetWslDistributionFromPath( if (PhStartsWithString(FileName, lxssBasePathName, TRUE)) { lxssDistributionName = PhQueryRegistryString(subKeyHandle, L"DistributionName"); - + if (LxssDistroPath) { PhSetReference(&lxssDistroPath, lxssBasePathName); @@ -126,7 +127,16 @@ PPH_STRING PhGetWslDistributionFromPath( *LxssFileName = lxssFileName; } - return lxssDistributionName; + if (LxssDistroName) + { + if (lxssDistributionName) + { + *LxssDistroName = lxssDistributionName; + return TRUE; + } + } + + return FALSE; } BOOLEAN PhInitializeLxssImageVersionInfo( @@ -144,13 +154,18 @@ BOOLEAN PhInitializeLxssImageVersionInfo( PPH_STRING result; lxssBaseFileName = PhGetBaseName(FileName); - lxssDistroName = PhGetWslDistributionFromPath( + + if (!PhGetWslDistributionFromPath( FileName, + &lxssDistroName, &lxssDistroPath, &lxssFileName - ); + )) + { + return FALSE; + } - if (!(lxssDistroName && lxssFileName && lxssBaseFileName)) + if (PhIsNullOrEmptyString(lxssDistroName) || PhIsNullOrEmptyString(lxssFileName) || PhIsNullOrEmptyString(lxssBaseFileName)) { if (lxssDistroName) PhDereferenceObject(lxssDistroName); if (lxssDistroPath) PhDereferenceObject(lxssDistroPath); @@ -159,11 +174,6 @@ BOOLEAN PhInitializeLxssImageVersionInfo( return FALSE; } - if (PhEqualString2(lxssFileName, L"/init", FALSE)) - { - PhMoveReference(&lxssFileName, PhCreateString(L"/sbin/init")); - } - PhMoveReference(&lxssCommandLine, PhFormatString( L"rpm -qf %s --queryformat \"%%{VERSION}|%%{VENDOR}|%%{SUMMARY}\"", lxssFileName->Buffer @@ -216,9 +226,18 @@ BOOLEAN PhInitializeLxssImageVersionInfo( PhDereferenceObject(result); } + if (!lxssPackageName) + { + PhDereferenceObject(lxssCommandLine); + PhDereferenceObject(lxssDistroName); + PhDereferenceObject(lxssFileName); + PhDereferenceObject(lxssBaseFileName); + return FALSE; + } + PhMoveReference(&lxssCommandLine, PhFormatString( L"dpkg-query -W -f=${Version}|${Maintainer}|${binary:Summary} %s", - lxssPackageName ? lxssPackageName->Buffer : lxssBaseFileName->Buffer + lxssPackageName->Buffer )); status = PhCreateProcessLxss( From 5c1995201de5ac86314c850591b8b29655b1d719 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 8 Feb 2019 00:34:00 +0100 Subject: [PATCH 1639/2058] Fix options window not showing when topmost --- ProcessHacker/options.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ProcessHacker/options.c b/ProcessHacker/options.c index 14d9b697b741..9299149bb677 100644 --- a/ProcessHacker/options.c +++ b/ProcessHacker/options.c @@ -291,6 +291,8 @@ INT_PTR CALLBACK PhOptionsDialogProc( //PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDC_APPLY), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDOK), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); + PhRegisterWindowCallback(hwndDlg, PH_PLUGIN_WINDOW_EVENT_TYPE_TOPMOST, NULL); + if (PhEnableThemeSupport) // TODO: fix options dialog theme (dmex) PhInitializeWindowTheme(hwndDlg, TRUE); @@ -347,6 +349,8 @@ INT_PTR CALLBACK PhOptionsDialogProc( if (OptionsTreeImageList) ImageList_Destroy(OptionsTreeImageList); + PhUnregisterWindowCallback(hwndDlg); + PhUnregisterDialog(PhOptionsWindowHandle); PhOptionsWindowHandle = NULL; } From 65209996bac647398da5a8aece28f605b5140617 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 8 Feb 2019 00:35:51 +0100 Subject: [PATCH 1640/2058] Fix sysinfo graph mouseover regression on Win7 --- ProcessHacker/sysinfo.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/ProcessHacker/sysinfo.c b/ProcessHacker/sysinfo.c index 6d27ffd48b15..70387905cae6 100644 --- a/ProcessHacker/sysinfo.c +++ b/ProcessHacker/sysinfo.c @@ -1463,17 +1463,17 @@ VOID PhSipDefaultDrawPanel( { if (CurrentView == SysInfoSummaryView) { - if (Section->GraphHot) - { - DrawThemeBackground( - ThemeData, - hdc, - TVP_TREEITEM, - TREIS_HOT, - &DrawPanel->Rect, - &DrawPanel->Rect - ); - } + //if (Section->GraphHot) + //{ + // DrawThemeBackground( + // ThemeData, + // hdc, + // TVP_TREEITEM, + // TREIS_HOT, + // &DrawPanel->Rect, + // &DrawPanel->Rect + // ); + //} } else if (CurrentView == SysInfoSectionView) { From 241b7346c42ee237760ed661e606be8f06291a23 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 8 Feb 2019 00:36:52 +0100 Subject: [PATCH 1641/2058] Update directory attributes --- phlib/native.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/phlib/native.c b/phlib/native.c index d9caddc479d5..a481ca04283f 100644 --- a/phlib/native.c +++ b/phlib/native.c @@ -735,10 +735,9 @@ NTSTATUS PhGetProcessCommandLine( _Out_ PPH_STRING *CommandLine ) { - NTSTATUS status; - if (WindowsVersion >= WINDOWS_8_1) { + NTSTATUS status; PUNICODE_STRING commandLine; status = PhpQueryProcessVariableSize( @@ -7226,7 +7225,7 @@ NTSTATUS PhCreateDirectory( &directoryHandle, PhGetString(tempPathString), FILE_GENERIC_READ, - FILE_ATTRIBUTE_NORMAL, + FILE_ATTRIBUTE_DIRECTORY, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_CREATE, FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT @@ -7280,7 +7279,7 @@ static BOOLEAN PhpDeleteDirectoryCallback( &directoryHandle, PhGetString(fullName), FILE_GENERIC_READ | DELETE, - FILE_ATTRIBUTE_NORMAL, + FILE_ATTRIBUTE_DIRECTORY, FILE_SHARE_READ | FILE_SHARE_DELETE, FILE_OPEN, FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT @@ -7364,7 +7363,7 @@ NTSTATUS PhDeleteDirectory( &directoryHandle, PhGetString(DirectoryPath), FILE_GENERIC_READ | DELETE, - FILE_ATTRIBUTE_NORMAL, + FILE_ATTRIBUTE_DIRECTORY, FILE_SHARE_READ | FILE_SHARE_DELETE, FILE_OPEN, FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT From 857237b940a3d9b2133b8f44e96d4b3727fef21c Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 10 Feb 2019 02:17:27 +0100 Subject: [PATCH 1642/2058] Fix warning C4701 --- phlib/lsasup.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/phlib/lsasup.c b/phlib/lsasup.c index 9807db5751fa..87a90ecfbbc3 100644 --- a/phlib/lsasup.c +++ b/phlib/lsasup.c @@ -510,8 +510,7 @@ VOID PhInitializeCapabilitySidCache( _Out_ PSID CapabilitySid ); PPH_STRING applicationDirectory; - PPH_STRING capabilityListFileName; - PPH_STRING capabilityListString; + PPH_STRING capabilityListString = NULL; PH_STRINGREF namePart; PH_STRINGREF remainingPart; @@ -520,6 +519,8 @@ VOID PhInitializeCapabilitySidCache( if (applicationDirectory = PhGetApplicationDirectory()) { + PPH_STRING capabilityListFileName; + capabilityListFileName = PhConcatStringRefZ(&applicationDirectory->sr, L"capslist.txt"); PhDereferenceObject(applicationDirectory); From d8272ba43b271bdfc8751b12dae9d0d34121319b Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 10 Feb 2019 06:23:38 +0100 Subject: [PATCH 1643/2058] Add PhGetMappedImageTlsCallbacks --- phlib/include/mapimg.h | 32 ++++++++ phlib/mapimg.c | 180 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 212 insertions(+) diff --git a/phlib/include/mapimg.h b/phlib/include/mapimg.h index ff759722b832..30187f189ccb 100644 --- a/phlib/include/mapimg.h +++ b/phlib/include/mapimg.h @@ -426,6 +426,38 @@ PhGetMappedImageResources( _In_ PPH_MAPPED_IMAGE MappedImage ); +typedef struct _PH_IMAGE_TLS_CALLBACK_ENTRY +{ + ULONG_PTR Index; + ULONG_PTR Address; +} PH_IMAGE_TLS_CALLBACK_ENTRY, *PPH_IMAGE_TLS_CALLBACK_ENTRY; + +typedef struct _PH_MAPPED_IMAGE_TLS_CALLBACKS +{ + PPH_MAPPED_IMAGE MappedImage; + PIMAGE_DATA_DIRECTORY DataDirectory; + + union + { + PIMAGE_TLS_DIRECTORY32 TlsDirectory32; + PIMAGE_TLS_DIRECTORY64 TlsDirectory64; + }; + + PVOID CallbackIndexes; + PVOID CallbackAddress; + + ULONG NumberOfEntries; + PPH_IMAGE_TLS_CALLBACK_ENTRY Entries; +} PH_MAPPED_IMAGE_TLS_CALLBACKS, *PPH_MAPPED_IMAGE_TLS_CALLBACKS; + +PHLIBAPI +NTSTATUS +NTAPI +PhGetMappedImageTlsCallbacks( + _Out_ PPH_MAPPED_IMAGE_TLS_CALLBACKS TlsCallbacks, + _In_ PPH_MAPPED_IMAGE MappedImage + ); + // maplib struct _PH_MAPPED_ARCHIVE; diff --git a/phlib/mapimg.c b/phlib/mapimg.c index 13d499d8996d..43fd8cb715e2 100644 --- a/phlib/mapimg.c +++ b/phlib/mapimg.c @@ -1708,3 +1708,183 @@ NTSTATUS PhGetMappedImageResources( CleanupExit: return status; } + +NTSTATUS PhGetMappedImageTlsCallbackDirectory32( + _Out_ PPH_MAPPED_IMAGE_TLS_CALLBACKS TlsCallbacks, + _In_ PPH_MAPPED_IMAGE MappedImage + ) +{ + NTSTATUS status; + PIMAGE_TLS_DIRECTORY32 tlsDirectory; + ULONG_PTR tlsCallbacksOffset; + + // Get a pointer to the resource directory. + + status = PhGetMappedImageDataEntry( + MappedImage, + IMAGE_DIRECTORY_ENTRY_TLS, + &TlsCallbacks->DataDirectory + ); + + if (!NT_SUCCESS(status)) + return status; + + tlsDirectory = PhMappedImageRvaToVa( + MappedImage, + TlsCallbacks->DataDirectory->VirtualAddress, + NULL + ); + + if (!tlsDirectory) + return STATUS_INVALID_PARAMETER; + + __try + { + PhpMappedImageProbe(MappedImage, tlsDirectory, sizeof(PIMAGE_TLS_DIRECTORY32)); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + return GetExceptionCode(); + } + + TlsCallbacks->TlsDirectory32 = tlsDirectory; + + if (tlsDirectory->StartAddressOfRawData > MappedImage->NtHeaders32->OptionalHeader.ImageBase) + tlsCallbacksOffset = MappedImage->NtHeaders32->OptionalHeader.ImageBase; + else + tlsCallbacksOffset = 0; + + TlsCallbacks->CallbackIndexes = PhMappedImageRvaToVa(MappedImage, (ULONG)(ULONG_PTR)PTR_SUB_OFFSET(tlsDirectory->AddressOfIndex, tlsCallbacksOffset), NULL); + TlsCallbacks->CallbackAddress = PhMappedImageRvaToVa(MappedImage, (ULONG)(ULONG_PTR)PTR_SUB_OFFSET(tlsDirectory->AddressOfCallBacks, tlsCallbacksOffset), NULL); + + if (TlsCallbacks->CallbackAddress) + return STATUS_SUCCESS; + + return STATUS_INVALID_PARAMETER; +} + +NTSTATUS PhGetMappedImageTlsCallbackDirectory64( + _Out_ PPH_MAPPED_IMAGE_TLS_CALLBACKS TlsCallbacks, + _In_ PPH_MAPPED_IMAGE MappedImage + ) +{ + NTSTATUS status; + PIMAGE_TLS_DIRECTORY64 tlsDirectory; + ULONG_PTR tlsCallbacksOffset; + + // Get a pointer to the resource directory. + + status = PhGetMappedImageDataEntry( + MappedImage, + IMAGE_DIRECTORY_ENTRY_TLS, + &TlsCallbacks->DataDirectory + ); + + if (!NT_SUCCESS(status)) + return status; + + tlsDirectory = PhMappedImageRvaToVa( + MappedImage, + TlsCallbacks->DataDirectory->VirtualAddress, + NULL + ); + + if (!tlsDirectory) + return STATUS_INVALID_PARAMETER; + + __try + { + PhpMappedImageProbe(MappedImage, tlsDirectory, sizeof(PIMAGE_TLS_DIRECTORY64)); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + return GetExceptionCode(); + } + + TlsCallbacks->TlsDirectory64 = tlsDirectory; + + if (tlsDirectory->StartAddressOfRawData > MappedImage->NtHeaders->OptionalHeader.ImageBase) + tlsCallbacksOffset = MappedImage->NtHeaders->OptionalHeader.ImageBase; + else + tlsCallbacksOffset = 0; + + TlsCallbacks->CallbackIndexes = PhMappedImageRvaToVa(MappedImage, (ULONG)(ULONG_PTR)PTR_SUB_OFFSET(tlsDirectory->AddressOfIndex, tlsCallbacksOffset), NULL); + TlsCallbacks->CallbackAddress = PhMappedImageRvaToVa(MappedImage, (ULONG)(ULONG_PTR)PTR_SUB_OFFSET(tlsDirectory->AddressOfCallBacks, tlsCallbacksOffset), NULL); + + if (TlsCallbacks->CallbackAddress) + return STATUS_SUCCESS; + + return STATUS_INVALID_PARAMETER; +} + +NTSTATUS PhGetMappedImageTlsCallbacks( + _Out_ PPH_MAPPED_IMAGE_TLS_CALLBACKS TlsCallbacks, + _In_ PPH_MAPPED_IMAGE MappedImage + ) +{ + NTSTATUS status; + ULONG count = 0; + ULONG i; + + // Get a pointer to the TLS directory. + + if (MappedImage->Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) + status = PhGetMappedImageTlsCallbackDirectory32(TlsCallbacks, MappedImage); + else + status = PhGetMappedImageTlsCallbackDirectory64(TlsCallbacks, MappedImage); + + if (!NT_SUCCESS(status)) + return status; + + // Do a scan to determine how many callbacks there are. + + if (TlsCallbacks->CallbackAddress) + { + if (MappedImage->Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) + { + PULONG array = (PULONG)(PULONG_PTR)TlsCallbacks->CallbackAddress; + + for (i = 0; array[i]; i++) + count++; + } + else + { + PULONGLONG array = (PULONGLONG)(PULONG_PTR)TlsCallbacks->CallbackAddress; + + for (i = 0; array[i]; i++) + count++; + } + } + + if (count == 0) + return STATUS_INVALID_IMAGE_FORMAT; + + // Allocate the number of callbacks. + + TlsCallbacks->NumberOfEntries = count; + TlsCallbacks->Entries = PhAllocate(sizeof(PH_IMAGE_TLS_CALLBACK_ENTRY) * count); + memset(TlsCallbacks->Entries, 0, sizeof(PH_IMAGE_TLS_CALLBACK_ENTRY) * count); + + // Add the callbacks into our buffer. + + if (MappedImage->Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) + { + PULONG array = (PULONG)(PULONG_PTR)TlsCallbacks->CallbackAddress; + + for (i = 0; i < count; i++) + { + TlsCallbacks->Entries[i].Address = array[i]; + } + } + else + { + PULONGLONG array = (PULONGLONG)(PULONG_PTR)TlsCallbacks->CallbackAddress; + + for (i = 0; i < count; i++) + { + TlsCallbacks->Entries[i].Address = array[i]; + } + } + + return status; +} From 4def2724ef445d0b9924ec6ae547f486f8c88b5b Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 10 Feb 2019 06:24:16 +0100 Subject: [PATCH 1644/2058] peview: Fix loading 32bit symbols --- tools/peview/peprp.c | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/tools/peview/peprp.c b/tools/peview/peprp.c index 1c7a4e693b8a..a7ae260aed9c 100644 --- a/tools/peview/peprp.c +++ b/tools/peview/peprp.c @@ -69,12 +69,25 @@ VOID PvPeProperties( { // Load current PE pdb // TODO: Move into seperate thread. - PhLoadModuleSymbolProvider( - PvSymbolProvider, - PvFileName->Buffer, - (ULONG64)PvMappedImage.NtHeaders->OptionalHeader.ImageBase, - PvMappedImage.NtHeaders->OptionalHeader.SizeOfImage - ); + + if (PvMappedImage.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) + { + PhLoadModuleSymbolProvider( + PvSymbolProvider, + PvFileName->Buffer, + (ULONG64)PvMappedImage.NtHeaders32->OptionalHeader.ImageBase, + PvMappedImage.NtHeaders32->OptionalHeader.SizeOfImage + ); + } + else + { + PhLoadModuleSymbolProvider( + PvSymbolProvider, + PvFileName->Buffer, + (ULONG64)PvMappedImage.NtHeaders->OptionalHeader.ImageBase, + PvMappedImage.NtHeaders->OptionalHeader.SizeOfImage + ); + } } if (propContext = PvCreatePropContext(PvFileName)) From 4feaa9eea1e93cc66e6bdab4bb8b3397da35daa6 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 10 Feb 2019 06:26:47 +0100 Subject: [PATCH 1645/2058] peview: Add TLS properties --- tools/peview/include/peview.h | 7 ++ tools/peview/peprp.c | 11 ++ tools/peview/peview.rc | 16 +++ tools/peview/peview.vcxproj | 1 + tools/peview/peview.vcxproj.filters | 3 + tools/peview/resource.h | 1 + tools/peview/settings.c | 1 + tools/peview/tlsprp.c | 155 ++++++++++++++++++++++++++++ 8 files changed, 195 insertions(+) create mode 100644 tools/peview/tlsprp.c diff --git a/tools/peview/include/peview.h b/tools/peview/include/peview.h index ecd62d571566..86db57a5148c 100644 --- a/tools/peview/include/peview.h +++ b/tools/peview/include/peview.h @@ -382,6 +382,13 @@ INT_PTR CALLBACK PvpPeProcessesDlgProc( _In_ LPARAM lParam ); +INT_PTR CALLBACK PvpPeTlsDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + // ELF PWSTR PvpGetSymbolTypeName( diff --git a/tools/peview/peprp.c b/tools/peview/peprp.c index a7ae260aed9c..813536c26973 100644 --- a/tools/peview/peprp.c +++ b/tools/peview/peprp.c @@ -241,6 +241,17 @@ VOID PvPeProperties( PvAddPropPage(propContext, newPage); } + // TLS page + if (NT_SUCCESS(PhGetMappedImageDataEntry(&PvMappedImage, IMAGE_DIRECTORY_ENTRY_TLS, &entry)) && entry->VirtualAddress) + { + newPage = PvCreatePropPageContext( + MAKEINTRESOURCE(IDD_TLS), + PvpPeTlsDlgProc, + NULL + ); + PvAddPropPage(propContext, newPage); + } + // Symbols page if (NT_SUCCESS(PhGetMappedImageDataEntry(&PvMappedImage, IMAGE_DIRECTORY_ENTRY_DEBUG, &entry)) && entry->VirtualAddress) { diff --git a/tools/peview/peview.rc b/tools/peview/peview.rc index 9a8f4766ccb8..40aa784aa804 100644 --- a/tools/peview/peview.rc +++ b/tools/peview/peview.rc @@ -180,6 +180,14 @@ BEGIN TOPMARGIN, 3 BOTTOMMARGIN, 277 END + + IDD_TLS, DIALOG + BEGIN + LEFTMARGIN, 3 + RIGHTMARGIN, 297 + TOPMARGIN, 3 + BOTTOMMARGIN, 277 + END END #endif // APSTUDIO_INVOKED @@ -364,6 +372,14 @@ BEGIN CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,3,3,294,274 END +IDD_TLS DIALOGEX 0, 0, 300, 280 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Tls" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,3,3,294,274 +END + ///////////////////////////////////////////////////////////////////////////// // diff --git a/tools/peview/peview.vcxproj b/tools/peview/peview.vcxproj index a1ed0800c9f8..a32ecf7b01a3 100644 --- a/tools/peview/peview.vcxproj +++ b/tools/peview/peview.vcxproj @@ -244,6 +244,7 @@ + diff --git a/tools/peview/peview.vcxproj.filters b/tools/peview/peview.vcxproj.filters index c62e52a0acac..09b75161567c 100644 --- a/tools/peview/peview.vcxproj.filters +++ b/tools/peview/peview.vcxproj.filters @@ -99,6 +99,9 @@ Source Files\Pages\Linux + + Source Files + diff --git a/tools/peview/resource.h b/tools/peview/resource.h index b2ea897b6f19..5d6f4d16e200 100644 --- a/tools/peview/resource.h +++ b/tools/peview/resource.h @@ -22,6 +22,7 @@ #define IDD_PELINKS 114 #define IDD_PIDS 115 #define IDD_ELFDYNAMIC 116 +#define IDD_TLS 117 #define IDC_SYMBOLTREE 119 #define IDC_TARGETMACHINE 1003 #define IDC_CHECKSUM 1004 diff --git a/tools/peview/settings.c b/tools/peview/settings.c index 4062287774e7..0fc7cfeaa24e 100644 --- a/tools/peview/settings.c +++ b/tools/peview/settings.c @@ -49,6 +49,7 @@ VOID PhAddDefaultSettings( PhpAddStringSetting(L"ImageStreamsListViewColumns", L""); PhpAddStringSetting(L"ImageHardLinksListViewColumns", L""); PhpAddStringSetting(L"ImagePidsListViewColumns", L""); + PhpAddStringSetting(L"ImageTlsListViewColumns", L""); PhpAddStringSetting(L"LibListViewColumns", L""); PhpAddStringSetting(L"PdbTreeListColumns", L""); diff --git a/tools/peview/tlsprp.c b/tools/peview/tlsprp.c new file mode 100644 index 000000000000..cb17ce401890 --- /dev/null +++ b/tools/peview/tlsprp.c @@ -0,0 +1,155 @@ +/* + * Process Hacker - + * PE viewer + * + * Copyright (C) 2019 dmex + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include + +VOID PvpPeEnumerateTlsCallbacks( + _In_ HWND ListViewHandle + ) +{ + PH_MAPPED_IMAGE_TLS_CALLBACKS callbacks; + PH_IMAGE_TLS_CALLBACK_ENTRY entry; + ULONG count = 0; + ULONG i; + + if (NT_SUCCESS(PhGetMappedImageTlsCallbacks(&callbacks, &PvMappedImage))) + { + for (i = 0; i < callbacks.NumberOfEntries; i++) + { + INT lvItemIndex; + PPH_STRING symbol; + PPH_STRING symbolName = NULL; + WCHAR number[PH_INT32_STR_LEN_1]; + WCHAR pointer[PH_PTR_STR_LEN_1]; + + entry = callbacks.Entries[i]; + + PhPrintUInt32(number, ++count); + lvItemIndex = PhAddListViewItem(ListViewHandle, MAXINT, number, NULL); + + PhPrintPointer(pointer, (PVOID)(ULONG_PTR)entry.Address); + PhSetListViewSubItem(ListViewHandle, lvItemIndex, 1, pointer); + + if (PvMappedImage.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) + { + symbol = PhGetSymbolFromAddress( + PvSymbolProvider, + (ULONG64)ULongToPtr((ULONG)entry.Address), + NULL, + NULL, + &symbolName, + NULL + ); + } + else + { + symbol = PhGetSymbolFromAddress( + PvSymbolProvider, + (ULONG64)(ULONGLONG)entry.Address, + NULL, + NULL, + &symbolName, + NULL + ); + } + + if (symbolName) + { + PhSetListViewSubItem(ListViewHandle, lvItemIndex, 2, symbolName->Buffer); + PhDereferenceObject(symbolName); + } + + if (symbol) PhDereferenceObject(symbol); + } + + PhFree(callbacks.Entries); + } +} + +INT_PTR CALLBACK PvpPeTlsDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + LPPROPSHEETPAGE propSheetPage; + PPV_PROPPAGECONTEXT propPageContext; + + if (!PvPropPageDlgProcHeader(hwndDlg, uMsg, lParam, &propSheetPage, &propPageContext)) + return FALSE; + + switch (uMsg) + { + case WM_INITDIALOG: + { + HWND lvHandle; + + lvHandle = GetDlgItem(hwndDlg, IDC_LIST); + PhSetListViewStyle(lvHandle, TRUE, TRUE); + PhSetControlTheme(lvHandle, L"explorer"); + PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 40, L"#"); + PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 150, L"RVA"); + PhAddListViewColumn(lvHandle, 2, 2, 2, LVCFMT_LEFT, 200, L"Symbol"); + PhSetExtendedListView(lvHandle); + PhLoadListViewColumnsFromSetting(L"ImageTlsListViewColumns", lvHandle); + + PvpPeEnumerateTlsCallbacks(lvHandle); + //ExtendedListView_SortItems(lvHandle); + + EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); + } + break; + case WM_DESTROY: + { + PhSaveListViewColumnsToSetting(L"ImageTlsListViewColumns", GetDlgItem(hwndDlg, IDC_LIST)); + } + break; + case WM_SHOWWINDOW: + { + if (!propPageContext->LayoutInitialized) + { + PPH_LAYOUT_ITEM dialogItem; + + dialogItem = PvAddPropPageLayoutItem(hwndDlg, hwndDlg, PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL); + PvAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_LIST), dialogItem, PH_ANCHOR_ALL); + + PvDoPropPageLayout(hwndDlg); + + propPageContext->LayoutInitialized = TRUE; + } + } + break; + case WM_NOTIFY: + { + PvHandleListViewNotifyForCopy(lParam, GetDlgItem(hwndDlg, IDC_LIST)); + } + break; + case WM_CONTEXTMENU: + { + PvHandleListViewCommandCopy(hwndDlg, lParam, wParam, GetDlgItem(hwndDlg, IDC_LIST)); + } + break; + } + + return FALSE; +} From 8fe038ad1006f6b0a554709aeaa5d39e595818ed Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 10 Feb 2019 06:38:33 +0100 Subject: [PATCH 1646/2058] peview: Fix symbol imagebase --- tools/peview/cfgprp.c | 36 +++++++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/tools/peview/cfgprp.c b/tools/peview/cfgprp.c index 91f283e53723..7ad1d3eb66ff 100644 --- a/tools/peview/cfgprp.c +++ b/tools/peview/cfgprp.c @@ -79,16 +79,34 @@ INT_PTR CALLBACK PvpPeCgfDlgProc( PhSetListViewSubItem(lvHandle, lvItemIndex, 1, pointer); // Resolve name based on public symbols - if (!(symbol = PhGetSymbolFromAddress( - PvSymbolProvider, - (ULONG64)PTR_ADD_OFFSET(PvMappedImage.NtHeaders->OptionalHeader.ImageBase, cfgFunctionEntry.Rva), - &symbolResolveLevel, - NULL, - &symbolName, - &displacement - ))) + + if (PvMappedImage.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) { - continue; + if (!(symbol = PhGetSymbolFromAddress( + PvSymbolProvider, + (ULONG64)PTR_ADD_OFFSET(PvMappedImage.NtHeaders32->OptionalHeader.ImageBase, cfgFunctionEntry.Rva), + &symbolResolveLevel, + NULL, + &symbolName, + &displacement + ))) + { + continue; + } + } + else + { + if (!(symbol = PhGetSymbolFromAddress( + PvSymbolProvider, + (ULONG64)PTR_ADD_OFFSET(PvMappedImage.NtHeaders->OptionalHeader.ImageBase, cfgFunctionEntry.Rva), + &symbolResolveLevel, + NULL, + &symbolName, + &displacement + ))) + { + continue; + } } switch (symbolResolveLevel) From 7441ae2684528c9050e6689ab14779cf44930875 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 10 Feb 2019 06:43:16 +0100 Subject: [PATCH 1647/2058] Fix build warning --- phlib/mapimg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phlib/mapimg.c b/phlib/mapimg.c index 43fd8cb715e2..d0c72af5c0c6 100644 --- a/phlib/mapimg.c +++ b/phlib/mapimg.c @@ -1882,7 +1882,7 @@ NTSTATUS PhGetMappedImageTlsCallbacks( for (i = 0; i < count; i++) { - TlsCallbacks->Entries[i].Address = array[i]; + TlsCallbacks->Entries[i].Address = (ULONG_PTR)array[i]; } } From 02f98f3b355426c26849004b36605f5bc1484558 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 10 Feb 2019 06:55:23 +0100 Subject: [PATCH 1648/2058] ExtendedTools: Fix module services dialog parent --- plugins/ExtendedTools/main.c | 2 +- plugins/ExtendedTools/modsrv.c | 97 +++++++++++++++++++++++++--------- 2 files changed, 72 insertions(+), 27 deletions(-) diff --git a/plugins/ExtendedTools/main.c b/plugins/ExtendedTools/main.c index d0bf94cc42e5..e2263bd33d9b 100644 --- a/plugins/ExtendedTools/main.c +++ b/plugins/ExtendedTools/main.c @@ -113,7 +113,7 @@ VOID NTAPI MenuItemCallback( case ID_MODULE_SERVICES: { EtShowModuleServicesDialog( - !!PhGetIntegerSetting(L"ForceNoParent") ? NULL : menuItem->OwnerWindow, + menuItem->OwnerWindow, ModuleProcessId, ((PPH_MODULE_ITEM)menuItem->Context)->Name ); diff --git a/plugins/ExtendedTools/modsrv.c b/plugins/ExtendedTools/modsrv.c index f05d676fc417..ee0d2967ef12 100644 --- a/plugins/ExtendedTools/modsrv.c +++ b/plugins/ExtendedTools/modsrv.c @@ -26,6 +26,7 @@ typedef struct _MODULE_SERVICES_CONTEXT { + HWND ParentWindowHandle; HWND ServiceListHandle; HANDLE ProcessId; PPH_STRING ModuleName; @@ -39,6 +40,47 @@ INT_PTR CALLBACK EtpModuleServicesDlgProc( _In_ LPARAM lParam ); +NTSTATUS EtpModuleServicesDialogThreadStart( + _In_ PVOID Parameter + ) +{ + BOOL result; + MSG message; + HWND windowHandle; + PH_AUTO_POOL autoPool; + + PhInitializeAutoPool(&autoPool); + + windowHandle = CreateDialogParam( + PluginInstance->DllBase, + MAKEINTRESOURCE(IDD_MODSERVICES), + NULL, + EtpModuleServicesDlgProc, + (LPARAM)Parameter + ); + + ShowWindow(windowHandle, SW_SHOW); + SetForegroundWindow(windowHandle); + + while (result = GetMessage(&message, NULL, 0, 0)) + { + if (result == -1) + break; + + if (!IsDialogMessage(windowHandle, &message)) + { + TranslateMessage(&message); + DispatchMessage(&message); + } + + PhDrainAutoPool(&autoPool); + } + + PhDeleteAutoPool(&autoPool); + + return STATUS_SUCCESS; +} + VOID EtShowModuleServicesDialog( _In_ HWND ParentWindowHandle, _In_ HANDLE ProcessId, @@ -48,22 +90,17 @@ VOID EtShowModuleServicesDialog( PMODULE_SERVICES_CONTEXT context; context = PhAllocateZero(sizeof(MODULE_SERVICES_CONTEXT)); + context->ParentWindowHandle = ParentWindowHandle; context->ProcessId = ProcessId; context->ModuleName = PhReferenceObject(ModuleName); - DialogBoxParam( - PluginInstance->DllBase, - MAKEINTRESOURCE(IDD_MODSERVICES), - ParentWindowHandle, - EtpModuleServicesDlgProc, - (LPARAM)context - ); + PhCreateThread2(EtpModuleServicesDialogThreadStart, context); } -PPH_LIST PhpQueryModuleServiceReferences( - _In_ HWND WindowHandle, - _In_ HANDLE ProcessId, - _In_ PWSTR ModuleName +ULONG PhpQueryModuleServiceReferences( + _In_ HWND WindowHandle, + _In_ PMODULE_SERVICES_CONTEXT Context, + _Out_ PPH_LIST *ServiceList ) { ULONG win32Result; @@ -72,14 +109,11 @@ PPH_LIST PhpQueryModuleServiceReferences( PPH_LIST serviceList; if (!(I_QueryTagInformation = PhGetModuleProcAddress(L"advapi32.dll", "I_QueryTagInformation"))) - { - PhShowError(GetParent(WindowHandle), L"Unable to query services because the feature is not supported by the operating system."); - return NULL; - } + return ERROR_SUCCESS; memset(&namesReferencingModule, 0, sizeof(TAG_INFO_NAMES_REFERENCING_MODULE)); - namesReferencingModule.InParams.dwPid = HandleToUlong(ProcessId); - namesReferencingModule.InParams.pszModule = ModuleName; + namesReferencingModule.InParams.dwPid = HandleToUlong(Context->ProcessId); + namesReferencingModule.InParams.pszModule = PhGetString(Context->ModuleName); win32Result = I_QueryTagInformation(NULL, eTagInfoLevelNamesReferencingModule, &namesReferencingModule); @@ -87,10 +121,7 @@ PPH_LIST PhpQueryModuleServiceReferences( win32Result = ERROR_SUCCESS; if (win32Result != ERROR_SUCCESS) - { - PhShowStatus(GetParent(WindowHandle), L"Unable to query module references.", 0, win32Result); - return NULL; - } + return win32Result; serviceList = PhCreateList(16); @@ -118,6 +149,8 @@ PPH_LIST PhpQueryModuleServiceReferences( LocalFree(namesReferencingModule.OutParams.pmszNames); } + *ServiceList = serviceList; + //if (serviceList->Count == 0) //{ // PhShowInformation2(GetParent(WindowHandle), L"", L"This module was not referenced by a service."); @@ -125,7 +158,7 @@ PPH_LIST PhpQueryModuleServiceReferences( // return NULL; //} - return serviceList; + return win32Result; } INT_PTR CALLBACK EtpModuleServicesDlgProc( @@ -155,6 +188,8 @@ INT_PTR CALLBACK EtpModuleServicesDlgProc( PhDereferenceObject(context->ModuleName); PhFree(context); + + PostQuitMessage(0); } } @@ -165,13 +200,18 @@ INT_PTR CALLBACK EtpModuleServicesDlgProc( { case WM_INITDIALOG: { + ULONG win32Result; PPH_LIST serviceList; PPH_SERVICE_ITEM *serviceItems; RECT rect; - if (!(serviceList = PhpQueryModuleServiceReferences(hwndDlg, context->ProcessId, PhGetString(context->ModuleName)))) + if ((win32Result = PhpQueryModuleServiceReferences(hwndDlg, context, &serviceList)) != STATUS_SUCCESS) { - EndDialog(hwndDlg, IDCANCEL); + PhShowStatus( + (IsWindowVisible(context->ParentWindowHandle) && !IsMinimized(context->ParentWindowHandle)) ? context->ParentWindowHandle : NULL, + L"Unable to query module references.", 0, win32Result + ); + DestroyWindow(hwndDlg); return FALSE; } @@ -189,7 +229,12 @@ INT_PTR CALLBACK EtpModuleServicesDlgProc( if (processItem = PhReferenceProcessItem(context->ProcessId)) { - message = PhFormatString(L"Services referencing %s in %s:", PhGetString(context->ModuleName), PhGetStringOrEmpty(processItem->ProcessName)); + message = PhFormatString( + L"Services referencing %s in %s (%lu):", + PhGetString(context->ModuleName), + PhGetStringOrEmpty(processItem->ProcessName), + HandleToUlong(processItem->ProcessId) + ); PhDereferenceObject(processItem); } else @@ -235,7 +280,7 @@ INT_PTR CALLBACK EtpModuleServicesDlgProc( // NOTE: Don't save placement during WM_DESTROY since the dialog won't be created after an error querying service references. (dmex) PhSaveWindowPlacementToSetting(SETTING_NAME_MODULE_SERVICES_WINDOW_POSITION, SETTING_NAME_MODULE_SERVICES_WINDOW_SIZE, hwndDlg); - EndDialog(hwndDlg, IDOK); + DestroyWindow(hwndDlg); } break; } From 10b7d8412d58b37c26c411106a74977b5886ee6e Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 10 Feb 2019 07:53:16 +0100 Subject: [PATCH 1649/2058] peview: Fix clr header offsets --- tools/peview/clrprp.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tools/peview/clrprp.c b/tools/peview/clrprp.c index 2846ed89727a..77ce395a3e88 100644 --- a/tools/peview/clrprp.c +++ b/tools/peview/clrprp.c @@ -38,7 +38,7 @@ typedef struct _STORAGESIGNATURE USHORT MinorVersion; ULONG ExtraData; // Offset to next structure of information ULONG VersionLength; // Length of version string - UCHAR VersionString[1]; // dmex: added for convenience. + //UCHAR VersionString[1]; } STORAGESIGNATURE, *PSTORAGESIGNATURE; typedef struct _STORAGEHEADER @@ -137,12 +137,12 @@ INT_PTR CALLBACK PvpPeClrDlgProc( if (metaData && metaData->VersionLength != 0) { - string = PhZeroExtendToUtf16Ex((PCHAR)metaData->VersionString, metaData->VersionLength); + string = PhZeroExtendToUtf16Ex(PTR_ADD_OFFSET(metaData, RTL_SIZEOF_THROUGH_FIELD(STORAGESIGNATURE, VersionLength)), metaData->VersionLength); PhSetDialogItemText(hwndDlg, IDC_VERSIONSTRING, string->Buffer); PhDereferenceObject(string); { - PSTORAGEHEADER storageHeader = PTR_ADD_OFFSET(metaData, (sizeof(STORAGESIGNATURE) - sizeof(UCHAR)) + metaData->VersionLength); + PSTORAGEHEADER storageHeader = PTR_ADD_OFFSET(metaData, sizeof(STORAGESIGNATURE) + metaData->VersionLength); PSTORAGESTREAM streamHeader = PTR_ADD_OFFSET(storageHeader, sizeof(STORAGEHEADER)); for (USHORT i = 0; i < storageHeader->Streams; i++) @@ -169,7 +169,7 @@ INT_PTR CALLBACK PvpPeClrDlgProc( // Stream headers don't have fixed sizes... // The size is aligned up based on a variable length string at the end. - streamHeader = PTR_ADD_OFFSET(streamHeader, ALIGN_UP(FIELD_OFFSET(STORAGESTREAM, Name) + strlen(streamHeader->Name) + 1, 4)); + streamHeader = PTR_ADD_OFFSET(streamHeader, ALIGN_UP(UFIELD_OFFSET(STORAGESTREAM, Name) + strlen(streamHeader->Name) + 1, ULONG)); } } } From 19339eb88d7b0bb87c44cfe84910bd86c1e14db8 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 10 Feb 2019 08:01:00 +0100 Subject: [PATCH 1650/2058] peview: Update loadconfig properties --- tools/peview/ldprp.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/tools/peview/ldprp.c b/tools/peview/ldprp.c index d5f85aaba41c..29a790bb0c9f 100644 --- a/tools/peview/ldprp.c +++ b/tools/peview/ldprp.c @@ -139,6 +139,35 @@ INT_PTR CALLBACK PvpPeLoadConfigDlgProc( ADD_VALUE(L"CFG LongJump table entry count", PhaFormatUInt64((Config)->GuardLongJumpTargetCount, TRUE)->Buffer); \ } \ } \ + \ + if (RTL_CONTAINS_FIELD((Config), (Config)->Size, CodeIntegrity)) \ + { \ + ADD_VALUE(L"CI flags", PhaFormatString(L"0x%x", (Config)->CodeIntegrity.Flags)->Buffer); \ + ADD_VALUE(L"CI catalog", PhaFormatString(L"0x%Ix", (Config)->CodeIntegrity.Catalog)->Buffer); \ + ADD_VALUE(L"CI catalog offset", PhaFormatString(L"0x%Ix", (Config)->CodeIntegrity.CatalogOffset)->Buffer); \ + } \ + \ + if (RTL_CONTAINS_FIELD((Config), (Config)->Size, DynamicValueRelocTable)) \ + { \ + ADD_VALUE(L"DynamicValueRelocTable", PhaFormatString(L"0x%Ix", (Config)->DynamicValueRelocTable)->Buffer); \ + ADD_VALUE(L"CHPEMetadataPointer", PhaFormatString(L"0x%Ix", (Config)->CHPEMetadataPointer)->Buffer); \ + ADD_VALUE(L"GuardRFFailureRoutine", PhaFormatString(L"0x%Ix", (Config)->GuardRFFailureRoutine)->Buffer); \ + ADD_VALUE(L"GuardRFFailureRoutineFunctionPointer", PhaFormatString(L"0x%Ix", (Config)->GuardRFFailureRoutineFunctionPointer)->Buffer); \ + } \ + \ + if (RTL_CONTAINS_FIELD((Config), (Config)->Size, DynamicValueRelocTableOffset)) \ + { \ + ADD_VALUE(L"DynamicValueRelocTableOffset", PhaFormatString(L"0x%Ix", (Config)->DynamicValueRelocTableOffset)->Buffer); \ + ADD_VALUE(L"DynamicValueRelocTableSection", PhaFormatString(L"0x%Ix", (Config)->DynamicValueRelocTableSection)->Buffer); \ + ADD_VALUE(L"GuardRFVerifyStackPointerFunctionPointer", PhaFormatString(L"0x%Ix", (Config)->GuardRFVerifyStackPointerFunctionPointer)->Buffer); \ + ADD_VALUE(L"HotPatchTableOffset", PhaFormatString(L"0x%Ix", (Config)->HotPatchTableOffset)->Buffer); \ + ADD_VALUE(L"EnclaveConfigurationPointer", PhaFormatString(L"0x%Ix", (Config)->EnclaveConfigurationPointer)->Buffer); \ + } \ + \ + if (RTL_CONTAINS_FIELD((Config), (Config)->Size, VolatileMetadataPointer)) \ + { \ + ADD_VALUE(L"VolatileMetadataPointer", PhaFormatString(L"0x%Ix", (Config)->VolatileMetadataPointer)->Buffer); \ + } \ } if (PvMappedImage.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) From 7b6abf751a6a7a7f751095f46e30fdb726c79d40 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 10 Feb 2019 08:01:41 +0100 Subject: [PATCH 1651/2058] peview: Add ELF section name helper --- tools/peview/exlfprp.c | 17 +++++++++++++++++ tools/peview/include/peview.h | 4 ++++ 2 files changed, 21 insertions(+) diff --git a/tools/peview/exlfprp.c b/tools/peview/exlfprp.c index ba47db808f21..ecbd8fff9640 100644 --- a/tools/peview/exlfprp.c +++ b/tools/peview/exlfprp.c @@ -89,6 +89,23 @@ PWSTR PvpGetSymbolVisibility( return L"***ERROR***"; } +PPH_STRING PvpGetSymbolSectionName( + _In_ ULONG Index + ) +{ + switch (Index) + { + case SHN_UNDEF: + return PhCreateString(L"UND"); + case SHN_ABS: + return PhCreateString(L"ABS"); + case SHN_COMMON: + return PhCreateString(L"Common"); + } + + return PhaFormatUInt64(Index, TRUE); +} + VOID PvExlfProperties( VOID ) diff --git a/tools/peview/include/peview.h b/tools/peview/include/peview.h index 86db57a5148c..056f561a5d4b 100644 --- a/tools/peview/include/peview.h +++ b/tools/peview/include/peview.h @@ -403,6 +403,10 @@ PWSTR PvpGetSymbolVisibility( _In_ UCHAR OtherInfo ); +PPH_STRING PvpGetSymbolSectionName( + _In_ ULONG Index + ); + INT_PTR CALLBACK PvpExlfGeneralDlgProc( _In_ HWND hwndDlg, _In_ UINT uMsg, From 2fa2fe0b02c1d812069a07e3fdb67bc81cc5e335 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 10 Feb 2019 08:12:56 +0100 Subject: [PATCH 1652/2058] peview: Add ELF export section name --- tools/peview/exlfexports.c | 2 ++ tools/peview/exlfimports.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/tools/peview/exlfexports.c b/tools/peview/exlfexports.c index 6ef3c8bfaaeb..21b187a9f51e 100644 --- a/tools/peview/exlfexports.c +++ b/tools/peview/exlfexports.c @@ -52,6 +52,7 @@ VOID PvpProcessElfExports( PhSetListViewSubItem(ListViewHandle, lvItemIndex, 4, PvpGetSymbolTypeName(export->TypeInfo)); PhSetListViewSubItem(ListViewHandle, lvItemIndex, 5, PvpGetSymbolBindingName(export->TypeInfo)); PhSetListViewSubItem(ListViewHandle, lvItemIndex, 6, PvpGetSymbolVisibility(export->OtherInfo)); + PhSetListViewSubItem(ListViewHandle, lvItemIndex, 7, PvpGetSymbolSectionName(export->SectionIndex)->Buffer); } PhFreeMappedWslImageSymbols(exports); @@ -86,6 +87,7 @@ INT_PTR CALLBACK PvpExlfExportsDlgProc( PhAddListViewColumn(lvHandle, 4, 4, 4, LVCFMT_LEFT, 80, L"Type"); PhAddListViewColumn(lvHandle, 5, 5, 5, LVCFMT_LEFT, 80, L"Binding"); PhAddListViewColumn(lvHandle, 6, 6, 6, LVCFMT_LEFT, 80, L"Visibility"); + PhAddListViewColumn(lvHandle, 7, 7, 7, LVCFMT_LEFT, 80, L"Section"); PhSetExtendedListView(lvHandle); PhLoadListViewColumnsFromSetting(L"ExportsWslListViewColumns", lvHandle); diff --git a/tools/peview/exlfimports.c b/tools/peview/exlfimports.c index b82f51e0ae21..0c01daf154c9 100644 --- a/tools/peview/exlfimports.c +++ b/tools/peview/exlfimports.c @@ -48,6 +48,7 @@ VOID PvpProcessElfImports( PhSetListViewSubItem(ListViewHandle, lvItemIndex, 3, PvpGetSymbolTypeName(import->TypeInfo)); PhSetListViewSubItem(ListViewHandle, lvItemIndex, 4, PvpGetSymbolBindingName(import->TypeInfo)); PhSetListViewSubItem(ListViewHandle, lvItemIndex, 5, PvpGetSymbolVisibility(import->OtherInfo)); + PhSetListViewSubItem(ListViewHandle, lvItemIndex, 6, PvpGetSymbolSectionName(import->SectionIndex)->Buffer); } PhFreeMappedWslImageSymbols(imports); @@ -81,6 +82,7 @@ INT_PTR CALLBACK PvpExlfImportsDlgProc( PhAddListViewColumn(lvHandle, 3, 3, 3, LVCFMT_LEFT, 100, L"Type"); PhAddListViewColumn(lvHandle, 4, 4, 4, LVCFMT_LEFT, 80, L"Binding"); PhAddListViewColumn(lvHandle, 5, 5, 5, LVCFMT_LEFT, 80, L"Visibility"); + PhAddListViewColumn(lvHandle, 6, 6, 6, LVCFMT_LEFT, 80, L"Section"); PhSetExtendedListView(lvHandle); PhLoadListViewColumnsFromSetting(L"ImportsWslListViewColumns", lvHandle); From 789f2ce48363e9c56c340fab624cbab4763b9ed5 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 10 Feb 2019 08:41:49 +0100 Subject: [PATCH 1653/2058] Add missing file from previous commit --- phlib/include/mapimg.h | 1 + 1 file changed, 1 insertion(+) diff --git a/phlib/include/mapimg.h b/phlib/include/mapimg.h index 30187f189ccb..a32dd4106295 100644 --- a/phlib/include/mapimg.h +++ b/phlib/include/mapimg.h @@ -602,6 +602,7 @@ typedef struct _PH_ELF_IMAGE_SYMBOL_ENTRY }; UCHAR TypeInfo; UCHAR OtherInfo; + ULONG SectionIndex; ULONGLONG Address; ULONGLONG Size; WCHAR Name[MAX_PATH * 2]; From 1c974dbfa147fbe518cb10761aad9c914d5232d7 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 11 Feb 2019 17:35:04 +0100 Subject: [PATCH 1654/2058] Add missing file from commit 2fa2fe0 --- phlib/mapexlf.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/phlib/mapexlf.c b/phlib/mapexlf.c index 5326ba030565..aed2fb818468 100644 --- a/phlib/mapexlf.c +++ b/phlib/mapexlf.c @@ -419,6 +419,7 @@ BOOLEAN PhGetMappedWslImageSymbols( import->Size = entry[ii].st_size; import->TypeInfo = entry[ii].st_info; import->OtherInfo = entry[ii].st_other; + import->SectionIndex = entry[ii].st_shndx; // function name PhCopyStringZFromBytes( @@ -461,6 +462,7 @@ BOOLEAN PhGetMappedWslImageSymbols( export->Size = entry[ii].st_size; export->TypeInfo = entry[ii].st_info; export->OtherInfo = entry[ii].st_other; + export->SectionIndex = entry[ii].st_shndx; // function name PhCopyStringZFromBytes( @@ -483,6 +485,7 @@ BOOLEAN PhGetMappedWslImageSymbols( export->Size = entry[ii].st_size; export->TypeInfo = entry[ii].st_info; export->OtherInfo = entry[ii].st_other; + export->SectionIndex = entry[ii].st_shndx; // function name PhCopyStringZFromBytes( From 7478f7e7302fad9120e24de9f32d9d89e52f6d3f Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 11 Feb 2019 20:47:56 +0100 Subject: [PATCH 1655/2058] Fix some warnings --- phlib/mapimg.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/phlib/mapimg.c b/phlib/mapimg.c index d0c72af5c0c6..d4e94f431b57 100644 --- a/phlib/mapimg.c +++ b/phlib/mapimg.c @@ -1630,7 +1630,7 @@ NTSTATUS PhGetMappedImageResources( for (ULONG i = 0; i < resourceTypeCount; ++i, ++resourceType) { if (!resourceType->DataIsDirectory) - return STATUS_RESOURCE_TYPE_NOT_FOUND; + continue; // return STATUS_RESOURCE_TYPE_NOT_FOUND; nameDirectory = PTR_ADD_OFFSET(resourceDirectory, resourceType->OffsetToDirectory); resourceName = PTR_ADD_OFFSET(nameDirectory, sizeof(IMAGE_RESOURCE_DIRECTORY)); @@ -1639,7 +1639,7 @@ NTSTATUS PhGetMappedImageResources( for (ULONG j = 0; j < resourceNameCount; ++j, ++resourceName) { if (!resourceName->DataIsDirectory) - return STATUS_RESOURCE_NAME_NOT_FOUND; + continue; // return STATUS_RESOURCE_NAME_NOT_FOUND; languageDirectory = PTR_ADD_OFFSET(resourceDirectory, resourceName->OffsetToDirectory); resourceLanguage = PTR_ADD_OFFSET(languageDirectory, sizeof(IMAGE_RESOURCE_DIRECTORY)); @@ -1648,7 +1648,7 @@ NTSTATUS PhGetMappedImageResources( for (ULONG k = 0; k < resourceLanguageCount; ++k, ++resourceLanguage) { if (resourceLanguage->DataIsDirectory) - return STATUS_RESOURCE_DATA_NOT_FOUND; + continue; // return STATUS_RESOURCE_DATA_NOT_FOUND; resourceCount++; } @@ -1754,8 +1754,8 @@ NTSTATUS PhGetMappedImageTlsCallbackDirectory32( else tlsCallbacksOffset = 0; - TlsCallbacks->CallbackIndexes = PhMappedImageRvaToVa(MappedImage, (ULONG)(ULONG_PTR)PTR_SUB_OFFSET(tlsDirectory->AddressOfIndex, tlsCallbacksOffset), NULL); - TlsCallbacks->CallbackAddress = PhMappedImageRvaToVa(MappedImage, (ULONG)(ULONG_PTR)PTR_SUB_OFFSET(tlsDirectory->AddressOfCallBacks, tlsCallbacksOffset), NULL); + TlsCallbacks->CallbackIndexes = PhMappedImageRvaToVa(MappedImage, PtrToUlong(PTR_SUB_OFFSET(tlsDirectory->AddressOfIndex, tlsCallbacksOffset)), NULL); + TlsCallbacks->CallbackAddress = PhMappedImageRvaToVa(MappedImage, PtrToUlong(PTR_SUB_OFFSET(tlsDirectory->AddressOfCallBacks, tlsCallbacksOffset)), NULL); if (TlsCallbacks->CallbackAddress) return STATUS_SUCCESS; @@ -1808,8 +1808,8 @@ NTSTATUS PhGetMappedImageTlsCallbackDirectory64( else tlsCallbacksOffset = 0; - TlsCallbacks->CallbackIndexes = PhMappedImageRvaToVa(MappedImage, (ULONG)(ULONG_PTR)PTR_SUB_OFFSET(tlsDirectory->AddressOfIndex, tlsCallbacksOffset), NULL); - TlsCallbacks->CallbackAddress = PhMappedImageRvaToVa(MappedImage, (ULONG)(ULONG_PTR)PTR_SUB_OFFSET(tlsDirectory->AddressOfCallBacks, tlsCallbacksOffset), NULL); + TlsCallbacks->CallbackIndexes = PhMappedImageRvaToVa(MappedImage, PtrToUlong(PTR_SUB_OFFSET(tlsDirectory->AddressOfIndex, tlsCallbacksOffset)), NULL); + TlsCallbacks->CallbackAddress = PhMappedImageRvaToVa(MappedImage, PtrToUlong(PTR_SUB_OFFSET(tlsDirectory->AddressOfCallBacks, tlsCallbacksOffset)), NULL); if (TlsCallbacks->CallbackAddress) return STATUS_SUCCESS; @@ -1882,7 +1882,7 @@ NTSTATUS PhGetMappedImageTlsCallbacks( for (i = 0; i < count; i++) { - TlsCallbacks->Entries[i].Address = (ULONG_PTR)array[i]; + TlsCallbacks->Entries[i].Address = array[i]; } } From da9a19c0984a92987cef188894f4ff45aa28e77a Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 11 Feb 2019 20:48:11 +0100 Subject: [PATCH 1656/2058] Fix macro usage --- phlib/basesup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phlib/basesup.c b/phlib/basesup.c index ca03dd5509c1..ca60555b2c76 100644 --- a/phlib/basesup.c +++ b/phlib/basesup.c @@ -970,7 +970,7 @@ BOOLEAN PhCopyStringZFromMultiByte( if (NT_SUCCESS(status)) { // RtlMultiByteToUnicodeN doesn't null terminate the string. - *(PWCHAR)PTR_ADD_OFFSET(OutputBuffer, unicodeBytes) = 0; + *(PWCHAR)PTR_ADD_OFFSET(OutputBuffer, unicodeBytes) = UNICODE_NULL; copied = TRUE; } else From 95ea07dc63308e6fe674afe8a4ae411f18ef0f92 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 11 Feb 2019 21:49:16 +0100 Subject: [PATCH 1657/2058] Fix types --- phlib/include/mapimg.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/phlib/include/mapimg.h b/phlib/include/mapimg.h index a32dd4106295..38865136966a 100644 --- a/phlib/include/mapimg.h +++ b/phlib/include/mapimg.h @@ -428,8 +428,8 @@ PhGetMappedImageResources( typedef struct _PH_IMAGE_TLS_CALLBACK_ENTRY { - ULONG_PTR Index; - ULONG_PTR Address; + ULONGLONG Index; + ULONGLONG Address; } PH_IMAGE_TLS_CALLBACK_ENTRY, *PPH_IMAGE_TLS_CALLBACK_ENTRY; typedef struct _PH_MAPPED_IMAGE_TLS_CALLBACKS From d9350c4d9f221485f67c2a84e4068838df6cb495 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 11 Feb 2019 21:56:05 +0100 Subject: [PATCH 1658/2058] peview: Improve TLS symbol lookup --- tools/peview/tlsprp.c | 30 ++++++++---------------------- 1 file changed, 8 insertions(+), 22 deletions(-) diff --git a/tools/peview/tlsprp.c b/tools/peview/tlsprp.c index cb17ce401890..deadbe1e36ca 100644 --- a/tools/peview/tlsprp.c +++ b/tools/peview/tlsprp.c @@ -49,28 +49,14 @@ VOID PvpPeEnumerateTlsCallbacks( PhPrintPointer(pointer, (PVOID)(ULONG_PTR)entry.Address); PhSetListViewSubItem(ListViewHandle, lvItemIndex, 1, pointer); - if (PvMappedImage.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) - { - symbol = PhGetSymbolFromAddress( - PvSymbolProvider, - (ULONG64)ULongToPtr((ULONG)entry.Address), - NULL, - NULL, - &symbolName, - NULL - ); - } - else - { - symbol = PhGetSymbolFromAddress( - PvSymbolProvider, - (ULONG64)(ULONGLONG)entry.Address, - NULL, - NULL, - &symbolName, - NULL - ); - } + symbol = PhGetSymbolFromAddress( + PvSymbolProvider, + (ULONG64)entry.Address, + NULL, + NULL, + &symbolName, + NULL + ); if (symbolName) { From 2a4787558c263f474541ce9d52e7573da1219310 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 11 Feb 2019 21:56:37 +0100 Subject: [PATCH 1659/2058] peview: Add enclave load config information --- tools/peview/ldprp.c | 151 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 143 insertions(+), 8 deletions(-) diff --git a/tools/peview/ldprp.c b/tools/peview/ldprp.c index 29a790bb0c9f..f9ec7a00403e 100644 --- a/tools/peview/ldprp.c +++ b/tools/peview/ldprp.c @@ -3,7 +3,7 @@ * PE viewer * * Copyright (C) 2010-2011 wj32 - * Copyright (C) 2017-2018 dmex + * Copyright (C) 2017-2019 dmex * * This file is part of Process Hacker. * @@ -23,6 +23,13 @@ #include +#define ADD_VALUE(Name, Value) \ +{ \ + INT lvItemIndex; \ + lvItemIndex = PhAddListViewItem(lvHandle, MAXINT, Name, NULL); \ + PhSetListViewSubItem(lvHandle, lvItemIndex, 1, Value); \ +} + PPH_STRING PvpGetPeGuardFlagsText( _In_ ULONG GuardFlags ) @@ -58,6 +65,139 @@ PPH_STRING PvpGetPeGuardFlagsText( return PhFinalStringBuilderString(&stringBuilder); } +PPH_STRING PvpGetPeEnclaveImportsText( + _In_ PVOID EnclaveConfig + ) +{ + PH_STRING_BUILDER stringBuilder; + ULONG i; + + PhInitializeStringBuilder(&stringBuilder, 10); + + if (PvMappedImage.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) + { + PIMAGE_ENCLAVE_CONFIG32 enclaveConfig32 = EnclaveConfig; + PIMAGE_ENCLAVE_IMPORT enclaveImports; + + enclaveImports = PhMappedImageRvaToVa( + &PvMappedImage, + enclaveConfig32->ImportList, + NULL + ); + + for (i = 0; i < enclaveConfig32->NumberOfImports; i++) + { + PSTR importName; + + if (enclaveImports->ImportName == USHRT_MAX) + break; + + if (importName = PhMappedImageRvaToVa( + &PvMappedImage, + enclaveImports->ImportName, + NULL + )) + { + PhAppendFormatStringBuilder(&stringBuilder, L"%hs, ", importName); + } + + enclaveImports++; + } + } + else + { + PIMAGE_ENCLAVE_CONFIG64 enclaveConfig64 = EnclaveConfig; + PIMAGE_ENCLAVE_IMPORT enclaveImports; + + enclaveImports = PhMappedImageRvaToVa( + &PvMappedImage, + enclaveConfig64->ImportList, + NULL + ); + + for (i = 0; i < enclaveConfig64->NumberOfImports; i++) + { + PSTR importName; + + if (enclaveImports->ImportName == USHRT_MAX) + break; + + if (importName = PhMappedImageRvaToVa( + &PvMappedImage, + enclaveImports->ImportName, + NULL + )) + { + PhAppendFormatStringBuilder(&stringBuilder, L"%hs, ", importName); + } + + enclaveImports++; + } + } + + if (PhEndsWithString2(stringBuilder.String, L", ", FALSE)) + PhRemoveEndStringBuilder(&stringBuilder, 2); + + return PhFinalStringBuilderString(&stringBuilder); +} + +VOID PvpAddPeEnclaveConfig( + _In_ PVOID ImageConfig, + _In_ HWND lvHandle + ) +{ + if (PvMappedImage.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) + { + PIMAGE_LOAD_CONFIG_DIRECTORY32 imageConfig32 = ImageConfig; + PIMAGE_ENCLAVE_CONFIG32 enclaveConfig; + + enclaveConfig = PhMappedImageRvaToVa( + &PvMappedImage, + PtrToUlong(PTR_SUB_OFFSET(imageConfig32->EnclaveConfigurationPointer, PvMappedImage.NtHeaders32->OptionalHeader.ImageBase)), + NULL + ); + + if (enclaveConfig) + { + ADD_VALUE(L"Enclave PolicyFlags", PhaFormatUInt64(enclaveConfig->PolicyFlags, TRUE)->Buffer); + ADD_VALUE(L"Enclave FamilyID", PH_AUTO_T(PH_STRING, PhFormatGuid((PGUID)enclaveConfig->FamilyID))->Buffer); + ADD_VALUE(L"Enclave ImageID", PH_AUTO_T(PH_STRING, PhFormatGuid((PGUID)enclaveConfig->ImageID))->Buffer); + ADD_VALUE(L"Enclave ImageVersion", PhaFormatUInt64(enclaveConfig->ImageVersion, TRUE)->Buffer); + ADD_VALUE(L"Enclave SecurityVersion", PhaFormatUInt64(enclaveConfig->SecurityVersion, TRUE)->Buffer); + ADD_VALUE(L"Enclave EnclaveSize", PhaFormatUInt64(enclaveConfig->EnclaveSize, TRUE)->Buffer); + ADD_VALUE(L"Enclave NumberOfThreads", PhaFormatUInt64(enclaveConfig->NumberOfThreads, TRUE)->Buffer); + ADD_VALUE(L"Enclave EnclaveFlags", PhaFormatUInt64(enclaveConfig->EnclaveFlags, TRUE)->Buffer); + ADD_VALUE(L"Enclave NumberOfImports", PhaFormatUInt64(enclaveConfig->NumberOfImports, TRUE)->Buffer); + ADD_VALUE(L"Enclave Imports", PH_AUTO_T(PH_STRING, PvpGetPeEnclaveImportsText(enclaveConfig))->Buffer); + } + } + else + { + PIMAGE_LOAD_CONFIG_DIRECTORY64 imageConfig64 = ImageConfig; + PIMAGE_ENCLAVE_CONFIG64 enclaveConfig; + + enclaveConfig = PhMappedImageRvaToVa( + &PvMappedImage, + PtrToUlong(PTR_SUB_OFFSET(imageConfig64->EnclaveConfigurationPointer, PvMappedImage.NtHeaders->OptionalHeader.ImageBase)), + NULL + ); + + if (enclaveConfig) + { + ADD_VALUE(L"Enclave PolicyFlags", PhaFormatUInt64(enclaveConfig->PolicyFlags, TRUE)->Buffer); + ADD_VALUE(L"Enclave FamilyID", PH_AUTO_T(PH_STRING, PhFormatGuid((PGUID)enclaveConfig->FamilyID))->Buffer); + ADD_VALUE(L"Enclave ImageID", PH_AUTO_T(PH_STRING, PhFormatGuid((PGUID)enclaveConfig->ImageID))->Buffer); + ADD_VALUE(L"Enclave ImageVersion", PhaFormatUInt64(enclaveConfig->ImageVersion, TRUE)->Buffer); + ADD_VALUE(L"Enclave SecurityVersion", PhaFormatUInt64(enclaveConfig->SecurityVersion, TRUE)->Buffer); + ADD_VALUE(L"Enclave EnclaveSize", PhaFormatUInt64(enclaveConfig->EnclaveSize, TRUE)->Buffer); + ADD_VALUE(L"Enclave NumberOfThreads", PhaFormatUInt64(enclaveConfig->NumberOfThreads, TRUE)->Buffer); + ADD_VALUE(L"Enclave EnclaveFlags", PhaFormatUInt64(enclaveConfig->EnclaveFlags, TRUE)->Buffer); + ADD_VALUE(L"Enclave NumberOfImports", PhaFormatUInt64(enclaveConfig->NumberOfImports, TRUE)->Buffer); + ADD_VALUE(L"Enclave Imports", PH_AUTO_T(PH_STRING, PvpGetPeEnclaveImportsText(enclaveConfig))->Buffer); + } + } +} + INT_PTR CALLBACK PvpPeLoadConfigDlgProc( _In_ HWND hwndDlg, _In_ UINT uMsg, @@ -87,13 +227,6 @@ INT_PTR CALLBACK PvpPeLoadConfigDlgProc( PhSetExtendedListView(lvHandle); PhLoadListViewColumnsFromSetting(L"ImageLoadCfgListViewColumns", lvHandle); - #define ADD_VALUE(Name, Value) \ - { \ - INT lvItemIndex; \ - lvItemIndex = PhAddListViewItem(lvHandle, MAXINT, Name, NULL); \ - PhSetListViewSubItem(lvHandle, lvItemIndex, 1, Value); \ - } - #define ADD_VALUES(Type, Config) \ { \ LARGE_INTEGER time; \ @@ -175,6 +308,7 @@ INT_PTR CALLBACK PvpPeLoadConfigDlgProc( if (NT_SUCCESS(PhGetMappedImageLoadConfig32(&PvMappedImage, &config32))) { ADD_VALUES(IMAGE_LOAD_CONFIG_DIRECTORY32, config32); + PvpAddPeEnclaveConfig(config32, lvHandle); } } else @@ -182,6 +316,7 @@ INT_PTR CALLBACK PvpPeLoadConfigDlgProc( if (NT_SUCCESS(PhGetMappedImageLoadConfig64(&PvMappedImage, &config64))) { ADD_VALUES(IMAGE_LOAD_CONFIG_DIRECTORY64, config64); + PvpAddPeEnclaveConfig(config64, lvHandle); } } From ae20121fc85d52226d1d37eea39082911a72e004 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 12 Feb 2019 19:02:03 +0100 Subject: [PATCH 1660/2058] Add PhQueryAttributesFileWin32 --- phlib/include/phnative.h | 8 ++++++++ phlib/native.c | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/phlib/include/phnative.h b/phlib/include/phnative.h index 30b7ce4a7ef6..fb8b69b61ae1 100644 --- a/phlib/include/phnative.h +++ b/phlib/include/phnative.h @@ -1241,6 +1241,14 @@ PhQueryFullAttributesFileWin32( _Out_ PFILE_NETWORK_OPEN_INFORMATION FileInformation ); +PHLIBAPI +NTSTATUS +NTAPI +PhQueryAttributesFileWin32( + _In_ PWSTR FileName, + _Out_ PFILE_BASIC_INFORMATION FileInformation + ); + PHLIBAPI NTSTATUS NTAPI diff --git a/phlib/native.c b/phlib/native.c index a481ca04283f..55d43b7bb4de 100644 --- a/phlib/native.c +++ b/phlib/native.c @@ -7145,6 +7145,38 @@ NTSTATUS PhQueryFullAttributesFileWin32( return status; } +NTSTATUS PhQueryAttributesFileWin32( + _In_ PWSTR FileName, + _Out_ PFILE_BASIC_INFORMATION FileInformation + ) +{ + NTSTATUS status; + UNICODE_STRING fileName; + OBJECT_ATTRIBUTES oa; + + if (!NT_SUCCESS(status = RtlDosPathNameToNtPathName_U_WithStatus( + FileName, + &fileName, + NULL, + NULL + ))) + return status; + + InitializeObjectAttributes( + &oa, + &fileName, + OBJ_CASE_INSENSITIVE, + NULL, + NULL + ); + + status = NtQueryAttributesFile(&oa, FileInformation); + + RtlFreeUnicodeString(&fileName); + + return status; +} + /** * Deletes a file. * From 5b64e80c70697dede17a5b288842ee382320814c Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 12 Feb 2019 19:07:09 +0100 Subject: [PATCH 1661/2058] Fix PhSearchFilePath maxpath limitations --- ProcessHacker/mainwnd.c | 2 +- phlib/include/phutil.h | 5 ++- phlib/util.c | 79 +++++++++++++++++++++-------------------- 3 files changed, 43 insertions(+), 43 deletions(-) diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index 7ec8bf1857fe..6e82632139c7 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -1879,7 +1879,7 @@ BOOLEAN PhMwpOnNotify( PPH_STRING filePathString; // The user typed a name without a path so attempt to locate the executable. - if (PhSearchFilePath(fileName->Buffer, L".exe", &filePathString)) + if (filePathString = PhSearchFilePath(fileName->Buffer, L".exe")) PhMoveReference(&fileName, filePathString); else PhClearReference(&fileName); diff --git a/phlib/include/phutil.h b/phlib/include/phutil.h index d16f07b17d52..e8141b72fb3e 100644 --- a/phlib/include/phutil.h +++ b/phlib/include/phutil.h @@ -1105,12 +1105,11 @@ PhParseCommandLineFuzzy( ); PHLIBAPI -BOOLEAN +PPH_STRING NTAPI PhSearchFilePath( _In_ PWSTR FileName, - _In_opt_ PWSTR Extension, - _Out_ PPH_STRING *FilePath + _In_opt_ PWSTR Extension ); PHLIBAPI diff --git a/phlib/util.c b/phlib/util.c index 2b987b1bcf90..987219782726 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -2691,7 +2691,7 @@ NTSTATUS PhCreateProcessWin32Ex( PPH_STRING filePathSr; // The user typed a name without a path so attempt to locate the executable. - if (PhSearchFilePath(fileName->Buffer, L".exe", &filePathSr)) + if (filePathSr = PhSearchFilePath(fileName->Buffer, L".exe")) PhMoveReference(&fileName, filePathSr); else PhClearReference(&fileName); @@ -5017,7 +5017,7 @@ BOOLEAN PhParseCommandLineFuzzy( tempCommandLine = PhCreateString2(&commandLine); - if (PhSearchFilePath(tempCommandLine->Buffer, L".exe", &filePathSr)) + if (filePathSr = PhSearchFilePath(tempCommandLine->Buffer, L".exe")) { *FullFileName = filePathSr; } @@ -5073,7 +5073,7 @@ BOOLEAN PhParseCommandLineFuzzy( if (result) { FileName->Buffer = commandLine.Buffer; - FileName->Length = ((PCHAR)currentPart.Buffer - (PCHAR)temp.Buffer) + currentPart.Length; + FileName->Length = (SIZE_T)PTR_SUB_OFFSET(currentPart.Buffer, temp.Buffer) + currentPart.Length; PhTrimStringRef(&remainingPart, &whitespace, PH_TRIM_START_ONLY); *Arguments = remainingPart; @@ -5100,61 +5100,62 @@ BOOLEAN PhParseCommandLineFuzzy( return FALSE; } -BOOLEAN PhSearchFilePath( +PPH_STRING PhSearchFilePath( _In_ PWSTR FileName, - _In_opt_ PWSTR Extension, - _Out_ PPH_STRING *FilePath + _In_opt_ PWSTR Extension ) { - NTSTATUS status; - ULONG bufferLength; - UNICODE_STRING fileNameUs; - OBJECT_ATTRIBUTES objectAttributes; + PPH_STRING fullPath; + ULONG bufferSize; + ULONG returnLength; FILE_BASIC_INFORMATION basicInfo; - WCHAR buffer[MAX_PATH + 1] = L""; - bufferLength = SearchPath( + bufferSize = MAX_PATH; + fullPath = PhCreateStringEx(NULL, bufferSize * sizeof(WCHAR)); + + returnLength = SearchPath( NULL, FileName, Extension, - MAX_PATH, - buffer, + (ULONG)fullPath->Length / sizeof(WCHAR), + fullPath->Buffer, NULL ); - if (bufferLength == 0 && bufferLength <= MAX_PATH) - return FALSE; - - // Make sure this is not a directory. + if (returnLength == 0 && returnLength <= MAX_PATH) + goto CleanupExit; - if (!NT_SUCCESS(RtlDosPathNameToNtPathName_U_WithStatus( - buffer, - &fileNameUs, - NULL, - NULL - ))) + if (returnLength > bufferSize) { - return FALSE; + bufferSize = returnLength; + PhDereferenceObject(fullPath); + fullPath = PhCreateStringEx(NULL, bufferSize * sizeof(WCHAR)); + + returnLength = SearchPath( + NULL, + FileName, + Extension, + (ULONG)fullPath->Length / sizeof(WCHAR), + fullPath->Buffer, + NULL + ); } - InitializeObjectAttributes( - &objectAttributes, - &fileNameUs, - OBJ_CASE_INSENSITIVE, - NULL, - NULL - ); + if (returnLength == 0 && returnLength <= MAX_PATH) + goto CleanupExit; - status = NtQueryAttributesFile(&objectAttributes, &basicInfo); - RtlFreeUnicodeString(&fileNameUs); + // Make sure this is not a directory. - if (!NT_SUCCESS(status)) - return FALSE; + if (!NT_SUCCESS(PhQueryAttributesFileWin32(fullPath->Buffer, &basicInfo))) + goto CleanupExit; if (basicInfo.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) - return FALSE; + goto CleanupExit; - *FilePath = PhCreateString(buffer); - return TRUE; + return fullPath; + +CleanupExit: + PhDereferenceObject(fullPath); + return NULL; } PPH_STRING PhCreateCacheFile( From faf40f07df315f0413949e935a85b15ffc6e39ea Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 12 Feb 2019 19:11:25 +0100 Subject: [PATCH 1662/2058] Fix previous commit --- phlib/util.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/phlib/util.c b/phlib/util.c index 987219782726..2c167df1efb2 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -5053,7 +5053,6 @@ BOOLEAN PhParseCommandLineFuzzy( while (remainingPart.Length != 0) { BOOLEAN found; - BOOLEAN result; found = PhSplitStringRefAtChar(&remainingPart, ' ', ¤tPart, &remainingPart); @@ -5063,14 +5062,14 @@ BOOLEAN PhParseCommandLineFuzzy( *(remainingPart.Buffer - 1) = 0; } - result = PhSearchFilePath(temp.Buffer, L".exe", &filePathSr); + filePathSr = PhSearchFilePath(temp.Buffer, L".exe"); if (found) { *(remainingPart.Buffer - 1) = originalChar; } - if (result) + if (filePathSr) { FileName->Buffer = commandLine.Buffer; FileName->Length = (SIZE_T)PTR_SUB_OFFSET(currentPart.Buffer, temp.Buffer) + currentPart.Length; @@ -5122,7 +5121,7 @@ PPH_STRING PhSearchFilePath( NULL ); - if (returnLength == 0 && returnLength <= MAX_PATH) + if (returnLength == 0 && returnLength <= bufferSize) goto CleanupExit; if (returnLength > bufferSize) @@ -5141,7 +5140,7 @@ PPH_STRING PhSearchFilePath( ); } - if (returnLength == 0 && returnLength <= MAX_PATH) + if (returnLength == 0 && returnLength <= bufferSize) goto CleanupExit; // Make sure this is not a directory. From 7fbbdcc0b1de0a195a2b18ddaab4c010cb0fa56d Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 12 Feb 2019 19:30:34 +0100 Subject: [PATCH 1663/2058] peview: Fix imports/exports issues --- tools/peview/expprp.c | 42 ++++++++---- tools/peview/impprp.c | 155 +++++++++++++++++++++++++++++++++++------- 2 files changed, 158 insertions(+), 39 deletions(-) diff --git a/tools/peview/expprp.c b/tools/peview/expprp.c index 368828a583ec..201d76c1e246 100644 --- a/tools/peview/expprp.c +++ b/tools/peview/expprp.c @@ -3,7 +3,7 @@ * PE viewer * * Copyright (C) 2010-2011 wj32 - * Copyright (C) 2017 dmex + * Copyright (C) 2017-2019 dmex * * This file is part of Process Hacker. * @@ -118,16 +118,30 @@ INT_PTR CALLBACK PvpPeExportsDlgProc( if (exportFunction.Function) { PPH_STRING exportName; - + // Try find the export name using symbols. - exportName = PhGetSymbolFromAddress( - PvSymbolProvider, - (ULONG64)PTR_ADD_OFFSET(PvMappedImage.NtHeaders->OptionalHeader.ImageBase, exportFunction.Function), - NULL, - NULL, - NULL, - NULL - ); + if (PvMappedImage.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) + { + exportName = PhGetSymbolFromAddress( + PvSymbolProvider, + (ULONG64)PTR_ADD_OFFSET(PvMappedImage.NtHeaders32->OptionalHeader.ImageBase, exportFunction.Function), + NULL, + NULL, + NULL, + NULL + ); + } + else + { + exportName = PhGetSymbolFromAddress( + PvSymbolProvider, + (ULONG64)PTR_ADD_OFFSET(PvMappedImage.NtHeaders->OptionalHeader.ImageBase, exportFunction.Function), + NULL, + NULL, + NULL, + NULL + ); + } if (exportName) { @@ -158,7 +172,7 @@ INT_PTR CALLBACK PvpPeExportsDlgProc( PhPrintUInt32(number, exportEntry.Ordinal); PhSetListViewSubItem(lvHandle, lvItemIndex, 3, number); - if (exportEntry.Name) // Note: The 'Hint' is only valid for named exports. + if (exportEntry.Name) // Note: The 'Hint' is only valid for named exports. (dmex) { PhPrintUInt32(number, exportEntry.Hint); PhSetListViewSubItem(lvHandle, lvItemIndex, 4, number); @@ -183,10 +197,8 @@ INT_PTR CALLBACK PvpPeExportsDlgProc( { PPH_LAYOUT_ITEM dialogItem; - dialogItem = PvAddPropPageLayoutItem(hwndDlg, hwndDlg, - PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL); - PvAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_LIST), - dialogItem, PH_ANCHOR_ALL); + dialogItem = PvAddPropPageLayoutItem(hwndDlg, hwndDlg, PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL); + PvAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_LIST), dialogItem, PH_ANCHOR_ALL); PvDoPropPageLayout(hwndDlg); diff --git a/tools/peview/impprp.c b/tools/peview/impprp.c index 167d08c47a5b..d8b21a5f0826 100644 --- a/tools/peview/impprp.c +++ b/tools/peview/impprp.c @@ -3,7 +3,7 @@ * PE viewer * * Copyright (C) 2010-2011 wj32 - * Copyright (C) 2017-2018 dmex + * Copyright (C) 2017-2019 dmex * * This file is part of Process Hacker. * @@ -23,6 +23,103 @@ #include +PPH_STRING PvpQueryModuleOrdinalName( + _In_ PPH_STRING FileName, + _In_ USHORT Ordinal + ) +{ + PPH_STRING exportName = NULL; + PH_MAPPED_IMAGE mappedImage; + + if (NT_SUCCESS(PhLoadMappedImage(FileName->Buffer, NULL, TRUE, &mappedImage))) + { + PH_MAPPED_IMAGE_EXPORTS exports; + PH_MAPPED_IMAGE_EXPORT_ENTRY exportEntry; + PH_MAPPED_IMAGE_EXPORT_FUNCTION exportFunction; + ULONG i; + + if (NT_SUCCESS(PhGetMappedImageExports(&exports, &mappedImage))) + { + for (i = 0; i < exports.NumberOfEntries; i++) + { + if ( + NT_SUCCESS(PhGetMappedImageExportEntry(&exports, i, &exportEntry)) && + NT_SUCCESS(PhGetMappedImageExportFunction(&exports, NULL, exportEntry.Ordinal, &exportFunction)) + ) + { + if (exportEntry.Ordinal == Ordinal) + { + if (exportEntry.Name) + { + exportName = PhZeroExtendToUtf16(exportEntry.Name); + + if (exportName->Buffer[0] == '?') + { + PPH_STRING undecoratedName; + + if (undecoratedName = PhUndecorateSymbolName(PvSymbolProvider, exportName->Buffer)) + PhMoveReference(&exportName, undecoratedName); + } + } + else + { + if (exportFunction.Function) + { + PPH_STRING symbolName; + + // Try find the export name using symbols. + if (PvMappedImage.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) + { + symbolName = PhGetSymbolFromAddress( + PvSymbolProvider, + (ULONG64)PTR_ADD_OFFSET(PvMappedImage.NtHeaders32->OptionalHeader.ImageBase, exportFunction.Function), + NULL, + NULL, + NULL, + NULL + ); + } + else + { + symbolName = PhGetSymbolFromAddress( + PvSymbolProvider, + (ULONG64)PTR_ADD_OFFSET(PvMappedImage.NtHeaders->OptionalHeader.ImageBase, exportFunction.Function), + NULL, + NULL, + NULL, + NULL + ); + } + + if (symbolName) + { + static PH_STRINGREF unnamedText = PH_STRINGREF_INIT(L" (unnamed)"); + PH_STRINGREF exportNameText; + PH_STRINGREF firstPart; + PH_STRINGREF secondPart; + + if (PhSplitStringRefAtLastChar(&symbolName->sr, L'!', &firstPart, &secondPart)) + exportNameText = secondPart; + else + exportNameText = symbolName->sr; + + exportName = PhCreateString2(&exportNameText); + } + } + } + + break; + } + } + } + } + + PhUnloadMappedImage(&mappedImage); + } + + return exportName; +} + VOID PvpProcessImports( _In_ HWND ListViewHandle, _In_ PPH_MAPPED_IMAGE_IMPORTS Imports, @@ -83,29 +180,41 @@ VOID PvpProcessImports( PLDR_DATA_TABLE_ENTRY moduleLdrEntry = NULL; PVOID moduleExportAddress = NULL; PVOID importModuleDllBase = NULL; + PPH_STRING exportDllName = NULL; PPH_STRING exportOrdinalName = NULL; PPH_STRING exportSymbolName = NULL; - PPH_STRING baseDirectory; - if (baseDirectory = PhGetBaseDirectory(PvFileName)) + //PPH_STRING baseDirectory; + // + //if (baseDirectory = PhGetBaseDirectory(PvFileName)) + //{ + // static DLL_DIRECTORY_COOKIE (WINAPI *AddDllDirectory_I)( + // _In_ PCWSTR NewDirectory + // ); + // + // if (AddDllDirectory_I = PhGetDllProcedureAddress(L"kernel32.dll", "AddDllDirectory", 0)) + // { + // AddDllDirectory_I(baseDirectory->Buffer); + // } + //} + // + //if (importModuleDllBase = LoadLibraryA(importDll.Name)) + //{ + // moduleLdrEntry = PhFindLoaderEntry(importModuleDllBase, NULL, NULL); + // moduleExportAddress = PhGetDllBaseProcedureAddress(importModuleDllBase, NULL, importEntry.Ordinal); + // exportOrdinalName = PhGetExportNameFromOrdinal(importModuleDllBase, importEntry.Ordinal); + //} + + if (exportDllName = PhConvertUtf8ToUtf16(importDll.Name)) { - static DLL_DIRECTORY_COOKIE (WINAPI *AddDllDirectory_I)( - _In_ PCWSTR NewDirectory - ); + PPH_STRING filePath; - if (AddDllDirectory_I = PhGetDllProcedureAddress(L"kernel32.dll", "AddDllDirectory", 0)) + if (filePath = PhSearchFilePath(exportDllName->Buffer, L".dll")) { - // HACK (dmex) - // Add the parent directory to the search path so we can locate exports from 3rd party binaries. - AddDllDirectory_I(baseDirectory->Buffer); + PhMoveReference(&exportDllName, filePath); } - } - if (importModuleDllBase = LoadLibraryA(importDll.Name)) - { - moduleLdrEntry = PhFindLoaderEntry(importModuleDllBase, NULL, NULL); - moduleExportAddress = PhGetDllBaseProcedureAddress(importModuleDllBase, NULL, importEntry.Ordinal); - exportOrdinalName = PhGetExportNameFromOrdinal(importModuleDllBase, importEntry.Ordinal); + exportOrdinalName = PvpQueryModuleOrdinalName(exportDllName, importEntry.Ordinal); } if (exportOrdinalName) @@ -149,14 +258,14 @@ VOID PvpProcessImports( } else { - name = PhaFormatString(L"(Ordinal %u) [??]", importEntry.Ordinal); + name = PhaFormatString(L"(Ordinal %u)", importEntry.Ordinal); PhSetListViewSubItem(ListViewHandle, lvItemIndex, 2, name->Buffer); } } - PhClearReference(&exportSymbolName); - PhClearReference(&exportOrdinalName); - PhClearReference(&baseDirectory); + if (exportSymbolName) PhDereferenceObject(exportSymbolName); + if (exportOrdinalName) PhDereferenceObject(exportOrdinalName); + if (exportDllName) PhDereferenceObject(exportDllName); } } } @@ -223,10 +332,8 @@ INT_PTR CALLBACK PvpPeImportsDlgProc( { PPH_LAYOUT_ITEM dialogItem; - dialogItem = PvAddPropPageLayoutItem(hwndDlg, hwndDlg, - PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL); - PvAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_LIST), - dialogItem, PH_ANCHOR_ALL); + dialogItem = PvAddPropPageLayoutItem(hwndDlg, hwndDlg, PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL); + PvAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_LIST), dialogItem, PH_ANCHOR_ALL); PvDoPropPageLayout(hwndDlg); From 27d8849bf910bfff3d7fae4fba5bea13b5f14e68 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 12 Feb 2019 19:52:23 +0100 Subject: [PATCH 1664/2058] Update token capabilities --- ProcessHacker/resources/capslist.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/ProcessHacker/resources/capslist.txt b/ProcessHacker/resources/capslist.txt index f0a95a9af18f..d910fe7785a4 100644 --- a/ProcessHacker/resources/capslist.txt +++ b/ProcessHacker/resources/capslist.txt @@ -765,6 +765,7 @@ lpacSessionManagement lpacWebPlatform microphone microsoftEdgeRemoteDebugging +microsoft.eSIMManagement_8wekyb3d8bbwe mixedRealityEnvironmentInternal mmsTransportSystem multiplaneOverlay From cbbea2d12dbad5040c8b31f957d0b61e61d1f227 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 12 Feb 2019 19:59:20 +0100 Subject: [PATCH 1665/2058] BuildTools: Update exported phlib headers --- tools/CustomBuildTool/Source Files/Build.cs | 1 + .../bin/Release/CustomBuildTool.exe | Bin 168448 -> 168448 bytes .../bin/Release/CustomBuildTool.pdb | Bin 85504 -> 85504 bytes 3 files changed, 1 insertion(+) diff --git a/tools/CustomBuildTool/Source Files/Build.cs b/tools/CustomBuildTool/Source Files/Build.cs index 564b2532b288..94558410a073 100644 --- a/tools/CustomBuildTool/Source Files/Build.cs +++ b/tools/CustomBuildTool/Source Files/Build.cs @@ -123,6 +123,7 @@ public static class Build private static readonly string[] phlib_headers = { + "appresolver.h", "circbuf.h", "circbuf_h.h", "cpysave.h", diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe b/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe index e9aa76deb40f409e2638f385e7a8458234e49218..2e91ecb79677763e7550c04afb66ccd5f39f3e5b 100644 GIT binary patch delta 3296 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 jW@pEaUJhc-3+C%m~^@bSm diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb b/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb index 591514433d8ff6cd55055dc738b6d8fc941f40ea..620531b869eb020a928c8cb92944f61e2d0fe1e2 100644 GIT binary patch delta 8036 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 delta 8044 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 From 316432e02df0c72748778c027a661af6f372ffba Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 12 Feb 2019 19:59:34 +0100 Subject: [PATCH 1666/2058] Export PhAppResolverGetAppIdForWindow --- ProcessHacker/ProcessHacker.def | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ProcessHacker/ProcessHacker.def b/ProcessHacker/ProcessHacker.def index c4127b3316b3..bf67ee1ee60f 100644 --- a/ProcessHacker/ProcessHacker.def +++ b/ProcessHacker/ProcessHacker.def @@ -679,3 +679,6 @@ EXPORTS ; cache PhCreateCacheFile PhDeleteCacheFile + +; appresolver + PhAppResolverGetAppIdForWindow From f4e988d82823a65066eecc23bc752b580d468c55 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 12 Feb 2019 20:00:14 +0100 Subject: [PATCH 1667/2058] WindowExplorer: Show window AppId --- plugins/WindowExplorer/WindowExplorer.rc | 10 ---------- plugins/WindowExplorer/wndprp.c | 10 ++++++++++ 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/plugins/WindowExplorer/WindowExplorer.rc b/plugins/WindowExplorer/WindowExplorer.rc index 3e531eb86ff0..4e198db14f90 100644 --- a/plugins/WindowExplorer/WindowExplorer.rc +++ b/plugins/WindowExplorer/WindowExplorer.rc @@ -199,16 +199,6 @@ BEGIN END -///////////////////////////////////////////////////////////////////////////// -// -// AFX_DIALOG_LAYOUT -// - -IDD_WNDGENERAL AFX_DIALOG_LAYOUT -BEGIN - 0 -END - #endif // English (Australia) resources ///////////////////////////////////////////////////////////////////////////// diff --git a/plugins/WindowExplorer/wndprp.c b/plugins/WindowExplorer/wndprp.c index ba92075ae634..3523195ca97e 100644 --- a/plugins/WindowExplorer/wndprp.c +++ b/plugins/WindowExplorer/wndprp.c @@ -23,6 +23,7 @@ #include "wndexp.h" #include "resource.h" +#include #include #include @@ -80,6 +81,7 @@ typedef enum _WINDOW_PROPERTIES_CATEGORY typedef enum _NETADAPTER_DETAILS_INDEX { + WINDOW_PROPERTIES_INDEX_APPID, WINDOW_PROPERTIES_INDEX_TEXT, WINDOW_PROPERTIES_INDEX_THREAD, WINDOW_PROPERTIES_INDEX_RECT, @@ -461,6 +463,7 @@ VOID WepRefreshWindowGeneralInfo( MONITORINFO monitorInfo = { sizeof(MONITORINFO) }; HANDLE processHandle; PPH_STRING fileName = NULL; + PPH_STRING appIdText; HMENU menuHandle; PVOID instanceHandle; PVOID userdataHandle; @@ -554,6 +557,12 @@ VOID WepRefreshWindowGeneralInfo( } WepRefreshWindowGeneralInfoSymbols(ListViewHandle, Context); + + if (PhAppResolverGetAppIdForWindow(Context->WindowHandle, &appIdText)) + { + PhSetListViewSubItem(ListViewHandle, WINDOW_PROPERTIES_INDEX_APPID, 1, appIdText->Buffer); + PhDereferenceObject(appIdText); + } } VOID WepRefreshWindowStyles( @@ -788,6 +797,7 @@ VOID WepGeneralAddListViewItemGroups( PhAddListViewGroup(ListViewHandle, WINDOW_PROPERTIES_CATEGORY_GENERAL, L"General"); PhAddListViewGroup(ListViewHandle, WINDOW_PROPERTIES_CATEGORY_CLASS, L"Class"); + PhAddListViewGroupItem(ListViewHandle, WINDOW_PROPERTIES_CATEGORY_GENERAL, WINDOW_PROPERTIES_INDEX_APPID, L"AppId", NULL); PhAddListViewGroupItem(ListViewHandle, WINDOW_PROPERTIES_CATEGORY_GENERAL, WINDOW_PROPERTIES_INDEX_TEXT, L"Text", NULL); PhAddListViewGroupItem(ListViewHandle, WINDOW_PROPERTIES_CATEGORY_GENERAL, WINDOW_PROPERTIES_INDEX_THREAD, L"Thread", NULL); PhAddListViewGroupItem(ListViewHandle, WINDOW_PROPERTIES_CATEGORY_GENERAL, WINDOW_PROPERTIES_INDEX_RECT, L"Rectangle", NULL); From 5073dfa33c6c19de7fad58d2fdd66da7252629b9 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 12 Feb 2019 20:10:41 +0100 Subject: [PATCH 1668/2058] Fix messagebox window handle check --- phlib/util.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/phlib/util.c b/phlib/util.c index 2c167df1efb2..7c9093c083a1 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -455,7 +455,7 @@ INT PhShowMessage2( if (!message) return -1; - config.dwFlags = TDF_ALLOW_DIALOG_CANCELLATION | (IsWindowVisible(hWnd) ? TDF_POSITION_RELATIVE_TO_WINDOW : 0); + config.dwFlags = TDF_ALLOW_DIALOG_CANCELLATION | ((hWnd && IsWindowVisible(hWnd)) ? TDF_POSITION_RELATIVE_TO_WINDOW : 0) | TDF_SIZE_TO_CONTENT; config.dwCommonButtons = Buttons; config.hwndParent = hWnd; config.pszWindowTitle = PhApplicationName; @@ -628,7 +628,7 @@ BOOLEAN PhShowConfirmMessage( config.hwndParent = hWnd; config.hInstance = PhInstanceHandle; - config.dwFlags = TDF_ALLOW_DIALOG_CANCELLATION | (IsWindowVisible(hWnd) ? TDF_POSITION_RELATIVE_TO_WINDOW : 0); + config.dwFlags = TDF_ALLOW_DIALOG_CANCELLATION | ((hWnd && IsWindowVisible(hWnd)) ? TDF_POSITION_RELATIVE_TO_WINDOW : 0); config.pszWindowTitle = PhApplicationName; config.pszMainIcon = Warning ? TD_WARNING_ICON : TD_INFORMATION_ICON; config.pszMainInstruction = PhaConcatStrings(3, L"Do you want to ", action->Buffer, L"?")->Buffer; From 6de870607311f49ccc0d2206a15e599c84436497 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 12 Feb 2019 20:26:58 +0100 Subject: [PATCH 1669/2058] NetworkTools: Fix tracert hostname lookup --- plugins/NetworkTools/tracert.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/plugins/NetworkTools/tracert.c b/plugins/NetworkTools/tracert.c index 95faab401753..1f880864cdcf 100644 --- a/plugins/NetworkTools/tracert.c +++ b/plugins/NetworkTools/tracert.c @@ -59,6 +59,10 @@ NTSTATUS TracertHostnameLookupCallback( ) { PTRACERT_RESOLVE_WORKITEM resolve = Parameter; + WSADATA winsockStartup; + + if (WSAStartup(WINSOCK_VERSION, &winsockStartup) != ERROR_SUCCESS) + return STATUS_INVALID_PARAMETER; if (resolve->Type == PH_IPV4_NETWORK_TYPE) { @@ -131,6 +135,8 @@ NTSTATUS TracertHostnameLookupCallback( } } + WSACleanup(); + return STATUS_SUCCESS; } @@ -269,11 +275,6 @@ NTSTATUS NetworkTracertThreadStart( IP_FLAG_DF, 0 }; - WSADATA winsockStartup; - - // WSAStartup required by GetNameInfo. - if (WSAStartup(WINSOCK_VERSION, &winsockStartup) != ERROR_SUCCESS) - goto CleanupExit; if (icmpRandString = PhCreateStringEx(NULL, PhGetIntegerSetting(SETTING_NAME_PING_SIZE) * 2 + 2)) { @@ -468,7 +469,6 @@ NTSTATUS NetworkTracertThreadStart( if (icmpEchoBuffer) PhDereferenceObject(icmpEchoBuffer); - WSACleanup(); return STATUS_SUCCESS; } From 4950c866b4c2811b72949c3c9f7f4608d86c10eb Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 12 Feb 2019 20:39:36 +0100 Subject: [PATCH 1670/2058] Update resources --- ProcessHacker/ProcessHacker.rc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ProcessHacker/ProcessHacker.rc b/ProcessHacker/ProcessHacker.rc index df4282cdfe69..78d9bf4e7d45 100644 --- a/ProcessHacker/ProcessHacker.rc +++ b/ProcessHacker/ProcessHacker.rc @@ -212,8 +212,9 @@ BEGIN MENUITEM "&Protected", ID_HANDLE_PROTECTED MENUITEM "&Inherit", ID_HANDLE_INHERIT MENUITEM SEPARATOR - MENUITEM "&Copy\aCtrl+C", ID_HANDLE_COPY MENUITEM "Prope&rties\aEnter", ID_HANDLE_PROPERTIES + MENUITEM SEPARATOR + MENUITEM "&Copy\aCtrl+C", ID_HANDLE_COPY END END @@ -1353,7 +1354,7 @@ STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSM CAPTION "Capabilities" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN - CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,7,256,214 + CONTROL "",IDC_LIST,"PhTreeNew",WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP | 0x32,7,7,256,214,WS_EX_CLIENTEDGE END IDD_TOKATTRIBUTES DIALOGEX 0, 0, 270, 228 From d0f0ee50b53d9e33196c40ed759e0a201ce0b796 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 12 Feb 2019 20:40:47 +0100 Subject: [PATCH 1671/2058] Update token capabilities tab layout --- ProcessHacker/tokprp.c | 466 +++++++++++++++++++++-------------------- 1 file changed, 236 insertions(+), 230 deletions(-) diff --git a/ProcessHacker/tokprp.c b/ProcessHacker/tokprp.c index 8b4c481314f7..1430aed846b8 100644 --- a/ProcessHacker/tokprp.c +++ b/ProcessHacker/tokprp.c @@ -95,6 +95,7 @@ typedef struct _TOKEN_PAGE_CONTEXT PTOKEN_PRIVILEGES Privileges; PTOKEN_GROUPS Capabilities; + ATTRIBUTE_TREE_CONTEXT CapsTreeContext; ATTRIBUTE_TREE_CONTEXT ClaimsTreeContext; ATTRIBUTE_TREE_CONTEXT AuthzTreeContext; } TOKEN_PAGE_CONTEXT, *PTOKEN_PAGE_CONTEXT; @@ -1908,232 +1909,6 @@ INT_PTR CALLBACK PhpTokenAdvancedPageProc( return FALSE; } -//static COLORREF NTAPI PhpTokenCapabilitiesColorFunction( -// _In_ INT Index, -// _In_ PVOID Param, -// _In_opt_ PVOID Context -// ) -//{ -// PSID_AND_ATTRIBUTES sidAndAttributes = Param; -// -// return PhGetGroupAttributesColor(sidAndAttributes->Attributes); -//} - -INT_PTR CALLBACK PhpTokenCapabilitiesPageProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - PTOKEN_PAGE_CONTEXT tokenPageContext; - HWND lvHandle; - - tokenPageContext = PhpTokenPageHeader(hwndDlg, uMsg, wParam, lParam); - - if (!tokenPageContext) - return FALSE; - - lvHandle = GetDlgItem(hwndDlg, IDC_LIST); - - switch (uMsg) - { - case WM_INITDIALOG: - { - HANDLE tokenHandle; - ULONG i; - - PhSetListViewStyle(lvHandle, FALSE, TRUE); - PhSetControlTheme(lvHandle, L"explorer"); - PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 160, L"Name"); - //PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 200, L"Flags"); - PhSetExtendedListView(lvHandle); - //ExtendedListView_SetItemColorFunction(lvHandle, PhpTokenCapabilitiesColorFunction); - - if (NT_SUCCESS(tokenPageContext->OpenObject( - &tokenHandle, - TOKEN_QUERY, - tokenPageContext->Context - ))) - { - if (NT_SUCCESS(PhQueryTokenVariableSize(tokenHandle, TokenCapabilities, &tokenPageContext->Capabilities))) - { - for (i = 0; i < tokenPageContext->Capabilities->GroupCount; i++) - { - INT lvItemIndex; - PPH_STRING name; - //PPH_STRING attributesString; - - name = PhGetCapabilitySidName(tokenPageContext->Capabilities->Groups[i].Sid); - - if (!name) - { - ULONG subAuthoritiesCount; - ULONG subAuthority; - - subAuthoritiesCount = *RtlSubAuthorityCountSid(tokenPageContext->Capabilities->Groups[i].Sid); - subAuthority = *RtlSubAuthoritySid(tokenPageContext->Capabilities->Groups[i].Sid, 0); - - // RtlIdentifierAuthoritySid(tokenPageContext->Capabilities->Groups[i].Sid) == (BYTE[])SECURITY_APP_PACKAGE_AUTHORITY - if (subAuthority == SECURITY_CAPABILITY_BASE_RID) - { - if (subAuthoritiesCount == SECURITY_APP_PACKAGE_RID_COUNT) - { - PTOKEN_APPCONTAINER_INFORMATION appContainerInfo; - - //if (*RtlSubAuthoritySid(tokenPageContext->Capabilities->Groups[i].Sid, 1) == SECURITY_CAPABILITY_APP_RID) - // continue; - - if (NT_SUCCESS(PhQueryTokenVariableSize(tokenHandle, TokenAppContainerSid, &appContainerInfo))) - { - if (appContainerInfo->TokenAppContainer) - { - if (PhIsPackageCapabilitySid(appContainerInfo->TokenAppContainer, tokenPageContext->Capabilities->Groups[i].Sid)) - { - HANDLE processHandle; - - if (NT_SUCCESS(PhOpenProcess(&processHandle, PROCESS_QUERY_LIMITED_INFORMATION, (HANDLE)tokenPageContext->Context))) - { - name = PhGetProcessPackageFullName(processHandle); - NtClose(processHandle); - } - } - } - - PhFree(appContainerInfo); - } - } - else if (subAuthoritiesCount == SECURITY_CAPABILITY_RID_COUNT) - { - PPH_STRING capabilityName; - GUID capabilityGuid; - ULONG firstPart; - ULONG secondPart; - ULONG thirdPart; - ULONG lastPart; - - firstPart = *RtlSubAuthoritySid(tokenPageContext->Capabilities->Groups[i].Sid, 1); - secondPart = *RtlSubAuthoritySid(tokenPageContext->Capabilities->Groups[i].Sid, 2); - thirdPart = *RtlSubAuthoritySid(tokenPageContext->Capabilities->Groups[i].Sid, 3); - lastPart = *RtlSubAuthoritySid(tokenPageContext->Capabilities->Groups[i].Sid, 4); - - capabilityGuid.Data1 = firstPart; - capabilityGuid.Data2 = LOWORD(secondPart); - capabilityGuid.Data3 = HIWORD(secondPart); - *((PULONG)&capabilityGuid.Data4[0]) = thirdPart; - *((PULONG)&capabilityGuid.Data4[4]) = lastPart; - - if (name = PhFormatGuid(&capabilityGuid)) - { - if (capabilityName = PhGetCapabilityGuidName(name)) - { - PhMoveReference(&name, capabilityName); - } - } - } - } - } - - if (!name) - name = PhGetSidFullName(tokenPageContext->Capabilities->Groups[i].Sid, TRUE, NULL); - - if (!name) - name = PhSidToStringSid(tokenPageContext->Capabilities->Groups[i].Sid); - - if (name) - { - lvItemIndex = PhAddListViewItem(lvHandle, MAXINT, name->Buffer, &tokenPageContext->Capabilities->Groups[i]); - //attributesString = PhGetGroupAttributesString(tokenPageContext->Capabilities->Groups[i].Attributes, FALSE); - //PhSetListViewSubItem(lvHandle, lvItemIndex, 1, attributesString->Buffer); - //PhDereferenceObject(attributesString); - PhDereferenceObject(name); - } - } - - ExtendedListView_SortItems(lvHandle); - } - - NtClose(tokenHandle); - } - - ExtendedListView_SetColumnWidth(lvHandle, 0, ELVSCW_AUTOSIZE_REMAININGSPACE); - - PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport); - } - break; - case WM_DESTROY: - { - PhFree(tokenPageContext->Capabilities); - tokenPageContext->Capabilities = NULL; - } - break; - case WM_NOTIFY: - { - PhHandleListViewNotifyBehaviors(lParam, lvHandle, PH_LIST_VIEW_DEFAULT_1_BEHAVIORS); - } - break; - case WM_CONTEXTMENU: - { - if ((HWND)wParam == lvHandle) - { - POINT point; - PPH_EMENU menu; - PPH_EMENU item; - PVOID *listviewItems; - ULONG numberOfItems; - - point.x = GET_X_LPARAM(lParam); - point.y = GET_Y_LPARAM(lParam); - - if (point.x == -1 && point.y == -1) - PhGetListViewContextMenuPoint((HWND)wParam, &point); - - PhGetSelectedListViewItemParams(lvHandle, &listviewItems, &numberOfItems); - - if (numberOfItems != 0) - { - menu = PhCreateEMenu(); - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, IDC_COPY, L"&Copy", NULL, NULL), ULONG_MAX); - PhInsertCopyListViewEMenuItem(menu, IDC_COPY, lvHandle); - - item = PhShowEMenu( - menu, - hwndDlg, - PH_EMENU_SHOW_SEND_COMMAND | PH_EMENU_SHOW_LEFTRIGHT, - PH_ALIGN_LEFT | PH_ALIGN_TOP, - point.x, - point.y - ); - - if (item && item->Id != ULONG_MAX) - { - if (!PhHandleCopyListViewEMenuItem(item)) - { - switch (item->Id) - { - case IDC_COPY: - { - PhCopyListView(lvHandle); - } - break; - } - } - } - - PhDestroyEMenu(menu); - } - - PhFree(listviewItems); - } - } - break; - } - - REFLECT_MESSAGE_DLG(hwndDlg, lvHandle, uMsg, wParam, lParam); - - return FALSE; -} - BOOLEAN NTAPI PhpAttributeTreeNewCallback( _In_ HWND hwnd, _In_ PH_TREENEW_MESSAGE Message, @@ -2314,6 +2089,241 @@ VOID PhpDeleteAttributeTreeContext( PhDereferenceObject(Context->RootList); } +//static COLORREF NTAPI PhpTokenCapabilitiesColorFunction( +// _In_ INT Index, +// _In_ PVOID Param, +// _In_opt_ PVOID Context +// ) +//{ +// PSID_AND_ATTRIBUTES sidAndAttributes = Param; +// +// return PhGetGroupAttributesColor(sidAndAttributes->Attributes); +//} + +BOOLEAN PhpAddTokenCapabilities( + _In_ PTOKEN_PAGE_CONTEXT TokenPageContext, + _In_ HWND tnHandle + ) +{ + HANDLE tokenHandle; + ULONG i; + + if (!NT_SUCCESS(TokenPageContext->OpenObject( + &tokenHandle, + TOKEN_QUERY, + TokenPageContext->Context + ))) + return FALSE; + + if (NT_SUCCESS(PhQueryTokenVariableSize(tokenHandle, TokenCapabilities, &TokenPageContext->Capabilities))) + { + for (i = 0; i < TokenPageContext->Capabilities->GroupCount; i++) + { + PATTRIBUTE_NODE node; + PPH_STRING name; + ULONG subAuthoritiesCount; + ULONG subAuthority; + + name = PhSidToStringSid(TokenPageContext->Capabilities->Groups[i].Sid); + node = PhpAddAttributeNode(&TokenPageContext->CapsTreeContext, NULL, name); + + if (name = PhGetSidFullName(TokenPageContext->Capabilities->Groups[i].Sid, TRUE, NULL)) + { + PhpAddAttributeNode(&TokenPageContext->CapsTreeContext, node, PhFormatString(L"FullName: %s", PhGetString(name))); + PhDereferenceObject(name); + } + + if (name = PhGetCapabilitySidName(TokenPageContext->Capabilities->Groups[i].Sid)) + { + PhpAddAttributeNode(&TokenPageContext->CapsTreeContext, node, PhFormatString(L"Capability: %s", PhGetString(name))); + PhDereferenceObject(name); + } + + subAuthoritiesCount = *RtlSubAuthorityCountSid(TokenPageContext->Capabilities->Groups[i].Sid); + subAuthority = *RtlSubAuthoritySid(TokenPageContext->Capabilities->Groups[i].Sid, 0); + + // RtlIdentifierAuthoritySid(TokenPageContext->Capabilities->Groups[i].Sid) == (BYTE[])SECURITY_APP_PACKAGE_AUTHORITY + if (subAuthority == SECURITY_CAPABILITY_BASE_RID) + { + if (subAuthoritiesCount == SECURITY_APP_PACKAGE_RID_COUNT) + { + PTOKEN_APPCONTAINER_INFORMATION appContainerInfo; + + //if (*RtlSubAuthoritySid(TokenPageContext->Capabilities->Groups[i].Sid, 1) == SECURITY_CAPABILITY_APP_RID) + // continue; + + if (NT_SUCCESS(PhQueryTokenVariableSize(tokenHandle, TokenAppContainerSid, &appContainerInfo))) + { + if (appContainerInfo->TokenAppContainer) + { + if (PhIsPackageCapabilitySid(appContainerInfo->TokenAppContainer, TokenPageContext->Capabilities->Groups[i].Sid)) + { + HANDLE processHandle; + + if (NT_SUCCESS(PhOpenProcess(&processHandle, PROCESS_QUERY_LIMITED_INFORMATION, (HANDLE)TokenPageContext->Context))) + { + name = PhGetProcessPackageFullName(processHandle); + PhpAddAttributeNode(&TokenPageContext->CapsTreeContext, node, PhFormatString(L"Package: %s", PhGetString(name))); + PhDereferenceObject(name); + + NtClose(processHandle); + } + } + } + + PhFree(appContainerInfo); + } + } + else if (subAuthoritiesCount == SECURITY_CAPABILITY_RID_COUNT) + { + PPH_STRING capabilityName; + GUID capabilityGuid; + ULONG firstPart; + ULONG secondPart; + ULONG thirdPart; + ULONG lastPart; + + firstPart = *RtlSubAuthoritySid(TokenPageContext->Capabilities->Groups[i].Sid, 1); + secondPart = *RtlSubAuthoritySid(TokenPageContext->Capabilities->Groups[i].Sid, 2); + thirdPart = *RtlSubAuthoritySid(TokenPageContext->Capabilities->Groups[i].Sid, 3); + lastPart = *RtlSubAuthoritySid(TokenPageContext->Capabilities->Groups[i].Sid, 4); + + capabilityGuid.Data1 = firstPart; + capabilityGuid.Data2 = LOWORD(secondPart); + capabilityGuid.Data3 = HIWORD(secondPart); + *((PULONG)&capabilityGuid.Data4[0]) = thirdPart; + *((PULONG)&capabilityGuid.Data4[4]) = lastPart; + + if (name = PhFormatGuid(&capabilityGuid)) + { + PhpAddAttributeNode(&TokenPageContext->CapsTreeContext, node, PhFormatString(L"Guid: %s", PhGetString(name))); + + if (capabilityName = PhGetCapabilityGuidName(name)) + { + PhpAddAttributeNode(&TokenPageContext->CapsTreeContext, node, PhFormatString(L"GuidName: %s", PhGetString(capabilityName))); + PhDereferenceObject(capabilityName); + } + + PhDereferenceObject(name); + } + } + } + } + } + + NtClose(tokenHandle); + + return TRUE; +} + +INT_PTR CALLBACK PhpTokenCapabilitiesPageProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + PTOKEN_PAGE_CONTEXT tokenPageContext; + HWND tnHandle; + + tokenPageContext = PhpTokenPageHeader(hwndDlg, uMsg, wParam, lParam); + + if (!tokenPageContext) + return FALSE; + + tnHandle = GetDlgItem(hwndDlg, IDC_LIST); + + switch (uMsg) + { + case WM_INITDIALOG: + { + tokenPageContext->CapsTreeContext.WindowHandle = hwndDlg; + tokenPageContext->CapsTreeContext.NodeList = PhCreateList(10); + tokenPageContext->CapsTreeContext.RootList = PhCreateList(10); + + PhSetControlTheme(tnHandle, L"explorer"); + TreeNew_SetCallback(tnHandle, PhpAttributeTreeNewCallback, &tokenPageContext->CapsTreeContext); + PhAddTreeNewColumnEx2(tnHandle, 0, TRUE, L"Capabilities", 200, PH_ALIGN_LEFT, 0, 0, TN_COLUMN_FLAG_NODPISCALEONADD); + + TreeNew_SetRedraw(tnHandle, FALSE); + PhpAddTokenCapabilities(tokenPageContext, tnHandle); + TreeNew_NodesStructured(tnHandle); + TreeNew_SetRedraw(tnHandle, TRUE); + + PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport); + } + break; + case WM_DESTROY: + { + PhpDeleteAttributeTreeContext(&tokenPageContext->CapsTreeContext); + + if (tokenPageContext->Capabilities) + { + PhFree(tokenPageContext->Capabilities); + tokenPageContext->Capabilities = NULL; + } + } + break; + case WM_SHOWWINDOW: + { + TreeNew_AutoSizeColumn(tnHandle, 0, TN_AUTOSIZE_REMAINING_SPACE); + } + break; + case WM_CONTEXTMENU: + { + PPH_TREENEW_CONTEXT_MENU contextMenuEvent = (PPH_TREENEW_CONTEXT_MENU)lParam; + PPH_EMENU menu; + PPH_EMENU_ITEM selectedItem; + PATTRIBUTE_NODE *attributeObjectNodes = NULL; + ULONG numberOfAttributeObjectNodes = 0; + + PhpGetSelectedAttributeTreeNodes(&tokenPageContext->CapsTreeContext, &attributeObjectNodes, &numberOfAttributeObjectNodes); + + if (numberOfAttributeObjectNodes != 0) + { + menu = PhCreateEMenu(); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, IDC_COPY, L"Copy", NULL, NULL), ULONG_MAX); + PhInsertCopyCellEMenuItem(menu, IDC_COPY, tnHandle, contextMenuEvent->Column); + + selectedItem = PhShowEMenu( + menu, + hwndDlg, + PH_EMENU_SHOW_SEND_COMMAND | PH_EMENU_SHOW_LEFTRIGHT, + PH_ALIGN_LEFT | PH_ALIGN_TOP, + contextMenuEvent->Location.x, + contextMenuEvent->Location.y + ); + + if (selectedItem && selectedItem->Id != ULONG_MAX) + { + if (!PhHandleCopyCellEMenuItem(selectedItem)) + { + switch (selectedItem->Id) + { + case IDC_COPY: + { + PPH_STRING text; + + text = PhGetTreeNewText(tnHandle, 0); + PhSetClipboardString(tnHandle, &text->sr); + PhDereferenceObject(text); + } + break; + } + } + } + + PhDestroyEMenu(menu); + } + + PhFree(attributeObjectNodes); + } + break; + } + + return FALSE; +} + PWSTR PhGetSecurityAttributeTypeString( _In_ USHORT Type ) @@ -2526,8 +2536,6 @@ BOOLEAN PhpAddTokenClaimAttributes( NtClose(tokenHandle); - TreeNew_NodesStructured(tnHandle); - return TRUE; } @@ -2692,8 +2700,6 @@ BOOLEAN PhpAddTokenAttributes( NtClose(tokenHandle); - TreeNew_NodesStructured(tnHandle); - return TRUE; } From 9e927e6931f78a64410b3ffe6782703f037006c9 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 13 Feb 2019 20:12:00 +0100 Subject: [PATCH 1672/2058] Updater: Fix crash #379 --- plugins/Updater/main.c | 6 +++--- plugins/Updater/options.c | 6 ++---- plugins/Updater/page1.c | 8 ++++---- plugins/Updater/page2.c | 4 ++-- plugins/Updater/page3.c | 8 ++++---- plugins/Updater/page4.c | 4 ++-- plugins/Updater/page5.c | 14 ++++++------- plugins/Updater/updater.c | 43 +++++++++++++++++++++++++++++++-------- plugins/Updater/updater.h | 19 +++++++++++++---- plugins/Updater/verify.c | 5 ++--- 10 files changed, 75 insertions(+), 42 deletions(-) diff --git a/plugins/Updater/main.c b/plugins/Updater/main.c index 251a6987195e..129b5a8ab255 100644 --- a/plugins/Updater/main.c +++ b/plugins/Updater/main.c @@ -2,7 +2,7 @@ * Process Hacker Plugins - * Update Checker Plugin * - * Copyright (C) 2011-2016 dmex + * Copyright (C) 2011-2019 dmex * * This file is part of Process Hacker. * @@ -138,10 +138,10 @@ LOGICAL DllMain( &PluginShowOptionsCallbackRegistration ); - PhAddSettings(settings, ARRAYSIZE(settings)); + PhAddSettings(settings, RTL_NUMBER_OF(settings)); } break; } return TRUE; -} \ No newline at end of file +} diff --git a/plugins/Updater/options.c b/plugins/Updater/options.c index 2c71b40d4f82..3535a21b4845 100644 --- a/plugins/Updater/options.c +++ b/plugins/Updater/options.c @@ -2,7 +2,7 @@ * Process Hacker Plugins - * Update Checker Plugin * - * Copyright (C) 2011-2016 dmex + * Copyright (C) 2011-2019 dmex * * This file is part of Process Hacker. * @@ -33,8 +33,6 @@ INT_PTR CALLBACK OptionsDlgProc( { case WM_INITDIALOG: { - PhCenterWindow(hwndDlg, GetParent(hwndDlg)); - if (PhGetIntegerSetting(SETTING_NAME_AUTO_CHECK)) Button_SetCheck(GetDlgItem(hwndDlg, IDC_AUTOCHECKBOX), BST_CHECKED); } @@ -114,4 +112,4 @@ INT_PTR CALLBACK TextDlgProc( } return FALSE; -} \ No newline at end of file +} diff --git a/plugins/Updater/page1.c b/plugins/Updater/page1.c index 584691343fa3..cdf3bb303220 100644 --- a/plugins/Updater/page1.c +++ b/plugins/Updater/page1.c @@ -2,7 +2,7 @@ * Process Hacker Plugins - * Update Checker Plugin * - * Copyright (C) 2016 dmex + * Copyright (C) 2016-2019 dmex * * This file is part of Process Hacker. * @@ -69,7 +69,7 @@ VOID ShowCheckForUpdatesDialog( config.hMainIcon = Context->IconLargeHandle; config.cxWidth = 200; config.pButtons = TaskDialogButtonArray; - config.cButtons = ARRAYSIZE(TaskDialogButtonArray); + config.cButtons = RTL_NUMBER_OF(TaskDialogButtonArray); config.pfCallback = CheckForUpdatesCallbackProc; config.lpCallbackData = (LONG_PTR)Context; @@ -78,5 +78,5 @@ VOID ShowCheckForUpdatesDialog( //config.pszContent = L"The updater will check for new Process Hacker releases and optionally download and install the update.\r\n\r\nClick the check for updates button to continue."; config.pszContent = L"Select \"check for updates\" to continue.\r\n"; - SendMessage(Context->DialogHandle, TDM_NAVIGATE_PAGE, 0, (LPARAM)&config); -} \ No newline at end of file + TaskDialogNavigatePage(Context->DialogHandle, &config); +} diff --git a/plugins/Updater/page2.c b/plugins/Updater/page2.c index c08ba0c50531..9f239ad68e1b 100644 --- a/plugins/Updater/page2.c +++ b/plugins/Updater/page2.c @@ -2,7 +2,7 @@ * Process Hacker Plugins - * Update Checker Plugin * - * Copyright (C) 2016 dmex + * Copyright (C) 2016-2019 dmex * * This file is part of Process Hacker. * @@ -66,5 +66,5 @@ VOID ShowCheckingForUpdatesDialog( config.pszWindowTitle = L"Process Hacker - Updater"; config.pszMainInstruction = L"Checking for new releases..."; - SendMessage(Context->DialogHandle, TDM_NAVIGATE_PAGE, 0, (LPARAM)&config); + TaskDialogNavigatePage(Context->DialogHandle, &config); } diff --git a/plugins/Updater/page3.c b/plugins/Updater/page3.c index 162df7d379e4..91e2eccddc97 100644 --- a/plugins/Updater/page3.c +++ b/plugins/Updater/page3.c @@ -2,7 +2,7 @@ * Process Hacker Plugins - * Update Checker Plugin * - * Copyright (C) 2016 dmex + * Copyright (C) 2016-2019 dmex * * This file is part of Process Hacker. * @@ -75,7 +75,7 @@ VOID ShowAvailableDialog( config.hMainIcon = Context->IconLargeHandle; config.cxWidth = 200; config.pButtons = TaskDialogButtonArray; - config.cButtons = ARRAYSIZE(TaskDialogButtonArray); + config.cButtons = RTL_NUMBER_OF(TaskDialogButtonArray); config.lpCallbackData = (LONG_PTR)Context; config.pfCallback = ShowAvailableCallbackProc; @@ -86,5 +86,5 @@ VOID ShowAvailableDialog( PhGetStringOrEmpty(Context->SetupFileLength) )->Buffer; - SendMessage(Context->DialogHandle, TDM_NAVIGATE_PAGE, 0, (LPARAM)&config); -} \ No newline at end of file + TaskDialogNavigatePage(Context->DialogHandle, &config); +} diff --git a/plugins/Updater/page4.c b/plugins/Updater/page4.c index 1dbe904257cc..3717910302af 100644 --- a/plugins/Updater/page4.c +++ b/plugins/Updater/page4.c @@ -2,7 +2,7 @@ * Process Hacker Plugins - * Update Checker Plugin * - * Copyright (C) 2016 dmex + * Copyright (C) 2016-2019 dmex * * This file is part of Process Hacker. * @@ -73,5 +73,5 @@ VOID ShowProgressDialog( config.pszMainInstruction = PhaFormatString(L"Downloading update %s...", PhGetStringOrEmpty(Context->Version))->Buffer; config.pszContent = L"Downloaded: ~ of ~ (0%)\r\nSpeed: ~ KB/s"; - SendMessage(Context->DialogHandle, TDM_NAVIGATE_PAGE, 0, (LPARAM)&config); + TaskDialogNavigatePage(Context->DialogHandle, &config); } diff --git a/plugins/Updater/page5.c b/plugins/Updater/page5.c index 1feda530db5a..506dafccbd6e 100644 --- a/plugins/Updater/page5.c +++ b/plugins/Updater/page5.c @@ -2,7 +2,7 @@ * Process Hacker Plugins - * Update Checker Plugin * - * Copyright (C) 2016 dmex + * Copyright (C) 2016-2019 dmex * * This file is part of Process Hacker. * @@ -196,13 +196,13 @@ VOID ShowUpdateInstallDialog( config.pfCallback = FinalTaskDialogCallbackProc; config.lpCallbackData = (LONG_PTR)Context; config.pButtons = TaskDialogButtonArray; - config.cButtons = ARRAYSIZE(TaskDialogButtonArray); + config.cButtons = RTL_NUMBER_OF(TaskDialogButtonArray); config.pszWindowTitle = L"Process Hacker - Updater"; config.pszMainInstruction = L"Ready to install update?"; config.pszContent = L"The update has been successfully downloaded and verified.\r\n\r\nClick Install to continue."; - SendMessage(Context->DialogHandle, TDM_NAVIGATE_PAGE, 0, (LPARAM)&config); + TaskDialogNavigatePage(Context->DialogHandle, &config); } VOID ShowLatestVersionDialog( @@ -226,7 +226,7 @@ VOID ShowLatestVersionDialog( // HACK imageDosHeader = (PIMAGE_DOS_HEADER)NtCurrentPeb()->ImageBaseAddress; - imageNtHeader = (PIMAGE_NT_HEADERS)PTR_ADD_OFFSET(imageDosHeader, (ULONG)imageDosHeader->e_lfanew); + imageNtHeader = (PIMAGE_NT_HEADERS)PTR_ADD_OFFSET(imageDosHeader, imageDosHeader->e_lfanew); RtlSecondsSince1970ToTime(imageNtHeader->FileHeader.TimeDateStamp, &time); PhLargeIntegerToLocalSystemTime(&systemTime, &time); @@ -238,7 +238,7 @@ VOID ShowLatestVersionDialog( PhaFormatDateTime(&systemTime)->Buffer )->Buffer; - SendMessage(Context->DialogHandle, TDM_NAVIGATE_PAGE, 0, (LPARAM)&config); + TaskDialogNavigatePage(Context->DialogHandle, &config); } VOID ShowNewerVersionDialog( @@ -263,7 +263,7 @@ VOID ShowNewerVersionDialog( PhGetStringOrEmpty(Context->CurrentVersionString) )->Buffer; - SendMessage(Context->DialogHandle, TDM_NAVIGATE_PAGE, 0, (LPARAM)&config); + TaskDialogNavigatePage(Context->DialogHandle, &config); } VOID ShowUpdateFailedDialog( @@ -318,5 +318,5 @@ VOID ShowUpdateFailedDialog( config.pfCallback = FinalTaskDialogCallbackProc; config.lpCallbackData = (LONG_PTR)Context; - SendMessage(Context->DialogHandle, TDM_NAVIGATE_PAGE, 0, (LPARAM)&config); + TaskDialogNavigatePage(Context->DialogHandle, &config); } diff --git a/plugins/Updater/updater.c b/plugins/Updater/updater.c index c5608851a44e..3a9d94ca8ed7 100644 --- a/plugins/Updater/updater.c +++ b/plugins/Updater/updater.c @@ -452,7 +452,7 @@ NTSTATUS UpdateCheckThread( if (!context->HaveData) { - ShowUpdateFailedDialog(context, FALSE, FALSE); + PostMessage(context->DialogHandle, PH_SHOWERROR, FALSE, FALSE); PhDereferenceObject(context); PhDeleteAutoPool(&autoPool); @@ -462,17 +462,17 @@ NTSTATUS UpdateCheckThread( if (context->CurrentVersion == context->LatestVersion) { // User is running the latest version - ShowLatestVersionDialog(context); + PostMessage(context->DialogHandle, PH_SHOWLATEST, 0, 0); } else if (context->CurrentVersion > context->LatestVersion) { // User is running a newer version - ShowNewerVersionDialog(context); + PostMessage(context->DialogHandle, PH_SHOWNEWEST, 0, 0); } else { // User is running an older version - ShowAvailableDialog(context); + PostMessage(context->DialogHandle, PH_SHOWUPDATE, 0, 0); } PhDereferenceObject(context); @@ -734,20 +734,20 @@ NTSTATUS UpdateDownloadThread( { if (downloadSuccess && hashSuccess && signatureSuccess) { - ShowUpdateInstallDialog(context); + PostMessage(context->DialogHandle, PH_SHOWINSTALL, 0, 0); } else if (downloadSuccess) { if (signatureSuccess) - ShowUpdateFailedDialog(context, TRUE, FALSE); + PostMessage(context->DialogHandle, PH_SHOWERROR, TRUE, FALSE); else if (hashSuccess) - ShowUpdateFailedDialog(context, FALSE, TRUE); + PostMessage(context->DialogHandle, PH_SHOWERROR, FALSE, TRUE); else - ShowUpdateFailedDialog(context, FALSE, FALSE); + PostMessage(context->DialogHandle, PH_SHOWERROR, FALSE, FALSE); } else { - ShowUpdateFailedDialog(context, FALSE, FALSE); + PostMessage(context->DialogHandle, PH_SHOWERROR, FALSE, FALSE); } } @@ -790,6 +790,31 @@ LRESULT CALLBACK TaskDialogSubclassProc( SetForegroundWindow(hwndDlg); } break; + case PH_SHOWLATEST: + { + ShowLatestVersionDialog(context); + } + break; + case PH_SHOWNEWEST: + { + ShowNewerVersionDialog(context); + } + break; + case PH_SHOWUPDATE: + { + ShowAvailableDialog(context); + } + break; + case PH_SHOWINSTALL: + { + ShowUpdateInstallDialog(context); + } + break; + case PH_SHOWERROR: + { + ShowUpdateFailedDialog(context, (BOOLEAN)wParam, (BOOLEAN)lParam); + } + break; //case WM_PARENTNOTIFY: // { // if (wParam == WM_CREATE) diff --git a/plugins/Updater/updater.h b/plugins/Updater/updater.h index 6742f7e2cdf3..5e8e0a747213 100644 --- a/plugins/Updater/updater.h +++ b/plugins/Updater/updater.h @@ -2,7 +2,7 @@ * Process Hacker Plugins - * Update Checker Plugin * - * Copyright (C) 2011-2017 dmex + * Copyright (C) 2011-2019 dmex * * This file is part of Process Hacker. * @@ -37,8 +37,13 @@ #include "resource.h" -#define UPDATE_MENUITEM 1001 -#define PH_SHOWDIALOG (WM_APP + 501) +#define UPDATE_MENUITEM 1001 +#define PH_SHOWDIALOG (WM_APP + 501) +#define PH_SHOWLATEST (WM_APP + 502) +#define PH_SHOWNEWEST (WM_APP + 503) +#define PH_SHOWUPDATE (WM_APP + 504) +#define PH_SHOWINSTALL (WM_APP + 505) +#define PH_SHOWERROR (WM_APP + 506) #define PLUGIN_NAME L"ProcessHacker.UpdateChecker" #define SETTING_NAME_AUTO_CHECK (PLUGIN_NAME L".PromptStart") @@ -100,6 +105,12 @@ typedef struct _PH_UPDATER_CONTEXT PPH_STRING BuildMessage; } PH_UPDATER_CONTEXT, *PPH_UPDATER_CONTEXT; +// TDM_NAVIGATE_PAGE can not be called from other threads without comctl32.dll throwing access violations +// after navigating to the page and you press keys such as ctrl, alt, home and insert. (dmex) +#define TaskDialogNavigatePage(WindowHandle, Config) \ + assert(HandleToUlong(NtCurrentThreadId()) == GetWindowThreadProcessId(WindowHandle, NULL)); \ + SendMessage(WindowHandle, TDM_NAVIGATE_PAGE, 0, (LPARAM)Config); + VOID TaskDialogLinkClicked( _In_ PPH_UPDATER_CONTEXT Context ); @@ -230,4 +241,4 @@ VOID ShowLinkDialog( _In_ PPH_UPDATER_CONTEXT Context ); -#endif \ No newline at end of file +#endif diff --git a/plugins/Updater/verify.c b/plugins/Updater/verify.c index c2fb55e1780c..5bffe8c3aaa1 100644 --- a/plugins/Updater/verify.c +++ b/plugins/Updater/verify.c @@ -2,7 +2,7 @@ * Process Hacker Plugins - * Update Checker Plugin * - * Copyright (C) 2016 dmex + * Copyright (C) 2016-2019 dmex * * This file is part of Process Hacker. * @@ -52,7 +52,6 @@ PUPDATER_HASH_CONTEXT UpdaterInitializeHash( VOID ) { - BOOLEAN success = FALSE; ULONG querySize; PUPDATER_HASH_CONTEXT hashContext; @@ -255,4 +254,4 @@ VOID UpdaterDestroyHash( PhFree(Context->Hash); PhFree(Context); -} \ No newline at end of file +} From 39417f1f9a00674af50d2066b4bedb651cb148e0 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 13 Feb 2019 20:28:27 +0100 Subject: [PATCH 1673/2058] NetworkTools: Fix crash #379 --- plugins/NetworkTools/nettools.h | 15 ++-- plugins/NetworkTools/pages.c | 10 +-- plugins/NetworkTools/update.c | 117 +++++++++++++++++++++++++++----- 3 files changed, 115 insertions(+), 27 deletions(-) diff --git a/plugins/NetworkTools/nettools.h b/plugins/NetworkTools/nettools.h index 8795746a2a4b..f1f1cd75dfde 100644 --- a/plugins/NetworkTools/nettools.h +++ b/plugins/NetworkTools/nettools.h @@ -93,6 +93,7 @@ typedef enum _PH_NETWORK_ACTION MENU_ACTION_COPY, } PH_NETWORK_ACTION; +#define UPDATE_MENUITEM 1005 #define NTM_RECEIVEDTRACE (WM_APP + 1) #define NTM_RECEIVEDWHOIS (WM_APP + 2) #define NTM_RECEIVEDFINISH (WM_APP + 3) @@ -100,7 +101,9 @@ typedef enum _PH_NETWORK_ACTION #define WM_TRACERT_HOSTNAME (WM_APP + 5) #define WM_TRACERT_COUNTRY (WM_APP + 6) -#define UPDATE_MENUITEM 1005 +#define PH_SHOWDIALOG (WM_APP + 10) +#define PH_SHOWINSTALL (WM_APP + 11) +#define PH_SHOWERROR (WM_APP + 12) typedef struct _NETWORK_PING_CONTEXT { @@ -155,6 +158,12 @@ typedef struct _NETWORK_WHOIS_CONTEXT WCHAR IpAddressString[INET6_ADDRSTRLEN + 1]; } NETWORK_WHOIS_CONTEXT, *PNETWORK_WHOIS_CONTEXT; +// TDM_NAVIGATE_PAGE can not be called from other threads without comctl32.dll throwing access violations +// after navigating to the page and you press keys such as ctrl, alt, home and insert. (dmex) +#define TaskDialogNavigatePage(WindowHandle, Config) \ + assert(HandleToUlong(NtCurrentThreadId()) == GetWindowThreadProcessId(WindowHandle, NULL)); \ + SendMessage(WindowHandle, TDM_NAVIGATE_PAGE, 0, (LPARAM)Config); + VOID ShowWhoisWindow( _In_ PPH_NETWORK_ITEM NetworkItem ); @@ -294,14 +303,12 @@ VOID DrawCountryIcon( typedef struct _PH_UPDATER_CONTEXT { - BOOLEAN FixedWindowStyles; HWND DialogHandle; HICON IconSmallHandle; HICON IconLargeHandle; + WNDPROC DefaultWindowProc; PPH_STRING FileDownloadUrl; - PPH_STRING RevVersion; - PPH_STRING Size; } PH_UPDATER_CONTEXT, *PPH_UPDATER_CONTEXT; VOID TaskDialogLinkClicked( diff --git a/plugins/NetworkTools/pages.c b/plugins/NetworkTools/pages.c index 8479aa9886ff..c72b2a4b3faa 100644 --- a/plugins/NetworkTools/pages.c +++ b/plugins/NetworkTools/pages.c @@ -182,7 +182,7 @@ VOID ShowDbCheckForUpdatesDialog( config.pszMainInstruction = L"Download the latest GeoIP database?"; config.pszContent = L"This product includes GeoLite2 data created by MaxMind, available from http://www.maxmind.com\r\n\r\nSelect download to continue."; - SendMessage(Context->DialogHandle, TDM_NAVIGATE_PAGE, 0, (LPARAM)&config); + TaskDialogNavigatePage(Context->DialogHandle, &config); } VOID ShowDbCheckingForUpdatesDialog( @@ -204,7 +204,7 @@ VOID ShowDbCheckingForUpdatesDialog( config.pszMainInstruction = L"Downloading"; config.pszContent = L"Downloaded: ~ of ~ (~%%)\r\nSpeed: ~/s"; - SendMessage(Context->DialogHandle, TDM_NAVIGATE_PAGE, 0, (LPARAM)&config); + TaskDialogNavigatePage(Context->DialogHandle, &config); } VOID ShowDbInstallRestartDialog( @@ -228,7 +228,7 @@ VOID ShowDbInstallRestartDialog( config.pszMainInstruction = L"The GeoIP database has been installed"; config.pszContent = L"You need to restart Process Hacker for the changes to take effect..."; - SendMessage(Context->DialogHandle, TDM_NAVIGATE_PAGE, 0, (LPARAM)&config); + TaskDialogNavigatePage(Context->DialogHandle, &config); } VOID ShowDbUpdateFailedDialog( @@ -251,5 +251,5 @@ VOID ShowDbUpdateFailedDialog( config.pszMainInstruction = L"Error downloading GeoIP database."; config.pszContent = L"Click Retry to download the database again."; - SendMessage(Context->DialogHandle, TDM_NAVIGATE_PAGE, 0, (LPARAM)&config); -} \ No newline at end of file + TaskDialogNavigatePage(Context->DialogHandle, &config); +} diff --git a/plugins/NetworkTools/update.c b/plugins/NetworkTools/update.c index d2d2b5bee767..23258f6c0130 100644 --- a/plugins/NetworkTools/update.c +++ b/plugins/NetworkTools/update.c @@ -2,7 +2,7 @@ * Process Hacker Network Tools - * GeoIP database updater * - * Copyright (C) 2016 dmex + * Copyright (C) 2016-2019 dmex * * This file is part of Process Hacker. * @@ -29,21 +29,36 @@ HWND UpdateDialogHandle = NULL; HANDLE UpdateDialogThreadHandle = NULL; PH_EVENT InitializedEvent = PH_EVENT_INIT; +PPH_OBJECT_TYPE UpdateContextType = NULL; +PH_INITONCE UpdateContextTypeInitOnce = PH_INITONCE_INIT; -VOID FreeUpdateContext( - _In_ _Post_invalid_ PPH_UPDATER_CONTEXT Context +VOID UpdateContextDeleteProcedure( + _In_ PVOID Object, + _In_ ULONG Flags ) { - if (Context->FileDownloadUrl) - PhDereferenceObject(Context->FileDownloadUrl); + PPH_UPDATER_CONTEXT context = Object; - if (Context->RevVersion) - PhDereferenceObject(Context->RevVersion); + if (context->FileDownloadUrl) + PhDereferenceObject(context->FileDownloadUrl); +} + +PPH_UPDATER_CONTEXT CreateUpdateContext( + VOID + ) +{ + PPH_UPDATER_CONTEXT context; + + if (PhBeginInitOnce(&UpdateContextTypeInitOnce)) + { + UpdateContextType = PhCreateObjectType(L"GeoIpContextObjectType", 0, UpdateContextDeleteProcedure); + PhEndInitOnce(&UpdateContextTypeInitOnce); + } - if (Context->Size) - PhDereferenceObject(Context->Size); + context = PhCreateObject(sizeof(PH_UPDATER_CONTEXT), UpdateContextType); + memset(context, 0, sizeof(PH_UPDATER_CONTEXT)); - PhDereferenceObject(Context); + return context; } VOID TaskDialogCreateIcons( @@ -484,11 +499,11 @@ NTSTATUS GeoIPUpdateThread( { if (success) { - ShowDbInstallRestartDialog(context); + PostMessage(context->DialogHandle, PH_SHOWINSTALL, 0, 0); } else { - ShowDbUpdateFailedDialog(context); + PostMessage(context->DialogHandle, PH_SHOWERROR, 0, 0); } } @@ -496,6 +511,56 @@ NTSTATUS GeoIPUpdateThread( return STATUS_SUCCESS; } +LRESULT CALLBACK TaskDialogSubclassProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + PPH_UPDATER_CONTEXT context; + WNDPROC oldWndProc; + + if (!(context = PhGetWindowContext(hwndDlg, UCHAR_MAX))) + return 0; + + oldWndProc = context->DefaultWindowProc; + + switch (uMsg) + { + case WM_DESTROY: + { + SetWindowLongPtr(hwndDlg, GWLP_WNDPROC, (LONG_PTR)oldWndProc); + PhRemoveWindowContext(hwndDlg, UCHAR_MAX); + + PhUnregisterWindowCallback(hwndDlg); + } + break; + case PH_SHOWDIALOG: + { + if (IsMinimized(hwndDlg)) + ShowWindow(hwndDlg, SW_RESTORE); + else + ShowWindow(hwndDlg, SW_SHOW); + + SetForegroundWindow(hwndDlg); + } + break; + case PH_SHOWINSTALL: + { + ShowDbInstallRestartDialog(context); + } + break; + case PH_SHOWERROR: + { + ShowDbUpdateFailedDialog(context); + } + break; + } + + return CallWindowProc(oldWndProc, hwndDlg, uMsg, wParam, lParam); +} + HRESULT CALLBACK TaskDialogBootstrapCallback( _In_ HWND hwndDlg, _In_ UINT uMsg, @@ -518,6 +583,13 @@ HRESULT CALLBACK TaskDialogBootstrapCallback( // Create the Taskdialog icons TaskDialogCreateIcons(context); + PhRegisterWindowCallback(hwndDlg, PH_PLUGIN_WINDOW_EVENT_TYPE_TOPMOST, NULL); + + // Subclass the Taskdialog. + context->DefaultWindowProc = (WNDPROC)GetWindowLongPtr(hwndDlg, GWLP_WNDPROC); + PhSetWindowContext(hwndDlg, UCHAR_MAX, context); + SetWindowLongPtr(hwndDlg, GWLP_WNDPROC, (LONG_PTR)TaskDialogSubclassProc); + ShowDbCheckForUpdatesDialog(context); } break; @@ -532,13 +604,11 @@ NTSTATUS GeoIPUpdateDialogThread( { PH_AUTO_POOL autoPool; PPH_UPDATER_CONTEXT context; - INT result = 0; TASKDIALOGCONFIG config = { sizeof(TASKDIALOGCONFIG) }; PhInitializeAutoPool(&autoPool); - context = (PPH_UPDATER_CONTEXT)PhCreateAlloc(sizeof(PH_UPDATER_CONTEXT)); - memset(context, 0, sizeof(PH_UPDATER_CONTEXT)); + context = CreateUpdateContext(); config.dwFlags = TDF_ALLOW_DIALOG_CANCELLATION | TDF_CAN_BE_MINIMIZED; config.pszContent = L"Initializing..."; @@ -546,9 +616,9 @@ NTSTATUS GeoIPUpdateDialogThread( config.pfCallback = TaskDialogBootstrapCallback; config.hwndParent = Parameter; - TaskDialogIndirect(&config, &result, NULL, NULL); + TaskDialogIndirect(&config, NULL, NULL, NULL); - FreeUpdateContext(context); + PhDereferenceObject(context); PhDeleteAutoPool(&autoPool); return STATUS_SUCCESS; @@ -601,5 +671,16 @@ VOID ShowGeoIPUpdateDialog( _In_opt_ HWND Parent ) { - PhCreateThread2(GeoIPUpdateDialogThread, Parent); + if (!UpdateDialogThreadHandle) + { + if (!(UpdateDialogThreadHandle = PhCreateThread(0, GeoIPUpdateDialogThread, NULL))) + { + PhShowStatus(PhMainWndHandle, L"Unable to create the updater window.", 0, GetLastError()); + return; + } + + PhWaitForEvent(&InitializedEvent, NULL); + } + + PostMessage(UpdateDialogHandle, PH_SHOWDIALOG, 0, 0); } From dc51c36ed9263de69955d9b787741224626e9451 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 13 Feb 2019 20:28:41 +0100 Subject: [PATCH 1674/2058] Add missing copyright --- plugins/Updater/updater.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/Updater/updater.c b/plugins/Updater/updater.c index 3a9d94ca8ed7..ccf83bc83c85 100644 --- a/plugins/Updater/updater.c +++ b/plugins/Updater/updater.c @@ -2,7 +2,7 @@ * Process Hacker Plugins - * Update Checker Plugin * - * Copyright (C) 2011-2017 dmex + * Copyright (C) 2011-2019 dmex * * This file is part of Process Hacker. * From bf30fcf09bd217fba27d97517e7196dba1d1a15f Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 14 Feb 2019 08:38:51 +0100 Subject: [PATCH 1675/2058] Fix PhSearchFilePath regression from commit 5b64e80c --- phlib/util.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/phlib/util.c b/phlib/util.c index 7c9093c083a1..b0d50044003e 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -5143,6 +5143,8 @@ PPH_STRING PhSearchFilePath( if (returnLength == 0 && returnLength <= bufferSize) goto CleanupExit; + PhTrimToNullTerminatorString(fullPath); + // Make sure this is not a directory. if (!NT_SUCCESS(PhQueryAttributesFileWin32(fullPath->Buffer, &basicInfo))) From 5c65ce7dc1fbb4b603943c534e8c82f8ddfa5d6f Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 14 Feb 2019 08:39:49 +0100 Subject: [PATCH 1676/2058] NetworkTools: Fix geoip updater regression 39417f1f --- plugins/NetworkTools/nettools.h | 3 +++ plugins/NetworkTools/pages.c | 1 + plugins/NetworkTools/update.c | 2 ++ 3 files changed, 6 insertions(+) diff --git a/plugins/NetworkTools/nettools.h b/plugins/NetworkTools/nettools.h index f1f1cd75dfde..2038f86b1521 100644 --- a/plugins/NetworkTools/nettools.h +++ b/plugins/NetworkTools/nettools.h @@ -324,6 +324,9 @@ VOID ShowGeoIPUpdateDialog( ); // pages.c + +extern PH_EVENT InitializedEvent; + VOID ShowDbCheckForUpdatesDialog( _In_ PPH_UPDATER_CONTEXT Context ); diff --git a/plugins/NetworkTools/pages.c b/plugins/NetworkTools/pages.c index c72b2a4b3faa..75def35df281 100644 --- a/plugins/NetworkTools/pages.c +++ b/plugins/NetworkTools/pages.c @@ -46,6 +46,7 @@ HRESULT CALLBACK CheckForUpdatesDbCallbackProc( switch (uMsg) { case TDN_NAVIGATED: + PhSetEvent(&InitializedEvent); break; case TDN_BUTTON_CLICKED: { diff --git a/plugins/NetworkTools/update.c b/plugins/NetworkTools/update.c index 23258f6c0130..ec57f34b2343 100644 --- a/plugins/NetworkTools/update.c +++ b/plugins/NetworkTools/update.c @@ -621,6 +621,8 @@ NTSTATUS GeoIPUpdateDialogThread( PhDereferenceObject(context); PhDeleteAutoPool(&autoPool); + PhResetEvent(&InitializedEvent); + return STATUS_SUCCESS; //SHELLEXECUTEINFO info = { sizeof(SHELLEXECUTEINFO) }; From 75181715d93a876f15a79eecb9894bba991957dd Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 17 Feb 2019 02:18:34 +0100 Subject: [PATCH 1677/2058] Improve service highlighting --- ProcessHacker/proctree.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/ProcessHacker/proctree.c b/ProcessHacker/proctree.c index 25eb284d4004..0ef0936f2e2d 100644 --- a/ProcessHacker/proctree.c +++ b/ProcessHacker/proctree.c @@ -3039,8 +3039,11 @@ BOOLEAN NTAPI PhpProcessTreeNewCallback( getNodeColor->BackColor = PhCsColorJobProcesses; else if ( PhCsUseColorServiceProcesses && - ((processItem->Sid && RtlEqualSid(processItem->Sid, &PhSeLocalServiceSid)) || - processItem->ServiceList && processItem->ServiceList->Count != 0)) + ((processItem->ServiceList && processItem->ServiceList->Count != 0) || + (processItem->Sid && RtlEqualSid(processItem->Sid, &PhSeServiceSid)) || + (processItem->Sid && RtlEqualSid(processItem->Sid, &PhSeLocalServiceSid)) || + (processItem->Sid && RtlEqualSid(processItem->Sid, &PhSeNetworkServiceSid)) + )) getNodeColor->BackColor = PhCsColorServiceProcesses; else if ( PhCsUseColorSystemProcesses && From f859257d8c44cc49bbd3c5dcac41a3721ca3c13c Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 17 Feb 2019 02:19:46 +0100 Subject: [PATCH 1678/2058] Improve macro usage --- phlib/filepool.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/phlib/filepool.c b/phlib/filepool.c index 58790ae17f55..8126fa264f18 100644 --- a/phlib/filepool.c +++ b/phlib/filepool.c @@ -1277,7 +1277,7 @@ VOID PhFppFreeBlocks( RtlInitializeBitMap(&bitmap, SegmentHeader->Bitmap, PH_FP_BLOCK_COUNT); // Mark the blocks as free. - startIndex = (ULONG)((PCHAR)BlockHeader - (PCHAR)FirstBlock) >> Pool->BlockShift; + startIndex = PtrToUlong(PTR_SUB_OFFSET(BlockHeader, FirstBlock)) >> Pool->BlockShift; blockSpan = BlockHeader->Span; RtlClearBits(&bitmap, startIndex, blockSpan); SegmentHeader->FreeBlocks += blockSpan; @@ -1480,7 +1480,7 @@ ULONG PhFppEncodeRva( _In_ PVOID Address ) { - return (SegmentIndex << Pool->SegmentShift) + (ULONG)((PCHAR)Address - (PCHAR)FirstBlock); + return (SegmentIndex << Pool->SegmentShift) + PtrToUlong(PTR_SUB_OFFSET(Address, FirstBlock)); } /** From 952c7ed9e2fc7bd5785e2db08f1f01c4faeee1a1 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 17 Feb 2019 02:25:33 +0100 Subject: [PATCH 1679/2058] phnt: Fix some SAL annotations --- phnt/include/ntexapi.h | 2 +- phnt/include/ntrtl.h | 2 +- phnt/include/ntseapi.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/phnt/include/ntexapi.h b/phnt/include/ntexapi.h index 7507efaba63e..84be461f53fb 100644 --- a/phnt/include/ntexapi.h +++ b/phnt/include/ntexapi.h @@ -32,7 +32,7 @@ NTSTATUS NTAPI NtDelayExecution( _In_ BOOLEAN Alertable, - _In_ PLARGE_INTEGER DelayInterval + _In_opt_ PLARGE_INTEGER DelayInterval ); // Environment values diff --git a/phnt/include/ntrtl.h b/phnt/include/ntrtl.h index 3ee1381be445..3e9b1e3656ae 100644 --- a/phnt/include/ntrtl.h +++ b/phnt/include/ntrtl.h @@ -1408,7 +1408,7 @@ VOID NTAPI RtlInitEmptyUnicodeString( _Out_ PUNICODE_STRING DestinationString, - _In_ PWCHAR Buffer, + _In_opt_ PWCHAR Buffer, _In_ USHORT MaximumLength ) { diff --git a/phnt/include/ntseapi.h b/phnt/include/ntseapi.h index 2f0b2f8888a3..13e3972dbb54 100644 --- a/phnt/include/ntseapi.h +++ b/phnt/include/ntseapi.h @@ -310,7 +310,7 @@ NtAdjustGroupsToken( _In_opt_ PTOKEN_GROUPS NewState, _In_opt_ ULONG BufferLength, _Out_writes_bytes_to_opt_(BufferLength, *ReturnLength) PTOKEN_GROUPS PreviousState, - _Out_ PULONG ReturnLength + _Out_opt_ PULONG ReturnLength ); #if (PHNT_VERSION >= PHNT_WIN8) From af6041841ee203ac9f9573d61edbd447cfac42cd Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 17 Feb 2019 02:30:51 +0100 Subject: [PATCH 1680/2058] Fix some VS2019 warnings, Fix empty unicode strings, Improve macro usage --- ProcessHacker/memedit.c | 6 +++--- ProcessHacker/procprp.c | 6 +++--- ProcessHacker/prpgwmi.c | 33 ++++++++++++++++++--------------- ProcessHacker/thrdlist.c | 8 ++++---- phlib/include/phbasesup.h | 4 ++-- phlib/include/phnative.h | 2 +- phlib/include/phutil.h | 4 ++-- phlib/include/symprvp.h | 14 +++++++------- phlib/lsasup.c | 4 ++-- phlib/native.c | 22 ++++++++++------------ phlib/symprv.c | 2 +- phlib/util.c | 6 +++--- 12 files changed, 56 insertions(+), 55 deletions(-) diff --git a/ProcessHacker/memedit.c b/ProcessHacker/memedit.c index 44fdc26963d6..dc821cc892f1 100644 --- a/ProcessHacker/memedit.c +++ b/ProcessHacker/memedit.c @@ -120,7 +120,7 @@ VOID PhShowMemoryEditorDialog( return; } - if (SelectOffset != -1) + if (SelectOffset != ULONG_MAX) PostMessage(context->WindowHandle, WM_PH_SELECT_OFFSET, SelectOffset, SelectLength); PhRegisterDialog(context->WindowHandle); @@ -138,7 +138,7 @@ VOID PhShowMemoryEditorDialog( else SetForegroundWindow(context->WindowHandle); - if (SelectOffset != -1) + if (SelectOffset != ULONG_MAX) PostMessage(context->WindowHandle, WM_PH_SELECT_OFFSET, SelectOffset, SelectLength); // Just in case. @@ -542,7 +542,7 @@ INT_PTR CALLBACK PhpMemoryEditorDlgProc( case WM_PH_SELECT_OFFSET: { HexEdit_SetEditMode(context->HexEditHandle, EDIT_ASCII); - HexEdit_SetSel(context->HexEditHandle, (ULONG)wParam, (ULONG)wParam + (ULONG)lParam); + HexEdit_SetSel(context->HexEditHandle, (ULONG)wParam, PtrToUlong(PTR_ADD_OFFSET(wParam, lParam))); } break; } diff --git a/ProcessHacker/procprp.c b/ProcessHacker/procprp.c index 4bedb5d5e5b9..c5593af224d6 100644 --- a/ProcessHacker/procprp.c +++ b/ProcessHacker/procprp.c @@ -459,9 +459,9 @@ BOOLEAN PhPropPageDlgProcHeader( _In_ HWND hwndDlg, _In_ UINT uMsg, _In_ LPARAM lParam, - _Out_ LPPROPSHEETPAGE *PropSheetPage, - _Out_ PPH_PROCESS_PROPPAGECONTEXT *PropPageContext, - _Out_ PPH_PROCESS_ITEM *ProcessItem + _Out_opt_ LPPROPSHEETPAGE *PropSheetPage, + _Out_opt_ PPH_PROCESS_PROPPAGECONTEXT *PropPageContext, + _Out_opt_ PPH_PROCESS_ITEM *ProcessItem ) { LPPROPSHEETPAGE propSheetPage; diff --git a/ProcessHacker/prpgwmi.c b/ProcessHacker/prpgwmi.c index 2300e26d90ab..ec1bd9339059 100644 --- a/ProcessHacker/prpgwmi.c +++ b/ProcessHacker/prpgwmi.c @@ -142,22 +142,25 @@ HRESULT PhpWmiProviderExecMethod( VariantClear(&variant); } - if ( - PhEqualString(Entry->NamespacePath, namespacePath, FALSE) && - PhEqualString(Entry->ProviderName, providerName, FALSE) && - PhEqualString(Entry->UserName, userName, FALSE) - ) + if (namespacePath && providerName && userName && instancePath) { - status = IWbemServices_ExecMethod( - wbemServices, - instancePath->Buffer, - Method, - 0, - NULL, - wbemClassObject, - NULL, - NULL - ); + if ( + PhEqualString(Entry->NamespacePath, namespacePath, FALSE) && + PhEqualString(Entry->ProviderName, providerName, FALSE) && + PhEqualString(Entry->UserName, userName, FALSE) + ) + { + status = IWbemServices_ExecMethod( + wbemServices, + instancePath->Buffer, + Method, + 0, + NULL, + wbemClassObject, + NULL, + NULL + ); + } } if (instancePath) diff --git a/ProcessHacker/thrdlist.c b/ProcessHacker/thrdlist.c index 1bd51861e9a9..096f9f6182e6 100644 --- a/ProcessHacker/thrdlist.c +++ b/ProcessHacker/thrdlist.c @@ -610,7 +610,7 @@ BOOLEAN NTAPI PhpThreadTreeNewCallback( if (PhFormatToBuffer(&format, 1, node->ThreadIdText, sizeof(node->ThreadIdText), &returnLength)) { getCellText->Text.Buffer = node->ThreadIdText; - getCellText->Text.Length = returnLength - sizeof(WCHAR); // minus null terminator + getCellText->Text.Length = returnLength - sizeof(UNICODE_NULL); // minus null terminator } } break; @@ -630,7 +630,7 @@ BOOLEAN NTAPI PhpThreadTreeNewCallback( if (PhFormatToBuffer(&format, 1, node->CpuUsageText, sizeof(node->CpuUsageText), &returnLength)) { getCellText->Text.Buffer = node->CpuUsageText; - getCellText->Text.Length = returnLength - sizeof(WCHAR); // minus null terminator + getCellText->Text.Length = returnLength - sizeof(UNICODE_NULL); } } else if (cpuUsage != 0 && PhCsShowCpuBelow001) @@ -644,7 +644,7 @@ BOOLEAN NTAPI PhpThreadTreeNewCallback( if (PhFormatToBuffer(format, 2, node->CpuUsageText, sizeof(node->CpuUsageText), &returnLength)) { getCellText->Text.Buffer = node->CpuUsageText; - getCellText->Text.Length = returnLength - sizeof(WCHAR); + getCellText->Text.Length = returnLength - sizeof(UNICODE_NULL); } } } @@ -894,7 +894,7 @@ BOOLEAN NTAPI PhpThreadTreeNewCallback( if (PhFormatToBuffer(&format, 1, node->ThreadIdHexText, sizeof(node->ThreadIdHexText), &returnLength)) { getCellText->Text.Buffer = node->ThreadIdHexText; - getCellText->Text.Length = returnLength - sizeof(WCHAR); // minus null terminator + getCellText->Text.Length = returnLength - sizeof(UNICODE_NULL); } } break; diff --git a/phlib/include/phbasesup.h b/phlib/include/phbasesup.h index 1eda2180e15c..c710b5cff8e5 100644 --- a/phlib/include/phbasesup.h +++ b/phlib/include/phbasesup.h @@ -742,8 +742,8 @@ typedef struct _PH_RELATIVE_BYTESREF ULONG Offset; } PH_RELATIVE_BYTESREF, *PPH_RELATIVE_BYTESREF, PH_RELATIVE_STRINGREF, *PPH_RELATIVE_STRINGREF; -#define PH_STRINGREF_INIT(String) { sizeof(String) - sizeof(WCHAR), (String) } -#define PH_BYTESREF_INIT(String) { sizeof(String) - sizeof(CHAR), (String) } +#define PH_STRINGREF_INIT(String) { sizeof(String) - sizeof(UNICODE_NULL), (String) } +#define PH_BYTESREF_INIT(String) { sizeof(String) - sizeof(ANSI_NULL), (String) } FORCEINLINE VOID diff --git a/phlib/include/phnative.h b/phlib/include/phnative.h index fb8b69b61ae1..14bd25e53e7e 100644 --- a/phlib/include/phnative.h +++ b/phlib/include/phnative.h @@ -1285,7 +1285,7 @@ PhCreatePipeEx( _Out_ PHANDLE PipeReadHandle, _Out_ PHANDLE PipeWriteHandle, _In_ BOOLEAN InheritHandles, - _In_ PSECURITY_DESCRIPTOR SecurityDescriptor + _In_opt_ PSECURITY_DESCRIPTOR SecurityDescriptor ); PHLIBAPI diff --git a/phlib/include/phutil.h b/phlib/include/phutil.h index e8141b72fb3e..be1f366fdfc7 100644 --- a/phlib/include/phutil.h +++ b/phlib/include/phutil.h @@ -212,7 +212,7 @@ PHLIBAPI INT NTAPI PhShowMessage( - _In_ HWND hWnd, + _In_opt_ HWND hWnd, _In_ ULONG Type, _In_ PWSTR Format, ... @@ -226,7 +226,7 @@ PHLIBAPI INT NTAPI PhShowMessage2( - _In_ HWND hWnd, + _In_opt_ HWND hWnd, _In_ ULONG Buttons, _In_opt_ PWSTR Icon, _In_opt_ PWSTR Title, diff --git a/phlib/include/symprvp.h b/phlib/include/symprvp.h index a0c368ea9e85..48af6207819d 100644 --- a/phlib/include/symprvp.h +++ b/phlib/include/symprvp.h @@ -62,12 +62,12 @@ typedef BOOL (WINAPI *_SymGetLineFromAddrW64)( typedef ULONG64 (WINAPI *_SymLoadModuleExW)( _In_ HANDLE ProcessHandle, _In_opt_ HANDLE FileHandle, - _In_ PCWSTR ImageName, - _In_ PCWSTR ModuleName, + _In_opt_ PCWSTR ImageName, + _In_opt_ PCWSTR ModuleName, _In_ ULONG64 BaseOfDll, _In_ ULONG DllSize, - _In_ PMODLOAD_DATA Data, - _In_ ULONG Flags + _In_opt_ PMODLOAD_DATA Data, + _In_opt_ ULONG Flags ); typedef ULONG (WINAPI *_SymGetOptions)(); @@ -125,9 +125,9 @@ typedef BOOL (WINAPI *_MiniDumpWriteDump)( _In_ ULONG ProcessId, _In_ HANDLE FileHandle, _In_ MINIDUMP_TYPE DumpType, - _In_ PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, - _In_ PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam, - _In_ PMINIDUMP_CALLBACK_INFORMATION CallbackParam + _In_opt_ PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, + _In_opt_ PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam, + _In_opt_ PMINIDUMP_CALLBACK_INFORMATION CallbackParam ); typedef UINT_PTR (CALLBACK *_SymbolServerGetOptions)( diff --git a/phlib/lsasup.c b/phlib/lsasup.c index 87a90ecfbbc3..021700d9653c 100644 --- a/phlib/lsasup.c +++ b/phlib/lsasup.c @@ -528,11 +528,11 @@ VOID PhInitializeCapabilitySidCache( PhDereferenceObject(capabilityListFileName); } - if (PhIsNullOrEmptyString(capabilityListString)) + if (!capabilityListString) return; PhInitializeArray(CapabilitySidArrayList, sizeof(PH_CAPABILITY_ENTRY), 800); - remainingPart = capabilityListString->sr; + remainingPart = PhGetStringRef(capabilityListString); while (remainingPart.Length != 0) { diff --git a/phlib/native.c b/phlib/native.c index 55d43b7bb4de..e251de4e7be8 100644 --- a/phlib/native.c +++ b/phlib/native.c @@ -1123,7 +1123,7 @@ NTSTATUS PhQueryEnvironmentVariable( } else { - RtlInitUnicodeString(&variableValueUs, UNICODE_NULL); + RtlInitEmptyUnicodeString(&variableValueUs, NULL, 0); } status = RtlQueryEnvironmentVariable_U( @@ -3550,8 +3550,7 @@ BOOLEAN NTAPI PhpEnumProcessModulesCallback( NULL ))) { - // HACK: Fixup the module load count. - // Temp fix until PhpModuleQueryWorker can be used for 'Stage2'. + // Fixup the module load count. (dmex) Entry->ObsoleteLoadCount = (USHORT)ldrDagNode.LoadCount; } } @@ -3860,7 +3859,7 @@ BOOLEAN NTAPI PhpEnumProcessModules32Callback( { // Read the base DLL name string and add a null terminator. - baseDllNameBuffer = PhAllocate(nativeEntry.BaseDllName.Length + sizeof(WCHAR)); + baseDllNameBuffer = PhAllocate(nativeEntry.BaseDllName.Length + sizeof(UNICODE_NULL)); if (NT_SUCCESS(NtReadVirtualMemory( ProcessHandle, @@ -3882,7 +3881,7 @@ BOOLEAN NTAPI PhpEnumProcessModules32Callback( // Read the full DLL name string and add a null terminator. - fullDllNameBuffer = PhAllocate(nativeEntry.FullDllName.Length + sizeof(WCHAR)); + fullDllNameBuffer = PhAllocate(nativeEntry.FullDllName.Length + sizeof(UNICODE_NULL)); if (NT_SUCCESS(NtReadVirtualMemory( ProcessHandle, @@ -3942,8 +3941,7 @@ BOOLEAN NTAPI PhpEnumProcessModules32Callback( NULL ))) { - // HACK: Fixup the module load count. - // Temp fix until PhpModuleQueryWorker can be used for 'Stage2'. + // Fixup the module load count. (dmex) nativeEntry.ObsoleteLoadCount = (USHORT)ldrDagNode32.LoadCount; } } @@ -5841,10 +5839,10 @@ PPH_STRING PhGetFileName( PH_STRINGREF systemRoot; PhGetSystemRoot(&systemRoot); - newFileName = PhCreateStringEx(NULL, systemRoot.Length + sizeof(WCHAR) + FileName->Length); + newFileName = PhCreateStringEx(NULL, systemRoot.Length + sizeof(UNICODE_NULL) + FileName->Length); memcpy(newFileName->Buffer, systemRoot.Buffer, systemRoot.Length); newFileName->Buffer[systemRoot.Length / sizeof(WCHAR)] = OBJ_NAME_PATH_SEPARATOR; - memcpy(PTR_ADD_OFFSET(newFileName->Buffer, systemRoot.Length + sizeof(WCHAR)), FileName->Buffer, FileName->Length); + memcpy(PTR_ADD_OFFSET(newFileName->Buffer, systemRoot.Length + sizeof(UNICODE_NULL)), FileName->Buffer, FileName->Length); } else if (FileName->Length != 0 && FileName->Buffer[0] == OBJ_NAME_PATH_SEPARATOR) { @@ -5862,7 +5860,7 @@ PPH_STRING PhGetFileName( // If the file name starts with "\Windows", prepend the system drive. if (PhStartsWithString2(newFileName, L"\\Windows", TRUE)) { - newFileName = PhCreateStringEx(NULL, FileName->Length + sizeof(WCHAR) * sizeof(WCHAR)); + newFileName = PhCreateStringEx(NULL, FileName->Length + sizeof(UNICODE_NULL) * sizeof(WCHAR)); newFileName->Buffer[0] = USER_SHARED_DATA->NtSystemRoot[0]; newFileName->Buffer[1] = ':'; memcpy(&newFileName->Buffer[2], FileName->Buffer, FileName->Length); @@ -6801,7 +6799,7 @@ NTSTATUS PhQueryValueKey( } else { - RtlInitUnicodeString(&valueName, NULL); + RtlInitEmptyUnicodeString(&valueName, NULL, 0); } bufferSize = 0x100; @@ -7451,7 +7449,7 @@ NTSTATUS PhCreatePipeEx( _Out_ PHANDLE PipeReadHandle, _Out_ PHANDLE PipeWriteHandle, _In_ BOOLEAN InheritHandles, - _In_ PSECURITY_DESCRIPTOR SecurityDescriptor + _In_opt_ PSECURITY_DESCRIPTOR SecurityDescriptor ) { NTSTATUS status; diff --git a/phlib/symprv.c b/phlib/symprv.c index fd902eebedf6..8023806dfcd6 100644 --- a/phlib/symprv.c +++ b/phlib/symprv.c @@ -540,7 +540,7 @@ PPH_STRING PhGetSymbolFromAddress( ULONG64 displacement; PPH_STRING modFileName = NULL; PPH_STRING modBaseName = NULL; - ULONG64 modBase; + ULONG64 modBase = 0; PPH_STRING symbolName = NULL; if (Address == 0) diff --git a/phlib/util.c b/phlib/util.c index b0d50044003e..0330a5f3c2dd 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -255,7 +255,7 @@ PPH_STRING PhGetUserDefaultLocaleName( if (NT_SUCCESS(RtlLcidToLocaleName(PhGetUserDefaultLCID(), &localeNameUs, 0, FALSE))) { - return PhCreateString(localeName); + return PhCreateStringFromUnicodeString(&localeNameUs); } return NULL; @@ -411,7 +411,7 @@ PPH_STRING PhGetWin32Message( * \return The user's response. */ INT PhShowMessage( - _In_ HWND hWnd, + _In_opt_ HWND hWnd, _In_ ULONG Type, _In_ PWSTR Format, ... @@ -435,7 +435,7 @@ INT PhShowMessage( } INT PhShowMessage2( - _In_ HWND hWnd, + _In_opt_ HWND hWnd, _In_ ULONG Buttons, _In_opt_ PWSTR Icon, _In_opt_ PWSTR Title, From 57fe40b7aa25b0c6f4d2a00bd5859aabef94e2c8 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 17 Feb 2019 02:42:30 +0100 Subject: [PATCH 1681/2058] Improve startup, Fix delayload version check, Update delayload imports, Remove legacy imports --- ProcessHacker/ProcessHacker.vcxproj | 16 ++++---- ProcessHacker/mainwnd.c | 49 ++++++++++-------------- ProcessHacker/procprv.c | 8 ++-- ProcessHacker/runas.c | 4 +- phlib/apiimport.c | 3 -- phlib/guisup.c | 58 +++++++++++++++++++++-------- phlib/include/apiimport.h | 31 --------------- phlib/include/guisup.h | 34 ++++++----------- phlib/util.c | 12 +++--- 9 files changed, 94 insertions(+), 121 deletions(-) diff --git a/ProcessHacker/ProcessHacker.vcxproj b/ProcessHacker/ProcessHacker.vcxproj index cb239e9a62fe..b10224efca48 100644 --- a/ProcessHacker/ProcessHacker.vcxproj +++ b/ProcessHacker/ProcessHacker.vcxproj @@ -106,14 +106,14 @@ true - aclui.lib;comctl32.lib;iphlpapi.lib;noarg.obj;noenv.obj;ntdll.lib;phlib.lib;userenv.lib;uxtheme.lib;version.lib;wbemuuid.lib;windowscodecs.lib;winsta.lib;ws2_32.lib;%(AdditionalDependencies) + aclui.lib;comctl32.lib;iphlpapi.lib;noarg.obj;noenv.obj;ntdll.lib;phlib.lib;shlwapi.lib;userenv.lib;uxtheme.lib;version.lib;wbemuuid.lib;windowscodecs.lib;winsta.lib;ws2_32.lib;%(AdditionalDependencies) true Windows MachineX86 6.01 $(SolutionDir)phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) ProcessHacker.def - advapi32.dll;aclui.dll;comdlg32.dll;comctl32.dll;gdi32.dll;iphlpapi.dll;oleaut32.dll;ole32.dll;shell32.dll;userenv.dll;user32.dll;uxtheme.dll;version.dll;winsta.dll;ws2_32.dll;%(DelayLoadDLLs) + advapi32.dll;aclui.dll;comdlg32.dll;comctl32.dll;gdi32.dll;iphlpapi.dll;oleaut32.dll;ole32.dll;shell32.dll;shlwapi.dll;userenv.dll;user32.dll;uxtheme.dll;version.dll;winsta.dll;ws2_32.dll;%(DelayLoadDLLs) _UNICODE;UNICODE;%(PreprocessorDefinitions);$(ExternalCompilerOptions) @@ -138,14 +138,14 @@ true - aclui.lib;comctl32.lib;iphlpapi.lib;noarg.obj;noenv.obj;ntdll.lib;phlib.lib;userenv.lib;uxtheme.lib;version.lib;wbemuuid.lib;windowscodecs.lib;winsta.lib;ws2_32.lib;%(AdditionalDependencies) + aclui.lib;comctl32.lib;iphlpapi.lib;noarg.obj;noenv.obj;ntdll.lib;phlib.lib;shlwapi.lib;userenv.lib;uxtheme.lib;version.lib;wbemuuid.lib;windowscodecs.lib;winsta.lib;ws2_32.lib;%(AdditionalDependencies) true Windows MachineX64 6.01 $(SolutionDir)phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) ProcessHacker.def - advapi32.dll;aclui.dll;comdlg32.dll;comctl32.dll;gdi32.dll;iphlpapi.dll;oleaut32.dll;ole32.dll;shell32.dll;userenv.dll;user32.dll;uxtheme.dll;version.dll;winsta.dll;ws2_32.dll;%(DelayLoadDLLs) + advapi32.dll;aclui.dll;comdlg32.dll;comctl32.dll;gdi32.dll;iphlpapi.dll;oleaut32.dll;ole32.dll;shell32.dll;shlwapi.dll;userenv.dll;user32.dll;uxtheme.dll;version.dll;winsta.dll;ws2_32.dll;%(DelayLoadDLLs) _UNICODE;UNICODE;%(PreprocessorDefinitions);$(ExternalCompilerOptions) @@ -175,7 +175,7 @@ Guard - aclui.lib;comctl32.lib;iphlpapi.lib;noarg.obj;noenv.obj;ntdll.lib;phlib.lib;userenv.lib;uxtheme.lib;version.lib;wbemuuid.lib;windowscodecs.lib;winsta.lib;ws2_32.lib;%(AdditionalDependencies) + aclui.lib;comctl32.lib;iphlpapi.lib;noarg.obj;noenv.obj;ntdll.lib;phlib.lib;shlwapi.lib;userenv.lib;uxtheme.lib;version.lib;wbemuuid.lib;windowscodecs.lib;winsta.lib;ws2_32.lib;%(AdditionalDependencies) Windows true true @@ -184,7 +184,7 @@ 6.01 $(SolutionDir)phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) ProcessHacker.def - advapi32.dll;aclui.dll;comdlg32.dll;comctl32.dll;gdi32.dll;iphlpapi.dll;oleaut32.dll;ole32.dll;shell32.dll;userenv.dll;user32.dll;uxtheme.dll;version.dll;winsta.dll;ws2_32.dll;%(DelayLoadDLLs) + advapi32.dll;aclui.dll;comdlg32.dll;comctl32.dll;gdi32.dll;iphlpapi.dll;oleaut32.dll;ole32.dll;shell32.dll;shlwapi.dll;userenv.dll;user32.dll;uxtheme.dll;version.dll;winsta.dll;ws2_32.dll;%(DelayLoadDLLs) true @@ -213,7 +213,7 @@ Guard - aclui.lib;comctl32.lib;iphlpapi.lib;noarg.obj;noenv.obj;ntdll.lib;phlib.lib;userenv.lib;uxtheme.lib;version.lib;wbemuuid.lib;windowscodecs.lib;winsta.lib;ws2_32.lib;%(AdditionalDependencies) + aclui.lib;comctl32.lib;iphlpapi.lib;noarg.obj;noenv.obj;ntdll.lib;phlib.lib;shlwapi.lib;userenv.lib;uxtheme.lib;version.lib;wbemuuid.lib;windowscodecs.lib;winsta.lib;ws2_32.lib;%(AdditionalDependencies) Windows true true @@ -222,7 +222,7 @@ 6.01 $(SolutionDir)phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) ProcessHacker.def - advapi32.dll;aclui.dll;comdlg32.dll;comctl32.dll;gdi32.dll;iphlpapi.dll;oleaut32.dll;ole32.dll;shell32.dll;userenv.dll;user32.dll;uxtheme.dll;version.dll;winsta.dll;ws2_32.dll;%(DelayLoadDLLs) + advapi32.dll;aclui.dll;comdlg32.dll;comctl32.dll;gdi32.dll;iphlpapi.dll;oleaut32.dll;ole32.dll;shell32.dll;shlwapi.dll;userenv.dll;user32.dll;uxtheme.dll;version.dll;winsta.dll;ws2_32.dll;%(DelayLoadDLLs) true diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index 6e82632139c7..39fbe34e198b 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -606,43 +606,34 @@ VOID PhMwpOnCommand( break; case ID_HACKER_RUN: { - if (RunFileDlg) - { - SelectedRunAsMode = 0; - RunFileDlg(PhMainWndHandle, NULL, NULL, NULL, NULL, RFF_OPTRUNAS); - } + SelectedRunAsMode = 0; + PhShowRunFileDialog(PhMainWndHandle, NULL, NULL, NULL, NULL, RFF_OPTRUNAS); } break; case ID_HACKER_RUNASADMINISTRATOR: { - if (RunFileDlg) - { - SelectedRunAsMode = RUNAS_MODE_ADMIN; - RunFileDlg( - PhMainWndHandle, - NULL, - NULL, - NULL, - L"Type the name of a program that will be opened under alternate credentials.", - 0 - ); - } + SelectedRunAsMode = RUNAS_MODE_ADMIN; + PhShowRunFileDialog( + PhMainWndHandle, + NULL, + NULL, + NULL, + L"Type the name of a program that will be opened under alternate credentials.", + 0 + ); } break; case ID_HACKER_RUNASLIMITEDUSER: { - if (RunFileDlg) - { - SelectedRunAsMode = RUNAS_MODE_LIMITED; - RunFileDlg( - PhMainWndHandle, - NULL, - NULL, - NULL, - L"Type the name of a program that will be opened under standard user privileges.", - 0 - ); - } + SelectedRunAsMode = RUNAS_MODE_LIMITED; + PhShowRunFileDialog( + PhMainWndHandle, + NULL, + NULL, + NULL, + L"Type the name of a program that will be opened under standard user privileges.", + 0 + ); } break; case ID_HACKER_RUNAS: diff --git a/ProcessHacker/procprv.c b/ProcessHacker/procprv.c index 0891dba0c2fb..68223e832dde 100644 --- a/ProcessHacker/procprv.c +++ b/ProcessHacker/procprv.c @@ -864,9 +864,9 @@ VOID PhpProcessQueryStage1( } // Immersive - if (processHandleLimited && IsImmersiveProcess_I && !processItem->IsSubsystemProcess) + if (processHandleLimited && WINDOWS_HAS_IMMERSIVE && IsImmersiveProcess && !processItem->IsSubsystemProcess) { - Data->IsImmersive = !!IsImmersiveProcess_I(processHandleLimited); + Data->IsImmersive = !!IsImmersiveProcess(processHandleLimited); } // Package full name @@ -2350,11 +2350,11 @@ VOID PhProcessProviderUpdate( } // Immersive - if (processItem->QueryHandle && IsImmersiveProcess_I) + if (processItem->QueryHandle && WINDOWS_HAS_IMMERSIVE && IsImmersiveProcess) { BOOLEAN isImmersive; - isImmersive = !!IsImmersiveProcess_I(processItem->QueryHandle); + isImmersive = !!IsImmersiveProcess(processItem->QueryHandle); if (processItem->IsImmersive != isImmersive) { diff --git a/ProcessHacker/runas.c b/ProcessHacker/runas.c index 02a4902c3ba4..844f61e50b2b 100644 --- a/ProcessHacker/runas.c +++ b/ProcessHacker/runas.c @@ -855,8 +855,8 @@ INT_PTR CALLBACK PhpRunAsDlgProc( if (SendMessage(context->ProgramComboBoxWindowHandle, CB_GETCOMBOBOXINFO, 0, (LPARAM)&info)) { - if (SHAutoComplete_I) - SHAutoComplete_I(info.hwndItem, SHACF_DEFAULT); + if (SHAutoComplete) + SHAutoComplete(info.hwndItem, SHACF_DEFAULT); } } diff --git a/phlib/apiimport.c b/phlib/apiimport.c index 2ac0e9290ea0..1b3e1acc7928 100644 --- a/phlib/apiimport.c +++ b/phlib/apiimport.c @@ -62,6 +62,3 @@ PH_DEFINE_IMPORT(L"ntdll.dll", NtQueryInformationEnlistment); PH_DEFINE_IMPORT(L"ntdll.dll", NtQueryInformationResourceManager); PH_DEFINE_IMPORT(L"ntdll.dll", NtQueryInformationTransaction); PH_DEFINE_IMPORT(L"ntdll.dll", NtQueryInformationTransactionManager); -PH_DEFINE_IMPORT(L"shell32.dll", SHCreateShellItem); -PH_DEFINE_IMPORT(L"shell32.dll", SHOpenFolderAndSelectItems); -PH_DEFINE_IMPORT(L"shell32.dll", SHParseDisplayName); diff --git a/phlib/guisup.c b/phlib/guisup.c index dea378acb44f..cae5334b86e0 100644 --- a/phlib/guisup.c +++ b/phlib/guisup.c @@ -53,10 +53,6 @@ typedef struct _PH_WINDOW_PROPERTY_CONTEXT PVOID Context; } PH_WINDOW_PROPERTY_CONTEXT, *PPH_WINDOW_PROPERTY_CONTEXT; -_IsImmersiveProcess IsImmersiveProcess_I = NULL; -_RunFileDlg RunFileDlg = NULL; -_SHAutoComplete SHAutoComplete_I = NULL; - HFONT PhApplicationFont = NULL; HFONT PhTreeWindowFont = NULL; PH_INTEGER_PAIR PhSmallIconSize = { 16, 16 }; @@ -76,8 +72,6 @@ VOID PhGuiSupportInitialization( ) { HDC hdc; - PVOID shell32Handle; - PVOID shlwapiHandle; WindowCallbackHashTable = PhCreateHashtable( sizeof(PH_PLUGIN_WINDOW_CALLBACK_REGISTRATION), @@ -102,14 +96,6 @@ VOID PhGuiSupportInitialization( PhGlobalDpi = GetDeviceCaps(hdc, LOGPIXELSY); ReleaseDC(NULL, hdc); } - - shell32Handle = LoadLibrary(L"shell32.dll"); - shlwapiHandle = LoadLibrary(L"shlwapi.dll"); - - if (WINDOWS_HAS_IMMERSIVE) - IsImmersiveProcess_I = PhGetDllProcedureAddress(L"user32.dll", "IsImmersiveProcess", 0); - RunFileDlg = PhGetDllBaseProcedureAddress(shell32Handle, NULL, 61); - SHAutoComplete_I = PhGetDllBaseProcedureAddress(shlwapiHandle, "SHAutoComplete", 0); } VOID PhSetControlTheme( @@ -1497,8 +1483,8 @@ HWND PhGetProcessMainWindowEx( else PhOpenProcess(&processHandle, PROCESS_QUERY_LIMITED_INFORMATION, ProcessId); - if (processHandle && IsImmersiveProcess_I) - context.IsImmersive = IsImmersiveProcess_I(processHandle); + if (processHandle && WINDOWS_HAS_IMMERSIVE && IsImmersiveProcess) + context.IsImmersive = IsImmersiveProcess(processHandle); PhEnumChildWindows(NULL, 0x800, PhpGetProcessMainWindowEnumWindowsProc, &context); @@ -1676,3 +1662,43 @@ VOID PhWindowNotifyTopMostEvent( PhReleaseQueuedLockExclusive(&WindowCallbackListLock); } + +BOOLEAN PhShowRunFileDialog( + _In_ HWND WindowHandle, + _In_opt_ HICON WindowIcon, + _In_opt_ PWSTR WorkingDirectory, + _In_opt_ PWSTR WindowTitle, + _In_opt_ PWSTR WindowDescription, + _In_ ULONG Flags + ) +{ + BOOL (WINAPI *RunFileDlg_I)( + _In_ HWND hwndOwner, + _In_opt_ HICON hIcon, + _In_opt_ LPCWSTR lpszDirectory, + _In_opt_ LPCWSTR lpszTitle, + _In_opt_ LPCWSTR lpszDescription, + _In_ ULONG uFlags + ); + BOOLEAN result = FALSE; + PVOID shell32Handle; + + if (shell32Handle = LoadLibrary(L"shell32.dll")) + { + if (RunFileDlg_I = PhGetDllBaseProcedureAddress(shell32Handle, NULL, 61)) + { + result = !!RunFileDlg_I( + WindowHandle, + WindowIcon, + WorkingDirectory, + WindowTitle, + WindowDescription, + Flags + ); + } + + FreeLibrary(shell32Handle); + } + + return result; +} diff --git a/phlib/include/apiimport.h b/phlib/include/apiimport.h index 574b6d9eb86c..05b895ae24e1 100644 --- a/phlib/include/apiimport.h +++ b/phlib/include/apiimport.h @@ -35,42 +35,11 @@ typedef NTSTATUS (NTAPI *_NtQueryInformationTransactionManager)( _Out_opt_ PULONG ReturnLength ); -// shell32 - -#if defined(_M_IX86) -#define __unaligned -#endif - -typedef HRESULT (WINAPI *_SHCreateShellItem)( - _In_opt_ const struct _ITEMIDLIST __unaligned *pidlParent, - _In_opt_ struct IShellFolder *psfParent, - _In_ const struct _ITEMIDLIST __unaligned *pidl, - _Out_ struct IShellItem **ppsi - ); - -typedef HRESULT (WINAPI *_SHOpenFolderAndSelectItems)( - _In_ const struct _ITEMIDLIST __unaligned *pidlFolder, - _In_ UINT cidl, - _In_reads_opt_(cidl) const struct _ITEMIDLIST __unaligned **apidl, - _In_ ULONG dwFlags - ); - -typedef HRESULT (WINAPI *_SHParseDisplayName)( - _In_ LPCWSTR pszName, - _In_opt_ struct IBindCtx *pbc, - _Out_ const struct _ITEMIDLIST __unaligned **ppidl, - _In_ ULONG sfgaoIn, - _Out_ ULONG *psfgaoOut - ); - #define PH_DECLARE_IMPORT(Name) _##Name Name##_Import(VOID) PH_DECLARE_IMPORT(NtQueryInformationEnlistment); PH_DECLARE_IMPORT(NtQueryInformationResourceManager); PH_DECLARE_IMPORT(NtQueryInformationTransaction); PH_DECLARE_IMPORT(NtQueryInformationTransactionManager); -PH_DECLARE_IMPORT(SHCreateShellItem); -PH_DECLARE_IMPORT(SHOpenFolderAndSelectItems); -PH_DECLARE_IMPORT(SHParseDisplayName); #endif diff --git a/phlib/include/guisup.h b/phlib/include/guisup.h index 37dfea2a3b28..d3ab3f9426e3 100644 --- a/phlib/include/guisup.h +++ b/phlib/include/guisup.h @@ -11,10 +11,6 @@ extern "C" { // guisup -typedef BOOL (WINAPI *_IsImmersiveProcess)( - _In_ HANDLE hProcess - ); - #define RFF_NOBROWSE 0x0001 #define RFF_NODEFAULT 0x0002 #define RFF_CALCDIRECTORY 0x0004 @@ -43,24 +39,6 @@ typedef LPNMRUNFILEDLGW LPNMRUNFILEDLG; typedef HANDLE HTHEME; -typedef BOOL (WINAPI *_RunFileDlg)( - _In_ HWND hwndOwner, - _In_opt_ HICON hIcon, - _In_opt_ LPCWSTR lpszDirectory, - _In_opt_ LPCWSTR lpszTitle, - _In_opt_ LPCWSTR lpszDescription, - _In_ ULONG uFlags - ); - -typedef HRESULT (WINAPI *_SHAutoComplete)( - _In_ HWND hwndEdit, - _In_ ULONG dwFlags - ); - -extern _IsImmersiveProcess IsImmersiveProcess_I; -extern _RunFileDlg RunFileDlg; -extern _SHAutoComplete SHAutoComplete_I; - extern PH_INTEGER_PAIR PhSmallIconSize; extern PH_INTEGER_PAIR PhLargeIconSize; @@ -905,6 +883,18 @@ PhWindowNotifyTopMostEvent( _In_ BOOLEAN TopMost ); +PHLIBAPI +BOOLEAN +NTAPI +PhShowRunFileDialog( + _In_ HWND WindowHandle, + _In_opt_ HICON WindowIcon, + _In_opt_ PWSTR WorkingDirectory, + _In_opt_ PWSTR WindowTitle, + _In_opt_ PWSTR WindowDescription, + _In_ ULONG Flags + ); + // theme support (theme.c) PHLIBAPI extern HFONT PhApplicationFont; // phapppub diff --git a/phlib/util.c b/phlib/util.c index 0330a5f3c2dd..0d1ab8316150 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -3401,14 +3401,14 @@ VOID PhShellExploreFile( _In_ PWSTR FileName ) { - if (SHOpenFolderAndSelectItems_Import() && SHParseDisplayName_Import()) + if (SHOpenFolderAndSelectItems && SHParseDisplayName) { LPITEMIDLIST item; SFGAOF attributes; - if (SUCCEEDED(SHParseDisplayName_Import()(FileName, NULL, &item, 0, &attributes))) + if (SUCCEEDED(SHParseDisplayName(FileName, NULL, &item, 0, &attributes))) { - SHOpenFolderAndSelectItems_Import()(item, 0, NULL, 0); + SHOpenFolderAndSelectItems(item, 0, NULL, 0); CoTaskMemFree(item); } else @@ -4263,7 +4263,7 @@ VOID PhSetFileDialogFileName( PH_STRINGREF baseNamePart; if (PhSplitStringRefAtLastChar(&fileName, OBJ_NAME_PATH_SEPARATOR, &pathNamePart, &baseNamePart) && - SHParseDisplayName_Import() && SHCreateShellItem_Import()) + SHParseDisplayName && SHCreateShellItem) { LPITEMIDLIST item; SFGAOF attributes; @@ -4271,9 +4271,9 @@ VOID PhSetFileDialogFileName( pathName = PhCreateString2(&pathNamePart); - if (SUCCEEDED(SHParseDisplayName_Import()(pathName->Buffer, NULL, &item, 0, &attributes))) + if (SUCCEEDED(SHParseDisplayName(pathName->Buffer, NULL, &item, 0, &attributes))) { - SHCreateShellItem_Import()(NULL, NULL, item, &shellItem); + SHCreateShellItem(NULL, NULL, item, &shellItem); CoTaskMemFree(item); } From 08119a44971420d99192fda80edf9dd041980eb5 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 17 Feb 2019 02:45:50 +0100 Subject: [PATCH 1682/2058] peview: Improve import/export ordinal name lookup, Fix import/export symbol lookup --- tools/peview/expprp.c | 32 ++++------ tools/peview/impprp.c | 139 +++++++++++++----------------------------- 2 files changed, 56 insertions(+), 115 deletions(-) diff --git a/tools/peview/expprp.c b/tools/peview/expprp.c index 201d76c1e246..3354edb20e2b 100644 --- a/tools/peview/expprp.c +++ b/tools/peview/expprp.c @@ -70,7 +70,7 @@ INT_PTR CALLBACK PvpPeExportsDlgProc( WCHAR number[PH_INT32_STR_LEN_1]; WCHAR pointer[PH_PTR_STR_LEN_1]; - PhPrintUInt64(number, i + 1); + PhPrintUInt32(number, i + 1); lvItemIndex = PhAddListViewItem(lvHandle, MAXINT, number, NULL); if (exportFunction.ForwardedName) @@ -117,51 +117,45 @@ INT_PTR CALLBACK PvpPeExportsDlgProc( { if (exportFunction.Function) { - PPH_STRING exportName; + PPH_STRING exportSymbol = NULL; + PPH_STRING exportSymbolName = NULL; // Try find the export name using symbols. if (PvMappedImage.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) { - exportName = PhGetSymbolFromAddress( + exportSymbol = PhGetSymbolFromAddress( PvSymbolProvider, (ULONG64)PTR_ADD_OFFSET(PvMappedImage.NtHeaders32->OptionalHeader.ImageBase, exportFunction.Function), NULL, NULL, - NULL, + &exportSymbolName, NULL ); } else { - exportName = PhGetSymbolFromAddress( + exportSymbol = PhGetSymbolFromAddress( PvSymbolProvider, (ULONG64)PTR_ADD_OFFSET(PvMappedImage.NtHeaders->OptionalHeader.ImageBase, exportFunction.Function), NULL, NULL, - NULL, + &exportSymbolName, NULL ); } - if (exportName) + if (exportSymbolName) { - static PH_STRINGREF unnamedText = PH_STRINGREF_INIT(L" (unnamed)"); - PH_STRINGREF exportNameText; - PH_STRINGREF firstPart; - PH_STRINGREF secondPart; - - if (PhSplitStringRefAtLastChar(&exportName->sr, L'!', &firstPart, &secondPart)) - exportNameText = secondPart; - else - exportNameText = exportName->sr; - - PhSetListViewSubItem(lvHandle, lvItemIndex, 2, PH_AUTO_T(PH_STRING, PhConcatStringRef2(&exportNameText, &unnamedText))->Buffer); - PhDereferenceObject(exportName); + PhSetListViewSubItem(lvHandle, lvItemIndex, 2, PH_AUTO_T(PH_STRING, PhConcatStringRefZ(&exportSymbolName->sr, L" (unnamed)"))->Buffer); + PhDereferenceObject(exportSymbolName); } else { PhSetListViewSubItem(lvHandle, lvItemIndex, 2, L"(unnamed)"); } + + if (exportSymbol) + PhDereferenceObject(exportSymbol); } else { diff --git a/tools/peview/impprp.c b/tools/peview/impprp.c index d8b21a5f0826..e5ee24c5f6d1 100644 --- a/tools/peview/impprp.c +++ b/tools/peview/impprp.c @@ -63,48 +63,54 @@ PPH_STRING PvpQueryModuleOrdinalName( } else { - if (exportFunction.Function) + if (exportFunction.ForwardedName) { - PPH_STRING symbolName; + PPH_STRING forwardName; - // Try find the export name using symbols. - if (PvMappedImage.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) + forwardName = PhZeroExtendToUtf16(exportFunction.ForwardedName); + + if (forwardName->Buffer[0] == '?') { - symbolName = PhGetSymbolFromAddress( - PvSymbolProvider, - (ULONG64)PTR_ADD_OFFSET(PvMappedImage.NtHeaders32->OptionalHeader.ImageBase, exportFunction.Function), - NULL, - NULL, - NULL, - NULL - ); + PPH_STRING undecoratedName; + + if (undecoratedName = PhUndecorateSymbolName(PvSymbolProvider, forwardName->Buffer)) + PhMoveReference(&forwardName, undecoratedName); } - else + + PhMoveReference(&exportName, PhFormatString(L"%s (Forwarded)", forwardName->Buffer)); + PhDereferenceObject(forwardName); + } + else if (exportFunction.Function) + { + PPH_STRING exportSymbol = NULL; + PPH_STRING exportSymbolName = NULL; + + if (PhLoadModuleSymbolProvider( + PvSymbolProvider, + FileName->Buffer, + (ULONG64)mappedImage.ViewBase, + (ULONG)mappedImage.Size + )) { - symbolName = PhGetSymbolFromAddress( + // Try find the export name using symbols. + exportSymbol = PhGetSymbolFromAddress( PvSymbolProvider, - (ULONG64)PTR_ADD_OFFSET(PvMappedImage.NtHeaders->OptionalHeader.ImageBase, exportFunction.Function), - NULL, + (ULONG64)PTR_ADD_OFFSET(mappedImage.ViewBase, exportFunction.Function), NULL, NULL, + &exportSymbolName, NULL ); } - if (symbolName) + if (exportSymbolName) { - static PH_STRINGREF unnamedText = PH_STRINGREF_INIT(L" (unnamed)"); - PH_STRINGREF exportNameText; - PH_STRINGREF firstPart; - PH_STRINGREF secondPart; - - if (PhSplitStringRefAtLastChar(&symbolName->sr, L'!', &firstPart, &secondPart)) - exportNameText = secondPart; - else - exportNameText = symbolName->sr; - - exportName = PhCreateString2(&exportNameText); + PhSetReference(&exportName, exportSymbolName); + PhDereferenceObject(exportSymbolName); } + + if (exportSymbol) + PhDereferenceObject(exportSymbol); } } @@ -149,7 +155,7 @@ VOID PvpProcessImports( else name = PhZeroExtendToUtf16(importDll.Name); - PhPrintUInt64(number, ++(*Count)); // HACK + PhPrintUInt32(number, ++(*Count)); // HACK lvItemIndex = PhAddListViewItem(ListViewHandle, MAXINT, number, NULL); PhSetListViewSubItem(ListViewHandle, lvItemIndex, 1, name->Buffer); @@ -177,95 +183,36 @@ VOID PvpProcessImports( } else { - PLDR_DATA_TABLE_ENTRY moduleLdrEntry = NULL; - PVOID moduleExportAddress = NULL; - PVOID importModuleDllBase = NULL; - PPH_STRING exportDllName = NULL; + PPH_STRING exportDllName; PPH_STRING exportOrdinalName = NULL; - PPH_STRING exportSymbolName = NULL; - - //PPH_STRING baseDirectory; - // - //if (baseDirectory = PhGetBaseDirectory(PvFileName)) - //{ - // static DLL_DIRECTORY_COOKIE (WINAPI *AddDllDirectory_I)( - // _In_ PCWSTR NewDirectory - // ); - // - // if (AddDllDirectory_I = PhGetDllProcedureAddress(L"kernel32.dll", "AddDllDirectory", 0)) - // { - // AddDllDirectory_I(baseDirectory->Buffer); - // } - //} - // - //if (importModuleDllBase = LoadLibraryA(importDll.Name)) - //{ - // moduleLdrEntry = PhFindLoaderEntry(importModuleDllBase, NULL, NULL); - // moduleExportAddress = PhGetDllBaseProcedureAddress(importModuleDllBase, NULL, importEntry.Ordinal); - // exportOrdinalName = PhGetExportNameFromOrdinal(importModuleDllBase, importEntry.Ordinal); - //} if (exportDllName = PhConvertUtf8ToUtf16(importDll.Name)) { PPH_STRING filePath; + // TODO: Implement ApiSet mappings for exportDllName. (dmex) + // TODO: Add DLL directory to PhSearchFilePath for locating non-system images. (dmex) + if (filePath = PhSearchFilePath(exportDllName->Buffer, L".dll")) { PhMoveReference(&exportDllName, filePath); } exportOrdinalName = PvpQueryModuleOrdinalName(exportDllName, importEntry.Ordinal); + PhDereferenceObject(exportDllName); } if (exportOrdinalName) { name = PhaFormatString(L"%s (Ordinal %u)", PhGetStringOrEmpty(exportOrdinalName), importEntry.Ordinal); PhSetListViewSubItem(ListViewHandle, lvItemIndex, 2, PhGetString(name)); + PhDereferenceObject(exportOrdinalName); } else { - if (moduleLdrEntry && moduleExportAddress) - { - if (PhLoadModuleSymbolProvider( - PvSymbolProvider, - moduleLdrEntry->FullDllName.Buffer, - (ULONG64)importModuleDllBase, - moduleLdrEntry->SizeOfImage - )) - { - exportSymbolName = PhGetSymbolFromAddress( - PvSymbolProvider, - (ULONG64)moduleExportAddress, - NULL, - NULL, - NULL, - NULL - ); - } - } - - if (exportSymbolName) - { - PH_STRINGREF firstPart; - PH_STRINGREF secondPart; - - if (PhSplitStringRefAtLastChar(&exportSymbolName->sr, L'!', &firstPart, &secondPart)) - name = PhaFormatString(L"%s (Ordinal %u)", secondPart.Buffer, importEntry.Ordinal); - else - name = PhaFormatString(L"%s (Ordinal %u)", exportSymbolName->Buffer, importEntry.Ordinal); - - PhSetListViewSubItem(ListViewHandle, lvItemIndex, 2, name->Buffer); - } - else - { - name = PhaFormatString(L"(Ordinal %u)", importEntry.Ordinal); - PhSetListViewSubItem(ListViewHandle, lvItemIndex, 2, name->Buffer); - } + name = PhaFormatString(L"(Ordinal %u)", importEntry.Ordinal); + PhSetListViewSubItem(ListViewHandle, lvItemIndex, 2, name->Buffer); } - - if (exportSymbolName) PhDereferenceObject(exportSymbolName); - if (exportOrdinalName) PhDereferenceObject(exportOrdinalName); - if (exportDllName) PhDereferenceObject(exportDllName); } } } From 06ae7a85f617af5081aea8bbb7188757300f4589 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 17 Feb 2019 03:12:19 +0100 Subject: [PATCH 1683/2058] Setup: Update DelayLoadDLLs --- tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj b/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj index 47be456378f5..9d52f172dd0c 100644 --- a/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj +++ b/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj @@ -69,7 +69,7 @@ $(SolutionDir)..\..\phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) Windows 6.01 - %(DelayLoadDLLs) + advapi32.dll;comctl32.dll;gdi32.dll;ole32.dll;oleaut32.dll;shell32.dll;user32.dll;uxtheme.dll;winhttp.dll;%(DelayLoadDLLs) _UNICODE;UNICODE;%(PreprocessorDefinitions);$(ExternalCompilerOptions) @@ -102,7 +102,7 @@ Windows 6.01 true - %(DelayLoadDLLs) + advapi32.dll;comctl32.dll;gdi32.dll;ole32.dll;oleaut32.dll;shell32.dll;user32.dll;uxtheme.dll;winhttp.dll;%(DelayLoadDLLs) _UNICODE;UNICODE;%(PreprocessorDefinitions);$(ExternalCompilerOptions) From 006055ce066ed405d84539003a96a52d431a38d8 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 17 Feb 2019 03:15:56 +0100 Subject: [PATCH 1684/2058] peview: Update DelayLoadDLLs --- tools/peview/peview.vcxproj | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tools/peview/peview.vcxproj b/tools/peview/peview.vcxproj index a32ecf7b01a3..7a4d9475fd0b 100644 --- a/tools/peview/peview.vcxproj +++ b/tools/peview/peview.vcxproj @@ -107,7 +107,7 @@ Windows MachineX86 6.01 - %(DelayLoadDLLs) + advapi32.dll;comctl32.dll;gdi32.dll;ole32.dll;propsys.dll;shell32.dll;user32.dll;userenv.dll;uxtheme.dll;version.dll;winsta.dll;%(DelayLoadDLLs) ..\..\phnt\include;..\..\phlib\include;include;%(AdditionalIncludeDirectories) @@ -138,7 +138,7 @@ Windows MachineX64 6.01 - %(DelayLoadDLLs) + advapi32.dll;comctl32.dll;gdi32.dll;ole32.dll;propsys.dll;shell32.dll;user32.dll;userenv.dll;uxtheme.dll;version.dll;winsta.dll;%(DelayLoadDLLs) ..\..\phnt\include;..\..\phlib\include;include;%(AdditionalIncludeDirectories) @@ -175,7 +175,7 @@ MachineX86 true 6.01 - %(DelayLoadDLLs) + advapi32.dll;comctl32.dll;gdi32.dll;ole32.dll;propsys.dll;shell32.dll;user32.dll;userenv.dll;uxtheme.dll;version.dll;winsta.dll;%(DelayLoadDLLs) ..\..\phnt\include;..\..\phlib\include;include;%(AdditionalIncludeDirectories) @@ -211,7 +211,7 @@ MachineX64 true 6.01 - %(DelayLoadDLLs) + advapi32.dll;comctl32.dll;gdi32.dll;ole32.dll;propsys.dll;shell32.dll;user32.dll;userenv.dll;uxtheme.dll;version.dll;winsta.dll;%(DelayLoadDLLs) ..\..\phnt\include;..\..\phlib\include;include;%(AdditionalIncludeDirectories) From 35fda0b17d4271384f6c270d6d7ece86b2bb7f57 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 17 Feb 2019 04:03:55 +0100 Subject: [PATCH 1685/2058] Improve maro usage --- phlib/basesup.c | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/phlib/basesup.c b/phlib/basesup.c index ca60555b2c76..915d1fe06ffa 100644 --- a/phlib/basesup.c +++ b/phlib/basesup.c @@ -651,7 +651,7 @@ PSTR PhDuplicateBytesZ( PSTR newString; SIZE_T length; - length = strlen(String) + 1; // include the null terminator + length = strlen(String) + sizeof(ANSI_NULL); // include the null terminator newString = PhAllocate(length); memcpy(newString, String, length); @@ -674,7 +674,7 @@ PSTR PhDuplicateBytesZSafe( PSTR newString; SIZE_T length; - length = strlen(String) + 1; // include the null terminator + length = strlen(String) + sizeof(ANSI_NULL); // include the null terminator newString = PhAllocateSafe(length); @@ -700,7 +700,7 @@ PWSTR PhDuplicateStringZ( PWSTR newString; SIZE_T length; - length = (PhCountStringZ(String) + 1) * sizeof(WCHAR); // include the null terminator + length = (PhCountStringZ(String) + sizeof(UNICODE_NULL)) * sizeof(WCHAR); // include the null terminator newString = PhAllocate(length); memcpy(newString, String, length); @@ -753,10 +753,10 @@ BOOLEAN PhCopyBytesZ( // Copy the string if there is enough room. - if (OutputBuffer && OutputCount >= i + 1) // need one character for null terminator + if (OutputBuffer && OutputCount >= i + sizeof(ANSI_NULL)) // need one character for null terminator { memcpy(OutputBuffer, InputBuffer, i); - OutputBuffer[i] = 0; + OutputBuffer[i] = ANSI_NULL; copied = TRUE; } else @@ -765,7 +765,7 @@ BOOLEAN PhCopyBytesZ( } if (ReturnCount) - *ReturnCount = i + 1; + *ReturnCount = i + sizeof(ANSI_NULL); return copied; } @@ -815,10 +815,10 @@ BOOLEAN PhCopyStringZ( // Copy the string if there is enough room. - if (OutputBuffer && OutputCount >= i + 1) // need one character for null terminator + if (OutputBuffer && OutputCount >= i + sizeof(UNICODE_NULL)) // need one character for null terminator { memcpy(OutputBuffer, InputBuffer, i * sizeof(WCHAR)); - OutputBuffer[i] = 0; + OutputBuffer[i] = UNICODE_NULL; copied = TRUE; } else @@ -827,7 +827,7 @@ BOOLEAN PhCopyStringZ( } if (ReturnCount) - *ReturnCount = i + 1; + *ReturnCount = i + sizeof(UNICODE_NULL); return copied; } @@ -877,10 +877,10 @@ BOOLEAN PhCopyStringZFromBytes( // Copy the string if there is enough room. - if (OutputBuffer && OutputCount >= i + 1) // need one character for null terminator + if (OutputBuffer && OutputCount >= i + sizeof(UNICODE_NULL)) // need one character for null terminator { PhZeroExtendToUtf16Buffer(InputBuffer, i, OutputBuffer); - OutputBuffer[i] = 0; + OutputBuffer[i] = UNICODE_NULL; copied = TRUE; } else @@ -889,7 +889,7 @@ BOOLEAN PhCopyStringZFromBytes( } if (ReturnCount) - *ReturnCount = i + 1; + *ReturnCount = i + sizeof(UNICODE_NULL); return copied; } @@ -957,7 +957,7 @@ BOOLEAN PhCopyStringZFromMultiByte( // Convert the string to Unicode if there is enough room. - if (OutputBuffer && OutputCount >= unicodeBytes / sizeof(WCHAR) + 1) + if (OutputBuffer && OutputCount >= unicodeBytes / sizeof(WCHAR) + sizeof(UNICODE_NULL)) { status = RtlMultiByteToUnicodeN( OutputBuffer, @@ -984,7 +984,7 @@ BOOLEAN PhCopyStringZFromMultiByte( } if (ReturnCount) - *ReturnCount = unicodeBytes / sizeof(WCHAR) + 1; + *ReturnCount = unicodeBytes / sizeof(WCHAR) + sizeof(UNICODE_NULL); return copied; } @@ -2187,7 +2187,7 @@ PPH_STRING PhCreateStringEx( PPH_STRING string; string = PhCreateObject( - FIELD_OFFSET(PH_STRING, Data) + Length + sizeof(WCHAR), // Null terminator + UFIELD_OFFSET(PH_STRING, Data) + Length + sizeof(UNICODE_NULL), // Null terminator for compatibility PhStringType ); @@ -2483,7 +2483,7 @@ PPH_BYTES PhCreateBytesEx( PPH_BYTES bytes; bytes = PhCreateObject( - FIELD_OFFSET(PH_BYTES, Data) + Length + sizeof(CHAR), // Null terminator for compatibility + UFIELD_OFFSET(PH_BYTES, Data) + Length + sizeof(ANSI_NULL), // Null terminator for compatibility PhBytesType ); @@ -3513,7 +3513,7 @@ VOID PhpResizeStringBuilder( memcpy( newString->Buffer, StringBuilder->String->Buffer, - StringBuilder->String->Length + sizeof(WCHAR) // Include null terminator + StringBuilder->String->Length + sizeof(UNICODE_NULL) // Include null terminator ); // Copy the old string length. @@ -3889,7 +3889,7 @@ VOID PhpResizeBytesBuilder( memcpy( newBytes->Buffer, BytesBuilder->Bytes->Buffer, - BytesBuilder->Bytes->Length + sizeof(CHAR) // Include null terminator + BytesBuilder->Bytes->Length + sizeof(ANSI_NULL) // Include null terminator ); // Copy the old byte string length. @@ -5217,7 +5217,7 @@ PVOID PhAllocateFromFreeList( } else { - entry = PhAllocate(FIELD_OFFSET(PH_FREE_LIST_ENTRY, Body) + FreeList->Size); + entry = PhAllocate(UFIELD_OFFSET(PH_FREE_LIST_ENTRY, Body) + FreeList->Size); } return &entry->Body; From 8168b44e47f9b8daab14203db62d6e64fcfe4b2c Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 17 Feb 2019 04:14:42 +0100 Subject: [PATCH 1686/2058] Improve macro usage --- ProcessHacker/about.c | 2 +- ProcessHacker/appsup.c | 8 ++++---- ProcessHacker/dbgcon.c | 20 +++++++++++--------- ProcessHacker/hndllist.c | 2 +- ProcessHacker/logwnd.c | 2 +- ProcessHacker/mainwnd.c | 6 +++--- ProcessHacker/memedit.c | 2 +- ProcessHacker/memlists.c | 2 +- ProcessHacker/memprv.c | 2 +- ProcessHacker/options.c | 2 +- ProcessHacker/procprp.c | 2 +- ProcessHacker/syssccpu.c | 2 +- phlib/extlv.c | 12 ++++++------ phlib/maplib.c | 4 ++-- phlib/symprv.c | 2 +- phlib/theme.c | 8 ++++---- tools/peview/prpsh.c | 2 +- 17 files changed, 41 insertions(+), 39 deletions(-) diff --git a/ProcessHacker/about.c b/ProcessHacker/about.c index 0a8adc946709..357ca6374037 100644 --- a/ProcessHacker/about.c +++ b/ProcessHacker/about.c @@ -161,7 +161,7 @@ VOID PhShowAboutDialog( ShowWindow(PhAboutWindowHandle, SW_SHOW); } - if (IsIconic(PhAboutWindowHandle)) + if (IsMinimized(PhAboutWindowHandle)) ShowWindow(PhAboutWindowHandle, SW_RESTORE); else SetForegroundWindow(PhAboutWindowHandle); diff --git a/ProcessHacker/appsup.c b/ProcessHacker/appsup.c index 57eae47c214d..96161692ab31 100644 --- a/ProcessHacker/appsup.c +++ b/ProcessHacker/appsup.c @@ -941,7 +941,7 @@ VOID PhCopyListViewInfoTip( Tip->Buffer, copyLength * 2 ); - GetInfoTip->pszText[copyIndex + copyLength] = 0; + GetInfoTip->pszText[copyIndex + copyLength] = UNICODE_NULL; } VOID PhCopyListView( @@ -1969,11 +1969,11 @@ BOOLEAN PhpSelectFavoriteInRegedit( for (i = 3; i < count; i++) { MENUITEMINFO info = { sizeof(MENUITEMINFO) }; - WCHAR buffer[32]; + WCHAR buffer[MAX_PATH]; info.fMask = MIIM_ID | MIIM_STRING; info.dwTypeData = buffer; - info.cch = sizeof(buffer) / sizeof(WCHAR); + info.cch = RTL_NUMBER_OF(buffer); GetMenuItemInfo(favoritesMenu, i, TRUE, &info); if (info.cch == FavoriteName->Length / sizeof(WCHAR)) @@ -2007,7 +2007,7 @@ BOOLEAN PhpSelectFavoriteInRegedit( PostMessage(RegeditWindow, WM_MENUSELECT, MAKEWPARAM(0, 0xffff), 0); // Bring regedit to the top. - if (IsIconic(RegeditWindow)) + if (IsMinimized(RegeditWindow)) { ShowWindow(RegeditWindow, SW_RESTORE); SetForegroundWindow(RegeditWindow); diff --git a/ProcessHacker/dbgcon.c b/ProcessHacker/dbgcon.c index de27117ce759..523352124088 100644 --- a/ProcessHacker/dbgcon.c +++ b/ProcessHacker/dbgcon.c @@ -90,9 +90,10 @@ VOID PhShowDebugConsole( // Set a handler so we can catch Ctrl+C and Ctrl+Break. SetConsoleCtrlHandler(ConsoleHandlerRoutine, TRUE); - freopen("CONOUT$", "w", stdout); - freopen("CONOUT$", "w", stderr); - freopen("CONIN$", "r", stdin); + _wfreopen(L"CONOUT$", L"w", stdout); + _wfreopen(L"CONOUT$", L"w", stderr); + _wfreopen(L"CONIN$", L"r", stdin); + DebugConsoleThreadHandle = PhCreateThread(0, PhpDebugConsoleThreadStart, NULL); } else @@ -102,7 +103,7 @@ VOID PhShowDebugConsole( consoleWindow = GetConsoleWindow(); // Console window already exists, so bring it to the top. - if (IsIconic(consoleWindow)) + if (IsMinimized(consoleWindow)) ShowWindow(consoleWindow, SW_RESTORE); else BringWindowToTop(consoleWindow); @@ -115,9 +116,9 @@ VOID PhCloseDebugConsole( VOID ) { - freopen("NUL", "w", stdout); - freopen("NUL", "w", stderr); - freopen("NUL", "r", stdin); + _wfreopen(L"NUL", L"w", stdout); + _wfreopen(L"NUL", L"w", stderr); + _wfreopen(L"NUL", L"r", stdin); FreeConsole(); } @@ -599,7 +600,7 @@ static VOID PhpTestRwLock( Context->ReleaseShared(Context->Parameter); // Null test - + PhInitializeStopwatch(&stopwatch); PhStartStopwatch(&stopwatch); for (i = 0; i < 2000000; i++) @@ -626,6 +627,7 @@ static VOID PhpTestRwLock( } PhWaitForBarrier(&RwStartBarrier, FALSE); + PhInitializeStopwatch(&stopwatch); PhStartStopwatch(&stopwatch); NtWaitForMultipleObjects(RW_PROCESSORS, threadHandles, WaitAll, FALSE, NULL); PhStopStopwatch(&stopwatch); @@ -742,7 +744,7 @@ NTSTATUS PhpDebugConsoleThreadStart( inputLength = (ULONG)PhCountStringZ(line); if (inputLength != 0) - line[inputLength - 1] = 0; + line[inputLength - 1] = UNICODE_NULL; context = NULL; command = wcstok_s(line, delims, &context); diff --git a/ProcessHacker/hndllist.c b/ProcessHacker/hndllist.c index 1bf0b08b34ad..7f16065c2e4a 100644 --- a/ProcessHacker/hndllist.c +++ b/ProcessHacker/hndllist.c @@ -596,7 +596,7 @@ BOOLEAN NTAPI PhpHandleTreeNewCallback( node->FileShareAccessText[0] = '-'; node->FileShareAccessText[1] = '-'; node->FileShareAccessText[2] = '-'; - node->FileShareAccessText[3] = 0; + node->FileShareAccessText[3] = UNICODE_NULL; if (handleItem->FileFlags & PH_HANDLE_FILE_SHARED_READ) node->FileShareAccessText[0] = 'R'; diff --git a/ProcessHacker/logwnd.c b/ProcessHacker/logwnd.c index c917b31c0f6a..d03dd2c8f250 100644 --- a/ProcessHacker/logwnd.c +++ b/ProcessHacker/logwnd.c @@ -58,7 +58,7 @@ VOID PhShowLogDialog( ShowWindow(PhLogWindowHandle, SW_SHOW); } - if (IsIconic(PhLogWindowHandle)) + if (IsMinimized(PhLogWindowHandle)) ShowWindow(PhLogWindowHandle, SW_RESTORE); else SetForegroundWindow(PhLogWindowHandle); diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index 39fbe34e198b..a6d7bbb5994e 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -1712,7 +1712,7 @@ VOID PhMwpOnSize( VOID ) { - if (!IsIconic(PhMainWndHandle)) + if (!IsMinimized(PhMainWndHandle)) { HDWP deferHandle; @@ -1956,7 +1956,7 @@ ULONG_PTR PhMwpOnUserMessage( ShowWindow(PhMainWndHandle, SW_SHOW); } - if (IsIconic(PhMainWndHandle)) + if (IsMinimized(PhMainWndHandle)) { ShowWindow(PhMainWndHandle, SW_RESTORE); } @@ -2351,7 +2351,7 @@ VOID PhMwpActivateWindow( _In_ BOOLEAN Toggle ) { - if (IsIconic(PhMainWndHandle)) + if (IsMinimized(PhMainWndHandle)) { ShowWindow(PhMainWndHandle, SW_RESTORE); SetForegroundWindow(PhMainWndHandle); diff --git a/ProcessHacker/memedit.c b/ProcessHacker/memedit.c index dc821cc892f1..ad83c8438a4a 100644 --- a/ProcessHacker/memedit.c +++ b/ProcessHacker/memedit.c @@ -133,7 +133,7 @@ VOID PhShowMemoryEditorDialog( { context = CONTAINING_RECORD(links, MEMORY_EDITOR_CONTEXT, Links); - if (IsIconic(context->WindowHandle)) + if (IsMinimized(context->WindowHandle)) ShowWindow(context->WindowHandle, SW_RESTORE); else SetForegroundWindow(context->WindowHandle); diff --git a/ProcessHacker/memlists.c b/ProcessHacker/memlists.c index 61948f7cb774..72eaa0015f9b 100644 --- a/ProcessHacker/memlists.c +++ b/ProcessHacker/memlists.c @@ -62,7 +62,7 @@ VOID PhShowMemoryListsDialog( if (!IsWindowVisible(PhMemoryListsWindowHandle)) ShowWindow(PhMemoryListsWindowHandle, SW_SHOW); - else if (IsIconic(PhMemoryListsWindowHandle)) + else if (IsMinimized(PhMemoryListsWindowHandle)) ShowWindow(PhMemoryListsWindowHandle, SW_RESTORE); else SetForegroundWindow(PhMemoryListsWindowHandle); diff --git a/ProcessHacker/memprv.c b/ProcessHacker/memprv.c index 108b7335bdb9..b04e2cd2529e 100644 --- a/ProcessHacker/memprv.c +++ b/ProcessHacker/memprv.c @@ -46,7 +46,7 @@ VOID PhGetMemoryProtectionString( if (!Protection) { - String[0] = 0; + String[0] = UNICODE_NULL; return; } diff --git a/ProcessHacker/options.c b/ProcessHacker/options.c index 9299149bb677..e842296d920a 100644 --- a/ProcessHacker/options.c +++ b/ProcessHacker/options.c @@ -174,7 +174,7 @@ VOID PhShowOptionsDialog( ShowWindow(PhOptionsWindowHandle, SW_SHOW); } - if (IsIconic(PhOptionsWindowHandle)) + if (IsMinimized(PhOptionsWindowHandle)) ShowWindow(PhOptionsWindowHandle, SW_RESTORE); else SetForegroundWindow(PhOptionsWindowHandle); diff --git a/ProcessHacker/procprp.c b/ProcessHacker/procprp.c index c5593af224d6..da34daa94e8b 100644 --- a/ProcessHacker/procprp.c +++ b/ProcessHacker/procprp.c @@ -273,7 +273,7 @@ LRESULT CALLBACK PhpPropSheetWndProc( break; case WM_SIZE: { - if (!IsIconic(hwnd)) + if (!IsMinimized(hwnd)) { PhLayoutManagerLayout(&propSheetContext->LayoutManager); } diff --git a/ProcessHacker/syssccpu.c b/ProcessHacker/syssccpu.c index 4b800884af0b..03c48530e5a3 100644 --- a/ProcessHacker/syssccpu.c +++ b/ProcessHacker/syssccpu.c @@ -840,7 +840,7 @@ VOID PhSipGetCpuBrandString( ); PhZeroExtendToUtf16Buffer(brandString, 48, BrandString); - BrandString[48] = 0; + BrandString[48] = UNICODE_NULL; } BOOLEAN PhSipGetCpuFrequencyFromDistribution( diff --git a/phlib/extlv.c b/phlib/extlv.c index 6aad9f6535e6..8a9184feaedc 100644 --- a/phlib/extlv.c +++ b/phlib/extlv.c @@ -721,8 +721,8 @@ static INT PhpDefaultCompareListViewItems( _In_ ULONG Column ) { - WCHAR xText[261]; - WCHAR yText[261]; + WCHAR xText[MAX_PATH + 1]; + WCHAR yText[MAX_PATH + 1]; LVITEM item; // Get the X item text. @@ -731,18 +731,18 @@ static INT PhpDefaultCompareListViewItems( item.iItem = X; item.iSubItem = Column; item.pszText = xText; - item.cchTextMax = 260; + item.cchTextMax = MAX_PATH; - xText[0] = 0; + xText[0] = UNICODE_NULL; CallWindowProc(Context->OldWndProc, Context->Handle, LVM_GETITEM, 0, (LPARAM)&item); // Get the Y item text. item.iItem = Y; item.pszText = yText; - item.cchTextMax = 260; + item.cchTextMax = MAX_PATH; - yText[0] = 0; + yText[0] = UNICODE_NULL; CallWindowProc(Context->OldWndProc, Context->Handle, LVM_GETITEM, 0, (LPARAM)&item); // Compare them. diff --git a/phlib/maplib.c b/phlib/maplib.c index 2a24acae8911..2e9c171de5a3 100644 --- a/phlib/maplib.c +++ b/phlib/maplib.c @@ -294,14 +294,14 @@ NTSTATUS PhpGetMappedArchiveMemberFromHeader( { // Longnames member. Set the name to "/". Member->NameBuffer[0] = '/'; - Member->NameBuffer[1] = 0; + Member->NameBuffer[1] = ANSI_NULL; Member->Type = LongnamesArchiveMemberType; } else { // Linker member. Set the name to "". - Member->NameBuffer[0] = 0; + Member->NameBuffer[0] = ANSI_NULL; Member->Type = LinkerArchiveMemberType; } diff --git a/phlib/symprv.c b/phlib/symprv.c index 8023806dfcd6..b6054b4df439 100644 --- a/phlib/symprv.c +++ b/phlib/symprv.c @@ -967,7 +967,7 @@ NTSTATUS PhpLookupDynamicFunctionTable( } else { - OutOfProcessCallbackDllBuffer[0] = 0; + OutOfProcessCallbackDllBuffer[0] = UNICODE_NULL; if (OutOfProcessCallbackDllString) { diff --git a/phlib/theme.c b/phlib/theme.c index 173b7e7d0ed7..54ff46887044 100644 --- a/phlib/theme.c +++ b/phlib/theme.c @@ -242,7 +242,7 @@ VOID PhReInitializeWindowTheme( WCHAR windowClassName[MAX_PATH]; if (!GetClassName(currentWindow, windowClassName, RTL_NUMBER_OF(windowClassName))) - windowClassName[0] = 0; + windowClassName[0] = UNICODE_NULL; //dprintf("PhReInitializeWindowTheme: %S\r\n", windowClassName); @@ -352,7 +352,7 @@ BOOLEAN CALLBACK PhpThemeWindowEnumChildWindows( return TRUE; if (!GetClassName(WindowHandle, windowClassName, RTL_NUMBER_OF(windowClassName))) - windowClassName[0] = 0; + windowClassName[0] = UNICODE_NULL; //dprintf("PhpThemeWindowEnumChildWindows: %S\r\n", windowClassName); @@ -506,7 +506,7 @@ BOOLEAN CALLBACK PhpReInitializeThemeWindowEnumChildWindows( ); if (!GetClassName(WindowHandle, windowClassName, RTL_NUMBER_OF(windowClassName))) - windowClassName[0] = 0; + windowClassName[0] = UNICODE_NULL; //dprintf("PhpReInitializeThemeWindowEnumChildWindows: %S\r\n", windowClassName); @@ -1442,7 +1442,7 @@ LRESULT CALLBACK PhpThemeWindowSubclassProc( WCHAR className[MAX_PATH]; if (!GetClassName(customDraw->hdr.hwndFrom, className, RTL_NUMBER_OF(className))) - className[0] = 0; + className[0] = UNICODE_NULL; //dprintf("NM_CUSTOMDRAW: %S\r\n", className); diff --git a/tools/peview/prpsh.c b/tools/peview/prpsh.c index 0db1b41c09bc..58cac39eeaca 100644 --- a/tools/peview/prpsh.c +++ b/tools/peview/prpsh.c @@ -252,7 +252,7 @@ LRESULT CALLBACK PvpPropSheetWndProc( break; case WM_SIZE: { - if (!IsIconic(hWnd)) + if (!IsMinimized(hWnd)) { PhLayoutManagerLayout(&propSheetContext->LayoutManager); } From 5ce94f26381d338bbd76ebec1ed710f952066742 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 17 Feb 2019 04:18:00 +0100 Subject: [PATCH 1687/2058] peview: Add missing DelayLoadDLL --- tools/peview/peview.vcxproj | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tools/peview/peview.vcxproj b/tools/peview/peview.vcxproj index 7a4d9475fd0b..649231cfe9d6 100644 --- a/tools/peview/peview.vcxproj +++ b/tools/peview/peview.vcxproj @@ -107,7 +107,7 @@ Windows MachineX86 6.01 - advapi32.dll;comctl32.dll;gdi32.dll;ole32.dll;propsys.dll;shell32.dll;user32.dll;userenv.dll;uxtheme.dll;version.dll;winsta.dll;%(DelayLoadDLLs) + advapi32.dll;comctl32.dll;comdlg32.dll;gdi32.dll;ole32.dll;propsys.dll;shell32.dll;user32.dll;userenv.dll;uxtheme.dll;version.dll;winsta.dll;%(DelayLoadDLLs) ..\..\phnt\include;..\..\phlib\include;include;%(AdditionalIncludeDirectories) @@ -138,7 +138,7 @@ Windows MachineX64 6.01 - advapi32.dll;comctl32.dll;gdi32.dll;ole32.dll;propsys.dll;shell32.dll;user32.dll;userenv.dll;uxtheme.dll;version.dll;winsta.dll;%(DelayLoadDLLs) + advapi32.dll;comctl32.dll;comdlg32.dll;gdi32.dll;ole32.dll;propsys.dll;shell32.dll;user32.dll;userenv.dll;uxtheme.dll;version.dll;winsta.dll;%(DelayLoadDLLs) ..\..\phnt\include;..\..\phlib\include;include;%(AdditionalIncludeDirectories) @@ -175,7 +175,7 @@ MachineX86 true 6.01 - advapi32.dll;comctl32.dll;gdi32.dll;ole32.dll;propsys.dll;shell32.dll;user32.dll;userenv.dll;uxtheme.dll;version.dll;winsta.dll;%(DelayLoadDLLs) + advapi32.dll;comctl32.dll;comdlg32.dll;gdi32.dll;ole32.dll;propsys.dll;shell32.dll;user32.dll;userenv.dll;uxtheme.dll;version.dll;winsta.dll;%(DelayLoadDLLs) ..\..\phnt\include;..\..\phlib\include;include;%(AdditionalIncludeDirectories) @@ -211,7 +211,7 @@ MachineX64 true 6.01 - advapi32.dll;comctl32.dll;gdi32.dll;ole32.dll;propsys.dll;shell32.dll;user32.dll;userenv.dll;uxtheme.dll;version.dll;winsta.dll;%(DelayLoadDLLs) + advapi32.dll;comctl32.dll;comdlg32.dll;gdi32.dll;ole32.dll;propsys.dll;shell32.dll;user32.dll;userenv.dll;uxtheme.dll;version.dll;winsta.dll;%(DelayLoadDLLs) ..\..\phnt\include;..\..\phlib\include;include;%(AdditionalIncludeDirectories) From 126e7db477a7ff3a1949a27c973cf7e493c1b7d6 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 17 Feb 2019 04:18:56 +0100 Subject: [PATCH 1688/2058] peview: Remove unused win10 sets support --- tools/peview/prpsh.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tools/peview/prpsh.c b/tools/peview/prpsh.c index 58cac39eeaca..d1044585dce1 100644 --- a/tools/peview/prpsh.c +++ b/tools/peview/prpsh.c @@ -158,10 +158,6 @@ INT CALLBACK PvpPropSheetProc( PhSetWindowContext(hwndDlg, UCHAR_MAX, context); SetWindowLongPtr(hwndDlg, GWLP_WNDPROC, (LONG_PTR)PvpPropSheetWndProc); - // HACK HACK HACK - if (WindowsVersion >= WINDOWS_10_RS3) - PhSetWindowStyle(hwndDlg, WS_POPUP, 0); - if (MinimumSize.left == -1) { RECT rect; From f2ba0ebaab7bd3b283670a480736b86f217a6d61 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 17 Feb 2019 04:19:31 +0100 Subject: [PATCH 1689/2058] Add comment --- ProcessHacker/prpgenv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ProcessHacker/prpgenv.c b/ProcessHacker/prpgenv.c index 06ebc431371d..f9f7ef565632 100644 --- a/ProcessHacker/prpgenv.c +++ b/ProcessHacker/prpgenv.c @@ -241,7 +241,7 @@ VOID PhpRefreshEnvironmentList( // Remove the most confusing item. Some say it's just a weird per-drive current directory // with a colon used as a drive letter for some reason. It should not be here. (diversenok) - //if (PhEqualStringRef2(&variable.Name, L"=::", FALSE)) + //if (PhEqualStringRef2(&variable.Name, L"=::", FALSE) && PhEqualStringRef2(&variable.Value, L"::\\", FALSE)) // continue; item.Name = PhCreateString2(&variable.Name); From ae0de7e1e2eb492d6703c9fb05c8f3cdcaed118f Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 17 Feb 2019 04:20:38 +0100 Subject: [PATCH 1690/2058] Improve token capability RID guid lookup --- ProcessHacker/tokprp.c | 47 ++++++++++++++++++++++++++---------------- 1 file changed, 29 insertions(+), 18 deletions(-) diff --git a/ProcessHacker/tokprp.c b/ProcessHacker/tokprp.c index 1430aed846b8..a45cd95e4893 100644 --- a/ProcessHacker/tokprp.c +++ b/ProcessHacker/tokprp.c @@ -2177,24 +2177,24 @@ BOOLEAN PhpAddTokenCapabilities( else if (subAuthoritiesCount == SECURITY_CAPABILITY_RID_COUNT) { PPH_STRING capabilityName; - GUID capabilityGuid; - ULONG firstPart; - ULONG secondPart; - ULONG thirdPart; - ULONG lastPart; - - firstPart = *RtlSubAuthoritySid(TokenPageContext->Capabilities->Groups[i].Sid, 1); - secondPart = *RtlSubAuthoritySid(TokenPageContext->Capabilities->Groups[i].Sid, 2); - thirdPart = *RtlSubAuthoritySid(TokenPageContext->Capabilities->Groups[i].Sid, 3); - lastPart = *RtlSubAuthoritySid(TokenPageContext->Capabilities->Groups[i].Sid, 4); - - capabilityGuid.Data1 = firstPart; - capabilityGuid.Data2 = LOWORD(secondPart); - capabilityGuid.Data3 = HIWORD(secondPart); - *((PULONG)&capabilityGuid.Data4[0]) = thirdPart; - *((PULONG)&capabilityGuid.Data4[4]) = lastPart; - - if (name = PhFormatGuid(&capabilityGuid)) + union + { + GUID Guid; + struct + { + ULONG Data1; + ULONG Data2; + ULONG Data3; + ULONG Data4; + }; + } capabilityGuid; + + capabilityGuid.Data1 = *RtlSubAuthoritySid(TokenPageContext->Capabilities->Groups[i].Sid, 1); + capabilityGuid.Data2 = *RtlSubAuthoritySid(TokenPageContext->Capabilities->Groups[i].Sid, 2); + capabilityGuid.Data3 = *RtlSubAuthoritySid(TokenPageContext->Capabilities->Groups[i].Sid, 3); + capabilityGuid.Data4 = *RtlSubAuthoritySid(TokenPageContext->Capabilities->Groups[i].Sid, 4); + + if (name = PhFormatGuid(&capabilityGuid.Guid)) { PhpAddAttributeNode(&TokenPageContext->CapsTreeContext, node, PhFormatString(L"Guid: %s", PhGetString(name))); @@ -2206,6 +2206,17 @@ BOOLEAN PhpAddTokenCapabilities( PhDereferenceObject(name); } + + //ULONG firstPart = *RtlSubAuthoritySid(TokenPageContext->Capabilities->Groups[i].Sid, 1); + //ULONG secondPart = *RtlSubAuthoritySid(TokenPageContext->Capabilities->Groups[i].Sid, 2); + //ULONG thirdPart = *RtlSubAuthoritySid(TokenPageContext->Capabilities->Groups[i].Sid, 3); + //ULONG lastPart = *RtlSubAuthoritySid(TokenPageContext->Capabilities->Groups[i].Sid, 4); + //GUID capabilityGuid; + //capabilityGuid.Data1 = firstPart; + //capabilityGuid.Data2 = LOWORD(secondPart); + //capabilityGuid.Data3 = HIWORD(secondPart); + //*((PULONG)&capabilityGuid.Data4[0]) = thirdPart; + //*((PULONG)&capabilityGuid.Data4[4]) = lastPart; } } } From 89631ca30efd5a71e1918cfadf87841c688a6f9c Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 17 Feb 2019 04:41:52 +0100 Subject: [PATCH 1691/2058] peview: Add MVID for CLR images --- tools/peview/clrprp.c | 248 +++++++++++++++++++++++++--------------- tools/peview/pdb.c | 10 +- tools/peview/peview.rc | 6 +- tools/peview/resource.h | 1 + 4 files changed, 167 insertions(+), 98 deletions(-) diff --git a/tools/peview/clrprp.c b/tools/peview/clrprp.c index 77ce395a3e88..aeff3a2a7188 100644 --- a/tools/peview/clrprp.c +++ b/tools/peview/clrprp.c @@ -56,6 +56,156 @@ typedef struct _STORAGESTREAM } STORAGESTREAM, *PSTORAGESTREAM; #include +PSTORAGESIGNATURE PvpPeGetClrMetaDataHeader( + VOID + ) +{ + PSTORAGESIGNATURE metaData; + + metaData = PhMappedImageRvaToVa(&PvMappedImage, PvImageCor20Header->MetaData.VirtualAddress, NULL); + + if (metaData) + { + __try + { + PhProbeAddress(metaData, PvImageCor20Header->MetaData.Size, PvMappedImage.ViewBase, PvMappedImage.Size, 4); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + metaData = NULL; + } + } + + return metaData; +} + +PPH_STRING PvpPeGetClrFlagsText( + VOID + ) +{ + PH_STRING_BUILDER stringBuilder; + + PhInitializeStringBuilder(&stringBuilder, 256); + + if (PvImageCor20Header->Flags & COMIMAGE_FLAGS_ILONLY) + PhAppendStringBuilder2(&stringBuilder, L"IL only, "); + if (PvImageCor20Header->Flags & COMIMAGE_FLAGS_32BITREQUIRED) + PhAppendStringBuilder2(&stringBuilder, L"32-bit only, "); + if (PvImageCor20Header->Flags & COMIMAGE_FLAGS_32BITPREFERRED) + PhAppendStringBuilder2(&stringBuilder, L"32-bit preferred, "); + if (PvImageCor20Header->Flags & COMIMAGE_FLAGS_IL_LIBRARY) + PhAppendStringBuilder2(&stringBuilder, L"IL library, "); + + if (PvImageCor20Header->StrongNameSignature.VirtualAddress != 0 && PvImageCor20Header->StrongNameSignature.Size != 0) + { + if (PvImageCor20Header->Flags & COMIMAGE_FLAGS_STRONGNAMESIGNED) + PhAppendStringBuilder2(&stringBuilder, L"Strong-name signed, "); + else + PhAppendStringBuilder2(&stringBuilder, L"Strong-name delay signed, "); + } + + if (PvImageCor20Header->Flags & COMIMAGE_FLAGS_NATIVE_ENTRYPOINT) + PhAppendStringBuilder2(&stringBuilder, L"Native entry-point, "); + if (PvImageCor20Header->Flags & COMIMAGE_FLAGS_TRACKDEBUGDATA) + PhAppendStringBuilder2(&stringBuilder, L"Track debug data, "); + + if (PhEndsWithString2(stringBuilder.String, L", ", FALSE)) + PhRemoveEndStringBuilder(&stringBuilder, 2); + + return PhFinalStringBuilderString(&stringBuilder); +} + +PPH_STRING PvpPeGetClrVersionText( + VOID + ) +{ + return PhFormatString( + L"%hu.%hu", + PvImageCor20Header->MajorRuntimeVersion, + PvImageCor20Header->MinorRuntimeVersion + ); +} + +PPH_STRING PvpPeGetClrStorageVersionText( + _In_ PSTORAGESIGNATURE ClrMetaData + ) +{ + if (ClrMetaData && ClrMetaData->VersionLength != 0) + { + return PhZeroExtendToUtf16Ex( + PTR_ADD_OFFSET(ClrMetaData, RTL_SIZEOF_THROUGH_FIELD(STORAGESIGNATURE, VersionLength)), + ClrMetaData->VersionLength + ); + } + + return PhCreateString(L"N/A"); +} + +PPH_STRING PvpPeClrGetMvid( + _In_ PSTORAGESIGNATURE ClrMetaData + ) +{ + PPH_STRING guidMvidString = NULL; + PSTORAGEHEADER storageHeader; + PSTORAGESTREAM streamHeader; + USHORT i; + + storageHeader = PTR_ADD_OFFSET(ClrMetaData, sizeof(STORAGESIGNATURE) + ClrMetaData->VersionLength); + streamHeader = PTR_ADD_OFFSET(storageHeader, sizeof(STORAGEHEADER)); + + for (i = 0; i < storageHeader->Streams; i++) + { + if (PhEqualBytesZ(streamHeader->Name, "#GUID", TRUE)) + { + guidMvidString = PhFormatGuid(PTR_ADD_OFFSET(ClrMetaData, streamHeader->Offset)); + break; + } + + streamHeader = PTR_ADD_OFFSET(streamHeader, ALIGN_UP(UFIELD_OFFSET(STORAGESTREAM, Name) + strlen(streamHeader->Name) + 1, ULONG)); + } + + return guidMvidString; +} + +VOID PvpPeClrEnumSections( + _In_ PSTORAGESIGNATURE ClrMetaData, + _In_ HWND ListViewHandle + ) +{ + PSTORAGEHEADER storageHeader; + PSTORAGESTREAM streamHeader; + USHORT i; + + storageHeader = PTR_ADD_OFFSET(ClrMetaData, sizeof(STORAGESIGNATURE) + ClrMetaData->VersionLength); + streamHeader = PTR_ADD_OFFSET(storageHeader, sizeof(STORAGEHEADER)); + + for (i = 0; i < storageHeader->Streams; i++) + { + INT lvItemIndex; + WCHAR sectionName[65]; + WCHAR pointer[PH_PTR_STR_LEN_1]; + + if (PhCopyStringZFromBytes( + streamHeader->Name, + sizeof(streamHeader->Name), + sectionName, + ARRAYSIZE(sectionName), + NULL + )) + { + lvItemIndex = PhAddListViewItem(ListViewHandle, MAXINT, sectionName, NULL); + PhPrintPointer(pointer, UlongToPtr(streamHeader->Offset)); + PhSetListViewSubItem(ListViewHandle, lvItemIndex, 1, pointer); + PhSetListViewSubItem(ListViewHandle, lvItemIndex, 2, PhaFormatSize(streamHeader->Size, -1)->Buffer); + } + + // Stream headers don't have fixed sizes... + // The size is aligned up based on a variable length string at the end. + streamHeader = PTR_ADD_OFFSET(streamHeader, ALIGN_UP(UFIELD_OFFSET(STORAGESTREAM, Name) + strlen(streamHeader->Name) + 1, ULONG)); + } +} + + INT_PTR CALLBACK PvpPeClrDlgProc( _In_ HWND hwndDlg, _In_ UINT uMsg, @@ -74,9 +224,7 @@ INT_PTR CALLBACK PvpPeClrDlgProc( case WM_INITDIALOG: { HWND lvHandle; - PPH_STRING string; - PH_STRING_BUILDER stringBuilder; - PSTORAGESIGNATURE metaData; + PSTORAGESIGNATURE clrMetaData; lvHandle = GetDlgItem(hwndDlg, IDC_LIST); PhSetListViewStyle(lvHandle, TRUE, TRUE); @@ -85,97 +233,15 @@ INT_PTR CALLBACK PvpPeClrDlgProc( PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 80, L"VA"); PhAddListViewColumn(lvHandle, 2, 2, 2, LVCFMT_LEFT, 80, L"Size"); - string = PhaFormatString( - L"%u.%u", - PvImageCor20Header->MajorRuntimeVersion, - PvImageCor20Header->MinorRuntimeVersion); - PhSetDialogItemText(hwndDlg, IDC_RUNTIMEVERSION, string->Buffer); + PhSetDialogItemText(hwndDlg, IDC_RUNTIMEVERSION, PH_AUTO_T(PH_STRING, PvpPeGetClrVersionText())->Buffer); + PhSetDialogItemText(hwndDlg, IDC_FLAGS, PH_AUTO_T(PH_STRING, PvpPeGetClrFlagsText())->Buffer); - PhInitializeStringBuilder(&stringBuilder, 256); - - if (PvImageCor20Header->Flags & COMIMAGE_FLAGS_ILONLY) - PhAppendStringBuilder2(&stringBuilder, L"IL only, "); - if (PvImageCor20Header->Flags & COMIMAGE_FLAGS_32BITREQUIRED) - PhAppendStringBuilder2(&stringBuilder, L"32-bit only, "); - if (PvImageCor20Header->Flags & COMIMAGE_FLAGS_32BITPREFERRED) - PhAppendStringBuilder2(&stringBuilder, L"32-bit preferred, "); - if (PvImageCor20Header->Flags & COMIMAGE_FLAGS_IL_LIBRARY) - PhAppendStringBuilder2(&stringBuilder, L"IL library, "); - - if (PvImageCor20Header->StrongNameSignature.VirtualAddress != 0 && PvImageCor20Header->StrongNameSignature.Size != 0) - { - if (PvImageCor20Header->Flags & COMIMAGE_FLAGS_STRONGNAMESIGNED) - PhAppendStringBuilder2(&stringBuilder, L"Strong-name signed, "); - else - PhAppendStringBuilder2(&stringBuilder, L"Strong-name delay signed, "); - } - - if (PvImageCor20Header->Flags & COMIMAGE_FLAGS_NATIVE_ENTRYPOINT) - PhAppendStringBuilder2(&stringBuilder, L"Native entry-point, "); - if (PvImageCor20Header->Flags & COMIMAGE_FLAGS_TRACKDEBUGDATA) - PhAppendStringBuilder2(&stringBuilder, L"Track debug data, "); - - if (PhEndsWithString2(stringBuilder.String, L", ", FALSE)) - PhRemoveEndStringBuilder(&stringBuilder, 2); - - PhSetDialogItemText(hwndDlg, IDC_FLAGS, stringBuilder.String->Buffer); - PhDeleteStringBuilder(&stringBuilder); - - metaData = PhMappedImageRvaToVa(&PvMappedImage, PvImageCor20Header->MetaData.VirtualAddress, NULL); - - if (metaData) - { - __try - { - PhProbeAddress(metaData, PvImageCor20Header->MetaData.Size, PvMappedImage.ViewBase, PvMappedImage.Size, 4); - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - metaData = NULL; - } - } - - if (metaData && metaData->VersionLength != 0) + if (clrMetaData = PvpPeGetClrMetaDataHeader()) { - string = PhZeroExtendToUtf16Ex(PTR_ADD_OFFSET(metaData, RTL_SIZEOF_THROUGH_FIELD(STORAGESIGNATURE, VersionLength)), metaData->VersionLength); - PhSetDialogItemText(hwndDlg, IDC_VERSIONSTRING, string->Buffer); - PhDereferenceObject(string); + PhSetDialogItemText(hwndDlg, IDC_VERSIONSTRING, PH_AUTO_T(PH_STRING, PvpPeGetClrStorageVersionText(clrMetaData))->Buffer); + PhSetDialogItemText(hwndDlg, IDC_MVIDSTRING, PH_AUTO_T(PH_STRING, PvpPeClrGetMvid(clrMetaData))->Buffer); - { - PSTORAGEHEADER storageHeader = PTR_ADD_OFFSET(metaData, sizeof(STORAGESIGNATURE) + metaData->VersionLength); - PSTORAGESTREAM streamHeader = PTR_ADD_OFFSET(storageHeader, sizeof(STORAGEHEADER)); - - for (USHORT i = 0; i < storageHeader->Streams; i++) - { - INT lvItemIndex; - WCHAR sectionName[65]; - WCHAR pointer[PH_PTR_STR_LEN_1]; - - if (PhCopyStringZFromBytes( - streamHeader->Name, - sizeof(streamHeader->Name), - sectionName, - ARRAYSIZE(sectionName), - NULL - )) - { - lvItemIndex = PhAddListViewItem(lvHandle, MAXINT, sectionName, NULL); - - PhPrintPointer(pointer, UlongToPtr(streamHeader->Offset)); - - PhSetListViewSubItem(lvHandle, lvItemIndex, 1, pointer); - PhSetListViewSubItem(lvHandle, lvItemIndex, 2, PhaFormatSize(streamHeader->Size, -1)->Buffer); - } - - // Stream headers don't have fixed sizes... - // The size is aligned up based on a variable length string at the end. - streamHeader = PTR_ADD_OFFSET(streamHeader, ALIGN_UP(UFIELD_OFFSET(STORAGESTREAM, Name) + strlen(streamHeader->Name) + 1, ULONG)); - } - } - } - else - { - PhSetDialogItemText(hwndDlg, IDC_VERSIONSTRING, L"N/A"); + PvpPeClrEnumSections(clrMetaData, lvHandle); } } break; diff --git a/tools/peview/pdb.c b/tools/peview/pdb.c index db06b8833681..80d2b16041bd 100644 --- a/tools/peview/pdb.c +++ b/tools/peview/pdb.c @@ -211,7 +211,7 @@ BOOLEAN PdbGetSymbolTypedefType( Info->TypeIndex = typeIndex; wcsncpy(Info->Name, symbolName, ARRAYSIZE(Info->Name)); - Info->Name[ARRAYSIZE(Info->Name) - 1] = 0; + Info->Name[ARRAYSIZE(Info->Name) - 1] = UNICODE_NULL; LocalFree(symbolName); return TRUE; @@ -235,7 +235,7 @@ BOOLEAN PdbGetSymbolEnumType( return FALSE; wcsncpy(Info->Name, symbolName, ARRAYSIZE(Info->Name)); - Info->Name[ARRAYSIZE(Info->Name) - 1] = 0; + Info->Name[ARRAYSIZE(Info->Name) - 1] = UNICODE_NULL; LocalFree(symbolName); // Type index ("typeId" in DIA) @@ -367,7 +367,7 @@ BOOLEAN PdbGetSymbolUDTClass( return FALSE; wcsncpy(Info->Name, symbolName, ARRAYSIZE(Info->Name)); - Info->Name[ARRAYSIZE(Info->Name) - 1] = 0; + Info->Name[ARRAYSIZE(Info->Name) - 1] = UNICODE_NULL; LocalFree(symbolName); // Length ("length" in DIA) @@ -423,7 +423,7 @@ BOOLEAN PdbGetSymbolUDTUnion( return FALSE; wcsncpy(Info->Name, symbolName, ARRAYSIZE(Info->Name)); - Info->Name[ARRAYSIZE(Info->Name) - 1] = 0; + Info->Name[ARRAYSIZE(Info->Name) - 1] = UNICODE_NULL; LocalFree(symbolName); // Length ("length" in DIA) @@ -649,7 +649,7 @@ BOOLEAN PdbGetSymbolData( return FALSE; wcsncpy(Info->Name, symbolName, ARRAYSIZE(Info->Name)); - Info->Name[ARRAYSIZE(Info->Name) - 1] = 0; + Info->Name[ARRAYSIZE(Info->Name) - 1] = UNICODE_NULL; LocalFree(symbolName); // Index of type symbol ("typeId" in DIA) diff --git a/tools/peview/peview.rc b/tools/peview/peview.rc index 40aa784aa804..0c69d66339d0 100644 --- a/tools/peview/peview.rc +++ b/tools/peview/peview.rc @@ -264,8 +264,10 @@ BEGIN EDITTEXT IDC_FLAGS,76,19,217,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER LTEXT "Version String:",IDC_STATIC,7,31,48,8 LTEXT "Static",IDC_VERSIONSTRING,78,31,215,8 - CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,57,286,216 - LTEXT "Sections:",IDC_STATIC,7,47,30,8 + CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,69,286,204 + LTEXT "Sections:",IDC_STATIC,7,58,30,8 + LTEXT "MVID:",IDC_STATIC,7,44,21,8 + EDITTEXT IDC_MVIDSTRING,76,45,217,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER END IDD_PELOADCONFIG DIALOGEX 0, 0, 300, 280 diff --git a/tools/peview/resource.h b/tools/peview/resource.h index 5d6f4d16e200..e492b1f01bdc 100644 --- a/tools/peview/resource.h +++ b/tools/peview/resource.h @@ -39,6 +39,7 @@ #define IDC_VERSION 1013 #define IDC_VERSIONSTRING 1014 #define IDC_IMAGEBASE 1015 +#define IDC_MVIDSTRING 1015 #define IDC_ENTRYPOINT 1016 #define IDC_SYMSEARCH 1017 #define IDC_IMAGETYPE 1017 From 619ee0f599f3352827515902c7f7443f5089aa60 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 17 Feb 2019 04:42:16 +0100 Subject: [PATCH 1692/2058] Add missing copyright --- phlib/mapimg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phlib/mapimg.c b/phlib/mapimg.c index d4e94f431b57..ef931f521da1 100644 --- a/phlib/mapimg.c +++ b/phlib/mapimg.c @@ -3,7 +3,7 @@ * mapped image * * Copyright (C) 2010 wj32 - * Copyright (C) 2017 dmex + * Copyright (C) 2017-2019 dmex * * This file is part of Process Hacker. * From 6e71c2e7999393cbec4fc7a06569c630eb807156 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 19 Feb 2019 18:34:39 +0100 Subject: [PATCH 1693/2058] Fix PhCopyStringZFromBytes regression from commit 35fda0b1 --- phlib/basesup.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/phlib/basesup.c b/phlib/basesup.c index 915d1fe06ffa..5ecb3f1cb2d9 100644 --- a/phlib/basesup.c +++ b/phlib/basesup.c @@ -877,7 +877,7 @@ BOOLEAN PhCopyStringZFromBytes( // Copy the string if there is enough room. - if (OutputBuffer && OutputCount >= i + sizeof(UNICODE_NULL)) // need one character for null terminator + if (OutputBuffer && OutputCount >= i + sizeof(ANSI_NULL)) // need one character for null terminator { PhZeroExtendToUtf16Buffer(InputBuffer, i, OutputBuffer); OutputBuffer[i] = UNICODE_NULL; @@ -889,7 +889,7 @@ BOOLEAN PhCopyStringZFromBytes( } if (ReturnCount) - *ReturnCount = i + sizeof(UNICODE_NULL); + *ReturnCount = i + sizeof(ANSI_NULL); return copied; } From 3bd31f661a0bbf669347332ce5b6c8db538c0704 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 19 Feb 2019 18:35:43 +0100 Subject: [PATCH 1694/2058] Fix SAL warnings --- phlib/include/phutil.h | 8 ++++---- phlib/util.c | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/phlib/include/phutil.h b/phlib/include/phutil.h index be1f366fdfc7..9a23f7700fe1 100644 --- a/phlib/include/phutil.h +++ b/phlib/include/phutil.h @@ -1156,8 +1156,8 @@ BOOLEAN NTAPI PhExtractIcon( _In_ PWSTR FileName, - _In_ HICON *IconLarge, - _In_ HICON *IconSmall + _Out_opt_ HICON *IconLarge, + _Out_opt_ HICON *IconSmall ); PHLIBAPI @@ -1166,8 +1166,8 @@ NTAPI PhExtractIconEx( _In_ PWSTR FileName, _In_ INT IconIndex, - _In_ HICON *IconLarge, - _In_ HICON *IconSmall + _Out_opt_ HICON *IconLarge, + _Out_opt_ HICON *IconSmall ); PHLIBAPI diff --git a/phlib/util.c b/phlib/util.c index 0d1ab8316150..3e449c84b4c2 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -5427,8 +5427,8 @@ PPH_STRING PhLoadIndirectString( // rev from ExtractIconExW BOOLEAN PhExtractIcon( _In_ PWSTR FileName, - _In_ HICON *IconLarge, - _In_ HICON *IconSmall + _Out_opt_ HICON *IconLarge, + _Out_opt_ HICON *IconSmall ) { return PhExtractIconEx(FileName, 0, IconLarge, IconSmall); @@ -5437,8 +5437,8 @@ BOOLEAN PhExtractIcon( BOOLEAN PhExtractIconEx( _In_ PWSTR FileName, _In_ INT IconIndex, - _In_ HICON *IconLarge, - _In_ HICON *IconSmall + _Out_opt_ HICON *IconLarge, + _Out_opt_ HICON *IconSmall ) { static PH_INITONCE initOnce = PH_INITONCE_INIT; From 21271db27fd0e59f80bcea22896f91ef8accd404 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 19 Feb 2019 18:49:42 +0100 Subject: [PATCH 1695/2058] Improve single instance checks --- ProcessHacker/main.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/ProcessHacker/main.c b/ProcessHacker/main.c index 519784f7b3be..fde4e63bb330 100644 --- a/ProcessHacker/main.c +++ b/ProcessHacker/main.c @@ -427,6 +427,7 @@ static BOOLEAN NTAPI PhpPreviousInstancesCallback( HANDLE processHandle = NULL; HANDLE tokenHandle = NULL; PTOKEN_USER tokenUser = NULL; + ULONG attempts = 50; if (objectInfo.ClientId.UniqueProcess == NtCurrentProcessId()) goto CleanupExit; @@ -439,11 +440,20 @@ static BOOLEAN NTAPI PhpPreviousInstancesCallback( if (!RtlEqualSid(tokenUser->User.Sid, PhGetOwnTokenAttributes().TokenSid)) goto CleanupExit; - hwnd = PhGetProcessMainWindowEx( - objectInfo.ClientId.UniqueProcess, - processHandle, - FALSE - ); + // Try to locate the window a few times because some users reported issues that it might not yet have been created. (dmex) + do + { + if (hwnd = PhGetProcessMainWindowEx( + objectInfo.ClientId.UniqueProcess, + processHandle, + FALSE + )) + { + break; + } + + PhDelayExecution(100); + } while (--attempts != 0); if (hwnd) { From 055d83658bd15f576b483e7d4335fa42eaa0b4da Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 19 Feb 2019 18:51:08 +0100 Subject: [PATCH 1696/2058] Fix typo --- ProcessHacker/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ProcessHacker/main.c b/ProcessHacker/main.c index fde4e63bb330..0b4f4c318237 100644 --- a/ProcessHacker/main.c +++ b/ProcessHacker/main.c @@ -440,7 +440,7 @@ static BOOLEAN NTAPI PhpPreviousInstancesCallback( if (!RtlEqualSid(tokenUser->User.Sid, PhGetOwnTokenAttributes().TokenSid)) goto CleanupExit; - // Try to locate the window a few times because some users reported issues that it might not yet have been created. (dmex) + // Try to locate the window a few times because some users reported that it might not yet have been created. (dmex) do { if (hwnd = PhGetProcessMainWindowEx( From e059d784408a0f1793fd91d4201104bfac55d03b Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 19 Feb 2019 19:21:45 +0100 Subject: [PATCH 1697/2058] Fix delayload CRT module handle --- phlib/include/phutil.h | 8 +++ phlib/util.c | 111 +++++++++++++++++++++++++++++++++++------ 2 files changed, 105 insertions(+), 14 deletions(-) diff --git a/phlib/include/phutil.h b/phlib/include/phutil.h index 9a23f7700fe1..c816353a80a0 100644 --- a/phlib/include/phutil.h +++ b/phlib/include/phutil.h @@ -1263,6 +1263,14 @@ PhGetExportNameFromOrdinal( _In_opt_ USHORT ProcedureNumber ); +PHLIBAPI +NTSTATUS +NTAPI +PhLoadAllImportsForDll( + _In_ PWSTR TargetDllName, + _In_ PSTR ImportDllName + ); + PHLIBAPI PPH_STRING NTAPI diff --git a/phlib/util.c b/phlib/util.c index 3e449c84b4c2..56d4221f8009 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -5673,7 +5673,7 @@ NTSTATUS PhGetLoaderEntryImageEntryPoint( ) { if (ImageNtHeader->OptionalHeader.AddressOfEntryPoint == 0) - return STATUS_FAIL_CHECK; // STATUS_ENTRYPOINT_NOT_FOUND + return STATUS_ENTRYPOINT_NOT_FOUND; *ImageEntryPoint = PTR_ADD_OFFSET(BaseAddress, ImageNtHeader->OptionalHeader.AddressOfEntryPoint); return STATUS_SUCCESS; @@ -5877,6 +5877,7 @@ static NTSTATUS PhpFixupLoaderEntryImageImports( if (PhEqualBytesZ(importName, "ProcessHacker.exe", FALSE)) { importBaseAddress = PhInstanceHandle; + status = STATUS_SUCCESS; } else { @@ -5998,7 +5999,8 @@ static NTSTATUS PhpFixupLoaderEntryImageImports( static NTSTATUS PhpFixupLoaderEntryImageDelayImports( _In_ PVOID BaseAddress, - _In_ PIMAGE_NT_HEADERS ImageNtHeader + _In_ PIMAGE_NT_HEADERS ImageNtHeaders, + _In_ PSTR ImportDllName ) { NTSTATUS status; @@ -6010,7 +6012,7 @@ static NTSTATUS PhpFixupLoaderEntryImageDelayImports( status = PhGetLoaderEntryImageDirectory( BaseAddress, - ImageNtHeader, + ImageNtHeaders, IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT, &dataDirectory, &delayImportDirectory, @@ -6027,7 +6029,7 @@ static NTSTATUS PhpFixupLoaderEntryImageDelayImports( status = PhGetLoaderEntryImageSection( BaseAddress, - ImageNtHeader, + ImageNtHeaders, delayImportDirectory, &importDirectorySection, &importDirectorySize @@ -6050,15 +6052,54 @@ static NTSTATUS PhpFixupLoaderEntryImageDelayImports( for (delayImportDirectory = delayImportDirectory; delayImportDirectory->DllNameRVA; delayImportDirectory++) { PSTR importName; + PVOID* importHandle; PIMAGE_THUNK_DATA importThunk; PIMAGE_THUNK_DATA originalThunk; + PVOID importBaseAddress; + BOOLEAN importNeedsFree = FALSE; importName = PTR_ADD_OFFSET(BaseAddress, delayImportDirectory->DllNameRVA); + importHandle = PTR_ADD_OFFSET(BaseAddress, delayImportDirectory->ModuleHandleRVA); importThunk = PTR_ADD_OFFSET(BaseAddress, delayImportDirectory->ImportAddressTableRVA); originalThunk = PTR_ADD_OFFSET(BaseAddress, delayImportDirectory->ImportNameTableRVA); - if (PhEqualBytesZ(importName, "ProcessHacker.exe", TRUE)) + if (PhEqualBytesZ(importName, ImportDllName, TRUE)) { + if (PhEqualBytesZ(importName, "ProcessHacker.exe", FALSE)) + { + importBaseAddress = PhInstanceHandle; + status = STATUS_SUCCESS; + } + else if (*importHandle) + { + importBaseAddress = *importHandle; + status = STATUS_SUCCESS; + } + else + { + PPH_STRING importNameSr; + + importNameSr = PhZeroExtendToUtf16(importName); + + if (!(importBaseAddress = PhGetLoaderEntryDllBase(importNameSr->Buffer))) + { + if (importBaseAddress = LoadLibrary(importNameSr->Buffer)) + { + importNeedsFree = TRUE; + status = STATUS_SUCCESS; + } + else + { + status = PhGetLastWin32ErrorAsNtStatus(); + } + } + + PhDereferenceObject(importNameSr); + } + + if (!NT_SUCCESS(status)) + break; + for ( originalThunk = originalThunk, importThunk = importThunk; originalThunk->u1.AddressOfData; @@ -6071,7 +6112,7 @@ static NTSTATUS PhpFixupLoaderEntryImageDelayImports( PVOID procedureAddress; procedureOrdinal = IMAGE_ORDINAL(originalThunk->u1.Ordinal); - procedureAddress = PhGetDllBaseProcedureAddress(PhInstanceHandle, NULL, procedureOrdinal); + procedureAddress = PhGetDllBaseProcedureAddress(importBaseAddress, NULL, procedureOrdinal); importThunk->u1.Function = (ULONG_PTR)procedureAddress; } @@ -6081,11 +6122,16 @@ static NTSTATUS PhpFixupLoaderEntryImageDelayImports( PVOID procedureAddress; importByName = PTR_ADD_OFFSET(BaseAddress, originalThunk->u1.AddressOfData); - procedureAddress = PhGetDllBaseProcedureAddress(PhInstanceHandle, importByName->Name, 0); + procedureAddress = PhGetDllBaseProcedureAddress(importBaseAddress, importByName->Name, 0); importThunk->u1.Function = (ULONG_PTR)procedureAddress; } } + + if ((InterlockedExchangePointer(importHandle, importBaseAddress) == importBaseAddress) && importNeedsFree) + { + FreeLibrary(importBaseAddress); // A different thread has already updated the cache. + } } } @@ -6104,14 +6150,49 @@ static NTSTATUS PhpFixupLoaderEntryImageDelayImports( return status; } +NTSTATUS PhLoaderEntryLoadAllImportsForDll( + _In_ PVOID BaseAddress, + _In_ PSTR ImportDllName + ) +{ + NTSTATUS status; + PIMAGE_NT_HEADERS imageNtHeaders; + + status = PhGetLoaderEntryImageNtHeaders( + BaseAddress, + &imageNtHeaders + ); + + if (!NT_SUCCESS(status)) + return status; + + status = PhpFixupLoaderEntryImageDelayImports( + BaseAddress, + imageNtHeaders, + ImportDllName + ); + + return status; +} + +NTSTATUS PhLoadAllImportsForDll( + _In_ PWSTR TargetDllName, + _In_ PSTR ImportDllName + ) +{ + PVOID imageBaseAddress; + + if (!(imageBaseAddress = PhGetLoaderEntryDllBase(TargetDllName))) + return STATUS_INVALID_PARAMETER; + + return PhLoaderEntryLoadAllImportsForDll( + imageBaseAddress, + ImportDllName + ); +} + // dmex: This function and the other LoaderEntryImage functions don't belong in this file // and should be moved into mapimg.c at some stage. -// -// We use this function to load plugins since we can 'fixup' the import table at runtime which is required when -// users have renamed the main executable to avoid malware, spyware and other software that targets Process Hacker. -// This function can only fixup images that have static imports from processhacker.exe, -// plugins that use LoadLibrary/GetProcAddress will continue to fail when the main executable is renamed. -// Note: This functionality is a WIP and not be used for anything other than plugins. NTSTATUS PhLoadPluginImage( _In_ PPH_STRING FileName, _Out_opt_ PVOID *BaseAddress @@ -6153,9 +6234,11 @@ NTSTATUS PhLoadPluginImage( if (!NT_SUCCESS(status)) goto CleanupExit; + //status = PhLoaderEntryLoadAllImportsForDll(imageBaseAddress, "ProcessHacker.exe"); status = PhpFixupLoaderEntryImageDelayImports( imageBaseAddress, - imageHeaders + imageHeaders, + "ProcessHacker.exe" ); if (!NT_SUCCESS(status)) From dba2ade8f2df6c9045e9ba2c4a84eda322ff6974 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 19 Feb 2019 19:21:58 +0100 Subject: [PATCH 1698/2058] FIx macro usage --- phnt/include/ntrtl.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phnt/include/ntrtl.h b/phnt/include/ntrtl.h index 3e9b1e3656ae..68ab76c65ab3 100644 --- a/phnt/include/ntrtl.h +++ b/phnt/include/ntrtl.h @@ -1424,7 +1424,7 @@ FORCEINLINE VOID RtlInitUnicodeString( ) { if (SourceString) - DestinationString->MaximumLength = (DestinationString->Length = (USHORT)(wcslen(SourceString) * sizeof(WCHAR))) + sizeof(WCHAR); + DestinationString->MaximumLength = (DestinationString->Length = (USHORT)(wcslen(SourceString) * sizeof(WCHAR))) + sizeof(UNICODE_NULL); else DestinationString->MaximumLength = DestinationString->Length = 0; From 1905e36b233f66bcc37306800de5973d858414c8 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 19 Feb 2019 19:23:41 +0100 Subject: [PATCH 1699/2058] Fix MSVC warning C28112 --- phlib/basesup.c | 8 ++++++-- phlib/lsasup.c | 4 ++-- phlib/util.c | 6 +++--- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/phlib/basesup.c b/phlib/basesup.c index 5ecb3f1cb2d9..0a65c2ed8a31 100644 --- a/phlib/basesup.c +++ b/phlib/basesup.c @@ -2214,13 +2214,17 @@ PPH_STRING PhReferenceEmptyString( PPH_STRING string; PPH_STRING newString; - string = PhSharedEmptyString; + string = InterlockedCompareExchangePointer( + &PhSharedEmptyString, + NULL, + NULL + ); if (!string) { newString = PhCreateStringEx(NULL, 0); - string = _InterlockedCompareExchangePointer( + string = InterlockedCompareExchangePointer( &PhSharedEmptyString, newString, NULL diff --git a/phlib/lsasup.c b/phlib/lsasup.c index 021700d9653c..f06a16622393 100644 --- a/phlib/lsasup.c +++ b/phlib/lsasup.c @@ -64,7 +64,7 @@ LSA_HANDLE PhGetLookupPolicyHandle( // Use the cached value if possible. - lookupPolicyHandle = cachedLookupPolicyHandle; + lookupPolicyHandle = InterlockedCompareExchangePointer(&cachedLookupPolicyHandle, NULL, NULL); // If there is no cached handle, open one. @@ -79,7 +79,7 @@ LSA_HANDLE PhGetLookupPolicyHandle( // We succeeded in opening a policy handle, and since we did not have a cached handle // before, we will now store it. - lookupPolicyHandle = _InterlockedCompareExchangePointer( + lookupPolicyHandle = InterlockedCompareExchangePointer( &cachedLookupPolicyHandle, newLookupPolicyHandle, NULL diff --git a/phlib/util.c b/phlib/util.c index 56d4221f8009..fcfe54c6a0d9 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -2201,14 +2201,14 @@ PPH_STRING PhGetSystemDirectory( // Use the cached value if possible. - if (cachedSystemDirectory) - return PhReferenceObject(cachedSystemDirectory); + if (systemDirectory = InterlockedCompareExchangePointer(&cachedSystemDirectory, NULL, NULL)) + return PhReferenceObject(systemDirectory); PhGetSystemRoot(&systemRootString); systemDirectory = PhConcatStringRef2(&systemRootString, &system32String); // Try to cache the value. - if (_InterlockedCompareExchangePointer( + if (InterlockedCompareExchangePointer( &cachedSystemDirectory, systemDirectory, NULL From fbf70474ee774db12c0862c503631225eb00ca6a Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 19 Feb 2019 19:25:38 +0100 Subject: [PATCH 1700/2058] Fix SAL warning --- phlib/include/phutil.h | 2 +- phlib/util.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/phlib/include/phutil.h b/phlib/include/phutil.h index c816353a80a0..624cee4b2e1e 100644 --- a/phlib/include/phutil.h +++ b/phlib/include/phutil.h @@ -250,7 +250,7 @@ PHLIBAPI VOID NTAPI PhShowStatus( - _In_ HWND hWnd, + _In_opt_ HWND hWnd, _In_opt_ PWSTR Message, _In_ NTSTATUS Status, _In_opt_ ULONG Win32Result diff --git a/phlib/util.c b/phlib/util.c index fcfe54c6a0d9..956996329706 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -517,7 +517,7 @@ PPH_STRING PhGetStatusMessage( * \param Win32Result A Win32 error code, or 0 if there is none. */ VOID PhShowStatus( - _In_ HWND hWnd, + _In_opt_ HWND hWnd, _In_opt_ PWSTR Message, _In_ NTSTATUS Status, _In_opt_ ULONG Win32Result From eaf0fea3a908217b07e0f355ee9f9206e3f8fe64 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 20 Feb 2019 19:51:23 +0100 Subject: [PATCH 1701/2058] Add workaround for #204 --- ProcessHacker/actions.c | 4 ++-- phlib/include/phutil.h | 1 + phlib/util.c | 2 ++ 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/ProcessHacker/actions.c b/ProcessHacker/actions.c index 96cbc4de87c6..23481d60d105 100644 --- a/ProcessHacker/actions.c +++ b/ProcessHacker/actions.c @@ -331,7 +331,7 @@ BOOLEAN PhpStartPhSvcProcess( hWnd, L"-phsvc", SW_HIDE, - PH_SHELL_EXECUTE_ADMIN, + PH_SHELL_EXECUTE_ADMIN | PH_SHELL_EXECUTE_NOZONECHECKS, PH_SHELL_APP_PROPAGATE_PARAMETERS, 0, NULL @@ -373,7 +373,7 @@ BOOLEAN PhpStartPhSvcProcess( fileName->Buffer, L"-phsvc", SW_HIDE, - 0, + PH_SHELL_EXECUTE_NOZONECHECKS, PH_SHELL_APP_PROPAGATE_PARAMETERS, 0, NULL diff --git a/phlib/include/phutil.h b/phlib/include/phutil.h index 624cee4b2e1e..744e397269fe 100644 --- a/phlib/include/phutil.h +++ b/phlib/include/phutil.h @@ -796,6 +796,7 @@ PhShellExecute( #define PH_SHELL_EXECUTE_ADMIN 0x1 #define PH_SHELL_EXECUTE_PUMP_MESSAGES 0x2 +#define PH_SHELL_EXECUTE_NOZONECHECKS 0x3 PHLIBAPI BOOLEAN diff --git a/phlib/util.c b/phlib/util.c index 956996329706..0960ca2e5b93 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -3360,6 +3360,8 @@ BOOLEAN PhShellExecuteEx( if (Flags & PH_SHELL_EXECUTE_ADMIN) info.lpVerb = L"runas"; + if (Flags & PH_SHELL_EXECUTE_NOZONECHECKS) + info.fMask |= SEE_MASK_NOZONECHECKS; if (ShellExecuteEx(&info)) { From 7a33be87b8919767b5ecd4481c38d9ef72f6f953 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 20 Feb 2019 19:52:07 +0100 Subject: [PATCH 1702/2058] Fix SAL warnings --- phlib/include/phutil.h | 2 +- phlib/util.c | 14 ++++++-------- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/phlib/include/phutil.h b/phlib/include/phutil.h index 744e397269fe..8ff120f99b80 100644 --- a/phlib/include/phutil.h +++ b/phlib/include/phutil.h @@ -918,7 +918,7 @@ PHLIBAPI BOOLEAN NTAPI PhShowFileDialog( - _In_ HWND hWnd, + _In_opt_ HWND hWnd, _In_ PVOID FileDialog ); diff --git a/phlib/util.c b/phlib/util.c index 0960ca2e5b93..30940b2c6383 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -3529,7 +3529,7 @@ VOID PhShellOpenKey( RtlInitUnicodeString(&valueName, L"LastKey"); lastKey = PhExpandKeyName(KeyName, TRUE); - NtSetValueKey(regeditKeyHandle, &valueName, 0, REG_SZ, lastKey->Buffer, (ULONG)lastKey->Length + 2); + NtSetValueKey(regeditKeyHandle, &valueName, 0, REG_SZ, lastKey->Buffer, (ULONG)lastKey->Length + sizeof(UNICODE_NULL)); PhDereferenceObject(lastKey); NtClose(regeditKeyHandle); @@ -3583,8 +3583,8 @@ PPH_STRING PhQueryRegistryString( buffer->Type == REG_MULTI_SZ || buffer->Type == REG_EXPAND_SZ) { - if (buffer->DataLength >= sizeof(WCHAR)) - string = PhCreateStringEx((PWCHAR)buffer->Data, buffer->DataLength - sizeof(WCHAR)); + if (buffer->DataLength >= sizeof(UNICODE_NULL)) + string = PhCreateStringEx((PWCHAR)buffer->Data, buffer->DataLength - sizeof(UNICODE_NULL)); else string = PhReferenceEmptyString(); } @@ -3786,9 +3786,7 @@ OPENFILENAME *PhpCreateOpenFileName( { OPENFILENAME *ofn; - ofn = PhAllocate(sizeof(OPENFILENAME)); - memset(ofn, 0, sizeof(OPENFILENAME)); - + ofn = PhAllocateZero(sizeof(OPENFILENAME)); ofn->lStructSize = sizeof(OPENFILENAME); ofn->nMaxFile = 0x400; ofn->lpstrFile = PhAllocate(ofn->nMaxFile * sizeof(WCHAR)); @@ -3939,7 +3937,7 @@ VOID PhFreeFileDialog( * occurred. */ BOOLEAN PhShowFileDialog( - _In_ HWND hWnd, + _In_opt_ HWND hWnd, _In_ PVOID FileDialog ) { @@ -4186,7 +4184,7 @@ VOID PhSetFileDialogFilter( if (ofn->lpstrFilter) PhFree((PVOID)ofn->lpstrFilter); - ofn->lpstrFilter = PhAllocateCopy(filterString->Buffer, filterString->Length + 2); + ofn->lpstrFilter = PhAllocateCopy(filterString->Buffer, filterString->Length + sizeof(UNICODE_NULL)); PhDereferenceObject(filterString); } } From bb47a70a9b1f5cec4e0a86471be134fd6486f701 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 20 Feb 2019 19:52:35 +0100 Subject: [PATCH 1703/2058] Update SE_MAX_WELL_KNOWN_PRIVILEGE --- phnt/include/ntseapi.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/phnt/include/ntseapi.h b/phnt/include/ntseapi.h index 13e3972dbb54..9552bbec0bea 100644 --- a/phnt/include/ntseapi.h +++ b/phnt/include/ntseapi.h @@ -59,7 +59,8 @@ #define SE_INC_WORKING_SET_PRIVILEGE (33L) #define SE_TIME_ZONE_PRIVILEGE (34L) #define SE_CREATE_SYMBOLIC_LINK_PRIVILEGE (35L) -#define SE_MAX_WELL_KNOWN_PRIVILEGE SE_CREATE_SYMBOLIC_LINK_PRIVILEGE +#define SE_DELEGATE_SESSION_USER_IMPERSONATE_PRIVILEGE (36L) +#define SE_MAX_WELL_KNOWN_PRIVILEGE SE_DELEGATE_SESSION_USER_IMPERSONATE_PRIVILEGE // Authz From cc27a8e9a7571fefb73151cd05d5454602c5abd7 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 20 Feb 2019 20:35:09 +0100 Subject: [PATCH 1704/2058] Improve mxml usage (required for future mxml updates) --- ProcessHacker/ProcessHacker.def | 2 ++ phlib/mxml/mxml.h | 4 ++-- phlib/settings.c | 9 +++----- plugins/UserNotes/db.c | 41 +++++++++++++++++++-------------- 4 files changed, 31 insertions(+), 25 deletions(-) diff --git a/ProcessHacker/ProcessHacker.def b/ProcessHacker/ProcessHacker.def index bf67ee1ee60f..98e0ba4ab968 100644 --- a/ProcessHacker/ProcessHacker.def +++ b/ProcessHacker/ProcessHacker.def @@ -651,6 +651,8 @@ EXPORTS ; mxml mxmlDelete + mxmlElementGetAttrCount + mxmlElementGetAttrByIndex mxmlElementSetAttr mxmlLoadFd mxmlNewOpaque diff --git a/phlib/mxml/mxml.h b/phlib/mxml/mxml.h index e608cb863782..0f2939d29491 100644 --- a/phlib/mxml/mxml.h +++ b/phlib/mxml/mxml.h @@ -205,8 +205,8 @@ PHMXMLAPI extern void mxmlDelete(mxml_node_t *node); PHMXMLAPI extern void mxmlElementDeleteAttr(mxml_node_t *node, const char *name); PHMXMLAPI extern const char *mxmlElementGetAttr(mxml_node_t *node, const char *name); -extern const char *mxmlElementGetAttrByIndex(mxml_node_t *node, int idx, const char **name); -extern int mxmlElementGetAttrCount(mxml_node_t *node); +PHMXMLAPI extern const char *mxmlElementGetAttrByIndex(mxml_node_t *node, int idx, const char **name); +PHMXMLAPI extern int mxmlElementGetAttrCount(mxml_node_t *node); PHMXMLAPI extern void mxmlElementSetAttr(mxml_node_t *node, const char *name, const char *value); extern void mxmlElementSetAttrf(mxml_node_t *node, const char *name, diff --git a/phlib/settings.c b/phlib/settings.c index ad653a438a21..4094853ff580 100644 --- a/phlib/settings.c +++ b/phlib/settings.c @@ -790,14 +790,11 @@ NTSTATUS PhLoadSettings( while (currentNode) { PPH_STRING settingName = NULL; + PCSTR elementValue; - if ( - currentNode->type == MXML_ELEMENT && - currentNode->value.element.num_attrs >= 1 && - _stricmp(currentNode->value.element.attrs[0].name, "name") == 0 - ) + if (elementValue = mxmlElementGetAttr(currentNode, "name")) { - settingName = PhConvertUtf8ToUtf16(currentNode->value.element.attrs[0].value); + settingName = PhConvertUtf8ToUtf16((PSTR)elementValue); } if (settingName) diff --git a/plugins/UserNotes/db.c b/plugins/UserNotes/db.c index 70a6982efbcd..b0f2fc0e05c1 100644 --- a/plugins/UserNotes/db.c +++ b/plugins/UserNotes/db.c @@ -239,25 +239,32 @@ NTSTATUS LoadDb( PPH_STRING collapse = NULL; PPH_STRING affinityMask = NULL; - if (currentNode->type == MXML_ELEMENT && - currentNode->value.element.num_attrs >= 2) + if (mxmlElementGetAttrCount(currentNode) >= 2) { - for (INT i = 0; i < currentNode->value.element.num_attrs; i++) + for (INT i = 0; i < mxmlElementGetAttrCount(currentNode); i++) { - if (_stricmp(currentNode->value.element.attrs[i].name, "tag") == 0) - PhMoveReference(&tag, PhConvertUtf8ToUtf16(currentNode->value.element.attrs[i].value)); - else if (_stricmp(currentNode->value.element.attrs[i].name, "name") == 0) - PhMoveReference(&name, PhConvertUtf8ToUtf16(currentNode->value.element.attrs[i].value)); - else if (_stricmp(currentNode->value.element.attrs[i].name, "priorityclass") == 0) - PhMoveReference(&priorityClass, PhConvertUtf8ToUtf16(currentNode->value.element.attrs[i].value)); - else if (_stricmp(currentNode->value.element.attrs[i].name, "iopriorityplusone") == 0) - PhMoveReference(&ioPriorityPlusOne, PhConvertUtf8ToUtf16(currentNode->value.element.attrs[i].value)); - else if (_stricmp(currentNode->value.element.attrs[i].name, "backcolor") == 0) - PhMoveReference(&backColor, PhConvertUtf8ToUtf16(currentNode->value.element.attrs[i].value)); - else if (_stricmp(currentNode->value.element.attrs[i].name, "collapse") == 0) - PhMoveReference(&collapse, PhConvertUtf8ToUtf16(currentNode->value.element.attrs[i].value)); - else if (_stricmp(currentNode->value.element.attrs[i].name, "affinity") == 0) - PhMoveReference(&affinityMask, PhConvertUtf8ToUtf16(currentNode->value.element.attrs[i].value)); + PSTR elementName; + PSTR elementValue; + + elementValue = (PSTR)mxmlElementGetAttrByIndex(currentNode, i, &elementName); + + if (!(elementName && elementValue)) + continue; + + if (_stricmp(elementName, "tag") == 0) + PhMoveReference(&tag, PhConvertUtf8ToUtf16(elementValue)); + else if (_stricmp(elementName, "name") == 0) + PhMoveReference(&name, PhConvertUtf8ToUtf16(elementValue)); + else if (_stricmp(elementName, "priorityclass") == 0) + PhMoveReference(&priorityClass, PhConvertUtf8ToUtf16(elementValue)); + else if (_stricmp(elementName, "iopriorityplusone") == 0) + PhMoveReference(&ioPriorityPlusOne, PhConvertUtf8ToUtf16(elementValue)); + else if (_stricmp(elementName, "backcolor") == 0) + PhMoveReference(&backColor, PhConvertUtf8ToUtf16(elementValue)); + else if (_stricmp(elementName, "collapse") == 0) + PhMoveReference(&collapse, PhConvertUtf8ToUtf16(elementValue)); + else if (_stricmp(elementName, "affinity") == 0) + PhMoveReference(&affinityMask, PhConvertUtf8ToUtf16(elementValue)); } } From 830ecc3c48f79d39d4130b32d4ca4c66c78424ae Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 20 Feb 2019 20:35:52 +0100 Subject: [PATCH 1705/2058] Improve PhGetObjectTypeName --- phlib/hndlinfo.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/phlib/hndlinfo.c b/phlib/hndlinfo.c index 2ed2307ce4cb..92882ff06d62 100644 --- a/phlib/hndlinfo.c +++ b/phlib/hndlinfo.c @@ -1496,13 +1496,17 @@ PPH_STRING PhGetObjectTypeName( _In_ ULONG TypeIndex ) { + static PH_INITONCE initOnce = PH_INITONCE_INIT; static POBJECT_TYPES_INFORMATION objectTypes = NULL; POBJECT_TYPE_INFORMATION objectType; PPH_STRING objectTypeName = NULL; ULONG i; - if (!objectTypes) // HACK (dmex) + if (PhBeginInitOnce(&initOnce)) + { PhEnumObjectTypes(&objectTypes); + PhEndInitOnce(&initOnce); + } if (objectTypes) { @@ -1539,7 +1543,6 @@ PPHP_CALL_WITH_TIMEOUT_THREAD_CONTEXT PhpAcquireCallWithTimeoutThread( ) { static PH_INITONCE initOnce = PH_INITONCE_INIT; - PPHP_CALL_WITH_TIMEOUT_THREAD_CONTEXT threadContext; PSLIST_ENTRY listEntry; PH_QUEUED_WAIT_BLOCK waitBlock; From cdd3f0229cf54101a21e4b4811476ddd5e6ea9c6 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 20 Feb 2019 20:36:51 +0100 Subject: [PATCH 1706/2058] Updater: Fix error message --- plugins/Updater/page5.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/Updater/page5.c b/plugins/Updater/page5.c index 506dafccbd6e..b0ff5ace1ea5 100644 --- a/plugins/Updater/page5.c +++ b/plugins/Updater/page5.c @@ -139,7 +139,7 @@ HRESULT CALLBACK FinalTaskDialogCallbackProc( info.lpVerb = UpdaterCheckApplicationDirectory() ? NULL : L"runas"; info.nShow = SW_SHOW; info.hwnd = hwndDlg; - info.fMask = SEE_MASK_NOASYNC | SEE_MASK_FLAG_NO_UI; + info.fMask = SEE_MASK_NOASYNC | SEE_MASK_FLAG_NO_UI | SEE_MASK_NOZONECHECKS; ProcessHacker_PrepareForEarlyShutdown(PhMainWndHandle); @@ -157,7 +157,7 @@ HRESULT CALLBACK FinalTaskDialogCallbackProc( // Show error dialog. if (errorCode != ERROR_CANCELLED) // Ignore UAC decline. { - PhShowStatus(hwndDlg, L"Unable to execute the setup.", 0, GetLastError()); + PhShowStatus(hwndDlg, L"Unable to execute the setup.", 0, errorCode); if (context->StartupCheck) ShowAvailableDialog(context); From 84dac8cfc077b9e516a48dc0b9fe76e84ee23b48 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 20 Feb 2019 20:50:35 +0100 Subject: [PATCH 1707/2058] Improve mxml usage (required for future mxml updates) --- ProcessHacker/ProcessHacker.def | 1 + phlib/mxml/mxml.h | 2 +- phlib/settings.c | 6 ++++-- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/ProcessHacker/ProcessHacker.def b/ProcessHacker/ProcessHacker.def index 98e0ba4ab968..32165c26bc53 100644 --- a/ProcessHacker/ProcessHacker.def +++ b/ProcessHacker/ProcessHacker.def @@ -654,6 +654,7 @@ EXPORTS mxmlElementGetAttrCount mxmlElementGetAttrByIndex mxmlElementSetAttr + mxmlGetOpaque mxmlLoadFd mxmlNewOpaque mxmlNewElement diff --git a/phlib/mxml/mxml.h b/phlib/mxml/mxml.h index 0f2939d29491..97af308df608 100644 --- a/phlib/mxml/mxml.h +++ b/phlib/mxml/mxml.h @@ -230,7 +230,7 @@ extern mxml_node_t *mxmlGetFirstChild(mxml_node_t *node); extern int mxmlGetInteger(mxml_node_t *node); extern mxml_node_t *mxmlGetLastChild(mxml_node_t *node); extern mxml_node_t *mxmlGetNextSibling(mxml_node_t *node); -extern const char *mxmlGetOpaque(mxml_node_t *node); +PHMXMLAPI extern const char *mxmlGetOpaque(mxml_node_t *node); extern mxml_node_t *mxmlGetParent(mxml_node_t *node); extern mxml_node_t *mxmlGetPrevSibling(mxml_node_t *node); extern double mxmlGetReal(mxml_node_t *node); diff --git a/phlib/settings.c b/phlib/settings.c index 4094853ff580..0f2f025b72cd 100644 --- a/phlib/settings.c +++ b/phlib/settings.c @@ -731,9 +731,11 @@ PPH_STRING PhpGetOpaqueXmlNodeText( _In_ mxml_node_t *node ) { - if (node->child && node->child->type == MXML_OPAQUE && node->child->value.opaque) + PCSTR string; + + if (string = mxmlGetOpaque(node)) { - return PhConvertUtf8ToUtf16(node->child->value.opaque); + return PhConvertUtf8ToUtf16((PSTR)string); } else { From 484725e1dbb9c8d9c1110fe697b121acd101f5f4 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 20 Feb 2019 20:52:11 +0100 Subject: [PATCH 1708/2058] UserNotes: Fix process priorities not being properly restored after restart --- plugins/UserNotes/db.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/plugins/UserNotes/db.c b/plugins/UserNotes/db.c index b0f2fc0e05c1..a56d8efb9d0a 100644 --- a/plugins/UserNotes/db.c +++ b/plugins/UserNotes/db.c @@ -173,7 +173,9 @@ PPH_STRING GetOpaqueXmlNodeText( _In_ mxml_node_t *node ) { - if (node->child && node->child->type == MXML_OPAQUE && node->child->value.opaque) + PCSTR string; + + if (string = mxmlGetOpaque(node)) { return PhConvertUtf8ToUtf16(node->child->value.opaque); } @@ -270,7 +272,7 @@ NTSTATUS LoadDb( comment = GetOpaqueXmlNodeText(currentNode); - if (tag && name && comment) + if (tag && name) { ULONG64 tagInteger; ULONG64 priorityClassInteger = 0; From 430199c84640f335df98619ec10acf555754a1d0 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 20 Feb 2019 20:52:48 +0100 Subject: [PATCH 1709/2058] Fix typo --- plugins/UserNotes/db.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/UserNotes/db.c b/plugins/UserNotes/db.c index a56d8efb9d0a..ef0175604722 100644 --- a/plugins/UserNotes/db.c +++ b/plugins/UserNotes/db.c @@ -177,7 +177,7 @@ PPH_STRING GetOpaqueXmlNodeText( if (string = mxmlGetOpaque(node)) { - return PhConvertUtf8ToUtf16(node->child->value.opaque); + return PhConvertUtf8ToUtf16(string); } else { From f0ad15f020fd0573679a23a04a68448fab06b6ef Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 20 Feb 2019 20:57:01 +0100 Subject: [PATCH 1710/2058] Fix build warning --- plugins/UserNotes/db.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/UserNotes/db.c b/plugins/UserNotes/db.c index ef0175604722..97fb9aea9682 100644 --- a/plugins/UserNotes/db.c +++ b/plugins/UserNotes/db.c @@ -177,7 +177,7 @@ PPH_STRING GetOpaqueXmlNodeText( if (string = mxmlGetOpaque(node)) { - return PhConvertUtf8ToUtf16(string); + return PhConvertUtf8ToUtf16((PSTR)string); } else { From edb70e5feed598464367ef342661bbe57ff9b25e Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 20 Feb 2019 22:44:06 +0100 Subject: [PATCH 1711/2058] Add PhDeleteFile --- phlib/include/phnative.h | 7 +++++++ phlib/native.c | 42 +++++++++++++++++++--------------------- 2 files changed, 27 insertions(+), 22 deletions(-) diff --git a/phlib/include/phnative.h b/phlib/include/phnative.h index 14bd25e53e7e..422f45b1c29a 100644 --- a/phlib/include/phnative.h +++ b/phlib/include/phnative.h @@ -491,6 +491,13 @@ PhSetFileSize( _In_ PLARGE_INTEGER Size ); +PHLIBAPI +NTSTATUS +NTAPI +PhDeleteFile( + _In_ HANDLE FileHandle + ); + PHLIBAPI NTSTATUS NTAPI diff --git a/phlib/native.c b/phlib/native.c index e251de4e7be8..abfe654d5cd3 100644 --- a/phlib/native.c +++ b/phlib/native.c @@ -2528,6 +2528,24 @@ NTSTATUS PhSetFileSize( ); } +NTSTATUS PhDeleteFile( + _In_ HANDLE FileHandle + ) +{ + FILE_DISPOSITION_INFORMATION dispositionInfo; + IO_STATUS_BLOCK isb; + + dispositionInfo.DeleteFile = TRUE; + + return NtSetInformationFile( + FileHandle, + &isb, + &dispositionInfo, + sizeof(FILE_DISPOSITION_INFORMATION), + FileDispositionInformation + ); +} + NTSTATUS PhGetFileHandleName( _In_ HANDLE FileHandle, _Out_ PPH_STRING *FileName @@ -7315,20 +7333,10 @@ static BOOLEAN PhpDeleteDirectoryCallback( FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT ))) { - IO_STATUS_BLOCK isb; - FILE_DISPOSITION_INFORMATION fileInfo; - PhEnumDirectoryFile(directoryHandle, NULL, PhpDeleteDirectoryCallback, fullName); // Delete the directory. - fileInfo.DeleteFile = TRUE; - NtSetInformationFile( - directoryHandle, - &isb, - &fileInfo, - sizeof(FILE_DISPOSITION_INFORMATION), - FileDispositionInformation - ); + PhDeleteFile(directoryHandle); NtClose(directoryHandle); } @@ -7401,9 +7409,6 @@ NTSTATUS PhDeleteDirectory( if (NT_SUCCESS(status)) { - IO_STATUS_BLOCK isb; - FILE_DISPOSITION_INFORMATION fileInfo; - // Remove any files or folders inside the directory. status = PhEnumDirectoryFile( directoryHandle, @@ -7413,14 +7418,7 @@ NTSTATUS PhDeleteDirectory( ); // Remove the directory. - fileInfo.DeleteFile = TRUE; - status = NtSetInformationFile( - directoryHandle, - &isb, - &fileInfo, - sizeof(FILE_DISPOSITION_INFORMATION), - FileDispositionInformation - ); + PhDeleteFile(directoryHandle); NtClose(directoryHandle); } From 3a6b2a8cf561e110d0021317447997b2be8a3294 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 20 Feb 2019 22:44:52 +0100 Subject: [PATCH 1712/2058] Update mxml usage (required for future mxml updates) --- ProcessHacker/ProcessHacker.def | 3 +++ phlib/mxml/mxml.h | 6 +++--- phlib/settings.c | 15 ++++++++++----- plugins/UserNotes/db.c | 4 ++-- 4 files changed, 18 insertions(+), 10 deletions(-) diff --git a/ProcessHacker/ProcessHacker.def b/ProcessHacker/ProcessHacker.def index 32165c26bc53..ba796b4944f4 100644 --- a/ProcessHacker/ProcessHacker.def +++ b/ProcessHacker/ProcessHacker.def @@ -654,7 +654,10 @@ EXPORTS mxmlElementGetAttrCount mxmlElementGetAttrByIndex mxmlElementSetAttr + mxmlGetFirstChild + mxmlGetNextSibling mxmlGetOpaque + mxmlGetType mxmlLoadFd mxmlNewOpaque mxmlNewElement diff --git a/phlib/mxml/mxml.h b/phlib/mxml/mxml.h index 97af308df608..f2e07c02feab 100644 --- a/phlib/mxml/mxml.h +++ b/phlib/mxml/mxml.h @@ -226,17 +226,17 @@ extern mxml_node_t *mxmlFindPath(mxml_node_t *node, const char *path); extern const char *mxmlGetCDATA(mxml_node_t *node); extern const void *mxmlGetCustom(mxml_node_t *node); extern const char *mxmlGetElement(mxml_node_t *node); -extern mxml_node_t *mxmlGetFirstChild(mxml_node_t *node); +PHMXMLAPI extern mxml_node_t *mxmlGetFirstChild(mxml_node_t *node); extern int mxmlGetInteger(mxml_node_t *node); extern mxml_node_t *mxmlGetLastChild(mxml_node_t *node); -extern mxml_node_t *mxmlGetNextSibling(mxml_node_t *node); +PHMXMLAPI extern mxml_node_t *mxmlGetNextSibling(mxml_node_t *node); PHMXMLAPI extern const char *mxmlGetOpaque(mxml_node_t *node); extern mxml_node_t *mxmlGetParent(mxml_node_t *node); extern mxml_node_t *mxmlGetPrevSibling(mxml_node_t *node); extern double mxmlGetReal(mxml_node_t *node); extern int mxmlGetRefCount(mxml_node_t *node); extern const char *mxmlGetText(mxml_node_t *node, int *whitespace); -extern mxml_type_t mxmlGetType(mxml_node_t *node); +PHMXMLAPI extern mxml_type_t mxmlGetType(mxml_node_t *node); extern void *mxmlGetUserData(mxml_node_t *node); extern void mxmlIndexDelete(mxml_index_t *ind); extern mxml_node_t *mxmlIndexEnum(mxml_index_t *ind); diff --git a/phlib/settings.c b/phlib/settings.c index 0f2f025b72cd..8fd38b5b967d 100644 --- a/phlib/settings.c +++ b/phlib/settings.c @@ -781,13 +781,13 @@ NTSTATUS PhLoadSettings( if (!topNode) return STATUS_FILE_CORRUPT_ERROR; - if (topNode->type != MXML_ELEMENT) + if (mxmlGetType(topNode) != MXML_ELEMENT) { mxmlDelete(topNode); return STATUS_FILE_CORRUPT_ERROR; } - currentNode = topNode->child; + currentNode = mxmlGetFirstChild(topNode); while (currentNode) { @@ -849,7 +849,7 @@ NTSTATUS PhLoadSettings( PhDereferenceObject(settingName); } - currentNode = currentNode->next; + currentNode = mxmlGetNextSibling(currentNode); } mxmlDelete(topNode); @@ -864,14 +864,19 @@ char *PhpSettingsSaveCallback( _In_ int position ) { - if (PhEqualBytesZ(node->value.element.name, "setting", TRUE)) + PSTR elementName; + + if (!(elementName = (PSTR)mxmlGetElement(node))) + return NULL; + + if (PhEqualBytesZ(elementName, "setting", TRUE)) { if (position == MXML_WS_BEFORE_OPEN) return " "; else if (position == MXML_WS_AFTER_CLOSE) return "\r\n"; } - else if (PhEqualBytesZ(node->value.element.name, "settings", TRUE)) + else if (PhEqualBytesZ(elementName, "settings", TRUE)) { if (position == MXML_WS_AFTER_OPEN) return "\r\n"; diff --git a/plugins/UserNotes/db.c b/plugins/UserNotes/db.c index 97fb9aea9682..d18e28e01359 100644 --- a/plugins/UserNotes/db.c +++ b/plugins/UserNotes/db.c @@ -221,7 +221,7 @@ NTSTATUS LoadDb( if (!topNode) return STATUS_FILE_CORRUPT_ERROR; - if (topNode->type != MXML_ELEMENT) + if (mxmlGetType(topNode) != MXML_ELEMENT) { mxmlDelete(topNode); return STATUS_FILE_CORRUPT_ERROR; @@ -229,7 +229,7 @@ NTSTATUS LoadDb( LockDb(); - for (currentNode = topNode->child; currentNode; currentNode = currentNode->next) + for (currentNode = mxmlGetFirstChild(topNode); currentNode; currentNode = mxmlGetNextSibling(currentNode)) { PDB_OBJECT object = NULL; PPH_STRING tag = NULL; From 4a4a0a57987131eba2228c35aa8157ae32166e7c Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 21 Feb 2019 22:06:58 +0100 Subject: [PATCH 1713/2058] Fix typo --- phlib/include/phutil.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phlib/include/phutil.h b/phlib/include/phutil.h index 8ff120f99b80..4d0c043a5a56 100644 --- a/phlib/include/phutil.h +++ b/phlib/include/phutil.h @@ -796,7 +796,7 @@ PhShellExecute( #define PH_SHELL_EXECUTE_ADMIN 0x1 #define PH_SHELL_EXECUTE_PUMP_MESSAGES 0x2 -#define PH_SHELL_EXECUTE_NOZONECHECKS 0x3 +#define PH_SHELL_EXECUTE_NOZONECHECKS 0x4 PHLIBAPI BOOLEAN From e7b2f34903785ec93c9e3cb79961d06425100796 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 24 Feb 2019 12:37:48 +0100 Subject: [PATCH 1714/2058] Fix dark theme groupbox sizes --- phlib/theme.c | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/phlib/theme.c b/phlib/theme.c index 54ff46887044..85349aa5b014 100644 --- a/phlib/theme.c +++ b/phlib/theme.c @@ -177,7 +177,7 @@ VOID PhInitializeWindowTheme( WindowHandle, 0x1000, PhpThemeWindowEnumChildWindows, - 0 + NULL ); InvalidateRect(WindowHandle, NULL, FALSE); // HACK @@ -226,7 +226,7 @@ VOID PhReInitializeWindowTheme( WindowHandle, 0x1000, PhpReInitializeThemeWindowEnumChildWindows, - 0 + NULL ); do @@ -254,7 +254,7 @@ VOID PhReInitializeWindowTheme( currentWindow, 0x1000, PhpReInitializeThemeWindowEnumChildWindows, - 0 + NULL ); //PhReInitializeWindowTheme(currentWindow); } @@ -272,12 +272,12 @@ VOID PhInitializeThemeWindowHeader( _In_ HWND HeaderWindow ) { - PPHP_THEME_WINDOW_HEADER_CONTEXT headerControlContext; + PPHP_THEME_WINDOW_HEADER_CONTEXT context; - headerControlContext = PhAllocateZero(sizeof(PHP_THEME_WINDOW_HEADER_CONTEXT)); - headerControlContext->DefaultWindowProc = (WNDPROC)GetWindowLongPtr(HeaderWindow, GWLP_WNDPROC); + context = PhAllocateZero(sizeof(PHP_THEME_WINDOW_HEADER_CONTEXT)); + context->DefaultWindowProc = (WNDPROC)GetWindowLongPtr(HeaderWindow, GWLP_WNDPROC); - PhSetWindowContext(HeaderWindow, SHRT_MAX, headerControlContext); + PhSetWindowContext(HeaderWindow, SHRT_MAX, context); SetWindowLongPtr(HeaderWindow, GWLP_WNDPROC, (LONG_PTR)PhpThemeWindowHeaderSubclassProc); InvalidateRect(HeaderWindow, NULL, FALSE); @@ -287,15 +287,15 @@ VOID PhInitializeThemeWindowTabControl( _In_ HWND TabControlWindow ) { - PPHP_THEME_WINDOW_TAB_CONTEXT tabControlContext; + PPHP_THEME_WINDOW_TAB_CONTEXT context; if (!PhpTabControlFontHandle) PhpTabControlFontHandle = PhDuplicateFontWithNewHeight(PhApplicationFont, 15); - tabControlContext = PhAllocateZero(sizeof(PHP_THEME_WINDOW_TAB_CONTEXT)); - tabControlContext->DefaultWindowProc = (WNDPROC)GetWindowLongPtr(TabControlWindow, GWLP_WNDPROC); + context = PhAllocateZero(sizeof(PHP_THEME_WINDOW_TAB_CONTEXT)); + context->DefaultWindowProc = (WNDPROC)GetWindowLongPtr(TabControlWindow, GWLP_WNDPROC); - PhSetWindowContext(TabControlWindow, SHRT_MAX, tabControlContext); + PhSetWindowContext(TabControlWindow, SHRT_MAX, context); SetWindowLongPtr(TabControlWindow, GWLP_WNDPROC, (LONG_PTR)PhpThemeWindowTabControlWndSubclassProc); PhSetWindowStyle(TabControlWindow, TCS_OWNERDRAWFIXED, TCS_OWNERDRAWFIXED); @@ -309,13 +309,13 @@ VOID PhInitializeWindowThemeStatusBar( _In_ HWND StatusBarHandle ) { - PPHP_THEME_WINDOW_STATUSBAR_CONTEXT statusbarContext; + PPHP_THEME_WINDOW_STATUSBAR_CONTEXT context; - statusbarContext = PhAllocateZero(sizeof(PHP_THEME_WINDOW_STATUSBAR_CONTEXT)); - statusbarContext->DefaultWindowProc = (WNDPROC)GetWindowLongPtr(StatusBarHandle, GWLP_WNDPROC); - statusbarContext->StatusThemeData = OpenThemeData(StatusBarHandle, VSCLASS_STATUS); + context = PhAllocateZero(sizeof(PHP_THEME_WINDOW_STATUSBAR_CONTEXT)); + context->DefaultWindowProc = (WNDPROC)GetWindowLongPtr(StatusBarHandle, GWLP_WNDPROC); + context->StatusThemeData = OpenThemeData(StatusBarHandle, VSCLASS_STATUS); - PhSetWindowContext(StatusBarHandle, SHRT_MAX, statusbarContext); + PhSetWindowContext(StatusBarHandle, SHRT_MAX, context); SetWindowLongPtr(StatusBarHandle, GWLP_WNDPROC, (LONG_PTR)PhpThemeWindowStatusbarWndSubclassProc); InvalidateRect(StatusBarHandle, NULL, FALSE); @@ -345,7 +345,7 @@ BOOLEAN CALLBACK PhpThemeWindowEnumChildWindows( WindowHandle, 0x1000, PhpThemeWindowEnumChildWindows, - 0 + NULL ); if (PhGetWindowContext(WindowHandle, SHRT_MAX)) // HACK @@ -502,7 +502,7 @@ BOOLEAN CALLBACK PhpReInitializeThemeWindowEnumChildWindows( WindowHandle, 0x1000, PhpReInitializeThemeWindowEnumChildWindows, - 0 + NULL ); if (!GetClassName(WindowHandle, windowClassName, RTL_NUMBER_OF(windowClassName))) @@ -1362,7 +1362,7 @@ LRESULT CALLBACK PhpThemeWindowDrawListViewGroup( if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, &metrics, 0)) { - metrics.lfMessageFont.lfHeight = -11; + metrics.lfMessageFont.lfHeight = PhMultiplyDivideSigned(-11, PhGlobalDpi, 96); metrics.lfMessageFont.lfWeight = FW_BOLD; PhpListViewFontHandle = CreateFontIndirect(&metrics.lfMessageFont); @@ -1563,7 +1563,7 @@ LRESULT CALLBACK PhpThemeWindowGroupBoxSubclassProc( if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, &metrics, 0)) { - metrics.lfMessageFont.lfHeight = -12; + metrics.lfMessageFont.lfHeight = PhMultiplyDivideSigned(-11, PhGlobalDpi, 96); metrics.lfMessageFont.lfWeight = FW_BOLD; PhpGroupboxFontHandle = CreateFontIndirect(&metrics.lfMessageFont); From 18c20b8ec6911da793e77d72888d6973d6941712 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 24 Feb 2019 12:38:16 +0100 Subject: [PATCH 1715/2058] Remove unused PhCreateProcessLxss paramater --- phlib/wslsup.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/phlib/wslsup.c b/phlib/wslsup.c index 27e388f53bca..f1fbc619eb00 100644 --- a/phlib/wslsup.c +++ b/phlib/wslsup.c @@ -183,8 +183,7 @@ BOOLEAN PhInitializeLxssImageVersionInfo( lxssDistroName->Buffer, lxssCommandLine->Buffer, NULL, - &result, - NULL + &result ); if (status == 0) @@ -201,8 +200,7 @@ BOOLEAN PhInitializeLxssImageVersionInfo( lxssDistroName->Buffer, lxssCommandLine->Buffer, NULL, - &result, - NULL + &result ); if (status != 0) @@ -244,8 +242,7 @@ BOOLEAN PhInitializeLxssImageVersionInfo( lxssDistroName->Buffer, lxssCommandLine->Buffer, NULL, - &result, - NULL + &result ); if (status != 0) @@ -269,7 +266,7 @@ BOOLEAN PhInitializeLxssImageVersionInfo( PH_STRINGREF descriptionPart; PH_STRINGREF versionPart; - remainingPart = result->sr; + remainingPart = PhGetStringRef(result); PhSplitStringRefAtChar(&remainingPart, '|', &versionPart, &remainingPart); PhSplitStringRefAtChar(&remainingPart, '|', &companyPart, &remainingPart); PhSplitStringRefAtChar(&remainingPart, '|', &descriptionPart, &remainingPart); @@ -296,8 +293,7 @@ ULONG PhCreateProcessLxss( _In_ PWSTR LxssDistribution, _In_ PWSTR LxssCommandLine, _In_opt_ PWSTR LxssCurrentDirectory, - _Out_ PPH_STRING *Result, - _Out_opt_ PHANDLE ProcessHandle + _Out_ PPH_STRING *Result ) { NTSTATUS status; From 58a1ae7c211d3c5280d824f024d03aea38639465 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 24 Feb 2019 12:39:20 +0100 Subject: [PATCH 1716/2058] Fix SAL warnings --- phlib/guisup.c | 4 ++-- phlib/include/guisup.h | 4 ++-- phlib/include/secedit.h | 4 ++-- phlib/include/wslsup.h | 3 +-- phlib/secedit.c | 2 +- 5 files changed, 8 insertions(+), 9 deletions(-) diff --git a/phlib/guisup.c b/phlib/guisup.c index cae5334b86e0..d1c655b75f25 100644 --- a/phlib/guisup.c +++ b/phlib/guisup.c @@ -1393,7 +1393,7 @@ VOID PhEnumChildWindows( _In_opt_ HWND WindowHandle, _In_ ULONG Limit, _In_ PH_CHILD_ENUM_CALLBACK Callback, - _In_ PVOID Context + _In_opt_ PVOID Context ) { HWND childWindow = NULL; @@ -1592,7 +1592,7 @@ static ULONG NTAPI PhpWindowCallbackHashtableHashFunction( VOID PhRegisterWindowCallback( _In_ HWND WindowHandle, _In_ PH_PLUGIN_WINDOW_EVENT_TYPE Type, - _In_ PVOID Context + _In_opt_ PVOID Context ) { PPH_PLUGIN_WINDOW_CALLBACK_REGISTRATION entry; diff --git a/phlib/include/guisup.h b/phlib/include/guisup.h index d3ab3f9426e3..b31a5ab17f21 100644 --- a/phlib/include/guisup.h +++ b/phlib/include/guisup.h @@ -500,7 +500,7 @@ VOID PhEnumChildWindows( _In_opt_ HWND WindowHandle, _In_ ULONG Limit, _In_ PH_CHILD_ENUM_CALLBACK Callback, - _In_ PVOID Context + _In_opt_ PVOID Context ); HWND PhGetProcessMainWindow( @@ -866,7 +866,7 @@ NTAPI PhRegisterWindowCallback( _In_ HWND WindowHandle, _In_ PH_PLUGIN_WINDOW_EVENT_TYPE Type, - _In_ PVOID Context + _In_opt_ PVOID Context ); PHLIBAPI diff --git a/phlib/include/secedit.h b/phlib/include/secedit.h index 2c013cabb84c..abf1c69d138b 100644 --- a/phlib/include/secedit.h +++ b/phlib/include/secedit.h @@ -33,7 +33,7 @@ PHLIBAPI VOID NTAPI PhEditSecurity( - _In_ HWND WindowHandle, + _In_opt_ HWND WindowHandle, _In_ PWSTR ObjectName, _In_ PWSTR ObjectType, _In_ PPH_OPEN_OBJECT OpenCallback, @@ -183,4 +183,4 @@ PhGetAccessString( } #endif -#endif \ No newline at end of file +#endif diff --git a/phlib/include/wslsup.h b/phlib/include/wslsup.h index c6a3d6578bfd..830d443fb511 100644 --- a/phlib/include/wslsup.h +++ b/phlib/include/wslsup.h @@ -36,8 +36,7 @@ ULONG PhCreateProcessLxss( _In_ PWSTR LxssDistribution, _In_ PWSTR LxssCommandLine, _In_opt_ PWSTR LxssCurrentDirectory, - _Out_ PPH_STRING *Result, - _Out_opt_ PHANDLE ProcessHandle + _Out_ PPH_STRING *Result ); #ifdef __cplusplus diff --git a/phlib/secedit.c b/phlib/secedit.c index 0be5a0975882..68bea3d7cdf4 100644 --- a/phlib/secedit.c +++ b/phlib/secedit.c @@ -140,7 +140,7 @@ static NTSTATUS PhpEditSecurityInformationThread( * \param Context A user-defined value to pass to the callback functions. */ VOID PhEditSecurity( - _In_ HWND WindowHandle, + _In_opt_ HWND WindowHandle, _In_ PWSTR ObjectName, _In_ PWSTR ObjectType, _In_ PPH_OPEN_OBJECT OpenObject, From a39d0f312c863ccb1c4ed927bfcd8eedac1b5fd7 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 24 Feb 2019 12:40:44 +0100 Subject: [PATCH 1717/2058] Add helper macro, Update comment authors --- phlib/include/phnativeinl.h | 2 +- phlib/include/phsup.h | 4 ++++ phlib/native.c | 3 +-- phlib/svcsup.c | 2 +- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/phlib/include/phnativeinl.h b/phlib/include/phnativeinl.h index 87a4c48ffda4..664b8eb17368 100644 --- a/phlib/include/phnativeinl.h +++ b/phlib/include/phnativeinl.h @@ -890,7 +890,7 @@ PhGetThreadLastSystemCall( ThreadHandle, ThreadLastSystemCall, LastSystemCall, - RTL_SIZEOF_THROUGH_FIELD(THREAD_LAST_SYSCALL_INFORMATION, Pad), // HACK: Win7 requires exact size. + RTL_SIZEOF_THROUGH_FIELD(THREAD_LAST_SYSCALL_INFORMATION, Pad), // HACK: Win7 requires exact size. (dmex) NULL ); } diff --git a/phlib/include/phsup.h b/phlib/include/phsup.h index 7ce52597ebbe..7e23a55430fc 100644 --- a/phlib/include/phsup.h +++ b/phlib/include/phsup.h @@ -42,6 +42,10 @@ #define ASSUME_NO_DEFAULT __assume(FALSE) #endif +// Math + +#define UInt32Add32To64(a, b) ((unsigned __int64)((unsigned __int64)(a) + ((unsigned __int64)(b)))) // Avoids warning C26451 (dmex) + // Time #define PH_TICKS_PER_NS ((LONG64)1 * 10) diff --git a/phlib/native.c b/phlib/native.c index abfe654d5cd3..2c22432dc6bb 100644 --- a/phlib/native.c +++ b/phlib/native.c @@ -6021,8 +6021,7 @@ VOID PhpRtlModulesToGenericModules( // directory. PhGetSystemRoot(&systemRoot); newFileName = PhConcatStringRef3(&systemRoot, &driversString, &moduleInfo.Name->sr); - PhDereferenceObject(moduleInfo.FileName); - moduleInfo.FileName = newFileName; + PhMoveReference(&moduleInfo.FileName, newFileName); } cont = Callback(&moduleInfo, Context); diff --git a/phlib/svcsup.c b/phlib/svcsup.c index 0a04876341ae..85bbdfa55938 100644 --- a/phlib/svcsup.c +++ b/phlib/svcsup.c @@ -562,7 +562,7 @@ NTSTATUS PhGetServiceDllParameter( // The SCM creates multiple "user service instance" processes for each user session with the following template: // [Host Service Instance Name]_[LUID for Session] // The SCM internally uses the ServiceDll of the "host service instance" for all "user service instance" processes/services - // and we need to parse the user service template and query the "host service instance" configuration. + // and we need to parse the user service template and query the "host service instance" configuration. (hsebs) if (PhSplitStringRefAtLastChar(ServiceName, L'_', &hostServiceName, &userSessionLuid)) keyName = PhConcatStringRef3(&servicesKeyName, &hostServiceName, ¶meters); From cb7ea5aef3a9d136989ea912e0e04cf24973c5b5 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 24 Feb 2019 12:42:55 +0100 Subject: [PATCH 1718/2058] ToolStatus: Improve toolbar graph performance (experimental) --- plugins/ToolStatus/graph.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/ToolStatus/graph.c b/plugins/ToolStatus/graph.c index 4e107af47920..f1a588e2fed5 100644 --- a/plugins/ToolStatus/graph.c +++ b/plugins/ToolStatus/graph.c @@ -283,7 +283,7 @@ VOID ToolbarUpdateGraphs( graph->GraphState.TooltipIndex = ULONG_MAX; Graph_MoveGrid(graph->GraphHandle, 1); Graph_Draw(graph->GraphHandle); - Graph_UpdateTooltip(graph->GraphHandle); + //Graph_UpdateTooltip(graph->GraphHandle); InvalidateRect(graph->GraphHandle, NULL, FALSE); } } From 63fed4491db4680c4801dea28d09b10bf234d04c Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 24 Feb 2019 12:43:43 +0100 Subject: [PATCH 1719/2058] Fix PhpStartPhSvcProcess crash --- ProcessHacker/actions.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ProcessHacker/actions.c b/ProcessHacker/actions.c index 23481d60d105..608528f26261 100644 --- a/ProcessHacker/actions.c +++ b/ProcessHacker/actions.c @@ -386,8 +386,9 @@ BOOLEAN PhpStartPhSvcProcess( } PhClearReference(&fileName); - PhClearReference(&applicationDirectory); } + + PhClearReference(&applicationDirectory); } break; } From eeeeca16c103aa4cb25a0fc5fe5907b587f7f932 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 24 Feb 2019 12:49:51 +0100 Subject: [PATCH 1720/2058] Add token properties dark theme support --- ProcessHacker/thrdstk.c | 4 +++- ProcessHacker/tokprp.c | 7 +++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/ProcessHacker/thrdstk.c b/ProcessHacker/thrdstk.c index 92fd9978c50b..7821e2978171 100644 --- a/ProcessHacker/thrdstk.c +++ b/ProcessHacker/thrdstk.c @@ -3,7 +3,7 @@ * thread stack viewer * * Copyright (C) 2010-2016 wj32 - * Copyright (C) 2017-2018 dmex + * Copyright (C) 2017-2019 dmex * * This file is part of Process Hacker. * @@ -820,6 +820,8 @@ INT_PTR CALLBACK PhpThreadStackDlgProc( PhLoadWindowPlacementFromSetting(NULL, L"ThreadStackWindowSize", hwndDlg); PhCenterWindow(hwndDlg, GetParent(hwndDlg)); + PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport); + if (PhPluginsEnabled) { PH_PLUGIN_THREAD_STACK_CONTROL control; diff --git a/ProcessHacker/tokprp.c b/ProcessHacker/tokprp.c index a45cd95e4893..8ae401ecb8c3 100644 --- a/ProcessHacker/tokprp.c +++ b/ProcessHacker/tokprp.c @@ -1766,6 +1766,11 @@ INT_PTR CALLBACK PhpTokenGeneralPageProc( if (!hasLinkedToken) ShowWindow(GetDlgItem(hwndDlg, IDC_LINKEDTOKEN), SW_HIDE); + + if (PhEnableThemeSupport) // TODO: Required for compat (dmex) + PhInitializeWindowTheme(GetParent(hwndDlg), PhEnableThemeSupport); // HACK (GetParent) + else + PhInitializeWindowTheme(hwndDlg, FALSE); } break; case WM_COMMAND: @@ -1902,6 +1907,8 @@ INT_PTR CALLBACK PhpTokenAdvancedPageProc( PhSetDialogItemText(hwndDlg, IDC_AUTHENTICATIONLUID, authenticationLuid); PhSetDialogItemText(hwndDlg, IDC_MEMORYUSED, PhGetStringOrDefault(memoryUsed, L"Unknown")); PhSetDialogItemText(hwndDlg, IDC_MEMORYAVAILABLE, PhGetStringOrDefault(memoryAvailable, L"Unknown")); + + PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport); } break; } From 6ed1c64d8868fd97c22f3e93fbc071eea12f1c3a Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 24 Feb 2019 12:51:11 +0100 Subject: [PATCH 1721/2058] Improve macro usage --- ProcessHacker/appsup.c | 2 +- ProcessHacker/runas.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ProcessHacker/appsup.c b/ProcessHacker/appsup.c index 96161692ab31..25e62c21d415 100644 --- a/ProcessHacker/appsup.c +++ b/ProcessHacker/appsup.c @@ -2075,7 +2075,7 @@ BOOLEAN PhShellOpenKey2( PhUnicodeStringToStringRef(&valueName, &valueNameSr); expandedKeyName = PhExpandKeyName(KeyName, TRUE); - NtSetValueKey(favoritesKeyHandle, &valueName, 0, REG_SZ, expandedKeyName->Buffer, (ULONG)expandedKeyName->Length + 2); + NtSetValueKey(favoritesKeyHandle, &valueName, 0, REG_SZ, expandedKeyName->Buffer, (ULONG)expandedKeyName->Length + sizeof(UNICODE_NULL)); PhDereferenceObject(expandedKeyName); // Select our entry in regedit. diff --git a/ProcessHacker/runas.c b/ProcessHacker/runas.c index 844f61e50b2b..c76a9f24b0bc 100644 --- a/ProcessHacker/runas.c +++ b/ProcessHacker/runas.c @@ -246,7 +246,7 @@ PPH_STRING GetCurrentWinStaName( GetProcessWindowStation(), UOI_NAME, string->Buffer, - (ULONG)string->Length + 2, + (ULONG)string->Length + sizeof(UNICODE_NULL), NULL )) { @@ -1098,8 +1098,8 @@ INT_PTR CALLBACK PhpRunAsDlgProc( createInfo.Password = PhGetStringOrEmpty(password); // Whenever we can, try not to set the desktop name; it breaks a lot of things. - if (desktopName->Length != 0 && !PhEqualString2(desktopName, L"WinSta0\\Default", TRUE)) - createInfo.DesktopName = desktopName->Buffer; + if (!PhIsNullOrEmptyString(desktopName) && !PhEqualString2(desktopName, L"WinSta0\\Default", TRUE)) + createInfo.DesktopName = PhGetString(desktopName); PhSetDesktopWinStaAccess(); From b1461f151a2a35aff929e17c5acfb1bd047d4bb7 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 24 Feb 2019 12:54:33 +0100 Subject: [PATCH 1722/2058] Improve network hostname lookup performance, Fix incorrect local address hostname lookup when using hostsfile --- ProcessHacker/ProcessHacker.vcxproj | 16 ++--- ProcessHacker/netprv.c | 94 ++++++++++++++++++++++++++--- 2 files changed, 94 insertions(+), 16 deletions(-) diff --git a/ProcessHacker/ProcessHacker.vcxproj b/ProcessHacker/ProcessHacker.vcxproj index b10224efca48..2424f13fc227 100644 --- a/ProcessHacker/ProcessHacker.vcxproj +++ b/ProcessHacker/ProcessHacker.vcxproj @@ -106,14 +106,14 @@ true - aclui.lib;comctl32.lib;iphlpapi.lib;noarg.obj;noenv.obj;ntdll.lib;phlib.lib;shlwapi.lib;userenv.lib;uxtheme.lib;version.lib;wbemuuid.lib;windowscodecs.lib;winsta.lib;ws2_32.lib;%(AdditionalDependencies) + aclui.lib;comctl32.lib;dnsapi.lib;iphlpapi.lib;noarg.obj;noenv.obj;ntdll.lib;phlib.lib;shlwapi.lib;userenv.lib;uxtheme.lib;version.lib;wbemuuid.lib;windowscodecs.lib;winsta.lib;ws2_32.lib;%(AdditionalDependencies) true Windows MachineX86 6.01 $(SolutionDir)phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) ProcessHacker.def - advapi32.dll;aclui.dll;comdlg32.dll;comctl32.dll;gdi32.dll;iphlpapi.dll;oleaut32.dll;ole32.dll;shell32.dll;shlwapi.dll;userenv.dll;user32.dll;uxtheme.dll;version.dll;winsta.dll;ws2_32.dll;%(DelayLoadDLLs) + advapi32.dll;aclui.dll;comdlg32.dll;comctl32.dll;dnsapi.dll;gdi32.dll;iphlpapi.dll;oleaut32.dll;ole32.dll;shell32.dll;shlwapi.dll;userenv.dll;user32.dll;uxtheme.dll;version.dll;winsta.dll;ws2_32.dll;%(DelayLoadDLLs) _UNICODE;UNICODE;%(PreprocessorDefinitions);$(ExternalCompilerOptions) @@ -138,14 +138,14 @@ true - aclui.lib;comctl32.lib;iphlpapi.lib;noarg.obj;noenv.obj;ntdll.lib;phlib.lib;shlwapi.lib;userenv.lib;uxtheme.lib;version.lib;wbemuuid.lib;windowscodecs.lib;winsta.lib;ws2_32.lib;%(AdditionalDependencies) + aclui.lib;comctl32.lib;dnsapi.lib;iphlpapi.lib;noarg.obj;noenv.obj;ntdll.lib;phlib.lib;shlwapi.lib;userenv.lib;uxtheme.lib;version.lib;wbemuuid.lib;windowscodecs.lib;winsta.lib;ws2_32.lib;%(AdditionalDependencies) true Windows MachineX64 6.01 $(SolutionDir)phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) ProcessHacker.def - advapi32.dll;aclui.dll;comdlg32.dll;comctl32.dll;gdi32.dll;iphlpapi.dll;oleaut32.dll;ole32.dll;shell32.dll;shlwapi.dll;userenv.dll;user32.dll;uxtheme.dll;version.dll;winsta.dll;ws2_32.dll;%(DelayLoadDLLs) + advapi32.dll;aclui.dll;comdlg32.dll;comctl32.dll;dnsapi.dll;gdi32.dll;iphlpapi.dll;oleaut32.dll;ole32.dll;shell32.dll;shlwapi.dll;userenv.dll;user32.dll;uxtheme.dll;version.dll;winsta.dll;ws2_32.dll;%(DelayLoadDLLs) _UNICODE;UNICODE;%(PreprocessorDefinitions);$(ExternalCompilerOptions) @@ -175,7 +175,7 @@ Guard - aclui.lib;comctl32.lib;iphlpapi.lib;noarg.obj;noenv.obj;ntdll.lib;phlib.lib;shlwapi.lib;userenv.lib;uxtheme.lib;version.lib;wbemuuid.lib;windowscodecs.lib;winsta.lib;ws2_32.lib;%(AdditionalDependencies) + aclui.lib;comctl32.lib;dnsapi.lib;iphlpapi.lib;noarg.obj;noenv.obj;ntdll.lib;phlib.lib;shlwapi.lib;userenv.lib;uxtheme.lib;version.lib;wbemuuid.lib;windowscodecs.lib;winsta.lib;ws2_32.lib;%(AdditionalDependencies) Windows true true @@ -184,7 +184,7 @@ 6.01 $(SolutionDir)phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) ProcessHacker.def - advapi32.dll;aclui.dll;comdlg32.dll;comctl32.dll;gdi32.dll;iphlpapi.dll;oleaut32.dll;ole32.dll;shell32.dll;shlwapi.dll;userenv.dll;user32.dll;uxtheme.dll;version.dll;winsta.dll;ws2_32.dll;%(DelayLoadDLLs) + advapi32.dll;aclui.dll;comdlg32.dll;comctl32.dll;dnsapi.dll;gdi32.dll;iphlpapi.dll;oleaut32.dll;ole32.dll;shell32.dll;shlwapi.dll;userenv.dll;user32.dll;uxtheme.dll;version.dll;winsta.dll;ws2_32.dll;%(DelayLoadDLLs) true @@ -213,7 +213,7 @@ Guard - aclui.lib;comctl32.lib;iphlpapi.lib;noarg.obj;noenv.obj;ntdll.lib;phlib.lib;shlwapi.lib;userenv.lib;uxtheme.lib;version.lib;wbemuuid.lib;windowscodecs.lib;winsta.lib;ws2_32.lib;%(AdditionalDependencies) + aclui.lib;comctl32.lib;dnsapi.lib;iphlpapi.lib;noarg.obj;noenv.obj;ntdll.lib;phlib.lib;shlwapi.lib;userenv.lib;uxtheme.lib;version.lib;wbemuuid.lib;windowscodecs.lib;winsta.lib;ws2_32.lib;%(AdditionalDependencies) Windows true true @@ -222,7 +222,7 @@ 6.01 $(SolutionDir)phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) ProcessHacker.def - advapi32.dll;aclui.dll;comdlg32.dll;comctl32.dll;gdi32.dll;iphlpapi.dll;oleaut32.dll;ole32.dll;shell32.dll;shlwapi.dll;userenv.dll;user32.dll;uxtheme.dll;version.dll;winsta.dll;ws2_32.dll;%(DelayLoadDLLs) + advapi32.dll;aclui.dll;comdlg32.dll;comctl32.dll;dnsapi.dll;gdi32.dll;iphlpapi.dll;oleaut32.dll;ole32.dll;shell32.dll;shlwapi.dll;userenv.dll;user32.dll;uxtheme.dll;version.dll;winsta.dll;ws2_32.dll;%(DelayLoadDLLs) true diff --git a/ProcessHacker/netprv.c b/ProcessHacker/netprv.c index 63a6c9ac7a2b..6457beb17f5f 100644 --- a/ProcessHacker/netprv.c +++ b/ProcessHacker/netprv.c @@ -4,6 +4,7 @@ * * Copyright (C) 2010 wj32 * Copyright (C) 2010 evilpie + * Copyright (C) 2016-2019 dmex * * This file is part of Process Hacker. * @@ -284,9 +285,9 @@ PPH_STRING PhGetHostNameFromAddress( _In_ PPH_IP_ADDRESS Address ) { - struct sockaddr_in ipv4Address; - struct sockaddr_in6 ipv6Address; - struct sockaddr *address; + SOCKADDR_IN ipv4Address; + SOCKADDR_IN6 ipv6Address; + PSOCKADDR address; socklen_t length; PPH_STRING hostName; @@ -295,7 +296,7 @@ PPH_STRING PhGetHostNameFromAddress( ipv4Address.sin_family = AF_INET; ipv4Address.sin_port = 0; ipv4Address.sin_addr = Address->InAddr; - address = (struct sockaddr *)&ipv4Address; + address = (PSOCKADDR)&ipv4Address; length = sizeof(ipv4Address); } else if (Address->Type == PH_IPV6_NETWORK_TYPE) @@ -305,7 +306,7 @@ PPH_STRING PhGetHostNameFromAddress( ipv6Address.sin6_flowinfo = 0; ipv6Address.sin6_addr = Address->In6Addr; ipv6Address.sin6_scope_id = 0; - address = (struct sockaddr *)&ipv6Address; + address = (PSOCKADDR)&ipv6Address; length = sizeof(ipv6Address); } else @@ -350,6 +351,84 @@ PPH_STRING PhGetHostNameFromAddress( return hostName; } +PPH_STRING PhpGetIp4ReverseNameFromAddress( + _In_ IN_ADDR Address + ) +{ + return PhFormatString( + L"%u.%u.%u.%u.%s", + Address.s_impno, + Address.s_lh, + Address.s_host, + Address.s_net, + DNS_IP4_REVERSE_DOMAIN_STRING_W + ); +} + +PPH_STRING PhpGetIp6ReverseNameFromAddress( + _In_ IN6_ADDR Address + ) +{ + PH_STRING_BUILDER stringBuilder; + + PhInitializeStringBuilder(&stringBuilder, 32); + + for (INT i = sizeof(IN6_ADDR) - 1; i >= 0; i--) + { + PhAppendFormatStringBuilder( + &stringBuilder, + L"%x.%x.", + Address.s6_addr[i] & 0xF, + (Address.s6_addr[i] >> 4) & 0xF + ); + } + + PhAppendStringBuilder2(&stringBuilder, DNS_IP6_REVERSE_DOMAIN_STRING_W); + + return PhFinalStringBuilderString(&stringBuilder); +} + +PPH_STRING PhGetHostNameFromAddressEx( + _In_ PPH_IP_ADDRESS Address + ) +{ + PPH_STRING addressHostName = NULL; + PPH_STRING addressReverse = NULL; + PDNS_RECORD addressResults = NULL; + + if (Address->Type == PH_IPV4_NETWORK_TYPE) + { + addressReverse = PhpGetIp4ReverseNameFromAddress(Address->InAddr); + } + else if (Address->Type == PH_IPV6_NETWORK_TYPE) + { + addressReverse = PhpGetIp6ReverseNameFromAddress(Address->In6Addr); + } + else + { + return NULL; + } + + DnsQuery( + addressReverse->Buffer, + DNS_TYPE_PTR, + DNS_QUERY_BYPASS_CACHE | DNS_QUERY_NO_HOSTS_FILE, + NULL, + &addressResults, + NULL + ); + + if (addressResults) + { + addressHostName = PhCreateString(addressResults->Data.PTR.pNameHost); // Return the first result (dmex) + DnsRecordListFree(addressResults, DnsFreeRecordList); + } + + PhDereferenceObject(addressReverse); + + return addressHostName; +} + NTSTATUS PhpNetworkItemQueryWorker( _In_ PVOID Parameter ) @@ -366,7 +445,7 @@ NTSTATUS PhpNetworkItemQueryWorker( if (!cacheItem) { - hostString = PhGetHostNameFromAddress(&data->Address); + hostString = PhGetHostNameFromAddressEx(&data->Address); if (hostString) { @@ -492,8 +571,7 @@ VOID PhNetworkProviderUpdate( if (!NetworkImportDone) { WSADATA wsaData; - - // Make sure WSA is initialized. + // Make sure WSA is initialized. (wj32) WSAStartup(WINSOCK_VERSION, &wsaData); NetworkImportDone = TRUE; } From bb89acbecc4b32689f822700311840d8cca891af Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 24 Feb 2019 12:55:17 +0100 Subject: [PATCH 1723/2058] Remove legacy dbghelp minidump support --- ProcessHacker/mdump.c | 68 +++++++++---------------------------------- 1 file changed, 13 insertions(+), 55 deletions(-) diff --git a/ProcessHacker/mdump.c b/ProcessHacker/mdump.c index ac3c37967c21..a80026a5f8cf 100644 --- a/ProcessHacker/mdump.c +++ b/ProcessHacker/mdump.c @@ -245,25 +245,12 @@ NTSTATUS PhpProcessMiniDumpThreadStart( } else { - // We may have an old version of dbghelp - in that case, try using minimal dump flags. - if (status == STATUS_INVALID_PARAMETER && NT_SUCCESS(status = PhSvcCallWriteMiniDumpProcess( - context->ProcessHandle, - context->ProcessId, - context->FileHandle, - MiniDumpWithFullMemory | MiniDumpWithHandleData - ))) - { - context->Succeeded = TRUE; - } - else - { - SendMessage( - context->WindowHandle, - WM_PH_MINIDUMP_STATUS_UPDATE, - PH_MINIDUMP_ERROR, - (LPARAM)PhNtStatusToDosError(status) - ); - } + SendMessage( + context->WindowHandle, + WM_PH_MINIDUMP_STATUS_UPDATE, + PH_MINIDUMP_ERROR, + (LPARAM)PhNtStatusToDosError(status) + ); } PhUiDisconnectFromPhSvc(); @@ -280,18 +267,7 @@ NTSTATUS PhpProcessMiniDumpThreadStart( L"A 64-bit dump will be created instead. Do you want to continue?" ) == IDNO) { - FILE_DISPOSITION_INFORMATION dispositionInfo; - IO_STATUS_BLOCK isb; - - dispositionInfo.DeleteFile = TRUE; - NtSetInformationFile( - context->FileHandle, - &isb, - &dispositionInfo, - sizeof(FILE_DISPOSITION_INFORMATION), - FileDispositionInformation - ); - + PhDeleteFile(context->FileHandle, TRUE); goto Completed; } } @@ -312,28 +288,12 @@ NTSTATUS PhpProcessMiniDumpThreadStart( } else { - // We may have an old version of dbghelp - in that case, try using minimal dump flags. - if (GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER) && PhWriteMiniDumpProcess( - context->ProcessHandle, - context->ProcessId, - context->FileHandle, - MiniDumpWithFullMemory | MiniDumpWithHandleData, - NULL, - NULL, - &callbackInfo - )) - { - context->Succeeded = TRUE; - } - else - { - SendMessage( - context->WindowHandle, - WM_PH_MINIDUMP_STATUS_UPDATE, - PH_MINIDUMP_ERROR, - (LPARAM)GetLastError() - ); - } + SendMessage( + context->WindowHandle, + WM_PH_MINIDUMP_STATUS_UPDATE, + PH_MINIDUMP_ERROR, + (LPARAM)GetLastError() + ); } #ifdef _WIN64 @@ -421,7 +381,6 @@ INT_PTR CALLBACK PhpProcessMiniDumpDlgProc( // No status message update for 2 seconds. PhSetDialogItemText(hwndDlg, IDC_PROGRESSTEXT, L"Creating the dump file..."); - InvalidateRect(GetDlgItem(hwndDlg, IDC_PROGRESSTEXT), NULL, FALSE); context->LastTickCount = currentTickCount; } @@ -434,7 +393,6 @@ INT_PTR CALLBACK PhpProcessMiniDumpDlgProc( { case PH_MINIDUMP_STATUS_UPDATE: PhSetDialogItemText(hwndDlg, IDC_PROGRESSTEXT, (PWSTR)lParam); - InvalidateRect(GetDlgItem(hwndDlg, IDC_PROGRESSTEXT), NULL, FALSE); context->LastTickCount = NtGetTickCount64(); break; case PH_MINIDUMP_ERROR: From f5f8e16592a5dce31a8205ca97de2b6925a4a2e5 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 24 Feb 2019 12:57:56 +0100 Subject: [PATCH 1724/2058] NetworkTools: Improve hostname lookup performance, Fix crash --- plugins/NetworkTools/NetworkTools.vcxproj | 16 +- plugins/NetworkTools/main.c | 4 +- plugins/NetworkTools/ping.c | 2 +- plugins/NetworkTools/tracert.c | 172 +++++++++++++--------- plugins/NetworkTools/tracetree.c | 6 +- plugins/NetworkTools/whois.c | 12 +- 6 files changed, 127 insertions(+), 85 deletions(-) diff --git a/plugins/NetworkTools/NetworkTools.vcxproj b/plugins/NetworkTools/NetworkTools.vcxproj index 00a63496d21a..f55bd1e227a5 100644 --- a/plugins/NetworkTools/NetworkTools.vcxproj +++ b/plugins/NetworkTools/NetworkTools.vcxproj @@ -56,27 +56,27 @@ - iphlpapi.lib;winhttp.lib;ws2_32.lib;%(AdditionalDependencies) - comctl32.dll;gdi32.dll;iphlpapi.dll;winhttp.dll;ws2_32.dll;user32.dll;%(DelayLoadDLLs) + dnsapi.lib;iphlpapi.lib;winhttp.lib;ws2_32.lib;%(AdditionalDependencies) + comctl32.dll;dnsapi.dll;gdi32.dll;iphlpapi.dll;winhttp.dll;ws2_32.dll;user32.dll;%(DelayLoadDLLs) - iphlpapi.lib;winhttp.lib;ws2_32.lib;%(AdditionalDependencies) - comctl32.dll;gdi32.dll;iphlpapi.dll;winhttp.dll;ws2_32.dll;user32.dll;%(DelayLoadDLLs) + dnsapi.lib;iphlpapi.lib;winhttp.lib;ws2_32.lib;%(AdditionalDependencies) + comctl32.dll;dnsapi.dll;gdi32.dll;iphlpapi.dll;winhttp.dll;ws2_32.dll;user32.dll;%(DelayLoadDLLs) - iphlpapi.lib;winhttp.lib;ws2_32.lib;%(AdditionalDependencies) - comctl32.dll;gdi32.dll;iphlpapi.dll;winhttp.dll;ws2_32.dll;user32.dll;%(DelayLoadDLLs) + dnsapi.lib;iphlpapi.lib;winhttp.lib;ws2_32.lib;%(AdditionalDependencies) + comctl32.dll;dnsapi.dll;gdi32.dll;iphlpapi.dll;winhttp.dll;ws2_32.dll;user32.dll;%(DelayLoadDLLs) - iphlpapi.lib;winhttp.lib;ws2_32.lib;%(AdditionalDependencies) - comctl32.dll;gdi32.dll;iphlpapi.dll;winhttp.dll;ws2_32.dll;user32.dll;%(DelayLoadDLLs) + dnsapi.lib;iphlpapi.lib;winhttp.lib;ws2_32.lib;%(AdditionalDependencies) + comctl32.dll;dnsapi.dll;gdi32.dll;iphlpapi.dll;winhttp.dll;ws2_32.dll;user32.dll;%(DelayLoadDLLs) diff --git a/plugins/NetworkTools/main.c b/plugins/NetworkTools/main.c index cb30a4edfb6e..86f3b3e5f5cd 100644 --- a/plugins/NetworkTools/main.c +++ b/plugins/NetworkTools/main.c @@ -836,7 +836,7 @@ VOID ProcessesUpdatedCallback( sizeof(TCP_ESTATS_PATH_ROD_v0) ) == ERROR_SUCCESS) { - extension->NumberOfLostPackets = pathRod.FastRetran + pathRod.PktsRetrans; + extension->NumberOfLostPackets = UInt32Add32To64(pathRod.FastRetran, pathRod.PktsRetrans); extension->SampleRtt = pathRod.SampleRtt; if (extension->SampleRtt == ULONG_MAX) // HACK @@ -883,7 +883,7 @@ VOID ProcessesUpdatedCallback( sizeof(TCP_ESTATS_PATH_ROD_v0) ) == ERROR_SUCCESS) { - extension->NumberOfLostPackets = pathRod.FastRetran + pathRod.PktsRetrans; + extension->NumberOfLostPackets = UInt32Add32To64(pathRod.FastRetran, pathRod.PktsRetrans); extension->SampleRtt = pathRod.SampleRtt; if (extension->SampleRtt == ULONG_MAX) // HACK diff --git a/plugins/NetworkTools/ping.c b/plugins/NetworkTools/ping.c index 633f613086ba..224dc930ac4b 100644 --- a/plugins/NetworkTools/ping.c +++ b/plugins/NetworkTools/ping.c @@ -49,7 +49,7 @@ NTSTATUS NetworkPingThreadStart( }; //pingOptions.Flags |= IP_FLAG_REVERSE; - if (icmpRandString = PhCreateStringEx(NULL, PhGetIntegerSetting(SETTING_NAME_PING_SIZE) * 2 + 2)) + if (icmpRandString = PhCreateStringEx(NULL, PhGetIntegerSetting(SETTING_NAME_PING_SIZE) * sizeof(WCHAR) + sizeof(UNICODE_NULL))) { PhGenerateRandomAlphaString(icmpRandString->Buffer, (ULONG)icmpRandString->Length / sizeof(WCHAR)); diff --git a/plugins/NetworkTools/tracert.c b/plugins/NetworkTools/tracert.c index 1f880864cdcf..509b76fee22b 100644 --- a/plugins/NetworkTools/tracert.c +++ b/plugins/NetworkTools/tracert.c @@ -54,88 +54,105 @@ PPH_STRING TracertGetErrorMessage( return message; } +PPH_STRING PhpGetIp4ReverseNameFromAddress( + _In_ IN_ADDR Address + ) +{ + return PhFormatString(L"%u.%u.%u.%u.%s", + Address.s_impno, + Address.s_lh, + Address.s_host, + Address.s_net, + DNS_IP4_REVERSE_DOMAIN_STRING_W + ); +} + +PPH_STRING PhpGetIp6ReverseNameFromAddress( + _In_ IN6_ADDR Address + ) +{ + PH_STRING_BUILDER stringBuilder; + + PhInitializeStringBuilder(&stringBuilder, 32); + + for (INT i = sizeof(IN6_ADDR) - 1; i >= 0; i--) + { + PhAppendFormatStringBuilder( + &stringBuilder, + L"%x.%x.", + Address.s6_addr[i] & 0xF, + (Address.s6_addr[i] >> 4) & 0xF + ); + } + + PhAppendStringBuilder2(&stringBuilder, DNS_IP6_REVERSE_DOMAIN_STRING_W); + + return PhFinalStringBuilderString(&stringBuilder); +} + NTSTATUS TracertHostnameLookupCallback( _In_ PVOID Parameter ) { PTRACERT_RESOLVE_WORKITEM resolve = Parameter; - WSADATA winsockStartup; + DNS_STATUS status; + PPH_STRING addressHostName = NULL; + PPH_STRING addressReverse = NULL; + PDNS_RECORD dnsQueryResults = NULL; - if (WSAStartup(WINSOCK_VERSION, &winsockStartup) != ERROR_SUCCESS) + if (resolve->Type == PH_IPV4_NETWORK_TYPE) + { + addressReverse = PhpGetIp4ReverseNameFromAddress(((PSOCKADDR_IN)&resolve->SocketAddress)->sin_addr); + } + else if (resolve->Type == PH_IPV6_NETWORK_TYPE) + { + addressReverse = PhpGetIp6ReverseNameFromAddress(((PSOCKADDR_IN6)&resolve->SocketAddress)->sin6_addr); + } + else + { return STATUS_INVALID_PARAMETER; + } - if (resolve->Type == PH_IPV4_NETWORK_TYPE) + status = DnsQuery( + addressReverse->Buffer, + DNS_TYPE_PTR, + DNS_QUERY_BYPASS_CACHE | DNS_QUERY_NO_HOSTS_FILE, + NULL, + &dnsQueryResults, + NULL + ); + + if (dnsQueryResults) { - if (!GetNameInfo( - (PSOCKADDR)&resolve->SocketAddress, - sizeof(SOCKADDR_IN), - resolve->SocketAddressHostname, - sizeof(resolve->SocketAddressHostname), - NULL, - 0, - NI_NAMEREQD - )) - { - SendMessage( - resolve->WindowHandle, - WM_TRACERT_HOSTNAME, - resolve->Index, - (LPARAM)PhCreateString(resolve->SocketAddressHostname) - ); - } - else - { - ULONG errorCode = WSAGetLastError(); - if (errorCode != WSAHOST_NOT_FOUND && errorCode != WSATRY_AGAIN) - { - SendMessage( - resolve->WindowHandle, - WM_TRACERT_HOSTNAME, - resolve->Index, - (LPARAM)PhGetWin32Message(errorCode) - ); - } + addressHostName = PhCreateString(dnsQueryResults->Data.PTR.pNameHost); // Return the first result (dmex) + DnsRecordListFree(dnsQueryResults, DnsFreeRecordList); + } - PhDereferenceObject(resolve); - } + if (addressHostName) + { + SendMessage( + resolve->WindowHandle, + WM_TRACERT_HOSTNAME, + resolve->Index, + (LPARAM)addressHostName + ); } - else if (resolve->Type == PH_IPV6_NETWORK_TYPE) + else { - if (!GetNameInfo( - (PSOCKADDR)&resolve->SocketAddress, - sizeof(SOCKADDR_IN6), - resolve->SocketAddressHostname, - sizeof(resolve->SocketAddressHostname), - NULL, - 0, - NI_NAMEREQD - )) + if (status != DNS_ERROR_RCODE_NAME_ERROR) { SendMessage( - resolve->WindowHandle, - WM_TRACERT_HOSTNAME, - resolve->Index, - (LPARAM)PhCreateString(resolve->SocketAddressHostname) + resolve->WindowHandle, + WM_TRACERT_HOSTNAME, + resolve->Index, + (LPARAM)PhGetWin32Message(status) ); } - else - { - ULONG errorCode = WSAGetLastError(); - if (errorCode != WSAHOST_NOT_FOUND && errorCode != WSATRY_AGAIN) - { - SendMessage( - resolve->WindowHandle, - WM_TRACERT_HOSTNAME, - resolve->Index, - (LPARAM)PhGetWin32Message(errorCode) - ); - } - PhDereferenceObject(resolve); - } + PhDereferenceObject(resolve); } - WSACleanup(); + PhDereferenceObject(addressReverse); return STATUS_SUCCESS; } @@ -276,7 +293,7 @@ NTSTATUS NetworkTracertThreadStart( 0 }; - if (icmpRandString = PhCreateStringEx(NULL, PhGetIntegerSetting(SETTING_NAME_PING_SIZE) * 2 + 2)) + if (icmpRandString = PhCreateStringEx(NULL, PhGetIntegerSetting(SETTING_NAME_PING_SIZE) * sizeof(WCHAR) + sizeof(UNICODE_NULL))) { PhGenerateRandomAlphaString(icmpRandString->Buffer, (ULONG)icmpRandString->Length / sizeof(WCHAR)); @@ -485,7 +502,7 @@ VOID TracertMenuActionCallback( PWSTR terminator = NULL; PTRACERT_ROOT_NODE node; - if (node = GetSelectedTracertNode(Context)) + if ((node = GetSelectedTracertNode(Context)) && !PhIsNullOrEmptyString(node->IpAddressString)) { if (NT_SUCCESS(RtlIpv4StringToAddress( node->IpAddressString->Buffer, @@ -518,7 +535,7 @@ VOID TracertMenuActionCallback( PWSTR terminator = NULL; PTRACERT_ROOT_NODE node; - if (node = GetSelectedTracertNode(Context)) + if ((node = GetSelectedTracertNode(Context)) && !PhIsNullOrEmptyString(node->IpAddressString)) { if (NT_SUCCESS(RtlIpv4StringToAddress( node->IpAddressString->Buffer, @@ -551,7 +568,7 @@ VOID TracertMenuActionCallback( PWSTR terminator = NULL; PTRACERT_ROOT_NODE node; - if (node = GetSelectedTracertNode(Context)) + if ((node = GetSelectedTracertNode(Context)) && !PhIsNullOrEmptyString(node->IpAddressString)) { if (NT_SUCCESS(RtlIpv4StringToAddress( node->IpAddressString->Buffer, @@ -719,6 +736,13 @@ INT_PTR CALLBACK TracertDlgProc( PhInsertEMenuItem(menu, PhCreateEMenuItem(0, MENU_ACTION_COPY, L"Copy", NULL, NULL), ULONG_MAX); PhInsertCopyCellEMenuItem(menu, MENU_ACTION_COPY, context->TreeNewHandle, contextMenuEvent->Column); + if (PhIsNullOrEmptyString(selectedNode->IpAddressString)) + { + PhSetFlagsEMenuItem(menu, MAINMENU_ACTION_PING, PH_EMENU_DISABLED, PH_EMENU_DISABLED); + PhSetFlagsEMenuItem(menu, NETWORK_ACTION_TRACEROUTE, PH_EMENU_DISABLED, PH_EMENU_DISABLED); + PhSetFlagsEMenuItem(menu, NETWORK_ACTION_WHOIS, PH_EMENU_DISABLED, PH_EMENU_DISABLED); + } + selectedItem = PhShowEMenu( menu, hwndDlg, @@ -856,7 +880,12 @@ VOID ShowTracertWindow( memset(context, 0, sizeof(NETWORK_TRACERT_CONTEXT)); context->MaximumHops = PhGetIntegerSetting(SETTING_NAME_TRACERT_MAX_HOPS); - context->RemoteEndpoint = NetworkItem->RemoteEndpoint; + + RtlCopyMemory( + &context->RemoteEndpoint, + &NetworkItem->RemoteEndpoint, + sizeof(PH_IP_ENDPOINT) + ); if (NetworkItem->RemoteEndpoint.Address.Type == PH_IPV4_NETWORK_TYPE) { @@ -880,7 +909,12 @@ VOID ShowTracertWindowFromAddress( memset(context, 0, sizeof(NETWORK_TRACERT_CONTEXT)); context->MaximumHops = PhGetIntegerSetting(SETTING_NAME_TRACERT_MAX_HOPS); - context->RemoteEndpoint = RemoteEndpoint; + + RtlCopyMemory( + &context->RemoteEndpoint, + &RemoteEndpoint, + sizeof(PH_IP_ENDPOINT) + ); if (RemoteEndpoint.Address.Type == PH_IPV4_NETWORK_TYPE) { diff --git a/plugins/NetworkTools/tracetree.c b/plugins/NetworkTools/tracetree.c index 002147ff504c..1650bb7d53f8 100644 --- a/plugins/NetworkTools/tracetree.c +++ b/plugins/NetworkTools/tracetree.c @@ -193,7 +193,7 @@ VOID DestroyTracertNode( _In_ PTRACERT_ROOT_NODE Node ) { - PhDereferenceObject(Node); + PhDereferenceObject(Node); } PTRACERT_ROOT_NODE AddTracertNode( @@ -277,8 +277,8 @@ VOID UpdateTracertNodePingText( _In_ ULONG Index ) { - if (Node->PingStatus[Index] == IP_HOP_LIMIT_EXCEEDED || - Node->PingStatus[Index] == IP_SUCCESS) + if (Node->PingStatus[Index] == IP_SUCCESS || + Node->PingStatus[Index] == IP_TTL_EXPIRED_TRANSIT) // IP_HOP_LIMIT_EXCEEDED { if (Node->PingList[Index]) { diff --git a/plugins/NetworkTools/whois.c b/plugins/NetworkTools/whois.c index 41834bec4169..ea6e810c8ebb 100644 --- a/plugins/NetworkTools/whois.c +++ b/plugins/NetworkTools/whois.c @@ -573,7 +573,11 @@ VOID ShowWhoisWindow( context = (PNETWORK_WHOIS_CONTEXT)PhCreateAlloc(sizeof(NETWORK_WHOIS_CONTEXT)); memset(context, 0, sizeof(NETWORK_WHOIS_CONTEXT)); - context->RemoteEndpoint = NetworkItem->RemoteEndpoint; + RtlCopyMemory( + &context->RemoteEndpoint, + &NetworkItem->RemoteEndpoint, + sizeof(PH_IP_ENDPOINT) + ); if (NetworkItem->RemoteEndpoint.Address.Type == PH_IPV4_NETWORK_TYPE) { @@ -596,7 +600,11 @@ VOID ShowWhoisWindowFromAddress( context = (PNETWORK_WHOIS_CONTEXT)PhCreateAlloc(sizeof(NETWORK_WHOIS_CONTEXT)); memset(context, 0, sizeof(NETWORK_WHOIS_CONTEXT)); - context->RemoteEndpoint = RemoteEndpoint; + RtlCopyMemory( + &context->RemoteEndpoint, + &RemoteEndpoint, + sizeof(PH_IP_ENDPOINT) + ); if (RemoteEndpoint.Address.Type == PH_IPV4_NETWORK_TYPE) { From f63d84cbf2ca83bf0db788944b9b8be9222f33fb Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 24 Feb 2019 13:09:22 +0100 Subject: [PATCH 1725/2058] Fix typo from commit bb89acbe --- ProcessHacker/mdump.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ProcessHacker/mdump.c b/ProcessHacker/mdump.c index a80026a5f8cf..f7303d13ac37 100644 --- a/ProcessHacker/mdump.c +++ b/ProcessHacker/mdump.c @@ -267,7 +267,7 @@ NTSTATUS PhpProcessMiniDumpThreadStart( L"A 64-bit dump will be created instead. Do you want to continue?" ) == IDNO) { - PhDeleteFile(context->FileHandle, TRUE); + PhDeleteFile(context->FileHandle); goto Completed; } } From fb28a4779ec627710506039d12a14c39d3d119fa Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 24 Feb 2019 13:40:38 +0100 Subject: [PATCH 1726/2058] Fix Ip6ReverseName buffer length --- ProcessHacker/netprv.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ProcessHacker/netprv.c b/ProcessHacker/netprv.c index 6457beb17f5f..b676e4c5556f 100644 --- a/ProcessHacker/netprv.c +++ b/ProcessHacker/netprv.c @@ -371,7 +371,7 @@ PPH_STRING PhpGetIp6ReverseNameFromAddress( { PH_STRING_BUILDER stringBuilder; - PhInitializeStringBuilder(&stringBuilder, 32); + PhInitializeStringBuilder(&stringBuilder, DNS_MAX_NAME_BUFFER_LENGTH); for (INT i = sizeof(IN6_ADDR) - 1; i >= 0; i--) { @@ -753,10 +753,10 @@ VOID PhNetworkProviderUpdate( PROCESS_EXTENDED_BASIC_INFORMATION basicInfo; // HACK HACK HACK - // WSL subsystem processes (e.g. nginx) create sockets, clone/fork themselves, duplicate the socket into the child process and then terminate. + // WSL subsystem processes (e.g. apache/nginx) create sockets, clone/fork themselves, duplicate the socket into the child process and then terminate. // The socket handle remains valid and in-use by the child process BUT the socket continues returning the PID of the exited process??? // Fixing this causes a major performance problem; If we have 100,000 sockets then on previous versions of Windows we would only need 2 system calls maximum - // (for the process list) to identify the owner of every socket but now we need to make 4 system calls for every_last_socket totaling 400,000 system calls... great. + // (for the process list) to identify the owner of every socket but now we need to make 4 system calls for every_last_socket totaling 400,000 system calls... great. (dmex) if (NT_SUCCESS(PhOpenProcess(&processHandle, PROCESS_QUERY_LIMITED_INFORMATION, networkItem->ProcessId))) { if (NT_SUCCESS(PhGetProcessExtendedBasicInformation(processHandle, &basicInfo))) @@ -768,7 +768,7 @@ VOID PhNetworkProviderUpdate( { PhMoveReference(&networkItem->ProcessName, PhGetBaseName(fileName)); } - + NtClose(processHandle); } From ab5a1ff7a34c7ca4fb2fade0c509898a9a93d425 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 24 Feb 2019 13:42:08 +0100 Subject: [PATCH 1727/2058] Add PhGetInternalWindowIcon --- phlib/guisup.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/phlib/guisup.c b/phlib/guisup.c index d1c655b75f25..6a4ae11f1342 100644 --- a/phlib/guisup.c +++ b/phlib/guisup.c @@ -1702,3 +1702,32 @@ BOOLEAN PhShowRunFileDialog( return result; } + +HICON PhGetInternalWindowIcon( + _In_ HWND WindowHandle, + _In_ UINT Type + ) +{ + static PH_INITONCE initOnce = PH_INITONCE_INIT; + static HICON (WINAPI *InternalGetWindowIcon_I)( + _In_ HWND WindowHandle, + _In_ ULONG Type + ) = NULL; + + if (PhBeginInitOnce(&initOnce)) + { + PVOID shell32Handle; + + if (shell32Handle = LoadLibrary(L"shell32.dll")) + { + InternalGetWindowIcon_I = PhGetDllBaseProcedureAddress(shell32Handle, "InternalGetWindowIcon", 0); + } + + PhEndInitOnce(&initOnce); + } + + if (!InternalGetWindowIcon_I) + return NULL; + + return InternalGetWindowIcon_I(WindowHandle, Type);; +} From d91026384b06a85d818bb7589f70be0f3b4719cd Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 24 Feb 2019 14:01:49 +0100 Subject: [PATCH 1728/2058] Update DnsQuery flags --- ProcessHacker/netprv.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ProcessHacker/netprv.c b/ProcessHacker/netprv.c index b676e4c5556f..51426b071416 100644 --- a/ProcessHacker/netprv.c +++ b/ProcessHacker/netprv.c @@ -356,7 +356,7 @@ PPH_STRING PhpGetIp4ReverseNameFromAddress( ) { return PhFormatString( - L"%u.%u.%u.%u.%s", + L"%hhu.%hhu.%hhu.%hhu.%s", Address.s_impno, Address.s_lh, Address.s_host, @@ -377,7 +377,7 @@ PPH_STRING PhpGetIp6ReverseNameFromAddress( { PhAppendFormatStringBuilder( &stringBuilder, - L"%x.%x.", + L"%hhx.%hhx.", Address.s6_addr[i] & 0xF, (Address.s6_addr[i] >> 4) & 0xF ); @@ -412,7 +412,7 @@ PPH_STRING PhGetHostNameFromAddressEx( DnsQuery( addressReverse->Buffer, DNS_TYPE_PTR, - DNS_QUERY_BYPASS_CACHE | DNS_QUERY_NO_HOSTS_FILE, + DNS_QUERY_NO_HOSTS_FILE, // DNS_QUERY_BYPASS_CACHE NULL, &addressResults, NULL From 0b221a862043d7402f462230db2277e2392ee33f Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 24 Feb 2019 18:51:14 +0100 Subject: [PATCH 1729/2058] Fix searchbox memory leaks --- ProcessHacker/prpgenv.c | 5 +++++ ProcessHacker/prpghndl.c | 3 +++ ProcessHacker/prpgmem.c | 4 ++++ ProcessHacker/prpgmod.c | 3 +++ plugins/WindowExplorer/wndtree.c | 3 +++ 5 files changed, 18 insertions(+) diff --git a/ProcessHacker/prpgenv.c b/ProcessHacker/prpgenv.c index f9f7ef565632..7771b6b76c92 100644 --- a/ProcessHacker/prpgenv.c +++ b/ProcessHacker/prpgenv.c @@ -1233,6 +1233,8 @@ VOID PhpDeleteEnvironmentTree( _In_ PPH_ENVIRONMENT_CONTEXT Context ) { + PhDeleteTreeNewFilterSupport(&Context->TreeFilterSupport); + for (ULONG i = 0; i < Context->NodeList->Count; i++) { PhpDestroyEnvironmentNode(Context->NodeList->Items[i]); @@ -1331,6 +1333,9 @@ INT_PTR CALLBACK PhpProcessEnvironmentDlgProc( break; case WM_DESTROY: { + PhRemoveTreeNewFilter(&context->TreeFilterSupport, context->TreeFilterEntry); + if (context->SearchboxText) PhDereferenceObject(context->SearchboxText); + PhSaveSettingsEnvironmentList(context); PhpDeleteEnvironmentTree(context); diff --git a/ProcessHacker/prpghndl.c b/ProcessHacker/prpghndl.c index 6086e33eb5ae..03cbfc40b1f1 100644 --- a/ProcessHacker/prpghndl.c +++ b/ProcessHacker/prpghndl.c @@ -438,6 +438,9 @@ INT_PTR CALLBACK PhpProcessHandlesDlgProc( break; case WM_DESTROY: { + PhRemoveTreeNewFilter(&handlesContext->ListContext.TreeFilterSupport, handlesContext->FilterEntry); + if (handlesContext->SearchboxText) PhDereferenceObject(handlesContext->SearchboxText); + PhEmCallObjectOperation(EmHandlesContextType, handlesContext, EmObjectDelete); PhUnregisterCallback( diff --git a/ProcessHacker/prpgmem.c b/ProcessHacker/prpgmem.c index 86a8f21fa323..29196be6efed 100644 --- a/ProcessHacker/prpgmem.c +++ b/ProcessHacker/prpgmem.c @@ -423,6 +423,10 @@ INT_PTR CALLBACK PhpProcessMemoryDlgProc( break; case WM_DESTROY: { + PhRemoveTreeNewFilter(&memoryContext->ListContext.TreeFilterSupport, memoryContext->FilterEntry); + PhRemoveTreeNewFilter(&memoryContext->ListContext.TreeFilterSupport, memoryContext->AllocationFilterEntry); + if (memoryContext->SearchboxText) PhDereferenceObject(memoryContext->SearchboxText); + PhEmCallObjectOperation(EmMemoryContextType, memoryContext, EmObjectDelete); if (PhPluginsEnabled) diff --git a/ProcessHacker/prpgmod.c b/ProcessHacker/prpgmod.c index 988901eb16a9..70f14986a8df 100644 --- a/ProcessHacker/prpgmod.c +++ b/ProcessHacker/prpgmod.c @@ -496,6 +496,9 @@ INT_PTR CALLBACK PhpProcessModulesDlgProc( break; case WM_DESTROY: { + PhRemoveTreeNewFilter(&modulesContext->ListContext.TreeFilterSupport, modulesContext->FilterEntry); + if (modulesContext->SearchboxText) PhDereferenceObject(modulesContext->SearchboxText); + PhEmCallObjectOperation(EmModulesContextType, modulesContext, EmObjectDelete); PhUnregisterCallback( diff --git a/plugins/WindowExplorer/wndtree.c b/plugins/WindowExplorer/wndtree.c index 55c942fe41c1..f3b45269d549 100644 --- a/plugins/WindowExplorer/wndtree.c +++ b/plugins/WindowExplorer/wndtree.c @@ -187,6 +187,9 @@ VOID WeDeleteWindowTree( PPH_STRING settings; ULONG i; + PhRemoveTreeNewFilter(&Context->FilterSupport, Context->TreeFilterEntry); + if (Context->SearchboxText) PhDereferenceObject(Context->SearchboxText); + PhDeleteTreeNewFilterSupport(&Context->FilterSupport); settings = PhCmSaveSettings(Context->TreeNewHandle); From b45b3e16f553bb59dc600c306894421f33b431f4 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 24 Feb 2019 19:01:02 +0100 Subject: [PATCH 1730/2058] DotNetTools: Fix memory leak --- plugins/DotNetTools/asmpage.c | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/DotNetTools/asmpage.c b/plugins/DotNetTools/asmpage.c index 22876ba89eec..d705dfb3e293 100644 --- a/plugins/DotNetTools/asmpage.c +++ b/plugins/DotNetTools/asmpage.c @@ -1504,6 +1504,7 @@ INT_PTR CALLBACK DotNetAsmPageDlgProc( { PhRemoveTreeNewFilter(&context->TreeFilterSupport, context->TreeFilterEntry); PhDeleteTreeNewFilterSupport(&context->TreeFilterSupport); + if (context->SearchBoxText) PhDereferenceObject(context->SearchBoxText); DotNetAsmSaveSettingsTreeList(context); DotNetAsmDestroyTreeNodes(context); From 515790545ecf5ed21874235993c6b20a76605b84 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 24 Feb 2019 19:02:41 +0100 Subject: [PATCH 1731/2058] Update token capabilities tab layout --- ProcessHacker/ProcessHacker.rc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ProcessHacker/ProcessHacker.rc b/ProcessHacker/ProcessHacker.rc index 78d9bf4e7d45..c5e0b3e0c179 100644 --- a/ProcessHacker/ProcessHacker.rc +++ b/ProcessHacker/ProcessHacker.rc @@ -1354,7 +1354,7 @@ STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSM CAPTION "Capabilities" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN - CONTROL "",IDC_LIST,"PhTreeNew",WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP | 0x32,7,7,256,214,WS_EX_CLIENTEDGE + CONTROL "",IDC_LIST,"PhTreeNew",WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP | 0x32,0,0,270,228,WS_EX_CLIENTEDGE END IDD_TOKATTRIBUTES DIALOGEX 0, 0, 270, 228 @@ -1362,7 +1362,7 @@ STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSM CAPTION "Attributes" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN - CONTROL "",IDC_LIST,"PhTreeNew",WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP | 0x32,7,7,256,214,WS_EX_CLIENTEDGE + CONTROL "",IDC_LIST,"PhTreeNew",WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP | 0x32,0,0,270,228,WS_EX_CLIENTEDGE END IDD_SYSINFO_CPU DIALOGEX 0, 0, 316, 195 From c57b049f08375a70b052e55c66051d21463b1e9e Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 24 Feb 2019 19:03:35 +0100 Subject: [PATCH 1732/2058] Add initial RS5 SideChannelIsolationPolicy mitigation --- ProcessHacker/include/procmtgn.h | 1 + ProcessHacker/procmtgn.c | 1 + phnt/include/ntpsapi.h | 1 + 3 files changed, 3 insertions(+) diff --git a/ProcessHacker/include/procmtgn.h b/ProcessHacker/include/procmtgn.h index 53adeaaf112c..72a931e3d144 100644 --- a/ProcessHacker/include/procmtgn.h +++ b/ProcessHacker/include/procmtgn.h @@ -18,6 +18,7 @@ typedef struct _PH_PROCESS_MITIGATION_POLICY_ALL_INFORMATION PROCESS_MITIGATION_SYSTEM_CALL_FILTER_POLICY SystemCallFilterPolicy; // ProcessSystemCallFilterPolicy PROCESS_MITIGATION_PAYLOAD_RESTRICTION_POLICY PayloadRestrictionPolicy; // ProcessPayloadRestrictionPolicy PROCESS_MITIGATION_CHILD_PROCESS_POLICY ChildProcessPolicy; // ProcessChildProcessPolicy + PROCESS_MITIGATION_SIDE_CHANNEL_ISOLATION_POLICY SideChannelIsolationPolicy; // ProcessSideChannelIsolationPolicy } PH_PROCESS_MITIGATION_POLICY_ALL_INFORMATION, *PPH_PROCESS_MITIGATION_POLICY_ALL_INFORMATION; NTSTATUS PhGetProcessMitigationPolicy( diff --git a/ProcessHacker/procmtgn.c b/ProcessHacker/procmtgn.c index 1016a27e0acc..72e03c74c8cc 100644 --- a/ProcessHacker/procmtgn.c +++ b/ProcessHacker/procmtgn.c @@ -119,6 +119,7 @@ NTSTATUS PhGetProcessMitigationPolicy( COPY_PROCESS_MITIGATION_POLICY(SystemCallFilter, PROCESS_MITIGATION_SYSTEM_CALL_FILTER_POLICY); // REDSTONE3 COPY_PROCESS_MITIGATION_POLICY(PayloadRestriction, PROCESS_MITIGATION_PAYLOAD_RESTRICTION_POLICY); COPY_PROCESS_MITIGATION_POLICY(ChildProcess, PROCESS_MITIGATION_CHILD_PROCESS_POLICY); + COPY_PROCESS_MITIGATION_POLICY(SideChannelIsolation, PROCESS_MITIGATION_CHILD_PROCESS_POLICY); return status; } diff --git a/phnt/include/ntpsapi.h b/phnt/include/ntpsapi.h index c7b4d4b02687..d459ca453e52 100644 --- a/phnt/include/ntpsapi.h +++ b/phnt/include/ntpsapi.h @@ -646,6 +646,7 @@ typedef struct _PROCESS_MITIGATION_POLICY_INFORMATION PROCESS_MITIGATION_SYSTEM_CALL_FILTER_POLICY SystemCallFilterPolicy; PROCESS_MITIGATION_PAYLOAD_RESTRICTION_POLICY PayloadRestrictionPolicy; PROCESS_MITIGATION_CHILD_PROCESS_POLICY ChildProcessPolicy; + PROCESS_MITIGATION_SIDE_CHANNEL_ISOLATION_POLICY SideChannelIsolationPolicy; }; } PROCESS_MITIGATION_POLICY_INFORMATION, *PPROCESS_MITIGATION_POLICY_INFORMATION; From db520d3fc5a26efe3d089fb634a18b00cd66dbc4 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 24 Feb 2019 19:04:44 +0100 Subject: [PATCH 1733/2058] Add search support to process threads tab --- ProcessHacker/ProcessHacker.rc | 4 +- ProcessHacker/include/procprpp.h | 4 +- ProcessHacker/include/thrdlist.h | 1 + ProcessHacker/prpgthrd.c | 172 ++++++++++++++++++++++++++++++- ProcessHacker/thrdlist.c | 2 + 5 files changed, 176 insertions(+), 7 deletions(-) diff --git a/ProcessHacker/ProcessHacker.rc b/ProcessHacker/ProcessHacker.rc index c5e0b3e0c179..976619a00107 100644 --- a/ProcessHacker/ProcessHacker.rc +++ b/ProcessHacker/ProcessHacker.rc @@ -517,7 +517,9 @@ STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSM CAPTION "Threads" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN - CONTROL "",IDC_LIST,"PhTreeNew",WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP | 0xa,2,2,256,256,WS_EX_CLIENTEDGE + CONTROL "",IDC_LIST,"PhTreeNew",WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP | 0xa,2,19,256,239,WS_EX_CLIENTEDGE + EDITTEXT IDC_SEARCH,114,3,144,14,ES_AUTOHSCROLL + PUSHBUTTON "Options",IDC_FILTEROPTIONS,2,2,50,14 END IDD_PROCHANDLES DIALOGEX 0, 0, 260, 260 diff --git a/ProcessHacker/include/procprpp.h b/ProcessHacker/include/procprpp.h index 26956ce8950d..b6f58d33ddd3 100644 --- a/ProcessHacker/include/procprpp.h +++ b/ProcessHacker/include/procprpp.h @@ -164,8 +164,10 @@ typedef struct _PH_THREADS_CONTEXT PH_CALLBACK_REGISTRATION LoadingStateChangedEventRegistration; HWND WindowHandle; + HWND SearchboxHandle; // end_phapppub - + PPH_STRING SearchboxText; + PPH_TN_FILTER_ENTRY FilterEntry; union { PH_THREAD_LIST_CONTEXT ListContext; diff --git a/ProcessHacker/include/thrdlist.h b/ProcessHacker/include/thrdlist.h index 2a876e5d8a75..110388a583d7 100644 --- a/ProcessHacker/include/thrdlist.h +++ b/ProcessHacker/include/thrdlist.h @@ -85,6 +85,7 @@ typedef struct _PH_THREAD_LIST_CONTEXT BOOLEAN EnableStateHighlighting; PPH_POINTER_LIST NodeStateList; + PH_TN_FILTER_SUPPORT TreeFilterSupport; } PH_THREAD_LIST_CONTEXT, *PPH_THREAD_LIST_CONTEXT; VOID PhInitializeThreadList( diff --git a/ProcessHacker/prpgthrd.c b/ProcessHacker/prpgthrd.c index 87bea2b8d2aa..3635f752c405 100644 --- a/ProcessHacker/prpgthrd.c +++ b/ProcessHacker/prpgthrd.c @@ -315,6 +315,136 @@ static NTSTATUS NTAPI PhpOpenThreadTokenObject( ); } +static BOOLEAN PhpWordMatchThreadStringRef( + _In_ PPH_STRING SearchText, + _In_ PPH_STRINGREF Text + ) +{ + PH_STRINGREF part; + PH_STRINGREF remainingPart; + + remainingPart = SearchText->sr; + + while (remainingPart.Length) + { + PhSplitStringRefAtChar(&remainingPart, '|', &part, &remainingPart); + + if (part.Length) + { + if (PhFindStringInStringRef(Text, &part, TRUE) != -1) + return TRUE; + } + } + + return FALSE; +} + +static BOOLEAN PhpWordMatchThreadStringZ( + _In_ PPH_STRING SearchText, + _In_ PWSTR Text + ) +{ + PH_STRINGREF text; + + PhInitializeStringRef(&text, Text); + + return PhpWordMatchThreadStringRef(SearchText, &text); +} + +BOOLEAN PhpThreadTreeFilterCallback( + _In_ PPH_TREENEW_NODE Node, + _In_opt_ PPH_THREADS_CONTEXT Context + ) +{ + PPH_THREAD_NODE threadNode = (PPH_THREAD_NODE)Node; + PPH_THREAD_ITEM threadItem = threadNode->ThreadItem; + + if (PhIsNullOrEmptyString(Context->SearchboxText)) + return TRUE; + + // thread properties + + if (threadNode->ThreadIdText[0]) + { + if (PhpWordMatchThreadStringZ(Context->SearchboxText, threadNode->ThreadIdText)) + return TRUE; + } + + if (threadNode->PriorityText[0]) + { + if (PhpWordMatchThreadStringZ(Context->SearchboxText, threadNode->PriorityText)) + return TRUE; + } + + if (threadNode->BasePriorityText[0]) + { + if (PhpWordMatchThreadStringZ(Context->SearchboxText, threadNode->BasePriorityText)) + return TRUE; + } + + if (threadNode->IdealProcessorText[0]) + { + if (PhpWordMatchThreadStringZ(Context->SearchboxText, threadNode->IdealProcessorText)) + return TRUE; + } + + if (threadNode->ThreadIdHexText[0]) + { + if (PhpWordMatchThreadStringZ(Context->SearchboxText, threadNode->ThreadIdHexText)) + return TRUE; + } + + if (!PhIsNullOrEmptyString(threadNode->StartAddressText)) + { + if (PhpWordMatchThreadStringRef(Context->SearchboxText, &threadNode->StartAddressText->sr)) + return TRUE; + } + + if (!PhIsNullOrEmptyString(threadNode->PrioritySymbolicText)) + { + if (PhpWordMatchThreadStringRef(Context->SearchboxText, &threadNode->PrioritySymbolicText->sr)) + return TRUE; + } + + if (!PhIsNullOrEmptyString(threadNode->CreatedText)) + { + if (PhpWordMatchThreadStringRef(Context->SearchboxText, &threadNode->CreatedText->sr)) + return TRUE; + } + + if (!PhIsNullOrEmptyString(threadNode->NameText)) + { + if (PhpWordMatchThreadStringRef(Context->SearchboxText, &threadNode->NameText->sr)) + return TRUE; + } + + if (!PhIsNullOrEmptyString(threadNode->StateText)) + { + if (PhpWordMatchThreadStringRef(Context->SearchboxText, &threadNode->StateText->sr)) + return TRUE; + } + + if (!PhIsNullOrEmptyString(threadNode->ThreadItem->ServiceName)) + { + if (PhpWordMatchThreadStringRef(Context->SearchboxText, &threadNode->ThreadItem->ServiceName->sr)) + return TRUE; + } + + if (!PhIsNullOrEmptyString(threadNode->ThreadItem->StartAddressString)) + { + if (PhpWordMatchThreadStringRef(Context->SearchboxText, &threadNode->ThreadItem->StartAddressString->sr)) + return TRUE; + } + + if (!PhIsNullOrEmptyString(threadNode->ThreadItem->StartAddressFileName)) + { + if (PhpWordMatchThreadStringRef(Context->SearchboxText, &threadNode->ThreadItem->StartAddressFileName->sr)) + return TRUE; + } + + return FALSE; +} + VOID PhShowThreadContextMenu( _In_ HWND hwndDlg, _In_ PPH_PROCESS_ITEM ProcessItem, @@ -445,21 +575,27 @@ INT_PTR CALLBACK PhpProcessThreadsDlgProc( &threadsContext->LoadingStateChangedEventRegistration ); threadsContext->WindowHandle = hwndDlg; + threadsContext->SearchboxHandle = GetDlgItem(hwndDlg, IDC_SEARCH); + + PhCreateSearchControl(hwndDlg, threadsContext->SearchboxHandle, L"Search Threads (Ctrl+K)"); // Initialize the list. tnHandle = GetDlgItem(hwndDlg, IDC_LIST); PhInitializeThreadList(hwndDlg, tnHandle, &threadsContext->ListContext); TreeNew_SetEmptyText(tnHandle, &EmptyThreadsText, 0); PhInitializeProviderEventQueue(&threadsContext->EventQueue, 100); + threadsContext->SearchboxText = PhReferenceEmptyString(); + threadsContext->FilterEntry = PhAddTreeNewFilter(&threadsContext->ListContext.TreeFilterSupport, PhpThreadTreeFilterCallback, threadsContext); + // Use Cycles instead of Context Switches on Vista and above, but only when we can // open the process, since cycle time information requires sufficient access to the - // threads. + // threads. (wj32) { HANDLE processHandle; // We make a distinction between PROCESS_QUERY_INFORMATION and PROCESS_QUERY_LIMITED_INFORMATION since // the latter can be used when opening audiodg.exe even though we can't access its threads using - // THREAD_QUERY_LIMITED_INFORMATION. + // THREAD_QUERY_LIMITED_INFORMATION. (wj32) if (processItem->ProcessId == SYSTEM_IDLE_PROCESS_ID) { @@ -474,7 +610,7 @@ INT_PTR CALLBACK PhpProcessThreadsDlgProc( { threadsContext->ListContext.UseCycleTime = TRUE; - // We can't use cycle time for protected processes (without KProcessHacker). + // We can't use cycle time for protected processes (without KProcessHacker). (wj32) if (processItem->IsProtectedProcess) { threadsContext->ListContext.UseCycleTime = FALSE; @@ -509,6 +645,9 @@ INT_PTR CALLBACK PhpProcessThreadsDlgProc( break; case WM_DESTROY: { + PhRemoveTreeNewFilter(&threadsContext->ListContext.TreeFilterSupport, threadsContext->FilterEntry); + if (threadsContext->SearchboxText) PhDereferenceObject(threadsContext->SearchboxText); + PhEmCallObjectOperation(EmThreadsContextType, threadsContext, EmObjectDelete); PhUnregisterCallback( @@ -557,13 +696,36 @@ INT_PTR CALLBACK PhpProcessThreadsDlgProc( if (dialogItem = PhBeginPropPageLayout(hwndDlg, propPageContext)) { - PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_LIST), dialogItem, PH_ANCHOR_ALL); + PhAddPropPageLayoutItem(hwndDlg, threadsContext->SearchboxHandle, dialogItem, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); + PhAddPropPageLayoutItem(hwndDlg, tnHandle, dialogItem, PH_ANCHOR_ALL); PhEndPropPageLayout(hwndDlg, propPageContext); } } break; case WM_COMMAND: { + switch (GET_WM_COMMAND_CMD(wParam, lParam)) + { + case EN_CHANGE: + { + PPH_STRING newSearchboxText; + + if (GET_WM_COMMAND_HWND(wParam, lParam) != threadsContext->SearchboxHandle) + break; + + newSearchboxText = PH_AUTO(PhGetWindowText(threadsContext->SearchboxHandle)); + + if (!PhEqualString(threadsContext->SearchboxText, newSearchboxText, FALSE)) + { + // Cache the current search text for our callback. + PhSwapReference(&threadsContext->SearchboxText, newSearchboxText); + + PhApplyTreeNewFilters(&threadsContext->ListContext.TreeFilterSupport); + } + } + break; + } + switch (GET_WM_COMMAND_ID(wParam, lParam)) { case ID_SHOWCONTEXTMENU: @@ -915,7 +1077,7 @@ INT_PTR CALLBACK PhpProcessThreadsDlgProc( // Can't disable, it screws up the deltas. break; case PSN_QUERYINITIALFOCUS: - SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, (LPARAM)GetDlgItem(hwndDlg, IDC_LIST)); + SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, (LPARAM)tnHandle); return TRUE; } } diff --git a/ProcessHacker/thrdlist.c b/ProcessHacker/thrdlist.c index 096f9f6182e6..65f7e8d7bd0d 100644 --- a/ProcessHacker/thrdlist.c +++ b/ProcessHacker/thrdlist.c @@ -120,6 +120,8 @@ VOID PhInitializeThreadList( //TreeNew_SetSort(TreeNewHandle, PHTHTLC_CYCLESDELTA, DescendingSortOrder); PhCmInitializeManager(&Context->Cm, TreeNewHandle, PH_THREAD_TREELIST_COLUMN_MAXIMUM, PhpThreadTreeNewPostSortFunction); + + PhInitializeTreeNewFilterSupport(&Context->TreeFilterSupport, Context->TreeNewHandle, Context->NodeList); } VOID PhDeleteThreadList( From 41005d6870f8322a23a1074c68ca936124468be2 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 24 Feb 2019 19:05:27 +0100 Subject: [PATCH 1734/2058] NetworkTools: Update hostname query flags --- plugins/NetworkTools/tracert.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/plugins/NetworkTools/tracert.c b/plugins/NetworkTools/tracert.c index 509b76fee22b..d10d45610323 100644 --- a/plugins/NetworkTools/tracert.c +++ b/plugins/NetworkTools/tracert.c @@ -58,7 +58,8 @@ PPH_STRING PhpGetIp4ReverseNameFromAddress( _In_ IN_ADDR Address ) { - return PhFormatString(L"%u.%u.%u.%u.%s", + return PhFormatString( + L"%hhu.%hhu.%hhu.%hhu.%s", Address.s_impno, Address.s_lh, Address.s_host, @@ -73,13 +74,13 @@ PPH_STRING PhpGetIp6ReverseNameFromAddress( { PH_STRING_BUILDER stringBuilder; - PhInitializeStringBuilder(&stringBuilder, 32); + PhInitializeStringBuilder(&stringBuilder, DNS_MAX_NAME_BUFFER_LENGTH); for (INT i = sizeof(IN6_ADDR) - 1; i >= 0; i--) { PhAppendFormatStringBuilder( &stringBuilder, - L"%x.%x.", + L"%hhx.%hhx.", Address.s6_addr[i] & 0xF, (Address.s6_addr[i] >> 4) & 0xF ); From 76b6e2c944109efb3292408e7377f5c101e723c4 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 3 Mar 2019 01:34:12 +0100 Subject: [PATCH 1735/2058] Update mxml to v3.0 --- phlib/mxml/COPYING | 507 --------- phlib/mxml/LICENSE | 201 ++++ phlib/mxml/config.h | 9 +- phlib/mxml/mxml-attr.c | 32 +- phlib/mxml/mxml-entity.c | 25 +- phlib/mxml/mxml-file.c | 2263 +++++++++++++++++++------------------ phlib/mxml/mxml-get.c | 23 +- phlib/mxml/mxml-index.c | 103 +- phlib/mxml/mxml-node.c | 165 ++- phlib/mxml/mxml-private.c | 17 +- phlib/mxml/mxml-private.h | 73 +- phlib/mxml/mxml-search.c | 29 +- phlib/mxml/mxml-set.c | 77 +- phlib/mxml/mxml-string.c | 372 +++--- phlib/mxml/mxml.h | 164 +-- 15 files changed, 1885 insertions(+), 2175 deletions(-) delete mode 100644 phlib/mxml/COPYING create mode 100644 phlib/mxml/LICENSE diff --git a/phlib/mxml/COPYING b/phlib/mxml/COPYING deleted file mode 100644 index 4d0aa78af224..000000000000 --- a/phlib/mxml/COPYING +++ /dev/null @@ -1,507 +0,0 @@ - Mini-XML License - September 18, 2010 - - -The Mini-XML library and included programs are provided under the -terms of the GNU Library General Public License version 2 (LGPL2) -with the following exceptions: - - 1. Static linking of applications to the Mini-XML library -does not constitute a derivative work and does not require -the author to provide source code for the application, use -the shared Mini-XML libraries, or link their applications -against a user-supplied version of Mini-XML. - -If you link the application to a modified version of -Mini-XML, then the changes to Mini-XML must be provided -under the terms of the LGPL2 in sections 1, 2, and 4. - - 2. You do not have to provide a copy of the Mini-XML license -with programs that are linked to the Mini-XML library, nor -do you have to identify the Mini-XML license in your -program or documentation as required by section 6 of the -LGPL2. - - - GNU LIBRARY GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1991 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - [This is the first released version of the library GPL. It is - numbered 2 because it goes with version 2 of the ordinary GPL.] - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Library General Public License, applies to some -specially designated Free Software Foundation software, and to any -other libraries whose authors decide to use it. You can use it for -your libraries, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if -you distribute copies of the library, or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link a program with the library, you must provide -complete object files to the recipients so that they can relink them -with the library, after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - Our method of protecting your rights has two steps: (1) copyright -the library, and (2) offer you this license which gives you legal -permission to copy, distribute and/or modify the library. - - Also, for each distributor's protection, we want to make certain -that everyone understands that there is no warranty for this free -library. If the library is modified by someone else and passed on, we -want its recipients to know that what they have is not the original -version, so that any problems introduced by others will not reflect on -the original authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that companies distributing free -software will individually obtain patent licenses, thus in effect -transforming the program into proprietary software. To prevent this, -we have made it clear that any patent must be licensed for everyone's -free use or not licensed at all. - - Most GNU software, including some libraries, is covered by the ordinary -GNU General Public License, which was designed for utility programs. This -license, the GNU Library General Public License, applies to certain -designated libraries. This license is quite different from the ordinary -one; be sure to read it in full, and don't assume that anything in it is -the same as in the ordinary license. - - The reason we have a separate public license for some libraries is that -they blur the distinction we usually make between modifying or adding to a -program and simply using it. Linking a program with a library, without -changing the library, is in some sense simply using the library, and is -analogous to running a utility program or application program. However, in -a textual and legal sense, the linked executable is a combined work, a -derivative of the original library, and the ordinary General Public License -treats it as such. - - Because of this blurred distinction, using the ordinary General -Public License for libraries did not effectively promote software -sharing, because most developers did not use the libraries. We -concluded that weaker conditions might promote sharing better. - - However, unrestricted linking of non-free programs would deprive the -users of those programs of all benefit from the free status of the -libraries themselves. This Library General Public License is intended to -permit developers of non-free programs to use free libraries, while -preserving your freedom as a user of such programs to change the free -libraries that are incorporated in them. (We have not seen how to achieve -this as regards changes in header files, but we have achieved it as regards -changes in the actual functions of the Library.) The hope is that this -will lead to faster development of free libraries. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, while the latter only -works together with the library. - - Note that it is possible for a library to be covered by the ordinary -General Public License rather than by this special one. - - GNU LIBRARY GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library which -contains a notice placed by the copyright holder or other authorized -party saying it may be distributed under the terms of this Library -General Public License (also called "this License"). Each licensee is -addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, complete source code means -all the source code for all modules it contains, plus any associated -interface definition files, plus the scripts used to control compilation -and installation of the library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete source code as you receive it, in any medium, provided that -you conspicuously and appropriately publish on each copy an -appropriate copyright notice and disclaimer of warranty; keep intact -all the notices that refer to this License and to the absence of any -warranty; and distribute a copy of this License along with the -Library. - - You may charge a fee for the physical act of transferring a copy, -and you may at your option offer warranty protection in exchange for a -fee. - - 2. You may modify your copy or copies of the Library or any portion -of it, thus forming a work based on the Library, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Library, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote -it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you accompany -it with the complete corresponding machine-readable source code, which -must be distributed under the terms of Sections 1 and 2 above on a -medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy -from a designated place, then offering equivalent access to copy the -source code from the same place satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also compile or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Accompany the work with a written offer, valid for at - least three years, to give the same user the materials - specified in Subsection 6a, above, for a charge no more - than the cost of performing this distribution. - - c) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - d) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the source code distributed need not include anything that is normally -distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies -the executable. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library is void, and will automatically terminate your -rights under this License. However, parties who have received copies, -or rights, from you under this License will not have their licenses -terminated so long as such parties remain in full compliance. - - 9. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -subject to these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 11. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under any -particular circumstance, the balance of the section is intended to apply, -and the section as a whole is intended to apply in other circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library under this License may add -an explicit geographical distribution limitation excluding those countries, -so that distribution is permitted only in or among countries not thus -excluded. In such case, this License incorporates the limitation as if -written in the body of this License. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Library General Public License from time to time. -Such new versions will be similar in spirit to the present version, -but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library -specifies a version number of this License which applies to it and -"any later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -write to the author to ask for permission. For software which is -copyrighted by the Free Software Foundation, write to the Free -Software Foundation; we sometimes make exceptions for this. Our -decision will be guided by the two goals of preserving the free status -of all derivatives of our free software and of promoting the sharing -and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY -KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU -FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR -CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE -LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING -RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A -FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF -SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. - - END OF TERMS AND CONDITIONS - - Appendix: How to Apply These Terms to Your New Libraries - - If you develop a new library, and you want it to be of the greatest -possible use to the public, we recommend making it free software that -everyone can redistribute and change. You can do so by permitting -redistribution under these terms (or, alternatively, under the terms of the -ordinary General Public License). - - To apply these terms, attach the following notices to the library. It is -safest to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least the -"copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this library; if not, write to the Free - Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -Also add information on how to contact you by electronic and paper mail. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the library, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - library `Frob' (a library for tweaking knobs) written by James Random Hacker. - - , 1 April 1990 - Ty Coon, President of Vice - -That's all there is to it! diff --git a/phlib/mxml/LICENSE b/phlib/mxml/LICENSE new file mode 100644 index 000000000000..261eeb9e9f8b --- /dev/null +++ b/phlib/mxml/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/phlib/mxml/config.h b/phlib/mxml/config.h index 038ba6eb7d35..da2fd910e593 100644 --- a/phlib/mxml/config.h +++ b/phlib/mxml/config.h @@ -2,7 +2,7 @@ * Visual Studio configuration file for Mini-XML, a small XML file parsing * library. * - * Copyright 2003-2018 by Michael R Sweet. + * Copyright 2003-2019 by Michael R Sweet. * * These coded instructions, statements, and computer programs are the * property of Michael R Sweet and are protected by Federal copyright @@ -63,7 +63,7 @@ * Version number... */ -#define MXML_VERSION "Mini-XML v2.12" +#define MXML_VERSION "Mini-XML v3.0" /* @@ -113,6 +113,11 @@ extern char *_mxml_strdup(const char *); # define strdup _mxml_strdup # endif /* !HAVE_STRDUP */ +# ifndef HAVE_STRLCAT +extern size_t _mxml_strlcat(char *, const char *, size_t); +# define strlcat _mxml_strlcat +# endif /* !HAVE_STRLCAT */ + # ifndef HAVE_STRLCPY extern size_t _mxml_strlcpy(char *, const char *, size_t); # define strlcpy _mxml_strlcpy diff --git a/phlib/mxml/mxml-attr.c b/phlib/mxml/mxml-attr.c index 88a7a6b8867c..6a1336f76780 100644 --- a/phlib/mxml/mxml-attr.c +++ b/phlib/mxml/mxml-attr.c @@ -1,33 +1,27 @@ /* * Attribute support code for Mini-XML, a small XML file parsing library. * - * Copyright 2003-2017 by Michael R Sweet. + * https://www.msweet.org/mxml * - * These coded instructions, statements, and computer programs are the - * property of Michael R Sweet and are protected by Federal copyright - * law. Distribution and use rights are outlined in the file "COPYING" - * which should have been included with this file. If this file is - * missing or damaged, see the license at: + * Copyright © 2003-2019 by Michael R Sweet. * - * https://michaelrsweet.github.io/mxml + * Licensed under Apache License v2.0. See the file "LICENSE" for more + * information. */ /* * Include necessary headers... */ -#include - #include "config.h" -#include "mxml.h" +#include "mxml-private.h" /* * Local functions... */ -static int mxml_set_attr(mxml_node_t *node, const char *name, - char *value); +static int mxml_set_attr(mxml_node_t *node, const char *name, char *value); /* @@ -41,7 +35,7 @@ mxmlElementDeleteAttr(mxml_node_t *node,/* I - Element */ const char *name)/* I - Attribute name */ { int i; /* Looping var */ - mxml_attr_t *attr; /* Cirrent attribute */ + _mxml_attr_t *attr; /* Cirrent attribute */ #ifdef MXMLDEBUG @@ -79,7 +73,7 @@ mxmlElementDeleteAttr(mxml_node_t *node,/* I - Element */ i --; if (i > 0) - memmove(attr, attr + 1, i * sizeof(mxml_attr_t)); + memmove(attr, attr + 1, i * sizeof(_mxml_attr_t)); node->value.element.num_attrs --; @@ -103,7 +97,7 @@ mxmlElementGetAttr(mxml_node_t *node, /* I - Element node */ const char *name) /* I - Name of attribute */ { int i; /* Looping var */ - mxml_attr_t *attr; /* Cirrent attribute */ + _mxml_attr_t *attr; /* Cirrent attribute */ #ifdef MXMLDEBUG @@ -247,7 +241,7 @@ void mxmlElementSetAttrf(mxml_node_t *node, /* I - Element node */ const char *name, /* I - Name of attribute */ const char *format,/* I - Printf-style attribute value */ - ...) /* I - Additional arguments as needed */ + ...) /* I - Additional arguments as needed */ { va_list ap; /* Argument pointer */ char *value; /* Value */ @@ -292,7 +286,7 @@ mxml_set_attr(mxml_node_t *node, /* I - Element node */ char *value) /* I - Attribute value */ { int i; /* Looping var */ - mxml_attr_t *attr; /* New attribute */ + _mxml_attr_t *attr; /* New attribute */ /* @@ -321,10 +315,10 @@ mxml_set_attr(mxml_node_t *node, /* I - Element node */ */ if (node->value.element.num_attrs == 0) - attr = PhAllocateSafe(sizeof(mxml_attr_t)); + attr = PhAllocateSafe(sizeof(_mxml_attr_t)); else attr = PhReAllocateSafe(node->value.element.attrs, - (node->value.element.num_attrs + 1) * sizeof(mxml_attr_t)); + (node->value.element.num_attrs + 1) * sizeof(_mxml_attr_t)); if (!attr) { diff --git a/phlib/mxml/mxml-entity.c b/phlib/mxml/mxml-entity.c index d4845084b83b..3b17d1e06914 100644 --- a/phlib/mxml/mxml-entity.c +++ b/phlib/mxml/mxml-entity.c @@ -1,15 +1,12 @@ /* * Character entity support code for Mini-XML, a small XML file parsing library. * - * Copyright 2003-2017 by Michael R Sweet. + * https://www.msweet.org/mxml * - * These coded instructions, statements, and computer programs are the - * property of Michael R Sweet and are protected by Federal copyright - * law. Distribution and use rights are outlined in the file "COPYING" - * which should have been included with this file. If this file is - * missing or damaged, see the license at: + * Copyright © 2003-2019 by Michael R Sweet. * - * https://michaelrsweet.github.io/mxml + * Licensed under Apache License v2.0. See the file "LICENSE" for more + * information. */ /* @@ -28,7 +25,7 @@ mxmlEntityAddCallback( mxml_entity_cb_t cb) /* I - Callback function to add */ { _mxml_global_t *global = _mxml_global(); - /* Global data */ + /* Global data */ if (global->num_entity_cbs < (int)(sizeof(global->entity_cbs) / sizeof(global->entity_cbs[0]))) @@ -89,7 +86,7 @@ mxmlEntityGetValue(const char *name) /* I - Entity name */ int i; /* Looping var */ int ch; /* Character value */ _mxml_global_t *global = _mxml_global(); - /* Global data */ + /* Global data */ for (i = 0; i < global->num_entity_cbs; i ++) @@ -110,7 +107,7 @@ mxmlEntityRemoveCallback( { int i; /* Looping var */ _mxml_global_t *global = _mxml_global(); - /* Global data */ + /* Global data */ for (i = 0; i < global->num_entity_cbs; i ++) @@ -124,7 +121,7 @@ mxmlEntityRemoveCallback( if (i < global->num_entity_cbs) memmove(global->entity_cbs + i, global->entity_cbs + i + 1, - (global->num_entity_cbs - i) * sizeof(global->entity_cbs[0])); + (global->num_entity_cbs - i) * sizeof(global->entity_cbs[0])); return; } @@ -139,9 +136,9 @@ int /* O - Unicode value or -1 */ _mxml_entity_cb(const char *name) /* I - Entity name */ { int diff, /* Difference between names */ - current, /* Current entity in search */ - first, /* First entity in search */ - last; /* Last entity in search */ + current, /* Current entity in search */ + first, /* First entity in search */ + last; /* Last entity in search */ static const struct { const char *name; /* Entity name */ diff --git a/phlib/mxml/mxml-file.c b/phlib/mxml/mxml-file.c index 86624a5c7be9..4599506c209e 100644 --- a/phlib/mxml/mxml-file.c +++ b/phlib/mxml/mxml-file.c @@ -1,27 +1,21 @@ /* * File loading code for Mini-XML, a small XML file parsing library. * - * Copyright 2003-2018 by Michael R Sweet. + * https://www.msweet.org/mxml * - * These coded instructions, statements, and computer programs are the - * property of Michael R Sweet and are protected by Federal copyright - * law. Distribution and use rights are outlined in the file "COPYING" - * which should have been included with this file. If this file is - * missing or damaged, see the license at: + * Copyright © 2003-2019 by Michael R Sweet. * - * https://michaelrsweet.github.io/mxml + * Licensed under Apache License v2.0. See the file "LICENSE" for more + * information. */ /* * Include necessary headers... */ - /* dmex: modified to use file handles */ -#include - #ifndef _WIN32 # include -#endif /* !WIN32 */ +#endif /* !_WIN32 */ #include "mxml-private.h" @@ -52,8 +46,8 @@ typedef struct _mxml_fdbuf_s /**** File descriptor buffer ****/ { HANDLE fd; /* File descriptor */ unsigned char *current, /* Current position in buffer */ - *end, /* End of buffer */ - buffer[8192]; /* Character buffer */ + *end, /* End of buffer */ + buffer[8192]; /* Character buffer */ } _mxml_fdbuf_t; @@ -61,42 +55,26 @@ typedef struct _mxml_fdbuf_s /**** File descriptor buffer ****/ * Local functions... */ -static int mxml_add_char(int ch, char **ptr, char **buffer, - int *bufsize); +static int mxml_add_char(int ch, char **ptr, char **buffer, int *bufsize); static int mxml_fd_getc(void *p, int *encoding); static int mxml_fd_putc(int ch, void *p); static int mxml_fd_read(_mxml_fdbuf_t *buf); static int mxml_fd_write(_mxml_fdbuf_t *buf); static int mxml_file_getc(void *p, int *encoding); static int mxml_file_putc(int ch, void *p); -static int mxml_get_entity(mxml_node_t *parent, void *p, - int *encoding, - _mxml_getc_cb_t getc_cb); +static int mxml_get_entity(mxml_node_t *parent, void *p, int *encoding, _mxml_getc_cb_t getc_cb, int *line); static inline int mxml_isspace(int ch) - { - return (ch == ' ' || ch == '\t' || ch == '\r' || - ch == '\n'); - } -static mxml_node_t *mxml_load_data(mxml_node_t *top, void *p, - mxml_load_cb_t cb, - _mxml_getc_cb_t getc_cb, - mxml_sax_cb_t sax_cb, void *sax_data); -static int mxml_parse_element(mxml_node_t *node, void *p, - int *encoding, - _mxml_getc_cb_t getc_cb); + { + return (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n'); + } +static mxml_node_t *mxml_load_data(mxml_node_t *top, void *p, mxml_load_cb_t cb, _mxml_getc_cb_t getc_cb, mxml_sax_cb_t sax_cb, void *sax_data); +static int mxml_parse_element(mxml_node_t *node, void *p, int *encoding, _mxml_getc_cb_t getc_cb, int *line); static int mxml_string_getc(void *p, int *encoding); static int mxml_string_putc(int ch, void *p); -static int mxml_write_name(const char *s, void *p, - _mxml_putc_cb_t putc_cb); -static int mxml_write_node(mxml_node_t *node, void *p, - mxml_save_cb_t cb, int col, - _mxml_putc_cb_t putc_cb, - _mxml_global_t *global); -static int mxml_write_string(const char *s, void *p, - _mxml_putc_cb_t putc_cb); -static int mxml_write_ws(mxml_node_t *node, void *p, - mxml_save_cb_t cb, int ws, - int col, _mxml_putc_cb_t putc_cb); +static int mxml_write_name(const char *s, void *p, _mxml_putc_cb_t putc_cb); +static int mxml_write_node(mxml_node_t *node, void *p, mxml_save_cb_t cb, int col, _mxml_putc_cb_t putc_cb, _mxml_global_t *global); +static int mxml_write_string(const char *s, void *p, _mxml_putc_cb_t putc_cb); +static int mxml_write_ws(mxml_node_t *node, void *p, mxml_save_cb_t cb, int ws, int col, _mxml_putc_cb_t putc_cb); /* @@ -280,12 +258,12 @@ mxmlSaveAllocString( int /* O - 0 on success, -1 on error. */ mxmlSaveFd(mxml_node_t *node, /* I - Node to write */ HANDLE fd, /* I - File descriptor to write to */ - mxml_save_cb_t cb) /* I - Whitespace callback or @code MXML_NO_CALLBACK@ */ + mxml_save_cb_t cb) /* I - Whitespace callback or @code MXML_NO_CALLBACK@ */ { int col; /* Final column */ _mxml_fdbuf_t buf; /* File descriptor buffer */ _mxml_global_t *global = _mxml_global(); - /* Global data */ + /* Global data */ /* @@ -328,11 +306,11 @@ mxmlSaveFd(mxml_node_t *node, /* I - Node to write */ int /* O - 0 on success, -1 on error. */ mxmlSaveFile(mxml_node_t *node, /* I - Node to write */ FILE *fp, /* I - File to write to */ - mxml_save_cb_t cb) /* I - Whitespace callback or @code MXML_NO_CALLBACK@ */ + mxml_save_cb_t cb) /* I - Whitespace callback or @code MXML_NO_CALLBACK@ */ { int col; /* Final column */ _mxml_global_t *global = _mxml_global(); - /* Global data */ + /* Global data */ /* @@ -377,7 +355,7 @@ mxmlSaveString(mxml_node_t *node, /* I - Node to write */ int col; /* Final column */ char *ptr[2]; /* Pointers for putc_cb */ _mxml_global_t *global = _mxml_global(); - /* Global data */ + /* Global data */ /* @@ -542,7 +520,7 @@ mxmlSetCustomHandlers( mxml_custom_save_cb_t save) /* I - Save function */ { _mxml_global_t *global = _mxml_global(); - /* Global data */ + /* Global data */ global->custom_load_cb = load; @@ -558,7 +536,7 @@ void mxmlSetErrorCallback(mxml_error_cb_t cb)/* I - Error callback function */ { _mxml_global_t *global = _mxml_global(); - /* Global data */ + /* Global data */ global->error_cb = cb; @@ -577,7 +555,7 @@ void mxmlSetWrapMargin(int column) /* I - Column for wrapping, 0 to disable wrapping */ { _mxml_global_t *global = _mxml_global(); - /* Global data */ + /* Global data */ global->wrap = column; @@ -591,8 +569,8 @@ mxmlSetWrapMargin(int column) /* I - Column for wrapping, 0 to disable wrapping static int /* O - 0 on success, -1 on error */ mxml_add_char(int ch, /* I - Character to add */ char **bufptr, /* IO - Current position in buffer */ - char **buffer, /* IO - Current buffer */ - int *bufsize) /* IO - Current buffer size */ + char **buffer, /* IO - Current buffer */ + int *bufsize) /* IO - Current buffer size */ { char *newbuffer; /* New buffer value */ @@ -674,7 +652,7 @@ mxml_fd_getc(void *p, /* I - File descriptor buffer */ { _mxml_fdbuf_t *buf; /* File descriptor buffer */ int ch, /* Current character */ - temp; /* Temporary character */ + temp; /* Temporary character */ /* @@ -693,270 +671,270 @@ mxml_fd_getc(void *p, /* I - File descriptor buffer */ { case ENCODE_UTF8 : /* - * Got a UTF-8 character; convert UTF-8 to Unicode and return... - */ + * Got a UTF-8 character; convert UTF-8 to Unicode and return... + */ - if (!(ch & 0x80)) - { + if (!(ch & 0x80)) + { #if DEBUG > 1 printf("mxml_fd_getc: %c (0x%04x)\n", ch < ' ' ? '.' : ch, ch); #endif /* DEBUG > 1 */ - if (mxml_bad_char(ch)) - { - mxml_error("Bad control character 0x%02x not allowed by XML standard!", - ch); - return (EOF); - } + if (mxml_bad_char(ch)) + { + mxml_error("Bad control character 0x%02x not allowed by XML standard!", + ch); + return (EOF); + } - return (ch); + return (ch); } - else if (ch == 0xfe) - { - /* - * UTF-16 big-endian BOM? - */ + else if (ch == 0xfe) + { + /* + * UTF-16 big-endian BOM? + */ - if (buf->current >= buf->end) - if (mxml_fd_read(buf) < 0) - return (EOF); + if (buf->current >= buf->end) + if (mxml_fd_read(buf) < 0) + return (EOF); - ch = *(buf->current)++; + ch = *(buf->current)++; - if (ch != 0xff) - return (EOF); + if (ch != 0xff) + return (EOF); - *encoding = ENCODE_UTF16BE; + *encoding = ENCODE_UTF16BE; - return (mxml_fd_getc(p, encoding)); - } - else if (ch == 0xff) - { - /* - * UTF-16 little-endian BOM? - */ + return (mxml_fd_getc(p, encoding)); + } + else if (ch == 0xff) + { + /* + * UTF-16 little-endian BOM? + */ - if (buf->current >= buf->end) - if (mxml_fd_read(buf) < 0) - return (EOF); + if (buf->current >= buf->end) + if (mxml_fd_read(buf) < 0) + return (EOF); - ch = *(buf->current)++; + ch = *(buf->current)++; - if (ch != 0xfe) - return (EOF); + if (ch != 0xfe) + return (EOF); - *encoding = ENCODE_UTF16LE; + *encoding = ENCODE_UTF16LE; - return (mxml_fd_getc(p, encoding)); - } - else if ((ch & 0xe0) == 0xc0) - { - /* - * Two-byte value... - */ + return (mxml_fd_getc(p, encoding)); + } + else if ((ch & 0xe0) == 0xc0) + { + /* + * Two-byte value... + */ - if (buf->current >= buf->end) - if (mxml_fd_read(buf) < 0) - return (EOF); + if (buf->current >= buf->end) + if (mxml_fd_read(buf) < 0) + return (EOF); - temp = *(buf->current)++; + temp = *(buf->current)++; - if ((temp & 0xc0) != 0x80) - return (EOF); + if ((temp & 0xc0) != 0x80) + return (EOF); - ch = ((ch & 0x1f) << 6) | (temp & 0x3f); + ch = ((ch & 0x1f) << 6) | (temp & 0x3f); - if (ch < 0x80) - { - mxml_error("Invalid UTF-8 sequence for character 0x%04x!", ch); - return (EOF); - } - } - else if ((ch & 0xf0) == 0xe0) - { - /* - * Three-byte value... - */ + if (ch < 0x80) + { + mxml_error("Invalid UTF-8 sequence for character 0x%04x!", ch); + return (EOF); + } + } + else if ((ch & 0xf0) == 0xe0) + { + /* + * Three-byte value... + */ - if (buf->current >= buf->end) - if (mxml_fd_read(buf) < 0) - return (EOF); + if (buf->current >= buf->end) + if (mxml_fd_read(buf) < 0) + return (EOF); - temp = *(buf->current)++; + temp = *(buf->current)++; - if ((temp & 0xc0) != 0x80) - return (EOF); + if ((temp & 0xc0) != 0x80) + return (EOF); - ch = ((ch & 0x0f) << 6) | (temp & 0x3f); + ch = ((ch & 0x0f) << 6) | (temp & 0x3f); - if (buf->current >= buf->end) - if (mxml_fd_read(buf) < 0) - return (EOF); + if (buf->current >= buf->end) + if (mxml_fd_read(buf) < 0) + return (EOF); - temp = *(buf->current)++; + temp = *(buf->current)++; - if ((temp & 0xc0) != 0x80) - return (EOF); + if ((temp & 0xc0) != 0x80) + return (EOF); - ch = (ch << 6) | (temp & 0x3f); + ch = (ch << 6) | (temp & 0x3f); - if (ch < 0x800) - { - mxml_error("Invalid UTF-8 sequence for character 0x%04x!", ch); - return (EOF); - } + if (ch < 0x800) + { + mxml_error("Invalid UTF-8 sequence for character 0x%04x!", ch); + return (EOF); + } /* - * Ignore (strip) Byte Order Mark (BOM)... - */ + * Ignore (strip) Byte Order Mark (BOM)... + */ - if (ch == 0xfeff) - return (mxml_fd_getc(p, encoding)); - } - else if ((ch & 0xf8) == 0xf0) - { - /* - * Four-byte value... - */ + if (ch == 0xfeff) + return (mxml_fd_getc(p, encoding)); + } + else if ((ch & 0xf8) == 0xf0) + { + /* + * Four-byte value... + */ - if (buf->current >= buf->end) - if (mxml_fd_read(buf) < 0) - return (EOF); + if (buf->current >= buf->end) + if (mxml_fd_read(buf) < 0) + return (EOF); - temp = *(buf->current)++; + temp = *(buf->current)++; - if ((temp & 0xc0) != 0x80) - return (EOF); + if ((temp & 0xc0) != 0x80) + return (EOF); - ch = ((ch & 0x07) << 6) | (temp & 0x3f); + ch = ((ch & 0x07) << 6) | (temp & 0x3f); - if (buf->current >= buf->end) - if (mxml_fd_read(buf) < 0) - return (EOF); + if (buf->current >= buf->end) + if (mxml_fd_read(buf) < 0) + return (EOF); - temp = *(buf->current)++; + temp = *(buf->current)++; - if ((temp & 0xc0) != 0x80) - return (EOF); + if ((temp & 0xc0) != 0x80) + return (EOF); - ch = (ch << 6) | (temp & 0x3f); + ch = (ch << 6) | (temp & 0x3f); - if (buf->current >= buf->end) - if (mxml_fd_read(buf) < 0) - return (EOF); + if (buf->current >= buf->end) + if (mxml_fd_read(buf) < 0) + return (EOF); - temp = *(buf->current)++; + temp = *(buf->current)++; - if ((temp & 0xc0) != 0x80) - return (EOF); + if ((temp & 0xc0) != 0x80) + return (EOF); - ch = (ch << 6) | (temp & 0x3f); + ch = (ch << 6) | (temp & 0x3f); - if (ch < 0x10000) - { - mxml_error("Invalid UTF-8 sequence for character 0x%04x!", ch); - return (EOF); - } - } - else - return (EOF); - break; + if (ch < 0x10000) + { + mxml_error("Invalid UTF-8 sequence for character 0x%04x!", ch); + return (EOF); + } + } + else + return (EOF); + break; case ENCODE_UTF16BE : /* * Read UTF-16 big-endian char... - */ + */ - if (buf->current >= buf->end) - if (mxml_fd_read(buf) < 0) - return (EOF); + if (buf->current >= buf->end) + if (mxml_fd_read(buf) < 0) + return (EOF); - temp = *(buf->current)++; + temp = *(buf->current)++; - ch = (ch << 8) | temp; + ch = (ch << 8) | temp; - if (mxml_bad_char(ch)) - { - mxml_error("Bad control character 0x%02x not allowed by XML standard!", - ch); - return (EOF); - } + if (mxml_bad_char(ch)) + { + mxml_error("Bad control character 0x%02x not allowed by XML standard!", + ch); + return (EOF); + } else if (ch >= 0xd800 && ch <= 0xdbff) - { - /* - * Multi-word UTF-16 char... - */ + { + /* + * Multi-word UTF-16 char... + */ int lch; - if (buf->current >= buf->end) - if (mxml_fd_read(buf) < 0) - return (EOF); + if (buf->current >= buf->end) + if (mxml_fd_read(buf) < 0) + return (EOF); - lch = *(buf->current)++; + lch = *(buf->current)++; - if (buf->current >= buf->end) - if (mxml_fd_read(buf) < 0) - return (EOF); + if (buf->current >= buf->end) + if (mxml_fd_read(buf) < 0) + return (EOF); - temp = *(buf->current)++; + temp = *(buf->current)++; - lch = (lch << 8) | temp; + lch = (lch << 8) | temp; if (lch < 0xdc00 || lch >= 0xdfff) - return (EOF); + return (EOF); ch = (((ch & 0x3ff) << 10) | (lch & 0x3ff)) + 0x10000; - } - break; + } + break; case ENCODE_UTF16LE : /* * Read UTF-16 little-endian char... - */ + */ - if (buf->current >= buf->end) - if (mxml_fd_read(buf) < 0) - return (EOF); + if (buf->current >= buf->end) + if (mxml_fd_read(buf) < 0) + return (EOF); - temp = *(buf->current)++; + temp = *(buf->current)++; - ch |= (temp << 8); + ch |= (temp << 8); if (mxml_bad_char(ch)) - { - mxml_error("Bad control character 0x%02x not allowed by XML standard!", - ch); - return (EOF); - } + { + mxml_error("Bad control character 0x%02x not allowed by XML standard!", + ch); + return (EOF); + } else if (ch >= 0xd800 && ch <= 0xdbff) - { - /* - * Multi-word UTF-16 char... - */ + { + /* + * Multi-word UTF-16 char... + */ int lch; - if (buf->current >= buf->end) - if (mxml_fd_read(buf) < 0) - return (EOF); + if (buf->current >= buf->end) + if (mxml_fd_read(buf) < 0) + return (EOF); - lch = *(buf->current)++; + lch = *(buf->current)++; - if (buf->current >= buf->end) - if (mxml_fd_read(buf) < 0) - return (EOF); + if (buf->current >= buf->end) + if (mxml_fd_read(buf) < 0) + return (EOF); - temp = *(buf->current)++; + temp = *(buf->current)++; - lch |= (temp << 8); + lch |= (temp << 8); if (lch < 0xdc00 || lch >= 0xdfff) - return (EOF); + return (EOF); ch = (((ch & 0x3ff) << 10) | (lch & 0x3ff)) + 0x10000; - } - break; + } + break; } #if DEBUG > 1 @@ -1056,7 +1034,7 @@ mxml_file_getc(void *p, /* I - Pointer to file */ int *encoding) /* IO - Encoding */ { int ch, /* Character from file */ - temp; /* Temporary character */ + temp; /* Temporary character */ FILE *fp; /* Pointer to file */ @@ -1074,186 +1052,186 @@ mxml_file_getc(void *p, /* I - Pointer to file */ { case ENCODE_UTF8 : /* - * Got a UTF-8 character; convert UTF-8 to Unicode and return... - */ - - if (!(ch & 0x80)) - { - if (mxml_bad_char(ch)) - { - mxml_error("Bad control character 0x%02x not allowed by XML standard!", - ch); - return (EOF); - } + * Got a UTF-8 character; convert UTF-8 to Unicode and return... + */ + + if (!(ch & 0x80)) + { + if (mxml_bad_char(ch)) + { + mxml_error("Bad control character 0x%02x not allowed by XML standard!", + ch); + return (EOF); + } #if DEBUG > 1 printf("mxml_file_getc: %c (0x%04x)\n", ch < ' ' ? '.' : ch, ch); #endif /* DEBUG > 1 */ - return (ch); + return (ch); } - else if (ch == 0xfe) - { - /* - * UTF-16 big-endian BOM? - */ + else if (ch == 0xfe) + { + /* + * UTF-16 big-endian BOM? + */ ch = getc(fp); - if (ch != 0xff) - return (EOF); + if (ch != 0xff) + return (EOF); - *encoding = ENCODE_UTF16BE; + *encoding = ENCODE_UTF16BE; - return (mxml_file_getc(p, encoding)); - } - else if (ch == 0xff) - { - /* - * UTF-16 little-endian BOM? - */ + return (mxml_file_getc(p, encoding)); + } + else if (ch == 0xff) + { + /* + * UTF-16 little-endian BOM? + */ ch = getc(fp); - if (ch != 0xfe) - return (EOF); + if (ch != 0xfe) + return (EOF); - *encoding = ENCODE_UTF16LE; + *encoding = ENCODE_UTF16LE; - return (mxml_file_getc(p, encoding)); - } - else if ((ch & 0xe0) == 0xc0) - { - /* - * Two-byte value... - */ + return (mxml_file_getc(p, encoding)); + } + else if ((ch & 0xe0) == 0xc0) + { + /* + * Two-byte value... + */ - if ((temp = getc(fp)) == EOF || (temp & 0xc0) != 0x80) - return (EOF); + if ((temp = getc(fp)) == EOF || (temp & 0xc0) != 0x80) + return (EOF); - ch = ((ch & 0x1f) << 6) | (temp & 0x3f); + ch = ((ch & 0x1f) << 6) | (temp & 0x3f); - if (ch < 0x80) - { - mxml_error("Invalid UTF-8 sequence for character 0x%04x!", ch); - return (EOF); - } - } - else if ((ch & 0xf0) == 0xe0) - { - /* - * Three-byte value... - */ + if (ch < 0x80) + { + mxml_error("Invalid UTF-8 sequence for character 0x%04x!", ch); + return (EOF); + } + } + else if ((ch & 0xf0) == 0xe0) + { + /* + * Three-byte value... + */ - if ((temp = getc(fp)) == EOF || (temp & 0xc0) != 0x80) - return (EOF); + if ((temp = getc(fp)) == EOF || (temp & 0xc0) != 0x80) + return (EOF); - ch = ((ch & 0x0f) << 6) | (temp & 0x3f); + ch = ((ch & 0x0f) << 6) | (temp & 0x3f); - if ((temp = getc(fp)) == EOF || (temp & 0xc0) != 0x80) - return (EOF); + if ((temp = getc(fp)) == EOF || (temp & 0xc0) != 0x80) + return (EOF); - ch = (ch << 6) | (temp & 0x3f); + ch = (ch << 6) | (temp & 0x3f); - if (ch < 0x800) - { - mxml_error("Invalid UTF-8 sequence for character 0x%04x!", ch); - return (EOF); - } + if (ch < 0x800) + { + mxml_error("Invalid UTF-8 sequence for character 0x%04x!", ch); + return (EOF); + } /* - * Ignore (strip) Byte Order Mark (BOM)... - */ + * Ignore (strip) Byte Order Mark (BOM)... + */ - if (ch == 0xfeff) - return (mxml_file_getc(p, encoding)); - } - else if ((ch & 0xf8) == 0xf0) - { - /* - * Four-byte value... - */ + if (ch == 0xfeff) + return (mxml_file_getc(p, encoding)); + } + else if ((ch & 0xf8) == 0xf0) + { + /* + * Four-byte value... + */ - if ((temp = getc(fp)) == EOF || (temp & 0xc0) != 0x80) - return (EOF); + if ((temp = getc(fp)) == EOF || (temp & 0xc0) != 0x80) + return (EOF); - ch = ((ch & 0x07) << 6) | (temp & 0x3f); + ch = ((ch & 0x07) << 6) | (temp & 0x3f); - if ((temp = getc(fp)) == EOF || (temp & 0xc0) != 0x80) - return (EOF); + if ((temp = getc(fp)) == EOF || (temp & 0xc0) != 0x80) + return (EOF); - ch = (ch << 6) | (temp & 0x3f); + ch = (ch << 6) | (temp & 0x3f); - if ((temp = getc(fp)) == EOF || (temp & 0xc0) != 0x80) - return (EOF); + if ((temp = getc(fp)) == EOF || (temp & 0xc0) != 0x80) + return (EOF); - ch = (ch << 6) | (temp & 0x3f); + ch = (ch << 6) | (temp & 0x3f); - if (ch < 0x10000) - { - mxml_error("Invalid UTF-8 sequence for character 0x%04x!", ch); - return (EOF); - } - } - else - return (EOF); - break; + if (ch < 0x10000) + { + mxml_error("Invalid UTF-8 sequence for character 0x%04x!", ch); + return (EOF); + } + } + else + return (EOF); + break; case ENCODE_UTF16BE : /* * Read UTF-16 big-endian char... - */ + */ - ch = (ch << 8) | getc(fp); + ch = (ch << 8) | getc(fp); - if (mxml_bad_char(ch)) - { - mxml_error("Bad control character 0x%02x not allowed by XML standard!", - ch); - return (EOF); - } + if (mxml_bad_char(ch)) + { + mxml_error("Bad control character 0x%02x not allowed by XML standard!", + ch); + return (EOF); + } else if (ch >= 0xd800 && ch <= 0xdbff) - { - /* - * Multi-word UTF-16 char... - */ + { + /* + * Multi-word UTF-16 char... + */ int lch = getc(fp); lch = (lch << 8) | getc(fp); if (lch < 0xdc00 || lch >= 0xdfff) - return (EOF); + return (EOF); ch = (((ch & 0x3ff) << 10) | (lch & 0x3ff)) + 0x10000; - } - break; + } + break; case ENCODE_UTF16LE : /* * Read UTF-16 little-endian char... - */ + */ - ch |= (getc(fp) << 8); + ch |= (getc(fp) << 8); if (mxml_bad_char(ch)) - { - mxml_error("Bad control character 0x%02x not allowed by XML standard!", - ch); - return (EOF); - } + { + mxml_error("Bad control character 0x%02x not allowed by XML standard!", + ch); + return (EOF); + } else if (ch >= 0xd800 && ch <= 0xdbff) - { - /* - * Multi-word UTF-16 char... - */ + { + /* + * Multi-word UTF-16 char... + */ int lch = getc(fp); lch |= (getc(fp) << 8); if (lch < 0xdc00 || lch >= 0xdfff) - return (EOF); + return (EOF); ch = (((ch & 0x3ff) << 10) | (lch & 0x3ff)) + 0x10000; - } - break; + } + break; } #if DEBUG > 1 @@ -1282,36 +1260,41 @@ mxml_file_putc(int ch, /* I - Character to write */ static int /* O - Character value or EOF on error */ mxml_get_entity(mxml_node_t *parent, /* I - Parent node */ - void *p, /* I - Pointer to source */ - int *encoding, /* IO - Character encoding */ - int (*getc_cb)(void *, int *)) - /* I - Get character function */ + void *p, /* I - Pointer to source */ + int *encoding, /* IO - Character encoding */ + int (*getc_cb)(void *, int *), + /* I - Get character function */ + int *line) /* IO - Current line number */ { int ch; /* Current character */ char entity[64], /* Entity string */ - *entptr; /* Pointer into entity */ + *entptr; /* Pointer into entity */ entptr = entity; while ((ch = (*getc_cb)(p, encoding)) != EOF) + { if (ch > 126 || (!isalnum(ch) && ch != '#')) break; else if (entptr < (entity + sizeof(entity) - 1)) *entptr++ = ch; else { - mxml_error("Entity name too long under parent <%s>!", - parent ? parent->value.element.name : "null"); + mxml_error("Entity name too long under parent <%s> on line %d.", parent ? parent->value.element.name : "null", *line); break; } + } *entptr = '\0'; if (ch != ';') { - mxml_error("Character entity \"%s\" not terminated under parent <%s>!", - entity, parent ? parent->value.element.name : "null"); + mxml_error("Character entity '%s' not terminated under parent <%s> on line %d.", entity, parent ? parent->value.element.name : "null", *line); + + if (ch == '\n') + (*line)++; + return (EOF); } @@ -1323,13 +1306,11 @@ mxml_get_entity(mxml_node_t *parent, /* I - Parent node */ ch = (int)strtol(entity + 1, NULL, 10); } else if ((ch = mxmlEntityGetValue(entity)) < 0) - mxml_error("Entity name \"%s;\" not supported under parent <%s>!", - entity, parent ? parent->value.element.name : "null"); + mxml_error("Entity name '%s;' not supported under parent <%s> on line %d.", entity, parent ? parent->value.element.name : "null", *line); if (mxml_bad_char(ch)) { - mxml_error("Bad control character 0x%02x under parent <%s> not allowed by XML standard!", - ch, parent ? parent->value.element.name : "null"); + mxml_error("Bad control character 0x%02x under parent <%s> on line %d not allowed by XML standard.", ch, parent ? parent->value.element.name : "null", *line); return (EOF); } @@ -1351,26 +1332,27 @@ mxml_load_data( void *sax_data) /* I - SAX user data */ { mxml_node_t *node, /* Current node */ - *first, /* First node added */ - *parent; /* Current parent node */ - int ch, /* Character from file */ - whitespace; /* Non-zero if whitespace seen */ + *first, /* First node added */ + *parent; /* Current parent node */ + int line = 1, /* Current line number */ + ch, /* Character from file */ + whitespace; /* Non-zero if whitespace seen */ char *buffer, /* String buffer */ - *bufptr; /* Pointer into buffer */ + *bufptr; /* Pointer into buffer */ int bufsize; /* Size of buffer */ mxml_type_t type; /* Current node type */ int encoding; /* Character encoding */ _mxml_global_t *global = _mxml_global(); - /* Global data */ + /* Global data */ static const char * const types[] = /* Type strings... */ - { - "MXML_ELEMENT", /* XML element with attributes */ - "MXML_INTEGER", /* Integer value */ - "MXML_OPAQUE", /* Opaque string */ - "MXML_REAL", /* Real value */ - "MXML_TEXT", /* Text fragment */ - "MXML_CUSTOM" /* Custom data */ - }; + { + "MXML_ELEMENT", /* XML element with attributes */ + "MXML_INTEGER", /* Integer value */ + "MXML_OPAQUE", /* Opaque string */ + "MXML_REAL", /* Real value */ + "MXML_TEXT", /* Text fragment */ + "MXML_CUSTOM" /* Custom data */ + }; /* @@ -1411,56 +1393,53 @@ mxml_load_data( switch (type) { - case MXML_INTEGER : + case MXML_INTEGER : node = mxmlNewInteger(parent, (int)strtol(buffer, &bufptr, 0)); - break; + break; - case MXML_OPAQUE : + case MXML_OPAQUE : node = mxmlNewOpaque(parent, buffer); - break; + break; - case MXML_REAL : + case MXML_REAL : node = mxmlNewReal(parent, strtod(buffer, &bufptr)); - break; + break; - case MXML_TEXT : + case MXML_TEXT : node = mxmlNewText(parent, whitespace, buffer); - break; + break; - case MXML_CUSTOM : - if (global->custom_load_cb) - { - /* - * Use the callback to fill in the custom data... - */ + case MXML_CUSTOM : + if (global->custom_load_cb) + { + /* + * Use the callback to fill in the custom data... + */ node = mxmlNewCustom(parent, NULL, NULL); - if ((*global->custom_load_cb)(node, buffer)) - { - mxml_error("Bad custom value '%s' in parent <%s>!", - buffer, parent ? parent->value.element.name : "null"); - mxmlDelete(node); - node = NULL; - } - break; - } + if ((*global->custom_load_cb)(node, buffer)) + { + mxml_error("Bad custom value '%s' in parent <%s> on line %d.", buffer, parent ? parent->value.element.name : "null", line); + mxmlDelete(node); + node = NULL; + } + break; + } default : /* Ignore... */ - node = NULL; - break; + node = NULL; + break; } if (*bufptr) { /* * Bad integer/real number value... - */ + */ - mxml_error("Bad %s value '%s' in parent <%s>!", - type == MXML_INTEGER ? "integer" : "real", buffer, - parent ? parent->value.element.name : "null"); - break; + mxml_error("Bad %s value '%s' in parent <%s> on line %d.", type == MXML_INTEGER ? "integer" : "real", buffer, parent ? parent->value.element.name : "null", line); + break; } bufptr = buffer; @@ -1469,12 +1448,11 @@ mxml_load_data( if (!node && type != MXML_IGNORE) { /* - * Print error and return... - */ + * Print error and return... + */ - mxml_error("Unable to add value node of type %s to parent <%s>!", - types[type], parent ? parent->value.element.name : "null"); - goto error; + mxml_error("Unable to add value node of type %s to parent <%s> on line %d.", types[type], parent ? parent->value.element.name : "null", line); + goto error; } if (sax_cb) @@ -1491,6 +1469,9 @@ mxml_load_data( else if (mxml_isspace(ch) && type == MXML_TEXT) whitespace = 1; + if (ch == '\n') + line ++; + /* * Add lone whitespace node if we have an element and existing * whitespace... @@ -1500,18 +1481,18 @@ mxml_load_data( { if (parent) { - node = mxmlNewText(parent, whitespace, ""); + node = mxmlNewText(parent, whitespace, ""); - if (sax_cb) - { - (*sax_cb)(node, MXML_SAX_DATA, sax_data); + if (sax_cb) + { + (*sax_cb)(node, MXML_SAX_DATA, sax_data); - if (!mxmlRelease(node)) - node = NULL; - } + if (!mxmlRelease(node)) + node = NULL; + } - if (!first && node) - first = node; + if (!first && node) + first = node; } whitespace = 0; @@ -1526,29 +1507,34 @@ mxml_load_data( bufptr = buffer; while ((ch = (*getc_cb)(p, &encoding)) != EOF) + { if (mxml_isspace(ch) || ch == '>' || (ch == '/' && bufptr > buffer)) - break; - else if (ch == '<') - { - mxml_error("Bare < in element!"); - goto error; - } - else if (ch == '&') - { - if ((ch = mxml_get_entity(parent, p, &encoding, getc_cb)) == EOF) - goto error; - - if (mxml_add_char(ch, &bufptr, &buffer, &bufsize)) - goto error; - } - else if (ch < '0' && ch != '!' && ch != '-' && ch != '.' && ch != '/') - goto error; - else if (mxml_add_char(ch, &bufptr, &buffer, &bufsize)) - goto error; - else if (((bufptr - buffer) == 1 && buffer[0] == '?') || - ((bufptr - buffer) == 3 && !strncmp(buffer, "!--", 3)) || - ((bufptr - buffer) == 8 && !strncmp(buffer, "![CDATA[", 8))) - break; + break; + else if (ch == '<') + { + mxml_error("Bare < in element!"); + goto error; + } + else if (ch == '&') + { + if ((ch = mxml_get_entity(parent, p, &encoding, getc_cb, &line)) == EOF) + goto error; + + if (mxml_add_char(ch, &bufptr, &buffer, &bufsize)) + goto error; + } + else if (ch < '0' && ch != '!' && ch != '-' && ch != '.' && ch != '/') + goto error; + else if (mxml_add_char(ch, &bufptr, &buffer, &bufsize)) + goto error; + else if (((bufptr - buffer) == 1 && buffer[0] == '?') || + ((bufptr - buffer) == 3 && !strncmp(buffer, "!--", 3)) || + ((bufptr - buffer) == 8 && !strncmp(buffer, "![CDATA[", 8))) + break; + + if (ch == '\n') + line ++; + } *bufptr = '\0'; @@ -1556,59 +1542,60 @@ mxml_load_data( { /* * Gather rest of comment... - */ + */ - while ((ch = (*getc_cb)(p, &encoding)) != EOF) - { - if (ch == '>' && bufptr > (buffer + 4) && - bufptr[-3] != '-' && bufptr[-2] == '-' && bufptr[-1] == '-') - break; - else if (mxml_add_char(ch, &bufptr, &buffer, &bufsize)) - goto error; - } + while ((ch = (*getc_cb)(p, &encoding)) != EOF) + { + if (ch == '>' && bufptr > (buffer + 4) && + bufptr[-3] != '-' && bufptr[-2] == '-' && bufptr[-1] == '-') + break; + else if (mxml_add_char(ch, &bufptr, &buffer, &bufsize)) + goto error; + + if (ch == '\n') + line ++; + } /* * Error out if we didn't get the whole comment... - */ + */ if (ch != '>') - { - /* - * Print error and return... - */ + { + /* + * Print error and return... + */ - mxml_error("Early EOF in comment node!"); - goto error; - } + mxml_error("Early EOF in comment node on line %d.", line); + goto error; + } /* * Otherwise add this as an element under the current parent... - */ + */ - *bufptr = '\0'; + *bufptr = '\0'; if (!parent && first) - { - /* - * There can only be one root element! - */ + { + /* + * There can only be one root element! + */ - mxml_error("<%s> cannot be a second root node after <%s>", - buffer, first->value.element.name); + mxml_error("<%s> cannot be a second root node after <%s> on line %d.", buffer, first->value.element.name, line); goto error; - } + } - if ((node = mxmlNewElement(parent, buffer)) == NULL) - { - /* - * Just print error for now... - */ + if ((node = mxmlNewElement(parent, buffer)) == NULL) + { + /* + * Just print error for now... + */ - mxml_error("Unable to add comment node to parent <%s>!", - parent ? parent->value.element.name : "null"); - break; - } + mxml_error("Unable to add comment node to parent <%s> on line %d.", parent ? parent->value.element.name : "null", line); + break; + } if (sax_cb) { @@ -1618,72 +1605,73 @@ mxml_load_data( node = NULL; } - if (node && !first) - first = node; + if (node && !first) + first = node; } else if (!strcmp(buffer, "![CDATA[")) { /* * Gather CDATA section... - */ - - while ((ch = (*getc_cb)(p, &encoding)) != EOF) - { - if (ch == '>' && !strncmp(bufptr - 2, "]]", 2)) - { - /* - * Drop terminator from CDATA string... - */ - - bufptr[-2] = '\0'; - break; - } - else if (mxml_add_char(ch, &bufptr, &buffer, &bufsize)) - goto error; - } + */ + + while ((ch = (*getc_cb)(p, &encoding)) != EOF) + { + if (ch == '>' && !strncmp(bufptr - 2, "]]", 2)) + { + /* + * Drop terminator from CDATA string... + */ + + bufptr[-2] = '\0'; + break; + } + else if (mxml_add_char(ch, &bufptr, &buffer, &bufsize)) + goto error; + + if (ch == '\n') + line ++; + } /* * Error out if we didn't get the whole comment... - */ + */ if (ch != '>') - { - /* - * Print error and return... - */ + { + /* + * Print error and return... + */ - mxml_error("Early EOF in CDATA node!"); - goto error; - } + mxml_error("Early EOF in CDATA node on line %d.", line); + goto error; + } /* * Otherwise add this as an element under the current parent... - */ + */ - *bufptr = '\0'; + *bufptr = '\0'; if (!parent && first) - { - /* - * There can only be one root element! - */ + { + /* + * There can only be one root element! + */ - mxml_error("<%s> cannot be a second root node after <%s>", - buffer, first->value.element.name); + mxml_error("<%s> cannot be a second root node after <%s> on line %d.", buffer, first->value.element.name, line); goto error; - } + } - if ((node = mxmlNewElement(parent, buffer)) == NULL) - { - /* - * Print error and return... - */ + if ((node = mxmlNewElement(parent, buffer)) == NULL) + { + /* + * Print error and return... + */ - mxml_error("Unable to add CDATA node to parent <%s>!", - parent ? parent->value.element.name : "null"); - goto error; - } + mxml_error("Unable to add CDATA node to parent <%s> on line %d.", parent ? parent->value.element.name : "null", line); + goto error; + } if (sax_cb) { @@ -1693,64 +1681,65 @@ mxml_load_data( node = NULL; } - if (node && !first) - first = node; + if (node && !first) + first = node; } else if (buffer[0] == '?') { /* * Gather rest of processing instruction... - */ + */ - while ((ch = (*getc_cb)(p, &encoding)) != EOF) - { - if (ch == '>' && bufptr > buffer && bufptr[-1] == '?') - break; - else if (mxml_add_char(ch, &bufptr, &buffer, &bufsize)) - goto error; - } + while ((ch = (*getc_cb)(p, &encoding)) != EOF) + { + if (ch == '>' && bufptr > buffer && bufptr[-1] == '?') + break; + else if (mxml_add_char(ch, &bufptr, &buffer, &bufsize)) + goto error; + + if (ch == '\n') + line ++; + } /* * Error out if we didn't get the whole processing instruction... - */ + */ if (ch != '>') - { - /* - * Print error and return... - */ + { + /* + * Print error and return... + */ - mxml_error("Early EOF in processing instruction node!"); - goto error; - } + mxml_error("Early EOF in processing instruction node on line %d.", line); + goto error; + } /* * Otherwise add this as an element under the current parent... - */ + */ - *bufptr = '\0'; + *bufptr = '\0'; if (!parent && first) - { - /* - * There can only be one root element! - */ + { + /* + * There can only be one root element! + */ - mxml_error("<%s> cannot be a second root node after <%s>", - buffer, first->value.element.name); + mxml_error("<%s> cannot be a second root node after <%s> on line %d.", buffer, first->value.element.name, line); goto error; - } + } - if ((node = mxmlNewElement(parent, buffer)) == NULL) - { - /* - * Print error and return... - */ + if ((node = mxmlNewElement(parent, buffer)) == NULL) + { + /* + * Print error and return... + */ - mxml_error("Unable to add processing instruction node to parent <%s>!", - parent ? parent->value.element.name : "null"); - goto error; - } + mxml_error("Unable to add processing instruction node to parent <%s> on line %d.", parent ? parent->value.element.name : "null", line); + goto error; + } if (sax_cb) { @@ -1761,84 +1750,87 @@ mxml_load_data( } if (node) - { - if (!first) + { + if (!first) first = node; - if (!parent) - { - parent = node; + if (!parent) + { + parent = node; - if (cb) - type = (*cb)(parent); - else - type = MXML_TEXT; - } - } + if (cb) + type = (*cb)(parent); + else + type = MXML_TEXT; + } + } } else if (buffer[0] == '!') { /* * Gather rest of declaration... - */ - - do - { - if (ch == '>') - break; - else - { + */ + + do + { + if (ch == '>') + break; + else + { if (ch == '&') - if ((ch = mxml_get_entity(parent, p, &encoding, getc_cb)) == EOF) - goto error; + { + if ((ch = mxml_get_entity(parent, p, &encoding, getc_cb, &line)) == EOF) + goto error; + } - if (mxml_add_char(ch, &bufptr, &buffer, &bufsize)) - goto error; - } - } + if (mxml_add_char(ch, &bufptr, &buffer, &bufsize)) + goto error; + } + + if (ch == '\n') + line ++; + } while ((ch = (*getc_cb)(p, &encoding)) != EOF); /* * Error out if we didn't get the whole declaration... - */ + */ if (ch != '>') - { - /* - * Print error and return... - */ + { + /* + * Print error and return... + */ - mxml_error("Early EOF in declaration node!"); - goto error; - } + mxml_error("Early EOF in declaration node on line %d.", line); + goto error; + } /* * Otherwise add this as an element under the current parent... - */ + */ - *bufptr = '\0'; + *bufptr = '\0'; if (!parent && first) - { - /* - * There can only be one root element! - */ + { + /* + * There can only be one root element! + */ - mxml_error("<%s> cannot be a second root node after <%s>", - buffer, first->value.element.name); + mxml_error("<%s> cannot be a second root node after <%s> on line %d.", buffer, first->value.element.name, line); goto error; - } + } - if ((node = mxmlNewElement(parent, buffer)) == NULL) - { - /* - * Print error and return... - */ + if ((node = mxmlNewElement(parent, buffer)) == NULL) + { + /* + * Print error and return... + */ - mxml_error("Unable to add declaration node to parent <%s>!", - parent ? parent->value.element.name : "null"); - goto error; - } + mxml_error("Unable to add declaration node to parent <%s> on line %d.", parent ? parent->value.element.name : "null", line); + goto error; + } if (sax_cb) { @@ -1849,44 +1841,43 @@ mxml_load_data( } if (node) - { - if (!first) + { + if (!first) first = node; - if (!parent) - { - parent = node; + if (!parent) + { + parent = node; - if (cb) - type = (*cb)(parent); - else - type = MXML_TEXT; - } - } + if (cb) + type = (*cb)(parent); + else + type = MXML_TEXT; + } + } } else if (buffer[0] == '/') { /* * Handle close tag... - */ + */ if (!parent || strcmp(buffer + 1, parent->value.element.name)) - { - /* - * Close tag doesn't match tree; print an error for now... - */ + { + /* + * Close tag doesn't match tree; print an error for now... + */ - mxml_error("Mismatched close tag <%s> under parent <%s>!", - buffer, parent ? parent->value.element.name : "(null)"); + mxml_error("Mismatched close tag <%s> under parent <%s> on line %d.", buffer, parent ? parent->value.element.name : "(null)", line); goto error; - } + } /* * Keep reading until we see >... - */ + */ while (ch != '>' && ch != EOF) - ch = (*getc_cb)(p, &encoding); + ch = (*getc_cb)(p, &encoding); node = parent; parent = parent->parent; @@ -1896,84 +1887,81 @@ mxml_load_data( (*sax_cb)(node, MXML_SAX_ELEMENT_CLOSE, sax_data); if (!mxmlRelease(node) && first == node) - first = NULL; + first = NULL; } /* - * Ascend into the parent and set the value type as needed... - */ + * Ascend into the parent and set the value type as needed... + */ - if (cb && parent) - type = (*cb)(parent); + if (cb && parent) + type = (*cb)(parent); } else { /* * Handle open tag... - */ + */ if (!parent && first) - { - /* - * There can only be one root element! - */ + { + /* + * There can only be one root element! + */ - mxml_error("<%s> cannot be a second root node after <%s>", - buffer, first->value.element.name); + mxml_error("<%s> cannot be a second root node after <%s> on line %d.", buffer, first->value.element.name, line); goto error; - } + } if ((node = mxmlNewElement(parent, buffer)) == NULL) - { - /* - * Just print error for now... - */ + { + /* + * Just print error for now... + */ - mxml_error("Unable to add element node to parent <%s>!", - parent ? parent->value.element.name : "null"); - goto error; - } + mxml_error("Unable to add element node to parent <%s> on line %d.", parent ? parent->value.element.name : "null", line); + goto error; + } if (mxml_isspace(ch)) { - if ((ch = mxml_parse_element(node, p, &encoding, getc_cb)) == EOF) - goto error; + if ((ch = mxml_parse_element(node, p, &encoding, getc_cb, &line)) == EOF) + goto error; } else if (ch == '/') - { - if ((ch = (*getc_cb)(p, &encoding)) != '>') - { - mxml_error("Expected > but got '%c' instead for element <%s/>!", - ch, buffer); + { + if ((ch = (*getc_cb)(p, &encoding)) != '>') + { + mxml_error("Expected > but got '%c' instead for element <%s/> on line %d.", ch, buffer, line); mxmlDelete(node); goto error; - } + } - ch = '/'; - } + ch = '/'; + } if (sax_cb) (*sax_cb)(node, MXML_SAX_ELEMENT_OPEN, sax_data); if (!first) - first = node; + first = node; - if (ch == EOF) - break; + if (ch == EOF) + break; if (ch != '/') - { - /* - * Descend into this node, setting the value type as needed... - */ - - parent = node; - - if (cb && parent) - type = (*cb)(parent); - else - type = MXML_TEXT; - } + { + /* + * Descend into this node, setting the value type as needed... + */ + + parent = node; + + if (cb && parent) + type = (*cb)(parent); + else + type = MXML_TEXT; + } else if (sax_cb) { (*sax_cb)(node, MXML_SAX_ELEMENT_CLOSE, sax_data); @@ -1991,11 +1979,11 @@ mxml_load_data( * Add character entity to current buffer... */ - if ((ch = mxml_get_entity(parent, p, &encoding, getc_cb)) == EOF) - goto error; + if ((ch = mxml_get_entity(parent, p, &encoding, getc_cb, &line)) == EOF) + goto error; if (mxml_add_char(ch, &bufptr, &buffer, &bufsize)) - goto error; + goto error; } else if (type == MXML_OPAQUE || type == MXML_CUSTOM || !mxml_isspace(ch)) { @@ -2004,7 +1992,7 @@ mxml_load_data( */ if (mxml_add_char(ch, &bufptr, &buffer, &bufsize)) - goto error; + goto error; } } @@ -2012,7 +2000,7 @@ mxml_load_data( * Free the string buffer - we don't need it anymore... */ - PhFree(buffer); + free(buffer); /* * Find the top element and return it... @@ -2027,9 +2015,7 @@ mxml_load_data( if (node != parent) { - mxml_error("Missing close tag under parent <%s>!", - node->value.element.name, - node->parent ? node->parent->value.element.name : "(null)"); + mxml_error("Missing close tag under parent <%s> on line %d.", node->value.element.name, node->parent ? node->parent->value.element.name : "(null)", line); mxmlDelete(first); @@ -2046,11 +2032,11 @@ mxml_load_data( * Common error return... */ -error: + error: mxmlDelete(first); - PhFree(buffer); + free(buffer); return (NULL); } @@ -2065,15 +2051,16 @@ mxml_parse_element( mxml_node_t *node, /* I - Element node */ void *p, /* I - Data to read from */ int *encoding, /* IO - Encoding */ - _mxml_getc_cb_t getc_cb) /* I - Data callback */ + _mxml_getc_cb_t getc_cb, /* I - Data callback */ + int *line) /* IO - Current line number */ { int ch, /* Current character in file */ - quote; /* Quoting character */ + quote; /* Quoting character */ char *name, /* Attribute name */ - *value, /* Attribute value */ - *ptr; /* Pointer into name/value */ + *value, /* Attribute value */ + *ptr; /* Pointer into name/value */ int namesize, /* Size of name string */ - valsize; /* Size of value string */ + valsize; /* Size of value string */ /* @@ -2112,7 +2099,12 @@ mxml_parse_element( */ if (mxml_isspace(ch)) + { + if (ch == '\n') + (*line)++; + continue; + } /* * Stop at /, ?, or >... @@ -2128,8 +2120,7 @@ mxml_parse_element( if (quote != '>') { - mxml_error("Expected '>' after '%c' for element %s, but got '%c'!", - ch, node->value.element.name, quote); + mxml_error("Expected '>' after '%c' for element %s, but got '%c' on line %d.", ch, node->value.element.name, quote, *line); goto error; } @@ -2137,7 +2128,7 @@ mxml_parse_element( } else if (ch == '<') { - mxml_error("Bare < in element %s!", node->value.element.name); + mxml_error("Bare < in element %s on line %d.", node->value.element.name, *line); goto error; } else if (ch == '>') @@ -2161,13 +2152,17 @@ mxml_parse_element( while ((ch = (*getc_cb)(p, encoding)) != EOF) { if (ch == '&') - if ((ch = mxml_get_entity(node, p, encoding, getc_cb)) == EOF) - goto error; + { + if ((ch = mxml_get_entity(node, p, encoding, getc_cb, line)) == EOF) + goto error; + } + else if (ch == '\n') + (*line)++; - if (mxml_add_char(ch, &ptr, &name, &namesize)) - goto error; + if (mxml_add_char(ch, &ptr, &name, &namesize)) + goto error; - if (ch == quote) + if (ch == quote) break; } } @@ -2178,40 +2173,59 @@ mxml_parse_element( */ while ((ch = (*getc_cb)(p, encoding)) != EOF) - if (mxml_isspace(ch) || ch == '=' || ch == '/' || ch == '>' || - ch == '?') + { + if (mxml_isspace(ch) || ch == '=' || ch == '/' || ch == '>' || + ch == '?') + { + if (ch == '\n') + (*line)++; break; - else - { + } + else + { if (ch == '&') - if ((ch = mxml_get_entity(node, p, encoding, getc_cb)) == EOF) - goto error; + { + if ((ch = mxml_get_entity(node, p, encoding, getc_cb, line)) == EOF) + goto error; + } - if (mxml_add_char(ch, &ptr, &name, &namesize)) - goto error; - } + if (mxml_add_char(ch, &ptr, &name, &namesize)) + goto error; + } + } } *ptr = '\0'; if (mxmlElementGetAttr(node, name)) + { + mxml_error("Duplicate attribute '%s' in element %s on line %d.", name, node->value.element.name, name, *line); goto error; + } while (ch != EOF && mxml_isspace(ch)) + { ch = (*getc_cb)(p, encoding); + if (ch == '\n') + (*line)++; + } + if (ch == '=') { /* * Read the attribute value... */ - while ((ch = (*getc_cb)(p, encoding)) != EOF && mxml_isspace(ch)); + while ((ch = (*getc_cb)(p, encoding)) != EOF && mxml_isspace(ch)) + { + if (ch == '\n') + (*line)++; + } if (ch == EOF) { - mxml_error("Missing value for attribute '%s' in element %s!", - name, node->value.element.name); + mxml_error("Missing value for attribute '%s' in element %s on line %d.", name, node->value.element.name, *line); goto error; } @@ -2219,23 +2233,31 @@ mxml_parse_element( { /* * Read quoted value... - */ + */ quote = ch; - ptr = value; + ptr = value; while ((ch = (*getc_cb)(p, encoding)) != EOF) - if (ch == quote) - break; - else - { - if (ch == '&') - if ((ch = mxml_get_entity(node, p, encoding, getc_cb)) == EOF) - goto error; - - if (mxml_add_char(ch, &ptr, &value, &valsize)) - goto error; - } + { + if (ch == quote) + { + break; + } + else + { + if (ch == '&') + { + if ((ch = mxml_get_entity(node, p, encoding, getc_cb, line)) == EOF) + goto error; + } + else if (ch == '\n') + (*line)++; + + if (mxml_add_char(ch, &ptr, &value, &valsize)) + goto error; + } + } *ptr = '\0'; } @@ -2243,23 +2265,32 @@ mxml_parse_element( { /* * Read unquoted value... - */ + */ - value[0] = ch; - ptr = value + 1; + value[0] = ch; + ptr = value + 1; - while ((ch = (*getc_cb)(p, encoding)) != EOF) - if (mxml_isspace(ch) || ch == '=' || ch == '/' || ch == '>') - break; - else - { - if (ch == '&') - if ((ch = mxml_get_entity(node, p, encoding, getc_cb)) == EOF) - goto error; + while ((ch = (*getc_cb)(p, encoding)) != EOF) + { + if (mxml_isspace(ch) || ch == '=' || ch == '/' || ch == '>') + { + if (ch == '\n') + (*line)++; - if (mxml_add_char(ch, &ptr, &value, &valsize)) - goto error; - } + break; + } + else + { + if (ch == '&') + { + if ((ch = mxml_get_entity(node, p, encoding, getc_cb, line)) == EOF) + goto error; + } + + if (mxml_add_char(ch, &ptr, &value, &valsize)) + goto error; + } + } *ptr = '\0'; } @@ -2272,8 +2303,7 @@ mxml_parse_element( } else { - mxml_error("Missing value for attribute '%s' in element %s!", - name, node->value.element.name); + mxml_error("Missing value for attribute '%s' in element %s on line %d.", name, node->value.element.name, *line); goto error; } @@ -2291,8 +2321,7 @@ mxml_parse_element( if (quote != '>') { - mxml_error("Expected '>' after '%c' for element %s, but got '%c'!", - ch, node->value.element.name, quote); + mxml_error("Expected '>' after '%c' for element %s, but got '%c' on line %d.", ch, node->value.element.name, quote, *line); ch = EOF; } @@ -2315,7 +2344,7 @@ mxml_parse_element( * Common error return point... */ -error: + error: PhFree(name); PhFree(value); @@ -2349,226 +2378,226 @@ mxml_string_getc(void *p, /* I - Pointer to file */ switch (*encoding) { case ENCODE_UTF8 : - if (!(ch & 0x80)) - { + if (!(ch & 0x80)) + { #if DEBUG > 1 printf("mxml_string_getc: %c (0x%04x)\n", ch < ' ' ? '.' : ch, ch); #endif /* DEBUG > 1 */ - if (mxml_bad_char(ch)) - { - mxml_error("Bad control character 0x%02x not allowed by XML standard!", - ch); - return (EOF); - } + if (mxml_bad_char(ch)) + { + mxml_error("Bad control character 0x%02x not allowed by XML standard!", + ch); + return (EOF); + } - return (ch); + return (ch); } - else if (ch == 0xfe) - { - /* - * UTF-16 big-endian BOM? - */ + else if (ch == 0xfe) + { + /* + * UTF-16 big-endian BOM? + */ if (((*s)[0] & 255) != 0xff) - return (EOF); + return (EOF); - *encoding = ENCODE_UTF16BE; - (*s)++; + *encoding = ENCODE_UTF16BE; + (*s)++; - return (mxml_string_getc(p, encoding)); - } - else if (ch == 0xff) - { - /* - * UTF-16 little-endian BOM? - */ + return (mxml_string_getc(p, encoding)); + } + else if (ch == 0xff) + { + /* + * UTF-16 little-endian BOM? + */ if (((*s)[0] & 255) != 0xfe) - return (EOF); + return (EOF); - *encoding = ENCODE_UTF16LE; - (*s)++; + *encoding = ENCODE_UTF16LE; + (*s)++; - return (mxml_string_getc(p, encoding)); - } - else if ((ch & 0xe0) == 0xc0) - { - /* - * Two-byte value... - */ + return (mxml_string_getc(p, encoding)); + } + else if ((ch & 0xe0) == 0xc0) + { + /* + * Two-byte value... + */ - if (((*s)[0] & 0xc0) != 0x80) + if (((*s)[0] & 0xc0) != 0x80) return (EOF); - ch = ((ch & 0x1f) << 6) | ((*s)[0] & 0x3f); + ch = ((ch & 0x1f) << 6) | ((*s)[0] & 0x3f); - (*s)++; + (*s)++; - if (ch < 0x80) - { - mxml_error("Invalid UTF-8 sequence for character 0x%04x!", ch); - return (EOF); - } + if (ch < 0x80) + { + mxml_error("Invalid UTF-8 sequence for character 0x%04x!", ch); + return (EOF); + } #if DEBUG > 1 printf("mxml_string_getc: %c (0x%04x)\n", ch < ' ' ? '.' : ch, ch); #endif /* DEBUG > 1 */ - return (ch); - } - else if ((ch & 0xf0) == 0xe0) - { - /* - * Three-byte value... - */ + return (ch); + } + else if ((ch & 0xf0) == 0xe0) + { + /* + * Three-byte value... + */ - if (((*s)[0] & 0xc0) != 0x80 || - ((*s)[1] & 0xc0) != 0x80) + if (((*s)[0] & 0xc0) != 0x80 || + ((*s)[1] & 0xc0) != 0x80) return (EOF); - ch = ((((ch & 0x0f) << 6) | ((*s)[0] & 0x3f)) << 6) | ((*s)[1] & 0x3f); + ch = ((((ch & 0x0f) << 6) | ((*s)[0] & 0x3f)) << 6) | ((*s)[1] & 0x3f); - (*s) += 2; + (*s) += 2; - if (ch < 0x800) - { - mxml_error("Invalid UTF-8 sequence for character 0x%04x!", ch); - return (EOF); - } + if (ch < 0x800) + { + mxml_error("Invalid UTF-8 sequence for character 0x%04x!", ch); + return (EOF); + } - /* - * Ignore (strip) Byte Order Mark (BOM)... - */ + /* + * Ignore (strip) Byte Order Mark (BOM)... + */ - if (ch == 0xfeff) - return (mxml_string_getc(p, encoding)); + if (ch == 0xfeff) + return (mxml_string_getc(p, encoding)); #if DEBUG > 1 printf("mxml_string_getc: %c (0x%04x)\n", ch < ' ' ? '.' : ch, ch); #endif /* DEBUG > 1 */ - return (ch); - } - else if ((ch & 0xf8) == 0xf0) - { - /* - * Four-byte value... - */ - - if (((*s)[0] & 0xc0) != 0x80 || - ((*s)[1] & 0xc0) != 0x80 || - ((*s)[2] & 0xc0) != 0x80) + return (ch); + } + else if ((ch & 0xf8) == 0xf0) + { + /* + * Four-byte value... + */ + + if (((*s)[0] & 0xc0) != 0x80 || + ((*s)[1] & 0xc0) != 0x80 || + ((*s)[2] & 0xc0) != 0x80) return (EOF); - ch = ((((((ch & 0x07) << 6) | ((*s)[0] & 0x3f)) << 6) | - ((*s)[1] & 0x3f)) << 6) | ((*s)[2] & 0x3f); + ch = ((((((ch & 0x07) << 6) | ((*s)[0] & 0x3f)) << 6) | + ((*s)[1] & 0x3f)) << 6) | ((*s)[2] & 0x3f); - (*s) += 3; + (*s) += 3; - if (ch < 0x10000) - { - mxml_error("Invalid UTF-8 sequence for character 0x%04x!", ch); - return (EOF); - } + if (ch < 0x10000) + { + mxml_error("Invalid UTF-8 sequence for character 0x%04x!", ch); + return (EOF); + } #if DEBUG > 1 printf("mxml_string_getc: %c (0x%04x)\n", ch < ' ' ? '.' : ch, ch); #endif /* DEBUG > 1 */ - return (ch); - } - else - return (EOF); + return (ch); + } + else + return (EOF); case ENCODE_UTF16BE : - /* + /* * Read UTF-16 big-endian char... - */ + */ - ch = (ch << 8) | ((*s)[0] & 255); - (*s) ++; + ch = (ch << 8) | ((*s)[0] & 255); + (*s) ++; if (mxml_bad_char(ch)) - { - mxml_error("Bad control character 0x%02x not allowed by XML standard!", - ch); - return (EOF); - } + { + mxml_error("Bad control character 0x%02x not allowed by XML standard!", + ch); + return (EOF); + } else if (ch >= 0xd800 && ch <= 0xdbff) - { - /* - * Multi-word UTF-16 char... - */ + { + /* + * Multi-word UTF-16 char... + */ int lch; /* Lower word */ if (!(*s)[0]) - return (EOF); + return (EOF); lch = (((*s)[0] & 255) << 8) | ((*s)[1] & 255); - (*s) += 2; + (*s) += 2; if (lch < 0xdc00 || lch >= 0xdfff) - return (EOF); + return (EOF); ch = (((ch & 0x3ff) << 10) | (lch & 0x3ff)) + 0x10000; - } + } #if DEBUG > 1 printf("mxml_string_getc: %c (0x%04x)\n", ch < ' ' ? '.' : ch, ch); #endif /* DEBUG > 1 */ - return (ch); + return (ch); case ENCODE_UTF16LE : - /* + /* * Read UTF-16 little-endian char... - */ + */ - ch = ch | (((*s)[0] & 255) << 8); + ch = ch | (((*s)[0] & 255) << 8); - if (!ch) - { - (*s) --; - return (EOF); - } + if (!ch) + { + (*s) --; + return (EOF); + } - (*s) ++; + (*s) ++; if (mxml_bad_char(ch)) - { - mxml_error("Bad control character 0x%02x not allowed by XML standard!", - ch); - return (EOF); - } + { + mxml_error("Bad control character 0x%02x not allowed by XML standard!", + ch); + return (EOF); + } else if (ch >= 0xd800 && ch <= 0xdbff) - { - /* - * Multi-word UTF-16 char... - */ + { + /* + * Multi-word UTF-16 char... + */ int lch; /* Lower word */ if (!(*s)[1]) - return (EOF); + return (EOF); lch = (((*s)[1] & 255) << 8) | ((*s)[0] & 255); - (*s) += 2; + (*s) += 2; if (lch < 0xdc00 || lch >= 0xdfff) - return (EOF); + return (EOF); ch = (((ch & 0x3ff) << 10) | (lch & 0x3ff)) + 0x10000; - } + } #if DEBUG > 1 printf("mxml_string_getc: %c (0x%04x)\n", ch < ' ' ? '.' : ch, ch); #endif /* DEBUG > 1 */ - return (ch); + return (ch); } } @@ -2605,8 +2634,8 @@ mxml_string_putc(int ch, /* I - Character to write */ static int /* O - 0 on success, -1 on failure */ mxml_write_name(const char *s, /* I - Name to write */ void *p, /* I - Write pointer */ - int (*putc_cb)(int, void *)) - /* I - Write callback */ + int (*putc_cb)(int, void *)) + /* I - Write callback */ { char quote; /* Quote character */ const char *name; /* Entity name */ @@ -2627,22 +2656,22 @@ mxml_write_name(const char *s, /* I - Name to write */ { if ((name = mxmlEntityGetName(*s)) != NULL) { - if ((*putc_cb)('&', p) < 0) + if ((*putc_cb)('&', p) < 0) return (-1); while (*name) - { - if ((*putc_cb)(*name, p) < 0) + { + if ((*putc_cb)(*name, p) < 0) return (-1); name ++; - } + } - if ((*putc_cb)(';', p) < 0) + if ((*putc_cb)(';', p) < 0) return (-1); } else if ((*putc_cb)(*s, p) < 0) - return (-1); + return (-1); s ++; } @@ -2663,7 +2692,7 @@ mxml_write_name(const char *s, /* I - Name to write */ while (*s) { if ((*putc_cb)(*s, p) < 0) - return (-1); + return (-1); s ++; } @@ -2680,16 +2709,16 @@ mxml_write_name(const char *s, /* I - Name to write */ static int /* O - Column or -1 on error */ mxml_write_node(mxml_node_t *node, /* I - Node to write */ void *p, /* I - File to write to */ - mxml_save_cb_t cb, /* I - Whitespace callback */ - int col, /* I - Current column */ - _mxml_putc_cb_t putc_cb,/* I - Output callback */ - _mxml_global_t *global)/* I - Global data */ + mxml_save_cb_t cb, /* I - Whitespace callback */ + int col, /* I - Current column */ + _mxml_putc_cb_t putc_cb,/* I - Output callback */ + _mxml_global_t *global)/* I - Global data */ { mxml_node_t *current, /* Current node */ - *next; /* Next node */ + *next; /* Next node */ int i, /* Looping var */ - width; /* Width of attr + value */ - mxml_attr_t *attr; /* Current attribute */ + width; /* Width of attr + value */ + _mxml_attr_t *attr; /* Current attribute */ char s[255]; /* Temporary string */ @@ -2706,230 +2735,230 @@ mxml_write_node(mxml_node_t *node, /* I - Node to write */ switch (current->type) { case MXML_ELEMENT : - col = mxml_write_ws(current, p, cb, MXML_WS_BEFORE_OPEN, col, putc_cb); - - if ((*putc_cb)('<', p) < 0) - return (-1); - if (current->value.element.name[0] == '?' || - !strncmp(current->value.element.name, "!--", 3)) - { - /* - * Comments and processing instructions do not use character - * entities. - */ - - const char *ptr; /* Pointer into name */ - - for (ptr = current->value.element.name; *ptr; ptr ++) - if ((*putc_cb)(*ptr, p) < 0) - return (-1); - } - else if (!strncmp(current->value.element.name, "![CDATA[", 8)) - { - /* - * CDATA elements do not use character entities, but also need the - * "]]" terminator added at the end. - */ - - const char *ptr; /* Pointer into name */ - - for (ptr = current->value.element.name; *ptr; ptr ++) - if ((*putc_cb)(*ptr, p) < 0) - return (-1); + col = mxml_write_ws(current, p, cb, MXML_WS_BEFORE_OPEN, col, putc_cb); + + if ((*putc_cb)('<', p) < 0) + return (-1); + if (current->value.element.name[0] == '?' || + !strncmp(current->value.element.name, "!--", 3)) + { + /* + * Comments and processing instructions do not use character + * entities. + */ + + const char *ptr; /* Pointer into name */ + + for (ptr = current->value.element.name; *ptr; ptr ++) + if ((*putc_cb)(*ptr, p) < 0) + return (-1); + } + else if (!strncmp(current->value.element.name, "![CDATA[", 8)) + { + /* + * CDATA elements do not use character entities, but also need the + * "]]" terminator added at the end. + */ + + const char *ptr; /* Pointer into name */ + + for (ptr = current->value.element.name; *ptr; ptr ++) + if ((*putc_cb)(*ptr, p) < 0) + return (-1); if ((*putc_cb)(']', p) < 0) return (-1); if ((*putc_cb)(']', p) < 0) return (-1); - } - else if (mxml_write_name(current->value.element.name, p, putc_cb) < 0) - return (-1); - - col += (int)strlen(current->value.element.name) + 1; - - for (i = current->value.element.num_attrs, attr = current->value.element.attrs; - i > 0; - i --, attr ++) - { - width = (int)strlen(attr->name); - - if (attr->value) - width += (int)strlen(attr->value) + 3; - - if (global->wrap > 0 && (col + width) > global->wrap) - { - if ((*putc_cb)('\n', p) < 0) - return (-1); - - col = 0; - } - else - { - if ((*putc_cb)(' ', p) < 0) - return (-1); - - col ++; - } - - if (mxml_write_name(attr->name, p, putc_cb) < 0) - return (-1); - - if (attr->value) - { - if ((*putc_cb)('=', p) < 0) - return (-1); - if ((*putc_cb)('\"', p) < 0) - return (-1); - if (mxml_write_string(attr->value, p, putc_cb) < 0) - return (-1); - if ((*putc_cb)('\"', p) < 0) - return (-1); - } - - col += width; - } - - if (current->child) - { - /* - * Write children... - */ - - if ((*putc_cb)('>', p) < 0) - return (-1); - else - col ++; - - col = mxml_write_ws(current, p, cb, MXML_WS_AFTER_OPEN, col, putc_cb); - } - else if (current->value.element.name[0] == '!' || - current->value.element.name[0] == '?') - { - /* - * The ? and ! elements are special-cases... - */ - - if ((*putc_cb)('>', p) < 0) - return (-1); - else - col ++; - - col = mxml_write_ws(current, p, cb, MXML_WS_AFTER_OPEN, col, putc_cb); - } - else - { - if ((*putc_cb)(' ', p) < 0) - return (-1); - if ((*putc_cb)('/', p) < 0) - return (-1); - if ((*putc_cb)('>', p) < 0) - return (-1); - - col += 3; - - col = mxml_write_ws(current, p, cb, MXML_WS_AFTER_OPEN, col, putc_cb); - } - break; + } + else if (mxml_write_name(current->value.element.name, p, putc_cb) < 0) + return (-1); + + col += (int)strlen(current->value.element.name) + 1; + + for (i = current->value.element.num_attrs, attr = current->value.element.attrs; + i > 0; + i --, attr ++) + { + width = (int)strlen(attr->name); + + if (attr->value) + width += (int)strlen(attr->value) + 3; + + if (global->wrap > 0 && (col + width) > global->wrap) + { + if ((*putc_cb)('\n', p) < 0) + return (-1); + + col = 0; + } + else + { + if ((*putc_cb)(' ', p) < 0) + return (-1); + + col ++; + } + + if (mxml_write_name(attr->name, p, putc_cb) < 0) + return (-1); + + if (attr->value) + { + if ((*putc_cb)('=', p) < 0) + return (-1); + if ((*putc_cb)('\"', p) < 0) + return (-1); + if (mxml_write_string(attr->value, p, putc_cb) < 0) + return (-1); + if ((*putc_cb)('\"', p) < 0) + return (-1); + } + + col += width; + } + + if (current->child) + { + /* + * Write children... + */ + + if ((*putc_cb)('>', p) < 0) + return (-1); + else + col ++; + + col = mxml_write_ws(current, p, cb, MXML_WS_AFTER_OPEN, col, putc_cb); + } + else if (current->value.element.name[0] == '!' || + current->value.element.name[0] == '?') + { + /* + * The ? and ! elements are special-cases... + */ + + if ((*putc_cb)('>', p) < 0) + return (-1); + else + col ++; + + col = mxml_write_ws(current, p, cb, MXML_WS_AFTER_OPEN, col, putc_cb); + } + else + { + if ((*putc_cb)(' ', p) < 0) + return (-1); + if ((*putc_cb)('/', p) < 0) + return (-1); + if ((*putc_cb)('>', p) < 0) + return (-1); + + col += 3; + + col = mxml_write_ws(current, p, cb, MXML_WS_AFTER_OPEN, col, putc_cb); + } + break; case MXML_INTEGER : - if (current->prev) - { - if (global->wrap > 0 && col > global->wrap) - { - if ((*putc_cb)('\n', p) < 0) - return (-1); - - col = 0; - } - else if ((*putc_cb)(' ', p) < 0) - return (-1); - else - col ++; - } - - sprintf(s, "%d", current->value.integer); - if (mxml_write_string(s, p, putc_cb) < 0) - return (-1); - - col += (int)strlen(s); - break; + if (current->prev) + { + if (global->wrap > 0 && col > global->wrap) + { + if ((*putc_cb)('\n', p) < 0) + return (-1); + + col = 0; + } + else if ((*putc_cb)(' ', p) < 0) + return (-1); + else + col ++; + } + + snprintf(s, sizeof(s), "%d", current->value.integer); + if (mxml_write_string(s, p, putc_cb) < 0) + return (-1); + + col += (int)strlen(s); + break; case MXML_OPAQUE : - if (mxml_write_string(current->value.opaque, p, putc_cb) < 0) - return (-1); + if (mxml_write_string(current->value.opaque, p, putc_cb) < 0) + return (-1); - col += (int)strlen(current->value.opaque); - break; + col += (int)strlen(current->value.opaque); + break; case MXML_REAL : - if (current->prev) - { - if (global->wrap > 0 && col > global->wrap) - { - if ((*putc_cb)('\n', p) < 0) - return (-1); - - col = 0; - } - else if ((*putc_cb)(' ', p) < 0) - return (-1); - else - col ++; - } - - sprintf(s, "%f", current->value.real); - if (mxml_write_string(s, p, putc_cb) < 0) - return (-1); - - col += (int)strlen(s); - break; + if (current->prev) + { + if (global->wrap > 0 && col > global->wrap) + { + if ((*putc_cb)('\n', p) < 0) + return (-1); + + col = 0; + } + else if ((*putc_cb)(' ', p) < 0) + return (-1); + else + col ++; + } + + snprintf(s, sizeof(s), "%f", current->value.real); + if (mxml_write_string(s, p, putc_cb) < 0) + return (-1); + + col += (int)strlen(s); + break; case MXML_TEXT : - if (current->value.text.whitespace && col > 0) - { - if (global->wrap > 0 && col > global->wrap) - { - if ((*putc_cb)('\n', p) < 0) - return (-1); - - col = 0; - } - else if ((*putc_cb)(' ', p) < 0) - return (-1); - else - col ++; - } - - if (mxml_write_string(current->value.text.string, p, putc_cb) < 0) - return (-1); - - col += (int)strlen(current->value.text.string); - break; + if (current->value.text.whitespace && col > 0) + { + if (global->wrap > 0 && col > global->wrap) + { + if ((*putc_cb)('\n', p) < 0) + return (-1); + + col = 0; + } + else if ((*putc_cb)(' ', p) < 0) + return (-1); + else + col ++; + } + + if (mxml_write_string(current->value.text.string, p, putc_cb) < 0) + return (-1); + + col += (int)strlen(current->value.text.string); + break; case MXML_CUSTOM : - if (global->custom_save_cb) - { - char *data; /* Custom data string */ - const char *newline; /* Last newline in string */ + if (global->custom_save_cb) + { + char *data; /* Custom data string */ + const char *newline; /* Last newline in string */ - if ((data = (*global->custom_save_cb)(current)) == NULL) - return (-1); + if ((data = (*global->custom_save_cb)(current)) == NULL) + return (-1); - if (mxml_write_string(data, p, putc_cb) < 0) - return (-1); + if (mxml_write_string(data, p, putc_cb) < 0) + return (-1); - if ((newline = strrchr(data, '\n')) == NULL) - col += (int)strlen(data); - else - col = (int)strlen(newline); + if ((newline = strrchr(data, '\n')) == NULL) + col += (int)strlen(data); + else + col = (int)strlen(newline); PhFree(data); - break; - } + break; + } default : /* Should never happen */ - return (-1); + return (-1); } /* @@ -2952,39 +2981,39 @@ mxml_write_node(mxml_node_t *node, /* I - Node to write */ * Try the next sibling, and continue traversing upwards as needed... */ - while ((next = current->next) == NULL) - { - if (current == node || !current->parent) - break; + while ((next = current->next) == NULL) + { + if (current == node || !current->parent) + break; - /* - * The ? and ! elements are special-cases and have no end tags... - */ + /* + * The ? and ! elements are special-cases and have no end tags... + */ - current = current->parent; + current = current->parent; - if (current->value.element.name[0] != '!' && - current->value.element.name[0] != '?') - { - col = mxml_write_ws(current, p, cb, MXML_WS_BEFORE_CLOSE, col, putc_cb); + if (current->value.element.name[0] != '!' && + current->value.element.name[0] != '?') + { + col = mxml_write_ws(current, p, cb, MXML_WS_BEFORE_CLOSE, col, putc_cb); - if ((*putc_cb)('<', p) < 0) - return (-1); - if ((*putc_cb)('/', p) < 0) - return (-1); - if (mxml_write_string(current->value.element.name, p, putc_cb) < 0) - return (-1); - if ((*putc_cb)('>', p) < 0) - return (-1); + if ((*putc_cb)('<', p) < 0) + return (-1); + if ((*putc_cb)('/', p) < 0) + return (-1); + if (mxml_write_string(current->value.element.name, p, putc_cb) < 0) + return (-1); + if ((*putc_cb)('>', p) < 0) + return (-1); - col += (int)strlen(current->value.element.name) + 3; + col += (int)strlen(current->value.element.name) + 3; - col = mxml_write_ws(current, p, cb, MXML_WS_AFTER_CLOSE, col, putc_cb); - } + col = mxml_write_ws(current, p, cb, MXML_WS_AFTER_CLOSE, col, putc_cb); + } - if (current == node) - break; - } + if (current == node) + break; + } } } } @@ -3015,7 +3044,7 @@ mxml_write_string( while (*name) { - if ((*putc_cb)(*name, p) < 0) + if ((*putc_cb)(*name, p) < 0) return (-1); name ++; } @@ -3041,8 +3070,8 @@ static int /* O - New column */ mxml_write_ws(mxml_node_t *node, /* I - Current node */ void *p, /* I - Write pointer */ mxml_save_cb_t cb, /* I - Callback function */ - int ws, /* I - Where value */ - int col, /* I - Current column */ + int ws, /* I - Where value */ + int col, /* I - Current column */ _mxml_putc_cb_t putc_cb) /* I - Write callback */ { const char *s; /* Whitespace string */ @@ -3053,16 +3082,16 @@ mxml_write_ws(mxml_node_t *node, /* I - Current node */ while (*s) { if ((*putc_cb)(*s, p) < 0) - return (-1); + return (-1); else if (*s == '\n') - col = 0; + col = 0; else if (*s == '\t') { - col += MXML_TAB; - col = col - (col % MXML_TAB); + col += MXML_TAB; + col = col - (col % MXML_TAB); } else - col ++; + col ++; s ++; } diff --git a/phlib/mxml/mxml-get.c b/phlib/mxml/mxml-get.c index 1f00d7f77b44..e2ff2bd545d2 100644 --- a/phlib/mxml/mxml-get.c +++ b/phlib/mxml/mxml-get.c @@ -1,15 +1,12 @@ /* * Node get functions for Mini-XML, a small XML file parsing library. * - * Copyright 2014-2018 by Michael R Sweet. + * https://www.msweet.org/mxml * - * These coded instructions, statements, and computer programs are the - * property of Michael R Sweet and are protected by Federal copyright - * law. Distribution and use rights are outlined in the file "COPYING" - * which should have been included with this file. If this file is - * missing or damaged, see the license at: + * Copyright © 2014-2019 by Michael R Sweet. * - * https://michaelrsweet.github.io/mxml + * Licensed under Apache License v2.0. See the file "LICENSE" for more + * information. */ /* @@ -17,7 +14,7 @@ */ #include "config.h" -#include "mxml.h" +#include "mxml-private.h" /* @@ -74,7 +71,7 @@ mxmlGetCustom(mxml_node_t *node) /* I - Node to get */ return (node->value.custom.data); else if (node->type == MXML_ELEMENT && node->child && - node->child->type == MXML_CUSTOM) + node->child->type == MXML_CUSTOM) return (node->child->value.custom.data); else return (NULL); @@ -161,7 +158,7 @@ mxmlGetInteger(mxml_node_t *node) /* I - Node to get */ return (node->value.integer); else if (node->type == MXML_ELEMENT && node->child && - node->child->type == MXML_INTEGER) + node->child->type == MXML_INTEGER) return (node->child->value.integer); else return (0); @@ -248,7 +245,7 @@ mxmlGetOpaque(mxml_node_t *node) /* I - Node to get */ return (node->value.opaque); else if (node->type == MXML_ELEMENT && node->child && - node->child->type == MXML_OPAQUE) + node->child->type == MXML_OPAQUE) return (node->child->value.opaque); else return (NULL); @@ -333,7 +330,7 @@ mxmlGetReal(mxml_node_t *node) /* I - Node to get */ return (node->value.real); else if (node->type == MXML_ELEMENT && node->child && - node->child->type == MXML_REAL) + node->child->type == MXML_REAL) return (node->child->value.real); else return (0.0); @@ -384,7 +381,7 @@ mxmlGetText(mxml_node_t *node, /* I - Node to get */ } else if (node->type == MXML_ELEMENT && node->child && - node->child->type == MXML_TEXT) + node->child->type == MXML_TEXT) { if (whitespace) *whitespace = node->child->value.text.whitespace; diff --git a/phlib/mxml/mxml-index.c b/phlib/mxml/mxml-index.c index 350294cea2b9..c5766a4488b5 100644 --- a/phlib/mxml/mxml-index.c +++ b/phlib/mxml/mxml-index.c @@ -1,25 +1,20 @@ /* * Index support code for Mini-XML, a small XML file parsing library. * - * Copyright 2003-2017 by Michael R Sweet. + * https://www.msweet.org/mxml * - * These coded instructions, statements, and computer programs are the - * property of Michael R Sweet and are protected by Federal copyright - * law. Distribution and use rights are outlined in the file "COPYING" - * which should have been included with this file. If this file is - * missing or damaged, see the license at: + * Copyright © 2003-2019 by Michael R Sweet. * - * https://michaelrsweet.github.io/mxml + * Licensed under Apache License v2.0. See the file "LICENSE" for more + * information. */ /* * Include necessary headers... */ -#include - #include "config.h" -#include "mxml.h" +#include "mxml-private.h" /* @@ -27,9 +22,9 @@ */ static int index_compare(mxml_index_t *ind, mxml_node_t *first, - mxml_node_t *second); + mxml_node_t *second); static int index_find(mxml_index_t *ind, const char *element, - const char *value, mxml_node_t *node); + const char *value, mxml_node_t *node); static void index_sort(mxml_index_t *ind, int left, int right); @@ -52,10 +47,10 @@ mxmlIndexDelete(mxml_index_t *ind) /* I - Index to delete */ */ if (ind->attr) - PhFree(ind->attr); + PhFree(ind->attr); if (ind->alloc_nodes) - PhFree(ind->nodes); + PhFree(ind->nodes); PhFree(ind); } @@ -102,12 +97,12 @@ mxmlIndexEnum(mxml_index_t *ind) /* I - Index to enumerate */ mxml_node_t * /* O - Node or @code NULL@ if none found */ mxmlIndexFind(mxml_index_t *ind, /* I - Index to search */ const char *element, /* I - Element name to find, if any */ - const char *value) /* I - Attribute value, if any */ + const char *value) /* I - Attribute value, if any */ { int diff, /* Difference between names */ - current, /* Current entity in search */ - first, /* First entity in search */ - last; /* Last entity in search */ + current, /* Current entity in search */ + first, /* First entity in search */ + last; /* Last entity in search */ #ifdef DEBUG @@ -181,15 +176,15 @@ mxmlIndexFind(mxml_index_t *ind, /* I - Index to search */ { /* * Found a match, move back to find the first... - */ + */ #ifdef DEBUG puts(" match!"); #endif /* DEBUG */ while (current > 0 && - !index_find(ind, element, value, ind->nodes[current - 1])) - current --; + !index_find(ind, element, value, ind->nodes[current - 1])) + current --; #ifdef DEBUG printf(" returning first match=%d\n", current); @@ -197,16 +192,16 @@ mxmlIndexFind(mxml_index_t *ind, /* I - Index to search */ /* * Return the first match and save the index to the next... - */ + */ ind->cur_node = current + 1; - return (ind->nodes[current]); + return (ind->nodes[current]); } else if (diff < 0) - last = current; + last = current; else - first = current; + first = current; #ifdef DEBUG printf(" diff=%d\n", diff); @@ -221,16 +216,16 @@ mxmlIndexFind(mxml_index_t *ind, /* I - Index to search */ if (!index_find(ind, element, value, ind->nodes[current])) { /* - * Found exactly one (or possibly two) match... - */ + * Found exactly one (or possibly two) match... + */ #ifdef DEBUG - printf(" returning only match %d...\n", current); + printf(" returning only match %d...\n", current); #endif /* DEBUG */ - ind->cur_node = current + 1; + ind->cur_node = current + 1; - return (ind->nodes[current]); + return (ind->nodes[current]); } /* @@ -314,7 +309,7 @@ mxmlIndexNew(mxml_node_t *node, /* I - XML node tree */ { mxml_index_t *ind; /* New index */ mxml_node_t *current, /* Current node in index */ - **temp; /* Temporary node pointer array */ + **temp; /* Temporary node pointer array */ /* @@ -361,14 +356,14 @@ mxmlIndexNew(mxml_node_t *node, /* I - XML node tree */ { /* * Unable to allocate memory for the index, so abort... - */ + */ mxml_error("Unable to allocate %d bytes for index: %s", - (ind->alloc_nodes + 64) * sizeof(mxml_node_t *), - strerror(errno)); + (ind->alloc_nodes + 64) * sizeof(mxml_node_t *), + strerror(errno)); mxmlIndexDelete(ind); - return (NULL); + return (NULL); } ind->nodes = temp; @@ -397,9 +392,9 @@ mxmlIndexNew(mxml_node_t *node, /* I - XML node tree */ puts("-------- -------- -------------- ------------------------------"); for (i = 0; i < ind->num_nodes; i ++) - printf("%8d %-8p %-14.14s %s\n", i, ind->nodes[i], - ind->nodes[i]->value.element.name, - mxmlElementGetAttr(ind->nodes[i], attr)); + printf("%8d %-8p %-14.14s %s\n", i, ind->nodes[i], + ind->nodes[i]->value.element.name, + mxmlElementGetAttr(ind->nodes[i], attr)); } else { @@ -407,8 +402,8 @@ mxmlIndexNew(mxml_node_t *node, /* I - XML node tree */ puts("-------- -------- --------------"); for (i = 0; i < ind->num_nodes; i ++) - printf("%8d %-8p %s\n", i, ind->nodes[i], - ind->nodes[i]->value.element.name); + printf("%8d %-8p %s\n", i, ind->nodes[i], + ind->nodes[i]->value.element.name); } putchar('\n'); @@ -431,9 +426,9 @@ mxmlIndexNew(mxml_node_t *node, /* I - XML node tree */ puts("-------- -------- -------------- ------------------------------"); for (i = 0; i < ind->num_nodes; i ++) - printf("%8d %-8p %-14.14s %s\n", i, ind->nodes[i], - ind->nodes[i]->value.element.name, - mxmlElementGetAttr(ind->nodes[i], attr)); + printf("%8d %-8p %-14.14s %s\n", i, ind->nodes[i], + ind->nodes[i]->value.element.name, + mxmlElementGetAttr(ind->nodes[i], attr)); } else { @@ -441,8 +436,8 @@ mxmlIndexNew(mxml_node_t *node, /* I - XML node tree */ puts("-------- -------- --------------"); for (i = 0; i < ind->num_nodes; i ++) - printf("%8d %-8p %s\n", i, ind->nodes[i], - ind->nodes[i]->value.element.name); + printf("%8d %-8p %s\n", i, ind->nodes[i], + ind->nodes[i]->value.element.name); } putchar('\n'); @@ -542,7 +537,7 @@ index_compare(mxml_index_t *ind, /* I - Index */ static int /* O - Result of comparison */ index_find(mxml_index_t *ind, /* I - Index */ const char *element, /* I - Element name or @code NULL@ */ - const char *value, /* I - Attribute value or @code NULL@ */ + const char *value, /* I - Attribute value or @code NULL@ */ mxml_node_t *node) /* I - Node */ { int diff; /* Difference */ @@ -585,12 +580,12 @@ index_find(mxml_index_t *ind, /* I - Index */ static void index_sort(mxml_index_t *ind, /* I - Index to sort */ int left, /* I - Left node in partition */ - int right) /* I - Right node in partition */ + int right) /* I - Right node in partition */ { mxml_node_t *pivot, /* Pivot node */ - *temp; /* Swap node */ + *temp; /* Swap node */ int templ, /* Temporary left node */ - tempr; /* Temporary right node */ + tempr; /* Temporary right node */ /* @@ -613,7 +608,7 @@ index_sort(mxml_index_t *ind, /* I - Index to sort */ while ((templ < right) && index_compare(ind, ind->nodes[templ], pivot) <= 0) - templ ++; + templ ++; /* * Move right while right node > pivot node... @@ -621,7 +616,7 @@ index_sort(mxml_index_t *ind, /* I - Index to sort */ while ((tempr > left) && index_compare(ind, ind->nodes[tempr], pivot) > 0) - tempr --; + tempr --; /* * Swap nodes if needed... @@ -629,9 +624,9 @@ index_sort(mxml_index_t *ind, /* I - Index to sort */ if (templ < tempr) { - temp = ind->nodes[templ]; - ind->nodes[templ] = ind->nodes[tempr]; - ind->nodes[tempr] = temp; + temp = ind->nodes[templ]; + ind->nodes[templ] = ind->nodes[tempr]; + ind->nodes[tempr] = temp; } } diff --git a/phlib/mxml/mxml-node.c b/phlib/mxml/mxml-node.c index 977db33007e9..f67b06b96e15 100644 --- a/phlib/mxml/mxml-node.c +++ b/phlib/mxml/mxml-node.c @@ -1,25 +1,20 @@ /* * Node support code for Mini-XML, a small XML file parsing library. * - * Copyright 2003-2018 by Michael R Sweet. + * https://www.msweet.org/mxml * - * These coded instructions, statements, and computer programs are the - * property of Michael R Sweet and are protected by Federal copyright - * law. Distribution and use rights are outlined in the file "COPYING" - * which should have been included with this file. If this file is - * missing or damaged, see the license at: + * Copyright © 2003-2019 by Michael R Sweet. * - * https://michaelrsweet.github.io/mxml + * Licensed under Apache License v2.0. See the file "LICENSE" for more + * information. */ /* * Include necessary headers... */ -#include - #include "config.h" -#include "mxml.h" +#include "mxml-private.h" /* @@ -45,7 +40,7 @@ void mxmlAdd(mxml_node_t *parent, /* I - Parent node */ int where, /* I - Where to add, @code MXML_ADD_BEFORE@ or @code MXML_ADD_AFTER@ */ mxml_node_t *child, /* I - Child node for where or @code MXML_ADD_TO_PARENT@ */ - mxml_node_t *node) /* I - Node to add */ + mxml_node_t *node) /* I - Node to add */ { #ifdef MXMLDEBUG fprintf(stderr, "mxmlAdd(parent=%p, where=%d, child=%p, node=%p)\n", parent, @@ -87,71 +82,71 @@ mxmlAdd(mxml_node_t *parent, /* I - Parent node */ { case MXML_ADD_BEFORE : if (!child || child == parent->child || child->parent != parent) - { - /* - * Insert as first node under parent... - */ - - node->next = parent->child; - - if (parent->child) - parent->child->prev = node; - else - parent->last_child = node; - - parent->child = node; - } - else - { - /* - * Insert node before this child... - */ - - node->next = child; - node->prev = child->prev; - - if (child->prev) - child->prev->next = node; - else - parent->child = node; - - child->prev = node; - } + { + /* + * Insert as first node under parent... + */ + + node->next = parent->child; + + if (parent->child) + parent->child->prev = node; + else + parent->last_child = node; + + parent->child = node; + } + else + { + /* + * Insert node before this child... + */ + + node->next = child; + node->prev = child->prev; + + if (child->prev) + child->prev->next = node; + else + parent->child = node; + + child->prev = node; + } break; case MXML_ADD_AFTER : if (!child || child == parent->last_child || child->parent != parent) - { - /* - * Insert as last node under parent... - */ + { + /* + * Insert as last node under parent... + */ - node->parent = parent; - node->prev = parent->last_child; + node->parent = parent; + node->prev = parent->last_child; - if (parent->last_child) - parent->last_child->next = node; - else - parent->child = node; + if (parent->last_child) + parent->last_child->next = node; + else + parent->child = node; - parent->last_child = node; + parent->last_child = node; } - else - { - /* - * Insert node after this child... - */ - - node->prev = child; - node->next = child->next; - - if (child->next) - child->next->prev = node; - else - parent->last_child = node; - - child->next = node; - } + else + { + /* + * Insert node after this child... + */ + + node->prev = child; + node->next = child->next; + + if (child->next) + child->next->prev = node; + else + parent->last_child = node; + + child->next = node; + } break; } @@ -179,7 +174,7 @@ void mxmlDelete(mxml_node_t *node) /* I - Node to delete */ { mxml_node_t *current, /* Current node */ - *next; /* Next node */ + *next; /* Next node */ #ifdef MXMLDEBUG @@ -286,7 +281,7 @@ mxmlGetRefCount(mxml_node_t *node) /* I - Node */ mxml_node_t * /* O - New node */ mxmlNewCDATA(mxml_node_t *parent, /* I - Parent node or @code MXML_NO_PARENT@ */ - const char *data) /* I - Data string */ + const char *data) /* I - Data string */ { mxml_node_t *node; /* New node */ @@ -472,7 +467,7 @@ mxmlNewOpaque(mxml_node_t *parent, /* I - Parent node or @code MXML_NO_PARENT@ * mxml_node_t * /* O - New node */ mxmlNewOpaquef(mxml_node_t *parent, /* I - Parent node or @code MXML_NO_PARENT@ */ const char *format, /* I - Printf-style format string */ - ...) /* I - Additional args as needed */ + ...) /* I - Additional args as needed */ { mxml_node_t *node; /* New node */ va_list ap; /* Pointer to arguments */ @@ -549,7 +544,7 @@ mxmlNewReal(mxml_node_t *parent, /* I - Parent node or @code MXML_NO_PARENT@ */ mxml_node_t * /* O - New node */ mxmlNewText(mxml_node_t *parent, /* I - Parent node or @code MXML_NO_PARENT@ */ int whitespace, /* I - 1 = leading whitespace, 0 = no whitespace */ - const char *string) /* I - String */ + const char *string) /* I - String */ { mxml_node_t *node; /* New node */ @@ -593,8 +588,8 @@ mxmlNewText(mxml_node_t *parent, /* I - Parent node or @code MXML_NO_PARENT@ */ mxml_node_t * /* O - New node */ mxmlNewTextf(mxml_node_t *parent, /* I - Parent node or @code MXML_NO_PARENT@ */ int whitespace, /* I - 1 = leading whitespace, 0 = no whitespace */ - const char *format, /* I - Printf-style format string */ - ...) /* I - Additional args as needed */ + const char *format, /* I - Printf-style format string */ + ...) /* I - Additional args as needed */ { mxml_node_t *node; /* New node */ va_list ap; /* Pointer to arguments */ @@ -780,18 +775,18 @@ mxml_free(mxml_node_t *node) /* I - Node */ if (node->value.element.name) PhFree(node->value.element.name); - if (node->value.element.num_attrs) - { - for (i = 0; i < node->value.element.num_attrs; i ++) - { - if (node->value.element.attrs[i].name) + if (node->value.element.num_attrs) + { + for (i = 0; i < node->value.element.num_attrs; i ++) + { + if (node->value.element.attrs[i].name) PhFree(node->value.element.attrs[i].name); - if (node->value.element.attrs[i].value) + if (node->value.element.attrs[i].value) PhFree(node->value.element.attrs[i].value); - } + } PhFree(node->value.element.attrs); - } + } break; case MXML_INTEGER : /* Nothing to do */ @@ -809,9 +804,9 @@ mxml_free(mxml_node_t *node) /* I - Node */ break; case MXML_CUSTOM : if (node->value.custom.data && - node->value.custom.destroy) - (*(node->value.custom.destroy))(node->value.custom.data); - break; + node->value.custom.destroy) + (*(node->value.custom.destroy))(node->value.custom.data); + break; default : break; } diff --git a/phlib/mxml/mxml-private.c b/phlib/mxml/mxml-private.c index 0a0d787d02c5..726acc9a8705 100644 --- a/phlib/mxml/mxml-private.c +++ b/phlib/mxml/mxml-private.c @@ -1,15 +1,12 @@ /* * Private functions for Mini-XML, a small XML file parsing library. * - * Copyright 2003-2017 by Michael R Sweet. + * https://www.msweet.org/mxml * - * These coded instructions, statements, and computer programs are the - * property of Michael R Sweet and are protected by Federal copyright - * law. Distribution and use rights are outlined in the file "COPYING" - * which should have been included with this file. If this file is - * missing or damaged, see the license at: + * Copyright © 2003-2019 by Michael R Sweet. * - * https://michaelrsweet.github.io/mxml + * Licensed under Apache License v2.0. See the file "LICENSE" for more + * information. */ /* @@ -57,7 +54,7 @@ mxml_error(const char *format, /* I - Printf-style format string */ va_list ap; /* Pointer to arguments */ char s[1024]; /* Message string */ _mxml_global_t *global = _mxml_global(); - /* Global data */ + /* Global data */ /* @@ -145,7 +142,7 @@ mxml_real_cb(mxml_node_t *node) /* I - Current node */ static pthread_key_t _mxml_key = -1; /* Thread local storage key */ static pthread_once_t _mxml_key_once = PTHREAD_ONCE_INIT; - /* One-time initialization object */ + /* One-time initialization object */ static void _mxml_init(void); static void _mxml_destructor(void *g); @@ -219,7 +216,7 @@ _mxml_init(void) } -#elif defined(WIN32) && defined(MXML1_EXPORTS) /**** WIN32 threading ****/ +#elif defined(_WIN32) && defined(MXML1_EXPORTS) /**** WIN32 threading ****/ # include static DWORD _mxml_tls_index; /* Index for global storage */ diff --git a/phlib/mxml/mxml-private.h b/phlib/mxml/mxml-private.h index a78dcde16971..a97d76947748 100644 --- a/phlib/mxml/mxml-private.h +++ b/phlib/mxml/mxml-private.h @@ -1,15 +1,12 @@ /* * Private definitions for Mini-XML, a small XML file parsing library. * - * Copyright 2003-2017 by Michael R Sweet. + * https://www.msweet.org/mxml * - * These coded instructions, statements, and computer programs are the - * property of Michael R Sweet and are protected by Federal copyright - * law. Distribution and use rights are outlined in the file "COPYING" - * which should have been included with this file. If this file is - * missing or damaged, see the license at: + * Copyright © 2003-2019 by Michael R Sweet. * - * https://michaelrsweet.github.io/mxml + * Licensed under Apache License v2.0. See the file "LICENSE" for more + * information. */ /* @@ -21,10 +18,68 @@ /* - * Global, per-thread data... + * Private structures... */ -typedef struct _mxml_global_s +typedef struct _mxml_attr_s /**** An XML element attribute value. ****/ +{ + char *name; /* Attribute name */ + char *value; /* Attribute value */ +} _mxml_attr_t; + +typedef struct _mxml_element_s /**** An XML element value. ****/ +{ + char *name; /* Name of element */ + int num_attrs; /* Number of attributes */ + _mxml_attr_t *attrs; /* Attributes */ +} _mxml_element_t; + +typedef struct _mxml_text_s /**** An XML text value. ****/ +{ + int whitespace; /* Leading whitespace? */ + char *string; /* Fragment string */ +} _mxml_text_t; + +typedef struct _mxml_custom_s /**** An XML custom value. ****/ +{ + void *data; /* Pointer to (allocated) custom data */ + mxml_custom_destroy_cb_t destroy; /* Pointer to destructor function */ +} _mxml_custom_t; + +typedef union _mxml_value_u /**** An XML node value. ****/ +{ + _mxml_element_t element; /* Element */ + int integer; /* Integer number */ + char *opaque; /* Opaque string */ + double real; /* Real number */ + _mxml_text_t text; /* Text fragment */ + _mxml_custom_t custom; /* Custom data @since Mini-XML 2.1@ */ +} _mxml_value_t; + +struct _mxml_node_s /**** An XML node. ****/ +{ + mxml_type_t type; /* Node type */ + struct _mxml_node_s *next; /* Next node under same parent */ + struct _mxml_node_s *prev; /* Previous node under same parent */ + struct _mxml_node_s *parent; /* Parent node */ + struct _mxml_node_s *child; /* First child node */ + struct _mxml_node_s *last_child; /* Last child node */ + _mxml_value_t value; /* Node value */ + int ref_count; /* Use count */ + void *user_data; /* User data */ +}; + +struct _mxml_index_s /**** An XML node index. ****/ +{ + char *attr; /* Attribute used for indexing or NULL */ + int num_nodes; /* Number of nodes in index */ + int alloc_nodes; /* Allocated nodes in index */ + int cur_node; /* Current node */ + mxml_node_t **nodes; /* Node array */ +}; + +typedef struct _mxml_global_s /**** Global, per-thread data ****/ + { void (*error_cb)(const char *); int num_entity_cbs; diff --git a/phlib/mxml/mxml-search.c b/phlib/mxml/mxml-search.c index 9c6c7745ce16..8e2ef0afc29b 100644 --- a/phlib/mxml/mxml-search.c +++ b/phlib/mxml/mxml-search.c @@ -1,15 +1,12 @@ /* * Search/navigation functions for Mini-XML, a small XML file parsing library. * - * Copyright 2003-2017 by Michael R Sweet. + * https://www.msweet.org/mxml * - * These coded instructions, statements, and computer programs are the - * property of Michael R Sweet and are protected by Federal copyright - * law. Distribution and use rights are outlined in the file "COPYING" - * which should have been included with this file. If this file is - * missing or damaged, see the license at: + * Copyright © 2003-2019 by Michael R Sweet. * - * https://michaelrsweet.github.io/mxml + * Licensed under Apache License v2.0. See the file "LICENSE" for more + * information. */ /* @@ -17,7 +14,7 @@ */ #include "config.h" -#include "mxml.h" +#include "mxml-private.h" /* @@ -37,9 +34,9 @@ mxml_node_t * /* O - Element node or @code NULL@ */ mxmlFindElement(mxml_node_t *node, /* I - Current node */ mxml_node_t *top, /* I - Top node */ const char *element, /* I - Element name or @code NULL@ for any */ - const char *attr, /* I - Attribute name, or @code NULL@ for none */ - const char *value, /* I - Attribute value, or @code NULL@ for any */ - int descend) /* I - Descend into tree - @code MXML_DESCEND@, @code MXML_NO_DESCEND@, or @code MXML_DESCEND_FIRST@ */ + const char *attr, /* I - Attribute name, or @code NULL@ for none */ + const char *value, /* I - Attribute value, or @code NULL@ for any */ + int descend) /* I - Descend into tree - @code MXML_DESCEND@, @code MXML_NO_DESCEND@, or @code MXML_DESCEND_FIRST@ */ { const char *temp; /* Current attribute value */ @@ -69,7 +66,7 @@ mxmlFindElement(mxml_node_t *node, /* I - Current node */ if (node->type == MXML_ELEMENT && node->value.element.name && - (!element || !strcmp(node->value.element.name, element))) + (!element || !strcmp(node->value.element.name, element))) { /* * See if we need to check for an attribute... @@ -86,10 +83,10 @@ mxmlFindElement(mxml_node_t *node, /* I - Current node */ { /* * OK, we have the attribute, does it match? - */ + */ - if (!value || !strcmp(value, temp)) - return (node); /* Yes, return it... */ + if (!value || !strcmp(value, temp)) + return (node); /* Yes, return it... */ } } @@ -122,7 +119,7 @@ mxmlFindElement(mxml_node_t *node, /* I - Current node */ mxml_node_t * /* O - Found node or @code NULL@ */ mxmlFindPath(mxml_node_t *top, /* I - Top node */ - const char *path) /* I - Path to element */ + const char *path) /* I - Path to element */ { mxml_node_t *node; /* Current node */ char element[256]; /* Current element name */ diff --git a/phlib/mxml/mxml-set.c b/phlib/mxml/mxml-set.c index 5af723745825..cf8d0c105629 100644 --- a/phlib/mxml/mxml-set.c +++ b/phlib/mxml/mxml-set.c @@ -1,25 +1,20 @@ /* * Node set functions for Mini-XML, a small XML file parsing library. * - * Copyright 2003-2018 by Michael R Sweet. + * https://www.msweet.org/mxml * - * These coded instructions, statements, and computer programs are the - * property of Michael R Sweet and are protected by Federal copyright - * law. Distribution and use rights are outlined in the file "COPYING" - * which should have been included with this file. If this file is - * missing or damaged, see the license at: + * Copyright © 2003-2019 by Michael R Sweet. * - * https://michaelrsweet.github.io/mxml + * Licensed under Apache License v2.0. See the file "LICENSE" for more + * information. */ /* * Include necessary headers... */ -#include - #include "config.h" -#include "mxml.h" +#include "mxml-private.h" /* @@ -34,6 +29,9 @@ int /* O - 0 on success, -1 on failure */ mxmlSetCDATA(mxml_node_t *node, /* I - Node to set */ const char *data) /* I - New data string */ { + char *s; /* String pointer */ + + /* * Range check input... */ @@ -48,14 +46,19 @@ mxmlSetCDATA(mxml_node_t *node, /* I - Node to set */ strncmp(node->value.element.name, "![CDATA[", 8)) return (-1); + if (data == (node->value.element.name + 8)) + return (0); + /* - * Free any old element value and set the new value... + * Allocate the new value, free any old element value, and set the new value... */ + s = _mxml_strdupf("![CDATA[%s", data); + if (node->value.element.name) PhFree(node->value.element.name); - node->value.element.name = _mxml_strdupf("![CDATA[%s", data); + node->value.element.name = s; return (0); } @@ -86,6 +89,12 @@ mxmlSetCustom( if (!node || node->type != MXML_CUSTOM) return (-1); + if (data == node->value.custom.data) + { + node->value.custom.destroy = destroy; + return (0); + } + /* * Free any old element value and set the new value... */ @@ -117,6 +126,9 @@ mxmlSetElement(mxml_node_t *node, /* I - Node to set */ if (!node || node->type != MXML_ELEMENT || !name) return (-1); + if (name == node->value.element.name) + return (0); + /* * Free any old element value and set the new value... */ @@ -182,6 +194,9 @@ mxmlSetOpaque(mxml_node_t *node, /* I - Node to set */ if (!node || node->type != MXML_OPAQUE || !opaque) return (-1); + if (node->value.opaque == opaque) + return (0); + /* * Free any old opaque value and set the new value... */ @@ -206,9 +221,10 @@ mxmlSetOpaque(mxml_node_t *node, /* I - Node to set */ int /* O - 0 on success, -1 on failure */ mxmlSetOpaquef(mxml_node_t *node, /* I - Node to set */ const char *format, /* I - Printf-style format string */ - ...) /* I - Additional arguments as needed */ + ...) /* I - Additional arguments as needed */ { va_list ap; /* Pointer to arguments */ + char *s; /* Temporary string */ /* @@ -223,17 +239,17 @@ mxmlSetOpaquef(mxml_node_t *node, /* I - Node to set */ return (-1); /* - * Free any old string value and set the new value... + * Format the new string, free any old string value, and set the new value... */ - if (node->value.opaque) - PhFree(node->value.opaque); - va_start(ap, format); + s = _mxml_vstrdupf(format, ap); + va_end(ap); - node->value.opaque = _mxml_strdupf(format, ap); + if (node->value.opaque) + PhFree(node->value.opaque); - va_end(ap); + node->value.opaque = s; return (0); } @@ -279,7 +295,7 @@ mxmlSetReal(mxml_node_t *node, /* I - Node to set */ int /* O - 0 on success, -1 on failure */ mxmlSetText(mxml_node_t *node, /* I - Node to set */ int whitespace, /* I - 1 = leading whitespace, 0 = no whitespace */ - const char *string) /* I - String */ + const char *string) /* I - String */ { /* * Range check input... @@ -292,6 +308,12 @@ mxmlSetText(mxml_node_t *node, /* I - Node to set */ if (!node || node->type != MXML_TEXT || !string) return (-1); + if (string == node->value.text.string) + { + node->value.text.whitespace = whitespace; + return (0); + } + /* * Free any old string value and set the new value... */ @@ -316,9 +338,10 @@ int /* O - 0 on success, -1 on failure */ mxmlSetTextf(mxml_node_t *node, /* I - Node to set */ int whitespace, /* I - 1 = leading whitespace, 0 = no whitespace */ const char *format, /* I - Printf-style format string */ - ...) /* I - Additional arguments as needed */ + ...) /* I - Additional arguments as needed */ { va_list ap; /* Pointer to arguments */ + char *s; /* Temporary string */ /* @@ -336,15 +359,15 @@ mxmlSetTextf(mxml_node_t *node, /* I - Node to set */ * Free any old string value and set the new value... */ - if (node->value.text.string) - PhFree(node->value.text.string); - va_start(ap, format); + s = _mxml_vstrdupf(format, ap); + va_end(ap); - node->value.text.whitespace = whitespace; - node->value.text.string = _mxml_strdupf(format, ap); + if (node->value.text.string) + PhFree(node->value.text.string); - va_end(ap); + node->value.text.whitespace = whitespace; + node->value.text.string = s; return (0); } diff --git a/phlib/mxml/mxml-string.c b/phlib/mxml/mxml-string.c index c09c40dcb9d8..942087382dcf 100644 --- a/phlib/mxml/mxml-string.c +++ b/phlib/mxml/mxml-string.c @@ -1,25 +1,20 @@ /* * String functions for Mini-XML, a small XML file parsing library. * - * Copyright 2003-2018 by Michael R Sweet. + * https://www.msweet.org/mxml * - * These coded instructions, statements, and computer programs are the - * property of Michael R Sweet and are protected by Federal copyright - * law. Distribution and use rights are outlined in the file "COPYING" - * which should have been included with this file. If this file is - * missing or damaged, see the license at: + * Copyright © 2003-2019 by Michael R Sweet. * - * https://michaelrsweet.github.io/mxml + * Licensed under Apache License v2.0. See the file "LICENSE" for more + * information. */ /* * Include necessary headers... */ -#include - #include "config.h" - +#include "mxml-private.h" /* * The va_copy macro is part of C99, but many compilers don't implement it. @@ -43,8 +38,8 @@ int /* O - Number of bytes formatted */ _mxml_snprintf(char *buffer, /* I - Output buffer */ size_t bufsize, /* I - Size of output buffer */ - const char *format, /* I - Printf-style format string */ - ...) /* I - Additional arguments as needed */ + const char *format, /* I - Printf-style format string */ + ...) /* I - Additional arguments as needed */ { va_list ap; /* Argument list */ int bytes; /* Number of bytes formatted */ @@ -201,19 +196,19 @@ _mxml_strlcpy(char *dst, /* I - Destination buffer */ int /* O - Number of bytes formatted */ _mxml_vsnprintf(char *buffer, /* O - Output buffer */ size_t bufsize, /* O - Size of output buffer */ - const char *format, /* I - Printf-style format string */ - va_list ap) /* I - Pointer to additional arguments */ + const char *format, /* I - Printf-style format string */ + va_list ap) /* I - Pointer to additional arguments */ { char *bufptr, /* Pointer to position in buffer */ - *bufend, /* Pointer to end of buffer */ - sign, /* Sign of format width */ - size, /* Size character (h, l, L) */ - type; /* Format type character */ + *bufend, /* Pointer to end of buffer */ + sign, /* Sign of format width */ + size, /* Size character (h, l, L) */ + type; /* Format type character */ int width, /* Width of field */ - prec; /* Number of characters of precision */ + prec; /* Number of characters of precision */ char tformat[100], /* Temporary format string for sprintf() */ - *tptr, /* Pointer into temporary format */ - temp[1024]; /* Buffer for formatted numbers */ + *tptr, /* Pointer into temporary format */ + temp[1024]; /* Buffer for formatted numbers */ char *s; /* Pointer to string */ int slen; /* Length of string */ int bytes; /* Total number of bytes needed */ @@ -240,7 +235,7 @@ _mxml_vsnprintf(char *buffer, /* O - Output buffer */ *bufptr++ = *format; bytes ++; format ++; - continue; + continue; } else if (strchr(" -+#\'", *format)) { @@ -254,58 +249,58 @@ _mxml_vsnprintf(char *buffer, /* O - Output buffer */ { /* * Get width from argument... - */ + */ - format ++; - width = va_arg(ap, int); + format ++; + width = va_arg(ap, int); - snprintf(tptr, sizeof(tformat) - (tptr - tformat), "%d", width); - tptr += strlen(tptr); + snprintf(tptr, sizeof(tformat) - (tptr - tformat), "%d", width); + tptr += strlen(tptr); } else { - width = 0; + width = 0; - while (isdigit(*format & 255)) - { - if (tptr < (tformat + sizeof(tformat) - 1)) - *tptr++ = *format; + while (isdigit(*format & 255)) + { + if (tptr < (tformat + sizeof(tformat) - 1)) + *tptr++ = *format; - width = width * 10 + *format++ - '0'; - } + width = width * 10 + *format++ - '0'; + } } if (*format == '.') { - if (tptr < (tformat + sizeof(tformat) - 1)) - *tptr++ = *format; + if (tptr < (tformat + sizeof(tformat) - 1)) + *tptr++ = *format; format ++; if (*format == '*') - { + { /* - * Get precision from argument... - */ - - format ++; - prec = va_arg(ap, int); - - snprintf(tptr, sizeof(tformat) - (tptr - tformat), "%d", prec); - tptr += strlen(tptr); - } - else - { - prec = 0; - - while (isdigit(*format & 255)) - { - if (tptr < (tformat + sizeof(tformat) - 1)) - *tptr++ = *format; - - prec = prec * 10 + *format++ - '0'; - } - } + * Get precision from argument... + */ + + format ++; + prec = va_arg(ap, int); + + snprintf(tptr, sizeof(tformat) - (tptr - tformat), "%d", prec); + tptr += strlen(tptr); + } + else + { + prec = 0; + + while (isdigit(*format & 255)) + { + if (tptr < (tformat + sizeof(tformat) - 1)) + *tptr++ = *format; + + prec = prec * 10 + *format++ - '0'; + } + } } else prec = -1; @@ -314,18 +309,18 @@ _mxml_vsnprintf(char *buffer, /* O - Output buffer */ { size = 'L'; - if (tptr < (tformat + sizeof(tformat) - 2)) - { - *tptr++ = 'l'; - *tptr++ = 'l'; - } + if (tptr < (tformat + sizeof(tformat) - 2)) + { + *tptr++ = 'l'; + *tptr++ = 'l'; + } - format += 2; + format += 2; } else if (*format == 'h' || *format == 'l' || *format == 'L') { - if (tptr < (tformat + sizeof(tformat) - 1)) - *tptr++ = *format; + if (tptr < (tformat + sizeof(tformat) - 1)) + *tptr++ = *format; size = *format++; } @@ -341,145 +336,145 @@ _mxml_vsnprintf(char *buffer, /* O - Output buffer */ switch (type) { - case 'E' : /* Floating point formats */ - case 'G' : - case 'e' : - case 'f' : - case 'g' : - if ((width + 2) > sizeof(temp)) - break; + case 'E' : /* Floating point formats */ + case 'G' : + case 'e' : + case 'f' : + case 'g' : + if ((width + 2) > sizeof(temp)) + break; - sprintf(temp, tformat, va_arg(ap, double)); + sprintf(temp, tformat, va_arg(ap, double)); bytes += strlen(temp); if (bufptr) - { - if ((bufptr + strlen(temp)) > bufend) - { - strncpy(bufptr, temp, (size_t)(bufend - bufptr)); - bufptr = bufend; - } - else - { - strcpy(bufptr, temp); - bufptr += strlen(temp); - } - } - break; + { + if ((bufptr + strlen(temp)) > bufend) + { + strncpy(bufptr, temp, (size_t)(bufend - bufptr)); + bufptr = bufend; + } + else + { + strcpy(bufptr, temp); + bufptr += strlen(temp); + } + } + break; case 'B' : /* Integer formats */ - case 'X' : - case 'b' : + case 'X' : + case 'b' : case 'd' : - case 'i' : - case 'o' : - case 'u' : - case 'x' : - if ((width + 2) > sizeof(temp)) - break; + case 'i' : + case 'o' : + case 'u' : + case 'x' : + if ((width + 2) > sizeof(temp)) + break; #ifdef HAVE_LONG_LONG - if (size == 'L') - sprintf(temp, tformat, va_arg(ap, long long)); - else + if (size == 'L') + sprintf(temp, tformat, va_arg(ap, long long)); + else #endif /* HAVE_LONG_LONG */ - sprintf(temp, tformat, va_arg(ap, int)); + sprintf(temp, tformat, va_arg(ap, int)); bytes += strlen(temp); - if (bufptr) - { - if ((bufptr + strlen(temp)) > bufend) - { - strncpy(bufptr, temp, (size_t)(bufend - bufptr)); - bufptr = bufend; - } - else - { - strcpy(bufptr, temp); - bufptr += strlen(temp); - } - } - break; - - case 'p' : /* Pointer value */ - if ((width + 2) > sizeof(temp)) - break; - - sprintf(temp, tformat, va_arg(ap, void *)); + if (bufptr) + { + if ((bufptr + strlen(temp)) > bufend) + { + strncpy(bufptr, temp, (size_t)(bufend - bufptr)); + bufptr = bufend; + } + else + { + strcpy(bufptr, temp); + bufptr += strlen(temp); + } + } + break; + + case 'p' : /* Pointer value */ + if ((width + 2) > sizeof(temp)) + break; + + sprintf(temp, tformat, va_arg(ap, void *)); bytes += strlen(temp); - if (bufptr) - { - if ((bufptr + strlen(temp)) > bufend) - { - strncpy(bufptr, temp, (size_t)(bufend - bufptr)); - bufptr = bufend; - } - else - { - strcpy(bufptr, temp); - bufptr += strlen(temp); - } - } - break; + if (bufptr) + { + if ((bufptr + strlen(temp)) > bufend) + { + strncpy(bufptr, temp, (size_t)(bufend - bufptr)); + bufptr = bufend; + } + else + { + strcpy(bufptr, temp); + bufptr += strlen(temp); + } + } + break; case 'c' : /* Character or character array */ - bytes += width; - - if (bufptr) - { - if (width <= 1) - *bufptr++ = va_arg(ap, int); - else - { - if ((bufptr + width) > bufend) - width = bufend - bufptr; - - memcpy(bufptr, va_arg(ap, char *), (size_t)width); - bufptr += width; - } - } - break; - - case 's' : /* String */ - if ((s = va_arg(ap, char *)) == NULL) - s = "(null)"; - - slen = strlen(s); - if (slen > width && prec != width) - width = slen; + bytes += width; + + if (bufptr) + { + if (width <= 1) + *bufptr++ = va_arg(ap, int); + else + { + if ((bufptr + width) > bufend) + width = bufend - bufptr; + + memcpy(bufptr, va_arg(ap, char *), (size_t)width); + bufptr += width; + } + } + break; + + case 's' : /* String */ + if ((s = va_arg(ap, char *)) == NULL) + s = "(null)"; + + slen = strlen(s); + if (slen > width && prec != width) + width = slen; bytes += width; - if (bufptr) - { - if ((bufptr + width) > bufend) - width = bufend - bufptr; + if (bufptr) + { + if ((bufptr + width) > bufend) + width = bufend - bufptr; if (slen > width) - slen = width; - - if (sign == '-') - { - strncpy(bufptr, s, (size_t)slen); - memset(bufptr + slen, ' ', (size_t)(width - slen)); - } - else - { - memset(bufptr, ' ', (size_t)(width - slen)); - strncpy(bufptr + width - slen, s, (size_t)slen); - } - - bufptr += width; - } - break; - - case 'n' : /* Output number of chars so far */ - *(va_arg(ap, int *)) = bytes; - break; + slen = width; + + if (sign == '-') + { + strncpy(bufptr, s, (size_t)slen); + memset(bufptr + slen, ' ', (size_t)(width - slen)); + } + else + { + memset(bufptr, ' ', (size_t)(width - slen)); + strncpy(bufptr + width - slen, s, (size_t)slen); + } + + bufptr += width; + } + break; + + case 'n' : /* Output number of chars so far */ + *(va_arg(ap, int *)) = bytes; + break; } } else @@ -522,8 +517,7 @@ _mxml_vstrdupf(const char *format, /* I - Printf-style format string */ #else int bytes; /* Number of bytes required */ - char *buffer, /* String buffer */ - temp[256]; /* Small buffer for first vsnprintf */ + char *buffer; /* String buffer */ /* @@ -531,17 +525,15 @@ _mxml_vstrdupf(const char *format, /* I - Printf-style format string */ * needed... */ -# ifdef WIN32 +# ifdef _WIN32 bytes = _vscprintf(format, ap); # else va_list apcopy; /* Copy of argument list */ + char* temp[256]; /* Small buffer for first vsnprintf */ va_copy(apcopy, ap); - bytes = vsnprintf(temp, sizeof(temp), format, apcopy); -# endif /* WIN32 */ - - if (bytes < sizeof(temp)) + if ((bytes = vsnprintf(temp, sizeof(temp), format, apcopy)) < sizeof(temp)) { /* * Hey, the formatted string fits in the tiny buffer, so just dup that... @@ -549,10 +541,10 @@ _mxml_vstrdupf(const char *format, /* I - Printf-style format string */ return (PhDuplicateBytesZSafe(temp)); } +# endif /* _WIN32 */ /* - * Allocate memory for the whole thing and reformat to the new, larger - * buffer... + * Allocate memory for the whole thing and reformat to the new buffer... */ if ((buffer = PhAllocateExSafe(bytes + 1, HEAP_ZERO_MEMORY)) != NULL) diff --git a/phlib/mxml/mxml.h b/phlib/mxml/mxml.h index f2e07c02feab..79122d3adc2b 100644 --- a/phlib/mxml/mxml.h +++ b/phlib/mxml/mxml.h @@ -1,15 +1,12 @@ /* * Header file for Mini-XML, a small XML file parsing library. * - * Copyright 2003-2017 by Michael R Sweet. + * https://www.msweet.org/mxml * - * These coded instructions, statements, and computer programs are the - * property of Michael R Sweet and are protected by Federal copyright - * law. Distribution and use rights are outlined in the file "COPYING" - * which should have been included with this file. If this file is - * missing or damaged, see the license at: + * Copyright © 2003-2019 by Michael R Sweet. * - * https://michaelrsweet.github.io/mxml + * Licensed under Apache License v2.0. See the file "LICENSE" for more + * information. */ /* @@ -29,8 +26,8 @@ # include # include -// dmex: Include custom types. -#include + // dmex: custom headers. +#include #ifdef _PHAPP_ #define PHMXMLAPI __declspec(dllexport) @@ -43,21 +40,21 @@ * Constants... */ -# define MXML_MAJOR_VERSION 2 /* Major version number */ -# define MXML_MINOR_VERSION 12 /* Minor version number */ +# define MXML_MAJOR_VERSION 3 /* Major version number */ +# define MXML_MINOR_VERSION 0 /* Minor version number */ # define MXML_TAB 8 /* Tabs every N columns */ # define MXML_NO_CALLBACK 0 /* Don't use a type callback */ # define MXML_INTEGER_CALLBACK mxml_integer_cb - /* Treat all data as integers */ + /* Treat all data as integers */ # define MXML_OPAQUE_CALLBACK mxml_opaque_cb - /* Treat all data as opaque */ + /* Treat all data as opaque */ # define MXML_REAL_CALLBACK mxml_real_cb - /* Treat all data as real numbers */ + /* Treat all data as real numbers */ # define MXML_TEXT_CALLBACK 0 /* Treat all data as text */ # define MXML_IGNORE_CALLBACK mxml_ignore_cb - /* Ignore all non-element content */ + /* Ignore all non-element content */ # define MXML_NO_PARENT 0 /* No parent for the node */ @@ -101,90 +98,33 @@ typedef enum mxml_type_e /**** The XML node type. ****/ } mxml_type_t; typedef void (*mxml_custom_destroy_cb_t)(void *); - /**** Custom data destructor ****/ + /**** Custom data destructor ****/ typedef void (*mxml_error_cb_t)(const char *); - /**** Error callback function ****/ + /**** Error callback function ****/ -typedef struct mxml_attr_s /**** An XML element attribute value. @private@ ****/ -{ - char *name; /* Attribute name */ - char *value; /* Attribute value */ -} mxml_attr_t; - -typedef struct mxml_element_s /**** An XML element value. @private@ ****/ -{ - char *name; /* Name of element */ - int num_attrs; /* Number of attributes */ - mxml_attr_t *attrs; /* Attributes */ -} mxml_element_t; - -typedef struct mxml_text_s /**** An XML text value. @private@ ****/ -{ - int whitespace; /* Leading whitespace? */ - char *string; /* Fragment string */ -} mxml_text_t; - -typedef struct mxml_custom_s /**** An XML custom value. @private@ ****/ -{ - void *data; /* Pointer to (allocated) custom data */ - mxml_custom_destroy_cb_t destroy; /* Pointer to destructor function */ -} mxml_custom_t; - -typedef union mxml_value_u /**** An XML node value. @private@ ****/ -{ - mxml_element_t element; /* Element */ - int integer; /* Integer number */ - char *opaque; /* Opaque string */ - double real; /* Real number */ - mxml_text_t text; /* Text fragment */ - mxml_custom_t custom; /* Custom data @since Mini-XML 2.1@ */ -} mxml_value_t; - -struct mxml_node_s /**** An XML node. @private@ ****/ -{ - mxml_type_t type; /* Node type */ - struct mxml_node_s *next; /* Next node under same parent */ - struct mxml_node_s *prev; /* Previous node under same parent */ - struct mxml_node_s *parent; /* Parent node */ - struct mxml_node_s *child; /* First child node */ - struct mxml_node_s *last_child; /* Last child node */ - mxml_value_t value; /* Node value */ - int ref_count; /* Use count */ - void *user_data; /* User data */ -}; - -typedef struct mxml_node_s mxml_node_t; /**** An XML node. ****/ - -struct mxml_index_s /**** An XML node index. @private@ ****/ -{ - char *attr; /* Attribute used for indexing or NULL */ - int num_nodes; /* Number of nodes in index */ - int alloc_nodes; /* Allocated nodes in index */ - int cur_node; /* Current node */ - mxml_node_t **nodes; /* Node array */ -}; +typedef struct _mxml_node_s mxml_node_t; /**** An XML node. ****/ -typedef struct mxml_index_s mxml_index_t; - /**** An XML node index. ****/ +typedef struct _mxml_index_s mxml_index_t; + /**** An XML node index. ****/ typedef int (*mxml_custom_load_cb_t)(mxml_node_t *, const char *); - /**** Custom data load callback function ****/ + /**** Custom data load callback function ****/ typedef char *(*mxml_custom_save_cb_t)(mxml_node_t *); - /**** Custom data save callback function ****/ + /**** Custom data save callback function ****/ typedef int (*mxml_entity_cb_t)(const char *); - /**** Entity callback function */ + /**** Entity callback function */ typedef mxml_type_t (*mxml_load_cb_t)(mxml_node_t *); - /**** Load callback function ****/ + /**** Load callback function ****/ typedef const char *(*mxml_save_cb_t)(mxml_node_t *, int); - /**** Save callback function ****/ + /**** Save callback function ****/ typedef void (*mxml_sax_cb_t)(mxml_node_t *, mxml_sax_event_t, void *); - /**** SAX callback function ****/ + /**** SAX callback function ****/ /* @@ -200,17 +140,17 @@ extern "C" { */ PHMXMLAPI extern void mxmlAdd(mxml_node_t *parent, int where, - mxml_node_t *child, mxml_node_t *node); + mxml_node_t *child, mxml_node_t *node); PHMXMLAPI extern void mxmlDelete(mxml_node_t *node); PHMXMLAPI extern void mxmlElementDeleteAttr(mxml_node_t *node, - const char *name); + const char *name); PHMXMLAPI extern const char *mxmlElementGetAttr(mxml_node_t *node, const char *name); PHMXMLAPI extern const char *mxmlElementGetAttrByIndex(mxml_node_t *node, int idx, const char **name); PHMXMLAPI extern int mxmlElementGetAttrCount(mxml_node_t *node); PHMXMLAPI extern void mxmlElementSetAttr(mxml_node_t *node, const char *name, - const char *value); + const char *value); extern void mxmlElementSetAttrf(mxml_node_t *node, const char *name, - const char *format, ...) + const char *format, ...) # ifdef __GNUC__ __attribute__ ((__format__ (__printf__, 3, 4))) # endif /* __GNUC__ */ @@ -220,8 +160,8 @@ extern const char *mxmlEntityGetName(int val); extern int mxmlEntityGetValue(const char *name); extern void mxmlEntityRemoveCallback(mxml_entity_cb_t cb); PHMXMLAPI extern mxml_node_t *mxmlFindElement(mxml_node_t *node, mxml_node_t *top, - const char *element, const char *attr, - const char *value, int descend); + const char *element, const char *attr, + const char *value, int descend); extern mxml_node_t *mxmlFindPath(mxml_node_t *node, const char *path); extern const char *mxmlGetCDATA(mxml_node_t *node); extern const void *mxmlGetCustom(mxml_node_t *node); @@ -241,21 +181,21 @@ extern void *mxmlGetUserData(mxml_node_t *node); extern void mxmlIndexDelete(mxml_index_t *ind); extern mxml_node_t *mxmlIndexEnum(mxml_index_t *ind); extern mxml_node_t *mxmlIndexFind(mxml_index_t *ind, - const char *element, - const char *value); + const char *element, + const char *value); extern int mxmlIndexGetCount(mxml_index_t *ind); extern mxml_index_t *mxmlIndexNew(mxml_node_t *node, const char *element, - const char *attr); + const char *attr); extern mxml_node_t *mxmlIndexReset(mxml_index_t *ind); PHMXMLAPI extern mxml_node_t *mxmlLoadFd(mxml_node_t *top, HANDLE fd, - mxml_type_t (*cb)(mxml_node_t *)); + mxml_type_t (*cb)(mxml_node_t *)); extern mxml_node_t *mxmlLoadFile(mxml_node_t *top, FILE *fp, - mxml_type_t (*cb)(mxml_node_t *)); + mxml_type_t (*cb)(mxml_node_t *)); PHMXMLAPI extern mxml_node_t *mxmlLoadString(mxml_node_t *top, const char *s, - mxml_type_t (*cb)(mxml_node_t *)); + mxml_type_t (*cb)(mxml_node_t *)); PHMXMLAPI extern mxml_node_t *mxmlNewCDATA(mxml_node_t *parent, const char *string); PHMXMLAPI extern mxml_node_t *mxmlNewCustom(mxml_node_t *parent, void *data, - mxml_custom_destroy_cb_t destroy); + mxml_custom_destroy_cb_t destroy); PHMXMLAPI extern mxml_node_t *mxmlNewElement(mxml_node_t *parent, const char *name); PHMXMLAPI extern mxml_node_t *mxmlNewInteger(mxml_node_t *parent, int integer); PHMXMLAPI extern mxml_node_t *mxmlNewOpaque(mxml_node_t *parent, const char *opaque); @@ -276,27 +216,27 @@ PHMXMLAPI extern int mxmlRelease(mxml_node_t *node); PHMXMLAPI extern void mxmlRemove(mxml_node_t *node); PHMXMLAPI extern int mxmlRetain(mxml_node_t *node); PHMXMLAPI extern char *mxmlSaveAllocString(mxml_node_t *node, - mxml_save_cb_t cb); + mxml_save_cb_t cb); PHMXMLAPI extern int mxmlSaveFd(mxml_node_t *node, HANDLE fd, - mxml_save_cb_t cb); + mxml_save_cb_t cb); extern int mxmlSaveFile(mxml_node_t *node, FILE *fp, - mxml_save_cb_t cb); + mxml_save_cb_t cb); extern int mxmlSaveString(mxml_node_t *node, char *buffer, - int bufsize, mxml_save_cb_t cb); + int bufsize, mxml_save_cb_t cb); extern mxml_node_t *mxmlSAXLoadFd(mxml_node_t *top, HANDLE fd, - mxml_type_t (*cb)(mxml_node_t *), - mxml_sax_cb_t sax, void *sax_data); + mxml_type_t (*cb)(mxml_node_t *), + mxml_sax_cb_t sax, void *sax_data); extern mxml_node_t *mxmlSAXLoadFile(mxml_node_t *top, FILE *fp, - mxml_type_t (*cb)(mxml_node_t *), - mxml_sax_cb_t sax, void *sax_data); + mxml_type_t (*cb)(mxml_node_t *), + mxml_sax_cb_t sax, void *sax_data); extern mxml_node_t *mxmlSAXLoadString(mxml_node_t *top, const char *s, - mxml_type_t (*cb)(mxml_node_t *), - mxml_sax_cb_t sax, void *sax_data); + mxml_type_t (*cb)(mxml_node_t *), + mxml_sax_cb_t sax, void *sax_data); PHMXMLAPI extern int mxmlSetCDATA(mxml_node_t *node, const char *data); PHMXMLAPI extern int mxmlSetCustom(mxml_node_t *node, void *data, - mxml_custom_destroy_cb_t destroy); + mxml_custom_destroy_cb_t destroy); PHMXMLAPI extern void mxmlSetCustomHandlers(mxml_custom_load_cb_t load, - mxml_custom_save_cb_t save); + mxml_custom_save_cb_t save); PHMXMLAPI extern int mxmlSetElement(mxml_node_t *node, const char *name); PHMXMLAPI extern void mxmlSetErrorCallback(mxml_error_cb_t cb); extern int mxmlSetInteger(mxml_node_t *node, int integer); @@ -308,9 +248,9 @@ __attribute__ ((__format__ (__printf__, 2, 3))) ; extern int mxmlSetReal(mxml_node_t *node, double real); PHMXMLAPI extern int mxmlSetText(mxml_node_t *node, int whitespace, - const char *string); + const char *string); extern int mxmlSetTextf(mxml_node_t *node, int whitespace, - const char *format, ...) + const char *format, ...) # ifdef __GNUC__ __attribute__ ((__format__ (__printf__, 3, 4))) # endif /* __GNUC__ */ @@ -318,9 +258,9 @@ __attribute__ ((__format__ (__printf__, 3, 4))) PHMXMLAPI extern int mxmlSetUserData(mxml_node_t *node, void *data); extern void mxmlSetWrapMargin(int column); PHMXMLAPI extern mxml_node_t *mxmlWalkNext(mxml_node_t *node, mxml_node_t *top, - int descend); + int descend); PHMXMLAPI extern mxml_node_t *mxmlWalkPrev(mxml_node_t *node, mxml_node_t *top, - int descend); + int descend); /* From 2b3a90bdaf9833987c2dee09b90db130bd3574c2 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 3 Mar 2019 06:08:20 +0100 Subject: [PATCH 1736/2058] Update PCRE to 10.32 --- ProcessHacker/pcre/LICENCE | 33 +- ProcessHacker/pcre/README | 234 +- ProcessHacker/pcre/config.h | 105 +- ProcessHacker/pcre/dftables.c | 27 +- ProcessHacker/pcre/pcre2.h | 208 +- ProcessHacker/pcre/pcre2_auto_possess.c | 7 +- ProcessHacker/pcre/pcre2_chartables.c | 50 +- ProcessHacker/pcre/pcre2_compile.c | 336 +- ProcessHacker/pcre/pcre2_convert.c | 1182 +++ ProcessHacker/pcre/pcre2_dfa_match.c | 271 +- ProcessHacker/pcre/pcre2_error.c | 15 +- ProcessHacker/pcre/pcre2_extuni.c | 8 +- ProcessHacker/pcre/pcre2_find_bracket.c | 3 +- ProcessHacker/pcre/pcre2_fuzzsupport.c | 365 + ProcessHacker/pcre/pcre2_internal.h | 131 +- ProcessHacker/pcre/pcre2_intmodedep.h | 17 + ProcessHacker/pcre/pcre2_jit_compile.c | 37 +- ProcessHacker/pcre/pcre2_jit_test.c | 9 +- ProcessHacker/pcre/pcre2_maketables.c | 9 +- ProcessHacker/pcre/pcre2_match.c | 54 +- ProcessHacker/pcre/pcre2_pattern_info.c | 3 +- ProcessHacker/pcre/pcre2_printint.c | 3 +- ProcessHacker/pcre/pcre2_serialize.c | 22 +- ProcessHacker/pcre/pcre2_string_utils.c | 38 +- ProcessHacker/pcre/pcre2_study.c | 6 +- ProcessHacker/pcre/pcre2_substitute.c | 47 +- ProcessHacker/pcre/pcre2_tables.c | 378 +- ProcessHacker/pcre/pcre2_ucd.c | 6727 ++++++++--------- ProcessHacker/pcre/pcre2_ucp.h | 48 +- ProcessHacker/pcre/pcre2demo.c | 488 ++ ProcessHacker/pcre/pcre2grep.c | 4340 +++++++++++ ProcessHacker/pcre/pcre2posix.c | 14 +- ProcessHacker/pcre/pcre2test.c | 8789 +++++++++++++++++++++++ 33 files changed, 19964 insertions(+), 4040 deletions(-) create mode 100644 ProcessHacker/pcre/pcre2_convert.c create mode 100644 ProcessHacker/pcre/pcre2_fuzzsupport.c create mode 100644 ProcessHacker/pcre/pcre2demo.c create mode 100644 ProcessHacker/pcre/pcre2grep.c create mode 100644 ProcessHacker/pcre/pcre2test.c diff --git a/ProcessHacker/pcre/LICENCE b/ProcessHacker/pcre/LICENCE index 6600a659074f..b0f8804fffa0 100644 --- a/ProcessHacker/pcre/LICENCE +++ b/ProcessHacker/pcre/LICENCE @@ -4,10 +4,11 @@ PCRE2 LICENCE PCRE2 is a library of functions to support regular expressions whose syntax and semantics are as close as possible to those of the Perl 5 language. -Release 10 of PCRE2 is distributed under the terms of the "BSD" licence, as -specified below. The documentation for PCRE2, supplied in the "doc" -directory, is distributed under the same terms as the software itself. The data -in the testdata directory is not copyrighted and is in the public domain. +Releases 10.00 and above of PCRE2 are distributed under the terms of the "BSD" +licence, as specified below, with one exemption for certain binary +redistributions. The documentation for PCRE2, supplied in the "doc" directory, +is distributed under the same terms as the software itself. The data in the +testdata directory is not copyrighted and is in the public domain. The basic library functions are written in C and are freestanding. Also included in the distribution is a just-in-time compiler that can be used to @@ -25,7 +26,7 @@ Email domain: cam.ac.uk University of Cambridge Computing Service, Cambridge, England. -Copyright (c) 1997-2016 University of Cambridge +Copyright (c) 1997-2018 University of Cambridge All rights reserved. @@ -34,9 +35,9 @@ PCRE2 JUST-IN-TIME COMPILATION SUPPORT Written by: Zoltan Herczeg Email local part: hzmester -Emain domain: freemail.hu +Email domain: freemail.hu -Copyright(c) 2010-2016 Zoltan Herczeg +Copyright(c) 2010-2018 Zoltan Herczeg All rights reserved. @@ -45,9 +46,9 @@ STACK-LESS JUST-IN-TIME COMPILER Written by: Zoltan Herczeg Email local part: hzmester -Emain domain: freemail.hu +Email domain: freemail.hu -Copyright(c) 2009-2016 Zoltan Herczeg +Copyright(c) 2009-2018 Zoltan Herczeg All rights reserved. @@ -57,11 +58,11 @@ THE "BSD" LICENCE Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright notice, + * Redistributions of source code must retain the above copyright notices, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the + notices, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the University of Cambridge nor the names of any @@ -80,4 +81,14 @@ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +EXEMPTION FOR BINARY LIBRARY-LIKE PACKAGES +------------------------------------------ + +The second condition in the BSD licence (covering binary redistributions) does +not apply all the way down a chain of software. If binary package A includes +PCRE2, it must respect the condition, but if package B is software that +includes package A, the condition is not imposed on package B unless it uses +PCRE2 independently. + End diff --git a/ProcessHacker/pcre/README b/ProcessHacker/pcre/README index 48d2ffdd7cbc..2eb621b0ffcd 100644 --- a/ProcessHacker/pcre/README +++ b/ProcessHacker/pcre/README @@ -15,8 +15,8 @@ subscribe or manage your subscription here: https://lists.exim.org/mailman/listinfo/pcre-dev -Please read the NEWS file if you are upgrading from a previous release. -The contents of this README file are: +Please read the NEWS file if you are upgrading from a previous release. The +contents of this README file are: The PCRE2 APIs Documentation for PCRE2 @@ -44,8 +44,8 @@ wrappers. The distribution does contain a set of C wrapper functions for the 8-bit library that are based on the POSIX regular expression API (see the pcre2posix -man page). These can be found in a library called libpcre2posix. Note that this -just provides a POSIX calling interface to PCRE2; the regular expressions +man page). These can be found in a library called libpcre2-posix. Note that +this just provides a POSIX calling interface to PCRE2; the regular expressions themselves still follow Perl syntax and semantics. The POSIX API is restricted, and does not give full access to all of PCRE2's facilities. @@ -58,8 +58,8 @@ renamed or pointed at by a link. If you are using the POSIX interface to PCRE2 and there is already a POSIX regex library installed on your system, as well as worrying about the regex.h header file (as mentioned above), you must also take care when linking programs -to ensure that they link with PCRE2's libpcre2posix library. Otherwise they may -pick up the POSIX functions of the same name from the other library. +to ensure that they link with PCRE2's libpcre2-posix library. Otherwise they +may pick up the POSIX functions of the same name from the other library. One way of avoiding this confusion is to compile PCRE2 with the addition of -Dregcomp=PCRE2regcomp (and similarly for the other POSIX functions) to the @@ -95,10 +95,9 @@ PCRE2 documentation is supplied in two other forms: Building PCRE2 on non-Unix-like systems --------------------------------------- -For a non-Unix-like system, please read the comments in the file -NON-AUTOTOOLS-BUILD, though if your system supports the use of "configure" and -"make" you may be able to build PCRE2 using autotools in the same way as for -many Unix-like systems. +For a non-Unix-like system, please read the file NON-AUTOTOOLS-BUILD, though if +your system supports the use of "configure" and "make" you may be able to build +PCRE2 using autotools in the same way as for many Unix-like systems. PCRE2 can also be configured using CMake, which can be run in various ways (command line, GUI, etc). This creates Makefiles, solution files, etc. The file @@ -168,28 +167,30 @@ library. They are also documented in the pcre2build man page. built. If you want only the 16-bit or 32-bit library, use --disable-pcre2-8 to disable building the 8-bit library. -. If you want to include support for just-in-time compiling, which can give - large performance improvements on certain platforms, add --enable-jit to the - "configure" command. This support is available only for certain hardware +. If you want to include support for just-in-time (JIT) compiling, which can + give large performance improvements on certain platforms, add --enable-jit to + the "configure" command. This support is available only for certain hardware architectures. If you try to enable it on an unsupported architecture, there - will be a compile time error. - -. When JIT support is enabled, pcre2grep automatically makes use of it, unless - you add --disable-pcre2grep-jit to the "configure" command. - -. If you do not want to make use of the support for UTF-8 Unicode character - strings in the 8-bit library, UTF-16 Unicode character strings in the 16-bit - library, or UTF-32 Unicode character strings in the 32-bit library, you can - add --disable-unicode to the "configure" command. This reduces the size of - the libraries. It is not possible to configure one library with Unicode - support, and another without, in the same configuration. + will be a compile time error. If in doubt, use --enable-jit=auto, which + enables JIT only if the current hardware is supported. + +. If you are enabling JIT under SELinux you may also want to add + --enable-jit-sealloc, which enables the use of an execmem allocator in JIT + that is compatible with SELinux. This has no effect if JIT is not enabled. + +. If you do not want to make use of the default support for UTF-8 Unicode + character strings in the 8-bit library, UTF-16 Unicode character strings in + the 16-bit library, or UTF-32 Unicode character strings in the 32-bit + library, you can add --disable-unicode to the "configure" command. This + reduces the size of the libraries. It is not possible to configure one + library with Unicode support, and another without, in the same configuration. + It is also not possible to use --enable-ebcdic (see below) with Unicode + support, so if this option is set, you must also use --disable-unicode. When Unicode support is available, the use of a UTF encoding still has to be enabled by setting the PCRE2_UTF option at run time or starting a pattern with (*UTF). When PCRE2 is compiled with Unicode support, its input can only - either be ASCII or UTF-8/16/32, even when running on EBCDIC platforms. It is - not possible to use both --enable-unicode and --enable-ebcdic at the same - time. + either be ASCII or UTF-8/16/32, even when running on EBCDIC platforms. As well as supporting UTF strings, Unicode support includes support for the \P, \p, and \X sequences that recognize Unicode character properties. @@ -199,20 +200,14 @@ library. They are also documented in the pcre2build man page. or starting a pattern with (*UCP). . You can build PCRE2 to recognize either CR or LF or the sequence CRLF, or any - of the preceding, or any of the Unicode newline sequences, as indicating the - end of a line. Whatever you specify at build time is the default; the caller - of PCRE2 can change the selection at run time. The default newline indicator - is a single LF character (the Unix standard). You can specify the default - newline indicator by adding --enable-newline-is-cr, --enable-newline-is-lf, - --enable-newline-is-crlf, --enable-newline-is-anycrlf, or - --enable-newline-is-any to the "configure" command, respectively. - - If you specify --enable-newline-is-cr or --enable-newline-is-crlf, some of - the standard tests will fail, because the lines in the test files end with - LF. Even if the files are edited to change the line endings, there are likely - to be some failures. With --enable-newline-is-anycrlf or - --enable-newline-is-any, many tests should succeed, but there may be some - failures. + of the preceding, or any of the Unicode newline sequences, or the NUL (zero) + character as indicating the end of a line. Whatever you specify at build time + is the default; the caller of PCRE2 can change the selection at run time. The + default newline indicator is a single LF character (the Unix standard). You + can specify the default newline indicator by adding --enable-newline-is-cr, + --enable-newline-is-lf, --enable-newline-is-crlf, + --enable-newline-is-anycrlf, --enable-newline-is-any, or + --enable-newline-is-nul to the "configure" command, respectively. . By default, the sequence \R in a pattern matches any Unicode line ending sequence. This is independent of the option specifying what PCRE2 considers @@ -234,49 +229,47 @@ library. They are also documented in the pcre2build man page. --with-parens-nest-limit=500 -. PCRE2 has a counter that can be set to limit the amount of resources it uses - when matching a pattern. If the limit is exceeded during a match, the match - fails. The default is ten million. You can change the default by setting, for - example, +. PCRE2 has a counter that can be set to limit the amount of computing resource + it uses when matching a pattern. If the limit is exceeded during a match, the + match fails. The default is ten million. You can change the default by + setting, for example, --with-match-limit=500000 on the "configure" command. This is just the default; individual calls to - pcre2_match() can supply their own value. There is more discussion on the - pcre2api man page. + pcre2_match() or pcre2_dfa_match() can supply their own value. There is more + discussion in the pcre2api man page (search for pcre2_set_match_limit). + +. There is a separate counter that limits the depth of nested backtracking + (pcre2_match()) or nested function calls (pcre2_dfa_match()) during a + matching process, which indirectly limits the amount of heap memory that is + used, and in the case of pcre2_dfa_match() the amount of stack as well. This + counter also has a default of ten million, which is essentially "unlimited". + You can change the default by setting, for example, -. There is a separate counter that limits the depth of recursive function calls - during a matching process. This also has a default of ten million, which is - essentially "unlimited". You can change the default by setting, for example, + --with-match-limit-depth=5000 - --with-match-limit-recursion=500000 + There is more discussion in the pcre2api man page (search for + pcre2_set_depth_limit). - Recursive function calls use up the runtime stack; running out of stack can - cause programs to crash in strange ways. There is a discussion about stack - sizes in the pcre2stack man page. +. You can also set an explicit limit on the amount of heap memory used by + the pcre2_match() and pcre2_dfa_match() interpreters: + + --with-heap-limit=500 + + The units are kibibytes (units of 1024 bytes). This limit does not apply when + the JIT optimization (which has its own memory control features) is used. + There is more discussion on the pcre2api man page (search for + pcre2_set_heap_limit). . In the 8-bit library, the default maximum compiled pattern size is around - 64K. You can increase this by adding --with-link-size=3 to the "configure" - command. PCRE2 then uses three bytes instead of two for offsets to different - parts of the compiled pattern. In the 16-bit library, --with-link-size=3 is - the same as --with-link-size=4, which (in both libraries) uses four-byte - offsets. Increasing the internal link size reduces performance in the 8-bit - and 16-bit libraries. In the 32-bit library, the link size setting is - ignored, as 4-byte offsets are always used. - -. You can build PCRE2 so that its internal match() function that is called from - pcre2_match() does not call itself recursively. Instead, it uses memory - blocks obtained from the heap to save data that would otherwise be saved on - the stack. To build PCRE2 like this, use - - --disable-stack-for-recursion - - on the "configure" command. PCRE2 runs more slowly in this mode, but it may - be necessary in environments with limited stack sizes. This applies only to - the normal execution of the pcre2_match() function; if JIT support is being - successfully used, it is not relevant. Equally, it does not apply to - pcre2_dfa_match(), which does not use deeply nested recursion. There is a - discussion about stack sizes in the pcre2stack man page. + 64 kibibytes. You can increase this by adding --with-link-size=3 to the + "configure" command. PCRE2 then uses three bytes instead of two for offsets + to different parts of the compiled pattern. In the 16-bit library, + --with-link-size=3 is the same as --with-link-size=4, which (in both + libraries) uses four-byte offsets. Increasing the internal link size reduces + performance in the 8-bit and 16-bit libraries. In the 32-bit library, the + link size setting is ignored, as 4-byte offsets are always used. . For speed, PCRE2 uses four tables for manipulating and identifying characters whose code point values are less than 256. By default, it uses a set of @@ -324,6 +317,14 @@ library. They are also documented in the pcre2build man page. running "make" to build PCRE2. There is more information about coverage reporting in the "pcre2build" documentation. +. When JIT support is enabled, pcre2grep automatically makes use of it, unless + you add --disable-pcre2grep-jit to the "configure" command. + +. There is support for calling external programs during matching in the + pcre2grep command, using PCRE2's callout facility with string arguments. This + support can be disabled by adding --disable-pcre2grep-callout to the + "configure" command. + . The pcre2grep program currently supports only 8-bit data files, and so requires the 8-bit PCRE2 library. It is possible to compile pcre2grep to use libz and/or libbz2, in order to read .gz and .bz2 files (respectively), by @@ -334,12 +335,23 @@ library. They are also documented in the pcre2build man page. Of course, the relevant libraries must be installed on your system. -. The default size (in bytes) of the internal buffer used by pcre2grep can be - set by, for example: +. The default starting size (in bytes) of the internal buffer used by pcre2grep + can be set by, for example: --with-pcre2grep-bufsize=51200 - The value must be a plain integer. The default is 20480. + The value must be a plain integer. The default is 20480. The amount of memory + used by pcre2grep is actually three times this number, to allow for "before" + and "after" lines. If very long lines are encountered, the buffer is + automatically enlarged, up to a fixed maximum size. + +. The default maximum size of pcre2grep's internal buffer can be set by, for + example: + + --with-pcre2grep-max-bufsize=2097152 + + The default is either 1048576 or the value of --with-pcre2grep-bufsize, + whichever is the larger. . It is possible to compile pcre2test so that it links with the libreadline or libedit libraries, by specifying, respectively, @@ -364,6 +376,29 @@ library. They are also documented in the pcre2build man page. tgetflag, or tgoto, this is the problem, and linking with the ncurses library should fix it. +. There is a special option called --enable-fuzz-support for use by people who + want to run fuzzing tests on PCRE2. At present this applies only to the 8-bit + library. If set, it causes an extra library called libpcre2-fuzzsupport.a to + be built, but not installed. This contains a single function called + LLVMFuzzerTestOneInput() whose arguments are a pointer to a string and the + length of the string. When called, this function tries to compile the string + as a pattern, and if that succeeds, to match it. This is done both with no + options and with some random options bits that are generated from the string. + Setting --enable-fuzz-support also causes a binary called pcre2fuzzcheck to + be created. This is normally run under valgrind or used when PCRE2 is + compiled with address sanitizing enabled. It calls the fuzzing function and + outputs information about it is doing. The input strings are specified by + arguments: if an argument starts with "=" the rest of it is a literal input + string. Otherwise, it is assumed to be a file name, and the contents of the + file are the test string. + +. Releases before 10.30 could be compiled with --disable-stack-for-recursion, + which caused pcre2_match() to use individual blocks on the heap for + backtracking instead of recursive function calls (which use the stack). This + is now obsolete since pcre2_match() was refactored always to use the heap (in + a much more efficient way than before). This option is retained for backwards + compatibility, but has no effect other than to output a warning. + The "configure" script builds the following files for the basic C library: . Makefile the makefile that builds the library @@ -538,7 +573,7 @@ script creates the .txt and HTML forms of the documentation from the man pages. Testing PCRE2 ------------- +------------- To test the basic PCRE2 library on a Unix-like system, run the RunTest script. There is another script called RunGrepTest that tests the pcre2grep command. @@ -630,32 +665,43 @@ with the perltest.sh script, and test 5 checking PCRE2-specific things. Tests 6 and 7 check the pcre2_dfa_match() alternative matching function, in non-UTF mode and UTF-mode with Unicode property support, respectively. -Test 8 checks some internal offsets and code size features; it is run only when -the default "link size" of 2 is set (in other cases the sizes change) and when -Unicode support is enabled. +Test 8 checks some internal offsets and code size features, but it is run only +when Unicode support is enabled. The output is different in 8-bit, 16-bit, and +32-bit modes and for different link sizes, so there are different output files +for each mode and link size. Tests 9 and 10 are run only in 8-bit mode, and tests 11 and 12 are run only in 16-bit and 32-bit modes. These are tests that generate different output in 8-bit mode. Each pair are for general cases and Unicode support, respectively. + Test 13 checks the handling of non-UTF characters greater than 255 by pcre2_dfa_match() in 16-bit and 32-bit modes. -Test 14 contains a number of tests that must not be run with JIT. They check, +Test 14 contains some special UTF and UCP tests that give different output for +different code unit widths. + +Test 15 contains a number of tests that must not be run with JIT. They check, among other non-JIT things, the match-limiting features of the intepretive matcher. -Test 15 is run only when JIT support is not available. It checks that an +Test 16 is run only when JIT support is not available. It checks that an attempt to use JIT has the expected behaviour. -Test 16 is run only when JIT support is available. It checks JIT complete and +Test 17 is run only when JIT support is available. It checks JIT complete and partial modes, match-limiting under JIT, and other JIT-specific features. -Tests 17 and 18 are run only in 8-bit mode. They check the POSIX interface to +Tests 18 and 19 are run only in 8-bit mode. They check the POSIX interface to the 8-bit library, without and with Unicode support, respectively. -Test 19 checks the serialization functions by writing a set of compiled +Test 20 checks the serialization functions by writing a set of compiled patterns to a file, and then reloading and checking them. +Tests 21 and 22 test \C support when the use of \C is not locked out, without +and with UTF support, respectively. Test 23 tests \C when it is locked out. + +Tests 24 and 25 test the experimental pattern conversion functions, without and +with UTF support, respectively. + Character tables ---------------- @@ -674,7 +720,7 @@ specified for ./configure, a different version of pcre2_chartables.c is built by the program dftables (compiled from dftables.c), which uses the ANSI C character handling functions such as isalnum(), isalpha(), isupper(), islower(), etc. to build the table sources. This means that the default C -locale which is set for your system will control the contents of these default +locale that is set for your system will control the contents of these default tables. You can change the default tables by editing pcre2_chartables.c and then re-building PCRE2. If you do this, you should take care to ensure that the file does not get automatically re-generated. The best way to do this is to @@ -729,8 +775,10 @@ The distribution should contain the files listed below. src/pcre2_compile.c ) src/pcre2_config.c ) src/pcre2_context.c ) + src/pcre2_convert.c ) src/pcre2_dfa_match.c ) src/pcre2_error.c ) + src/pcre2_extuni.c ) src/pcre2_find_bracket.c ) src/pcre2_jit_compile.c ) src/pcre2_jit_match.c ) sources for the functions in the library, @@ -752,6 +800,7 @@ The distribution should contain the files listed below. src/pcre2_xclass.c ) src/pcre2_printint.c debugging function that is used by pcre2test, + src/pcre2_fuzzsupport.c function for (optional) fuzzing support src/config.h.in template for config.h, when built by "configure" src/pcre2.h.in template for pcre2.h when built by "configure" @@ -767,7 +816,6 @@ The distribution should contain the files listed below. src/pcre2demo.c simple demonstration of coding calls to PCRE2 src/pcre2grep.c source of a grep utility that uses PCRE2 src/pcre2test.c comprehensive test program - src/pcre2_printint.c part of pcre2test src/pcre2_jit_test.c JIT test program (C) Auxiliary files: @@ -809,7 +857,7 @@ The distribution should contain the files listed below. libpcre2-8.pc.in template for libpcre2-8.pc for pkg-config libpcre2-16.pc.in template for libpcre2-16.pc for pkg-config libpcre2-32.pc.in template for libpcre2-32.pc for pkg-config - libpcre2posix.pc.in template for libpcre2posix.pc for pkg-config + libpcre2-posix.pc.in template for libpcre2-posix.pc for pkg-config ltmain.sh file used to build a libtool script missing ) common stub for a few missing GNU programs while ) installing, generated by automake @@ -832,12 +880,12 @@ The distribution should contain the files listed below. (E) Auxiliary files for building PCRE2 "by hand" - pcre2.h.generic ) a version of the public PCRE2 header file + src/pcre2.h.generic ) a version of the public PCRE2 header file ) for use in non-"configure" environments - config.h.generic ) a version of config.h for use in non-"configure" + src/config.h.generic ) a version of config.h for use in non-"configure" ) environments Philip Hazel Email local part: ph10 Email domain: cam.ac.uk -Last updated: 16 October 2015 +Last updated: 17 June 2018 diff --git a/ProcessHacker/pcre/config.h b/ProcessHacker/pcre/config.h index c15b764c4783..05cd1469c416 100644 --- a/ProcessHacker/pcre/config.h +++ b/ProcessHacker/pcre/config.h @@ -18,10 +18,10 @@ to set the macro values. In this case, you do not have to set -DHAVE_CONFIG_H, but if you do, default values will be taken from config.h for non-boolean macros that are not defined on the command line. -Boolean macros such as HAVE_STDLIB_H and SUPPORT_PCRE2_8 should either be defined -(conventionally to 1) for TRUE, and not defined at all for FALSE. All such -macros are listed as a commented #undef in config.h.generic. Macros such as -MATCH_LIMIT, whose actual value is relevant, have defaults defined, but are +Boolean macros such as HAVE_STDLIB_H and SUPPORT_PCRE2_8 should either be +defined (conventionally to 1) for TRUE, and not defined at all for FALSE. All +such macros are listed as a commented #undef in config.h.generic. Macros such +as MATCH_LIMIT, whose actual value is relevant, have defaults defined, but are surrounded by #ifndef/#endif lines so that the value can be overridden by -D. PCRE2 uses memmove() if HAVE_MEMMOVE is defined; otherwise it uses bcopy() if @@ -37,37 +37,36 @@ sure both macros are undefined; an emulation function will then be used. */ #define BSR_ANYCRLF 1 #endif - /* If you are compiling for a system that uses EBCDIC instead of ASCII character codes, define this macro to any value. When EBCDIC is set, PCRE2 assumes that all input strings are in EBCDIC. If you do not define this macro, PCRE2 will assume input strings are ASCII or UTF-8/16/32 Unicode. It is not possible to build a version of PCRE2 that supports both EBCDIC and UTF-8/16/32. */ -#undef EBCDIC +/* #undef EBCDIC */ /* In an EBCDIC environment, define this macro to any value to arrange for the NL character to be 0x25 instead of the default 0x15. NL plays the role that LF does in an ASCII/Unicode environment. */ -#undef EBCDIC_NL25 +/* #undef EBCDIC_NL25 */ /* Define to 1 if you have the `bcopy' function. */ -#undef HAVE_BCOPY +/* #undef HAVE_BCOPY */ /* Define to 1 if you have the header file. */ -#undef HAVE_BZLIB_H +/* #undef HAVE_BZLIB_H */ /* Define to 1 if you have the header file. */ -#undef HAVE_DIRENT_H +/* #undef HAVE_DIRENT_H */ /* Define to 1 if you have the header file. */ -#undef HAVE_DLFCN_H +/* #undef HAVE_DLFCN_H */ /* Define to 1 if you have the header file. */ -#undef HAVE_EDITLINE_READLINE_H +/* #undef HAVE_EDITLINE_READLINE_H */ /* Define to 1 if you have the header file. */ -#undef HAVE_EDIT_READLINE_READLINE_H +/* #undef HAVE_EDIT_READLINE_READLINE_H */ /* Define to 1 if you have the header file. */ #ifndef HAVE_INTTYPES_H @@ -90,22 +89,22 @@ sure both macros are undefined; an emulation function will then be used. */ #endif /* Define to 1 if you have the `mkostemp' function. */ -#undef HAVE_MKOSTEMP +/* #undef HAVE_MKOSTEMP */ /* Define if you have POSIX threads libraries and header files. */ -#undef HAVE_PTHREAD +/* #undef HAVE_PTHREAD */ /* Have PTHREAD_PRIO_INHERIT. */ -#undef HAVE_PTHREAD_PRIO_INHERIT +/* #undef HAVE_PTHREAD_PRIO_INHERIT */ /* Define to 1 if you have the header file. */ -#undef HAVE_READLINE_HISTORY_H +/* #undef HAVE_READLINE_HISTORY_H */ /* Define to 1 if you have the header file. */ -#undef HAVE_READLINE_READLINE_H +/* #undef HAVE_READLINE_READLINE_H */ /* Define to 1 if you have the `secure_getenv' function. */ -#undef HAVE_SECURE_GETENV +/* #undef HAVE_SECURE_GETENV */ /* Define to 1 if you have the header file. */ #ifndef HAVE_STDINT_H @@ -123,7 +122,7 @@ sure both macros are undefined; an emulation function will then be used. */ #endif /* Define to 1 if you have the header file. */ -#undef HAVE_STRINGS_H +/* #undef HAVE_STRINGS_H */ /* Define to 1 if you have the header file. */ #ifndef HAVE_STRING_H @@ -141,13 +140,13 @@ sure both macros are undefined; an emulation function will then be used. */ #endif /* Define to 1 if you have the header file. */ -#undef HAVE_SYS_WAIT_H +/* #undef HAVE_SYS_WAIT_H */ /* Define to 1 if you have the header file. */ -#undef HAVE_UNISTD_H +/* #undef HAVE_UNISTD_H */ /* Define to 1 if the compiler supports simple visibility declarations. */ -#undef HAVE_VISIBILITY +/* #undef HAVE_VISIBILITY */ /* Define to 1 if you have the header file. */ #ifndef HAVE_WINDOWS_H @@ -155,19 +154,20 @@ sure both macros are undefined; an emulation function will then be used. */ #endif /* Define to 1 if you have the header file. */ -#undef HAVE_ZLIB_H +/* #undef HAVE_ZLIB_H */ -/* This limits the amount of memory that pcre2_match() may use while matching - a pattern. The value is in kilobytes. */ +/* This limits the amount of memory that may be used while matching a pattern. + It applies to both pcre2_match() and pcre2_dfa_match(). It does not apply + to JIT matching. The value is in kibibytes (units of 1024 bytes). */ #ifndef HEAP_LIMIT #define HEAP_LIMIT 20000000 #endif /* The value of LINK_SIZE determines the number of bytes used to store links as offsets within the compiled regex. The default is 2, which allows for - compiled patterns up to 64K long. This covers the vast majority of cases. - However, PCRE2 can also be compiled to use 3 or 4 bytes instead. This - allows for longer patterns in extreme cases. */ + compiled patterns up to 65535 code units long. This covers the vast + majority of cases. However, PCRE2 can also be compiled to use 3 or 4 bytes + instead. This allows for longer patterns in extreme cases. */ #ifndef LINK_SIZE #define LINK_SIZE 2 #endif @@ -180,7 +180,8 @@ sure both macros are undefined; an emulation function will then be used. */ /* The value of MATCH_LIMIT determines the default number of times the pcre2_match() function can record a backtrack position during a single - matching attempt. There is a runtime interface for setting a different + matching attempt. The value is also used to limit a loop counter in + pcre2_dfa_match(). There is a runtime interface for setting a different limit. The limit exists in order to catch runaway regular expressions that take for ever to determine that they do not match. The default is set very large so that it does not accidentally catch legitimate cases. */ @@ -195,7 +196,9 @@ sure both macros are undefined; an emulation function will then be used. */ MATCH_LIMIT_DEPTH provides this facility. To have any useful effect, it must be less than the value of MATCH_LIMIT. The default is to use the same value as MATCH_LIMIT. There is a runtime method for setting a different - limit. */ + limit. In the case of pcre2_dfa_match(), this limit controls the depth of + the internal nested function calls that are used for pattern recursions, + lookarounds, and atomic groups. */ #ifndef MATCH_LIMIT_DEPTH #define MATCH_LIMIT_DEPTH MATCH_LIMIT #endif @@ -215,7 +218,7 @@ sure both macros are undefined; an emulation function will then be used. */ #endif /* Defining NEVER_BACKSLASH_C locks out the use of \C in all patterns. */ -#undef NEVER_BACKSLASH_C +/* #undef NEVER_BACKSLASH_C */ /* The value of NEWLINE_DEFAULT determines the default newline character sequence. PCRE2 client programs can override this by selecting other values @@ -235,7 +238,7 @@ sure both macros are undefined; an emulation function will then be used. */ #define PACKAGE_NAME "PCRE2" /* Define to the full name and version of this package. */ -#define PACKAGE_STRING "PCRE2 10.31" +#define PACKAGE_STRING "PCRE2 10.32" /* Define to the one symbol short name of this package. */ #define PACKAGE_TARNAME "pcre2" @@ -244,7 +247,7 @@ sure both macros are undefined; an emulation function will then be used. */ #define PACKAGE_URL "" /* Define to the version of this package. */ -#define PACKAGE_VERSION "10.31" +#define PACKAGE_VERSION "10.32" /* The value of PARENS_NEST_LIMIT specifies the maximum depth of nested parentheses (of any kind) in a pattern. This limits the amount of system @@ -272,7 +275,7 @@ sure both macros are undefined; an emulation function will then be used. */ #endif /* Define to any value to include debugging code. */ -#undef PCRE2_DEBUG +/* #undef PCRE2_DEBUG */ /* If you are compiling for a system other than a Unix-like system or Win32, and it needs some magic to be inserted before the definition @@ -283,7 +286,7 @@ sure both macros are undefined; an emulation function will then be used. */ This macro apears at the start of every exported function that is part of the external API. It does not appear on functions that are "external" in the C sense, but which are internal to the library. */ -#undef PCRE2_EXP_DEFN +/* #undef PCRE2_EXP_DEFN */ /* Define to any value if linking statically (TODO: make nice with Libtool) */ #ifndef PCRE2_STATIC @@ -292,7 +295,7 @@ sure both macros are undefined; an emulation function will then be used. */ /* Define to necessary symbol if this constant uses a non-standard name on your system. */ -#undef PTHREAD_CREATE_JOINABLE +/* #undef PTHREAD_CREATE_JOINABLE */ /* Define to any non-zero number to enable support for SELinux compatible executable memory allocator in JIT. Note that this will have no effect @@ -305,28 +308,28 @@ sure both macros are undefined; an emulation function will then be used. */ #endif /* Define to any value to enable support for Just-In-Time compiling. */ -#undef SUPPORT_JIT +/* #undef SUPPORT_JIT */ /* Define to any value to allow pcre2grep to be linked with libbz2, so that it is able to handle .bz2 files. */ -#undef SUPPORT_LIBBZ2 +/* #undef SUPPORT_LIBBZ2 */ /* Define to any value to allow pcre2test to be linked with libedit. */ -#undef SUPPORT_LIBEDIT +/* #undef SUPPORT_LIBEDIT */ /* Define to any value to allow pcre2test to be linked with libreadline. */ -#undef SUPPORT_LIBREADLINE +/* #undef SUPPORT_LIBREADLINE */ /* Define to any value to allow pcre2grep to be linked with libz, so that it is able to handle .gz files. */ -#undef SUPPORT_LIBZ +/* #undef SUPPORT_LIBZ */ /* Define to any value to enable callout script support in pcre2grep. */ -#undef SUPPORT_PCRE2GREP_CALLOUT +/* #undef SUPPORT_PCRE2GREP_CALLOUT */ /* Define to any value to enable JIT support in pcre2grep. Note that this will have no effect unless SUPPORT_JIT is also defined. */ -#undef SUPPORT_PCRE2GREP_JIT +/* #undef SUPPORT_PCRE2GREP_JIT */ /* Define to any value to enable the 16 bit PCRE2 library. */ #ifndef SUPPORT_PCRE2_16 @@ -334,10 +337,10 @@ sure both macros are undefined; an emulation function will then be used. */ #endif /* Define to any value to enable the 32 bit PCRE2 library. */ -#undef SUPPORT_PCRE2_32 +/* #undef SUPPORT_PCRE2_32 */ /* Define to any value to enable the 8 bit PCRE2 library. */ -#undef SUPPORT_PCRE2_8 +/* #undef SUPPORT_PCRE2_8 */ /* Define to any value to enable support for Unicode and UTF encoding. This will work even in an EBCDIC environment, but it is incompatible with the @@ -348,7 +351,7 @@ sure both macros are undefined; an emulation function will then be used. */ #endif /* Define to any value for valgrind support to find invalid memory reads. */ -#undef SUPPORT_VALGRIND +/* #undef SUPPORT_VALGRIND */ /* Enable extensions on AIX 3, Interix. */ #ifndef _ALL_SOURCE @@ -372,17 +375,17 @@ sure both macros are undefined; an emulation function will then be used. */ #endif /* Version number of package */ -#define VERSION "10.31" +#define VERSION "10.32" /* Define to 1 if on MINIX. */ -#undef _MINIX +/* #undef _MINIX */ /* Define to 2 if the system does not provide POSIX.1 features except with this defined. */ -#undef _POSIX_1_SOURCE +/* #undef _POSIX_1_SOURCE */ /* Define to 1 if you need to in order for `stat' and other things to work. */ -#undef _POSIX_SOURCE +/* #undef _POSIX_SOURCE */ /* Define to empty if `const' does not conform to ANSI C. */ /* #undef const */ diff --git a/ProcessHacker/pcre/dftables.c b/ProcessHacker/pcre/dftables.c index dfb90b594a45..c0af36252a81 100644 --- a/ProcessHacker/pcre/dftables.c +++ b/ProcessHacker/pcre/dftables.c @@ -7,7 +7,7 @@ and semantics are as close as possible to those of the Perl 5 language. Written by Philip Hazel Original API code Copyright (c) 1997-2012 University of Cambridge - New API code Copyright (c) 2016 University of Cambridge + New API code Copyright (c) 2016-2018 University of Cambridge ----------------------------------------------------------------------------- Redistribution and use in source and binary forms, with or without @@ -104,6 +104,14 @@ fprintf(f, "tables are passed to PCRE2 by the application that calls it. The tables\n" "are used only for characters whose code values are less than 256. */\n\n"); +fprintf(f, + "/*The dftables program (which is distributed with PCRE2) can be used to\n" + "build alternative versions of this file. This is necessary if you are\n" + "running in an EBCDIC environment, or if you want to default to a different\n" + "encoding, for example ISO-8859-1. When dftables is run, it creates these\n" + "tables in the current locale. This happens automatically if PCRE2 is\n" + "configured with --enable-rebuild-chartables. */\n\n"); + /* Force config.h in z/OS */ #if defined NATIVE_ZOS @@ -115,7 +123,7 @@ fprintf(f, #endif fprintf(f, - "/* The following #includes are present because without them gcc 4.x may remove\n" + "/* The following #include is present because without it gcc 4.x may remove\n" "the array definition from the final binary if PCRE2 is built into a static\n" "library and dead code stripping is activated. This leads to link errors.\n" "Pulling in the header ensures that the array gets flagged as \"someone\n" @@ -153,11 +161,10 @@ for (i = 0; i < 256; i++) fprintf(f, ",\n\n"); fprintf(f, - "/* This table contains bit maps for various character classes.\n" - "Each map is 32 bytes long and the bits run from the least\n" - "significant end of each byte. The classes that have their own\n" - "maps are: space, xdigit, digit, upper, lower, word, graph\n" - "print, punct, and cntrl. Other classes are built from combinations. */\n\n"); + "/* This table contains bit maps for various character classes. Each map is 32\n" + "bytes long and the bits run from the least significant end of each byte. The\n" + "classes that have their own maps are: space, xdigit, digit, upper, lower, word,\n" + "graph print, punct, and cntrl. Other classes are built from combinations. */\n\n"); fprintf(f, " "); for (i = 0; i < cbit_length; i++) @@ -178,10 +185,8 @@ fprintf(f, " 0x%02x letter\n" " 0x%02x decimal digit\n" " 0x%02x hexadecimal digit\n" - " 0x%02x alphanumeric or '_'\n" - " 0x%02x regular expression metacharacter or binary zero\n*/\n\n", - ctype_space, ctype_letter, ctype_digit, ctype_xdigit, ctype_word, - ctype_meta); + " 0x%02x alphanumeric or '_'\n*/\n\n", + ctype_space, ctype_letter, ctype_digit, ctype_xdigit, ctype_word); fprintf(f, " "); for (i = 0; i < 256; i++) diff --git a/ProcessHacker/pcre/pcre2.h b/ProcessHacker/pcre/pcre2.h index ac15ba885be1..dfbc75677a39 100644 --- a/ProcessHacker/pcre/pcre2.h +++ b/ProcessHacker/pcre/pcre2.h @@ -5,7 +5,7 @@ /* This is the public header file for the PCRE library, second API, to be #included by applications that call PCRE2 functions. - Copyright (c) 2016-2017 University of Cambridge + Copyright (c) 2016-2018 University of Cambridge ----------------------------------------------------------------------------- Redistribution and use in source and binary forms, with or without @@ -47,10 +47,16 @@ POSSIBILITY OF SUCH DAMAGE. /* The current PCRE version information. */ -#define PCRE2_MAJOR 10 -#define PCRE2_MINOR 31 -#define PCRE2_PRERELEASE -#define PCRE2_DATE 2018-02-12 +#define PCRE2_MAJOR 10 +#define PCRE2_MINOR 32 +#define PCRE2_PRERELEASE +#define PCRE2_DATE 2018-09-10 + +/* For the benefit of systems without stdint.h, an alternative is to use +inttypes.h. The existence of these headers is checked by configure or CMake. */ + +#define PCRE2_HAVE_STDINT_H 1 +#define PCRE2_HAVE_INTTYPES_H 1 /* When an application links to a PCRE DLL in Windows, the symbols that are imported have to be identified as such. When building PCRE2, the appropriate @@ -87,12 +93,18 @@ set, we ensure here that it has no effect. */ #define PCRE2_CALL_CONVENTION #endif -/* Have to include limits.h, stdlib.h and stdint.h to ensure that size_t and -uint8_t, UCHAR_MAX, etc are defined. */ +/* Have to include limits.h, stdlib.h and stdint.h (or inttypes.h) to ensure +that size_t and uint8_t, UCHAR_MAX, etc are defined. If the system has neither +header, the relevant values must be provided by some other means. */ #include #include + +#if PCRE2_HAVE_STDINT_H #include +#elif PCRE2_HAVE_INTTYPES_H +#include +#endif /* Allow for C++ users compiling this directly. */ @@ -100,24 +112,24 @@ uint8_t, UCHAR_MAX, etc are defined. */ extern "C" { #endif -/* The following option bits can be passed to pcre2_compile(), pcre2_match(), -or pcre2_dfa_match(). PCRE2_NO_UTF_CHECK affects only the function to which it -is passed. Put these bits at the most significant end of the options word so -others can be added next to them */ + /* The following option bits can be passed to pcre2_compile(), pcre2_match(), + or pcre2_dfa_match(). PCRE2_NO_UTF_CHECK affects only the function to which it + is passed. Put these bits at the most significant end of the options word so + others can be added next to them */ #define PCRE2_ANCHORED 0x80000000u #define PCRE2_NO_UTF_CHECK 0x40000000u #define PCRE2_ENDANCHORED 0x20000000u -/* The following option bits can be passed only to pcre2_compile(). However, -they may affect compilation, JIT compilation, and/or interpretive execution. -The following tags indicate which: + /* The following option bits can be passed only to pcre2_compile(). However, + they may affect compilation, JIT compilation, and/or interpretive execution. + The following tags indicate which: -C alters what is compiled by pcre2_compile() -J alters what is compiled by pcre2_jit_compile() -M is inspected during pcre2_match() execution -D is inspected during pcre2_dfa_match() execution -*/ + C alters what is compiled by pcre2_compile() + J alters what is compiled by pcre2_jit_compile() + M is inspected during pcre2_match() execution + D is inspected during pcre2_dfa_match() execution + */ #define PCRE2_ALLOW_EMPTY_CLASS 0x00000001u /* C */ #define PCRE2_ALT_BSUX 0x00000002u /* C */ @@ -146,7 +158,7 @@ D is inspected during pcre2_dfa_match() execution #define PCRE2_EXTENDED_MORE 0x01000000u /* C */ #define PCRE2_LITERAL 0x02000000u /* C */ -/* An additional compile options word is available in the compile context. */ + /* An additional compile options word is available in the compile context. */ #define PCRE2_EXTRA_ALLOW_SURROGATE_ESCAPES 0x00000001u /* C */ #define PCRE2_EXTRA_BAD_ESCAPE_IS_LITERAL 0x00000002u /* C */ @@ -214,7 +226,107 @@ greater than zero. */ #define PCRE2_BSR_UNICODE 1 #define PCRE2_BSR_ANYCRLF 2 -/* Error codes: no match and partial match are "expected" errors. */ +/* Error codes for pcre2_compile(). Some of these are also used by +pcre2_pattern_convert(). */ + +#define PCRE2_ERROR_END_BACKSLASH 101 +#define PCRE2_ERROR_END_BACKSLASH_C 102 +#define PCRE2_ERROR_UNKNOWN_ESCAPE 103 +#define PCRE2_ERROR_QUANTIFIER_OUT_OF_ORDER 104 +#define PCRE2_ERROR_QUANTIFIER_TOO_BIG 105 +#define PCRE2_ERROR_MISSING_SQUARE_BRACKET 106 +#define PCRE2_ERROR_ESCAPE_INVALID_IN_CLASS 107 +#define PCRE2_ERROR_CLASS_RANGE_ORDER 108 +#define PCRE2_ERROR_QUANTIFIER_INVALID 109 +#define PCRE2_ERROR_INTERNAL_UNEXPECTED_REPEAT 110 +#define PCRE2_ERROR_INVALID_AFTER_PARENS_QUERY 111 +#define PCRE2_ERROR_POSIX_CLASS_NOT_IN_CLASS 112 +#define PCRE2_ERROR_POSIX_NO_SUPPORT_COLLATING 113 +#define PCRE2_ERROR_MISSING_CLOSING_PARENTHESIS 114 +#define PCRE2_ERROR_BAD_SUBPATTERN_REFERENCE 115 +#define PCRE2_ERROR_NULL_PATTERN 116 +#define PCRE2_ERROR_BAD_OPTIONS 117 +#define PCRE2_ERROR_MISSING_COMMENT_CLOSING 118 +#define PCRE2_ERROR_PARENTHESES_NEST_TOO_DEEP 119 +#define PCRE2_ERROR_PATTERN_TOO_LARGE 120 +#define PCRE2_ERROR_HEAP_FAILED 121 +#define PCRE2_ERROR_UNMATCHED_CLOSING_PARENTHESIS 122 +#define PCRE2_ERROR_INTERNAL_CODE_OVERFLOW 123 +#define PCRE2_ERROR_MISSING_CONDITION_CLOSING 124 +#define PCRE2_ERROR_LOOKBEHIND_NOT_FIXED_LENGTH 125 +#define PCRE2_ERROR_ZERO_RELATIVE_REFERENCE 126 +#define PCRE2_ERROR_TOO_MANY_CONDITION_BRANCHES 127 +#define PCRE2_ERROR_CONDITION_ASSERTION_EXPECTED 128 +#define PCRE2_ERROR_BAD_RELATIVE_REFERENCE 129 +#define PCRE2_ERROR_UNKNOWN_POSIX_CLASS 130 +#define PCRE2_ERROR_INTERNAL_STUDY_ERROR 131 +#define PCRE2_ERROR_UNICODE_NOT_SUPPORTED 132 +#define PCRE2_ERROR_PARENTHESES_STACK_CHECK 133 +#define PCRE2_ERROR_CODE_POINT_TOO_BIG 134 +#define PCRE2_ERROR_LOOKBEHIND_TOO_COMPLICATED 135 +#define PCRE2_ERROR_LOOKBEHIND_INVALID_BACKSLASH_C 136 +#define PCRE2_ERROR_UNSUPPORTED_ESCAPE_SEQUENCE 137 +#define PCRE2_ERROR_CALLOUT_NUMBER_TOO_BIG 138 +#define PCRE2_ERROR_MISSING_CALLOUT_CLOSING 139 +#define PCRE2_ERROR_ESCAPE_INVALID_IN_VERB 140 +#define PCRE2_ERROR_UNRECOGNIZED_AFTER_QUERY_P 141 +#define PCRE2_ERROR_MISSING_NAME_TERMINATOR 142 +#define PCRE2_ERROR_DUPLICATE_SUBPATTERN_NAME 143 +#define PCRE2_ERROR_INVALID_SUBPATTERN_NAME 144 +#define PCRE2_ERROR_UNICODE_PROPERTIES_UNAVAILABLE 145 +#define PCRE2_ERROR_MALFORMED_UNICODE_PROPERTY 146 +#define PCRE2_ERROR_UNKNOWN_UNICODE_PROPERTY 147 +#define PCRE2_ERROR_SUBPATTERN_NAME_TOO_LONG 148 +#define PCRE2_ERROR_TOO_MANY_NAMED_SUBPATTERNS 149 +#define PCRE2_ERROR_CLASS_INVALID_RANGE 150 +#define PCRE2_ERROR_OCTAL_BYTE_TOO_BIG 151 +#define PCRE2_ERROR_INTERNAL_OVERRAN_WORKSPACE 152 +#define PCRE2_ERROR_INTERNAL_MISSING_SUBPATTERN 153 +#define PCRE2_ERROR_DEFINE_TOO_MANY_BRANCHES 154 +#define PCRE2_ERROR_BACKSLASH_O_MISSING_BRACE 155 +#define PCRE2_ERROR_INTERNAL_UNKNOWN_NEWLINE 156 +#define PCRE2_ERROR_BACKSLASH_G_SYNTAX 157 +#define PCRE2_ERROR_PARENS_QUERY_R_MISSING_CLOSING 158 +/* Error 159 is obsolete and should now never occur */ +#define PCRE2_ERROR_VERB_ARGUMENT_NOT_ALLOWED 159 +#define PCRE2_ERROR_VERB_UNKNOWN 160 +#define PCRE2_ERROR_SUBPATTERN_NUMBER_TOO_BIG 161 +#define PCRE2_ERROR_SUBPATTERN_NAME_EXPECTED 162 +#define PCRE2_ERROR_INTERNAL_PARSED_OVERFLOW 163 +#define PCRE2_ERROR_INVALID_OCTAL 164 +#define PCRE2_ERROR_SUBPATTERN_NAMES_MISMATCH 165 +#define PCRE2_ERROR_MARK_MISSING_ARGUMENT 166 +#define PCRE2_ERROR_INVALID_HEXADECIMAL 167 +#define PCRE2_ERROR_BACKSLASH_C_SYNTAX 168 +#define PCRE2_ERROR_BACKSLASH_K_SYNTAX 169 +#define PCRE2_ERROR_INTERNAL_BAD_CODE_LOOKBEHINDS 170 +#define PCRE2_ERROR_BACKSLASH_N_IN_CLASS 171 +#define PCRE2_ERROR_CALLOUT_STRING_TOO_LONG 172 +#define PCRE2_ERROR_UNICODE_DISALLOWED_CODE_POINT 173 +#define PCRE2_ERROR_UTF_IS_DISABLED 174 +#define PCRE2_ERROR_UCP_IS_DISABLED 175 +#define PCRE2_ERROR_VERB_NAME_TOO_LONG 176 +#define PCRE2_ERROR_BACKSLASH_U_CODE_POINT_TOO_BIG 177 +#define PCRE2_ERROR_MISSING_OCTAL_OR_HEX_DIGITS 178 +#define PCRE2_ERROR_VERSION_CONDITION_SYNTAX 179 +#define PCRE2_ERROR_INTERNAL_BAD_CODE_AUTO_POSSESS 180 +#define PCRE2_ERROR_CALLOUT_NO_STRING_DELIMITER 181 +#define PCRE2_ERROR_CALLOUT_BAD_STRING_DELIMITER 182 +#define PCRE2_ERROR_BACKSLASH_C_CALLER_DISABLED 183 +#define PCRE2_ERROR_QUERY_BARJX_NEST_TOO_DEEP 184 +#define PCRE2_ERROR_BACKSLASH_C_LIBRARY_DISABLED 185 +#define PCRE2_ERROR_PATTERN_TOO_COMPLICATED 186 +#define PCRE2_ERROR_LOOKBEHIND_TOO_LONG 187 +#define PCRE2_ERROR_PATTERN_STRING_TOO_LONG 188 +#define PCRE2_ERROR_INTERNAL_BAD_CODE 189 +#define PCRE2_ERROR_INTERNAL_BAD_CODE_IN_SKIP 190 +#define PCRE2_ERROR_NO_SURROGATES_IN_UTF16 191 +#define PCRE2_ERROR_BAD_LITERAL_OPTIONS 192 +#define PCRE2_ERROR_SUPPORTED_ONLY_IN_UNICODE 193 +#define PCRE2_ERROR_INVALID_HYPHEN_IN_OPTIONS 194 + + +/* "Expected" matching error codes: no match and partial match. */ #define PCRE2_ERROR_NOMATCH (-1) #define PCRE2_ERROR_PARTIAL (-2) @@ -254,10 +366,10 @@ greater than zero. */ #define PCRE2_ERROR_UTF32_ERR1 (-27) #define PCRE2_ERROR_UTF32_ERR2 (-28) -/* Error codes for pcre2[_dfa]_match(), substring extraction functions, context -functions, and serializing functions. They are in numerical order. Originally -they were in alphabetical order too, but now that PCRE2 is released, the -numbers must not be changed. */ +/* Miscellaneous error codes for pcre2[_dfa]_match(), substring extraction +functions, context functions, and serializing functions. They are in numerical +order. Originally they were in alphabetical order too, but now that PCRE2 is +released, the numbers must not be changed. */ #define PCRE2_ERROR_BADDATA (-29) #define PCRE2_ERROR_MIXEDTABLES (-30) /* Name was changed */ @@ -296,6 +408,7 @@ numbers must not be changed. */ #define PCRE2_ERROR_BADSERIALIZEDDATA (-62) #define PCRE2_ERROR_HEAPLIMIT (-63) #define PCRE2_ERROR_CONVERT_SYNTAX (-64) +#define PCRE2_ERROR_INTERNAL_DUPMATCH (-65) /* Request types for pcre2_pattern_info() */ @@ -348,28 +461,29 @@ numbers must not be changed. */ #define PCRE2_CONFIG_NEVER_BACKSLASH_C 13 #define PCRE2_CONFIG_COMPILED_WIDTHS 14 + /* Types for code units in patterns and subject strings. */ -typedef uint8_t PCRE2_UCHAR8; -typedef uint16_t PCRE2_UCHAR16; -typedef uint32_t PCRE2_UCHAR32; + typedef uint8_t PCRE2_UCHAR8; + typedef uint16_t PCRE2_UCHAR16; + typedef uint32_t PCRE2_UCHAR32; -typedef const PCRE2_UCHAR8 *PCRE2_SPTR8; -typedef const PCRE2_UCHAR16 *PCRE2_SPTR16; -typedef const PCRE2_UCHAR32 *PCRE2_SPTR32; + typedef const PCRE2_UCHAR8* PCRE2_SPTR8; + typedef const PCRE2_UCHAR16* PCRE2_SPTR16; + typedef const PCRE2_UCHAR32* PCRE2_SPTR32; -/* The PCRE2_SIZE type is used for all string lengths and offsets in PCRE2, -including pattern offsets for errors and subject offsets after a match. We -define special values to indicate zero-terminated strings and unset offsets in -the offset vector (ovector). */ + /* The PCRE2_SIZE type is used for all string lengths and offsets in PCRE2, + including pattern offsets for errors and subject offsets after a match. We + define special values to indicate zero-terminated strings and unset offsets in + the offset vector (ovector). */ #define PCRE2_SIZE size_t #define PCRE2_SIZE_MAX SIZE_MAX #define PCRE2_ZERO_TERMINATED (~(PCRE2_SIZE)0) #define PCRE2_UNSET (~(PCRE2_SIZE)0) -/* Generic types for opaque structures and JIT callback functions. These -declarations are defined in a macro that is expanded for each width later. */ + /* Generic types for opaque structures and JIT callback functions. These + declarations are defined in a macro that is expanded for each width later. */ #define PCRE2_TYPES_LIST \ struct pcre2_real_general_context; \ @@ -396,13 +510,13 @@ typedef struct pcre2_real_jit_stack pcre2_jit_stack; \ typedef pcre2_jit_stack *(*pcre2_jit_callback)(void *); -/* The structure for passing out data via the pcre_callout_function. We use a -structure so that new fields can be added on the end in future versions, -without changing the API of the function, thereby allowing old clients to work -without modification. Define the generic version in a macro; the width-specific -versions are generated from this macro below. */ + /* The structure for passing out data via the pcre_callout_function. We use a + structure so that new fields can be added on the end in future versions, + without changing the API of the function, thereby allowing old clients to work + without modification. Define the generic version in a macro; the width-specific + versions are generated from this macro below. */ -/* Flags for the callout_flags field. These are cleared after a callout. */ + /* Flags for the callout_flags field. These are cleared after a callout. */ #define PCRE2_CALLOUT_STARTMATCH 0x00000001u /* Set for each bumpalong */ #define PCRE2_CALLOUT_BACKTRACK 0x00000002u /* Set after a backtrack */ @@ -805,18 +919,18 @@ PCRE2_JIT_FUNCTIONS \ PCRE2_OTHER_FUNCTIONS #define PCRE2_LOCAL_WIDTH 8 -PCRE2_TYPES_STRUCTURES_AND_FUNCTIONS + PCRE2_TYPES_STRUCTURES_AND_FUNCTIONS #undef PCRE2_LOCAL_WIDTH #define PCRE2_LOCAL_WIDTH 16 -PCRE2_TYPES_STRUCTURES_AND_FUNCTIONS + PCRE2_TYPES_STRUCTURES_AND_FUNCTIONS #undef PCRE2_LOCAL_WIDTH #define PCRE2_LOCAL_WIDTH 32 -PCRE2_TYPES_STRUCTURES_AND_FUNCTIONS + PCRE2_TYPES_STRUCTURES_AND_FUNCTIONS #undef PCRE2_LOCAL_WIDTH -/* Undefine the list macros; they are no longer needed. */ + /* Undefine the list macros; they are no longer needed. */ #undef PCRE2_TYPES_LIST #undef PCRE2_STRUCTURE_LIST diff --git a/ProcessHacker/pcre/pcre2_auto_possess.c b/ProcessHacker/pcre/pcre2_auto_possess.c index 23275a2e39cd..2ce152e9522f 100644 --- a/ProcessHacker/pcre/pcre2_auto_possess.c +++ b/ProcessHacker/pcre/pcre2_auto_possess.c @@ -7,7 +7,7 @@ and semantics are as close as possible to those of the Perl 5 language. Written by Philip Hazel Original API code Copyright (c) 1997-2012 University of Cambridge - New API code Copyright (c) 2016-2017 University of Cambridge + New API code Copyright (c) 2016-2018 University of Cambridge ----------------------------------------------------------------------------- Redistribution and use in source and binary forms, with or without @@ -505,7 +505,7 @@ which case the base cannot be possessified. utf TRUE in UTF mode cb compile data block base_list the data list of the base opcode - base_end the end of the data list + base_end the end of the base opcode rec_limit points to recursion depth counter Returns: TRUE if the auto-possessification is possible @@ -730,7 +730,7 @@ for(;;) if ((*xclass_flags & XCL_MAP) == 0) { /* No bits are set for characters < 256. */ - if (list[1] == 0) return TRUE; + if (list[1] == 0) return (*xclass_flags & XCL_NOT) == 0; /* Might be an empty repeat. */ continue; } @@ -1235,6 +1235,7 @@ for (;;) #endif case OP_MARK: + case OP_COMMIT_ARG: case OP_PRUNE_ARG: case OP_SKIP_ARG: case OP_THEN_ARG: diff --git a/ProcessHacker/pcre/pcre2_chartables.c b/ProcessHacker/pcre/pcre2_chartables.c index 203cb1a4ab04..4046500c00d0 100644 --- a/ProcessHacker/pcre/pcre2_chartables.c +++ b/ProcessHacker/pcre/pcre2_chartables.c @@ -2,23 +2,24 @@ * Perl-Compatible Regular Expressions * *************************************************/ -/* This file contains character tables that are used when no external tables -are passed to PCRE2 by the application that calls it. The tables are used only -for characters whose code values are less than 256. - -This is a default version of the tables that assumes ASCII encoding. A program -called dftables (which is distributed with PCRE2) can be used to build -alternative versions of this file. This is necessary if you are running in an -EBCDIC environment, or if you want to default to a different encoding, for -example ISO-8859-1. When dftables is run, it creates these tables in the -current locale. If PCRE2 is configured with --enable-rebuild-chartables, this -happens automatically. - -The following #includes are present because without them gcc 4.x may remove the -array definition from the final binary if PCRE2 is built into a static library -and dead code stripping is activated. This leads to link errors. Pulling in the -header ensures that the array gets flagged as "someone outside this compilation -unit might reference this" and so it will always be supplied to the linker. */ +/* This file was automatically written by the dftables auxiliary +program. It contains character tables that are used when no external +tables are passed to PCRE2 by the application that calls it. The tables +are used only for characters whose code values are less than 256. */ + +/*The dftables program (which is distributed with PCRE2) can be used to +build alternative versions of this file. This is necessary if you are +running in an EBCDIC environment, or if you want to default to a different +encoding, for example ISO-8859-1. When dftables is run, it creates these +tables in the current locale. This happens automatically if PCRE2 is +configured with --enable-rebuild-chartables. */ + +/* The following #include is present because without it gcc 4.x may remove +the array definition from the final binary if PCRE2 is built into a static +library and dead code stripping is activated. This leads to link errors. +Pulling in the header ensures that the array gets flagged as "someone +outside this compilation unit might reference this" and so it will always +be supplied to the linker. */ #ifdef HAVE_CONFIG_H #include "config.h" @@ -101,7 +102,7 @@ const uint8_t PRIV(default_tables)[] = { /* This table contains bit maps for various character classes. Each map is 32 bytes long and the bits run from the least significant end of each byte. The classes that have their own maps are: space, xdigit, digit, upper, lower, word, -graph, print, punct, and cntrl. Other classes are built from combinations. */ +graph print, punct, and cntrl. Other classes are built from combinations. */ 0x00,0x3e,0x00,0x00,0x01,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, @@ -159,25 +160,24 @@ graph, print, punct, and cntrl. Other classes are built from combinations. */ 0x04 decimal digit 0x08 hexadecimal digit 0x10 alphanumeric or '_' - 0x80 regular expression metacharacter or binary zero */ - 0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0- 7 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0- 7 */ 0x00,0x01,0x01,0x01,0x01,0x01,0x00,0x00, /* 8- 15 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 16- 23 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 24- 31 */ - 0x01,0x00,0x00,0x00,0x80,0x00,0x00,0x00, /* - ' */ - 0x80,0x80,0x80,0x80,0x00,0x00,0x80,0x00, /* ( - / */ + 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* - ' */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* ( - / */ 0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c, /* 0 - 7 */ - 0x1c,0x1c,0x00,0x00,0x00,0x00,0x00,0x80, /* 8 - ? */ + 0x1c,0x1c,0x00,0x00,0x00,0x00,0x00,0x00, /* 8 - ? */ 0x00,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x12, /* @ - G */ 0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12, /* H - O */ 0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12, /* P - W */ - 0x12,0x12,0x12,0x80,0x80,0x00,0x80,0x10, /* X - _ */ + 0x12,0x12,0x12,0x00,0x00,0x00,0x00,0x10, /* X - _ */ 0x00,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x12, /* ` - g */ 0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12, /* h - o */ 0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12, /* p - w */ - 0x12,0x12,0x12,0x80,0x80,0x00,0x00,0x00, /* x -127 */ + 0x12,0x12,0x12,0x00,0x00,0x00,0x00,0x00, /* x -127 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 128-135 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 136-143 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 144-151 */ diff --git a/ProcessHacker/pcre/pcre2_compile.c b/ProcessHacker/pcre/pcre2_compile.c index 87530fb58441..6bb1de361001 100644 --- a/ProcessHacker/pcre/pcre2_compile.c +++ b/ProcessHacker/pcre/pcre2_compile.c @@ -7,7 +7,7 @@ and semantics are as close as possible to those of the Perl 5 language. Written by Philip Hazel Original API code Copyright (c) 1997-2012 University of Cambridge - New API code Copyright (c) 2016-2017 University of Cambridge + New API code Copyright (c) 2016-2018 University of Cambridge ----------------------------------------------------------------------------- Redistribution and use in source and binary forms, with or without @@ -63,8 +63,8 @@ POSSIBILITY OF SUCH DAMAGE. /* Other debugging code can be enabled by these defines. */ -// #define DEBUG_SHOW_CAPTURES -// #define DEBUG_SHOW_PARSED +/* #define DEBUG_SHOW_CAPTURES */ +/* #define DEBUG_SHOW_PARSED */ /* There are a few things that vary with different code unit sizes. Handle them by defining macros in order to minimize #if usage. */ @@ -250,34 +250,35 @@ is present where expected in a conditional group. */ #define META_LOOKBEHINDNOT 0x80250000u /* (? 0 => must have an argument */ { 4, META_MARK, +1 }, - { 6, META_ACCEPT, -1 }, /* < 0 => must not have an argument */ - { 6, META_COMMIT, -1 }, + { 6, META_ACCEPT, -1 }, /* < 0 => Optional argument, convert to pre-MARK */ { 1, META_FAIL, -1 }, { 4, META_FAIL, -1 }, - { 5, META_PRUNE, 0 }, /* Argument is optional; bump META code if found */ + { 6, META_COMMIT, 0 }, + { 5, META_PRUNE, 0 }, /* Optional argument; bump META code if found */ { 4, META_SKIP, 0 }, { 4, META_THEN, 0 } }; @@ -610,8 +612,8 @@ static const int verbcount = sizeof(verbs)/sizeof(verbitem); /* Verb opcodes, indexed by their META code offset from META_MARK. */ static const uint32_t verbops[] = { - OP_MARK, OP_ACCEPT, OP_COMMIT, OP_FAIL, OP_PRUNE, OP_PRUNE_ARG, OP_SKIP, - OP_SKIP_ARG, OP_THEN, OP_THEN_ARG }; + OP_MARK, OP_ACCEPT, OP_FAIL, OP_COMMIT, OP_COMMIT_ARG, OP_PRUNE, + OP_PRUNE_ARG, OP_SKIP, OP_SKIP_ARG, OP_THEN, OP_THEN_ARG }; /* Offsets from OP_STAR for case-independent and negative repeat opcodes. */ @@ -729,7 +731,7 @@ enum { ERR0 = COMPILE_ERROR_BASE, ERR61, ERR62, ERR63, ERR64, ERR65, ERR66, ERR67, ERR68, ERR69, ERR70, ERR71, ERR72, ERR73, ERR74, ERR75, ERR76, ERR77, ERR78, ERR79, ERR80, ERR81, ERR82, ERR83, ERR84, ERR85, ERR86, ERR87, ERR88, ERR89, ERR90, - ERR91, ERR92}; + ERR91, ERR92, ERR93, ERR94 }; /* This is a table of start-of-pattern options such as (*UTF) and settings such as (*LIMIT_MATCH=nnnn) and (*CRLF). For completeness and backward @@ -976,8 +978,8 @@ for (;;) case META_POSIX_NEG: fprintf(stderr, "META_POSIX_NEG %d", *pptr++); break; case META_ACCEPT: fprintf(stderr, "META (*ACCEPT)"); break; - case META_COMMIT: fprintf(stderr, "META (*COMMIT)"); break; case META_FAIL: fprintf(stderr, "META (*FAIL)"); break; + case META_COMMIT: fprintf(stderr, "META (*COMMIT)"); break; case META_PRUNE: fprintf(stderr, "META (*PRUNE)"); break; case META_SKIP: fprintf(stderr, "META (*SKIP)"); break; case META_THEN: fprintf(stderr, "META (*THEN)"); break; @@ -1067,6 +1069,10 @@ for (;;) fprintf(stderr, "META (*MARK:"); goto SHOWARG; + case META_COMMIT_ARG: + fprintf(stderr, "META (*COMMIT:"); + goto SHOWARG; + case META_PRUNE_ARG: fprintf(stderr, "META (*PRUNE:"); goto SHOWARG; @@ -1435,6 +1441,48 @@ else if ((i = escapes[c - ESCAPES_FIRST]) != 0) escape = -i; /* Else return a special escape */ if (cb != NULL && (escape == ESC_P || escape == ESC_p || escape == ESC_X)) cb->external_flags |= PCRE2_HASBKPORX; /* Note \P, \p, or \X */ + + /* Perl supports \N{name} for character names and \N{U+dddd} for numerical + Unicode code points, as well as plain \N for "not newline". PCRE does not + support \N{name}. However, it does support quantification such as \N{2,3}, + so if \N{ is not followed by U+dddd we check for a quantifier. */ + + if (escape == ESC_N && ptr < ptrend && *ptr == CHAR_LEFT_CURLY_BRACKET) + { + PCRE2_SPTR p = ptr + 1; + + /* \N{U+ can be handled by the \x{ code. However, this construction is + not valid in EBCDIC environments because it specifies a Unicode + character, not a codepoint in the local code. For example \N{U+0041} + must be "A" in all environments. Also, in Perl, \N{U+ forces Unicode + casing semantics for the entire pattern, so allow it only in UTF (i.e. + Unicode) mode. */ + + if (ptrend - p > 1 && *p == CHAR_U && p[1] == CHAR_PLUS) + { +#ifdef EBCDIC + *errorcodeptr = ERR93; +#else + if (utf) + { + ptr = p + 1; + escape = 0; /* Not a fancy escape after all */ + goto COME_FROM_NU; + } + else *errorcodeptr = ERR93; +#endif + } + + /* Give an error if what follows is not a quantifier, but don't override + an error set by the quantifier reader (e.g. number overflow). */ + + else + { + if (!read_repeat_counts(&p, ptrend, NULL, NULL, errorcodeptr) && + *errorcodeptr == 0) + *errorcodeptr = ERR37; + } + } } } @@ -1462,6 +1510,7 @@ else /* A number of Perl escapes are not handled by PCRE. We give an explicit error. */ + case CHAR_F: case CHAR_l: case CHAR_L: *errorcodeptr = ERR37; @@ -1719,6 +1768,9 @@ else { if (ptr < ptrend && *ptr == CHAR_LEFT_CURLY_BRACKET) { +#ifndef EBCDIC + COME_FROM_NU: +#endif if (++ptr >= ptrend || *ptr == CHAR_RIGHT_CURLY_BRACKET) { *errorcodeptr = ERR78; @@ -1852,19 +1904,6 @@ else } } -/* Perl supports \N{name} for character names, as well as plain \N for "not -newline". PCRE does not support \N{name}. However, it does support -quantification such as \N{2,3}. */ - -if (escape == ESC_N && ptr < ptrend && *ptr == CHAR_LEFT_CURLY_BRACKET && - ptrend - ptr > 2) - { - PCRE2_SPTR p = ptr + 1; - if (!read_repeat_counts(&p, ptrend, NULL, NULL, errorcodeptr) && - *errorcodeptr == 0) - *errorcodeptr = ERR37; - } - /* Set the pointer to the next character before returning. */ *ptrptr = ptr; @@ -2251,11 +2290,14 @@ typedef struct nest_save { #define NSF_RESET 0x0001u #define NSF_CONDASSERT 0x0002u -/* Of the options that are changeable within the pattern, these are tracked -during parsing. The rest are used from META_OPTIONS items when compiling. */ +/* Options that are changeable within the pattern must be tracked during +parsing. Some (e.g. PCRE2_EXTENDED) are implemented entirely during parsing, +but all must be tracked so that META_OPTIONS items set the correct values for +the main compiling phase. */ -#define PARSE_TRACKED_OPTIONS \ - (PCRE2_DUPNAMES|PCRE2_EXTENDED|PCRE2_EXTENDED_MORE|PCRE2_NO_AUTO_CAPTURE) +#define PARSE_TRACKED_OPTIONS (PCRE2_CASELESS|PCRE2_DOTALL|PCRE2_DUPNAMES| \ + PCRE2_EXTENDED|PCRE2_EXTENDED_MORE|PCRE2_MULTILINE|PCRE2_NO_AUTO_CAPTURE| \ + PCRE2_UNGREEDY) /* States used for analyzing ranges in character classes. The two OK values must be last. */ @@ -2290,6 +2332,7 @@ uint32_t *previous_callout = NULL; uint32_t *parsed_pattern = cb->parsed_pattern; uint32_t *parsed_pattern_end = cb->parsed_pattern_end; uint32_t meta_quantifier = 0; +uint32_t add_after_mark = 0; uint16_t nest_depth = 0; int after_manual_callout = 0; int expect_cond_assert = 0; @@ -2434,11 +2477,17 @@ while (ptr < ptrend) /* EITHER: not both options set */ ((options & (PCRE2_EXTENDED | PCRE2_ALT_VERBNAMES)) != (PCRE2_EXTENDED | PCRE2_ALT_VERBNAMES)) || - /* OR: character > 255 */ - c > 255 || - /* OR: not a # comment or white space */ - (c != CHAR_NUMBER_SIGN && (cb->ctypes[c] & ctype_space) == 0) - )) +#ifdef SUPPORT_UNICODE + /* OR: character > 255 AND not Unicode Pattern White Space */ + (c > 255 && (c|1) != 0x200f && (c|1) != 0x2029) || +#endif + /* OR: not a # comment or isspace() white space */ + (c < 256 && c != CHAR_NUMBER_SIGN && (cb->ctypes[c] & ctype_space) == 0 +#ifdef SUPPORT_UNICODE + /* and not CHAR_NEL when Unicode is supported */ + && c != CHAR_NEL +#endif + ))) { PCRE2_SIZE verbnamelength; @@ -2461,6 +2510,16 @@ while (ptr < ptrend) goto FAILED; } *verblengthptr = (uint32_t)verbnamelength; + + /* If this name was on a verb such as (*ACCEPT) which does not continue, + a (*MARK) was generated for the name. We now add the original verb as the + next item. */ + + if (add_after_mark != 0) + { + *parsed_pattern++ = add_after_mark; + add_after_mark = 0; + } break; case CHAR_BACKSLASH: @@ -2510,11 +2569,18 @@ while (ptr < ptrend) /* Skip over whitespace and # comments in extended mode. Note that c is a character, not a code unit, so we must not use MAX_255 to test its size - because MAX_255 tests code units and is assumed TRUE in 8-bit mode. */ + because MAX_255 tests code units and is assumed TRUE in 8-bit mode. The + whitespace characters are those designated as "Pattern White Space" by + Unicode, which are the isspace() characters plus CHAR_NEL (newline), which is + U+0085 in Unicode, plus U+200E, U+200F, U+2028, and U+2029. These are a + subset of space characters that match \h and \v. */ if ((options & PCRE2_EXTENDED) != 0) { if (c < 256 && (cb->ctypes[c] & ctype_space) != 0) continue; +#ifdef SUPPORT_UNICODE + if (c == CHAR_NEL || (c|1) == 0x200f || (c|1) == 0x2029) continue; +#endif if (c == CHAR_NUMBER_SIGN) { while (ptr < ptrend) @@ -3206,7 +3272,6 @@ while (ptr < ptrend) tempptr = ptr; escape = PRIV(check_escape)(&ptr, ptrend, &c, &errorcode, options, TRUE, cb); - if (errorcode != 0) { CLASS_ESCAPE_FAILED: @@ -3454,13 +3519,25 @@ while (ptr < ptrend) if (*ptr++ == CHAR_COLON) /* Skip past : or ) */ { - if (verbs[i].has_arg < 0) /* Argument is forbidden */ + /* Some optional arguments can be treated as a preceding (*MARK) */ + + if (verbs[i].has_arg < 0) { - errorcode = ERR59; - goto FAILED; + add_after_mark = verbs[i].meta; + *parsed_pattern++ = META_MARK; } - *parsed_pattern++ = verbs[i].meta + - ((verbs[i].meta != META_MARK)? 0x00010000u:0); + + /* The remaining verbs with arguments (except *MARK) need a different + opcode. */ + + else + { + *parsed_pattern++ = verbs[i].meta + + ((verbs[i].meta != META_MARK)? 0x00010000u:0); + } + + /* Set up for reading the name in the main loop. */ + verblengthptr = parsed_pattern++; verbnamestart = ptr; inverbname = TRUE; @@ -3521,17 +3598,39 @@ while (ptr < ptrend) else { + BOOL hyphenok = TRUE; + uint32_t oldoptions = options; + top_nest->reset_group = 0; top_nest->max_group = 0; set = unset = 0; optset = &set; + /* ^ at the start unsets imnsx and disables the subsequent use of - */ + + if (ptr < ptrend && *ptr == CHAR_CIRCUMFLEX_ACCENT) + { + options &= ~(PCRE2_CASELESS|PCRE2_MULTILINE|PCRE2_NO_AUTO_CAPTURE| + PCRE2_DOTALL|PCRE2_EXTENDED|PCRE2_EXTENDED_MORE); + hyphenok = FALSE; + ptr++; + } + while (ptr < ptrend && *ptr != CHAR_RIGHT_PARENTHESIS && *ptr != CHAR_COLON) { switch (*ptr++) { - case CHAR_MINUS: optset = &unset; break; + case CHAR_MINUS: + if (!hyphenok) + { + errorcode = ERR94; + ptr--; /* Correct the offset */ + goto FAILED; + } + optset = &unset; + hyphenok = FALSE; + break; case CHAR_J: /* Record that it changed in the external options */ *optset |= PCRE2_DUPNAMES; @@ -3591,7 +3690,7 @@ while (ptr < ptrend) /* If nothing changed, no need to record. */ - if (set != 0 || unset != 0) + if (options != oldoptions) { *parsed_pattern++ = META_OPTIONS; *parsed_pattern++ = options; @@ -3896,9 +3995,8 @@ while (ptr < ptrend) if (*ptr == CHAR_DOT) { if (++ptr >= ptrend || !IS_DIGIT(*ptr)) goto BAD_VERSION_CONDITION; - if (!read_number(&ptr, ptrend, -1, 99 , ERR79, &minor, &errorcode)) - goto FAILED; - if (minor < 10) minor *= 10; + minor = (*ptr++ - CHAR_0) * 10; + if (IS_DIGIT(*ptr)) minor += *ptr++ - CHAR_0; if (ptr >= ptrend || *ptr != CHAR_RIGHT_PARENTHESIS) goto BAD_VERSION_CONDITION; } @@ -4261,11 +4359,11 @@ goto FAILED; /************************************************* -* Find first significant op code * +* Find first significant opcode * *************************************************/ /* This is called by several functions that scan a compiled expression looking -for a fixed first character, or an anchoring op code etc. It skips over things +for a fixed first character, or an anchoring opcode etc. It skips over things that do not influence this. For some calls, it makes sense to skip negative forward and all backward assertions, and also the \b assertion; for others it does not. @@ -5472,7 +5570,7 @@ for (;; pptr++) set xclass = TRUE. Then, in the pre-compile phase, accumulate the length of the extra data and reset the pointer. This is so that very large classes that contain a zillion wide characters or Unicode property tests - do not overwrite the work space (which is on the stack). */ + do not overwrite the workspace (which is on the stack). */ if (class_uchardata > class_uchardata_base) { @@ -5563,7 +5661,7 @@ for (;; pptr++) if (class_has_8bitchar > 0) { *code++ |= XCL_MAP; - memmove(code + (32 / sizeof(PCRE2_UCHAR)), code, + (void)memmove(code + (32 / sizeof(PCRE2_UCHAR)), code, CU2BYTES(class_uchardata - code)); if (negate_class && !xclass_has_prop) for (i = 0; i < 32; i++) classbits[i] = ~classbits[i]; @@ -5655,6 +5753,7 @@ for (;; pptr++) cb->had_pruneorskip = TRUE; /* Fall through */ case META_MARK: + case META_COMMIT_ARG: VERB_ARG: *code++ = verbops[(meta - META_MARK) >> 16]; /* The length is in characters. */ @@ -6509,7 +6608,7 @@ for (;; pptr++) /* Wrap the recursion call in OP_BRA brackets. */ - memmove(previous + 1 + LINK_SIZE, previous, CU2BYTES(1 + LINK_SIZE)); + (void)memmove(previous + 1 + LINK_SIZE, previous, CU2BYTES(1 + LINK_SIZE)); op_previous = *previous = OP_BRA; PUT(previous, 1, 2 + 2*LINK_SIZE); previous[2 + 2*LINK_SIZE] = OP_KET; @@ -6589,7 +6688,7 @@ for (;; pptr++) if (repeat_max <= 1 || repeat_max == REPEAT_UNLIMITED) { - memmove(previous + 1, previous, CU2BYTES(len)); + (void)memmove(previous + 1, previous, CU2BYTES(len)); code++; if (repeat_max == 0) { @@ -6610,7 +6709,7 @@ for (;; pptr++) else { int linkoffset; - memmove(previous + 2 + LINK_SIZE, previous, CU2BYTES(len)); + (void)memmove(previous + 2 + LINK_SIZE, previous, CU2BYTES(len)); code += 2 + LINK_SIZE; *previous++ = OP_BRAZERO + repeat_type; *previous++ = OP_BRA; @@ -6811,7 +6910,7 @@ for (;; pptr++) if (*bracode == OP_COND || *bracode == OP_SCOND) { int nlen = (int)(code - bracode); - memmove(bracode + 1 + LINK_SIZE, bracode, CU2BYTES(nlen)); + (void)memmove(bracode + 1 + LINK_SIZE, bracode, CU2BYTES(nlen)); code += 1 + LINK_SIZE; nlen += 1 + LINK_SIZE; *bracode = (*bracode == OP_COND)? OP_BRAPOS : OP_SBRAPOS; @@ -7082,7 +7181,7 @@ for (;; pptr++) else { - memmove(tempcode + 1 + LINK_SIZE, tempcode, CU2BYTES(len)); + (void)memmove(tempcode + 1 + LINK_SIZE, tempcode, CU2BYTES(len)); code += 1 + LINK_SIZE; len += 1 + LINK_SIZE; tempcode[0] = OP_ONCE; @@ -7460,7 +7559,7 @@ length of the BRA and KET and any extra code units that are required at the beginning. We accumulate in a local variable to save frequent testing of lengthptr for NULL. We cannot do this by looking at the value of 'code' at the start and end of each alternative, because compiled items are discarded during -the pre-compile phase so that the work space is not exceeded. */ +the pre-compile phase so that the workspace is not exceeded. */ length = 2 + 2*LINK_SIZE + skipunits; @@ -7622,7 +7721,7 @@ for (;;) { if (cb->open_caps->flag) { - memmove(start_bracket + 1 + LINK_SIZE, start_bracket, + (void)memmove(start_bracket + 1 + LINK_SIZE, start_bracket, CU2BYTES(code - start_bracket)); *start_bracket = OP_ONCE; code += 1 + LINK_SIZE; @@ -7765,10 +7864,11 @@ do { if (!is_anchored(scode, bracket_map, cb, atomcount, TRUE)) return FALSE; } - /* Condition */ + /* Condition. If there is no second branch, it can't be anchored. */ - else if (op == OP_COND) + else if (op == OP_COND || op == OP_SCOND) { + if (scode[GET(scode,1)] != OP_ALT) return FALSE; if (!is_anchored(scode, bracket_map, cb, atomcount, inassert)) return FALSE; } @@ -8003,6 +8103,7 @@ for (;;) break; case OP_MARK: + case OP_COMMIT_ARG: case OP_PRUNE_ARG: case OP_SKIP_ARG: case OP_THEN_ARG: @@ -8221,7 +8322,7 @@ for (i = 0; i < tablecount; i++) if (crc < 0) { - memmove(slot + cb->name_entry_size, slot, + (void)memmove(slot + cb->name_entry_size, slot, CU2BYTES((tablecount - i) * cb->name_entry_size)); break; } @@ -8311,6 +8412,7 @@ for (;; pptr++) break; case META_MARK: /* Add the length of the name. */ + case META_COMMIT_ARG: case META_PRUNE_ARG: case META_SKIP_ARG: case META_THEN_ARG: @@ -8501,6 +8603,7 @@ for (;; pptr++) goto EXIT; case META_MARK: + case META_COMMIT_ARG: case META_PRUNE_ARG: case META_SKIP_ARG: case META_THEN_ARG: @@ -8572,6 +8675,32 @@ for (;; pptr++) case META_LOOKAHEADNOT: pptr = parsed_skip(pptr + 1, PSKIP_KET); if (pptr == NULL) goto PARSED_SKIP_FAILED; + + /* Also ignore any qualifiers that follow a lookahead assertion. */ + + switch (pptr[1]) + { + case META_ASTERISK: + case META_ASTERISK_PLUS: + case META_ASTERISK_QUERY: + case META_PLUS: + case META_PLUS_PLUS: + case META_PLUS_QUERY: + case META_QUERY: + case META_QUERY_PLUS: + case META_QUERY_QUERY: + pptr++; + break; + + case META_MINMAX: + case META_MINMAX_PLUS: + case META_MINMAX_QUERY: + pptr += 3; + break; + + default: + break; + } break; /* Lookbehinds can be ignored, but must themselves be checked. */ @@ -8942,6 +9071,7 @@ for (pptr = cb->parsed_pattern; *pptr != META_END; pptr++) break; case META_MARK: + case META_COMMIT_ARG: case META_PRUNE_ARG: case META_SKIP_ARG: case META_THEN_ARG: diff --git a/ProcessHacker/pcre/pcre2_convert.c b/ProcessHacker/pcre/pcre2_convert.c new file mode 100644 index 000000000000..1dd5c337dc3c --- /dev/null +++ b/ProcessHacker/pcre/pcre2_convert.c @@ -0,0 +1,1182 @@ +/************************************************* +* Perl-Compatible Regular Expressions * +*************************************************/ + +/* PCRE is a library of functions to support regular expressions whose syntax +and semantics are as close as possible to those of the Perl 5 language. + + Written by Philip Hazel + Original API code Copyright (c) 1997-2012 University of Cambridge + New API code Copyright (c) 2016-2018 University of Cambridge + +----------------------------------------------------------------------------- +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of the University of Cambridge nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +----------------------------------------------------------------------------- +*/ + + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "pcre2_internal.h" + +#define TYPE_OPTIONS (PCRE2_CONVERT_GLOB| \ + PCRE2_CONVERT_POSIX_BASIC|PCRE2_CONVERT_POSIX_EXTENDED) + +#define ALL_OPTIONS (PCRE2_CONVERT_UTF|PCRE2_CONVERT_NO_UTF_CHECK| \ + PCRE2_CONVERT_GLOB_NO_WILD_SEPARATOR| \ + PCRE2_CONVERT_GLOB_NO_STARSTAR| \ + TYPE_OPTIONS) + +#define DUMMY_BUFFER_SIZE 100 + +/* Generated pattern fragments */ + +#define STR_BACKSLASH_A STR_BACKSLASH STR_A +#define STR_BACKSLASH_z STR_BACKSLASH STR_z +#define STR_COLON_RIGHT_SQUARE_BRACKET STR_COLON STR_RIGHT_SQUARE_BRACKET +#define STR_DOT_STAR_LOOKBEHIND STR_DOT STR_ASTERISK STR_LEFT_PARENTHESIS STR_QUESTION_MARK STR_LESS_THAN_SIGN STR_EQUALS_SIGN +#define STR_LOOKAHEAD_NOT_DOT STR_LEFT_PARENTHESIS STR_QUESTION_MARK STR_EXCLAMATION_MARK STR_BACKSLASH STR_DOT STR_RIGHT_PARENTHESIS +#define STR_QUERY_s STR_LEFT_PARENTHESIS STR_QUESTION_MARK STR_s STR_RIGHT_PARENTHESIS +#define STR_STAR_NUL STR_LEFT_PARENTHESIS STR_ASTERISK STR_N STR_U STR_L STR_RIGHT_PARENTHESIS + +/* States for range and POSIX processing */ + +enum { RANGE_NOT_STARTED, RANGE_STARTING, RANGE_STARTED }; +enum { POSIX_START_REGEX, POSIX_ANCHORED, POSIX_NOT_BRACKET, + POSIX_CLASS_NOT_STARTED, POSIX_CLASS_STARTING, POSIX_CLASS_STARTED }; + +/* Macro to add a character string to the output buffer, checking for overflow. */ + +#define PUTCHARS(string) \ + { \ + for (s = (char *)(string); *s != 0; s++) \ + { \ + if (p >= endp) return PCRE2_ERROR_NOMEMORY; \ + *p++ = *s; \ + } \ + } + +/* Literals that must be escaped: \ ? * + | . ^ $ { } [ ] ( ) */ + +static const char *pcre2_escaped_literals = + STR_BACKSLASH STR_QUESTION_MARK STR_ASTERISK STR_PLUS + STR_VERTICAL_LINE STR_DOT STR_CIRCUMFLEX_ACCENT STR_DOLLAR_SIGN + STR_LEFT_CURLY_BRACKET STR_RIGHT_CURLY_BRACKET + STR_LEFT_SQUARE_BRACKET STR_RIGHT_SQUARE_BRACKET + STR_LEFT_PARENTHESIS STR_RIGHT_PARENTHESIS; + +/* Recognized escaped metacharacters in POSIX basic patterns. */ + +static const char *posix_meta_escapes = + STR_LEFT_PARENTHESIS STR_RIGHT_PARENTHESIS + STR_LEFT_CURLY_BRACKET STR_RIGHT_CURLY_BRACKET + STR_1 STR_2 STR_3 STR_4 STR_5 STR_6 STR_7 STR_8 STR_9; + + + +/************************************************* +* Convert a POSIX pattern * +*************************************************/ + +/* This function handles both basic and extended POSIX patterns. + +Arguments: + pattype the pattern type + pattern the pattern + plength length in code units + utf TRUE if UTF + use_buffer where to put the output + use_length length of use_buffer + bufflenptr where to put the used length + dummyrun TRUE if a dummy run + ccontext the convert context + +Returns: 0 => success + !0 => error code +*/ + +static int +convert_posix(uint32_t pattype, PCRE2_SPTR pattern, PCRE2_SIZE plength, + BOOL utf, PCRE2_UCHAR *use_buffer, PCRE2_SIZE use_length, + PCRE2_SIZE *bufflenptr, BOOL dummyrun, pcre2_convert_context *ccontext) +{ +char *s; +PCRE2_SPTR posix = pattern; +PCRE2_UCHAR *p = use_buffer; +PCRE2_UCHAR *pp = p; +PCRE2_UCHAR *endp = p + use_length - 1; /* Allow for trailing zero */ +PCRE2_SIZE convlength = 0; + +uint32_t bracount = 0; +uint32_t posix_state = POSIX_START_REGEX; +uint32_t lastspecial = 0; +BOOL extended = (pattype & PCRE2_CONVERT_POSIX_EXTENDED) != 0; +BOOL nextisliteral = FALSE; + +(void)utf; /* Not used when Unicode not supported */ +(void)ccontext; /* Not currently used */ + +/* Initialize default for error offset as end of input. */ + +*bufflenptr = plength; +PUTCHARS(STR_STAR_NUL); + +/* Now scan the input. */ + +while (plength > 0) + { + uint32_t c, sc; + int clength = 1; + + /* Add in the length of the last item, then, if in the dummy run, pull the + pointer back to the start of the (temporary) buffer and then remember the + start of the next item. */ + + convlength += p - pp; + if (dummyrun) p = use_buffer; + pp = p; + + /* Pick up the next character */ + +#ifndef SUPPORT_UNICODE + c = *posix; +#else + GETCHARLENTEST(c, posix, clength); +#endif + posix += clength; + plength -= clength; + + sc = nextisliteral? 0 : c; + nextisliteral = FALSE; + + /* Handle a character within a class. */ + + if (posix_state >= POSIX_CLASS_NOT_STARTED) + { + if (c == CHAR_RIGHT_SQUARE_BRACKET) + { + PUTCHARS(STR_RIGHT_SQUARE_BRACKET); + posix_state = POSIX_NOT_BRACKET; + } + + /* Not the end of the class */ + + else + { + switch (posix_state) + { + case POSIX_CLASS_STARTED: + if (c <= 127 && islower(c)) break; /* Remain in started state */ + posix_state = POSIX_CLASS_NOT_STARTED; + if (c == CHAR_COLON && plength > 0 && + *posix == CHAR_RIGHT_SQUARE_BRACKET) + { + PUTCHARS(STR_COLON_RIGHT_SQUARE_BRACKET); + plength--; + posix++; + continue; /* With next character after :] */ + } + /* Fall through */ + + case POSIX_CLASS_NOT_STARTED: + if (c == CHAR_LEFT_SQUARE_BRACKET) + posix_state = POSIX_CLASS_STARTING; + break; + + case POSIX_CLASS_STARTING: + if (c == CHAR_COLON) posix_state = POSIX_CLASS_STARTED; + break; + } + + if (c == CHAR_BACKSLASH) PUTCHARS(STR_BACKSLASH); + if (p + clength > endp) return PCRE2_ERROR_NOMEMORY; + memcpy(p, posix - clength, CU2BYTES(clength)); + p += clength; + } + } + + /* Handle a character not within a class. */ + + else switch(sc) + { + case CHAR_LEFT_SQUARE_BRACKET: + PUTCHARS(STR_LEFT_SQUARE_BRACKET); + +#ifdef NEVER + /* We could handle special cases [[:<:]] and [[:>:]] (which PCRE does + support) but they are not part of POSIX 1003.1. */ + + if (plength >= 6) + { + if (posix[0] == CHAR_LEFT_SQUARE_BRACKET && + posix[1] == CHAR_COLON && + (posix[2] == CHAR_LESS_THAN_SIGN || + posix[2] == CHAR_GREATER_THAN_SIGN) && + posix[3] == CHAR_COLON && + posix[4] == CHAR_RIGHT_SQUARE_BRACKET && + posix[5] == CHAR_RIGHT_SQUARE_BRACKET) + { + if (p + 6 > endp) return PCRE2_ERROR_NOMEMORY; + memcpy(p, posix, CU2BYTES(6)); + p += 6; + posix += 6; + plength -= 6; + continue; /* With next character */ + } + } +#endif + + /* Handle start of "normal" character classes */ + + posix_state = POSIX_CLASS_NOT_STARTED; + + /* Handle ^ and ] as first characters */ + + if (plength > 0) + { + if (*posix == CHAR_CIRCUMFLEX_ACCENT) + { + posix++; + plength--; + PUTCHARS(STR_CIRCUMFLEX_ACCENT); + } + if (plength > 0 && *posix == CHAR_RIGHT_SQUARE_BRACKET) + { + posix++; + plength--; + PUTCHARS(STR_RIGHT_SQUARE_BRACKET); + } + } + break; + + case CHAR_BACKSLASH: + if (plength <= 0) return PCRE2_ERROR_END_BACKSLASH; + if (extended) nextisliteral = TRUE; else + { + if (*posix < 127 && strchr(posix_meta_escapes, *posix) != NULL) + { + if (isdigit(*posix)) PUTCHARS(STR_BACKSLASH); + if (p + 1 > endp) return PCRE2_ERROR_NOMEMORY; + lastspecial = *p++ = *posix++; + plength--; + } + else nextisliteral = TRUE; + } + break; + + case CHAR_RIGHT_PARENTHESIS: + if (!extended || bracount == 0) goto ESCAPE_LITERAL; + bracount--; + goto COPY_SPECIAL; + + case CHAR_LEFT_PARENTHESIS: + bracount++; + /* Fall through */ + + case CHAR_QUESTION_MARK: + case CHAR_PLUS: + case CHAR_LEFT_CURLY_BRACKET: + case CHAR_RIGHT_CURLY_BRACKET: + case CHAR_VERTICAL_LINE: + if (!extended) goto ESCAPE_LITERAL; + /* Fall through */ + + case CHAR_DOT: + case CHAR_DOLLAR_SIGN: + posix_state = POSIX_NOT_BRACKET; + COPY_SPECIAL: + lastspecial = c; + if (p + 1 > endp) return PCRE2_ERROR_NOMEMORY; + *p++ = c; + break; + + case CHAR_ASTERISK: + if (lastspecial != CHAR_ASTERISK) + { + if (!extended && (posix_state < POSIX_NOT_BRACKET || + lastspecial == CHAR_LEFT_PARENTHESIS)) + goto ESCAPE_LITERAL; + goto COPY_SPECIAL; + } + break; /* Ignore second and subsequent asterisks */ + + case CHAR_CIRCUMFLEX_ACCENT: + if (extended) goto COPY_SPECIAL; + if (posix_state == POSIX_START_REGEX || + lastspecial == CHAR_LEFT_PARENTHESIS) + { + posix_state = POSIX_ANCHORED; + goto COPY_SPECIAL; + } + /* Fall through */ + + default: + if (c < 128 && strchr(pcre2_escaped_literals, c) != NULL) + { + ESCAPE_LITERAL: + PUTCHARS(STR_BACKSLASH); + } + lastspecial = 0xff; /* Indicates nothing special */ + if (p + clength > endp) return PCRE2_ERROR_NOMEMORY; + memcpy(p, posix - clength, CU2BYTES(clength)); + p += clength; + posix_state = POSIX_NOT_BRACKET; + break; + } + } + +if (posix_state >= POSIX_CLASS_NOT_STARTED) + return PCRE2_ERROR_MISSING_SQUARE_BRACKET; +convlength += p - pp; /* Final segment */ +*bufflenptr = convlength; +*p++ = 0; +return 0; +} + + +/************************************************* +* Convert a glob pattern * +*************************************************/ + +/* Context for writing the output into a buffer. */ + +typedef struct pcre2_output_context { + PCRE2_UCHAR *output; /* current output position */ + PCRE2_SPTR output_end; /* output end */ + PCRE2_SIZE output_size; /* size of the output */ + uint8_t out_str[8]; /* string copied to the output */ +} pcre2_output_context; + + +/* Write a character into the output. + +Arguments: + out output context + chr the next character +*/ + +static void +convert_glob_write(pcre2_output_context *out, PCRE2_UCHAR chr) +{ +out->output_size++; + +if (out->output < out->output_end) + *out->output++ = chr; +} + + +/* Write a string into the output. + +Arguments: + out output context + length length of out->out_str +*/ + +static void +convert_glob_write_str(pcre2_output_context *out, PCRE2_SIZE length) +{ +uint8_t *out_str = out->out_str; +PCRE2_UCHAR *output = out->output; +PCRE2_SPTR output_end = out->output_end; +PCRE2_SIZE output_size = out->output_size; + +do + { + output_size++; + + if (output < output_end) + *output++ = *out_str++; + } +while (--length != 0); + +out->output = output; +out->output_size = output_size; +} + + +/* Prints the separator into the output. + +Arguments: + out output context + separator glob separator + with_escape backslash is needed before separator +*/ + +static void +convert_glob_print_separator(pcre2_output_context *out, + PCRE2_UCHAR separator, BOOL with_escape) +{ +if (with_escape) + convert_glob_write(out, CHAR_BACKSLASH); + +convert_glob_write(out, separator); +} + + +/* Prints a wildcard into the output. + +Arguments: + out output context + separator glob separator + with_escape backslash is needed before separator +*/ + +static void +convert_glob_print_wildcard(pcre2_output_context *out, + PCRE2_UCHAR separator, BOOL with_escape) +{ +out->out_str[0] = CHAR_LEFT_SQUARE_BRACKET; +out->out_str[1] = CHAR_CIRCUMFLEX_ACCENT; +convert_glob_write_str(out, 2); + +convert_glob_print_separator(out, separator, with_escape); + +convert_glob_write(out, CHAR_RIGHT_SQUARE_BRACKET); +} + + +/* Parse a posix class. + +Arguments: + from starting point of scanning the range + pattern_end end of pattern + out output context + +Returns: >0 => class index + 0 => malformed class +*/ + +static int +convert_glob_parse_class(PCRE2_SPTR *from, PCRE2_SPTR pattern_end, + pcre2_output_context *out) +{ +static const char *posix_classes = "alnum:alpha:ascii:blank:cntrl:digit:" + "graph:lower:print:punct:space:upper:word:xdigit:"; +PCRE2_SPTR start = *from + 1; +PCRE2_SPTR pattern = start; +const char *class_ptr; +PCRE2_UCHAR c; +int class_index; + +while (TRUE) + { + if (pattern >= pattern_end) return 0; + + c = *pattern++; + + if (c < CHAR_a || c > CHAR_z) break; + } + +if (c != CHAR_COLON || pattern >= pattern_end || + *pattern != CHAR_RIGHT_SQUARE_BRACKET) + return 0; + +class_ptr = posix_classes; +class_index = 1; + +while (TRUE) + { + if (*class_ptr == CHAR_NUL) return 0; + + pattern = start; + + while (*pattern == (PCRE2_UCHAR) *class_ptr) + { + if (*pattern == CHAR_COLON) + { + pattern += 2; + start -= 2; + + do convert_glob_write(out, *start++); while (start < pattern); + + *from = pattern; + return class_index; + } + pattern++; + class_ptr++; + } + + while (*class_ptr != CHAR_COLON) class_ptr++; + class_ptr++; + class_index++; + } +} + +/* Checks whether the character is in the class. + +Arguments: + class_index class index + c character + +Returns: !0 => character is found in the class + 0 => otherwise +*/ + +static BOOL +convert_glob_char_in_class(int class_index, PCRE2_UCHAR c) +{ +switch (class_index) + { + case 1: return isalnum(c); + case 2: return isalpha(c); + case 3: return 1; + case 4: return c == CHAR_HT || c == CHAR_SPACE; + case 5: return iscntrl(c); + case 6: return isdigit(c); + case 7: return isgraph(c); + case 8: return islower(c); + case 9: return isprint(c); + case 10: return ispunct(c); + case 11: return isspace(c); + case 12: return isupper(c); + case 13: return isalnum(c) || c == CHAR_UNDERSCORE; + default: return isxdigit(c); + } +} + +/* Parse a range of characters. + +Arguments: + from starting point of scanning the range + pattern_end end of pattern + out output context + separator glob separator + with_escape backslash is needed before separator + +Returns: 0 => success + !0 => error code +*/ + +static int +convert_glob_parse_range(PCRE2_SPTR *from, PCRE2_SPTR pattern_end, + pcre2_output_context *out, BOOL utf, PCRE2_UCHAR separator, + BOOL with_escape, PCRE2_UCHAR escape, BOOL no_wildsep) +{ +BOOL is_negative = FALSE; +BOOL separator_seen = FALSE; +BOOL has_prev_c; +PCRE2_SPTR pattern = *from; +PCRE2_SPTR char_start = NULL; +uint32_t c, prev_c; +int len, class_index; + +(void)utf; /* Avoid compiler warning. */ + +if (pattern >= pattern_end) + { + *from = pattern; + return PCRE2_ERROR_MISSING_SQUARE_BRACKET; + } + +if (*pattern == CHAR_EXCLAMATION_MARK + || *pattern == CHAR_CIRCUMFLEX_ACCENT) + { + pattern++; + + if (pattern >= pattern_end) + { + *from = pattern; + return PCRE2_ERROR_MISSING_SQUARE_BRACKET; + } + + is_negative = TRUE; + + out->out_str[0] = CHAR_LEFT_SQUARE_BRACKET; + out->out_str[1] = CHAR_CIRCUMFLEX_ACCENT; + len = 2; + + if (!no_wildsep) + { + if (with_escape) + { + out->out_str[len] = CHAR_BACKSLASH; + len++; + } + out->out_str[len] = (uint8_t) separator; + } + + convert_glob_write_str(out, len + 1); + } +else + convert_glob_write(out, CHAR_LEFT_SQUARE_BRACKET); + +has_prev_c = FALSE; +prev_c = 0; + +if (*pattern == CHAR_RIGHT_SQUARE_BRACKET) + { + out->out_str[0] = CHAR_BACKSLASH; + out->out_str[1] = CHAR_RIGHT_SQUARE_BRACKET; + convert_glob_write_str(out, 2); + has_prev_c = TRUE; + prev_c = CHAR_RIGHT_SQUARE_BRACKET; + pattern++; + } + +while (pattern < pattern_end) + { + char_start = pattern; + GETCHARINCTEST(c, pattern); + + if (c == CHAR_RIGHT_SQUARE_BRACKET) + { + convert_glob_write(out, c); + + if (!is_negative && !no_wildsep && separator_seen) + { + out->out_str[0] = CHAR_LEFT_PARENTHESIS; + out->out_str[1] = CHAR_QUESTION_MARK; + out->out_str[2] = CHAR_LESS_THAN_SIGN; + out->out_str[3] = CHAR_EXCLAMATION_MARK; + convert_glob_write_str(out, 4); + + convert_glob_print_separator(out, separator, with_escape); + convert_glob_write(out, CHAR_RIGHT_PARENTHESIS); + } + + *from = pattern; + return 0; + } + + if (pattern >= pattern_end) break; + + if (c == CHAR_LEFT_SQUARE_BRACKET && *pattern == CHAR_COLON) + { + *from = pattern; + class_index = convert_glob_parse_class(from, pattern_end, out); + + if (class_index != 0) + { + pattern = *from; + + has_prev_c = FALSE; + prev_c = 0; + + if (!is_negative && + convert_glob_char_in_class (class_index, separator)) + separator_seen = TRUE; + continue; + } + } + else if (c == CHAR_MINUS && has_prev_c && + *pattern != CHAR_RIGHT_SQUARE_BRACKET) + { + convert_glob_write(out, CHAR_MINUS); + + char_start = pattern; + GETCHARINCTEST(c, pattern); + + if (pattern >= pattern_end) break; + + if (escape != 0 && c == escape) + { + char_start = pattern; + GETCHARINCTEST(c, pattern); + } + else if (c == CHAR_LEFT_SQUARE_BRACKET && *pattern == CHAR_COLON) + { + *from = pattern; + return PCRE2_ERROR_CONVERT_SYNTAX; + } + + if (prev_c > c) + { + *from = pattern; + return PCRE2_ERROR_CONVERT_SYNTAX; + } + + if (prev_c < separator && separator < c) separator_seen = TRUE; + + has_prev_c = FALSE; + prev_c = 0; + } + else + { + if (escape != 0 && c == escape) + { + char_start = pattern; + GETCHARINCTEST(c, pattern); + + if (pattern >= pattern_end) break; + } + + has_prev_c = TRUE; + prev_c = c; + } + + if (c == CHAR_LEFT_SQUARE_BRACKET || c == CHAR_RIGHT_SQUARE_BRACKET || + c == CHAR_BACKSLASH || c == CHAR_MINUS) + convert_glob_write(out, CHAR_BACKSLASH); + + if (c == separator) separator_seen = TRUE; + + do convert_glob_write(out, *char_start++); while (char_start < pattern); + } + +*from = pattern; +return PCRE2_ERROR_MISSING_SQUARE_BRACKET; +} + + +/* Prints a (*COMMIT) into the output. + +Arguments: + out output context +*/ + +static void +convert_glob_print_commit(pcre2_output_context *out) +{ +out->out_str[0] = CHAR_LEFT_PARENTHESIS; +out->out_str[1] = CHAR_ASTERISK; +out->out_str[2] = CHAR_C; +out->out_str[3] = CHAR_O; +out->out_str[4] = CHAR_M; +out->out_str[5] = CHAR_M; +out->out_str[6] = CHAR_I; +out->out_str[7] = CHAR_T; +convert_glob_write_str(out, 8); +convert_glob_write(out, CHAR_RIGHT_PARENTHESIS); +} + + +/* Bash glob converter. + +Arguments: + pattype the pattern type + pattern the pattern + plength length in code units + utf TRUE if UTF + use_buffer where to put the output + use_length length of use_buffer + bufflenptr where to put the used length + dummyrun TRUE if a dummy run + ccontext the convert context + +Returns: 0 => success + !0 => error code +*/ + +static int +convert_glob(uint32_t options, PCRE2_SPTR pattern, PCRE2_SIZE plength, + BOOL utf, PCRE2_UCHAR *use_buffer, PCRE2_SIZE use_length, + PCRE2_SIZE *bufflenptr, BOOL dummyrun, pcre2_convert_context *ccontext) +{ +pcre2_output_context out; +PCRE2_SPTR pattern_start = pattern; +PCRE2_SPTR pattern_end = pattern + plength; +PCRE2_UCHAR separator = ccontext->glob_separator; +PCRE2_UCHAR escape = ccontext->glob_escape; +PCRE2_UCHAR c; +BOOL no_wildsep = (options & PCRE2_CONVERT_GLOB_NO_WILD_SEPARATOR) != 0; +BOOL no_starstar = (options & PCRE2_CONVERT_GLOB_NO_STARSTAR) != 0; +BOOL in_atomic = FALSE; +BOOL after_starstar = FALSE; +BOOL no_slash_z = FALSE; +BOOL with_escape, is_start, after_separator; +int result = 0; + +(void)utf; /* Avoid compiler warning. */ + +#ifdef SUPPORT_UNICODE +if (utf && (separator >= 128 || escape >= 128)) + { + /* Currently only ASCII characters are supported. */ + *bufflenptr = 0; + return PCRE2_ERROR_CONVERT_SYNTAX; + } +#endif + +with_escape = strchr(pcre2_escaped_literals, separator) != NULL; + +/* Initialize default for error offset as end of input. */ +out.output = use_buffer; +out.output_end = use_buffer + use_length; +out.output_size = 0; + +out.out_str[0] = CHAR_LEFT_PARENTHESIS; +out.out_str[1] = CHAR_QUESTION_MARK; +out.out_str[2] = CHAR_s; +out.out_str[3] = CHAR_RIGHT_PARENTHESIS; +convert_glob_write_str(&out, 4); + +is_start = TRUE; + +if (pattern < pattern_end && pattern[0] == CHAR_ASTERISK) + { + if (no_wildsep) + is_start = FALSE; + else if (!no_starstar && pattern + 1 < pattern_end && + pattern[1] == CHAR_ASTERISK) + is_start = FALSE; + } + +if (is_start) + { + out.out_str[0] = CHAR_BACKSLASH; + out.out_str[1] = CHAR_A; + convert_glob_write_str(&out, 2); + } + +while (pattern < pattern_end) + { + c = *pattern++; + + if (c == CHAR_ASTERISK) + { + is_start = pattern == pattern_start + 1; + + if (in_atomic) + { + convert_glob_write(&out, CHAR_RIGHT_PARENTHESIS); + in_atomic = FALSE; + } + + if (!no_starstar && pattern < pattern_end && *pattern == CHAR_ASTERISK) + { + after_separator = is_start || (pattern[-2] == separator); + + do pattern++; while (pattern < pattern_end && + *pattern == CHAR_ASTERISK); + + if (pattern >= pattern_end) + { + no_slash_z = TRUE; + break; + } + + after_starstar = TRUE; + + if (after_separator && escape != 0 && *pattern == escape && + pattern + 1 < pattern_end && pattern[1] == separator) + pattern++; + + if (is_start) + { + if (*pattern != separator) continue; + + out.out_str[0] = CHAR_LEFT_PARENTHESIS; + out.out_str[1] = CHAR_QUESTION_MARK; + out.out_str[2] = CHAR_COLON; + out.out_str[3] = CHAR_BACKSLASH; + out.out_str[4] = CHAR_A; + out.out_str[5] = CHAR_VERTICAL_LINE; + convert_glob_write_str(&out, 6); + + convert_glob_print_separator(&out, separator, with_escape); + convert_glob_write(&out, CHAR_RIGHT_PARENTHESIS); + + pattern++; + continue; + } + + convert_glob_print_commit(&out); + + if (!after_separator || *pattern != separator) + { + out.out_str[0] = CHAR_DOT; + out.out_str[1] = CHAR_ASTERISK; + out.out_str[2] = CHAR_QUESTION_MARK; + convert_glob_write_str(&out, 3); + continue; + } + + out.out_str[0] = CHAR_LEFT_PARENTHESIS; + out.out_str[1] = CHAR_QUESTION_MARK; + out.out_str[2] = CHAR_COLON; + out.out_str[3] = CHAR_DOT; + out.out_str[4] = CHAR_ASTERISK; + out.out_str[5] = CHAR_QUESTION_MARK; + + convert_glob_write_str(&out, 6); + + convert_glob_print_separator(&out, separator, with_escape); + + out.out_str[0] = CHAR_RIGHT_PARENTHESIS; + out.out_str[1] = CHAR_QUESTION_MARK; + out.out_str[2] = CHAR_QUESTION_MARK; + convert_glob_write_str(&out, 3); + + pattern++; + continue; + } + + if (pattern < pattern_end && *pattern == CHAR_ASTERISK) + { + do pattern++; while (pattern < pattern_end && + *pattern == CHAR_ASTERISK); + } + + if (no_wildsep) + { + if (pattern >= pattern_end) + { + no_slash_z = TRUE; + break; + } + + /* Start check must be after the end check. */ + if (is_start) continue; + } + + if (!is_start) + { + if (after_starstar) + { + out.out_str[0] = CHAR_LEFT_PARENTHESIS; + out.out_str[1] = CHAR_QUESTION_MARK; + out.out_str[2] = CHAR_GREATER_THAN_SIGN; + convert_glob_write_str(&out, 3); + in_atomic = TRUE; + } + else + convert_glob_print_commit(&out); + } + + if (no_wildsep) + convert_glob_write(&out, CHAR_DOT); + else + convert_glob_print_wildcard(&out, separator, with_escape); + + out.out_str[0] = CHAR_ASTERISK; + out.out_str[1] = CHAR_QUESTION_MARK; + if (pattern >= pattern_end) + out.out_str[1] = CHAR_PLUS; + convert_glob_write_str(&out, 2); + continue; + } + + if (c == CHAR_QUESTION_MARK) + { + if (no_wildsep) + convert_glob_write(&out, CHAR_DOT); + else + convert_glob_print_wildcard(&out, separator, with_escape); + continue; + } + + if (c == CHAR_LEFT_SQUARE_BRACKET) + { + result = convert_glob_parse_range(&pattern, pattern_end, + &out, utf, separator, with_escape, escape, no_wildsep); + if (result != 0) break; + continue; + } + + if (escape != 0 && c == escape) + { + if (pattern >= pattern_end) + { + result = PCRE2_ERROR_CONVERT_SYNTAX; + break; + } + c = *pattern++; + } + + if (c < 128 && strchr(pcre2_escaped_literals, c) != NULL) + convert_glob_write(&out, CHAR_BACKSLASH); + + convert_glob_write(&out, c); + } + +if (result == 0) + { + if (!no_slash_z) + { + out.out_str[0] = CHAR_BACKSLASH; + out.out_str[1] = CHAR_z; + convert_glob_write_str(&out, 2); + } + + if (in_atomic) + convert_glob_write(&out, CHAR_RIGHT_PARENTHESIS); + + convert_glob_write(&out, CHAR_NUL); + + if (!dummyrun && out.output_size != (PCRE2_SIZE) (out.output - use_buffer)) + result = PCRE2_ERROR_NOMEMORY; + } + +if (result != 0) + { + *bufflenptr = pattern - pattern_start; + return result; + } + +*bufflenptr = out.output_size - 1; +return 0; +} + + +/************************************************* +* Convert pattern * +*************************************************/ + +/* This is the external-facing function for converting other forms of pattern +into PCRE2 regular expression patterns. On error, the bufflenptr argument is +used to return an offset in the original pattern. + +Arguments: + pattern the input pattern + plength length of input, or PCRE2_ZERO_TERMINATED + options options bits + buffptr pointer to pointer to output buffer + bufflenptr pointer to length of output buffer + ccontext convert context or NULL + +Returns: 0 for success, else an error code (+ve or -ve) +*/ + +PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION +pcre2_pattern_convert(PCRE2_SPTR pattern, PCRE2_SIZE plength, uint32_t options, + PCRE2_UCHAR **buffptr, PCRE2_SIZE *bufflenptr, + pcre2_convert_context *ccontext) +{ +int i, rc; +PCRE2_UCHAR dummy_buffer[DUMMY_BUFFER_SIZE]; +PCRE2_UCHAR *use_buffer = dummy_buffer; +PCRE2_SIZE use_length = DUMMY_BUFFER_SIZE; +BOOL utf = (options & PCRE2_CONVERT_UTF) != 0; +uint32_t pattype = options & TYPE_OPTIONS; + +if (pattern == NULL || bufflenptr == NULL) return PCRE2_ERROR_NULL; + +if ((options & ~ALL_OPTIONS) != 0 || /* Undefined bit set */ + (pattype & (~pattype+1)) != pattype || /* More than one type set */ + pattype == 0) /* No type set */ + { + *bufflenptr = 0; /* Error offset */ + return PCRE2_ERROR_BADOPTION; + } + +if (plength == PCRE2_ZERO_TERMINATED) plength = PRIV(strlen)(pattern); +if (ccontext == NULL) ccontext = + (pcre2_convert_context *)(&PRIV(default_convert_context)); + +/* Check UTF if required. */ + +#ifndef SUPPORT_UNICODE +if (utf) + { + *bufflenptr = 0; /* Error offset */ + return PCRE2_ERROR_UNICODE_NOT_SUPPORTED; + } +#else +if (utf && (options & PCRE2_CONVERT_NO_UTF_CHECK) == 0) + { + PCRE2_SIZE erroroffset; + rc = PRIV(valid_utf)(pattern, plength, &erroroffset); + if (rc != 0) + { + *bufflenptr = erroroffset; + return rc; + } + } +#endif + +/* If buffptr is not NULL, and what it points to is not NULL, we are being +provided with a buffer and a length, so set them as the buffer to use. */ + +if (buffptr != NULL && *buffptr != NULL) + { + use_buffer = *buffptr; + use_length = *bufflenptr; + } + +/* Call an individual converter, either just once (if a buffer was provided or +just the length is needed), or twice (if a memory allocation is required). */ + +for (i = 0; i < 2; i++) + { + PCRE2_UCHAR *allocated; + BOOL dummyrun = buffptr == NULL || *buffptr == NULL; + + switch(pattype) + { + case PCRE2_CONVERT_GLOB: + rc = convert_glob(options & ~PCRE2_CONVERT_GLOB, pattern, plength, utf, + use_buffer, use_length, bufflenptr, dummyrun, ccontext); + break; + + case PCRE2_CONVERT_POSIX_BASIC: + case PCRE2_CONVERT_POSIX_EXTENDED: + rc = convert_posix(pattype, pattern, plength, utf, use_buffer, use_length, + bufflenptr, dummyrun, ccontext); + break; + + default: + *bufflenptr = 0; /* Error offset */ + return PCRE2_ERROR_INTERNAL; + } + + if (rc != 0 || /* Error */ + buffptr == NULL || /* Just the length is required */ + *buffptr != NULL) /* Buffer was provided or allocated */ + return rc; + + /* Allocate memory for the buffer, with hidden space for an allocator at + the start. The next time round the loop runs the conversion for real. */ + + allocated = PRIV(memctl_malloc)(sizeof(pcre2_memctl) + + (*bufflenptr + 1)*PCRE2_CODE_UNIT_WIDTH, (pcre2_memctl *)ccontext); + if (allocated == NULL) return PCRE2_ERROR_NOMEMORY; + *buffptr = (PCRE2_UCHAR *)(((char *)allocated) + sizeof(pcre2_memctl)); + + use_buffer = *buffptr; + use_length = *bufflenptr + 1; + } + +/* Control should never get here. */ + +return PCRE2_ERROR_INTERNAL; +} + + +/************************************************* +* Free converted pattern * +*************************************************/ + +/* This frees a converted pattern that was put in newly-allocated memory. + +Argument: the converted pattern +Returns: nothing +*/ + +PCRE2_EXP_DEFN void PCRE2_CALL_CONVENTION +pcre2_converted_pattern_free(PCRE2_UCHAR *converted) +{ +if (converted != NULL) + { + pcre2_memctl *memctl = + (pcre2_memctl *)((char *)converted - sizeof(pcre2_memctl)); + memctl->free(memctl, memctl->memory_data); + } +} + +/* End of pcre2_convert.c */ diff --git a/ProcessHacker/pcre/pcre2_dfa_match.c b/ProcessHacker/pcre/pcre2_dfa_match.c index c6184ff5e9ea..9b43237da750 100644 --- a/ProcessHacker/pcre/pcre2_dfa_match.c +++ b/ProcessHacker/pcre/pcre2_dfa_match.c @@ -181,7 +181,8 @@ static const uint8_t coptable[] = { 0, 0, 0, /* BRAZERO, BRAMINZERO, BRAPOSZERO */ 0, 0, 0, /* MARK, PRUNE, PRUNE_ARG */ 0, 0, 0, 0, /* SKIP, SKIP_ARG, THEN, THEN_ARG */ - 0, 0, 0, 0, /* COMMIT, FAIL, ACCEPT, ASSERT_ACCEPT */ + 0, 0, /* COMMIT, COMMIT_ARG */ + 0, 0, 0, /* FAIL, ACCEPT, ASSERT_ACCEPT */ 0, 0, 0 /* CLOSE, SKIPZERO, DEFINE */ }; @@ -254,7 +255,8 @@ static const uint8_t poptable[] = { 0, 0, 0, /* BRAZERO, BRAMINZERO, BRAPOSZERO */ 0, 0, 0, /* MARK, PRUNE, PRUNE_ARG */ 0, 0, 0, 0, /* SKIP, SKIP_ARG, THEN, THEN_ARG */ - 0, 0, 0, 0, /* COMMIT, FAIL, ACCEPT, ASSERT_ACCEPT */ + 0, 0, /* COMMIT, COMMIT_ARG */ + 0, 0, 0, /* FAIL, ACCEPT, ASSERT_ACCEPT */ 0, 0, 0 /* CLOSE, SKIPZERO, DEFINE */ }; @@ -292,6 +294,35 @@ typedef struct stateblock { #define INTS_PER_STATEBLOCK (int)(sizeof(stateblock)/sizeof(int)) +/* Before version 10.32 the recursive calls of internal_dfa_match() were passed +local working space and output vectors that were created on the stack. This has +caused issues for some patterns, especially in small-stack environments such as +Windows. A new scheme is now in use which sets up a vector on the stack, but if +this is too small, heap memory is used, up to the heap_limit. The main +parameters are all numbers of ints because the workspace is a vector of ints. + +The size of the starting stack vector, DFA_START_RWS_SIZE, is in bytes, and is +defined in pcre2_internal.h so as to be available to pcre2test when it is +finding the minimum heap requirement for a match. */ + +#define OVEC_UNIT (sizeof(PCRE2_SIZE)/sizeof(int)) + +#define RWS_BASE_SIZE (DFA_START_RWS_SIZE/sizeof(int)) /* Stack vector */ +#define RWS_RSIZE 1000 /* Work size for recursion */ +#define RWS_OVEC_RSIZE (1000*OVEC_UNIT) /* Ovector for recursion */ +#define RWS_OVEC_OSIZE (2*OVEC_UNIT) /* Ovector in other cases */ + +/* This structure is at the start of each workspace block. */ + +typedef struct RWS_anchor { + struct RWS_anchor *next; + unsigned int size; /* Number of ints */ + unsigned int free; /* Number of ints */ +} RWS_anchor; + +#define RWS_ANCHOR_SIZE (sizeof(RWS_anchor)/sizeof(int)) + + /************************************************* * Process a callout * @@ -353,6 +384,61 @@ return (mb->callout)(cb, mb->callout_data); +/************************************************* +* Expand local workspace memory * +*************************************************/ + +/* This function is called when internal_dfa_match() is about to be called +recursively and there is insufficient working space left in the current +workspace block. If there's an existing next block, use it; otherwise get a new +block unless the heap limit is reached. + +Arguments: + rwsptr pointer to block pointer (updated) + ovecsize space needed for an ovector + mb the match block + +Returns: 0 rwsptr has been updated + !0 an error code +*/ + +static int +more_workspace(RWS_anchor **rwsptr, unsigned int ovecsize, dfa_match_block *mb) +{ +RWS_anchor *rws = *rwsptr; +RWS_anchor *new; + +if (rws->next != NULL) + { + new = rws->next; + } + +/* All sizes are in units of sizeof(int), except for mb->heaplimit, which is in +kibibytes. */ + +else + { + unsigned int newsize = rws->size * 2; + unsigned int heapleft = (unsigned int) + (((1024/sizeof(int))*mb->heap_limit - mb->heap_used)); + if (newsize > heapleft) newsize = heapleft; + if (newsize < RWS_RSIZE + ovecsize + RWS_ANCHOR_SIZE) + return PCRE2_ERROR_HEAPLIMIT; + new = mb->memctl.malloc(newsize*sizeof(int), mb->memctl.memory_data); + if (new == NULL) return PCRE2_ERROR_NOMEMORY; + mb->heap_used += newsize; + new->next = NULL; + new->size = newsize; + rws->next = new; + } + +new->free = new->size - RWS_ANCHOR_SIZE; +*rwsptr = new; +return 0; +} + + + /************************************************* * Match a Regular Expression - DFA engine * *************************************************/ @@ -431,7 +517,8 @@ internal_dfa_match( uint32_t offsetcount, int *workspace, int wscount, - uint32_t rlevel) + uint32_t rlevel, + int *RWS) { stateblock *active_states, *new_states, *temp_states; stateblock *next_active_state, *next_new_state; @@ -788,7 +875,7 @@ for (;;) else if (match_count > 0 && ++match_count * 2 > (int)offsetcount) match_count = 0; count = ((match_count == 0)? (int)offsetcount : match_count * 2) - 2; - if (count > 0) memmove(offsets + 2, offsets, + if (count > 0) (void)memmove(offsets + 2, offsets, (size_t)count * sizeof(PCRE2_SIZE)); if (offsetcount >= 2) { @@ -2587,10 +2674,22 @@ for (;;) case OP_ASSERTBACK: case OP_ASSERTBACK_NOT: { - PCRE2_SPTR endasscode = code + GET(code, 1); - PCRE2_SIZE local_offsets[2]; int rc; - int local_workspace[1000]; + int *local_workspace; + PCRE2_SIZE *local_offsets; + PCRE2_SPTR endasscode = code + GET(code, 1); + RWS_anchor *rws = (RWS_anchor *)RWS; + + if (rws->free < RWS_RSIZE + RWS_OVEC_OSIZE) + { + rc = more_workspace(&rws, RWS_OVEC_OSIZE, mb); + if (rc != 0) return rc; + RWS = (int *)rws; + } + + local_offsets = (PCRE2_SIZE *)(RWS + rws->size - rws->free); + local_workspace = ((int *)local_offsets) + RWS_OVEC_OSIZE; + rws->free -= RWS_RSIZE + RWS_OVEC_OSIZE; while (*endasscode == OP_ALT) endasscode += GET(endasscode, 1); @@ -2600,10 +2699,13 @@ for (;;) ptr, /* where we currently are */ (PCRE2_SIZE)(ptr - start_subject), /* start offset */ local_offsets, /* offset vector */ - sizeof(local_offsets)/sizeof(PCRE2_SIZE), /* size of same */ + RWS_OVEC_OSIZE/OVEC_UNIT, /* size of same */ local_workspace, /* workspace vector */ - sizeof(local_workspace)/sizeof(int), /* size of same */ - rlevel); /* function recursion level */ + RWS_RSIZE, /* size of same */ + rlevel, /* function recursion level */ + RWS); /* recursion workspace */ + + rws->free += RWS_RSIZE + RWS_OVEC_OSIZE; if (rc < 0 && rc != PCRE2_ERROR_NOMATCH) return rc; if ((rc >= 0) == (codevalue == OP_ASSERT || codevalue == OP_ASSERTBACK)) @@ -2615,8 +2717,6 @@ for (;;) case OP_COND: case OP_SCOND: { - PCRE2_SIZE local_offsets[1000]; - int local_workspace[1000]; int codelink = (int)GET(code, 1); PCRE2_UCHAR condcode; @@ -2673,8 +2773,22 @@ for (;;) else { int rc; + int *local_workspace; + PCRE2_SIZE *local_offsets; PCRE2_SPTR asscode = code + LINK_SIZE + 1; PCRE2_SPTR endasscode = asscode + GET(asscode, 1); + RWS_anchor *rws = (RWS_anchor *)RWS; + + if (rws->free < RWS_RSIZE + RWS_OVEC_OSIZE) + { + rc = more_workspace(&rws, RWS_OVEC_OSIZE, mb); + if (rc != 0) return rc; + RWS = (int *)rws; + } + + local_offsets = (PCRE2_SIZE *)(RWS + rws->size - rws->free); + local_workspace = ((int *)local_offsets) + RWS_OVEC_OSIZE; + rws->free -= RWS_RSIZE + RWS_OVEC_OSIZE; while (*endasscode == OP_ALT) endasscode += GET(endasscode, 1); @@ -2684,10 +2798,13 @@ for (;;) ptr, /* where we currently are */ (PCRE2_SIZE)(ptr - start_subject), /* start offset */ local_offsets, /* offset vector */ - sizeof(local_offsets)/sizeof(PCRE2_SIZE), /* size of same */ + RWS_OVEC_OSIZE/OVEC_UNIT, /* size of same */ local_workspace, /* workspace vector */ - sizeof(local_workspace)/sizeof(int), /* size of same */ - rlevel); /* function recursion level */ + RWS_RSIZE, /* size of same */ + rlevel, /* function recursion level */ + RWS); /* recursion workspace */ + + rws->free += RWS_RSIZE + RWS_OVEC_OSIZE; if (rc < 0 && rc != PCRE2_ERROR_NOMATCH) return rc; if ((rc >= 0) == @@ -2702,13 +2819,25 @@ for (;;) /*-----------------------------------------------------------------*/ case OP_RECURSE: { + int rc; + int *local_workspace; + PCRE2_SIZE *local_offsets; + RWS_anchor *rws = (RWS_anchor *)RWS; dfa_recursion_info *ri; - PCRE2_SIZE local_offsets[1000]; - int local_workspace[1000]; PCRE2_SPTR callpat = start_code + GET(code, 1); uint32_t recno = (callpat == mb->start_code)? 0 : GET2(callpat, 1 + LINK_SIZE); - int rc; + + if (rws->free < RWS_RSIZE + RWS_OVEC_RSIZE) + { + rc = more_workspace(&rws, RWS_OVEC_RSIZE, mb); + if (rc != 0) return rc; + RWS = (int *)rws; + } + + local_offsets = (PCRE2_SIZE *)(RWS + rws->size - rws->free); + local_workspace = ((int *)local_offsets) + RWS_OVEC_RSIZE; + rws->free -= RWS_RSIZE + RWS_OVEC_RSIZE; /* Check for repeating a recursion without advancing the subject pointer. This should catch convoluted mutual recursions. (Some simple @@ -2732,11 +2861,13 @@ for (;;) ptr, /* where we currently are */ (PCRE2_SIZE)(ptr - start_subject), /* start offset */ local_offsets, /* offset vector */ - sizeof(local_offsets)/sizeof(PCRE2_SIZE), /* size of same */ + RWS_OVEC_RSIZE/OVEC_UNIT, /* size of same */ local_workspace, /* workspace vector */ - sizeof(local_workspace)/sizeof(int), /* size of same */ - rlevel); /* function recursion level */ + RWS_RSIZE, /* size of same */ + rlevel, /* function recursion level */ + RWS); /* recursion workspace */ + rws->free += RWS_RSIZE + RWS_OVEC_RSIZE; mb->recursive = new_recursive.prevrec; /* Done this recursion */ /* Ran out of internal offsets */ @@ -2782,10 +2913,25 @@ for (;;) case OP_SCBRAPOS: case OP_BRAPOSZERO: { + int rc; + int *local_workspace; + PCRE2_SIZE *local_offsets; PCRE2_SIZE charcount, matched_count; PCRE2_SPTR local_ptr = ptr; + RWS_anchor *rws = (RWS_anchor *)RWS; BOOL allow_zero; + if (rws->free < RWS_RSIZE + RWS_OVEC_OSIZE) + { + rc = more_workspace(&rws, RWS_OVEC_OSIZE, mb); + if (rc != 0) return rc; + RWS = (int *)rws; + } + + local_offsets = (PCRE2_SIZE *)(RWS + rws->size - rws->free); + local_workspace = ((int *)local_offsets) + RWS_OVEC_OSIZE; + rws->free -= RWS_RSIZE + RWS_OVEC_OSIZE; + if (codevalue == OP_BRAPOSZERO) { allow_zero = TRUE; @@ -2798,19 +2944,17 @@ for (;;) for (matched_count = 0;; matched_count++) { - PCRE2_SIZE local_offsets[2]; - int local_workspace[1000]; - - int rc = internal_dfa_match( + rc = internal_dfa_match( mb, /* fixed match data */ code, /* this subexpression's code */ local_ptr, /* where we currently are */ (PCRE2_SIZE)(ptr - start_subject), /* start offset */ local_offsets, /* offset vector */ - sizeof(local_offsets)/sizeof(PCRE2_SIZE), /* size of same */ + RWS_OVEC_OSIZE/OVEC_UNIT, /* size of same */ local_workspace, /* workspace vector */ - sizeof(local_workspace)/sizeof(int), /* size of same */ - rlevel); /* function recursion level */ + RWS_RSIZE, /* size of same */ + rlevel, /* function recursion level */ + RWS); /* recursion workspace */ /* Failed to match */ @@ -2827,6 +2971,8 @@ for (;;) local_ptr += charcount; /* Advance temporary position ptr */ } + rws->free += RWS_RSIZE + RWS_OVEC_OSIZE; + /* At this point we have matched the subpattern matched_count times, and local_ptr is pointing to the character after the end of the last match. */ @@ -2869,19 +3015,35 @@ for (;;) /*-----------------------------------------------------------------*/ case OP_ONCE: { - PCRE2_SIZE local_offsets[2]; - int local_workspace[1000]; + int rc; + int *local_workspace; + PCRE2_SIZE *local_offsets; + RWS_anchor *rws = (RWS_anchor *)RWS; - int rc = internal_dfa_match( + if (rws->free < RWS_RSIZE + RWS_OVEC_OSIZE) + { + rc = more_workspace(&rws, RWS_OVEC_OSIZE, mb); + if (rc != 0) return rc; + RWS = (int *)rws; + } + + local_offsets = (PCRE2_SIZE *)(RWS + rws->size - rws->free); + local_workspace = ((int *)local_offsets) + RWS_OVEC_OSIZE; + rws->free -= RWS_RSIZE + RWS_OVEC_OSIZE; + + rc = internal_dfa_match( mb, /* fixed match data */ code, /* this subexpression's code */ ptr, /* where we currently are */ (PCRE2_SIZE)(ptr - start_subject), /* start offset */ local_offsets, /* offset vector */ - sizeof(local_offsets)/sizeof(PCRE2_SIZE), /* size of same */ + RWS_OVEC_OSIZE/OVEC_UNIT, /* size of same */ local_workspace, /* workspace vector */ - sizeof(local_workspace)/sizeof(int), /* size of same */ - rlevel); /* function recursion level */ + RWS_RSIZE, /* size of same */ + rlevel, /* function recursion level */ + RWS); /* recursion workspace */ + + rws->free += RWS_RSIZE + RWS_OVEC_OSIZE; if (rc >= 0) { @@ -3063,6 +3225,7 @@ pcre2_dfa_match(const pcre2_code *code, PCRE2_SPTR subject, PCRE2_SIZE length, PCRE2_SIZE start_offset, uint32_t options, pcre2_match_data *match_data, pcre2_match_context *mcontext, int *workspace, PCRE2_SIZE wscount) { +int rc; const pcre2_real_code *re = (const pcre2_real_code *)code; PCRE2_SPTR start_match; @@ -3071,9 +3234,9 @@ PCRE2_SPTR bumpalong_limit; PCRE2_SPTR req_cu_ptr; BOOL utf, anchored, startline, firstline; - BOOL has_first_cu = FALSE; BOOL has_req_cu = FALSE; + PCRE2_UCHAR first_cu = 0; PCRE2_UCHAR first_cu2 = 0; PCRE2_UCHAR req_cu = 0; @@ -3088,6 +3251,17 @@ pcre2_callout_block cb; dfa_match_block actual_match_block; dfa_match_block *mb = &actual_match_block; +/* Set up a starting block of memory for use during recursive calls to +internal_dfa_match(). By putting this on the stack, it minimizes resource use +in the case when it is not needed. If this is too small, more memory is +obtained from the heap. At the start of each block is an anchor structure.*/ + +int base_recursion_workspace[RWS_BASE_SIZE]; +RWS_anchor *rws = (RWS_anchor *)base_recursion_workspace; +rws->next = NULL; +rws->size = RWS_BASE_SIZE; +rws->free = RWS_BASE_SIZE - RWS_ANCHOR_SIZE; + /* A length equal to PCRE2_ZERO_TERMINATED implies a zero-terminated subject string. */ @@ -3184,6 +3358,7 @@ if (mcontext == NULL) mb->memctl = re->memctl; mb->match_limit = PRIV(default_match_context).match_limit; mb->match_limit_depth = PRIV(default_match_context).depth_limit; + mb->heap_limit = PRIV(default_match_context).heap_limit; } else { @@ -3198,6 +3373,7 @@ else mb->memctl = mcontext->memctl; mb->match_limit = mcontext->match_limit; mb->match_limit_depth = mcontext->depth_limit; + mb->heap_limit = mcontext->heap_limit; } if (mb->match_limit > re->limit_match) @@ -3206,6 +3382,9 @@ if (mb->match_limit > re->limit_match) if (mb->match_limit_depth > re->limit_depth) mb->match_limit_depth = re->limit_depth; +if (mb->heap_limit > re->limit_heap) + mb->heap_limit = re->limit_heap; + mb->start_code = (PCRE2_UCHAR *)((uint8_t *)re + sizeof(pcre2_real_code)) + re->name_count * re->name_entry_size; mb->tables = re->tables; @@ -3215,6 +3394,7 @@ mb->start_offset = start_offset; mb->moptions = options; mb->poptions = re->overall_options; mb->match_call_count = 0; +mb->heap_used = 0; /* Process the \R and newline settings. */ @@ -3351,8 +3531,6 @@ a match. */ for (;;) { - int rc; - /* ----------------- Start of match optimizations ---------------- */ /* There are some optimizations that avoid running the match if a known @@ -3544,7 +3722,7 @@ for (;;) in characters, we treat it as code units to avoid spending too much time in this optimization. */ - if (end_subject - start_match < re->minlength) return PCRE2_ERROR_NOMATCH; + if (end_subject - start_match < re->minlength) goto NOMATCH_EXIT; /* If req_cu is set, we know that that code unit must appear in the subject for the match to succeed. If the first code unit is set, req_cu @@ -3621,7 +3799,8 @@ for (;;) (uint32_t)match_data->oveccount * 2, /* actual size of same */ workspace, /* workspace vector */ (int)wscount, /* size of same */ - 0); /* function recurse level */ + 0, /* function recurse level */ + base_recursion_workspace); /* initial workspace for recursion */ /* Anything other than "no match" means we are done, always; otherwise, carry on only if not anchored. */ @@ -3637,7 +3816,7 @@ for (;;) match_data->rightchar = (PCRE2_SIZE)( mb->last_used_ptr - subject); match_data->startchar = (PCRE2_SIZE)(start_match - subject); match_data->rc = rc; - return rc; + goto EXIT; } /* Advance to the next subject character unless we are at the end of a line @@ -3668,8 +3847,18 @@ for (;;) } /* "Bumpalong" loop */ +NOMATCH_EXIT: +rc = PCRE2_ERROR_NOMATCH; + +EXIT: +while (rws->next != NULL) + { + RWS_anchor *next = rws->next; + rws->next = next->next; + mb->memctl.free(next, mb->memctl.memory_data); + } -return PCRE2_ERROR_NOMATCH; +return rc; } /* End of pcre2_dfa_match.c */ diff --git a/ProcessHacker/pcre/pcre2_error.c b/ProcessHacker/pcre/pcre2_error.c index d98cae99636a..4b3b3f1bc0d2 100644 --- a/ProcessHacker/pcre/pcre2_error.c +++ b/ProcessHacker/pcre/pcre2_error.c @@ -7,7 +7,7 @@ and semantics are as close as possible to those of the Perl 5 language. Written by Philip Hazel Original API code Copyright (c) 1997-2012 University of Cambridge - New API code Copyright (c) 2016-2017 University of Cambridge + New API code Copyright (c) 2016-2018 University of Cambridge ----------------------------------------------------------------------------- Redistribution and use in source and binary forms, with or without @@ -107,7 +107,7 @@ static const unsigned char compile_error_texts[] = /* 35 */ "lookbehind is too complicated\0" "\\C is not allowed in a lookbehind assertion in UTF-" XSTRING(PCRE2_CODE_UNIT_WIDTH) " mode\0" - "PCRE does not support \\L, \\l, \\N{name}, \\U, or \\u\0" + "PCRE2 does not support \\F, \\L, \\l, \\N{name}, \\U, or \\u\0" "number after (?C is greater than 255\0" "closing parenthesis for (?C expected\0" /* 40 */ @@ -133,7 +133,8 @@ static const unsigned char compile_error_texts[] = "internal error: unknown newline setting\0" "\\g is not followed by a braced, angle-bracketed, or quoted name/number or by a plain number\0" "(?R (recursive pattern call) must be followed by a closing parenthesis\0" - "an argument is not allowed for (*ACCEPT), (*FAIL), or (*COMMIT)\0" + /* "an argument is not allowed for (*ACCEPT), (*FAIL), or (*COMMIT)\0" */ + "obsolete error (should not occur)\0" /* Was the above */ /* 60 */ "(*VERB) not recognized or malformed\0" "group number is too big\0" @@ -160,7 +161,7 @@ static const unsigned char compile_error_texts[] = "using UCP is disabled by the application\0" "name is too long in (*MARK), (*PRUNE), (*SKIP), or (*THEN)\0" "character code point value in \\u.... sequence is too large\0" - "digits missing in \\x{} or \\o{}\0" + "digits missing in \\x{} or \\o{} or \\N{U+}\0" "syntax error or number too big in (?(VERSION condition\0" /* 80 */ "internal error: unknown opcode in auto_possessify()\0" @@ -178,6 +179,8 @@ static const unsigned char compile_error_texts[] = "internal error: bad code value in parsed_skip()\0" "PCRE2_EXTRA_ALLOW_SURROGATE_ESCAPES is not allowed in UTF-16 mode\0" "invalid option bits with PCRE2_LITERAL\0" + "\\N{U+dddd} is supported only in Unicode (UTF) mode\0" + "invalid hyphen in option setting\0" ; /* Match-time and UTF error texts are in the same format. */ @@ -255,11 +258,13 @@ static const unsigned char match_error_texts[] = "expected closing curly bracket in replacement string\0" "bad substitution in replacement string\0" /* 60 */ - "match with end before start is not supported\0" + "match with end before start or start moved backwards is not supported\0" "too many replacements (more than INT_MAX)\0" "bad serialized data\0" "heap limit exceeded\0" "invalid syntax\0" + /* 65 */ + "internal error - duplicate substitution match\0" ; diff --git a/ProcessHacker/pcre/pcre2_extuni.c b/ProcessHacker/pcre/pcre2_extuni.c index 11a0bfbdd679..237211abf7f9 100644 --- a/ProcessHacker/pcre/pcre2_extuni.c +++ b/ProcessHacker/pcre/pcre2_extuni.c @@ -129,11 +129,11 @@ while (eptr < end_subject) if ((ricount & 1) != 0) break; /* Grapheme break required */ } - /* If Extend follows E_Base[_GAZ] do not update lgb; this allows - any number of Extend before a following E_Modifier. */ + /* If Extend or ZWJ follows Extended_Pictographic, do not update lgb; this + allows any number of them before a following Extended_Pictographic. */ - if (rgb != ucp_gbExtend || - (lgb != ucp_gbE_Base && lgb != ucp_gbE_Base_GAZ)) + if ((rgb != ucp_gbExtend && rgb != ucp_gbZWJ) || + lgb != ucp_gbExtended_Pictographic) lgb = rgb; eptr += len; diff --git a/ProcessHacker/pcre/pcre2_find_bracket.c b/ProcessHacker/pcre/pcre2_find_bracket.c index 357385a11ccc..70baa1394f57 100644 --- a/ProcessHacker/pcre/pcre2_find_bracket.c +++ b/ProcessHacker/pcre/pcre2_find_bracket.c @@ -7,7 +7,7 @@ and semantics are as close as possible to those of the Perl 5 language. Written by Philip Hazel Original API code Copyright (c) 1997-2012 University of Cambridge - New API code Copyright (c) 2016 University of Cambridge + New API code Copyright (c) 2016-2018 University of Cambridge ----------------------------------------------------------------------------- Redistribution and use in source and binary forms, with or without @@ -131,6 +131,7 @@ for (;;) break; case OP_MARK: + case OP_COMMIT_ARG: case OP_PRUNE_ARG: case OP_SKIP_ARG: case OP_THEN_ARG: diff --git a/ProcessHacker/pcre/pcre2_fuzzsupport.c b/ProcessHacker/pcre/pcre2_fuzzsupport.c new file mode 100644 index 000000000000..48781ffc0996 --- /dev/null +++ b/ProcessHacker/pcre/pcre2_fuzzsupport.c @@ -0,0 +1,365 @@ +/*************************************************************************** +Fuzzer driver for PCRE2. Given an arbitrary string of bytes and a length, it +tries to compile and match it, deriving options from the string itself. If +STANDALONE is defined, a main program that calls the driver with the contents +of specified files is compiled, and commentary on what is happening is output. +If an argument starts with '=' the rest of it it is taken as a literal string +rather than a file name. This allows easy testing of short strings. + +Written by Philip Hazel, October 2016 +***************************************************************************/ + +#include +#include +#include +#include + +#define PCRE2_CODE_UNIT_WIDTH 8 +#include "pcre2.h" + +#define MAX_MATCH_SIZE 1000 + +#define DFA_WORKSPACE_COUNT 100 + +#define ALLOWED_COMPILE_OPTIONS \ + (PCRE2_ANCHORED|PCRE2_ALLOW_EMPTY_CLASS|PCRE2_ALT_BSUX|PCRE2_ALT_CIRCUMFLEX| \ + PCRE2_ALT_VERBNAMES|PCRE2_AUTO_CALLOUT|PCRE2_CASELESS|PCRE2_DOLLAR_ENDONLY| \ + PCRE2_DOTALL|PCRE2_DUPNAMES|PCRE2_ENDANCHORED|PCRE2_EXTENDED|PCRE2_FIRSTLINE| \ + PCRE2_MATCH_UNSET_BACKREF|PCRE2_MULTILINE|PCRE2_NEVER_BACKSLASH_C| \ + PCRE2_NO_AUTO_CAPTURE| \ + PCRE2_NO_AUTO_POSSESS|PCRE2_NO_DOTSTAR_ANCHOR|PCRE2_NO_START_OPTIMIZE| \ + PCRE2_UCP|PCRE2_UNGREEDY|PCRE2_USE_OFFSET_LIMIT| \ + PCRE2_UTF) + +#define ALLOWED_MATCH_OPTIONS \ + (PCRE2_ANCHORED|PCRE2_ENDANCHORED|PCRE2_NOTBOL|PCRE2_NOTEOL|PCRE2_NOTEMPTY| \ + PCRE2_NOTEMPTY_ATSTART|PCRE2_PARTIAL_HARD| \ + PCRE2_PARTIAL_SOFT|PCRE2_NO_JIT) + +/* This is the callout function. Its only purpose is to halt matching if there +are more than 100 callouts, as one way of stopping too much time being spent on +fruitless matches. The callout data is a pointer to the counter. */ + +static int callout_function(pcre2_callout_block *cb, void *callout_data) +{ +(void)cb; /* Avoid unused parameter warning */ +*((uint32_t *)callout_data) += 1; +return (*((uint32_t *)callout_data) > 100)? PCRE2_ERROR_CALLOUT : 0; +} + +/* Putting in this apparently unnecessary prototype prevents gcc from giving a +"no previous prototype" warning when compiling at high warning level. */ + +int LLVMFuzzerTestOneInput(const unsigned char *, size_t); + +/* Here's the driving function. */ + +int LLVMFuzzerTestOneInput(const unsigned char *data, size_t size) +{ +uint32_t compile_options; +uint32_t match_options; +pcre2_match_data *match_data = NULL; +pcre2_match_context *match_context = NULL; +size_t match_size; +int dfa_workspace[DFA_WORKSPACE_COUNT]; +int r1, r2; +int i; + +if (size < 1) return 0; + +/* Limiting the length of the subject for matching stops fruitless searches +in large trees taking too much time. */ + +match_size = (size > MAX_MATCH_SIZE)? MAX_MATCH_SIZE : size; + +/* Figure out some options to use. Initialize the random number to ensure +repeatability. Ensure that we get a 32-bit unsigned random number for testing +options. (RAND_MAX is required to be at least 32767, but is commonly +2147483647, which excludes the top bit.) */ + +srand((unsigned int)(data[size/2])); +r1 = rand(); +r2 = rand(); + +/* Ensure that all undefined option bits are zero (waste of time trying them) +and also that PCRE2_NO_UTF_CHECK is unset, as there is no guarantee that the +input is UTF-8. Also unset PCRE2_NEVER_UTF and PCRE2_NEVER_UCP as there is no +reason to disallow UTF and UCP. Force PCRE2_NEVER_BACKSLASH_C to be set because +\C in random patterns is highly likely to cause a crash. */ + +compile_options = + ((((uint32_t)r1 << 16) | ((uint32_t)r2 & 0xffff)) & ALLOWED_COMPILE_OPTIONS) | + PCRE2_NEVER_BACKSLASH_C; + +match_options = + ((((uint32_t)r1 << 16) | ((uint32_t)r2 & 0xffff)) & ALLOWED_MATCH_OPTIONS); + +/* Discard partial matching if PCRE2_ENDANCHORED is set, because they are not +allowed together and just give an immediate error return. */ + +if (((compile_options|match_options) & PCRE2_ENDANCHORED) != 0) + match_options &= ~(PCRE2_PARTIAL_HARD|PCRE2_PARTIAL_SOFT); + +/* Do the compile with and without the options, and after a successful compile, +likewise do the match with and without the options. */ + +for (i = 0; i < 2; i++) + { + uint32_t callout_count; + int errorcode; + PCRE2_SIZE erroroffset; + pcre2_code *code; + +#ifdef STANDALONE + printf("Compile options %.8x never_backslash_c", compile_options); + printf("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", + ((compile_options & PCRE2_ALT_BSUX) != 0)? ",alt_bsux" : "", + ((compile_options & PCRE2_ALT_CIRCUMFLEX) != 0)? ",alt_circumflex" : "", + ((compile_options & PCRE2_ALT_VERBNAMES) != 0)? ",alt_verbnames" : "", + ((compile_options & PCRE2_ALLOW_EMPTY_CLASS) != 0)? ",allow_empty_class" : "", + ((compile_options & PCRE2_ANCHORED) != 0)? ",anchored" : "", + ((compile_options & PCRE2_AUTO_CALLOUT) != 0)? ",auto_callout" : "", + ((compile_options & PCRE2_CASELESS) != 0)? ",caseless" : "", + ((compile_options & PCRE2_DOLLAR_ENDONLY) != 0)? ",dollar_endonly" : "", + ((compile_options & PCRE2_DOTALL) != 0)? ",dotall" : "", + ((compile_options & PCRE2_DUPNAMES) != 0)? ",dupnames" : "", + ((compile_options & PCRE2_ENDANCHORED) != 0)? ",endanchored" : "", + ((compile_options & PCRE2_EXTENDED) != 0)? ",extended" : "", + ((compile_options & PCRE2_FIRSTLINE) != 0)? ",firstline" : "", + ((compile_options & PCRE2_MATCH_UNSET_BACKREF) != 0)? ",match_unset_backref" : "", + ((compile_options & PCRE2_MULTILINE) != 0)? ",multiline" : "", + ((compile_options & PCRE2_NEVER_UCP) != 0)? ",never_ucp" : "", + ((compile_options & PCRE2_NEVER_UTF) != 0)? ",never_utf" : "", + ((compile_options & PCRE2_NO_AUTO_CAPTURE) != 0)? ",no_auto_capture" : "", + ((compile_options & PCRE2_NO_AUTO_POSSESS) != 0)? ",no_auto_possess" : "", + ((compile_options & PCRE2_NO_DOTSTAR_ANCHOR) != 0)? ",no_dotstar_anchor" : "", + ((compile_options & PCRE2_NO_UTF_CHECK) != 0)? ",no_utf_check" : "", + ((compile_options & PCRE2_NO_START_OPTIMIZE) != 0)? ",no_start_optimize" : "", + ((compile_options & PCRE2_UCP) != 0)? ",ucp" : "", + ((compile_options & PCRE2_UNGREEDY) != 0)? ",ungreedy" : "", + ((compile_options & PCRE2_USE_OFFSET_LIMIT) != 0)? ",use_offset_limit" : "", + ((compile_options & PCRE2_UTF) != 0)? ",utf" : ""); +#endif + + code = pcre2_compile((PCRE2_SPTR)data, (PCRE2_SIZE)size, compile_options, + &errorcode, &erroroffset, NULL); + + /* Compilation succeeded */ + + if (code != NULL) + { + int j; + uint32_t save_match_options = match_options; + + /* Create match data and context blocks only when we first need them. Set + low match and depth limits to avoid wasting too much searching large + pattern trees. Almost all matches are going to fail. */ + + if (match_data == NULL) + { + match_data = pcre2_match_data_create(32, NULL); + if (match_data == NULL) + { +#ifdef STANDALONE + printf("** Failed to create match data block\n"); +#endif + return 0; + } + } + + if (match_context == NULL) + { + match_context = pcre2_match_context_create(NULL); + if (match_context == NULL) + { +#ifdef STANDALONE + printf("** Failed to create match context block\n"); +#endif + return 0; + } + (void)pcre2_set_match_limit(match_context, 100); + (void)pcre2_set_depth_limit(match_context, 100); + (void)pcre2_set_callout(match_context, callout_function, &callout_count); + } + + /* Match twice, with and without options. */ + + for (j = 0; j < 2; j++) + { +#ifdef STANDALONE + printf("Match options %.8x", match_options); + printf("%s%s%s%s%s%s%s%s%s%s\n", + ((match_options & PCRE2_ANCHORED) != 0)? ",anchored" : "", + ((match_options & PCRE2_ENDANCHORED) != 0)? ",endanchored" : "", + ((match_options & PCRE2_NO_JIT) != 0)? ",no_jit" : "", + ((match_options & PCRE2_NO_UTF_CHECK) != 0)? ",no_utf_check" : "", + ((match_options & PCRE2_NOTBOL) != 0)? ",notbol" : "", + ((match_options & PCRE2_NOTEMPTY) != 0)? ",notempty" : "", + ((match_options & PCRE2_NOTEMPTY_ATSTART) != 0)? ",notempty_atstart" : "", + ((match_options & PCRE2_NOTEOL) != 0)? ",noteol" : "", + ((match_options & PCRE2_PARTIAL_HARD) != 0)? ",partial_hard" : "", + ((match_options & PCRE2_PARTIAL_SOFT) != 0)? ",partial_soft" : ""); +#endif + + callout_count = 0; + errorcode = pcre2_match(code, (PCRE2_SPTR)data, (PCRE2_SIZE)match_size, 0, + match_options, match_data, match_context); + +#ifdef STANDALONE + if (errorcode >= 0) printf("Match returned %d\n", errorcode); else + { + unsigned char buffer[256]; + pcre2_get_error_message(errorcode, buffer, 256); + printf("Match failed: error %d: %s\n", errorcode, buffer); + } +#endif + + match_options = 0; /* For second time */ + } + + /* Match with DFA twice, with and without options. */ + + match_options = save_match_options & ~PCRE2_NO_JIT; /* Not valid for DFA */ + + for (j = 0; j < 2; j++) + { +#ifdef STANDALONE + printf("DFA match options %.8x", match_options); + printf("%s%s%s%s%s%s%s%s%s\n", + ((match_options & PCRE2_ANCHORED) != 0)? ",anchored" : "", + ((match_options & PCRE2_ENDANCHORED) != 0)? ",endanchored" : "", + ((match_options & PCRE2_NO_UTF_CHECK) != 0)? ",no_utf_check" : "", + ((match_options & PCRE2_NOTBOL) != 0)? ",notbol" : "", + ((match_options & PCRE2_NOTEMPTY) != 0)? ",notempty" : "", + ((match_options & PCRE2_NOTEMPTY_ATSTART) != 0)? ",notempty_atstart" : "", + ((match_options & PCRE2_NOTEOL) != 0)? ",noteol" : "", + ((match_options & PCRE2_PARTIAL_HARD) != 0)? ",partial_hard" : "", + ((match_options & PCRE2_PARTIAL_SOFT) != 0)? ",partial_soft" : ""); +#endif + + callout_count = 0; + errorcode = pcre2_dfa_match(code, (PCRE2_SPTR)data, + (PCRE2_SIZE)match_size, 0, match_options, match_data, match_context, + dfa_workspace, DFA_WORKSPACE_COUNT); + +#ifdef STANDALONE + if (errorcode >= 0) printf("Match returned %d\n", errorcode); else + { + unsigned char buffer[256]; + pcre2_get_error_message(errorcode, buffer, 256); + printf("Match failed: error %d: %s\n", errorcode, buffer); + } +#endif + + match_options = 0; /* For second time */ + } + + match_options = save_match_options; /* Reset for the second compile */ + pcre2_code_free(code); + } + + /* Compilation failed */ + + else + { + unsigned char buffer[256]; + pcre2_get_error_message(errorcode, buffer, 256); +#ifdef STANDALONE + printf("Error %d at offset %lu: %s\n", errorcode, erroroffset, buffer); +#else + if (strstr((const char *)buffer, "internal error") != NULL) abort(); +#endif + } + + compile_options = PCRE2_NEVER_BACKSLASH_C; /* For second time */ + } + +if (match_data != NULL) pcre2_match_data_free(match_data); +if (match_context != NULL) pcre2_match_context_free(match_context); + +return 0; +} + + +/* Optional main program. */ + +#ifdef STANDALONE +int main(int argc, char **argv) +{ +int i; + +if (argc < 2) + { + printf("** No arguments given\n"); + return 0; + } + +for (i = 1; i < argc; i++) + { + size_t filelen; + size_t readsize; + unsigned char *buffer; + FILE *f; + + /* Handle a literal string. Copy to an exact size buffer so that checks for + overrunning work. */ + + if (argv[i][0] == '=') + { + readsize = strlen(argv[i]) - 1; + printf("------ ------\n"); + printf("Length = %lu\n", readsize); + printf("%.*s\n", (int)readsize, argv[i]+1); + buffer = (unsigned char *)malloc(readsize); + if (buffer == NULL) + printf("** Failed to allocate %lu bytes of memory\n", readsize); + else + { + memcpy(buffer, argv[i]+1, readsize); + LLVMFuzzerTestOneInput(buffer, readsize); + free(buffer); + } + continue; + } + + /* Handle a string given in a file */ + + f = fopen(argv[i], "rb"); + if (f == NULL) + { + printf("** Failed to open %s: %s\n", argv[i], strerror(errno)); + continue; + } + + printf("------ %s ------\n", argv[i]); + + fseek(f, 0, SEEK_END); + filelen = ftell(f); + fseek(f, 0, SEEK_SET); + + buffer = (unsigned char *)malloc(filelen); + if (buffer == NULL) + { + printf("** Failed to allocate %lu bytes of memory\n", filelen); + fclose(f); + continue; + } + + readsize = fread(buffer, 1, filelen, f); + fclose(f); + + if (readsize != filelen) + printf("** File size is %lu but fread() returned %lu\n", filelen, readsize); + else + { + printf("Length = %lu\n", filelen); + LLVMFuzzerTestOneInput(buffer, filelen); + } + free(buffer); + } + +return 0; +} +#endif /* STANDALONE */ + +/* End */ diff --git a/ProcessHacker/pcre/pcre2_internal.h b/ProcessHacker/pcre/pcre2_internal.h index 3db9d604f47d..8750f2f17468 100644 --- a/ProcessHacker/pcre/pcre2_internal.h +++ b/ProcessHacker/pcre/pcre2_internal.h @@ -7,7 +7,7 @@ and semantics are as close as possible to those of the Perl 5 language. Written by Philip Hazel Original API code Copyright (c) 1997-2012 University of Cambridge - New API code Copyright (c) 2016-2017 University of Cambridge + New API code Copyright (c) 2016-2018 University of Cambridge ----------------------------------------------------------------------------- Redistribution and use in source and binary forms, with or without @@ -165,6 +165,16 @@ by "configure". */ #define INT64_OR_DOUBLE double #endif +/* External (in the C sense) functions and tables that are private to the +libraries are always referenced using the PRIV macro. This makes it possible +for pcre2test.c to include some of the source files from the libraries using a +different PRIV definition to avoid name clashes. It also makes it clear in the +code that a non-static object is being referenced. */ + +#ifndef PRIV +#define PRIV(name) _pcre2_##name +#endif + /* When compiling for use with the Virtual Pascal compiler, these functions need to have their names changed. PCRE2 must be compiled with the -DVPCOMPAT option on the command line. */ @@ -178,50 +188,15 @@ option on the command line. */ #define memset(s,c,n) _memset(s,c,n) #else /* VPCOMPAT */ -/* To cope with SunOS4 and other systems that lack memmove() but have bcopy(), -define a macro for memmove() if HAVE_MEMMOVE is false, provided that HAVE_BCOPY -is set. Otherwise, include an emulating function for those systems that have -neither (there some non-Unix environments where this is the case). */ +/* Otherwise, to cope with SunOS4 and other systems that lack memmove(), define +a macro that calls an emulating function. */ #ifndef HAVE_MEMMOVE -#undef memmove /* some systems may have a macro */ -#ifdef HAVE_BCOPY -#define memmove(a, b, c) bcopy(b, a, c) -#else /* HAVE_BCOPY */ -static void * -pcre2_memmove(void *d, const void *s, size_t n) -{ -size_t i; -unsigned char *dest = (unsigned char *)d; -const unsigned char *src = (const unsigned char *)s; -if (dest > src) - { - dest += n; - src += n; - for (i = 0; i < n; ++i) *(--dest) = *(--src); - return (void *)dest; - } -else - { - for (i = 0; i < n; ++i) *dest++ = *src++; - return (void *)(dest - n); - } -} -#define memmove(a, b, c) pcre2_memmove(a, b, c) -#endif /* not HAVE_BCOPY */ +#undef memmove /* Some systems may have a macro */ +#define memmove(a, b, c) PRIV(memmove)(a, b, c) #endif /* not HAVE_MEMMOVE */ #endif /* not VPCOMPAT */ -/* External (in the C sense) functions and tables that are private to the -libraries are always referenced using the PRIV macro. This makes it possible -for pcre2test.c to include some of the source files from the libraries using a -different PRIV definition to avoid name clashes. It also makes it clear in the -code that a non-static object is being referenced. */ - -#ifndef PRIV -#define PRIV(name) _pcre2_##name -#endif - /* This is an unsigned int value that no UTF character can ever have, as Unicode doesn't go beyond 0x0010ffff. */ @@ -247,12 +222,17 @@ not rely on this. */ pcre2_match() is allocated on the system stack, of this size (bytes). The size must be a multiple of sizeof(PCRE2_SPTR) in all environments, so making it a multiple of 8 is best. Typical frame sizes are a few hundred bytes (it depends -on the number of capturing parentheses) so 20K handles quite a few frames. A +on the number of capturing parentheses) so 20KiB handles quite a few frames. A larger vector on the heap is obtained for patterns that need more frames. The maximum size of this can be limited. */ #define START_FRAMES_SIZE 20480 +/* Similarly, for DFA matching, an initial internal workspace vector is +allocated on the stack. */ + +#define DFA_START_RWS_SIZE 30720 + /* Define the default BSR convention. */ #ifdef BSR_ANYCRLF @@ -585,14 +565,15 @@ these tables. */ #define cbit_cntrl 288 /* [:cntrl:] */ #define cbit_length 320 /* Length of the cbits table */ -/* Bit definitions for entries in the ctypes table. */ +/* Bit definitions for entries in the ctypes table. Do not change these values +without checking pcre2_jit_compile.c, which has an assertion to ensure that +ctype_word has the value 16. */ #define ctype_space 0x01 #define ctype_letter 0x02 #define ctype_digit 0x04 -#define ctype_xdigit 0x08 +#define ctype_xdigit 0x08 /* not actually used any more */ #define ctype_word 0x10 /* alphanumeric or '_' */ -#define ctype_meta 0x80 /* regexp meta char or zero (end pattern) */ /* Offsets of the various tables from the base tables pointer, and total length of the tables. */ @@ -1267,36 +1248,6 @@ contain characters with values greater than 255. */ #define XCL_PROP 3 /* Unicode property (2-byte property code follows) */ #define XCL_NOTPROP 4 /* Unicode inverted property (ditto) */ -/* Escape items that are just an encoding of a particular data value. These -appear in the escapes[] table in pcre2_compile.c as positive numbers. */ - -#ifndef ESC_a -#define ESC_a CHAR_BEL -#endif - -#ifndef ESC_e -#define ESC_e CHAR_ESC -#endif - -#ifndef ESC_f -#define ESC_f CHAR_FF -#endif - -#ifndef ESC_n -#define ESC_n CHAR_LF -#endif - -#ifndef ESC_r -#define ESC_r CHAR_CR -#endif - -/* We can't officially use ESC_t because it is a POSIX reserved identifier -(presumably because of all the others like size_t). */ - -#ifndef ESC_tee -#define ESC_tee CHAR_HT -#endif - /* These are escaped items that aren't just an encoding of a particular data value such as \n. They must have non-zero values, as check_escape() returns 0 for a data character. In the escapes[] table in pcre2_compile.c their values @@ -1578,23 +1529,26 @@ enum { OP_THEN, /* 155 */ OP_THEN_ARG, /* 156 same, but with argument */ OP_COMMIT, /* 157 */ + OP_COMMIT_ARG, /* 158 same, but with argument */ - /* These are forced failure and success verbs */ + /* These are forced failure and success verbs. FAIL and ACCEPT do accept an + argument, but these cases can be compiled as, for example, (*MARK:X)(*FAIL) + without the need for a special opcode. */ - OP_FAIL, /* 158 */ - OP_ACCEPT, /* 159 */ - OP_ASSERT_ACCEPT, /* 160 Used inside assertions */ - OP_CLOSE, /* 161 Used before OP_ACCEPT to close open captures */ + OP_FAIL, /* 159 */ + OP_ACCEPT, /* 160 */ + OP_ASSERT_ACCEPT, /* 161 Used inside assertions */ + OP_CLOSE, /* 162 Used before OP_ACCEPT to close open captures */ /* This is used to skip a subpattern with a {0} quantifier */ - OP_SKIPZERO, /* 162 */ + OP_SKIPZERO, /* 163 */ /* This is used to identify a DEFINE group during compilation so that it can be checked for having only one branch. It is changed to OP_FALSE before compilation finishes. */ - OP_DEFINE, /* 163 */ + OP_DEFINE, /* 164 */ /* This is not an opcode, but is used to check that tables indexed by opcode are the correct length, in order to catch updating errors - there have been @@ -1650,7 +1604,7 @@ some cases doesn't actually use these names at all). */ "Cond false", "Cond true", \ "Brazero", "Braminzero", "Braposzero", \ "*MARK", "*PRUNE", "*PRUNE", "*SKIP", "*SKIP", \ - "*THEN", "*THEN", "*COMMIT", "*FAIL", \ + "*THEN", "*THEN", "*COMMIT", "*COMMIT", "*FAIL", \ "*ACCEPT", "*ASSERT_ACCEPT", \ "Close", "Skip zero", "Define" @@ -1742,7 +1696,8 @@ in UTF-8 mode. The code that uses this table must know about such things. */ 3, 1, 3, /* MARK, PRUNE, PRUNE_ARG */ \ 1, 3, /* SKIP, SKIP_ARG */ \ 1, 3, /* THEN, THEN_ARG */ \ - 1, 1, 1, 1, /* COMMIT, FAIL, ACCEPT, ASSERT_ACCEPT */ \ + 1, 3, /* COMMIT, COMMIT_ARG */ \ + 1, 1, 1, /* FAIL, ACCEPT, ASSERT_ACCEPT */ \ 1+IMM2_SIZE, 1, /* CLOSE, SKIPZERO */ \ 1 /* DEFINE */ @@ -1896,7 +1851,7 @@ extern const ucd_record PRIV(ucd_records)[]; #if PCRE2_CODE_UNIT_WIDTH == 32 extern const ucd_record PRIV(dummy_ucd_record)[]; #endif -extern const uint8_t PRIV(ucd_stage1)[]; +extern const uint16_t PRIV(ucd_stage1)[]; extern const uint16_t PRIV(ucd_stage2)[]; extern const uint32_t PRIV(ucp_gbtable)[]; extern const uint32_t PRIV(ucp_gentype)[]; @@ -1976,6 +1931,14 @@ extern int _pcre2_valid_utf(PCRE2_SPTR, PCRE2_SIZE, PCRE2_SIZE *); extern BOOL _pcre2_was_newline(PCRE2_SPTR, uint32_t, PCRE2_SPTR, uint32_t *, BOOL); extern BOOL _pcre2_xclass(uint32_t, PCRE2_SPTR, BOOL); + +/* This function is needed only when memmove() is not available. */ + +#if !defined(VPCOMPAT) && !defined(HAVE_MEMMOVE) +#define _pcre2_memmove PCRE2_SUFFIX(_pcre2_memmove) +extern void * _pcre2_memmove(void *, const void *, size_t); +#endif + #endif /* PCRE2_CODE_UNIT_WIDTH */ #endif /* PCRE2_INTERNAL_H_IDEMPOTENT_GUARD */ diff --git a/ProcessHacker/pcre/pcre2_intmodedep.h b/ProcessHacker/pcre/pcre2_intmodedep.h index c4c4c3adb9d1..62626d0a8a74 100644 --- a/ProcessHacker/pcre/pcre2_intmodedep.h +++ b/ProcessHacker/pcre/pcre2_intmodedep.h @@ -793,11 +793,23 @@ typedef struct heapframe { uint8_t return_id; /* Where to go on in internal "return" */ uint8_t op; /* Processing opcode */ + /* At this point, the structure is 16-bit aligned. On most architectures + the alignment requirement for a pointer will ensure that the eptr field below + is 32-bit or 64-bit aligned. However, on m68k it is fine to have a pointer + that is 16-bit aligned. We must therefore ensure that what comes between here + and eptr is an odd multiple of 16 bits so as to get back into 32-bit + alignment. This happens naturally when PCRE2_UCHAR is 8 bits wide, but needs + fudges in the other cases. In the 32-bit case the padding comes first so that + the occu field itself is 32-bit aligned. Without the padding, this structure + is no longer a multiple of PCRE2_SIZE on m68k, and the check below fails. */ + #if PCRE2_CODE_UNIT_WIDTH == 8 PCRE2_UCHAR occu[6]; /* Used for other case code units */ #elif PCRE2_CODE_UNIT_WIDTH == 16 PCRE2_UCHAR occu[2]; /* Used for other case code units */ + uint8_t unused[2]; /* Ensure 32-bit alignment (see above) */ #else + uint8_t unused[2]; /* Ensure 32-bit alignment (see above) */ PCRE2_UCHAR occu[1]; /* Used for other case code units */ #endif @@ -818,6 +830,9 @@ typedef struct heapframe { PCRE2_SIZE ovector[131072]; /* Must be last in the structure */ } heapframe; +/* This typedef is a check that the size of the heapframe structure is a +multiple of PCRE2_SIZE. See various comments above. */ + typedef char check_heapframe_size[ ((sizeof(heapframe) % sizeof(PCRE2_SIZE)) == 0)? (+1):(-1)]; @@ -881,6 +896,8 @@ typedef struct dfa_match_block { PCRE2_SPTR last_used_ptr; /* Latest consulted character */ const uint8_t *tables; /* Character tables */ PCRE2_SIZE start_offset; /* The start offset value */ + PCRE2_SIZE heap_limit; /* As it says */ + PCRE2_SIZE heap_used; /* As it says */ uint32_t match_limit; /* As it says */ uint32_t match_limit_depth; /* As it says */ uint32_t match_call_count; /* Number of calls of internal function */ diff --git a/ProcessHacker/pcre/pcre2_jit_compile.c b/ProcessHacker/pcre/pcre2_jit_compile.c index 80ed1c4ca6a7..32e985b79385 100644 --- a/ProcessHacker/pcre/pcre2_jit_compile.c +++ b/ProcessHacker/pcre/pcre2_jit_compile.c @@ -7,7 +7,7 @@ and semantics are as close as possible to those of the Perl 5 language. Written by Philip Hazel Original API code Copyright (c) 1997-2012 University of Cambridge - New API code Copyright (c) 2016-2017 University of Cambridge + New API code Copyright (c) 2016-2018 University of Cambridge ----------------------------------------------------------------------------- Redistribution and use in source and binary forms, with or without @@ -839,6 +839,7 @@ switch(*cc) #endif case OP_MARK: + case OP_COMMIT_ARG: case OP_PRUNE_ARG: case OP_SKIP_ARG: case OP_THEN_ARG: @@ -939,6 +940,7 @@ while (cc < ccend) common->control_head_ptr = 1; /* Fall through. */ + case OP_COMMIT_ARG: case OP_PRUNE_ARG: case OP_MARK: if (common->mark_ptr == 0) @@ -1553,6 +1555,7 @@ while (cc < ccend) break; case OP_MARK: + case OP_COMMIT_ARG: case OP_PRUNE_ARG: case OP_THEN_ARG: SLJIT_ASSERT(common->mark_ptr != 0); @@ -1733,6 +1736,7 @@ while (cc < ccend) break; case OP_MARK: + case OP_COMMIT_ARG: case OP_PRUNE_ARG: case OP_THEN_ARG: SLJIT_ASSERT(common->mark_ptr != 0); @@ -2041,6 +2045,7 @@ while (cc < ccend) break; case OP_MARK: + case OP_COMMIT_ARG: case OP_PRUNE_ARG: case OP_THEN_ARG: SLJIT_ASSERT(common->mark_ptr != 0); @@ -2428,6 +2433,7 @@ while (cc < ccend) break; case OP_MARK: + case OP_COMMIT_ARG: case OP_PRUNE_ARG: case OP_THEN_ARG: SLJIT_ASSERT(common->mark_ptr != 0); @@ -3666,7 +3672,8 @@ if (!common->utf) #endif OP2(SLJIT_LSHR, TMP2, 0, TMP1, 0, SLJIT_IMM, UCD_BLOCK_SHIFT); -OP1(SLJIT_MOV_U8, TMP2, 0, SLJIT_MEM1(TMP2), (sljit_sw)PRIV(ucd_stage1)); +OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, 1); +OP1(SLJIT_MOV_U16, TMP2, 0, SLJIT_MEM1(TMP2), (sljit_sw)PRIV(ucd_stage1)); OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, UCD_BLOCK_MASK); OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, UCD_BLOCK_SHIFT); OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, TMP2, 0); @@ -5894,6 +5901,8 @@ for (i = 0; i < 32; i++) } } +if (len == 0) return FALSE; /* Should never occur, but stops analyzers complaining. */ + i = 0; j = 0; @@ -6627,7 +6636,8 @@ if (needstype || needsscript) #endif OP2(SLJIT_LSHR, TMP2, 0, TMP1, 0, SLJIT_IMM, UCD_BLOCK_SHIFT); - OP1(SLJIT_MOV_U8, TMP2, 0, SLJIT_MEM1(TMP2), (sljit_sw)PRIV(ucd_stage1)); + OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, 1); + OP1(SLJIT_MOV_U16, TMP2, 0, SLJIT_MEM1(TMP2), (sljit_sw)PRIV(ucd_stage1)); OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, UCD_BLOCK_MASK); OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, UCD_BLOCK_SHIFT); OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, TMP2, 0); @@ -7254,10 +7264,11 @@ while (cc < end_subject) if ((ricount & 1) != 0) break; /* Grapheme break required */ } - /* If Extend follows E_Base[_GAZ] do not update lgb; this allows - any number of Extend before a following E_Modifier. */ + /* If Extend or ZWJ follows Extended_Pictographic, do not update lgb; this + allows any number of them before a following Extended_Pictographic. */ - if (rgb != ucp_gbExtend || (lgb != ucp_gbE_Base && lgb != ucp_gbE_Base_GAZ)) + if ((rgb != ucp_gbExtend && rgb != ucp_gbZWJ) || + lgb != ucp_gbExtended_Pictographic) lgb = rgb; prevcc = cc; @@ -7309,10 +7320,11 @@ while (cc < end_subject) if ((ricount & 1) != 0) break; /* Grapheme break required */ } - /* If Extend follows E_Base[_GAZ] do not update lgb; this allows - any number of Extend before a following E_Modifier. */ + /* If Extend or ZWJ follows Extended_Pictographic, do not update lgb; this + allows any number of them before a following Extended_Pictographic. */ - if (rgb != ucp_gbExtend || (lgb != ucp_gbE_Base && lgb != ucp_gbE_Base_GAZ)) + if ((rgb != ucp_gbExtend && rgb != ucp_gbZWJ) || + lgb != ucp_gbExtended_Pictographic) lgb = rgb; cc++; @@ -10346,7 +10358,8 @@ backtrack_common *backtrack; PCRE2_UCHAR opcode = *cc; PCRE2_SPTR ccend = cc + 1; -if (opcode == OP_PRUNE_ARG || opcode == OP_SKIP_ARG || opcode == OP_THEN_ARG) +if (opcode == OP_COMMIT_ARG || opcode == OP_PRUNE_ARG || + opcode == OP_SKIP_ARG || opcode == OP_THEN_ARG) ccend += 2 + cc[1]; PUSH_BACKTRACK(sizeof(backtrack_common), cc, NULL); @@ -10358,7 +10371,7 @@ if (opcode == OP_SKIP) return ccend; } -if (opcode == OP_PRUNE_ARG || opcode == OP_THEN_ARG) +if (opcode == OP_COMMIT_ARG || opcode == OP_PRUNE_ARG || opcode == OP_THEN_ARG) { OP1(SLJIT_MOV, TMP1, 0, ARGUMENTS, 0); OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, (sljit_sw)(cc + 2)); @@ -10677,6 +10690,7 @@ while (cc < ccend) case OP_THEN: case OP_THEN_ARG: case OP_COMMIT: + case OP_COMMIT_ARG: cc = compile_control_verb_matchingpath(common, cc, parent); break; @@ -11751,6 +11765,7 @@ while (current) break; case OP_COMMIT: + case OP_COMMIT_ARG: if (!common->local_quit_available) OP1(SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_IMM, PCRE2_ERROR_NOMATCH); if (common->quit_label == NULL) diff --git a/ProcessHacker/pcre/pcre2_jit_test.c b/ProcessHacker/pcre/pcre2_jit_test.c index d9916b7ca065..a28e9a0b183e 100644 --- a/ProcessHacker/pcre/pcre2_jit_test.c +++ b/ProcessHacker/pcre/pcre2_jit_test.c @@ -1331,8 +1331,9 @@ static int regression_tests(void) ovector8_2[i] = -2; } if (re8) { + (void)pcre2_set_match_limit_8(mcontext8, 10000000); return_value8[1] = pcre2_match_8(re8, (PCRE2_SPTR8)current->input, strlen(current->input), - current->start_offset & OFFSET_MASK, current->match_options, mdata8_2, NULL); + current->start_offset & OFFSET_MASK, current->match_options, mdata8_2, mcontext8); if (pcre2_jit_compile_8(re8, jit_compile_mode)) { printf("\n8 bit: JIT compiler does not support \"%s\"\n", current->pattern); @@ -1375,8 +1376,9 @@ static int regression_tests(void) else length16 = copy_char8_to_char16((PCRE2_SPTR8)current->input, regtest_buf16, REGTEST_MAX_LENGTH16); + (void)pcre2_set_match_limit_16(mcontext16, 10000000); return_value16[1] = pcre2_match_16(re16, regtest_buf16, length16, - current->start_offset & OFFSET_MASK, current->match_options, mdata16_2, NULL); + current->start_offset & OFFSET_MASK, current->match_options, mdata16_2, mcontext16); if (pcre2_jit_compile_16(re16, jit_compile_mode)) { printf("\n16 bit: JIT compiler does not support \"%s\"\n", current->pattern); @@ -1419,8 +1421,9 @@ static int regression_tests(void) else length32 = copy_char8_to_char32((PCRE2_SPTR8)current->input, regtest_buf32, REGTEST_MAX_LENGTH32); + (void)pcre2_set_match_limit_32(mcontext32, 10000000); return_value32[1] = pcre2_match_32(re32, regtest_buf32, length32, - current->start_offset & OFFSET_MASK, current->match_options, mdata32_2, NULL); + current->start_offset & OFFSET_MASK, current->match_options, mdata32_2, mcontext32); if (pcre2_jit_compile_32(re32, jit_compile_mode)) { printf("\n32 bit: JIT compiler does not support \"%s\"\n", current->pattern); diff --git a/ProcessHacker/pcre/pcre2_maketables.c b/ProcessHacker/pcre/pcre2_maketables.c index 467e4c533c84..342248340823 100644 --- a/ProcessHacker/pcre/pcre2_maketables.c +++ b/ProcessHacker/pcre/pcre2_maketables.c @@ -7,7 +7,7 @@ and semantics are as close as possible to those of the Perl 5 language. Written by Philip Hazel Original API code Copyright (c) 1997-2012 University of Cambridge - New API code Copyright (c) 2016 University of Cambridge + New API code Copyright (c) 2016-2018 University of Cambridge ----------------------------------------------------------------------------- Redistribution and use in source and binary forms, with or without @@ -142,13 +142,6 @@ for (i = 0; i < 256; i++) if (isdigit(i)) x += ctype_digit; if (isxdigit(i)) x += ctype_xdigit; if (isalnum(i) || i == '_') x += ctype_word; - - /* Note: strchr includes the terminating zero in the characters it considers. - In this instance, that is ok because we want binary zero to be flagged as a - meta-character, which in this sense is any character that terminates a run - of data characters. */ - - if (strchr("\\*+?{^.$|()[", i) != 0) x += ctype_meta; *p++ = x; } diff --git a/ProcessHacker/pcre/pcre2_match.c b/ProcessHacker/pcre/pcre2_match.c index 79cc93f91800..8741e1432d61 100644 --- a/ProcessHacker/pcre/pcre2_match.c +++ b/ProcessHacker/pcre/pcre2_match.c @@ -43,11 +43,11 @@ POSSIBILITY OF SUCH DAMAGE. #include "config.h" #endif -/* These defines enables debugging code */ +/* These defines enable debugging code */ -//#define DEBUG_FRAMES_DISPLAY -//#define DEBUG_SHOW_OPS -//#define DEBUG_SHOW_RMATCH +/* #define DEBUG_FRAMES_DISPLAY */ +/* #define DEBUG_SHOW_OPS */ +/* #define DEBUG_SHOW_RMATCH */ #ifdef DEBUG_FRAME_DISPLAY #include @@ -149,7 +149,7 @@ changed, the code at RETURN_SWITCH below must be updated in sync. */ enum { RM1=1, RM2, RM3, RM4, RM5, RM6, RM7, RM8, RM9, RM10, RM11, RM12, RM13, RM14, RM15, RM16, RM17, RM18, RM19, RM20, RM21, RM22, RM23, RM24, RM25, RM26, RM27, RM28, RM29, RM30, - RM31, RM32, RM33, RM34, RM35 }; + RM31, RM32, RM33, RM34, RM35, RM36 }; #ifdef SUPPORT_WIDE_CHARS enum { RM100=100, RM101 }; @@ -770,7 +770,7 @@ fprintf(stderr, "++ op=%d\n", *Fecode); /* ===================================================================== */ /* Real or forced end of the pattern, assertion, or recursion. In an assertion ACCEPT, update the last used pointer and remember the current - frame so that the captures can be fished out of it. */ + frame so that the captures and mark can be fished out of it. */ case OP_ASSERT_ACCEPT: if (Feptr > mb->last_used_ptr) mb->last_used_ptr = Feptr; @@ -1776,7 +1776,7 @@ fprintf(stderr, "++ op=%d\n", *Fecode); /* ===================================================================== */ - /* Match a bit-mapped character class, possibly repeatedly. These op codes + /* Match a bit-mapped character class, possibly repeatedly. These opcodes are used when all the characters in the class have values in the range 0-255, and either the matching is caseful, or the characters are in the range 0-127 when UTF processing is enabled. The only difference between @@ -1962,11 +1962,15 @@ fprintf(stderr, "++ op=%d\n", *Fecode); if (reptype == REPTYPE_POS) continue; /* No backtracking */ + /* After \C in UTF mode, Lstart_eptr might be in the middle of a + Unicode character. Use <= Lstart_eptr to ensure backtracking doesn't + go too far. */ + for (;;) { RMATCH(Fecode, RM201); if (rrc != MATCH_NOMATCH) RRETURN(rrc); - if (Feptr-- == Lstart_eptr) break; /* Tried at original position */ + if (Feptr-- <= Lstart_eptr) break; /* Tried at original position */ BACKCHAR(Feptr); } } @@ -2126,11 +2130,15 @@ fprintf(stderr, "++ op=%d\n", *Fecode); if (reptype == REPTYPE_POS) continue; /* No backtracking */ + /* After \C in UTF mode, Lstart_eptr might be in the middle of a + Unicode character. Use <= Lstart_eptr to ensure backtracking doesn't + go too far. */ + for(;;) { RMATCH(Fecode, RM101); if (rrc != MATCH_NOMATCH) RRETURN(rrc); - if (Feptr-- == Lstart_eptr) break; /* Tried at original position */ + if (Feptr-- <= Lstart_eptr) break; /* Tried at original position */ #ifdef SUPPORT_UNICODE if (utf) BACKCHAR(Feptr); #endif @@ -2456,7 +2464,7 @@ fprintf(stderr, "++ op=%d\n", *Fecode); /* ===================================================================== */ /* Match a single character type repeatedly. Note that the property type - does not need to be in a stack frame as it not used within an RMATCH() + does not need to be in a stack frame as it is not used within an RMATCH() loop. */ #define Lstart_eptr F->temp_sptr[0] @@ -4002,8 +4010,8 @@ fprintf(stderr, "++ op=%d\n", *Fecode); if (reptype == REPTYPE_POS) continue; /* No backtracking */ /* After \C in UTF mode, Lstart_eptr might be in the middle of a - Unicode character. Use <= pp to ensure backtracking doesn't go too far. - */ + Unicode character. Use <= Lstart_eptr to ensure backtracking doesn't + go too far. */ for(;;) { @@ -4135,7 +4143,7 @@ fprintf(stderr, "++ op=%d\n", *Fecode); } break; - /* The "byte" (i.e. "code unit") case is the same as non-UTF */ + /* The "byte" (i.e. "code unit") case is the same as non-UTF */ case OP_ANYBYTE: fc = Lmax - Lmin; @@ -5111,7 +5119,7 @@ fprintf(stderr, "++ op=%d\n", *Fecode); /* Positive assertions are like other groups except that PCRE doesn't allow the effect of (*THEN) to escape beyond an assertion; it is therefore treated as NOMATCH. (*ACCEPT) is treated as successful assertion, with its - captures retained. Any other return is an error. */ + captures and mark retained. Any other return is an error. */ #define Lframe_type F->temp_32[0] @@ -5128,6 +5136,7 @@ fprintf(stderr, "++ op=%d\n", *Fecode); (char *)assert_accept_frame + offsetof(heapframe, ovector), assert_accept_frame->offset_top * sizeof(PCRE2_SIZE)); Foffset_top = assert_accept_frame->offset_top; + Fmark = assert_accept_frame->mark; break; } if (rrc != MATCH_NOMATCH && rrc != MATCH_THEN) RRETURN(rrc); @@ -5416,7 +5425,7 @@ fprintf(stderr, "++ op=%d\n", *Fecode); Feptr -= number; } - /* Save the earliest consulted character, then skip to next op code */ + /* Save the earliest consulted character, then skip to next opcode */ if (Feptr < mb->start_used_ptr) mb->start_used_ptr = Feptr; Fecode += 1 + LINK_SIZE; @@ -5501,7 +5510,7 @@ fprintf(stderr, "++ op=%d\n", *Fecode); frame so that it points to the final branch. */ case OP_ONCE: - Fback_frame = ((char *)F - (char *)P) + frame_size; + Fback_frame = ((char *)F - (char *)P); for (;;) { uint32_t y = GET(P->ecode,1); @@ -5829,6 +5838,13 @@ fprintf(stderr, "++ op=%d\n", *Fecode); mb->verb_current_recurse = Fcurrent_recurse; RRETURN(MATCH_COMMIT); + case OP_COMMIT_ARG: + Fmark = mb->nomatch_mark = Fecode + 2; + RMATCH(Fecode + PRIV(OP_lengths)[*Fecode] + Fecode[1], RM36); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + mb->verb_current_recurse = Fcurrent_recurse; + RRETURN(MATCH_COMMIT); + case OP_PRUNE: RMATCH(Fecode + PRIV(OP_lengths)[*Fecode], RM14); if (rrc != MATCH_NOMATCH) RRETURN(rrc); @@ -5921,7 +5937,7 @@ in rrc. */ RETURN_SWITCH: if (Frdepth == 0) return rrc; /* Exit from the top level */ -F = (heapframe *)((char *)F - Fback_frame); /* Back track */ +F = (heapframe *)((char *)F - Fback_frame); /* Backtrack */ mb->cb->callout_flags |= PCRE2_CALLOUT_BACKTRACK; /* Note for callouts */ #ifdef DEBUG_SHOW_RMATCH @@ -5934,7 +5950,7 @@ switch (Freturn_id) LBL( 9) LBL(10) LBL(11) LBL(12) LBL(13) LBL(14) LBL(15) LBL(16) LBL(17) LBL(18) LBL(19) LBL(20) LBL(21) LBL(22) LBL(23) LBL(24) LBL(25) LBL(26) LBL(27) LBL(28) LBL(29) LBL(30) LBL(31) LBL(32) - LBL(33) LBL(34) LBL(35) + LBL(33) LBL(34) LBL(35) LBL(36) #ifdef SUPPORT_WIDE_CHARS LBL(100) LBL(101) @@ -6275,7 +6291,7 @@ mb->match_limit_depth = (mcontext->depth_limit < re->limit_depth)? /* If a pattern has very many capturing parentheses, the frame size may be very large. Ensure that there are at least 10 available frames by getting an initial vector on the heap if necessary, except when the heap limit prevents this. Get -fewer if possible. (The heap limit is in kilobytes.) */ +fewer if possible. (The heap limit is in kibibytes.) */ if (frame_size <= START_FRAMES_SIZE/10) { diff --git a/ProcessHacker/pcre/pcre2_pattern_info.c b/ProcessHacker/pcre/pcre2_pattern_info.c index 906e9198f590..a29f5eff673b 100644 --- a/ProcessHacker/pcre/pcre2_pattern_info.c +++ b/ProcessHacker/pcre/pcre2_pattern_info.c @@ -7,7 +7,7 @@ and semantics are as close as possible to those of the Perl 5 language. Written by Philip Hazel Original API code Copyright (c) 1997-2012 University of Cambridge - New API code Copyright (c) 2016-2017 University of Cambridge + New API code Copyright (c) 2016-2018 University of Cambridge ----------------------------------------------------------------------------- Redistribution and use in source and binary forms, with or without @@ -390,6 +390,7 @@ while (TRUE) #endif case OP_MARK: + case OP_COMMIT_ARG: case OP_PRUNE_ARG: case OP_SKIP_ARG: case OP_THEN_ARG: diff --git a/ProcessHacker/pcre/pcre2_printint.c b/ProcessHacker/pcre/pcre2_printint.c index e4dd53fe8ca0..bd10c6b1da3d 100644 --- a/ProcessHacker/pcre/pcre2_printint.c +++ b/ProcessHacker/pcre/pcre2_printint.c @@ -7,7 +7,7 @@ and semantics are as close as possible to those of the Perl 5 language. Written by Philip Hazel Original API code Copyright (c) 1997-2012 University of Cambridge - New API code Copyright (c) 2016-2017 University of Cambridge + New API code Copyright (c) 2016-2018 University of Cambridge ----------------------------------------------------------------------------- Redistribution and use in source and binary forms, with or without @@ -799,6 +799,7 @@ for(;;) break; case OP_MARK: + case OP_COMMIT_ARG: case OP_PRUNE_ARG: case OP_SKIP_ARG: case OP_THEN_ARG: diff --git a/ProcessHacker/pcre/pcre2_serialize.c b/ProcessHacker/pcre/pcre2_serialize.c index d2cc603cbb5b..cec1a035d19d 100644 --- a/ProcessHacker/pcre/pcre2_serialize.c +++ b/ProcessHacker/pcre/pcre2_serialize.c @@ -7,7 +7,7 @@ and semantics are as close as possible to those of the Perl 5 language. Written by Philip Hazel Original API code Copyright (c) 1997-2012 University of Cambridge - New API code Copyright (c) 2016-2017 University of Cambridge + New API code Copyright (c) 2016-2018 University of Cambridge ----------------------------------------------------------------------------- Redistribution and use in source and binary forms, with or without @@ -127,7 +127,25 @@ dst_bytes += tables_length; for (i = 0; i < number_of_codes; i++) { re = (const pcre2_real_code *)(codes[i]); - memcpy(dst_bytes, (char *)re, re->blocksize); + (void)memcpy(dst_bytes, (char *)re, re->blocksize); + + /* Certain fields in the compiled code block are re-set during + deserialization. In order to ensure that the serialized data stream is always + the same for the same pattern, set them to zero here. We can't assume the + copy of the pattern is correctly aligned for accessing the fields as part of + a structure. Note the use of sizeof(void *) in the second of these, to + specify the size of a pointer. If sizeof(uint8_t *) is used (tables is a + pointer to uint8_t), gcc gives a warning because the first argument is also a + pointer to uint8_t. Casting the first argument to (void *) can stop this, but + it didn't stop Coverity giving the same complaint. */ + + (void)memset(dst_bytes + offsetof(pcre2_real_code, memctl), 0, + sizeof(pcre2_memctl)); + (void)memset(dst_bytes + offsetof(pcre2_real_code, tables), 0, + sizeof(void *)); + (void)memset(dst_bytes + offsetof(pcre2_real_code, executable_jit), 0, + sizeof(void *)); + dst_bytes += re->blocksize; } diff --git a/ProcessHacker/pcre/pcre2_string_utils.c b/ProcessHacker/pcre/pcre2_string_utils.c index 2a1f282629ab..d6be01acf55a 100644 --- a/ProcessHacker/pcre/pcre2_string_utils.c +++ b/ProcessHacker/pcre/pcre2_string_utils.c @@ -7,7 +7,7 @@ and semantics are as close as possible to those of the Perl 5 language. Written by Philip Hazel Original API code Copyright (c) 1997-2012 University of Cambridge - New API code Copyright (c) 2016 University of Cambridge + New API code Copyright (c) 2018 University of Cambridge ----------------------------------------------------------------------------- Redistribution and use in source and binary forms, with or without @@ -50,6 +50,42 @@ functions work only on 8-bit data. */ #include "pcre2_internal.h" +/************************************************* +* Emulated memmove() for systems without it * +*************************************************/ + +/* This function can make use of bcopy() if it is available. Otherwise do it by +steam, as there some non-Unix environments that lack both memmove() and +bcopy(). */ + +#if !defined(VPCOMPAT) && !defined(HAVE_MEMMOVE) +void * +PRIV(memmove)(void *d, const void *s, size_t n) +{ +#ifdef HAVE_BCOPY +bcopy(s, d, n); +return d; +#else +size_t i; +unsigned char *dest = (unsigned char *)d; +const unsigned char *src = (const unsigned char *)s; +if (dest > src) + { + dest += n; + src += n; + for (i = 0; i < n; ++i) *(--dest) = *(--src); + return (void *)dest; + } +else + { + for (i = 0; i < n; ++i) *dest++ = *src++; + return (void *)(dest - n); + } +#endif /* not HAVE_BCOPY */ +} +#endif /* not VPCOMPAT && not HAVE_MEMMOVE */ + + /************************************************* * Compare two zero-terminated PCRE2 strings * *************************************************/ diff --git a/ProcessHacker/pcre/pcre2_study.c b/ProcessHacker/pcre/pcre2_study.c index b92686759dac..acbf98b41b51 100644 --- a/ProcessHacker/pcre/pcre2_study.c +++ b/ProcessHacker/pcre/pcre2_study.c @@ -7,7 +7,7 @@ and semantics are as close as possible to those of the Perl 5 language. Written by Philip Hazel Original API code Copyright (c) 1997-2012 University of Cambridge - New API code Copyright (c) 2016-2017 University of Cambridge + New API code Copyright (c) 2016-2018 University of Cambridge ----------------------------------------------------------------------------- Redistribution and use in source and binary forms, with or without @@ -707,6 +707,7 @@ for (;;) /* Skip these, but we need to add in the name length. */ case OP_MARK: + case OP_COMMIT_ARG: case OP_PRUNE_ARG: case OP_SKIP_ARG: case OP_THEN_ARG: @@ -956,6 +957,7 @@ do case OP_CIRCM: case OP_CLOSE: case OP_COMMIT: + case OP_COMMIT_ARG: case OP_COND: case OP_CREF: case OP_FALSE: @@ -1274,7 +1276,7 @@ do break; /* Single character types set the bits and stop. Note that if PCRE2_UCP - is set, we do not see these op codes because \d etc are converted to + is set, we do not see these opcodes because \d etc are converted to properties. Therefore, these apply in the case when only characters less than 256 are recognized to match the types. */ diff --git a/ProcessHacker/pcre/pcre2_substitute.c b/ProcessHacker/pcre/pcre2_substitute.c index 8da951fc6e2a..ab8d10908aa2 100644 --- a/ProcessHacker/pcre/pcre2_substitute.c +++ b/ProcessHacker/pcre/pcre2_substitute.c @@ -7,7 +7,7 @@ and semantics are as close as possible to those of the Perl 5 language. Written by Philip Hazel Original API code Copyright (c) 1997-2012 University of Cambridge - New API code Copyright (c) 2016 University of Cambridge + New API code Copyright (c) 2016-2018 University of Cambridge ----------------------------------------------------------------------------- Redistribution and use in source and binary forms, with or without @@ -238,10 +238,12 @@ PCRE2_SPTR repend; PCRE2_SIZE extra_needed = 0; PCRE2_SIZE buff_offset, buff_length, lengthleft, fraglength; PCRE2_SIZE *ovector; +PCRE2_SIZE ovecsave[3]; buff_offset = 0; lengthleft = buff_length = *blength; *blength = PCRE2_UNSET; +ovecsave[0] = ovecsave[1] = ovecsave[2] = PCRE2_UNSET; /* Partial matching is not valid. */ @@ -361,13 +363,33 @@ do } /* Handle a successful match. Matches that use \K to end before they start - are not supported. */ - - if (ovector[1] < ovector[0]) + or start before the current point in the subject are not supported. */ + + if (ovector[1] < ovector[0] || ovector[0] < start_offset) { rc = PCRE2_ERROR_BADSUBSPATTERN; goto EXIT; } + + /* Check for the same match as previous. This is legitimate after matching an + empty string that starts after the initial match offset. We have tried again + at the match point in case the pattern is one like /(?<=\G.)/ which can never + match at its starting point, so running the match achieves the bumpalong. If + we do get the same (null) match at the original match point, it isn't such a + pattern, so we now do the empty string magic. In all other cases, a repeat + match should never occur. */ + + if (ovecsave[0] == ovector[0] && ovecsave[1] == ovector[1]) + { + if (ovector[0] == ovector[1] && ovecsave[2] != start_offset) + { + goptions = PCRE2_NOTEMPTY_ATSTART | PCRE2_ANCHORED; + ovecsave[2] = start_offset; + continue; /* Back to the top of the loop */ + } + rc = PCRE2_ERROR_INTERNAL_DUPMATCH; + goto EXIT; + } /* Count substitutions with a paranoid check for integer overflow; surely no real call to this function would ever hit this! */ @@ -799,13 +821,18 @@ do } /* End handling a literal code unit */ } /* End of loop for scanning the replacement. */ - /* The replacement has been copied to the output. Update the start offset to - point to the rest of the subject string. If we matched an empty string, - do the magic for global matches. */ - - start_offset = ovector[1]; - goptions = (ovector[0] != ovector[1])? 0 : + /* The replacement has been copied to the output. Save the details of this + match. See above for how this data is used. If we matched an empty string, do + the magic for global matches. Finally, update the start offset to point to + the rest of the subject string. */ + + ovecsave[0] = ovector[0]; + ovecsave[1] = ovector[1]; + ovecsave[2] = start_offset; + + goptions = (ovector[0] != ovector[1] || ovector[0] > start_offset)? 0 : PCRE2_ANCHORED|PCRE2_NOTEMPTY_ATSTART; + start_offset = ovector[1]; } while ((suboptions & PCRE2_SUBSTITUTE_GLOBAL) != 0); /* Repeat "do" loop */ /* Copy the rest of the subject. */ diff --git a/ProcessHacker/pcre/pcre2_tables.c b/ProcessHacker/pcre/pcre2_tables.c index 9f8dc293aa22..83d6f9de55ed 100644 --- a/ProcessHacker/pcre/pcre2_tables.c +++ b/ProcessHacker/pcre/pcre2_tables.c @@ -7,7 +7,7 @@ and semantics are as close as possible to those of the Perl 5 language. Written by Philip Hazel Original API code Copyright (c) 1997-2012 University of Cambridge - New API code Copyright (c) 2016-2017 University of Cambridge + New API code Copyright (c) 2016-2018 University of Cambridge ----------------------------------------------------------------------------- Redistribution and use in source and binary forms, with or without @@ -137,9 +137,10 @@ const uint32_t PRIV(ucp_gentype)[] = { /* This table encodes the rules for finding the end of an extended grapheme cluster. Every code point has a grapheme break property which is one of the -ucp_gbXX values defined in pcre2_ucp.h. The 2-dimensional table is indexed by -the properties of two adjacent code points. The left property selects a word -from the table, and the right property selects a bit from that word like this: +ucp_gbXX values defined in pcre2_ucp.h. These changed between Unicode versions +10 and 11. The 2-dimensional table is indexed by the properties of two adjacent +code points. The left property selects a word from the table, and the right +property selects a bit from that word like this: PRIV(ucp_gbtable)[left-property] & (1 << right-property) @@ -166,49 +167,41 @@ are implementing). 6. Do not break after Prepend characters. -7. Do not break within emoji modifier sequences (E_Base or E_Base_GAZ followed - by E_Modifier). Extend characters are allowed before the modifier; this - cannot be represented in this table, the code has to deal with it. +7. Do not break within emoji modifier sequences or emoji zwj sequences. That + is, do not break between characters with the Extended_Pictographic property. + Extend and ZWJ characters are allowed between the characters; this cannot be + represented in this table, the code has to deal with it. -8. Do not break within emoji zwj sequences (ZWJ followed by Glue_After_Zwj or - E_Base_GAZ). - -9. Do not break within emoji flag sequences. That is, do not break between +8. Do not break within emoji flag sequences. That is, do not break between regional indicator (RI) symbols if there are an odd number of RI characters before the break point. This table encodes "join RI characters"; the code has to deal with checking for previous adjoining RIs. -10. Otherwise, break everywhere. +9. Otherwise, break everywhere. */ #define ESZ (1< +#include +#include + + +/************************************************************************** +* Here is the program. The API includes the concept of "contexts" for * +* setting up unusual interface requirements for compiling and matching, * +* such as custom memory managers and non-standard newline definitions. * +* This program does not do any of this, so it makes no use of contexts, * +* always passing NULL where a context could be given. * +**************************************************************************/ + +int main(int argc, char **argv) +{ +pcre2_code *re; +PCRE2_SPTR pattern; /* PCRE2_SPTR is a pointer to unsigned code units of */ +PCRE2_SPTR subject; /* the appropriate width (in this case, 8 bits). */ +PCRE2_SPTR name_table; + +int crlf_is_newline; +int errornumber; +int find_all; +int i; +int rc; +int utf8; + +uint32_t option_bits; +uint32_t namecount; +uint32_t name_entry_size; +uint32_t newline; + +PCRE2_SIZE erroroffset; +PCRE2_SIZE *ovector; + +size_t subject_length; +pcre2_match_data *match_data; + + + +/************************************************************************** +* First, sort out the command line. There is only one possible option at * +* the moment, "-g" to request repeated matching to find all occurrences, * +* like Perl's /g option. We set the variable find_all to a non-zero value * +* if the -g option is present. * +**************************************************************************/ + +find_all = 0; +for (i = 1; i < argc; i++) + { + if (strcmp(argv[i], "-g") == 0) find_all = 1; + else if (argv[i][0] == '-') + { + printf("Unrecognised option %s\n", argv[i]); + return 1; + } + else break; + } + +/* After the options, we require exactly two arguments, which are the pattern, +and the subject string. */ + +if (argc - i != 2) + { + printf("Exactly two arguments required: a regex and a subject string\n"); + return 1; + } + +/* As pattern and subject are char arguments, they can be straightforwardly +cast to PCRE2_SPTR as we are working in 8-bit code units. */ + +pattern = (PCRE2_SPTR)argv[i]; +subject = (PCRE2_SPTR)argv[i+1]; +subject_length = strlen((char *)subject); + + +/************************************************************************* +* Now we are going to compile the regular expression pattern, and handle * +* any errors that are detected. * +*************************************************************************/ + +re = pcre2_compile( + pattern, /* the pattern */ + PCRE2_ZERO_TERMINATED, /* indicates pattern is zero-terminated */ + 0, /* default options */ + &errornumber, /* for error number */ + &erroroffset, /* for error offset */ + NULL); /* use default compile context */ + +/* Compilation failed: print the error message and exit. */ + +if (re == NULL) + { + PCRE2_UCHAR buffer[256]; + pcre2_get_error_message(errornumber, buffer, sizeof(buffer)); + printf("PCRE2 compilation failed at offset %d: %s\n", (int)erroroffset, + buffer); + return 1; + } + + +/************************************************************************* +* If the compilation succeeded, we call PCRE again, in order to do a * +* pattern match against the subject string. This does just ONE match. If * +* further matching is needed, it will be done below. Before running the * +* match we must set up a match_data block for holding the result. * +*************************************************************************/ + +/* Using this function ensures that the block is exactly the right size for +the number of capturing parentheses in the pattern. */ + +match_data = pcre2_match_data_create_from_pattern(re, NULL); + +rc = pcre2_match( + re, /* the compiled pattern */ + subject, /* the subject string */ + subject_length, /* the length of the subject */ + 0, /* start at offset 0 in the subject */ + 0, /* default options */ + match_data, /* block for storing the result */ + NULL); /* use default match context */ + +/* Matching failed: handle error cases */ + +if (rc < 0) + { + switch(rc) + { + case PCRE2_ERROR_NOMATCH: printf("No match\n"); break; + /* + Handle other special cases if you like + */ + default: printf("Matching error %d\n", rc); break; + } + pcre2_match_data_free(match_data); /* Release memory used for the match */ + pcre2_code_free(re); /* data and the compiled pattern. */ + return 1; + } + +/* Match succeded. Get a pointer to the output vector, where string offsets are +stored. */ + +ovector = pcre2_get_ovector_pointer(match_data); +printf("Match succeeded at offset %d\n", (int)ovector[0]); + + +/************************************************************************* +* We have found the first match within the subject string. If the output * +* vector wasn't big enough, say so. Then output any substrings that were * +* captured. * +*************************************************************************/ + +/* The output vector wasn't big enough. This should not happen, because we used +pcre2_match_data_create_from_pattern() above. */ + +if (rc == 0) + printf("ovector was not big enough for all the captured substrings\n"); + +/* We must guard against patterns such as /(?=.\K)/ that use \K in an assertion +to set the start of a match later than its end. In this demonstration program, +we just detect this case and give up. */ + +if (ovector[0] > ovector[1]) + { + printf("\\K was used in an assertion to set the match start after its end.\n" + "From end to start the match was: %.*s\n", (int)(ovector[0] - ovector[1]), + (char *)(subject + ovector[1])); + printf("Run abandoned\n"); + pcre2_match_data_free(match_data); + pcre2_code_free(re); + return 1; + } + +/* Show substrings stored in the output vector by number. Obviously, in a real +application you might want to do things other than print them. */ + +for (i = 0; i < rc; i++) + { + PCRE2_SPTR substring_start = subject + ovector[2*i]; + size_t substring_length = ovector[2*i+1] - ovector[2*i]; + printf("%2d: %.*s\n", i, (int)substring_length, (char *)substring_start); + } + + +/************************************************************************** +* That concludes the basic part of this demonstration program. We have * +* compiled a pattern, and performed a single match. The code that follows * +* shows first how to access named substrings, and then how to code for * +* repeated matches on the same subject. * +**************************************************************************/ + +/* See if there are any named substrings, and if so, show them by name. First +we have to extract the count of named parentheses from the pattern. */ + +(void)pcre2_pattern_info( + re, /* the compiled pattern */ + PCRE2_INFO_NAMECOUNT, /* get the number of named substrings */ + &namecount); /* where to put the answer */ + +if (namecount == 0) printf("No named substrings\n"); else + { + PCRE2_SPTR tabptr; + printf("Named substrings\n"); + + /* Before we can access the substrings, we must extract the table for + translating names to numbers, and the size of each entry in the table. */ + + (void)pcre2_pattern_info( + re, /* the compiled pattern */ + PCRE2_INFO_NAMETABLE, /* address of the table */ + &name_table); /* where to put the answer */ + + (void)pcre2_pattern_info( + re, /* the compiled pattern */ + PCRE2_INFO_NAMEENTRYSIZE, /* size of each entry in the table */ + &name_entry_size); /* where to put the answer */ + + /* Now we can scan the table and, for each entry, print the number, the name, + and the substring itself. In the 8-bit library the number is held in two + bytes, most significant first. */ + + tabptr = name_table; + for (i = 0; i < namecount; i++) + { + int n = (tabptr[0] << 8) | tabptr[1]; + printf("(%d) %*s: %.*s\n", n, name_entry_size - 3, tabptr + 2, + (int)(ovector[2*n+1] - ovector[2*n]), subject + ovector[2*n]); + tabptr += name_entry_size; + } + } + + +/************************************************************************* +* If the "-g" option was given on the command line, we want to continue * +* to search for additional matches in the subject string, in a similar * +* way to the /g option in Perl. This turns out to be trickier than you * +* might think because of the possibility of matching an empty string. * +* What happens is as follows: * +* * +* If the previous match was NOT for an empty string, we can just start * +* the next match at the end of the previous one. * +* * +* If the previous match WAS for an empty string, we can't do that, as it * +* would lead to an infinite loop. Instead, a call of pcre2_match() is * +* made with the PCRE2_NOTEMPTY_ATSTART and PCRE2_ANCHORED flags set. The * +* first of these tells PCRE2 that an empty string at the start of the * +* subject is not a valid match; other possibilities must be tried. The * +* second flag restricts PCRE2 to one match attempt at the initial string * +* position. If this match succeeds, an alternative to the empty string * +* match has been found, and we can print it and proceed round the loop, * +* advancing by the length of whatever was found. If this match does not * +* succeed, we still stay in the loop, advancing by just one character. * +* In UTF-8 mode, which can be set by (*UTF) in the pattern, this may be * +* more than one byte. * +* * +* However, there is a complication concerned with newlines. When the * +* newline convention is such that CRLF is a valid newline, we must * +* advance by two characters rather than one. The newline convention can * +* be set in the regex by (*CR), etc.; if not, we must find the default. * +*************************************************************************/ + +if (!find_all) /* Check for -g */ + { + pcre2_match_data_free(match_data); /* Release the memory that was used */ + pcre2_code_free(re); /* for the match data and the pattern. */ + return 0; /* Exit the program. */ + } + +/* Before running the loop, check for UTF-8 and whether CRLF is a valid newline +sequence. First, find the options with which the regex was compiled and extract +the UTF state. */ + +(void)pcre2_pattern_info(re, PCRE2_INFO_ALLOPTIONS, &option_bits); +utf8 = (option_bits & PCRE2_UTF) != 0; + +/* Now find the newline convention and see whether CRLF is a valid newline +sequence. */ + +(void)pcre2_pattern_info(re, PCRE2_INFO_NEWLINE, &newline); +crlf_is_newline = newline == PCRE2_NEWLINE_ANY || + newline == PCRE2_NEWLINE_CRLF || + newline == PCRE2_NEWLINE_ANYCRLF; + +/* Loop for second and subsequent matches */ + +for (;;) + { + uint32_t options = 0; /* Normally no options */ + PCRE2_SIZE start_offset = ovector[1]; /* Start at end of previous match */ + + /* If the previous match was for an empty string, we are finished if we are + at the end of the subject. Otherwise, arrange to run another match at the + same point to see if a non-empty match can be found. */ + + if (ovector[0] == ovector[1]) + { + if (ovector[0] == subject_length) break; + options = PCRE2_NOTEMPTY_ATSTART | PCRE2_ANCHORED; + } + + /* If the previous match was not an empty string, there is one tricky case to + consider. If a pattern contains \K within a lookbehind assertion at the + start, the end of the matched string can be at the offset where the match + started. Without special action, this leads to a loop that keeps on matching + the same substring. We must detect this case and arrange to move the start on + by one character. The pcre2_get_startchar() function returns the starting + offset that was passed to pcre2_match(). */ + + else + { + PCRE2_SIZE startchar = pcre2_get_startchar(match_data); + if (start_offset <= startchar) + { + if (startchar >= subject_length) break; /* Reached end of subject. */ + start_offset = startchar + 1; /* Advance by one character. */ + if (utf8) /* If UTF-8, it may be more */ + { /* than one code unit. */ + for (; start_offset < subject_length; start_offset++) + if ((subject[start_offset] & 0xc0) != 0x80) break; + } + } + } + + /* Run the next matching operation */ + + rc = pcre2_match( + re, /* the compiled pattern */ + subject, /* the subject string */ + subject_length, /* the length of the subject */ + start_offset, /* starting offset in the subject */ + options, /* options */ + match_data, /* block for storing the result */ + NULL); /* use default match context */ + + /* This time, a result of NOMATCH isn't an error. If the value in "options" + is zero, it just means we have found all possible matches, so the loop ends. + Otherwise, it means we have failed to find a non-empty-string match at a + point where there was a previous empty-string match. In this case, we do what + Perl does: advance the matching position by one character, and continue. We + do this by setting the "end of previous match" offset, because that is picked + up at the top of the loop as the point at which to start again. + + There are two complications: (a) When CRLF is a valid newline sequence, and + the current position is just before it, advance by an extra byte. (b) + Otherwise we must ensure that we skip an entire UTF character if we are in + UTF mode. */ + + if (rc == PCRE2_ERROR_NOMATCH) + { + if (options == 0) break; /* All matches found */ + ovector[1] = start_offset + 1; /* Advance one code unit */ + if (crlf_is_newline && /* If CRLF is a newline & */ + start_offset < subject_length - 1 && /* we are at CRLF, */ + subject[start_offset] == '\r' && + subject[start_offset + 1] == '\n') + ovector[1] += 1; /* Advance by one more. */ + else if (utf8) /* Otherwise, ensure we */ + { /* advance a whole UTF-8 */ + while (ovector[1] < subject_length) /* character. */ + { + if ((subject[ovector[1]] & 0xc0) != 0x80) break; + ovector[1] += 1; + } + } + continue; /* Go round the loop again */ + } + + /* Other matching errors are not recoverable. */ + + if (rc < 0) + { + printf("Matching error %d\n", rc); + pcre2_match_data_free(match_data); + pcre2_code_free(re); + return 1; + } + + /* Match succeded */ + + printf("\nMatch succeeded again at offset %d\n", (int)ovector[0]); + + /* The match succeeded, but the output vector wasn't big enough. This + should not happen. */ + + if (rc == 0) + printf("ovector was not big enough for all the captured substrings\n"); + + /* We must guard against patterns such as /(?=.\K)/ that use \K in an + assertion to set the start of a match later than its end. In this + demonstration program, we just detect this case and give up. */ + + if (ovector[0] > ovector[1]) + { + printf("\\K was used in an assertion to set the match start after its end.\n" + "From end to start the match was: %.*s\n", (int)(ovector[0] - ovector[1]), + (char *)(subject + ovector[1])); + printf("Run abandoned\n"); + pcre2_match_data_free(match_data); + pcre2_code_free(re); + return 1; + } + + /* As before, show substrings stored in the output vector by number, and then + also any named substrings. */ + + for (i = 0; i < rc; i++) + { + PCRE2_SPTR substring_start = subject + ovector[2*i]; + size_t substring_length = ovector[2*i+1] - ovector[2*i]; + printf("%2d: %.*s\n", i, (int)substring_length, (char *)substring_start); + } + + if (namecount == 0) printf("No named substrings\n"); else + { + PCRE2_SPTR tabptr = name_table; + printf("Named substrings\n"); + for (i = 0; i < namecount; i++) + { + int n = (tabptr[0] << 8) | tabptr[1]; + printf("(%d) %*s: %.*s\n", n, name_entry_size - 3, tabptr + 2, + (int)(ovector[2*n+1] - ovector[2*n]), subject + ovector[2*n]); + tabptr += name_entry_size; + } + } + } /* End of loop to find second and subsequent matches */ + +printf("\n"); +pcre2_match_data_free(match_data); +pcre2_code_free(re); +return 0; +} + +/* End of pcre2demo.c */ diff --git a/ProcessHacker/pcre/pcre2grep.c b/ProcessHacker/pcre/pcre2grep.c new file mode 100644 index 000000000000..d5f34c81fb29 --- /dev/null +++ b/ProcessHacker/pcre/pcre2grep.c @@ -0,0 +1,4340 @@ +/************************************************* +* pcre2grep program * +*************************************************/ + +/* This is a grep program that uses the 8-bit PCRE regular expression library +via the PCRE2 updated API to do its pattern matching. On Unix-like, Windows, +and native z/OS systems it can recurse into directories, and in z/OS it can +handle PDS files. + +Note that for native z/OS, in addition to defining the NATIVE_ZOS macro, an +additional header is required. That header is not included in the main PCRE2 +distribution because other apparatus is needed to compile pcre2grep for z/OS. +The header can be found in the special z/OS distribution, which is available +from www.zaconsultants.net or from www.cbttape.org. + + Copyright (c) 1997-2018 University of Cambridge + +----------------------------------------------------------------------------- +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of the University of Cambridge nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +----------------------------------------------------------------------------- +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include +#include + +#include +#include + +#if (defined _WIN32 || (defined HAVE_WINDOWS_H && HAVE_WINDOWS_H)) \ + && !defined WIN32 && !defined(__CYGWIN__) +#define WIN32 +#endif + +/* Some cmake's define it still */ +#if defined(__CYGWIN__) && defined(WIN32) +#undef WIN32 +#endif + +#ifdef WIN32 +#include /* For _setmode() */ +#include /* For _O_BINARY */ +#endif + +#ifdef SUPPORT_PCRE2GREP_CALLOUT +#ifdef WIN32 +#include +#else +#include +#endif +#endif + +#ifdef HAVE_UNISTD_H +#include +#endif + +#ifdef SUPPORT_LIBZ +#include +#endif + +#ifdef SUPPORT_LIBBZ2 +#include +#endif + +#define PCRE2_CODE_UNIT_WIDTH 8 +#include "pcre2.h" + +/* Older versions of MSVC lack snprintf(). This define allows for +warning/error-free compilation and testing with MSVC compilers back to at least +MSVC 10/2010. Except for VC6 (which is missing some fundamentals and fails). */ + +#if defined(_MSC_VER) && (_MSC_VER < 1900) +#define snprintf _snprintf +#endif + +#define FALSE 0 +#define TRUE 1 + +typedef int BOOL; + +#define OFFSET_SIZE 33 + +#if BUFSIZ > 8192 +#define MAXPATLEN BUFSIZ +#else +#define MAXPATLEN 8192 +#endif + +#define FNBUFSIZ 2048 +#define ERRBUFSIZ 256 + +/* Values for the "filenames" variable, which specifies options for file name +output. The order is important; it is assumed that a file name is wanted for +all values greater than FN_DEFAULT. */ + +enum { FN_NONE, FN_DEFAULT, FN_MATCH_ONLY, FN_NOMATCH_ONLY, FN_FORCE }; + +/* File reading styles */ + +enum { FR_PLAIN, FR_LIBZ, FR_LIBBZ2 }; + +/* Actions for the -d and -D options */ + +enum { dee_READ, dee_SKIP, dee_RECURSE }; +enum { DEE_READ, DEE_SKIP }; + +/* Actions for special processing options (flag bits) */ + +#define PO_WORD_MATCH 0x0001 +#define PO_LINE_MATCH 0x0002 +#define PO_FIXED_STRINGS 0x0004 + +/* Binary file options */ + +enum { BIN_BINARY, BIN_NOMATCH, BIN_TEXT }; + +/* In newer versions of gcc, with FORTIFY_SOURCE set (the default in some +environments), a warning is issued if the value of fwrite() is ignored. +Unfortunately, casting to (void) does not suppress the warning. To get round +this, we use a macro that compiles a fudge. Oddly, this does not also seem to +apply to fprintf(). */ + +#define FWRITE_IGNORE(a,b,c,d) if (fwrite(a,b,c,d)) {} + +/* Under Windows, we have to set stdout to be binary, so that it does not +convert \r\n at the ends of output lines to \r\r\n. However, that means that +any messages written to stdout must have \r\n as their line terminator. This is +handled by using STDOUT_NL as the newline string. We also use a normal double +quote for the example, as single quotes aren't usually available. */ + +#ifdef WIN32 +#define STDOUT_NL "\r\n" +#define QUOT "\"" +#else +#define STDOUT_NL "\n" +#define QUOT "'" +#endif + + + +/************************************************* +* Global variables * +*************************************************/ + +/* Jeffrey Friedl has some debugging requirements that are not part of the +regular code. */ + +#ifdef JFRIEDL_DEBUG +static int S_arg = -1; +static unsigned int jfriedl_XR = 0; /* repeat regex attempt this many times */ +static unsigned int jfriedl_XT = 0; /* replicate text this many times */ +static const char *jfriedl_prefix = ""; +static const char *jfriedl_postfix = ""; +#endif + +static const char *colour_string = "1;31"; +static const char *colour_option = NULL; +static const char *dee_option = NULL; +static const char *DEE_option = NULL; +static const char *locale = NULL; +static const char *newline_arg = NULL; +static const char *om_separator = NULL; +static const char *stdin_name = "(standard input)"; +static const char *output_text = NULL; + +static char *main_buffer = NULL; + +static int after_context = 0; +static int before_context = 0; +static int binary_files = BIN_BINARY; +static int both_context = 0; +static int bufthird = PCRE2GREP_BUFSIZE; +static int max_bufthird = PCRE2GREP_MAX_BUFSIZE; +static int bufsize = 3*PCRE2GREP_BUFSIZE; +static int endlinetype; + +static unsigned long int total_count = 0; +static unsigned long int counts_printed = 0; + +#ifdef WIN32 +static int dee_action = dee_SKIP; +#else +static int dee_action = dee_READ; +#endif + +static int DEE_action = DEE_READ; +static int error_count = 0; +static int filenames = FN_DEFAULT; + +#ifdef SUPPORT_PCRE2GREP_JIT +static BOOL use_jit = TRUE; +#else +static BOOL use_jit = FALSE; +#endif + +static const uint8_t *character_tables = NULL; + +static uint32_t pcre2_options = 0; +static uint32_t extra_options = 0; +static PCRE2_SIZE heap_limit = PCRE2_UNSET; +static uint32_t match_limit = 0; +static uint32_t depth_limit = 0; + +static pcre2_compile_context *compile_context; +static pcre2_match_context *match_context; +static pcre2_match_data *match_data; +static PCRE2_SIZE *offsets; + +static BOOL count_only = FALSE; +static BOOL do_colour = FALSE; +#ifdef WIN32 +static BOOL do_ansi = FALSE; +#endif +static BOOL file_offsets = FALSE; +static BOOL hyphenpending = FALSE; +static BOOL invert = FALSE; +static BOOL line_buffered = FALSE; +static BOOL line_offsets = FALSE; +static BOOL multiline = FALSE; +static BOOL number = FALSE; +static BOOL omit_zero_count = FALSE; +static BOOL resource_error = FALSE; +static BOOL quiet = FALSE; +static BOOL show_total_count = FALSE; +static BOOL silent = FALSE; +static BOOL utf = FALSE; + +/* Structure for list of --only-matching capturing numbers. */ + +typedef struct omstr { + struct omstr *next; + int groupnum; +} omstr; + +static omstr *only_matching = NULL; +static omstr *only_matching_last = NULL; +static int only_matching_count; + +/* Structure for holding the two variables that describe a number chain. */ + +typedef struct omdatastr { + omstr **anchor; + omstr **lastptr; +} omdatastr; + +static omdatastr only_matching_data = { &only_matching, &only_matching_last }; + +/* Structure for list of file names (for -f and --{in,ex}clude-from) */ + +typedef struct fnstr { + struct fnstr *next; + char *name; +} fnstr; + +static fnstr *exclude_from = NULL; +static fnstr *exclude_from_last = NULL; +static fnstr *include_from = NULL; +static fnstr *include_from_last = NULL; + +static fnstr *file_lists = NULL; +static fnstr *file_lists_last = NULL; +static fnstr *pattern_files = NULL; +static fnstr *pattern_files_last = NULL; + +/* Structure for holding the two variables that describe a file name chain. */ + +typedef struct fndatastr { + fnstr **anchor; + fnstr **lastptr; +} fndatastr; + +static fndatastr exclude_from_data = { &exclude_from, &exclude_from_last }; +static fndatastr include_from_data = { &include_from, &include_from_last }; +static fndatastr file_lists_data = { &file_lists, &file_lists_last }; +static fndatastr pattern_files_data = { &pattern_files, &pattern_files_last }; + +/* Structure for pattern and its compiled form; used for matching patterns and +also for include/exclude patterns. */ + +typedef struct patstr { + struct patstr *next; + char *string; + PCRE2_SIZE length; + pcre2_code *compiled; +} patstr; + +static patstr *patterns = NULL; +static patstr *patterns_last = NULL; +static patstr *include_patterns = NULL; +static patstr *include_patterns_last = NULL; +static patstr *exclude_patterns = NULL; +static patstr *exclude_patterns_last = NULL; +static patstr *include_dir_patterns = NULL; +static patstr *include_dir_patterns_last = NULL; +static patstr *exclude_dir_patterns = NULL; +static patstr *exclude_dir_patterns_last = NULL; + +/* Structure holding the two variables that describe a pattern chain. A pointer +to such structures is used for each appropriate option. */ + +typedef struct patdatastr { + patstr **anchor; + patstr **lastptr; +} patdatastr; + +static patdatastr match_patdata = { &patterns, &patterns_last }; +static patdatastr include_patdata = { &include_patterns, &include_patterns_last }; +static patdatastr exclude_patdata = { &exclude_patterns, &exclude_patterns_last }; +static patdatastr include_dir_patdata = { &include_dir_patterns, &include_dir_patterns_last }; +static patdatastr exclude_dir_patdata = { &exclude_dir_patterns, &exclude_dir_patterns_last }; + +static patstr **incexlist[4] = { &include_patterns, &exclude_patterns, + &include_dir_patterns, &exclude_dir_patterns }; + +static const char *incexname[4] = { "--include", "--exclude", + "--include-dir", "--exclude-dir" }; + +/* Structure for options and list of them */ + +enum { OP_NODATA, OP_STRING, OP_OP_STRING, OP_NUMBER, OP_U32NUMBER, OP_SIZE, + OP_OP_NUMBER, OP_OP_NUMBERS, OP_PATLIST, OP_FILELIST, OP_BINFILES }; + +typedef struct option_item { + int type; + int one_char; + void *dataptr; + const char *long_name; + const char *help_text; +} option_item; + +/* Options without a single-letter equivalent get a negative value. This can be +used to identify them. */ + +#define N_COLOUR (-1) +#define N_EXCLUDE (-2) +#define N_EXCLUDE_DIR (-3) +#define N_HELP (-4) +#define N_INCLUDE (-5) +#define N_INCLUDE_DIR (-6) +#define N_LABEL (-7) +#define N_LOCALE (-8) +#define N_NULL (-9) +#define N_LOFFSETS (-10) +#define N_FOFFSETS (-11) +#define N_LBUFFER (-12) +#define N_H_LIMIT (-13) +#define N_M_LIMIT (-14) +#define N_M_LIMIT_DEP (-15) +#define N_BUFSIZE (-16) +#define N_NOJIT (-17) +#define N_FILE_LIST (-18) +#define N_BINARY_FILES (-19) +#define N_EXCLUDE_FROM (-20) +#define N_INCLUDE_FROM (-21) +#define N_OM_SEPARATOR (-22) +#define N_MAX_BUFSIZE (-23) + +static option_item optionlist[] = { + { OP_NODATA, N_NULL, NULL, "", "terminate options" }, + { OP_NODATA, N_HELP, NULL, "help", "display this help and exit" }, + { OP_NUMBER, 'A', &after_context, "after-context=number", "set number of following context lines" }, + { OP_NODATA, 'a', NULL, "text", "treat binary files as text" }, + { OP_NUMBER, 'B', &before_context, "before-context=number", "set number of prior context lines" }, + { OP_BINFILES, N_BINARY_FILES, NULL, "binary-files=word", "set treatment of binary files" }, + { OP_NUMBER, N_BUFSIZE,&bufthird, "buffer-size=number", "set processing buffer starting size" }, + { OP_NUMBER, N_MAX_BUFSIZE,&max_bufthird, "max-buffer-size=number", "set processing buffer maximum size" }, + { OP_OP_STRING, N_COLOUR, &colour_option, "color=option", "matched text color option" }, + { OP_OP_STRING, N_COLOUR, &colour_option, "colour=option", "matched text colour option" }, + { OP_NUMBER, 'C', &both_context, "context=number", "set number of context lines, before & after" }, + { OP_NODATA, 'c', NULL, "count", "print only a count of matching lines per FILE" }, + { OP_STRING, 'D', &DEE_option, "devices=action","how to handle devices, FIFOs, and sockets" }, + { OP_STRING, 'd', &dee_option, "directories=action", "how to handle directories" }, + { OP_PATLIST, 'e', &match_patdata, "regex(p)=pattern", "specify pattern (may be used more than once)" }, + { OP_NODATA, 'F', NULL, "fixed-strings", "patterns are sets of newline-separated strings" }, + { OP_FILELIST, 'f', &pattern_files_data, "file=path", "read patterns from file" }, + { OP_FILELIST, N_FILE_LIST, &file_lists_data, "file-list=path","read files to search from file" }, + { OP_NODATA, N_FOFFSETS, NULL, "file-offsets", "output file offsets, not text" }, + { OP_NODATA, 'H', NULL, "with-filename", "force the prefixing filename on output" }, + { OP_NODATA, 'h', NULL, "no-filename", "suppress the prefixing filename on output" }, + { OP_NODATA, 'I', NULL, "", "treat binary files as not matching (ignore)" }, + { OP_NODATA, 'i', NULL, "ignore-case", "ignore case distinctions" }, + { OP_NODATA, 'l', NULL, "files-with-matches", "print only FILE names containing matches" }, + { OP_NODATA, 'L', NULL, "files-without-match","print only FILE names not containing matches" }, + { OP_STRING, N_LABEL, &stdin_name, "label=name", "set name for standard input" }, + { OP_NODATA, N_LBUFFER, NULL, "line-buffered", "use line buffering" }, + { OP_NODATA, N_LOFFSETS, NULL, "line-offsets", "output line numbers and offsets, not text" }, + { OP_STRING, N_LOCALE, &locale, "locale=locale", "use the named locale" }, + { OP_SIZE, N_H_LIMIT, &heap_limit, "heap-limit=number", "set PCRE2 heap limit option (kibibytes)" }, + { OP_U32NUMBER, N_M_LIMIT, &match_limit, "match-limit=number", "set PCRE2 match limit option" }, + { OP_U32NUMBER, N_M_LIMIT_DEP, &depth_limit, "depth-limit=number", "set PCRE2 depth limit option" }, + { OP_U32NUMBER, N_M_LIMIT_DEP, &depth_limit, "recursion-limit=number", "obsolete synonym for depth-limit" }, + { OP_NODATA, 'M', NULL, "multiline", "run in multiline mode" }, + { OP_STRING, 'N', &newline_arg, "newline=type", "set newline type (CR, LF, CRLF, ANYCRLF, ANY, or NUL)" }, + { OP_NODATA, 'n', NULL, "line-number", "print line number with output lines" }, +#ifdef SUPPORT_PCRE2GREP_JIT + { OP_NODATA, N_NOJIT, NULL, "no-jit", "do not use just-in-time compiler optimization" }, +#else + { OP_NODATA, N_NOJIT, NULL, "no-jit", "ignored: this pcre2grep does not support JIT" }, +#endif + { OP_STRING, 'O', &output_text, "output=text", "show only this text (possibly expanded)" }, + { OP_OP_NUMBERS, 'o', &only_matching_data, "only-matching=n", "show only the part of the line that matched" }, + { OP_STRING, N_OM_SEPARATOR, &om_separator, "om-separator=text", "set separator for multiple -o output" }, + { OP_NODATA, 'q', NULL, "quiet", "suppress output, just set return code" }, + { OP_NODATA, 'r', NULL, "recursive", "recursively scan sub-directories" }, + { OP_PATLIST, N_EXCLUDE,&exclude_patdata, "exclude=pattern","exclude matching files when recursing" }, + { OP_PATLIST, N_INCLUDE,&include_patdata, "include=pattern","include matching files when recursing" }, + { OP_PATLIST, N_EXCLUDE_DIR,&exclude_dir_patdata, "exclude-dir=pattern","exclude matching directories when recursing" }, + { OP_PATLIST, N_INCLUDE_DIR,&include_dir_patdata, "include-dir=pattern","include matching directories when recursing" }, + { OP_FILELIST, N_EXCLUDE_FROM,&exclude_from_data, "exclude-from=path", "read exclude list from file" }, + { OP_FILELIST, N_INCLUDE_FROM,&include_from_data, "include-from=path", "read include list from file" }, +#ifdef JFRIEDL_DEBUG + { OP_OP_NUMBER, 'S', &S_arg, "jeffS", "replace matched (sub)string with X" }, +#endif + { OP_NODATA, 's', NULL, "no-messages", "suppress error messages" }, + { OP_NODATA, 't', NULL, "total-count", "print total count of matching lines" }, + { OP_NODATA, 'u', NULL, "utf", "use UTF mode" }, + { OP_NODATA, 'V', NULL, "version", "print version information and exit" }, + { OP_NODATA, 'v', NULL, "invert-match", "select non-matching lines" }, + { OP_NODATA, 'w', NULL, "word-regex(p)", "force patterns to match only as words" }, + { OP_NODATA, 'x', NULL, "line-regex(p)", "force patterns to match only whole lines" }, + { OP_NODATA, 0, NULL, NULL, NULL } +}; + +/* Table of names for newline types. Must be kept in step with the definitions +of PCRE2_NEWLINE_xx in pcre2.h. */ + +static const char *newlines[] = { + "DEFAULT", "CR", "LF", "CRLF", "ANY", "ANYCRLF", "NUL" }; + +/* UTF-8 tables - used only when the newline setting is "any". */ + +const int utf8_table3[] = { 0xff, 0x1f, 0x0f, 0x07, 0x03, 0x01}; + +const char utf8_table4[] = { + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5 }; + + +#if !defined(VPCOMPAT) && !defined(HAVE_MEMMOVE) +/************************************************* +* Emulated memmove() for systems without it * +*************************************************/ + +/* This function can make use of bcopy() if it is available. Otherwise do it by +steam, as there are some non-Unix environments that lack both memmove() and +bcopy(). */ + +static void * +emulated_memmove(void *d, const void *s, size_t n) +{ +#ifdef HAVE_BCOPY +bcopy(s, d, n); +return d; +#else +size_t i; +unsigned char *dest = (unsigned char *)d; +const unsigned char *src = (const unsigned char *)s; +if (dest > src) + { + dest += n; + src += n; + for (i = 0; i < n; ++i) *(--dest) = *(--src); + return (void *)dest; + } +else + { + for (i = 0; i < n; ++i) *dest++ = *src++; + return (void *)(dest - n); + } +#endif /* not HAVE_BCOPY */ +} +#undef memmove +#define memmove(d,s,n) emulated_memmove(d,s,n) +#endif /* not VPCOMPAT && not HAVE_MEMMOVE */ + + +/************************************************* +* Case-independent string compare * +*************************************************/ + +static int +strcmpic(const char *str1, const char *str2) +{ +unsigned int c1, c2; +while (*str1 != '\0' || *str2 != '\0') + { + c1 = tolower(*str1++); + c2 = tolower(*str2++); + if (c1 != c2) return ((c1 > c2) << 1) - 1; + } +return 0; +} + + +/************************************************* +* Parse GREP_COLORS * +*************************************************/ + +/* Extract ms or mt from GREP_COLORS. + +Argument: the string, possibly NULL +Returns: the value of ms or mt, or NULL if neither present +*/ + +static char * +parse_grep_colors(const char *gc) +{ +static char seq[16]; +char *col; +uint32_t len; +if (gc == NULL) return NULL; +col = strstr(gc, "ms="); +if (col == NULL) col = strstr(gc, "mt="); +if (col == NULL) return NULL; +len = 0; +col += 3; +while (*col != ':' && *col != 0 && len < sizeof(seq)-1) + seq[len++] = *col++; +seq[len] = 0; +return seq; +} + + +/************************************************* +* Exit from the program * +*************************************************/ + +/* If there has been a resource error, give a suitable message. + +Argument: the return code +Returns: does not return +*/ + +static void +pcre2grep_exit(int rc) +{ +/* VMS does exit codes differently: both exit(1) and exit(0) return with a +status of 1, which is not helpful. To help with this problem, define a symbol +(akin to an environment variable) called "PCRE2GREP_RC" and put the exit code +therein. */ + +#ifdef __VMS +#include descrip +#include lib$routines + char val_buf[4]; + $DESCRIPTOR(sym_nam, "PCRE2GREP_RC"); + $DESCRIPTOR(sym_val, val_buf); + sprintf(val_buf, "%d", rc); + sym_val.dsc$w_length = strlen(val_buf); + lib$set_symbol(&sym_nam, &sym_val); +#endif + +if (resource_error) + { + fprintf(stderr, "pcre2grep: Error %d, %d, %d or %d means that a resource " + "limit was exceeded.\n", PCRE2_ERROR_JIT_STACKLIMIT, PCRE2_ERROR_MATCHLIMIT, + PCRE2_ERROR_DEPTHLIMIT, PCRE2_ERROR_HEAPLIMIT); + fprintf(stderr, "pcre2grep: Check your regex for nested unlimited loops.\n"); + } +exit(rc); +} + + +/************************************************* +* Add item to chain of patterns * +*************************************************/ + +/* Used to add an item onto a chain, or just return an unconnected item if the +"after" argument is NULL. + +Arguments: + s pattern string to add + patlen length of pattern + after if not NULL points to item to insert after + +Returns: new pattern block or NULL on error +*/ + +static patstr * +add_pattern(char *s, PCRE2_SIZE patlen, patstr *after) +{ +patstr *p = (patstr *)malloc(sizeof(patstr)); +if (p == NULL) + { + fprintf(stderr, "pcre2grep: malloc failed\n"); + pcre2grep_exit(2); + } +if (patlen > MAXPATLEN) + { + fprintf(stderr, "pcre2grep: pattern is too long (limit is %d bytes)\n", + MAXPATLEN); + free(p); + return NULL; + } +p->next = NULL; +p->string = s; +p->length = patlen; +p->compiled = NULL; + +if (after != NULL) + { + p->next = after->next; + after->next = p; + } +return p; +} + + +/************************************************* +* Free chain of patterns * +*************************************************/ + +/* Used for several chains of patterns. + +Argument: pointer to start of chain +Returns: nothing +*/ + +static void +free_pattern_chain(patstr *pc) +{ +while (pc != NULL) + { + patstr *p = pc; + pc = p->next; + if (p->compiled != NULL) pcre2_code_free(p->compiled); + free(p); + } +} + + +/************************************************* +* Free chain of file names * +*************************************************/ + +/* +Argument: pointer to start of chain +Returns: nothing +*/ + +static void +free_file_chain(fnstr *fn) +{ +while (fn != NULL) + { + fnstr *f = fn; + fn = f->next; + free(f); + } +} + + +/************************************************* +* OS-specific functions * +*************************************************/ + +/* These definitions are needed in all Windows environments, even those where +Unix-style directory scanning can be used (see below). */ + +#ifdef WIN32 + +#ifndef STRICT +# define STRICT +#endif +#ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +#endif + +#include + +#define iswild(name) (strpbrk(name, "*?") != NULL) + +/* Convert ANSI BGR format to RGB used by Windows */ +#define BGR_RGB(x) ((x & 1 ? 4 : 0) | (x & 2) | (x & 4 ? 1 : 0)) + +static HANDLE hstdout; +static CONSOLE_SCREEN_BUFFER_INFO csbi; +static WORD match_colour; + +static WORD +decode_ANSI_colour(const char *cs) +{ +WORD result = csbi.wAttributes; +while (*cs) + { + if (isdigit(*cs)) + { + int code = atoi(cs); + if (code == 1) result |= 0x08; + else if (code == 4) result |= 0x8000; + else if (code == 5) result |= 0x80; + else if (code >= 30 && code <= 37) result = (result & 0xF8) | BGR_RGB(code - 30); + else if (code == 39) result = (result & 0xF0) | (csbi.wAttributes & 0x0F); + else if (code >= 40 && code <= 47) result = (result & 0x8F) | (BGR_RGB(code - 40) << 4); + else if (code == 49) result = (result & 0x0F) | (csbi.wAttributes & 0xF0); + /* aixterm high intensity colour codes */ + else if (code >= 90 && code <= 97) result = (result & 0xF0) | BGR_RGB(code - 90) | 0x08; + else if (code >= 100 && code <= 107) result = (result & 0x0F) | (BGR_RGB(code - 100) << 4) | 0x80; + + while (isdigit(*cs)) cs++; + } + if (*cs) cs++; + } +return result; +} + + +static void +init_colour_output() +{ +if (do_colour) + { + hstdout = GetStdHandle(STD_OUTPUT_HANDLE); + /* This fails when redirected to con; try again if so. */ + if (!GetConsoleScreenBufferInfo(hstdout, &csbi) && !do_ansi) + { + HANDLE hcon = CreateFile("CONOUT$", GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); + GetConsoleScreenBufferInfo(hcon, &csbi); + CloseHandle(hcon); + } + match_colour = decode_ANSI_colour(colour_string); + /* No valid colour found - turn off colouring */ + if (!match_colour) do_colour = FALSE; + } +} + +#endif /* WIN32 */ + + +/* The following sets of functions are defined so that they can be made system +specific. At present there are versions for Unix-style environments, Windows, +native z/OS, and "no support". */ + + +/************* Directory scanning Unix-style and z/OS ***********/ + +#if (defined HAVE_SYS_STAT_H && defined HAVE_DIRENT_H && defined HAVE_SYS_TYPES_H) || defined NATIVE_ZOS +#include +#include +#include + +#if defined NATIVE_ZOS +/************* Directory and PDS/E scanning for z/OS ***********/ +/************* z/OS looks mostly like Unix with USS ************/ +/* However, z/OS needs the #include statements in this header */ +#include "pcrzosfs.h" +/* That header is not included in the main PCRE distribution because + other apparatus is needed to compile pcre2grep for z/OS. The header + can be found in the special z/OS distribution, which is available + from www.zaconsultants.net or from www.cbttape.org. */ +#endif + +typedef DIR directory_type; +#define FILESEP '/' + +static int +isdirectory(char *filename) +{ +struct stat statbuf; +if (stat(filename, &statbuf) < 0) + return 0; /* In the expectation that opening as a file will fail */ +return S_ISDIR(statbuf.st_mode); +} + +static directory_type * +opendirectory(char *filename) +{ +return opendir(filename); +} + +static char * +readdirectory(directory_type *dir) +{ +for (;;) + { + struct dirent *dent = readdir(dir); + if (dent == NULL) return NULL; + if (strcmp(dent->d_name, ".") != 0 && strcmp(dent->d_name, "..") != 0) + return dent->d_name; + } +/* Control never reaches here */ +} + +static void +closedirectory(directory_type *dir) +{ +closedir(dir); +} + + +/************* Test for regular file, Unix-style **********/ + +static int +isregfile(char *filename) +{ +struct stat statbuf; +if (stat(filename, &statbuf) < 0) + return 1; /* In the expectation that opening as a file will fail */ +return S_ISREG(statbuf.st_mode); +} + + +#if defined NATIVE_ZOS +/************* Test for a terminal in z/OS **********/ +/* isatty() does not work in a TSO environment, so always give FALSE.*/ + +static BOOL +is_stdout_tty(void) +{ +return FALSE; +} + +static BOOL +is_file_tty(FILE *f) +{ +return FALSE; +} + + +/************* Test for a terminal, Unix-style **********/ + +#else +static BOOL +is_stdout_tty(void) +{ +return isatty(fileno(stdout)); +} + +static BOOL +is_file_tty(FILE *f) +{ +return isatty(fileno(f)); +} +#endif + + +/************* Print optionally coloured match Unix-style and z/OS **********/ + +static void +print_match(const void *buf, int length) +{ +if (length == 0) return; +if (do_colour) fprintf(stdout, "%c[%sm", 0x1b, colour_string); +FWRITE_IGNORE(buf, 1, length, stdout); +if (do_colour) fprintf(stdout, "%c[0m", 0x1b); +} + +/* End of Unix-style or native z/OS environment functions. */ + + +/************* Directory scanning in Windows ***********/ + +/* I (Philip Hazel) have no means of testing this code. It was contributed by +Lionel Fourquaux. David Burgess added a patch to define INVALID_FILE_ATTRIBUTES +when it did not exist. David Byron added a patch that moved the #include of + to before the INVALID_FILE_ATTRIBUTES definition rather than after. +*/ + +#elif defined WIN32 + +#ifndef INVALID_FILE_ATTRIBUTES +#define INVALID_FILE_ATTRIBUTES 0xFFFFFFFF +#endif + +typedef struct directory_type +{ +HANDLE handle; +BOOL first; +WIN32_FIND_DATA data; +} directory_type; + +#define FILESEP '/' + +int +isdirectory(char *filename) +{ +DWORD attr = GetFileAttributes(filename); +if (attr == INVALID_FILE_ATTRIBUTES) + return 0; +return (attr & FILE_ATTRIBUTE_DIRECTORY) != 0; +} + +directory_type * +opendirectory(char *filename) +{ +size_t len; +char *pattern; +directory_type *dir; +DWORD err; +len = strlen(filename); +pattern = (char *)malloc(len + 3); +dir = (directory_type *)malloc(sizeof(*dir)); +if ((pattern == NULL) || (dir == NULL)) + { + fprintf(stderr, "pcre2grep: malloc failed\n"); + pcre2grep_exit(2); + } +memcpy(pattern, filename, len); +if (iswild(filename)) + pattern[len] = 0; +else + memcpy(&(pattern[len]), "\\*", 3); +dir->handle = FindFirstFile(pattern, &(dir->data)); +if (dir->handle != INVALID_HANDLE_VALUE) + { + free(pattern); + dir->first = TRUE; + return dir; + } +err = GetLastError(); +free(pattern); +free(dir); +errno = (err == ERROR_ACCESS_DENIED) ? EACCES : ENOENT; +return NULL; +} + +char * +readdirectory(directory_type *dir) +{ +for (;;) + { + if (!dir->first) + { + if (!FindNextFile(dir->handle, &(dir->data))) + return NULL; + } + else + { + dir->first = FALSE; + } + if (strcmp(dir->data.cFileName, ".") != 0 && strcmp(dir->data.cFileName, "..") != 0) + return dir->data.cFileName; + } +#ifndef _MSC_VER +return NULL; /* Keep compiler happy; never executed */ +#endif +} + +void +closedirectory(directory_type *dir) +{ +FindClose(dir->handle); +free(dir); +} + + +/************* Test for regular file in Windows **********/ + +/* I don't know how to do this, or if it can be done; assume all paths are +regular if they are not directories. */ + +int isregfile(char *filename) +{ +return !isdirectory(filename); +} + + +/************* Test for a terminal in Windows **********/ + +static BOOL +is_stdout_tty(void) +{ +return _isatty(_fileno(stdout)); +} + +static BOOL +is_file_tty(FILE *f) +{ +return _isatty(_fileno(f)); +} + + +/************* Print optionally coloured match in Windows **********/ + +static void +print_match(const void *buf, int length) +{ +if (length == 0) return; +if (do_colour) + { + if (do_ansi) fprintf(stdout, "%c[%sm", 0x1b, colour_string); + else SetConsoleTextAttribute(hstdout, match_colour); + } +FWRITE_IGNORE(buf, 1, length, stdout); +if (do_colour) + { + if (do_ansi) fprintf(stdout, "%c[0m", 0x1b); + else SetConsoleTextAttribute(hstdout, csbi.wAttributes); + } +} + +/* End of Windows functions */ + + +/************* Directory scanning when we can't do it ***********/ + +/* The type is void, and apart from isdirectory(), the functions do nothing. */ + +#else + +#define FILESEP 0 +typedef void directory_type; + +int isdirectory(char *filename) { return 0; } +directory_type * opendirectory(char *filename) { return (directory_type*)0;} +char *readdirectory(directory_type *dir) { return (char*)0;} +void closedirectory(directory_type *dir) {} + + +/************* Test for regular file when we can't do it **********/ + +/* Assume all files are regular. */ + +int isregfile(char *filename) { return 1; } + + +/************* Test for a terminal when we can't do it **********/ + +static BOOL +is_stdout_tty(void) +{ +return FALSE; +} + +static BOOL +is_file_tty(FILE *f) +{ +return FALSE; +} + + +/************* Print optionally coloured match when we can't do it **********/ + +static void +print_match(const void *buf, int length) +{ +if (length == 0) return; +FWRITE_IGNORE(buf, 1, length, stdout); +} + +#endif /* End of system-specific functions */ + + + +#ifndef HAVE_STRERROR +/************************************************* +* Provide strerror() for non-ANSI libraries * +*************************************************/ + +/* Some old-fashioned systems still around (e.g. SunOS4) don't have strerror() +in their libraries, but can provide the same facility by this simple +alternative function. */ + +extern int sys_nerr; +extern char *sys_errlist[]; + +char * +strerror(int n) +{ +if (n < 0 || n >= sys_nerr) return "unknown error number"; +return sys_errlist[n]; +} +#endif /* HAVE_STRERROR */ + + + +/************************************************* +* Usage function * +*************************************************/ + +static int +usage(int rc) +{ +option_item *op; +fprintf(stderr, "Usage: pcre2grep [-"); +for (op = optionlist; op->one_char != 0; op++) + { + if (op->one_char > 0) fprintf(stderr, "%c", op->one_char); + } +fprintf(stderr, "] [long options] [pattern] [files]\n"); +fprintf(stderr, "Type \"pcre2grep --help\" for more information and the long " + "options.\n"); +return rc; +} + + + +/************************************************* +* Help function * +*************************************************/ + +static void +help(void) +{ +option_item *op; + +printf("Usage: pcre2grep [OPTION]... [PATTERN] [FILE1 FILE2 ...]" STDOUT_NL); +printf("Search for PATTERN in each FILE or standard input." STDOUT_NL); +printf("PATTERN must be present if neither -e nor -f is used." STDOUT_NL); + +#ifdef SUPPORT_PCRE2GREP_CALLOUT +printf("Callout scripts in patterns are supported." STDOUT_NL); +#else +printf("Callout scripts are not supported in this pcre2grep." STDOUT_NL); +#endif + +printf("\"-\" can be used as a file name to mean STDIN." STDOUT_NL); + +#ifdef SUPPORT_LIBZ +printf("Files whose names end in .gz are read using zlib." STDOUT_NL); +#endif + +#ifdef SUPPORT_LIBBZ2 +printf("Files whose names end in .bz2 are read using bzlib2." STDOUT_NL); +#endif + +#if defined SUPPORT_LIBZ || defined SUPPORT_LIBBZ2 +printf("Other files and the standard input are read as plain files." STDOUT_NL STDOUT_NL); +#else +printf("All files are read as plain files, without any interpretation." STDOUT_NL STDOUT_NL); +#endif + +printf("Example: pcre2grep -i " QUOT "hello.*world" QUOT " menu.h main.c" STDOUT_NL STDOUT_NL); +printf("Options:" STDOUT_NL); + +for (op = optionlist; op->one_char != 0; op++) + { + int n; + char s[4]; + + if (op->one_char > 0 && (op->long_name)[0] == 0) + n = 31 - printf(" -%c", op->one_char); + else + { + if (op->one_char > 0) sprintf(s, "-%c,", op->one_char); + else strcpy(s, " "); + n = 31 - printf(" %s --%s", s, op->long_name); + } + + if (n < 1) n = 1; + printf("%.*s%s" STDOUT_NL, n, " ", op->help_text); + } + +printf(STDOUT_NL "Numbers may be followed by K or M, e.g. --max-buffer-size=100K." STDOUT_NL); +printf("The default value for --buffer-size is %d." STDOUT_NL, PCRE2GREP_BUFSIZE); +printf("The default value for --max-buffer-size is %d." STDOUT_NL, PCRE2GREP_MAX_BUFSIZE); +printf("When reading patterns or file names from a file, trailing white" STDOUT_NL); +printf("space is removed and blank lines are ignored." STDOUT_NL); +printf("The maximum size of any pattern is %d bytes." STDOUT_NL, MAXPATLEN); + +printf(STDOUT_NL "With no FILEs, read standard input. If fewer than two FILEs given, assume -h." STDOUT_NL); +printf("Exit status is 0 if any matches, 1 if no matches, and 2 if trouble." STDOUT_NL); +} + + + +/************************************************* +* Test exclude/includes * +*************************************************/ + +/* If any exclude pattern matches, the path is excluded. Otherwise, unless +there are no includes, the path must match an include pattern. + +Arguments: + path the path to be matched + ip the chain of include patterns + ep the chain of exclude patterns + +Returns: TRUE if the path is not excluded +*/ + +static BOOL +test_incexc(char *path, patstr *ip, patstr *ep) +{ +int plen = strlen((const char *)path); + +for (; ep != NULL; ep = ep->next) + { + if (pcre2_match(ep->compiled, (PCRE2_SPTR)path, plen, 0, 0, match_data, NULL) >= 0) + return FALSE; + } + +if (ip == NULL) return TRUE; + +for (; ip != NULL; ip = ip->next) + { + if (pcre2_match(ip->compiled, (PCRE2_SPTR)path, plen, 0, 0, match_data, NULL) >= 0) + return TRUE; + } + +return FALSE; +} + + + +/************************************************* +* Decode integer argument value * +*************************************************/ + +/* Integer arguments can be followed by K or M. Avoid the use of strtoul() +because SunOS4 doesn't have it. This is used only for unpicking arguments, so +just keep it simple. + +Arguments: + option_data the option data string + op the option item (for error messages) + longop TRUE if option given in long form + +Returns: a long integer +*/ + +static long int +decode_number(char *option_data, option_item *op, BOOL longop) +{ +unsigned long int n = 0; +char *endptr = option_data; +while (*endptr != 0 && isspace((unsigned char)(*endptr))) endptr++; +while (isdigit((unsigned char)(*endptr))) + n = n * 10 + (int)(*endptr++ - '0'); +if (toupper(*endptr) == 'K') + { + n *= 1024; + endptr++; + } +else if (toupper(*endptr) == 'M') + { + n *= 1024*1024; + endptr++; + } + +if (*endptr != 0) /* Error */ + { + if (longop) + { + char *equals = strchr(op->long_name, '='); + int nlen = (equals == NULL)? (int)strlen(op->long_name) : + (int)(equals - op->long_name); + fprintf(stderr, "pcre2grep: Malformed number \"%s\" after --%.*s\n", + option_data, nlen, op->long_name); + } + else + fprintf(stderr, "pcre2grep: Malformed number \"%s\" after -%c\n", + option_data, op->one_char); + pcre2grep_exit(usage(2)); + } + +return n; +} + + + +/************************************************* +* Add item to a chain of numbers * +*************************************************/ + +/* Used to add an item onto a chain, or just return an unconnected item if the +"after" argument is NULL. + +Arguments: + n the number to add + after if not NULL points to item to insert after + +Returns: new number block +*/ + +static omstr * +add_number(int n, omstr *after) +{ +omstr *om = (omstr *)malloc(sizeof(omstr)); + +if (om == NULL) + { + fprintf(stderr, "pcre2grep: malloc failed\n"); + pcre2grep_exit(2); + } +om->next = NULL; +om->groupnum = n; + +if (after != NULL) + { + om->next = after->next; + after->next = om; + } +return om; +} + + + +/************************************************* +* Read one line of input * +*************************************************/ + +/* Normally, input that is to be scanned is read using fread() (or gzread, or +BZ2_read) into a large buffer, so many lines may be read at once. However, +doing this for tty input means that no output appears until a lot of input has +been typed. Instead, tty input is handled line by line. We cannot use fgets() +for this, because it does not stop at a binary zero, and therefore there is no +way of telling how many characters it has read, because there may be binary +zeros embedded in the data. This function is also used for reading patterns +from files (the -f option). + +Arguments: + buffer the buffer to read into + length the maximum number of characters to read + f the file + +Returns: the number of characters read, zero at end of file +*/ + +static PCRE2_SIZE +read_one_line(char *buffer, int length, FILE *f) +{ +int c; +int yield = 0; +while ((c = fgetc(f)) != EOF) + { + buffer[yield++] = c; + if (c == '\n' || yield >= length) break; + } +return yield; +} + + + +/************************************************* +* Find end of line * +*************************************************/ + +/* The length of the endline sequence that is found is set via lenptr. This may +be zero at the very end of the file if there is no line-ending sequence there. + +Arguments: + p current position in line + endptr end of available data + lenptr where to put the length of the eol sequence + +Returns: pointer after the last byte of the line, + including the newline byte(s) +*/ + +static char * +end_of_line(char *p, char *endptr, int *lenptr) +{ +switch(endlinetype) + { + default: /* Just in case */ + case PCRE2_NEWLINE_LF: + while (p < endptr && *p != '\n') p++; + if (p < endptr) + { + *lenptr = 1; + return p + 1; + } + *lenptr = 0; + return endptr; + + case PCRE2_NEWLINE_CR: + while (p < endptr && *p != '\r') p++; + if (p < endptr) + { + *lenptr = 1; + return p + 1; + } + *lenptr = 0; + return endptr; + + case PCRE2_NEWLINE_NUL: + while (p < endptr && *p != '\0') p++; + if (p < endptr) + { + *lenptr = 1; + return p + 1; + } + *lenptr = 0; + return endptr; + + case PCRE2_NEWLINE_CRLF: + for (;;) + { + while (p < endptr && *p != '\r') p++; + if (++p >= endptr) + { + *lenptr = 0; + return endptr; + } + if (*p == '\n') + { + *lenptr = 2; + return p + 1; + } + } + break; + + case PCRE2_NEWLINE_ANYCRLF: + while (p < endptr) + { + int extra = 0; + int c = *((unsigned char *)p); + + if (utf && c >= 0xc0) + { + int gcii, gcss; + extra = utf8_table4[c & 0x3f]; /* Number of additional bytes */ + gcss = 6*extra; + c = (c & utf8_table3[extra]) << gcss; + for (gcii = 1; gcii <= extra; gcii++) + { + gcss -= 6; + c |= (p[gcii] & 0x3f) << gcss; + } + } + + p += 1 + extra; + + switch (c) + { + case '\n': + *lenptr = 1; + return p; + + case '\r': + if (p < endptr && *p == '\n') + { + *lenptr = 2; + p++; + } + else *lenptr = 1; + return p; + + default: + break; + } + } /* End of loop for ANYCRLF case */ + + *lenptr = 0; /* Must have hit the end */ + return endptr; + + case PCRE2_NEWLINE_ANY: + while (p < endptr) + { + int extra = 0; + int c = *((unsigned char *)p); + + if (utf && c >= 0xc0) + { + int gcii, gcss; + extra = utf8_table4[c & 0x3f]; /* Number of additional bytes */ + gcss = 6*extra; + c = (c & utf8_table3[extra]) << gcss; + for (gcii = 1; gcii <= extra; gcii++) + { + gcss -= 6; + c |= (p[gcii] & 0x3f) << gcss; + } + } + + p += 1 + extra; + + switch (c) + { + case '\n': /* LF */ + case '\v': /* VT */ + case '\f': /* FF */ + *lenptr = 1; + return p; + + case '\r': /* CR */ + if (p < endptr && *p == '\n') + { + *lenptr = 2; + p++; + } + else *lenptr = 1; + return p; + +#ifndef EBCDIC + case 0x85: /* Unicode NEL */ + *lenptr = utf? 2 : 1; + return p; + + case 0x2028: /* Unicode LS */ + case 0x2029: /* Unicode PS */ + *lenptr = 3; + return p; +#endif /* Not EBCDIC */ + + default: + break; + } + } /* End of loop for ANY case */ + + *lenptr = 0; /* Must have hit the end */ + return endptr; + } /* End of overall switch */ +} + + + +/************************************************* +* Find start of previous line * +*************************************************/ + +/* This is called when looking back for before lines to print. + +Arguments: + p start of the subsequent line + startptr start of available data + +Returns: pointer to the start of the previous line +*/ + +static char * +previous_line(char *p, char *startptr) +{ +switch(endlinetype) + { + default: /* Just in case */ + case PCRE2_NEWLINE_LF: + p--; + while (p > startptr && p[-1] != '\n') p--; + return p; + + case PCRE2_NEWLINE_CR: + p--; + while (p > startptr && p[-1] != '\n') p--; + return p; + + case PCRE2_NEWLINE_NUL: + p--; + while (p > startptr && p[-1] != '\0') p--; + return p; + + case PCRE2_NEWLINE_CRLF: + for (;;) + { + p -= 2; + while (p > startptr && p[-1] != '\n') p--; + if (p <= startptr + 1 || p[-2] == '\r') return p; + } + /* Control can never get here */ + + case PCRE2_NEWLINE_ANY: + case PCRE2_NEWLINE_ANYCRLF: + if (*(--p) == '\n' && p > startptr && p[-1] == '\r') p--; + if (utf) while ((*p & 0xc0) == 0x80) p--; + + while (p > startptr) + { + unsigned int c; + char *pp = p - 1; + + if (utf) + { + int extra = 0; + while ((*pp & 0xc0) == 0x80) pp--; + c = *((unsigned char *)pp); + if (c >= 0xc0) + { + int gcii, gcss; + extra = utf8_table4[c & 0x3f]; /* Number of additional bytes */ + gcss = 6*extra; + c = (c & utf8_table3[extra]) << gcss; + for (gcii = 1; gcii <= extra; gcii++) + { + gcss -= 6; + c |= (pp[gcii] & 0x3f) << gcss; + } + } + } + else c = *((unsigned char *)pp); + + if (endlinetype == PCRE2_NEWLINE_ANYCRLF) switch (c) + { + case '\n': /* LF */ + case '\r': /* CR */ + return p; + + default: + break; + } + + else switch (c) + { + case '\n': /* LF */ + case '\v': /* VT */ + case '\f': /* FF */ + case '\r': /* CR */ +#ifndef EBCDIC + case 0x85: /* Unicode NEL */ + case 0x2028: /* Unicode LS */ + case 0x2029: /* Unicode PS */ +#endif /* Not EBCDIC */ + return p; + + default: + break; + } + + p = pp; /* Back one character */ + } /* End of loop for ANY case */ + + return startptr; /* Hit start of data */ + } /* End of overall switch */ +} + + + +/************************************************* +* Print the previous "after" lines * +*************************************************/ + +/* This is called if we are about to lose said lines because of buffer filling, +and at the end of the file. The data in the line is written using fwrite() so +that a binary zero does not terminate it. + +Arguments: + lastmatchnumber the number of the last matching line, plus one + lastmatchrestart where we restarted after the last match + endptr end of available data + printname filename for printing + +Returns: nothing +*/ + +static void +do_after_lines(unsigned long int lastmatchnumber, char *lastmatchrestart, + char *endptr, const char *printname) +{ +if (after_context > 0 && lastmatchnumber > 0) + { + int count = 0; + while (lastmatchrestart < endptr && count < after_context) + { + int ellength; + char *pp = end_of_line(lastmatchrestart, endptr, &ellength); + if (ellength == 0 && pp == main_buffer + bufsize) break; + if (printname != NULL) fprintf(stdout, "%s-", printname); + if (number) fprintf(stdout, "%lu-", lastmatchnumber++); + FWRITE_IGNORE(lastmatchrestart, 1, pp - lastmatchrestart, stdout); + lastmatchrestart = pp; + count++; + } + if (count > 0) hyphenpending = TRUE; + } +} + + + +/************************************************* +* Apply patterns to subject till one matches * +*************************************************/ + +/* This function is called to run through all patterns, looking for a match. It +is used multiple times for the same subject when colouring is enabled, in order +to find all possible matches. + +Arguments: + matchptr the start of the subject + length the length of the subject to match + options options for pcre_exec + startoffset where to start matching + mrc address of where to put the result of pcre2_match() + +Returns: TRUE if there was a match + FALSE if there was no match + invert if there was a non-fatal error +*/ + +static BOOL +match_patterns(char *matchptr, PCRE2_SIZE length, unsigned int options, + PCRE2_SIZE startoffset, int *mrc) +{ +int i; +PCRE2_SIZE slen = length; +patstr *p = patterns; +const char *msg = "this text:\n\n"; + +if (slen > 200) + { + slen = 200; + msg = "text that starts:\n\n"; + } +for (i = 1; p != NULL; p = p->next, i++) + { + *mrc = pcre2_match(p->compiled, (PCRE2_SPTR)matchptr, (int)length, + startoffset, options, match_data, match_context); + if (*mrc >= 0) return TRUE; + if (*mrc == PCRE2_ERROR_NOMATCH) continue; + fprintf(stderr, "pcre2grep: pcre2_match() gave error %d while matching ", *mrc); + if (patterns->next != NULL) fprintf(stderr, "pattern number %d to ", i); + fprintf(stderr, "%s", msg); + FWRITE_IGNORE(matchptr, 1, slen, stderr); /* In case binary zero included */ + fprintf(stderr, "\n\n"); + if (*mrc == PCRE2_ERROR_MATCHLIMIT || *mrc == PCRE2_ERROR_DEPTHLIMIT || + *mrc == PCRE2_ERROR_HEAPLIMIT || *mrc == PCRE2_ERROR_JIT_STACKLIMIT) + resource_error = TRUE; + if (error_count++ > 20) + { + fprintf(stderr, "pcre2grep: Too many errors - abandoned.\n"); + pcre2grep_exit(2); + } + return invert; /* No more matching; don't show the line again */ + } + +return FALSE; /* No match, no errors */ +} + + +/************************************************* +* Check output text for errors * +*************************************************/ + +static BOOL +syntax_check_output_text(PCRE2_SPTR string, BOOL callout) +{ +PCRE2_SPTR begin = string; +for (; *string != 0; string++) + { + if (*string == '$') + { + PCRE2_SIZE capture_id = 0; + BOOL brace = FALSE; + + string++; + + /* Syntax error: a character must be present after $. */ + if (*string == 0) + { + if (!callout) + fprintf(stderr, "pcre2grep: Error in output text at offset %d: %s\n", + (int)(string - begin), "no character after $"); + return FALSE; + } + + if (*string == '{') + { + /* Must be a decimal number in braces, e.g: {5} or {38} */ + string++; + + brace = TRUE; + } + + if ((*string >= '1' && *string <= '9') || (!callout && *string == '0')) + { + do + { + /* Maximum capture id is 65535. */ + if (capture_id <= 65535) + capture_id = capture_id * 10 + (*string - '0'); + + string++; + } + while (*string >= '0' && *string <= '9'); + + if (brace) + { + /* Syntax error: closing brace is missing. */ + if (*string != '}') + { + if (!callout) + fprintf(stderr, "pcre2grep: Error in output text at offset %d: %s\n", + (int)(string - begin), "missing closing brace"); + return FALSE; + } + } + else + { + /* To negate the effect of the for. */ + string--; + } + } + else if (brace) + { + /* Syntax error: a decimal number required. */ + if (!callout) + fprintf(stderr, "pcre2grep: Error in output text at offset %d: %s\n", + (int)(string - begin), "decimal number expected"); + return FALSE; + } + else if (*string == 'o') + { + string++; + + if (*string < '0' || *string > '7') + { + /* Syntax error: an octal number required. */ + if (!callout) + fprintf(stderr, "pcre2grep: Error in output text at offset %d: %s\n", + (int)(string - begin), "octal number expected"); + return FALSE; + } + } + else if (*string == 'x') + { + string++; + + if (!isxdigit((unsigned char)*string)) + { + /* Syntax error: a hexdecimal number required. */ + if (!callout) + fprintf(stderr, "pcre2grep: Error in output text at offset %d: %s\n", + (int)(string - begin), "hexadecimal number expected"); + return FALSE; + } + } + } + } + + return TRUE; +} + + +/************************************************* +* Display output text * +*************************************************/ + +/* Display the output text, which is assumed to have already been syntax +checked. Output may contain escape sequences started by the dollar sign. The +escape sequences are substituted as follows: + + $ or ${} is replaced by the captured substring of the given + decimal number; zero will substitute the whole match. If the number is + greater than the number of capturing substrings, or if the capture is unset, + the replacement is empty. + + $a is replaced by bell. + $b is replaced by backspace. + $e is replaced by escape. + $f is replaced by form feed. + $n is replaced by newline. + $r is replaced by carriage return. + $t is replaced by tab. + $v is replaced by vertical tab. + + $o is replaced by the character represented by the given octal + number; up to three digits are processed. + + $x is replaced by the character represented by the given hexadecimal + number; up to two digits are processed. + + Any other character is substituted by itself. E.g: $$ is replaced by a single + dollar. + +Arguments: + string: the output text + callout: TRUE for the builtin callout, FALSE for --output + subject the start of the subject + ovector: capture offsets + capture_top: number of captures + +Returns: TRUE if something was output, other than newline + FALSE if nothing was output, or newline was last output +*/ + +static BOOL +display_output_text(PCRE2_SPTR string, BOOL callout, PCRE2_SPTR subject, + PCRE2_SIZE *ovector, PCRE2_SIZE capture_top) +{ +BOOL printed = FALSE; + +for (; *string != 0; string++) + { + int ch = EOF; + if (*string == '$') + { + PCRE2_SIZE capture_id = 0; + BOOL brace = FALSE; + + string++; + + if (*string == '{') + { + /* Must be a decimal number in braces, e.g: {5} or {38} */ + string++; + + brace = TRUE; + } + + if ((*string >= '1' && *string <= '9') || (!callout && *string == '0')) + { + do + { + /* Maximum capture id is 65535. */ + if (capture_id <= 65535) + capture_id = capture_id * 10 + (*string - '0'); + + string++; + } + while (*string >= '0' && *string <= '9'); + + if (!brace) + { + /* To negate the effect of the for. */ + string--; + } + + if (capture_id < capture_top) + { + PCRE2_SIZE capturesize; + capture_id *= 2; + + capturesize = ovector[capture_id + 1] - ovector[capture_id]; + if (capturesize > 0) + { + print_match(subject + ovector[capture_id], capturesize); + printed = TRUE; + } + } + } + else if (*string == 'a') ch = '\a'; + else if (*string == 'b') ch = '\b'; +#ifndef EBCDIC + else if (*string == 'e') ch = '\033'; +#else + else if (*string == 'e') ch = '\047'; +#endif + else if (*string == 'f') ch = '\f'; + else if (*string == 'r') ch = '\r'; + else if (*string == 't') ch = '\t'; + else if (*string == 'v') ch = '\v'; + else if (*string == 'n') + { + fprintf(stdout, STDOUT_NL); + printed = FALSE; + } + else if (*string == 'o') + { + string++; + + ch = *string - '0'; + if (string[1] >= '0' && string[1] <= '7') + { + string++; + ch = ch * 8 + (*string - '0'); + } + if (string[1] >= '0' && string[1] <= '7') + { + string++; + ch = ch * 8 + (*string - '0'); + } + } + else if (*string == 'x') + { + string++; + + if (*string >= '0' && *string <= '9') + ch = *string - '0'; + else + ch = (*string | 0x20) - 'a' + 10; + if (isxdigit((unsigned char)string[1])) + { + string++; + ch *= 16; + if (*string >= '0' && *string <= '9') + ch += *string - '0'; + else + ch += (*string | 0x20) - 'a' + 10; + } + } + else + { + ch = *string; + } + } + else + { + ch = *string; + } + if (ch != EOF) + { + fprintf(stdout, "%c", ch); + printed = TRUE; + } + } + +return printed; +} + + +#ifdef SUPPORT_PCRE2GREP_CALLOUT + +/************************************************* +* Parse and execute callout scripts * +*************************************************/ + +/* This function parses a callout string block and executes the +program specified by the string. The string is a list of substrings +separated by pipe characters. The first substring represents the +executable name, and the following substrings specify the arguments: + + program_name|param1|param2|... + +Any substring (including the program name) can contain escape sequences +started by the dollar character. The escape sequences are substituted as +follows: + + $ or ${} is replaced by the captured substring of the given + decimal number, which must be greater than zero. If the number is greater + than the number of capturing substrings, or if the capture is unset, the + replacement is empty. + + Any other character is substituted by itself. E.g: $$ is replaced by a single + dollar or $| replaced by a pipe character. + +Alternatively, if string starts with pipe, the remainder is taken as an output +string, same as --output. In this case, --om-separator is used to separate each +callout, defaulting to newline. + +Example: + + echo -e "abcde\n12345" | pcre2grep \ + '(.)(..(.))(?C"/bin/echo|Arg1: [$1] [$2] [$3]|Arg2: $|${1}$| ($4)")()' - + + Output: + + Arg1: [a] [bcd] [d] Arg2: |a| () + abcde + Arg1: [1] [234] [4] Arg2: |1| () + 12345 + +Arguments: + blockptr the callout block + +Returns: currently it always returns with 0 +*/ + +static int +pcre2grep_callout(pcre2_callout_block *calloutptr, void *unused) +{ +PCRE2_SIZE length = calloutptr->callout_string_length; +PCRE2_SPTR string = calloutptr->callout_string; +PCRE2_SPTR subject = calloutptr->subject; +PCRE2_SIZE *ovector = calloutptr->offset_vector; +PCRE2_SIZE capture_top = calloutptr->capture_top; +PCRE2_SIZE argsvectorlen = 2; +PCRE2_SIZE argslen = 1; +char *args; +char *argsptr; +char **argsvector; +char **argsvectorptr; +#ifndef WIN32 +pid_t pid; +#endif +int result = 0; + +(void)unused; /* Avoid compiler warning */ + +/* Only callout with strings are supported. */ +if (string == NULL || length == 0) return 0; + +/* If there's no command, output the remainder directly. */ + +if (*string == '|') + { + string++; + if (!syntax_check_output_text(string, TRUE)) return 0; + (void)display_output_text(string, TRUE, subject, ovector, capture_top); + return 0; + } + +/* Checking syntax and compute the number of string fragments. Callout strings +are ignored in case of a syntax error. */ + +while (length > 0) + { + if (*string == '|') + { + argsvectorlen++; + + /* Maximum 10000 arguments allowed. */ + if (argsvectorlen > 10000) return 0; + } + else if (*string == '$') + { + PCRE2_SIZE capture_id = 0; + + string++; + length--; + + /* Syntax error: a character must be present after $. */ + if (length == 0) return 0; + + if (*string >= '1' && *string <= '9') + { + do + { + /* Maximum capture id is 65535. */ + if (capture_id <= 65535) + capture_id = capture_id * 10 + (*string - '0'); + + string++; + length--; + } + while (length > 0 && *string >= '0' && *string <= '9'); + + /* To negate the effect of string++ below. */ + string--; + length++; + } + else if (*string == '{') + { + /* Must be a decimal number in braces, e.g: {5} or {38} */ + string++; + length--; + + /* Syntax error: a decimal number required. */ + if (length == 0) return 0; + if (*string < '1' || *string > '9') return 0; + + do + { + /* Maximum capture id is 65535. */ + if (capture_id <= 65535) + capture_id = capture_id * 10 + (*string - '0'); + + string++; + length--; + + /* Syntax error: no more characters */ + if (length == 0) return 0; + } + while (*string >= '0' && *string <= '9'); + + /* Syntax error: closing brace is missing. */ + if (*string != '}') return 0; + } + + if (capture_id > 0) + { + if (capture_id < capture_top) + { + capture_id *= 2; + argslen += ovector[capture_id + 1] - ovector[capture_id]; + } + + /* To negate the effect of argslen++ below. */ + argslen--; + } + } + + string++; + length--; + argslen++; + } + +args = (char*)malloc(argslen); +if (args == NULL) return 0; + +argsvector = (char**)malloc(argsvectorlen * sizeof(char*)); +if (argsvector == NULL) + { + free(args); + return 0; + } + +argsptr = args; +argsvectorptr = argsvector; + +*argsvectorptr++ = argsptr; + +length = calloutptr->callout_string_length; +string = calloutptr->callout_string; + +while (length > 0) + { + if (*string == '|') + { + *argsptr++ = '\0'; + *argsvectorptr++ = argsptr; + } + else if (*string == '$') + { + string++; + length--; + + if ((*string >= '1' && *string <= '9') || *string == '{') + { + PCRE2_SIZE capture_id = 0; + + if (*string != '{') + { + do + { + /* Maximum capture id is 65535. */ + if (capture_id <= 65535) + capture_id = capture_id * 10 + (*string - '0'); + + string++; + length--; + } + while (length > 0 && *string >= '0' && *string <= '9'); + + /* To negate the effect of string++ below. */ + string--; + length++; + } + else + { + string++; + length--; + + do + { + /* Maximum capture id is 65535. */ + if (capture_id <= 65535) + capture_id = capture_id * 10 + (*string - '0'); + + string++; + length--; + } + while (*string != '}'); + } + + if (capture_id < capture_top) + { + PCRE2_SIZE capturesize; + capture_id *= 2; + + capturesize = ovector[capture_id + 1] - ovector[capture_id]; + memcpy(argsptr, subject + ovector[capture_id], capturesize); + argsptr += capturesize; + } + } + else + { + *argsptr++ = *string; + } + } + else + { + *argsptr++ = *string; + } + + string++; + length--; + } + +*argsptr++ = '\0'; +*argsvectorptr = NULL; + +#ifdef WIN32 +result = _spawnvp(_P_WAIT, argsvector[0], (const char * const *)argsvector); +#else +pid = fork(); + +if (pid == 0) + { + (void)execv(argsvector[0], argsvector); + /* Control gets here if there is an error, e.g. a non-existent program */ + exit(1); + } +else if (pid > 0) + (void)waitpid(pid, &result, 0); +#endif + +free(args); +free(argsvector); + +/* Currently negative return values are not supported, only zero (match +continues) or non-zero (match fails). */ + +return result != 0; +} + +#endif + + + +/************************************************* +* Read a portion of the file into buffer * +*************************************************/ + +static int +fill_buffer(void *handle, int frtype, char *buffer, int length, + BOOL input_line_buffered) +{ +(void)frtype; /* Avoid warning when not used */ + +#ifdef SUPPORT_LIBZ +if (frtype == FR_LIBZ) + return gzread((gzFile)handle, buffer, length); +else +#endif + +#ifdef SUPPORT_LIBBZ2 +if (frtype == FR_LIBBZ2) + return BZ2_bzread((BZFILE *)handle, buffer, length); +else +#endif + +return (input_line_buffered ? + read_one_line(buffer, length, (FILE *)handle) : + fread(buffer, 1, length, (FILE *)handle)); +} + + + +/************************************************* +* Grep an individual file * +*************************************************/ + +/* This is called from grep_or_recurse() below. It uses a buffer that is three +times the value of bufthird. The matching point is never allowed to stray into +the top third of the buffer, thus keeping more of the file available for +context printing or for multiline scanning. For large files, the pointer will +be in the middle third most of the time, so the bottom third is available for +"before" context printing. + +Arguments: + handle the fopened FILE stream for a normal file + the gzFile pointer when reading is via libz + the BZFILE pointer when reading is via libbz2 + frtype FR_PLAIN, FR_LIBZ, or FR_LIBBZ2 + filename the file name or NULL (for errors) + printname the file name if it is to be printed for each match + or NULL if the file name is not to be printed + it cannot be NULL if filenames[_nomatch]_only is set + +Returns: 0 if there was at least one match + 1 otherwise (no matches) + 2 if an overlong line is encountered + 3 if there is a read error on a .bz2 file +*/ + +static int +pcre2grep(void *handle, int frtype, const char *filename, const char *printname) +{ +int rc = 1; +int filepos = 0; +unsigned long int linenumber = 1; +unsigned long int lastmatchnumber = 0; +unsigned long int count = 0; +char *lastmatchrestart = main_buffer; +char *ptr = main_buffer; +char *endptr; +PCRE2_SIZE bufflength; +BOOL binary = FALSE; +BOOL endhyphenpending = FALSE; +BOOL input_line_buffered = line_buffered; +FILE *in = NULL; /* Ensure initialized */ + +/* Do the first read into the start of the buffer and set up the pointer to end +of what we have. In the case of libz, a non-zipped .gz file will be read as a +plain file. However, if a .bz2 file isn't actually bzipped, the first read will +fail. */ + +if (frtype != FR_LIBZ && frtype != FR_LIBBZ2) + { + in = (FILE *)handle; + if (is_file_tty(in)) input_line_buffered = TRUE; + } +else input_line_buffered = FALSE; + +bufflength = fill_buffer(handle, frtype, main_buffer, bufsize, + input_line_buffered); + +#ifdef SUPPORT_LIBBZ2 +if (frtype == FR_LIBBZ2 && (int)bufflength < 0) return 2; /* Gotcha: bufflength is PCRE2_SIZE; */ +#endif + +endptr = main_buffer + bufflength; + +/* Unless binary-files=text, see if we have a binary file. This uses the same +rule as GNU grep, namely, a search for a binary zero byte near the start of the +file. However, when the newline convention is binary zero, we can't do this. */ + +if (binary_files != BIN_TEXT) + { + if (endlinetype != PCRE2_NEWLINE_NUL) + binary = memchr(main_buffer, 0, (bufflength > 1024)? 1024 : bufflength) + != NULL; + if (binary && binary_files == BIN_NOMATCH) return 1; + } + +/* Loop while the current pointer is not at the end of the file. For large +files, endptr will be at the end of the buffer when we are in the middle of the +file, but ptr will never get there, because as soon as it gets over 2/3 of the +way, the buffer is shifted left and re-filled. */ + +while (ptr < endptr) + { + int endlinelength; + int mrc = 0; + unsigned int options = 0; + BOOL match; + char *t = ptr; + PCRE2_SIZE length, linelength; + PCRE2_SIZE startoffset = 0; + + /* At this point, ptr is at the start of a line. We need to find the length + of the subject string to pass to pcre2_match(). In multiline mode, it is the + length remainder of the data in the buffer. Otherwise, it is the length of + the next line, excluding the terminating newline. After matching, we always + advance by the length of the next line. In multiline mode the PCRE2_FIRSTLINE + option is used for compiling, so that any match is constrained to be in the + first line. */ + + t = end_of_line(t, endptr, &endlinelength); + linelength = t - ptr - endlinelength; + length = multiline? (PCRE2_SIZE)(endptr - ptr) : linelength; + + /* Check to see if the line we are looking at extends right to the very end + of the buffer without a line terminator. This means the line is too long to + handle at the current buffer size. Until the buffer reaches its maximum size, + try doubling it and reading more data. */ + + if (endlinelength == 0 && t == main_buffer + bufsize) + { + if (bufthird < max_bufthird) + { + char *new_buffer; + int new_bufthird = 2*bufthird; + + if (new_bufthird > max_bufthird) new_bufthird = max_bufthird; + new_buffer = (char *)malloc(3*new_bufthird); + + if (new_buffer == NULL) + { + fprintf(stderr, + "pcre2grep: line %lu%s%s is too long for the internal buffer\n" + "pcre2grep: not enough memory to increase the buffer size to %d\n", + linenumber, + (filename == NULL)? "" : " of file ", + (filename == NULL)? "" : filename, + new_bufthird); + return 2; + } + + /* Copy the data and adjust pointers to the new buffer location. */ + + memcpy(new_buffer, main_buffer, bufsize); + bufthird = new_bufthird; + bufsize = 3*bufthird; + ptr = new_buffer + (ptr - main_buffer); + lastmatchrestart = new_buffer + (lastmatchrestart - main_buffer); + free(main_buffer); + main_buffer = new_buffer; + + /* Read more data into the buffer and then try to find the line ending + again. */ + + bufflength += fill_buffer(handle, frtype, main_buffer + bufflength, + bufsize - bufflength, input_line_buffered); + endptr = main_buffer + bufflength; + continue; + } + else + { + fprintf(stderr, + "pcre2grep: line %lu%s%s is too long for the internal buffer\n" + "pcre2grep: the maximum buffer size is %d\n" + "pcre2grep: use the --max-buffer-size option to change it\n", + linenumber, + (filename == NULL)? "" : " of file ", + (filename == NULL)? "" : filename, + bufthird); + return 2; + } + } + + /* Extra processing for Jeffrey Friedl's debugging. */ + +#ifdef JFRIEDL_DEBUG + if (jfriedl_XT || jfriedl_XR) + { +# include +# include + struct timeval start_time, end_time; + struct timezone dummy; + int i; + + if (jfriedl_XT) + { + unsigned long newlen = length * jfriedl_XT + strlen(jfriedl_prefix) + strlen(jfriedl_postfix); + const char *orig = ptr; + ptr = malloc(newlen + 1); + if (!ptr) { + printf("out of memory"); + pcre2grep_exit(2); + } + endptr = ptr; + strcpy(endptr, jfriedl_prefix); endptr += strlen(jfriedl_prefix); + for (i = 0; i < jfriedl_XT; i++) { + strncpy(endptr, orig, length); + endptr += length; + } + strcpy(endptr, jfriedl_postfix); endptr += strlen(jfriedl_postfix); + length = newlen; + } + + if (gettimeofday(&start_time, &dummy) != 0) + perror("bad gettimeofday"); + + + for (i = 0; i < jfriedl_XR; i++) + match = (pcre_exec(patterns->compiled, patterns->hint, ptr, length, 0, + PCRE2_NOTEMPTY, offsets, OFFSET_SIZE) >= 0); + + if (gettimeofday(&end_time, &dummy) != 0) + perror("bad gettimeofday"); + + double delta = ((end_time.tv_sec + (end_time.tv_usec / 1000000.0)) + - + (start_time.tv_sec + (start_time.tv_usec / 1000000.0))); + + printf("%s TIMER[%.4f]\n", match ? "MATCH" : "FAIL", delta); + return 0; + } +#endif + + /* We come back here after a match when only_matching_count is non-zero, in + order to find any further matches in the same line. This applies to + --only-matching, --file-offsets, and --line-offsets. */ + + ONLY_MATCHING_RESTART: + + /* Run through all the patterns until one matches or there is an error other + than NOMATCH. This code is in a subroutine so that it can be re-used for + finding subsequent matches when colouring matched lines. After finding one + match, set PCRE2_NOTEMPTY to disable any further matches of null strings in + this line. */ + + match = match_patterns(ptr, length, options, startoffset, &mrc); + options = PCRE2_NOTEMPTY; + + /* If it's a match or a not-match (as required), do what's wanted. NOTE: Use + only FWRITE_IGNORE() - which is just a packaged fwrite() that ignores its + return code - to output data lines, so that binary zeroes are treated as just + another data character. */ + + if (match != invert) + { + BOOL hyphenprinted = FALSE; + + /* We've failed if we want a file that doesn't have any matches. */ + + if (filenames == FN_NOMATCH_ONLY) return 1; + + /* If all we want is a yes/no answer, we can return immediately. */ + + if (quiet) return 0; + + /* Just count if just counting is wanted. */ + + else if (count_only || show_total_count) count++; + + /* When handling a binary file and binary-files==binary, the "binary" + variable will be set true (it's false in all other cases). In this + situation we just want to output the file name. No need to scan further. */ + + else if (binary) + { + fprintf(stdout, "Binary file %s matches" STDOUT_NL, filename); + return 0; + } + + /* Likewise, if all we want is a file name, there is no need to scan any + more lines in the file. */ + + else if (filenames == FN_MATCH_ONLY) + { + fprintf(stdout, "%s" STDOUT_NL, printname); + return 0; + } + + /* The --only-matching option prints just the substring that matched, + and/or one or more captured portions of it, as long as these strings are + not empty. The --file-offsets and --line-offsets options output offsets for + the matching substring (all three set only_matching_count non-zero). None + of these mutually exclusive options prints any context. Afterwards, adjust + the start and then jump back to look for further matches in the same line. + If we are in invert mode, however, nothing is printed and we do not restart + - this could still be useful because the return code is set. */ + + else if (only_matching_count != 0) + { + if (!invert) + { + PCRE2_SIZE oldstartoffset; + + if (printname != NULL) fprintf(stdout, "%s:", printname); + if (number) fprintf(stdout, "%lu:", linenumber); + + /* Handle --line-offsets */ + + if (line_offsets) + fprintf(stdout, "%d,%d" STDOUT_NL, (int)(ptr + offsets[0] - ptr), + (int)(offsets[1] - offsets[0])); + + /* Handle --file-offsets */ + + else if (file_offsets) + fprintf(stdout, "%d,%d" STDOUT_NL, + (int)(filepos + ptr + offsets[0] - ptr), + (int)(offsets[1] - offsets[0])); + + /* Handle --output (which has already been syntax checked) */ + + else if (output_text != NULL) + { + if (display_output_text((PCRE2_SPTR)output_text, FALSE, + (PCRE2_SPTR)ptr, offsets, mrc) || printname != NULL || + number) + fprintf(stdout, STDOUT_NL); + } + + /* Handle --only-matching, which may occur many times */ + + else + { + BOOL printed = FALSE; + omstr *om; + + for (om = only_matching; om != NULL; om = om->next) + { + int n = om->groupnum; + if (n < mrc) + { + int plen = offsets[2*n + 1] - offsets[2*n]; + if (plen > 0) + { + if (printed && om_separator != NULL) + fprintf(stdout, "%s", om_separator); + print_match(ptr + offsets[n*2], plen); + printed = TRUE; + } + } + } + + if (printed || printname != NULL || number) + fprintf(stdout, STDOUT_NL); + } + + /* Prepare to repeat to find the next match in the line. */ + + match = FALSE; + if (line_buffered) fflush(stdout); + rc = 0; /* Had some success */ + + /* If the pattern contained a lookbehind that included \K, it is + possible that the end of the match might be at or before the actual + starting offset we have just used. In this case, start one character + further on. */ + + startoffset = offsets[1]; /* Restart after the match */ + oldstartoffset = pcre2_get_startchar(match_data); + if (startoffset <= oldstartoffset) + { + if (startoffset >= length) goto END_ONE_MATCH; /* Were at end */ + startoffset = oldstartoffset + 1; + if (utf) while ((ptr[startoffset] & 0xc0) == 0x80) startoffset++; + } + + /* If the current match ended past the end of the line (only possible + in multiline mode), we must move on to the line in which it did end + before searching for more matches. */ + + while (startoffset > linelength) + { + ptr += linelength + endlinelength; + filepos += (int)(linelength + endlinelength); + linenumber++; + startoffset -= (int)(linelength + endlinelength); + t = end_of_line(ptr, endptr, &endlinelength); + linelength = t - ptr - endlinelength; + length = (PCRE2_SIZE)(endptr - ptr); + } + + goto ONLY_MATCHING_RESTART; + } + } + + /* This is the default case when none of the above options is set. We print + the matching lines(s), possibly preceded and/or followed by other lines of + context. */ + + else + { + /* See if there is a requirement to print some "after" lines from a + previous match. We never print any overlaps. */ + + if (after_context > 0 && lastmatchnumber > 0) + { + int ellength; + int linecount = 0; + char *p = lastmatchrestart; + + while (p < ptr && linecount < after_context) + { + p = end_of_line(p, ptr, &ellength); + linecount++; + } + + /* It is important to advance lastmatchrestart during this printing so + that it interacts correctly with any "before" printing below. Print + each line's data using fwrite() in case there are binary zeroes. */ + + while (lastmatchrestart < p) + { + char *pp = lastmatchrestart; + if (printname != NULL) fprintf(stdout, "%s-", printname); + if (number) fprintf(stdout, "%lu-", lastmatchnumber++); + pp = end_of_line(pp, endptr, &ellength); + FWRITE_IGNORE(lastmatchrestart, 1, pp - lastmatchrestart, stdout); + lastmatchrestart = pp; + } + if (lastmatchrestart != ptr) hyphenpending = TRUE; + } + + /* If there were non-contiguous lines printed above, insert hyphens. */ + + if (hyphenpending) + { + fprintf(stdout, "--" STDOUT_NL); + hyphenpending = FALSE; + hyphenprinted = TRUE; + } + + /* See if there is a requirement to print some "before" lines for this + match. Again, don't print overlaps. */ + + if (before_context > 0) + { + int linecount = 0; + char *p = ptr; + + while (p > main_buffer && (lastmatchnumber == 0 || p > lastmatchrestart) && + linecount < before_context) + { + linecount++; + p = previous_line(p, main_buffer); + } + + if (lastmatchnumber > 0 && p > lastmatchrestart && !hyphenprinted) + fprintf(stdout, "--" STDOUT_NL); + + while (p < ptr) + { + int ellength; + char *pp = p; + if (printname != NULL) fprintf(stdout, "%s-", printname); + if (number) fprintf(stdout, "%lu-", linenumber - linecount--); + pp = end_of_line(pp, endptr, &ellength); + FWRITE_IGNORE(p, 1, pp - p, stdout); + p = pp; + } + } + + /* Now print the matching line(s); ensure we set hyphenpending at the end + of the file if any context lines are being output. */ + + if (after_context > 0 || before_context > 0) + endhyphenpending = TRUE; + + if (printname != NULL) fprintf(stdout, "%s:", printname); + if (number) fprintf(stdout, "%lu:", linenumber); + + /* This extra option, for Jeffrey Friedl's debugging requirements, + replaces the matched string, or a specific captured string if it exists, + with X. When this happens, colouring is ignored. */ + +#ifdef JFRIEDL_DEBUG + if (S_arg >= 0 && S_arg < mrc) + { + int first = S_arg * 2; + int last = first + 1; + FWRITE_IGNORE(ptr, 1, offsets[first], stdout); + fprintf(stdout, "X"); + FWRITE_IGNORE(ptr + offsets[last], 1, linelength - offsets[last], stdout); + } + else +#endif + + /* In multiline mode, or if colouring, we have to split the line(s) up + and search for further matches, but not of course if the line is a + non-match. In multiline mode this is necessary in case there is another + match that spans the end of the current line. When colouring we want to + colour all matches. */ + + if ((multiline || do_colour) && !invert) + { + int plength; + PCRE2_SIZE endprevious; + + /* The use of \K may make the end offset earlier than the start. In + this situation, swap them round. */ + + if (offsets[0] > offsets[1]) + { + PCRE2_SIZE temp = offsets[0]; + offsets[0] = offsets[1]; + offsets[1] = temp; + } + + FWRITE_IGNORE(ptr, 1, offsets[0], stdout); + print_match(ptr + offsets[0], offsets[1] - offsets[0]); + + for (;;) + { + PCRE2_SIZE oldstartoffset = pcre2_get_startchar(match_data); + + endprevious = offsets[1]; + startoffset = endprevious; /* Advance after previous match. */ + + /* If the pattern contained a lookbehind that included \K, it is + possible that the end of the match might be at or before the actual + starting offset we have just used. In this case, start one character + further on. */ + + if (startoffset <= oldstartoffset) + { + startoffset = oldstartoffset + 1; + if (utf) while ((ptr[startoffset] & 0xc0) == 0x80) startoffset++; + } + + /* If the current match ended past the end of the line (only possible + in multiline mode), we must move on to the line in which it did end + before searching for more matches. Because the PCRE2_FIRSTLINE option + is set, the start of the match will always be before the first + newline sequence. */ + + while (startoffset > linelength + endlinelength) + { + ptr += linelength + endlinelength; + filepos += (int)(linelength + endlinelength); + linenumber++; + startoffset -= (int)(linelength + endlinelength); + endprevious -= (int)(linelength + endlinelength); + t = end_of_line(ptr, endptr, &endlinelength); + linelength = t - ptr - endlinelength; + length = (PCRE2_SIZE)(endptr - ptr); + } + + /* If startoffset is at the exact end of the line it means this + complete line was the final part of the match, so there is nothing + more to do. */ + + if (startoffset == linelength + endlinelength) break; + + /* Otherwise, run a match from within the final line, and if found, + loop for any that may follow. */ + + if (!match_patterns(ptr, length, options, startoffset, &mrc)) break; + + /* The use of \K may make the end offset earlier than the start. In + this situation, swap them round. */ + + if (offsets[0] > offsets[1]) + { + PCRE2_SIZE temp = offsets[0]; + offsets[0] = offsets[1]; + offsets[1] = temp; + } + + FWRITE_IGNORE(ptr + endprevious, 1, offsets[0] - endprevious, stdout); + print_match(ptr + offsets[0], offsets[1] - offsets[0]); + } + + /* In multiline mode, we may have already printed the complete line + and its line-ending characters (if they matched the pattern), so there + may be no more to print. */ + + plength = (int)((linelength + endlinelength) - endprevious); + if (plength > 0) FWRITE_IGNORE(ptr + endprevious, 1, plength, stdout); + } + + /* Not colouring or multiline; no need to search for further matches. */ + + else FWRITE_IGNORE(ptr, 1, linelength + endlinelength, stdout); + } + + /* End of doing what has to be done for a match. If --line-buffered was + given, flush the output. */ + + if (line_buffered) fflush(stdout); + rc = 0; /* Had some success */ + + /* Remember where the last match happened for after_context. We remember + where we are about to restart, and that line's number. */ + + lastmatchrestart = ptr + linelength + endlinelength; + lastmatchnumber = linenumber + 1; + } + + /* For a match in multiline inverted mode (which of course did not cause + anything to be printed), we have to move on to the end of the match before + proceeding. */ + + if (multiline && invert && match) + { + int ellength; + char *endmatch = ptr + offsets[1]; + t = ptr; + while (t < endmatch) + { + t = end_of_line(t, endptr, &ellength); + if (t <= endmatch) linenumber++; else break; + } + endmatch = end_of_line(endmatch, endptr, &ellength); + linelength = endmatch - ptr - ellength; + } + + /* Advance to after the newline and increment the line number. The file + offset to the current line is maintained in filepos. */ + + END_ONE_MATCH: + ptr += linelength + endlinelength; + filepos += (int)(linelength + endlinelength); + linenumber++; + + /* If input is line buffered, and the buffer is not yet full, read another + line and add it into the buffer. */ + + if (input_line_buffered && bufflength < (PCRE2_SIZE)bufsize) + { + int add = read_one_line(ptr, bufsize - (int)(ptr - main_buffer), in); + bufflength += add; + endptr += add; + } + + /* If we haven't yet reached the end of the file (the buffer is full), and + the current point is in the top 1/3 of the buffer, slide the buffer down by + 1/3 and refill it. Before we do this, if some unprinted "after" lines are + about to be lost, print them. */ + + if (bufflength >= (PCRE2_SIZE)bufsize && ptr > main_buffer + 2*bufthird) + { + if (after_context > 0 && + lastmatchnumber > 0 && + lastmatchrestart < main_buffer + bufthird) + { + do_after_lines(lastmatchnumber, lastmatchrestart, endptr, printname); + lastmatchnumber = 0; /* Indicates no after lines pending */ + } + + /* Now do the shuffle */ + + (void)memmove(main_buffer, main_buffer + bufthird, 2*bufthird); + ptr -= bufthird; + + bufflength = 2*bufthird + fill_buffer(handle, frtype, + main_buffer + 2*bufthird, bufthird, input_line_buffered); + endptr = main_buffer + bufflength; + + /* Adjust any last match point */ + + if (lastmatchnumber > 0) lastmatchrestart -= bufthird; + } + } /* Loop through the whole file */ + +/* End of file; print final "after" lines if wanted; do_after_lines sets +hyphenpending if it prints something. */ + +if (only_matching_count == 0 && !(count_only|show_total_count)) + { + do_after_lines(lastmatchnumber, lastmatchrestart, endptr, printname); + hyphenpending |= endhyphenpending; + } + +/* Print the file name if we are looking for those without matches and there +were none. If we found a match, we won't have got this far. */ + +if (filenames == FN_NOMATCH_ONLY) + { + fprintf(stdout, "%s" STDOUT_NL, printname); + return 0; + } + +/* Print the match count if wanted */ + +if (count_only && !quiet) + { + if (count > 0 || !omit_zero_count) + { + if (printname != NULL && filenames != FN_NONE) + fprintf(stdout, "%s:", printname); + fprintf(stdout, "%lu" STDOUT_NL, count); + counts_printed++; + } + } + +total_count += count; /* Can be set without count_only */ +return rc; +} + + + +/************************************************* +* Grep a file or recurse into a directory * +*************************************************/ + +/* Given a path name, if it's a directory, scan all the files if we are +recursing; if it's a file, grep it. + +Arguments: + pathname the path to investigate + dir_recurse TRUE if recursing is wanted (-r or -drecurse) + only_one_at_top TRUE if the path is the only one at toplevel + +Returns: -1 the file/directory was skipped + 0 if there was at least one match + 1 if there were no matches + 2 there was some kind of error + +However, file opening failures are suppressed if "silent" is set. +*/ + +static int +grep_or_recurse(char *pathname, BOOL dir_recurse, BOOL only_one_at_top) +{ +int rc = 1; +int frtype; +void *handle; +char *lastcomp; +FILE *in = NULL; /* Ensure initialized */ + +#ifdef SUPPORT_LIBZ +gzFile ingz = NULL; +#endif + +#ifdef SUPPORT_LIBBZ2 +BZFILE *inbz2 = NULL; +#endif + +#if defined SUPPORT_LIBZ || defined SUPPORT_LIBBZ2 +int pathlen; +#endif + +#if defined NATIVE_ZOS +int zos_type; +FILE *zos_test_file; +#endif + +/* If the file name is "-" we scan stdin */ + +if (strcmp(pathname, "-") == 0) + { + return pcre2grep(stdin, FR_PLAIN, stdin_name, + (filenames > FN_DEFAULT || (filenames == FN_DEFAULT && !only_one_at_top))? + stdin_name : NULL); + } + +/* Inclusion and exclusion: --include-dir and --exclude-dir apply only to +directories, whereas --include and --exclude apply to everything else. The test +is against the final component of the path. */ + +lastcomp = strrchr(pathname, FILESEP); +lastcomp = (lastcomp == NULL)? pathname : lastcomp + 1; + +/* If the file is a directory, skip if not recursing or if explicitly excluded. +Otherwise, scan the directory and recurse for each path within it. The scanning +code is localized so it can be made system-specific. */ + + +/* For z/OS, determine the file type. */ + +#if defined NATIVE_ZOS +zos_test_file = fopen(pathname,"rb"); + +if (zos_test_file == NULL) + { + if (!silent) fprintf(stderr, "pcre2grep: failed to test next file %s\n", + pathname, strerror(errno)); + return -1; + } +zos_type = identifyzosfiletype (zos_test_file); +fclose (zos_test_file); + +/* Handle a PDS in separate code */ + +if (zos_type == __ZOS_PDS || zos_type == __ZOS_PDSE) + { + return travelonpdsdir (pathname, only_one_at_top); + } + +/* Deal with regular files in the normal way below. These types are: + zos_type == __ZOS_PDS_MEMBER + zos_type == __ZOS_PS + zos_type == __ZOS_VSAM_KSDS + zos_type == __ZOS_VSAM_ESDS + zos_type == __ZOS_VSAM_RRDS +*/ + +/* Handle a z/OS directory using common code. */ + +else if (zos_type == __ZOS_HFS) + { +#endif /* NATIVE_ZOS */ + + +/* Handle directories: common code for all OS */ + +if (isdirectory(pathname)) + { + if (dee_action == dee_SKIP || + !test_incexc(lastcomp, include_dir_patterns, exclude_dir_patterns)) + return -1; + + if (dee_action == dee_RECURSE) + { + char buffer[FNBUFSIZ]; + char *nextfile; + directory_type *dir = opendirectory(pathname); + + if (dir == NULL) + { + if (!silent) + fprintf(stderr, "pcre2grep: Failed to open directory %s: %s\n", pathname, + strerror(errno)); + return 2; + } + + while ((nextfile = readdirectory(dir)) != NULL) + { + int frc; + int fnlength = strlen(pathname) + strlen(nextfile) + 2; + if (fnlength > FNBUFSIZ) + { + fprintf(stderr, "pcre2grep: recursive filename is too long\n"); + rc = 2; + break; + } + sprintf(buffer, "%s%c%s", pathname, FILESEP, nextfile); + frc = grep_or_recurse(buffer, dir_recurse, FALSE); + if (frc > 1) rc = frc; + else if (frc == 0 && rc == 1) rc = 0; + } + + closedirectory(dir); + return rc; + } + } + +#ifdef WIN32 +if (iswild(pathname)) + { + char buffer[1024]; + char *nextfile; + char *name; + directory_type *dir = opendirectory(pathname); + + if (dir == NULL) + return 0; + + for (nextfile = name = pathname; *nextfile != 0; nextfile++) + if (*nextfile == '/' || *nextfile == '\\') + name = nextfile + 1; + *name = 0; + + while ((nextfile = readdirectory(dir)) != NULL) + { + int frc; + sprintf(buffer, "%.512s%.128s", pathname, nextfile); + frc = grep_or_recurse(buffer, dir_recurse, FALSE); + if (frc > 1) rc = frc; + else if (frc == 0 && rc == 1) rc = 0; + } + + closedirectory(dir); + return rc; + } +#endif + +#if defined NATIVE_ZOS + } +#endif + +/* If the file is not a directory, check for a regular file, and if it is not, +skip it if that's been requested. Otherwise, check for an explicit inclusion or +exclusion. */ + +else if ( +#if defined NATIVE_ZOS + (zos_type == __ZOS_NOFILE && DEE_action == DEE_SKIP) || +#else /* all other OS */ + (!isregfile(pathname) && DEE_action == DEE_SKIP) || +#endif + !test_incexc(lastcomp, include_patterns, exclude_patterns)) + return -1; /* File skipped */ + +/* Control reaches here if we have a regular file, or if we have a directory +and recursion or skipping was not requested, or if we have anything else and +skipping was not requested. The scan proceeds. If this is the first and only +argument at top level, we don't show the file name, unless we are only showing +the file name, or the filename was forced (-H). */ + +#if defined SUPPORT_LIBZ || defined SUPPORT_LIBBZ2 +pathlen = (int)(strlen(pathname)); +#endif + +/* Open using zlib if it is supported and the file name ends with .gz. */ + +#ifdef SUPPORT_LIBZ +if (pathlen > 3 && strcmp(pathname + pathlen - 3, ".gz") == 0) + { + ingz = gzopen(pathname, "rb"); + if (ingz == NULL) + { + if (!silent) + fprintf(stderr, "pcre2grep: Failed to open %s: %s\n", pathname, + strerror(errno)); + return 2; + } + handle = (void *)ingz; + frtype = FR_LIBZ; + } +else +#endif + +/* Otherwise open with bz2lib if it is supported and the name ends with .bz2. */ + +#ifdef SUPPORT_LIBBZ2 +if (pathlen > 4 && strcmp(pathname + pathlen - 4, ".bz2") == 0) + { + inbz2 = BZ2_bzopen(pathname, "rb"); + handle = (void *)inbz2; + frtype = FR_LIBBZ2; + } +else +#endif + +/* Otherwise use plain fopen(). The label is so that we can come back here if +an attempt to read a .bz2 file indicates that it really is a plain file. */ + +#ifdef SUPPORT_LIBBZ2 +PLAIN_FILE: +#endif + { + in = fopen(pathname, "rb"); + handle = (void *)in; + frtype = FR_PLAIN; + } + +/* All the opening methods return errno when they fail. */ + +if (handle == NULL) + { + if (!silent) + fprintf(stderr, "pcre2grep: Failed to open %s: %s\n", pathname, + strerror(errno)); + return 2; + } + +/* Now grep the file */ + +rc = pcre2grep(handle, frtype, pathname, (filenames > FN_DEFAULT || + (filenames == FN_DEFAULT && !only_one_at_top))? pathname : NULL); + +/* Close in an appropriate manner. */ + +#ifdef SUPPORT_LIBZ +if (frtype == FR_LIBZ) + gzclose(ingz); +else +#endif + +/* If it is a .bz2 file and the result is 3, it means that the first attempt to +read failed. If the error indicates that the file isn't in fact bzipped, try +again as a normal file. */ + +#ifdef SUPPORT_LIBBZ2 +if (frtype == FR_LIBBZ2) + { + if (rc == 3) + { + int errnum; + const char *err = BZ2_bzerror(inbz2, &errnum); + if (errnum == BZ_DATA_ERROR_MAGIC) + { + BZ2_bzclose(inbz2); + goto PLAIN_FILE; + } + else if (!silent) + fprintf(stderr, "pcre2grep: Failed to read %s using bzlib: %s\n", + pathname, err); + rc = 2; /* The normal "something went wrong" code */ + } + BZ2_bzclose(inbz2); + } +else +#endif + +/* Normal file close */ + +fclose(in); + +/* Pass back the yield from pcre2grep(). */ + +return rc; +} + + + +/************************************************* +* Handle a single-letter, no data option * +*************************************************/ + +static int +handle_option(int letter, int options) +{ +switch(letter) + { + case N_FOFFSETS: file_offsets = TRUE; break; + case N_HELP: help(); pcre2grep_exit(0); break; /* Stops compiler warning */ + case N_LBUFFER: line_buffered = TRUE; break; + case N_LOFFSETS: line_offsets = number = TRUE; break; + case N_NOJIT: use_jit = FALSE; break; + case 'a': binary_files = BIN_TEXT; break; + case 'c': count_only = TRUE; break; + case 'F': options |= PCRE2_LITERAL; break; + case 'H': filenames = FN_FORCE; break; + case 'I': binary_files = BIN_NOMATCH; break; + case 'h': filenames = FN_NONE; break; + case 'i': options |= PCRE2_CASELESS; break; + case 'l': omit_zero_count = TRUE; filenames = FN_MATCH_ONLY; break; + case 'L': filenames = FN_NOMATCH_ONLY; break; + case 'M': multiline = TRUE; options |= PCRE2_MULTILINE|PCRE2_FIRSTLINE; break; + case 'n': number = TRUE; break; + + case 'o': + only_matching_last = add_number(0, only_matching_last); + if (only_matching == NULL) only_matching = only_matching_last; + break; + + case 'q': quiet = TRUE; break; + case 'r': dee_action = dee_RECURSE; break; + case 's': silent = TRUE; break; + case 't': show_total_count = TRUE; break; + case 'u': options |= PCRE2_UTF; utf = TRUE; break; + case 'v': invert = TRUE; break; + case 'w': extra_options |= PCRE2_EXTRA_MATCH_WORD; break; + case 'x': extra_options |= PCRE2_EXTRA_MATCH_LINE; break; + + case 'V': + { + unsigned char buffer[128]; + (void)pcre2_config(PCRE2_CONFIG_VERSION, buffer); + fprintf(stdout, "pcre2grep version %s" STDOUT_NL, buffer); + } + pcre2grep_exit(0); + break; + + default: + fprintf(stderr, "pcre2grep: Unknown option -%c\n", letter); + pcre2grep_exit(usage(2)); + } + +return options; +} + + + +/************************************************* +* Construct printed ordinal * +*************************************************/ + +/* This turns a number into "1st", "3rd", etc. */ + +static char * +ordin(int n) +{ +static char buffer[14]; +char *p = buffer; +sprintf(p, "%d", n); +while (*p != 0) p++; +n %= 100; +if (n >= 11 && n <= 13) n = 0; +switch (n%10) + { + case 1: strcpy(p, "st"); break; + case 2: strcpy(p, "nd"); break; + case 3: strcpy(p, "rd"); break; + default: strcpy(p, "th"); break; + } +return buffer; +} + + + +/************************************************* +* Compile a single pattern * +*************************************************/ + +/* Do nothing if the pattern has already been compiled. This is the case for +include/exclude patterns read from a file. + +When the -F option has been used, each "pattern" may be a list of strings, +separated by line breaks. They will be matched literally. We split such a +string and compile the first substring, inserting an additional block into the +pattern chain. + +Arguments: + p points to the pattern block + options the PCRE options + fromfile TRUE if the pattern was read from a file + fromtext file name or identifying text (e.g. "include") + count 0 if this is the only command line pattern, or + number of the command line pattern, or + linenumber for a pattern from a file + +Returns: TRUE on success, FALSE after an error +*/ + +static BOOL +compile_pattern(patstr *p, int options, int fromfile, const char *fromtext, + int count) +{ +char *ps; +int errcode; +PCRE2_SIZE patlen, erroffset; +PCRE2_UCHAR errmessbuffer[ERRBUFSIZ]; + +if (p->compiled != NULL) return TRUE; +ps = p->string; +patlen = p->length; + +if ((options & PCRE2_LITERAL) != 0) + { + int ellength; + char *eop = ps + patlen; + char *pe = end_of_line(ps, eop, &ellength); + + if (ellength != 0) + { + patlen = pe - ps - ellength; + if (add_pattern(pe, p->length-patlen-ellength, p) == NULL) return FALSE; + } + } + +p->compiled = pcre2_compile((PCRE2_SPTR)ps, patlen, options, &errcode, + &erroffset, compile_context); + +/* Handle successful compile. Try JIT-compiling if supported and enabled. We +ignore any JIT compiler errors, relying falling back to interpreting if +anything goes wrong with JIT. */ + +if (p->compiled != NULL) + { +#ifdef SUPPORT_PCRE2GREP_JIT + if (use_jit) (void)pcre2_jit_compile(p->compiled, PCRE2_JIT_COMPLETE); +#endif + return TRUE; + } + +/* Handle compile errors */ + +if (erroffset > patlen) erroffset = patlen; +pcre2_get_error_message(errcode, errmessbuffer, sizeof(errmessbuffer)); + +if (fromfile) + { + fprintf(stderr, "pcre2grep: Error in regex in line %d of %s " + "at offset %d: %s\n", count, fromtext, (int)erroffset, errmessbuffer); + } +else + { + if (count == 0) + fprintf(stderr, "pcre2grep: Error in %s regex at offset %d: %s\n", + fromtext, (int)erroffset, errmessbuffer); + else + fprintf(stderr, "pcre2grep: Error in %s %s regex at offset %d: %s\n", + ordin(count), fromtext, (int)erroffset, errmessbuffer); + } + +return FALSE; +} + + + +/************************************************* +* Read and compile a file of patterns * +*************************************************/ + +/* This is used for --filelist, --include-from, and --exclude-from. + +Arguments: + name the name of the file; "-" is stdin + patptr pointer to the pattern chain anchor + patlastptr pointer to the last pattern pointer + +Returns: TRUE if all went well +*/ + +static BOOL +read_pattern_file(char *name, patstr **patptr, patstr **patlastptr) +{ +int linenumber = 0; +PCRE2_SIZE patlen; +FILE *f; +const char *filename; +char buffer[MAXPATLEN+20]; + +if (strcmp(name, "-") == 0) + { + f = stdin; + filename = stdin_name; + } +else + { + f = fopen(name, "r"); + if (f == NULL) + { + fprintf(stderr, "pcre2grep: Failed to open %s: %s\n", name, strerror(errno)); + return FALSE; + } + filename = name; + } + +while ((patlen = read_one_line(buffer, sizeof(buffer), f)) > 0) + { + while (patlen > 0 && isspace((unsigned char)(buffer[patlen-1]))) patlen--; + linenumber++; + if (patlen == 0) continue; /* Skip blank lines */ + + /* Note: this call to add_pattern() puts a pointer to the local variable + "buffer" into the pattern chain. However, that pointer is used only when + compiling the pattern, which happens immediately below, so we flatten it + afterwards, as a precaution against any later code trying to use it. */ + + *patlastptr = add_pattern(buffer, patlen, *patlastptr); + if (*patlastptr == NULL) + { + if (f != stdin) fclose(f); + return FALSE; + } + if (*patptr == NULL) *patptr = *patlastptr; + + /* This loop is needed because compiling a "pattern" when -F is set may add + on additional literal patterns if the original contains a newline. In the + common case, it never will, because read_one_line() stops at a newline. + However, the -N option can be used to give pcre2grep a different newline + setting. */ + + for(;;) + { + if (!compile_pattern(*patlastptr, pcre2_options, TRUE, filename, + linenumber)) + { + if (f != stdin) fclose(f); + return FALSE; + } + (*patlastptr)->string = NULL; /* Insurance */ + if ((*patlastptr)->next == NULL) break; + *patlastptr = (*patlastptr)->next; + } + } + +if (f != stdin) fclose(f); +return TRUE; +} + + + +/************************************************* +* Main program * +*************************************************/ + +/* Returns 0 if something matched, 1 if nothing matched, 2 after an error. */ + +int +main(int argc, char **argv) +{ +int i, j; +int rc = 1; +BOOL only_one_at_top; +patstr *cp; +fnstr *fn; +const char *locale_from = "--locale"; + +#ifdef SUPPORT_PCRE2GREP_JIT +pcre2_jit_stack *jit_stack = NULL; +#endif + +/* In Windows, stdout is set up as a text stream, which means that \n is +converted to \r\n. This causes output lines that are copied from the input to +change from ....\r\n to ....\r\r\n, which is not right. We therefore ensure +that stdout is a binary stream. Note that this means all other output to stdout +must use STDOUT_NL to terminate lines. */ + +#ifdef WIN32 +_setmode(_fileno(stdout), _O_BINARY); +#endif + +/* Set up a default compile and match contexts and a match data block. */ + +compile_context = pcre2_compile_context_create(NULL); +match_context = pcre2_match_context_create(NULL); +match_data = pcre2_match_data_create(OFFSET_SIZE, NULL); +offsets = pcre2_get_ovector_pointer(match_data); + +/* If string (script) callouts are supported, set up the callout processing +function. */ + +#ifdef SUPPORT_PCRE2GREP_CALLOUT +pcre2_set_callout(match_context, pcre2grep_callout, NULL); +#endif + +/* Process the options */ + +for (i = 1; i < argc; i++) + { + option_item *op = NULL; + char *option_data = (char *)""; /* default to keep compiler happy */ + BOOL longop; + BOOL longopwasequals = FALSE; + + if (argv[i][0] != '-') break; + + /* If we hit an argument that is just "-", it may be a reference to STDIN, + but only if we have previously had -e or -f to define the patterns. */ + + if (argv[i][1] == 0) + { + if (pattern_files != NULL || patterns != NULL) break; + else pcre2grep_exit(usage(2)); + } + + /* Handle a long name option, or -- to terminate the options */ + + if (argv[i][1] == '-') + { + char *arg = argv[i] + 2; + char *argequals = strchr(arg, '='); + + if (*arg == 0) /* -- terminates options */ + { + i++; + break; /* out of the options-handling loop */ + } + + longop = TRUE; + + /* Some long options have data that follows after =, for example file=name. + Some options have variations in the long name spelling: specifically, we + allow "regexp" because GNU grep allows it, though I personally go along + with Jeffrey Friedl and Larry Wall in preferring "regex" without the "p". + These options are entered in the table as "regex(p)". Options can be in + both these categories. */ + + for (op = optionlist; op->one_char != 0; op++) + { + char *opbra = strchr(op->long_name, '('); + char *equals = strchr(op->long_name, '='); + + /* Handle options with only one spelling of the name */ + + if (opbra == NULL) /* Does not contain '(' */ + { + if (equals == NULL) /* Not thing=data case */ + { + if (strcmp(arg, op->long_name) == 0) break; + } + else /* Special case xxx=data */ + { + int oplen = (int)(equals - op->long_name); + int arglen = (argequals == NULL)? + (int)strlen(arg) : (int)(argequals - arg); + if (oplen == arglen && strncmp(arg, op->long_name, oplen) == 0) + { + option_data = arg + arglen; + if (*option_data == '=') + { + option_data++; + longopwasequals = TRUE; + } + break; + } + } + } + + /* Handle options with an alternate spelling of the name */ + + else + { + char buff1[24]; + char buff2[24]; + int ret; + + int baselen = (int)(opbra - op->long_name); + int fulllen = (int)(strchr(op->long_name, ')') - op->long_name + 1); + int arglen = (argequals == NULL || equals == NULL)? + (int)strlen(arg) : (int)(argequals - arg); + + if ((ret = snprintf(buff1, sizeof(buff1), "%.*s", baselen, op->long_name), + ret < 0 || ret > (int)sizeof(buff1)) || + (ret = snprintf(buff2, sizeof(buff2), "%s%.*s", buff1, + fulllen - baselen - 2, opbra + 1), + ret < 0 || ret > (int)sizeof(buff2))) + { + fprintf(stderr, "pcre2grep: Buffer overflow when parsing %s option\n", + op->long_name); + pcre2grep_exit(2); + } + + if (strncmp(arg, buff1, arglen) == 0 || + strncmp(arg, buff2, arglen) == 0) + { + if (equals != NULL && argequals != NULL) + { + option_data = argequals; + if (*option_data == '=') + { + option_data++; + longopwasequals = TRUE; + } + } + break; + } + } + } + + if (op->one_char == 0) + { + fprintf(stderr, "pcre2grep: Unknown option %s\n", argv[i]); + pcre2grep_exit(usage(2)); + } + } + + /* Jeffrey Friedl's debugging harness uses these additional options which + are not in the right form for putting in the option table because they use + only one hyphen, yet are more than one character long. By putting them + separately here, they will not get displayed as part of the help() output, + but I don't think Jeffrey will care about that. */ + +#ifdef JFRIEDL_DEBUG + else if (strcmp(argv[i], "-pre") == 0) { + jfriedl_prefix = argv[++i]; + continue; + } else if (strcmp(argv[i], "-post") == 0) { + jfriedl_postfix = argv[++i]; + continue; + } else if (strcmp(argv[i], "-XT") == 0) { + sscanf(argv[++i], "%d", &jfriedl_XT); + continue; + } else if (strcmp(argv[i], "-XR") == 0) { + sscanf(argv[++i], "%d", &jfriedl_XR); + continue; + } +#endif + + + /* One-char options; many that have no data may be in a single argument; we + continue till we hit the last one or one that needs data. */ + + else + { + char *s = argv[i] + 1; + longop = FALSE; + + while (*s != 0) + { + for (op = optionlist; op->one_char != 0; op++) + { + if (*s == op->one_char) break; + } + if (op->one_char == 0) + { + fprintf(stderr, "pcre2grep: Unknown option letter '%c' in \"%s\"\n", + *s, argv[i]); + pcre2grep_exit(usage(2)); + } + + option_data = s+1; + + /* Break out if this is the last character in the string; it's handled + below like a single multi-char option. */ + + if (*option_data == 0) break; + + /* Check for a single-character option that has data: OP_OP_NUMBER(S) + are used for ones that either have a numerical number or defaults, i.e. + the data is optional. If a digit follows, there is data; if not, carry on + with other single-character options in the same string. */ + + if (op->type == OP_OP_NUMBER || op->type == OP_OP_NUMBERS) + { + if (isdigit((unsigned char)s[1])) break; + } + else /* Check for an option with data */ + { + if (op->type != OP_NODATA) break; + } + + /* Handle a single-character option with no data, then loop for the + next character in the string. */ + + pcre2_options = handle_option(*s++, pcre2_options); + } + } + + /* At this point we should have op pointing to a matched option. If the type + is NO_DATA, it means that there is no data, and the option might set + something in the PCRE options. */ + + if (op->type == OP_NODATA) + { + pcre2_options = handle_option(op->one_char, pcre2_options); + continue; + } + + /* If the option type is OP_OP_STRING or OP_OP_NUMBER(S), it's an option that + either has a value or defaults to something. It cannot have data in a + separate item. At the moment, the only such options are "colo(u)r", + "only-matching", and Jeffrey Friedl's special -S debugging option. */ + + if (*option_data == 0 && + (op->type == OP_OP_STRING || op->type == OP_OP_NUMBER || + op->type == OP_OP_NUMBERS)) + { + switch (op->one_char) + { + case N_COLOUR: + colour_option = "auto"; + break; + + case 'o': + only_matching_last = add_number(0, only_matching_last); + if (only_matching == NULL) only_matching = only_matching_last; + break; + +#ifdef JFRIEDL_DEBUG + case 'S': + S_arg = 0; + break; +#endif + } + continue; + } + + /* Otherwise, find the data string for the option. */ + + if (*option_data == 0) + { + if (i >= argc - 1 || longopwasequals) + { + fprintf(stderr, "pcre2grep: Data missing after %s\n", argv[i]); + pcre2grep_exit(usage(2)); + } + option_data = argv[++i]; + } + + /* If the option type is OP_OP_NUMBERS, the value is a number that is to be + added to a chain of numbers. */ + + if (op->type == OP_OP_NUMBERS) + { + unsigned long int n = decode_number(option_data, op, longop); + omdatastr *omd = (omdatastr *)op->dataptr; + *(omd->lastptr) = add_number((int)n, *(omd->lastptr)); + if (*(omd->anchor) == NULL) *(omd->anchor) = *(omd->lastptr); + } + + /* If the option type is OP_PATLIST, it's the -e option, or one of the + include/exclude options, which can be called multiple times to create lists + of patterns. */ + + else if (op->type == OP_PATLIST) + { + patdatastr *pd = (patdatastr *)op->dataptr; + *(pd->lastptr) = add_pattern(option_data, (PCRE2_SIZE)strlen(option_data), + *(pd->lastptr)); + if (*(pd->lastptr) == NULL) goto EXIT2; + if (*(pd->anchor) == NULL) *(pd->anchor) = *(pd->lastptr); + } + + /* If the option type is OP_FILELIST, it's one of the options that names a + file. */ + + else if (op->type == OP_FILELIST) + { + fndatastr *fd = (fndatastr *)op->dataptr; + fn = (fnstr *)malloc(sizeof(fnstr)); + if (fn == NULL) + { + fprintf(stderr, "pcre2grep: malloc failed\n"); + goto EXIT2; + } + fn->next = NULL; + fn->name = option_data; + if (*(fd->anchor) == NULL) + *(fd->anchor) = fn; + else + (*(fd->lastptr))->next = fn; + *(fd->lastptr) = fn; + } + + /* Handle OP_BINARY_FILES */ + + else if (op->type == OP_BINFILES) + { + if (strcmp(option_data, "binary") == 0) + binary_files = BIN_BINARY; + else if (strcmp(option_data, "without-match") == 0) + binary_files = BIN_NOMATCH; + else if (strcmp(option_data, "text") == 0) + binary_files = BIN_TEXT; + else + { + fprintf(stderr, "pcre2grep: unknown value \"%s\" for binary-files\n", + option_data); + pcre2grep_exit(usage(2)); + } + } + + /* Otherwise, deal with a single string or numeric data value. */ + + else if (op->type != OP_NUMBER && op->type != OP_U32NUMBER && + op->type != OP_OP_NUMBER && op->type != OP_SIZE) + { + *((char **)op->dataptr) = option_data; + } + else + { + unsigned long int n = decode_number(option_data, op, longop); + if (op->type == OP_U32NUMBER) *((uint32_t *)op->dataptr) = n; + else if (op->type == OP_SIZE) *((PCRE2_SIZE *)op->dataptr) = n; + else *((int *)op->dataptr) = n; + } + } + +/* Options have been decoded. If -C was used, its value is used as a default +for -A and -B. */ + +if (both_context > 0) + { + if (after_context == 0) after_context = both_context; + if (before_context == 0) before_context = both_context; + } + +/* Only one of --only-matching, --output, --file-offsets, or --line-offsets is +permitted. They display, each in their own way, only the data that has matched. +*/ + +only_matching_count = (only_matching != NULL) + (output_text != NULL) + + file_offsets + line_offsets; + +if (only_matching_count > 1) + { + fprintf(stderr, "pcre2grep: Cannot mix --only-matching, --output, " + "--file-offsets and/or --line-offsets\n"); + pcre2grep_exit(usage(2)); + } + +/* Check the text supplied to --output for errors. */ + +if (output_text != NULL && + !syntax_check_output_text((PCRE2_SPTR)output_text, FALSE)) + goto EXIT2; + +/* Put limits into the match data block. */ + +if (heap_limit != PCRE2_UNSET) pcre2_set_heap_limit(match_context, heap_limit); +if (match_limit > 0) pcre2_set_match_limit(match_context, match_limit); +if (depth_limit > 0) pcre2_set_depth_limit(match_context, depth_limit); + +/* If a locale has not been provided as an option, see if the LC_CTYPE or +LC_ALL environment variable is set, and if so, use it. */ + +if (locale == NULL) + { + locale = getenv("LC_ALL"); + locale_from = "LC_ALL"; + } + +if (locale == NULL) + { + locale = getenv("LC_CTYPE"); + locale_from = "LC_CTYPE"; + } + +/* If a locale is set, use it to generate the tables the PCRE needs. Passing +NULL to pcre2_maketables() means that malloc() is used to get the memory. */ + +if (locale != NULL) + { + if (setlocale(LC_CTYPE, locale) == NULL) + { + fprintf(stderr, "pcre2grep: Failed to set locale %s (obtained from %s)\n", + locale, locale_from); + goto EXIT2; + } + character_tables = pcre2_maketables(NULL); + pcre2_set_character_tables(compile_context, character_tables); + } + +/* Sort out colouring */ + +if (colour_option != NULL && strcmp(colour_option, "never") != 0) + { + if (strcmp(colour_option, "always") == 0) +#ifdef WIN32 + do_ansi = !is_stdout_tty(), +#endif + do_colour = TRUE; + else if (strcmp(colour_option, "auto") == 0) do_colour = is_stdout_tty(); + else + { + fprintf(stderr, "pcre2grep: Unknown colour setting \"%s\"\n", + colour_option); + goto EXIT2; + } + if (do_colour) + { + char *cs = getenv("PCRE2GREP_COLOUR"); + if (cs == NULL) cs = getenv("PCRE2GREP_COLOR"); + if (cs == NULL) cs = getenv("PCREGREP_COLOUR"); + if (cs == NULL) cs = getenv("PCREGREP_COLOR"); + if (cs == NULL) cs = parse_grep_colors(getenv("GREP_COLORS")); + if (cs == NULL) cs = getenv("GREP_COLOR"); + if (cs != NULL) + { + if (strspn(cs, ";0123456789") == strlen(cs)) colour_string = cs; + } +#ifdef WIN32 + init_colour_output(); +#endif + } + } + +/* Sort out a newline setting. */ + +if (newline_arg != NULL) + { + for (endlinetype = 1; endlinetype < (int)(sizeof(newlines)/sizeof(char *)); + endlinetype++) + { + if (strcmpic(newline_arg, newlines[endlinetype]) == 0) break; + } + if (endlinetype < (int)(sizeof(newlines)/sizeof(char *))) + pcre2_set_newline(compile_context, endlinetype); + else + { + fprintf(stderr, "pcre2grep: Invalid newline specifier \"%s\"\n", + newline_arg); + goto EXIT2; + } + } + +/* Find default newline convention */ + +else + { + (void)pcre2_config(PCRE2_CONFIG_NEWLINE, &endlinetype); + } + +/* Interpret the text values for -d and -D */ + +if (dee_option != NULL) + { + if (strcmp(dee_option, "read") == 0) dee_action = dee_READ; + else if (strcmp(dee_option, "recurse") == 0) dee_action = dee_RECURSE; + else if (strcmp(dee_option, "skip") == 0) dee_action = dee_SKIP; + else + { + fprintf(stderr, "pcre2grep: Invalid value \"%s\" for -d\n", dee_option); + goto EXIT2; + } + } + +if (DEE_option != NULL) + { + if (strcmp(DEE_option, "read") == 0) DEE_action = DEE_READ; + else if (strcmp(DEE_option, "skip") == 0) DEE_action = DEE_SKIP; + else + { + fprintf(stderr, "pcre2grep: Invalid value \"%s\" for -D\n", DEE_option); + goto EXIT2; + } + } + +/* Set the extra options */ + +(void)pcre2_set_compile_extra_options(compile_context, extra_options); + +/* Check the values for Jeffrey Friedl's debugging options. */ + +#ifdef JFRIEDL_DEBUG +if (S_arg > 9) + { + fprintf(stderr, "pcre2grep: bad value for -S option\n"); + return 2; + } +if (jfriedl_XT != 0 || jfriedl_XR != 0) + { + if (jfriedl_XT == 0) jfriedl_XT = 1; + if (jfriedl_XR == 0) jfriedl_XR = 1; + } +#endif + +/* If use_jit is set, check whether JIT is available. If not, do not try +to use JIT. */ + +if (use_jit) + { + uint32_t answer; + (void)pcre2_config(PCRE2_CONFIG_JIT, &answer); + if (!answer) use_jit = FALSE; + } + +/* Get memory for the main buffer. */ + +if (bufthird <= 0) + { + fprintf(stderr, "pcre2grep: --buffer-size must be greater than zero\n"); + goto EXIT2; + } + +bufsize = 3*bufthird; +main_buffer = (char *)malloc(bufsize); + +if (main_buffer == NULL) + { + fprintf(stderr, "pcre2grep: malloc failed\n"); + goto EXIT2; + } + +/* If no patterns were provided by -e, and there are no files provided by -f, +the first argument is the one and only pattern, and it must exist. */ + +if (patterns == NULL && pattern_files == NULL) + { + if (i >= argc) return usage(2); + patterns = patterns_last = add_pattern(argv[i], (PCRE2_SIZE)strlen(argv[i]), + NULL); + i++; + if (patterns == NULL) goto EXIT2; + } + +/* Compile the patterns that were provided on the command line, either by +multiple uses of -e or as a single unkeyed pattern. We cannot do this until +after all the command-line options are read so that we know which PCRE options +to use. When -F is used, compile_pattern() may add another block into the +chain, so we must not access the next pointer till after the compile. */ + +for (j = 1, cp = patterns; cp != NULL; j++, cp = cp->next) + { + if (!compile_pattern(cp, pcre2_options, FALSE, "command-line", + (j == 1 && patterns->next == NULL)? 0 : j)) + goto EXIT2; + } + +/* Read and compile the regular expressions that are provided in files. */ + +for (fn = pattern_files; fn != NULL; fn = fn->next) + { + if (!read_pattern_file(fn->name, &patterns, &patterns_last)) goto EXIT2; + } + +/* Unless JIT has been explicitly disabled, arrange a stack for it to use. */ + +#ifdef SUPPORT_PCRE2GREP_JIT +if (use_jit) + { + jit_stack = pcre2_jit_stack_create(32*1024, 1024*1024, NULL); + if (jit_stack != NULL ) + pcre2_jit_stack_assign(match_context, NULL, jit_stack); + } +#endif + +/* -F, -w, and -x do not apply to include or exclude patterns, so we must +adjust the options. */ + +pcre2_options &= ~PCRE2_LITERAL; +(void)pcre2_set_compile_extra_options(compile_context, 0); + +/* If there are include or exclude patterns read from the command line, compile +them. */ + +for (j = 0; j < 4; j++) + { + int k; + for (k = 1, cp = *(incexlist[j]); cp != NULL; k++, cp = cp->next) + { + if (!compile_pattern(cp, pcre2_options, FALSE, incexname[j], + (k == 1 && cp->next == NULL)? 0 : k)) + goto EXIT2; + } + } + +/* Read and compile include/exclude patterns from files. */ + +for (fn = include_from; fn != NULL; fn = fn->next) + { + if (!read_pattern_file(fn->name, &include_patterns, &include_patterns_last)) + goto EXIT2; + } + +for (fn = exclude_from; fn != NULL; fn = fn->next) + { + if (!read_pattern_file(fn->name, &exclude_patterns, &exclude_patterns_last)) + goto EXIT2; + } + +/* If there are no files that contain lists of files to search, and there are +no file arguments, search stdin, and then exit. */ + +if (file_lists == NULL && i >= argc) + { + rc = pcre2grep(stdin, FR_PLAIN, stdin_name, + (filenames > FN_DEFAULT)? stdin_name : NULL); + goto EXIT; + } + +/* If any files that contains a list of files to search have been specified, +read them line by line and search the given files. */ + +for (fn = file_lists; fn != NULL; fn = fn->next) + { + char buffer[FNBUFSIZ]; + FILE *fl; + if (strcmp(fn->name, "-") == 0) fl = stdin; else + { + fl = fopen(fn->name, "rb"); + if (fl == NULL) + { + fprintf(stderr, "pcre2grep: Failed to open %s: %s\n", fn->name, + strerror(errno)); + goto EXIT2; + } + } + while (fgets(buffer, sizeof(buffer), fl) != NULL) + { + int frc; + char *end = buffer + (int)strlen(buffer); + while (end > buffer && isspace(end[-1])) end--; + *end = 0; + if (*buffer != 0) + { + frc = grep_or_recurse(buffer, dee_action == dee_RECURSE, FALSE); + if (frc > 1) rc = frc; + else if (frc == 0 && rc == 1) rc = 0; + } + } + if (fl != stdin) fclose(fl); + } + +/* After handling file-list, work through remaining arguments. Pass in the fact +that there is only one argument at top level - this suppresses the file name if +the argument is not a directory and filenames are not otherwise forced. */ + +only_one_at_top = i == argc - 1 && file_lists == NULL; + +for (; i < argc; i++) + { + int frc = grep_or_recurse(argv[i], dee_action == dee_RECURSE, + only_one_at_top); + if (frc > 1) rc = frc; + else if (frc == 0 && rc == 1) rc = 0; + } + +#ifdef SUPPORT_PCRE2GREP_CALLOUT +/* If separating builtin echo callouts by implicit newline, add one more for +the final item. */ + +if (om_separator != NULL && strcmp(om_separator, STDOUT_NL) == 0) + fprintf(stdout, STDOUT_NL); +#endif + +/* Show the total number of matches if requested, but not if only one file's +count was printed. */ + +if (show_total_count && counts_printed != 1 && filenames != FN_NOMATCH_ONLY) + { + if (counts_printed != 0 && filenames >= FN_DEFAULT) + fprintf(stdout, "TOTAL:"); + fprintf(stdout, "%lu" STDOUT_NL, total_count); + } + +EXIT: +#ifdef SUPPORT_PCRE2GREP_JIT +if (jit_stack != NULL) pcre2_jit_stack_free(jit_stack); +#endif + +free(main_buffer); +free((void *)character_tables); + +pcre2_compile_context_free(compile_context); +pcre2_match_context_free(match_context); +pcre2_match_data_free(match_data); + +free_pattern_chain(patterns); +free_pattern_chain(include_patterns); +free_pattern_chain(include_dir_patterns); +free_pattern_chain(exclude_patterns); +free_pattern_chain(exclude_dir_patterns); + +free_file_chain(exclude_from); +free_file_chain(include_from); +free_file_chain(pattern_files); +free_file_chain(file_lists); + +while (only_matching != NULL) + { + omstr *this = only_matching; + only_matching = this->next; + free(this); + } + +pcre2grep_exit(rc); + +EXIT2: +rc = 2; +goto EXIT; +} + +/* End of pcre2grep */ diff --git a/ProcessHacker/pcre/pcre2posix.c b/ProcessHacker/pcre/pcre2posix.c index 6a860844649d..7b9f4774227e 100644 --- a/ProcessHacker/pcre/pcre2posix.c +++ b/ProcessHacker/pcre/pcre2posix.c @@ -7,7 +7,7 @@ and semantics are as close as possible to those of the Perl 5 language. Written by Philip Hazel Original API code Copyright (c) 1997-2012 University of Cambridge - New API code Copyright (c) 2016 University of Cambridge + New API code Copyright (c) 2016-2018 University of Cambridge ----------------------------------------------------------------------------- Redistribution and use in source and binary forms, with or without @@ -38,9 +38,6 @@ POSSIBILITY OF SUCH DAMAGE. ----------------------------------------------------------------------------- */ -// dmex: Disable warnings. -#pragma warning(push) -#pragma warning(disable : 4267) /* This module is a wrapper that provides a POSIX API to the underlying PCRE2 functions. */ @@ -96,7 +93,7 @@ information; I know nothing about MSVC myself). For example, something like void __cdecl function(....) -might be needed. In order so make this easy, all the exported functions have +might be needed. In order to make this easy, all the exported functions have PCRE2_CALL_CONVENTION just before their names. It is rarely needed; if not set, we ensure here that it has no effect. */ @@ -347,8 +344,10 @@ if (rc >= 0) if ((size_t)rc > nmatch) rc = (int)nmatch; for (i = 0; i < (size_t)rc; i++) { - pmatch[i].rm_so = ovector[i*2] + so; - pmatch[i].rm_eo = ovector[i*2+1] + so; + pmatch[i].rm_so = (ovector[i*2] == PCRE2_UNSET)? -1 : + (int)(ovector[i*2] + so); + pmatch[i].rm_eo = (ovector[i*2+1] == PCRE2_UNSET)? -1 : + (int)(ovector[i*2+1] + so); } for (; i < nmatch; i++) pmatch[i].rm_so = pmatch[i].rm_eo = -1; return 0; @@ -374,4 +373,3 @@ switch(rc) } /* End of pcre2posix.c */ -#pragma warning(pop) diff --git a/ProcessHacker/pcre/pcre2test.c b/ProcessHacker/pcre/pcre2test.c new file mode 100644 index 000000000000..8cfb8e919e1e --- /dev/null +++ b/ProcessHacker/pcre/pcre2test.c @@ -0,0 +1,8789 @@ +/************************************************* +* PCRE2 testing program * +*************************************************/ + +/* PCRE2 is a library of functions to support regular expressions whose syntax +and semantics are as close as possible to those of the Perl 5 language. In 2014 +the API was completely revised and '2' was added to the name, because the old +API, which had lasted for 16 years, could not accommodate new requirements. At +the same time, this testing program was re-designed because its original +hacked-up (non-) design had also run out of steam. + + Written by Philip Hazel + Original code Copyright (c) 1997-2012 University of Cambridge + Rewritten code Copyright (c) 2016-2018 University of Cambridge + +----------------------------------------------------------------------------- +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of the University of Cambridge nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +----------------------------------------------------------------------------- +*/ + + +/* This program supports testing of the 8-bit, 16-bit, and 32-bit PCRE2 +libraries in a single program, though its input and output are always 8-bit. +It is different from modules such as pcre2_compile.c in the library itself, +which are compiled separately for each code unit width. If two widths are +enabled, for example, pcre2_compile.c is compiled twice. In contrast, +pcre2test.c is compiled only once, and linked with all the enabled libraries. +Therefore, it must not make use of any of the macros from pcre2.h or +pcre2_internal.h that depend on PCRE2_CODE_UNIT_WIDTH. It does, however, make +use of SUPPORT_PCRE2_8, SUPPORT_PCRE2_16, and SUPPORT_PCRE2_32, to ensure that +it references only the enabled library functions. */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include +#include +#include + +#if defined NATIVE_ZOS +#include "pcrzoscs.h" +/* That header is not included in the main PCRE2 distribution because other +apparatus is needed to compile pcre2test for z/OS. The header can be found in +the special z/OS distribution, which is available from www.zaconsultants.net or +from www.cbttape.org. */ +#endif + +#ifdef HAVE_UNISTD_H +#include +#endif + +/* Debugging code enabler */ + +/* #define DEBUG_SHOW_MALLOC_ADDRESSES */ + +/* Both libreadline and libedit are optionally supported. The user-supplied +original patch uses readline/readline.h for libedit, but in at least one system +it is installed as editline/readline.h, so the configuration code now looks for +that first, falling back to readline/readline.h. */ + +#if defined(SUPPORT_LIBREADLINE) || defined(SUPPORT_LIBEDIT) +#if defined(SUPPORT_LIBREADLINE) +#include +#include +#else +#if defined(HAVE_EDITLINE_READLINE_H) +#include +#else +#include +#endif +#endif +#endif + +/* Put the test for interactive input into a macro so that it can be changed if +required for different environments. */ + +#define INTERACTIVE(f) isatty(fileno(f)) + + +/* ---------------------- System-specific definitions ---------------------- */ + +/* A number of things vary for Windows builds. Originally, pcretest opened its +input and output without "b"; then I was told that "b" was needed in some +environments, so it was added for release 5.0 to both the input and output. (It +makes no difference on Unix-like systems.) Later I was told that it is wrong +for the input on Windows. I've now abstracted the modes into macros that are +set here, to make it easier to fiddle with them, and removed "b" from the input +mode under Windows. The BINARY versions are used when saving/restoring compiled +patterns. */ + +#if defined(_WIN32) || defined(WIN32) +#include /* For _setmode() */ +#include /* For _O_BINARY */ +#define INPUT_MODE "r" +#define OUTPUT_MODE "wb" +#define BINARY_INPUT_MODE "rb" +#define BINARY_OUTPUT_MODE "wb" + +#ifndef isatty +#define isatty _isatty /* This is what Windows calls them, I'm told, */ +#endif /* though in some environments they seem to */ + /* be already defined, hence the #ifndefs. */ +#ifndef fileno +#define fileno _fileno +#endif + +/* A user sent this fix for Borland Builder 5 under Windows. */ + +#ifdef __BORLANDC__ +#define _setmode(handle, mode) setmode(handle, mode) +#endif + +/* Not Windows */ + +#else +#include /* These two includes are needed */ +#include /* for setrlimit(). */ +#if defined NATIVE_ZOS /* z/OS uses non-binary I/O */ +#define INPUT_MODE "r" +#define OUTPUT_MODE "w" +#define BINARY_INPUT_MODE "rb" +#define BINARY_OUTPUT_MODE "wb" +#else +#define INPUT_MODE "rb" +#define OUTPUT_MODE "wb" +#define BINARY_INPUT_MODE "rb" +#define BINARY_OUTPUT_MODE "wb" +#endif +#endif + +#ifdef __VMS +#include +void vms_setsymbol( char *, char *, int ); +#endif + +/* VC and older compilers don't support %td or %zu. */ + +#if defined(_MSC_VER) || !defined(__STDC_VERSION__) || __STDC_VERSION__ < 199901L +#define PTR_FORM "lu" +#define SIZ_FORM "lu" +#define SIZ_CAST (unsigned long int) +#else +#define PTR_FORM "td" +#define SIZ_FORM "zu" +#define SIZ_CAST +#endif + +/* ------------------End of system-specific definitions -------------------- */ + +/* Glueing macros that are used in several places below. */ + +#define glue(a,b) a##b +#define G(a,b) glue(a,b) + +/* Miscellaneous parameters and manifests */ + +#ifndef CLOCKS_PER_SEC +#ifdef CLK_TCK +#define CLOCKS_PER_SEC CLK_TCK +#else +#define CLOCKS_PER_SEC 100 +#endif +#endif + +#define CFORE_UNSET UINT32_MAX /* Unset value for startend/cfail/cerror fields */ +#define CONVERT_UNSET UINT32_MAX /* Unset value for convert_type field */ +#define DFA_WS_DIMENSION 1000 /* Size of DFA workspace */ +#define DEFAULT_OVECCOUNT 15 /* Default ovector count */ +#define JUNK_OFFSET 0xdeadbeef /* For initializing ovector */ +#define LOCALESIZE 32 /* Size of locale name */ +#define LOOPREPEAT 500000 /* Default loop count for timing */ +#define MALLOCLISTSIZE 20 /* For remembering mallocs */ +#define PARENS_NEST_DEFAULT 220 /* Default parentheses nest limit */ +#define PATSTACKSIZE 20 /* Pattern stack for save/restore testing */ +#define REPLACE_MODSIZE 100 /* Field for reading 8-bit replacement */ +#define VERSION_SIZE 64 /* Size of buffer for the version strings */ + +/* Make sure the buffer into which replacement strings are copied is big enough +to hold them as 32-bit code units. */ + +#define REPLACE_BUFFSIZE 1024 /* This is a byte value */ + +/* Execution modes */ + +#define PCRE8_MODE 8 +#define PCRE16_MODE 16 +#define PCRE32_MODE 32 + +/* Processing returns */ + +enum { PR_OK, PR_SKIP, PR_ABEND }; + +/* The macro PRINTABLE determines whether to print an output character as-is or +as a hex value when showing compiled patterns. is We use it in cases when the +locale has not been explicitly changed, so as to get consistent output from +systems that differ in their output from isprint() even in the "C" locale. */ + +#ifdef EBCDIC +#define PRINTABLE(c) ((c) >= 64 && (c) < 255) +#else +#define PRINTABLE(c) ((c) >= 32 && (c) < 127) +#endif + +#define PRINTOK(c) ((use_tables != NULL && c < 256)? isprint(c) : PRINTABLE(c)) + +/* We have to include some of the library source files because we need +to use some of the macros, internal structure definitions, and other internal +values - pcre2test has "inside information" compared to an application program +that strictly follows the PCRE2 API. + +Before including pcre2_internal.h we define PRIV so that it does not get +defined therein. This ensures that PRIV names in the included files do not +clash with those in the libraries. Also, although pcre2_internal.h does itself +include pcre2.h, we explicitly include it beforehand, along with pcre2posix.h, +so that the PCRE2_EXP_xxx macros get set appropriately for an application, not +for building the library. */ + +#define PRIV(name) name +#define PCRE2_CODE_UNIT_WIDTH 0 +#include "pcre2.h" +#include "pcre2posix.h" +#include "pcre2_internal.h" + +/* We need access to some of the data tables that PCRE2 uses. Defining +PCRE2_PCRETEST makes some minor changes in the files. The previous definition +of PRIV avoids name clashes. */ + +#define PCRE2_PCRE2TEST +#include "pcre2_tables.c" +#include "pcre2_ucd.c" + +/* 32-bit integer values in the input are read by strtoul() or strtol(). The +check needed for overflow depends on whether long ints are in fact longer than +ints. They are defined not to be shorter. */ + +#if ULONG_MAX > UINT32_MAX +#define U32OVERFLOW(x) (x > UINT32_MAX) +#else +#define U32OVERFLOW(x) (x == UINT32_MAX) +#endif + +#if LONG_MAX > INT32_MAX +#define S32OVERFLOW(x) (x > INT32_MAX || x < INT32_MIN) +#else +#define S32OVERFLOW(x) (x == INT32_MAX || x == INT32_MIN) +#endif + +/* When PCRE2_CODE_UNIT_WIDTH is zero, pcre2_internal.h does not include +pcre2_intmodedep.h, which is where mode-dependent macros and structures are +defined. We can now include it for each supported code unit width. Because +PCRE2_CODE_UNIT_WIDTH was defined as zero before including pcre2.h, it will +have left PCRE2_SUFFIX defined as a no-op. We must re-define it appropriately +while including these files, and then restore it to a no-op. Because LINK_SIZE +may be changed in 16-bit mode and forced to 1 in 32-bit mode, the order of +these inclusions should not be changed. */ + +#undef PCRE2_SUFFIX +#undef PCRE2_CODE_UNIT_WIDTH + +#ifdef SUPPORT_PCRE2_8 +#define PCRE2_CODE_UNIT_WIDTH 8 +#define PCRE2_SUFFIX(a) G(a,8) +#include "pcre2_intmodedep.h" +#include "pcre2_printint.c" +#undef PCRE2_CODE_UNIT_WIDTH +#undef PCRE2_SUFFIX +#endif /* SUPPORT_PCRE2_8 */ + +#ifdef SUPPORT_PCRE2_16 +#define PCRE2_CODE_UNIT_WIDTH 16 +#define PCRE2_SUFFIX(a) G(a,16) +#include "pcre2_intmodedep.h" +#include "pcre2_printint.c" +#undef PCRE2_CODE_UNIT_WIDTH +#undef PCRE2_SUFFIX +#endif /* SUPPORT_PCRE2_16 */ + +#ifdef SUPPORT_PCRE2_32 +#define PCRE2_CODE_UNIT_WIDTH 32 +#define PCRE2_SUFFIX(a) G(a,32) +#include "pcre2_intmodedep.h" +#include "pcre2_printint.c" +#undef PCRE2_CODE_UNIT_WIDTH +#undef PCRE2_SUFFIX +#endif /* SUPPORT_PCRE2_32 */ + +#define PCRE2_SUFFIX(a) a + +/* We need to be able to check input text for UTF-8 validity, whatever code +widths are actually available, because the input to pcre2test is always in +8-bit code units. So we include the UTF validity checking function for 8-bit +code units. */ + +extern int valid_utf(PCRE2_SPTR8, PCRE2_SIZE, PCRE2_SIZE *); + +#define PCRE2_CODE_UNIT_WIDTH 8 +#undef PCRE2_SPTR +#define PCRE2_SPTR PCRE2_SPTR8 +#include "pcre2_valid_utf.c" +#undef PCRE2_CODE_UNIT_WIDTH +#undef PCRE2_SPTR + +/* If we have 8-bit support, default to it; if there is also 16-or 32-bit +support, it can be selected by a command-line option. If there is no 8-bit +support, there must be 16-bit or 32-bit support, so default to one of them. The +config function, JIT stack, contexts, and version string are the same in all +modes, so use the form of the first that is available. */ + +#if defined SUPPORT_PCRE2_8 +#define DEFAULT_TEST_MODE PCRE8_MODE +#define VERSION_TYPE PCRE2_UCHAR8 +#define PCRE2_CONFIG pcre2_config_8 +#define PCRE2_JIT_STACK pcre2_jit_stack_8 +#define PCRE2_REAL_GENERAL_CONTEXT pcre2_real_general_context_8 +#define PCRE2_REAL_COMPILE_CONTEXT pcre2_real_compile_context_8 +#define PCRE2_REAL_CONVERT_CONTEXT pcre2_real_convert_context_8 +#define PCRE2_REAL_MATCH_CONTEXT pcre2_real_match_context_8 + +#elif defined SUPPORT_PCRE2_16 +#define DEFAULT_TEST_MODE PCRE16_MODE +#define VERSION_TYPE PCRE2_UCHAR16 +#define PCRE2_CONFIG pcre2_config_16 +#define PCRE2_JIT_STACK pcre2_jit_stack_16 +#define PCRE2_REAL_GENERAL_CONTEXT pcre2_real_general_context_16 +#define PCRE2_REAL_COMPILE_CONTEXT pcre2_real_compile_context_16 +#define PCRE2_REAL_CONVERT_CONTEXT pcre2_real_convert_context_16 +#define PCRE2_REAL_MATCH_CONTEXT pcre2_real_match_context_16 + +#elif defined SUPPORT_PCRE2_32 +#define DEFAULT_TEST_MODE PCRE32_MODE +#define VERSION_TYPE PCRE2_UCHAR32 +#define PCRE2_CONFIG pcre2_config_32 +#define PCRE2_JIT_STACK pcre2_jit_stack_32 +#define PCRE2_REAL_GENERAL_CONTEXT pcre2_real_general_context_32 +#define PCRE2_REAL_COMPILE_CONTEXT pcre2_real_compile_context_32 +#define PCRE2_REAL_CONVERT_CONTEXT pcre2_real_convert_context_32 +#define PCRE2_REAL_MATCH_CONTEXT pcre2_real_match_context_32 +#endif + +/* ------------- Structure and table for handling #-commands ------------- */ + +typedef struct cmdstruct { + const char *name; + int value; +} cmdstruct; + +enum { CMD_FORBID_UTF, CMD_LOAD, CMD_NEWLINE_DEFAULT, CMD_PATTERN, + CMD_PERLTEST, CMD_POP, CMD_POPCOPY, CMD_SAVE, CMD_SUBJECT, CMD_UNKNOWN }; + +static cmdstruct cmdlist[] = { + { "forbid_utf", CMD_FORBID_UTF }, + { "load", CMD_LOAD }, + { "newline_default", CMD_NEWLINE_DEFAULT }, + { "pattern", CMD_PATTERN }, + { "perltest", CMD_PERLTEST }, + { "pop", CMD_POP }, + { "popcopy", CMD_POPCOPY }, + { "save", CMD_SAVE }, + { "subject", CMD_SUBJECT }}; + +#define cmdlistcount (sizeof(cmdlist)/sizeof(cmdstruct)) + +/* ------------- Structures and tables for handling modifiers -------------- */ + +/* Table of names for newline types. Must be kept in step with the definitions +of PCRE2_NEWLINE_xx in pcre2.h. */ + +static const char *newlines[] = { + "DEFAULT", "CR", "LF", "CRLF", "ANY", "ANYCRLF", "NUL" }; + +/* Structure and table for handling pattern conversion types. */ + +typedef struct convertstruct { + const char *name; + uint32_t option; +} convertstruct; + +static convertstruct convertlist[] = { + { "glob", PCRE2_CONVERT_GLOB }, + { "glob_no_starstar", PCRE2_CONVERT_GLOB_NO_STARSTAR }, + { "glob_no_wild_separator", PCRE2_CONVERT_GLOB_NO_WILD_SEPARATOR }, + { "posix_basic", PCRE2_CONVERT_POSIX_BASIC }, + { "posix_extended", PCRE2_CONVERT_POSIX_EXTENDED }, + { "unset", CONVERT_UNSET }}; + +#define convertlistcount (sizeof(convertlist)/sizeof(convertstruct)) + +/* Modifier types and applicability */ + +enum { MOD_CTC, /* Applies to a compile context */ + MOD_CTM, /* Applies to a match context */ + MOD_PAT, /* Applies to a pattern */ + MOD_PATP, /* Ditto, OK for Perl test */ + MOD_DAT, /* Applies to a data line */ + MOD_PD, /* Applies to a pattern or a data line */ + MOD_PDP, /* As MOD_PD, OK for Perl test */ + MOD_PND, /* As MOD_PD, but not for a default pattern */ + MOD_PNDP, /* As MOD_PND, OK for Perl test */ + MOD_CHR, /* Is a single character */ + MOD_CON, /* Is a "convert" type/options list */ + MOD_CTL, /* Is a control bit */ + MOD_BSR, /* Is a BSR value */ + MOD_IN2, /* Is one or two unsigned integers */ + MOD_INS, /* Is a signed integer */ + MOD_INT, /* Is an unsigned integer */ + MOD_IND, /* Is an unsigned integer, but no value => default */ + MOD_NL, /* Is a newline value */ + MOD_NN, /* Is a number or a name; more than one may occur */ + MOD_OPT, /* Is an option bit */ + MOD_SIZ, /* Is a PCRE2_SIZE value */ + MOD_STR }; /* Is a string */ + +/* Control bits. Some apply to compiling, some to matching, but some can be set +either on a pattern or a data line, so they must all be distinct. There are now +so many of them that they are split into two fields. */ + +#define CTL_AFTERTEXT 0x00000001u +#define CTL_ALLAFTERTEXT 0x00000002u +#define CTL_ALLCAPTURES 0x00000004u +#define CTL_ALLUSEDTEXT 0x00000008u +#define CTL_ALTGLOBAL 0x00000010u +#define CTL_BINCODE 0x00000020u +#define CTL_CALLOUT_CAPTURE 0x00000040u +#define CTL_CALLOUT_INFO 0x00000080u +#define CTL_CALLOUT_NONE 0x00000100u +#define CTL_DFA 0x00000200u +#define CTL_EXPAND 0x00000400u +#define CTL_FINDLIMITS 0x00000800u +#define CTL_FRAMESIZE 0x00001000u +#define CTL_FULLBINCODE 0x00002000u +#define CTL_GETALL 0x00004000u +#define CTL_GLOBAL 0x00008000u +#define CTL_HEXPAT 0x00010000u /* Same word as USE_LENGTH */ +#define CTL_INFO 0x00020000u +#define CTL_JITFAST 0x00040000u +#define CTL_JITVERIFY 0x00080000u +#define CTL_MARK 0x00100000u +#define CTL_MEMORY 0x00200000u +#define CTL_NULLCONTEXT 0x00400000u +#define CTL_POSIX 0x00800000u +#define CTL_POSIX_NOSUB 0x01000000u +#define CTL_PUSH 0x02000000u /* These three must be */ +#define CTL_PUSHCOPY 0x04000000u /* all in the same */ +#define CTL_PUSHTABLESCOPY 0x08000000u /* word. */ +#define CTL_STARTCHAR 0x10000000u +#define CTL_USE_LENGTH 0x20000000u /* Same word as HEXPAT */ +#define CTL_UTF8_INPUT 0x40000000u +#define CTL_ZERO_TERMINATE 0x80000000u + +/* Combinations */ + +#define CTL_DEBUG (CTL_FULLBINCODE|CTL_INFO) /* For setting */ +#define CTL_ANYINFO (CTL_DEBUG|CTL_BINCODE|CTL_CALLOUT_INFO) +#define CTL_ANYGLOB (CTL_ALTGLOBAL|CTL_GLOBAL) + +/* Second control word */ + +#define CTL2_SUBSTITUTE_EXTENDED 0x00000001u +#define CTL2_SUBSTITUTE_OVERFLOW_LENGTH 0x00000002u +#define CTL2_SUBSTITUTE_UNKNOWN_UNSET 0x00000004u +#define CTL2_SUBSTITUTE_UNSET_EMPTY 0x00000008u +#define CTL2_SUBJECT_LITERAL 0x00000010u +#define CTL2_CALLOUT_NO_WHERE 0x00000020u +#define CTL2_CALLOUT_EXTRA 0x00000040u + +#define CTL2_NL_SET 0x40000000u /* Informational */ +#define CTL2_BSR_SET 0x80000000u /* Informational */ + +/* These are the matching controls that may be set either on a pattern or on a +data line. They are copied from the pattern controls as initial settings for +data line controls. Note that CTL_MEMORY is not included here, because it does +different things in the two cases. */ + +#define CTL_ALLPD (CTL_AFTERTEXT|\ + CTL_ALLAFTERTEXT|\ + CTL_ALLCAPTURES|\ + CTL_ALLUSEDTEXT|\ + CTL_ALTGLOBAL|\ + CTL_GLOBAL|\ + CTL_MARK|\ + CTL_STARTCHAR|\ + CTL_UTF8_INPUT) + +#define CTL2_ALLPD (CTL2_SUBSTITUTE_EXTENDED|\ + CTL2_SUBSTITUTE_OVERFLOW_LENGTH|\ + CTL2_SUBSTITUTE_UNKNOWN_UNSET|\ + CTL2_SUBSTITUTE_UNSET_EMPTY) + +/* Structures for holding modifier information for patterns and subject strings +(data). Fields containing modifiers that can be set either for a pattern or a +subject must be at the start and in the same order in both cases so that the +same offset in the big table below works for both. */ + +typedef struct patctl { /* Structure for pattern modifiers. */ + uint32_t options; /* Must be in same position as datctl */ + uint32_t control; /* Must be in same position as datctl */ + uint32_t control2; /* Must be in same position as datctl */ + uint32_t jitstack; /* Must be in same position as datctl */ + uint8_t replacement[REPLACE_MODSIZE]; /* So must this */ + uint32_t jit; + uint32_t stackguard_test; + uint32_t tables_id; + uint32_t convert_type; + uint32_t convert_length; + uint32_t convert_glob_escape; + uint32_t convert_glob_separator; + uint32_t regerror_buffsize; + uint8_t locale[LOCALESIZE]; +} patctl; + +#define MAXCPYGET 10 +#define LENCPYGET 64 + +typedef struct datctl { /* Structure for data line modifiers. */ + uint32_t options; /* Must be in same position as patctl */ + uint32_t control; /* Must be in same position as patctl */ + uint32_t control2; /* Must be in same position as patctl */ + uint32_t jitstack; /* Must be in same position as patctl */ + uint8_t replacement[REPLACE_MODSIZE]; /* So must this */ + uint32_t startend[2]; + uint32_t cerror[2]; + uint32_t cfail[2]; + int32_t callout_data; + int32_t copy_numbers[MAXCPYGET]; + int32_t get_numbers[MAXCPYGET]; + uint32_t oveccount; + uint32_t offset; + uint8_t copy_names[LENCPYGET]; + uint8_t get_names[LENCPYGET]; +} datctl; + +/* Ids for which context to modify. */ + +enum { CTX_PAT, /* Active pattern context */ + CTX_POPPAT, /* Ditto, for a popped pattern */ + CTX_DEFPAT, /* Default pattern context */ + CTX_DAT, /* Active data (match) context */ + CTX_DEFDAT }; /* Default data (match) context */ + +/* Macros to simplify the big table below. */ + +#define CO(name) offsetof(PCRE2_REAL_COMPILE_CONTEXT, name) +#define MO(name) offsetof(PCRE2_REAL_MATCH_CONTEXT, name) +#define PO(name) offsetof(patctl, name) +#define PD(name) PO(name) +#define DO(name) offsetof(datctl, name) + +/* Table of all long-form modifiers. Must be in collating sequence of modifier +name because it is searched by binary chop. */ + +typedef struct modstruct { + const char *name; + uint16_t which; + uint16_t type; + uint32_t value; + PCRE2_SIZE offset; +} modstruct; + +static modstruct modlist[] = { + { "aftertext", MOD_PNDP, MOD_CTL, CTL_AFTERTEXT, PO(control) }, + { "allaftertext", MOD_PNDP, MOD_CTL, CTL_ALLAFTERTEXT, PO(control) }, + { "allcaptures", MOD_PND, MOD_CTL, CTL_ALLCAPTURES, PO(control) }, + { "allow_empty_class", MOD_PAT, MOD_OPT, PCRE2_ALLOW_EMPTY_CLASS, PO(options) }, + { "allow_surrogate_escapes", MOD_CTC, MOD_OPT, PCRE2_EXTRA_ALLOW_SURROGATE_ESCAPES, CO(extra_options) }, + { "allusedtext", MOD_PNDP, MOD_CTL, CTL_ALLUSEDTEXT, PO(control) }, + { "alt_bsux", MOD_PAT, MOD_OPT, PCRE2_ALT_BSUX, PO(options) }, + { "alt_circumflex", MOD_PAT, MOD_OPT, PCRE2_ALT_CIRCUMFLEX, PO(options) }, + { "alt_verbnames", MOD_PAT, MOD_OPT, PCRE2_ALT_VERBNAMES, PO(options) }, + { "altglobal", MOD_PND, MOD_CTL, CTL_ALTGLOBAL, PO(control) }, + { "anchored", MOD_PD, MOD_OPT, PCRE2_ANCHORED, PD(options) }, + { "auto_callout", MOD_PAT, MOD_OPT, PCRE2_AUTO_CALLOUT, PO(options) }, + { "bad_escape_is_literal", MOD_CTC, MOD_OPT, PCRE2_EXTRA_BAD_ESCAPE_IS_LITERAL, CO(extra_options) }, + { "bincode", MOD_PAT, MOD_CTL, CTL_BINCODE, PO(control) }, + { "bsr", MOD_CTC, MOD_BSR, 0, CO(bsr_convention) }, + { "callout_capture", MOD_DAT, MOD_CTL, CTL_CALLOUT_CAPTURE, DO(control) }, + { "callout_data", MOD_DAT, MOD_INS, 0, DO(callout_data) }, + { "callout_error", MOD_DAT, MOD_IN2, 0, DO(cerror) }, + { "callout_extra", MOD_DAT, MOD_CTL, CTL2_CALLOUT_EXTRA, DO(control2) }, + { "callout_fail", MOD_DAT, MOD_IN2, 0, DO(cfail) }, + { "callout_info", MOD_PAT, MOD_CTL, CTL_CALLOUT_INFO, PO(control) }, + { "callout_no_where", MOD_DAT, MOD_CTL, CTL2_CALLOUT_NO_WHERE, DO(control2) }, + { "callout_none", MOD_DAT, MOD_CTL, CTL_CALLOUT_NONE, DO(control) }, + { "caseless", MOD_PATP, MOD_OPT, PCRE2_CASELESS, PO(options) }, + { "convert", MOD_PAT, MOD_CON, 0, PO(convert_type) }, + { "convert_glob_escape", MOD_PAT, MOD_CHR, 0, PO(convert_glob_escape) }, + { "convert_glob_separator", MOD_PAT, MOD_CHR, 0, PO(convert_glob_separator) }, + { "convert_length", MOD_PAT, MOD_INT, 0, PO(convert_length) }, + { "copy", MOD_DAT, MOD_NN, DO(copy_numbers), DO(copy_names) }, + { "debug", MOD_PAT, MOD_CTL, CTL_DEBUG, PO(control) }, + { "depth_limit", MOD_CTM, MOD_INT, 0, MO(depth_limit) }, + { "dfa", MOD_DAT, MOD_CTL, CTL_DFA, DO(control) }, + { "dfa_restart", MOD_DAT, MOD_OPT, PCRE2_DFA_RESTART, DO(options) }, + { "dfa_shortest", MOD_DAT, MOD_OPT, PCRE2_DFA_SHORTEST, DO(options) }, + { "dollar_endonly", MOD_PAT, MOD_OPT, PCRE2_DOLLAR_ENDONLY, PO(options) }, + { "dotall", MOD_PATP, MOD_OPT, PCRE2_DOTALL, PO(options) }, + { "dupnames", MOD_PATP, MOD_OPT, PCRE2_DUPNAMES, PO(options) }, + { "endanchored", MOD_PD, MOD_OPT, PCRE2_ENDANCHORED, PD(options) }, + { "expand", MOD_PAT, MOD_CTL, CTL_EXPAND, PO(control) }, + { "extended", MOD_PATP, MOD_OPT, PCRE2_EXTENDED, PO(options) }, + { "extended_more", MOD_PATP, MOD_OPT, PCRE2_EXTENDED_MORE, PO(options) }, + { "find_limits", MOD_DAT, MOD_CTL, CTL_FINDLIMITS, DO(control) }, + { "firstline", MOD_PAT, MOD_OPT, PCRE2_FIRSTLINE, PO(options) }, + { "framesize", MOD_PAT, MOD_CTL, CTL_FRAMESIZE, PO(control) }, + { "fullbincode", MOD_PAT, MOD_CTL, CTL_FULLBINCODE, PO(control) }, + { "get", MOD_DAT, MOD_NN, DO(get_numbers), DO(get_names) }, + { "getall", MOD_DAT, MOD_CTL, CTL_GETALL, DO(control) }, + { "global", MOD_PNDP, MOD_CTL, CTL_GLOBAL, PO(control) }, + { "heap_limit", MOD_CTM, MOD_INT, 0, MO(heap_limit) }, + { "hex", MOD_PAT, MOD_CTL, CTL_HEXPAT, PO(control) }, + { "info", MOD_PAT, MOD_CTL, CTL_INFO, PO(control) }, + { "jit", MOD_PAT, MOD_IND, 7, PO(jit) }, + { "jitfast", MOD_PAT, MOD_CTL, CTL_JITFAST, PO(control) }, + { "jitstack", MOD_PNDP, MOD_INT, 0, PO(jitstack) }, + { "jitverify", MOD_PAT, MOD_CTL, CTL_JITVERIFY, PO(control) }, + { "literal", MOD_PAT, MOD_OPT, PCRE2_LITERAL, PO(options) }, + { "locale", MOD_PAT, MOD_STR, LOCALESIZE, PO(locale) }, + { "mark", MOD_PNDP, MOD_CTL, CTL_MARK, PO(control) }, + { "match_limit", MOD_CTM, MOD_INT, 0, MO(match_limit) }, + { "match_line", MOD_CTC, MOD_OPT, PCRE2_EXTRA_MATCH_LINE, CO(extra_options) }, + { "match_unset_backref", MOD_PAT, MOD_OPT, PCRE2_MATCH_UNSET_BACKREF, PO(options) }, + { "match_word", MOD_CTC, MOD_OPT, PCRE2_EXTRA_MATCH_WORD, CO(extra_options) }, + { "max_pattern_length", MOD_CTC, MOD_SIZ, 0, CO(max_pattern_length) }, + { "memory", MOD_PD, MOD_CTL, CTL_MEMORY, PD(control) }, + { "multiline", MOD_PATP, MOD_OPT, PCRE2_MULTILINE, PO(options) }, + { "never_backslash_c", MOD_PAT, MOD_OPT, PCRE2_NEVER_BACKSLASH_C, PO(options) }, + { "never_ucp", MOD_PAT, MOD_OPT, PCRE2_NEVER_UCP, PO(options) }, + { "never_utf", MOD_PAT, MOD_OPT, PCRE2_NEVER_UTF, PO(options) }, + { "newline", MOD_CTC, MOD_NL, 0, CO(newline_convention) }, + { "no_auto_capture", MOD_PAT, MOD_OPT, PCRE2_NO_AUTO_CAPTURE, PO(options) }, + { "no_auto_possess", MOD_PATP, MOD_OPT, PCRE2_NO_AUTO_POSSESS, PO(options) }, + { "no_dotstar_anchor", MOD_PAT, MOD_OPT, PCRE2_NO_DOTSTAR_ANCHOR, PO(options) }, + { "no_jit", MOD_DAT, MOD_OPT, PCRE2_NO_JIT, DO(options) }, + { "no_start_optimize", MOD_PATP, MOD_OPT, PCRE2_NO_START_OPTIMIZE, PO(options) }, + { "no_utf_check", MOD_PD, MOD_OPT, PCRE2_NO_UTF_CHECK, PD(options) }, + { "notbol", MOD_DAT, MOD_OPT, PCRE2_NOTBOL, DO(options) }, + { "notempty", MOD_DAT, MOD_OPT, PCRE2_NOTEMPTY, DO(options) }, + { "notempty_atstart", MOD_DAT, MOD_OPT, PCRE2_NOTEMPTY_ATSTART, DO(options) }, + { "noteol", MOD_DAT, MOD_OPT, PCRE2_NOTEOL, DO(options) }, + { "null_context", MOD_PD, MOD_CTL, CTL_NULLCONTEXT, PO(control) }, + { "offset", MOD_DAT, MOD_INT, 0, DO(offset) }, + { "offset_limit", MOD_CTM, MOD_SIZ, 0, MO(offset_limit)}, + { "ovector", MOD_DAT, MOD_INT, 0, DO(oveccount) }, + { "parens_nest_limit", MOD_CTC, MOD_INT, 0, CO(parens_nest_limit) }, + { "partial_hard", MOD_DAT, MOD_OPT, PCRE2_PARTIAL_HARD, DO(options) }, + { "partial_soft", MOD_DAT, MOD_OPT, PCRE2_PARTIAL_SOFT, DO(options) }, + { "ph", MOD_DAT, MOD_OPT, PCRE2_PARTIAL_HARD, DO(options) }, + { "posix", MOD_PAT, MOD_CTL, CTL_POSIX, PO(control) }, + { "posix_nosub", MOD_PAT, MOD_CTL, CTL_POSIX|CTL_POSIX_NOSUB, PO(control) }, + { "posix_startend", MOD_DAT, MOD_IN2, 0, DO(startend) }, + { "ps", MOD_DAT, MOD_OPT, PCRE2_PARTIAL_SOFT, DO(options) }, + { "push", MOD_PAT, MOD_CTL, CTL_PUSH, PO(control) }, + { "pushcopy", MOD_PAT, MOD_CTL, CTL_PUSHCOPY, PO(control) }, + { "pushtablescopy", MOD_PAT, MOD_CTL, CTL_PUSHTABLESCOPY, PO(control) }, + { "recursion_limit", MOD_CTM, MOD_INT, 0, MO(depth_limit) }, /* Obsolete synonym */ + { "regerror_buffsize", MOD_PAT, MOD_INT, 0, PO(regerror_buffsize) }, + { "replace", MOD_PND, MOD_STR, REPLACE_MODSIZE, PO(replacement) }, + { "stackguard", MOD_PAT, MOD_INT, 0, PO(stackguard_test) }, + { "startchar", MOD_PND, MOD_CTL, CTL_STARTCHAR, PO(control) }, + { "startoffset", MOD_DAT, MOD_INT, 0, DO(offset) }, + { "subject_literal", MOD_PATP, MOD_CTL, CTL2_SUBJECT_LITERAL, PO(control2) }, + { "substitute_extended", MOD_PND, MOD_CTL, CTL2_SUBSTITUTE_EXTENDED, PO(control2) }, + { "substitute_overflow_length", MOD_PND, MOD_CTL, CTL2_SUBSTITUTE_OVERFLOW_LENGTH, PO(control2) }, + { "substitute_unknown_unset", MOD_PND, MOD_CTL, CTL2_SUBSTITUTE_UNKNOWN_UNSET, PO(control2) }, + { "substitute_unset_empty", MOD_PND, MOD_CTL, CTL2_SUBSTITUTE_UNSET_EMPTY, PO(control2) }, + { "tables", MOD_PAT, MOD_INT, 0, PO(tables_id) }, + { "ucp", MOD_PATP, MOD_OPT, PCRE2_UCP, PO(options) }, + { "ungreedy", MOD_PAT, MOD_OPT, PCRE2_UNGREEDY, PO(options) }, + { "use_length", MOD_PAT, MOD_CTL, CTL_USE_LENGTH, PO(control) }, + { "use_offset_limit", MOD_PAT, MOD_OPT, PCRE2_USE_OFFSET_LIMIT, PO(options) }, + { "utf", MOD_PATP, MOD_OPT, PCRE2_UTF, PO(options) }, + { "utf8_input", MOD_PAT, MOD_CTL, CTL_UTF8_INPUT, PO(control) }, + { "zero_terminate", MOD_DAT, MOD_CTL, CTL_ZERO_TERMINATE, DO(control) } +}; + +#define MODLISTCOUNT sizeof(modlist)/sizeof(modstruct) + +/* Controls and options that are supported for use with the POSIX interface. */ + +#define POSIX_SUPPORTED_COMPILE_OPTIONS ( \ + PCRE2_CASELESS|PCRE2_DOTALL|PCRE2_LITERAL|PCRE2_MULTILINE|PCRE2_UCP| \ + PCRE2_UTF|PCRE2_UNGREEDY) + +#define POSIX_SUPPORTED_COMPILE_EXTRA_OPTIONS (0) + +#define POSIX_SUPPORTED_COMPILE_CONTROLS ( \ + CTL_AFTERTEXT|CTL_ALLAFTERTEXT|CTL_EXPAND|CTL_HEXPAT|CTL_POSIX| \ + CTL_POSIX_NOSUB|CTL_USE_LENGTH) + +#define POSIX_SUPPORTED_COMPILE_CONTROLS2 (0) + +#define POSIX_SUPPORTED_MATCH_OPTIONS ( \ + PCRE2_NOTBOL|PCRE2_NOTEMPTY|PCRE2_NOTEOL) + +#define POSIX_SUPPORTED_MATCH_CONTROLS (CTL_AFTERTEXT|CTL_ALLAFTERTEXT) +#define POSIX_SUPPORTED_MATCH_CONTROLS2 (0) + +/* Control bits that are not ignored with 'push'. */ + +#define PUSH_SUPPORTED_COMPILE_CONTROLS ( \ + CTL_BINCODE|CTL_CALLOUT_INFO|CTL_FULLBINCODE|CTL_HEXPAT|CTL_INFO| \ + CTL_JITVERIFY|CTL_MEMORY|CTL_FRAMESIZE|CTL_PUSH|CTL_PUSHCOPY| \ + CTL_PUSHTABLESCOPY|CTL_USE_LENGTH) + +#define PUSH_SUPPORTED_COMPILE_CONTROLS2 (CTL2_BSR_SET|CTL2_NL_SET) + +/* Controls that apply only at compile time with 'push'. */ + +#define PUSH_COMPILE_ONLY_CONTROLS CTL_JITVERIFY +#define PUSH_COMPILE_ONLY_CONTROLS2 (0) + +/* Controls that are forbidden with #pop or #popcopy. */ + +#define NOTPOP_CONTROLS (CTL_HEXPAT|CTL_POSIX|CTL_POSIX_NOSUB|CTL_PUSH| \ + CTL_PUSHCOPY|CTL_PUSHTABLESCOPY|CTL_USE_LENGTH) + +/* Pattern controls that are mutually exclusive. At present these are all in +the first control word. Note that CTL_POSIX_NOSUB is always accompanied by +CTL_POSIX, so it doesn't need its own entries. */ + +static uint32_t exclusive_pat_controls[] = { + CTL_POSIX | CTL_PUSH, + CTL_POSIX | CTL_PUSHCOPY, + CTL_POSIX | CTL_PUSHTABLESCOPY, + CTL_PUSH | CTL_PUSHCOPY, + CTL_PUSH | CTL_PUSHTABLESCOPY, + CTL_PUSHCOPY | CTL_PUSHTABLESCOPY, + CTL_EXPAND | CTL_HEXPAT }; + +/* Data controls that are mutually exclusive. At present these are all in the +first control word. */ + +static uint32_t exclusive_dat_controls[] = { + CTL_ALLUSEDTEXT | CTL_STARTCHAR, + CTL_FINDLIMITS | CTL_NULLCONTEXT }; + +/* Table of single-character abbreviated modifiers. The index field is +initialized to -1, but the first time the modifier is encountered, it is filled +in with the index of the full entry in modlist, to save repeated searching when +processing multiple test items. This short list is searched serially, so its +order does not matter. */ + +typedef struct c1modstruct { + const char *fullname; + uint32_t onechar; + int index; +} c1modstruct; + +static c1modstruct c1modlist[] = { + { "bincode", 'B', -1 }, + { "info", 'I', -1 }, + { "global", 'g', -1 }, + { "caseless", 'i', -1 }, + { "multiline", 'm', -1 }, + { "no_auto_capture", 'n', -1 }, + { "dotall", 's', -1 }, + { "extended", 'x', -1 } +}; + +#define C1MODLISTCOUNT sizeof(c1modlist)/sizeof(c1modstruct) + +/* Table of arguments for the -C command line option. Use macros to make the +table itself easier to read. */ + +#if defined SUPPORT_PCRE2_8 +#define SUPPORT_8 1 +#endif +#if defined SUPPORT_PCRE2_16 +#define SUPPORT_16 1 +#endif +#if defined SUPPORT_PCRE2_32 +#define SUPPORT_32 1 +#endif + +#ifndef SUPPORT_8 +#define SUPPORT_8 0 +#endif +#ifndef SUPPORT_16 +#define SUPPORT_16 0 +#endif +#ifndef SUPPORT_32 +#define SUPPORT_32 0 +#endif + +#ifdef EBCDIC +#define SUPPORT_EBCDIC 1 +#define EBCDIC_NL CHAR_LF +#else +#define SUPPORT_EBCDIC 0 +#define EBCDIC_NL 0 +#endif + +#ifdef NEVER_BACKSLASH_C +#define BACKSLASH_C 0 +#else +#define BACKSLASH_C 1 +#endif + +typedef struct coptstruct { + const char *name; + uint32_t type; + uint32_t value; +} coptstruct; + +enum { CONF_BSR, + CONF_FIX, + CONF_FIZ, + CONF_INT, + CONF_NL +}; + +static coptstruct coptlist[] = { + { "backslash-C", CONF_FIX, BACKSLASH_C }, + { "bsr", CONF_BSR, PCRE2_CONFIG_BSR }, + { "ebcdic", CONF_FIX, SUPPORT_EBCDIC }, + { "ebcdic-nl", CONF_FIZ, EBCDIC_NL }, + { "jit", CONF_INT, PCRE2_CONFIG_JIT }, + { "linksize", CONF_INT, PCRE2_CONFIG_LINKSIZE }, + { "newline", CONF_NL, PCRE2_CONFIG_NEWLINE }, + { "pcre2-16", CONF_FIX, SUPPORT_16 }, + { "pcre2-32", CONF_FIX, SUPPORT_32 }, + { "pcre2-8", CONF_FIX, SUPPORT_8 }, + { "unicode", CONF_INT, PCRE2_CONFIG_UNICODE } +}; + +#define COPTLISTCOUNT sizeof(coptlist)/sizeof(coptstruct) + +#undef SUPPORT_8 +#undef SUPPORT_16 +#undef SUPPORT_32 +#undef SUPPORT_EBCDIC + + +/* ----------------------- Static variables ------------------------ */ + +static FILE *infile; +static FILE *outfile; + +static const void *last_callout_mark; +static PCRE2_JIT_STACK *jit_stack = NULL; +static size_t jit_stack_size = 0; + +static BOOL first_callout; +static BOOL jit_was_used; +static BOOL restrict_for_perl_test = FALSE; +static BOOL show_memory = FALSE; + +static int code_unit_size; /* Bytes */ +static int jitrc; /* Return from JIT compile */ +static int test_mode = DEFAULT_TEST_MODE; +static int timeit = 0; +static int timeitm = 0; + +clock_t total_compile_time = 0; +clock_t total_jit_compile_time = 0; +clock_t total_match_time = 0; + +static uint32_t dfa_matched; +static uint32_t forbid_utf = 0; +static uint32_t maxlookbehind; +static uint32_t max_oveccount; +static uint32_t callout_count; + +static uint16_t local_newline_default = 0; + +static VERSION_TYPE jittarget[VERSION_SIZE]; +static VERSION_TYPE version[VERSION_SIZE]; +static VERSION_TYPE uversion[VERSION_SIZE]; + +static patctl def_patctl; +static patctl pat_patctl; +static datctl def_datctl; +static datctl dat_datctl; + +static void *patstack[PATSTACKSIZE]; +static int patstacknext = 0; + +static void *malloclist[MALLOCLISTSIZE]; +static PCRE2_SIZE malloclistlength[MALLOCLISTSIZE]; +static uint32_t malloclistptr = 0; + +#ifdef SUPPORT_PCRE2_8 +static regex_t preg = { NULL, NULL, 0, 0, 0, 0 }; +#endif + +static int *dfa_workspace = NULL; +static const uint8_t *locale_tables = NULL; +static const uint8_t *use_tables = NULL; +static uint8_t locale_name[32]; + +/* We need buffers for building 16/32-bit strings; 8-bit strings don't need +rebuilding, but set up the same naming scheme for use in macros. The "buffer" +buffer is where all input lines are read. Its size is the same as pbuffer8. +Pattern lines are always copied to pbuffer8 for use in callouts, even if they +are actually compiled from pbuffer16 or pbuffer32. */ + +static size_t pbuffer8_size = 50000; /* Initial size, bytes */ +static uint8_t *pbuffer8 = NULL; +static uint8_t *buffer = NULL; + +/* The dbuffer is where all processed data lines are put. In non-8-bit modes it +is cast as needed. For long data lines it grows as necessary. */ + +static size_t dbuffer_size = 1u << 14; /* Initial size, bytes */ +static uint8_t *dbuffer = NULL; + + +/* ---------------- Mode-dependent variables -------------------*/ + +#ifdef SUPPORT_PCRE2_8 +static pcre2_code_8 *compiled_code8; +static pcre2_general_context_8 *general_context8, *general_context_copy8; +static pcre2_compile_context_8 *pat_context8, *default_pat_context8; +static pcre2_convert_context_8 *con_context8, *default_con_context8; +static pcre2_match_context_8 *dat_context8, *default_dat_context8; +static pcre2_match_data_8 *match_data8; +#endif + +#ifdef SUPPORT_PCRE2_16 +static pcre2_code_16 *compiled_code16; +static pcre2_general_context_16 *general_context16, *general_context_copy16; +static pcre2_compile_context_16 *pat_context16, *default_pat_context16; +static pcre2_convert_context_16 *con_context16, *default_con_context16; +static pcre2_match_context_16 *dat_context16, *default_dat_context16; +static pcre2_match_data_16 *match_data16; +static PCRE2_SIZE pbuffer16_size = 0; /* Set only when needed */ +static uint16_t *pbuffer16 = NULL; +#endif + +#ifdef SUPPORT_PCRE2_32 +static pcre2_code_32 *compiled_code32; +static pcre2_general_context_32 *general_context32, *general_context_copy32; +static pcre2_compile_context_32 *pat_context32, *default_pat_context32; +static pcre2_convert_context_32 *con_context32, *default_con_context32; +static pcre2_match_context_32 *dat_context32, *default_dat_context32; +static pcre2_match_data_32 *match_data32; +static PCRE2_SIZE pbuffer32_size = 0; /* Set only when needed */ +static uint32_t *pbuffer32 = NULL; +#endif + + +/* ---------------- Macros that work in all modes ----------------- */ + +#define CAST8VAR(x) CASTVAR(uint8_t *, x) +#define SET(x,y) SETOP(x,y,=) +#define SETPLUS(x,y) SETOP(x,y,+=) +#define strlen8(x) strlen((char *)x) + + +/* ---------------- Mode-dependent, runtime-testing macros ------------------*/ + +/* Define macros for variables and functions that must be selected dynamically +depending on the mode setting (8, 16, 32). These are dependent on which modes +are supported. */ + +#if (defined (SUPPORT_PCRE2_8) + defined (SUPPORT_PCRE2_16) + \ + defined (SUPPORT_PCRE2_32)) >= 2 + +/* ----- All three modes supported ----- */ + +#if defined(SUPPORT_PCRE2_8) && defined(SUPPORT_PCRE2_16) && defined(SUPPORT_PCRE2_32) + +#define CASTFLD(t,a,b) ((test_mode == PCRE8_MODE)? (t)(G(a,8)->b) : \ + (test_mode == PCRE16_MODE)? (t)(G(a,16)->b) : (t)(G(a,32)->b)) + +#define CASTVAR(t,x) ( \ + (test_mode == PCRE8_MODE)? (t)G(x,8) : \ + (test_mode == PCRE16_MODE)? (t)G(x,16) : (t)G(x,32)) + +#define CODE_UNIT(a,b) ( \ + (test_mode == PCRE8_MODE)? (uint32_t)(((PCRE2_SPTR8)(a))[b]) : \ + (test_mode == PCRE16_MODE)? (uint32_t)(((PCRE2_SPTR16)(a))[b]) : \ + (uint32_t)(((PCRE2_SPTR32)(a))[b])) + +#define CONCTXCPY(a,b) \ + if (test_mode == PCRE8_MODE) \ + memcpy(G(a,8),G(b,8),sizeof(pcre2_convert_context_8)); \ + else if (test_mode == PCRE16_MODE) \ + memcpy(G(a,16),G(b,16),sizeof(pcre2_convert_context_16)); \ + else memcpy(G(a,32),G(b,32),sizeof(pcre2_convert_context_32)) + +#define CONVERT_COPY(a,b,c) \ + if (test_mode == PCRE8_MODE) \ + memcpy(G(a,8),(char *)b,c); \ + else if (test_mode == PCRE16_MODE) \ + memcpy(G(a,16),(char *)b,(c)*2); \ + else if (test_mode == PCRE32_MODE) \ + memcpy(G(a,32),(char *)b,(c)*4) + +#define DATCTXCPY(a,b) \ + if (test_mode == PCRE8_MODE) \ + memcpy(G(a,8),G(b,8),sizeof(pcre2_match_context_8)); \ + else if (test_mode == PCRE16_MODE) \ + memcpy(G(a,16),G(b,16),sizeof(pcre2_match_context_16)); \ + else memcpy(G(a,32),G(b,32),sizeof(pcre2_match_context_32)) + +#define FLD(a,b) ((test_mode == PCRE8_MODE)? G(a,8)->b : \ + (test_mode == PCRE16_MODE)? G(a,16)->b : G(a,32)->b) + +#define PATCTXCPY(a,b) \ + if (test_mode == PCRE8_MODE) \ + memcpy(G(a,8),G(b,8),sizeof(pcre2_compile_context_8)); \ + else if (test_mode == PCRE16_MODE) \ + memcpy(G(a,16),G(b,16),sizeof(pcre2_compile_context_16)); \ + else memcpy(G(a,32),G(b,32),sizeof(pcre2_compile_context_32)) + +#define PCHARS(lv, p, offset, len, utf, f) \ + if (test_mode == PCRE32_MODE) \ + lv = pchars32((PCRE2_SPTR32)(p)+offset, len, utf, f); \ + else if (test_mode == PCRE16_MODE) \ + lv = pchars16((PCRE2_SPTR16)(p)+offset, len, utf, f); \ + else \ + lv = pchars8((PCRE2_SPTR8)(p)+offset, len, utf, f) + +#define PCHARSV(p, offset, len, utf, f) \ + if (test_mode == PCRE32_MODE) \ + (void)pchars32((PCRE2_SPTR32)(p)+offset, len, utf, f); \ + else if (test_mode == PCRE16_MODE) \ + (void)pchars16((PCRE2_SPTR16)(p)+offset, len, utf, f); \ + else \ + (void)pchars8((PCRE2_SPTR8)(p)+offset, len, utf, f) + +#define PCRE2_CALLOUT_ENUMERATE(a,b,c) \ + if (test_mode == PCRE8_MODE) \ + a = pcre2_callout_enumerate_8(compiled_code8, \ + (int (*)(struct pcre2_callout_enumerate_block_8 *, void *))b,c); \ + else if (test_mode == PCRE16_MODE) \ + a = pcre2_callout_enumerate_16(compiled_code16, \ + (int(*)(struct pcre2_callout_enumerate_block_16 *, void *))b,c); \ + else \ + a = pcre2_callout_enumerate_32(compiled_code32, \ + (int (*)(struct pcre2_callout_enumerate_block_32 *, void *))b,c) + +#define PCRE2_CODE_COPY_FROM_VOID(a,b) \ + if (test_mode == PCRE8_MODE) \ + G(a,8) = pcre2_code_copy_8(b); \ + else if (test_mode == PCRE16_MODE) \ + G(a,16) = pcre2_code_copy_16(b); \ + else \ + G(a,32) = pcre2_code_copy_32(b) + +#define PCRE2_CODE_COPY_TO_VOID(a,b) \ + if (test_mode == PCRE8_MODE) \ + a = (void *)pcre2_code_copy_8(G(b,8)); \ + else if (test_mode == PCRE16_MODE) \ + a = (void *)pcre2_code_copy_16(G(b,16)); \ + else \ + a = (void *)pcre2_code_copy_32(G(b,32)) + +#define PCRE2_CODE_COPY_WITH_TABLES_TO_VOID(a,b) \ + if (test_mode == PCRE8_MODE) \ + a = (void *)pcre2_code_copy_with_tables_8(G(b,8)); \ + else if (test_mode == PCRE16_MODE) \ + a = (void *)pcre2_code_copy_with_tables_16(G(b,16)); \ + else \ + a = (void *)pcre2_code_copy_with_tables_32(G(b,32)) + +#define PCRE2_COMPILE(a,b,c,d,e,f,g) \ + if (test_mode == PCRE8_MODE) \ + G(a,8) = pcre2_compile_8(G(b,8),c,d,e,f,g); \ + else if (test_mode == PCRE16_MODE) \ + G(a,16) = pcre2_compile_16(G(b,16),c,d,e,f,g); \ + else \ + G(a,32) = pcre2_compile_32(G(b,32),c,d,e,f,g) + +#define PCRE2_CONVERTED_PATTERN_FREE(a) \ + if (test_mode == PCRE8_MODE) pcre2_converted_pattern_free_8((PCRE2_UCHAR8 *)a); \ + else if (test_mode == PCRE16_MODE) pcre2_converted_pattern_free_16((PCRE2_UCHAR16 *)a); \ + else pcre2_converted_pattern_free_32((PCRE2_UCHAR32 *)a) + +#define PCRE2_DFA_MATCH(a,b,c,d,e,f,g,h,i,j) \ + if (test_mode == PCRE8_MODE) \ + a = pcre2_dfa_match_8(G(b,8),(PCRE2_SPTR8)c,d,e,f,G(g,8),h,i,j); \ + else if (test_mode == PCRE16_MODE) \ + a = pcre2_dfa_match_16(G(b,16),(PCRE2_SPTR16)c,d,e,f,G(g,16),h,i,j); \ + else \ + a = pcre2_dfa_match_32(G(b,32),(PCRE2_SPTR32)c,d,e,f,G(g,32),h,i,j) + +#define PCRE2_GET_ERROR_MESSAGE(r,a,b) \ + if (test_mode == PCRE8_MODE) \ + r = pcre2_get_error_message_8(a,G(b,8),G(G(b,8),_size)); \ + else if (test_mode == PCRE16_MODE) \ + r = pcre2_get_error_message_16(a,G(b,16),G(G(b,16),_size/2)); \ + else \ + r = pcre2_get_error_message_32(a,G(b,32),G(G(b,32),_size/4)) + +#define PCRE2_GET_OVECTOR_COUNT(a,b) \ + if (test_mode == PCRE8_MODE) \ + a = pcre2_get_ovector_count_8(G(b,8)); \ + else if (test_mode == PCRE16_MODE) \ + a = pcre2_get_ovector_count_16(G(b,16)); \ + else \ + a = pcre2_get_ovector_count_32(G(b,32)) + +#define PCRE2_GET_STARTCHAR(a,b) \ + if (test_mode == PCRE8_MODE) \ + a = pcre2_get_startchar_8(G(b,8)); \ + else if (test_mode == PCRE16_MODE) \ + a = pcre2_get_startchar_16(G(b,16)); \ + else \ + a = pcre2_get_startchar_32(G(b,32)) + +#define PCRE2_JIT_COMPILE(r,a,b) \ + if (test_mode == PCRE8_MODE) r = pcre2_jit_compile_8(G(a,8),b); \ + else if (test_mode == PCRE16_MODE) r = pcre2_jit_compile_16(G(a,16),b); \ + else r = pcre2_jit_compile_32(G(a,32),b) + +#define PCRE2_JIT_FREE_UNUSED_MEMORY(a) \ + if (test_mode == PCRE8_MODE) pcre2_jit_free_unused_memory_8(G(a,8)); \ + else if (test_mode == PCRE16_MODE) pcre2_jit_free_unused_memory_16(G(a,16)); \ + else pcre2_jit_free_unused_memory_32(G(a,32)) + +#define PCRE2_JIT_MATCH(a,b,c,d,e,f,g,h) \ + if (test_mode == PCRE8_MODE) \ + a = pcre2_jit_match_8(G(b,8),(PCRE2_SPTR8)c,d,e,f,G(g,8),h); \ + else if (test_mode == PCRE16_MODE) \ + a = pcre2_jit_match_16(G(b,16),(PCRE2_SPTR16)c,d,e,f,G(g,16),h); \ + else \ + a = pcre2_jit_match_32(G(b,32),(PCRE2_SPTR32)c,d,e,f,G(g,32),h) + +#define PCRE2_JIT_STACK_CREATE(a,b,c,d) \ + if (test_mode == PCRE8_MODE) \ + a = (PCRE2_JIT_STACK *)pcre2_jit_stack_create_8(b,c,d); \ + else if (test_mode == PCRE16_MODE) \ + a = (PCRE2_JIT_STACK *)pcre2_jit_stack_create_16(b,c,d); \ + else \ + a = (PCRE2_JIT_STACK *)pcre2_jit_stack_create_32(b,c,d); + +#define PCRE2_JIT_STACK_ASSIGN(a,b,c) \ + if (test_mode == PCRE8_MODE) \ + pcre2_jit_stack_assign_8(G(a,8),(pcre2_jit_callback_8)b,c); \ + else if (test_mode == PCRE16_MODE) \ + pcre2_jit_stack_assign_16(G(a,16),(pcre2_jit_callback_16)b,c); \ + else \ + pcre2_jit_stack_assign_32(G(a,32),(pcre2_jit_callback_32)b,c); + +#define PCRE2_JIT_STACK_FREE(a) \ + if (test_mode == PCRE8_MODE) \ + pcre2_jit_stack_free_8((pcre2_jit_stack_8 *)a); \ + else if (test_mode == PCRE16_MODE) \ + pcre2_jit_stack_free_16((pcre2_jit_stack_16 *)a); \ + else \ + pcre2_jit_stack_free_32((pcre2_jit_stack_32 *)a); + +#define PCRE2_MAKETABLES(a) \ + if (test_mode == PCRE8_MODE) a = pcre2_maketables_8(NULL); \ + else if (test_mode == PCRE16_MODE) a = pcre2_maketables_16(NULL); \ + else a = pcre2_maketables_32(NULL) + +#define PCRE2_MATCH(a,b,c,d,e,f,g,h) \ + if (test_mode == PCRE8_MODE) \ + a = pcre2_match_8(G(b,8),(PCRE2_SPTR8)c,d,e,f,G(g,8),h); \ + else if (test_mode == PCRE16_MODE) \ + a = pcre2_match_16(G(b,16),(PCRE2_SPTR16)c,d,e,f,G(g,16),h); \ + else \ + a = pcre2_match_32(G(b,32),(PCRE2_SPTR32)c,d,e,f,G(g,32),h) + +#define PCRE2_MATCH_DATA_CREATE(a,b,c) \ + if (test_mode == PCRE8_MODE) \ + G(a,8) = pcre2_match_data_create_8(b,c); \ + else if (test_mode == PCRE16_MODE) \ + G(a,16) = pcre2_match_data_create_16(b,c); \ + else \ + G(a,32) = pcre2_match_data_create_32(b,c) + +#define PCRE2_MATCH_DATA_CREATE_FROM_PATTERN(a,b,c) \ + if (test_mode == PCRE8_MODE) \ + G(a,8) = pcre2_match_data_create_from_pattern_8(G(b,8),c); \ + else if (test_mode == PCRE16_MODE) \ + G(a,16) = pcre2_match_data_create_from_pattern_16(G(b,16),c); \ + else \ + G(a,32) = pcre2_match_data_create_from_pattern_32(G(b,32),c) + +#define PCRE2_MATCH_DATA_FREE(a) \ + if (test_mode == PCRE8_MODE) \ + pcre2_match_data_free_8(G(a,8)); \ + else if (test_mode == PCRE16_MODE) \ + pcre2_match_data_free_16(G(a,16)); \ + else \ + pcre2_match_data_free_32(G(a,32)) + +#define PCRE2_PATTERN_CONVERT(a,b,c,d,e,f,g) \ + if (test_mode == PCRE8_MODE) \ + a = pcre2_pattern_convert_8(G(b,8),c,d,(PCRE2_UCHAR8 **)e,f,G(g,8)); \ + else if (test_mode == PCRE16_MODE) \ + a = pcre2_pattern_convert_16(G(b,16),c,d,(PCRE2_UCHAR16 **)e,f,G(g,16)); \ + else \ + a = pcre2_pattern_convert_32(G(b,32),c,d,(PCRE2_UCHAR32 **)e,f,G(g,32)) + +#define PCRE2_PATTERN_INFO(a,b,c,d) \ + if (test_mode == PCRE8_MODE) \ + a = pcre2_pattern_info_8(G(b,8),c,d); \ + else if (test_mode == PCRE16_MODE) \ + a = pcre2_pattern_info_16(G(b,16),c,d); \ + else \ + a = pcre2_pattern_info_32(G(b,32),c,d) + +#define PCRE2_PRINTINT(a) \ + if (test_mode == PCRE8_MODE) \ + pcre2_printint_8(compiled_code8,outfile,a); \ + else if (test_mode == PCRE16_MODE) \ + pcre2_printint_16(compiled_code16,outfile,a); \ + else \ + pcre2_printint_32(compiled_code32,outfile,a) + +#define PCRE2_SERIALIZE_DECODE(r,a,b,c,d) \ + if (test_mode == PCRE8_MODE) \ + r = pcre2_serialize_decode_8((pcre2_code_8 **)a,b,c,G(d,8)); \ + else if (test_mode == PCRE16_MODE) \ + r = pcre2_serialize_decode_16((pcre2_code_16 **)a,b,c,G(d,16)); \ + else \ + r = pcre2_serialize_decode_32((pcre2_code_32 **)a,b,c,G(d,32)) + +#define PCRE2_SERIALIZE_ENCODE(r,a,b,c,d,e) \ + if (test_mode == PCRE8_MODE) \ + r = pcre2_serialize_encode_8((const pcre2_code_8 **)a,b,c,d,G(e,8)); \ + else if (test_mode == PCRE16_MODE) \ + r = pcre2_serialize_encode_16((const pcre2_code_16 **)a,b,c,d,G(e,16)); \ + else \ + r = pcre2_serialize_encode_32((const pcre2_code_32 **)a,b,c,d,G(e,32)) + +#define PCRE2_SERIALIZE_FREE(a) \ + if (test_mode == PCRE8_MODE) \ + pcre2_serialize_free_8(a); \ + else if (test_mode == PCRE16_MODE) \ + pcre2_serialize_free_16(a); \ + else \ + pcre2_serialize_free_32(a) + +#define PCRE2_SERIALIZE_GET_NUMBER_OF_CODES(r,a) \ + if (test_mode == PCRE8_MODE) \ + r = pcre2_serialize_get_number_of_codes_8(a); \ + else if (test_mode == PCRE16_MODE) \ + r = pcre2_serialize_get_number_of_codes_16(a); \ + else \ + r = pcre2_serialize_get_number_of_codes_32(a); \ + +#define PCRE2_SET_CALLOUT(a,b,c) \ + if (test_mode == PCRE8_MODE) \ + pcre2_set_callout_8(G(a,8),(int (*)(pcre2_callout_block_8 *, void *))b,c); \ + else if (test_mode == PCRE16_MODE) \ + pcre2_set_callout_16(G(a,16),(int (*)(pcre2_callout_block_16 *, void *))b,c); \ + else \ + pcre2_set_callout_32(G(a,32),(int (*)(pcre2_callout_block_32 *, void *))b,c); + +#define PCRE2_SET_CHARACTER_TABLES(a,b) \ + if (test_mode == PCRE8_MODE) \ + pcre2_set_character_tables_8(G(a,8),b); \ + else if (test_mode == PCRE16_MODE) \ + pcre2_set_character_tables_16(G(a,16),b); \ + else \ + pcre2_set_character_tables_32(G(a,32),b) + +#define PCRE2_SET_COMPILE_RECURSION_GUARD(a,b,c) \ + if (test_mode == PCRE8_MODE) \ + pcre2_set_compile_recursion_guard_8(G(a,8),b,c); \ + else if (test_mode == PCRE16_MODE) \ + pcre2_set_compile_recursion_guard_16(G(a,16),b,c); \ + else \ + pcre2_set_compile_recursion_guard_32(G(a,32),b,c) + +#define PCRE2_SET_DEPTH_LIMIT(a,b) \ + if (test_mode == PCRE8_MODE) \ + pcre2_set_depth_limit_8(G(a,8),b); \ + else if (test_mode == PCRE16_MODE) \ + pcre2_set_depth_limit_16(G(a,16),b); \ + else \ + pcre2_set_depth_limit_32(G(a,32),b) + +#define PCRE2_SET_GLOB_SEPARATOR(r,a,b) \ + if (test_mode == PCRE8_MODE) \ + r = pcre2_set_glob_separator_8(G(a,8),b); \ + else if (test_mode == PCRE16_MODE) \ + r = pcre2_set_glob_separator_16(G(a,16),b); \ + else \ + r = pcre2_set_glob_separator_32(G(a,32),b) + +#define PCRE2_SET_GLOB_ESCAPE(r,a,b) \ + if (test_mode == PCRE8_MODE) \ + r = pcre2_set_glob_escape_8(G(a,8),b); \ + else if (test_mode == PCRE16_MODE) \ + r = pcre2_set_glob_escape_16(G(a,16),b); \ + else \ + r = pcre2_set_glob_escape_32(G(a,32),b) + +#define PCRE2_SET_HEAP_LIMIT(a,b) \ + if (test_mode == PCRE8_MODE) \ + pcre2_set_heap_limit_8(G(a,8),b); \ + else if (test_mode == PCRE16_MODE) \ + pcre2_set_heap_limit_16(G(a,16),b); \ + else \ + pcre2_set_heap_limit_32(G(a,32),b) + +#define PCRE2_SET_MATCH_LIMIT(a,b) \ + if (test_mode == PCRE8_MODE) \ + pcre2_set_match_limit_8(G(a,8),b); \ + else if (test_mode == PCRE16_MODE) \ + pcre2_set_match_limit_16(G(a,16),b); \ + else \ + pcre2_set_match_limit_32(G(a,32),b) + +#define PCRE2_SET_MAX_PATTERN_LENGTH(a,b) \ + if (test_mode == PCRE8_MODE) \ + pcre2_set_max_pattern_length_8(G(a,8),b); \ + else if (test_mode == PCRE16_MODE) \ + pcre2_set_max_pattern_length_16(G(a,16),b); \ + else \ + pcre2_set_max_pattern_length_32(G(a,32),b) + +#define PCRE2_SET_OFFSET_LIMIT(a,b) \ + if (test_mode == PCRE8_MODE) \ + pcre2_set_offset_limit_8(G(a,8),b); \ + else if (test_mode == PCRE16_MODE) \ + pcre2_set_offset_limit_16(G(a,16),b); \ + else \ + pcre2_set_offset_limit_32(G(a,32),b) + +#define PCRE2_SET_PARENS_NEST_LIMIT(a,b) \ + if (test_mode == PCRE8_MODE) \ + pcre2_set_parens_nest_limit_8(G(a,8),b); \ + else if (test_mode == PCRE16_MODE) \ + pcre2_set_parens_nest_limit_16(G(a,16),b); \ + else \ + pcre2_set_parens_nest_limit_32(G(a,32),b) + +#define PCRE2_SUBSTITUTE(a,b,c,d,e,f,g,h,i,j,k,l) \ + if (test_mode == PCRE8_MODE) \ + a = pcre2_substitute_8(G(b,8),(PCRE2_SPTR8)c,d,e,f,G(g,8),G(h,8), \ + (PCRE2_SPTR8)i,j,(PCRE2_UCHAR8 *)k,l); \ + else if (test_mode == PCRE16_MODE) \ + a = pcre2_substitute_16(G(b,16),(PCRE2_SPTR16)c,d,e,f,G(g,16),G(h,16), \ + (PCRE2_SPTR16)i,j,(PCRE2_UCHAR16 *)k,l); \ + else \ + a = pcre2_substitute_32(G(b,32),(PCRE2_SPTR32)c,d,e,f,G(g,32),G(h,32), \ + (PCRE2_SPTR32)i,j,(PCRE2_UCHAR32 *)k,l) + +#define PCRE2_SUBSTRING_COPY_BYNAME(a,b,c,d,e) \ + if (test_mode == PCRE8_MODE) \ + a = pcre2_substring_copy_byname_8(G(b,8),G(c,8),(PCRE2_UCHAR8 *)d,e); \ + else if (test_mode == PCRE16_MODE) \ + a = pcre2_substring_copy_byname_16(G(b,16),G(c,16),(PCRE2_UCHAR16 *)d,e); \ + else \ + a = pcre2_substring_copy_byname_32(G(b,32),G(c,32),(PCRE2_UCHAR32 *)d,e) + +#define PCRE2_SUBSTRING_COPY_BYNUMBER(a,b,c,d,e) \ + if (test_mode == PCRE8_MODE) \ + a = pcre2_substring_copy_bynumber_8(G(b,8),c,(PCRE2_UCHAR8 *)d,e); \ + else if (test_mode == PCRE16_MODE) \ + a = pcre2_substring_copy_bynumber_16(G(b,16),c,(PCRE2_UCHAR16 *)d,e); \ + else \ + a = pcre2_substring_copy_bynumber_32(G(b,32),c,(PCRE2_UCHAR32 *)d,e) + +#define PCRE2_SUBSTRING_FREE(a) \ + if (test_mode == PCRE8_MODE) pcre2_substring_free_8((PCRE2_UCHAR8 *)a); \ + else if (test_mode == PCRE16_MODE) \ + pcre2_substring_free_16((PCRE2_UCHAR16 *)a); \ + else pcre2_substring_free_32((PCRE2_UCHAR32 *)a) + +#define PCRE2_SUBSTRING_GET_BYNAME(a,b,c,d,e) \ + if (test_mode == PCRE8_MODE) \ + a = pcre2_substring_get_byname_8(G(b,8),G(c,8),(PCRE2_UCHAR8 **)d,e); \ + else if (test_mode == PCRE16_MODE) \ + a = pcre2_substring_get_byname_16(G(b,16),G(c,16),(PCRE2_UCHAR16 **)d,e); \ + else \ + a = pcre2_substring_get_byname_32(G(b,32),G(c,32),(PCRE2_UCHAR32 **)d,e) + +#define PCRE2_SUBSTRING_GET_BYNUMBER(a,b,c,d,e) \ + if (test_mode == PCRE8_MODE) \ + a = pcre2_substring_get_bynumber_8(G(b,8),c,(PCRE2_UCHAR8 **)d,e); \ + else if (test_mode == PCRE16_MODE) \ + a = pcre2_substring_get_bynumber_16(G(b,16),c,(PCRE2_UCHAR16 **)d,e); \ + else \ + a = pcre2_substring_get_bynumber_32(G(b,32),c,(PCRE2_UCHAR32 **)d,e) + +#define PCRE2_SUBSTRING_LENGTH_BYNAME(a,b,c,d) \ + if (test_mode == PCRE8_MODE) \ + a = pcre2_substring_length_byname_8(G(b,8),G(c,8),d); \ + else if (test_mode == PCRE16_MODE) \ + a = pcre2_substring_length_byname_16(G(b,16),G(c,16),d); \ + else \ + a = pcre2_substring_length_byname_32(G(b,32),G(c,32),d) + +#define PCRE2_SUBSTRING_LENGTH_BYNUMBER(a,b,c,d) \ + if (test_mode == PCRE8_MODE) \ + a = pcre2_substring_length_bynumber_8(G(b,8),c,d); \ + else if (test_mode == PCRE16_MODE) \ + a = pcre2_substring_length_bynumber_16(G(b,16),c,d); \ + else \ + a = pcre2_substring_length_bynumber_32(G(b,32),c,d) + +#define PCRE2_SUBSTRING_LIST_GET(a,b,c,d) \ + if (test_mode == PCRE8_MODE) \ + a = pcre2_substring_list_get_8(G(b,8),(PCRE2_UCHAR8 ***)c,d); \ + else if (test_mode == PCRE16_MODE) \ + a = pcre2_substring_list_get_16(G(b,16),(PCRE2_UCHAR16 ***)c,d); \ + else \ + a = pcre2_substring_list_get_32(G(b,32),(PCRE2_UCHAR32 ***)c,d) + +#define PCRE2_SUBSTRING_LIST_FREE(a) \ + if (test_mode == PCRE8_MODE) \ + pcre2_substring_list_free_8((PCRE2_SPTR8 *)a); \ + else if (test_mode == PCRE16_MODE) \ + pcre2_substring_list_free_16((PCRE2_SPTR16 *)a); \ + else \ + pcre2_substring_list_free_32((PCRE2_SPTR32 *)a) + +#define PCRE2_SUBSTRING_NUMBER_FROM_NAME(a,b,c) \ + if (test_mode == PCRE8_MODE) \ + a = pcre2_substring_number_from_name_8(G(b,8),G(c,8)); \ + else if (test_mode == PCRE16_MODE) \ + a = pcre2_substring_number_from_name_16(G(b,16),G(c,16)); \ + else \ + a = pcre2_substring_number_from_name_32(G(b,32),G(c,32)) + +#define PTR(x) ( \ + (test_mode == PCRE8_MODE)? (void *)G(x,8) : \ + (test_mode == PCRE16_MODE)? (void *)G(x,16) : \ + (void *)G(x,32)) + +#define SETFLD(x,y,z) \ + if (test_mode == PCRE8_MODE) G(x,8)->y = z; \ + else if (test_mode == PCRE16_MODE) G(x,16)->y = z; \ + else G(x,32)->y = z + +#define SETFLDVEC(x,y,v,z) \ + if (test_mode == PCRE8_MODE) G(x,8)->y[v] = z; \ + else if (test_mode == PCRE16_MODE) G(x,16)->y[v] = z; \ + else G(x,32)->y[v] = z + +#define SETOP(x,y,z) \ + if (test_mode == PCRE8_MODE) G(x,8) z y; \ + else if (test_mode == PCRE16_MODE) G(x,16) z y; \ + else G(x,32) z y + +#define SETCASTPTR(x,y) \ + if (test_mode == PCRE8_MODE) \ + G(x,8) = (uint8_t *)(y); \ + else if (test_mode == PCRE16_MODE) \ + G(x,16) = (uint16_t *)(y); \ + else \ + G(x,32) = (uint32_t *)(y) + +#define STRLEN(p) ((test_mode == PCRE8_MODE)? ((int)strlen((char *)p)) : \ + (test_mode == PCRE16_MODE)? ((int)strlen16((PCRE2_SPTR16)p)) : \ + ((int)strlen32((PCRE2_SPTR32)p))) + +#define SUB1(a,b) \ + if (test_mode == PCRE8_MODE) G(a,8)(G(b,8)); \ + else if (test_mode == PCRE16_MODE) G(a,16)(G(b,16)); \ + else G(a,32)(G(b,32)) + +#define SUB2(a,b,c) \ + if (test_mode == PCRE8_MODE) G(a,8)(G(b,8),G(c,8)); \ + else if (test_mode == PCRE16_MODE) G(a,16)(G(b,16),G(c,16)); \ + else G(a,32)(G(b,32),G(c,32)) + +#define TEST(x,r,y) ( \ + (test_mode == PCRE8_MODE && G(x,8) r (y)) || \ + (test_mode == PCRE16_MODE && G(x,16) r (y)) || \ + (test_mode == PCRE32_MODE && G(x,32) r (y))) + +#define TESTFLD(x,f,r,y) ( \ + (test_mode == PCRE8_MODE && G(x,8)->f r (y)) || \ + (test_mode == PCRE16_MODE && G(x,16)->f r (y)) || \ + (test_mode == PCRE32_MODE && G(x,32)->f r (y))) + + +/* ----- Two out of three modes are supported ----- */ + +#else + +/* We can use some macro trickery to make a single set of definitions work in +the three different cases. */ + +/* ----- 32-bit and 16-bit but not 8-bit supported ----- */ + +#if defined(SUPPORT_PCRE2_32) && defined(SUPPORT_PCRE2_16) +#define BITONE 32 +#define BITTWO 16 + +/* ----- 32-bit and 8-bit but not 16-bit supported ----- */ + +#elif defined(SUPPORT_PCRE2_32) && defined(SUPPORT_PCRE2_8) +#define BITONE 32 +#define BITTWO 8 + +/* ----- 16-bit and 8-bit but not 32-bit supported ----- */ + +#else +#define BITONE 16 +#define BITTWO 8 +#endif + + +/* ----- Common macros for two-mode cases ----- */ + +#define BYTEONE (BITONE/8) +#define BYTETWO (BITTWO/8) + +#define CASTFLD(t,a,b) \ + ((test_mode == G(G(PCRE,BITONE),_MODE))? (t)(G(a,BITONE)->b) : \ + (t)(G(a,BITTWO)->b)) + +#define CASTVAR(t,x) ( \ + (test_mode == G(G(PCRE,BITONE),_MODE))? \ + (t)G(x,BITONE) : (t)G(x,BITTWO)) + +#define CODE_UNIT(a,b) ( \ + (test_mode == G(G(PCRE,BITONE),_MODE))? \ + (uint32_t)(((G(PCRE2_SPTR,BITONE))(a))[b]) : \ + (uint32_t)(((G(PCRE2_SPTR,BITTWO))(a))[b])) + +#define CONCTXCPY(a,b) \ + if (test_mode == G(G(PCRE,BITONE),_MODE)) \ + memcpy(G(a,BITONE),G(b,BITONE),sizeof(G(pcre2_convert_context_,BITONE))); \ + else \ + memcpy(G(a,BITTWO),G(b,BITTWO),sizeof(G(pcre2_convert_context_,BITTWO))) + +#define CONVERT_COPY(a,b,c) \ + (test_mode == G(G(PCRE,BITONE),_MODE))? \ + memcpy(G(a,BITONE),(char *)b,(c)*BYTEONE) : \ + memcpy(G(a,BITTWO),(char *)b,(c)*BYTETWO) + +#define DATCTXCPY(a,b) \ + if (test_mode == G(G(PCRE,BITONE),_MODE)) \ + memcpy(G(a,BITONE),G(b,BITONE),sizeof(G(pcre2_match_context_,BITONE))); \ + else \ + memcpy(G(a,BITTWO),G(b,BITTWO),sizeof(G(pcre2_match_context_,BITTWO))) + +#define FLD(a,b) \ + ((test_mode == G(G(PCRE,BITONE),_MODE))? G(a,BITONE)->b : G(a,BITTWO)->b) + +#define PATCTXCPY(a,b) \ + if (test_mode == G(G(PCRE,BITONE),_MODE)) \ + memcpy(G(a,BITONE),G(b,BITONE),sizeof(G(pcre2_compile_context_,BITONE))); \ + else \ + memcpy(G(a,BITTWO),G(b,BITTWO),sizeof(G(pcre2_compile_context_,BITTWO))) + +#define PCHARS(lv, p, offset, len, utf, f) \ + if (test_mode == G(G(PCRE,BITONE),_MODE)) \ + lv = G(pchars,BITONE)((G(PCRE2_SPTR,BITONE))(p)+offset, len, utf, f); \ + else \ + lv = G(pchars,BITTWO)((G(PCRE2_SPTR,BITTWO))(p)+offset, len, utf, f) + +#define PCHARSV(p, offset, len, utf, f) \ + if (test_mode == G(G(PCRE,BITONE),_MODE)) \ + (void)G(pchars,BITONE)((G(PCRE2_SPTR,BITONE))(p)+offset, len, utf, f); \ + else \ + (void)G(pchars,BITTWO)((G(PCRE2_SPTR,BITTWO))(p)+offset, len, utf, f) + +#define PCRE2_CALLOUT_ENUMERATE(a,b,c) \ + if (test_mode == G(G(PCRE,BITONE),_MODE)) \ + a = G(pcre2_callout_enumerate,BITONE)(G(compiled_code,BITONE), \ + (int (*)(struct G(pcre2_callout_enumerate_block_,BITONE) *, void *))b,c); \ + else \ + a = G(pcre2_callout_enumerate,BITTWO)(G(compiled_code,BITTWO), \ + (int (*)(struct G(pcre2_callout_enumerate_block_,BITTWO) *, void *))b,c) + +#define PCRE2_CODE_COPY_FROM_VOID(a,b) \ + if (test_mode == G(G(PCRE,BITONE),_MODE)) \ + G(a,BITONE) = G(pcre2_code_copy_,BITONE)(b); \ + else \ + G(a,BITTWO) = G(pcre2_code_copy_,BITTWO)(b) + +#define PCRE2_CODE_COPY_TO_VOID(a,b) \ + if (test_mode == G(G(PCRE,BITONE),_MODE)) \ + a = (void *)G(pcre2_code_copy_,BITONE)(G(b,BITONE)); \ + else \ + a = (void *)G(pcre2_code_copy_,BITTWO)(G(b,BITTWO)) + +#define PCRE2_CODE_COPY_WITH_TABLES_TO_VOID(a,b) \ + if (test_mode == G(G(PCRE,BITONE),_MODE)) \ + a = (void *)G(pcre2_code_copy_with_tables_,BITONE)(G(b,BITONE)); \ + else \ + a = (void *)G(pcre2_code_copy_with_tables_,BITTWO)(G(b,BITTWO)) + +#define PCRE2_COMPILE(a,b,c,d,e,f,g) \ + if (test_mode == G(G(PCRE,BITONE),_MODE)) \ + G(a,BITONE) = G(pcre2_compile_,BITONE)(G(b,BITONE),c,d,e,f,g); \ + else \ + G(a,BITTWO) = G(pcre2_compile_,BITTWO)(G(b,BITTWO),c,d,e,f,g) + +#define PCRE2_CONVERTED_PATTERN_FREE(a) \ + if (test_mode == G(G(PCRE,BITONE),_MODE)) \ + G(pcre2_converted_pattern_free_,BITONE)((G(PCRE2_UCHAR,BITONE) *)a); \ + else \ + G(pcre2_converted_pattern_free_,BITTWO)((G(PCRE2_UCHAR,BITTWO) *)a) + +#define PCRE2_DFA_MATCH(a,b,c,d,e,f,g,h,i,j) \ + if (test_mode == G(G(PCRE,BITONE),_MODE)) \ + a = G(pcre2_dfa_match_,BITONE)(G(b,BITONE),(G(PCRE2_SPTR,BITONE))c,d,e,f, \ + G(g,BITONE),h,i,j); \ + else \ + a = G(pcre2_dfa_match_,BITTWO)(G(b,BITTWO),(G(PCRE2_SPTR,BITTWO))c,d,e,f, \ + G(g,BITTWO),h,i,j) + +#define PCRE2_GET_ERROR_MESSAGE(r,a,b) \ + if (test_mode == G(G(PCRE,BITONE),_MODE)) \ + r = G(pcre2_get_error_message_,BITONE)(a,G(b,BITONE),G(G(b,BITONE),_size/BYTEONE)); \ + else \ + r = G(pcre2_get_error_message_,BITTWO)(a,G(b,BITTWO),G(G(b,BITTWO),_size/BYTETWO)) + +#define PCRE2_GET_OVECTOR_COUNT(a,b) \ + if (test_mode == G(G(PCRE,BITONE),_MODE)) \ + a = G(pcre2_get_ovector_count_,BITONE)(G(b,BITONE)); \ + else \ + a = G(pcre2_get_ovector_count_,BITTWO)(G(b,BITTWO)) + +#define PCRE2_GET_STARTCHAR(a,b) \ + if (test_mode == G(G(PCRE,BITONE),_MODE)) \ + a = G(pcre2_get_startchar_,BITONE)(G(b,BITONE)); \ + else \ + a = G(pcre2_get_startchar_,BITTWO)(G(b,BITTWO)) + +#define PCRE2_JIT_COMPILE(r,a,b) \ + if (test_mode == G(G(PCRE,BITONE),_MODE)) \ + r = G(pcre2_jit_compile_,BITONE)(G(a,BITONE),b); \ + else \ + r = G(pcre2_jit_compile_,BITTWO)(G(a,BITTWO),b) + +#define PCRE2_JIT_FREE_UNUSED_MEMORY(a) \ + if (test_mode == G(G(PCRE,BITONE),_MODE)) \ + G(pcre2_jit_free_unused_memory_,BITONE)(G(a,BITONE)); \ + else \ + G(pcre2_jit_free_unused_memory_,BITTWO)(G(a,BITTWO)) + +#define PCRE2_JIT_MATCH(a,b,c,d,e,f,g,h) \ + if (test_mode == G(G(PCRE,BITONE),_MODE)) \ + a = G(pcre2_jit_match_,BITONE)(G(b,BITONE),(G(PCRE2_SPTR,BITONE))c,d,e,f, \ + G(g,BITONE),h); \ + else \ + a = G(pcre2_jit_match_,BITTWO)(G(b,BITTWO),(G(PCRE2_SPTR,BITTWO))c,d,e,f, \ + G(g,BITTWO),h) + +#define PCRE2_JIT_STACK_CREATE(a,b,c,d) \ + if (test_mode == G(G(PCRE,BITONE),_MODE)) \ + a = (PCRE2_JIT_STACK *)G(pcre2_jit_stack_create_,BITONE)(b,c,d); \ + else \ + a = (PCRE2_JIT_STACK *)G(pcre2_jit_stack_create_,BITTWO)(b,c,d); \ + +#define PCRE2_JIT_STACK_ASSIGN(a,b,c) \ + if (test_mode == G(G(PCRE,BITONE),_MODE)) \ + G(pcre2_jit_stack_assign_,BITONE)(G(a,BITONE),(G(pcre2_jit_callback_,BITONE))b,c); \ + else \ + G(pcre2_jit_stack_assign_,BITTWO)(G(a,BITTWO),(G(pcre2_jit_callback_,BITTWO))b,c); + +#define PCRE2_JIT_STACK_FREE(a) \ + if (test_mode == G(G(PCRE,BITONE),_MODE)) \ + G(pcre2_jit_stack_free_,BITONE)((G(pcre2_jit_stack_,BITONE) *)a); \ + else \ + G(pcre2_jit_stack_free_,BITTWO)((G(pcre2_jit_stack_,BITTWO) *)a); + +#define PCRE2_MAKETABLES(a) \ + if (test_mode == G(G(PCRE,BITONE),_MODE)) \ + a = G(pcre2_maketables_,BITONE)(NULL); \ + else \ + a = G(pcre2_maketables_,BITTWO)(NULL) + +#define PCRE2_MATCH(a,b,c,d,e,f,g,h) \ + if (test_mode == G(G(PCRE,BITONE),_MODE)) \ + a = G(pcre2_match_,BITONE)(G(b,BITONE),(G(PCRE2_SPTR,BITONE))c,d,e,f, \ + G(g,BITONE),h); \ + else \ + a = G(pcre2_match_,BITTWO)(G(b,BITTWO),(G(PCRE2_SPTR,BITTWO))c,d,e,f, \ + G(g,BITTWO),h) + +#define PCRE2_MATCH_DATA_CREATE(a,b,c) \ + if (test_mode == G(G(PCRE,BITONE),_MODE)) \ + G(a,BITONE) = G(pcre2_match_data_create_,BITONE)(b,c); \ + else \ + G(a,BITTWO) = G(pcre2_match_data_create_,BITTWO)(b,c) + +#define PCRE2_MATCH_DATA_CREATE_FROM_PATTERN(a,b,c) \ + if (test_mode == G(G(PCRE,BITONE),_MODE)) \ + G(a,BITONE) = G(pcre2_match_data_create_from_pattern_,BITONE)(G(b,BITONE),c); \ + else \ + G(a,BITTWO) = G(pcre2_match_data_create_from_pattern_,BITTWO)(G(b,BITTWO),c) + +#define PCRE2_MATCH_DATA_FREE(a) \ + if (test_mode == G(G(PCRE,BITONE),_MODE)) \ + G(pcre2_match_data_free_,BITONE)(G(a,BITONE)); \ + else \ + G(pcre2_match_data_free_,BITTWO)(G(a,BITTWO)) + +#define PCRE2_PATTERN_CONVERT(a,b,c,d,e,f,g) \ + if (test_mode == G(G(PCRE,BITONE),_MODE)) \ + a = G(pcre2_pattern_convert_,BITONE)(G(b,BITONE),c,d,(G(PCRE2_UCHAR,BITONE) **)e,f,G(g,BITONE)); \ + else \ + a = G(pcre2_pattern_convert_,BITTWO)(G(b,BITTWO),c,d,(G(PCRE2_UCHAR,BITTWO) **)e,f,G(g,BITTWO)) + +#define PCRE2_PATTERN_INFO(a,b,c,d) \ + if (test_mode == G(G(PCRE,BITONE),_MODE)) \ + a = G(pcre2_pattern_info_,BITONE)(G(b,BITONE),c,d); \ + else \ + a = G(pcre2_pattern_info_,BITTWO)(G(b,BITTWO),c,d) + +#define PCRE2_PRINTINT(a) \ + if (test_mode == G(G(PCRE,BITONE),_MODE)) \ + G(pcre2_printint_,BITONE)(G(compiled_code,BITONE),outfile,a); \ + else \ + G(pcre2_printint_,BITTWO)(G(compiled_code,BITTWO),outfile,a) + +#define PCRE2_SERIALIZE_DECODE(r,a,b,c,d) \ + if (test_mode == G(G(PCRE,BITONE),_MODE)) \ + r = G(pcre2_serialize_decode_,BITONE)((G(pcre2_code_,BITONE) **)a,b,c,G(d,BITONE)); \ + else \ + r = G(pcre2_serialize_decode_,BITTWO)((G(pcre2_code_,BITTWO) **)a,b,c,G(d,BITTWO)) + +#define PCRE2_SERIALIZE_ENCODE(r,a,b,c,d,e) \ + if (test_mode == G(G(PCRE,BITONE),_MODE)) \ + r = G(pcre2_serialize_encode_,BITONE)((G(const pcre2_code_,BITONE) **)a,b,c,d,G(e,BITONE)); \ + else \ + r = G(pcre2_serialize_encode_,BITTWO)((G(const pcre2_code_,BITTWO) **)a,b,c,d,G(e,BITTWO)) + +#define PCRE2_SERIALIZE_FREE(a) \ + if (test_mode == G(G(PCRE,BITONE),_MODE)) \ + G(pcre2_serialize_free_,BITONE)(a); \ + else \ + G(pcre2_serialize_free_,BITTWO)(a) + +#define PCRE2_SERIALIZE_GET_NUMBER_OF_CODES(r,a) \ + if (test_mode == G(G(PCRE,BITONE),_MODE)) \ + r = G(pcre2_serialize_get_number_of_codes_,BITONE)(a); \ + else \ + r = G(pcre2_serialize_get_number_of_codes_,BITTWO)(a) + +#define PCRE2_SET_CALLOUT(a,b,c) \ + if (test_mode == G(G(PCRE,BITONE),_MODE)) \ + G(pcre2_set_callout_,BITONE)(G(a,BITONE), \ + (int (*)(G(pcre2_callout_block_,BITONE) *, void *))b,c); \ + else \ + G(pcre2_set_callout_,BITTWO)(G(a,BITTWO), \ + (int (*)(G(pcre2_callout_block_,BITTWO) *, void *))b,c); + +#define PCRE2_SET_CHARACTER_TABLES(a,b) \ + if (test_mode == G(G(PCRE,BITONE),_MODE)) \ + G(pcre2_set_character_tables_,BITONE)(G(a,BITONE),b); \ + else \ + G(pcre2_set_character_tables_,BITTWO)(G(a,BITTWO),b) + +#define PCRE2_SET_COMPILE_RECURSION_GUARD(a,b,c) \ + if (test_mode == G(G(PCRE,BITONE),_MODE)) \ + G(pcre2_set_compile_recursion_guard_,BITONE)(G(a,BITONE),b,c); \ + else \ + G(pcre2_set_compile_recursion_guard_,BITTWO)(G(a,BITTWO),b,c) + +#define PCRE2_SET_DEPTH_LIMIT(a,b) \ + if (test_mode == G(G(PCRE,BITONE),_MODE)) \ + G(pcre2_set_depth_limit_,BITONE)(G(a,BITONE),b); \ + else \ + G(pcre2_set_depth_limit_,BITTWO)(G(a,BITTWO),b) + +#define PCRE2_SET_GLOB_ESCAPE(r,a,b) \ + if (test_mode == G(G(PCRE,BITONE),_MODE)) \ + r = G(pcre2_set_glob_escape_,BITONE)(G(a,BITONE),b); \ + else \ + r = G(pcre2_set_glob_escape_,BITTWO)(G(a,BITTWO),b) + +#define PCRE2_SET_GLOB_SEPARATOR(r,a,b) \ + if (test_mode == G(G(PCRE,BITONE),_MODE)) \ + r = G(pcre2_set_glob_separator_,BITONE)(G(a,BITONE),b); \ + else \ + r = G(pcre2_set_glob_separator_,BITTWO)(G(a,BITTWO),b) + +#define PCRE2_SET_HEAP_LIMIT(a,b) \ + if (test_mode == G(G(PCRE,BITONE),_MODE)) \ + G(pcre2_set_heap_limit_,BITONE)(G(a,BITONE),b); \ + else \ + G(pcre2_set_heap_limit_,BITTWO)(G(a,BITTWO),b) + +#define PCRE2_SET_MATCH_LIMIT(a,b) \ + if (test_mode == G(G(PCRE,BITONE),_MODE)) \ + G(pcre2_set_match_limit_,BITONE)(G(a,BITONE),b); \ + else \ + G(pcre2_set_match_limit_,BITTWO)(G(a,BITTWO),b) + +#define PCRE2_SET_MAX_PATTERN_LENGTH(a,b) \ + if (test_mode == G(G(PCRE,BITONE),_MODE)) \ + G(pcre2_set_max_pattern_length_,BITONE)(G(a,BITONE),b); \ + else \ + G(pcre2_set_max_pattern_length_,BITTWO)(G(a,BITTWO),b) + +#define PCRE2_SET_OFFSET_LIMIT(a,b) \ + if (test_mode == G(G(PCRE,BITONE),_MODE)) \ + G(pcre2_set_offset_limit_,BITONE)(G(a,BITONE),b); \ + else \ + G(pcre2_set_offset_limit_,BITTWO)(G(a,BITTWO),b) + +#define PCRE2_SET_PARENS_NEST_LIMIT(a,b) \ + if (test_mode == G(G(PCRE,BITONE),_MODE)) \ + G(pcre2_set_parens_nest_limit_,BITONE)(G(a,BITONE),b); \ + else \ + G(pcre2_set_parens_nest_limit_,BITTWO)(G(a,BITTWO),b) + +#define PCRE2_SUBSTITUTE(a,b,c,d,e,f,g,h,i,j,k,l) \ + if (test_mode == G(G(PCRE,BITONE),_MODE)) \ + a = G(pcre2_substitute_,BITONE)(G(b,BITONE),(G(PCRE2_SPTR,BITONE))c,d,e,f, \ + G(g,BITONE),G(h,BITONE),(G(PCRE2_SPTR,BITONE))i,j, \ + (G(PCRE2_UCHAR,BITONE) *)k,l); \ + else \ + a = G(pcre2_substitute_,BITTWO)(G(b,BITTWO),(G(PCRE2_SPTR,BITTWO))c,d,e,f, \ + G(g,BITTWO),G(h,BITTWO),(G(PCRE2_SPTR,BITTWO))i,j, \ + (G(PCRE2_UCHAR,BITTWO) *)k,l) + +#define PCRE2_SUBSTRING_COPY_BYNAME(a,b,c,d,e) \ + if (test_mode == G(G(PCRE,BITONE),_MODE)) \ + a = G(pcre2_substring_copy_byname_,BITONE)(G(b,BITONE),G(c,BITONE),\ + (G(PCRE2_UCHAR,BITONE) *)d,e); \ + else \ + a = G(pcre2_substring_copy_byname_,BITTWO)(G(b,BITTWO),G(c,BITTWO),\ + (G(PCRE2_UCHAR,BITTWO) *)d,e) + +#define PCRE2_SUBSTRING_COPY_BYNUMBER(a,b,c,d,e) \ + if (test_mode == G(G(PCRE,BITONE),_MODE)) \ + a = G(pcre2_substring_copy_bynumber_,BITONE)(G(b,BITONE),c,\ + (G(PCRE2_UCHAR,BITONE) *)d,e); \ + else \ + a = G(pcre2_substring_copy_bynumber_,BITTWO)(G(b,BITTWO),c,\ + (G(PCRE2_UCHAR,BITTWO) *)d,e) + +#define PCRE2_SUBSTRING_FREE(a) \ + if (test_mode == G(G(PCRE,BITONE),_MODE)) \ + G(pcre2_substring_free_,BITONE)((G(PCRE2_UCHAR,BITONE) *)a); \ + else G(pcre2_substring_free_,BITTWO)((G(PCRE2_UCHAR,BITTWO) *)a) + +#define PCRE2_SUBSTRING_GET_BYNAME(a,b,c,d,e) \ + if (test_mode == G(G(PCRE,BITONE),_MODE)) \ + a = G(pcre2_substring_get_byname_,BITONE)(G(b,BITONE),G(c,BITONE),\ + (G(PCRE2_UCHAR,BITONE) **)d,e); \ + else \ + a = G(pcre2_substring_get_byname_,BITTWO)(G(b,BITTWO),G(c,BITTWO),\ + (G(PCRE2_UCHAR,BITTWO) **)d,e) + +#define PCRE2_SUBSTRING_GET_BYNUMBER(a,b,c,d,e) \ + if (test_mode == G(G(PCRE,BITONE),_MODE)) \ + a = G(pcre2_substring_get_bynumber_,BITONE)(G(b,BITONE),c,\ + (G(PCRE2_UCHAR,BITONE) **)d,e); \ + else \ + a = G(pcre2_substring_get_bynumber_,BITTWO)(G(b,BITTWO),c,\ + (G(PCRE2_UCHAR,BITTWO) **)d,e) + +#define PCRE2_SUBSTRING_LENGTH_BYNAME(a,b,c,d) \ + if (test_mode == G(G(PCRE,BITONE),_MODE)) \ + a = G(pcre2_substring_length_byname_,BITONE)(G(b,BITONE),G(c,BITONE),d); \ + else \ + a = G(pcre2_substring_length_byname_,BITTWO)(G(b,BITTWO),G(c,BITTWO),d) + +#define PCRE2_SUBSTRING_LENGTH_BYNUMBER(a,b,c,d) \ + if (test_mode == G(G(PCRE,BITONE),_MODE)) \ + a = G(pcre2_substring_length_bynumber_,BITONE)(G(b,BITONE),c,d); \ + else \ + a = G(pcre2_substring_length_bynumber_,BITTWO)(G(b,BITTWO),c,d) + +#define PCRE2_SUBSTRING_LIST_GET(a,b,c,d) \ + if (test_mode == G(G(PCRE,BITONE),_MODE)) \ + a = G(pcre2_substring_list_get_,BITONE)(G(b,BITONE), \ + (G(PCRE2_UCHAR,BITONE) ***)c,d); \ + else \ + a = G(pcre2_substring_list_get_,BITTWO)(G(b,BITTWO), \ + (G(PCRE2_UCHAR,BITTWO) ***)c,d) + +#define PCRE2_SUBSTRING_LIST_FREE(a) \ + if (test_mode == G(G(PCRE,BITONE),_MODE)) \ + G(pcre2_substring_list_free_,BITONE)((G(PCRE2_SPTR,BITONE) *)a); \ + else \ + G(pcre2_substring_list_free_,BITTWO)((G(PCRE2_SPTR,BITTWO) *)a) + +#define PCRE2_SUBSTRING_NUMBER_FROM_NAME(a,b,c) \ + if (test_mode == G(G(PCRE,BITONE),_MODE)) \ + a = G(pcre2_substring_number_from_name_,BITONE)(G(b,BITONE),G(c,BITONE)); \ + else \ + a = G(pcre2_substring_number_from_name_,BITTWO)(G(b,BITTWO),G(c,BITTWO)) + +#define PTR(x) ( \ + (test_mode == G(G(PCRE,BITONE),_MODE))? (void *)G(x,BITONE) : \ + (void *)G(x,BITTWO)) + +#define SETFLD(x,y,z) \ + if (test_mode == G(G(PCRE,BITONE),_MODE)) G(x,BITONE)->y = z; \ + else G(x,BITTWO)->y = z + +#define SETFLDVEC(x,y,v,z) \ + if (test_mode == G(G(PCRE,BITONE),_MODE)) G(x,BITONE)->y[v] = z; \ + else G(x,BITTWO)->y[v] = z + +#define SETOP(x,y,z) \ + if (test_mode == G(G(PCRE,BITONE),_MODE)) G(x,BITONE) z y; \ + else G(x,BITTWO) z y + +#define SETCASTPTR(x,y) \ + if (test_mode == G(G(PCRE,BITONE),_MODE)) \ + G(x,BITONE) = (G(G(uint,BITONE),_t) *)(y); \ + else \ + G(x,BITTWO) = (G(G(uint,BITTWO),_t) *)(y) + +#define STRLEN(p) ((test_mode == G(G(PCRE,BITONE),_MODE))? \ + G(strlen,BITONE)((G(PCRE2_SPTR,BITONE))p) : \ + G(strlen,BITTWO)((G(PCRE2_SPTR,BITTWO))p)) + +#define SUB1(a,b) \ + if (test_mode == G(G(PCRE,BITONE),_MODE)) \ + G(a,BITONE)(G(b,BITONE)); \ + else \ + G(a,BITTWO)(G(b,BITTWO)) + +#define SUB2(a,b,c) \ + if (test_mode == G(G(PCRE,BITONE),_MODE)) \ + G(a,BITONE))(G(b,BITONE),G(c,BITONE)); \ + else \ + G(a,BITTWO))(G(b,BITTWO),G(c,BITTWO)) + +#define TEST(x,r,y) ( \ + (test_mode == G(G(PCRE,BITONE),_MODE) && G(x,BITONE) r (y)) || \ + (test_mode == G(G(PCRE,BITTWO),_MODE) && G(x,BITTWO) r (y))) + +#define TESTFLD(x,f,r,y) ( \ + (test_mode == G(G(PCRE,BITONE),_MODE) && G(x,BITONE)->f r (y)) || \ + (test_mode == G(G(PCRE,BITTWO),_MODE) && G(x,BITTWO)->f r (y))) + + +#endif /* Two out of three modes */ + +/* ----- End of cases where more than one mode is supported ----- */ + + +/* ----- Only 8-bit mode is supported ----- */ + +#elif defined SUPPORT_PCRE2_8 +#define CASTFLD(t,a,b) (t)(G(a,8)->b) +#define CASTVAR(t,x) (t)G(x,8) +#define CODE_UNIT(a,b) (uint32_t)(((PCRE2_SPTR8)(a))[b]) +#define CONCTXCPY(a,b) memcpy(G(a,8),G(b,8),sizeof(pcre2_convert_context_8)) +#define CONVERT_COPY(a,b,c) memcpy(G(a,8),(char *)b, c) +#define DATCTXCPY(a,b) memcpy(G(a,8),G(b,8),sizeof(pcre2_match_context_8)) +#define FLD(a,b) G(a,8)->b +#define PATCTXCPY(a,b) memcpy(G(a,8),G(b,8),sizeof(pcre2_compile_context_8)) +#define PCHARS(lv, p, offset, len, utf, f) \ + lv = pchars8((PCRE2_SPTR8)(p)+offset, len, utf, f) +#define PCHARSV(p, offset, len, utf, f) \ + (void)pchars8((PCRE2_SPTR8)(p)+offset, len, utf, f) +#define PCRE2_CALLOUT_ENUMERATE(a,b,c) \ + a = pcre2_callout_enumerate_8(compiled_code8, \ + (int (*)(struct pcre2_callout_enumerate_block_8 *, void *))b,c) +#define PCRE2_CODE_COPY_FROM_VOID(a,b) G(a,8) = pcre2_code_copy_8(b) +#define PCRE2_CODE_COPY_TO_VOID(a,b) a = (void *)pcre2_code_copy_8(G(b,8)) +#define PCRE2_CODE_COPY_WITH_TABLES_TO_VOID(a,b) a = (void *)pcre2_code_copy_with_tables_8(G(b,8)) +#define PCRE2_COMPILE(a,b,c,d,e,f,g) \ + G(a,8) = pcre2_compile_8(G(b,8),c,d,e,f,g) +#define PCRE2_CONVERTED_PATTERN_FREE(a) \ + pcre2_converted_pattern_free_8((PCRE2_UCHAR8 *)a) +#define PCRE2_DFA_MATCH(a,b,c,d,e,f,g,h,i,j) \ + a = pcre2_dfa_match_8(G(b,8),(PCRE2_SPTR8)c,d,e,f,G(g,8),h,i,j) +#define PCRE2_GET_ERROR_MESSAGE(r,a,b) \ + r = pcre2_get_error_message_8(a,G(b,8),G(G(b,8),_size)) +#define PCRE2_GET_OVECTOR_COUNT(a,b) a = pcre2_get_ovector_count_8(G(b,8)) +#define PCRE2_GET_STARTCHAR(a,b) a = pcre2_get_startchar_8(G(b,8)) +#define PCRE2_JIT_COMPILE(r,a,b) r = pcre2_jit_compile_8(G(a,8),b) +#define PCRE2_JIT_FREE_UNUSED_MEMORY(a) pcre2_jit_free_unused_memory_8(G(a,8)) +#define PCRE2_JIT_MATCH(a,b,c,d,e,f,g,h) \ + a = pcre2_jit_match_8(G(b,8),(PCRE2_SPTR8)c,d,e,f,G(g,8),h) +#define PCRE2_JIT_STACK_CREATE(a,b,c,d) \ + a = (PCRE2_JIT_STACK *)pcre2_jit_stack_create_8(b,c,d); +#define PCRE2_JIT_STACK_ASSIGN(a,b,c) \ + pcre2_jit_stack_assign_8(G(a,8),(pcre2_jit_callback_8)b,c); +#define PCRE2_JIT_STACK_FREE(a) pcre2_jit_stack_free_8((pcre2_jit_stack_8 *)a); +#define PCRE2_MAKETABLES(a) a = pcre2_maketables_8(NULL) +#define PCRE2_MATCH(a,b,c,d,e,f,g,h) \ + a = pcre2_match_8(G(b,8),(PCRE2_SPTR8)c,d,e,f,G(g,8),h) +#define PCRE2_MATCH_DATA_CREATE(a,b,c) G(a,8) = pcre2_match_data_create_8(b,c) +#define PCRE2_MATCH_DATA_CREATE_FROM_PATTERN(a,b,c) \ + G(a,8) = pcre2_match_data_create_from_pattern_8(G(b,8),c) +#define PCRE2_MATCH_DATA_FREE(a) pcre2_match_data_free_8(G(a,8)) +#define PCRE2_PATTERN_CONVERT(a,b,c,d,e,f,g) a = pcre2_pattern_convert_8(G(b,8),c,d,(PCRE2_UCHAR8 **)e,f,G(g,8)) +#define PCRE2_PATTERN_INFO(a,b,c,d) a = pcre2_pattern_info_8(G(b,8),c,d) +#define PCRE2_PRINTINT(a) pcre2_printint_8(compiled_code8,outfile,a) +#define PCRE2_SERIALIZE_DECODE(r,a,b,c,d) \ + r = pcre2_serialize_decode_8((pcre2_code_8 **)a,b,c,G(d,8)) +#define PCRE2_SERIALIZE_ENCODE(r,a,b,c,d,e) \ + r = pcre2_serialize_encode_8((const pcre2_code_8 **)a,b,c,d,G(e,8)) +#define PCRE2_SERIALIZE_FREE(a) pcre2_serialize_free_8(a) +#define PCRE2_SERIALIZE_GET_NUMBER_OF_CODES(r,a) \ + r = pcre2_serialize_get_number_of_codes_8(a) +#define PCRE2_SET_CALLOUT(a,b,c) \ + pcre2_set_callout_8(G(a,8),(int (*)(pcre2_callout_block_8 *, void *))b,c) +#define PCRE2_SET_CHARACTER_TABLES(a,b) pcre2_set_character_tables_8(G(a,8),b) +#define PCRE2_SET_COMPILE_RECURSION_GUARD(a,b,c) \ + pcre2_set_compile_recursion_guard_8(G(a,8),b,c) +#define PCRE2_SET_DEPTH_LIMIT(a,b) pcre2_set_depth_limit_8(G(a,8),b) +#define PCRE2_SET_GLOB_ESCAPE(r,a,b) r = pcre2_set_glob_escape_8(G(a,8),b) +#define PCRE2_SET_GLOB_SEPARATOR(r,a,b) r = pcre2_set_glob_separator_8(G(a,8),b) +#define PCRE2_SET_HEAP_LIMIT(a,b) pcre2_set_heap_limit_8(G(a,8),b) +#define PCRE2_SET_MATCH_LIMIT(a,b) pcre2_set_match_limit_8(G(a,8),b) +#define PCRE2_SET_MAX_PATTERN_LENGTH(a,b) pcre2_set_max_pattern_length_8(G(a,8),b) +#define PCRE2_SET_OFFSET_LIMIT(a,b) pcre2_set_offset_limit_8(G(a,8),b) +#define PCRE2_SET_PARENS_NEST_LIMIT(a,b) pcre2_set_parens_nest_limit_8(G(a,8),b) +#define PCRE2_SUBSTITUTE(a,b,c,d,e,f,g,h,i,j,k,l) \ + a = pcre2_substitute_8(G(b,8),(PCRE2_SPTR8)c,d,e,f,G(g,8),G(h,8), \ + (PCRE2_SPTR8)i,j,(PCRE2_UCHAR8 *)k,l) +#define PCRE2_SUBSTRING_COPY_BYNAME(a,b,c,d,e) \ + a = pcre2_substring_copy_byname_8(G(b,8),G(c,8),(PCRE2_UCHAR8 *)d,e) +#define PCRE2_SUBSTRING_COPY_BYNUMBER(a,b,c,d,e) \ + a = pcre2_substring_copy_bynumber_8(G(b,8),c,(PCRE2_UCHAR8 *)d,e) +#define PCRE2_SUBSTRING_FREE(a) pcre2_substring_free_8((PCRE2_UCHAR8 *)a) +#define PCRE2_SUBSTRING_GET_BYNAME(a,b,c,d,e) \ + a = pcre2_substring_get_byname_8(G(b,8),G(c,8),(PCRE2_UCHAR8 **)d,e) +#define PCRE2_SUBSTRING_GET_BYNUMBER(a,b,c,d,e) \ + a = pcre2_substring_get_bynumber_8(G(b,8),c,(PCRE2_UCHAR8 **)d,e) +#define PCRE2_SUBSTRING_LENGTH_BYNAME(a,b,c,d) \ + a = pcre2_substring_length_byname_8(G(b,8),G(c,8),d) +#define PCRE2_SUBSTRING_LENGTH_BYNUMBER(a,b,c,d) \ + a = pcre2_substring_length_bynumber_8(G(b,8),c,d) +#define PCRE2_SUBSTRING_LIST_GET(a,b,c,d) \ + a = pcre2_substring_list_get_8(G(b,8),(PCRE2_UCHAR8 ***)c,d) +#define PCRE2_SUBSTRING_LIST_FREE(a) \ + pcre2_substring_list_free_8((PCRE2_SPTR8 *)a) +#define PCRE2_SUBSTRING_NUMBER_FROM_NAME(a,b,c) \ + a = pcre2_substring_number_from_name_8(G(b,8),G(c,8)); +#define PTR(x) (void *)G(x,8) +#define SETFLD(x,y,z) G(x,8)->y = z +#define SETFLDVEC(x,y,v,z) G(x,8)->y[v] = z +#define SETOP(x,y,z) G(x,8) z y +#define SETCASTPTR(x,y) G(x,8) = (uint8_t *)(y) +#define STRLEN(p) (int)strlen((char *)p) +#define SUB1(a,b) G(a,8)(G(b,8)) +#define SUB2(a,b,c) G(a,8)(G(b,8),G(c,8)) +#define TEST(x,r,y) (G(x,8) r (y)) +#define TESTFLD(x,f,r,y) (G(x,8)->f r (y)) + + +/* ----- Only 16-bit mode is supported ----- */ + +#elif defined SUPPORT_PCRE2_16 +#define CASTFLD(t,a,b) (t)(G(a,16)->b) +#define CASTVAR(t,x) (t)G(x,16) +#define CODE_UNIT(a,b) (uint32_t)(((PCRE2_SPTR16)(a))[b]) +#define CONCTXCPY(a,b) memcpy(G(a,16),G(b,16),sizeof(pcre2_convert_context_16)) +#define CONVERT_COPY(a,b,c) memcpy(G(a,16),(char *)b, (c)*2) +#define DATCTXCPY(a,b) memcpy(G(a,16),G(b,16),sizeof(pcre2_match_context_16)) +#define FLD(a,b) G(a,16)->b +#define PATCTXCPY(a,b) memcpy(G(a,16),G(b,16),sizeof(pcre2_compile_context_16)) +#define PCHARS(lv, p, offset, len, utf, f) \ + lv = pchars16((PCRE2_SPTR16)(p)+offset, len, utf, f) +#define PCHARSV(p, offset, len, utf, f) \ + (void)pchars16((PCRE2_SPTR16)(p)+offset, len, utf, f) +#define PCRE2_CALLOUT_ENUMERATE(a,b,c) \ + a = pcre2_callout_enumerate_16(compiled_code16, \ + (int (*)(struct pcre2_callout_enumerate_block_16 *, void *))b,c) +#define PCRE2_CODE_COPY_FROM_VOID(a,b) G(a,16) = pcre2_code_copy_16(b) +#define PCRE2_CODE_COPY_TO_VOID(a,b) a = (void *)pcre2_code_copy_16(G(b,16)) +#define PCRE2_CODE_COPY_WITH_TABLES_TO_VOID(a,b) a = (void *)pcre2_code_copy_with_tables_16(G(b,16)) +#define PCRE2_COMPILE(a,b,c,d,e,f,g) \ + G(a,16) = pcre2_compile_16(G(b,16),c,d,e,f,g) +#define PCRE2_CONVERTED_PATTERN_FREE(a) \ + pcre2_converted_pattern_free_16((PCRE2_UCHAR16 *)a) +#define PCRE2_DFA_MATCH(a,b,c,d,e,f,g,h,i,j) \ + a = pcre2_dfa_match_16(G(b,16),(PCRE2_SPTR16)c,d,e,f,G(g,16),h,i,j) +#define PCRE2_GET_ERROR_MESSAGE(r,a,b) \ + r = pcre2_get_error_message_16(a,G(b,16),G(G(b,16),_size/2)) +#define PCRE2_GET_OVECTOR_COUNT(a,b) a = pcre2_get_ovector_count_16(G(b,16)) +#define PCRE2_GET_STARTCHAR(a,b) a = pcre2_get_startchar_16(G(b,16)) +#define PCRE2_JIT_COMPILE(r,a,b) r = pcre2_jit_compile_16(G(a,16),b) +#define PCRE2_JIT_FREE_UNUSED_MEMORY(a) pcre2_jit_free_unused_memory_16(G(a,16)) +#define PCRE2_JIT_MATCH(a,b,c,d,e,f,g,h) \ + a = pcre2_jit_match_16(G(b,16),(PCRE2_SPTR16)c,d,e,f,G(g,16),h) +#define PCRE2_JIT_STACK_CREATE(a,b,c,d) \ + a = (PCRE2_JIT_STACK *)pcre2_jit_stack_create_16(b,c,d); +#define PCRE2_JIT_STACK_ASSIGN(a,b,c) \ + pcre2_jit_stack_assign_16(G(a,16),(pcre2_jit_callback_16)b,c); +#define PCRE2_JIT_STACK_FREE(a) pcre2_jit_stack_free_16((pcre2_jit_stack_16 *)a); +#define PCRE2_MAKETABLES(a) a = pcre2_maketables_16(NULL) +#define PCRE2_MATCH(a,b,c,d,e,f,g,h) \ + a = pcre2_match_16(G(b,16),(PCRE2_SPTR16)c,d,e,f,G(g,16),h) +#define PCRE2_MATCH_DATA_CREATE(a,b,c) G(a,16) = pcre2_match_data_create_16(b,c) +#define PCRE2_MATCH_DATA_CREATE_FROM_PATTERN(a,b,c) \ + G(a,16) = pcre2_match_data_create_from_pattern_16(G(b,16),c) +#define PCRE2_MATCH_DATA_FREE(a) pcre2_match_data_free_16(G(a,16)) +#define PCRE2_PATTERN_CONVERT(a,b,c,d,e,f,g) a = pcre2_pattern_convert_16(G(b,16),c,d,(PCRE2_UCHAR16 **)e,f,G(g,16)) +#define PCRE2_PATTERN_INFO(a,b,c,d) a = pcre2_pattern_info_16(G(b,16),c,d) +#define PCRE2_PRINTINT(a) pcre2_printint_16(compiled_code16,outfile,a) +#define PCRE2_SERIALIZE_DECODE(r,a,b,c,d) \ + r = pcre2_serialize_decode_16((pcre2_code_16 **)a,b,c,G(d,16)) +#define PCRE2_SERIALIZE_ENCODE(r,a,b,c,d,e) \ + r = pcre2_serialize_encode_16((const pcre2_code_16 **)a,b,c,d,G(e,16)) +#define PCRE2_SERIALIZE_FREE(a) pcre2_serialize_free_16(a) +#define PCRE2_SERIALIZE_GET_NUMBER_OF_CODES(r,a) \ + r = pcre2_serialize_get_number_of_codes_16(a) +#define PCRE2_SET_CALLOUT(a,b,c) \ + pcre2_set_callout_16(G(a,16),(int (*)(pcre2_callout_block_16 *, void *))b,c); +#define PCRE2_SET_CHARACTER_TABLES(a,b) pcre2_set_character_tables_16(G(a,16),b) +#define PCRE2_SET_COMPILE_RECURSION_GUARD(a,b,c) \ + pcre2_set_compile_recursion_guard_16(G(a,16),b,c) +#define PCRE2_SET_DEPTH_LIMIT(a,b) pcre2_set_depth_limit_16(G(a,16),b) +#define PCRE2_SET_GLOB_ESCAPE(r,a,b) r = pcre2_set_glob_escape_16(G(a,16),b) +#define PCRE2_SET_GLOB_SEPARATOR(r,a,b) r = pcre2_set_glob_separator_16(G(a,16),b) +#define PCRE2_SET_HEAP_LIMIT(a,b) pcre2_set_heap_limit_16(G(a,16),b) +#define PCRE2_SET_MATCH_LIMIT(a,b) pcre2_set_match_limit_16(G(a,16),b) +#define PCRE2_SET_MAX_PATTERN_LENGTH(a,b) pcre2_set_max_pattern_length_16(G(a,16),b) +#define PCRE2_SET_OFFSET_LIMIT(a,b) pcre2_set_offset_limit_16(G(a,16),b) +#define PCRE2_SET_PARENS_NEST_LIMIT(a,b) pcre2_set_parens_nest_limit_16(G(a,16),b) +#define PCRE2_SUBSTITUTE(a,b,c,d,e,f,g,h,i,j,k,l) \ + a = pcre2_substitute_16(G(b,16),(PCRE2_SPTR16)c,d,e,f,G(g,16),G(h,16), \ + (PCRE2_SPTR16)i,j,(PCRE2_UCHAR16 *)k,l) +#define PCRE2_SUBSTRING_COPY_BYNAME(a,b,c,d,e) \ + a = pcre2_substring_copy_byname_16(G(b,16),G(c,16),(PCRE2_UCHAR16 *)d,e) +#define PCRE2_SUBSTRING_COPY_BYNUMBER(a,b,c,d,e) \ + a = pcre2_substring_copy_bynumber_16(G(b,16),c,(PCRE2_UCHAR16 *)d,e) +#define PCRE2_SUBSTRING_FREE(a) pcre2_substring_free_16((PCRE2_UCHAR16 *)a) +#define PCRE2_SUBSTRING_GET_BYNAME(a,b,c,d,e) \ + a = pcre2_substring_get_byname_16(G(b,16),G(c,16),(PCRE2_UCHAR16 **)d,e) +#define PCRE2_SUBSTRING_GET_BYNUMBER(a,b,c,d,e) \ + a = pcre2_substring_get_bynumber_16(G(b,16),c,(PCRE2_UCHAR16 **)d,e) +#define PCRE2_SUBSTRING_LENGTH_BYNAME(a,b,c,d) \ + a = pcre2_substring_length_byname_16(G(b,16),G(c,16),d) +#define PCRE2_SUBSTRING_LENGTH_BYNUMBER(a,b,c,d) \ + a = pcre2_substring_length_bynumber_16(G(b,16),c,d) +#define PCRE2_SUBSTRING_LIST_GET(a,b,c,d) \ + a = pcre2_substring_list_get_16(G(b,16),(PCRE2_UCHAR16 ***)c,d) +#define PCRE2_SUBSTRING_LIST_FREE(a) \ + pcre2_substring_list_free_16((PCRE2_SPTR16 *)a) +#define PCRE2_SUBSTRING_NUMBER_FROM_NAME(a,b,c) \ + a = pcre2_substring_number_from_name_16(G(b,16),G(c,16)); +#define PTR(x) (void *)G(x,16) +#define SETFLD(x,y,z) G(x,16)->y = z +#define SETFLDVEC(x,y,v,z) G(x,16)->y[v] = z +#define SETOP(x,y,z) G(x,16) z y +#define SETCASTPTR(x,y) G(x,16) = (uint16_t *)(y) +#define STRLEN(p) (int)strlen16((PCRE2_SPTR16)p) +#define SUB1(a,b) G(a,16)(G(b,16)) +#define SUB2(a,b,c) G(a,16)(G(b,16),G(c,16)) +#define TEST(x,r,y) (G(x,16) r (y)) +#define TESTFLD(x,f,r,y) (G(x,16)->f r (y)) + + +/* ----- Only 32-bit mode is supported ----- */ + +#elif defined SUPPORT_PCRE2_32 +#define CASTFLD(t,a,b) (t)(G(a,32)->b) +#define CASTVAR(t,x) (t)G(x,32) +#define CODE_UNIT(a,b) (uint32_t)(((PCRE2_SPTR32)(a))[b]) +#define CONCTXCPY(a,b) memcpy(G(a,32),G(b,32),sizeof(pcre2_convert_context_32)) +#define CONVERT_COPY(a,b,c) memcpy(G(a,32),(char *)b, (c)*4) +#define DATCTXCPY(a,b) memcpy(G(a,32),G(b,32),sizeof(pcre2_match_context_32)) +#define FLD(a,b) G(a,32)->b +#define PATCTXCPY(a,b) memcpy(G(a,32),G(b,32),sizeof(pcre2_compile_context_32)) +#define PCHARS(lv, p, offset, len, utf, f) \ + lv = pchars32((PCRE2_SPTR32)(p)+offset, len, utf, f) +#define PCHARSV(p, offset, len, utf, f) \ + (void)pchars32((PCRE2_SPTR32)(p)+offset, len, utf, f) +#define PCRE2_CALLOUT_ENUMERATE(a,b,c) \ + a = pcre2_callout_enumerate_32(compiled_code32, \ + (int (*)(struct pcre2_callout_enumerate_block_32 *, void *))b,c) +#define PCRE2_CODE_COPY_FROM_VOID(a,b) G(a,32) = pcre2_code_copy_32(b) +#define PCRE2_CODE_COPY_TO_VOID(a,b) a = (void *)pcre2_code_copy_32(G(b,32)) +#define PCRE2_CODE_COPY_WITH_TABLES_TO_VOID(a,b) a = (void *)pcre2_code_copy_with_tables_32(G(b,32)) +#define PCRE2_COMPILE(a,b,c,d,e,f,g) \ + G(a,32) = pcre2_compile_32(G(b,32),c,d,e,f,g) +#define PCRE2_CONVERTED_PATTERN_FREE(a) \ + pcre2_converted_pattern_free_32((PCRE2_UCHAR32 *)a) +#define PCRE2_DFA_MATCH(a,b,c,d,e,f,g,h,i,j) \ + a = pcre2_dfa_match_32(G(b,32),(PCRE2_SPTR32)c,d,e,f,G(g,32),h,i,j) +#define PCRE2_GET_ERROR_MESSAGE(r,a,b) \ + r = pcre2_get_error_message_32(a,G(b,32),G(G(b,32),_size/4)) +#define PCRE2_GET_OVECTOR_COUNT(a,b) a = pcre2_get_ovector_count_32(G(b,32)) +#define PCRE2_GET_STARTCHAR(a,b) a = pcre2_get_startchar_32(G(b,32)) +#define PCRE2_JIT_COMPILE(r,a,b) r = pcre2_jit_compile_32(G(a,32),b) +#define PCRE2_JIT_FREE_UNUSED_MEMORY(a) pcre2_jit_free_unused_memory_32(G(a,32)) +#define PCRE2_JIT_MATCH(a,b,c,d,e,f,g,h) \ + a = pcre2_jit_match_32(G(b,32),(PCRE2_SPTR32)c,d,e,f,G(g,32),h) +#define PCRE2_JIT_STACK_CREATE(a,b,c,d) \ + a = (PCRE2_JIT_STACK *)pcre2_jit_stack_create_32(b,c,d); +#define PCRE2_JIT_STACK_ASSIGN(a,b,c) \ + pcre2_jit_stack_assign_32(G(a,32),(pcre2_jit_callback_32)b,c); +#define PCRE2_JIT_STACK_FREE(a) pcre2_jit_stack_free_32((pcre2_jit_stack_32 *)a); +#define PCRE2_MAKETABLES(a) a = pcre2_maketables_32(NULL) +#define PCRE2_MATCH(a,b,c,d,e,f,g,h) \ + a = pcre2_match_32(G(b,32),(PCRE2_SPTR32)c,d,e,f,G(g,32),h) +#define PCRE2_MATCH_DATA_CREATE(a,b,c) G(a,32) = pcre2_match_data_create_32(b,c) +#define PCRE2_MATCH_DATA_CREATE_FROM_PATTERN(a,b,c) \ + G(a,32) = pcre2_match_data_create_from_pattern_32(G(b,32),c) +#define PCRE2_MATCH_DATA_FREE(a) pcre2_match_data_free_32(G(a,32)) +#define PCRE2_PATTERN_CONVERT(a,b,c,d,e,f,g) a = pcre2_pattern_convert_32(G(b,32),c,d,(PCRE2_UCHAR32 **)e,f,G(g,32)) +#define PCRE2_PATTERN_INFO(a,b,c,d) a = pcre2_pattern_info_32(G(b,32),c,d) +#define PCRE2_PRINTINT(a) pcre2_printint_32(compiled_code32,outfile,a) +#define PCRE2_SERIALIZE_DECODE(r,a,b,c,d) \ + r = pcre2_serialize_decode_32((pcre2_code_32 **)a,b,c,G(d,32)) +#define PCRE2_SERIALIZE_ENCODE(r,a,b,c,d,e) \ + r = pcre2_serialize_encode_32((const pcre2_code_32 **)a,b,c,d,G(e,32)) +#define PCRE2_SERIALIZE_FREE(a) pcre2_serialize_free_32(a) +#define PCRE2_SERIALIZE_GET_NUMBER_OF_CODES(r,a) \ + r = pcre2_serialize_get_number_of_codes_32(a) +#define PCRE2_SET_CALLOUT(a,b,c) \ + pcre2_set_callout_32(G(a,32),(int (*)(pcre2_callout_block_32 *, void *))b,c); +#define PCRE2_SET_CHARACTER_TABLES(a,b) pcre2_set_character_tables_32(G(a,32),b) +#define PCRE2_SET_COMPILE_RECURSION_GUARD(a,b,c) \ + pcre2_set_compile_recursion_guard_32(G(a,32),b,c) +#define PCRE2_SET_DEPTH_LIMIT(a,b) pcre2_set_depth_limit_32(G(a,32),b) +#define PCRE2_SET_GLOB_ESCAPE(r,a,b) r = pcre2_set_glob_escape_32(G(a,32),b) +#define PCRE2_SET_GLOB_SEPARATOR(r,a,b) r = pcre2_set_glob_separator_32(G(a,32),b) +#define PCRE2_SET_HEAP_LIMIT(a,b) pcre2_set_heap_limit_32(G(a,32),b) +#define PCRE2_SET_MATCH_LIMIT(a,b) pcre2_set_match_limit_32(G(a,32),b) +#define PCRE2_SET_MAX_PATTERN_LENGTH(a,b) pcre2_set_max_pattern_length_32(G(a,32),b) +#define PCRE2_SET_OFFSET_LIMIT(a,b) pcre2_set_offset_limit_32(G(a,32),b) +#define PCRE2_SET_PARENS_NEST_LIMIT(a,b) pcre2_set_parens_nest_limit_32(G(a,32),b) +#define PCRE2_SUBSTITUTE(a,b,c,d,e,f,g,h,i,j,k,l) \ + a = pcre2_substitute_32(G(b,32),(PCRE2_SPTR32)c,d,e,f,G(g,32),G(h,32), \ + (PCRE2_SPTR32)i,j,(PCRE2_UCHAR32 *)k,l) +#define PCRE2_SUBSTRING_COPY_BYNAME(a,b,c,d,e) \ + a = pcre2_substring_copy_byname_32(G(b,32),G(c,32),(PCRE2_UCHAR32 *)d,e) +#define PCRE2_SUBSTRING_COPY_BYNUMBER(a,b,c,d,e) \ + a = pcre2_substring_copy_bynumber_32(G(b,32),c,(PCRE2_UCHAR32 *)d,e); +#define PCRE2_SUBSTRING_FREE(a) pcre2_substring_free_32((PCRE2_UCHAR32 *)a) +#define PCRE2_SUBSTRING_GET_BYNAME(a,b,c,d,e) \ + a = pcre2_substring_get_byname_32(G(b,32),G(c,32),(PCRE2_UCHAR32 **)d,e) +#define PCRE2_SUBSTRING_GET_BYNUMBER(a,b,c,d,e) \ + a = pcre2_substring_get_bynumber_32(G(b,32),c,(PCRE2_UCHAR32 **)d,e) +#define PCRE2_SUBSTRING_LENGTH_BYNAME(a,b,c,d) \ + a = pcre2_substring_length_byname_32(G(b,32),G(c,32),d) +#define PCRE2_SUBSTRING_LENGTH_BYNUMBER(a,b,c,d) \ + a = pcre2_substring_length_bynumber_32(G(b,32),c,d) +#define PCRE2_SUBSTRING_LIST_GET(a,b,c,d) \ + a = pcre2_substring_list_get_32(G(b,32),(PCRE2_UCHAR32 ***)c,d) +#define PCRE2_SUBSTRING_LIST_FREE(a) \ + pcre2_substring_list_free_32((PCRE2_SPTR32 *)a) +#define PCRE2_SUBSTRING_NUMBER_FROM_NAME(a,b,c) \ + a = pcre2_substring_number_from_name_32(G(b,32),G(c,32)); +#define PTR(x) (void *)G(x,32) +#define SETFLD(x,y,z) G(x,32)->y = z +#define SETFLDVEC(x,y,v,z) G(x,32)->y[v] = z +#define SETOP(x,y,z) G(x,32) z y +#define SETCASTPTR(x,y) G(x,32) = (uint32_t *)(y) +#define STRLEN(p) (int)strlen32((PCRE2_SPTR32)p) +#define SUB1(a,b) G(a,32)(G(b,32)) +#define SUB2(a,b,c) G(a,32)(G(b,32),G(c,32)) +#define TEST(x,r,y) (G(x,32) r (y)) +#define TESTFLD(x,f,r,y) (G(x,32)->f r (y)) + +#endif + +/* ----- End of mode-specific function call macros ----- */ + + + + +/************************************************* +* Alternate character tables * +*************************************************/ + +/* By default, the "tables" pointer in the compile context when calling +pcre2_compile() is not set (= NULL), thereby using the default tables of the +library. However, the tables modifier can be used to select alternate sets of +tables, for different kinds of testing. Note that the locale modifier also +adjusts the tables. */ + +/* This is the set of tables distributed as default with PCRE2. It recognizes +only ASCII characters. */ + +static const uint8_t tables1[] = { + +/* This table is a lower casing table. */ + + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, 60, 61, 62, 63, + 64, 97, 98, 99,100,101,102,103, + 104,105,106,107,108,109,110,111, + 112,113,114,115,116,117,118,119, + 120,121,122, 91, 92, 93, 94, 95, + 96, 97, 98, 99,100,101,102,103, + 104,105,106,107,108,109,110,111, + 112,113,114,115,116,117,118,119, + 120,121,122,123,124,125,126,127, + 128,129,130,131,132,133,134,135, + 136,137,138,139,140,141,142,143, + 144,145,146,147,148,149,150,151, + 152,153,154,155,156,157,158,159, + 160,161,162,163,164,165,166,167, + 168,169,170,171,172,173,174,175, + 176,177,178,179,180,181,182,183, + 184,185,186,187,188,189,190,191, + 192,193,194,195,196,197,198,199, + 200,201,202,203,204,205,206,207, + 208,209,210,211,212,213,214,215, + 216,217,218,219,220,221,222,223, + 224,225,226,227,228,229,230,231, + 232,233,234,235,236,237,238,239, + 240,241,242,243,244,245,246,247, + 248,249,250,251,252,253,254,255, + +/* This table is a case flipping table. */ + + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, 60, 61, 62, 63, + 64, 97, 98, 99,100,101,102,103, + 104,105,106,107,108,109,110,111, + 112,113,114,115,116,117,118,119, + 120,121,122, 91, 92, 93, 94, 95, + 96, 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,123,124,125,126,127, + 128,129,130,131,132,133,134,135, + 136,137,138,139,140,141,142,143, + 144,145,146,147,148,149,150,151, + 152,153,154,155,156,157,158,159, + 160,161,162,163,164,165,166,167, + 168,169,170,171,172,173,174,175, + 176,177,178,179,180,181,182,183, + 184,185,186,187,188,189,190,191, + 192,193,194,195,196,197,198,199, + 200,201,202,203,204,205,206,207, + 208,209,210,211,212,213,214,215, + 216,217,218,219,220,221,222,223, + 224,225,226,227,228,229,230,231, + 232,233,234,235,236,237,238,239, + 240,241,242,243,244,245,246,247, + 248,249,250,251,252,253,254,255, + +/* This table contains bit maps for various character classes. Each map is 32 +bytes long and the bits run from the least significant end of each byte. The +classes that have their own maps are: space, xdigit, digit, upper, lower, word, +graph, print, punct, and cntrl. Other classes are built from combinations. */ + + 0x00,0x3e,0x00,0x00,0x01,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + + 0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x03, + 0x7e,0x00,0x00,0x00,0x7e,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + + 0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x03, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0xfe,0xff,0xff,0x07,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0x07, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + + 0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x03, + 0xfe,0xff,0xff,0x87,0xfe,0xff,0xff,0x07, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + + 0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + + 0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + + 0x00,0x00,0x00,0x00,0xfe,0xff,0x00,0xfc, + 0x01,0x00,0x00,0xf8,0x01,0x00,0x00,0x78, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + + 0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + +/* This table identifies various classes of character by individual bits: + 0x01 white space character + 0x02 letter + 0x04 decimal digit + 0x08 hexadecimal digit + 0x10 alphanumeric or '_' + 0x80 regular expression metacharacter or binary zero +*/ + + 0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0- 7 */ + 0x00,0x01,0x01,0x01,0x01,0x01,0x00,0x00, /* 8- 15 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 16- 23 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 24- 31 */ + 0x01,0x00,0x00,0x00,0x80,0x00,0x00,0x00, /* - ' */ + 0x80,0x80,0x80,0x80,0x00,0x00,0x80,0x00, /* ( - / */ + 0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c, /* 0 - 7 */ + 0x1c,0x1c,0x00,0x00,0x00,0x00,0x00,0x80, /* 8 - ? */ + 0x00,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x12, /* @ - G */ + 0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12, /* H - O */ + 0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12, /* P - W */ + 0x12,0x12,0x12,0x80,0x80,0x00,0x80,0x10, /* X - _ */ + 0x00,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x12, /* ` - g */ + 0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12, /* h - o */ + 0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12, /* p - w */ + 0x12,0x12,0x12,0x80,0x80,0x00,0x00,0x00, /* x -127 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 128-135 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 136-143 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 144-151 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 152-159 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 160-167 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 168-175 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 176-183 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 184-191 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 192-199 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 200-207 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 208-215 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 216-223 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 224-231 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 232-239 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 240-247 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};/* 248-255 */ + +/* This is a set of tables that came originally from a Windows user. It seems +to be at least an approximation of ISO 8859. In particular, there are +characters greater than 128 that are marked as spaces, letters, etc. */ + +static const uint8_t tables2[] = { +0,1,2,3,4,5,6,7, +8,9,10,11,12,13,14,15, +16,17,18,19,20,21,22,23, +24,25,26,27,28,29,30,31, +32,33,34,35,36,37,38,39, +40,41,42,43,44,45,46,47, +48,49,50,51,52,53,54,55, +56,57,58,59,60,61,62,63, +64,97,98,99,100,101,102,103, +104,105,106,107,108,109,110,111, +112,113,114,115,116,117,118,119, +120,121,122,91,92,93,94,95, +96,97,98,99,100,101,102,103, +104,105,106,107,108,109,110,111, +112,113,114,115,116,117,118,119, +120,121,122,123,124,125,126,127, +128,129,130,131,132,133,134,135, +136,137,138,139,140,141,142,143, +144,145,146,147,148,149,150,151, +152,153,154,155,156,157,158,159, +160,161,162,163,164,165,166,167, +168,169,170,171,172,173,174,175, +176,177,178,179,180,181,182,183, +184,185,186,187,188,189,190,191, +224,225,226,227,228,229,230,231, +232,233,234,235,236,237,238,239, +240,241,242,243,244,245,246,215, +248,249,250,251,252,253,254,223, +224,225,226,227,228,229,230,231, +232,233,234,235,236,237,238,239, +240,241,242,243,244,245,246,247, +248,249,250,251,252,253,254,255, +0,1,2,3,4,5,6,7, +8,9,10,11,12,13,14,15, +16,17,18,19,20,21,22,23, +24,25,26,27,28,29,30,31, +32,33,34,35,36,37,38,39, +40,41,42,43,44,45,46,47, +48,49,50,51,52,53,54,55, +56,57,58,59,60,61,62,63, +64,97,98,99,100,101,102,103, +104,105,106,107,108,109,110,111, +112,113,114,115,116,117,118,119, +120,121,122,91,92,93,94,95, +96,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,123,124,125,126,127, +128,129,130,131,132,133,134,135, +136,137,138,139,140,141,142,143, +144,145,146,147,148,149,150,151, +152,153,154,155,156,157,158,159, +160,161,162,163,164,165,166,167, +168,169,170,171,172,173,174,175, +176,177,178,179,180,181,182,183, +184,185,186,187,188,189,190,191, +224,225,226,227,228,229,230,231, +232,233,234,235,236,237,238,239, +240,241,242,243,244,245,246,215, +248,249,250,251,252,253,254,223, +192,193,194,195,196,197,198,199, +200,201,202,203,204,205,206,207, +208,209,210,211,212,213,214,247, +216,217,218,219,220,221,222,255, +0,62,0,0,1,0,0,0, +0,0,0,0,0,0,0,0, +32,0,0,0,1,0,0,0, +0,0,0,0,0,0,0,0, +0,0,0,0,0,0,255,3, +126,0,0,0,126,0,0,0, +0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0, +0,0,0,0,0,0,255,3, +0,0,0,0,0,0,0,0, +0,0,0,0,0,0,12,2, +0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0, +254,255,255,7,0,0,0,0, +0,0,0,0,0,0,0,0, +255,255,127,127,0,0,0,0, +0,0,0,0,0,0,0,0, +0,0,0,0,254,255,255,7, +0,0,0,0,0,4,32,4, +0,0,0,128,255,255,127,255, +0,0,0,0,0,0,255,3, +254,255,255,135,254,255,255,7, +0,0,0,0,0,4,44,6, +255,255,127,255,255,255,127,255, +0,0,0,0,254,255,255,255, +255,255,255,255,255,255,255,127, +0,0,0,0,254,255,255,255, +255,255,255,255,255,255,255,255, +0,2,0,0,255,255,255,255, +255,255,255,255,255,255,255,127, +0,0,0,0,255,255,255,255, +255,255,255,255,255,255,255,255, +0,0,0,0,254,255,0,252, +1,0,0,248,1,0,0,120, +0,0,0,0,254,255,255,255, +0,0,128,0,0,0,128,0, +255,255,255,255,0,0,0,0, +0,0,0,0,0,0,0,128, +255,255,255,255,0,0,0,0, +0,0,0,0,0,0,0,0, +128,0,0,0,0,0,0,0, +0,1,1,0,1,1,0,0, +0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0, +1,0,0,0,128,0,0,0, +128,128,128,128,0,0,128,0, +28,28,28,28,28,28,28,28, +28,28,0,0,0,0,0,128, +0,26,26,26,26,26,26,18, +18,18,18,18,18,18,18,18, +18,18,18,18,18,18,18,18, +18,18,18,128,128,0,128,16, +0,26,26,26,26,26,26,18, +18,18,18,18,18,18,18,18, +18,18,18,18,18,18,18,18, +18,18,18,128,128,0,0,0, +0,0,0,0,0,1,0,0, +0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0, +1,0,0,0,0,0,0,0, +0,0,18,0,0,0,0,0, +0,0,20,20,0,18,0,0, +0,20,18,0,0,0,0,0, +18,18,18,18,18,18,18,18, +18,18,18,18,18,18,18,18, +18,18,18,18,18,18,18,0, +18,18,18,18,18,18,18,18, +18,18,18,18,18,18,18,18, +18,18,18,18,18,18,18,18, +18,18,18,18,18,18,18,0, +18,18,18,18,18,18,18,18 +}; + + + +#if !defined(VPCOMPAT) && !defined(HAVE_MEMMOVE) +/************************************************* +* Emulated memmove() for systems without it * +*************************************************/ + +/* This function can make use of bcopy() if it is available. Otherwise do it by +steam, as there are some non-Unix environments that lack both memmove() and +bcopy(). */ + +static void * +emulated_memmove(void *d, const void *s, size_t n) +{ +#ifdef HAVE_BCOPY +bcopy(s, d, n); +return d; +#else +size_t i; +unsigned char *dest = (unsigned char *)d; +const unsigned char *src = (const unsigned char *)s; +if (dest > src) + { + dest += n; + src += n; + for (i = 0; i < n; ++i) *(--dest) = *(--src); + return (void *)dest; + } +else + { + for (i = 0; i < n; ++i) *dest++ = *src++; + return (void *)(dest - n); + } +#endif /* not HAVE_BCOPY */ +} +#undef memmove +#define memmove(d,s,n) emulated_memmove(d,s,n) +#endif /* not VPCOMPAT && not HAVE_MEMMOVE */ + + + +#ifndef HAVE_STRERROR +/************************************************* +* Provide strerror() for non-ANSI libraries * +*************************************************/ + +/* Some old-fashioned systems (e.g. SunOS4) didn't have strerror() in their +libraries. They may no longer be around, but just in case, we can try to +provide the same facility by this simple alternative function. */ + +extern int sys_nerr; +extern char *sys_errlist[]; + +char * +strerror(int n) +{ +if (n < 0 || n >= sys_nerr) return "unknown error number"; +return sys_errlist[n]; +} +#endif /* HAVE_STRERROR */ + + + +/************************************************* +* Local memory functions * +*************************************************/ + +/* Alternative memory functions, to test functionality. */ + +static void *my_malloc(PCRE2_SIZE size, void *data) +{ +void *block = malloc(size); +(void)data; +if (show_memory) + { + if (block == NULL) + { + fprintf(outfile, "** malloc() failed for %" SIZ_FORM "\n", SIZ_CAST size); + } + else + { + fprintf(outfile, "malloc %5" SIZ_FORM, SIZ_CAST size); +#ifdef DEBUG_SHOW_MALLOC_ADDRESSES + fprintf(outfile, " %p", block); /* Not portable */ +#endif + if (malloclistptr < MALLOCLISTSIZE) + { + malloclist[malloclistptr] = block; + malloclistlength[malloclistptr++] = size; + } + else + fprintf(outfile, " (not remembered)"); + fprintf(outfile, "\n"); + } + } +return block; +} + +static void my_free(void *block, void *data) +{ +(void)data; +if (show_memory) + { + uint32_t i, j; + BOOL found = FALSE; + + fprintf(outfile, "free"); + for (i = 0; i < malloclistptr; i++) + { + if (block == malloclist[i]) + { + fprintf(outfile, " %5" SIZ_FORM, SIZ_CAST malloclistlength[i]); + malloclistptr--; + for (j = i; j < malloclistptr; j++) + { + malloclist[j] = malloclist[j+1]; + malloclistlength[j] = malloclistlength[j+1]; + } + found = TRUE; + break; + } + } + if (!found) fprintf(outfile, " unremembered block"); +#ifdef DEBUG_SHOW_MALLOC_ADDRESSES + fprintf(outfile, " %p", block); /* Not portable */ +#endif + fprintf(outfile, "\n"); + } +free(block); +} + + + +/************************************************* +* Callback function for stack guard * +*************************************************/ + +/* This is set up to be called from pcre2_compile() when the stackguard=n +modifier sets a value greater than zero. The test we do is whether the +parenthesis nesting depth is greater than the value set by the modifier. + +Argument: the current parenthesis nesting depth +Returns: non-zero to kill the compilation +*/ + +static int +stack_guard(uint32_t depth, void *user_data) +{ +(void)user_data; +return depth > pat_patctl.stackguard_test; +} + + +/************************************************* +* JIT memory callback * +*************************************************/ + +static PCRE2_JIT_STACK* +jit_callback(void *arg) +{ +jit_was_used = TRUE; +return (PCRE2_JIT_STACK *)arg; +} + + +/************************************************* +* Convert UTF-8 character to code point * +*************************************************/ + +/* This function reads one or more bytes that represent a UTF-8 character, +and returns the codepoint of that character. Note that the function supports +the original UTF-8 definition of RFC 2279, allowing for values in the range 0 +to 0x7fffffff, up to 6 bytes long. This makes it possible to generate +codepoints greater than 0x10ffff which are useful for testing PCRE2's error +checking, and also for generating 32-bit non-UTF data values above the UTF +limit. + +Argument: + utf8bytes a pointer to the byte vector + vptr a pointer to an int to receive the value + +Returns: > 0 => the number of bytes consumed + -6 to 0 => malformed UTF-8 character at offset = (-return) +*/ + +static int +utf82ord(PCRE2_SPTR8 utf8bytes, uint32_t *vptr) +{ +uint32_t c = *utf8bytes++; +uint32_t d = c; +int i, j, s; + +for (i = -1; i < 6; i++) /* i is number of additional bytes */ + { + if ((d & 0x80) == 0) break; + d <<= 1; + } + +if (i == -1) { *vptr = c; return 1; } /* ascii character */ +if (i == 0 || i == 6) return 0; /* invalid UTF-8 */ + +/* i now has a value in the range 1-5 */ + +s = 6*i; +d = (c & utf8_table3[i]) << s; + +for (j = 0; j < i; j++) + { + c = *utf8bytes++; + if ((c & 0xc0) != 0x80) return -(j+1); + s -= 6; + d |= (c & 0x3f) << s; + } + +/* Check that encoding was the correct unique one */ + +for (j = 0; j < utf8_table1_size; j++) + if (d <= (uint32_t)utf8_table1[j]) break; +if (j != i) return -(i+1); + +/* Valid value */ + +*vptr = d; +return i+1; +} + + + +/************************************************* +* Print one character * +*************************************************/ + +/* Print a single character either literally, or as a hex escape, and count how +many printed characters are used. + +Arguments: + c the character + utf TRUE in UTF mode + f the FILE to print to, or NULL just to count characters + +Returns: number of characters written +*/ + +static int +pchar(uint32_t c, BOOL utf, FILE *f) +{ +int n = 0; +char tempbuffer[16]; + +if (PRINTOK(c)) + { + if (f != NULL) fprintf(f, "%c", c); + return 1; + } + +if (c < 0x100) + { + if (utf) + { + if (f != NULL) fprintf(f, "\\x{%02x}", c); + return 6; + } + else + { + if (f != NULL) fprintf(f, "\\x%02x", c); + return 4; + } + } + +if (f != NULL) n = fprintf(f, "\\x{%02x}", c); + else n = sprintf(tempbuffer, "\\x{%02x}", c); + +return n >= 0 ? n : 0; +} + + + +#ifdef SUPPORT_PCRE2_16 +/************************************************* +* Find length of 0-terminated 16-bit string * +*************************************************/ + +static size_t strlen16(PCRE2_SPTR16 p) +{ +PCRE2_SPTR16 pp = p; +while (*pp != 0) pp++; +return (int)(pp - p); +} +#endif /* SUPPORT_PCRE2_16 */ + + + +#ifdef SUPPORT_PCRE2_32 +/************************************************* +* Find length of 0-terminated 32-bit string * +*************************************************/ + +static size_t strlen32(PCRE2_SPTR32 p) +{ +PCRE2_SPTR32 pp = p; +while (*pp != 0) pp++; +return (int)(pp - p); +} +#endif /* SUPPORT_PCRE2_32 */ + + +#ifdef SUPPORT_PCRE2_8 +/************************************************* +* Print 8-bit character string * +*************************************************/ + +/* Must handle UTF-8 strings in utf8 mode. Yields number of characters printed. +For printing *MARK strings, a negative length is given. If handed a NULL file, +just counts chars without printing (because pchar() does that). */ + +static int pchars8(PCRE2_SPTR8 p, int length, BOOL utf, FILE *f) +{ +uint32_t c = 0; +int yield = 0; + +if (length < 0) length = p[-1]; +while (length-- > 0) + { + if (utf) + { + int rc = utf82ord(p, &c); + if (rc > 0 && rc <= length + 1) /* Mustn't run over the end */ + { + length -= rc - 1; + p += rc; + yield += pchar(c, utf, f); + continue; + } + } + c = *p++; + yield += pchar(c, utf, f); + } + +return yield; +} +#endif + + +#ifdef SUPPORT_PCRE2_16 +/************************************************* +* Print 16-bit character string * +*************************************************/ + +/* Must handle UTF-16 strings in utf mode. Yields number of characters printed. +For printing *MARK strings, a negative length is given. If handed a NULL file, +just counts chars without printing. */ + +static int pchars16(PCRE2_SPTR16 p, int length, BOOL utf, FILE *f) +{ +int yield = 0; +if (length < 0) length = p[-1]; +while (length-- > 0) + { + uint32_t c = *p++ & 0xffff; + if (utf && c >= 0xD800 && c < 0xDC00 && length > 0) + { + int d = *p & 0xffff; + if (d >= 0xDC00 && d <= 0xDFFF) + { + c = ((c & 0x3ff) << 10) + (d & 0x3ff) + 0x10000; + length--; + p++; + } + } + yield += pchar(c, utf, f); + } +return yield; +} +#endif /* SUPPORT_PCRE2_16 */ + + + +#ifdef SUPPORT_PCRE2_32 +/************************************************* +* Print 32-bit character string * +*************************************************/ + +/* Must handle UTF-32 strings in utf mode. Yields number of characters printed. +For printing *MARK strings, a negative length is given. If handed a NULL file, +just counts chars without printing. */ + +static int pchars32(PCRE2_SPTR32 p, int length, BOOL utf, FILE *f) +{ +int yield = 0; +(void)(utf); /* Avoid compiler warning */ + +if (length < 0) length = p[-1]; +while (length-- > 0) + { + uint32_t c = *p++; + yield += pchar(c, utf, f); + } +return yield; +} +#endif /* SUPPORT_PCRE2_32 */ + + + + +#ifdef SUPPORT_PCRE2_8 +/************************************************* +* Convert character value to UTF-8 * +*************************************************/ + +/* This function takes an integer value in the range 0 - 0x7fffffff +and encodes it as a UTF-8 character in 0 to 6 bytes. + +Arguments: + cvalue the character value + utf8bytes pointer to buffer for result - at least 6 bytes long + +Returns: number of characters placed in the buffer +*/ + +static int +ord2utf8(uint32_t cvalue, uint8_t *utf8bytes) +{ +int i, j; +if (cvalue > 0x7fffffffu) + return -1; +for (i = 0; i < utf8_table1_size; i++) + if (cvalue <= (uint32_t)utf8_table1[i]) break; +utf8bytes += i; +for (j = i; j > 0; j--) + { + *utf8bytes-- = 0x80 | (cvalue & 0x3f); + cvalue >>= 6; + } +*utf8bytes = utf8_table2[i] | cvalue; +return i + 1; +} +#endif /* SUPPORT_PCRE2_8 */ + + + +#ifdef SUPPORT_PCRE2_16 +/************************************************* +* Convert string to 16-bit * +*************************************************/ + +/* In UTF mode the input is always interpreted as a string of UTF-8 bytes using +the original UTF-8 definition of RFC 2279, which allows for up to 6 bytes, and +code values from 0 to 0x7fffffff. However, values greater than the later UTF +limit of 0x10ffff cause an error. In non-UTF mode the input is interpreted as +UTF-8 if the utf8_input modifier is set, but an error is generated for values +greater than 0xffff. + +If all the input bytes are ASCII, the space needed for a 16-bit string is +exactly double the 8-bit size. Otherwise, the size needed for a 16-bit string +is no more than double, because up to 0xffff uses no more than 3 bytes in UTF-8 +but possibly 4 in UTF-16. Higher values use 4 bytes in UTF-8 and up to 4 bytes +in UTF-16. The result is always left in pbuffer16. Impose a minimum size to +save repeated re-sizing. + +Note that this function does not object to surrogate values. This is +deliberate; it makes it possible to construct UTF-16 strings that are invalid, +for the purpose of testing that they are correctly faulted. + +Arguments: + p points to a byte string + utf true in UTF mode + lenptr points to number of bytes in the string (excluding trailing zero) + +Returns: 0 on success, with the length updated to the number of 16-bit + data items used (excluding the trailing zero) + OR -1 if a UTF-8 string is malformed + OR -2 if a value > 0x10ffff is encountered in UTF mode + OR -3 if a value > 0xffff is encountered when not in UTF mode +*/ + +static PCRE2_SIZE +to16(uint8_t *p, int utf, PCRE2_SIZE *lenptr) +{ +uint16_t *pp; +PCRE2_SIZE len = *lenptr; + +if (pbuffer16_size < 2*len + 2) + { + if (pbuffer16 != NULL) free(pbuffer16); + pbuffer16_size = 2*len + 2; + if (pbuffer16_size < 4096) pbuffer16_size = 4096; + pbuffer16 = (uint16_t *)malloc(pbuffer16_size); + if (pbuffer16 == NULL) + { + fprintf(stderr, "pcre2test: malloc(%" SIZ_FORM ") failed for pbuffer16\n", + SIZ_CAST pbuffer16_size); + exit(1); + } + } + +pp = pbuffer16; +if (!utf && (pat_patctl.control & CTL_UTF8_INPUT) == 0) + { + for (; len > 0; len--) *pp++ = *p++; + } +else while (len > 0) + { + uint32_t c; + int chlen = utf82ord(p, &c); + if (chlen <= 0) return -1; + if (!utf && c > 0xffff) return -3; + if (c > 0x10ffff) return -2; + p += chlen; + len -= chlen; + if (c < 0x10000) *pp++ = c; else + { + c -= 0x10000; + *pp++ = 0xD800 | (c >> 10); + *pp++ = 0xDC00 | (c & 0x3ff); + } + } + +*pp = 0; +*lenptr = pp - pbuffer16; +return 0; +} +#endif + + + +#ifdef SUPPORT_PCRE2_32 +/************************************************* +* Convert string to 32-bit * +*************************************************/ + +/* In UTF mode the input is always interpreted as a string of UTF-8 bytes using +the original UTF-8 definition of RFC 2279, which allows for up to 6 bytes, and +code values from 0 to 0x7fffffff. However, values greater than the later UTF +limit of 0x10ffff cause an error. + +In non-UTF mode the input is interpreted as UTF-8 if the utf8_input modifier +is set, and no limit is imposed. There is special interpretation of the 0xff +byte (which is illegal in UTF-8) in this case: it causes the top bit of the +next character to be set. This provides a way of generating 32-bit characters +greater than 0x7fffffff. + +If all the input bytes are ASCII, the space needed for a 32-bit string is +exactly four times the 8-bit size. Otherwise, the size needed for a 32-bit +string is no more than four times, because the number of characters must be +less than the number of bytes. The result is always left in pbuffer32. Impose a +minimum size to save repeated re-sizing. + +Note that this function does not object to surrogate values. This is +deliberate; it makes it possible to construct UTF-32 strings that are invalid, +for the purpose of testing that they are correctly faulted. + +Arguments: + p points to a byte string + utf true in UTF mode + lenptr points to number of bytes in the string (excluding trailing zero) + +Returns: 0 on success, with the length updated to the number of 32-bit + data items used (excluding the trailing zero) + OR -1 if a UTF-8 string is malformed + OR -2 if a value > 0x10ffff is encountered in UTF mode +*/ + +static PCRE2_SIZE +to32(uint8_t *p, int utf, PCRE2_SIZE *lenptr) +{ +uint32_t *pp; +PCRE2_SIZE len = *lenptr; + +if (pbuffer32_size < 4*len + 4) + { + if (pbuffer32 != NULL) free(pbuffer32); + pbuffer32_size = 4*len + 4; + if (pbuffer32_size < 8192) pbuffer32_size = 8192; + pbuffer32 = (uint32_t *)malloc(pbuffer32_size); + if (pbuffer32 == NULL) + { + fprintf(stderr, "pcre2test: malloc(%" SIZ_FORM ") failed for pbuffer32\n", + SIZ_CAST pbuffer32_size); + exit(1); + } + } + +pp = pbuffer32; + +if (!utf && (pat_patctl.control & CTL_UTF8_INPUT) == 0) + { + for (; len > 0; len--) *pp++ = *p++; + } + +else while (len > 0) + { + int chlen; + uint32_t c; + uint32_t topbit = 0; + if (!utf && *p == 0xff && len > 1) + { + topbit = 0x80000000u; + p++; + len--; + } + chlen = utf82ord(p, &c); + if (chlen <= 0) return -1; + if (utf && c > 0x10ffff) return -2; + p += chlen; + len -= chlen; + *pp++ = c | topbit; + } + +*pp = 0; +*lenptr = pp - pbuffer32; +return 0; +} +#endif /* SUPPORT_PCRE2_32 */ + + + +/************************************************* +* Move back by so many characters * +*************************************************/ + +/* Given a code unit offset in a subject string, move backwards by a number of +characters, and return the resulting offset. + +Arguments: + subject pointer to the string + offset start offset + count count to move back by + utf TRUE if in UTF mode + +Returns: a possibly changed offset +*/ + +static PCRE2_SIZE +backchars(uint8_t *subject, PCRE2_SIZE offset, uint32_t count, BOOL utf) +{ +if (!utf || test_mode == PCRE32_MODE) + return (count >= offset)? 0 : (offset - count); + +else if (test_mode == PCRE8_MODE) + { + PCRE2_SPTR8 pp = (PCRE2_SPTR8)subject + offset; + for (; count > 0 && pp > (PCRE2_SPTR8)subject; count--) + { + pp--; + while ((*pp & 0xc0) == 0x80) pp--; + } + return pp - (PCRE2_SPTR8)subject; + } + +else /* 16-bit mode */ + { + PCRE2_SPTR16 pp = (PCRE2_SPTR16)subject + offset; + for (; count > 0 && pp > (PCRE2_SPTR16)subject; count--) + { + pp--; + if ((*pp & 0xfc00) == 0xdc00) pp--; + } + return pp - (PCRE2_SPTR16)subject; + } +} + + + +/************************************************* +* Expand input buffers * +*************************************************/ + +/* This function doubles the size of the input buffer and the buffer for +keeping an 8-bit copy of patterns (pbuffer8), and copies the current buffers to +the new ones. + +Arguments: none +Returns: nothing (aborts if malloc() fails) +*/ + +static void +expand_input_buffers(void) +{ +int new_pbuffer8_size = 2*pbuffer8_size; +uint8_t *new_buffer = (uint8_t *)malloc(new_pbuffer8_size); +uint8_t *new_pbuffer8 = (uint8_t *)malloc(new_pbuffer8_size); + +if (new_buffer == NULL || new_pbuffer8 == NULL) + { + fprintf(stderr, "pcre2test: malloc(%d) failed\n", new_pbuffer8_size); + exit(1); + } + +memcpy(new_buffer, buffer, pbuffer8_size); +memcpy(new_pbuffer8, pbuffer8, pbuffer8_size); + +pbuffer8_size = new_pbuffer8_size; + +free(buffer); +free(pbuffer8); + +buffer = new_buffer; +pbuffer8 = new_pbuffer8; +} + + + +/************************************************* +* Read or extend an input line * +*************************************************/ + +/* Input lines are read into buffer, but both patterns and data lines can be +continued over multiple input lines. In addition, if the buffer fills up, we +want to automatically expand it so as to be able to handle extremely large +lines that are needed for certain stress tests, although this is less likely +now that there are repetition features for both patterns and data. When the +input buffer is expanded, the other two buffers must also be expanded likewise, +and the contents of pbuffer, which are a copy of the input for callouts, must +be preserved (for when expansion happens for a data line). This is not the most +optimal way of handling this, but hey, this is just a test program! + +Arguments: + f the file to read + start where in buffer to start (this *must* be within buffer) + prompt for stdin or readline() + +Returns: pointer to the start of new data + could be a copy of start, or could be moved + NULL if no data read and EOF reached +*/ + +static uint8_t * +extend_inputline(FILE *f, uint8_t *start, const char *prompt) +{ +uint8_t *here = start; + +for (;;) + { + size_t rlen = (size_t)(pbuffer8_size - (here - buffer)); + + if (rlen > 1000) + { + size_t dlen; + + /* If libreadline or libedit support is required, use readline() to read a + line if the input is a terminal. Note that readline() removes the trailing + newline, so we must put it back again, to be compatible with fgets(). */ + +#if defined(SUPPORT_LIBREADLINE) || defined(SUPPORT_LIBEDIT) + if (INTERACTIVE(f)) + { + size_t len; + char *s = readline(prompt); + if (s == NULL) return (here == start)? NULL : start; + len = strlen(s); + if (len > 0) add_history(s); + if (len > rlen - 1) len = rlen - 1; + memcpy(here, s, len); + here[len] = '\n'; + here[len+1] = 0; + free(s); + } + else +#endif + + /* Read the next line by normal means, prompting if the file is a tty. */ + + { + if (INTERACTIVE(f)) printf("%s", prompt); + if (fgets((char *)here, rlen, f) == NULL) + return (here == start)? NULL : start; + } + + dlen = strlen((char *)here); + here += dlen; + + /* Check for end of line reached. Take care not to read data from before + start (dlen will be zero for a file starting with a binary zero). */ + + if (here > start && here[-1] == '\n') return start; + + /* If we have not read a newline when reading a file, we have either filled + the buffer or reached the end of the file. We can detect the former by + checking that the string fills the buffer, and the latter by feof(). If + neither of these is true, it means we read a binary zero which has caused + strlen() to give a short length. This is a hard error because pcre2test + expects to work with C strings. */ + + if (!INTERACTIVE(f) && dlen < rlen - 1 && !feof(f)) + { + fprintf(outfile, "** Binary zero encountered in input\n"); + fprintf(outfile, "** pcre2test run abandoned\n"); + exit(1); + } + } + + else + { + size_t start_offset = start - buffer; + size_t here_offset = here - buffer; + expand_input_buffers(); + start = buffer + start_offset; + here = buffer + here_offset; + } + } + +/* Control never gets here */ +} + + + +/************************************************* +* Case-independent strncmp() function * +*************************************************/ + +/* +Arguments: + s first string + t second string + n number of characters to compare + +Returns: < 0, = 0, or > 0, according to the comparison +*/ + +static int +strncmpic(const uint8_t *s, const uint8_t *t, int n) +{ +while (n--) + { + int c = tolower(*s++) - tolower(*t++); + if (c != 0) return c; + } +return 0; +} + + + +/************************************************* +* Scan the main modifier list * +*************************************************/ + +/* This function searches the modifier list for a long modifier name. + +Argument: + p start of the name + lenp length of the name + +Returns: an index in the modifier list, or -1 on failure +*/ + +static int +scan_modifiers(const uint8_t *p, unsigned int len) +{ +int bot = 0; +int top = MODLISTCOUNT; + +while (top > bot) + { + int mid = (bot + top)/2; + unsigned int mlen = strlen(modlist[mid].name); + int c = strncmp((char *)p, modlist[mid].name, (len < mlen)? len : mlen); + if (c == 0) + { + if (len == mlen) return mid; + c = (int)len - (int)mlen; + } + if (c > 0) bot = mid + 1; else top = mid; + } + +return -1; + +} + + + +/************************************************* +* Check a modifer and find its field * +*************************************************/ + +/* This function is called when a modifier has been identified. We check that +it is allowed here and find the field that is to be changed. + +Arguments: + m the modifier list entry + ctx CTX_PAT => pattern context + CTX_POPPAT => pattern context for popped pattern + CTX_DEFPAT => default pattern context + CTX_DAT => data context + CTX_DEFDAT => default data context + pctl point to pattern control block + dctl point to data control block + c a single character or 0 + +Returns: a field pointer or NULL +*/ + +static void * +check_modifier(modstruct *m, int ctx, patctl *pctl, datctl *dctl, uint32_t c) +{ +void *field = NULL; +PCRE2_SIZE offset = m->offset; + +if (restrict_for_perl_test) switch(m->which) + { + case MOD_PNDP: + case MOD_PATP: + case MOD_PDP: + break; + + default: + fprintf(outfile, "** '%s' is not allowed in a Perl-compatible test\n", + m->name); + return NULL; + } + +switch (m->which) + { + case MOD_CTC: /* Compile context modifier */ + if (ctx == CTX_DEFPAT) field = PTR(default_pat_context); + else if (ctx == CTX_PAT) field = PTR(pat_context); + break; + + case MOD_CTM: /* Match context modifier */ + if (ctx == CTX_DEFDAT) field = PTR(default_dat_context); + else if (ctx == CTX_DAT) field = PTR(dat_context); + break; + + case MOD_DAT: /* Data line modifier */ + if (dctl != NULL) field = dctl; + break; + + case MOD_PAT: /* Pattern modifier */ + case MOD_PATP: /* Allowed for Perl test */ + if (pctl != NULL) field = pctl; + break; + + case MOD_PD: /* Pattern or data line modifier */ + case MOD_PDP: /* Ditto, allowed for Perl test */ + case MOD_PND: /* Ditto, but not default pattern */ + case MOD_PNDP: /* Ditto, allowed for Perl test */ + if (dctl != NULL) field = dctl; + else if (pctl != NULL && (m->which == MOD_PD || m->which == MOD_PDP || + ctx != CTX_DEFPAT)) + field = pctl; + break; + } + +if (field == NULL) + { + if (c == 0) + fprintf(outfile, "** '%s' is not valid here\n", m->name); + else + fprintf(outfile, "** /%c is not valid here\n", c); + return NULL; + } + +return (char *)field + offset; +} + + + +/************************************************* +* Decode a modifier list * +*************************************************/ + +/* A pointer to a control block is NULL when called in cases when that block is +not relevant. They are never all relevant in one call. At least one of patctl +and datctl is NULL. The second argument specifies which context to use for +modifiers that apply to contexts. + +Arguments: + p point to modifier string + ctx CTX_PAT => pattern context + CTX_POPPAT => pattern context for popped pattern + CTX_DEFPAT => default pattern context + CTX_DAT => data context + CTX_DEFDAT => default data context + pctl point to pattern control block + dctl point to data control block + +Returns: TRUE if successful decode, FALSE otherwise +*/ + +static BOOL +decode_modifiers(uint8_t *p, int ctx, patctl *pctl, datctl *dctl) +{ +uint8_t *ep, *pp; +long li; +unsigned long uli; +BOOL first = TRUE; + +for (;;) + { + void *field; + modstruct *m; + BOOL off = FALSE; + unsigned int i, len; + int index; + char *endptr; + + /* Skip white space and commas. */ + + while (isspace(*p) || *p == ',') p++; + if (*p == 0) break; + + /* Find the end of the item; lose trailing whitespace at end of line. */ + + for (ep = p; *ep != 0 && *ep != ','; ep++); + if (*ep == 0) + { + while (ep > p && isspace(ep[-1])) ep--; + *ep = 0; + } + + /* Remember if the first character is '-'. */ + + if (*p == '-') + { + off = TRUE; + p++; + } + + /* Find the length of a full-length modifier name, and scan for it. */ + + pp = p; + while (pp < ep && *pp != '=') pp++; + index = scan_modifiers(p, pp - p); + + /* If the first modifier is unrecognized, try to interpret it as a sequence + of single-character abbreviated modifiers. None of these modifiers have any + associated data. They just set options or control bits. */ + + if (index < 0) + { + uint32_t cc; + uint8_t *mp = p; + + if (!first) + { + fprintf(outfile, "** Unrecognized modifier '%.*s'\n", (int)(ep-p), p); + if (ep - p == 1) + fprintf(outfile, "** Single-character modifiers must come first\n"); + return FALSE; + } + + for (cc = *p; cc != ',' && cc != '\n' && cc != 0; cc = *(++p)) + { + for (i = 0; i < C1MODLISTCOUNT; i++) + if (cc == c1modlist[i].onechar) break; + + if (i >= C1MODLISTCOUNT) + { + fprintf(outfile, "** Unrecognized modifier '%c' in '%.*s'\n", + *p, (int)(ep-mp), mp); + return FALSE; + } + + if (c1modlist[i].index >= 0) + { + index = c1modlist[i].index; + } + + else + { + index = scan_modifiers((uint8_t *)(c1modlist[i].fullname), + strlen(c1modlist[i].fullname)); + if (index < 0) + { + fprintf(outfile, "** Internal error: single-character equivalent " + "modifier '%s' not found\n", c1modlist[i].fullname); + return FALSE; + } + c1modlist[i].index = index; /* Cache for next time */ + } + + field = check_modifier(modlist + index, ctx, pctl, dctl, *p); + if (field == NULL) return FALSE; + + /* /x is a special case; a second appearance changes PCRE2_EXTENDED to + PCRE2_EXTENDED_MORE. */ + + if (cc == 'x' && (*((uint32_t *)field) & PCRE2_EXTENDED) != 0) + { + *((uint32_t *)field) &= ~PCRE2_EXTENDED; + *((uint32_t *)field) |= PCRE2_EXTENDED_MORE; + } + else + *((uint32_t *)field) |= modlist[index].value; + } + + continue; /* With tne next (fullname) modifier */ + } + + /* We have a match on a full-name modifier. Check for the existence of data + when needed. */ + + m = modlist + index; /* Save typing */ + if (m->type != MOD_CTL && m->type != MOD_OPT && + (m->type != MOD_IND || *pp == '=')) + { + if (*pp++ != '=') + { + fprintf(outfile, "** '=' expected after '%s'\n", m->name); + return FALSE; + } + if (off) + { + fprintf(outfile, "** '-' is not valid for '%s'\n", m->name); + return FALSE; + } + } + + /* These on/off types have no data. */ + + else if (*pp != ',' && *pp != '\n' && *pp != ' ' && *pp != 0) + { + fprintf(outfile, "** Unrecognized modifier '%.*s'\n", (int)(ep-p), p); + return FALSE; + } + + /* Set the data length for those types that have data. Then find the field + that is to be set. If check_modifier() returns NULL, it has already output an + error message. */ + + len = ep - pp; + field = check_modifier(m, ctx, pctl, dctl, 0); + if (field == NULL) return FALSE; + + /* Process according to data type. */ + + switch (m->type) + { + case MOD_CTL: + case MOD_OPT: + if (off) *((uint32_t *)field) &= ~m->value; + else *((uint32_t *)field) |= m->value; + break; + + case MOD_BSR: + if (len == 7 && strncmpic(pp, (const uint8_t *)"default", 7) == 0) + { +#ifdef BSR_ANYCRLF + *((uint16_t *)field) = PCRE2_BSR_ANYCRLF; +#else + *((uint16_t *)field) = PCRE2_BSR_UNICODE; +#endif + if (ctx == CTX_PAT || ctx == CTX_DEFPAT) pctl->control2 &= ~CTL2_BSR_SET; + else dctl->control2 &= ~CTL2_BSR_SET; + } + else + { + if (len == 7 && strncmpic(pp, (const uint8_t *)"anycrlf", 7) == 0) + *((uint16_t *)field) = PCRE2_BSR_ANYCRLF; + else if (len == 7 && strncmpic(pp, (const uint8_t *)"unicode", 7) == 0) + *((uint16_t *)field) = PCRE2_BSR_UNICODE; + else goto INVALID_VALUE; + if (ctx == CTX_PAT || ctx == CTX_DEFPAT) pctl->control2 |= CTL2_BSR_SET; + else dctl->control2 |= CTL2_BSR_SET; + } + pp = ep; + break; + + case MOD_CHR: /* A single character */ + *((uint32_t *)field) = *pp++; + break; + + case MOD_CON: /* A convert type/options list */ + for (;; pp++) + { + uint8_t *colon = (uint8_t *)strchr((const char *)pp, ':'); + len = ((colon != NULL && colon < ep)? colon:ep) - pp; + for (i = 0; i < convertlistcount; i++) + { + if (strncmpic(pp, (const uint8_t *)convertlist[i].name, len) == 0) + { + if (*((uint32_t *)field) == CONVERT_UNSET) + *((uint32_t *)field) = convertlist[i].option; + else + *((uint32_t *)field) |= convertlist[i].option; + break; + } + } + if (i >= convertlistcount) goto INVALID_VALUE; + pp += len; + if (*pp != ':') break; + } + break; + + case MOD_IN2: /* One or two unsigned integers */ + if (!isdigit(*pp)) goto INVALID_VALUE; + uli = strtoul((const char *)pp, &endptr, 10); + if (U32OVERFLOW(uli)) goto INVALID_VALUE; + ((uint32_t *)field)[0] = (uint32_t)uli; + if (*endptr == ':') + { + uli = strtoul((const char *)endptr+1, &endptr, 10); + if (U32OVERFLOW(uli)) goto INVALID_VALUE; + ((uint32_t *)field)[1] = (uint32_t)uli; + } + else ((uint32_t *)field)[1] = 0; + pp = (uint8_t *)endptr; + break; + + /* PCRE2_SIZE_MAX is usually SIZE_MAX, which may be greater, equal to, or + less than ULONG_MAX. So first test for overflowing the long int, and then + test for overflowing PCRE2_SIZE_MAX if it is smaller than ULONG_MAX. */ + + case MOD_SIZ: /* PCRE2_SIZE value */ + if (!isdigit(*pp)) goto INVALID_VALUE; + uli = strtoul((const char *)pp, &endptr, 10); + if (uli == ULONG_MAX) goto INVALID_VALUE; +#if ULONG_MAX > PCRE2_SIZE_MAX + if (uli > PCRE2_SIZE_MAX) goto INVALID_VALUE; +#endif + *((PCRE2_SIZE *)field) = (PCRE2_SIZE)uli; + pp = (uint8_t *)endptr; + break; + + case MOD_IND: /* Unsigned integer with default */ + if (len == 0) + { + *((uint32_t *)field) = (uint32_t)(m->value); + break; + } + /* Fall through */ + + case MOD_INT: /* Unsigned integer */ + if (!isdigit(*pp)) goto INVALID_VALUE; + uli = strtoul((const char *)pp, &endptr, 10); + if (U32OVERFLOW(uli)) goto INVALID_VALUE; + *((uint32_t *)field) = (uint32_t)uli; + pp = (uint8_t *)endptr; + break; + + case MOD_INS: /* Signed integer */ + if (!isdigit(*pp) && *pp != '-') goto INVALID_VALUE; + li = strtol((const char *)pp, &endptr, 10); + if (S32OVERFLOW(li)) goto INVALID_VALUE; + *((int32_t *)field) = (int32_t)li; + pp = (uint8_t *)endptr; + break; + + case MOD_NL: + for (i = 0; i < sizeof(newlines)/sizeof(char *); i++) + if (len == strlen(newlines[i]) && + strncmpic(pp, (const uint8_t *)newlines[i], len) == 0) break; + if (i >= sizeof(newlines)/sizeof(char *)) goto INVALID_VALUE; + if (i == 0) + { + *((uint16_t *)field) = NEWLINE_DEFAULT; + if (ctx == CTX_PAT || ctx == CTX_DEFPAT) pctl->control2 &= ~CTL2_NL_SET; + else dctl->control2 &= ~CTL2_NL_SET; + } + else + { + *((uint16_t *)field) = i; + if (ctx == CTX_PAT || ctx == CTX_DEFPAT) pctl->control2 |= CTL2_NL_SET; + else dctl->control2 |= CTL2_NL_SET; + } + pp = ep; + break; + + case MOD_NN: /* Name or (signed) number; may be several */ + if (isdigit(*pp) || *pp == '-') + { + int ct = MAXCPYGET - 1; + int32_t value; + li = strtol((const char *)pp, &endptr, 10); + if (S32OVERFLOW(li)) goto INVALID_VALUE; + value = (int32_t)li; + field = (char *)field - m->offset + m->value; /* Adjust field ptr */ + if (value >= 0) /* Add new number */ + { + while (*((int32_t *)field) >= 0 && ct-- > 0) /* Skip previous */ + field = (char *)field + sizeof(int32_t); + if (ct <= 0) + { + fprintf(outfile, "** Too many numeric '%s' modifiers\n", m->name); + return FALSE; + } + } + *((int32_t *)field) = value; + if (ct > 0) ((int32_t *)field)[1] = -1; + pp = (uint8_t *)endptr; + } + + /* Multiple strings are put end to end. */ + + else + { + char *nn = (char *)field; + if (len > 0) /* Add new name */ + { + if (len > MAX_NAME_SIZE) + { + fprintf(outfile, "** Group name in '%s' is too long\n", m->name); + return FALSE; + } + while (*nn != 0) nn += strlen(nn) + 1; + if (nn + len + 2 - (char *)field > LENCPYGET) + { + fprintf(outfile, "** Too many characters in named '%s' modifiers\n", + m->name); + return FALSE; + } + memcpy(nn, pp, len); + } + nn[len] = 0 ; + nn[len+1] = 0; + pp = ep; + } + break; + + case MOD_STR: + if (len + 1 > m->value) + { + fprintf(outfile, "** Overlong value for '%s' (max %d code units)\n", + m->name, m->value - 1); + return FALSE; + } + memcpy(field, pp, len); + ((uint8_t *)field)[len] = 0; + pp = ep; + break; + } + + if (*pp != ',' && *pp != '\n' && *pp != ' ' && *pp != 0) + { + fprintf(outfile, "** Comma expected after modifier item '%s'\n", m->name); + return FALSE; + } + + p = pp; + first = FALSE; + + if (ctx == CTX_POPPAT && + (pctl->options != 0 || + pctl->tables_id != 0 || + pctl->locale[0] != 0 || + (pctl->control & NOTPOP_CONTROLS) != 0)) + { + fprintf(outfile, "** '%s' is not valid here\n", m->name); + return FALSE; + } + } + +return TRUE; + +INVALID_VALUE: +fprintf(outfile, "** Invalid value in '%.*s'\n", (int)(ep-p), p); +return FALSE; +} + + +/************************************************* +* Get info from a pattern * +*************************************************/ + +/* A wrapped call to pcre2_pattern_info(), applied to the current compiled +pattern. + +Arguments: + what code for the required information + where where to put the answer + unsetok PCRE2_ERROR_UNSET is an "expected" result + +Returns: the return from pcre2_pattern_info() +*/ + +static int +pattern_info(int what, void *where, BOOL unsetok) +{ +int rc; +PCRE2_PATTERN_INFO(rc, compiled_code, what, NULL); /* Exercise the code */ +PCRE2_PATTERN_INFO(rc, compiled_code, what, where); +if (rc >= 0) return 0; +if (rc != PCRE2_ERROR_UNSET || !unsetok) + { + fprintf(outfile, "Error %d from pcre2_pattern_info_%d(%d)\n", rc, test_mode, + what); + if (rc == PCRE2_ERROR_BADMODE) + fprintf(outfile, "Running in %d-bit mode but pattern was compiled in " + "%d-bit mode\n", test_mode, + 8 * (FLD(compiled_code, flags) & PCRE2_MODE_MASK)); + } +return rc; +} + + + +#ifdef SUPPORT_PCRE2_8 +/************************************************* +* Show something in a list * +*************************************************/ + +/* This function just helps to keep the code that uses it tidier. It's used for +various lists of things where there needs to be introductory text before the +first item. As these calls are all in the POSIX-support code, they happen only +when 8-bit mode is supported. */ + +static void +prmsg(const char **msg, const char *s) +{ +fprintf(outfile, "%s %s", *msg, s); +*msg = ""; +} +#endif /* SUPPORT_PCRE2_8 */ + + + +/************************************************* +* Show control bits * +*************************************************/ + +/* Called for mutually exclusive controls and for unsupported POSIX controls. +Because the bits are unique, this can be used for both pattern and data control +words. + +Arguments: + controls control bits + controls2 more control bits + before text to print before + +Returns: nothing +*/ + +static void +show_controls(uint32_t controls, uint32_t controls2, const char *before) +{ +fprintf(outfile, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", + before, + ((controls & CTL_AFTERTEXT) != 0)? " aftertext" : "", + ((controls & CTL_ALLAFTERTEXT) != 0)? " allaftertext" : "", + ((controls & CTL_ALLCAPTURES) != 0)? " allcaptures" : "", + ((controls & CTL_ALLUSEDTEXT) != 0)? " allusedtext" : "", + ((controls & CTL_ALTGLOBAL) != 0)? " altglobal" : "", + ((controls & CTL_BINCODE) != 0)? " bincode" : "", + ((controls2 & CTL2_BSR_SET) != 0)? " bsr" : "", + ((controls & CTL_CALLOUT_CAPTURE) != 0)? " callout_capture" : "", + ((controls2 & CTL2_CALLOUT_EXTRA) != 0)? " callout_extra" : "", + ((controls & CTL_CALLOUT_INFO) != 0)? " callout_info" : "", + ((controls & CTL_CALLOUT_NONE) != 0)? " callout_none" : "", + ((controls2 & CTL2_CALLOUT_NO_WHERE) != 0)? " callout_no_where" : "", + ((controls & CTL_DFA) != 0)? " dfa" : "", + ((controls & CTL_EXPAND) != 0)? " expand" : "", + ((controls & CTL_FINDLIMITS) != 0)? " find_limits" : "", + ((controls & CTL_FRAMESIZE) != 0)? " framesize" : "", + ((controls & CTL_FULLBINCODE) != 0)? " fullbincode" : "", + ((controls & CTL_GETALL) != 0)? " getall" : "", + ((controls & CTL_GLOBAL) != 0)? " global" : "", + ((controls & CTL_HEXPAT) != 0)? " hex" : "", + ((controls & CTL_INFO) != 0)? " info" : "", + ((controls & CTL_JITFAST) != 0)? " jitfast" : "", + ((controls & CTL_JITVERIFY) != 0)? " jitverify" : "", + ((controls & CTL_MARK) != 0)? " mark" : "", + ((controls & CTL_MEMORY) != 0)? " memory" : "", + ((controls2 & CTL2_NL_SET) != 0)? " newline" : "", + ((controls & CTL_NULLCONTEXT) != 0)? " null_context" : "", + ((controls & CTL_POSIX) != 0)? " posix" : "", + ((controls & CTL_POSIX_NOSUB) != 0)? " posix_nosub" : "", + ((controls & CTL_PUSH) != 0)? " push" : "", + ((controls & CTL_PUSHCOPY) != 0)? " pushcopy" : "", + ((controls & CTL_PUSHTABLESCOPY) != 0)? " pushtablescopy" : "", + ((controls & CTL_STARTCHAR) != 0)? " startchar" : "", + ((controls2 & CTL2_SUBSTITUTE_EXTENDED) != 0)? " substitute_extended" : "", + ((controls2 & CTL2_SUBSTITUTE_OVERFLOW_LENGTH) != 0)? " substitute_overflow_length" : "", + ((controls2 & CTL2_SUBSTITUTE_UNKNOWN_UNSET) != 0)? " substitute_unknown_unset" : "", + ((controls2 & CTL2_SUBSTITUTE_UNSET_EMPTY) != 0)? " substitute_unset_empty" : "", + ((controls & CTL_USE_LENGTH) != 0)? " use_length" : "", + ((controls & CTL_UTF8_INPUT) != 0)? " utf8_input" : "", + ((controls & CTL_ZERO_TERMINATE) != 0)? " zero_terminate" : ""); +} + + + +/************************************************* +* Show compile options * +*************************************************/ + +/* Called from show_pattern_info() and for unsupported POSIX options. + +Arguments: + options an options word + before text to print before + after text to print after + +Returns: nothing +*/ + +static void +show_compile_options(uint32_t options, const char *before, const char *after) +{ +if (options == 0) fprintf(outfile, "%s %s", before, after); +else fprintf(outfile, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", + before, + ((options & PCRE2_ALT_BSUX) != 0)? " alt_bsux" : "", + ((options & PCRE2_ALT_CIRCUMFLEX) != 0)? " alt_circumflex" : "", + ((options & PCRE2_ALT_VERBNAMES) != 0)? " alt_verbnames" : "", + ((options & PCRE2_ALLOW_EMPTY_CLASS) != 0)? " allow_empty_class" : "", + ((options & PCRE2_ANCHORED) != 0)? " anchored" : "", + ((options & PCRE2_AUTO_CALLOUT) != 0)? " auto_callout" : "", + ((options & PCRE2_CASELESS) != 0)? " caseless" : "", + ((options & PCRE2_DOLLAR_ENDONLY) != 0)? " dollar_endonly" : "", + ((options & PCRE2_DOTALL) != 0)? " dotall" : "", + ((options & PCRE2_DUPNAMES) != 0)? " dupnames" : "", + ((options & PCRE2_ENDANCHORED) != 0)? " endanchored" : "", + ((options & PCRE2_EXTENDED) != 0)? " extended" : "", + ((options & PCRE2_EXTENDED_MORE) != 0)? " extended_more" : "", + ((options & PCRE2_FIRSTLINE) != 0)? " firstline" : "", + ((options & PCRE2_LITERAL) != 0)? " literal" : "", + ((options & PCRE2_MATCH_UNSET_BACKREF) != 0)? " match_unset_backref" : "", + ((options & PCRE2_MULTILINE) != 0)? " multiline" : "", + ((options & PCRE2_NEVER_BACKSLASH_C) != 0)? " never_backslash_c" : "", + ((options & PCRE2_NEVER_UCP) != 0)? " never_ucp" : "", + ((options & PCRE2_NEVER_UTF) != 0)? " never_utf" : "", + ((options & PCRE2_NO_AUTO_CAPTURE) != 0)? " no_auto_capture" : "", + ((options & PCRE2_NO_AUTO_POSSESS) != 0)? " no_auto_possess" : "", + ((options & PCRE2_NO_DOTSTAR_ANCHOR) != 0)? " no_dotstar_anchor" : "", + ((options & PCRE2_NO_UTF_CHECK) != 0)? " no_utf_check" : "", + ((options & PCRE2_NO_START_OPTIMIZE) != 0)? " no_start_optimize" : "", + ((options & PCRE2_UCP) != 0)? " ucp" : "", + ((options & PCRE2_UNGREEDY) != 0)? " ungreedy" : "", + ((options & PCRE2_USE_OFFSET_LIMIT) != 0)? " use_offset_limit" : "", + ((options & PCRE2_UTF) != 0)? " utf" : "", + after); +} + + +/************************************************* +* Show compile extra options * +*************************************************/ + +/* Called from show_pattern_info() and for unsupported POSIX options. + +Arguments: + options an options word + before text to print before + after text to print after + +Returns: nothing +*/ + +static void +show_compile_extra_options(uint32_t options, const char *before, + const char *after) +{ +if (options == 0) fprintf(outfile, "%s %s", before, after); +else fprintf(outfile, "%s%s%s%s%s%s", + before, + ((options & PCRE2_EXTRA_ALLOW_SURROGATE_ESCAPES) != 0)? " allow_surrogate_escapes" : "", + ((options & PCRE2_EXTRA_BAD_ESCAPE_IS_LITERAL) != 0)? " bad_escape_is_literal" : "", + ((options & PCRE2_EXTRA_MATCH_WORD) != 0)? " match_word" : "", + ((options & PCRE2_EXTRA_MATCH_LINE) != 0)? " match_line" : "", + after); +} + + + +#ifdef SUPPORT_PCRE2_8 +/************************************************* +* Show match options * +*************************************************/ + +/* Called for unsupported POSIX options. */ + +static void +show_match_options(uint32_t options) +{ +fprintf(outfile, "%s%s%s%s%s%s%s%s%s%s%s", + ((options & PCRE2_ANCHORED) != 0)? " anchored" : "", + ((options & PCRE2_DFA_RESTART) != 0)? " dfa_restart" : "", + ((options & PCRE2_DFA_SHORTEST) != 0)? " dfa_shortest" : "", + ((options & PCRE2_ENDANCHORED) != 0)? " endanchored" : "", + ((options & PCRE2_NO_UTF_CHECK) != 0)? " no_utf_check" : "", + ((options & PCRE2_NOTBOL) != 0)? " notbol" : "", + ((options & PCRE2_NOTEMPTY) != 0)? " notempty" : "", + ((options & PCRE2_NOTEMPTY_ATSTART) != 0)? " notempty_atstart" : "", + ((options & PCRE2_NOTEOL) != 0)? " noteol" : "", + ((options & PCRE2_PARTIAL_HARD) != 0)? " partial_hard" : "", + ((options & PCRE2_PARTIAL_SOFT) != 0)? " partial_soft" : ""); +} +#endif /* SUPPORT_PCRE2_8 */ + + + +/************************************************* +* Show memory usage info for a pattern * +*************************************************/ + +static void +show_memory_info(void) +{ +uint32_t name_count, name_entry_size; +size_t size, cblock_size; + +/* One of the test_mode values will always be true, but to stop a compiler +warning we must initialize cblock_size. */ + +cblock_size = 0; +#ifdef SUPPORT_PCRE2_8 +if (test_mode == PCRE8_MODE) cblock_size = sizeof(pcre2_real_code_8); +#endif +#ifdef SUPPORT_PCRE2_16 +if (test_mode == PCRE16_MODE) cblock_size = sizeof(pcre2_real_code_16); +#endif +#ifdef SUPPORT_PCRE2_32 +if (test_mode == PCRE32_MODE) cblock_size = sizeof(pcre2_real_code_32); +#endif + +(void)pattern_info(PCRE2_INFO_SIZE, &size, FALSE); +(void)pattern_info(PCRE2_INFO_NAMECOUNT, &name_count, FALSE); +(void)pattern_info(PCRE2_INFO_NAMEENTRYSIZE, &name_entry_size, FALSE); +fprintf(outfile, "Memory allocation (code space): %d\n", + (int)(size - name_count*name_entry_size*code_unit_size - cblock_size)); +if (pat_patctl.jit != 0) + { + (void)pattern_info(PCRE2_INFO_JITSIZE, &size, FALSE); + fprintf(outfile, "Memory allocation (JIT code): %d\n", (int)size); + } +} + + + +/************************************************* +* Show frame size info for a pattern * +*************************************************/ + +static void +show_framesize(void) +{ +size_t frame_size; +(void)pattern_info(PCRE2_INFO_FRAMESIZE, &frame_size, FALSE); +fprintf(outfile, "Frame size for pcre2_match(): %d\n", (int)frame_size); +} + + + +/************************************************* +* Get and output an error message * +*************************************************/ + +static BOOL +print_error_message(int errorcode, const char *before, const char *after) +{ +int len; +PCRE2_GET_ERROR_MESSAGE(len, errorcode, pbuffer); +if (len < 0) + { + fprintf(outfile, "\n** pcre2test internal error: cannot interpret error " + "number\n** Unexpected return (%d) from pcre2_get_error_message()\n", len); + } +else + { + fprintf(outfile, "%s", before); + PCHARSV(CASTVAR(void *, pbuffer), 0, len, FALSE, outfile); + fprintf(outfile, "%s", after); + } +return len >= 0; +} + + +/************************************************* +* Callback function for callout enumeration * +*************************************************/ + +/* The only differences in the callout emumeration block for different code +unit widths are that the pointers to the subject, the most recent MARK, and a +callout argument string point to strings of the appropriate width. Casts can be +used to deal with this. + +Argument: + cb pointer to enumerate block + callout_data user data + +Returns: 0 +*/ + +static int callout_callback(pcre2_callout_enumerate_block_8 *cb, + void *callout_data) +{ +uint32_t i; +BOOL utf = (FLD(compiled_code, overall_options) & PCRE2_UTF) != 0; + +(void)callout_data; /* Not currently displayed */ + +fprintf(outfile, "Callout "); +if (cb->callout_string != NULL) + { + uint32_t delimiter = CODE_UNIT(cb->callout_string, -1); + fprintf(outfile, "%c", delimiter); + PCHARSV(cb->callout_string, 0, + cb->callout_string_length, utf, outfile); + for (i = 0; callout_start_delims[i] != 0; i++) + if (delimiter == callout_start_delims[i]) + { + delimiter = callout_end_delims[i]; + break; + } + fprintf(outfile, "%c ", delimiter); + } +else fprintf(outfile, "%d ", cb->callout_number); + +fprintf(outfile, "%.*s\n", + (int)((cb->next_item_length == 0)? 1 : cb->next_item_length), + pbuffer8 + cb->pattern_position); + +return 0; +} + + + +/************************************************* +* Show information about a pattern * +*************************************************/ + +/* This function is called after a pattern has been compiled if any of the +information-requesting controls have been set. + +Arguments: none + +Returns: PR_OK continue processing next line + PR_SKIP skip to a blank line + PR_ABEND abort the pcre2test run +*/ + +static int +show_pattern_info(void) +{ +uint32_t compile_options, overall_options, extra_options; + +if ((pat_patctl.control & (CTL_BINCODE|CTL_FULLBINCODE)) != 0) + { + fprintf(outfile, "------------------------------------------------------------------\n"); + PCRE2_PRINTINT((pat_patctl.control & CTL_FULLBINCODE) != 0); + } + +if ((pat_patctl.control & CTL_INFO) != 0) + { + int rc; + void *nametable; + uint8_t *start_bits; + BOOL heap_limit_set, match_limit_set, depth_limit_set; + uint32_t backrefmax, bsr_convention, capture_count, first_ctype, first_cunit, + hasbackslashc, hascrorlf, jchanged, last_ctype, last_cunit, match_empty, + depth_limit, heap_limit, match_limit, minlength, nameentrysize, namecount, + newline_convention; + + /* Exercise the error route. */ + + PCRE2_PATTERN_INFO(rc, compiled_code, 999, NULL); + (void)rc; + + /* These info requests may return PCRE2_ERROR_UNSET. */ + + switch(pattern_info(PCRE2_INFO_HEAPLIMIT, &heap_limit, TRUE)) + { + case 0: + heap_limit_set = TRUE; + break; + + case PCRE2_ERROR_UNSET: + heap_limit_set = FALSE; + break; + + default: + return PR_ABEND; + } + + switch(pattern_info(PCRE2_INFO_MATCHLIMIT, &match_limit, TRUE)) + { + case 0: + match_limit_set = TRUE; + break; + + case PCRE2_ERROR_UNSET: + match_limit_set = FALSE; + break; + + default: + return PR_ABEND; + } + + switch(pattern_info(PCRE2_INFO_DEPTHLIMIT, &depth_limit, TRUE)) + { + case 0: + depth_limit_set = TRUE; + break; + + case PCRE2_ERROR_UNSET: + depth_limit_set = FALSE; + break; + + default: + return PR_ABEND; + } + + /* These info requests should always succeed. */ + + if (pattern_info(PCRE2_INFO_BACKREFMAX, &backrefmax, FALSE) + + pattern_info(PCRE2_INFO_BSR, &bsr_convention, FALSE) + + pattern_info(PCRE2_INFO_CAPTURECOUNT, &capture_count, FALSE) + + pattern_info(PCRE2_INFO_FIRSTBITMAP, &start_bits, FALSE) + + pattern_info(PCRE2_INFO_FIRSTCODEUNIT, &first_cunit, FALSE) + + pattern_info(PCRE2_INFO_FIRSTCODETYPE, &first_ctype, FALSE) + + pattern_info(PCRE2_INFO_HASBACKSLASHC, &hasbackslashc, FALSE) + + pattern_info(PCRE2_INFO_HASCRORLF, &hascrorlf, FALSE) + + pattern_info(PCRE2_INFO_JCHANGED, &jchanged, FALSE) + + pattern_info(PCRE2_INFO_LASTCODEUNIT, &last_cunit, FALSE) + + pattern_info(PCRE2_INFO_LASTCODETYPE, &last_ctype, FALSE) + + pattern_info(PCRE2_INFO_MATCHEMPTY, &match_empty, FALSE) + + pattern_info(PCRE2_INFO_MINLENGTH, &minlength, FALSE) + + pattern_info(PCRE2_INFO_NAMECOUNT, &namecount, FALSE) + + pattern_info(PCRE2_INFO_NAMEENTRYSIZE, &nameentrysize, FALSE) + + pattern_info(PCRE2_INFO_NAMETABLE, &nametable, FALSE) + + pattern_info(PCRE2_INFO_NEWLINE, &newline_convention, FALSE) + != 0) + return PR_ABEND; + + fprintf(outfile, "Capturing subpattern count = %d\n", capture_count); + + if (backrefmax > 0) + fprintf(outfile, "Max back reference = %d\n", backrefmax); + + if (maxlookbehind > 0) + fprintf(outfile, "Max lookbehind = %d\n", maxlookbehind); + + if (heap_limit_set) + fprintf(outfile, "Heap limit = %u\n", heap_limit); + + if (match_limit_set) + fprintf(outfile, "Match limit = %u\n", match_limit); + + if (depth_limit_set) + fprintf(outfile, "Depth limit = %u\n", depth_limit); + + if (namecount > 0) + { + fprintf(outfile, "Named capturing subpatterns:\n"); + for (; namecount > 0; namecount--) + { + int imm2_size = test_mode == PCRE8_MODE ? 2 : 1; + uint32_t length = (uint32_t)STRLEN(nametable + imm2_size); + fprintf(outfile, " "); + PCHARSV(nametable, imm2_size, length, FALSE, outfile); + while (length++ < nameentrysize - imm2_size) putc(' ', outfile); +#ifdef SUPPORT_PCRE2_32 + if (test_mode == PCRE32_MODE) + fprintf(outfile, "%3d\n", (int)(((PCRE2_SPTR32)nametable)[0])); +#endif +#ifdef SUPPORT_PCRE2_16 + if (test_mode == PCRE16_MODE) + fprintf(outfile, "%3d\n", (int)(((PCRE2_SPTR16)nametable)[0])); +#endif +#ifdef SUPPORT_PCRE2_8 + if (test_mode == PCRE8_MODE) + fprintf(outfile, "%3d\n", (int)( + ((((PCRE2_SPTR8)nametable)[0]) << 8) | ((PCRE2_SPTR8)nametable)[1])); +#endif + nametable = (void*)((PCRE2_SPTR8)nametable + nameentrysize * code_unit_size); + } + } + + if (hascrorlf) fprintf(outfile, "Contains explicit CR or LF match\n"); + if (hasbackslashc) fprintf(outfile, "Contains \\C\n"); + if (match_empty) fprintf(outfile, "May match empty string\n"); + + pattern_info(PCRE2_INFO_ARGOPTIONS, &compile_options, FALSE); + pattern_info(PCRE2_INFO_ALLOPTIONS, &overall_options, FALSE); + pattern_info(PCRE2_INFO_EXTRAOPTIONS, &extra_options, FALSE); + + /* Remove UTF/UCP if they were there only because of forbid_utf. This saves + cluttering up the verification output of non-UTF test files. */ + + if ((pat_patctl.options & PCRE2_NEVER_UTF) == 0) + { + compile_options &= ~PCRE2_NEVER_UTF; + overall_options &= ~PCRE2_NEVER_UTF; + } + + if ((pat_patctl.options & PCRE2_NEVER_UCP) == 0) + { + compile_options &= ~PCRE2_NEVER_UCP; + overall_options &= ~PCRE2_NEVER_UCP; + } + + if ((compile_options|overall_options) != 0) + { + if (compile_options == overall_options) + show_compile_options(compile_options, "Options:", "\n"); + else + { + show_compile_options(compile_options, "Compile options:", "\n"); + show_compile_options(overall_options, "Overall options:", "\n"); + } + } + + if (extra_options != 0) + show_compile_extra_options(extra_options, "Extra options:", "\n"); + + if (jchanged) fprintf(outfile, "Duplicate name status changes\n"); + + if ((pat_patctl.control2 & CTL2_BSR_SET) != 0 || + (FLD(compiled_code, flags) & PCRE2_BSR_SET) != 0) + fprintf(outfile, "\\R matches %s\n", (bsr_convention == PCRE2_BSR_UNICODE)? + "any Unicode newline" : "CR, LF, or CRLF"); + + if ((FLD(compiled_code, flags) & PCRE2_NL_SET) != 0) + { + switch (newline_convention) + { + case PCRE2_NEWLINE_CR: + fprintf(outfile, "Forced newline is CR\n"); + break; + + case PCRE2_NEWLINE_LF: + fprintf(outfile, "Forced newline is LF\n"); + break; + + case PCRE2_NEWLINE_CRLF: + fprintf(outfile, "Forced newline is CRLF\n"); + break; + + case PCRE2_NEWLINE_ANYCRLF: + fprintf(outfile, "Forced newline is CR, LF, or CRLF\n"); + break; + + case PCRE2_NEWLINE_ANY: + fprintf(outfile, "Forced newline is any Unicode newline\n"); + break; + + case PCRE2_NEWLINE_NUL: + fprintf(outfile, "Forced newline is NUL\n"); + break; + + default: + break; + } + } + + if (first_ctype == 2) + { + fprintf(outfile, "First code unit at start or follows newline\n"); + } + else if (first_ctype == 1) + { + const char *caseless = + ((FLD(compiled_code, flags) & PCRE2_FIRSTCASELESS) == 0)? + "" : " (caseless)"; + if (PRINTOK(first_cunit)) + fprintf(outfile, "First code unit = \'%c\'%s\n", first_cunit, caseless); + else + { + fprintf(outfile, "First code unit = "); + pchar(first_cunit, FALSE, outfile); + fprintf(outfile, "%s\n", caseless); + } + } + else if (start_bits != NULL) + { + int i; + int c = 24; + fprintf(outfile, "Starting code units: "); + for (i = 0; i < 256; i++) + { + if ((start_bits[i/8] & (1<<(i&7))) != 0) + { + if (c > 75) + { + fprintf(outfile, "\n "); + c = 2; + } + if (PRINTOK(i) && i != ' ') + { + fprintf(outfile, "%c ", i); + c += 2; + } + else + { + fprintf(outfile, "\\x%02x ", i); + c += 5; + } + } + } + fprintf(outfile, "\n"); + } + + if (last_ctype != 0) + { + const char *caseless = + ((FLD(compiled_code, flags) & PCRE2_LASTCASELESS) == 0)? + "" : " (caseless)"; + if (PRINTOK(last_cunit)) + fprintf(outfile, "Last code unit = \'%c\'%s\n", last_cunit, caseless); + else + { + fprintf(outfile, "Last code unit = "); + pchar(last_cunit, FALSE, outfile); + fprintf(outfile, "%s\n", caseless); + } + } + + fprintf(outfile, "Subject length lower bound = %d\n", minlength); + + if (pat_patctl.jit != 0 && (pat_patctl.control & CTL_JITVERIFY) != 0) + { + if (FLD(compiled_code, executable_jit) != NULL) + fprintf(outfile, "JIT compilation was successful\n"); + else + { +#ifdef SUPPORT_JIT + fprintf(outfile, "JIT compilation was not successful"); + if (jitrc != 0 && !print_error_message(jitrc, " (", ")")) + return PR_ABEND; + fprintf(outfile, "\n"); +#else + fprintf(outfile, "JIT support is not available in this version of PCRE2\n"); +#endif + } + } + } + +if ((pat_patctl.control & CTL_CALLOUT_INFO) != 0) + { + int errorcode; + PCRE2_CALLOUT_ENUMERATE(errorcode, callout_callback, 0); + if (errorcode != 0) + { + fprintf(outfile, "Callout enumerate failed: error %d: ", errorcode); + if (errorcode < 0 && !print_error_message(errorcode, "", "\n")) + return PR_ABEND; + return PR_SKIP; + } + } + +return PR_OK; +} + + + +/************************************************* +* Handle serialization error * +*************************************************/ + +/* Print an error message after a serialization failure. + +Arguments: + rc the error code + msg an initial message for what failed + +Returns: FALSE if print_error_message() fails +*/ + +static BOOL +serial_error(int rc, const char *msg) +{ +fprintf(outfile, "%s failed: error %d: ", msg, rc); +return print_error_message(rc, "", "\n"); +} + + + +/************************************************* +* Open file for save/load commands * +*************************************************/ + +/* This function decodes the file name and opens the file. + +Arguments: + buffptr point after the #command + mode open mode + fptr points to the FILE variable + +Returns: PR_OK or PR_ABEND +*/ + +static int +open_file(uint8_t *buffptr, const char *mode, FILE **fptr) +{ +char *endf; +char *filename = (char *)buffptr; +while (isspace(*filename)) filename++; +endf = filename + strlen8(filename); +while (endf > filename && isspace(endf[-1])) endf--; + +if (endf == filename) + { + fprintf(outfile, "** File name expected after #save\n"); + return PR_ABEND; + } + +*endf = 0; +*fptr = fopen((const char *)filename, mode); +if (*fptr == NULL) + { + fprintf(outfile, "** Failed to open '%s': %s\n", filename, strerror(errno)); + return PR_ABEND; + } + +return PR_OK; +} + + + +/************************************************* +* Process command line * +*************************************************/ + +/* This function is called for lines beginning with # and a character that is +not ! or whitespace, when encountered between tests, which means that there is +no compiled pattern (compiled_code is NULL). The line is in buffer. + +Arguments: none + +Returns: PR_OK continue processing next line + PR_SKIP skip to a blank line + PR_ABEND abort the pcre2test run +*/ + +static int +process_command(void) +{ +FILE *f; +PCRE2_SIZE serial_size; +size_t i; +int rc, cmd, cmdlen, yield; +uint16_t first_listed_newline; +const char *cmdname; +uint8_t *argptr, *serial; + +yield = PR_OK; +cmd = CMD_UNKNOWN; +cmdlen = 0; + +for (i = 0; i < cmdlistcount; i++) + { + cmdname = cmdlist[i].name; + cmdlen = strlen(cmdname); + if (strncmp((char *)(buffer+1), cmdname, cmdlen) == 0 && + isspace(buffer[cmdlen+1])) + { + cmd = cmdlist[i].value; + break; + } + } + +argptr = buffer + cmdlen + 1; + +if (restrict_for_perl_test && cmd != CMD_PATTERN && cmd != CMD_SUBJECT) + { + fprintf(outfile, "** #%s is not allowed after #perltest\n", cmdname); + return PR_ABEND; + } + +switch(cmd) + { + case CMD_UNKNOWN: + fprintf(outfile, "** Unknown command: %s", buffer); + break; + + case CMD_FORBID_UTF: + forbid_utf = PCRE2_NEVER_UTF|PCRE2_NEVER_UCP; + break; + + case CMD_PERLTEST: + restrict_for_perl_test = TRUE; + break; + + /* Set default pattern modifiers */ + + case CMD_PATTERN: + (void)decode_modifiers(argptr, CTX_DEFPAT, &def_patctl, NULL); + if (def_patctl.jit == 0 && (def_patctl.control & CTL_JITVERIFY) != 0) + def_patctl.jit = 7; + break; + + /* Set default subject modifiers */ + + case CMD_SUBJECT: + (void)decode_modifiers(argptr, CTX_DEFDAT, NULL, &def_datctl); + break; + + /* Check the default newline, and if not one of those listed, set up the + first one to be forced. An empty list unsets. */ + + case CMD_NEWLINE_DEFAULT: + local_newline_default = 0; /* Unset */ + first_listed_newline = 0; + for (;;) + { + while (isspace(*argptr)) argptr++; + if (*argptr == 0) break; + for (i = 1; i < sizeof(newlines)/sizeof(char *); i++) + { + size_t nlen = strlen(newlines[i]); + if (strncmpic(argptr, (const uint8_t *)newlines[i], nlen) == 0 && + isspace(argptr[nlen])) + { + if (i == NEWLINE_DEFAULT) return PR_OK; /* Default is valid */ + if (first_listed_newline == 0) first_listed_newline = i; + } + } + while (*argptr != 0 && !isspace(*argptr)) argptr++; + } + local_newline_default = first_listed_newline; + break; + + /* Pop or copy a compiled pattern off the stack. Modifiers that do not affect + the compiled pattern (e.g. to give information) are permitted. The default + pattern modifiers are ignored. */ + + case CMD_POP: + case CMD_POPCOPY: + if (patstacknext <= 0) + { + fprintf(outfile, "** Can't pop off an empty stack\n"); + return PR_SKIP; + } + memset(&pat_patctl, 0, sizeof(patctl)); /* Completely unset */ + if (!decode_modifiers(argptr, CTX_POPPAT, &pat_patctl, NULL)) + return PR_SKIP; + + if (cmd == CMD_POP) + { + SET(compiled_code, patstack[--patstacknext]); + } + else + { + PCRE2_CODE_COPY_FROM_VOID(compiled_code, patstack[patstacknext - 1]); + } + + if (pat_patctl.jit != 0) + { + PCRE2_JIT_COMPILE(jitrc, compiled_code, pat_patctl.jit); + } + if ((pat_patctl.control & CTL_MEMORY) != 0) show_memory_info(); + if ((pat_patctl.control & CTL_FRAMESIZE) != 0) show_framesize(); + if ((pat_patctl.control & CTL_ANYINFO) != 0) + { + rc = show_pattern_info(); + if (rc != PR_OK) return rc; + } + break; + + /* Save the stack of compiled patterns to a file, then empty the stack. */ + + case CMD_SAVE: + if (patstacknext <= 0) + { + fprintf(outfile, "** No stacked patterns to save\n"); + return PR_OK; + } + + rc = open_file(argptr+1, BINARY_OUTPUT_MODE, &f); + if (rc != PR_OK) return rc; + + PCRE2_SERIALIZE_ENCODE(rc, patstack, patstacknext, &serial, &serial_size, + general_context); + if (rc < 0) + { + fclose(f); + if (!serial_error(rc, "Serialization")) return PR_ABEND; + break; + } + + /* Write the length at the start of the file to make it straightforward to + get the right memory when re-loading. This saves having to read the file size + in different operating systems. To allow for different endianness (even + though reloading with the opposite endianness does not work), write the + length byte-by-byte. */ + + for (i = 0; i < 4; i++) fputc((serial_size >> (i*8)) & 255, f); + if (fwrite(serial, 1, serial_size, f) != serial_size) + { + fprintf(outfile, "** Wrong return from fwrite()\n"); + fclose(f); + return PR_ABEND; + } + + fclose(f); + PCRE2_SERIALIZE_FREE(serial); + while(patstacknext > 0) + { + SET(compiled_code, patstack[--patstacknext]); + SUB1(pcre2_code_free, compiled_code); + } + SET(compiled_code, NULL); + break; + + /* Load a set of compiled patterns from a file onto the stack */ + + case CMD_LOAD: + rc = open_file(argptr+1, BINARY_INPUT_MODE, &f); + if (rc != PR_OK) return rc; + + serial_size = 0; + for (i = 0; i < 4; i++) serial_size |= fgetc(f) << (i*8); + + serial = malloc(serial_size); + if (serial == NULL) + { + fprintf(outfile, "** Failed to get memory (size %" SIZ_FORM ") for #load\n", + SIZ_CAST serial_size); + fclose(f); + return PR_ABEND; + } + + i = fread(serial, 1, serial_size, f); + fclose(f); + + if (i != serial_size) + { + fprintf(outfile, "** Wrong return from fread()\n"); + yield = PR_ABEND; + } + else + { + PCRE2_SERIALIZE_GET_NUMBER_OF_CODES(rc, serial); + if (rc < 0) + { + if (!serial_error(rc, "Get number of codes")) yield = PR_ABEND; + } + else + { + if (rc + patstacknext > PATSTACKSIZE) + { + fprintf(outfile, "** Not enough space on pattern stack for %d pattern%s\n", + rc, (rc == 1)? "" : "s"); + rc = PATSTACKSIZE - patstacknext; + fprintf(outfile, "** Decoding %d pattern%s\n", rc, + (rc == 1)? "" : "s"); + } + PCRE2_SERIALIZE_DECODE(rc, patstack + patstacknext, rc, serial, + general_context); + if (rc < 0) + { + if (!serial_error(rc, "Deserialization")) yield = PR_ABEND; + } + else patstacknext += rc; + } + } + + free(serial); + break; + } + +return yield; +} + + + +/************************************************* +* Process pattern line * +*************************************************/ + +/* This function is called when the input buffer contains the start of a +pattern. The first character is known to be a valid delimiter. The pattern is +read, modifiers are interpreted, and a suitable local context is set up for +this test. The pattern is then compiled. + +Arguments: none + +Returns: PR_OK continue processing next line + PR_SKIP skip to a blank line + PR_ABEND abort the pcre2test run +*/ + +static int +process_pattern(void) +{ +BOOL utf; +uint32_t k; +uint8_t *p = buffer; +unsigned int delimiter = *p++; +int errorcode; +void *use_pat_context; +uint32_t use_forbid_utf = forbid_utf; +PCRE2_SIZE patlen; +PCRE2_SIZE valgrind_access_length; +PCRE2_SIZE erroroffset; + +/* Initialize the context and pattern/data controls for this test from the +defaults. */ + +PATCTXCPY(pat_context, default_pat_context); +memcpy(&pat_patctl, &def_patctl, sizeof(patctl)); + +/* Find the end of the pattern, reading more lines if necessary. */ + +for(;;) + { + while (*p != 0) + { + if (*p == '\\' && p[1] != 0) p++; + else if (*p == delimiter) break; + p++; + } + if (*p != 0) break; + if ((p = extend_inputline(infile, p, " > ")) == NULL) + { + fprintf(outfile, "** Unexpected EOF\n"); + return PR_ABEND; + } + if (!INTERACTIVE(infile)) fprintf(outfile, "%s", (char *)p); + } + +/* If the first character after the delimiter is backslash, make the pattern +end with backslash. This is purely to provide a way of testing for the error +message when a pattern ends with backslash. */ + +if (p[1] == '\\') *p++ = '\\'; + +/* Terminate the pattern at the delimiter, and compute the length. */ + +*p++ = 0; +patlen = p - buffer - 2; + +/* Look for modifiers and options after the final delimiter. */ + +if (!decode_modifiers(p, CTX_PAT, &pat_patctl, NULL)) return PR_SKIP; +utf = (pat_patctl.options & PCRE2_UTF) != 0; + +/* The utf8_input modifier is not allowed in 8-bit mode, and is mutually +exclusive with the utf modifier. */ + +if ((pat_patctl.control & CTL_UTF8_INPUT) != 0) + { + if (test_mode == PCRE8_MODE) + { + fprintf(outfile, "** The utf8_input modifier is not allowed in 8-bit mode\n"); + return PR_SKIP; + } + if (utf) + { + fprintf(outfile, "** The utf and utf8_input modifiers are mutually exclusive\n"); + return PR_SKIP; + } + } + +/* The convert and posix modifiers are mutually exclusive. */ + +if (pat_patctl.convert_type != CONVERT_UNSET && + (pat_patctl.control & CTL_POSIX) != 0) + { + fprintf(outfile, "** The convert and posix modifiers are mutually exclusive\n"); + return PR_SKIP; + } + +/* Check for mutually exclusive control modifiers. At present, these are all in +the first control word. */ + +for (k = 0; k < sizeof(exclusive_pat_controls)/sizeof(uint32_t); k++) + { + uint32_t c = pat_patctl.control & exclusive_pat_controls[k]; + if (c != 0 && c != (c & (~c+1))) + { + show_controls(c, 0, "** Not allowed together:"); + fprintf(outfile, "\n"); + return PR_SKIP; + } + } + +/* Assume full JIT compile for jitverify and/or jitfast if nothing else was +specified. */ + +if (pat_patctl.jit == 0 && + (pat_patctl.control & (CTL_JITVERIFY|CTL_JITFAST)) != 0) + pat_patctl.jit = 7; + +/* Now copy the pattern to pbuffer8 for use in 8-bit testing and for reflecting +in callouts. Convert from hex if requested (literal strings in quotes may be +present within the hexadecimal pairs). The result must necessarily be fewer +characters so will always fit in pbuffer8. */ + +if ((pat_patctl.control & CTL_HEXPAT) != 0) + { + uint8_t *pp, *pt; + uint32_t c, d; + + pt = pbuffer8; + for (pp = buffer + 1; *pp != 0; pp++) + { + if (isspace(*pp)) continue; + c = *pp++; + + /* Handle a literal substring */ + + if (c == '\'' || c == '"') + { + uint8_t *pq = pp; + for (;; pp++) + { + d = *pp; + if (d == 0) + { + fprintf(outfile, "** Missing closing quote in hex pattern: " + "opening quote is at offset %" PTR_FORM ".\n", pq - buffer - 2); + return PR_SKIP; + } + if (d == c) break; + *pt++ = d; + } + } + + /* Expect a hex pair */ + + else + { + if (!isxdigit(c)) + { + fprintf(outfile, "** Unexpected non-hex-digit '%c' at offset %" + PTR_FORM " in hex pattern: quote missing?\n", c, pp - buffer - 2); + return PR_SKIP; + } + if (*pp == 0) + { + fprintf(outfile, "** Odd number of digits in hex pattern\n"); + return PR_SKIP; + } + d = *pp; + if (!isxdigit(d)) + { + fprintf(outfile, "** Unexpected non-hex-digit '%c' at offset %" + PTR_FORM " in hex pattern: quote missing?\n", d, pp - buffer - 1); + return PR_SKIP; + } + c = toupper(c); + d = toupper(d); + *pt++ = ((isdigit(c)? (c - '0') : (c - 'A' + 10)) << 4) + + (isdigit(d)? (d - '0') : (d - 'A' + 10)); + } + } + *pt = 0; + patlen = pt - pbuffer8; + } + +/* If not a hex string, process for repetition expansion if requested. */ + +else if ((pat_patctl.control & CTL_EXPAND) != 0) + { + uint8_t *pp, *pt; + + pt = pbuffer8; + for (pp = buffer + 1; *pp != 0; pp++) + { + uint8_t *pc = pp; + uint32_t count = 1; + size_t length = 1; + + /* Check for replication syntax; if not found, the defaults just set will + prevail and one character will be copied. */ + + if (pp[0] == '\\' && pp[1] == '[') + { + uint8_t *pe; + for (pe = pp + 2; *pe != 0; pe++) + { + if (pe[0] == ']' && pe[1] == '{') + { + uint32_t clen = pe - pc - 2; + uint32_t i = 0; + unsigned long uli; + char *endptr; + + pe += 2; + uli = strtoul((const char *)pe, &endptr, 10); + if (U32OVERFLOW(uli)) + { + fprintf(outfile, "** Pattern repeat count too large\n"); + return PR_SKIP; + } + + i = (uint32_t)uli; + pe = (uint8_t *)endptr; + if (*pe == '}') + { + if (i == 0) + { + fprintf(outfile, "** Zero repeat not allowed\n"); + return PR_SKIP; + } + pc += 2; + count = i; + length = clen; + pp = pe; + break; + } + } + } + } + + /* Add to output. If the buffer is too small expand it. The function for + expanding buffers always keeps buffer and pbuffer8 in step as far as their + size goes. */ + + while (pt + count * length > pbuffer8 + pbuffer8_size) + { + size_t pc_offset = pc - buffer; + size_t pp_offset = pp - buffer; + size_t pt_offset = pt - pbuffer8; + expand_input_buffers(); + pc = buffer + pc_offset; + pp = buffer + pp_offset; + pt = pbuffer8 + pt_offset; + } + + for (; count > 0; count--) + { + memcpy(pt, pc, length); + pt += length; + } + } + + *pt = 0; + patlen = pt - pbuffer8; + + if ((pat_patctl.control & CTL_INFO) != 0) + fprintf(outfile, "Expanded: %s\n", pbuffer8); + } + +/* Neither hex nor expanded, just copy the input verbatim. */ + +else + { + strncpy((char *)pbuffer8, (char *)(buffer+1), patlen + 1); + } + +/* Sort out character tables */ + +if (pat_patctl.locale[0] != 0) + { + if (pat_patctl.tables_id != 0) + { + fprintf(outfile, "** 'Locale' and 'tables' must not both be set\n"); + return PR_SKIP; + } + if (setlocale(LC_CTYPE, (const char *)pat_patctl.locale) == NULL) + { + fprintf(outfile, "** Failed to set locale '%s'\n", pat_patctl.locale); + return PR_SKIP; + } + if (strcmp((const char *)pat_patctl.locale, (const char *)locale_name) != 0) + { + strcpy((char *)locale_name, (char *)pat_patctl.locale); + if (locale_tables != NULL) free((void *)locale_tables); + PCRE2_MAKETABLES(locale_tables); + } + use_tables = locale_tables; + } + +else switch (pat_patctl.tables_id) + { + case 0: use_tables = NULL; break; + case 1: use_tables = tables1; break; + case 2: use_tables = tables2; break; + default: + fprintf(outfile, "** 'Tables' must specify 0, 1, or 2.\n"); + return PR_SKIP; + } + +PCRE2_SET_CHARACTER_TABLES(pat_context, use_tables); + +/* Set up for the stackguard test. */ + +if (pat_patctl.stackguard_test != 0) + { + PCRE2_SET_COMPILE_RECURSION_GUARD(pat_context, stack_guard, NULL); + } + +/* Handle compiling via the POSIX interface, which doesn't support the +timing, showing, or debugging options, nor the ability to pass over +local character tables. Neither does it have 16-bit or 32-bit support. */ + +if ((pat_patctl.control & CTL_POSIX) != 0) + { +#ifdef SUPPORT_PCRE2_8 + int rc; + int cflags = 0; + const char *msg = "** Ignored with POSIX interface:"; +#endif + + if (test_mode != PCRE8_MODE) + { + fprintf(outfile, "** The POSIX interface is available only in 8-bit mode\n"); + return PR_SKIP; + } + +#ifdef SUPPORT_PCRE2_8 + /* Check for features that the POSIX interface does not support. */ + + if (pat_patctl.locale[0] != 0) prmsg(&msg, "locale"); + if (pat_patctl.replacement[0] != 0) prmsg(&msg, "replace"); + if (pat_patctl.tables_id != 0) prmsg(&msg, "tables"); + if (pat_patctl.stackguard_test != 0) prmsg(&msg, "stackguard"); + if (timeit > 0) prmsg(&msg, "timing"); + if (pat_patctl.jit != 0) prmsg(&msg, "JIT"); + + if ((pat_patctl.options & ~POSIX_SUPPORTED_COMPILE_OPTIONS) != 0) + { + show_compile_options( + pat_patctl.options & ~POSIX_SUPPORTED_COMPILE_OPTIONS, msg, ""); + msg = ""; + } + + if ((FLD(pat_context, extra_options) & + ~POSIX_SUPPORTED_COMPILE_EXTRA_OPTIONS) != 0) + { + show_compile_extra_options( + FLD(pat_context, extra_options) & ~POSIX_SUPPORTED_COMPILE_EXTRA_OPTIONS, + msg, ""); + msg = ""; + } + + if ((pat_patctl.control & ~POSIX_SUPPORTED_COMPILE_CONTROLS) != 0 || + (pat_patctl.control2 & ~POSIX_SUPPORTED_COMPILE_CONTROLS2) != 0) + { + show_controls(pat_patctl.control & ~POSIX_SUPPORTED_COMPILE_CONTROLS, + pat_patctl.control2 & ~POSIX_SUPPORTED_COMPILE_CONTROLS2, msg); + msg = ""; + } + + if (local_newline_default != 0) prmsg(&msg, "#newline_default"); + if (FLD(pat_context, max_pattern_length) != PCRE2_UNSET) + prmsg(&msg, "max_pattern_length"); + if (FLD(pat_context, parens_nest_limit) != PARENS_NEST_DEFAULT) + prmsg(&msg, "parens_nest_limit"); + + if (msg[0] == 0) fprintf(outfile, "\n"); + + /* Translate PCRE2 options to POSIX options and then compile. */ + + if (utf) cflags |= REG_UTF; + if ((pat_patctl.control & CTL_POSIX_NOSUB) != 0) cflags |= REG_NOSUB; + if ((pat_patctl.options & PCRE2_UCP) != 0) cflags |= REG_UCP; + if ((pat_patctl.options & PCRE2_CASELESS) != 0) cflags |= REG_ICASE; + if ((pat_patctl.options & PCRE2_LITERAL) != 0) cflags |= REG_NOSPEC; + if ((pat_patctl.options & PCRE2_MULTILINE) != 0) cflags |= REG_NEWLINE; + if ((pat_patctl.options & PCRE2_DOTALL) != 0) cflags |= REG_DOTALL; + if ((pat_patctl.options & PCRE2_UNGREEDY) != 0) cflags |= REG_UNGREEDY; + + if ((pat_patctl.control & (CTL_HEXPAT|CTL_USE_LENGTH)) != 0) + { + preg.re_endp = (char *)pbuffer8 + patlen; + cflags |= REG_PEND; + } + + rc = regcomp(&preg, (char *)pbuffer8, cflags); + + /* Compiling failed */ + + if (rc != 0) + { + size_t bsize, usize; + int psize; + + preg.re_pcre2_code = NULL; /* In case something was left in there */ + preg.re_match_data = NULL; + + bsize = (pat_patctl.regerror_buffsize != 0)? + pat_patctl.regerror_buffsize : pbuffer8_size; + if (bsize + 8 < pbuffer8_size) + memcpy(pbuffer8 + bsize, "DEADBEEF", 8); + usize = regerror(rc, &preg, (char *)pbuffer8, bsize); + + /* Inside regerror(), snprintf() is used. If the buffer is too small, some + versions of snprintf() put a zero byte at the end, but others do not. + Therefore, we print a maximum of one less than the size of the buffer. */ + + psize = (int)bsize - 1; + fprintf(outfile, "Failed: POSIX code %d: %.*s\n", rc, psize, pbuffer8); + if (usize > bsize) + { + fprintf(outfile, "** regerror() message truncated\n"); + if (memcmp(pbuffer8 + bsize, "DEADBEEF", 8) != 0) + fprintf(outfile, "** regerror() buffer overflow\n"); + } + return PR_SKIP; + } + + /* Compiling succeeded. Check that the values in the preg block are sensible. + It can happen that pcre2test is accidentally linked with a different POSIX + library which succeeds, but of course puts different things into preg. In + this situation, calling regfree() may cause a segfault (or invalid free() in + valgrind), so ensure that preg.re_pcre2_code is NULL, which suppresses the + calling of regfree() on exit. */ + + if (preg.re_pcre2_code == NULL || + ((pcre2_real_code_8 *)preg.re_pcre2_code)->magic_number != MAGIC_NUMBER || + ((pcre2_real_code_8 *)preg.re_pcre2_code)->top_bracket != preg.re_nsub || + preg.re_match_data == NULL || + preg.re_cflags != cflags) + { + fprintf(outfile, + "** The regcomp() function returned zero (success), but the values set\n" + "** in the preg block are not valid for PCRE2. Check that pcre2test is\n" + "** linked with PCRE2's pcre2posix module (-lpcre2-posix) and not with\n" + "** some other POSIX regex library.\n**\n"); + preg.re_pcre2_code = NULL; + return PR_ABEND; + } + + return PR_OK; +#endif /* SUPPORT_PCRE2_8 */ + } + +/* Handle compiling via the native interface. Controls that act later are +ignored with "push". Replacements are locked out. */ + +if ((pat_patctl.control & (CTL_PUSH|CTL_PUSHCOPY|CTL_PUSHTABLESCOPY)) != 0) + { + if (pat_patctl.replacement[0] != 0) + { + fprintf(outfile, "** Replacement text is not supported with 'push'.\n"); + return PR_OK; + } + if ((pat_patctl.control & ~PUSH_SUPPORTED_COMPILE_CONTROLS) != 0 || + (pat_patctl.control2 & ~PUSH_SUPPORTED_COMPILE_CONTROLS2) != 0) + { + show_controls(pat_patctl.control & ~PUSH_SUPPORTED_COMPILE_CONTROLS, + pat_patctl.control2 & ~PUSH_SUPPORTED_COMPILE_CONTROLS2, + "** Ignored when compiled pattern is stacked with 'push':"); + fprintf(outfile, "\n"); + } + if ((pat_patctl.control & PUSH_COMPILE_ONLY_CONTROLS) != 0 || + (pat_patctl.control2 & PUSH_COMPILE_ONLY_CONTROLS2) != 0) + { + show_controls(pat_patctl.control & PUSH_COMPILE_ONLY_CONTROLS, + pat_patctl.control2 & PUSH_COMPILE_ONLY_CONTROLS2, + "** Applies only to compile when pattern is stacked with 'push':"); + fprintf(outfile, "\n"); + } + } + +/* Convert the input in non-8-bit modes. */ + +errorcode = 0; + +#ifdef SUPPORT_PCRE2_16 +if (test_mode == PCRE16_MODE) errorcode = to16(pbuffer8, utf, &patlen); +#endif + +#ifdef SUPPORT_PCRE2_32 +if (test_mode == PCRE32_MODE) errorcode = to32(pbuffer8, utf, &patlen); +#endif + +switch(errorcode) + { + case -1: + fprintf(outfile, "** Failed: invalid UTF-8 string cannot be " + "converted to %d-bit string\n", (test_mode == PCRE16_MODE)? 16:32); + return PR_SKIP; + + case -2: + fprintf(outfile, "** Failed: character value greater than 0x10ffff " + "cannot be converted to UTF\n"); + return PR_SKIP; + + case -3: + fprintf(outfile, "** Failed: character value greater than 0xffff " + "cannot be converted to 16-bit in non-UTF mode\n"); + return PR_SKIP; + + default: + break; + } + +/* The pattern is now in pbuffer[8|16|32], with the length in code units in +patlen. If it is to be converted, copy the result back afterwards so that it +ends up back in the usual place. */ + +if (pat_patctl.convert_type != CONVERT_UNSET) + { + int rc; + int convert_return = PR_OK; + uint32_t convert_options = pat_patctl.convert_type; + void *converted_pattern; + PCRE2_SIZE converted_length; + + if (pat_patctl.convert_length != 0) + { + converted_length = pat_patctl.convert_length; + converted_pattern = malloc(converted_length * code_unit_size); + if (converted_pattern == NULL) + { + fprintf(outfile, "** Failed: malloc failed for converted pattern\n"); + return PR_SKIP; + } + } + else converted_pattern = NULL; /* Let the library allocate */ + + if (utf) convert_options |= PCRE2_CONVERT_UTF; + if ((pat_patctl.options & PCRE2_NO_UTF_CHECK) != 0) + convert_options |= PCRE2_CONVERT_NO_UTF_CHECK; + + CONCTXCPY(con_context, default_con_context); + + if (pat_patctl.convert_glob_escape != 0) + { + uint32_t escape = (pat_patctl.convert_glob_escape == '0')? 0 : + pat_patctl.convert_glob_escape; + PCRE2_SET_GLOB_ESCAPE(rc, con_context, escape); + if (rc != 0) + { + fprintf(outfile, "** Invalid glob escape '%c'\n", + pat_patctl.convert_glob_escape); + convert_return = PR_SKIP; + goto CONVERT_FINISH; + } + } + + if (pat_patctl.convert_glob_separator != 0) + { + PCRE2_SET_GLOB_SEPARATOR(rc, con_context, pat_patctl.convert_glob_separator); + if (rc != 0) + { + fprintf(outfile, "** Invalid glob separator '%c'\n", + pat_patctl.convert_glob_separator); + convert_return = PR_SKIP; + goto CONVERT_FINISH; + } + } + + PCRE2_PATTERN_CONVERT(rc, pbuffer, patlen, convert_options, + &converted_pattern, &converted_length, con_context); + + if (rc != 0) + { + fprintf(outfile, "** Pattern conversion error at offset %" SIZ_FORM ": ", + SIZ_CAST converted_length); + convert_return = print_error_message(rc, "", "\n")? PR_SKIP:PR_ABEND; + } + + /* Output the converted pattern, then copy it. */ + + else + { + PCHARSV(converted_pattern, 0, converted_length, utf, outfile); + fprintf(outfile, "\n"); + patlen = converted_length; + CONVERT_COPY(pbuffer, converted_pattern, converted_length + 1); + } + + /* Free the converted pattern. */ + + CONVERT_FINISH: + if (pat_patctl.convert_length != 0) + free(converted_pattern); + else + PCRE2_CONVERTED_PATTERN_FREE(converted_pattern); + + /* Return if conversion was unsuccessful. */ + + if (convert_return != PR_OK) return convert_return; + } + +/* By default we pass a zero-terminated pattern, but a length is passed if +"use_length" was specified or this is a hex pattern (which might contain binary +zeros). When valgrind is supported, arrange for the unused part of the buffer +to be marked as no access. */ + +valgrind_access_length = patlen; +if ((pat_patctl.control & (CTL_HEXPAT|CTL_USE_LENGTH)) == 0) + { + patlen = PCRE2_ZERO_TERMINATED; + valgrind_access_length += 1; /* For the terminating zero */ + } + +#ifdef SUPPORT_VALGRIND +#ifdef SUPPORT_PCRE2_8 +if (test_mode == PCRE8_MODE && pbuffer8 != NULL) + { + VALGRIND_MAKE_MEM_NOACCESS(pbuffer8 + valgrind_access_length, + pbuffer8_size - valgrind_access_length); + } +#endif +#ifdef SUPPORT_PCRE2_16 +if (test_mode == PCRE16_MODE && pbuffer16 != NULL) + { + VALGRIND_MAKE_MEM_NOACCESS(pbuffer16 + valgrind_access_length, + pbuffer16_size - valgrind_access_length*sizeof(uint16_t)); + } +#endif +#ifdef SUPPORT_PCRE2_32 +if (test_mode == PCRE32_MODE && pbuffer32 != NULL) + { + VALGRIND_MAKE_MEM_NOACCESS(pbuffer32 + valgrind_access_length, + pbuffer32_size - valgrind_access_length*sizeof(uint32_t)); + } +#endif +#else /* Valgrind not supported */ +(void)valgrind_access_length; /* Avoid compiler warning */ +#endif + +/* If #newline_default has been used and the library was not compiled with an +appropriate default newline setting, local_newline_default will be non-zero. We +use this if there is no explicit newline modifier. */ + +if ((pat_patctl.control2 & CTL2_NL_SET) == 0 && local_newline_default != 0) + { + SETFLD(pat_context, newline_convention, local_newline_default); + } + +/* The null_context modifier is used to test calling pcre2_compile() with a +NULL context. */ + +use_pat_context = ((pat_patctl.control & CTL_NULLCONTEXT) != 0)? + NULL : PTR(pat_context); + +/* If PCRE2_LITERAL is set, set use_forbid_utf zero because PCRE2_NEVER_UTF +and PCRE2_NEVER_UCP are invalid with it. */ + +if ((pat_patctl.options & PCRE2_LITERAL) != 0) use_forbid_utf = 0; + +/* Compile many times when timing. */ + +if (timeit > 0) + { + int i; + clock_t time_taken = 0; + for (i = 0; i < timeit; i++) + { + clock_t start_time = clock(); + PCRE2_COMPILE(compiled_code, pbuffer, patlen, + pat_patctl.options|use_forbid_utf, &errorcode, &erroroffset, + use_pat_context); + time_taken += clock() - start_time; + if (TEST(compiled_code, !=, NULL)) + { SUB1(pcre2_code_free, compiled_code); } + } + total_compile_time += time_taken; + fprintf(outfile, "Compile time %.4f milliseconds\n", + (((double)time_taken * 1000.0) / (double)timeit) / + (double)CLOCKS_PER_SEC); + } + +/* A final compile that is used "for real". */ + +PCRE2_COMPILE(compiled_code, pbuffer, patlen, pat_patctl.options|use_forbid_utf, + &errorcode, &erroroffset, use_pat_context); + +/* Call the JIT compiler if requested. When timing, we must free and recompile +the pattern each time because that is the only way to free the JIT compiled +code. We know that compilation will always succeed. */ + +if (TEST(compiled_code, !=, NULL) && pat_patctl.jit != 0) + { + if (timeit > 0) + { + int i; + clock_t time_taken = 0; + for (i = 0; i < timeit; i++) + { + clock_t start_time; + SUB1(pcre2_code_free, compiled_code); + PCRE2_COMPILE(compiled_code, pbuffer, patlen, + pat_patctl.options|use_forbid_utf, &errorcode, &erroroffset, + use_pat_context); + start_time = clock(); + PCRE2_JIT_COMPILE(jitrc,compiled_code, pat_patctl.jit); + time_taken += clock() - start_time; + } + total_jit_compile_time += time_taken; + fprintf(outfile, "JIT compile %.4f milliseconds\n", + (((double)time_taken * 1000.0) / (double)timeit) / + (double)CLOCKS_PER_SEC); + } + else + { + PCRE2_JIT_COMPILE(jitrc, compiled_code, pat_patctl.jit); + } + } + +/* If valgrind is supported, mark the pbuffer as accessible again. The 16-bit +and 32-bit buffers can be marked completely undefined, but we must leave the +pattern in the 8-bit buffer defined because it may be read from a callout +during matching. */ + +#ifdef SUPPORT_VALGRIND +#ifdef SUPPORT_PCRE2_8 +if (test_mode == PCRE8_MODE) + { + VALGRIND_MAKE_MEM_UNDEFINED(pbuffer8 + valgrind_access_length, + pbuffer8_size - valgrind_access_length); + } +#endif +#ifdef SUPPORT_PCRE2_16 +if (test_mode == PCRE16_MODE) + { + VALGRIND_MAKE_MEM_UNDEFINED(pbuffer16, pbuffer16_size); + } +#endif +#ifdef SUPPORT_PCRE2_32 +if (test_mode == PCRE32_MODE) + { + VALGRIND_MAKE_MEM_UNDEFINED(pbuffer32, pbuffer32_size); + } +#endif +#endif + +/* Compilation failed; go back for another re, skipping to blank line +if non-interactive. */ + +if (TEST(compiled_code, ==, NULL)) + { + fprintf(outfile, "Failed: error %d at offset %d: ", errorcode, + (int)erroroffset); + if (!print_error_message(errorcode, "", "\n")) return PR_ABEND; + return PR_SKIP; + } + +/* If forbid_utf is non-zero, we are running a non-UTF test. UTF and UCP are +locked out at compile time, but we must also check for occurrences of \P, \p, +and \X, which are only supported when Unicode is supported. */ + +if (forbid_utf != 0) + { + if ((FLD(compiled_code, flags) & PCRE2_HASBKPORX) != 0) + { + fprintf(outfile, "** \\P, \\p, and \\X are not allowed after the " + "#forbid_utf command\n"); + return PR_SKIP; + } + } + +/* Remember the maximum lookbehind, for partial matching. */ + +if (pattern_info(PCRE2_INFO_MAXLOOKBEHIND, &maxlookbehind, FALSE) != 0) + return PR_ABEND; + +/* If an explicit newline modifier was given, set the information flag in the +pattern so that it is preserved over push/pop. */ + +if ((pat_patctl.control2 & CTL2_NL_SET) != 0) + { + SETFLD(compiled_code, flags, FLD(compiled_code, flags) | PCRE2_NL_SET); + } + +/* Output code size and other information if requested. */ + +if ((pat_patctl.control & CTL_MEMORY) != 0) show_memory_info(); +if ((pat_patctl.control & CTL_FRAMESIZE) != 0) show_framesize(); +if ((pat_patctl.control & CTL_ANYINFO) != 0) + { + int rc = show_pattern_info(); + if (rc != PR_OK) return rc; + } + +/* The "push" control requests that the compiled pattern be remembered on a +stack. This is mainly for testing the serialization functionality. */ + +if ((pat_patctl.control & CTL_PUSH) != 0) + { + if (patstacknext >= PATSTACKSIZE) + { + fprintf(outfile, "** Too many pushed patterns (max %d)\n", PATSTACKSIZE); + return PR_ABEND; + } + patstack[patstacknext++] = PTR(compiled_code); + SET(compiled_code, NULL); + } + +/* The "pushcopy" and "pushtablescopy" controls are similar, but push a +copy of the pattern, the latter with a copy of its character tables. This tests +the pcre2_code_copy() and pcre2_code_copy_with_tables() functions. */ + +if ((pat_patctl.control & (CTL_PUSHCOPY|CTL_PUSHTABLESCOPY)) != 0) + { + if (patstacknext >= PATSTACKSIZE) + { + fprintf(outfile, "** Too many pushed patterns (max %d)\n", PATSTACKSIZE); + return PR_ABEND; + } + if ((pat_patctl.control & CTL_PUSHCOPY) != 0) + { + PCRE2_CODE_COPY_TO_VOID(patstack[patstacknext++], compiled_code); + } + else + { + PCRE2_CODE_COPY_WITH_TABLES_TO_VOID(patstack[patstacknext++], + compiled_code); } + } + +return PR_OK; +} + + + +/************************************************* +* Check heap, match or depth limit * +*************************************************/ + +/* This is used for DFA, normal, and JIT fast matching. For DFA matching it +should only be called with the third argument set to PCRE2_ERROR_DEPTHLIMIT. + +Arguments: + pp the subject string + ulen length of subject or PCRE2_ZERO_TERMINATED + errnumber defines which limit to test + msg string to include in final message + +Returns: the return from the final match function call +*/ + +static int +check_match_limit(uint8_t *pp, PCRE2_SIZE ulen, int errnumber, const char *msg) +{ +int capcount; +uint32_t min = 0; +uint32_t mid = 64; +uint32_t max = UINT32_MAX; + +PCRE2_SET_MATCH_LIMIT(dat_context, max); +PCRE2_SET_DEPTH_LIMIT(dat_context, max); +PCRE2_SET_HEAP_LIMIT(dat_context, max); + +for (;;) + { + uint32_t stack_start = 0; + + if (errnumber == PCRE2_ERROR_HEAPLIMIT) + { + PCRE2_SET_HEAP_LIMIT(dat_context, mid); + } + else if (errnumber == PCRE2_ERROR_MATCHLIMIT) + { + PCRE2_SET_MATCH_LIMIT(dat_context, mid); + } + else + { + PCRE2_SET_DEPTH_LIMIT(dat_context, mid); + } + + if ((dat_datctl.control & CTL_DFA) != 0) + { + stack_start = DFA_START_RWS_SIZE/1024; + if (dfa_workspace == NULL) + dfa_workspace = (int *)malloc(DFA_WS_DIMENSION*sizeof(int)); + if (dfa_matched++ == 0) + dfa_workspace[0] = -1; /* To catch bad restart */ + PCRE2_DFA_MATCH(capcount, compiled_code, pp, ulen, dat_datctl.offset, + dat_datctl.options, match_data, + PTR(dat_context), dfa_workspace, DFA_WS_DIMENSION); + } + + else if ((pat_patctl.control & CTL_JITFAST) != 0) + PCRE2_JIT_MATCH(capcount, compiled_code, pp, ulen, dat_datctl.offset, + dat_datctl.options, match_data, PTR(dat_context)); + + else + { + stack_start = START_FRAMES_SIZE/1024; + PCRE2_MATCH(capcount, compiled_code, pp, ulen, dat_datctl.offset, + dat_datctl.options, match_data, PTR(dat_context)); + } + + if (capcount == errnumber) + { + if ((mid & 0x80000000u) != 0) + { + fprintf(outfile, "Can't find minimum %s limit: check pattern for " + "restriction\n", msg); + break; + } + + min = mid; + mid = (mid == max - 1)? max : (max != UINT32_MAX)? (min + max)/2 : mid*2; + } + else if (capcount >= 0 || + capcount == PCRE2_ERROR_NOMATCH || + capcount == PCRE2_ERROR_PARTIAL) + { + /* If we've not hit the error with a heap limit less than the size of the + initial stack frame vector (for pcre2_match()) or the initial stack + workspace vector (for pcre2_dfa_match()), the heap is not being used, so + the minimum limit is zero; there's no need to go on. The other limits are + always greater than zero. */ + + if (errnumber == PCRE2_ERROR_HEAPLIMIT && mid < stack_start) + { + fprintf(outfile, "Minimum %s limit = 0\n", msg); + break; + } + if (mid == min + 1) + { + fprintf(outfile, "Minimum %s limit = %d\n", msg, mid); + break; + } + max = mid; + mid = (min + max)/2; + } + else break; /* Some other error */ + } + +return capcount; +} + + + +/************************************************* +* Callout function * +*************************************************/ + +/* Called from a PCRE2 library as a result of the (?C) item. We print out where +we are in the match (unless suppressed). Yield zero unless more callouts than +the fail count, or the callout data is not zero. The only differences in the +callout block for different code unit widths are that the pointers to the +subject, the most recent MARK, and a callout argument string point to strings +of the appropriate width. Casts can be used to deal with this. + +Argument: a pointer to a callout block +Return: +*/ + +static int +callout_function(pcre2_callout_block_8 *cb, void *callout_data_ptr) +{ +FILE *f, *fdefault; +uint32_t i, pre_start, post_start, subject_length; +PCRE2_SIZE current_position; +BOOL utf = (FLD(compiled_code, overall_options) & PCRE2_UTF) != 0; +BOOL callout_capture = (dat_datctl.control & CTL_CALLOUT_CAPTURE) != 0; +BOOL callout_where = (dat_datctl.control2 & CTL2_CALLOUT_NO_WHERE) == 0; + +/* The FILE f is used for echoing the subject string if it is non-NULL. This +happens only once in simple cases, but we want to repeat after any additional +output caused by CALLOUT_EXTRA. */ + +fdefault = (!first_callout && !callout_capture && cb->callout_string == NULL)? + NULL : outfile; + +if ((dat_datctl.control2 & CTL2_CALLOUT_EXTRA) != 0) + { + f = outfile; + switch (cb->callout_flags) + { + case PCRE2_CALLOUT_BACKTRACK: + fprintf(f, "Backtrack\n"); + break; + + case PCRE2_CALLOUT_STARTMATCH|PCRE2_CALLOUT_BACKTRACK: + fprintf(f, "Backtrack\nNo other matching paths\n"); + /* Fall through */ + + case PCRE2_CALLOUT_STARTMATCH: + fprintf(f, "New match attempt\n"); + break; + + default: + f = fdefault; + break; + } + } +else f = fdefault; + +/* For a callout with a string argument, show the string first because there +isn't a tidy way to fit it in the rest of the data. */ + +if (cb->callout_string != NULL) + { + uint32_t delimiter = CODE_UNIT(cb->callout_string, -1); + fprintf(outfile, "Callout (%" SIZ_FORM "): %c", + SIZ_CAST cb->callout_string_offset, delimiter); + PCHARSV(cb->callout_string, 0, + cb->callout_string_length, utf, outfile); + for (i = 0; callout_start_delims[i] != 0; i++) + if (delimiter == callout_start_delims[i]) + { + delimiter = callout_end_delims[i]; + break; + } + fprintf(outfile, "%c", delimiter); + if (!callout_capture) fprintf(outfile, "\n"); + } + +/* Show captured strings if required */ + +if (callout_capture) + { + if (cb->callout_string == NULL) + fprintf(outfile, "Callout %d:", cb->callout_number); + fprintf(outfile, " last capture = %d\n", cb->capture_last); + for (i = 2; i < cb->capture_top * 2; i += 2) + { + fprintf(outfile, "%2d: ", i/2); + if (cb->offset_vector[i] == PCRE2_UNSET) + fprintf(outfile, ""); + else + { + PCHARSV(cb->subject, cb->offset_vector[i], + cb->offset_vector[i+1] - cb->offset_vector[i], utf, f); + } + fprintf(outfile, "\n"); + } + } + +/* Unless suppressed, re-print the subject in canonical form (with escapes for +non-printing characters), the first time, or if giving full details. On +subsequent calls in the same match, we use PCHARS() just to find the printed +lengths of the substrings. */ + +if (callout_where) + { + if (f != NULL) fprintf(f, "--->"); + + /* The subject before the match start. */ + + PCHARS(pre_start, cb->subject, 0, cb->start_match, utf, f); + + /* If a lookbehind is involved, the current position may be earlier than the + match start. If so, use the match start instead. */ + + current_position = (cb->current_position >= cb->start_match)? + cb->current_position : cb->start_match; + + /* The subject between the match start and the current position. */ + + PCHARS(post_start, cb->subject, cb->start_match, + current_position - cb->start_match, utf, f); + + /* Print from the current position to the end. */ + + PCHARSV(cb->subject, current_position, cb->subject_length - current_position, + utf, f); + + /* Calculate the total subject printed length (no print). */ + + PCHARS(subject_length, cb->subject, 0, cb->subject_length, utf, NULL); + + if (f != NULL) fprintf(f, "\n"); + + /* For automatic callouts, show the pattern offset. Otherwise, for a + numerical callout whose number has not already been shown with captured + strings, show the number here. A callout with a string argument has been + displayed above. */ + + if (cb->callout_number == 255) + { + fprintf(outfile, "%+3d ", (int)cb->pattern_position); + if (cb->pattern_position > 99) fprintf(outfile, "\n "); + } + else + { + if (callout_capture || cb->callout_string != NULL) fprintf(outfile, " "); + else fprintf(outfile, "%3d ", cb->callout_number); + } + + /* Now show position indicators */ + + for (i = 0; i < pre_start; i++) fprintf(outfile, " "); + fprintf(outfile, "^"); + + if (post_start > 0) + { + for (i = 0; i < post_start - 1; i++) fprintf(outfile, " "); + fprintf(outfile, "^"); + } + + for (i = 0; i < subject_length - pre_start - post_start + 4; i++) + fprintf(outfile, " "); + + if (cb->next_item_length != 0) + fprintf(outfile, "%.*s", (int)(cb->next_item_length), + pbuffer8 + cb->pattern_position); + else + fprintf(outfile, "End of pattern"); + + fprintf(outfile, "\n"); + } + +first_callout = FALSE; + +/* Show any mark info */ + +if (cb->mark != last_callout_mark) + { + if (cb->mark == NULL) + fprintf(outfile, "Latest Mark: \n"); + else + { + fprintf(outfile, "Latest Mark: "); + PCHARSV(cb->mark, 0, -1, utf, outfile); + putc('\n', outfile); + } + last_callout_mark = cb->mark; + } + +/* Show callout data */ + +if (callout_data_ptr != NULL) + { + int callout_data = *((int32_t *)callout_data_ptr); + if (callout_data != 0) + { + fprintf(outfile, "Callout data = %d\n", callout_data); + return callout_data; + } + } + +/* Keep count and give the appropriate return code */ + +callout_count++; + +if (cb->callout_number == dat_datctl.cerror[0] && + callout_count >= dat_datctl.cerror[1]) + return PCRE2_ERROR_CALLOUT; + +if (cb->callout_number == dat_datctl.cfail[0] && + callout_count >= dat_datctl.cfail[1]) + return 1; + +return 0; +} + + + +/************************************************* +* Handle *MARK and copy/get tests * +*************************************************/ + +/* This function is called after complete and partial matches. It runs the +tests for substring extraction. + +Arguments: + utf TRUE for utf + capcount return from pcre2_match() + +Returns: FALSE if print_error_message() fails +*/ + +static BOOL +copy_and_get(BOOL utf, int capcount) +{ +int i; +uint8_t *nptr; + +/* Test copy strings by number */ + +for (i = 0; i < MAXCPYGET && dat_datctl.copy_numbers[i] >= 0; i++) + { + int rc; + PCRE2_SIZE length, length2; + uint32_t copybuffer[256]; + uint32_t n = (uint32_t)(dat_datctl.copy_numbers[i]); + length = sizeof(copybuffer)/code_unit_size; + PCRE2_SUBSTRING_COPY_BYNUMBER(rc, match_data, n, copybuffer, &length); + if (rc < 0) + { + fprintf(outfile, "Copy substring %d failed (%d): ", n, rc); + if (!print_error_message(rc, "", "\n")) return FALSE; + } + else + { + PCRE2_SUBSTRING_LENGTH_BYNUMBER(rc, match_data, n, &length2); + if (rc < 0) + { + fprintf(outfile, "Get substring %d length failed (%d): ", n, rc); + if (!print_error_message(rc, "", "\n")) return FALSE; + } + else if (length2 != length) + { + fprintf(outfile, "Mismatched substring lengths: %" + SIZ_FORM " %" SIZ_FORM "\n", SIZ_CAST length, SIZ_CAST length2); + } + fprintf(outfile, "%2dC ", n); + PCHARSV(copybuffer, 0, length, utf, outfile); + fprintf(outfile, " (%" SIZ_FORM ")\n", SIZ_CAST length); + } + } + +/* Test copy strings by name */ + +nptr = dat_datctl.copy_names; +for (;;) + { + int rc; + int groupnumber; + PCRE2_SIZE length, length2; + uint32_t copybuffer[256]; + int namelen = strlen((const char *)nptr); +#if defined SUPPORT_PCRE2_16 || defined SUPPORT_PCRE2_32 + PCRE2_SIZE cnl = namelen; +#endif + if (namelen == 0) break; + +#ifdef SUPPORT_PCRE2_8 + if (test_mode == PCRE8_MODE) strcpy((char *)pbuffer8, (char *)nptr); +#endif +#ifdef SUPPORT_PCRE2_16 + if (test_mode == PCRE16_MODE)(void)to16(nptr, utf, &cnl); +#endif +#ifdef SUPPORT_PCRE2_32 + if (test_mode == PCRE32_MODE)(void)to32(nptr, utf, &cnl); +#endif + + PCRE2_SUBSTRING_NUMBER_FROM_NAME(groupnumber, compiled_code, pbuffer); + if (groupnumber < 0 && groupnumber != PCRE2_ERROR_NOUNIQUESUBSTRING) + fprintf(outfile, "Number not found for group '%s'\n", nptr); + + length = sizeof(copybuffer)/code_unit_size; + PCRE2_SUBSTRING_COPY_BYNAME(rc, match_data, pbuffer, copybuffer, &length); + if (rc < 0) + { + fprintf(outfile, "Copy substring '%s' failed (%d): ", nptr, rc); + if (!print_error_message(rc, "", "\n")) return FALSE; + } + else + { + PCRE2_SUBSTRING_LENGTH_BYNAME(rc, match_data, pbuffer, &length2); + if (rc < 0) + { + fprintf(outfile, "Get substring '%s' length failed (%d): ", nptr, rc); + if (!print_error_message(rc, "", "\n")) return FALSE; + } + else if (length2 != length) + { + fprintf(outfile, "Mismatched substring lengths: %" + SIZ_FORM " %" SIZ_FORM "\n", SIZ_CAST length, SIZ_CAST length2); + } + fprintf(outfile, " C "); + PCHARSV(copybuffer, 0, length, utf, outfile); + fprintf(outfile, " (%" SIZ_FORM ") %s", SIZ_CAST length, nptr); + if (groupnumber >= 0) fprintf(outfile, " (group %d)\n", groupnumber); + else fprintf(outfile, " (non-unique)\n"); + } + nptr += namelen + 1; + } + +/* Test get strings by number */ + +for (i = 0; i < MAXCPYGET && dat_datctl.get_numbers[i] >= 0; i++) + { + int rc; + PCRE2_SIZE length; + void *gotbuffer; + uint32_t n = (uint32_t)(dat_datctl.get_numbers[i]); + PCRE2_SUBSTRING_GET_BYNUMBER(rc, match_data, n, &gotbuffer, &length); + if (rc < 0) + { + fprintf(outfile, "Get substring %d failed (%d): ", n, rc); + if (!print_error_message(rc, "", "\n")) return FALSE; + } + else + { + fprintf(outfile, "%2dG ", n); + PCHARSV(gotbuffer, 0, length, utf, outfile); + fprintf(outfile, " (%" SIZ_FORM ")\n", SIZ_CAST length); + PCRE2_SUBSTRING_FREE(gotbuffer); + } + } + +/* Test get strings by name */ + +nptr = dat_datctl.get_names; +for (;;) + { + PCRE2_SIZE length; + void *gotbuffer; + int rc; + int groupnumber; + int namelen = strlen((const char *)nptr); +#if defined SUPPORT_PCRE2_16 || defined SUPPORT_PCRE2_32 + PCRE2_SIZE cnl = namelen; +#endif + if (namelen == 0) break; + +#ifdef SUPPORT_PCRE2_8 + if (test_mode == PCRE8_MODE) strcpy((char *)pbuffer8, (char *)nptr); +#endif +#ifdef SUPPORT_PCRE2_16 + if (test_mode == PCRE16_MODE)(void)to16(nptr, utf, &cnl); +#endif +#ifdef SUPPORT_PCRE2_32 + if (test_mode == PCRE32_MODE)(void)to32(nptr, utf, &cnl); +#endif + + PCRE2_SUBSTRING_NUMBER_FROM_NAME(groupnumber, compiled_code, pbuffer); + if (groupnumber < 0 && groupnumber != PCRE2_ERROR_NOUNIQUESUBSTRING) + fprintf(outfile, "Number not found for group '%s'\n", nptr); + + PCRE2_SUBSTRING_GET_BYNAME(rc, match_data, pbuffer, &gotbuffer, &length); + if (rc < 0) + { + fprintf(outfile, "Get substring '%s' failed (%d): ", nptr, rc); + if (!print_error_message(rc, "", "\n")) return FALSE; + } + else + { + fprintf(outfile, " G "); + PCHARSV(gotbuffer, 0, length, utf, outfile); + fprintf(outfile, " (%" SIZ_FORM ") %s", SIZ_CAST length, nptr); + if (groupnumber >= 0) fprintf(outfile, " (group %d)\n", groupnumber); + else fprintf(outfile, " (non-unique)\n"); + PCRE2_SUBSTRING_FREE(gotbuffer); + } + nptr += namelen + 1; + } + +/* Test getting the complete list of captured strings. */ + +if ((dat_datctl.control & CTL_GETALL) != 0) + { + int rc; + void **stringlist; + PCRE2_SIZE *lengths; + PCRE2_SUBSTRING_LIST_GET(rc, match_data, &stringlist, &lengths); + if (rc < 0) + { + fprintf(outfile, "get substring list failed (%d): ", rc); + if (!print_error_message(rc, "", "\n")) return FALSE; + } + else + { + for (i = 0; i < capcount; i++) + { + fprintf(outfile, "%2dL ", i); + PCHARSV(stringlist[i], 0, lengths[i], utf, outfile); + putc('\n', outfile); + } + if (stringlist[i] != NULL) + fprintf(outfile, "string list not terminated by NULL\n"); + PCRE2_SUBSTRING_LIST_FREE(stringlist); + } + } + +return TRUE; +} + + + +/************************************************* +* Process a data line * +*************************************************/ + +/* The line is in buffer; it will not be empty. + +Arguments: none + +Returns: PR_OK continue processing next line + PR_SKIP skip to a blank line + PR_ABEND abort the pcre2test run +*/ + +static int +process_data(void) +{ +PCRE2_SIZE len, ulen, arg_ulen; +uint32_t gmatched; +uint32_t c, k; +uint32_t g_notempty = 0; +uint8_t *p, *pp, *start_rep; +size_t needlen; +void *use_dat_context; +BOOL utf; +BOOL subject_literal; +PCRE2_SIZE ovecsave[3]; + +#ifdef SUPPORT_PCRE2_8 +uint8_t *q8 = NULL; +#endif +#ifdef SUPPORT_PCRE2_16 +uint16_t *q16 = NULL; +#endif +#ifdef SUPPORT_PCRE2_32 +uint32_t *q32 = NULL; +#endif + +subject_literal = (pat_patctl.control2 & CTL2_SUBJECT_LITERAL) != 0; + +/* Copy the default context and data control blocks to the active ones. Then +copy from the pattern the controls that can be set in either the pattern or the +data. This allows them to be overridden in the data line. We do not do this for +options because those that are common apply separately to compiling and +matching. */ + +DATCTXCPY(dat_context, default_dat_context); +memcpy(&dat_datctl, &def_datctl, sizeof(datctl)); +dat_datctl.control |= (pat_patctl.control & CTL_ALLPD); +dat_datctl.control2 |= (pat_patctl.control2 & CTL2_ALLPD); +strcpy((char *)dat_datctl.replacement, (char *)pat_patctl.replacement); +if (dat_datctl.jitstack == 0) dat_datctl.jitstack = pat_patctl.jitstack; + +/* Initialize for scanning the data line. */ + +#ifdef SUPPORT_PCRE2_8 +utf = ((((pat_patctl.control & CTL_POSIX) != 0)? + ((pcre2_real_code_8 *)preg.re_pcre2_code)->overall_options : + FLD(compiled_code, overall_options)) & PCRE2_UTF) != 0; +#else +utf = (FLD(compiled_code, overall_options) & PCRE2_UTF) != 0; +#endif + +start_rep = NULL; +len = strlen((const char *)buffer); +while (len > 0 && isspace(buffer[len-1])) len--; +buffer[len] = 0; +p = buffer; +while (isspace(*p)) p++; + +/* Check that the data is well-formed UTF-8 if we're in UTF mode. To create +invalid input to pcre2_match(), you must use \x?? or \x{} sequences. */ + +if (utf) + { + uint8_t *q; + uint32_t cc; + int n = 1; + for (q = p; n > 0 && *q; q += n) n = utf82ord(q, &cc); + if (n <= 0) + { + fprintf(outfile, "** Failed: invalid UTF-8 string cannot be used as input " + "in UTF mode\n"); + return PR_OK; + } + } + +#ifdef SUPPORT_VALGRIND +/* Mark the dbuffer as addressable but undefined again. */ +if (dbuffer != NULL) + { + VALGRIND_MAKE_MEM_UNDEFINED(dbuffer, dbuffer_size); + } +#endif + +/* Allocate a buffer to hold the data line; len+1 is an upper bound on +the number of code units that will be needed (though the buffer may have to be +extended if replication is involved). */ + +needlen = (size_t)((len+1) * code_unit_size); +if (dbuffer == NULL || needlen >= dbuffer_size) + { + while (needlen >= dbuffer_size) dbuffer_size *= 2; + dbuffer = (uint8_t *)realloc(dbuffer, dbuffer_size); + if (dbuffer == NULL) + { + fprintf(stderr, "pcre2test: realloc(%d) failed\n", (int)dbuffer_size); + exit(1); + } + } +SETCASTPTR(q, dbuffer); /* Sets q8, q16, or q32, as appropriate. */ + +/* Scan the data line, interpreting data escapes, and put the result into a +buffer of the appropriate width. In UTF mode, input is always UTF-8; otherwise, +in 16- and 32-bit modes, it can be forced to UTF-8 by the utf8_input modifier. +*/ + +while ((c = *p++) != 0) + { + int32_t i = 0; + size_t replen; + + /* ] may mark the end of a replicated sequence */ + + if (c == ']' && start_rep != NULL) + { + long li; + char *endptr; + size_t qoffset = CAST8VAR(q) - dbuffer; + size_t rep_offset = start_rep - dbuffer; + + if (*p++ != '{') + { + fprintf(outfile, "** Expected '{' after \\[....]\n"); + return PR_OK; + } + + li = strtol((const char *)p, &endptr, 10); + if (S32OVERFLOW(li)) + { + fprintf(outfile, "** Repeat count too large\n"); + return PR_OK; + } + + p = (uint8_t *)endptr; + if (*p++ != '}') + { + fprintf(outfile, "** Expected '}' after \\[...]{...\n"); + return PR_OK; + } + + i = (int32_t)li; + if (i-- == 0) + { + fprintf(outfile, "** Zero repeat not allowed\n"); + return PR_OK; + } + + replen = CAST8VAR(q) - start_rep; + needlen += replen * i; + + if (needlen >= dbuffer_size) + { + while (needlen >= dbuffer_size) dbuffer_size *= 2; + dbuffer = (uint8_t *)realloc(dbuffer, dbuffer_size); + if (dbuffer == NULL) + { + fprintf(stderr, "pcre2test: realloc(%d) failed\n", (int)dbuffer_size); + exit(1); + } + SETCASTPTR(q, dbuffer + qoffset); + start_rep = dbuffer + rep_offset; + } + + while (i-- > 0) + { + memcpy(CAST8VAR(q), start_rep, replen); + SETPLUS(q, replen/code_unit_size); + } + + start_rep = NULL; + continue; + } + + /* Handle a non-escaped character. In non-UTF 32-bit mode with utf8_input + set, do the fudge for setting the top bit. */ + + if (c != '\\' || subject_literal) + { + uint32_t topbit = 0; + if (test_mode == PCRE32_MODE && c == 0xff && *p != 0) + { + topbit = 0x80000000; + c = *p++; + } + if ((utf || (pat_patctl.control & CTL_UTF8_INPUT) != 0) && + HASUTF8EXTRALEN(c)) { GETUTF8INC(c, p); } + c |= topbit; + } + + /* Handle backslash escapes */ + + else switch ((c = *p++)) + { + case '\\': break; + case 'a': c = CHAR_BEL; break; + case 'b': c = '\b'; break; + case 'e': c = CHAR_ESC; break; + case 'f': c = '\f'; break; + case 'n': c = '\n'; break; + case 'r': c = '\r'; break; + case 't': c = '\t'; break; + case 'v': c = '\v'; break; + + case '0': case '1': case '2': case '3': + case '4': case '5': case '6': case '7': + c -= '0'; + while (i++ < 2 && isdigit(*p) && *p != '8' && *p != '9') + c = c * 8 + *p++ - '0'; + break; + + case 'o': + if (*p == '{') + { + uint8_t *pt = p; + c = 0; + for (pt++; isdigit(*pt) && *pt != '8' && *pt != '9'; pt++) + { + if (++i == 12) + fprintf(outfile, "** Too many octal digits in \\o{...} item; " + "using only the first twelve.\n"); + else c = c * 8 + *pt - '0'; + } + if (*pt == '}') p = pt + 1; + else fprintf(outfile, "** Missing } after \\o{ (assumed)\n"); + } + break; + + case 'x': + if (*p == '{') + { + uint8_t *pt = p; + c = 0; + + /* We used to have "while (isxdigit(*(++pt)))" here, but it fails + when isxdigit() is a macro that refers to its argument more than + once. This is banned by the C Standard, but apparently happens in at + least one MacOS environment. */ + + for (pt++; isxdigit(*pt); pt++) + { + if (++i == 9) + fprintf(outfile, "** Too many hex digits in \\x{...} item; " + "using only the first eight.\n"); + else c = c * 16 + tolower(*pt) - ((isdigit(*pt))? '0' : 'a' - 10); + } + if (*pt == '}') + { + p = pt + 1; + break; + } + /* Not correct form for \x{...}; fall through */ + } + + /* \x without {} always defines just one byte in 8-bit mode. This + allows UTF-8 characters to be constructed byte by byte, and also allows + invalid UTF-8 sequences to be made. Just copy the byte in UTF-8 mode. + Otherwise, pass it down as data. */ + + c = 0; + while (i++ < 2 && isxdigit(*p)) + { + c = c * 16 + tolower(*p) - ((isdigit(*p))? '0' : 'a' - 10); + p++; + } +#if defined SUPPORT_PCRE2_8 + if (utf && (test_mode == PCRE8_MODE)) + { + *q8++ = c; + continue; + } +#endif + break; + + case 0: /* \ followed by EOF allows for an empty line */ + p--; + continue; + + case '=': /* \= terminates the data, starts modifiers */ + goto ENDSTRING; + + case '[': /* \[ introduces a replicated character sequence */ + if (start_rep != NULL) + { + fprintf(outfile, "** Nested replication is not supported\n"); + return PR_OK; + } + start_rep = CAST8VAR(q); + continue; + + default: + if (isalnum(c)) + { + fprintf(outfile, "** Unrecognized escape sequence \"\\%c\"\n", c); + return PR_OK; + } + } + + /* We now have a character value in c that may be greater than 255. + In 8-bit mode we convert to UTF-8 if we are in UTF mode. Values greater + than 127 in UTF mode must have come from \x{...} or octal constructs + because values from \x.. get this far only in non-UTF mode. */ + +#ifdef SUPPORT_PCRE2_8 + if (test_mode == PCRE8_MODE) + { + if (utf) + { + if (c > 0x7fffffff) + { + fprintf(outfile, "** Character \\x{%x} is greater than 0x7fffffff " + "and so cannot be converted to UTF-8\n", c); + return PR_OK; + } + q8 += ord2utf8(c, q8); + } + else + { + if (c > 0xffu) + { + fprintf(outfile, "** Character \\x{%x} is greater than 255 " + "and UTF-8 mode is not enabled.\n", c); + fprintf(outfile, "** Truncation will probably give the wrong " + "result.\n"); + } + *q8++ = c; + } + } +#endif +#ifdef SUPPORT_PCRE2_16 + if (test_mode == PCRE16_MODE) + { + if (utf) + { + if (c > 0x10ffffu) + { + fprintf(outfile, "** Failed: character \\x{%x} is greater than " + "0x10ffff and so cannot be converted to UTF-16\n", c); + return PR_OK; + } + else if (c >= 0x10000u) + { + c-= 0x10000u; + *q16++ = 0xD800 | (c >> 10); + *q16++ = 0xDC00 | (c & 0x3ff); + } + else + *q16++ = c; + } + else + { + if (c > 0xffffu) + { + fprintf(outfile, "** Character \\x{%x} is greater than 0xffff " + "and UTF-16 mode is not enabled.\n", c); + fprintf(outfile, "** Truncation will probably give the wrong " + "result.\n"); + } + + *q16++ = c; + } + } +#endif +#ifdef SUPPORT_PCRE2_32 + if (test_mode == PCRE32_MODE) + { + *q32++ = c; + } +#endif + } + +ENDSTRING: +SET(*q, 0); +len = CASTVAR(uint8_t *, q) - dbuffer; /* Length in bytes */ +ulen = len/code_unit_size; /* Length in code units */ +arg_ulen = ulen; /* Value to use in match arg */ + +/* If the string was terminated by \= we must now interpret modifiers. */ + +if (p[-1] != 0 && !decode_modifiers(p, CTX_DAT, NULL, &dat_datctl)) + return PR_OK; + +/* Check for mutually exclusive modifiers. At present, these are all in the +first control word. */ + +for (k = 0; k < sizeof(exclusive_dat_controls)/sizeof(uint32_t); k++) + { + c = dat_datctl.control & exclusive_dat_controls[k]; + if (c != 0 && c != (c & (~c+1))) + { + show_controls(c, 0, "** Not allowed together:"); + fprintf(outfile, "\n"); + return PR_OK; + } + } + +if (pat_patctl.replacement[0] != 0 && + (dat_datctl.control & CTL_NULLCONTEXT) != 0) + { + fprintf(outfile, "** Replacement text is not supported with null_context.\n"); + return PR_OK; + } + +/* We now have the subject in dbuffer, with len containing the byte length, and +ulen containing the code unit length, with a copy in arg_ulen for use in match +function arguments (this gets changed to PCRE2_ZERO_TERMINATED when the +zero_terminate modifier is present). + +Move the data to the end of the buffer so that a read over the end can be +caught by valgrind or other means. If we have explicit valgrind support, mark +the unused start of the buffer unaddressable. If we are using the POSIX +interface, or testing zero-termination, we must include the terminating zero in +the usable data. */ + +c = code_unit_size * (((pat_patctl.control & CTL_POSIX) + + (dat_datctl.control & CTL_ZERO_TERMINATE) != 0)? 1:0); +pp = memmove(dbuffer + dbuffer_size - len - c, dbuffer, len + c); +#ifdef SUPPORT_VALGRIND + VALGRIND_MAKE_MEM_NOACCESS(dbuffer, dbuffer_size - (len + c)); +#endif + +/* Now pp points to the subject string. POSIX matching is only possible in +8-bit mode, and it does not support timing or other fancy features. Some were +checked at compile time, but we need to check the match-time settings here. */ + +#ifdef SUPPORT_PCRE2_8 +if ((pat_patctl.control & CTL_POSIX) != 0) + { + int rc; + int eflags = 0; + regmatch_t *pmatch = NULL; + const char *msg = "** Ignored with POSIX interface:"; + + if (dat_datctl.cerror[0] != CFORE_UNSET || dat_datctl.cerror[1] != CFORE_UNSET) + prmsg(&msg, "callout_error"); + if (dat_datctl.cfail[0] != CFORE_UNSET || dat_datctl.cfail[1] != CFORE_UNSET) + prmsg(&msg, "callout_fail"); + if (dat_datctl.copy_numbers[0] >= 0 || dat_datctl.copy_names[0] != 0) + prmsg(&msg, "copy"); + if (dat_datctl.get_numbers[0] >= 0 || dat_datctl.get_names[0] != 0) + prmsg(&msg, "get"); + if (dat_datctl.jitstack != 0) prmsg(&msg, "jitstack"); + if (dat_datctl.offset != 0) prmsg(&msg, "offset"); + + if ((dat_datctl.options & ~POSIX_SUPPORTED_MATCH_OPTIONS) != 0) + { + fprintf(outfile, "%s", msg); + show_match_options(dat_datctl.options & ~POSIX_SUPPORTED_MATCH_OPTIONS); + msg = ""; + } + if ((dat_datctl.control & ~POSIX_SUPPORTED_MATCH_CONTROLS) != 0 || + (dat_datctl.control2 & ~POSIX_SUPPORTED_MATCH_CONTROLS2) != 0) + { + show_controls(dat_datctl.control & ~POSIX_SUPPORTED_MATCH_CONTROLS, + dat_datctl.control2 & ~POSIX_SUPPORTED_MATCH_CONTROLS2, msg); + msg = ""; + } + + if (msg[0] == 0) fprintf(outfile, "\n"); + + if (dat_datctl.oveccount > 0) + { + pmatch = (regmatch_t *)malloc(sizeof(regmatch_t) * dat_datctl.oveccount); + if (pmatch == NULL) + { + fprintf(outfile, "** Failed to get memory for recording matching " + "information (size set = %du)\n", dat_datctl.oveccount); + return PR_OK; + } + } + + if (dat_datctl.startend[0] != CFORE_UNSET) + { + pmatch[0].rm_so = dat_datctl.startend[0]; + pmatch[0].rm_eo = (dat_datctl.startend[1] != 0)? + dat_datctl.startend[1] : len; + eflags |= REG_STARTEND; + } + + if ((dat_datctl.options & PCRE2_NOTBOL) != 0) eflags |= REG_NOTBOL; + if ((dat_datctl.options & PCRE2_NOTEOL) != 0) eflags |= REG_NOTEOL; + if ((dat_datctl.options & PCRE2_NOTEMPTY) != 0) eflags |= REG_NOTEMPTY; + + rc = regexec(&preg, (const char *)pp, dat_datctl.oveccount, pmatch, eflags); + if (rc != 0) + { + (void)regerror(rc, &preg, (char *)pbuffer8, pbuffer8_size); + fprintf(outfile, "No match: POSIX code %d: %s\n", rc, pbuffer8); + } + else if ((pat_patctl.control & CTL_POSIX_NOSUB) != 0) + fprintf(outfile, "Matched with REG_NOSUB\n"); + else if (dat_datctl.oveccount == 0) + fprintf(outfile, "Matched without capture\n"); + else + { + size_t i, j; + size_t last_printed = (size_t)dat_datctl.oveccount; + for (i = 0; i < (size_t)dat_datctl.oveccount; i++) + { + if (pmatch[i].rm_so >= 0) + { + PCRE2_SIZE start = pmatch[i].rm_so; + PCRE2_SIZE end = pmatch[i].rm_eo; + for (j = last_printed + 1; j < i; j++) + fprintf(outfile, "%2d: \n", (int)j); + last_printed = i; + if (start > end) + { + start = pmatch[i].rm_eo; + end = pmatch[i].rm_so; + fprintf(outfile, "Start of matched string is beyond its end - " + "displaying from end to start.\n"); + } + fprintf(outfile, "%2d: ", (int)i); + PCHARSV(pp, start, end - start, utf, outfile); + fprintf(outfile, "\n"); + + if ((i == 0 && (dat_datctl.control & CTL_AFTERTEXT) != 0) || + (dat_datctl.control & CTL_ALLAFTERTEXT) != 0) + { + fprintf(outfile, "%2d+ ", (int)i); + /* Note: don't use the start/end variables here because we want to + show the text from what is reported as the end. */ + PCHARSV(pp, pmatch[i].rm_eo, len - pmatch[i].rm_eo, utf, outfile); + fprintf(outfile, "\n"); } + } + } + } + free(pmatch); + return PR_OK; + } +#endif /* SUPPORT_PCRE2_8 */ + + /* Handle matching via the native interface. Check for consistency of +modifiers. */ + +if (dat_datctl.startend[0] != CFORE_UNSET) + fprintf(outfile, "** \\=posix_startend ignored for non-POSIX matching\n"); + +/* ALLUSEDTEXT is not supported with JIT, but JIT is not used with DFA +matching, even if the JIT compiler was used. */ + +if ((dat_datctl.control & (CTL_ALLUSEDTEXT|CTL_DFA)) == CTL_ALLUSEDTEXT && + FLD(compiled_code, executable_jit) != NULL) + { + fprintf(outfile, "** Showing all consulted text is not supported by JIT: ignored\n"); + dat_datctl.control &= ~CTL_ALLUSEDTEXT; + } + +/* Handle passing the subject as zero-terminated. */ + +if ((dat_datctl.control & CTL_ZERO_TERMINATE) != 0) + arg_ulen = PCRE2_ZERO_TERMINATED; + +/* The nullcontext modifier is used to test calling pcre2_[jit_]match() with a +NULL context. */ + +use_dat_context = ((dat_datctl.control & CTL_NULLCONTEXT) != 0)? + NULL : PTR(dat_context); + +/* Enable display of malloc/free if wanted. We can do this only if either the +pattern or the subject is processed with a context. */ + +show_memory = (dat_datctl.control & CTL_MEMORY) != 0; + +if (show_memory && + (pat_patctl.control & dat_datctl.control & CTL_NULLCONTEXT) != 0) + fprintf(outfile, "** \\=memory requires either a pattern or a subject " + "context: ignored\n"); + +/* Create and assign a JIT stack if requested. */ + +if (dat_datctl.jitstack != 0) + { + if (dat_datctl.jitstack != jit_stack_size) + { + PCRE2_JIT_STACK_FREE(jit_stack); + PCRE2_JIT_STACK_CREATE(jit_stack, 1, dat_datctl.jitstack * 1024, NULL); + jit_stack_size = dat_datctl.jitstack; + } + PCRE2_JIT_STACK_ASSIGN(dat_context, jit_callback, jit_stack); + } + +/* Or de-assign */ + +else if (jit_stack != NULL) + { + PCRE2_JIT_STACK_ASSIGN(dat_context, NULL, NULL); + PCRE2_JIT_STACK_FREE(jit_stack); + jit_stack = NULL; + jit_stack_size = 0; + } + +/* When no JIT stack is assigned, we must ensure that there is a JIT callback +if we want to verify that JIT was actually used. */ + +if ((pat_patctl.control & CTL_JITVERIFY) != 0 && jit_stack == NULL) + { + PCRE2_JIT_STACK_ASSIGN(dat_context, jit_callback, NULL); + } + +/* Adjust match_data according to size of offsets required. A size of zero +causes a new match data block to be obtained that exactly fits the pattern. */ + +if (dat_datctl.oveccount == 0) + { + PCRE2_MATCH_DATA_FREE(match_data); + PCRE2_MATCH_DATA_CREATE_FROM_PATTERN(match_data, compiled_code, NULL); + PCRE2_GET_OVECTOR_COUNT(max_oveccount, match_data); + } +else if (dat_datctl.oveccount <= max_oveccount) + { + SETFLD(match_data, oveccount, dat_datctl.oveccount); + } +else + { + max_oveccount = dat_datctl.oveccount; + PCRE2_MATCH_DATA_FREE(match_data); + PCRE2_MATCH_DATA_CREATE(match_data, max_oveccount, NULL); + } + +if (CASTVAR(void *, match_data) == NULL) + { + fprintf(outfile, "** Failed to get memory for recording matching " + "information (size requested: %d)\n", dat_datctl.oveccount); + max_oveccount = 0; + return PR_OK; + } + +/* Replacement processing is ignored for DFA matching. */ + +if (dat_datctl.replacement[0] != 0 && (dat_datctl.control & CTL_DFA) != 0) + { + fprintf(outfile, "** Ignored for DFA matching: replace\n"); + dat_datctl.replacement[0] = 0; + } + +/* If a replacement string is provided, call pcre2_substitute() instead of one +of the matching functions. First we have to convert the replacement string to +the appropriate width. */ + +if (dat_datctl.replacement[0] != 0) + { + int rc; + uint8_t *pr; + uint8_t rbuffer[REPLACE_BUFFSIZE]; + uint8_t nbuffer[REPLACE_BUFFSIZE]; + uint32_t xoptions; + PCRE2_SIZE rlen, nsize, erroroffset; + BOOL badutf = FALSE; + +#ifdef SUPPORT_PCRE2_8 + uint8_t *r8 = NULL; +#endif +#ifdef SUPPORT_PCRE2_16 + uint16_t *r16 = NULL; +#endif +#ifdef SUPPORT_PCRE2_32 + uint32_t *r32 = NULL; +#endif + + if (timeitm) + fprintf(outfile, "** Timing is not supported with replace: ignored\n"); + + if ((dat_datctl.control & CTL_ALTGLOBAL) != 0) + fprintf(outfile, "** Altglobal is not supported with replace: ignored\n"); + + xoptions = (((dat_datctl.control & CTL_GLOBAL) == 0)? 0 : + PCRE2_SUBSTITUTE_GLOBAL) | + (((dat_datctl.control2 & CTL2_SUBSTITUTE_EXTENDED) == 0)? 0 : + PCRE2_SUBSTITUTE_EXTENDED) | + (((dat_datctl.control2 & CTL2_SUBSTITUTE_OVERFLOW_LENGTH) == 0)? 0 : + PCRE2_SUBSTITUTE_OVERFLOW_LENGTH) | + (((dat_datctl.control2 & CTL2_SUBSTITUTE_UNKNOWN_UNSET) == 0)? 0 : + PCRE2_SUBSTITUTE_UNKNOWN_UNSET) | + (((dat_datctl.control2 & CTL2_SUBSTITUTE_UNSET_EMPTY) == 0)? 0 : + PCRE2_SUBSTITUTE_UNSET_EMPTY); + + SETCASTPTR(r, rbuffer); /* Sets r8, r16, or r32, as appropriate. */ + pr = dat_datctl.replacement; + + /* If the replacement starts with '[]' we interpret that as length + value for the replacement buffer. */ + + nsize = REPLACE_BUFFSIZE/code_unit_size; + if (*pr == '[') + { + PCRE2_SIZE n = 0; + while ((c = *(++pr)) >= CHAR_0 && c <= CHAR_9) n = n * 10 + c - CHAR_0; + if (*pr++ != ']') + { + fprintf(outfile, "Bad buffer size in replacement string\n"); + return PR_OK; + } + if (n > nsize) + { + fprintf(outfile, "Replacement buffer setting (%" SIZ_FORM ") is too " + "large (max %" SIZ_FORM ")\n", SIZ_CAST n, SIZ_CAST nsize); + return PR_OK; + } + nsize = n; + } + + /* Now copy the replacement string to a buffer of the appropriate width. No + escape processing is done for replacements. In UTF mode, check for an invalid + UTF-8 input string, and if it is invalid, just copy its code units without + UTF interpretation. This provides a means of checking that an invalid string + is detected. Otherwise, UTF-8 can be used to include wide characters in a + replacement. */ + + if (utf) badutf = valid_utf(pr, strlen((const char *)pr), &erroroffset); + + /* Not UTF or invalid UTF-8: just copy the code units. */ + + if (!utf || badutf) + { + while ((c = *pr++) != 0) + { +#ifdef SUPPORT_PCRE2_8 + if (test_mode == PCRE8_MODE) *r8++ = c; +#endif +#ifdef SUPPORT_PCRE2_16 + if (test_mode == PCRE16_MODE) *r16++ = c; +#endif +#ifdef SUPPORT_PCRE2_32 + if (test_mode == PCRE32_MODE) *r32++ = c; +#endif + } + } + + /* Valid UTF-8 replacement string */ + + else while ((c = *pr++) != 0) + { + if (HASUTF8EXTRALEN(c)) { GETUTF8INC(c, pr); } + +#ifdef SUPPORT_PCRE2_8 + if (test_mode == PCRE8_MODE) r8 += ord2utf8(c, r8); +#endif + +#ifdef SUPPORT_PCRE2_16 + if (test_mode == PCRE16_MODE) + { + if (c >= 0x10000u) + { + c-= 0x10000u; + *r16++ = 0xD800 | (c >> 10); + *r16++ = 0xDC00 | (c & 0x3ff); + } + else *r16++ = c; + } +#endif + +#ifdef SUPPORT_PCRE2_32 + if (test_mode == PCRE32_MODE) *r32++ = c; +#endif + } + + SET(*r, 0); + if ((dat_datctl.control & CTL_ZERO_TERMINATE) != 0) + rlen = PCRE2_ZERO_TERMINATED; + else + rlen = (CASTVAR(uint8_t *, r) - rbuffer)/code_unit_size; + PCRE2_SUBSTITUTE(rc, compiled_code, pp, arg_ulen, dat_datctl.offset, + dat_datctl.options|xoptions, match_data, dat_context, + rbuffer, rlen, nbuffer, &nsize); + + if (rc < 0) + { + fprintf(outfile, "Failed: error %d", rc); + if (rc != PCRE2_ERROR_NOMEMORY && nsize != PCRE2_UNSET) + fprintf(outfile, " at offset %ld in replacement", (long int)nsize); + fprintf(outfile, ": "); + if (!print_error_message(rc, "", "")) return PR_ABEND; + if (rc == PCRE2_ERROR_NOMEMORY && + (xoptions & PCRE2_SUBSTITUTE_OVERFLOW_LENGTH) != 0) + fprintf(outfile, ": %ld code units are needed", (long int)nsize); + } + else + { + fprintf(outfile, "%2d: ", rc); + PCHARSV(nbuffer, 0, nsize, utf, outfile); + } + + fprintf(outfile, "\n"); + show_memory = FALSE; + return PR_OK; + } /* End of substitution handling */ + +/* When a replacement string is not provided, run a loop for global matching +with one of the basic matching functions. For altglobal (or first time round +the loop), set an "unset" value for the previous match info. */ + +ovecsave[0] = ovecsave[1] = ovecsave[2] = PCRE2_UNSET; + +for (gmatched = 0;; gmatched++) + { + PCRE2_SIZE j; + int capcount; + PCRE2_SIZE *ovector; + + ovector = FLD(match_data, ovector); + + /* Fill the ovector with junk to detect elements that do not get set + when they should be. */ + + for (j = 0; j < 2*dat_datctl.oveccount; j++) ovector[j] = JUNK_OFFSET; + + /* When matching is via pcre2_match(), we will detect the use of JIT via the + stack callback function. */ + + jit_was_used = (pat_patctl.control & CTL_JITFAST) != 0; + + /* Do timing if required. */ + + if (timeitm > 0) + { + int i; + clock_t start_time, time_taken; + + if ((dat_datctl.control & CTL_DFA) != 0) + { + if ((dat_datctl.options & PCRE2_DFA_RESTART) != 0) + { + fprintf(outfile, "Timing DFA restarts is not supported\n"); + return PR_OK; + } + if (dfa_workspace == NULL) + dfa_workspace = (int *)malloc(DFA_WS_DIMENSION*sizeof(int)); + start_time = clock(); + for (i = 0; i < timeitm; i++) + { + PCRE2_DFA_MATCH(capcount, compiled_code, pp, arg_ulen, + dat_datctl.offset, dat_datctl.options | g_notempty, match_data, + use_dat_context, dfa_workspace, DFA_WS_DIMENSION); + } + } + + else if ((pat_patctl.control & CTL_JITFAST) != 0) + { + start_time = clock(); + for (i = 0; i < timeitm; i++) + { + PCRE2_JIT_MATCH(capcount, compiled_code, pp, arg_ulen, + dat_datctl.offset, dat_datctl.options | g_notempty, match_data, + use_dat_context); + } + } + + else + { + start_time = clock(); + for (i = 0; i < timeitm; i++) + { + PCRE2_MATCH(capcount, compiled_code, pp, arg_ulen, + dat_datctl.offset, dat_datctl.options | g_notempty, match_data, + use_dat_context); + } + } + total_match_time += (time_taken = clock() - start_time); + fprintf(outfile, "Match time %.4f milliseconds\n", + (((double)time_taken * 1000.0) / (double)timeitm) / + (double)CLOCKS_PER_SEC); + } + + /* Find the heap, match and depth limits if requested. The depth and heap + limits are not relevant for JIT. The return from check_match_limit() is the + return from the final call to pcre2_match() or pcre2_dfa_match(). */ + + if ((dat_datctl.control & CTL_FINDLIMITS) != 0) + { + capcount = 0; /* This stops compiler warnings */ + + if (FLD(compiled_code, executable_jit) == NULL || + (dat_datctl.options & PCRE2_NO_JIT) != 0) + { + (void)check_match_limit(pp, arg_ulen, PCRE2_ERROR_HEAPLIMIT, "heap"); + } + + capcount = check_match_limit(pp, arg_ulen, PCRE2_ERROR_MATCHLIMIT, + "match"); + + if (FLD(compiled_code, executable_jit) == NULL || + (dat_datctl.options & PCRE2_NO_JIT) != 0 || + (dat_datctl.control & CTL_DFA) != 0) + { + capcount = check_match_limit(pp, arg_ulen, PCRE2_ERROR_DEPTHLIMIT, + "depth"); + } + + if (capcount == 0) + { + fprintf(outfile, "Matched, but offsets vector is too small to show all matches\n"); + capcount = dat_datctl.oveccount; + } + } + + /* Otherwise just run a single match, setting up a callout if required (the + default). There is a copy of the pattern in pbuffer8 for use by callouts. */ + + else + { + if ((dat_datctl.control & CTL_CALLOUT_NONE) == 0) + { + PCRE2_SET_CALLOUT(dat_context, callout_function, + (void *)(&dat_datctl.callout_data)); + first_callout = TRUE; + last_callout_mark = NULL; + callout_count = 0; + } + else + { + PCRE2_SET_CALLOUT(dat_context, NULL, NULL); /* No callout */ + } + + /* Run a single DFA or NFA match. */ + + if ((dat_datctl.control & CTL_DFA) != 0) + { + if (dfa_workspace == NULL) + dfa_workspace = (int *)malloc(DFA_WS_DIMENSION*sizeof(int)); + if (dfa_matched++ == 0) + dfa_workspace[0] = -1; /* To catch bad restart */ + PCRE2_DFA_MATCH(capcount, compiled_code, pp, arg_ulen, + dat_datctl.offset, dat_datctl.options | g_notempty, match_data, + use_dat_context, dfa_workspace, DFA_WS_DIMENSION); + if (capcount == 0) + { + fprintf(outfile, "Matched, but offsets vector is too small to show all matches\n"); + capcount = dat_datctl.oveccount; + } + } + else + { + if ((pat_patctl.control & CTL_JITFAST) != 0) + PCRE2_JIT_MATCH(capcount, compiled_code, pp, arg_ulen, dat_datctl.offset, + dat_datctl.options | g_notempty, match_data, use_dat_context); + else + PCRE2_MATCH(capcount, compiled_code, pp, arg_ulen, dat_datctl.offset, + dat_datctl.options | g_notempty, match_data, use_dat_context); + if (capcount == 0) + { + fprintf(outfile, "Matched, but too many substrings\n"); + capcount = dat_datctl.oveccount; + } + } + } + + /* The result of the match is now in capcount. First handle a successful + match. */ + + if (capcount >= 0) + { + int i; + uint32_t oveccount; + + /* This is a check against a lunatic return value. */ + + PCRE2_GET_OVECTOR_COUNT(oveccount, match_data); + if (capcount > (int)oveccount) + { + fprintf(outfile, + "** PCRE2 error: returned count %d is too big for ovector count %d\n", + capcount, oveccount); + capcount = oveccount; + if ((dat_datctl.control & CTL_ANYGLOB) != 0) + { + fprintf(outfile, "** Global loop abandoned\n"); + dat_datctl.control &= ~CTL_ANYGLOB; /* Break g/G loop */ + } + } + + /* If this is not the first time round a global loop, check that the + returned string has changed. If it has not, check for an empty string match + at different starting offset from the previous match. This is a failed test + retry for null-matching patterns that don't match at their starting offset, + for example /(?<=\G.)/. A repeated match at the same point is not such a + pattern, and must be discarded, and we then proceed to seek a non-null + match at the current point. For any other repeated match, there is a bug + somewhere and we must break the loop because it will go on for ever. We + know that there are always at least two elements in the ovector. */ + + if (gmatched > 0 && ovecsave[0] == ovector[0] && ovecsave[1] == ovector[1]) + { + if (ovector[0] == ovector[1] && ovecsave[2] != dat_datctl.offset) + { + g_notempty = PCRE2_NOTEMPTY_ATSTART | PCRE2_ANCHORED; + ovecsave[2] = dat_datctl.offset; + continue; /* Back to the top of the loop */ + } + fprintf(outfile, + "** PCRE2 error: global repeat returned the same string as previous\n"); + fprintf(outfile, "** Global loop abandoned\n"); + dat_datctl.control &= ~CTL_ANYGLOB; /* Break g/G loop */ + } + + /* "allcaptures" requests showing of all captures in the pattern, to check + unset ones at the end. It may be set on the pattern or the data. Implement + by setting capcount to the maximum. This is not relevant for DFA matching, + so ignore it. */ + + if ((dat_datctl.control & CTL_ALLCAPTURES) != 0) + { + uint32_t maxcapcount; + if ((dat_datctl.control & CTL_DFA) != 0) + { + fprintf(outfile, "** Ignored after DFA matching: allcaptures\n"); + } + else + { + if (pattern_info(PCRE2_INFO_CAPTURECOUNT, &maxcapcount, FALSE) < 0) + return PR_SKIP; + capcount = maxcapcount + 1; /* Allow for full match */ + if (capcount > (int)oveccount) capcount = oveccount; + } + } + + /* Output the captured substrings. Note that, for the matched string, + the use of \K in an assertion can make the start later than the end. */ + + for (i = 0; i < 2*capcount; i += 2) + { + PCRE2_SIZE lleft, lmiddle, lright; + PCRE2_SIZE start = ovector[i]; + PCRE2_SIZE end = ovector[i+1]; + + if (start > end) + { + start = ovector[i+1]; + end = ovector[i]; + fprintf(outfile, "Start of matched string is beyond its end - " + "displaying from end to start.\n"); + } + + fprintf(outfile, "%2d: ", i/2); + + /* Check for an unset group */ + + if (start == PCRE2_UNSET) + { + fprintf(outfile, "\n"); + continue; + } + + /* Check for silly offsets, in particular, values that have not been + set when they should have been. */ + + if (start > ulen || end > ulen) + { + fprintf(outfile, "ERROR: bad value(s) for offset(s): 0x%lx 0x%lx\n", + (unsigned long int)start, (unsigned long int)end); + continue; + } + + /* When JIT is not being used, ALLUSEDTEXT may be set. (It if is set with + JIT, it is disabled above, with a comment.) When the match is done by the + interpreter, leftchar and rightchar are available, and if ALLUSEDTEXT is + set, and if the leftmost consulted character is before the start of the + match or the rightmost consulted character is past the end of the match, + we want to show all consulted characters for the main matched string, and + indicate which were lookarounds. */ + + if (i == 0) + { + BOOL showallused; + PCRE2_SIZE leftchar, rightchar; + + if ((dat_datctl.control & CTL_ALLUSEDTEXT) != 0) + { + leftchar = FLD(match_data, leftchar); + rightchar = FLD(match_data, rightchar); + showallused = i == 0 && (leftchar < start || rightchar > end); + } + else showallused = FALSE; + + if (showallused) + { + PCHARS(lleft, pp, leftchar, start - leftchar, utf, outfile); + PCHARS(lmiddle, pp, start, end - start, utf, outfile); + PCHARS(lright, pp, end, rightchar - end, utf, outfile); + if ((pat_patctl.control & CTL_JITVERIFY) != 0 && jit_was_used) + fprintf(outfile, " (JIT)"); + fprintf(outfile, "\n "); + for (j = 0; j < lleft; j++) fprintf(outfile, "<"); + for (j = 0; j < lmiddle; j++) fprintf(outfile, " "); + for (j = 0; j < lright; j++) fprintf(outfile, ">"); + } + + /* When a pattern contains \K, the start of match position may be + different to the start of the matched string. When this is the case, + show it when requested. */ + + else if ((dat_datctl.control & CTL_STARTCHAR) != 0) + { + PCRE2_SIZE startchar; + PCRE2_GET_STARTCHAR(startchar, match_data); + PCHARS(lleft, pp, startchar, start - startchar, utf, outfile); + PCHARSV(pp, start, end - start, utf, outfile); + if ((pat_patctl.control & CTL_JITVERIFY) != 0 && jit_was_used) + fprintf(outfile, " (JIT)"); + if (startchar != start) + { + fprintf(outfile, "\n "); + for (j = 0; j < lleft; j++) fprintf(outfile, "^"); + } + } + + /* Otherwise, just show the matched string. */ + + else + { + PCHARSV(pp, start, end - start, utf, outfile); + if ((pat_patctl.control & CTL_JITVERIFY) != 0 && jit_was_used) + fprintf(outfile, " (JIT)"); + } + } + + /* Not the main matched string. Just show it unadorned. */ + + else + { + PCHARSV(pp, start, end - start, utf, outfile); + } + + fprintf(outfile, "\n"); + + /* Note: don't use the start/end variables here because we want to + show the text from what is reported as the end. */ + + if ((dat_datctl.control & CTL_ALLAFTERTEXT) != 0 || + (i == 0 && (dat_datctl.control & CTL_AFTERTEXT) != 0)) + { + fprintf(outfile, "%2d+ ", i/2); + PCHARSV(pp, ovector[i+1], ulen - ovector[i+1], utf, outfile); + fprintf(outfile, "\n"); + } + } + + /* Output (*MARK) data if requested */ + + if ((dat_datctl.control & CTL_MARK) != 0 && + TESTFLD(match_data, mark, !=, NULL)) + { + fprintf(outfile, "MK: "); + PCHARSV(CASTFLD(void *, match_data, mark), 0, -1, utf, outfile); + fprintf(outfile, "\n"); + } + + /* Process copy/get strings */ + + if (!copy_and_get(utf, capcount)) return PR_ABEND; + + } /* End of handling a successful match */ + + /* There was a partial match. The value of ovector[0] is the bumpalong point, + that is, startchar, not any \K point that might have been passed. */ + + else if (capcount == PCRE2_ERROR_PARTIAL) + { + PCRE2_SIZE poffset; + int backlength; + int rubriclength = 0; + + fprintf(outfile, "Partial match"); + if ((dat_datctl.control & CTL_MARK) != 0 && + TESTFLD(match_data, mark, !=, NULL)) + { + fprintf(outfile, ", mark="); + PCHARS(rubriclength, CASTFLD(void *, match_data, mark), 0, -1, utf, + outfile); + rubriclength += 7; + } + fprintf(outfile, ": "); + rubriclength += 15; + + poffset = backchars(pp, ovector[0], maxlookbehind, utf); + PCHARS(backlength, pp, poffset, ovector[0] - poffset, utf, outfile); + PCHARSV(pp, ovector[0], ulen - ovector[0], utf, outfile); + + if ((pat_patctl.control & CTL_JITVERIFY) != 0 && jit_was_used) + fprintf(outfile, " (JIT)"); + fprintf(outfile, "\n"); + + if (backlength != 0) + { + int i; + for (i = 0; i < rubriclength; i++) fprintf(outfile, " "); + for (i = 0; i < backlength; i++) fprintf(outfile, "<"); + fprintf(outfile, "\n"); + } + + /* Process copy/get strings */ + + if (!copy_and_get(utf, 1)) return PR_ABEND; + + break; /* Out of the /g loop */ + } /* End of handling partial match */ + + /* Failed to match. If this is a /g or /G loop, we might previously have + set g_notempty (to PCRE2_NOTEMPTY_ATSTART|PCRE2_ANCHORED) after a null match. + If that is the case, this is not necessarily the end. We want to advance the + start offset, and continue. We won't be at the end of the string - that was + checked before setting g_notempty. We achieve the effect by pretending that a + single character was matched. + + Complication arises in the case when the newline convention is "any", "crlf", + or "anycrlf". If the previous match was at the end of a line terminated by + CRLF, an advance of one character just passes the CR, whereas we should + prefer the longer newline sequence, as does the code in pcre2_match(). + + Otherwise, in the case of UTF-8 or UTF-16 matching, the advance must be one + character, not one byte. */ + + else if (g_notempty != 0) /* There was a previous null match */ + { + uint16_t nl = FLD(compiled_code, newline_convention); + PCRE2_SIZE start_offset = dat_datctl.offset; /* Where the match was */ + PCRE2_SIZE end_offset = start_offset + 1; + + if ((nl == PCRE2_NEWLINE_CRLF || nl == PCRE2_NEWLINE_ANY || + nl == PCRE2_NEWLINE_ANYCRLF) && + start_offset < ulen - 1 && + CODE_UNIT(pp, start_offset) == '\r' && + CODE_UNIT(pp, end_offset) == '\n') + end_offset++; + + else if (utf && test_mode != PCRE32_MODE) + { + if (test_mode == PCRE8_MODE) + { + for (; end_offset < ulen; end_offset++) + if ((((PCRE2_SPTR8)pp)[end_offset] & 0xc0) != 0x80) break; + } + else /* 16-bit mode */ + { + for (; end_offset < ulen; end_offset++) + if ((((PCRE2_SPTR16)pp)[end_offset] & 0xfc00) != 0xdc00) break; + } + } + + SETFLDVEC(match_data, ovector, 0, start_offset); + SETFLDVEC(match_data, ovector, 1, end_offset); + } /* End of handling null match in a global loop */ + + /* A "normal" match failure. There will be a negative error number in + capcount. */ + + else + { + switch(capcount) + { + case PCRE2_ERROR_NOMATCH: + if (gmatched == 0) + { + fprintf(outfile, "No match"); + if ((dat_datctl.control & CTL_MARK) != 0 && + TESTFLD(match_data, mark, !=, NULL)) + { + fprintf(outfile, ", mark = "); + PCHARSV(CASTFLD(void *, match_data, mark), 0, -1, utf, outfile); + } + if ((pat_patctl.control & CTL_JITVERIFY) != 0 && jit_was_used) + fprintf(outfile, " (JIT)"); + fprintf(outfile, "\n"); + } + break; + + case PCRE2_ERROR_BADUTFOFFSET: + fprintf(outfile, "Error %d (bad UTF-%d offset)\n", capcount, test_mode); + break; + + default: + fprintf(outfile, "Failed: error %d: ", capcount); + if (!print_error_message(capcount, "", "")) return PR_ABEND; + if (capcount <= PCRE2_ERROR_UTF8_ERR1 && + capcount >= PCRE2_ERROR_UTF32_ERR2) + { + PCRE2_SIZE startchar; + PCRE2_GET_STARTCHAR(startchar, match_data); + fprintf(outfile, " at offset %" SIZ_FORM, SIZ_CAST startchar); + } + fprintf(outfile, "\n"); + break; + } + + break; /* Out of the /g loop */ + } /* End of failed match handling */ + + /* Control reaches here in two circumstances: (a) after a match, and (b) + after a non-match that immediately followed a match on an empty string when + doing a global search. Such a match is done with PCRE2_NOTEMPTY_ATSTART and + PCRE2_ANCHORED set in g_notempty. The code above turns it into a fake match + of one character. So effectively we get here only after a match. If we + are not doing a global search, we are done. */ + + if ((dat_datctl.control & CTL_ANYGLOB) == 0) break; else + { + PCRE2_SIZE match_offset = FLD(match_data, ovector)[0]; + PCRE2_SIZE end_offset = FLD(match_data, ovector)[1]; + + /* We must now set up for the next iteration of a global search. If we have + matched an empty string, first check to see if we are at the end of the + subject. If so, the loop is over. Otherwise, mimic what Perl's /g option + does. Set PCRE2_NOTEMPTY_ATSTART and PCRE2_ANCHORED and try the match again + at the same point. If this fails it will be picked up above, where a fake + match is set up so that at this point we advance to the next character. + + However, in order to cope with patterns that never match at their starting + offset (e.g. /(?<=\G.)/) we don't do this when the match offset is greater + than the starting offset. This means there will be a retry with the + starting offset at the match offset. If this returns the same match again, + it is picked up above and ignored, and the special action is then taken. */ + + if (match_offset == end_offset) + { + if (end_offset == ulen) break; /* End of subject */ + if (match_offset <= dat_datctl.offset) + g_notempty = PCRE2_NOTEMPTY_ATSTART | PCRE2_ANCHORED; + } + + /* However, even after matching a non-empty string, there is still one + tricky case. If a pattern contains \K within a lookbehind assertion at the + start, the end of the matched string can be at the offset where the match + started. In the case of a normal /g iteration without special action, this + leads to a loop that keeps on returning the same substring. The loop would + be caught above, but we really want to move on to the next match. */ + + else + { + g_notempty = 0; /* Set for a "normal" repeat */ + if ((dat_datctl.control & CTL_GLOBAL) != 0) + { + PCRE2_SIZE startchar; + PCRE2_GET_STARTCHAR(startchar, match_data); + if (end_offset <= startchar) + { + if (startchar >= ulen) break; /* End of subject */ + end_offset = startchar + 1; + if (utf && test_mode != PCRE32_MODE) + { + if (test_mode == PCRE8_MODE) + { + for (; end_offset < ulen; end_offset++) + if ((((PCRE2_SPTR8)pp)[end_offset] & 0xc0) != 0x80) break; + } + else /* 16-bit mode */ + { + for (; end_offset < ulen; end_offset++) + if ((((PCRE2_SPTR16)pp)[end_offset] & 0xfc00) != 0xdc00) break; + } + } + } + } + } + + /* For a normal global (/g) iteration, save the current ovector[0,1] and + the starting offset so that we can check that they do change each time. + Otherwise a matching bug that returns the same string causes an infinite + loop. It has happened! Then update the start offset, leaving other + parameters alone. */ + + if ((dat_datctl.control & CTL_GLOBAL) != 0) + { + ovecsave[0] = ovector[0]; + ovecsave[1] = ovector[1]; + ovecsave[2] = dat_datctl.offset; + dat_datctl.offset = end_offset; + } + + /* For altglobal, just update the pointer and length. */ + + else + { + pp += end_offset * code_unit_size; + len -= end_offset * code_unit_size; + ulen -= end_offset; + if (arg_ulen != PCRE2_ZERO_TERMINATED) arg_ulen -= end_offset; + } + } + } /* End of global loop */ + +show_memory = FALSE; +return PR_OK; +} + + + + +/************************************************* +* Print PCRE2 version * +*************************************************/ + +static void +print_version(FILE *f) +{ +VERSION_TYPE *vp; +fprintf(f, "PCRE2 version "); +for (vp = version; *vp != 0; vp++) fprintf(f, "%c", *vp); +fprintf(f, "\n"); +} + + + +/************************************************* +* Print Unicode version * +*************************************************/ + +static void +print_unicode_version(FILE *f) +{ +VERSION_TYPE *vp; +fprintf(f, "Unicode version "); +for (vp = uversion; *vp != 0; vp++) fprintf(f, "%c", *vp); +} + + + +/************************************************* +* Print JIT target * +*************************************************/ + +static void +print_jit_target(FILE *f) +{ +VERSION_TYPE *vp; +for (vp = jittarget; *vp != 0; vp++) fprintf(f, "%c", *vp); +} + + + +/************************************************* +* Print newline configuration * +*************************************************/ + +/* Output is always to stdout. + +Arguments: + rc the return code from PCRE2_CONFIG_NEWLINE + isc TRUE if called from "-C newline" +Returns: nothing +*/ + +static void +print_newline_config(uint32_t optval, BOOL isc) +{ +if (!isc) printf(" Newline sequence is "); +if (optval < sizeof(newlines)/sizeof(char *)) + printf("%s\n", newlines[optval]); +else + printf("a non-standard value: %d\n", optval); +} + + + +/************************************************* +* Usage function * +*************************************************/ + +static void +usage(void) +{ +printf("Usage: pcre2test [options] [ []]\n\n"); +printf("Input and output default to stdin and stdout.\n"); +#if defined(SUPPORT_LIBREADLINE) || defined(SUPPORT_LIBEDIT) +printf("If input is a terminal, readline() is used to read from it.\n"); +#else +printf("This version of pcre2test is not linked with readline().\n"); +#endif +printf("\nOptions:\n"); +#ifdef SUPPORT_PCRE2_8 +printf(" -8 use the 8-bit library\n"); +#endif +#ifdef SUPPORT_PCRE2_16 +printf(" -16 use the 16-bit library\n"); +#endif +#ifdef SUPPORT_PCRE2_32 +printf(" -32 use the 32-bit library\n"); +#endif +printf(" -ac set default pattern modifier PCRE2_AUTO_CALLOUT\n"); +printf(" -AC as -ac, but also set subject 'callout_extra' modifier\n"); +printf(" -b set default pattern modifier 'fullbincode'\n"); +printf(" -C show PCRE2 compile-time options and exit\n"); +printf(" -C arg show a specific compile-time option and exit with its\n"); +printf(" value if numeric (else 0). The arg can be:\n"); +printf(" backslash-C use of \\C is enabled [0, 1]\n"); +printf(" bsr \\R type [ANYCRLF, ANY]\n"); +printf(" ebcdic compiled for EBCDIC character code [0,1]\n"); +printf(" ebcdic-nl NL code if compiled for EBCDIC\n"); +printf(" jit just-in-time compiler supported [0, 1]\n"); +printf(" linksize internal link size [2, 3, 4]\n"); +printf(" newline newline type [CR, LF, CRLF, ANYCRLF, ANY, NUL]\n"); +printf(" pcre2-8 8 bit library support enabled [0, 1]\n"); +printf(" pcre2-16 16 bit library support enabled [0, 1]\n"); +printf(" pcre2-32 32 bit library support enabled [0, 1]\n"); +printf(" unicode Unicode and UTF support enabled [0, 1]\n"); +printf(" -d set default pattern modifier 'debug'\n"); +printf(" -dfa set default subject modifier 'dfa'\n"); +printf(" -error show messages for error numbers, then exit\n"); +printf(" -help show usage information\n"); +printf(" -i set default pattern modifier 'info'\n"); +printf(" -jit set default pattern modifier 'jit'\n"); +printf(" -jitverify set default pattern modifier 'jitverify'\n"); +printf(" -LM list pattern and subject modifiers, then exit\n"); +printf(" -q quiet: do not output PCRE2 version number at start\n"); +printf(" -pattern set default pattern modifier fields\n"); +printf(" -subject set default subject modifier fields\n"); +printf(" -S set stack size to mebibytes\n"); +printf(" -t [] time compilation and execution, repeating times\n"); +printf(" -tm [] time execution (matching) only, repeating times\n"); +printf(" -T same as -t, but show total times at the end\n"); +printf(" -TM same as -tm, but show total time at the end\n"); +printf(" -version show PCRE2 version and exit\n"); +} + + + +/************************************************* +* Handle -C option * +*************************************************/ + +/* This option outputs configuration options and sets an appropriate return +code when asked for a single option. The code is abstracted into a separate +function because of its size. Use whichever pcre2_config() function is +available. + +Argument: an option name or NULL +Returns: the return code +*/ + +static int +c_option(const char *arg) +{ +uint32_t optval; +unsigned int i = COPTLISTCOUNT; +int yield = 0; + +if (arg != NULL && arg[0] != CHAR_MINUS) + { + for (i = 0; i < COPTLISTCOUNT; i++) + if (strcmp(arg, coptlist[i].name) == 0) break; + + if (i >= COPTLISTCOUNT) + { + fprintf(stderr, "** Unknown -C option '%s'\n", arg); + return 0; + } + + switch (coptlist[i].type) + { + case CONF_BSR: + (void)PCRE2_CONFIG(coptlist[i].value, &optval); + printf("%s\n", (optval == PCRE2_BSR_ANYCRLF)? "ANYCRLF" : "ANY"); + break; + + case CONF_FIX: + yield = coptlist[i].value; + printf("%d\n", yield); + break; + + case CONF_FIZ: + optval = coptlist[i].value; + printf("%d\n", optval); + break; + + case CONF_INT: + (void)PCRE2_CONFIG(coptlist[i].value, &yield); + printf("%d\n", yield); + break; + + case CONF_NL: + (void)PCRE2_CONFIG(coptlist[i].value, &optval); + print_newline_config(optval, TRUE); + break; + } + +/* For VMS, return the value by setting a symbol, for certain values only. */ + +#ifdef __VMS + if (copytlist[i].type == CONF_FIX || coptlist[i].type == CONF_INT) + { + char ucname[16]; + strcpy(ucname, coptlist[i].name); + for (i = 0; ucname[i] != 0; i++) ucname[i] = toupper[ucname[i]]; + vms_setsymbol(ucname, 0, optval); + } +#endif + + return yield; + } + +/* No argument for -C: output all configuration information. */ + +print_version(stdout); +printf("Compiled with\n"); + +#ifdef EBCDIC +printf(" EBCDIC code support: LF is 0x%02x\n", CHAR_LF); +#if defined NATIVE_ZOS +printf(" EBCDIC code page %s or similar\n", pcrz_cpversion()); +#endif +#endif + +(void)PCRE2_CONFIG(PCRE2_CONFIG_COMPILED_WIDTHS, &optval); +if (optval & 1) printf(" 8-bit support\n"); +if (optval & 2) printf(" 16-bit support\n"); +if (optval & 4) printf(" 32-bit support\n"); + +#ifdef SUPPORT_VALGRIND +printf(" Valgrind support\n"); +#endif + +(void)PCRE2_CONFIG(PCRE2_CONFIG_UNICODE, &optval); +if (optval != 0) + { + printf(" UTF and UCP support ("); + print_unicode_version(stdout); + printf(")\n"); + } +else printf(" No Unicode support\n"); + +(void)PCRE2_CONFIG(PCRE2_CONFIG_JIT, &optval); +if (optval != 0) + { + printf(" Just-in-time compiler support: "); + print_jit_target(stdout); + printf("\n"); + } +else + { + printf(" No just-in-time compiler support\n"); + } + +(void)PCRE2_CONFIG(PCRE2_CONFIG_NEWLINE, &optval); +print_newline_config(optval, FALSE); +(void)PCRE2_CONFIG(PCRE2_CONFIG_BSR, &optval); +printf(" \\R matches %s\n", + (optval == PCRE2_BSR_ANYCRLF)? "CR, LF, or CRLF only" : + "all Unicode newlines"); +(void)PCRE2_CONFIG(PCRE2_CONFIG_NEVER_BACKSLASH_C, &optval); +printf(" \\C is %ssupported\n", optval? "not ":""); +(void)PCRE2_CONFIG(PCRE2_CONFIG_LINKSIZE, &optval); +printf(" Internal link size = %d\n", optval); +(void)PCRE2_CONFIG(PCRE2_CONFIG_PARENSLIMIT, &optval); +printf(" Parentheses nest limit = %d\n", optval); +(void)PCRE2_CONFIG(PCRE2_CONFIG_HEAPLIMIT, &optval); +printf(" Default heap limit = %d\n", optval); +(void)PCRE2_CONFIG(PCRE2_CONFIG_MATCHLIMIT, &optval); +printf(" Default match limit = %d\n", optval); +(void)PCRE2_CONFIG(PCRE2_CONFIG_DEPTHLIMIT, &optval); +printf(" Default depth limit = %d\n", optval); +return 0; +} + + + +/************************************************* +* Display one modifier * +*************************************************/ + +static void +display_one_modifier(modstruct *m, BOOL for_pattern) +{ +uint32_t c = (!for_pattern && (m->which == MOD_PND || m->which == MOD_PNDP))? + '*' : ' '; +printf("%c%s", c, m->name); +} + + + +/************************************************* +* Display pattern or subject modifiers * +*************************************************/ + +/* In order to print in two columns, first scan without printing to get a list +of the modifiers that are required. + +Arguments: + for_pattern TRUE for pattern modifiers, FALSE for subject modifiers + title string to be used in title + +Returns: nothing +*/ + +static void +display_selected_modifiers(BOOL for_pattern, const char *title) +{ +uint32_t i, j; +uint32_t n = 0; +uint32_t list[MODLISTCOUNT]; + +for (i = 0; i < MODLISTCOUNT; i++) + { + BOOL is_pattern = TRUE; + modstruct *m = modlist + i; + + switch (m->which) + { + case MOD_CTC: /* Compile context */ + case MOD_PAT: /* Pattern */ + case MOD_PATP: /* Pattern, OK for Perl-compatible test */ + break; + + /* The MOD_PND and MOD_PNDP modifiers are precisely those that affect + subjects, but can be given with a pattern. We list them as subject + modifiers, but marked with an asterisk.*/ + + case MOD_CTM: /* Match context */ + case MOD_DAT: /* Subject line */ + case MOD_PND: /* As PD, but not default pattern */ + case MOD_PNDP: /* As PND, OK for Perl-compatible test */ + is_pattern = FALSE; + break; + + default: printf("** Unknown type for modifier '%s'\n", m->name); + /* Fall through */ + case MOD_PD: /* Pattern or subject */ + case MOD_PDP: /* As PD, OK for Perl-compatible test */ + is_pattern = for_pattern; + break; + } + + if (for_pattern == is_pattern) list[n++] = i; + } + +/* Now print from the list in two columns. */ + +printf("-------------- %s MODIFIERS --------------\n", title); + +for (i = 0, j = (n+1)/2; i < (n+1)/2; i++, j++) + { + modstruct *m = modlist + list[i]; + display_one_modifier(m, for_pattern); + if (j < n) + { + uint32_t k = 27 - strlen(m->name); + while (k-- > 0) printf(" "); + display_one_modifier(modlist + list[j], for_pattern); + } + printf("\n"); + } +} + + + +/************************************************* +* Display the list of modifiers * +*************************************************/ + +static void +display_modifiers(void) +{ +printf( + "An asterisk on a subject modifier means that it may be given on a pattern\n" + "line, in order to apply to all subjects matched by that pattern. Modifiers\n" + "that are listed for both patterns and subjects have different effects in\n" + "each case.\n\n"); +display_selected_modifiers(TRUE, "PATTERN"); +printf("\n"); +display_selected_modifiers(FALSE, "SUBJECT"); +} + + + +/************************************************* +* Main Program * +*************************************************/ + +int +main(int argc, char **argv) +{ +uint32_t temp; +uint32_t yield = 0; +uint32_t op = 1; +BOOL notdone = TRUE; +BOOL quiet = FALSE; +BOOL showtotaltimes = FALSE; +BOOL skipping = FALSE; +char *arg_subject = NULL; +char *arg_pattern = NULL; +char *arg_error = NULL; + +/* The offsets to the options and control bits fields of the pattern and data +control blocks must be the same so that common options and controls such as +"anchored" or "memory" can work for either of them from a single table entry. +We cannot test this till runtime because "offsetof" does not work in the +preprocessor. */ + +if (PO(options) != DO(options) || PO(control) != DO(control) || + PO(control2) != DO(control2)) + { + fprintf(stderr, "** Coding error: " + "options and control offsets for pattern and data must be the same.\n"); + return 1; + } + +/* Get the PCRE2 and Unicode version number and JIT target information, at the +same time checking that a request for the length gives the same answer. Also +check lengths for non-string items. */ + +if (PCRE2_CONFIG(PCRE2_CONFIG_VERSION, NULL) != + PCRE2_CONFIG(PCRE2_CONFIG_VERSION, version) || + + PCRE2_CONFIG(PCRE2_CONFIG_UNICODE_VERSION, NULL) != + PCRE2_CONFIG(PCRE2_CONFIG_UNICODE_VERSION, uversion) || + + PCRE2_CONFIG(PCRE2_CONFIG_JITTARGET, NULL) != + PCRE2_CONFIG(PCRE2_CONFIG_JITTARGET, jittarget) || + + PCRE2_CONFIG(PCRE2_CONFIG_UNICODE, NULL) != sizeof(uint32_t) || + PCRE2_CONFIG(PCRE2_CONFIG_MATCHLIMIT, NULL) != sizeof(uint32_t)) + { + fprintf(stderr, "** Error in pcre2_config(): bad length\n"); + return 1; + } + +/* Check that bad options are diagnosed. */ + +if (PCRE2_CONFIG(999, NULL) != PCRE2_ERROR_BADOPTION || + PCRE2_CONFIG(999, &temp) != PCRE2_ERROR_BADOPTION) + { + fprintf(stderr, "** Error in pcre2_config(): bad option not diagnosed\n"); + return 1; + } + +/* This configuration option is now obsolete, but running a quick check ensures +that its code is covered. */ + +(void)PCRE2_CONFIG(PCRE2_CONFIG_STACKRECURSE, &temp); + +/* Get buffers from malloc() so that valgrind will check their misuse when +debugging. They grow automatically when very long lines are read. The 16- +and 32-bit buffers (pbuffer16, pbuffer32) are obtained only if needed. */ + +buffer = (uint8_t *)malloc(pbuffer8_size); +pbuffer8 = (uint8_t *)malloc(pbuffer8_size); + +/* The following _setmode() stuff is some Windows magic that tells its runtime +library to translate CRLF into a single LF character. At least, that's what +I've been told: never having used Windows I take this all on trust. Originally +it set 0x8000, but then I was advised that _O_BINARY was better. */ + +#if defined(_WIN32) || defined(WIN32) +_setmode( _fileno( stdout ), _O_BINARY ); +#endif + +/* Initialization that does not depend on the running mode. */ + +locale_name[0] = 0; + +memset(&def_patctl, 0, sizeof(patctl)); +def_patctl.convert_type = CONVERT_UNSET; + +memset(&def_datctl, 0, sizeof(datctl)); +def_datctl.oveccount = DEFAULT_OVECCOUNT; +def_datctl.copy_numbers[0] = -1; +def_datctl.get_numbers[0] = -1; +def_datctl.startend[0] = def_datctl.startend[1] = CFORE_UNSET; +def_datctl.cerror[0] = def_datctl.cerror[1] = CFORE_UNSET; +def_datctl.cfail[0] = def_datctl.cfail[1] = CFORE_UNSET; + +/* Scan command line options. */ + +while (argc > 1 && argv[op][0] == '-' && argv[op][1] != 0) + { + char *endptr; + char *arg = argv[op]; + unsigned long uli; + + /* List modifiers and exit. */ + + if (strcmp(arg, "-LM") == 0) + { + display_modifiers(); + goto EXIT; + } + + /* Display and/or set return code for configuration options. */ + + if (strcmp(arg, "-C") == 0) + { + yield = c_option(argv[op + 1]); + goto EXIT; + } + + /* Select operating mode. Ensure that pcre2_config() is called in 16-bit + and 32-bit modes because that won't happen naturally when 8-bit is also + configured. Also call some other functions that are not otherwise used. This + means that a coverage report won't claim there are uncalled functions. */ + + if (strcmp(arg, "-8") == 0) + { +#ifdef SUPPORT_PCRE2_8 + test_mode = PCRE8_MODE; + (void)pcre2_set_bsr_8(pat_context8, 999); + (void)pcre2_set_newline_8(pat_context8, 999); +#else + fprintf(stderr, + "** This version of PCRE2 was built without 8-bit support\n"); + exit(1); +#endif + } + + else if (strcmp(arg, "-16") == 0) + { +#ifdef SUPPORT_PCRE2_16 + test_mode = PCRE16_MODE; + (void)pcre2_config_16(PCRE2_CONFIG_VERSION, NULL); + (void)pcre2_set_bsr_16(pat_context16, 999); + (void)pcre2_set_newline_16(pat_context16, 999); +#else + fprintf(stderr, + "** This version of PCRE2 was built without 16-bit support\n"); + exit(1); +#endif + } + + else if (strcmp(arg, "-32") == 0) + { +#ifdef SUPPORT_PCRE2_32 + test_mode = PCRE32_MODE; + (void)pcre2_config_32(PCRE2_CONFIG_VERSION, NULL); + (void)pcre2_set_bsr_32(pat_context32, 999); + (void)pcre2_set_newline_32(pat_context32, 999); +#else + fprintf(stderr, + "** This version of PCRE2 was built without 32-bit support\n"); + exit(1); +#endif + } + + /* Set quiet (no version verification) */ + + else if (strcmp(arg, "-q") == 0) quiet = TRUE; + + /* Set system stack size */ + + else if (strcmp(arg, "-S") == 0 && argc > 2 && + ((uli = strtoul(argv[op+1], &endptr, 10)), *endptr == 0)) + { +#if defined(_WIN32) || defined(WIN32) || defined(__minix) || defined(NATIVE_ZOS) || defined(__VMS) + fprintf(stderr, "pcre2test: -S is not supported on this OS\n"); + exit(1); +#else + int rc; + uint32_t stack_size; + struct rlimit rlim; + if (U32OVERFLOW(uli)) + { + fprintf(stderr, "** Argument for -S is too big\n"); + exit(1); + } + stack_size = (uint32_t)uli; + getrlimit(RLIMIT_STACK, &rlim); + rlim.rlim_cur = stack_size * 1024 * 1024; + if (rlim.rlim_cur > rlim.rlim_max) + { + fprintf(stderr, + "pcre2test: requested stack size %luMiB is greater than hard limit " + "%luMiB\n", (unsigned long int)stack_size, + (unsigned long int)(rlim.rlim_max)); + exit(1); + } + rc = setrlimit(RLIMIT_STACK, &rlim); + if (rc != 0) + { + fprintf(stderr, "pcre2test: setting stack size %luMiB failed: %s\n", + (unsigned long int)stack_size, strerror(errno)); + exit(1); + } + op++; + argc--; +#endif + } + + /* Set some common pattern and subject controls */ + + else if (strcmp(arg, "-AC") == 0) + { + def_patctl.options |= PCRE2_AUTO_CALLOUT; + def_datctl.control2 |= CTL2_CALLOUT_EXTRA; + } + else if (strcmp(arg, "-ac") == 0) def_patctl.options |= PCRE2_AUTO_CALLOUT; + else if (strcmp(arg, "-b") == 0) def_patctl.control |= CTL_FULLBINCODE; + else if (strcmp(arg, "-d") == 0) def_patctl.control |= CTL_DEBUG; + else if (strcmp(arg, "-dfa") == 0) def_datctl.control |= CTL_DFA; + else if (strcmp(arg, "-i") == 0) def_patctl.control |= CTL_INFO; + else if (strcmp(arg, "-jit") == 0 || strcmp(arg, "-jitverify") == 0) + { + if (arg[4] != 0) def_patctl.control |= CTL_JITVERIFY; + def_patctl.jit = 7; /* full & partial */ +#ifndef SUPPORT_JIT + fprintf(stderr, "** Warning: JIT support is not available: " + "-jit[verify] calls functions that do nothing.\n"); +#endif + } + + /* Set timing parameters */ + + else if (strcmp(arg, "-t") == 0 || strcmp(arg, "-tm") == 0 || + strcmp(arg, "-T") == 0 || strcmp(arg, "-TM") == 0) + { + int both = arg[2] == 0; + showtotaltimes = arg[1] == 'T'; + if (argc > 2 && (uli = strtoul(argv[op+1], &endptr, 10), *endptr == 0)) + { + if (U32OVERFLOW(uli)) + { + fprintf(stderr, "** Argument for %s is too big\n", arg); + exit(1); + } + timeitm = (int)uli; + op++; + argc--; + } + else timeitm = LOOPREPEAT; + if (both) timeit = timeitm; + } + + /* Give help */ + + else if (strcmp(arg, "-help") == 0 || + strcmp(arg, "--help") == 0) + { + usage(); + goto EXIT; + } + + /* Show version */ + + else if (strcmp(arg, "-version") == 0 || + strcmp(arg, "--version") == 0) + { + print_version(stdout); + goto EXIT; + } + + /* The following options save their data for processing once we know what + the running mode is. */ + + else if (strcmp(arg, "-error") == 0) + { + arg_error = argv[op+1]; + goto CHECK_VALUE_EXISTS; + } + + else if (strcmp(arg, "-subject") == 0) + { + arg_subject = argv[op+1]; + goto CHECK_VALUE_EXISTS; + } + + else if (strcmp(arg, "-pattern") == 0) + { + arg_pattern = argv[op+1]; + CHECK_VALUE_EXISTS: + if (argc <= 2) + { + fprintf(stderr, "** Missing value for %s\n", arg); + yield = 1; + goto EXIT; + } + op++; + argc--; + } + + /* Unrecognized option */ + + else + { + fprintf(stderr, "** Unknown or malformed option '%s'\n", arg); + usage(); + yield = 1; + goto EXIT; + } + op++; + argc--; + } + +/* If -error was present, get the error numbers, show the messages, and exit. +We wait to do this until we know which mode we are in. */ + +if (arg_error != NULL) + { + int len; + int errcode; + char *endptr; + +/* Ensure the relevant non-8-bit buffer is available. Ensure that it is at +least 128 code units, because it is used for retrieving error messages. */ + +#ifdef SUPPORT_PCRE2_16 + if (test_mode == PCRE16_MODE) + { + pbuffer16_size = 256; + pbuffer16 = (uint16_t *)malloc(pbuffer16_size); + if (pbuffer16 == NULL) + { + fprintf(stderr, "pcre2test: malloc(%" SIZ_FORM ") failed for pbuffer16\n", + SIZ_CAST pbuffer16_size); + yield = 1; + goto EXIT; + } + } +#endif + +#ifdef SUPPORT_PCRE2_32 + if (test_mode == PCRE32_MODE) + { + pbuffer32_size = 512; + pbuffer32 = (uint32_t *)malloc(pbuffer32_size); + if (pbuffer32 == NULL) + { + fprintf(stderr, "pcre2test: malloc(%" SIZ_FORM ") failed for pbuffer32\n", + SIZ_CAST pbuffer32_size); + yield = 1; + goto EXIT; + } + } +#endif + + /* Loop along a list of error numbers. */ + + for (;;) + { + errcode = strtol(arg_error, &endptr, 10); + if (*endptr != 0 && *endptr != CHAR_COMMA) + { + fprintf(stderr, "** '%s' is not a valid error number list\n", arg_error); + yield = 1; + goto EXIT; + } + printf("Error %d: ", errcode); + PCRE2_GET_ERROR_MESSAGE(len, errcode, pbuffer); + if (len < 0) + { + switch (len) + { + case PCRE2_ERROR_BADDATA: + printf("PCRE2_ERROR_BADDATA (unknown error number)"); + break; + + case PCRE2_ERROR_NOMEMORY: + printf("PCRE2_ERROR_NOMEMORY (buffer too small)"); + break; + + default: + printf("Unexpected return (%d) from pcre2_get_error_message()", len); + break; + } + } + else + { + PCHARSV(CASTVAR(void *, pbuffer), 0, len, FALSE, stdout); + } + printf("\n"); + if (*endptr == 0) goto EXIT; + arg_error = endptr + 1; + } + /* Control never reaches here */ + } /* End of -error handling */ + +/* Initialize things that cannot be done until we know which test mode we are +running in. Exercise the general context copying function, which is not +otherwise used. */ + +code_unit_size = test_mode/8; +max_oveccount = DEFAULT_OVECCOUNT; + +/* Use macros to save a lot of duplication. */ + +#define CREATECONTEXTS \ + G(general_context,BITS) = G(pcre2_general_context_create_,BITS)(&my_malloc, &my_free, NULL); \ + G(general_context_copy,BITS) = G(pcre2_general_context_copy_,BITS)(G(general_context,BITS)); \ + G(default_pat_context,BITS) = G(pcre2_compile_context_create_,BITS)(G(general_context,BITS)); \ + G(pat_context,BITS) = G(pcre2_compile_context_copy_,BITS)(G(default_pat_context,BITS)); \ + G(default_dat_context,BITS) = G(pcre2_match_context_create_,BITS)(G(general_context,BITS)); \ + G(dat_context,BITS) = G(pcre2_match_context_copy_,BITS)(G(default_dat_context,BITS)); \ + G(default_con_context,BITS) = G(pcre2_convert_context_create_,BITS)(G(general_context,BITS)); \ + G(con_context,BITS) = G(pcre2_convert_context_copy_,BITS)(G(default_con_context,BITS)); \ + G(match_data,BITS) = G(pcre2_match_data_create_,BITS)(max_oveccount, G(general_context,BITS)) + +#define CONTEXTTESTS \ + (void)G(pcre2_set_compile_extra_options_,BITS)(G(pat_context,BITS), 0); \ + (void)G(pcre2_set_max_pattern_length_,BITS)(G(pat_context,BITS), 0); \ + (void)G(pcre2_set_offset_limit_,BITS)(G(dat_context,BITS), 0); \ + (void)G(pcre2_set_recursion_memory_management_,BITS)(G(dat_context,BITS), my_malloc, my_free, NULL) + +/* Call the appropriate functions for the current mode, and exercise some +functions that are not otherwise called. */ + +#ifdef SUPPORT_PCRE2_8 +#undef BITS +#define BITS 8 +if (test_mode == PCRE8_MODE) + { + CREATECONTEXTS; + CONTEXTTESTS; + } +#endif + +#ifdef SUPPORT_PCRE2_16 +#undef BITS +#define BITS 16 +if (test_mode == PCRE16_MODE) + { + CREATECONTEXTS; + CONTEXTTESTS; + } +#endif + +#ifdef SUPPORT_PCRE2_32 +#undef BITS +#define BITS 32 +if (test_mode == PCRE32_MODE) + { + CREATECONTEXTS; + CONTEXTTESTS; + } +#endif + +/* Set a default parentheses nest limit that is large enough to run the +standard tests (this also exercises the function). */ + +PCRE2_SET_PARENS_NEST_LIMIT(default_pat_context, PARENS_NEST_DEFAULT); + +/* Handle command line modifier settings, sending any error messages to +stderr. We need to know the mode before modifying the context, and it is tidier +to do them all in the same way. */ + +outfile = stderr; +if ((arg_pattern != NULL && + !decode_modifiers((uint8_t *)arg_pattern, CTX_DEFPAT, &def_patctl, NULL)) || + (arg_subject != NULL && + !decode_modifiers((uint8_t *)arg_subject, CTX_DEFDAT, NULL, &def_datctl))) + { + yield = 1; + goto EXIT; + } + +/* Sort out the input and output files, defaulting to stdin/stdout. */ + +infile = stdin; +outfile = stdout; + +if (argc > 1 && strcmp(argv[op], "-") != 0) + { + infile = fopen(argv[op], INPUT_MODE); + if (infile == NULL) + { + printf("** Failed to open '%s': %s\n", argv[op], strerror(errno)); + yield = 1; + goto EXIT; + } + } + +#if defined(SUPPORT_LIBREADLINE) || defined(SUPPORT_LIBEDIT) +if (INTERACTIVE(infile)) using_history(); +#endif + +if (argc > 2) + { + outfile = fopen(argv[op+1], OUTPUT_MODE); + if (outfile == NULL) + { + printf("** Failed to open '%s': %s\n", argv[op+1], strerror(errno)); + yield = 1; + goto EXIT; + } + } + +/* Output a heading line unless quiet, then process input lines. */ + +if (!quiet) print_version(outfile); + +SET(compiled_code, NULL); + +#ifdef SUPPORT_PCRE2_8 +preg.re_pcre2_code = NULL; +preg.re_match_data = NULL; +#endif + +while (notdone) + { + uint8_t *p; + int rc = PR_OK; + BOOL expectdata = TEST(compiled_code, !=, NULL); +#ifdef SUPPORT_PCRE2_8 + expectdata |= preg.re_pcre2_code != NULL; +#endif + + if (extend_inputline(infile, buffer, expectdata? "data> " : " re> ") == NULL) + break; + if (!INTERACTIVE(infile)) fprintf(outfile, "%s", (char *)buffer); + fflush(outfile); + p = buffer; + + /* If we have a pattern set up for testing, or we are skipping after a + compile failure, a blank line terminates this test. */ + + if (expectdata || skipping) + { + while (isspace(*p)) p++; + if (*p == 0) + { +#ifdef SUPPORT_PCRE2_8 + if (preg.re_pcre2_code != NULL) + { + regfree(&preg); + preg.re_pcre2_code = NULL; + preg.re_match_data = NULL; + } +#endif /* SUPPORT_PCRE2_8 */ + if (TEST(compiled_code, !=, NULL)) + { + SUB1(pcre2_code_free, compiled_code); + SET(compiled_code, NULL); + } + skipping = FALSE; + setlocale(LC_CTYPE, "C"); + } + + /* Otherwise, if we are not skipping, and the line is not a data comment + line starting with "\=", process a data line. */ + + else if (!skipping && !(p[0] == '\\' && p[1] == '=' && isspace(p[2]))) + { + rc = process_data(); + } + } + + /* We do not have a pattern set up for testing. Lines starting with # are + either comments or special commands. Blank lines are ignored. Otherwise, the + line must start with a valid delimiter. It is then processed as a pattern + line. A copy of the pattern is left in pbuffer8 for use by callouts. Under + valgrind, make the unused part of the buffer undefined, to catch overruns. */ + + else if (*p == '#') + { + if (isspace(p[1]) || p[1] == '!' || p[1] == 0) continue; + rc = process_command(); + } + + else if (strchr("/!\"'`%&-=_:;,@~", *p) != NULL) + { + rc = process_pattern(); + dfa_matched = 0; + } + + else + { + while (isspace(*p)) p++; + if (*p != 0) + { + fprintf(outfile, "** Invalid pattern delimiter '%c' (x%x).\n", *buffer, + *buffer); + rc = PR_SKIP; + } + } + + if (rc == PR_SKIP && !INTERACTIVE(infile)) skipping = TRUE; + else if (rc == PR_ABEND) + { + fprintf(outfile, "** pcre2test run abandoned\n"); + yield = 1; + goto EXIT; + } + } + +/* Finish off a normal run. */ + +if (INTERACTIVE(infile)) fprintf(outfile, "\n"); + +if (showtotaltimes) + { + const char *pad = ""; + fprintf(outfile, "--------------------------------------\n"); + if (timeit > 0) + { + fprintf(outfile, "Total compile time %.4f milliseconds\n", + (((double)total_compile_time * 1000.0) / (double)timeit) / + (double)CLOCKS_PER_SEC); + if (total_jit_compile_time > 0) + fprintf(outfile, "Total JIT compile %.4f milliseconds\n", + (((double)total_jit_compile_time * 1000.0) / (double)timeit) / + (double)CLOCKS_PER_SEC); + pad = " "; + } + fprintf(outfile, "Total match time %s%.4f milliseconds\n", pad, + (((double)total_match_time * 1000.0) / (double)timeitm) / + (double)CLOCKS_PER_SEC); + } + + +EXIT: + +#if defined(SUPPORT_LIBREADLINE) || defined(SUPPORT_LIBEDIT) +if (infile != NULL && INTERACTIVE(infile)) clear_history(); +#endif + +if (infile != NULL && infile != stdin) fclose(infile); +if (outfile != NULL && outfile != stdout) fclose(outfile); + +free(buffer); +free(dbuffer); +free(pbuffer8); +free(dfa_workspace); +free((void *)locale_tables); +PCRE2_MATCH_DATA_FREE(match_data); +SUB1(pcre2_code_free, compiled_code); + +while(patstacknext-- > 0) + { + SET(compiled_code, patstack[patstacknext]); + SUB1(pcre2_code_free, compiled_code); + } + +PCRE2_JIT_FREE_UNUSED_MEMORY(general_context); +if (jit_stack != NULL) + { + PCRE2_JIT_STACK_FREE(jit_stack); + } + +#define FREECONTEXTS \ + G(pcre2_general_context_free_,BITS)(G(general_context,BITS)); \ + G(pcre2_general_context_free_,BITS)(G(general_context_copy,BITS)); \ + G(pcre2_compile_context_free_,BITS)(G(pat_context,BITS)); \ + G(pcre2_compile_context_free_,BITS)(G(default_pat_context,BITS)); \ + G(pcre2_match_context_free_,BITS)(G(dat_context,BITS)); \ + G(pcre2_match_context_free_,BITS)(G(default_dat_context,BITS)); \ + G(pcre2_convert_context_free_,BITS)(G(default_con_context,BITS)); \ + G(pcre2_convert_context_free_,BITS)(G(con_context,BITS)); + +#ifdef SUPPORT_PCRE2_8 +#undef BITS +#define BITS 8 +if (preg.re_pcre2_code != NULL) regfree(&preg); +FREECONTEXTS; +#endif + +#ifdef SUPPORT_PCRE2_16 +#undef BITS +#define BITS 16 +free(pbuffer16); +FREECONTEXTS; +#endif + +#ifdef SUPPORT_PCRE2_32 +#undef BITS +#define BITS 32 +free(pbuffer32); +FREECONTEXTS; +#endif + +#if defined(__VMS) + yield = SS$_NORMAL; /* Return values via DCL symbols */ +#endif + +return yield; +} + +/* End of pcre2test.c */ From 47e8b396b653c5f5830ce8fa9d942c30d9ec6d7e Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 3 Mar 2019 07:17:19 +0100 Subject: [PATCH 1737/2058] Update mxml-file.c --- phlib/mxml/mxml-file.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/phlib/mxml/mxml-file.c b/phlib/mxml/mxml-file.c index 4599506c209e..1ef0279efdf4 100644 --- a/phlib/mxml/mxml-file.c +++ b/phlib/mxml/mxml-file.c @@ -2000,7 +2000,7 @@ mxml_load_data( * Free the string buffer - we don't need it anymore... */ - free(buffer); + PhFree(buffer); /* * Find the top element and return it... @@ -2036,7 +2036,7 @@ mxml_load_data( mxmlDelete(first); - free(buffer); + PhFree(buffer); return (NULL); } From 7f8c384848e74b98b81b8483e68685dd4374695d Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 15 Mar 2019 20:34:22 +0100 Subject: [PATCH 1738/2058] Update ntrtl.h Co-Authored-By: Biswapriyo Nath --- phnt/include/ntrtl.h | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/phnt/include/ntrtl.h b/phnt/include/ntrtl.h index 68ab76c65ab3..4c85ffca9ab8 100644 --- a/phnt/include/ntrtl.h +++ b/phnt/include/ntrtl.h @@ -4099,6 +4099,13 @@ RtlWalkHeap( #define HeapDetailedFailureInformation 0x80000001 #define HeapSetDebuggingInformation 0x80000002 // q; s: HEAP_DEBUGGING_INFORMATION +typedef enum _HEAP_COMPATIBILITY_MODE +{ + HEAP_COMPATIBILITY_STANDARD = 0UL, + HEAP_COMPATIBILITY_LAL = 1UL, + HEAP_COMPATIBILITY_LFH = 2UL, +} HEAP_COMPATIBILITY_MODE; + typedef struct _PROCESS_HEAP_INFORMATION { ULONG_PTR ReserveSize; @@ -4124,8 +4131,11 @@ typedef struct _HEAP_EXTENDED_INFORMATION ULONG Level; PVOID CallbackRoutine; PVOID CallbackContext; - PROCESS_HEAP_INFORMATION ProcessHeapInformation; - HEAP_INFORMATION HeapInformation; + union + { + PROCESS_HEAP_INFORMATION ProcessHeapInformation; + HEAP_INFORMATION HeapInformation; + }; } HEAP_EXTENDED_INFORMATION, *PHEAP_EXTENDED_INFORMATION; // rev From 0b8486af42366b2cbc60a4f7032902e84cc29e1b Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 15 Mar 2019 20:39:10 +0100 Subject: [PATCH 1739/2058] Enable LFH mode for private heaps --- ProcessHacker/memsrch.c | 7 +++++++ ProcessHacker/phsvc/clapi.c | 9 ++++++++- phlib/global.c | 8 ++++++++ 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/ProcessHacker/memsrch.c b/ProcessHacker/memsrch.c index a9a36fabe112..87617dfed783 100644 --- a/ProcessHacker/memsrch.c +++ b/ProcessHacker/memsrch.c @@ -97,6 +97,13 @@ PVOID PhAllocateForMemorySearch( if (PhMemorySearchHeap) { + RtlSetHeapInformation( + PhMemorySearchHeap, + HeapCompatibilityInformation, + &(ULONG){ HEAP_COMPATIBILITY_LFH }, + sizeof(ULONG) + ); + // Don't use HEAP_NO_SERIALIZE - it's very slow on Vista and above. memory = RtlAllocateHeap(PhMemorySearchHeap, 0, Size); diff --git a/ProcessHacker/phsvc/clapi.c b/ProcessHacker/phsvc/clapi.c index 724571350472..ae229a216c64 100644 --- a/ProcessHacker/phsvc/clapi.c +++ b/ProcessHacker/phsvc/clapi.c @@ -116,6 +116,13 @@ NTSTATUS PhSvcConnectToServer( return STATUS_INSUFFICIENT_RESOURCES; } + RtlSetHeapInformation( + PhSvcClPortHeap, + HeapCompatibilityInformation, + &(ULONG){ HEAP_COMPATIBILITY_LFH }, + sizeof(ULONG) + ); + return status; } @@ -153,7 +160,7 @@ PVOID PhSvcpAllocateHeap( if (!memory) return NULL; - *Offset = (ULONG)((ULONG_PTR)memory - (ULONG_PTR)PhSvcClPortHeap); + *Offset = PtrToUlong(PTR_SUB_OFFSET(memory, PhSvcClPortHeap)); return memory; } diff --git a/phlib/global.c b/phlib/global.c index 35e28696be05..57fc87112822 100644 --- a/phlib/global.c +++ b/phlib/global.c @@ -76,6 +76,7 @@ NTSTATUS PhInitializePhLibEx( { PhApplicationName = ApplicationName; PhInstanceHandle = ImageBaseAddress; + PhHeapHandle = RtlCreateHeap( HEAP_GROWABLE | HEAP_CLASS_1, NULL, @@ -88,6 +89,13 @@ NTSTATUS PhInitializePhLibEx( if (!PhHeapHandle) return STATUS_INSUFFICIENT_RESOURCES; + RtlSetHeapInformation( + PhHeapHandle, + HeapCompatibilityInformation, + &(ULONG){ HEAP_COMPATIBILITY_LFH }, + sizeof(ULONG) + ); + PhInitializeWindowsVersion(); PhInitializeSystemInformation(); From f186d6b4a655da72635642af0710a6f25455c77b Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 15 Mar 2019 20:43:15 +0100 Subject: [PATCH 1740/2058] Update create service window icons --- ProcessHacker/srvcr.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/ProcessHacker/srvcr.c b/ProcessHacker/srvcr.c index f376ac96ac24..e582d69fc301 100644 --- a/ProcessHacker/srvcr.c +++ b/ProcessHacker/srvcr.c @@ -3,6 +3,7 @@ * service creation dialog * * Copyright (C) 2010-2013 wj32 + * Copyright (C) 2019 dmex * * This file is part of Process Hacker. * @@ -57,14 +58,14 @@ INT_PTR CALLBACK PhpCreateServiceDlgProc( { case WM_INITDIALOG: { + SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER))); + SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER))); + PhCenterWindow(hwndDlg, GetParent(hwndDlg)); - PhAddComboBoxStrings(GetDlgItem(hwndDlg, IDC_TYPE), PhServiceTypeStrings, - sizeof(PhServiceTypeStrings) / sizeof(WCHAR *)); - PhAddComboBoxStrings(GetDlgItem(hwndDlg, IDC_STARTTYPE), PhServiceStartTypeStrings, - sizeof(PhServiceStartTypeStrings) / sizeof(WCHAR *)); - PhAddComboBoxStrings(GetDlgItem(hwndDlg, IDC_ERRORCONTROL), PhServiceErrorControlStrings, - sizeof(PhServiceErrorControlStrings) / sizeof(WCHAR *)); + PhAddComboBoxStrings(GetDlgItem(hwndDlg, IDC_TYPE), PhServiceTypeStrings, RTL_NUMBER_OF(PhServiceTypeStrings)); + PhAddComboBoxStrings(GetDlgItem(hwndDlg, IDC_STARTTYPE), PhServiceStartTypeStrings, RTL_NUMBER_OF(PhServiceStartTypeStrings)); + PhAddComboBoxStrings(GetDlgItem(hwndDlg, IDC_ERRORCONTROL), PhServiceErrorControlStrings, RTL_NUMBER_OF(PhServiceErrorControlStrings)); PhSelectComboBoxString(GetDlgItem(hwndDlg, IDC_TYPE), L"Own Process", FALSE); PhSelectComboBoxString(GetDlgItem(hwndDlg, IDC_STARTTYPE), L"Demand Start", FALSE); @@ -90,11 +91,11 @@ INT_PTR CALLBACK PhpCreateServiceDlgProc( break; case IDOK: { - NTSTATUS status = 0; + NTSTATUS status = STATUS_SUCCESS; BOOLEAN success = FALSE; SC_HANDLE scManagerHandle; SC_HANDLE serviceHandle; - ULONG win32Result = 0; + ULONG win32Result = ERROR_SUCCESS; PPH_STRING serviceName; PPH_STRING serviceDisplayName; PPH_STRING serviceTypeString; From 3ca832adfeb7fcacd1c9f2edb43cdfe883d18974 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 15 Mar 2019 20:46:13 +0100 Subject: [PATCH 1741/2058] Add support for legacy v1 delayload imports (Fixes #390) --- phlib/include/mapimg.h | 10 ++++ phlib/mapimg.c | 127 ++++++++++++++++++++++++++++++++++------- 2 files changed, 117 insertions(+), 20 deletions(-) diff --git a/phlib/include/mapimg.h b/phlib/include/mapimg.h index 38865136966a..5f85b2528229 100644 --- a/phlib/include/mapimg.h +++ b/phlib/include/mapimg.h @@ -103,6 +103,15 @@ PhMappedImageRvaToVa( _Out_opt_ PIMAGE_SECTION_HEADER *Section ); +PHLIBAPI +PVOID +NTAPI +PhMappedImageVaToVa( + _In_ PPH_MAPPED_IMAGE MappedImage, + _In_ ULONG Va, + _Out_opt_ PIMAGE_SECTION_HEADER* Section + ); + PHLIBAPI BOOLEAN NTAPI @@ -243,6 +252,7 @@ PhGetMappedImageExportFunctionRemote( ); #define PH_MAPPED_IMAGE_DELAY_IMPORTS 0x1 +#define PH_MAPPED_IMAGE_DELAY_IMPORTS_V1 0x2 typedef struct _PH_MAPPED_IMAGE_IMPORTS { diff --git a/phlib/mapimg.c b/phlib/mapimg.c index ef931f521da1..aca26f9bc8b2 100644 --- a/phlib/mapimg.c +++ b/phlib/mapimg.c @@ -371,6 +371,43 @@ PVOID PhMappedImageRvaToVa( ); } +PVOID PhMappedImageVaToVa( + _In_ PPH_MAPPED_IMAGE MappedImage, + _In_ ULONG Va, + _Out_opt_ PIMAGE_SECTION_HEADER *Section + ) +{ + ULONG rva; + PIMAGE_SECTION_HEADER section; + + if (MappedImage->Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) + { + rva = PtrToUlong(PTR_SUB_OFFSET(Va, MappedImage->NtHeaders32->OptionalHeader.ImageBase)); + } + else if (MappedImage->Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) + { + rva = PtrToUlong(PTR_SUB_OFFSET(Va, MappedImage->NtHeaders->OptionalHeader.ImageBase)); + } + else + { + return NULL; + } + + section = PhMappedImageRvaToSection(MappedImage, rva); + + if (!section) + return NULL; + + if (Section) + *Section = section; + + return PTR_ADD_OFFSET( + MappedImage->ViewBase, + (rva - section->VirtualAddress) + + section->PointerToRawData + ); +} + BOOLEAN PhGetMappedImageSectionName( _In_ PIMAGE_SECTION_HEADER Section, _Out_writes_opt_z_(Count) PWSTR Buffer, @@ -1014,22 +1051,50 @@ NTSTATUS PhGetMappedImageImportDll( { ImportDll->DelayDescriptor = &Imports->DelayDescriptorTable[Index]; - ImportDll->Name = PhMappedImageRvaToVa( - ImportDll->MappedImage, - ImportDll->DelayDescriptor->DllNameRVA, - NULL - ); + // Backwards compatible support for legacy V1 delay imports. (dmex) + if (ImportDll->DelayDescriptor->Attributes.RvaBased == 0) + { + ImportDll->Flags |= PH_MAPPED_IMAGE_DELAY_IMPORTS_V1; + } + + if (!(ImportDll->Flags & PH_MAPPED_IMAGE_DELAY_IMPORTS_V1)) + { + ImportDll->Name = PhMappedImageRvaToVa( + ImportDll->MappedImage, + ImportDll->DelayDescriptor->DllNameRVA, + NULL + ); + } + else + { + ImportDll->Name = PhMappedImageVaToVa( + ImportDll->MappedImage, + ImportDll->DelayDescriptor->DllNameRVA, + NULL + ); + } if (!ImportDll->Name) return STATUS_INVALID_PARAMETER; // TODO: Probe the name. - ImportDll->LookupTable = PhMappedImageRvaToVa( - ImportDll->MappedImage, - ImportDll->DelayDescriptor->ImportNameTableRVA, - NULL - ); + if (!(ImportDll->Flags & PH_MAPPED_IMAGE_DELAY_IMPORTS_V1)) + { + ImportDll->LookupTable = PhMappedImageRvaToVa( + ImportDll->MappedImage, + ImportDll->DelayDescriptor->ImportNameTableRVA, + NULL + ); + } + else + { + ImportDll->LookupTable = PhMappedImageVaToVa( + ImportDll->MappedImage, + ImportDll->DelayDescriptor->ImportNameTableRVA, + NULL + ); + } } if (!ImportDll->LookupTable) @@ -1124,11 +1189,22 @@ NTSTATUS PhGetMappedImageImportEntry( } else { - importByName = PhMappedImageRvaToVa( - ImportDll->MappedImage, - entry.u1.AddressOfData, - NULL - ); + if (!(ImportDll->Flags & PH_MAPPED_IMAGE_DELAY_IMPORTS_V1)) + { + importByName = PhMappedImageRvaToVa( + ImportDll->MappedImage, + entry.u1.AddressOfData, + NULL + ); + } + else + { + importByName = PhMappedImageVaToVa( + ImportDll->MappedImage, + entry.u1.AddressOfData, + NULL + ); + } } } else if (ImportDll->MappedImage->Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) @@ -1147,11 +1223,22 @@ NTSTATUS PhGetMappedImageImportEntry( } else { - importByName = PhMappedImageRvaToVa( - ImportDll->MappedImage, - (ULONG)entry.u1.AddressOfData, - NULL - ); + if (!(ImportDll->Flags & PH_MAPPED_IMAGE_DELAY_IMPORTS_V1)) + { + importByName = PhMappedImageRvaToVa( + ImportDll->MappedImage, + (ULONG)entry.u1.AddressOfData, + NULL + ); + } + else + { + importByName = PhMappedImageVaToVa( + ImportDll->MappedImage, + (ULONG)entry.u1.AddressOfData, + NULL + ); + } } } else From 22bbf8f2a295729e3a4c7167bbac2bf6d3bfd047 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 16 Mar 2019 00:15:18 +0100 Subject: [PATCH 1742/2058] Fix dark themed edit controls --- ProcessHacker/searchbox.c | 41 +++++++++++++++--- phlib/theme.c | 90 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 123 insertions(+), 8 deletions(-) diff --git a/ProcessHacker/searchbox.c b/ProcessHacker/searchbox.c index 4e645806c560..7689f0ab8216 100644 --- a/ProcessHacker/searchbox.c +++ b/ProcessHacker/searchbox.c @@ -34,9 +34,10 @@ typedef struct _EDIT_CONTEXT ULONG Flags; struct { + ULONG ThemeSupport : 1; ULONG Hot : 1; ULONG Pushed : 1; - ULONG Spare : 30; + ULONG Spare : 29; }; }; @@ -170,6 +171,7 @@ VOID PhpSearchGetButtonRect( VOID PhpSearchDrawButton( _Inout_ PEDIT_CONTEXT Context, + _In_ RECT WindowRect, _In_ RECT ButtonRect ) { @@ -240,6 +242,28 @@ VOID PhpSearchDrawButton( DeleteObject(bufferBitmap); DeleteDC(bufferDc); + if (Context->ThemeSupport) // HACK + { + if (GetFocus() == Context->WindowHandle) + { + SetDCBrushColor(hdc, RGB(0x0, 0x66, 0xcc)); + SelectObject(hdc, GetStockObject(DC_BRUSH)); + PatBlt(hdc, WindowRect.left, WindowRect.top, 2, WindowRect.bottom - WindowRect.top, PATCOPY); + PatBlt(hdc, WindowRect.right - 2, WindowRect.top, 2, WindowRect.bottom - WindowRect.top, PATCOPY); + PatBlt(hdc, WindowRect.left, WindowRect.top, WindowRect.right - WindowRect.left, 2, PATCOPY); + PatBlt(hdc, WindowRect.left, WindowRect.bottom - 2, WindowRect.right - WindowRect.left, 2, PATCOPY); + } + else + { + SetDCBrushColor(hdc, RGB(65, 65, 65)); + SelectObject(hdc, GetStockObject(DC_BRUSH)); + PatBlt(hdc, WindowRect.left, WindowRect.top, 2, WindowRect.bottom - WindowRect.top, PATCOPY); + PatBlt(hdc, WindowRect.right - 2, WindowRect.top, 2, WindowRect.bottom - WindowRect.top, PATCOPY); + PatBlt(hdc, WindowRect.left, WindowRect.top, WindowRect.right - WindowRect.left, 2, PATCOPY); + PatBlt(hdc, WindowRect.left, WindowRect.bottom - 2, WindowRect.right - WindowRect.left, 2, PATCOPY); + } + } + ReleaseDC(Context->WindowHandle, hdc); } @@ -253,7 +277,7 @@ LRESULT CALLBACK PhpSearchWndSubclassProc( PEDIT_CONTEXT context; WNDPROC oldWndProc; - if (!(context = PhGetWindowContext(hWnd, 10))) + if (!(context = PhGetWindowContext(hWnd, SHRT_MAX))) return 0; oldWndProc = context->DefaultWindowProc; @@ -268,7 +292,7 @@ LRESULT CALLBACK PhpSearchWndSubclassProc( DeleteObject(context->WindowFont); SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)oldWndProc); - PhRemoveWindowContext(hWnd, 10); + PhRemoveWindowContext(hWnd, SHRT_MAX); PhFree(context); } break; @@ -288,6 +312,7 @@ LRESULT CALLBACK PhpSearchWndSubclassProc( case WM_NCPAINT: { RECT windowRect; + RECT buttonRect; // Let Windows handle the non-client defaults. CallWindowProc(oldWndProc, hWnd, uMsg, wParam, lParam); @@ -297,12 +322,13 @@ LRESULT CALLBACK PhpSearchWndSubclassProc( // Adjust the coordinates (start from 0,0). OffsetRect(&windowRect, -windowRect.left, -windowRect.top); + buttonRect = windowRect; // Get the position of the inserted button. - PhpSearchGetButtonRect(context, &windowRect); + PhpSearchGetButtonRect(context, &buttonRect); // Draw the button. - PhpSearchDrawButton(context, windowRect); + PhpSearchDrawButton(context, windowRect, buttonRect); } return 0; case WM_NCHITTEST: @@ -523,6 +549,7 @@ VOID PhCreateSearchControl( memset(context, 0, sizeof(EDIT_CONTEXT)); context->WindowHandle = WindowHandle; + context->ThemeSupport = !!PhGetIntegerSetting(L"EnableThemeSupport"); // HACK //PhpSearchInitializeTheme(context); PhpSearchInitializeImages(context); @@ -533,7 +560,7 @@ VOID PhCreateSearchControl( // Subclass the Edit control window procedure. context->DefaultWindowProc = (WNDPROC)GetWindowLongPtr(WindowHandle, GWLP_WNDPROC); - PhSetWindowContext(WindowHandle, 10, context); + PhSetWindowContext(WindowHandle, SHRT_MAX, context); SetWindowLongPtr(WindowHandle, GWLP_WNDPROC, (LONG_PTR)PhpSearchWndSubclassProc); // Initialize the theme parameters. @@ -689,4 +716,4 @@ HBITMAP PhLoadPngImageFromResource( DeleteObject(bitmapHandle); return NULL; -} \ No newline at end of file +} diff --git a/phlib/theme.c b/phlib/theme.c index 85349aa5b014..e13c898679b3 100644 --- a/phlib/theme.c +++ b/phlib/theme.c @@ -71,6 +71,12 @@ LRESULT CALLBACK PhpThemeWindowGroupBoxSubclassProc( _In_ WPARAM wParam, _In_ LPARAM lParam ); +LRESULT CALLBACK PhpThemeWindowEditSubclassProc( + _In_ HWND WindowHandle, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); LRESULT CALLBACK PhpThemeWindowTabControlWndSubclassProc( _In_ HWND WindowHandle, _In_ UINT uMsg, @@ -334,6 +340,25 @@ VOID PhInitializeThemeWindowGroupBox( InvalidateRect(GroupBoxHandle, NULL, FALSE); } +VOID PhInitializeThemeWindowEditControl( + _In_ HWND EditControlHandle + ) +{ + WNDPROC editControlWindowProc; + + // HACK: The searchbox control does its own themed drawing and it uses the + // same window context value so we know when to ignore theming. + if (PhGetWindowContext(EditControlHandle, SHRT_MAX)) + return; + + editControlWindowProc = (WNDPROC)GetWindowLongPtr(EditControlHandle, GWLP_WNDPROC); + PhSetWindowContext(EditControlHandle, SHRT_MAX, editControlWindowProc); + SetWindowLongPtr(EditControlHandle, GWLP_WNDPROC, (LONG_PTR)PhpThemeWindowEditSubclassProc); + + InvalidateRect(EditControlHandle, NULL, FALSE); + //SetWindowPos(EditControlHandle, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_DRAWFRAME); +} + BOOLEAN CALLBACK PhpThemeWindowEnumChildWindows( _In_ HWND WindowHandle, _In_opt_ PVOID Context @@ -377,7 +402,7 @@ BOOLEAN CALLBACK PhpThemeWindowEnumChildWindows( } else if (PhEqualStringZ(windowClassName, L"Edit", TRUE)) { - NOTHING; + PhInitializeThemeWindowEditControl(WindowHandle); } else if (PhEqualStringZ(windowClassName, L"ScrollBar", FALSE)) { @@ -1647,6 +1672,69 @@ LRESULT CALLBACK PhpThemeWindowGroupBoxSubclassProc( return CallWindowProc(oldWndProc, WindowHandle, uMsg, wParam, lParam); } +LRESULT CALLBACK PhpThemeWindowEditSubclassProc( + _In_ HWND WindowHandle, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + WNDPROC oldWndProc; + + if (!(oldWndProc = PhGetWindowContext(WindowHandle, SHRT_MAX))) + return FALSE; + + switch (uMsg) + { + case WM_DESTROY: + { + SetWindowLongPtr(WindowHandle, GWLP_WNDPROC, (LONG_PTR)oldWndProc); + PhRemoveWindowContext(WindowHandle, SHRT_MAX); + } + break; + case WM_NCPAINT: + { + HDC hdc; + ULONG flags; + RECT windowRect; + HRGN updateRegion; + + updateRegion = (HRGN)wParam; + + if (updateRegion == (HRGN)1) // HRGN_FULL + updateRegion = NULL; + + flags = DCX_WINDOW | DCX_LOCKWINDOWUPDATE | 0x10000; + + if (updateRegion) + flags |= DCX_INTERSECTRGN | 0x40000; + + if (hdc = GetDCEx(WindowHandle, updateRegion, flags)) + { + GetWindowRect(WindowHandle, &windowRect); + OffsetRect(&windowRect, -windowRect.left, -windowRect.top); + + if (GetFocus() == WindowHandle) + { + SetDCBrushColor(hdc, GetSysColor(COLOR_HOTLIGHT)); + FrameRect(hdc, &windowRect, GetStockObject(DC_BRUSH)); + } + else + { + SetDCBrushColor(hdc, RGB(65, 65, 65)); + FrameRect(hdc, &windowRect, GetStockObject(DC_BRUSH)); + } + + ReleaseDC(WindowHandle, hdc); + return 0; + } + } + break; + } + + return CallWindowProc(oldWndProc, WindowHandle, uMsg, wParam, lParam); +} + LRESULT CALLBACK PhpThemeWindowTabControlWndSubclassProc( _In_ HWND WindowHandle, _In_ UINT uMsg, From d2368072fcf6695279781993b5fc4a697becddeb Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 16 Mar 2019 00:22:08 +0100 Subject: [PATCH 1743/2058] Fix warning --- phlib/mapimg.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/phlib/mapimg.c b/phlib/mapimg.c index aca26f9bc8b2..8eecc0e0ad23 100644 --- a/phlib/mapimg.c +++ b/phlib/mapimg.c @@ -401,11 +401,10 @@ PVOID PhMappedImageVaToVa( if (Section) *Section = section; - return PTR_ADD_OFFSET( - MappedImage->ViewBase, - (rva - section->VirtualAddress) + + return PTR_ADD_OFFSET(MappedImage->ViewBase, PTR_ADD_OFFSET( + PTR_SUB_OFFSET(rva, section->VirtualAddress), section->PointerToRawData - ); + )); } BOOLEAN PhGetMappedImageSectionName( From 25527dc10573d8fee201696d1fb56ce77d8ec4f5 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 16 Mar 2019 00:23:46 +0100 Subject: [PATCH 1744/2058] HardwareDevices: Update common smart attributes --- plugins/HardwareDevices/devices.h | 4 +++- plugins/HardwareDevices/storage.c | 6 +++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/plugins/HardwareDevices/devices.h b/plugins/HardwareDevices/devices.h index b89644816b91..3cdf0497fd4c 100644 --- a/plugins/HardwareDevices/devices.h +++ b/plugins/HardwareDevices/devices.h @@ -765,7 +765,9 @@ typedef enum _SMART_ATTRIBUTE_ID SMART_ATTRIBUTE_ID_TOTAL_LBA_READ = 0xF2, // TODO: Add values 243-249 SMART_ATTRIBUTE_ID_READ_ERROR_RETY_RATE = 0xFA, - // TODO: Add values 251-253 + SMART_ATTRIBUTE_ID_MIN_SPARES_REMAINING = 0xFB, + SMART_ATTRIBUTE_ID_NEWLY_ADDED_BAD_FLASH_BLOCK = 0xFC, + // TODO: Add value 253 SMART_ATTRIBUTE_ID_FREE_FALL_PROTECTION = 0xFE, } SMART_ATTRIBUTE_ID; diff --git a/plugins/HardwareDevices/storage.c b/plugins/HardwareDevices/storage.c index f2a48c403b53..d38e8c70e183 100644 --- a/plugins/HardwareDevices/storage.c +++ b/plugins/HardwareDevices/storage.c @@ -698,7 +698,7 @@ NTSTATUS DiskDriveQueryImminentFailure( for (UCHAR i = 0; i < 30; ++i) { - PSMART_ATTRIBUTE attribute = (PSMART_ATTRIBUTE)(storagePredictFailure.VendorSpecific + i * sizeof(SMART_ATTRIBUTE) + SMART_HEADER_SIZE); + PSMART_ATTRIBUTE attribute = (PSMART_ATTRIBUTE)PTR_ADD_OFFSET(storagePredictFailure.VendorSpecific, i * sizeof(SMART_ATTRIBUTE) + SMART_HEADER_SIZE); // Attribute values 0x00, 0xFE, 0xFF are invalid. // There is no requirement that attributes be in any particular order. @@ -1501,6 +1501,10 @@ PWSTR SmartAttributeGetText( return L"Media Wearout Indicator"; case SMART_ATTRIBUTE_ID_SSD_ERASE_COUNT: return L"Erase count"; + case SMART_ATTRIBUTE_ID_MIN_SPARES_REMAINING: + return L"Minimum Spares Remaining"; + case SMART_ATTRIBUTE_ID_NEWLY_ADDED_BAD_FLASH_BLOCK: + return L"Newly Added Bad Flash Block"; } return L"BUG BUG BUG"; From 44c5ae7cd3d8fcfd5387437b0f4db305f910c668 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 16 Mar 2019 05:03:08 +0100 Subject: [PATCH 1745/2058] Fix sysinfo window dark frame support --- ProcessHacker/sysinfo.c | 1 + phlib/include/guisup.h | 7 +++++++ phlib/theme.c | 20 ++++++++++++++++++++ 3 files changed, 28 insertions(+) diff --git a/ProcessHacker/sysinfo.c b/ProcessHacker/sysinfo.c index 70387905cae6..5723a49f8d4f 100644 --- a/ProcessHacker/sysinfo.c +++ b/ProcessHacker/sysinfo.c @@ -464,6 +464,7 @@ VOID PhSipOnInitDialog( } PhRegisterWindowCallback(PhSipWindow, PH_PLUGIN_WINDOW_EVENT_TYPE_TOPMOST, NULL); + PhInitializeThemeWindowFrame(PhSipWindow); PhSipOnSize(); PhSipOnUserMessage(SI_MSG_SYSINFO_UPDATE, 0, 0); diff --git a/phlib/include/guisup.h b/phlib/include/guisup.h index b31a5ab17f21..44cebad04a89 100644 --- a/phlib/include/guisup.h +++ b/phlib/include/guisup.h @@ -916,6 +916,13 @@ PhReInitializeWindowTheme( _In_ HWND WindowHandle ); +PHLIBAPI +VOID +NTAPI +PhInitializeThemeWindowFrame( + _In_ HWND WindowHandle + ); + PHLIBAPI BOOLEAN NTAPI diff --git a/phlib/theme.c b/phlib/theme.c index e13c898679b3..69bfea64ccdb 100644 --- a/phlib/theme.c +++ b/phlib/theme.c @@ -274,6 +274,26 @@ VOID PhReInitializeWindowTheme( InvalidateRect(WindowHandle, NULL, FALSE); } +VOID PhInitializeThemeWindowFrame( + _In_ HWND WindowHandle + ) +{ + if (!PhpThemeEnable) + return; + + switch (PhpThemeColorMode) + { + case 0: // New colors + if (WindowsVersion >= WINDOWS_10_RS5) + RemoveProp(WindowHandle, L"UseImmersiveDarkModeColors"); + break; + case 1: // Old colors + if (WindowsVersion >= WINDOWS_10_RS5) + SetProp(WindowHandle, L"UseImmersiveDarkModeColors", (HANDLE)TRUE); + break; + } +} + VOID PhInitializeThemeWindowHeader( _In_ HWND HeaderWindow ) From 0bfa9c8a936d1e84bb7248de060fe6e120a544b2 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 16 Mar 2019 05:03:53 +0100 Subject: [PATCH 1746/2058] Add missing ChpeImage flag --- phnt/include/ntldr.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/phnt/include/ntldr.h b/phnt/include/ntldr.h index c9a7dfdc926a..0859374439cf 100644 --- a/phnt/include/ntldr.h +++ b/phnt/include/ntldr.h @@ -180,7 +180,8 @@ typedef struct _LDR_DATA_TABLE_ENTRY ULONG CorImage : 1; ULONG DontRelocate : 1; ULONG CorILOnly : 1; - ULONG ReservedFlags5 : 3; + ULONG ChpeImage : 1; + ULONG ReservedFlags5 : 2; ULONG Redirected : 1; ULONG ReservedFlags6 : 2; ULONG CompatDatabaseProcessed : 1; From 23be1db878e391de85416ed932bd273f5627003b Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 16 Mar 2019 20:23:11 +0100 Subject: [PATCH 1747/2058] peview: Fix regression/crash for image load config --- tools/peview/ldprp.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/tools/peview/ldprp.c b/tools/peview/ldprp.c index f9ec7a00403e..f0757cf1a7f8 100644 --- a/tools/peview/ldprp.c +++ b/tools/peview/ldprp.c @@ -151,9 +151,12 @@ VOID PvpAddPeEnclaveConfig( PIMAGE_LOAD_CONFIG_DIRECTORY32 imageConfig32 = ImageConfig; PIMAGE_ENCLAVE_CONFIG32 enclaveConfig; - enclaveConfig = PhMappedImageRvaToVa( + if (!RTL_CONTAINS_FIELD(imageConfig32, imageConfig32->Size, EnclaveConfigurationPointer)) + return; + + enclaveConfig = PhMappedImageVaToVa( &PvMappedImage, - PtrToUlong(PTR_SUB_OFFSET(imageConfig32->EnclaveConfigurationPointer, PvMappedImage.NtHeaders32->OptionalHeader.ImageBase)), + (ULONG)imageConfig32->EnclaveConfigurationPointer, NULL ); @@ -176,9 +179,12 @@ VOID PvpAddPeEnclaveConfig( PIMAGE_LOAD_CONFIG_DIRECTORY64 imageConfig64 = ImageConfig; PIMAGE_ENCLAVE_CONFIG64 enclaveConfig; - enclaveConfig = PhMappedImageRvaToVa( + if (!RTL_CONTAINS_FIELD(imageConfig64, imageConfig64->Size, EnclaveConfigurationPointer)) + return; + + enclaveConfig = PhMappedImageVaToVa( &PvMappedImage, - PtrToUlong(PTR_SUB_OFFSET(imageConfig64->EnclaveConfigurationPointer, PvMappedImage.NtHeaders->OptionalHeader.ImageBase)), + (ULONG)imageConfig64->EnclaveConfigurationPointer, NULL ); From 343c05a4318f0e38ea38f8ee3f4bb53c4c461381 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 16 Mar 2019 20:24:11 +0100 Subject: [PATCH 1748/2058] Add ProcessSideChannelIsolationPolicy support (Fixes #382) --- ProcessHacker/procmtgn.c | 51 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) diff --git a/ProcessHacker/procmtgn.c b/ProcessHacker/procmtgn.c index 72e03c74c8cc..b1e9a6ce75ed 100644 --- a/ProcessHacker/procmtgn.c +++ b/ProcessHacker/procmtgn.c @@ -119,7 +119,7 @@ NTSTATUS PhGetProcessMitigationPolicy( COPY_PROCESS_MITIGATION_POLICY(SystemCallFilter, PROCESS_MITIGATION_SYSTEM_CALL_FILTER_POLICY); // REDSTONE3 COPY_PROCESS_MITIGATION_POLICY(PayloadRestriction, PROCESS_MITIGATION_PAYLOAD_RESTRICTION_POLICY); COPY_PROCESS_MITIGATION_POLICY(ChildProcess, PROCESS_MITIGATION_CHILD_PROCESS_POLICY); - COPY_PROCESS_MITIGATION_POLICY(SideChannelIsolation, PROCESS_MITIGATION_CHILD_PROCESS_POLICY); + COPY_PROCESS_MITIGATION_POLICY(SideChannelIsolation, PROCESS_MITIGATION_SIDE_CHANNEL_ISOLATION_POLICY); return status; } @@ -479,6 +479,55 @@ BOOLEAN PhDescribeProcessMitigationPolicy( } } break; + case ProcessSideChannelIsolationPolicy: + { + PPROCESS_MITIGATION_SIDE_CHANNEL_ISOLATION_POLICY data = Data; + + if (data->SmtBranchTargetIsolation) + { + if (ShortDescription) + *ShortDescription = PhCreateString(L"SMT-thread branch target isolation"); + + if (LongDescription) + *LongDescription = PhCreateString(L"Branch target pollution cross-SMT-thread in user mode is enabled.\r\n"); + + result = TRUE; + } + + if (data->IsolateSecurityDomain) + { + if (ShortDescription) + *ShortDescription = PhCreateString(L"Distinct security domain"); + + if (LongDescription) + *LongDescription = PhCreateString(L"Isolated security domain is enabled.\r\n"); + + result = TRUE; + } + + if (data->DisablePageCombine) + { + if (ShortDescription) + *ShortDescription = PhCreateString(L"Restricted page combining"); + + if (LongDescription) + *LongDescription = PhCreateString(L"Disables all page combining for this process.\r\n"); + + result = TRUE; + } + + if (data->SpeculativeStoreBypassDisable) + { + if (ShortDescription) + *ShortDescription = PhCreateString(L"Restricted page combining"); + + if (LongDescription) + *LongDescription = PhCreateString(L"Memory Disambiguation is enabled for this process.\r\n"); + + result = TRUE; + } + } + break; default: result = FALSE; } From 5c53ea5f35281f11b8f8cf386b203b8355380330 Mon Sep 17 00:00:00 2001 From: Gisle Vanem Date: Sun, 17 Mar 2019 18:28:49 +0100 Subject: [PATCH 1749/2058] Fix "NaN" in network adapter utilisation (#392) When calculation the adapter utilisation for an adapter with "interfaceLinkSpeed == 0", ensure we do not divide by zero. --- plugins/HardwareDevices/netdetails.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/plugins/HardwareDevices/netdetails.c b/plugins/HardwareDevices/netdetails.c index 97f1f5b58f69..a395ed278c57 100644 --- a/plugins/HardwareDevices/netdetails.c +++ b/plugins/HardwareDevices/netdetails.c @@ -454,7 +454,15 @@ VOID NetAdapterUpdateDetails( PhSetListViewSubItem(Context->ListViewHandle, NETADAPTER_DETAILS_INDEX_TOTAL, 1, PhaFormatSize(interfaceStats.ifHCInOctets + interfaceStats.ifHCOutOctets, -1)->Buffer); PhSetListViewSubItem(Context->ListViewHandle, NETADAPTER_DETAILS_INDEX_SENDING, 1, interfaceXmitSpeed != 0 ? PhaFormatString(L"%s/s", PhaFormatSize(interfaceXmitSpeed, -1)->Buffer)->Buffer : L""); PhSetListViewSubItem(Context->ListViewHandle, NETADAPTER_DETAILS_INDEX_RECEIVING, 1, interfaceRcvSpeed != 0 ? PhaFormatString(L"%s/s", PhaFormatSize(interfaceRcvSpeed, -1)->Buffer)->Buffer : L""); - PhSetListViewSubItem(Context->ListViewHandle, NETADAPTER_DETAILS_INDEX_UTILIZATION, 1, PhaFormatString(L"%.2f%%", (FLOAT)(interfaceRcvSpeed + interfaceXmitSpeed) / (interfaceLinkSpeed / BITS_IN_ONE_BYTE) * 100)->Buffer); + + if (interfaceLinkSpeed > 0) + { + FLOAT utilization = (FLOAT) (interfaceRcvSpeed + interfaceXmitSpeed) / (interfaceLinkSpeed / BITS_IN_ONE_BYTE); + + PhSetListViewSubItem(Context->ListViewHandle, NETADAPTER_DETAILS_INDEX_UTILIZATION, 1, PhaFormatString(L"%.2f%%", 100.0*utilization)->Buffer); + } + else + PhSetListViewSubItem(Context->ListViewHandle, NETADAPTER_DETAILS_INDEX_UTILIZATION, 1, L"N/A"); PhSetListViewSubItem(Context->ListViewHandle, NETADAPTER_DETAILS_INDEX_UNICAST_SENTPKTS, 1, PhaFormatUInt64(interfaceStats.ifHCOutUcastPkts, TRUE)->Buffer); PhSetListViewSubItem(Context->ListViewHandle, NETADAPTER_DETAILS_INDEX_UNICAST_RECVPKTS, 1, PhaFormatUInt64(interfaceStats.ifHCInUcastPkts, TRUE)->Buffer); From 13be58b8941dc306e11e6ba338a8ca8764c4d77c Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 22 Mar 2019 22:47:22 +0100 Subject: [PATCH 1750/2058] Fix PhShowMessage2 dialog location issues --- phlib/util.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/phlib/util.c b/phlib/util.c index 30940b2c6383..a71955e1a50e 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -455,7 +455,7 @@ INT PhShowMessage2( if (!message) return -1; - config.dwFlags = TDF_ALLOW_DIALOG_CANCELLATION | ((hWnd && IsWindowVisible(hWnd)) ? TDF_POSITION_RELATIVE_TO_WINDOW : 0) | TDF_SIZE_TO_CONTENT; + config.dwFlags = TDF_ALLOW_DIALOG_CANCELLATION | ((hWnd && IsWindowVisible(hWnd) && !IsMinimized(hWnd)) ? TDF_POSITION_RELATIVE_TO_WINDOW : 0); config.dwCommonButtons = Buttons; config.hwndParent = hWnd; config.pszWindowTitle = PhApplicationName; @@ -628,7 +628,7 @@ BOOLEAN PhShowConfirmMessage( config.hwndParent = hWnd; config.hInstance = PhInstanceHandle; - config.dwFlags = TDF_ALLOW_DIALOG_CANCELLATION | ((hWnd && IsWindowVisible(hWnd)) ? TDF_POSITION_RELATIVE_TO_WINDOW : 0); + config.dwFlags = TDF_ALLOW_DIALOG_CANCELLATION | ((hWnd && IsWindowVisible(hWnd) && !IsMinimized(hWnd)) ? TDF_POSITION_RELATIVE_TO_WINDOW : 0); config.pszWindowTitle = PhApplicationName; config.pszMainIcon = Warning ? TD_WARNING_ICON : TD_INFORMATION_ICON; config.pszMainInstruction = PhaConcatStrings(3, L"Do you want to ", action->Buffer, L"?")->Buffer; From af043c47d4fd4e87bf458a80bcf5ea2633490eb5 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 22 Mar 2019 22:47:48 +0100 Subject: [PATCH 1751/2058] Fix THREAD_UMS_INFORMATION type --- phnt/include/ntpsapi.h | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/phnt/include/ntpsapi.h b/phnt/include/ntpsapi.h index d459ca453e52..ebe8980ee3e7 100644 --- a/phnt/include/ntpsapi.h +++ b/phnt/include/ntpsapi.h @@ -1016,9 +1016,16 @@ typedef struct _THREAD_UMS_INFORMATION THREAD_UMS_INFORMATION_COMMAND Command; PRTL_UMS_COMPLETION_LIST CompletionList; PRTL_UMS_CONTEXT UmsContext; - ULONG Flags; - ULONG IsUmsSchedulerThread; - ULONG IsUmsWorkerThread; + union + { + ULONG Flags; + struct + { + ULONG IsUmsSchedulerThread : 1; + ULONG IsUmsWorkerThread : 1; + ULONG SpareBits : 30; + }; + }; } THREAD_UMS_INFORMATION, *PTHREAD_UMS_INFORMATION; // private From 2edfa639c1a5b9dce87f5526d2dea3dc85851149 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 22 Mar 2019 22:49:09 +0100 Subject: [PATCH 1752/2058] HardwareDevices: Fix window icon --- plugins/HardwareDevices/diskdetails.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/HardwareDevices/diskdetails.c b/plugins/HardwareDevices/diskdetails.c index 24551f71c568..c71d5cb01fa6 100644 --- a/plugins/HardwareDevices/diskdetails.c +++ b/plugins/HardwareDevices/diskdetails.c @@ -607,6 +607,8 @@ INT_PTR CALLBACK DiskDriveFileSystemDetailsDlgProc( context->ListViewHandle = GetDlgItem(hwndDlg, IDC_DETAILS_LIST); PhCenterWindow(GetParent(hwndDlg), NULL); // HACK (dmex) + SendMessage(GetParent(hwndDlg), WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhInstanceHandle, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); + SendMessage(GetParent(hwndDlg), WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhInstanceHandle, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); if (!!PhGetIntegerSetting(L"EnableThemeSupport")) // TODO: Required for compat (dmex) PhInitializeWindowTheme(GetParent(hwndDlg), !!PhGetIntegerSetting(L"EnableThemeSupport")); From a69ada036ab35536c7c05a64398e6599a9114a90 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 24 Mar 2019 01:46:16 +0100 Subject: [PATCH 1753/2058] Force system shutdown/reboot while holding the CTL key and selecting the menu --- ProcessHacker/actions.c | 66 +++++++++++++++++++++++++++++++---------- 1 file changed, 50 insertions(+), 16 deletions(-) diff --git a/ProcessHacker/actions.c b/ProcessHacker/actions.c index 608528f26261..452aeab4b7d2 100644 --- a/ProcessHacker/actions.c +++ b/ProcessHacker/actions.c @@ -520,7 +520,7 @@ BOOLEAN PhUiLockComputer( if (LockWorkStation()) return TRUE; else - PhShowStatus(hWnd, L"Unable to lock the computer", 0, GetLastError()); + PhShowStatus(hWnd, L"Unable to lock the computer.", 0, GetLastError()); return FALSE; } @@ -532,7 +532,7 @@ BOOLEAN PhUiLogoffComputer( if (ExitWindowsEx(EWX_LOGOFF, 0)) return TRUE; else - PhShowStatus(hWnd, L"Unable to log off the computer", 0, GetLastError()); + PhShowStatus(hWnd, L"Unable to log off the computer.", 0, GetLastError()); return FALSE; } @@ -551,7 +551,7 @@ BOOLEAN PhUiSleepComputer( ))) return TRUE; else - PhShowStatus(hWnd, L"Unable to sleep the computer", status, 0); + PhShowStatus(hWnd, L"Unable to sleep the computer.", status, 0); return FALSE; } @@ -570,7 +570,7 @@ BOOLEAN PhUiHibernateComputer( ))) return TRUE; else - PhShowStatus(hWnd, L"Unable to hibernate the computer", status, 0); + PhShowStatus(hWnd, L"Unable to hibernate the computer.", status, 0); return FALSE; } @@ -580,6 +580,13 @@ BOOLEAN PhUiRestartComputer( _In_ ULONG Flags ) { + NTSTATUS status; + BOOLEAN forceShutdown; + + // Taskmgr prior to Windows 8 included a feature to force shutdown via NT instead of CSRSS + // when holding the control key. (dmex) + forceShutdown = !!(GetKeyState(VK_CONTROL) < 0); + if (!PhGetIntegerSetting(L"EnableWarnings") || PhShowConfirmMessage( hWnd, L"restart", @@ -588,10 +595,20 @@ BOOLEAN PhUiRestartComputer( FALSE )) { - if (ExitWindowsEx(EWX_REBOOT | Flags, 0)) - return TRUE; + if (forceShutdown) + { + if (!NT_SUCCESS(status = NtShutdownSystem(ShutdownReboot))) + { + PhShowStatus(hWnd, L"Unable to restart the computer.", status, 0); + } + } else - PhShowStatus(hWnd, L"Unable to restart the computer", 0, GetLastError()); + { + if (ExitWindowsEx(EWX_REBOOT | Flags, 0)) + return TRUE; + else + PhShowStatus(hWnd, L"Unable to restart the computer.", 0, GetLastError()); + } } return FALSE; @@ -602,6 +619,13 @@ BOOLEAN PhUiShutdownComputer( _In_ ULONG Flags ) { + NTSTATUS status; + BOOLEAN forceShutdown; + + // Taskmgr prior to Windows 8 included a feature to force shutdown via NT instead of CSRSS + // when holding the control key. (dmex) + forceShutdown = !!(GetKeyState(VK_CONTROL) < 0); + if (!PhGetIntegerSetting(L"EnableWarnings") || PhShowConfirmMessage( hWnd, L"shut down", @@ -610,17 +634,27 @@ BOOLEAN PhUiShutdownComputer( FALSE )) { - if (ExitWindowsEx(EWX_POWEROFF | Flags, 0)) + if (forceShutdown) { - return TRUE; - } - else if (ExitWindowsEx(EWX_SHUTDOWN | Flags, 0)) - { - return TRUE; + if (!NT_SUCCESS(status = NtShutdownSystem(ShutdownPowerOff))) + { + PhShowStatus(hWnd, L"Unable to shut down the computer.", status, 0); + } } else { - PhShowStatus(hWnd, L"Unable to shut down the computer.", 0, GetLastError()); + if (ExitWindowsEx(EWX_POWEROFF | Flags, 0)) + { + return TRUE; + } + else if (ExitWindowsEx(EWX_SHUTDOWN | Flags, 0)) + { + return TRUE; + } + else + { + PhShowStatus(hWnd, L"Unable to shut down the computer.", 0, GetLastError()); + } } } @@ -637,7 +671,7 @@ BOOLEAN PhUiConnectSession( PPH_STRING oldSelectedChoice = NULL; // Try once with no password. - if (WinStationConnectW(NULL, SessionId, -1, L"", TRUE)) + if (WinStationConnectW(NULL, SessionId, LOGONID_CURRENT, L"", TRUE)) return TRUE; while (PhaChoiceDialog( @@ -661,7 +695,7 @@ BOOLEAN PhUiConnectSession( oldSelectedChoice = selectedChoice; - if (WinStationConnectW(NULL, SessionId, -1, selectedChoice->Buffer, TRUE)) + if (WinStationConnectW(NULL, SessionId, LOGONID_CURRENT, selectedChoice->Buffer, TRUE)) { success = TRUE; break; From 75087dae5c7410eddb23c9272e705ecc9577cc39 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 31 Mar 2019 01:10:45 +0100 Subject: [PATCH 1754/2058] Add PhOpenProcessTokenPublic, Export PhQueryTokenVariableSize --- ProcessHacker/ProcessHacker.def | 2 ++ phlib/include/phnative.h | 9 +++++++++ phlib/native.c | 14 ++++++++++++++ 3 files changed, 25 insertions(+) diff --git a/ProcessHacker/ProcessHacker.def b/ProcessHacker/ProcessHacker.def index ba796b4944f4..83c926d6007f 100644 --- a/ProcessHacker/ProcessHacker.def +++ b/ProcessHacker/ProcessHacker.def @@ -298,10 +298,12 @@ EXPORTS PhOpenProcess = PhOpenProcessPublic PhOpenThread = PhOpenThreadPublic PhOpenThreadProcess + PhOpenProcessToken = PhOpenProcessTokenPublic PhPeekNamedPipe PhQueryFullAttributesFileWin32 PhQueryKey PhQueryValueKey + PhQueryTokenVariableSize PhResolveDevicePrefix PhSetFileSize PhSetObjectSecurity diff --git a/phlib/include/phnative.h b/phlib/include/phnative.h index 422f45b1c29a..bac192dbd7c9 100644 --- a/phlib/include/phnative.h +++ b/phlib/include/phnative.h @@ -119,6 +119,15 @@ PhOpenProcessToken( _Out_ PHANDLE TokenHandle ); +PHLIBAPI +NTSTATUS +NTAPI +PhOpenProcessTokenPublic( + _In_ HANDLE ProcessHandle, + _In_ ACCESS_MASK DesiredAccess, + _Out_ PHANDLE TokenHandle + ); + PHLIBAPI NTSTATUS NTAPI diff --git a/phlib/native.c b/phlib/native.c index 2c22432dc6bb..ea18d7c8eaf2 100644 --- a/phlib/native.c +++ b/phlib/native.c @@ -356,6 +356,20 @@ NTSTATUS PhOpenProcessToken( return status; } +/** Limited API for untrusted/external code. */ +NTSTATUS PhOpenProcessTokenPublic( + _In_ HANDLE ProcessHandle, + _In_ ACCESS_MASK DesiredAccess, + _Out_ PHANDLE TokenHandle + ) +{ + return NtOpenProcessToken( + ProcessHandle, + DesiredAccess, + TokenHandle + ); +} + NTSTATUS PhGetObjectSecurity( _In_ HANDLE Handle, _In_ SECURITY_INFORMATION SecurityInformation, From cbf0576c9873de63bf8394f697777efc406cf043 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 31 Mar 2019 01:14:08 +0100 Subject: [PATCH 1755/2058] Fix some SAL warnings --- ProcessHacker/anawait.c | 2 +- ProcessHacker/findobj.c | 5 ++++- ProcessHacker/runas.c | 18 +++++++++++------- phlib/basesup.c | 18 +++++++++--------- phlib/include/seceditp.h | 2 +- phlib/util.c | 14 +++++++------- 6 files changed, 33 insertions(+), 26 deletions(-) diff --git a/ProcessHacker/anawait.c b/ProcessHacker/anawait.c index 815742f042b0..8fda48493b59 100644 --- a/ProcessHacker/anawait.c +++ b/ProcessHacker/anawait.c @@ -999,7 +999,7 @@ static PPH_STRING PhpaGetSendMessageReceiver( return PhaFormatString(L"Window 0x%Ix (%s): %s \"%s\"", windowHandle, clientIdName->Buffer, windowClass, PhGetStringOrEmpty(windowText)); } -static PPH_STRING PhpaGetAlpcInformation( +PPH_STRING PhpaGetAlpcInformation( _In_ HANDLE ThreadId ) { diff --git a/ProcessHacker/findobj.c b/ProcessHacker/findobj.c index 7551d9fcfb1e..fb07e9d65ad7 100644 --- a/ProcessHacker/findobj.c +++ b/ProcessHacker/findobj.c @@ -726,7 +726,10 @@ VOID PhpFindObjectAddResultEntries( PhPrintPointer(objectNode->ObjectString, searchResult->Object); } - PhDereferenceObject(processItem); + if (processItem) + { + PhDereferenceObject(processItem); + } } Context->SearchResultsAddIndex = i; diff --git a/ProcessHacker/runas.c b/ProcessHacker/runas.c index c76a9f24b0bc..9c4c4c9bc8b4 100644 --- a/ProcessHacker/runas.c +++ b/ProcessHacker/runas.c @@ -273,7 +273,7 @@ BOOLEAN PhpInitializeNetApi(VOID) NetApiBufferFree_I = PhGetDllBaseProcedureAddress(netapiModuleHandle, "NetApiBufferFree", 0); } - if (!NetUserEnum_I && !NetApiBufferFree_I) + if (netapiModuleHandle && !NetUserEnum_I && !NetApiBufferFree_I) { FreeLibrary(netapiModuleHandle); netapiModuleHandle = NULL; @@ -414,7 +414,8 @@ VOID PhpFreeProgramsComboBox( { ULONG total; - total = ComboBox_GetCount(ComboBoxHandle); + if ((total = ComboBox_GetCount(ComboBoxHandle)) == CB_ERR) + return; for (ULONG i = 0; i < total; i++) { @@ -428,7 +429,8 @@ static VOID PhpFreeAccountsComboBox( { ULONG total; - total = ComboBox_GetCount(ComboBoxHandle); + if ((total = ComboBox_GetCount(ComboBoxHandle)) == CB_ERR) + return; for (ULONG i = 0; i < total; i++) { @@ -573,7 +575,8 @@ static VOID PhpFreeSessionsComboBox( ULONG total; ULONG i; - total = ComboBox_GetCount(ComboBoxHandle); + if ((total = ComboBox_GetCount(ComboBoxHandle)) == CB_ERR) + return; for (i = 0; i < total; i++) { @@ -701,7 +704,8 @@ static VOID PhpFreeDesktopsComboBox( ULONG total; ULONG i; - total = ComboBox_GetCount(ComboBoxHandle); + if ((total = ComboBox_GetCount(ComboBoxHandle)) == CB_ERR) + return; for (i = 0; i < total; i++) { @@ -1512,8 +1516,8 @@ NTSTATUS PhExecuteRunAsCommand3( static VOID PhpSplitUserName( _In_ PWSTR UserName, - _Out_ PPH_STRING *DomainPart, - _Out_ PPH_STRING *UserPart + _Out_opt_ PPH_STRING *DomainPart, + _Out_opt_ PPH_STRING *UserPart ) { PH_STRINGREF userName; diff --git a/phlib/basesup.c b/phlib/basesup.c index 0a65c2ed8a31..4b3fed830c81 100644 --- a/phlib/basesup.c +++ b/phlib/basesup.c @@ -4733,7 +4733,7 @@ VOID PhpResizeHashtable( for (i = 0; i < Hashtable->NextEntry; i++) { - if (entry->HashCode != -1) + if (entry->HashCode != ULONG_MAX) { ULONG index = PhpIndexFromHash(Hashtable, entry->HashCode); @@ -4764,7 +4764,7 @@ FORCEINLINE PVOID PhpAddEntryHashtable( { ULONG i; - for (i = Hashtable->Buckets[index]; i != -1; i = entry->Next) + for (i = Hashtable->Buckets[index]; i != ULONG_MAX; i = entry->Next) { entry = PH_HASHTABLE_GET_ENTRY(Hashtable, i); @@ -4779,7 +4779,7 @@ FORCEINLINE PVOID PhpAddEntryHashtable( } // Use a free entry if possible. - if (Hashtable->FreeEntry != -1) + if (Hashtable->FreeEntry != ULONG_MAX) { freeEntry = Hashtable->FreeEntry; entry = PH_HASHTABLE_GET_ENTRY(Hashtable, freeEntry); @@ -4909,7 +4909,7 @@ BOOLEAN PhEnumHashtable( (*EnumerationKey)++; - if (entry->HashCode != -1) + if (entry->HashCode != ULONG_MAX) { *Entry = &entry->Body; return TRUE; @@ -4944,7 +4944,7 @@ PVOID PhFindEntryHashtable( hashCode = PhpValidateHash(Hashtable->HashFunction(Entry)); index = PhpIndexFromHash(Hashtable, hashCode); - for (i = Hashtable->Buckets[index]; i != -1; i = entry->Next) + for (i = Hashtable->Buckets[index]; i != ULONG_MAX; i = entry->Next) { entry = PH_HASHTABLE_GET_ENTRY(Hashtable, i); @@ -4981,16 +4981,16 @@ BOOLEAN PhRemoveEntryHashtable( hashCode = PhpValidateHash(Hashtable->HashFunction(Entry)); index = PhpIndexFromHash(Hashtable, hashCode); - previousIndex = -1; + previousIndex = ULONG_MAX; - for (i = Hashtable->Buckets[index]; i != -1; i = entry->Next) + for (i = Hashtable->Buckets[index]; i != ULONG_MAX; i = entry->Next) { entry = PH_HASHTABLE_GET_ENTRY(Hashtable, i); if (entry->HashCode == hashCode && Hashtable->EqualFunction(&entry->Body, Entry)) { // Unlink the entry from the bucket. - if (previousIndex == -1) + if (previousIndex == ULONG_MAX) { Hashtable->Buckets[index] = entry->Next; } @@ -4999,7 +4999,7 @@ BOOLEAN PhRemoveEntryHashtable( PH_HASHTABLE_GET_ENTRY(Hashtable, previousIndex)->Next = entry->Next; } - entry->HashCode = -1; // indicates the entry is not being used + entry->HashCode = ULONG_MAX; // indicates the entry is not being used entry->Next = Hashtable->FreeEntry; Hashtable->FreeEntry = i; diff --git a/phlib/include/seceditp.h b/phlib/include/seceditp.h index 7aaf0de070ad..460a382b9b88 100644 --- a/phlib/include/seceditp.h +++ b/phlib/include/seceditp.h @@ -53,7 +53,7 @@ typedef struct // ISecurityInformation ISecurityInformation *PhSecurityInformation_Create( - _In_ HWND WindowHandle, + _In_opt_ HWND WindowHandle, _In_ PWSTR ObjectName, _In_ PWSTR ObjectType, _In_ PPH_OPEN_OBJECT OpenObject, diff --git a/phlib/util.c b/phlib/util.c index a71955e1a50e..672050df6d15 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -1519,7 +1519,7 @@ PPH_STRING PhFormatSize( // PhFormat handles this better than the old method. format.Type = SizeFormatType | FormatUseRadix; - format.Radix = (UCHAR)(MaxSizeUnit != -1 ? MaxSizeUnit : PhMaxSizeUnit); + format.Radix = (UCHAR)(MaxSizeUnit != ULONG_MAX ? MaxSizeUnit : PhMaxSizeUnit); format.u.Size = Size; return PhFormat(&format, 1, 0); @@ -2078,12 +2078,12 @@ NTSTATUS PhGetFullPathEx( if (filePart) { // The path points to a file. - *IndexOfFileName = (ULONG)(filePart - fullPath->Buffer); + *IndexOfFileName = PtrToUlong(PTR_SUB_OFFSET(filePart, fullPath->Buffer)); } else { // The path points to a directory. - *IndexOfFileName = -1; + *IndexOfFileName = ULONG_MAX; } } @@ -5167,7 +5167,7 @@ PPH_STRING PhCreateCacheFile( PPH_STRING cacheDirectory; PPH_STRING cacheFilePath; PPH_STRING cacheFullFilePath = NULL; - ULONG indexOfFileName = -1; + ULONG indexOfFileName = ULONG_MAX; WCHAR alphastring[16] = L""; cacheDirectory = PhExpandEnvironmentStrings(&cacheDirectorySr); @@ -5186,7 +5186,7 @@ PPH_STRING PhCreateCacheFile( { PPH_STRING directoryPath; - if (indexOfFileName != -1 && (directoryPath = PhSubstring(cacheFullFilePath, 0, indexOfFileName))) + if (indexOfFileName != ULONG_MAX && (directoryPath = PhSubstring(cacheFullFilePath, 0, indexOfFileName))) { PhCreateDirectory(directoryPath); PhDereferenceObject(directoryPath); @@ -5205,7 +5205,7 @@ VOID PhDeleteCacheFile( { PPH_STRING cacheDirectory; PPH_STRING cacheFullFilePath; - ULONG indexOfFileName = -1; + ULONG indexOfFileName = ULONG_MAX; if (RtlDoesFileExists_U(PhGetString(FileName))) { @@ -5214,7 +5214,7 @@ VOID PhDeleteCacheFile( if (cacheFullFilePath = PhGetFullPath(PhGetString(FileName), &indexOfFileName)) { - if (indexOfFileName != -1 && (cacheDirectory = PhSubstring(cacheFullFilePath, 0, indexOfFileName))) + if (indexOfFileName != ULONG_MAX && (cacheDirectory = PhSubstring(cacheFullFilePath, 0, indexOfFileName))) { PhDeleteDirectory(cacheDirectory); PhDereferenceObject(cacheDirectory); From bee99e31210ae35a663d0f1f6b3a6c1d87366331 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 31 Mar 2019 01:15:57 +0100 Subject: [PATCH 1756/2058] Add PhAccessResource --- phlib/include/phutil.h | 18 +++++++ phlib/util.c | 116 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 133 insertions(+), 1 deletion(-) diff --git a/phlib/include/phutil.h b/phlib/include/phutil.h index 4d0c043a5a56..2eff399e0d9b 100644 --- a/phlib/include/phutil.h +++ b/phlib/include/phutil.h @@ -1236,6 +1236,24 @@ PhGetLoaderEntryImageSection( _Out_ SIZE_T *ImageSectionLength ); +PHLIBAPI +NTSTATUS +NTAPI +PhLoaderEntryImageRvaToSection( + _In_ PIMAGE_NT_HEADERS ImageNtHeader, + _In_ ULONG Rva, + _Out_ PIMAGE_SECTION_HEADER *ImageSection, + _Out_ SIZE_T *ImageSectionLength + ); + +PHLIBAPI +PVOID +NTAPI +PhLoaderEntryImageRvaToVa( + _In_ PVOID BaseAddress, + _In_ ULONG Rva + ); + PHLIBAPI PVOID NTAPI diff --git a/phlib/util.c b/phlib/util.c index 672050df6d15..0ebb5b095ebe 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -5290,6 +5290,49 @@ HANDLE PhGetNamespaceHandle( return directory; } +// rev from LdrAccessResource (dmex) +NTSTATUS PhAccessResource( + _In_ PVOID DllBase, + _In_ PIMAGE_RESOURCE_DATA_ENTRY ResourceDataEntry, + _Out_opt_ PVOID *ResourceBuffer, + _Out_opt_ ULONG *ResourceLength + ) +{ + PVOID baseAddress; + + if (LDR_IS_DATAFILE(DllBase)) + baseAddress = (PVOID)((ULONG_PTR)DllBase & ~1); + else if (LDR_IS_IMAGEMAPPING(DllBase)) + baseAddress = (PVOID)((ULONG_PTR)DllBase & ~2); + else + baseAddress = DllBase; + + if (ResourceBuffer) + { + if (LDR_IS_DATAFILE(DllBase)) + { + *ResourceBuffer = PhLoaderEntryImageRvaToVa( + baseAddress, + ResourceDataEntry->OffsetToData + ); + } + else + { + *ResourceBuffer = PTR_ADD_OFFSET( + baseAddress, + ResourceDataEntry->OffsetToData + ); + } + } + + if (ResourceLength) + { + *ResourceLength = ResourceDataEntry->Size; + } + + return STATUS_SUCCESS; +} + BOOLEAN PhLoadResource( _In_ PVOID DllBase, _In_ PCWSTR Name, @@ -5310,7 +5353,7 @@ BOOLEAN PhLoadResource( if (!NT_SUCCESS(LdrFindResource_U(DllBase, &resourceInfo, RESOURCE_DATA_LEVEL, &resourceData))) return FALSE; - if (!NT_SUCCESS(LdrAccessResource(DllBase, resourceData, &resourceBuffer, &resourceLength))) + if (!NT_SUCCESS(PhAccessResource(DllBase, resourceData, &resourceBuffer, &resourceLength))) return FALSE; if (ResourceLength) @@ -5740,6 +5783,77 @@ NTSTATUS PhGetLoaderEntryImageSection( return STATUS_SECTION_NOT_IMAGE; } +NTSTATUS PhLoaderEntryImageRvaToSection( + _In_ PIMAGE_NT_HEADERS ImageNtHeader, + _In_ ULONG Rva, + _Out_ PIMAGE_SECTION_HEADER *ImageSection, + _Out_ SIZE_T *ImageSectionLength + ) +{ + SIZE_T directorySectionLength = 0; + PIMAGE_SECTION_HEADER sectionHeader; + PIMAGE_SECTION_HEADER directorySectionHeader = NULL; + ULONG i; + + for (i = 0; i < ImageNtHeader->FileHeader.NumberOfSections; i++) + { + sectionHeader = PTR_ADD_OFFSET(IMAGE_FIRST_SECTION(ImageNtHeader), sizeof(IMAGE_SECTION_HEADER) * i); + + if ( + ((ULONG_PTR)Rva >= (ULONG_PTR)sectionHeader->VirtualAddress) && + ((ULONG_PTR)Rva < (ULONG_PTR)PTR_ADD_OFFSET(sectionHeader->VirtualAddress, sectionHeader->SizeOfRawData)) + ) + { + directorySectionLength = sectionHeader->Misc.VirtualSize; + directorySectionHeader = sectionHeader; + break; + } + } + + if (directorySectionHeader && directorySectionLength) + { + *ImageSection = directorySectionHeader; + *ImageSectionLength = directorySectionLength; + return STATUS_SUCCESS; + } + + return STATUS_SECTION_NOT_IMAGE; +} + +PVOID PhLoaderEntryImageRvaToVa( + _In_ PVOID BaseAddress, + _In_ ULONG Rva + ) +{ + NTSTATUS status; + SIZE_T imageSectionSize; + PIMAGE_SECTION_HEADER imageSection; + PIMAGE_NT_HEADERS imageNtHeader; + + status = PhGetLoaderEntryImageNtHeaders( + BaseAddress, + &imageNtHeader + ); + + if (!NT_SUCCESS(status)) + return NULL; + + status = PhLoaderEntryImageRvaToSection( + imageNtHeader, + Rva, + &imageSection, + &imageSectionSize + ); + + if (!NT_SUCCESS(status)) + return NULL; + + return PTR_ADD_OFFSET(BaseAddress, PTR_ADD_OFFSET( + PTR_SUB_OFFSET(Rva, imageSection->VirtualAddress), + imageSection->PointerToRawData + )); +} + PVOID PhGetLoaderEntryImageExportFunction( _In_ PVOID BaseAddress, _In_ PIMAGE_NT_HEADERS ImageNtHeader, From b0ae418eac350dfd5499c6e9f36c34f1fdf7705e Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 31 Mar 2019 14:33:04 +0200 Subject: [PATCH 1757/2058] Fix regression from commit cbf0576c --- phlib/util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phlib/util.c b/phlib/util.c index 0ebb5b095ebe..ccaf7b0e0ce8 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -2078,7 +2078,7 @@ NTSTATUS PhGetFullPathEx( if (filePart) { // The path points to a file. - *IndexOfFileName = PtrToUlong(PTR_SUB_OFFSET(filePart, fullPath->Buffer)); + *IndexOfFileName = (ULONG)(filePart - fullPath->Buffer); } else { From 1cdc6aded9f7c9c56b69d2847ad8cd42da9f0746 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 31 Mar 2019 15:05:45 +0200 Subject: [PATCH 1758/2058] Add workaround for the ImDisk driver (see commit description) The ImDisk driver doesn't implement various ioctls required by Windows and works around this by patching Windows and the registry... ImDisk patches the Win32 API but since PH uses the NTAPI it breaks path traversal and other things including the updater... We can workaround this by using directory paths that ImDisk won't modify. --- ProcessHacker/ProcessHacker.def | 1 + phlib/include/phutil.h | 7 +++++++ phlib/util.c | 16 +++++++++++++++- plugins/Updater/updater.c | 2 ++ 4 files changed, 25 insertions(+), 1 deletion(-) diff --git a/ProcessHacker/ProcessHacker.def b/ProcessHacker/ProcessHacker.def index 83c926d6007f..59064057e535 100644 --- a/ProcessHacker/ProcessHacker.def +++ b/ProcessHacker/ProcessHacker.def @@ -686,6 +686,7 @@ EXPORTS ; cache PhCreateCacheFile + PhClearCacheDirectory PhDeleteCacheFile ; appresolver diff --git a/phlib/include/phutil.h b/phlib/include/phutil.h index 2eff399e0d9b..050344de5db5 100644 --- a/phlib/include/phutil.h +++ b/phlib/include/phutil.h @@ -1120,6 +1120,13 @@ PhCreateCacheFile( _In_ PPH_STRING FileName ); +PHLIBAPI +VOID +NTAPI +PhClearCacheDirectory( + VOID + ); + PHLIBAPI VOID NTAPI diff --git a/phlib/util.c b/phlib/util.c index ccaf7b0e0ce8..68544f519327 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -5163,7 +5163,7 @@ PPH_STRING PhCreateCacheFile( _In_ PPH_STRING FileName ) { - static PH_STRINGREF cacheDirectorySr = PH_STRINGREF_INIT(L"%TEMP%"); + static PH_STRINGREF cacheDirectorySr = PH_STRINGREF_INIT(L"%APPDATA%\\Process Hacker\\Cache"); PPH_STRING cacheDirectory; PPH_STRING cacheFilePath; PPH_STRING cacheFullFilePath = NULL; @@ -5199,6 +5199,20 @@ PPH_STRING PhCreateCacheFile( return cacheFullFilePath; } +VOID PhClearCacheDirectory( + VOID + ) +{ + static PH_STRINGREF cacheDirectorySr = PH_STRINGREF_INIT(L"%APPDATA%\\Process Hacker\\Cache"); + PPH_STRING cacheDirectory; + + if (cacheDirectory = PhExpandEnvironmentStrings(&cacheDirectorySr)) + { + PhDeleteDirectory(cacheDirectory); + PhDereferenceObject(cacheDirectory); + } +} + VOID PhDeleteCacheFile( _In_ PPH_STRING FileName ) diff --git a/plugins/Updater/updater.c b/plugins/Updater/updater.c index ccf83bc83c85..df6854714703 100644 --- a/plugins/Updater/updater.c +++ b/plugins/Updater/updater.c @@ -444,6 +444,8 @@ NTSTATUS UpdateCheckThread( PhInitializeAutoPool(&autoPool); + PhClearCacheDirectory(); // HACK + // Check if we have cached update data if (!context->HaveData) { From 013995ccb0eebf0988f1a1cddf4a2caa54f69dbe Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 31 Mar 2019 15:22:06 +0200 Subject: [PATCH 1759/2058] Improve PhAccessResource error checking --- phlib/include/phutil.h | 5 +- phlib/util.c | 108 ++++++++++++++++++++++------------------- 2 files changed, 60 insertions(+), 53 deletions(-) diff --git a/phlib/include/phutil.h b/phlib/include/phutil.h index 050344de5db5..dee0fad155fa 100644 --- a/phlib/include/phutil.h +++ b/phlib/include/phutil.h @@ -1254,11 +1254,12 @@ PhLoaderEntryImageRvaToSection( ); PHLIBAPI -PVOID +NTSTATUS NTAPI PhLoaderEntryImageRvaToVa( _In_ PVOID BaseAddress, - _In_ ULONG Rva + _In_ ULONG Rva, + _Out_ PVOID *Va ); PHLIBAPI diff --git a/phlib/util.c b/phlib/util.c index 68544f519327..8689d3936a27 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -5321,14 +5321,24 @@ NTSTATUS PhAccessResource( else baseAddress = DllBase; + if (ResourceLength) + { + *ResourceLength = ResourceDataEntry->Size; + } + if (ResourceBuffer) { if (LDR_IS_DATAFILE(DllBase)) { - *ResourceBuffer = PhLoaderEntryImageRvaToVa( + NTSTATUS status; + + status = PhLoaderEntryImageRvaToVa( baseAddress, - ResourceDataEntry->OffsetToData + ResourceDataEntry->OffsetToData, + ResourceBuffer ); + + return status; } else { @@ -5336,12 +5346,9 @@ NTSTATUS PhAccessResource( baseAddress, ResourceDataEntry->OffsetToData ); - } - } - if (ResourceLength) - { - *ResourceLength = ResourceDataEntry->Size; + return STATUS_SUCCESS; + } } return STATUS_SUCCESS; @@ -5834,9 +5841,10 @@ NTSTATUS PhLoaderEntryImageRvaToSection( return STATUS_SECTION_NOT_IMAGE; } -PVOID PhLoaderEntryImageRvaToVa( +NTSTATUS PhLoaderEntryImageRvaToVa( _In_ PVOID BaseAddress, - _In_ ULONG Rva + _In_ ULONG Rva, + _Out_ PVOID *Va ) { NTSTATUS status; @@ -5850,7 +5858,7 @@ PVOID PhLoaderEntryImageRvaToVa( ); if (!NT_SUCCESS(status)) - return NULL; + return status; status = PhLoaderEntryImageRvaToSection( imageNtHeader, @@ -5860,12 +5868,14 @@ PVOID PhLoaderEntryImageRvaToVa( ); if (!NT_SUCCESS(status)) - return NULL; + return status; - return PTR_ADD_OFFSET(BaseAddress, PTR_ADD_OFFSET( + *Va = PTR_ADD_OFFSET(BaseAddress, PTR_ADD_OFFSET( PTR_SUB_OFFSET(Rva, imageSection->VirtualAddress), imageSection->PointerToRawData )); + + return STATUS_SUCCESS; } PVOID PhGetLoaderEntryImageExportFunction( @@ -6043,28 +6053,26 @@ static NTSTATUS PhpFixupLoaderEntryImageImports( if (!procedureAddress) { - if (PhGetIntegerSetting(L"ShowPluginLoadErrors")) // HACK abstraction violation (dmex) +#ifdef DEBUG + PPH_STRING fileName; + + if (NT_SUCCESS(PhGetProcessMappedFileName(NtCurrentProcess(), BaseAddress, &fileName))) { - PPH_STRING fileName; - - if (NT_SUCCESS(PhGetProcessMappedFileName(NtCurrentProcess(), BaseAddress, &fileName))) - { - PhMoveReference(&fileName, PhGetFileName(fileName)); - PhMoveReference(&fileName, PhGetBaseName(fileName)); - - PhShowError( - NULL, - L"Unable to load plugin.\r\nName: %s\r\nOrdinal: %u\r\nModule: %hs", - PhGetStringOrEmpty(fileName), - procedureOrdinal, - importName - ); - - PhDereferenceObject(fileName); - } - } + PhMoveReference(&fileName, PhGetFileName(fileName)); + PhMoveReference(&fileName, PhGetBaseName(fileName)); + + PhShowError( + NULL, + L"Unable to load plugin.\r\nName: %s\r\nOrdinal: %u\r\nModule: %hs", + PhGetStringOrEmpty(fileName), + procedureOrdinal, + importName + ); - status = STATUS_INVALID_PARAMETER;STATUS_ORDINAL_NOT_FOUND; + PhDereferenceObject(fileName); + } +#endif + status = STATUS_ORDINAL_NOT_FOUND; goto CleanupExit; } @@ -6080,27 +6088,25 @@ static NTSTATUS PhpFixupLoaderEntryImageImports( if (!procedureAddress) { - if (PhGetIntegerSetting(L"ShowPluginLoadErrors")) // HACK abstraction violation (dmex) +#ifdef DEBUG + PPH_STRING fileName; + + if (NT_SUCCESS(PhGetProcessMappedFileName(NtCurrentProcess(), BaseAddress, &fileName))) { - PPH_STRING fileName; - - if (NT_SUCCESS(PhGetProcessMappedFileName(NtCurrentProcess(), BaseAddress, &fileName))) - { - PhMoveReference(&fileName, PhGetFileName(fileName)); - PhMoveReference(&fileName, PhGetBaseName(fileName)); - - PhShowError( - NULL, - L"Unable to load plugin.\r\nName: %s\r\nFunction: %hs\r\nModule: %hs", - PhGetStringOrEmpty(fileName), - importByName->Name, - importName - ); - - PhDereferenceObject(fileName); - } - } + PhMoveReference(&fileName, PhGetFileName(fileName)); + PhMoveReference(&fileName, PhGetBaseName(fileName)); + + PhShowError( + NULL, + L"Unable to load plugin.\r\nName: %s\r\nFunction: %hs\r\nModule: %hs", + PhGetStringOrEmpty(fileName), + importByName->Name, + importName + ); + PhDereferenceObject(fileName); + } +#endif status = STATUS_PROCEDURE_NOT_FOUND; goto CleanupExit; } From 1a049593163c045e6080f73b449df596e9e32fbd Mon Sep 17 00:00:00 2001 From: Xiaoyin Liu Date: Wed, 3 Apr 2019 08:42:53 +0200 Subject: [PATCH 1760/2058] Use HTTPS for Microsoft Symbol server URL (#399) Microsoft now recommends using https://msdl.microsoft.com/download/symbols --- tools/peview/pdb.c | 2 +- tools/peview/peprp.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/peview/pdb.c b/tools/peview/pdb.c index 80d2b16041bd..1b6a705fa526 100644 --- a/tools/peview/pdb.c +++ b/tools/peview/pdb.c @@ -2415,7 +2415,7 @@ NTSTATUS PeDumpFileSymbols( if (!SymInitializeW_I(NtCurrentProcess(), NULL, FALSE)) return 1; - if (!SymSetSearchPathW_I(NtCurrentProcess(), L"SRV*C:\\symbols*http://msdl.microsoft.com/download/symbols")) + if (!SymSetSearchPathW_I(NtCurrentProcess(), L"SRV*C:\\symbols*https://msdl.microsoft.com/download/symbols")) goto CleanupExit; if (!NT_SUCCESS(status = PhCreateFileWin32( diff --git a/tools/peview/peprp.c b/tools/peview/peprp.c index 813536c26973..4203cfa7fc18 100644 --- a/tools/peview/peprp.c +++ b/tools/peview/peprp.c @@ -884,7 +884,7 @@ BOOLEAN PvpLoadDbgHelp( else { // Set the default path (C:\\Symbols is the default hard-coded path for livekd). - symbolSearchPath = PhCreateString(L"SRV*C:\\Symbols*http://msdl.microsoft.com/download/symbols"); + symbolSearchPath = PhCreateString(L"SRV*C:\\Symbols*https://msdl.microsoft.com/download/symbols"); } symbolProvider = PhCreateSymbolProvider(NULL); From be39ed6e9a86eebedb7ec6cce76d63b950896d02 Mon Sep 17 00:00:00 2001 From: diversenok Date: Wed, 3 Apr 2019 14:04:41 +0300 Subject: [PATCH 1761/2058] Optimize SID translation (#401) * Optimize SID translation * Eliminate string duplication --- ProcessHacker/tokprp.c | 27 ++++++--- phlib/include/lsasup.h | 9 +++ phlib/lsasup.c | 121 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 148 insertions(+), 9 deletions(-) diff --git a/ProcessHacker/tokprp.c b/ProcessHacker/tokprp.c index 8ae401ecb8c3..380c434d37fa 100644 --- a/ProcessHacker/tokprp.c +++ b/ProcessHacker/tokprp.c @@ -429,19 +429,26 @@ VOID PhpUpdateSidsFromTokenGroups( ) { ULONG i; + PSID *sids; + PPH_STRING *names = NULL; + + sids = PhAllocate(sizeof(PSID) * Groups->GroupCount); for (i = 0; i < Groups->GroupCount; i++) { - INT lvItemIndex; - PPH_STRING fullName; - PPH_STRING attributesString; - PPH_STRING descriptionString; + sids[i] = Groups->Groups[i].Sid; + } - if (!(fullName = PhGetSidFullName(Groups->Groups[i].Sid, TRUE, NULL))) - fullName = PhSidToStringSid(Groups->Groups[i].Sid); + PhLookupSids(Groups->GroupCount, sids, &names); + PhFree(sids); - if (fullName) + for (i = 0; i < Groups->GroupCount; i++) + { + if (names[i]) { + INT lvItemIndex; + PPH_STRING attributesString; + PPH_STRING descriptionString; PPHP_TOKEN_PAGE_LISTVIEW_ITEM lvitem; lvitem = PhAllocateZero(sizeof(PHP_TOKEN_PAGE_LISTVIEW_ITEM)); @@ -452,7 +459,7 @@ VOID PhpUpdateSidsFromTokenGroups( ListViewHandle, lvitem->ItemCategory, PH_PROCESS_TOKEN_INDEX_NAME, - fullName->Buffer, + names[i]->Buffer, lvitem ); @@ -474,9 +481,11 @@ VOID PhpUpdateSidsFromTokenGroups( PhDereferenceObject(descriptionString); } - PhDereferenceObject(fullName); + PhDereferenceObject(names[i]); } } + + PhFree(names); } BOOLEAN PhpUpdateTokenGroups( diff --git a/phlib/include/lsasup.h b/phlib/include/lsasup.h index 7b45bf110551..a58972c3cd09 100644 --- a/phlib/include/lsasup.h +++ b/phlib/include/lsasup.h @@ -55,6 +55,15 @@ PhLookupSid( _Out_opt_ PSID_NAME_USE NameUse ); +PHLIBAPI +VOID +NTAPI +PhLookupSids( + _In_ ULONG Count, + _In_ PSID *Sids, + _Out_ PPH_STRING **FullNames + ); + PHLIBAPI NTSTATUS NTAPI diff --git a/phlib/lsasup.c b/phlib/lsasup.c index f06a16622393..3141fc5529a4 100644 --- a/phlib/lsasup.c +++ b/phlib/lsasup.c @@ -269,6 +269,127 @@ NTSTATUS PhLookupSid( return status; } +/** + * Converts an array of SIDs to a human-readable form. + * + * \param Count The size of the array. + * \param Sids An array of SIDs to query. + * \param FullNames A variable which receives a pointer to an array of strings in the following format: + * domain\\user. If not applicable to a particular SID, the function returns its SDDL representation. + * You must free each item using PhDereferenceObject(), and then free the array by calling PhFree(). + */ +VOID PhLookupSids( + _In_ ULONG Count, + _In_ PSID *Sids, + _Out_ PPH_STRING **FullNames + ) +{ + NTSTATUS status; + PLSA_REFERENCED_DOMAIN_LIST referencedDomains = NULL; + PLSA_TRANSLATED_NAME names = NULL; + PPH_STRING *translatedNames; + + translatedNames = PhAllocateZero(sizeof(PPH_STRING) * Count); + + status = LsaLookupSids( + PhGetLookupPolicyHandle(), + Count, + Sids, + &referencedDomains, + &names + ); + + if (status == STATUS_NONE_MAPPED) + { + // Even without mapping names it converts most of them to SDDL representation + status = STATUS_SOME_NOT_MAPPED; + } + + if (NT_SUCCESS(status)) + { + PPH_STRING userName; + PPH_STRING domainName; + + for (ULONG i = 0; i < Count; i++) + { + userName = NULL; + domainName = NULL; + + // Reference user if present + if (names[i].Name.Length > 0) + { + userName = PhCreateStringFromUnicodeString(&names[i].Name); + } + + // Reference domain if present + if (names[i].DomainIndex >= 0) + { + PLSA_TRUST_INFORMATION trustInfo; + + trustInfo = &referencedDomains->Domains[names[i].DomainIndex]; + + if (trustInfo->Name.Length > 0) + { + domainName = PhCreateStringFromUnicodeString(&trustInfo->Name); + } + } + + // Construct the name + if (names[i].Use != SidTypeInvalid && names[i].Use != SidTypeUnknown) + { + if (domainName && userName) + { + translatedNames[i] = PhConcatStrings( + 3, + domainName->Buffer, + L"\\", + userName->Buffer + ); + } + else if (domainName) + { + translatedNames[i] = PhReferenceObject(domainName); + } + else if (userName) + { + translatedNames[i] = PhReferenceObject(userName); + } + } + else + { + if (PhStartsWithString2(userName, L"S-1-", TRUE)) + { + translatedNames[i] = PhReferenceObject(userName); + } + } + + if (userName) + { + PhDereferenceObject(userName); + } + + if (domainName) + { + PhDereferenceObject(domainName); + } + } + + LsaFreeMemory(referencedDomains); + LsaFreeMemory(names); + } + + for (ULONG i = 0; i < Count; i++) + { + // Make sure everything is converted at least to SDDL + if (!translatedNames[i]) + { + translatedNames[i] = PhSidToStringSid(Sids[i]); + } + } + + *FullNames = translatedNames; +} + /** * Gets information about a name. * From 22d212068df19b6890356ddf7b0c71d38911bf0f Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 3 Apr 2019 18:11:49 +0200 Subject: [PATCH 1762/2058] Fix SAL annotation warning, remove unused dpkg paramaters --- ProcessHacker/actions.c | 2 +- phlib/include/phsup.h | 3 +++ phlib/include/secedit.h | 4 ++-- phlib/secedit.c | 4 ++-- phlib/wslsup.c | 20 ++++++-------------- 5 files changed, 14 insertions(+), 19 deletions(-) diff --git a/ProcessHacker/actions.c b/ProcessHacker/actions.c index 452aeab4b7d2..699bc54396b2 100644 --- a/ProcessHacker/actions.c +++ b/ProcessHacker/actions.c @@ -431,7 +431,7 @@ BOOLEAN PhUiConnectToPhSvcEx( { PhAcquireQueuedLockExclusive(&PhSvcStartLock); - if (PhSvcReferenceCount == 0) + if (_InterlockedExchange(PhSvcReferenceCount, 0) == 0) { started = FALSE; PhpGetPhSvcPortName(Mode, &portName); diff --git a/phlib/include/phsup.h b/phlib/include/phsup.h index 7e23a55430fc..3ef4ed36fdc2 100644 --- a/phlib/include/phsup.h +++ b/phlib/include/phsup.h @@ -534,6 +534,9 @@ FORCEINLINE PLARGE_INTEGER PhTimeoutFromMilliseconds( return Timeout; } +#define PhTimeoutFromMillisecondsEx(Milliseconds) \ + &(LARGE_INTEGER) { -(LONGLONG)UInt32x32To64((Milliseconds), PH_TIMEOUT_MS) } + FORCEINLINE NTSTATUS PhGetLastWin32ErrorAsNtStatus( VOID ) diff --git a/phlib/include/secedit.h b/phlib/include/secedit.h index abf1c69d138b..8f34cf621878 100644 --- a/phlib/include/secedit.h +++ b/phlib/include/secedit.h @@ -25,7 +25,7 @@ PhCreateSecurityPage( _In_ PWSTR ObjectName, _In_ PWSTR ObjectType, _In_ PPH_OPEN_OBJECT OpenObject, - _In_ PPH_CLOSE_OBJECT CloseObject, + _In_opt_ PPH_CLOSE_OBJECT CloseObject, _In_opt_ PVOID Context ); @@ -37,7 +37,7 @@ PhEditSecurity( _In_ PWSTR ObjectName, _In_ PWSTR ObjectType, _In_ PPH_OPEN_OBJECT OpenCallback, - _In_ PPH_CLOSE_OBJECT CloseCallback, + _In_opt_ PPH_CLOSE_OBJECT CloseCallback, _In_opt_ PVOID Context ); diff --git a/phlib/secedit.c b/phlib/secedit.c index 68bea3d7cdf4..6b83c2bba2a7 100644 --- a/phlib/secedit.c +++ b/phlib/secedit.c @@ -90,7 +90,7 @@ HPROPSHEETPAGE PhCreateSecurityPage( _In_ PWSTR ObjectName, _In_ PWSTR ObjectType, _In_ PPH_OPEN_OBJECT OpenObject, - _In_ PPH_CLOSE_OBJECT CloseObject, + _In_opt_ PPH_CLOSE_OBJECT CloseObject, _In_opt_ PVOID Context ) { @@ -144,7 +144,7 @@ VOID PhEditSecurity( _In_ PWSTR ObjectName, _In_ PWSTR ObjectType, _In_ PPH_OPEN_OBJECT OpenObject, - _In_ PPH_CLOSE_OBJECT CloseObject, + _In_opt_ PPH_CLOSE_OBJECT CloseObject, _In_opt_ PVOID Context ) { diff --git a/phlib/wslsup.c b/phlib/wslsup.c index f1fbc619eb00..7bdd5163bdd0 100644 --- a/phlib/wslsup.c +++ b/phlib/wslsup.c @@ -150,11 +150,8 @@ BOOLEAN PhInitializeLxssImageVersionInfo( PPH_STRING lxssDistroName; PPH_STRING lxssDistroPath; PPH_STRING lxssFileName; - PPH_STRING lxssBaseFileName; PPH_STRING result; - lxssBaseFileName = PhGetBaseName(FileName); - if (!PhGetWslDistributionFromPath( FileName, &lxssDistroName, @@ -165,12 +162,11 @@ BOOLEAN PhInitializeLxssImageVersionInfo( return FALSE; } - if (PhIsNullOrEmptyString(lxssDistroName) || PhIsNullOrEmptyString(lxssFileName) || PhIsNullOrEmptyString(lxssBaseFileName)) + if (PhIsNullOrEmptyString(lxssDistroName) || PhIsNullOrEmptyString(lxssDistroPath) || PhIsNullOrEmptyString(lxssFileName)) { if (lxssDistroName) PhDereferenceObject(lxssDistroName); if (lxssDistroPath) PhDereferenceObject(lxssDistroPath); if (lxssFileName) PhDereferenceObject(lxssFileName); - if (lxssBaseFileName) PhDereferenceObject(lxssBaseFileName); return FALSE; } @@ -191,8 +187,8 @@ BOOLEAN PhInitializeLxssImageVersionInfo( goto ParseResult; } - PhMoveReference(&lxssCommandLine, PhFormatString( - L"dpkg -S %s", + PhMoveReference(&lxssCommandLine, PhConcatStrings2( + L"dpkg -S ", lxssFileName->Buffer )); @@ -208,7 +204,6 @@ BOOLEAN PhInitializeLxssImageVersionInfo( PhDereferenceObject(lxssCommandLine); PhDereferenceObject(lxssDistroName); PhDereferenceObject(lxssFileName); - PhDereferenceObject(lxssBaseFileName); return FALSE; } else @@ -224,17 +219,16 @@ BOOLEAN PhInitializeLxssImageVersionInfo( PhDereferenceObject(result); } - if (!lxssPackageName) + if (PhIsNullOrEmptyString(lxssPackageName)) { PhDereferenceObject(lxssCommandLine); PhDereferenceObject(lxssDistroName); PhDereferenceObject(lxssFileName); - PhDereferenceObject(lxssBaseFileName); return FALSE; } - PhMoveReference(&lxssCommandLine, PhFormatString( - L"dpkg-query -W -f=${Version}|${Maintainer}|${binary:Summary} %s", + PhMoveReference(&lxssCommandLine, PhConcatStrings2( + L"dpkg-query -W -f=${Version}|${Maintainer}|${binary:Summary} ", lxssPackageName->Buffer )); @@ -250,7 +244,6 @@ BOOLEAN PhInitializeLxssImageVersionInfo( PhDereferenceObject(lxssCommandLine); PhDereferenceObject(lxssDistroName); PhDereferenceObject(lxssFileName); - PhDereferenceObject(lxssBaseFileName); return FALSE; } @@ -284,7 +277,6 @@ BOOLEAN PhInitializeLxssImageVersionInfo( if (lxssPackageName) PhDereferenceObject(lxssPackageName); if (lxssDistroName) PhDereferenceObject(lxssDistroName); if (lxssFileName) PhDereferenceObject(lxssFileName); - if (lxssBaseFileName) PhDereferenceObject(lxssBaseFileName); return TRUE; } From bfa8776779aa80c7285889c6c54bf4d0af8e93e4 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 3 Apr 2019 18:12:13 +0200 Subject: [PATCH 1763/2058] Remove string privileges --- ProcessHacker/runas.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ProcessHacker/runas.c b/ProcessHacker/runas.c index 9c4c4c9bc8b4..fd5cfc04c4e6 100644 --- a/ProcessHacker/runas.c +++ b/ProcessHacker/runas.c @@ -1612,11 +1612,11 @@ NTSTATUS PhRunAsServiceStart( &tokenHandle ))) { - PhSetTokenPrivilege(tokenHandle, L"SeAssignPrimaryTokenPrivilege", NULL, SE_PRIVILEGE_ENABLED); - PhSetTokenPrivilege(tokenHandle, L"SeBackupPrivilege", NULL, SE_PRIVILEGE_ENABLED); - PhSetTokenPrivilege(tokenHandle, L"SeImpersonatePrivilege", NULL, SE_PRIVILEGE_ENABLED); - PhSetTokenPrivilege(tokenHandle, L"SeIncreaseQuotaPrivilege", NULL, SE_PRIVILEGE_ENABLED); - PhSetTokenPrivilege(tokenHandle, L"SeRestorePrivilege", NULL, SE_PRIVILEGE_ENABLED); + PhSetTokenPrivilege2(tokenHandle, SE_ASSIGNPRIMARYTOKEN_PRIVILEGE, SE_PRIVILEGE_ENABLED); + PhSetTokenPrivilege2(tokenHandle, SE_INCREASE_QUOTA_PRIVILEGE, SE_PRIVILEGE_ENABLED); + PhSetTokenPrivilege2(tokenHandle, SE_BACKUP_PRIVILEGE, SE_PRIVILEGE_ENABLED); + PhSetTokenPrivilege2(tokenHandle, SE_RESTORE_PRIVILEGE, SE_PRIVILEGE_ENABLED); + PhSetTokenPrivilege2(tokenHandle, SE_IMPERSONATE_PRIVILEGE, SE_PRIVILEGE_ENABLED); NtClose(tokenHandle); } From 977b0024d9f23c7db381f2b44fd070f98203f5de Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 3 Apr 2019 18:12:45 +0200 Subject: [PATCH 1764/2058] Fix stack memory leak --- ProcessHacker/thrdstk.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/ProcessHacker/thrdstk.c b/ProcessHacker/thrdstk.c index 7821e2978171..cbeec1f67611 100644 --- a/ProcessHacker/thrdstk.c +++ b/ProcessHacker/thrdstk.c @@ -682,9 +682,10 @@ VOID NTAPI PhpThreadStackContextDeleteProcedure( { PPH_THREAD_STACK_CONTEXT context = (PPH_THREAD_STACK_CONTEXT)Object; - PhDereferenceObject(context->StatusMessage); - PhDereferenceObject(context->NewList); - PhDereferenceObject(context->List); + if (context->StatusMessage) PhDereferenceObject(context->StatusMessage); + if (context->StatusContent) PhDereferenceObject(context->StatusContent); + if (context->NewList) PhDereferenceObject(context->NewList); + if (context->List) PhDereferenceObject(context->List); if (context->ThreadHandle) NtClose(context->ThreadHandle); @@ -985,7 +986,7 @@ BOOLEAN NTAPI PhpWalkThreadStackCallback( PhReleaseQueuedLockExclusive(&threadStackContext->StatusLock); symbol = PhGetSymbolFromAddress( - threadStackContext->SymbolProvider, + threadStackContext->SymbolProvider, (ULONG64)StackFrame->PcAddress, NULL, NULL, From 5761b19f615d9e46bfd590a2de0893ac71a81e62 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 3 Apr 2019 18:14:35 +0200 Subject: [PATCH 1765/2058] Fix SAL types --- ProcessHacker/options.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/ProcessHacker/options.c b/ProcessHacker/options.c index e842296d920a..4b83df6392a0 100644 --- a/ProcessHacker/options.c +++ b/ProcessHacker/options.c @@ -105,7 +105,7 @@ PPH_OPTIONS_SECTION PhOptionsCreateSection( _In_ PVOID Instance, _In_ PWSTR Template, _In_ DLGPROC DialogProc, - _In_ PVOID Parameter + _In_opt_ PVOID Parameter ); PPH_OPTIONS_SECTION PhOptionsCreateSectionAdvanced( @@ -113,7 +113,7 @@ PPH_OPTIONS_SECTION PhOptionsCreateSectionAdvanced( _In_ PVOID Instance, _In_ PWSTR Template, _In_ DLGPROC DialogProc, - _In_ PVOID Parameter + _In_opt_ PVOID Parameter ); BOOLEAN PhpIsDefaultTaskManager( @@ -523,7 +523,7 @@ PPH_OPTIONS_SECTION PhOptionsCreateSection( _In_ PVOID Instance, _In_ PWSTR Template, _In_ DLGPROC DialogProc, - _In_ PVOID Parameter + _In_opt_ PVOID Parameter ) { PPH_OPTIONS_SECTION section; @@ -546,7 +546,7 @@ PPH_OPTIONS_SECTION PhOptionsCreateSectionAdvanced( _In_ PVOID Instance, _In_ PWSTR Template, _In_ DLGPROC DialogProc, - _In_ PVOID Parameter + _In_opt_ PVOID Parameter ) { PPH_OPTIONS_SECTION section; @@ -839,7 +839,7 @@ static BOOLEAN PathMatchesPh( } // Allow for a quoted value. else if ( - OldTaskMgrDebugger->Length == fileName->Length + sizeof(WCHAR) * sizeof(WCHAR) && + OldTaskMgrDebugger->Length == (fileName->Length + sizeof(UNICODE_NULL)) * sizeof(WCHAR) && OldTaskMgrDebugger->Buffer[0] == '"' && OldTaskMgrDebugger->Buffer[OldTaskMgrDebugger->Length / sizeof(WCHAR) - 1] == '"' ) @@ -847,7 +847,7 @@ static BOOLEAN PathMatchesPh( PH_STRINGREF partInside; partInside.Buffer = &OldTaskMgrDebugger->Buffer[1]; - partInside.Length = OldTaskMgrDebugger->Length - sizeof(WCHAR) * sizeof(WCHAR); + partInside.Length = (OldTaskMgrDebugger->Length - sizeof(UNICODE_NULL)) * sizeof(WCHAR); if (PhEqualStringRef(&partInside, &fileName->sr, TRUE)) match = TRUE; @@ -943,7 +943,7 @@ VOID PhpSetDefaultTaskManager( 0, REG_SZ, quotedFileName->Buffer, - (ULONG)quotedFileName->Length + sizeof(WCHAR) + (ULONG)quotedFileName->Length + sizeof(UNICODE_NULL) ); PhDereferenceObject(applicationFileName); From 7cab27285dcad87be7b1a547df246f5241bbf6e7 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 3 Apr 2019 18:15:16 +0200 Subject: [PATCH 1766/2058] Remove string privilege --- ProcessHacker/memlists.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ProcessHacker/memlists.c b/ProcessHacker/memlists.c index 72eaa0015f9b..d211b4ffc218 100644 --- a/ProcessHacker/memlists.c +++ b/ProcessHacker/memlists.c @@ -175,7 +175,7 @@ INT_PTR CALLBACK PhpMemoryListsDlgProc( if (NT_SUCCESS(PhOpenProcessToken(NtCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &tokenHandle))) { - PhSetTokenPrivilege(tokenHandle, L"SeProfileSingleProcessPrivilege", NULL, SE_PRIVILEGE_ENABLED); + PhSetTokenPrivilege2(tokenHandle, SE_PROF_SINGLE_PROCESS_PRIVILEGE, SE_PRIVILEGE_ENABLED); NtClose(tokenHandle); } From 803efb2530d30fd414525cec1c23a709f7ca5767 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 3 Apr 2019 18:16:13 +0200 Subject: [PATCH 1767/2058] Fix crash viewing large default-token security descriptors --- phlib/secedit.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/phlib/secedit.c b/phlib/secedit.c index 6b83c2bba2a7..077f4af2a6c3 100644 --- a/phlib/secedit.c +++ b/phlib/secedit.c @@ -796,7 +796,7 @@ NTSTATUS PhpGetObjectSecurityWithTimeout( bufferSize = 0x100; buffer = PhAllocate(bufferSize); // This is required (especially for File objects) because some drivers don't seem to handle - // QuerySecurity properly. + // QuerySecurity properly. (wj32) memset(buffer, 0, bufferSize); status = PhCallNtQuerySecurityObjectWithTimeout( @@ -947,13 +947,17 @@ _Callback_ NTSTATUS PhStdGetObjectSecurity( allocationLength = SECURITY_DESCRIPTOR_MIN_LENGTH + defaultDacl->DefaultDacl->AclSize; - securityDescriptor = PhAllocateZero(PAGE_SIZE); + securityDescriptor = PhAllocateZero(allocationLength); RtlCreateSecurityDescriptor(securityDescriptor, SECURITY_DESCRIPTOR_REVISION); RtlSetDaclSecurityDescriptor(securityDescriptor, TRUE, defaultDacl->DefaultDacl, FALSE); assert(allocationLength == RtlLengthSecurityDescriptor(securityDescriptor)); - *SecurityDescriptor = securityDescriptor; + *SecurityDescriptor = PhAllocateCopy( + securityDescriptor, + RtlLengthSecurityDescriptor(securityDescriptor) + ); + PhFree(securityDescriptor); } if (defaultDacl) From 877f3929c2db56c8c230aabc2972848c4ec6a8ec Mon Sep 17 00:00:00 2001 From: Xiaoyin Liu Date: Wed, 3 Apr 2019 19:03:31 +0200 Subject: [PATCH 1768/2058] Don't prepend "Computer" when open key (#402) When user clicks "Open key", the key name is prepended "Computer", but Regedit doesn't recognize "Computer" if the system locale is not English. --- ProcessHacker/appsup.c | 2 +- phlib/util.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ProcessHacker/appsup.c b/ProcessHacker/appsup.c index 25e62c21d415..a983649203e0 100644 --- a/ProcessHacker/appsup.c +++ b/ProcessHacker/appsup.c @@ -2074,7 +2074,7 @@ BOOLEAN PhShellOpenKey2( RtlInitUnicodeString(&valueName, favoriteName); PhUnicodeStringToStringRef(&valueName, &valueNameSr); - expandedKeyName = PhExpandKeyName(KeyName, TRUE); + expandedKeyName = PhExpandKeyName(KeyName, FALSE); NtSetValueKey(favoritesKeyHandle, &valueName, 0, REG_SZ, expandedKeyName->Buffer, (ULONG)expandedKeyName->Length + sizeof(UNICODE_NULL)); PhDereferenceObject(expandedKeyName); diff --git a/phlib/util.c b/phlib/util.c index 8689d3936a27..f07755c4141a 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -3528,7 +3528,7 @@ VOID PhShellOpenKey( return; RtlInitUnicodeString(&valueName, L"LastKey"); - lastKey = PhExpandKeyName(KeyName, TRUE); + lastKey = PhExpandKeyName(KeyName, FALSE); NtSetValueKey(regeditKeyHandle, &valueName, 0, REG_SZ, lastKey->Buffer, (ULONG)lastKey->Length + sizeof(UNICODE_NULL)); PhDereferenceObject(lastKey); From 744b5f88f9dfc2f0ff329ae788dc5a4cf30328a8 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 3 Apr 2019 19:58:15 +0200 Subject: [PATCH 1769/2058] Fix build errror from commit 22d21206 --- ProcessHacker/actions.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ProcessHacker/actions.c b/ProcessHacker/actions.c index 699bc54396b2..097ae748e0dd 100644 --- a/ProcessHacker/actions.c +++ b/ProcessHacker/actions.c @@ -431,7 +431,7 @@ BOOLEAN PhUiConnectToPhSvcEx( { PhAcquireQueuedLockExclusive(&PhSvcStartLock); - if (_InterlockedExchange(PhSvcReferenceCount, 0) == 0) + if (_InterlockedExchange(&PhSvcReferenceCount, 0) == 0) { started = FALSE; PhpGetPhSvcPortName(Mode, &portName); From 483ce6112903733239400617f3df9f27d217291d Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 3 Apr 2019 20:23:43 +0200 Subject: [PATCH 1770/2058] DotNetTools: Remove legacy code --- plugins/DotNetTools/counters.c | 27 ++------------------------- 1 file changed, 2 insertions(+), 25 deletions(-) diff --git a/plugins/DotNetTools/counters.c b/plugins/DotNetTools/counters.c index f2b1d8f7e549..f1b53cae3ccb 100644 --- a/plugins/DotNetTools/counters.c +++ b/plugins/DotNetTools/counters.c @@ -537,33 +537,10 @@ BOOLEAN OpenDotNetPublicControlBlock_V4( if (WINDOWS_HAS_IMMERSIVE && IsImmersive) { - if (NT_SUCCESS(NtOpenProcessToken(ProcessHandle, TOKEN_QUERY, &tokenHandle))) + if (NT_SUCCESS(PhOpenProcessToken(ProcessHandle, TOKEN_QUERY, &tokenHandle))) { - ULONG returnLength = 0; - - if (NtQueryInformationToken( - tokenHandle, - TokenAppContainerSid, - NULL, - 0, - &returnLength - ) != STATUS_BUFFER_TOO_SMALL) - { + if (!NT_SUCCESS(PhQueryTokenVariableSize(tokenHandle, TokenAppContainerSid, &appContainerInfo))) goto CleanupExit; - } - - appContainerInfo = PhAllocate(returnLength); - - if (!NT_SUCCESS(NtQueryInformationToken( - tokenHandle, - TokenAppContainerSid, - appContainerInfo, - returnLength, - &returnLength - ))) - { - goto CleanupExit; - } if (!NT_SUCCESS(RtlAddSIDToBoundaryDescriptor(&boundaryDescriptorHandle, appContainerInfo->TokenAppContainer))) goto CleanupExit; From 9bb1cd2bf1b26d426ba6c2c50e06086865df652a Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 5 Apr 2019 19:17:12 +0200 Subject: [PATCH 1771/2058] Add setting to disable Linux subystem support #393 --- ProcessHacker/include/phsettings.h | 1 + ProcessHacker/mainwnd.c | 1 + ProcessHacker/procprv.c | 2 +- ProcessHacker/settings.c | 1 + 4 files changed, 4 insertions(+), 1 deletion(-) diff --git a/ProcessHacker/include/phsettings.h b/ProcessHacker/include/phsettings.h index 44efb3517bb7..82efa0913059 100644 --- a/ProcessHacker/include/phsettings.h +++ b/ProcessHacker/include/phsettings.h @@ -15,6 +15,7 @@ EXT BOOLEAN PhEnableProcessQueryStage2; EXT BOOLEAN PhEnableServiceQueryStage2; EXT BOOLEAN PhEnableThemeSupport; EXT BOOLEAN PhEnableTooltipSupport; +EXT BOOLEAN PhEnableLinuxSubsystemSupport; EXT ULONG PhCsCollapseServicesOnStart; EXT ULONG PhCsForceNoParent; diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index a6d7bbb5994e..f71677736f23 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -2198,6 +2198,7 @@ VOID PhMwpLoadSettings( PhEnableServiceQueryStage2 = !!PhGetIntegerSetting(L"EnableServiceStage2"); PhEnableThemeSupport = !!PhGetIntegerSetting(L"EnableThemeSupport"); PhEnableTooltipSupport = !!PhGetIntegerSetting(L"EnableTooltipSupport"); + PhEnableLinuxSubsystemSupport = !!PhGetIntegerSetting(L"EnableLinuxSubsystemSupport"); PhMwpNotifyIconNotifyMask = PhGetIntegerSetting(L"IconNotifyMask"); if (PhGetIntegerSetting(L"MainWindowAlwaysOnTop")) diff --git a/ProcessHacker/procprv.c b/ProcessHacker/procprv.c index 68223e832dde..a8161478188c 100644 --- a/ProcessHacker/procprv.c +++ b/ProcessHacker/procprv.c @@ -939,7 +939,7 @@ VOID PhpProcessQueryStage2( } } - if (PhEnableProcessQueryStage2 && processItem->FileName && processItem->IsSubsystemProcess) + if (PhEnableLinuxSubsystemSupport && processItem->FileName && processItem->IsSubsystemProcess) { PhInitializeImageVersionInfoCached(&Data->VersionInfo, processItem->FileName, TRUE); } diff --git a/ProcessHacker/settings.c b/ProcessHacker/settings.c index efe250240565..3e977293ed29 100644 --- a/ProcessHacker/settings.c +++ b/ProcessHacker/settings.c @@ -55,6 +55,7 @@ VOID PhAddDefaultSettings( PhpAddIntegerSetting(L"EnableThemeSupport", L"0"); PhpAddIntegerSetting(L"EnableTooltipSupport", L"1"); PhpAddIntegerSetting(L"EnableSecurityAdvancedDialog", L"1"); + PhpAddIntegerSetting(L"EnableLinuxSubsystemSupport", L"1"); PhpAddStringSetting(L"EnvironmentTreeListColumns", L""); PhpAddStringSetting(L"EnvironmentTreeListSort", L"0,0"); // 0, NoSortOrder PhpAddIntegerSetting(L"EnvironmentTreeListFlags", L"0"); From 70e4567d8e594980751a1ce644d9e93416eaa1fb Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 5 Apr 2019 20:34:27 +0200 Subject: [PATCH 1772/2058] Add setting for disabling linux support to options window #393 --- ProcessHacker/options.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/ProcessHacker/options.c b/ProcessHacker/options.c index 4b83df6392a0..8f6aaf890948 100644 --- a/ProcessHacker/options.c +++ b/ProcessHacker/options.c @@ -3,7 +3,7 @@ * options window * * Copyright (C) 2010-2016 wj32 - * Copyright (C) 2017-2018 dmex + * Copyright (C) 2017-2019 dmex * * This file is part of Process Hacker. * @@ -996,6 +996,7 @@ typedef enum _PHP_OPTIONS_INDEX PHP_OPTIONS_INDEX_ENABLE_UNDECORATE_SYMBOLS, PHP_OPTIONS_INDEX_ENABLE_CYCLE_CPU_USAGE, PHP_OPTIONS_INDEX_ENABLE_THEME_SUPPORT, + PHP_OPTIONS_INDEX_ENABLE_LINUX_SUPPORT, PHP_OPTIONS_INDEX_ENABLE_NETWORK_RESOLVE, PHP_OPTIONS_INDEX_ENABLE_INSTANT_TOOLTIPS, PHP_OPTIONS_INDEX_ENABLE_STAGE2, @@ -1033,6 +1034,7 @@ static VOID PhpAdvancedPageLoad( PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_UNDECORATE_SYMBOLS, L"Enable undecorated symbols", NULL); PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_CYCLE_CPU_USAGE, L"Enable cycle-based CPU usage", NULL); PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_THEME_SUPPORT, L"Enable theme support (experimental)", NULL); + PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_LINUX_SUPPORT, L"Enable Windows subsystem for Linux support", NULL); PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_NETWORK_RESOLVE, L"Resolve network addresses", NULL); PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_INSTANT_TOOLTIPS, L"Show tooltips instantly", NULL); PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_STAGE2, L"Check images for digital signatures", NULL); @@ -1054,6 +1056,7 @@ static VOID PhpAdvancedPageLoad( SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_UNDECORATE_SYMBOLS, L"DbgHelpUndecorate"); SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_CYCLE_CPU_USAGE, L"EnableCycleCpuUsage"); SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_THEME_SUPPORT, L"EnableThemeSupport"); + SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_LINUX_SUPPORT, L"EnableLinuxSubsystemSupport"); SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_NETWORK_RESOLVE, L"EnableNetworkResolve"); SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_INSTANT_TOOLTIPS, L"EnableInstantTooltips"); SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_STAGE2, L"EnableStage2"); @@ -1145,6 +1148,7 @@ static VOID PhpAdvancedPageSave( SetSettingForLvItemCheck(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_UNDECORATE_SYMBOLS, L"DbgHelpUndecorate"); SetSettingForLvItemCheckRestartRequired(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_CYCLE_CPU_USAGE, L"EnableCycleCpuUsage"); SetSettingForLvItemCheckRestartRequired(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_THEME_SUPPORT, L"EnableThemeSupport"); + SetSettingForLvItemCheckRestartRequired(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_LINUX_SUPPORT, L"EnableLinuxSubsystemSupport"); SetSettingForLvItemCheckRestartRequired(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_NETWORK_RESOLVE, L"EnableNetworkResolve"); SetSettingForLvItemCheck(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_INSTANT_TOOLTIPS, L"EnableInstantTooltips"); SetSettingForLvItemCheckRestartRequired(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_STAGE2, L"EnableStage2"); From bf67024caa38f75650f29f013391fa3a13d2c2cf Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 5 Apr 2019 21:01:16 +0200 Subject: [PATCH 1773/2058] Remove legacy code, Add PhSetDebugKillProcessOnExit --- ProcessHacker/actions.c | 17 +++++-------- ProcessHacker/appsup.c | 49 +++++++++++++++++-------------------- phlib/include/phnativeinl.h | 20 +++++++++++++++ phlib/include/phutil.h | 4 ++- 4 files changed, 52 insertions(+), 38 deletions(-) diff --git a/ProcessHacker/actions.c b/ProcessHacker/actions.c index 097ae748e0dd..56a7fbf40401 100644 --- a/ProcessHacker/actions.c +++ b/ProcessHacker/actions.c @@ -1716,19 +1716,14 @@ BOOLEAN PhUiDetachFromDebuggerProcess( &debugObjectHandle ))) { - ULONG killProcessOnExit; - // Disable kill-on-close. - killProcessOnExit = 0; - NtSetInformationDebugObject( + if (NT_SUCCESS(status = PhSetDebugKillProcessOnExit( debugObjectHandle, - DebugObjectKillProcessOnExitInformation, - &killProcessOnExit, - sizeof(ULONG), - NULL - ); - - status = NtRemoveProcessDebug(processHandle, debugObjectHandle); + FALSE + ))) + { + status = NtRemoveProcessDebug(processHandle, debugObjectHandle); + } NtClose(debugObjectHandle); } diff --git a/ProcessHacker/appsup.c b/ProcessHacker/appsup.c index a983649203e0..d5cefa8a6b9d 100644 --- a/ProcessHacker/appsup.c +++ b/ProcessHacker/appsup.c @@ -1315,8 +1315,7 @@ BOOLEAN PhCreateProcessIgnoreIfeoDebugger( { BOOLEAN result; BOOLEAN originalValue; - STARTUPINFO startupInfo; - PROCESS_INFORMATION processInfo; + HANDLE processHandle; result = FALSE; @@ -1325,47 +1324,45 @@ BOOLEAN PhCreateProcessIgnoreIfeoDebugger( NtCurrentPeb()->ReadImageFileExecOptions = FALSE; RtlLeaveCriticalSection(NtCurrentPeb()->FastPebLock); - memset(&startupInfo, 0, sizeof(STARTUPINFO)); - startupInfo.cb = sizeof(STARTUPINFO); - memset(&processInfo, 0, sizeof(PROCESS_INFORMATION)); - // The combination of ReadImageFileExecOptions = FALSE and the DEBUG_PROCESS flag - // allows us to skip the Debugger IFEO value. - if (CreateProcess(FileName, NULL, NULL, NULL, FALSE, DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS, NULL, NULL, &startupInfo, &processInfo)) + // allows us to skip the Debugger IFEO value. (wj32) + + if (NT_SUCCESS(PhCreateProcessWin32( + FileName, + NULL, + NULL, + NULL, + PH_CREATE_PROCESS_DEBUG | PH_CREATE_PROCESS_DEBUG_ONLY_THIS_PROCESS, + NULL, + &processHandle, + NULL + ))) { HANDLE debugObjectHandle; if (NT_SUCCESS(PhGetProcessDebugObject( - processInfo.hProcess, + processHandle, &debugObjectHandle ))) { - ULONG killProcessOnExit; - // Disable kill-on-close. - killProcessOnExit = 0; - NtSetInformationDebugObject( + if (NT_SUCCESS(PhSetDebugKillProcessOnExit( debugObjectHandle, - DebugObjectKillProcessOnExitInformation, - &killProcessOnExit, - sizeof(ULONG), - NULL - ); - - // Stop debugging the process now. - NtRemoveProcessDebug(processInfo.hProcess, debugObjectHandle); + FALSE + ))) + { + // Stop debugging the process now. + NtRemoveProcessDebug(processHandle, debugObjectHandle); + } NtClose(debugObjectHandle); } result = TRUE; + + NtClose(processHandle); } - if (processInfo.hProcess) - NtClose(processInfo.hProcess); - if (processInfo.hThread) - NtClose(processInfo.hThread); - if (originalValue) { RtlEnterCriticalSection(NtCurrentPeb()->FastPebLock); diff --git a/phlib/include/phnativeinl.h b/phlib/include/phnativeinl.h index 664b8eb17368..d5d28d0667d7 100644 --- a/phlib/include/phnativeinl.h +++ b/phlib/include/phnativeinl.h @@ -1536,4 +1536,24 @@ PhGetTimerBasicInformation( ); } +FORCEINLINE +NTSTATUS +PhSetDebugKillProcessOnExit( + _In_ HANDLE DebugObjectHandle, + _In_ BOOLEAN KillProcessOnExit + ) +{ + ULONG killProcessOnExit; + + killProcessOnExit = KillProcessOnExit ? 1 : 0; + + return NtSetInformationDebugObject( + DebugObjectHandle, + DebugObjectKillProcessOnExitInformation, + &killProcessOnExit, + sizeof(ULONG), + NULL + ); +} + #endif diff --git a/phlib/include/phutil.h b/phlib/include/phutil.h index dee0fad155fa..415d54629afa 100644 --- a/phlib/include/phutil.h +++ b/phlib/include/phutil.h @@ -690,7 +690,9 @@ typedef struct _PH_CREATE_PROCESS_INFO #define PH_CREATE_PROCESS_SUSPENDED 0x4 #define PH_CREATE_PROCESS_BREAKAWAY_FROM_JOB 0x8 #define PH_CREATE_PROCESS_NEW_CONSOLE 0x10 -#define PH_CREATE_PROCESS_EXTENDED_STARTUPINFO 0x20 +#define PH_CREATE_PROCESS_DEBUG 0x20 +#define PH_CREATE_PROCESS_DEBUG_ONLY_THIS_PROCESS 0x40 +#define PH_CREATE_PROCESS_EXTENDED_STARTUPINFO 0x80 PHLIBAPI NTSTATUS From cc442f50909c4760212f46b66b26d52a5ced64d3 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 5 Apr 2019 21:50:49 +0200 Subject: [PATCH 1774/2058] Fix build, Fix service properties crash/regression --- ProcessHacker/srvprp.c | 3 +++ phlib/util.c | 4 +++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/ProcessHacker/srvprp.c b/ProcessHacker/srvprp.c index 69ef4d0ec0db..287f85a3632f 100644 --- a/ProcessHacker/srvprp.c +++ b/ProcessHacker/srvprp.c @@ -188,6 +188,8 @@ NTSTATUS PhpShowServicePropertiesThread( PhModalPropertySheet(&propSheetHeader); + PhDereferenceObject(serviceItem); + return STATUS_SUCCESS; } @@ -196,6 +198,7 @@ VOID PhShowServiceProperties( _In_ PPH_SERVICE_ITEM ServiceItem ) { + PhReferenceObject(ServiceItem); PhCreateThread2(PhpShowServicePropertiesThread, ServiceItem); } diff --git a/phlib/util.c b/phlib/util.c index f07755c4141a..b56a40d10aba 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -2606,6 +2606,8 @@ static const PH_FLAG_MAPPING PhpCreateProcessMappings[] = { PH_CREATE_PROCESS_SUSPENDED, CREATE_SUSPENDED }, { PH_CREATE_PROCESS_BREAKAWAY_FROM_JOB, CREATE_BREAKAWAY_FROM_JOB }, { PH_CREATE_PROCESS_NEW_CONSOLE, CREATE_NEW_CONSOLE }, + { PH_CREATE_PROCESS_DEBUG, DEBUG_PROCESS }, + { PH_CREATE_PROCESS_DEBUG_ONLY_THIS_PROCESS, DEBUG_ONLY_THIS_PROCESS }, { PH_CREATE_PROCESS_EXTENDED_STARTUPINFO, EXTENDED_STARTUPINFO_PRESENT } }; @@ -5374,7 +5376,7 @@ BOOLEAN PhLoadResource( if (!NT_SUCCESS(LdrFindResource_U(DllBase, &resourceInfo, RESOURCE_DATA_LEVEL, &resourceData))) return FALSE; - if (!NT_SUCCESS(PhAccessResource(DllBase, resourceData, &resourceBuffer, &resourceLength))) + if (!NT_SUCCESS(LdrAccessResource(DllBase, resourceData, &resourceBuffer, &resourceLength))) return FALSE; if (ResourceLength) From fd1fd775dc868c91067e98a9d396f99f874ef617 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 5 Apr 2019 23:36:46 +0200 Subject: [PATCH 1775/2058] Improve searchbox GDI usage, Improve searchbox dark theme --- ProcessHacker/searchbox.c | 195 ++++++++++++++++++++++++++++++-------- phlib/theme.c | 4 + 2 files changed, 158 insertions(+), 41 deletions(-) diff --git a/ProcessHacker/searchbox.c b/ProcessHacker/searchbox.c index 7689f0ab8216..686d4920d371 100644 --- a/ProcessHacker/searchbox.c +++ b/ProcessHacker/searchbox.c @@ -37,7 +37,8 @@ typedef struct _EDIT_CONTEXT ULONG ThemeSupport : 1; ULONG Hot : 1; ULONG Pushed : 1; - ULONG Spare : 29; + ULONG ColorMode : 8; + ULONG Spare : 21; }; }; @@ -48,8 +49,7 @@ typedef struct _EDIT_CONTEXT HWND WindowHandle; WNDPROC DefaultWindowProc; HFONT WindowFont; - HICON BitmapActive; - HICON BitmapInactive; + HIMAGELIST ImageListHandle; HBRUSH BrushNormal; HBRUSH BrushPushed; HBRUSH BrushHot; @@ -93,6 +93,7 @@ VOID PhpSearchInitializeTheme( Context->BrushNormal = GetSysColorBrush(COLOR_WINDOW); Context->BrushHot = CreateSolidBrush(RGB(205, 232, 255)); Context->BrushPushed = CreateSolidBrush(RGB(153, 209, 255)); + Context->ColorMode = PhGetIntegerSetting(L"GraphColorMode"); if (IsThemeActive()) { @@ -134,27 +135,33 @@ VOID PhpSearchInitializeImages( Context->ImageWidth = GetSystemMetrics(SM_CXSMICON) + 4; Context->ImageHeight = GetSystemMetrics(SM_CYSMICON) + 4; + Context->ImageListHandle = ImageList_Create( + Context->ImageWidth, + Context->ImageHeight, + ILC_COLOR32, + 2, + 0 + ); + ImageList_SetImageCount(Context->ImageListHandle, 2); if (bitmap = PhLoadPngImageFromResource(PhInstanceHandle, Context->ImageWidth, Context->ImageHeight, MAKEINTRESOURCE(IDB_SEARCH_ACTIVE), TRUE)) { - Context->BitmapActive = PhpSearchBitmapToIcon(bitmap, Context->ImageWidth, Context->ImageHeight); + ImageList_Replace(Context->ImageListHandle, 0, bitmap, NULL); DeleteObject(bitmap); } - else if (bitmap = LoadImage(PhInstanceHandle, MAKEINTRESOURCE(IDB_SEARCH_ACTIVE_BMP), IMAGE_BITMAP, 0, 0, 0)) + else { - Context->BitmapActive = PhpSearchBitmapToIcon(bitmap, Context->ImageWidth, Context->ImageHeight); - DeleteObject(bitmap); + PhSetImageListBitmap(Context->ImageListHandle, 0, PhInstanceHandle, MAKEINTRESOURCE(IDB_SEARCH_ACTIVE_BMP)); } if (bitmap = PhLoadPngImageFromResource(PhInstanceHandle, Context->ImageWidth, Context->ImageHeight, MAKEINTRESOURCE(IDB_SEARCH_INACTIVE), TRUE)) { - Context->BitmapInactive = PhpSearchBitmapToIcon(bitmap, Context->ImageWidth, Context->ImageHeight); + ImageList_Replace(Context->ImageListHandle, 1, bitmap, NULL); DeleteObject(bitmap); } - else if (bitmap = LoadImage(PhInstanceHandle, MAKEINTRESOURCE(IDB_SEARCH_INACTIVE_BMP), IMAGE_BITMAP, 0, 0, 0)) + else { - Context->BitmapInactive = PhpSearchBitmapToIcon(bitmap, Context->ImageWidth, Context->ImageHeight); - DeleteObject(bitmap); + PhSetImageListBitmap(Context->ImageListHandle, 1, PhInstanceHandle, MAKEINTRESOURCE(IDB_SEARCH_INACTIVE_BMP)); } } @@ -195,45 +202,91 @@ VOID PhpSearchDrawButton( if (Context->Pushed) { - FillRect(bufferDc, &bufferRect, Context->BrushPushed); - //FrameRect(bufferDc, &bufferRect, CreateSolidBrush(RGB(0xff, 0, 0))); + if (Context->ThemeSupport) + { + switch (Context->ColorMode) + { + case 0: // New colors + FillRect(bufferDc, &bufferRect, Context->BrushPushed); + break; + case 1: // Old colors + SetTextColor(bufferDc, GetSysColor(COLOR_HIGHLIGHTTEXT)); + SetDCBrushColor(bufferDc, RGB(99, 99, 99)); + FillRect(bufferDc, &bufferRect, GetStockObject(DC_BRUSH)); + break; + } + } + else + { + FillRect(bufferDc, &bufferRect, Context->BrushPushed); + //FrameRect(bufferDc, &bufferRect, CreateSolidBrush(RGB(0xff, 0, 0))); + } } else if (Context->Hot) { - FillRect(bufferDc, &bufferRect, Context->BrushHot); - //FrameRect(bufferDc, &bufferRect, CreateSolidBrush(RGB(38, 160, 218))); + if (Context->ThemeSupport) + { + switch (Context->ColorMode) + { + case 0: // New colors + FillRect(bufferDc, &bufferRect, Context->BrushHot); + break; + case 1: // Old colors + SetTextColor(bufferDc, GetSysColor(COLOR_HIGHLIGHTTEXT)); + SetDCBrushColor(bufferDc, RGB(78, 78, 78)); + FillRect(bufferDc, &bufferRect, GetStockObject(DC_BRUSH)); + break; + } + } + else + { + FillRect(bufferDc, &bufferRect, Context->BrushHot); + //FrameRect(bufferDc, &bufferRect, CreateSolidBrush(RGB(38, 160, 218))); + } } else { - FillRect(bufferDc, &bufferRect, Context->BrushNormal); + if (Context->ThemeSupport) + { + switch (Context->ColorMode) + { + case 0: // New colors + FillRect(bufferDc, &bufferRect, Context->BrushNormal); + break; + case 1: // Old colors + SetTextColor(bufferDc, GetSysColor(COLOR_HIGHLIGHTTEXT)); + SetDCBrushColor(bufferDc, RGB(60, 60, 60)); + FillRect(bufferDc, &bufferRect, GetStockObject(DC_BRUSH)); + break; + } + + } + else + { + FillRect(bufferDc, &bufferRect, Context->BrushNormal); + } } if (Edit_GetTextLength(Context->WindowHandle) > 0) { - DrawIconEx( + ImageList_Draw( + Context->ImageListHandle, + 0, bufferDc, bufferRect.left + 1, // offset bufferRect.top, - Context->BitmapActive, - Context->ImageWidth, - Context->ImageHeight, - 0, - NULL, - DI_NORMAL + ILD_TRANSPARENT ); } else { - DrawIconEx( + ImageList_Draw( + Context->ImageListHandle, + 1, bufferDc, bufferRect.left + 2, // offset bufferRect.top + 1, // offset - Context->BitmapInactive, - Context->ImageWidth, - Context->ImageHeight, - 0, - NULL, - DI_NORMAL + ILD_TRANSPARENT ); } @@ -246,21 +299,71 @@ VOID PhpSearchDrawButton( { if (GetFocus() == Context->WindowHandle) { - SetDCBrushColor(hdc, RGB(0x0, 0x66, 0xcc)); + switch (Context->ColorMode) + { + case 0: // New colors + SetDCBrushColor(hdc, RGB(0, 0, 0)); + break; + case 1: // Old colors + SetDCBrushColor(hdc, RGB(65, 65, 65)); + break; + } + SelectObject(hdc, GetStockObject(DC_BRUSH)); - PatBlt(hdc, WindowRect.left, WindowRect.top, 2, WindowRect.bottom - WindowRect.top, PATCOPY); - PatBlt(hdc, WindowRect.right - 2, WindowRect.top, 2, WindowRect.bottom - WindowRect.top, PATCOPY); - PatBlt(hdc, WindowRect.left, WindowRect.top, WindowRect.right - WindowRect.left, 2, PATCOPY); - PatBlt(hdc, WindowRect.left, WindowRect.bottom - 2, WindowRect.right - WindowRect.left, 2, PATCOPY); + PatBlt(hdc, WindowRect.left, WindowRect.top, 1, WindowRect.bottom - WindowRect.top, PATCOPY); + PatBlt(hdc, WindowRect.right - 1, WindowRect.top, 1, WindowRect.bottom - WindowRect.top, PATCOPY); + PatBlt(hdc, WindowRect.left, WindowRect.top, WindowRect.right - WindowRect.left, 1, PATCOPY); + PatBlt(hdc, WindowRect.left, WindowRect.bottom - 1, WindowRect.right - WindowRect.left, 1, PATCOPY); + + switch (Context->ColorMode) + { + case 0: // New colors + SetDCBrushColor(hdc, RGB(0xff, 0xff, 0xff)); + break; + case 1: // Old colors + SetDCBrushColor(hdc, RGB(60, 60, 60)); + break; + } + + SelectObject(hdc, GetStockObject(DC_BRUSH)); + PatBlt(hdc, WindowRect.left + 1, WindowRect.top + 1, 1, WindowRect.bottom - WindowRect.top - 2, PATCOPY); + PatBlt(hdc, WindowRect.right - 2, WindowRect.top + 1, 1, WindowRect.bottom - WindowRect.top - 2, PATCOPY); + PatBlt(hdc, WindowRect.left + 1, WindowRect.top + 1, WindowRect.right - WindowRect.left - 2, 1, PATCOPY); + PatBlt(hdc, WindowRect.left + 1, WindowRect.bottom - 2, WindowRect.right - WindowRect.left - 2, 1, PATCOPY); } else - { - SetDCBrushColor(hdc, RGB(65, 65, 65)); + { + switch (Context->ColorMode) + { + case 0: // New colors + SetDCBrushColor(hdc, RGB(0, 0, 0)); + break; + case 1: // Old colors + SetDCBrushColor(hdc, RGB(65, 65, 65)); + break; + } + + SelectObject(hdc, GetStockObject(DC_BRUSH)); + PatBlt(hdc, WindowRect.left, WindowRect.top, 1, WindowRect.bottom - WindowRect.top, PATCOPY); + PatBlt(hdc, WindowRect.right - 1, WindowRect.top, 1, WindowRect.bottom - WindowRect.top, PATCOPY); + PatBlt(hdc, WindowRect.left, WindowRect.top, WindowRect.right - WindowRect.left, 1, PATCOPY); + PatBlt(hdc, WindowRect.left, WindowRect.bottom - 1, WindowRect.right - WindowRect.left, 1, PATCOPY); + + switch (Context->ColorMode) + { + case 0: // New colors + SetDCBrushColor(hdc, RGB(0xff, 0xff, 0xff)); + break; + case 1: // Old colors + SetDCBrushColor(hdc, RGB(60, 60, 60)); + break; + } + SelectObject(hdc, GetStockObject(DC_BRUSH)); - PatBlt(hdc, WindowRect.left, WindowRect.top, 2, WindowRect.bottom - WindowRect.top, PATCOPY); - PatBlt(hdc, WindowRect.right - 2, WindowRect.top, 2, WindowRect.bottom - WindowRect.top, PATCOPY); - PatBlt(hdc, WindowRect.left, WindowRect.top, WindowRect.right - WindowRect.left, 2, PATCOPY); - PatBlt(hdc, WindowRect.left, WindowRect.bottom - 2, WindowRect.right - WindowRect.left, 2, PATCOPY); + PatBlt(hdc, WindowRect.left + 1, WindowRect.top + 1, 1, WindowRect.bottom - WindowRect.top - 2, PATCOPY); + PatBlt(hdc, WindowRect.right - 2, WindowRect.top + 1, 1, WindowRect.bottom - WindowRect.top - 2, PATCOPY); + PatBlt(hdc, WindowRect.left + 1, WindowRect.top + 1, WindowRect.right - WindowRect.left - 2, 1, PATCOPY); + PatBlt(hdc, WindowRect.left + 1, WindowRect.bottom - 2, WindowRect.right - WindowRect.left - 2, 1, PATCOPY); } } @@ -289,7 +392,16 @@ LRESULT CALLBACK PhpSearchWndSubclassProc( PhpSearchFreeTheme(context); if (context->WindowFont) + { DeleteObject(context->WindowFont); + context->WindowFont = NULL; + } + + if (context->ImageListHandle) + { + ImageList_Destroy(context->ImageListHandle); + context->ImageListHandle = NULL; + } SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)oldWndProc); PhRemoveWindowContext(hWnd, SHRT_MAX); @@ -550,6 +662,7 @@ VOID PhCreateSearchControl( context->WindowHandle = WindowHandle; context->ThemeSupport = !!PhGetIntegerSetting(L"EnableThemeSupport"); // HACK + context->ColorMode = PhGetIntegerSetting(L"GraphColorMode"); //PhpSearchInitializeTheme(context); PhpSearchInitializeImages(context); diff --git a/phlib/theme.c b/phlib/theme.c index 69bfea64ccdb..66aa788d4211 100644 --- a/phlib/theme.c +++ b/phlib/theme.c @@ -598,6 +598,10 @@ BOOLEAN CALLBACK PhpReInitializeThemeWindowEnumChildWindows( break; } } + else if (PhEqualStringZ(windowClassName, L"Edit", FALSE)) + { + SendMessage(WindowHandle, WM_THEMECHANGED, 0, 0); // searchbox.c + } InvalidateRect(WindowHandle, NULL, TRUE); From dad517b0445069e27a4e96f1d6b53884c458cd49 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 5 Apr 2019 23:40:52 +0200 Subject: [PATCH 1776/2058] peview: Add program icon (fixes random pinned shell icon corruption on win10) --- tools/peview/peview.rc | 10 ++++++++++ tools/peview/peview.vcxproj | 1 + tools/peview/peview.vcxproj.filters | 3 +++ tools/peview/resource.h | 3 ++- tools/peview/resources/application.ico | Bin 0 -> 45289 bytes 5 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 tools/peview/resources/application.ico diff --git a/tools/peview/peview.rc b/tools/peview/peview.rc index 0c69d66339d0..2e9ea1bed7c1 100644 --- a/tools/peview/peview.rc +++ b/tools/peview/peview.rc @@ -441,6 +441,16 @@ BEGIN END END + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_APPICON ICON "resources\\application.ico" + #endif // English (Australia) resources ///////////////////////////////////////////////////////////////////////////// diff --git a/tools/peview/peview.vcxproj b/tools/peview/peview.vcxproj index 649231cfe9d6..e722e8408f3a 100644 --- a/tools/peview/peview.vcxproj +++ b/tools/peview/peview.vcxproj @@ -268,6 +268,7 @@ + diff --git a/tools/peview/peview.vcxproj.filters b/tools/peview/peview.vcxproj.filters index 09b75161567c..c7bc25dca9b7 100644 --- a/tools/peview/peview.vcxproj.filters +++ b/tools/peview/peview.vcxproj.filters @@ -146,5 +146,8 @@ Resource Files + + Resource Files + \ No newline at end of file diff --git a/tools/peview/resource.h b/tools/peview/resource.h index e492b1f01bdc..6028d8b84447 100644 --- a/tools/peview/resource.h +++ b/tools/peview/resource.h @@ -24,6 +24,7 @@ #define IDD_ELFDYNAMIC 116 #define IDD_TLS 117 #define IDC_SYMBOLTREE 119 +#define IDI_APPICON 122 #define IDC_TARGETMACHINE 1003 #define IDC_CHECKSUM 1004 #define IDC_SUBSYSTEM 1005 @@ -50,7 +51,7 @@ // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 122 +#define _APS_NEXT_RESOURCE_VALUE 123 #define _APS_NEXT_COMMAND_VALUE 40001 #define _APS_NEXT_CONTROL_VALUE 1023 #define _APS_NEXT_SYMED_VALUE 115 diff --git a/tools/peview/resources/application.ico b/tools/peview/resources/application.ico new file mode 100644 index 0000000000000000000000000000000000000000..c31fc6534c6408224b56fef68d0286d908199fa0 GIT binary patch literal 45289 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 literal 0 HcmV?d00001 From f3b2255519ac97e325a30a5035526c8a9802c8cf Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 5 Apr 2019 23:58:53 +0200 Subject: [PATCH 1777/2058] Add Win10 uptime stats to process statistics tab --- ProcessHacker/prpgstat.c | 45 +++++++++++++++++++++++++++++++++---- phlib/include/phnativeinl.h | 26 +++++++++++++++++++++ 2 files changed, 67 insertions(+), 4 deletions(-) diff --git a/ProcessHacker/prpgstat.c b/ProcessHacker/prpgstat.c index cc4a68c41979..8ea49a6fb631 100644 --- a/ProcessHacker/prpgstat.c +++ b/ProcessHacker/prpgstat.c @@ -85,6 +85,11 @@ typedef enum _PH_PROCESS_STATISTICS_INDEX PH_PROCESS_STATISTICS_INDEX_GDIHANDLES, PH_PROCESS_STATISTICS_INDEX_USERHANDLES, + PH_PROCESS_STATISTICS_INDEX_RUNNINGTIME, + PH_PROCESS_STATISTICS_INDEX_SUSPENDEDTIME, + PH_PROCESS_STATISTICS_INDEX_HANGCOUNT, + PH_PROCESS_STATISTICS_INDEX_GHOSTCOUNT, + PH_PROCESS_STATISTICS_INDEX_CONTEXTSWITCHES, PH_PROCESS_STATISTICS_INDEX_DISKREAD, PH_PROCESS_STATISTICS_INDEX_DISKWRITE, @@ -141,13 +146,21 @@ VOID PhpUpdateStatisticsAddListViewGroups( PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_IO, PH_PROCESS_STATISTICS_INDEX_OTHERDELTA, L"Other delta", NULL); PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_IO, PH_PROCESS_STATISTICS_INDEX_OTHERBYTES, L"Other bytes", NULL); PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_IO, PH_PROCESS_STATISTICS_INDEX_OTHERBYTESDELTA, L"Other bytes delta", NULL); - PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_IO, PH_PROCESS_STATISTICS_INDEX_IOPRIORITY, L"I/O priority", NULL); + PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_OTHER, PH_PROCESS_STATISTICS_INDEX_HANDLES, L"Handles", NULL); PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_OTHER, PH_PROCESS_STATISTICS_INDEX_PEAKHANDLES, L"Peak handles", NULL); PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_OTHER, PH_PROCESS_STATISTICS_INDEX_GDIHANDLES, L"GDI handles", NULL); PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_OTHER, PH_PROCESS_STATISTICS_INDEX_USERHANDLES, L"USER handles", NULL); + if (WindowsVersion >= WINDOWS_10_RS3) + { + PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_OTHER, PH_PROCESS_STATISTICS_INDEX_RUNNINGTIME, L"Running time", NULL); + PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_OTHER, PH_PROCESS_STATISTICS_INDEX_SUSPENDEDTIME, L"Suspended time", NULL); + PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_OTHER, PH_PROCESS_STATISTICS_INDEX_HANGCOUNT, L"Hang count", NULL); + PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_OTHER, PH_PROCESS_STATISTICS_INDEX_GHOSTCOUNT, L"Ghost count", NULL); + } + if (WindowsVersion >= WINDOWS_10_RS3 && !PhIsExecutingInWow64()) { PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_EXTENSION, PH_PROCESS_STATISTICS_INDEX_CONTEXTSWITCHES, L"ContextSwitches", NULL); @@ -281,11 +294,18 @@ VOID PhpUpdateProcessStatistics( PPH_STRING sharedWs = NULL; BOOLEAN gotCycles = FALSE; BOOLEAN gotWsCounters = FALSE; + BOOLEAN gotUptime = FALSE; + ULONG hangCount = 0; + ULONG ghostCount = 0; + ULONGLONG runningTime = 0; + ULONGLONG suspendedTime = 0; + WCHAR timeSpan[PH_TIMESPAN_STR_LEN_1] = L""; if (ProcessItem->QueryHandle) { ULONG64 cycleTime; PROCESS_HANDLE_INFORMATION handleInfo; + PROCESS_UPTIME_INFORMATION uptimeInfo; if (NT_SUCCESS(PhGetProcessHandleCount(ProcessItem->QueryHandle, &handleInfo))) { @@ -303,6 +323,15 @@ VOID PhpUpdateProcessStatistics( PhGetProcessPagePriority(ProcessItem->QueryHandle, &pagePriority); PhGetProcessIoPriority(ProcessItem->QueryHandle, &ioPriority); + + if (WindowsVersion >= WINDOWS_10_RS3 && NT_SUCCESS(PhGetProcessUptime(ProcessItem->QueryHandle, &uptimeInfo))) + { + runningTime = uptimeInfo.Uptime; + suspendedTime = uptimeInfo.SuspendedTime; + hangCount = uptimeInfo.HangCount; + ghostCount = uptimeInfo.GhostCount; + gotUptime = TRUE; + } } if (Context->ProcessHandle) @@ -342,6 +371,16 @@ VOID PhpUpdateProcessStatistics( PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_PEAKHANDLES, 1, PhGetStringOrDefault(peakHandles, L"N/A")); PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_GDIHANDLES, 1, PhGetStringOrDefault(gdiHandles, L"N/A")); PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_USERHANDLES, 1, PhGetStringOrDefault(userHandles, L"N/A")); + + if (WindowsVersion >= WINDOWS_10_RS3) + { + PhPrintTimeSpan(timeSpan, runningTime, PH_TIMESPAN_HMSM); + PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_RUNNINGTIME, 1, timeSpan); + PhPrintTimeSpan(timeSpan, suspendedTime, PH_TIMESPAN_HMSM); + PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_SUSPENDEDTIME, 1, timeSpan); + PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_HANGCOUNT, 1, PhaFormatUInt64(hangCount, TRUE)->Buffer); + PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_GHOSTCOUNT, 1, PhaFormatUInt64(ghostCount, TRUE)->Buffer); + } } if (WindowsVersion >= WINDOWS_10_RS3 && !PhIsExecutingInWow64()) @@ -404,9 +443,7 @@ INT_PTR CALLBACK PhpProcessStatisticsDlgProc( { case WM_INITDIALOG: { - statisticsContext = propPageContext->Context = PhAllocate(sizeof(PH_STATISTICS_CONTEXT)); - memset(statisticsContext, 0, sizeof(PH_STATISTICS_CONTEXT)); - + statisticsContext = propPageContext->Context = PhAllocateZero(sizeof(PH_STATISTICS_CONTEXT)); statisticsContext->WindowHandle = hwndDlg; statisticsContext->ListViewHandle = GetDlgItem(hwndDlg, IDC_STATISTICS_LIST); statisticsContext->Enabled = TRUE; diff --git a/phlib/include/phnativeinl.h b/phlib/include/phnativeinl.h index d5d28d0667d7..aa6021d2de62 100644 --- a/phlib/include/phnativeinl.h +++ b/phlib/include/phnativeinl.h @@ -452,6 +452,32 @@ PhGetProcessCycleTime( return status; } +FORCEINLINE +NTSTATUS +PhGetProcessUptime( + _In_ HANDLE ProcessHandle, + _Out_ PPROCESS_UPTIME_INFORMATION Uptime + ) +{ + NTSTATUS status; + PROCESS_UPTIME_INFORMATION uptimeInfo; + + status = NtQueryInformationProcess( + ProcessHandle, + ProcessUptimeInformation, + &uptimeInfo, + sizeof(PROCESS_UPTIME_INFORMATION), + NULL + ); + + if (!NT_SUCCESS(status)) + return status; + + *Uptime = uptimeInfo; + + return status; +} + FORCEINLINE NTSTATUS PhGetProcessConsoleHostProcessId( From 25fe6072d4561fd7fcb2f8c0715d776a3407956f Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 5 Apr 2019 23:59:12 +0200 Subject: [PATCH 1778/2058] Improve macro usage --- ProcessHacker/procprv.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/ProcessHacker/procprv.c b/ProcessHacker/procprv.c index a8161478188c..70d7c85381ca 100644 --- a/ProcessHacker/procprv.c +++ b/ProcessHacker/procprv.c @@ -776,7 +776,7 @@ VOID PhpProcessQueryStage1( // can't display them, we'll replace them with spaces. for (ULONG i = 0; i < (ULONG)commandLine->Length / sizeof(WCHAR); i++) { - if (commandLine->Buffer[i] == 0) + if (commandLine->Buffer[i] == UNICODE_NULL) commandLine->Buffer[i] = ' '; } @@ -949,11 +949,10 @@ NTSTATUS PhpProcessQueryStage1Worker( _In_ PVOID Parameter ) { - PPH_PROCESS_QUERY_S1_DATA data; PPH_PROCESS_ITEM processItem = (PPH_PROCESS_ITEM)Parameter; + PPH_PROCESS_QUERY_S1_DATA data; - data = PhAllocate(sizeof(PH_PROCESS_QUERY_S1_DATA)); - memset(data, 0, sizeof(PH_PROCESS_QUERY_S1_DATA)); + data = PhAllocateZero(sizeof(PH_PROCESS_QUERY_S1_DATA)); data->Header.Stage = 1; data->Header.ProcessItem = processItem; @@ -968,11 +967,10 @@ NTSTATUS PhpProcessQueryStage2Worker( _In_ PVOID Parameter ) { - PPH_PROCESS_QUERY_S2_DATA data; PPH_PROCESS_ITEM processItem = (PPH_PROCESS_ITEM)Parameter; + PPH_PROCESS_QUERY_S2_DATA data; - data = PhAllocate(sizeof(PH_PROCESS_QUERY_S2_DATA)); - memset(data, 0, sizeof(PH_PROCESS_QUERY_S2_DATA)); + data = PhAllocateZero(sizeof(PH_PROCESS_QUERY_S2_DATA)); data->Header.Stage = 2; data->Header.ProcessItem = processItem; From 7ff7e84d6115fd7b97a28b58e5524197b2314e40 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 6 Apr 2019 00:01:51 +0200 Subject: [PATCH 1779/2058] Add filter options to threads tab --- ProcessHacker/include/thrdlist.h | 37 +++++++++++++++-- ProcessHacker/prpgthrd.c | 58 +++++++++++++++++++++++++++ ProcessHacker/settings.c | 1 + ProcessHacker/thrdlist.c | 68 +++++++++++++++++++++++++------- ProcessHacker/thrdprv.c | 4 +- 5 files changed, 147 insertions(+), 21 deletions(-) diff --git a/ProcessHacker/include/thrdlist.h b/ProcessHacker/include/thrdlist.h index 110388a583d7..a64ffc790787 100644 --- a/ProcessHacker/include/thrdlist.h +++ b/ProcessHacker/include/thrdlist.h @@ -32,6 +32,16 @@ typedef enum _PH_THREAD_TREELIST_COLUMN PH_THREAD_TREELIST_COLUMN_MAXIMUM } PH_THREAD_TREELIST_COLUMN; +typedef enum _PH_THREAD_TREELIST_MENUITEM +{ + PH_THREAD_TREELIST_MENUITEM_HIDE_SUSPENDED = 1, + PH_THREAD_TREELIST_MENUITEM_HIDE_GUITHREADS, + PH_THREAD_TREELIST_MENUITEM_HIDE_UNKNOWNSTARTADDRESS, + PH_THREAD_TREELIST_MENUITEM_HIGHLIGHT_SUSPENDED, + PH_THREAD_TREELIST_MENUITEM_HIGHLIGHT_GUITHREADS, + PH_THREAD_TREELIST_MENUITEM_MAXIMUM +} PH_THREAD_TREELIST_MENUITEM; + // begin_phapppub typedef struct _PH_THREAD_NODE { @@ -77,15 +87,29 @@ typedef struct _PH_THREAD_LIST_CONTEXT ULONG TreeNewSortColumn; PH_SORT_ORDER TreeNewSortOrder; PH_CM_MANAGER Cm; - BOOLEAN UseCycleTime; - BOOLEAN HasServices; PPH_HASHTABLE NodeHashtable; PPH_LIST NodeList; - - BOOLEAN EnableStateHighlighting; PPH_POINTER_LIST NodeStateList; PH_TN_FILTER_SUPPORT TreeFilterSupport; + + union + { + ULONG Flags; + struct + { + ULONG EnableStateHighlighting : 1; + ULONG UseCycleTime : 1; + ULONG HasServices : 1; + + ULONG HideSuspended : 1; + ULONG HideGuiThreads : 1; + ULONG HighlightSuspended : 1; + ULONG HighlightGuiThreads : 1; + + ULONG Spare : 25; + }; + }; } PH_THREAD_LIST_CONTEXT, *PPH_THREAD_LIST_CONTEXT; VOID PhInitializeThreadList( @@ -106,6 +130,11 @@ VOID PhSaveSettingsThreadList( _Inout_ PPH_THREAD_LIST_CONTEXT Context ); +VOID PhSetOptionsThreadList( + _Inout_ PPH_THREAD_LIST_CONTEXT Context, + _In_ ULONG Options + ); + PPH_THREAD_NODE PhAddThreadNode( _Inout_ PPH_THREAD_LIST_CONTEXT Context, _In_ PPH_THREAD_ITEM ThreadItem, diff --git a/ProcessHacker/prpgthrd.c b/ProcessHacker/prpgthrd.c index 3635f752c405..55980b7571c3 100644 --- a/ProcessHacker/prpgthrd.c +++ b/ProcessHacker/prpgthrd.c @@ -359,6 +359,11 @@ BOOLEAN PhpThreadTreeFilterCallback( PPH_THREAD_NODE threadNode = (PPH_THREAD_NODE)Node; PPH_THREAD_ITEM threadItem = threadNode->ThreadItem; + if (Context->ListContext.HideSuspended && threadItem->WaitReason == Suspended) + return FALSE; + if (Context->ListContext.HideGuiThreads && threadItem->IsGuiThread) + return FALSE; + if (PhIsNullOrEmptyString(Context->SearchboxText)) return TRUE; @@ -1062,6 +1067,59 @@ INT_PTR CALLBACK PhpProcessThreadsDlgProc( // } // } // break; + case IDC_OPTIONS: + { + RECT rect; + PPH_EMENU menu; + PPH_EMENU_ITEM hideSuspendedMenuItem; + PPH_EMENU_ITEM hideGuiMenuItem; + PPH_EMENU_ITEM highlightSuspendedMenuItem; + PPH_EMENU_ITEM highlightGuiMenuItem; + PPH_EMENU_ITEM selectedItem; + + if (!GetWindowRect(GetDlgItem(hwndDlg, IDC_OPTIONS), &rect)) + break; + + hideSuspendedMenuItem = PhCreateEMenuItem(0, PH_THREAD_TREELIST_MENUITEM_HIDE_SUSPENDED, L"Hide suspended", NULL, NULL); + hideGuiMenuItem = PhCreateEMenuItem(0, PH_THREAD_TREELIST_MENUITEM_HIDE_GUITHREADS, L"Hide gui", NULL, NULL); + highlightSuspendedMenuItem = PhCreateEMenuItem(0, PH_THREAD_TREELIST_MENUITEM_HIGHLIGHT_SUSPENDED, L"Highlight suspended", NULL, NULL); + highlightGuiMenuItem = PhCreateEMenuItem(0, PH_THREAD_TREELIST_MENUITEM_HIGHLIGHT_GUITHREADS, L"Highlight gui", NULL, NULL); + + menu = PhCreateEMenu(); + PhInsertEMenuItem(menu, hideSuspendedMenuItem, ULONG_MAX); + PhInsertEMenuItem(menu, hideGuiMenuItem, ULONG_MAX); + PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX); + PhInsertEMenuItem(menu, highlightSuspendedMenuItem, ULONG_MAX); + PhInsertEMenuItem(menu, highlightGuiMenuItem, ULONG_MAX); + + if (threadsContext->ListContext.HideSuspended) + hideSuspendedMenuItem->Flags |= PH_EMENU_CHECKED; + if (threadsContext->ListContext.HideGuiThreads) + hideGuiMenuItem->Flags |= PH_EMENU_CHECKED; + if (threadsContext->ListContext.HighlightSuspended) + highlightSuspendedMenuItem->Flags |= PH_EMENU_CHECKED; + if (threadsContext->ListContext.HighlightGuiThreads) + highlightGuiMenuItem->Flags |= PH_EMENU_CHECKED; + + selectedItem = PhShowEMenu( + menu, + hwndDlg, + PH_EMENU_SHOW_LEFTRIGHT, + PH_ALIGN_LEFT | PH_ALIGN_TOP, + rect.left, + rect.bottom + ); + + if (selectedItem && selectedItem->Id) + { + PhSetOptionsThreadList(&threadsContext->ListContext, selectedItem->Id); + PhSaveSettingsThreadList(&threadsContext->ListContext); + PhApplyTreeNewFilters(&threadsContext->ListContext.TreeFilterSupport); + } + + PhDestroyEMenu(menu); + } + break; } } break; diff --git a/ProcessHacker/settings.c b/ProcessHacker/settings.c index 3e977293ed29..2fa0839d78b6 100644 --- a/ProcessHacker/settings.c +++ b/ProcessHacker/settings.c @@ -171,6 +171,7 @@ VOID PhAddDefaultSettings( PhpAddIntegerSetting(L"ThinRows", L"0"); PhpAddStringSetting(L"ThreadTreeListColumns", L""); PhpAddStringSetting(L"ThreadTreeListSort", L"1,2"); // 1, DescendingSortOrder + PhpAddIntegerSetting(L"ThreadTreeListFlags", L"0"); PhpAddStringSetting(L"ThreadStackTreeListColumns", L""); PhpAddScalableIntegerPairSetting(L"ThreadStackWindowSize", L"@96|420,400"); PhpAddStringSetting(L"TokenGroupsListViewColumns", L""); diff --git a/ProcessHacker/thrdlist.c b/ProcessHacker/thrdlist.c index 65f7e8d7bd0d..94a12647645a 100644 --- a/ProcessHacker/thrdlist.c +++ b/ProcessHacker/thrdlist.c @@ -3,7 +3,7 @@ * thread list * * Copyright (C) 2011-2012 wj32 - * Copyright (C) 2018 dmex + * Copyright (C) 2018-2019 dmex * * This file is part of Process Hacker. * @@ -26,6 +26,7 @@ #include #include +#include #include #include @@ -130,6 +131,8 @@ VOID PhDeleteThreadList( { ULONG i; + PhDeleteTreeNewFilterSupport(&Context->TreeFilterSupport); + PhCmDeleteManager(&Context->Cm); for (i = 0; i < Context->NodeList->Count; i++) @@ -169,7 +172,10 @@ VOID PhLoadSettingsThreadList( settings = PhGetStringSetting(L"ThreadTreeListColumns"); sortSettings = PhGetStringSetting(L"ThreadTreeListSort"); + Context->Flags = PhGetIntegerSetting(L"ThreadTreeListFlags"); + PhCmLoadSettingsEx(Context->TreeNewHandle, &Context->Cm, 0, &settings->sr, &sortSettings->sr); + PhDereferenceObject(settings); PhDereferenceObject(sortSettings); @@ -190,12 +196,37 @@ VOID PhSaveSettingsThreadList( PPH_STRING sortSettings; settings = PhCmSaveSettingsEx(Context->TreeNewHandle, &Context->Cm, 0, &sortSettings); + + PhSetIntegerSetting(L"ThreadTreeListFlags", Context->Flags); PhSetStringSetting2(L"ThreadTreeListColumns", &settings->sr); PhSetStringSetting2(L"ThreadTreeListSort", &sortSettings->sr); + PhDereferenceObject(settings); PhDereferenceObject(sortSettings); } +VOID PhSetOptionsThreadList( + _Inout_ PPH_THREAD_LIST_CONTEXT Context, + _In_ ULONG Options + ) +{ + switch (Options) + { + case PH_THREAD_TREELIST_MENUITEM_HIDE_SUSPENDED: + Context->HideSuspended = !Context->HideSuspended; + break; + case PH_THREAD_TREELIST_MENUITEM_HIDE_GUITHREADS: + Context->HideGuiThreads = !Context->HideGuiThreads; + break; + case PH_THREAD_TREELIST_MENUITEM_HIGHLIGHT_SUSPENDED: + Context->HighlightSuspended = !Context->HighlightSuspended; + break; + case PH_THREAD_TREELIST_MENUITEM_HIGHLIGHT_GUITHREADS: + Context->HighlightGuiThreads = !Context->HighlightGuiThreads; + break; + } +} + PPH_THREAD_NODE PhAddThreadNode( _Inout_ PPH_THREAD_LIST_CONTEXT Context, _In_ PPH_THREAD_ITEM ThreadItem, @@ -652,20 +683,22 @@ BOOLEAN NTAPI PhpThreadTreeNewCallback( } break; case PH_THREAD_TREELIST_COLUMN_CYCLESDELTA: - if (context->UseCycleTime) { - if (threadItem->CyclesDelta.Delta != threadItem->CyclesDelta.Value && threadItem->CyclesDelta.Delta != 0) + if (context->UseCycleTime) { - PhMoveReference(&node->CyclesDeltaText, PhFormatUInt64(threadItem->CyclesDelta.Delta, TRUE)); - getCellText->Text = node->CyclesDeltaText->sr; + if (threadItem->CyclesDelta.Delta != threadItem->CyclesDelta.Value && threadItem->CyclesDelta.Delta != 0) + { + PhMoveReference(&node->CyclesDeltaText, PhFormatUInt64(threadItem->CyclesDelta.Delta, TRUE)); + getCellText->Text = node->CyclesDeltaText->sr; + } } - } - else - { - if (threadItem->ContextSwitchesDelta.Delta != threadItem->ContextSwitchesDelta.Value && threadItem->ContextSwitchesDelta.Delta != 0) + else { - PhMoveReference(&node->CyclesDeltaText, PhFormatUInt64(threadItem->ContextSwitchesDelta.Delta, TRUE)); - getCellText->Text = node->CyclesDeltaText->sr; + if (threadItem->ContextSwitchesDelta.Delta != threadItem->ContextSwitchesDelta.Value && threadItem->ContextSwitchesDelta.Delta != 0) + { + PhMoveReference(&node->CyclesDeltaText, PhFormatUInt64(threadItem->ContextSwitchesDelta.Delta, TRUE)); + getCellText->Text = node->CyclesDeltaText->sr; + } } } break; @@ -916,13 +949,15 @@ BOOLEAN NTAPI PhpThreadTreeNewCallback( threadItem = node->ThreadItem; if (!threadItem) - ; // Dummy - else if (PhCsUseColorSuspended && threadItem->WaitReason == Suspended) + NOTHING; + //else if (context->HighlightUnknownStartAddress && threadItem->StartAddressResolveLevel == PhsrlAddress) + // getNodeColor->BackColor = PhCsColorUnknown; + else if (context->HighlightSuspended && threadItem->WaitReason == Suspended) getNodeColor->BackColor = PhCsColorSuspended; - else if (PhCsUseColorGuiThreads && threadItem->IsGuiThread) + else if (context->HighlightGuiThreads && threadItem->IsGuiThread) getNodeColor->BackColor = PhCsColorGuiThreads; - getNodeColor->Flags = TN_CACHE | TN_AUTO_FORECOLOR; + getNodeColor->Flags = TN_AUTO_FORECOLOR; } return TRUE; case TreeNewSortChanged: @@ -946,6 +981,9 @@ BOOLEAN NTAPI PhpThreadTreeNewCallback( if (GetKeyState(VK_CONTROL) < 0) TreeNew_SelectRange(context->TreeNewHandle, 0, -1); break; + case 'K': + SetFocus(GetDlgItem(context->ParentWindowHandle, IDC_SEARCH)); + break; case VK_DELETE: SendMessage(context->ParentWindowHandle, WM_COMMAND, ID_THREAD_TERMINATE, 0); break; diff --git a/ProcessHacker/thrdprv.c b/ProcessHacker/thrdprv.c index a1adc9111d68..211d50146af2 100644 --- a/ProcessHacker/thrdprv.c +++ b/ProcessHacker/thrdprv.c @@ -933,8 +933,6 @@ VOID PhpThreadProviderUpdate( PhTrimToNullTerminatorString(threadItem->StartAddressString); } - PhpQueueThreadQuery(threadProvider, threadItem); - // Is it a GUI thread? { GUITHREADINFO info = { sizeof(GUITHREADINFO) }; @@ -942,6 +940,8 @@ VOID PhpThreadProviderUpdate( threadItem->IsGuiThread = !!GetGUIThreadInfo(HandleToUlong(threadItem->ThreadId), &info); } + PhpQueueThreadQuery(threadProvider, threadItem); + // Add the thread item to the hashtable. PhAcquireFastLockExclusive(&threadProvider->ThreadHashtableLock); PhAddEntryHashtable(threadProvider->ThreadHashtable, &threadItem); From c0140896b94e5a1deda162b11ec03ea95657d66a Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 6 Apr 2019 00:05:03 +0200 Subject: [PATCH 1780/2058] Update token guid string --- ProcessHacker/tokprp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ProcessHacker/tokprp.c b/ProcessHacker/tokprp.c index 380c434d37fa..201b50517c3a 100644 --- a/ProcessHacker/tokprp.c +++ b/ProcessHacker/tokprp.c @@ -2216,7 +2216,7 @@ BOOLEAN PhpAddTokenCapabilities( if (capabilityName = PhGetCapabilityGuidName(name)) { - PhpAddAttributeNode(&TokenPageContext->CapsTreeContext, node, PhFormatString(L"GuidName: %s", PhGetString(capabilityName))); + PhpAddAttributeNode(&TokenPageContext->CapsTreeContext, node, PhFormatString(L"Capability: %s", PhGetString(capabilityName))); PhDereferenceObject(capabilityName); } From f91082ce74b2491353882acd5f0ee4e8d34b15b2 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 6 Apr 2019 00:29:24 +0200 Subject: [PATCH 1781/2058] Update resource ID --- ProcessHacker/ProcessHacker.rc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ProcessHacker/ProcessHacker.rc b/ProcessHacker/ProcessHacker.rc index 976619a00107..b89da45070fe 100644 --- a/ProcessHacker/ProcessHacker.rc +++ b/ProcessHacker/ProcessHacker.rc @@ -519,7 +519,7 @@ FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN CONTROL "",IDC_LIST,"PhTreeNew",WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP | 0xa,2,19,256,239,WS_EX_CLIENTEDGE EDITTEXT IDC_SEARCH,114,3,144,14,ES_AUTOHSCROLL - PUSHBUTTON "Options",IDC_FILTEROPTIONS,2,2,50,14 + PUSHBUTTON "Options",IDC_OPTIONS,2,2,50,14 END IDD_PROCHANDLES DIALOGEX 0, 0, 260, 260 From f39a5121b3d6866f987773be8bda38e7ff1bf3ac Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 6 Apr 2019 18:55:01 +0200 Subject: [PATCH 1782/2058] Fix tray icon layout persistence after restart --- ProcessHacker/include/notifico.h | 7 +- ProcessHacker/include/phplug.h | 2 + ProcessHacker/notifico.c | 106 +++++++++++++++++++------------ plugins/ExtendedTools/iconext.c | 19 ++++++ 4 files changed, 89 insertions(+), 45 deletions(-) diff --git a/ProcessHacker/include/notifico.h b/ProcessHacker/include/notifico.h index a42e7902e65e..90a1d6277e2a 100644 --- a/ProcessHacker/include/notifico.h +++ b/ProcessHacker/include/notifico.h @@ -92,11 +92,11 @@ typedef struct _PH_NF_ICON PWSTR Text; ULONG Flags; ULONG IconId; + PGUID IconGuid; PPH_NF_ICON_UPDATE_CALLBACK UpdateCallback; PPH_NF_ICON_MESSAGE_CALLBACK MessageCallback; PPH_STRING TextCache; - // begin_phapppub } PH_NF_ICON, *PPH_NF_ICON; // end_phapppub @@ -128,7 +128,6 @@ VOID PhNfSetVisibleIcon( ); BOOLEAN PhNfShowBalloonTip( - _In_opt_ ULONG Id, _In_ PWSTR Title, _In_ PWSTR Text, _In_ ULONG Timeout, @@ -142,6 +141,7 @@ HICON PhNfBitmapToIcon( struct _PH_NF_ICON *PhNfPluginRegisterIcon( _In_ struct _PH_PLUGIN * Plugin, _In_ ULONG SubId, + _In_ PGUID Guid, _In_opt_ PVOID Context, _In_ PWSTR Text, _In_ ULONG Flags, @@ -149,8 +149,9 @@ struct _PH_NF_ICON *PhNfPluginRegisterIcon( ); PPH_NF_ICON PhNfRegisterIcon( - _In_ struct _PH_PLUGIN *Plugin, + _In_opt_ struct _PH_PLUGIN *Plugin, _In_ ULONG Id, + _In_ PGUID Guid, _In_opt_ PVOID Context, _In_ PWSTR Text, _In_ ULONG Flags, diff --git a/ProcessHacker/include/phplug.h b/ProcessHacker/include/phplug.h index 61ac7df6a68c..35189e53a36f 100644 --- a/ProcessHacker/include/phplug.h +++ b/ProcessHacker/include/phplug.h @@ -352,6 +352,7 @@ typedef struct _PH_PLUGIN_MINIINFO_POINTERS * \param Plugin A plugin instance structure. * \param SubId An identifier for the column. This should be unique within the * plugin. + * \param Guid A unique guid for this icon. * \param Context A user-defined value. * \param Text A string describing the notification icon. * \param Flags A combination of flags. @@ -362,6 +363,7 @@ typedef struct _PH_PLUGIN_MINIINFO_POINTERS typedef struct _PH_NF_ICON * (NTAPI *PPH_REGISTER_TRAY_ICON)( _In_ struct _PH_PLUGIN * Plugin, _In_ ULONG SubId, + _In_ PGUID Guid, _In_opt_ PVOID Context, _In_ PWSTR Text, _In_ ULONG Flags, diff --git a/ProcessHacker/notifico.c b/ProcessHacker/notifico.c index 9df586a1f858..ed4e734d8908 100644 --- a/ProcessHacker/notifico.c +++ b/ProcessHacker/notifico.c @@ -3,7 +3,7 @@ * notification icon manager * * Copyright (C) 2011-2016 wj32 - * Copyright (C) 2017-2018 dmex + * Copyright (C) 2017-2019 dmex * * This file is part of Process Hacker. * @@ -37,8 +37,10 @@ #include #include -BOOLEAN PhNfMiniInfoEnabled; -BOOLEAN PhNfMiniInfoPinned; +BOOLEAN PhNfMiniInfoEnabled = FALSE; +BOOLEAN PhNfMiniInfoPinned = FALSE; +// Note: no lock is needed because we only ever modify the list on this same thread. +PPH_LIST PhTrayIconItemList = NULL; PH_NF_POINTERS PhNfpPointers; PH_CALLBACK_REGISTRATION PhNfpProcessesUpdatedRegistration; @@ -49,11 +51,27 @@ HICON PhNfpBlackIcon = NULL; static POINT IconClickLocation; static PH_NF_MSG_SHOWMINIINFOSECTION_DATA IconClickShowMiniInfoSectionData; -static BOOLEAN IconClickUpDueToDown; -static BOOLEAN IconDisableHover; - -// Note: no lock is needed because we only ever modify the list on this same thread. -PPH_LIST PhTrayIconItemList = NULL; +static BOOLEAN IconClickUpDueToDown = FALSE; +static BOOLEAN IconDisableHover = FALSE; + +// {41713862-1CEA-4AA0-AF28-FA2F4C5C5A3B} +static GUID PhNfCpuUsageGuid = { 0x41713862, 0x1cea, 0x4aa0, { 0xaf, 0x28, 0xfa, 0x2f, 0x4c, 0x5c, 0x5a, 0x3b } }; +// {5485E389-97BC-4E5B-969D-3273127DA696} +static GUID PhNfCpuHistoryGuid = { 0x5485e389, 0x97bc, 0x4e5b, { 0x96, 0x9d, 0x32, 0x73, 0x12, 0x7d, 0xa6, 0x96 } }; +// {7EAE88B5-ABBB-4024-99B8-AB7982E66AA3} +static GUID PhNfIoHistoryGuid = { 0x7eae88b5, 0xabbb, 0x4024, { 0x99, 0xb8, 0xab, 0x79, 0x82, 0xe6, 0x6a, 0xa3 } }; +// {040C2141-11EC-4D2B-B438-C407B11A6242} +static GUID PhNfCommitHistoryGuid = { 0x40c2141, 0x11ec, 0x4d2b, { 0xb4, 0x38, 0xc4, 0x7, 0xb1, 0x1a, 0x62, 0x42 } }; +// {85071CE7-FC91-4847-8F7C-CD722F6540AE} +static GUID PhNfPhysicalHistoryGuid = { 0x85071ce7, 0xfc91, 0x4847, { 0x8f, 0x7c, 0xcd, 0x72, 0x2f, 0x65, 0x40, 0xae } }; +// {BFCCBE8A-C2D8-469E-9F50-2941C895273E} +static GUID PhNfCpuUsageTextGuid = { 0xbfccbe8a, 0xc2d8, 0x469e, { 0x9f, 0x50, 0x29, 0x41, 0xc8, 0x95, 0x27, 0x3e } }; +// {E040836D-8436-4E81-A1AA-954DD37FDDDF} +static GUID PhNfIoUsageTextGuid = { 0xe040836d, 0x8436, 0x4e81, { 0xa1, 0xaa, 0x95, 0x4d, 0xd3, 0x7f, 0xdd, 0xdf } }; +// {CEA50FA3-F116-4720-8F8A-921E8030904C} +static GUID PhNfCommitTextGuid = { 0xcea50fa3, 0xf116, 0x4720, { 0x8f, 0x8a, 0x92, 0x1e, 0x80, 0x30, 0x90, 0x4c } }; +// {3A7A2A3A-FAAB-49CA-A313-A31C4CF60E1B} +static GUID PhNfPhysicalUsageTextGuid = { 0x3a7a2a3a, 0xfaab, 0x49ca, { 0xa3, 0x13, 0xa3, 0x1c, 0x4c, 0xf6, 0xe, 0x1b } }; VOID PhNfLoadStage1( VOID @@ -153,15 +171,15 @@ VOID PhNfLoadStage2( { PhNfMiniInfoEnabled = !!PhGetIntegerSetting(L"MiniInfoWindowEnabled"); - PhNfRegisterIcon(NULL, PH_TRAY_ICON_ID_CPU_USAGE, NULL, L"CPU &usage", 0, PhNfpCpuUsageIconUpdateCallback, NULL); - PhNfRegisterIcon(NULL, PH_TRAY_ICON_ID_CPU_HISTORY, NULL, L"CPU &history", 0, PhNfpCpuHistoryIconUpdateCallback, NULL); - PhNfRegisterIcon(NULL, PH_TRAY_ICON_ID_IO_HISTORY, NULL, L"&I/O history", 0, PhNfpIoHistoryIconUpdateCallback, NULL); - PhNfRegisterIcon(NULL, PH_TRAY_ICON_ID_COMMIT_HISTORY, NULL, L"&Commit charge history", 0, PhNfpCommitHistoryIconUpdateCallback, NULL); - PhNfRegisterIcon(NULL, PH_TRAY_ICON_ID_PHYSICAL_HISTORY, NULL, L"&Physical memory history", 0, PhNfpPhysicalHistoryIconUpdateCallback, NULL); - PhNfRegisterIcon(NULL, PH_TRAY_ICON_ID_CPU_TEXT, NULL, L"CPU usage (text)", 0, PhNfpCpuUsageTextIconUpdateCallback, NULL); - PhNfRegisterIcon(NULL, PH_TRAY_ICON_ID_IO_TEXT, NULL, L"IO usage (text)", 0, PhNfpIoUsageTextIconUpdateCallback, NULL); - PhNfRegisterIcon(NULL, PH_TRAY_ICON_ID_COMMIT_TEXT, NULL, L"Commit usage (text)", 0, PhNfpCommitTextIconUpdateCallback, NULL); - PhNfRegisterIcon(NULL, PH_TRAY_ICON_ID_PHYSICAL_TEXT, NULL, L"Physical usage (text)", 0, PhNfpPhysicalUsageTextIconUpdateCallback, NULL); + PhNfRegisterIcon(NULL, PH_TRAY_ICON_ID_CPU_USAGE, &PhNfCpuUsageGuid, NULL, L"CPU &usage", 0, PhNfpCpuUsageIconUpdateCallback, NULL); + PhNfRegisterIcon(NULL, PH_TRAY_ICON_ID_CPU_HISTORY, &PhNfCpuHistoryGuid, NULL, L"CPU &history", 0, PhNfpCpuHistoryIconUpdateCallback, NULL); + PhNfRegisterIcon(NULL, PH_TRAY_ICON_ID_IO_HISTORY, &PhNfIoHistoryGuid, NULL, L"&I/O history", 0, PhNfpIoHistoryIconUpdateCallback, NULL); + PhNfRegisterIcon(NULL, PH_TRAY_ICON_ID_COMMIT_HISTORY, &PhNfCommitHistoryGuid, NULL, L"&Commit charge history", 0, PhNfpCommitHistoryIconUpdateCallback, NULL); + PhNfRegisterIcon(NULL, PH_TRAY_ICON_ID_PHYSICAL_HISTORY, &PhNfPhysicalHistoryGuid, NULL, L"&Physical memory history", 0, PhNfpPhysicalHistoryIconUpdateCallback, NULL); + PhNfRegisterIcon(NULL, PH_TRAY_ICON_ID_CPU_TEXT, &PhNfCpuUsageTextGuid, NULL, L"CPU usage (text)", 0, PhNfpCpuUsageTextIconUpdateCallback, NULL); + PhNfRegisterIcon(NULL, PH_TRAY_ICON_ID_IO_TEXT, &PhNfIoUsageTextGuid, NULL, L"IO usage (text)", 0, PhNfpIoUsageTextIconUpdateCallback, NULL); + PhNfRegisterIcon(NULL, PH_TRAY_ICON_ID_COMMIT_TEXT, &PhNfCommitTextGuid, NULL, L"Commit usage (text)", 0, PhNfpCommitTextIconUpdateCallback, NULL); + PhNfRegisterIcon(NULL, PH_TRAY_ICON_ID_PHYSICAL_TEXT, &PhNfPhysicalUsageTextGuid, NULL, L"Physical usage (text)", 0, PhNfpPhysicalUsageTextIconUpdateCallback, NULL); if (PhPluginsEnabled) { @@ -368,39 +386,35 @@ VOID PhNfSetVisibleIcon( } BOOLEAN PhNfShowBalloonTip( - _In_opt_ ULONG Id, _In_ PWSTR Title, _In_ PWSTR Text, _In_ ULONG Timeout, _In_ ULONG Flags ) { - NOTIFYICONDATA notifyIcon = { sizeof(NOTIFYICONDATA) }; + NOTIFYICONDATA notifyIcon = { NOTIFYICONDATA_V3_SIZE }; PPH_NF_ICON registeredIcon = NULL; - ULONG iconID = Id; - if (iconID == 0) + for (ULONG i = 0; i < PhTrayIconItemList->Count; i++) { - for (ULONG i = 0; i < PhTrayIconItemList->Count; i++) - { - PPH_NF_ICON icon = PhTrayIconItemList->Items[i]; - - if (!(icon->Flags & PH_NF_ICON_ENABLED)) - continue; + PPH_NF_ICON icon = PhTrayIconItemList->Items[i]; - iconID = icon->IconId; - break; - } + if (!(icon->Flags & PH_NF_ICON_ENABLED)) + continue; - if (iconID == 0) - return FALSE; + registeredIcon = icon; + break; } + if (!registeredIcon) + return FALSE; + + notifyIcon.uFlags = NIF_INFO | NIF_GUID; notifyIcon.hWnd = PhMainWndHandle; - notifyIcon.uID = iconID; - notifyIcon.uFlags = NIF_INFO; - wcsncpy_s(notifyIcon.szInfoTitle, ARRAYSIZE(notifyIcon.szInfoTitle), Title, _TRUNCATE); - wcsncpy_s(notifyIcon.szInfo, ARRAYSIZE(notifyIcon.szInfo), Text, _TRUNCATE); + notifyIcon.uID = registeredIcon->IconId; + notifyIcon.guidItem = *registeredIcon->IconGuid; + wcsncpy_s(notifyIcon.szInfoTitle, RTL_NUMBER_OF(notifyIcon.szInfoTitle), Title, _TRUNCATE); + wcsncpy_s(notifyIcon.szInfo, RTL_NUMBER_OF(notifyIcon.szInfo), Text, _TRUNCATE); notifyIcon.uTimeout = Timeout; notifyIcon.dwInfoFlags = Flags; @@ -427,8 +441,9 @@ HICON PhNfBitmapToIcon( } PPH_NF_ICON PhNfRegisterIcon( - _In_ struct _PH_PLUGIN *Plugin, + _In_opt_ struct _PH_PLUGIN *Plugin, _In_ ULONG Id, + _In_ PGUID Guid, _In_opt_ PVOID Context, _In_ PWSTR Text, _In_ ULONG Flags, @@ -438,7 +453,7 @@ PPH_NF_ICON PhNfRegisterIcon( { PPH_NF_ICON icon; - icon = PhAllocate(sizeof(PH_NF_ICON)); + icon = PhAllocateZero(sizeof(PH_NF_ICON)); icon->Plugin = Plugin; icon->SubId = Id; icon->Context = Context; @@ -449,6 +464,7 @@ PPH_NF_ICON PhNfRegisterIcon( icon->MessageCallback = MessageCallback; icon->TextCache = PhReferenceEmptyString(); icon->IconId = PhTrayIconItemList->Count + 1; // HACK + icon->IconGuid = Guid; PhAddItemList(PhTrayIconItemList, icon); @@ -458,6 +474,7 @@ PPH_NF_ICON PhNfRegisterIcon( struct _PH_NF_ICON *PhNfPluginRegisterIcon( _In_ struct _PH_PLUGIN * Plugin, _In_ ULONG Id, + _In_ PGUID Guid, _In_opt_ PVOID Context, _In_ PWSTR Text, _In_ ULONG Flags, @@ -467,6 +484,7 @@ struct _PH_NF_ICON *PhNfPluginRegisterIcon( return PhNfRegisterIcon( Plugin, Id, + Guid, Context, Text, Flags, @@ -589,15 +607,16 @@ BOOLEAN PhNfpAddNotifyIcon( _In_ PPH_NF_ICON Icon ) { - NOTIFYICONDATA notifyIcon = { sizeof(NOTIFYICONDATA) }; + NOTIFYICONDATA notifyIcon = { NOTIFYICONDATA_V3_SIZE }; if (PhMainWndExiting) return FALSE; notifyIcon.hWnd = PhMainWndHandle; notifyIcon.uID = Icon->IconId; - notifyIcon.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP; + notifyIcon.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP | NIF_GUID; notifyIcon.uCallbackMessage = WM_PH_NOTIFY_ICON_MESSAGE; + notifyIcon.guidItem = *Icon->IconGuid; wcsncpy_s( notifyIcon.szTip, sizeof(notifyIcon.szTip) / sizeof(WCHAR), PhGetStringOrDefault(Icon->TextCache, PhApplicationName), @@ -620,10 +639,12 @@ BOOLEAN PhNfpRemoveNotifyIcon( _In_ PPH_NF_ICON Icon ) { - NOTIFYICONDATA notifyIcon = { sizeof(NOTIFYICONDATA) }; + NOTIFYICONDATA notifyIcon = { NOTIFYICONDATA_V3_SIZE }; + notifyIcon.uFlags = NIF_GUID; notifyIcon.hWnd = PhMainWndHandle; notifyIcon.uID = Icon->IconId; + notifyIcon.guidItem = *Icon->IconGuid; Shell_NotifyIcon(NIM_DELETE, ¬ifyIcon); @@ -644,9 +665,10 @@ BOOLEAN PhNfpModifyNotifyIcon( if (Icon->Flags & PH_NF_ICON_UNAVAILABLE) return FALSE; + notifyIcon.uFlags = Flags | NIF_GUID; notifyIcon.hWnd = PhMainWndHandle; notifyIcon.uID = Icon->IconId; - notifyIcon.uFlags = Flags; + notifyIcon.guidItem = *Icon->IconGuid; notifyIcon.hIcon = IconHandle; if (!PhNfMiniInfoEnabled || PhNfMiniInfoPinned || (Icon->Flags & PH_NF_ICON_NOSHOW_MINIINFO)) diff --git a/plugins/ExtendedTools/iconext.c b/plugins/ExtendedTools/iconext.c index 20d32010a919..80a41a30352e 100644 --- a/plugins/ExtendedTools/iconext.c +++ b/plugins/ExtendedTools/iconext.c @@ -33,6 +33,19 @@ #define DISK_ICON_TEXT_ID 5 #define NETWORK_ICON_TEXT_ID 6 +// {0B50C566-8386-44A5-897F-8FE07D55975C} +static GUID EtpGpuIconGuid = { 0xb50c566, 0x8386, 0x44a5, { 0x89, 0x7f, 0x8f, 0xe0, 0x7d, 0x55, 0x97, 0x5c } }; +// {633E07FF-4B3C-405E-82EF-1F0C6904FC05} +static GUID EtpDiskIconGuid = { 0x633e07ff, 0x4b3c, 0x405e, { 0x82, 0xef, 0x1f, 0xc, 0x69, 0x4, 0xfc, 0x5 } }; +// {05606BEE-D4B0-4BC8-B6B7-69F9685AF782} +static GUID EtpNetworkIconGuid = { 0x5606bee, 0xd4b0, 0x4bc8, { 0xb6, 0xb7, 0x69, 0xf9, 0x68, 0x5a, 0xf7, 0x82 } }; +// {A2DA7963-AD12-4938-8DF8-280D971E5277} +static GUID EtpGpuTextIconGuid = { 0xa2da7963, 0xad12, 0x4938, { 0x8d, 0xf8, 0x28, 0xd, 0x97, 0x1e, 0x52, 0x77 } }; +// {C76B1DF8-F2D2-42D0-AA78-13E214BDC663} +static GUID EtpDiskTextIconGuid = { 0xc76b1df8, 0xf2d2, 0x42d0, { 0xaa, 0x78, 0x13, 0xe2, 0x14, 0xbd, 0xc6, 0x63 } }; +// {0AE1EDF2-220D-4EAA-B4F8-ED3E07A6FB12} +static GUID EtpNetworkTextIconGuid = { 0xae1edf2, 0x220d, 0x4eaa, { 0xb4, 0xf8, 0xed, 0x3e, 0x7, 0xa6, 0xfb, 0x12 } }; + VOID EtpGpuIconUpdateCallback( _In_ struct _PH_NF_ICON *Icon, _Out_ PVOID *NewIconOrBitmap, @@ -115,6 +128,7 @@ VOID EtRegisterNotifyIcons( Pointers->RegisterTrayIcon( PluginInstance, GPU_ICON_ID, + &EtpGpuIconGuid, NULL, L"&GPU history", EtGpuEnabled ? 0 : PH_NF_ICON_UNAVAILABLE, @@ -126,6 +140,7 @@ VOID EtRegisterNotifyIcons( Pointers->RegisterTrayIcon( PluginInstance, DISK_ICON_ID, + &EtpDiskIconGuid, NULL, L"&Disk history", EtEtwEnabled ? 0 : PH_NF_ICON_UNAVAILABLE, @@ -137,6 +152,7 @@ VOID EtRegisterNotifyIcons( Pointers->RegisterTrayIcon( PluginInstance, NETWORK_ICON_ID, + &EtpNetworkIconGuid, NULL, L"&Network history", EtEtwEnabled ? 0 : PH_NF_ICON_UNAVAILABLE, @@ -148,6 +164,7 @@ VOID EtRegisterNotifyIcons( Pointers->RegisterTrayIcon( PluginInstance, GPU_ICON_TEXT_ID, + &EtpGpuTextIconGuid, NULL, L"&GPU usage (Text)", EtGpuEnabled ? 0 : PH_NF_ICON_UNAVAILABLE, @@ -159,6 +176,7 @@ VOID EtRegisterNotifyIcons( Pointers->RegisterTrayIcon( PluginInstance, DISK_ICON_TEXT_ID, + &EtpDiskTextIconGuid, NULL, L"&Disk usage (Text)", EtEtwEnabled ? 0 : PH_NF_ICON_UNAVAILABLE, @@ -170,6 +188,7 @@ VOID EtRegisterNotifyIcons( Pointers->RegisterTrayIcon( PluginInstance, NETWORK_ICON_TEXT_ID, + &EtpNetworkTextIconGuid, NULL, L"&Network usage (Text)", EtEtwEnabled ? 0 : PH_NF_ICON_UNAVAILABLE, From 60b97e63c9d40431504dc6c9674c0816e309c890 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 6 Apr 2019 18:57:03 +0200 Subject: [PATCH 1783/2058] Remove unused paramater --- ProcessHacker/mainwnd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index f71677736f23..723298d6cde5 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -3302,7 +3302,7 @@ VOID PhShowIconNotification( _In_ ULONG Flags ) { - PhNfShowBalloonTip(0, Title, Text, 10, Flags); + PhNfShowBalloonTip(Title, Text, 10, Flags); } VOID PhShowDetailsForIconNotification( From b128ec4c9139e00eb4f6c992ecfe3460e2d0792d Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 6 Apr 2019 19:07:37 +0200 Subject: [PATCH 1784/2058] Remove guid copy --- ProcessHacker/include/notifico.h | 6 +++--- ProcessHacker/include/phplug.h | 2 +- ProcessHacker/notifico.c | 30 +++++++++++++++--------------- plugins/ExtendedTools/iconext.c | 12 ++++++------ 4 files changed, 25 insertions(+), 25 deletions(-) diff --git a/ProcessHacker/include/notifico.h b/ProcessHacker/include/notifico.h index 90a1d6277e2a..53d79bac1daa 100644 --- a/ProcessHacker/include/notifico.h +++ b/ProcessHacker/include/notifico.h @@ -92,7 +92,7 @@ typedef struct _PH_NF_ICON PWSTR Text; ULONG Flags; ULONG IconId; - PGUID IconGuid; + GUID IconGuid; PPH_NF_ICON_UPDATE_CALLBACK UpdateCallback; PPH_NF_ICON_MESSAGE_CALLBACK MessageCallback; @@ -141,7 +141,7 @@ HICON PhNfBitmapToIcon( struct _PH_NF_ICON *PhNfPluginRegisterIcon( _In_ struct _PH_PLUGIN * Plugin, _In_ ULONG SubId, - _In_ PGUID Guid, + _In_ GUID Guid, _In_opt_ PVOID Context, _In_ PWSTR Text, _In_ ULONG Flags, @@ -151,7 +151,7 @@ struct _PH_NF_ICON *PhNfPluginRegisterIcon( PPH_NF_ICON PhNfRegisterIcon( _In_opt_ struct _PH_PLUGIN *Plugin, _In_ ULONG Id, - _In_ PGUID Guid, + _In_ GUID Guid, _In_opt_ PVOID Context, _In_ PWSTR Text, _In_ ULONG Flags, diff --git a/ProcessHacker/include/phplug.h b/ProcessHacker/include/phplug.h index 35189e53a36f..86cc825dddf0 100644 --- a/ProcessHacker/include/phplug.h +++ b/ProcessHacker/include/phplug.h @@ -363,7 +363,7 @@ typedef struct _PH_PLUGIN_MINIINFO_POINTERS typedef struct _PH_NF_ICON * (NTAPI *PPH_REGISTER_TRAY_ICON)( _In_ struct _PH_PLUGIN * Plugin, _In_ ULONG SubId, - _In_ PGUID Guid, + _In_ GUID Guid, _In_opt_ PVOID Context, _In_ PWSTR Text, _In_ ULONG Flags, diff --git a/ProcessHacker/notifico.c b/ProcessHacker/notifico.c index ed4e734d8908..376a9904e083 100644 --- a/ProcessHacker/notifico.c +++ b/ProcessHacker/notifico.c @@ -171,15 +171,15 @@ VOID PhNfLoadStage2( { PhNfMiniInfoEnabled = !!PhGetIntegerSetting(L"MiniInfoWindowEnabled"); - PhNfRegisterIcon(NULL, PH_TRAY_ICON_ID_CPU_USAGE, &PhNfCpuUsageGuid, NULL, L"CPU &usage", 0, PhNfpCpuUsageIconUpdateCallback, NULL); - PhNfRegisterIcon(NULL, PH_TRAY_ICON_ID_CPU_HISTORY, &PhNfCpuHistoryGuid, NULL, L"CPU &history", 0, PhNfpCpuHistoryIconUpdateCallback, NULL); - PhNfRegisterIcon(NULL, PH_TRAY_ICON_ID_IO_HISTORY, &PhNfIoHistoryGuid, NULL, L"&I/O history", 0, PhNfpIoHistoryIconUpdateCallback, NULL); - PhNfRegisterIcon(NULL, PH_TRAY_ICON_ID_COMMIT_HISTORY, &PhNfCommitHistoryGuid, NULL, L"&Commit charge history", 0, PhNfpCommitHistoryIconUpdateCallback, NULL); - PhNfRegisterIcon(NULL, PH_TRAY_ICON_ID_PHYSICAL_HISTORY, &PhNfPhysicalHistoryGuid, NULL, L"&Physical memory history", 0, PhNfpPhysicalHistoryIconUpdateCallback, NULL); - PhNfRegisterIcon(NULL, PH_TRAY_ICON_ID_CPU_TEXT, &PhNfCpuUsageTextGuid, NULL, L"CPU usage (text)", 0, PhNfpCpuUsageTextIconUpdateCallback, NULL); - PhNfRegisterIcon(NULL, PH_TRAY_ICON_ID_IO_TEXT, &PhNfIoUsageTextGuid, NULL, L"IO usage (text)", 0, PhNfpIoUsageTextIconUpdateCallback, NULL); - PhNfRegisterIcon(NULL, PH_TRAY_ICON_ID_COMMIT_TEXT, &PhNfCommitTextGuid, NULL, L"Commit usage (text)", 0, PhNfpCommitTextIconUpdateCallback, NULL); - PhNfRegisterIcon(NULL, PH_TRAY_ICON_ID_PHYSICAL_TEXT, &PhNfPhysicalUsageTextGuid, NULL, L"Physical usage (text)", 0, PhNfpPhysicalUsageTextIconUpdateCallback, NULL); + PhNfRegisterIcon(NULL, PH_TRAY_ICON_ID_CPU_USAGE, PhNfCpuUsageGuid, NULL, L"CPU &usage", 0, PhNfpCpuUsageIconUpdateCallback, NULL); + PhNfRegisterIcon(NULL, PH_TRAY_ICON_ID_CPU_HISTORY, PhNfCpuHistoryGuid, NULL, L"CPU &history", 0, PhNfpCpuHistoryIconUpdateCallback, NULL); + PhNfRegisterIcon(NULL, PH_TRAY_ICON_ID_IO_HISTORY, PhNfIoHistoryGuid, NULL, L"&I/O history", 0, PhNfpIoHistoryIconUpdateCallback, NULL); + PhNfRegisterIcon(NULL, PH_TRAY_ICON_ID_COMMIT_HISTORY, PhNfCommitHistoryGuid, NULL, L"&Commit charge history", 0, PhNfpCommitHistoryIconUpdateCallback, NULL); + PhNfRegisterIcon(NULL, PH_TRAY_ICON_ID_PHYSICAL_HISTORY, PhNfPhysicalHistoryGuid, NULL, L"&Physical memory history", 0, PhNfpPhysicalHistoryIconUpdateCallback, NULL); + PhNfRegisterIcon(NULL, PH_TRAY_ICON_ID_CPU_TEXT, PhNfCpuUsageTextGuid, NULL, L"CPU usage (text)", 0, PhNfpCpuUsageTextIconUpdateCallback, NULL); + PhNfRegisterIcon(NULL, PH_TRAY_ICON_ID_IO_TEXT, PhNfIoUsageTextGuid, NULL, L"IO usage (text)", 0, PhNfpIoUsageTextIconUpdateCallback, NULL); + PhNfRegisterIcon(NULL, PH_TRAY_ICON_ID_COMMIT_TEXT, PhNfCommitTextGuid, NULL, L"Commit usage (text)", 0, PhNfpCommitTextIconUpdateCallback, NULL); + PhNfRegisterIcon(NULL, PH_TRAY_ICON_ID_PHYSICAL_TEXT, PhNfPhysicalUsageTextGuid, NULL, L"Physical usage (text)", 0, PhNfpPhysicalUsageTextIconUpdateCallback, NULL); if (PhPluginsEnabled) { @@ -412,7 +412,7 @@ BOOLEAN PhNfShowBalloonTip( notifyIcon.uFlags = NIF_INFO | NIF_GUID; notifyIcon.hWnd = PhMainWndHandle; notifyIcon.uID = registeredIcon->IconId; - notifyIcon.guidItem = *registeredIcon->IconGuid; + notifyIcon.guidItem = registeredIcon->IconGuid; wcsncpy_s(notifyIcon.szInfoTitle, RTL_NUMBER_OF(notifyIcon.szInfoTitle), Title, _TRUNCATE); wcsncpy_s(notifyIcon.szInfo, RTL_NUMBER_OF(notifyIcon.szInfo), Text, _TRUNCATE); notifyIcon.uTimeout = Timeout; @@ -443,7 +443,7 @@ HICON PhNfBitmapToIcon( PPH_NF_ICON PhNfRegisterIcon( _In_opt_ struct _PH_PLUGIN *Plugin, _In_ ULONG Id, - _In_ PGUID Guid, + _In_ GUID Guid, _In_opt_ PVOID Context, _In_ PWSTR Text, _In_ ULONG Flags, @@ -474,7 +474,7 @@ PPH_NF_ICON PhNfRegisterIcon( struct _PH_NF_ICON *PhNfPluginRegisterIcon( _In_ struct _PH_PLUGIN * Plugin, _In_ ULONG Id, - _In_ PGUID Guid, + _In_ GUID Guid, _In_opt_ PVOID Context, _In_ PWSTR Text, _In_ ULONG Flags, @@ -616,7 +616,7 @@ BOOLEAN PhNfpAddNotifyIcon( notifyIcon.uID = Icon->IconId; notifyIcon.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP | NIF_GUID; notifyIcon.uCallbackMessage = WM_PH_NOTIFY_ICON_MESSAGE; - notifyIcon.guidItem = *Icon->IconGuid; + notifyIcon.guidItem = Icon->IconGuid; wcsncpy_s( notifyIcon.szTip, sizeof(notifyIcon.szTip) / sizeof(WCHAR), PhGetStringOrDefault(Icon->TextCache, PhApplicationName), @@ -644,7 +644,7 @@ BOOLEAN PhNfpRemoveNotifyIcon( notifyIcon.uFlags = NIF_GUID; notifyIcon.hWnd = PhMainWndHandle; notifyIcon.uID = Icon->IconId; - notifyIcon.guidItem = *Icon->IconGuid; + notifyIcon.guidItem = Icon->IconGuid; Shell_NotifyIcon(NIM_DELETE, ¬ifyIcon); @@ -668,7 +668,7 @@ BOOLEAN PhNfpModifyNotifyIcon( notifyIcon.uFlags = Flags | NIF_GUID; notifyIcon.hWnd = PhMainWndHandle; notifyIcon.uID = Icon->IconId; - notifyIcon.guidItem = *Icon->IconGuid; + notifyIcon.guidItem = Icon->IconGuid; notifyIcon.hIcon = IconHandle; if (!PhNfMiniInfoEnabled || PhNfMiniInfoPinned || (Icon->Flags & PH_NF_ICON_NOSHOW_MINIINFO)) diff --git a/plugins/ExtendedTools/iconext.c b/plugins/ExtendedTools/iconext.c index 80a41a30352e..017df337c9e8 100644 --- a/plugins/ExtendedTools/iconext.c +++ b/plugins/ExtendedTools/iconext.c @@ -128,7 +128,7 @@ VOID EtRegisterNotifyIcons( Pointers->RegisterTrayIcon( PluginInstance, GPU_ICON_ID, - &EtpGpuIconGuid, + EtpGpuIconGuid, NULL, L"&GPU history", EtGpuEnabled ? 0 : PH_NF_ICON_UNAVAILABLE, @@ -140,7 +140,7 @@ VOID EtRegisterNotifyIcons( Pointers->RegisterTrayIcon( PluginInstance, DISK_ICON_ID, - &EtpDiskIconGuid, + EtpDiskIconGuid, NULL, L"&Disk history", EtEtwEnabled ? 0 : PH_NF_ICON_UNAVAILABLE, @@ -152,7 +152,7 @@ VOID EtRegisterNotifyIcons( Pointers->RegisterTrayIcon( PluginInstance, NETWORK_ICON_ID, - &EtpNetworkIconGuid, + EtpNetworkIconGuid, NULL, L"&Network history", EtEtwEnabled ? 0 : PH_NF_ICON_UNAVAILABLE, @@ -164,7 +164,7 @@ VOID EtRegisterNotifyIcons( Pointers->RegisterTrayIcon( PluginInstance, GPU_ICON_TEXT_ID, - &EtpGpuTextIconGuid, + EtpGpuTextIconGuid, NULL, L"&GPU usage (Text)", EtGpuEnabled ? 0 : PH_NF_ICON_UNAVAILABLE, @@ -176,7 +176,7 @@ VOID EtRegisterNotifyIcons( Pointers->RegisterTrayIcon( PluginInstance, DISK_ICON_TEXT_ID, - &EtpDiskTextIconGuid, + EtpDiskTextIconGuid, NULL, L"&Disk usage (Text)", EtEtwEnabled ? 0 : PH_NF_ICON_UNAVAILABLE, @@ -188,7 +188,7 @@ VOID EtRegisterNotifyIcons( Pointers->RegisterTrayIcon( PluginInstance, NETWORK_ICON_TEXT_ID, - &EtpNetworkTextIconGuid, + EtpNetworkTextIconGuid, NULL, L"&Network usage (Text)", EtEtwEnabled ? 0 : PH_NF_ICON_UNAVAILABLE, From 4a51480843c9809fb70c81732f231fa8a247e192 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 6 Apr 2019 22:18:42 +0200 Subject: [PATCH 1785/2058] Add workaround for process path/trayicon guid caching by generating one-time unique guids --- ProcessHacker/notifico.c | 113 ++++++++++++++++++------- ProcessHacker/settings.c | 1 + plugins/ExtendedTools/exttools.h | 5 ++ plugins/ExtendedTools/iconext.c | 137 ++++++++++++++++++++++++------- plugins/ExtendedTools/main.c | 2 + 5 files changed, 197 insertions(+), 61 deletions(-) diff --git a/ProcessHacker/notifico.c b/ProcessHacker/notifico.c index 376a9904e083..77e6ebfeb544 100644 --- a/ProcessHacker/notifico.c +++ b/ProcessHacker/notifico.c @@ -48,31 +48,13 @@ PH_NF_BITMAP PhNfpDefaultBitmapContext = { 0 }; PH_NF_BITMAP PhNfpBlackBitmapContext = { 0 }; HBITMAP PhNfpBlackBitmap = NULL; HICON PhNfpBlackIcon = NULL; +GUID PhNfpTrayIconItemGuids[PH_TRAY_ICON_GUID_MAXIMUM]; static POINT IconClickLocation; static PH_NF_MSG_SHOWMINIINFOSECTION_DATA IconClickShowMiniInfoSectionData; static BOOLEAN IconClickUpDueToDown = FALSE; static BOOLEAN IconDisableHover = FALSE; -// {41713862-1CEA-4AA0-AF28-FA2F4C5C5A3B} -static GUID PhNfCpuUsageGuid = { 0x41713862, 0x1cea, 0x4aa0, { 0xaf, 0x28, 0xfa, 0x2f, 0x4c, 0x5c, 0x5a, 0x3b } }; -// {5485E389-97BC-4E5B-969D-3273127DA696} -static GUID PhNfCpuHistoryGuid = { 0x5485e389, 0x97bc, 0x4e5b, { 0x96, 0x9d, 0x32, 0x73, 0x12, 0x7d, 0xa6, 0x96 } }; -// {7EAE88B5-ABBB-4024-99B8-AB7982E66AA3} -static GUID PhNfIoHistoryGuid = { 0x7eae88b5, 0xabbb, 0x4024, { 0x99, 0xb8, 0xab, 0x79, 0x82, 0xe6, 0x6a, 0xa3 } }; -// {040C2141-11EC-4D2B-B438-C407B11A6242} -static GUID PhNfCommitHistoryGuid = { 0x40c2141, 0x11ec, 0x4d2b, { 0xb4, 0x38, 0xc4, 0x7, 0xb1, 0x1a, 0x62, 0x42 } }; -// {85071CE7-FC91-4847-8F7C-CD722F6540AE} -static GUID PhNfPhysicalHistoryGuid = { 0x85071ce7, 0xfc91, 0x4847, { 0x8f, 0x7c, 0xcd, 0x72, 0x2f, 0x65, 0x40, 0xae } }; -// {BFCCBE8A-C2D8-469E-9F50-2941C895273E} -static GUID PhNfCpuUsageTextGuid = { 0xbfccbe8a, 0xc2d8, 0x469e, { 0x9f, 0x50, 0x29, 0x41, 0xc8, 0x95, 0x27, 0x3e } }; -// {E040836D-8436-4E81-A1AA-954DD37FDDDF} -static GUID PhNfIoUsageTextGuid = { 0xe040836d, 0x8436, 0x4e81, { 0xa1, 0xaa, 0x95, 0x4d, 0xd3, 0x7f, 0xdd, 0xdf } }; -// {CEA50FA3-F116-4720-8F8A-921E8030904C} -static GUID PhNfCommitTextGuid = { 0xcea50fa3, 0xf116, 0x4720, { 0x8f, 0x8a, 0x92, 0x1e, 0x80, 0x30, 0x90, 0x4c } }; -// {3A7A2A3A-FAAB-49CA-A313-A31C4CF60E1B} -static GUID PhNfPhysicalUsageTextGuid = { 0x3a7a2a3a, 0xfaab, 0x49ca, { 0xa3, 0x13, 0xa3, 0x1c, 0x4c, 0xf6, 0xe, 0x1b } }; - VOID PhNfLoadStage1( VOID ) @@ -90,7 +72,7 @@ VOID PhNfLoadSettings( PH_STRINGREF remaining; settingsString = PhGetStringSetting(L"IconSettings"); - remaining = settingsString->sr; + remaining = PhGetStringRef(settingsString); if (remaining.Length == 0) return; @@ -165,21 +147,92 @@ VOID PhNfSaveSettings( PhDereferenceObject(settingsString); } +VOID PhNfLoadGuids( + VOID + ) +{ + PPH_STRING settingsString = NULL; + PH_STRINGREF remaining; + ULONG i; + + settingsString = PhGetStringSetting(L"IconGuids"); + + if (PhIsNullOrEmptyString(settingsString)) + { + PH_STRING_BUILDER iconListBuilder; + PPH_STRING iconGuid; + + PhInitializeStringBuilder(&iconListBuilder, 100); + + for (i = 0; i < RTL_NUMBER_OF(PhNfpTrayIconItemGuids); i++) + { + PhGenerateGuid(&PhNfpTrayIconItemGuids[i]); + + if (iconGuid = PhFormatGuid(&PhNfpTrayIconItemGuids[i])) + { + PhAppendFormatStringBuilder( + &iconListBuilder, + L"%s|", + iconGuid->Buffer + ); + PhDereferenceObject(iconGuid); + } + } + + if (iconListBuilder.String->Length != 0) + PhRemoveEndStringBuilder(&iconListBuilder, 1); + + PhMoveReference(&settingsString, PhFinalStringBuilderString(&iconListBuilder)); + PhSetStringSetting2(L"IconGuids", &settingsString->sr); + PhDereferenceObject(settingsString); + } + else + { + remaining = PhGetStringRef(settingsString); + + for (i = 0; i < RTL_NUMBER_OF(PhNfpTrayIconItemGuids); i++) + { + PH_STRINGREF guidPart; + UNICODE_STRING guidStringUs; + GUID guid; + + if (remaining.Length == 0) + continue; + + PhSplitStringRefAtChar(&remaining, '|', &guidPart, &remaining); + + if (guidPart.Length == 0) + continue; + + if (!PhStringRefToUnicodeString(&guidPart, &guidStringUs)) + continue; + + if (!NT_SUCCESS(RtlGUIDFromString(&guidStringUs, &guid))) + PhGenerateGuid(&PhNfpTrayIconItemGuids[i]); + else + PhNfpTrayIconItemGuids[i] = guid; + } + + PhDereferenceObject(settingsString); + } +} + VOID PhNfLoadStage2( VOID ) { PhNfMiniInfoEnabled = !!PhGetIntegerSetting(L"MiniInfoWindowEnabled"); - - PhNfRegisterIcon(NULL, PH_TRAY_ICON_ID_CPU_USAGE, PhNfCpuUsageGuid, NULL, L"CPU &usage", 0, PhNfpCpuUsageIconUpdateCallback, NULL); - PhNfRegisterIcon(NULL, PH_TRAY_ICON_ID_CPU_HISTORY, PhNfCpuHistoryGuid, NULL, L"CPU &history", 0, PhNfpCpuHistoryIconUpdateCallback, NULL); - PhNfRegisterIcon(NULL, PH_TRAY_ICON_ID_IO_HISTORY, PhNfIoHistoryGuid, NULL, L"&I/O history", 0, PhNfpIoHistoryIconUpdateCallback, NULL); - PhNfRegisterIcon(NULL, PH_TRAY_ICON_ID_COMMIT_HISTORY, PhNfCommitHistoryGuid, NULL, L"&Commit charge history", 0, PhNfpCommitHistoryIconUpdateCallback, NULL); - PhNfRegisterIcon(NULL, PH_TRAY_ICON_ID_PHYSICAL_HISTORY, PhNfPhysicalHistoryGuid, NULL, L"&Physical memory history", 0, PhNfpPhysicalHistoryIconUpdateCallback, NULL); - PhNfRegisterIcon(NULL, PH_TRAY_ICON_ID_CPU_TEXT, PhNfCpuUsageTextGuid, NULL, L"CPU usage (text)", 0, PhNfpCpuUsageTextIconUpdateCallback, NULL); - PhNfRegisterIcon(NULL, PH_TRAY_ICON_ID_IO_TEXT, PhNfIoUsageTextGuid, NULL, L"IO usage (text)", 0, PhNfpIoUsageTextIconUpdateCallback, NULL); - PhNfRegisterIcon(NULL, PH_TRAY_ICON_ID_COMMIT_TEXT, PhNfCommitTextGuid, NULL, L"Commit usage (text)", 0, PhNfpCommitTextIconUpdateCallback, NULL); - PhNfRegisterIcon(NULL, PH_TRAY_ICON_ID_PHYSICAL_TEXT, PhNfPhysicalUsageTextGuid, NULL, L"Physical usage (text)", 0, PhNfpPhysicalUsageTextIconUpdateCallback, NULL); + PhNfLoadGuids(); + + PhNfRegisterIcon(NULL, PH_TRAY_ICON_ID_CPU_USAGE, PhNfpTrayIconItemGuids[PH_TRAY_ICON_GUID_CPU_USAGE], NULL, L"CPU &usage", 0, PhNfpCpuUsageIconUpdateCallback, NULL); + PhNfRegisterIcon(NULL, PH_TRAY_ICON_ID_CPU_HISTORY, PhNfpTrayIconItemGuids[PH_TRAY_ICON_GUID_CPU_HISTORY], NULL, L"CPU &history", 0, PhNfpCpuHistoryIconUpdateCallback, NULL); + PhNfRegisterIcon(NULL, PH_TRAY_ICON_ID_IO_HISTORY, PhNfpTrayIconItemGuids[PH_TRAY_ICON_GUID_IO_HISTORY], NULL, L"&I/O history", 0, PhNfpIoHistoryIconUpdateCallback, NULL); + PhNfRegisterIcon(NULL, PH_TRAY_ICON_ID_COMMIT_HISTORY, PhNfpTrayIconItemGuids[PH_TRAY_ICON_GUID_COMMIT_HISTORY], NULL, L"&Commit charge history", 0, PhNfpCommitHistoryIconUpdateCallback, NULL); + PhNfRegisterIcon(NULL, PH_TRAY_ICON_ID_PHYSICAL_HISTORY, PhNfpTrayIconItemGuids[PH_TRAY_ICON_GUID_PHYSICAL_HISTORY], NULL, L"&Physical memory history", 0, PhNfpPhysicalHistoryIconUpdateCallback, NULL); + PhNfRegisterIcon(NULL, PH_TRAY_ICON_ID_CPU_TEXT, PhNfpTrayIconItemGuids[PH_TRAY_ICON_GUID_CPU_TEXT], NULL, L"CPU usage (text)", 0, PhNfpCpuUsageTextIconUpdateCallback, NULL); + PhNfRegisterIcon(NULL, PH_TRAY_ICON_ID_IO_TEXT, PhNfpTrayIconItemGuids[PH_TRAY_ICON_GUID_IO_TEXT], NULL, L"IO usage (text)", 0, PhNfpIoUsageTextIconUpdateCallback, NULL); + PhNfRegisterIcon(NULL, PH_TRAY_ICON_ID_COMMIT_TEXT, PhNfpTrayIconItemGuids[PH_TRAY_ICON_GUID_COMMIT_TEXT], NULL, L"Commit usage (text)", 0, PhNfpCommitTextIconUpdateCallback, NULL); + PhNfRegisterIcon(NULL, PH_TRAY_ICON_ID_PHYSICAL_TEXT, PhNfpTrayIconItemGuids[PH_TRAY_ICON_GUID_PHYSICAL_TEXT], NULL, L"Physical usage (text)", 0, PhNfpPhysicalUsageTextIconUpdateCallback, NULL); if (PhPluginsEnabled) { diff --git a/ProcessHacker/settings.c b/ProcessHacker/settings.c index 2fa0839d78b6..581ebe2e2153 100644 --- a/ProcessHacker/settings.c +++ b/ProcessHacker/settings.c @@ -84,6 +84,7 @@ VOID PhAddDefaultSettings( PhpAddIntegerSetting(L"HideSignedProcesses", L"0"); PhpAddIntegerSetting(L"HideWaitingConnections", L"0"); PhpAddIntegerSetting(L"HighlightingDuration", L"3e8"); // 1000ms + PhpAddStringSetting(L"IconGuids", L""); PhpAddStringSetting(L"IconSettings", L"1|1"); PhpAddIntegerSetting(L"IconNotifyMask", L"c"); // PH_NOTIFY_SERVICE_CREATE | PH_NOTIFY_SERVICE_DELETE PhpAddIntegerSetting(L"IconProcesses", L"f"); // 15 diff --git a/plugins/ExtendedTools/exttools.h b/plugins/ExtendedTools/exttools.h index e156b03f86c4..16ad31d5e604 100644 --- a/plugins/ExtendedTools/exttools.h +++ b/plugins/ExtendedTools/exttools.h @@ -37,6 +37,7 @@ extern ULONG ProcessesUpdatedCount; #define SETTING_NAME_WSWATCH_WINDOW_POSITION (PLUGIN_NAME L".WsWatchWindowPosition") #define SETTING_NAME_WSWATCH_WINDOW_SIZE (PLUGIN_NAME L".WsWatchWindowSize") #define SETTING_NAME_WSWATCH_COLUMNS (PLUGIN_NAME L".WsWatchListColumns") +#define SETTING_NAME_TRAYICON_GUIDS (PLUGIN_NAME L".TrayIconGuids") // Window messages #define ET_WM_SHOWDIALOG (WM_APP + 1) @@ -559,6 +560,10 @@ VOID EtGpuMiniInformationInitializing( // iconext +VOID EtLoadTrayIconGuids( + VOID + ); + VOID EtRegisterNotifyIcons( _In_ PPH_TRAY_ICON_POINTERS Pointers ); diff --git a/plugins/ExtendedTools/iconext.c b/plugins/ExtendedTools/iconext.c index 017df337c9e8..ebb32788914e 100644 --- a/plugins/ExtendedTools/iconext.c +++ b/plugins/ExtendedTools/iconext.c @@ -26,25 +26,28 @@ #include "gpusys.h" #include -#define GPU_ICON_ID 1 -#define DISK_ICON_ID 2 -#define NETWORK_ICON_ID 3 -#define GPU_ICON_TEXT_ID 4 -#define DISK_ICON_TEXT_ID 5 -#define NETWORK_ICON_TEXT_ID 6 - -// {0B50C566-8386-44A5-897F-8FE07D55975C} -static GUID EtpGpuIconGuid = { 0xb50c566, 0x8386, 0x44a5, { 0x89, 0x7f, 0x8f, 0xe0, 0x7d, 0x55, 0x97, 0x5c } }; -// {633E07FF-4B3C-405E-82EF-1F0C6904FC05} -static GUID EtpDiskIconGuid = { 0x633e07ff, 0x4b3c, 0x405e, { 0x82, 0xef, 0x1f, 0xc, 0x69, 0x4, 0xfc, 0x5 } }; -// {05606BEE-D4B0-4BC8-B6B7-69F9685AF782} -static GUID EtpNetworkIconGuid = { 0x5606bee, 0xd4b0, 0x4bc8, { 0xb6, 0xb7, 0x69, 0xf9, 0x68, 0x5a, 0xf7, 0x82 } }; -// {A2DA7963-AD12-4938-8DF8-280D971E5277} -static GUID EtpGpuTextIconGuid = { 0xa2da7963, 0xad12, 0x4938, { 0x8d, 0xf8, 0x28, 0xd, 0x97, 0x1e, 0x52, 0x77 } }; -// {C76B1DF8-F2D2-42D0-AA78-13E214BDC663} -static GUID EtpDiskTextIconGuid = { 0xc76b1df8, 0xf2d2, 0x42d0, { 0xaa, 0x78, 0x13, 0xe2, 0x14, 0xbd, 0xc6, 0x63 } }; -// {0AE1EDF2-220D-4EAA-B4F8-ED3E07A6FB12} -static GUID EtpNetworkTextIconGuid = { 0xae1edf2, 0x220d, 0x4eaa, { 0xb4, 0xf8, 0xed, 0x3e, 0x7, 0xa6, 0xfb, 0x12 } }; +typedef enum _ETP_TRAY_ICON_ID +{ + ETP_TRAY_ICON_ID_NONE, + ETP_TRAY_ICON_ID_GPU, + ETP_TRAY_ICON_ID_DISK, + ETP_TRAY_ICON_ID_NETWORK, + ETP_TRAY_ICON_ID_GPUTEXT, + ETP_TRAY_ICON_ID_DISKTEXT, + ETP_TRAY_ICON_ID_NETWORKTEXT, + ETP_TRAY_ICON_ID_MAXIMUM +} ETP_TRAY_ICON_ID; + +typedef enum _ETP_TRAY_ICON_GUID +{ + ETP_TRAY_ICON_GUID_GPU, + ETP_TRAY_ICON_GUID_DISK, + ETP_TRAY_ICON_GUID_NETWORK, + ETP_TRAY_ICON_GUID_GPUTEXT, + ETP_TRAY_ICON_GUID_DISKTEXT, + ETP_TRAY_ICON_GUID_NETWORKTEXT, + ETP_TRAY_ICON_GUID_MAXIMUM +} ETP_TRAY_ICON_GUID; VOID EtpGpuIconUpdateCallback( _In_ struct _PH_NF_ICON *Icon, @@ -115,6 +118,78 @@ VOID EtpNetworkTextIconUpdateCallback( _In_opt_ PVOID Context ); +GUID EtpTrayIconGuids[ETP_TRAY_ICON_GUID_MAXIMUM]; + +VOID EtLoadTrayIconGuids( + VOID + ) +{ + PPH_STRING settingsString = NULL; + PH_STRINGREF remaining; + ULONG i; + + settingsString = PhGetStringSetting(SETTING_NAME_TRAYICON_GUIDS); + + if (PhIsNullOrEmptyString(settingsString)) + { + PH_STRING_BUILDER iconListBuilder; + PPH_STRING iconGuid; + + PhInitializeStringBuilder(&iconListBuilder, 100); + + for (i = 0; i < RTL_NUMBER_OF(EtpTrayIconGuids); i++) + { + PhGenerateGuid(&EtpTrayIconGuids[i]); + + if (iconGuid = PhFormatGuid(&EtpTrayIconGuids[i])) + { + PhAppendFormatStringBuilder( + &iconListBuilder, + L"%s|", + iconGuid->Buffer + ); + PhDereferenceObject(iconGuid); + } + } + + if (iconListBuilder.String->Length != 0) + PhRemoveEndStringBuilder(&iconListBuilder, 1); + + PhMoveReference(&settingsString, PhFinalStringBuilderString(&iconListBuilder)); + PhSetStringSetting2(SETTING_NAME_TRAYICON_GUIDS, &settingsString->sr); + PhDereferenceObject(settingsString); + } + else + { + remaining = PhGetStringRef(settingsString); + + for (i = 0; i < RTL_NUMBER_OF(EtpTrayIconGuids); i++) + { + PH_STRINGREF guidPart; + UNICODE_STRING guidStringUs; + GUID guid; + + if (remaining.Length == 0) + continue; + + PhSplitStringRefAtChar(&remaining, '|', &guidPart, &remaining); + + if (guidPart.Length == 0) + continue; + + if (!PhStringRefToUnicodeString(&guidPart, &guidStringUs)) + continue; + + if (!NT_SUCCESS(RtlGUIDFromString(&guidStringUs, &guid))) + PhGenerateGuid(&EtpTrayIconGuids[i]); + else + EtpTrayIconGuids[i] = guid; + } + + PhDereferenceObject(settingsString); + } +} + VOID EtRegisterNotifyIcons( _In_ PPH_TRAY_ICON_POINTERS Pointers ) @@ -127,8 +202,8 @@ VOID EtRegisterNotifyIcons( data.MessageCallback = EtpGpuIconMessageCallback; Pointers->RegisterTrayIcon( PluginInstance, - GPU_ICON_ID, - EtpGpuIconGuid, + ETP_TRAY_ICON_ID_GPU, + EtpTrayIconGuids[ETP_TRAY_ICON_GUID_GPU], NULL, L"&GPU history", EtGpuEnabled ? 0 : PH_NF_ICON_UNAVAILABLE, @@ -139,8 +214,8 @@ VOID EtRegisterNotifyIcons( data.MessageCallback = EtpDiskIconMessageCallback; Pointers->RegisterTrayIcon( PluginInstance, - DISK_ICON_ID, - EtpDiskIconGuid, + ETP_TRAY_ICON_ID_DISK, + EtpTrayIconGuids[ETP_TRAY_ICON_GUID_DISK], NULL, L"&Disk history", EtEtwEnabled ? 0 : PH_NF_ICON_UNAVAILABLE, @@ -151,8 +226,8 @@ VOID EtRegisterNotifyIcons( data.MessageCallback = EtpNetworkIconMessageCallback; Pointers->RegisterTrayIcon( PluginInstance, - NETWORK_ICON_ID, - EtpNetworkIconGuid, + ETP_TRAY_ICON_ID_NETWORK, + EtpTrayIconGuids[ETP_TRAY_ICON_GUID_NETWORK], NULL, L"&Network history", EtEtwEnabled ? 0 : PH_NF_ICON_UNAVAILABLE, @@ -163,8 +238,8 @@ VOID EtRegisterNotifyIcons( data.MessageCallback = EtpGpuIconMessageCallback; Pointers->RegisterTrayIcon( PluginInstance, - GPU_ICON_TEXT_ID, - EtpGpuTextIconGuid, + ETP_TRAY_ICON_ID_GPUTEXT, + EtpTrayIconGuids[ETP_TRAY_ICON_GUID_GPUTEXT], NULL, L"&GPU usage (Text)", EtGpuEnabled ? 0 : PH_NF_ICON_UNAVAILABLE, @@ -175,8 +250,8 @@ VOID EtRegisterNotifyIcons( data.MessageCallback = EtpDiskIconMessageCallback; Pointers->RegisterTrayIcon( PluginInstance, - DISK_ICON_TEXT_ID, - EtpDiskTextIconGuid, + ETP_TRAY_ICON_ID_DISKTEXT, + EtpTrayIconGuids[ETP_TRAY_ICON_GUID_DISKTEXT], NULL, L"&Disk usage (Text)", EtEtwEnabled ? 0 : PH_NF_ICON_UNAVAILABLE, @@ -187,8 +262,8 @@ VOID EtRegisterNotifyIcons( data.MessageCallback = EtpNetworkIconMessageCallback; Pointers->RegisterTrayIcon( PluginInstance, - NETWORK_ICON_TEXT_ID, - EtpNetworkTextIconGuid, + ETP_TRAY_ICON_ID_NETWORKTEXT, + EtpTrayIconGuids[ETP_TRAY_ICON_GUID_NETWORKTEXT], NULL, L"&Network usage (Text)", EtEtwEnabled ? 0 : PH_NF_ICON_UNAVAILABLE, diff --git a/plugins/ExtendedTools/main.c b/plugins/ExtendedTools/main.c index e2263bd33d9b..f59c9c0a3d67 100644 --- a/plugins/ExtendedTools/main.c +++ b/plugins/ExtendedTools/main.c @@ -330,6 +330,7 @@ VOID NTAPI TrayIconsInitializingCallback( _In_opt_ PVOID Context ) { + EtLoadTrayIconGuids(); EtRegisterNotifyIcons(Parameter); } @@ -527,6 +528,7 @@ LOGICAL DllMain( { IntegerPairSettingType, SETTING_NAME_WSWATCH_WINDOW_POSITION, L"0,0" }, { ScalableIntegerPairSettingType, SETTING_NAME_WSWATCH_WINDOW_SIZE, L"@96|325,266" }, { StringSettingType, SETTING_NAME_WSWATCH_COLUMNS, L"" }, + { StringSettingType, SETTING_NAME_TRAYICON_GUIDS, L"" }, }; PluginInstance = PhRegisterPlugin(PLUGIN_NAME, Instance, &info); From b19bc89aeef9de82884adf8473028622f4b8b65d Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 6 Apr 2019 22:22:12 +0200 Subject: [PATCH 1786/2058] Add missing file from previous commit --- ProcessHacker/include/notifico.h | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/ProcessHacker/include/notifico.h b/ProcessHacker/include/notifico.h index 53d79bac1daa..44cabf79f699 100644 --- a/ProcessHacker/include/notifico.h +++ b/ProcessHacker/include/notifico.h @@ -14,9 +14,24 @@ typedef enum _PH_TRAY_ICON_ID PH_TRAY_ICON_ID_CPU_TEXT, PH_TRAY_ICON_ID_IO_TEXT, PH_TRAY_ICON_ID_COMMIT_TEXT, - PH_TRAY_ICON_ID_PHYSICAL_TEXT + PH_TRAY_ICON_ID_PHYSICAL_TEXT, + PH_TRAY_ICON_ID_MAXIMUM } PH_TRAY_ICON_ID; +typedef enum _PH_TRAY_ICON_GUID +{ + PH_TRAY_ICON_GUID_CPU_USAGE, + PH_TRAY_ICON_GUID_CPU_HISTORY, + PH_TRAY_ICON_GUID_IO_HISTORY, + PH_TRAY_ICON_GUID_COMMIT_HISTORY, + PH_TRAY_ICON_GUID_PHYSICAL_HISTORY, + PH_TRAY_ICON_GUID_CPU_TEXT, + PH_TRAY_ICON_GUID_IO_TEXT, + PH_TRAY_ICON_GUID_COMMIT_TEXT, + PH_TRAY_ICON_GUID_PHYSICAL_TEXT, + PH_TRAY_ICON_GUID_MAXIMUM +} PH_TRAY_ICON_GUID; + #define PH_TRAY_ICON_ID_PLUGIN 0x80 #define PH_ICON_LIMIT 0x80000000 From 57def91eae17255c1707e4ee0267857274934680 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 12 Apr 2019 20:53:19 +0200 Subject: [PATCH 1787/2058] ToolStatus: Fix searching PID as hex --- plugins/ToolStatus/filter.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/plugins/ToolStatus/filter.c b/plugins/ToolStatus/filter.c index a82218228d1b..4a2ccb40bf0a 100644 --- a/plugins/ToolStatus/filter.c +++ b/plugins/ToolStatus/filter.c @@ -133,10 +133,29 @@ BOOLEAN ProcessTreeFilterCallback( return TRUE; } - if (processNode->ProcessItem->ProcessIdString[0]) + if (PH_IS_REAL_PROCESS_ID(processNode->ProcessItem->ProcessId) && processNode->ProcessItem->ProcessIdString[0]) { if (WordMatchStringZ(processNode->ProcessItem->ProcessIdString)) return TRUE; + + // HACK PidHexText from PH_PROCESS_NODE is not exported (dmex) + { + PH_FORMAT format; + SIZE_T returnLength; + PH_STRINGREF processIdHex; + WCHAR pidHexText[PH_PTR_STR_LEN_1]; + + PhInitFormatIX(&format, HandleToUlong(processNode->ProcessItem->ProcessId)); + + if (PhFormatToBuffer(&format, 1, pidHexText, sizeof(pidHexText), &returnLength)) + { + processIdHex.Buffer = pidHexText; + processIdHex.Length = returnLength - sizeof(UNICODE_NULL); + + if (WordMatchStringRef(&processIdHex)) + return TRUE; + } + } } if (processNode->ProcessItem->ParentProcessIdString[0]) From 5c9f46ca4d8ba16627fdfa628316cc94e4e11ca5 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 12 Apr 2019 20:53:54 +0200 Subject: [PATCH 1788/2058] Remove legacy trayicon version support --- ProcessHacker/notifico.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ProcessHacker/notifico.c b/ProcessHacker/notifico.c index 77e6ebfeb544..821c8b280d3f 100644 --- a/ProcessHacker/notifico.c +++ b/ProcessHacker/notifico.c @@ -445,7 +445,7 @@ BOOLEAN PhNfShowBalloonTip( _In_ ULONG Flags ) { - NOTIFYICONDATA notifyIcon = { NOTIFYICONDATA_V3_SIZE }; + NOTIFYICONDATA notifyIcon = { sizeof(NOTIFYICONDATA) }; PPH_NF_ICON registeredIcon = NULL; for (ULONG i = 0; i < PhTrayIconItemList->Count; i++) @@ -660,7 +660,7 @@ BOOLEAN PhNfpAddNotifyIcon( _In_ PPH_NF_ICON Icon ) { - NOTIFYICONDATA notifyIcon = { NOTIFYICONDATA_V3_SIZE }; + NOTIFYICONDATA notifyIcon = { sizeof(NOTIFYICONDATA) }; if (PhMainWndExiting) return FALSE; @@ -692,7 +692,7 @@ BOOLEAN PhNfpRemoveNotifyIcon( _In_ PPH_NF_ICON Icon ) { - NOTIFYICONDATA notifyIcon = { NOTIFYICONDATA_V3_SIZE }; + NOTIFYICONDATA notifyIcon = { sizeof(NOTIFYICONDATA) }; notifyIcon.uFlags = NIF_GUID; notifyIcon.hWnd = PhMainWndHandle; From 37a037cdf4ce4ea7fa9b3840bd620f7b36d4471e Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 14 Apr 2019 13:18:27 +0200 Subject: [PATCH 1789/2058] Add combobox theme support --- phlib/theme.c | 49 +++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 43 insertions(+), 6 deletions(-) diff --git a/phlib/theme.c b/phlib/theme.c index 66aa788d4211..e6bd0a1b4214 100644 --- a/phlib/theme.c +++ b/phlib/theme.c @@ -869,6 +869,37 @@ BOOLEAN PhThemeWindowDrawItem( return TRUE; } + case ODT_COMBOBOX: + { + WCHAR comboText[MAX_PATH]; + + switch (PhpThemeColorMode) + { + case 0: // New colors + SetTextColor(DrawInfo->hDC, GetSysColor(COLOR_WINDOWTEXT)); + SetDCBrushColor(DrawInfo->hDC, RGB(0xff, 0xff, 0xff)); + break; + case 1: // Old colors + SetTextColor(DrawInfo->hDC, GetSysColor(COLOR_HIGHLIGHTTEXT)); + SetDCBrushColor(DrawInfo->hDC, RGB(28, 28, 28)); + break; + } + + FillRect(DrawInfo->hDC, &DrawInfo->rcItem, GetStockObject(DC_BRUSH)); + + if (ComboBox_GetLBText(DrawInfo->hwndItem, DrawInfo->itemID, (LPARAM)comboText) != CB_ERR) + { + DrawText( + DrawInfo->hDC, + comboText, + (UINT)PhCountStringZ(comboText), + &DrawInfo->rcItem, + DT_LEFT | DT_END_ELLIPSIS | DT_SINGLELINE + ); + } + return TRUE; + } + break; } return FALSE; @@ -1066,11 +1097,12 @@ LRESULT CALLBACK PhpThemeWindowDrawButton( } else if ((buttonStyle & BS_CHECKBOX) == BS_CHECKBOX) { - HFONT newFont = PhDuplicateFontWithNewHeight(PhApplicationFont, 22); - oldFont = SelectFont(DrawInfo->hdc, newFont); - + if (Button_GetCheck(DrawInfo->hdr.hwndFrom) == BST_CHECKED) { + HFONT newFont = PhDuplicateFontWithNewHeight(PhApplicationFont, 16); + + oldFont = SelectFont(DrawInfo->hdc, newFont); DrawText( DrawInfo->hdc, L"\u2611", @@ -1078,9 +1110,14 @@ LRESULT CALLBACK PhpThemeWindowDrawButton( &DrawInfo->rc, DT_LEFT | DT_SINGLELINE | DT_VCENTER ); + SelectFont(DrawInfo->hdc, oldFont); + DeleteFont(newFont); } else { + HFONT newFont = PhDuplicateFontWithNewHeight(PhApplicationFont, 22); + + oldFont = SelectFont(DrawInfo->hdc, newFont); DrawText( DrawInfo->hdc, L"\u2610", @@ -1088,11 +1125,10 @@ LRESULT CALLBACK PhpThemeWindowDrawButton( &DrawInfo->rc, DT_LEFT | DT_SINGLELINE | DT_VCENTER ); + SelectFont(DrawInfo->hdc, oldFont); + DeleteFont(newFont); } - SelectFont(DrawInfo->hdc, oldFont); - DeleteFont(newFont); - DrawInfo->rc.left += 10; DrawText( DrawInfo->hdc, @@ -1540,6 +1576,7 @@ LRESULT CALLBACK PhpThemeWindowSubclassProc( case WM_CTLCOLORBTN: case WM_CTLCOLORDLG: case WM_CTLCOLORSTATIC: + case WM_CTLCOLORLISTBOX: { SetBkMode((HDC)wParam, TRANSPARENT); From cd17bbc0fd468337b0d3a44f8b1f940f0ea90a68 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 14 Apr 2019 15:03:33 +0200 Subject: [PATCH 1790/2058] Fix appresolver type --- phlib/include/appresolverp.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/phlib/include/appresolverp.h b/phlib/include/appresolverp.h index 04cf9d2a49ec..2d85aa5e6659 100644 --- a/phlib/include/appresolverp.h +++ b/phlib/include/appresolverp.h @@ -71,7 +71,7 @@ static BOOL (WINAPI* AppContainerFreeMemory_I)( static HRESULT (WINAPI* AppPolicyGetWindowingModel_I)( _In_ HANDLE ProcessTokenHandle, _Out_ AppPolicyWindowingModel *ProcessWindowingModelPolicy - ); + ) = NULL; typedef enum _START_MENU_APP_ITEMS_FLAGS { @@ -494,8 +494,8 @@ DECLARE_INTERFACE_IID(IResourceMap, IUnknown) ((This)->lpVtbl->GetNamedResourceCount(This, Count)) #define IResourceMap_GetNamedResourceUri(This, Index, Name) \ ((This)->lpVtbl->GetNamedResourceUri(This, Index, Name)) -#define IResourceMap_GetNamedResource(This) \ - ((This)->lpVtbl->GetNamedResource(This)) +#define IResourceMap_GetNamedResource(This, Name, rrid, ppvObject) \ + ((This)->lpVtbl->GetNamedResource(This, Name, rrid, ppvObject)) #define IResourceMap_GetFullyQualifiedReference(This) \ ((This)->lpVtbl->GetFullyQualifiedReference(This)) #define IResourceMap_GetFilePathByUri(This) \ From cc3582a8d48e410dfa8a0b08b53db38dd568e700 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 14 Apr 2019 15:05:46 +0200 Subject: [PATCH 1791/2058] Add PhGetTokenProcessTrustLevelRID, PhGetAppContainerNamedObjectPath, PhGetTokenIsAppContainer, PhGetSecurityDescriptorAsString --- phlib/include/phnative.h | 52 ++++++++++ phlib/include/phnativeinl.h | 46 +++++++++ phlib/native.c | 200 ++++++++++++++++++++++++++++++++++++ 3 files changed, 298 insertions(+) diff --git a/phlib/include/phnative.h b/phlib/include/phnative.h index bac192dbd7c9..ce23587df5fb 100644 --- a/phlib/include/phnative.h +++ b/phlib/include/phnative.h @@ -146,6 +146,14 @@ PhSetObjectSecurity( _In_ PSECURITY_DESCRIPTOR SecurityDescriptor ); +PHLIBAPI +PPH_STRING +NTAPI +PhGetSecurityDescriptorAsString( + _In_ SECURITY_INFORMATION SecurityInformation, + _In_ PSECURITY_DESCRIPTOR SecurityDescriptor + ); + PHLIBAPI NTSTATUS NTAPI @@ -421,6 +429,33 @@ PhGetTokenTrustLevel( _Out_ PTOKEN_PROCESS_TRUST_LEVEL *TrustLevel ); +PHLIBAPI +NTSTATUS +NTAPI +PhGetTokenNamedObjectPath( + _In_ HANDLE TokenHandle, + _In_opt_ PSID Sid, + _Out_ PPH_STRING* ObjectPath + ); + +PHLIBAPI +NTSTATUS +NTAPI +PhGetAppContainerNamedObjectPath( + _In_ HANDLE TokenHandle, + _In_opt_ PSID AppContainerSid, + _In_ BOOLEAN RelativePath, + _Out_ PPH_STRING* ObjectPath + ); + +PHLIBAPI +BOOLEAN +NTAPI +PhGetTokenSecurityDescriptorAsString( + _In_ HANDLE TokenHandle, + _Out_ PPH_STRING* SecurityDescriptorString + ); + PHLIBAPI NTSTATUS NTAPI @@ -484,6 +519,17 @@ PhGetTokenIntegrityLevel( _Out_opt_ PWSTR *IntegrityString ); +PHLIBAPI +NTSTATUS +NTAPI +PhGetTokenProcessTrustLevelRID( + _In_ HANDLE TokenHandle, + _Out_opt_ PULONG ProtectionType, + _Out_opt_ PULONG ProtectionLevel, + _Out_opt_ PPH_STRING* TrustLevelString, + _Out_opt_ PPH_STRING* TrustLevelSidString + ); + PHLIBAPI NTSTATUS NTAPI @@ -784,6 +830,12 @@ PhGetKernelFileName( sizeof(SYSTEM_THREAD_INFORMATION) * \ ((PSYSTEM_PROCESS_INFORMATION)(Process))->NumberOfThreads)) +#define PH_EXTENDED_PROCESS_EXTENSION(Process) \ + ((PSYSTEM_PROCESS_INFORMATION_EXTENSION)PTR_ADD_OFFSET((Process), \ + UFIELD_OFFSET(SYSTEM_PROCESS_INFORMATION, Threads) + \ + sizeof(SYSTEM_EXTENDED_THREAD_INFORMATION) * \ + ((PSYSTEM_PROCESS_INFORMATION)(Process))->NumberOfThreads)) + PHLIBAPI NTSTATUS NTAPI diff --git a/phlib/include/phnativeinl.h b/phlib/include/phnativeinl.h index aa6021d2de62..87628c59eacb 100644 --- a/phlib/include/phnativeinl.h +++ b/phlib/include/phnativeinl.h @@ -1466,6 +1466,52 @@ PhGetTokenOrigin( ); } +FORCEINLINE +NTSTATUS +PhGetTokenIsAppContainer( + _In_ HANDLE TokenHandle, + _Out_ PBOOLEAN IsAppContainer + ) +{ + NTSTATUS status; + ULONG returnLength; + ULONG isAppContainer; + + status = NtQueryInformationToken( + TokenHandle, + TokenIsAppContainer, + &isAppContainer, + sizeof(ULONG), + &returnLength + ); + + if (!NT_SUCCESS(status)) + return status; + + *IsAppContainer = !!isAppContainer; + + return status; +} + +FORCEINLINE +NTSTATUS +PhGetTokenAppContainerNumber( + _In_ HANDLE TokenHandle, + _Out_ PULONG AppContainerNumber + ) +{ + ULONG returnLength; + + return NtQueryInformationToken( + TokenHandle, + TokenAppContainerNumber, + AppContainerNumber, + sizeof(ULONG), + &returnLength + ); +} + + FORCEINLINE NTSTATUS PhGetEventBasicInformation( diff --git a/phlib/native.c b/phlib/native.c index ea18d7c8eaf2..a859715d796d 100644 --- a/phlib/native.c +++ b/phlib/native.c @@ -28,6 +28,8 @@ #include #include +#include + #define PH_DEVICE_PREFIX_LENGTH 64 #define PH_DEVICE_MUP_PREFIX_MAX_COUNT 16 @@ -433,6 +435,33 @@ NTSTATUS PhSetObjectSecurity( ); } +PPH_STRING PhGetSecurityDescriptorAsString( + _In_ SECURITY_INFORMATION SecurityInformation, + _In_ PSECURITY_DESCRIPTOR SecurityDescriptor + ) +{ + PPH_STRING securityDescriptorString = NULL; + ULONG stringSecurityDescriptorLength; + PWSTR stringSecurityDescriptor; + + if (ConvertSecurityDescriptorToStringSecurityDescriptor( + SecurityDescriptor, + SDDL_REVISION, + SecurityInformation, + &stringSecurityDescriptor, + &stringSecurityDescriptorLength + )) + { + securityDescriptorString = PhCreateStringEx( + stringSecurityDescriptor, + stringSecurityDescriptorLength * sizeof(WCHAR) + ); + LocalFree(stringSecurityDescriptor); + } + + return securityDescriptorString; +} + /** * Terminates a process. * @@ -2165,6 +2194,86 @@ NTSTATUS PhSetTokenSessionId( ); } +NTSTATUS PhGetTokenNamedObjectPath( + _In_ HANDLE TokenHandle, + _In_opt_ PSID Sid, + _Out_ PPH_STRING* ObjectPath + ) +{ + NTSTATUS status; + UNICODE_STRING namedObjectPathUs; + + status = RtlGetTokenNamedObjectPath( + TokenHandle, + Sid, + &namedObjectPathUs + ); + + if (NT_SUCCESS(status)) + { + *ObjectPath = PhCreateStringFromUnicodeString(&namedObjectPathUs); + RtlFreeUnicodeString(&namedObjectPathUs); + } + + return status; +} + +NTSTATUS PhGetAppContainerNamedObjectPath( + _In_ HANDLE TokenHandle, + _In_opt_ PSID AppContainerSid, + _In_ BOOLEAN RelativePath, + _Out_ PPH_STRING* ObjectPath + ) +{ + NTSTATUS status; + UNICODE_STRING namedObjectPathUs; + + status = RtlGetAppContainerNamedObjectPath( + TokenHandle, + AppContainerSid, + RelativePath, + &namedObjectPathUs + ); + + if (NT_SUCCESS(status)) + { + *ObjectPath = PhCreateStringFromUnicodeString(&namedObjectPathUs); + RtlFreeUnicodeString(&namedObjectPathUs); + } + + return status; +} + +BOOLEAN PhGetTokenSecurityDescriptorAsString( + _In_ HANDLE TokenHandle, + _Out_ PPH_STRING* SecurityDescriptorString + ) +{ + PSECURITY_DESCRIPTOR securityDescriptor; + + if (NT_SUCCESS(PhGetObjectSecurity( + TokenHandle, + OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | + DACL_SECURITY_INFORMATION | LABEL_SECURITY_INFORMATION | + ATTRIBUTE_SECURITY_INFORMATION | SCOPE_SECURITY_INFORMATION, + &securityDescriptor + ))) + { + *SecurityDescriptorString = PhGetSecurityDescriptorAsString( + OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | + DACL_SECURITY_INFORMATION | LABEL_SECURITY_INFORMATION | + ATTRIBUTE_SECURITY_INFORMATION | SCOPE_SECURITY_INFORMATION, + securityDescriptor + ); + + PhFree(securityDescriptor); + + return TRUE; + } + + return FALSE; +} + /** * Modifies a token privilege. * @@ -2451,6 +2560,97 @@ NTSTATUS PhGetTokenIntegrityLevel( return status; } +NTSTATUS PhGetTokenProcessTrustLevelRID( + _In_ HANDLE TokenHandle, + _Out_opt_ PULONG ProtectionType, + _Out_opt_ PULONG ProtectionLevel, + _Out_opt_ PPH_STRING* TrustLevelString, + _Out_opt_ PPH_STRING* TrustLevelSidString + ) +{ + NTSTATUS status; + PTOKEN_SID_INFORMATION trustLevel; + ULONG subAuthoritiesCount; + ULONG protectionType; + ULONG protectionLevel; + + status = PhpQueryTokenVariableSize(TokenHandle, TokenProcessTrustLevel, &trustLevel); + + if (!NT_SUCCESS(status)) + return status; + + if (!RtlValidSid(trustLevel->Sid)) + return STATUS_UNSUCCESSFUL; + + subAuthoritiesCount = *RtlSubAuthorityCountSid(trustLevel->Sid); + //RtlIdentifierAuthoritySid(TokenPageContext->Capabilities->Groups[i].Sid) == (BYTE[])SECURITY_PROCESS_TRUST_AUTHORITY + + if (subAuthoritiesCount == SECURITY_PROCESS_TRUST_AUTHORITY_RID_COUNT) + { + protectionType = *RtlSubAuthoritySid(trustLevel->Sid, 0); + protectionLevel = *RtlSubAuthoritySid(trustLevel->Sid, 1); + } + else + { + protectionType = SECURITY_PROCESS_PROTECTION_TYPE_NONE_RID; + protectionLevel = SECURITY_PROCESS_PROTECTION_LEVEL_NONE_RID; + } + + if (ProtectionType) + *ProtectionType = protectionType; + if (ProtectionLevel) + *ProtectionLevel = protectionLevel; + + if (TrustLevelString) + { + PWSTR protectionTypeString = NULL; + PWSTR protectionLevelString = NULL; + + switch (protectionType) + { + case SECURITY_PROCESS_PROTECTION_TYPE_FULL_RID: + protectionTypeString = L"Full"; + break; + case SECURITY_PROCESS_PROTECTION_TYPE_LITE_RID: + protectionTypeString = L"Lite"; + break; + } + + switch (protectionLevel) + { + case SECURITY_PROCESS_PROTECTION_LEVEL_WINTCB_RID: + protectionLevelString = L" (WinTcb)"; + break; + case SECURITY_PROCESS_PROTECTION_LEVEL_WINDOWS_RID: + protectionLevelString = L" (Windows)"; + break; + case SECURITY_PROCESS_PROTECTION_LEVEL_APP_RID: + protectionLevelString = L" (StoreApp)"; + break; + case SECURITY_PROCESS_PROTECTION_LEVEL_ANTIMALWARE_RID: + protectionLevelString = L" (Antimalware)"; + break; + case SECURITY_PROCESS_PROTECTION_LEVEL_AUTHENTICODE_RID: + protectionLevelString = L" (Authenticode)"; + break; + } + + if (protectionTypeString && protectionLevelString) + *TrustLevelString = PhConcatStrings2(protectionTypeString, protectionLevelString); + else + *TrustLevelString = PhCreateString(L"Unknown"); + } + + if (TrustLevelSidString) + { + *TrustLevelSidString = PhSidToStringSid(trustLevel->Sid); + } + + PhFree(trustLevel); + + return status; +} + NTSTATUS PhpQueryFileVariableSize( _In_ HANDLE FileHandle, _In_ FILE_INFORMATION_CLASS FileInformationClass, From ff53d413b2cf8ef3dbd4e5e76ba514eb5612816d Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 14 Apr 2019 15:07:18 +0200 Subject: [PATCH 1792/2058] Fix SystemProcessType --- ProcessHacker/appsup.c | 2 +- ProcessHacker/chproc.c | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/ProcessHacker/appsup.c b/ProcessHacker/appsup.c index d5cefa8a6b9d..27f9e832af78 100644 --- a/ProcessHacker/appsup.c +++ b/ProcessHacker/appsup.c @@ -313,7 +313,7 @@ PH_KNOWN_PROCESS_TYPE PhGetProcessKnownTypeEx( BOOLEAN isWow64 = FALSE; #endif - if (ProcessId == SYSTEM_PROCESS_ID) + if (ProcessId == SYSTEM_PROCESS_ID || ProcessId == SYSTEM_IDLE_PROCESS_ID) return SystemProcessType; if (PhIsNullOrEmptyString(FileName)) diff --git a/ProcessHacker/chproc.c b/ProcessHacker/chproc.c index c1eae2d61438..73c96962c15c 100644 --- a/ProcessHacker/chproc.c +++ b/ProcessHacker/chproc.c @@ -21,6 +21,7 @@ */ #include +#include #include typedef struct _CHOOSE_PROCESS_DIALOG_CONTEXT @@ -137,7 +138,7 @@ static VOID PhpRefreshProcessList( if (process->UniqueProcessId == SYSTEM_PROCESS_ID) fileName = PhGetKernelFileName(); - else + else if (PH_IS_REAL_PROCESS_ID(process->UniqueProcessId)) PhGetProcessImageFileNameByProcessId(process->UniqueProcessId, &fileName); if (fileName) From ac444ac6b71ebbf91c2793da37e9e04fa3917fc5 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 14 Apr 2019 15:10:06 +0200 Subject: [PATCH 1793/2058] Update token advanced page layout, Add new token properties, Add token appcontainer page --- ProcessHacker/ProcessHacker.rc | 21 +- ProcessHacker/tokprp.c | 541 ++++++++++++++++++++++++++++++--- 2 files changed, 509 insertions(+), 53 deletions(-) diff --git a/ProcessHacker/ProcessHacker.rc b/ProcessHacker/ProcessHacker.rc index b89da45070fe..f7baf30c2ce9 100644 --- a/ProcessHacker/ProcessHacker.rc +++ b/ProcessHacker/ProcessHacker.rc @@ -756,18 +756,7 @@ STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSM CAPTION "Advanced" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN - LTEXT "Type:",IDC_STATIC,7,8,20,8 - EDITTEXT IDC_TYPE,81,7,116,12,ES_AUTOHSCROLL | ES_READONLY - LTEXT "Impersonation level:",IDC_STATIC,7,26,68,8 - EDITTEXT IDC_IMPERSONATIONLEVEL,81,24,116,12,ES_AUTOHSCROLL | ES_READONLY - LTEXT "Token LUID:",IDC_STATIC,7,43,55,8 - EDITTEXT IDC_TOKENLUID,81,41,116,12,ES_AUTOHSCROLL | ES_READONLY - LTEXT "Authentication LUID:",IDC_STATIC,7,61,68,8 - EDITTEXT IDC_AUTHENTICATIONLUID,81,59,116,12,ES_AUTOHSCROLL | ES_READONLY - LTEXT "Memory used:",IDC_STATIC,7,78,47,8 - EDITTEXT IDC_MEMORYUSED,81,76,116,12,ES_AUTOHSCROLL | ES_READONLY - LTEXT "Memory available:",IDC_STATIC,7,95,60,8 - EDITTEXT IDC_MEMORYAVAILABLE,81,93,116,12,ES_AUTOHSCROLL | ES_READONLY + CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_ALIGNLEFT | WS_TABSTOP,0,0,236,186 END IDD_OBJJOB DIALOGEX 0, 0, 260, 260 @@ -1356,7 +1345,7 @@ STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSM CAPTION "Capabilities" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN - CONTROL "",IDC_LIST,"PhTreeNew",WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP | 0x32,0,0,270,228,WS_EX_CLIENTEDGE + CONTROL "",IDC_LIST,"PhTreeNew",WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP | 0x32,0,0,270,228 END IDD_TOKATTRIBUTES DIALOGEX 0, 0, 270, 228 @@ -1364,7 +1353,7 @@ STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSM CAPTION "Attributes" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN - CONTROL "",IDC_LIST,"PhTreeNew",WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP | 0x32,0,0,270,228,WS_EX_CLIENTEDGE + CONTROL "",IDC_LIST,"PhTreeNew",WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP | 0x32,0,0,270,228 END IDD_SYSINFO_CPU DIALOGEX 0, 0, 316, 195 @@ -1871,10 +1860,6 @@ BEGIN IDD_TOKADVANCED, DIALOG BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 229 - TOPMARGIN, 7 - BOTTOMMARGIN, 179 END IDD_OBJJOB, DIALOG diff --git a/ProcessHacker/tokprp.c b/ProcessHacker/tokprp.c index 201b50517c3a..088e413f8a68 100644 --- a/ProcessHacker/tokprp.c +++ b/ProcessHacker/tokprp.c @@ -32,10 +32,10 @@ typedef enum _PH_PROCESS_TOKEN_CATEGORY { + PH_PROCESS_TOKEN_CATEGORY_DANGEROUS_FLAGS, PH_PROCESS_TOKEN_CATEGORY_PRIVILEGES, PH_PROCESS_TOKEN_CATEGORY_GROUPS, - PH_PROCESS_TOKEN_CATEGORY_RESTRICTED, - PH_PROCESS_TOKEN_CATEGORY_DANGEROUS_FLAGS + PH_PROCESS_TOKEN_CATEGORY_RESTRICTED } PH_PROCESS_TOKEN_CATEGORY; typedef enum _PH_PROCESS_TOKEN_FLAG @@ -110,6 +110,10 @@ PH_ACCESS_ENTRY GroupDescriptionEntries[6] = { NULL, SE_GROUP_RESOURCE, FALSE, FALSE, L"Resource" } }; +static PH_STRINGREF PhpEmptyTokenAttributesText = PH_STRINGREF_INIT(L"There are no attributes to display."); +static PH_STRINGREF PhpEmptyTokenClaimsText = PH_STRINGREF_INIT(L"There are no claims to display."); +static PH_STRINGREF PhpEmptyTokenCapabilitiesText = PH_STRINGREF_INIT(L"There are no capabilities to display."); + INT CALLBACK PhpTokenPropPageProc( _In_ HWND hwnd, _In_ UINT uMsg, @@ -125,7 +129,8 @@ INT_PTR CALLBACK PhpTokenPageProc( VOID PhpShowTokenAdvancedProperties( _In_ HWND ParentWindowHandle, - _In_ PTOKEN_PAGE_CONTEXT Context + _In_ PTOKEN_PAGE_CONTEXT Context, + _In_ BOOLEAN ShowAppContainerPage ); INT_PTR CALLBACK PhpTokenGeneralPageProc( @@ -171,6 +176,13 @@ INT_PTR CALLBACK PhpTokenAttributesPageProc( _In_ LPARAM lParam ); +INT_PTR CALLBACK PhpTokenContainerPageProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + VOID PhShowTokenProperties( _In_ HWND ParentWindowHandle, _In_ PPH_OPEN_OBJECT OpenObject, @@ -604,7 +616,8 @@ VOID PhpUpdateTokenDangerousFlagItem( lvitem ); - PhSetListViewSubItem(ListViewHandle, + PhSetListViewSubItem( + ListViewHandle, lvItemIndex, PH_PROCESS_TOKEN_INDEX_STATUS, State ? L"Enabled (modified)" : L"Disabled (modified)" @@ -752,9 +765,7 @@ INT_PTR CALLBACK PhpTokenPageProc( PTOKEN_APPCONTAINER_INFORMATION appContainerInfo; PPH_STRING appContainerName; PPH_STRING appContainerSid; - - // TOKEN_BNO_ISOLATION_INFORMATION - + if (NT_SUCCESS(PhGetTokenUser(tokenHandle, &tokenUser))) { if (fullUserName = PhGetSidFullName(tokenUser->User.Sid, TRUE, NULL)) @@ -1405,7 +1416,20 @@ INT_PTR CALLBACK PhpTokenPageProc( break; case IDC_ADVANCED: { - PhpShowTokenAdvancedProperties(hwndDlg, tokenPageContext); + HANDLE tokenHandle; + BOOLEAN tokenIsAppContainer = FALSE; + + if (NT_SUCCESS(tokenPageContext->OpenObject( + &tokenHandle, + TOKEN_QUERY, + tokenPageContext->Context + ))) + { + PhGetTokenIsAppContainer(tokenHandle, &tokenIsAppContainer); + NtClose(tokenHandle); + } + + PhpShowTokenAdvancedProperties(hwndDlg, tokenPageContext, tokenIsAppContainer); } break; } @@ -1543,11 +1567,12 @@ INT_PTR CALLBACK PhpTokenPageProc( VOID PhpShowTokenAdvancedProperties( _In_ HWND ParentWindowHandle, - _In_ PTOKEN_PAGE_CONTEXT Context + _In_ PTOKEN_PAGE_CONTEXT Context, + _In_ BOOLEAN ShowAppContainerPage ) { PROPSHEETHEADER propSheetHeader = { sizeof(propSheetHeader) }; - HPROPSHEETPAGE pages[5]; + HPROPSHEETPAGE pages[6]; PROPSHEETPAGE page; ULONG numberOfPages; @@ -1585,6 +1610,19 @@ VOID PhpShowTokenAdvancedProperties( if (WindowsVersion >= WINDOWS_8) { + if (ShowAppContainerPage) + { + memset(&page, 0, sizeof(PROPSHEETPAGE)); + page.dwSize = sizeof(PROPSHEETPAGE); + page.dwFlags = PSP_USETITLE; + page.pszTemplate = MAKEINTRESOURCE(IDD_TOKADVANCED); + page.hInstance = PhInstanceHandle; + page.pszTitle = L"Container"; + page.pfnDlgProc = PhpTokenContainerPageProc; + page.lParam = (LPARAM)Context; + pages[numberOfPages++] = CreatePropertySheetPage(&page); + } + // Capabilities memset(&page, 0, sizeof(PROPSHEETPAGE)); @@ -1747,7 +1785,7 @@ INT_PTR CALLBACK PhpTokenGeneralPageProc( tokenSource.SourceName, TOKEN_SOURCE_LENGTH, tokenSourceName, - sizeof(tokenSourceName) / 2, + RTL_NUMBER_OF(tokenSourceName), NULL ); @@ -1829,6 +1867,13 @@ INT_PTR CALLBACK PhpTokenGeneralPageProc( return FALSE; } +typedef struct _PHP_TOKEN_ADVANCED_CONTEXT +{ + HWND WindowHandle; + HWND ListViewHandle; + PH_LAYOUT_MANAGER LayoutManager; +} PHP_TOKEN_ADVANCED_CONTEXT, *PPHP_TOKEN_ADVANCED_CONTEXT; + INT_PTR CALLBACK PhpTokenAdvancedPageProc( _In_ HWND hwndDlg, _In_ UINT uMsg, @@ -1837,12 +1882,25 @@ INT_PTR CALLBACK PhpTokenAdvancedPageProc( ) { PTOKEN_PAGE_CONTEXT tokenPageContext; + PPHP_TOKEN_ADVANCED_CONTEXT context; tokenPageContext = PhpTokenPageHeader(hwndDlg, uMsg, wParam, lParam); if (!tokenPageContext) return FALSE; + if (uMsg == WM_INITDIALOG) + { + context = PhAllocateZero(sizeof(PHP_TOKEN_ADVANCED_CONTEXT)); + PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context); + } + else + { + context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); + } + if (!context) + return FALSE; + switch (uMsg) { case WM_INITDIALOG: @@ -1852,8 +1910,40 @@ INT_PTR CALLBACK PhpTokenAdvancedPageProc( PWSTR tokenImpersonationLevel = L"Unknown"; WCHAR tokenLuid[PH_PTR_STR_LEN_1] = L"Unknown"; WCHAR authenticationLuid[PH_PTR_STR_LEN_1] = L"Unknown"; + WCHAR tokenModifiedLuid[PH_PTR_STR_LEN_1] = L"Unknown"; + WCHAR tokenOriginLogonSession[PH_PTR_STR_LEN_1] = L"Unknown"; PPH_STRING memoryUsed = NULL; PPH_STRING memoryAvailable = NULL; + PPH_STRING tokenNamedObjectPathString = NULL; + PPH_STRING tokenSecurityDescriptorString = NULL; + PPH_STRING tokenTrustLevelSidString; + PPH_STRING tokenTrustLevelNameString; + + context->ListViewHandle = GetDlgItem(hwndDlg, IDC_LIST); + PhSetListViewStyle(context->ListViewHandle, FALSE, TRUE); + PhSetControlTheme(context->ListViewHandle, L"explorer"); + PhAddListViewColumn(context->ListViewHandle, 0, 0, 0, LVCFMT_LEFT, 120, L"Name"); + PhAddListViewColumn(context->ListViewHandle, 1, 1, 1, LVCFMT_LEFT, 280, L"Value"); + PhSetExtendedListView(context->ListViewHandle); + + PhInitializeLayoutManager(&context->LayoutManager, hwndDlg); + PhAddLayoutItem(&context->LayoutManager, context->ListViewHandle, NULL, PH_ANCHOR_ALL); + + ListView_EnableGroupView(context->ListViewHandle, TRUE); + PhAddListViewGroup(context->ListViewHandle, 0, L"General"); + PhAddListViewGroup(context->ListViewHandle, 1, L"LUIDs"); + PhAddListViewGroup(context->ListViewHandle, 2, L"Memory"); + PhAddListViewGroup(context->ListViewHandle, 3, L"Properties"); + PhAddListViewGroupItem(context->ListViewHandle, 0, MAXINT, L"Type", NULL); + PhAddListViewGroupItem(context->ListViewHandle, 0, MAXINT, L"Impersonation level", NULL); + PhAddListViewGroupItem(context->ListViewHandle, 1, MAXINT, L"Token LUID", NULL); + PhAddListViewGroupItem(context->ListViewHandle, 1, MAXINT, L"Authentication LUID", NULL); + PhAddListViewGroupItem(context->ListViewHandle, 1, MAXINT, L"ModifiedId LUID", NULL); + PhAddListViewGroupItem(context->ListViewHandle, 1, MAXINT, L"Origin LUID", NULL); + PhAddListViewGroupItem(context->ListViewHandle, 2, MAXINT, L"Memory used", NULL); + PhAddListViewGroupItem(context->ListViewHandle, 2, MAXINT, L"Memory available", NULL); + PhAddListViewGroupItem(context->ListViewHandle, 3, MAXINT, L"Token object path", NULL); + PhAddListViewGroupItem(context->ListViewHandle, 3, MAXINT, L"Token SDDL", NULL); if (NT_SUCCESS(tokenPageContext->OpenObject( &tokenHandle, @@ -1862,6 +1952,7 @@ INT_PTR CALLBACK PhpTokenAdvancedPageProc( ))) { TOKEN_STATISTICS statistics; + TOKEN_ORIGIN origin; if (NT_SUCCESS(PhGetTokenStatistics(tokenHandle, &statistics))) { @@ -1900,26 +1991,156 @@ INT_PTR CALLBACK PhpTokenAdvancedPageProc( PhPrintPointer(tokenLuid, UlongToPtr(statistics.TokenId.LowPart)); PhPrintPointer(authenticationLuid, UlongToPtr(statistics.AuthenticationId.LowPart)); + PhPrintPointer(tokenModifiedLuid, UlongToPtr(statistics.ModifiedId.LowPart)); - // DynamicCharged contains the number of bytes allocated. - // DynamicAvailable contains the number of bytes free. - memoryUsed = PhaFormatSize(statistics.DynamicCharged - statistics.DynamicAvailable, ULONG_MAX); - memoryAvailable = PhaFormatSize(statistics.DynamicCharged, ULONG_MAX); + memoryUsed = PhFormatSize(statistics.DynamicCharged - statistics.DynamicAvailable, ULONG_MAX); // DynamicAvailable contains the number of bytes free. + memoryAvailable = PhFormatSize(statistics.DynamicCharged, ULONG_MAX); // DynamicCharged contains the number of bytes allocated. } + if (NT_SUCCESS(PhGetTokenOrigin(tokenHandle, &origin))) + { + PhPrintPointer(tokenOriginLogonSession, UlongToPtr(origin.OriginatingLogonSession.LowPart)); + } + + PhGetTokenNamedObjectPath(tokenHandle, NULL, &tokenNamedObjectPathString); + PhGetTokenSecurityDescriptorAsString(tokenHandle, &tokenSecurityDescriptorString); + + if (NT_SUCCESS(PhGetTokenProcessTrustLevelRID( + tokenHandle, + NULL, + NULL, + &tokenTrustLevelNameString, + &tokenTrustLevelSidString + ))) + { + INT trustLevelGroupIndex; + INT trustLevelSidIndex; + INT trustLevelNameIndex; + + trustLevelGroupIndex = PhAddListViewGroup(context->ListViewHandle, 4, L"TrustLevel"); + trustLevelSidIndex = PhAddListViewGroupItem(context->ListViewHandle, trustLevelGroupIndex, MAXINT, L"TrustLevel Sid", NULL); + trustLevelNameIndex = PhAddListViewGroupItem(context->ListViewHandle, trustLevelGroupIndex, MAXINT, L"TrustLevel Name", NULL); + + PhSetListViewSubItem(context->ListViewHandle, trustLevelSidIndex, 1, PhGetStringOrDefault(tokenTrustLevelSidString, L"N/A")); + PhSetListViewSubItem(context->ListViewHandle, trustLevelNameIndex, 1, PhGetStringOrDefault(tokenTrustLevelNameString, L"N/A")); + + PhClearReference(&tokenTrustLevelNameString); + PhClearReference(&tokenTrustLevelSidString); + } + + //PTOKEN_GROUPS tokenLogonGroups; + //if (NT_SUCCESS(PhQueryTokenVariableSize(tokenHandle, TokenLogonSid, &tokenLogonGroups))) + //{ + // PPH_STRING tokenLogonName = PhGetSidFullName(tokenLogonGroups->Groups[0].Sid, TRUE, NULL); + // PPH_STRING tokenLogonSid = PhSidToStringSid(tokenLogonGroups->Groups[0].Sid); + // INT tokenLogonGroupIndex = PhAddListViewGroup(context->ListViewHandle, 5, L"Logon"); + // INT tokenLogonNameIndex = PhAddListViewGroupItem(context->ListViewHandle, tokenLogonGroupIndex, MAXINT, L"Token logon SID", NULL); + // INT tokenLogonSidIndex = PhAddListViewGroupItem(context->ListViewHandle, tokenLogonGroupIndex, MAXINT, L"Token logon Name", NULL); + // PhSetListViewSubItem(context->ListViewHandle, tokenLogonNameIndex, 1, PhGetStringOrDefault(tokenLogonName, L"Unknown")); + // PhSetListViewSubItem(context->ListViewHandle, tokenLogonSidIndex, 1, PhGetStringOrDefault(tokenLogonSid, L"Unknown")); + // PhFree(tokenLogonGroups); + //} + NtClose(tokenHandle); } - PhSetDialogItemText(hwndDlg, IDC_TYPE, tokenType); - PhSetDialogItemText(hwndDlg, IDC_IMPERSONATIONLEVEL, tokenImpersonationLevel); - PhSetDialogItemText(hwndDlg, IDC_TOKENLUID, tokenLuid); - PhSetDialogItemText(hwndDlg, IDC_AUTHENTICATIONLUID, authenticationLuid); - PhSetDialogItemText(hwndDlg, IDC_MEMORYUSED, PhGetStringOrDefault(memoryUsed, L"Unknown")); - PhSetDialogItemText(hwndDlg, IDC_MEMORYAVAILABLE, PhGetStringOrDefault(memoryAvailable, L"Unknown")); + PhSetListViewSubItem(context->ListViewHandle, 0, 1, tokenType); + PhSetListViewSubItem(context->ListViewHandle, 1, 1, tokenImpersonationLevel); + PhSetListViewSubItem(context->ListViewHandle, 2, 1, tokenLuid); + PhSetListViewSubItem(context->ListViewHandle, 3, 1, authenticationLuid); + PhSetListViewSubItem(context->ListViewHandle, 4, 1, tokenModifiedLuid); + PhSetListViewSubItem(context->ListViewHandle, 5, 1, tokenOriginLogonSession); + PhSetListViewSubItem(context->ListViewHandle, 6, 1, PhGetStringOrDefault(memoryUsed, L"Unknown")); + PhSetListViewSubItem(context->ListViewHandle, 7, 1, PhGetStringOrDefault(memoryAvailable, L"Unknown")); + + PhSetListViewSubItem(context->ListViewHandle, 8, 1, PhGetStringOrDefault(tokenNamedObjectPathString, L"Unknown")); + PhSetListViewSubItem(context->ListViewHandle, 9, 1, PhGetStringOrDefault(tokenSecurityDescriptorString, L"Unknown")); + + PhClearReference(&memoryUsed); + PhClearReference(&memoryAvailable); + PhClearReference(&tokenNamedObjectPathString); + PhClearReference(&tokenSecurityDescriptorString); PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport); } break; + case WM_DESTROY: + { + PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); + + PhDeleteLayoutManager(&context->LayoutManager); + PhFree(context); + } + break; + case WM_SIZE: + { + PhLayoutManagerLayout(&context->LayoutManager); + + ExtendedListView_SetColumnWidth(context->ListViewHandle, 0, ELVSCW_AUTOSIZE_REMAININGSPACE); + } + break; + case WM_CONTEXTMENU: + { + if ((HWND)wParam == context->ListViewHandle) + { + POINT point; + PPH_EMENU menu; + PPH_EMENU item; + PPHP_TOKEN_PAGE_LISTVIEW_ITEM* listviewItems; + ULONG numberOfItems; + + point.x = GET_X_LPARAM(lParam); + point.y = GET_Y_LPARAM(lParam); + + if (point.x == -1 && point.y == -1) + PhGetListViewContextMenuPoint((HWND)wParam, &point); + + PhGetSelectedListViewItemParams(context->ListViewHandle, &listviewItems, &numberOfItems); + + if (numberOfItems != 0) + { + menu = PhCreateEMenu(); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, IDC_COPY, L"&Copy", NULL, NULL), ULONG_MAX); + PhInsertCopyListViewEMenuItem(menu, IDC_COPY, context->ListViewHandle); + + item = PhShowEMenu( + menu, + hwndDlg, + PH_EMENU_SHOW_SEND_COMMAND | PH_EMENU_SHOW_LEFTRIGHT, + PH_ALIGN_LEFT | PH_ALIGN_TOP, + point.x, + point.y + ); + + if (item) + { + BOOLEAN handled = FALSE; + + handled = PhHandleCopyListViewEMenuItem(item); + + //if (!handled && PhPluginsEnabled) + // handled = PhPluginTriggerEMenuItem(&menuInfo, item); + + if (!handled) + { + switch (item->Id) + { + case IDC_COPY: + { + PhCopyListView(context->ListViewHandle); + } + break; + } + } + } + + PhDestroyEMenu(menu); + } + + PhFree(listviewItems); + } + } + break; } return FALSE; @@ -2222,17 +2443,6 @@ BOOLEAN PhpAddTokenCapabilities( PhDereferenceObject(name); } - - //ULONG firstPart = *RtlSubAuthoritySid(TokenPageContext->Capabilities->Groups[i].Sid, 1); - //ULONG secondPart = *RtlSubAuthoritySid(TokenPageContext->Capabilities->Groups[i].Sid, 2); - //ULONG thirdPart = *RtlSubAuthoritySid(TokenPageContext->Capabilities->Groups[i].Sid, 3); - //ULONG lastPart = *RtlSubAuthoritySid(TokenPageContext->Capabilities->Groups[i].Sid, 4); - //GUID capabilityGuid; - //capabilityGuid.Data1 = firstPart; - //capabilityGuid.Data2 = LOWORD(secondPart); - //capabilityGuid.Data3 = HIWORD(secondPart); - //*((PULONG)&capabilityGuid.Data4[0]) = thirdPart; - //*((PULONG)&capabilityGuid.Data4[4]) = lastPart; } } } @@ -2272,6 +2482,7 @@ INT_PTR CALLBACK PhpTokenCapabilitiesPageProc( TreeNew_SetCallback(tnHandle, PhpAttributeTreeNewCallback, &tokenPageContext->CapsTreeContext); PhAddTreeNewColumnEx2(tnHandle, 0, TRUE, L"Capabilities", 200, PH_ALIGN_LEFT, 0, 0, TN_COLUMN_FLAG_NODPISCALEONADD); + TreeNew_SetEmptyText(tnHandle, &PhpEmptyTokenCapabilitiesText, 0); TreeNew_SetRedraw(tnHandle, FALSE); PhpAddTokenCapabilities(tokenPageContext, tnHandle); TreeNew_NodesStructured(tnHandle); @@ -2403,7 +2614,7 @@ PPH_STRING PhGetSecurityAttributeFlagsString( if (Flags & TOKEN_SECURITY_ATTRIBUTE_NON_INHERITABLE) PhAppendStringBuilder2(&sb, L"Non-inheritable, "); if (Flags & TOKEN_SECURITY_ATTRIBUTE_COMPARE_IGNORE) - PhAppendStringBuilder2(&sb, L"Compare-Ignore, "); + PhAppendStringBuilder2(&sb, L"Compare-ignore, "); if (sb.String->Length != 0) PhRemoveEndStringBuilder(&sb, 2); @@ -2592,6 +2803,7 @@ INT_PTR CALLBACK PhpTokenClaimsPageProc( PhpInitializeAttributeTreeContext(&tokenPageContext->ClaimsTreeContext, hwndDlg, tnHandle); + TreeNew_SetEmptyText(tnHandle, &PhpEmptyTokenClaimsText, 0); TreeNew_SetRedraw(tnHandle, FALSE); userNode = PhpAddAttributeNode(&tokenPageContext->ClaimsTreeContext, NULL, PhCreateString(L"User claims")); @@ -2753,12 +2965,13 @@ INT_PTR CALLBACK PhpTokenAttributesPageProc( { PhpInitializeAttributeTreeContext(&tokenPageContext->AuthzTreeContext, hwndDlg, tnHandle); + TreeNew_SetEmptyText(tnHandle, &PhpEmptyTokenAttributesText, 0); TreeNew_SetRedraw(tnHandle, FALSE); PhpAddTokenAttributes(tokenPageContext, tnHandle); - if (tokenPageContext->AuthzTreeContext.RootList->Count == 0) - PhpAddAttributeNode(&tokenPageContext->AuthzTreeContext, NULL, PhCreateString(L"(None)")); + //if (tokenPageContext->AuthzTreeContext.RootList->Count == 0) + // PhpAddAttributeNode(&tokenPageContext->AuthzTreeContext, NULL, PhCreateString(L"(None)")); TreeNew_NodesStructured(tnHandle); TreeNew_SetRedraw(tnHandle, TRUE); @@ -2830,3 +3043,261 @@ INT_PTR CALLBACK PhpTokenAttributesPageProc( return FALSE; } + +INT_PTR CALLBACK PhpTokenContainerPageProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + PTOKEN_PAGE_CONTEXT tokenPageContext; + PPHP_TOKEN_ADVANCED_CONTEXT context; + + tokenPageContext = PhpTokenPageHeader(hwndDlg, uMsg, wParam, lParam); + + if (!tokenPageContext) + return FALSE; + + if (uMsg == WM_INITDIALOG) + { + context = PhAllocateZero(sizeof(PHP_TOKEN_ADVANCED_CONTEXT)); + PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context); + } + else + { + context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); + } + if (!context) + return FALSE; + + switch (uMsg) + { + case WM_INITDIALOG: + { + HANDLE tokenHandle; + BOOLEAN isLessPrivilegedAppContainer = FALSE; + WCHAR appContainerNumberString[PH_INT64_STR_LEN_1] = L"Unknown"; + PPH_STRING tokenNamedObjectPathString = NULL; + + context->ListViewHandle = GetDlgItem(hwndDlg, IDC_LIST); + PhSetListViewStyle(context->ListViewHandle, FALSE, TRUE); + PhSetControlTheme(context->ListViewHandle, L"explorer"); + PhAddListViewColumn(context->ListViewHandle, 0, 0, 0, LVCFMT_LEFT, 120, L"Name"); + PhAddListViewColumn(context->ListViewHandle, 1, 1, 1, LVCFMT_LEFT, 280, L"Value"); + PhSetExtendedListView(context->ListViewHandle); + + PhInitializeLayoutManager(&context->LayoutManager, hwndDlg); + PhAddLayoutItem(&context->LayoutManager, context->ListViewHandle, NULL, PH_ANCHOR_ALL); + + ListView_EnableGroupView(context->ListViewHandle, TRUE); + PhAddListViewGroup(context->ListViewHandle, 0, L"General"); + PhAddListViewGroup(context->ListViewHandle, 1, L"Properties"); + PhAddListViewGroup(context->ListViewHandle, 2, L"Parent"); + + PhAddListViewGroupItem(context->ListViewHandle, 0, MAXINT, L"Name", NULL); + PhAddListViewGroupItem(context->ListViewHandle, 0, MAXINT, L"Type", NULL); + PhAddListViewGroupItem(context->ListViewHandle, 0, MAXINT, L"SID", NULL); + + PhAddListViewGroupItem(context->ListViewHandle, 1, MAXINT, L"Number", NULL); + PhAddListViewGroupItem(context->ListViewHandle, 1, MAXINT, L"LPAC", NULL); + PhAddListViewGroupItem(context->ListViewHandle, 1, MAXINT, L"Token object path", NULL); + + PhAddListViewGroupItem(context->ListViewHandle, 2, MAXINT, L"Name", NULL); + PhAddListViewGroupItem(context->ListViewHandle, 2, MAXINT, L"SID", NULL); + + if (NT_SUCCESS(tokenPageContext->OpenObject( + &tokenHandle, + TOKEN_QUERY, + tokenPageContext->Context + ))) + { + PTOKEN_APPCONTAINER_INFORMATION appContainerInfo; + APPCONTAINER_SID_TYPE appContainerSidType = InvalidAppContainerSidType; + PSID appContainerSidParent = NULL; + PPH_STRING appContainerName = NULL; + PPH_STRING appContainerSid = NULL; + ULONG appContainerNumber; + + if (NT_SUCCESS(PhQueryTokenVariableSize(tokenHandle, TokenAppContainerSid, &appContainerInfo))) + { + if (appContainerInfo->TokenAppContainer) + { + RtlGetAppContainerSidType(appContainerInfo->TokenAppContainer, &appContainerSidType); + RtlGetAppContainerParent(appContainerInfo->TokenAppContainer, &appContainerSidParent); + + appContainerName = PhGetAppContainerName(appContainerInfo->TokenAppContainer); + appContainerSid = PhSidToStringSid(appContainerInfo->TokenAppContainer); + } + + PhFree(appContainerInfo); + } + + if (appContainerName) + { + PhSetListViewSubItem(context->ListViewHandle, 0, 1, appContainerName->Buffer); + PhDereferenceObject(appContainerName); + } + + switch (appContainerSidType) + { + case ChildAppContainerSidType: + PhSetListViewSubItem(context->ListViewHandle, 1, 1, L"Child"); + break; + case ParentAppContainerSidType: + PhSetListViewSubItem(context->ListViewHandle, 1, 1, L"Parent"); + break; + default: + PhSetListViewSubItem(context->ListViewHandle, 1, 1, L"Unknown"); + break; + } + + if (appContainerSid) + { + PhSetListViewSubItem(context->ListViewHandle, 2, 1, appContainerSid->Buffer); + PhDereferenceObject(appContainerSid); + } + + if (NT_SUCCESS(PhGetTokenAppContainerNumber(tokenHandle, &appContainerNumber))) + { + PhPrintUInt32(appContainerNumberString, appContainerNumber); + PhSetListViewSubItem(context->ListViewHandle, 3, 1, appContainerNumberString); + } + + // TODO: TokenIsLessPrivilegedAppContainer + { + static UNICODE_STRING attributeNameUs = RTL_CONSTANT_STRING(L"WIN://NOALLAPPPKG"); + PTOKEN_SECURITY_ATTRIBUTES_INFORMATION info; + + if (NT_SUCCESS(PhQueryTokenVariableSize(tokenHandle, TokenSecurityAttributes, &info))) + { + for (ULONG i = 0; i < info->AttributeCount; i++) + { + PTOKEN_SECURITY_ATTRIBUTE_V1 attribute = &info->Attribute.pAttributeV1[i]; + + if (attribute->ValueType == TOKEN_SECURITY_ATTRIBUTE_TYPE_STRING) + { + if (RtlEqualUnicodeString(&attribute->Name, &attributeNameUs, FALSE)) + { + isLessPrivilegedAppContainer = TRUE; + break; + } + } + } + + PhFree(info); + } + + PhSetListViewSubItem(context->ListViewHandle, 4, 1, isLessPrivilegedAppContainer ? L"True" : L"False"); + } + + if (NT_SUCCESS(PhGetAppContainerNamedObjectPath(tokenHandle, NULL, FALSE, &tokenNamedObjectPathString))) + { + PhSetListViewSubItem(context->ListViewHandle, 5, 1, PhGetStringOrDefault(tokenNamedObjectPathString, L"Unknown")); + PhDereferenceObject(tokenNamedObjectPathString); + } + + if (appContainerSidParent) + { + if (appContainerName = PhGetAppContainerName(appContainerSidParent)) + { + PhSetListViewSubItem(context->ListViewHandle, 6, 1, appContainerName->Buffer); + PhDereferenceObject(appContainerName); + } + + if (appContainerSid = PhSidToStringSid(appContainerSidParent)) + { + PhSetListViewSubItem(context->ListViewHandle, 7, 1, appContainerSid->Buffer); + PhDereferenceObject(appContainerSid); + } + + RtlFreeSid(appContainerSidParent); + } + + NtClose(tokenHandle); + } + + PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport); + } + break; + case WM_DESTROY: + { + PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); + + PhDeleteLayoutManager(&context->LayoutManager); + PhFree(context); + } + break; + case WM_SIZE: + { + PhLayoutManagerLayout(&context->LayoutManager); + + ExtendedListView_SetColumnWidth(context->ListViewHandle, 0, ELVSCW_AUTOSIZE_REMAININGSPACE); + } + break; + case WM_CONTEXTMENU: + { + if ((HWND)wParam == context->ListViewHandle) + { + POINT point; + PPH_EMENU menu; + PPH_EMENU item; + PPHP_TOKEN_PAGE_LISTVIEW_ITEM* listviewItems; + ULONG numberOfItems; + + point.x = GET_X_LPARAM(lParam); + point.y = GET_Y_LPARAM(lParam); + + if (point.x == -1 && point.y == -1) + PhGetListViewContextMenuPoint((HWND)wParam, &point); + + PhGetSelectedListViewItemParams(context->ListViewHandle, &listviewItems, &numberOfItems); + + if (numberOfItems != 0) + { + menu = PhCreateEMenu(); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, IDC_COPY, L"&Copy", NULL, NULL), ULONG_MAX); + PhInsertCopyListViewEMenuItem(menu, IDC_COPY, context->ListViewHandle); + + item = PhShowEMenu( + menu, + hwndDlg, + PH_EMENU_SHOW_SEND_COMMAND | PH_EMENU_SHOW_LEFTRIGHT, + PH_ALIGN_LEFT | PH_ALIGN_TOP, + point.x, + point.y + ); + + if (item) + { + BOOLEAN handled = FALSE; + + handled = PhHandleCopyListViewEMenuItem(item); + + //if (!handled && PhPluginsEnabled) + // handled = PhPluginTriggerEMenuItem(&menuInfo, item); + + if (!handled) + { + switch (item->Id) + { + case IDC_COPY: + { + PhCopyListView(context->ListViewHandle); + } + break; + } + } + } + + PhDestroyEMenu(menu); + } + + PhFree(listviewItems); + } + } + break; + } + + return FALSE; +} From ac3a1c9651696bb1a19f668a406ad9e9950886ae Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 14 Apr 2019 16:05:38 +0200 Subject: [PATCH 1794/2058] Fix win7 crash regression from previous commit --- ProcessHacker/hndlprp.c | 5 +-- ProcessHacker/include/phapp.h | 2 ++ ProcessHacker/procprp.c | 2 +- ProcessHacker/prpgthrd.c | 1 + ProcessHacker/runas.c | 4 +-- ProcessHacker/tokprp.c | 58 +++++++++++++++++++++++++++++++---- phlib/native.c | 35 +++++++++++++++++++-- phlib/util.c | 4 +-- 8 files changed, 95 insertions(+), 16 deletions(-) diff --git a/ProcessHacker/hndlprp.c b/ProcessHacker/hndlprp.c index e38df6a530c8..fd598872a369 100644 --- a/ProcessHacker/hndlprp.c +++ b/ProcessHacker/hndlprp.c @@ -235,6 +235,7 @@ NTSTATUS PhpShowHandlePropertiesThread( { pages[propSheetHeader.nPages++] = PhCreateTokenPage( PhpDuplicateHandleFromProcess, + context.ProcessId, &context, NULL ); @@ -643,7 +644,7 @@ VOID PhpUpdateHandleGeneral( NtClose(alpcPortHandle); } } - else if (PhEqualStringRef2(&Context->HandleItem->TypeName->sr, L"File", TRUE)) + else if (PhEqualString2(Context->HandleItem->TypeName, L"File", TRUE)) { NTSTATUS status; HANDLE processHandle; @@ -831,7 +832,7 @@ VOID PhpUpdateHandleGeneral( NtClose(fileHandle); } } - else if (PhEqualStringRef2(&Context->HandleItem->TypeName->sr, L"Section", TRUE)) + else if (PhEqualString2(Context->HandleItem->TypeName, L"Section", TRUE)) { NTSTATUS status; HANDLE processHandle; diff --git a/ProcessHacker/include/phapp.h b/ProcessHacker/include/phapp.h index 781535811cfb..756e91426188 100644 --- a/ProcessHacker/include/phapp.h +++ b/ProcessHacker/include/phapp.h @@ -799,12 +799,14 @@ PWSTR PhGetPrivilegeAttributesString( VOID PhShowTokenProperties( _In_ HWND ParentWindowHandle, _In_ PPH_OPEN_OBJECT OpenObject, + _In_ HANDLE ProcessId, _In_opt_ PVOID Context, _In_opt_ PWSTR Title ); HPROPSHEETPAGE PhCreateTokenPage( _In_ PPH_OPEN_OBJECT OpenObject, + _In_ HANDLE ProcessId, _In_opt_ PVOID Context, _In_opt_ DLGPROC HookProc ); diff --git a/ProcessHacker/procprp.c b/ProcessHacker/procprp.c index da34daa94e8b..c1e34fe27f28 100644 --- a/ProcessHacker/procprp.c +++ b/ProcessHacker/procprp.c @@ -624,7 +624,7 @@ NTSTATUS PhpProcessPropertiesThreadStart( // Token PhAddProcessPropPage2( PropContext, - PhCreateTokenPage(PhpOpenProcessTokenForPage, (PVOID)PropContext->ProcessItem->ProcessId, PhpProcessTokenHookProc) + PhCreateTokenPage(PhpOpenProcessTokenForPage, PropContext->ProcessItem->ProcessId, (PVOID)PropContext->ProcessItem->ProcessId, PhpProcessTokenHookProc) ); // Modules diff --git a/ProcessHacker/prpgthrd.c b/ProcessHacker/prpgthrd.c index 55980b7571c3..b3697eb542e1 100644 --- a/ProcessHacker/prpgthrd.c +++ b/ProcessHacker/prpgthrd.c @@ -897,6 +897,7 @@ INT_PTR CALLBACK PhpProcessThreadsDlgProc( PhShowTokenProperties( hwndDlg, PhpOpenThreadTokenObject, + threadsContext->Provider->ProcessId, (PVOID)threadHandle, NULL ); diff --git a/ProcessHacker/runas.c b/ProcessHacker/runas.c index fd5cfc04c4e6..bcfd1dfecbdf 100644 --- a/ProcessHacker/runas.c +++ b/ProcessHacker/runas.c @@ -160,8 +160,8 @@ VOID PhSetDesktopWinStaAccess( VOID PhpSplitUserName( _In_ PWSTR UserName, - _Out_ PPH_STRING *DomainPart, - _Out_ PPH_STRING *UserPart + _Out_opt_ PPH_STRING* DomainPart, + _Out_opt_ PPH_STRING* UserPart ); #define SIP(String, Integer) { (String), (PVOID)(Integer) } diff --git a/ProcessHacker/tokprp.c b/ProcessHacker/tokprp.c index 088e413f8a68..c5602f0f4208 100644 --- a/ProcessHacker/tokprp.c +++ b/ProcessHacker/tokprp.c @@ -86,6 +86,7 @@ typedef struct _TOKEN_PAGE_CONTEXT PPH_OPEN_OBJECT OpenObject; PVOID Context; DLGPROC HookProc; + HANDLE ProcessId; HWND ListViewHandle; HIMAGELIST ListViewImageList; @@ -186,6 +187,7 @@ INT_PTR CALLBACK PhpTokenContainerPageProc( VOID PhShowTokenProperties( _In_ HWND ParentWindowHandle, _In_ PPH_OPEN_OBJECT OpenObject, + _In_ HANDLE ProcessId, _In_opt_ PVOID Context, _In_opt_ PWSTR Title ) @@ -204,13 +206,14 @@ VOID PhShowTokenProperties( propSheetHeader.nStartPage = 0; propSheetHeader.phpage = pages; - pages[0] = PhCreateTokenPage(OpenObject, Context, NULL); + pages[0] = PhCreateTokenPage(OpenObject, ProcessId, Context, NULL); PhModalPropertySheet(&propSheetHeader); } HPROPSHEETPAGE PhCreateTokenPage( _In_ PPH_OPEN_OBJECT OpenObject, + _In_ HANDLE ProcessId, _In_opt_ PVOID Context, _In_opt_ DLGPROC HookProc ) @@ -224,6 +227,7 @@ HPROPSHEETPAGE PhCreateTokenPage( tokenPageContext->OpenObject = OpenObject; tokenPageContext->Context = Context; tokenPageContext->HookProc = HookProc; + tokenPageContext->ProcessId = ProcessId; memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE)); propSheetPage.dwSize = sizeof(PROPSHEETPAGE); @@ -1835,7 +1839,7 @@ INT_PTR CALLBACK PhpTokenGeneralPageProc( tokenPageContext->Context ))) { - PhShowTokenProperties(hwndDlg, PhpOpenLinkedToken, (PVOID)tokenHandle, L"Linked Token"); + PhShowTokenProperties(hwndDlg, PhpOpenLinkedToken, tokenPageContext->ProcessId, (PVOID)tokenHandle, L"Linked Token"); NtClose(tokenHandle); } else @@ -3079,6 +3083,7 @@ INT_PTR CALLBACK PhpTokenContainerPageProc( BOOLEAN isLessPrivilegedAppContainer = FALSE; WCHAR appContainerNumberString[PH_INT64_STR_LEN_1] = L"Unknown"; PPH_STRING tokenNamedObjectPathString = NULL; + HANDLE processHandle; context->ListViewHandle = GetDlgItem(hwndDlg, IDC_LIST); PhSetListViewStyle(context->ListViewHandle, FALSE, TRUE); @@ -3094,17 +3099,18 @@ INT_PTR CALLBACK PhpTokenContainerPageProc( PhAddListViewGroup(context->ListViewHandle, 0, L"General"); PhAddListViewGroup(context->ListViewHandle, 1, L"Properties"); PhAddListViewGroup(context->ListViewHandle, 2, L"Parent"); + PhAddListViewGroup(context->ListViewHandle, 3, L"Package"); PhAddListViewGroupItem(context->ListViewHandle, 0, MAXINT, L"Name", NULL); PhAddListViewGroupItem(context->ListViewHandle, 0, MAXINT, L"Type", NULL); PhAddListViewGroupItem(context->ListViewHandle, 0, MAXINT, L"SID", NULL); - PhAddListViewGroupItem(context->ListViewHandle, 1, MAXINT, L"Number", NULL); PhAddListViewGroupItem(context->ListViewHandle, 1, MAXINT, L"LPAC", NULL); PhAddListViewGroupItem(context->ListViewHandle, 1, MAXINT, L"Token object path", NULL); - PhAddListViewGroupItem(context->ListViewHandle, 2, MAXINT, L"Name", NULL); PhAddListViewGroupItem(context->ListViewHandle, 2, MAXINT, L"SID", NULL); + PhAddListViewGroupItem(context->ListViewHandle, 3, MAXINT, L"Name", NULL); + PhAddListViewGroupItem(context->ListViewHandle, 3, MAXINT, L"Path", NULL); if (NT_SUCCESS(tokenPageContext->OpenObject( &tokenHandle, @@ -3123,8 +3129,27 @@ INT_PTR CALLBACK PhpTokenContainerPageProc( { if (appContainerInfo->TokenAppContainer) { - RtlGetAppContainerSidType(appContainerInfo->TokenAppContainer, &appContainerSidType); - RtlGetAppContainerParent(appContainerInfo->TokenAppContainer, &appContainerSidParent); + static PH_INITONCE initOnce = PH_INITONCE_INIT; + static NTSTATUS (WINAPI* RtlGetAppContainerSidType_I)( + _In_ PSID AppContainerSid, + _Out_ PAPPCONTAINER_SID_TYPE AppContainerSidType + ) = NULL; + static NTSTATUS (WINAPI* RtlGetAppContainerParent_I)( + _In_ PSID AppContainerSid, + _Out_ PSID* AppContainerSidParent + ) = NULL; + + if (PhBeginInitOnce(&initOnce)) + { + RtlGetAppContainerSidType_I = PhGetDllProcedureAddress(L"ntdll.dll", "RtlGetAppContainerSidType", 0); + RtlGetAppContainerParent_I = PhGetDllProcedureAddress(L"ntdll.dll", "RtlGetAppContainerParent", 0); + PhEndInitOnce(&initOnce); + } + + if (RtlGetAppContainerSidType_I) + RtlGetAppContainerSidType_I(appContainerInfo->TokenAppContainer, &appContainerSidType); + if (RtlGetAppContainerParent_I) + RtlGetAppContainerParent_I(appContainerInfo->TokenAppContainer, &appContainerSidParent); appContainerName = PhGetAppContainerName(appContainerInfo->TokenAppContainer); appContainerSid = PhSidToStringSid(appContainerInfo->TokenAppContainer); @@ -3217,6 +3242,27 @@ INT_PTR CALLBACK PhpTokenContainerPageProc( NtClose(tokenHandle); } + if (NT_SUCCESS(PhOpenProcess(&processHandle, PROCESS_QUERY_LIMITED_INFORMATION, tokenPageContext->ProcessId))) + { + PPH_STRING packageFullName; + PPH_STRING packagePath; + + if (packageFullName = PhGetProcessPackageFullName(processHandle)) + { + PhSetListViewSubItem(context->ListViewHandle, 8, 1, packageFullName->Buffer); + + if (packagePath = PhGetPackagePath(packageFullName)) + { + PhSetListViewSubItem(context->ListViewHandle, 9, 1, packagePath->Buffer); + PhDereferenceObject(packagePath); + } + + PhDereferenceObject(packageFullName); + } + + NtClose(processHandle); + } + PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport); } break; diff --git a/phlib/native.c b/phlib/native.c index a859715d796d..79a9bc1c5f28 100644 --- a/phlib/native.c +++ b/phlib/native.c @@ -2200,10 +2200,25 @@ NTSTATUS PhGetTokenNamedObjectPath( _Out_ PPH_STRING* ObjectPath ) { + static PH_INITONCE initOnce = PH_INITONCE_INIT; + static NTSTATUS(WINAPI * RtlGetTokenNamedObjectPath_I)( + _In_ HANDLE Token, + _In_opt_ PSID Sid, + _Out_ PUNICODE_STRING ObjectPath + ) = NULL; NTSTATUS status; UNICODE_STRING namedObjectPathUs; - status = RtlGetTokenNamedObjectPath( + if (PhBeginInitOnce(&initOnce)) + { + RtlGetTokenNamedObjectPath_I = PhGetDllProcedureAddress(L"ntdll.dll", "RtlGetTokenNamedObjectPath", 0); + PhEndInitOnce(&initOnce); + } + + if (!RtlGetTokenNamedObjectPath_I) + return STATUS_UNSUCCESSFUL; + + status = RtlGetTokenNamedObjectPath_I( TokenHandle, Sid, &namedObjectPathUs @@ -2225,10 +2240,26 @@ NTSTATUS PhGetAppContainerNamedObjectPath( _Out_ PPH_STRING* ObjectPath ) { + static PH_INITONCE initOnce = PH_INITONCE_INIT; + static NTSTATUS (WINAPI * RtlGetAppContainerNamedObjectPath_I)( + _In_opt_ HANDLE Token, + _In_opt_ PSID AppContainerSid, + _In_ BOOLEAN RelativePath, + _Out_ PUNICODE_STRING ObjectPath + ) = NULL; NTSTATUS status; UNICODE_STRING namedObjectPathUs; - status = RtlGetAppContainerNamedObjectPath( + if (PhBeginInitOnce(&initOnce)) + { + RtlGetAppContainerNamedObjectPath_I = PhGetDllProcedureAddress(L"ntdll.dll", "RtlGetAppContainerNamedObjectPath", 0); + PhEndInitOnce(&initOnce); + } + + if (!RtlGetAppContainerNamedObjectPath_I) + return STATUS_UNSUCCESSFUL; + + status = RtlGetAppContainerNamedObjectPath_I( TokenHandle, AppContainerSid, RelativePath, diff --git a/phlib/util.c b/phlib/util.c index b56a40d10aba..af289bc041e6 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -5518,9 +5518,7 @@ BOOLEAN PhExtractIconEx( if (PhBeginInitOnce(&initOnce)) { - if (!PrivateExtractIconExW) - PrivateExtractIconExW = PhGetDllProcedureAddress(L"user32.dll", "PrivateExtractIconExW", 0); - + PrivateExtractIconExW = PhGetDllProcedureAddress(L"user32.dll", "PrivateExtractIconExW", 0); PhEndInitOnce(&initOnce); } From 74437fb924291c296fd7f8d928edf79dd4a5ecb8 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 14 Apr 2019 18:47:08 +0200 Subject: [PATCH 1795/2058] Fix type --- ProcessHacker/tokprp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ProcessHacker/tokprp.c b/ProcessHacker/tokprp.c index c5602f0f4208..4bd68b08062a 100644 --- a/ProcessHacker/tokprp.c +++ b/ProcessHacker/tokprp.c @@ -2090,7 +2090,7 @@ INT_PTR CALLBACK PhpTokenAdvancedPageProc( POINT point; PPH_EMENU menu; PPH_EMENU item; - PPHP_TOKEN_PAGE_LISTVIEW_ITEM* listviewItems; + PVOID* listviewItems; ULONG numberOfItems; point.x = GET_X_LPARAM(lParam); @@ -3288,7 +3288,7 @@ INT_PTR CALLBACK PhpTokenContainerPageProc( POINT point; PPH_EMENU menu; PPH_EMENU item; - PPHP_TOKEN_PAGE_LISTVIEW_ITEM* listviewItems; + PVOID* listviewItems; ULONG numberOfItems; point.x = GET_X_LPARAM(lParam); From f3d91aa599df2b24c1e65a0a1f44bcdd9033eee4 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 14 Apr 2019 18:47:36 +0200 Subject: [PATCH 1796/2058] Add copy menu to process services page --- ProcessHacker/srvctl.c | 64 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/ProcessHacker/srvctl.c b/ProcessHacker/srvctl.c index 14a233483a27..7536a0ba5a03 100644 --- a/ProcessHacker/srvctl.c +++ b/ProcessHacker/srvctl.c @@ -3,6 +3,7 @@ * service list control * * Copyright (C) 2010-2011 wj32 + * Copyright (C) 2017-2019 dmex * * This file is part of Process Hacker. * @@ -25,6 +26,7 @@ #include #include #include +#include #include #include @@ -426,6 +428,68 @@ INT_PTR CALLBACK PhpServicesPageProc( PhLoadListViewColumnsFromSetting(settingName, context->ListViewHandle); } break; + case WM_CONTEXTMENU: + { + if ((HWND)wParam == context->ListViewHandle) + { + POINT point; + PPH_EMENU menu; + PPH_EMENU item; + PVOID* listviewItems; + ULONG numberOfItems; + + point.x = GET_X_LPARAM(lParam); + point.y = GET_Y_LPARAM(lParam); + + if (point.x == -1 && point.y == -1) + PhGetListViewContextMenuPoint((HWND)wParam, &point); + + PhGetSelectedListViewItemParams(context->ListViewHandle, &listviewItems, &numberOfItems); + + if (numberOfItems != 0) + { + menu = PhCreateEMenu(); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, IDC_COPY, L"&Copy", NULL, NULL), ULONG_MAX); + PhInsertCopyListViewEMenuItem(menu, IDC_COPY, context->ListViewHandle); + + item = PhShowEMenu( + menu, + hwndDlg, + PH_EMENU_SHOW_SEND_COMMAND | PH_EMENU_SHOW_LEFTRIGHT, + PH_ALIGN_LEFT | PH_ALIGN_TOP, + point.x, + point.y + ); + + if (item) + { + BOOLEAN handled = FALSE; + + handled = PhHandleCopyListViewEMenuItem(item); + + //if (!handled && PhPluginsEnabled) + // handled = PhPluginTriggerEMenuItem(&menuInfo, item); + + if (!handled) + { + switch (item->Id) + { + case IDC_COPY: + { + PhCopyListView(context->ListViewHandle); + } + break; + } + } + } + + PhDestroyEMenu(menu); + } + + PhFree(listviewItems); + } + } + break; } return FALSE; From d7244dfa5b78dc738411ecc189881d8d556ac61f Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 18 Apr 2019 20:50:27 +0200 Subject: [PATCH 1797/2058] SetupTool: Increase service timeout --- tools/CustomSetupTool/CustomSetupTool/setup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/CustomSetupTool/CustomSetupTool/setup.c b/tools/CustomSetupTool/CustomSetupTool/setup.c index 95fb8f681f46..a1ba529b34d1 100644 --- a/tools/CustomSetupTool/CustomSetupTool/setup.c +++ b/tools/CustomSetupTool/CustomSetupTool/setup.c @@ -348,7 +348,7 @@ VOID SetupStopService( { if (status.dwCurrentState != SERVICE_STOPPED) { - ULONG attempts = 10; + ULONG attempts = 60; do { From 8c35d74321fb5df455698310d4422520de4b82b1 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 18 Apr 2019 20:51:26 +0200 Subject: [PATCH 1798/2058] BuildTools: Update build links, Improve GC usage --- tools/CustomBuildTool/Source Files/Build.cs | 14 +++++--------- tools/CustomBuildTool/Source Files/Utils.cs | 13 +++++-------- .../bin/Release/CustomBuildTool.exe | Bin 168448 -> 168448 bytes .../bin/Release/CustomBuildTool.pdb | Bin 85504 -> 85504 bytes 4 files changed, 10 insertions(+), 17 deletions(-) diff --git a/tools/CustomBuildTool/Source Files/Build.cs b/tools/CustomBuildTool/Source Files/Build.cs index 94558410a073..136bcaa43685 100644 --- a/tools/CustomBuildTool/Source Files/Build.cs +++ b/tools/CustomBuildTool/Source Files/Build.cs @@ -1164,8 +1164,7 @@ public static bool BuildSolution(string Solution, BuildFlags Flags) public static bool BuildDeployUpdateConfig() { - string accountName; - string projectName; + string buildJobId; string buildPostUrl; string buildPostApiKey; string buildChangelog; @@ -1173,14 +1172,11 @@ public static bool BuildDeployUpdateConfig() string buildMessage; string buildPostString; - accountName = Environment.ExpandEnvironmentVariables("%APPVEYOR_ACCOUNT_NAME%").Replace("%APPVEYOR_ACCOUNT_NAME%", string.Empty); - projectName = Environment.ExpandEnvironmentVariables("%APPVEYOR_PROJECT_NAME%").Replace("%APPVEYOR_PROJECT_NAME%", string.Empty); + buildJobId = Environment.ExpandEnvironmentVariables("%APPVEYOR_JOB_ID%").Replace("%APPVEYOR_JOB_ID%", string.Empty); buildPostUrl = Environment.ExpandEnvironmentVariables("%APPVEYOR_BUILD_API%").Replace("%APPVEYOR_BUILD_API%", string.Empty); buildPostApiKey = Environment.ExpandEnvironmentVariables("%APPVEYOR_BUILD_KEY%").Replace("%APPVEYOR_BUILD_KEY%", string.Empty); - if (string.IsNullOrEmpty(accountName)) - return true; - if (string.IsNullOrEmpty(projectName)) + if (string.IsNullOrEmpty(buildJobId)) return true; if (string.IsNullOrEmpty(buildPostUrl)) return true; @@ -1209,12 +1205,12 @@ public static bool BuildDeployUpdateConfig() BuildCommit = BuildCommit, BuildMessage = buildMessage, - BinUrl = $"https://ci.appveyor.com/api/projects/%7BaccountName%7D/%7BprojectName%7D/artifacts/processhacker-build-bin.zip", + BinUrl = $"https://ci.appveyor.com/api/buildjobs/%7BbuildJobId%7D/artifacts/processhacker-build-bin.zip", BinLength = BuildBinFileLength.ToString(), BinHash = BuildBinHash, BinSig = BuildBinSig, - SetupUrl = $"https://ci.appveyor.com/api/projects/%7BaccountName%7D/%7BprojectName%7D/artifacts/processhacker-build-setup.exe", + SetupUrl = $"https://ci.appveyor.com/api/buildjobs/%7BbuildJobId%7D/artifacts/processhacker-build-setup.exe", SetupLength = BuildSetupFileLength.ToString(), SetupHash = BuildSetupHash, SetupSig = BuildSetupSig, diff --git a/tools/CustomBuildTool/Source Files/Utils.cs b/tools/CustomBuildTool/Source Files/Utils.cs index 3b1d24f81f65..b8cb380143c8 100644 --- a/tools/CustomBuildTool/Source Files/Utils.cs +++ b/tools/CustomBuildTool/Source Files/Utils.cs @@ -215,11 +215,10 @@ private static Rijndael GetRijndael(string secret) public static void Encrypt(string fileName, string outFileName, string secret) { - FileStream fileOutStream = File.Create(outFileName); - + using (FileStream fileOutStream = File.Create(outFileName)) using (Rijndael rijndael = GetRijndael(secret)) using (FileStream fileStream = File.OpenRead(fileName)) - using (CryptoStream cryptoStream = new CryptoStream(fileOutStream, rijndael.CreateEncryptor(), CryptoStreamMode.Write)) + using (CryptoStream cryptoStream = new CryptoStream(fileOutStream, rijndael.CreateEncryptor(), CryptoStreamMode.Write, true)) { fileStream.CopyTo(cryptoStream); } @@ -227,11 +226,10 @@ public static void Encrypt(string fileName, string outFileName, string secret) public static void Decrypt(string FileName, string outFileName, string secret) { - FileStream fileOutStream = File.Create(outFileName); - + using (FileStream fileOutStream = File.Create(outFileName)) using (Rijndael rijndael = GetRijndael(secret)) using (FileStream fileStream = File.OpenRead(FileName)) - using (CryptoStream cryptoStream = new CryptoStream(fileOutStream, rijndael.CreateDecryptor(), CryptoStreamMode.Write)) + using (CryptoStream cryptoStream = new CryptoStream(fileOutStream, rijndael.CreateDecryptor(), CryptoStreamMode.Write, true)) { fileStream.CopyTo(cryptoStream); } @@ -246,8 +244,7 @@ public static string HashFile(string FileName) // return BitConverter.ToString(hashBytes).Replace("-", String.Empty); //} - FileStream fileInStream = File.OpenRead(FileName); - + using (FileStream fileInStream = File.OpenRead(FileName)) using (BufferedStream bufferedStream = new BufferedStream(fileInStream, 0x1000)) { SHA256Managed sha = new SHA256Managed(); diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe b/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe index 2e91ecb79677763e7550c04afb66ccd5f39f3e5b..2fb69b740cdd4026d01c36d5c0ac0decefe96ce0 100644 GIT binary patch delta 8720 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 C3&Ujq diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb b/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb index 620531b869eb020a928c8cb92944f61e2d0fe1e2..cb320d1d49c8a2cd109c9567cc5a8a305ccaa013 100644 GIT binary patch delta 8391 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 QO4k(eQ?p9{6yYrY2O_ttOaK4? delta 8289 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 O8GDvj1@+`H(!T*Z1XYp% From f384d25b7a8bd0caf50d04dc7df08b12e0ccfc6e Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 18 Apr 2019 20:53:26 +0200 Subject: [PATCH 1799/2058] Fix rare WMI providers tab crash --- ProcessHacker/prpgwmi.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/ProcessHacker/prpgwmi.c b/ProcessHacker/prpgwmi.c index ec1bd9339059..148852ae3a84 100644 --- a/ProcessHacker/prpgwmi.c +++ b/ProcessHacker/prpgwmi.c @@ -2,7 +2,7 @@ * Process Hacker - * Process properties: WMI Providor page * - * Copyright (C) 2017 dmex + * Copyright (C) 2017-2019 dmex * * This file is part of Process Hacker. * @@ -256,7 +256,11 @@ HRESULT PhpQueryWmiProviderFileName( if (SUCCEEDED(IWbemClassObject_Get(wbemClassObject, L"CLSID", 0, &variant, 0, 0))) { - clsidString = PhCreateString(variant.bstrVal); + if (variant.bstrVal) // returns NULL for some host processes (dmex) + { + clsidString = PhCreateString(variant.bstrVal); + } + VariantClear(&variant); } From 5d66001983f2000a7a323f450b5abe8f97178988 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 19 Apr 2019 00:09:45 +0200 Subject: [PATCH 1800/2058] Update versioning for 19H1 --- phlib/global.c | 5 ++++- phlib/include/phconfig.h | 3 ++- phlib/kphdata.c | 12 ++++++++++-- phnt/include/phnt.h | 1 + 4 files changed, 17 insertions(+), 4 deletions(-) diff --git a/phlib/global.c b/phlib/global.c index 57fc87112822..f7a7cc3a7a32 100644 --- a/phlib/global.c +++ b/phlib/global.c @@ -207,8 +207,11 @@ VOID PhInitializeWindowsVersion( case 17763: WindowsVersion = WINDOWS_10_RS5; break; + case 18362: + WindowsVersion = WINDOWS_10_19H1; + break; default: - WindowsVersion = buildVersion > 17763 ? WINDOWS_10_RS5 : WINDOWS_10; + WindowsVersion = WINDOWS_10; break; } } diff --git a/phlib/include/phconfig.h b/phlib/include/phconfig.h index a9e0c5edca84..d0d71cf72432 100644 --- a/phlib/include/phconfig.h +++ b/phlib/include/phconfig.h @@ -34,7 +34,8 @@ PHLIBAPI extern ACCESS_MASK ThreadAllAccess; #define WINDOWS_10_RS3 104 #define WINDOWS_10_RS4 105 #define WINDOWS_10_RS5 106 -#define WINDOWS_NEW MAXLONG +#define WINDOWS_10_19H1 107 +#define WINDOWS_NEW ULONG_MAX #define WINDOWS_HAS_IMMERSIVE (WindowsVersion >= WINDOWS_8) diff --git a/phlib/kphdata.c b/phlib/kphdata.c index 61e4e6a9dbfd..66f55f0f2009 100644 --- a/phlib/kphdata.c +++ b/phlib/kphdata.c @@ -43,7 +43,7 @@ ULONG KphpGetKernelRevisionNumber( PhDereferenceObject(kernelFileName); if (versionInfo && VerQueryValue(versionInfo, L"\\", &rootBlock, &rootBlockLength) && rootBlockLength != 0) - result = rootBlock->dwFileVersionLS & 0xffff; + result = LOWORD(rootBlock->dwFileVersionLS); PhFree(versionInfo); @@ -66,7 +66,7 @@ NTSTATUS KphInitializeDynamicPackage( Package->MajorVersion = (USHORT)majorVersion; Package->MinorVersion = (USHORT)minorVersion; Package->ServicePackMajor = (USHORT)servicePack; - Package->BuildNumber = -1; + Package->BuildNumber = USHRT_MAX; // Windows 7, Windows Server 2008 R2 if (majorVersion == 6 && minorVersion == 1) @@ -159,6 +159,10 @@ NTSTATUS KphInitializeDynamicPackage( Package->BuildNumber = 17763; Package->ResultingNtVersion = PHNT_REDSTONE5; break; + case 18362: + Package->BuildNumber = 18362; + Package->ResultingNtVersion = PHNT_19H1; + break; default: return STATUS_NOT_SUPPORTED; } @@ -297,6 +301,10 @@ NTSTATUS KphInitializeDynamicPackage( Package->BuildNumber = 17763; Package->ResultingNtVersion = PHNT_REDSTONE5; break; + case 18362: + Package->BuildNumber = 18362; + Package->ResultingNtVersion = PHNT_19H1; + break; default: return STATUS_NOT_SUPPORTED; } diff --git a/phnt/include/phnt.h b/phnt/include/phnt.h index 677c784ef54e..0f6e1d72d2c5 100644 --- a/phnt/include/phnt.h +++ b/phnt/include/phnt.h @@ -38,6 +38,7 @@ #define PHNT_REDSTONE3 104 #define PHNT_REDSTONE4 105 #define PHNT_REDSTONE5 106 +#define PHNT_19H1 107 #ifndef PHNT_MODE #define PHNT_MODE PHNT_MODE_USER From 1064051067f6495d0a988c745ef31d6bf3d0374c Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 19 Apr 2019 00:10:22 +0200 Subject: [PATCH 1801/2058] PHNT: Add RtlQueryTokenHostIdAsUlong64 --- phnt/include/ntrtl.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/phnt/include/ntrtl.h b/phnt/include/ntrtl.h index 4c85ffca9ab8..b2dfe464207b 100644 --- a/phnt/include/ntrtl.h +++ b/phnt/include/ntrtl.h @@ -7665,6 +7665,15 @@ RtlCheckTokenMembershipEx( _Out_ PBOOLEAN IsMember ); +// rev +NTSYSAPI +NTSTATUS +NTAPI +RtlQueryTokenHostIdAsUlong64( + _In_ HANDLE TokenHandle, + _Out_ PULONG64 HostId // (WIN://PKGHOSTID) + ); + // rev NTSYSAPI NTSTATUS From 7e814aed63f5fd9ab9fffcaa83ef57f2d93909cf Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 19 Apr 2019 00:11:51 +0200 Subject: [PATCH 1802/2058] Add workaround for issue with selection->search->termination of invisible entries --- ProcessHacker/proctree.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ProcessHacker/proctree.c b/ProcessHacker/proctree.c index 0ef0936f2e2d..d473e640ff28 100644 --- a/ProcessHacker/proctree.c +++ b/ProcessHacker/proctree.c @@ -3433,6 +3433,10 @@ VOID PhGetSelectedProcessItems( { PPH_PROCESS_NODE node = ProcessNodeList->Items[i]; + // HACK workaround issue with multiple select->search->termination and Searchbox->PhApplyTreeNewFilters (dmex) + if (!node->Node.Visible) + continue; + if (node->Node.Selected) PhAddItemArray(&array, &node->ProcessItem); } From 40f6e981e7908c6c498efbe66004d0cad6b0b510 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 19 Apr 2019 00:12:44 +0200 Subject: [PATCH 1803/2058] Add copy support to WMI providers tab --- ProcessHacker/prpgwmi.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/ProcessHacker/prpgwmi.c b/ProcessHacker/prpgwmi.c index 148852ae3a84..d87028a9f1dd 100644 --- a/ProcessHacker/prpgwmi.c +++ b/ProcessHacker/prpgwmi.c @@ -680,7 +680,8 @@ INT_PTR CALLBACK PhpProcessWmiProvidersDlgProc( PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), -1); } PhInsertEMenuItem(menu, PhCreateEMenuItem(0, 4, L"Open &file location", NULL, NULL), -1); - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, 5, L"&Copy", NULL, NULL), -1); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, IDC_COPY, L"&Copy", NULL, NULL), -1); + PhInsertCopyListViewEMenuItem(menu, IDC_COPY, context->ListViewHandle); selectedItem = PhShowEMenu( menu, @@ -692,10 +693,19 @@ INT_PTR CALLBACK PhpProcessWmiProvidersDlgProc( ); PhDestroyEMenu(menu); - if (selectedItem && selectedItem->Id != -1) + if (selectedItem && selectedItem->Id != ULONG_MAX) { PPH_WMI_ENTRY entry; - + BOOLEAN handled = FALSE; + + handled = PhHandleCopyListViewEMenuItem(selectedItem); + + //if (!handled && PhPluginsEnabled) + // handled = PhPluginTriggerEMenuItem(&menuInfo, item); + + if (handled) + break; + entry = context->WmiProviderList->Items[PtrToUlong(index) - 1]; switch (selectedItem->Id) @@ -741,6 +751,11 @@ INT_PTR CALLBACK PhpProcessWmiProvidersDlgProc( PhSetDialogFocus(hwndDlg, context->ListViewHandle); } break; + case IDC_COPY: + { + PhCopyListView(context->ListViewHandle); + } + break; } } } From 4800197d9dc96df1bb77b1e9af30fb188782ed57 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 19 Apr 2019 00:13:40 +0200 Subject: [PATCH 1804/2058] Remove unused string duplication --- ProcessHacker/appsup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ProcessHacker/appsup.c b/ProcessHacker/appsup.c index 27f9e832af78..ebc1c1ef5b2f 100644 --- a/ProcessHacker/appsup.c +++ b/ProcessHacker/appsup.c @@ -321,7 +321,7 @@ PH_KNOWN_PROCESS_TYPE PhGetProcessKnownTypeEx( PhGetSystemRoot(&systemRootPrefix); - fileName = PhDuplicateString(FileName); + fileName = PhReferenceObject(FileName); name = fileName->sr; knownProcessType = UnknownProcessType; From b7ba0caf87bd4994b3fed64e9a16178474d54a1d Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 19 Apr 2019 00:29:10 +0200 Subject: [PATCH 1805/2058] Fix some SAL annotations --- plugins/CommonUtil/http.c | 10 +++++----- plugins/CommonUtil/http.h | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/plugins/CommonUtil/http.c b/plugins/CommonUtil/http.c index 35e30725e209..db1bc06c80cd 100644 --- a/plugins/CommonUtil/http.c +++ b/plugins/CommonUtil/http.c @@ -132,7 +132,7 @@ BOOLEAN PhHttpSocketBeginRequest( &httpFlags, Flags, PhpHttpRequestFlagMappings, - ARRAYSIZE(PhpHttpRequestFlagMappings) + RTL_NUMBER_OF(PhpHttpRequestFlagMappings) ); HttpContext->RequestHandle = WinHttpOpenRequest( @@ -160,8 +160,8 @@ BOOLEAN PhHttpSocketBeginRequest( BOOLEAN PhHttpSocketSendRequest( _In_ PPH_HTTP_CONTEXT HttpContext, - _In_ PVOID RequestData, - _In_ ULONG RequestDataLength + _In_opt_ PVOID RequestData, + _In_opt_ ULONG RequestDataLength ) { return !!WinHttpSendRequest( @@ -271,7 +271,7 @@ BOOLEAN PhHttpSocketQueryHeaderUlong( &queryFlags, QueryValue, PhpHttpHeaderQueryMappings, - ARRAYSIZE(PhpHttpHeaderQueryMappings) + RTL_NUMBER_OF(PhpHttpHeaderQueryMappings) ); if (WinHttpQueryHeaders( @@ -422,7 +422,7 @@ BOOLEAN PhHttpSocketSetFeature( &featureValue, Feature, PhpHttpFeatureMappings, - ARRAYSIZE(PhpHttpFeatureMappings) + RTL_NUMBER_OF(PhpHttpFeatureMappings) ); return !!WinHttpSetOption( diff --git a/plugins/CommonUtil/http.h b/plugins/CommonUtil/http.h index 8b5ce31f818f..4cd8cc0addf9 100644 --- a/plugins/CommonUtil/http.h +++ b/plugins/CommonUtil/http.h @@ -53,8 +53,8 @@ BOOLEAN NTAPI PhHttpSocketSendRequest( _In_ PPH_HTTP_CONTEXT HttpContext, - _In_ PVOID RequestData, - _In_ ULONG RequestDataLength + _In_opt_ PVOID RequestData, + _In_opt_ ULONG RequestDataLength ); BOOLEAN From e0d0ea97b1c40eb11877afe8ff45d6715123b79e Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 19 Apr 2019 00:30:04 +0200 Subject: [PATCH 1806/2058] Add undocumented PSM functions --- phlib/include/appresolverp.h | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/phlib/include/appresolverp.h b/phlib/include/appresolverp.h index 2d85aa5e6659..4279f69a230b 100644 --- a/phlib/include/appresolverp.h +++ b/phlib/include/appresolverp.h @@ -2,7 +2,7 @@ * Process Hacker - * Appmodel support functions * - * Copyright (C) 2017-2018 dmex + * Copyright (C) 2017-2019 dmex * * This file is part of Process Hacker. * @@ -73,6 +73,34 @@ static HRESULT (WINAPI* AppPolicyGetWindowingModel_I)( _Out_ AppPolicyWindowingModel *ProcessWindowingModelPolicy ) = NULL; +// rev +static NTSTATUS (NTAPI* PsmGetKeyFromProcess_I)( + _In_ HANDLE ProcessHandle, + _Out_ PVOID KeyBuffer, + _Inout_ PULONG KeyLength + ) = NULL; + +// rev +static NTSTATUS (NTAPI* PsmGetKeyFromToken_I)( + _In_ HANDLE TokenHandle, + _Out_ PVOID KeyBuffer, + _Inout_ PULONG KeyLength + ) = NULL; + +// rev +static NTSTATUS (NTAPI* PsmGetApplicationNameFromKey_I)( + _In_ PVOID KeyBuffer, + _Out_ PVOID NameBuffer, + _Inout_ PULONG NameLength + ) = NULL; + +// rev +static NTSTATUS (NTAPI* PsmGetPackageFullNameFromKey_I)( + _In_ PVOID KeyBuffer, + _Out_ PVOID NameBuffer, + _Inout_ PULONG NameLength + ) = NULL; + typedef enum _START_MENU_APP_ITEMS_FLAGS { SMAIF_DEFAULT = 0, From 884d2eca64522cc10a3f8d9c2b01bda36272facf Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 19 Apr 2019 01:51:16 +0200 Subject: [PATCH 1807/2058] Add package tasks function --- phlib/appresolver.c | 110 ++++++++++++++++++++++++++++++++++++ phlib/include/appresolver.h | 10 ++++ 2 files changed, 120 insertions(+) diff --git a/phlib/appresolver.c b/phlib/appresolver.c index a700532fed89..a3e7d4c073ef 100644 --- a/phlib/appresolver.c +++ b/phlib/appresolver.c @@ -240,6 +240,62 @@ HRESULT PhAppResolverActivateAppId( return status; } +PPH_LIST PhAppResolverEnumeratePackageBackgroundTasks( + _In_ PPH_STRING PackageFullName + ) +{ + HRESULT status; + PPH_LIST packageTasks = NULL; + IPackageDebugSettings* packageDebugSettings; + + status = CoCreateInstance( + &CLSID_PackageDebugSettings, + NULL, + CLSCTX_INPROC_SERVER, + &IID_IPackageDebugSettings, + &packageDebugSettings + ); + + if (SUCCEEDED(status)) + { + ULONG taskCount = 0; + PGUID taskIds = NULL; + PWSTR* taskNames = NULL; + + status = IPackageDebugSettings_EnumerateBackgroundTasks( + packageDebugSettings, + PhGetString(PackageFullName), + &taskCount, + &taskIds, + &taskNames + ); + + if (SUCCEEDED(status)) + { + for (ULONG i = 0; i < taskCount; i++) + { + PPH_PACKAGE_TASK_ENTRY entry; + + entry = PhAllocateZero(sizeof(PH_PACKAGE_TASK_ENTRY)); + entry->TaskGuid = taskIds[i]; + entry->TaskName = PhCreateString(taskNames[i]); + + if (!packageTasks) + packageTasks = PhCreateList(taskCount); + + PhAddItemList(packageTasks, entry); + } + } + + IPackageDebugSettings_Release(packageDebugSettings); + } + + if (packageTasks) + return packageTasks; + else + return NULL; +} + PPH_STRING PhGetAppContainerName( _In_ PSID AppContainerSid ) @@ -357,6 +413,60 @@ PPH_STRING PhGetPackagePath( return packagePath; } +PPH_STRING PhGetPackageAppDataPath( + _In_ HANDLE ProcessHandle + ) +{ + static UNICODE_STRING attributeNameUs = RTL_CONSTANT_STRING(L"WIN://SYSAPPID"); + static PH_STRINGREF appdataPackages = PH_STRINGREF_INIT(L"%APPDATALOCAL%\\Packages\\"); + HANDLE tokenHandle; + PTOKEN_SECURITY_ATTRIBUTES_INFORMATION info; + PPH_STRING packageAppDataPath = NULL; + + if (NT_SUCCESS(PhOpenProcessToken( + ProcessHandle, + TOKEN_QUERY, + &tokenHandle + ))) + { + if (NT_SUCCESS(PhQueryTokenVariableSize(tokenHandle, TokenSecurityAttributes, &info))) + { + for (ULONG i = 0; i < info->AttributeCount; i++) + { + PTOKEN_SECURITY_ATTRIBUTE_V1 attribute = &info->Attribute.pAttributeV1[i]; + + if (attribute->ValueType == TOKEN_SECURITY_ATTRIBUTE_TYPE_STRING) + { + if (RtlEqualUnicodeString(&attribute->Name, &attributeNameUs, FALSE)) + { + PPH_STRING attributeValue; + PPH_STRING attributePath; + + attributeValue = PhCreateStringFromUnicodeString(&attribute->Values.pString[2]); + + if (attributePath = PhExpandEnvironmentStrings(&appdataPackages)) + { + packageAppDataPath = PhConcatStringRef2(&attributePath->sr, &attributeValue->sr); + + PhDereferenceObject(attributePath); + PhDereferenceObject(attributeValue); + break; + } + + PhDereferenceObject(attributeValue); + } + } + } + + PhFree(info); + } + + NtClose(tokenHandle); + } + + return packageAppDataPath; +} + PPH_STRING PhGetProcessPackageFullName( _In_ HANDLE ProcessHandle ) diff --git a/phlib/include/appresolver.h b/phlib/include/appresolver.h index d61188f1c85d..073342d28a2c 100644 --- a/phlib/include/appresolver.h +++ b/phlib/include/appresolver.h @@ -43,6 +43,16 @@ HRESULT PhAppResolverActivateAppId( _Out_opt_ HANDLE *ProcessId ); +typedef struct _PH_PACKAGE_TASK_ENTRY +{ + PPH_STRING TaskName; + GUID TaskGuid; +} PH_PACKAGE_TASK_ENTRY, *PPH_PACKAGE_TASK_ENTRY; + +PPH_LIST PhAppResolverEnumeratePackageBackgroundTasks( + _In_ PPH_STRING PackageFullName + ); + PPH_STRING PhGetAppContainerName( _In_ PSID AppContainerSid ); From baa183db3e2faceee76ff38ac58b1bef9c383db2 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 19 Apr 2019 02:08:34 +0200 Subject: [PATCH 1808/2058] Add LdrIsModuleSxsRedirected --- phnt/include/ntldr.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/phnt/include/ntldr.h b/phnt/include/ntldr.h index 0859374439cf..2996960c7cd3 100644 --- a/phnt/include/ntldr.h +++ b/phnt/include/ntldr.h @@ -937,6 +937,16 @@ LdrControlFlowGuardEnforced( VOID ); +#if (PHNT_VERSION >= PHNT_19H1) +// rev +NTSYSAPI +BOOLEAN +NTAPI +LdrIsModuleSxsRedirected( + _In_ PVOID DllHandle + ); +#endif + #endif // (PHNT_MODE != PHNT_MODE_KERNEL) #endif From 9c0844716eaaccccaf9e658f15724abc19c8794a Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 19 Apr 2019 02:26:25 +0200 Subject: [PATCH 1809/2058] Add PhInitializeWindowThemeEx --- phlib/include/guisup.h | 7 +++++++ phlib/theme.c | 23 +++++++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/phlib/include/guisup.h b/phlib/include/guisup.h index 44cebad04a89..a2d40ef8d625 100644 --- a/phlib/include/guisup.h +++ b/phlib/include/guisup.h @@ -909,6 +909,13 @@ PhInitializeWindowTheme( _In_ BOOLEAN EnableThemeSupport ); +PHLIBAPI +VOID +NTAPI +PhInitializeWindowThemeEx( + _In_ HWND WindowHandle + ); + PHLIBAPI VOID NTAPI diff --git a/phlib/theme.c b/phlib/theme.c index e6bd0a1b4214..37efd68d9b06 100644 --- a/phlib/theme.c +++ b/phlib/theme.c @@ -194,6 +194,29 @@ VOID PhInitializeWindowTheme( } } +VOID PhInitializeWindowThemeEx( + _In_ HWND WindowHandle + ) +{ + static PH_STRINGREF keyPath = PH_STRINGREF_INIT(L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize"); + HANDLE keyHandle; + BOOLEAN enableThemeSupport = FALSE; + + if (NT_SUCCESS(PhOpenKey( + &keyHandle, + KEY_READ, + PH_KEY_CURRENT_USER, + &keyPath, + 0 + ))) + { + enableThemeSupport = !PhQueryRegistryUlong(keyHandle, L"AppsUseLightTheme"); + NtClose(keyHandle); + } + + PhInitializeWindowTheme(WindowHandle, enableThemeSupport); +} + VOID PhReInitializeWindowTheme( _In_ HWND WindowHandle ) From 0b6e99cba24e38a6ae8a9814393d53d2ae8e8d36 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 19 Apr 2019 08:40:56 +0200 Subject: [PATCH 1810/2058] Add PhImpersonateToken/PhRevertImpersonationToken --- phlib/include/phnative.h | 15 ++++++++++ phlib/native.c | 62 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+) diff --git a/phlib/include/phnative.h b/phlib/include/phnative.h index ce23587df5fb..a776cfb026d2 100644 --- a/phlib/include/phnative.h +++ b/phlib/include/phnative.h @@ -1432,6 +1432,21 @@ PhGetThreadName( _Out_ PPH_STRING *ThreadName ); +PHLIBAPI +NTSTATUS +NTAPI +PhImpersonateToken( + _In_ HANDLE ThreadHandle, + _In_ HANDLE TokenHandle + ); + +PHLIBAPI +NTSTATUS +NTAPI +PhRevertImpersonationToken( + _In_ HANDLE ThreadHandle + ); + #ifdef __cplusplus } #endif diff --git a/phlib/native.c b/phlib/native.c index 79a9bc1c5f28..ad015a27777f 100644 --- a/phlib/native.c +++ b/phlib/native.c @@ -8227,3 +8227,65 @@ NTSTATUS PhGetThreadName( return status; } + +NTSTATUS PhImpersonateToken( + _In_ HANDLE ThreadHandle, + _In_ HANDLE TokenHandle + ) +{ + NTSTATUS status; + SECURITY_QUALITY_OF_SERVICE securityService; + OBJECT_ATTRIBUTES objectAttributes; + HANDLE tokenHandle; + + InitializeObjectAttributes( + &objectAttributes, + NULL, + 0, + NULL, + NULL + ); + + securityService.Length = sizeof(SECURITY_QUALITY_OF_SERVICE); + securityService.ImpersonationLevel = SecurityImpersonation; + securityService.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING; + securityService.EffectiveOnly = FALSE; + objectAttributes.SecurityQualityOfService = &securityService; + + status = NtDuplicateToken( + TokenHandle, + TOKEN_IMPERSONATE | TOKEN_QUERY, + &objectAttributes, + FALSE, + TokenImpersonation, + &tokenHandle + ); + + if (!NT_SUCCESS(status)) + return status; + + status = NtSetInformationThread( + ThreadHandle, + ThreadImpersonationToken, + &tokenHandle, + sizeof(HANDLE) + ); + + NtClose(tokenHandle); + + return status; +} + +NTSTATUS PhRevertImpersonationToken( + _In_ HANDLE ThreadHandle + ) +{ + HANDLE tokenHandle = NULL; + + return NtSetInformationThread( + ThreadHandle, + ThreadImpersonationToken, + &tokenHandle, + sizeof(HANDLE) + ); +} From 549de5f57b4301237a03fa6f40a1de0bd106d4e3 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 19 Apr 2019 08:42:33 +0200 Subject: [PATCH 1811/2058] Add appcontainer profile locations to token container properties page --- ProcessHacker/tokprp.c | 108 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 105 insertions(+), 3 deletions(-) diff --git a/ProcessHacker/tokprp.c b/ProcessHacker/tokprp.c index 4bd68b08062a..061e7bce4b4b 100644 --- a/ProcessHacker/tokprp.c +++ b/ProcessHacker/tokprp.c @@ -25,11 +25,14 @@ #include #include #include +#include #include #include #include #include +#include + typedef enum _PH_PROCESS_TOKEN_CATEGORY { PH_PROCESS_TOKEN_CATEGORY_DANGEROUS_FLAGS, @@ -3048,6 +3051,63 @@ INT_PTR CALLBACK PhpTokenAttributesPageProc( return FALSE; } +PPH_STRING PhpGetTokenAppContainerFolderPath( + _In_ PSID TokenAppContainerSid + ) +{ + PPH_STRING appContainerFolderPath = NULL; + PPH_STRING appContainerSid; + PWSTR folderPath; + + appContainerSid = PhSidToStringSid(TokenAppContainerSid); + + if (GetAppContainerFolderPath) + { + if (SUCCEEDED(GetAppContainerFolderPath(appContainerSid->Buffer, &folderPath))) + { + appContainerFolderPath = PhCreateString(folderPath); + CoTaskMemFree(folderPath); + } + } + + PhDereferenceObject(appContainerSid); + + return appContainerFolderPath; +} + +PPH_STRING PhpGetTokenAppContainerRegistryPath( + _In_ HANDLE TokenHandle + ) +{ + PPH_STRING appContainerRegistryPath = NULL; + HKEY registryHandle = NULL; + + if (NT_SUCCESS(PhImpersonateToken(NtCurrentThread(), TokenHandle))) + { + if (GetAppContainerRegistryLocation) + GetAppContainerRegistryLocation(KEY_READ, ®istryHandle); + + PhRevertImpersonationToken(NtCurrentThread()); + } + + if (registryHandle) + { + PhGetHandleInformation( + NtCurrentProcess(), + registryHandle, + ULONG_MAX, + NULL, + NULL, + NULL, + &appContainerRegistryPath + ); + + NtClose(registryHandle); + } + + return appContainerRegistryPath; +} + INT_PTR CALLBACK PhpTokenContainerPageProc( _In_ HWND hwndDlg, _In_ UINT uMsg, @@ -3100,6 +3160,7 @@ INT_PTR CALLBACK PhpTokenContainerPageProc( PhAddListViewGroup(context->ListViewHandle, 1, L"Properties"); PhAddListViewGroup(context->ListViewHandle, 2, L"Parent"); PhAddListViewGroup(context->ListViewHandle, 3, L"Package"); + PhAddListViewGroup(context->ListViewHandle, 4, L"Profile"); PhAddListViewGroupItem(context->ListViewHandle, 0, MAXINT, L"Name", NULL); PhAddListViewGroupItem(context->ListViewHandle, 0, MAXINT, L"Type", NULL); @@ -3111,6 +3172,8 @@ INT_PTR CALLBACK PhpTokenContainerPageProc( PhAddListViewGroupItem(context->ListViewHandle, 2, MAXINT, L"SID", NULL); PhAddListViewGroupItem(context->ListViewHandle, 3, MAXINT, L"Name", NULL); PhAddListViewGroupItem(context->ListViewHandle, 3, MAXINT, L"Path", NULL); + PhAddListViewGroupItem(context->ListViewHandle, 4, MAXINT, L"Folder path", NULL); + PhAddListViewGroupItem(context->ListViewHandle, 4, MAXINT, L"Registry path", NULL); if (NT_SUCCESS(tokenPageContext->OpenObject( &tokenHandle, @@ -3130,11 +3193,11 @@ INT_PTR CALLBACK PhpTokenContainerPageProc( if (appContainerInfo->TokenAppContainer) { static PH_INITONCE initOnce = PH_INITONCE_INIT; - static NTSTATUS (WINAPI* RtlGetAppContainerSidType_I)( + static NTSTATUS (NTAPI* RtlGetAppContainerSidType_I)( _In_ PSID AppContainerSid, _Out_ PAPPCONTAINER_SID_TYPE AppContainerSidType ) = NULL; - static NTSTATUS (WINAPI* RtlGetAppContainerParent_I)( + static NTSTATUS (NTAPI* RtlGetAppContainerParent_I)( _In_ PSID AppContainerSid, _Out_ PSID* AppContainerSidParent ) = NULL; @@ -3242,7 +3305,11 @@ INT_PTR CALLBACK PhpTokenContainerPageProc( NtClose(tokenHandle); } - if (NT_SUCCESS(PhOpenProcess(&processHandle, PROCESS_QUERY_LIMITED_INFORMATION, tokenPageContext->ProcessId))) + if (NT_SUCCESS(PhOpenProcess( + &processHandle, + PROCESS_QUERY_LIMITED_INFORMATION, + tokenPageContext->ProcessId + ))) { PPH_STRING packageFullName; PPH_STRING packagePath; @@ -3263,6 +3330,41 @@ INT_PTR CALLBACK PhpTokenContainerPageProc( NtClose(processHandle); } + if (NT_SUCCESS(tokenPageContext->OpenObject( + &tokenHandle, + TOKEN_QUERY | TOKEN_IMPERSONATE | TOKEN_DUPLICATE, + tokenPageContext->Context + ))) + { + PTOKEN_APPCONTAINER_INFORMATION appContainerInfo; + PPH_STRING appContainerFolderPath = NULL; + PPH_STRING appContainerRegistryPath = NULL; + + if (NT_SUCCESS(PhQueryTokenVariableSize(tokenHandle, TokenAppContainerSid, &appContainerInfo))) + { + if (appContainerInfo->TokenAppContainer) + { + appContainerFolderPath = PhpGetTokenAppContainerFolderPath(appContainerInfo->TokenAppContainer); + } + + PhFree(appContainerInfo); + } + + if (appContainerFolderPath) + { + PhSetListViewSubItem(context->ListViewHandle, 10, 1, appContainerFolderPath->Buffer); + PhDereferenceObject(appContainerFolderPath); + } + + if (appContainerRegistryPath = PhpGetTokenAppContainerRegistryPath(tokenHandle)) + { + PhSetListViewSubItem(context->ListViewHandle, 11, 1, appContainerRegistryPath->Buffer); + PhDereferenceObject(appContainerRegistryPath); + } + + NtClose(tokenHandle); + } + PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport); } break; From 83c98f82ad6e903136f3271820f578aab59c9bf1 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 19 Apr 2019 15:50:02 +0200 Subject: [PATCH 1812/2058] Update token advanced page with standard profile locations --- ProcessHacker/tokprp.c | 174 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 163 insertions(+), 11 deletions(-) diff --git a/ProcessHacker/tokprp.c b/ProcessHacker/tokprp.c index 061e7bce4b4b..fd1c005abe95 100644 --- a/ProcessHacker/tokprp.c +++ b/ProcessHacker/tokprp.c @@ -187,6 +187,13 @@ INT_PTR CALLBACK PhpTokenContainerPageProc( _In_ LPARAM lParam ); +PPH_STRING PhpGetTokenFolderPath( + _In_ HANDLE TokenHandle + ); +PPH_STRING PhpGetTokenRegistryPath( + _In_ HANDLE TokenHandle + ); + VOID PhShowTokenProperties( _In_ HWND ParentWindowHandle, _In_ PPH_OPEN_OBJECT OpenObject, @@ -1913,6 +1920,7 @@ INT_PTR CALLBACK PhpTokenAdvancedPageProc( case WM_INITDIALOG: { HANDLE tokenHandle; + ULONG listViewGroupIndex = 0; PWSTR tokenType = L"Unknown"; PWSTR tokenImpersonationLevel = L"Unknown"; WCHAR tokenLuid[PH_PTR_STR_LEN_1] = L"Unknown"; @@ -1925,6 +1933,8 @@ INT_PTR CALLBACK PhpTokenAdvancedPageProc( PPH_STRING tokenSecurityDescriptorString = NULL; PPH_STRING tokenTrustLevelSidString; PPH_STRING tokenTrustLevelNameString; + PPH_STRING tokenProfilePathString; + PPH_STRING tokenProfileRegistryString; context->ListViewHandle = GetDlgItem(hwndDlg, IDC_LIST); PhSetListViewStyle(context->ListViewHandle, FALSE, TRUE); @@ -1937,10 +1947,10 @@ INT_PTR CALLBACK PhpTokenAdvancedPageProc( PhAddLayoutItem(&context->LayoutManager, context->ListViewHandle, NULL, PH_ANCHOR_ALL); ListView_EnableGroupView(context->ListViewHandle, TRUE); - PhAddListViewGroup(context->ListViewHandle, 0, L"General"); - PhAddListViewGroup(context->ListViewHandle, 1, L"LUIDs"); - PhAddListViewGroup(context->ListViewHandle, 2, L"Memory"); - PhAddListViewGroup(context->ListViewHandle, 3, L"Properties"); + PhAddListViewGroup(context->ListViewHandle, listViewGroupIndex++, L"General"); + PhAddListViewGroup(context->ListViewHandle, listViewGroupIndex++, L"LUIDs"); + PhAddListViewGroup(context->ListViewHandle, listViewGroupIndex++, L"Memory"); + PhAddListViewGroup(context->ListViewHandle, listViewGroupIndex++, L"Properties"); PhAddListViewGroupItem(context->ListViewHandle, 0, MAXINT, L"Type", NULL); PhAddListViewGroupItem(context->ListViewHandle, 0, MAXINT, L"Impersonation level", NULL); PhAddListViewGroupItem(context->ListViewHandle, 1, MAXINT, L"Token LUID", NULL); @@ -2024,7 +2034,7 @@ INT_PTR CALLBACK PhpTokenAdvancedPageProc( INT trustLevelSidIndex; INT trustLevelNameIndex; - trustLevelGroupIndex = PhAddListViewGroup(context->ListViewHandle, 4, L"TrustLevel"); + trustLevelGroupIndex = PhAddListViewGroup(context->ListViewHandle, listViewGroupIndex++, L"TrustLevel"); trustLevelSidIndex = PhAddListViewGroupItem(context->ListViewHandle, trustLevelGroupIndex, MAXINT, L"TrustLevel Sid", NULL); trustLevelNameIndex = PhAddListViewGroupItem(context->ListViewHandle, trustLevelGroupIndex, MAXINT, L"TrustLevel Name", NULL); @@ -2040,7 +2050,7 @@ INT_PTR CALLBACK PhpTokenAdvancedPageProc( //{ // PPH_STRING tokenLogonName = PhGetSidFullName(tokenLogonGroups->Groups[0].Sid, TRUE, NULL); // PPH_STRING tokenLogonSid = PhSidToStringSid(tokenLogonGroups->Groups[0].Sid); - // INT tokenLogonGroupIndex = PhAddListViewGroup(context->ListViewHandle, 5, L"Logon"); + // INT tokenLogonGroupIndex = PhAddListViewGroup(context->ListViewHandle, listViewGroupIndex++, L"Logon"); // INT tokenLogonNameIndex = PhAddListViewGroupItem(context->ListViewHandle, tokenLogonGroupIndex, MAXINT, L"Token logon SID", NULL); // INT tokenLogonSidIndex = PhAddListViewGroupItem(context->ListViewHandle, tokenLogonGroupIndex, MAXINT, L"Token logon Name", NULL); // PhSetListViewSubItem(context->ListViewHandle, tokenLogonNameIndex, 1, PhGetStringOrDefault(tokenLogonName, L"Unknown")); @@ -2048,6 +2058,27 @@ INT_PTR CALLBACK PhpTokenAdvancedPageProc( // PhFree(tokenLogonGroups); //} + if (tokenProfilePathString = PhpGetTokenFolderPath(tokenHandle)) + { + INT profileGroupIndex; + INT profileFolderIndex; + INT profileRegistryIndex; + + profileGroupIndex = PhAddListViewGroup(context->ListViewHandle, listViewGroupIndex++, L"Profile"); + profileFolderIndex = PhAddListViewGroupItem(context->ListViewHandle, profileGroupIndex, MAXINT, L"Folder path", NULL); + profileRegistryIndex = PhAddListViewGroupItem(context->ListViewHandle, profileGroupIndex, MAXINT, L"Registry path", NULL); + + PhSetListViewSubItem(context->ListViewHandle, profileFolderIndex, 1, PhGetStringOrDefault(tokenProfilePathString, L"N/A")); + + if (tokenProfileRegistryString = PhpGetTokenRegistryPath(tokenHandle)) + { + PhSetListViewSubItem(context->ListViewHandle, profileRegistryIndex, 1, PhGetStringOrDefault(tokenProfileRegistryString, L"N/A")); + PhDereferenceObject(tokenProfileRegistryString); + } + + PhDereferenceObject(tokenProfilePathString); + } + NtClose(tokenHandle); } @@ -2278,6 +2309,21 @@ VOID PhpDestroyAttributeNode( PhFree(Node); } +VOID PhpRemoveAttributeNode( + _In_ PATTRIBUTE_TREE_CONTEXT Context, + _In_ PATTRIBUTE_NODE Node + ) +{ + ULONG index; + + if ((index = PhFindItemList(Context->NodeList, Node)) != -1) + PhRemoveItemList(Context->NodeList, index); + if ((index = PhFindItemList(Context->RootList, Node)) != -1) + PhRemoveItemList(Context->RootList, index); + + PhpDestroyAttributeNode(Node); +} + VOID PhpGetSelectedAttributeTreeNodes( _Inout_ PATTRIBUTE_TREE_CONTEXT Context, _Out_ PATTRIBUTE_NODE **AttributeNodes, @@ -2814,14 +2860,23 @@ INT_PTR CALLBACK PhpTokenClaimsPageProc( TreeNew_SetRedraw(tnHandle, FALSE); userNode = PhpAddAttributeNode(&tokenPageContext->ClaimsTreeContext, NULL, PhCreateString(L"User claims")); - PhpAddTokenClaimAttributes(tokenPageContext, tnHandle, FALSE, userNode); deviceNode = PhpAddAttributeNode(&tokenPageContext->ClaimsTreeContext, NULL, PhCreateString(L"Device claims")); + + PhpAddTokenClaimAttributes(tokenPageContext, tnHandle, FALSE, userNode); PhpAddTokenClaimAttributes(tokenPageContext, tnHandle, TRUE, deviceNode); - if (userNode->Children->Count == 0) - PhpAddAttributeNode(&tokenPageContext->ClaimsTreeContext, userNode, PhCreateString(L"(None)")); - if (deviceNode->Children->Count == 0) - PhpAddAttributeNode(&tokenPageContext->ClaimsTreeContext, deviceNode, PhCreateString(L"(None)")); + if (userNode->Children->Count == 0 && deviceNode->Children->Count == 0) + { + PhpRemoveAttributeNode(&tokenPageContext->ClaimsTreeContext, userNode); + PhpRemoveAttributeNode(&tokenPageContext->ClaimsTreeContext, deviceNode); + } + else + { + if (userNode->Children->Count == 0) + PhpAddAttributeNode(&tokenPageContext->ClaimsTreeContext, userNode, PhCreateString(L"(None)")); + if (deviceNode->Children->Count == 0) + PhpAddAttributeNode(&tokenPageContext->ClaimsTreeContext, deviceNode, PhCreateString(L"(None)")); + } TreeNew_NodesStructured(tnHandle); TreeNew_SetRedraw(tnHandle, TRUE); @@ -3051,6 +3106,103 @@ INT_PTR CALLBACK PhpTokenAttributesPageProc( return FALSE; } +// rev from GetUserProfileDirectory (dmex) +PPH_STRING PhpGetTokenFolderPath( + _In_ HANDLE TokenHandle + ) +{ + static PH_STRINGREF servicesKeyName = PH_STRINGREF_INIT(L"Software\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList\\"); + PPH_STRING profileFolderPath = NULL; + PPH_STRING profileKeyPath = NULL; + PPH_STRING tokenUserSid; + PTOKEN_USER tokenUser; + + if (NT_SUCCESS(PhGetTokenUser(TokenHandle, &tokenUser))) + { + if (tokenUserSid = PhSidToStringSid(tokenUser->User.Sid)) + { + profileKeyPath = PhConcatStringRef2(&servicesKeyName, &tokenUserSid->sr); + PhDereferenceObject(tokenUserSid); + } + + PhFree(tokenUser); + } + + if (profileKeyPath) + { + HANDLE keyHandle; + + if (NT_SUCCESS(PhOpenKey( + &keyHandle, + KEY_READ, + PH_KEY_LOCAL_MACHINE, + &profileKeyPath->sr, + 0 + ))) + { + PPH_STRING profileImagePath; + + if (profileFolderPath = PhQueryRegistryString(keyHandle, L"ProfileImagePath")) + { + if (profileImagePath = PhExpandEnvironmentStrings(&profileFolderPath->sr)) + { + PhMoveReference(&profileFolderPath, profileImagePath); + } + } + + NtClose(keyHandle); + } + + PhDereferenceObject(profileKeyPath); + } + + //ULONG profileFolderLength; + //if (GetUserProfileDirectory) + //{ + // GetUserProfileDirectory(TokenHandle, NULL, &profileFolderLength); + // profileFolderPath = PhCreateStringEx(NULL, profileFolderLength * sizeof(WCHAR)); + // GetUserProfileDirectory(TokenHandle, profileFolderPath->Buffer, &profileFolderLength); + //} + + return profileFolderPath; +} + +PPH_STRING PhpGetTokenRegistryPath( + _In_ HANDLE TokenHandle + ) +{ + PPH_STRING profileRegistryPath = NULL; + PPH_STRING tokenUserSid = NULL; + PTOKEN_USER tokenUser; + + if (NT_SUCCESS(PhGetTokenUser(TokenHandle, &tokenUser))) + { + tokenUserSid = PhSidToStringSid(tokenUser->User.Sid); + PhFree(tokenUser); + } + + if (tokenUserSid) + { + HANDLE keyHandle; + + if (NT_SUCCESS(PhOpenKey( + &keyHandle, + KEY_READ, + PH_KEY_USERS, + &tokenUserSid->sr, + 0 + ))) + { + profileRegistryPath = PhConcatStrings2(L"HKU\\", tokenUserSid->Buffer); + NtClose(keyHandle); + } + + PhDereferenceObject(tokenUserSid); + } + + return profileRegistryPath; +} + PPH_STRING PhpGetTokenAppContainerFolderPath( _In_ PSID TokenAppContainerSid ) From bb672498b9399f074ce094c77ffb31725ad29501 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 19 Apr 2019 20:38:43 +0200 Subject: [PATCH 1813/2058] Update ACL editor with partial FileObject support --- phlib/include/seceditp.h | 52 +++++++++- phlib/secedit.c | 203 +++++++++++++++++++++++++++++++++++++-- 2 files changed, 244 insertions(+), 11 deletions(-) diff --git a/phlib/include/seceditp.h b/phlib/include/seceditp.h index 460a382b9b88..b03bd218e8cc 100644 --- a/phlib/include/seceditp.h +++ b/phlib/include/seceditp.h @@ -50,6 +50,31 @@ typedef struct PPH_LIST NameCache; } PhSecurityIDataObject; + +#undef INTERFACE +#define INTERFACE ISecurityObjectTypeInfoEx +DECLARE_INTERFACE_IID_(ISecurityObjectTypeInfoEx, IUnknown, "FC3066EB-79EF-444b-9111-D18A75EBF2FA") +{ + // *** IUnknown methods *** + STDMETHOD(QueryInterface) (THIS_ _In_ REFIID riid, _Outptr_ void** ppvObj) PURE; + STDMETHOD_(ULONG, AddRef) (THIS) PURE; + STDMETHOD_(ULONG, Release) (THIS) PURE; + + // *** ISecurityInformation methods *** + STDMETHOD(GetInheritSource)(THIS_ SECURITY_INFORMATION si, + PACL pACL, + PINHERITED_FROM * ppInheritArray) PURE; +}; +typedef ISecurityObjectTypeInfoEx* LPSecurityObjectTypeInfoEx; + +typedef struct +{ + ISecurityObjectTypeInfoExVtbl* VTable; + + PhSecurityInformation* Context; + ULONG RefCount; +} PhSecurityObjectTypeInfo; + // ISecurityInformation ISecurityInformation *PhSecurityInformation_Create( @@ -57,7 +82,7 @@ ISecurityInformation *PhSecurityInformation_Create( _In_ PWSTR ObjectName, _In_ PWSTR ObjectType, _In_ PPH_OPEN_OBJECT OpenObject, - _In_ PPH_CLOSE_OBJECT CloseObject, + _In_opt_ PPH_CLOSE_OBJECT CloseObject, _In_opt_ PVOID Context, _In_ BOOLEAN IsPage ); @@ -183,7 +208,7 @@ HRESULT STDMETHODCALLTYPE PhSecurityInformation3_OpenElevatedEditor( HRESULT STDMETHODCALLTYPE PhSecurityDataObject_QueryInterface( _In_ IDataObject *This, _In_ REFIID Riid, - _Out_ PVOID *Object + _COM_Outptr_ PVOID *Object ); ULONG STDMETHODCALLTYPE PhSecurityDataObject_AddRef( @@ -247,4 +272,27 @@ HRESULT STDMETHODCALLTYPE PhSecurityDataObject_EnumDAdvise( _Out_opt_ IEnumSTATDATA **ppenumAdvise ); +// ISecurityObjectTypeInfo + +HRESULT STDMETHODCALLTYPE PhSecurityObjectTypeInfo_QueryInterface( + _In_ ISecurityObjectTypeInfoEx* This, + _In_ REFIID Riid, + _Out_ PVOID* Object + ); + +ULONG STDMETHODCALLTYPE PhSecurityObjectTypeInfo_AddRef( + _In_ ISecurityObjectTypeInfoEx* This + ); + +ULONG STDMETHODCALLTYPE PhSecurityObjectTypeInfo_Release( + _In_ ISecurityObjectTypeInfoEx* This + ); + +HRESULT STDMETHODCALLTYPE PhSecurityObjectTypeInfo_GetInheritSource( + _In_ ISecurityObjectTypeInfoEx* This, + _In_ SECURITY_INFORMATION SecurityInfo, + _In_ PACL Acl, + _Out_ PINHERITED_FROM *InheritArray + ); + #endif diff --git a/phlib/secedit.c b/phlib/secedit.c index 077f4af2a6c3..e9c574bdca9c 100644 --- a/phlib/secedit.c +++ b/phlib/secedit.c @@ -79,6 +79,14 @@ static IDataObjectVtbl PhDataObject_VTable = PhSecurityDataObject_EnumDAdvise }; +static ISecurityObjectTypeInfoExVtbl PhSecurityObjectTypeInfo_VTable3 = +{ + PhSecurityObjectTypeInfo_QueryInterface, + PhSecurityObjectTypeInfo_AddRef, + PhSecurityObjectTypeInfo_Release, + PhSecurityObjectTypeInfo_GetInheritSource +}; + /** * Creates a security editor page. * @@ -168,7 +176,7 @@ ISecurityInformation *PhSecurityInformation_Create( _In_ PWSTR ObjectName, _In_ PWSTR ObjectType, _In_ PPH_OPEN_OBJECT OpenObject, - _In_ PPH_CLOSE_OBJECT CloseObject, + _In_opt_ PPH_CLOSE_OBJECT CloseObject, _In_opt_ PVOID Context, _In_ BOOLEAN IsPage ) @@ -201,6 +209,9 @@ ISecurityInformation *PhSecurityInformation_Create( info->AccessEntries[i].dwFlags |= SI_ACCESS_GENERAL; if (info->AccessEntriesArray[i].Specific) info->AccessEntries[i].dwFlags |= SI_ACCESS_SPECIFIC; + + if (PhEqualString2(info->ObjectType, L"FileObject", TRUE)) // TODO: Remove PhEqualString2 (dmex) + info->AccessEntries[i].dwFlags |= OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE; } } @@ -254,6 +265,21 @@ HRESULT STDMETHODCALLTYPE PhSecurityInformation_QueryInterface( return S_OK; } } + else if (IsEqualGUID(Riid, &IID_ISecurityObjectTypeInfo)) + { + if (WindowsVersion >= WINDOWS_8) + { + PhSecurityObjectTypeInfo* info; + + info = PhAllocateZero(sizeof(PhSecurityObjectTypeInfo)); + info->VTable = &PhSecurityObjectTypeInfo_VTable3; + info->Context = this; + info->RefCount = 1; + + *Object = info; + return S_OK; + } + } *Object = NULL; return E_NOINTERFACE; @@ -311,6 +337,11 @@ HRESULT STDMETHODCALLTYPE PhSecurityInformation_GetObjectInformation( ObjectInfo->dwFlags = SI_EDIT_ALL | SI_ADVANCED | (WindowsVersion >= WINDOWS_8 ? SI_VIEW_ONLY : 0); ObjectInfo->pszObjectName = PhGetString(this->ObjectName); + if (PhEqualString2(this->ObjectType, L"FileObject", TRUE)) + { + ObjectInfo->dwFlags |= SI_ENABLE_EDIT_ATTRIBUTE_CONDITION | SI_MAY_WRITE; // SI_RESET | SI_READONLY + //if (Folder) ObjectInfo->dwFlags |= SI_CONTAINER; + } if (PhEqualString2(this->ObjectType, L"TokenDefault", TRUE)) { ObjectInfo->dwFlags &= ~(SI_EDIT_OWNER | SI_EDIT_AUDITS); @@ -332,14 +363,34 @@ HRESULT STDMETHODCALLTYPE PhSecurityInformation_GetSecurity( ULONG sdLength; PSECURITY_DESCRIPTOR newSd; - status = PhStdGetObjectSecurity( - &securityDescriptor, - RequestedInformation, - this - ); + //if (Default) + //{ + // securityDescriptor = PhAllocateZero(SECURITY_DESCRIPTOR_MIN_LENGTH); + // + // status = RtlCreateSecurityDescriptor( + // securityDescriptor, + // SECURITY_DESCRIPTOR_REVISION + // ); + // + // if (!NT_SUCCESS(status)) + // return HRESULT_FROM_WIN32(PhNtStatusToDosError(status)); + // + // status = RtlSetDaclSecurityDescriptor(securityDescriptor, TRUE, NULL, FALSE); + // + // if (!NT_SUCCESS(status)) + // return HRESULT_FROM_WIN32(PhNtStatusToDosError(status)); + //} + //else + { + status = PhStdGetObjectSecurity( + &securityDescriptor, + RequestedInformation, + this + ); - if (!NT_SUCCESS(status)) - return HRESULT_FROM_WIN32(PhNtStatusToDosError(status)); + if (!NT_SUCCESS(status)) + return HRESULT_FROM_WIN32(PhNtStatusToDosError(status)); + } sdLength = RtlLengthSecurityDescriptor(securityDescriptor); newSd = LocalAlloc(0, sdLength); @@ -783,6 +834,100 @@ HRESULT STDMETHODCALLTYPE PhSecurityDataObject_EnumDAdvise( return E_NOTIMPL; } +// ISecurityObjectTypeInfo + +HRESULT STDMETHODCALLTYPE PhSecurityObjectTypeInfo_QueryInterface( + _In_ ISecurityObjectTypeInfoEx* This, + _In_ REFIID Riid, + _Out_ PVOID* Object + ) +{ + if ( + IsEqualIID(Riid, &IID_IUnknown) || + IsEqualIID(Riid, &IID_ISecurityObjectTypeInfo) + ) + { + PhSecurityObjectTypeInfo_AddRef(This); + *Object = This; + return S_OK; + } + + *Object = NULL; + return E_NOINTERFACE; +} + +ULONG STDMETHODCALLTYPE PhSecurityObjectTypeInfo_AddRef( + _In_ ISecurityObjectTypeInfoEx* This + ) +{ + PhSecurityObjectTypeInfo* this = (PhSecurityObjectTypeInfo*)This; + + this->RefCount++; + + return this->RefCount; +} + +ULONG STDMETHODCALLTYPE PhSecurityObjectTypeInfo_Release( + _In_ ISecurityObjectTypeInfoEx* This + ) +{ + PhSecurityObjectTypeInfo* this = (PhSecurityObjectTypeInfo*)This; + + this->RefCount--; + + if (this->RefCount == 0) + { + PhFree(this); + return 0; + } + + return this->RefCount; +} + +HRESULT STDMETHODCALLTYPE PhSecurityObjectTypeInfo_GetInheritSource( + _In_ ISecurityObjectTypeInfoEx* This, + _In_ SECURITY_INFORMATION SecurityInfo, + _In_ PACL Acl, + _Out_ PINHERITED_FROM* InheritArray + ) +{ + static GENERIC_MAPPING genericMappings = + { + FILE_GENERIC_READ, + FILE_GENERIC_WRITE, + FILE_GENERIC_EXECUTE, + FILE_ALL_ACCESS + }; + + PhSecurityObjectTypeInfo* this = (PhSecurityObjectTypeInfo*)This; + PINHERITED_FROM result; + ULONG status; + + result = (PINHERITED_FROM)LocalAlloc(LPTR, ((ULONGLONG)Acl->AceCount + 1) * sizeof(INHERITED_FROM)); + + if ((status = GetInheritanceSource( + PhGetString(this->Context->ObjectName), + SE_FILE_OBJECT, + SecurityInfo, + TRUE, // Container + NULL, + 0, + Acl, + NULL, + &genericMappings, + result + )) == ERROR_SUCCESS) + { + *InheritArray = result; + } + else + { + LocalFree(result); + } + + return HRESULT_FROM_WIN32(status); +} + NTSTATUS PhpGetObjectSecurityWithTimeout( _In_ HANDLE Handle, _In_ SECURITY_INFORMATION SecurityInformation, @@ -873,6 +1018,11 @@ _Callback_ NTSTATUS PhStdGetObjectSecurity( status = PhpGetObjectSecurityWithTimeout(handle, SecurityInformation, SecurityDescriptor); NtClose(handle); } + else if (PhEqualString2(this->ObjectType, L"FileObject", TRUE)) + { + status = PhGetSeObjectSecurity(handle, SE_FILE_OBJECT, SecurityInformation, SecurityDescriptor); + NtClose(handle); + } else if ( PhEqualString2(this->ObjectType, L"LsaAccount", TRUE) || PhEqualString2(this->ObjectType, L"LsaPolicy", TRUE) || @@ -1008,6 +1158,16 @@ _Callback_ NTSTATUS PhStdSetObjectSecurity( status = PhSetSeObjectSecurity(handle, SE_SERVICE, SecurityInformation, SecurityDescriptor); CloseServiceHandle(handle); } + else if (PhEqualString2(this->ObjectType, L"File", TRUE)) + { + status = PhSetObjectSecurity(handle, SecurityInformation, SecurityDescriptor); + NtClose(handle); + } + else if (PhEqualString2(this->ObjectType, L"FileObject", TRUE)) + { + status = PhSetSeObjectSecurity(handle, SE_FILE_OBJECT, SecurityInformation, SecurityDescriptor); + NtClose(handle); + } else if ( PhEqualString2(this->ObjectType, L"LsaAccount", TRUE) || PhEqualString2(this->ObjectType, L"LsaPolicy", TRUE) || @@ -1151,10 +1311,35 @@ NTSTATUS PhSetSeObjectSecurity( securityInformation |= SACL_SECURITY_INFORMATION; } + if (ObjectType == SE_FILE_OBJECT) // probably works with other types but haven't checked (dmex) + { + SECURITY_DESCRIPTOR_CONTROL control; + ULONG revision; + + if (NT_SUCCESS(RtlGetControlSecurityDescriptor(SecurityDescriptor, &control, &revision))) + { + if (SecurityInformation & DACL_SECURITY_INFORMATION) + { + if (control & SE_DACL_PROTECTED) + securityInformation |= PROTECTED_DACL_SECURITY_INFORMATION; + else + securityInformation |= UNPROTECTED_DACL_SECURITY_INFORMATION; + } + + if (SecurityInformation & SACL_SECURITY_INFORMATION) + { + if (control & SE_SACL_PROTECTED) + securityInformation |= PROTECTED_SACL_SECURITY_INFORMATION; + else + securityInformation |= UNPROTECTED_SACL_SECURITY_INFORMATION; + } + } + } + win32Result = SetSecurityInfo( Handle, ObjectType, - SecurityInformation, + securityInformation, // SecurityInformation owner, group, dacl, From b51cf5328c9775b66f97d04377080d7239f64624 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 19 Apr 2019 20:38:59 +0200 Subject: [PATCH 1814/2058] Add LdrStandardizeSystemPath --- phnt/include/ntldr.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/phnt/include/ntldr.h b/phnt/include/ntldr.h index 2996960c7cd3..92a3b49c324f 100644 --- a/phnt/include/ntldr.h +++ b/phnt/include/ntldr.h @@ -557,6 +557,14 @@ LdrUnregisterDllNotification( // end_msdn +// rev +NTSYSAPI +PUNICODE_STRING +NTAPI +LdrStandardizeSystemPath( + _In_ PUNICODE_STRING SystemPath + ); + // private typedef struct _PS_MITIGATION_OPTIONS_MAP { From 3d4a9b073eda50cc230aec16be8cfde2c634cf31 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 19 Apr 2019 20:42:02 +0200 Subject: [PATCH 1815/2058] peview: Add security button, Add PE import table hash after checksum --- tools/peview/main.c | 10 +-- tools/peview/peprp.c | 185 ++++++++++++++++++++++++++++++++++++---- tools/peview/settings.c | 3 +- 3 files changed, 174 insertions(+), 24 deletions(-) diff --git a/tools/peview/main.c b/tools/peview/main.c index 21d062c724b0..8df47a4e7422 100644 --- a/tools/peview/main.c +++ b/tools/peview/main.c @@ -3,6 +3,7 @@ * PE viewer * * Copyright (C) 2010 wj32 + * Copyright (C) 2017-2019 dmex * * This file is part of Process Hacker. * @@ -21,11 +22,10 @@ */ #include -#include PPH_STRING PvFileName = NULL; -static BOOLEAN NTAPI PvCommandLineCallback( +BOOLEAN NTAPI PvpCommandLineCallback( _In_opt_ PPH_COMMAND_LINE_OPTION Option, _In_opt_ PPH_STRING Value, _In_opt_ PVOID Context @@ -112,9 +112,9 @@ INT WINAPI wWinMain( PhParseCommandLine( &commandLine->sr, options, - sizeof(options) / sizeof(PH_COMMAND_LINE_OPTION), + RTL_NUMBER_OF(options), PH_COMMAND_LINE_IGNORE_FIRST_PART, - PvCommandLineCallback, + PvpCommandLineCallback, NULL ); PhDereferenceObject(commandLine); @@ -128,8 +128,6 @@ INT WINAPI wWinMain( }; PVOID fileDialog; - CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE); - fileDialog = PhCreateOpenFileDialog(); PhSetFileDialogOptions(fileDialog, PH_FILEDIALOG_NOPATHVALIDATE); PhSetFileDialogFilter(fileDialog, filters, RTL_NUMBER_OF(filters)); diff --git a/tools/peview/peprp.c b/tools/peview/peprp.c index 4203cfa7fc18..7c70a39ebd66 100644 --- a/tools/peview/peprp.c +++ b/tools/peview/peprp.c @@ -28,6 +28,8 @@ #include #include +#include + #define PVM_CHECKSUM_DONE (WM_APP + 1) #define PVM_VERIFY_DONE (WM_APP + 2) @@ -50,6 +52,8 @@ HICON PvImageLargeIcon = NULL; PH_IMAGE_VERSION_INFO PvImageVersionInfo; static VERIFY_RESULT PvImageVerifyResult; static PPH_STRING PvImageSignerName; +static HWND ResetButton; +static WNDPROC OldWndProc; VOID PvPeProperties( VOID @@ -273,17 +277,36 @@ static NTSTATUS CheckSumImageThreadStart( _In_ PVOID Parameter ) { - HWND windowHandle; + HWND windowHandle = Parameter; + PPH_STRING importHash = NULL; ULONG checkSum; + HANDLE fileHandle; - windowHandle = Parameter; checkSum = PhCheckSumMappedImage(&PvMappedImage); + if (NT_SUCCESS(PhCreateFileWin32( + &fileHandle, + PhGetString(PvFileName), + FILE_READ_ACCESS, + FILE_ATTRIBUTE_NORMAL, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + FILE_OPEN, + 0 + ))) + { + BYTE importTableShaHash[16]; + + if (NT_SUCCESS(RtlComputeImportTableHash(fileHandle, importTableShaHash, 1))) + { + importHash = PhBufferToHexString(importTableShaHash, 16); + } + } + PostMessage( windowHandle, PVM_CHECKSUM_DONE, checkSum, - 0 + (LPARAM)importHash ); return STATUS_SUCCESS; @@ -533,7 +556,7 @@ VOID PvpSetPeImageEntryPoint( if (PvMappedImage.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) string = PhFormatString(L"0x%I32x", ((PIMAGE_OPTIONAL_HEADER32)&PvMappedImage.NtHeaders->OptionalHeader)->AddressOfEntryPoint); else - string = PhFormatString(L"0x%I64x", ((PIMAGE_OPTIONAL_HEADER64)&PvMappedImage.NtHeaders->OptionalHeader)->AddressOfEntryPoint); + string = PhFormatString(L"0x%I32x", ((PIMAGE_OPTIONAL_HEADER64)&PvMappedImage.NtHeaders->OptionalHeader)->AddressOfEntryPoint); PhSetDialogItemText(WindowHandle, IDC_ENTRYPOINT, string->Buffer); PhDereferenceObject(string); @@ -701,6 +724,128 @@ VOID PvpSetPeImageSections( } } +NTSTATUS PhpOpenFileSecurity( + _Out_ PHANDLE Handle, + _In_ ACCESS_MASK DesiredAccess, + _In_opt_ PVOID Context + ) +{ + NTSTATUS status; + FILE_NETWORK_OPEN_INFORMATION networkOpenInfo; + + status = PhQueryFullAttributesFileWin32(PhGetString(PvFileName), &networkOpenInfo); + + if (!NT_SUCCESS(status)) + return status; + + if (networkOpenInfo.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) + { + status = PhCreateFileWin32( + Handle, + PhGetString(PvFileName), + DesiredAccess| READ_CONTROL | WRITE_DAC, + FILE_ATTRIBUTE_DIRECTORY, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + FILE_OPEN, + 0 + ); + } + else + { + status = PhCreateFileWin32( + Handle, + PhGetString(PvFileName), + DesiredAccess | READ_CONTROL | WRITE_DAC, + FILE_ATTRIBUTE_NORMAL, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + FILE_OPEN, + 0 + ); + + if (!NT_SUCCESS(status)) + { + status = PhCreateFileWin32( + Handle, + PhGetString(PvFileName), + DesiredAccess | READ_CONTROL, + FILE_ATTRIBUTE_NORMAL, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + FILE_OPEN, + 0 + ); + } + } + + return status; +} + +LRESULT CALLBACK PhpOptionsWndProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + switch (uMsg) + { + case WM_COMMAND: + { + if (GET_WM_COMMAND_HWND(wParam, lParam) == ResetButton) + { + PhEditSecurity( + hwndDlg, + PhGetString(PvFileName), + L"FileObject", + PhpOpenFileSecurity, + NULL, + NULL + ); + } + } + break; + } + + return CallWindowProc(OldWndProc, hwndDlg, uMsg, wParam, lParam); +} + +static HWND PvpCreateSecurityButton( + _In_ HWND hwndDlg + ) +{ + if (!ResetButton) + { + HWND optionsWindow; + RECT clientRect; + RECT rect; + + optionsWindow = GetParent(hwndDlg); + OldWndProc = (WNDPROC)GetWindowLongPtr(optionsWindow, GWLP_WNDPROC); + SetWindowLongPtr(optionsWindow, GWLP_WNDPROC, (LONG_PTR)PhpOptionsWndProc); + + // Create the Reset button. + GetClientRect(optionsWindow, &clientRect); + GetWindowRect(GetDlgItem(optionsWindow, IDCANCEL), &rect); + MapWindowPoints(NULL, optionsWindow, (POINT*)&rect, 2); + ResetButton = CreateWindowEx( + WS_EX_NOPARENTNOTIFY, + WC_BUTTON, + L"Security", + WS_CHILD | WS_VISIBLE | WS_TABSTOP, + clientRect.right - rect.right, + rect.top, + rect.right - rect.left, + rect.bottom - rect.top, + optionsWindow, + NULL, + PhInstanceHandle, + NULL + ); + SendMessage(ResetButton, WM_SETFONT, SendMessage(GetDlgItem(optionsWindow, IDCANCEL), WM_GETFONT, 0, 0), TRUE); + } + + return ResetButton; +} + INT_PTR CALLBACK PvpPeGeneralDlgProc( _In_ HWND hwndDlg, _In_ UINT uMsg, @@ -720,6 +865,16 @@ INT_PTR CALLBACK PvpPeGeneralDlgProc( { HWND lvHandle; + lvHandle = GetDlgItem(hwndDlg, IDC_LIST); + PhSetListViewStyle(lvHandle, TRUE, TRUE); + PhSetControlTheme(lvHandle, L"explorer"); + PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 80, L"Name"); + PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 80, L"VA"); + PhAddListViewColumn(lvHandle, 2, 2, 2, LVCFMT_LEFT, 80, L"Size"); + PhAddListViewColumn(lvHandle, 3, 3, 3, LVCFMT_LEFT, 250, L"Characteristics"); + //PhAddListViewColumn(lvHandle, 4, 4, 4, LVCFMT_LEFT, 80, L"Hash"); + PhLoadListViewColumnsFromSetting(L"ImageGeneralListViewColumns", lvHandle); + // File version information PvpSetPeImageVersionInfo(hwndDlg); @@ -732,16 +887,6 @@ INT_PTR CALLBACK PvpPeGeneralDlgProc( PvpSetPeImageSubsystem(hwndDlg); PvpSetPeImageCharacteristics(hwndDlg); - lvHandle = GetDlgItem(hwndDlg, IDC_LIST); - PhSetListViewStyle(lvHandle, TRUE, TRUE); - PhSetControlTheme(lvHandle, L"explorer"); - PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 80, L"Name"); - PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 80, L"VA"); - PhAddListViewColumn(lvHandle, 2, 2, 2, LVCFMT_LEFT, 80, L"Size"); - PhAddListViewColumn(lvHandle, 3, 3, 3, LVCFMT_LEFT, 250, L"Characteristics"); - //PhAddListViewColumn(lvHandle, 4, 4, 4, LVCFMT_LEFT, 80, L"Hash"); - PhLoadListViewColumnsFromSetting(L"ImageGeneralListViewColumns", lvHandle); - PvpSetPeImageSections(lvHandle); } break; @@ -762,6 +907,8 @@ INT_PTR CALLBACK PvpPeGeneralDlgProc( PvAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_CHARACTERISTICS), dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); PvAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_LIST), dialogItem, PH_ANCHOR_ALL); + PvAddPropPageLayoutItem(hwndDlg, PvpCreateSecurityButton(hwndDlg), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_BOTTOM); + PvDoPropPageLayout(hwndDlg); propPageContext->LayoutInitialized = TRUE; @@ -771,31 +918,35 @@ INT_PTR CALLBACK PvpPeGeneralDlgProc( case PVM_CHECKSUM_DONE: { PPH_STRING string; + PPH_STRING importTableHash; ULONG headerCheckSum; ULONG realCheckSum; headerCheckSum = PvMappedImage.NtHeaders->OptionalHeader.CheckSum; // same for 32-bit and 64-bit images realCheckSum = (ULONG)wParam; + importTableHash = (PPH_STRING)lParam; if (headerCheckSum == 0) { // Some executables, like .NET ones, don't have a check sum. - string = PhFormatString(L"0x0 (real 0x%Ix)", realCheckSum); + string = PhFormatString(L"0x0 (real 0x%Ix) (%s)", realCheckSum, PhGetStringOrDefault(importTableHash, L"N/A")); PhSetDialogItemText(hwndDlg, IDC_CHECKSUM, string->Buffer); PhDereferenceObject(string); } else if (headerCheckSum == realCheckSum) { - string = PhFormatString(L"0x%Ix (correct)", headerCheckSum); + string = PhFormatString(L"0x%Ix (correct) (%s)", headerCheckSum, PhGetStringOrDefault(importTableHash, L"N/A")); PhSetDialogItemText(hwndDlg, IDC_CHECKSUM, string->Buffer); PhDereferenceObject(string); } else { - string = PhFormatString(L"0x%Ix (incorrect, real 0x%Ix)", headerCheckSum, realCheckSum); + string = PhFormatString(L"0x%Ix (incorrect, real 0x%Ix) (%s)", headerCheckSum, realCheckSum, PhGetStringOrDefault(importTableHash, L"N/A")); PhSetDialogItemText(hwndDlg, IDC_CHECKSUM, string->Buffer); PhDereferenceObject(string); } + + PhClearReference(&importTableHash); } break; case PVM_VERIFY_DONE: diff --git a/tools/peview/settings.c b/tools/peview/settings.c index 0fc7cfeaa24e..8facea27bce3 100644 --- a/tools/peview/settings.c +++ b/tools/peview/settings.c @@ -31,8 +31,9 @@ VOID PhAddDefaultSettings( { PhpAddIntegerSetting(L"FirstRun", L"1"); PhpAddStringSetting(L"Font", L""); // null + PhpAddIntegerSetting(L"EnableSecurityAdvancedDialog", L"1"); PhpAddIntegerSetting(L"EnableThemeSupport", L"0"); - PhpAddIntegerSetting(L"GraphColorMode", L"0"); + PhpAddIntegerSetting(L"GraphColorMode", L"1"); PhpAddIntegerSetting(L"HashAlgorithm", L"0"); PhpAddIntegerSetting(L"MaxSizeUnit", L"6"); PhpAddStringSetting(L"MainWindowPage", L"General"); From 2b3afd4c59d982cdb7de52f8824bacadafc4b581 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 19 Apr 2019 20:44:25 +0200 Subject: [PATCH 1816/2058] peview: Add missing file from previous commit --- tools/peview/peprp.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/peview/peprp.c b/tools/peview/peprp.c index 7c70a39ebd66..bf80b373145d 100644 --- a/tools/peview/peprp.c +++ b/tools/peview/peprp.c @@ -300,6 +300,8 @@ static NTSTATUS CheckSumImageThreadStart( { importHash = PhBufferToHexString(importTableShaHash, 16); } + + NtClose(fileHandle); } PostMessage( From 644ed35575099ac8e3e3fd30b10377b95d55606f Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 19 Apr 2019 20:48:10 +0200 Subject: [PATCH 1817/2058] peview: Update dependencies, Update DelayLoadDLLs --- tools/peview/peview.vcxproj | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tools/peview/peview.vcxproj b/tools/peview/peview.vcxproj index e722e8408f3a..54eff02b040f 100644 --- a/tools/peview/peview.vcxproj +++ b/tools/peview/peview.vcxproj @@ -99,7 +99,7 @@ true - noarg.obj;noenv.obj;propsys.lib;phlib.lib;ntdll.lib;uxtheme.lib;userenv.lib;windowscodecs.lib;winsta.lib;%(AdditionalDependencies) + aclui.lib;propsys.lib;phlib.lib;ntdll.lib;uxtheme.lib;userenv.lib;windowscodecs.lib;winsta.lib;noarg.obj;noenv.obj;%(AdditionalDependencies) ..\..\phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) @@ -107,7 +107,7 @@ Windows MachineX86 6.01 - advapi32.dll;comctl32.dll;comdlg32.dll;gdi32.dll;ole32.dll;propsys.dll;shell32.dll;user32.dll;userenv.dll;uxtheme.dll;version.dll;winsta.dll;%(DelayLoadDLLs) + aclui.dll;advapi32.dll;comctl32.dll;comdlg32.dll;gdi32.dll;ole32.dll;propsys.dll;shell32.dll;user32.dll;userenv.dll;uxtheme.dll;version.dll;winsta.dll;%(DelayLoadDLLs) ..\..\phnt\include;..\..\phlib\include;include;%(AdditionalIncludeDirectories) @@ -130,7 +130,7 @@ true - noarg.obj;noenv.obj;propsys.lib;phlib.lib;ntdll.lib;uxtheme.lib;userenv.lib;windowscodecs.lib;winsta.lib;%(AdditionalDependencies) + aclui.lib;propsys.lib;phlib.lib;ntdll.lib;uxtheme.lib;userenv.lib;windowscodecs.lib;winsta.lib;noarg.obj;noenv.obj;%(AdditionalDependencies) ..\..\phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) @@ -138,7 +138,7 @@ Windows MachineX64 6.01 - advapi32.dll;comctl32.dll;comdlg32.dll;gdi32.dll;ole32.dll;propsys.dll;shell32.dll;user32.dll;userenv.dll;uxtheme.dll;version.dll;winsta.dll;%(DelayLoadDLLs) + aclui.dll;advapi32.dll;comctl32.dll;comdlg32.dll;gdi32.dll;ole32.dll;propsys.dll;shell32.dll;user32.dll;userenv.dll;uxtheme.dll;version.dll;winsta.dll;%(DelayLoadDLLs) ..\..\phnt\include;..\..\phlib\include;include;%(AdditionalIncludeDirectories) @@ -164,7 +164,7 @@ Guard - noarg.obj;noenv.obj;propsys.lib;phlib.lib;ntdll.lib;uxtheme.lib;userenv.lib;windowscodecs.lib;winsta.lib;%(AdditionalDependencies) + aclui.lib;propsys.lib;phlib.lib;ntdll.lib;uxtheme.lib;userenv.lib;windowscodecs.lib;winsta.lib;noarg.obj;noenv.obj;%(AdditionalDependencies) ..\..\phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) @@ -175,7 +175,7 @@ MachineX86 true 6.01 - advapi32.dll;comctl32.dll;comdlg32.dll;gdi32.dll;ole32.dll;propsys.dll;shell32.dll;user32.dll;userenv.dll;uxtheme.dll;version.dll;winsta.dll;%(DelayLoadDLLs) + aclui.dll;advapi32.dll;comctl32.dll;comdlg32.dll;gdi32.dll;ole32.dll;propsys.dll;shell32.dll;user32.dll;userenv.dll;uxtheme.dll;version.dll;winsta.dll;%(DelayLoadDLLs) ..\..\phnt\include;..\..\phlib\include;include;%(AdditionalIncludeDirectories) @@ -200,7 +200,7 @@ Guard - noarg.obj;noenv.obj;propsys.lib;phlib.lib;ntdll.lib;uxtheme.lib;userenv.lib;windowscodecs.lib;winsta.lib;%(AdditionalDependencies) + aclui.lib;propsys.lib;phlib.lib;ntdll.lib;uxtheme.lib;userenv.lib;windowscodecs.lib;winsta.lib;noarg.obj;noenv.obj;%(AdditionalDependencies) ..\..\phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) @@ -211,7 +211,7 @@ MachineX64 true 6.01 - advapi32.dll;comctl32.dll;comdlg32.dll;gdi32.dll;ole32.dll;propsys.dll;shell32.dll;user32.dll;userenv.dll;uxtheme.dll;version.dll;winsta.dll;%(DelayLoadDLLs) + aclui.dll;advapi32.dll;comctl32.dll;comdlg32.dll;gdi32.dll;ole32.dll;propsys.dll;shell32.dll;user32.dll;userenv.dll;uxtheme.dll;version.dll;winsta.dll;%(DelayLoadDLLs) ..\..\phnt\include;..\..\phlib\include;include;%(AdditionalIncludeDirectories) From cb1b18fe8524f46adff0f08fc311182a4404eea2 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 19 Apr 2019 20:58:57 +0200 Subject: [PATCH 1818/2058] Add missing FileObject access entry type --- phlib/secdata.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/phlib/secdata.c b/phlib/secdata.c index 42d6d3966593..c5f109a0ef0d 100644 --- a/phlib/secdata.c +++ b/phlib/secdata.c @@ -672,6 +672,10 @@ BOOLEAN PhGetAccessEntries( { Type = L"Thread60"; } + else if (PhEqualStringZ(Type, L"FileObject", TRUE)) + { + Type = L"File"; + } // Find the specific type. for (i = 0; i < sizeof(PhSpecificTypes) / sizeof(PH_SPECIFIC_TYPE); i++) From 97afc27c6b1cdea3c1511b122c88e9341cd45a77 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 19 Apr 2019 21:15:14 +0200 Subject: [PATCH 1819/2058] Add ACL editor generic mapping / inheritance support --- phlib/secedit.c | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/phlib/secedit.c b/phlib/secedit.c index e9c574bdca9c..387b35b9c240 100644 --- a/phlib/secedit.c +++ b/phlib/secedit.c @@ -448,6 +448,16 @@ HRESULT STDMETHODCALLTYPE PhSecurityInformation_MapGeneric( _Inout_ PACCESS_MASK Mask ) { + static GENERIC_MAPPING genericMappings = + { + FILE_GENERIC_READ, + FILE_GENERIC_WRITE, + FILE_GENERIC_EXECUTE, + FILE_ALL_ACCESS + }; + + RtlMapGenericMask(Mask, &genericMappings); + return S_OK; } @@ -457,7 +467,21 @@ HRESULT STDMETHODCALLTYPE PhSecurityInformation_GetInheritTypes( _Out_ PULONG InheritTypesCount ) { - return E_NOTIMPL; + static SI_INHERIT_TYPE inheritTypes[] = + { + 0, 0, L"This folder only", + 0, CONTAINER_INHERIT_ACE, L"This folder, subfolders and files", + 0, INHERIT_ONLY_ACE | CONTAINER_INHERIT_ACE, L"Subfolders and files only", + }; + + PhSecurityInformation* this = (PhSecurityInformation*)This; + + // if (Folder-Container) + *InheritTypes = inheritTypes; + *InheritTypesCount = RTL_NUMBER_OF(inheritTypes); + return S_OK; + // else + //return E_NOTIMPL; } HRESULT STDMETHODCALLTYPE PhSecurityInformation_PropertySheetPageCallback( From b3bf840e94a32753eda7e06d4b7b8be0887ca556 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 19 Apr 2019 21:54:38 +0200 Subject: [PATCH 1820/2058] peview: Fix regression on Win7 --- tools/peview/settings.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/peview/settings.c b/tools/peview/settings.c index 8facea27bce3..1da2be85eebf 100644 --- a/tools/peview/settings.c +++ b/tools/peview/settings.c @@ -54,6 +54,8 @@ VOID PhAddDefaultSettings( PhpAddStringSetting(L"LibListViewColumns", L""); PhpAddStringSetting(L"PdbTreeListColumns", L""); + PhpAddIntegerSetting(L"TreeListBorderEnable", L"0"); + // Wsl properties PhpAddStringSetting(L"GeneralWslTreeListColumns", L""); PhpAddStringSetting(L"DynamicWslListViewColumns", L""); From c4b62e9f2adc1817a31904a4195b13473a5ddfa5 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 20 Apr 2019 00:10:45 +0200 Subject: [PATCH 1821/2058] peview: Add section header hashes --- tools/peview/peprp.c | 42 ++++++++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/tools/peview/peprp.c b/tools/peview/peprp.c index bf80b373145d..eade518e72f3 100644 --- a/tools/peview/peprp.c +++ b/tools/peview/peprp.c @@ -294,11 +294,11 @@ static NTSTATUS CheckSumImageThreadStart( 0 ))) { - BYTE importTableShaHash[16]; + BYTE importTableMd5Hash[16]; - if (NT_SUCCESS(RtlComputeImportTableHash(fileHandle, importTableShaHash, 1))) + if (NT_SUCCESS(RtlComputeImportTableHash(fileHandle, importTableMd5Hash, 1))) { - importHash = PhBufferToHexString(importTableShaHash, 16); + importHash = PhBufferToHexString(importTableMd5Hash, 16); } NtClose(fileHandle); @@ -708,20 +708,26 @@ VOID PvpSetPeImageSections( PhSetListViewSubItem(ListViewHandle, lvItemIndex, 2, PhaFormatSize(PvMappedImage.Sections[i].SizeOfRawData, -1)->Buffer); PhSetListViewSubItem(ListViewHandle, lvItemIndex, 3, PH_AUTO_T(PH_STRING, PvpGetSectionCharacteristics(PvMappedImage.Sections[i].Characteristics))->Buffer); - //if (PvMappedImage.Sections[i].PointerToRawData && PvMappedImage.Sections[i].SizeOfRawData) - //{ - // PH_HASH_CONTEXT hashContext; - // PPH_STRING hashString; - // UCHAR hash[32]; - // - // PhInitializeHash(&hashContext, PhGetIntegerSetting(L"HashAlgorithm")); - // PhUpdateHash(&hashContext, PTR_ADD_OFFSET(PvMappedImage.ViewBase, PvMappedImage.Sections[i].PointerToRawData), PvMappedImage.Sections[i].SizeOfRawData); - // PhFinalHash(&hashContext, hash, 16, NULL); - // - // hashString = PhBufferToHexString(hash, 16); - // PhSetListViewSubItem(ListViewHandle, lvItemIndex, 4, hashString->Buffer); - // PhDereferenceObject(hashString); - //} + if (PvMappedImage.Sections[i].VirtualAddress && PvMappedImage.Sections[i].SizeOfRawData) + { + PVOID imageSectionData; + PH_HASH_CONTEXT hashContext; + PPH_STRING hashString; + UCHAR hash[32]; + + if (imageSectionData = PhMappedImageRvaToVa(&PvMappedImage, PvMappedImage.Sections[i].VirtualAddress, NULL)) + { + PhInitializeHash(&hashContext, Md5HashAlgorithm); // PhGetIntegerSetting(L"HashAlgorithm") + PhUpdateHash(&hashContext, imageSectionData, PvMappedImage.Sections[i].SizeOfRawData); + + if (PhFinalHash(&hashContext, hash, 16, NULL)) + { + hashString = PhBufferToHexString(hash, 16); + PhSetListViewSubItem(ListViewHandle, lvItemIndex, 4, hashString->Buffer); + PhDereferenceObject(hashString); + } + } + } } } } @@ -874,7 +880,7 @@ INT_PTR CALLBACK PvpPeGeneralDlgProc( PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 80, L"VA"); PhAddListViewColumn(lvHandle, 2, 2, 2, LVCFMT_LEFT, 80, L"Size"); PhAddListViewColumn(lvHandle, 3, 3, 3, LVCFMT_LEFT, 250, L"Characteristics"); - //PhAddListViewColumn(lvHandle, 4, 4, 4, LVCFMT_LEFT, 80, L"Hash"); + PhAddListViewColumn(lvHandle, 4, 4, 4, LVCFMT_LEFT, 80, L"Hash"); PhLoadListViewColumnsFromSetting(L"ImageGeneralListViewColumns", lvHandle); // File version information From e09d4a8c527c161725bc7cef7980846c81939d31 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 20 Apr 2019 00:47:46 +0200 Subject: [PATCH 1822/2058] Fix SAL annotation warnings --- ProcessHacker/hndlprp.c | 2 +- phlib/basesup.c | 9 ++++++--- phlib/include/seceditp.h | 2 +- phlib/native.c | 2 +- phlib/secedit.c | 2 +- tools/peview/resprp.c | 2 +- 6 files changed, 11 insertions(+), 8 deletions(-) diff --git a/ProcessHacker/hndlprp.c b/ProcessHacker/hndlprp.c index fd598872a369..83e2f5ff1666 100644 --- a/ProcessHacker/hndlprp.c +++ b/ProcessHacker/hndlprp.c @@ -511,7 +511,7 @@ VOID PhpUpdateHandleGeneral( PPH_ACCESS_ENTRY accessEntries; ULONG numberOfAccessEntries; OBJECT_BASIC_INFORMATION basicInfo; - WCHAR string[PH_PTR_STR_LEN]; + WCHAR string[PH_INT64_STR_LEN_1]; PhSetListViewSubItem(Context->ListViewHandle, Context->ListViewRowCache[PH_HANDLE_GENERAL_INDEX_NAME], 1, PhGetStringOrEmpty(Context->HandleItem->BestObjectName)); PhSetListViewSubItem(Context->ListViewHandle, Context->ListViewRowCache[PH_HANDLE_GENERAL_INDEX_TYPE], 1, PhGetStringOrEmpty(Context->HandleItem->TypeName)); diff --git a/phlib/basesup.c b/phlib/basesup.c index 4b3fed830c81..39b22f1e0e85 100644 --- a/phlib/basesup.c +++ b/phlib/basesup.c @@ -5905,9 +5905,10 @@ VOID PhPrintTimeSpan( switch (Mode) { case PH_TIMESPAN_HMSM: - _snwprintf( + _snwprintf_s( Destination, PH_TIMESPAN_STR_LEN, + _TRUNCATE, L"%02I64u:%02I64u:%02I64u.%03I64u", PH_TICKS_PARTIAL_HOURS(Ticks), PH_TICKS_PARTIAL_MIN(Ticks), @@ -5916,9 +5917,10 @@ VOID PhPrintTimeSpan( ); break; case PH_TIMESPAN_DHMS: - _snwprintf( + _snwprintf_s( Destination, PH_TIMESPAN_STR_LEN, + _TRUNCATE, L"%I64u:%02I64u:%02I64u:%02I64u", PH_TICKS_PARTIAL_DAYS(Ticks), PH_TICKS_PARTIAL_HOURS(Ticks), @@ -5927,9 +5929,10 @@ VOID PhPrintTimeSpan( ); break; default: - _snwprintf( + _snwprintf_s( Destination, PH_TIMESPAN_STR_LEN, + _TRUNCATE, L"%02I64u:%02I64u:%02I64u", PH_TICKS_PARTIAL_HOURS(Ticks), PH_TICKS_PARTIAL_MIN(Ticks), diff --git a/phlib/include/seceditp.h b/phlib/include/seceditp.h index b03bd218e8cc..a08e30720873 100644 --- a/phlib/include/seceditp.h +++ b/phlib/include/seceditp.h @@ -225,7 +225,7 @@ HRESULT STDMETHODCALLTYPE PhSecurityDataObject_GetData( _Out_ STGMEDIUM *pmedium); HRESULT STDMETHODCALLTYPE PhSecurityDataObject_GetDataHere( - IDataObject *This, + _In_ IDataObject *This, _In_ FORMATETC *pformatetc, _Inout_ STGMEDIUM *pmedium ); diff --git a/phlib/native.c b/phlib/native.c index ad015a27777f..dcd444d144f4 100644 --- a/phlib/native.c +++ b/phlib/native.c @@ -6123,7 +6123,7 @@ PPH_STRING PhGetFileName( // If the file name starts with "\Windows", prepend the system drive. if (PhStartsWithString2(newFileName, L"\\Windows", TRUE)) { - newFileName = PhCreateStringEx(NULL, FileName->Length + sizeof(UNICODE_NULL) * sizeof(WCHAR)); + newFileName = PhCreateStringEx(NULL, (FileName->Length + 2) * sizeof(WCHAR)); newFileName->Buffer[0] = USER_SHARED_DATA->NtSystemRoot[0]; newFileName->Buffer[1] = ':'; memcpy(&newFileName->Buffer[2], FileName->Buffer, FileName->Length); diff --git a/phlib/secedit.c b/phlib/secedit.c index 387b35b9c240..f8aeed78f91b 100644 --- a/phlib/secedit.c +++ b/phlib/secedit.c @@ -172,7 +172,7 @@ VOID PhEditSecurity( } ISecurityInformation *PhSecurityInformation_Create( - _In_ HWND WindowHandle, + _In_opt_ HWND WindowHandle, _In_ PWSTR ObjectName, _In_ PWSTR ObjectType, _In_ PPH_OPEN_OBJECT OpenObject, diff --git a/tools/peview/resprp.c b/tools/peview/resprp.c index 9fe4f4d1ebad..ff6df3db3481 100644 --- a/tools/peview/resprp.c +++ b/tools/peview/resprp.c @@ -121,7 +121,7 @@ INT_PTR CALLBACK PvpPeResourcesDlgProc( entry = resources.ResourceEntries[i]; - PhPrintUInt64(number, ++count); + PhPrintUInt32(number, ++count); lvItemIndex = PhAddListViewItem(lvHandle, MAXINT, number, NULL); if (IS_INTRESOURCE(entry.Type)) From 8c9d62202b8b576d1de0a182ba77dc6d1468dc4f Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 20 Apr 2019 00:48:29 +0200 Subject: [PATCH 1823/2058] Fix deadlock querying some types of pipe handles on Win10 --- ProcessHacker/hndlprp.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/ProcessHacker/hndlprp.c b/ProcessHacker/hndlprp.c index 83e2f5ff1666..4705b90383c7 100644 --- a/ProcessHacker/hndlprp.c +++ b/ProcessHacker/hndlprp.c @@ -673,6 +673,7 @@ VOID PhpUpdateHandleGeneral( BOOLEAN disableFlushButton = FALSE; BOOLEAN isFileOrDirectory = FALSE; BOOLEAN isConsoleHandle = FALSE; + BOOLEAN isPipeHandle = FALSE; FILE_FS_DEVICE_INFORMATION fileDeviceInfo; FILE_MODE_INFORMATION fileModeInfo; FILE_STANDARD_INFORMATION fileStandardInfo; @@ -690,6 +691,7 @@ VOID PhpUpdateHandleGeneral( switch (fileDeviceInfo.DeviceType) { case FILE_DEVICE_NAMED_PIPE: + isPipeHandle = TRUE; PhSetListViewSubItem(Context->ListViewHandle, Context->ListViewRowCache[PH_HANDLE_GENERAL_INDEX_FILETYPE], 1, L"Pipe"); break; case FILE_DEVICE_CD_ROM: @@ -713,10 +715,11 @@ VOID PhpUpdateHandleGeneral( } } - if (isConsoleHandle) + if (isPipeHandle || isConsoleHandle) { - // TODO: We block indefinitely when calling NtQueryInformationFile for '\Device\ConDrv\CurrentIn' - // but we can query other '\Device\ConDrv' console handles (dmex) + // NOTE: NtQueryInformationFile for '\Device\ConDrv\CurrentIn' causes a deadlock but + // we can query other '\Device\ConDrv' console handles. NtQueryInformationFile also + // causes a deadlock for some types of named pipes and only on Win10 (dmex) status = PhCallNtQueryFileInformationWithTimeout( fileHandle, FileModeInformation, From 718b1e824cab98bd86d99217730154dee31bf2fe Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 20 Apr 2019 00:49:44 +0200 Subject: [PATCH 1824/2058] OnlineChecks: remove some junk --- plugins/OnlineChecks/upload.c | 4 ++-- plugins/OnlineChecks/virustotal.c | 30 ++++++++---------------------- 2 files changed, 10 insertions(+), 24 deletions(-) diff --git a/plugins/OnlineChecks/upload.c b/plugins/OnlineChecks/upload.c index 7ff310f6eab4..1efbdde3153e 100644 --- a/plugins/OnlineChecks/upload.c +++ b/plugins/OnlineChecks/upload.c @@ -176,7 +176,7 @@ NTSTATUS HashFileAndResetPosition( FILE_POSITION_INFORMATION positionInfo; LONG priority; IO_PRIORITY_HINT ioPriority; - UCHAR buffer[PAGE_SIZE]; + BYTE buffer[PAGE_SIZE]; bytesRemaining = FileSize->QuadPart; @@ -213,7 +213,7 @@ NTSTATUS HashFileAndResetPosition( if (NT_SUCCESS(status)) { - UCHAR hash[32]; + BYTE hash[32]; switch (Algorithm) { diff --git a/plugins/OnlineChecks/virustotal.c b/plugins/OnlineChecks/virustotal.c index fff09e230f62..e10a45eeae30 100644 --- a/plugins/OnlineChecks/virustotal.c +++ b/plugins/OnlineChecks/virustotal.c @@ -86,11 +86,8 @@ PVIRUSTOTAL_FILE_HASH_ENTRY VirusTotalAddCacheResult( { PVIRUSTOTAL_FILE_HASH_ENTRY result; - result = PhAllocate(sizeof(VIRUSTOTAL_FILE_HASH_ENTRY)); - memset(result, 0, sizeof(VIRUSTOTAL_FILE_HASH_ENTRY)); - - PhReferenceObject(FileName); - result->FileName = FileName; + result = PhAllocateZero(sizeof(VIRUSTOTAL_FILE_HASH_ENTRY)); + result->FileName = PhReferenceObject(FileName); result->FileNameAnsi = PhConvertUtf16ToMultiByte(PhGetString(FileName)); result->Extension = Extension; @@ -224,9 +221,7 @@ PPH_LIST VirusTotalJsonToResultList( if (!(jsonArrayObject = PhGetJsonArrayIndexObject(JsonObject, i))) continue; - result = PhAllocate(sizeof(VIRUSTOTAL_API_RESULT)); - memset(result, 0, sizeof(VIRUSTOTAL_API_RESULT)); - + result = PhAllocateZero(sizeof(VIRUSTOTAL_API_RESULT)); result->FileHash = PhGetJsonValueAsString(jsonArrayObject, "hash"); result->Found = PhGetJsonObjectBool(jsonArrayObject, "found") == TRUE; result->Positives = PhGetJsonValueAsLong64(jsonArrayObject, "positives"); @@ -437,9 +432,7 @@ PVIRUSTOTAL_FILE_REPORT VirusTotalRequestFileReport( if (!(jsonRootObject = PhCreateJsonParser(jsonString->Buffer))) goto CleanupExit; - result = PhAllocate(sizeof(VIRUSTOTAL_FILE_REPORT)); - memset(result, 0, sizeof(VIRUSTOTAL_FILE_REPORT)); - + result = PhAllocateZero(sizeof(VIRUSTOTAL_FILE_REPORT)); result->ResponseCode = PhGetJsonValueAsLong64(jsonRootObject, "response_code"); result->StatusMessage = PhGetJsonValueAsString(jsonRootObject, "verbose_msg"); result->PermaLink = PhGetJsonValueAsString(jsonRootObject, "permalink"); @@ -464,9 +457,7 @@ PVIRUSTOTAL_FILE_REPORT VirusTotalRequestFileReport( PVIRUSTOTAL_FILE_REPORT_RESULT entry; PJSON_ARRAY_LIST_OBJECT object = jsonArrayList->Items[i]; - entry = PhAllocate(sizeof(VIRUSTOTAL_FILE_REPORT_RESULT)); - memset(entry, 0, sizeof(VIRUSTOTAL_FILE_REPORT_RESULT)); - + entry = PhAllocateZero(sizeof(VIRUSTOTAL_FILE_REPORT_RESULT)); entry->Vendor = PhConvertUtf8ToUtf16(object->Key); entry->Detected = PhGetJsonObjectBool(object->Entry, "detected"); entry->EngineVersion = PhGetJsonValueAsString(object->Entry, "version"); @@ -602,9 +593,7 @@ PVIRUSTOTAL_API_RESPONSE VirusTotalRequestFileReScan( if (!(jsonRootObject = PhCreateJsonParser(jsonString->Buffer))) goto CleanupExit; - result = PhAllocate(sizeof(VIRUSTOTAL_API_RESPONSE)); - memset(result, 0, sizeof(VIRUSTOTAL_API_RESPONSE)); - + result = PhAllocateZero(sizeof(VIRUSTOTAL_API_RESPONSE)); result->ResponseCode = PhGetJsonValueAsLong64(jsonRootObject, "response_code"); result->StatusMessage = PhGetJsonValueAsString(jsonRootObject, "verbose_msg"); result->PermaLink = PhGetJsonValueAsString(jsonRootObject, "permalink"); @@ -711,9 +700,7 @@ PVIRUSTOTAL_API_RESPONSE VirusTotalRequestIpAddressReport( if (!(jsonRootObject = PhCreateJsonParser(jsonString->Buffer))) goto CleanupExit; - result = PhAllocate(sizeof(VIRUSTOTAL_API_RESPONSE)); - memset(result, 0, sizeof(VIRUSTOTAL_API_RESPONSE)); - + result = PhAllocateZero(sizeof(VIRUSTOTAL_API_RESPONSE)); //result->ResponseCode = PhGetJsonValueAsLong64(jsonRootObject, "response_code"); //result->StatusMessage = PhGetJsonValueAsString(jsonRootObject, "verbose_msg"); //result->PermaLink = PhGetJsonValueAsString(jsonRootObject, "permalink"); @@ -924,7 +911,6 @@ VOID CleanupVirusTotalProcessMonitor( } } - // NOTE: This function does not use the SCM due to major performance issues. // For now just query this information from the registry but it might be out-of-sync // with any recent services changes until the SCM flushes its cache. @@ -1033,4 +1019,4 @@ NTSTATUS QueryServiceFileName( PhDereferenceObject(keyName); return status; -} \ No newline at end of file +} From 139fed7efde3577b3192e711da738be2494cf6ad Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 20 Apr 2019 04:18:47 +0200 Subject: [PATCH 1825/2058] Update PHNT types for 19H1 --- phnt/include/ntexapi.h | 135 ++++++++++++++++++++++++++++++++++------- 1 file changed, 113 insertions(+), 22 deletions(-) diff --git a/phnt/include/ntexapi.h b/phnt/include/ntexapi.h index 84be461f53fb..638998d1d960 100644 --- a/phnt/include/ntexapi.h +++ b/phnt/include/ntexapi.h @@ -1051,6 +1051,7 @@ typedef enum _WORKERFACTORYINFOCLASS WorkerFactoryTimeoutWaiters, // since THRESHOLD WorkerFactoryFlags, WorkerFactoryThreadSoftMaximum, + WorkerFactoryThreadCpuSets, // since REDSTONE5 MaxWorkerFactoryInfoClass } WORKERFACTORYINFOCLASS, *PWORKERFACTORYINFOCLASS; @@ -1446,6 +1447,8 @@ typedef enum _SYSTEM_INFORMATION_CLASS SystemCodeIntegrityUnlockModeInformation, SystemLeapSecondInformation, // SYSTEM_LEAP_SECOND_INFORMATION SystemFlags2Information, + SystemSecurityModelInformation, // SYSTEM_SECURITY_MODEL_INFORMATION // since 19H1 + SystemCodeIntegritySyntheticCacheInformation, MaxSystemInfoClass } SYSTEM_INFORMATION_CLASS; @@ -2119,10 +2122,49 @@ typedef struct _SYSTEM_RANGE_START_INFORMATION PVOID SystemRangeStart; } SYSTEM_RANGE_START_INFORMATION, *PSYSTEM_RANGE_START_INFORMATION; +typedef struct _SYSTEM_VERIFIER_INFORMATION_LEGACY // pre-19H1 +{ + ULONG NextEntryOffset; + ULONG Level; + UNICODE_STRING DriverName; + + ULONG RaiseIrqls; + ULONG AcquireSpinLocks; + ULONG SynchronizeExecutions; + ULONG AllocationsAttempted; + + ULONG AllocationsSucceeded; + ULONG AllocationsSucceededSpecialPool; + ULONG AllocationsWithNoTag; + ULONG TrimRequests; + + ULONG Trims; + ULONG AllocationsFailed; + ULONG AllocationsFailedDeliberately; + ULONG Loads; + + ULONG Unloads; + ULONG UnTrackedPool; + ULONG CurrentPagedPoolAllocations; + ULONG CurrentNonPagedPoolAllocations; + + ULONG PeakPagedPoolAllocations; + ULONG PeakNonPagedPoolAllocations; + + SIZE_T PagedPoolUsageInBytes; + SIZE_T NonPagedPoolUsageInBytes; + SIZE_T PeakPagedPoolUsageInBytes; + SIZE_T PeakNonPagedPoolUsageInBytes; +} SYSTEM_VERIFIER_INFORMATION_LEGACY, *PSYSTEM_VERIFIER_INFORMATION_LEGACY; + typedef struct _SYSTEM_VERIFIER_INFORMATION { ULONG NextEntryOffset; ULONG Level; + ULONG RuleClasses[2]; + ULONG TriageContext; + ULONG AreAllDriversBeingVerified; + UNICODE_STRING DriverName; ULONG RaiseIrqls; @@ -2355,6 +2397,9 @@ typedef struct _SYSTEM_BOOT_ENVIRONMENT_INFORMATION ULONGLONG DbgHiberBoot : 1; ULONGLONG DbgSoftBoot : 1; ULONGLONG DbgMeasuredLaunch : 1; + ULONGLONG DbgMeasuredLaunchCapable : 1; // 19H1 + ULONGLONG DbgSystemHiveReplace : 1; + ULONGLONG DbgMeasuredLaunchSmmProtections : 1; }; }; } SYSTEM_BOOT_ENVIRONMENT_INFORMATION, *PSYSTEM_BOOT_ENVIRONMENT_INFORMATION; @@ -2615,18 +2660,40 @@ typedef struct _MEMORY_SCRUB_INFORMATION // private typedef struct _PEBS_DS_SAVE_AREA { - ULONGLONG BtsBufferBase; - ULONGLONG BtsIndex; - ULONGLONG BtsAbsoluteMaximum; - ULONGLONG BtsInterruptThreshold; - ULONGLONG PebsBufferBase; - ULONGLONG PebsIndex; - ULONGLONG PebsAbsoluteMaximum; - ULONGLONG PebsInterruptThreshold; - ULONGLONG PebsCounterReset0; - ULONGLONG PebsCounterReset1; - ULONGLONG PebsCounterReset2; - ULONGLONG PebsCounterReset3; + union + { + ULONG As32Bit; // PEBS_DS_SAVE_AREA32 + struct + { + ULONG BtsBufferBase; + ULONG BtsIndex; + ULONG BtsAbsoluteMaximum; + ULONG BtsInterruptThreshold; + ULONG PebsBufferBase; + ULONG PebsIndex; + ULONG PebsAbsoluteMaximum; + ULONG PebsInterruptThreshold; + ULONG PebsGpCounterReset[8]; + ULONG PebsFixedCounterReset[4]; + }; + }; + union + { + ULONGLONG As64Bit; // PEBS_DS_SAVE_AREA64 + struct + { + ULONGLONG BtsBufferBase; + ULONGLONG BtsIndex; + ULONGLONG BtsAbsoluteMaximum; + ULONGLONG BtsInterruptThreshold; + ULONGLONG PebsBufferBase; + ULONGLONG PebsIndex; + ULONGLONG PebsAbsoluteMaximum; + ULONGLONG PebsInterruptThreshold; + ULONGLONG PebsGpCounterReset[8]; + ULONGLONG PebsFixedCounterReset[4]; + }; + }; } PEBS_DS_SAVE_AREA, *PPEBS_DS_SAVE_AREA; // private @@ -2803,7 +2870,7 @@ typedef union _ENERGY_STATE_DURATION typedef struct _PROCESS_ENERGY_VALUES { - ULONGLONG Cycles[2][4]; + ULONGLONG Cycles[4][2]; ULONGLONG DiskEnergy; ULONGLONG NetworkTailEnergy; ULONGLONG MBBTailEnergy; @@ -2979,7 +3046,7 @@ typedef struct _SYSTEM_HYPERVISOR_DETAIL_INFORMATION // private typedef struct _SYSTEM_PROCESSOR_CYCLE_STATS_INFORMATION { - ULONGLONG Cycles[2][4]; + ULONGLONG Cycles[4][2]; } SYSTEM_PROCESSOR_CYCLE_STATS_INFORMATION, *PSYSTEM_PROCESSOR_CYCLE_STATS_INFORMATION; // private @@ -3014,9 +3081,10 @@ typedef struct _SYSTEM_ISOLATED_USER_MODE_INFORMATION BOOLEAN DebugEnabled : 1; BOOLEAN FirmwarePageProtection : 1; BOOLEAN EncryptionKeyAvailable : 1; - BOOLEAN SpareFlags : 1; + BOOLEAN SpareFlags : 2; BOOLEAN TrustletRunning : 1; - BOOLEAN SpareFlags2 : 1; + BOOLEAN HvciDisableAllowed : 1; + BOOLEAN SpareFlags2 : 6; BOOLEAN Spare0[6]; ULONGLONG Spare1; } SYSTEM_ISOLATED_USER_MODE_INFORMATION, *PSYSTEM_ISOLATED_USER_MODE_INFORMATION; @@ -3167,10 +3235,9 @@ typedef struct _SYSTEM_CODEINTEGRITY_UNLOCK_INFORMATION struct { ULONG Locked : 1; - ULONG Unlockable : 1; - ULONG UnlockApplied : 1; - ULONG UnlockIdValid : 1; // REDSTONE4 - ULONG Reserved : 28; + ULONG UnlockApplied : 1; // Unlockable field removed 19H1 + ULONG UnlockIdValid : 1; + ULONG Reserved : 29; }; }; UCHAR UnlockId[32]; // REDSTONE4 @@ -3252,7 +3319,15 @@ typedef struct _SYSTEM_SPECULATION_CONTROL_INFORMATION ULONG BpbDisabledKernelToUser : 1; ULONG SpecCtrlRetpolineEnabled : 1; ULONG SpecCtrlImportOptimizationEnabled : 1; - ULONG Reserved : 16; + ULONG EnhancedIbrs : 1; // since 19H1 + ULONG HvL1tfStatusAvailable : 1; + ULONG HvL1tfProcessorNotAffected : 1; + ULONG HvL1tfMigitationEnabled : 1; + ULONG HvL1tfMigitationNotEnabled_Hardware : 1; + ULONG HvL1tfMigitationNotEnabled_LoadOption : 1; + ULONG HvL1tfMigitationNotEnabled_CoreScheduler : 1; + ULONG EnhancedIbrsReported : 1; + ULONG Reserved : 8; }; }; } SYSTEM_SPECULATION_CONTROL_INFORMATION, *PSYSTEM_SPECULATION_CONTROL_INFORMATION; @@ -3276,6 +3351,21 @@ typedef struct _SYSTEM_WORKLOAD_ALLOWED_CPU_SET_INFORMATION ULONGLONG CpuSets[1]; } SYSTEM_WORKLOAD_ALLOWED_CPU_SET_INFORMATION, *PSYSTEM_WORKLOAD_ALLOWED_CPU_SET_INFORMATION; +// private +typedef struct _SYSTEM_SECURITY_MODEL_INFORMATION +{ + union + { + ULONG SecurityModelFlags; + struct + { + ULONG SModeAdminlessEnabled : 1; + ULONG AllowDeviceOwnerProtectionDowngrade : 1; + ULONG Reserved : 30; + }; + }; +} SYSTEM_SECURITY_MODEL_INFORMATION, *PSYSTEM_SECURITY_MODEL_INFORMATION; + #if (PHNT_MODE != PHNT_MODE_KERNEL) NTSYSCALLAPI @@ -3600,7 +3690,8 @@ typedef struct _KUSER_SHARED_DATA UCHAR Reserved : 2; }; }; - UCHAR Reserved6[2]; + + USHORT CyclesPerYield; volatile ULONG ActiveConsoleId; From 118841c722fdc7fab49d89e79f83ca4674528301 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 20 Apr 2019 15:52:09 +0200 Subject: [PATCH 1826/2058] Fix token LPAC checks --- ProcessHacker/tokprp.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ProcessHacker/tokprp.c b/ProcessHacker/tokprp.c index fd1c005abe95..8ab35d421ed0 100644 --- a/ProcessHacker/tokprp.c +++ b/ProcessHacker/tokprp.c @@ -3415,11 +3415,11 @@ INT_PTR CALLBACK PhpTokenContainerPageProc( { PTOKEN_SECURITY_ATTRIBUTE_V1 attribute = &info->Attribute.pAttributeV1[i]; - if (attribute->ValueType == TOKEN_SECURITY_ATTRIBUTE_TYPE_STRING) + if (RtlEqualUnicodeString(&attribute->Name, &attributeNameUs, FALSE)) { - if (RtlEqualUnicodeString(&attribute->Name, &attributeNameUs, FALSE)) + if (attribute->ValueType == TOKEN_SECURITY_ATTRIBUTE_TYPE_UINT64) { - isLessPrivilegedAppContainer = TRUE; + isLessPrivilegedAppContainer = TRUE; // (*attribute->Values.pUint64 == 1); break; } } From 187e984fa2df46c6657dbbccd1f395c304d1950b Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 20 Apr 2019 15:52:53 +0200 Subject: [PATCH 1827/2058] Fix incorrect 19H1 type --- phnt/include/ntexapi.h | 68 ++++++++++++++++++++---------------------- 1 file changed, 33 insertions(+), 35 deletions(-) diff --git a/phnt/include/ntexapi.h b/phnt/include/ntexapi.h index 638998d1d960..a147bd6e1895 100644 --- a/phnt/include/ntexapi.h +++ b/phnt/include/ntexapi.h @@ -2658,42 +2658,40 @@ typedef struct _MEMORY_SCRUB_INFORMATION } MEMORY_SCRUB_INFORMATION, *PMEMORY_SCRUB_INFORMATION; // private -typedef struct _PEBS_DS_SAVE_AREA +typedef struct _PEBS_DS_SAVE_AREA32 +{ + ULONG BtsBufferBase; + ULONG BtsIndex; + ULONG BtsAbsoluteMaximum; + ULONG BtsInterruptThreshold; + ULONG PebsBufferBase; + ULONG PebsIndex; + ULONG PebsAbsoluteMaximum; + ULONG PebsInterruptThreshold; + ULONG PebsGpCounterReset[8]; + ULONG PebsFixedCounterReset[4]; +} PEBS_DS_SAVE_AREA32, *PPEBS_DS_SAVE_AREA32; + +// private +typedef struct _PEBS_DS_SAVE_AREA64 +{ + ULONGLONG BtsBufferBase; + ULONGLONG BtsIndex; + ULONGLONG BtsAbsoluteMaximum; + ULONGLONG BtsInterruptThreshold; + ULONGLONG PebsBufferBase; + ULONGLONG PebsIndex; + ULONGLONG PebsAbsoluteMaximum; + ULONGLONG PebsInterruptThreshold; + ULONGLONG PebsGpCounterReset[8]; + ULONGLONG PebsFixedCounterReset[4]; +} PEBS_DS_SAVE_AREA64, *PPEBS_DS_SAVE_AREA64; + +// private +typedef union _PEBS_DS_SAVE_AREA { - union - { - ULONG As32Bit; // PEBS_DS_SAVE_AREA32 - struct - { - ULONG BtsBufferBase; - ULONG BtsIndex; - ULONG BtsAbsoluteMaximum; - ULONG BtsInterruptThreshold; - ULONG PebsBufferBase; - ULONG PebsIndex; - ULONG PebsAbsoluteMaximum; - ULONG PebsInterruptThreshold; - ULONG PebsGpCounterReset[8]; - ULONG PebsFixedCounterReset[4]; - }; - }; - union - { - ULONGLONG As64Bit; // PEBS_DS_SAVE_AREA64 - struct - { - ULONGLONG BtsBufferBase; - ULONGLONG BtsIndex; - ULONGLONG BtsAbsoluteMaximum; - ULONGLONG BtsInterruptThreshold; - ULONGLONG PebsBufferBase; - ULONGLONG PebsIndex; - ULONGLONG PebsAbsoluteMaximum; - ULONGLONG PebsInterruptThreshold; - ULONGLONG PebsGpCounterReset[8]; - ULONGLONG PebsFixedCounterReset[4]; - }; - }; + PEBS_DS_SAVE_AREA32 As32Bit; + PEBS_DS_SAVE_AREA64 As64Bit; } PEBS_DS_SAVE_AREA, *PPEBS_DS_SAVE_AREA; // private From e969a8b38976ce7966a505ab625aa476c6d94087 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 20 Apr 2019 16:21:28 +0200 Subject: [PATCH 1828/2058] Add check for ACL editor MapGeneric types --- phlib/secedit.c | 39 ++++++++++++++++++++++++++++++++------- 1 file changed, 32 insertions(+), 7 deletions(-) diff --git a/phlib/secedit.c b/phlib/secedit.c index f8aeed78f91b..18c8e1ac9f54 100644 --- a/phlib/secedit.c +++ b/phlib/secedit.c @@ -448,15 +448,40 @@ HRESULT STDMETHODCALLTYPE PhSecurityInformation_MapGeneric( _Inout_ PACCESS_MASK Mask ) { - static GENERIC_MAPPING genericMappings = + PhSecurityInformation* this = (PhSecurityInformation*)This; + + if (PhEqualString2(this->ObjectType, L"FileObject", TRUE)) { - FILE_GENERIC_READ, - FILE_GENERIC_WRITE, - FILE_GENERIC_EXECUTE, - FILE_ALL_ACCESS - }; + static GENERIC_MAPPING genericMappings = + { + FILE_GENERIC_READ, + FILE_GENERIC_WRITE, + FILE_GENERIC_EXECUTE, + FILE_ALL_ACCESS + }; + + RtlMapGenericMask(Mask, &genericMappings); + } + + // TODO we're supposed to lookup the GenericMapping for the object type. (dmex) + + //POBJECT_TYPES_INFORMATION objectTypes; + //POBJECT_TYPE_INFORMATION objectType; + + //if (NT_SUCCESS(PhEnumObjectTypes(&objectTypes))) + //{ + // objectType = PH_FIRST_OBJECT_TYPE(objectTypes); + // + // for (ULONG i = 0; i < objectTypes->NumberOfTypes; i++) + // { + // RtlMapGenericMask(Mask, &objectType->GenericMapping); + // } + // + // PhFree(objectTypes); + //} - RtlMapGenericMask(Mask, &genericMappings); + // TODO + // NtQuerySystemInformation(SystemObjectInformation); return S_OK; } From 238287786b80abad647b988e60f69090cab4c8fe Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 20 Apr 2019 23:54:23 +0200 Subject: [PATCH 1829/2058] Update PHNT types for 19H1 (2/2) --- phnt/include/ntmmapi.h | 9 ++++++--- phnt/include/ntpebteb.h | 18 ++++++++++-------- phnt/include/ntpsapi.h | 19 +++++++++++++++++++ phnt/include/ntrtl.h | 4 ++++ 4 files changed, 39 insertions(+), 11 deletions(-) diff --git a/phnt/include/ntmmapi.h b/phnt/include/ntmmapi.h index 9730f6875d0c..1fd3865a8213 100644 --- a/phnt/include/ntmmapi.h +++ b/phnt/include/ntmmapi.h @@ -135,6 +135,7 @@ typedef struct _MEMORY_REGION_INFORMATION }; SIZE_T RegionSize; SIZE_T CommitSize; + ULONG_PTR PartitionId; // 19H1 } MEMORY_REGION_INFORMATION, *PMEMORY_REGION_INFORMATION; // private @@ -164,8 +165,9 @@ typedef struct _MEMORY_WORKING_SET_EX_BLOCK ULONG_PTR Reserved : 3; ULONG_PTR SharedOriginal : 1; ULONG_PTR Bad : 1; + ULONG_PTR Win32GraphicsProtection : 4; // 19H1 #ifdef _WIN64 - ULONG_PTR ReservedUlong : 32; + ULONG_PTR ReservedUlong : 28; #endif }; struct @@ -258,7 +260,7 @@ typedef struct _MEMORY_FRAME_INFORMATION { ULONGLONG UseDescription : 4; // MMPFNUSE_* ULONGLONG ListDescription : 3; // MMPFNLIST_* - ULONGLONG Reserved0 : 1; // reserved for future expansion + ULONGLONG Cold : 1; // 19H1 ULONGLONG Pinned : 1; // 1 - pinned, 0 - not pinned ULONGLONG DontUse : 48; // *_INFORMATION overlay ULONGLONG Priority : 3; // rev @@ -505,7 +507,8 @@ typedef enum _VIRTUAL_MEMORY_INFORMATION_CLASS VmPrefetchInformation, // ULONG VmPagePriorityInformation, VmCfgCallTargetInformation, // CFG_CALL_TARGET_LIST_INFORMATION // REDSTONE2 - VmPageDirtyStateInformation // REDSTONE3 + VmPageDirtyStateInformation, // REDSTONE3 + VmImageHotPatchInformation // 19H1 } VIRTUAL_MEMORY_INFORMATION_CLASS; typedef struct _MEMORY_RANGE_ENTRY diff --git a/phnt/include/ntpebteb.h b/phnt/include/ntpebteb.h index 98424574c298..bfe23b313976 100644 --- a/phnt/include/ntpebteb.h +++ b/phnt/include/ntpebteb.h @@ -107,7 +107,7 @@ typedef struct _PEB PVOID KernelCallbackTable; PVOID UserSharedInfoPtr; }; - ULONG SystemReserved[1]; + ULONG SystemReserved; ULONG AtlThunkSListPtr32; PAPI_SET_NAMESPACE ApiSetMap; ULONG TlsExpansionCounter; @@ -172,11 +172,13 @@ typedef struct _PEB SIZE_T MinimumStackCommit; - PVOID *FlsCallback; - LIST_ENTRY FlsListHead; - PVOID FlsBitmap; - ULONG FlsBitmapBits[FLS_MAXIMUM_AVAILABLE / (sizeof(ULONG) * 8)]; - ULONG FlsHighIndex; + PVOID SparePointers[4]; // 19H1 (previously FlsCallback to FlsHighIndex) + ULONG SpareUlongs[5]; // 19H1 + //PVOID* FlsCallback; + //LIST_ENTRY FlsListHead; + //PVOID FlsBitmap; + //ULONG FlsBitmapBits[FLS_MAXIMUM_AVAILABLE / (sizeof(ULONG) * 8)]; + //ULONG FlsHighIndex; PVOID WerRegistrationData; PVOID WerShipAssertPtr; @@ -219,12 +221,12 @@ typedef struct _PEB C_ASSERT(FIELD_OFFSET(PEB, SessionId) == 0x2C0); //C_ASSERT(sizeof(PEB) == 0x7B0); // REDSTONE3 //C_ASSERT(sizeof(PEB) == 0x7B8); // REDSTONE4 -C_ASSERT(sizeof(PEB) == 0x7C8); // REDSTONE5 +C_ASSERT(sizeof(PEB) == 0x7C8); // REDSTONE5 // 19H1 #else C_ASSERT(FIELD_OFFSET(PEB, SessionId) == 0x1D4); //C_ASSERT(sizeof(PEB) == 0x468); // REDSTONE3 //C_ASSERT(sizeof(PEB) == 0x470); // REDSTONE4 -C_ASSERT(sizeof(PEB) == 0x480); // REDSTONE5 +C_ASSERT(sizeof(PEB) == 0x480); // REDSTONE5 // 19H1 #endif #define GDI_BATCH_BUFFER_SIZE 310 diff --git a/phnt/include/ntpsapi.h b/phnt/include/ntpsapi.h index ebe8980ee3e7..8f5c08012f36 100644 --- a/phnt/include/ntpsapi.h +++ b/phnt/include/ntpsapi.h @@ -195,6 +195,8 @@ typedef enum _PROCESSINFOCLASS ProcessCombineSecurityDomainsInformation, // PROCESS_COMBINE_SECURITY_DOMAINS_INFORMATION ProcessEnableLogging, // PROCESS_LOGGING_INFORMATION ProcessLeapSecondInformation, // PROCESS_LEAP_SECOND_INFORMATION + ProcessFiberShadowStackAllocation, // PROCESS_FIBER_SHADOW_STACK_ALLOCATION_INFORMATION // since 19H1 + ProcessFreeFiberShadowStackAllocation, // PROCESS_FREE_FIBER_SHADOW_STACK_ALLOCATION_INFORMATION MaxProcessInfoClass } PROCESSINFOCLASS; #endif @@ -812,6 +814,7 @@ typedef struct _MANAGE_WRITES_TO_EXECUTABLE_MEMORY ULONG ProcessEnableWriteExceptions : 1; ULONG ThreadAllowWrites : 1; ULONG Spare : 22; + PVOID KernelWriteToExecutableSignal; // 19H1 } MANAGE_WRITES_TO_EXECUTABLE_MEMORY, *PMANAGE_WRITES_TO_EXECUTABLE_MEMORY; #define PROCESS_READWRITEVM_LOGGING_ENABLE_READVM 1 @@ -890,6 +893,22 @@ typedef struct _PROCESS_LEAP_SECOND_INFORMATION ULONG Reserved; } PROCESS_LEAP_SECOND_INFORMATION, *PPROCESS_LEAP_SECOND_INFORMATION; +// private +typedef struct _PROCESS_FIBER_SHADOW_STACK_ALLOCATION_INFORMATION +{ + ULONGLONG ReserveSize; + ULONGLONG CommitSize; + ULONG PreferredNode; + ULONG Reserved; + PVOID Ssp; +} PROCESS_FIBER_SHADOW_STACK_ALLOCATION_INFORMATION, *PPROCESS_FIBER_SHADOW_STACK_ALLOCATION_INFORMATION; + +// private +typedef struct _PROCESS_FREE_FIBER_SHADOW_STACK_ALLOCATION_INFORMATION +{ + PVOID Ssp; +} PROCESS_FREE_FIBER_SHADOW_STACK_ALLOCATION_INFORMATION, *PPROCESS_FREE_FIBER_SHADOW_STACK_ALLOCATION_INFORMATION; + // end_private #endif diff --git a/phnt/include/ntrtl.h b/phnt/include/ntrtl.h index b2dfe464207b..86b8824e9a4e 100644 --- a/phnt/include/ntrtl.h +++ b/phnt/include/ntrtl.h @@ -2540,6 +2540,9 @@ typedef struct _RTL_USER_PROCESS_PARAMETERS ULONG ProcessGroupId; ULONG LoaderThreads; UNICODE_STRING RedirectionDllName; // REDSTONE4 + UNICODE_STRING HeapPartitionName; // 19H1 + ULONG_PTR DefaultThreadpoolCpuSetMasks; + ULONG DefaultThreadpoolCpuSetMaskCount; } RTL_USER_PROCESS_PARAMETERS, *PRTL_USER_PROCESS_PARAMETERS; #define RTL_USER_PROC_PARAMS_NORMALIZED 0x00000001 @@ -7494,6 +7497,7 @@ typedef struct _RTL_IMAGE_MITIGATION_PAYLOAD_RESTRICTION_POLICY RTL_IMAGE_MITIGATION_POLICY EnableRopStackPivot; RTL_IMAGE_MITIGATION_POLICY EnableRopCallerCheck; RTL_IMAGE_MITIGATION_POLICY EnableRopSimExec; + WCHAR EafPlusModuleList[512]; // 19H1 } RTL_IMAGE_MITIGATION_PAYLOAD_RESTRICTION_POLICY, *PRTL_IMAGE_MITIGATION_PAYLOAD_RESTRICTION_POLICY; // rev From 03fae90f3740426f1e8afc048ca8fcfa775f6dbb Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 21 Apr 2019 00:21:40 +0200 Subject: [PATCH 1830/2058] Fix building with latest SDK --- phnt/include/ntpsapi.h | 2 +- phnt/include/ntrtl.h | 1 + phnt/include/ntwow64.h | 22 +++++++++++++++------- 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/phnt/include/ntpsapi.h b/phnt/include/ntpsapi.h index 8f5c08012f36..2320c41afb05 100644 --- a/phnt/include/ntpsapi.h +++ b/phnt/include/ntpsapi.h @@ -55,7 +55,7 @@ typedef ULONG GDI_HANDLE_BUFFER[GDI_HANDLE_BUFFER_SIZE]; typedef ULONG GDI_HANDLE_BUFFER32[GDI_HANDLE_BUFFER_SIZE32]; typedef ULONG GDI_HANDLE_BUFFER64[GDI_HANDLE_BUFFER_SIZE64]; -#define FLS_MAXIMUM_AVAILABLE 128 +//#define FLS_MAXIMUM_AVAILABLE 128 #define TLS_MINIMUM_AVAILABLE 64 #define TLS_EXPANSION_SLOTS 1024 diff --git a/phnt/include/ntrtl.h b/phnt/include/ntrtl.h index 86b8824e9a4e..f9be267cf2dd 100644 --- a/phnt/include/ntrtl.h +++ b/phnt/include/ntrtl.h @@ -2539,6 +2539,7 @@ typedef struct _RTL_USER_PROCESS_PARAMETERS PVOID PackageDependencyData; ULONG ProcessGroupId; ULONG LoaderThreads; + UNICODE_STRING RedirectionDllName; // REDSTONE4 UNICODE_STRING HeapPartitionName; // 19H1 ULONG_PTR DefaultThreadpoolCpuSetMasks; diff --git a/phnt/include/ntwow64.h b/phnt/include/ntwow64.h index 6f8bcdca32e2..c7b927adba3b 100644 --- a/phnt/include/ntwow64.h +++ b/phnt/include/ntwow64.h @@ -141,7 +141,8 @@ typedef struct _LDR_DATA_TABLE_ENTRY32 ULONG CorImage : 1; ULONG DontRelocate : 1; ULONG CorILOnly : 1; - ULONG ReservedFlags5 : 3; + ULONG ChpeImage : 1; + ULONG ReservedFlags5 : 2; ULONG Redirected : 1; ULONG ReservedFlags6 : 2; ULONG CompatDatabaseProcessed : 1; @@ -225,6 +226,11 @@ typedef struct _RTL_USER_PROCESS_PARAMETERS32 WOW64_POINTER(PVOID) PackageDependencyData; ULONG ProcessGroupId; ULONG LoaderThreads; + + UNICODE_STRING32 RedirectionDllName; // REDSTONE4 + UNICODE_STRING32 HeapPartitionName; // 19H1 + WOW64_POINTER(ULONG_PTR) DefaultThreadpoolCpuSetMasks; + ULONG DefaultThreadpoolCpuSetMaskCount; } RTL_USER_PROCESS_PARAMETERS32, *PRTL_USER_PROCESS_PARAMETERS32; typedef struct _PEB32 @@ -275,7 +281,7 @@ typedef struct _PEB32 WOW64_POINTER(PVOID) KernelCallbackTable; WOW64_POINTER(PVOID) UserSharedInfoPtr; }; - ULONG SystemReserved[1]; + ULONG SystemReserved; ULONG AtlThunkSListPtr32; WOW64_POINTER(PVOID) ApiSetMap; ULONG TlsExpansionCounter; @@ -338,11 +344,13 @@ typedef struct _PEB32 WOW64_POINTER(SIZE_T) MinimumStackCommit; - WOW64_POINTER(PVOID *) FlsCallback; - LIST_ENTRY32 FlsListHead; - WOW64_POINTER(PVOID) FlsBitmap; - ULONG FlsBitmapBits[FLS_MAXIMUM_AVAILABLE / (sizeof(ULONG) * 8)]; - ULONG FlsHighIndex; + WOW64_POINTER(PVOID) SparePointers[4]; + ULONG SpareUlongs[5]; + //WOW64_POINTER(PVOID *) FlsCallback; + //LIST_ENTRY32 FlsListHead; + //WOW64_POINTER(PVOID) FlsBitmap; + //ULONG FlsBitmapBits[FLS_MAXIMUM_AVAILABLE / (sizeof(ULONG) * 8)]; + //ULONG FlsHighIndex; WOW64_POINTER(PVOID) WerRegistrationData; WOW64_POINTER(PVOID) WerShipAssertPtr; From 49fcf7080041fbea7b68742cfe27c9ece3c933bc Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 22 Apr 2019 02:53:50 +0200 Subject: [PATCH 1831/2058] Fix #411 --- plugins/ExtendedTools/iconext.c | 6 +++--- plugins/ToolStatus/graph.c | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/plugins/ExtendedTools/iconext.c b/plugins/ExtendedTools/iconext.c index ebb32788914e..8bf42ca11228 100644 --- a/plugins/ExtendedTools/iconext.c +++ b/plugins/ExtendedTools/iconext.c @@ -871,7 +871,7 @@ TOOLSTATUS_GRAPH_MESSAGE_CALLBACK_DECLARE(EtpToolbarGpuHistoryGraphMessageCallba drawInfo->Flags = PH_GRAPH_USE_GRID_X; PhSiSetColorsGraphDrawInfo(drawInfo, PhGetIntegerSetting(L"ColorCpuKernel"), 0); - if (ProcessesUpdatedCount < 2) + if (ProcessesUpdatedCount <= 2) return; PhGraphStateGetDrawInfo(GraphState, getDrawInfo, EtGpuNodeHistory.Count); @@ -942,7 +942,7 @@ TOOLSTATUS_GRAPH_MESSAGE_CALLBACK_DECLARE(EtpToolbarDiskHistoryGraphMessageCallb drawInfo->Flags = PH_GRAPH_USE_GRID_X | PH_GRAPH_USE_LINE_2; PhSiSetColorsGraphDrawInfo(drawInfo, PhGetIntegerSetting(L"ColorIoReadOther"), PhGetIntegerSetting(L"ColorIoWrite")); - if (ProcessesUpdatedCount < 2) + if (ProcessesUpdatedCount <= 2) return; PhGraphStateGetDrawInfo( @@ -1051,7 +1051,7 @@ TOOLSTATUS_GRAPH_MESSAGE_CALLBACK_DECLARE(EtpToolbarNetworkHistoryGraphMessageCa drawInfo->Flags = PH_GRAPH_USE_GRID_X | PH_GRAPH_USE_LINE_2; PhSiSetColorsGraphDrawInfo(drawInfo, PhGetIntegerSetting(L"ColorIoReadOther"), PhGetIntegerSetting(L"ColorIoWrite")); - if (ProcessesUpdatedCount < 2) + if (ProcessesUpdatedCount <= 2) return; PhGraphStateGetDrawInfo( diff --git a/plugins/ToolStatus/graph.c b/plugins/ToolStatus/graph.c index f1a588e2fed5..3f63ed4ed3c0 100644 --- a/plugins/ToolStatus/graph.c +++ b/plugins/ToolStatus/graph.c @@ -582,7 +582,7 @@ TOOLSTATUS_GRAPH_MESSAGE_CALLBACK_DECLARE(CpuHistoryGraphMessageCallback) drawInfo->Flags = PH_GRAPH_USE_GRID_X | PH_GRAPH_USE_LINE_2; PhSiSetColorsGraphDrawInfo(drawInfo, PhGetIntegerSetting(L"ColorCpuKernel"), PhGetIntegerSetting(L"ColorCpuUser")); - if (ProcessesUpdatedCount < 2) + if (ProcessesUpdatedCount <= 2) return; PhGraphStateGetDrawInfo(GraphState, getDrawInfo, SystemStatistics.CpuUserHistory->Count); @@ -654,7 +654,7 @@ TOOLSTATUS_GRAPH_MESSAGE_CALLBACK_DECLARE(PhysicalHistoryGraphMessageCallback) drawInfo->Flags = PH_GRAPH_USE_GRID_X; PhSiSetColorsGraphDrawInfo(drawInfo, PhGetIntegerSetting(L"ColorPhysical"), 0); - if (ProcessesUpdatedCount < 2) + if (ProcessesUpdatedCount <= 2) return; PhGraphStateGetDrawInfo(GraphState, getDrawInfo, SystemStatistics.PhysicalHistory->Count); @@ -719,7 +719,7 @@ TOOLSTATUS_GRAPH_MESSAGE_CALLBACK_DECLARE(CommitHistoryGraphMessageCallback) drawInfo->Flags = PH_GRAPH_USE_GRID_X; PhSiSetColorsGraphDrawInfo(drawInfo, PhGetIntegerSetting(L"ColorPrivate"), 0); - if (ProcessesUpdatedCount < 2) + if (ProcessesUpdatedCount <= 2) return; PhGraphStateGetDrawInfo(GraphState, getDrawInfo, SystemStatistics.CommitHistory->Count); @@ -784,7 +784,7 @@ TOOLSTATUS_GRAPH_MESSAGE_CALLBACK_DECLARE(IoHistoryGraphMessageCallback) drawInfo->Flags = PH_GRAPH_USE_GRID_X | PH_GRAPH_USE_LINE_2; PhSiSetColorsGraphDrawInfo(drawInfo, PhGetIntegerSetting(L"ColorIoReadOther"), PhGetIntegerSetting(L"ColorIoWrite")); - if (ProcessesUpdatedCount < 2) + if (ProcessesUpdatedCount <= 2) return; PhGraphStateGetDrawInfo(GraphState, getDrawInfo, SystemStatistics.IoReadHistory->Count); From 0578c5696640e7e5fe53caebbcd5dd0069633bcc Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 27 Apr 2019 21:19:50 +0200 Subject: [PATCH 1832/2058] Update delay imports --- ProcessHacker/include/netprv.h | 6 +- ProcessHacker/netprv.c | 138 +++++++++++++------------- ProcessHacker/tokprp.c | 34 ++----- phlib/apiimport.c | 11 +++ phlib/include/apiimport.h | 58 +++++++++++ phlib/lsasup.c | 10 +- phlib/native.c | 172 ++++++++++++++++----------------- 7 files changed, 235 insertions(+), 194 deletions(-) diff --git a/ProcessHacker/include/netprv.h b/ProcessHacker/include/netprv.h index c12d10694bd0..76f8ed87efeb 100644 --- a/ProcessHacker/include/netprv.h +++ b/ProcessHacker/include/netprv.h @@ -69,9 +69,9 @@ PhReferenceNetworkItem( ); // end_phapppub -PPH_STRING PhGetHostNameFromAddress( - _In_ PPH_IP_ADDRESS Address - ); +//PPH_STRING PhGetHostNameFromAddress( +// _In_ PPH_IP_ADDRESS Address +// ); VOID PhNetworkProviderUpdate( _In_ PVOID Object diff --git a/ProcessHacker/netprv.c b/ProcessHacker/netprv.c index 51426b071416..836ee246ecfe 100644 --- a/ProcessHacker/netprv.c +++ b/ProcessHacker/netprv.c @@ -281,75 +281,75 @@ PPHP_RESOLVE_CACHE_ITEM PhpLookupResolveCacheItem( return NULL; } -PPH_STRING PhGetHostNameFromAddress( - _In_ PPH_IP_ADDRESS Address - ) -{ - SOCKADDR_IN ipv4Address; - SOCKADDR_IN6 ipv6Address; - PSOCKADDR address; - socklen_t length; - PPH_STRING hostName; - - if (Address->Type == PH_IPV4_NETWORK_TYPE) - { - ipv4Address.sin_family = AF_INET; - ipv4Address.sin_port = 0; - ipv4Address.sin_addr = Address->InAddr; - address = (PSOCKADDR)&ipv4Address; - length = sizeof(ipv4Address); - } - else if (Address->Type == PH_IPV6_NETWORK_TYPE) - { - ipv6Address.sin6_family = AF_INET6; - ipv6Address.sin6_port = 0; - ipv6Address.sin6_flowinfo = 0; - ipv6Address.sin6_addr = Address->In6Addr; - ipv6Address.sin6_scope_id = 0; - address = (PSOCKADDR)&ipv6Address; - length = sizeof(ipv6Address); - } - else - { - return NULL; - } - - hostName = PhCreateStringEx(NULL, 128); - - if (GetNameInfo( - address, - length, - hostName->Buffer, - (ULONG)hostName->Length / sizeof(WCHAR) + 1, - NULL, - 0, - NI_NAMEREQD - ) != 0) - { - // Try with the maximum host name size. - PhDereferenceObject(hostName); - hostName = PhCreateStringEx(NULL, NI_MAXHOST * sizeof(WCHAR)); - - if (GetNameInfo( - address, - length, - hostName->Buffer, - (ULONG)hostName->Length / sizeof(WCHAR) + 1, - NULL, - 0, - NI_NAMEREQD - ) != 0) - { - PhDereferenceObject(hostName); - - return NULL; - } - } - - PhTrimToNullTerminatorString(hostName); - - return hostName; -} +//PPH_STRING PhGetHostNameFromAddress( +// _In_ PPH_IP_ADDRESS Address +// ) +//{ +// SOCKADDR_IN ipv4Address; +// SOCKADDR_IN6 ipv6Address; +// PSOCKADDR address; +// socklen_t length; +// PPH_STRING hostName; +// +// if (Address->Type == PH_IPV4_NETWORK_TYPE) +// { +// ipv4Address.sin_family = AF_INET; +// ipv4Address.sin_port = 0; +// ipv4Address.sin_addr = Address->InAddr; +// address = (PSOCKADDR)&ipv4Address; +// length = sizeof(ipv4Address); +// } +// else if (Address->Type == PH_IPV6_NETWORK_TYPE) +// { +// ipv6Address.sin6_family = AF_INET6; +// ipv6Address.sin6_port = 0; +// ipv6Address.sin6_flowinfo = 0; +// ipv6Address.sin6_addr = Address->In6Addr; +// ipv6Address.sin6_scope_id = 0; +// address = (PSOCKADDR)&ipv6Address; +// length = sizeof(ipv6Address); +// } +// else +// { +// return NULL; +// } +// +// hostName = PhCreateStringEx(NULL, 128); +// +// if (GetNameInfo( +// address, +// length, +// hostName->Buffer, +// (ULONG)hostName->Length / sizeof(WCHAR) + 1, +// NULL, +// 0, +// NI_NAMEREQD +// ) != 0) +// { +// // Try with the maximum host name size. +// PhDereferenceObject(hostName); +// hostName = PhCreateStringEx(NULL, NI_MAXHOST * sizeof(WCHAR)); +// +// if (GetNameInfo( +// address, +// length, +// hostName->Buffer, +// (ULONG)hostName->Length / sizeof(WCHAR) + 1, +// NULL, +// 0, +// NI_NAMEREQD +// ) != 0) +// { +// PhDereferenceObject(hostName); +// +// return NULL; +// } +// } +// +// PhTrimToNullTerminatorString(hostName); +// +// return hostName; +//} PPH_STRING PhpGetIp4ReverseNameFromAddress( _In_ IN_ADDR Address diff --git a/ProcessHacker/tokprp.c b/ProcessHacker/tokprp.c index 8ab35d421ed0..c09c89c4252f 100644 --- a/ProcessHacker/tokprp.c +++ b/ProcessHacker/tokprp.c @@ -22,6 +22,7 @@ */ #include +#include #include #include #include @@ -3213,9 +3214,9 @@ PPH_STRING PhpGetTokenAppContainerFolderPath( appContainerSid = PhSidToStringSid(TokenAppContainerSid); - if (GetAppContainerFolderPath) + if (GetAppContainerFolderPath_Import()) { - if (SUCCEEDED(GetAppContainerFolderPath(appContainerSid->Buffer, &folderPath))) + if (SUCCEEDED(GetAppContainerFolderPath_Import()(appContainerSid->Buffer, &folderPath))) { appContainerFolderPath = PhCreateString(folderPath); CoTaskMemFree(folderPath); @@ -3236,8 +3237,8 @@ PPH_STRING PhpGetTokenAppContainerRegistryPath( if (NT_SUCCESS(PhImpersonateToken(NtCurrentThread(), TokenHandle))) { - if (GetAppContainerRegistryLocation) - GetAppContainerRegistryLocation(KEY_READ, ®istryHandle); + if (GetAppContainerRegistryLocation_Import()) + GetAppContainerRegistryLocation_Import()(KEY_READ, ®istryHandle); PhRevertImpersonationToken(NtCurrentThread()); } @@ -3344,27 +3345,10 @@ INT_PTR CALLBACK PhpTokenContainerPageProc( { if (appContainerInfo->TokenAppContainer) { - static PH_INITONCE initOnce = PH_INITONCE_INIT; - static NTSTATUS (NTAPI* RtlGetAppContainerSidType_I)( - _In_ PSID AppContainerSid, - _Out_ PAPPCONTAINER_SID_TYPE AppContainerSidType - ) = NULL; - static NTSTATUS (NTAPI* RtlGetAppContainerParent_I)( - _In_ PSID AppContainerSid, - _Out_ PSID* AppContainerSidParent - ) = NULL; - - if (PhBeginInitOnce(&initOnce)) - { - RtlGetAppContainerSidType_I = PhGetDllProcedureAddress(L"ntdll.dll", "RtlGetAppContainerSidType", 0); - RtlGetAppContainerParent_I = PhGetDllProcedureAddress(L"ntdll.dll", "RtlGetAppContainerParent", 0); - PhEndInitOnce(&initOnce); - } - - if (RtlGetAppContainerSidType_I) - RtlGetAppContainerSidType_I(appContainerInfo->TokenAppContainer, &appContainerSidType); - if (RtlGetAppContainerParent_I) - RtlGetAppContainerParent_I(appContainerInfo->TokenAppContainer, &appContainerSidParent); + if (RtlGetAppContainerSidType_Import()) + RtlGetAppContainerSidType_Import()(appContainerInfo->TokenAppContainer, &appContainerSidType); + if (RtlGetAppContainerParent_Import()) + RtlGetAppContainerParent_Import()(appContainerInfo->TokenAppContainer, &appContainerSidParent); appContainerName = PhGetAppContainerName(appContainerInfo->TokenAppContainer); appContainerSid = PhSidToStringSid(appContainerInfo->TokenAppContainer); diff --git a/phlib/apiimport.c b/phlib/apiimport.c index 1b3e1acc7928..d701fac00136 100644 --- a/phlib/apiimport.c +++ b/phlib/apiimport.c @@ -62,3 +62,14 @@ PH_DEFINE_IMPORT(L"ntdll.dll", NtQueryInformationEnlistment); PH_DEFINE_IMPORT(L"ntdll.dll", NtQueryInformationResourceManager); PH_DEFINE_IMPORT(L"ntdll.dll", NtQueryInformationTransaction); PH_DEFINE_IMPORT(L"ntdll.dll", NtQueryInformationTransactionManager); + +PH_DEFINE_IMPORT(L"ntdll.dll", RtlGetTokenNamedObjectPath); +PH_DEFINE_IMPORT(L"ntdll.dll", RtlGetAppContainerNamedObjectPath); +PH_DEFINE_IMPORT(L"ntdll.dll", RtlGetAppContainerSidType); +PH_DEFINE_IMPORT(L"ntdll.dll", RtlGetAppContainerParent); +PH_DEFINE_IMPORT(L"ntdll.dll", RtlDeriveCapabilitySidsFromName); + +PH_DEFINE_IMPORT(L"userenv.dll", GetAppContainerRegistryLocation); +PH_DEFINE_IMPORT(L"userenv.dll", GetAppContainerFolderPath); + +PH_DEFINE_IMPORT(L"advapi32.dll", ConvertSecurityDescriptorToStringSecurityDescriptorW); diff --git a/phlib/include/apiimport.h b/phlib/include/apiimport.h index 05b895ae24e1..dc35d3311387 100644 --- a/phlib/include/apiimport.h +++ b/phlib/include/apiimport.h @@ -35,6 +35,53 @@ typedef NTSTATUS (NTAPI *_NtQueryInformationTransactionManager)( _Out_opt_ PULONG ReturnLength ); +typedef NTSTATUS (NTAPI* _RtlGetTokenNamedObjectPath)( + _In_ HANDLE Token, + _In_opt_ PSID Sid, + _Out_ PUNICODE_STRING ObjectPath + ); + +typedef NTSTATUS (NTAPI* _RtlGetAppContainerNamedObjectPath)( + _In_opt_ HANDLE Token, + _In_opt_ PSID AppContainerSid, + _In_ BOOLEAN RelativePath, + _Out_ PUNICODE_STRING ObjectPath + ); + +typedef NTSTATUS (NTAPI* _RtlGetAppContainerSidType)( + _In_ PSID AppContainerSid, + _Out_ PAPPCONTAINER_SID_TYPE AppContainerSidType + ); + +typedef NTSTATUS (NTAPI* _RtlGetAppContainerParent)( + _In_ PSID AppContainerSid, + _Out_ PSID* AppContainerSidParent + ); + +typedef NTSTATUS (NTAPI* _RtlDeriveCapabilitySidsFromName)( + _Inout_ PUNICODE_STRING UnicodeString, + _Out_ PSID CapabilityGroupSid, + _Out_ PSID CapabilitySid + ); + +typedef HRESULT (WINAPI* _GetAppContainerRegistryLocation)( + _In_ REGSAM desiredAccess, + _Outptr_ PHKEY phAppContainerKey + ); + +typedef HRESULT (WINAPI* _GetAppContainerFolderPath)( + _In_ PCWSTR pszAppContainerSid, + _Outptr_ PWSTR* ppszPath + ); + +typedef BOOL (WINAPI* _ConvertSecurityDescriptorToStringSecurityDescriptorW)( + _In_ PSECURITY_DESCRIPTOR SecurityDescriptor, + _In_ DWORD RequestedStringSDRevision, + _In_ SECURITY_INFORMATION SecurityInformation, + _Outptr_ LPWSTR* StringSecurityDescriptor, + _Out_opt_ PULONG StringSecurityDescriptorLen + ); + #define PH_DECLARE_IMPORT(Name) _##Name Name##_Import(VOID) PH_DECLARE_IMPORT(NtQueryInformationEnlistment); @@ -42,4 +89,15 @@ PH_DECLARE_IMPORT(NtQueryInformationResourceManager); PH_DECLARE_IMPORT(NtQueryInformationTransaction); PH_DECLARE_IMPORT(NtQueryInformationTransactionManager); +PH_DECLARE_IMPORT(RtlGetTokenNamedObjectPath); +PH_DECLARE_IMPORT(RtlGetAppContainerNamedObjectPath); +PH_DECLARE_IMPORT(RtlGetAppContainerSidType); +PH_DECLARE_IMPORT(RtlGetAppContainerParent); +PH_DECLARE_IMPORT(RtlDeriveCapabilitySidsFromName); + +PH_DECLARE_IMPORT(GetAppContainerRegistryLocation); +PH_DECLARE_IMPORT(GetAppContainerFolderPath); + +PH_DECLARE_IMPORT(ConvertSecurityDescriptorToStringSecurityDescriptorW); + #endif diff --git a/phlib/lsasup.c b/phlib/lsasup.c index 3141fc5529a4..e6bce68e4826 100644 --- a/phlib/lsasup.c +++ b/phlib/lsasup.c @@ -29,6 +29,7 @@ */ #include +#include #include NTSTATUS PhOpenLsaPolicy( @@ -625,17 +626,12 @@ VOID PhInitializeCapabilitySidCache( _Inout_ PPH_ARRAY CapabilitySidArrayList ) { - NTSTATUS (NTAPI *RtlDeriveCapabilitySidsFromName_I)( - _Inout_ PUNICODE_STRING UnicodeString, - _Out_ PSID CapabilityGroupSid, - _Out_ PSID CapabilitySid - ); PPH_STRING applicationDirectory; PPH_STRING capabilityListString = NULL; PH_STRINGREF namePart; PH_STRINGREF remainingPart; - if (!(RtlDeriveCapabilitySidsFromName_I = PhGetDllProcedureAddress(L"ntdll.dll", "RtlDeriveCapabilitySidsFromName", 0))) + if (!RtlDeriveCapabilitySidsFromName_Import()) return; if (applicationDirectory = PhGetApplicationDirectory()) @@ -673,7 +669,7 @@ VOID PhInitializeCapabilitySidCache( if (!PhStringRefToUnicodeString(&namePart, &capabilityNameUs)) continue; - if (NT_SUCCESS(RtlDeriveCapabilitySidsFromName_I( + if (NT_SUCCESS(RtlDeriveCapabilitySidsFromName_Import()( &capabilityNameUs, capabilityGroupSid, capabilitySid diff --git a/phlib/native.c b/phlib/native.c index dcd444d144f4..43fb48b494ce 100644 --- a/phlib/native.c +++ b/phlib/native.c @@ -444,7 +444,10 @@ PPH_STRING PhGetSecurityDescriptorAsString( ULONG stringSecurityDescriptorLength; PWSTR stringSecurityDescriptor; - if (ConvertSecurityDescriptorToStringSecurityDescriptor( + if (!ConvertSecurityDescriptorToStringSecurityDescriptorW_Import()) + return NULL; + + if (ConvertSecurityDescriptorToStringSecurityDescriptorW_Import()( SecurityDescriptor, SDDL_REVISION, SecurityInformation, @@ -1503,7 +1506,7 @@ NTSTATUS PhLoadDllProcess( if (!isModule32) { #endif - threadStart = PhGetModuleProcAddress(L"kernel32.dll", "LoadLibraryW"); + threadStart = PhGetDllProcedureAddress(L"kernel32.dll", "LoadLibraryW", 0); #ifdef _WIN64 } else @@ -1750,10 +1753,10 @@ NTSTATUS PhSetEnvironmentVariableRemote( PVOID setEnvironmentVariableW = NULL; HANDLE threadHandle = NULL; - nameAllocationSize = Name->Length + sizeof(WCHAR); + nameAllocationSize = Name->Length + sizeof(UNICODE_NULL); if (Value) - valueAllocationSize = Value->Length + sizeof(WCHAR); + valueAllocationSize = Value->Length + sizeof(UNICODE_NULL); #ifdef _WIN64 if (!NT_SUCCESS(status = PhGetProcessIsWow64(ProcessHandle, &isWow64))) @@ -1790,6 +1793,7 @@ NTSTATUS PhSetEnvironmentVariableRemote( { goto CleanupExit; } + if (!NT_SUCCESS(status = PhGetProcedureAddressRemote( ProcessHandle, kernel32FileName->Buffer, @@ -1813,6 +1817,7 @@ NTSTATUS PhSetEnvironmentVariableRemote( { goto CleanupExit; } + if (!NT_SUCCESS(status = NtWriteVirtualMemory( ProcessHandle, nameBaseAddress, @@ -1837,6 +1842,7 @@ NTSTATUS PhSetEnvironmentVariableRemote( { goto CleanupExit; } + if (!NT_SUCCESS(status = NtWriteVirtualMemory( ProcessHandle, valueBaseAddress, @@ -2200,34 +2206,22 @@ NTSTATUS PhGetTokenNamedObjectPath( _Out_ PPH_STRING* ObjectPath ) { - static PH_INITONCE initOnce = PH_INITONCE_INIT; - static NTSTATUS(WINAPI * RtlGetTokenNamedObjectPath_I)( - _In_ HANDLE Token, - _In_opt_ PSID Sid, - _Out_ PUNICODE_STRING ObjectPath - ) = NULL; NTSTATUS status; - UNICODE_STRING namedObjectPathUs; + UNICODE_STRING objectPathUs; - if (PhBeginInitOnce(&initOnce)) - { - RtlGetTokenNamedObjectPath_I = PhGetDllProcedureAddress(L"ntdll.dll", "RtlGetTokenNamedObjectPath", 0); - PhEndInitOnce(&initOnce); - } - - if (!RtlGetTokenNamedObjectPath_I) - return STATUS_UNSUCCESSFUL; + if (!RtlGetTokenNamedObjectPath_Import()) + return STATUS_NOT_SUPPORTED; - status = RtlGetTokenNamedObjectPath_I( + status = RtlGetTokenNamedObjectPath_Import()( TokenHandle, Sid, - &namedObjectPathUs + &objectPathUs ); if (NT_SUCCESS(status)) { - *ObjectPath = PhCreateStringFromUnicodeString(&namedObjectPathUs); - RtlFreeUnicodeString(&namedObjectPathUs); + *ObjectPath = PhCreateStringFromUnicodeString(&objectPathUs); + RtlFreeUnicodeString(&objectPathUs); } return status; @@ -2240,36 +2234,23 @@ NTSTATUS PhGetAppContainerNamedObjectPath( _Out_ PPH_STRING* ObjectPath ) { - static PH_INITONCE initOnce = PH_INITONCE_INIT; - static NTSTATUS (WINAPI * RtlGetAppContainerNamedObjectPath_I)( - _In_opt_ HANDLE Token, - _In_opt_ PSID AppContainerSid, - _In_ BOOLEAN RelativePath, - _Out_ PUNICODE_STRING ObjectPath - ) = NULL; NTSTATUS status; - UNICODE_STRING namedObjectPathUs; - - if (PhBeginInitOnce(&initOnce)) - { - RtlGetAppContainerNamedObjectPath_I = PhGetDllProcedureAddress(L"ntdll.dll", "RtlGetAppContainerNamedObjectPath", 0); - PhEndInitOnce(&initOnce); - } + UNICODE_STRING objectPathUs; - if (!RtlGetAppContainerNamedObjectPath_I) + if (!RtlGetAppContainerNamedObjectPath_Import()) return STATUS_UNSUCCESSFUL; - status = RtlGetAppContainerNamedObjectPath_I( + status = RtlGetAppContainerNamedObjectPath_Import()( TokenHandle, AppContainerSid, RelativePath, - &namedObjectPathUs + &objectPathUs ); if (NT_SUCCESS(status)) { - *ObjectPath = PhCreateStringFromUnicodeString(&namedObjectPathUs); - RtlFreeUnicodeString(&namedObjectPathUs); + *ObjectPath = PhCreateStringFromUnicodeString(&objectPathUs); + RtlFreeUnicodeString(&objectPathUs); } return status; @@ -2281,6 +2262,7 @@ BOOLEAN PhGetTokenSecurityDescriptorAsString( ) { PSECURITY_DESCRIPTOR securityDescriptor; + PPH_STRING securityDescriptorString; if (NT_SUCCESS(PhGetObjectSecurity( TokenHandle, @@ -2290,16 +2272,20 @@ BOOLEAN PhGetTokenSecurityDescriptorAsString( &securityDescriptor ))) { - *SecurityDescriptorString = PhGetSecurityDescriptorAsString( + if (securityDescriptorString = PhGetSecurityDescriptorAsString( OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION | LABEL_SECURITY_INFORMATION | ATTRIBUTE_SECURITY_INFORMATION | SCOPE_SECURITY_INFORMATION, securityDescriptor - ); + )) + { + *SecurityDescriptorString = securityDescriptorString; - PhFree(securityDescriptor); + PhFree(securityDescriptor); + return TRUE; + } - return TRUE; + PhFree(securityDescriptor); } return FALSE; @@ -4347,30 +4333,34 @@ PVOID PhGetDllHandle( _In_ PWSTR DllName ) { - UNICODE_STRING dllName; - PVOID dllHandle; - - RtlInitUnicodeString(&dllName, DllName); + return PhGetLoaderEntryDllBase(DllName); - if (NT_SUCCESS(LdrGetDllHandle(NULL, NULL, &dllName, &dllHandle))) - return dllHandle; - else - return NULL; + //UNICODE_STRING dllName; + //PVOID dllHandle; + // + //RtlInitUnicodeString(&dllName, DllName); + // + //if (NT_SUCCESS(LdrGetDllHandle(NULL, NULL, &dllName, &dllHandle))) + // return dllHandle; + //else + // return NULL; } PVOID PhGetModuleProcAddress( _In_ PWSTR ModuleName, - _In_ PSTR ProcName + _In_ PSTR ProcedureName ) { - PVOID module; - - module = PhGetDllHandle(ModuleName); + return PhGetDllProcedureAddress(ModuleName, ProcedureName, 0); - if (module) - return PhGetProcedureAddress(module, ProcName, 0); - else - return NULL; + //PVOID module; + // + //module = PhGetDllHandle(ModuleName); + // + //if (module) + // return PhGetProcedureAddress(module, ProcName, 0); + //else + // return NULL; } PVOID PhGetProcedureAddress( @@ -4379,34 +4369,36 @@ PVOID PhGetProcedureAddress( _In_opt_ ULONG ProcedureNumber ) { - NTSTATUS status; - ANSI_STRING procedureName; - PVOID procedureAddress; - - if (ProcedureName) - { - RtlInitAnsiString(&procedureName, ProcedureName); - status = LdrGetProcedureAddress( - DllHandle, - &procedureName, - 0, - &procedureAddress - ); - } - else - { - status = LdrGetProcedureAddress( - DllHandle, - NULL, - ProcedureNumber, - &procedureAddress - ); - } - - if (!NT_SUCCESS(status)) - return NULL; - - return procedureAddress; + return PhGetDllBaseProcedureAddress(DllHandle, ProcedureName, (USHORT)ProcedureNumber); + + //NTSTATUS status; + //ANSI_STRING procedureName; + //PVOID procedureAddress; + // + //if (ProcedureName) + //{ + // RtlInitAnsiString(&procedureName, ProcedureName); + // status = LdrGetProcedureAddress( + // DllHandle, + // &procedureName, + // 0, + // &procedureAddress + // ); + //} + //else + //{ + // status = LdrGetProcedureAddress( + // DllHandle, + // NULL, + // ProcedureNumber, + // &procedureAddress + // ); + //} + // + //if (!NT_SUCCESS(status)) + // return NULL; + // + //return procedureAddress; } typedef struct _GET_PROCEDURE_ADDRESS_REMOTE_CONTEXT From da58a7ea0e06e110e034f53b20a31509bf58dd62 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 27 Apr 2019 21:20:40 +0200 Subject: [PATCH 1833/2058] Fix querying WSL process information when signature checking disabled --- ProcessHacker/procprv.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/ProcessHacker/procprv.c b/ProcessHacker/procprv.c index 70d7c85381ca..c74d8e70329e 100644 --- a/ProcessHacker/procprv.c +++ b/ProcessHacker/procprv.c @@ -993,8 +993,7 @@ VOID PhpQueueProcessQueryStage1( PhInitializeWorkQueueEnvironment(&environment); environment.BasePriority = THREAD_PRIORITY_BELOW_NORMAL; - PhQueueItemWorkQueueEx(PhGetGlobalWorkQueue(), PhpProcessQueryStage1Worker, ProcessItem, - NULL, &environment); + PhQueueItemWorkQueueEx(PhGetGlobalWorkQueue(), PhpProcessQueryStage1Worker, ProcessItem, NULL, &environment); } VOID PhpQueueProcessQueryStage2( @@ -1003,9 +1002,6 @@ VOID PhpQueueProcessQueryStage2( { PH_WORK_QUEUE_ENVIRONMENT environment; - if (!PhEnableProcessQueryStage2) - return; - PhReferenceObject(ProcessItem); PhInitializeWorkQueueEnvironment(&environment); @@ -1013,8 +1009,7 @@ VOID PhpQueueProcessQueryStage2( environment.IoPriority = IoPriorityVeryLow; environment.PagePriority = MEMORY_PRIORITY_VERY_LOW; - PhQueueItemWorkQueueEx(PhGetGlobalWorkQueue(), PhpProcessQueryStage2Worker, ProcessItem, - NULL, &environment); + PhQueueItemWorkQueueEx(PhGetGlobalWorkQueue(), PhpProcessQueryStage2Worker, ProcessItem, NULL, &environment); } VOID PhpFillProcessItemStage1( From 000dd29148e4354a0a9589df0e9279573a9ee0ad Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 27 Apr 2019 21:31:54 +0200 Subject: [PATCH 1834/2058] Update macro usage --- ProcessHacker/anawait.c | 6 ++-- ProcessHacker/appsup.c | 20 +++++------ ProcessHacker/findobj.c | 8 ++--- ProcessHacker/hndllist.c | 14 ++++---- ProcessHacker/hndlmenu.c | 4 +-- ProcessHacker/hndlprv.c | 2 +- ProcessHacker/memlists.c | 52 ++++++++++++++--------------- ProcessHacker/memrslt.c | 7 ++-- ProcessHacker/modlist.c | 44 ++++++++++++------------ ProcessHacker/mwpgproc.c | 4 +-- ProcessHacker/pagfiles.c | 6 ++-- ProcessHacker/plugman.c | 14 ++++---- ProcessHacker/sysscmem.c | 72 ++++++++++++++++++++-------------------- phlib/basesup.c | 2 +- phlib/filepool.c | 34 +++++++++---------- phlib/guisup.c | 2 +- phlib/workqueue.c | 2 +- 17 files changed, 147 insertions(+), 146 deletions(-) diff --git a/ProcessHacker/anawait.c b/ProcessHacker/anawait.c index 8fda48493b59..d33b1e4d661e 100644 --- a/ProcessHacker/anawait.c +++ b/ProcessHacker/anawait.c @@ -97,9 +97,9 @@ PPH_STRING PhpaGetAlpcInformation( ); static PH_INITONCE ServiceNumbersInitOnce = PH_INITONCE_INIT; -static USHORT NumberForWfso = -1; -static USHORT NumberForWfmo = -1; -static USHORT NumberForRf = -1; +static USHORT NumberForWfso = USHRT_MAX; +static USHORT NumberForWfmo = USHRT_MAX; +static USHORT NumberForRf = USHRT_MAX; VOID PhUiAnalyzeWaitThread( _In_ HWND hWnd, diff --git a/ProcessHacker/appsup.c b/ProcessHacker/appsup.c index ebc1c1ef5b2f..4986206d7212 100644 --- a/ProcessHacker/appsup.c +++ b/ProcessHacker/appsup.c @@ -1416,18 +1416,18 @@ VOID PhInitializeTreeNewColumnMenuEx( resetSortMenuItem = PhCreateEMenuItem(0, PH_TN_COLUMN_MENU_RESET_SORT_ID, L"Reset sort", NULL, NULL); } - PhInsertEMenuItem(Data->Menu, sizeColumnToFitMenuItem, -1); - PhInsertEMenuItem(Data->Menu, sizeAllColumnsToFitMenuItem, -1); + PhInsertEMenuItem(Data->Menu, sizeColumnToFitMenuItem, ULONG_MAX); + PhInsertEMenuItem(Data->Menu, sizeAllColumnsToFitMenuItem, ULONG_MAX); if (!(Flags & PH_TN_COLUMN_MENU_NO_VISIBILITY)) { - PhInsertEMenuItem(Data->Menu, hideColumnMenuItem, -1); + PhInsertEMenuItem(Data->Menu, hideColumnMenuItem, ULONG_MAX); if (resetSortMenuItem) - PhInsertEMenuItem(Data->Menu, resetSortMenuItem, -1); + PhInsertEMenuItem(Data->Menu, resetSortMenuItem, ULONG_MAX); - PhInsertEMenuItem(Data->Menu, PhCreateEMenuSeparator(), -1); - PhInsertEMenuItem(Data->Menu, chooseColumnsMenuItem, -1); + PhInsertEMenuItem(Data->Menu, PhCreateEMenuSeparator(), ULONG_MAX); + PhInsertEMenuItem(Data->Menu, chooseColumnsMenuItem, ULONG_MAX); if (TreeNew_GetFixedColumn(Data->TreeNewHandle)) minimumNumberOfColumns = 2; // don't allow user to remove all normal columns (the fixed column can never be removed) @@ -1445,7 +1445,7 @@ VOID PhInitializeTreeNewColumnMenuEx( else { if (resetSortMenuItem) - PhInsertEMenuItem(Data->Menu, resetSortMenuItem, -1); + PhInsertEMenuItem(Data->Menu, resetSortMenuItem, ULONG_MAX); } if (!Data->MouseEvent || !Data->MouseEvent->Column) @@ -1646,7 +1646,7 @@ VOID PhRemoveTreeNewFilter( index = PhFindItemList(Support->FilterList, Entry); - if (index != -1) + if (index != ULONG_MAX) { PhRemoveItemList(Support->FilterList, index); PhFree(Entry); @@ -1940,7 +1940,7 @@ BOOLEAN PhpSelectFavoriteInRegedit( HMENU favoritesMenu; ULONG count; ULONG i; - ULONG id = -1; + ULONG id = ULONG_MAX; if (!(menu = GetMenu(RegeditWindow))) return FALSE; @@ -1988,7 +1988,7 @@ BOOLEAN PhpSelectFavoriteInRegedit( } } - if (id == -1) + if (id == ULONG_MAX) return FALSE; // Activate our entry. diff --git a/ProcessHacker/findobj.c b/ProcessHacker/findobj.c index fb07e9d65ad7..c64c8597a0e6 100644 --- a/ProcessHacker/findobj.c +++ b/ProcessHacker/findobj.c @@ -294,7 +294,7 @@ VOID PhpRemoveHandleObjectNode( PhRemoveEntryHashtable(Context->NodeHashtable, &Node); - if ((index = PhFindItemList(Context->NodeList, Node)) != -1) + if ((index = PhFindItemList(Context->NodeList, Node)) != ULONG_MAX) { PhRemoveItemList(Context->NodeList, index); } @@ -551,8 +551,8 @@ VOID PhpInitializeHandleObjectTree( PhAddTreeNewColumn(Context->TreeNewHandle, PH_OBJECT_SEARCH_TREE_COLUMN_NAME, TRUE, L"Name", 200, PH_ALIGN_LEFT, 2, 0); PhAddTreeNewColumn(Context->TreeNewHandle, PH_OBJECT_SEARCH_TREE_COLUMN_HANDLE, TRUE, L"Handle", 80, PH_ALIGN_LEFT, 3, 0); - PhAddTreeNewColumn(Context->TreeNewHandle, PH_OBJECT_SEARCH_TREE_COLUMN_OBJECTADDRESS, FALSE, L"Object address", 80, PH_ALIGN_LEFT, -1, 0); - PhAddTreeNewColumn(Context->TreeNewHandle, PH_OBJECT_SEARCH_TREE_COLUMN_ORIGINALNAME, FALSE, L"Original name", 200, PH_ALIGN_LEFT, -1, 0); + PhAddTreeNewColumn(Context->TreeNewHandle, PH_OBJECT_SEARCH_TREE_COLUMN_OBJECTADDRESS, FALSE, L"Object address", 80, PH_ALIGN_LEFT, ULONG_MAX, 0); + PhAddTreeNewColumn(Context->TreeNewHandle, PH_OBJECT_SEARCH_TREE_COLUMN_ORIGINALNAME, FALSE, L"Original name", 200, PH_ALIGN_LEFT, ULONG_MAX, 0); TreeNew_SetTriState(Context->TreeNewHandle, TRUE); @@ -1401,7 +1401,7 @@ INT_PTR CALLBACK PhpFindObjectsDlgProc( contextMenuEvent->Location.y ); - if (selectedItem && selectedItem->Id != -1) + if (selectedItem && selectedItem->Id != ULONG_MAX) { BOOLEAN handled = FALSE; diff --git a/ProcessHacker/hndllist.c b/ProcessHacker/hndllist.c index 7f16065c2e4a..d67258febddc 100644 --- a/ProcessHacker/hndllist.c +++ b/ProcessHacker/hndllist.c @@ -99,12 +99,12 @@ VOID PhInitializeHandleList( PhAddTreeNewColumn(hwnd, PHHNTLC_NAME, TRUE, L"Name", 200, PH_ALIGN_LEFT, 1, 0); PhAddTreeNewColumn(hwnd, PHHNTLC_GRANTEDACCESSSYMBOLIC, TRUE, L"Granted access (symbolic)", 140, PH_ALIGN_LEFT, 2, 0); - PhAddTreeNewColumn(hwnd, PHHNTLC_HANDLE, FALSE, L"Handle", 80, PH_ALIGN_LEFT, -1, 0); - PhAddTreeNewColumn(hwnd, PHHNTLC_OBJECTADDRESS, FALSE, L"Object address", 80, PH_ALIGN_LEFT, -1, 0); - PhAddTreeNewColumnEx(hwnd, PHHNTLC_ATTRIBUTES, FALSE, L"Attributes", 120, PH_ALIGN_LEFT, -1, 0, TRUE); - PhAddTreeNewColumn(hwnd, PHHNTLC_GRANTEDACCESS, FALSE, L"Granted access", 80, PH_ALIGN_LEFT, -1, 0); - PhAddTreeNewColumn(hwnd, PHHNTLC_ORIGINALNAME, FALSE, L"Original name", 200, PH_ALIGN_LEFT, -1, 0); - PhAddTreeNewColumnEx(hwnd, PHHNTLC_FILESHAREACCESS, FALSE, L"File share access", 50, PH_ALIGN_LEFT, -1, 0, TRUE); + PhAddTreeNewColumn(hwnd, PHHNTLC_HANDLE, FALSE, L"Handle", 80, PH_ALIGN_LEFT, ULONG_MAX, 0); + PhAddTreeNewColumn(hwnd, PHHNTLC_OBJECTADDRESS, FALSE, L"Object address", 80, PH_ALIGN_LEFT, ULONG_MAX, 0); + PhAddTreeNewColumnEx(hwnd, PHHNTLC_ATTRIBUTES, FALSE, L"Attributes", 120, PH_ALIGN_LEFT, ULONG_MAX, 0, TRUE); + PhAddTreeNewColumn(hwnd, PHHNTLC_GRANTEDACCESS, FALSE, L"Granted access", 80, PH_ALIGN_LEFT, ULONG_MAX, 0); + PhAddTreeNewColumn(hwnd, PHHNTLC_ORIGINALNAME, FALSE, L"Original name", 200, PH_ALIGN_LEFT, ULONG_MAX, 0); + PhAddTreeNewColumnEx(hwnd, PHHNTLC_FILESHAREACCESS, FALSE, L"File share access", 50, PH_ALIGN_LEFT, ULONG_MAX, 0, TRUE); TreeNew_SetRedraw(hwnd, TRUE); @@ -314,7 +314,7 @@ VOID PhpRemoveHandleNode( // Remove from list and cleanup. - if ((index = PhFindItemList(Context->NodeList, HandleNode)) != -1) + if ((index = PhFindItemList(Context->NodeList, HandleNode)) != ULONG_MAX) PhRemoveItemList(Context->NodeList, index); PhpDestroyHandleNode(HandleNode); diff --git a/ProcessHacker/hndlmenu.c b/ProcessHacker/hndlmenu.c index 6f317ed61656..6a8b90711218 100644 --- a/ProcessHacker/hndlmenu.c +++ b/ProcessHacker/hndlmenu.c @@ -240,7 +240,7 @@ VOID PhShowHandleObjectProperties1( PVOID viewBase = NULL; BOOLEAN tooBig = FALSE; - PhGetHandleInformation(NtCurrentProcess(), handle, -1, NULL, NULL, NULL, §ionName); + PhGetHandleInformation(NtCurrentProcess(), handle, ULONG_MAX, NULL, NULL, NULL, §ionName); if (NT_SUCCESS(status = PhGetSectionBasicInformation(handle, &basicInfo))) { @@ -289,7 +289,7 @@ VOID PhShowHandleObjectProperties1( showMemoryEditor->ProcessId = NtCurrentProcessId(); showMemoryEditor->BaseAddress = viewBase; showMemoryEditor->RegionSize = viewSize; - showMemoryEditor->SelectOffset = -1; + showMemoryEditor->SelectOffset = ULONG_MAX; showMemoryEditor->SelectLength = 0; showMemoryEditor->Title = sectionName ? PhConcatStrings2(L"Section - ", sectionName->Buffer) : PhCreateString(L"Section"); showMemoryEditor->Flags = PH_MEMORY_EDITOR_UNMAP_VIEW_OF_SECTION; diff --git a/ProcessHacker/hndlprv.c b/ProcessHacker/hndlprv.c index 6d9437065568..cd55a44af6ef 100644 --- a/ProcessHacker/hndlprv.c +++ b/ProcessHacker/hndlprv.c @@ -436,7 +436,7 @@ VOID PhHandleProviderUpdate( ) { static PH_INITONCE initOnce = PH_INITONCE_INIT; - static ULONG fileObjectTypeIndex = -1; + static ULONG fileObjectTypeIndex = ULONG_MAX; PPH_HANDLE_PROVIDER handleProvider = (PPH_HANDLE_PROVIDER)Object; PSYSTEM_HANDLE_INFORMATION_EX handleInfo; diff --git a/ProcessHacker/memlists.c b/ProcessHacker/memlists.c index d211b4ffc218..137fa87b759b 100644 --- a/ProcessHacker/memlists.c +++ b/ProcessHacker/memlists.c @@ -102,32 +102,32 @@ static VOID PhpUpdateMemoryListInfo( repurposedPageCount += memoryListInfo.RepurposedPagesByPriority[i]; } - PhSetDialogItemText(hwndDlg, IDC_ZLISTZEROED_V, PhaFormatSize((ULONG64)memoryListInfo.ZeroPageCount * PAGE_SIZE, -1)->Buffer); - PhSetDialogItemText(hwndDlg, IDC_ZLISTFREE_V, PhaFormatSize((ULONG64)memoryListInfo.FreePageCount * PAGE_SIZE, -1)->Buffer); - PhSetDialogItemText(hwndDlg, IDC_ZLISTMODIFIED_V, PhaFormatSize((ULONG64)memoryListInfo.ModifiedPageCount * PAGE_SIZE, -1)->Buffer); - PhSetDialogItemText(hwndDlg, IDC_ZLISTMODIFIEDNOWRITE_V, PhaFormatSize((ULONG64)memoryListInfo.ModifiedNoWritePageCount * PAGE_SIZE, -1)->Buffer); - PhSetDialogItemText(hwndDlg, IDC_ZLISTBAD_V, PhaFormatSize((ULONG64)memoryListInfo.BadPageCount * PAGE_SIZE, -1)->Buffer); - PhSetDialogItemText(hwndDlg, IDC_ZLISTSTANDBY_V, PhaFormatSize((ULONG64)standbyPageCount * PAGE_SIZE, -1)->Buffer); - PhSetDialogItemText(hwndDlg, IDC_ZLISTSTANDBY0_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[0] * PAGE_SIZE, -1)->Buffer); - PhSetDialogItemText(hwndDlg, IDC_ZLISTSTANDBY1_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[1] * PAGE_SIZE, -1)->Buffer); - PhSetDialogItemText(hwndDlg, IDC_ZLISTSTANDBY2_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[2] * PAGE_SIZE, -1)->Buffer); - PhSetDialogItemText(hwndDlg, IDC_ZLISTSTANDBY3_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[3] * PAGE_SIZE, -1)->Buffer); - PhSetDialogItemText(hwndDlg, IDC_ZLISTSTANDBY4_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[4] * PAGE_SIZE, -1)->Buffer); - PhSetDialogItemText(hwndDlg, IDC_ZLISTSTANDBY5_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[5] * PAGE_SIZE, -1)->Buffer); - PhSetDialogItemText(hwndDlg, IDC_ZLISTSTANDBY6_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[6] * PAGE_SIZE, -1)->Buffer); - PhSetDialogItemText(hwndDlg, IDC_ZLISTSTANDBY7_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[7] * PAGE_SIZE, -1)->Buffer); - PhSetDialogItemText(hwndDlg, IDC_ZLISTREPURPOSED_V, PhaFormatSize((ULONG64)repurposedPageCount * PAGE_SIZE, -1)->Buffer); - PhSetDialogItemText(hwndDlg, IDC_ZLISTREPURPOSED0_V, PhaFormatSize((ULONG64)memoryListInfo.RepurposedPagesByPriority[0] * PAGE_SIZE, -1)->Buffer); - PhSetDialogItemText(hwndDlg, IDC_ZLISTREPURPOSED1_V, PhaFormatSize((ULONG64)memoryListInfo.RepurposedPagesByPriority[1] * PAGE_SIZE, -1)->Buffer); - PhSetDialogItemText(hwndDlg, IDC_ZLISTREPURPOSED2_V, PhaFormatSize((ULONG64)memoryListInfo.RepurposedPagesByPriority[2] * PAGE_SIZE, -1)->Buffer); - PhSetDialogItemText(hwndDlg, IDC_ZLISTREPURPOSED3_V, PhaFormatSize((ULONG64)memoryListInfo.RepurposedPagesByPriority[3] * PAGE_SIZE, -1)->Buffer); - PhSetDialogItemText(hwndDlg, IDC_ZLISTREPURPOSED4_V, PhaFormatSize((ULONG64)memoryListInfo.RepurposedPagesByPriority[4] * PAGE_SIZE, -1)->Buffer); - PhSetDialogItemText(hwndDlg, IDC_ZLISTREPURPOSED5_V, PhaFormatSize((ULONG64)memoryListInfo.RepurposedPagesByPriority[5] * PAGE_SIZE, -1)->Buffer); - PhSetDialogItemText(hwndDlg, IDC_ZLISTREPURPOSED6_V, PhaFormatSize((ULONG64)memoryListInfo.RepurposedPagesByPriority[6] * PAGE_SIZE, -1)->Buffer); - PhSetDialogItemText(hwndDlg, IDC_ZLISTREPURPOSED7_V, PhaFormatSize((ULONG64)memoryListInfo.RepurposedPagesByPriority[7] * PAGE_SIZE, -1)->Buffer); + PhSetDialogItemText(hwndDlg, IDC_ZLISTZEROED_V, PhaFormatSize((ULONG64)memoryListInfo.ZeroPageCount * PAGE_SIZE, ULONG_MAX)->Buffer); + PhSetDialogItemText(hwndDlg, IDC_ZLISTFREE_V, PhaFormatSize((ULONG64)memoryListInfo.FreePageCount * PAGE_SIZE, ULONG_MAX)->Buffer); + PhSetDialogItemText(hwndDlg, IDC_ZLISTMODIFIED_V, PhaFormatSize((ULONG64)memoryListInfo.ModifiedPageCount * PAGE_SIZE, ULONG_MAX)->Buffer); + PhSetDialogItemText(hwndDlg, IDC_ZLISTMODIFIEDNOWRITE_V, PhaFormatSize((ULONG64)memoryListInfo.ModifiedNoWritePageCount * PAGE_SIZE, ULONG_MAX)->Buffer); + PhSetDialogItemText(hwndDlg, IDC_ZLISTBAD_V, PhaFormatSize((ULONG64)memoryListInfo.BadPageCount * PAGE_SIZE, ULONG_MAX)->Buffer); + PhSetDialogItemText(hwndDlg, IDC_ZLISTSTANDBY_V, PhaFormatSize((ULONG64)standbyPageCount * PAGE_SIZE, ULONG_MAX)->Buffer); + PhSetDialogItemText(hwndDlg, IDC_ZLISTSTANDBY0_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[0] * PAGE_SIZE, ULONG_MAX)->Buffer); + PhSetDialogItemText(hwndDlg, IDC_ZLISTSTANDBY1_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[1] * PAGE_SIZE, ULONG_MAX)->Buffer); + PhSetDialogItemText(hwndDlg, IDC_ZLISTSTANDBY2_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[2] * PAGE_SIZE, ULONG_MAX)->Buffer); + PhSetDialogItemText(hwndDlg, IDC_ZLISTSTANDBY3_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[3] * PAGE_SIZE, ULONG_MAX)->Buffer); + PhSetDialogItemText(hwndDlg, IDC_ZLISTSTANDBY4_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[4] * PAGE_SIZE, ULONG_MAX)->Buffer); + PhSetDialogItemText(hwndDlg, IDC_ZLISTSTANDBY5_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[5] * PAGE_SIZE, ULONG_MAX)->Buffer); + PhSetDialogItemText(hwndDlg, IDC_ZLISTSTANDBY6_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[6] * PAGE_SIZE, ULONG_MAX)->Buffer); + PhSetDialogItemText(hwndDlg, IDC_ZLISTSTANDBY7_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[7] * PAGE_SIZE, ULONG_MAX)->Buffer); + PhSetDialogItemText(hwndDlg, IDC_ZLISTREPURPOSED_V, PhaFormatSize((ULONG64)repurposedPageCount * PAGE_SIZE, ULONG_MAX)->Buffer); + PhSetDialogItemText(hwndDlg, IDC_ZLISTREPURPOSED0_V, PhaFormatSize((ULONG64)memoryListInfo.RepurposedPagesByPriority[0] * PAGE_SIZE, ULONG_MAX)->Buffer); + PhSetDialogItemText(hwndDlg, IDC_ZLISTREPURPOSED1_V, PhaFormatSize((ULONG64)memoryListInfo.RepurposedPagesByPriority[1] * PAGE_SIZE, ULONG_MAX)->Buffer); + PhSetDialogItemText(hwndDlg, IDC_ZLISTREPURPOSED2_V, PhaFormatSize((ULONG64)memoryListInfo.RepurposedPagesByPriority[2] * PAGE_SIZE, ULONG_MAX)->Buffer); + PhSetDialogItemText(hwndDlg, IDC_ZLISTREPURPOSED3_V, PhaFormatSize((ULONG64)memoryListInfo.RepurposedPagesByPriority[3] * PAGE_SIZE, ULONG_MAX)->Buffer); + PhSetDialogItemText(hwndDlg, IDC_ZLISTREPURPOSED4_V, PhaFormatSize((ULONG64)memoryListInfo.RepurposedPagesByPriority[4] * PAGE_SIZE, ULONG_MAX)->Buffer); + PhSetDialogItemText(hwndDlg, IDC_ZLISTREPURPOSED5_V, PhaFormatSize((ULONG64)memoryListInfo.RepurposedPagesByPriority[5] * PAGE_SIZE, ULONG_MAX)->Buffer); + PhSetDialogItemText(hwndDlg, IDC_ZLISTREPURPOSED6_V, PhaFormatSize((ULONG64)memoryListInfo.RepurposedPagesByPriority[6] * PAGE_SIZE, ULONG_MAX)->Buffer); + PhSetDialogItemText(hwndDlg, IDC_ZLISTREPURPOSED7_V, PhaFormatSize((ULONG64)memoryListInfo.RepurposedPagesByPriority[7] * PAGE_SIZE, ULONG_MAX)->Buffer); if (WindowsVersion >= WINDOWS_8) - PhSetDialogItemText(hwndDlg, IDC_ZLISTMODIFIEDPAGEFILE_V, PhaFormatSize((ULONG64)memoryListInfo.ModifiedPageCountPageFile * PAGE_SIZE, -1)->Buffer); + PhSetDialogItemText(hwndDlg, IDC_ZLISTMODIFIEDPAGEFILE_V, PhaFormatSize((ULONG64)memoryListInfo.ModifiedPageCountPageFile * PAGE_SIZE, ULONG_MAX)->Buffer); else PhSetDialogItemText(hwndDlg, IDC_ZLISTMODIFIEDPAGEFILE_V, L"N/A"); } @@ -213,7 +213,7 @@ INT_PTR CALLBACK PhpMemoryListsDlgProc( RECT buttonRect; POINT point; PPH_EMENU_ITEM selectedItem; - SYSTEM_MEMORY_LIST_COMMAND command = -1; + SYSTEM_MEMORY_LIST_COMMAND command = ULONG_MAX; menu = PhCreateEMenu(); PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_EMPTY_COMBINEMEMORYLISTS, L"&Combine memory lists", NULL, NULL), ULONG_MAX); @@ -276,7 +276,7 @@ INT_PTR CALLBACK PhpMemoryListsDlgProc( } } - if (command != -1) + if (command != ULONG_MAX) { NTSTATUS status; diff --git a/ProcessHacker/memrslt.c b/ProcessHacker/memrslt.c index 20e97d60992a..7b5fe8a7ebe1 100644 --- a/ProcessHacker/memrslt.c +++ b/ProcessHacker/memrslt.c @@ -633,9 +633,10 @@ INT_PTR CALLBACK PhpMemoryResultsDlgProc( ULONG filterType = 0; menu = PhCreateEMenu(); - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_MEMORY_READWRITEMEMORY, L"Read/Write memory", NULL, NULL), -1); - PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), -1); - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, IDC_COPY, L"Copy", NULL, NULL), -1); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_MEMORY_READWRITEMEMORY, L"Read/Write memory", NULL, NULL), ULONG_MAX); + PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, IDC_COPY, L"Copy", NULL, NULL), ULONG_MAX); + GetCursorPos(&point); selectedItem = PhShowEMenu( diff --git a/ProcessHacker/modlist.c b/ProcessHacker/modlist.c index 0466fcda7817..4f3af9019d44 100644 --- a/ProcessHacker/modlist.c +++ b/ProcessHacker/modlist.c @@ -99,23 +99,23 @@ VOID PhInitializeModuleList( PhAddTreeNewColumnEx(Context->TreeNewHandle, PHMOTLC_SIZE, TRUE, L"Size", 60, PH_ALIGN_RIGHT, 1, DT_RIGHT, TRUE); PhAddTreeNewColumn(Context->TreeNewHandle, PHMOTLC_DESCRIPTION, TRUE, L"Description", 160, PH_ALIGN_LEFT, 2, 0); - PhAddTreeNewColumn(Context->TreeNewHandle, PHMOTLC_COMPANYNAME, FALSE, L"Company name", 180, PH_ALIGN_LEFT, -1, 0); - PhAddTreeNewColumn(Context->TreeNewHandle, PHMOTLC_VERSION, FALSE, L"Version", 100, PH_ALIGN_LEFT, -1, 0); - PhAddTreeNewColumn(Context->TreeNewHandle, PHMOTLC_FILENAME, FALSE, L"File name", 180, PH_ALIGN_LEFT, -1, DT_PATH_ELLIPSIS); - - PhAddTreeNewColumn(Context->TreeNewHandle, PHMOTLC_TYPE, FALSE, L"Type", 80, PH_ALIGN_LEFT, -1, 0); - PhAddTreeNewColumnEx(Context->TreeNewHandle, PHMOTLC_LOADCOUNT, FALSE, L"Load count", 40, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); - PhAddTreeNewColumn(Context->TreeNewHandle, PHMOTLC_VERIFICATIONSTATUS, FALSE, L"Verification status", 70, PH_ALIGN_LEFT, -1, 0); - PhAddTreeNewColumn(Context->TreeNewHandle, PHMOTLC_VERIFIEDSIGNER, FALSE, L"Verified signer", 100, PH_ALIGN_LEFT, -1, 0); - PhAddTreeNewColumnEx(Context->TreeNewHandle, PHMOTLC_ASLR, FALSE, L"ASLR", 50, PH_ALIGN_LEFT, -1, 0, TRUE); - PhAddTreeNewColumnEx(Context->TreeNewHandle, PHMOTLC_TIMESTAMP, FALSE, L"Time stamp", 100, PH_ALIGN_LEFT, -1, 0, TRUE); - PhAddTreeNewColumnEx(Context->TreeNewHandle, PHMOTLC_CFGUARD, FALSE, L"CF Guard", 70, PH_ALIGN_LEFT, -1, 0, TRUE); - PhAddTreeNewColumnEx(Context->TreeNewHandle, PHMOTLC_LOADTIME, FALSE, L"Load time", 100, PH_ALIGN_LEFT, -1, 0, TRUE); - PhAddTreeNewColumn(Context->TreeNewHandle, PHMOTLC_LOADREASON, FALSE, L"Load reason", 80, PH_ALIGN_LEFT, -1, 0); - PhAddTreeNewColumnEx(Context->TreeNewHandle, PHMOTLC_FILEMODIFIEDTIME, FALSE, L"File modified time", 140, PH_ALIGN_LEFT, -1, 0, TRUE); - PhAddTreeNewColumnEx(Context->TreeNewHandle, PHMOTLC_FILESIZE, FALSE, L"File size", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); - PhAddTreeNewColumnEx(Context->TreeNewHandle, PHMOTLC_ENTRYPOINT, FALSE, L"Entry point", 70, PH_ALIGN_LEFT, -1, 0, TRUE); - PhAddTreeNewColumnEx(Context->TreeNewHandle, PHMOTLC_PARENTBASEADDRESS, FALSE, L"Parent base address", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT, TRUE); + PhAddTreeNewColumn(Context->TreeNewHandle, PHMOTLC_COMPANYNAME, FALSE, L"Company name", 180, PH_ALIGN_LEFT, ULONG_MAX, 0); + PhAddTreeNewColumn(Context->TreeNewHandle, PHMOTLC_VERSION, FALSE, L"Version", 100, PH_ALIGN_LEFT, ULONG_MAX, 0); + PhAddTreeNewColumn(Context->TreeNewHandle, PHMOTLC_FILENAME, FALSE, L"File name", 180, PH_ALIGN_LEFT, ULONG_MAX, DT_PATH_ELLIPSIS); + + PhAddTreeNewColumn(Context->TreeNewHandle, PHMOTLC_TYPE, FALSE, L"Type", 80, PH_ALIGN_LEFT, ULONG_MAX, 0); + PhAddTreeNewColumnEx(Context->TreeNewHandle, PHMOTLC_LOADCOUNT, FALSE, L"Load count", 40, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE); + PhAddTreeNewColumn(Context->TreeNewHandle, PHMOTLC_VERIFICATIONSTATUS, FALSE, L"Verification status", 70, PH_ALIGN_LEFT, ULONG_MAX, 0); + PhAddTreeNewColumn(Context->TreeNewHandle, PHMOTLC_VERIFIEDSIGNER, FALSE, L"Verified signer", 100, PH_ALIGN_LEFT, ULONG_MAX, 0); + PhAddTreeNewColumnEx(Context->TreeNewHandle, PHMOTLC_ASLR, FALSE, L"ASLR", 50, PH_ALIGN_LEFT, ULONG_MAX, 0, TRUE); + PhAddTreeNewColumnEx(Context->TreeNewHandle, PHMOTLC_TIMESTAMP, FALSE, L"Time stamp", 100, PH_ALIGN_LEFT, ULONG_MAX, 0, TRUE); + PhAddTreeNewColumnEx(Context->TreeNewHandle, PHMOTLC_CFGUARD, FALSE, L"CF Guard", 70, PH_ALIGN_LEFT, ULONG_MAX, 0, TRUE); + PhAddTreeNewColumnEx(Context->TreeNewHandle, PHMOTLC_LOADTIME, FALSE, L"Load time", 100, PH_ALIGN_LEFT, ULONG_MAX, 0, TRUE); + PhAddTreeNewColumn(Context->TreeNewHandle, PHMOTLC_LOADREASON, FALSE, L"Load reason", 80, PH_ALIGN_LEFT, ULONG_MAX, 0); + PhAddTreeNewColumnEx(Context->TreeNewHandle, PHMOTLC_FILEMODIFIEDTIME, FALSE, L"File modified time", 140, PH_ALIGN_LEFT, ULONG_MAX, 0, TRUE); + PhAddTreeNewColumnEx(Context->TreeNewHandle, PHMOTLC_FILESIZE, FALSE, L"File size", 70, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE); + PhAddTreeNewColumnEx(Context->TreeNewHandle, PHMOTLC_ENTRYPOINT, FALSE, L"Entry point", 70, PH_ALIGN_LEFT, ULONG_MAX, 0, TRUE); + PhAddTreeNewColumnEx(Context->TreeNewHandle, PHMOTLC_PARENTBASEADDRESS, FALSE, L"Parent base address", 70, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT, TRUE); TreeNew_SetRedraw(Context->TreeNewHandle, TRUE); @@ -374,14 +374,14 @@ VOID PhpDestroyModuleNode( { // Remove the node from its parent. - if ((index = PhFindItemList(ModuleNode->Parent->Children, ModuleNode)) != -1) + if ((index = PhFindItemList(ModuleNode->Parent->Children, ModuleNode)) != ULONG_MAX) PhRemoveItemList(ModuleNode->Parent->Children, index); } else { // Remove the node from the root list. - if ((index = PhFindItemList(Context->NodeRootList, ModuleNode)) != -1) + if ((index = PhFindItemList(Context->NodeRootList, ModuleNode)) != ULONG_MAX) PhRemoveItemList(Context->NodeRootList, index); } @@ -416,7 +416,7 @@ VOID PhpRemoveModuleNode( // Remove from list and cleanup. - if ((index = PhFindItemList(Context->NodeList, ModuleNode)) != -1) + if ((index = PhFindItemList(Context->NodeList, ModuleNode)) != ULONG_MAX) PhRemoveItemList(Context->NodeList, index); PhpDestroyModuleNode(Context, ModuleNode); @@ -778,7 +778,7 @@ BOOLEAN NTAPI PhpModuleTreeNewCallback( break; case PHMOTLC_SIZE: if (!node->SizeText) - node->SizeText = PhFormatSize(moduleItem->Size, -1); + node->SizeText = PhFormatSize(moduleItem->Size, ULONG_MAX); getCellText->Text = PhGetStringRef(node->SizeText); break; case PHMOTLC_DESCRIPTION: @@ -964,7 +964,7 @@ BOOLEAN NTAPI PhpModuleTreeNewCallback( case PHMOTLC_FILESIZE: if (moduleItem->FileEndOfFile.QuadPart != -1) { - PhMoveReference(&node->FileSizeText, PhFormatSize(moduleItem->FileEndOfFile.QuadPart, -1)); + PhMoveReference(&node->FileSizeText, PhFormatSize(moduleItem->FileEndOfFile.QuadPart, ULONG_MAX)); getCellText->Text = node->FileSizeText->sr; } break; diff --git a/ProcessHacker/mwpgproc.c b/ProcessHacker/mwpgproc.c index 8380a3ffd6d4..b4a400f8ca54 100644 --- a/ProcessHacker/mwpgproc.c +++ b/ProcessHacker/mwpgproc.c @@ -162,8 +162,8 @@ BOOLEAN PhMwpProcessesPageCallback( PPH_COLUMN_SET_ENTRY entry = columnSetList->Items[index]; menuItem = PhCreateEMenuItem(PH_EMENU_TEXT_OWNED, ID_VIEW_LOADCOLUMNSET, - PhAllocateCopy(entry->Name->Buffer, entry->Name->Length + sizeof(WCHAR)), NULL, NULL); - PhInsertEMenuItem(columnSetMenuItem, menuItem, -1); + PhAllocateCopy(entry->Name->Buffer, entry->Name->Length + sizeof(UNICODE_NULL)), NULL, NULL); + PhInsertEMenuItem(columnSetMenuItem, menuItem, ULONG_MAX); } } diff --git a/ProcessHacker/pagfiles.c b/ProcessHacker/pagfiles.c index 21e319e376b3..27eecd3b4fdf 100644 --- a/ProcessHacker/pagfiles.c +++ b/ProcessHacker/pagfiles.c @@ -67,17 +67,17 @@ static VOID PhpAddPagefileItems( PhDereferenceObject(newFileName); // Usage - usage = PhFormatSize(UInt32x32To64(pagefile->TotalInUse, PAGE_SIZE), -1); + usage = PhFormatSize(UInt32x32To64(pagefile->TotalInUse, PAGE_SIZE), ULONG_MAX); PhSetListViewSubItem(ListViewHandle, lvItemIndex, 1, usage->Buffer); PhDereferenceObject(usage); // Peak usage - usage = PhFormatSize(UInt32x32To64(pagefile->PeakUsage, PAGE_SIZE), -1); + usage = PhFormatSize(UInt32x32To64(pagefile->PeakUsage, PAGE_SIZE), ULONG_MAX); PhSetListViewSubItem(ListViewHandle, lvItemIndex, 2, usage->Buffer); PhDereferenceObject(usage); // Total - usage = PhFormatSize(UInt32x32To64(pagefile->TotalSize, PAGE_SIZE), -1); + usage = PhFormatSize(UInt32x32To64(pagefile->TotalSize, PAGE_SIZE), ULONG_MAX); PhSetListViewSubItem(ListViewHandle, lvItemIndex, 3, usage->Buffer); PhDereferenceObject(usage); diff --git a/ProcessHacker/plugman.c b/ProcessHacker/plugman.c index 849fab3a9fab..3e70de2cf9dc 100644 --- a/ProcessHacker/plugman.c +++ b/ProcessHacker/plugman.c @@ -261,7 +261,7 @@ VOID RemovePluginsNode( PhRemoveEntryHashtable(Context->NodeHashtable, &Node); - if ((index = PhFindItemList(Context->NodeList, Node)) != -1) + if ((index = PhFindItemList(Context->NodeList, Node)) != ULONG_MAX) { PhRemoveItemList(Context->NodeList, index); } @@ -735,11 +735,11 @@ INT_PTR CALLBACK PhpPluginsDlgProc( break; menu = PhCreateEMenu(); - //PhInsertEMenuItem(menu, uninstallItem = PhCreateEMenuItem(0, PH_PLUGIN_TREE_ITEM_MENU_UNINSTALL, L"Uninstall", NULL, NULL), -1); - //PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), -1); - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, PH_PLUGIN_TREE_ITEM_MENU_DISABLE, L"Disable", NULL, NULL), -1); - PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), -1); - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, PH_PLUGIN_TREE_ITEM_MENU_PROPERTIES, L"Properties", NULL, NULL), -1); + //PhInsertEMenuItem(menu, uninstallItem = PhCreateEMenuItem(0, PH_PLUGIN_TREE_ITEM_MENU_UNINSTALL, L"Uninstall", NULL, NULL), ULONG_MAX); + //PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, PH_PLUGIN_TREE_ITEM_MENU_DISABLE, L"Disable", NULL, NULL), ULONG_MAX); + PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, PH_PLUGIN_TREE_ITEM_MENU_PROPERTIES, L"Properties", NULL, NULL), ULONG_MAX); //if (!PhGetOwnTokenAttributes().Elevated) //{ @@ -758,7 +758,7 @@ INT_PTR CALLBACK PhpPluginsDlgProc( contextMenuEvent->Location.y ); - if (selectedItem && selectedItem->Id != -1) + if (selectedItem && selectedItem->Id != ULONG_MAX) { switch (selectedItem->Id) { diff --git a/ProcessHacker/sysscmem.c b/ProcessHacker/sysscmem.c index 2fe8b7ae6c13..4e947f9cf8d7 100644 --- a/ProcessHacker/sysscmem.c +++ b/ProcessHacker/sysscmem.c @@ -165,7 +165,7 @@ BOOLEAN PhSipMemorySectionCallback( PhMoveReference(&Section->GraphState.TooltipText, PhFormatString( L"Commit charge: %s\n%s", - PhaFormatSize(UInt32x32To64(usedPages, PAGE_SIZE), -1)->Buffer, + PhaFormatSize(UInt32x32To64(usedPages, PAGE_SIZE), ULONG_MAX)->Buffer, PH_AUTO_T(PH_STRING, PhGetStatisticsTimeString(NULL, getTooltipText->Index))->Buffer )); getTooltipText->Text = Section->GraphState.TooltipText->sr; @@ -176,7 +176,7 @@ BOOLEAN PhSipMemorySectionCallback( PhMoveReference(&Section->GraphState.TooltipText, PhFormatString( L"Physical memory: %s\n%s", - PhaFormatSize(UInt32x32To64(usedPages, PAGE_SIZE), -1)->Buffer, + PhaFormatSize(UInt32x32To64(usedPages, PAGE_SIZE), ULONG_MAX)->Buffer, PH_AUTO_T(PH_STRING, PhGetStatisticsTimeString(NULL, getTooltipText->Index))->Buffer )); getTooltipText->Text = Section->GraphState.TooltipText->sr; @@ -310,12 +310,12 @@ INT_PTR CALLBACK PhSipMemoryDialogProc( if (getPhysicallyInstalledSystemMemory && getPhysicallyInstalledSystemMemory(&InstalledMemory)) { PhSetDialogItemText(hwndDlg, IDC_TOTALPHYSICAL, - PhaConcatStrings2(PhaFormatSize(InstalledMemory * 1024, -1)->Buffer, L" installed")->Buffer); + PhaConcatStrings2(PhaFormatSize(InstalledMemory * 1024, ULONG_MAX)->Buffer, L" installed")->Buffer); } else { PhSetDialogItemText(hwndDlg, IDC_TOTALPHYSICAL, - PhaConcatStrings2(PhaFormatSize(UInt32x32To64(PhSystemBasicInformation.NumberOfPhysicalPages, PAGE_SIZE), -1)->Buffer, L" total")->Buffer); + PhaConcatStrings2(PhaFormatSize(UInt32x32To64(PhSystemBasicInformation.NumberOfPhysicalPages, PAGE_SIZE), ULONG_MAX)->Buffer, L" total")->Buffer); } MemoryPanel = CreateDialog( @@ -547,7 +547,7 @@ VOID PhSipNotifyCommitGraph( PhMoveReference(&CommitGraphState.TooltipText, PhFormatString( L"Commit charge: %s\n%s", - PhaFormatSize(UInt32x32To64(usedPages, PAGE_SIZE), -1)->Buffer, + PhaFormatSize(UInt32x32To64(usedPages, PAGE_SIZE), ULONG_MAX)->Buffer, PH_AUTO_T(PH_STRING, PhGetStatisticsTimeString(NULL, getTooltipText->Index))->Buffer )); } @@ -615,7 +615,7 @@ VOID PhSipNotifyPhysicalGraph( PhMoveReference(&PhysicalGraphState.TooltipText, PhFormatString( L"Physical memory: %s\n%s", - PhaFormatSize(UInt32x32To64(usedPages, PAGE_SIZE), -1)->Buffer, + PhaFormatSize(UInt32x32To64(usedPages, PAGE_SIZE), ULONG_MAX)->Buffer, PH_AUTO_T(PH_STRING, PhGetStatisticsTimeString(NULL, getTooltipText->Index))->Buffer )); } @@ -632,14 +632,14 @@ VOID PhSipUpdateMemoryGraphs( ) { CommitGraphState.Valid = FALSE; - CommitGraphState.TooltipIndex = -1; + CommitGraphState.TooltipIndex = ULONG_MAX; Graph_MoveGrid(CommitGraphHandle, 1); Graph_Draw(CommitGraphHandle); Graph_UpdateTooltip(CommitGraphHandle); InvalidateRect(CommitGraphHandle, NULL, FALSE); PhysicalGraphState.Valid = FALSE; - PhysicalGraphState.TooltipIndex = -1; + PhysicalGraphState.TooltipIndex = ULONG_MAX; Graph_MoveGrid(PhysicalGraphHandle, 1); Graph_Draw(PhysicalGraphHandle); Graph_UpdateTooltip(PhysicalGraphHandle); @@ -657,23 +657,23 @@ VOID PhSipUpdateMemoryPanel( // Commit charge PhSetDialogItemText(MemoryPanel, IDC_ZCOMMITCURRENT_V, - PhaFormatSize(UInt32x32To64(PhPerfInformation.CommittedPages, PAGE_SIZE), -1)->Buffer); + PhaFormatSize(UInt32x32To64(PhPerfInformation.CommittedPages, PAGE_SIZE), ULONG_MAX)->Buffer); PhSetDialogItemText(MemoryPanel, IDC_ZCOMMITPEAK_V, - PhaFormatSize(UInt32x32To64(PhPerfInformation.PeakCommitment, PAGE_SIZE), -1)->Buffer); + PhaFormatSize(UInt32x32To64(PhPerfInformation.PeakCommitment, PAGE_SIZE), ULONG_MAX)->Buffer); PhSetDialogItemText(MemoryPanel, IDC_ZCOMMITLIMIT_V, - PhaFormatSize(UInt32x32To64(PhPerfInformation.CommitLimit, PAGE_SIZE), -1)->Buffer); + PhaFormatSize(UInt32x32To64(PhPerfInformation.CommitLimit, PAGE_SIZE), ULONG_MAX)->Buffer); // Physical memory PhSetDialogItemText(MemoryPanel, IDC_ZPHYSICALCURRENT_V, - PhaFormatSize(UInt32x32To64(PhSystemBasicInformation.NumberOfPhysicalPages - PhPerfInformation.AvailablePages, PAGE_SIZE), -1)->Buffer); + PhaFormatSize(UInt32x32To64(PhSystemBasicInformation.NumberOfPhysicalPages - PhPerfInformation.AvailablePages, PAGE_SIZE), ULONG_MAX)->Buffer); PhSetDialogItemText(MemoryPanel, IDC_ZPHYSICALTOTAL_V, - PhaFormatSize(UInt32x32To64(PhSystemBasicInformation.NumberOfPhysicalPages, PAGE_SIZE), -1)->Buffer); + PhaFormatSize(UInt32x32To64(PhSystemBasicInformation.NumberOfPhysicalPages, PAGE_SIZE), ULONG_MAX)->Buffer); if (InstalledMemory != 0) { PhSetDialogItemText(MemoryPanel, IDC_ZPHYSICALRESERVED_V, - PhaFormatSize(InstalledMemory * 1024 - UInt32x32To64(PhSystemBasicInformation.NumberOfPhysicalPages, PAGE_SIZE), -1)->Buffer); + PhaFormatSize(InstalledMemory * 1024 - UInt32x32To64(PhSystemBasicInformation.NumberOfPhysicalPages, PAGE_SIZE), ULONG_MAX)->Buffer); } else { @@ -681,18 +681,18 @@ VOID PhSipUpdateMemoryPanel( } PhSetDialogItemText(MemoryPanel, IDC_ZPHYSICALCACHEWS_V, - PhaFormatSize(UInt32x32To64(PhPerfInformation.ResidentSystemCachePage, PAGE_SIZE), -1)->Buffer); + PhaFormatSize(UInt32x32To64(PhPerfInformation.ResidentSystemCachePage, PAGE_SIZE), ULONG_MAX)->Buffer); PhSetDialogItemText(MemoryPanel, IDC_ZPHYSICALKERNELWS_V, - PhaFormatSize(UInt32x32To64(PhPerfInformation.ResidentSystemCodePage, PAGE_SIZE), -1)->Buffer); + PhaFormatSize(UInt32x32To64(PhPerfInformation.ResidentSystemCodePage, PAGE_SIZE), ULONG_MAX)->Buffer); PhSetDialogItemText(MemoryPanel, IDC_ZPHYSICALDRIVERWS_V, - PhaFormatSize(UInt32x32To64(PhPerfInformation.ResidentSystemDriverPage, PAGE_SIZE), -1)->Buffer); + PhaFormatSize(UInt32x32To64(PhPerfInformation.ResidentSystemDriverPage, PAGE_SIZE), ULONG_MAX)->Buffer); // Paged pool PhSetDialogItemText(MemoryPanel, IDC_ZPAGEDWORKINGSET_V, - PhaFormatSize(UInt32x32To64(PhPerfInformation.ResidentPagedPoolPage, PAGE_SIZE), -1)->Buffer); + PhaFormatSize(UInt32x32To64(PhPerfInformation.ResidentPagedPoolPage, PAGE_SIZE), ULONG_MAX)->Buffer); PhSetDialogItemText(MemoryPanel, IDC_ZPAGEDVIRTUALSIZE_V, - PhaFormatSize(UInt32x32To64(PhPerfInformation.PagedPoolPages, PAGE_SIZE), -1)->Buffer); + PhaFormatSize(UInt32x32To64(PhPerfInformation.PagedPoolPages, PAGE_SIZE), ULONG_MAX)->Buffer); if (MemoryTicked > 1) PhSetDialogItemText(MemoryPanel, IDC_ZPAGEDALLOCSDELTA_V, PhaFormatUInt64(PagedAllocsDelta.Delta, TRUE)->Buffer); @@ -707,7 +707,7 @@ VOID PhSipUpdateMemoryPanel( // Non-paged pool PhSetDialogItemText(MemoryPanel, IDC_ZNONPAGEDUSAGE_V, - PhaFormatSize(UInt32x32To64(PhPerfInformation.NonPagedPoolPages, PAGE_SIZE), -1)->Buffer); + PhaFormatSize(UInt32x32To64(PhPerfInformation.NonPagedPoolPages, PAGE_SIZE), ULONG_MAX)->Buffer); if (MemoryTicked > 1) PhSetDialogItemText(MemoryPanel, IDC_ZNONPAGEDALLOCSDELTA_V, PhaFormatUInt64(PagedAllocsDelta.Delta, TRUE)->Buffer); @@ -729,12 +729,12 @@ VOID PhSipUpdateMemoryPanel( PhSipGetPoolLimits(&paged, &nonPaged); if (paged != -1) - pagedLimit = PhaFormatSize(paged, -1)->Buffer; + pagedLimit = PhaFormatSize(paged, ULONG_MAX)->Buffer; else pagedLimit = L"N/A"; if (nonPaged != -1) - nonPagedLimit = PhaFormatSize(nonPaged, -1)->Buffer; + nonPagedLimit = PhaFormatSize(nonPaged, ULONG_MAX)->Buffer; else nonPagedLimit = L"N/A"; } @@ -797,22 +797,22 @@ VOID PhSipUpdateMemoryPanel( repurposedPageCount += memoryListInfo.RepurposedPagesByPriority[i]; } - PhSetDialogItemText(MemoryPanel, IDC_ZLISTZEROED_V, PhaFormatSize((ULONG64)memoryListInfo.ZeroPageCount * PAGE_SIZE, -1)->Buffer); - PhSetDialogItemText(MemoryPanel, IDC_ZLISTFREE_V, PhaFormatSize((ULONG64)memoryListInfo.FreePageCount * PAGE_SIZE, -1)->Buffer); - PhSetDialogItemText(MemoryPanel, IDC_ZLISTMODIFIED_V, PhaFormatSize((ULONG64)memoryListInfo.ModifiedPageCount * PAGE_SIZE, -1)->Buffer); - PhSetDialogItemText(MemoryPanel, IDC_ZLISTMODIFIEDNOWRITE_V, PhaFormatSize((ULONG64)memoryListInfo.ModifiedNoWritePageCount * PAGE_SIZE, -1)->Buffer); - PhSetDialogItemText(MemoryPanel, IDC_ZLISTSTANDBY_V, PhaFormatSize((ULONG64)standbyPageCount * PAGE_SIZE, -1)->Buffer); - PhSetDialogItemText(MemoryPanel, IDC_ZLISTSTANDBY0_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[0] * PAGE_SIZE, -1)->Buffer); - PhSetDialogItemText(MemoryPanel, IDC_ZLISTSTANDBY1_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[1] * PAGE_SIZE, -1)->Buffer); - PhSetDialogItemText(MemoryPanel, IDC_ZLISTSTANDBY2_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[2] * PAGE_SIZE, -1)->Buffer); - PhSetDialogItemText(MemoryPanel, IDC_ZLISTSTANDBY3_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[3] * PAGE_SIZE, -1)->Buffer); - PhSetDialogItemText(MemoryPanel, IDC_ZLISTSTANDBY4_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[4] * PAGE_SIZE, -1)->Buffer); - PhSetDialogItemText(MemoryPanel, IDC_ZLISTSTANDBY5_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[5] * PAGE_SIZE, -1)->Buffer); - PhSetDialogItemText(MemoryPanel, IDC_ZLISTSTANDBY6_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[6] * PAGE_SIZE, -1)->Buffer); - PhSetDialogItemText(MemoryPanel, IDC_ZLISTSTANDBY7_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[7] * PAGE_SIZE, -1)->Buffer); + PhSetDialogItemText(MemoryPanel, IDC_ZLISTZEROED_V, PhaFormatSize((ULONG64)memoryListInfo.ZeroPageCount * PAGE_SIZE, ULONG_MAX)->Buffer); + PhSetDialogItemText(MemoryPanel, IDC_ZLISTFREE_V, PhaFormatSize((ULONG64)memoryListInfo.FreePageCount * PAGE_SIZE, ULONG_MAX)->Buffer); + PhSetDialogItemText(MemoryPanel, IDC_ZLISTMODIFIED_V, PhaFormatSize((ULONG64)memoryListInfo.ModifiedPageCount * PAGE_SIZE, ULONG_MAX)->Buffer); + PhSetDialogItemText(MemoryPanel, IDC_ZLISTMODIFIEDNOWRITE_V, PhaFormatSize((ULONG64)memoryListInfo.ModifiedNoWritePageCount * PAGE_SIZE, ULONG_MAX)->Buffer); + PhSetDialogItemText(MemoryPanel, IDC_ZLISTSTANDBY_V, PhaFormatSize((ULONG64)standbyPageCount * PAGE_SIZE, ULONG_MAX)->Buffer); + PhSetDialogItemText(MemoryPanel, IDC_ZLISTSTANDBY0_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[0] * PAGE_SIZE, ULONG_MAX)->Buffer); + PhSetDialogItemText(MemoryPanel, IDC_ZLISTSTANDBY1_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[1] * PAGE_SIZE, ULONG_MAX)->Buffer); + PhSetDialogItemText(MemoryPanel, IDC_ZLISTSTANDBY2_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[2] * PAGE_SIZE, ULONG_MAX)->Buffer); + PhSetDialogItemText(MemoryPanel, IDC_ZLISTSTANDBY3_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[3] * PAGE_SIZE, ULONG_MAX)->Buffer); + PhSetDialogItemText(MemoryPanel, IDC_ZLISTSTANDBY4_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[4] * PAGE_SIZE, ULONG_MAX)->Buffer); + PhSetDialogItemText(MemoryPanel, IDC_ZLISTSTANDBY5_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[5] * PAGE_SIZE, ULONG_MAX)->Buffer); + PhSetDialogItemText(MemoryPanel, IDC_ZLISTSTANDBY6_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[6] * PAGE_SIZE, ULONG_MAX)->Buffer); + PhSetDialogItemText(MemoryPanel, IDC_ZLISTSTANDBY7_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[7] * PAGE_SIZE, ULONG_MAX)->Buffer); if (WindowsVersion >= WINDOWS_8) - PhSetDialogItemText(MemoryPanel, IDC_ZLISTMODIFIEDPAGEFILE_V, PhaFormatSize((ULONG64)memoryListInfo.ModifiedPageCountPageFile * PAGE_SIZE, -1)->Buffer); + PhSetDialogItemText(MemoryPanel, IDC_ZLISTMODIFIEDPAGEFILE_V, PhaFormatSize((ULONG64)memoryListInfo.ModifiedPageCountPageFile * PAGE_SIZE, ULONG_MAX)->Buffer); else PhSetDialogItemText(MemoryPanel, IDC_ZLISTMODIFIEDPAGEFILE_V, L"N/A"); } diff --git a/phlib/basesup.c b/phlib/basesup.c index 39b22f1e0e85..1f7ea06b9de9 100644 --- a/phlib/basesup.c +++ b/phlib/basesup.c @@ -4311,7 +4311,7 @@ ULONG PhFindItemList( return i; } - return -1; + return ULONG_MAX; } /** diff --git a/phlib/filepool.c b/phlib/filepool.c index 8126fa264f18..2933a7b5ad4d 100644 --- a/phlib/filepool.c +++ b/phlib/filepool.c @@ -169,7 +169,7 @@ NTSTATUS PhCreateFilePool( header->SegmentCount = 1; for (i = 0; i < PH_FP_FREE_LIST_COUNT; i++) - header->FreeLists[i] = -1; + header->FreeLists[i] = ULONG_MAX; } else { @@ -437,7 +437,7 @@ PVOID PhAllocateFilePool( { segmentIndex = Pool->Header->FreeLists[freeListIndex]; - while (segmentIndex != -1) + while (segmentIndex != ULONG_MAX) { firstBlock = PhFppReferenceSegment(Pool, segmentIndex); @@ -568,7 +568,7 @@ BOOLEAN PhFreeFilePoolByRva( offset = PhFppDecodeRva(Pool, Rva, &segmentIndex); - if (offset == -1) + if (offset == ULONG_MAX) return FALSE; firstBlock = PhFppReferenceSegment(Pool, segmentIndex); @@ -631,7 +631,7 @@ PVOID PhReferenceFilePoolByRva( offset = PhFppDecodeRva(Pool, Rva, &segmentIndex); - if (offset == -1) + if (offset == ULONG_MAX) return NULL; firstBlock = PhFppReferenceSegment(Pool, segmentIndex); @@ -658,7 +658,7 @@ BOOLEAN PhDereferenceFilePoolByRva( offset = PhFppDecodeRva(Pool, Rva, &segmentIndex); - if (offset == -1) + if (offset == ULONG_MAX) return FALSE; PhFppDereferenceSegment(Pool, segmentIndex); @@ -820,8 +820,8 @@ VOID PhFppInitializeSegment( RtlInitializeBitMap(&bitmap, segmentHeader->Bitmap, PH_FP_BLOCK_COUNT); RtlSetBits(&bitmap, 0, Pool->SegmentHeaderBlockSpan + AdditionalBlocksUsed); segmentHeader->FreeBlocks = PH_FP_BLOCK_COUNT - (Pool->SegmentHeaderBlockSpan + AdditionalBlocksUsed); - segmentHeader->FreeFlink = -1; - segmentHeader->FreeBlink = -1; + segmentHeader->FreeFlink = ULONG_MAX; + segmentHeader->FreeBlink = ULONG_MAX; } /** @@ -1240,7 +1240,7 @@ PPH_FP_BLOCK_HEADER PhFppAllocateBlocks( // Find a range of free blocks and mark them as in-use. foundIndex = RtlFindClearBitsAndSet(&bitmap, NumberOfBlocks, hintIndex); - if (foundIndex == -1) + if (foundIndex == ULONG_MAX) { // No more space. return NULL; @@ -1355,7 +1355,7 @@ BOOLEAN PhFppInsertFreeList( // Try to reference the segment before we commit any changes. - if (oldSegmentIndex != -1) + if (oldSegmentIndex != ULONG_MAX) { oldSegmentFirstBlock = PhFppReferenceSegment(Pool, oldSegmentIndex); @@ -1365,11 +1365,11 @@ BOOLEAN PhFppInsertFreeList( // Insert the segment into the list. - SegmentHeader->FreeBlink = -1; + SegmentHeader->FreeBlink = ULONG_MAX; SegmentHeader->FreeFlink = oldSegmentIndex; Pool->Header->FreeLists[FreeListIndex] = SegmentIndex; - if (oldSegmentIndex != -1) + if (oldSegmentIndex != ULONG_MAX) { oldSegmentHeader = PhFppGetHeaderSegment(Pool, oldSegmentFirstBlock); oldSegmentHeader->FreeBlink = SegmentIndex; @@ -1406,7 +1406,7 @@ BOOLEAN PhFppRemoveFreeList( // Try to reference the segments before we commit any changes. - if (flinkSegmentIndex != -1) + if (flinkSegmentIndex != ULONG_MAX) { flinkSegmentFirstBlock = PhFppReferenceSegment(Pool, flinkSegmentIndex); @@ -1414,13 +1414,13 @@ BOOLEAN PhFppRemoveFreeList( return FALSE; } - if (blinkSegmentIndex != -1) + if (blinkSegmentIndex != ULONG_MAX) { blinkSegmentFirstBlock = PhFppReferenceSegment(Pool, blinkSegmentIndex); if (!blinkSegmentFirstBlock) { - if (flinkSegmentIndex != -1) + if (flinkSegmentIndex != ULONG_MAX) PhFppDereferenceSegment(Pool, flinkSegmentIndex); return FALSE; @@ -1429,14 +1429,14 @@ BOOLEAN PhFppRemoveFreeList( // Unlink the segment from the list. - if (flinkSegmentIndex != -1) + if (flinkSegmentIndex != ULONG_MAX) { flinkSegmentHeader = PhFppGetHeaderSegment(Pool, flinkSegmentFirstBlock); flinkSegmentHeader->FreeBlink = blinkSegmentIndex; PhFppDereferenceSegment(Pool, flinkSegmentIndex); } - if (blinkSegmentIndex != -1) + if (blinkSegmentIndex != ULONG_MAX) { blinkSegmentHeader = PhFppGetHeaderSegment(Pool, blinkSegmentFirstBlock); blinkSegmentHeader->FreeFlink = flinkSegmentIndex; @@ -1503,7 +1503,7 @@ ULONG PhFppDecodeRva( segmentIndex = Rva >> Pool->SegmentShift; if (segmentIndex >= Pool->Header->SegmentCount) - return -1; + return ULONG_MAX; *SegmentIndex = segmentIndex; diff --git a/phlib/guisup.c b/phlib/guisup.c index 6a4ae11f1342..f452b92448d9 100644 --- a/phlib/guisup.c +++ b/phlib/guisup.c @@ -439,7 +439,7 @@ PPH_STRING PhGetComboBoxString( { Index = ComboBox_GetCurSel(hwnd); - if (Index == -1) + if (Index == CB_ERR) return NULL; } diff --git a/phlib/workqueue.c b/phlib/workqueue.c index 84842c102b40..519dcc753f82 100644 --- a/phlib/workqueue.c +++ b/phlib/workqueue.c @@ -104,7 +104,7 @@ VOID PhDeleteWorkQueue( #ifdef DEBUG PhAcquireQueuedLockExclusive(&PhDbgWorkQueueListLock); - if ((index = PhFindItemList(PhDbgWorkQueueList, WorkQueue)) != -1) + if ((index = PhFindItemList(PhDbgWorkQueueList, WorkQueue)) != ULONG_MAX) PhRemoveItemList(PhDbgWorkQueueList, index); PhReleaseQueuedLockExclusive(&PhDbgWorkQueueListLock); #endif From 7a9292d1b0cdf6ada072d879036cfb828e7c42c0 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 27 Apr 2019 21:38:43 +0200 Subject: [PATCH 1835/2058] Update macro usage --- ProcessHacker/procprv.c | 4 ++-- ProcessHacker/prpgperf.c | 20 ++++++++++---------- ProcessHacker/srvlist.c | 18 +++++++++--------- ProcessHacker/sysinfo.c | 2 +- ProcessHacker/syssccpu.c | 10 +++++----- ProcessHacker/sysscio.c | 34 +++++++++++++++++----------------- ProcessHacker/thrdstk.c | 22 +++++++++++----------- phlib/svcsup.c | 6 +++--- tools/peview/clrprp.c | 2 +- tools/peview/colmgr.c | 10 +++++----- tools/peview/exlfexports.c | 2 +- tools/peview/exlfprp.c | 2 +- tools/peview/pdbprp.c | 22 +++++++++++----------- tools/peview/peprp.c | 2 +- tools/peview/resprp.c | 2 +- 15 files changed, 79 insertions(+), 79 deletions(-) diff --git a/ProcessHacker/procprv.c b/ProcessHacker/procprv.c index c74d8e70329e..1e886279557e 100644 --- a/ProcessHacker/procprv.c +++ b/ProcessHacker/procprv.c @@ -934,8 +934,8 @@ VOID PhpProcessQueryStage2( ) { Data->IsPacked = TRUE; - Data->ImportModules = -1; - Data->ImportFunctions = -1; + Data->ImportModules = ULONG_MAX; + Data->ImportFunctions = ULONG_MAX; } } diff --git a/ProcessHacker/prpgperf.c b/ProcessHacker/prpgperf.c index ad3fb7760088..eb60d02f1c05 100644 --- a/ProcessHacker/prpgperf.c +++ b/ProcessHacker/prpgperf.c @@ -221,7 +221,7 @@ INT_PTR CALLBACK PhpProcessPerformanceDlgProc( PhMoveReference(&performanceContext->PrivateGraphState.Text, PhConcatStrings2( L"Private bytes: ", - PhaFormatSize(processItem->VmCounters.PagefileUsage, -1)->Buffer + PhaFormatSize(processItem->VmCounters.PagefileUsage, ULONG_MAX)->Buffer )); hdc = Graph_GetBufferedContext(performanceContext->PrivateGraphHandle); @@ -293,8 +293,8 @@ INT_PTR CALLBACK PhpProcessPerformanceDlgProc( PhMoveReference(&performanceContext->IoGraphState.Text, PhFormatString( L"R+O: %s, W: %s", - PhaFormatSize(processItem->IoReadDelta.Delta + processItem->IoOtherDelta.Delta, -1)->Buffer, - PhaFormatSize(processItem->IoWriteDelta.Delta, -1)->Buffer + PhaFormatSize(processItem->IoReadDelta.Delta + processItem->IoOtherDelta.Delta, ULONG_MAX)->Buffer, + PhaFormatSize(processItem->IoWriteDelta.Delta, ULONG_MAX)->Buffer )); hdc = Graph_GetBufferedContext(performanceContext->IoGraphHandle); @@ -347,7 +347,7 @@ INT_PTR CALLBACK PhpProcessPerformanceDlgProc( PhMoveReference(&performanceContext->PrivateGraphState.TooltipText, PhFormatString( L"Private bytes: %s\n%s", - PhaFormatSize(privateBytes, -1)->Buffer, + PhaFormatSize(privateBytes, ULONG_MAX)->Buffer, PH_AUTO_T(PH_STRING, PhGetStatisticsTimeString(processItem, getTooltipText->Index))->Buffer )); } @@ -371,9 +371,9 @@ INT_PTR CALLBACK PhpProcessPerformanceDlgProc( PhMoveReference(&performanceContext->IoGraphState.TooltipText, PhFormatString( L"R: %s\nW: %s\nO: %s\n%s", - PhaFormatSize(ioRead, -1)->Buffer, - PhaFormatSize(ioWrite, -1)->Buffer, - PhaFormatSize(ioOther, -1)->Buffer, + PhaFormatSize(ioRead, ULONG_MAX)->Buffer, + PhaFormatSize(ioWrite, ULONG_MAX)->Buffer, + PhaFormatSize(ioOther, ULONG_MAX)->Buffer, PH_AUTO_T(PH_STRING, PhGetStatisticsTimeString(processItem, getTooltipText->Index))->Buffer )); } @@ -399,11 +399,11 @@ INT_PTR CALLBACK PhpProcessPerformanceDlgProc( LONG height; performanceContext->CpuGraphState.Valid = FALSE; - performanceContext->CpuGraphState.TooltipIndex = -1; + performanceContext->CpuGraphState.TooltipIndex = ULONG_MAX; performanceContext->PrivateGraphState.Valid = FALSE; - performanceContext->PrivateGraphState.TooltipIndex = -1; + performanceContext->PrivateGraphState.TooltipIndex = ULONG_MAX; performanceContext->IoGraphState.Valid = FALSE; - performanceContext->IoGraphState.TooltipIndex = -1; + performanceContext->IoGraphState.TooltipIndex = ULONG_MAX; GetClientRect(hwndDlg, &clientRect); width = clientRect.right - margin.left - margin.right; diff --git a/ProcessHacker/srvlist.c b/ProcessHacker/srvlist.c index db3910af6ea6..3f1a566afd94 100644 --- a/ProcessHacker/srvlist.c +++ b/ProcessHacker/srvlist.c @@ -133,14 +133,14 @@ VOID PhInitializeServiceTreeList( PhAddTreeNewColumn(hwnd, PHSVTLC_STARTTYPE, TRUE, L"Start type", 130, PH_ALIGN_LEFT, 4, 0); PhAddTreeNewColumn(hwnd, PHSVTLC_PID, TRUE, L"PID", 50, PH_ALIGN_RIGHT, 5, DT_RIGHT); - PhAddTreeNewColumn(hwnd, PHSVTLC_BINARYPATH, FALSE, L"Binary path", 180, PH_ALIGN_LEFT, -1, DT_PATH_ELLIPSIS); - PhAddTreeNewColumn(hwnd, PHSVTLC_ERRORCONTROL, FALSE, L"Error control", 70, PH_ALIGN_LEFT, -1, 0); - PhAddTreeNewColumn(hwnd, PHSVTLC_GROUP, FALSE, L"Group", 100, PH_ALIGN_LEFT, -1, 0); - PhAddTreeNewColumn(hwnd, PHSVTLC_DESCRIPTION, FALSE, L"Description", 200, PH_ALIGN_LEFT, -1, 0); - PhAddTreeNewColumnEx(hwnd, PHSVTLC_KEYMODIFIEDTIME, FALSE, L"Key modified time", 140, PH_ALIGN_LEFT, -1, 0, TRUE); - PhAddTreeNewColumn(hwnd, PHSVTLC_VERIFICATIONSTATUS, FALSE, L"Verification status", 70, PH_ALIGN_LEFT, -1, 0); - PhAddTreeNewColumn(hwnd, PHSVTLC_VERIFIEDSIGNER, FALSE, L"Verified signer", 100, PH_ALIGN_LEFT, -1, 0); - PhAddTreeNewColumn(hwnd, PHSVTLC_FILENAME, FALSE, L"File name", 100, PH_ALIGN_LEFT, -1, DT_PATH_ELLIPSIS); + PhAddTreeNewColumn(hwnd, PHSVTLC_BINARYPATH, FALSE, L"Binary path", 180, PH_ALIGN_LEFT, ULONG_MAX, DT_PATH_ELLIPSIS); + PhAddTreeNewColumn(hwnd, PHSVTLC_ERRORCONTROL, FALSE, L"Error control", 70, PH_ALIGN_LEFT, ULONG_MAX, 0); + PhAddTreeNewColumn(hwnd, PHSVTLC_GROUP, FALSE, L"Group", 100, PH_ALIGN_LEFT, ULONG_MAX, 0); + PhAddTreeNewColumn(hwnd, PHSVTLC_DESCRIPTION, FALSE, L"Description", 200, PH_ALIGN_LEFT, ULONG_MAX, 0); + PhAddTreeNewColumnEx(hwnd, PHSVTLC_KEYMODIFIEDTIME, FALSE, L"Key modified time", 140, PH_ALIGN_LEFT, ULONG_MAX, 0, TRUE); + PhAddTreeNewColumn(hwnd, PHSVTLC_VERIFICATIONSTATUS, FALSE, L"Verification status", 70, PH_ALIGN_LEFT, ULONG_MAX, 0); + PhAddTreeNewColumn(hwnd, PHSVTLC_VERIFIEDSIGNER, FALSE, L"Verified signer", 100, PH_ALIGN_LEFT, ULONG_MAX, 0); + PhAddTreeNewColumn(hwnd, PHSVTLC_FILENAME, FALSE, L"File name", 100, PH_ALIGN_LEFT, ULONG_MAX, DT_PATH_ELLIPSIS); TreeNew_SetRedraw(hwnd, TRUE); @@ -293,7 +293,7 @@ VOID PhpRemoveServiceNode( // Remove from list and cleanup. - if ((index = PhFindItemList(ServiceNodeList, ServiceNode)) != -1) + if ((index = PhFindItemList(ServiceNodeList, ServiceNode)) != ULONG_MAX) PhRemoveItemList(ServiceNodeList, index); PhClearReference(&ServiceNode->BinaryPath); diff --git a/ProcessHacker/sysinfo.c b/ProcessHacker/sysinfo.c index 5723a49f8d4f..88b0f85414d5 100644 --- a/ProcessHacker/sysinfo.c +++ b/ProcessHacker/sysinfo.c @@ -912,7 +912,7 @@ VOID PhSiSetColorsGraphDrawInfo( ) { static PH_QUEUED_LOCK lock = PH_QUEUED_LOCK_INIT; - static ULONG lastDpi = -1; + static ULONG lastDpi = ULONG_MAX; static HFONT iconTitleFont; // Get the appropriate fonts. diff --git a/ProcessHacker/syssccpu.c b/ProcessHacker/syssccpu.c index 03c48530e5a3..479b5b72c012 100644 --- a/ProcessHacker/syssccpu.c +++ b/ProcessHacker/syssccpu.c @@ -326,7 +326,7 @@ INT_PTR CALLBACK PhSipCpuDialogProc( if (header->hwndFrom == CpuGraphHandle) { - PhSipNotifyCpuGraph(-1, header); + PhSipNotifyCpuGraph(ULONG_MAX, header); } else { @@ -543,7 +543,7 @@ VOID PhSipNotifyCpuGraph( drawInfo->Flags = PH_GRAPH_USE_GRID_X | PH_GRAPH_USE_GRID_Y | PH_GRAPH_USE_LINE_2; PhSiSetColorsGraphDrawInfo(drawInfo, PhCsColorCpuKernel, PhCsColorCpuUser); - if (Index == -1) + if (Index == ULONG_MAX) { PhGraphStateGetDrawInfo( &CpuGraphState, @@ -581,7 +581,7 @@ VOID PhSipNotifyCpuGraph( if (getTooltipText->Index < getTooltipText->TotalCount) { - if (Index == -1) + if (Index == ULONG_MAX) { if (CpuGraphState.TooltipIndex != getTooltipText->Index) { @@ -655,7 +655,7 @@ VOID PhSipUpdateCpuGraphs( ULONG i; CpuGraphState.Valid = FALSE; - CpuGraphState.TooltipIndex = -1; + CpuGraphState.TooltipIndex = ULONG_MAX; Graph_MoveGrid(CpuGraphHandle, 1); Graph_Draw(CpuGraphHandle); Graph_UpdateTooltip(CpuGraphHandle); @@ -664,7 +664,7 @@ VOID PhSipUpdateCpuGraphs( for (i = 0; i < NumberOfProcessors; i++) { CpusGraphState[i].Valid = FALSE; - CpusGraphState[i].TooltipIndex = -1; + CpusGraphState[i].TooltipIndex = ULONG_MAX; Graph_MoveGrid(CpusGraphHandle[i], 1); Graph_Draw(CpusGraphHandle[i]); Graph_UpdateTooltip(CpusGraphHandle[i]); diff --git a/ProcessHacker/sysscio.c b/ProcessHacker/sysscio.c index a49b0a6e85a4..35011f481114 100644 --- a/ProcessHacker/sysscio.c +++ b/ProcessHacker/sysscio.c @@ -144,9 +144,9 @@ BOOLEAN PhSipIoSectionCallback( PhMoveReference(&Section->GraphState.TooltipText, PhFormatString( L"R: %s\nW: %s\nO: %s%s\n%s", - PhaFormatSize(ioRead, -1)->Buffer, - PhaFormatSize(ioWrite, -1)->Buffer, - PhaFormatSize(ioOther, -1)->Buffer, + PhaFormatSize(ioRead, ULONG_MAX)->Buffer, + PhaFormatSize(ioWrite, ULONG_MAX)->Buffer, + PhaFormatSize(ioOther, ULONG_MAX)->Buffer, PhGetStringOrEmpty(PhSipGetMaxIoString(getTooltipText->Index)), PH_AUTO_T(PH_STRING, PhGetStatisticsTimeString(NULL, getTooltipText->Index))->Buffer )); @@ -380,9 +380,9 @@ VOID PhSipNotifyIoGraph( PhMoveReference(&IoGraphState.TooltipText, PhFormatString( L"R: %s\nW: %s\nO: %s%s\n%s", - PhaFormatSize(ioRead, -1)->Buffer, - PhaFormatSize(ioWrite, -1)->Buffer, - PhaFormatSize(ioOther, -1)->Buffer, + PhaFormatSize(ioRead, ULONG_MAX)->Buffer, + PhaFormatSize(ioWrite, ULONG_MAX)->Buffer, + PhaFormatSize(ioOther, ULONG_MAX)->Buffer, PhGetStringOrEmpty(PhSipGetMaxIoString(getTooltipText->Index)), PH_AUTO_T(PH_STRING, PhGetStatisticsTimeString(NULL, getTooltipText->Index))->Buffer )); @@ -419,7 +419,7 @@ VOID PhSipUpdateIoGraph( ) { IoGraphState.Valid = FALSE; - IoGraphState.TooltipIndex = -1; + IoGraphState.TooltipIndex = ULONG_MAX; Graph_MoveGrid(IoGraphHandle, 1); Graph_Draw(IoGraphHandle); Graph_UpdateTooltip(IoGraphHandle); @@ -447,9 +447,9 @@ VOID PhSipUpdateIoPanel( if (PhIoReadHistory.Count != 0) { - PhSetDialogItemText(IoPanel, IDC_ZREADBYTESDELTA_V, PhaFormatSize(PhIoReadDelta.Delta, -1)->Buffer); - PhSetDialogItemText(IoPanel, IDC_ZWRITEBYTESDELTA_V, PhaFormatSize(PhIoWriteDelta.Delta, -1)->Buffer); - PhSetDialogItemText(IoPanel, IDC_ZOTHERBYTESDELTA_V, PhaFormatSize(PhIoOtherDelta.Delta, -1)->Buffer); + PhSetDialogItemText(IoPanel, IDC_ZREADBYTESDELTA_V, PhaFormatSize(PhIoReadDelta.Delta, ULONG_MAX)->Buffer); + PhSetDialogItemText(IoPanel, IDC_ZWRITEBYTESDELTA_V, PhaFormatSize(PhIoWriteDelta.Delta, ULONG_MAX)->Buffer); + PhSetDialogItemText(IoPanel, IDC_ZOTHERBYTESDELTA_V, PhaFormatSize(PhIoOtherDelta.Delta, ULONG_MAX)->Buffer); } else { @@ -461,11 +461,11 @@ VOID PhSipUpdateIoPanel( // I/O Totals PhSetDialogItemText(IoPanel, IDC_ZREADS_V, PhaFormatUInt64(PhPerfInformation.IoReadOperationCount, TRUE)->Buffer); - PhSetDialogItemText(IoPanel, IDC_ZREADBYTES_V, PhaFormatSize(PhPerfInformation.IoReadTransferCount.QuadPart, -1)->Buffer); + PhSetDialogItemText(IoPanel, IDC_ZREADBYTES_V, PhaFormatSize(PhPerfInformation.IoReadTransferCount.QuadPart, ULONG_MAX)->Buffer); PhSetDialogItemText(IoPanel, IDC_ZWRITES_V, PhaFormatUInt64(PhPerfInformation.IoWriteOperationCount, TRUE)->Buffer); - PhSetDialogItemText(IoPanel, IDC_ZWRITEBYTES_V, PhaFormatSize(PhPerfInformation.IoWriteTransferCount.QuadPart, -1)->Buffer); + PhSetDialogItemText(IoPanel, IDC_ZWRITEBYTES_V, PhaFormatSize(PhPerfInformation.IoWriteTransferCount.QuadPart, ULONG_MAX)->Buffer); PhSetDialogItemText(IoPanel, IDC_ZOTHER_V, PhaFormatUInt64(PhPerfInformation.IoOtherOperationCount, TRUE)->Buffer); - PhSetDialogItemText(IoPanel, IDC_ZOTHERBYTES_V, PhaFormatSize(PhPerfInformation.IoOtherTransferCount.QuadPart, -1)->Buffer); + PhSetDialogItemText(IoPanel, IDC_ZOTHERBYTES_V, PhaFormatSize(PhPerfInformation.IoOtherTransferCount.QuadPart, ULONG_MAX)->Buffer); } PPH_PROCESS_RECORD PhSipReferenceMaxIoRecord( @@ -513,8 +513,8 @@ PPH_STRING PhSipGetMaxIoString( L"\n%s (%u): R+O: %s, W: %s", maxProcessRecord->ProcessName->Buffer, HandleToUlong(maxProcessRecord->ProcessId), - PhaFormatSize(maxIoReadOther, -1)->Buffer, - PhaFormatSize(maxIoWrite, -1)->Buffer + PhaFormatSize(maxIoReadOther, ULONG_MAX)->Buffer, + PhaFormatSize(maxIoWrite, ULONG_MAX)->Buffer ); } else @@ -522,8 +522,8 @@ PPH_STRING PhSipGetMaxIoString( maxUsageString = PhaFormatString( L"\n%s: R+O: %s, W: %s", maxProcessRecord->ProcessName->Buffer, - PhaFormatSize(maxIoReadOther, -1)->Buffer, - PhaFormatSize(maxIoWrite, -1)->Buffer + PhaFormatSize(maxIoReadOther, ULONG_MAX)->Buffer, + PhaFormatSize(maxIoWrite, ULONG_MAX)->Buffer ); } #else diff --git a/ProcessHacker/thrdstk.c b/ProcessHacker/thrdstk.c index cbeec1f67611..f4b3ecd6ca2c 100644 --- a/ProcessHacker/thrdstk.c +++ b/ProcessHacker/thrdstk.c @@ -328,7 +328,7 @@ VOID RemoveThreadStackNode( PhRemoveEntryHashtable(Context->NodeHashtable, &Node); - if ((index = PhFindItemList(Context->NodeList, Node)) != -1) + if ((index = PhFindItemList(Context->NodeList, Node)) != ULONG_MAX) { PhRemoveItemList(Context->NodeList, index); } @@ -645,14 +645,14 @@ VOID InitializeThreadStackTree( PhAddTreeNewColumn(Context->TreeNewHandle, PH_STACK_TREE_COLUMN_INDEX, TRUE, L"#", 30, PH_ALIGN_LEFT, 0, 0); PhAddTreeNewColumn(Context->TreeNewHandle, PH_STACK_TREE_COLUMN_SYMBOL, TRUE, L"Name", 250, PH_ALIGN_LEFT, 1, 0); - PhAddTreeNewColumn(Context->TreeNewHandle, PH_STACK_TREE_COLUMN_STACKADDRESS, FALSE, L"Stack address", 100, PH_ALIGN_LEFT, -1, 0); - PhAddTreeNewColumn(Context->TreeNewHandle, PH_STACK_TREE_COLUMN_FRAMEADDRESS, FALSE, L"Frame address", 100, PH_ALIGN_LEFT, -1, 0); - PhAddTreeNewColumn(Context->TreeNewHandle, PH_STACK_TREE_COLUMN_PARAMETER1, FALSE, L"Stack parameter #1", 100, PH_ALIGN_LEFT, -1, 0); - PhAddTreeNewColumn(Context->TreeNewHandle, PH_STACK_TREE_COLUMN_PARAMETER2, FALSE, L"Stack parameter #2", 100, PH_ALIGN_LEFT, -1, 0); - PhAddTreeNewColumn(Context->TreeNewHandle, PH_STACK_TREE_COLUMN_PARAMETER3, FALSE, L"Stack parameter #3", 100, PH_ALIGN_LEFT, -1, 0); - PhAddTreeNewColumn(Context->TreeNewHandle, PH_STACK_TREE_COLUMN_PARAMETER4, FALSE, L"Stack parameter #4", 100, PH_ALIGN_LEFT, -1, 0); - PhAddTreeNewColumn(Context->TreeNewHandle, PH_STACK_TREE_COLUMN_CONTROLADDRESS, FALSE, L"Control address", 100, PH_ALIGN_LEFT, -1, 0); - PhAddTreeNewColumn(Context->TreeNewHandle, PH_STACK_TREE_COLUMN_RETURNADDRESS, FALSE, L"Return address", 100, PH_ALIGN_LEFT, -1, 0); + PhAddTreeNewColumn(Context->TreeNewHandle, PH_STACK_TREE_COLUMN_STACKADDRESS, FALSE, L"Stack address", 100, PH_ALIGN_LEFT, ULONG_MAX, 0); + PhAddTreeNewColumn(Context->TreeNewHandle, PH_STACK_TREE_COLUMN_FRAMEADDRESS, FALSE, L"Frame address", 100, PH_ALIGN_LEFT, ULONG_MAX, 0); + PhAddTreeNewColumn(Context->TreeNewHandle, PH_STACK_TREE_COLUMN_PARAMETER1, FALSE, L"Stack parameter #1", 100, PH_ALIGN_LEFT, ULONG_MAX, 0); + PhAddTreeNewColumn(Context->TreeNewHandle, PH_STACK_TREE_COLUMN_PARAMETER2, FALSE, L"Stack parameter #2", 100, PH_ALIGN_LEFT, ULONG_MAX, 0); + PhAddTreeNewColumn(Context->TreeNewHandle, PH_STACK_TREE_COLUMN_PARAMETER3, FALSE, L"Stack parameter #3", 100, PH_ALIGN_LEFT, ULONG_MAX, 0); + PhAddTreeNewColumn(Context->TreeNewHandle, PH_STACK_TREE_COLUMN_PARAMETER4, FALSE, L"Stack parameter #4", 100, PH_ALIGN_LEFT, ULONG_MAX, 0); + PhAddTreeNewColumn(Context->TreeNewHandle, PH_STACK_TREE_COLUMN_CONTROLADDRESS, FALSE, L"Control address", 100, PH_ALIGN_LEFT, ULONG_MAX, 0); + PhAddTreeNewColumn(Context->TreeNewHandle, PH_STACK_TREE_COLUMN_RETURNADDRESS, FALSE, L"Return address", 100, PH_ALIGN_LEFT, ULONG_MAX, 0); TreeNew_SetTriState(Context->TreeNewHandle, FALSE); TreeNew_SetSort(Context->TreeNewHandle, PH_STACK_TREE_COLUMN_INDEX, AscendingSortOrder); @@ -920,7 +920,7 @@ INT_PTR CALLBACK PhpThreadStackDlgProc( if (selectedNode = GetSelectedThreadStackNode(context)) { menu = PhCreateEMenu(); - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, IDC_COPY, L"Copy", NULL, NULL), -1); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, IDC_COPY, L"Copy", NULL, NULL), ULONG_MAX); PhInsertCopyCellEMenuItem(menu, IDC_COPY, context->TreeNewHandle, contextMenuEvent->Column); selectedItem = PhShowEMenu( @@ -932,7 +932,7 @@ INT_PTR CALLBACK PhpThreadStackDlgProc( contextMenuEvent->Location.y ); - if (selectedItem && selectedItem->Id != -1) + if (selectedItem && selectedItem->Id != ULONG_MAX) { BOOLEAN handled = FALSE; diff --git a/phlib/svcsup.c b/phlib/svcsup.c index 85bbdfa55938..850357f97470 100644 --- a/phlib/svcsup.c +++ b/phlib/svcsup.c @@ -357,7 +357,7 @@ ULONG PhGetServiceTypeInteger( )) return integer; else - return -1; + return ULONG_MAX; } PWSTR PhGetServiceStartTypeString( @@ -391,7 +391,7 @@ ULONG PhGetServiceStartTypeInteger( )) return integer; else - return -1; + return ULONG_MAX; } PWSTR PhGetServiceErrorControlString( @@ -425,7 +425,7 @@ ULONG PhGetServiceErrorControlInteger( )) return integer; else - return -1; + return ULONG_MAX; } PPH_STRING PhGetServiceNameFromTag( diff --git a/tools/peview/clrprp.c b/tools/peview/clrprp.c index aeff3a2a7188..4da668763c63 100644 --- a/tools/peview/clrprp.c +++ b/tools/peview/clrprp.c @@ -196,7 +196,7 @@ VOID PvpPeClrEnumSections( lvItemIndex = PhAddListViewItem(ListViewHandle, MAXINT, sectionName, NULL); PhPrintPointer(pointer, UlongToPtr(streamHeader->Offset)); PhSetListViewSubItem(ListViewHandle, lvItemIndex, 1, pointer); - PhSetListViewSubItem(ListViewHandle, lvItemIndex, 2, PhaFormatSize(streamHeader->Size, -1)->Buffer); + PhSetListViewSubItem(ListViewHandle, lvItemIndex, 2, PhaFormatSize(streamHeader->Size, ULONG_MAX)->Buffer); } // Stream headers don't have fixed sizes... diff --git a/tools/peview/colmgr.c b/tools/peview/colmgr.c index 286f4f9ee564..a220a0fa3874 100644 --- a/tools/peview/colmgr.c +++ b/tools/peview/colmgr.c @@ -139,7 +139,7 @@ PPH_CM_COLUMN PhCmCreateColumn( tnColumn.Text = Column->Text; tnColumn.Width = Column->Width; tnColumn.Alignment = Column->Alignment; - tnColumn.DisplayIndex = Column->Visible ? Column->DisplayIndex : -1; + tnColumn.DisplayIndex = Column->Visible ? Column->DisplayIndex : ULONG_MAX; tnColumn.TextFlags = Column->TextFlags; TreeNew_AddColumn(Manager->Handle, &tnColumn); @@ -157,7 +157,7 @@ VOID PhCmSetNotifyPlugin( } else { - if (PhFindItemList(Manager->NotifyList, Plugin) != -1) + if (PhFindItemList(Manager->NotifyList, Plugin) != ULONG_MAX) return; } @@ -297,7 +297,7 @@ BOOLEAN PhCmLoadSettingsEx( if (valuePart.Length != 0) goto CleanupExit; - displayIndex = -1; + displayIndex = ULONG_MAX; } // Width @@ -413,7 +413,7 @@ BOOLEAN PhCmLoadSettingsEx( ULONG sortColumn; PH_SORT_ORDER sortOrder; - sortColumn = -1; + sortColumn = ULONG_MAX; if (valuePart.Buffer[0] == '+') { @@ -439,7 +439,7 @@ BOOLEAN PhCmLoadSettingsEx( PhStringToInteger64(&subPart, 10, &integer); sortOrder = (PH_SORT_ORDER)integer; - if (sortColumn != -1 && sortOrder <= DescendingSortOrder) + if (sortColumn != ULONG_MAX && sortOrder <= DescendingSortOrder) { TreeNew_SetSort(TreeNewHandle, sortColumn, sortOrder); } diff --git a/tools/peview/exlfexports.c b/tools/peview/exlfexports.c index 21b187a9f51e..dc89c3b3c629 100644 --- a/tools/peview/exlfexports.c +++ b/tools/peview/exlfexports.c @@ -48,7 +48,7 @@ VOID PvpProcessElfExports( PhSetListViewSubItem(ListViewHandle, lvItemIndex, 1, pointer); PhSetListViewSubItem(ListViewHandle, lvItemIndex, 2, export->Name); - PhSetListViewSubItem(ListViewHandle, lvItemIndex, 3, PhaFormatSize(export->Size, -1)->Buffer); + PhSetListViewSubItem(ListViewHandle, lvItemIndex, 3, PhaFormatSize(export->Size, ULONG_MAX)->Buffer); PhSetListViewSubItem(ListViewHandle, lvItemIndex, 4, PvpGetSymbolTypeName(export->TypeInfo)); PhSetListViewSubItem(ListViewHandle, lvItemIndex, 5, PvpGetSymbolBindingName(export->TypeInfo)); PhSetListViewSubItem(ListViewHandle, lvItemIndex, 6, PvpGetSymbolVisibility(export->OtherInfo)); diff --git a/tools/peview/exlfprp.c b/tools/peview/exlfprp.c index ecbd8fff9640..7fb7456a1418 100644 --- a/tools/peview/exlfprp.c +++ b/tools/peview/exlfprp.c @@ -416,7 +416,7 @@ VOID PvpLoadWslSections( PhPrintPointer(pointer, (PVOID)imageSections[i].Offset); PhSetListViewSubItem(LvHandle, lvItemIndex, 3, pointer); - PhSetListViewSubItem(LvHandle, lvItemIndex, 4, PhaFormatSize(imageSections[i].Size, -1)->Buffer); + PhSetListViewSubItem(LvHandle, lvItemIndex, 4, PhaFormatSize(imageSections[i].Size, ULONG_MAX)->Buffer); PhSetListViewSubItem(LvHandle, lvItemIndex, 5, PH_AUTO_T(PH_STRING, PvpGetWslImageSectionFlagsString(imageSections[i].Flags))->Buffer); } diff --git a/tools/peview/pdbprp.c b/tools/peview/pdbprp.c index 7d4751f39084..c86f32c99fbe 100644 --- a/tools/peview/pdbprp.c +++ b/tools/peview/pdbprp.c @@ -70,18 +70,18 @@ VOID PhInitializeTreeNewColumnMenuEx( resetSortMenuItem = PhCreateEMenuItem(0, PH_TN_COLUMN_MENU_RESET_SORT_ID, L"Reset sort", NULL, NULL); } - PhInsertEMenuItem(Data->Menu, sizeColumnToFitMenuItem, -1); - PhInsertEMenuItem(Data->Menu, sizeAllColumnsToFitMenuItem, -1); + PhInsertEMenuItem(Data->Menu, sizeColumnToFitMenuItem, ULONG_MAX); + PhInsertEMenuItem(Data->Menu, sizeAllColumnsToFitMenuItem, ULONG_MAX); if (!(Flags & PH_TN_COLUMN_MENU_NO_VISIBILITY)) { - PhInsertEMenuItem(Data->Menu, hideColumnMenuItem, -1); + PhInsertEMenuItem(Data->Menu, hideColumnMenuItem, ULONG_MAX); if (resetSortMenuItem) - PhInsertEMenuItem(Data->Menu, resetSortMenuItem, -1); + PhInsertEMenuItem(Data->Menu, resetSortMenuItem, ULONG_MAX); - PhInsertEMenuItem(Data->Menu, PhCreateEMenuSeparator(), -1); - PhInsertEMenuItem(Data->Menu, chooseColumnsMenuItem, -1); + PhInsertEMenuItem(Data->Menu, PhCreateEMenuSeparator(), ULONG_MAX); + PhInsertEMenuItem(Data->Menu, chooseColumnsMenuItem, ULONG_MAX); if (TreeNew_GetFixedColumn(Data->TreeNewHandle)) minimumNumberOfColumns = 2; // don't allow user to remove all normal columns (the fixed column can never be removed) @@ -99,7 +99,7 @@ VOID PhInitializeTreeNewColumnMenuEx( else { if (resetSortMenuItem) - PhInsertEMenuItem(Data->Menu, resetSortMenuItem, -1); + PhInsertEMenuItem(Data->Menu, resetSortMenuItem, ULONG_MAX); } if (!Data->MouseEvent || !Data->MouseEvent->Column) @@ -300,7 +300,7 @@ VOID PhRemoveTreeNewFilter( index = PhFindItemList(Support->FilterList, Entry); - if (index != -1) + if (index != ULONG_MAX) { PhRemoveItemList(Support->FilterList, index); PhFree(Entry); @@ -581,7 +581,7 @@ VOID PvRemoveSymbolNode( PhRemoveEntryHashtable(Context->NodeHashtable, &Node); - if ((index = PhFindItemList(Context->NodeList, Node)) != -1) + if ((index = PhFindItemList(Context->NodeList, Node)) != ULONG_MAX) PhRemoveItemList(Context->NodeList, index); PvDestroySymbolNode(Node); @@ -1217,7 +1217,7 @@ INT_PTR CALLBACK PvpSymbolsDlgProc( if (numberOfSymbolNodes != 0) { menu = PhCreateEMenu(); - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_SYMBOL_COPY, L"Copy", NULL, NULL), -1); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_SYMBOL_COPY, L"Copy", NULL, NULL), ULONG_MAX); PhInsertCopyCellEMenuItem(menu, ID_SYMBOL_COPY, context->TreeNewHandle, contextMenuEvent->Column); selectedItem = PhShowEMenu( @@ -1229,7 +1229,7 @@ INT_PTR CALLBACK PvpSymbolsDlgProc( contextMenuEvent->Location.y ); - if (selectedItem && selectedItem->Id != -1) + if (selectedItem && selectedItem->Id != ULONG_MAX) { BOOLEAN handled = FALSE; diff --git a/tools/peview/peprp.c b/tools/peview/peprp.c index eade518e72f3..4a94e9bd4b09 100644 --- a/tools/peview/peprp.c +++ b/tools/peview/peprp.c @@ -705,7 +705,7 @@ VOID PvpSetPeImageSections( lvItemIndex = PhAddListViewItem(ListViewHandle, MAXINT, sectionName, NULL); PhSetListViewSubItem(ListViewHandle, lvItemIndex, 1, pointer); - PhSetListViewSubItem(ListViewHandle, lvItemIndex, 2, PhaFormatSize(PvMappedImage.Sections[i].SizeOfRawData, -1)->Buffer); + PhSetListViewSubItem(ListViewHandle, lvItemIndex, 2, PhaFormatSize(PvMappedImage.Sections[i].SizeOfRawData, ULONG_MAX)->Buffer); PhSetListViewSubItem(ListViewHandle, lvItemIndex, 3, PH_AUTO_T(PH_STRING, PvpGetSectionCharacteristics(PvMappedImage.Sections[i].Characteristics))->Buffer); if (PvMappedImage.Sections[i].VirtualAddress && PvMappedImage.Sections[i].SizeOfRawData) diff --git a/tools/peview/resprp.c b/tools/peview/resprp.c index ff6df3db3481..e82d22a8b6d3 100644 --- a/tools/peview/resprp.c +++ b/tools/peview/resprp.c @@ -188,7 +188,7 @@ INT_PTR CALLBACK PvpPeResourcesDlgProc( PhDereferenceObject(string); } - PhSetListViewSubItem(lvHandle, lvItemIndex, PVE_RESOURCES_COLUMN_INDEX_SIZE, PhaFormatSize(entry.Size, -1)->Buffer); + PhSetListViewSubItem(lvHandle, lvItemIndex, PVE_RESOURCES_COLUMN_INDEX_SIZE, PhaFormatSize(entry.Size, ULONG_MAX)->Buffer); // dmex: This crashes when enumerating resources of VM protected binaries. //if (entry.Data && entry.Size) From 75956f1ab0c2c2f303900a1afe76d1e3b1afa0a6 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 27 Apr 2019 21:40:25 +0200 Subject: [PATCH 1836/2058] Update D3DKMT 19H1 types --- plugins/ExtendedTools/d3dkmt.h | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/plugins/ExtendedTools/d3dkmt.h b/plugins/ExtendedTools/d3dkmt.h index 84c26a8a7351..e5731477d26e 100644 --- a/plugins/ExtendedTools/d3dkmt.h +++ b/plugins/ExtendedTools/d3dkmt.h @@ -71,6 +71,9 @@ typedef enum _KMTQUERYADAPTERINFOTYPE KMTQAITYPE_ADAPTERPERFDATA = 62, // D3DKMT_ADAPTER_PERFDATA KMTQAITYPE_ADAPTERPERFDATA_CAPS = 63, // D3DKMT_ADAPTER_PERFDATACAPS KMTQUITYPE_GPUVERSION = 64, // D3DKMT_GPUVERSION + KMTQAITYPE_DRIVER_DESCRIPTION = 65, // D3DKMT_DRIVER_DESCRIPTION // since WDDM2_6 + KMTQAITYPE_DRIVER_DESCRIPTION_RENDER = 66, // D3DKMT_DRIVER_DESCRIPTION + KMTQAITYPE_SCANOUT_CAPS = 67, // D3DKMT_QUERY_SCANOUT_CAPS } KMTQUERYADAPTERINFOTYPE; typedef enum _KMTUMDVERSION @@ -418,6 +421,7 @@ typedef enum D3DKMT_DRIVERVERSION KMT_DRIVERVERSION_WDDM_2_3 = 2300, // 1709 KMT_DRIVERVERSION_WDDM_2_4 = 2400, // 1803 KMT_DRIVERVERSION_WDDM_2_5 = 2500, // 1809 + KMT_DRIVERVERSION_WDDM_2_6 = 2600, // 19H1 } D3DKMT_DRIVERVERSION; // Specifies the type of display device that the graphics adapter supports. @@ -889,6 +893,18 @@ typedef struct _D3DKMT_GPUVERSION _Out_ WCHAR GpuArchitecture[DXGK_MAX_GPUVERSION_NAME_LENGTH]; // The gpu architecture of the adapter. } D3DKMT_GPUVERSION; +// Describes the kernel mode display driver. +typedef struct _D3DKMT_DRIVER_DESCRIPTION +{ + WCHAR DriverDescription[4096]; // out: Pointer to a string of characters that represent the driver description. +} D3DKMT_DRIVER_DESCRIPTION; + +typedef struct _D3DKMT_QUERY_SCANOUT_CAPS +{ + ULONG VidPnSourceId; + UINT Caps; +} D3DKMT_QUERY_SCANOUT_CAPS; + // Describes the mapping of the given name of a device to a graphics adapter handle and monitor output. typedef struct _D3DKMT_OPENADAPTERFROMDEVICENAME { @@ -1480,6 +1496,7 @@ typedef enum _D3DKMT_ESCAPETYPE // unused (35 previously was D3DKMT_ESCAPE_GET_PREFERRED_MODE) D3DKMT_ESCAPE_GET_DISPLAY_CONFIGURATIONS = 36, // since WDDM2_3 D3DKMT_ESCAPE_QUERY_IOMMU_STATUS = 37, // since WDDM2_4 + D3DKMT_ESCAPE_CCD_DATABASE = 38, // since WDDM2_6 D3DKMT_ESCAPE_WIN32K_START = 1024, D3DKMT_ESCAPE_WIN32K_HIP_DEVICE_INFO = 1024, From bad9bca201ce4c5ab80bc286090b505b258f184b Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 27 Apr 2019 23:01:56 +0200 Subject: [PATCH 1837/2058] Fix token parameter --- ProcessHacker/tokprp.c | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/ProcessHacker/tokprp.c b/ProcessHacker/tokprp.c index c09c89c4252f..e9a5a6f83487 100644 --- a/ProcessHacker/tokprp.c +++ b/ProcessHacker/tokprp.c @@ -767,7 +767,7 @@ INT_PTR CALLBACK PhpTokenPageProc( if (NT_SUCCESS(tokenPageContext->OpenObject( &tokenHandle, TOKEN_QUERY, - tokenPageContext->Context + tokenPageContext->ProcessId ))) { PTOKEN_USER tokenUser; @@ -943,7 +943,7 @@ INT_PTR CALLBACK PhpTokenPageProc( status = tokenPageContext->OpenObject( &tokenHandle, TOKEN_ADJUST_PRIVILEGES, - tokenPageContext->Context + tokenPageContext->ProcessId ); if (NT_SUCCESS(status)) @@ -1091,7 +1091,7 @@ INT_PTR CALLBACK PhpTokenPageProc( status = tokenPageContext->OpenObject( &tokenHandle, TOKEN_ADJUST_GROUPS, - tokenPageContext->Context + tokenPageContext->ProcessId ); if (NT_SUCCESS(status)) @@ -1226,7 +1226,7 @@ INT_PTR CALLBACK PhpTokenPageProc( status = tokenPageContext->OpenObject( &tokenHandle, TOKEN_ADJUST_DEFAULT, - tokenPageContext->Context + tokenPageContext->ProcessId ); if (NT_SUCCESS(status)) @@ -1271,7 +1271,7 @@ INT_PTR CALLBACK PhpTokenPageProc( L"TokenDefault", tokenPageContext->OpenObject, NULL, - tokenPageContext->Context + tokenPageContext->ProcessId ); } break; @@ -1283,7 +1283,7 @@ INT_PTR CALLBACK PhpTokenPageProc( L"Token", tokenPageContext->OpenObject, NULL, - tokenPageContext->Context + tokenPageContext->ProcessId ); } break; @@ -1314,7 +1314,7 @@ INT_PTR CALLBACK PhpTokenPageProc( if (NT_SUCCESS(status = tokenPageContext->OpenObject( &tokenHandle, TOKEN_QUERY, - tokenPageContext->Context + tokenPageContext->ProcessId ))) { if (NT_SUCCESS(status = PhGetTokenIntegrityLevelRID( @@ -1385,7 +1385,7 @@ INT_PTR CALLBACK PhpTokenPageProc( if (NT_SUCCESS(status = tokenPageContext->OpenObject( &tokenHandle, TOKEN_QUERY | TOKEN_ADJUST_DEFAULT, - tokenPageContext->Context + tokenPageContext->ProcessId ))) { static SID_IDENTIFIER_AUTHORITY mandatoryLabelAuthority = SECURITY_MANDATORY_LABEL_AUTHORITY; @@ -1437,7 +1437,7 @@ INT_PTR CALLBACK PhpTokenPageProc( if (NT_SUCCESS(tokenPageContext->OpenObject( &tokenHandle, TOKEN_QUERY, - tokenPageContext->Context + tokenPageContext->ProcessId ))) { PhGetTokenIsAppContainer(tokenHandle, &tokenIsAppContainer); @@ -1723,7 +1723,7 @@ INT_PTR CALLBACK PhpTokenGeneralPageProc( if (NT_SUCCESS(tokenPageContext->OpenObject( &tokenHandle, TOKEN_QUERY, - tokenPageContext->Context + tokenPageContext->ProcessId ))) { PTOKEN_USER tokenUser; @@ -1789,7 +1789,7 @@ INT_PTR CALLBACK PhpTokenGeneralPageProc( if (NT_SUCCESS(tokenPageContext->OpenObject( &tokenHandle, TOKEN_QUERY_SOURCE, - tokenPageContext->Context + tokenPageContext->ProcessId ))) { TOKEN_SOURCE tokenSource; @@ -1847,7 +1847,7 @@ INT_PTR CALLBACK PhpTokenGeneralPageProc( if (NT_SUCCESS(status = tokenPageContext->OpenObject( &tokenHandle, TOKEN_QUERY, - tokenPageContext->Context + tokenPageContext->ProcessId ))) { PhShowTokenProperties(hwndDlg, PhpOpenLinkedToken, tokenPageContext->ProcessId, (PVOID)tokenHandle, L"Linked Token"); @@ -1966,7 +1966,7 @@ INT_PTR CALLBACK PhpTokenAdvancedPageProc( if (NT_SUCCESS(tokenPageContext->OpenObject( &tokenHandle, TOKEN_QUERY, - tokenPageContext->Context + tokenPageContext->ProcessId ))) { TOKEN_STATISTICS statistics; @@ -2451,7 +2451,7 @@ BOOLEAN PhpAddTokenCapabilities( { HANDLE processHandle; - if (NT_SUCCESS(PhOpenProcess(&processHandle, PROCESS_QUERY_LIMITED_INFORMATION, (HANDLE)TokenPageContext->Context))) + if (NT_SUCCESS(PhOpenProcess(&processHandle, PROCESS_QUERY_LIMITED_INFORMATION, TokenPageContext->ProcessId))) { name = PhGetProcessPackageFullName(processHandle); PhpAddAttributeNode(&TokenPageContext->CapsTreeContext, node, PhFormatString(L"Package: %s", PhGetString(name))); @@ -2790,7 +2790,7 @@ BOOLEAN PhpAddTokenClaimAttributes( if (!NT_SUCCESS(TokenPageContext->OpenObject( &tokenHandle, TOKEN_QUERY, - TokenPageContext->Context + TokenPageContext->ProcessId ))) return FALSE; @@ -2963,7 +2963,7 @@ BOOLEAN PhpAddTokenAttributes( if (!NT_SUCCESS(TokenPageContext->OpenObject( &tokenHandle, TOKEN_QUERY, - TokenPageContext->Context + TokenPageContext->ProcessId ))) return FALSE; @@ -3331,7 +3331,7 @@ INT_PTR CALLBACK PhpTokenContainerPageProc( if (NT_SUCCESS(tokenPageContext->OpenObject( &tokenHandle, TOKEN_QUERY, - tokenPageContext->Context + tokenPageContext->ProcessId ))) { PTOKEN_APPCONTAINER_INFORMATION appContainerInfo; @@ -3469,7 +3469,7 @@ INT_PTR CALLBACK PhpTokenContainerPageProc( if (NT_SUCCESS(tokenPageContext->OpenObject( &tokenHandle, TOKEN_QUERY | TOKEN_IMPERSONATE | TOKEN_DUPLICATE, - tokenPageContext->Context + tokenPageContext->ProcessId ))) { PTOKEN_APPCONTAINER_INFORMATION appContainerInfo; From 06bcc5540fc2328583e2c046f82b1022cfc117c2 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 27 Apr 2019 23:02:44 +0200 Subject: [PATCH 1838/2058] HardwareDevices: Improve error checking --- plugins/HardwareDevices/ndis.c | 259 ++++++++++++++++----------------- 1 file changed, 128 insertions(+), 131 deletions(-) diff --git a/plugins/HardwareDevices/ndis.c b/plugins/HardwareDevices/ndis.c index 45d3e4d55c0e..6ec421783dbd 100644 --- a/plugins/HardwareDevices/ndis.c +++ b/plugins/HardwareDevices/ndis.c @@ -401,7 +401,7 @@ NTSTATUS NetworkAdapterQueryLinkSpeed( memset(&result, 0, sizeof(NDIS_LINK_SPEED)); - status = NtDeviceIoControlFile( + if (NT_SUCCESS(status = NtDeviceIoControlFile( DeviceHandle, NULL, NULL, @@ -412,9 +412,10 @@ NTSTATUS NetworkAdapterQueryLinkSpeed( sizeof(NDIS_OID), &result, sizeof(result) - ); - - *LinkSpeed = UInt32x32To64(result.XmitLinkSpeed, NDIS_UNIT_OF_MEASUREMENT); + ))) + { + *LinkSpeed = UInt32x32To64(result.XmitLinkSpeed, NDIS_UNIT_OF_MEASUREMENT); + } return status; } @@ -526,131 +527,127 @@ PWSTR MediumTypeToString( return L"N/A"; } +BOOLEAN NetworkAdapterQueryInternet( + _Inout_ PDV_NETADAPTER_SYSINFO_CONTEXT Context, + _In_ PPH_STRING IpAddress + ) +{ + // https://technet.microsoft.com/en-us/library/cc766017.aspx + BOOLEAN socketResult = FALSE; + DNS_STATUS dnsQueryStatus = DNS_ERROR_RCODE_NO_ERROR; + PDNS_RECORD dnsQueryRecords = NULL; + + __try + { + if ((dnsQueryStatus = DnsQuery( + L"www.msftncsi.com", + DNS_TYPE_A, + DNS_QUERY_NO_HOSTS_FILE | DNS_QUERY_BYPASS_CACHE, + NULL, + &dnsQueryRecords, + NULL + )) != DNS_ERROR_RCODE_NO_ERROR) + { + __leave; + } -//BOOLEAN NetworkAdapterQueryInternet( -// _Inout_ PDV_NETADAPTER_SYSINFO_CONTEXT Context, -// _In_ PPH_STRING IpAddress -// ) -//{ -// // https://technet.microsoft.com/en-us/library/cc766017.aspx -// BOOLEAN socketResult = FALSE; -// WSADATA wsadata; -// DNS_STATUS dnsQueryStatus = DNS_ERROR_RCODE_NO_ERROR; -// PDNS_RECORD dnsQueryRecords = NULL; -// -// WSAStartup(WINSOCK_VERSION, &wsadata); -// -// __try -// { -// if ((dnsQueryStatus = DnsQuery( -// L"www.msftncsi.com", -// DNS_TYPE_A, -// DNS_QUERY_NO_HOSTS_FILE | DNS_QUERY_BYPASS_CACHE, -// NULL, -// &dnsQueryRecords, -// NULL -// )) != DNS_ERROR_RCODE_NO_ERROR) -// { -// __leave; -// } -// -// for (PDNS_RECORD i = dnsQueryRecords; i != NULL; i = i->pNext) -// { -// if (i->wType == DNS_TYPE_A) -// { -// SOCKET socketHandle = INVALID_SOCKET; -// -// if ((socketHandle = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, 0)) == INVALID_SOCKET) -// continue; -// -// IN_ADDR sockAddr; -// InetPton(AF_INET, IpAddress->Buffer, &sockAddr); -// -// SOCKADDR_IN localaddr = { 0 }; -// localaddr.sin_family = AF_INET; -// localaddr.sin_addr.s_addr = sockAddr.s_addr; -// -// if (bind(socketHandle, (PSOCKADDR)&localaddr, sizeof(localaddr)) == SOCKET_ERROR) -// { -// closesocket(socketHandle); -// continue; -// } -// -// SOCKADDR_IN remoteAddr; -// remoteAddr.sin_family = AF_INET; -// remoteAddr.sin_port = htons(80); -// remoteAddr.sin_addr.s_addr = i->Data.A.IpAddress; -// -// if (WSAConnect(socketHandle, (PSOCKADDR)&remoteAddr, sizeof(remoteAddr), NULL, NULL, NULL, NULL) != SOCKET_ERROR) -// { -// socketResult = TRUE; -// closesocket(socketHandle); -// break; -// } -// -// closesocket(socketHandle); -// } -// } -// } -// __finally -// { -// if (dnsQueryRecords) -// { -// DnsFree(dnsQueryRecords, DnsFreeRecordList); -// } -// } -// -// __try -// { -// if ((dnsQueryStatus = DnsQuery( -// L"ipv6.msftncsi.com", -// DNS_TYPE_AAAA, -// DNS_QUERY_NO_HOSTS_FILE | DNS_QUERY_BYPASS_CACHE, // | DNS_QUERY_DUAL_ADDR -// NULL, -// &dnsQueryRecords, -// NULL -// )) != DNS_ERROR_RCODE_NO_ERROR) -// { -// __leave; -// } -// -// for (PDNS_RECORD i = dnsQueryRecords; i != NULL; i = i->pNext) -// { -// if (i->wType == DNS_TYPE_AAAA) -// { -// SOCKET socketHandle = INVALID_SOCKET; -// -// if ((socketHandle = WSASocket(AF_INET6, SOCK_STREAM, IPPROTO_TCP, NULL, 0, 0)) == INVALID_SOCKET) -// continue; -// -// IN6_ADDR sockAddr; -// InetPton(AF_INET6, IpAddress->Buffer, &sockAddr); -// -// SOCKADDR_IN6 remoteAddr = { 0 }; -// remoteAddr.sin6_family = AF_INET6; -// remoteAddr.sin6_port = htons(80); -// memcpy(&remoteAddr.sin6_addr.u.Byte, i->Data.AAAA.Ip6Address.IP6Byte, sizeof(i->Data.AAAA.Ip6Address.IP6Byte)); -// -// if (WSAConnect(socketHandle, (PSOCKADDR)&remoteAddr, sizeof(SOCKADDR_IN6), NULL, NULL, NULL, NULL) != SOCKET_ERROR) -// { -// socketResult = TRUE; -// closesocket(socketHandle); -// break; -// } -// -// closesocket(socketHandle); -// } -// } -// } -// __finally -// { -// if (dnsQueryRecords) -// { -// DnsFree(dnsQueryRecords, DnsFreeRecordList); -// } -// } -// -// WSACleanup(); -// -// return socketResult; -//} \ No newline at end of file + for (PDNS_RECORD i = dnsQueryRecords; i != NULL; i = i->pNext) + { + if (i->wType == DNS_TYPE_A) + { + SOCKET socketHandle = INVALID_SOCKET; + + if ((socketHandle = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, 0)) == INVALID_SOCKET) + continue; + + IN_ADDR sockAddr; + InetPton(AF_INET, IpAddress->Buffer, &sockAddr); + + SOCKADDR_IN localaddr = { 0 }; + localaddr.sin_family = AF_INET; + localaddr.sin_addr.s_addr = sockAddr.s_addr; + + if (bind(socketHandle, (PSOCKADDR)&localaddr, sizeof(localaddr)) == SOCKET_ERROR) + { + closesocket(socketHandle); + continue; + } + + SOCKADDR_IN remoteAddr; + remoteAddr.sin_family = AF_INET; + remoteAddr.sin_port = htons(80); + remoteAddr.sin_addr.s_addr = i->Data.A.IpAddress; + + if (WSAConnect(socketHandle, (PSOCKADDR)&remoteAddr, sizeof(remoteAddr), NULL, NULL, NULL, NULL) != SOCKET_ERROR) + { + socketResult = TRUE; + closesocket(socketHandle); + break; + } + + closesocket(socketHandle); + } + } + } + __finally + { + if (dnsQueryRecords) + { + DnsFree(dnsQueryRecords, DnsFreeRecordList); + } + } + + __try + { + if ((dnsQueryStatus = DnsQuery( + L"ipv6.msftncsi.com", + DNS_TYPE_AAAA, + DNS_QUERY_NO_HOSTS_FILE | DNS_QUERY_BYPASS_CACHE, // | DNS_QUERY_DUAL_ADDR + NULL, + &dnsQueryRecords, + NULL + )) != DNS_ERROR_RCODE_NO_ERROR) + { + __leave; + } + + for (PDNS_RECORD i = dnsQueryRecords; i != NULL; i = i->pNext) + { + if (i->wType == DNS_TYPE_AAAA) + { + SOCKET socketHandle = INVALID_SOCKET; + + if ((socketHandle = WSASocket(AF_INET6, SOCK_STREAM, IPPROTO_TCP, NULL, 0, 0)) == INVALID_SOCKET) + continue; + + IN6_ADDR sockAddr; + InetPton(AF_INET6, IpAddress->Buffer, &sockAddr); + + SOCKADDR_IN6 remoteAddr = { 0 }; + remoteAddr.sin6_family = AF_INET6; + remoteAddr.sin6_port = htons(80); + memcpy(&remoteAddr.sin6_addr.u.Byte, i->Data.AAAA.Ip6Address.IP6Byte, sizeof(i->Data.AAAA.Ip6Address.IP6Byte)); + + if (WSAConnect(socketHandle, (PSOCKADDR)&remoteAddr, sizeof(SOCKADDR_IN6), NULL, NULL, NULL, NULL) != SOCKET_ERROR) + { + socketResult = TRUE; + closesocket(socketHandle); + break; + } + + closesocket(socketHandle); + } + } + } + __finally + { + if (dnsQueryRecords) + { + DnsFree(dnsQueryRecords, DnsFreeRecordList); + } + } + + WSACleanup(); + + return socketResult; +} From e511208922dbdf31bdf75f6c9042494cc6b4f7c2 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 27 Apr 2019 23:03:13 +0200 Subject: [PATCH 1839/2058] ExtendedTools: Fix SAL annotation --- plugins/ExtendedTools/gpumon.c | 10 +++++----- plugins/ExtendedTools/gpumon.h | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/plugins/ExtendedTools/gpumon.c b/plugins/ExtendedTools/gpumon.c index 9e0fdc642acd..cda289ee5b3a 100644 --- a/plugins/ExtendedTools/gpumon.c +++ b/plugins/ExtendedTools/gpumon.c @@ -374,11 +374,11 @@ ULONG64 EtpQueryGpuInstalledMemory( BOOLEAN EtQueryDeviceProperties( _In_ PWSTR DeviceInterface, - _Out_ PPH_STRING *Description, - _Out_ PPH_STRING *DriverDate, - _Out_ PPH_STRING *DriverVersion, - _Out_ PPH_STRING *LocationInfo, - _Out_ ULONG64 *InstalledMemory + _Out_opt_ PPH_STRING *Description, + _Out_opt_ PPH_STRING *DriverDate, + _Out_opt_ PPH_STRING *DriverVersion, + _Out_opt_ PPH_STRING *LocationInfo, + _Out_opt_ ULONG64 *InstalledMemory ) { DEVPROPTYPE devicePropertyType; diff --git a/plugins/ExtendedTools/gpumon.h b/plugins/ExtendedTools/gpumon.h index 825d2795a0e7..11fd82ec2f01 100644 --- a/plugins/ExtendedTools/gpumon.h +++ b/plugins/ExtendedTools/gpumon.h @@ -34,11 +34,11 @@ PETP_GPU_ADAPTER EtpAllocateGpuAdapter( BOOLEAN EtQueryDeviceProperties( _In_ PWSTR DeviceInterface, - _Out_ PPH_STRING *Description, - _Out_ PPH_STRING *DriverDate, - _Out_ PPH_STRING *DriverVersion, - _Out_ PPH_STRING *LocationInfo, - _Out_ ULONG64 *InstalledMemory + _Out_opt_ PPH_STRING *Description, + _Out_opt_ PPH_STRING *DriverDate, + _Out_opt_ PPH_STRING *DriverVersion, + _Out_opt_ PPH_STRING *LocationInfo, + _Out_opt_ ULONG64 *InstalledMemory ); VOID NTAPI EtGpuProcessesUpdatedCallback( From c3d6b7e82a3b9f7c232ff9489c377143fbc99145 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 27 Apr 2019 23:03:37 +0200 Subject: [PATCH 1840/2058] ExtendedTools: Add WDDM 2.6 version support --- plugins/ExtendedTools/gpudetails.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/plugins/ExtendedTools/gpudetails.c b/plugins/ExtendedTools/gpudetails.c index a8ba6dd0adcd..dedc812db667 100644 --- a/plugins/ExtendedTools/gpudetails.c +++ b/plugins/ExtendedTools/gpudetails.c @@ -2,7 +2,7 @@ * Process Hacker Extended Tools - * GPU details window * - * Copyright (C) 2018 dmex + * Copyright (C) 2018-2019 dmex * * This file is part of Process Hacker. * @@ -160,6 +160,9 @@ VOID EtpQueryAdapterDriverModel( case KMT_DRIVERVERSION_WDDM_2_5: PhSetListViewSubItem(ListViewHandle, GPUADAPTER_DETAILS_INDEX_WDDMVERSION, 1, L"WDDM 2.5"); break; + case KMT_DRIVERVERSION_WDDM_2_6: + PhSetListViewSubItem(ListViewHandle, GPUADAPTER_DETAILS_INDEX_WDDMVERSION, 1, L"WDDM 2.6"); + break; default: PhSetListViewSubItem(ListViewHandle, GPUADAPTER_DETAILS_INDEX_WDDMVERSION, 1, L"ERROR"); break; From 4345a51edece6673a7a609e66dcc1e9e81409655 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 27 Apr 2019 23:04:53 +0200 Subject: [PATCH 1841/2058] Improve macro usage --- phlib/mapimg.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/phlib/mapimg.c b/phlib/mapimg.c index 8eecc0e0ad23..3a9f7905d58e 100644 --- a/phlib/mapimg.c +++ b/phlib/mapimg.c @@ -766,7 +766,6 @@ NTSTATUS PhGetMappedImageExportEntry( } } - if (exportByName) { name = PhMappedImageRvaToVa( @@ -807,7 +806,7 @@ NTSTATUS PhGetMappedImageExportFunction( index = PhpLookupMappedImageExportName(Exports, Name); - if (index == -1) + if (index == ULONG_MAX) return STATUS_PROCEDURE_NOT_FOUND; Ordinal = Exports->OrdinalTable[index] + (USHORT)Exports->ExportDirectory->Base; @@ -865,7 +864,7 @@ NTSTATUS PhGetMappedImageExportFunctionRemote( index = PhpLookupMappedImageExportName(Exports, Name); - if (index == -1) + if (index == ULONG_MAX) return STATUS_PROCEDURE_NOT_FOUND; Ordinal = Exports->OrdinalTable[index] + (USHORT)Exports->ExportDirectory->Base; @@ -904,7 +903,7 @@ ULONG PhpLookupMappedImageExportName( LONG i; if (Exports->ExportDirectory->NumberOfNames == 0) - return -1; + return ULONG_MAX; low = 0; high = Exports->ExportDirectory->NumberOfNames - 1; @@ -923,7 +922,7 @@ ULONG PhpLookupMappedImageExportName( ); if (!name) - return -1; + return ULONG_MAX; // TODO: Probe the name. @@ -937,7 +936,7 @@ ULONG PhpLookupMappedImageExportName( low = i + 1; } while (low <= high); - return -1; + return ULONG_MAX; } NTSTATUS PhGetMappedImageImports( From 22e446a68ce6d67f0df1c69e322daefa19569ccd Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 27 Apr 2019 23:28:59 +0200 Subject: [PATCH 1842/2058] Remove RunAs dependencies on PEB --- ProcessHacker/runas.c | 77 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 73 insertions(+), 4 deletions(-) diff --git a/ProcessHacker/runas.c b/ProcessHacker/runas.c index bcfd1dfecbdf..383c4de67acf 100644 --- a/ProcessHacker/runas.c +++ b/ProcessHacker/runas.c @@ -260,6 +260,66 @@ PPH_STRING GetCurrentWinStaName( } } +PPH_STRING GetCurrentDesktopName( + VOID + ) +{ + PPH_STRING string; + + string = PhCreateStringEx(NULL, 0x200); + + if (GetUserObjectInformation( + GetThreadDesktop(HandleToULong(NtCurrentThreadId())), + UOI_NAME, + string->Buffer, + (ULONG)string->Length + sizeof(UNICODE_NULL), + NULL + )) + { + PhTrimToNullTerminatorString(string); + return string; + } + else + { + PhDereferenceObject(string); + return PhCreateString(L"Default"); + } +} + +PPH_STRING PhpGetCurrentDesktopInfo( + VOID + ) +{ + static PH_STRINGREF seperator = PH_STRINGREF_INIT(L"\\"); // OBJ_NAME_PATH_SEPARATOR + PPH_STRING desktopInfo = NULL; + PPH_STRING winstationName = NULL; + PPH_STRING desktopName = NULL; + + winstationName = GetCurrentWinStaName(); + desktopName = GetCurrentDesktopName(); + + if (winstationName && desktopName) + { + desktopInfo = PhConcatStringRef3(&winstationName->sr, &seperator, &desktopName->sr); + } + + if (PhIsNullOrEmptyString(desktopInfo)) + { + PH_STRINGREF desktopInfoSr; + + PhUnicodeStringToStringRef(&NtCurrentPeb()->ProcessParameters->DesktopInfo, &desktopInfoSr); + + PhMoveReference(&desktopInfo, PhCreateString2(&desktopInfoSr)); + } + + if (winstationName) + PhDereferenceObject(winstationName); + if (desktopName) + PhDereferenceObject(desktopName); + + return desktopInfo; +} + BOOLEAN PhpInitializeNetApi(VOID) { static PH_INITONCE initOnce = PH_INITONCE_INIT; @@ -795,23 +855,28 @@ VOID SetDefaultDesktopEntry( ) { INT sessionCount; - PH_STRINGREF desktopName; + PPH_STRING desktopName; - PhUnicodeStringToStringRef(&NtCurrentPeb()->ProcessParameters->DesktopInfo, &desktopName); + desktopName = PhpGetCurrentDesktopInfo(); if ((sessionCount = ComboBox_GetCount(ComboBoxHandle)) == CB_ERR) + { + PhClearReference(&desktopName); return; + } for (INT i = 0; i < sessionCount; i++) { PPH_RUNAS_DESKTOP_ITEM entry = (PPH_RUNAS_DESKTOP_ITEM)ComboBox_GetItemData(ComboBoxHandle, i); - if (PhEqualStringRef(&entry->DesktopName->sr, &desktopName, TRUE)) + if (PhEqualStringRef(&entry->DesktopName->sr, &desktopName->sr, TRUE)) { ComboBox_SetCurSel(ComboBoxHandle, i); break; } } + + PhClearReference(&desktopName); } INT_PTR CALLBACK PhpRunAsDlgProc( @@ -1078,10 +1143,14 @@ INT_PTR CALLBACK PhpRunAsDlgProc( &logonType )) { + ULONG sessionId = ULONG_MAX; + + PhGetProcessSessionId(NtCurrentProcess(), &sessionId); + if ( logonType == LOGON32_LOGON_INTERACTIVE && !context->ProcessId && - sessionId == NtCurrentPeb()->SessionId && + sessionId == sessionId && !useLinkedToken ) { From 96d1218408de929e324cf1c6372f7757ba736492 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 28 Apr 2019 00:36:25 +0200 Subject: [PATCH 1843/2058] Fix crash sorting threads by TID (hex) column --- ProcessHacker/thrdlist.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/ProcessHacker/thrdlist.c b/ProcessHacker/thrdlist.c index 94a12647645a..f1a6988a1e15 100644 --- a/ProcessHacker/thrdlist.c +++ b/ProcessHacker/thrdlist.c @@ -460,7 +460,7 @@ BEGIN_SORT_FUNCTION(Name) } END_SORT_FUNCTION -BEGIN_SORT_FUNCTION(Started) +BEGIN_SORT_FUNCTION(Created) { sortResult = uint64cmp(threadItem1->CreateTime.QuadPart, threadItem2->CreateTime.QuadPart); } @@ -539,6 +539,13 @@ BEGIN_SORT_FUNCTION(Critical) } END_SORT_FUNCTION +BEGIN_SORT_FUNCTION(TidHex) +{ + sortResult = uintptrcmp((ULONG_PTR)node1->ThreadId, (ULONG_PTR)node2->ThreadId); + //sortResult = ucharcmp(node1->ThreadIdHexText, node2->ThreadIdHexText, TRUE); +} +END_SORT_FUNCTION + BOOLEAN NTAPI PhpThreadTreeNewCallback( _In_ HWND hwnd, _In_ PH_TREENEW_MESSAGE Message, @@ -572,7 +579,7 @@ BOOLEAN NTAPI PhpThreadTreeNewCallback( SORT_FUNCTION(PrioritySymbolic), SORT_FUNCTION(Service), SORT_FUNCTION(Name), - SORT_FUNCTION(Started), + SORT_FUNCTION(Created), SORT_FUNCTION(StartModule), SORT_FUNCTION(ContextSwitches), SORT_FUNCTION(Priority), @@ -584,7 +591,8 @@ BOOLEAN NTAPI PhpThreadTreeNewCallback( SORT_FUNCTION(KernelTime), SORT_FUNCTION(UserTime), SORT_FUNCTION(IdealProcessor), - SORT_FUNCTION(Critical) + SORT_FUNCTION(Critical), + SORT_FUNCTION(TidHex), }; int (__cdecl *sortFunction)(void *, const void *, const void *); From 1a0ff98b0893a64d51aa60b439a10949aedbfa82 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 28 Apr 2019 02:19:48 +0200 Subject: [PATCH 1844/2058] Fix thread tab column index --- ProcessHacker/thrdlist.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ProcessHacker/thrdlist.c b/ProcessHacker/thrdlist.c index f1a6988a1e15..314ba487aaf2 100644 --- a/ProcessHacker/thrdlist.c +++ b/ProcessHacker/thrdlist.c @@ -114,7 +114,7 @@ VOID PhInitializeThreadList( PhAddTreeNewColumn(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_USERTIME, FALSE, L"User time", 100, PH_ALIGN_LEFT, ULONG_MAX, 0); PhAddTreeNewColumn(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_IDEALPROCESSOR, FALSE, L"Ideal processor", 80, PH_ALIGN_LEFT, ULONG_MAX, 0); PhAddTreeNewColumn(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_CRITICAL, FALSE, L"Critical", 80, PH_ALIGN_LEFT, ULONG_MAX, 0); - PhAddTreeNewColumn(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_TIDHEX, FALSE, L"TID (Hex)", 50, PH_ALIGN_RIGHT, 0, DT_RIGHT); + PhAddTreeNewColumn(TreeNewHandle, PH_THREAD_TREELIST_COLUMN_TIDHEX, FALSE, L"TID (Hex)", 50, PH_ALIGN_RIGHT, ULONG_MAX, DT_RIGHT); TreeNew_SetRedraw(TreeNewHandle, TRUE); TreeNew_SetTriState(TreeNewHandle, TRUE); @@ -345,7 +345,7 @@ VOID PhpRemoveThreadNode( // Remove from list and cleanup. - if ((index = PhFindItemList(Context->NodeList, ThreadNode)) != -1) + if ((index = PhFindItemList(Context->NodeList, ThreadNode)) != ULONG_MAX) PhRemoveItemList(Context->NodeList, index); PhpDestroyThreadNode(ThreadNode); From 0af44903692ed49834af387a0f7c0012bebc10a9 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 28 Apr 2019 02:48:27 +0200 Subject: [PATCH 1845/2058] Remove legacy PhCreateThread --- ProcessHacker/ProcessHacker.def | 1 + ProcessHacker/anawait.c | 6 +++--- ProcessHacker/dbgcon.c | 4 ++-- ProcessHacker/findobj.c | 10 ++++++---- ProcessHacker/plugman.c | 4 ++-- ProcessHacker/sysinfo.c | 6 +++--- phlib/basesup.c | 1 + plugins/ExtendedTools/etwmon.c | 13 +++++-------- plugins/ExtendedTools/gpunodes.c | 4 ++-- plugins/OnlineChecks/virustotal.c | 24 +++--------------------- plugins/WindowExplorer/wnddlg.c | 4 ++-- 11 files changed, 30 insertions(+), 47 deletions(-) diff --git a/ProcessHacker/ProcessHacker.def b/ProcessHacker/ProcessHacker.def index 59064057e535..337376084ee4 100644 --- a/ProcessHacker/ProcessHacker.def +++ b/ProcessHacker/ProcessHacker.def @@ -114,6 +114,7 @@ EXPORTS PhCreateStringEx PhCreateThread PhCreateThread2 + PhCreateThreadEx PhDecodeUnicodeDecoder PhDeleteArray PhDeleteBytesBuilder diff --git a/ProcessHacker/anawait.c b/ProcessHacker/anawait.c index d33b1e4d661e..f32333f9b624 100644 --- a/ProcessHacker/anawait.c +++ b/ProcessHacker/anawait.c @@ -769,7 +769,7 @@ static VOID PhpInitializeServiceNumbers( if (NT_SUCCESS(status)) { - if (threadHandle = PhCreateThread(0, PhpWfsoThreadStart, eventHandle)) + if (NT_SUCCESS(PhCreateThreadEx(&threadHandle, PhpWfsoThreadStart, eventHandle))) { if (PhpWaitUntilThreadIsWaiting(threadHandle)) { @@ -790,7 +790,7 @@ static VOID PhpInitializeServiceNumbers( if (NT_SUCCESS(status)) { - if (threadHandle = PhCreateThread(0, PhpWfmoThreadStart, eventHandle)) + if (NT_SUCCESS(PhCreateThreadEx(&threadHandle, PhpWfmoThreadStart, eventHandle))) { if (PhpWaitUntilThreadIsWaiting(threadHandle)) { @@ -810,7 +810,7 @@ static VOID PhpInitializeServiceNumbers( if (NT_SUCCESS(status)) { - if (threadHandle = PhCreateThread(0, PhpRfThreadStart, pipeReadHandle)) + if (NT_SUCCESS(PhCreateThreadEx(&threadHandle, PhpRfThreadStart, pipeReadHandle))) { ULONG data = 0; IO_STATUS_BLOCK isb; diff --git a/ProcessHacker/dbgcon.c b/ProcessHacker/dbgcon.c index 523352124088..c1e742071539 100644 --- a/ProcessHacker/dbgcon.c +++ b/ProcessHacker/dbgcon.c @@ -94,7 +94,7 @@ VOID PhShowDebugConsole( _wfreopen(L"CONOUT$", L"w", stderr); _wfreopen(L"CONIN$", L"r", stdin); - DebugConsoleThreadHandle = PhCreateThread(0, PhpDebugConsoleThreadStart, NULL); + PhCreateThreadEx(&DebugConsoleThreadHandle, PhpDebugConsoleThreadStart, NULL); } else { @@ -623,7 +623,7 @@ static VOID PhpTestRwLock( for (i = 0; i < RW_PROCESSORS; i++) { - threadHandles[i] = PhCreateThread(0, PhpRwLockTestThreadStart, Context); + PhCreateThreadEx(&threadHandles[i], PhpRwLockTestThreadStart, Context); } PhWaitForBarrier(&RwStartBarrier, FALSE); diff --git a/ProcessHacker/findobj.c b/ProcessHacker/findobj.c index c64c8597a0e6..e47529edff1f 100644 --- a/ProcessHacker/findobj.c +++ b/ProcessHacker/findobj.c @@ -1353,10 +1353,12 @@ INT_PTR CALLBACK PhpFindObjectsDlgProc( // Start the search. PhReferenceObject(context); - context->SearchThreadHandle = PhCreateThread(0, PhpFindObjectsThreadStart, context); - if (!context->SearchThreadHandle) + if (!NT_SUCCESS(PhCreateThreadEx(&context->SearchThreadHandle, PhpFindObjectsThreadStart, context))) + { + PhDereferenceObject(context); break; + } PhSetDialogItemText(hwndDlg, IDOK, L"Cancel"); @@ -1654,9 +1656,9 @@ VOID PhShowFindObjectsDialog( { if (!PhFindObjectsThreadHandle) { - if (!(PhFindObjectsThreadHandle = PhCreateThread(0, PhpFindObjectsDialogThreadStart, NULL))) + if (!NT_SUCCESS(PhCreateThreadEx(&PhFindObjectsThreadHandle, PhpFindObjectsDialogThreadStart, NULL))) { - PhShowStatus(PhMainWndHandle, L"Unable to create the window.", 0, GetLastError()); + PhShowError(PhMainWndHandle, L"Unable to create the window."); return; } diff --git a/ProcessHacker/plugman.c b/ProcessHacker/plugman.c index 3e70de2cf9dc..f20752c6ef54 100644 --- a/ProcessHacker/plugman.c +++ b/ProcessHacker/plugman.c @@ -895,9 +895,9 @@ VOID PhShowPluginsDialog( { if (!PhPluginsThreadHandle) { - if (!(PhPluginsThreadHandle = PhCreateThread(0, PhpPluginsDialogThreadStart, NULL))) + if (!NT_SUCCESS(PhCreateThreadEx(&PhPluginsThreadHandle, PhpPluginsDialogThreadStart, NULL))) { - PhShowStatus(PhMainWndHandle, L"Unable to create the window.", 0, GetLastError()); + PhShowError(PhMainWndHandle, L"Unable to create the window."); return; } diff --git a/ProcessHacker/sysinfo.c b/ProcessHacker/sysinfo.c index 88b0f85414d5..4c1eb91f1a8a 100644 --- a/ProcessHacker/sysinfo.c +++ b/ProcessHacker/sysinfo.c @@ -85,11 +85,11 @@ VOID PhShowSystemInformationDialog( { InitialSectionName = SectionName; - if (!PhSipWindow) + if (!PhSipThread) { - if (!(PhSipThread = PhCreateThread(0, PhSipSysInfoThreadStart, NULL))) + if (!NT_SUCCESS(PhCreateThreadEx(&PhSipThread, PhSipSysInfoThreadStart, NULL))) { - PhShowStatus(PhMainWndHandle, L"Unable to create the system information window", 0, GetLastError()); + PhShowError(PhMainWndHandle, L"Unable to create the window."); return; } diff --git a/phlib/basesup.c b/phlib/basesup.c index 1f7ea06b9de9..37bf4d2bec9e 100644 --- a/phlib/basesup.c +++ b/phlib/basesup.c @@ -201,6 +201,7 @@ NTSTATUS PhpBaseThreadStart( result = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE); // Call the user-supplied function. + status = context.StartAddress(context.Parameter); // De-initialization code diff --git a/plugins/ExtendedTools/etwmon.c b/plugins/ExtendedTools/etwmon.c index 52257066c8fb..d0dd93a8dd38 100644 --- a/plugins/ExtendedTools/etwmon.c +++ b/plugins/ExtendedTools/etwmon.c @@ -71,7 +71,6 @@ static PEVENT_TRACE_PROPERTIES EtpTraceProperties; static BOOLEAN EtpEtwActive; static BOOLEAN EtpStartedSession; static BOOLEAN EtpEtwExiting; -static HANDLE EtpEtwMonitorThreadHandle; // ETW rundown layer @@ -79,7 +78,6 @@ static UNICODE_STRING EtpRundownLoggerName = RTL_CONSTANT_STRING(L"PhEtRundownLo static TRACEHANDLE EtpRundownSessionHandle; static PEVENT_TRACE_PROPERTIES EtpRundownTraceProperties; static BOOLEAN EtpRundownActive; -static HANDLE EtpRundownEtwMonitorThreadHandle; VOID EtEtwMonitorInitialization( VOID @@ -90,7 +88,9 @@ VOID EtEtwMonitorInitialization( EtStartEtwSession(); if (EtEtwEnabled) - EtpEtwMonitorThreadHandle = PhCreateThread(0, EtpEtwMonitorThreadStart, NULL); + { + PhCreateThread2(EtpEtwMonitorThreadStart, NULL); + } } } @@ -484,7 +484,7 @@ ULONG EtStartEtwRundown( } EtpRundownActive = TRUE; - EtpRundownEtwMonitorThreadHandle = PhCreateThread(0, EtpRundownEtwMonitorThreadStart, NULL); + PhCreateThread2(EtpRundownEtwMonitorThreadStart, NULL); return result; } @@ -571,12 +571,9 @@ NTSTATUS EtpRundownEtwMonitorThreadStart( { ProcessTrace(&traceHandle, 1, NULL, NULL); - if (traceHandle != 0) + if (traceHandle != INVALID_PROCESSTRACE_HANDLE) CloseTrace(traceHandle); } - NtClose(EtpRundownEtwMonitorThreadHandle); - EtpRundownEtwMonitorThreadHandle = NULL; - return STATUS_SUCCESS; } diff --git a/plugins/ExtendedTools/gpunodes.c b/plugins/ExtendedTools/gpunodes.c index 8e1cd20c54e3..f73e82db7ea7 100644 --- a/plugins/ExtendedTools/gpunodes.c +++ b/plugins/ExtendedTools/gpunodes.c @@ -97,9 +97,9 @@ VOID EtShowGpuNodesDialog( { if (!EtGpuNodesThreadHandle) { - if (!(EtGpuNodesThreadHandle = PhCreateThread(0, EtpGpuNodesDialogThreadStart, ParentWindowHandle))) + if (!NT_SUCCESS(PhCreateThreadEx(&EtGpuNodesThreadHandle, EtpGpuNodesDialogThreadStart, ParentWindowHandle))) { - PhShowStatus(PhMainWndHandle, L"Unable to create the window.", 0, GetLastError()); + PhShowError(PhMainWndHandle, L"Unable to create the window."); return; } diff --git a/plugins/OnlineChecks/virustotal.c b/plugins/OnlineChecks/virustotal.c index e10a45eeae30..2e3db21e5575 100644 --- a/plugins/OnlineChecks/virustotal.c +++ b/plugins/OnlineChecks/virustotal.c @@ -892,7 +892,8 @@ VOID InitializeVirusTotalProcessMonitor( ) { VirusTotalList = PhCreateList(100); - VirusTotalHandle = PhCreateThread(0, VirusTotalProcessApiThread, NULL); + + PhCreateThreadEx(&VirusTotalHandle, VirusTotalProcessApiThread, NULL); } VOID CleanupVirusTotalProcessMonitor( @@ -921,8 +922,6 @@ NTSTATUS QueryServiceFileName( ) { static PH_STRINGREF servicesKeyName = PH_STRINGREF_INIT(L"System\\CurrentControlSet\\Services\\"); - static PH_STRINGREF typeKeyName = PH_STRINGREF_INIT(L"Type"); - NTSTATUS status; HANDLE keyHandle; ULONG serviceType = 0; @@ -943,25 +942,8 @@ NTSTATUS QueryServiceFileName( ))) { PPH_STRING serviceImagePath; - PKEY_VALUE_PARTIAL_INFORMATION buffer; - - if (NT_SUCCESS(status = PhQueryValueKey( - keyHandle, - &typeKeyName, - KeyValuePartialInformation, - &buffer - ))) - { - if ( - buffer->Type == REG_DWORD && - buffer->DataLength == sizeof(ULONG) - ) - { - serviceType = *(PULONG)buffer->Data; - } - PhFree(buffer); - } + serviceType = PhQueryRegistryUlong(keyHandle, L"Type"); if (serviceImagePath = PhQueryRegistryString(keyHandle, L"ImagePath")) { diff --git a/plugins/WindowExplorer/wnddlg.c b/plugins/WindowExplorer/wnddlg.c index 281e248cb24e..1a9aef93cc49 100644 --- a/plugins/WindowExplorer/wnddlg.c +++ b/plugins/WindowExplorer/wnddlg.c @@ -112,10 +112,10 @@ VOID WeShowWindowsDialog( context = PhAllocateZero(sizeof(WINDOWS_CONTEXT)); memcpy(&context->Selector, Selector, sizeof(WE_WINDOW_SELECTOR)); - if (!(WepWindowsDialogThreadHandle = PhCreateThread(0, WepShowWindowsDialogThread, context))) + if (!NT_SUCCESS(PhCreateThreadEx(&WepWindowsDialogThreadHandle, WepShowWindowsDialogThread, context))) { PhFree(context); - PhShowStatus(NULL, L"Unable to create the window.", 0, GetLastError()); + PhShowError(PhMainWndHandle, L"Unable to create the window."); return; } From 4706e501aece0f48987454ca7b1eea61c34f52f1 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 28 Apr 2019 02:48:56 +0200 Subject: [PATCH 1846/2058] Fix runas desktop name error checking --- ProcessHacker/runas.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ProcessHacker/runas.c b/ProcessHacker/runas.c index 383c4de67acf..6566bdf011f3 100644 --- a/ProcessHacker/runas.c +++ b/ProcessHacker/runas.c @@ -857,7 +857,8 @@ VOID SetDefaultDesktopEntry( INT sessionCount; PPH_STRING desktopName; - desktopName = PhpGetCurrentDesktopInfo(); + if (!(desktopName = PhpGetCurrentDesktopInfo())) + return; if ((sessionCount = ComboBox_GetCount(ComboBoxHandle)) == CB_ERR) { From b9820500e43bc37d7bd2605a8ec6f447426f0ca3 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 28 Apr 2019 02:49:28 +0200 Subject: [PATCH 1847/2058] Update session shadow error message --- ProcessHacker/sessshad.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/ProcessHacker/sessshad.c b/ProcessHacker/sessshad.c index 3d4994b7b6e2..ec891b65c8e2 100644 --- a/ProcessHacker/sessshad.c +++ b/ProcessHacker/sessshad.c @@ -108,9 +108,13 @@ VOID PhShowSessionShadowDialog( _In_ ULONG SessionId ) { - if (SessionId == NtCurrentPeb()->SessionId) + ULONG sessionId = ULONG_MAX; + + PhGetProcessSessionId(NtCurrentProcess(), &sessionId); + + if (SessionId == sessionId) { - PhShowError(ParentWindowHandle, L"You cannot remote control the current session."); + PhShowError2(ParentWindowHandle, L"Unable to shadow session.", L"You cannot remote control the current session."); return; } From 4576f841cba275eaa93d0790e57a26ef194b315c Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 28 Apr 2019 03:00:56 +0200 Subject: [PATCH 1848/2058] Remove legacy PhCreateThread --- plugins/DotNetTools/asmpage.c | 3 ++- plugins/NetworkTools/update.c | 4 ++-- plugins/OnlineChecks/page3.c | 20 ++++++++++++++++---- plugins/Updater/updater.c | 4 ++-- 4 files changed, 22 insertions(+), 9 deletions(-) diff --git a/plugins/DotNetTools/asmpage.c b/plugins/DotNetTools/asmpage.c index d705dfb3e293..f85df0ffab07 100644 --- a/plugins/DotNetTools/asmpage.c +++ b/plugins/DotNetTools/asmpage.c @@ -1169,7 +1169,8 @@ ULONG UpdateDotNetTraceInfoWithTimeout( Context->TraceHandleActive = 0; Context->TraceHandle = 0; - threadHandle = PhCreateThread(0, UpdateDotNetTraceInfoThreadStart, Context); + if (!NT_SUCCESS(PhCreateThreadEx(&threadHandle, UpdateDotNetTraceInfoThreadStart, Context))) + return ERROR_INVALID_HANDLE; if (NtWaitForSingleObject(threadHandle, FALSE, Timeout) != STATUS_WAIT_0) { diff --git a/plugins/NetworkTools/update.c b/plugins/NetworkTools/update.c index ec57f34b2343..54e1955bf46c 100644 --- a/plugins/NetworkTools/update.c +++ b/plugins/NetworkTools/update.c @@ -675,9 +675,9 @@ VOID ShowGeoIPUpdateDialog( { if (!UpdateDialogThreadHandle) { - if (!(UpdateDialogThreadHandle = PhCreateThread(0, GeoIPUpdateDialogThread, NULL))) + if (!NT_SUCCESS(PhCreateThreadEx(&UpdateDialogThreadHandle, GeoIPUpdateDialogThread, NULL))) { - PhShowStatus(PhMainWndHandle, L"Unable to create the updater window.", 0, GetLastError()); + PhShowError(PhMainWndHandle, L"Unable to create the window."); return; } diff --git a/plugins/OnlineChecks/page3.c b/plugins/OnlineChecks/page3.c index df23e83e9b2a..c035932d4c3e 100644 --- a/plugins/OnlineChecks/page3.c +++ b/plugins/OnlineChecks/page3.c @@ -43,7 +43,11 @@ HRESULT CALLBACK TaskDialogProgressCallbackProc( ITaskbarList3_SetProgressState(context->TaskbarListClass, PhMainWndHandle, TBPF_INDETERMINATE); PhReferenceObject(context); - context->UploadThreadHandle = PhCreateThread(0, UploadFileThreadStart, context); + + if (!NT_SUCCESS(PhCreateThreadEx(&context->UploadThreadHandle, UploadFileThreadStart, context))) + { + PhDereferenceObject(context); + } } break; case TDN_BUTTON_CLICKED: @@ -81,7 +85,11 @@ HRESULT CALLBACK TaskDialogReScanProgressCallbackProc( SendMessage(hwndDlg, TDM_SET_PROGRESS_BAR_MARQUEE, TRUE, 1); PhReferenceObject(context); - context->UploadThreadHandle = PhCreateThread(0, UploadRecheckThreadStart, context); + + if (!NT_SUCCESS(PhCreateThreadEx(&context->UploadThreadHandle, UploadRecheckThreadStart, context))) + { + PhDereferenceObject(context); + } } break; case TDN_BUTTON_CLICKED: @@ -119,7 +127,11 @@ HRESULT CALLBACK TaskDialogViewReportProgressCallbackProc( SendMessage(hwndDlg, TDM_SET_PROGRESS_BAR_MARQUEE, TRUE, 1); PhReferenceObject(context); - context->UploadThreadHandle = PhCreateThread(0, ViewReportThreadStart, context); + + if (!NT_SUCCESS(PhCreateThreadEx(&context->UploadThreadHandle, ViewReportThreadStart, context))) + { + PhDereferenceObject(context); + } } break; case TDN_BUTTON_CLICKED: @@ -204,4 +216,4 @@ VOID ShowVirusTotalViewReportProgressDialog( config.pfCallback = TaskDialogViewReportProgressCallbackProc; SendMessage(Context->DialogHandle, TDM_NAVIGATE_PAGE, 0, (LPARAM)&config); -} \ No newline at end of file +} diff --git a/plugins/Updater/updater.c b/plugins/Updater/updater.c index df6854714703..87a2e01c25d0 100644 --- a/plugins/Updater/updater.c +++ b/plugins/Updater/updater.c @@ -945,9 +945,9 @@ VOID ShowUpdateDialog( { if (!UpdateDialogThreadHandle) { - if (!(UpdateDialogThreadHandle = PhCreateThread(0, ShowUpdateDialogThread, Context))) + if (!NT_SUCCESS(PhCreateThreadEx(&UpdateDialogThreadHandle, ShowUpdateDialogThread, Context))) { - PhShowStatus(PhMainWndHandle, L"Unable to create the updater window.", 0, GetLastError()); + PhShowError(PhMainWndHandle, L"Unable to create the window."); return; } From d55a58022880e23f5f361e721f42e1c84b21cab0 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 28 Apr 2019 03:04:29 +0200 Subject: [PATCH 1849/2058] Remove ntdll import --- phlib/basesup.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/phlib/basesup.c b/phlib/basesup.c index 37bf4d2bec9e..142d0a657d3b 100644 --- a/phlib/basesup.c +++ b/phlib/basesup.c @@ -255,7 +255,8 @@ HANDLE PhCreateThread( // NOTE: PhCreateThread previously used CreateThread with callers using GetLastError() // for checking errors. We need to preserve this behavior for compatibility -dmex // TODO: Migrate code over to PhCreateThreadEx and remove this function. - RtlSetLastWin32ErrorAndNtStatusFromNtStatus(status); + //RtlSetLastWin32ErrorAndNtStatusFromNtStatus(status); + SetLastError(RtlNtStatusToDosError(status)); if (NT_SUCCESS(status)) { From 0cab4d91d68af7e4bcca10f46b494fed5d32133b Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 28 Apr 2019 03:08:57 +0200 Subject: [PATCH 1850/2058] Remove PEB SessionId dependency --- phlib/util.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/phlib/util.c b/phlib/util.c index af289bc041e6..64f6319e97cd 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -2814,7 +2814,11 @@ NTSTATUS PhCreateProcessAsUser( if (Flags & PH_CREATE_PROCESS_SET_SESSION_ID) { - if (Information->SessionId != NtCurrentPeb()->SessionId) + ULONG sessionId = ULONG_MAX; + + PhGetProcessSessionId(NtCurrentProcess(), &sessionId); + + if (Information->SessionId != sessionId) useWithLogon = FALSE; } From 4cd865a56e4c3bc362559cb83d8cd7f5cc736684 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 28 Apr 2019 03:09:02 +0200 Subject: [PATCH 1851/2058] Add PhLCIDToLocaleName --- phlib/util.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/phlib/util.c b/phlib/util.c index 64f6319e97cd..7da89583b6b4 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -261,6 +261,34 @@ PPH_STRING PhGetUserDefaultLocaleName( return NULL; } +// rev from LCIDToLocaleName +PPH_STRING PhLCIDToLocaleName( + _In_ LCID lcid + ) +{ + UNICODE_STRING localeNameUs; + WCHAR localeName[LOCALE_NAME_MAX_LENGTH]; + + RtlInitEmptyUnicodeString(&localeNameUs, localeName, sizeof(localeName)); + + if (lcid) + { + if (NT_SUCCESS(RtlLcidToLocaleName(lcid, &localeNameUs, 0, FALSE))) + { + return PhCreateStringFromUnicodeString(&localeNameUs); + } + } + else // Return the current user locale when zero is specified. + { + if (NT_SUCCESS(RtlLcidToLocaleName(PhGetUserDefaultLCID(), &localeNameUs, 0, FALSE))) + { + return PhCreateStringFromUnicodeString(&localeNameUs); + } + } + + return NULL; +} + /** * Gets a string stored in a DLL's message table. * From 2febbcad6e951748ab51eded0cbe817acb34cb1b Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 28 Apr 2019 03:56:15 +0200 Subject: [PATCH 1852/2058] Update ntexapi.h --- phnt/include/ntexapi.h | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/phnt/include/ntexapi.h b/phnt/include/ntexapi.h index a147bd6e1895..01f918d44935 100644 --- a/phnt/include/ntexapi.h +++ b/phnt/include/ntexapi.h @@ -1301,7 +1301,7 @@ typedef enum _SYSTEM_INFORMATION_CLASS SystemComPlusPackage, // q; s SystemNumaAvailableMemory, // 60 SystemProcessorPowerInformation, // q: SYSTEM_PROCESSOR_POWER_INFORMATION - SystemEmulationBasicInformation, // q + SystemEmulationBasicInformation, SystemEmulationProcessorInformation, SystemExtendedHandleInformation, // q: SYSTEM_HANDLE_INFORMATION_EX SystemLostDelayedWriteInformation, // q: ULONG @@ -1340,7 +1340,7 @@ typedef enum _SYSTEM_INFORMATION_CLASS SystemSystemPartitionInformation, // q: SYSTEM_SYSTEM_PARTITION_INFORMATION SystemSystemDiskInformation, // q: SYSTEM_SYSTEM_DISK_INFORMATION SystemProcessorPerformanceDistribution, // q: SYSTEM_PROCESSOR_PERFORMANCE_DISTRIBUTION // 100 - SystemNumaProximityNodeInformation, // q + SystemNumaProximityNodeInformation, SystemDynamicTimeZoneInformation, // q; s (requires SeTimeZonePrivilege) SystemCodeIntegrityInformation, // q: SYSTEM_CODEINTEGRITY_INFORMATION // SeCodeIntegrityQueryInformation SystemProcessorMicrocodeUpdateInformation, // s @@ -1360,7 +1360,7 @@ typedef enum _SYSTEM_INFORMATION_CLASS SystemVerifierCountersInformation, // q: SYSTEM_VERIFIER_COUNTERS_INFORMATION SystemPagedPoolInformationEx, // q: SYSTEM_FILECACHE_INFORMATION; s (requires SeIncreaseQuotaPrivilege) (info for WorkingSetTypePagedPool) SystemSystemPtesInformationEx, // q: SYSTEM_FILECACHE_INFORMATION; s (requires SeIncreaseQuotaPrivilege) (info for WorkingSetTypeSystemPtes) // 120 - SystemNodeDistanceInformation, // q + SystemNodeDistanceInformation, SystemAcpiAuditInformation, // q: SYSTEM_ACPI_AUDIT_INFORMATION // HaliQuerySystemInformation -> HalpAuditQueryResults, info class 26 SystemBasicPerformanceInformation, // q: SYSTEM_BASIC_PERFORMANCE_INFORMATION // name:wow64:whNtQuerySystemInformation_SystemBasicPerformanceInformation SystemQueryPerformanceCounterInformation, // q: SYSTEM_QUERY_PERFORMANCE_COUNTER_INFORMATION // since WIN7 SP1 @@ -1390,7 +1390,7 @@ typedef enum _SYSTEM_INFORMATION_CLASS SystemFullProcessInformation, // q: SYSTEM_PROCESS_INFORMATION with SYSTEM_PROCESS_INFORMATION_EXTENSION (requires admin) SystemKernelDebuggerInformationEx, // q: SYSTEM_KERNEL_DEBUGGER_INFORMATION_EX SystemBootMetadataInformation, // 150 - SystemSoftRebootInformation, + SystemSoftRebootInformation, // q: ULONG SystemElamCertificateInformation, // s: SYSTEM_ELAM_CERTIFICATE_INFORMATION SystemOfflineDumpConfigInformation, SystemProcessorFeaturesInformation, // q: SYSTEM_PROCESSOR_FEATURES_INFORMATION @@ -1402,7 +1402,7 @@ typedef enum _SYSTEM_INFORMATION_CLASS SystemProcessorCycleStatsInformation, // q: SYSTEM_PROCESSOR_CYCLE_STATS_INFORMATION // 160 SystemVmGenerationCountInformation, SystemTrustedPlatformModuleInformation, // q: SYSTEM_TPM_INFORMATION - SystemKernelDebuggerFlags, + SystemKernelDebuggerFlags, // SYSTEM_KERNEL_DEBUGGER_FLAGS SystemCodeIntegrityPolicyInformation, // q: SYSTEM_CODEINTEGRITYPOLICY_INFORMATION SystemIsolatedUserModeInformation, // q: SYSTEM_ISOLATED_USER_MODE_INFORMATION SystemHardwareSecurityTestInterfaceResultsInformation, @@ -1425,28 +1425,28 @@ typedef enum _SYSTEM_INFORMATION_CLASS SystemCodeIntegrityCertificateInformation, // q: SYSTEM_CODEINTEGRITY_CERTIFICATE_INFORMATION SystemPhysicalMemoryInformation, // q: SYSTEM_PHYSICAL_MEMORY_INFORMATION // since REDSTONE2 SystemControlFlowTransition, - SystemKernelDebuggingAllowed, + SystemKernelDebuggingAllowed, // s: ULONG SystemActivityModerationExeState, // SYSTEM_ACTIVITY_MODERATION_EXE_STATE SystemActivityModerationUserSettings, // SYSTEM_ACTIVITY_MODERATION_USER_SETTINGS SystemCodeIntegrityPoliciesFullInformation, SystemCodeIntegrityUnlockInformation, // SYSTEM_CODEINTEGRITY_UNLOCK_INFORMATION // 190 SystemIntegrityQuotaInformation, SystemFlushInformation, // q: SYSTEM_FLUSH_INFORMATION - SystemProcessorIdleMaskInformation, // since REDSTONE3 + SystemProcessorIdleMaskInformation, // q: ULONG_PTR // since REDSTONE3 SystemSecureDumpEncryptionInformation, SystemWriteConstraintInformation, // SYSTEM_WRITE_CONSTRAINT_INFORMATION SystemKernelVaShadowInformation, // SYSTEM_KERNEL_VA_SHADOW_INFORMATION SystemHypervisorSharedPageInformation, // SYSTEM_HYPERVISOR_SHARED_PAGE_INFORMATION // since REDSTONE4 SystemFirmwareBootPerformanceInformation, SystemCodeIntegrityVerificationInformation, // SYSTEM_CODEINTEGRITYVERIFICATION_INFORMATION - SystemFirmwarePartitionInformation, // 200 + SystemFirmwarePartitionInformation, // SYSTEM_FIRMWARE_PARTITION_INFORMATION // 200 SystemSpeculationControlInformation, // SYSTEM_SPECULATION_CONTROL_INFORMATION // (CVE-2017-5715) REDSTONE3 and above. SystemDmaGuardPolicyInformation, // SYSTEM_DMA_GUARD_POLICY_INFORMATION SystemEnclaveLaunchControlInformation, // SYSTEM_ENCLAVE_LAUNCH_CONTROL_INFORMATION SystemWorkloadAllowedCpuSetsInformation, // SYSTEM_WORKLOAD_ALLOWED_CPU_SET_INFORMATION // since REDSTONE5 SystemCodeIntegrityUnlockModeInformation, SystemLeapSecondInformation, // SYSTEM_LEAP_SECOND_INFORMATION - SystemFlags2Information, + SystemFlags2Information, // q: SYSTEM_FLAGS_INFORMATION SystemSecurityModelInformation, // SYSTEM_SECURITY_MODEL_INFORMATION // since 19H1 SystemCodeIntegritySyntheticCacheInformation, MaxSystemInfoClass @@ -3061,6 +3061,12 @@ typedef struct _SYSTEM_VSM_PROTECTION_INFORMATION BOOLEAN HardwareMbecAvailable; // REDSTONE4 (CVE-2018-3639) } SYSTEM_VSM_PROTECTION_INFORMATION, *PSYSTEM_VSM_PROTECTION_INFORMATION; +// private +typedef struct _SYSTEM_KERNEL_DEBUGGER_FLAGS +{ + UCHAR KernelDebuggerIgnoreUmExceptions; +} SYSTEM_KERNEL_DEBUGGER_FLAGS, *PSYSTEM_KERNEL_DEBUGGER_FLAGS; + // private typedef struct _SYSTEM_CODEINTEGRITYPOLICY_INFORMATION { @@ -3293,6 +3299,12 @@ typedef struct _SYSTEM_HYPERVISOR_SHARED_PAGE_INFORMATION PVOID HypervisorSharedUserVa; } SYSTEM_HYPERVISOR_SHARED_PAGE_INFORMATION, *PSYSTEM_HYPERVISOR_SHARED_PAGE_INFORMATION; +// private +typedef struct _SYSTEM_FIRMWARE_PARTITION_INFORMATION +{ + UNICODE_STRING FirmwarePartition; +} SYSTEM_FIRMWARE_PARTITION_INFORMATION, *PSYSTEM_FIRMWARE_PARTITION_INFORMATION; + // private typedef struct _SYSTEM_SPECULATION_CONTROL_INFORMATION { From 391cba60117273f2750c3df85a70511dc70a2a0c Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 28 Apr 2019 04:06:19 +0200 Subject: [PATCH 1853/2058] Update ntexapi.h --- phnt/include/ntexapi.h | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/phnt/include/ntexapi.h b/phnt/include/ntexapi.h index 01f918d44935..884c790f5d0e 100644 --- a/phnt/include/ntexapi.h +++ b/phnt/include/ntexapi.h @@ -1348,7 +1348,7 @@ typedef enum _SYSTEM_INFORMATION_CLASS SystemVirtualAddressInformation, // q: SYSTEM_VA_LIST_INFORMATION[]; s: SYSTEM_VA_LIST_INFORMATION[] (requires SeIncreaseQuotaPrivilege) // MmQuerySystemVaInformation SystemLogicalProcessorAndGroupInformation, // q: SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX // since WIN7 // KeQueryLogicalProcessorRelationship SystemProcessorCycleTimeInformation, // q: SYSTEM_PROCESSOR_CYCLE_TIME_INFORMATION[] - SystemStoreInformation, // q; s // SmQueryStoreInformation + SystemStoreInformation, // q; s: SYSTEM_STORE_INFORMATION // SmQueryStoreInformation SystemRegistryAppendString, // s: SYSTEM_REGISTRY_APPEND_STRING_PARAMETERS // 110 SystemAitSamplingValue, // s: ULONG (requires SeProfileSingleProcessPrivilege) SystemVhdBootInformation, // q: SYSTEM_VHD_BOOT_INFORMATION @@ -2495,6 +2495,35 @@ typedef struct _SYSTEM_VA_LIST_INFORMATION SIZE_T AllocationFailures; } SYSTEM_VA_LIST_INFORMATION, *PSYSTEM_VA_LIST_INFORMATION; +// rev +typedef enum _SYSTEM_STORE_INFORMATION_CLASS +{ + SystemStoreCompressionInformation = 23 // q: SYSTEM_STORE_COMPRESSION_INFORMATION +} SYSTEM_STORE_INFORMATION_CLASS; + +// rev +#define SYSTEM_STORE_INFORMATION_VERSION 1 + +// rev +typedef struct _SYSTEM_STORE_INFORMATION +{ + _In_ ULONG Version; + _In_ SYSTEM_STORE_INFORMATION_CLASS StoreInformationClass; + _Inout_ PVOID Data; + _Inout_ ULONG Length; +} SYSTEM_STORE_INFORMATION, *PSYSTEM_STORE_INFORMATION; + +// rev +typedef struct _SYSTEM_STORE_COMPRESSION_INFORMATION +{ + ULONG Version; + ULONG CompressionPid; + ULONGLONG CompressionWorkingSetSize; + ULONGLONG CompressSize; + ULONGLONG CompressedSize; + ULONGLONG NonCompressedSize; +} SYSTEM_STORE_COMPRESSION_INFORMATION, *PSYSTEM_STORE_COMPRESSION_INFORMATION; + // private typedef struct _SYSTEM_REGISTRY_APPEND_STRING_PARAMETERS { From c4f28e1fdc2c88aade2e4e5b9882d98c3e0cf368 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 28 Apr 2019 04:08:51 +0200 Subject: [PATCH 1854/2058] Update ntexapi.h --- phnt/include/ntexapi.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/phnt/include/ntexapi.h b/phnt/include/ntexapi.h index 884c790f5d0e..c68e710cbcbf 100644 --- a/phnt/include/ntexapi.h +++ b/phnt/include/ntexapi.h @@ -2513,6 +2513,9 @@ typedef struct _SYSTEM_STORE_INFORMATION _Inout_ ULONG Length; } SYSTEM_STORE_INFORMATION, *PSYSTEM_STORE_INFORMATION; +// rev +#define SYSTEM_STORE_COMPRESSION_INFORMATION_VERSION 3 + // rev typedef struct _SYSTEM_STORE_COMPRESSION_INFORMATION { From 36391ee40b19cc6200771e552dbdf4ab92b54e88 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 28 Apr 2019 04:42:46 +0200 Subject: [PATCH 1855/2058] HardwareDevices: Fix build --- plugins/HardwareDevices/ndis.c | 248 ++++++++++++++++----------------- 1 file changed, 124 insertions(+), 124 deletions(-) diff --git a/plugins/HardwareDevices/ndis.c b/plugins/HardwareDevices/ndis.c index 6ec421783dbd..4ed0e0f235f3 100644 --- a/plugins/HardwareDevices/ndis.c +++ b/plugins/HardwareDevices/ndis.c @@ -527,127 +527,127 @@ PWSTR MediumTypeToString( return L"N/A"; } -BOOLEAN NetworkAdapterQueryInternet( - _Inout_ PDV_NETADAPTER_SYSINFO_CONTEXT Context, - _In_ PPH_STRING IpAddress - ) -{ - // https://technet.microsoft.com/en-us/library/cc766017.aspx - BOOLEAN socketResult = FALSE; - DNS_STATUS dnsQueryStatus = DNS_ERROR_RCODE_NO_ERROR; - PDNS_RECORD dnsQueryRecords = NULL; - - __try - { - if ((dnsQueryStatus = DnsQuery( - L"www.msftncsi.com", - DNS_TYPE_A, - DNS_QUERY_NO_HOSTS_FILE | DNS_QUERY_BYPASS_CACHE, - NULL, - &dnsQueryRecords, - NULL - )) != DNS_ERROR_RCODE_NO_ERROR) - { - __leave; - } - - for (PDNS_RECORD i = dnsQueryRecords; i != NULL; i = i->pNext) - { - if (i->wType == DNS_TYPE_A) - { - SOCKET socketHandle = INVALID_SOCKET; - - if ((socketHandle = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, 0)) == INVALID_SOCKET) - continue; - - IN_ADDR sockAddr; - InetPton(AF_INET, IpAddress->Buffer, &sockAddr); - - SOCKADDR_IN localaddr = { 0 }; - localaddr.sin_family = AF_INET; - localaddr.sin_addr.s_addr = sockAddr.s_addr; - - if (bind(socketHandle, (PSOCKADDR)&localaddr, sizeof(localaddr)) == SOCKET_ERROR) - { - closesocket(socketHandle); - continue; - } - - SOCKADDR_IN remoteAddr; - remoteAddr.sin_family = AF_INET; - remoteAddr.sin_port = htons(80); - remoteAddr.sin_addr.s_addr = i->Data.A.IpAddress; - - if (WSAConnect(socketHandle, (PSOCKADDR)&remoteAddr, sizeof(remoteAddr), NULL, NULL, NULL, NULL) != SOCKET_ERROR) - { - socketResult = TRUE; - closesocket(socketHandle); - break; - } - - closesocket(socketHandle); - } - } - } - __finally - { - if (dnsQueryRecords) - { - DnsFree(dnsQueryRecords, DnsFreeRecordList); - } - } - - __try - { - if ((dnsQueryStatus = DnsQuery( - L"ipv6.msftncsi.com", - DNS_TYPE_AAAA, - DNS_QUERY_NO_HOSTS_FILE | DNS_QUERY_BYPASS_CACHE, // | DNS_QUERY_DUAL_ADDR - NULL, - &dnsQueryRecords, - NULL - )) != DNS_ERROR_RCODE_NO_ERROR) - { - __leave; - } - - for (PDNS_RECORD i = dnsQueryRecords; i != NULL; i = i->pNext) - { - if (i->wType == DNS_TYPE_AAAA) - { - SOCKET socketHandle = INVALID_SOCKET; - - if ((socketHandle = WSASocket(AF_INET6, SOCK_STREAM, IPPROTO_TCP, NULL, 0, 0)) == INVALID_SOCKET) - continue; - - IN6_ADDR sockAddr; - InetPton(AF_INET6, IpAddress->Buffer, &sockAddr); - - SOCKADDR_IN6 remoteAddr = { 0 }; - remoteAddr.sin6_family = AF_INET6; - remoteAddr.sin6_port = htons(80); - memcpy(&remoteAddr.sin6_addr.u.Byte, i->Data.AAAA.Ip6Address.IP6Byte, sizeof(i->Data.AAAA.Ip6Address.IP6Byte)); - - if (WSAConnect(socketHandle, (PSOCKADDR)&remoteAddr, sizeof(SOCKADDR_IN6), NULL, NULL, NULL, NULL) != SOCKET_ERROR) - { - socketResult = TRUE; - closesocket(socketHandle); - break; - } - - closesocket(socketHandle); - } - } - } - __finally - { - if (dnsQueryRecords) - { - DnsFree(dnsQueryRecords, DnsFreeRecordList); - } - } - - WSACleanup(); - - return socketResult; -} +//BOOLEAN NetworkAdapterQueryInternet( +// _Inout_ PDV_NETADAPTER_SYSINFO_CONTEXT Context, +// _In_ PPH_STRING IpAddress +// ) +//{ +// // https://technet.microsoft.com/en-us/library/cc766017.aspx +// BOOLEAN socketResult = FALSE; +// DNS_STATUS dnsQueryStatus = DNS_ERROR_RCODE_NO_ERROR; +// PDNS_RECORD dnsQueryRecords = NULL; +// +// __try +// { +// if ((dnsQueryStatus = DnsQuery( +// L"www.msftncsi.com", +// DNS_TYPE_A, +// DNS_QUERY_NO_HOSTS_FILE | DNS_QUERY_BYPASS_CACHE, +// NULL, +// &dnsQueryRecords, +// NULL +// )) != DNS_ERROR_RCODE_NO_ERROR) +// { +// __leave; +// } +// +// for (PDNS_RECORD i = dnsQueryRecords; i != NULL; i = i->pNext) +// { +// if (i->wType == DNS_TYPE_A) +// { +// SOCKET socketHandle = INVALID_SOCKET; +// +// if ((socketHandle = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, 0)) == INVALID_SOCKET) +// continue; +// +// IN_ADDR sockAddr; +// InetPton(AF_INET, IpAddress->Buffer, &sockAddr); +// +// SOCKADDR_IN localaddr = { 0 }; +// localaddr.sin_family = AF_INET; +// localaddr.sin_addr.s_addr = sockAddr.s_addr; +// +// if (bind(socketHandle, (PSOCKADDR)&localaddr, sizeof(localaddr)) == SOCKET_ERROR) +// { +// closesocket(socketHandle); +// continue; +// } +// +// SOCKADDR_IN remoteAddr; +// remoteAddr.sin_family = AF_INET; +// remoteAddr.sin_port = htons(80); +// remoteAddr.sin_addr.s_addr = i->Data.A.IpAddress; +// +// if (WSAConnect(socketHandle, (PSOCKADDR)&remoteAddr, sizeof(remoteAddr), NULL, NULL, NULL, NULL) != SOCKET_ERROR) +// { +// socketResult = TRUE; +// closesocket(socketHandle); +// break; +// } +// +// closesocket(socketHandle); +// } +// } +// } +// __finally +// { +// if (dnsQueryRecords) +// { +// DnsFree(dnsQueryRecords, DnsFreeRecordList); +// } +// } +// +// __try +// { +// if ((dnsQueryStatus = DnsQuery( +// L"ipv6.msftncsi.com", +// DNS_TYPE_AAAA, +// DNS_QUERY_NO_HOSTS_FILE | DNS_QUERY_BYPASS_CACHE, // | DNS_QUERY_DUAL_ADDR +// NULL, +// &dnsQueryRecords, +// NULL +// )) != DNS_ERROR_RCODE_NO_ERROR) +// { +// __leave; +// } +// +// for (PDNS_RECORD i = dnsQueryRecords; i != NULL; i = i->pNext) +// { +// if (i->wType == DNS_TYPE_AAAA) +// { +// SOCKET socketHandle = INVALID_SOCKET; +// +// if ((socketHandle = WSASocket(AF_INET6, SOCK_STREAM, IPPROTO_TCP, NULL, 0, 0)) == INVALID_SOCKET) +// continue; +// +// IN6_ADDR sockAddr; +// InetPton(AF_INET6, IpAddress->Buffer, &sockAddr); +// +// SOCKADDR_IN6 remoteAddr = { 0 }; +// remoteAddr.sin6_family = AF_INET6; +// remoteAddr.sin6_port = htons(80); +// memcpy(&remoteAddr.sin6_addr.u.Byte, i->Data.AAAA.Ip6Address.IP6Byte, sizeof(i->Data.AAAA.Ip6Address.IP6Byte)); +// +// if (WSAConnect(socketHandle, (PSOCKADDR)&remoteAddr, sizeof(SOCKADDR_IN6), NULL, NULL, NULL, NULL) != SOCKET_ERROR) +// { +// socketResult = TRUE; +// closesocket(socketHandle); +// break; +// } +// +// closesocket(socketHandle); +// } +// } +// } +// __finally +// { +// if (dnsQueryRecords) +// { +// DnsFree(dnsQueryRecords, DnsFreeRecordList); +// } +// } +// +// WSACleanup(); +// +// return socketResult; +//} From 26dce5089c2f4c131aecd96d14fbaf841d1b7e26 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 28 Apr 2019 04:44:24 +0200 Subject: [PATCH 1856/2058] Update d3dkmt.h --- plugins/ExtendedTools/d3dkmt.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/ExtendedTools/d3dkmt.h b/plugins/ExtendedTools/d3dkmt.h index e5731477d26e..cbf352d38dcd 100644 --- a/plugins/ExtendedTools/d3dkmt.h +++ b/plugins/ExtendedTools/d3dkmt.h @@ -973,7 +973,7 @@ typedef struct _D3DKMT_QUERYADAPTERINFO { _In_ D3DKMT_HANDLE AdapterHandle; _In_ KMTQUERYADAPTERINFOTYPE Type; - _Out_ PVOID PrivateDriverData; + _Inout_bytecount_(PrivateDriverDataSize) PVOID PrivateDriverData; _Out_ UINT32 PrivateDriverDataSize; } D3DKMT_QUERYADAPTERINFO; From 95a390527339c33664352a0589e0698f16ae6376 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 28 Apr 2019 05:33:30 +0200 Subject: [PATCH 1857/2058] Update ntexapi.h --- phnt/include/ntexapi.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phnt/include/ntexapi.h b/phnt/include/ntexapi.h index c68e710cbcbf..fb6c9f5945b9 100644 --- a/phnt/include/ntexapi.h +++ b/phnt/include/ntexapi.h @@ -2498,7 +2498,7 @@ typedef struct _SYSTEM_VA_LIST_INFORMATION // rev typedef enum _SYSTEM_STORE_INFORMATION_CLASS { - SystemStoreCompressionInformation = 23 // q: SYSTEM_STORE_COMPRESSION_INFORMATION + SystemStoreCompressionInformation = 22 // q: SYSTEM_STORE_COMPRESSION_INFORMATION } SYSTEM_STORE_INFORMATION_CLASS; // rev From 259623b13fd87495bcc2d2560dcdddb3c8dbafbb Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 28 Apr 2019 05:41:51 +0200 Subject: [PATCH 1858/2058] WindowExplorer: Fix typo --- plugins/WindowExplorer/wnddlg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/WindowExplorer/wnddlg.c b/plugins/WindowExplorer/wnddlg.c index 1a9aef93cc49..799843620252 100644 --- a/plugins/WindowExplorer/wnddlg.c +++ b/plugins/WindowExplorer/wnddlg.c @@ -115,7 +115,7 @@ VOID WeShowWindowsDialog( if (!NT_SUCCESS(PhCreateThreadEx(&WepWindowsDialogThreadHandle, WepShowWindowsDialogThread, context))) { PhFree(context); - PhShowError(PhMainWndHandle, L"Unable to create the window."); + PhShowError(ParentWindowHandle, L"Unable to create the window."); return; } From 5d7f8ecf301b5aa37c9237efbd0e911ec1748b64 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 28 Apr 2019 13:35:37 +0200 Subject: [PATCH 1859/2058] Fix #414 --- plugins/ExtendedTools/main.c | 2 +- plugins/ToolStatus/graph.c | 4 ++-- plugins/ToolStatus/main.c | 2 +- plugins/ToolStatus/statusbar.c | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/plugins/ExtendedTools/main.c b/plugins/ExtendedTools/main.c index f59c9c0a3d67..f2a905e688db 100644 --- a/plugins/ExtendedTools/main.c +++ b/plugins/ExtendedTools/main.c @@ -157,7 +157,7 @@ VOID NTAPI ProcessesUpdatedCallback( _In_opt_ PVOID Context ) { - if (ProcessesUpdatedCount < 2) + if (ProcessesUpdatedCount <= 2) { ProcessesUpdatedCount++; return; diff --git a/plugins/ToolStatus/graph.c b/plugins/ToolStatus/graph.c index 3f63ed4ed3c0..31372a21ca52 100644 --- a/plugins/ToolStatus/graph.c +++ b/plugins/ToolStatus/graph.c @@ -670,7 +670,7 @@ TOOLSTATUS_GRAPH_MESSAGE_CALLBACK_DECLARE(PhysicalHistoryGraphMessageCallback) GraphState->Data1, (FLOAT)PhSystemBasicInformation.NumberOfPhysicalPages, drawInfo->LineDataCount - ); + ); GraphState->Valid = TRUE; } @@ -692,7 +692,7 @@ TOOLSTATUS_GRAPH_MESSAGE_CALLBACK_DECLARE(PhysicalHistoryGraphMessageCallback) L"Physical memory: %s\n%s", PhaFormatSize(UInt32x32To64(physicalUsage, PAGE_SIZE), -1)->Buffer, PH_AUTO_T(PH_STRING, PhGetStatisticsTimeString(NULL, getTooltipText->Index))->Buffer - )); + )); } getTooltipText->Text = PhGetStringRef(GraphState->TooltipText); diff --git a/plugins/ToolStatus/main.c b/plugins/ToolStatus/main.c index fac5856bda76..17fde410bc10 100644 --- a/plugins/ToolStatus/main.c +++ b/plugins/ToolStatus/main.c @@ -99,7 +99,7 @@ VOID NTAPI ProcessesUpdatedCallback( _In_opt_ PVOID Context ) { - if (ProcessesUpdatedCount < 2) + if (ProcessesUpdatedCount <= 2) { ProcessesUpdatedCount++; return; diff --git a/plugins/ToolStatus/statusbar.c b/plugins/ToolStatus/statusbar.c index 43c540d580e2..4c2c563a22fb 100644 --- a/plugins/ToolStatus/statusbar.c +++ b/plugins/ToolStatus/statusbar.c @@ -237,7 +237,7 @@ VOID StatusBarUpdate( ULONG widths[MAX_STATUSBAR_ITEMS]; WCHAR text[MAX_STATUSBAR_ITEMS][0x80]; - if (ProcessesUpdatedCount < 2) + if (ProcessesUpdatedCount <= 2) return; if (ResetMaxWidths) From 63a233924f6726a20253fba9f7c9aee7d1f0b334 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 29 Apr 2019 00:13:58 +0200 Subject: [PATCH 1860/2058] Revert bad9bca2 --- ProcessHacker/tokprp.c | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/ProcessHacker/tokprp.c b/ProcessHacker/tokprp.c index e9a5a6f83487..865ac13077c4 100644 --- a/ProcessHacker/tokprp.c +++ b/ProcessHacker/tokprp.c @@ -767,7 +767,7 @@ INT_PTR CALLBACK PhpTokenPageProc( if (NT_SUCCESS(tokenPageContext->OpenObject( &tokenHandle, TOKEN_QUERY, - tokenPageContext->ProcessId + tokenPageContext->Context // ProcessId ))) { PTOKEN_USER tokenUser; @@ -943,7 +943,7 @@ INT_PTR CALLBACK PhpTokenPageProc( status = tokenPageContext->OpenObject( &tokenHandle, TOKEN_ADJUST_PRIVILEGES, - tokenPageContext->ProcessId + tokenPageContext->Context // ProcessId ); if (NT_SUCCESS(status)) @@ -1091,7 +1091,7 @@ INT_PTR CALLBACK PhpTokenPageProc( status = tokenPageContext->OpenObject( &tokenHandle, TOKEN_ADJUST_GROUPS, - tokenPageContext->ProcessId + tokenPageContext->Context // ProcessId ); if (NT_SUCCESS(status)) @@ -1226,7 +1226,7 @@ INT_PTR CALLBACK PhpTokenPageProc( status = tokenPageContext->OpenObject( &tokenHandle, TOKEN_ADJUST_DEFAULT, - tokenPageContext->ProcessId + tokenPageContext->Context // ProcessId ); if (NT_SUCCESS(status)) @@ -1271,7 +1271,7 @@ INT_PTR CALLBACK PhpTokenPageProc( L"TokenDefault", tokenPageContext->OpenObject, NULL, - tokenPageContext->ProcessId + tokenPageContext->Context // ProcessId ); } break; @@ -1283,7 +1283,7 @@ INT_PTR CALLBACK PhpTokenPageProc( L"Token", tokenPageContext->OpenObject, NULL, - tokenPageContext->ProcessId + tokenPageContext->Context // ProcessId ); } break; @@ -1314,7 +1314,7 @@ INT_PTR CALLBACK PhpTokenPageProc( if (NT_SUCCESS(status = tokenPageContext->OpenObject( &tokenHandle, TOKEN_QUERY, - tokenPageContext->ProcessId + tokenPageContext->Context // ProcessId ))) { if (NT_SUCCESS(status = PhGetTokenIntegrityLevelRID( @@ -1385,7 +1385,7 @@ INT_PTR CALLBACK PhpTokenPageProc( if (NT_SUCCESS(status = tokenPageContext->OpenObject( &tokenHandle, TOKEN_QUERY | TOKEN_ADJUST_DEFAULT, - tokenPageContext->ProcessId + tokenPageContext->Context // ProcessId ))) { static SID_IDENTIFIER_AUTHORITY mandatoryLabelAuthority = SECURITY_MANDATORY_LABEL_AUTHORITY; @@ -1437,7 +1437,7 @@ INT_PTR CALLBACK PhpTokenPageProc( if (NT_SUCCESS(tokenPageContext->OpenObject( &tokenHandle, TOKEN_QUERY, - tokenPageContext->ProcessId + tokenPageContext->Context // ProcessId ))) { PhGetTokenIsAppContainer(tokenHandle, &tokenIsAppContainer); @@ -1723,7 +1723,7 @@ INT_PTR CALLBACK PhpTokenGeneralPageProc( if (NT_SUCCESS(tokenPageContext->OpenObject( &tokenHandle, TOKEN_QUERY, - tokenPageContext->ProcessId + tokenPageContext->Context // ProcessId ))) { PTOKEN_USER tokenUser; @@ -1789,7 +1789,7 @@ INT_PTR CALLBACK PhpTokenGeneralPageProc( if (NT_SUCCESS(tokenPageContext->OpenObject( &tokenHandle, TOKEN_QUERY_SOURCE, - tokenPageContext->ProcessId + tokenPageContext->Context // ProcessId ))) { TOKEN_SOURCE tokenSource; @@ -1847,7 +1847,7 @@ INT_PTR CALLBACK PhpTokenGeneralPageProc( if (NT_SUCCESS(status = tokenPageContext->OpenObject( &tokenHandle, TOKEN_QUERY, - tokenPageContext->ProcessId + tokenPageContext->Context // ProcessId ))) { PhShowTokenProperties(hwndDlg, PhpOpenLinkedToken, tokenPageContext->ProcessId, (PVOID)tokenHandle, L"Linked Token"); @@ -1966,7 +1966,7 @@ INT_PTR CALLBACK PhpTokenAdvancedPageProc( if (NT_SUCCESS(tokenPageContext->OpenObject( &tokenHandle, TOKEN_QUERY, - tokenPageContext->ProcessId + tokenPageContext->Context // ProcessId ))) { TOKEN_STATISTICS statistics; @@ -2451,7 +2451,7 @@ BOOLEAN PhpAddTokenCapabilities( { HANDLE processHandle; - if (NT_SUCCESS(PhOpenProcess(&processHandle, PROCESS_QUERY_LIMITED_INFORMATION, TokenPageContext->ProcessId))) + if (NT_SUCCESS(PhOpenProcess(&processHandle, PROCESS_QUERY_LIMITED_INFORMATION, TokenPageContext->Context))) { name = PhGetProcessPackageFullName(processHandle); PhpAddAttributeNode(&TokenPageContext->CapsTreeContext, node, PhFormatString(L"Package: %s", PhGetString(name))); @@ -2790,7 +2790,7 @@ BOOLEAN PhpAddTokenClaimAttributes( if (!NT_SUCCESS(TokenPageContext->OpenObject( &tokenHandle, TOKEN_QUERY, - TokenPageContext->ProcessId + TokenPageContext->Context // ProcessId ))) return FALSE; @@ -2963,7 +2963,7 @@ BOOLEAN PhpAddTokenAttributes( if (!NT_SUCCESS(TokenPageContext->OpenObject( &tokenHandle, TOKEN_QUERY, - TokenPageContext->ProcessId + TokenPageContext->Context // ProcessId ))) return FALSE; @@ -3331,7 +3331,7 @@ INT_PTR CALLBACK PhpTokenContainerPageProc( if (NT_SUCCESS(tokenPageContext->OpenObject( &tokenHandle, TOKEN_QUERY, - tokenPageContext->ProcessId + tokenPageContext->Context // ProcessId ))) { PTOKEN_APPCONTAINER_INFORMATION appContainerInfo; @@ -3444,7 +3444,7 @@ INT_PTR CALLBACK PhpTokenContainerPageProc( if (NT_SUCCESS(PhOpenProcess( &processHandle, PROCESS_QUERY_LIMITED_INFORMATION, - tokenPageContext->ProcessId + tokenPageContext->Context // ProcessId ))) { PPH_STRING packageFullName; @@ -3469,7 +3469,7 @@ INT_PTR CALLBACK PhpTokenContainerPageProc( if (NT_SUCCESS(tokenPageContext->OpenObject( &tokenHandle, TOKEN_QUERY | TOKEN_IMPERSONATE | TOKEN_DUPLICATE, - tokenPageContext->ProcessId + tokenPageContext->Context // ProcessId ))) { PTOKEN_APPCONTAINER_INFORMATION appContainerInfo; From 02ecad2f7f3ba2b20ce51931f5abe59c9a867b1f Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 29 Apr 2019 00:14:45 +0200 Subject: [PATCH 1861/2058] Fix SAL annotation --- phlib/emenu.c | 2 +- phlib/include/emenu.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/phlib/emenu.c b/phlib/emenu.c index 46f5ff42468c..49906170b2c6 100644 --- a/phlib/emenu.c +++ b/phlib/emenu.c @@ -60,7 +60,7 @@ static const PH_FLAG_MAPPING EMenuStateMappings[] = PPH_EMENU_ITEM PhCreateEMenuItem( _In_ ULONG Flags, _In_ ULONG Id, - _In_ PWSTR Text, + _In_opt_ PWSTR Text, _In_opt_ HBITMAP Bitmap, _In_opt_ PVOID Context ) diff --git a/phlib/include/emenu.h b/phlib/include/emenu.h index 4760b56ec7b5..bde90b75c9c6 100644 --- a/phlib/include/emenu.h +++ b/phlib/include/emenu.h @@ -48,7 +48,7 @@ PHLIBAPI PPH_EMENU_ITEM PhCreateEMenuItem( _In_ ULONG Flags, _In_ ULONG Id, - _In_ PWSTR Text, + _In_opt_ PWSTR Text, _In_opt_ HBITMAP Bitmap, _In_opt_ PVOID Context ); From b3c9bbedfad9150c98d4b531836b325a8d9309b5 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 29 Apr 2019 00:15:46 +0200 Subject: [PATCH 1862/2058] Add types --- phnt/include/ntlpcapi.h | 6 +++++- phnt/include/ntpfapi.h | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/phnt/include/ntlpcapi.h b/phnt/include/ntlpcapi.h index 3adcc7021f75..e17fe0ae3e78 100644 --- a/phnt/include/ntlpcapi.h +++ b/phnt/include/ntlpcapi.h @@ -486,7 +486,7 @@ typedef struct _ALPC_HANDLE_ATTR } ALPC_HANDLE_ATTR, *PALPC_HANDLE_ATTR; #define ALPC_SECFLG_CREATE_HANDLE 0x20000 // dbg - +#define ALPC_SECFLG_NOSECTIONHANDLE 0x40000 // private typedef struct _ALPC_SECURITY_ATTR { @@ -880,6 +880,10 @@ AlpcGetHeaderSize( _In_ ULONG Flags ); +#define ALPC_ATTRFLG_ALLOCATEDATTR 0x20000000 +#define ALPC_ATTRFLG_VALIDATTR 0x40000000 +#define ALPC_ATTRFLG_KEEPRUNNINGATTR 0x60000000 + NTSYSAPI NTSTATUS NTAPI diff --git a/phnt/include/ntpfapi.h b/phnt/include/ntpfapi.h index aa635bd09692..0f5c1321f898 100644 --- a/phnt/include/ntpfapi.h +++ b/phnt/include/ntpfapi.h @@ -140,7 +140,7 @@ typedef struct _PF_PRIVSOURCE_INFO ULONG Spare : 28; } PF_PRIVSOURCE_INFO, *PPF_PRIVSOURCE_INFO; -#define PF_PRIVSOURCE_QUERY_REQUEST_VERSION 3 +#define PF_PRIVSOURCE_QUERY_REQUEST_VERSION 8 typedef struct _PF_PRIVSOURCE_QUERY_REQUEST { From 4434d563be11d3b1c45c3f92fed43e2714a2b409 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 29 Apr 2019 00:17:23 +0200 Subject: [PATCH 1863/2058] Add missing dates --- phlib/secdata.c | 1 + 1 file changed, 1 insertion(+) diff --git a/phlib/secdata.c b/phlib/secdata.c index c5f109a0ef0d..439ffbdac802 100644 --- a/phlib/secdata.c +++ b/phlib/secdata.c @@ -3,6 +3,7 @@ * object security data * * Copyright (C) 2010-2016 wj32 + * Copyright (C) 2017-2019 dmex * * This file is part of Process Hacker. * From fc0ff12f6b26cb012aa0d969be8c9eee9a48ef5a Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 1 May 2019 09:01:56 +0200 Subject: [PATCH 1864/2058] Update ntioapi.h --- phnt/include/ntioapi.h | 64 ++++++++++++++++++++++++++++++++---------- 1 file changed, 49 insertions(+), 15 deletions(-) diff --git a/phnt/include/ntioapi.h b/phnt/include/ntioapi.h index 3e0935650fec..bcc43a7b2688 100644 --- a/phnt/include/ntioapi.h +++ b/phnt/include/ntioapi.h @@ -253,22 +253,22 @@ typedef enum _FILE_INFORMATION_CLASS FileLinkInformationBypassAccessCheck, // (kernel-mode only); FILE_LINK_INFORMATION FileVolumeNameInformation, // FILE_VOLUME_NAME_INFORMATION FileIdInformation, // FILE_ID_INFORMATION - FileIdExtdDirectoryInformation, // FILE_ID_EXTD_DIR_INFORMATION + FileIdExtdDirectoryInformation, // FILE_ID_EXTD_DIR_INFORMATION // 60 FileReplaceCompletionInformation, // FILE_COMPLETION_INFORMATION // since WINBLUE FileHardLinkFullIdInformation, // FILE_LINK_ENTRY_FULL_ID_INFORMATION FileIdExtdBothDirectoryInformation, // FILE_ID_EXTD_BOTH_DIR_INFORMATION // since THRESHOLD FileDispositionInformationEx, // FILE_DISPOSITION_INFO_EX // since REDSTONE - FileRenameInformationEx, - FileRenameInformationExBypassAccessCheck, + FileRenameInformationEx, // FILE_RENAME_INFORMATION + FileRenameInformationExBypassAccessCheck, // FILE_RENAME_INFORMATION FileDesiredStorageClassInformation, // FILE_DESIRED_STORAGE_CLASS_INFORMATION // since REDSTONE2 FileStatInformation, // FILE_STAT_INFORMATION FileMemoryPartitionInformation, // FILE_MEMORY_PARTITION_INFORMATION // since REDSTONE3 - FileStatLxInformation, // FILE_STAT_LX_INFORMATION // since REDSTONE4 + FileStatLxInformation, // FILE_STAT_LX_INFORMATION // since REDSTONE4 // 70 FileCaseSensitiveInformation, // FILE_CASE_SENSITIVE_INFORMATION - FileLinkInformationEx, // since REDSTONE5 - FileLinkInformationExBypassAccessCheck, - FileStorageReserveIdInformation, - FileCaseSensitiveInformationForceAccessCheck, + FileLinkInformationEx, // FILE_LINK_INFORMATION // since REDSTONE5 + FileLinkInformationExBypassAccessCheck, // FILE_LINK_INFORMATION + FileStorageReserveIdInformation, // FILE_SET_STORAGE_RESERVE_ID_INFORMATION + FileCaseSensitiveInformationForceAccessCheck, // FILE_CASE_SENSITIVE_INFORMATION FileMaximumInformation } FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS; @@ -947,7 +947,7 @@ typedef enum _FSINFOCLASS FileFsFullSizeInformation, // FILE_FS_FULL_SIZE_INFORMATION FileFsObjectIdInformation, // FILE_FS_OBJECTID_INFORMATION FileFsDriverPathInformation, // FILE_FS_DRIVER_PATH_INFORMATION - FileFsVolumeFlagsInformation, // FILE_FS_VOLUME_FLAGS_INFORMATION + FileFsVolumeFlagsInformation, // FILE_FS_VOLUME_FLAGS_INFORMATION // 10 FileFsSectorSizeInformation, // FILE_FS_SECTOR_SIZE_INFORMATION // since WIN8 FileFsDataCopyInformation, // FILE_FS_DATA_COPY_INFORMATION FileFsMetadataSizeInformation, // FILE_FS_METADATA_SIZE_INFORMATION // since THRESHOLD @@ -957,12 +957,7 @@ typedef enum _FSINFOCLASS // NtQueryVolumeInformation/NtSetVolumeInformation types -typedef struct _FILE_FS_LABEL_INFORMATION -{ - ULONG VolumeLabelLength; - WCHAR VolumeLabel[1]; -} FILE_FS_LABEL_INFORMATION, *PFILE_FS_LABEL_INFORMATION; - +// private typedef struct _FILE_FS_VOLUME_INFORMATION { LARGE_INTEGER VolumeCreationTime; @@ -972,6 +967,14 @@ typedef struct _FILE_FS_VOLUME_INFORMATION WCHAR VolumeLabel[1]; } FILE_FS_VOLUME_INFORMATION, *PFILE_FS_VOLUME_INFORMATION; +// private +typedef struct _FILE_FS_LABEL_INFORMATION +{ + ULONG VolumeLabelLength; + WCHAR VolumeLabel[1]; +} FILE_FS_LABEL_INFORMATION, * PFILE_FS_LABEL_INFORMATION; + +// private typedef struct _FILE_FS_SIZE_INFORMATION { LARGE_INTEGER TotalAllocationUnits; @@ -991,6 +994,7 @@ typedef struct _FILE_FS_CONTROL_INFORMATION ULONG FileSystemControlFlags; } FILE_FS_CONTROL_INFORMATION, *PFILE_FS_CONTROL_INFORMATION; +// private typedef struct _FILE_FS_FULL_SIZE_INFORMATION { LARGE_INTEGER TotalAllocationUnits; @@ -1000,18 +1004,21 @@ typedef struct _FILE_FS_FULL_SIZE_INFORMATION ULONG BytesPerSector; } FILE_FS_FULL_SIZE_INFORMATION, *PFILE_FS_FULL_SIZE_INFORMATION; +// private typedef struct _FILE_FS_OBJECTID_INFORMATION { UCHAR ObjectId[16]; UCHAR ExtendedInfo[48]; } FILE_FS_OBJECTID_INFORMATION, *PFILE_FS_OBJECTID_INFORMATION; +// private typedef struct _FILE_FS_DEVICE_INFORMATION { DEVICE_TYPE DeviceType; ULONG Characteristics; } FILE_FS_DEVICE_INFORMATION, *PFILE_FS_DEVICE_INFORMATION; +// private typedef struct _FILE_FS_ATTRIBUTE_INFORMATION { ULONG FileSystemAttributes; @@ -1020,6 +1027,7 @@ typedef struct _FILE_FS_ATTRIBUTE_INFORMATION WCHAR FileSystemName[1]; } FILE_FS_ATTRIBUTE_INFORMATION, *PFILE_FS_ATTRIBUTE_INFORMATION; +// private typedef struct _FILE_FS_DRIVER_PATH_INFORMATION { BOOLEAN DriverInPath; @@ -1027,6 +1035,7 @@ typedef struct _FILE_FS_DRIVER_PATH_INFORMATION WCHAR DriverName[1]; } FILE_FS_DRIVER_PATH_INFORMATION, *PFILE_FS_DRIVER_PATH_INFORMATION; +// private typedef struct _FILE_FS_VOLUME_FLAGS_INFORMATION { ULONG Flags; @@ -1482,6 +1491,31 @@ NtNotifyChangeDirectoryFile( _In_ BOOLEAN WatchTree ); +// private +typedef enum _DIRECTORY_NOTIFY_INFORMATION_CLASS +{ + DirectoryNotifyInformation, // FILE_NOTIFY_INFORMATION + DirectoryNotifyExtendedInformation // FILE_NOTIFY_EXTENDED_INFORMATION +} DIRECTORY_NOTIFY_INFORMATION_CLASS, *PDIRECTORY_NOTIFY_INFORMATION_CLASS; + +#if (PHNT_VERSION >= PHNT_REDSTONE3) +NTSYSCALLAPI +NTSTATUS +NTAPI +NtNotifyChangeDirectoryFileEx( + _In_ HANDLE FileHandle, + _In_opt_ HANDLE Event, + _In_opt_ PIO_APC_ROUTINE ApcRoutine, + _In_opt_ PVOID ApcContext, + _Out_ PIO_STATUS_BLOCK IoStatusBlock, + _Out_writes_bytes_(Length) PVOID Buffer, + _In_ ULONG Length, + _In_ ULONG CompletionFilter, + _In_ BOOLEAN WatchTree, + _In_opt_ DIRECTORY_NOTIFY_INFORMATION_CLASS DirectoryNotifyInformationClass + ); +#endif + NTSYSCALLAPI NTSTATUS NTAPI From 046545844cf28c779575e478385c7119ef122ee2 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 1 May 2019 10:10:21 +0200 Subject: [PATCH 1865/2058] ExtendedTools: Fix Disk tab GDI issues (major performance/reliability improvement) --- plugins/ExtendedTools/exttools.h | 3 ++- plugins/ExtendedTools/procicon.c | 12 ++++++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/plugins/ExtendedTools/exttools.h b/plugins/ExtendedTools/exttools.h index 16ad31d5e604..9654f507d8be 100644 --- a/plugins/ExtendedTools/exttools.h +++ b/plugins/ExtendedTools/exttools.h @@ -78,6 +78,7 @@ typedef struct _ET_PROCESS_ICON { LONG RefCount; HICON Icon; + PPH_PROCESS_ITEM ProcessItem; } ET_PROCESS_ICON, *PET_PROCESS_ICON; // Disk item @@ -368,7 +369,7 @@ PPH_STRING EtFileObjectToFileName( // procicon PET_PROCESS_ICON EtProcIconCreateProcessIcon( - _In_ HICON Icon + _In_ PPH_PROCESS_ITEM ProcessItem ); VOID EtProcIconReferenceProcessIcon( diff --git a/plugins/ExtendedTools/procicon.c b/plugins/ExtendedTools/procicon.c index ee520007b270..e5c877eb1d54 100644 --- a/plugins/ExtendedTools/procicon.c +++ b/plugins/ExtendedTools/procicon.c @@ -3,6 +3,7 @@ * process icon duplication * * Copyright (C) 2011 wj32 + * Copyright (C) 2019 dmex * * This file is part of Process Hacker. * @@ -23,14 +24,16 @@ #include "exttools.h" PET_PROCESS_ICON EtProcIconCreateProcessIcon( - _In_ HICON Icon + _In_ PPH_PROCESS_ITEM ProcessItem ) { PET_PROCESS_ICON processIcon; processIcon = PhAllocate(sizeof(ET_PROCESS_ICON)); processIcon->RefCount = 1; - processIcon->Icon = CopyIcon(Icon); + processIcon->Icon = ProcessItem->SmallIcon; + + PhReferenceObject(ProcessItem); return processIcon; } @@ -48,7 +51,8 @@ VOID EtProcIconDereferenceProcessIcon( { if (_InterlockedDecrement(&ProcessIcon->RefCount) == 0) { - DestroyIcon(ProcessIcon->Icon); + PhDereferenceObject(ProcessIcon->ProcessItem); + PhFree(ProcessIcon); } } @@ -63,7 +67,7 @@ PET_PROCESS_ICON EtProcIconReferenceSmallProcessIcon( if (!smallProcessIcon && PhTestEvent(&Block->ProcessItem->Stage1Event) && Block->ProcessItem->SmallIcon) { - smallProcessIcon = EtProcIconCreateProcessIcon(Block->ProcessItem->SmallIcon); + smallProcessIcon = EtProcIconCreateProcessIcon(Block->ProcessItem); if (_InterlockedCompareExchangePointer( &Block->SmallProcessIcon, From 8fa0e662b21a7cb5678f6eff8479e5b7483e8b44 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 1 May 2019 22:08:21 +0200 Subject: [PATCH 1866/2058] ExtendedTools: Fix previous commit --- plugins/ExtendedTools/procicon.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/ExtendedTools/procicon.c b/plugins/ExtendedTools/procicon.c index e5c877eb1d54..75fe043ad269 100644 --- a/plugins/ExtendedTools/procicon.c +++ b/plugins/ExtendedTools/procicon.c @@ -33,7 +33,7 @@ PET_PROCESS_ICON EtProcIconCreateProcessIcon( processIcon->RefCount = 1; processIcon->Icon = ProcessItem->SmallIcon; - PhReferenceObject(ProcessItem); + PhSetReference(&processIcon->ProcessItem, ProcessItem); return processIcon; } From 6ad4b8c452c83b7ab22b8a99d8f309dd6741f61e Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 1 May 2019 22:11:18 +0200 Subject: [PATCH 1867/2058] Plugins: Update macro usage --- plugins/DotNetTools/asmpage.c | 2 +- plugins/ExtendedServices/main.c | 14 ++++----- plugins/ExtendedServices/trigger.c | 4 +-- plugins/ExtendedTools/disktab.c | 4 +-- plugins/ExtendedTools/etwmon.c | 18 +++++------ plugins/ExtendedTools/etwprprp.c | 36 +++++++++++----------- plugins/ExtendedTools/etwsys.c | 36 +++++++++++----------- plugins/ExtendedTools/gpunodes.c | 2 +- plugins/ExtendedTools/gpuprprp.c | 40 ++++++++++++------------ plugins/ExtendedTools/main.c | 4 +-- plugins/ExtendedTools/treeext.c | 28 ++++++++--------- plugins/HardwareDevices/diskdetails.c | 44 +++++++++++++-------------- plugins/HardwareDevices/diskgraph.c | 20 ++++++------ plugins/HardwareDevices/diskoptions.c | 8 ++--- plugins/HardwareDevices/netdetails.c | 22 +++++++------- plugins/HardwareDevices/netgraph.c | 24 +++++++-------- plugins/HardwareDevices/storage.c | 2 +- plugins/NetworkTools/tracetree.c | 2 +- plugins/NetworkTools/update.c | 6 ++-- plugins/OnlineChecks/main.c | 34 ++++++++++----------- plugins/ToolStatus/graph.c | 18 +++++------ plugins/ToolStatus/statusbar.c | 4 +-- plugins/UserNotes/main.c | 20 ++++++------ plugins/WindowExplorer/wnddlg.c | 4 +-- plugins/WindowExplorer/wndtree.c | 2 +- 25 files changed, 199 insertions(+), 199 deletions(-) diff --git a/plugins/DotNetTools/asmpage.c b/plugins/DotNetTools/asmpage.c index f85df0ffab07..136377228785 100644 --- a/plugins/DotNetTools/asmpage.c +++ b/plugins/DotNetTools/asmpage.c @@ -495,7 +495,7 @@ VOID DotNetAsmShowContextMenu( ContextMenuEvent->Location.y ); - if (selectedItem && selectedItem->Id != -1) + if (selectedItem && selectedItem->Id != ULONG_MAX) { BOOLEAN handled = FALSE; diff --git a/plugins/ExtendedServices/main.c b/plugins/ExtendedServices/main.c index 343d328d02db..f2e9bc39ab5c 100644 --- a/plugins/ExtendedServices/main.c +++ b/plugins/ExtendedServices/main.c @@ -185,11 +185,11 @@ VOID NTAPI ProcessMenuInitializingCallback( servicesMenuItem = serviceMenuItem; } - PhInsertEMenuItem(serviceMenuItem, PhPluginCreateEMenuItem(PluginInstance, 0, ID_SERVICE_GOTOSERVICE, L"&Go to service", serviceItem), -1); - PhInsertEMenuItem(serviceMenuItem, startMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, ID_SERVICE_START, L"Sta&rt", serviceItem), -1); - PhInsertEMenuItem(serviceMenuItem, continueMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, ID_SERVICE_CONTINUE, L"&Continue", serviceItem), -1); - PhInsertEMenuItem(serviceMenuItem, pauseMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, ID_SERVICE_PAUSE, L"&Pause", serviceItem), -1); - PhInsertEMenuItem(serviceMenuItem, stopMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, ID_SERVICE_STOP, L"St&op", serviceItem), -1); + PhInsertEMenuItem(serviceMenuItem, PhPluginCreateEMenuItem(PluginInstance, 0, ID_SERVICE_GOTOSERVICE, L"&Go to service", serviceItem), ULONG_MAX); + PhInsertEMenuItem(serviceMenuItem, startMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, ID_SERVICE_START, L"Sta&rt", serviceItem), ULONG_MAX); + PhInsertEMenuItem(serviceMenuItem, continueMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, ID_SERVICE_CONTINUE, L"&Continue", serviceItem), ULONG_MAX); + PhInsertEMenuItem(serviceMenuItem, pauseMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, ID_SERVICE_PAUSE, L"&Pause", serviceItem), ULONG_MAX); + PhInsertEMenuItem(serviceMenuItem, stopMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, ID_SERVICE_STOP, L"St&op", serviceItem), ULONG_MAX); // Massive copy and paste from mainwnd.c. // == START == @@ -247,7 +247,7 @@ VOID NTAPI ProcessMenuInitializingCallback( // == END == if (serviceList->Count != 1) - PhInsertEMenuItem(servicesMenuItem, serviceMenuItem, -1); + PhInsertEMenuItem(servicesMenuItem, serviceMenuItem, ULONG_MAX); } // Insert our Services menu after the I/O Priority menu. @@ -447,4 +447,4 @@ LOGICAL DllMain( } return TRUE; -} \ No newline at end of file +} diff --git a/plugins/ExtendedServices/trigger.c b/plugins/ExtendedServices/trigger.c index 0284f228d940..4d6a900029f7 100644 --- a/plugins/ExtendedServices/trigger.c +++ b/plugins/ExtendedServices/trigger.c @@ -932,7 +932,7 @@ VOID EsHandleEventServiceTrigger( { index = PhFindItemList(Context->InfoList, info); - if (index != -1) + if (index != ULONG_MAX) { Context->EditingInfo = EspCloneTriggerInfo(info); @@ -983,7 +983,7 @@ VOID EsHandleEventServiceTrigger( { index = PhFindItemList(Context->InfoList, info); - if (index != -1) + if (index != ULONG_MAX) { EspDestroyTriggerInfo(info); PhRemoveItemList(Context->InfoList, index); diff --git a/plugins/ExtendedTools/disktab.c b/plugins/ExtendedTools/disktab.c index b2ec7161685f..ff2c4b81748f 100644 --- a/plugins/ExtendedTools/disktab.c +++ b/plugins/ExtendedTools/disktab.c @@ -347,7 +347,7 @@ VOID EtRemoveDiskNode( PhRemoveEntryHashtable(DiskNodeHashtable, &DiskNode); - if ((index = PhFindItemList(DiskNodeList, DiskNode)) != -1) + if ((index = PhFindItemList(DiskNodeList, DiskNode)) != ULONG_MAX) PhRemoveItemList(DiskNodeList, index); if (DiskNode->ProcessNameText) PhDereferenceObject(DiskNode->ProcessNameText); @@ -613,7 +613,7 @@ BOOLEAN NTAPI EtpDiskTreeNewCallback( { getCellTooltip->Text = node->TooltipText->sr; getCellTooltip->Unfolding = FALSE; - getCellTooltip->MaximumWidth = -1; + getCellTooltip->MaximumWidth = ULONG_MAX; } else { diff --git a/plugins/ExtendedTools/etwmon.c b/plugins/ExtendedTools/etwmon.c index d0dd93a8dd38..8d26ee97149d 100644 --- a/plugins/ExtendedTools/etwmon.c +++ b/plugins/ExtendedTools/etwmon.c @@ -222,7 +222,7 @@ VOID NTAPI EtpEtwEventCallback( ET_ETW_DISK_EVENT diskEvent; memset(&diskEvent, 0, sizeof(ET_ETW_DISK_EVENT)); - diskEvent.Type = -1; + diskEvent.Type = ULONG_MAX; switch (EventRecord->EventHeader.EventDescriptor.Opcode) { @@ -236,7 +236,7 @@ VOID NTAPI EtpEtwEventCallback( break; } - if (diskEvent.Type != -1) + if (diskEvent.Type != ULONG_MAX) { DiskIo_TypeGroup1 *data = EventRecord->UserData; @@ -247,7 +247,7 @@ VOID NTAPI EtpEtwEventCallback( } else { - if (EventRecord->EventHeader.ProcessId != -1) + if (EventRecord->EventHeader.ProcessId != ULONG_MAX) { diskEvent.ClientId.UniqueProcess = UlongToHandle(EventRecord->EventHeader.ProcessId); diskEvent.ClientId.UniqueThread = UlongToHandle(EventRecord->EventHeader.ThreadId); @@ -270,7 +270,7 @@ VOID NTAPI EtpEtwEventCallback( ET_ETW_FILE_EVENT fileEvent; memset(&fileEvent, 0, sizeof(ET_ETW_FILE_EVENT)); - fileEvent.Type = -1; + fileEvent.Type = ULONG_MAX; switch (EventRecord->EventHeader.EventDescriptor.Opcode) { @@ -287,7 +287,7 @@ VOID NTAPI EtpEtwEventCallback( break; } - if (fileEvent.Type != -1) + if (fileEvent.Type != ULONG_MAX) { if (PhIsExecutingInWow64()) { @@ -317,7 +317,7 @@ VOID NTAPI EtpEtwEventCallback( ET_ETW_NETWORK_EVENT networkEvent; memset(&networkEvent, 0, sizeof(ET_ETW_NETWORK_EVENT)); - networkEvent.Type = -1; + networkEvent.Type = ULONG_MAX; switch (EventRecord->EventHeader.EventDescriptor.Opcode) { @@ -344,7 +344,7 @@ VOID NTAPI EtpEtwEventCallback( else networkEvent.ProtocolType |= PH_UDP_PROTOCOL_TYPE; - if (networkEvent.Type != -1) + if (networkEvent.Type != ULONG_MAX) { PH_IP_ENDPOINT source; PH_IP_ENDPOINT destination; @@ -518,7 +518,7 @@ VOID NTAPI EtpRundownEtwEventCallback( ET_ETW_FILE_EVENT fileEvent; memset(&fileEvent, 0, sizeof(ET_ETW_FILE_EVENT)); - fileEvent.Type = -1; + fileEvent.Type = ULONG_MAX; switch (EventRecord->EventHeader.EventDescriptor.Opcode) { @@ -529,7 +529,7 @@ VOID NTAPI EtpRundownEtwEventCallback( break; } - if (fileEvent.Type != -1) + if (fileEvent.Type != ULONG_MAX) { if (PhIsExecutingInWow64()) { diff --git a/plugins/ExtendedTools/etwprprp.c b/plugins/ExtendedTools/etwprprp.c index 08a691c7a5ed..f2efc7ff5a19 100644 --- a/plugins/ExtendedTools/etwprprp.c +++ b/plugins/ExtendedTools/etwprprp.c @@ -203,14 +203,14 @@ VOID EtwDiskNetworkUpdateGraphs( ) { Context->DiskGraphState.Valid = FALSE; - Context->DiskGraphState.TooltipIndex = -1; + Context->DiskGraphState.TooltipIndex = ULONG_MAX; Graph_MoveGrid(Context->DiskGraphHandle, 1); Graph_Draw(Context->DiskGraphHandle); Graph_UpdateTooltip(Context->DiskGraphHandle); InvalidateRect(Context->DiskGraphHandle, NULL, FALSE); Context->NetworkGraphState.Valid = FALSE; - Context->NetworkGraphState.TooltipIndex = -1; + Context->NetworkGraphState.TooltipIndex = ULONG_MAX; Graph_MoveGrid(Context->NetworkGraphHandle, 1); Graph_Draw(Context->NetworkGraphHandle); Graph_UpdateTooltip(Context->NetworkGraphHandle); @@ -224,18 +224,18 @@ VOID EtwDiskNetworkUpdatePanel( PET_PROCESS_BLOCK block = Context->Block; PhSetDialogItemText(Context->PanelHandle, IDC_ZREADS_V, PhaFormatUInt64(block->DiskReadCount, TRUE)->Buffer); - PhSetDialogItemText(Context->PanelHandle, IDC_ZREADBYTES_V, PhaFormatSize(block->DiskReadRawDelta.Value, -1)->Buffer); - PhSetDialogItemText(Context->PanelHandle, IDC_ZREADBYTESDELTA_V, PhaFormatSize(block->DiskReadRawDelta.Delta, -1)->Buffer); + PhSetDialogItemText(Context->PanelHandle, IDC_ZREADBYTES_V, PhaFormatSize(block->DiskReadRawDelta.Value, ULONG_MAX)->Buffer); + PhSetDialogItemText(Context->PanelHandle, IDC_ZREADBYTESDELTA_V, PhaFormatSize(block->DiskReadRawDelta.Delta, ULONG_MAX)->Buffer); PhSetDialogItemText(Context->PanelHandle, IDC_ZWRITES_V, PhaFormatUInt64(block->DiskWriteCount, TRUE)->Buffer); - PhSetDialogItemText(Context->PanelHandle, IDC_ZWRITEBYTES_V, PhaFormatSize(block->DiskWriteRawDelta.Value, -1)->Buffer); - PhSetDialogItemText(Context->PanelHandle, IDC_ZWRITEBYTESDELTA_V, PhaFormatSize(block->DiskWriteRawDelta.Delta, -1)->Buffer); + PhSetDialogItemText(Context->PanelHandle, IDC_ZWRITEBYTES_V, PhaFormatSize(block->DiskWriteRawDelta.Value, ULONG_MAX)->Buffer); + PhSetDialogItemText(Context->PanelHandle, IDC_ZWRITEBYTESDELTA_V, PhaFormatSize(block->DiskWriteRawDelta.Delta, ULONG_MAX)->Buffer); PhSetDialogItemText(Context->PanelHandle, IDC_ZRECEIVES_V, PhaFormatUInt64(block->NetworkReceiveCount, TRUE)->Buffer); - PhSetDialogItemText(Context->PanelHandle, IDC_ZRECEIVEBYTES_V, PhaFormatSize(block->NetworkReceiveRawDelta.Value, -1)->Buffer); - PhSetDialogItemText(Context->PanelHandle, IDC_ZRECEIVEBYTESDELTA_V, PhaFormatSize(block->NetworkReceiveRawDelta.Delta, -1)->Buffer); + PhSetDialogItemText(Context->PanelHandle, IDC_ZRECEIVEBYTES_V, PhaFormatSize(block->NetworkReceiveRawDelta.Value, ULONG_MAX)->Buffer); + PhSetDialogItemText(Context->PanelHandle, IDC_ZRECEIVEBYTESDELTA_V, PhaFormatSize(block->NetworkReceiveRawDelta.Delta, ULONG_MAX)->Buffer); PhSetDialogItemText(Context->PanelHandle, IDC_ZSENDS_V, PhaFormatUInt64(block->NetworkSendCount, TRUE)->Buffer); - PhSetDialogItemText(Context->PanelHandle, IDC_ZSENDBYTES_V, PhaFormatSize(block->NetworkSendRawDelta.Value, -1)->Buffer); - PhSetDialogItemText(Context->PanelHandle, IDC_ZSENDBYTESDELTA_V, PhaFormatSize(block->NetworkSendRawDelta.Delta, -1)->Buffer); + PhSetDialogItemText(Context->PanelHandle, IDC_ZSENDBYTES_V, PhaFormatSize(block->NetworkSendRawDelta.Value, ULONG_MAX)->Buffer); + PhSetDialogItemText(Context->PanelHandle, IDC_ZSENDBYTESDELTA_V, PhaFormatSize(block->NetworkSendRawDelta.Delta, ULONG_MAX)->Buffer); } VOID EtwDiskNetworkUpdateInfo( @@ -393,8 +393,8 @@ INT_PTR CALLBACK EtwDiskNetworkPageDlgProc( PhMoveReference(&context->DiskGraphState.Text, PhFormatString( L"R: %s, W: %s", - PhaFormatSize(context->CurrentDiskRead, -1)->Buffer, - PhaFormatSize(context->CurrentDiskWrite, -1)->Buffer + PhaFormatSize(context->CurrentDiskRead, ULONG_MAX)->Buffer, + PhaFormatSize(context->CurrentDiskWrite, ULONG_MAX)->Buffer )); hdc = Graph_GetBufferedContext(context->DiskGraphHandle); @@ -461,8 +461,8 @@ INT_PTR CALLBACK EtwDiskNetworkPageDlgProc( PhMoveReference(&context->NetworkGraphState.Text, PhFormatString( L"R: %s, S: %s", - PhaFormatSize(context->CurrentNetworkReceive, -1)->Buffer, - PhaFormatSize(context->CurrentNetworkSend, -1)->Buffer + PhaFormatSize(context->CurrentNetworkReceive, ULONG_MAX)->Buffer, + PhaFormatSize(context->CurrentNetworkSend, ULONG_MAX)->Buffer )); hdc = Graph_GetBufferedContext(context->NetworkGraphHandle); @@ -545,8 +545,8 @@ INT_PTR CALLBACK EtwDiskNetworkPageDlgProc( PhMoveReference(&context->DiskGraphState.TooltipText, PhFormatString( L"R: %s\nW: %s\n%s", - PhaFormatSize(diskRead, -1)->Buffer, - PhaFormatSize(diskWrite, -1)->Buffer, + PhaFormatSize(diskRead, ULONG_MAX)->Buffer, + PhaFormatSize(diskWrite, ULONG_MAX)->Buffer, ((PPH_STRING)PH_AUTO(PhGetStatisticsTimeString(NULL, getTooltipText->Index)))->Buffer )); } @@ -569,8 +569,8 @@ INT_PTR CALLBACK EtwDiskNetworkPageDlgProc( PhMoveReference(&context->NetworkGraphState.TooltipText, PhFormatString( L"S: %s\nR: %s\n%s", - PhaFormatSize(networkSend, -1)->Buffer, - PhaFormatSize(networkReceive, -1)->Buffer, + PhaFormatSize(networkSend, ULONG_MAX)->Buffer, + PhaFormatSize(networkReceive, ULONG_MAX)->Buffer, ((PPH_STRING)PH_AUTO(PhGetStatisticsTimeString(NULL, getTooltipText->Index)))->Buffer )); } diff --git a/plugins/ExtendedTools/etwsys.c b/plugins/ExtendedTools/etwsys.c index 81bf8de75566..cce7f436d5fe 100644 --- a/plugins/ExtendedTools/etwsys.c +++ b/plugins/ExtendedTools/etwsys.c @@ -155,8 +155,8 @@ BOOLEAN EtpDiskSysInfoSectionCallback( PhMoveReference(&Section->GraphState.TooltipText, PhFormatString( L"R: %s\nW: %s%s\n%s", - PhaFormatSize(diskRead, -1)->Buffer, - PhaFormatSize(diskWrite, -1)->Buffer, + PhaFormatSize(diskRead, ULONG_MAX)->Buffer, + PhaFormatSize(diskWrite, ULONG_MAX)->Buffer, PhGetStringOrEmpty(EtpGetMaxDiskString(getTooltipText->Index)), ((PPH_STRING)PH_AUTO(PhGetStatisticsTimeString(NULL, getTooltipText->Index)))->Buffer )); @@ -170,8 +170,8 @@ BOOLEAN EtpDiskSysInfoSectionCallback( drawPanel->Title = PhCreateString(L"Disk"); drawPanel->SubTitle = PhFormatString( L"R: %s\nW: %s", - PhaFormatSize(EtDiskReadDelta.Delta, -1)->Buffer, - PhaFormatSize(EtDiskWriteDelta.Delta, -1)->Buffer + PhaFormatSize(EtDiskReadDelta.Delta, ULONG_MAX)->Buffer, + PhaFormatSize(EtDiskWriteDelta.Delta, ULONG_MAX)->Buffer ); } return TRUE; @@ -341,8 +341,8 @@ VOID EtpNotifyDiskGraph( PhMoveReference(&DiskGraphState.TooltipText, PhFormatString( L"R: %s\nW: %s%s\n%s", - PhaFormatSize(diskRead, -1)->Buffer, - PhaFormatSize(diskWrite, -1)->Buffer, + PhaFormatSize(diskRead, ULONG_MAX)->Buffer, + PhaFormatSize(diskWrite, ULONG_MAX)->Buffer, PhGetStringOrEmpty(EtpGetMaxDiskString(getTooltipText->Index)), ((PPH_STRING)PH_AUTO(PhGetStatisticsTimeString(NULL, getTooltipText->Index)))->Buffer )); @@ -379,7 +379,7 @@ VOID EtpUpdateDiskGraph( ) { DiskGraphState.Valid = FALSE; - DiskGraphState.TooltipIndex = -1; + DiskGraphState.TooltipIndex = ULONG_MAX; Graph_MoveGrid(DiskGraphHandle, 1); Graph_Draw(DiskGraphHandle); Graph_UpdateTooltip(DiskGraphHandle); @@ -391,9 +391,9 @@ VOID EtpUpdateDiskPanel( ) { PhSetDialogItemText(DiskPanel, IDC_ZREADSDELTA_V, PhaFormatUInt64(EtDiskReadCountDelta.Delta, TRUE)->Buffer); - PhSetDialogItemText(DiskPanel, IDC_ZREADBYTESDELTA_V, PhaFormatSize(EtDiskReadDelta.Delta, -1)->Buffer); + PhSetDialogItemText(DiskPanel, IDC_ZREADBYTESDELTA_V, PhaFormatSize(EtDiskReadDelta.Delta, ULONG_MAX)->Buffer); PhSetDialogItemText(DiskPanel, IDC_ZWRITESDELTA_V, PhaFormatUInt64(EtDiskWriteCountDelta.Delta, TRUE)->Buffer); - PhSetDialogItemText(DiskPanel, IDC_ZWRITEBYTESDELTA_V, PhaFormatSize(EtDiskWriteDelta.Delta, -1)->Buffer); + PhSetDialogItemText(DiskPanel, IDC_ZWRITEBYTESDELTA_V, PhaFormatSize(EtDiskWriteDelta.Delta, ULONG_MAX)->Buffer); } PPH_PROCESS_RECORD EtpReferenceMaxDiskRecord( @@ -531,8 +531,8 @@ BOOLEAN EtpNetworkSysInfoSectionCallback( PhMoveReference(&Section->GraphState.TooltipText, PhFormatString( L"R: %s\nS: %s%s\n%s", - PhaFormatSize(networkReceive, -1)->Buffer, - PhaFormatSize(networkSend, -1)->Buffer, + PhaFormatSize(networkReceive, ULONG_MAX)->Buffer, + PhaFormatSize(networkSend, ULONG_MAX)->Buffer, PhGetStringOrEmpty(EtpGetMaxNetworkString(getTooltipText->Index)), ((PPH_STRING)PH_AUTO(PhGetStatisticsTimeString(NULL, getTooltipText->Index)))->Buffer )); @@ -546,8 +546,8 @@ BOOLEAN EtpNetworkSysInfoSectionCallback( drawPanel->Title = PhCreateString(L"Network"); drawPanel->SubTitle = PhFormatString( L"R: %s\nS: %s", - PhaFormatSize(EtNetworkReceiveDelta.Delta, -1)->Buffer, - PhaFormatSize(EtNetworkSendDelta.Delta, -1)->Buffer + PhaFormatSize(EtNetworkReceiveDelta.Delta, ULONG_MAX)->Buffer, + PhaFormatSize(EtNetworkSendDelta.Delta, ULONG_MAX)->Buffer ); } return TRUE; @@ -717,8 +717,8 @@ VOID EtpNotifyNetworkGraph( PhMoveReference(&NetworkGraphState.TooltipText, PhFormatString( L"R: %s\nS: %s%s\n%s", - PhaFormatSize(networkReceive, -1)->Buffer, - PhaFormatSize(networkSend, -1)->Buffer, + PhaFormatSize(networkReceive, ULONG_MAX)->Buffer, + PhaFormatSize(networkSend, ULONG_MAX)->Buffer, PhGetStringOrEmpty(EtpGetMaxNetworkString(getTooltipText->Index)), ((PPH_STRING)PH_AUTO(PhGetStatisticsTimeString(NULL, getTooltipText->Index)))->Buffer )); @@ -755,7 +755,7 @@ VOID EtpUpdateNetworkGraph( ) { NetworkGraphState.Valid = FALSE; - NetworkGraphState.TooltipIndex = -1; + NetworkGraphState.TooltipIndex = ULONG_MAX; Graph_MoveGrid(NetworkGraphHandle, 1); Graph_Draw(NetworkGraphHandle); Graph_UpdateTooltip(NetworkGraphHandle); @@ -767,9 +767,9 @@ VOID EtpUpdateNetworkPanel( ) { PhSetDialogItemText(NetworkPanel, IDC_ZRECEIVESDELTA_V, PhaFormatUInt64(EtNetworkReceiveCountDelta.Delta, TRUE)->Buffer); - PhSetDialogItemText(NetworkPanel, IDC_ZRECEIVEBYTESDELTA_V, PhaFormatSize(EtNetworkReceiveDelta.Delta, -1)->Buffer); + PhSetDialogItemText(NetworkPanel, IDC_ZRECEIVEBYTESDELTA_V, PhaFormatSize(EtNetworkReceiveDelta.Delta, ULONG_MAX)->Buffer); PhSetDialogItemText(NetworkPanel, IDC_ZSENDSDELTA_V, PhaFormatUInt64(EtNetworkSendCountDelta.Delta, TRUE)->Buffer); - PhSetDialogItemText(NetworkPanel, IDC_ZSENDBYTESDELTA_V, PhaFormatSize(EtNetworkSendDelta.Delta, -1)->Buffer); + PhSetDialogItemText(NetworkPanel, IDC_ZSENDBYTESDELTA_V, PhaFormatSize(EtNetworkSendDelta.Delta, ULONG_MAX)->Buffer); } PPH_PROCESS_RECORD EtpReferenceMaxNetworkRecord( diff --git a/plugins/ExtendedTools/gpunodes.c b/plugins/ExtendedTools/gpunodes.c index f73e82db7ea7..0938776422ec 100644 --- a/plugins/ExtendedTools/gpunodes.c +++ b/plugins/ExtendedTools/gpunodes.c @@ -451,7 +451,7 @@ INT_PTR CALLBACK EtpGpuNodesDlgProc( for (ULONG i = 0; i < EtGpuTotalNodeCount; i++) { GraphState[i].Valid = FALSE; - GraphState[i].TooltipIndex = -1; + GraphState[i].TooltipIndex = ULONG_MAX; Graph_MoveGrid(GraphHandle[i], 1); Graph_Draw(GraphHandle[i]); Graph_UpdateTooltip(GraphHandle[i]); diff --git a/plugins/ExtendedTools/gpuprprp.c b/plugins/ExtendedTools/gpuprprp.c index 26675da073ad..db33d672acf3 100644 --- a/plugins/ExtendedTools/gpuprprp.c +++ b/plugins/ExtendedTools/gpuprprp.c @@ -367,28 +367,28 @@ VOID GpuPropUpdateGraphs( ) { Context->GpuGraphState.Valid = FALSE; - Context->GpuGraphState.TooltipIndex = -1; + Context->GpuGraphState.TooltipIndex = ULONG_MAX; Graph_MoveGrid(Context->GpuGraphHandle, 1); Graph_Draw(Context->GpuGraphHandle); Graph_UpdateTooltip(Context->GpuGraphHandle); InvalidateRect(Context->GpuGraphHandle, NULL, FALSE); Context->MemoryGraphState.Valid = FALSE; - Context->MemoryGraphState.TooltipIndex = -1; + Context->MemoryGraphState.TooltipIndex = ULONG_MAX; Graph_MoveGrid(Context->MemGraphHandle, 1); Graph_Draw(Context->MemGraphHandle); Graph_UpdateTooltip(Context->MemGraphHandle); InvalidateRect(Context->MemGraphHandle, NULL, FALSE); Context->MemorySharedGraphState.Valid = FALSE; - Context->MemorySharedGraphState.TooltipIndex = -1; + Context->MemorySharedGraphState.TooltipIndex = ULONG_MAX; Graph_MoveGrid(Context->SharedGraphHandle, 1); Graph_Draw(Context->SharedGraphHandle); Graph_UpdateTooltip(Context->SharedGraphHandle); InvalidateRect(Context->SharedGraphHandle, NULL, FALSE); Context->GpuCommittedGraphState.Valid = FALSE; - Context->GpuCommittedGraphState.TooltipIndex = -1; + Context->GpuCommittedGraphState.TooltipIndex = ULONG_MAX; Graph_MoveGrid(Context->CommittedGraphHandle, 1); Graph_Draw(Context->CommittedGraphHandle); Graph_UpdateTooltip(Context->CommittedGraphHandle); @@ -411,16 +411,16 @@ VOID GpuPropUpdatePanel( if (Context->DetailsHandle) { // Note: no lock is needed because we only ever update the 'details' dialog text on this same thread. - PhSetDialogItemText(Context->DetailsHandle, IDC_ZDEDICATEDCOMMITTED_V, PhaFormatSize(Context->GpuStatistics.DedicatedCommitted, -1)->Buffer); - PhSetDialogItemText(Context->DetailsHandle, IDC_ZSHAREDCOMMITTED_V, PhaFormatSize(Context->GpuStatistics.SharedCommitted, -1)->Buffer); - PhSetDialogItemText(Context->DetailsHandle, IDC_ZTOTALALLOCATED_V, PhaFormatSize(Context->GpuStatistics.BytesAllocated, -1)->Buffer); - PhSetDialogItemText(Context->DetailsHandle, IDC_ZTOTALRESERVED_V, PhaFormatSize(Context->GpuStatistics.BytesReserved, -1)->Buffer); - PhSetDialogItemText(Context->DetailsHandle, IDC_ZWRITECOMBINEDALLOCATED_V, PhaFormatSize(Context->GpuStatistics.WriteCombinedBytesAllocated, -1)->Buffer); - PhSetDialogItemText(Context->DetailsHandle, IDC_ZWRITECOMBINEDRESERVED_V, PhaFormatSize(Context->GpuStatistics.WriteCombinedBytesReserved, -1)->Buffer); - PhSetDialogItemText(Context->DetailsHandle, IDC_ZCACHEDALLOCATED_V, PhaFormatSize(Context->GpuStatistics.CachedBytesAllocated, -1)->Buffer); - PhSetDialogItemText(Context->DetailsHandle, IDC_ZCACHEDRESERVED_V, PhaFormatSize(Context->GpuStatistics.CachedBytesReserved, -1)->Buffer); - PhSetDialogItemText(Context->DetailsHandle, IDC_ZSECTIONALLOCATED_V, PhaFormatSize(Context->GpuStatistics.SectionBytesAllocated, -1)->Buffer); - PhSetDialogItemText(Context->DetailsHandle, IDC_ZSECTIONRESERVED_V, PhaFormatSize(Context->GpuStatistics.SectionBytesReserved, -1)->Buffer); + PhSetDialogItemText(Context->DetailsHandle, IDC_ZDEDICATEDCOMMITTED_V, PhaFormatSize(Context->GpuStatistics.DedicatedCommitted, ULONG_MAX)->Buffer); + PhSetDialogItemText(Context->DetailsHandle, IDC_ZSHAREDCOMMITTED_V, PhaFormatSize(Context->GpuStatistics.SharedCommitted, ULONG_MAX)->Buffer); + PhSetDialogItemText(Context->DetailsHandle, IDC_ZTOTALALLOCATED_V, PhaFormatSize(Context->GpuStatistics.BytesAllocated, ULONG_MAX)->Buffer); + PhSetDialogItemText(Context->DetailsHandle, IDC_ZTOTALRESERVED_V, PhaFormatSize(Context->GpuStatistics.BytesReserved, ULONG_MAX)->Buffer); + PhSetDialogItemText(Context->DetailsHandle, IDC_ZWRITECOMBINEDALLOCATED_V, PhaFormatSize(Context->GpuStatistics.WriteCombinedBytesAllocated, ULONG_MAX)->Buffer); + PhSetDialogItemText(Context->DetailsHandle, IDC_ZWRITECOMBINEDRESERVED_V, PhaFormatSize(Context->GpuStatistics.WriteCombinedBytesReserved, ULONG_MAX)->Buffer); + PhSetDialogItemText(Context->DetailsHandle, IDC_ZCACHEDALLOCATED_V, PhaFormatSize(Context->GpuStatistics.CachedBytesAllocated, ULONG_MAX)->Buffer); + PhSetDialogItemText(Context->DetailsHandle, IDC_ZCACHEDRESERVED_V, PhaFormatSize(Context->GpuStatistics.CachedBytesReserved, ULONG_MAX)->Buffer); + PhSetDialogItemText(Context->DetailsHandle, IDC_ZSECTIONALLOCATED_V, PhaFormatSize(Context->GpuStatistics.SectionBytesAllocated, ULONG_MAX)->Buffer); + PhSetDialogItemText(Context->DetailsHandle, IDC_ZSECTIONRESERVED_V, PhaFormatSize(Context->GpuStatistics.SectionBytesReserved, ULONG_MAX)->Buffer); } } @@ -627,7 +627,7 @@ INT_PTR CALLBACK EtpGpuPageDlgProc( PhMoveReference(&context->MemoryGraphState.Text, PhFormatString( L"%s", - PhaFormatSize(UInt32x32To64(context->CurrentMemUsage, PAGE_SIZE), -1)->Buffer + PhaFormatSize(UInt32x32To64(context->CurrentMemUsage, PAGE_SIZE), ULONG_MAX)->Buffer )); hdc = Graph_GetBufferedContext(context->MemGraphHandle); @@ -681,7 +681,7 @@ INT_PTR CALLBACK EtpGpuPageDlgProc( PhMoveReference(&context->MemorySharedGraphState.Text, PhFormatString( L"%s", - PhaFormatSize(UInt32x32To64(context->CurrentMemSharedUsage, PAGE_SIZE), -1)->Buffer + PhaFormatSize(UInt32x32To64(context->CurrentMemSharedUsage, PAGE_SIZE), ULONG_MAX)->Buffer )); hdc = Graph_GetBufferedContext(context->SharedGraphHandle); @@ -729,7 +729,7 @@ INT_PTR CALLBACK EtpGpuPageDlgProc( PhMoveReference(&context->GpuCommittedGraphState.Text, PhFormatString( L"%s", - PhaFormatSize(UInt32x32To64(context->CurrentCommitUsage, PAGE_SIZE), -1)->Buffer + PhaFormatSize(UInt32x32To64(context->CurrentCommitUsage, PAGE_SIZE), ULONG_MAX)->Buffer )); hdc = Graph_GetBufferedContext(context->CommittedGraphHandle); @@ -812,7 +812,7 @@ INT_PTR CALLBACK EtpGpuPageDlgProc( PhMoveReference(&context->MemoryGraphState.TooltipText, PhFormatString( L"%s\n%s", - PhFormatSize(UInt32x32To64(gpuMemory, PAGE_SIZE), -1)->Buffer, + PhFormatSize(UInt32x32To64(gpuMemory, PAGE_SIZE), ULONG_MAX)->Buffer, PH_AUTO_T(PH_STRING, PhGetStatisticsTimeString(NULL, getTooltipText->Index))->Buffer) ); } @@ -830,7 +830,7 @@ INT_PTR CALLBACK EtpGpuPageDlgProc( PhMoveReference(&context->MemorySharedGraphState.TooltipText, PhFormatString( L"%s\n%s", - PhFormatSize(UInt32x32To64(gpuSharedMemory, PAGE_SIZE), -1)->Buffer, + PhFormatSize(UInt32x32To64(gpuSharedMemory, PAGE_SIZE), ULONG_MAX)->Buffer, PH_AUTO_T(PH_STRING, PhGetStatisticsTimeString(NULL, getTooltipText->Index))->Buffer) ); } @@ -848,7 +848,7 @@ INT_PTR CALLBACK EtpGpuPageDlgProc( PhMoveReference(&context->GpuCommittedGraphState.TooltipText, PhFormatString( L"%s\n%s", - PhFormatSize(UInt32x32To64(gpuCommitMemory, PAGE_SIZE), -1)->Buffer, + PhFormatSize(UInt32x32To64(gpuCommitMemory, PAGE_SIZE), ULONG_MAX)->Buffer, PH_AUTO_T(PH_STRING, PhGetStatisticsTimeString(NULL, getTooltipText->Index))->Buffer) ); } diff --git a/plugins/ExtendedTools/main.c b/plugins/ExtendedTools/main.c index f2a905e688db..4d28be0d21e5 100644 --- a/plugins/ExtendedTools/main.c +++ b/plugins/ExtendedTools/main.c @@ -205,8 +205,8 @@ VOID NTAPI ProcessMenuInitializingCallback( if (miscMenu) { - PhInsertEMenuItem(miscMenu, PhPluginCreateEMenuItem(PluginInstance, flags, ID_PROCESS_UNLOADEDMODULES, L"&Unloaded modules", processItem), -1); - PhInsertEMenuItem(miscMenu, PhPluginCreateEMenuItem(PluginInstance, flags, ID_PROCESS_WSWATCH, L"&WS watch", processItem), -1); + PhInsertEMenuItem(miscMenu, PhPluginCreateEMenuItem(PluginInstance, flags, ID_PROCESS_UNLOADEDMODULES, L"&Unloaded modules", processItem), ULONG_MAX); + PhInsertEMenuItem(miscMenu, PhPluginCreateEMenuItem(PluginInstance, flags, ID_PROCESS_WSWATCH, L"&WS watch", processItem), ULONG_MAX); } } diff --git a/plugins/ExtendedTools/treeext.c b/plugins/ExtendedTools/treeext.c index d24fddb8a16a..4e702f0cd063 100644 --- a/plugins/ExtendedTools/treeext.c +++ b/plugins/ExtendedTools/treeext.c @@ -276,11 +276,11 @@ VOID EtProcessTreeNewMessage( break; case ETPRTNC_DISKREADBYTES: if (block->DiskReadRaw != 0) - text = PhFormatSize(block->DiskReadRaw, -1); + text = PhFormatSize(block->DiskReadRaw, ULONG_MAX); break; case ETPRTNC_DISKWRITEBYTES: if (block->DiskWriteRaw != 0) - text = PhFormatSize(block->DiskWriteRaw, -1); + text = PhFormatSize(block->DiskWriteRaw, ULONG_MAX); break; case ETPRTNC_DISKTOTALBYTES: { @@ -303,11 +303,11 @@ VOID EtProcessTreeNewMessage( break; case ETPRTNC_DISKREADBYTESDELTA: if (block->DiskReadRawDelta.Delta != 0) - text = PhFormatSize(block->DiskReadRawDelta.Delta, -1); + text = PhFormatSize(block->DiskReadRawDelta.Delta, ULONG_MAX); break; case ETPRTNC_DISKWRITEBYTESDELTA: if (block->DiskWriteRawDelta.Delta != 0) - text = PhFormatSize(block->DiskWriteRawDelta.Delta, -1); + text = PhFormatSize(block->DiskWriteRawDelta.Delta, ULONG_MAX); break; case ETPRTNC_DISKTOTALBYTESDELTA: { @@ -330,11 +330,11 @@ VOID EtProcessTreeNewMessage( break; case ETPRTNC_NETWORKRECEIVEBYTES: if (block->NetworkReceiveRaw != 0) - text = PhFormatSize(block->NetworkReceiveRaw, -1); + text = PhFormatSize(block->NetworkReceiveRaw, ULONG_MAX); break; case ETPRTNC_NETWORKSENDBYTES: if (block->NetworkSendRaw != 0) - text = PhFormatSize(block->NetworkSendRaw, -1); + text = PhFormatSize(block->NetworkSendRaw, ULONG_MAX); break; case ETPRTNC_NETWORKTOTALBYTES: { @@ -357,11 +357,11 @@ VOID EtProcessTreeNewMessage( break; case ETPRTNC_NETWORKRECEIVEBYTESDELTA: if (block->NetworkReceiveRawDelta.Delta != 0) - text = PhFormatSize(block->NetworkReceiveRawDelta.Delta, -1); + text = PhFormatSize(block->NetworkReceiveRawDelta.Delta, ULONG_MAX); break; case ETPRTNC_NETWORKSENDBYTESDELTA: if (block->NetworkSendRawDelta.Delta != 0) - text = PhFormatSize(block->NetworkSendRawDelta.Delta, -1); + text = PhFormatSize(block->NetworkSendRawDelta.Delta, ULONG_MAX); break; case ETPRTNC_NETWORKTOTALBYTESDELTA: { @@ -719,15 +719,15 @@ VOID EtNetworkTreeNewMessage( break; case ETNETNC_RECEIVEBYTES: if (block->ReceiveRaw != 0) - text = PhFormatSize(block->ReceiveRaw, -1); + text = PhFormatSize(block->ReceiveRaw, ULONG_MAX); break; case ETNETNC_SENDBYTES: if (block->SendRaw != 0) - text = PhFormatSize(block->SendRaw, -1); + text = PhFormatSize(block->SendRaw, ULONG_MAX); break; case ETNETNC_TOTALBYTES: if (block->ReceiveRaw + block->SendRaw != 0) - text = PhFormatSize(block->ReceiveRaw + block->SendRaw, -1); + text = PhFormatSize(block->ReceiveRaw + block->SendRaw, ULONG_MAX); break; case ETNETNC_RECEIVESDELTA: if (block->ReceiveDelta.Delta != 0) @@ -739,15 +739,15 @@ VOID EtNetworkTreeNewMessage( break; case ETNETNC_RECEIVEBYTESDELTA: if (block->ReceiveRawDelta.Delta != 0) - text = PhFormatSize(block->ReceiveRawDelta.Delta, -1); + text = PhFormatSize(block->ReceiveRawDelta.Delta, ULONG_MAX); break; case ETNETNC_SENDBYTESDELTA: if (block->SendRawDelta.Delta != 0) - text = PhFormatSize(block->SendRawDelta.Delta, -1); + text = PhFormatSize(block->SendRawDelta.Delta, ULONG_MAX); break; case ETNETNC_TOTALBYTESDELTA: if (block->ReceiveRawDelta.Delta + block->SendRawDelta.Delta != 0) - text = PhFormatSize(block->ReceiveRawDelta.Delta + block->SendRawDelta.Delta, -1); + text = PhFormatSize(block->ReceiveRawDelta.Delta + block->SendRawDelta.Delta, ULONG_MAX); break; case ETNETNC_FIREWALLSTATUS: { diff --git a/plugins/HardwareDevices/diskdetails.c b/plugins/HardwareDevices/diskdetails.c index c71d5cb01fa6..8bfc8d46a76a 100644 --- a/plugins/HardwareDevices/diskdetails.c +++ b/plugins/HardwareDevices/diskdetails.c @@ -311,11 +311,11 @@ VOID DiskDriveQueryFileSystem( PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_LFS_VERSION, 1, PhaFormatString(L"%lu.%lu", ntfsVolumeInfo.ExtendedVolumeData.LfsMajorVersion, ntfsVolumeInfo.ExtendedVolumeData.LfsMinorVersion)->Buffer); //PhSetListViewSubItem(Context->ListViewHandle, lvItemIndex, 1, - // PhaFormatSize(ntfsVolumeInfo.ExtendedVolumeData.BytesPerPhysicalSector, -1)->Buffer); + // PhaFormatSize(ntfsVolumeInfo.ExtendedVolumeData.BytesPerPhysicalSector, ULONG_MAX)->Buffer); PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_TOTAL_SIZE, 1, - PhaFormatSize(ntfsVolumeInfo.VolumeData.NumberSectors.QuadPart * ntfsVolumeInfo.VolumeData.BytesPerSector, -1)->Buffer); + PhaFormatSize(ntfsVolumeInfo.VolumeData.NumberSectors.QuadPart * ntfsVolumeInfo.VolumeData.BytesPerSector, ULONG_MAX)->Buffer); PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_TOTAL_FREE, 1, - PhaFormatString(L"%s (%.2f%%)", PhaFormatSize(ntfsVolumeInfo.VolumeData.FreeClusters.QuadPart * ntfsVolumeInfo.VolumeData.BytesPerCluster, -1)->Buffer, (FLOAT)(ntfsVolumeInfo.VolumeData.FreeClusters.QuadPart * 100) / ntfsVolumeInfo.VolumeData.TotalClusters.QuadPart)->Buffer); + PhaFormatString(L"%s (%.2f%%)", PhaFormatSize(ntfsVolumeInfo.VolumeData.FreeClusters.QuadPart * ntfsVolumeInfo.VolumeData.BytesPerCluster, ULONG_MAX)->Buffer, (FLOAT)(ntfsVolumeInfo.VolumeData.FreeClusters.QuadPart * 100) / ntfsVolumeInfo.VolumeData.TotalClusters.QuadPart)->Buffer); PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_TOTAL_SECTORS, 1, PhaFormatUInt64(ntfsVolumeInfo.VolumeData.NumberSectors.QuadPart, TRUE)->Buffer); PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_TOTAL_CLUSTERS, 1, @@ -335,13 +335,13 @@ VOID DiskDriveQueryFileSystem( PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_MFT_RECORDS, 1, PhaFormatUInt64(ntfsVolumeInfo.VolumeData.MftValidDataLength.QuadPart / ntfsVolumeInfo.VolumeData.BytesPerFileRecordSegment, TRUE)->Buffer); PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_MFT_SIZE, 1, - PhaFormatString(L"%s (%.2f%%)", PhaFormatSize(ntfsVolumeInfo.VolumeData.MftValidDataLength.QuadPart, -1)->Buffer, (FLOAT)(ntfsVolumeInfo.VolumeData.MftValidDataLength.QuadPart * 100 / ntfsVolumeInfo.VolumeData.BytesPerCluster) / ntfsVolumeInfo.VolumeData.TotalClusters.QuadPart)->Buffer); + PhaFormatString(L"%s (%.2f%%)", PhaFormatSize(ntfsVolumeInfo.VolumeData.MftValidDataLength.QuadPart, ULONG_MAX)->Buffer, (FLOAT)(ntfsVolumeInfo.VolumeData.MftValidDataLength.QuadPart * 100 / ntfsVolumeInfo.VolumeData.BytesPerCluster) / ntfsVolumeInfo.VolumeData.TotalClusters.QuadPart)->Buffer); PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_MFT_START, 1, PhaFormatString(L"%I64u", ntfsVolumeInfo.VolumeData.MftStartLcn.QuadPart)->Buffer); PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_MFT_ZONE, 1, PhaFormatString(L"%I64u - %I64u", ntfsVolumeInfo.VolumeData.MftZoneStart.QuadPart, ntfsVolumeInfo.VolumeData.MftZoneEnd.QuadPart)->Buffer); PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_MFT_ZONE_SIZE, 1, - PhaFormatString(L"%s (%.2f%%)", PhaFormatSize((ntfsVolumeInfo.VolumeData.MftZoneEnd.QuadPart - ntfsVolumeInfo.VolumeData.MftZoneStart.QuadPart) * ntfsVolumeInfo.VolumeData.BytesPerCluster, -1)->Buffer, (FLOAT)(ntfsVolumeInfo.VolumeData.MftZoneEnd.QuadPart - ntfsVolumeInfo.VolumeData.MftZoneStart.QuadPart) * 100 / ntfsVolumeInfo.VolumeData.TotalClusters.QuadPart)->Buffer); + PhaFormatString(L"%s (%.2f%%)", PhaFormatSize((ntfsVolumeInfo.VolumeData.MftZoneEnd.QuadPart - ntfsVolumeInfo.VolumeData.MftZoneStart.QuadPart) * ntfsVolumeInfo.VolumeData.BytesPerCluster, ULONG_MAX)->Buffer, (FLOAT)(ntfsVolumeInfo.VolumeData.MftZoneEnd.QuadPart - ntfsVolumeInfo.VolumeData.MftZoneStart.QuadPart) * 100 / ntfsVolumeInfo.VolumeData.TotalClusters.QuadPart)->Buffer); PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_MFT_MIRROR_START, 1, PhaFormatString(L"%I64u", ntfsVolumeInfo.VolumeData.Mft2StartLcn.QuadPart)->Buffer); } @@ -361,9 +361,9 @@ VOID DiskDriveQueryFileSystem( PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_FS_VERSION, 1, PhaFormatString(L"%lu.%lu", refsVolumeInfo.MajorVersion, refsVolumeInfo.MinorVersion)->Buffer); PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_TOTAL_SIZE, 1, - PhaFormatSize(refsVolumeInfo.NumberSectors.QuadPart * refsVolumeInfo.BytesPerSector, -1)->Buffer); + PhaFormatSize(refsVolumeInfo.NumberSectors.QuadPart * refsVolumeInfo.BytesPerSector, ULONG_MAX)->Buffer); PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_TOTAL_FREE, 1, - PhaFormatString(L"%s (%.2f%%)", PhaFormatSize(refsVolumeInfo.FreeClusters.QuadPart * refsVolumeInfo.BytesPerCluster, -1)->Buffer, (FLOAT)(refsVolumeInfo.FreeClusters.QuadPart * 100) / refsVolumeInfo.TotalClusters.QuadPart)->Buffer); + PhaFormatString(L"%s (%.2f%%)", PhaFormatSize(refsVolumeInfo.FreeClusters.QuadPart * refsVolumeInfo.BytesPerCluster, ULONG_MAX)->Buffer, (FLOAT)(refsVolumeInfo.FreeClusters.QuadPart * 100) / refsVolumeInfo.TotalClusters.QuadPart)->Buffer); PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_TOTAL_SECTORS, 1, PhaFormatUInt64(refsVolumeInfo.NumberSectors.QuadPart, TRUE)->Buffer); PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_TOTAL_CLUSTERS, 1, @@ -390,9 +390,9 @@ VOID DiskDriveQueryFileSystem( PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_DISK_WRITES, 1, PhaFormatUInt64(buffer->FileSystemStatistics.UserDiskWrites, TRUE)->Buffer); PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_FILE_READ_BYTES, 1, - PhaFormatSize(buffer->FileSystemStatistics.UserFileReadBytes, -1)->Buffer); + PhaFormatSize(buffer->FileSystemStatistics.UserFileReadBytes, ULONG_MAX)->Buffer); PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_FILE_WRITE_BYTES, 1, - PhaFormatSize(buffer->FileSystemStatistics.UserFileWriteBytes, -1)->Buffer); + PhaFormatSize(buffer->FileSystemStatistics.UserFileWriteBytes, ULONG_MAX)->Buffer); PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_METADATA_READS, 1, PhaFormatUInt64(buffer->FileSystemStatistics.MetaDataReads, TRUE)->Buffer); PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_METADATA_WRITES, 1, @@ -402,9 +402,9 @@ VOID DiskDriveQueryFileSystem( PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_METADATA_DISK_WRITES, 1, PhaFormatUInt64(buffer->FileSystemStatistics.MetaDataDiskWrites, TRUE)->Buffer); PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_METADATA_READ_BYTES, 1, - PhaFormatSize(buffer->FileSystemStatistics.MetaDataReadBytes, -1)->Buffer); + PhaFormatSize(buffer->FileSystemStatistics.MetaDataReadBytes, ULONG_MAX)->Buffer); PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_METADATA_WRITE_BYTES, 1, - PhaFormatSize(buffer->FileSystemStatistics.MetaDataWriteBytes, -1)->Buffer); + PhaFormatSize(buffer->FileSystemStatistics.MetaDataWriteBytes, ULONG_MAX)->Buffer); // NTFS specific @@ -413,9 +413,9 @@ VOID DiskDriveQueryFileSystem( PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_MFT_WRITES, 1, PhaFormatUInt64(buffer->NtfsStatistics.MftWrites, TRUE)->Buffer); PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_MFT_READ_BYTES, 1, - PhaFormatSize(buffer->NtfsStatistics.MftReadBytes, -1)->Buffer); + PhaFormatSize(buffer->NtfsStatistics.MftReadBytes, ULONG_MAX)->Buffer); PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_MFT_WRITE_BYTES, 1, - PhaFormatSize(buffer->NtfsStatistics.MftWriteBytes, -1)->Buffer); + PhaFormatSize(buffer->NtfsStatistics.MftWriteBytes, ULONG_MAX)->Buffer); //PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_ROOT_INDEX_READS, 1, // PhaFormatUInt64(buffer->NtfsStatistics.RootIndexReads, TRUE)->Buffer); //PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_ROOT_INDEX_WRITES, 1, @@ -429,33 +429,33 @@ VOID DiskDriveQueryFileSystem( PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_BITMAP_WRITES, 1, PhaFormatUInt64(buffer->NtfsStatistics.BitmapWrites, TRUE)->Buffer); PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_BITMAP_READ_BYTES, 1, - PhaFormatSize(buffer->NtfsStatistics.BitmapReadBytes, -1)->Buffer); + PhaFormatSize(buffer->NtfsStatistics.BitmapReadBytes, ULONG_MAX)->Buffer); PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_BITMAP_WRITE_BYTES, 1, - PhaFormatSize(buffer->NtfsStatistics.BitmapWriteBytes, -1)->Buffer); + PhaFormatSize(buffer->NtfsStatistics.BitmapWriteBytes, ULONG_MAX)->Buffer); PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_MFT_BITMAP_READS, 1, PhaFormatUInt64(buffer->NtfsStatistics.MftBitmapReads, TRUE)->Buffer); PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_MFT_BITMAP_WRITES, 1, PhaFormatUInt64(buffer->NtfsStatistics.MftBitmapWrites, TRUE)->Buffer); PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_MFT_BITMAP_READ_BYTES, 1, - PhaFormatSize(buffer->NtfsStatistics.MftBitmapReadBytes, -1)->Buffer); + PhaFormatSize(buffer->NtfsStatistics.MftBitmapReadBytes, ULONG_MAX)->Buffer); PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_MFT_BITMAP_WRITE_BYTES, 1, - PhaFormatSize(buffer->NtfsStatistics.MftBitmapWriteBytes, -1)->Buffer); + PhaFormatSize(buffer->NtfsStatistics.MftBitmapWriteBytes, ULONG_MAX)->Buffer); PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_USER_INDEX_READS, 1, PhaFormatUInt64(buffer->NtfsStatistics.UserIndexReads, TRUE)->Buffer); PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_USER_INDEX_WRITES, 1, PhaFormatUInt64(buffer->NtfsStatistics.UserIndexWrites, TRUE)->Buffer); PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_USER_INDEX_READ_BYTES, 1, - PhaFormatSize(buffer->NtfsStatistics.UserIndexReadBytes, -1)->Buffer); + PhaFormatSize(buffer->NtfsStatistics.UserIndexReadBytes, ULONG_MAX)->Buffer); PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_USER_INDEX_WRITE_BYTES, 1, - PhaFormatSize(buffer->NtfsStatistics.UserIndexWriteBytes, -1)->Buffer); + PhaFormatSize(buffer->NtfsStatistics.UserIndexWriteBytes, ULONG_MAX)->Buffer); PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_LOGFILE_READS, 1, PhaFormatUInt64(buffer->NtfsStatistics.LogFileReads, TRUE)->Buffer); PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_LOGFILE_WRITES, 1, PhaFormatUInt64(buffer->NtfsStatistics.LogFileWrites, TRUE)->Buffer); PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_LOGFILE_READ_BYTES, 1, - PhaFormatSize(buffer->NtfsStatistics.LogFileReadBytes, -1)->Buffer); + PhaFormatSize(buffer->NtfsStatistics.LogFileReadBytes, ULONG_MAX)->Buffer); PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_LOGFILE_WRITE_BYTES, 1, - PhaFormatSize(buffer->NtfsStatistics.LogFileWriteBytes, -1)->Buffer); + PhaFormatSize(buffer->NtfsStatistics.LogFileWriteBytes, ULONG_MAX)->Buffer); /*PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_MFT_USER_LEVEL_WRITE, 1, PhaFormatUInt64(buffer->NtfsStatistics.MftWritesUserLevel.Write, TRUE)->Buffer); PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_MFT_USER_LEVEL_CREATE, 1, @@ -473,7 +473,7 @@ VOID DiskDriveQueryFileSystem( PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_MFT2_WRITES, 1, PhaFormatUInt64(buffer->NtfsStatistics.Mft2Writes, TRUE)->Buffer); PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_MFT2_WRITE_BYTES, 1, - PhaFormatSize(buffer->NtfsStatistics.Mft2WriteBytes, -1)->Buffer); + PhaFormatSize(buffer->NtfsStatistics.Mft2WriteBytes, ULONG_MAX)->Buffer); PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_MFT2_USER_LEVEL_WRITE, 1, PhaFormatUInt64(buffer->NtfsStatistics.Mft2WritesUserLevel.Write, TRUE)->Buffer); PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_MFT2_USER_LEVEL_CREATE, 1, diff --git a/plugins/HardwareDevices/diskgraph.c b/plugins/HardwareDevices/diskgraph.c index 571e27465c3c..36deb6a9d8b7 100644 --- a/plugins/HardwareDevices/diskgraph.c +++ b/plugins/HardwareDevices/diskgraph.c @@ -38,9 +38,9 @@ VOID DiskDriveUpdatePanel( _Inout_ PDV_DISK_SYSINFO_CONTEXT Context ) { - PhSetDialogItemText(Context->PanelWindowHandle, IDC_STAT_BREAD, PhaFormatSize(Context->DiskEntry->BytesReadDelta.Value, -1)->Buffer); - PhSetDialogItemText(Context->PanelWindowHandle, IDC_STAT_BWRITE, PhaFormatSize(Context->DiskEntry->BytesWrittenDelta.Value, -1)->Buffer); - PhSetDialogItemText(Context->PanelWindowHandle, IDC_STAT_BTOTAL, PhaFormatSize(Context->DiskEntry->BytesReadDelta.Value + Context->DiskEntry->BytesWrittenDelta.Value, -1)->Buffer); + PhSetDialogItemText(Context->PanelWindowHandle, IDC_STAT_BREAD, PhaFormatSize(Context->DiskEntry->BytesReadDelta.Value, ULONG_MAX)->Buffer); + PhSetDialogItemText(Context->PanelWindowHandle, IDC_STAT_BWRITE, PhaFormatSize(Context->DiskEntry->BytesWrittenDelta.Value, ULONG_MAX)->Buffer); + PhSetDialogItemText(Context->PanelWindowHandle, IDC_STAT_BTOTAL, PhaFormatSize(Context->DiskEntry->BytesReadDelta.Value + Context->DiskEntry->BytesWrittenDelta.Value, ULONG_MAX)->Buffer); PhSetDialogItemText(Context->PanelWindowHandle, IDC_STAT_ACTIVE, PhaFormatString(L"%.0f%%", Context->DiskEntry->ActiveTime)->Buffer @@ -324,8 +324,8 @@ INT_PTR CALLBACK DiskDriveDialogProc( PhMoveReference(&context->GraphState.TooltipText, PhFormatString( L"R: %s\nW: %s\n%s", - PhaFormatSize(diskReadValue, -1)->Buffer, - PhaFormatSize(diskWriteValue, -1)->Buffer, + PhaFormatSize(diskReadValue, ULONG_MAX)->Buffer, + PhaFormatSize(diskWriteValue, ULONG_MAX)->Buffer, ((PPH_STRING)PhAutoDereferenceObject(PhGetStatisticsTimeString(NULL, getTooltipText->Index)))->Buffer )); } @@ -453,8 +453,8 @@ BOOLEAN DiskDriveSectionCallback( PhMoveReference(&Section->GraphState.TooltipText, PhFormatString( L"R: %s\nW: %s\n%s", - PhaFormatSize(diskReadValue, -1)->Buffer, - PhaFormatSize(diskWriteValue, -1)->Buffer, + PhaFormatSize(diskReadValue, ULONG_MAX)->Buffer, + PhaFormatSize(diskWriteValue, ULONG_MAX)->Buffer, ((PPH_STRING)PhAutoDereferenceObject(PhGetStatisticsTimeString(NULL, getTooltipText->Index)))->Buffer )); @@ -468,8 +468,8 @@ BOOLEAN DiskDriveSectionCallback( PhSetReference(&drawPanel->Title, context->DiskEntry->DiskIndexName); drawPanel->SubTitle = PhFormatString( L"R: %s\nW: %s", - PhaFormatSize(context->DiskEntry->BytesReadDelta.Delta, -1)->Buffer, - PhaFormatSize(context->DiskEntry->BytesWrittenDelta.Delta, -1)->Buffer + PhaFormatSize(context->DiskEntry->BytesReadDelta.Delta, ULONG_MAX)->Buffer, + PhaFormatSize(context->DiskEntry->BytesWrittenDelta.Delta, ULONG_MAX)->Buffer ); if (!drawPanel->Title) @@ -501,4 +501,4 @@ VOID DiskDriveSysInfoInitializing( section.Name = context->SectionName->sr; context->SysinfoSection = Pointers->CreateSection(§ion); -} \ No newline at end of file +} diff --git a/plugins/HardwareDevices/diskoptions.c b/plugins/HardwareDevices/diskoptions.c index 8af567c6522c..5ba73a9173fe 100644 --- a/plugins/HardwareDevices/diskoptions.c +++ b/plugins/HardwareDevices/diskoptions.c @@ -216,13 +216,13 @@ VOID FreeListViewDiskDriveEntries( _In_ PDV_DISK_OPTIONS_CONTEXT Context ) { - ULONG index = -1; + ULONG index = ULONG_MAX; while ((index = PhFindListViewItemByFlags( Context->ListViewHandle, index, LVNI_ALL - )) != -1) + )) != ULONG_MAX) { PDV_DISK_ID param; @@ -445,7 +445,7 @@ VOID FindDiskDrives( PhAcquireQueuedLockShared(&DiskDrivesListLock); for (ULONG i = 0; i < DiskDrivesList->Count; i++) { - ULONG index = -1; + ULONG index = ULONG_MAX; BOOLEAN found = FALSE; PDV_DISK_ENTRY entry = PhReferenceObjectSafe(DiskDrivesList->Items[i]); @@ -456,7 +456,7 @@ VOID FindDiskDrives( Context->ListViewHandle, index, LVNI_ALL - )) != -1) + )) != ULONG_MAX) { PDV_DISK_ID param; diff --git a/plugins/HardwareDevices/netdetails.c b/plugins/HardwareDevices/netdetails.c index a395ed278c57..4e9e26d00721 100644 --- a/plugins/HardwareDevices/netdetails.c +++ b/plugins/HardwareDevices/netdetails.c @@ -467,26 +467,26 @@ VOID NetAdapterUpdateDetails( PhSetListViewSubItem(Context->ListViewHandle, NETADAPTER_DETAILS_INDEX_UNICAST_SENTPKTS, 1, PhaFormatUInt64(interfaceStats.ifHCOutUcastPkts, TRUE)->Buffer); PhSetListViewSubItem(Context->ListViewHandle, NETADAPTER_DETAILS_INDEX_UNICAST_RECVPKTS, 1, PhaFormatUInt64(interfaceStats.ifHCInUcastPkts, TRUE)->Buffer); PhSetListViewSubItem(Context->ListViewHandle, NETADAPTER_DETAILS_INDEX_UNICAST_TOTALPKTS, 1, PhaFormatUInt64(interfaceStats.ifHCInUcastPkts + interfaceStats.ifHCOutUcastPkts, TRUE)->Buffer); - PhSetListViewSubItem(Context->ListViewHandle, NETADAPTER_DETAILS_INDEX_UNICAST_SENT, 1, PhaFormatSize(interfaceStats.ifHCOutUcastOctets, -1)->Buffer); - PhSetListViewSubItem(Context->ListViewHandle, NETADAPTER_DETAILS_INDEX_UNICAST_RECEIVED, 1, PhaFormatSize(interfaceStats.ifHCInUcastOctets, -1)->Buffer); - PhSetListViewSubItem(Context->ListViewHandle, NETADAPTER_DETAILS_INDEX_UNICAST_TOTAL, 1, PhaFormatSize(interfaceStats.ifHCInUcastOctets + interfaceStats.ifHCOutUcastOctets, -1)->Buffer); - //PhSetListViewSubItem(Context->ListViewHandle, NETADAPTER_DETAILS_INDEX_UNICAST_SENDING, 1, interfaceXmitUnicastSpeed != 0 ? PhaFormatString(L"%s/s", PhaFormatSize(interfaceXmitUnicastSpeed, -1)->Buffer)->Buffer : L""); - //PhSetListViewSubItem(Context->ListViewHandle, NETADAPTER_DETAILS_INDEX_UNICAST_RECEIVING, 1, interfaceRcvUnicastSpeed != 0 ? PhaFormatString(L"%s/s", PhaFormatSize(interfaceRcvUnicastSpeed, -1)->Buffer)->Buffer : L""); + PhSetListViewSubItem(Context->ListViewHandle, NETADAPTER_DETAILS_INDEX_UNICAST_SENT, 1, PhaFormatSize(interfaceStats.ifHCOutUcastOctets, ULONG_MAX)->Buffer); + PhSetListViewSubItem(Context->ListViewHandle, NETADAPTER_DETAILS_INDEX_UNICAST_RECEIVED, 1, PhaFormatSize(interfaceStats.ifHCInUcastOctets, ULONG_MAX)->Buffer); + PhSetListViewSubItem(Context->ListViewHandle, NETADAPTER_DETAILS_INDEX_UNICAST_TOTAL, 1, PhaFormatSize(interfaceStats.ifHCInUcastOctets + interfaceStats.ifHCOutUcastOctets, ULONG_MAX)->Buffer); + //PhSetListViewSubItem(Context->ListViewHandle, NETADAPTER_DETAILS_INDEX_UNICAST_SENDING, 1, interfaceXmitUnicastSpeed != 0 ? PhaFormatString(L"%s/s", PhaFormatSize(interfaceXmitUnicastSpeed, ULONG_MAX)->Buffer)->Buffer : L""); + //PhSetListViewSubItem(Context->ListViewHandle, NETADAPTER_DETAILS_INDEX_UNICAST_RECEIVING, 1, interfaceRcvUnicastSpeed != 0 ? PhaFormatString(L"%s/s", PhaFormatSize(interfaceRcvUnicastSpeed, ULONG_MAX)->Buffer)->Buffer : L""); //PhSetListViewSubItem(Context->ListViewHandle, NETADAPTER_DETAILS_INDEX_UNICAST_UTILIZATION, 1, PhaFormatString(L"%.2f%%", utilization2)->Buffer); PhSetListViewSubItem(Context->ListViewHandle, NETADAPTER_DETAILS_INDEX_BROADCAST_SENTPKTS, 1, PhaFormatUInt64(interfaceStats.ifHCOutBroadcastPkts, TRUE)->Buffer); PhSetListViewSubItem(Context->ListViewHandle, NETADAPTER_DETAILS_INDEX_BROADCAST_RECVPKTS, 1, PhaFormatUInt64(interfaceStats.ifHCInBroadcastPkts, TRUE)->Buffer); PhSetListViewSubItem(Context->ListViewHandle, NETADAPTER_DETAILS_INDEX_BROADCAST_TOTALPKTS, 1, PhaFormatUInt64(interfaceStats.ifHCInBroadcastPkts + interfaceStats.ifHCOutBroadcastPkts, TRUE)->Buffer); - PhSetListViewSubItem(Context->ListViewHandle, NETADAPTER_DETAILS_INDEX_BROADCAST_SENT, 1, PhaFormatSize(interfaceStats.ifHCOutBroadcastOctets, -1)->Buffer); - PhSetListViewSubItem(Context->ListViewHandle, NETADAPTER_DETAILS_INDEX_BROADCAST_RECEIVED, 1, PhaFormatSize(interfaceStats.ifHCInBroadcastOctets, -1)->Buffer); - PhSetListViewSubItem(Context->ListViewHandle, NETADAPTER_DETAILS_INDEX_BROADCAST_TOTAL, 1, PhaFormatSize(interfaceStats.ifHCInBroadcastOctets + interfaceStats.ifHCOutBroadcastOctets, -1)->Buffer); + PhSetListViewSubItem(Context->ListViewHandle, NETADAPTER_DETAILS_INDEX_BROADCAST_SENT, 1, PhaFormatSize(interfaceStats.ifHCOutBroadcastOctets, ULONG_MAX)->Buffer); + PhSetListViewSubItem(Context->ListViewHandle, NETADAPTER_DETAILS_INDEX_BROADCAST_RECEIVED, 1, PhaFormatSize(interfaceStats.ifHCInBroadcastOctets, ULONG_MAX)->Buffer); + PhSetListViewSubItem(Context->ListViewHandle, NETADAPTER_DETAILS_INDEX_BROADCAST_TOTAL, 1, PhaFormatSize(interfaceStats.ifHCInBroadcastOctets + interfaceStats.ifHCOutBroadcastOctets, ULONG_MAX)->Buffer); PhSetListViewSubItem(Context->ListViewHandle, NETADAPTER_DETAILS_INDEX_MULTICAST_SENTPKTS, 1, PhaFormatUInt64(interfaceStats.ifHCOutMulticastPkts, TRUE)->Buffer); PhSetListViewSubItem(Context->ListViewHandle, NETADAPTER_DETAILS_INDEX_MULTICAST_RECVPKTS, 1, PhaFormatUInt64(interfaceStats.ifHCInMulticastPkts, TRUE)->Buffer); PhSetListViewSubItem(Context->ListViewHandle, NETADAPTER_DETAILS_INDEX_MULTICAST_TOTALPKTS, 1, PhaFormatUInt64(interfaceStats.ifHCInMulticastPkts + interfaceStats.ifHCOutMulticastPkts, TRUE)->Buffer); - PhSetListViewSubItem(Context->ListViewHandle, NETADAPTER_DETAILS_INDEX_MULTICAST_SENT, 1, PhaFormatSize(interfaceStats.ifHCOutMulticastOctets, -1)->Buffer); - PhSetListViewSubItem(Context->ListViewHandle, NETADAPTER_DETAILS_INDEX_MULTICAST_RECEIVED, 1, PhaFormatSize(interfaceStats.ifHCInMulticastOctets, -1)->Buffer); - PhSetListViewSubItem(Context->ListViewHandle, NETADAPTER_DETAILS_INDEX_MULTICAST_TOTAL, 1, PhaFormatSize(interfaceStats.ifHCInMulticastOctets + interfaceStats.ifHCOutMulticastOctets, -1)->Buffer); + PhSetListViewSubItem(Context->ListViewHandle, NETADAPTER_DETAILS_INDEX_MULTICAST_SENT, 1, PhaFormatSize(interfaceStats.ifHCOutMulticastOctets, ULONG_MAX)->Buffer); + PhSetListViewSubItem(Context->ListViewHandle, NETADAPTER_DETAILS_INDEX_MULTICAST_RECEIVED, 1, PhaFormatSize(interfaceStats.ifHCInMulticastOctets, ULONG_MAX)->Buffer); + PhSetListViewSubItem(Context->ListViewHandle, NETADAPTER_DETAILS_INDEX_MULTICAST_TOTAL, 1, PhaFormatSize(interfaceStats.ifHCInMulticastOctets + interfaceStats.ifHCOutMulticastOctets, ULONG_MAX)->Buffer); PhSetListViewSubItem(Context->ListViewHandle, NETADAPTER_DETAILS_INDEX_ERRORS_SENTPKTS, 1, PhaFormatUInt64(interfaceStats.ifOutErrors, TRUE)->Buffer); PhSetListViewSubItem(Context->ListViewHandle, NETADAPTER_DETAILS_INDEX_ERRORS_RECVPKTS, 1, PhaFormatUInt64(interfaceStats.ifInErrors, TRUE)->Buffer); diff --git a/plugins/HardwareDevices/netgraph.c b/plugins/HardwareDevices/netgraph.c index 46dfeed8762f..03886dc9a208 100644 --- a/plugins/HardwareDevices/netgraph.c +++ b/plugins/HardwareDevices/netgraph.c @@ -28,7 +28,7 @@ VOID NetAdapterUpdateGraphs( ) { Context->GraphState.Valid = FALSE; - Context->GraphState.TooltipIndex = -1; + Context->GraphState.TooltipIndex = ULONG_MAX; Graph_MoveGrid(Context->GraphHandle, 1); Graph_Draw(Context->GraphHandle); Graph_UpdateTooltip(Context->GraphHandle); @@ -131,14 +131,14 @@ VOID NetAdapterUpdatePanel( } } - PhSetDialogItemText(Context->PanelWindowHandle, IDC_STAT_BSENT, PhaFormatSize(outOctetsValue, -1)->Buffer); - PhSetDialogItemText(Context->PanelWindowHandle, IDC_STAT_BRECEIVED, PhaFormatSize(inOctetsValue, -1)->Buffer); - PhSetDialogItemText(Context->PanelWindowHandle, IDC_STAT_BTOTAL, PhaFormatSize(inOctetsValue + outOctetsValue, -1)->Buffer); + PhSetDialogItemText(Context->PanelWindowHandle, IDC_STAT_BSENT, PhaFormatSize(outOctetsValue, ULONG_MAX)->Buffer); + PhSetDialogItemText(Context->PanelWindowHandle, IDC_STAT_BRECEIVED, PhaFormatSize(inOctetsValue, ULONG_MAX)->Buffer); + PhSetDialogItemText(Context->PanelWindowHandle, IDC_STAT_BTOTAL, PhaFormatSize(inOctetsValue + outOctetsValue, ULONG_MAX)->Buffer); if (mediaState == MediaConnectStateConnected) { PhSetDialogItemText(Context->PanelWindowHandle, IDC_LINK_STATE, L"Connected"); - PhSetDialogItemText(Context->PanelWindowHandle, IDC_LINK_SPEED, PhaFormatString(L"%s/s", PhaFormatSize(linkSpeedValue / BITS_IN_ONE_BYTE, -1)->Buffer)->Buffer); + PhSetDialogItemText(Context->PanelWindowHandle, IDC_LINK_SPEED, PhaFormatString(L"%s/s", PhaFormatSize(linkSpeedValue / BITS_IN_ONE_BYTE, ULONG_MAX)->Buffer)->Buffer); } else { @@ -372,8 +372,8 @@ INT_PTR CALLBACK NetAdapterDialogProc( PhMoveReference(&context->GraphState.TooltipText, PhFormatString( L"R: %s\nS: %s\n%s", - PhaFormatSize(adapterInboundValue, -1)->Buffer, - PhaFormatSize(adapterOutboundValue, -1)->Buffer, + PhaFormatSize(adapterInboundValue, ULONG_MAX)->Buffer, + PhaFormatSize(adapterOutboundValue, ULONG_MAX)->Buffer, ((PPH_STRING)PH_AUTO(PhGetStatisticsTimeString(NULL, getTooltipText->Index)))->Buffer )); } @@ -495,8 +495,8 @@ BOOLEAN NetAdapterSectionCallback( PhMoveReference(&Section->GraphState.TooltipText, PhFormatString( L"R: %s\nS: %s\n%s", - PhaFormatSize(adapterInboundValue, -1)->Buffer, - PhaFormatSize(adapterOutboundValue, -1)->Buffer, + PhaFormatSize(adapterInboundValue, ULONG_MAX)->Buffer, + PhaFormatSize(adapterOutboundValue, ULONG_MAX)->Buffer, ((PPH_STRING)PH_AUTO(PhGetStatisticsTimeString(NULL, getTooltipText->Index)))->Buffer )); @@ -510,8 +510,8 @@ BOOLEAN NetAdapterSectionCallback( PhSetReference(&drawPanel->Title, context->AdapterEntry->AdapterName); drawPanel->SubTitle = PhFormatString( L"R: %s\nS: %s", - PhaFormatSize(context->AdapterEntry->InboundValue, -1)->Buffer, - PhaFormatSize(context->AdapterEntry->OutboundValue, -1)->Buffer + PhaFormatSize(context->AdapterEntry->InboundValue, ULONG_MAX)->Buffer, + PhaFormatSize(context->AdapterEntry->OutboundValue, ULONG_MAX)->Buffer ); if (!drawPanel->Title) @@ -541,4 +541,4 @@ VOID NetAdapterSysInfoInitializing( section.Name = PhGetStringRef(context->SectionName); context->SysinfoSection = Pointers->CreateSection(§ion); -} \ No newline at end of file +} diff --git a/plugins/HardwareDevices/storage.c b/plugins/HardwareDevices/storage.c index d38e8c70e183..d862cdedc192 100644 --- a/plugins/HardwareDevices/storage.c +++ b/plugins/HardwareDevices/storage.c @@ -633,7 +633,7 @@ PPH_STRING DiskDriveQueryGeometry( ))) { // TODO: This doesn't return total capacity like Task Manager. - return PhFormatSize(result.Cylinders.QuadPart * result.TracksPerCylinder * result.SectorsPerTrack * result.BytesPerSector, -1); + return PhFormatSize(result.Cylinders.QuadPart * result.TracksPerCylinder * result.SectorsPerTrack * result.BytesPerSector, ULONG_MAX); } return PhReferenceEmptyString(); diff --git a/plugins/NetworkTools/tracetree.c b/plugins/NetworkTools/tracetree.c index 1650bb7d53f8..bcfabb4e84e7 100644 --- a/plugins/NetworkTools/tracetree.c +++ b/plugins/NetworkTools/tracetree.c @@ -251,7 +251,7 @@ VOID RemoveTracertNode( PhRemoveEntryHashtable(Context->NodeHashtable, &Node); - if ((index = PhFindItemList(Context->NodeList, Node)) != -1) + if ((index = PhFindItemList(Context->NodeList, Node)) != ULONG_MAX) { PhRemoveItemList(Context->NodeList, index); } diff --git a/plugins/NetworkTools/update.c b/plugins/NetworkTools/update.c index 54e1955bf46c..df33b01296f1 100644 --- a/plugins/NetworkTools/update.c +++ b/plugins/NetworkTools/update.c @@ -364,9 +364,9 @@ NTSTATUS GeoIPUpdateThread( // TODO: Update on timer callback. { FLOAT percent = ((FLOAT)downloadedBytes / contentLength * 100); - PPH_STRING totalLength = PhFormatSize(contentLength, -1); - PPH_STRING totalDownloaded = PhFormatSize(downloadedBytes, -1); - PPH_STRING totalSpeed = PhFormatSize(timeBitsPerSecond, -1); + PPH_STRING totalLength = PhFormatSize(contentLength, ULONG_MAX); + PPH_STRING totalDownloaded = PhFormatSize(downloadedBytes, ULONG_MAX); + PPH_STRING totalSpeed = PhFormatSize(timeBitsPerSecond, ULONG_MAX); PPH_STRING statusMessage = PhFormatString( L"Downloaded: %s of %s (%.0f%%)\r\nSpeed: %s/s", diff --git a/plugins/OnlineChecks/main.c b/plugins/OnlineChecks/main.c index 13d74b3da80e..27bdf065fb31 100644 --- a/plugins/OnlineChecks/main.c +++ b/plugins/OnlineChecks/main.c @@ -277,12 +277,12 @@ VOID NTAPI MainMenuInitializingCallback( return; onlineMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, 0, L"&Online Checks", NULL); - PhInsertEMenuItem(onlineMenuItem, enableMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, ENABLE_SERVICE_VIRUSTOTAL, L"&Enable VirusTotal scanning", NULL), -1); - PhInsertEMenuItem(onlineMenuItem, PhCreateEMenuSeparator(), -1); - PhInsertEMenuItem(onlineMenuItem, PhPluginCreateEMenuItem(PluginInstance, 0, MENUITEM_HYBRIDANALYSIS_UPLOAD_FILE, L"Upload file to &Hybrid-Analysis...", NULL), -1); - PhInsertEMenuItem(onlineMenuItem, PhPluginCreateEMenuItem(PluginInstance, 0, MENUITEM_VIRUSTOTAL_UPLOAD_FILE, L"&Upload file to VirusTotal...", NULL), -1); - //PhInsertEMenuItem(onlineMenuItem, PhPluginCreateEMenuItem(PluginInstance, 0, MENUITEM_VIRUSTOTAL_QUEUE, L"Upload unknown files to VirusTotal...", NULL), -1); - PhInsertEMenuItem(menuInfo->Menu, onlineMenuItem, -1); + PhInsertEMenuItem(onlineMenuItem, enableMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, ENABLE_SERVICE_VIRUSTOTAL, L"&Enable VirusTotal scanning", NULL), ULONG_MAX); + PhInsertEMenuItem(onlineMenuItem, PhCreateEMenuSeparator(), ULONG_MAX); + PhInsertEMenuItem(onlineMenuItem, PhPluginCreateEMenuItem(PluginInstance, 0, MENUITEM_HYBRIDANALYSIS_UPLOAD_FILE, L"Upload file to &Hybrid-Analysis...", NULL), ULONG_MAX); + PhInsertEMenuItem(onlineMenuItem, PhPluginCreateEMenuItem(PluginInstance, 0, MENUITEM_VIRUSTOTAL_UPLOAD_FILE, L"&Upload file to VirusTotal...", NULL), ULONG_MAX); + //PhInsertEMenuItem(onlineMenuItem, PhPluginCreateEMenuItem(PluginInstance, 0, MENUITEM_VIRUSTOTAL_QUEUE, L"Upload unknown files to VirusTotal...", NULL), ULONG_MAX); + PhInsertEMenuItem(menuInfo->Menu, onlineMenuItem, ULONG_MAX); if (VirusTotalScanningEnabled) enableMenuItem->Flags |= PH_EMENU_CHECKED; @@ -299,9 +299,9 @@ PPH_EMENU_ITEM CreateSendToMenu( ULONG insertIndex; sendToMenu = PhPluginCreateEMenuItem(PluginInstance, 0, 0, L"Sen&d to", NULL); - PhInsertEMenuItem(sendToMenu, PhPluginCreateEMenuItem(PluginInstance, 0, MENUITEM_HYBRIDANALYSIS_UPLOAD, L"&hybrid-analysis.com", FileName), -1); - PhInsertEMenuItem(sendToMenu, PhPluginCreateEMenuItem(PluginInstance, 0, MENUITEM_VIRUSTOTAL_UPLOAD, L"&virustotal.com", FileName), -1); - PhInsertEMenuItem(sendToMenu, PhPluginCreateEMenuItem(PluginInstance, 0, MENUITEM_JOTTI_UPLOAD, L"virusscan.&jotti.org", FileName), -1); + PhInsertEMenuItem(sendToMenu, PhPluginCreateEMenuItem(PluginInstance, 0, MENUITEM_HYBRIDANALYSIS_UPLOAD, L"&hybrid-analysis.com", FileName), ULONG_MAX); + PhInsertEMenuItem(sendToMenu, PhPluginCreateEMenuItem(PluginInstance, 0, MENUITEM_VIRUSTOTAL_UPLOAD, L"&virustotal.com", FileName), ULONG_MAX); + PhInsertEMenuItem(sendToMenu, PhPluginCreateEMenuItem(PluginInstance, 0, MENUITEM_JOTTI_UPLOAD, L"virusscan.&jotti.org", FileName), ULONG_MAX); if (ProcessesMenu && (menuItem = PhFindEMenuItem(Parent, PH_EMENU_FIND_STARTSWITH, L"Search online", 0))) { @@ -311,8 +311,8 @@ PPH_EMENU_ITEM CreateSendToMenu( } else { - PhInsertEMenuItem(Parent, PhCreateEMenuSeparator(), -1); - PhInsertEMenuItem(Parent, sendToMenu, -1); + PhInsertEMenuItem(Parent, PhCreateEMenuSeparator(), ULONG_MAX); + PhInsertEMenuItem(Parent, sendToMenu, ULONG_MAX); } return sendToMenu; @@ -378,11 +378,11 @@ VOID NTAPI ServiceMenuInitializingCallback( serviceItem = NULL; sendToMenu = PhPluginCreateEMenuItem(PluginInstance, 0, 0, L"Sen&d to", NULL); - PhInsertEMenuItem(sendToMenu, PhPluginCreateEMenuItem(PluginInstance, 0, MENUITEM_HYBRIDANALYSIS_UPLOAD_SERVICE, L"&hybrid-analysis.com", serviceItem ? serviceItem : NULL), -1); - PhInsertEMenuItem(sendToMenu, PhPluginCreateEMenuItem(PluginInstance, 0, MENUITEM_VIRUSTOTAL_UPLOAD_SERVICE, L"&virustotal.com", serviceItem ? serviceItem : NULL), -1); - PhInsertEMenuItem(sendToMenu, PhPluginCreateEMenuItem(PluginInstance, 0, MENUITEM_JOTTI_UPLOAD_SERVICE, L"virusscan.&jotti.org", serviceItem ? serviceItem : NULL), -1); - PhInsertEMenuItem(menuInfo->Menu, PhCreateEMenuSeparator(), -1); - PhInsertEMenuItem(menuInfo->Menu, sendToMenu, -1); + PhInsertEMenuItem(sendToMenu, PhPluginCreateEMenuItem(PluginInstance, 0, MENUITEM_HYBRIDANALYSIS_UPLOAD_SERVICE, L"&hybrid-analysis.com", serviceItem ? serviceItem : NULL), ULONG_MAX); + PhInsertEMenuItem(sendToMenu, PhPluginCreateEMenuItem(PluginInstance, 0, MENUITEM_VIRUSTOTAL_UPLOAD_SERVICE, L"&virustotal.com", serviceItem ? serviceItem : NULL), ULONG_MAX); + PhInsertEMenuItem(sendToMenu, PhPluginCreateEMenuItem(PluginInstance, 0, MENUITEM_JOTTI_UPLOAD_SERVICE, L"virusscan.&jotti.org", serviceItem ? serviceItem : NULL), ULONG_MAX); + PhInsertEMenuItem(menuInfo->Menu, PhCreateEMenuSeparator(), ULONG_MAX); + PhInsertEMenuItem(menuInfo->Menu, sendToMenu, ULONG_MAX); if (!serviceItem) { @@ -872,4 +872,4 @@ LOGICAL DllMain( } return TRUE; -} \ No newline at end of file +} diff --git a/plugins/ToolStatus/graph.c b/plugins/ToolStatus/graph.c index 31372a21ca52..b549eab053d3 100644 --- a/plugins/ToolStatus/graph.c +++ b/plugins/ToolStatus/graph.c @@ -546,8 +546,8 @@ static PPH_STRING PhSipGetMaxIoString( L"\n%s (%u): R+O: %s, W: %s", maxProcessRecord->ProcessName->Buffer, HandleToUlong(maxProcessRecord->ProcessId), - PhaFormatSize(maxIoReadOther, -1)->Buffer, - PhaFormatSize(maxIoWrite, -1)->Buffer + PhaFormatSize(maxIoReadOther, ULONG_MAX)->Buffer, + PhaFormatSize(maxIoWrite, ULONG_MAX)->Buffer ); } else @@ -555,8 +555,8 @@ static PPH_STRING PhSipGetMaxIoString( maxUsageString = PhaFormatString( L"\n%s: R+O: %s, W: %s", maxProcessRecord->ProcessName->Buffer, - PhaFormatSize(maxIoReadOther, -1)->Buffer, - PhaFormatSize(maxIoWrite, -1)->Buffer + PhaFormatSize(maxIoReadOther, ULONG_MAX)->Buffer, + PhaFormatSize(maxIoWrite, ULONG_MAX)->Buffer ); } @@ -690,7 +690,7 @@ TOOLSTATUS_GRAPH_MESSAGE_CALLBACK_DECLARE(PhysicalHistoryGraphMessageCallback) PhMoveReference(&GraphState->TooltipText, PhFormatString( L"Physical memory: %s\n%s", - PhaFormatSize(UInt32x32To64(physicalUsage, PAGE_SIZE), -1)->Buffer, + PhaFormatSize(UInt32x32To64(physicalUsage, PAGE_SIZE), ULONG_MAX)->Buffer, PH_AUTO_T(PH_STRING, PhGetStatisticsTimeString(NULL, getTooltipText->Index))->Buffer )); } @@ -755,7 +755,7 @@ TOOLSTATUS_GRAPH_MESSAGE_CALLBACK_DECLARE(CommitHistoryGraphMessageCallback) PhMoveReference(&GraphState->TooltipText, PhFormatString( L"Commit charge: %s\n%s", - PhaFormatSize(UInt32x32To64(commitUsage, PAGE_SIZE), -1)->Buffer, + PhaFormatSize(UInt32x32To64(commitUsage, PAGE_SIZE), ULONG_MAX)->Buffer, PH_AUTO_T(PH_STRING, PhGetStatisticsTimeString(NULL, getTooltipText->Index))->Buffer )); } @@ -830,9 +830,9 @@ TOOLSTATUS_GRAPH_MESSAGE_CALLBACK_DECLARE(IoHistoryGraphMessageCallback) PhMoveReference(&GraphState->TooltipText, PhFormatString( L"R: %s\nW: %s\nO: %s%s\n%s", - PhaFormatSize(ioRead, -1)->Buffer, - PhaFormatSize(ioWrite, -1)->Buffer, - PhaFormatSize(ioOther, -1)->Buffer, + PhaFormatSize(ioRead, ULONG_MAX)->Buffer, + PhaFormatSize(ioWrite, ULONG_MAX)->Buffer, + PhaFormatSize(ioOther, ULONG_MAX)->Buffer, PhGetStringOrEmpty(PhSipGetMaxIoString(getTooltipText->Index)), PH_AUTO_T(PH_STRING, PhGetStatisticsTimeString(NULL, getTooltipText->Index))->Buffer )); diff --git a/plugins/ToolStatus/statusbar.c b/plugins/ToolStatus/statusbar.c index 4c2c563a22fb..d5a1f77c1318 100644 --- a/plugins/ToolStatus/statusbar.c +++ b/plugins/ToolStatus/statusbar.c @@ -203,7 +203,7 @@ VOID StatusBarShowMenu( GetCursorPos(&cursorPos); menu = PhCreateEMenu(); - PhInsertEMenuItem(menu, PhCreateEMenuItem(0, COMMAND_ID_ENABLE_SEARCHBOX, L"Customize...", NULL, NULL), -1); + PhInsertEMenuItem(menu, PhCreateEMenuItem(0, COMMAND_ID_ENABLE_SEARCHBOX, L"Customize...", NULL, NULL), ULONG_MAX); selectedItem = PhShowEMenu( menu, @@ -214,7 +214,7 @@ VOID StatusBarShowMenu( cursorPos.y ); - if (selectedItem && selectedItem->Id != -1) + if (selectedItem && selectedItem->Id != ULONG_MAX) { StatusBarShowCustomizeDialog(); diff --git a/plugins/UserNotes/main.c b/plugins/UserNotes/main.c index 43718883bdc9..1208276f0f87 100644 --- a/plugins/UserNotes/main.c +++ b/plugins/UserNotes/main.c @@ -919,14 +919,14 @@ VOID AddSavePriorityMenuItemsAndHook( if (affinityMenuItem = PhFindEMenuItem(MenuInfo->Menu, 0, L"Affinity", PHAPP_ID_PROCESS_AFFINITY)) { // HACK: Change default Affinity menu-item into a drop-down list - PhInsertEMenuItem(affinityMenuItem, PhCreateEMenuItem(0, affinityMenuItem->Id, L"Set &affinity", NULL, NULL), -1); + PhInsertEMenuItem(affinityMenuItem, PhCreateEMenuItem(0, affinityMenuItem->Id, L"Set &affinity", NULL, NULL), ULONG_MAX); //PhInsertEMenuItem(affinityMenuItem, PhPluginCreateEMenuItem(PluginInstance, 0, PHAPP_ID_PROCESS_AFFINITY, L"Set &affinity", NULL), PhIndexOfEMenuItem(MenuInfo->Menu, affinityMenuItem) + 1); //PhRemoveEMenuItem(affinityMenuItem, affinityMenuItem, 0); // Insert standard menu-items - PhInsertEMenuItem(affinityMenuItem, PhCreateEMenuSeparator(), -1); - PhInsertEMenuItem(affinityMenuItem, saveMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, PROCESS_AFFINITY_SAVE_ID, PhaFormatString(L"&Save for %s", ProcessItem->ProcessName->Buffer)->Buffer, NULL), -1); - PhInsertEMenuItem(affinityMenuItem, saveForCommandLineMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, PROCESS_AFFINITY_SAVE_FOR_THIS_COMMAND_LINE_ID, L"Save &for this command line", NULL), -1); + PhInsertEMenuItem(affinityMenuItem, PhCreateEMenuSeparator(), ULONG_MAX); + PhInsertEMenuItem(affinityMenuItem, saveMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, PROCESS_AFFINITY_SAVE_ID, PhaFormatString(L"&Save for %s", ProcessItem->ProcessName->Buffer)->Buffer, NULL), ULONG_MAX); + PhInsertEMenuItem(affinityMenuItem, saveForCommandLineMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, PROCESS_AFFINITY_SAVE_FOR_THIS_COMMAND_LINE_ID, L"Save &for this command line", NULL), ULONG_MAX); if (!ProcessItem->CommandLine) saveForCommandLineMenuItem->Flags |= PH_EMENU_DISABLED; @@ -944,9 +944,9 @@ VOID AddSavePriorityMenuItemsAndHook( // Priority if (priorityMenuItem = PhFindEMenuItem(MenuInfo->Menu, 0, L"Priority", 0)) { - PhInsertEMenuItem(priorityMenuItem, PhCreateEMenuSeparator(), -1); - PhInsertEMenuItem(priorityMenuItem, saveMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, PROCESS_PRIORITY_SAVE_ID, PhaFormatString(L"&Save for %s", ProcessItem->ProcessName->Buffer)->Buffer, NULL), -1); - PhInsertEMenuItem(priorityMenuItem, saveForCommandLineMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, PROCESS_PRIORITY_SAVE_FOR_THIS_COMMAND_LINE_ID, L"Save &for this command line", NULL), -1); + PhInsertEMenuItem(priorityMenuItem, PhCreateEMenuSeparator(), ULONG_MAX); + PhInsertEMenuItem(priorityMenuItem, saveMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, PROCESS_PRIORITY_SAVE_ID, PhaFormatString(L"&Save for %s", ProcessItem->ProcessName->Buffer)->Buffer, NULL), ULONG_MAX); + PhInsertEMenuItem(priorityMenuItem, saveForCommandLineMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, PROCESS_PRIORITY_SAVE_FOR_THIS_COMMAND_LINE_ID, L"Save &for this command line", NULL), ULONG_MAX); if (!ProcessItem->CommandLine) saveForCommandLineMenuItem->Flags |= PH_EMENU_DISABLED; @@ -964,9 +964,9 @@ VOID AddSavePriorityMenuItemsAndHook( // I/O Priority if (ioPriorityMenuItem = PhFindEMenuItem(MenuInfo->Menu, 0, L"I/O Priority", 0)) { - PhInsertEMenuItem(ioPriorityMenuItem, PhCreateEMenuSeparator(), -1); - PhInsertEMenuItem(ioPriorityMenuItem, saveMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, PROCESS_IO_PRIORITY_SAVE_ID, PhaFormatString(L"&Save for %s", ProcessItem->ProcessName->Buffer)->Buffer, NULL), -1); - PhInsertEMenuItem(ioPriorityMenuItem, saveForCommandLineMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, PROCESS_IO_PRIORITY_SAVE_FOR_THIS_COMMAND_LINE_ID, L"Save &for this command line", NULL), -1); + PhInsertEMenuItem(ioPriorityMenuItem, PhCreateEMenuSeparator(), ULONG_MAX); + PhInsertEMenuItem(ioPriorityMenuItem, saveMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, PROCESS_IO_PRIORITY_SAVE_ID, PhaFormatString(L"&Save for %s", ProcessItem->ProcessName->Buffer)->Buffer, NULL), ULONG_MAX); + PhInsertEMenuItem(ioPriorityMenuItem, saveForCommandLineMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, PROCESS_IO_PRIORITY_SAVE_FOR_THIS_COMMAND_LINE_ID, L"Save &for this command line", NULL), ULONG_MAX); if (!ProcessItem->CommandLine) saveForCommandLineMenuItem->Flags |= PH_EMENU_DISABLED; diff --git a/plugins/WindowExplorer/wnddlg.c b/plugins/WindowExplorer/wnddlg.c index 799843620252..05ecc581bdbd 100644 --- a/plugins/WindowExplorer/wnddlg.c +++ b/plugins/WindowExplorer/wnddlg.c @@ -621,7 +621,7 @@ INT_PTR CALLBACK WepWindowsDlgProc( contextMenuEvent->Location.y ); - if (selectedItem && selectedItem->Id != -1) + if (selectedItem && selectedItem->Id != ULONG_MAX) { BOOLEAN handled = FALSE; @@ -1062,7 +1062,7 @@ INT_PTR CALLBACK WepWindowsPageProc( contextMenuEvent->Location.y ); - if (selectedItem && selectedItem->Id != -1) + if (selectedItem && selectedItem->Id != ULONG_MAX) { BOOLEAN handled = FALSE; diff --git a/plugins/WindowExplorer/wndtree.c b/plugins/WindowExplorer/wndtree.c index f3b45269d549..c94d2c220d2d 100644 --- a/plugins/WindowExplorer/wndtree.c +++ b/plugins/WindowExplorer/wndtree.c @@ -282,7 +282,7 @@ VOID WeRemoveWindowNode( PhRemoveEntryHashtable(Context->NodeHashtable, &WindowNode); - if ((index = PhFindItemList(Context->NodeList, WindowNode)) != -1) + if ((index = PhFindItemList(Context->NodeList, WindowNode)) != ULONG_MAX) PhRemoveItemList(Context->NodeList, index); WepDestroyWindowNode(WindowNode); From 59a63ae30bae2cff0b1dd5f389435c58d104162f Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 1 May 2019 23:30:27 +0200 Subject: [PATCH 1868/2058] Add original name guid for ETW handles --- ProcessHacker/include/phplug.h | 2 +- phlib/hndlinfo.c | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/ProcessHacker/include/phplug.h b/ProcessHacker/include/phplug.h index 86cc825dddf0..b3d43a3fa010 100644 --- a/ProcessHacker/include/phplug.h +++ b/ProcessHacker/include/phplug.h @@ -399,7 +399,7 @@ typedef PPH_OPTIONS_SECTION (NTAPI *PPH_OPTIONS_CREATE_SECTION)( _In_ PVOID Instance, _In_ PWSTR Template, _In_ DLGPROC DialogProc, - _In_ PVOID Parameter + _In_opt_ PVOID Parameter ); typedef PPH_OPTIONS_SECTION (NTAPI *PPH_OPTIONS_FIND_SECTION)( diff --git a/phlib/hndlinfo.c b/phlib/hndlinfo.c index 92882ff06d62..8a5267ecf901 100644 --- a/phlib/hndlinfo.c +++ b/phlib/hndlinfo.c @@ -390,6 +390,32 @@ NTSTATUS PhpGetObjectName( return status; } +NTSTATUS PhpGetEtwObjectName( + _In_ HANDLE ProcessHandle, + _In_ HANDLE Handle, + _Out_ PPH_STRING *ObjectName + ) +{ + NTSTATUS status; + ETWREG_BASIC_INFORMATION basicInfo; + + status = KphQueryInformationObject( + ProcessHandle, + Handle, + KphObjectEtwRegBasicInformation, + &basicInfo, + sizeof(ETWREG_BASIC_INFORMATION), + NULL + ); + + if (NT_SUCCESS(status)) + { + *ObjectName = PhFormatGuid(&basicInfo.Guid); + } + + return status; +} + PPH_STRING PhFormatNativeKeyName( _In_ PPH_STRING Name ) @@ -1343,6 +1369,14 @@ NTSTATUS PhGetHandleInformationEx( &objectName ); } + else if (PhEqualString2(typeName, L"EtwRegistration", TRUE) && KphIsConnected()) + { + status = PhpGetEtwObjectName( + ProcessHandle, + Handle, + &objectName + ); + } else { // Query the object normally. From 76ca85784aed2cd022fc20c991b40e1c12875884 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 2 May 2019 00:03:34 +0200 Subject: [PATCH 1869/2058] Add PhGetThreadTimes --- phlib/include/phnativeinl.h | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/phlib/include/phnativeinl.h b/phlib/include/phnativeinl.h index 87628c59eacb..efaa08246818 100644 --- a/phlib/include/phnativeinl.h +++ b/phlib/include/phnativeinl.h @@ -966,7 +966,7 @@ PhGetThreadBreakOnTermination( FORCEINLINE NTSTATUS PhSetThreadBreakOnTermination( - _In_ HANDLE ProcessHandle, + _In_ HANDLE ThreadHandle, _In_ BOOLEAN BreakOnTermination ) { @@ -975,13 +975,36 @@ PhSetThreadBreakOnTermination( breakOnTermination = BreakOnTermination ? 1 : 0; return NtSetInformationThread( - ProcessHandle, + ThreadHandle, ThreadBreakOnTermination, &breakOnTermination, sizeof(ULONG) ); } +/** + * Gets time information for a thread. + * + * \param ProcessHandle A handle to a thread. The handle must have + * THREAD_QUERY_LIMITED_INFORMATION access. + * \param Times A variable which receives the information. + */ +FORCEINLINE +NTSTATUS +PhGetThreadTimes( + _In_ HANDLE ThreadHandle, + _Out_ PKERNEL_USER_TIMES Times + ) +{ + return NtQueryInformationThread( + ThreadHandle, + ThreadTimes, + Times, + sizeof(KERNEL_USER_TIMES), + NULL + ); +} + /** * Sets a thread's affinity mask. * From 4c6d4dec251d43e54a69b72847704b5c645e77bf Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 2 May 2019 00:04:53 +0200 Subject: [PATCH 1870/2058] Add thread properties to handle window --- ProcessHacker/hndlprp.c | 177 +++++++++++++++++++++++++++++++++++----- 1 file changed, 155 insertions(+), 22 deletions(-) diff --git a/ProcessHacker/hndlprp.c b/ProcessHacker/hndlprp.c index 4705b90383c7..379312d6dfb4 100644 --- a/ProcessHacker/hndlprp.c +++ b/ProcessHacker/hndlprp.c @@ -43,7 +43,7 @@ typedef enum _PHP_HANDLE_GENERAL_CATEGORY PH_HANDLE_GENERAL_CATEGORY_FILE, PH_HANDLE_GENERAL_CATEGORY_SECTION, PH_HANDLE_GENERAL_CATEGORY_MUTANT, - PH_HANDLE_GENERAL_CATEGORY_PROCESS, + PH_HANDLE_GENERAL_CATEGORY_PROCESSTHREAD, PH_HANDLE_GENERAL_CATEGORY_MAXIMUM } PHP_HANDLE_GENERAL_CATEGORY; @@ -77,10 +77,10 @@ typedef enum _PHP_HANDLE_GENERAL_INDEX PH_HANDLE_GENERAL_INDEX_MUTANTABANDONED, PH_HANDLE_GENERAL_INDEX_MUTANTOWNER, - PH_HANDLE_GENERAL_INDEX_PROCESSNAME, - PH_HANDLE_GENERAL_INDEX_PROCESSCREATETIME, - PH_HANDLE_GENERAL_INDEX_PROCESSEXITTIME, - PH_HANDLE_GENERAL_INDEX_PROCESSEXITCODE, + PH_HANDLE_GENERAL_INDEX_PROCESSTHREADNAME, + PH_HANDLE_GENERAL_INDEX_PROCESSTHREADCREATETIME, + PH_HANDLE_GENERAL_INDEX_PROCESSTHREADEXITTIME, + PH_HANDLE_GENERAL_INDEX_PROCESSTHREADEXITCODE, PH_HANDLE_GENERAL_INDEX_MAXIMUM } PHP_PROCESS_STATISTICS_INDEX; @@ -470,33 +470,66 @@ VOID PhpUpdateHandleGeneralListViewGroups( } else if (PhEqualStringRef2(&Context->HandleItem->TypeName->sr, L"Process", TRUE)) { - PhAddListViewGroup(Context->ListViewHandle, PH_HANDLE_GENERAL_CATEGORY_PROCESS, L"Process information"); + PhAddListViewGroup(Context->ListViewHandle, PH_HANDLE_GENERAL_CATEGORY_PROCESSTHREAD, L"Process information"); - Context->ListViewRowCache[PH_HANDLE_GENERAL_INDEX_PROCESSNAME] = PhAddListViewGroupItem( + Context->ListViewRowCache[PH_HANDLE_GENERAL_INDEX_PROCESSTHREADNAME] = PhAddListViewGroupItem( Context->ListViewHandle, - PH_HANDLE_GENERAL_CATEGORY_PROCESS, - PH_HANDLE_GENERAL_INDEX_PROCESSNAME, + PH_HANDLE_GENERAL_CATEGORY_PROCESSTHREAD, + PH_HANDLE_GENERAL_INDEX_PROCESSTHREADNAME, L"Name", NULL ); - Context->ListViewRowCache[PH_HANDLE_GENERAL_INDEX_PROCESSCREATETIME] = PhAddListViewGroupItem( + Context->ListViewRowCache[PH_HANDLE_GENERAL_INDEX_PROCESSTHREADCREATETIME] = PhAddListViewGroupItem( Context->ListViewHandle, - PH_HANDLE_GENERAL_CATEGORY_PROCESS, - PH_HANDLE_GENERAL_INDEX_PROCESSCREATETIME, + PH_HANDLE_GENERAL_CATEGORY_PROCESSTHREAD, + PH_HANDLE_GENERAL_INDEX_PROCESSTHREADCREATETIME, L"Created", NULL ); - Context->ListViewRowCache[PH_HANDLE_GENERAL_INDEX_PROCESSEXITTIME] = PhAddListViewGroupItem( + Context->ListViewRowCache[PH_HANDLE_GENERAL_INDEX_PROCESSTHREADEXITTIME] = PhAddListViewGroupItem( Context->ListViewHandle, - PH_HANDLE_GENERAL_CATEGORY_PROCESS, - PH_HANDLE_GENERAL_INDEX_PROCESSEXITTIME, + PH_HANDLE_GENERAL_CATEGORY_PROCESSTHREAD, + PH_HANDLE_GENERAL_INDEX_PROCESSTHREADEXITTIME, L"Exited", NULL ); - Context->ListViewRowCache[PH_HANDLE_GENERAL_INDEX_PROCESSEXITCODE] = PhAddListViewGroupItem( + Context->ListViewRowCache[PH_HANDLE_GENERAL_INDEX_PROCESSTHREADEXITCODE] = PhAddListViewGroupItem( Context->ListViewHandle, - PH_HANDLE_GENERAL_CATEGORY_PROCESS, - PH_HANDLE_GENERAL_INDEX_PROCESSEXITCODE, + PH_HANDLE_GENERAL_CATEGORY_PROCESSTHREAD, + PH_HANDLE_GENERAL_INDEX_PROCESSTHREADEXITCODE, + L"Exit status", + NULL + ); + } + else if (PhEqualStringRef2(&Context->HandleItem->TypeName->sr, L"Thread", TRUE)) + { + PhAddListViewGroup(Context->ListViewHandle, PH_HANDLE_GENERAL_CATEGORY_PROCESSTHREAD, L"Thread information"); + + Context->ListViewRowCache[PH_HANDLE_GENERAL_INDEX_PROCESSTHREADNAME] = PhAddListViewGroupItem( + Context->ListViewHandle, + PH_HANDLE_GENERAL_CATEGORY_PROCESSTHREAD, + PH_HANDLE_GENERAL_INDEX_PROCESSTHREADNAME, + L"Name", + NULL + ); + Context->ListViewRowCache[PH_HANDLE_GENERAL_INDEX_PROCESSTHREADCREATETIME] = PhAddListViewGroupItem( + Context->ListViewHandle, + PH_HANDLE_GENERAL_CATEGORY_PROCESSTHREAD, + PH_HANDLE_GENERAL_INDEX_PROCESSTHREADCREATETIME, + L"Created", + NULL + ); + Context->ListViewRowCache[PH_HANDLE_GENERAL_INDEX_PROCESSTHREADEXITTIME] = PhAddListViewGroupItem( + Context->ListViewHandle, + PH_HANDLE_GENERAL_CATEGORY_PROCESSTHREAD, + PH_HANDLE_GENERAL_INDEX_PROCESSTHREADEXITTIME, + L"Exited", + NULL + ); + Context->ListViewRowCache[PH_HANDLE_GENERAL_INDEX_PROCESSTHREADEXITCODE] = PhAddListViewGroupItem( + Context->ListViewHandle, + PH_HANDLE_GENERAL_CATEGORY_PROCESSTHREAD, + PH_HANDLE_GENERAL_INDEX_PROCESSTHREADEXITCODE, L"Exit status", NULL ); @@ -996,7 +1029,7 @@ VOID PhpUpdateHandleGeneral( if (NT_SUCCESS(PhGetProcessImageFileName(dupHandle, &fileName))) { PhMoveReference(&fileName, PhGetFileName(fileName)); - PhSetListViewSubItem(Context->ListViewHandle, Context->ListViewRowCache[PH_HANDLE_GENERAL_INDEX_PROCESSNAME], 1, PhGetStringOrEmpty(fileName)); + PhSetListViewSubItem(Context->ListViewHandle, Context->ListViewRowCache[PH_HANDLE_GENERAL_INDEX_PROCESSTHREADNAME], 1, PhGetStringOrEmpty(fileName)); PhDereferenceObject(fileName); } @@ -1010,12 +1043,112 @@ VOID PhpUpdateHandleGeneral( SYSTEMTIME time; PhLargeIntegerToLocalSystemTime(&time, ×.CreateTime); - PhSetListViewSubItem(Context->ListViewHandle, Context->ListViewRowCache[PH_HANDLE_GENERAL_INDEX_PROCESSCREATETIME], 1, PhaFormatDateTime(&time)->Buffer); + PhSetListViewSubItem(Context->ListViewHandle, Context->ListViewRowCache[PH_HANDLE_GENERAL_INDEX_PROCESSTHREADCREATETIME], 1, PhaFormatDateTime(&time)->Buffer); + + if (exitStatus != STATUS_PENDING) + { + PhLargeIntegerToLocalSystemTime(&time, ×.ExitTime); + PhSetListViewSubItem(Context->ListViewHandle, Context->ListViewRowCache[PH_HANDLE_GENERAL_INDEX_PROCESSTHREADEXITTIME], 1, PhaFormatDateTime(&time)->Buffer); + } + } + + if (exitStatus != STATUS_PENDING) + { + PPH_STRING status; + PPH_STRING exitcode; + + status = PhGetStatusMessage(exitStatus, 0); + exitcode = PhFormatString( + L"0x%x (%s)", + exitStatus, + status->Buffer + ); + + PhSetListViewSubItem( + Context->ListViewHandle, + Context->ListViewRowCache[PH_HANDLE_GENERAL_INDEX_PROCESSTHREADEXITCODE], + 1, + PhGetStringOrEmpty(exitcode) + ); + + PhDereferenceObject(exitcode); + PhDereferenceObject(status); + } + + NtClose(dupHandle); + } + } + else if (PhEqualString2(Context->HandleItem->TypeName, L"Thread", TRUE)) + { + NTSTATUS status; + HANDLE processHandle; + HANDLE dupHandle; + + if (NT_SUCCESS(status = PhOpenProcess( + &processHandle, + PROCESS_DUP_HANDLE, + Context->ProcessId + ))) + { + status = NtDuplicateObject( + processHandle, + Context->HandleItem->Handle, + NtCurrentProcess(), + &dupHandle, + THREAD_QUERY_LIMITED_INFORMATION, + 0, + 0 + ); + + NtClose(processHandle); + } + + if (NT_SUCCESS(status)) + { + NTSTATUS exitStatus = STATUS_PENDING; + THREAD_BASIC_INFORMATION basicInfo; + KERNEL_USER_TIMES times; + PPH_STRING name; + + if (NT_SUCCESS(PhGetThreadName(dupHandle, &name))) + { + PhSetListViewSubItem(Context->ListViewHandle, Context->ListViewRowCache[PH_HANDLE_GENERAL_INDEX_PROCESSTHREADNAME], 1, PhGetStringOrEmpty(name)); + PhDereferenceObject(name); + } + + + if (NT_SUCCESS(PhGetThreadBasicInformation(dupHandle, &basicInfo))) + { + exitStatus = basicInfo.ExitStatus; + + //if (NT_SUCCESS(PhOpenProcess( + // &processHandle, + // PROCESS_QUERY_LIMITED_INFORMATION, + // basicInfo.ClientId.UniqueProcess + // ))) + //{ + // if (NT_SUCCESS(PhGetProcessImageFileName(processHandle, &fileName))) + // { + // PhMoveReference(&fileName, PhGetFileName(fileName)); + // PhSetListViewSubItem(Context->ListViewHandle, Context->ListViewRowCache[PH_HANDLE_GENERAL_INDEX_PROCESSTHREADNAME], 1, PhGetStringOrEmpty(fileName)); + // PhDereferenceObject(fileName); + // } + // + // NtClose(processHandle); + //} + } + + if (NT_SUCCESS(PhGetThreadTimes(dupHandle, ×))) + { + SYSTEMTIME time; + + PhLargeIntegerToLocalSystemTime(&time, ×.CreateTime); + PhSetListViewSubItem(Context->ListViewHandle, Context->ListViewRowCache[PH_HANDLE_GENERAL_INDEX_PROCESSTHREADCREATETIME], 1, PhaFormatDateTime(&time)->Buffer); if (exitStatus != STATUS_PENDING) { PhLargeIntegerToLocalSystemTime(&time, ×.ExitTime); - PhSetListViewSubItem(Context->ListViewHandle, Context->ListViewRowCache[PH_HANDLE_GENERAL_INDEX_PROCESSEXITTIME], 1, PhaFormatDateTime(&time)->Buffer); + PhSetListViewSubItem(Context->ListViewHandle, Context->ListViewRowCache[PH_HANDLE_GENERAL_INDEX_PROCESSTHREADEXITTIME], 1, PhaFormatDateTime(&time)->Buffer); } } @@ -1033,7 +1166,7 @@ VOID PhpUpdateHandleGeneral( PhSetListViewSubItem( Context->ListViewHandle, - Context->ListViewRowCache[PH_HANDLE_GENERAL_INDEX_PROCESSEXITCODE], + Context->ListViewRowCache[PH_HANDLE_GENERAL_INDEX_PROCESSTHREADEXITCODE], 1, PhGetStringOrEmpty(exitcode) ); From e28971b52e080ab872e3b48ce0be0b5b4e1b7d4c Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 2 May 2019 01:34:31 +0200 Subject: [PATCH 1871/2058] ExtendedTools: Fix commit 04654584 (Fixes disk tab GDI issues) --- plugins/ExtendedTools/disktab.c | 2 +- plugins/ExtendedTools/etwdisk.c | 63 +++++++++++--------- plugins/ExtendedTools/exttools.h | 40 ++----------- plugins/ExtendedTools/main.c | 10 +--- plugins/ExtendedTools/procicon.c | 99 -------------------------------- 5 files changed, 44 insertions(+), 170 deletions(-) delete mode 100644 plugins/ExtendedTools/procicon.c diff --git a/plugins/ExtendedTools/disktab.c b/plugins/ExtendedTools/disktab.c index ff2c4b81748f..0be7c927681b 100644 --- a/plugins/ExtendedTools/disktab.c +++ b/plugins/ExtendedTools/disktab.c @@ -560,7 +560,7 @@ BOOLEAN NTAPI EtpDiskTreeNewCallback( if (node->DiskItem->ProcessIcon) { - getNodeIcon->Icon = node->DiskItem->ProcessIcon->Icon; + getNodeIcon->Icon = node->DiskItem->ProcessIcon; } else { diff --git a/plugins/ExtendedTools/etwdisk.c b/plugins/ExtendedTools/etwdisk.c index 4023ddb74768..2e38901e9368 100644 --- a/plugins/ExtendedTools/etwdisk.c +++ b/plugins/ExtendedTools/etwdisk.c @@ -124,8 +124,11 @@ VOID NTAPI EtpDiskItemDeleteProcedure( if (diskItem->FileName) PhDereferenceObject(diskItem->FileName); if (diskItem->FileNameWin32) PhDereferenceObject(diskItem->FileNameWin32); if (diskItem->ProcessName) PhDereferenceObject(diskItem->ProcessName); - if (diskItem->ProcessIcon) EtProcIconDereferenceProcessIcon(diskItem->ProcessIcon); if (diskItem->ProcessRecord) PhDereferenceProcessRecord(diskItem->ProcessRecord); + + // NOTE: Dereferencing the ProcessItem will destroy the DiskItem->ProcessIcon handle. + if (diskItem->ProcessItem) + PhDereferenceObject(diskItem->ProcessItem); } BOOLEAN NTAPI EtpDiskHashtableEqualFunction( @@ -302,12 +305,18 @@ VOID EtpProcessDiskPacket( if (processItem = PhReferenceProcessItem(diskItem->ProcessId)) { + PhSetReference(&diskItem->ProcessItem, processItem); PhSetReference(&diskItem->ProcessName, processItem->ProcessName); - diskItem->ProcessIcon = EtProcIconReferenceSmallProcessIcon(EtGetProcessBlock(processItem)); diskItem->ProcessRecord = processItem->Record; PhReferenceProcessRecord(diskItem->ProcessRecord); - PhDereferenceObject(processItem); + if (PhTestEvent(&processItem->Stage1Event)) + { + diskItem->ProcessIcon = processItem->SmallIcon; + diskItem->ProcessIconValid = TRUE; + } + + // NOTE: We dereference processItem in EtpDiskItemDeleteProcedure. (dmex) } // Add the disk item to the age list. @@ -491,33 +500,33 @@ VOID NTAPI EtpDiskProcessesUpdatedCallback( if (diskItem->AddTime != runCount) { BOOLEAN modified = FALSE; - PPH_PROCESS_ITEM processItem; - if (!diskItem->ProcessName || !diskItem->ProcessIcon || !diskItem->ProcessRecord) + if (!diskItem->ProcessItem) + { + diskItem->ProcessItem = PhReferenceProcessItem(diskItem->ProcessId); + // NOTE: We dereference processItem in EtpDiskItemDeleteProcedure. (dmex) + } + + if (diskItem->ProcessItem) { - if (processItem = PhReferenceProcessItem(diskItem->ProcessId)) + if (!diskItem->ProcessName) + { + PhSetReference(&diskItem->ProcessName, diskItem->ProcessItem->ProcessName); + modified = TRUE; + } + + if (!diskItem->ProcessIconValid && PhTestEvent(&diskItem->ProcessItem->Stage1Event)) + { + diskItem->ProcessIcon = diskItem->ProcessItem->SmallIcon; + diskItem->ProcessIconValid = TRUE; + modified = TRUE; + } + + if (!diskItem->ProcessRecord) { - if (!diskItem->ProcessName) - { - PhSetReference(&diskItem->ProcessName, processItem->ProcessName); - modified = TRUE; - } - - if (!diskItem->ProcessIcon) - { - diskItem->ProcessIcon = EtProcIconReferenceSmallProcessIcon(EtGetProcessBlock(processItem)); - - if (diskItem->ProcessIcon) - modified = TRUE; - } - - if (!diskItem->ProcessRecord) - { - diskItem->ProcessRecord = processItem->Record; - PhReferenceProcessRecord(diskItem->ProcessRecord); - } - - PhDereferenceObject(processItem); + PhReferenceProcessRecord(diskItem->ProcessRecord); + diskItem->ProcessRecord = diskItem->ProcessItem->Record; + modified = TRUE; } } diff --git a/plugins/ExtendedTools/exttools.h b/plugins/ExtendedTools/exttools.h index 9654f507d8be..4228fbf4be01 100644 --- a/plugins/ExtendedTools/exttools.h +++ b/plugins/ExtendedTools/exttools.h @@ -72,15 +72,6 @@ NTSTATUS CallGetProcessUnloadedDlls( _Out_ PPH_STRING *UnloadedDlls ); -// Process icon - -typedef struct _ET_PROCESS_ICON -{ - LONG RefCount; - HICON Icon; - PPH_PROCESS_ITEM ProcessItem; -} ET_PROCESS_ICON, *PET_PROCESS_ICON; - // Disk item #define HISTORY_SIZE 60 @@ -94,9 +85,12 @@ typedef struct _ET_DISK_ITEM HANDLE ProcessId; PPH_STRING FileName; PPH_STRING FileNameWin32; - PPH_STRING ProcessName; - PET_PROCESS_ICON ProcessIcon; + + PPH_PROCESS_ITEM ProcessItem; + HICON ProcessIcon; + BOOLEAN ProcessIconValid; + PPH_PROCESS_RECORD ProcessRecord; ULONG IoPriority; @@ -251,8 +245,6 @@ typedef struct _ET_PROCESS_BLOCK PH_QUEUED_LOCK TextCacheLock; PPH_STRING TextCache[ETPRTNC_MAXIMUM + 1]; BOOLEAN TextCacheValid[ETPRTNC_MAXIMUM + 1]; - - PET_PROCESS_ICON SmallProcessIcon; } ET_PROCESS_BLOCK, *PET_PROCESS_BLOCK; typedef struct _ET_NETWORK_BLOCK @@ -366,28 +358,6 @@ PPH_STRING EtFileObjectToFileName( _In_ PVOID FileObject ); -// procicon - -PET_PROCESS_ICON EtProcIconCreateProcessIcon( - _In_ PPH_PROCESS_ITEM ProcessItem - ); - -VOID EtProcIconReferenceProcessIcon( - _Inout_ PET_PROCESS_ICON ProcessIcon - ); - -VOID EtProcIconDereferenceProcessIcon( - _Inout_ PET_PROCESS_ICON ProcessIcon - ); - -PET_PROCESS_ICON EtProcIconReferenceSmallProcessIcon( - _Inout_ PET_PROCESS_BLOCK Block - ); - -VOID EtProcIconNotifyProcessDelete( - _Inout_ PET_PROCESS_BLOCK Block - ); - // etwprprp VOID EtProcessEtwPropertiesInitializing( diff --git a/plugins/ExtendedTools/main.c b/plugins/ExtendedTools/main.c index 4d28be0d21e5..92746e219d6a 100644 --- a/plugins/ExtendedTools/main.c +++ b/plugins/ExtendedTools/main.c @@ -424,11 +424,7 @@ VOID EtDeleteProcessBlock( _In_ PET_PROCESS_BLOCK Block ) { - ULONG i; - - EtProcIconNotifyProcessDelete(Block); - - for (i = 1; i <= ETPRTNC_MAXIMUM; i++) + for (ULONG i = 1; i <= ETPRTNC_MAXIMUM; i++) { PhClearReference(&Block->TextCache[i]); } @@ -451,9 +447,7 @@ VOID EtDeleteNetworkBlock( _In_ PET_NETWORK_BLOCK Block ) { - ULONG i; - - for (i = 1; i <= ETNETNC_MAXIMUM; i++) + for (ULONG i = 1; i <= ETNETNC_MAXIMUM; i++) { PhClearReference(&Block->TextCache[i]); } diff --git a/plugins/ExtendedTools/procicon.c b/plugins/ExtendedTools/procicon.c deleted file mode 100644 index 75fe043ad269..000000000000 --- a/plugins/ExtendedTools/procicon.c +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Process Hacker Extended Tools - - * process icon duplication - * - * Copyright (C) 2011 wj32 - * Copyright (C) 2019 dmex - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -#include "exttools.h" - -PET_PROCESS_ICON EtProcIconCreateProcessIcon( - _In_ PPH_PROCESS_ITEM ProcessItem - ) -{ - PET_PROCESS_ICON processIcon; - - processIcon = PhAllocate(sizeof(ET_PROCESS_ICON)); - processIcon->RefCount = 1; - processIcon->Icon = ProcessItem->SmallIcon; - - PhSetReference(&processIcon->ProcessItem, ProcessItem); - - return processIcon; -} - -VOID EtProcIconReferenceProcessIcon( - _Inout_ PET_PROCESS_ICON ProcessIcon - ) -{ - _InterlockedIncrement(&ProcessIcon->RefCount); -} - -VOID EtProcIconDereferenceProcessIcon( - _Inout_ PET_PROCESS_ICON ProcessIcon - ) -{ - if (_InterlockedDecrement(&ProcessIcon->RefCount) == 0) - { - PhDereferenceObject(ProcessIcon->ProcessItem); - - PhFree(ProcessIcon); - } -} - -PET_PROCESS_ICON EtProcIconReferenceSmallProcessIcon( - _Inout_ PET_PROCESS_BLOCK Block - ) -{ - PET_PROCESS_ICON smallProcessIcon; - - smallProcessIcon = Block->SmallProcessIcon; - - if (!smallProcessIcon && PhTestEvent(&Block->ProcessItem->Stage1Event) && Block->ProcessItem->SmallIcon) - { - smallProcessIcon = EtProcIconCreateProcessIcon(Block->ProcessItem); - - if (_InterlockedCompareExchangePointer( - &Block->SmallProcessIcon, - smallProcessIcon, - NULL - ) != NULL) - { - EtProcIconDereferenceProcessIcon(smallProcessIcon); - smallProcessIcon = Block->SmallProcessIcon; - } - } - - if (smallProcessIcon) - { - EtProcIconReferenceProcessIcon(smallProcessIcon); - } - - return smallProcessIcon; -} - -VOID EtProcIconNotifyProcessDelete( - _Inout_ PET_PROCESS_BLOCK Block - ) -{ - if (Block->SmallProcessIcon) - { - EtProcIconDereferenceProcessIcon(Block->SmallProcessIcon); - } -} From d38f7bbcdc1e3249e16ccfbbc8cf4489c30a8e66 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 2 May 2019 01:35:41 +0200 Subject: [PATCH 1872/2058] Improve network tab process icon error checking --- ProcessHacker/netprv.c | 37 +++++++++++++++++-------------------- 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/ProcessHacker/netprv.c b/ProcessHacker/netprv.c index 836ee246ecfe..1ff0f5a1002f 100644 --- a/ProcessHacker/netprv.c +++ b/ProcessHacker/netprv.c @@ -733,8 +733,8 @@ VOID PhNetworkProviderUpdate( // Get process information. if (processItem = PhReferenceProcessItem(networkItem->ProcessId)) { - networkItem->ProcessItem = processItem; - networkItem->ProcessName = PhReferenceObject(processItem->ProcessName); + PhSetReference(&networkItem->ProcessItem, processItem); + PhSetReference(&networkItem->ProcessName, processItem->ProcessName); networkItem->SubsystemProcess = !!processItem->IsSubsystemProcess; PhpUpdateNetworkItemOwner(networkItem, processItem); @@ -796,29 +796,26 @@ VOID PhNetworkProviderUpdate( modified = TRUE; } - if (!networkItem->ProcessIconValid) + if (!networkItem->ProcessItem) { - if (!networkItem->ProcessItem) + networkItem->ProcessItem = PhReferenceProcessItem(networkItem->ProcessId); + // NOTE: We dereference processItem in PhpNetworkItemDeleteProcedure. (dmex) + } + + if (networkItem->ProcessItem) + { + if (!networkItem->ProcessName) { - networkItem->ProcessItem = PhReferenceProcessItem(networkItem->ProcessId); - // NOTE: We dereference processItem in PhpNetworkItemDeleteProcedure. (dmex) + networkItem->ProcessName = PhReferenceObject(networkItem->ProcessItem->ProcessName); + PhpUpdateNetworkItemOwner(networkItem, networkItem->ProcessItem); + modified = TRUE; } - if (networkItem->ProcessItem) + if (!networkItem->ProcessIconValid && PhTestEvent(&networkItem->ProcessItem->Stage1Event)) { - if (!networkItem->ProcessName) - { - networkItem->ProcessName = PhReferenceObject(networkItem->ProcessItem->ProcessName); - PhpUpdateNetworkItemOwner(networkItem, networkItem->ProcessItem); - modified = TRUE; - } - - if (!networkItem->ProcessIconValid && PhTestEvent(&networkItem->ProcessItem->Stage1Event)) - { - networkItem->ProcessIcon = networkItem->ProcessItem->SmallIcon; - networkItem->ProcessIconValid = TRUE; - modified = TRUE; - } + networkItem->ProcessIcon = networkItem->ProcessItem->SmallIcon; + networkItem->ProcessIconValid = TRUE; + modified = TRUE; } } From ecd121ca22b4b38c97d64a84cbc209c8f554447d Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 2 May 2019 01:44:55 +0200 Subject: [PATCH 1873/2058] ExtendedTools: Remove deleted file from solution --- plugins/ExtendedTools/ExtendedTools.vcxproj | 1 - plugins/ExtendedTools/ExtendedTools.vcxproj.filters | 3 --- 2 files changed, 4 deletions(-) diff --git a/plugins/ExtendedTools/ExtendedTools.vcxproj b/plugins/ExtendedTools/ExtendedTools.vcxproj index 72d6713a4085..1a92f5ef1f1f 100644 --- a/plugins/ExtendedTools/ExtendedTools.vcxproj +++ b/plugins/ExtendedTools/ExtendedTools.vcxproj @@ -87,7 +87,6 @@ - diff --git a/plugins/ExtendedTools/ExtendedTools.vcxproj.filters b/plugins/ExtendedTools/ExtendedTools.vcxproj.filters index 346bc9a0b5c8..8f88f9af3cc5 100644 --- a/plugins/ExtendedTools/ExtendedTools.vcxproj.filters +++ b/plugins/ExtendedTools/ExtendedTools.vcxproj.filters @@ -60,9 +60,6 @@ Source Files - - Source Files - Source Files From ffe7d69f469dd0334368399f7b2e99dddb640cee Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 2 May 2019 02:26:31 +0200 Subject: [PATCH 1874/2058] Remove legacy event provider window messages --- ProcessHacker/include/mainwnd.h | 4 ---- ProcessHacker/mainwnd.c | 15 --------------- ProcessHacker/mwpgnet.c | 2 +- ProcessHacker/mwpgproc.c | 2 +- ProcessHacker/mwpgsrv.c | 2 +- 5 files changed, 3 insertions(+), 22 deletions(-) diff --git a/ProcessHacker/include/mainwnd.h b/ProcessHacker/include/mainwnd.h index 63766d28b4f4..00d00fc281f9 100644 --- a/ProcessHacker/include/mainwnd.h +++ b/ProcessHacker/include/mainwnd.h @@ -8,10 +8,6 @@ extern BOOLEAN PhMainWndExiting; #define WM_PH_ACTIVATE (WM_APP + 99) #define PH_ACTIVATE_REPLY 0x1119 -#define WM_PH_PROCESSES_UPDATED (WM_APP + 100) -#define WM_PH_SERVICES_UPDATED (WM_APP + 101) -#define WM_PH_NETWORK_ITEMS_UPDATED (WM_APP + 102) - // begin_phapppub #define WM_PH_SHOW_PROCESS_PROPERTIES (WM_APP + 120) #define WM_PH_DESTROY (WM_APP + 121) diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index 723298d6cde5..1b738be3b518 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -2160,21 +2160,6 @@ ULONG_PTR PhMwpOnUserMessage( PhMwpActivateWindow(!!PhGetIntegerSetting(L"IconTogglesVisibility")); } break; - case WM_PH_PROCESSES_UPDATED: - { - PhMwpOnProcessesUpdated((ULONG)WParam); - } - break; - case WM_PH_SERVICES_UPDATED: - { - PhMwpOnServicesUpdated((ULONG)WParam); - } - break; - case WM_PH_NETWORK_ITEMS_UPDATED: - { - PhMwpOnNetworkItemsUpdated((ULONG)WParam); - } - break; } return 0; diff --git a/ProcessHacker/mwpgnet.c b/ProcessHacker/mwpgnet.c index 6fdb0f2815ee..39b83291875c 100644 --- a/ProcessHacker/mwpgnet.c +++ b/ProcessHacker/mwpgnet.c @@ -365,7 +365,7 @@ VOID NTAPI PhMwpNetworkItemsUpdatedHandler( _In_opt_ PVOID Context ) { - PostMessage(PhMainWndHandle, WM_PH_NETWORK_ITEMS_UPDATED, PhGetRunIdProvider(&PhMwpNetworkProviderRegistration), 0); + ProcessHacker_Invoke(PhMainWndHandle, PhMwpOnNetworkItemsUpdated, PhGetRunIdProvider(&PhMwpNetworkProviderRegistration)); } VOID PhMwpOnNetworkItemsUpdated( diff --git a/ProcessHacker/mwpgproc.c b/ProcessHacker/mwpgproc.c index b4a400f8ca54..754ad713cb15 100644 --- a/ProcessHacker/mwpgproc.c +++ b/ProcessHacker/mwpgproc.c @@ -786,7 +786,7 @@ VOID NTAPI PhMwpProcessesUpdatedHandler( _In_opt_ PVOID Context ) { - PostMessage(PhMainWndHandle, WM_PH_PROCESSES_UPDATED, PhGetRunIdProvider(&PhMwpProcessProviderRegistration), 0); + ProcessHacker_Invoke(PhMainWndHandle, PhMwpOnProcessesUpdated, PhGetRunIdProvider(&PhMwpProcessProviderRegistration)); } VOID PhMwpOnProcessAdded( diff --git a/ProcessHacker/mwpgsrv.c b/ProcessHacker/mwpgsrv.c index be043cac2d5d..c7bce8c46e44 100644 --- a/ProcessHacker/mwpgsrv.c +++ b/ProcessHacker/mwpgsrv.c @@ -371,7 +371,7 @@ VOID NTAPI PhMwpServicesUpdatedHandler( _In_opt_ PVOID Context ) { - PostMessage(PhMainWndHandle, WM_PH_SERVICES_UPDATED, PhGetRunIdProvider(&PhMwpServiceProviderRegistration), 0); + ProcessHacker_Invoke(PhMainWndHandle, PhMwpOnServicesUpdated, PhGetRunIdProvider(&PhMwpServiceProviderRegistration)); } VOID PhMwpOnServiceAdded( From 3ee66cba7b98afd9e59384f23a3b4e6bd0327d71 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 2 May 2019 02:27:59 +0200 Subject: [PATCH 1875/2058] Add Provider Event Queue to PHSDK --- ProcessHacker/include/phuisup.h | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/ProcessHacker/include/phuisup.h b/ProcessHacker/include/phuisup.h index d1860f1f49fa..8b8c8d0a03e3 100644 --- a/ProcessHacker/include/phuisup.h +++ b/ProcessHacker/include/phuisup.h @@ -1,3 +1,25 @@ +/* + * Process Hacker - + * Provider Event Queue + * + * Copyright (C) 2009-2016 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + #ifndef PH_PHUISUP_H #define PH_PHUISUP_H @@ -96,6 +118,7 @@ FORCEINLINE VOID PhChangeShStateTn( } \ } while (0) +// begin_phapppub // Provider event queues typedef enum _PH_PROVIDER_EVENT_TYPE @@ -198,5 +221,6 @@ FORCEINLINE PPH_PROVIDER_EVENT PhFlushProviderEventQueue( return events; } +// end_phapppub #endif From 9c7d5ea5f91c87647f89bf2185a31a158a28429d Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 2 May 2019 02:50:25 +0200 Subject: [PATCH 1876/2058] ExtendedTools: Add Event Queue support to Disk tab (experimental) --- plugins/ExtendedTools/disktab.c | 130 ++++++++++++++++--------------- plugins/ExtendedTools/disktabp.h | 33 -------- plugins/ExtendedTools/etwdisk.c | 11 ++- plugins/ExtendedTools/exttools.h | 1 + 4 files changed, 72 insertions(+), 103 deletions(-) diff --git a/plugins/ExtendedTools/disktab.c b/plugins/ExtendedTools/disktab.c index 0be7c927681b..1e246c7f8d9d 100644 --- a/plugins/ExtendedTools/disktab.c +++ b/plugins/ExtendedTools/disktab.c @@ -3,6 +3,7 @@ * ETW disk monitoring * * Copyright (C) 2011-2015 wj32 + * Copyright (C) 2018-2019 dmex * * This file is part of Process Hacker. * @@ -25,20 +26,20 @@ #include #include "disktabp.h" -static PPH_MAIN_TAB_PAGE DiskPage; +static PPH_MAIN_TAB_PAGE DiskPage = NULL; static BOOLEAN DiskTreeNewCreated = FALSE; -static HWND DiskTreeNewHandle; -static ULONG DiskTreeNewSortColumn; -static PH_SORT_ORDER DiskTreeNewSortOrder; +static HWND DiskTreeNewHandle = NULL; +static ULONG DiskTreeNewSortColumn = 0; +static PH_SORT_ORDER DiskTreeNewSortOrder = NoSortOrder; -static PPH_HASHTABLE DiskNodeHashtable; // hashtable of all nodes -static PPH_LIST DiskNodeList; // list of all nodes +static PPH_HASHTABLE DiskNodeHashtable = NULL; // hashtable of all nodes +static PPH_LIST DiskNodeList = NULL; // list of all nodes +static PH_PROVIDER_EVENT_QUEUE EtpDiskEventQueue; static PH_CALLBACK_REGISTRATION DiskItemAddedRegistration; static PH_CALLBACK_REGISTRATION DiskItemModifiedRegistration; static PH_CALLBACK_REGISTRATION DiskItemRemovedRegistration; static PH_CALLBACK_REGISTRATION DiskItemsUpdatedRegistration; -static BOOLEAN DiskNeedsRedraw = FALSE; static PH_TN_FILTER_SUPPORT FilterSupport; static PTOOLSTATUS_INTERFACE ToolStatusInterface; @@ -135,6 +136,8 @@ BOOLEAN EtpDiskPageCallback( EtInitializeDiskTreeList(hwnd); + PhInitializeProviderEventQueue(&EtpDiskEventQueue, 100); + PhRegisterCallback( &EtDiskItemAddedEvent, EtpDiskItemAddedHandler, @@ -370,10 +373,32 @@ VOID EtUpdateDiskNode( { memset(DiskNode->TextCache, 0, sizeof(PH_STRINGREF) * ETDSTNC_MAXIMUM); + PhClearReference(&DiskNode->TooltipText); + PhInvalidateTreeNewNode(&DiskNode->Node, TN_CACHE_ICON); TreeNew_NodesStructured(DiskTreeNewHandle); } +VOID EtTickDiskNodes( + VOID + ) +{ + // Text invalidation + + for (ULONG i = 0; i < DiskNodeList->Count; i++) + { + PET_DISK_NODE node = DiskNodeList->Items[i]; + + // The name and file name never change, so we don't invalidate that. + memset(&node->TextCache[2], 0, sizeof(PH_STRINGREF) * (ETDSTNC_MAXIMUM - 2)); + + // Always get the newest tooltip text from the process tree. + PhClearReference(&node->TooltipText); + } + + InvalidateRect(DiskTreeNewHandle, NULL, FALSE); +} + #define SORT_FUNCTION(Column) EtpDiskTreeNewCompare##Column #define BEGIN_SORT_FUNCTION(Column) static int __cdecl EtpDiskTreeNewCompare##Column( \ @@ -972,7 +997,7 @@ VOID NTAPI EtpDiskItemAddedHandler( PET_DISK_ITEM diskItem = (PET_DISK_ITEM)Parameter; PhReferenceObject(diskItem); - ProcessHacker_Invoke(PhMainWndHandle, EtpOnDiskItemAdded, diskItem); + PhPushProviderEventQueue(&EtpDiskEventQueue, ProviderAddedEvent, Parameter, EtRunCount); } VOID NTAPI EtpDiskItemModifiedHandler( @@ -980,7 +1005,7 @@ VOID NTAPI EtpDiskItemModifiedHandler( _In_opt_ PVOID Context ) { - ProcessHacker_Invoke(PhMainWndHandle, EtpOnDiskItemModified, (PET_DISK_ITEM)Parameter); + PhPushProviderEventQueue(&EtpDiskEventQueue, ProviderModifiedEvent, Parameter, EtRunCount); } VOID NTAPI EtpDiskItemRemovedHandler( @@ -988,7 +1013,7 @@ VOID NTAPI EtpDiskItemRemovedHandler( _In_opt_ PVOID Context ) { - ProcessHacker_Invoke(PhMainWndHandle, EtpOnDiskItemRemoved, (PET_DISK_ITEM)Parameter); + PhPushProviderEventQueue(&EtpDiskEventQueue, ProviderRemovedEvent, Parameter, EtRunCount); } VOID NTAPI EtpDiskItemsUpdatedHandler( @@ -996,75 +1021,52 @@ VOID NTAPI EtpDiskItemsUpdatedHandler( _In_opt_ PVOID Context ) { - ProcessHacker_Invoke(PhMainWndHandle, EtpOnDiskItemsUpdated, NULL); + ProcessHacker_Invoke(PhMainWndHandle, EtpOnDiskItemsUpdated, ULongToPtr(EtRunCount)); } -VOID NTAPI EtpOnDiskItemAdded( - _In_ PVOID Parameter - ) -{ - PET_DISK_ITEM diskItem = Parameter; - PET_DISK_NODE diskNode; - - if (!DiskNeedsRedraw) - { - TreeNew_SetRedraw(DiskTreeNewHandle, FALSE); - DiskNeedsRedraw = TRUE; - } - - diskNode = EtAddDiskNode(diskItem); - PhDereferenceObject(diskItem); -} - -VOID NTAPI EtpOnDiskItemModified( +VOID NTAPI EtpOnDiskItemsUpdated( _In_ PVOID Parameter ) { - PET_DISK_ITEM diskItem = Parameter; - - EtUpdateDiskNode(EtFindDiskNode(diskItem)); -} + PPH_PROVIDER_EVENT events; + ULONG runId; + ULONG count; + ULONG i; -VOID NTAPI EtpOnDiskItemRemoved( - _In_ PVOID Parameter - ) -{ - PET_DISK_ITEM diskItem = Parameter; + runId = PtrToUlong(Parameter); + events = PhFlushProviderEventQueue(&EtpDiskEventQueue, runId, &count); - if (!DiskNeedsRedraw) + if (events) { TreeNew_SetRedraw(DiskTreeNewHandle, FALSE); - DiskNeedsRedraw = TRUE; - } - EtRemoveDiskNode(EtFindDiskNode(diskItem)); -} + for (i = 0; i < count; i++) + { + PH_PROVIDER_EVENT_TYPE type = PH_PROVIDER_EVENT_TYPE(events[i]); + PET_DISK_ITEM diskItem = PH_PROVIDER_EVENT_OBJECT(events[i]); -VOID NTAPI EtpOnDiskItemsUpdated( - _In_ PVOID Parameter - ) -{ - ULONG i; + switch (type) + { + case ProviderAddedEvent: + EtAddDiskNode(diskItem); + PhDereferenceObject(diskItem); + break; + case ProviderModifiedEvent: + EtUpdateDiskNode(EtFindDiskNode(diskItem)); + break; + case ProviderRemovedEvent: + EtRemoveDiskNode(EtFindDiskNode(diskItem)); + break; + } + } - if (DiskNeedsRedraw) - { - TreeNew_SetRedraw(DiskTreeNewHandle, TRUE); - DiskNeedsRedraw = FALSE; + PhFree(events); } - // Text invalidation - - for (i = 0; i < DiskNodeList->Count; i++) - { - PET_DISK_NODE node = DiskNodeList->Items[i]; + EtTickDiskNodes(); - // The name and file name never change, so we don't invalidate that. - memset(&node->TextCache[2], 0, sizeof(PH_STRINGREF) * (ETDSTNC_MAXIMUM - 2)); - // Always get the newest tooltip text from the process tree. - PhClearReference(&node->TooltipText); - } - - InvalidateRect(DiskTreeNewHandle, NULL, FALSE); + if (count != 0) + TreeNew_SetRedraw(DiskTreeNewHandle, TRUE); } VOID NTAPI EtpSearchChangedHandler( diff --git a/plugins/ExtendedTools/disktabp.h b/plugins/ExtendedTools/disktabp.h index 0a90f64716ef..72bd8b68c3e2 100644 --- a/plugins/ExtendedTools/disktabp.h +++ b/plugins/ExtendedTools/disktabp.h @@ -8,27 +8,6 @@ BOOLEAN EtpDiskPageCallback( _In_opt_ PVOID Parameter2 ); -VOID NTAPI EtpDiskTabSelectionChangedCallback( - _In_ PVOID Parameter1, - _In_ PVOID Parameter2, - _In_ PVOID Parameter3, - _In_ PVOID Context - ); - -VOID NTAPI EtpDiskTabSaveContentCallback( - _In_ PVOID Parameter1, - _In_ PVOID Parameter2, - _In_ PVOID Parameter3, - _In_ PVOID Context - ); - -VOID NTAPI EtpDiskTabFontChangedCallback( - _In_ PVOID Parameter1, - _In_ PVOID Parameter2, - _In_ PVOID Parameter3, - _In_ PVOID Context - ); - BOOLEAN EtpDiskNodeHashtableEqualFunction( _In_ PVOID Entry1, _In_ PVOID Entry2 @@ -131,18 +110,6 @@ VOID NTAPI EtpDiskItemsUpdatedHandler( _In_opt_ PVOID Context ); -VOID NTAPI EtpOnDiskItemAdded( - _In_ PVOID Parameter - ); - -VOID NTAPI EtpOnDiskItemModified( - _In_ PVOID Parameter - ); - -VOID NTAPI EtpOnDiskItemRemoved( - _In_ PVOID Parameter - ); - VOID NTAPI EtpOnDiskItemsUpdated( _In_ PVOID Parameter ); diff --git a/plugins/ExtendedTools/etwdisk.c b/plugins/ExtendedTools/etwdisk.c index 2e38901e9368..5f67f8fb465a 100644 --- a/plugins/ExtendedTools/etwdisk.c +++ b/plugins/ExtendedTools/etwdisk.c @@ -50,6 +50,7 @@ VOID NTAPI EtpDiskProcessesUpdatedCallback( ); BOOLEAN EtDiskEnabled = FALSE; +ULONG EtRunCount = 0; PPH_OBJECT_TYPE EtDiskItemType; PPH_HASHTABLE EtDiskHashtable; @@ -410,8 +411,6 @@ VOID NTAPI EtpDiskProcessesUpdatedCallback( _In_opt_ PVOID Context ) { - static ULONG runCount = 0; - PSLIST_ENTRY listEntry; PLIST_ENTRY ageListEntry; @@ -426,7 +425,7 @@ VOID NTAPI EtpDiskProcessesUpdatedCallback( packet = CONTAINING_RECORD(listEntry, ETP_DISK_PACKET, ListEntry); listEntry = listEntry->Next; - EtpProcessDiskPacket(packet, runCount); + EtpProcessDiskPacket(packet, EtRunCount); if (packet->FileName) PhDereferenceObject(packet->FileName); @@ -445,7 +444,7 @@ VOID NTAPI EtpDiskProcessesUpdatedCallback( diskItem = CONTAINING_RECORD(ageListEntry, ET_DISK_ITEM, AgeListEntry); ageListEntry = ageListEntry->Blink; - if (runCount - diskItem->FreshTime < HISTORY_SIZE) // must compare like this to avoid overflow/underflow problems + if (EtRunCount - diskItem->FreshTime < HISTORY_SIZE) // must compare like this to avoid overflow/underflow problems break; PhInvokeCallback(&EtDiskItemRemovedEvent, diskItem); @@ -497,7 +496,7 @@ VOID NTAPI EtpDiskProcessesUpdatedCallback( diskItem->ReadAverage = EtpCalculateAverage(diskItem->ReadHistory, HISTORY_SIZE, diskItem->HistoryPosition, diskItem->HistoryCount, HISTORY_SIZE); diskItem->WriteAverage = EtpCalculateAverage(diskItem->WriteHistory, HISTORY_SIZE, diskItem->HistoryPosition, diskItem->HistoryCount, HISTORY_SIZE); - if (diskItem->AddTime != runCount) + if (diskItem->AddTime != EtRunCount) { BOOLEAN modified = FALSE; @@ -541,5 +540,5 @@ VOID NTAPI EtpDiskProcessesUpdatedCallback( } PhInvokeCallback(&EtDiskItemsUpdatedEvent, NULL); - runCount++; + EtRunCount++; } diff --git a/plugins/ExtendedTools/exttools.h b/plugins/ExtendedTools/exttools.h index 4228fbf4be01..766fe873a789 100644 --- a/plugins/ExtendedTools/exttools.h +++ b/plugins/ExtendedTools/exttools.h @@ -334,6 +334,7 @@ VOID EtEtwStatisticsUninitialization( // etwdisk extern BOOLEAN EtDiskEnabled; +extern ULONG EtRunCount; extern PPH_OBJECT_TYPE EtDiskItemType; extern PH_CALLBACK EtDiskItemAddedEvent; From bc002f64a63737920631b8494128cd0631f773d6 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 3 May 2019 06:28:44 +0200 Subject: [PATCH 1877/2058] ExtendedTools: Fix regression from commit 9c7d5ea5 --- plugins/ExtendedTools/disktab.c | 10 ++++------ plugins/ExtendedTools/disktabp.h | 2 +- plugins/ExtendedTools/etwdisk.c | 7 +++---- 3 files changed, 8 insertions(+), 11 deletions(-) diff --git a/plugins/ExtendedTools/disktab.c b/plugins/ExtendedTools/disktab.c index 1e246c7f8d9d..fd5861ab1116 100644 --- a/plugins/ExtendedTools/disktab.c +++ b/plugins/ExtendedTools/disktab.c @@ -583,7 +583,7 @@ BOOLEAN NTAPI EtpDiskTreeNewCallback( node = (PET_DISK_NODE)getNodeIcon->Node; - if (node->DiskItem->ProcessIcon) + if (node->DiskItem->ProcessIconValid && node->DiskItem->ProcessIcon) { getNodeIcon->Icon = node->DiskItem->ProcessIcon; } @@ -1021,20 +1021,18 @@ VOID NTAPI EtpDiskItemsUpdatedHandler( _In_opt_ PVOID Context ) { - ProcessHacker_Invoke(PhMainWndHandle, EtpOnDiskItemsUpdated, ULongToPtr(EtRunCount)); + ProcessHacker_Invoke(PhMainWndHandle, EtpOnDiskItemsUpdated, EtRunCount); } VOID NTAPI EtpOnDiskItemsUpdated( - _In_ PVOID Parameter + _In_ ULONG RunId ) { PPH_PROVIDER_EVENT events; - ULONG runId; ULONG count; ULONG i; - runId = PtrToUlong(Parameter); - events = PhFlushProviderEventQueue(&EtpDiskEventQueue, runId, &count); + events = PhFlushProviderEventQueue(&EtpDiskEventQueue, RunId, &count); if (events) { diff --git a/plugins/ExtendedTools/disktabp.h b/plugins/ExtendedTools/disktabp.h index 72bd8b68c3e2..ea098610f797 100644 --- a/plugins/ExtendedTools/disktabp.h +++ b/plugins/ExtendedTools/disktabp.h @@ -111,7 +111,7 @@ VOID NTAPI EtpDiskItemsUpdatedHandler( ); VOID NTAPI EtpOnDiskItemsUpdated( - _In_ PVOID Parameter + _In_ ULONG RunId ); VOID NTAPI EtpSearchChangedHandler( diff --git a/plugins/ExtendedTools/etwdisk.c b/plugins/ExtendedTools/etwdisk.c index 5f67f8fb465a..e0d299b92d5f 100644 --- a/plugins/ExtendedTools/etwdisk.c +++ b/plugins/ExtendedTools/etwdisk.c @@ -128,8 +128,7 @@ VOID NTAPI EtpDiskItemDeleteProcedure( if (diskItem->ProcessRecord) PhDereferenceProcessRecord(diskItem->ProcessRecord); // NOTE: Dereferencing the ProcessItem will destroy the DiskItem->ProcessIcon handle. - if (diskItem->ProcessItem) - PhDereferenceObject(diskItem->ProcessItem); + if (diskItem->ProcessItem) PhDereferenceObject(diskItem->ProcessItem); } BOOLEAN NTAPI EtpDiskHashtableEqualFunction( @@ -306,12 +305,12 @@ VOID EtpProcessDiskPacket( if (processItem = PhReferenceProcessItem(diskItem->ProcessId)) { - PhSetReference(&diskItem->ProcessItem, processItem); + diskItem->ProcessItem = processItem; PhSetReference(&diskItem->ProcessName, processItem->ProcessName); diskItem->ProcessRecord = processItem->Record; PhReferenceProcessRecord(diskItem->ProcessRecord); - if (PhTestEvent(&processItem->Stage1Event)) + if (!diskItem->ProcessIconValid && PhTestEvent(&processItem->Stage1Event)) { diskItem->ProcessIcon = processItem->SmallIcon; diskItem->ProcessIconValid = TRUE; From 43ddcf042489823471cf753c4d7788ea69a3bc36 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 3 May 2019 06:29:16 +0200 Subject: [PATCH 1878/2058] Remove unused reference --- ProcessHacker/netlist.c | 2 -- ProcessHacker/netprv.c | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/ProcessHacker/netlist.c b/ProcessHacker/netlist.c index cce46d45770d..1ed8fa84a3e5 100644 --- a/ProcessHacker/netlist.c +++ b/ProcessHacker/netlist.c @@ -571,8 +571,6 @@ BOOLEAN NTAPI PhpNetworkTreeNewCallback( if (node->NetworkItem->ProcessIconValid && node->NetworkItem->ProcessIcon) { - // TODO: Check if the icon handle is actually valid, since the process item - // might get destroyed while the network node is still valid. getNodeIcon->Icon = node->NetworkItem->ProcessIcon; } else diff --git a/ProcessHacker/netprv.c b/ProcessHacker/netprv.c index 1ff0f5a1002f..b825d19564a1 100644 --- a/ProcessHacker/netprv.c +++ b/ProcessHacker/netprv.c @@ -733,7 +733,7 @@ VOID PhNetworkProviderUpdate( // Get process information. if (processItem = PhReferenceProcessItem(networkItem->ProcessId)) { - PhSetReference(&networkItem->ProcessItem, processItem); + networkItem->ProcessItem = processItem; PhSetReference(&networkItem->ProcessName, processItem->ProcessName); networkItem->SubsystemProcess = !!processItem->IsSubsystemProcess; PhpUpdateNetworkItemOwner(networkItem, processItem); From 71548afbcec94864962c8baf81be65c2303e700b Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 3 May 2019 06:29:41 +0200 Subject: [PATCH 1879/2058] Add PhGetThreadIsIoPending --- phlib/include/phnativeinl.h | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/phlib/include/phnativeinl.h b/phlib/include/phnativeinl.h index efaa08246818..b6a202157e06 100644 --- a/phlib/include/phnativeinl.h +++ b/phlib/include/phnativeinl.h @@ -982,6 +982,32 @@ PhSetThreadBreakOnTermination( ); } +FORCEINLINE +NTSTATUS +PhGetThreadIsIoPending( + _In_ HANDLE ThreadHandle, + _Out_ PBOOLEAN IsIoPending + ) +{ + NTSTATUS status; + ULONG isIoPending; + + status = NtQueryInformationThread( + ThreadHandle, + ThreadIsIoPending, + &isIoPending, + sizeof(ULONG), + NULL + ); + + if (NT_SUCCESS(status)) + { + *IsIoPending = !!isIoPending; + } + + return status; +} + /** * Gets time information for a thread. * From 30765e6bbffbfd4f4512e36d26ad678f6dee062f Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 3 May 2019 21:22:27 +0200 Subject: [PATCH 1880/2058] Fix regression querying token properties --- phlib/apiimport.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/phlib/apiimport.c b/phlib/apiimport.c index d701fac00136..afcbc9eab57a 100644 --- a/phlib/apiimport.c +++ b/phlib/apiimport.c @@ -3,6 +3,7 @@ * procedure import module * * Copyright (C) 2015 wj32 + * Copyright (C) 2019 dmex * * This file is part of Process Hacker. * @@ -36,7 +37,8 @@ PVOID PhpImportProcedure( if (*CacheValid) return *Cache; - module = PhGetLoaderEntryDllBase(ModuleName); + if (!(module = PhGetLoaderEntryDllBase(ModuleName))) + module = LoadLibrary(ModuleName); // HACK (dmex) if (!module) return NULL; From e0925a69dcc41c6f650c4e4f6da2a13a0cbee719 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 4 May 2019 09:12:50 +0200 Subject: [PATCH 1881/2058] ExtendedTools: Fix regression (reported by MarekKnapek) --- plugins/ExtendedTools/etwdisk.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/plugins/ExtendedTools/etwdisk.c b/plugins/ExtendedTools/etwdisk.c index e0d299b92d5f..0542374a13b3 100644 --- a/plugins/ExtendedTools/etwdisk.c +++ b/plugins/ExtendedTools/etwdisk.c @@ -307,8 +307,9 @@ VOID EtpProcessDiskPacket( { diskItem->ProcessItem = processItem; PhSetReference(&diskItem->ProcessName, processItem->ProcessName); + + PhReferenceProcessRecord(processItem->Record); diskItem->ProcessRecord = processItem->Record; - PhReferenceProcessRecord(diskItem->ProcessRecord); if (!diskItem->ProcessIconValid && PhTestEvent(&processItem->Stage1Event)) { @@ -522,7 +523,7 @@ VOID NTAPI EtpDiskProcessesUpdatedCallback( if (!diskItem->ProcessRecord) { - PhReferenceProcessRecord(diskItem->ProcessRecord); + PhReferenceProcessRecord(diskItem->ProcessItem->Record); diskItem->ProcessRecord = diskItem->ProcessItem->Record; modified = TRUE; } From 1f2b747edcc682b132945cb3e33f8ee0882e00f9 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 4 May 2019 09:13:18 +0200 Subject: [PATCH 1882/2058] ExtendedTools: Improve macro usage --- plugins/ExtendedTools/etwmon.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/plugins/ExtendedTools/etwmon.c b/plugins/ExtendedTools/etwmon.c index 8d26ee97149d..8e554667cbb0 100644 --- a/plugins/ExtendedTools/etwmon.c +++ b/plugins/ExtendedTools/etwmon.c @@ -215,7 +215,7 @@ VOID NTAPI EtpEtwEventCallback( _In_ PEVENT_RECORD EventRecord ) { - if (memcmp(&EventRecord->EventHeader.ProviderId, &DiskIoGuid_I, sizeof(GUID)) == 0) + if (IsEqualGUID(&EventRecord->EventHeader.ProviderId, &DiskIoGuid_I)) { // DiskIo @@ -263,7 +263,7 @@ VOID NTAPI EtpEtwEventCallback( EtDiskProcessDiskEvent(&diskEvent); } } - else if (memcmp(&EventRecord->EventHeader.ProviderId, &FileIoGuid_I, sizeof(GUID)) == 0) + else if (IsEqualGUID(&EventRecord->EventHeader.ProviderId, &FileIoGuid_I)) { // FileIo @@ -308,8 +308,8 @@ VOID NTAPI EtpEtwEventCallback( } } else if ( - memcmp(&EventRecord->EventHeader.ProviderId, &TcpIpGuid_I, sizeof(GUID)) == 0 || - memcmp(&EventRecord->EventHeader.ProviderId, &UdpIpGuid_I, sizeof(GUID)) == 0 + IsEqualGUID(&EventRecord->EventHeader.ProviderId, &TcpIpGuid_I) || + IsEqualGUID(&EventRecord->EventHeader.ProviderId, &UdpIpGuid_I) ) { // TcpIp/UdpIp @@ -339,7 +339,7 @@ VOID NTAPI EtpEtwEventCallback( break; } - if (memcmp(&EventRecord->EventHeader.ProviderId, &TcpIpGuid_I, sizeof(GUID)) == 0) + if (IsEqualGUID(&EventRecord->EventHeader.ProviderId, &TcpIpGuid_I)) networkEvent.ProtocolType |= PH_TCP_PROTOCOL_TYPE; else networkEvent.ProtocolType |= PH_UDP_PROTOCOL_TYPE; @@ -511,7 +511,7 @@ VOID NTAPI EtpRundownEtwEventCallback( // TODO: Find a way to call CloseTrace when the enumeration finishes so we can // stop the trace cleanly. - if (memcmp(&EventRecord->EventHeader.ProviderId, &FileIoGuid_I, sizeof(GUID)) == 0) + if (IsEqualGUID(&EventRecord->EventHeader.ProviderId, &FileIoGuid_I)) { // FileIo From b9cf9f73316bfaade5a92613d0e97f05025f1347 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 4 May 2019 10:10:59 +0200 Subject: [PATCH 1883/2058] Fix issue closing process properties window from the X on the taskbar thumbnail preview --- ProcessHacker/procprp.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/ProcessHacker/procprp.c b/ProcessHacker/procprp.c index c1e34fe27f28..cd6ac286aacf 100644 --- a/ProcessHacker/procprp.c +++ b/ProcessHacker/procprp.c @@ -259,6 +259,23 @@ LRESULT CALLBACK PhpPropSheetWndProc( PhFree(propSheetContext); } break; + case WM_SYSCOMMAND: + { + // Note: Clicking the X on the taskbar window thumbnail preview doens't close modeless property sheets + // when there are more than 1 window and the window doesn't have focus... The MFC, ATL and WTL libraries + // check if the propsheet is modeless and SendMessage WM_CLOSE and so we'll implement the same solution. (dmex) + switch (wParam & 0xFFF0) + { + case SC_CLOSE: + { + PostMessage(hwnd, WM_CLOSE, 0, 0); + //SetWindowLongPtr(hwnd, DWLP_MSGRESULT, TRUE); + //return TRUE; + } + break; + } + } + break; case WM_COMMAND: { switch (GET_WM_COMMAND_ID(wParam, lParam)) From dc6f581042a909b69a3bc7020eb087513b630944 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 4 May 2019 10:37:30 +0200 Subject: [PATCH 1884/2058] Update ntmmapi.h --- phnt/include/ntmmapi.h | 63 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/phnt/include/ntmmapi.h b/phnt/include/ntmmapi.h index 1fd3865a8213..97b91b0b48b2 100644 --- a/phnt/include/ntmmapi.h +++ b/phnt/include/ntmmapi.h @@ -931,4 +931,67 @@ NtFlushWriteBuffer( #endif +// Enclave support + +NTSYSAPI +NTSTATUS +NTAPI +NtCreateEnclave( + _In_ HANDLE ProcessHandle, + _Inout_ PVOID* BaseAddress, + _In_ ULONG_PTR ZeroBits, + _In_ SIZE_T Size, + _In_ SIZE_T InitialCommitment, + _In_ ULONG EnclaveType, + _In_reads_bytes_(EnclaveInformationLength) PVOID EnclaveInformation, + _In_ ULONG EnclaveInformationLength, + _Out_opt_ PULONG EnclaveError + ); + +NTSYSAPI +NTSTATUS +NTAPI +NtLoadEnclaveData( + _In_ HANDLE ProcessHandle, + _In_ PVOID BaseAddress, + _In_reads_bytes_(BufferSize) PVOID Buffer, + _In_ SIZE_T BufferSize, + _In_ ULONG Protect, + _In_reads_bytes_(PageInformationLength) PVOID PageInformation, + _In_ ULONG PageInformationLength, + _Out_opt_ PSIZE_T NumberOfBytesWritten, + _Out_opt_ PULONG EnclaveError + ); + +NTSYSAPI +NTSTATUS +NTAPI +NtInitializeEnclave( + _In_ HANDLE ProcessHandle, + _In_ PVOID BaseAddress, + _In_reads_bytes_(EnclaveInformationLength) PVOID EnclaveInformation, + _In_ ULONG EnclaveInformationLength, + _Out_opt_ PULONG EnclaveError + ); + +// rev +NTSYSAPI +NTSTATUS +NTAPI +NtTerminateEnclave( + _In_ PVOID BaseAddress, + _In_ BOOLEAN WaitForThread + ); + +// rev +NTSYSAPI +NTSTATUS +NTAPI +NtCallEnclave( + _In_ PENCLAVE_ROUTINE Routine, + _In_ PVOID Parameter, + _In_ BOOLEAN WaitForThread, + _Out_opt_ PVOID *ReturnValue + ); + #endif From c1579fcdfdfb8bcfc4bb053d73dd418b16e1f2b1 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 4 May 2019 13:23:04 +0200 Subject: [PATCH 1885/2058] Fix filename regression on Windows 7 --- phlib/native.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phlib/native.c b/phlib/native.c index 43fb48b494ce..f38405be158c 100644 --- a/phlib/native.c +++ b/phlib/native.c @@ -6115,7 +6115,7 @@ PPH_STRING PhGetFileName( // If the file name starts with "\Windows", prepend the system drive. if (PhStartsWithString2(newFileName, L"\\Windows", TRUE)) { - newFileName = PhCreateStringEx(NULL, (FileName->Length + 2) * sizeof(WCHAR)); + newFileName = PhCreateStringEx(NULL, FileName->Length + 2 * sizeof(WCHAR)); newFileName->Buffer[0] = USER_SHARED_DATA->NtSystemRoot[0]; newFileName->Buffer[1] = ':'; memcpy(&newFileName->Buffer[2], FileName->Buffer, FileName->Length); From 4d1da49bca8b3bd8e81561971e0adeceb0a03c71 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 7 May 2019 21:12:18 +0200 Subject: [PATCH 1886/2058] Fix some processes not showing as being debugged --- phlib/include/phnativeinl.h | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/phlib/include/phnativeinl.h b/phlib/include/phnativeinl.h index b6a202157e06..301ce23980f0 100644 --- a/phlib/include/phnativeinl.h +++ b/phlib/include/phnativeinl.h @@ -208,6 +208,32 @@ PhGetProcessIsBeingDebugged( { *IsBeingDebugged = !!debugPort; } + else + { + HANDLE debugHandle; + + // The ProcessDebugPort is only set by CsrCreateProcess when DEBUG_PROCESS is specified during process creation. + // Processes that are debugged at runtime (without the CreateProcess DEBUG_PROCESS flag) won't have a ProcessDebugPort and + // will instead only have the ProcessDebugObjectHandle and so we have to check both classes. (dmex) + status = NtQueryInformationProcess( + ProcessHandle, + ProcessDebugObjectHandle, + &debugHandle, + sizeof(HANDLE), + NULL + ); + + if (NT_SUCCESS(status)) + { + *IsBeingDebugged = TRUE; + NtClose(debugHandle); + } + else if (status == STATUS_ACCESS_DENIED) + { + *IsBeingDebugged = TRUE; + status = STATUS_SUCCESS; + } + } return status; } From ff2d44aad9f2c7d307795df512bb6aaed1d56add Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 7 May 2019 21:12:51 +0200 Subject: [PATCH 1887/2058] Fix uxtheme return types --- phlib/theme.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/phlib/theme.c b/phlib/theme.c index 37efd68d9b06..b9b339983d56 100644 --- a/phlib/theme.c +++ b/phlib/theme.c @@ -97,16 +97,16 @@ LRESULT CALLBACK PhpThemeWindowStatusbarWndSubclassProc( ); // rev // Win10-RS5 (uxtheme.dll ordinal 132) -BOOLEAN (WINAPI *ShouldAppsUseDarkMode_I)( +BOOL (WINAPI *ShouldAppsUseDarkMode_I)( VOID ) = NULL; // rev // Win10-RS5 (uxtheme.dll ordinal 133) -BOOLEAN (WINAPI *AllowDarkModeForWindow_I)( +BOOL (WINAPI *AllowDarkModeForWindow_I)( _In_ HWND WindowHandle, _In_ BOOL Enabled ) = NULL; // rev // Win10-RS5 (uxtheme.dll ordinal 137) -BOOLEAN (WINAPI *IsDarkModeAllowedForWindow_I)( +BOOL (WINAPI *IsDarkModeAllowedForWindow_I)( _In_ HWND WindowHandle ) = NULL; From b7ba3931c5e5acedb1bf6a62857af91983f942fc Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 8 May 2019 21:49:09 +0200 Subject: [PATCH 1888/2058] Remove unused window ids --- ProcessHacker/include/sysinfop.h | 1 + ProcessHacker/sysinfo.c | 33 ++++++++++++++++---------------- ProcessHacker/sysscio.c | 2 +- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/ProcessHacker/include/sysinfop.h b/ProcessHacker/include/sysinfop.h index cb21404d50ac..fe52c0660b92 100644 --- a/ProcessHacker/include/sysinfop.h +++ b/ProcessHacker/include/sysinfop.h @@ -76,6 +76,7 @@ VOID PhSipOnThemeChanged( ); VOID PhSipOnCommand( + _In_ HWND HwndControl, _In_ ULONG Id, _In_ ULONG Code ); diff --git a/ProcessHacker/sysinfo.c b/ProcessHacker/sysinfo.c index 4c1eb91f1a8a..d54404dec66d 100644 --- a/ProcessHacker/sysinfo.c +++ b/ProcessHacker/sysinfo.c @@ -3,7 +3,7 @@ * System Information window * * Copyright (C) 2011-2016 wj32 - * Copyright (C) 2017 dmex + * Copyright (C) 2017-2019 dmex * * This file is part of Process Hacker. * @@ -228,7 +228,7 @@ INT_PTR CALLBACK PhSipSysInfoDialogProc( break; case WM_COMMAND: { - PhSipOnCommand(LOWORD(wParam), HIWORD(wParam)); + PhSipOnCommand((HWND)lParam, LOWORD(wParam), HIWORD(wParam)); } break; case WM_NOTIFY: @@ -397,7 +397,7 @@ VOID PhSipOnInitDialog( 3, 3, PhSipWindow, - (HMENU)IDC_SEPARATOR, + NULL, PhInstanceHandle, NULL ); @@ -410,7 +410,7 @@ VOID PhSipOnInitDialog( 3, 3, PhSipWindow, - (HMENU)IDC_RESET, + NULL, PhInstanceHandle, NULL ); @@ -560,6 +560,7 @@ VOID PhSipOnThemeChanged( } VOID PhSipOnCommand( + _In_ HWND HwndControl, _In_ ULONG Id, _In_ ULONG Code ) @@ -569,14 +570,6 @@ VOID PhSipOnCommand( case IDCANCEL: DestroyWindow(PhSipWindow); break; - case IDC_RESET: - { - if (Code == STN_CLICKED) - { - PhSipRestoreSummaryView(); - } - } - break; case IDC_BACK: { PhSipRestoreSummaryView(); @@ -654,6 +647,14 @@ VOID PhSipOnCommand( } } } + + if (HwndControl == RestoreSummaryControl) + { + if (Code == STN_CLICKED) + { + PhSipRestoreSummaryView(); + } + } } BOOLEAN PhSipOnNotify( @@ -784,12 +785,12 @@ BOOLEAN PhSipOnDrawItem( ULONG i; PPH_SYSINFO_SECTION section; - if (Id == IDC_RESET) + if (DrawItemStruct->hwndItem == RestoreSummaryControl) { PhSipDrawRestoreSummaryPanel(DrawItemStruct); return TRUE; } - else if (Id == IDC_SEPARATOR) + else if (DrawItemStruct->hwndItem == SeparatorControl) { PhSipDrawSeparator(DrawItemStruct); return TRUE; @@ -1135,9 +1136,7 @@ PPH_SYSINFO_SECTION PhSipCreateSection( PPH_SYSINFO_SECTION section; PH_GRAPH_OPTIONS options; - section = PhAllocate(sizeof(PH_SYSINFO_SECTION)); - memset(section, 0, sizeof(PH_SYSINFO_SECTION)); - + section = PhAllocateZero(sizeof(PH_SYSINFO_SECTION)); section->Name = Template->Name; section->Flags = Template->Flags; section->Callback = Template->Callback; diff --git a/ProcessHacker/sysscio.c b/ProcessHacker/sysscio.c index 35011f481114..b5937e676278 100644 --- a/ProcessHacker/sysscio.c +++ b/ProcessHacker/sysscio.c @@ -243,7 +243,7 @@ INT_PTR CALLBACK PhSipIoDialogProc( 3, 3, IoDialog, - (HMENU)IDC_IO, + NULL, PhInstanceHandle, NULL ); From 9f962305a4fef75de80cf4a3fd24b1fc65b88aed Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 8 May 2019 21:53:53 +0200 Subject: [PATCH 1889/2058] ExtendedServices: update macro --- plugins/ExtendedServices/trigger.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/ExtendedServices/trigger.c b/plugins/ExtendedServices/trigger.c index 4d6a900029f7..33360c2dc952 100644 --- a/plugins/ExtendedServices/trigger.c +++ b/plugins/ExtendedServices/trigger.c @@ -653,7 +653,7 @@ VOID EspFormatTriggerInfo( triggerString = SubTypeEntries[i].Name; break; } - else if (Info->Subtype && SubTypeEntries[i].Guid && memcmp(Info->Subtype, SubTypeEntries[i].Guid, sizeof(GUID)) == 0) + else if (Info->Subtype && SubTypeEntries[i].Guid && IsEqualGUID(Info->Subtype, SubTypeEntries[i].Guid)) { subTypeFound = TRUE; triggerString = SubTypeEntries[i].Name; @@ -1320,7 +1320,7 @@ INT_PTR CALLBACK EspServiceTriggerDlgProc( SubTypeEntries[i].Type == context->EditingInfo->Type && SubTypeEntries[i].Guid && context->EditingInfo->Subtype && - memcmp(SubTypeEntries[i].Guid, context->EditingInfo->Subtype, sizeof(GUID)) == 0 + IsEqualGUID(SubTypeEntries[i].Guid, context->EditingInfo->Subtype) ) { PhSelectComboBoxString(GetDlgItem(hwndDlg, IDC_SUBTYPE), SubTypeEntries[i].Name, FALSE); From cc2d2c7821a4cfb523e1c500cd6c9701e959f87a Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 10 May 2019 22:32:30 +0200 Subject: [PATCH 1890/2058] Fix forwarder rva ordinal support --- phlib/util.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/phlib/util.c b/phlib/util.c index 7da89583b6b4..4aad6b256d6e 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -5974,7 +5974,21 @@ PVOID PhGetLoaderEntryImageExportFunction( if (libraryModule = LoadLibrary(libraryNameString->Buffer)) { - exportAddress = PhGetDllBaseProcedureAddress(libraryModule, libraryFunctionString->Buffer, 0); + if (libraryFunctionString->Buffer[0] == L'#') // This is a forwarder RVA with an ordinal import. + { + ULONG64 importOrdinal; + + PhSkipStringRef(&dllProcedureRef, sizeof(WCHAR)); + + if (PhStringToInteger64(&dllProcedureRef, 10, &importOrdinal)) + exportAddress = PhGetDllBaseProcedureAddress(libraryModule, NULL, (USHORT)importOrdinal); + else + exportAddress = PhGetDllBaseProcedureAddress(libraryModule, libraryFunctionString->Buffer, 0); + } + else + { + exportAddress = PhGetDllBaseProcedureAddress(libraryModule, libraryFunctionString->Buffer, 0); + } } PhDereferenceObject(libraryFunctionString); From 2103bd8a33604e43d6be237263e5e1694412b6ad Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 11 May 2019 03:17:42 +0200 Subject: [PATCH 1891/2058] Update ntexapi.h --- phnt/include/ntexapi.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/phnt/include/ntexapi.h b/phnt/include/ntexapi.h index fb6c9f5945b9..24c295c3b1a6 100644 --- a/phnt/include/ntexapi.h +++ b/phnt/include/ntexapi.h @@ -1036,14 +1036,14 @@ NtSetWnfProcessNotificationEvent( typedef enum _WORKERFACTORYINFOCLASS { - WorkerFactoryTimeout, - WorkerFactoryRetryTimeout, - WorkerFactoryIdleTimeout, + WorkerFactoryTimeout, // q; s: LARGE_INTEGER + WorkerFactoryRetryTimeout, // q; s: LARGE_INTEGER + WorkerFactoryIdleTimeout, // q; s: LARGE_INTEGER WorkerFactoryBindingCount, - WorkerFactoryThreadMinimum, - WorkerFactoryThreadMaximum, - WorkerFactoryPaused, - WorkerFactoryBasicInformation, + WorkerFactoryThreadMinimum, // q; s: ULONG + WorkerFactoryThreadMaximum, // q; s: ULONG + WorkerFactoryPaused, // ULONG or BOOLEAN + WorkerFactoryBasicInformation, // WORKER_FACTORY_BASIC_INFORMATION WorkerFactoryAdjustThreadGoal, WorkerFactoryCallbackType, WorkerFactoryStackInformation, // 10 From 5a7f26b96d5ec8398cb233245d378e03a57c0f31 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 11 May 2019 03:25:48 +0200 Subject: [PATCH 1892/2058] Fix token profile path --- ProcessHacker/tokprp.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/ProcessHacker/tokprp.c b/ProcessHacker/tokprp.c index 865ac13077c4..1684d44828da 100644 --- a/ProcessHacker/tokprp.c +++ b/ProcessHacker/tokprp.c @@ -3184,20 +3184,25 @@ PPH_STRING PhpGetTokenRegistryPath( if (tokenUserSid) { - HANDLE keyHandle; + NTSTATUS status; + HANDLE keyHandle = NULL; - if (NT_SUCCESS(PhOpenKey( + status = PhOpenKey( &keyHandle, KEY_READ, PH_KEY_USERS, &tokenUserSid->sr, 0 - ))) + ); + + if (NT_SUCCESS(status) || status == STATUS_ACCESS_DENIED) { profileRegistryPath = PhConcatStrings2(L"HKU\\", tokenUserSid->Buffer); - NtClose(keyHandle); } + if (keyHandle) + NtClose(keyHandle); + PhDereferenceObject(tokenUserSid); } From 4f6824d1a13d8745cb4b81fbb45ba0bf8456ff54 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 11 May 2019 03:26:48 +0200 Subject: [PATCH 1893/2058] Improve token error checking --- ProcessHacker/tokprp.c | 81 ++++++++++++++++++++++++------------------ 1 file changed, 46 insertions(+), 35 deletions(-) diff --git a/ProcessHacker/tokprp.c b/ProcessHacker/tokprp.c index 1684d44828da..93304741b052 100644 --- a/ProcessHacker/tokprp.c +++ b/ProcessHacker/tokprp.c @@ -522,13 +522,13 @@ BOOLEAN PhpUpdateTokenGroups( _In_ HANDLE TokenHandle ) { - PTOKEN_GROUPS groups; + PTOKEN_GROUPS groups = NULL; PTOKEN_GROUPS restrictedSIDs = NULL; - if (!NT_SUCCESS(PhGetTokenGroups(TokenHandle, &groups))) - return FALSE; - - PhpUpdateSidsFromTokenGroups(ListViewHandle, groups, FALSE); + if (NT_SUCCESS(PhGetTokenGroups(TokenHandle, &groups))) + { + PhpUpdateSidsFromTokenGroups(ListViewHandle, groups, FALSE); + } if (NT_SUCCESS(PhGetTokenRestrictedSids(TokenHandle, &restrictedSIDs))) { @@ -537,12 +537,10 @@ BOOLEAN PhpUpdateTokenGroups( if (TokenPageContext->RestrictedSids) PhFree(TokenPageContext->RestrictedSids); - - TokenPageContext->RestrictedSids = restrictedSIDs; - if (TokenPageContext->Groups) PhFree(TokenPageContext->Groups); + TokenPageContext->RestrictedSids = restrictedSIDs; TokenPageContext->Groups = groups; return TRUE; @@ -994,23 +992,26 @@ INT_PTR CALLBACK PhpTokenPageProc( listViewItems[i] ); - if (GET_WM_COMMAND_ID(wParam, lParam) != ID_PRIVILEGE_REMOVE) + if (lvItemIndex != -1) { - // Refresh the status text (and background color). - listViewItems[i]->TokenPrivilege->Attributes = newAttributes; - PhSetListViewSubItem( - tokenPageContext->ListViewHandle, - lvItemIndex, - PH_PROCESS_TOKEN_INDEX_STATUS, - PhGetPrivilegeAttributesString(newAttributes) - ); - } - else - { - ListView_DeleteItem( - tokenPageContext->ListViewHandle, - lvItemIndex - ); + if (GET_WM_COMMAND_ID(wParam, lParam) != ID_PRIVILEGE_REMOVE) + { + // Refresh the status text (and background color). + listViewItems[i]->TokenPrivilege->Attributes = newAttributes; + PhSetListViewSubItem( + tokenPageContext->ListViewHandle, + lvItemIndex, + PH_PROCESS_TOKEN_INDEX_STATUS, + PhGetPrivilegeAttributesString(newAttributes) + ); + } + else + { + ListView_DeleteItem( + tokenPageContext->ListViewHandle, + lvItemIndex + ); + } } } else @@ -1127,21 +1128,28 @@ INT_PTR CALLBACK PhpTokenPageProc( newAttributes ))) { - PPH_STRING attributesString = PhGetGroupAttributesString(newAttributes, FALSE); - INT lvItemIndex = PhFindListViewItemByParam( + PPH_STRING attributesString; + INT lvItemIndex; + + attributesString = PhGetGroupAttributesString(newAttributes, FALSE); + lvItemIndex = PhFindListViewItemByParam( tokenPageContext->ListViewHandle, -1, listViewItems[i] ); - // Refresh the status text (and background color). - listViewItems[i]->TokenGroup->Attributes = newAttributes; - PhSetListViewSubItem( - tokenPageContext->ListViewHandle, - lvItemIndex, - PH_PROCESS_TOKEN_INDEX_STATUS, - attributesString->Buffer - ); + if (lvItemIndex != -1) + { + // Refresh the status text (and background color). + listViewItems[i]->TokenGroup->Attributes = newAttributes; + PhSetListViewSubItem( + tokenPageContext->ListViewHandle, + lvItemIndex, + PH_PROCESS_TOKEN_INDEX_STATUS, + attributesString->Buffer + ); + } + PhDereferenceObject(attributesString); } else @@ -1243,7 +1251,10 @@ INT_PTR CALLBACK PhpTokenPageProc( listViewItems[0] ); - ListView_DeleteItem(tokenPageContext->ListViewHandle, lvItemIndex); + if (lvItemIndex != -1) + { + ListView_DeleteItem(tokenPageContext->ListViewHandle, lvItemIndex); + } } else { From 48d18a50dd3054f3ae3d8d88ff31b4635f6daeda Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 11 May 2019 03:41:09 +0200 Subject: [PATCH 1894/2058] Fix #349 --- ProcessHacker/tokprp.c | 177 ++++++++++++++++++++++++++++------------- 1 file changed, 123 insertions(+), 54 deletions(-) diff --git a/ProcessHacker/tokprp.c b/ProcessHacker/tokprp.c index 93304741b052..c97a5c7893f2 100644 --- a/ProcessHacker/tokprp.c +++ b/ProcessHacker/tokprp.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -71,6 +72,19 @@ typedef struct _PHP_TOKEN_PAGE_LISTVIEW_ITEM }; } PHP_TOKEN_PAGE_LISTVIEW_ITEM, *PPHP_TOKEN_PAGE_LISTVIEW_ITEM; +typedef struct _PHP_TOKEN_USER_RESOLVE_CONTEXT +{ + HWND WindowHandle; + PSID TokenUserSid; +} PHP_TOKEN_USER_RESOLVE_CONTEXT, *PPHP_TOKEN_USER_RESOLVE_CONTEXT; + +typedef struct _PHP_TOKEN_GROUP_RESOLVE_CONTEXT +{ + HWND ListViewHandle; + PPHP_TOKEN_PAGE_LISTVIEW_ITEM LvItem; + PSID TokenGroupSid; +} PHP_TOKEN_GROUP_RESOLVE_CONTEXT, *PPHP_TOKEN_GROUP_RESOLVE_CONTEXT; + typedef struct _ATTRIBUTE_NODE { PH_TREENEW_NODE Node; @@ -449,70 +463,94 @@ VOID PhpTokenPageFreeListViewEntries( } } -VOID PhpUpdateSidsFromTokenGroups( - _In_ HWND ListViewHandle, - _In_ PTOKEN_GROUPS Groups, - _In_ BOOLEAN Restricted +static NTSTATUS NTAPI PhpTokenGroupResolveWorker( + _In_ PVOID ThreadParameter ) { - ULONG i; - PSID *sids; - PPH_STRING *names = NULL; + PPHP_TOKEN_GROUP_RESOLVE_CONTEXT context = ThreadParameter; + PPH_STRING fullUserName; + INT lvItemIndex; - sids = PhAllocate(sizeof(PSID) * Groups->GroupCount); + lvItemIndex = PhFindListViewItemByParam( + context->ListViewHandle, + -1, + context->LvItem + ); - for (i = 0; i < Groups->GroupCount; i++) + if (lvItemIndex != -1) { - sids[i] = Groups->Groups[i].Sid; + if (fullUserName = PhGetSidFullName(context->TokenGroupSid, TRUE, NULL)) + { + PhSetListViewSubItem(context->ListViewHandle, lvItemIndex, PH_PROCESS_TOKEN_INDEX_NAME, PhGetString(fullUserName)); + PhDereferenceObject(fullUserName); + } } - PhLookupSids(Groups->GroupCount, sids, &names); - PhFree(sids); + PhFree(context->TokenGroupSid); + PhFree(context); - for (i = 0; i < Groups->GroupCount; i++) + return STATUS_SUCCESS; +} + +VOID PhpUpdateSidsFromTokenGroups( + _In_ HWND ListViewHandle, + _In_ PTOKEN_GROUPS Groups, + _In_ BOOLEAN Restricted + ) +{ + for (ULONG i = 0; i < Groups->GroupCount; i++) { - if (names[i]) - { - INT lvItemIndex; - PPH_STRING attributesString; - PPH_STRING descriptionString; - PPHP_TOKEN_PAGE_LISTVIEW_ITEM lvitem; + INT lvItemIndex; + PPH_STRING stringUserSid; + PPH_STRING attributesString; + PPH_STRING descriptionString; + PPHP_TOKEN_PAGE_LISTVIEW_ITEM lvitem; + + lvitem = PhAllocateZero(sizeof(PHP_TOKEN_PAGE_LISTVIEW_ITEM)); + lvitem->ItemCategory = Restricted ? PH_PROCESS_TOKEN_CATEGORY_RESTRICTED : PH_PROCESS_TOKEN_CATEGORY_GROUPS; + lvitem->TokenGroup = &Groups->Groups[i]; + + stringUserSid = PhSidToStringSid(Groups->Groups[i].Sid); + + lvItemIndex = PhAddListViewGroupItem( + ListViewHandle, + lvitem->ItemCategory, + MAXINT, + stringUserSid->Buffer, + lvitem + ); - lvitem = PhAllocateZero(sizeof(PHP_TOKEN_PAGE_LISTVIEW_ITEM)); - lvitem->ItemCategory = Restricted ? PH_PROCESS_TOKEN_CATEGORY_RESTRICTED : PH_PROCESS_TOKEN_CATEGORY_GROUPS; - lvitem->TokenGroup = &Groups->Groups[i]; + if (attributesString = PhGetGroupAttributesString(Groups->Groups[i].Attributes, Restricted)) + { + PhSetListViewSubItem(ListViewHandle, lvItemIndex, PH_PROCESS_TOKEN_INDEX_STATUS, PhGetString(attributesString)); + PhDereferenceObject(attributesString); + } - lvItemIndex = PhAddListViewGroupItem( - ListViewHandle, - lvitem->ItemCategory, - PH_PROCESS_TOKEN_INDEX_NAME, - names[i]->Buffer, - lvitem - ); + descriptionString = PhGetAccessString( + Groups->Groups[i].Attributes, + GroupDescriptionEntries, + RTL_NUMBER_OF(GroupDescriptionEntries) + ); - if (attributesString = PhGetGroupAttributesString(Groups->Groups[i].Attributes, Restricted)) - { - PhSetListViewSubItem(ListViewHandle, lvItemIndex, PH_PROCESS_TOKEN_INDEX_STATUS, PhGetString(attributesString)); - PhDereferenceObject(attributesString); - } + if (descriptionString) + { + PhSetListViewSubItem(ListViewHandle, lvItemIndex, PH_PROCESS_TOKEN_INDEX_DESCRIPTION, PhGetString(descriptionString)); + PhDereferenceObject(descriptionString); + } - descriptionString = PhGetAccessString( - Groups->Groups[i].Attributes, - GroupDescriptionEntries, - RTL_NUMBER_OF(GroupDescriptionEntries) - ); + { + PPHP_TOKEN_GROUP_RESOLVE_CONTEXT tokenGroupResolve; - if (descriptionString) - { - PhSetListViewSubItem(ListViewHandle, lvItemIndex, PH_PROCESS_TOKEN_INDEX_DESCRIPTION, PhGetString(descriptionString)); - PhDereferenceObject(descriptionString); - } + tokenGroupResolve = PhAllocateZero(sizeof(PHP_TOKEN_GROUP_RESOLVE_CONTEXT)); + tokenGroupResolve->ListViewHandle = ListViewHandle; + tokenGroupResolve->LvItem = lvitem; + tokenGroupResolve->TokenGroupSid = PhAllocateCopy(Groups->Groups[i].Sid, RtlLengthSid(Groups->Groups[i].Sid)); - PhDereferenceObject(names[i]); + PhQueueItemWorkQueue(PhGetGlobalWorkQueue(), PhpTokenGroupResolveWorker, tokenGroupResolve); } - } - PhFree(names); + PhDereferenceObject(stringUserSid); + } } BOOLEAN PhpUpdateTokenGroups( @@ -583,14 +621,14 @@ BOOLEAN PhpUpdateTokenPrivileges( lvItemIndex = PhAddListViewGroupItem( ListViewHandle, PH_PROCESS_TOKEN_CATEGORY_PRIVILEGES, - PH_PROCESS_TOKEN_INDEX_NAME, + MAXINT, privilegeName->Buffer, lvitem ); // Status PhSetListViewSubItem(ListViewHandle, lvItemIndex, PH_PROCESS_TOKEN_INDEX_STATUS, PhGetPrivilegeAttributesString(privileges->Privileges[i].Attributes)); // Description - PhSetListViewSubItem(ListViewHandle, lvItemIndex, PH_PROCESS_TOKEN_INDEX_DESCRIPTION, PhGetString(privilegeDisplayName)); + PhSetListViewSubItem(ListViewHandle, lvItemIndex, PH_PROCESS_TOKEN_INDEX_DESCRIPTION, PhGetStringOrEmpty(privilegeDisplayName)); if (privilegeDisplayName) PhDereferenceObject(privilegeDisplayName); PhDereferenceObject(privilegeName); @@ -624,7 +662,7 @@ VOID PhpUpdateTokenDangerousFlagItem( lvItemIndex = PhAddListViewGroupItem( ListViewHandle, lvitem->ItemCategory, - PH_PROCESS_TOKEN_INDEX_NAME, + MAXINT, Name, lvitem ); @@ -713,6 +751,25 @@ FORCEINLINE PTOKEN_PAGE_CONTEXT PhpTokenPageHeader( return PhpGenericPropertyPageHeader(hwndDlg, uMsg, wParam, lParam, 3); } +static NTSTATUS NTAPI PhpTokenUserResolveWorker( + _In_ PVOID ThreadParameter + ) +{ + PPHP_TOKEN_USER_RESOLVE_CONTEXT context = ThreadParameter; + PPH_STRING fullUserName; + + if (fullUserName = PhGetSidFullName(context->TokenUserSid, TRUE, NULL)) + { + PhSetWindowText(context->WindowHandle, fullUserName->Buffer); + PhDereferenceObject(fullUserName); + } + + PhFree(context->TokenUserSid); + PhFree(context); + + return STATUS_SUCCESS; +} + INT_PTR CALLBACK PhpTokenPageProc( _In_ HWND hwndDlg, _In_ UINT uMsg, @@ -769,7 +826,6 @@ INT_PTR CALLBACK PhpTokenPageProc( ))) { PTOKEN_USER tokenUser; - PPH_STRING fullUserName; PPH_STRING stringUserSid; ULONG sessionId; TOKEN_ELEVATION_TYPE elevationType; @@ -781,10 +837,21 @@ INT_PTR CALLBACK PhpTokenPageProc( if (NT_SUCCESS(PhGetTokenUser(tokenHandle, &tokenUser))) { - if (fullUserName = PhGetSidFullName(tokenUser->User.Sid, TRUE, NULL)) + BOOLEAN tokenIsAppContainer = FALSE; + + PhGetTokenIsAppContainer(tokenHandle, &tokenIsAppContainer); + + if (!tokenIsAppContainer) // HACK (dmex) { - PhSetDialogItemText(hwndDlg, IDC_USER, fullUserName->Buffer); - PhDereferenceObject(fullUserName); + PPHP_TOKEN_USER_RESOLVE_CONTEXT tokenUserResolve; + + PhSetDialogItemText(hwndDlg, IDC_USER, L"Resolving..."); + + tokenUserResolve = PhAllocateZero(sizeof(PHP_TOKEN_USER_RESOLVE_CONTEXT)); + tokenUserResolve->WindowHandle = GetDlgItem(hwndDlg, IDC_USER); + tokenUserResolve->TokenUserSid = PhAllocateCopy(tokenUser->User.Sid, RtlLengthSid(tokenUser->User.Sid)); + + PhQueueItemWorkQueue(PhGetGlobalWorkQueue(), PhpTokenUserResolveWorker, tokenUserResolve); } if (stringUserSid = PhSidToStringSid(tokenUser->User.Sid)) @@ -858,9 +925,11 @@ INT_PTR CALLBACK PhpTokenPageProc( ExtendedListView_SetRedraw(tokenPageContext->ListViewHandle, FALSE); PhpTokenPageFreeListViewEntries(tokenPageContext); ListView_DeleteAllItems(tokenPageContext->ListViewHandle); + PhpUpdateTokenDangerousFlags(hwndDlg, tokenPageContext, tokenPageContext->ListViewHandle, tokenHandle); PhpUpdateTokenGroups(hwndDlg, tokenPageContext, tokenPageContext->ListViewHandle, tokenHandle); PhpUpdateTokenPrivileges(hwndDlg, tokenPageContext, tokenPageContext->ListViewHandle, tokenHandle); + ExtendedListView_SortItems(tokenPageContext->ListViewHandle); ExtendedListView_SetRedraw(tokenPageContext->ListViewHandle, TRUE); From 5a69fa56bdb5ca4d2d8ee32a1c6d7ae1579a4cb1 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 11 May 2019 04:45:17 +0200 Subject: [PATCH 1895/2058] Fix performance issues with process username for sandboxie and slow domain networks --- ProcessHacker/include/procprv.h | 1 + ProcessHacker/include/proctree.h | 1 - ProcessHacker/procprv.c | 29 ++++++++++++++++++++++++----- ProcessHacker/proctree.c | 29 ++++------------------------- 4 files changed, 29 insertions(+), 31 deletions(-) diff --git a/ProcessHacker/include/procprv.h b/ProcessHacker/include/procprv.h index 522e05e9846e..1887aa29ac49 100644 --- a/ProcessHacker/include/procprv.h +++ b/ProcessHacker/include/procprv.h @@ -221,6 +221,7 @@ typedef struct _PH_PROCESS_ITEM // New fields PH_UINTPTR_DELTA PrivateBytesDelta; PPH_STRING PackageFullName; + PPH_STRING UserName; ULONGLONG ProcessSequenceNumber; PH_KNOWN_PROCESS_TYPE KnownProcessType; diff --git a/ProcessHacker/include/proctree.h b/ProcessHacker/include/proctree.h index 1b07fe8bb18f..ba807c3fff78 100644 --- a/ProcessHacker/include/proctree.h +++ b/ProcessHacker/include/proctree.h @@ -228,7 +228,6 @@ typedef struct _PH_PROCESS_NODE WCHAR JobObjectIdText[PH_INT32_STR_LEN_1]; PPH_STRING ProtectionText; PPH_STRING DesktopInfoText; - PPH_STRING UserName; WCHAR PidHexText[PH_PTR_STR_LEN_1]; // Graph buffers diff --git a/ProcessHacker/procprv.c b/ProcessHacker/procprv.c index 1e886279557e..83e3808657ca 100644 --- a/ProcessHacker/procprv.c +++ b/ProcessHacker/procprv.c @@ -114,6 +114,8 @@ typedef struct _PH_PROCESS_QUERY_S2_DATA { PH_PROCESS_QUERY_DATA Header; + PPH_STRING UserName; + VERIFY_RESULT VerifyResult; PPH_STRING VerifySignerName; @@ -477,6 +479,7 @@ VOID PhpProcessItemDeleteProcedure( if (processItem->JobName) PhDereferenceObject(processItem->JobName); if (processItem->VerifySignerName) PhDereferenceObject(processItem->VerifySignerName); if (processItem->PackageFullName) PhDereferenceObject(processItem->PackageFullName); + if (processItem->UserName) PhDereferenceObject(processItem->UserName); if (processItem->QueryHandle) NtClose(processItem->QueryHandle); @@ -908,6 +911,14 @@ VOID PhpProcessQueryStage2( { PPH_PROCESS_ITEM processItem = Data->Header.ProcessItem; + if (processItem->Sid) + { + // Note: We delay resolving the SID name because the local LSA cache might still be + // initializing for users on domain networks with slow links (e.g. VPNs). This can block + // for a very long time depending on server/network conditions. (dmex) + PhMoveReference(&Data->UserName, PhGetSidFullName(processItem->Sid, TRUE, NULL)); + } + if (PhEnableProcessQueryStage2 && processItem->FileName && !processItem->IsSubsystemProcess) { NTSTATUS status; @@ -1044,6 +1055,7 @@ VOID PhpFillProcessItemStage2( { PPH_PROCESS_ITEM processItem = Data->Header.ProcessItem; + processItem->UserName = Data->UserName; processItem->VerifyResult = Data->VerifyResult; processItem->VerifySignerName = Data->VerifySignerName; processItem->IsPacked = Data->IsPacked; @@ -2204,13 +2216,20 @@ VOID PhProcessProviderUpdate( // User if (NT_SUCCESS(PhGetTokenUser(tokenHandle, &tokenUser))) { - PSID processSid = processItem->Sid; + if (!RtlEqualSid(processItem->Sid, tokenUser->User.Sid)) + { + PSID processSid; - processItem->Sid = PhAllocateCopy(tokenUser->User.Sid, RtlLengthSid(tokenUser->User.Sid)); + // HACK (dmex) + processSid = processItem->Sid; + processItem->Sid = PhAllocateCopy(tokenUser->User.Sid, RtlLengthSid(tokenUser->User.Sid)); + PhFree(processSid); - PhFree(processSid); - PhFree(tokenUser); - modified = TRUE; + PhMoveReference(&processItem->UserName, PhGetSidFullName(processItem->Sid, TRUE, NULL)); + + PhFree(tokenUser); + modified = TRUE; + } } // Elevation diff --git a/ProcessHacker/proctree.c b/ProcessHacker/proctree.c index d473e640ff28..dd73e7e22126 100644 --- a/ProcessHacker/proctree.c +++ b/ProcessHacker/proctree.c @@ -604,7 +604,6 @@ VOID PhpRemoveProcessNode( PhClearReference(&ProcessNode->SubprocessCountText); PhClearReference(&ProcessNode->ProtectionText); PhClearReference(&ProcessNode->DesktopInfoText); - PhClearReference(&ProcessNode->UserName); PhDeleteGraphBuffers(&ProcessNode->CpuGraphBuffers); PhDeleteGraphBuffers(&ProcessNode->PrivateGraphBuffers); @@ -623,11 +622,7 @@ VOID PhUpdateProcessNode( { memset(ProcessNode->TextCache, 0, sizeof(PH_STRINGREF) * PHPRTLC_MAXIMUM); - if (ProcessNode->TooltipText) - { - PhDereferenceObject(ProcessNode->TooltipText); - ProcessNode->TooltipText = NULL; - } + PhClearReference(&ProcessNode->TooltipText); PhInvalidateTreeNewNode(&ProcessNode->Node, TN_CACHE_COLOR | TN_CACHE_ICON); TreeNew_InvalidateNode(ProcessTreeListHandle, &ProcessNode->Node); @@ -650,7 +645,7 @@ VOID PhTickProcessNodes( // The name and PID never change, so we don't invalidate that. memset(&node->TextCache[2], 0, sizeof(PH_STRINGREF) * (PHPRTLC_MAXIMUM - 2)); - node->ValidMask &= PHPN_OSCONTEXT | PHPN_IMAGE | PHPN_DPIAWARENESS | PHPN_APPID | PHPN_DESKTOPINFO | PHPN_USERNAME; // Items that always remain valid + node->ValidMask &= PHPN_OSCONTEXT | PHPN_IMAGE | PHPN_DPIAWARENESS | PHPN_APPID | PHPN_DESKTOPINFO; // Items that always remain valid // The DPI awareness defaults to unaware if not set or declared in the manifest in which case // it can be changed once, so we can only be sure that it won't be changed again if it is different @@ -838,21 +833,6 @@ static VOID PhpAggregateFieldIfNeeded( } } -static VOID PhpUpdateProcessNodeUserName( - _Inout_ PPH_PROCESS_NODE ProcessNode - ) -{ - if (!(ProcessNode->ValidMask & PHPN_USERNAME)) - { - if (ProcessNode->ProcessItem->Sid) - { - PhMoveReference(&ProcessNode->UserName, PhGetSidFullName(ProcessNode->ProcessItem->Sid, TRUE, NULL)); - } - - ProcessNode->ValidMask |= PHPN_USERNAME; - } -} - static VOID PhpUpdateProcessNodeWsCounters( _Inout_ PPH_PROCESS_NODE ProcessNode ) @@ -1421,7 +1401,7 @@ END_SORT_FUNCTION BEGIN_SORT_FUNCTION(UserName) { - sortResult = PhCompareStringWithNull(node1->UserName, node2->UserName, TRUE); + sortResult = PhCompareStringWithNull(processItem1->UserName, processItem2->UserName, TRUE); } END_SORT_FUNCTION @@ -2256,8 +2236,7 @@ BOOLEAN NTAPI PhpProcessTreeNewCallback( } break; case PHPRTLC_USERNAME: - PhpUpdateProcessNodeUserName(node); - getCellText->Text = PhGetStringRef(node->UserName); + getCellText->Text = PhGetStringRef(processItem->UserName); break; case PHPRTLC_DESCRIPTION: if (processItem->VersionInfo.FileDescription) From 02ecb4e2513021b5a77cbf0cb1423c790d6da304 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 11 May 2019 05:35:01 +0200 Subject: [PATCH 1896/2058] Improve process username caching for domain networks --- ProcessHacker/procprv.c | 68 +++++++++++++++++++++++++++++++++-------- 1 file changed, 55 insertions(+), 13 deletions(-) diff --git a/ProcessHacker/procprv.c b/ProcessHacker/procprv.c index 83e3808657ca..117578770782 100644 --- a/ProcessHacker/procprv.c +++ b/ProcessHacker/procprv.c @@ -92,6 +92,7 @@ typedef struct _PH_PROCESS_QUERY_S1_DATA PPH_STRING JobName; HANDLE ConsoleHostProcessId; PPH_STRING PackageFullName; + PPH_STRING UserName; union { @@ -114,7 +115,6 @@ typedef struct _PH_PROCESS_QUERY_S2_DATA { PH_PROCESS_QUERY_DATA Header; - PPH_STRING UserName; VERIFY_RESULT VerifyResult; PPH_STRING VerifySignerName; @@ -649,7 +649,7 @@ ULONG PhpSidFullNameCacheHashtableHashFunction( return PhHashBytes(entry->Sid, RtlLengthSid(entry->Sid)); } -PPH_STRING PhpGetSidFullNameCached( +PPH_STRING PhpGetSidFullNameCachedSlow( _In_ PSID Sid ) { @@ -690,6 +690,39 @@ PPH_STRING PhpGetSidFullNameCached( return fullName; } +PPH_STRING PhpGetSidFullNameCached( + _In_ PSID Sid + ) +{ + //if (!PhpSidFullNameCacheHashtable) + //{ + // PhpSidFullNameCacheHashtable = PhCreateHashtable( + // sizeof(PH_SID_FULL_NAME_CACHE_ENTRY), + // PhpSidFullNameCacheHashtableEqualFunction, + // PhpSidFullNameCacheHashtableHashFunction, + // 16 + // ); + // // HACK pre-cache local SIDs (dmex) + // PhpGetSidFullNameCachedSlow(&PhSeLocalSystemSid); + // PhpGetSidFullNameCachedSlow(&PhSeLocalServiceSid); + // PhpGetSidFullNameCachedSlow(&PhSeNetworkServiceSid); + //} + + if (PhpSidFullNameCacheHashtable) + { + PPH_SID_FULL_NAME_CACHE_ENTRY entry; + PH_SID_FULL_NAME_CACHE_ENTRY lookupEntry; + + lookupEntry.Sid = Sid; + entry = PhFindEntryHashtable(PhpSidFullNameCacheHashtable, &lookupEntry); + + if (entry) + return PhReferenceObject(entry->FullName); + } + + return NULL; +} + VOID PhpFlushSidFullNameCache( VOID ) @@ -903,6 +936,15 @@ VOID PhpProcessQueryStage1( Data->IsFilteredHandle = TRUE; } } + + if (!processItem->UserName && processItem->Sid) + { + // Note: We delay resolving the SID name because the local LSA cache might still be + // initializing for users on domain networks with slow links (e.g. VPNs). This can block + // for a very long time depending on server/network conditions. (dmex) + // TODO: This might need to be moved to Stage2... + PhMoveReference(&Data->UserName, PhpGetSidFullNameCachedSlow(processItem->Sid)); + } } VOID PhpProcessQueryStage2( @@ -911,14 +953,6 @@ VOID PhpProcessQueryStage2( { PPH_PROCESS_ITEM processItem = Data->Header.ProcessItem; - if (processItem->Sid) - { - // Note: We delay resolving the SID name because the local LSA cache might still be - // initializing for users on domain networks with slow links (e.g. VPNs). This can block - // for a very long time depending on server/network conditions. (dmex) - PhMoveReference(&Data->UserName, PhGetSidFullName(processItem->Sid, TRUE, NULL)); - } - if (PhEnableProcessQueryStage2 && processItem->FileName && !processItem->IsSubsystemProcess) { NTSTATUS status; @@ -1045,6 +1079,12 @@ VOID PhpFillProcessItemStage1( PhSwapReference(&processItem->Record->CommandLine, processItem->CommandLine); + // Note: We might have referenced the cached username so don't overwrite the previous data. (dmex) + if (!processItem->UserName) + processItem->UserName = Data->UserName; + else if (Data->UserName) + PhDereferenceObject(Data->UserName); + // Note: Queue stage 2 processing after filling stage1 process data. PhpQueueProcessQueryStage2(processItem); } @@ -1055,7 +1095,6 @@ VOID PhpFillProcessItemStage2( { PPH_PROCESS_ITEM processItem = Data->Header.ProcessItem; - processItem->UserName = Data->UserName; processItem->VerifyResult = Data->VerifyResult; processItem->VerifySignerName = Data->VerifySignerName; processItem->IsPacked = Data->IsPacked; @@ -1198,6 +1237,8 @@ VOID PhpFillProcessItem( if (NT_SUCCESS(PhGetTokenUser(tokenHandle, &tokenUser))) { ProcessItem->Sid = PhAllocateCopy(tokenUser->User.Sid, RtlLengthSid(tokenUser->User.Sid)); + ProcessItem->UserName = PhpGetSidFullNameCached(tokenUser->User.Sid); + PhFree(tokenUser); } @@ -1224,6 +1265,7 @@ VOID PhpFillProcessItem( ProcessItem->ProcessId == SYSTEM_PROCESS_ID) // System token can't be opened on XP (wj32) { ProcessItem->Sid = PhAllocateCopy(&PhSeLocalSystemSid, RtlLengthSid(&PhSeLocalSystemSid)); + ProcessItem->UserName = PhpGetSidFullNameCached(&PhSeLocalSystemSid); } } @@ -1771,6 +1813,8 @@ VOID PhProcessProviderUpdate( if (PhEnablePurgeProcessRecords) PhPurgeProcessRecords(); + PhpFlushSidFullNameCache(); + PhFlushImageVersionInfoCache(); } @@ -2412,8 +2456,6 @@ VOID PhProcessProviderUpdate( PhProcessInformation = processes; - PhpFlushSidFullNameCache(); - // History cannot be updated on the first run because the deltas are invalid. For example, the // I/O "deltas" will be huge because they are currently the raw accumulated values. if (runCount != 0) From d56c557bdc843828249bb6d78403856de5ab6b58 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 11 May 2019 05:35:29 +0200 Subject: [PATCH 1897/2058] Remove unused space --- ProcessHacker/procprv.c | 1 - 1 file changed, 1 deletion(-) diff --git a/ProcessHacker/procprv.c b/ProcessHacker/procprv.c index 117578770782..272de35bfdbd 100644 --- a/ProcessHacker/procprv.c +++ b/ProcessHacker/procprv.c @@ -115,7 +115,6 @@ typedef struct _PH_PROCESS_QUERY_S2_DATA { PH_PROCESS_QUERY_DATA Header; - VERIFY_RESULT VerifyResult; PPH_STRING VerifySignerName; From 669f01cc774b9a8f697d48831c56bade0edf9afe Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 11 May 2019 07:01:03 +0200 Subject: [PATCH 1898/2058] Remove duplicate process job query --- ProcessHacker/include/procprv.h | 1 - ProcessHacker/procprv.c | 53 +++++++++++---------------------- 2 files changed, 17 insertions(+), 37 deletions(-) diff --git a/ProcessHacker/include/procprv.h b/ProcessHacker/include/procprv.h index 1887aa29ac49..ec48d83b810c 100644 --- a/ProcessHacker/include/procprv.h +++ b/ProcessHacker/include/procprv.h @@ -127,7 +127,6 @@ typedef struct _PH_PROCESS_ITEM // Other - PPH_STRING JobName; HANDLE ConsoleHostProcessId; // Signature, Packed diff --git a/ProcessHacker/procprv.c b/ProcessHacker/procprv.c index 272de35bfdbd..45517f6c26f7 100644 --- a/ProcessHacker/procprv.c +++ b/ProcessHacker/procprv.c @@ -89,7 +89,6 @@ typedef struct _PH_PROCESS_QUERY_S1_DATA HICON LargeIcon; PH_IMAGE_VERSION_INFO VersionInfo; - PPH_STRING JobName; HANDLE ConsoleHostProcessId; PPH_STRING PackageFullName; PPH_STRING UserName; @@ -475,7 +474,6 @@ VOID PhpProcessItemDeleteProcedure( if (processItem->LargeIcon) DestroyIcon(processItem->LargeIcon); PhDeleteImageVersionInfo(&processItem->VersionInfo); if (processItem->Sid) PhFree(processItem->Sid); - if (processItem->JobName) PhDereferenceObject(processItem->JobName); if (processItem->VerifySignerName) PhDereferenceObject(processItem->VerifySignerName); if (processItem->PackageFullName) PhDereferenceObject(processItem->PackageFullName); if (processItem->UserName) PhDereferenceObject(processItem->UserName); @@ -858,16 +856,6 @@ VOID PhpProcessQueryStage1( Data->IsInJob = TRUE; - PhGetHandleInformation( - NtCurrentProcess(), - jobHandle, - ULONG_MAX, - NULL, - NULL, - NULL, - &Data->JobName - ); - // Process Explorer only recognizes processes as being in jobs if they don't have // the silent-breakaway-OK limit as their only limit. Emulate this behaviour. if (NT_SUCCESS(PhGetJobBasicLimits(jobHandle, &basicLimits))) @@ -1066,7 +1054,6 @@ VOID PhpFillProcessItemStage1( processItem->SmallIcon = Data->SmallIcon; processItem->LargeIcon = Data->LargeIcon; memcpy(&processItem->VersionInfo, &Data->VersionInfo, sizeof(PH_IMAGE_VERSION_INFO)); - processItem->JobName = Data->JobName; processItem->ConsoleHostProcessId = Data->ConsoleHostProcessId; processItem->PackageFullName = Data->PackageFullName; processItem->IsDotNet = Data->IsDotNet; @@ -2305,6 +2292,8 @@ VOID PhProcessProviderUpdate( if (processItem->QueryHandle) { NTSTATUS status; + BOOLEAN isInSignificantJob = FALSE; + BOOLEAN isInJob = FALSE; if (KphIsConnected()) { @@ -2319,29 +2308,12 @@ VOID PhProcessProviderUpdate( if (NT_SUCCESS(status) && status != STATUS_PROCESS_NOT_IN_JOB) { JOBOBJECT_BASIC_LIMIT_INFORMATION basicLimits; - PPH_STRING jobName = NULL; - - processItem->IsInJob = TRUE; - - PhGetHandleInformation( - NtCurrentProcess(), - jobHandle, - ULONG_MAX, - NULL, - NULL, - NULL, - &jobName - ); - if (jobName) - PhMoveReference(&processItem->JobName, jobName); + isInJob = TRUE; - // Process Explorer only recognizes processes as being in jobs if they don't have - // the silent-breakaway-OK limit as their only limit. Emulate this behaviour. (wj32) if (NT_SUCCESS(PhGetJobBasicLimits(jobHandle, &basicLimits))) { - processItem->IsInSignificantJob = - basicLimits.LimitFlags != JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK; + isInSignificantJob = basicLimits.LimitFlags != JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK; } } @@ -2350,13 +2322,22 @@ VOID PhProcessProviderUpdate( } else { - // KProcessHacker is not available. We can determine if the process is in a job, but we - // can't get a handle to the job. (wj32) - status = NtIsProcessInJob(processItem->QueryHandle, NULL); if (NT_SUCCESS(status)) - processItem->IsInJob = status == STATUS_PROCESS_IN_JOB; + isInJob = status == STATUS_PROCESS_IN_JOB; + } + + if (processItem->IsInSignificantJob != isInSignificantJob) + { + processItem->IsInSignificantJob = isInSignificantJob; + modified = TRUE; + } + + if (processItem->IsInJob != isInJob) + { + processItem->IsInJob = isInJob; + modified = TRUE; } } From 577daf2257675bf7ad08adad2af80275d8087cca Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 11 May 2019 08:53:33 +0200 Subject: [PATCH 1899/2058] Update filter.c --- plugins/ToolStatus/filter.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/plugins/ToolStatus/filter.c b/plugins/ToolStatus/filter.c index 4a2ccb40bf0a..f875ced4733f 100644 --- a/plugins/ToolStatus/filter.c +++ b/plugins/ToolStatus/filter.c @@ -121,11 +121,11 @@ BOOLEAN ProcessTreeFilterCallback( return TRUE; } - if (!PhIsNullOrEmptyString(processNode->ProcessItem->JobName)) - { - if (WordMatchStringRef(&processNode->ProcessItem->JobName->sr)) - return TRUE; - } + //if (!PhIsNullOrEmptyString(processNode->ProcessItem->JobName)) + //{ + // if (WordMatchStringRef(&processNode->ProcessItem->JobName->sr)) + // return TRUE; + //} if (!PhIsNullOrEmptyString(processNode->ProcessItem->VerifySignerName)) { From c72c77b6a2a02c918b08dbf9979f2796efa06c01 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 14 May 2019 03:27:39 +0200 Subject: [PATCH 1900/2058] Fix memory leak 02ecb4e2 --- ProcessHacker/procprv.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/ProcessHacker/procprv.c b/ProcessHacker/procprv.c index 45517f6c26f7..c2482a8debbd 100644 --- a/ProcessHacker/procprv.c +++ b/ProcessHacker/procprv.c @@ -924,7 +924,7 @@ VOID PhpProcessQueryStage1( } } - if (!processItem->UserName && processItem->Sid) + if (processItem->Sid) { // Note: We delay resolving the SID name because the local LSA cache might still be // initializing for users on domain networks with slow links (e.g. VPNs). This can block @@ -2255,11 +2255,12 @@ VOID PhProcessProviderUpdate( processItem->Sid = PhAllocateCopy(tokenUser->User.Sid, RtlLengthSid(tokenUser->User.Sid)); PhFree(processSid); - PhMoveReference(&processItem->UserName, PhGetSidFullName(processItem->Sid, TRUE, NULL)); - - PhFree(tokenUser); + PhMoveReference(&processItem->UserName, PhpGetSidFullNameCachedSlow(processItem->Sid)); + modified = TRUE; } + + PhFree(tokenUser); } // Elevation From 47074025783a8419405399b6b6cf1d4c86070bc1 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 15 May 2019 20:59:02 +0200 Subject: [PATCH 1901/2058] Fix highlighting regression from commit 4d1da49b --- phlib/include/phnative.h | 8 +++++ phlib/include/phnativeinl.h | 60 ------------------------------------ phlib/native.c | 61 +++++++++++++++++++++++++++++++++++++ 3 files changed, 69 insertions(+), 60 deletions(-) diff --git a/phlib/include/phnative.h b/phlib/include/phnative.h index a776cfb026d2..f189d0075288 100644 --- a/phlib/include/phnative.h +++ b/phlib/include/phnative.h @@ -186,6 +186,14 @@ PhGetProcessImageFileNameWin32( _Out_ PPH_STRING *FileName ); +PHLIBAPI +NTSTATUS +NTAPI +PhGetProcessIsBeingDebugged( + _In_ HANDLE ProcessHandle, + _Out_ PBOOLEAN IsBeingDebugged + ); + /** Specifies a PEB string. */ typedef enum _PH_PEB_OFFSET { diff --git a/phlib/include/phnativeinl.h b/phlib/include/phnativeinl.h index 301ce23980f0..a76e4f9f0c3c 100644 --- a/phlib/include/phnativeinl.h +++ b/phlib/include/phnativeinl.h @@ -178,66 +178,6 @@ PhGetProcessPeb32( return status; } -/** - * Gets whether a process is being debugged. - * - * \param ProcessHandle A handle to a process. The handle must have PROCESS_QUERY_INFORMATION - * access. - * \param IsBeingDebugged A variable which receives a boolean indicating whether the process is - * being debugged. - */ -FORCEINLINE -NTSTATUS -PhGetProcessIsBeingDebugged( - _In_ HANDLE ProcessHandle, - _Out_ PBOOLEAN IsBeingDebugged - ) -{ - NTSTATUS status; - PVOID debugPort; - - status = NtQueryInformationProcess( - ProcessHandle, - ProcessDebugPort, - &debugPort, - sizeof(PVOID), - NULL - ); - - if (NT_SUCCESS(status)) - { - *IsBeingDebugged = !!debugPort; - } - else - { - HANDLE debugHandle; - - // The ProcessDebugPort is only set by CsrCreateProcess when DEBUG_PROCESS is specified during process creation. - // Processes that are debugged at runtime (without the CreateProcess DEBUG_PROCESS flag) won't have a ProcessDebugPort and - // will instead only have the ProcessDebugObjectHandle and so we have to check both classes. (dmex) - status = NtQueryInformationProcess( - ProcessHandle, - ProcessDebugObjectHandle, - &debugHandle, - sizeof(HANDLE), - NULL - ); - - if (NT_SUCCESS(status)) - { - *IsBeingDebugged = TRUE; - NtClose(debugHandle); - } - else if (status == STATUS_ACCESS_DENIED) - { - *IsBeingDebugged = TRUE; - status = STATUS_SUCCESS; - } - } - - return status; -} - /** * Gets a handle to a process' debug object. * diff --git a/phlib/native.c b/phlib/native.c index f38405be158c..32445f945421 100644 --- a/phlib/native.c +++ b/phlib/native.c @@ -623,6 +623,67 @@ NTSTATUS PhGetProcessImageFileNameWin32( return status; } +/** + * Gets whether a process is being debugged. + * + * \param ProcessHandle A handle to a process. The handle must have PROCESS_QUERY_INFORMATION + * access. + * \param IsBeingDebugged A variable which receives a boolean indicating whether the process is + * being debugged. + */ +NTSTATUS PhGetProcessIsBeingDebugged( + _In_ HANDLE ProcessHandle, + _Out_ PBOOLEAN IsBeingDebugged + ) +{ + NTSTATUS status; + + // NOTE: The ProcessDebugObjectHandle is always valid when the process is being debugged while the ProcessDebugPort + // is only set when the process was created with DEBUG_PROCESS flag by CsrCreateProcess. (dmex) + if (KphIsVerified()) + { + HANDLE debugHandle; + + status = NtQueryInformationProcess( + ProcessHandle, + ProcessDebugObjectHandle, + &debugHandle, + sizeof(HANDLE), + NULL + ); + + if (NT_SUCCESS(status)) + { + *IsBeingDebugged = TRUE; + NtClose(debugHandle); + } + else if (status == STATUS_ACCESS_DENIED) + { + *IsBeingDebugged = TRUE; + status = STATUS_SUCCESS; + } + } + else + { + PVOID debugPort; + + status = NtQueryInformationProcess( + ProcessHandle, + ProcessDebugPort, + &debugPort, + sizeof(PVOID), + NULL + ); + + if (NT_SUCCESS(status)) + { + *IsBeingDebugged = !!debugPort; + } + } + + return status; +} + /** * Gets a string stored in a process' parameters structure. * From e5ebf2962ff1ffeaab9cd7803264f9c8153e47f4 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 15 May 2019 21:00:41 +0200 Subject: [PATCH 1902/2058] Update delayload imports --- phlib/apiimport.c | 2 ++ phlib/include/apiimport.h | 11 +++++++++++ phlib/util.c | 27 ++++++++++++++++++--------- 3 files changed, 31 insertions(+), 9 deletions(-) diff --git a/phlib/apiimport.c b/phlib/apiimport.c index afcbc9eab57a..ce42d222c683 100644 --- a/phlib/apiimport.c +++ b/phlib/apiimport.c @@ -64,6 +64,8 @@ PH_DEFINE_IMPORT(L"ntdll.dll", NtQueryInformationEnlistment); PH_DEFINE_IMPORT(L"ntdll.dll", NtQueryInformationResourceManager); PH_DEFINE_IMPORT(L"ntdll.dll", NtQueryInformationTransaction); PH_DEFINE_IMPORT(L"ntdll.dll", NtQueryInformationTransactionManager); +PH_DEFINE_IMPORT(L"ntdll.dll", NtQueryDefaultLocale); +PH_DEFINE_IMPORT(L"ntdll.dll", NtQueryDefaultUILanguage); PH_DEFINE_IMPORT(L"ntdll.dll", RtlGetTokenNamedObjectPath); PH_DEFINE_IMPORT(L"ntdll.dll", RtlGetAppContainerNamedObjectPath); diff --git a/phlib/include/apiimport.h b/phlib/include/apiimport.h index dc35d3311387..78b0e7f694fa 100644 --- a/phlib/include/apiimport.h +++ b/phlib/include/apiimport.h @@ -35,6 +35,15 @@ typedef NTSTATUS (NTAPI *_NtQueryInformationTransactionManager)( _Out_opt_ PULONG ReturnLength ); +typedef NTSTATUS (NTAPI *_NtQueryDefaultLocale)( + _In_ BOOLEAN UserProfile, + _Out_ PLCID DefaultLocaleId + ); + +typedef NTSTATUS (NTAPI *_NtQueryDefaultUILanguage)( + _Out_ LANGID* DefaultUILanguageId + ); + typedef NTSTATUS (NTAPI* _RtlGetTokenNamedObjectPath)( _In_ HANDLE Token, _In_opt_ PSID Sid, @@ -88,6 +97,8 @@ PH_DECLARE_IMPORT(NtQueryInformationEnlistment); PH_DECLARE_IMPORT(NtQueryInformationResourceManager); PH_DECLARE_IMPORT(NtQueryInformationTransaction); PH_DECLARE_IMPORT(NtQueryInformationTransactionManager); +PH_DECLARE_IMPORT(NtQueryDefaultLocale); +PH_DECLARE_IMPORT(NtQueryDefaultUILanguage); PH_DECLARE_IMPORT(RtlGetTokenNamedObjectPath); PH_DECLARE_IMPORT(RtlGetAppContainerNamedObjectPath); diff --git a/phlib/util.c b/phlib/util.c index 4aad6b256d6e..7775c8ff987a 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -178,10 +178,13 @@ LCID PhGetSystemDefaultLCID( VOID ) { - LCID localeId; + if (NtQueryDefaultLocale_Import()) + { + LCID localeId; - if (NT_SUCCESS(NtQueryDefaultLocale(FALSE, &localeId))) - return localeId; + if (NT_SUCCESS(NtQueryDefaultLocale_Import()(FALSE, &localeId))) + return localeId; + } return MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), SORT_DEFAULT); } @@ -191,10 +194,13 @@ LCID PhGetUserDefaultLCID( VOID ) { - LCID localeId; + if (NtQueryDefaultLocale_Import()) + { + LCID localeId; - if (NT_SUCCESS(NtQueryDefaultLocale(TRUE, &localeId))) - return localeId; + if (NT_SUCCESS(NtQueryDefaultLocale_Import()(TRUE, &localeId))) + return localeId; + } return MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), SORT_DEFAULT); } @@ -235,10 +241,13 @@ LANGID PhGetUserDefaultUILanguage( VOID ) { - LANGID languageId; + if (NtQueryDefaultUILanguage_Import()) + { + LANGID languageId; - if (NT_SUCCESS(NtQueryDefaultUILanguage(&languageId))) - return languageId; + if (NT_SUCCESS(NtQueryDefaultUILanguage_Import()(&languageId))) + return languageId; + } return MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT); } From f47d0752574864985890de39b2ca0a968fc97eb9 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 15 May 2019 21:01:44 +0200 Subject: [PATCH 1903/2058] Add PhEnumPagefilesEx --- phlib/native.c | 46 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 42 insertions(+), 4 deletions(-) diff --git a/phlib/native.c b/phlib/native.c index 32445f945421..33f0970e942a 100644 --- a/phlib/native.c +++ b/phlib/native.c @@ -1601,7 +1601,7 @@ NTSTATUS PhLoadDllProcess( #endif PhInitializeStringRefLongHint(&fileName, FileName); - allocSize = fileName.Length + sizeof(WCHAR); + allocSize = fileName.Length + sizeof(UNICODE_NULL); if (!NT_SUCCESS(status = NtAllocateVirtualMemory( ProcessHandle, @@ -1617,7 +1617,7 @@ NTSTATUS PhLoadDllProcess( ProcessHandle, baseAddress, fileName.Buffer, - fileName.Length + sizeof(WCHAR), + fileName.Length + sizeof(UNICODE_NULL), NULL ))) goto FreeExit; @@ -1758,7 +1758,7 @@ NTSTATUS PhUnloadDllProcess( 0, 0, 0, - (PUSER_THREAD_START_ROUTINE)threadStart, + threadStart, BaseAddress, &threadHandle, NULL @@ -1923,7 +1923,7 @@ NTSTATUS PhSetEnvironmentVariableRemote( 0, 0, 0, - (PUSER_THREAD_START_ROUTINE)rtlExitUserThread, + rtlExitUserThread, NULL, &threadHandle, NULL @@ -5085,6 +5085,44 @@ NTSTATUS PhEnumPagefiles( return status; } +NTSTATUS PhEnumPagefilesEx( + _Out_ PVOID *Pagefiles + ) +{ + NTSTATUS status; + PVOID buffer; + ULONG bufferSize = 0x200; + + buffer = PhAllocate(bufferSize); + + while ((status = NtQuerySystemInformation( + SystemPageFileInformationEx, + buffer, + bufferSize, + NULL + )) == STATUS_INFO_LENGTH_MISMATCH) + { + PhFree(buffer); + bufferSize *= 2; + + // Fail if we're resizing the buffer to something very large. + if (bufferSize > PH_LARGE_BUFFER_SIZE) + return STATUS_INSUFFICIENT_RESOURCES; + + buffer = PhAllocate(bufferSize); + } + + if (!NT_SUCCESS(status)) + { + PhFree(buffer); + return status; + } + + *Pagefiles = buffer; + + return status; +} + /** * Gets the file name of a process' image. * From 3b7771a1baaabed45da1dd4554087ecf71ca3bbb Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 15 May 2019 22:20:08 +0200 Subject: [PATCH 1904/2058] WindowExplorer: Update window context handling --- plugins/WindowExplorer/wndprp.c | 175 +++++++++++++++----------------- 1 file changed, 83 insertions(+), 92 deletions(-) diff --git a/plugins/WindowExplorer/wndprp.c b/plugins/WindowExplorer/wndprp.c index 3523195ca97e..9a453009d2fe 100644 --- a/plugins/WindowExplorer/wndprp.c +++ b/plugins/WindowExplorer/wndprp.c @@ -35,9 +35,9 @@ typedef struct _WINDOW_PROPERTIES_CONTEXT { - LONG RefCount; - HWND ParentWindowHandle; HWND WindowHandle; + HWND ParentWindowHandle; + HWND ListViewHandle; CLIENT_ID ClientId; PH_INITONCE SymbolProviderInitOnce; PPH_SYMBOL_PROVIDER SymbolProvider; @@ -109,15 +109,6 @@ typedef enum _NETADAPTER_DETAILS_INDEX WINDOW_PROPERTIES_INDEX_CLASS_WNDPROC } NETADAPTER_DETAILS_INDEX; - -VOID WepReferenceWindowPropertiesContext( - _Inout_ PWINDOW_PROPERTIES_CONTEXT Context - ); - -VOID WepDereferenceWindowPropertiesContext( - _Inout_ PWINDOW_PROPERTIES_CONTEXT Context - ); - NTSTATUS WepPropertiesThreadStart( _In_ PVOID Parameter ); @@ -209,6 +200,39 @@ static STRING_INTEGER_PAIR WepClassStylePairs[] = DEFINE_PAIR(CS_DROPSHADOW) }; +PPH_OBJECT_TYPE WeWindowItemType = NULL; + +VOID NTAPI WeWindowItemDeleteProcedure( + _In_ PVOID Object, + _In_ ULONG Flags + ) +{ + PWINDOW_PROPERTIES_CONTEXT context = Object; + + PLIST_ENTRY listEntry; + + PhClearReference(&context->SymbolProvider); + + // Destroy results that have not been processed by any property pages. + + listEntry = context->ResolveListHead.Flink; + + while (listEntry != &context->ResolveListHead) + { + PSYMBOL_RESOLVE_CONTEXT resolveContext; + + resolveContext = CONTAINING_RECORD(listEntry, SYMBOL_RESOLVE_CONTEXT, ListEntry); + listEntry = listEntry->Flink; + + PhClearReference(&resolveContext->Symbol); + PhFree(resolveContext); + } + + PhClearReference(&context->WndProcSymbol); + PhClearReference(&context->DlgProcSymbol); + PhClearReference(&context->ClassWndProcSymbol); +} + VOID WeShowWindowProperties( _In_ HWND ParentWindowHandle, _In_ HWND WindowHandle @@ -218,62 +242,25 @@ VOID WeShowWindowProperties( ULONG threadId; ULONG processId; - context = PhAllocateZero(sizeof(WINDOW_PROPERTIES_CONTEXT)); - context->RefCount = 1; - context->ParentWindowHandle = ParentWindowHandle; + if (!WeWindowItemType) + WeWindowItemType = PhCreateObjectType(L"WindowItemType", 0, WeWindowItemDeleteProcedure); + + context = PhCreateObjectZero(sizeof(WINDOW_PROPERTIES_CONTEXT), WeWindowItemType); context->WindowHandle = WindowHandle; + context->ParentWindowHandle = ParentWindowHandle; + + PhInitializeInitOnce(&context->SymbolProviderInitOnce); + InitializeListHead(&context->ResolveListHead); + PhInitializeQueuedLock(&context->ResolveListLock); processId = 0; threadId = GetWindowThreadProcessId(WindowHandle, &processId); context->ClientId.UniqueProcess = UlongToHandle(processId); context->ClientId.UniqueThread = UlongToHandle(threadId); - PhInitializeInitOnce(&context->SymbolProviderInitOnce); - InitializeListHead(&context->ResolveListHead); - PhInitializeQueuedLock(&context->ResolveListLock); PhCreateThread2(WepPropertiesThreadStart, context); } -VOID WepReferenceWindowPropertiesContext( - _Inout_ PWINDOW_PROPERTIES_CONTEXT Context - ) -{ - _InterlockedIncrement(&Context->RefCount); -} - -VOID WepDereferenceWindowPropertiesContext( - _Inout_ PWINDOW_PROPERTIES_CONTEXT Context - ) -{ - if (_InterlockedDecrement(&Context->RefCount) == 0) - { - PLIST_ENTRY listEntry; - - PhClearReference(&Context->SymbolProvider); - - // Destroy results that have not been processed by any property pages. - - listEntry = Context->ResolveListHead.Flink; - - while (listEntry != &Context->ResolveListHead) - { - PSYMBOL_RESOLVE_CONTEXT resolveContext; - - resolveContext = CONTAINING_RECORD(listEntry, SYMBOL_RESOLVE_CONTEXT, ListEntry); - listEntry = listEntry->Flink; - - PhClearReference(&resolveContext->Symbol); - PhFree(resolveContext); - } - - PhClearReference(&Context->WndProcSymbol); - PhClearReference(&Context->DlgProcSymbol); - PhClearReference(&Context->ClassWndProcSymbol); - - PhFree(Context); - } -} - NTSTATUS WepPropertiesThreadStart( _In_ PVOID Parameter ) @@ -315,6 +302,8 @@ NTSTATUS WepPropertiesThreadStart( PhDeleteAutoPool(&autoPool); + PhDereferenceObject(context); + return STATUS_SUCCESS; } @@ -355,7 +344,7 @@ NTSTATUS WepResolveSymbolFunction( // Fail if we don't have a symbol. if (!context->Symbol) { - WepDereferenceWindowPropertiesContext(context->Context); + PhDereferenceObject(context->Context); PhFree(context); return STATUS_SUCCESS; } @@ -366,7 +355,7 @@ NTSTATUS WepResolveSymbolFunction( PostMessage(context->NotifyWindow, WEM_RESOLVE_DONE, 0, (LPARAM)context); - WepDereferenceWindowPropertiesContext(context->Context); + PhDereferenceObject(context->Context); return STATUS_SUCCESS; } @@ -386,7 +375,7 @@ VOID WepQueueResolveSymbol( PhLoadSymbolProviderOptions(Context->SymbolProvider); } - WepReferenceWindowPropertiesContext(Context); + PhReferenceObject(Context); resolveContext = PhAllocateZero(sizeof(SYMBOL_RESOLVE_CONTEXT)); resolveContext->Address = Address; @@ -764,7 +753,7 @@ VOID WepRefreshWindowClassInfo( WCHAR className[256]; if (!GetClassName(Context->WindowHandle, className, RTL_NUMBER_OF(className))) - className[0] = 0; + className[0] = UNICODE_NULL; Context->ClassInfo.cbSize = sizeof(WNDCLASSEX); GetClassInfoEx(NULL, className, &Context->ClassInfo); @@ -847,26 +836,26 @@ INT_PTR CALLBACK WepWindowGeneralDlgProc( { case WM_INITDIALOG: { - HWND listViewHandle = GetDlgItem(hwndDlg, IDC_WINDOWINFO); + context->ListViewHandle = GetDlgItem(hwndDlg, IDC_WINDOWINFO); // HACK SendMessage(GetParent(hwndDlg), WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(WE_PhInstanceHandle, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); SendMessage(GetParent(hwndDlg), WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(WE_PhInstanceHandle, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); - + if (PhGetIntegerPairSetting(SETTING_NAME_WINDOWS_PROPERTY_POSITION).X == 0) // HACK PhCenterWindow(GetParent(hwndDlg), context->ParentWindowHandle); - PhSetListViewStyle(listViewHandle, FALSE, TRUE); - PhSetControlTheme(listViewHandle, L"explorer"); - PhAddListViewColumn(listViewHandle, 0, 0, 0, LVCFMT_LEFT, 180, L"Name"); - PhAddListViewColumn(listViewHandle, 1, 1, 1, LVCFMT_LEFT, 200, L"Value"); - PhSetExtendedListView(listViewHandle); - PhLoadListViewColumnsFromSetting(SETTING_NAME_WINDOWS_PROPERTY_COLUMNS, listViewHandle); + PhSetListViewStyle(context->ListViewHandle, FALSE, TRUE); + PhSetControlTheme(context->ListViewHandle, L"explorer"); + PhAddListViewColumn(context->ListViewHandle, 0, 0, 0, LVCFMT_LEFT, 180, L"Name"); + PhAddListViewColumn(context->ListViewHandle, 1, 1, 1, LVCFMT_LEFT, 200, L"Value"); + PhSetExtendedListView(context->ListViewHandle); + PhLoadListViewColumnsFromSetting(SETTING_NAME_WINDOWS_PROPERTY_COLUMNS, context->ListViewHandle); - WepGeneralAddListViewItemGroups(listViewHandle); - WepRefreshWindowGeneralInfo(hwndDlg, listViewHandle, context); - WepRefreshWindowStyles(listViewHandle, context); - WepRefreshWindowClassInfo(hwndDlg, listViewHandle, context); + WepGeneralAddListViewItemGroups(context->ListViewHandle); + WepRefreshWindowGeneralInfo(hwndDlg, context->ListViewHandle, context); + WepRefreshWindowStyles(context->ListViewHandle, context); + WepRefreshWindowClassInfo(hwndDlg, context->ListViewHandle, context); if (!!PhGetIntegerSetting(L"EnableThemeSupport")) // TODO: Required for compat (dmex) PhInitializeWindowTheme(GetParent(hwndDlg), !!PhGetIntegerSetting(L"EnableThemeSupport")); @@ -876,7 +865,7 @@ INT_PTR CALLBACK WepWindowGeneralDlgProc( break; case WM_DESTROY: { - PhSaveListViewColumnsToSetting(SETTING_NAME_WINDOWS_PROPERTY_COLUMNS, GetDlgItem(hwndDlg, IDC_WINDOWINFO)); + PhSaveListViewColumnsToSetting(SETTING_NAME_WINDOWS_PROPERTY_COLUMNS, context->ListViewHandle); } break; case WM_SHOWWINDOW: @@ -886,7 +875,7 @@ INT_PTR CALLBACK WepWindowGeneralDlgProc( PPH_LAYOUT_ITEM dialogItem; dialogItem = PvAddPropPageLayoutItem(hwndDlg, hwndDlg, PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL); - PvAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_WINDOWINFO), dialogItem, PH_ANCHOR_ALL); + PvAddPropPageLayoutItem(hwndDlg, context->ListViewHandle, dialogItem, PH_ANCHOR_ALL); PvDoPropPageLayout(hwndDlg); propPageContext->LayoutInitialized = TRUE; @@ -895,14 +884,12 @@ INT_PTR CALLBACK WepWindowGeneralDlgProc( break; case WM_NOTIFY: { - PhHandleListViewNotifyBehaviors(lParam, GetDlgItem(hwndDlg, IDC_WINDOWINFO), PH_LIST_VIEW_DEFAULT_1_BEHAVIORS); + PhHandleListViewNotifyBehaviors(lParam, context->ListViewHandle, PH_LIST_VIEW_DEFAULT_1_BEHAVIORS); } break; case WM_CONTEXTMENU: { - HWND listViewHandle = GetDlgItem(hwndDlg, IDC_WINDOWINFO); - - if ((HWND)wParam == listViewHandle) + if ((HWND)wParam == context->ListViewHandle) { POINT point; PPH_EMENU menu; @@ -916,14 +903,14 @@ INT_PTR CALLBACK WepWindowGeneralDlgProc( if (point.x == -1 && point.y == -1) PhGetListViewContextMenuPoint((HWND)wParam, &point); - PhGetSelectedListViewItemParams(listViewHandle, &listviewItems, &numberOfItems); + PhGetSelectedListViewItemParams(context->ListViewHandle, &listviewItems, &numberOfItems); if (numberOfItems != 0) { menu = PhCreateEMenu(); PhInsertEMenuItem(menu, PhCreateEMenuItem(0, PHAPP_IDC_COPY, L"&Copy", NULL, NULL), ULONG_MAX); - PhInsertCopyListViewEMenuItem(menu, PHAPP_IDC_COPY, listViewHandle); + PhInsertCopyListViewEMenuItem(menu, PHAPP_IDC_COPY, context->ListViewHandle); item = PhShowEMenu( menu, @@ -942,7 +929,7 @@ INT_PTR CALLBACK WepWindowGeneralDlgProc( { case PHAPP_IDC_COPY: { - PhCopyListView(listViewHandle); + PhCopyListView(context->ListViewHandle); } break; } @@ -1003,8 +990,8 @@ INT_PTR CALLBACK WepWindowGeneralDlgProc( context->ClassWndProcResolving--; } - WepRefreshWindowGeneralInfoSymbols(GetDlgItem(hwndDlg, IDC_WINDOWINFO), context); - WepRefreshWindowClassInfoSymbols(GetDlgItem(hwndDlg, IDC_WINDOWINFO), context); + WepRefreshWindowGeneralInfoSymbols(context->ListViewHandle, context); + WepRefreshWindowClassInfoSymbols(context->ListViewHandle, context); } break; } @@ -1014,25 +1001,27 @@ INT_PTR CALLBACK WepWindowGeneralDlgProc( BOOL CALLBACK EnumPropsExCallback( _In_ HWND hwnd, - _In_ LPTSTR lpszString, + _In_ PWSTR lpszString, _In_ HANDLE hData, _In_ ULONG_PTR dwData ) { INT lvItemIndex; - PWSTR propName; WCHAR value[PH_PTR_STR_LEN_1]; - propName = lpszString; + if ((ULONG_PTR)lpszString < USHRT_MAX) // This is an integer atom. + { + PPH_STRING propName; - if ((ULONG_PTR)lpszString < USHRT_MAX) + propName = PhFormatString(L"#%lu", (ULONG_PTR)lpszString); + lvItemIndex = PhAddListViewItem((HWND)dwData, MAXINT, propName->Buffer, NULL); + PhDereferenceObject(propName); + } + else { - // This is an integer atom. - propName = PhaFormatString(L"#%lu", (ULONG_PTR)lpszString)->Buffer; + lvItemIndex = PhAddListViewItem((HWND)dwData, MAXINT, lpszString, NULL); } - lvItemIndex = PhAddListViewItem((HWND)dwData, MAXINT, propName, NULL); - PhPrintPointer(value, (PVOID)hData); PhSetListViewSubItem((HWND)dwData, lvItemIndex, 1, value); @@ -1047,7 +1036,9 @@ VOID WepRefreshWindowProps( { ExtendedListView_SetRedraw(ListViewHandle, FALSE); ListView_DeleteAllItems(ListViewHandle); + EnumPropsEx(Context->WindowHandle, EnumPropsExCallback, (LPARAM)ListViewHandle); + ExtendedListView_SortItems(ListViewHandle); ExtendedListView_SetRedraw(ListViewHandle, TRUE); } From 82f1ad09a8c0e9546904283ac20cd07070516cf7 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 15 May 2019 23:52:41 +0200 Subject: [PATCH 1905/2058] Update ntmmapi.h --- phnt/include/ntmmapi.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/phnt/include/ntmmapi.h b/phnt/include/ntmmapi.h index 97b91b0b48b2..98bc4821a697 100644 --- a/phnt/include/ntmmapi.h +++ b/phnt/include/ntmmapi.h @@ -983,6 +983,7 @@ NtTerminateEnclave( _In_ BOOLEAN WaitForThread ); +#if (PHNT_MODE != PHNT_MODE_KERNEL) // rev NTSYSAPI NTSTATUS @@ -993,5 +994,6 @@ NtCallEnclave( _In_ BOOLEAN WaitForThread, _Out_opt_ PVOID *ReturnValue ); +#endif #endif From bc35992bf19a7c235a66c607ad1053299ea58e97 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 17 May 2019 01:23:50 +0200 Subject: [PATCH 1906/2058] Update ntpsapi.h --- phnt/include/ntpsapi.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/phnt/include/ntpsapi.h b/phnt/include/ntpsapi.h index 2320c41afb05..faa9065b4092 100644 --- a/phnt/include/ntpsapi.h +++ b/phnt/include/ntpsapi.h @@ -155,7 +155,7 @@ typedef enum _PROCESSINFOCLASS ProcessKeepAliveCount, // q: PROCESS_KEEPALIVE_COUNT_INFORMATION ProcessRevokeFileHandles, // s: PROCESS_REVOKE_FILE_HANDLES_INFORMATION ProcessWorkingSetControl, // s: PROCESS_WORKING_SET_CONTROL - ProcessHandleTable, // since WINBLUE + ProcessHandleTable, // q: ULONG[] // since WINBLUE ProcessCheckStackExtentsMode, ProcessCommandLineInformation, // q: UNICODE_STRING // 60 ProcessProtectionInformation, // q: PS_PROTECTION @@ -168,7 +168,7 @@ typedef enum _PROCESSINFOCLASS ProcessSubsystemProcess, ProcessJobMemoryInformation, // PROCESS_JOB_MEMORY_INFO ProcessInPrivate, // since THRESHOLD2 // 70 - ProcessRaiseUMExceptionOnInvalidHandleClose, + ProcessRaiseUMExceptionOnInvalidHandleClose, // qs: ULONG; s: 0 disables, otherwise enables ProcessIumChallengeResponse, ProcessChildProcessInformation, // PROCESS_CHILD_PROCESS_INFORMATION ProcessHighGraphicsPriorityInformation, @@ -186,7 +186,7 @@ typedef enum _PROCESSINFOCLASS ProcessEnclaveInformation, ProcessEnableReadWriteVmLogging, // PROCESS_READWRITEVM_LOGGING_INFORMATION ProcessUptimeInformation, // PROCESS_UPTIME_INFORMATION - ProcessImageSection, + ProcessImageSection, // q: HANDLE ProcessDebugAuthInformation, // since REDSTONE4 // 90 ProcessSystemResourceManagement, // PROCESS_SYSTEM_RESOURCE_MANAGEMENT ProcessSequenceNumber, // q: ULONGLONG From 23a100fd4d9fda5ab67fc9f305dd6275d14521a5 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 17 May 2019 01:24:51 +0200 Subject: [PATCH 1907/2058] Update Win10 version info --- phlib/global.c | 2 +- phlib/include/phconfig.h | 2 +- phlib/kphdata.c | 2 +- phnt/include/phnt.h | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/phlib/global.c b/phlib/global.c index f7a7cc3a7a32..6370e3a1f745 100644 --- a/phlib/global.c +++ b/phlib/global.c @@ -208,7 +208,7 @@ VOID PhInitializeWindowsVersion( WindowsVersion = WINDOWS_10_RS5; break; case 18362: - WindowsVersion = WINDOWS_10_19H1; + WindowsVersion = WINDOWS_10_RS6; break; default: WindowsVersion = WINDOWS_10; diff --git a/phlib/include/phconfig.h b/phlib/include/phconfig.h index d0d71cf72432..a3c573d96076 100644 --- a/phlib/include/phconfig.h +++ b/phlib/include/phconfig.h @@ -34,7 +34,7 @@ PHLIBAPI extern ACCESS_MASK ThreadAllAccess; #define WINDOWS_10_RS3 104 #define WINDOWS_10_RS4 105 #define WINDOWS_10_RS5 106 -#define WINDOWS_10_19H1 107 +#define WINDOWS_10_RS6 107 #define WINDOWS_NEW ULONG_MAX #define WINDOWS_HAS_IMMERSIVE (WindowsVersion >= WINDOWS_8) diff --git a/phlib/kphdata.c b/phlib/kphdata.c index 66f55f0f2009..3dfeeac26732 100644 --- a/phlib/kphdata.c +++ b/phlib/kphdata.c @@ -161,7 +161,7 @@ NTSTATUS KphInitializeDynamicPackage( break; case 18362: Package->BuildNumber = 18362; - Package->ResultingNtVersion = PHNT_19H1; + Package->ResultingNtVersion = PHNT_REDSTONE6; break; default: return STATUS_NOT_SUPPORTED; diff --git a/phnt/include/phnt.h b/phnt/include/phnt.h index 0f6e1d72d2c5..fa6ce2302c0e 100644 --- a/phnt/include/phnt.h +++ b/phnt/include/phnt.h @@ -38,7 +38,7 @@ #define PHNT_REDSTONE3 104 #define PHNT_REDSTONE4 105 #define PHNT_REDSTONE5 106 -#define PHNT_19H1 107 +#define PHNT_REDSTONE6 107 #ifndef PHNT_MODE #define PHNT_MODE PHNT_MODE_USER From 241405c11dba33e75dea87ca4163e4264492e734 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 17 May 2019 02:09:08 +0200 Subject: [PATCH 1908/2058] Fix runas regression --- ProcessHacker/runas.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ProcessHacker/runas.c b/ProcessHacker/runas.c index 6566bdf011f3..4b22932f6a86 100644 --- a/ProcessHacker/runas.c +++ b/ProcessHacker/runas.c @@ -1144,14 +1144,14 @@ INT_PTR CALLBACK PhpRunAsDlgProc( &logonType )) { - ULONG sessionId = ULONG_MAX; + ULONG currentSessionId = ULONG_MAX; - PhGetProcessSessionId(NtCurrentProcess(), &sessionId); + PhGetProcessSessionId(NtCurrentProcess(), ¤tSessionId); if ( logonType == LOGON32_LOGON_INTERACTIVE && !context->ProcessId && - sessionId == sessionId && + sessionId == currentSessionId && !useLinkedToken ) { From b542b6a5f8b0781a4e3d416f8c07ec18054cdeb8 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 17 May 2019 09:06:04 +0200 Subject: [PATCH 1909/2058] Remove legacy access mask --- phlib/symprv.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/phlib/symprv.c b/phlib/symprv.c index b6054b4df439..14253d8e8470 100644 --- a/phlib/symprv.c +++ b/phlib/symprv.c @@ -114,17 +114,15 @@ PPH_SYMBOL_PROVIDER PhCreateSymbolProvider( { static ACCESS_MASK accesses[] = { - STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xfff, // pre-Vista full access + //STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xfff, // pre-Vista full access PROCESS_QUERY_INFORMATION | PROCESS_VM_READ | PROCESS_DUP_HANDLE, PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, MAXIMUM_ALLOWED }; - ULONG i; - // Try to open the process with many different accesses. // This handle will be re-used when walking stacks, and doing various other things. - for (i = 0; i < sizeof(accesses) / sizeof(ACCESS_MASK); i++) + for (ULONG i = 0; i < sizeof(accesses) / sizeof(ACCESS_MASK); i++) { if (NT_SUCCESS(PhOpenProcess(&symbolProvider->ProcessHandle, accesses[i], ProcessId))) { From 0bd91327c89f7a68769ce8fdc2bd70eeb9e26c14 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 17 May 2019 22:05:45 +0200 Subject: [PATCH 1910/2058] add missing file --- phlib/kphdata.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phlib/kphdata.c b/phlib/kphdata.c index 3dfeeac26732..6b141ef8f62b 100644 --- a/phlib/kphdata.c +++ b/phlib/kphdata.c @@ -303,7 +303,7 @@ NTSTATUS KphInitializeDynamicPackage( break; case 18362: Package->BuildNumber = 18362; - Package->ResultingNtVersion = PHNT_19H1; + Package->ResultingNtVersion = PHNT_REDSTONE6; break; default: return STATUS_NOT_SUPPORTED; From ac816c22b61698ae3d722c496bf7f6c74f585276 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 18 May 2019 22:14:28 +0200 Subject: [PATCH 1911/2058] Update ntrtl.h --- phnt/include/ntrtl.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/phnt/include/ntrtl.h b/phnt/include/ntrtl.h index f9be267cf2dd..1528322581af 100644 --- a/phnt/include/ntrtl.h +++ b/phnt/include/ntrtl.h @@ -2619,8 +2619,8 @@ RtlDeNormalizeProcessParams( typedef struct _RTL_USER_PROCESS_INFORMATION { ULONG Length; - HANDLE Process; - HANDLE Thread; + HANDLE ProcessHandle; + HANDLE ThreadHandle; CLIENT_ID ClientId; SECTION_IMAGE_INFORMATION ImageInformation; } RTL_USER_PROCESS_INFORMATION, *PRTL_USER_PROCESS_INFORMATION; From 60d82acc581efce7564ea855dd459dcd36cff741 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 18 May 2019 22:14:41 +0200 Subject: [PATCH 1912/2058] Update util.c --- phlib/util.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/phlib/util.c b/phlib/util.c index 7775c8ff987a..0404a50130ac 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -2579,20 +2579,20 @@ NTSTATUS PhCreateProcess( if (NT_SUCCESS(status)) { if (!(Flags & PH_CREATE_PROCESS_SUSPENDED)) - NtResumeThread(processInfo.Thread, NULL); + NtResumeThread(processInfo.ThreadHandle, NULL); if (ClientId) *ClientId = processInfo.ClientId; if (ProcessHandle) - *ProcessHandle = processInfo.Process; + *ProcessHandle = processInfo.ProcessHandle; else - NtClose(processInfo.Process); + NtClose(processInfo.ProcessHandle); if (ThreadHandle) - *ThreadHandle = processInfo.Thread; + *ThreadHandle = processInfo.ThreadHandle; else - NtClose(processInfo.Thread); + NtClose(processInfo.ThreadHandle); } return status; From 4191f9554c743234a523000b8a80cdb42b64db64 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 19 May 2019 06:36:50 +0200 Subject: [PATCH 1913/2058] Plugins: Disable CRT argument/environment processing --- plugins/Plugins.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/Plugins.props b/plugins/Plugins.props index 47b6fdf83817..da18855cce14 100644 --- a/plugins/Plugins.props +++ b/plugins/Plugins.props @@ -31,7 +31,7 @@ true - ProcessHacker.lib;ntdll.lib;%(AdditionalDependencies) + ProcessHacker.lib;ntdll.lib;noenv.obj;noarg.obj;%(AdditionalDependencies) true 6.01 Windows From 3d6e1e76ca26f8e1f128ed6ffad1abfb9680caa8 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 19 May 2019 06:38:33 +0200 Subject: [PATCH 1914/2058] Update apiimport.c --- phlib/apiimport.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/phlib/apiimport.c b/phlib/apiimport.c index ce42d222c683..22158c9933f4 100644 --- a/phlib/apiimport.c +++ b/phlib/apiimport.c @@ -24,6 +24,20 @@ #include #include +PVOID PhpEncodeDecodePointer( // dmex + _In_ PVOID Pointer + ) +{ + static ULONG cookie = 0; + + if (cookie == 0) + { + RtlRandomEx(&cookie); + } + + return (PVOID)((ULONG_PTR)Pointer ^ cookie); +} + PVOID PhpImportProcedure( _Inout_ PVOID *Cache, _Inout_ PBOOLEAN CacheValid, @@ -35,7 +49,7 @@ PVOID PhpImportProcedure( PVOID procedure; if (*CacheValid) - return *Cache; + return PhpEncodeDecodePointer(*Cache); if (!(module = PhGetLoaderEntryDllBase(ModuleName))) module = LoadLibrary(ModuleName); // HACK (dmex) @@ -44,7 +58,8 @@ PVOID PhpImportProcedure( return NULL; procedure = PhGetDllBaseProcedureAddress(module, ProcedureName, 0); - *Cache = procedure; + *Cache = PhpEncodeDecodePointer(procedure); + MemoryBarrier(); *CacheValid = TRUE; From a9c061c54228d70f2a7927af5fedba63747c792d Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 19 May 2019 06:39:46 +0200 Subject: [PATCH 1915/2058] ToolStatus: Update index value --- phlib/apiimport.c | 3 +++ plugins/ToolStatus/graph.c | 8 ++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/phlib/apiimport.c b/phlib/apiimport.c index 22158c9933f4..5b6793c4d36e 100644 --- a/phlib/apiimport.c +++ b/phlib/apiimport.c @@ -75,6 +75,9 @@ _##Name Name##_Import(VOID) \ return (_##Name)PhpImportProcedure(&cache, &cacheValid, Module, #Name); \ } +PH_DEFINE_IMPORT(L"ntdll.dll", NtOpenProcess); +PH_DEFINE_IMPORT(L"ntdll.dll", NtOpenThread); +PH_DEFINE_IMPORT(L"ntdll.dll", NtTerminateProcess); PH_DEFINE_IMPORT(L"ntdll.dll", NtQueryInformationEnlistment); PH_DEFINE_IMPORT(L"ntdll.dll", NtQueryInformationResourceManager); PH_DEFINE_IMPORT(L"ntdll.dll", NtQueryInformationTransaction); diff --git a/plugins/ToolStatus/graph.c b/plugins/ToolStatus/graph.c index b549eab053d3..764ac932d8fa 100644 --- a/plugins/ToolStatus/graph.c +++ b/plugins/ToolStatus/graph.c @@ -582,7 +582,7 @@ TOOLSTATUS_GRAPH_MESSAGE_CALLBACK_DECLARE(CpuHistoryGraphMessageCallback) drawInfo->Flags = PH_GRAPH_USE_GRID_X | PH_GRAPH_USE_LINE_2; PhSiSetColorsGraphDrawInfo(drawInfo, PhGetIntegerSetting(L"ColorCpuKernel"), PhGetIntegerSetting(L"ColorCpuUser")); - if (ProcessesUpdatedCount <= 2) + if (ProcessesUpdatedCount < 3) return; PhGraphStateGetDrawInfo(GraphState, getDrawInfo, SystemStatistics.CpuUserHistory->Count); @@ -654,7 +654,7 @@ TOOLSTATUS_GRAPH_MESSAGE_CALLBACK_DECLARE(PhysicalHistoryGraphMessageCallback) drawInfo->Flags = PH_GRAPH_USE_GRID_X; PhSiSetColorsGraphDrawInfo(drawInfo, PhGetIntegerSetting(L"ColorPhysical"), 0); - if (ProcessesUpdatedCount <= 2) + if (ProcessesUpdatedCount < 3) return; PhGraphStateGetDrawInfo(GraphState, getDrawInfo, SystemStatistics.PhysicalHistory->Count); @@ -719,7 +719,7 @@ TOOLSTATUS_GRAPH_MESSAGE_CALLBACK_DECLARE(CommitHistoryGraphMessageCallback) drawInfo->Flags = PH_GRAPH_USE_GRID_X; PhSiSetColorsGraphDrawInfo(drawInfo, PhGetIntegerSetting(L"ColorPrivate"), 0); - if (ProcessesUpdatedCount <= 2) + if (ProcessesUpdatedCount < 3) return; PhGraphStateGetDrawInfo(GraphState, getDrawInfo, SystemStatistics.CommitHistory->Count); @@ -784,7 +784,7 @@ TOOLSTATUS_GRAPH_MESSAGE_CALLBACK_DECLARE(IoHistoryGraphMessageCallback) drawInfo->Flags = PH_GRAPH_USE_GRID_X | PH_GRAPH_USE_LINE_2; PhSiSetColorsGraphDrawInfo(drawInfo, PhGetIntegerSetting(L"ColorIoReadOther"), PhGetIntegerSetting(L"ColorIoWrite")); - if (ProcessesUpdatedCount <= 2) + if (ProcessesUpdatedCount < 3) return; PhGraphStateGetDrawInfo(GraphState, getDrawInfo, SystemStatistics.IoReadHistory->Count); From a6c0d554d0e2f8718f5914cf8ad76dcde0ec0926 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 19 May 2019 06:40:31 +0200 Subject: [PATCH 1916/2058] Update PhDuplicateStringZ buffer length --- phlib/basesup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phlib/basesup.c b/phlib/basesup.c index 142d0a657d3b..6959e2831202 100644 --- a/phlib/basesup.c +++ b/phlib/basesup.c @@ -702,7 +702,7 @@ PWSTR PhDuplicateStringZ( PWSTR newString; SIZE_T length; - length = (PhCountStringZ(String) + sizeof(UNICODE_NULL)) * sizeof(WCHAR); // include the null terminator + length = PhCountStringZ(String) * sizeof(WCHAR) + sizeof(UNICODE_NULL); // include the null terminator newString = PhAllocate(length); memcpy(newString, String, length); From d6225bcc746f31142efae86c949a48622e7c7ec0 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 19 May 2019 06:42:49 +0200 Subject: [PATCH 1917/2058] Remove unused const --- ProcessHacker/mainwnd.c | 15 +++++++++++---- phlib/include/guisup.h | 6 +++--- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index 1b738be3b518..7b29dd11de9f 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -1759,7 +1759,7 @@ BOOLEAN PhMwpOnNotify( PPH_STRING fullFileName; PPH_STRING argumentsString; - PhInitializeStringRefLongHint(&string, (PWSTR)runFileDlg->lpszFile); + PhInitializeStringRefLongHint(&string, runFileDlg->lpszFile); PhParseCommandLineFuzzy(&string, &fileName, &arguments, &fullFileName); if (!fullFileName) @@ -1767,8 +1767,15 @@ BOOLEAN PhMwpOnNotify( argumentsString = PhCreateString2(&arguments); - if (PhShellExecuteEx(PhMainWndHandle, fullFileName->Buffer, argumentsString->Buffer, - runFileDlg->nShow, PH_SHELL_EXECUTE_ADMIN, 0, NULL)) + if (PhShellExecuteEx( + PhMainWndHandle, + fullFileName->Buffer, + argumentsString->Buffer, + runFileDlg->ShowCmd, + PH_SHELL_EXECUTE_ADMIN, + 0, + NULL + )) { *Result = RF_CANCEL; } @@ -1802,7 +1809,7 @@ BOOLEAN PhMwpOnNotify( { status = PhCreateProcessWin32( NULL, - (PWSTR)runFileDlg->lpszFile, + runFileDlg->lpszFile, NULL, NULL, 0, diff --git a/phlib/include/guisup.h b/phlib/include/guisup.h index a2d40ef8d625..b50870aca3ad 100644 --- a/phlib/include/guisup.h +++ b/phlib/include/guisup.h @@ -24,9 +24,9 @@ extern "C" { typedef struct _NMRUNFILEDLGW { NMHDR hdr; - LPCWSTR lpszFile; - LPCWSTR lpszDirectory; - UINT nShow; + PWSTR lpszFile; + PWSTR lpszDirectory; + UINT ShowCmd; } NMRUNFILEDLGW, *LPNMRUNFILEDLGW, *PNMRUNFILEDLGW; typedef NMRUNFILEDLGW NMRUNFILEDLG; From 4d13ae8268d3e45a4eaf24f07058380bc5a3e618 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 19 May 2019 06:43:36 +0200 Subject: [PATCH 1918/2058] Update macro --- ProcessHacker/srvprv.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/ProcessHacker/srvprv.c b/ProcessHacker/srvprv.c index 4dff916637bc..5d89dd2aacab 100644 --- a/ProcessHacker/srvprv.c +++ b/ProcessHacker/srvprv.c @@ -558,8 +558,7 @@ NTSTATUS PhpServiceQueryStage1Worker( PPH_SERVICE_QUERY_S1_DATA data; PPH_SERVICE_ITEM serviceItem = (PPH_SERVICE_ITEM)Parameter; - data = PhAllocate(sizeof(PH_SERVICE_QUERY_S1_DATA)); - memset(data, 0, sizeof(PH_SERVICE_QUERY_S1_DATA)); + data = PhAllocateZero(sizeof(PH_SERVICE_QUERY_S1_DATA)); data->Header.Stage = 1; data->Header.ServiceItem = serviceItem; @@ -577,8 +576,7 @@ NTSTATUS PhpServiceQueryStage2Worker( PPH_SERVICE_QUERY_S2_DATA data; PPH_SERVICE_ITEM serviceItem = (PPH_SERVICE_ITEM)Parameter; - data = PhAllocate(sizeof(PH_SERVICE_QUERY_S2_DATA)); - memset(data, 0, sizeof(PH_SERVICE_QUERY_S2_DATA)); + data = PhAllocateZero(sizeof(PH_SERVICE_QUERY_S2_DATA)); data->Header.Stage = 2; data->Header.ServiceItem = serviceItem; @@ -1064,8 +1062,7 @@ VOID CALLBACK PhpServiceNonPollScNotifyCallback( PPHP_SERVICE_NOTIFY_CONTEXT newNotifyContext; // Service creation - newNotifyContext = PhAllocate(sizeof(PHP_SERVICE_NOTIFY_CONTEXT)); - memset(newNotifyContext, 0, sizeof(PHP_SERVICE_NOTIFY_CONTEXT)); + newNotifyContext = PhAllocateZero(sizeof(PHP_SERVICE_NOTIFY_CONTEXT)); newNotifyContext->State = SnAdding; newNotifyContext->ServiceName = PhCreateString(name + 1); InsertTailList(&PhpNonPollServicePendingListHead, &newNotifyContext->ListEntry); @@ -1184,8 +1181,7 @@ NTSTATUS PhpServiceNonPollThreadStart( if (serviceHandle) { - notifyContext = PhAllocate(sizeof(PHP_SERVICE_NOTIFY_CONTEXT)); - memset(notifyContext, 0, sizeof(PHP_SERVICE_NOTIFY_CONTEXT)); + notifyContext = PhAllocateZero(sizeof(PHP_SERVICE_NOTIFY_CONTEXT)); notifyContext->ServiceHandle = serviceHandle; notifyContext->State = SnNotify; notifyContext->ServiceName = PhCreateString(services[i].lpServiceName); @@ -1195,8 +1191,7 @@ NTSTATUS PhpServiceNonPollThreadStart( PhFree(services); - notifyContext = PhAllocate(sizeof(PHP_SERVICE_NOTIFY_CONTEXT)); - memset(notifyContext, 0, sizeof(PHP_SERVICE_NOTIFY_CONTEXT)); + notifyContext = PhAllocateZero(sizeof(PHP_SERVICE_NOTIFY_CONTEXT)); notifyContext->ServiceHandle = scManagerHandle; notifyContext->IsServiceManager = TRUE; notifyContext->State = SnNotify; From 057446a3d4f62441dfcb062f8a901b9cb9614029 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 19 May 2019 06:44:33 +0200 Subject: [PATCH 1919/2058] Remove whitespace --- ProcessHacker/prpgstat.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ProcessHacker/prpgstat.c b/ProcessHacker/prpgstat.c index 8ea49a6fb631..f2c8cea914c3 100644 --- a/ProcessHacker/prpgstat.c +++ b/ProcessHacker/prpgstat.c @@ -392,7 +392,7 @@ VOID PhpUpdateProcessStatistics( if (NT_SUCCESS(PhEnumProcesses(&processes))) { processInfo = PhFindProcessInformation(processes, ProcessItem->ProcessId); - + if (processInfo && (processExtension = PH_PROCESS_EXTENSION(processInfo))) { PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_CONTEXTSWITCHES, 1, PhaFormatUInt64(processExtension->ContextSwitches, TRUE)->Buffer); // TODO: ContextSwitchesDelta @@ -401,13 +401,13 @@ VOID PhpUpdateProcessStatistics( PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_NETWORKTXRXBYTES, 1, PhaFormatSize(processExtension->EnergyValues.NetworkTxRxBytes, ULONG_MAX)->Buffer); PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_MBBTXRXBYTES, 1, PhaFormatSize(processExtension->EnergyValues.MBBTxRxBytes, ULONG_MAX)->Buffer); } - + PhFree(processes); } } } -static VOID NTAPI StatisticsUpdateHandler( +static VOID NTAPI PhpStatisticsUpdateHandler( _In_opt_ PVOID Parameter, _In_opt_ PVOID Context ) @@ -470,7 +470,7 @@ INT_PTR CALLBACK PhpProcessStatisticsDlgProc( PhRegisterCallback( PhGetGeneralCallback(GeneralCallbackProcessProviderUpdatedEvent), - StatisticsUpdateHandler, + PhpStatisticsUpdateHandler, statisticsContext, &statisticsContext->ProcessesUpdatedRegistration ); From 3dbd1870e694a88ac78f57ecf73e0237a5ebe65a Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 19 May 2019 06:46:11 +0200 Subject: [PATCH 1920/2058] Fix debugger check failing for protected processes --- ProcessHacker/procprv.c | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/ProcessHacker/procprv.c b/ProcessHacker/procprv.c index c2482a8debbd..b2e5d59b6729 100644 --- a/ProcessHacker/procprv.c +++ b/ProcessHacker/procprv.c @@ -924,6 +924,17 @@ VOID PhpProcessQueryStage1( } } + // Debugged + if (processHandleLimited && !processItem->IsSubsystemProcess && !Data->IsFilteredHandle) // Don't query the debug object if the handle was filtered (dmex) + { + BOOLEAN isBeingDebugged; + + if (NT_SUCCESS(PhGetProcessIsBeingDebugged(processHandleLimited, &isBeingDebugged))) + { + Data->IsBeingDebugged = isBeingDebugged; + } + } + if (processItem->Sid) { // Note: We delay resolving the SID name because the local LSA cache might still be @@ -1379,8 +1390,7 @@ VOID PhpUpdateCpuInformation( for (i = 0; i < (ULONG)PhSystemBasicInformation.NumberOfProcessors; i++) { - PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION cpuInfo = - &PhCpuInformation[i]; + PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION cpuInfo = &PhCpuInformation[i]; // KernelTime includes IdleTime. cpuInfo->KernelTime.QuadPart -= cpuInfo->IdleTime.QuadPart; @@ -1407,8 +1417,8 @@ VOID PhpUpdateCpuInformation( } else { - PhCpusKernelUsage[i] = 0; - PhCpusUserUsage[i] = 0; + PhCpusKernelUsage[i] = 0.0f; + PhCpusUserUsage[i] = 0.0f; } } } @@ -1428,8 +1438,8 @@ VOID PhpUpdateCpuInformation( } else { - PhCpuKernelUsage = 0; - PhCpuUserUsage = 0; + PhCpuKernelUsage = 0.0f; + PhCpuUserUsage = 0.0f; } } @@ -2343,7 +2353,7 @@ VOID PhProcessProviderUpdate( } // Debugged - if (processItem->QueryHandle) + if (processItem->QueryHandle && !processItem->IsSubsystemProcess && !processItem->IsProtectedHandle) { BOOLEAN isBeingDebugged; @@ -2387,7 +2397,7 @@ VOID PhProcessProviderUpdate( } // Immersive - if (processItem->QueryHandle && WINDOWS_HAS_IMMERSIVE && IsImmersiveProcess) + if (processItem->QueryHandle && WINDOWS_HAS_IMMERSIVE && IsImmersiveProcess && !processItem->IsSubsystemProcess) { BOOLEAN isImmersive; From 84a9ffb16e361f368583cd4b22a40fbc0415a4d1 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 19 May 2019 06:46:27 +0200 Subject: [PATCH 1921/2058] Add missing file from previous commit --- ProcessHacker/procprv.c | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/ProcessHacker/procprv.c b/ProcessHacker/procprv.c index b2e5d59b6729..03407a14d9bd 100644 --- a/ProcessHacker/procprv.c +++ b/ProcessHacker/procprv.c @@ -766,17 +766,6 @@ VOID PhpProcessQueryStage1( PhInitializeImageVersionInfoCached(&Data->VersionInfo, processItem->FileName, FALSE); } - // Debugged - if (processHandleLimited && !processItem->IsSubsystemProcess) - { - BOOLEAN isBeingDebugged; - - if (NT_SUCCESS(PhGetProcessIsBeingDebugged(processHandleLimited, &isBeingDebugged))) - { - Data->IsBeingDebugged = isBeingDebugged; - } - } - // Command line, .NET if (processHandleLimited && !processItem->IsSubsystemProcess) { From e85482d6a2ad12c55fcdc071bea286384d139ea5 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 19 May 2019 06:47:16 +0200 Subject: [PATCH 1922/2058] Update macro usage --- ProcessHacker/procprp.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/ProcessHacker/procprp.c b/ProcessHacker/procprp.c index cd6ac286aacf..d44f6c24c1dd 100644 --- a/ProcessHacker/procprp.c +++ b/ProcessHacker/procprp.c @@ -149,7 +149,7 @@ INT CALLBACK PhpPropSheetProc( { if (lParam) { - if (((DLGTEMPLATEEX *)lParam)->signature == 0xffff) + if (((DLGTEMPLATEEX *)lParam)->signature == USHRT_MAX) { ((DLGTEMPLATEEX *)lParam)->style |= PROPSHEET_ADD_STYLE; } @@ -384,11 +384,9 @@ BOOLEAN PhAddProcessPropPage( // which would have added a reference. PhDereferenceObject(PropPageContext); - PropPageContext->PropContext = PropContext; - PhReferenceObject(PropContext); + PhSetReference(&PropPageContext->PropContext, PropContext); - PropContext->PropSheetPages[PropContext->PropSheetHeader.nPages] = - propSheetPageHandle; + PropContext->PropSheetPages[PropContext->PropSheetHeader.nPages] = propSheetPageHandle; PropContext->PropSheetHeader.nPages++; return TRUE; @@ -402,8 +400,7 @@ BOOLEAN PhAddProcessPropPage2( if (PropContext->PropSheetHeader.nPages == PH_PROCESS_PROPCONTEXT_MAXPAGES) return FALSE; - PropContext->PropSheetPages[PropContext->PropSheetHeader.nPages] = - PropSheetPageHandle; + PropContext->PropSheetPages[PropContext->PropSheetHeader.nPages] = PropSheetPageHandle; PropContext->PropSheetHeader.nPages++; return TRUE; @@ -427,9 +424,7 @@ PPH_PROCESS_PROPPAGECONTEXT PhCreateProcessPropPageContextEx( { PPH_PROCESS_PROPPAGECONTEXT propPageContext; - propPageContext = PhCreateObject(sizeof(PH_PROCESS_PROPPAGECONTEXT), PhpProcessPropPageContextType); - memset(propPageContext, 0, sizeof(PH_PROCESS_PROPPAGECONTEXT)); - + propPageContext = PhCreateObjectZero(sizeof(PH_PROCESS_PROPPAGECONTEXT), PhpProcessPropPageContextType); propPageContext->PropSheetPage.dwSize = sizeof(PROPSHEETPAGE); propPageContext->PropSheetPage.dwFlags = PSP_USECALLBACK; propPageContext->PropSheetPage.hInstance = InstanceHandle; From 4280f99b5d1db0ecc0211afc79883760f99169d9 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 20 May 2019 00:28:34 +0200 Subject: [PATCH 1923/2058] Fix debug highlighting --- ProcessHacker/procprv.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/ProcessHacker/procprv.c b/ProcessHacker/procprv.c index 03407a14d9bd..d7f5814c13f4 100644 --- a/ProcessHacker/procprv.c +++ b/ProcessHacker/procprv.c @@ -2344,12 +2344,11 @@ VOID PhProcessProviderUpdate( // Debugged if (processItem->QueryHandle && !processItem->IsSubsystemProcess && !processItem->IsProtectedHandle) { - BOOLEAN isBeingDebugged; + BOOLEAN isBeingDebugged = FALSE; - if (NT_SUCCESS(PhGetProcessIsBeingDebugged( - processItem->QueryHandle, - &isBeingDebugged - )) && processItem->IsBeingDebugged != isBeingDebugged) + PhGetProcessIsBeingDebugged(processItem->QueryHandle, &isBeingDebugged); + + if (processItem->IsBeingDebugged != isBeingDebugged) { processItem->IsBeingDebugged = isBeingDebugged; modified = TRUE; From e08dcfebf4032d13c1e835ea163dc69b23fe5b9d Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 20 May 2019 00:32:34 +0200 Subject: [PATCH 1924/2058] Fix build --- phlib/apiimport.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/phlib/apiimport.c b/phlib/apiimport.c index 5b6793c4d36e..22158c9933f4 100644 --- a/phlib/apiimport.c +++ b/phlib/apiimport.c @@ -75,9 +75,6 @@ _##Name Name##_Import(VOID) \ return (_##Name)PhpImportProcedure(&cache, &cacheValid, Module, #Name); \ } -PH_DEFINE_IMPORT(L"ntdll.dll", NtOpenProcess); -PH_DEFINE_IMPORT(L"ntdll.dll", NtOpenThread); -PH_DEFINE_IMPORT(L"ntdll.dll", NtTerminateProcess); PH_DEFINE_IMPORT(L"ntdll.dll", NtQueryInformationEnlistment); PH_DEFINE_IMPORT(L"ntdll.dll", NtQueryInformationResourceManager); PH_DEFINE_IMPORT(L"ntdll.dll", NtQueryInformationTransaction); From ecb6c09766a1813a09c05d96d4f9fc69cb267484 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 20 May 2019 02:44:22 +0200 Subject: [PATCH 1925/2058] peview: Add description to propstore tab --- tools/peview/propstore.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tools/peview/propstore.c b/tools/peview/propstore.c index 328d1e756dd9..f2b5a34152f4 100644 --- a/tools/peview/propstore.c +++ b/tools/peview/propstore.c @@ -81,7 +81,23 @@ VOID PvpPeEnumerateFilePropStore( if (SUCCEEDED(PSGetNameFromPropertyKey(&propkey, &propKeyName))) { + IPropertyDescription* propertyDescriptionPtr = NULL; + PhSetListViewSubItem(ListViewHandle, lvItemIndex, 1, propKeyName); + + if (SUCCEEDED(PSGetPropertyDescriptionByName(propKeyName, &IID_IPropertyDescription, &propertyDescriptionPtr))) + { + PWSTR propertyLabel = NULL; + + if (SUCCEEDED(IPropertyDescription_GetDisplayName(propertyDescriptionPtr, &propertyLabel))) + { + PhSetListViewSubItem(ListViewHandle, lvItemIndex, 3, propertyLabel); + CoTaskMemFree(propertyLabel); + } + + IPropertyDescription_Release(propertyDescriptionPtr); + } + CoTaskMemFree(propKeyName); } else @@ -137,6 +153,7 @@ INT_PTR CALLBACK PvpPePropStoreDlgProc( PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 40, L"#"); PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 150, L"Name"); PhAddListViewColumn(lvHandle, 2, 2, 2, LVCFMT_LEFT, 250, L"Value"); + PhAddListViewColumn(lvHandle, 3, 3, 3, LVCFMT_LEFT, 150, L"Description"); PhSetExtendedListView(lvHandle); PhLoadListViewColumnsFromSetting(L"ImagePropertiesListViewColumns", lvHandle); From 113ff63d239a276b5233165c4bc229ad7eda3a08 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 22 May 2019 05:03:42 +0200 Subject: [PATCH 1926/2058] Fix service notification leak --- ProcessHacker/srvprv.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/ProcessHacker/srvprv.c b/ProcessHacker/srvprv.c index 5d89dd2aacab..98163cfe2923 100644 --- a/ProcessHacker/srvprv.c +++ b/ProcessHacker/srvprv.c @@ -1164,7 +1164,7 @@ NTSTATUS PhpServiceNonPollThreadStart( while (TRUE) { - scManagerHandle = OpenSCManager(NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE); + scManagerHandle = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT | SC_MANAGER_ENUMERATE_SERVICE); if (!scManagerHandle) goto ErrorExit; @@ -1243,6 +1243,15 @@ NTSTATUS PhpServiceNonPollThreadStart( __fallthrough; case SnNotify: { + if (notifyContext->NotifyRegistration) + { + if (UnsubscribeServiceChangeNotifications_I && notifyContext->NotifyRegistration) + UnsubscribeServiceChangeNotifications_I(notifyContext->NotifyRegistration); + + notifyContext->JustAddedNotifyRegistration = FALSE; + notifyContext->NotifyRegistration = NULL; + } + if (SubscribeServiceChangeNotifications_I && !notifyContext->IsServiceManager) { PSC_NOTIFICATION_REGISTRATION serviceNotifyRegistration; From 280597e64885b8c7c6a7d6f96249ccb3dfaa3022 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 22 May 2019 05:04:36 +0200 Subject: [PATCH 1927/2058] Disable ServiceNonPoll by default --- ProcessHacker/settings.c | 2 +- ProcessHacker/srvlist.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ProcessHacker/settings.c b/ProcessHacker/settings.c index 581ebe2e2153..656fe91918aa 100644 --- a/ProcessHacker/settings.c +++ b/ProcessHacker/settings.c @@ -47,7 +47,7 @@ VOID PhAddDefaultSettings( PhpAddIntegerSetting(L"EnableHandleSnapshot", L"1"); PhpAddIntegerSetting(L"EnableNetworkResolve", L"1"); PhpAddIntegerSetting(L"EnablePlugins", L"1"); - PhpAddIntegerSetting(L"EnableServiceNonPoll", L"1"); + PhpAddIntegerSetting(L"EnableServiceNonPoll", L"0"); PhpAddIntegerSetting(L"EnableStage2", L"1"); PhpAddIntegerSetting(L"EnableServiceStage2", L"0"); PhpAddIntegerSetting(L"EnableWarnings", L"1"); diff --git a/ProcessHacker/srvlist.c b/ProcessHacker/srvlist.c index 3f1a566afd94..ccaa88dc1180 100644 --- a/ProcessHacker/srvlist.c +++ b/ProcessHacker/srvlist.c @@ -679,7 +679,7 @@ BOOLEAN NTAPI PhpServiceTreeNewCallback( switch (getCellText->Id) { case PHSVTLC_NAME: - getCellText->Text = serviceItem->Name->sr; + getCellText->Text = PhGetStringRef(serviceItem->Name); break; case PHSVTLC_DISPLAYNAME: getCellText->Text = PhGetStringRef(serviceItem->DisplayName); From 5bb5caf9e0cdef4298218ad1879dc7523d29bdff Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 22 May 2019 05:05:25 +0200 Subject: [PATCH 1928/2058] Fix some warnings, Fix PhLoadIndirectString parsing non-INF entries --- phlib/util.c | 2 +- phlib/verify.c | 35 +++++++++++++++++++++-------------- 2 files changed, 22 insertions(+), 15 deletions(-) diff --git a/phlib/util.c b/phlib/util.c index 0404a50130ac..f6451aaebeb8 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -5502,7 +5502,7 @@ PPH_STRING PhLoadIndirectString( // HACK: Services.exe includes custom logic for indirect Service description strings by reading descriptions from inf files, // these strings use the following format: "@FileName.inf,%SectionKeyName%;DefaultString". // Return the last token of the service string instead of locating and parsing the inf file with GetPrivateProfileString. - if (dllIndexRef.Buffer[0] == L'%' && PhSplitStringRefAtChar(&sourceRef, L';', &dllNameRef, &dllIndexRef)) + if (PhSplitStringRefAtChar(&sourceRef, L';', &dllNameRef, &dllIndexRef)) // dllIndexRef.Buffer[0] == L'%' return PhCreateString2(&dllIndexRef); else return NULL; diff --git a/phlib/verify.c b/phlib/verify.c index 7bfddad6c6ff..c7246bcdea81 100644 --- a/phlib/verify.c +++ b/phlib/verify.c @@ -60,20 +60,27 @@ static VOID PhpVerifyInitialization( wintrust = LoadLibrary(L"wintrust.dll"); crypt32 = LoadLibrary(L"crypt32.dll"); - CryptCATAdminCalcHashFromFileHandle = PhGetDllBaseProcedureAddress(wintrust, "CryptCATAdminCalcHashFromFileHandle", 0); - CryptCATAdminCalcHashFromFileHandle2 = PhGetDllBaseProcedureAddress(wintrust, "CryptCATAdminCalcHashFromFileHandle2", 0); - CryptCATAdminAcquireContext = PhGetDllBaseProcedureAddress(wintrust, "CryptCATAdminAcquireContext", 0); - CryptCATAdminAcquireContext2 = PhGetDllBaseProcedureAddress(wintrust, "CryptCATAdminAcquireContext2", 0); - CryptCATAdminEnumCatalogFromHash = PhGetDllBaseProcedureAddress(wintrust, "CryptCATAdminEnumCatalogFromHash", 0); - CryptCATCatalogInfoFromContext = PhGetDllBaseProcedureAddress(wintrust, "CryptCATCatalogInfoFromContext", 0); - CryptCATAdminReleaseCatalogContext = PhGetDllBaseProcedureAddress(wintrust, "CryptCATAdminReleaseCatalogContext", 0); - CryptCATAdminReleaseContext = PhGetDllBaseProcedureAddress(wintrust, "CryptCATAdminReleaseContext", 0); - WTHelperProvDataFromStateData_I = PhGetDllBaseProcedureAddress(wintrust, "WTHelperProvDataFromStateData", 0); - WTHelperGetProvSignerFromChain_I = PhGetDllBaseProcedureAddress(wintrust, "WTHelperGetProvSignerFromChain", 0); - WinVerifyTrust_I = PhGetDllBaseProcedureAddress(wintrust, "WinVerifyTrust", 0); - CertNameToStr_I = PhGetDllBaseProcedureAddress(crypt32, "CertNameToStrW", 0); - CertDuplicateCertificateContext_I = PhGetDllBaseProcedureAddress(crypt32, "CertDuplicateCertificateContext", 0); - CertFreeCertificateContext_I = PhGetDllBaseProcedureAddress(crypt32, "CertFreeCertificateContext", 0); + if (wintrust) + { + CryptCATAdminCalcHashFromFileHandle = PhGetDllBaseProcedureAddress(wintrust, "CryptCATAdminCalcHashFromFileHandle", 0); + CryptCATAdminCalcHashFromFileHandle2 = PhGetDllBaseProcedureAddress(wintrust, "CryptCATAdminCalcHashFromFileHandle2", 0); + CryptCATAdminAcquireContext = PhGetDllBaseProcedureAddress(wintrust, "CryptCATAdminAcquireContext", 0); + CryptCATAdminAcquireContext2 = PhGetDllBaseProcedureAddress(wintrust, "CryptCATAdminAcquireContext2", 0); + CryptCATAdminEnumCatalogFromHash = PhGetDllBaseProcedureAddress(wintrust, "CryptCATAdminEnumCatalogFromHash", 0); + CryptCATCatalogInfoFromContext = PhGetDllBaseProcedureAddress(wintrust, "CryptCATCatalogInfoFromContext", 0); + CryptCATAdminReleaseCatalogContext = PhGetDllBaseProcedureAddress(wintrust, "CryptCATAdminReleaseCatalogContext", 0); + CryptCATAdminReleaseContext = PhGetDllBaseProcedureAddress(wintrust, "CryptCATAdminReleaseContext", 0); + WTHelperProvDataFromStateData_I = PhGetDllBaseProcedureAddress(wintrust, "WTHelperProvDataFromStateData", 0); + WTHelperGetProvSignerFromChain_I = PhGetDllBaseProcedureAddress(wintrust, "WTHelperGetProvSignerFromChain", 0); + WinVerifyTrust_I = PhGetDllBaseProcedureAddress(wintrust, "WinVerifyTrust", 0); + } + + if (crypt32) + { + CertNameToStr_I = PhGetDllBaseProcedureAddress(crypt32, "CertNameToStrW", 0); + CertDuplicateCertificateContext_I = PhGetDllBaseProcedureAddress(crypt32, "CertDuplicateCertificateContext", 0); + CertFreeCertificateContext_I = PhGetDllBaseProcedureAddress(crypt32, "CertFreeCertificateContext", 0); + } } VERIFY_RESULT PhpStatusToVerifyResult( From 77c9a747678cd5b5615a028e4e5d730c9d7a6b21 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 24 May 2019 22:48:31 +0200 Subject: [PATCH 1929/2058] WindowExplorer: Add font name to window properties --- plugins/WindowExplorer/wndprp.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/plugins/WindowExplorer/wndprp.c b/plugins/WindowExplorer/wndprp.c index 9a453009d2fe..bbaef1610bea 100644 --- a/plugins/WindowExplorer/wndprp.c +++ b/plugins/WindowExplorer/wndprp.c @@ -94,6 +94,7 @@ typedef enum _NETADAPTER_DETAILS_INDEX WINDOW_PROPERTIES_INDEX_WNDPROC, WINDOW_PROPERTIES_INDEX_DLGPROC, WINDOW_PROPERTIES_INDEX_DLGCTLID, + WINDOW_PROPERTIES_INDEX_FONTNAME, WINDOW_PROPERTIES_INDEX_STYLES, WINDOW_PROPERTIES_INDEX_EXSTYLES, @@ -457,6 +458,7 @@ VOID WepRefreshWindowGeneralInfo( PVOID instanceHandle; PVOID userdataHandle; ULONG windowId; + HFONT fontHandle; menuHandle = GetMenu(Context->WindowHandle); instanceHandle = (PVOID)GetWindowLongPtr(Context->WindowHandle, GWLP_HINSTANCE); @@ -529,6 +531,20 @@ VOID WepRefreshWindowGeneralInfo( PhSetListViewSubItem(ListViewHandle, WINDOW_PROPERTIES_INDEX_UNICODE, 1, IsWindowUnicode(Context->WindowHandle) ? L"Yes" : L"No"); PhSetListViewSubItem(ListViewHandle, WINDOW_PROPERTIES_INDEX_DLGCTLID, 1, PhaFormatString(L"%lu", windowId)->Buffer); + if (fontHandle = (HFONT)SendMessage(Context->WindowHandle, WM_GETFONT, 0, 0)) + { + LOGFONT logFont; + + if (GetObject(fontHandle, sizeof(LOGFONT), &logFont)) + PhSetListViewSubItem(ListViewHandle, WINDOW_PROPERTIES_INDEX_FONTNAME, 1, logFont.lfFaceName); + else + PhSetListViewSubItem(ListViewHandle, WINDOW_PROPERTIES_INDEX_FONTNAME, 1, L"N/A"); + } + else + { + PhSetListViewSubItem(ListViewHandle, WINDOW_PROPERTIES_INDEX_FONTNAME, 1, L"N/A"); + } + //ULONG version; //if (SendMessageTimeout(Context->WindowHandle, CCM_GETVERSION, 0, 0, SMTO_ABORTIFHUNG, 5000, &version)) //WepQueryProcessWndProc(Context); @@ -799,6 +815,7 @@ VOID WepGeneralAddListViewItemGroups( PhAddListViewGroupItem(ListViewHandle, WINDOW_PROPERTIES_CATEGORY_GENERAL, WINDOW_PROPERTIES_INDEX_WNDPROC, L"Window procedure", NULL); PhAddListViewGroupItem(ListViewHandle, WINDOW_PROPERTIES_CATEGORY_GENERAL, WINDOW_PROPERTIES_INDEX_DLGPROC, L"Dialog procedure", NULL); PhAddListViewGroupItem(ListViewHandle, WINDOW_PROPERTIES_CATEGORY_GENERAL, WINDOW_PROPERTIES_INDEX_DLGCTLID, L"Dialog control ID", NULL); + PhAddListViewGroupItem(ListViewHandle, WINDOW_PROPERTIES_CATEGORY_GENERAL, WINDOW_PROPERTIES_INDEX_FONTNAME, L"Font", NULL); PhAddListViewGroupItem(ListViewHandle, WINDOW_PROPERTIES_CATEGORY_GENERAL, WINDOW_PROPERTIES_INDEX_STYLES, L"Styles", NULL); PhAddListViewGroupItem(ListViewHandle, WINDOW_PROPERTIES_CATEGORY_GENERAL, WINDOW_PROPERTIES_INDEX_EXSTYLES, L"Extended styles", NULL); PhAddListViewGroupItem(ListViewHandle, WINDOW_PROPERTIES_CATEGORY_CLASS, WINDOW_PROPERTIES_INDEX_CLASS_NAME, L"Name", NULL); From 331af4ade82309be7443bb75541407efc7f11336 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 29 May 2019 17:26:08 +0200 Subject: [PATCH 1930/2058] Fix #421 --- tools/CustomSetupTool/CustomSetupTool/install.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/tools/CustomSetupTool/CustomSetupTool/install.c b/tools/CustomSetupTool/CustomSetupTool/install.c index e25c9db1c155..53d183529d6f 100644 --- a/tools/CustomSetupTool/CustomSetupTool/install.c +++ b/tools/CustomSetupTool/CustomSetupTool/install.c @@ -38,18 +38,16 @@ NTSTATUS SetupProgressThread( if (!SetupUninstallKph(Context)) goto CleanupExit; - // Create the install folder path. - if (!NT_SUCCESS(PhCreateDirectory(SetupInstallPath))) - goto CleanupExit; - // Upgrade the 2.x settings file. SetupUpgradeSettingsFile(); // Remove the previous installation. if (Context->SetupResetSettings) - { PhDeleteDirectory(SetupInstallPath); - } + + // Create the install folder path. + if (!NT_SUCCESS(PhCreateDirectory(SetupInstallPath))) + goto CleanupExit; // Create the uninstaller. if (!SetupCreateUninstallFile(Context)) @@ -216,4 +214,4 @@ INT_PTR CALLBACK SetupInstallPropPage_WndProc( } return FALSE; -} \ No newline at end of file +} From dd6ce8f5ab5544ee0e2a7a676c03f40c88fb3d33 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 30 May 2019 16:29:06 +0200 Subject: [PATCH 1931/2058] Enable dark listview scrollbar on RS6 --- phlib/theme.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/phlib/theme.c b/phlib/theme.c index b9b339983d56..04b4eceea6c3 100644 --- a/phlib/theme.c +++ b/phlib/theme.c @@ -468,6 +468,19 @@ BOOLEAN CALLBACK PhpThemeWindowEnumChildWindows( } else if (PhEqualStringZ(windowClassName, L"SysListView32", FALSE)) { + if (WindowsVersion >= WINDOWS_10_RS5) + { + switch (PhpThemeColorMode) + { + case 0: // New colors + PhSetControlTheme(WindowHandle, L"explorer"); + break; + case 1: // Old colors + PhSetControlTheme(WindowHandle, L"DarkMode_Explorer"); + break; + } + } + if (PhpThemeBorderEnable) { PhSetWindowStyle(WindowHandle, WS_BORDER, WS_BORDER); @@ -580,6 +593,19 @@ BOOLEAN CALLBACK PhpReInitializeThemeWindowEnumChildWindows( if (PhEqualStringZ(windowClassName, L"SysListView32", FALSE)) { + if (WindowsVersion >= WINDOWS_10_RS5) + { + switch (PhpThemeColorMode) + { + case 0: // New colors + PhSetControlTheme(WindowHandle, L"explorer"); + break; + case 1: // Old colors + PhSetControlTheme(WindowHandle, L"DarkMode_Explorer"); + break; + } + } + switch (PhpThemeColorMode) { case 0: // New colors From a29338f15a0147d0a063a6ee6417d34ded15fab1 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 30 May 2019 16:30:50 +0200 Subject: [PATCH 1932/2058] Update mapimg.c --- phlib/mapimg.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/phlib/mapimg.c b/phlib/mapimg.c index 3a9f7905d58e..d9d77bc132af 100644 --- a/phlib/mapimg.c +++ b/phlib/mapimg.c @@ -86,12 +86,12 @@ NTSTATUS PhInitializeMappedImage( PhpMappedImageProbe( MappedImage, MappedImage->NtHeaders, - FIELD_OFFSET(IMAGE_NT_HEADERS, OptionalHeader) + UFIELD_OFFSET(IMAGE_NT_HEADERS, OptionalHeader) ); PhpMappedImageProbe( MappedImage, MappedImage->NtHeaders, - FIELD_OFFSET(IMAGE_NT_HEADERS, OptionalHeader) + + UFIELD_OFFSET(IMAGE_NT_HEADERS, OptionalHeader) + MappedImage->NtHeaders->FileHeader.SizeOfOptionalHeader + MappedImage->NtHeaders->FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER) ); From 21eb8927f6c0de1106a283f8ee276a818d6d2612 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 30 May 2019 16:54:54 +0200 Subject: [PATCH 1933/2058] peview: disable section hash --- tools/peview/peprp.c | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/tools/peview/peprp.c b/tools/peview/peprp.c index 4a94e9bd4b09..95ee0bda7f4b 100644 --- a/tools/peview/peprp.c +++ b/tools/peview/peprp.c @@ -708,26 +708,26 @@ VOID PvpSetPeImageSections( PhSetListViewSubItem(ListViewHandle, lvItemIndex, 2, PhaFormatSize(PvMappedImage.Sections[i].SizeOfRawData, ULONG_MAX)->Buffer); PhSetListViewSubItem(ListViewHandle, lvItemIndex, 3, PH_AUTO_T(PH_STRING, PvpGetSectionCharacteristics(PvMappedImage.Sections[i].Characteristics))->Buffer); - if (PvMappedImage.Sections[i].VirtualAddress && PvMappedImage.Sections[i].SizeOfRawData) - { - PVOID imageSectionData; - PH_HASH_CONTEXT hashContext; - PPH_STRING hashString; - UCHAR hash[32]; - - if (imageSectionData = PhMappedImageRvaToVa(&PvMappedImage, PvMappedImage.Sections[i].VirtualAddress, NULL)) - { - PhInitializeHash(&hashContext, Md5HashAlgorithm); // PhGetIntegerSetting(L"HashAlgorithm") - PhUpdateHash(&hashContext, imageSectionData, PvMappedImage.Sections[i].SizeOfRawData); - - if (PhFinalHash(&hashContext, hash, 16, NULL)) - { - hashString = PhBufferToHexString(hash, 16); - PhSetListViewSubItem(ListViewHandle, lvItemIndex, 4, hashString->Buffer); - PhDereferenceObject(hashString); - } - } - } + //if (PvMappedImage.Sections[i].VirtualAddress && PvMappedImage.Sections[i].SizeOfRawData) + //{ + // PVOID imageSectionData; + // PH_HASH_CONTEXT hashContext; + // PPH_STRING hashString; + // UCHAR hash[32]; + // + // if (imageSectionData = PhMappedImageRvaToVa(&PvMappedImage, PvMappedImage.Sections[i].VirtualAddress, NULL)) + // { + // PhInitializeHash(&hashContext, Md5HashAlgorithm); // PhGetIntegerSetting(L"HashAlgorithm") + // PhUpdateHash(&hashContext, imageSectionData, PvMappedImage.Sections[i].SizeOfRawData); + // + // if (PhFinalHash(&hashContext, hash, 16, NULL)) + // { + // hashString = PhBufferToHexString(hash, 16); + // PhSetListViewSubItem(ListViewHandle, lvItemIndex, 4, hashString->Buffer); + // PhDereferenceObject(hashString); + // } + // } + //} } } } @@ -880,7 +880,7 @@ INT_PTR CALLBACK PvpPeGeneralDlgProc( PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 80, L"VA"); PhAddListViewColumn(lvHandle, 2, 2, 2, LVCFMT_LEFT, 80, L"Size"); PhAddListViewColumn(lvHandle, 3, 3, 3, LVCFMT_LEFT, 250, L"Characteristics"); - PhAddListViewColumn(lvHandle, 4, 4, 4, LVCFMT_LEFT, 80, L"Hash"); + //PhAddListViewColumn(lvHandle, 4, 4, 4, LVCFMT_LEFT, 80, L"Hash"); PhLoadListViewColumnsFromSetting(L"ImageGeneralListViewColumns", lvHandle); // File version information From f3fd5c379971d365c0896a9c6e181f6c66d1c9df Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 6 Jun 2019 05:41:25 +0200 Subject: [PATCH 1934/2058] Update process statistics tab with pool usage --- ProcessHacker/prpgstat.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/ProcessHacker/prpgstat.c b/ProcessHacker/prpgstat.c index f2c8cea914c3..068d49aa8c08 100644 --- a/ProcessHacker/prpgstat.c +++ b/ProcessHacker/prpgstat.c @@ -85,6 +85,11 @@ typedef enum _PH_PROCESS_STATISTICS_INDEX PH_PROCESS_STATISTICS_INDEX_GDIHANDLES, PH_PROCESS_STATISTICS_INDEX_USERHANDLES, + PH_PROCESS_STATISTICS_INDEX_PAGEDPOOL, + PH_PROCESS_STATISTICS_INDEX_PEAKPAGEDPOOL, + PH_PROCESS_STATISTICS_INDEX_NONPAGED, + PH_PROCESS_STATISTICS_INDEX_PEAKNONPAGED, + PH_PROCESS_STATISTICS_INDEX_RUNNINGTIME, PH_PROCESS_STATISTICS_INDEX_SUSPENDEDTIME, PH_PROCESS_STATISTICS_INDEX_HANGCOUNT, @@ -126,12 +131,15 @@ VOID PhpUpdateStatisticsAddListViewGroups( PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_MEMORY, PH_PROCESS_STATISTICS_INDEX_PEAKVIRTUALSIZE, L"Peak virtual size", NULL); PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_MEMORY, PH_PROCESS_STATISTICS_INDEX_PAGEFAULTS, L"Page faults", NULL); PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_MEMORY, PH_PROCESS_STATISTICS_INDEX_PAGEFAULTSDELTA, L"Page faults delta", NULL); - PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_MEMORY, PH_PROCESS_STATISTICS_INDEX_WORKINGSET, L"Working set", NULL); PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_MEMORY, PH_PROCESS_STATISTICS_INDEX_PEAKWORKINGSET, L"Peak working set", NULL); PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_MEMORY, PH_PROCESS_STATISTICS_INDEX_PRIVATEWS, L"Private WS", NULL); PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_MEMORY, PH_PROCESS_STATISTICS_INDEX_SHAREABLEWS, L"Shareable WS", NULL); PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_MEMORY, PH_PROCESS_STATISTICS_INDEX_SHAREDWS, L"Shared WS", NULL); + PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_MEMORY, PH_PROCESS_STATISTICS_INDEX_PAGEDPOOL, L"Paged pool bytes", NULL); + PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_MEMORY, PH_PROCESS_STATISTICS_INDEX_PEAKPAGEDPOOL, L"Peak paged pool bytes", NULL); + PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_MEMORY, PH_PROCESS_STATISTICS_INDEX_NONPAGED, L"Nonpaged pool bytes", NULL); + PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_MEMORY, PH_PROCESS_STATISTICS_INDEX_PEAKNONPAGED, L"Peak nonpaged pool bytes", NULL); PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_MEMORY, PH_PROCESS_STATISTICS_INDEX_PAGEPRIORITY, L"Page priority", NULL); PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_IO, PH_PROCESS_STATISTICS_INDEX_READS, L"Reads", NULL); @@ -266,6 +274,11 @@ VOID PhpUpdateProcessStatistics( PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_WORKINGSET, 1, PhaFormatSize(ProcessItem->VmCounters.WorkingSetSize, ULONG_MAX)->Buffer); PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_PEAKWORKINGSET, 1, PhaFormatSize(ProcessItem->VmCounters.PeakWorkingSetSize, ULONG_MAX)->Buffer); + PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_PAGEDPOOL, 1, PhaFormatSize(ProcessItem->VmCounters.QuotaPagedPoolUsage, ULONG_MAX)->Buffer); + PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_PEAKPAGEDPOOL, 1, PhaFormatSize(ProcessItem->VmCounters.QuotaPeakPagedPoolUsage, ULONG_MAX)->Buffer); + PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_NONPAGED, 1, PhaFormatSize(ProcessItem->VmCounters.QuotaNonPagedPoolUsage, ULONG_MAX)->Buffer); + PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_PEAKNONPAGED, 1, PhaFormatSize(ProcessItem->VmCounters.QuotaPeakNonPagedPoolUsage, ULONG_MAX)->Buffer); + PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_READS, 1, PhaFormatUInt64(ProcessItem->IoCounters.ReadOperationCount, TRUE)->Buffer); PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_READSDELTA, 1, PhaFormatUInt64(ProcessItem->IoReadCountDelta.Delta, TRUE)->Buffer); PhSetListViewSubItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_INDEX_READBYTES, 1, PhaFormatSize(ProcessItem->IoCounters.ReadTransferCount, ULONG_MAX)->Buffer); From 717092e84ccb76e14a43c904d88d2ccf5e6ca7a5 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 8 Jun 2019 00:01:54 +0200 Subject: [PATCH 1935/2058] Update solutions to VS 2019, Update Appveyor build image to VS 2019 --- ProcessHacker/ProcessHacker.vcxproj | 10 +++++----- appveyor.yml | 2 +- phlib/phlib.vcxproj | 10 +++++----- plugins/DotNetTools/DotNetTools.vcxproj | 10 +++++----- .../ExtendedNotifications.vcxproj | 10 +++++----- plugins/ExtendedServices/ExtendedServices.vcxproj | 10 +++++----- plugins/ExtendedTools/ExtendedTools.vcxproj | 10 +++++----- plugins/HardwareDevices/HardwareDevices.vcxproj | 10 +++++----- plugins/NetworkTools/NetworkTools.vcxproj | 10 +++++----- plugins/OnlineChecks/OnlineChecks.vcxproj | 10 +++++----- plugins/ToolStatus/ToolStatus.vcxproj | 10 +++++----- plugins/Updater/Updater.vcxproj | 10 +++++----- plugins/UserNotes/UserNotes.vcxproj | 10 +++++----- plugins/WindowExplorer/WindowExplorer.vcxproj | 10 +++++----- .../CustomSetupTool/CustomSetupTool.vcxproj | 6 +++--- tools/peview/peview.vcxproj | 10 +++++----- 16 files changed, 74 insertions(+), 74 deletions(-) diff --git a/ProcessHacker/ProcessHacker.vcxproj b/ProcessHacker/ProcessHacker.vcxproj index 2424f13fc227..6a83f0e98fb6 100644 --- a/ProcessHacker/ProcessHacker.vcxproj +++ b/ProcessHacker/ProcessHacker.vcxproj @@ -22,14 +22,14 @@ {0271DD27-6707-4290-8DFE-285702B7115D} ProcessHacker Win32Proj - 10.0.17763.0 + 10.0 Application Unicode true - v141 + v142 WindowsLocalDebugger $(SolutionDir)bin\$(Configuration)$(PlatformArchitecture)\ Spectre @@ -37,7 +37,7 @@ Application Unicode - v141 + v142 WindowsLocalDebugger $(SolutionDir)bin\$(Configuration)$(PlatformArchitecture)\ @@ -45,7 +45,7 @@ Application Unicode true - v141 + v142 WindowsLocalDebugger $(SolutionDir)bin\$(Configuration)$(PlatformArchitecture)\ Spectre @@ -53,7 +53,7 @@ Application Unicode - v141 + v142 WindowsLocalDebugger $(SolutionDir)bin\$(Configuration)$(PlatformArchitecture)\ diff --git a/appveyor.yml b/appveyor.yml index c71e48f79d57..321ce514fe26 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,5 +1,5 @@ # Build image. -image: Visual Studio 2017 +image: Visual Studio 2019 # Version format. version: "#{build}" diff --git a/phlib/phlib.vcxproj b/phlib/phlib.vcxproj index dceab869782f..c927de8a9cfd 100644 --- a/phlib/phlib.vcxproj +++ b/phlib/phlib.vcxproj @@ -22,32 +22,32 @@ {477D0215-F252-41A1-874B-F27E3EA1ED17} phlib Win32Proj - 10.0.17763.0 + 10.0 StaticLibrary Unicode true - v141 + v142 Spectre StaticLibrary Unicode - v141 + v142 StaticLibrary Unicode true - v141 + v142 Spectre StaticLibrary Unicode - v141 + v142 diff --git a/plugins/DotNetTools/DotNetTools.vcxproj b/plugins/DotNetTools/DotNetTools.vcxproj index 66df5200d23f..5c635ebbb2ea 100644 --- a/plugins/DotNetTools/DotNetTools.vcxproj +++ b/plugins/DotNetTools/DotNetTools.vcxproj @@ -23,28 +23,28 @@ DotNetTools Win32Proj DotNetTools - 10.0.17763.0 + 10.0 DynamicLibrary Unicode - v141 + v142 DynamicLibrary Unicode - v141 + v142 DynamicLibrary Unicode - v141 + v142 DynamicLibrary Unicode - v141 + v142 diff --git a/plugins/ExtendedNotifications/ExtendedNotifications.vcxproj b/plugins/ExtendedNotifications/ExtendedNotifications.vcxproj index 41fdf7c61cdd..d8d8c7d64ed8 100644 --- a/plugins/ExtendedNotifications/ExtendedNotifications.vcxproj +++ b/plugins/ExtendedNotifications/ExtendedNotifications.vcxproj @@ -23,28 +23,28 @@ ExtendedNotifications Win32Proj ExtendedNotifications - 10.0.17763.0 + 10.0 DynamicLibrary Unicode - v141 + v142 DynamicLibrary Unicode - v141 + v142 DynamicLibrary Unicode - v141 + v142 DynamicLibrary Unicode - v141 + v142 diff --git a/plugins/ExtendedServices/ExtendedServices.vcxproj b/plugins/ExtendedServices/ExtendedServices.vcxproj index 073a89063451..1bf18d1db0a0 100644 --- a/plugins/ExtendedServices/ExtendedServices.vcxproj +++ b/plugins/ExtendedServices/ExtendedServices.vcxproj @@ -23,28 +23,28 @@ ExtendedServices Win32Proj ExtendedServices - 10.0.17763.0 + 10.0 DynamicLibrary Unicode - v141 + v142 DynamicLibrary Unicode - v141 + v142 DynamicLibrary Unicode - v141 + v142 DynamicLibrary Unicode - v141 + v142 diff --git a/plugins/ExtendedTools/ExtendedTools.vcxproj b/plugins/ExtendedTools/ExtendedTools.vcxproj index 1a92f5ef1f1f..3ffc4f1cf357 100644 --- a/plugins/ExtendedTools/ExtendedTools.vcxproj +++ b/plugins/ExtendedTools/ExtendedTools.vcxproj @@ -23,28 +23,28 @@ ExtendedTools Win32Proj ExtendedTools - 10.0.17763.0 + 10.0 DynamicLibrary Unicode - v141 + v142 DynamicLibrary Unicode - v141 + v142 DynamicLibrary Unicode - v141 + v142 DynamicLibrary Unicode - v141 + v142 diff --git a/plugins/HardwareDevices/HardwareDevices.vcxproj b/plugins/HardwareDevices/HardwareDevices.vcxproj index 39b3efefb8ba..0ce216dcb72c 100644 --- a/plugins/HardwareDevices/HardwareDevices.vcxproj +++ b/plugins/HardwareDevices/HardwareDevices.vcxproj @@ -23,28 +23,28 @@ HardwareDevices Win32Proj HardwareDevices - 10.0.17763.0 + 10.0 DynamicLibrary Unicode - v141 + v142 DynamicLibrary Unicode - v141 + v142 DynamicLibrary Unicode - v141 + v142 DynamicLibrary Unicode - v141 + v142 diff --git a/plugins/NetworkTools/NetworkTools.vcxproj b/plugins/NetworkTools/NetworkTools.vcxproj index f55bd1e227a5..49031ce6f2d2 100644 --- a/plugins/NetworkTools/NetworkTools.vcxproj +++ b/plugins/NetworkTools/NetworkTools.vcxproj @@ -23,28 +23,28 @@ NetworkTools Win32Proj NetworkTools - 10.0.17763.0 + 10.0 DynamicLibrary Unicode - v141 + v142 DynamicLibrary Unicode - v141 + v142 DynamicLibrary Unicode - v141 + v142 DynamicLibrary Unicode - v141 + v142 diff --git a/plugins/OnlineChecks/OnlineChecks.vcxproj b/plugins/OnlineChecks/OnlineChecks.vcxproj index ce8e88b3d4c2..fef273413f95 100644 --- a/plugins/OnlineChecks/OnlineChecks.vcxproj +++ b/plugins/OnlineChecks/OnlineChecks.vcxproj @@ -23,28 +23,28 @@ OnlineChecks Win32Proj OnlineChecks - 10.0.17763.0 + 10.0 DynamicLibrary Unicode - v141 + v142 DynamicLibrary Unicode - v141 + v142 DynamicLibrary Unicode - v141 + v142 DynamicLibrary Unicode - v141 + v142 diff --git a/plugins/ToolStatus/ToolStatus.vcxproj b/plugins/ToolStatus/ToolStatus.vcxproj index b31153c1de42..45ae6d69d8ee 100644 --- a/plugins/ToolStatus/ToolStatus.vcxproj +++ b/plugins/ToolStatus/ToolStatus.vcxproj @@ -23,28 +23,28 @@ ToolStatus Win32Proj ToolStatus - 10.0.17763.0 + 10.0 DynamicLibrary Unicode - v141 + v142 DynamicLibrary Unicode - v141 + v142 DynamicLibrary Unicode - v141 + v142 DynamicLibrary Unicode - v141 + v142 diff --git a/plugins/Updater/Updater.vcxproj b/plugins/Updater/Updater.vcxproj index 4434a44bdb14..07b112497684 100644 --- a/plugins/Updater/Updater.vcxproj +++ b/plugins/Updater/Updater.vcxproj @@ -23,28 +23,28 @@ Updater Win32Proj Updater - 10.0.17763.0 + 10.0 DynamicLibrary Unicode - v141 + v142 DynamicLibrary Unicode - v141 + v142 DynamicLibrary Unicode - v141 + v142 DynamicLibrary Unicode - v141 + v142 diff --git a/plugins/UserNotes/UserNotes.vcxproj b/plugins/UserNotes/UserNotes.vcxproj index 72732b329e56..48436c6458ce 100644 --- a/plugins/UserNotes/UserNotes.vcxproj +++ b/plugins/UserNotes/UserNotes.vcxproj @@ -23,28 +23,28 @@ UserNotes Win32Proj UserNotes - 10.0.17763.0 + 10.0 DynamicLibrary Unicode - v141 + v142 DynamicLibrary Unicode - v141 + v142 DynamicLibrary Unicode - v141 + v142 DynamicLibrary Unicode - v141 + v142 diff --git a/plugins/WindowExplorer/WindowExplorer.vcxproj b/plugins/WindowExplorer/WindowExplorer.vcxproj index 4183ef6b9d99..467f05833956 100644 --- a/plugins/WindowExplorer/WindowExplorer.vcxproj +++ b/plugins/WindowExplorer/WindowExplorer.vcxproj @@ -23,28 +23,28 @@ WindowExplorer Win32Proj WindowExplorer - 10.0.17763.0 + 10.0 DynamicLibrary Unicode - v141 + v142 DynamicLibrary Unicode - v141 + v142 DynamicLibrary Unicode - v141 + v142 DynamicLibrary Unicode - v141 + v142 diff --git a/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj b/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj index 9d52f172dd0c..b7fd319b2e09 100644 --- a/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj +++ b/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj @@ -13,20 +13,20 @@ {5C00734F-F50A-49FC-9D2A-F6EE51ECB00F} CustomSetupTool - 10.0.17763.0 + 10.0 CustomSetupTool Application true - v141 + v142 Unicode Application false - v141 + v142 true Unicode Spectre diff --git a/tools/peview/peview.vcxproj b/tools/peview/peview.vcxproj index 54eff02b040f..f2a45df1243d 100644 --- a/tools/peview/peview.vcxproj +++ b/tools/peview/peview.vcxproj @@ -22,32 +22,32 @@ {72C124A2-3C80-41C6-ABA1-C4948B713204} peview Win32Proj - 10.0.17763.0 + 10.0 Application Unicode true - v141 + v142 Spectre Application Unicode - v141 + v142 Application Unicode true - v141 + v142 Spectre Application Unicode - v141 + v142 From 321f125b534bd0a3f131d3312a01366be749c971 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 8 Jun 2019 00:15:06 +0200 Subject: [PATCH 1936/2058] Revert "Update solutions to VS 2019, Update Appveyor build image to VS 2019" This reverts commit 717092e84ccb76e14a43c904d88d2ccf5e6ca7a5. --- ProcessHacker/ProcessHacker.vcxproj | 10 +++++----- appveyor.yml | 2 +- phlib/phlib.vcxproj | 10 +++++----- plugins/DotNetTools/DotNetTools.vcxproj | 10 +++++----- .../ExtendedNotifications.vcxproj | 10 +++++----- plugins/ExtendedServices/ExtendedServices.vcxproj | 10 +++++----- plugins/ExtendedTools/ExtendedTools.vcxproj | 10 +++++----- plugins/HardwareDevices/HardwareDevices.vcxproj | 10 +++++----- plugins/NetworkTools/NetworkTools.vcxproj | 10 +++++----- plugins/OnlineChecks/OnlineChecks.vcxproj | 10 +++++----- plugins/ToolStatus/ToolStatus.vcxproj | 10 +++++----- plugins/Updater/Updater.vcxproj | 10 +++++----- plugins/UserNotes/UserNotes.vcxproj | 10 +++++----- plugins/WindowExplorer/WindowExplorer.vcxproj | 10 +++++----- .../CustomSetupTool/CustomSetupTool.vcxproj | 6 +++--- tools/peview/peview.vcxproj | 10 +++++----- 16 files changed, 74 insertions(+), 74 deletions(-) diff --git a/ProcessHacker/ProcessHacker.vcxproj b/ProcessHacker/ProcessHacker.vcxproj index 6a83f0e98fb6..2424f13fc227 100644 --- a/ProcessHacker/ProcessHacker.vcxproj +++ b/ProcessHacker/ProcessHacker.vcxproj @@ -22,14 +22,14 @@ {0271DD27-6707-4290-8DFE-285702B7115D} ProcessHacker Win32Proj - 10.0 + 10.0.17763.0 Application Unicode true - v142 + v141 WindowsLocalDebugger $(SolutionDir)bin\$(Configuration)$(PlatformArchitecture)\ Spectre @@ -37,7 +37,7 @@ Application Unicode - v142 + v141 WindowsLocalDebugger $(SolutionDir)bin\$(Configuration)$(PlatformArchitecture)\ @@ -45,7 +45,7 @@ Application Unicode true - v142 + v141 WindowsLocalDebugger $(SolutionDir)bin\$(Configuration)$(PlatformArchitecture)\ Spectre @@ -53,7 +53,7 @@ Application Unicode - v142 + v141 WindowsLocalDebugger $(SolutionDir)bin\$(Configuration)$(PlatformArchitecture)\ diff --git a/appveyor.yml b/appveyor.yml index 321ce514fe26..c71e48f79d57 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,5 +1,5 @@ # Build image. -image: Visual Studio 2019 +image: Visual Studio 2017 # Version format. version: "#{build}" diff --git a/phlib/phlib.vcxproj b/phlib/phlib.vcxproj index c927de8a9cfd..dceab869782f 100644 --- a/phlib/phlib.vcxproj +++ b/phlib/phlib.vcxproj @@ -22,32 +22,32 @@ {477D0215-F252-41A1-874B-F27E3EA1ED17} phlib Win32Proj - 10.0 + 10.0.17763.0 StaticLibrary Unicode true - v142 + v141 Spectre StaticLibrary Unicode - v142 + v141 StaticLibrary Unicode true - v142 + v141 Spectre StaticLibrary Unicode - v142 + v141 diff --git a/plugins/DotNetTools/DotNetTools.vcxproj b/plugins/DotNetTools/DotNetTools.vcxproj index 5c635ebbb2ea..66df5200d23f 100644 --- a/plugins/DotNetTools/DotNetTools.vcxproj +++ b/plugins/DotNetTools/DotNetTools.vcxproj @@ -23,28 +23,28 @@ DotNetTools Win32Proj DotNetTools - 10.0 + 10.0.17763.0 DynamicLibrary Unicode - v142 + v141 DynamicLibrary Unicode - v142 + v141 DynamicLibrary Unicode - v142 + v141 DynamicLibrary Unicode - v142 + v141 diff --git a/plugins/ExtendedNotifications/ExtendedNotifications.vcxproj b/plugins/ExtendedNotifications/ExtendedNotifications.vcxproj index d8d8c7d64ed8..41fdf7c61cdd 100644 --- a/plugins/ExtendedNotifications/ExtendedNotifications.vcxproj +++ b/plugins/ExtendedNotifications/ExtendedNotifications.vcxproj @@ -23,28 +23,28 @@ ExtendedNotifications Win32Proj ExtendedNotifications - 10.0 + 10.0.17763.0 DynamicLibrary Unicode - v142 + v141 DynamicLibrary Unicode - v142 + v141 DynamicLibrary Unicode - v142 + v141 DynamicLibrary Unicode - v142 + v141 diff --git a/plugins/ExtendedServices/ExtendedServices.vcxproj b/plugins/ExtendedServices/ExtendedServices.vcxproj index 1bf18d1db0a0..073a89063451 100644 --- a/plugins/ExtendedServices/ExtendedServices.vcxproj +++ b/plugins/ExtendedServices/ExtendedServices.vcxproj @@ -23,28 +23,28 @@ ExtendedServices Win32Proj ExtendedServices - 10.0 + 10.0.17763.0 DynamicLibrary Unicode - v142 + v141 DynamicLibrary Unicode - v142 + v141 DynamicLibrary Unicode - v142 + v141 DynamicLibrary Unicode - v142 + v141 diff --git a/plugins/ExtendedTools/ExtendedTools.vcxproj b/plugins/ExtendedTools/ExtendedTools.vcxproj index 3ffc4f1cf357..1a92f5ef1f1f 100644 --- a/plugins/ExtendedTools/ExtendedTools.vcxproj +++ b/plugins/ExtendedTools/ExtendedTools.vcxproj @@ -23,28 +23,28 @@ ExtendedTools Win32Proj ExtendedTools - 10.0 + 10.0.17763.0 DynamicLibrary Unicode - v142 + v141 DynamicLibrary Unicode - v142 + v141 DynamicLibrary Unicode - v142 + v141 DynamicLibrary Unicode - v142 + v141 diff --git a/plugins/HardwareDevices/HardwareDevices.vcxproj b/plugins/HardwareDevices/HardwareDevices.vcxproj index 0ce216dcb72c..39b3efefb8ba 100644 --- a/plugins/HardwareDevices/HardwareDevices.vcxproj +++ b/plugins/HardwareDevices/HardwareDevices.vcxproj @@ -23,28 +23,28 @@ HardwareDevices Win32Proj HardwareDevices - 10.0 + 10.0.17763.0 DynamicLibrary Unicode - v142 + v141 DynamicLibrary Unicode - v142 + v141 DynamicLibrary Unicode - v142 + v141 DynamicLibrary Unicode - v142 + v141 diff --git a/plugins/NetworkTools/NetworkTools.vcxproj b/plugins/NetworkTools/NetworkTools.vcxproj index 49031ce6f2d2..f55bd1e227a5 100644 --- a/plugins/NetworkTools/NetworkTools.vcxproj +++ b/plugins/NetworkTools/NetworkTools.vcxproj @@ -23,28 +23,28 @@ NetworkTools Win32Proj NetworkTools - 10.0 + 10.0.17763.0 DynamicLibrary Unicode - v142 + v141 DynamicLibrary Unicode - v142 + v141 DynamicLibrary Unicode - v142 + v141 DynamicLibrary Unicode - v142 + v141 diff --git a/plugins/OnlineChecks/OnlineChecks.vcxproj b/plugins/OnlineChecks/OnlineChecks.vcxproj index fef273413f95..ce8e88b3d4c2 100644 --- a/plugins/OnlineChecks/OnlineChecks.vcxproj +++ b/plugins/OnlineChecks/OnlineChecks.vcxproj @@ -23,28 +23,28 @@ OnlineChecks Win32Proj OnlineChecks - 10.0 + 10.0.17763.0 DynamicLibrary Unicode - v142 + v141 DynamicLibrary Unicode - v142 + v141 DynamicLibrary Unicode - v142 + v141 DynamicLibrary Unicode - v142 + v141 diff --git a/plugins/ToolStatus/ToolStatus.vcxproj b/plugins/ToolStatus/ToolStatus.vcxproj index 45ae6d69d8ee..b31153c1de42 100644 --- a/plugins/ToolStatus/ToolStatus.vcxproj +++ b/plugins/ToolStatus/ToolStatus.vcxproj @@ -23,28 +23,28 @@ ToolStatus Win32Proj ToolStatus - 10.0 + 10.0.17763.0 DynamicLibrary Unicode - v142 + v141 DynamicLibrary Unicode - v142 + v141 DynamicLibrary Unicode - v142 + v141 DynamicLibrary Unicode - v142 + v141 diff --git a/plugins/Updater/Updater.vcxproj b/plugins/Updater/Updater.vcxproj index 07b112497684..4434a44bdb14 100644 --- a/plugins/Updater/Updater.vcxproj +++ b/plugins/Updater/Updater.vcxproj @@ -23,28 +23,28 @@ Updater Win32Proj Updater - 10.0 + 10.0.17763.0 DynamicLibrary Unicode - v142 + v141 DynamicLibrary Unicode - v142 + v141 DynamicLibrary Unicode - v142 + v141 DynamicLibrary Unicode - v142 + v141 diff --git a/plugins/UserNotes/UserNotes.vcxproj b/plugins/UserNotes/UserNotes.vcxproj index 48436c6458ce..72732b329e56 100644 --- a/plugins/UserNotes/UserNotes.vcxproj +++ b/plugins/UserNotes/UserNotes.vcxproj @@ -23,28 +23,28 @@ UserNotes Win32Proj UserNotes - 10.0 + 10.0.17763.0 DynamicLibrary Unicode - v142 + v141 DynamicLibrary Unicode - v142 + v141 DynamicLibrary Unicode - v142 + v141 DynamicLibrary Unicode - v142 + v141 diff --git a/plugins/WindowExplorer/WindowExplorer.vcxproj b/plugins/WindowExplorer/WindowExplorer.vcxproj index 467f05833956..4183ef6b9d99 100644 --- a/plugins/WindowExplorer/WindowExplorer.vcxproj +++ b/plugins/WindowExplorer/WindowExplorer.vcxproj @@ -23,28 +23,28 @@ WindowExplorer Win32Proj WindowExplorer - 10.0 + 10.0.17763.0 DynamicLibrary Unicode - v142 + v141 DynamicLibrary Unicode - v142 + v141 DynamicLibrary Unicode - v142 + v141 DynamicLibrary Unicode - v142 + v141 diff --git a/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj b/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj index b7fd319b2e09..9d52f172dd0c 100644 --- a/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj +++ b/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj @@ -13,20 +13,20 @@ {5C00734F-F50A-49FC-9D2A-F6EE51ECB00F} CustomSetupTool - 10.0 + 10.0.17763.0 CustomSetupTool Application true - v142 + v141 Unicode Application false - v142 + v141 true Unicode Spectre diff --git a/tools/peview/peview.vcxproj b/tools/peview/peview.vcxproj index f2a45df1243d..54eff02b040f 100644 --- a/tools/peview/peview.vcxproj +++ b/tools/peview/peview.vcxproj @@ -22,32 +22,32 @@ {72C124A2-3C80-41C6-ABA1-C4948B713204} peview Win32Proj - 10.0 + 10.0.17763.0 Application Unicode true - v142 + v141 Spectre Application Unicode - v142 + v141 Application Unicode true - v142 + v141 Spectre Application Unicode - v142 + v141 From 8d275b08afa7e9271f5d1f9fa880d0dd76e81f57 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 8 Jun 2019 00:16:24 +0200 Subject: [PATCH 1937/2058] Fix invalid NtSystemRoot --- ProcessHacker/memprv.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/ProcessHacker/memprv.c b/ProcessHacker/memprv.c index b04e2cd2529e..4653985d0342 100644 --- a/ProcessHacker/memprv.c +++ b/ProcessHacker/memprv.c @@ -520,9 +520,12 @@ NTSTATUS PhpUpdateMemoryRegionTypes( PS_SYSTEM_DLL_INIT_BLOCK ldrInitBlock = { 0 }; PVOID ldrInitBlockBaseAddress = NULL; PPH_MEMORY_ITEM cfgBitmapMemoryItem; + PH_STRINGREF systemRootString; PPH_STRING ntdllFileName; - - ntdllFileName = PhConcatStrings2(USER_SHARED_DATA->NtSystemRoot, L"\\System32\\ntdll.dll"); + + PhGetSystemRoot(&systemRootString); + ntdllFileName = PhConcatStringRefZ(&systemRootString, L"\\System32\\ntdll.dll"); + status = PhGetProcedureAddressRemote( ProcessHandle, ntdllFileName->Buffer, From 04214de12d4a01587b0742927f3f2a3f9a70ec90 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 8 Jun 2019 00:17:08 +0200 Subject: [PATCH 1938/2058] Add theme support to search window --- ProcessHacker/memsrch.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ProcessHacker/memsrch.c b/ProcessHacker/memsrch.c index 87617dfed783..64277536e25c 100644 --- a/ProcessHacker/memsrch.c +++ b/ProcessHacker/memsrch.c @@ -25,6 +25,7 @@ #include #include #include +#include #define WM_PH_MEMORY_STATUS_UPDATE (WM_APP + 301) @@ -582,6 +583,8 @@ INT_PTR CALLBACK PhpMemoryStringDlgProc( Button_SetCheck(GetDlgItem(hwndDlg, IDC_DETECTUNICODE), BST_CHECKED); Button_SetCheck(GetDlgItem(hwndDlg, IDC_PRIVATE), BST_CHECKED); + + PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport); } break; case WM_DESTROY: From 6d544f14e552f1554cc841f70b4503e0fd067b13 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 8 Jun 2019 00:17:43 +0200 Subject: [PATCH 1939/2058] Fix SAL annotation --- ProcessHacker/include/procprp.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ProcessHacker/include/procprp.h b/ProcessHacker/include/procprp.h index 15e498643fc6..769afddd4f61 100644 --- a/ProcessHacker/include/procprp.h +++ b/ProcessHacker/include/procprp.h @@ -89,9 +89,9 @@ PhPropPageDlgProcHeader( _In_ HWND hwndDlg, _In_ UINT uMsg, _In_ LPARAM lParam, - _Out_ LPPROPSHEETPAGE *PropSheetPage, - _Out_ PPH_PROCESS_PROPPAGECONTEXT *PropPageContext, - _Out_ PPH_PROCESS_ITEM *ProcessItem + _Out_opt_ LPPROPSHEETPAGE *PropSheetPage, + _Out_opt_ PPH_PROCESS_PROPPAGECONTEXT *PropPageContext, + _Out_opt_ PPH_PROCESS_ITEM *ProcessItem ); #define PH_PROP_PAGE_TAB_CONTROL_PARENT ((PPH_LAYOUT_ITEM)0x1) From 8642ff7d8c2d16738e296de9566df5acd1665089 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 8 Jun 2019 00:18:42 +0200 Subject: [PATCH 1940/2058] WindowExplorer: Improve path prefix resolution --- plugins/WindowExplorer/wnddlg.c | 2 +- plugins/WindowExplorer/wndprp.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/WindowExplorer/wnddlg.c b/plugins/WindowExplorer/wnddlg.c index 05ecc581bdbd..5137a977137f 100644 --- a/plugins/WindowExplorer/wnddlg.c +++ b/plugins/WindowExplorer/wnddlg.c @@ -196,7 +196,7 @@ VOID WepFillWindowInfo( { if (NT_SUCCESS(PhGetProcessMappedFileName(processHandle, instanceHandle, &fileName))) { - PhMoveReference(&fileName, PhResolveDevicePrefix(fileName)); + PhMoveReference(&fileName, PhGetFileName(fileName)); PhMoveReference(&fileName, PhGetBaseName(fileName)); PhMoveReference(&Node->ModuleString, fileName); diff --git a/plugins/WindowExplorer/wndprp.c b/plugins/WindowExplorer/wndprp.c index bbaef1610bea..44d3af50f2f8 100644 --- a/plugins/WindowExplorer/wndprp.c +++ b/plugins/WindowExplorer/wndprp.c @@ -502,7 +502,7 @@ VOID WepRefreshWindowGeneralInfo( { if (NT_SUCCESS(PhGetProcessMappedFileName(processHandle, instanceHandle, &fileName))) { - PhMoveReference(&fileName, PhResolveDevicePrefix(fileName)); + PhMoveReference(&fileName, PhGetFileName(fileName)); PhMoveReference(&fileName, PhGetBaseName(fileName)); } @@ -702,7 +702,7 @@ VOID WepRefreshClassModule( { if (NT_SUCCESS(PhGetProcessMappedFileName(processHandle, instanceHandle, &fileName))) { - PhMoveReference(&fileName, PhResolveDevicePrefix(fileName)); + PhMoveReference(&fileName, PhGetFileName(fileName)); PhMoveReference(&fileName, PhGetBaseName(fileName)); } From 0044617669b2772900a666f974cfd1b813b7f863 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 8 Jun 2019 03:01:29 +0200 Subject: [PATCH 1941/2058] Add workaround for #424 --- phlib/util.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/phlib/util.c b/phlib/util.c index f6451aaebeb8..57eca831d228 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -6424,14 +6424,14 @@ NTSTATUS PhLoadPluginImage( goto CleanupExit; //status = PhLoaderEntryLoadAllImportsForDll(imageBaseAddress, "ProcessHacker.exe"); - status = PhpFixupLoaderEntryImageDelayImports( - imageBaseAddress, - imageHeaders, - "ProcessHacker.exe" - ); - - if (!NT_SUCCESS(status)) - goto CleanupExit; + //status = PhpFixupLoaderEntryImageDelayImports( + // imageBaseAddress, + // imageHeaders, + // "ProcessHacker.exe" + // ); + // + //if (!NT_SUCCESS(status)) + // goto CleanupExit; status = PhGetLoaderEntryImageEntryPoint( imageBaseAddress, From 1a2763b8db6a3a7e45a9c315917a591c057867fb Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 9 Jun 2019 02:35:59 +0200 Subject: [PATCH 1942/2058] Fix #424 --- phlib/include/phutil.h | 6 +++--- phlib/util.c | 48 +++++++++++++++++++++--------------------- 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/phlib/include/phutil.h b/phlib/include/phutil.h index 415d54629afa..da5b7596f5af 100644 --- a/phlib/include/phutil.h +++ b/phlib/include/phutil.h @@ -1237,11 +1237,11 @@ PhGetLoaderEntryImageDirectory( PHLIBAPI NTSTATUS NTAPI -PhGetLoaderEntryImageSection( +PhGetLoaderEntryImageVaToSection( _In_ PVOID BaseAddress, _In_ PIMAGE_NT_HEADERS ImageNtHeader, - _In_ PVOID ImageDirectory, - _Out_ PIMAGE_SECTION_HEADER *ImageSection, + _In_ PVOID ImageDirectoryAddress, + _Out_ PVOID *ImageSectionAddress, _Out_ SIZE_T *ImageSectionLength ); diff --git a/phlib/util.c b/phlib/util.c index 57eca831d228..f3e2fdfea50e 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -5807,17 +5807,17 @@ NTSTATUS PhGetLoaderEntryImageDirectory( return STATUS_SUCCESS; } -NTSTATUS PhGetLoaderEntryImageSection( +NTSTATUS PhGetLoaderEntryImageVaToSection( _In_ PVOID BaseAddress, _In_ PIMAGE_NT_HEADERS ImageNtHeader, - _In_ PVOID ImageDirectory, - _Out_ PIMAGE_SECTION_HEADER *ImageSection, + _In_ PVOID ImageDirectoryAddress, + _Out_ PVOID *ImageSectionAddress, _Out_ SIZE_T *ImageSectionLength ) { SIZE_T directorySectionLength = 0; PIMAGE_SECTION_HEADER sectionHeader; - PIMAGE_SECTION_HEADER directorySectionHeader = NULL; + PVOID directorySectionAddress = NULL; ULONG i; for (i = 0; i < ImageNtHeader->FileHeader.NumberOfSections; i++) @@ -5825,19 +5825,19 @@ NTSTATUS PhGetLoaderEntryImageSection( sectionHeader = PTR_ADD_OFFSET(IMAGE_FIRST_SECTION(ImageNtHeader), sizeof(IMAGE_SECTION_HEADER) * i); if ( - ((ULONG_PTR)ImageDirectory >= (ULONG_PTR)PTR_ADD_OFFSET(BaseAddress, sectionHeader->VirtualAddress)) && - ((ULONG_PTR)ImageDirectory < (ULONG_PTR)PTR_ADD_OFFSET(PTR_ADD_OFFSET(BaseAddress, sectionHeader->VirtualAddress), sectionHeader->SizeOfRawData)) + ((ULONG_PTR)ImageDirectoryAddress >= (ULONG_PTR)PTR_ADD_OFFSET(BaseAddress, sectionHeader->VirtualAddress)) && + ((ULONG_PTR)ImageDirectoryAddress < (ULONG_PTR)PTR_ADD_OFFSET(PTR_ADD_OFFSET(BaseAddress, sectionHeader->VirtualAddress), sectionHeader->SizeOfRawData)) ) { directorySectionLength = sectionHeader->Misc.VirtualSize; - directorySectionHeader = PTR_ADD_OFFSET(BaseAddress, sectionHeader->VirtualAddress); + directorySectionAddress = PTR_ADD_OFFSET(BaseAddress, sectionHeader->VirtualAddress); break; } } - if (directorySectionHeader && directorySectionLength) + if (directorySectionAddress && directorySectionLength) { - *ImageSection = directorySectionHeader; + *ImageSectionAddress = directorySectionAddress; *ImageSectionLength = directorySectionLength; return STATUS_SUCCESS; } @@ -6020,7 +6020,7 @@ static NTSTATUS PhpFixupLoaderEntryImageImports( ULONG importDirectoryProtect; PIMAGE_DATA_DIRECTORY dataDirectory; PIMAGE_IMPORT_DESCRIPTOR importDirectory; - PIMAGE_SECTION_HEADER importDirectorySection; + PVOID importDirectorySectionAddress; status = PhGetLoaderEntryImageDirectory( BaseAddress, @@ -6034,11 +6034,11 @@ static NTSTATUS PhpFixupLoaderEntryImageImports( if (!NT_SUCCESS(status)) goto CleanupExit; - status = PhGetLoaderEntryImageSection( + status = PhGetLoaderEntryImageVaToSection( BaseAddress, ImageNtHeader, importDirectory, - &importDirectorySection, + &importDirectorySectionAddress, &importDirectorySize ); @@ -6047,7 +6047,7 @@ static NTSTATUS PhpFixupLoaderEntryImageImports( status = NtProtectVirtualMemory( NtCurrentProcess(), - &importDirectorySection, + &importDirectorySectionAddress, &importDirectorySize, PAGE_READWRITE, &importDirectoryProtect @@ -6173,7 +6173,7 @@ static NTSTATUS PhpFixupLoaderEntryImageImports( status = NtProtectVirtualMemory( NtCurrentProcess(), - &importDirectorySection, + &importDirectorySectionAddress, &importDirectorySize, importDirectoryProtect, &importDirectoryProtect @@ -6193,11 +6193,11 @@ static NTSTATUS PhpFixupLoaderEntryImageDelayImports( ) { NTSTATUS status; - SIZE_T importDirectorySize; + SIZE_T importDirectorySectionSize; ULONG importDirectoryProtect; PIMAGE_DATA_DIRECTORY dataDirectory; PIMAGE_DELAYLOAD_DESCRIPTOR delayImportDirectory; - PIMAGE_SECTION_HEADER importDirectorySection; + PVOID importDirectorySectionAddress; status = PhGetLoaderEntryImageDirectory( BaseAddress, @@ -6216,12 +6216,12 @@ static NTSTATUS PhpFixupLoaderEntryImageDelayImports( goto CleanupExit; } - status = PhGetLoaderEntryImageSection( + status = PhGetLoaderEntryImageVaToSection( BaseAddress, ImageNtHeaders, - delayImportDirectory, - &importDirectorySection, - &importDirectorySize + PTR_ADD_OFFSET(BaseAddress, delayImportDirectory->ImportAddressTableRVA), + &importDirectorySectionAddress, + &importDirectorySectionSize ); if (!NT_SUCCESS(status)) @@ -6229,8 +6229,8 @@ static NTSTATUS PhpFixupLoaderEntryImageDelayImports( status = NtProtectVirtualMemory( NtCurrentProcess(), - &importDirectorySection, - &importDirectorySize, + &importDirectorySectionAddress, + &importDirectorySectionSize, PAGE_READWRITE, &importDirectoryProtect ); @@ -6326,8 +6326,8 @@ static NTSTATUS PhpFixupLoaderEntryImageDelayImports( status = NtProtectVirtualMemory( NtCurrentProcess(), - &importDirectorySection, - &importDirectorySize, + &importDirectorySectionAddress, + &importDirectorySectionSize, importDirectoryProtect, &importDirectoryProtect ); From 3730238c4c9c97149d0899b9b6786849b1fdf5e3 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 9 Jun 2019 02:51:14 +0200 Subject: [PATCH 1943/2058] Re-enable the delayload fixup for plugins --- phlib/util.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/phlib/util.c b/phlib/util.c index f3e2fdfea50e..f4b9a4cb20ab 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -6424,14 +6424,13 @@ NTSTATUS PhLoadPluginImage( goto CleanupExit; //status = PhLoaderEntryLoadAllImportsForDll(imageBaseAddress, "ProcessHacker.exe"); - //status = PhpFixupLoaderEntryImageDelayImports( - // imageBaseAddress, - // imageHeaders, - // "ProcessHacker.exe" - // ); - // - //if (!NT_SUCCESS(status)) - // goto CleanupExit; + status = PhpFixupLoaderEntryImageDelayImports( + imageBaseAddress, + imageHeaders, + "ProcessHacker.exe" + ); + if (!NT_SUCCESS(status)) + goto CleanupExit; status = PhGetLoaderEntryImageEntryPoint( imageBaseAddress, From 436e742550f21fd32d93cdcd80ff8078cd5f4dc3 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 10 Jun 2019 22:41:37 +0200 Subject: [PATCH 1944/2058] Fix handle properties object address regression --- ProcessHacker/hndllist.c | 4 ++-- ProcessHacker/hndlprp.c | 4 +++- ProcessHacker/include/hndllist.h | 1 + ProcessHacker/include/hndlprv.h | 1 - 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/ProcessHacker/hndllist.c b/ProcessHacker/hndllist.c index d67258febddc..3aab612a7ddf 100644 --- a/ProcessHacker/hndllist.c +++ b/ProcessHacker/hndllist.c @@ -546,9 +546,9 @@ BOOLEAN NTAPI PhpHandleTreeNewCallback( case PHHNTLC_OBJECTADDRESS: { if (handleItem->Object) - PhPrintPointer(handleItem->ObjectString, handleItem->Object); + PhPrintPointer(node->ObjectString, handleItem->Object); - PhInitializeStringRefLongHint(&getCellText->Text, handleItem->ObjectString); + PhInitializeStringRefLongHint(&getCellText->Text, node->ObjectString); } break; case PHHNTLC_ATTRIBUTES: diff --git a/ProcessHacker/hndlprp.c b/ProcessHacker/hndlprp.c index 379312d6dfb4..6e6c6c7a8689 100644 --- a/ProcessHacker/hndlprp.c +++ b/ProcessHacker/hndlprp.c @@ -548,7 +548,9 @@ VOID PhpUpdateHandleGeneral( PhSetListViewSubItem(Context->ListViewHandle, Context->ListViewRowCache[PH_HANDLE_GENERAL_INDEX_NAME], 1, PhGetStringOrEmpty(Context->HandleItem->BestObjectName)); PhSetListViewSubItem(Context->ListViewHandle, Context->ListViewRowCache[PH_HANDLE_GENERAL_INDEX_TYPE], 1, PhGetStringOrEmpty(Context->HandleItem->TypeName)); - PhSetListViewSubItem(Context->ListViewHandle, Context->ListViewRowCache[PH_HANDLE_GENERAL_INDEX_OBJECT], 1, Context->HandleItem->ObjectString); + + if (Context->HandleItem->Object) PhPrintPointer(string, Context->HandleItem->Object); + PhSetListViewSubItem(Context->ListViewHandle, Context->ListViewRowCache[PH_HANDLE_GENERAL_INDEX_OBJECT], 1, string); if (PhGetAccessEntries( PhGetStringOrEmpty(Context->HandleItem->TypeName), diff --git a/ProcessHacker/include/hndllist.h b/ProcessHacker/include/hndllist.h index 5188d548d52a..d6dcbaa7233a 100644 --- a/ProcessHacker/include/hndllist.h +++ b/ProcessHacker/include/hndllist.h @@ -44,6 +44,7 @@ typedef struct _PH_HANDLE_NODE PPH_STRING GrantedAccessSymbolicText; WCHAR FileShareAccessText[4]; + WCHAR ObjectString[PH_PTR_STR_LEN_1]; // begin_phapppub } PH_HANDLE_NODE, *PPH_HANDLE_NODE; // end_phapppub diff --git a/ProcessHacker/include/hndlprv.h b/ProcessHacker/include/hndlprv.h index 05cdb782c18c..2edc43ef7c6e 100644 --- a/ProcessHacker/include/hndlprv.h +++ b/ProcessHacker/include/hndlprv.h @@ -26,7 +26,6 @@ typedef struct _PH_HANDLE_ITEM PPH_STRING BestObjectName; WCHAR HandleString[PH_PTR_STR_LEN_1]; - WCHAR ObjectString[PH_PTR_STR_LEN_1]; WCHAR GrantedAccessString[PH_PTR_STR_LEN_1]; } PH_HANDLE_ITEM, *PPH_HANDLE_ITEM; From 017d6ec6bb992d4abea614b360aa9ac33a2dde28 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 10 Jun 2019 22:42:06 +0200 Subject: [PATCH 1945/2058] Fix handle object address search --- ProcessHacker/prpghndl.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/ProcessHacker/prpghndl.c b/ProcessHacker/prpghndl.c index 03cbfc40b1f1..8a7034aaa5f3 100644 --- a/ProcessHacker/prpghndl.c +++ b/ProcessHacker/prpghndl.c @@ -305,12 +305,6 @@ BOOLEAN PhpHandleTreeFilterCallback( return TRUE; } - if (handleItem->ObjectString[0]) - { - if (PhpWordMatchHandleStringZ(handlesContext->SearchboxText, handleItem->ObjectString)) - return TRUE; - } - if (handleItem->GrantedAccessString[0]) { if (PhpWordMatchHandleStringZ(handlesContext->SearchboxText, handleItem->GrantedAccessString)) @@ -321,6 +315,12 @@ BOOLEAN PhpHandleTreeFilterCallback( // node properties + if (handleNode->ObjectString[0]) + { + if (PhpWordMatchHandleStringZ(handlesContext->SearchboxText, handleNode->ObjectString)) + return TRUE; + } + if (!PhIsNullOrEmptyString(handleNode->GrantedAccessSymbolicText)) { if (PhpWordMatchHandleStringRef(handlesContext->SearchboxText, &handleNode->GrantedAccessSymbolicText->sr)) From 6e793854b7da157da2d99dcea89970047e87c95b Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 10 Jun 2019 22:45:51 +0200 Subject: [PATCH 1946/2058] Fix tray icon graph warning/overflow when using large sample count settings --- ProcessHacker/notifico.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/ProcessHacker/notifico.c b/ProcessHacker/notifico.c index 821c8b280d3f..2259f28d3dfb 100644 --- a/ProcessHacker/notifico.c +++ b/ProcessHacker/notifico.c @@ -939,8 +939,8 @@ VOID PhNfpCpuHistoryIconUpdateCallback( Icon->Pointers->BeginBitmap(&drawInfo.Width, &drawInfo.Height, &bitmap, &bits, &hdc, &oldBitmap); maxDataCount = drawInfo.Width / 2 + 1; - lineData1 = _alloca(maxDataCount * sizeof(FLOAT)); - lineData2 = _alloca(maxDataCount * sizeof(FLOAT)); + lineData1 = _malloca(maxDataCount * sizeof(FLOAT)); + lineData2 = _malloca(maxDataCount * sizeof(FLOAT)); lineDataCount = min(maxDataCount, PhCpuKernelHistory.Count); PhCopyCircularBuffer_FLOAT(&PhCpuKernelHistory, lineData1, lineDataCount); @@ -988,6 +988,9 @@ VOID PhNfpCpuHistoryIconUpdateCallback( *NewText = PhFormat(format, maxCpuProcessItem ? 8 : 3, 128); if (maxCpuProcessItem) PhDereferenceObject(maxCpuProcessItem); + + _freea(lineData2); + _freea(lineData1); } VOID PhNfpIoHistoryIconUpdateCallback( @@ -1031,8 +1034,8 @@ VOID PhNfpIoHistoryIconUpdateCallback( Icon->Pointers->BeginBitmap(&drawInfo.Width, &drawInfo.Height, &bitmap, &bits, &hdc, &oldBitmap); maxDataCount = drawInfo.Width / 2 + 1; - lineData1 = _alloca(maxDataCount * sizeof(FLOAT)); - lineData2 = _alloca(maxDataCount * sizeof(FLOAT)); + lineData1 = _malloca(maxDataCount * sizeof(FLOAT)); + lineData2 = _malloca(maxDataCount * sizeof(FLOAT)); lineDataCount = min(maxDataCount, PhIoReadHistory.Count); max = 1024 * 1024; // minimum scaling of 1 MB. @@ -1094,6 +1097,9 @@ VOID PhNfpIoHistoryIconUpdateCallback( *NewText = PhFormat(format, maxIoProcessItem ? 8 : 6, 128); if (maxIoProcessItem) PhDereferenceObject(maxIoProcessItem); + + _freea(lineData2); + _freea(lineData1); } VOID PhNfpCommitHistoryIconUpdateCallback( @@ -1134,7 +1140,7 @@ VOID PhNfpCommitHistoryIconUpdateCallback( Icon->Pointers->BeginBitmap(&drawInfo.Width, &drawInfo.Height, &bitmap, &bits, &hdc, &oldBitmap); maxDataCount = drawInfo.Width / 2 + 1; - lineData1 = _alloca(maxDataCount * sizeof(FLOAT)); + lineData1 = _malloca(maxDataCount * sizeof(FLOAT)); lineDataCount = min(maxDataCount, PhCommitHistory.Count); @@ -1166,6 +1172,8 @@ VOID PhNfpCommitHistoryIconUpdateCallback( PhInitFormatS(&format[4], L"%)"); *NewText = PhFormat(format, 5, 96); + + _freea(lineData1); } VOID PhNfpPhysicalHistoryIconUpdateCallback( @@ -1207,7 +1215,7 @@ VOID PhNfpPhysicalHistoryIconUpdateCallback( Icon->Pointers->BeginBitmap(&drawInfo.Width, &drawInfo.Height, &bitmap, &bits, &hdc, &oldBitmap); maxDataCount = drawInfo.Width / 2 + 1; - lineData1 = _alloca(maxDataCount * sizeof(FLOAT)); + lineData1 = _malloca(maxDataCount * sizeof(FLOAT)); lineDataCount = min(maxDataCount, PhPhysicalHistory.Count); @@ -1240,6 +1248,8 @@ VOID PhNfpPhysicalHistoryIconUpdateCallback( PhInitFormatS(&format[4], L"%)"); *NewText = PhFormat(format, 5, 96); + + _freea(lineData1); } VOID PhNfpCpuUsageIconUpdateCallback( From 208b3fdb9f1d2e896d117a6040ac2a3b25200017 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 11 Jun 2019 00:25:06 +0200 Subject: [PATCH 1947/2058] Fix typo --- ProcessHacker/hndlprp.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/ProcessHacker/hndlprp.c b/ProcessHacker/hndlprp.c index 6e6c6c7a8689..68391a8163c0 100644 --- a/ProcessHacker/hndlprp.c +++ b/ProcessHacker/hndlprp.c @@ -549,8 +549,11 @@ VOID PhpUpdateHandleGeneral( PhSetListViewSubItem(Context->ListViewHandle, Context->ListViewRowCache[PH_HANDLE_GENERAL_INDEX_NAME], 1, PhGetStringOrEmpty(Context->HandleItem->BestObjectName)); PhSetListViewSubItem(Context->ListViewHandle, Context->ListViewRowCache[PH_HANDLE_GENERAL_INDEX_TYPE], 1, PhGetStringOrEmpty(Context->HandleItem->TypeName)); - if (Context->HandleItem->Object) PhPrintPointer(string, Context->HandleItem->Object); - PhSetListViewSubItem(Context->ListViewHandle, Context->ListViewRowCache[PH_HANDLE_GENERAL_INDEX_OBJECT], 1, string); + if (Context->HandleItem->Object) + { + PhPrintPointer(string, Context->HandleItem->Object); + PhSetListViewSubItem(Context->ListViewHandle, Context->ListViewRowCache[PH_HANDLE_GENERAL_INDEX_OBJECT], 1, string); + } if (PhGetAccessEntries( PhGetStringOrEmpty(Context->HandleItem->TypeName), From a9fd6a0fa4ee685471a8a64d6424581fa415dfc5 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 11 Jun 2019 00:39:54 +0200 Subject: [PATCH 1948/2058] ExtendedTools: Fix #427 (missing UDP connection statistics and utilisation) Co-Authored-By: DavidXanatos --- plugins/ExtendedTools/etwmon.c | 11 +++++++++++ plugins/ExtendedTools/etwstat.c | 26 ++++++++++++++++++++++++-- 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/plugins/ExtendedTools/etwmon.c b/plugins/ExtendedTools/etwmon.c index 8e554667cbb0..3ac1a776ee14 100644 --- a/plugins/ExtendedTools/etwmon.c +++ b/plugins/ExtendedTools/etwmon.c @@ -3,6 +3,7 @@ * ETW monitoring * * Copyright (C) 2010-2015 wj32 + * Copyright (C) 2019 dmex * * This file is part of Process Hacker. * @@ -378,6 +379,16 @@ VOID NTAPI EtpEtwEventCallback( destination.Port = _byteswap_ushort(data->dport); } + // Note: The endpoints are swapped for incoming UDP packets. The destination endpoint + // corresponds to the local socket not the source endpoint. (DavidXanatos) + if ((networkEvent.ProtocolType & PH_UDP_PROTOCOL_TYPE) != 0 && + networkEvent.Type == EtEtwNetworkReceiveType) + { + PH_IP_ENDPOINT swapsource = source; + source = destination; + destination = swapsource; + } + networkEvent.LocalEndpoint = source; if (networkEvent.ProtocolType & PH_TCP_PROTOCOL_TYPE) diff --git a/plugins/ExtendedTools/etwstat.c b/plugins/ExtendedTools/etwstat.c index b67eea9ceea1..0d07799b5230 100644 --- a/plugins/ExtendedTools/etwstat.c +++ b/plugins/ExtendedTools/etwstat.c @@ -3,6 +3,7 @@ * ETW statistics collection * * Copyright (C) 2010-2011 wj32 + * Copyright (C) 2019 dmex * * This file is part of Process Hacker. * @@ -184,12 +185,33 @@ VOID EtProcessNetworkEvent( PhDereferenceObject(processItem); } - if (networkItem = PhReferenceNetworkItem( + networkItem = PhReferenceNetworkItem( Event->ProtocolType, &Event->LocalEndpoint, &Event->RemoteEndpoint, Event->ClientId.UniqueProcess - )) + ); + + if (!networkItem && Event->ProtocolType & PH_UDP_PROTOCOL_TYPE) + { + // Note: ETW generates UDP events with the LocalEndpoint set to the LAN endpoint address + // of the local adapter the packet was sent or recieved but GetExtendedUdpTable + // returns some UDP connections with endpoints set to in4addr_any/in6addr_any (zero). (dmex) + + if (Event->ProtocolType & PH_IPV4_NETWORK_TYPE) + memset(&Event->LocalEndpoint.Address.InAddr, 0, sizeof(IN_ADDR)); // same as in4addr_any + else + memset(&Event->LocalEndpoint.Address.In6Addr, 0, sizeof(IN6_ADDR)); // same as in6addr_any + + networkItem = PhReferenceNetworkItem( + Event->ProtocolType, + &Event->LocalEndpoint, + &Event->RemoteEndpoint, + Event->ClientId.UniqueProcess + ); + } + + if (networkItem) { networkBlock = EtGetNetworkBlock(networkItem); From 7249abbcea42a34615beeb012dd3bb495bc74837 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 25 Jun 2019 06:05:45 +0200 Subject: [PATCH 1949/2058] Disable WSL support by default --- ProcessHacker/settings.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ProcessHacker/settings.c b/ProcessHacker/settings.c index 656fe91918aa..183d2e676416 100644 --- a/ProcessHacker/settings.c +++ b/ProcessHacker/settings.c @@ -55,7 +55,7 @@ VOID PhAddDefaultSettings( PhpAddIntegerSetting(L"EnableThemeSupport", L"0"); PhpAddIntegerSetting(L"EnableTooltipSupport", L"1"); PhpAddIntegerSetting(L"EnableSecurityAdvancedDialog", L"1"); - PhpAddIntegerSetting(L"EnableLinuxSubsystemSupport", L"1"); + PhpAddIntegerSetting(L"EnableLinuxSubsystemSupport", L"0"); PhpAddStringSetting(L"EnvironmentTreeListColumns", L""); PhpAddStringSetting(L"EnvironmentTreeListSort", L"0,0"); // 0, NoSortOrder PhpAddIntegerSetting(L"EnvironmentTreeListFlags", L"0"); From 5a51710472075e684cad396dd689e6a8aba92ecb Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 25 Jun 2019 06:06:47 +0200 Subject: [PATCH 1950/2058] Export PhSetWindowText --- ProcessHacker/ProcessHacker.def | 1 + ProcessHacker/settings.c | 1 + 2 files changed, 2 insertions(+) diff --git a/ProcessHacker/ProcessHacker.def b/ProcessHacker/ProcessHacker.def index 337376084ee4..00b749dc3bb9 100644 --- a/ProcessHacker/ProcessHacker.def +++ b/ProcessHacker/ProcessHacker.def @@ -529,6 +529,7 @@ EXPORTS PhGetDialogItemValue PhSetDialogItemValue PhSetDialogItemText + PhSetWindowText PhApplicationFont PhTreeWindowFont PhRegisterWindowCallback diff --git a/ProcessHacker/settings.c b/ProcessHacker/settings.c index 183d2e676416..c25cdf771ce8 100644 --- a/ProcessHacker/settings.c +++ b/ProcessHacker/settings.c @@ -67,6 +67,7 @@ VOID PhAddDefaultSettings( PhpAddIntegerSetting(L"FirstRun", L"1"); PhpAddStringSetting(L"Font", L""); // null PhpAddIntegerSetting(L"ForceNoParent", L"1"); + PhpAddIntegerSetting(L"KphBuildNumber", L"0"); PhpAddStringSetting(L"HandleTreeListColumns", L""); PhpAddStringSetting(L"HandleTreeListSort", L"0,1"); // 0, AscendingSortOrder PhpAddIntegerSetting(L"HandleTreeListFlags", L"3"); From a9c63d980ec9e0b091f7a21f1cd80df82173ca4b Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 25 Jun 2019 06:09:20 +0200 Subject: [PATCH 1951/2058] Plugins: Update macro usage --- plugins/CommonUtil/http.c | 4 ++-- plugins/CommonUtil/http.h | 2 +- plugins/DotNetTools/asmpage.c | 2 +- plugins/DotNetTools/clrsup.c | 2 +- plugins/ExtendedTools/iconext.c | 18 +++++++++++++----- plugins/HardwareDevices/netdetails.c | 2 +- plugins/NetworkTools/ping.c | 4 ++-- plugins/Updater/options.c | 2 +- plugins/Updater/verify.c | 2 +- plugins/WindowExplorer/wnddlg.c | 2 +- 10 files changed, 24 insertions(+), 16 deletions(-) diff --git a/plugins/CommonUtil/http.c b/plugins/CommonUtil/http.c index db1bc06c80cd..c4af0524103a 100644 --- a/plugins/CommonUtil/http.c +++ b/plugins/CommonUtil/http.c @@ -121,7 +121,7 @@ BOOLEAN PhHttpSocketConnect( BOOLEAN PhHttpSocketBeginRequest( _In_ PPH_HTTP_CONTEXT HttpContext, - _In_ PWSTR Method, + _In_opt_ PWSTR Method, _In_ PWSTR UrlPath, _In_ ULONG Flags ) @@ -211,7 +211,7 @@ BOOLEAN PhHttpSocketAddRequestHeaders( return !!WinHttpAddRequestHeaders( HttpContext->RequestHandle, Headers, - HeadersLength ? HeadersLength : -1L, + HeadersLength ? HeadersLength : ULONG_MAX, WINHTTP_ADDREQ_FLAG_ADD | WINHTTP_ADDREQ_FLAG_REPLACE ); } diff --git a/plugins/CommonUtil/http.h b/plugins/CommonUtil/http.h index 4cd8cc0addf9..7bc875bc1e06 100644 --- a/plugins/CommonUtil/http.h +++ b/plugins/CommonUtil/http.h @@ -44,7 +44,7 @@ BOOLEAN NTAPI PhHttpSocketBeginRequest( _In_ PPH_HTTP_CONTEXT HttpContext, - _In_ PWSTR Method, + _In_opt_ PWSTR Method, _In_ PWSTR UrlPath, _In_ ULONG Flags ); diff --git a/plugins/DotNetTools/asmpage.c b/plugins/DotNetTools/asmpage.c index 136377228785..87255e50f15b 100644 --- a/plugins/DotNetTools/asmpage.c +++ b/plugins/DotNetTools/asmpage.c @@ -859,7 +859,7 @@ static VOID NTAPI DotNetEventCallback( node->Type = DNA_TYPE_CLR; node->u.Clr.ClrInstanceID = data->ClrInstanceID; node->u.Clr.StartupFlags = data->StartupFlags; - node->u.Clr.DisplayName = PhFormatString(L"CLR v%u.%u.%u.%u", data->VMMajorVersion, data->VMMinorVersion, data->VMBuildNumber, data->VMQfeNumber); + node->u.Clr.DisplayName = PhFormatString(L"CLR v%hu.%hu.%hu.%hu", data->VMMajorVersion, data->VMMinorVersion, data->VMBuildNumber, data->VMQfeNumber); node->StructureText = node->u.Clr.DisplayName->sr; node->IdText = PhFormatUInt64(data->ClrInstanceID, FALSE); diff --git a/plugins/DotNetTools/clrsup.c b/plugins/DotNetTools/clrsup.c index 32d66fb59ac9..29b9ab434274 100644 --- a/plugins/DotNetTools/clrsup.c +++ b/plugins/DotNetTools/clrsup.c @@ -225,7 +225,7 @@ HRESULT CreateXCLRDataProcess( ULONG flags; BOOLEAN clrV4; HMODULE dllBase; - HRESULT (__stdcall *clrDataCreateInstance)(REFIID, ICLRDataTarget *, void **); + PFN_CLRDataCreateInstance clrDataCreateInstance; clrV4 = FALSE; diff --git a/plugins/ExtendedTools/iconext.c b/plugins/ExtendedTools/iconext.c index 8bf42ca11228..4c510b47de06 100644 --- a/plugins/ExtendedTools/iconext.c +++ b/plugins/ExtendedTools/iconext.c @@ -310,7 +310,7 @@ VOID EtpGpuIconUpdateCallback( Icon->Pointers->BeginBitmap(&drawInfo.Width, &drawInfo.Height, &bitmap, &bits, &hdc, &oldBitmap); maxDataCount = drawInfo.Width / 2 + 1; - lineData1 = _alloca(maxDataCount * sizeof(FLOAT)); + lineData1 = _malloca(maxDataCount * sizeof(FLOAT)); lineDataCount = min(maxDataCount, EtGpuNodeHistory.Count); PhCopyCircularBuffer_FLOAT(&EtGpuNodeHistory, lineData1, lineDataCount); @@ -354,6 +354,8 @@ VOID EtpGpuIconUpdateCallback( *NewText = PhFormat(format, maxGpuProcessItem ? 8 : 3, 128); if (maxGpuProcessItem) PhDereferenceObject(maxGpuProcessItem); + + _freea(lineData1); } BOOLEAN EtpGpuIconMessageCallback( @@ -419,8 +421,8 @@ VOID EtpDiskIconUpdateCallback( Icon->Pointers->BeginBitmap(&drawInfo.Width, &drawInfo.Height, &bitmap, &bits, &hdc, &oldBitmap); maxDataCount = drawInfo.Width / 2 + 1; - lineData1 = _alloca(maxDataCount * sizeof(FLOAT)); - lineData2 = _alloca(maxDataCount * sizeof(FLOAT)); + lineData1 = _malloca(maxDataCount * sizeof(FLOAT)); + lineData2 = _malloca(maxDataCount * sizeof(FLOAT)); lineDataCount = min(maxDataCount, EtDiskReadHistory.Count); max = 1024 * 1024; // minimum scaling of 1 MB. @@ -477,6 +479,9 @@ VOID EtpDiskIconUpdateCallback( *NewText = PhFormat(format, maxDiskProcessItem ? 6 : 4, 128); if (maxDiskProcessItem) PhDereferenceObject(maxDiskProcessItem); + + _freea(lineData2); + _freea(lineData1); } BOOLEAN EtpDiskIconMessageCallback( @@ -542,8 +547,8 @@ VOID EtpNetworkIconUpdateCallback( Icon->Pointers->BeginBitmap(&drawInfo.Width, &drawInfo.Height, &bitmap, &bits, &hdc, &oldBitmap); maxDataCount = drawInfo.Width / 2 + 1; - lineData1 = _alloca(maxDataCount * sizeof(FLOAT)); - lineData2 = _alloca(maxDataCount * sizeof(FLOAT)); + lineData1 = _malloca(maxDataCount * sizeof(FLOAT)); + lineData2 = _malloca(maxDataCount * sizeof(FLOAT)); lineDataCount = min(maxDataCount, EtNetworkReceiveHistory.Count); max = 1024 * 1024; // minimum scaling of 1 MB. @@ -600,6 +605,9 @@ VOID EtpNetworkIconUpdateCallback( *NewText = PhFormat(format, maxNetworkProcessItem ? 6 : 4, 128); if (maxNetworkProcessItem) PhDereferenceObject(maxNetworkProcessItem); + + _freea(lineData2); + _freea(lineData1); } BOOLEAN EtpNetworkIconMessageCallback( diff --git a/plugins/HardwareDevices/netdetails.c b/plugins/HardwareDevices/netdetails.c index 4e9e26d00721..dea0aa54f327 100644 --- a/plugins/HardwareDevices/netdetails.c +++ b/plugins/HardwareDevices/netdetails.c @@ -536,7 +536,7 @@ INT_PTR CALLBACK NetAdapterDetailsDlgProc( SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhInstanceHandle, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhInstanceHandle, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); - SetWindowText(hwndDlg, PhGetStringOrDefault(context->AdapterName, L"Unknown network adapter")); + PhSetWindowText(hwndDlg, PhGetStringOrDefault(context->AdapterName, L"Unknown network adapter")); PhCenterWindow(hwndDlg, context->ParentHandle); PhSetListViewStyle(context->ListViewHandle, FALSE, TRUE); diff --git a/plugins/NetworkTools/ping.c b/plugins/NetworkTools/ping.c index 224dc930ac4b..7052ad24fac9 100644 --- a/plugins/NetworkTools/ping.c +++ b/plugins/NetworkTools/ping.c @@ -335,8 +335,8 @@ INT_PTR CALLBACK NetworkPingWndProc( else PhCenterWindow(hwndDlg, PhMainWndHandle); - SetWindowText(hwndDlg, PhaFormatString(L"Ping %s", context->IpAddressString)->Buffer); - SetWindowText(context->StatusHandle, PhaFormatString(L"Pinging %s with %lu bytes of data...", + PhSetWindowText(hwndDlg, PhaFormatString(L"Ping %s", context->IpAddressString)->Buffer); + PhSetWindowText(context->StatusHandle, PhaFormatString(L"Pinging %s with %lu bytes of data...", context->IpAddressString, PhGetIntegerSetting(SETTING_NAME_PING_SIZE))->Buffer ); diff --git a/plugins/Updater/options.c b/plugins/Updater/options.c index 3535a21b4845..0e3f7ce854d0 100644 --- a/plugins/Updater/options.c +++ b/plugins/Updater/options.c @@ -73,7 +73,7 @@ INT_PTR CALLBACK TextDlgProc( SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhInstanceHandle, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhInstanceHandle, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); - SetWindowText(GetDlgItem(hwndDlg, IDC_TEXT), PhGetString(context->BuildMessage)); + PhSetWindowText(GetDlgItem(hwndDlg, IDC_TEXT), PhGetString(context->BuildMessage)); PhInitializeLayoutManager(&LayoutManager, hwndDlg); PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDC_TEXT), NULL, PH_ANCHOR_ALL); diff --git a/plugins/Updater/verify.c b/plugins/Updater/verify.c index 5bffe8c3aaa1..68af978790fb 100644 --- a/plugins/Updater/verify.c +++ b/plugins/Updater/verify.c @@ -232,7 +232,7 @@ BOOLEAN UpdaterVerifySignature( } VOID UpdaterDestroyHash( - _Inout_ PUPDATER_HASH_CONTEXT Context + _Frees_ptr_opt_ PUPDATER_HASH_CONTEXT Context ) { if (Context->HashAlgHandle) diff --git a/plugins/WindowExplorer/wnddlg.c b/plugins/WindowExplorer/wnddlg.c index 5137a977137f..4ad8dab84c90 100644 --- a/plugins/WindowExplorer/wnddlg.c +++ b/plugins/WindowExplorer/wnddlg.c @@ -422,7 +422,7 @@ INT_PTR CALLBACK WepWindowsDlgProc( context->TreeNewHandle = GetDlgItem(hwndDlg, IDC_LIST); context->SearchBoxHandle = GetDlgItem(hwndDlg, IDC_SEARCHEDIT); - SetWindowText(hwndDlg, PH_AUTO_T(PH_STRING, WepGetWindowTitleForSelector(&context->Selector))->Buffer); + PhSetWindowText(hwndDlg, PH_AUTO_T(PH_STRING, WepGetWindowTitleForSelector(&context->Selector))->Buffer); PhCreateSearchControl(hwndDlg, context->SearchBoxHandle, L"Search Windows (Ctrl+K)"); WeInitializeWindowTree(hwndDlg, context->TreeNewHandle, &context->TreeContext); From 65b23f683bd75f548913ab591129cf479fb7a76a Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 25 Jun 2019 06:09:58 +0200 Subject: [PATCH 1952/2058] Fix SharedIconCacheHashtableEqual --- phlib/guisup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phlib/guisup.c b/phlib/guisup.c index f452b92448d9..099140251376 100644 --- a/phlib/guisup.c +++ b/phlib/guisup.c @@ -635,7 +635,7 @@ static BOOLEAN SharedIconCacheHashtableEqualFunction( if (IS_INTRESOURCE(entry1->Name)) { if (IS_INTRESOURCE(entry2->Name)) - return entry1->Name == entry2->Name; + return PtrToUlong(entry1->Name) == PtrToUlong(entry2->Name); else return FALSE; } From 43b335498f8dba04ae08788b916ecab88c6353ae Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 25 Jun 2019 06:10:34 +0200 Subject: [PATCH 1953/2058] Add PhGetAccountPrivileges --- phlib/include/lsasup.h | 8 ++++++++ phlib/lsasup.c | 34 +++++++++++++++++++++++++++++++++- phlib/util.c | 34 +--------------------------------- 3 files changed, 42 insertions(+), 34 deletions(-) diff --git a/phlib/include/lsasup.h b/phlib/include/lsasup.h index a58972c3cd09..d5a07d7d5c0c 100644 --- a/phlib/include/lsasup.h +++ b/phlib/include/lsasup.h @@ -98,6 +98,14 @@ PhGetTokenUserString( _In_ BOOLEAN IncludeDomain ); +PHLIBAPI +NTSTATUS +NTAPI +PhGetAccountPrivileges( + _In_ PSID AccountSid, + _Out_ PTOKEN_PRIVILEGES* Privileges + ); + PHLIBAPI PPH_STRING NTAPI diff --git a/phlib/lsasup.c b/phlib/lsasup.c index e6bce68e4826..ea662665b325 100644 --- a/phlib/lsasup.c +++ b/phlib/lsasup.c @@ -529,7 +529,7 @@ PPH_STRING PhGetSidFullName( if (domainNameBuffer && domainNameLength != 0) { - fullName = PhCreateStringEx(NULL, domainNameLength + sizeof(WCHAR) + names[0].Name.Length); + fullName = PhCreateStringEx(NULL, domainNameLength + sizeof(UNICODE_NULL) + names[0].Name.Length); memcpy(&fullName->Buffer[0], domainNameBuffer, domainNameLength); fullName->Buffer[domainNameLength / sizeof(WCHAR)] = OBJ_NAME_PATH_SEPARATOR; memcpy(&fullName->Buffer[domainNameLength / sizeof(WCHAR) + 1], names[0].Name.Buffer, names[0].Name.Length); @@ -615,6 +615,38 @@ PPH_STRING PhGetTokenUserString( return tokenUserString; } +NTSTATUS PhGetAccountPrivileges( + _In_ PSID AccountSid, + _Out_ PTOKEN_PRIVILEGES *Privileges + ) +{ + NTSTATUS status; + LSA_HANDLE accountHandle; + PPRIVILEGE_SET accountPrivileges; + PTOKEN_PRIVILEGES privileges; + + status = LsaOpenAccount(PhGetLookupPolicyHandle(), AccountSid, ACCOUNT_VIEW, &accountHandle); + + if (!NT_SUCCESS(status)) + return status; + + status = LsaEnumeratePrivilegesOfAccount(accountHandle, &accountPrivileges); + LsaClose(accountHandle); + + if (!NT_SUCCESS(status)) + return status; + + privileges = PhAllocate(FIELD_OFFSET(TOKEN_PRIVILEGES, Privileges) + sizeof(LUID_AND_ATTRIBUTES) * accountPrivileges->PrivilegeCount); + privileges->PrivilegeCount = accountPrivileges->PrivilegeCount; + memcpy(privileges->Privileges, accountPrivileges->Privilege, sizeof(LUID_AND_ATTRIBUTES) * accountPrivileges->PrivilegeCount); + + LsaFreeMemory(accountPrivileges); + + *Privileges = privileges; + + return status; +} + typedef struct _PH_CAPABILITY_ENTRY { PPH_STRING Name; diff --git a/phlib/util.c b/phlib/util.c index f4b9a4cb20ab..9451f2e5a34a 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -3101,38 +3101,6 @@ NTSTATUS PhCreateProcessAsUser( return status; } -NTSTATUS PhpGetAccountPrivileges( - _In_ PSID AccountSid, - _Out_ PTOKEN_PRIVILEGES *Privileges - ) -{ - NTSTATUS status; - LSA_HANDLE accountHandle; - PPRIVILEGE_SET accountPrivileges; - PTOKEN_PRIVILEGES privileges; - - status = LsaOpenAccount(PhGetLookupPolicyHandle(), AccountSid, ACCOUNT_VIEW, &accountHandle); - - if (!NT_SUCCESS(status)) - return status; - - status = LsaEnumeratePrivilegesOfAccount(accountHandle, &accountPrivileges); - LsaClose(accountHandle); - - if (!NT_SUCCESS(status)) - return status; - - privileges = PhAllocate(FIELD_OFFSET(TOKEN_PRIVILEGES, Privileges) + sizeof(LUID_AND_ATTRIBUTES) * accountPrivileges->PrivilegeCount); - privileges->PrivilegeCount = accountPrivileges->PrivilegeCount; - memcpy(privileges->Privileges, accountPrivileges->Privilege, sizeof(LUID_AND_ATTRIBUTES) * accountPrivileges->PrivilegeCount); - - LsaFreeMemory(accountPrivileges); - - *Privileges = privileges; - - return status; -} - /** * Filters a token to create a limited user security context. * @@ -3212,7 +3180,7 @@ NTSTATUS PhFilterTokenForLimitedUser( return status; // Get the privileges of the Users group - the privileges that we are going to allow. - if (!NT_SUCCESS(PhpGetAccountPrivileges(usersSid, &privilegesOfUsers))) + if (!NT_SUCCESS(PhGetAccountPrivileges(usersSid, &privilegesOfUsers))) { // Unsuccessful, so use the default set of privileges. privilegesOfUsers = PhAllocate(FIELD_OFFSET(TOKEN_PRIVILEGES, Privileges) + sizeof(defaultAllowedPrivileges)); From e2c45f98c8805ad65bf14546ba13a5c515c8551e Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 25 Jun 2019 06:14:07 +0200 Subject: [PATCH 1954/2058] Add MMapIO statistics to memory information tab --- ProcessHacker/ProcessHacker.rc | 5 +++++ ProcessHacker/resource.h | 2 ++ ProcessHacker/sysscmem.c | 24 ++++++++++++++++++++---- 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/ProcessHacker/ProcessHacker.rc b/ProcessHacker/ProcessHacker.rc index f7baf30c2ce9..cbf282a04982 100644 --- a/ProcessHacker/ProcessHacker.rc +++ b/ProcessHacker/ProcessHacker.rc @@ -1482,6 +1482,11 @@ BEGIN PUSHBUTTON "&More",IDC_MORE,242,152,50,14 RTEXT "Static",IDC_ZPHYSICALRESERVED_V,167,31,55,8,SS_ENDELLIPSIS LTEXT "Reserved",IDC_STATIC,120,31,32,8 + GROUPBOX "Mapped IO",IDC_STATIC,112,132,118,36 + LTEXT "Mapped reads",IDC_STATIC,119,145,68,8 + RTEXT "Static",IDC_ZMAPPEDREADIO,180,145,42,8,SS_ENDELLIPSIS + LTEXT "Mapped writes",IDC_STATIC,119,156,68,8 + RTEXT "Static",IDC_ZMAPPEDWRITEIO,180,156,42,8,SS_ENDELLIPSIS END IDD_SYSINFO_MEM DIALOGEX 0, 0, 316, 250 diff --git a/ProcessHacker/resource.h b/ProcessHacker/resource.h index 5db3122f8be5..35374aa7771e 100644 --- a/ProcessHacker/resource.h +++ b/ProcessHacker/resource.h @@ -517,7 +517,9 @@ #define IDC_ZPAGINGPAGEFILEWRITESDELTA_V 1370 #define IDC_PINWINDOW 1370 #define IDC_ZPAGINGMAPPEDWRITESDELTA_V 1371 +#define IDC_ZMAPPEDREADIO 1372 #define IDC_ZLISTMODIFIEDPAGEFILE_V 1373 +#define IDC_ZMAPPEDWRITEIO 1374 #define IDC_SECTION 1375 #define IDC_REGEX 1377 #define IDC_DESCRIPTIONLABEL 1378 diff --git a/ProcessHacker/sysscmem.c b/ProcessHacker/sysscmem.c index 4e947f9cf8d7..96c684e40645 100644 --- a/ProcessHacker/sysscmem.c +++ b/ProcessHacker/sysscmem.c @@ -50,6 +50,8 @@ static PH_UINT32_DELTA PageFaultsDelta; static PH_UINT32_DELTA PageReadsDelta; static PH_UINT32_DELTA PagefileWritesDelta; static PH_UINT32_DELTA MappedWritesDelta; +static PH_UINT64_DELTA MappedIoReadDelta; +static PH_UINT64_DELTA MappedIoWritesDelta; static BOOLEAN MmAddressesInitialized; static PSIZE_T MmSizeOfPagedPoolInBytes; static PSIZE_T MmMaximumNonPagedPoolInBytes; @@ -231,6 +233,8 @@ VOID PhSipInitializeMemoryDialog( PhInitializeDelta(&PageReadsDelta); PhInitializeDelta(&PagefileWritesDelta); PhInitializeDelta(&MappedWritesDelta); + PhInitializeDelta(&MappedIoReadDelta); + PhInitializeDelta(&MappedIoWritesDelta); PhInitializeGraphState(&CommitGraphState); PhInitializeGraphState(&PhysicalGraphState); @@ -264,11 +268,11 @@ VOID PhSipTickMemoryDialog( PhUpdateDelta(&PageReadsDelta, PhPerfInformation.PageReadCount); PhUpdateDelta(&PagefileWritesDelta, PhPerfInformation.DirtyPagesWriteCount); PhUpdateDelta(&MappedWritesDelta, PhPerfInformation.MappedPagesWriteCount); + PhUpdateDelta(&MappedIoReadDelta, UInt32x32To64(PhPerfInformation.PageReadCount, PAGE_SIZE)); + PhUpdateDelta(&MappedIoWritesDelta, PhPerfInformation.MappedPagesWriteCount + PhPerfInformation.DirtyPagesWriteCount + PhPerfInformation.CcLazyWritePages * PAGE_SIZE); - MemoryTicked++; - - if (MemoryTicked > 2) - MemoryTicked = 2; + if (MemoryTicked < 2) + MemoryTicked++; PhSipUpdateMemoryGraphs(); PhSipUpdateMemoryPanel(); @@ -775,6 +779,18 @@ VOID PhSipUpdateMemoryPanel( else PhSetDialogItemText(MemoryPanel, IDC_ZPAGINGMAPPEDWRITESDELTA_V, L"-"); + // Mapped + + if (MemoryTicked > 1) + PhSetDialogItemText(MemoryPanel, IDC_ZMAPPEDREADIO, PhaFormatSize(MappedIoReadDelta.Delta, ULONG_MAX)->Buffer); + else + PhSetDialogItemText(MemoryPanel, IDC_ZMAPPEDREADIO, L"-"); + + if (MemoryTicked > 1) + PhSetDialogItemText(MemoryPanel, IDC_ZMAPPEDWRITEIO, PhaFormatSize(MappedIoWritesDelta.Delta, ULONG_MAX)->Buffer); + else + PhSetDialogItemText(MemoryPanel, IDC_ZMAPPEDWRITEIO, L"-"); + // Memory lists if (NT_SUCCESS(NtQuerySystemInformation( From 5daffdee586145faa4499e33a72de52ad983e513 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 25 Jun 2019 06:15:27 +0200 Subject: [PATCH 1955/2058] Remove autopool from PhFormatTimeSpanRelative --- phlib/util.c | 65 ++++++++++++++++++++++++++++++++++------------------ 1 file changed, 43 insertions(+), 22 deletions(-) diff --git a/phlib/util.c b/phlib/util.c index 9451f2e5a34a..12a4c16303fb 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -1349,7 +1349,6 @@ PPH_STRING PhFormatTimeSpanRelative( _In_ ULONG64 TimeSpan ) { - PH_AUTO_POOL autoPool; PPH_STRING string; DOUBLE days; DOUBLE weeks; @@ -1358,8 +1357,6 @@ PPH_STRING PhFormatTimeSpanRelative( DOUBLE years; DOUBLE centuries; - PhInitializeAutoPool(&autoPool); - days = (DOUBLE)TimeSpan / PH_TICKS_PER_DAY; weeks = days / 7; fortnights = weeks / 2; @@ -1369,23 +1366,23 @@ PPH_STRING PhFormatTimeSpanRelative( if (centuries >= 1) { - string = PhaFormatString(L"%u %s", (ULONG)centuries, (ULONG)centuries == 1 ? L"century" : L"centuries"); + string = PhFormatString(L"%u %s", (ULONG)centuries, (ULONG)centuries == 1 ? L"century" : L"centuries"); } else if (years >= 1) { - string = PhaFormatString(L"%u %s", (ULONG)years, (ULONG)years == 1 ? L"year" : L"years"); + string = PhFormatString(L"%u %s", (ULONG)years, (ULONG)years == 1 ? L"year" : L"years"); } else if (months >= 1) { - string = PhaFormatString(L"%u %s", (ULONG)months, (ULONG)months == 1 ? L"month" : L"months"); + string = PhFormatString(L"%u %s", (ULONG)months, (ULONG)months == 1 ? L"month" : L"months"); } else if (fortnights >= 1) { - string = PhaFormatString(L"%u %s", (ULONG)fortnights, (ULONG)fortnights == 1 ? L"fortnight" : L"fortnights"); + string = PhFormatString(L"%u %s", (ULONG)fortnights, (ULONG)fortnights == 1 ? L"fortnight" : L"fortnights"); } else if (weeks >= 1) { - string = PhaFormatString(L"%u %s", (ULONG)weeks, (ULONG)weeks == 1 ? L"week" : L"weeks"); + string = PhFormatString(L"%u %s", (ULONG)weeks, (ULONG)weeks == 1 ? L"week" : L"weeks"); } else { @@ -1404,45 +1401,72 @@ PPH_STRING PhFormatTimeSpanRelative( if (days >= 1) { - string = PhaFormatString(L"%u %s", (ULONG)days, (ULONG)days == 1 ? L"day" : L"days"); hoursPartial = (ULONG)PH_TICKS_PARTIAL_HOURS(TimeSpan); if (hoursPartial >= 1) { - string = PhaFormatString(L"%s and %u %s", string->Buffer, hoursPartial, hoursPartial == 1 ? L"hour" : L"hours"); + string = PhFormatString( + L"%u %s and %u %s", + (ULONG)days, + (ULONG)days == 1 ? L"day" : L"days", + hoursPartial, + hoursPartial == 1 ? L"hour" : L"hours" + ); + } + else + { + string = PhFormatString(L"%u %s", (ULONG)days, (ULONG)days == 1 ? L"day" : L"days"); } } else if (hours >= 1) { - string = PhaFormatString(L"%u %s", (ULONG)hours, (ULONG)hours == 1 ? L"hour" : L"hours"); minutesPartial = (ULONG)PH_TICKS_PARTIAL_MIN(TimeSpan); if (minutesPartial >= 1) { - string = PhaFormatString(L"%s and %u %s", string->Buffer, (ULONG)minutesPartial, (ULONG)minutesPartial == 1 ? L"minute" : L"minutes"); + string = PhFormatString( + L"%u %s and %u %s", + (ULONG)hours, + (ULONG)hours == 1 ? L"hour" : L"hours", + (ULONG)minutesPartial, + (ULONG)minutesPartial == 1 ? L"minute" : L"minutes" + ); + } + else + { + string = PhFormatString(L"%u %s", (ULONG)hours, (ULONG)hours == 1 ? L"hour" : L"hours"); } } else if (minutes >= 1) { - string = PhaFormatString(L"%u %s", (ULONG)minutes, (ULONG)minutes == 1 ? L"minute" : L"minutes"); secondsPartial = (ULONG)PH_TICKS_PARTIAL_SEC(TimeSpan); if (secondsPartial >= 1) { - string = PhaFormatString(L"%s and %u %s", string->Buffer, (ULONG)secondsPartial, (ULONG)secondsPartial == 1 ? L"second" : L"seconds"); + string = PhFormatString( + L"%u %s and %u %s", + (ULONG)minutes, + (ULONG)minutes == 1 ? L"minute" : L"minutes", + (ULONG)secondsPartial, + (ULONG)secondsPartial == 1 ? L"second" : L"seconds" + ); + } + else + { + string = PhFormatString(L"%u %s", (ULONG)minutes, (ULONG)minutes == 1 ? L"minute" : L"minutes"); } } else if (seconds >= 1) { - string = PhaFormatString(L"%u %s", (ULONG)seconds, (ULONG)seconds == 1 ? L"second" : L"seconds"); + string = PhFormatString(L"%u %s", (ULONG)seconds, (ULONG)seconds == 1 ? L"second" : L"seconds"); } else if (milliseconds >= 1) { - string = PhaFormatString(L"%u %s", (ULONG)milliseconds, (ULONG)milliseconds == 1 ? L"millisecond" : L"milliseconds"); + string = PhFormatString(L"%u %s", (ULONG)milliseconds, (ULONG)milliseconds == 1 ? L"millisecond" : L"milliseconds"); } else { - string = PhaCreateString(L"a very short time"); + string = PhCreateString(L"a very short time"); } } @@ -1451,14 +1475,11 @@ PPH_STRING PhFormatTimeSpanRelative( { // Special vowel case: a hour -> an hour if (string->Buffer[2] != 'h') - string = PhaConcatStrings2(L"a ", &string->Buffer[2]); + PhMoveReference(&string, PhConcatStrings2(L"a ", &string->Buffer[2])); else - string = PhaConcatStrings2(L"an ", &string->Buffer[2]); + PhMoveReference(&string, PhConcatStrings2(L"an ", &string->Buffer[2])); } - PhReferenceObject(string); - PhDeleteAutoPool(&autoPool); - return string; } From 574da6d2b8614c028f41f025d388bbf6f5d06aea Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 25 Jun 2019 06:21:49 +0200 Subject: [PATCH 1956/2058] Add PhEnumWindows, Update PhGetProcessMainWindow to enumerate top-level only --- phlib/guisup.c | 13 +++++++++++-- phlib/include/guisup.h | 10 ++++++++++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/phlib/guisup.c b/phlib/guisup.c index 099140251376..657ad5c0814a 100644 --- a/phlib/guisup.c +++ b/phlib/guisup.c @@ -1389,6 +1389,14 @@ VOID PhRemoveWindowContext( PhReleaseQueuedLockExclusive(&WindowContextListLock); } +VOID PhEnumWindows( + _In_ PH_ENUM_CALLBACK Callback, + _In_opt_ PVOID Context + ) +{ + EnumWindows((WNDENUMPROC)Callback, (LPARAM)Context); +} + VOID PhEnumChildWindows( _In_opt_ HWND WindowHandle, _In_ ULONG Limit, @@ -1417,7 +1425,7 @@ typedef struct _GET_PROCESS_MAIN_WINDOW_CONTEXT BOOLEAN SkipInvisible; } GET_PROCESS_MAIN_WINDOW_CONTEXT, *PGET_PROCESS_MAIN_WINDOW_CONTEXT; -BOOLEAN CALLBACK PhpGetProcessMainWindowEnumWindowsProc( +BOOL CALLBACK PhpGetProcessMainWindowEnumWindowsProc( _In_ HWND WindowHandle, _In_opt_ PVOID Context ) @@ -1486,7 +1494,8 @@ HWND PhGetProcessMainWindowEx( if (processHandle && WINDOWS_HAS_IMMERSIVE && IsImmersiveProcess) context.IsImmersive = IsImmersiveProcess(processHandle); - PhEnumChildWindows(NULL, 0x800, PhpGetProcessMainWindowEnumWindowsProc, &context); + PhEnumWindows(PhpGetProcessMainWindowEnumWindowsProc, &context); + //PhEnumChildWindows(NULL, 0x800, PhpGetProcessMainWindowEnumWindowsProc, &context); if (!ProcessHandle && processHandle) NtClose(processHandle); diff --git a/phlib/include/guisup.h b/phlib/include/guisup.h index b50870aca3ad..f76abc2d6128 100644 --- a/phlib/include/guisup.h +++ b/phlib/include/guisup.h @@ -491,6 +491,16 @@ PhRemoveWindowContext( _In_ ULONG PropertyHash ); +typedef BOOL (CALLBACK* PH_ENUM_CALLBACK)( + _In_ HWND WindowHandle, + _In_opt_ PVOID Context + ); + +VOID PhEnumWindows( + _In_ PH_ENUM_CALLBACK Callback, + _In_opt_ PVOID Context + ); + typedef BOOLEAN (CALLBACK *PH_CHILD_ENUM_CALLBACK)( _In_ HWND WindowHandle, _In_opt_ PVOID Context From c581a7649aef19623558fd3833a2775197a7104d Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 25 Jun 2019 06:22:28 +0200 Subject: [PATCH 1957/2058] Improve window title column performance --- ProcessHacker/proctree.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/ProcessHacker/proctree.c b/ProcessHacker/proctree.c index dd73e7e22126..926573e769d5 100644 --- a/ProcessHacker/proctree.c +++ b/ProcessHacker/proctree.c @@ -912,11 +912,7 @@ static VOID PhpUpdateProcessNodeWindow( { PhClearReference(&ProcessNode->WindowText); - if (ProcessNode->ProcessItem->IsSubsystemProcess) - { - NOTHING; - } - else + if (ProcessNode->ProcessItem->QueryHandle && !ProcessNode->ProcessItem->IsSubsystemProcess) { ProcessNode->WindowHandle = PhGetProcessMainWindow( ProcessNode->ProcessId, @@ -925,7 +921,12 @@ static VOID PhpUpdateProcessNodeWindow( if (ProcessNode->WindowHandle) { - PhGetWindowTextEx(ProcessNode->WindowHandle, PH_GET_WINDOW_TEXT_INTERNAL, &ProcessNode->WindowText); + PhGetWindowTextEx( + ProcessNode->WindowHandle, + PH_GET_WINDOW_TEXT_INTERNAL, + &ProcessNode->WindowText + ); + ProcessNode->WindowHung = !!IsHungAppWindow(ProcessNode->WindowHandle); } } From 57762d456477c37e984e9d1c159b799b21b85456 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 25 Jun 2019 09:19:35 +0200 Subject: [PATCH 1958/2058] peview: Fix CLR tab layout spacing --- tools/peview/peview.rc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/peview/peview.rc b/tools/peview/peview.rc index 2e9ea1bed7c1..d2e0526072fb 100644 --- a/tools/peview/peview.rc +++ b/tools/peview/peview.rc @@ -262,8 +262,8 @@ BEGIN LTEXT "Static",IDC_RUNTIMEVERSION,78,7,215,8 LTEXT "Flags:",IDC_STATIC,7,19,20,8 EDITTEXT IDC_FLAGS,76,19,217,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER - LTEXT "Version String:",IDC_STATIC,7,31,48,8 - LTEXT "Static",IDC_VERSIONSTRING,78,31,215,8 + LTEXT "Version String:",IDC_STATIC,7,32,48,8 + LTEXT "Static",IDC_VERSIONSTRING,78,32,215,8 CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,69,286,204 LTEXT "Sections:",IDC_STATIC,7,58,30,8 LTEXT "MVID:",IDC_STATIC,7,44,21,8 From e2e1f0593c3e10a8a343c723fac48ab840b22c58 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 28 Jun 2019 02:53:52 +0200 Subject: [PATCH 1959/2058] Fix #431 --- ProcessHacker/runas.c | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/ProcessHacker/runas.c b/ProcessHacker/runas.c index 4b22932f6a86..99c8d25054b6 100644 --- a/ProcessHacker/runas.c +++ b/ProcessHacker/runas.c @@ -200,18 +200,29 @@ BOOLEAN IsServiceAccount( _In_ PPH_STRING UserName ) { + BOOLEAN serviceAccount = FALSE; + PPH_STRING localSystemSidName; + PPH_STRING localServiceSidName; + PPH_STRING localNetworkSidName; + + localSystemSidName = PhGetSidFullName(&PhSeLocalSystemSid, TRUE, NULL); + localServiceSidName = PhGetSidFullName(&PhSeLocalServiceSid, TRUE, NULL); + localNetworkSidName = PhGetSidFullName(&PhSeNetworkServiceSid, TRUE, NULL); + if ( - PhEqualString2(UserName, L"NT AUTHORITY\\LOCAL SERVICE", TRUE) || - PhEqualString2(UserName, L"NT AUTHORITY\\NETWORK SERVICE", TRUE) || - PhEqualString2(UserName, L"NT AUTHORITY\\SYSTEM", TRUE) + PhEqualString(localSystemSidName, UserName, TRUE) || + PhEqualString(localServiceSidName, UserName, TRUE) || + PhEqualString(localNetworkSidName, UserName, TRUE) ) { - return TRUE; - } - else - { - return FALSE; + serviceAccount = TRUE; } + + PhDereferenceObject(localNetworkSidName); + PhDereferenceObject(localServiceSidName); + PhDereferenceObject(localSystemSidName); + + return serviceAccount; } BOOLEAN IsCurrentUserAccount( From c5aa9e2fbb94c4b6e08a364a57f4259b53439304 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 5 Jul 2019 17:11:37 +0200 Subject: [PATCH 1960/2058] Fix #396 --- ProcessHacker/mtgndlg.c | 47 +++++++++++++++++++++-------------------- 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/ProcessHacker/mtgndlg.c b/ProcessHacker/mtgndlg.c index 85bd4aa4fb69..d874475dedad 100644 --- a/ProcessHacker/mtgndlg.c +++ b/ProcessHacker/mtgndlg.c @@ -181,29 +181,30 @@ INT_PTR CALLBACK PhpProcessMitigationPolicyDlgProc( if (context->SystemDllInitBlock && RTL_CONTAINS_FIELD(context->SystemDllInitBlock, context->SystemDllInitBlock->Size, MitigationOptionsMap)) { - if (context->SystemDllInitBlock->MitigationOptionsMap.Map[0] & PROCESS_CREATION_MITIGATION_POLICY2_LOADER_INTEGRITY_CONTINUITY_ALWAYS_ON) - { - PMITIGATION_POLICY_ENTRY entry; - - entry = PhAllocate(sizeof(MITIGATION_POLICY_ENTRY)); - entry->NonStandard = TRUE; - entry->ShortDescription = PhCreateString(L"Loader Integrity"); - entry->LongDescription = PhCreateString(L"OS signing levels for dependent module loads are enabled."); - - PhAddListViewItem(lvHandle, MAXINT, entry->ShortDescription->Buffer, entry); - } - - if (context->SystemDllInitBlock->MitigationOptionsMap.Map[0] & PROCESS_CREATION_MITIGATION_POLICY2_MODULE_TAMPERING_PROTECTION_ALWAYS_ON) - { - PMITIGATION_POLICY_ENTRY entry; - - entry = PhAllocate(sizeof(MITIGATION_POLICY_ENTRY)); - entry->NonStandard = TRUE; - entry->ShortDescription = PhCreateString(L"Module Tampering"); - entry->LongDescription = PhCreateString(L"Module Tampering protection is enabled."); - - PhAddListViewItem(lvHandle, MAXINT, entry->ShortDescription->Buffer, entry); - } + // TODO: Windows doesn't propagate these flags into the MitigationOptionsMap array. (dmex) + //if (context->SystemDllInitBlock->MitigationOptionsMap.Map[0] & PROCESS_CREATION_MITIGATION_POLICY2_LOADER_INTEGRITY_CONTINUITY_ALWAYS_ON) + //{ + // PMITIGATION_POLICY_ENTRY entry; + // + // entry = PhAllocate(sizeof(MITIGATION_POLICY_ENTRY)); + // entry->NonStandard = TRUE; + // entry->ShortDescription = PhCreateString(L"Loader Integrity"); + // entry->LongDescription = PhCreateString(L"OS signing levels for dependent module loads are enabled."); + // + // PhAddListViewItem(lvHandle, MAXINT, entry->ShortDescription->Buffer, entry); + //} + + //if (context->SystemDllInitBlock->MitigationOptionsMap.Map[0] & PROCESS_CREATION_MITIGATION_POLICY2_MODULE_TAMPERING_PROTECTION_ALWAYS_ON) + //{ + // PMITIGATION_POLICY_ENTRY entry; + // + // entry = PhAllocate(sizeof(MITIGATION_POLICY_ENTRY)); + // entry->NonStandard = TRUE; + // entry->ShortDescription = PhCreateString(L"Module Tampering"); + // entry->LongDescription = PhCreateString(L"Module Tampering protection is enabled."); + // + // PhAddListViewItem(lvHandle, MAXINT, entry->ShortDescription->Buffer, entry); + //} if (context->SystemDllInitBlock->MitigationOptionsMap.Map[0] & PROCESS_CREATION_MITIGATION_POLICY2_RESTRICT_INDIRECT_BRANCH_PREDICTION_ALWAYS_ON) { From 2239c6a5da6ea1caf7583d1adb36e36ba9937325 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 5 Jul 2019 17:13:09 +0200 Subject: [PATCH 1961/2058] Fix #423 --- phnt/include/ntexapi.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phnt/include/ntexapi.h b/phnt/include/ntexapi.h index 24c295c3b1a6..43c9ef517039 100644 --- a/phnt/include/ntexapi.h +++ b/phnt/include/ntexapi.h @@ -1580,7 +1580,7 @@ typedef struct _SYSTEM_THREAD_INFORMATION KPRIORITY Priority; LONG BasePriority; ULONG ContextSwitches; - ULONG ThreadState; + KTHREAD_STATE ThreadState; KWAIT_REASON WaitReason; } SYSTEM_THREAD_INFORMATION, *PSYSTEM_THREAD_INFORMATION; From a47161c3b7644962f811276d48bee86589fcf426 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 5 Jul 2019 18:45:35 +0200 Subject: [PATCH 1962/2058] Add PhDoesFileExistsWin32 --- phlib/include/phnative.h | 7 +++++++ phlib/native.c | 27 ++++++++++++++++++++++++--- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/phlib/include/phnative.h b/phlib/include/phnative.h index f189d0075288..3b7fc65b9d9c 100644 --- a/phlib/include/phnative.h +++ b/phlib/include/phnative.h @@ -1325,6 +1325,13 @@ PhQueryAttributesFileWin32( _Out_ PFILE_BASIC_INFORMATION FileInformation ); +PHLIBAPI +BOOLEAN +NTAPI +PhDoesFileExistsWin32( + _In_ PWSTR FileName + ); + PHLIBAPI NTSTATUS NTAPI diff --git a/phlib/native.c b/phlib/native.c index 33f0970e942a..9c0cee8329ab 100644 --- a/phlib/native.c +++ b/phlib/native.c @@ -7528,6 +7528,27 @@ NTSTATUS PhQueryAttributesFileWin32( return status; } +BOOLEAN PhDoesFileExistsWin32( + _In_ PWSTR FileName + ) +{ + NTSTATUS status; + FILE_BASIC_INFORMATION basicInfo; + + status = PhQueryAttributesFileWin32(FileName, &basicInfo); + + if ( + NT_SUCCESS(status) || + status == STATUS_SHARING_VIOLATION || + status == STATUS_ACCESS_DENIED + ) + { + return TRUE; + } + + return FALSE; +} + /** * Deletes a file. * @@ -7575,7 +7596,7 @@ NTSTATUS PhCreateDirectory( if (PhIsNullOrEmptyString(DirectoryPath)) return STATUS_FAIL_CHECK; - if (RtlDoesFileExists_U(PhGetString(DirectoryPath))) + if (PhDoesFileExistsWin32(PhGetString(DirectoryPath))) return STATUS_SUCCESS; remainingPart = PhGetStringRef(DirectoryPath); @@ -7599,7 +7620,7 @@ NTSTATUS PhCreateDirectory( ); // Check if the directory already exists. - if (!RtlDoesFileExists_U(PhGetString(tempPathString))) + if (!PhDoesFileExistsWin32(PhGetString(tempPathString))) { HANDLE directoryHandle; @@ -7626,7 +7647,7 @@ NTSTATUS PhCreateDirectory( if (directoryPath) PhDereferenceObject(directoryPath); - if (RtlDoesFileExists_U(PhGetString(DirectoryPath))) + if (PhDoesFileExistsWin32(PhGetString(DirectoryPath))) return STATUS_SUCCESS; else return STATUS_NOT_FOUND; From 7665661da34595b3b359a539f2ca243de3b61261 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 5 Jul 2019 18:51:20 +0200 Subject: [PATCH 1963/2058] Update PhDeleteFile flags for RS5 --- phlib/native.c | 40 +++++++++++++++++++++++++++++----------- 1 file changed, 29 insertions(+), 11 deletions(-) diff --git a/phlib/native.c b/phlib/native.c index 9c0cee8329ab..883f13ca02df 100644 --- a/phlib/native.c +++ b/phlib/native.c @@ -2824,18 +2824,36 @@ NTSTATUS PhDeleteFile( _In_ HANDLE FileHandle ) { - FILE_DISPOSITION_INFORMATION dispositionInfo; - IO_STATUS_BLOCK isb; + if (WindowsVersion >= WINDOWS_10_RS5) + { + FILE_DISPOSITION_INFO_EX dispositionInfoEx; + IO_STATUS_BLOCK isb; - dispositionInfo.DeleteFile = TRUE; + dispositionInfoEx.Flags = FILE_DISPOSITION_FLAG_DELETE | FILE_DISPOSITION_FLAG_IGNORE_READONLY_ATTRIBUTE; - return NtSetInformationFile( - FileHandle, - &isb, - &dispositionInfo, - sizeof(FILE_DISPOSITION_INFORMATION), - FileDispositionInformation - ); + return NtSetInformationFile( + FileHandle, + &isb, + &dispositionInfoEx, + sizeof(FILE_DISPOSITION_INFO_EX), + FileDispositionInformationEx + ); + } + else + { + FILE_DISPOSITION_INFORMATION dispositionInfo; + IO_STATUS_BLOCK isb; + + dispositionInfo.DeleteFile = TRUE; + + return NtSetInformationFile( + FileHandle, + &isb, + &dispositionInfo, + sizeof(FILE_DISPOSITION_INFORMATION), + FileDispositionInformation + ); + } } NTSTATUS PhGetFileHandleName( @@ -7699,7 +7717,7 @@ static BOOLEAN PhpDeleteDirectoryCallback( } else { - if (Information->FileAttributes & FILE_ATTRIBUTE_READONLY) + if (WindowsVersion < WINDOWS_10_RS5 && (Information->FileAttributes & FILE_ATTRIBUTE_READONLY)) { HANDLE fileHandle; From 48c25f9ba4eaa05182d197620a550b1cf8121f00 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 6 Jul 2019 09:19:52 +0200 Subject: [PATCH 1964/2058] Improve memory enumeration performance --- ProcessHacker/include/memprv.h | 5 +++++ ProcessHacker/memprv.c | 21 ++++++++++++++++++--- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/ProcessHacker/include/memprv.h b/ProcessHacker/include/memprv.h index 79ecaa694f5b..420331c6f888 100644 --- a/ProcessHacker/include/memprv.h +++ b/ProcessHacker/include/memprv.h @@ -47,6 +47,11 @@ typedef struct _PH_MEMORY_ITEM MEMORY_BASIC_INFORMATION BasicInfo; }; + union + { + MEMORY_WORKING_SET_EX_BLOCK VirtualAttributes; + }; + struct _PH_MEMORY_ITEM *AllocationBaseItem; SIZE_T CommittedSize; diff --git a/ProcessHacker/memprv.c b/ProcessHacker/memprv.c index 4653985d0342..1c4ce6a102d9 100644 --- a/ProcessHacker/memprv.c +++ b/ProcessHacker/memprv.c @@ -469,12 +469,11 @@ NTSTATUS PhpUpdateMemoryRegionTypes( } } - if (memoryItem->State & MEM_COMMIT) + if (memoryItem->VirtualAttributes.Valid && memoryItem->State & MEM_COMMIT) { UCHAR buffer[HEAP_SEGMENT_MAX_SIZE]; - if (NT_SUCCESS(NtReadVirtualMemory(ProcessHandle, memoryItem->BaseAddress, - buffer, sizeof(buffer), NULL))) + if (NT_SUCCESS(NtReadVirtualMemory(ProcessHandle, memoryItem->BaseAddress, buffer, sizeof(buffer), NULL))) { PVOID candidateHeap = NULL; ULONG candidateHeap32 = 0; @@ -761,6 +760,7 @@ NTSTATUS PhQueryMemoryItemList( ))) { PPH_MEMORY_ITEM memoryItem; + MEMORY_WORKING_SET_EX_INFORMATION info; if (basicInfo.State & MEM_FREE) { @@ -786,6 +786,21 @@ NTSTATUS PhQueryMemoryItemList( memoryItem->PrivateSize = memoryItem->RegionSize; } + // Query the region attributes (dmex) + info.VirtualAddress = baseAddress; + + if (NT_SUCCESS(NtQueryVirtualMemory( + processHandle, + NULL, + MemoryWorkingSetExInformation, + &info, + sizeof(MEMORY_WORKING_SET_EX_INFORMATION), + NULL + ))) + { + memoryItem->VirtualAttributes = info.u1.VirtualAttributes; + } + PhAddElementAvlTree(&List->Set, &memoryItem->Links); InsertTailList(&List->ListHead, &memoryItem->ListEntry); From 19009210a929973d59043418840afa04bceef5bc Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 6 Jul 2019 09:21:02 +0200 Subject: [PATCH 1965/2058] Fix filtered handle highlighting --- ProcessHacker/procprv.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/ProcessHacker/procprv.c b/ProcessHacker/procprv.c index d7f5814c13f4..25cab7dff5b2 100644 --- a/ProcessHacker/procprv.c +++ b/ProcessHacker/procprv.c @@ -2398,6 +2398,41 @@ VOID PhProcessProviderUpdate( } } + if (processItem->QueryHandle && processItem->IsHandleValid) + { + OBJECT_BASIC_INFORMATION basicInfo; + BOOLEAN filteredHandle = FALSE; + + if (NT_SUCCESS(PhGetHandleInformationEx( + NtCurrentProcess(), + processItem->QueryHandle, + ULONG_MAX, + 0, + NULL, + &basicInfo, + NULL, + NULL, + NULL, + NULL + ))) + { + if ((basicInfo.GrantedAccess & PROCESS_QUERY_INFORMATION) != PROCESS_QUERY_INFORMATION) + { + filteredHandle = TRUE; + } + } + else + { + filteredHandle = TRUE; + } + + if (processItem->IsProtectedHandle != filteredHandle) + { + processItem->IsProtectedHandle = filteredHandle; + modified = TRUE; + } + } + if (modified) { PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackProcessProviderModifiedEvent), processItem); From 40a225db57cf27a828bc699d2c1e825dd8e30a07 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 6 Jul 2019 09:22:52 +0200 Subject: [PATCH 1966/2058] Add theme support to selection dialog --- ProcessHacker/chdlg.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ProcessHacker/chdlg.c b/ProcessHacker/chdlg.c index 4f7567e92077..995946356e62 100644 --- a/ProcessHacker/chdlg.c +++ b/ProcessHacker/chdlg.c @@ -22,6 +22,7 @@ #include #include +#include typedef struct _CHOICE_DIALOG_CONTEXT { @@ -259,6 +260,8 @@ INT_PTR CALLBACK PhpChoiceDlgProc( SWP_NOACTIVATE | SWP_NOZORDER); } + PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport); + PhSetDialogFocus(hwndDlg, comboBoxHandle); } break; From 804a46f9ba8ede05b4ee123d9584892297f5a5eb Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 6 Jul 2019 09:25:00 +0200 Subject: [PATCH 1967/2058] Fix macro usage --- ProcessHacker/runas.c | 20 +++++++++----------- phlib/native.c | 2 +- phlib/util.c | 6 +++--- 3 files changed, 13 insertions(+), 15 deletions(-) diff --git a/ProcessHacker/runas.c b/ProcessHacker/runas.c index 99c8d25054b6..7b91344a31a7 100644 --- a/ProcessHacker/runas.c +++ b/ProcessHacker/runas.c @@ -119,7 +119,7 @@ static ULONG (WINAPI *NetUserEnum_I)( _In_ PCWSTR servername, _In_ ULONG level, _In_ ULONG filter, - _Out_ PBYTE *bufptr, + _Out_ PVOID *bufptr, _In_ ULONG prefmaxlen, _Out_ PULONG entriesread, _Out_ PULONG totalentries, @@ -280,7 +280,7 @@ PPH_STRING GetCurrentDesktopName( string = PhCreateStringEx(NULL, 0x200); if (GetUserObjectInformation( - GetThreadDesktop(HandleToULong(NtCurrentThreadId())), + GetThreadDesktop(HandleToUlong(NtCurrentThreadId())), UOI_NAME, string->Buffer, (ULONG)string->Length + sizeof(UNICODE_NULL), @@ -517,10 +517,8 @@ static VOID PhpAddAccountsToComboBox( { NET_API_STATUS status; LPUSER_INFO_0 userinfoArray = NULL; - ULONG userinfoMaxLength = MAX_PREFERRED_LENGTH; ULONG userinfoEntriesRead = 0; ULONG userinfoTotalEntries = 0; - ULONG userinfoResumeHandle = 0; PhpFreeAccountsComboBox(ComboBoxHandle); @@ -535,11 +533,11 @@ static VOID PhpAddAccountsToComboBox( NULL, 0, FILTER_NORMAL_ACCOUNT, - (PBYTE*)&userinfoArray, - userinfoMaxLength, + &userinfoArray, + MAX_PREFERRED_LENGTH, &userinfoEntriesRead, &userinfoTotalEntries, - &userinfoResumeHandle + NULL ); if (userinfoArray) @@ -552,11 +550,11 @@ static VOID PhpAddAccountsToComboBox( NULL, 0, FILTER_NORMAL_ACCOUNT, - (PBYTE*)&userinfoArray, - userinfoMaxLength, + &userinfoArray, + MAX_PREFERRED_LENGTH, &userinfoEntriesRead, &userinfoTotalEntries, - &userinfoResumeHandle + NULL ); if (status == NERR_Success) @@ -816,7 +814,7 @@ static VOID PhpAddDesktopsToComboBox( { PPH_RUNAS_DESKTOP_ITEM entry; - entry = PhAllocateZero(sizeof(PH_RUNAS_DESKTOP_ITEM)); + entry = PhAllocate(sizeof(PH_RUNAS_DESKTOP_ITEM)); entry->DesktopName = callback.DesktopList->Items[i]; ComboBox_SetItemData(ComboBoxHandle, itemIndex, entry); diff --git a/phlib/native.c b/phlib/native.c index 883f13ca02df..49e11ac6b47c 100644 --- a/phlib/native.c +++ b/phlib/native.c @@ -5345,7 +5345,7 @@ NTSTATUS PhGetProcessIsDotNetEx( // * Better performance. // * No need for admin rights to get .NET status of processes owned by other users. - PhInitFormatIU(&format[1], (ULONG_PTR)ProcessId); + PhInitFormatU(&format[1], HandleToUlong(ProcessId)); // Version 4 section object diff --git a/phlib/util.c b/phlib/util.c index 12a4c16303fb..dda96e6be41f 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -3343,7 +3343,7 @@ VOID PhShellExecute( _In_opt_ PWSTR Parameters ) { - SHELLEXECUTEINFO info = { sizeof(info) }; + SHELLEXECUTEINFO info = { sizeof(SHELLEXECUTEINFO) }; info.lpFile = FileName; info.lpParameters = Parameters; @@ -4337,7 +4337,7 @@ VOID PhSetFileDialogFileName( ofn->nMaxFile = (ULONG)max(fileName.Length / sizeof(WCHAR) + 1, 0x400); ofn->lpstrFile = PhAllocate(ofn->nMaxFile * sizeof(WCHAR)); - memcpy(ofn->lpstrFile, fileName.Buffer, fileName.Length + sizeof(WCHAR)); + memcpy(ofn->lpstrFile, fileName.Buffer, fileName.Length + sizeof(UNICODE_NULL)); } } @@ -5076,7 +5076,7 @@ BOOLEAN PhParseCommandLineFuzzy( // Note that we do not trim whitespace in each part because filenames can contain trailing // whitespace before the extension (e.g. "Internet .exe"). - temp.Buffer = PhAllocate(commandLine.Length + sizeof(WCHAR)); + temp.Buffer = PhAllocate(commandLine.Length + sizeof(UNICODE_NULL)); memcpy(temp.Buffer, commandLine.Buffer, commandLine.Length); temp.Buffer[commandLine.Length / sizeof(WCHAR)] = UNICODE_NULL; temp.Length = commandLine.Length; From 5af3f8fbf913ab4a6ee8890ab17490085888c699 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 6 Jul 2019 20:03:17 +0200 Subject: [PATCH 1968/2058] Fix flags --- ProcessHacker/include/memprv.h | 10 ++++++++-- ProcessHacker/memprv.c | 9 ++++++--- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/ProcessHacker/include/memprv.h b/ProcessHacker/include/memprv.h index 420331c6f888..c6772298c146 100644 --- a/ProcessHacker/include/memprv.h +++ b/ProcessHacker/include/memprv.h @@ -34,6 +34,7 @@ typedef struct _PH_MEMORY_ITEM union { + MEMORY_BASIC_INFORMATION BasicInfo; struct { PVOID BaseAddress; @@ -44,12 +45,17 @@ typedef struct _PH_MEMORY_ITEM ULONG Protect; ULONG Type; }; - MEMORY_BASIC_INFORMATION BasicInfo; }; union { - MEMORY_WORKING_SET_EX_BLOCK VirtualAttributes; + BOOLEAN Attributes; + struct + { + BOOLEAN Valid : 1; + BOOLEAN Bad : 1; + BOOLEAN Spare : 6; + }; }; struct _PH_MEMORY_ITEM *AllocationBaseItem; diff --git a/ProcessHacker/memprv.c b/ProcessHacker/memprv.c index 1c4ce6a102d9..21ca87a079f6 100644 --- a/ProcessHacker/memprv.c +++ b/ProcessHacker/memprv.c @@ -314,7 +314,7 @@ NTSTATUS PhpUpdateMemoryRegionTypes( if (NT_SUCCESS(PhGetProcessBasicInformation(ProcessHandle, &basicInfo)) && basicInfo.PebBaseAddress != 0) { - // HACK: Windows 10 RS2 and above 'added TEB/PEB sub-VAD segments' and we need to tag individual sections. + // HACK: Windows 10 RS2 and above 'added TEB/PEB sub-VAD segments' and we need to tag individual sections. (dmex) PhpSetMemoryRegionType(List, basicInfo.PebBaseAddress, WindowsVersion < WINDOWS_10_RS2 ? TRUE : FALSE, PebRegion); if (NT_SUCCESS(NtReadVirtualMemory(ProcessHandle, @@ -469,7 +469,7 @@ NTSTATUS PhpUpdateMemoryRegionTypes( } } - if (memoryItem->VirtualAttributes.Valid && memoryItem->State & MEM_COMMIT) + if (memoryItem->State & MEM_COMMIT && memoryItem->Valid && !memoryItem->Bad) { UCHAR buffer[HEAP_SEGMENT_MAX_SIZE]; @@ -798,7 +798,10 @@ NTSTATUS PhQueryMemoryItemList( NULL ))) { - memoryItem->VirtualAttributes = info.u1.VirtualAttributes; + PMEMORY_WORKING_SET_EX_BLOCK block = &info.u1.VirtualAttributes; + + memoryItem->Valid = !!block->Valid; + memoryItem->Bad = !!block->Bad; } PhAddElementAvlTree(&List->Set, &memoryItem->Links); From 73edb1560a4c49a2e18a7d9ac691f58c94cbd347 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 6 Jul 2019 20:12:53 +0200 Subject: [PATCH 1969/2058] Add alternate runas method (experimental) --- ProcessHacker/runas.c | 99 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 89 insertions(+), 10 deletions(-) diff --git a/ProcessHacker/runas.c b/ProcessHacker/runas.c index 7b91344a31a7..246a27b9479e 100644 --- a/ProcessHacker/runas.c +++ b/ProcessHacker/runas.c @@ -1199,18 +1199,97 @@ INT_PTR CALLBACK PhpRunAsDlgProc( } else { - status = PhExecuteRunAsCommand3( - hwndDlg, + HANDLE processHandle = NULL; + HANDLE newProcessHandle; + STARTUPINFOEX startupInfo; + SIZE_T attributeListLength = 0; + + memset(&startupInfo, 0, sizeof(STARTUPINFOEX)); + startupInfo.StartupInfo.cb = sizeof(STARTUPINFOEX); + startupInfo.StartupInfo.dwFlags = STARTF_USESHOWWINDOW; + startupInfo.StartupInfo.wShowWindow = SW_SHOWNORMAL; + + status = PhOpenProcess( + &processHandle, + PROCESS_CREATE_PROCESS, + context->ProcessId + ); + + if (!NT_SUCCESS(status)) + goto CleanupExit; + + if (!InitializeProcThreadAttributeList(NULL, 1, 0, &attributeListLength) && GetLastError() != ERROR_INSUFFICIENT_BUFFER) + { + status = PhGetLastWin32ErrorAsNtStatus(); + goto CleanupExit; + } + + startupInfo.lpAttributeList = PhAllocate(attributeListLength); + + if (!InitializeProcThreadAttributeList(startupInfo.lpAttributeList, 1, 0, &attributeListLength)) + { + status = PhGetLastWin32ErrorAsNtStatus(); + goto CleanupExit; + } + + if (!UpdateProcThreadAttribute(startupInfo.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, &processHandle, sizeof(HANDLE), NULL, NULL)) + { + status = PhGetLastWin32ErrorAsNtStatus(); + goto CleanupExit; + } + + status = PhCreateProcessWin32Ex( + NULL, PhGetString(program), - PhGetString(username), - PhGetStringOrEmpty(password), - logonType, - context->ProcessId, - sessionId, - PhGetString(desktopName), - useLinkedToken, - createSuspended + NULL, + NULL, + &startupInfo.StartupInfo, + PH_CREATE_PROCESS_SUSPENDED | PH_CREATE_PROCESS_NEW_CONSOLE | PH_CREATE_PROCESS_EXTENDED_STARTUPINFO, + NULL, + NULL, + &newProcessHandle, + NULL ); + + if (NT_SUCCESS(status)) + { + PROCESS_BASIC_INFORMATION basicInfo; + + if (NT_SUCCESS(PhGetProcessBasicInformation(newProcessHandle, &basicInfo))) + { + AllowSetForegroundWindow(HandleToUlong(basicInfo.UniqueProcessId)); + } + + NtResumeProcess(newProcessHandle); + NtClose(newProcessHandle); + } + + CleanupExit: + + if (startupInfo.lpAttributeList) + { + DeleteProcThreadAttributeList(startupInfo.lpAttributeList); + PhFree(startupInfo.lpAttributeList); + } + + if (processHandle) + { + NtClose(processHandle); + } + + // TODO: Commented out while testing above method (dmex) + //status = PhExecuteRunAsCommand3( + // hwndDlg, + // PhGetString(program), + // PhGetString(username), + // PhGetStringOrEmpty(password), + // logonType, + // context->ProcessId, + // sessionId, + // PhGetString(desktopName), + // useLinkedToken, + // createSuspended + // ); } } else From 16687609cfa1ce6e17ff76c00073395976d3aee9 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 6 Jul 2019 20:20:57 +0200 Subject: [PATCH 1970/2058] Add alternate rundlg method (experimental) --- ProcessHacker/mainwnd.c | 256 ++++++++++++++++++++++++++++------------ 1 file changed, 182 insertions(+), 74 deletions(-) diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index 7b29dd11de9f..c4e8766098e0 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -1840,99 +1840,207 @@ BOOLEAN PhMwpOnNotify( else if (Header->code == RFN_LIMITEDRUNAS) { LPNMRUNFILEDLG runFileDlg = (LPNMRUNFILEDLG)Header; - PVOID WdcLibraryHandle; - ULONG (WINAPI* WdcRunTaskAsInteractiveUser_I)( - _In_ PCWSTR CommandLine, - _In_ PCWSTR CurrentDirectory, - _In_ ULONG Reserved - ); + NTSTATUS status; + ULONG processId = ULONG_MAX; + HANDLE processHandle = NULL; + HANDLE newProcessHandle; + HWND shellWindow; + STARTUPINFOEX startupInfo; + SIZE_T attributeListLength; - // dmex: Task Manager uses RFF_OPTRUNAS and RFN_LIMITEDRUNAS to show the 'Create this task with administrative privileges' checkbox - // on the RunFileDlg when the current process is elevated. Task Manager also uses the WdcRunTaskAsInteractiveUser function to launch processes - // as the interactive user from an elevated token. The WdcRunTaskAsInteractiveUser function - // invokes the "\Microsoft\Windows\Task Manager\Interactive" Task Scheduler task for launching the process but - // doesn't return error information and we need to perform some sanity checks before invoking the task. - // Ideally, we should use our own task but for now just re-use the existing task and do what Task Manager does... + memset(&startupInfo, 0, sizeof(STARTUPINFOEX)); + startupInfo.StartupInfo.cb = sizeof(STARTUPINFOEX); + startupInfo.StartupInfo.dwFlags = STARTF_USESHOWWINDOW; + startupInfo.StartupInfo.wShowWindow = SW_SHOWNORMAL; - if (WdcLibraryHandle = LoadLibrary(L"wdc.dll")) + if (!(shellWindow = GetShellWindow())) { - if (WdcRunTaskAsInteractiveUser_I = PhGetDllBaseProcedureAddress(WdcLibraryHandle, "WdcRunTaskAsInteractiveUser", 0)) - { - PH_STRINGREF string; - PPH_STRING commandlineString; - PPH_STRING executeString = NULL; - INT cmdlineArgCount; - PWSTR* cmdlineArgList; + status = STATUS_UNSUCCESSFUL; + goto CleanupExit; + } - PhInitializeStringRefLongHint(&string, (PWSTR)runFileDlg->lpszFile); - commandlineString = PhCreateString2(&string); + GetWindowThreadProcessId(shellWindow, &processId); - // Extract the filename. - if (cmdlineArgList = CommandLineToArgvW(commandlineString->Buffer, &cmdlineArgCount)) - { - PPH_STRING fileName = PhCreateString(cmdlineArgList[0]); + if (processId == ULONG_MAX) + { + status = STATUS_UNSUCCESSFUL; + goto CleanupExit; + } - if (fileName && !RtlDoesFileExists_U(fileName->Buffer)) - { - PPH_STRING filePathString; + status = PhOpenProcess( + &processHandle, + PROCESS_CREATE_PROCESS, + UlongToHandle(processId) + ); - // The user typed a name without a path so attempt to locate the executable. - if (filePathString = PhSearchFilePath(fileName->Buffer, L".exe")) - PhMoveReference(&fileName, filePathString); - else - PhClearReference(&fileName); - } + if (!NT_SUCCESS(status)) + goto CleanupExit; - if (fileName) - { - // Escape the filename. - PhMoveReference(&fileName, PhConcatStrings(3, L"\"", fileName->Buffer, L"\"")); + if (!InitializeProcThreadAttributeList(NULL, 1, 0, &attributeListLength) && GetLastError() != ERROR_INSUFFICIENT_BUFFER) + { + status = PhGetLastWin32ErrorAsNtStatus(); + goto CleanupExit; + } - if (cmdlineArgCount == 2) - { - PPH_STRING fileArgs = PhCreateString(cmdlineArgList[1]); + startupInfo.lpAttributeList = PhAllocate(attributeListLength); - // Escape the parameters. - PhMoveReference(&fileArgs, PhConcatStrings(3, L"\"", fileArgs->Buffer, L"\"")); + if (!InitializeProcThreadAttributeList(startupInfo.lpAttributeList, 1, 0, &attributeListLength)) + { + status = PhGetLastWin32ErrorAsNtStatus(); + goto CleanupExit; + } - // Create the escaped execute string. - PhMoveReference(&executeString, PhConcatStrings(3, fileName->Buffer, L" ", fileArgs->Buffer)); + if (!UpdateProcThreadAttribute(startupInfo.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, &(HANDLE){ processHandle }, sizeof(HANDLE), NULL, NULL)) + { + status = PhGetLastWin32ErrorAsNtStatus(); + goto CleanupExit; + } - // Cleanup. - PhDereferenceObject(fileArgs); - } - else - { - // Create the escaped execute string. - executeString = PhReferenceObject(fileName); - } + status = PhCreateProcessWin32Ex( + NULL, + runFileDlg->lpszFile, + NULL, + NULL, + &startupInfo.StartupInfo, + PH_CREATE_PROCESS_SUSPENDED | PH_CREATE_PROCESS_NEW_CONSOLE | PH_CREATE_PROCESS_EXTENDED_STARTUPINFO, + NULL, + NULL, + &newProcessHandle, + NULL + ); - PhDereferenceObject(fileName); - } + if (NT_SUCCESS(status)) + { + PROCESS_BASIC_INFORMATION basicInfo; - LocalFree(cmdlineArgList); - } + if (NT_SUCCESS(PhGetProcessBasicInformation(newProcessHandle, &basicInfo))) + { + AllowSetForegroundWindow(HandleToUlong(basicInfo.UniqueProcessId)); + } - if (!PhIsNullOrEmptyString(executeString)) - { - if (WdcRunTaskAsInteractiveUser_I(executeString->Buffer, NULL, 0) == 0) - *Result = RF_CANCEL; - else - *Result = RF_RETRY; - } - else - { - *Result = RF_RETRY; - } + NtResumeProcess(newProcessHandle); - if (executeString) - PhDereferenceObject(executeString); - PhDereferenceObject(commandlineString); - } + NtClose(newProcessHandle); + } + + CleanupExit: + + if (startupInfo.lpAttributeList) + { + DeleteProcThreadAttributeList(startupInfo.lpAttributeList); + PhFree(startupInfo.lpAttributeList); + } - FreeLibrary(WdcLibraryHandle); + if (processHandle) + { + NtClose(processHandle); } + + if (NT_SUCCESS(status)) + { + *Result = RF_CANCEL; + } + else + { + *Result = RF_RETRY; + } + return TRUE; + + // TODO: Commented out while testing above code (dmex) + //PVOID WdcLibraryHandle; + //ULONG (WINAPI* WdcRunTaskAsInteractiveUser_I)( + // _In_ PCWSTR CommandLine, + // _In_ PCWSTR CurrentDirectory, + // _In_ ULONG Reserved + // ); + + // dmex: Task Manager uses RFF_OPTRUNAS and RFN_LIMITEDRUNAS to show the 'Create this task with administrative privileges' checkbox + // on the RunFileDlg when the current process is elevated. Task Manager also uses the WdcRunTaskAsInteractiveUser function to launch processes + // as the interactive user from an elevated token. The WdcRunTaskAsInteractiveUser function + // invokes the "\Microsoft\Windows\Task Manager\Interactive" Task Scheduler task for launching the process but + // doesn't return error information and we need to perform some sanity checks before invoking the task. + // Ideally, we should use our own task but for now just re-use the existing task and do what Task Manager does... + + //if (WdcLibraryHandle = LoadLibrary(L"wdc.dll")) + //{ + // if (WdcRunTaskAsInteractiveUser_I = PhGetDllBaseProcedureAddress(WdcLibraryHandle, "WdcRunTaskAsInteractiveUser", 0)) + // { + // PH_STRINGREF string; + // PPH_STRING commandlineString; + // PPH_STRING executeString = NULL; + // INT cmdlineArgCount; + // PWSTR* cmdlineArgList; + // + // PhInitializeStringRefLongHint(&string, (PWSTR)runFileDlg->lpszFile); + // commandlineString = PhCreateString2(&string); + // + // // Extract the filename. + // if (cmdlineArgList = CommandLineToArgvW(commandlineString->Buffer, &cmdlineArgCount)) + // { + // PPH_STRING fileName = PhCreateString(cmdlineArgList[0]); + // + // if (fileName && !RtlDoesFileExists_U(fileName->Buffer)) + // { + // PPH_STRING filePathString; + // + // // The user typed a name without a path so attempt to locate the executable. + // if (filePathString = PhSearchFilePath(fileName->Buffer, L".exe")) + // PhMoveReference(&fileName, filePathString); + // else + // PhClearReference(&fileName); + // } + // + // if (fileName) + // { + // // Escape the filename. + // PhMoveReference(&fileName, PhConcatStrings(3, L"\"", fileName->Buffer, L"\"")); + // + // if (cmdlineArgCount == 2) + // { + // PPH_STRING fileArgs = PhCreateString(cmdlineArgList[1]); + // + // // Escape the parameters. + // PhMoveReference(&fileArgs, PhConcatStrings(3, L"\"", fileArgs->Buffer, L"\"")); + // + // // Create the escaped execute string. + // PhMoveReference(&executeString, PhConcatStrings(3, fileName->Buffer, L" ", fileArgs->Buffer)); + // + // // Cleanup. + // PhDereferenceObject(fileArgs); + // } + // else + // { + // // Create the escaped execute string. + // executeString = PhReferenceObject(fileName); + // } + // + // PhDereferenceObject(fileName); + // } + // + // LocalFree(cmdlineArgList); + // } + // + // if (!PhIsNullOrEmptyString(executeString)) + // { + // if (WdcRunTaskAsInteractiveUser_I(executeString->Buffer, NULL, 0) == 0) + // *Result = RF_CANCEL; + // else + // *Result = RF_RETRY; + // } + // else + // { + // *Result = RF_RETRY; + // } + // + // if (executeString) + // PhDereferenceObject(executeString); + // PhDereferenceObject(commandlineString); + // } + // + // FreeLibrary(WdcLibraryHandle); + //} + //return TRUE; } return FALSE; From f4f490c00bf48d605ab697c1bb77f61a3c2e1e58 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 6 Jul 2019 20:22:42 +0200 Subject: [PATCH 1971/2058] Enable processes menu for System process --- ProcessHacker/mwpgproc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ProcessHacker/mwpgproc.c b/ProcessHacker/mwpgproc.c index 754ad713cb15..cd6f2e69b55b 100644 --- a/ProcessHacker/mwpgproc.c +++ b/ProcessHacker/mwpgproc.c @@ -3,7 +3,7 @@ * Main window: Processes tab * * Copyright (C) 2009-2016 wj32 - * Copyright (C) 2017-2018 dmex + * Copyright (C) 2017-2019 dmex * * This file is part of Process Hacker. * @@ -537,8 +537,8 @@ VOID PhMwpInitializeProcessMenu( // If the user selected a fake process, disable all but a few menu items. if ( PH_IS_FAKE_PROCESS_ID(Processes[0]->ProcessId) || - Processes[0]->ProcessId == SYSTEM_IDLE_PROCESS_ID || - Processes[0]->ProcessId == SYSTEM_PROCESS_ID // TODO: Some menu entires could be enabled for the system process? + Processes[0]->ProcessId == SYSTEM_IDLE_PROCESS_ID + //Processes[0]->ProcessId == SYSTEM_PROCESS_ID // (dmex) ) { PhSetFlagsAllEMenuItems(Menu, PH_EMENU_DISABLED, PH_EMENU_DISABLED); From 2e795625e50068b5f2c84f057876a1fe1e7ca7bc Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 6 Jul 2019 20:34:38 +0200 Subject: [PATCH 1972/2058] Fix runas regression from commit 73edb156 --- ProcessHacker/runas.c | 152 ++++++++++++++++++++++-------------------- 1 file changed, 78 insertions(+), 74 deletions(-) diff --git a/ProcessHacker/runas.c b/ProcessHacker/runas.c index 246a27b9479e..29e1bdbbc236 100644 --- a/ProcessHacker/runas.c +++ b/ProcessHacker/runas.c @@ -1199,97 +1199,101 @@ INT_PTR CALLBACK PhpRunAsDlgProc( } else { - HANDLE processHandle = NULL; - HANDLE newProcessHandle; - STARTUPINFOEX startupInfo; - SIZE_T attributeListLength = 0; - - memset(&startupInfo, 0, sizeof(STARTUPINFOEX)); - startupInfo.StartupInfo.cb = sizeof(STARTUPINFOEX); - startupInfo.StartupInfo.dwFlags = STARTF_USESHOWWINDOW; - startupInfo.StartupInfo.wShowWindow = SW_SHOWNORMAL; - - status = PhOpenProcess( - &processHandle, - PROCESS_CREATE_PROCESS, - context->ProcessId + if (context->ProcessId) + { + HANDLE processHandle = NULL; + HANDLE newProcessHandle; + STARTUPINFOEX startupInfo; + SIZE_T attributeListLength = 0; + + memset(&startupInfo, 0, sizeof(STARTUPINFOEX)); + startupInfo.StartupInfo.cb = sizeof(STARTUPINFOEX); + startupInfo.StartupInfo.dwFlags = STARTF_USESHOWWINDOW; + startupInfo.StartupInfo.wShowWindow = SW_SHOWNORMAL; + + status = PhOpenProcess( + &processHandle, + PROCESS_CREATE_PROCESS, + context->ProcessId ); - if (!NT_SUCCESS(status)) - goto CleanupExit; + if (!NT_SUCCESS(status)) + goto CleanupExit; - if (!InitializeProcThreadAttributeList(NULL, 1, 0, &attributeListLength) && GetLastError() != ERROR_INSUFFICIENT_BUFFER) - { - status = PhGetLastWin32ErrorAsNtStatus(); - goto CleanupExit; - } + if (!InitializeProcThreadAttributeList(NULL, 1, 0, &attributeListLength) && GetLastError() != ERROR_INSUFFICIENT_BUFFER) + { + status = PhGetLastWin32ErrorAsNtStatus(); + goto CleanupExit; + } - startupInfo.lpAttributeList = PhAllocate(attributeListLength); + startupInfo.lpAttributeList = PhAllocate(attributeListLength); - if (!InitializeProcThreadAttributeList(startupInfo.lpAttributeList, 1, 0, &attributeListLength)) - { - status = PhGetLastWin32ErrorAsNtStatus(); - goto CleanupExit; - } + if (!InitializeProcThreadAttributeList(startupInfo.lpAttributeList, 1, 0, &attributeListLength)) + { + status = PhGetLastWin32ErrorAsNtStatus(); + goto CleanupExit; + } - if (!UpdateProcThreadAttribute(startupInfo.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, &processHandle, sizeof(HANDLE), NULL, NULL)) - { - status = PhGetLastWin32ErrorAsNtStatus(); - goto CleanupExit; - } + if (!UpdateProcThreadAttribute(startupInfo.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, &processHandle, sizeof(HANDLE), NULL, NULL)) + { + status = PhGetLastWin32ErrorAsNtStatus(); + goto CleanupExit; + } - status = PhCreateProcessWin32Ex( - NULL, - PhGetString(program), - NULL, - NULL, - &startupInfo.StartupInfo, - PH_CREATE_PROCESS_SUSPENDED | PH_CREATE_PROCESS_NEW_CONSOLE | PH_CREATE_PROCESS_EXTENDED_STARTUPINFO, - NULL, - NULL, - &newProcessHandle, - NULL + status = PhCreateProcessWin32Ex( + NULL, + PhGetString(program), + NULL, + NULL, + &startupInfo.StartupInfo, + PH_CREATE_PROCESS_SUSPENDED | PH_CREATE_PROCESS_NEW_CONSOLE | PH_CREATE_PROCESS_EXTENDED_STARTUPINFO, + NULL, + NULL, + &newProcessHandle, + NULL ); - if (NT_SUCCESS(status)) - { - PROCESS_BASIC_INFORMATION basicInfo; - - if (NT_SUCCESS(PhGetProcessBasicInformation(newProcessHandle, &basicInfo))) + if (NT_SUCCESS(status)) { - AllowSetForegroundWindow(HandleToUlong(basicInfo.UniqueProcessId)); + PROCESS_BASIC_INFORMATION basicInfo; + + if (NT_SUCCESS(PhGetProcessBasicInformation(newProcessHandle, &basicInfo))) + { + AllowSetForegroundWindow(HandleToUlong(basicInfo.UniqueProcessId)); + } + + NtResumeProcess(newProcessHandle); + NtClose(newProcessHandle); } - NtResumeProcess(newProcessHandle); - NtClose(newProcessHandle); - } + CleanupExit: - CleanupExit: + if (startupInfo.lpAttributeList) + { + DeleteProcThreadAttributeList(startupInfo.lpAttributeList); + PhFree(startupInfo.lpAttributeList); + } - if (startupInfo.lpAttributeList) - { - DeleteProcThreadAttributeList(startupInfo.lpAttributeList); - PhFree(startupInfo.lpAttributeList); + if (processHandle) + { + NtClose(processHandle); + } } - - if (processHandle) + else { - NtClose(processHandle); + status = PhExecuteRunAsCommand3( + hwndDlg, + PhGetString(program), + PhGetString(username), + PhGetStringOrEmpty(password), + logonType, + context->ProcessId, + sessionId, + PhGetString(desktopName), + useLinkedToken, + createSuspended + ); } - - // TODO: Commented out while testing above method (dmex) - //status = PhExecuteRunAsCommand3( - // hwndDlg, - // PhGetString(program), - // PhGetString(username), - // PhGetStringOrEmpty(password), - // logonType, - // context->ProcessId, - // sessionId, - // PhGetString(desktopName), - // useLinkedToken, - // createSuspended - // ); } } else From 843a637f8b960a8cb36a80c4d11ecb05ff2a620b Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 6 Jul 2019 20:45:55 +0200 Subject: [PATCH 1973/2058] Fix default CreateProcess parent directory path --- phlib/util.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/phlib/util.c b/phlib/util.c index dda96e6be41f..38f71028cb23 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -2725,11 +2725,12 @@ NTSTATUS PhCreateProcessWin32Ex( NTSTATUS status; PPH_STRING fileName = NULL; PPH_STRING commandLine = NULL; + PPH_STRING currentDirectory = NULL; STARTUPINFO startupInfo; PROCESS_INFORMATION processInfo; ULONG newFlags; - if (CommandLine) // duplicate because CreateProcess modifies the string + if (CommandLine) // duplicate because CreateProcess modifies the string (wj32) commandLine = PhCreateString(CommandLine); if (FileName) @@ -2739,7 +2740,7 @@ NTSTATUS PhCreateProcessWin32Ex( INT cmdlineArgCount; PWSTR* cmdlineArgList; - // (dmex) Try extract the filename or CreateProcess might execute the wrong executable. + // Try extract the filename or CreateProcess might execute the wrong executable. (dmex) if (commandLine && (cmdlineArgList = CommandLineToArgvW(commandLine->Buffer, &cmdlineArgCount))) { PhMoveReference(&fileName, PhCreateString(cmdlineArgList[0])); @@ -2750,7 +2751,7 @@ NTSTATUS PhCreateProcessWin32Ex( { PPH_STRING filePathSr; - // The user typed a name without a path so attempt to locate the executable. + // The user typed a name without a path so attempt to locate the executable. (dmex) if (filePathSr = PhSearchFilePath(fileName->Buffer, L".exe")) PhMoveReference(&fileName, filePathSr); else @@ -2758,6 +2759,16 @@ NTSTATUS PhCreateProcessWin32Ex( } } + // Set the current directory to the same location as the target executable + // or CreateProcess uses our current directory. (dmex) + if (CurrentDirectory) + currentDirectory = PhCreateString(CurrentDirectory); + else + { + if (!PhIsNullOrEmptyString(fileName)) + currentDirectory = PhGetBaseDirectory(fileName); + } + newFlags = 0; PhMapFlags1(&newFlags, Flags, PhpCreateProcessMappings, sizeof(PhpCreateProcessMappings) / sizeof(PH_FLAG_MAPPING)); @@ -2778,7 +2789,7 @@ NTSTATUS PhCreateProcessWin32Ex( !!(Flags & PH_CREATE_PROCESS_INHERIT_HANDLES), newFlags, Environment, - CurrentDirectory, + PhGetString(currentDirectory), StartupInfo ? StartupInfo : &startupInfo, &processInfo )) @@ -2796,7 +2807,7 @@ NTSTATUS PhCreateProcessWin32Ex( !!(Flags & PH_CREATE_PROCESS_INHERIT_HANDLES), newFlags, Environment, - CurrentDirectory, + PhGetString(currentDirectory), StartupInfo ? StartupInfo : &startupInfo, &processInfo )) @@ -2809,6 +2820,8 @@ NTSTATUS PhCreateProcessWin32Ex( PhDereferenceObject(fileName); if (commandLine) PhDereferenceObject(commandLine); + if (currentDirectory) + PhDereferenceObject(currentDirectory); if (NT_SUCCESS(status)) { From 37202dbf90af7885b14d233d68968f143cd4d44a Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 8 Jul 2019 23:30:05 +0200 Subject: [PATCH 1974/2058] Update runas dialog with ctrl/shift support, Remove deprecated limited runas menu --- ProcessHacker/ProcessHacker.rc | 1 - ProcessHacker/mainwnd.c | 112 +++++++++++++++++++-------------- phlib/settings.c | 4 +- 3 files changed, 66 insertions(+), 51 deletions(-) diff --git a/ProcessHacker/ProcessHacker.rc b/ProcessHacker/ProcessHacker.rc index cbf282a04982..c228dc149c9a 100644 --- a/ProcessHacker/ProcessHacker.rc +++ b/ProcessHacker/ProcessHacker.rc @@ -78,7 +78,6 @@ BEGIN BEGIN MENUITEM "&Run...\aCtrl+R", ID_HACKER_RUN MENUITEM "Run as ad&ministrator...", ID_HACKER_RUNASADMINISTRATOR - MENUITEM "Run as &limited user...", ID_HACKER_RUNASLIMITEDUSER MENUITEM "Run &as...\aCtrl+Shift+R", ID_HACKER_RUNAS MENUITEM "Show &details for all processes", ID_HACKER_SHOWDETAILSFORALLPROCESSES MENUITEM SEPARATOR diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index c4e8766098e0..f8ff5025a5a0 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -636,6 +636,19 @@ VOID PhMwpOnCommand( ); } break; + //case ID_HACKER_RUNASLIMITEDUSER: + // { + // SelectedRunAsMode = RUNAS_MODE_LIMITED; + // PhShowRunFileDialog( + // PhMainWndHandle, + // NULL, + // NULL, + // NULL, + // L"Type the name of a program that will be opened under standard user privileges.", + // 0 + // ); + // } + // break; case ID_HACKER_RUNAS: { PhShowRunAsDialog(PhMainWndHandle, NULL); @@ -1751,7 +1764,10 @@ BOOLEAN PhMwpOnNotify( { LPNMRUNFILEDLG runFileDlg = (LPNMRUNFILEDLG)Header; - if (SelectedRunAsMode == RUNAS_MODE_ADMIN) + if (SelectedRunAsMode == RUNAS_MODE_ADMIN || + // The explorer runas dialog executes programs as administrator when holding ctrl/shift keys + // and clicking the OK button, so we'll implement the same functionality. (dmex) + (!!(GetKeyState(VK_CONTROL) < 0 && !!(GetKeyState(VK_SHIFT) < 0)))) { PH_STRINGREF string; PH_STRINGREF fileName; @@ -1789,53 +1805,53 @@ BOOLEAN PhMwpOnNotify( return TRUE; } - else if (SelectedRunAsMode == RUNAS_MODE_LIMITED) - { - NTSTATUS status; - HANDLE tokenHandle; - HANDLE newTokenHandle; - - if (NT_SUCCESS(status = PhOpenProcessToken( - NtCurrentProcess(), - TOKEN_ASSIGN_PRIMARY | TOKEN_DUPLICATE | TOKEN_QUERY | TOKEN_ADJUST_GROUPS | - TOKEN_ADJUST_DEFAULT | READ_CONTROL | WRITE_DAC, - &tokenHandle - ))) - { - if (NT_SUCCESS(status = PhFilterTokenForLimitedUser( - tokenHandle, - &newTokenHandle - ))) - { - status = PhCreateProcessWin32( - NULL, - runFileDlg->lpszFile, - NULL, - NULL, - 0, - newTokenHandle, - NULL, - NULL - ); - - NtClose(newTokenHandle); - } - - NtClose(tokenHandle); - } - - if (NT_SUCCESS(status)) - { - *Result = RF_CANCEL; - } - else - { - PhShowStatus(PhMainWndHandle, L"Unable to execute the program.", status, 0); - *Result = RF_RETRY; - } - - return TRUE; - } + //else if (SelectedRunAsMode == RUNAS_MODE_LIMITED) + //{ + // NTSTATUS status; + // HANDLE tokenHandle; + // HANDLE newTokenHandle; + // + // if (NT_SUCCESS(status = PhOpenProcessToken( + // NtCurrentProcess(), + // TOKEN_ASSIGN_PRIMARY | TOKEN_DUPLICATE | TOKEN_QUERY | TOKEN_ADJUST_GROUPS | + // TOKEN_ADJUST_DEFAULT | READ_CONTROL | WRITE_DAC, + // &tokenHandle + // ))) + // { + // if (NT_SUCCESS(status = PhFilterTokenForLimitedUser( + // tokenHandle, + // &newTokenHandle + // ))) + // { + // status = PhCreateProcessWin32( + // NULL, + // runFileDlg->lpszFile, + // NULL, + // NULL, + // 0, + // newTokenHandle, + // NULL, + // NULL + // ); + // + // NtClose(newTokenHandle); + // } + // + // NtClose(tokenHandle); + // } + // + // if (NT_SUCCESS(status)) + // { + // *Result = RF_CANCEL; + // } + // else + // { + // PhShowStatus(PhMainWndHandle, L"Unable to execute the program.", status, 0); + // *Result = RF_RETRY; + // } + // + // return TRUE; + //} } else if (Header->code == RFN_LIMITEDRUNAS) { diff --git a/phlib/settings.c b/phlib/settings.c index 8fd38b5b967d..dd0899a45a78 100644 --- a/phlib/settings.c +++ b/phlib/settings.c @@ -859,7 +859,7 @@ NTSTATUS PhLoadSettings( return STATUS_SUCCESS; } -char *PhpSettingsSaveCallback( +PSTR PhpSettingsSaveCallback( _In_ mxml_node_t *node, _In_ int position ) @@ -967,7 +967,7 @@ NTSTATUS PhSaveSettings( if (indexOfFileName != -1) { directoryName = PhSubstring(fullPath, 0, indexOfFileName); - //PhCreateDirectory(directoryName); + PhCreateDirectory(directoryName); PhDereferenceObject(directoryName); } From a9b86753390eb1af00d509f55c6e6a8aa9a24a6b Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 8 Jul 2019 23:30:35 +0200 Subject: [PATCH 1975/2058] Fix previous commit --- ProcessHacker/mainwnd.c | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index f8ff5025a5a0..da37c77b39e8 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -618,20 +618,7 @@ VOID PhMwpOnCommand( NULL, NULL, NULL, - L"Type the name of a program that will be opened under alternate credentials.", - 0 - ); - } - break; - case ID_HACKER_RUNASLIMITEDUSER: - { - SelectedRunAsMode = RUNAS_MODE_LIMITED; - PhShowRunFileDialog( - PhMainWndHandle, - NULL, - NULL, - NULL, - L"Type the name of a program that will be opened under standard user privileges.", + L"Type the name of a program that will be opened with administrative credentials.", 0 ); } From 6cf32d9e4555f3e3900e6b5aeafac764d86a620a Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 8 Jul 2019 23:30:56 +0200 Subject: [PATCH 1976/2058] Fix tabspace --- ProcessHacker/runas.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ProcessHacker/runas.c b/ProcessHacker/runas.c index 29e1bdbbc236..ff1954e011a8 100644 --- a/ProcessHacker/runas.c +++ b/ProcessHacker/runas.c @@ -1215,7 +1215,7 @@ INT_PTR CALLBACK PhpRunAsDlgProc( &processHandle, PROCESS_CREATE_PROCESS, context->ProcessId - ); + ); if (!NT_SUCCESS(status)) goto CleanupExit; From ad12dbb1f1159fe75c67431efd1eb51d3c070007 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 9 Jul 2019 12:22:29 +0200 Subject: [PATCH 1977/2058] Fix #435 --- plugins/ToolStatus/graph.c | 8 +++++++- plugins/ToolStatus/main.c | 34 ++++++++++++++++++++-------------- plugins/ToolStatus/options.c | 1 + plugins/ToolStatus/toolbar.c | 28 +++++++++++++++++----------- 4 files changed, 45 insertions(+), 26 deletions(-) diff --git a/plugins/ToolStatus/graph.c b/plugins/ToolStatus/graph.c index 764ac932d8fa..eae8a7df2f63 100644 --- a/plugins/ToolStatus/graph.c +++ b/plugins/ToolStatus/graph.c @@ -197,7 +197,7 @@ BOOLEAN ToolbarAddGraph( _In_ PPH_TOOLBAR_GRAPH Graph ) { - if (!Graph->GraphHandle) + if (!Graph->GraphHandle && RebarHandle && ToolStatusConfig.ToolBarEnabled) { UINT rebarHeight = (UINT)SendMessage(RebarHandle, RB_GETROWHEIGHT, 0, 0); @@ -272,6 +272,9 @@ VOID ToolbarUpdateGraphs( VOID ) { + if (!ToolStatusConfig.ToolBarEnabled) + return; + for (ULONG i = 0; i < PhpToolbarGraphList->Count; i++) { PPH_TOOLBAR_GRAPH graph = PhpToolbarGraphList->Items[i]; @@ -279,6 +282,9 @@ VOID ToolbarUpdateGraphs( if (!(graph->Flags & TOOLSTATUS_GRAPH_ENABLED)) continue; + if (!graph->GraphHandle) + continue; + graph->GraphState.Valid = FALSE; graph->GraphState.TooltipIndex = ULONG_MAX; Graph_MoveGrid(graph->GraphHandle, 1); diff --git a/plugins/ToolStatus/main.c b/plugins/ToolStatus/main.c index 17fde410bc10..405b064647bc 100644 --- a/plugins/ToolStatus/main.c +++ b/plugins/ToolStatus/main.c @@ -107,7 +107,7 @@ VOID NTAPI ProcessesUpdatedCallback( PhPluginGetSystemStatistics(&SystemStatistics); - if (UpdateGraphs) + if (ToolStatusConfig.ToolBarEnabled && ToolBarHandle && UpdateGraphs) ToolbarUpdateGraphs(); if (ToolStatusConfig.StatusBarEnabled) @@ -910,7 +910,7 @@ LRESULT CALLBACK MainWndSubclassProc( { if (ToolbarButtons[i].idCommand == toolbarDisplayInfo->idCommand) { - if (ToolbarButtons[i].iBitmap != I_IMAGECALLBACK) + if (ToolbarButtons[i].iBitmap == I_IMAGECALLBACK) { found = TRUE; @@ -933,18 +933,20 @@ LRESULT CALLBACK MainWndSubclassProc( { HBITMAP buttonImage; - buttonImage = ToolbarGetImage(toolbarDisplayInfo->idCommand); + if (buttonImage = ToolbarGetImage(toolbarDisplayInfo->idCommand)) + { + // Cache the bitmap index. + toolbarDisplayInfo->dwMask |= TBNF_DI_SETITEM; - // Cache the bitmap index. - toolbarDisplayInfo->dwMask |= TBNF_DI_SETITEM; - // Add the image, cache the value in the ToolbarButtons array, set the bitmap index. - toolbarDisplayInfo->iImage = ToolbarButtons[i].iBitmap = ImageList_Add( - ToolBarImageList, - buttonImage, - NULL - ); - - DeleteObject(buttonImage); + // Add the image, cache the value in the ToolbarButtons array, set the bitmap index. + toolbarDisplayInfo->iImage = ToolbarButtons[i].iBitmap = ImageList_Add( + ToolBarImageList, + buttonImage, + NULL + ); + + DeleteObject(buttonImage); + } break; } } @@ -1057,7 +1059,11 @@ LRESULT CALLBACK MainWndSubclassProc( } else { - if (ToolbarUpdateGraphsInfo(hdr)) + if ( + ToolStatusConfig.ToolBarEnabled && + ToolBarHandle && + ToolbarUpdateGraphsInfo(hdr) + ) { goto DefaultWndProc; } diff --git a/plugins/ToolStatus/options.c b/plugins/ToolStatus/options.c index 1ab5ac891182..d2b0ca3129a0 100644 --- a/plugins/ToolStatus/options.c +++ b/plugins/ToolStatus/options.c @@ -54,6 +54,7 @@ INT_PTR CALLBACK OptionsDlgProc( PhSetIntegerSetting(SETTING_NAME_TOOLSTATUS_CONFIG, ToolStatusConfig.Flags); ToolbarLoadSettings(); + ToolbarCreateGraphs(); if (ToolStatusConfig.AutoHideMenu) { diff --git a/plugins/ToolStatus/toolbar.c b/plugins/ToolStatus/toolbar.c index a07ac0e1df47..3f8e9560058f 100644 --- a/plugins/ToolStatus/toolbar.c +++ b/plugins/ToolStatus/toolbar.c @@ -155,10 +155,12 @@ VOID RebarLoadSettings( SendMessage(ToolBarHandle, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0); // Set the toolbar extended toolbar styles. SendMessage(ToolBarHandle, TB_SETEXTENDEDSTYLE, 0, TBSTYLE_EX_DOUBLEBUFFER | TBSTYLE_EX_MIXEDBUTTONS | TBSTYLE_EX_HIDECLIPPEDBUTTONS); - // Configure the toolbar imagelist. - SendMessage(ToolBarHandle, TB_SETIMAGELIST, 0, (LPARAM)ToolBarImageList); + // Add the buttons to the toolbar. ToolbarLoadButtonSettings(); + // Configure the toolbar imagelist. + SendMessage(ToolBarHandle, TB_SETIMAGELIST, 0, (LPARAM)ToolBarImageList); + // Configure the toolbar font. SendMessage(ToolBarHandle, WM_SETFONT, (WPARAM)ToolStatusWindowFont, FALSE); // Resize the toolbar. SendMessage(ToolBarHandle, TB_AUTOSIZE, 0, 0); @@ -692,16 +694,20 @@ VOID ToolbarLoadButtonSettings( { HBITMAP bitmap; - bitmap = ToolbarGetImage(ToolbarButtons[i].idCommand); - - // Add the image, cache the value in the ToolbarButtons array, set the bitmap index. - buttonArray[index].iBitmap = ToolbarButtons[i].iBitmap = ImageList_Add( - ToolBarImageList, - bitmap, - NULL - ); + if (buttonArray[index].fsStyle & BTNS_SEP) + continue; - DeleteObject(bitmap); + if (bitmap = ToolbarGetImage(ToolbarButtons[i].idCommand)) + { + // Add the image, cache the value in the ToolbarButtons array, set the bitmap index. + buttonArray[index].iBitmap = ToolbarButtons[i].iBitmap = ImageList_Add( + ToolBarImageList, + bitmap, + NULL + ); + + DeleteObject(bitmap); + } break; } } From 6f8cc93a3dd232a6ecd007fa4332d43eba2f1a8a Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 9 Jul 2019 12:28:57 +0200 Subject: [PATCH 1978/2058] ToolStatus: Improve toolbar image caching --- plugins/ToolStatus/main.c | 17 +++++------------ plugins/ToolStatus/toolbar.c | 2 +- 2 files changed, 6 insertions(+), 13 deletions(-) diff --git a/plugins/ToolStatus/main.c b/plugins/ToolStatus/main.c index 405b064647bc..31662d2102bf 100644 --- a/plugins/ToolStatus/main.c +++ b/plugins/ToolStatus/main.c @@ -900,8 +900,6 @@ LRESULT CALLBACK MainWndSubclassProc( if (toolbarDisplayInfo->dwMask & TBNF_IMAGE) { - BOOLEAN found = FALSE; - // Try to find the cached bitmap index. // NOTE: The TBNF_DI_SETITEM flag below will cache the index so we only get called once. // However, when adding buttons from the customize dialog we get called a second time, @@ -910,20 +908,15 @@ LRESULT CALLBACK MainWndSubclassProc( { if (ToolbarButtons[i].idCommand == toolbarDisplayInfo->idCommand) { - if (ToolbarButtons[i].iBitmap == I_IMAGECALLBACK) - { - found = TRUE; - - // Cache the bitmap index. - toolbarDisplayInfo->dwMask |= TBNF_DI_SETITEM; - // Set the bitmap index. - toolbarDisplayInfo->iImage = ToolbarButtons[i].iBitmap; - } + // Cache the bitmap index. + toolbarDisplayInfo->dwMask |= TBNF_DI_SETITEM; + // Set the bitmap index. + toolbarDisplayInfo->iImage = ToolbarButtons[i].iBitmap; break; } } - if (!found) + if (toolbarDisplayInfo->iImage == I_IMAGECALLBACK) { // We didn't find a cached bitmap index... // Load the button bitmap and cache the index. diff --git a/plugins/ToolStatus/toolbar.c b/plugins/ToolStatus/toolbar.c index 3f8e9560058f..6fd37f3ff337 100644 --- a/plugins/ToolStatus/toolbar.c +++ b/plugins/ToolStatus/toolbar.c @@ -675,7 +675,7 @@ VOID ToolbarLoadButtonSettings( PhStringToInteger64(&commandIdPart, 10, &commandInteger); buttonArray[index].idCommand = (INT)commandInteger; - //buttonArray[index].iBitmap = I_IMAGECALLBACK; + buttonArray[index].iBitmap = I_IMAGECALLBACK; buttonArray[index].fsState = TBSTATE_ENABLED; if (commandInteger) From a33657cece882aee101a584e6eafae5f4f33edcf Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 9 Jul 2019 12:48:55 +0200 Subject: [PATCH 1979/2058] Fix incorrect listview values --- phlib/guisup.c | 39 +++++++++++++++++---------------------- phlib/include/guisup.h | 4 ++-- 2 files changed, 19 insertions(+), 24 deletions(-) diff --git a/phlib/guisup.c b/phlib/guisup.c index 657ad5c0814a..488218e57507 100644 --- a/phlib/guisup.c +++ b/phlib/guisup.c @@ -169,50 +169,44 @@ INT PhFindListViewItemByParam( return ListView_FindItem(ListViewHandle, StartIndex, &findInfo); } -LOGICAL PhGetListViewItemImageIndex( +BOOLEAN PhGetListViewItemImageIndex( _In_ HWND ListViewHandle, _In_ INT Index, _Out_ PINT ImageIndex ) { - LOGICAL result; LVITEM item; item.mask = LVIF_IMAGE; item.iItem = Index; item.iSubItem = 0; - result = ListView_GetItem(ListViewHandle, &item); - - if (!result) - return result; + if (!ListView_GetItem(ListViewHandle, &item)) + return FALSE; *ImageIndex = item.iImage; - return result; + return TRUE; } -LOGICAL PhGetListViewItemParam( +BOOLEAN PhGetListViewItemParam( _In_ HWND ListViewHandle, _In_ INT Index, _Out_ PVOID *Param ) { - LOGICAL result; LVITEM item; item.mask = LVIF_PARAM; item.iItem = Index; item.iSubItem = 0; - result = ListView_GetItem(ListViewHandle, &item); - - if (!result) - return result; + if (!ListView_GetItem(ListViewHandle, &item)) + return FALSE; *Param = (PVOID)item.lParam; - return result; + return TRUE; } VOID PhRemoveListViewItem( @@ -530,12 +524,12 @@ VOID PhSetStateAllListViewItems( _In_ ULONG Mask ) { - ULONG i; - ULONG count; + INT i; + INT count; count = ListView_GetItemCount(hWnd); - if (count == -1) + if (count <= 0) return; for (i = 0; i < count; i++) @@ -919,7 +913,7 @@ VOID PhSetClipboardString( HANDLE data; PVOID memory; - data = GlobalAlloc(GMEM_MOVEABLE, String->Length + sizeof(WCHAR)); + data = GlobalAlloc(GMEM_MOVEABLE, String->Length + sizeof(UNICODE_NULL)); memory = GlobalLock(data); memcpy(memory, String->Buffer, String->Length); @@ -1432,7 +1426,6 @@ BOOL CALLBACK PhpGetProcessMainWindowEnumWindowsProc( { PGET_PROCESS_MAIN_WINDOW_CONTEXT context = (PGET_PROCESS_MAIN_WINDOW_CONTEXT)Context; ULONG processId; - HWND parentWindow; WINDOWINFO windowInfo; if (context->SkipInvisible && !IsWindowVisible(WindowHandle)) @@ -1440,9 +1433,11 @@ BOOL CALLBACK PhpGetProcessMainWindowEnumWindowsProc( GetWindowThreadProcessId(WindowHandle, &processId); - if (UlongToHandle(processId) == context->ProcessId && (context->SkipInvisible ? - !((parentWindow = GetParent(WindowHandle)) && IsWindowVisible(parentWindow)) && // skip windows with a visible parent - PhGetWindowTextEx(WindowHandle, PH_GET_WINDOW_TEXT_INTERNAL | PH_GET_WINDOW_TEXT_LENGTH_ONLY, NULL) != 0 : TRUE)) // skip windows with no title + //if (UlongToHandle(processId) == context->ProcessId && (context->SkipInvisible ? + // !((parentWindow = GetParent(WindowHandle)) && IsWindowVisible(parentWindow)) && // skip windows with a visible parent + // PhGetWindowTextEx(WindowHandle, PH_GET_WINDOW_TEXT_INTERNAL | PH_GET_WINDOW_TEXT_LENGTH_ONLY, NULL) != 0 : TRUE)) // skip windows with no title + + if (UlongToHandle(processId) == context->ProcessId) { if (!context->ImmersiveWindow && context->IsImmersive && GetProp(WindowHandle, L"Windows.ImmersiveShell.IdentifyAsMainCoreWindow")) diff --git a/phlib/include/guisup.h b/phlib/include/guisup.h index f76abc2d6128..6cce406f8ed4 100644 --- a/phlib/include/guisup.h +++ b/phlib/include/guisup.h @@ -183,14 +183,14 @@ INT PhFindListViewItemByParam( ); PHLIBAPI -LOGICAL PhGetListViewItemImageIndex( +BOOLEAN PhGetListViewItemImageIndex( _In_ HWND ListViewHandle, _In_ INT Index, _Out_ PINT ImageIndex ); PHLIBAPI -LOGICAL PhGetListViewItemParam( +BOOLEAN PhGetListViewItemParam( _In_ HWND ListViewHandle, _In_ INT Index, _Out_ PVOID *Param From 1640dd820cac4e09c10305f0bbec47bd996a1df8 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 9 Jul 2019 15:21:23 +0200 Subject: [PATCH 1980/2058] Export PhDoesFileExistsWin32, Update RtlDoesFileExists_U --- ProcessHacker/ProcessHacker.def | 1 + ProcessHacker/actions.c | 2 +- ProcessHacker/mainwnd.c | 4 ++-- ProcessHacker/mwpgproc.c | 2 +- ProcessHacker/prpggen.c | 2 +- ProcessHacker/prpgwmi.c | 2 +- phlib/kph.c | 2 +- phlib/native.c | 4 ++-- phlib/util.c | 6 ++++-- plugins/DotNetTools/asmpage.c | 6 +++--- plugins/NetworkTools/country.c | 2 +- plugins/NetworkTools/update.c | 2 +- plugins/UserNotes/main.c | 2 +- 13 files changed, 20 insertions(+), 17 deletions(-) diff --git a/ProcessHacker/ProcessHacker.def b/ProcessHacker/ProcessHacker.def index 00b749dc3bb9..4f928d5cc488 100644 --- a/ProcessHacker/ProcessHacker.def +++ b/ProcessHacker/ProcessHacker.def @@ -241,6 +241,7 @@ EXPORTS PhConnectPipe PhDeleteDirectory PhDeleteFileWin32 + PhDoesFileExistsWin32 PhDisconnectNamedPipe PhEnumDirectoryFile PhEnumDirectoryObjects diff --git a/ProcessHacker/actions.c b/ProcessHacker/actions.c index 56a7fbf40401..eda52f17df05 100644 --- a/ProcessHacker/actions.c +++ b/ProcessHacker/actions.c @@ -366,7 +366,7 @@ BOOLEAN PhpStartPhSvcProcess( fileName = PhConcatStrings2(applicationDirectory->Buffer, relativeFileNames[i]); PhMoveReference(&fileName, PhGetFullPath(fileName->Buffer, NULL)); - if (fileName && RtlDoesFileExists_U(fileName->Buffer)) + if (fileName && PhDoesFileExistsWin32(fileName->Buffer)) { if (PhShellProcessHackerEx( hWnd, diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index da37c77b39e8..a878d77722aa 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -1300,7 +1300,7 @@ VOID PhMwpOnCommand( if (processItem && !PhIsNullOrEmptyString(processItem->FileName) && - RtlDoesFileExists_U(PhGetString(processItem->FileName) + PhDoesFileExistsWin32(PhGetString(processItem->FileName) )) { PhReferenceObject(processItem); @@ -1983,7 +1983,7 @@ BOOLEAN PhMwpOnNotify( // { // PPH_STRING fileName = PhCreateString(cmdlineArgList[0]); // - // if (fileName && !RtlDoesFileExists_U(fileName->Buffer)) + // if (fileName && !PhDoesFileExistsWin32(fileName->Buffer)) // { // PPH_STRING filePathString; // diff --git a/ProcessHacker/mwpgproc.c b/ProcessHacker/mwpgproc.c index cd6f2e69b55b..ca4f6e84fed5 100644 --- a/ProcessHacker/mwpgproc.c +++ b/ProcessHacker/mwpgproc.c @@ -546,7 +546,7 @@ VOID PhMwpInitializeProcessMenu( PhEnableEMenuItem(Menu, ID_PROCESS_SEARCHONLINE, TRUE); } - if (PhIsNullOrEmptyString(Processes[0]->FileName) || !RtlDoesFileExists_U(PhGetString(Processes[0]->FileName))) + if (PhIsNullOrEmptyString(Processes[0]->FileName) || !PhDoesFileExistsWin32(PhGetString(Processes[0]->FileName))) { PhEnableEMenuItem(Menu, ID_PROCESS_OPENFILELOCATION, FALSE); } diff --git a/ProcessHacker/prpggen.c b/ProcessHacker/prpggen.c index ff776ebe4b34..1d5c21fc003f 100644 --- a/ProcessHacker/prpggen.c +++ b/ProcessHacker/prpggen.c @@ -232,7 +232,7 @@ INT_PTR CALLBACK PhpProcessGeneralDlgProc( } else { - if (!RtlDoesFileExists_U(PhGetString(processItem->FileName))) + if (!PhDoesFileExistsWin32(PhGetString(processItem->FileName))) { EnableWindow(GetDlgItem(hwndDlg, IDC_OPENFILENAME), FALSE); EnableWindow(GetDlgItem(hwndDlg, IDC_INSPECT), FALSE); diff --git a/ProcessHacker/prpgwmi.c b/ProcessHacker/prpgwmi.c index d87028a9f1dd..f4be2fe003ef 100644 --- a/ProcessHacker/prpgwmi.c +++ b/ProcessHacker/prpgwmi.c @@ -721,7 +721,7 @@ INT_PTR CALLBACK PhpProcessWmiProvidersDlgProc( break; case 4: { - if (!PhIsNullOrEmptyString(entry->FileName) && RtlDoesFileExists_U(entry->FileName->Buffer)) + if (!PhIsNullOrEmptyString(entry->FileName) && PhDoesFileExistsWin32(entry->FileName->Buffer)) { PhShellExecuteUserString( hwndDlg, diff --git a/phlib/kph.c b/phlib/kph.c index 75ccd9d2c3b2..95e510f7f94e 100644 --- a/phlib/kph.c +++ b/phlib/kph.c @@ -152,7 +152,7 @@ NTSTATUS KphConnect2Ex( CloseServiceHandle(scmHandle); } - if (!started && RtlDoesFileExists_U(FileName)) + if (!started && PhDoesFileExistsWin32(FileName)) { // Try to create the service. diff --git a/phlib/native.c b/phlib/native.c index 49e11ac6b47c..8794fb312acf 100644 --- a/phlib/native.c +++ b/phlib/native.c @@ -7612,7 +7612,7 @@ NTSTATUS PhCreateDirectory( PH_STRINGREF remainingPart; if (PhIsNullOrEmptyString(DirectoryPath)) - return STATUS_FAIL_CHECK; + return STATUS_INVALID_PARAMETER; if (PhDoesFileExistsWin32(PhGetString(DirectoryPath))) return STATUS_SUCCESS; @@ -7797,7 +7797,7 @@ NTSTATUS PhDeleteDirectory( NtClose(directoryHandle); } - if (!RtlDoesFileExists_U(PhGetString(DirectoryPath))) + if (!PhDoesFileExistsWin32(PhGetString(DirectoryPath))) return STATUS_SUCCESS; return status; diff --git a/phlib/util.c b/phlib/util.c index 38f71028cb23..45f6986b4eff 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -2747,7 +2747,7 @@ NTSTATUS PhCreateProcessWin32Ex( LocalFree(cmdlineArgList); } - if (fileName && !RtlDoesFileExists_U(fileName->Buffer)) + if (fileName && !PhDoesFileExistsWin32(fileName->Buffer)) { PPH_STRING filePathSr; @@ -2867,6 +2867,8 @@ NTSTATUS PhCreateProcessAsUser( if (!Information->ApplicationName && !Information->CommandLine) return STATUS_INVALID_PARAMETER_MIX; + startupInfo.dwFlags = STARTF_USESHOWWINDOW; + startupInfo.wShowWindow = SW_NORMAL; startupInfo.lpDesktop = Information->DesktopName; // Try to use CreateProcessWithLogonW if we need to load the user profile. @@ -5266,7 +5268,7 @@ VOID PhDeleteCacheFile( PPH_STRING cacheFullFilePath; ULONG indexOfFileName = ULONG_MAX; - if (RtlDoesFileExists_U(PhGetString(FileName))) + if (PhDoesFileExistsWin32(PhGetString(FileName))) { PhDeleteFileWin32(PhGetString(FileName)); } diff --git a/plugins/DotNetTools/asmpage.c b/plugins/DotNetTools/asmpage.c index 87255e50f15b..9dcb397fa5da 100644 --- a/plugins/DotNetTools/asmpage.c +++ b/plugins/DotNetTools/asmpage.c @@ -480,7 +480,7 @@ VOID DotNetAsmShowContextMenu( PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_CLR_COPY, L"&Copy", NULL, NULL), ULONG_MAX); PhInsertCopyCellEMenuItem(menu, ID_CLR_COPY, Context->TreeNewHandle, ContextMenuEvent->Column); - if (PhIsNullOrEmptyString(node->PathText) || !RtlDoesFileExists_U(node->PathText->Buffer)) + if (PhIsNullOrEmptyString(node->PathText) || !PhDoesFileExistsWin32(PhGetString(node->PathText))) { PhSetFlagsEMenuItem(menu, ID_CLR_INSPECT, PH_EMENU_DISABLED, PH_EMENU_DISABLED); PhSetFlagsEMenuItem(menu, ID_CLR_OPENFILELOCATION, PH_EMENU_DISABLED, PH_EMENU_DISABLED); @@ -507,7 +507,7 @@ VOID DotNetAsmShowContextMenu( { case ID_CLR_INSPECT: { - if (!PhIsNullOrEmptyString(node->PathText) && RtlDoesFileExists_U(node->PathText->Buffer)) + if (!PhIsNullOrEmptyString(node->PathText) && PhDoesFileExistsWin32(PhGetString(node->PathText))) { PhShellExecuteUserString( Context->WindowHandle, @@ -521,7 +521,7 @@ VOID DotNetAsmShowContextMenu( break; case ID_CLR_OPENFILELOCATION: { - if (!PhIsNullOrEmptyString(node->PathText) && RtlDoesFileExists_U(node->PathText->Buffer)) + if (!PhIsNullOrEmptyString(node->PathText) && PhDoesFileExistsWin32(PhGetString(node->PathText))) { PhShellExploreFile(Context->WindowHandle, node->PathText->Buffer); } diff --git a/plugins/NetworkTools/country.c b/plugins/NetworkTools/country.c index f4ba9e28b469..d4a3cbf9988d 100644 --- a/plugins/NetworkTools/country.c +++ b/plugins/NetworkTools/country.c @@ -44,7 +44,7 @@ PPH_STRING NetToolsGetGeoLiteDbPath( directory = PH_AUTO(PhGetApplicationDirectory()); path = PH_AUTO(PhConcatStringRef2(&directory->sr, &databaseFile->sr)); - if (RtlDoesFileExists_U(path->Buffer)) + if (PhDoesFileExistsWin32(path->Buffer)) { return PhReferenceObject(path); } diff --git a/plugins/NetworkTools/update.c b/plugins/NetworkTools/update.c index df33b01296f1..ad60b52d1507 100644 --- a/plugins/NetworkTools/update.c +++ b/plugins/NetworkTools/update.c @@ -392,7 +392,7 @@ NTSTATUS GeoIPUpdateThread( if (PhIsNullOrEmptyString(dbpath)) goto CleanupExit; - if (RtlDoesFileExists_U(PhGetString(dbpath))) + if (PhDoesFileExistsWin32(PhGetString(dbpath))) { if (!NT_SUCCESS(PhDeleteFileWin32(PhGetString(dbpath)))) goto CleanupExit; diff --git a/plugins/UserNotes/main.c b/plugins/UserNotes/main.c index 1208276f0f87..9b6dc01fa9fb 100644 --- a/plugins/UserNotes/main.c +++ b/plugins/UserNotes/main.c @@ -294,7 +294,7 @@ VOID NTAPI LoadCallback( directory = PH_AUTO(PhGetApplicationDirectory()); path = PH_AUTO(PhConcatStringRef2(&directory->sr, &databaseFile)); - if (RtlDoesFileExists_U(path->Buffer)) + if (PhDoesFileExistsWin32(path->Buffer)) { SetDbPath(path); } From 96cd2b9bd5d0b404fc2665f445c42f6d69321c18 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 9 Jul 2019 15:23:58 +0200 Subject: [PATCH 1981/2058] ExtendedTools: Disable disk events when tab disabled --- plugins/ExtendedTools/disktab.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/plugins/ExtendedTools/disktab.c b/plugins/ExtendedTools/disktab.c index fd5861ab1116..d4b793233cea 100644 --- a/plugins/ExtendedTools/disktab.c +++ b/plugins/ExtendedTools/disktab.c @@ -180,6 +180,20 @@ BOOLEAN EtpDiskPageCallback( // Nothing } return TRUE; + case MainTabPageSelected: + { + BOOLEAN selected = (BOOLEAN)Parameter1; + + if (selected) + { + EtDiskEnabled = TRUE; + } + else + { + EtDiskEnabled = FALSE; + } + } + break; case MainTabPageExportContent: { PPH_MAIN_TAB_PAGE_EXPORT_CONTENT exportContent = Parameter1; From e4b65db54078497a10a1d616e384e3a93c20f6ae Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 9 Jul 2019 15:26:24 +0200 Subject: [PATCH 1982/2058] Update solutions to VS2019 --- ProcessHacker/ProcessHacker.vcxproj | 10 +++++----- appveyor.yml | 2 +- phlib/phlib.vcxproj | 10 +++++----- plugins/DotNetTools/DotNetTools.vcxproj | 10 +++++----- .../ExtendedNotifications.vcxproj | 10 +++++----- plugins/ExtendedServices/ExtendedServices.vcxproj | 10 +++++----- plugins/ExtendedTools/ExtendedTools.vcxproj | 10 +++++----- plugins/HardwareDevices/HardwareDevices.vcxproj | 10 +++++----- plugins/NetworkTools/NetworkTools.vcxproj | 10 +++++----- plugins/OnlineChecks/OnlineChecks.vcxproj | 10 +++++----- plugins/ToolStatus/ToolStatus.vcxproj | 10 +++++----- plugins/Updater/Updater.vcxproj | 10 +++++----- plugins/UserNotes/UserNotes.vcxproj | 10 +++++----- plugins/WindowExplorer/WindowExplorer.vcxproj | 10 +++++----- tools/peview/peview.vcxproj | 10 +++++----- 15 files changed, 71 insertions(+), 71 deletions(-) diff --git a/ProcessHacker/ProcessHacker.vcxproj b/ProcessHacker/ProcessHacker.vcxproj index 2424f13fc227..6a83f0e98fb6 100644 --- a/ProcessHacker/ProcessHacker.vcxproj +++ b/ProcessHacker/ProcessHacker.vcxproj @@ -22,14 +22,14 @@ {0271DD27-6707-4290-8DFE-285702B7115D} ProcessHacker Win32Proj - 10.0.17763.0 + 10.0 Application Unicode true - v141 + v142 WindowsLocalDebugger $(SolutionDir)bin\$(Configuration)$(PlatformArchitecture)\ Spectre @@ -37,7 +37,7 @@ Application Unicode - v141 + v142 WindowsLocalDebugger $(SolutionDir)bin\$(Configuration)$(PlatformArchitecture)\ @@ -45,7 +45,7 @@ Application Unicode true - v141 + v142 WindowsLocalDebugger $(SolutionDir)bin\$(Configuration)$(PlatformArchitecture)\ Spectre @@ -53,7 +53,7 @@ Application Unicode - v141 + v142 WindowsLocalDebugger $(SolutionDir)bin\$(Configuration)$(PlatformArchitecture)\ diff --git a/appveyor.yml b/appveyor.yml index c71e48f79d57..321ce514fe26 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,5 +1,5 @@ # Build image. -image: Visual Studio 2017 +image: Visual Studio 2019 # Version format. version: "#{build}" diff --git a/phlib/phlib.vcxproj b/phlib/phlib.vcxproj index dceab869782f..c927de8a9cfd 100644 --- a/phlib/phlib.vcxproj +++ b/phlib/phlib.vcxproj @@ -22,32 +22,32 @@ {477D0215-F252-41A1-874B-F27E3EA1ED17} phlib Win32Proj - 10.0.17763.0 + 10.0 StaticLibrary Unicode true - v141 + v142 Spectre StaticLibrary Unicode - v141 + v142 StaticLibrary Unicode true - v141 + v142 Spectre StaticLibrary Unicode - v141 + v142 diff --git a/plugins/DotNetTools/DotNetTools.vcxproj b/plugins/DotNetTools/DotNetTools.vcxproj index 66df5200d23f..5c635ebbb2ea 100644 --- a/plugins/DotNetTools/DotNetTools.vcxproj +++ b/plugins/DotNetTools/DotNetTools.vcxproj @@ -23,28 +23,28 @@ DotNetTools Win32Proj DotNetTools - 10.0.17763.0 + 10.0 DynamicLibrary Unicode - v141 + v142 DynamicLibrary Unicode - v141 + v142 DynamicLibrary Unicode - v141 + v142 DynamicLibrary Unicode - v141 + v142 diff --git a/plugins/ExtendedNotifications/ExtendedNotifications.vcxproj b/plugins/ExtendedNotifications/ExtendedNotifications.vcxproj index 41fdf7c61cdd..d8d8c7d64ed8 100644 --- a/plugins/ExtendedNotifications/ExtendedNotifications.vcxproj +++ b/plugins/ExtendedNotifications/ExtendedNotifications.vcxproj @@ -23,28 +23,28 @@ ExtendedNotifications Win32Proj ExtendedNotifications - 10.0.17763.0 + 10.0 DynamicLibrary Unicode - v141 + v142 DynamicLibrary Unicode - v141 + v142 DynamicLibrary Unicode - v141 + v142 DynamicLibrary Unicode - v141 + v142 diff --git a/plugins/ExtendedServices/ExtendedServices.vcxproj b/plugins/ExtendedServices/ExtendedServices.vcxproj index 073a89063451..1bf18d1db0a0 100644 --- a/plugins/ExtendedServices/ExtendedServices.vcxproj +++ b/plugins/ExtendedServices/ExtendedServices.vcxproj @@ -23,28 +23,28 @@ ExtendedServices Win32Proj ExtendedServices - 10.0.17763.0 + 10.0 DynamicLibrary Unicode - v141 + v142 DynamicLibrary Unicode - v141 + v142 DynamicLibrary Unicode - v141 + v142 DynamicLibrary Unicode - v141 + v142 diff --git a/plugins/ExtendedTools/ExtendedTools.vcxproj b/plugins/ExtendedTools/ExtendedTools.vcxproj index 1a92f5ef1f1f..3ffc4f1cf357 100644 --- a/plugins/ExtendedTools/ExtendedTools.vcxproj +++ b/plugins/ExtendedTools/ExtendedTools.vcxproj @@ -23,28 +23,28 @@ ExtendedTools Win32Proj ExtendedTools - 10.0.17763.0 + 10.0 DynamicLibrary Unicode - v141 + v142 DynamicLibrary Unicode - v141 + v142 DynamicLibrary Unicode - v141 + v142 DynamicLibrary Unicode - v141 + v142 diff --git a/plugins/HardwareDevices/HardwareDevices.vcxproj b/plugins/HardwareDevices/HardwareDevices.vcxproj index 39b3efefb8ba..0ce216dcb72c 100644 --- a/plugins/HardwareDevices/HardwareDevices.vcxproj +++ b/plugins/HardwareDevices/HardwareDevices.vcxproj @@ -23,28 +23,28 @@ HardwareDevices Win32Proj HardwareDevices - 10.0.17763.0 + 10.0 DynamicLibrary Unicode - v141 + v142 DynamicLibrary Unicode - v141 + v142 DynamicLibrary Unicode - v141 + v142 DynamicLibrary Unicode - v141 + v142 diff --git a/plugins/NetworkTools/NetworkTools.vcxproj b/plugins/NetworkTools/NetworkTools.vcxproj index f55bd1e227a5..49031ce6f2d2 100644 --- a/plugins/NetworkTools/NetworkTools.vcxproj +++ b/plugins/NetworkTools/NetworkTools.vcxproj @@ -23,28 +23,28 @@ NetworkTools Win32Proj NetworkTools - 10.0.17763.0 + 10.0 DynamicLibrary Unicode - v141 + v142 DynamicLibrary Unicode - v141 + v142 DynamicLibrary Unicode - v141 + v142 DynamicLibrary Unicode - v141 + v142 diff --git a/plugins/OnlineChecks/OnlineChecks.vcxproj b/plugins/OnlineChecks/OnlineChecks.vcxproj index ce8e88b3d4c2..fef273413f95 100644 --- a/plugins/OnlineChecks/OnlineChecks.vcxproj +++ b/plugins/OnlineChecks/OnlineChecks.vcxproj @@ -23,28 +23,28 @@ OnlineChecks Win32Proj OnlineChecks - 10.0.17763.0 + 10.0 DynamicLibrary Unicode - v141 + v142 DynamicLibrary Unicode - v141 + v142 DynamicLibrary Unicode - v141 + v142 DynamicLibrary Unicode - v141 + v142 diff --git a/plugins/ToolStatus/ToolStatus.vcxproj b/plugins/ToolStatus/ToolStatus.vcxproj index b31153c1de42..45ae6d69d8ee 100644 --- a/plugins/ToolStatus/ToolStatus.vcxproj +++ b/plugins/ToolStatus/ToolStatus.vcxproj @@ -23,28 +23,28 @@ ToolStatus Win32Proj ToolStatus - 10.0.17763.0 + 10.0 DynamicLibrary Unicode - v141 + v142 DynamicLibrary Unicode - v141 + v142 DynamicLibrary Unicode - v141 + v142 DynamicLibrary Unicode - v141 + v142 diff --git a/plugins/Updater/Updater.vcxproj b/plugins/Updater/Updater.vcxproj index 4434a44bdb14..07b112497684 100644 --- a/plugins/Updater/Updater.vcxproj +++ b/plugins/Updater/Updater.vcxproj @@ -23,28 +23,28 @@ Updater Win32Proj Updater - 10.0.17763.0 + 10.0 DynamicLibrary Unicode - v141 + v142 DynamicLibrary Unicode - v141 + v142 DynamicLibrary Unicode - v141 + v142 DynamicLibrary Unicode - v141 + v142 diff --git a/plugins/UserNotes/UserNotes.vcxproj b/plugins/UserNotes/UserNotes.vcxproj index 72732b329e56..48436c6458ce 100644 --- a/plugins/UserNotes/UserNotes.vcxproj +++ b/plugins/UserNotes/UserNotes.vcxproj @@ -23,28 +23,28 @@ UserNotes Win32Proj UserNotes - 10.0.17763.0 + 10.0 DynamicLibrary Unicode - v141 + v142 DynamicLibrary Unicode - v141 + v142 DynamicLibrary Unicode - v141 + v142 DynamicLibrary Unicode - v141 + v142 diff --git a/plugins/WindowExplorer/WindowExplorer.vcxproj b/plugins/WindowExplorer/WindowExplorer.vcxproj index 4183ef6b9d99..467f05833956 100644 --- a/plugins/WindowExplorer/WindowExplorer.vcxproj +++ b/plugins/WindowExplorer/WindowExplorer.vcxproj @@ -23,28 +23,28 @@ WindowExplorer Win32Proj WindowExplorer - 10.0.17763.0 + 10.0 DynamicLibrary Unicode - v141 + v142 DynamicLibrary Unicode - v141 + v142 DynamicLibrary Unicode - v141 + v142 DynamicLibrary Unicode - v141 + v142 diff --git a/tools/peview/peview.vcxproj b/tools/peview/peview.vcxproj index 54eff02b040f..f2a45df1243d 100644 --- a/tools/peview/peview.vcxproj +++ b/tools/peview/peview.vcxproj @@ -22,32 +22,32 @@ {72C124A2-3C80-41C6-ABA1-C4948B713204} peview Win32Proj - 10.0.17763.0 + 10.0 Application Unicode true - v141 + v142 Spectre Application Unicode - v141 + v142 Application Unicode true - v141 + v142 Spectre Application Unicode - v141 + v142 From c6d36062cd4ca140141eff8edd99cef42495c456 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 9 Jul 2019 15:52:00 +0200 Subject: [PATCH 1983/2058] Create SECURITY.md --- SECURITY.md | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 SECURITY.md diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 000000000000..28258c33ff09 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,40 @@ +# Security Policies and Procedures + +This document outlines security procedures and general policies for the Process Hacker project. + + * [Reporting a Bug](#reporting-a-bug) + * [Disclosure Policy](#disclosure-policy) + * [Comments on this Policy](#comments-on-this-policy) + +## Reporting a Bug + +The Process Hacker team and community take all security bugs very seriously. We appreciate efforts +for responsible disclosure and will make every effort to acknowledge your contributions. + +Report security bugs by emailing the lead maintainers at dmex04@gmail.com and wj32.64@gmail.com. + +The Process Hacker team will acknowledge your email within 48 hours, and will send a +more detailed response indicating the next steps in handling +your report. After the initial reply to your report, the security team will +endeavor to keep you informed of the progress towards a fix and full +announcement, and may ask for additional information or guidance. + +Report security bugs in third-party modules to the person or team maintaining +the module. + +## Disclosure Policy + +When the Process Hacker team receives a security bug report, they will assign it to a +primary developer. This person will coordinate the fix and release process, +involving the following steps: + + * Confirm the problem and determine the affected versions. + * Audit code to find any potential similar problems. + * Seek review from respected third-party security experts. + * Prepare fixes for all releases still under maintenance. These fixes will be + released as fast as possible. + +## Comments on this Policy + +If you have suggestions on how this process could be improved please submit a +pull request. From 7969fba41dcc5f557d9ff45013fd3973b0533e23 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 9 Jul 2019 15:53:51 +0200 Subject: [PATCH 1984/2058] SetupTool: Update solution to VS2019 --- .../CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj b/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj index 9d52f172dd0c..b7fd319b2e09 100644 --- a/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj +++ b/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj @@ -13,20 +13,20 @@ {5C00734F-F50A-49FC-9D2A-F6EE51ECB00F} CustomSetupTool - 10.0.17763.0 + 10.0 CustomSetupTool Application true - v141 + v142 Unicode Application false - v141 + v142 true Unicode Spectre From 2021adb0ec0f017070013023ceea23270a8c3168 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 9 Jul 2019 16:05:22 +0200 Subject: [PATCH 1985/2058] Update KPH solution to latest WDK --- KProcessHacker/KProcessHacker.vcxproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/KProcessHacker/KProcessHacker.vcxproj b/KProcessHacker/KProcessHacker.vcxproj index e81758b6c06f..2523a02cadc5 100644 --- a/KProcessHacker/KProcessHacker.vcxproj +++ b/KProcessHacker/KProcessHacker.vcxproj @@ -28,7 +28,7 @@ KProcessHacker $(VCTargetsPath11) - 10.0.17763.0 + 10.0.18362.0 WindowsKernelModeDriver10.0 From 302d0b87fa2f29aedfe3a5115d6ce6d6c4ec73ec Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 11 Jul 2019 12:52:39 +0200 Subject: [PATCH 1986/2058] peview: Fix crash searching large pdbs --- tools/peview/pdb.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/tools/peview/pdb.c b/tools/peview/pdb.c index 1b6a705fa526..5485c2372e33 100644 --- a/tools/peview/pdb.c +++ b/tools/peview/pdb.c @@ -971,7 +971,7 @@ BOOLEAN PdbGetSymbolChildren( return TRUE; length = sizeof(TI_FINDCHILDREN_PARAMS) + symbolCount * sizeof(ULONG); - symbols = _alloca(length); + symbols = _malloca(length); memset(symbols, 0, length); symbols->Count = symbolCount; @@ -1020,6 +1020,8 @@ BOOLEAN PdbGetSymbolUdtVariables( } } + _freea(symbolParams); + return TRUE; } @@ -1096,6 +1098,8 @@ BOOLEAN PdbGetSymbolUdtBaseClasses( } } + _freea(symbolParams); + return TRUE; } @@ -1134,6 +1138,8 @@ BOOLEAN PdbGetSymbolUdtUnionMembers( } } + _freea(symbolParams); + return TRUE; } @@ -1172,6 +1178,8 @@ BOOLEAN PdbGetSymbolFunctionArguments( } } + _freea(symbolParams); + return TRUE; } @@ -1210,6 +1218,8 @@ BOOLEAN PdbGetSymbolEnumerations( } } + _freea(symbolParams); + return TRUE; } From 40f7cd4e097110c9e55da24987e85bd553e029d7 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 11 Jul 2019 12:54:12 +0200 Subject: [PATCH 1987/2058] peview: Remove SetWindowSubclass --- tools/peview/searchbox.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/tools/peview/searchbox.c b/tools/peview/searchbox.c index bb3a20dbf82d..fcedf529d181 100644 --- a/tools/peview/searchbox.c +++ b/tools/peview/searchbox.c @@ -51,6 +51,7 @@ typedef struct _EDIT_CONTEXT HBRUSH BrushNormal; HBRUSH BrushPushed; HBRUSH BrushHot; + WNDPROC DefaultWindowProc; } EDIT_CONTEXT, *PEDIT_CONTEXT; HICON PhpSearchBitmapToIcon( @@ -421,12 +422,16 @@ LRESULT CALLBACK PhpSearchWndSubclassProc( _In_ HWND hWnd, _In_ UINT uMsg, _In_ WPARAM wParam, - _In_ LPARAM lParam, - _In_ UINT_PTR uIdSubclass, - _In_ ULONG_PTR dwRefData + _In_ LPARAM lParam ) { - PEDIT_CONTEXT context = (PEDIT_CONTEXT)dwRefData; + PEDIT_CONTEXT context; + WNDPROC oldWndProc; + + if (!(context = PhGetWindowContext(hWnd, SHRT_MAX))) + return 0; + + oldWndProc = context->DefaultWindowProc; switch (uMsg) { @@ -437,7 +442,8 @@ LRESULT CALLBACK PhpSearchWndSubclassProc( if (context->WindowFont) DeleteObject(context->WindowFont); - RemoveWindowSubclass(hWnd, PhpSearchWndSubclassProc, uIdSubclass); + SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)oldWndProc); + PhRemoveWindowContext(hWnd, SHRT_MAX); PhFree(context); } break; @@ -651,7 +657,7 @@ LRESULT CALLBACK PhpSearchWndSubclassProc( break; } - return DefSubclassProc(hWnd, uMsg, wParam, lParam); + return CallWindowProc(oldWndProc, hWnd, uMsg, wParam, lParam); } HICON PhpSearchBitmapToIcon( @@ -687,9 +693,7 @@ VOID PvCreateSearchControl( { PEDIT_CONTEXT context; - context = (PEDIT_CONTEXT)PhAllocate(sizeof(EDIT_CONTEXT)); - memset(context, 0, sizeof(EDIT_CONTEXT)); - + context = PhAllocateZero(sizeof(EDIT_CONTEXT)); context->WindowHandle = WindowHandle; //PhpSearchInitializeTheme(context); @@ -700,7 +704,9 @@ VOID PvCreateSearchControl( Edit_SetCueBannerText(context->WindowHandle, BannerText); // Subclass the Edit control window procedure. - SetWindowSubclass(context->WindowHandle, PhpSearchWndSubclassProc, 0, (ULONG_PTR)context); + context->DefaultWindowProc = (WNDPROC)GetWindowLongPtr(WindowHandle, GWLP_WNDPROC); + PhSetWindowContext(WindowHandle, SHRT_MAX, context); + SetWindowLongPtr(WindowHandle, GWLP_WNDPROC, (LONG_PTR)PhpSearchWndSubclassProc); // Initialize the theme parameters. SendMessage(context->WindowHandle, WM_THEMECHANGED, 0, 0); From db2b76dc8ab8213d182be3ec8cda2dbadaf0d3d2 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 11 Jul 2019 12:59:48 +0200 Subject: [PATCH 1988/2058] peview: Update checksum selection --- tools/peview/peview.rc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/peview/peview.rc b/tools/peview/peview.rc index d2e0526072fb..1df275454ecd 100644 --- a/tools/peview/peview.rc +++ b/tools/peview/peview.rc @@ -205,7 +205,6 @@ BEGIN LTEXT "Target machine:",IDC_STATIC,7,57,53,8 LTEXT "Static",IDC_TARGETMACHINE,78,57,215,8 LTEXT "Checksum:",IDC_STATIC,7,100,36,8 - LTEXT "Static",IDC_CHECKSUM,78,100,215,8 LTEXT "Subsystem:",IDC_STATIC,7,111,38,8 LTEXT "Subsystem version:",IDC_STATIC,7,122,64,8 LTEXT "Characteristics:",IDC_STATIC,7,133,51,8 @@ -227,6 +226,7 @@ BEGIN LTEXT "Version:",IDC_STATIC,15,41,27,8 EDITTEXT IDC_VERSION,44,41,242,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER CONTROL "Company Name Link",IDC_COMPANYNAME_LINK,"SysLink",LWS_NOPREFIX | NOT WS_VISIBLE | WS_TABSTOP,46,29,240,9 + EDITTEXT IDC_CHECKSUM,76,100,217,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER END IDD_PEIMPORTS DIALOGEX 0, 0, 300, 280 From c7342505c26a37dcb5adb7cf925d1520fd645f8b Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 11 Jul 2019 13:37:46 +0200 Subject: [PATCH 1989/2058] Fix message error checking (#437) --- ProcessHacker/hndlprp.c | 8 +++---- plugins/DotNetTools/asmpage.c | 10 +++++--- plugins/ExtendedServices/depend.c | 24 ++++++++++++++----- plugins/ExtendedServices/main.c | 4 ++-- plugins/ExtendedServices/other.c | 27 +++++++++++++++------- plugins/ExtendedServices/recovery.c | 33 ++++++++++++++++++-------- plugins/ExtendedServices/triggpg.c | 36 +++++++++++++++++++++-------- plugins/NetworkTools/tracert.c | 2 +- 8 files changed, 101 insertions(+), 43 deletions(-) diff --git a/ProcessHacker/hndlprp.c b/ProcessHacker/hndlprp.c index 68391a8163c0..fe5158ae44ea 100644 --- a/ProcessHacker/hndlprp.c +++ b/ProcessHacker/hndlprp.c @@ -1066,7 +1066,7 @@ VOID PhpUpdateHandleGeneral( exitcode = PhFormatString( L"0x%x (%s)", exitStatus, - status->Buffer + PhGetStringOrDefault(status, L"Unknown") ); PhSetListViewSubItem( @@ -1077,7 +1077,7 @@ VOID PhpUpdateHandleGeneral( ); PhDereferenceObject(exitcode); - PhDereferenceObject(status); + PhClearReference(&status); } NtClose(dupHandle); @@ -1166,7 +1166,7 @@ VOID PhpUpdateHandleGeneral( exitcode = PhFormatString( L"0x%x (%s)", exitStatus, - status->Buffer + PhGetStringOrDefault(status, L"Unknown") ); PhSetListViewSubItem( @@ -1177,7 +1177,7 @@ VOID PhpUpdateHandleGeneral( ); PhDereferenceObject(exitcode); - PhDereferenceObject(status); + PhClearReference(&status); } NtClose(dupHandle); diff --git a/plugins/DotNetTools/asmpage.c b/plugins/DotNetTools/asmpage.c index 9dcb397fa5da..a05a18e0bae7 100644 --- a/plugins/DotNetTools/asmpage.c +++ b/plugins/DotNetTools/asmpage.c @@ -1665,12 +1665,16 @@ INT_PTR CALLBACK DotNetAsmPageDlgProc( } else { + PPH_STRING errorMessage = PhGetWin32Message(result); - PhMoveReference(&context->TreeErrorMessage, - PhConcatStrings2(L"Unable to start the event tracing session: ", PhGetStringOrDefault(PhGetWin32Message(result), L"Unknown error")) - ); + PhMoveReference(&context->TreeErrorMessage, PhConcatStrings2( + L"Unable to start the event tracing session: ", + PhGetStringOrDefault(errorMessage, L"Unknown error") + )); TreeNew_SetEmptyText(context->TreeNewHandle, &context->TreeErrorMessage->sr, 0); TreeNew_NodesStructured(context->TreeNewHandle); + + PhClearReference(&errorMessage); } DestroyDotNetTraceQuery(queryContext); diff --git a/plugins/ExtendedServices/depend.c b/plugins/ExtendedServices/depend.c index 9ed76d38e253..89dd011feeaa 100644 --- a/plugins/ExtendedServices/depend.c +++ b/plugins/ExtendedServices/depend.c @@ -139,7 +139,7 @@ INT_PTR CALLBACK EspServiceDependenciesDlgProc( HWND serviceListHandle; PPH_LIST serviceList; SC_HANDLE serviceHandle; - ULONG win32Result = 0; + ULONG win32Result = ERROR_SUCCESS; BOOLEAN success = FALSE; PPH_SERVICE_ITEM *services; @@ -206,9 +206,15 @@ INT_PTR CALLBACK EspServiceDependenciesDlgProc( if (!success) { - PhSetDialogItemText(hwndDlg, IDC_SERVICES_LAYOUT, PhaConcatStrings2(L"Unable to enumerate dependencies: ", - ((PPH_STRING)PH_AUTO(PhGetWin32Message(win32Result)))->Buffer)->Buffer); + PPH_STRING errorMessage = PhGetWin32Message(win32Result); + + PhSetDialogItemText(hwndDlg, IDC_SERVICES_LAYOUT, PhaConcatStrings2( + L"Unable to enumerate dependencies: ", + PhGetStringOrDefault(errorMessage, L"Unknown error.")) + ); + ShowWindow(GetDlgItem(hwndDlg, IDC_SERVICES_LAYOUT), SW_SHOW); + PhClearReference(&errorMessage); } PhInitializeWindowTheme(hwndDlg, !!PhGetIntegerSetting(L"EnableThemeSupport")); @@ -269,7 +275,7 @@ INT_PTR CALLBACK EspServiceDependentsDlgProc( HWND serviceListHandle; PPH_LIST serviceList; SC_HANDLE serviceHandle; - ULONG win32Result = 0; + ULONG win32Result = ERROR_SUCCESS; BOOLEAN success = FALSE; PPH_SERVICE_ITEM *services; @@ -320,9 +326,15 @@ INT_PTR CALLBACK EspServiceDependentsDlgProc( if (!success) { - PhSetDialogItemText(hwndDlg, IDC_SERVICES_LAYOUT, PhaConcatStrings2(L"Unable to enumerate dependents: ", - ((PPH_STRING)PH_AUTO(PhGetWin32Message(win32Result)))->Buffer)->Buffer); + PPH_STRING errorMessage = PhGetWin32Message(win32Result); + + PhSetDialogItemText(hwndDlg, IDC_SERVICES_LAYOUT, PhaConcatStrings2( + L"Unable to enumerate dependents: ", + PhGetStringOrDefault(errorMessage, L"Unknown error.")) + ); + ShowWindow(GetDlgItem(hwndDlg, IDC_SERVICES_LAYOUT), SW_SHOW); + PhClearReference(&errorMessage); } PhInitializeWindowTheme(hwndDlg, !!PhGetIntegerSetting(L"EnableThemeSupport")); diff --git a/plugins/ExtendedServices/main.c b/plugins/ExtendedServices/main.c index f2e9bc39ab5c..3cbf85bfb1e2 100644 --- a/plugins/ExtendedServices/main.c +++ b/plugins/ExtendedServices/main.c @@ -67,7 +67,7 @@ VOID NTAPI MenuItemCallback( { PPH_SERVICE_ITEM serviceItem = menuItem->Context; SC_HANDLE serviceHandle; - ULONG win32Result = 0; + ULONG win32Result = ERROR_SUCCESS; if (serviceHandle = PhOpenService(serviceItem->Name->Buffer, SERVICE_QUERY_STATUS)) { @@ -79,7 +79,7 @@ VOID NTAPI MenuItemCallback( win32Result = GetLastError(); } - if (win32Result != 0) + if (win32Result != ERROR_SUCCESS) { PhShowStatus( PhMainWndHandle, diff --git a/plugins/ExtendedServices/other.c b/plugins/ExtendedServices/other.c index 93a35003787b..97c961fd16f8 100644 --- a/plugins/ExtendedServices/other.c +++ b/plugins/ExtendedServices/other.c @@ -375,8 +375,15 @@ INT_PTR CALLBACK EspServiceOtherDlgProc( if (!NT_SUCCESS(status)) { - PhShowWarning(hwndDlg, L"Unable to query service information: %s", - ((PPH_STRING)PH_AUTO(PhGetNtMessage(status)))->Buffer); + PPH_STRING errorMessage = PhGetNtMessage(status); + + PhShowWarning( + hwndDlg, + L"Unable to query service information: %s", + PhGetStringOrDefault(errorMessage, L"Unknown error.") + ); + + PhClearReference(&errorMessage); } context->Ready = TRUE; @@ -585,7 +592,7 @@ INT_PTR CALLBACK EspServiceOtherDlgProc( case PSN_APPLY: { SC_HANDLE serviceHandle = NULL; - ULONG win32Result = 0; + ULONG win32Result = ERROR_SUCCESS; BOOLEAN connectedToPhSvc = FALSE; PPH_STRING launchProtectedString; ULONG launchProtected; @@ -624,7 +631,7 @@ INT_PTR CALLBACK EspServiceOtherDlgProc( // Elevate using phsvc. if (PhUiConnectToPhSvc(hwndDlg, FALSE)) { - win32Result = 0; + win32Result = ERROR_SUCCESS; connectedToPhSvc = TRUE; } else @@ -666,7 +673,7 @@ INT_PTR CALLBACK EspServiceOtherDlgProc( requiredPrivilegesInfo.pmszRequiredPrivileges = sb.String->Buffer; - if (win32Result == 0 && !EspChangeServiceConfig2(context->ServiceItem->Name->Buffer, serviceHandle, + if (win32Result == ERROR_SUCCESS && !EspChangeServiceConfig2(context->ServiceItem->Name->Buffer, serviceHandle, SERVICE_CONFIG_REQUIRED_PRIVILEGES_INFO, &requiredPrivilegesInfo)) { win32Result = GetLastError(); @@ -682,7 +689,7 @@ INT_PTR CALLBACK EspServiceOtherDlgProc( sidTypeString = PH_AUTO(PhGetWindowText(GetDlgItem(hwndDlg, IDC_SIDTYPE))); sidInfo.dwServiceSidType = EspGetServiceSidTypeInteger(sidTypeString->Buffer); - if (win32Result == 0 && !EspChangeServiceConfig2(context->ServiceItem->Name->Buffer, serviceHandle, + if (win32Result == ERROR_SUCCESS && !EspChangeServiceConfig2(context->ServiceItem->Name->Buffer, serviceHandle, SERVICE_CONFIG_SERVICE_SID_INFO, &sidInfo)) { win32Result = GetLastError(); @@ -707,17 +714,21 @@ INT_PTR CALLBACK EspServiceOtherDlgProc( if (serviceHandle) CloseServiceHandle(serviceHandle); - if (win32Result != 0) + if (win32Result != ERROR_SUCCESS) { + PPH_STRING errorMessage = PhGetWin32Message(win32Result); + if (win32Result == ERROR_CANCELLED || PhShowMessage( hwndDlg, MB_ICONERROR | MB_RETRYCANCEL, L"Unable to change service information: %s", - ((PPH_STRING)PH_AUTO(PhGetWin32Message(win32Result)))->Buffer + PhGetStringOrDefault(errorMessage, L"Unknown error.") ) == IDRETRY) { SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_INVALID); } + + PhClearReference(&errorMessage); } } diff --git a/plugins/ExtendedServices/recovery.c b/plugins/ExtendedServices/recovery.c index 6404ce75318d..8b66feb99c95 100644 --- a/plugins/ExtendedServices/recovery.c +++ b/plugins/ExtendedServices/recovery.c @@ -317,13 +317,20 @@ INT_PTR CALLBACK EspServiceRecoveryDlgProc( } else if (!NT_SUCCESS(status)) { + PPH_STRING errorMessage = PhGetNtMessage(status); + PhSetDialogItemText(hwndDlg, IDC_RESETFAILCOUNT, L"0"); context->EnableFlagCheckBox = TRUE; EnableWindow(GetDlgItem(hwndDlg, IDC_ENABLEFORERRORSTOPS), TRUE); - - PhShowWarning(hwndDlg, L"Unable to query service recovery information: %s", - ((PPH_STRING)PH_AUTO(PhGetNtMessage(status)))->Buffer); + + PhShowWarning( + hwndDlg, + L"Unable to query service recovery information: %s", + PhGetStringOrDefault(errorMessage, L"Unknown error.") + ); + + PhClearReference(&errorMessage); } EspFixControls(hwndDlg, context); @@ -555,14 +562,20 @@ INT_PTR CALLBACK EspServiceRecoveryDlgProc( return TRUE; ErrorCase: - if (PhShowMessage( - hwndDlg, - MB_ICONERROR | MB_RETRYCANCEL, - L"Unable to change service recovery information: %s", - ((PPH_STRING)PH_AUTO(PhGetWin32Message(GetLastError())))->Buffer - ) == IDRETRY) { - SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_INVALID); + PPH_STRING errorMessage = PhGetWin32Message(GetLastError()); + + if (PhShowMessage( + hwndDlg, + MB_ICONERROR | MB_RETRYCANCEL, + L"Unable to change service recovery information: %s", + PhGetStringOrDefault(errorMessage, L"Unknown error.") + ) == IDRETRY) + { + SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_INVALID); + } + + PhClearReference(&errorMessage); } } return TRUE; diff --git a/plugins/ExtendedServices/triggpg.c b/plugins/ExtendedServices/triggpg.c index 1355a3a58300..1216d106ee63 100644 --- a/plugins/ExtendedServices/triggpg.c +++ b/plugins/ExtendedServices/triggpg.c @@ -95,8 +95,15 @@ INT_PTR CALLBACK EspServiceTriggersDlgProc( if (!NT_SUCCESS(status)) { - PhShowWarning(hwndDlg, L"Unable to query service trigger information: %s", - ((PPH_STRING)PH_AUTO(PhGetNtMessage(status)))->Buffer); + PPH_STRING errorMessage = PhGetNtMessage(status); + + PhShowWarning( + hwndDlg, + L"Unable to query service trigger information: %s", + PhGetStringOrDefault(errorMessage, L"Unknown error.") + ); + + PhClearReference(&errorMessage); } PhInitializeLayoutManager(&context->LayoutManager, hwndDlg); @@ -148,21 +155,32 @@ INT_PTR CALLBACK EspServiceTriggersDlgProc( return TRUE; case PSN_APPLY: { - ULONG win32Result = 0; + ULONG win32Result = ERROR_SUCCESS; SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_NOERROR); if (!EsSaveServiceTriggerInfo(context->TriggerContext, &win32Result)) { - if (win32Result == ERROR_CANCELLED || (PhShowMessage( - hwndDlg, - MB_ICONERROR | MB_RETRYCANCEL, - L"Unable to change service trigger information: %s", - ((PPH_STRING)PH_AUTO(PhGetWin32Message(win32Result)))->Buffer - ) == IDRETRY)) + if (win32Result == ERROR_CANCELLED) { SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_INVALID); } + else + { + PPH_STRING errorMessage = PhGetWin32Message(win32Result); + + if (PhShowMessage( + hwndDlg, + MB_ICONERROR | MB_RETRYCANCEL, + L"Unable to change service trigger information: %s", + PhGetStringOrDefault(errorMessage, L"Unknown error.") + ) == IDRETRY) + { + SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_INVALID); + } + + PhClearReference(&errorMessage); + } } return TRUE; diff --git a/plugins/NetworkTools/tracert.c b/plugins/NetworkTools/tracert.c index d10d45610323..76d2963ad56e 100644 --- a/plugins/NetworkTools/tracert.c +++ b/plugins/NetworkTools/tracert.c @@ -821,7 +821,7 @@ INT_PTR CALLBACK TracertDlgProc( } } - PhDereferenceObject(hostName); + PhClearReference(&hostName); } break; } From 32d49c86c05b7c18e384f65bcd97a6459e843a6b Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 11 Jul 2019 15:24:30 +0200 Subject: [PATCH 1990/2058] Remove unused paramaters --- ProcessHacker/include/mainwndp.h | 12 +- ProcessHacker/main.c | 3 + ProcessHacker/mainwnd.c | 212 ++++++++++++++++--------------- 3 files changed, 125 insertions(+), 102 deletions(-) diff --git a/ProcessHacker/include/mainwndp.h b/ProcessHacker/include/mainwndp.h index 78d8bb56c2a2..9a9f779cbfa2 100644 --- a/ProcessHacker/include/mainwndp.h +++ b/ProcessHacker/include/mainwndp.h @@ -46,7 +46,7 @@ VOID PhMwpApplyUpdateInterval( ); VOID PhMwpInitializeControls( - VOID + _In_ HWND WindowHandle ); NTSTATUS PhMwpLoadStage1Worker( @@ -68,33 +68,38 @@ VOID PhMwpOnSettingChange( ); VOID PhMwpOnCommand( + _In_ HWND WindowHandle, _In_ ULONG Id ); VOID PhMwpOnShowWindow( + _In_ HWND WindowHandle, _In_ BOOLEAN Showing, _In_ ULONG State ); BOOLEAN PhMwpOnSysCommand( + _In_ HWND WindowHandle, _In_ ULONG Type, _In_ LONG CursorScreenX, _In_ LONG CursorScreenY ); VOID PhMwpOnMenuCommand( + _In_ HWND WindowHandle, _In_ ULONG Index, _In_ HMENU Menu ); VOID PhMwpOnInitMenuPopup( + _In_ HWND WindowHandle, _In_ HMENU Menu, _In_ ULONG Index, _In_ BOOLEAN IsWindowMenu ); VOID PhMwpOnSize( - VOID + _In_ HWND WindowHandle ); VOID PhMwpOnSizing( @@ -112,6 +117,7 @@ BOOLEAN PhMwpOnNotify( ); ULONG_PTR PhMwpOnUserMessage( + _In_ HWND WindowHandle, _In_ ULONG Message, _In_ ULONG_PTR WParam, _In_ ULONG_PTR LParam @@ -155,6 +161,7 @@ BOOLEAN PhMwpExecuteComputerCommand( ); VOID PhMwpActivateWindow( + _In_ HWND WindowHandle, _In_ BOOLEAN Toggle ); @@ -165,6 +172,7 @@ VOID PhMwpInitializeMainMenu( ); VOID PhMwpDispatchMenuCommand( + _In_ HWND WindowHandle, _In_ HMENU MenuHandle, _In_ ULONG ItemIndex, _In_ ULONG ItemId, diff --git a/ProcessHacker/main.c b/ProcessHacker/main.c index 0b4f4c318237..bad6f146f4ec 100644 --- a/ProcessHacker/main.c +++ b/ProcessHacker/main.c @@ -512,6 +512,9 @@ VOID PhInitializeFont( { NONCLIENTMETRICS metrics = { sizeof(metrics) }; + if (PhApplicationFont) + DeleteObject(PhApplicationFont); + if ( !(PhApplicationFont = PhCreateFont(L"Microsoft Sans Serif", 8, FW_NORMAL)) && !(PhApplicationFont = PhCreateFont(L"Tahoma", 8, FW_NORMAL)) diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index a878d77722aa..9071fbaf3932 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -197,7 +197,7 @@ BOOLEAN PhMainWndInitialization( PhMwpOnSettingChange(); // Initialize child controls. - PhMwpInitializeControls(); + PhMwpInitializeControls(PhMainWndHandle); PhMwpLoadSettings(); PhLogInitialization(); @@ -208,11 +208,11 @@ BOOLEAN PhMainWndInitialization( PhMwpInitializeProviders(); // Queue delayed init functions. - PhQueueItemWorkQueue(PhGetGlobalWorkQueue(), PhMwpLoadStage1Worker, NULL); + PhQueueItemWorkQueue(PhGetGlobalWorkQueue(), PhMwpLoadStage1Worker, PhMainWndHandle); // Perform a layout. PhMwpSelectionChangedTabControl(ULONG_MAX); - PhMwpOnSize(); + PhMwpOnSize(PhMainWndHandle); if ((PhStartupParameters.ShowHidden || PhGetIntegerSetting(L"StartHidden")) && PhNfIconsEnabled()) ShowCommand = SW_HIDE; @@ -286,33 +286,33 @@ LRESULT CALLBACK PhMwpWndProc( break; case WM_COMMAND: { - PhMwpOnCommand(GET_WM_COMMAND_ID(wParam, lParam)); + PhMwpOnCommand(hWnd, GET_WM_COMMAND_ID(wParam, lParam)); } break; case WM_SHOWWINDOW: { - PhMwpOnShowWindow(!!wParam, (ULONG)lParam); + PhMwpOnShowWindow(hWnd, !!wParam, (ULONG)lParam); } break; case WM_SYSCOMMAND: { - if (PhMwpOnSysCommand((ULONG)wParam, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))) + if (PhMwpOnSysCommand(hWnd, (ULONG)wParam, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))) return 0; } break; case WM_MENUCOMMAND: { - PhMwpOnMenuCommand((ULONG)wParam, (HMENU)lParam); + PhMwpOnMenuCommand(hWnd, (ULONG)wParam, (HMENU)lParam); } break; case WM_INITMENUPOPUP: { - PhMwpOnInitMenuPopup((HMENU)wParam, LOWORD(lParam), !!HIWORD(lParam)); + PhMwpOnInitMenuPopup(hWnd, (HMENU)wParam, LOWORD(lParam), !!HIWORD(lParam)); } break; case WM_SIZE: { - PhMwpOnSize(); + PhMwpOnSize(hWnd); } break; case WM_SIZING: @@ -350,7 +350,7 @@ LRESULT CALLBACK PhMwpWndProc( if (uMsg >= WM_PH_FIRST && uMsg <= WM_PH_LAST) { - return PhMwpOnUserMessage(uMsg, wParam, lParam); + return PhMwpOnUserMessage(hWnd, uMsg, wParam, lParam); } return DefWindowProc(hWnd, uMsg, wParam, lParam); @@ -408,7 +408,7 @@ VOID PhMwpApplyUpdateInterval( } VOID PhMwpInitializeControls( - VOID + _In_ HWND WindowHandle ) { ULONG thinRows; @@ -435,7 +435,7 @@ VOID PhMwpInitializeControls( 0, 3, 3, - PhMainWndHandle, + WindowHandle, NULL, PhInstanceHandle, NULL @@ -450,7 +450,7 @@ VOID PhMwpInitializeControls( 0, 3, 3, - PhMainWndHandle, + WindowHandle, NULL, PhInstanceHandle, &treelistCreateParams @@ -464,7 +464,7 @@ VOID PhMwpInitializeControls( 0, 3, 3, - PhMainWndHandle, + WindowHandle, NULL, PhInstanceHandle, &treelistCreateParams @@ -478,7 +478,7 @@ VOID PhMwpInitializeControls( 0, 3, 3, - PhMainWndHandle, + WindowHandle, NULL, PhInstanceHandle, &treelistCreateParams @@ -521,7 +521,7 @@ NTSTATUS PhMwpLoadStage1Worker( SetProcessShutdownParameters(0x100, 0); DelayedLoadCompleted = TRUE; - //PostMessage(PhMainWndHandle, WM_PH_DELAYED_LOAD_COMPLETED, 0, 0); + //PostMessage((HWND)Parameter, WM_PH_DELAYED_LOAD_COMPLETED, 0, 0); return STATUS_SUCCESS; } @@ -560,9 +560,6 @@ VOID PhMwpOnSettingChange( VOID ) { - if (PhApplicationFont) - DeleteObject(PhApplicationFont); - PhInitializeFont(); SendMessage(TabControlHandle, WM_SETFONT, (WPARAM)PhApplicationFont, FALSE); @@ -586,6 +583,7 @@ static NTSTATUS PhpOpenServiceControlManager( } VOID PhMwpOnCommand( + _In_ HWND WindowHandle, _In_ ULONG Id ) { @@ -596,25 +594,25 @@ VOID PhMwpOnCommand( if (PhGetIntegerSetting(L"HideOnClose")) { if (PhNfIconsEnabled()) - ShowWindow(PhMainWndHandle, SW_HIDE); + ShowWindow(WindowHandle, SW_HIDE); } else if (PhGetIntegerSetting(L"CloseOnEscape")) { - ProcessHacker_Destroy(PhMainWndHandle); + ProcessHacker_Destroy(WindowHandle); } } break; case ID_HACKER_RUN: { SelectedRunAsMode = 0; - PhShowRunFileDialog(PhMainWndHandle, NULL, NULL, NULL, NULL, RFF_OPTRUNAS); + PhShowRunFileDialog(WindowHandle, NULL, NULL, NULL, NULL, RFF_OPTRUNAS); } break; case ID_HACKER_RUNASADMINISTRATOR: { SelectedRunAsMode = RUNAS_MODE_ADMIN; PhShowRunFileDialog( - PhMainWndHandle, + WindowHandle, NULL, NULL, NULL, @@ -627,7 +625,7 @@ VOID PhMwpOnCommand( // { // SelectedRunAsMode = RUNAS_MODE_LIMITED; // PhShowRunFileDialog( - // PhMainWndHandle, + // WindowHandle, // NULL, // NULL, // NULL, @@ -638,15 +636,15 @@ VOID PhMwpOnCommand( // break; case ID_HACKER_RUNAS: { - PhShowRunAsDialog(PhMainWndHandle, NULL); + PhShowRunAsDialog(WindowHandle, NULL); } break; case ID_HACKER_SHOWDETAILSFORALLPROCESSES: { - ProcessHacker_PrepareForEarlyShutdown(PhMainWndHandle); + ProcessHacker_PrepareForEarlyShutdown(WindowHandle); if (PhShellProcessHacker( - PhMainWndHandle, + WindowHandle, L"-v", SW_SHOW, PH_SHELL_EXECUTE_ADMIN, @@ -655,11 +653,11 @@ VOID PhMwpOnCommand( NULL )) { - ProcessHacker_Destroy(PhMainWndHandle); + ProcessHacker_Destroy(WindowHandle); } else { - ProcessHacker_CancelEarlyShutdown(PhMainWndHandle); + ProcessHacker_CancelEarlyShutdown(WindowHandle); } } break; @@ -681,7 +679,7 @@ VOID PhMwpOnCommand( PhSetFileDialogFilter(fileDialog, filters, sizeof(filters) / sizeof(PH_FILETYPE_FILTER)); PhSetFileDialogFileName(fileDialog, PH_AUTO_T(PH_STRING, PhFormat(format, 3, 60))->Buffer); - if (PhShowFileDialog(PhMainWndHandle, fileDialog)) + if (PhShowFileDialog(WindowHandle, fileDialog)) { NTSTATUS status; PPH_STRING fileName; @@ -719,7 +717,7 @@ VOID PhMwpOnCommand( } if (!NT_SUCCESS(status)) - PhShowStatus(PhMainWndHandle, L"Unable to create the file", status, 0); + PhShowStatus(WindowHandle, L"Unable to create the file", status, 0); } PhFreeFileDialog(fileDialog); @@ -732,12 +730,12 @@ VOID PhMwpOnCommand( break; case ID_HACKER_OPTIONS: { - PhShowOptionsDialog(PhMainWndHandle); + PhShowOptionsDialog(WindowHandle); } break; case ID_HACKER_PLUGINS: { - PhShowPluginsDialog(PhMainWndHandle); + PhShowPluginsDialog(WindowHandle); } break; case ID_COMPUTER_LOCK: @@ -751,7 +749,7 @@ VOID PhMwpOnCommand( PhMwpExecuteComputerCommand(Id); break; case ID_HACKER_EXIT: - ProcessHacker_Destroy(PhMainWndHandle); + ProcessHacker_Destroy(WindowHandle); break; case ID_VIEW_SYSTEMINFORMATION: PhShowSystemInformationDialog(NULL); @@ -790,7 +788,7 @@ VOID PhMwpOnCommand( case ID_VIEW_ALWAYSONTOP: { AlwaysOnTop = !AlwaysOnTop; - SetWindowPos(PhMainWndHandle, AlwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST, + SetWindowPos(WindowHandle, AlwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE); PhSetIntegerSetting(L"MainWindowAlwaysOnTop", AlwaysOnTop); @@ -812,7 +810,7 @@ VOID PhMwpOnCommand( opacity = PH_ID_TO_OPACITY(Id); PhSetIntegerSetting(L"MainWindowOpacity", opacity); - PhSetWindowOpacity(PhMainWndHandle, opacity); + PhSetWindowOpacity(WindowHandle, opacity); } break; case ID_VIEW_REFRESH: @@ -866,7 +864,7 @@ VOID PhMwpOnCommand( break; case ID_TOOLS_CREATESERVICE: { - PhShowCreateServiceDialog(PhMainWndHandle); + PhShowCreateServiceDialog(WindowHandle); } break; case ID_TOOLS_HIDDENPROCESSES: @@ -885,10 +883,10 @@ VOID PhMwpOnCommand( PhSetFileDialogFilter(fileDialog, filters, sizeof(filters) / sizeof(PH_FILETYPE_FILTER)); - if (PhShowFileDialog(PhMainWndHandle, fileDialog)) + if (PhShowFileDialog(WindowHandle, fileDialog)) { PhShellExecuteUserString( - PhMainWndHandle, + WindowHandle, L"ProgramInspectExecutables", PH_AUTO_T(PH_STRING, PhGetFileDialogFileName(fileDialog))->Buffer, FALSE, @@ -901,7 +899,7 @@ VOID PhMwpOnCommand( break; case ID_TOOLS_PAGEFILES: { - PhShowPagefilesDialog(PhMainWndHandle); + PhShowPagefilesDialog(WindowHandle); } break; case ID_TOOLS_STARTTASKMANAGER: @@ -914,7 +912,7 @@ VOID PhMwpOnCommand( if (WindowsVersion >= WINDOWS_8 && !PhGetOwnTokenAttributes().Elevated) { - if (PhUiConnectToPhSvc(PhMainWndHandle, FALSE)) + if (PhUiConnectToPhSvc(WindowHandle, FALSE)) { PhSvcCallCreateProcessIgnoreIfeoDebugger(taskmgrFileName->Buffer); PhUiDisconnectFromPhSvc(); @@ -940,32 +938,32 @@ VOID PhMwpOnCommand( break; case ID_USER_CONNECT: { - PhUiConnectSession(PhMainWndHandle, SelectedUserSessionId); + PhUiConnectSession(WindowHandle, SelectedUserSessionId); } break; case ID_USER_DISCONNECT: { - PhUiDisconnectSession(PhMainWndHandle, SelectedUserSessionId); + PhUiDisconnectSession(WindowHandle, SelectedUserSessionId); } break; case ID_USER_LOGOFF: { - PhUiLogoffSession(PhMainWndHandle, SelectedUserSessionId); + PhUiLogoffSession(WindowHandle, SelectedUserSessionId); } break; case ID_USER_REMOTECONTROL: { - PhShowSessionShadowDialog(PhMainWndHandle, SelectedUserSessionId); + PhShowSessionShadowDialog(WindowHandle, SelectedUserSessionId); } break; case ID_USER_SENDMESSAGE: { - PhShowSessionSendMessageDialog(PhMainWndHandle, SelectedUserSessionId); + PhShowSessionSendMessageDialog(WindowHandle, SelectedUserSessionId); } break; case ID_USER_PROPERTIES: { - PhShowSessionProperties(PhMainWndHandle, SelectedUserSessionId); + PhShowSessionProperties(WindowHandle, SelectedUserSessionId); } break; case ID_HELP_LOG: @@ -975,7 +973,7 @@ VOID PhMwpOnCommand( break; case ID_HELP_DONATE: { - PhShellExecute(PhMainWndHandle, L"https://sourceforge.net/project/project_donations.php?group_id=242527", NULL); + PhShellExecute(WindowHandle, L"https://sourceforge.net/project/project_donations.php?group_id=242527", NULL); } break; case ID_HELP_DEBUGCONSOLE: @@ -996,7 +994,7 @@ VOID PhMwpOnCommand( PhGetSelectedProcessItems(&processes, &numberOfProcesses); PhReferenceObjects(processes, numberOfProcesses); - if (PhUiTerminateProcesses(PhMainWndHandle, processes, numberOfProcesses)) + if (PhUiTerminateProcesses(WindowHandle, processes, numberOfProcesses)) PhDeselectAllProcessNodes(); PhDereferenceObjects(processes, numberOfProcesses); @@ -1011,7 +1009,7 @@ VOID PhMwpOnCommand( { PhReferenceObject(processItem); - if (PhUiTerminateTreeProcess(PhMainWndHandle, processItem)) + if (PhUiTerminateTreeProcess(WindowHandle, processItem)) PhDeselectAllProcessNodes(); PhDereferenceObject(processItem); @@ -1025,7 +1023,7 @@ VOID PhMwpOnCommand( PhGetSelectedProcessItems(&processes, &numberOfProcesses); PhReferenceObjects(processes, numberOfProcesses); - PhUiSuspendProcesses(PhMainWndHandle, processes, numberOfProcesses); + PhUiSuspendProcesses(WindowHandle, processes, numberOfProcesses); PhDereferenceObjects(processes, numberOfProcesses); PhFree(processes); } @@ -1037,7 +1035,7 @@ VOID PhMwpOnCommand( PhGetSelectedProcessItems(&processes, &numberOfProcesses); PhReferenceObjects(processes, numberOfProcesses); - PhUiResumeProcesses(PhMainWndHandle, processes, numberOfProcesses); + PhUiResumeProcesses(WindowHandle, processes, numberOfProcesses); PhDereferenceObjects(processes, numberOfProcesses); PhFree(processes); } @@ -1064,7 +1062,7 @@ VOID PhMwpOnCommand( if (processItem) { PhReferenceObject(processItem); - PhUiCreateDumpFileProcess(PhMainWndHandle, processItem); + PhUiCreateDumpFileProcess(WindowHandle, processItem); PhDereferenceObject(processItem); } } @@ -1076,7 +1074,7 @@ VOID PhMwpOnCommand( if (processItem) { PhReferenceObject(processItem); - PhUiDebugProcess(PhMainWndHandle, processItem); + PhUiDebugProcess(WindowHandle, processItem); PhDereferenceObject(processItem); } } @@ -1089,7 +1087,7 @@ VOID PhMwpOnCommand( { PhReferenceObject(processItem); PhUiSetVirtualizationProcess( - PhMainWndHandle, + WindowHandle, processItem, !PhMwpSelectedProcessVirtualizationEnabled ); @@ -1104,7 +1102,7 @@ VOID PhMwpOnCommand( if (processItem) { PhReferenceObject(processItem); - PhShowProcessAffinityDialog(PhMainWndHandle, processItem, NULL); + PhShowProcessAffinityDialog(WindowHandle, processItem, NULL); PhDereferenceObject(processItem); } } @@ -1116,7 +1114,7 @@ VOID PhMwpOnCommand( if (processItem) { PhReferenceObject(processItem); - PhUiSetCriticalProcess(PhMainWndHandle, processItem); + PhUiSetCriticalProcess(WindowHandle, processItem); PhDereferenceObject(processItem); } } @@ -1128,7 +1126,7 @@ VOID PhMwpOnCommand( if (processItem) { PhReferenceObject(processItem); - PhUiDetachFromDebuggerProcess(PhMainWndHandle, processItem); + PhUiDetachFromDebuggerProcess(WindowHandle, processItem); PhDereferenceObject(processItem); } } @@ -1140,7 +1138,7 @@ VOID PhMwpOnCommand( if (processItem) { PhReferenceObject(processItem); - PhShowGdiHandlesDialog(PhMainWndHandle, processItem); + PhShowGdiHandlesDialog(WindowHandle, processItem); PhDereferenceObject(processItem); } } @@ -1177,7 +1175,7 @@ VOID PhMwpOnCommand( } PhReferenceObject(processItem); - PhUiSetPagePriorityProcess(PhMainWndHandle, processItem, pagePriority); + PhUiSetPagePriorityProcess(WindowHandle, processItem, pagePriority); PhDereferenceObject(processItem); } } @@ -1189,7 +1187,7 @@ VOID PhMwpOnCommand( PhGetSelectedProcessItems(&processes, &numberOfProcesses); PhReferenceObjects(processes, numberOfProcesses); - PhUiReduceWorkingSetProcesses(PhMainWndHandle, processes, numberOfProcesses); + PhUiReduceWorkingSetProcesses(WindowHandle, processes, numberOfProcesses); PhDereferenceObjects(processes, numberOfProcesses); PhFree(processes); } @@ -1201,7 +1199,7 @@ VOID PhMwpOnCommand( if (processItem && processItem->FileName) { PhSetStringSetting2(L"RunAsProgram", &processItem->FileName->sr); - PhShowRunAsDialog(PhMainWndHandle, NULL); + PhShowRunAsDialog(WindowHandle, NULL); } } break; @@ -1211,7 +1209,7 @@ VOID PhMwpOnCommand( if (processItem) { - PhShowRunAsDialog(PhMainWndHandle, processItem->ProcessId); + PhShowRunAsDialog(WindowHandle, processItem->ProcessId); } } break; @@ -1305,7 +1303,7 @@ VOID PhMwpOnCommand( { PhReferenceObject(processItem); PhShellExecuteUserString( - PhMainWndHandle, + WindowHandle, L"FileBrowseExecutable", processItem->FileName->Buffer, FALSE, @@ -1321,7 +1319,7 @@ VOID PhMwpOnCommand( if (processItem) { - PhSearchOnlineString(PhMainWndHandle, processItem->ProcessName->Buffer); + PhSearchOnlineString(WindowHandle, processItem->ProcessName->Buffer); } } break; @@ -1364,7 +1362,7 @@ VOID PhMwpOnCommand( if (serviceItem) { PhReferenceObject(serviceItem); - PhUiStartService(PhMainWndHandle, serviceItem); + PhUiStartService(WindowHandle, serviceItem); PhDereferenceObject(serviceItem); } } @@ -1376,7 +1374,7 @@ VOID PhMwpOnCommand( if (serviceItem) { PhReferenceObject(serviceItem); - PhUiContinueService(PhMainWndHandle, serviceItem); + PhUiContinueService(WindowHandle, serviceItem); PhDereferenceObject(serviceItem); } } @@ -1388,7 +1386,7 @@ VOID PhMwpOnCommand( if (serviceItem) { PhReferenceObject(serviceItem); - PhUiPauseService(PhMainWndHandle, serviceItem); + PhUiPauseService(WindowHandle, serviceItem); PhDereferenceObject(serviceItem); } } @@ -1400,7 +1398,7 @@ VOID PhMwpOnCommand( if (serviceItem) { PhReferenceObject(serviceItem); - PhUiStopService(PhMainWndHandle, serviceItem); + PhUiStopService(WindowHandle, serviceItem); PhDereferenceObject(serviceItem); } } @@ -1413,7 +1411,7 @@ VOID PhMwpOnCommand( { PhReferenceObject(serviceItem); - if (PhUiDeleteService(PhMainWndHandle, serviceItem)) + if (PhUiDeleteService(WindowHandle, serviceItem)) PhDeselectAllServiceNodes(); PhDereferenceObject(serviceItem); @@ -1443,7 +1441,7 @@ VOID PhMwpOnCommand( PPH_STRING hklmServiceKeyName; hklmServiceKeyName = PH_AUTO(PhConcatStringRef2(&hklm, &serviceKeyName->sr)); - PhShellOpenKey2(PhMainWndHandle, hklmServiceKeyName); + PhShellOpenKey2(WindowHandle, hklmServiceKeyName); NtClose(keyHandle); } } @@ -1461,7 +1459,7 @@ VOID PhMwpOnCommand( if (fileName = PhGetServiceRelevantFileName(&serviceItem->Name->sr, serviceHandle)) { PhShellExecuteUserString( - PhMainWndHandle, + WindowHandle, L"FileBrowseExecutable", fileName->Buffer, FALSE, @@ -1483,7 +1481,7 @@ VOID PhMwpOnCommand( // The object relies on the list view reference, which could // disappear if we don't reference the object here. PhReferenceObject(serviceItem); - PhShowServiceProperties(PhMainWndHandle, serviceItem); + PhShowServiceProperties(WindowHandle, serviceItem); PhDereferenceObject(serviceItem); } } @@ -1520,7 +1518,7 @@ VOID PhMwpOnCommand( { PhMwpSelectPage(PhMwpServicesPage->Index); SetFocus(PhMwpServiceTreeNewHandle); - ProcessHacker_SelectServiceItem(PhMainWndHandle, serviceItem); + ProcessHacker_SelectServiceItem(WindowHandle, serviceItem); PhDereferenceObject(serviceItem); } @@ -1535,7 +1533,7 @@ VOID PhMwpOnCommand( PhGetSelectedNetworkItems(&networkItems, &numberOfNetworkItems); PhReferenceObjects(networkItems, numberOfNetworkItems); - if (PhUiCloseConnections(PhMainWndHandle, networkItems, numberOfNetworkItems)) + if (PhUiCloseConnections(WindowHandle, networkItems, numberOfNetworkItems)) PhDeselectAllNetworkNodes(); PhDereferenceObjects(networkItems, numberOfNetworkItems); @@ -1575,18 +1573,20 @@ VOID PhMwpOnCommand( } VOID PhMwpOnShowWindow( + _In_ HWND WindowHandle, _In_ BOOLEAN Showing, _In_ ULONG State ) { if (NeedsMaximize) { - ShowWindow(PhMainWndHandle, SW_MAXIMIZE); + ShowWindow(WindowHandle, SW_MAXIMIZE); NeedsMaximize = FALSE; } } BOOLEAN PhMwpOnSysCommand( + _In_ HWND WindowHandle, _In_ ULONG Type, _In_ LONG CursorScreenX, _In_ LONG CursorScreenY @@ -1598,7 +1598,7 @@ BOOLEAN PhMwpOnSysCommand( { if (PhGetIntegerSetting(L"HideOnClose") && PhNfIconsEnabled()) { - ShowWindow(PhMainWndHandle, SW_HIDE); + ShowWindow(WindowHandle, SW_HIDE); return TRUE; } } @@ -1610,7 +1610,7 @@ BOOLEAN PhMwpOnSysCommand( if (PhGetIntegerSetting(L"HideOnMinimize") && PhNfIconsEnabled()) { - ShowWindow(PhMainWndHandle, SW_HIDE); + ShowWindow(WindowHandle, SW_HIDE); return TRUE; } } @@ -1621,22 +1621,31 @@ BOOLEAN PhMwpOnSysCommand( } VOID PhMwpOnMenuCommand( + _In_ HWND WindowHandle, _In_ ULONG Index, _In_ HMENU Menu ) { MENUITEMINFO menuItemInfo; + memset(&menuItemInfo, 0, sizeof(MENUITEMINFO)); menuItemInfo.cbSize = sizeof(MENUITEMINFO); menuItemInfo.fMask = MIIM_ID | MIIM_DATA; if (GetMenuItemInfo(Menu, Index, TRUE, &menuItemInfo)) { - PhMwpDispatchMenuCommand(Menu, Index, menuItemInfo.wID, menuItemInfo.dwItemData); + PhMwpDispatchMenuCommand( + WindowHandle, + Menu, + Index, + menuItemInfo.wID, + menuItemInfo.dwItemData + ); } } VOID PhMwpOnInitMenuPopup( + _In_ HWND WindowHandle, _In_ HMENU Menu, _In_ ULONG Index, _In_ BOOLEAN IsWindowMenu @@ -1699,7 +1708,7 @@ VOID PhMwpOnInitMenuPopup( { PH_PLUGIN_MENU_INFORMATION menuInfo; - PhPluginInitializeMenuInfo(&menuInfo, menu, PhMainWndHandle, PH_PLUGIN_MENU_DISALLOW_HOOKS); + PhPluginInitializeMenuInfo(&menuInfo, menu, WindowHandle, PH_PLUGIN_MENU_DISALLOW_HOOKS); menuInfo.u.MainMenu.SubMenuIndex = Index; PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackMainMenuInitializing), &menuInfo); } @@ -1709,10 +1718,10 @@ VOID PhMwpOnInitMenuPopup( } VOID PhMwpOnSize( - VOID + _In_ HWND WindowHandle ) { - if (!IsMinimized(PhMainWndHandle)) + if (!IsMinimized(WindowHandle)) { HDWP deferHandle; @@ -2050,6 +2059,7 @@ BOOLEAN PhMwpOnNotify( } ULONG_PTR PhMwpOnUserMessage( + _In_ HWND WindowHandle, _In_ ULONG Message, _In_ ULONG_PTR WParam, _In_ ULONG_PTR LParam @@ -2069,14 +2079,14 @@ ULONG_PTR PhMwpOnUserMessage( PhSelectAndEnsureVisibleProcessNode(processNode); } - if (!IsWindowVisible(PhMainWndHandle)) + if (!IsWindowVisible(WindowHandle)) { - ShowWindow(PhMainWndHandle, SW_SHOW); + ShowWindow(WindowHandle, SW_SHOW); } - if (IsMinimized(PhMainWndHandle)) + if (IsMinimized(WindowHandle)) { - ShowWindow(PhMainWndHandle, SW_RESTORE); + ShowWindow(WindowHandle, SW_RESTORE); } return PH_ACTIVATE_REPLY; @@ -2094,7 +2104,7 @@ ULONG_PTR PhMwpOnUserMessage( break; case WM_PH_DESTROY: { - DestroyWindow(PhMainWndHandle); + DestroyWindow(WindowHandle); } break; case WM_PH_SAVE_ALL_SETTINGS: @@ -2125,7 +2135,7 @@ ULONG_PTR PhMwpOnUserMessage( break; case WM_PH_TOGGLE_VISIBLE: { - PhMwpActivateWindow(!WParam); + PhMwpActivateWindow(WindowHandle, !WParam); } break; case WM_PH_SHOW_MEMORY_EDITOR: @@ -2257,7 +2267,7 @@ ULONG_PTR PhMwpOnUserMessage( break; case WM_PH_REFRESH: { - SendMessage(PhMainWndHandle, WM_COMMAND, ID_VIEW_REFRESH, 0); + SendMessage(WindowHandle, WM_COMMAND, ID_VIEW_REFRESH, 0); } break; case WM_PH_GET_UPDATE_AUTOMATICALLY: @@ -2269,13 +2279,13 @@ ULONG_PTR PhMwpOnUserMessage( { if (!!WParam != PhMwpUpdateAutomatically) { - SendMessage(PhMainWndHandle, WM_COMMAND, ID_VIEW_UPDATEAUTOMATICALLY, 0); + SendMessage(WindowHandle, WM_COMMAND, ID_VIEW_UPDATEAUTOMATICALLY, 0); } } break; case WM_PH_ICON_CLICK: { - PhMwpActivateWindow(!!PhGetIntegerSetting(L"IconTogglesVisibility")); + PhMwpActivateWindow(WindowHandle, !!PhGetIntegerSetting(L"IconTogglesVisibility")); } break; } @@ -2452,25 +2462,26 @@ BOOLEAN PhMwpExecuteComputerCommand( } VOID PhMwpActivateWindow( + _In_ HWND WindowHandle, _In_ BOOLEAN Toggle ) { - if (IsMinimized(PhMainWndHandle)) + if (IsMinimized(WindowHandle)) { - ShowWindow(PhMainWndHandle, SW_RESTORE); - SetForegroundWindow(PhMainWndHandle); + ShowWindow(WindowHandle, SW_RESTORE); + SetForegroundWindow(WindowHandle); } - else if (IsWindowVisible(PhMainWndHandle)) + else if (IsWindowVisible(WindowHandle)) { if (Toggle) - ShowWindow(PhMainWndHandle, SW_HIDE); + ShowWindow(WindowHandle, SW_HIDE); else - SetForegroundWindow(PhMainWndHandle); + SetForegroundWindow(WindowHandle); } else { - ShowWindow(PhMainWndHandle, SW_SHOW); - SetForegroundWindow(PhMainWndHandle); + ShowWindow(WindowHandle, SW_SHOW); + SetForegroundWindow(WindowHandle); } } @@ -2495,6 +2506,7 @@ VOID PhMwpInitializeMainMenu( } VOID PhMwpDispatchMenuCommand( + _In_ HWND WindowHandle, _In_ HMENU MenuHandle, _In_ ULONG ItemIndex, _In_ ULONG ItemId, @@ -2622,7 +2634,7 @@ VOID PhMwpDispatchMenuCommand( return; } - SendMessage(PhMainWndHandle, WM_COMMAND, ItemId, 0); + SendMessage(WindowHandle, WM_COMMAND, ItemId, 0); } VOID PhMwpInitializeSubMenu( From d10de4fe87015c5c57516aa93a4ae395670cefa6 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 11 Jul 2019 15:33:31 +0200 Subject: [PATCH 1991/2058] Fix #439 --- plugins/ExtendedServices/depend.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/ExtendedServices/depend.c b/plugins/ExtendedServices/depend.c index 89dd011feeaa..5c2c09ebfaa7 100644 --- a/plugins/ExtendedServices/depend.c +++ b/plugins/ExtendedServices/depend.c @@ -210,8 +210,8 @@ INT_PTR CALLBACK EspServiceDependenciesDlgProc( PhSetDialogItemText(hwndDlg, IDC_SERVICES_LAYOUT, PhaConcatStrings2( L"Unable to enumerate dependencies: ", - PhGetStringOrDefault(errorMessage, L"Unknown error.")) - ); + PhGetStringOrDefault(errorMessage, L"Unknown error.") + )->Buffer); ShowWindow(GetDlgItem(hwndDlg, IDC_SERVICES_LAYOUT), SW_SHOW); PhClearReference(&errorMessage); @@ -330,8 +330,8 @@ INT_PTR CALLBACK EspServiceDependentsDlgProc( PhSetDialogItemText(hwndDlg, IDC_SERVICES_LAYOUT, PhaConcatStrings2( L"Unable to enumerate dependents: ", - PhGetStringOrDefault(errorMessage, L"Unknown error.")) - ); + PhGetStringOrDefault(errorMessage, L"Unknown error.") + )->Buffer); ShowWindow(GetDlgItem(hwndDlg, IDC_SERVICES_LAYOUT), SW_SHOW); PhClearReference(&errorMessage); From ca3e48f6591189e0b3b2695cec5af5afdbcb2a28 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 13 Jul 2019 17:57:14 +0200 Subject: [PATCH 1992/2058] Fix #436 --- ProcessHacker/mainwnd.c | 209 +++++++++++++++++++++------------------- ProcessHacker/runas.c | 23 ++++- 2 files changed, 129 insertions(+), 103 deletions(-) diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index 9071fbaf3932..2653b85d763f 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -25,6 +25,7 @@ #include #include +#include #include #include @@ -1852,13 +1853,16 @@ BOOLEAN PhMwpOnNotify( else if (Header->code == RFN_LIMITEDRUNAS) { LPNMRUNFILEDLG runFileDlg = (LPNMRUNFILEDLG)Header; - NTSTATUS status; + NTSTATUS status = STATUS_UNSUCCESSFUL; ULONG processId = ULONG_MAX; HANDLE processHandle = NULL; HANDLE newProcessHandle; + HANDLE tokenHandle; HWND shellWindow; STARTUPINFOEX startupInfo; - SIZE_T attributeListLength; + SIZE_T attributeListLength = 0; + PVOID environment = NULL; + ULONG flags = 0; memset(&startupInfo, 0, sizeof(STARTUPINFOEX)); startupInfo.StartupInfo.cb = sizeof(STARTUPINFOEX); @@ -1867,7 +1871,92 @@ BOOLEAN PhMwpOnNotify( if (!(shellWindow = GetShellWindow())) { - status = STATUS_UNSUCCESSFUL; + PVOID wdcLibraryHandle; + + if (wdcLibraryHandle = LoadLibrary(L"wdc.dll")) + { + ULONG (WINAPI* WdcRunTaskAsInteractiveUser_I)( + _In_ PCWSTR CommandLine, + _In_ PCWSTR CurrentDirectory, + _In_ ULONG Reserved + ); + + if (WdcRunTaskAsInteractiveUser_I = PhGetDllBaseProcedureAddress(wdcLibraryHandle, "WdcRunTaskAsInteractiveUser", 0)) + { + PH_STRINGREF string; + PPH_STRING commandlineString; + PPH_STRING executeString = NULL; + INT cmdlineArgCount; + PWSTR* cmdlineArgList; + + PhInitializeStringRefLongHint(&string, (PWSTR)runFileDlg->lpszFile); + commandlineString = PhCreateString2(&string); + + // Extract the filename. + if (cmdlineArgList = CommandLineToArgvW(commandlineString->Buffer, &cmdlineArgCount)) + { + PPH_STRING fileName = PhCreateString(cmdlineArgList[0]); + + if (fileName && !PhDoesFileExistsWin32(fileName->Buffer)) + { + PPH_STRING filePathString; + + // The user typed a name without a path so attempt to locate the executable. + if (filePathString = PhSearchFilePath(fileName->Buffer, L".exe")) + PhMoveReference(&fileName, filePathString); + else + PhClearReference(&fileName); + } + + if (fileName) + { + // Escape the filename. + PhMoveReference(&fileName, PhConcatStrings(3, L"\"", fileName->Buffer, L"\"")); + + if (cmdlineArgCount == 2) + { + PPH_STRING fileArgs = PhCreateString(cmdlineArgList[1]); + + // Escape the parameters. + PhMoveReference(&fileArgs, PhConcatStrings(3, L"\"", fileArgs->Buffer, L"\"")); + + // Create the escaped execute string. + PhMoveReference(&executeString, PhConcatStrings(3, fileName->Buffer, L" ", fileArgs->Buffer)); + + // Cleanup. + PhDereferenceObject(fileArgs); + } + else + { + // Create the escaped execute string. + executeString = PhReferenceObject(fileName); + } + + PhDereferenceObject(fileName); + } + + LocalFree(cmdlineArgList); + } + + if (!PhIsNullOrEmptyString(executeString)) + { + if (WdcRunTaskAsInteractiveUser_I(executeString->Buffer, NULL, 0) == 0) + status = STATUS_SUCCESS; + else + status = STATUS_UNSUCCESSFUL; + } + else + { + status = STATUS_UNSUCCESSFUL; + } + + PhClearReference(&executeString); + PhClearReference(&commandlineString); + } + + FreeLibrary(wdcLibraryHandle); + } + goto CleanupExit; } @@ -1908,13 +1997,23 @@ BOOLEAN PhMwpOnNotify( goto CleanupExit; } + if (NT_SUCCESS(PhOpenProcessToken(processHandle, TOKEN_QUERY, &tokenHandle))) + { + if (CreateEnvironmentBlock && CreateEnvironmentBlock(&environment, tokenHandle, FALSE)) + { + flags |= PH_CREATE_PROCESS_UNICODE_ENVIRONMENT; + } + + NtClose(tokenHandle); + } + status = PhCreateProcessWin32Ex( NULL, runFileDlg->lpszFile, - NULL, + environment, NULL, &startupInfo.StartupInfo, - PH_CREATE_PROCESS_SUSPENDED | PH_CREATE_PROCESS_NEW_CONSOLE | PH_CREATE_PROCESS_EXTENDED_STARTUPINFO, + PH_CREATE_PROCESS_SUSPENDED | PH_CREATE_PROCESS_NEW_CONSOLE | PH_CREATE_PROCESS_EXTENDED_STARTUPINFO | flags, NULL, NULL, &newProcessHandle, @@ -1937,6 +2036,11 @@ BOOLEAN PhMwpOnNotify( CleanupExit: + if (environment && DestroyEnvironmentBlock) + { + DestroyEnvironmentBlock(environment); + } + if (startupInfo.lpAttributeList) { DeleteProcThreadAttributeList(startupInfo.lpAttributeList); @@ -1958,101 +2062,6 @@ BOOLEAN PhMwpOnNotify( } return TRUE; - - // TODO: Commented out while testing above code (dmex) - //PVOID WdcLibraryHandle; - //ULONG (WINAPI* WdcRunTaskAsInteractiveUser_I)( - // _In_ PCWSTR CommandLine, - // _In_ PCWSTR CurrentDirectory, - // _In_ ULONG Reserved - // ); - - // dmex: Task Manager uses RFF_OPTRUNAS and RFN_LIMITEDRUNAS to show the 'Create this task with administrative privileges' checkbox - // on the RunFileDlg when the current process is elevated. Task Manager also uses the WdcRunTaskAsInteractiveUser function to launch processes - // as the interactive user from an elevated token. The WdcRunTaskAsInteractiveUser function - // invokes the "\Microsoft\Windows\Task Manager\Interactive" Task Scheduler task for launching the process but - // doesn't return error information and we need to perform some sanity checks before invoking the task. - // Ideally, we should use our own task but for now just re-use the existing task and do what Task Manager does... - - //if (WdcLibraryHandle = LoadLibrary(L"wdc.dll")) - //{ - // if (WdcRunTaskAsInteractiveUser_I = PhGetDllBaseProcedureAddress(WdcLibraryHandle, "WdcRunTaskAsInteractiveUser", 0)) - // { - // PH_STRINGREF string; - // PPH_STRING commandlineString; - // PPH_STRING executeString = NULL; - // INT cmdlineArgCount; - // PWSTR* cmdlineArgList; - // - // PhInitializeStringRefLongHint(&string, (PWSTR)runFileDlg->lpszFile); - // commandlineString = PhCreateString2(&string); - // - // // Extract the filename. - // if (cmdlineArgList = CommandLineToArgvW(commandlineString->Buffer, &cmdlineArgCount)) - // { - // PPH_STRING fileName = PhCreateString(cmdlineArgList[0]); - // - // if (fileName && !PhDoesFileExistsWin32(fileName->Buffer)) - // { - // PPH_STRING filePathString; - // - // // The user typed a name without a path so attempt to locate the executable. - // if (filePathString = PhSearchFilePath(fileName->Buffer, L".exe")) - // PhMoveReference(&fileName, filePathString); - // else - // PhClearReference(&fileName); - // } - // - // if (fileName) - // { - // // Escape the filename. - // PhMoveReference(&fileName, PhConcatStrings(3, L"\"", fileName->Buffer, L"\"")); - // - // if (cmdlineArgCount == 2) - // { - // PPH_STRING fileArgs = PhCreateString(cmdlineArgList[1]); - // - // // Escape the parameters. - // PhMoveReference(&fileArgs, PhConcatStrings(3, L"\"", fileArgs->Buffer, L"\"")); - // - // // Create the escaped execute string. - // PhMoveReference(&executeString, PhConcatStrings(3, fileName->Buffer, L" ", fileArgs->Buffer)); - // - // // Cleanup. - // PhDereferenceObject(fileArgs); - // } - // else - // { - // // Create the escaped execute string. - // executeString = PhReferenceObject(fileName); - // } - // - // PhDereferenceObject(fileName); - // } - // - // LocalFree(cmdlineArgList); - // } - // - // if (!PhIsNullOrEmptyString(executeString)) - // { - // if (WdcRunTaskAsInteractiveUser_I(executeString->Buffer, NULL, 0) == 0) - // *Result = RF_CANCEL; - // else - // *Result = RF_RETRY; - // } - // else - // { - // *Result = RF_RETRY; - // } - // - // if (executeString) - // PhDereferenceObject(executeString); - // PhDereferenceObject(commandlineString); - // } - // - // FreeLibrary(WdcLibraryHandle); - //} - //return TRUE; } return FALSE; diff --git a/ProcessHacker/runas.c b/ProcessHacker/runas.c index ff1954e011a8..eecaa97f4382 100644 --- a/ProcessHacker/runas.c +++ b/ProcessHacker/runas.c @@ -62,6 +62,7 @@ #include #include +#include #include #include @@ -1205,6 +1206,7 @@ INT_PTR CALLBACK PhpRunAsDlgProc( HANDLE newProcessHandle; STARTUPINFOEX startupInfo; SIZE_T attributeListLength = 0; + HANDLE tokenHandle; memset(&startupInfo, 0, sizeof(STARTUPINFOEX)); startupInfo.StartupInfo.cb = sizeof(STARTUPINFOEX); @@ -1240,18 +1242,28 @@ INT_PTR CALLBACK PhpRunAsDlgProc( goto CleanupExit; } + if (NT_SUCCESS(PhOpenProcessToken(processHandle, TOKEN_QUERY, &tokenHandle))) + { + if (CreateEnvironmentBlock && CreateEnvironmentBlock(&environment, tokenHandle, FALSE)) + { + flags |= PH_CREATE_PROCESS_UNICODE_ENVIRONMENT; + } + + NtClose(tokenHandle); + } + status = PhCreateProcessWin32Ex( NULL, PhGetString(program), - NULL, + environment, NULL, &startupInfo.StartupInfo, - PH_CREATE_PROCESS_SUSPENDED | PH_CREATE_PROCESS_NEW_CONSOLE | PH_CREATE_PROCESS_EXTENDED_STARTUPINFO, + PH_CREATE_PROCESS_SUSPENDED | PH_CREATE_PROCESS_NEW_CONSOLE | PH_CREATE_PROCESS_EXTENDED_STARTUPINFO | flags, NULL, NULL, &newProcessHandle, NULL - ); + ); if (NT_SUCCESS(status)) { @@ -1268,6 +1280,11 @@ INT_PTR CALLBACK PhpRunAsDlgProc( CleanupExit: + if (environment && DestroyEnvironmentBlock) + { + DestroyEnvironmentBlock(environment); + } + if (startupInfo.lpAttributeList) { DeleteProcThreadAttributeList(startupInfo.lpAttributeList); From 0d91802e85f589a858888c6c77ff402d143f399f Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 13 Jul 2019 17:57:27 +0200 Subject: [PATCH 1993/2058] Fix build --- ProcessHacker/runas.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ProcessHacker/runas.c b/ProcessHacker/runas.c index eecaa97f4382..b62a2660e717 100644 --- a/ProcessHacker/runas.c +++ b/ProcessHacker/runas.c @@ -1206,7 +1206,9 @@ INT_PTR CALLBACK PhpRunAsDlgProc( HANDLE newProcessHandle; STARTUPINFOEX startupInfo; SIZE_T attributeListLength = 0; + PVOID environment = NULL; HANDLE tokenHandle; + ULONG flags = 0; memset(&startupInfo, 0, sizeof(STARTUPINFOEX)); startupInfo.StartupInfo.cb = sizeof(STARTUPINFOEX); From 10425533054d5bd0ff2f2938a8ed7bf899e773e3 Mon Sep 17 00:00:00 2001 From: Rocco Matano Date: Mon, 15 Jul 2019 05:29:21 +0200 Subject: [PATCH 1994/2058] make RunFileDialog showing 'Run as Administrator' configurable (#440) --- ProcessHacker/mainwnd.c | 7 ++++++- ProcessHacker/settings.c | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index 2653b85d763f..64d3e4a93746 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -605,8 +605,13 @@ VOID PhMwpOnCommand( break; case ID_HACKER_RUN: { + ULONG flags = RFF_OPTRUNAS; + if (PhGetIntegerSetting(L"RunDlgHideRunAsAdministrator")) + { + flags = 0; + } SelectedRunAsMode = 0; - PhShowRunFileDialog(WindowHandle, NULL, NULL, NULL, NULL, RFF_OPTRUNAS); + PhShowRunFileDialog(WindowHandle, NULL, NULL, NULL, NULL, flags); } break; case ID_HACKER_RUNASADMINISTRATOR: diff --git a/ProcessHacker/settings.c b/ProcessHacker/settings.c index c25cdf771ce8..b313e8a42af4 100644 --- a/ProcessHacker/settings.c +++ b/ProcessHacker/settings.c @@ -150,6 +150,7 @@ VOID PhAddDefaultSettings( PhpAddIntegerSetting(L"PropagateCpuUsage", L"0"); PhpAddStringSetting(L"RunAsProgram", L""); PhpAddStringSetting(L"RunAsUserName", L""); + PhpAddIntegerSetting(L"RunDlgHideRunAsAdministrator", L"0"); PhpAddIntegerSetting(L"SampleCount", L"200"); // 512 PhpAddIntegerSetting(L"SampleCountAutomatic", L"1"); PhpAddIntegerSetting(L"ScrollToNewProcesses", L"0"); From f32141d60d35d05ed9a8137544d3df5166af05c0 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 18 Jul 2019 02:52:21 +0200 Subject: [PATCH 1995/2058] Improve GDI handle checks --- ProcessHacker/findobj.c | 2 +- ProcessHacker/miniinfo.c | 10 +-- ProcessHacker/modlist.c | 4 +- ProcessHacker/mwpgnet.c | 2 +- ProcessHacker/mwpgproc.c | 2 +- ProcessHacker/mwpgsrv.c | 2 +- ProcessHacker/notifico.c | 34 ++++---- ProcessHacker/options.c | 22 ++--- ProcessHacker/plugman.c | 8 +- ProcessHacker/proctree.c | 6 +- ProcessHacker/searchbox.c | 40 +++++---- ProcessHacker/sysinfo.c | 40 ++++----- ProcessHacker/syssccpu.c | 10 +-- ProcessHacker/sysscio.c | 2 +- ProcessHacker/sysscmem.c | 4 +- phlib/colorbox.c | 4 +- phlib/emenu.c | 4 +- phlib/extlv.c | 2 +- phlib/graph.c | 34 ++++---- phlib/guisup.c | 4 +- phlib/hexedit.c | 14 ++-- phlib/icotobmp.c | 10 +-- phlib/theme.c | 122 ++++++++++++++-------------- phlib/treenew.c | 86 ++++++++++---------- plugins/ExtendedTools/disktab.c | 2 +- plugins/ExtendedTools/etwprprp.c | 4 +- plugins/ExtendedTools/etwsys.c | 4 +- plugins/ExtendedTools/gpunodes.c | 2 +- plugins/ExtendedTools/gpuprprp.c | 8 +- plugins/ExtendedTools/gpusys.c | 4 +- plugins/ExtendedTools/iconext.c | 12 +-- plugins/HardwareDevices/diskgraph.c | 4 +- plugins/HardwareDevices/netgraph.c | 2 +- plugins/NetworkTools/country.c | 14 ++-- plugins/NetworkTools/ping.c | 4 +- plugins/NetworkTools/tracert.c | 2 +- plugins/ToolStatus/customizesb.c | 6 +- plugins/ToolStatus/customizetb.c | 18 ++-- plugins/ToolStatus/main.c | 2 +- plugins/ToolStatus/statusbar.c | 2 +- plugins/ToolStatus/toolbar.c | 9 +- plugins/WindowExplorer/utils.c | 10 +-- plugins/include/commonutil.h | 4 +- 43 files changed, 285 insertions(+), 296 deletions(-) diff --git a/ProcessHacker/findobj.c b/ProcessHacker/findobj.c index e47529edff1f..b3570f40789d 100644 --- a/ProcessHacker/findobj.c +++ b/ProcessHacker/findobj.c @@ -660,7 +660,7 @@ VOID PhpPopulateObjectTypes( maxLength = 0; comboDc = GetDC(FilterTypeCombo); - SendMessage(FilterTypeCombo, WM_SETFONT, (WPARAM)PhApplicationFont, TRUE); + SetWindowFont(FilterTypeCombo, PhApplicationFont, TRUE); for (ULONG i = 0; i < objectTypeList->Count; i++) { diff --git a/ProcessHacker/miniinfo.c b/ProcessHacker/miniinfo.c index 4a3922bb0319..18f8e86b8fe9 100644 --- a/ProcessHacker/miniinfo.c +++ b/ProcessHacker/miniinfo.c @@ -486,7 +486,7 @@ VOID PhMipOnShowWindow( SectionList = PhCreateList(8); PhMipInitializeParameters(); - SendMessage(GetDlgItem(PhMipWindow, IDC_SECTION), WM_SETFONT, (WPARAM)CurrentParameters.MediumFont, FALSE); + SetWindowFont(GetDlgItem(PhMipWindow, IDC_SECTION), CurrentParameters.MediumFont, FALSE); PhMipCreateInternalListSection(L"CPU", 0, PhMipCpuListSectionCallback); PhMipCreateInternalListSection(L"Commit charge", 0, PhMipCommitListSectionCallback); @@ -783,19 +783,19 @@ VOID PhMipInitializeParameters( logFont.lfHeight -= PhMultiplyDivide(2, PhGlobalDpi, 72); CurrentParameters.MediumFont = CreateFontIndirect(&logFont); - originalFont = SelectObject(hdc, CurrentParameters.Font); + originalFont = SelectFont(hdc, CurrentParameters.Font); GetTextMetrics(hdc, &textMetrics); CurrentParameters.FontHeight = textMetrics.tmHeight; CurrentParameters.FontAverageWidth = textMetrics.tmAveCharWidth; - SelectObject(hdc, CurrentParameters.MediumFont); + SelectFont(hdc, CurrentParameters.MediumFont); GetTextMetrics(hdc, &textMetrics); CurrentParameters.MediumFontHeight = textMetrics.tmHeight; CurrentParameters.MediumFontAverageWidth = textMetrics.tmAveCharWidth; CurrentParameters.SetSectionText = PhMipSetSectionText; - SelectObject(hdc, originalFont); + SelectFont(hdc, originalFont); ReleaseDC(PhMipWindow, hdc); } @@ -1540,7 +1540,7 @@ BOOLEAN PhMipListSectionTreeNewCallback( 0, NULL, DI_NORMAL); rect.left += (MIP_CELL_PADDING - MIP_ICON_PADDING) + PhLargeIconSize.X + MIP_CELL_PADDING; rect.top += MIP_CELL_PADDING - MIP_ICON_PADDING; - SelectObject(hdc, CurrentParameters.Font); + SelectFont(hdc, CurrentParameters.Font); // This color changes depending on whether the node is selected, etc. originalTextColor = GetTextColor(hdc); diff --git a/ProcessHacker/modlist.c b/ProcessHacker/modlist.c index 4f3af9019d44..21e82fd4731a 100644 --- a/ProcessHacker/modlist.c +++ b/ProcessHacker/modlist.c @@ -136,7 +136,7 @@ VOID PhDeleteModuleList( PhDeleteTreeNewFilterSupport(&Context->TreeFilterSupport); if (Context->BoldFont) - DeleteObject(Context->BoldFont); + DeleteFont(Context->BoldFont); PhCmDeleteManager(&Context->Cm); @@ -1021,7 +1021,7 @@ BOOLEAN NTAPI PhpModuleTreeNewCallback( if (node->ModuleItem->IsFirst) { if (!context->BoldFont) - context->BoldFont = PhDuplicateFontWithNewWeight((HFONT)SendMessage(hwnd, WM_GETFONT, 0, 0), FW_BOLD); + context->BoldFont = PhDuplicateFontWithNewWeight(GetWindowFont(hwnd), FW_BOLD); getNodeFont->Font = context->BoldFont ? context->BoldFont : NULL; getNodeFont->Flags = TN_CACHE; diff --git a/ProcessHacker/mwpgnet.c b/ProcessHacker/mwpgnet.c index 39b83291875c..2bbdc0504c26 100644 --- a/ProcessHacker/mwpgnet.c +++ b/ProcessHacker/mwpgnet.c @@ -155,7 +155,7 @@ BOOLEAN PhMwpNetworkPageCallback( { HFONT font = (HFONT)Parameter1; - SendMessage(PhMwpNetworkTreeNewHandle, WM_SETFONT, (WPARAM)font, TRUE); + SetWindowFont(PhMwpNetworkTreeNewHandle, font, TRUE); } break; case MainTabPageUpdateAutomaticallyChanged: diff --git a/ProcessHacker/mwpgproc.c b/ProcessHacker/mwpgproc.c index ca4f6e84fed5..57a482bfa05f 100644 --- a/ProcessHacker/mwpgproc.c +++ b/ProcessHacker/mwpgproc.c @@ -197,7 +197,7 @@ BOOLEAN PhMwpProcessesPageCallback( { HFONT font = (HFONT)Parameter1; - SendMessage(PhMwpProcessTreeNewHandle, WM_SETFONT, (WPARAM)font, TRUE); + SetWindowFont(PhMwpProcessTreeNewHandle, font, TRUE); } break; case MainTabPageUpdateAutomaticallyChanged: diff --git a/ProcessHacker/mwpgsrv.c b/ProcessHacker/mwpgsrv.c index c7bce8c46e44..ac9b464dcb14 100644 --- a/ProcessHacker/mwpgsrv.c +++ b/ProcessHacker/mwpgsrv.c @@ -138,7 +138,7 @@ BOOLEAN PhMwpServicesPageCallback( { HFONT font = (HFONT)Parameter1; - SendMessage(PhMwpServiceTreeNewHandle, WM_SETFONT, (WPARAM)font, TRUE); + SetWindowFont(PhMwpServiceTreeNewHandle, font, TRUE); } break; case MainTabPageUpdateAutomaticallyChanged: diff --git a/ProcessHacker/notifico.c b/ProcessHacker/notifico.c index 2259f28d3dfb..eed27493604a 100644 --- a/ProcessHacker/notifico.c +++ b/ProcessHacker/notifico.c @@ -650,7 +650,7 @@ HICON PhNfpGetBlackIcon( iconInfo.hbmColor = PhNfpBlackBitmap; PhNfpBlackIcon = CreateIconIndirect(&iconInfo); - SelectObject(hdc, oldBitmap); + SelectBitmap(hdc, oldBitmap); } return PhNfpBlackIcon; @@ -897,7 +897,7 @@ VOID PhNfpBeginBitmap2( *Bitmap = Context->Bitmap; if (Bits) *Bits = Context->Bits; *Hdc = Context->Hdc; - *OldBitmap = SelectObject(Context->Hdc, Context->Bitmap); + *OldBitmap = SelectBitmap(Context->Hdc, Context->Bitmap); } VOID PhNfpCpuHistoryIconUpdateCallback( @@ -957,7 +957,7 @@ VOID PhNfpCpuHistoryIconUpdateCallback( if (bits) PhDrawGraphDirect(hdc, bits, &drawInfo); - SelectObject(hdc, oldBitmap); + SelectBitmap(hdc, oldBitmap); *NewIconOrBitmap = bitmap; *Flags = PH_NF_UPDATE_IS_BITMAP; @@ -1066,7 +1066,7 @@ VOID PhNfpIoHistoryIconUpdateCallback( if (bits) PhDrawGraphDirect(hdc, bits, &drawInfo); - SelectObject(hdc, oldBitmap); + SelectBitmap(hdc, oldBitmap); *NewIconOrBitmap = bitmap; *Flags = PH_NF_UPDATE_IS_BITMAP; @@ -1157,7 +1157,7 @@ VOID PhNfpCommitHistoryIconUpdateCallback( if (bits) PhDrawGraphDirect(hdc, bits, &drawInfo); - SelectObject(hdc, oldBitmap); + SelectBitmap(hdc, oldBitmap); *NewIconOrBitmap = bitmap; *Flags = PH_NF_UPDATE_IS_BITMAP; @@ -1232,7 +1232,7 @@ VOID PhNfpPhysicalHistoryIconUpdateCallback( if (bits) PhDrawGraphDirect(hdc, bits, &drawInfo); - SelectObject(hdc, oldBitmap); + SelectBitmap(hdc, oldBitmap); *NewIconOrBitmap = bitmap; *Flags = PH_NF_UPDATE_IS_BITMAP; @@ -1285,11 +1285,11 @@ VOID PhNfpCpuUsageIconUpdateCallback( LONG ul = (LONG)(u * height); RECT rect; HBRUSH dcBrush; - HBRUSH dcPen; + HPEN dcPen; POINT points[2]; - dcBrush = GetStockObject(DC_BRUSH); - dcPen = GetStockObject(DC_PEN); + dcBrush = GetStockBrush(DC_BRUSH); + dcPen = GetStockPen(DC_PEN); rect.left = 0; rect.top = 0; rect.right = width; @@ -1300,7 +1300,7 @@ VOID PhNfpCpuUsageIconUpdateCallback( // Draw the base line. if (kl + ul == 0) { - SelectObject(hdc, dcPen); + SelectPen(hdc, dcPen); SetDCPenColor(hdc, uColor); points[0].x = 0; points[0].y = height - 1; @@ -1322,7 +1322,7 @@ VOID PhNfpCpuUsageIconUpdateCallback( if (points[0].y < 0) points[0].y = 0; points[1].x = width; points[1].y = points[0].y; - SelectObject(hdc, dcPen); + SelectPen(hdc, dcPen); SetDCPenColor(hdc, uColor); Polyline(hdc, points, 2); @@ -1340,14 +1340,14 @@ VOID PhNfpCpuUsageIconUpdateCallback( if (points[0].y < 0) points[0].y = 0; points[1].x = width; points[1].y = points[0].y; - SelectObject(hdc, dcPen); + SelectPen(hdc, dcPen); SetDCPenColor(hdc, kColor); Polyline(hdc, points, 2); } } } - SelectObject(hdc, oldBitmap); + SelectBitmap(hdc, oldBitmap); *NewIconOrBitmap = bitmap; *Flags = PH_NF_UPDATE_IS_BITMAP; @@ -1422,7 +1422,7 @@ VOID PhNfpCpuUsageTextIconUpdateCallback( PhDrawTrayIconText(hdc, bits, &drawInfo, &text->sr); PhDereferenceObject(text); - SelectObject(hdc, oldBitmap); + SelectBitmap(hdc, oldBitmap); *NewIconOrBitmap = bitmap; *Flags = PH_NF_UPDATE_IS_BITMAP; @@ -1500,7 +1500,7 @@ VOID PhNfpIoUsageTextIconUpdateCallback( PhDrawTrayIconText(hdc, bits, &drawInfo, &text->sr); PhDereferenceObject(text); - SelectObject(hdc, oldBitmap); + SelectBitmap(hdc, oldBitmap); *NewIconOrBitmap = bitmap; *Flags = PH_NF_UPDATE_IS_BITMAP; @@ -1575,7 +1575,7 @@ VOID PhNfpCommitTextIconUpdateCallback( PhDrawTrayIconText(hdc, bits, &drawInfo, &text->sr); PhDereferenceObject(text); - SelectObject(hdc, oldBitmap); + SelectBitmap(hdc, oldBitmap); *NewIconOrBitmap = bitmap; *Flags = PH_NF_UPDATE_IS_BITMAP; @@ -1638,7 +1638,7 @@ VOID PhNfpPhysicalUsageTextIconUpdateCallback( PhDrawTrayIconText(hdc, bits, &drawInfo, &text->sr); PhDereferenceObject(text); - SelectObject(hdc, oldBitmap); + SelectBitmap(hdc, oldBitmap); *NewIconOrBitmap = bitmap; *Flags = PH_NF_UPDATE_IS_BITMAP; diff --git a/ProcessHacker/options.c b/ProcessHacker/options.c index 8f6aaf890948..07e6b008c195 100644 --- a/ProcessHacker/options.c +++ b/ProcessHacker/options.c @@ -442,7 +442,7 @@ INT_PTR CALLBACK PhOptionsDialogProc( case 1: // Old colors { SetDCBrushColor(drawInfo->hDC, RGB(0, 0, 0)); - FillRect(drawInfo->hDC, &rect, GetStockObject(DC_BRUSH)); + FillRect(drawInfo->hDC, &rect, GetStockBrush(DC_BRUSH)); } break; } @@ -1268,9 +1268,9 @@ INT_PTR CALLBACK PhpOptionsGeneralDlgProc( if (CurrentFontInstance) { - SendMessage(OptionsTreeControl, WM_SETFONT, (WPARAM)CurrentFontInstance, TRUE); // HACK - SendMessage(listviewHandle, WM_SETFONT, (WPARAM)CurrentFontInstance, TRUE); - SendMessage(GetDlgItem(hwndDlg, IDC_FONT), WM_SETFONT, (WPARAM)CurrentFontInstance, TRUE); + SetWindowFont(OptionsTreeControl, CurrentFontInstance, TRUE); // HACK + SetWindowFont(listviewHandle, CurrentFontInstance, TRUE); + SetWindowFont(GetDlgItem(hwndDlg, IDC_FONT), CurrentFontInstance, TRUE); } } @@ -1291,7 +1291,7 @@ INT_PTR CALLBACK PhpOptionsGeneralDlgProc( PhpAdvancedPageSave(hwndDlg); if (CurrentFontInstance) - DeleteObject(CurrentFontInstance); + DeleteFont(CurrentFontInstance); if (GeneralListviewImageList) ImageList_Destroy(GeneralListviewImageList); @@ -1333,13 +1333,13 @@ INT_PTR CALLBACK PhpOptionsGeneralDlgProc( // Update the button's font. if (CurrentFontInstance) - DeleteObject(CurrentFontInstance); + DeleteFont(CurrentFontInstance); CurrentFontInstance = CreateFontIndirect(&font); - SendMessage(OptionsTreeControl, WM_SETFONT, (WPARAM)CurrentFontInstance, TRUE); // HACK - SendMessage(GetDlgItem(hwndDlg, IDC_SETTINGS), WM_SETFONT, (WPARAM)CurrentFontInstance, TRUE); - SendMessage(GetDlgItem(hwndDlg, IDC_FONT), WM_SETFONT, (WPARAM)CurrentFontInstance, TRUE); + SetWindowFont(OptionsTreeControl, CurrentFontInstance, TRUE); // HACK + SetWindowFont(GetDlgItem(hwndDlg, IDC_SETTINGS), CurrentFontInstance, TRUE); + SetWindowFont(GetDlgItem(hwndDlg, IDC_FONT), CurrentFontInstance, TRUE); RestartRequired = TRUE; // HACK: Fix ToolStatus plugin toolbar resize on font change } } @@ -1485,13 +1485,13 @@ INT_PTR CALLBACK PhpOptionsGeneralDlgProc( // if (GetDlgCtrlID(control) == IDC_DEFSTATE) // { // if (!BoldFont) - // BoldFont = PhDuplicateFontWithNewWeight((HFONT)SendMessage(control, WM_GETFONT, 0, 0), FW_BOLD); + // BoldFont = PhDuplicateFontWithNewWeight(GetWindowFont(control), FW_BOLD); // // SetBkMode(hdc, TRANSPARENT); // // if (!PhpIsDefaultTaskManager()) // { - // SelectObject(hdc, BoldFont); + // SelectFont(hdc, BoldFont); // } // } // } diff --git a/ProcessHacker/plugman.c b/ProcessHacker/plugman.c index f20752c6ef54..665ed05c5a29 100644 --- a/ProcessHacker/plugman.c +++ b/ProcessHacker/plugman.c @@ -441,14 +441,14 @@ BOOLEAN NTAPI PluginsTreeNewCallback( // top SetTextColor(customDraw->Dc, RGB(0x0, 0x0, 0x0)); - SelectObject(customDraw->Dc, context->TitleFontHandle); + SelectFont(customDraw->Dc, context->TitleFontHandle); text = PhIsNullOrEmptyString(node->Name) ? PhGetStringRef(node->InternalName) : PhGetStringRef(node->Name); GetTextExtentPoint32(customDraw->Dc, text.Buffer, (ULONG)text.Length / sizeof(WCHAR), &nameSize); DrawText(customDraw->Dc, text.Buffer, (ULONG)text.Length / sizeof(WCHAR), &rect, DT_TOP | DT_LEFT | DT_END_ELLIPSIS | DT_SINGLELINE); // bottom SetTextColor(customDraw->Dc, RGB(0x64, 0x64, 0x64)); - SelectObject(customDraw->Dc, context->NormalFontHandle); + SelectFont(customDraw->Dc, context->NormalFontHandle); text = PhGetStringRef(node->Description); GetTextExtentPoint32(customDraw->Dc, text.Buffer, (ULONG)text.Length / sizeof(WCHAR), &textSize); DrawText( @@ -558,9 +558,9 @@ VOID DeletePluginsTree( ) { if (Context->TitleFontHandle) - DeleteObject(Context->TitleFontHandle); + DeleteFont(Context->TitleFontHandle); if (Context->NormalFontHandle) - DeleteObject(Context->NormalFontHandle); + DeleteFont(Context->NormalFontHandle); PluginsSaveSettingsTreeList(Context); diff --git a/ProcessHacker/proctree.c b/ProcessHacker/proctree.c index 926573e769d5..82f6501e23cc 100644 --- a/ProcessHacker/proctree.c +++ b/ProcessHacker/proctree.c @@ -701,8 +701,8 @@ static VOID PhpNeedGraphContext( { // The original bitmap must be selected back into the context, otherwise // the bitmap can't be deleted. - SelectObject(GraphContext, GraphBitmap); - DeleteObject(GraphBitmap); + SelectBitmap(GraphContext, GraphBitmap); + DeleteBitmap(GraphBitmap); DeleteDC(GraphContext); GraphContext = NULL; @@ -719,7 +719,7 @@ static VOID PhpNeedGraphContext( header.biPlanes = 1; header.biBitCount = 32; GraphBitmap = CreateDIBSection(hdc, (BITMAPINFO *)&header, DIB_RGB_COLORS, &GraphBits, NULL, 0); - GraphOldBitmap = SelectObject(GraphContext, GraphBitmap); + GraphOldBitmap = SelectBitmap(GraphContext, GraphBitmap); } static BOOLEAN PhpFormatInt32GroupDigits( diff --git a/ProcessHacker/searchbox.c b/ProcessHacker/searchbox.c index 686d4920d371..8dd22570470f 100644 --- a/ProcessHacker/searchbox.c +++ b/ProcessHacker/searchbox.c @@ -66,13 +66,11 @@ VOID PhpSearchFreeTheme( ) { if (Context->BrushNormal) - DeleteObject(Context->BrushNormal); - + DeleteBrush(Context->BrushNormal); if (Context->BrushHot) - DeleteObject(Context->BrushHot); - + DeleteBrush(Context->BrushHot); if (Context->BrushPushed) - DeleteObject(Context->BrushPushed); + DeleteBrush(Context->BrushPushed); } VOID PhpSearchInitializeFont( @@ -80,7 +78,7 @@ VOID PhpSearchInitializeFont( ) { if (Context->WindowFont) - DeleteObject(Context->WindowFont); + DeleteFont(Context->WindowFont); Context->WindowFont = PhCreateCommonFont(10, FW_MEDIUM, Context->WindowHandle); } @@ -147,7 +145,7 @@ VOID PhpSearchInitializeImages( if (bitmap = PhLoadPngImageFromResource(PhInstanceHandle, Context->ImageWidth, Context->ImageHeight, MAKEINTRESOURCE(IDB_SEARCH_ACTIVE), TRUE)) { ImageList_Replace(Context->ImageListHandle, 0, bitmap, NULL); - DeleteObject(bitmap); + DeleteBitmap(bitmap); } else { @@ -157,7 +155,7 @@ VOID PhpSearchInitializeImages( if (bitmap = PhLoadPngImageFromResource(PhInstanceHandle, Context->ImageWidth, Context->ImageHeight, MAKEINTRESOURCE(IDB_SEARCH_INACTIVE), TRUE)) { ImageList_Replace(Context->ImageListHandle, 1, bitmap, NULL); - DeleteObject(bitmap); + DeleteBitmap(bitmap); } else { @@ -198,7 +196,7 @@ VOID PhpSearchDrawButton( bufferDc = CreateCompatibleDC(hdc); bufferBitmap = CreateCompatibleBitmap(hdc, bufferRect.right, bufferRect.bottom); - oldBufferBitmap = SelectObject(bufferDc, bufferBitmap); + oldBufferBitmap = SelectBitmap(bufferDc, bufferBitmap); if (Context->Pushed) { @@ -212,7 +210,7 @@ VOID PhpSearchDrawButton( case 1: // Old colors SetTextColor(bufferDc, GetSysColor(COLOR_HIGHLIGHTTEXT)); SetDCBrushColor(bufferDc, RGB(99, 99, 99)); - FillRect(bufferDc, &bufferRect, GetStockObject(DC_BRUSH)); + FillRect(bufferDc, &bufferRect, GetStockBrush(DC_BRUSH)); break; } } @@ -234,7 +232,7 @@ VOID PhpSearchDrawButton( case 1: // Old colors SetTextColor(bufferDc, GetSysColor(COLOR_HIGHLIGHTTEXT)); SetDCBrushColor(bufferDc, RGB(78, 78, 78)); - FillRect(bufferDc, &bufferRect, GetStockObject(DC_BRUSH)); + FillRect(bufferDc, &bufferRect, GetStockBrush(DC_BRUSH)); break; } } @@ -256,7 +254,7 @@ VOID PhpSearchDrawButton( case 1: // Old colors SetTextColor(bufferDc, GetSysColor(COLOR_HIGHLIGHTTEXT)); SetDCBrushColor(bufferDc, RGB(60, 60, 60)); - FillRect(bufferDc, &bufferRect, GetStockObject(DC_BRUSH)); + FillRect(bufferDc, &bufferRect, GetStockBrush(DC_BRUSH)); break; } @@ -291,8 +289,8 @@ VOID PhpSearchDrawButton( } BitBlt(hdc, ButtonRect.left, ButtonRect.top, ButtonRect.right, ButtonRect.bottom, bufferDc, 0, 0, SRCCOPY); - SelectObject(bufferDc, oldBufferBitmap); - DeleteObject(bufferBitmap); + SelectBitmap(bufferDc, oldBufferBitmap); + DeleteBitmap(bufferBitmap); DeleteDC(bufferDc); if (Context->ThemeSupport) // HACK @@ -309,7 +307,7 @@ VOID PhpSearchDrawButton( break; } - SelectObject(hdc, GetStockObject(DC_BRUSH)); + SelectBrush(hdc, GetStockBrush(DC_BRUSH)); PatBlt(hdc, WindowRect.left, WindowRect.top, 1, WindowRect.bottom - WindowRect.top, PATCOPY); PatBlt(hdc, WindowRect.right - 1, WindowRect.top, 1, WindowRect.bottom - WindowRect.top, PATCOPY); PatBlt(hdc, WindowRect.left, WindowRect.top, WindowRect.right - WindowRect.left, 1, PATCOPY); @@ -325,7 +323,7 @@ VOID PhpSearchDrawButton( break; } - SelectObject(hdc, GetStockObject(DC_BRUSH)); + SelectBrush(hdc, GetStockBrush(DC_BRUSH)); PatBlt(hdc, WindowRect.left + 1, WindowRect.top + 1, 1, WindowRect.bottom - WindowRect.top - 2, PATCOPY); PatBlt(hdc, WindowRect.right - 2, WindowRect.top + 1, 1, WindowRect.bottom - WindowRect.top - 2, PATCOPY); PatBlt(hdc, WindowRect.left + 1, WindowRect.top + 1, WindowRect.right - WindowRect.left - 2, 1, PATCOPY); @@ -343,7 +341,7 @@ VOID PhpSearchDrawButton( break; } - SelectObject(hdc, GetStockObject(DC_BRUSH)); + SelectBrush(hdc, GetStockBrush(DC_BRUSH)); PatBlt(hdc, WindowRect.left, WindowRect.top, 1, WindowRect.bottom - WindowRect.top, PATCOPY); PatBlt(hdc, WindowRect.right - 1, WindowRect.top, 1, WindowRect.bottom - WindowRect.top, PATCOPY); PatBlt(hdc, WindowRect.left, WindowRect.top, WindowRect.right - WindowRect.left, 1, PATCOPY); @@ -359,7 +357,7 @@ VOID PhpSearchDrawButton( break; } - SelectObject(hdc, GetStockObject(DC_BRUSH)); + SelectBrush(hdc, GetStockBrush(DC_BRUSH)); PatBlt(hdc, WindowRect.left + 1, WindowRect.top + 1, 1, WindowRect.bottom - WindowRect.top - 2, PATCOPY); PatBlt(hdc, WindowRect.right - 2, WindowRect.top + 1, 1, WindowRect.bottom - WindowRect.top - 2, PATCOPY); PatBlt(hdc, WindowRect.left + 1, WindowRect.top + 1, WindowRect.right - WindowRect.left - 2, 1, PATCOPY); @@ -393,7 +391,7 @@ LRESULT CALLBACK PhpSearchWndSubclassProc( if (context->WindowFont) { - DeleteObject(context->WindowFont); + DeleteFont(context->WindowFont); context->WindowFont = NULL; } @@ -643,7 +641,7 @@ HICON PhpSearchBitmapToIcon( icon = CreateIconIndirect(&iconInfo); - DeleteObject(screenBitmap); + DeleteBitmap(screenBitmap); ReleaseDC(NULL, screenDc); return icon; @@ -827,6 +825,6 @@ HBITMAP PhLoadPngImageFromResource( if (success) return bitmapHandle; - DeleteObject(bitmapHandle); + DeleteBitmap(bitmapHandle); return NULL; } diff --git a/ProcessHacker/sysinfo.c b/ProcessHacker/sysinfo.c index d54404dec66d..91afaab549db 100644 --- a/ProcessHacker/sysinfo.c +++ b/ProcessHacker/sysinfo.c @@ -269,7 +269,7 @@ INT_PTR CALLBACK PhSipSysInfoDialogProc( break; } - return (INT_PTR)GetStockObject(DC_BRUSH); + return (INT_PTR)GetStockBrush(DC_BRUSH); } break; } @@ -317,7 +317,7 @@ INT_PTR CALLBACK PhSipContainerDialogProc( SetDCBrushColor((HDC)wParam, GetSysColor(COLOR_WINDOW)); } - return (INT_PTR)GetStockObject(DC_BRUSH); + return (INT_PTR)GetStockBrush(DC_BRUSH); } break; } @@ -1058,17 +1058,17 @@ VOID PhSipInitializeParameters( CurrentParameters.ColorSetupFunction = PhSiSetColorsGraphDrawInfo; - originalFont = SelectObject(hdc, CurrentParameters.Font); + originalFont = SelectFont(hdc, CurrentParameters.Font); GetTextMetrics(hdc, &textMetrics); CurrentParameters.FontHeight = textMetrics.tmHeight; CurrentParameters.FontAverageWidth = textMetrics.tmAveCharWidth; - SelectObject(hdc, CurrentParameters.MediumFont); + SelectFont(hdc, CurrentParameters.MediumFont); GetTextMetrics(hdc, &textMetrics); CurrentParameters.MediumFontHeight = textMetrics.tmHeight; CurrentParameters.MediumFontAverageWidth = textMetrics.tmAveCharWidth; - SelectObject(hdc, originalFont); + SelectFont(hdc, originalFont); // Internal padding and other values CurrentParameters.PanelPadding = PH_SCALE_DPI(PH_SYSINFO_PANEL_PADDING); @@ -1105,11 +1105,11 @@ VOID PhSipDeleteParameters( ) { if (CurrentParameters.Font) - DeleteObject(CurrentParameters.Font); + DeleteFont(CurrentParameters.Font); if (CurrentParameters.MediumFont) - DeleteObject(CurrentParameters.MediumFont); + DeleteFont(CurrentParameters.MediumFont); if (CurrentParameters.LargeFont) - DeleteObject(CurrentParameters.LargeFont); + DeleteFont(CurrentParameters.LargeFont); } VOID PhSipUpdateColorParameters( @@ -1260,7 +1260,7 @@ VOID PhSipDrawRestoreSummaryPanel( bufferDc = CreateCompatibleDC(hdc); bufferBitmap = CreateCompatibleBitmap(hdc, bufferRect.right, bufferRect.bottom); - oldBufferBitmap = SelectObject(bufferDc, bufferBitmap); + oldBufferBitmap = SelectBitmap(bufferDc, bufferBitmap); SetBkMode(bufferDc, TRANSPARENT); @@ -1275,7 +1275,7 @@ VOID PhSipDrawRestoreSummaryPanel( case 1: // Old colors SetTextColor(bufferDc, CurrentParameters.PanelForeColor); SetDCBrushColor(bufferDc, RGB(30, 30, 30)); - FillRect(bufferDc, &bufferRect, GetStockObject(DC_BRUSH)); + FillRect(bufferDc, &bufferRect, GetStockBrush(DC_BRUSH)); break; } } @@ -1304,7 +1304,7 @@ VOID PhSipDrawRestoreSummaryPanel( } } - SelectObject(bufferDc, CurrentParameters.MediumFont); + SelectFont(bufferDc, CurrentParameters.MediumFont); DrawText(bufferDc, L"Back", 4, &bufferRect, DT_CENTER | DT_VCENTER | DT_SINGLELINE); BitBlt( @@ -1319,8 +1319,8 @@ VOID PhSipDrawRestoreSummaryPanel( SRCCOPY ); - SelectObject(bufferDc, oldBufferBitmap); - DeleteObject(bufferBitmap); + SelectBitmap(bufferDc, oldBufferBitmap); + DeleteBitmap(bufferBitmap); DeleteDC(bufferDc); ReleaseDC(DrawItemStruct->hwndItem, hdc); @@ -1346,7 +1346,7 @@ VOID PhSipDrawSeparator( bufferDc = CreateCompatibleDC(hdc); bufferBitmap = CreateCompatibleBitmap(hdc, bufferRect.right, bufferRect.bottom); - oldBufferBitmap = SelectObject(bufferDc, bufferBitmap); + oldBufferBitmap = SelectBitmap(bufferDc, bufferBitmap); SetBkMode(bufferDc, TRANSPARENT); @@ -1365,7 +1365,7 @@ VOID PhSipDrawSeparator( case 1: // Old colors { SetDCBrushColor(bufferDc, RGB(0, 0, 0)); - FillRect(bufferDc, &bufferRect, GetStockObject(DC_BRUSH)); + FillRect(bufferDc, &bufferRect, GetStockBrush(DC_BRUSH)); } break; } @@ -1390,8 +1390,8 @@ VOID PhSipDrawSeparator( SRCCOPY ); - SelectObject(bufferDc, oldBufferBitmap); - DeleteObject(bufferBitmap); + SelectBitmap(bufferDc, oldBufferBitmap); + DeleteBitmap(bufferBitmap); DeleteDC(bufferDc); ReleaseDC(DrawItemStruct->hwndItem, hdc); @@ -1416,7 +1416,7 @@ VOID PhSipDrawPanel( break; case 1: // Old colors SetDCBrushColor(hdc, RGB(30, 30, 30)); - FillRect(hdc, Rect, GetStockObject(DC_BRUSH)); + FillRect(hdc, Rect, GetStockBrush(DC_BRUSH)); break; } } @@ -1574,7 +1574,7 @@ VOID PhSipDefaultDrawPanel( if (DrawPanel->Title) { - SelectObject(hdc, CurrentParameters.MediumFont); + SelectFont(hdc, CurrentParameters.MediumFont); DrawText(hdc, DrawPanel->Title->Buffer, (ULONG)DrawPanel->Title->Length / sizeof(WCHAR), &rect, flags | DT_SINGLELINE); } @@ -1592,7 +1592,7 @@ VOID PhSipDefaultDrawPanel( rect.top += CurrentParameters.MediumFontHeight + CurrentParameters.PanelPadding; measureRect = rect; - SelectObject(hdc, CurrentParameters.Font); + SelectFont(hdc, CurrentParameters.Font); GetTextExtentPoint32(hdc, DrawPanel->SubTitle->Buffer, (ULONG)DrawPanel->SubTitle->Length / sizeof(WCHAR), &textSize); DrawText(hdc, DrawPanel->SubTitle->Buffer, (ULONG)DrawPanel->SubTitle->Length / sizeof(WCHAR), &measureRect, flags | DT_CALCRECT); diff --git a/ProcessHacker/syssccpu.c b/ProcessHacker/syssccpu.c index 479b5b72c012..2a78c5d6fb04 100644 --- a/ProcessHacker/syssccpu.c +++ b/ProcessHacker/syssccpu.c @@ -279,8 +279,8 @@ INT_PTR CALLBACK PhSipCpuDialogProc( CpuGraphMargin = graphItem->Margin; panelItem = PhAddLayoutItem(&CpuLayoutManager, GetDlgItem(hwndDlg, IDC_LAYOUT), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); - SendMessage(GetDlgItem(hwndDlg, IDC_TITLE), WM_SETFONT, (WPARAM)CpuSection->Parameters->LargeFont, FALSE); - SendMessage(GetDlgItem(hwndDlg, IDC_CPUNAME), WM_SETFONT, (WPARAM)CpuSection->Parameters->MediumFont, FALSE); + SetWindowFont(GetDlgItem(hwndDlg, IDC_TITLE), CpuSection->Parameters->LargeFont, FALSE); + SetWindowFont(GetDlgItem(hwndDlg, IDC_CPUNAME), CpuSection->Parameters->MediumFont, FALSE); PhSipGetCpuBrandString(brandString); PhSetDialogItemText(hwndDlg, IDC_CPUNAME, brandString); @@ -357,13 +357,13 @@ INT_PTR CALLBACK PhSipCpuPanelDialogProc( { case WM_INITDIALOG: { - SendMessage(GetDlgItem(hwndDlg, IDC_UTILIZATION), WM_SETFONT, (WPARAM)CpuSection->Parameters->MediumFont, FALSE); - SendMessage(GetDlgItem(hwndDlg, IDC_SPEED), WM_SETFONT, (WPARAM)CpuSection->Parameters->MediumFont, FALSE); + SetWindowFont(GetDlgItem(hwndDlg, IDC_UTILIZATION), CpuSection->Parameters->MediumFont, FALSE); + SetWindowFont(GetDlgItem(hwndDlg, IDC_SPEED), CpuSection->Parameters->MediumFont, FALSE); } break; case WM_COMMAND: { - switch (LOWORD(wParam)) + switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDC_ONEGRAPHPERCPU: { diff --git a/ProcessHacker/sysscio.c b/ProcessHacker/sysscio.c index b5937e676278..2ba206292dc8 100644 --- a/ProcessHacker/sysscio.c +++ b/ProcessHacker/sysscio.c @@ -228,7 +228,7 @@ INT_PTR CALLBACK PhSipIoDialogProc( graphItem = PhAddLayoutItem(&IoLayoutManager, GetDlgItem(hwndDlg, IDC_GRAPH_LAYOUT), NULL, PH_ANCHOR_ALL); panelItem = PhAddLayoutItem(&IoLayoutManager, GetDlgItem(hwndDlg, IDC_LAYOUT), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); - SendMessage(GetDlgItem(hwndDlg, IDC_TITLE), WM_SETFONT, (WPARAM)IoSection->Parameters->LargeFont, FALSE); + SetWindowFont(GetDlgItem(hwndDlg, IDC_TITLE), IoSection->Parameters->LargeFont, FALSE); IoPanel = CreateDialog(PhInstanceHandle, MAKEINTRESOURCE(IDD_SYSINFO_IOPANEL), hwndDlg, PhSipIoPanelDialogProc); ShowWindow(IoPanel, SW_SHOW); diff --git a/ProcessHacker/sysscmem.c b/ProcessHacker/sysscmem.c index 96c684e40645..69f1f255420e 100644 --- a/ProcessHacker/sysscmem.c +++ b/ProcessHacker/sysscmem.c @@ -303,8 +303,8 @@ INT_PTR CALLBACK PhSipMemoryDialogProc( panelItem = PhAddLayoutItem(&MemoryLayoutManager, GetDlgItem(hwndDlg, IDC_LAYOUT), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); MemoryGraphMargin = graphItem->Margin; - SendMessage(GetDlgItem(hwndDlg, IDC_TITLE), WM_SETFONT, (WPARAM)MemorySection->Parameters->LargeFont, FALSE); - SendMessage(GetDlgItem(hwndDlg, IDC_TOTALPHYSICAL), WM_SETFONT, (WPARAM)MemorySection->Parameters->MediumFont, FALSE); + SetWindowFont(GetDlgItem(hwndDlg, IDC_TITLE), MemorySection->Parameters->LargeFont, FALSE); + SetWindowFont(GetDlgItem(hwndDlg, IDC_TOTALPHYSICAL), MemorySection->Parameters->MediumFont, FALSE); if (!getPhysicallyInstalledSystemMemory) getPhysicallyInstalledSystemMemory = PhGetDllProcedureAddress(L"kernel32.dll", "GetPhysicallyInstalledSystemMemory", 0); diff --git a/phlib/colorbox.c b/phlib/colorbox.c index 89cdcdac3cc1..913e8b9a629a 100644 --- a/phlib/colorbox.c +++ b/phlib/colorbox.c @@ -156,8 +156,8 @@ LRESULT CALLBACK PhpColorBoxWndProc( SetDCBrushColor(hdc, PhMakeColorBrighter(context->SelectedColor, 64)); // Draw the rectangle. - SelectObject(hdc, GetStockObject(DC_PEN)); - SelectObject(hdc, GetStockObject(DC_BRUSH)); + SelectPen(hdc, GetStockPen(DC_PEN)); + SelectBrush(hdc, GetStockBrush(DC_BRUSH)); Rectangle(hdc, clientRect.left, clientRect.top, clientRect.right, clientRect.bottom); EndPaint(hwnd, &paintStruct); diff --git a/phlib/emenu.c b/phlib/emenu.c index 49906170b2c6..50228b1e0e2b 100644 --- a/phlib/emenu.c +++ b/phlib/emenu.c @@ -97,7 +97,7 @@ VOID PhpDestroyEMenuItem( if ((Item->Flags & PH_EMENU_TEXT_OWNED) && Item->Text) PhFree(Item->Text); if ((Item->Flags & PH_EMENU_BITMAP_OWNED) && Item->Bitmap) - DeleteObject(Item->Bitmap); + DeleteBitmap(Item->Bitmap); if (Item->Items) { @@ -856,7 +856,7 @@ VOID PhModifyEMenuItem( if (ModifyFlags & PH_EMENU_MODIFY_BITMAP) { if ((Item->Flags & PH_EMENU_BITMAP_OWNED) && Item->Bitmap) - DeleteObject(Item->Bitmap); + DeleteBitmap(Item->Bitmap); Item->Bitmap = Bitmap; Item->Flags &= ~PH_EMENU_BITMAP_OWNED; diff --git a/phlib/extlv.c b/phlib/extlv.c index 8a9184feaedc..f6aa450bb20a 100644 --- a/phlib/extlv.c +++ b/phlib/extlv.c @@ -254,7 +254,7 @@ LRESULT CALLBACK PhpExtendedListViewWndProc( } if (newFont) - SelectObject(customDraw->nmcd.hdc, newFont); + SelectFont(customDraw->nmcd.hdc, newFont); if (colorChanged) { diff --git a/phlib/graph.c b/phlib/graph.c index 6808bd0c7dc9..6c990a4abd56 100644 --- a/phlib/graph.c +++ b/phlib/graph.c @@ -518,7 +518,7 @@ VOID PhDrawGraphDirect( RECT rect; if (DrawInfo->LabelYFont) - oldFont = SelectObject(hdc, DrawInfo->LabelYFont); + oldFont = SelectFont(hdc, DrawInfo->LabelYFont); SetTextColor(hdc, DrawInfo->LabelYColor); SetBkMode(hdc, TRANSPARENT); @@ -539,7 +539,7 @@ VOID PhDrawGraphDirect( DrawText(hdc, label->Buffer, (ULONG)label->Length / sizeof(WCHAR), &rect, DT_NOCLIP | DT_RIGHT); if (oldFont) - SelectObject(hdc, oldFont); + SelectFont(hdc, oldFont); PhDereferenceObject(label); } @@ -550,11 +550,11 @@ VOID PhDrawGraphDirect( HFONT oldFont = NULL; if (DrawInfo->TextFont) - oldFont = SelectObject(hdc, DrawInfo->TextFont); + oldFont = SelectFont(hdc, DrawInfo->TextFont); // Fill in the text box. SetDCBrushColor(hdc, DrawInfo->TextBoxColor); - FillRect(hdc, &DrawInfo->TextBoxRect, GetStockObject(DC_BRUSH)); + FillRect(hdc, &DrawInfo->TextBoxRect, GetStockBrush(DC_BRUSH)); // Draw the text. SetTextColor(hdc, DrawInfo->TextColor); @@ -562,7 +562,7 @@ VOID PhDrawGraphDirect( DrawText(hdc, DrawInfo->Text.Buffer, (ULONG)DrawInfo->Text.Length / sizeof(WCHAR), &DrawInfo->TextRect, DT_NOCLIP); if (oldFont) - SelectObject(hdc, oldFont); + SelectFont(hdc, oldFont); } } @@ -592,13 +592,13 @@ VOID PhSetGraphText( PH_RECTANGLE textRectangle; if (DrawInfo->TextFont) - oldFont = SelectObject(hdc, DrawInfo->TextFont); + oldFont = SelectFont(hdc, DrawInfo->TextFont); DrawInfo->Text = *Text; GetTextExtentPoint32(hdc, Text->Buffer, (ULONG)Text->Length / sizeof(WCHAR), &textSize); if (oldFont) - SelectObject(hdc, oldFont); + SelectFont(hdc, oldFont); // Calculate the box rectangle. @@ -690,7 +690,7 @@ VOID PhDrawTrayIconText( // dmex DrawInfo->TextFont = PhpTrayIconFont(); if (DrawInfo->TextFont) - oldFont = SelectObject(hdc, DrawInfo->TextFont); + oldFont = SelectFont(hdc, DrawInfo->TextFont); DrawInfo->Text = *Text; GetTextExtentPoint32(hdc, Text->Buffer, (ULONG)Text->Length / sizeof(WCHAR), &textSize); @@ -715,7 +715,7 @@ VOID PhDrawTrayIconText( // dmex // Fill in the text box. //SetDCBrushColor(hdc, DrawInfo->TextBoxColor); - //FillRect(hdc, &DrawInfo->TextBoxRect, GetStockObject(DC_BRUSH)); + //FillRect(hdc, &DrawInfo->TextBoxRect, GetStockBrush(DC_BRUSH)); // Draw the text. SetTextColor(hdc, DrawInfo->TextColor); @@ -724,7 +724,7 @@ VOID PhDrawTrayIconText( // dmex DrawText(hdc, DrawInfo->Text.Buffer, (ULONG)DrawInfo->Text.Length / sizeof(WCHAR), &DrawInfo->TextRect, DT_NOCLIP | DT_SINGLELINE); if (oldFont) - SelectObject(hdc, oldFont); + SelectFont(hdc, oldFont); } VOID PhpCreateGraphContext( @@ -780,8 +780,8 @@ static VOID PhpDeleteBufferedContext( { // The original bitmap must be selected back into the context, otherwise the bitmap can't be // deleted. - SelectObject(Context->BufferedContext, Context->BufferedOldBitmap); - DeleteObject(Context->BufferedBitmap); + SelectBitmap(Context->BufferedContext, Context->BufferedOldBitmap); + DeleteBitmap(Context->BufferedBitmap); DeleteDC(Context->BufferedContext); Context->BufferedContext = NULL; @@ -814,7 +814,7 @@ static VOID PhpCreateBufferedContext( Context->BufferedBitmap = CreateDIBSection(hdc, (BITMAPINFO *)&header, DIB_RGB_COLORS, &Context->BufferedBits, NULL, 0); ReleaseDC(Context->Handle, hdc); - Context->BufferedOldBitmap = SelectObject(Context->BufferedContext, Context->BufferedBitmap); + Context->BufferedOldBitmap = SelectBitmap(Context->BufferedContext, Context->BufferedBitmap); } static VOID PhpDeleteFadeOutContext( @@ -823,8 +823,8 @@ static VOID PhpDeleteFadeOutContext( { if (Context->FadeOutContext) { - SelectObject(Context->FadeOutContext, Context->FadeOutOldBitmap); - DeleteObject(Context->FadeOutBitmap); + SelectBitmap(Context->FadeOutContext, Context->FadeOutOldBitmap); + DeleteBitmap(Context->FadeOutBitmap); DeleteDC(Context->FadeOutContext); Context->FadeOutContext = NULL; @@ -866,7 +866,7 @@ static VOID PhpCreateFadeOutContext( Context->FadeOutBitmap = CreateDIBSection(hdc, (BITMAPINFO *)&header, DIB_RGB_COLORS, &Context->FadeOutBits, NULL, 0); ReleaseDC(Context->Handle, hdc); - Context->FadeOutOldBitmap = SelectObject(Context->FadeOutContext, Context->FadeOutBitmap); + Context->FadeOutOldBitmap = SelectBitmap(Context->FadeOutContext, Context->FadeOutBitmap); if (!Context->FadeOutBits) return; @@ -1128,7 +1128,7 @@ LRESULT CALLBACK PhpGraphWndProc( rect.right += 2; rect.bottom += 2; SetDCBrushColor(hdc, RGB(0x8f, 0x8f, 0x8f)); - FrameRect(hdc, &rect, GetStockObject(DC_BRUSH)); + FrameRect(hdc, &rect, GetStockBrush(DC_BRUSH)); ReleaseDC(hwnd, hdc); return 0; diff --git a/phlib/guisup.c b/phlib/guisup.c index 488218e57507..671da01fada1 100644 --- a/phlib/guisup.c +++ b/phlib/guisup.c @@ -607,7 +607,7 @@ VOID PhSetImageListBitmap( if (bitmap) { ImageList_Replace(ImageList, Index, bitmap, NULL); - DeleteObject(bitmap); + DeleteBitmap(bitmap); } } @@ -1733,5 +1733,5 @@ HICON PhGetInternalWindowIcon( if (!InternalGetWindowIcon_I) return NULL; - return InternalGetWindowIcon_I(WindowHandle, Type);; + return InternalGetWindowIcon_I(WindowHandle, Type); } diff --git a/phlib/hexedit.c b/phlib/hexedit.c index 3d2894404874..18e1f5f4f4bb 100644 --- a/phlib/hexedit.c +++ b/phlib/hexedit.c @@ -95,7 +95,7 @@ VOID PhpFreeHexEditContext( { if (!Context->UserBuffer && Context->Data) PhFree(Context->Data); if (Context->CharBuffer) PhFree(Context->CharBuffer); - if (Context->Font) DeleteObject(Context->Font); + if (Context->Font) DeleteFont(Context->Font); PhFree(Context); } @@ -1000,7 +1000,7 @@ VOID PhpHexEditUpdateMetrics( if (!hdc && UpdateLineHeight) { hdc = CreateCompatibleDC(hdc); - SelectObject(hdc, Context->Font); + SelectFont(hdc, Context->Font); freeHdc = TRUE; } @@ -1059,11 +1059,11 @@ VOID PhpHexEditOnPaint( bufferDc = CreateCompatibleDC(hdc); bufferBitmap = CreateCompatibleBitmap(hdc, clientRect.right, clientRect.bottom); - oldBufferBitmap = SelectObject(bufferDc, bufferBitmap); + oldBufferBitmap = SelectBitmap(bufferDc, bufferBitmap); SetDCBrushColor(bufferDc, GetSysColor(COLOR_WINDOW)); - FillRect(bufferDc, &clientRect, GetStockObject(DC_BRUSH)); - SelectObject(bufferDc, Context->Font); + FillRect(bufferDc, &clientRect, GetStockBrush(DC_BRUSH)); + SelectFont(bufferDc, Context->Font); SetBoundsRect(bufferDc, &clientRect, DCB_DISABLE); requiredBufferLength = (max(8, Context->BytesPerRow * 3) + 1) * sizeof(WCHAR); @@ -1301,8 +1301,8 @@ VOID PhpHexEditOnPaint( } BitBlt(hdc, 0, 0, clientRect.right, clientRect.bottom, bufferDc, 0, 0, SRCCOPY); - SelectObject(bufferDc, oldBufferBitmap); - DeleteObject(bufferBitmap); + SelectBitmap(bufferDc, oldBufferBitmap); + DeleteBitmap(bufferBitmap); DeleteDC(bufferDc); } diff --git a/phlib/icotobmp.c b/phlib/icotobmp.c index 9d4ce2878c84..048a6f17aec4 100644 --- a/phlib/icotobmp.c +++ b/phlib/icotobmp.c @@ -132,8 +132,8 @@ static VOID PhpConvertToPArgb32IfNeeded( PhpConvertToPArgb32(hdc, argb, iconInfo.hbmMask, Width, Height, rowWidth); } - DeleteObject(iconInfo.hbmColor); - DeleteObject(iconInfo.hbmMask); + DeleteBitmap(iconInfo.hbmColor); + DeleteBitmap(iconInfo.hbmMask); } } } @@ -164,7 +164,7 @@ HBITMAP PhIconToBitmap( hdc = CreateCompatibleDC(screenHdc); bitmap = PhpCreateBitmap32(screenHdc, Width, Height, NULL); ReleaseDC(NULL, screenHdc); - oldBitmap = SelectObject(hdc, bitmap); + oldBitmap = SelectBitmap(hdc, bitmap); paintParams.dwFlags = BPPF_ERASE; paintParams.pBlendFunction = &blendFunction; @@ -182,10 +182,10 @@ HBITMAP PhIconToBitmap( // Default to unbuffered painting. FillRect(hdc, &iconRectangle, (HBRUSH)(COLOR_WINDOW + 1)); DrawIconEx(hdc, 0, 0, Icon, Width, Height, 0, NULL, DI_NORMAL); - SelectObject(hdc, oldBitmap); + //SelectBitmap(hdc, oldBitmap); // ?? (dmex) } - SelectObject(hdc, oldBitmap); + SelectBitmap(hdc, oldBitmap); DeleteDC(hdc); return bitmap; diff --git a/phlib/theme.c b/phlib/theme.c index 04b4eceea6c3..cbc34f7e5572 100644 --- a/phlib/theme.c +++ b/phlib/theme.c @@ -349,7 +349,7 @@ VOID PhInitializeThemeWindowTabControl( PhSetWindowStyle(TabControlWindow, TCS_OWNERDRAWFIXED, TCS_OWNERDRAWFIXED); - SendMessage(TabControlWindow, WM_SETFONT, (WPARAM)PhpTabControlFontHandle, FALSE); + SetWindowFont(TabControlWindow, PhpTabControlFontHandle, FALSE); InvalidateRect(TabControlWindow, NULL, FALSE); } @@ -687,7 +687,7 @@ BOOLEAN PhThemeWindowDrawItem( SetTextColor(DrawInfo->hDC, GetSysColor(COLOR_HIGHLIGHTTEXT)); SetDCBrushColor(DrawInfo->hDC, RGB(30, 30, 30)); - FillRect(DrawInfo->hDC, &DrawInfo->rcItem, GetStockObject(DC_BRUSH)); + FillRect(DrawInfo->hDC, &DrawInfo->rcItem, GetStockBrush(DC_BRUSH)); DrawEdge(DrawInfo->hDC, &DrawInfo->rcItem, BDR_RAISEDOUTER, BF_RIGHT); memset(headerText, 0, sizeof(headerText)); @@ -733,7 +733,7 @@ BOOLEAN PhThemeWindowDrawItem( break; } - FillRect(DrawInfo->hDC, &DrawInfo->rcItem, GetStockObject(DC_BRUSH)); + FillRect(DrawInfo->hDC, &DrawInfo->rcItem, GetStockBrush(DC_BRUSH)); } else if (isSelected) { @@ -749,7 +749,7 @@ BOOLEAN PhThemeWindowDrawItem( break; } - FillRect(DrawInfo->hDC, &DrawInfo->rcItem, GetStockObject(DC_BRUSH)); + FillRect(DrawInfo->hDC, &DrawInfo->rcItem, GetStockBrush(DC_BRUSH)); } else { @@ -765,7 +765,7 @@ BOOLEAN PhThemeWindowDrawItem( break; } - FillRect(DrawInfo->hDC, &DrawInfo->rcItem, GetStockObject(DC_BRUSH)); + FillRect(DrawInfo->hDC, &DrawInfo->rcItem, GetStockBrush(DC_BRUSH)); } if (isChecked) @@ -794,7 +794,7 @@ BOOLEAN PhThemeWindowDrawItem( break; case 1: // Old colors oldTextColor = SetTextColor(DrawInfo->hDC, PhpThemeWindowTextColor); - //FillRect(DrawInfo->hDC, &DrawInfo->rcItem, GetStockObject(DC_BRUSH)); + //FillRect(DrawInfo->hDC, &DrawInfo->rcItem, GetStockBrush(DC_BRUSH)); //SetTextColor(DrawInfo->hDC, PhpThemeWindowTextColor); break; } @@ -820,11 +820,11 @@ BOOLEAN PhThemeWindowDrawItem( { case 0: // New colors SetDCBrushColor(DrawInfo->hDC, RGB(0xff, 0xff, 0xff)); - FillRect(DrawInfo->hDC, &DrawInfo->rcItem, GetStockObject(DC_BRUSH)); + FillRect(DrawInfo->hDC, &DrawInfo->rcItem, GetStockBrush(DC_BRUSH)); break; case 1: // Old colors SetDCBrushColor(DrawInfo->hDC, RGB(28, 28, 28)); - FillRect(DrawInfo->hDC, &DrawInfo->rcItem, GetStockObject(DC_BRUSH)); + FillRect(DrawInfo->hDC, &DrawInfo->rcItem, GetStockBrush(DC_BRUSH)); break; } @@ -844,11 +844,11 @@ BOOLEAN PhThemeWindowDrawItem( { case 0: // New colors SetDCBrushColor(DrawInfo->hDC, RGB(0xff, 0xff, 0xff)); - FillRect(DrawInfo->hDC, &DrawInfo->rcItem, GetStockObject(DC_BRUSH)); + FillRect(DrawInfo->hDC, &DrawInfo->rcItem, GetStockBrush(DC_BRUSH)); break; case 1: // Old colors SetDCBrushColor(DrawInfo->hDC, RGB(78, 78, 78)); - FillRect(DrawInfo->hDC, &DrawInfo->rcItem, GetStockObject(DC_BRUSH)); + FillRect(DrawInfo->hDC, &DrawInfo->rcItem, GetStockBrush(DC_BRUSH)); break; } @@ -864,7 +864,7 @@ BOOLEAN PhThemeWindowDrawItem( PhSplitStringRefAtLastChar(&part, '\b', &firstPart, &secondPart); //SetDCBrushColor(DrawInfo->hDC, RGB(28, 28, 28)); - //FillRect(DrawInfo->hDC, &DrawInfo->rcItem, GetStockObject(DC_BRUSH)); + //FillRect(DrawInfo->hDC, &DrawInfo->rcItem, GetStockBrush(DC_BRUSH)); if (menuItemInfo->Bitmap) { @@ -934,7 +934,7 @@ BOOLEAN PhThemeWindowDrawItem( break; } - FillRect(DrawInfo->hDC, &DrawInfo->rcItem, GetStockObject(DC_BRUSH)); + FillRect(DrawInfo->hDC, &DrawInfo->rcItem, GetStockBrush(DC_BRUSH)); if (ComboBox_GetLBText(DrawInfo->hwndItem, DrawInfo->itemID, (LPARAM)comboText) != CB_ERR) { @@ -1046,7 +1046,7 @@ LRESULT CALLBACK PhpThemeWindowDrawButton( SetDCBrushColor(DrawInfo->hdc, RGB(78, 78, 78)); break; } - FillRect(DrawInfo->hdc, &DrawInfo->rc, GetStockObject(DC_BRUSH)); + FillRect(DrawInfo->hdc, &DrawInfo->rc, GetStockBrush(DC_BRUSH)); } else if (isHighlighted) { @@ -1061,7 +1061,7 @@ LRESULT CALLBACK PhpThemeWindowDrawButton( SetDCBrushColor(DrawInfo->hdc, RGB(65, 65, 65)); break; } - FillRect(DrawInfo->hdc, &DrawInfo->rc, GetStockObject(DC_BRUSH)); + FillRect(DrawInfo->hdc, &DrawInfo->rc, GetStockBrush(DC_BRUSH)); } else { @@ -1076,7 +1076,7 @@ LRESULT CALLBACK PhpThemeWindowDrawButton( SetDCBrushColor(DrawInfo->hdc, RGB(42, 42, 42)); // WindowForegroundColor break; } - FillRect(DrawInfo->hdc, &DrawInfo->rc, GetStockObject(DC_BRUSH)); + FillRect(DrawInfo->hdc, &DrawInfo->rc, GetStockBrush(DC_BRUSH)); } if ((buttonStyle & BS_ICON) == BS_ICON) @@ -1090,7 +1090,7 @@ LRESULT CALLBACK PhpThemeWindowDrawButton( HICON buttonIcon; SetDCBrushColor(DrawInfo->hdc, RGB(65, 65, 65)); - FrameRect(DrawInfo->hdc, &DrawInfo->rc, GetStockObject(DC_BRUSH)); + FrameRect(DrawInfo->hdc, &DrawInfo->rc, GetStockBrush(DC_BRUSH)); if (!(buttonIcon = Static_GetIcon(DrawInfo->hdr.hwndFrom, 0))) buttonIcon = (HICON)SendMessage(DrawInfo->hdr.hwndFrom, BM_GETIMAGE, IMAGE_ICON, 0); @@ -1115,7 +1115,7 @@ LRESULT CALLBACK PhpThemeWindowDrawButton( height = bmp.bmHeight; } - DeleteObject(iconInfo.hbmColor); + DeleteBitmap(iconInfo.hbmColor); } else if (iconInfo.hbmMask) { @@ -1125,7 +1125,7 @@ LRESULT CALLBACK PhpThemeWindowDrawButton( height = bmp.bmHeight / 2; } - DeleteObject(iconInfo.hbmMask); + DeleteBitmap(iconInfo.hbmMask); } bufferRect.left += 1; // HACK @@ -1199,7 +1199,7 @@ LRESULT CALLBACK PhpThemeWindowDrawButton( HICON buttonIcon; SetDCBrushColor(DrawInfo->hdc, RGB(65, 65, 65)); - FrameRect(DrawInfo->hdc, &DrawInfo->rc, GetStockObject(DC_BRUSH)); + FrameRect(DrawInfo->hdc, &DrawInfo->rc, GetStockBrush(DC_BRUSH)); if (!(buttonIcon = Static_GetIcon(DrawInfo->hdr.hwndFrom, 0))) buttonIcon = (HICON)SendMessage(DrawInfo->hdr.hwndFrom, BM_GETIMAGE, IMAGE_ICON, 0); @@ -1257,7 +1257,7 @@ LRESULT CALLBACK PhThemeWindowDrawRebar( break; } - FillRect(DrawInfo->hdc, &DrawInfo->rc, GetStockObject(DC_BRUSH)); + FillRect(DrawInfo->hdc, &DrawInfo->rc, GetStockBrush(DC_BRUSH)); } return CDRF_NOTIFYITEMDRAW; case CDDS_ITEMPREPAINT: @@ -1273,7 +1273,7 @@ LRESULT CALLBACK PhThemeWindowDrawRebar( break; } - FillRect(DrawInfo->hdc, &DrawInfo->rc, GetStockObject(DC_BRUSH)); + FillRect(DrawInfo->hdc, &DrawInfo->rc, GetStockBrush(DC_BRUSH)); } return CDRF_SKIPDEFAULT; } @@ -1332,7 +1332,7 @@ LRESULT CALLBACK PhThemeWindowDrawToolbar( //{ // SetTextColor(DrawInfo->nmcd.hdc, PhpThemeWindowTextColor); // SetDCBrushColor(DrawInfo->nmcd.hdc, RGB(0xff, 0xff, 0xff)); - // FillRect(DrawInfo->nmcd.hdc, &DrawInfo->nmcd.rc, GetStockObject(DC_BRUSH)); + // FillRect(DrawInfo->nmcd.hdc, &DrawInfo->nmcd.rc, GetStockBrush(DC_BRUSH)); //} if (isHighlighted) @@ -1374,12 +1374,12 @@ LRESULT CALLBACK PhThemeWindowDrawToolbar( case 0: // New colors SetTextColor(DrawInfo->nmcd.hdc, PhpThemeWindowTextColor); SetDCBrushColor(DrawInfo->nmcd.hdc, PhpThemeWindowBackgroundColor); - FillRect(DrawInfo->nmcd.hdc, &DrawInfo->nmcd.rc, GetStockObject(DC_BRUSH)); + FillRect(DrawInfo->nmcd.hdc, &DrawInfo->nmcd.rc, GetStockBrush(DC_BRUSH)); break; case 1: // Old colors SetTextColor(DrawInfo->nmcd.hdc, PhpThemeWindowTextColor); SetDCBrushColor(DrawInfo->nmcd.hdc, RGB(128, 128, 128)); - FillRect(DrawInfo->nmcd.hdc, &DrawInfo->nmcd.rc, GetStockObject(DC_BRUSH)); + FillRect(DrawInfo->nmcd.hdc, &DrawInfo->nmcd.rc, GetStockBrush(DC_BRUSH)); break; } } @@ -1390,12 +1390,12 @@ LRESULT CALLBACK PhThemeWindowDrawToolbar( case 0: // New colors SetTextColor(DrawInfo->nmcd.hdc, RGB(0x0, 0x0, 0x0)); SetDCBrushColor(DrawInfo->nmcd.hdc, GetSysColor(COLOR_3DFACE));// RGB(0xff, 0xff, 0xff)); - FillRect(DrawInfo->nmcd.hdc, &DrawInfo->nmcd.rc, GetStockObject(DC_BRUSH)); + FillRect(DrawInfo->nmcd.hdc, &DrawInfo->nmcd.rc, GetStockBrush(DC_BRUSH)); break; case 1: // Old colors SetTextColor(DrawInfo->nmcd.hdc, PhpThemeWindowTextColor); SetDCBrushColor(DrawInfo->nmcd.hdc, RGB(65, 65, 65)); //RGB(28, 28, 28)); // RGB(65, 65, 65)); - FillRect(DrawInfo->nmcd.hdc, &DrawInfo->nmcd.rc, GetStockObject(DC_BRUSH)); + FillRect(DrawInfo->nmcd.hdc, &DrawInfo->nmcd.rc, GetStockBrush(DC_BRUSH)); break; } } @@ -1481,12 +1481,12 @@ LRESULT CALLBACK PhpThemeWindowDrawListViewGroup( case 0: // New colors SetTextColor(DrawInfo->nmcd.hdc, RGB(0x0, 0x0, 0x0)); SetDCBrushColor(DrawInfo->nmcd.hdc, PhpThemeWindowTextColor); - //FillRect(DrawInfo->nmcd.hdc, &DrawInfo->nmcd.rc, GetStockObject(DC_BRUSH)); + //FillRect(DrawInfo->nmcd.hdc, &DrawInfo->nmcd.rc, GetStockBrush(DC_BRUSH)); break; case 1: // Old colors SetTextColor(DrawInfo->nmcd.hdc, RGB(0x0, 0x0, 0x0)); SetDCBrushColor(DrawInfo->nmcd.hdc, RGB(128, 128, 128)); - //FillRect(DrawInfo->nmcd.hdc, &DrawInfo->nmcd.rc, GetStockObject(DC_BRUSH)); + //FillRect(DrawInfo->nmcd.hdc, &DrawInfo->nmcd.rc, GetStockBrush(DC_BRUSH)); break; } @@ -1521,7 +1521,7 @@ LRESULT CALLBACK PhpThemeWindowDrawListViewGroup( DrawInfo->rcText.top += 2; DrawInfo->rcText.bottom -= 2; - FillRect(DrawInfo->nmcd.hdc, &DrawInfo->rcText, GetStockObject(DC_BRUSH)); + FillRect(DrawInfo->nmcd.hdc, &DrawInfo->rcText, GetStockBrush(DC_BRUSH)); DrawInfo->rcText.top -= 2; DrawInfo->rcText.bottom += 2; @@ -1614,11 +1614,11 @@ LRESULT CALLBACK PhpThemeWindowSubclassProc( case 0: // New colors SetTextColor((HDC)wParam, RGB(0x0, 0x0, 0x0)); SetDCBrushColor((HDC)wParam, PhpThemeWindowTextColor); - return (INT_PTR)GetStockObject(DC_BRUSH); + return (INT_PTR)GetStockBrush(DC_BRUSH); case 1: // Old colors SetTextColor((HDC)wParam, PhpThemeWindowTextColor); SetDCBrushColor((HDC)wParam, RGB(60, 60, 60)); - return (INT_PTR)GetStockObject(DC_BRUSH); + return (INT_PTR)GetStockBrush(DC_BRUSH); } } break; @@ -1634,11 +1634,11 @@ LRESULT CALLBACK PhpThemeWindowSubclassProc( case 0: // New colors SetTextColor((HDC)wParam, RGB(0x0, 0x0, 0x0)); SetDCBrushColor((HDC)wParam, PhpThemeWindowTextColor); - return (INT_PTR)GetStockObject(DC_BRUSH); + return (INT_PTR)GetStockBrush(DC_BRUSH); case 1: // Old colors SetTextColor((HDC)wParam, PhpThemeWindowTextColor); SetDCBrushColor((HDC)wParam, RGB(30, 30, 30)); - return (INT_PTR)GetStockObject(DC_BRUSH); + return (INT_PTR)GetStockBrush(DC_BRUSH); } } break; @@ -1725,12 +1725,12 @@ LRESULT CALLBACK PhpThemeWindowGroupBoxSubclassProc( //case 0: // New colors // SetTextColor(hdc, GetSysColor(COLOR_GRAYTEXT)); // SetDCBrushColor(hdc, RGB(0xff, 0xff, 0xff)); - // FrameRect(hdc, &clientRect, GetStockObject(DC_BRUSH)); + // FrameRect(hdc, &clientRect, GetStockBrush(DC_BRUSH)); // break; //case 1: // Old colors // SetTextColor(hdc, GetSysColor(COLOR_GRAYTEXT)); // SetDCBrushColor(hdc, RGB(0, 0, 0)); // RGB(28, 28, 28)); // RGB(65, 65, 65)); - // FrameRect(hdc, &clientRect, GetStockObject(DC_BRUSH)); + // FrameRect(hdc, &clientRect, GetStockBrush(DC_BRUSH)); // break; //} @@ -1741,7 +1741,7 @@ LRESULT CALLBACK PhpThemeWindowGroupBoxSubclassProc( SetTextColor(hdc, RGB(255, 69, 0)); SetDCBrushColor(hdc, RGB(65, 65, 65)); - FillRect(hdc, &textRect, GetStockObject(DC_BRUSH)); + FillRect(hdc, &textRect, GetStockBrush(DC_BRUSH)); switch (PhpThemeColorMode) { @@ -1750,14 +1750,14 @@ LRESULT CALLBACK PhpThemeWindowGroupBoxSubclassProc( SetDCBrushColor(hdc, RGB(65, 65, 65)); //SetTextColor(hdc, RGB(0x0, 0x0, 0x0)); //SetDCBrushColor(hdc, PhpThemeWindowTextColor); - //FrameRect(hdc, &clientRect, GetStockObject(DC_BRUSH)); + //FrameRect(hdc, &clientRect, GetStockBrush(DC_BRUSH)); break; case 1: // Old colors SetTextColor(hdc, RGB(255, 69, 0)); SetDCBrushColor(hdc, RGB(65, 65, 65)); //SetTextColor(hdc, PhpThemeWindowTextColor); //SetDCBrushColor(hdc, PhpThemeWindowBackgroundColor); - //FrameRect(hdc, &clientRect, GetStockObject(DC_BRUSH)); + //FrameRect(hdc, &clientRect, GetStockBrush(DC_BRUSH)); break; } @@ -1827,12 +1827,12 @@ LRESULT CALLBACK PhpThemeWindowEditSubclassProc( if (GetFocus() == WindowHandle) { SetDCBrushColor(hdc, GetSysColor(COLOR_HOTLIGHT)); - FrameRect(hdc, &windowRect, GetStockObject(DC_BRUSH)); + FrameRect(hdc, &windowRect, GetStockBrush(DC_BRUSH)); } else { SetDCBrushColor(hdc, RGB(65, 65, 65)); - FrameRect(hdc, &windowRect, GetStockObject(DC_BRUSH)); + FrameRect(hdc, &windowRect, GetStockBrush(DC_BRUSH)); } ReleaseDC(WindowHandle, hdc); @@ -1980,12 +1980,12 @@ LRESULT CALLBACK PhpThemeWindowTabControlWndSubclassProc( case 0: // New colors //SetTextColor(hdc, RGB(0x0, 0xff, 0x0)); SetDCBrushColor(hdc, GetSysColor(COLOR_3DFACE));// PhpThemeWindowTextColor); - FillRect(hdc, &clientRect, GetStockObject(DC_BRUSH)); + FillRect(hdc, &clientRect, GetStockBrush(DC_BRUSH)); break; case 1: // Old colors //SetTextColor(hdc, PhpThemeWindowTextColor); SetDCBrushColor(hdc, RGB(65, 65, 65)); //WindowForegroundColor); // RGB(65, 65, 65)); - FillRect(hdc, &clientRect, GetStockObject(DC_BRUSH)); + FillRect(hdc, &clientRect, GetStockBrush(DC_BRUSH)); break; } @@ -2010,20 +2010,20 @@ LRESULT CALLBACK PhpThemeWindowTabControlWndSubclassProc( { SetTextColor(hdc, RGB(0xff, 0xff, 0xff)); SetDCBrushColor(hdc, RGB(128, 128, 128)); - FillRect(hdc, &itemRect, GetStockObject(DC_BRUSH)); + FillRect(hdc, &itemRect, GetStockBrush(DC_BRUSH)); } else { SetTextColor(hdc, PhpThemeWindowTextColor); SetDCBrushColor(hdc, PhpThemeWindowBackgroundColor); - FillRect(hdc, &itemRect, GetStockObject(DC_BRUSH)); + FillRect(hdc, &itemRect, GetStockBrush(DC_BRUSH)); } } break; case 1: // Old colors SetTextColor(hdc, PhpThemeWindowTextColor); SetDCBrushColor(hdc, RGB(128, 128, 128)); - FillRect(hdc, &itemRect, GetStockObject(DC_BRUSH)); + FillRect(hdc, &itemRect, GetStockBrush(DC_BRUSH)); break; } @@ -2041,13 +2041,13 @@ LRESULT CALLBACK PhpThemeWindowTabControlWndSubclassProc( { SetTextColor(hdc, RGB(0x0, 0x0, 0x0)); SetDCBrushColor(hdc, RGB(0xff, 0xff, 0xff)); - FillRect(hdc, &itemRect, GetStockObject(DC_BRUSH)); + FillRect(hdc, &itemRect, GetStockBrush(DC_BRUSH)); } else { SetTextColor(hdc, RGB(0, 0, 0)); SetDCBrushColor(hdc, GetSysColor(COLOR_3DFACE));// PhpThemeWindowTextColor); - FillRect(hdc, &itemRect, GetStockObject(DC_BRUSH)); + FillRect(hdc, &itemRect, GetStockBrush(DC_BRUSH)); } } break; @@ -2057,13 +2057,13 @@ LRESULT CALLBACK PhpThemeWindowTabControlWndSubclassProc( { SetTextColor(hdc, PhpThemeWindowTextColor); SetDCBrushColor(hdc, PhpThemeWindowForegroundColor); - FillRect(hdc, &itemRect, GetStockObject(DC_BRUSH)); + FillRect(hdc, &itemRect, GetStockBrush(DC_BRUSH)); } else { SetTextColor(hdc, PhpThemeWindowTextColor); SetDCBrushColor(hdc, PhpThemeWindowBackgroundColor); - FillRect(hdc, &itemRect, GetStockObject(DC_BRUSH)); + FillRect(hdc, &itemRect, GetStockBrush(DC_BRUSH)); } } break; @@ -2228,12 +2228,12 @@ LRESULT CALLBACK PhpThemeWindowHeaderSubclassProc( case 0: // New colors SetTextColor(hdc, RGB(0x0, 0x0, 0x0)); SetDCBrushColor(hdc, PhpThemeWindowTextColor); - FillRect(hdc, &clientRect, GetStockObject(DC_BRUSH)); + FillRect(hdc, &clientRect, GetStockBrush(DC_BRUSH)); break; case 1: // Old colors SetTextColor(hdc, PhpThemeWindowTextColor); SetDCBrushColor(hdc, RGB(65, 65, 65)); //WindowForegroundColor); // RGB(65, 65, 65)); - FillRect(hdc, &clientRect, GetStockObject(DC_BRUSH)); + FillRect(hdc, &clientRect, GetStockBrush(DC_BRUSH)); break; } @@ -2256,12 +2256,12 @@ LRESULT CALLBACK PhpThemeWindowHeaderSubclassProc( case 0: // New colors SetTextColor(hdc, PhpThemeWindowTextColor); SetDCBrushColor(hdc, PhpThemeWindowBackgroundColor); - FillRect(hdc, &headerRect, GetStockObject(DC_BRUSH)); + FillRect(hdc, &headerRect, GetStockBrush(DC_BRUSH)); break; case 1: // Old colors SetTextColor(hdc, PhpThemeWindowTextColor); SetDCBrushColor(hdc, RGB(128, 128, 128)); - FillRect(hdc, &headerRect, GetStockObject(DC_BRUSH)); + FillRect(hdc, &headerRect, GetStockBrush(DC_BRUSH)); break; } @@ -2274,12 +2274,12 @@ LRESULT CALLBACK PhpThemeWindowHeaderSubclassProc( case 0: // New colors SetTextColor(hdc, RGB(0x0, 0x0, 0x0)); SetDCBrushColor(hdc, PhpThemeWindowTextColor); - FillRect(hdc, &headerRect, GetStockObject(DC_BRUSH)); + FillRect(hdc, &headerRect, GetStockBrush(DC_BRUSH)); break; case 1: // Old colors SetTextColor(hdc, PhpThemeWindowTextColor); SetDCBrushColor(hdc, PhpThemeWindowBackgroundColor); - FillRect(hdc, &headerRect, GetStockObject(DC_BRUSH)); + FillRect(hdc, &headerRect, GetStockBrush(DC_BRUSH)); break; } @@ -2404,12 +2404,12 @@ LRESULT CALLBACK PhpThemeWindowStatusbarWndSubclassProc( case 0: // New colors SetTextColor(hdc, RGB(0x0, 0x0, 0x0)); SetDCBrushColor(hdc, GetSysColor(COLOR_3DFACE)); // RGB(0xff, 0xff, 0xff)); - FillRect(hdc, &clientRect, GetStockObject(DC_BRUSH)); + FillRect(hdc, &clientRect, GetStockBrush(DC_BRUSH)); break; case 1: // Old colors SetTextColor(hdc, RGB(0xff, 0xff, 0xff)); SetDCBrushColor(hdc, RGB(65, 65, 65)); //RGB(28, 28, 28)); // RGB(65, 65, 65)); - FillRect(hdc, &clientRect, GetStockObject(DC_BRUSH)); + FillRect(hdc, &clientRect, GetStockBrush(DC_BRUSH)); break; } @@ -2434,12 +2434,12 @@ LRESULT CALLBACK PhpThemeWindowStatusbarWndSubclassProc( case 0: // New colors SetTextColor(hdc, PhpThemeWindowTextColor); SetDCBrushColor(hdc, PhpThemeWindowBackgroundColor); - FillRect(hdc, &blockRect, GetStockObject(DC_BRUSH)); + FillRect(hdc, &blockRect, GetStockBrush(DC_BRUSH)); break; case 1: // Old colors SetTextColor(hdc, RGB(0xff, 0xff, 0xff)); SetDCBrushColor(hdc, RGB(128, 128, 128)); - FillRect(hdc, &blockRect, GetStockObject(DC_BRUSH)); + FillRect(hdc, &blockRect, GetStockBrush(DC_BRUSH)); //FrameRect(hdc, &blockRect, GetSysColorBrush(COLOR_HIGHLIGHT)); break; } @@ -2451,13 +2451,13 @@ LRESULT CALLBACK PhpThemeWindowStatusbarWndSubclassProc( case 0: // New colors SetTextColor(hdc, RGB(0x0, 0x0, 0x0)); SetDCBrushColor(hdc, GetSysColor(COLOR_3DFACE)); // RGB(0xff, 0xff, 0xff)); - FillRect(hdc, &blockRect, GetStockObject(DC_BRUSH)); + FillRect(hdc, &blockRect, GetStockBrush(DC_BRUSH)); //FrameRect(hdc, &blockRect, GetSysColorBrush(COLOR_HIGHLIGHT)); break; case 1: // Old colors SetTextColor(hdc, RGB(0xff, 0xff, 0xff)); SetDCBrushColor(hdc, RGB(64, 64, 64)); - FillRect(hdc, &blockRect, GetStockObject(DC_BRUSH)); + FillRect(hdc, &blockRect, GetStockBrush(DC_BRUSH)); //FrameRect(hdc, &blockRect, GetSysColorBrush(COLOR_HIGHLIGHT)); break; } diff --git a/phlib/treenew.c b/phlib/treenew.c index e9f86950d22c..5153865b6ea8 100644 --- a/phlib/treenew.c +++ b/phlib/treenew.c @@ -352,9 +352,7 @@ VOID PhTnpCreateTreeNewContext( { PPH_TREENEW_CONTEXT context; - context = PhAllocate(sizeof(PH_TREENEW_CONTEXT)); - memset(context, 0, sizeof(PH_TREENEW_CONTEXT)); - + context = PhAllocateZero(sizeof(PH_TREENEW_CONTEXT)); context->FixedWidthMinimum = 20; context->RowHeight = 1; // must never be 0 context->HotNodeIndex = -1; @@ -374,11 +372,9 @@ VOID PhTnpDestroyTreeNewContext( _In_ PPH_TREENEW_CONTEXT Context ) { - ULONG i; - if (Context->Columns) { - for (i = 0; i < Context->NextId; i++) + for (ULONG i = 0; i < Context->NextId; i++) { if (Context->Columns[i]) PhFree(Context->Columns[i]); @@ -393,7 +389,7 @@ VOID PhTnpDestroyTreeNewContext( PhDereferenceObject(Context->FlatList); if (Context->FontOwned) - DeleteObject(Context->Font); + DeleteFont(Context->Font); if (Context->ThemeData) CloseThemeData(Context->ThemeData); @@ -408,7 +404,7 @@ VOID PhTnpDestroyTreeNewContext( PhTnpDestroyBufferedContext(Context); if (Context->SuspendUpdateRegion) - DeleteObject(Context->SuspendUpdateRegion); + DeleteRgn(Context->SuspendUpdateRegion); PhFree(Context); } @@ -660,7 +656,7 @@ VOID PhTnpOnPaint( else { CombineRgn(Context->SuspendUpdateRegion, Context->SuspendUpdateRegion, updateRegion, RGN_OR); - DeleteObject(updateRegion); + DeleteRgn(updateRegion); } // Pretend we painted something; this ensures the update region is validated properly. @@ -2022,7 +2018,7 @@ VOID PhTnpSetFont( { if (Context->FontOwned) { - DeleteObject(Context->Font); + DeleteFont(Context->Font); Context->FontOwned = FALSE; } @@ -2039,12 +2035,12 @@ VOID PhTnpSetFont( } } - SendMessage(Context->FixedHeaderHandle, WM_SETFONT, (WPARAM)Context->Font, Redraw); - SendMessage(Context->HeaderHandle, WM_SETFONT, (WPARAM)Context->Font, Redraw); + SetWindowFont(Context->FixedHeaderHandle, Context->Font, Redraw); + SetWindowFont(Context->HeaderHandle, Context->Font, Redraw); if (Context->TooltipsHandle) { - SendMessage(Context->TooltipsHandle, WM_SETFONT, (WPARAM)Context->Font, FALSE); + SetWindowFont(Context->TooltipsHandle, Context->Font, FALSE); Context->TooltipFont = Context->Font; } @@ -2078,7 +2074,7 @@ VOID PhTnpUpdateTextMetrics( if (hdc = GetDC(Context->Handle)) { - SelectObject(hdc, Context->Font); + SelectFont(hdc, Context->Font); GetTextMetrics(hdc, &Context->TextMetrics); if (!Context->CustomRowHeight) @@ -2337,7 +2333,7 @@ VOID PhTnpSetRedraw( if (Context->SuspendUpdateRegion) { InvalidateRgn(Context->Handle, Context->SuspendUpdateRegion, FALSE); - DeleteObject(Context->SuspendUpdateRegion); + DeleteRgn(Context->SuspendUpdateRegion); Context->SuspendUpdateRegion = NULL; } } @@ -3145,7 +3141,7 @@ VOID PhTnpAutoSizeColumnHeader( if (hdc = GetDC(Context->Handle)) { - SelectObject(hdc, Context->Font); + SelectFont(hdc, Context->Font); if (GetTextExtentPoint32(hdc, text, (ULONG)textCount, &textSize)) { @@ -3508,7 +3504,7 @@ BOOLEAN PhTnpGetCellParts( else font = Context->Font; - SelectObject(hdc, font); + SelectFont(hdc, font); if (GetTextExtentPoint32(hdc, text.Buffer, (ULONG)text.Length / sizeof(WCHAR), &textSize)) { @@ -5094,7 +5090,7 @@ VOID PhTnpPaint( SetTextColor(hdc, RGB(0xff, 0xff, 0xff)); SetDCBrushColor(hdc, RGB(30, 30, 30)); - FillRect(hdc, &rowRect, GetStockObject(DC_BRUSH)); + FillRect(hdc, &rowRect, GetStockBrush(DC_BRUSH)); if (tempDc = CreateCompatibleDC(hdc)) { @@ -5112,7 +5108,7 @@ VOID PhTnpPaint( //FrameRect(hdc, &rowRect, GetSysColorBrush(COLOR_HIGHLIGHT)); // Fill in the selection rectangle. - oldBitmap = SelectObject(tempDc, bitmap); + oldBitmap = SelectBitmap(tempDc, bitmap); tempRect.left = 0; tempRect.top = 0; tempRect.right = 1; @@ -5123,12 +5119,12 @@ VOID PhTnpPaint( if (node->s.DrawBackColor != 16777215) { SetDCBrushColor(tempDc, node->s.DrawBackColor); - FillRect(tempDc, &tempRect, GetStockObject(DC_BRUSH)); + FillRect(tempDc, &tempRect, GetStockBrush(DC_BRUSH)); } else { SetDCBrushColor(tempDc, RGB(30, 30, 30)); - FillRect(tempDc, &tempRect, GetStockObject(DC_BRUSH)); + FillRect(tempDc, &tempRect, GetStockBrush(DC_BRUSH)); } blendFunction.BlendOp = AC_SRC_OVER; @@ -5169,7 +5165,7 @@ VOID PhTnpPaint( { SetTextColor(hdc, Context->CustomTextColor); SetDCBrushColor(hdc, Context->CustomFocusColor); - FillRect(hdc, &rowRect, GetStockObject(DC_BRUSH)); + FillRect(hdc, &rowRect, GetStockBrush(DC_BRUSH)); } else { @@ -5183,7 +5179,7 @@ VOID PhTnpPaint( { SetTextColor(hdc, Context->CustomTextColor); SetDCBrushColor(hdc, Context->CustomSelectedColor); - FillRect(hdc, &rowRect, GetStockObject(DC_BRUSH)); + FillRect(hdc, &rowRect, GetStockBrush(DC_BRUSH)); } else { @@ -5196,7 +5192,7 @@ VOID PhTnpPaint( { SetTextColor(hdc, node->s.DrawForeColor); SetDCBrushColor(hdc, node->s.DrawBackColor); - FillRect(hdc, &rowRect, GetStockObject(DC_BRUSH)); + FillRect(hdc, &rowRect, GetStockBrush(DC_BRUSH)); } } @@ -5266,7 +5262,7 @@ VOID PhTnpPaint( if (GetClipRgn(hdc, oldClipRegion) != 1) { - DeleteObject(oldClipRegion); + DeleteRgn(oldClipRegion); oldClipRegion = NULL; } @@ -5285,7 +5281,7 @@ VOID PhTnpPaint( if (oldClipRegion) { - DeleteObject(oldClipRegion); + DeleteRgn(oldClipRegion); } } @@ -5302,7 +5298,7 @@ VOID PhTnpPaint( { SetTextColor(hdc, RGB(0xff, 0xff, 0xff)); SetDCBrushColor(hdc, RGB(30, 30, 30)); - FillRect(hdc, &rowRect, GetStockObject(DC_BRUSH)); + FillRect(hdc, &rowRect, GetStockBrush(DC_BRUSH)); } else { @@ -5322,7 +5318,7 @@ VOID PhTnpPaint( { SetTextColor(hdc, RGB(0xff, 0xff, 0xff)); SetDCBrushColor(hdc, RGB(30, 30, 30)); - FillRect(hdc, &rowRect, GetStockObject(DC_BRUSH)); + FillRect(hdc, &rowRect, GetStockBrush(DC_BRUSH)); } else { @@ -5515,7 +5511,7 @@ VOID PhTnpDrawCell( if (GetClipRgn(hdc, oldClipRegion) != 1) { - DeleteObject(oldClipRegion); + DeleteRgn(oldClipRegion); oldClipRegion = NULL; } @@ -5600,7 +5596,7 @@ VOID PhTnpDrawCell( SelectClipRgn(hdc, oldClipRegion); if (oldClipRegion) - DeleteObject(oldClipRegion); + DeleteRgn(oldClipRegion); } if (textRect.left > textRect.right) @@ -5644,7 +5640,7 @@ VOID PhTnpDrawCell( textRect.bottom = CellRect->bottom; if (font) - oldFont = SelectObject(hdc, font); + oldFont = SelectFont(hdc, font); DrawText( hdc, @@ -5655,7 +5651,7 @@ VOID PhTnpDrawCell( ); if (font) - SelectObject(hdc, oldFont); + SelectFont(hdc, oldFont); } } @@ -5684,7 +5680,7 @@ VOID PhTnpDrawDivider( points[1].x = Context->ClientRect.right; points[1].y = Context->ClientRect.bottom; SetDCPenColor(Context->BufferedContext, RGB(0x77, 0x77, 0x77)); - SelectObject(Context->BufferedContext, GetStockObject(DC_PEN)); + SelectPen(Context->BufferedContext, GetStockPen(DC_PEN)); Polyline(Context->BufferedContext, points, 2); blendFunction.BlendOp = AC_SRC_OVER; @@ -5721,7 +5717,7 @@ VOID PhTnpDrawDivider( points[1].x = Context->FixedWidth; points[1].y = Context->ClientRect.bottom; SetDCPenColor(hdc, RGB(0x77, 0x77, 0x77)); - SelectObject(hdc, GetStockObject(DC_PEN)); + SelectPen(hdc, GetStockPen(DC_PEN)); Polyline(hdc, points, 2); } @@ -5738,9 +5734,9 @@ VOID PhTnpDrawPlusMinusGlyph( savedDc = SaveDC(hdc); - SelectObject(hdc, GetStockObject(DC_PEN)); + SelectPen(hdc, GetStockPen(DC_PEN)); SetDCPenColor(hdc, RGB(0x55, 0x55, 0x55)); - SelectObject(hdc, GetStockObject(DC_BRUSH)); + SelectBrush(hdc, GetStockBrush(DC_BRUSH)); SetDCBrushColor(hdc, RGB(0xff, 0xff, 0xff)); width = Rect->right - Rect->left; @@ -5818,7 +5814,7 @@ VOID PhTnpDrawSelectionRectangle( // Fill in the selection rectangle. - oldBitmap = SelectObject(tempDc, bitmap); + oldBitmap = SelectBitmap(tempDc, bitmap); tempRect.left = 0; tempRect.top = 0; tempRect.right = 1; @@ -5846,8 +5842,8 @@ VOID PhTnpDrawSelectionRectangle( drewWithAlpha = TRUE; - SelectObject(tempDc, oldBitmap); - DeleteObject(bitmap); + SelectBitmap(tempDc, oldBitmap); + DeleteBitmap(bitmap); } DeleteDC(tempDc); @@ -5973,7 +5969,7 @@ VOID PhTnpInitializeTooltips( SetWindowLongPtr(Context->HeaderHandle, GWLP_WNDPROC, (LONG_PTR)PhTnpHeaderHookWndProc); SendMessage(Context->TooltipsHandle, TTM_SETMAXTIPWIDTH, 0, MAXSHORT); // no limit - SendMessage(Context->TooltipsHandle, WM_SETFONT, (WPARAM)Context->Font, FALSE); + SetWindowFont(Context->TooltipsHandle, Context->Font, FALSE); Context->TooltipFont = Context->Font; } @@ -6096,7 +6092,7 @@ BOOLEAN PhTnpPrepareTooltipShow( if (Context->TooltipFont != Context->NewTooltipFont) { Context->TooltipFont = Context->NewTooltipFont; - SendMessage(Context->TooltipsHandle, WM_SETFONT, (WPARAM)Context->TooltipFont, FALSE); + SetWindowFont(Context->TooltipsHandle, Context->TooltipFont, FALSE); } if (!Context->TooltipUnfolding) @@ -6234,7 +6230,7 @@ VOID PhTnpGetHeaderTooltipText( if (!(hdc = GetDC(Context->Handle))) return; - SelectObject(hdc, Context->Font); + SelectFont(hdc, Context->Font); result = GetTextExtentPoint32(hdc, text, (ULONG)textCount, &textSize); ReleaseDC(Context->Handle, hdc); @@ -6813,7 +6809,7 @@ VOID PhTnpCreateBufferedContext( } ReleaseDC(Context->Handle, hdc); - Context->BufferedOldBitmap = SelectObject(Context->BufferedContext, Context->BufferedBitmap); + Context->BufferedOldBitmap = SelectBitmap(Context->BufferedContext, Context->BufferedBitmap); } } @@ -6823,8 +6819,8 @@ VOID PhTnpDestroyBufferedContext( { // The original bitmap must be selected back into the context, otherwise the bitmap can't be // deleted. - SelectObject(Context->BufferedContext, Context->BufferedOldBitmap); - DeleteObject(Context->BufferedBitmap); + SelectBitmap(Context->BufferedContext, Context->BufferedOldBitmap); + DeleteBitmap(Context->BufferedBitmap); DeleteDC(Context->BufferedContext); Context->BufferedContext = NULL; diff --git a/plugins/ExtendedTools/disktab.c b/plugins/ExtendedTools/disktab.c index d4b793233cea..63923fedf3c8 100644 --- a/plugins/ExtendedTools/disktab.c +++ b/plugins/ExtendedTools/disktab.c @@ -209,7 +209,7 @@ BOOLEAN EtpDiskPageCallback( HFONT font = (HFONT)Parameter1; if (DiskTreeNewHandle) - SendMessage(DiskTreeNewHandle, WM_SETFONT, (WPARAM)Parameter1, TRUE); + SetWindowFont(DiskTreeNewHandle, font, TRUE); } break; } diff --git a/plugins/ExtendedTools/etwprprp.c b/plugins/ExtendedTools/etwprprp.c index f2efc7ff5a19..07a36ccd62d9 100644 --- a/plugins/ExtendedTools/etwprprp.c +++ b/plugins/ExtendedTools/etwprprp.c @@ -398,7 +398,7 @@ INT_PTR CALLBACK EtwDiskNetworkPageDlgProc( )); hdc = Graph_GetBufferedContext(context->DiskGraphHandle); - SelectObject(hdc, PhApplicationFont); + SelectFont(hdc, PhApplicationFont); PhSetGraphText(hdc, drawInfo, &context->DiskGraphState.Text->sr, &NormalGraphTextMargin, &NormalGraphTextPadding, PH_ALIGN_TOP | PH_ALIGN_LEFT); } @@ -466,7 +466,7 @@ INT_PTR CALLBACK EtwDiskNetworkPageDlgProc( )); hdc = Graph_GetBufferedContext(context->NetworkGraphHandle); - SelectObject(hdc, PhApplicationFont); + SelectFont(hdc, PhApplicationFont); PhSetGraphText(hdc, drawInfo, &context->NetworkGraphState.Text->sr, &NormalGraphTextMargin, &NormalGraphTextPadding, PH_ALIGN_TOP | PH_ALIGN_LEFT); } diff --git a/plugins/ExtendedTools/etwsys.c b/plugins/ExtendedTools/etwsys.c index cce7f436d5fe..e10c96abba22 100644 --- a/plugins/ExtendedTools/etwsys.c +++ b/plugins/ExtendedTools/etwsys.c @@ -201,7 +201,7 @@ INT_PTR CALLBACK EtpDiskDialogProc( graphItem = PhAddLayoutItem(&DiskLayoutManager, GetDlgItem(hwndDlg, IDC_GRAPH_LAYOUT), NULL, PH_ANCHOR_ALL); panelItem = PhAddLayoutItem(&DiskLayoutManager, GetDlgItem(hwndDlg, IDC_PANEL_LAYOUT), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); - SendMessage(GetDlgItem(hwndDlg, IDC_TITLE), WM_SETFONT, (WPARAM)DiskSection->Parameters->LargeFont, FALSE); + SetWindowFont(GetDlgItem(hwndDlg, IDC_TITLE), DiskSection->Parameters->LargeFont, FALSE); DiskPanel = CreateDialog(PluginInstance->DllBase, MAKEINTRESOURCE(IDD_SYSINFO_DISKPANEL), hwndDlg, EtpDiskPanelDialogProc); ShowWindow(DiskPanel, SW_SHOW); @@ -577,7 +577,7 @@ INT_PTR CALLBACK EtpNetworkDialogProc( graphItem = PhAddLayoutItem(&NetworkLayoutManager, GetDlgItem(hwndDlg, IDC_GRAPH_LAYOUT), NULL, PH_ANCHOR_ALL); panelItem = PhAddLayoutItem(&NetworkLayoutManager, GetDlgItem(hwndDlg, IDC_PANEL_LAYOUT), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); - SendMessage(GetDlgItem(hwndDlg, IDC_TITLE), WM_SETFONT, (WPARAM)NetworkSection->Parameters->LargeFont, FALSE); + SetWindowFont(GetDlgItem(hwndDlg, IDC_TITLE), NetworkSection->Parameters->LargeFont, FALSE); NetworkPanel = CreateDialog(PluginInstance->DllBase, MAKEINTRESOURCE(IDD_SYSINFO_NETPANEL), hwndDlg, EtpNetworkPanelDialogProc); ShowWindow(NetworkPanel, SW_SHOW); diff --git a/plugins/ExtendedTools/gpunodes.c b/plugins/ExtendedTools/gpunodes.c index 0938776422ec..5b4549ffcf7a 100644 --- a/plugins/ExtendedTools/gpunodes.c +++ b/plugins/ExtendedTools/gpunodes.c @@ -337,7 +337,7 @@ INT_PTR CALLBACK EtpGpuNodesDlgProc( } hdc = Graph_GetBufferedContext(GraphHandle[i]); - SelectObject(hdc, PhApplicationFont); + SelectFont(hdc, PhApplicationFont); PhSetGraphText(hdc, drawInfo, &GraphState[i].Text->sr, &NormalGraphTextMargin, &NormalGraphTextPadding, PH_ALIGN_TOP | PH_ALIGN_LEFT); } diff --git a/plugins/ExtendedTools/gpuprprp.c b/plugins/ExtendedTools/gpuprprp.c index db33d672acf3..57e6baad547b 100644 --- a/plugins/ExtendedTools/gpuprprp.c +++ b/plugins/ExtendedTools/gpuprprp.c @@ -600,7 +600,7 @@ INT_PTR CALLBACK EtpGpuPageDlgProc( )); hdc = Graph_GetBufferedContext(context->GpuGraphHandle); - SelectObject(hdc, PhApplicationFont); + SelectFont(hdc, PhApplicationFont); PhSetGraphText(hdc, drawInfo, &context->GpuGraphState.Text->sr, &NormalGraphTextMargin, &NormalGraphTextPadding, PH_ALIGN_TOP | PH_ALIGN_LEFT); } @@ -631,7 +631,7 @@ INT_PTR CALLBACK EtpGpuPageDlgProc( )); hdc = Graph_GetBufferedContext(context->MemGraphHandle); - SelectObject(hdc, PhApplicationFont); + SelectFont(hdc, PhApplicationFont); PhSetGraphText( hdc, drawInfo, @@ -685,7 +685,7 @@ INT_PTR CALLBACK EtpGpuPageDlgProc( )); hdc = Graph_GetBufferedContext(context->SharedGraphHandle); - SelectObject(hdc, PhApplicationFont); + SelectFont(hdc, PhApplicationFont); PhSetGraphText(hdc, drawInfo, &context->MemorySharedGraphState.Text->sr, &NormalGraphTextMargin, &NormalGraphTextPadding, PH_ALIGN_TOP | PH_ALIGN_LEFT); } @@ -733,7 +733,7 @@ INT_PTR CALLBACK EtpGpuPageDlgProc( )); hdc = Graph_GetBufferedContext(context->CommittedGraphHandle); - SelectObject(hdc, PhApplicationFont); + SelectFont(hdc, PhApplicationFont); PhSetGraphText(hdc, drawInfo, &context->GpuCommittedGraphState.Text->sr, &NormalGraphTextMargin, &NormalGraphTextPadding, PH_ALIGN_TOP | PH_ALIGN_LEFT); } diff --git a/plugins/ExtendedTools/gpusys.c b/plugins/ExtendedTools/gpusys.c index 290d699bc766..ab0e6ac14417 100644 --- a/plugins/ExtendedTools/gpusys.c +++ b/plugins/ExtendedTools/gpusys.c @@ -198,8 +198,8 @@ INT_PTR CALLBACK EtpGpuDialogProc( GpuGraphMargin = graphItem->Margin; panelItem = PhAddLayoutItem(&GpuLayoutManager, GetDlgItem(hwndDlg, IDC_PANEL_LAYOUT), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); - SendMessage(GetDlgItem(hwndDlg, IDC_TITLE), WM_SETFONT, (WPARAM)GpuSection->Parameters->LargeFont, FALSE); - SendMessage(GetDlgItem(hwndDlg, IDC_GPUNAME), WM_SETFONT, (WPARAM)GpuSection->Parameters->MediumFont, FALSE); + SetWindowFont(GetDlgItem(hwndDlg, IDC_TITLE), GpuSection->Parameters->LargeFont, FALSE); + SetWindowFont(GetDlgItem(hwndDlg, IDC_GPUNAME), GpuSection->Parameters->MediumFont, FALSE); PhSetDialogItemText(hwndDlg, IDC_GPUNAME, ((PPH_STRING)PH_AUTO(EtpGetGpuNameString()))->Buffer); diff --git a/plugins/ExtendedTools/iconext.c b/plugins/ExtendedTools/iconext.c index 4c510b47de06..a863806317bf 100644 --- a/plugins/ExtendedTools/iconext.c +++ b/plugins/ExtendedTools/iconext.c @@ -323,7 +323,7 @@ VOID EtpGpuIconUpdateCallback( if (bits) PhDrawGraphDirect(hdc, bits, &drawInfo); - SelectObject(hdc, oldBitmap); + SelectBitmap(hdc, oldBitmap); *NewIconOrBitmap = bitmap; *Flags = PH_NF_UPDATE_IS_BITMAP; @@ -450,7 +450,7 @@ VOID EtpDiskIconUpdateCallback( if (bits) PhDrawGraphDirect(hdc, bits, &drawInfo); - SelectObject(hdc, oldBitmap); + SelectBitmap(hdc, oldBitmap); *NewIconOrBitmap = bitmap; *Flags = PH_NF_UPDATE_IS_BITMAP; @@ -576,7 +576,7 @@ VOID EtpNetworkIconUpdateCallback( if (bits) PhDrawGraphDirect(hdc, bits, &drawInfo); - SelectObject(hdc, oldBitmap); + SelectBitmap(hdc, oldBitmap); *NewIconOrBitmap = bitmap; *Flags = PH_NF_UPDATE_IS_BITMAP; @@ -676,7 +676,7 @@ VOID EtpGpuTextIconUpdateCallback( PhDrawTrayIconText(hdc, bits, &drawInfo, &text->sr); PhDereferenceObject(text); - SelectObject(hdc, oldBitmap); + SelectBitmap(hdc, oldBitmap); *NewIconOrBitmap = bitmap; *Flags = PH_NF_UPDATE_IS_BITMAP; @@ -756,7 +756,7 @@ VOID EtpDiskTextIconUpdateCallback( PhDrawTrayIconText(hdc, bits, &drawInfo, &text->sr); PhDereferenceObject(text); - SelectObject(hdc, oldBitmap); + SelectBitmap(hdc, oldBitmap); *NewIconOrBitmap = bitmap; *Flags = PH_NF_UPDATE_IS_BITMAP; @@ -834,7 +834,7 @@ VOID EtpNetworkTextIconUpdateCallback( PhDrawTrayIconText(hdc, bits, &drawInfo, &text->sr); PhDereferenceObject(text); - SelectObject(hdc, oldBitmap); + SelectBitmap(hdc, oldBitmap); *NewIconOrBitmap = bitmap; *Flags = PH_NF_UPDATE_IS_BITMAP; diff --git a/plugins/HardwareDevices/diskgraph.c b/plugins/HardwareDevices/diskgraph.c index 36deb6a9d8b7..9a52e3104d00 100644 --- a/plugins/HardwareDevices/diskgraph.c +++ b/plugins/HardwareDevices/diskgraph.c @@ -201,8 +201,8 @@ INT_PTR CALLBACK DiskDriveDialogProc( graphItem = PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_GRAPH_LAYOUT), NULL, PH_ANCHOR_ALL); panelItem = PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_LAYOUT), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); - SendMessage(GetDlgItem(hwndDlg, IDC_DISKMOUNTPATH), WM_SETFONT, (WPARAM)context->SysinfoSection->Parameters->LargeFont, FALSE); - SendMessage(GetDlgItem(hwndDlg, IDC_DISKNAME), WM_SETFONT, (WPARAM)context->SysinfoSection->Parameters->MediumFont, FALSE); + SetWindowFont(GetDlgItem(hwndDlg, IDC_DISKMOUNTPATH), context->SysinfoSection->Parameters->LargeFont, FALSE); + SetWindowFont(GetDlgItem(hwndDlg, IDC_DISKNAME), context->SysinfoSection->Parameters->MediumFont, FALSE); if (context->DiskEntry->DiskIndexName) PhSetDialogItemText(hwndDlg, IDC_DISKMOUNTPATH, context->DiskEntry->DiskIndexName->Buffer); diff --git a/plugins/HardwareDevices/netgraph.c b/plugins/HardwareDevices/netgraph.c index 03886dc9a208..710311bf4918 100644 --- a/plugins/HardwareDevices/netgraph.c +++ b/plugins/HardwareDevices/netgraph.c @@ -248,7 +248,7 @@ INT_PTR CALLBACK NetAdapterDialogProc( graphItem = PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_GRAPH_LAYOUT), NULL, PH_ANCHOR_ALL); panelItem = PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_LAYOUT), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); - SendMessage(GetDlgItem(hwndDlg, IDC_ADAPTERNAME), WM_SETFONT, (WPARAM)context->SysinfoSection->Parameters->LargeFont, FALSE); + SetWindowFont(GetDlgItem(hwndDlg, IDC_ADAPTERNAME), context->SysinfoSection->Parameters->LargeFont, FALSE); PhSetDialogItemText(hwndDlg, IDC_ADAPTERNAME, PhGetStringOrDefault(context->AdapterEntry->AdapterName, L"Unknown network adapter")); context->PanelWindowHandle = CreateDialogParam(PluginInstance->DllBase, MAKEINTRESOURCE(IDD_NETADAPTER_PANEL), hwndDlg, NetAdapterPanelDialogProc, (LPARAM)context); diff --git a/plugins/NetworkTools/country.c b/plugins/NetworkTools/country.c index d4a3cbf9988d..2860876ec4e2 100644 --- a/plugins/NetworkTools/country.c +++ b/plugins/NetworkTools/country.c @@ -496,22 +496,20 @@ INT LookupCountryIcon( { HBITMAP countryBitmap; - countryBitmap = PhLoadPngImageFromResource( - PluginInstance->DllBase, + if (countryBitmap = PhLoadPngImageFromResource( + PluginInstance->DllBase, 16, - 11, - MAKEINTRESOURCE(CountryResourceTable[i].ResourceID), + 11, + MAKEINTRESOURCE(CountryResourceTable[i].ResourceID), TRUE - ); - - if (countryBitmap) + )) { CountryResourceTable[i].IconIndex = ImageList_Add( GeoImageList, countryBitmap, NULL ); - DeleteObject(countryBitmap); + DeleteBitmap(countryBitmap); } } diff --git a/plugins/NetworkTools/ping.c b/plugins/NetworkTools/ping.c index 7052ad24fac9..93ba2c7a0213 100644 --- a/plugins/NetworkTools/ping.c +++ b/plugins/NetworkTools/ping.c @@ -379,7 +379,7 @@ INT_PTR CALLBACK NetworkPingWndProc( DestroyWindow(context->PingGraphHandle); if (context->FontHandle) - DeleteObject(context->FontHandle); + DeleteFont(context->FontHandle); PhDeleteWorkQueue(&context->PingWorkQueue); PhDeleteGraphState(&context->PingGraphState); @@ -450,7 +450,7 @@ INT_PTR CALLBACK NetworkPingWndProc( PhFormatString(L"%lu ms", context->CurrentPingMs) ); - SelectObject(hdc, PhApplicationFont); + SelectFont(hdc, PhApplicationFont); PhSetGraphText(hdc, drawInfo, &context->PingGraphState.Text->sr, &NormalGraphTextMargin, &NormalGraphTextPadding, PH_ALIGN_TOP | PH_ALIGN_LEFT); } diff --git a/plugins/NetworkTools/tracert.c b/plugins/NetworkTools/tracert.c index 76d2963ad56e..42cc17b3f75d 100644 --- a/plugins/NetworkTools/tracert.c +++ b/plugins/NetworkTools/tracert.c @@ -633,7 +633,7 @@ INT_PTR CALLBACK TracertDlgProc( PhSaveWindowPlacementToSetting(SETTING_NAME_TRACERT_WINDOW_POSITION, SETTING_NAME_TRACERT_WINDOW_SIZE, hwndDlg); if (context->FontHandle) - DeleteObject(context->FontHandle); + DeleteFont(context->FontHandle); DeleteTracertTree(context); diff --git a/plugins/ToolStatus/customizesb.c b/plugins/ToolStatus/customizesb.c index 2c2a8421f594..36abceb230b9 100644 --- a/plugins/ToolStatus/customizesb.c +++ b/plugins/ToolStatus/customizesb.c @@ -308,7 +308,7 @@ INT_PTR CALLBACK CustomizeStatusBarDialogProc( context->MoveDownButtonHandle = GetDlgItem(hwndDlg, IDC_MOVEDOWN); context->AddButtonHandle = GetDlgItem(hwndDlg, IDC_ADD); context->RemoveButtonHandle = GetDlgItem(hwndDlg, IDC_REMOVE); - context->FontHandle = PhDuplicateFont((HFONT)SendMessage(StatusBarHandle, WM_GETFONT, 0, 0)); + context->FontHandle = PhDuplicateFont(GetWindowFont(StatusBarHandle)); ListBox_SetItemHeight(context->AvailableListHandle, 0, PH_SCALE_DPI(22)); // BitmapHeight ListBox_SetItemHeight(context->CurrentListHandle, 0, PH_SCALE_DPI(22)); // BitmapHeight @@ -326,7 +326,7 @@ INT_PTR CALLBACK CustomizeStatusBarDialogProc( if (context->FontHandle) { - DeleteObject(context->FontHandle); + DeleteFont(context->FontHandle); } } break; @@ -631,4 +631,4 @@ VOID StatusBarShowCustomizeDialog( PhMainWndHandle, CustomizeStatusBarDialogProc ); -} \ No newline at end of file +} diff --git a/plugins/ToolStatus/customizetb.c b/plugins/ToolStatus/customizetb.c index 259b2e21325f..11eb0edae83b 100644 --- a/plugins/ToolStatus/customizetb.c +++ b/plugins/ToolStatus/customizetb.c @@ -252,7 +252,7 @@ VOID CustomizeFreeToolbarItems( { if (button->IconHandle) { - DeleteObject(button->IconHandle); + DestroyIcon(button->IconHandle); } PhFree(button); @@ -268,7 +268,7 @@ VOID CustomizeFreeToolbarItems( { if (button->IconHandle) { - DeleteObject(button->IconHandle); + DestroyIcon(button->IconHandle); } PhFree(button); @@ -445,7 +445,7 @@ HICON CustomizeGetToolbarIcon( bitmapHandle = ToolbarGetImage(CommandID); iconHandle = CommonBitmapToIcon(bitmapHandle, Context->CXWidth, Context->CXWidth); - DeleteObject(bitmapHandle); + DeleteBitmap(bitmapHandle); return iconHandle; } @@ -470,7 +470,7 @@ VOID CustomizeResetToolbarImages( NULL ); - DeleteObject(bitmap); + DeleteBitmap(bitmap); } } } @@ -524,7 +524,7 @@ INT_PTR CALLBACK CustomizeToolbarDialogProc( context->BrushNormal = GetSysColorBrush(COLOR_WINDOW); context->BrushHot = CreateSolidBrush(RGB(145, 201, 247)); context->BrushPushed = CreateSolidBrush(RGB(153, 209, 255)); - context->FontHandle = PhDuplicateFont((HFONT)SendMessage(ToolBarHandle, WM_GETFONT, 0, 0)); + context->FontHandle = PhDuplicateFont(GetWindowFont(ToolBarHandle)); ListBox_SetItemHeight(context->AvailableListHandle, 0, context->CXWidth + 6); // BitmapHeight ListBox_SetItemHeight(context->CurrentListHandle, 0, context->CXWidth + 6); // BitmapHeight @@ -542,13 +542,13 @@ INT_PTR CALLBACK CustomizeToolbarDialogProc( CustomizeFreeToolbarItems(context); if (context->BrushHot) - DeleteObject(context->BrushHot); + DeleteBrush(context->BrushHot); if (context->BrushPushed) - DeleteObject(context->BrushPushed); + DeleteBrush(context->BrushPushed); if (context->FontHandle) - DeleteObject(context->FontHandle); + DeleteBrush(context->FontHandle); } break; case WM_COMMAND: @@ -958,4 +958,4 @@ VOID ToolBarShowCustomizeDialog( PhMainWndHandle, CustomizeToolbarDialogProc ); -} \ No newline at end of file +} diff --git a/plugins/ToolStatus/main.c b/plugins/ToolStatus/main.c index 31662d2102bf..f1e3e5d89bbc 100644 --- a/plugins/ToolStatus/main.c +++ b/plugins/ToolStatus/main.c @@ -938,7 +938,7 @@ LRESULT CALLBACK MainWndSubclassProc( NULL ); - DeleteObject(buttonImage); + DeleteBitmap(buttonImage); } break; } diff --git a/plugins/ToolStatus/statusbar.c b/plugins/ToolStatus/statusbar.c index d5a1f77c1318..7cb7ad9e0a28 100644 --- a/plugins/ToolStatus/statusbar.c +++ b/plugins/ToolStatus/statusbar.c @@ -253,7 +253,7 @@ VOID StatusBarUpdate( } hdc = GetDC(StatusBarHandle); - SelectObject(hdc, (HFONT)SendMessage(StatusBarHandle, WM_GETFONT, 0, 0)); + SelectFont(hdc, GetWindowFont(StatusBarHandle)); // Reset max. widths for Max. CPU Process and Max. I/O Process parts once in a while. { diff --git a/plugins/ToolStatus/toolbar.c b/plugins/ToolStatus/toolbar.c index 6fd37f3ff337..d7fd59dbc891 100644 --- a/plugins/ToolStatus/toolbar.c +++ b/plugins/ToolStatus/toolbar.c @@ -115,10 +115,9 @@ VOID RebarLoadSettings( HFONT newFont; - if (newFont = ToolStatusGetTreeWindowFont()) + if (newFont = (HFONT)SendMessage(PhMainWndHandle, WM_PH_GET_FONT, 0, 0)) { - if (ToolStatusWindowFont) - DeleteObject(ToolStatusWindowFont); + if (ToolStatusWindowFont) DeleteFont(ToolStatusWindowFont); ToolStatusWindowFont = newFont; } } @@ -161,7 +160,7 @@ VOID RebarLoadSettings( // Configure the toolbar imagelist. SendMessage(ToolBarHandle, TB_SETIMAGELIST, 0, (LPARAM)ToolBarImageList); // Configure the toolbar font. - SendMessage(ToolBarHandle, WM_SETFONT, (WPARAM)ToolStatusWindowFont, FALSE); + SetWindowFont(ToolBarHandle, ToolStatusWindowFont, FALSE); // Resize the toolbar. SendMessage(ToolBarHandle, TB_AUTOSIZE, 0, 0); @@ -706,7 +705,7 @@ VOID ToolbarLoadButtonSettings( NULL ); - DeleteObject(bitmap); + DeleteBitmap(bitmap); } break; } diff --git a/plugins/WindowExplorer/utils.c b/plugins/WindowExplorer/utils.c index 66d84f30007a..25abb5743a48 100644 --- a/plugins/WindowExplorer/utils.c +++ b/plugins/WindowExplorer/utils.c @@ -68,9 +68,8 @@ VOID WeInvertWindowBorder( HDC hdc; GetWindowRect(hWnd, &rect); - hdc = GetWindowDC(hWnd); - if (hdc) + if (hdc = GetWindowDC(hWnd)) { ULONG penWidth = GetSystemMetrics(SM_CXBORDER) * 3; INT oldDc; @@ -83,17 +82,16 @@ VOID WeInvertWindowBorder( SetROP2(hdc, R2_NOT); pen = CreatePen(PS_INSIDEFRAME, penWidth, RGB(0x00, 0x00, 0x00)); - SelectObject(hdc, pen); + SelectPen(hdc, pen); brush = GetStockObject(NULL_BRUSH); - SelectObject(hdc, brush); + SelectBrush(hdc, brush); // Draw the rectangle. Rectangle(hdc, 0, 0, rect.right - rect.left, rect.bottom - rect.top); // Cleanup. - DeleteObject(pen); - + DeletePen(pen); RestoreDC(hdc, oldDc); ReleaseDC(hWnd, hdc); } diff --git a/plugins/include/commonutil.h b/plugins/include/commonutil.h index 18f4aea48cd2..075300db272f 100644 --- a/plugins/include/commonutil.h +++ b/plugins/include/commonutil.h @@ -46,7 +46,7 @@ CommonBitmapToIcon( icon = CreateIconIndirect(&iconInfo); - DeleteObject(screenBitmap); + DeleteBitmap(screenBitmap); ReleaseDC(NULL, screenDc); return icon; @@ -104,4 +104,4 @@ FormatAnsiString( } -#endif \ No newline at end of file +#endif From 8911eb846d6d0c5afed323371eb9b0b2ba84b658 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 18 Jul 2019 02:52:38 +0200 Subject: [PATCH 1996/2058] Remove unused type --- phlib/include/phbase.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/phlib/include/phbase.h b/phlib/include/phbase.h index 47ef494ebe1f..910eaff0b60d 100644 --- a/phlib/include/phbase.h +++ b/phlib/include/phbase.h @@ -1,8 +1,6 @@ #ifndef _PH_PHBASE_H #define _PH_PHBASE_H -#pragma once - #ifndef PHLIB_NO_DEFAULT_LIB #pragma comment(lib, "ntdll.lib") #pragma comment(lib, "comctl32.lib") From 71aa65896059e128526136b80d37a130fc24b7a6 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 18 Jul 2019 02:53:43 +0200 Subject: [PATCH 1997/2058] Update default locale LCIDs --- phlib/util.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/phlib/util.c b/phlib/util.c index 45f6986b4eff..9b6922d0ef82 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -186,7 +186,7 @@ LCID PhGetSystemDefaultLCID( return localeId; } - return MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), SORT_DEFAULT); + return LOCALE_SYSTEM_DEFAULT; // MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), SORT_DEFAULT); } // rev from GetUserDefaultLCID @@ -202,7 +202,7 @@ LCID PhGetUserDefaultLCID( return localeId; } - return MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), SORT_DEFAULT); + return LOCALE_USER_DEFAULT; // MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), SORT_DEFAULT); } // rev from GetThreadLocale @@ -483,7 +483,7 @@ INT PhShowMessage2( INT result; va_list argptr; PPH_STRING message; - TASKDIALOGCONFIG config = { sizeof(config) }; + TASKDIALOGCONFIG config = { sizeof(TASKDIALOGCONFIG) }; va_start(argptr, Format); message = PhFormatString_V(Format, argptr); @@ -500,12 +500,12 @@ INT PhShowMessage2( config.pszMainInstruction = Title; config.pszContent = message->Buffer; - if (TaskDialogIndirect( + if (SUCCEEDED(TaskDialogIndirect( &config, &result, NULL, NULL - ) == S_OK) + ))) { PhDereferenceObject(message); return result; @@ -682,12 +682,12 @@ BOOLEAN PhShowConfirmMessage( config.pButtons = buttons; config.nDefaultButton = IDYES; - if (TaskDialogIndirect( + if (SUCCEEDED(TaskDialogIndirect( &config, &button, NULL, NULL - ) == S_OK) + ))) { return button == IDYES; } From 5fb507e1f3a939c9530914f2080f315dcdeb0d91 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 18 Jul 2019 02:57:26 +0200 Subject: [PATCH 1998/2058] ToolStatus: Fix font memory leak --- plugins/ToolStatus/graph.c | 3 +- plugins/ToolStatus/main.c | 80 +++++++++++---------------------- plugins/ToolStatus/toolstatus.h | 5 +-- 3 files changed, 31 insertions(+), 57 deletions(-) diff --git a/plugins/ToolStatus/graph.c b/plugins/ToolStatus/graph.c index eae8a7df2f63..73f957c752dc 100644 --- a/plugins/ToolStatus/graph.c +++ b/plugins/ToolStatus/graph.c @@ -295,6 +295,7 @@ VOID ToolbarUpdateGraphs( } BOOLEAN ToolbarUpdateGraphsInfo( + _In_ HWND WindowHandle, _In_ LPNMHDR Header ) { @@ -308,7 +309,7 @@ BOOLEAN ToolbarUpdateGraphsInfo( if (mouseEvent->Message == WM_RBUTTONUP) { - ShowCustomizeMenu(); + ShowCustomizeMenu(WindowHandle); } } diff --git a/plugins/ToolStatus/main.c b/plugins/ToolStatus/main.c index f1e3e5d89bbc..22f2d1753d48 100644 --- a/plugins/ToolStatus/main.c +++ b/plugins/ToolStatus/main.c @@ -199,7 +199,7 @@ HWND GetCurrentTreeNewHandle( } VOID ShowCustomizeMenu( - VOID + _In_ HWND WindowHandle ) { POINT cursorPos; @@ -234,7 +234,7 @@ VOID ShowCustomizeMenu( selectedItem = PhShowEMenu( menu, - PhMainWndHandle, + WindowHandle, PH_EMENU_SHOW_LEFTRIGHT, PH_ALIGN_LEFT | PH_ALIGN_TOP, cursorPos.x, @@ -253,12 +253,12 @@ VOID ShowCustomizeMenu( if (ToolStatusConfig.AutoHideMenu) { - SetMenu(PhMainWndHandle, NULL); + SetMenu(WindowHandle, NULL); } else { - SetMenu(PhMainWndHandle, MainMenu); - DrawMenuBar(PhMainWndHandle); + SetMenu(WindowHandle, MainMenu); + DrawMenuBar(WindowHandle); } } break; @@ -275,7 +275,7 @@ VOID ShowCustomizeMenu( { // Adding the Searchbox makes it focused, // reset the focus back to the main window. - SetFocus(PhMainWndHandle); + SetFocus(WindowHandle); } } break; @@ -569,40 +569,13 @@ VOID DrawWindowBorderForTargeting( Rectangle(hdc, 0, 0, rect.right - rect.left, rect.bottom - rect.top); // Cleanup. - DeleteObject(pen); + DeletePen(pen); RestoreDC(hdc, oldDc); ReleaseDC(hWnd, hdc); } } -HFONT ToolStatusGetTreeWindowFont( - VOID - ) -{ - PPH_STRING fontHexString; - LOGFONT font; - - fontHexString = PhaGetStringSetting(L"Font"); - - if ( - fontHexString->Length / sizeof(WCHAR) / 2 == sizeof(LOGFONT) && - PhHexStringToBuffer(&fontHexString->sr, (PUCHAR)&font) - ) - { - HFONT newFont; - - newFont = CreateFontIndirect(&font); - - if (newFont) - { - return newFont; - } - } - - return NULL; -} - LRESULT CALLBACK MainWndSubclassProc( _In_ HWND hWnd, _In_ UINT uMsg, @@ -748,7 +721,7 @@ LRESULT CALLBACK MainWndSubclassProc( case RBN_HEIGHTCHANGE: { // Invoke the LayoutPaddingCallback. - SendMessage(PhMainWndHandle, WM_SIZE, 0, 0); + SendMessage(hWnd, WM_SIZE, 0, 0); } break; case RBN_CHEVRONPUSHED: @@ -873,7 +846,7 @@ LRESULT CALLBACK MainWndSubclassProc( if (selectedItem && selectedItem->Id != ULONG_MAX) { - SendMessage(PhMainWndHandle, WM_COMMAND, MAKEWPARAM(selectedItem->Id, BN_CLICKED), 0); + SendMessage(hWnd, WM_COMMAND, MAKEWPARAM(selectedItem->Id, BN_CLICKED), 0); } PhDestroyEMenu(menu); @@ -991,7 +964,7 @@ LRESULT CALLBACK MainWndSubclassProc( if (selectedItem && selectedItem->Id != ULONG_MAX) { - SendMessage(PhMainWndHandle, WM_COMMAND, MAKEWPARAM(selectedItem->Id, BN_CLICKED), 0); + SendMessage(hWnd, WM_COMMAND, MAKEWPARAM(selectedItem->Id, BN_CLICKED), 0); } PhDestroyEMenu(menu); @@ -1028,7 +1001,7 @@ LRESULT CALLBACK MainWndSubclassProc( break; case NM_RCLICK: { - ShowCustomizeMenu(); + ShowCustomizeMenu(hWnd); } break; case NM_CUSTOMDRAW: @@ -1055,7 +1028,7 @@ LRESULT CALLBACK MainWndSubclassProc( if ( ToolStatusConfig.ToolBarEnabled && ToolBarHandle && - ToolbarUpdateGraphsInfo(hdr) + ToolbarUpdateGraphsInfo(hWnd, hdr) ) { goto DefaultWndProc; @@ -1119,7 +1092,7 @@ LRESULT CALLBACK MainWndSubclassProc( SetCursor(LoadCursor(NULL, IDC_ARROW)); // Bring the window back to the top, and preserve the Always on Top setting. - SetWindowPos(PhMainWndHandle, PhGetIntegerSetting(L"MainWindowAlwaysOnTop") ? HWND_TOPMOST : HWND_TOP, + SetWindowPos(hWnd, PhGetIntegerSetting(L"MainWindowAlwaysOnTop") ? HWND_TOPMOST : HWND_TOP, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE); TargetingWindow = FALSE; @@ -1232,7 +1205,7 @@ LRESULT CALLBACK MainWndSubclassProc( } } - SetWindowPos(PhMainWndHandle, PhGetIntegerSetting(L"MainWindowAlwaysOnTop") ? HWND_TOPMOST : HWND_TOP, + SetWindowPos(hWnd, PhGetIntegerSetting(L"MainWindowAlwaysOnTop") ? HWND_TOPMOST : HWND_TOP, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE); TargetingCompleted = TRUE; @@ -1259,14 +1232,14 @@ LRESULT CALLBACK MainWndSubclassProc( if (!ToolStatusConfig.AutoHideMenu) break; - if (GetMenu(PhMainWndHandle)) + if (GetMenu(hWnd)) { - SetMenu(PhMainWndHandle, NULL); + SetMenu(hWnd, NULL); } else { - SetMenu(PhMainWndHandle, MainMenu); - DrawMenuBar(PhMainWndHandle); + SetMenu(hWnd, MainMenu); + DrawMenuBar(hWnd); } } else if ((wParam & 0xFFF0) == SC_MINIMIZE) @@ -1287,30 +1260,31 @@ LRESULT CALLBACK MainWndSubclassProc( if (!ToolStatusConfig.AutoHideMenu) break; - if (GetMenu(PhMainWndHandle)) + if (GetMenu(hWnd)) { - SetMenu(PhMainWndHandle, NULL); + SetMenu(hWnd, NULL); } } break; - case PHAPP_WM_PLUGIN_UPDATE_FONT: + case WM_PH_UPDATE_FONT: { HFONT newFont; // Let Process Hacker perform the default processing. CallWindowProc(MainWindowHookProc, hWnd, uMsg, wParam, lParam); - if (newFont = ToolStatusGetTreeWindowFont()) + if (newFont = (HFONT)SendMessage(hWnd, WM_PH_GET_FONT, 0, 0)) { - if (ToolStatusWindowFont) - DeleteObject(ToolStatusWindowFont); + if (ToolStatusWindowFont) DeleteFont(ToolStatusWindowFont); ToolStatusWindowFont = newFont; - SendMessage(ToolBarHandle, WM_SETFONT, (WPARAM)ToolStatusWindowFont, TRUE); - SendMessage(StatusBarHandle, WM_SETFONT, (WPARAM)ToolStatusWindowFont, TRUE); + SetWindowFont(ToolBarHandle, ToolStatusWindowFont, TRUE); + SetWindowFont(StatusBarHandle, ToolStatusWindowFont, TRUE); ToolbarLoadSettings(); } + + goto DefaultWndProc; } break; } diff --git a/plugins/ToolStatus/toolstatus.h b/plugins/ToolStatus/toolstatus.h index 46e92337cd5a..6273182ad47f 100644 --- a/plugins/ToolStatus/toolstatus.h +++ b/plugins/ToolStatus/toolstatus.h @@ -212,7 +212,7 @@ HFONT ToolStatusGetTreeWindowFont( ); VOID ShowCustomizeMenu( - VOID + _In_ HWND WindowHandle ); // options.c @@ -296,6 +296,7 @@ VOID ToolbarUpdateGraphs( ); BOOLEAN ToolbarUpdateGraphsInfo( + _In_ HWND WindowHandle, _In_ LPNMHDR Header ); @@ -434,8 +435,6 @@ BOOLEAN CreateSearchboxControl( VOID ); -// extern HFONT ToolStatusWindowFont; -#define PHAPP_WM_PLUGIN_UPDATE_FONT (WM_APP + 136) #endif From 9553cc69e4a5b72d911d710ba8977f7698f4e1ab Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 18 Jul 2019 03:21:12 +0200 Subject: [PATCH 1999/2058] Fix duplicate tab font initialization --- ProcessHacker/include/mainwnd.h | 2 +- ProcessHacker/include/mainwndp.h | 6 ++--- ProcessHacker/mainwnd.c | 44 +++++++++++++++++--------------- 3 files changed, 27 insertions(+), 25 deletions(-) diff --git a/ProcessHacker/include/mainwnd.h b/ProcessHacker/include/mainwnd.h index 00d00fc281f9..c13d48d33056 100644 --- a/ProcessHacker/include/mainwnd.h +++ b/ProcessHacker/include/mainwnd.h @@ -27,9 +27,9 @@ extern BOOLEAN PhMainWndExiting; #define WM_PH_SELECT_PROCESS_NODE (WM_APP + 133) #define WM_PH_SELECT_SERVICE_ITEM (WM_APP + 134) #define WM_PH_SELECT_NETWORK_ITEM (WM_APP + 135) -// end_phapppub #define WM_PH_UPDATE_FONT (WM_APP + 136) #define WM_PH_GET_FONT (WM_APP + 137) +// end_phapppub // begin_phapppub #define WM_PH_INVOKE (WM_APP + 138) // WM_PH_DEPRECATED (WM_APP + 139) diff --git a/ProcessHacker/include/mainwndp.h b/ProcessHacker/include/mainwndp.h index 9a9f779cbfa2..c75ed4a4849f 100644 --- a/ProcessHacker/include/mainwndp.h +++ b/ProcessHacker/include/mainwndp.h @@ -126,15 +126,15 @@ ULONG_PTR PhMwpOnUserMessage( // Settings VOID PhMwpLoadSettings( - VOID + _In_ HWND WindowHandle ); VOID PhMwpSaveSettings( - VOID + _In_ HWND WindowHandle ); VOID PhMwpSaveWindowState( - VOID + _In_ HWND WindowHandle ); // Misc. diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index 64d3e4a93746..92f6017468da 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -195,12 +195,12 @@ BOOLEAN PhMainWndInitialization( // Allow WM_PH_ACTIVATE to pass through UIPI. ChangeWindowMessageFilterEx(PhMainWndHandle, WM_PH_ACTIVATE, MSGFLT_ADD, NULL); - PhMwpOnSettingChange(); - // Initialize child controls. PhMwpInitializeControls(PhMainWndHandle); - PhMwpLoadSettings(); + PhMwpOnSettingChange(); + + PhMwpLoadSettings(PhMainWndHandle); PhLogInitialization(); PhInitializeWindowTheme(PhMainWndHandle, PhEnableThemeSupport); // HACK @@ -415,7 +415,7 @@ VOID PhMwpInitializeControls( ULONG thinRows; ULONG treelistBorder; ULONG treelistCustomColors; - PH_TREENEW_CREATEPARAMS treelistCreateParams; + PH_TREENEW_CREATEPARAMS treelistCreateParams = { 0 }; thinRows = PhGetIntegerSetting(L"ThinRows") ? TN_STYLE_THIN_ROWS : 0; treelistBorder = (PhGetIntegerSetting(L"TreeListBorderEnable") && !PhEnableThemeSupport) ? WS_BORDER : 0; @@ -441,7 +441,6 @@ VOID PhMwpInitializeControls( PhInstanceHandle, NULL ); - SendMessage(TabControlHandle, WM_SETFONT, (WPARAM)PhApplicationFont, FALSE); PhMwpProcessTreeNewHandle = CreateWindow( PH_TREENEW_CLASSNAME, @@ -563,7 +562,10 @@ VOID PhMwpOnSettingChange( { PhInitializeFont(); - SendMessage(TabControlHandle, WM_SETFONT, (WPARAM)PhApplicationFont, FALSE); + if (TabControlHandle) + { + SetWindowFont(TabControlHandle, PhApplicationFont, TRUE); + } } static NTSTATUS PhpOpenServiceControlManager( @@ -1054,7 +1056,7 @@ VOID PhMwpOnCommand( { PhReferenceObject(processItem); - if (PhUiRestartProcess(PhMainWndHandle, processItem)) + if (PhUiRestartProcess(WindowHandle, processItem)) PhDeselectAllProcessNodes(); PhDereferenceObject(processItem); @@ -2256,7 +2258,7 @@ ULONG_PTR PhMwpOnUserMessage( if (newFont) { if (PhTreeWindowFont) - DeleteObject(PhTreeWindowFont); + DeleteFont(PhTreeWindowFont); PhTreeWindowFont = newFont; PhMwpNotifyAllPages(MainTabPageFontChanged, newFont, NULL); @@ -2265,7 +2267,7 @@ ULONG_PTR PhMwpOnUserMessage( } break; case WM_PH_GET_FONT: - return SendMessage(PhMwpProcessTreeNewHandle, WM_GETFONT, 0, 0); + return (ULONG_PTR)GetWindowFont(PhMwpProcessTreeNewHandle); case WM_PH_INVOKE: { VOID (NTAPI *function)(PVOID); @@ -2308,7 +2310,7 @@ ULONG_PTR PhMwpOnUserMessage( } VOID PhMwpLoadSettings( - VOID + _In_ HWND WindowHandle ) { ULONG opacity; @@ -2331,23 +2333,23 @@ VOID PhMwpLoadSettings( if (PhGetIntegerSetting(L"MainWindowAlwaysOnTop")) { AlwaysOnTop = TRUE; - SetWindowPos(PhMainWndHandle, HWND_TOPMOST, 0, 0, 0, 0, + SetWindowPos(WindowHandle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOREDRAW | SWP_NOSIZE); } if (opacity != 0) - PhSetWindowOpacity(PhMainWndHandle, opacity); + PhSetWindowOpacity(WindowHandle, opacity); PhNfLoadStage1(); if (customFont->Length / sizeof(WCHAR) / 2 == sizeof(LOGFONT)) - SendMessage(PhMainWndHandle, WM_PH_UPDATE_FONT, 0, 0); + SendMessage(WindowHandle, WM_PH_UPDATE_FONT, 0, 0); PhMwpNotifyAllPages(MainTabPageLoadSettings, NULL, NULL); } VOID PhMwpSaveSettings( - VOID + _In_ HWND WindowHandle ) { PhMwpNotifyAllPages(MainTabPageSaveSettings, NULL, NULL); @@ -2355,20 +2357,20 @@ VOID PhMwpSaveSettings( PhNfSaveSettings(); PhSetIntegerSetting(L"IconNotifyMask", PhMwpNotifyIconNotifyMask); - PhSaveWindowPlacementToSetting(L"MainWindowPosition", L"MainWindowSize", PhMainWndHandle); - PhMwpSaveWindowState(); + PhSaveWindowPlacementToSetting(L"MainWindowPosition", L"MainWindowSize", WindowHandle); + PhMwpSaveWindowState(WindowHandle); if (PhSettingsFileName) PhSaveSettings(PhSettingsFileName->Buffer); } VOID PhMwpSaveWindowState( - VOID + _In_ HWND WindowHandle ) { WINDOWPLACEMENT placement = { sizeof(placement) }; - GetWindowPlacement(PhMainWndHandle, &placement); + GetWindowPlacement(WindowHandle, &placement); if (placement.showCmd == SW_NORMAL) PhSetIntegerSetting(L"MainWindowState", SW_NORMAL); @@ -2538,7 +2540,7 @@ VOID PhMwpDispatchMenuCommand( if (menuItem) { - PhPluginInitializeMenuInfo(&menuInfo, NULL, PhMainWndHandle, 0); + PhPluginInitializeMenuInfo(&menuInfo, NULL, WindowHandle, 0); PhPluginTriggerEMenuItem(&menuInfo, menuItem); } @@ -2581,7 +2583,7 @@ VOID PhMwpDispatchMenuCommand( break; case ID_VIEW_ORGANIZECOLUMNSETS: { - PhShowColumnSetEditorDialog(PhMainWndHandle, L"ProcessTreeColumnSetConfig"); + PhShowColumnSetEditorDialog(WindowHandle, L"ProcessTreeColumnSetConfig"); } return; case ID_VIEW_SAVECOLUMNSET: @@ -2592,7 +2594,7 @@ VOID PhMwpDispatchMenuCommand( menuItem = (PPH_EMENU_ITEM)ItemData; while (PhaChoiceDialog( - PhMainWndHandle, + WindowHandle, L"Column Set Name", L"Enter a name for this column set:", NULL, From 7d638dc5dba3cf2df4b8a1011fcbe0d3fe4d3216 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 18 Jul 2019 03:26:09 +0200 Subject: [PATCH 2000/2058] Add missing files from previous commit --- ProcessHacker/include/mainwndp.h | 4 ++-- ProcessHacker/mainwnd.c | 16 ++++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/ProcessHacker/include/mainwndp.h b/ProcessHacker/include/mainwndp.h index c75ed4a4849f..8be6ecafb14c 100644 --- a/ProcessHacker/include/mainwndp.h +++ b/ProcessHacker/include/mainwndp.h @@ -56,11 +56,11 @@ NTSTATUS PhMwpLoadStage1Worker( // Event handlers VOID PhMwpOnDestroy( - VOID + _In_ HWND WindowHandle ); VOID PhMwpOnEndSession( - VOID + _In_ HWND WindowHandle ); VOID PhMwpOnSettingChange( diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index 92f6017468da..cb6f0161fada 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -272,12 +272,12 @@ LRESULT CALLBACK PhMwpWndProc( { case WM_DESTROY: { - PhMwpOnDestroy(); + PhMwpOnDestroy(hWnd); } break; case WM_ENDSESSION: { - PhMwpOnEndSession(); + PhMwpOnEndSession(hWnd); } break; case WM_SETTINGCHANGE: @@ -527,7 +527,7 @@ NTSTATUS PhMwpLoadStage1Worker( } VOID PhMwpOnDestroy( - VOID + _In_ HWND WindowHandle ) { PhMainWndExiting = TRUE; @@ -542,7 +542,7 @@ VOID PhMwpOnDestroy( PhUnloadPlugins(); if (!PhMainWndEarlyExit) - PhMwpSaveSettings(); + PhMwpSaveSettings(WindowHandle); PhNfUninitialization(); @@ -550,10 +550,10 @@ VOID PhMwpOnDestroy( } VOID PhMwpOnEndSession( - VOID + _In_ HWND WindowHandle ) { - PhMwpOnDestroy(); + PhMwpOnDestroy(WindowHandle); } VOID PhMwpOnSettingChange( @@ -2125,12 +2125,12 @@ ULONG_PTR PhMwpOnUserMessage( break; case WM_PH_SAVE_ALL_SETTINGS: { - PhMwpSaveSettings(); + PhMwpSaveSettings(WindowHandle); } break; case WM_PH_PREPARE_FOR_EARLY_SHUTDOWN: { - PhMwpSaveSettings(); + PhMwpSaveSettings(WindowHandle); PhMainWndEarlyExit = TRUE; } break; From fd2b6c4357b705a47b09ba7232b9b00ef5d68022 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 18 Jul 2019 07:58:18 +0200 Subject: [PATCH 2001/2058] Add custom RunFileDialog, Update Run menu options --- ProcessHacker/ProcessHacker.rc | 20 +- ProcessHacker/include/phapp.h | 9 + ProcessHacker/mainwnd.c | 341 +---------------------- ProcessHacker/runas.c | 485 +++++++++++++++++++++++++++++++++ phlib/guisup.c | 40 --- phlib/include/guisup.h | 12 - 6 files changed, 514 insertions(+), 393 deletions(-) diff --git a/ProcessHacker/ProcessHacker.rc b/ProcessHacker/ProcessHacker.rc index c228dc149c9a..33a08b00949b 100644 --- a/ProcessHacker/ProcessHacker.rc +++ b/ProcessHacker/ProcessHacker.rc @@ -77,7 +77,6 @@ BEGIN POPUP "&Hacker" BEGIN MENUITEM "&Run...\aCtrl+R", ID_HACKER_RUN - MENUITEM "Run as ad&ministrator...", ID_HACKER_RUNASADMINISTRATOR MENUITEM "Run &as...\aCtrl+Shift+R", ID_HACKER_RUNAS MENUITEM "Show &details for all processes", ID_HACKER_SHOWDETAILSFORALLPROCESSES MENUITEM SEPARATOR @@ -1713,6 +1712,22 @@ BEGIN CONTROL "",IDC_COLUMNSETLIST,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_EDITLABELS | LVS_ALIGNLEFT | LVS_NOCOLUMNHEADER | WS_BORDER | WS_TABSTOP,4,4,170,180 END +IDD_RUNFILEDLG DIALOGEX 0, 0, 235, 105 +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Run" +FONT 9, "Segoe UI", 0, 0, 0x1 +BEGIN + ICON 100,IDC_FILEICON,7,11,18,17 + LTEXT "Type the name of a program, folder, document, or Internet resource, and Windows will open it for you.",IDC_STATIC,36,11,182,22 + LTEXT "&Open:",IDC_STATIC,7,39,28,10 + COMBOBOX IDC_PROGRAMCOMBO,36,37,183,200,CBS_DROPDOWN | CBS_AUTOHSCROLL | CBS_DISABLENOSCROLL | WS_VSCROLL | WS_TABSTOP + CONTROL "Create this task with administrative privileges.",IDC_TOGGLEELEVATION, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,40,50,180,10 + DEFPUSHBUTTON "OK",IDOK,62,82,50,14 + PUSHBUTTON "Cancel",IDCANCEL,116,82,50,14 + PUSHBUTTON "&Browse...",IDC_BROWSE,170,82,50,14 +END + ///////////////////////////////////////////////////////////////////////////// // @@ -2259,6 +2274,9 @@ BEGIN TOPMARGIN, 4 BOTTOMMARGIN, 184 END + IDD_RUNFILEDLG, DIALOG + BEGIN + END END #endif // APSTUDIO_INVOKED diff --git a/ProcessHacker/include/phapp.h b/ProcessHacker/include/phapp.h index 756e91426188..f82ea5c57dcd 100644 --- a/ProcessHacker/include/phapp.h +++ b/ProcessHacker/include/phapp.h @@ -559,6 +559,15 @@ VOID PhShowRunAsDialog( _In_opt_ HANDLE ProcessId ); +// begin_phapppub +PHLIBAPI +BOOLEAN +NTAPI +PhShowRunFileDialog( + _In_ HWND ParentWindowHandle + ); +// end_phapppub + NTSTATUS PhExecuteRunAsCommand( _In_ PPH_RUNAS_SERVICE_PARAMETERS Parameters ); diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index cb6f0161fada..8661a4aa0a0b 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -24,7 +24,6 @@ #include #include -#include #include #include @@ -607,41 +606,9 @@ VOID PhMwpOnCommand( break; case ID_HACKER_RUN: { - ULONG flags = RFF_OPTRUNAS; - if (PhGetIntegerSetting(L"RunDlgHideRunAsAdministrator")) - { - flags = 0; - } - SelectedRunAsMode = 0; - PhShowRunFileDialog(WindowHandle, NULL, NULL, NULL, NULL, flags); + PhShowRunFileDialog(WindowHandle); } break; - case ID_HACKER_RUNASADMINISTRATOR: - { - SelectedRunAsMode = RUNAS_MODE_ADMIN; - PhShowRunFileDialog( - WindowHandle, - NULL, - NULL, - NULL, - L"Type the name of a program that will be opened with administrative credentials.", - 0 - ); - } - break; - //case ID_HACKER_RUNASLIMITEDUSER: - // { - // SelectedRunAsMode = RUNAS_MODE_LIMITED; - // PhShowRunFileDialog( - // WindowHandle, - // NULL, - // NULL, - // NULL, - // L"Type the name of a program that will be opened under standard user privileges.", - // 0 - // ); - // } - // break; case ID_HACKER_RUNAS: { PhShowRunAsDialog(WindowHandle, NULL); @@ -1764,312 +1731,6 @@ BOOLEAN PhMwpOnNotify( { PhMwpNotifyTabControl(Header); } - else if (Header->code == RFN_VALIDATE) - { - LPNMRUNFILEDLG runFileDlg = (LPNMRUNFILEDLG)Header; - - if (SelectedRunAsMode == RUNAS_MODE_ADMIN || - // The explorer runas dialog executes programs as administrator when holding ctrl/shift keys - // and clicking the OK button, so we'll implement the same functionality. (dmex) - (!!(GetKeyState(VK_CONTROL) < 0 && !!(GetKeyState(VK_SHIFT) < 0)))) - { - PH_STRINGREF string; - PH_STRINGREF fileName; - PH_STRINGREF arguments; - PPH_STRING fullFileName; - PPH_STRING argumentsString; - - PhInitializeStringRefLongHint(&string, runFileDlg->lpszFile); - PhParseCommandLineFuzzy(&string, &fileName, &arguments, &fullFileName); - - if (!fullFileName) - fullFileName = PhCreateString2(&fileName); - - argumentsString = PhCreateString2(&arguments); - - if (PhShellExecuteEx( - PhMainWndHandle, - fullFileName->Buffer, - argumentsString->Buffer, - runFileDlg->ShowCmd, - PH_SHELL_EXECUTE_ADMIN, - 0, - NULL - )) - { - *Result = RF_CANCEL; - } - else - { - *Result = RF_RETRY; - } - - PhDereferenceObject(fullFileName); - PhDereferenceObject(argumentsString); - - return TRUE; - } - //else if (SelectedRunAsMode == RUNAS_MODE_LIMITED) - //{ - // NTSTATUS status; - // HANDLE tokenHandle; - // HANDLE newTokenHandle; - // - // if (NT_SUCCESS(status = PhOpenProcessToken( - // NtCurrentProcess(), - // TOKEN_ASSIGN_PRIMARY | TOKEN_DUPLICATE | TOKEN_QUERY | TOKEN_ADJUST_GROUPS | - // TOKEN_ADJUST_DEFAULT | READ_CONTROL | WRITE_DAC, - // &tokenHandle - // ))) - // { - // if (NT_SUCCESS(status = PhFilterTokenForLimitedUser( - // tokenHandle, - // &newTokenHandle - // ))) - // { - // status = PhCreateProcessWin32( - // NULL, - // runFileDlg->lpszFile, - // NULL, - // NULL, - // 0, - // newTokenHandle, - // NULL, - // NULL - // ); - // - // NtClose(newTokenHandle); - // } - // - // NtClose(tokenHandle); - // } - // - // if (NT_SUCCESS(status)) - // { - // *Result = RF_CANCEL; - // } - // else - // { - // PhShowStatus(PhMainWndHandle, L"Unable to execute the program.", status, 0); - // *Result = RF_RETRY; - // } - // - // return TRUE; - //} - } - else if (Header->code == RFN_LIMITEDRUNAS) - { - LPNMRUNFILEDLG runFileDlg = (LPNMRUNFILEDLG)Header; - NTSTATUS status = STATUS_UNSUCCESSFUL; - ULONG processId = ULONG_MAX; - HANDLE processHandle = NULL; - HANDLE newProcessHandle; - HANDLE tokenHandle; - HWND shellWindow; - STARTUPINFOEX startupInfo; - SIZE_T attributeListLength = 0; - PVOID environment = NULL; - ULONG flags = 0; - - memset(&startupInfo, 0, sizeof(STARTUPINFOEX)); - startupInfo.StartupInfo.cb = sizeof(STARTUPINFOEX); - startupInfo.StartupInfo.dwFlags = STARTF_USESHOWWINDOW; - startupInfo.StartupInfo.wShowWindow = SW_SHOWNORMAL; - - if (!(shellWindow = GetShellWindow())) - { - PVOID wdcLibraryHandle; - - if (wdcLibraryHandle = LoadLibrary(L"wdc.dll")) - { - ULONG (WINAPI* WdcRunTaskAsInteractiveUser_I)( - _In_ PCWSTR CommandLine, - _In_ PCWSTR CurrentDirectory, - _In_ ULONG Reserved - ); - - if (WdcRunTaskAsInteractiveUser_I = PhGetDllBaseProcedureAddress(wdcLibraryHandle, "WdcRunTaskAsInteractiveUser", 0)) - { - PH_STRINGREF string; - PPH_STRING commandlineString; - PPH_STRING executeString = NULL; - INT cmdlineArgCount; - PWSTR* cmdlineArgList; - - PhInitializeStringRefLongHint(&string, (PWSTR)runFileDlg->lpszFile); - commandlineString = PhCreateString2(&string); - - // Extract the filename. - if (cmdlineArgList = CommandLineToArgvW(commandlineString->Buffer, &cmdlineArgCount)) - { - PPH_STRING fileName = PhCreateString(cmdlineArgList[0]); - - if (fileName && !PhDoesFileExistsWin32(fileName->Buffer)) - { - PPH_STRING filePathString; - - // The user typed a name without a path so attempt to locate the executable. - if (filePathString = PhSearchFilePath(fileName->Buffer, L".exe")) - PhMoveReference(&fileName, filePathString); - else - PhClearReference(&fileName); - } - - if (fileName) - { - // Escape the filename. - PhMoveReference(&fileName, PhConcatStrings(3, L"\"", fileName->Buffer, L"\"")); - - if (cmdlineArgCount == 2) - { - PPH_STRING fileArgs = PhCreateString(cmdlineArgList[1]); - - // Escape the parameters. - PhMoveReference(&fileArgs, PhConcatStrings(3, L"\"", fileArgs->Buffer, L"\"")); - - // Create the escaped execute string. - PhMoveReference(&executeString, PhConcatStrings(3, fileName->Buffer, L" ", fileArgs->Buffer)); - - // Cleanup. - PhDereferenceObject(fileArgs); - } - else - { - // Create the escaped execute string. - executeString = PhReferenceObject(fileName); - } - - PhDereferenceObject(fileName); - } - - LocalFree(cmdlineArgList); - } - - if (!PhIsNullOrEmptyString(executeString)) - { - if (WdcRunTaskAsInteractiveUser_I(executeString->Buffer, NULL, 0) == 0) - status = STATUS_SUCCESS; - else - status = STATUS_UNSUCCESSFUL; - } - else - { - status = STATUS_UNSUCCESSFUL; - } - - PhClearReference(&executeString); - PhClearReference(&commandlineString); - } - - FreeLibrary(wdcLibraryHandle); - } - - goto CleanupExit; - } - - GetWindowThreadProcessId(shellWindow, &processId); - - if (processId == ULONG_MAX) - { - status = STATUS_UNSUCCESSFUL; - goto CleanupExit; - } - - status = PhOpenProcess( - &processHandle, - PROCESS_CREATE_PROCESS, - UlongToHandle(processId) - ); - - if (!NT_SUCCESS(status)) - goto CleanupExit; - - if (!InitializeProcThreadAttributeList(NULL, 1, 0, &attributeListLength) && GetLastError() != ERROR_INSUFFICIENT_BUFFER) - { - status = PhGetLastWin32ErrorAsNtStatus(); - goto CleanupExit; - } - - startupInfo.lpAttributeList = PhAllocate(attributeListLength); - - if (!InitializeProcThreadAttributeList(startupInfo.lpAttributeList, 1, 0, &attributeListLength)) - { - status = PhGetLastWin32ErrorAsNtStatus(); - goto CleanupExit; - } - - if (!UpdateProcThreadAttribute(startupInfo.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, &(HANDLE){ processHandle }, sizeof(HANDLE), NULL, NULL)) - { - status = PhGetLastWin32ErrorAsNtStatus(); - goto CleanupExit; - } - - if (NT_SUCCESS(PhOpenProcessToken(processHandle, TOKEN_QUERY, &tokenHandle))) - { - if (CreateEnvironmentBlock && CreateEnvironmentBlock(&environment, tokenHandle, FALSE)) - { - flags |= PH_CREATE_PROCESS_UNICODE_ENVIRONMENT; - } - - NtClose(tokenHandle); - } - - status = PhCreateProcessWin32Ex( - NULL, - runFileDlg->lpszFile, - environment, - NULL, - &startupInfo.StartupInfo, - PH_CREATE_PROCESS_SUSPENDED | PH_CREATE_PROCESS_NEW_CONSOLE | PH_CREATE_PROCESS_EXTENDED_STARTUPINFO | flags, - NULL, - NULL, - &newProcessHandle, - NULL - ); - - if (NT_SUCCESS(status)) - { - PROCESS_BASIC_INFORMATION basicInfo; - - if (NT_SUCCESS(PhGetProcessBasicInformation(newProcessHandle, &basicInfo))) - { - AllowSetForegroundWindow(HandleToUlong(basicInfo.UniqueProcessId)); - } - - NtResumeProcess(newProcessHandle); - - NtClose(newProcessHandle); - } - - CleanupExit: - - if (environment && DestroyEnvironmentBlock) - { - DestroyEnvironmentBlock(environment); - } - - if (startupInfo.lpAttributeList) - { - DeleteProcThreadAttributeList(startupInfo.lpAttributeList); - PhFree(startupInfo.lpAttributeList); - } - - if (processHandle) - { - NtClose(processHandle); - } - - if (NT_SUCCESS(status)) - { - *Result = RF_CANCEL; - } - else - { - *Result = RF_RETRY; - } - - return TRUE; - } return FALSE; } diff --git a/ProcessHacker/runas.c b/ProcessHacker/runas.c index b62a2660e717..1e6f7feeb660 100644 --- a/ProcessHacker/runas.c +++ b/ProcessHacker/runas.c @@ -61,6 +61,7 @@ #include +#include #include #include #include @@ -155,6 +156,13 @@ INT_PTR CALLBACK PhpRunAsDlgProc( _In_ LPARAM lParam ); +INT_PTR CALLBACK PhpRunFileWndProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + VOID PhSetDesktopWinStaAccess( VOID ); @@ -197,6 +205,51 @@ VOID PhShowRunAsDialog( ); } +BOOLEAN PhShowRunFileDialog( + _In_ HWND ParentWindowHandle + ) +{ + if (DialogBox( + PhInstanceHandle, + MAKEINTRESOURCE(IDD_RUNFILEDLG), + ParentWindowHandle, + PhpRunFileWndProc + ) == IDOK) + { + return TRUE; + } + + return FALSE; + + // Removed from guisup.c (dmex) + //BOOL (WINAPI *RunFileDlg_I)( + // _In_ HWND hwndOwner, + // _In_opt_ HICON hIcon, + // _In_opt_ LPCWSTR lpszDirectory, + // _In_opt_ LPCWSTR lpszTitle, + // _In_opt_ LPCWSTR lpszDescription, + // _In_ ULONG uFlags + // ); + //PVOID shell32Handle; + // + //if (shell32Handle = LoadLibrary(L"shell32.dll")) + //{ + // if (RunFileDlg_I = PhGetDllBaseProcedureAddress(shell32Handle, NULL, 61)) + // { + // result = !!RunFileDlg_I( + // WindowHandle, + // WindowIcon, + // WorkingDirectory, + // WindowTitle, + // WindowDescription, + // Flags + // ); + // } + // + // FreeLibrary(shell32Handle); + //} +} + BOOLEAN IsServiceAccount( _In_ PPH_STRING UserName ) @@ -1868,3 +1921,435 @@ NTSTATUS PhInvokeRunAsService( return status; } + +typedef struct _PHP_RUNFILEDLG +{ + HWND ComboBoxHandle; + HWND RunAsCheckboxHandle; +} PHP_RUNFILEDLG, *PPHP_RUNFILEDLG; + +INT_PTR CALLBACK PhpRunFileWndProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + PPHP_RUNFILEDLG context = NULL; + + if (uMsg == WM_INITDIALOG) + { + context = PhAllocateZero(sizeof(PHP_RUNFILEDLG)); + + PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context); + } + else + { + context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); + + if (uMsg == WM_DESTROY) + { + PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); + } + } + + if (!context) + return FALSE; + + switch (uMsg) + { + case WM_INITDIALOG: + { + context->ComboBoxHandle = GetDlgItem(hwndDlg, IDC_PROGRAMCOMBO); + context->RunAsCheckboxHandle = GetDlgItem(hwndDlg, IDC_TOGGLEELEVATION); + + SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER))); + SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER))); + + PhpAddProgramsToComboBox(context->ComboBoxHandle); + ComboBox_SetCurSel(context->ComboBoxHandle, 0); + + { + COMBOBOXINFO info = { sizeof(COMBOBOXINFO) }; + + if (SendMessage(context->ComboBoxHandle, CB_GETCOMBOBOXINFO, 0, (LPARAM)& info)) + { + if (SHAutoComplete) + SHAutoComplete(info.hwndItem, SHACF_DEFAULT); + } + } + + Button_SetCheck(context->RunAsCheckboxHandle, PhGetIntegerSetting(L"RunFileDlgState") ? TRUE : FALSE); + } + break; + case WM_DESTROY: + { + PhSetIntegerSetting(L"RunFileDlgState", Button_GetCheck(context->RunAsCheckboxHandle) == BST_CHECKED); + + PhFree(context); + } + break; + case WM_CTLCOLORSTATIC: + { + HDC hdc = (HDC)wParam; + + SetBkMode(hdc, TRANSPARENT); + + return (INT_PTR)GetStockBrush(WHITE_BRUSH); + } + break; + case WM_ERASEBKGND: + { + HDC hdc = (HDC)wParam; + RECT clientRect; + + if (!GetClientRect(hwndDlg, &clientRect)) + break; + + SetBkMode(hdc, TRANSPARENT); + + clientRect.bottom -= PH_SCALE_DPI(60); + FillRect(hdc, &clientRect, GetSysColorBrush(COLOR_WINDOW)); + + clientRect.top = clientRect.bottom; + clientRect.bottom = clientRect.top + PH_SCALE_DPI(60); + FillRect(hdc, &clientRect, GetSysColorBrush(COLOR_3DFACE)); + + SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, TRUE); + } + return TRUE; + case WM_COMMAND: + { + switch (GET_WM_COMMAND_ID(wParam, lParam)) + { + case IDCANCEL: + EndDialog(hwndDlg, IDCANCEL); + break; + case IDOK: + { + PPH_STRING string = NULL; + PPH_STRING fullFileName = NULL; + PPH_STRING argumentsString = NULL; + PH_STRINGREF fileName; + PH_STRINGREF arguments; + FILE_BASIC_INFORMATION basicInfo; + BOOLEAN isDirectory = FALSE; + + if (!(string = PhGetWindowText(context->ComboBoxHandle))) + break; + + PhParseCommandLineFuzzy(&string->sr, &fileName, &arguments, &fullFileName); + + if (PhIsNullOrEmptyString(fullFileName)) + PhMoveReference(&fullFileName, PhCreateString2(&fileName)); + + if (PhIsNullOrEmptyString(fullFileName)) + { + PhDereferenceObject(string); + break; + } + + if (arguments.Length) + { + argumentsString = PhCreateString2(&arguments); + } + + if (NT_SUCCESS(PhQueryAttributesFileWin32(fullFileName->Buffer, &basicInfo))) + { + isDirectory = !!(basicInfo.FileAttributes & FILE_ATTRIBUTE_DIRECTORY); + } + + if (isDirectory) + { + if (PhShellExecuteEx( + hwndDlg, + fullFileName->Buffer, + PhGetString(argumentsString), + SW_SHOWNORMAL, + 0, + 0, + NULL + )) + { + PhpAddRunMRUListEntry(string); + + EndDialog(hwndDlg, IDOK); + } + } + else if (Button_GetCheck(context->RunAsCheckboxHandle) == BST_CHECKED || + // The explorer runas dialog executes programs as administrator when holding ctrl/shift keys + // and clicking the OK button, so we'll implement the same functionality. (dmex) + (!!(GetKeyState(VK_CONTROL) < 0 && !!(GetKeyState(VK_SHIFT) < 0)))) + { + if (PhShellExecuteEx( + hwndDlg, + fullFileName->Buffer, + PhGetString(argumentsString), + SW_SHOWNORMAL, + PH_SHELL_EXECUTE_ADMIN, + 0, + NULL + )) + { + PhpAddRunMRUListEntry(string); + + EndDialog(hwndDlg, IDOK); + } + } + else if (!PhDoesFileExistsWin32(fullFileName->Buffer)) + { + if (PhShellExecuteEx( + hwndDlg, + fullFileName->Buffer, + PhGetString(argumentsString), + SW_SHOWNORMAL, + 0, + 0, + NULL + )) + { + PhpAddRunMRUListEntry(string); + + EndDialog(hwndDlg, IDOK); + } + } + else + { + NTSTATUS status = STATUS_UNSUCCESSFUL; + ULONG processId = ULONG_MAX; + HANDLE processHandle = NULL; + HANDLE newProcessHandle; + HANDLE tokenHandle; + HWND shellWindow; + STARTUPINFOEX startupInfo; + SIZE_T attributeListLength = 0; + PVOID environment = NULL; + ULONG flags = 0; + + memset(&startupInfo, 0, sizeof(STARTUPINFOEX)); + startupInfo.StartupInfo.cb = sizeof(STARTUPINFOEX); + startupInfo.StartupInfo.dwFlags = STARTF_USESHOWWINDOW; + startupInfo.StartupInfo.wShowWindow = SW_SHOWNORMAL; + + if (!(shellWindow = GetShellWindow())) + { + PVOID wdcLibraryHandle; + + if (wdcLibraryHandle = LoadLibrary(L"wdc.dll")) + { + ULONG (WINAPI *WdcRunTaskAsInteractiveUser_I)( + _In_ PCWSTR CommandLine, + _In_ PCWSTR CurrentDirectory, + _In_ ULONG Reserved + ); + + if (WdcRunTaskAsInteractiveUser_I = PhGetDllBaseProcedureAddress(wdcLibraryHandle, "WdcRunTaskAsInteractiveUser", 0)) + { + PPH_STRING executeString = NULL; + INT cmdlineArgCount; + PWSTR* cmdlineArgList; + + // Extract the filename. + if (cmdlineArgList = CommandLineToArgvW(string->Buffer, &cmdlineArgCount)) + { + PPH_STRING fileName = PhCreateString(cmdlineArgList[0]); + + if (fileName && !PhDoesFileExistsWin32(fileName->Buffer)) + { + PPH_STRING filePathString; + + // The user typed a name without a path so attempt to locate the executable. + if (filePathString = PhSearchFilePath(fileName->Buffer, L".exe")) + PhMoveReference(&fileName, filePathString); + else + PhClearReference(&fileName); + } + + if (fileName) + { + // Escape the filename. + PhMoveReference(&fileName, PhConcatStrings(3, L"\"", fileName->Buffer, L"\"")); + + if (cmdlineArgCount == 2) + { + PPH_STRING fileArgs = PhCreateString(cmdlineArgList[1]); + + // Escape the parameters. + PhMoveReference(&fileArgs, PhConcatStrings(3, L"\"", fileArgs->Buffer, L"\"")); + + // Create the escaped execute string. + PhMoveReference(&executeString, PhConcatStrings(3, fileName->Buffer, L" ", fileArgs->Buffer)); + + // Cleanup. + PhDereferenceObject(fileArgs); + } + else + { + // Create the escaped execute string. + executeString = PhReferenceObject(fileName); + } + + PhDereferenceObject(fileName); + } + + LocalFree(cmdlineArgList); + } + + if (!PhIsNullOrEmptyString(executeString)) + { + if (WdcRunTaskAsInteractiveUser_I(executeString->Buffer, NULL, 0) == 0) + status = STATUS_SUCCESS; + else + status = STATUS_UNSUCCESSFUL; + } + else + { + status = STATUS_UNSUCCESSFUL; + } + + PhClearReference(&executeString); + } + + FreeLibrary(wdcLibraryHandle); + } + + goto CleanupExit; + } + + GetWindowThreadProcessId(shellWindow, &processId); + + if (processId == ULONG_MAX) + { + status = STATUS_UNSUCCESSFUL; + goto CleanupExit; + } + + status = PhOpenProcess( + &processHandle, + PROCESS_CREATE_PROCESS, + UlongToHandle(processId) + ); + + if (!NT_SUCCESS(status)) + goto CleanupExit; + + if (!InitializeProcThreadAttributeList(NULL, 1, 0, &attributeListLength) && GetLastError() != ERROR_INSUFFICIENT_BUFFER) + { + status = PhGetLastWin32ErrorAsNtStatus(); + goto CleanupExit; + } + + startupInfo.lpAttributeList = PhAllocate(attributeListLength); + + if (!InitializeProcThreadAttributeList(startupInfo.lpAttributeList, 1, 0, &attributeListLength)) + { + status = PhGetLastWin32ErrorAsNtStatus(); + goto CleanupExit; + } + + if (!UpdateProcThreadAttribute(startupInfo.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, &(HANDLE){ processHandle }, sizeof(HANDLE), NULL, NULL)) + { + status = PhGetLastWin32ErrorAsNtStatus(); + goto CleanupExit; + } + + if (NT_SUCCESS(PhOpenProcessToken(processHandle, TOKEN_QUERY, &tokenHandle))) + { + if (CreateEnvironmentBlock && CreateEnvironmentBlock(&environment, tokenHandle, FALSE)) + { + flags |= PH_CREATE_PROCESS_UNICODE_ENVIRONMENT; + } + + NtClose(tokenHandle); + } + + status = PhCreateProcessWin32Ex( + fullFileName->Buffer, + PhGetString(argumentsString), + environment, + NULL, + &startupInfo.StartupInfo, + PH_CREATE_PROCESS_SUSPENDED | PH_CREATE_PROCESS_NEW_CONSOLE | PH_CREATE_PROCESS_EXTENDED_STARTUPINFO | flags, + NULL, + NULL, + &newProcessHandle, + NULL + ); + + if (NT_SUCCESS(status)) + { + PROCESS_BASIC_INFORMATION basicInfo; + + if (NT_SUCCESS(PhGetProcessBasicInformation(newProcessHandle, &basicInfo))) + { + AllowSetForegroundWindow(HandleToUlong(basicInfo.UniqueProcessId)); + } + + NtResumeProcess(newProcessHandle); + + NtClose(newProcessHandle); + } + + CleanupExit: + + if (environment && DestroyEnvironmentBlock) + { + DestroyEnvironmentBlock(environment); + } + + if (startupInfo.lpAttributeList) + { + DeleteProcThreadAttributeList(startupInfo.lpAttributeList); + PhFree(startupInfo.lpAttributeList); + } + + if (processHandle) + { + NtClose(processHandle); + } + + if (NT_SUCCESS(status)) + { + PhpAddRunMRUListEntry(string); + + EndDialog(hwndDlg, IDOK); + } + } + + if (fullFileName) PhDereferenceObject(fullFileName); + if (argumentsString) PhDereferenceObject(argumentsString); + if (string) PhDereferenceObject(string); + } + break; + case IDC_BROWSE: + { + PH_FILETYPE_FILTER filters[] = + { + { L"Executable files (*.exe;*.pif;*.com;*.bat;*.cmd)", L"*.exe;*.pif;*.com;*.bat;*.cmd" }, + { L"All files (*.*)", L"*.*" } + }; + PVOID fileDialog = PhCreateOpenFileDialog(); + + PhSetFileDialogFilter(fileDialog, filters, RTL_NUMBER_OF(filters)); + + if (PhShowFileDialog(hwndDlg, fileDialog)) + { + PPH_STRING fileName; + + if (fileName = PhGetFileDialogFileName(fileDialog)) + { + ComboBox_SetText(GetDlgItem(hwndDlg, IDC_PROGRAMCOMBO), PhGetString(fileName)); + PhDereferenceObject(fileName); + } + } + + PhFreeFileDialog(fileDialog); + } + break; + } + } + break; + } + + return FALSE; +} diff --git a/phlib/guisup.c b/phlib/guisup.c index 671da01fada1..f3e5fdd6e6a9 100644 --- a/phlib/guisup.c +++ b/phlib/guisup.c @@ -1667,46 +1667,6 @@ VOID PhWindowNotifyTopMostEvent( PhReleaseQueuedLockExclusive(&WindowCallbackListLock); } -BOOLEAN PhShowRunFileDialog( - _In_ HWND WindowHandle, - _In_opt_ HICON WindowIcon, - _In_opt_ PWSTR WorkingDirectory, - _In_opt_ PWSTR WindowTitle, - _In_opt_ PWSTR WindowDescription, - _In_ ULONG Flags - ) -{ - BOOL (WINAPI *RunFileDlg_I)( - _In_ HWND hwndOwner, - _In_opt_ HICON hIcon, - _In_opt_ LPCWSTR lpszDirectory, - _In_opt_ LPCWSTR lpszTitle, - _In_opt_ LPCWSTR lpszDescription, - _In_ ULONG uFlags - ); - BOOLEAN result = FALSE; - PVOID shell32Handle; - - if (shell32Handle = LoadLibrary(L"shell32.dll")) - { - if (RunFileDlg_I = PhGetDllBaseProcedureAddress(shell32Handle, NULL, 61)) - { - result = !!RunFileDlg_I( - WindowHandle, - WindowIcon, - WorkingDirectory, - WindowTitle, - WindowDescription, - Flags - ); - } - - FreeLibrary(shell32Handle); - } - - return result; -} - HICON PhGetInternalWindowIcon( _In_ HWND WindowHandle, _In_ UINT Type diff --git a/phlib/include/guisup.h b/phlib/include/guisup.h index 6cce406f8ed4..bfea5fe03086 100644 --- a/phlib/include/guisup.h +++ b/phlib/include/guisup.h @@ -893,18 +893,6 @@ PhWindowNotifyTopMostEvent( _In_ BOOLEAN TopMost ); -PHLIBAPI -BOOLEAN -NTAPI -PhShowRunFileDialog( - _In_ HWND WindowHandle, - _In_opt_ HICON WindowIcon, - _In_opt_ PWSTR WorkingDirectory, - _In_opt_ PWSTR WindowTitle, - _In_opt_ PWSTR WindowDescription, - _In_ ULONG Flags - ); - // theme support (theme.c) PHLIBAPI extern HFONT PhApplicationFont; // phapppub From c96089fb758c0e26fc69c525f086a2bc835dbb68 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 18 Jul 2019 08:05:18 +0200 Subject: [PATCH 2002/2058] Fix build --- ProcessHacker/include/phapp.h | 4 +--- ProcessHacker/mainwnd.c | 2 +- ProcessHacker/resource.h | 1 + 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/ProcessHacker/include/phapp.h b/ProcessHacker/include/phapp.h index f82ea5c57dcd..ce37bc4f036a 100644 --- a/ProcessHacker/include/phapp.h +++ b/ProcessHacker/include/phapp.h @@ -1,8 +1,6 @@ #ifndef PHAPP_H #define PHAPP_H -#define PHNT_VERSION PHNT_WIN7 - #if !defined(_PHAPP_) #define PHAPPAPI __declspec(dllimport) #else @@ -697,7 +695,7 @@ PhCreateCommonFont( return NULL; if (hwnd) - SendMessage(hwnd, WM_SETFONT, (WPARAM)fontHandle, TRUE); + SetWindowFont(hwnd, fontHandle, TRUE); return fontHandle; } diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index 8661a4aa0a0b..571b187f478a 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -1581,7 +1581,7 @@ BOOLEAN PhMwpOnSysCommand( case SC_MINIMIZE: { // Save the current window state because we may not have a chance to later. - PhMwpSaveWindowState(); + PhMwpSaveWindowState(WindowHandle); if (PhGetIntegerSetting(L"HideOnMinimize") && PhNfIconsEnabled()) { diff --git a/ProcessHacker/resource.h b/ProcessHacker/resource.h index 35374aa7771e..45f750f01572 100644 --- a/ProcessHacker/resource.h +++ b/ProcessHacker/resource.h @@ -128,6 +128,7 @@ #define IDD_COLUMNSETS 243 #define ID_VIEW_TRAYICONS 244 #define IDD_OBJFILE 249 +#define IDD_RUNFILEDLG 253 #define IDC_TERMINATE 1003 #define IDC_FILEICON 1005 #define IDC_FILE 1006 From 0d8d945f9d14a2cbbb8fc56f81644ab5a4018a99 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 18 Jul 2019 08:43:20 +0200 Subject: [PATCH 2003/2058] Update settings.c --- ProcessHacker/settings.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ProcessHacker/settings.c b/ProcessHacker/settings.c index b313e8a42af4..176c0cf3ce31 100644 --- a/ProcessHacker/settings.c +++ b/ProcessHacker/settings.c @@ -150,7 +150,7 @@ VOID PhAddDefaultSettings( PhpAddIntegerSetting(L"PropagateCpuUsage", L"0"); PhpAddStringSetting(L"RunAsProgram", L""); PhpAddStringSetting(L"RunAsUserName", L""); - PhpAddIntegerSetting(L"RunDlgHideRunAsAdministrator", L"0"); + PhpAddIntegerSetting(L"RunFileDlgState", L"0"); PhpAddIntegerSetting(L"SampleCount", L"200"); // 512 PhpAddIntegerSetting(L"SampleCountAutomatic", L"1"); PhpAddIntegerSetting(L"ScrollToNewProcesses", L"0"); From aa359b981e2e3b0636580c5a34ed5f2adabaaa3f Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 18 Jul 2019 10:45:00 +0200 Subject: [PATCH 2004/2058] Fix #443 --- ProcessHacker/memsrch.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ProcessHacker/memsrch.c b/ProcessHacker/memsrch.c index 64277536e25c..4e8b50410167 100644 --- a/ProcessHacker/memsrch.c +++ b/ProcessHacker/memsrch.c @@ -489,6 +489,9 @@ VOID PhSearchMemoryString( baseAddress = PTR_ADD_OFFSET(baseAddress, basicInfo.RegionSize); } + if (displayBuffer) + PhFreePage(displayBuffer); + if (buffer) PhFreePage(buffer); } From 01155db32176f781b6f409efdf3931ba53d17b44 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 19 Jul 2019 04:02:47 +0200 Subject: [PATCH 2005/2058] Add error message to RunFileDialog --- ProcessHacker/runas.c | 589 ++++++++++++++++++++++-------------------- 1 file changed, 304 insertions(+), 285 deletions(-) diff --git a/ProcessHacker/runas.c b/ProcessHacker/runas.c index 1e6f7feeb660..eaee8cc55bc8 100644 --- a/ProcessHacker/runas.c +++ b/ProcessHacker/runas.c @@ -1924,10 +1924,303 @@ NTSTATUS PhInvokeRunAsService( typedef struct _PHP_RUNFILEDLG { + HWND WindowHandle; HWND ComboBoxHandle; HWND RunAsCheckboxHandle; } PHP_RUNFILEDLG, *PPHP_RUNFILEDLG; +BOOLEAN PhpRunFileAsInteractiveUser( + _In_ PPHP_RUNFILEDLG Context, + _In_ PPH_STRING Command + ) +{ + ULONG (WINAPI *WdcRunTaskAsInteractiveUser_I)( + _In_ PWSTR CommandLine, + _In_ PWSTR CurrentDirectory, + _In_ ULONG Reserved + ) = NULL; + BOOLEAN success = FALSE; + PVOID wdcLibraryHandle; + PPH_STRING executeString = NULL; + INT cmdlineArgCount; + PWSTR* cmdlineArgList; + + if (!(wdcLibraryHandle = LoadLibrary(L"wdc.dll"))) + return FALSE; + + if (!(WdcRunTaskAsInteractiveUser_I = PhGetDllBaseProcedureAddress(wdcLibraryHandle, "WdcRunTaskAsInteractiveUser", 0))) + { + FreeLibrary(wdcLibraryHandle); + return FALSE; + } + + // Extract the filename. + if (cmdlineArgList = CommandLineToArgvW(Command->Buffer, &cmdlineArgCount)) + { + PPH_STRING fileName = PhCreateString(cmdlineArgList[0]); + + if (fileName && !PhDoesFileExistsWin32(fileName->Buffer)) + { + PPH_STRING filePathString; + + // The user typed a name without a path so attempt to locate the executable. + if (filePathString = PhSearchFilePath(fileName->Buffer, L".exe")) + PhMoveReference(&fileName, filePathString); + else + PhClearReference(&fileName); + } + + if (fileName) + { + // Escape the filename. + PhMoveReference(&fileName, PhConcatStrings(3, L"\"", fileName->Buffer, L"\"")); + + if (cmdlineArgCount == 2) + { + PPH_STRING fileArgs = PhCreateString(cmdlineArgList[1]); + + // Escape the parameters. + PhMoveReference(&fileArgs, PhConcatStrings(3, L"\"", fileArgs->Buffer, L"\"")); + + // Create the escaped execute string. + PhMoveReference(&executeString, PhConcatStrings(3, fileName->Buffer, L" ", fileArgs->Buffer)); + + // Cleanup. + PhDereferenceObject(fileArgs); + } + else + { + // Create the escaped execute string. + executeString = PhReferenceObject(fileName); + } + + PhDereferenceObject(fileName); + } + + LocalFree(cmdlineArgList); + } + + if (!PhIsNullOrEmptyString(executeString)) + { + if (WdcRunTaskAsInteractiveUser_I(executeString->Buffer, NULL, 0) == 0) + success = TRUE; + } + + if (executeString) PhDereferenceObject(executeString); + FreeLibrary(wdcLibraryHandle); + + return success; +} + +BOOLEAN PhpRunFileProgram( + _In_ PPHP_RUNFILEDLG Context, + _In_ PPH_STRING Command + ) +{ + BOOLEAN success = FALSE; + PPH_STRING fullFileName = NULL; + PPH_STRING argumentsString = NULL; + PH_STRINGREF fileName; + PH_STRINGREF arguments; + FILE_BASIC_INFORMATION basicInfo; + BOOLEAN isDirectory = FALSE; + + PhParseCommandLineFuzzy(&Command->sr, &fileName, &arguments, &fullFileName); + + if (PhIsNullOrEmptyString(fullFileName)) + PhMoveReference(&fullFileName, PhCreateString2(&fileName)); + + if (PhIsNullOrEmptyString(fullFileName)) + { + return FALSE; + } + + if (arguments.Length) + { + argumentsString = PhCreateString2(&arguments); + } + + if (NT_SUCCESS(PhQueryAttributesFileWin32(fullFileName->Buffer, &basicInfo))) + { + isDirectory = !!(basicInfo.FileAttributes & FILE_ATTRIBUTE_DIRECTORY); + } + + if (isDirectory) + { + if (PhShellExecuteEx( + Context->WindowHandle, + fullFileName->Buffer, + PhGetString(argumentsString), + SW_SHOWNORMAL, + 0, + 0, + NULL + )) + { + success = TRUE; + } + } + else if (Button_GetCheck(Context->RunAsCheckboxHandle) == BST_CHECKED || + // The explorer runas dialog executes programs as administrator when holding ctrl/shift keys + // and clicking the OK button, so we'll implement the same functionality. (dmex) + (!!(GetKeyState(VK_CONTROL) < 0 && !!(GetKeyState(VK_SHIFT) < 0)))) + { + if (PhShellExecuteEx( + Context->WindowHandle, + fullFileName->Buffer, + PhGetString(argumentsString), + SW_SHOWNORMAL, + PH_SHELL_EXECUTE_ADMIN, + 0, + NULL + )) + { + success = TRUE; + } + } + else if (!PhDoesFileExistsWin32(fullFileName->Buffer)) + { + if (PhShellExecuteEx( + Context->WindowHandle, + fullFileName->Buffer, + PhGetString(argumentsString), + SW_SHOWNORMAL, + 0, + 0, + NULL + )) + { + success = TRUE; + } + } + else + { + NTSTATUS status = STATUS_UNSUCCESSFUL; + ULONG processId = ULONG_MAX; + HANDLE processHandle = NULL; + HANDLE newProcessHandle; + HANDLE tokenHandle; + HWND shellWindow; + STARTUPINFOEX startupInfo; + SIZE_T attributeListLength = 0; + PVOID environment = NULL; + ULONG flags = 0; + + memset(&startupInfo, 0, sizeof(STARTUPINFOEX)); + startupInfo.StartupInfo.cb = sizeof(STARTUPINFOEX); + startupInfo.StartupInfo.dwFlags = STARTF_USESHOWWINDOW; + startupInfo.StartupInfo.wShowWindow = SW_SHOWNORMAL; + + if (!(shellWindow = GetShellWindow())) + { + success = PhpRunFileAsInteractiveUser(Context, Command); + goto CleanupExit; + } + + GetWindowThreadProcessId(shellWindow, &processId); + + if (processId == ULONG_MAX) + { + status = STATUS_UNSUCCESSFUL; + goto CleanupExit; + } + + status = PhOpenProcess( + &processHandle, + PROCESS_CREATE_PROCESS, + UlongToHandle(processId) + ); + + if (!NT_SUCCESS(status)) + goto CleanupExit; + + if (!InitializeProcThreadAttributeList(NULL, 1, 0, &attributeListLength) && GetLastError() != ERROR_INSUFFICIENT_BUFFER) + { + status = PhGetLastWin32ErrorAsNtStatus(); + goto CleanupExit; + } + + startupInfo.lpAttributeList = PhAllocate(attributeListLength); + + if (!InitializeProcThreadAttributeList(startupInfo.lpAttributeList, 1, 0, &attributeListLength)) + { + status = PhGetLastWin32ErrorAsNtStatus(); + goto CleanupExit; + } + + if (!UpdateProcThreadAttribute(startupInfo.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, &(HANDLE){ processHandle }, sizeof(HANDLE), NULL, NULL)) + { + status = PhGetLastWin32ErrorAsNtStatus(); + goto CleanupExit; + } + + if (NT_SUCCESS(PhOpenProcessToken(processHandle, TOKEN_QUERY, &tokenHandle))) + { + if (CreateEnvironmentBlock && CreateEnvironmentBlock(&environment, tokenHandle, FALSE)) + { + flags |= PH_CREATE_PROCESS_UNICODE_ENVIRONMENT; + } + + NtClose(tokenHandle); + } + + status = PhCreateProcessWin32Ex( + fullFileName->Buffer, + PhGetString(argumentsString), + environment, + NULL, + &startupInfo.StartupInfo, + PH_CREATE_PROCESS_SUSPENDED | PH_CREATE_PROCESS_NEW_CONSOLE | PH_CREATE_PROCESS_EXTENDED_STARTUPINFO | flags, + NULL, + NULL, + &newProcessHandle, + NULL + ); + + if (NT_SUCCESS(status)) + { + PROCESS_BASIC_INFORMATION basicInfo; + + if (NT_SUCCESS(PhGetProcessBasicInformation(newProcessHandle, &basicInfo))) + { + AllowSetForegroundWindow(HandleToUlong(basicInfo.UniqueProcessId)); + } + + NtResumeProcess(newProcessHandle); + + NtClose(newProcessHandle); + } + + CleanupExit: + + if (environment && DestroyEnvironmentBlock) + { + DestroyEnvironmentBlock(environment); + } + + if (startupInfo.lpAttributeList) + { + DeleteProcThreadAttributeList(startupInfo.lpAttributeList); + PhFree(startupInfo.lpAttributeList); + } + + if (processHandle) + { + NtClose(processHandle); + } + + if (NT_SUCCESS(status)) + { + success = TRUE; + } + } + + if (fullFileName) PhDereferenceObject(fullFileName); + if (argumentsString) PhDereferenceObject(argumentsString); + + return success; +} + INT_PTR CALLBACK PhpRunFileWndProc( _In_ HWND hwndDlg, _In_ UINT uMsg, @@ -1960,12 +2253,13 @@ INT_PTR CALLBACK PhpRunFileWndProc( { case WM_INITDIALOG: { - context->ComboBoxHandle = GetDlgItem(hwndDlg, IDC_PROGRAMCOMBO); - context->RunAsCheckboxHandle = GetDlgItem(hwndDlg, IDC_TOGGLEELEVATION); - SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER))); SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER))); + context->WindowHandle = hwndDlg; + context->ComboBoxHandle = GetDlgItem(hwndDlg, IDC_PROGRAMCOMBO); + context->RunAsCheckboxHandle = GetDlgItem(hwndDlg, IDC_TOGGLEELEVATION); + PhpAddProgramsToComboBox(context->ComboBoxHandle); ComboBox_SetCurSel(context->ComboBoxHandle, 0); @@ -2027,298 +2321,23 @@ INT_PTR CALLBACK PhpRunFileWndProc( break; case IDOK: { - PPH_STRING string = NULL; - PPH_STRING fullFileName = NULL; - PPH_STRING argumentsString = NULL; - PH_STRINGREF fileName; - PH_STRINGREF arguments; - FILE_BASIC_INFORMATION basicInfo; - BOOLEAN isDirectory = FALSE; - - if (!(string = PhGetWindowText(context->ComboBoxHandle))) - break; - - PhParseCommandLineFuzzy(&string->sr, &fileName, &arguments, &fullFileName); - - if (PhIsNullOrEmptyString(fullFileName)) - PhMoveReference(&fullFileName, PhCreateString2(&fileName)); - - if (PhIsNullOrEmptyString(fullFileName)) - { - PhDereferenceObject(string); - break; - } - - if (arguments.Length) - { - argumentsString = PhCreateString2(&arguments); - } + PPH_STRING commandString; - if (NT_SUCCESS(PhQueryAttributesFileWin32(fullFileName->Buffer, &basicInfo))) + if (commandString = PhGetWindowText(context->ComboBoxHandle)) { - isDirectory = !!(basicInfo.FileAttributes & FILE_ATTRIBUTE_DIRECTORY); - } - - if (isDirectory) - { - if (PhShellExecuteEx( - hwndDlg, - fullFileName->Buffer, - PhGetString(argumentsString), - SW_SHOWNORMAL, - 0, - 0, - NULL - )) - { - PhpAddRunMRUListEntry(string); - - EndDialog(hwndDlg, IDOK); - } - } - else if (Button_GetCheck(context->RunAsCheckboxHandle) == BST_CHECKED || - // The explorer runas dialog executes programs as administrator when holding ctrl/shift keys - // and clicking the OK button, so we'll implement the same functionality. (dmex) - (!!(GetKeyState(VK_CONTROL) < 0 && !!(GetKeyState(VK_SHIFT) < 0)))) - { - if (PhShellExecuteEx( - hwndDlg, - fullFileName->Buffer, - PhGetString(argumentsString), - SW_SHOWNORMAL, - PH_SHELL_EXECUTE_ADMIN, - 0, - NULL - )) + if (PhpRunFileProgram(context, commandString)) { - PhpAddRunMRUListEntry(string); + PhpAddRunMRUListEntry(commandString); EndDialog(hwndDlg, IDOK); } - } - else if (!PhDoesFileExistsWin32(fullFileName->Buffer)) - { - if (PhShellExecuteEx( - hwndDlg, - fullFileName->Buffer, - PhGetString(argumentsString), - SW_SHOWNORMAL, - 0, - 0, - NULL - )) - { - PhpAddRunMRUListEntry(string); - - EndDialog(hwndDlg, IDOK); - } - } - else - { - NTSTATUS status = STATUS_UNSUCCESSFUL; - ULONG processId = ULONG_MAX; - HANDLE processHandle = NULL; - HANDLE newProcessHandle; - HANDLE tokenHandle; - HWND shellWindow; - STARTUPINFOEX startupInfo; - SIZE_T attributeListLength = 0; - PVOID environment = NULL; - ULONG flags = 0; - - memset(&startupInfo, 0, sizeof(STARTUPINFOEX)); - startupInfo.StartupInfo.cb = sizeof(STARTUPINFOEX); - startupInfo.StartupInfo.dwFlags = STARTF_USESHOWWINDOW; - startupInfo.StartupInfo.wShowWindow = SW_SHOWNORMAL; - - if (!(shellWindow = GetShellWindow())) - { - PVOID wdcLibraryHandle; - - if (wdcLibraryHandle = LoadLibrary(L"wdc.dll")) - { - ULONG (WINAPI *WdcRunTaskAsInteractiveUser_I)( - _In_ PCWSTR CommandLine, - _In_ PCWSTR CurrentDirectory, - _In_ ULONG Reserved - ); - - if (WdcRunTaskAsInteractiveUser_I = PhGetDllBaseProcedureAddress(wdcLibraryHandle, "WdcRunTaskAsInteractiveUser", 0)) - { - PPH_STRING executeString = NULL; - INT cmdlineArgCount; - PWSTR* cmdlineArgList; - - // Extract the filename. - if (cmdlineArgList = CommandLineToArgvW(string->Buffer, &cmdlineArgCount)) - { - PPH_STRING fileName = PhCreateString(cmdlineArgList[0]); - - if (fileName && !PhDoesFileExistsWin32(fileName->Buffer)) - { - PPH_STRING filePathString; - - // The user typed a name without a path so attempt to locate the executable. - if (filePathString = PhSearchFilePath(fileName->Buffer, L".exe")) - PhMoveReference(&fileName, filePathString); - else - PhClearReference(&fileName); - } - - if (fileName) - { - // Escape the filename. - PhMoveReference(&fileName, PhConcatStrings(3, L"\"", fileName->Buffer, L"\"")); - - if (cmdlineArgCount == 2) - { - PPH_STRING fileArgs = PhCreateString(cmdlineArgList[1]); - - // Escape the parameters. - PhMoveReference(&fileArgs, PhConcatStrings(3, L"\"", fileArgs->Buffer, L"\"")); - - // Create the escaped execute string. - PhMoveReference(&executeString, PhConcatStrings(3, fileName->Buffer, L" ", fileArgs->Buffer)); - - // Cleanup. - PhDereferenceObject(fileArgs); - } - else - { - // Create the escaped execute string. - executeString = PhReferenceObject(fileName); - } - - PhDereferenceObject(fileName); - } - - LocalFree(cmdlineArgList); - } - - if (!PhIsNullOrEmptyString(executeString)) - { - if (WdcRunTaskAsInteractiveUser_I(executeString->Buffer, NULL, 0) == 0) - status = STATUS_SUCCESS; - else - status = STATUS_UNSUCCESSFUL; - } - else - { - status = STATUS_UNSUCCESSFUL; - } - - PhClearReference(&executeString); - } - - FreeLibrary(wdcLibraryHandle); - } - - goto CleanupExit; - } - - GetWindowThreadProcessId(shellWindow, &processId); - - if (processId == ULONG_MAX) - { - status = STATUS_UNSUCCESSFUL; - goto CleanupExit; - } - - status = PhOpenProcess( - &processHandle, - PROCESS_CREATE_PROCESS, - UlongToHandle(processId) - ); - - if (!NT_SUCCESS(status)) - goto CleanupExit; - - if (!InitializeProcThreadAttributeList(NULL, 1, 0, &attributeListLength) && GetLastError() != ERROR_INSUFFICIENT_BUFFER) - { - status = PhGetLastWin32ErrorAsNtStatus(); - goto CleanupExit; - } - - startupInfo.lpAttributeList = PhAllocate(attributeListLength); - - if (!InitializeProcThreadAttributeList(startupInfo.lpAttributeList, 1, 0, &attributeListLength)) - { - status = PhGetLastWin32ErrorAsNtStatus(); - goto CleanupExit; - } - - if (!UpdateProcThreadAttribute(startupInfo.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, &(HANDLE){ processHandle }, sizeof(HANDLE), NULL, NULL)) - { - status = PhGetLastWin32ErrorAsNtStatus(); - goto CleanupExit; - } - - if (NT_SUCCESS(PhOpenProcessToken(processHandle, TOKEN_QUERY, &tokenHandle))) - { - if (CreateEnvironmentBlock && CreateEnvironmentBlock(&environment, tokenHandle, FALSE)) - { - flags |= PH_CREATE_PROCESS_UNICODE_ENVIRONMENT; - } - - NtClose(tokenHandle); - } - - status = PhCreateProcessWin32Ex( - fullFileName->Buffer, - PhGetString(argumentsString), - environment, - NULL, - &startupInfo.StartupInfo, - PH_CREATE_PROCESS_SUSPENDED | PH_CREATE_PROCESS_NEW_CONSOLE | PH_CREATE_PROCESS_EXTENDED_STARTUPINFO | flags, - NULL, - NULL, - &newProcessHandle, - NULL - ); - - if (NT_SUCCESS(status)) - { - PROCESS_BASIC_INFORMATION basicInfo; - - if (NT_SUCCESS(PhGetProcessBasicInformation(newProcessHandle, &basicInfo))) - { - AllowSetForegroundWindow(HandleToUlong(basicInfo.UniqueProcessId)); - } - - NtResumeProcess(newProcessHandle); - - NtClose(newProcessHandle); - } - - CleanupExit: - - if (environment && DestroyEnvironmentBlock) - { - DestroyEnvironmentBlock(environment); - } - - if (startupInfo.lpAttributeList) - { - DeleteProcThreadAttributeList(startupInfo.lpAttributeList); - PhFree(startupInfo.lpAttributeList); - } - - if (processHandle) + else { - NtClose(processHandle); + PhShowStatus(hwndDlg, L"Unable to execute the command.", 0, ERROR_FILE_NOT_FOUND); } - if (NT_SUCCESS(status)) - { - PhpAddRunMRUListEntry(string); - - EndDialog(hwndDlg, IDOK); - } + PhDereferenceObject(commandString); } - - if (fullFileName) PhDereferenceObject(fullFileName); - if (argumentsString) PhDereferenceObject(argumentsString); - if (string) PhDereferenceObject(string); } break; case IDC_BROWSE: From 69f30f91004943b34581753b7076d4e28df705eb Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 19 Jul 2019 04:03:24 +0200 Subject: [PATCH 2006/2058] Update nttp.h --- phnt/include/nttp.h | 36 +++++++++++++++++++++++++++++++----- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/phnt/include/nttp.h b/phnt/include/nttp.h index 09edc590c3da..d0e86614950c 100644 --- a/phnt/include/nttp.h +++ b/phnt/include/nttp.h @@ -46,7 +46,7 @@ VOID NTAPI TpSetPoolMaxThreads( _Inout_ PTP_POOL Pool, - _In_ LONG MaxThreads + _In_ ULONG MaxThreads ); // private @@ -55,7 +55,7 @@ NTSTATUS NTAPI TpSetPoolMinThreads( _Inout_ PTP_POOL Pool, - _In_ LONG MinThreads + _In_ ULONG MinThreads ); #if (PHNT_VERSION >= PHNT_WIN7) @@ -123,7 +123,7 @@ NTAPI TpCallbackReleaseSemaphoreOnCompletion( _Inout_ PTP_CALLBACK_INSTANCE Instance, _In_ HANDLE Semaphore, - _In_ LONG ReleaseCount + _In_ ULONG ReleaseCount ); // winbase:ReleaseMutexWhenCallbackReturns @@ -244,10 +244,23 @@ NTAPI TpSetTimer( _Inout_ PTP_TIMER Timer, _In_opt_ PLARGE_INTEGER DueTime, - _In_ LONG Period, - _In_opt_ LONG WindowLength + _In_ ULONG Period, + _In_opt_ ULONG WindowLength ); +#if (PHNT_VERSION >= PHNT_WIN7) +// winbase:SetThreadpoolTimerEx +NTSYSAPI +NTSTATUS +NTAPI +TpSetTimerEx( + _Inout_ PTP_TIMER Timer, + _In_opt_ PLARGE_INTEGER DueTime, + _In_ ULONG Period, + _In_opt_ ULONG WindowLength + ); +#endif + // winbase:IsThreadpoolTimerSet NTSYSAPI LOGICAL @@ -295,6 +308,19 @@ TpSetWait( _In_opt_ PLARGE_INTEGER Timeout ); +#if (PHNT_VERSION >= PHNT_WIN7) +// winbase:SetThreadpoolWaitEx +NTSYSAPI +NTSTATUS +NTAPI +TpSetWaitEx( + _Inout_ PTP_WAIT Wait, + _In_opt_ HANDLE Handle, + _In_opt_ PLARGE_INTEGER Timeout, + _In_opt_ PVOID Reserved + ); +#endif + // winbase:WaitForThreadpoolWaitCallbacks NTSYSAPI VOID From 4015b13498bad8436b4d40f1fe9b39337f7a3111 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 21 Jul 2019 04:23:49 +0200 Subject: [PATCH 2007/2058] Fix RunFileDialog command expansion, Fix default RunFileDialog parent directory --- ProcessHacker/runas.c | 156 +++++++++++++++++++++++++++++++++--------- 1 file changed, 122 insertions(+), 34 deletions(-) diff --git a/ProcessHacker/runas.c b/ProcessHacker/runas.c index eaee8cc55bc8..cdd55a6f70fd 100644 --- a/ProcessHacker/runas.c +++ b/ProcessHacker/runas.c @@ -1929,6 +1929,86 @@ typedef struct _PHP_RUNFILEDLG HWND RunAsCheckboxHandle; } PHP_RUNFILEDLG, *PPHP_RUNFILEDLG; +PPH_STRING PhpQueryRunFileParentDirectory( + _In_ BOOLEAN Elevated + ) +{ + // Note: Explorer creates new processes with the parent directory as SystemRoot when elevated or + // the below environment variables when not elevated. (dmex) + if (!Elevated) + { + static PH_STRINGREF homeDriveNameSr = PH_STRINGREF_INIT(L"HOMEDRIVE"); + static PH_STRINGREF homePathNameSr = PH_STRINGREF_INIT(L"HOMEPATH"); + PPH_STRING parentDirectoryString = NULL; + PPH_STRING homeDriveNameString = NULL; + PPH_STRING homePathNameString = NULL; + + PhQueryEnvironmentVariable(NULL, &homeDriveNameSr, &homeDriveNameString); + PhQueryEnvironmentVariable(NULL, &homePathNameSr, &homePathNameString); + + if (homeDriveNameString && homePathNameString) + { + parentDirectoryString = PhConcatStringRef2( + &homeDriveNameString->sr, + &homePathNameString->sr + ); + } + + if (homeDriveNameString) + PhDereferenceObject(homeDriveNameString); + if (homePathNameString) + PhDereferenceObject(homePathNameString); + + return parentDirectoryString; + } + else + { + return PhGetSystemDirectory(); + } +} + +BOOLEAN PhpCustomShellExecute( + _In_ HWND hWnd, + _In_ PWSTR FileName, + _In_opt_ PWSTR Parameters, + _In_ ULONG Flags + ) +{ + PPH_STRING parentDirectory = NULL; + SHELLEXECUTEINFO info; + + parentDirectory = PhpQueryRunFileParentDirectory(!!(Flags & PH_SHELL_EXECUTE_ADMIN)); + + memset(&info, 0, sizeof(SHELLEXECUTEINFO)); + info.cbSize = sizeof(SHELLEXECUTEINFO); + info.lpFile = FileName; + info.lpParameters = Parameters; + info.lpDirectory = PhGetString(parentDirectory); + info.fMask = SEE_MASK_FLAG_NO_UI; + info.nShow = SW_SHOWNORMAL; + info.hwnd = hWnd; + + if (Flags & PH_SHELL_EXECUTE_ADMIN) + info.lpVerb = L"runas"; + + if (ShellExecuteEx(&info)) + { + if (info.hProcess) + NtClose(info.hProcess); + + if (parentDirectory) + PhDereferenceObject(parentDirectory); + + return TRUE; + } + + if (parentDirectory) + PhDereferenceObject(parentDirectory); + + return FALSE; +} + + BOOLEAN PhpRunFileAsInteractiveUser( _In_ PPHP_RUNFILEDLG Context, _In_ PPH_STRING Command @@ -2002,8 +2082,17 @@ BOOLEAN PhpRunFileAsInteractiveUser( if (!PhIsNullOrEmptyString(executeString)) { - if (WdcRunTaskAsInteractiveUser_I(executeString->Buffer, NULL, 0) == 0) + PPH_STRING parentDirectory = PhpQueryRunFileParentDirectory(FALSE); + + if (WdcRunTaskAsInteractiveUser_I(executeString->Buffer, PhGetString(parentDirectory), 0) == 0) + { success = TRUE; + } + + if (parentDirectory) + { + PhDereferenceObject(parentDirectory); + } } if (executeString) PhDereferenceObject(executeString); @@ -2018,6 +2107,7 @@ BOOLEAN PhpRunFileProgram( ) { BOOLEAN success = FALSE; + PPH_STRING commandString = NULL; PPH_STRING fullFileName = NULL; PPH_STRING argumentsString = NULL; PH_STRINGREF fileName; @@ -2025,13 +2115,22 @@ BOOLEAN PhpRunFileProgram( FILE_BASIC_INFORMATION basicInfo; BOOLEAN isDirectory = FALSE; - PhParseCommandLineFuzzy(&Command->sr, &fileName, &arguments, &fullFileName); + if (PhIsNullOrEmptyString(Command)) + return FALSE; + + if (!(commandString = PhExpandEnvironmentStrings(&Command->sr))) + commandString = PhCreateString2(&Command->sr); + + PhParseCommandLineFuzzy(&commandString->sr, &fileName, &arguments, &fullFileName); if (PhIsNullOrEmptyString(fullFileName)) PhMoveReference(&fullFileName, PhCreateString2(&fileName)); if (PhIsNullOrEmptyString(fullFileName)) { + if (fullFileName) + PhDereferenceObject(fullFileName); + return FALSE; } @@ -2045,16 +2144,14 @@ BOOLEAN PhpRunFileProgram( isDirectory = !!(basicInfo.FileAttributes & FILE_ATTRIBUTE_DIRECTORY); } - if (isDirectory) + // If the file doesn't exist its probably a URL with http, https, www (dmex) + if (isDirectory || !PhDoesFileExistsWin32(fullFileName->Buffer)) { - if (PhShellExecuteEx( + if (PhpCustomShellExecute( Context->WindowHandle, - fullFileName->Buffer, - PhGetString(argumentsString), - SW_SHOWNORMAL, - 0, - 0, - NULL + commandString->Buffer, + NULL, + 0 )) { success = TRUE; @@ -2065,29 +2162,11 @@ BOOLEAN PhpRunFileProgram( // and clicking the OK button, so we'll implement the same functionality. (dmex) (!!(GetKeyState(VK_CONTROL) < 0 && !!(GetKeyState(VK_SHIFT) < 0)))) { - if (PhShellExecuteEx( + if (PhpCustomShellExecute( Context->WindowHandle, - fullFileName->Buffer, - PhGetString(argumentsString), - SW_SHOWNORMAL, - PH_SHELL_EXECUTE_ADMIN, - 0, - NULL - )) - { - success = TRUE; - } - } - else if (!PhDoesFileExistsWin32(fullFileName->Buffer)) - { - if (PhShellExecuteEx( - Context->WindowHandle, - fullFileName->Buffer, - PhGetString(argumentsString), - SW_SHOWNORMAL, - 0, - 0, - NULL + commandString->Buffer, + NULL, + PH_SHELL_EXECUTE_ADMIN )) { success = TRUE; @@ -2097,6 +2176,7 @@ BOOLEAN PhpRunFileProgram( { NTSTATUS status = STATUS_UNSUCCESSFUL; ULONG processId = ULONG_MAX; + PPH_STRING parentDirectory = NULL; HANDLE processHandle = NULL; HANDLE newProcessHandle; HANDLE tokenHandle; @@ -2113,7 +2193,7 @@ BOOLEAN PhpRunFileProgram( if (!(shellWindow = GetShellWindow())) { - success = PhpRunFileAsInteractiveUser(Context, Command); + success = PhpRunFileAsInteractiveUser(Context, commandString); goto CleanupExit; } @@ -2164,11 +2244,13 @@ BOOLEAN PhpRunFileProgram( NtClose(tokenHandle); } + parentDirectory = PhpQueryRunFileParentDirectory(FALSE); + status = PhCreateProcessWin32Ex( fullFileName->Buffer, PhGetString(argumentsString), environment, - NULL, + PhGetString(parentDirectory), &startupInfo.StartupInfo, PH_CREATE_PROCESS_SUSPENDED | PH_CREATE_PROCESS_NEW_CONSOLE | PH_CREATE_PROCESS_EXTENDED_STARTUPINFO | flags, NULL, @@ -2209,6 +2291,11 @@ BOOLEAN PhpRunFileProgram( NtClose(processHandle); } + if (parentDirectory) + { + PhDereferenceObject(parentDirectory); + } + if (NT_SUCCESS(status)) { success = TRUE; @@ -2217,6 +2304,7 @@ BOOLEAN PhpRunFileProgram( if (fullFileName) PhDereferenceObject(fullFileName); if (argumentsString) PhDereferenceObject(argumentsString); + if (commandString) PhDereferenceObject(commandString); return success; } From d8c2daa045b95e824664a0b2584e693614a2aabc Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 21 Jul 2019 06:29:28 +0200 Subject: [PATCH 2008/2058] Add PhLoadMenu --- ProcessHacker/mainwnd.c | 2 +- phlib/emenu.c | 2 +- phlib/include/phutil.h | 8 ++++++++ phlib/util.c | 26 ++++++++++++++++++++++++++ 4 files changed, 36 insertions(+), 2 deletions(-) diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index 571b187f478a..c9dea217450e 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -176,7 +176,7 @@ BOOLEAN PhMainWndInitialization( // Load the main menu - PhMainWndMenuHandle = LoadMenu(PhInstanceHandle, MAKEINTRESOURCE(IDR_MAINWND)); + PhMainWndMenuHandle = PhLoadMenu(PhInstanceHandle, MAKEINTRESOURCE(IDR_MAINWND)); SetMenu(PhMainWndHandle, PhMainWndMenuHandle); PhMwpInitializeMainMenu(PhMainWndMenuHandle); diff --git a/phlib/emenu.c b/phlib/emenu.c index 50228b1e0e2b..5d79ccc57245 100644 --- a/phlib/emenu.c +++ b/phlib/emenu.c @@ -680,7 +680,7 @@ VOID PhLoadResourceEMenuItem( HMENU menu; HMENU realMenu; - menu = LoadMenu(InstanceHandle, Resource); + menu = PhLoadMenu(InstanceHandle, Resource); if (SubMenuIndex != ULONG_MAX) realMenu = GetSubMenu(menu, SubMenuIndex); diff --git a/phlib/include/phutil.h b/phlib/include/phutil.h index da5b7596f5af..7dbfecbf9bd8 100644 --- a/phlib/include/phutil.h +++ b/phlib/include/phutil.h @@ -1154,6 +1154,14 @@ PhLoadResource( _Out_ PVOID *ResourceBuffer ); +PHLIBAPI +HMENU +NTAPI +PhLoadMenu( + _In_ PVOID DllBase, + _In_ PWSTR MenuName + ); + PHLIBAPI PPH_STRING NTAPI diff --git a/phlib/util.c b/phlib/util.c index 9b6922d0ef82..3825da3282aa 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -5473,6 +5473,32 @@ PPH_STRING PhLoadString( return string; } +// rev from LoadMenuW +HMENU PhLoadMenu( + _In_ PVOID DllBase, + _In_ PWSTR MenuName + ) +{ + HMENU menuHandle = NULL; + ULONG resourceLength; + PVOID resourceBuffer; + + if (PhLoadResource( + DllBase, + MenuName, + RT_MENU, + &resourceLength, + &resourceBuffer + )) + { + menuHandle = LoadMenuIndirect(resourceBuffer); + + PhFree(resourceBuffer); + } + + return menuHandle; +} + // rev from SHLoadIndirectString /** * Extracts a specified text resource when given that resource in the form of an indirect string (a string that begins with the '@' symbol). From c0bade862af4aa3f024812355fe7539da730307c Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 21 Jul 2019 06:30:15 +0200 Subject: [PATCH 2009/2058] Update menu command handle --- ProcessHacker/include/mainwndp.h | 1 + ProcessHacker/mainwnd.c | 21 +++++++++++---------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/ProcessHacker/include/mainwndp.h b/ProcessHacker/include/mainwndp.h index 8be6ecafb14c..e7bd8f8d3833 100644 --- a/ProcessHacker/include/mainwndp.h +++ b/ProcessHacker/include/mainwndp.h @@ -157,6 +157,7 @@ VOID PhMwpSetupComputerMenu( ); BOOLEAN PhMwpExecuteComputerCommand( + _In_ HWND WindowHandle, _In_ ULONG Id ); diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index c9dea217450e..88a6c6b93697 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -721,7 +721,7 @@ VOID PhMwpOnCommand( case ID_COMPUTER_RESTARTBOOTOPTIONS: case ID_COMPUTER_SHUTDOWN: case ID_COMPUTER_SHUTDOWNHYBRID: - PhMwpExecuteComputerCommand(Id); + PhMwpExecuteComputerCommand(WindowHandle, Id); break; case ID_HACKER_EXIT: ProcessHacker_Destroy(WindowHandle); @@ -2104,34 +2104,35 @@ VOID PhMwpSetupComputerMenu( } BOOLEAN PhMwpExecuteComputerCommand( + _In_ HWND WindowHandle, _In_ ULONG Id ) { switch (Id) { case ID_COMPUTER_LOCK: - PhUiLockComputer(PhMainWndHandle); + PhUiLockComputer(WindowHandle); return TRUE; case ID_COMPUTER_LOGOFF: - PhUiLogoffComputer(PhMainWndHandle); + PhUiLogoffComputer(WindowHandle); return TRUE; case ID_COMPUTER_SLEEP: - PhUiSleepComputer(PhMainWndHandle); + PhUiSleepComputer(WindowHandle); return TRUE; case ID_COMPUTER_HIBERNATE: - PhUiHibernateComputer(PhMainWndHandle); + PhUiHibernateComputer(WindowHandle); return TRUE; case ID_COMPUTER_RESTART: - PhUiRestartComputer(PhMainWndHandle, 0); + PhUiRestartComputer(WindowHandle, 0); return TRUE; case ID_COMPUTER_RESTARTBOOTOPTIONS: - PhUiRestartComputer(PhMainWndHandle, EWX_BOOTOPTIONS); + PhUiRestartComputer(WindowHandle, EWX_BOOTOPTIONS); return TRUE; case ID_COMPUTER_SHUTDOWN: - PhUiShutdownComputer(PhMainWndHandle, 0); + PhUiShutdownComputer(WindowHandle, 0); return TRUE; case ID_COMPUTER_SHUTDOWNHYBRID: - PhUiShutdownComputer(PhMainWndHandle, EWX_HYBRID_SHUTDOWN); + PhUiShutdownComputer(WindowHandle, EWX_HYBRID_SHUTDOWN); return TRUE; } @@ -3026,7 +3027,7 @@ VOID PhShowIconContextMenu( handled = PhHandleMiniProcessMenuItem(item); if (!handled) - handled = PhMwpExecuteComputerCommand(item->Id); + handled = PhMwpExecuteComputerCommand(PhMainWndHandle, item->Id); if (!handled) { From d120a4de2f27fc3394a18ea73612c3e02d89e210 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 21 Jul 2019 06:31:55 +0200 Subject: [PATCH 2010/2058] Remove unused field --- phlib/util.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/phlib/util.c b/phlib/util.c index 3825da3282aa..32ebc843de13 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -5480,20 +5480,19 @@ HMENU PhLoadMenu( ) { HMENU menuHandle = NULL; - ULONG resourceLength; - PVOID resourceBuffer; + LPMENUTEMPLATE templateBuffer; if (PhLoadResource( DllBase, MenuName, RT_MENU, - &resourceLength, - &resourceBuffer + NULL, + &templateBuffer )) { - menuHandle = LoadMenuIndirect(resourceBuffer); + menuHandle = LoadMenuIndirect(templateBuffer); - PhFree(resourceBuffer); + PhFree(templateBuffer); } return menuHandle; From 4d4eabc085fe7cb866afe9e49feea36cf90157a0 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 21 Jul 2019 08:04:34 +0200 Subject: [PATCH 2011/2058] Improve RunFileDialog error messages --- ProcessHacker/runas.c | 74 +++++++++++++++++++++---------------------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/ProcessHacker/runas.c b/ProcessHacker/runas.c index cdd55a6f70fd..61c1ae592ebe 100644 --- a/ProcessHacker/runas.c +++ b/ProcessHacker/runas.c @@ -1967,17 +1967,18 @@ PPH_STRING PhpQueryRunFileParentDirectory( } } -BOOLEAN PhpCustomShellExecute( +NTSTATUS PhpCustomShellExecute( _In_ HWND hWnd, _In_ PWSTR FileName, _In_opt_ PWSTR Parameters, - _In_ ULONG Flags + _In_ BOOLEAN Elevated ) { + NTSTATUS status; PPH_STRING parentDirectory = NULL; SHELLEXECUTEINFO info; - parentDirectory = PhpQueryRunFileParentDirectory(!!(Flags & PH_SHELL_EXECUTE_ADMIN)); + parentDirectory = PhpQueryRunFileParentDirectory(Elevated); memset(&info, 0, sizeof(SHELLEXECUTEINFO)); info.cbSize = sizeof(SHELLEXECUTEINFO); @@ -1988,7 +1989,7 @@ BOOLEAN PhpCustomShellExecute( info.nShow = SW_SHOWNORMAL; info.hwnd = hWnd; - if (Flags & PH_SHELL_EXECUTE_ADMIN) + if (Elevated) info.lpVerb = L"runas"; if (ShellExecuteEx(&info)) @@ -1996,19 +1997,19 @@ BOOLEAN PhpCustomShellExecute( if (info.hProcess) NtClose(info.hProcess); - if (parentDirectory) - PhDereferenceObject(parentDirectory); - - return TRUE; + status = STATUS_SUCCESS; + } + else + { + status = PhGetLastWin32ErrorAsNtStatus(); } if (parentDirectory) PhDereferenceObject(parentDirectory); - return FALSE; + return status; } - BOOLEAN PhpRunFileAsInteractiveUser( _In_ PPHP_RUNFILEDLG Context, _In_ PPH_STRING Command @@ -2101,12 +2102,12 @@ BOOLEAN PhpRunFileAsInteractiveUser( return success; } -BOOLEAN PhpRunFileProgram( +NTSTATUS PhpRunFileProgram( _In_ PPHP_RUNFILEDLG Context, _In_ PPH_STRING Command ) { - BOOLEAN success = FALSE; + NTSTATUS status = STATUS_UNSUCCESSFUL; PPH_STRING commandString = NULL; PPH_STRING fullFileName = NULL; PPH_STRING argumentsString = NULL; @@ -2116,7 +2117,7 @@ BOOLEAN PhpRunFileProgram( BOOLEAN isDirectory = FALSE; if (PhIsNullOrEmptyString(Command)) - return FALSE; + return STATUS_UNSUCCESSFUL; if (!(commandString = PhExpandEnvironmentStrings(&Command->sr))) commandString = PhCreateString2(&Command->sr); @@ -2131,7 +2132,7 @@ BOOLEAN PhpRunFileProgram( if (fullFileName) PhDereferenceObject(fullFileName); - return FALSE; + return STATUS_UNSUCCESSFUL; } if (arguments.Length) @@ -2147,34 +2148,27 @@ BOOLEAN PhpRunFileProgram( // If the file doesn't exist its probably a URL with http, https, www (dmex) if (isDirectory || !PhDoesFileExistsWin32(fullFileName->Buffer)) { - if (PhpCustomShellExecute( + status = PhpCustomShellExecute( Context->WindowHandle, commandString->Buffer, NULL, - 0 - )) - { - success = TRUE; - } + FALSE + ); } else if (Button_GetCheck(Context->RunAsCheckboxHandle) == BST_CHECKED || // The explorer runas dialog executes programs as administrator when holding ctrl/shift keys // and clicking the OK button, so we'll implement the same functionality. (dmex) (!!(GetKeyState(VK_CONTROL) < 0 && !!(GetKeyState(VK_SHIFT) < 0)))) { - if (PhpCustomShellExecute( + status = PhpCustomShellExecute( Context->WindowHandle, commandString->Buffer, NULL, - PH_SHELL_EXECUTE_ADMIN - )) - { - success = TRUE; - } + TRUE + ); } else { - NTSTATUS status = STATUS_UNSUCCESSFUL; ULONG processId = ULONG_MAX; PPH_STRING parentDirectory = NULL; HANDLE processHandle = NULL; @@ -2193,7 +2187,9 @@ BOOLEAN PhpRunFileProgram( if (!(shellWindow = GetShellWindow())) { - success = PhpRunFileAsInteractiveUser(Context, commandString); + if (PhpRunFileAsInteractiveUser(Context, commandString)) + status = STATUS_SUCCESS; + goto CleanupExit; } @@ -2295,18 +2291,13 @@ BOOLEAN PhpRunFileProgram( { PhDereferenceObject(parentDirectory); } - - if (NT_SUCCESS(status)) - { - success = TRUE; - } } if (fullFileName) PhDereferenceObject(fullFileName); if (argumentsString) PhDereferenceObject(argumentsString); if (commandString) PhDereferenceObject(commandString); - return success; + return status; } INT_PTR CALLBACK PhpRunFileWndProc( @@ -2409,11 +2400,17 @@ INT_PTR CALLBACK PhpRunFileWndProc( break; case IDOK: { + NTSTATUS status; PPH_STRING commandString; if (commandString = PhGetWindowText(context->ComboBoxHandle)) { - if (PhpRunFileProgram(context, commandString)) + status = PhpRunFileProgram( + context, + commandString + ); + + if (NT_SUCCESS(status)) { PhpAddRunMRUListEntry(commandString); @@ -2421,7 +2418,10 @@ INT_PTR CALLBACK PhpRunFileWndProc( } else { - PhShowStatus(hwndDlg, L"Unable to execute the command.", 0, ERROR_FILE_NOT_FOUND); + if (!(NT_NTWIN32(status) && WIN32_FROM_NTSTATUS(status) == ERROR_CANCELLED)) + { + PhShowStatus(hwndDlg, L"Unable to execute the command.", status, 0); + } } PhDereferenceObject(commandString); @@ -2445,7 +2445,7 @@ INT_PTR CALLBACK PhpRunFileWndProc( if (fileName = PhGetFileDialogFileName(fileDialog)) { - ComboBox_SetText(GetDlgItem(hwndDlg, IDC_PROGRAMCOMBO), PhGetString(fileName)); + ComboBox_SetText(context->ComboBoxHandle, PhGetString(fileName)); PhDereferenceObject(fileName); } } From 9503fb464eb21a92c2e07f85ee6c6d74e419a945 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 21 Jul 2019 09:38:00 +0200 Subject: [PATCH 2012/2058] #444 --- phlib/basesup.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/phlib/basesup.c b/phlib/basesup.c index 6959e2831202..ab0c3f8082a8 100644 --- a/phlib/basesup.c +++ b/phlib/basesup.c @@ -5382,9 +5382,7 @@ VOID PhInvokeCallback( PhAcquireQueuedLockShared(&Callback->ListLock); - listEntry = Callback->ListHead.Flink; - - while (listEntry != &Callback->ListHead) + for (listEntry = Callback->ListHead.Flink; listEntry != &Callback->ListHead; listEntry = listEntry->Flink) { PPH_CALLBACK_REGISTRATION registration; LONG busy; @@ -5414,8 +5412,6 @@ VOID PhInvokeCallback( // wake them. PhPulseAllCondition(&Callback->BusyCondition); } - - listEntry = listEntry->Flink; } PhReleaseQueuedLockShared(&Callback->ListLock); From 8878da27ec7a4e3a7e846ab8eb7af70db05dac5d Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 23 Jul 2019 16:08:25 +0200 Subject: [PATCH 2013/2058] Remove unused string reference --- phlib/guisup.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/phlib/guisup.c b/phlib/guisup.c index f3e5fdd6e6a9..7b69669bc065 100644 --- a/phlib/guisup.c +++ b/phlib/guisup.c @@ -787,12 +787,13 @@ VOID PhGetStockApplicationIcon( if (systemDirectory = PhGetSystemDirectory()) { - PH_STRINGREF dllBaseName; + dllFileName = PhConcatStringRefZ(&systemDirectory->sr, L"\\user32.dll"); - PhInitializeStringRef(&dllBaseName, L"\\user32.dll"); - dllFileName = PhConcatStringRef2(&systemDirectory->sr, &dllBaseName); - - PhExtractIcon(dllFileName->Buffer, &largeIcon, &smallIcon); + PhExtractIcon( + dllFileName->Buffer, + &largeIcon, + &smallIcon + ); PhDereferenceObject(dllFileName); PhDereferenceObject(systemDirectory); From ba51d70c99f3ab5b11bac174ec1367fddfe1a601 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 23 Jul 2019 16:10:23 +0200 Subject: [PATCH 2014/2058] ExtendedTools: Fix default window handle --- plugins/ExtendedTools/disktab.c | 23 ++++++++++++----------- plugins/ExtendedTools/disktabp.h | 3 ++- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/plugins/ExtendedTools/disktab.c b/plugins/ExtendedTools/disktab.c index 63923fedf3c8..400b107fb447 100644 --- a/plugins/ExtendedTools/disktab.c +++ b/plugins/ExtendedTools/disktab.c @@ -476,7 +476,7 @@ BEGIN_SORT_FUNCTION(ResponseTime) END_SORT_FUNCTION BOOLEAN NTAPI EtpDiskTreeNewCallback( - _In_ HWND hwnd, + _In_ HWND WindowHandle, _In_ PH_TREENEW_MESSAGE Message, _In_opt_ PVOID Parameter1, _In_opt_ PVOID Parameter2, @@ -662,9 +662,9 @@ BOOLEAN NTAPI EtpDiskTreeNewCallback( return TRUE; case TreeNewSortChanged: { - TreeNew_GetSort(hwnd, &DiskTreeNewSortColumn, &DiskTreeNewSortOrder); + TreeNew_GetSort(WindowHandle, &DiskTreeNewSortColumn, &DiskTreeNewSortOrder); // Force a rebuild to sort the items. - TreeNew_NodesStructured(hwnd); + TreeNew_NodesStructured(WindowHandle); } return TRUE; case TreeNewKeyDown: @@ -675,14 +675,14 @@ BOOLEAN NTAPI EtpDiskTreeNewCallback( { case 'C': if (GetKeyState(VK_CONTROL) < 0) - EtHandleDiskCommand(ID_DISK_COPY); + EtHandleDiskCommand(WindowHandle, ID_DISK_COPY); break; case 'A': if (GetKeyState(VK_CONTROL) < 0) TreeNew_SelectRange(DiskTreeNewHandle, 0, -1); break; case VK_RETURN: - EtHandleDiskCommand(ID_DISK_OPENFILELOCATION); + EtHandleDiskCommand(WindowHandle, ID_DISK_OPENFILELOCATION); break; } } @@ -691,13 +691,13 @@ BOOLEAN NTAPI EtpDiskTreeNewCallback( { PH_TN_COLUMN_MENU_DATA data; - data.TreeNewHandle = hwnd; + data.TreeNewHandle = WindowHandle; data.MouseEvent = Parameter1; data.DefaultSortColumn = 0; data.DefaultSortOrder = AscendingSortOrder; PhInitializeTreeNewColumnMenu(&data); - data.Selection = PhShowEMenu(data.Menu, hwnd, PH_EMENU_SHOW_LEFTRIGHT, + data.Selection = PhShowEMenu(data.Menu, WindowHandle, PH_EMENU_SHOW_LEFTRIGHT, PH_ALIGN_LEFT | PH_ALIGN_TOP, data.MouseEvent->ScreenLocation.x, data.MouseEvent->ScreenLocation.y); PhHandleTreeNewColumnMenu(&data); PhDeleteTreeNewColumnMenu(&data); @@ -705,14 +705,14 @@ BOOLEAN NTAPI EtpDiskTreeNewCallback( return TRUE; case TreeNewLeftDoubleClick: { - EtHandleDiskCommand(ID_DISK_OPENFILELOCATION); + EtHandleDiskCommand(WindowHandle, ID_DISK_OPENFILELOCATION); } return TRUE; case TreeNewContextMenu: { PPH_TREENEW_CONTEXT_MENU contextMenuEvent = Parameter1; - EtShowDiskContextMenu(hwnd, contextMenuEvent); + EtShowDiskContextMenu(WindowHandle, contextMenuEvent); } return TRUE; case TreeNewDestroying: @@ -850,6 +850,7 @@ VOID EtWriteDiskList( } VOID EtHandleDiskCommand( + _In_ HWND WindowHandle, _In_ ULONG Id ) { @@ -980,7 +981,7 @@ VOID EtShowDiskContextMenu( item = PhShowEMenu( menu, - PhMainWndHandle, + TreeWindowHandle, PH_EMENU_SHOW_LEFTRIGHT, PH_ALIGN_LEFT | PH_ALIGN_TOP, ContextMenuEvent->Location.x, @@ -994,7 +995,7 @@ VOID EtShowDiskContextMenu( handled = PhHandleCopyCellEMenuItem(item); if (!handled) - EtHandleDiskCommand(item->Id); + EtHandleDiskCommand(TreeWindowHandle, item->Id); } PhDestroyEMenu(menu); diff --git a/plugins/ExtendedTools/disktabp.h b/plugins/ExtendedTools/disktabp.h index ea098610f797..85adb65d21c6 100644 --- a/plugins/ExtendedTools/disktabp.h +++ b/plugins/ExtendedTools/disktabp.h @@ -38,7 +38,7 @@ VOID EtUpdateDiskNode( ); BOOLEAN NTAPI EtpDiskTreeNewCallback( - _In_ HWND hwnd, + _In_ HWND WindowHandle, _In_ PH_TREENEW_MESSAGE Message, _In_opt_ PVOID Parameter1, _In_opt_ PVOID Parameter2, @@ -76,6 +76,7 @@ VOID EtWriteDiskList( ); VOID EtHandleDiskCommand( + _In_ HWND WindowHandle, _In_ ULONG Id ); From 31ef91a60c26b8655d609e7bebb6ee096a5bb852 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 23 Jul 2019 16:11:45 +0200 Subject: [PATCH 2015/2058] Fix default notify icon handle --- ProcessHacker/include/notifico.h | 1 + ProcessHacker/mainwnd.c | 2 +- ProcessHacker/notifico.c | 17 +++++++++-------- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/ProcessHacker/include/notifico.h b/ProcessHacker/include/notifico.h index 44cabf79f699..639723e8b7da 100644 --- a/ProcessHacker/include/notifico.h +++ b/ProcessHacker/include/notifico.h @@ -133,6 +133,7 @@ VOID PhNfUninitialization( ); VOID PhNfForwardMessage( + _In_ HWND WindowHandle, _In_ ULONG_PTR WParam, _In_ ULONG_PTR LParam ); diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index 88a6c6b93697..9303b663e593 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -1807,7 +1807,7 @@ ULONG_PTR PhMwpOnUserMessage( break; case WM_PH_NOTIFY_ICON_MESSAGE: { - PhNfForwardMessage(WParam, LParam); + PhNfForwardMessage(WindowHandle, WParam, LParam); } break; case WM_PH_TOGGLE_VISIBLE: diff --git a/ProcessHacker/notifico.c b/ProcessHacker/notifico.c index eed27493604a..d0c2002576d6 100644 --- a/ProcessHacker/notifico.c +++ b/ProcessHacker/notifico.c @@ -282,6 +282,7 @@ VOID PhNfUninitialization( } VOID PhNfForwardMessage( + _In_ HWND WindowHandle, _In_ ULONG_PTR WParam, _In_ ULONG_PTR LParam ) @@ -325,7 +326,7 @@ VOID PhNfForwardMessage( { if (PhGetIntegerSetting(L"IconSingleClick")) { - ProcessHacker_IconClick(PhMainWndHandle); + ProcessHacker_IconClick(WindowHandle); PhNfpDisableHover(); } else @@ -355,11 +356,11 @@ VOID PhNfForwardMessage( IconClickShowMiniInfoSectionData.SectionName = PhDuplicateStringZ(showMiniInfoSectionData.SectionName); } - SetTimer(PhMainWndHandle, TIMER_ICON_CLICK_ACTIVATE, GetDoubleClickTime() + NFP_ICON_CLICK_ACTIVATE_DELAY, PhNfpIconClickActivateTimerProc); + SetTimer(WindowHandle, TIMER_ICON_CLICK_ACTIVATE, GetDoubleClickTime() + NFP_ICON_CLICK_ACTIVATE_DELAY, PhNfpIconClickActivateTimerProc); } else { - KillTimer(PhMainWndHandle, TIMER_ICON_CLICK_ACTIVATE); + KillTimer(WindowHandle, TIMER_ICON_CLICK_ACTIVATE); } } } @@ -372,12 +373,12 @@ VOID PhNfForwardMessage( { // We will get another WM_LBUTTONUP message corresponding to the double-click, // and we need to make sure that it doesn't start the activation timer again. - KillTimer(PhMainWndHandle, TIMER_ICON_CLICK_ACTIVATE); + KillTimer(WindowHandle, TIMER_ICON_CLICK_ACTIVATE); IconClickUpDueToDown = FALSE; PhNfpDisableHover(); } - ProcessHacker_IconClick(PhMainWndHandle); + ProcessHacker_IconClick(WindowHandle); } } break; @@ -387,7 +388,7 @@ VOID PhNfForwardMessage( POINT location; if (!PhGetIntegerSetting(L"IconSingleClick") && PhNfMiniInfoEnabled) - KillTimer(PhMainWndHandle, TIMER_ICON_CLICK_ACTIVATE); + KillTimer(WindowHandle, TIMER_ICON_CLICK_ACTIVATE); PhPinMiniInformation(MiniInfoIconPinType, -1, 0, 0, NULL, NULL); GetCursorPos(&location); @@ -396,8 +397,8 @@ VOID PhNfForwardMessage( break; case NIN_KEYSELECT: // HACK: explorer seems to send two NIN_KEYSELECT messages when the user selects the icon and presses ENTER. - if (GetForegroundWindow() != PhMainWndHandle) - ProcessHacker_IconClick(PhMainWndHandle); + if (GetForegroundWindow() != WindowHandle) + ProcessHacker_IconClick(WindowHandle); break; case NIN_BALLOONUSERCLICK: PhShowDetailsForIconNotification(); From aefd92ad15a76534958b6ecee8a55f218b05a94a Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 23 Jul 2019 16:13:58 +0200 Subject: [PATCH 2016/2058] ExtendedTools: Fix IPv4 event types --- plugins/ExtendedTools/etwmon.c | 4 ++-- plugins/ExtendedTools/etwmon.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/ExtendedTools/etwmon.c b/plugins/ExtendedTools/etwmon.c index 3ac1a776ee14..e29fcb65ac76 100644 --- a/plugins/ExtendedTools/etwmon.c +++ b/plugins/ExtendedTools/etwmon.c @@ -358,10 +358,10 @@ VOID NTAPI EtpEtwEventCallback( networkEvent.TransferSize = data->size; source.Address.Type = PH_IPV4_NETWORK_TYPE; - source.Address.Ipv4 = data->saddr; + source.Address.Ipv4 = data->saddr.s_addr; source.Port = _byteswap_ushort(data->sport); destination.Address.Type = PH_IPV4_NETWORK_TYPE; - destination.Address.Ipv4 = data->daddr; + destination.Address.Ipv4 = data->daddr.s_addr; destination.Port = _byteswap_ushort(data->dport); } else if (networkEvent.ProtocolType & PH_IPV6_NETWORK_TYPE) diff --git a/plugins/ExtendedTools/etwmon.h b/plugins/ExtendedTools/etwmon.h index 68aef52ff55c..860bcc4f57f7 100644 --- a/plugins/ExtendedTools/etwmon.h +++ b/plugins/ExtendedTools/etwmon.h @@ -32,8 +32,8 @@ typedef struct { ULONG PID; ULONG size; - ULONG daddr; - ULONG saddr; + IN_ADDR daddr; + IN_ADDR saddr; USHORT dport; USHORT sport; } TcpIpOrUdpIp_IPV4_Header; From 8569819b948dfb56b851f3b869b2c86fa14609bb Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 24 Jul 2019 13:16:56 +0200 Subject: [PATCH 2017/2058] Add workaround for CreateProcess runas bug #436 --- ProcessHacker/runas.c | 93 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 86 insertions(+), 7 deletions(-) diff --git a/ProcessHacker/runas.c b/ProcessHacker/runas.c index 61c1ae592ebe..46739b253513 100644 --- a/ProcessHacker/runas.c +++ b/ProcessHacker/runas.c @@ -1259,6 +1259,7 @@ INT_PTR CALLBACK PhpRunAsDlgProc( HANDLE newProcessHandle; STARTUPINFOEX startupInfo; SIZE_T attributeListLength = 0; + PSECURITY_DESCRIPTOR securityDescriptor = NULL; PVOID environment = NULL; HANDLE tokenHandle; ULONG flags = 0; @@ -1270,7 +1271,7 @@ INT_PTR CALLBACK PhpRunAsDlgProc( status = PhOpenProcess( &processHandle, - PROCESS_CREATE_PROCESS, + PROCESS_CREATE_PROCESS | PROCESS_QUERY_LIMITED_INFORMATION, context->ProcessId ); @@ -1297,8 +1298,21 @@ INT_PTR CALLBACK PhpRunAsDlgProc( goto CleanupExit; } - if (NT_SUCCESS(PhOpenProcessToken(processHandle, TOKEN_QUERY, &tokenHandle))) + if (NT_SUCCESS(PhOpenProcessToken( + processHandle, + TOKEN_QUERY | (PhGetOwnTokenAttributes().Elevated ? READ_CONTROL : 0), + &tokenHandle + ))) { + if (PhGetOwnTokenAttributes().Elevated) + { + PhGetObjectSecurity( + tokenHandle, + OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION | LABEL_SECURITY_INFORMATION, + &securityDescriptor + ); + } + if (CreateEnvironmentBlock && CreateEnvironmentBlock(&environment, tokenHandle, FALSE)) { flags |= PH_CREATE_PROCESS_UNICODE_ENVIRONMENT; @@ -1324,6 +1338,27 @@ INT_PTR CALLBACK PhpRunAsDlgProc( { PROCESS_BASIC_INFORMATION basicInfo; + if (PhGetOwnTokenAttributes().Elevated && securityDescriptor) + { + if (NT_SUCCESS(PhOpenProcessToken( + newProcessHandle, + WRITE_DAC | WRITE_OWNER, + &tokenHandle + ))) + { + // Note: This is needed to workaround a severe bug with CreateProcess where the new process + // token DAC is created without an ACE for the current user, owned by the wrong user + // and with a High-IL when the process token is Medium-IL blocking the new process from + // accessing system resources. (dmex) + PhSetObjectSecurity( + tokenHandle, + OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION | LABEL_SECURITY_INFORMATION, + securityDescriptor + ); + NtClose(tokenHandle); + } + } + if (NT_SUCCESS(PhGetProcessBasicInformation(newProcessHandle, &basicInfo))) { AllowSetForegroundWindow(HandleToUlong(basicInfo.UniqueProcessId)); @@ -1340,6 +1375,11 @@ INT_PTR CALLBACK PhpRunAsDlgProc( DestroyEnvironmentBlock(environment); } + if (securityDescriptor) + { + PhFree(securityDescriptor); + } + if (startupInfo.lpAttributeList) { DeleteProcThreadAttributeList(startupInfo.lpAttributeList); @@ -2177,6 +2217,7 @@ NTSTATUS PhpRunFileProgram( HWND shellWindow; STARTUPINFOEX startupInfo; SIZE_T attributeListLength = 0; + PSECURITY_DESCRIPTOR securityDescriptor = NULL; PVOID environment = NULL; ULONG flags = 0; @@ -2184,6 +2225,7 @@ NTSTATUS PhpRunFileProgram( startupInfo.StartupInfo.cb = sizeof(STARTUPINFOEX); startupInfo.StartupInfo.dwFlags = STARTF_USESHOWWINDOW; startupInfo.StartupInfo.wShowWindow = SW_SHOWNORMAL; + parentDirectory = PhpQueryRunFileParentDirectory(FALSE); if (!(shellWindow = GetShellWindow())) { @@ -2203,7 +2245,7 @@ NTSTATUS PhpRunFileProgram( status = PhOpenProcess( &processHandle, - PROCESS_CREATE_PROCESS, + PROCESS_CREATE_PROCESS | PROCESS_QUERY_LIMITED_INFORMATION, UlongToHandle(processId) ); @@ -2224,14 +2266,27 @@ NTSTATUS PhpRunFileProgram( goto CleanupExit; } - if (!UpdateProcThreadAttribute(startupInfo.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, &(HANDLE){ processHandle }, sizeof(HANDLE), NULL, NULL)) + if (!UpdateProcThreadAttribute(startupInfo.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, &processHandle, sizeof(HANDLE), NULL, NULL)) { status = PhGetLastWin32ErrorAsNtStatus(); goto CleanupExit; } - if (NT_SUCCESS(PhOpenProcessToken(processHandle, TOKEN_QUERY, &tokenHandle))) + if (NT_SUCCESS(PhOpenProcessToken( + processHandle, + TOKEN_QUERY | (PhGetOwnTokenAttributes().Elevated ? READ_CONTROL : 0), + &tokenHandle + ))) { + if (PhGetOwnTokenAttributes().Elevated) + { + PhGetObjectSecurity( + tokenHandle, + OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION | LABEL_SECURITY_INFORMATION, + &securityDescriptor + ); + } + if (CreateEnvironmentBlock && CreateEnvironmentBlock(&environment, tokenHandle, FALSE)) { flags |= PH_CREATE_PROCESS_UNICODE_ENVIRONMENT; @@ -2240,8 +2295,6 @@ NTSTATUS PhpRunFileProgram( NtClose(tokenHandle); } - parentDirectory = PhpQueryRunFileParentDirectory(FALSE); - status = PhCreateProcessWin32Ex( fullFileName->Buffer, PhGetString(argumentsString), @@ -2259,6 +2312,27 @@ NTSTATUS PhpRunFileProgram( { PROCESS_BASIC_INFORMATION basicInfo; + if (PhGetOwnTokenAttributes().Elevated && securityDescriptor) + { + if (NT_SUCCESS(PhOpenProcessToken( + newProcessHandle, + WRITE_DAC | WRITE_OWNER, + &tokenHandle + ))) + { + // Note: This is needed to workaround a severe bug with CreateProcess where the new process + // token DAC is created without an ACE for the current user, owned by the wrong user + // and with a High-IL when the process token is Medium-IL blocking the new process from + // accessing system resources. (dmex) + status = PhSetObjectSecurity( + tokenHandle, + OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION | LABEL_SECURITY_INFORMATION, + securityDescriptor + ); + NtClose(tokenHandle); + } + } + if (NT_SUCCESS(PhGetProcessBasicInformation(newProcessHandle, &basicInfo))) { AllowSetForegroundWindow(HandleToUlong(basicInfo.UniqueProcessId)); @@ -2276,6 +2350,11 @@ NTSTATUS PhpRunFileProgram( DestroyEnvironmentBlock(environment); } + if (securityDescriptor) + { + PhFree(securityDescriptor); + } + if (startupInfo.lpAttributeList) { DeleteProcThreadAttributeList(startupInfo.lpAttributeList); From dcbeadf7ac2ed636c44edbbd1573ffcc891ae099 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 25 Jul 2019 20:59:09 +0200 Subject: [PATCH 2018/2058] Fix CreateProcess runas bug #436 --- ProcessHacker/runas.c | 100 +++++++++++++++++++++++++++++++----------- 1 file changed, 75 insertions(+), 25 deletions(-) diff --git a/ProcessHacker/runas.c b/ProcessHacker/runas.c index 46739b253513..31a935072595 100644 --- a/ProcessHacker/runas.c +++ b/ProcessHacker/runas.c @@ -1259,7 +1259,8 @@ INT_PTR CALLBACK PhpRunAsDlgProc( HANDLE newProcessHandle; STARTUPINFOEX startupInfo; SIZE_T attributeListLength = 0; - PSECURITY_DESCRIPTOR securityDescriptor = NULL; + PSECURITY_DESCRIPTOR processSecurityDescriptor = NULL; + PSECURITY_DESCRIPTOR tokenSecurityDescriptor = NULL; PVOID environment = NULL; HANDLE tokenHandle; ULONG flags = 0; @@ -1271,7 +1272,7 @@ INT_PTR CALLBACK PhpRunAsDlgProc( status = PhOpenProcess( &processHandle, - PROCESS_CREATE_PROCESS | PROCESS_QUERY_LIMITED_INFORMATION, + PROCESS_CREATE_PROCESS | (PhGetOwnTokenAttributes().Elevated ? PROCESS_QUERY_LIMITED_INFORMATION | READ_CONTROL : 0), context->ProcessId ); @@ -1298,6 +1299,15 @@ INT_PTR CALLBACK PhpRunAsDlgProc( goto CleanupExit; } + if (PhGetOwnTokenAttributes().Elevated) + { + PhGetObjectSecurity( + processHandle, + OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION | LABEL_SECURITY_INFORMATION, + &processSecurityDescriptor + ); + } + if (NT_SUCCESS(PhOpenProcessToken( processHandle, TOKEN_QUERY | (PhGetOwnTokenAttributes().Elevated ? READ_CONTROL : 0), @@ -1309,7 +1319,7 @@ INT_PTR CALLBACK PhpRunAsDlgProc( PhGetObjectSecurity( tokenHandle, OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION | LABEL_SECURITY_INFORMATION, - &securityDescriptor + &tokenSecurityDescriptor ); } @@ -1338,22 +1348,32 @@ INT_PTR CALLBACK PhpRunAsDlgProc( { PROCESS_BASIC_INFORMATION basicInfo; - if (PhGetOwnTokenAttributes().Elevated && securityDescriptor) + if (PhGetOwnTokenAttributes().Elevated) { - if (NT_SUCCESS(PhOpenProcessToken( + // Note: This is needed to workaround a severe bug with PROC_THREAD_ATTRIBUTE_PARENT_PROCESS + // where the process and token security descriptors are created without an ACE for the current user, + // owned by the wrong user and with a High-IL when the process token is Medium-IL + // preventing the new process from accessing user/system resources above Low-IL. (dmex) + + if (processSecurityDescriptor) + { + PhSetObjectSecurity( + newProcessHandle, + OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION | LABEL_SECURITY_INFORMATION, + processSecurityDescriptor + ); + } + + if (tokenSecurityDescriptor && NT_SUCCESS(PhOpenProcessToken( newProcessHandle, WRITE_DAC | WRITE_OWNER, &tokenHandle ))) { - // Note: This is needed to workaround a severe bug with CreateProcess where the new process - // token DAC is created without an ACE for the current user, owned by the wrong user - // and with a High-IL when the process token is Medium-IL blocking the new process from - // accessing system resources. (dmex) PhSetObjectSecurity( tokenHandle, OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION | LABEL_SECURITY_INFORMATION, - securityDescriptor + tokenSecurityDescriptor ); NtClose(tokenHandle); } @@ -1375,9 +1395,14 @@ INT_PTR CALLBACK PhpRunAsDlgProc( DestroyEnvironmentBlock(environment); } - if (securityDescriptor) + if (tokenSecurityDescriptor) + { + PhFree(tokenSecurityDescriptor); + } + + if (processSecurityDescriptor) { - PhFree(securityDescriptor); + PhFree(processSecurityDescriptor); } if (startupInfo.lpAttributeList) @@ -2217,7 +2242,8 @@ NTSTATUS PhpRunFileProgram( HWND shellWindow; STARTUPINFOEX startupInfo; SIZE_T attributeListLength = 0; - PSECURITY_DESCRIPTOR securityDescriptor = NULL; + PSECURITY_DESCRIPTOR processSecurityDescriptor = NULL; + PSECURITY_DESCRIPTOR tokenSecurityDescriptor = NULL; PVOID environment = NULL; ULONG flags = 0; @@ -2245,7 +2271,7 @@ NTSTATUS PhpRunFileProgram( status = PhOpenProcess( &processHandle, - PROCESS_CREATE_PROCESS | PROCESS_QUERY_LIMITED_INFORMATION, + PROCESS_CREATE_PROCESS | (PhGetOwnTokenAttributes().Elevated ? PROCESS_QUERY_LIMITED_INFORMATION | READ_CONTROL : 0), UlongToHandle(processId) ); @@ -2272,6 +2298,15 @@ NTSTATUS PhpRunFileProgram( goto CleanupExit; } + if (PhGetOwnTokenAttributes().Elevated) + { + PhGetObjectSecurity( + processHandle, + OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION | LABEL_SECURITY_INFORMATION, + &processSecurityDescriptor + ); + } + if (NT_SUCCESS(PhOpenProcessToken( processHandle, TOKEN_QUERY | (PhGetOwnTokenAttributes().Elevated ? READ_CONTROL : 0), @@ -2283,7 +2318,7 @@ NTSTATUS PhpRunFileProgram( PhGetObjectSecurity( tokenHandle, OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION | LABEL_SECURITY_INFORMATION, - &securityDescriptor + &tokenSecurityDescriptor ); } @@ -2312,22 +2347,32 @@ NTSTATUS PhpRunFileProgram( { PROCESS_BASIC_INFORMATION basicInfo; - if (PhGetOwnTokenAttributes().Elevated && securityDescriptor) + if (PhGetOwnTokenAttributes().Elevated) { - if (NT_SUCCESS(PhOpenProcessToken( + // Note: This is needed to workaround a severe bug with PROC_THREAD_ATTRIBUTE_PARENT_PROCESS + // where the process and token security descriptors are created without an ACE for the current user, + // owned by the wrong user and with a High-IL when the process token is Medium-IL + // preventing the new process from accessing user/system resources above Low-IL. (dmex) + + if (processSecurityDescriptor) + { + PhSetObjectSecurity( + newProcessHandle, + OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION | LABEL_SECURITY_INFORMATION, + processSecurityDescriptor + ); + } + + if (tokenSecurityDescriptor && NT_SUCCESS(PhOpenProcessToken( newProcessHandle, WRITE_DAC | WRITE_OWNER, &tokenHandle ))) { - // Note: This is needed to workaround a severe bug with CreateProcess where the new process - // token DAC is created without an ACE for the current user, owned by the wrong user - // and with a High-IL when the process token is Medium-IL blocking the new process from - // accessing system resources. (dmex) - status = PhSetObjectSecurity( + PhSetObjectSecurity( tokenHandle, OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION | LABEL_SECURITY_INFORMATION, - securityDescriptor + tokenSecurityDescriptor ); NtClose(tokenHandle); } @@ -2350,9 +2395,14 @@ NTSTATUS PhpRunFileProgram( DestroyEnvironmentBlock(environment); } - if (securityDescriptor) + if (tokenSecurityDescriptor) + { + PhFree(tokenSecurityDescriptor); + } + + if (processSecurityDescriptor) { - PhFree(securityDescriptor); + PhFree(processSecurityDescriptor); } if (startupInfo.lpAttributeList) From 80166bb15aa991d7bfe1d328439862b2240ebf88 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 26 Jul 2019 10:04:34 +0200 Subject: [PATCH 2019/2058] Rename SDDLAsString --- ProcessHacker/tokprp.c | 2 +- phlib/include/phnative.h | 16 ++++----- phlib/native.c | 71 ++++++++++++++++++++-------------------- 3 files changed, 45 insertions(+), 44 deletions(-) diff --git a/ProcessHacker/tokprp.c b/ProcessHacker/tokprp.c index c97a5c7893f2..e08f15330e67 100644 --- a/ProcessHacker/tokprp.c +++ b/ProcessHacker/tokprp.c @@ -2101,7 +2101,7 @@ INT_PTR CALLBACK PhpTokenAdvancedPageProc( } PhGetTokenNamedObjectPath(tokenHandle, NULL, &tokenNamedObjectPathString); - PhGetTokenSecurityDescriptorAsString(tokenHandle, &tokenSecurityDescriptorString); + PhGetObjectSecurityDescriptorAsString(tokenHandle, &tokenSecurityDescriptorString); if (NT_SUCCESS(PhGetTokenProcessTrustLevelRID( tokenHandle, diff --git a/phlib/include/phnative.h b/phlib/include/phnative.h index 3b7fc65b9d9c..2f591f8ff0e8 100644 --- a/phlib/include/phnative.h +++ b/phlib/include/phnative.h @@ -154,6 +154,14 @@ PhGetSecurityDescriptorAsString( _In_ PSECURITY_DESCRIPTOR SecurityDescriptor ); +PHLIBAPI +BOOLEAN +NTAPI +PhGetObjectSecurityDescriptorAsString( + _In_ HANDLE Handle, + _Out_ PPH_STRING* SecurityDescriptorString + ); + PHLIBAPI NTSTATUS NTAPI @@ -456,14 +464,6 @@ PhGetAppContainerNamedObjectPath( _Out_ PPH_STRING* ObjectPath ); -PHLIBAPI -BOOLEAN -NTAPI -PhGetTokenSecurityDescriptorAsString( - _In_ HANDLE TokenHandle, - _Out_ PPH_STRING* SecurityDescriptorString - ); - PHLIBAPI NTSTATUS NTAPI diff --git a/phlib/native.c b/phlib/native.c index 8794fb312acf..f21df8584f9a 100644 --- a/phlib/native.c +++ b/phlib/native.c @@ -465,6 +465,42 @@ PPH_STRING PhGetSecurityDescriptorAsString( return securityDescriptorString; } +BOOLEAN PhGetObjectSecurityDescriptorAsString( + _In_ HANDLE Handle, + _Out_ PPH_STRING* SecurityDescriptorString + ) +{ + PSECURITY_DESCRIPTOR securityDescriptor; + PPH_STRING securityDescriptorString; + + if (NT_SUCCESS(PhGetObjectSecurity( + Handle, + OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | + DACL_SECURITY_INFORMATION | LABEL_SECURITY_INFORMATION | + ATTRIBUTE_SECURITY_INFORMATION | SCOPE_SECURITY_INFORMATION, + &securityDescriptor + ))) + { + if (securityDescriptorString = PhGetSecurityDescriptorAsString( + OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | + DACL_SECURITY_INFORMATION | LABEL_SECURITY_INFORMATION | + ATTRIBUTE_SECURITY_INFORMATION | SCOPE_SECURITY_INFORMATION, + securityDescriptor + )) + { + *SecurityDescriptorString = securityDescriptorString; + + PhFree(securityDescriptor); + return TRUE; + } + + PhFree(securityDescriptor); + } + + return FALSE; +} + + /** * Terminates a process. * @@ -2317,41 +2353,6 @@ NTSTATUS PhGetAppContainerNamedObjectPath( return status; } -BOOLEAN PhGetTokenSecurityDescriptorAsString( - _In_ HANDLE TokenHandle, - _Out_ PPH_STRING* SecurityDescriptorString - ) -{ - PSECURITY_DESCRIPTOR securityDescriptor; - PPH_STRING securityDescriptorString; - - if (NT_SUCCESS(PhGetObjectSecurity( - TokenHandle, - OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | - DACL_SECURITY_INFORMATION | LABEL_SECURITY_INFORMATION | - ATTRIBUTE_SECURITY_INFORMATION | SCOPE_SECURITY_INFORMATION, - &securityDescriptor - ))) - { - if (securityDescriptorString = PhGetSecurityDescriptorAsString( - OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | - DACL_SECURITY_INFORMATION | LABEL_SECURITY_INFORMATION | - ATTRIBUTE_SECURITY_INFORMATION | SCOPE_SECURITY_INFORMATION, - securityDescriptor - )) - { - *SecurityDescriptorString = securityDescriptorString; - - PhFree(securityDescriptor); - return TRUE; - } - - PhFree(securityDescriptor); - } - - return FALSE; -} - /** * Modifies a token privilege. * From 51ee5642441f48783a393558a0e116bf5f27412e Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 27 Jul 2019 02:10:13 +0200 Subject: [PATCH 2020/2058] Fix PhDeleteFile regression --- phlib/native.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phlib/native.c b/phlib/native.c index f21df8584f9a..28af3916cdc2 100644 --- a/phlib/native.c +++ b/phlib/native.c @@ -7718,7 +7718,7 @@ static BOOLEAN PhpDeleteDirectoryCallback( } else { - if (WindowsVersion < WINDOWS_10_RS5 && (Information->FileAttributes & FILE_ATTRIBUTE_READONLY)) + if (Information->FileAttributes & FILE_ATTRIBUTE_READONLY) { HANDLE fileHandle; From 5c1e5ce178d9e38bb6c3113b3cbe50900450c352 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 27 Jul 2019 02:10:44 +0200 Subject: [PATCH 2021/2058] Remove unused return --- phlib/util.c | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/phlib/util.c b/phlib/util.c index 32ebc843de13..9482637c3dab 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -562,32 +562,30 @@ VOID PhShowStatus( { PPH_STRING statusMessage; - statusMessage = PhGetStatusMessage(Status, Win32Result); - - if (!statusMessage) + if (statusMessage = PhGetStatusMessage(Status, Win32Result)) { if (Message) { - PhShowError(hWnd, L"%s.", Message); + PhShowError2(hWnd, Message, L"%s", statusMessage->Buffer); } else { - PhShowError(hWnd, L"Unable to perform the operation."); + PhShowError(hWnd, L"%s", statusMessage->Buffer); } - return; - } - - if (Message) - { - PhShowError2(hWnd, Message, L"%s", statusMessage->Buffer); + PhDereferenceObject(statusMessage); } else { - PhShowError(hWnd, L"%s", statusMessage->Buffer); + if (Message) + { + PhShowError(hWnd, L"%s.", Message); + } + else + { + PhShowError(hWnd, L"Unable to perform the operation."); + } } - - PhDereferenceObject(statusMessage); } /** From 09f60a4e57691a905dbfec1777450705a6655737 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 27 Jul 2019 02:17:32 +0200 Subject: [PATCH 2022/2058] Remove unused parameter --- ProcessHacker/actions.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/ProcessHacker/actions.c b/ProcessHacker/actions.c index eda52f17df05..c1865544e3a1 100644 --- a/ProcessHacker/actions.c +++ b/ProcessHacker/actions.c @@ -80,7 +80,6 @@ HRESULT CALLBACK PhpElevateActionCallbackProc( BOOLEAN PhpShowElevatePrompt( _In_ HWND hWnd, _In_ PWSTR Message, - _In_ NTSTATUS Status, _Out_ PINT Button ) { @@ -95,7 +94,7 @@ BOOLEAN PhpShowElevatePrompt( config.hwndParent = hWnd; config.hInstance = PhInstanceHandle; config.dwFlags = IsWindowVisible(hWnd) ? TDF_POSITION_RELATIVE_TO_WINDOW : 0; - config.pszWindowTitle = L"Process Hacker"; + config.pszWindowTitle = PhApplicationName; config.pszMainIcon = TD_ERROR_ICON; config.pszMainInstruction = PhaConcatStrings2(Message, L".")->Buffer; config.pszContent = L"You will need to provide administrator permission. " @@ -169,7 +168,7 @@ BOOLEAN PhpShowErrorAndElevateAction( if (elevationLevel == PromptElevateAction) { - if (!PhpShowElevatePrompt(hWnd, Message, Status, &button)) + if (!PhpShowElevatePrompt(hWnd, Message, &button)) return FALSE; } @@ -269,7 +268,7 @@ BOOLEAN PhpShowErrorAndConnectToPhSvc( if (elevationLevel == PromptElevateAction) { - if (!PhpShowElevatePrompt(hWnd, Message, Status, &button)) + if (!PhpShowElevatePrompt(hWnd, Message, &button)) return FALSE; } @@ -362,11 +361,14 @@ BOOLEAN PhpStartPhSvcProcess( for (i = 0; i < RTL_NUMBER_OF(relativeFileNames); i++) { PPH_STRING fileName; + PPH_STRING fileFullPath; + + fileName = PhConcatStringRefZ(&applicationDirectory->sr, relativeFileNames[i]); - fileName = PhConcatStrings2(applicationDirectory->Buffer, relativeFileNames[i]); - PhMoveReference(&fileName, PhGetFullPath(fileName->Buffer, NULL)); + if (fileFullPath = PhGetFullPath(fileName->Buffer, NULL)) + PhMoveReference(&fileName, fileFullPath); - if (fileName && PhDoesFileExistsWin32(fileName->Buffer)) + if (PhDoesFileExistsWin32(fileName->Buffer)) { if (PhShellProcessHackerEx( hWnd, @@ -385,10 +387,10 @@ BOOLEAN PhpStartPhSvcProcess( } } - PhClearReference(&fileName); + PhDereferenceObject(fileName); } - PhClearReference(&applicationDirectory); + PhDereferenceObject(applicationDirectory); } break; } From 21aef753184dcbe780ee33df71331a6cb67365dd Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 27 Jul 2019 02:19:56 +0200 Subject: [PATCH 2023/2058] Fix window title name --- ProcessHacker/mainwnd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index 9303b663e593..98cb38f126e7 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -122,7 +122,7 @@ BOOLEAN PhMainWndInitialization( PPH_STRING currentUserName; PhInitializeStringBuilder(&stringBuilder, 100); - PhAppendStringBuilder2(&stringBuilder, L"Process Hacker"); + PhAppendStringBuilder2(&stringBuilder, PhApplicationName); if (currentUserName = PhGetSidFullName(PhGetOwnTokenAttributes().TokenSid, TRUE, NULL)) { From 15d53be3724b9a2183e5d8b345850c7297ec1ebe Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 27 Jul 2019 15:25:20 +0200 Subject: [PATCH 2024/2058] WindowExplorer: Fix #448 --- plugins/WindowExplorer/wnddlg.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/plugins/WindowExplorer/wnddlg.c b/plugins/WindowExplorer/wnddlg.c index 4ad8dab84c90..2df3c40a1a10 100644 --- a/plugins/WindowExplorer/wnddlg.c +++ b/plugins/WindowExplorer/wnddlg.c @@ -638,11 +638,12 @@ INT_PTR CALLBACK WepWindowsDlgProc( if (selectedNode = WeGetSelectedWindowNode(&context->TreeContext)) { - WINDOWPLACEMENT placement = { sizeof(placement) }; + WINDOWPLACEMENT placement = { sizeof(WINDOWPLACEMENT) }; - GetWindowPlacement(selectedNode->WindowHandle, &placement); + if (!GetWindowPlacement(selectedNode->WindowHandle, &placement)) + break; - if (placement.showCmd == SW_SHOWMINIMIZED) + if (placement.showCmd == SW_SHOWMINIMIZED || placement.showCmd == SW_MINIMIZE) { ShowWindowAsync(selectedNode->WindowHandle, SW_RESTORE); } From 4b012a737ca9cf5cfd76cf6124ac945ae5904271 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 27 Jul 2019 17:31:04 +0200 Subject: [PATCH 2025/2058] Fix #447 --- phlib/util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phlib/util.c b/phlib/util.c index 9482637c3dab..74538a464131 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -1331,7 +1331,7 @@ PPH_STRING PhFormatTimeSpan( { PPH_STRING string; - string = PhCreateStringEx(NULL, PH_TIMESPAN_STR_LEN); + string = PhCreateStringEx(NULL, PH_TIMESPAN_STR_LEN * sizeof(WCHAR)); PhPrintTimeSpan(string->Buffer, Ticks, Mode); PhTrimToNullTerminatorString(string); From ae87606046e9edd92e5a9a565d01aaa71be582cc Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 28 Jul 2019 15:52:15 +0200 Subject: [PATCH 2026/2058] DotNetTools: Hide CLR statistics when the CLR data is invalid --- plugins/DotNetTools/perfpage.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/plugins/DotNetTools/perfpage.c b/plugins/DotNetTools/perfpage.c index 128030e9b643..5777b80d0ec4 100644 --- a/plugins/DotNetTools/perfpage.c +++ b/plugins/DotNetTools/perfpage.c @@ -935,6 +935,9 @@ INT_PTR CALLBACK DotNetPerfPageDlgProc( { NMLVDISPINFO *dispInfo = (NMLVDISPINFO *)header; + if (!context->ControlBlockValid) // Don't show statistics when the CLR data is invalid. (dmex) + break; + if (dispInfo->item.iSubItem == 1) { if (dispInfo->item.mask & LVIF_TEXT) From 813fd9a9685a4169fc28b1a63dba944774d795b7 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 28 Jul 2019 19:15:11 +0200 Subject: [PATCH 2027/2058] DotNetTools: Remove unused section handle --- plugins/DotNetTools/counters.c | 16 ++++++---------- plugins/DotNetTools/dn.h | 2 -- plugins/DotNetTools/perfpage.c | 8 -------- 3 files changed, 6 insertions(+), 20 deletions(-) diff --git a/plugins/DotNetTools/counters.c b/plugins/DotNetTools/counters.c index f1b53cae3ccb..4bf0a4dbf289 100644 --- a/plugins/DotNetTools/counters.c +++ b/plugins/DotNetTools/counters.c @@ -438,7 +438,6 @@ PPH_LIST EnumerateAppDomainIpcBlockWow64( BOOLEAN OpenDotNetPublicControlBlock_V2( _In_ HANDLE ProcessId, - _Out_ HANDLE* BlockTableHandle, _Out_ PVOID* BlockTableAddress ) { @@ -483,9 +482,9 @@ BOOLEAN OpenDotNetPublicControlBlock_V2( PAGE_READONLY ))) { - *BlockTableHandle = blockTableHandle; *BlockTableAddress = blockTableAddress; + NtClose(blockTableHandle); return TRUE; } @@ -502,7 +501,6 @@ BOOLEAN OpenDotNetPublicControlBlock_V4( _In_ BOOLEAN IsImmersive, _In_ HANDLE ProcessHandle, _In_ HANDLE ProcessId, - _Out_ HANDLE* BlockTableHandle, _Out_ PVOID* BlockTableAddress ) { @@ -600,7 +598,6 @@ BOOLEAN OpenDotNetPublicControlBlock_V4( goto CleanupExit; } - *BlockTableHandle = blockTableHandle; *BlockTableAddress = blockTableAddress; result = TRUE; @@ -609,20 +606,19 @@ BOOLEAN OpenDotNetPublicControlBlock_V4( if (!result) { - if (blockTableHandle) - { - NtClose(blockTableHandle); - } - if (blockTableAddress) { NtUnmapViewOfSection(NtCurrentProcess(), blockTableAddress); } - *BlockTableHandle = NULL; *BlockTableAddress = NULL; } + if (blockTableHandle) + { + NtClose(blockTableHandle); + } + if (tokenHandle) { NtClose(tokenHandle); diff --git a/plugins/DotNetTools/dn.h b/plugins/DotNetTools/dn.h index c334dd6be301..f0f70e6c4e30 100644 --- a/plugins/DotNetTools/dn.h +++ b/plugins/DotNetTools/dn.h @@ -68,7 +68,6 @@ PVOID GetPerfIpcBlock_V4( BOOLEAN OpenDotNetPublicControlBlock_V2( _In_ HANDLE ProcessId, - _Out_ HANDLE* BlockTableHandle, _Out_ PVOID* BlockTableAddress ); @@ -76,7 +75,6 @@ BOOLEAN OpenDotNetPublicControlBlock_V4( _In_ BOOLEAN IsImmersive, _In_ HANDLE ProcessHandle, _In_ HANDLE ProcessId, - _Out_ HANDLE* BlockTableHandle, _Out_ PVOID* BlockTableAddress ); diff --git a/plugins/DotNetTools/perfpage.c b/plugins/DotNetTools/perfpage.c index 5777b80d0ec4..fc63376281c4 100644 --- a/plugins/DotNetTools/perfpage.c +++ b/plugins/DotNetTools/perfpage.c @@ -152,7 +152,6 @@ typedef struct _PERFPAGE_CONTEXT }; HANDLE ProcessHandle; - HANDLE BlockTableHandle; PVOID BlockTableAddress; PH_CALLBACK_REGISTRATION ProcessesUpdatedCallbackRegistration; Perf_GC DotNetPerfGC; @@ -836,7 +835,6 @@ INT_PTR CALLBACK DotNetPerfPageDlgProc( !!context->ProcessItem->IsImmersive, context->ProcessHandle, context->ProcessItem->ProcessId, - &context->BlockTableHandle, &context->BlockTableAddress )) { @@ -847,7 +845,6 @@ INT_PTR CALLBACK DotNetPerfPageDlgProc( { if (OpenDotNetPublicControlBlock_V2( context->ProcessItem->ProcessId, - &context->BlockTableHandle, &context->BlockTableAddress )) { @@ -882,11 +879,6 @@ INT_PTR CALLBACK DotNetPerfPageDlgProc( NtUnmapViewOfSection(NtCurrentProcess(), context->BlockTableAddress); } - if (context->BlockTableHandle) - { - NtClose(context->BlockTableHandle); - } - if (context->ProcessHandle) { NtClose(context->ProcessHandle); From cd1b120640bdf8d42180ca3421d7a9b4efa83a4f Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 6 Aug 2019 17:41:29 +1000 Subject: [PATCH 2028/2058] DotNetTools: Update .NET AppDomain layout --- plugins/DotNetTools/DotNetTools.rc | 3 +-- plugins/DotNetTools/perfpage.c | 38 ++++++------------------------ plugins/DotNetTools/resource.h | 1 - 3 files changed, 8 insertions(+), 34 deletions(-) diff --git a/plugins/DotNetTools/DotNetTools.rc b/plugins/DotNetTools/DotNetTools.rc index e382546b5469..0574b642f188 100644 --- a/plugins/DotNetTools/DotNetTools.rc +++ b/plugins/DotNetTools/DotNetTools.rc @@ -92,8 +92,7 @@ STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSM CAPTION ".NET performance" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN - CONTROL "",IDC_APPDOMAINS,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_SORTASCENDING | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,2,3,256,67 - CONTROL "",IDC_COUNTERS,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,2,73,256,185 + CONTROL "",IDC_COUNTERS,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,2,3,256,255 END IDD_PROCDOTNETASM DIALOGEX 0, 0, 260, 260 diff --git a/plugins/DotNetTools/perfpage.c b/plugins/DotNetTools/perfpage.c index fc63376281c4..add61a24f978 100644 --- a/plugins/DotNetTools/perfpage.c +++ b/plugins/DotNetTools/perfpage.c @@ -134,7 +134,6 @@ typedef enum _DOTNET_INDEX typedef struct _PERFPAGE_CONTEXT { HWND WindowHandle; - HWND AppDomainsListViewHandle; HWND CountersListViewHandle; PPH_PROCESS_ITEM ProcessItem; @@ -593,7 +592,7 @@ VOID DotNetPerfAddListViewGroups( // Reserved for future use. } -VOID DotNetPerfAddProcessAppDomains( +/*VOID DotNetPerfAddProcessAppDomains( _In_ HWND hwndDlg, _In_ PPERFPAGE_CONTEXT Context ) @@ -641,7 +640,7 @@ VOID DotNetPerfAddProcessAppDomains( } ExtendedListView_SetRedraw(Context->AppDomainsListViewHandle, TRUE); -} +}*/ VOID DotNetPerfUpdateCounterData( _In_ HWND hwndDlg, @@ -773,15 +772,9 @@ INT_PTR CALLBACK DotNetPerfPageDlgProc( context = propPageContext->Context = PhAllocateZero(sizeof(PERFPAGE_CONTEXT)); context->WindowHandle = hwndDlg; context->ProcessItem = processItem; - context->AppDomainsListViewHandle = GetDlgItem(hwndDlg, IDC_APPDOMAINS); context->CountersListViewHandle = GetDlgItem(hwndDlg, IDC_COUNTERS); context->Enabled = TRUE; - PhSetListViewStyle(context->AppDomainsListViewHandle, FALSE, TRUE); - PhSetControlTheme(context->AppDomainsListViewHandle, L"explorer"); - PhAddListViewColumn(context->AppDomainsListViewHandle, 0, 0, 0, LVCFMT_LEFT, 300, L"Application domain"); - PhSetExtendedListView(context->AppDomainsListViewHandle); - PhSetListViewStyle(context->CountersListViewHandle, FALSE, TRUE); PhSetControlTheme(context->CountersListViewHandle, L"explorer"); PhAddListViewColumn(context->CountersListViewHandle, 0, 0, 0, LVCFMT_LEFT, 250, L"Counter"); @@ -821,12 +814,6 @@ INT_PTR CALLBACK DotNetPerfPageDlgProc( context->ClrV4 = TRUE; } } - - // Skip AppDomain enumeration of 'Modern' .NET applications as they don't expose the CLR 'Private IPC' block. - if (!context->ProcessItem->IsImmersive) - { - DotNetPerfAddProcessAppDomains(hwndDlg, context); - } } if (context->ClrV4) @@ -897,19 +884,15 @@ INT_PTR CALLBACK DotNetPerfPageDlgProc( if (dialogItem = PhBeginPropPageLayout(hwndDlg, propPageContext)) { - PhAddPropPageLayoutItem(hwndDlg, context->AppDomainsListViewHandle, dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); PhAddPropPageLayoutItem(hwndDlg, context->CountersListViewHandle, dialogItem, PH_ANCHOR_ALL); PhEndPropPageLayout(hwndDlg, propPageContext); } - - ExtendedListView_SetColumnWidth(context->AppDomainsListViewHandle, 0, ELVSCW_AUTOSIZE_REMAININGSPACE); } break; case WM_NOTIFY: { LPNMHDR header = (LPNMHDR)lParam; - PhHandleListViewNotifyBehaviors(lParam, context->AppDomainsListViewHandle, PH_LIST_VIEW_DEFAULT_1_BEHAVIORS); PhHandleListViewNotifyBehaviors(lParam, context->CountersListViewHandle, PH_LIST_VIEW_DEFAULT_1_BEHAVIORS); switch (header->code) @@ -1798,19 +1781,12 @@ INT_PTR CALLBACK DotNetPerfPageDlgProc( break; case WM_SIZE: { - ExtendedListView_SetColumnWidth(context->AppDomainsListViewHandle, 0, ELVSCW_AUTOSIZE_REMAININGSPACE); + //ExtendedListView_SetColumnWidth(context->AppDomainsListViewHandle, 0, ELVSCW_AUTOSIZE_REMAININGSPACE); } break; case WM_CONTEXTMENU: { - HWND listViewHandle = NULL; - - if ((HWND)wParam == context->AppDomainsListViewHandle) - listViewHandle = context->AppDomainsListViewHandle; - else if ((HWND)wParam == context->CountersListViewHandle) - listViewHandle = context->CountersListViewHandle; - - if (listViewHandle) + if ((HWND)wParam == context->CountersListViewHandle) { POINT point; PPH_EMENU menu; @@ -1824,13 +1800,13 @@ INT_PTR CALLBACK DotNetPerfPageDlgProc( if (point.x == -1 && point.y == -1) PhGetListViewContextMenuPoint((HWND)wParam, &point); - PhGetSelectedListViewItemParams(listViewHandle, &listviewItems, &numberOfItems); + PhGetSelectedListViewItemParams(context->CountersListViewHandle, &listviewItems, &numberOfItems); if (numberOfItems != 0) { menu = PhCreateEMenu(); PhInsertEMenuItem(menu, PhCreateEMenuItem(0, ID_CLR_COPY, L"&Copy", NULL, NULL), ULONG_MAX); - PhInsertCopyListViewEMenuItem(menu, ID_CLR_COPY, listViewHandle); + PhInsertCopyListViewEMenuItem(menu, ID_CLR_COPY, context->CountersListViewHandle); item = PhShowEMenu( menu, @@ -1856,7 +1832,7 @@ INT_PTR CALLBACK DotNetPerfPageDlgProc( { case ID_CLR_COPY: { - PhCopyListView(listViewHandle); + PhCopyListView(context->CountersListViewHandle); } break; } diff --git a/plugins/DotNetTools/resource.h b/plugins/DotNetTools/resource.h index 911b6d4e1ddc..e10bf043fe59 100644 --- a/plugins/DotNetTools/resource.h +++ b/plugins/DotNetTools/resource.h @@ -8,7 +8,6 @@ #define ID_CLR_COPY 104 #define ID_CLR_INSPECT 105 #define ID_COPY 106 -#define IDC_APPDOMAINS 1001 #define IDC_OPTIONS 1002 #define IDC_COUNTERS 1003 #define IDC_REFRESH 1003 From 1a4e27994b004eb6ccd4f445f5b2c671b95e1409 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 6 Aug 2019 17:46:22 +1000 Subject: [PATCH 2029/2058] Save process token group states --- ProcessHacker/settings.c | 3 ++- ProcessHacker/tokprp.c | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/ProcessHacker/settings.c b/ProcessHacker/settings.c index 176c0cf3ce31..965abfde667e 100644 --- a/ProcessHacker/settings.c +++ b/ProcessHacker/settings.c @@ -178,7 +178,8 @@ VOID PhAddDefaultSettings( PhpAddStringSetting(L"ThreadStackTreeListColumns", L""); PhpAddScalableIntegerPairSetting(L"ThreadStackWindowSize", L"@96|420,400"); PhpAddStringSetting(L"TokenGroupsListViewColumns", L""); - PhpAddStringSetting(L"TokenGroupsListViewSort", L""); + PhpAddStringSetting(L"TokenGroupsListViewStates", L""); + PhpAddStringSetting(L"TokenGroupsListViewSort", L"1,2"); PhpAddIntegerSetting(L"TokenSplitterEnable", L"0"); PhpAddIntegerSetting(L"TokenSplitterPosition", L"150"); PhpAddStringSetting(L"TokenPrivilegesListViewColumns", L""); diff --git a/ProcessHacker/tokprp.c b/ProcessHacker/tokprp.c index e08f15330e67..be55c1412f83 100644 --- a/ProcessHacker/tokprp.c +++ b/ProcessHacker/tokprp.c @@ -814,6 +814,7 @@ INT_PTR CALLBACK PhpTokenPageProc( PhAddListViewGroup(tokenPageContext->ListViewHandle, PH_PROCESS_TOKEN_CATEGORY_RESTRICTED, L"Restricting SIDs"); ListView_SetImageList(tokenPageContext->ListViewHandle, tokenPageContext->ListViewImageList, LVSIL_SMALL); PhLoadListViewColumnsFromSetting(L"TokenGroupsListViewColumns", tokenPageContext->ListViewHandle); + PhLoadListViewGroupStatesFromSetting(L"TokenGroupsListViewStates", tokenPageContext->ListViewHandle); PhLoadListViewSortColumnsFromSetting(L"TokenGroupsListViewSort", tokenPageContext->ListViewHandle); PhSetDialogItemText(hwndDlg, IDC_USER, L"Unknown"); @@ -942,6 +943,7 @@ INT_PTR CALLBACK PhpTokenPageProc( case WM_DESTROY: { PhSaveListViewSortColumnsToSetting(L"TokenGroupsListViewSort", tokenPageContext->ListViewHandle); + PhSaveListViewGroupStatesToSetting(L"TokenGroupsListViewStates", tokenPageContext->ListViewHandle); PhSaveListViewColumnsToSetting(L"TokenGroupsListViewColumns", tokenPageContext->ListViewHandle); if (tokenPageContext->ListViewImageList) From 7f5e35b9b7690d7dc6cce0ac7686d994a6d0a2ae Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 6 Aug 2019 22:53:58 +1000 Subject: [PATCH 2030/2058] Update default token ACL editor types --- phlib/secdata.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/phlib/secdata.c b/phlib/secdata.c index 439ffbdac802..4aec01b09e65 100644 --- a/phlib/secdata.c +++ b/phlib/secdata.c @@ -508,17 +508,17 @@ ACCESS_ENTRIES(TmTx) ACCESS_ENTRIES(Token) { { L"Full control", TOKEN_ALL_ACCESS, TRUE, TRUE }, - { L"Read", TOKEN_READ, TRUE, FALSE }, - { L"Write", TOKEN_WRITE, TRUE, FALSE }, - { L"Execute", TOKEN_EXECUTE, TRUE, FALSE }, - { L"Adjust privileges", TOKEN_ADJUST_PRIVILEGES, FALSE, TRUE }, - { L"Adjust groups", TOKEN_ADJUST_GROUPS, FALSE, TRUE }, - { L"Adjust defaults", TOKEN_ADJUST_DEFAULT, FALSE, TRUE }, - { L"Adjust session ID", TOKEN_ADJUST_SESSIONID, FALSE, TRUE }, - { L"Assign as primary token", TOKEN_ASSIGN_PRIMARY, FALSE, TRUE, L"Assign primary" }, - { L"Duplicate", TOKEN_DUPLICATE, FALSE, TRUE }, - { L"Impersonate", TOKEN_IMPERSONATE, FALSE, TRUE }, - { L"Query", TOKEN_QUERY, FALSE, TRUE }, + { L"Read", TOKEN_READ, FALSE, FALSE }, + { L"Write", TOKEN_WRITE, FALSE, FALSE }, + { L"Execute", TOKEN_EXECUTE, FALSE, FALSE }, + { L"Adjust privileges", TOKEN_ADJUST_PRIVILEGES, TRUE, TRUE }, + { L"Adjust groups", TOKEN_ADJUST_GROUPS, TRUE, TRUE }, + { L"Adjust defaults", TOKEN_ADJUST_DEFAULT, TRUE, TRUE }, + { L"Adjust session ID", TOKEN_ADJUST_SESSIONID, TRUE, TRUE }, + { L"Assign as primary token", TOKEN_ASSIGN_PRIMARY, TRUE, TRUE, L"Assign primary" }, + { L"Duplicate", TOKEN_DUPLICATE, TRUE, TRUE }, + { L"Impersonate", TOKEN_IMPERSONATE, TRUE, TRUE }, + { L"Query", TOKEN_QUERY, TRUE, TRUE }, { L"Query source", TOKEN_QUERY_SOURCE, FALSE, TRUE } }; From 7ca273409d4475e499a103b8dfd58bb0867df7ea Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 6 Aug 2019 22:54:30 +1000 Subject: [PATCH 2031/2058] ExtendedServices: Remove unused timer --- plugins/ExtendedServices/srvprgrs.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/ExtendedServices/srvprgrs.c b/plugins/ExtendedServices/srvprgrs.c index 0e8bcaabd939..0a505130c7eb 100644 --- a/plugins/ExtendedServices/srvprgrs.c +++ b/plugins/ExtendedServices/srvprgrs.c @@ -85,6 +85,8 @@ INT_PTR CALLBACK EspRestartServiceDlgProc( { case IDCANCEL: { + KillTimer(hwndDlg, 1); + EndDialog(hwndDlg, IDCANCEL); } break; From f3311d8a39773dac98f152f4523c9f5b50a1d9cd Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 6 Aug 2019 22:55:58 +1000 Subject: [PATCH 2032/2058] Fix window app name text --- ProcessHacker/miniinfo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ProcessHacker/miniinfo.c b/ProcessHacker/miniinfo.c index 18f8e86b8fe9..c89dc59be6cc 100644 --- a/ProcessHacker/miniinfo.c +++ b/ProcessHacker/miniinfo.c @@ -123,7 +123,7 @@ VOID PhPinMiniInformation( PhMipContainerWindow = CreateWindow( MAKEINTATOM(windowAtom), - PhGetIntegerSetting(L"EnableWindowText") ? L"Process Hacker" : NULL, + PhGetIntegerSetting(L"EnableWindowText") ? PhApplicationName : NULL, WS_BORDER | WS_THICKFRAME | WS_POPUP, 0, 0, From b9582f8b75ed61243bae824117344257ebafed48 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 7 Aug 2019 03:29:28 +1000 Subject: [PATCH 2033/2058] SetupTool: Improve caching --- .../CustomSetupTool/CustomSetupTool/appsup.c | 40 ++++++++++++++++ .../CustomSetupTool/CustomSetupTool/extract.c | 46 +++++++++++++++---- .../CustomSetupTool/include/setup.h | 3 +- .../CustomSetupTool/include/setupsup.h | 10 +++- .../CustomSetupTool/resources/version.rc | 2 +- 5 files changed, 89 insertions(+), 12 deletions(-) diff --git a/tools/CustomSetupTool/CustomSetupTool/appsup.c b/tools/CustomSetupTool/CustomSetupTool/appsup.c index 83a26b81e022..7f3b3eeaba2a 100644 --- a/tools/CustomSetupTool/CustomSetupTool/appsup.c +++ b/tools/CustomSetupTool/CustomSetupTool/appsup.c @@ -575,3 +575,43 @@ PPH_STRING SetupCreateFullPath( return pathString; } + +BOOLEAN SetupBase64StringToBufferEx( + _In_ PVOID InputBuffer, + _In_ ULONG InputBufferLength, + _Out_opt_ PVOID* OutputBuffer, + _Out_opt_ ULONG* OutputBufferLength + ) +{ + PVOID buffer = NULL; + ULONG bufferLength = 0; + ULONG bufferSkip = 0; + ULONG bufferFlags = 0; + + if (CryptStringToBinary(InputBuffer, InputBufferLength, CRYPT_STRING_BASE64, NULL, &bufferLength, &bufferSkip, &bufferFlags)) + { + if (buffer = PhAllocateSafe(bufferLength)) + { + if (!CryptStringToBinary(InputBuffer, InputBufferLength, CRYPT_STRING_BASE64, buffer, &bufferLength, &bufferSkip, &bufferFlags)) + { + PhFree(buffer); + buffer = NULL; + } + } + } + + if (buffer) + { + if (OutputBuffer) + *OutputBuffer = buffer; + else + PhFree(buffer); + + if (OutputBufferLength) + *OutputBufferLength = bufferLength; + + return TRUE; + } + + return FALSE; +} diff --git a/tools/CustomSetupTool/CustomSetupTool/extract.c b/tools/CustomSetupTool/CustomSetupTool/extract.c index f2f6421c2b22..f654fe4c6fee 100644 --- a/tools/CustomSetupTool/CustomSetupTool/extract.c +++ b/tools/CustomSetupTool/CustomSetupTool/extract.c @@ -38,12 +38,36 @@ BOOLEAN SetupExtractBuild( #ifdef PH_BUILD_API ULONG resourceLength; PVOID resourceBuffer = NULL; + PVOID zipBuffer = NULL; + ULONG zipBufferLength = 0; + PPH_STRING bufferString; if (!PhLoadResource(PhInstanceHandle, MAKEINTRESOURCE(IDR_BIN_DATA), RT_RCDATA, &resourceLength, &resourceBuffer)) return FALSE; - if (!(status = mz_zip_reader_init_mem(&zip_archive, resourceBuffer, resourceLength, 0))) + if (!(bufferString = PhZeroExtendToUtf16Ex(resourceBuffer, resourceLength))) + { + Context->ErrorCode = ERROR_PATH_NOT_FOUND; goto CleanupExit; + } + + if (!SetupBase64StringToBufferEx( + bufferString->Buffer, + bufferString->Length / sizeof(WCHAR), + &zipBuffer, + &zipBufferLength + )) + { + Context->ErrorCode = ERROR_PATH_NOT_FOUND; + goto CleanupExit; + } + + if (!(status = mz_zip_reader_init_mem(&zip_archive, zipBuffer, zipBufferLength, 0))) + { + Context->ErrorCode = ERROR_PATH_NOT_FOUND; + goto CleanupExit; + } + #else PPH_BYTES zipPathUtf8; @@ -256,16 +280,18 @@ BOOLEAN SetupExtractBuild( mz_free(buffer); } - { - mz_zip_reader_end(&zip_archive); + mz_zip_reader_end(&zip_archive); #ifdef PH_BUILD_API - if (resourceBuffer) - PhFree(resourceBuffer); + if (zipBuffer) + PhFree(zipBuffer); + if (resourceBuffer) + PhFree(resourceBuffer); + if (bufferString) + PhDereferenceObject(bufferString); #endif - if (extractPath) - PhDereferenceObject(extractPath); - } + if (extractPath) + PhDereferenceObject(extractPath); return TRUE; @@ -274,8 +300,12 @@ BOOLEAN SetupExtractBuild( mz_zip_reader_end(&zip_archive); #ifdef PH_BUILD_API + if (zipBuffer) + PhFree(zipBuffer); if (resourceBuffer) PhFree(resourceBuffer); + if (bufferString) + PhDereferenceObject(bufferString); #endif if (extractPath) PhDereferenceObject(extractPath); diff --git a/tools/CustomSetupTool/CustomSetupTool/include/setup.h b/tools/CustomSetupTool/CustomSetupTool/include/setup.h index 13f3aea379c8..fc6734629457 100644 --- a/tools/CustomSetupTool/CustomSetupTool/include/setup.h +++ b/tools/CustomSetupTool/CustomSetupTool/include/setup.h @@ -32,6 +32,7 @@ #include #include +#include #include #include #include @@ -284,4 +285,4 @@ VOID SetupShowUninstallDialog( VOID ); -#endif \ No newline at end of file +#endif diff --git a/tools/CustomSetupTool/CustomSetupTool/include/setupsup.h b/tools/CustomSetupTool/CustomSetupTool/include/setupsup.h index a766ce646206..afe7c130dc0f 100644 --- a/tools/CustomSetupTool/CustomSetupTool/include/setupsup.h +++ b/tools/CustomSetupTool/CustomSetupTool/include/setupsup.h @@ -73,8 +73,7 @@ BOOLEAN ShutdownProcessHacker( VOID ); -NTSTATUS -QueryProcessesUsingVolumeOrFile( +NTSTATUS QueryProcessesUsingVolumeOrFile( _In_ HANDLE VolumeOrFileHandle, _Out_ PFILE_PROCESS_IDS_USING_FILE_INFORMATION *Information ); @@ -84,4 +83,11 @@ PPH_STRING SetupCreateFullPath( _In_ PWSTR FileName ); +BOOLEAN SetupBase64StringToBufferEx( + _In_ PVOID InputBuffer, + _In_ ULONG InputBufferLength, + _Out_opt_ PVOID* OutputBuffer, + _Out_opt_ ULONG* OutputBufferLength + ); + #endif diff --git a/tools/CustomSetupTool/CustomSetupTool/resources/version.rc b/tools/CustomSetupTool/CustomSetupTool/resources/version.rc index 6d78a05f559e..73ed715bc03e 100644 --- a/tools/CustomSetupTool/CustomSetupTool/resources/version.rc +++ b/tools/CustomSetupTool/CustomSetupTool/resources/version.rc @@ -110,7 +110,7 @@ END // #if defined(PH_BUILD_API) -IDR_BIN_DATA RCDATA "../../../../build/output/processhacker-build-bin.zip" +IDR_BIN_DATA RCDATA "../../../../build/output/processhacker-build-bin.64" #endif From 11de28809190f12b3ee1648d332bd62115da4523 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 7 Aug 2019 03:36:12 +1000 Subject: [PATCH 2034/2058] BuildTools: Update to v4.7.2 --- tools/CustomBuildTool/CustomBuildTool.csproj | 2 +- .../Properties/Resources.Designer.cs | 2 +- tools/CustomBuildTool/Source Files/Build.cs | 8 +++++++- .../bin/Release/CustomBuildTool.exe | Bin 168448 -> 168960 bytes .../bin/Release/CustomBuildTool.pdb | Bin 85504 -> 85504 bytes 5 files changed, 9 insertions(+), 3 deletions(-) diff --git a/tools/CustomBuildTool/CustomBuildTool.csproj b/tools/CustomBuildTool/CustomBuildTool.csproj index 7c3f771214cf..ed8ea03ff67c 100644 --- a/tools/CustomBuildTool/CustomBuildTool.csproj +++ b/tools/CustomBuildTool/CustomBuildTool.csproj @@ -9,7 +9,7 @@ Properties CustomBuildTool CustomBuildTool - v4.6.1 + v4.7.2 512 true diff --git a/tools/CustomBuildTool/Properties/Resources.Designer.cs b/tools/CustomBuildTool/Properties/Resources.Designer.cs index 697eb463ba82..85e519b4710e 100644 --- a/tools/CustomBuildTool/Properties/Resources.Designer.cs +++ b/tools/CustomBuildTool/Properties/Resources.Designer.cs @@ -19,7 +19,7 @@ namespace CustomBuildTool.Properties { // class via a tool like ResGen or Visual Studio. // To add or remove a member, edit your .ResX file then rerun ResGen // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] internal class Resources { diff --git a/tools/CustomBuildTool/Source Files/Build.cs b/tools/CustomBuildTool/Source Files/Build.cs index 136bcaa43685..b1d5e83cdea2 100644 --- a/tools/CustomBuildTool/Source Files/Build.cs +++ b/tools/CustomBuildTool/Source Files/Build.cs @@ -903,9 +903,15 @@ public static bool BuildBinZip() if (File.Exists(BuildOutputFolder + "\\processhacker-build-bin.zip")) File.Delete(BuildOutputFolder + "\\processhacker-build-bin.zip"); - Zip.CreateCompressedFolder("bin", BuildOutputFolder + "\\processhacker-build-bin.zip"); + if (File.Exists(BuildOutputFolder + "\\processhacker-build-bin.64")) + File.Delete(BuildOutputFolder + "\\processhacker-build-bin.64"); + File.WriteAllBytes( + BuildOutputFolder + "\\processhacker-build-bin.64", + Encoding.UTF8.GetBytes(Convert.ToBase64String(File.ReadAllBytes(BuildOutputFolder + "\\processhacker-build-bin.zip"))) + ); + Directory.Move("bin\\x32", "bin\\Release32"); Directory.Move("bin\\x64", "bin\\Release64"); diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe b/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe index 2fb69b740cdd4026d01c36d5c0ac0decefe96ce0..b5f35893caf67efd7efc2f9188cdc7dc54120f44 100644 GIT binary patch delta 15061 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 A#sB~S delta 14873 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 diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb b/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb index cb320d1d49c8a2cd109c9567cc5a8a305ccaa013..7440abc8fe273860e058b50f827123241e784966 100644 GIT binary patch delta 7975 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� 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 SWT3z4Q=@?%Ir5xd_5KGWLiZ;C From fc09eb16e1157cb028e463754fc694d04f0389b3 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 7 Aug 2019 03:42:18 +1000 Subject: [PATCH 2035/2058] Update CustomSetupTool.vcxproj --- .../CustomSetupTool/CustomSetupTool.vcxproj | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj b/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj index b7fd319b2e09..c6b76fd0d6b4 100644 --- a/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj +++ b/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj @@ -65,11 +65,11 @@ true - comctl32.lib;uxtheme.lib;winhttp.lib;ntdll.lib;phlib.lib;shlwapi.lib;userenv.lib;windowscodecs.lib;winsta.lib;%(AdditionalDependencies) + comctl32.lib;crypt32.lib;uxtheme.lib;winhttp.lib;ntdll.lib;phlib.lib;shlwapi.lib;userenv.lib;windowscodecs.lib;winsta.lib;%(AdditionalDependencies) $(SolutionDir)..\..\phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) Windows 6.01 - advapi32.dll;comctl32.dll;gdi32.dll;ole32.dll;oleaut32.dll;shell32.dll;user32.dll;uxtheme.dll;winhttp.dll;%(DelayLoadDLLs) + advapi32.dll;comctl32.dll;crypt32.dll;gdi32.dll;ole32.dll;oleaut32.dll;shell32.dll;user32.dll;uxtheme.dll;winhttp.dll;%(DelayLoadDLLs) _UNICODE;UNICODE;%(PreprocessorDefinitions);$(ExternalCompilerOptions) @@ -97,12 +97,12 @@ true true true - comctl32.lib;uxtheme.lib;winhttp.lib;ntdll.lib;phlib.lib;shlwapi.lib;userenv.lib;windowscodecs.lib;winsta.lib;%(AdditionalDependencies) + comctl32.lib;crypt32.lib;uxtheme.lib;winhttp.lib;ntdll.lib;phlib.lib;shlwapi.lib;userenv.lib;windowscodecs.lib;winsta.lib;%(AdditionalDependencies) $(SolutionDir)..\..\phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) Windows 6.01 true - advapi32.dll;comctl32.dll;gdi32.dll;ole32.dll;oleaut32.dll;shell32.dll;user32.dll;uxtheme.dll;winhttp.dll;%(DelayLoadDLLs) + advapi32.dll;comctl32.dll;crypt32.dll;gdi32.dll;ole32.dll;oleaut32.dll;shell32.dll;user32.dll;uxtheme.dll;winhttp.dll;%(DelayLoadDLLs) _UNICODE;UNICODE;%(PreprocessorDefinitions);$(ExternalCompilerOptions) From 6989ac1667673cf8fadd5bebde0cbc6dfac4adc3 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 7 Aug 2019 04:10:19 +1000 Subject: [PATCH 2036/2058] Add GPU/Disk/Network to process statistics page --- ProcessHacker/include/phplug.h | 9 ++ ProcessHacker/include/procprpp.h | 1 + ProcessHacker/prpgstat.c | 156 ++++++++++++++++++------------- plugins/ExtendedTools/etwdisk.c | 9 +- plugins/ExtendedTools/exttools.h | 34 +++++++ plugins/ExtendedTools/main.c | 136 +++++++++++++++++++++++++-- 6 files changed, 267 insertions(+), 78 deletions(-) diff --git a/ProcessHacker/include/phplug.h b/ProcessHacker/include/phplug.h index b3d43a3fa010..eeaff9264c90 100644 --- a/ProcessHacker/include/phplug.h +++ b/ProcessHacker/include/phplug.h @@ -62,6 +62,7 @@ typedef enum _PH_GENERAL_CALLBACK GeneralCallbackLoggedEvent, GeneralCallbackTrayIconsInitializing, GeneralCallbackWindowNotifyEvent, + GeneralCallbackProcessStatsNotifyEvent, GeneralCallbackMaximum } PH_GENERAL_CALLBACK, *PPH_GENERAL_CALLBACK; @@ -128,6 +129,14 @@ typedef struct _PH_PLUGIN_OBJECT_PROPERTIES HPROPSHEETPAGE *Pages; } PH_PLUGIN_OBJECT_PROPERTIES, *PPH_PLUGIN_OBJECT_PROPERTIES; +typedef struct _PH_PLUGIN_PROCESS_STATS_EVENT +{ + ULONG Version; + ULONG Type; + PPH_PROCESS_ITEM ProcessItem; + PVOID Parameter; +} PH_PLUGIN_PROCESS_STATS_EVENT, *PPH_PLUGIN_PROCESS_STATS_EVENT; + typedef struct _PH_PLUGIN_HANDLE_PROPERTIES_CONTEXT { HANDLE ProcessId; diff --git a/ProcessHacker/include/procprpp.h b/ProcessHacker/include/procprpp.h index b6f58d33ddd3..7e5747b345ca 100644 --- a/ProcessHacker/include/procprpp.h +++ b/ProcessHacker/include/procprpp.h @@ -293,6 +293,7 @@ typedef struct _PH_STATISTICS_CONTEXT HWND ListViewHandle; BOOLEAN Enabled; HANDLE ProcessHandle; + PPH_PROCESS_ITEM ProcessItem; } PH_STATISTICS_CONTEXT, *PPH_STATISTICS_CONTEXT; #define WM_PH_PERFORMANCE_UPDATE (WM_APP + 241) diff --git a/ProcessHacker/prpgstat.c b/ProcessHacker/prpgstat.c index 068d49aa8c08..7fa296c15c23 100644 --- a/ProcessHacker/prpgstat.c +++ b/ProcessHacker/prpgstat.c @@ -103,79 +103,91 @@ typedef enum _PH_PROCESS_STATISTICS_INDEX } PH_PROCESS_STATISTICS_INDEX; VOID PhpUpdateStatisticsAddListViewGroups( - _In_ HWND ListViewHandle + _In_ PPH_STATISTICS_CONTEXT Context ) { - ListView_EnableGroupView(ListViewHandle, TRUE); - - PhAddListViewGroup(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_CPU, L"CPU"); - PhAddListViewGroup(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_MEMORY, L"Memory"); - PhAddListViewGroup(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_IO, L"I/O"); - PhAddListViewGroup(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_OTHER, L"Other"); - PhAddListViewGroup(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_EXTENSION, L"Extension"); - - PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_CPU, PH_PROCESS_STATISTICS_INDEX_PRIORITY, L"Priority", NULL); - PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_CPU, PH_PROCESS_STATISTICS_INDEX_CYCLES, L"Cycles", NULL); - PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_CPU, PH_PROCESS_STATISTICS_INDEX_CYCLESDELTA, L"Cycles delta", NULL); - PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_CPU, PH_PROCESS_STATISTICS_INDEX_KERNELTIME, L"Kernel time", NULL); - PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_CPU, PH_PROCESS_STATISTICS_INDEX_KERNELDELTA, L"Kernel delta", NULL); - PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_CPU, PH_PROCESS_STATISTICS_INDEX_USERTIME, L"User time", NULL); - PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_CPU, PH_PROCESS_STATISTICS_INDEX_USERDELTA, L"User delta", NULL); - PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_CPU, PH_PROCESS_STATISTICS_INDEX_TOTALTIME, L"Total time", NULL); - PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_CPU, PH_PROCESS_STATISTICS_INDEX_TOTALDELTA, L"Total delta", NULL); - - PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_MEMORY, PH_PROCESS_STATISTICS_INDEX_PRIVATEBYTES, L"Private bytes", NULL); - PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_MEMORY, PH_PROCESS_STATISTICS_INDEX_PRIVATEBYTESDELTA, L"Private bytes delta", NULL); - PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_MEMORY, PH_PROCESS_STATISTICS_INDEX_PEAKPRIVATEBYTES, L"Peak private bytes", NULL); - PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_MEMORY, PH_PROCESS_STATISTICS_INDEX_VIRTUALSIZE, L"Virtual size", NULL); - PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_MEMORY, PH_PROCESS_STATISTICS_INDEX_PEAKVIRTUALSIZE, L"Peak virtual size", NULL); - PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_MEMORY, PH_PROCESS_STATISTICS_INDEX_PAGEFAULTS, L"Page faults", NULL); - PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_MEMORY, PH_PROCESS_STATISTICS_INDEX_PAGEFAULTSDELTA, L"Page faults delta", NULL); - PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_MEMORY, PH_PROCESS_STATISTICS_INDEX_WORKINGSET, L"Working set", NULL); - PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_MEMORY, PH_PROCESS_STATISTICS_INDEX_PEAKWORKINGSET, L"Peak working set", NULL); - PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_MEMORY, PH_PROCESS_STATISTICS_INDEX_PRIVATEWS, L"Private WS", NULL); - PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_MEMORY, PH_PROCESS_STATISTICS_INDEX_SHAREABLEWS, L"Shareable WS", NULL); - PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_MEMORY, PH_PROCESS_STATISTICS_INDEX_SHAREDWS, L"Shared WS", NULL); - PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_MEMORY, PH_PROCESS_STATISTICS_INDEX_PAGEDPOOL, L"Paged pool bytes", NULL); - PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_MEMORY, PH_PROCESS_STATISTICS_INDEX_PEAKPAGEDPOOL, L"Peak paged pool bytes", NULL); - PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_MEMORY, PH_PROCESS_STATISTICS_INDEX_NONPAGED, L"Nonpaged pool bytes", NULL); - PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_MEMORY, PH_PROCESS_STATISTICS_INDEX_PEAKNONPAGED, L"Peak nonpaged pool bytes", NULL); - PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_MEMORY, PH_PROCESS_STATISTICS_INDEX_PAGEPRIORITY, L"Page priority", NULL); - - PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_IO, PH_PROCESS_STATISTICS_INDEX_READS, L"Reads", NULL); - PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_IO, PH_PROCESS_STATISTICS_INDEX_READSDELTA, L"Reads delta", NULL); - PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_IO, PH_PROCESS_STATISTICS_INDEX_READBYTES, L"Read bytes", NULL); - PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_IO, PH_PROCESS_STATISTICS_INDEX_READBYTESDELTA, L"Read bytes delta", NULL); - PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_IO, PH_PROCESS_STATISTICS_INDEX_WRITES, L"Writes", NULL); - PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_IO, PH_PROCESS_STATISTICS_INDEX_WRITESDELTA, L"Writes delta", NULL); - PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_IO, PH_PROCESS_STATISTICS_INDEX_WRITEBYTES, L"Write bytes", NULL); - PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_IO, PH_PROCESS_STATISTICS_INDEX_WRITEBYTESDELTA, L"Write bytes delta", NULL); - PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_IO, PH_PROCESS_STATISTICS_INDEX_OTHER, L"Other", NULL); - PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_IO, PH_PROCESS_STATISTICS_INDEX_OTHERDELTA, L"Other delta", NULL); - PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_IO, PH_PROCESS_STATISTICS_INDEX_OTHERBYTES, L"Other bytes", NULL); - PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_IO, PH_PROCESS_STATISTICS_INDEX_OTHERBYTESDELTA, L"Other bytes delta", NULL); - PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_IO, PH_PROCESS_STATISTICS_INDEX_IOPRIORITY, L"I/O priority", NULL); - - PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_OTHER, PH_PROCESS_STATISTICS_INDEX_HANDLES, L"Handles", NULL); - PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_OTHER, PH_PROCESS_STATISTICS_INDEX_PEAKHANDLES, L"Peak handles", NULL); - PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_OTHER, PH_PROCESS_STATISTICS_INDEX_GDIHANDLES, L"GDI handles", NULL); - PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_OTHER, PH_PROCESS_STATISTICS_INDEX_USERHANDLES, L"USER handles", NULL); + ListView_EnableGroupView(Context->ListViewHandle, TRUE); + + PhAddListViewGroup(Context->ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_CPU, L"CPU"); + PhAddListViewGroup(Context->ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_MEMORY, L"Memory"); + PhAddListViewGroup(Context->ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_IO, L"I/O"); + PhAddListViewGroup(Context->ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_OTHER, L"Other"); + PhAddListViewGroup(Context->ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_EXTENSION, L"Extension"); + + PhAddListViewGroupItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_CPU, PH_PROCESS_STATISTICS_INDEX_PRIORITY, L"Priority", NULL); + PhAddListViewGroupItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_CPU, PH_PROCESS_STATISTICS_INDEX_CYCLES, L"Cycles", NULL); + PhAddListViewGroupItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_CPU, PH_PROCESS_STATISTICS_INDEX_CYCLESDELTA, L"Cycles delta", NULL); + PhAddListViewGroupItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_CPU, PH_PROCESS_STATISTICS_INDEX_KERNELTIME, L"Kernel time", NULL); + PhAddListViewGroupItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_CPU, PH_PROCESS_STATISTICS_INDEX_KERNELDELTA, L"Kernel delta", NULL); + PhAddListViewGroupItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_CPU, PH_PROCESS_STATISTICS_INDEX_USERTIME, L"User time", NULL); + PhAddListViewGroupItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_CPU, PH_PROCESS_STATISTICS_INDEX_USERDELTA, L"User delta", NULL); + PhAddListViewGroupItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_CPU, PH_PROCESS_STATISTICS_INDEX_TOTALTIME, L"Total time", NULL); + PhAddListViewGroupItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_CPU, PH_PROCESS_STATISTICS_INDEX_TOTALDELTA, L"Total delta", NULL); + + PhAddListViewGroupItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_MEMORY, PH_PROCESS_STATISTICS_INDEX_PRIVATEBYTES, L"Private bytes", NULL); + PhAddListViewGroupItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_MEMORY, PH_PROCESS_STATISTICS_INDEX_PRIVATEBYTESDELTA, L"Private bytes delta", NULL); + PhAddListViewGroupItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_MEMORY, PH_PROCESS_STATISTICS_INDEX_PEAKPRIVATEBYTES, L"Peak private bytes", NULL); + PhAddListViewGroupItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_MEMORY, PH_PROCESS_STATISTICS_INDEX_VIRTUALSIZE, L"Virtual size", NULL); + PhAddListViewGroupItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_MEMORY, PH_PROCESS_STATISTICS_INDEX_PEAKVIRTUALSIZE, L"Peak virtual size", NULL); + PhAddListViewGroupItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_MEMORY, PH_PROCESS_STATISTICS_INDEX_PAGEFAULTS, L"Page faults", NULL); + PhAddListViewGroupItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_MEMORY, PH_PROCESS_STATISTICS_INDEX_PAGEFAULTSDELTA, L"Page faults delta", NULL); + PhAddListViewGroupItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_MEMORY, PH_PROCESS_STATISTICS_INDEX_WORKINGSET, L"Working set", NULL); + PhAddListViewGroupItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_MEMORY, PH_PROCESS_STATISTICS_INDEX_PEAKWORKINGSET, L"Peak working set", NULL); + PhAddListViewGroupItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_MEMORY, PH_PROCESS_STATISTICS_INDEX_PRIVATEWS, L"Private WS", NULL); + PhAddListViewGroupItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_MEMORY, PH_PROCESS_STATISTICS_INDEX_SHAREABLEWS, L"Shareable WS", NULL); + PhAddListViewGroupItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_MEMORY, PH_PROCESS_STATISTICS_INDEX_SHAREDWS, L"Shared WS", NULL); + PhAddListViewGroupItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_MEMORY, PH_PROCESS_STATISTICS_INDEX_PAGEDPOOL, L"Paged pool bytes", NULL); + PhAddListViewGroupItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_MEMORY, PH_PROCESS_STATISTICS_INDEX_PEAKPAGEDPOOL, L"Peak paged pool bytes", NULL); + PhAddListViewGroupItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_MEMORY, PH_PROCESS_STATISTICS_INDEX_NONPAGED, L"Nonpaged pool bytes", NULL); + PhAddListViewGroupItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_MEMORY, PH_PROCESS_STATISTICS_INDEX_PEAKNONPAGED, L"Peak nonpaged pool bytes", NULL); + PhAddListViewGroupItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_MEMORY, PH_PROCESS_STATISTICS_INDEX_PAGEPRIORITY, L"Page priority", NULL); + + PhAddListViewGroupItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_IO, PH_PROCESS_STATISTICS_INDEX_READS, L"Reads", NULL); + PhAddListViewGroupItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_IO, PH_PROCESS_STATISTICS_INDEX_READSDELTA, L"Reads delta", NULL); + PhAddListViewGroupItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_IO, PH_PROCESS_STATISTICS_INDEX_READBYTES, L"Read bytes", NULL); + PhAddListViewGroupItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_IO, PH_PROCESS_STATISTICS_INDEX_READBYTESDELTA, L"Read bytes delta", NULL); + PhAddListViewGroupItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_IO, PH_PROCESS_STATISTICS_INDEX_WRITES, L"Writes", NULL); + PhAddListViewGroupItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_IO, PH_PROCESS_STATISTICS_INDEX_WRITESDELTA, L"Writes delta", NULL); + PhAddListViewGroupItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_IO, PH_PROCESS_STATISTICS_INDEX_WRITEBYTES, L"Write bytes", NULL); + PhAddListViewGroupItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_IO, PH_PROCESS_STATISTICS_INDEX_WRITEBYTESDELTA, L"Write bytes delta", NULL); + PhAddListViewGroupItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_IO, PH_PROCESS_STATISTICS_INDEX_OTHER, L"Other", NULL); + PhAddListViewGroupItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_IO, PH_PROCESS_STATISTICS_INDEX_OTHERDELTA, L"Other delta", NULL); + PhAddListViewGroupItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_IO, PH_PROCESS_STATISTICS_INDEX_OTHERBYTES, L"Other bytes", NULL); + PhAddListViewGroupItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_IO, PH_PROCESS_STATISTICS_INDEX_OTHERBYTESDELTA, L"Other bytes delta", NULL); + PhAddListViewGroupItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_IO, PH_PROCESS_STATISTICS_INDEX_IOPRIORITY, L"I/O priority", NULL); + + PhAddListViewGroupItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_OTHER, PH_PROCESS_STATISTICS_INDEX_HANDLES, L"Handles", NULL); + PhAddListViewGroupItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_OTHER, PH_PROCESS_STATISTICS_INDEX_PEAKHANDLES, L"Peak handles", NULL); + PhAddListViewGroupItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_OTHER, PH_PROCESS_STATISTICS_INDEX_GDIHANDLES, L"GDI handles", NULL); + PhAddListViewGroupItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_OTHER, PH_PROCESS_STATISTICS_INDEX_USERHANDLES, L"USER handles", NULL); if (WindowsVersion >= WINDOWS_10_RS3) { - PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_OTHER, PH_PROCESS_STATISTICS_INDEX_RUNNINGTIME, L"Running time", NULL); - PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_OTHER, PH_PROCESS_STATISTICS_INDEX_SUSPENDEDTIME, L"Suspended time", NULL); - PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_OTHER, PH_PROCESS_STATISTICS_INDEX_HANGCOUNT, L"Hang count", NULL); - PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_OTHER, PH_PROCESS_STATISTICS_INDEX_GHOSTCOUNT, L"Ghost count", NULL); + PhAddListViewGroupItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_OTHER, PH_PROCESS_STATISTICS_INDEX_RUNNINGTIME, L"Running time", NULL); + PhAddListViewGroupItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_OTHER, PH_PROCESS_STATISTICS_INDEX_SUSPENDEDTIME, L"Suspended time", NULL); + PhAddListViewGroupItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_OTHER, PH_PROCESS_STATISTICS_INDEX_HANGCOUNT, L"Hang count", NULL); + PhAddListViewGroupItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_OTHER, PH_PROCESS_STATISTICS_INDEX_GHOSTCOUNT, L"Ghost count", NULL); } if (WindowsVersion >= WINDOWS_10_RS3 && !PhIsExecutingInWow64()) { - PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_EXTENSION, PH_PROCESS_STATISTICS_INDEX_CONTEXTSWITCHES, L"ContextSwitches", NULL); - PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_EXTENSION, PH_PROCESS_STATISTICS_INDEX_DISKREAD, L"BytesRead", NULL); - PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_EXTENSION, PH_PROCESS_STATISTICS_INDEX_DISKWRITE, L"BytesWritten", NULL); - PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_EXTENSION, PH_PROCESS_STATISTICS_INDEX_NETWORKTXRXBYTES, L"NetworkTxRxBytes", NULL); - PhAddListViewGroupItem(ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_EXTENSION, PH_PROCESS_STATISTICS_INDEX_MBBTXRXBYTES, L"MBBTxRxBytes", NULL); + PhAddListViewGroupItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_EXTENSION, PH_PROCESS_STATISTICS_INDEX_CONTEXTSWITCHES, L"ContextSwitches", NULL); + PhAddListViewGroupItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_EXTENSION, PH_PROCESS_STATISTICS_INDEX_DISKREAD, L"BytesRead", NULL); + PhAddListViewGroupItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_EXTENSION, PH_PROCESS_STATISTICS_INDEX_DISKWRITE, L"BytesWritten", NULL); + PhAddListViewGroupItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_EXTENSION, PH_PROCESS_STATISTICS_INDEX_NETWORKTXRXBYTES, L"NetworkTxRxBytes", NULL); + PhAddListViewGroupItem(Context->ListViewHandle, PH_PROCESS_STATISTICS_CATEGORY_EXTENSION, PH_PROCESS_STATISTICS_INDEX_MBBTXRXBYTES, L"MBBTxRxBytes", NULL); + } + + if (PhPluginsEnabled) + { + PH_PLUGIN_PROCESS_STATS_EVENT notifyEvent; + + notifyEvent.Version = 0; + notifyEvent.Type = 1; + notifyEvent.ProcessItem = Context->ProcessItem; + notifyEvent.Parameter = Context->ListViewHandle; + + PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackProcessStatsNotifyEvent), ¬ifyEvent); } } @@ -418,6 +430,18 @@ VOID PhpUpdateProcessStatistics( PhFree(processes); } } + + if (PhPluginsEnabled) + { + PH_PLUGIN_PROCESS_STATS_EVENT notifyEvent; + + notifyEvent.Version = 0; + notifyEvent.Type = 2; + notifyEvent.ProcessItem = Context->ProcessItem; + notifyEvent.Parameter = Context->ListViewHandle; + + PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackProcessStatsNotifyEvent), ¬ifyEvent); + } } static VOID NTAPI PhpStatisticsUpdateHandler( @@ -459,8 +483,8 @@ INT_PTR CALLBACK PhpProcessStatisticsDlgProc( statisticsContext = propPageContext->Context = PhAllocateZero(sizeof(PH_STATISTICS_CONTEXT)); statisticsContext->WindowHandle = hwndDlg; statisticsContext->ListViewHandle = GetDlgItem(hwndDlg, IDC_STATISTICS_LIST); + statisticsContext->ProcessItem = processItem; statisticsContext->Enabled = TRUE; - statisticsContext->ProcessHandle = NULL; // Try to open a process handle with PROCESS_QUERY_INFORMATION access for WS information. if (PH_IS_REAL_PROCESS_ID(processItem->ProcessId)) @@ -478,7 +502,7 @@ INT_PTR CALLBACK PhpProcessStatisticsDlgProc( PhAddListViewColumn(statisticsContext->ListViewHandle, 1, 1, 1, LVCFMT_LEFT, 150, L"Value"); PhSetExtendedListView(statisticsContext->ListViewHandle); - PhpUpdateStatisticsAddListViewGroups(statisticsContext->ListViewHandle); + PhpUpdateStatisticsAddListViewGroups(statisticsContext); PhLoadListViewGroupStatesFromSetting(L"ProcStatPropPageGroupStates", statisticsContext->ListViewHandle); PhRegisterCallback( diff --git a/plugins/ExtendedTools/etwdisk.c b/plugins/ExtendedTools/etwdisk.c index 0542374a13b3..237a1d09c3d0 100644 --- a/plugins/ExtendedTools/etwdisk.c +++ b/plugins/ExtendedTools/etwdisk.c @@ -52,10 +52,10 @@ VOID NTAPI EtpDiskProcessesUpdatedCallback( BOOLEAN EtDiskEnabled = FALSE; ULONG EtRunCount = 0; -PPH_OBJECT_TYPE EtDiskItemType; -PPH_HASHTABLE EtDiskHashtable; +PPH_OBJECT_TYPE EtDiskItemType = NULL; +PPH_HASHTABLE EtDiskHashtable = NULL; PH_QUEUED_LOCK EtDiskHashtableLock = PH_QUEUED_LOCK_INIT; -LIST_ENTRY EtDiskAgeListHead; +LIST_ENTRY EtDiskAgeListHead = { &EtDiskAgeListHead, &EtDiskAgeListHead }; PH_CALLBACK_DECLARE(EtDiskItemAddedEvent); PH_CALLBACK_DECLARE(EtDiskItemModifiedEvent); PH_CALLBACK_DECLARE(EtDiskItemRemovedEvent); @@ -63,7 +63,7 @@ PH_CALLBACK_DECLARE(EtDiskItemsUpdatedEvent); PH_FREE_LIST EtDiskPacketFreeList; SLIST_HEADER EtDiskPacketListHead; -PPH_HASHTABLE EtFileNameHashtable; +PPH_HASHTABLE EtFileNameHashtable = NULL; PH_QUEUED_LOCK EtFileNameHashtableLock = PH_QUEUED_LOCK_INIT; static LARGE_INTEGER EtpPerformanceFrequency; @@ -82,7 +82,6 @@ VOID EtInitializeDiskInformation( EtpDiskHashtableHashFunction, 128 ); - InitializeListHead(&EtDiskAgeListHead); PhInitializeFreeList(&EtDiskPacketFreeList, sizeof(ETP_DISK_PACKET), 64); RtlInitializeSListHead(&EtDiskPacketListHead); diff --git a/plugins/ExtendedTools/exttools.h b/plugins/ExtendedTools/exttools.h index 766fe873a789..d5b1fe6a8d7c 100644 --- a/plugins/ExtendedTools/exttools.h +++ b/plugins/ExtendedTools/exttools.h @@ -193,6 +193,38 @@ typedef struct _ET_DISK_NODE #define ETNETNC_TOTALRATE 14 #define ETNETNC_MAXIMUM 14 +typedef enum _ET_PROCESS_STATISTICS_CATEGORY +{ + ET_PROCESS_STATISTICS_CATEGORY_GPU, + ET_PROCESS_STATISTICS_CATEGORY_DISK, + ET_PROCESS_STATISTICS_CATEGORY_NETWORK, + ET_PROCESS_STATISTICS_CATEGORY_MAX +} ET_PROCESS_STATISTICS_CATEGORY; + +typedef enum _ET_PROCESS_STATISTICS_INDEX +{ + ET_PROCESS_STATISTICS_INDEX_RUNNINGTIME, + ET_PROCESS_STATISTICS_INDEX_CONTEXTSWITCHES, + ET_PROCESS_STATISTICS_INDEX_TOTALNODES, + ET_PROCESS_STATISTICS_INDEX_TOTALSEGMENTS, + + ET_PROCESS_STATISTICS_INDEX_DISKREADS, + ET_PROCESS_STATISTICS_INDEX_DISKREADBYTES, + ET_PROCESS_STATISTICS_INDEX_DISKREADBYTESDELTA, + ET_PROCESS_STATISTICS_INDEX_DISKWRITES, + ET_PROCESS_STATISTICS_INDEX_DISKWRITEBYTES, + ET_PROCESS_STATISTICS_INDEX_DISKWRITEBYTESDELTA, + + ET_PROCESS_STATISTICS_INDEX_NETWORKREADS, + ET_PROCESS_STATISTICS_INDEX_NETWORKREADBYTES, + ET_PROCESS_STATISTICS_INDEX_NETWORKREADBYTESDELTA, + ET_PROCESS_STATISTICS_INDEX_NETWORKWRITES, + ET_PROCESS_STATISTICS_INDEX_NETWORKWRITEBYTES, + ET_PROCESS_STATISTICS_INDEX_NETWORKWRITEBYTESDELTA, + + ET_PROCESS_STATISTICS_INDEX_MAX +} ET_PROCESS_STATISTICS_INDEX; + // Firewall status typedef enum _ET_FIREWALL_STATUS @@ -245,6 +277,8 @@ typedef struct _ET_PROCESS_BLOCK PH_QUEUED_LOCK TextCacheLock; PPH_STRING TextCache[ETPRTNC_MAXIMUM + 1]; BOOLEAN TextCacheValid[ETPRTNC_MAXIMUM + 1]; + ULONG ListViewGroupCache[ET_PROCESS_STATISTICS_CATEGORY_MAX + 1]; + ULONG ListViewRowCache[ET_PROCESS_STATISTICS_INDEX_MAX + 1]; } ET_PROCESS_BLOCK, *PET_PROCESS_BLOCK; typedef struct _ET_NETWORK_BLOCK diff --git a/plugins/ExtendedTools/main.c b/plugins/ExtendedTools/main.c index 92746e219d6a..6efea0bd8782 100644 --- a/plugins/ExtendedTools/main.c +++ b/plugins/ExtendedTools/main.c @@ -23,11 +23,11 @@ #include "exttools.h" -PPH_PLUGIN PluginInstance; -LIST_ENTRY EtProcessBlockListHead; -LIST_ENTRY EtNetworkBlockListHead; -HWND ProcessTreeNewHandle; -HWND NetworkTreeNewHandle; +PPH_PLUGIN PluginInstance = NULL; +HWND ProcessTreeNewHandle = NULL; +HWND NetworkTreeNewHandle = NULL; +LIST_ENTRY EtProcessBlockListHead = { &EtProcessBlockListHead, &EtProcessBlockListHead }; +LIST_ENTRY EtNetworkBlockListHead = { &EtNetworkBlockListHead, &EtNetworkBlockListHead }; PH_CALLBACK_REGISTRATION PluginLoadCallbackRegistration; PH_CALLBACK_REGISTRATION PluginUnloadCallbackRegistration; PH_CALLBACK_REGISTRATION PluginShowOptionsCallbackRegistration; @@ -48,6 +48,7 @@ PH_CALLBACK_REGISTRATION MiniInformationInitializingCallbackRegistration; PH_CALLBACK_REGISTRATION TrayIconsInitializingCallbackRegistration; PH_CALLBACK_REGISTRATION ProcessItemsUpdatedCallbackRegistration; PH_CALLBACK_REGISTRATION NetworkItemsUpdatedCallbackRegistration; +PH_CALLBACK_REGISTRATION ProcessStatsEventCallbackRegistration; ULONG ProcessesUpdatedCount = 0; static HANDLE ModuleProcessId = NULL; @@ -390,6 +391,123 @@ VOID NTAPI NetworkItemsUpdatedCallback( } } +VOID NTAPI ProcessStatsEventCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + PPH_PLUGIN_PROCESS_STATS_EVENT event = Parameter; + + if (event->Version) + return; + + switch (event->Type) + { + case 1: + { + HWND listViewHandle = event->Parameter; + PET_PROCESS_BLOCK block; + + if (!(block = EtGetProcessBlock(event->ProcessItem))) + break; + + block->ListViewGroupCache[ET_PROCESS_STATISTICS_CATEGORY_GPU] = PhAddListViewGroup( + listViewHandle, (INT)ListView_GetGroupCount(listViewHandle), L"GPU"); + block->ListViewRowCache[ET_PROCESS_STATISTICS_INDEX_RUNNINGTIME] = PhAddListViewGroupItem( + listViewHandle, block->ListViewGroupCache[ET_PROCESS_STATISTICS_CATEGORY_GPU], MAXINT, L"Running time", NULL); + block->ListViewRowCache[ET_PROCESS_STATISTICS_INDEX_CONTEXTSWITCHES] = PhAddListViewGroupItem( + listViewHandle, block->ListViewGroupCache[ET_PROCESS_STATISTICS_CATEGORY_GPU], MAXINT, L"Context switches", NULL); + block->ListViewRowCache[ET_PROCESS_STATISTICS_INDEX_TOTALNODES] = PhAddListViewGroupItem( + listViewHandle, block->ListViewGroupCache[ET_PROCESS_STATISTICS_CATEGORY_GPU], MAXINT, L"Total Nodes", NULL); + block->ListViewRowCache[ET_PROCESS_STATISTICS_INDEX_TOTALSEGMENTS] = PhAddListViewGroupItem( + listViewHandle, block->ListViewGroupCache[ET_PROCESS_STATISTICS_CATEGORY_GPU], MAXINT, L"Total Segments", NULL); + + block->ListViewGroupCache[ET_PROCESS_STATISTICS_CATEGORY_DISK] = PhAddListViewGroup( + listViewHandle, (INT)ListView_GetGroupCount(event->Parameter), L"Disk I/O"); + block->ListViewRowCache[ET_PROCESS_STATISTICS_INDEX_DISKREADS] = PhAddListViewGroupItem( + listViewHandle, block->ListViewGroupCache[ET_PROCESS_STATISTICS_CATEGORY_DISK], MAXINT, L"Reads", NULL); + block->ListViewRowCache[ET_PROCESS_STATISTICS_INDEX_DISKREADBYTES] = PhAddListViewGroupItem( + listViewHandle, block->ListViewGroupCache[ET_PROCESS_STATISTICS_CATEGORY_DISK], MAXINT, L"Read bytes", NULL); + block->ListViewRowCache[ET_PROCESS_STATISTICS_INDEX_DISKREADBYTESDELTA] = PhAddListViewGroupItem( + listViewHandle, block->ListViewGroupCache[ET_PROCESS_STATISTICS_CATEGORY_DISK], MAXINT, L"Read bytes delta", NULL); + block->ListViewRowCache[ET_PROCESS_STATISTICS_INDEX_DISKWRITES] = PhAddListViewGroupItem( + listViewHandle, block->ListViewGroupCache[ET_PROCESS_STATISTICS_CATEGORY_DISK], MAXINT, L"Writes", NULL); + block->ListViewRowCache[ET_PROCESS_STATISTICS_INDEX_DISKWRITEBYTES] = PhAddListViewGroupItem( + listViewHandle, block->ListViewGroupCache[ET_PROCESS_STATISTICS_CATEGORY_DISK], MAXINT, L"Write bytes", NULL); + block->ListViewRowCache[ET_PROCESS_STATISTICS_INDEX_DISKWRITEBYTESDELTA] = PhAddListViewGroupItem( + listViewHandle, block->ListViewGroupCache[ET_PROCESS_STATISTICS_CATEGORY_DISK], MAXINT, L"Write bytes delta", NULL); + + block->ListViewGroupCache[ET_PROCESS_STATISTICS_CATEGORY_NETWORK] = PhAddListViewGroup( + listViewHandle, (INT)ListView_GetGroupCount(event->Parameter), L"Network I/O"); + block->ListViewRowCache[ET_PROCESS_STATISTICS_INDEX_NETWORKREADS] = PhAddListViewGroupItem( + listViewHandle, block->ListViewGroupCache[ET_PROCESS_STATISTICS_CATEGORY_NETWORK], MAXINT, L"Receives", NULL); + block->ListViewRowCache[ET_PROCESS_STATISTICS_INDEX_NETWORKREADBYTES] = PhAddListViewGroupItem( + listViewHandle, block->ListViewGroupCache[ET_PROCESS_STATISTICS_CATEGORY_NETWORK], MAXINT, L"Receive bytes", NULL); + block->ListViewRowCache[ET_PROCESS_STATISTICS_INDEX_NETWORKREADBYTESDELTA] = PhAddListViewGroupItem( + listViewHandle, block->ListViewGroupCache[ET_PROCESS_STATISTICS_CATEGORY_NETWORK], MAXINT, L"Receive bytes delta", NULL); + block->ListViewRowCache[ET_PROCESS_STATISTICS_INDEX_NETWORKWRITES] = PhAddListViewGroupItem( + listViewHandle, block->ListViewGroupCache[ET_PROCESS_STATISTICS_CATEGORY_NETWORK], MAXINT, L"Sends", NULL); + block->ListViewRowCache[ET_PROCESS_STATISTICS_INDEX_NETWORKWRITEBYTES] = PhAddListViewGroupItem( + listViewHandle, block->ListViewGroupCache[ET_PROCESS_STATISTICS_CATEGORY_NETWORK], MAXINT, L"Send bytes", NULL); + block->ListViewRowCache[ET_PROCESS_STATISTICS_INDEX_NETWORKWRITEBYTESDELTA] = PhAddListViewGroupItem( + listViewHandle, block->ListViewGroupCache[ET_PROCESS_STATISTICS_CATEGORY_NETWORK], MAXINT, L"Send bytes delta", NULL); + } + break; + case 2: + { + HWND listViewHandle = event->Parameter; + PET_PROCESS_BLOCK block; + ET_PROCESS_GPU_STATISTICS gpuStatistics; + WCHAR runningTimeString[PH_TIMESPAN_STR_LEN_1] = L"N/A"; + + if (!(block = EtGetProcessBlock(event->ProcessItem))) + break; + + if (block->ProcessItem->QueryHandle) + EtQueryProcessGpuStatistics(block->ProcessItem->QueryHandle, &gpuStatistics); + else + memset(&gpuStatistics, 0, sizeof(ET_PROCESS_GPU_STATISTICS)); + + PhPrintTimeSpan(runningTimeString, gpuStatistics.RunningTime * 10, PH_TIMESPAN_HMSM); + PhSetListViewSubItem(listViewHandle, block->ListViewRowCache[ET_PROCESS_STATISTICS_INDEX_RUNNINGTIME], 1, + runningTimeString); + PhSetListViewSubItem(listViewHandle, block->ListViewRowCache[ET_PROCESS_STATISTICS_INDEX_CONTEXTSWITCHES], 1, + PhaFormatUInt64(gpuStatistics.ContextSwitches, TRUE)->Buffer); + PhSetListViewSubItem(listViewHandle, block->ListViewRowCache[ET_PROCESS_STATISTICS_INDEX_TOTALNODES], 1, + PhaFormatUInt64(gpuStatistics.NodeCount, TRUE)->Buffer); + PhSetListViewSubItem(listViewHandle, block->ListViewRowCache[ET_PROCESS_STATISTICS_INDEX_TOTALSEGMENTS], 1, + PhaFormatUInt64(gpuStatistics.SegmentCount, TRUE)->Buffer); + + PhSetListViewSubItem(listViewHandle, block->ListViewRowCache[ET_PROCESS_STATISTICS_INDEX_DISKREADS], 1, + PhaFormatUInt64(block->DiskReadCount, TRUE)->Buffer); + PhSetListViewSubItem(listViewHandle, block->ListViewRowCache[ET_PROCESS_STATISTICS_INDEX_DISKREADBYTES], 1, + PhaFormatSize(block->DiskReadRawDelta.Value, ULONG_MAX)->Buffer); + PhSetListViewSubItem(listViewHandle, block->ListViewRowCache[ET_PROCESS_STATISTICS_INDEX_DISKREADBYTESDELTA], 1, + PhaFormatSize(block->DiskReadRawDelta.Delta, ULONG_MAX)->Buffer); + PhSetListViewSubItem(listViewHandle, block->ListViewRowCache[ET_PROCESS_STATISTICS_INDEX_DISKWRITES], 1, + PhaFormatUInt64(block->DiskWriteCount, TRUE)->Buffer); + PhSetListViewSubItem(listViewHandle, block->ListViewRowCache[ET_PROCESS_STATISTICS_INDEX_DISKWRITEBYTES], 1, + PhaFormatSize(block->DiskWriteRawDelta.Value, ULONG_MAX)->Buffer); + PhSetListViewSubItem(listViewHandle, block->ListViewRowCache[ET_PROCESS_STATISTICS_INDEX_DISKWRITEBYTESDELTA], 1, + PhaFormatSize(block->DiskWriteRawDelta.Delta, ULONG_MAX)->Buffer); + + PhSetListViewSubItem(listViewHandle, block->ListViewRowCache[ET_PROCESS_STATISTICS_INDEX_NETWORKREADS], 1, + PhaFormatUInt64(block->NetworkReceiveCount, TRUE)->Buffer); + PhSetListViewSubItem(listViewHandle, block->ListViewRowCache[ET_PROCESS_STATISTICS_INDEX_NETWORKREADBYTES], 1, + PhaFormatSize(block->NetworkReceiveRawDelta.Value, ULONG_MAX)->Buffer); + PhSetListViewSubItem(listViewHandle, block->ListViewRowCache[ET_PROCESS_STATISTICS_INDEX_NETWORKREADBYTESDELTA], 1, + PhaFormatSize(block->NetworkReceiveRawDelta.Delta, ULONG_MAX)->Buffer); + PhSetListViewSubItem(listViewHandle, block->ListViewRowCache[ET_PROCESS_STATISTICS_INDEX_NETWORKWRITES], 1, + PhaFormatUInt64(block->NetworkSendCount, TRUE)->Buffer); + PhSetListViewSubItem(listViewHandle, block->ListViewRowCache[ET_PROCESS_STATISTICS_INDEX_NETWORKWRITEBYTES], 1, + PhaFormatSize(block->NetworkSendRawDelta.Value, ULONG_MAX)->Buffer); + PhSetListViewSubItem(listViewHandle, block->ListViewRowCache[ET_PROCESS_STATISTICS_INDEX_NETWORKWRITEBYTESDELTA], 1, + PhaFormatSize(block->NetworkSendRawDelta.Delta, ULONG_MAX)->Buffer); + } + break; + } +} + PET_PROCESS_BLOCK EtGetProcessBlock( _In_ PPH_PROCESS_ITEM ProcessItem ) @@ -660,8 +778,12 @@ LOGICAL DllMain( &NetworkItemsUpdatedCallbackRegistration ); - InitializeListHead(&EtProcessBlockListHead); - InitializeListHead(&EtNetworkBlockListHead); + PhRegisterCallback( + PhGetGeneralCallback(GeneralCallbackProcessStatsNotifyEvent), + ProcessStatsEventCallback, + NULL, + &ProcessStatsEventCallbackRegistration + ); PhPluginSetObjectExtension( PluginInstance, From 85e5c3141d8d2b02c847a2cb58b31d09e0b2340b Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 7 Aug 2019 07:33:31 +1000 Subject: [PATCH 2037/2058] peview: Improve file dialog performance --- tools/peview/main.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/tools/peview/main.c b/tools/peview/main.c index 8df47a4e7422..2fa7380e4846 100644 --- a/tools/peview/main.c +++ b/tools/peview/main.c @@ -134,7 +134,28 @@ INT WINAPI wWinMain( if (PhShowFileDialog(NULL, fileDialog)) { - PvFileName = PhGetFileDialogFileName(fileDialog); + PPH_STRING applicationFileName; + + if (PvFileName = PhGetFileDialogFileName(fileDialog)) + { + if (applicationFileName = PhGetApplicationFileName()) + { + PhMoveReference(&PvFileName, PhConcatStrings(3, L"\"", PvFileName->Buffer, L"\"")); + + if (PhShellExecuteEx( + NULL, + PhGetString(applicationFileName), + PvFileName->Buffer, + SW_SHOWDEFAULT, + 0, + ULONG_MAX, + NULL + )) + { + RtlExitUserProcess(STATUS_SUCCESS); + } + } + } } PhFreeFileDialog(fileDialog); From c644c5196d86200f68725ac72d6100cdc942082b Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 7 Aug 2019 07:37:35 +1000 Subject: [PATCH 2038/2058] peview: Add options button --- tools/peview/include/pdb.h | 6 +- tools/peview/include/peview.h | 6 ++ tools/peview/peprp.c | 74 +------------ tools/peview/peview.rc | 16 +++ tools/peview/prpsh.c | 193 ++++++++++++++++++++++++++++++++-- tools/peview/resource.h | 6 ++ tools/peview/searchbox.c | 30 +++--- tools/peview/settings.c | 1 + 8 files changed, 232 insertions(+), 100 deletions(-) diff --git a/tools/peview/include/pdb.h b/tools/peview/include/pdb.h index f4891ac22cd1..0ecc68302afa 100644 --- a/tools/peview/include/pdb.h +++ b/tools/peview/include/pdb.h @@ -547,9 +547,9 @@ PPH_STRING SymbolInfo_GetTypeName( _In_ ULONG Index, _In_ PWSTR VarName ); -PWSTR SymbolInfo_TagStr(enum SymTagEnum Tag); -PWSTR SymbolInfo_BaseTypeStr(BasicType Type, ULONG64 Length); -PWSTR SymbolInfo_CallConvStr(CV_call_e CallConv); +PWSTR SymbolInfo_TagStr(_In_ enum SymTagEnum Tag); +PWSTR SymbolInfo_BaseTypeStr(_In_ BasicType Type, _In_ ULONG64 Length); +PWSTR SymbolInfo_CallConvStr(_In_ CV_call_e CallConv); PWSTR SymbolInfo_DataKindFromSymbolInfo(_In_ PSYMBOL_INFOW rSymbol); PWSTR SymbolInfo_DataKindStr(DataKind dataKind); VOID SymbolInfo_SymbolLocationStr(PSYMBOL_INFOW rSymbol, PWSTR pBuffer); diff --git a/tools/peview/include/peview.h b/tools/peview/include/peview.h index 056f561a5d4b..4cf8ebc40eff 100644 --- a/tools/peview/include/peview.h +++ b/tools/peview/include/peview.h @@ -64,6 +64,12 @@ VOID PvPeProperties( VOID ); +NTSTATUS PhpOpenFileSecurity( + _Out_ PHANDLE Handle, + _In_ ACCESS_MASK DesiredAccess, + _In_opt_ PVOID Context + ); + // libprp VOID PvLibProperties( diff --git a/tools/peview/peprp.c b/tools/peview/peprp.c index 95ee0bda7f4b..d4dc6c1b2f3a 100644 --- a/tools/peview/peprp.c +++ b/tools/peview/peprp.c @@ -3,7 +3,7 @@ * PE viewer * * Copyright (C) 2010-2011 wj32 - * Copyright (C) 2017-2018 dmex + * Copyright (C) 2017-2019 dmex * * This file is part of Process Hacker. * @@ -52,8 +52,6 @@ HICON PvImageLargeIcon = NULL; PH_IMAGE_VERSION_INFO PvImageVersionInfo; static VERIFY_RESULT PvImageVerifyResult; static PPH_STRING PvImageSignerName; -static HWND ResetButton; -static WNDPROC OldWndProc; VOID PvPeProperties( VOID @@ -453,7 +451,7 @@ FORCEINLINE PPH_STRING PvpGetSectionCharacteristics( if (PhEndsWithString2(stringBuilder.String, L", ", FALSE)) PhRemoveEndStringBuilder(&stringBuilder, 2); - PhPrintPointer(pointer, (PVOID)(ULONG_PTR)Characteristics); + PhPrintPointer(pointer, UlongToPtr(Characteristics)); PhAppendFormatStringBuilder(&stringBuilder, L" (%s)", pointer); return PhFinalStringBuilderString(&stringBuilder); @@ -787,72 +785,6 @@ NTSTATUS PhpOpenFileSecurity( return status; } -LRESULT CALLBACK PhpOptionsWndProc( - _In_ HWND hwndDlg, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam - ) -{ - switch (uMsg) - { - case WM_COMMAND: - { - if (GET_WM_COMMAND_HWND(wParam, lParam) == ResetButton) - { - PhEditSecurity( - hwndDlg, - PhGetString(PvFileName), - L"FileObject", - PhpOpenFileSecurity, - NULL, - NULL - ); - } - } - break; - } - - return CallWindowProc(OldWndProc, hwndDlg, uMsg, wParam, lParam); -} - -static HWND PvpCreateSecurityButton( - _In_ HWND hwndDlg - ) -{ - if (!ResetButton) - { - HWND optionsWindow; - RECT clientRect; - RECT rect; - - optionsWindow = GetParent(hwndDlg); - OldWndProc = (WNDPROC)GetWindowLongPtr(optionsWindow, GWLP_WNDPROC); - SetWindowLongPtr(optionsWindow, GWLP_WNDPROC, (LONG_PTR)PhpOptionsWndProc); - - // Create the Reset button. - GetClientRect(optionsWindow, &clientRect); - GetWindowRect(GetDlgItem(optionsWindow, IDCANCEL), &rect); - MapWindowPoints(NULL, optionsWindow, (POINT*)&rect, 2); - ResetButton = CreateWindowEx( - WS_EX_NOPARENTNOTIFY, - WC_BUTTON, - L"Security", - WS_CHILD | WS_VISIBLE | WS_TABSTOP, - clientRect.right - rect.right, - rect.top, - rect.right - rect.left, - rect.bottom - rect.top, - optionsWindow, - NULL, - PhInstanceHandle, - NULL - ); - SendMessage(ResetButton, WM_SETFONT, SendMessage(GetDlgItem(optionsWindow, IDCANCEL), WM_GETFONT, 0, 0), TRUE); - } - - return ResetButton; -} INT_PTR CALLBACK PvpPeGeneralDlgProc( _In_ HWND hwndDlg, @@ -915,8 +847,6 @@ INT_PTR CALLBACK PvpPeGeneralDlgProc( PvAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_CHARACTERISTICS), dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT); PvAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_LIST), dialogItem, PH_ANCHOR_ALL); - PvAddPropPageLayoutItem(hwndDlg, PvpCreateSecurityButton(hwndDlg), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_BOTTOM); - PvDoPropPageLayout(hwndDlg); propPageContext->LayoutInitialized = TRUE; diff --git a/tools/peview/peview.rc b/tools/peview/peview.rc index 1df275454ecd..52bb5741483a 100644 --- a/tools/peview/peview.rc +++ b/tools/peview/peview.rc @@ -382,6 +382,22 @@ BEGIN CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,3,3,294,274 END +IDD_OPTIONS DIALOGEX 0, 0, 309, 176 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME +CAPTION "Options" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + DEFPUSHBUTTON "OK",IDOK,198,155,50,14 + PUSHBUTTON "Cancel",IDCANCEL,252,155,50,14 + LTEXT "Max. size unit:",IDC_STATIC,7,24,49,8 + COMBOBOX IDC_MAXSIZEUNIT,61,23,39,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Font...",IDC_FONT,179,23,49,14 + CONTROL "",IDC_SETTINGS,"SysListView32",LVS_LIST | LVS_SINGLESEL | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,39,295,113 + LTEXT "Application font:",IDC_STATIC,121,25,54,8 + LTEXT "Symbol path:",IDC_STATIC,7,8,43,8 + EDITTEXT IDC_DBGHELPSEARCHPATH,61,7,241,12,ES_AUTOHSCROLL +END + ///////////////////////////////////////////////////////////////////////////// // diff --git a/tools/peview/prpsh.c b/tools/peview/prpsh.c index d1044585dce1..7252e561c0f2 100644 --- a/tools/peview/prpsh.c +++ b/tools/peview/prpsh.c @@ -23,6 +23,7 @@ // NOTE: Copied from processhacker2\ProcessHacker\procprp.c #include +#include #include PPH_OBJECT_TYPE PvpPropContextType; @@ -119,6 +120,176 @@ VOID NTAPI PvpPropContextDeleteProcedure( PhDereferenceObject(propContext->StartPage); } +static HWND OptionsButton = NULL; +static HWND SecurityButton = NULL; +static WNDPROC OldOptionsWndProc = NULL; +static WNDPROC OldSecurityWndProc = NULL; + +INT_PTR CALLBACK PvpOptionsWndProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + switch (uMsg) + { + case WM_INITDIALOG: + { + HWND comboBoxHandle; + + SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PvImageSmallIcon); + SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PvImageLargeIcon); + + comboBoxHandle = GetDlgItem(hwndDlg, IDC_MAXSIZEUNIT); + + PhCenterWindow(hwndDlg, GetParent(hwndDlg)); + + //PhSetDialogItemText(hwndDlg, IDC_DBGHELPSEARCHPATH, PhaGetStringSetting(L"DbgHelpSearchPath")->Buffer); + + for (ULONG i = 0; i < RTL_NUMBER_OF(PhSizeUnitNames); i++) + ComboBox_AddString(comboBoxHandle, PhSizeUnitNames[i]); + + if (PhMaxSizeUnit != ULONG_MAX) + ComboBox_SetCurSel(comboBoxHandle, PhMaxSizeUnit); + else + ComboBox_SetCurSel(comboBoxHandle, RTL_NUMBER_OF(PhSizeUnitNames) - 1); + + //PhInitializeWindowThemeEx(hwndDlg); + } + break; + case WM_COMMAND: + { + switch (GET_WM_COMMAND_ID(wParam, lParam)) + { + case IDCANCEL: + EndDialog(hwndDlg, IDCANCEL); + break; + } + } + break; + } + + return FALSE; +} +LRESULT CALLBACK PvpButtonWndProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + switch (uMsg) + { + case WM_COMMAND: + { + if (GET_WM_COMMAND_HWND(wParam, lParam) == OptionsButton) + { + DialogBox( + PhInstanceHandle, + MAKEINTRESOURCE(IDD_OPTIONS), + hwndDlg, + PvpOptionsWndProc + ); + } + else if (GET_WM_COMMAND_HWND(wParam, lParam) == SecurityButton) + { + PhEditSecurity( + hwndDlg, + PhGetString(PvFileName), + L"FileObject", + PhpOpenFileSecurity, + NULL, + NULL + ); + } + } + break; + } + + return CallWindowProc(OldOptionsWndProc, hwndDlg, uMsg, wParam, lParam); +} + +static HWND PvpCreateOptionsButton( + _In_ HWND hwndDlg +) +{ + if (!OptionsButton) + { + HWND optionsWindow; + RECT clientRect; + RECT rect; + + optionsWindow = hwndDlg; + OldOptionsWndProc = (WNDPROC)GetWindowLongPtr(optionsWindow, GWLP_WNDPROC); + SetWindowLongPtr(optionsWindow, GWLP_WNDPROC, (LONG_PTR)PvpButtonWndProc); + + // Create the Reset button. + GetClientRect(optionsWindow, &clientRect); + GetWindowRect(GetDlgItem(optionsWindow, IDCANCEL), &rect); + MapWindowPoints(NULL, optionsWindow, (POINT*)& rect, 2); + OptionsButton = CreateWindowEx( + WS_EX_NOPARENTNOTIFY, + WC_BUTTON, + L"Options", + WS_CHILD | WS_VISIBLE | WS_TABSTOP, + clientRect.right - rect.right, + rect.top, + rect.right - rect.left, + rect.bottom - rect.top, + optionsWindow, + NULL, + PhInstanceHandle, + NULL + ); + SetWindowFont(OptionsButton, GetWindowFont(GetDlgItem(optionsWindow, IDCANCEL)), TRUE); + } + + return OptionsButton; +} + +static HWND PvpCreateSecurityButton( + _In_ HWND hwndDlg +) +{ + if (!SecurityButton) + { + HWND optionsWindow; + RECT clientRect; + RECT rect; + + optionsWindow = hwndDlg; + OldSecurityWndProc = (WNDPROC)GetWindowLongPtr(optionsWindow, GWLP_WNDPROC); + SetWindowLongPtr(optionsWindow, GWLP_WNDPROC, (LONG_PTR)PvpButtonWndProc); + + // Create the Reset button. + GetClientRect(optionsWindow, &clientRect); + GetWindowRect(OptionsButton, &rect); + MapWindowPoints(NULL, optionsWindow, (POINT*)& rect, 2); + + SecurityButton = CreateWindowEx( + WS_EX_NOPARENTNOTIFY, + WC_BUTTON, + L"Security", + WS_CHILD | WS_VISIBLE | WS_TABSTOP, + rect.right, + rect.top, + rect.right - rect.left, + rect.bottom - rect.top, + optionsWindow, + NULL, + PhInstanceHandle, + NULL + ); + + SetWindowFont(SecurityButton, GetWindowFont(GetDlgItem(optionsWindow, IDCANCEL)), TRUE); + } + + return SecurityButton; +} + + + INT CALLBACK PvpPropSheetProc( _In_ HWND hwndDlg, _In_ UINT uMsg, @@ -147,9 +318,13 @@ INT CALLBACK PvpPropSheetProc( case PSCB_INITIALIZED: { PPV_PROPSHEETCONTEXT context; + HICON smallIcon; + HICON largeIcon; - SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PvImageLargeIcon); - SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PvImageSmallIcon); + PhGetStockApplicationIcon(&smallIcon, &largeIcon); + + SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)smallIcon); + SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)largeIcon); context = PhAllocateZero(sizeof(PV_PROPSHEETCONTEXT)); PhInitializeLayoutManager(&context->LayoutManager, hwndDlg); @@ -276,15 +451,14 @@ BOOLEAN PhpInitializePropSheetLayoutStage1( PPH_LAYOUT_ITEM tabPageItem; tabControlHandle = PropSheet_GetTabControl(hwnd); - tabControlItem = PhAddLayoutItem(&PropSheetContext->LayoutManager, tabControlHandle, - NULL, PH_ANCHOR_ALL | PH_LAYOUT_IMMEDIATE_RESIZE); - tabPageItem = PhAddLayoutItem(&PropSheetContext->LayoutManager, tabControlHandle, - NULL, PH_LAYOUT_TAB_CONTROL); // dummy item to fix multiline tab control + tabControlItem = PhAddLayoutItem(&PropSheetContext->LayoutManager, tabControlHandle, NULL, PH_ANCHOR_ALL | PH_LAYOUT_IMMEDIATE_RESIZE); + tabPageItem = PhAddLayoutItem(&PropSheetContext->LayoutManager, tabControlHandle, NULL, PH_LAYOUT_TAB_CONTROL); // dummy item to fix multiline tab control PropSheetContext->TabPageItem = tabPageItem; - PhAddLayoutItem(&PropSheetContext->LayoutManager, GetDlgItem(hwnd, IDCANCEL), - NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); + PhAddLayoutItem(&PropSheetContext->LayoutManager, GetDlgItem(hwnd, IDCANCEL), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); + PhAddLayoutItem(&PropSheetContext->LayoutManager, PvpCreateOptionsButton(hwnd), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_BOTTOM); + PhAddLayoutItem(&PropSheetContext->LayoutManager, PvpCreateSecurityButton(hwnd), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_BOTTOM); // Hide the OK button. ShowWindow(GetDlgItem(hwnd, IDOK), SW_HIDE); @@ -345,8 +519,7 @@ BOOLEAN PvAddPropPage( PropPageContext->PropContext = PropContext; PhReferenceObject(PropContext); - PropContext->PropSheetPages[PropContext->PropSheetHeader.nPages] = - propSheetPageHandle; + PropContext->PropSheetPages[PropContext->PropSheetHeader.nPages] = propSheetPageHandle; PropContext->PropSheetHeader.nPages++; return TRUE; diff --git a/tools/peview/resource.h b/tools/peview/resource.h index 6028d8b84447..fb023fa24282 100644 --- a/tools/peview/resource.h +++ b/tools/peview/resource.h @@ -25,6 +25,7 @@ #define IDD_TLS 117 #define IDC_SYMBOLTREE 119 #define IDI_APPICON 122 +#define IDD_OPTIONS 126 #define IDC_TARGETMACHINE 1003 #define IDC_CHECKSUM 1004 #define IDC_SUBSYSTEM 1005 @@ -46,6 +47,11 @@ #define IDC_IMAGETYPE 1017 #define IDC_NAME 1019 #define IDC_COMPANYNAME_LINK 1020 +#define IDC_FONT 1079 +#define IDC_SEARCHENGINE 1143 +#define IDC_MAXSIZEUNIT 1144 +#define IDC_DBGHELPSEARCHPATH 1218 +#define IDC_SETTINGS 1399 // Next default values for new objects // diff --git a/tools/peview/searchbox.c b/tools/peview/searchbox.c index fcedf529d181..87dbabafc6d3 100644 --- a/tools/peview/searchbox.c +++ b/tools/peview/searchbox.c @@ -65,13 +65,13 @@ VOID PhpSearchFreeTheme( ) { if (Context->BrushNormal) - DeleteObject(Context->BrushNormal); + DeleteBrush(Context->BrushNormal); if (Context->BrushHot) - DeleteObject(Context->BrushHot); + DeleteBrush(Context->BrushHot); if (Context->BrushPushed) - DeleteObject(Context->BrushPushed); + DeleteBrush(Context->BrushPushed); } VOID PhpSearchInitializeFont( @@ -81,7 +81,7 @@ VOID PhpSearchInitializeFont( LOGFONT logFont; if (Context->WindowFont) - DeleteObject(Context->WindowFont); + DeleteFont(Context->WindowFont); if (!SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(LOGFONT), &logFont, 0)) return; @@ -103,7 +103,7 @@ VOID PhpSearchInitializeFont( logFont.lfFaceName ); - SendMessage(Context->WindowHandle, WM_SETFONT, (WPARAM)Context->WindowFont, TRUE); + SetWindowFont(Context->WindowHandle, Context->WindowFont, TRUE); } VOID PhpSearchInitializeTheme( @@ -296,7 +296,7 @@ HBITMAP PhLoadPngImageFromResource( return bitmapHandle; } - DeleteObject(bitmapHandle); + DeleteBitmap(bitmapHandle); return NULL; } @@ -312,23 +312,23 @@ VOID PhpSearchInitializeImages( if (bitmap = PhLoadPngImageFromResource(PhInstanceHandle, Context->ImageWidth, Context->ImageHeight, MAKEINTRESOURCE(IDB_SEARCH_ACTIVE), TRUE)) { Context->BitmapActive = PhpSearchBitmapToIcon(bitmap, Context->ImageWidth, Context->ImageHeight); - DeleteObject(bitmap); + DeleteBitmap(bitmap); } else if (bitmap = LoadImage(PhInstanceHandle, MAKEINTRESOURCE(IDB_SEARCH_ACTIVE_BMP), IMAGE_BITMAP, 0, 0, 0)) { Context->BitmapActive = PhpSearchBitmapToIcon(bitmap, Context->ImageWidth, Context->ImageHeight); - DeleteObject(bitmap); + DeleteBitmap(bitmap); } if (bitmap = PhLoadPngImageFromResource(PhInstanceHandle, Context->ImageWidth, Context->ImageHeight, MAKEINTRESOURCE(IDB_SEARCH_INACTIVE), TRUE)) { Context->BitmapInactive = PhpSearchBitmapToIcon(bitmap, Context->ImageWidth, Context->ImageHeight); - DeleteObject(bitmap); + DeleteBitmap(bitmap); } else if (bitmap = LoadImage(PhInstanceHandle, MAKEINTRESOURCE(IDB_SEARCH_INACTIVE_BMP), IMAGE_BITMAP, 0, 0, 0)) { Context->BitmapInactive = PhpSearchBitmapToIcon(bitmap, Context->ImageWidth, Context->ImageHeight); - DeleteObject(bitmap); + DeleteBitmap(bitmap); } } @@ -364,7 +364,7 @@ VOID PhpSearchDrawButton( bufferDc = CreateCompatibleDC(hdc); bufferBitmap = CreateCompatibleBitmap(hdc, bufferRect.right, bufferRect.bottom); - oldBufferBitmap = SelectObject(bufferDc, bufferBitmap); + oldBufferBitmap = SelectBitmap(bufferDc, bufferBitmap); if (Context->Pushed) { @@ -411,8 +411,8 @@ VOID PhpSearchDrawButton( } BitBlt(hdc, ButtonRect.left, ButtonRect.top, ButtonRect.right, ButtonRect.bottom, bufferDc, 0, 0, SRCCOPY); - SelectObject(bufferDc, oldBufferBitmap); - DeleteObject(bufferBitmap); + SelectBitmap(bufferDc, oldBufferBitmap); + DeleteBitmap(bufferBitmap); DeleteDC(bufferDc); ReleaseDC(Context->WindowHandle, hdc); @@ -440,7 +440,7 @@ LRESULT CALLBACK PhpSearchWndSubclassProc( PhpSearchFreeTheme(context); if (context->WindowFont) - DeleteObject(context->WindowFont); + DeleteFont(context->WindowFont); SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)oldWndProc); PhRemoveWindowContext(hWnd, SHRT_MAX); @@ -680,7 +680,7 @@ HICON PhpSearchBitmapToIcon( icon = CreateIconIndirect(&iconInfo); - DeleteObject(screenBitmap); + DeleteBitmap(screenBitmap); ReleaseDC(NULL, screenDc); return icon; diff --git a/tools/peview/settings.c b/tools/peview/settings.c index 1da2be85eebf..0033333ceb14 100644 --- a/tools/peview/settings.c +++ b/tools/peview/settings.c @@ -31,6 +31,7 @@ VOID PhAddDefaultSettings( { PhpAddIntegerSetting(L"FirstRun", L"1"); PhpAddStringSetting(L"Font", L""); // null + PhpAddStringSetting(L"DbgHelpSearchPath", L"SRV*C:\\Symbols*https://msdl.microsoft.com/download/symbols"); PhpAddIntegerSetting(L"EnableSecurityAdvancedDialog", L"1"); PhpAddIntegerSetting(L"EnableThemeSupport", L"0"); PhpAddIntegerSetting(L"GraphColorMode", L"1"); From 333d48a49474fa4cd30748099d9fa77177358ab7 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 7 Aug 2019 07:42:05 +1000 Subject: [PATCH 2039/2058] peview: Add groups for module exports --- tools/peview/impprp.c | 169 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 166 insertions(+), 3 deletions(-) diff --git a/tools/peview/impprp.c b/tools/peview/impprp.c index e5ee24c5f6d1..006d1388d3eb 100644 --- a/tools/peview/impprp.c +++ b/tools/peview/impprp.c @@ -126,6 +126,93 @@ PPH_STRING PvpQueryModuleOrdinalName( return exportName; } +INT PvpAddListViewGroup( + _In_ HWND ListViewHandle, + _In_ PWSTR Text + ) +{ + LVGROUP group; + + memset(&group, 0, sizeof(LVGROUP)); + group.cbSize = sizeof(LVGROUP); + group.mask = LVGF_HEADER | LVGF_ALIGN | LVGF_STATE | LVGF_GROUPID;// | LVGF_TASK; + group.uAlign = LVGA_HEADER_LEFT; + group.state = LVGS_COLLAPSIBLE; + group.iGroupId = (INT)ListView_GetGroupCount(ListViewHandle); + group.pszHeader = Text; + //group.pszTask = L"Properties"; + + return (INT)ListView_InsertGroup(ListViewHandle, MAXINT, &group); +} + +BOOLEAN PvpCheckGroupExists( + _In_ HWND ListViewHandle, + _In_ PWSTR GroupText + ) +{ + BOOLEAN exists = FALSE; + INT groupCount; + + groupCount = (INT)ListView_GetGroupCount(ListViewHandle); + + for (INT i = 0; i < groupCount; i++) + { + LVGROUP group; + WCHAR headerText[MAX_PATH] = L""; + + memset(&group, 0, sizeof(LVGROUP)); + group.cbSize = sizeof(LVGROUP); + group.mask = LVGF_HEADER; + group.cchHeader = RTL_NUMBER_OF(headerText); + group.pszHeader = headerText; + + if (ListView_GetGroupInfoByIndex(ListViewHandle, i, &group)) + { + if (PhEqualStringZ(headerText, GroupText, TRUE)) + { + exists = TRUE; + break; + } + } + } + + return exists; +} + +INT PvpGroupIndex( + _In_ HWND ListViewHandle, + _In_ PWSTR GroupText + ) +{ + INT groupIndex = MAXINT; + INT groupCount; + + groupCount = (INT)ListView_GetGroupCount(ListViewHandle); + + for (INT i = 0; i < groupCount; i++) + { + LVGROUP group; + WCHAR headerText[MAX_PATH] = L""; + + memset(&group, 0, sizeof(LVGROUP)); + group.cbSize = sizeof(LVGROUP); + group.mask = LVGF_HEADER | LVGF_GROUPID; + group.cchHeader = RTL_NUMBER_OF(headerText); + group.pszHeader = headerText; + + if (ListView_GetGroupInfoByIndex(ListViewHandle, i, &group)) + { + if (PhEqualStringZ(headerText, GroupText, TRUE)) + { + groupIndex = group.iGroupId; + break; + } + } + } + + return groupIndex; +} + VOID PvpProcessImports( _In_ HWND ListViewHandle, _In_ PPH_MAPPED_IMAGE_IMPORTS Imports, @@ -137,6 +224,7 @@ VOID PvpProcessImports( PH_MAPPED_IMAGE_IMPORT_ENTRY importEntry; ULONG i; ULONG j; + INT groupCount = 0; for (i = 0; i < Imports->NumberOfDlls; i++) { @@ -146,8 +234,9 @@ VOID PvpProcessImports( { if (NT_SUCCESS(PhGetMappedImageImportEntry(&importDll, j, &importEntry))) { - INT lvItemIndex; - PPH_STRING name; + INT groupId = INT_MAX; + INT lvItemIndex = INT_MAX; + PPH_STRING name = NULL; WCHAR number[PH_INT32_STR_LEN_1]; if (DelayImports) @@ -155,8 +244,17 @@ VOID PvpProcessImports( else name = PhZeroExtendToUtf16(importDll.Name); + if (PvpCheckGroupExists(ListViewHandle, name->Buffer)) + { + groupId = PvpGroupIndex(ListViewHandle, name->Buffer); + } + else + { + groupId = PvpAddListViewGroup(ListViewHandle, name->Buffer); + } + PhPrintUInt32(number, ++(*Count)); // HACK - lvItemIndex = PhAddListViewItem(ListViewHandle, MAXINT, number, NULL); + lvItemIndex = PhAddListViewGroupItem(ListViewHandle, groupId, MAXINT, number, NULL); // PhAddListViewItem(ListViewHandle, MAXINT, number, NULL); PhSetListViewSubItem(ListViewHandle, lvItemIndex, 1, name->Buffer); PhDereferenceObject(name); @@ -253,6 +351,8 @@ INT_PTR CALLBACK PvpPeImportsDlgProc( ExtendedListView_AddFallbackColumns(lvHandle, 3, fallbackColumns); PhLoadListViewColumnsFromSetting(L"ImageImportsListViewColumns", lvHandle); + ListView_EnableGroupView(lvHandle, TRUE); + if (NT_SUCCESS(PhGetMappedImageImports(&imports, &PvMappedImage))) { PvpProcessImports(lvHandle, &imports, FALSE, &count); @@ -290,6 +390,69 @@ INT_PTR CALLBACK PvpPeImportsDlgProc( break; case WM_NOTIFY: { + LPNMHDR header = (LPNMHDR)lParam; + + switch (header->code) + { + case LVN_LINKCLICK: + { + PNMLVLINK lvLinkInfo = (PNMLVLINK)lParam; + PPH_STRING applicationFileName; + LVGROUP groupInfo; + WCHAR headerText[MAX_PATH] = L""; + + memset(&groupInfo, 0, sizeof(LVGROUP)); + groupInfo.cbSize = sizeof(LVGROUP); + groupInfo.mask = LVGF_HEADER | LVGF_TASK; + groupInfo.cchHeader = RTL_NUMBER_OF(headerText); + groupInfo.pszHeader = headerText; + + ListView_GetGroupInfoByIndex(lvLinkInfo->hdr.hwndFrom, lvLinkInfo->iSubItem, &groupInfo); + + memset(&groupInfo, 0, sizeof(LVGROUP)); + groupInfo.cbSize = sizeof(LVGROUP); + groupInfo.mask = LVGF_TASK; + + if (ListView_GetGroupState(lvLinkInfo->hdr.hwndFrom, lvLinkInfo->iSubItem, LVGS_COLLAPSED)) + { + //ListView_SetGroupState(lvLinkInfo->hdr.hwndFrom, lvLinkInfo->iSubItem, LVGS_COLLAPSED, 0); + groupInfo.pszTask = L"Properties"; + } + else + { + //ListView_SetGroupState(lvLinkInfo->hdr.hwndFrom, lvLinkInfo->iSubItem, LVGS_COLLAPSED, LVGS_COLLAPSED); + groupInfo.pszTask = L"Properties"; + } + + ListView_SetGroupInfo(lvLinkInfo->hdr.hwndFrom, lvLinkInfo->iSubItem, &groupInfo); + + if (applicationFileName = PhGetApplicationFileName()) + { + PPH_STRING filePath; + + if (filePath = PhSearchFilePath(headerText, NULL)) + { + PhMoveReference(&filePath, PhConcatStrings(3, L"\"", filePath->Buffer, L"\"")); + + PhShellExecuteEx( + hwndDlg, + PhGetString(applicationFileName), + PhGetString(filePath), + SW_SHOW, + 0, + 0, + NULL + ); + + PhDereferenceObject(filePath); + } + + PhDereferenceObject(applicationFileName); + } + break; + } + } + PvHandleListViewNotifyForCopy(lParam, GetDlgItem(hwndDlg, IDC_LIST)); } break; From 343da0c2ee17d08823e8cdd5aa7b69701be98162 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 7 Aug 2019 07:44:58 +1000 Subject: [PATCH 2040/2058] peview: Add missing resources --- tools/peview/peview.rc | 8 ++++++++ tools/peview/prpsh.c | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/tools/peview/peview.rc b/tools/peview/peview.rc index 52bb5741483a..21b312458d8d 100644 --- a/tools/peview/peview.rc +++ b/tools/peview/peview.rc @@ -188,6 +188,14 @@ BEGIN TOPMARGIN, 3 BOTTOMMARGIN, 277 END + + IDD_OPTIONS, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 302 + TOPMARGIN, 7 + BOTTOMMARGIN, 169 + END END #endif // APSTUDIO_INVOKED diff --git a/tools/peview/prpsh.c b/tools/peview/prpsh.c index 7252e561c0f2..3378ed102e88 100644 --- a/tools/peview/prpsh.c +++ b/tools/peview/prpsh.c @@ -232,7 +232,7 @@ static HWND PvpCreateOptionsButton( WS_EX_NOPARENTNOTIFY, WC_BUTTON, L"Options", - WS_CHILD | WS_VISIBLE | WS_TABSTOP, + WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_DISABLED, // TODO: Remove disabled flag clientRect.right - rect.right, rect.top, rect.right - rect.left, From c01a9fb318cfe03c29b39dbff1d0a206eda2a148 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 7 Aug 2019 08:55:31 +1000 Subject: [PATCH 2041/2058] Fix error message parent window --- ProcessHacker/hndlmenu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ProcessHacker/hndlmenu.c b/ProcessHacker/hndlmenu.c index 6a8b90711218..20bb605fdb9b 100644 --- a/ProcessHacker/hndlmenu.c +++ b/ProcessHacker/hndlmenu.c @@ -126,7 +126,7 @@ VOID PhShowHandleObjectProperties1( if (Info->BestObjectName) { PhShellExecuteUserString( - PhMainWndHandle, + hWnd, L"FileBrowseExecutable", Info->BestObjectName->Buffer, FALSE, From 68c87f16242a52f887ae70a8324876afca9e90f5 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 7 Aug 2019 09:27:40 +1000 Subject: [PATCH 2042/2058] ExtendedTools: Update process gpu statistics --- plugins/ExtendedTools/exttools.h | 3 +++ plugins/ExtendedTools/main.c | 12 ++++++++++++ 2 files changed, 15 insertions(+) diff --git a/plugins/ExtendedTools/exttools.h b/plugins/ExtendedTools/exttools.h index d5b1fe6a8d7c..f34f7cdf093e 100644 --- a/plugins/ExtendedTools/exttools.h +++ b/plugins/ExtendedTools/exttools.h @@ -207,6 +207,9 @@ typedef enum _ET_PROCESS_STATISTICS_INDEX ET_PROCESS_STATISTICS_INDEX_CONTEXTSWITCHES, ET_PROCESS_STATISTICS_INDEX_TOTALNODES, ET_PROCESS_STATISTICS_INDEX_TOTALSEGMENTS, + ET_PROCESS_STATISTICS_INDEX_TOTALDEDICATED, + ET_PROCESS_STATISTICS_INDEX_TOTALSHARED, + ET_PROCESS_STATISTICS_INDEX_TOTALCOMMIT, ET_PROCESS_STATISTICS_INDEX_DISKREADS, ET_PROCESS_STATISTICS_INDEX_DISKREADBYTES, diff --git a/plugins/ExtendedTools/main.c b/plugins/ExtendedTools/main.c index 6efea0bd8782..612eae1419d4 100644 --- a/plugins/ExtendedTools/main.c +++ b/plugins/ExtendedTools/main.c @@ -421,6 +421,12 @@ VOID NTAPI ProcessStatsEventCallback( listViewHandle, block->ListViewGroupCache[ET_PROCESS_STATISTICS_CATEGORY_GPU], MAXINT, L"Total Nodes", NULL); block->ListViewRowCache[ET_PROCESS_STATISTICS_INDEX_TOTALSEGMENTS] = PhAddListViewGroupItem( listViewHandle, block->ListViewGroupCache[ET_PROCESS_STATISTICS_CATEGORY_GPU], MAXINT, L"Total Segments", NULL); + block->ListViewRowCache[ET_PROCESS_STATISTICS_INDEX_TOTALDEDICATED] = PhAddListViewGroupItem( + listViewHandle, block->ListViewGroupCache[ET_PROCESS_STATISTICS_CATEGORY_GPU], MAXINT, L"Total Dedicated", NULL); + block->ListViewRowCache[ET_PROCESS_STATISTICS_INDEX_TOTALSHARED] = PhAddListViewGroupItem( + listViewHandle, block->ListViewGroupCache[ET_PROCESS_STATISTICS_CATEGORY_GPU], MAXINT, L"Total Shared", NULL); + block->ListViewRowCache[ET_PROCESS_STATISTICS_INDEX_TOTALCOMMIT] = PhAddListViewGroupItem( + listViewHandle, block->ListViewGroupCache[ET_PROCESS_STATISTICS_CATEGORY_GPU], MAXINT, L"Total Commit", NULL); block->ListViewGroupCache[ET_PROCESS_STATISTICS_CATEGORY_DISK] = PhAddListViewGroup( listViewHandle, (INT)ListView_GetGroupCount(event->Parameter), L"Disk I/O"); @@ -477,6 +483,12 @@ VOID NTAPI ProcessStatsEventCallback( PhaFormatUInt64(gpuStatistics.NodeCount, TRUE)->Buffer); PhSetListViewSubItem(listViewHandle, block->ListViewRowCache[ET_PROCESS_STATISTICS_INDEX_TOTALSEGMENTS], 1, PhaFormatUInt64(gpuStatistics.SegmentCount, TRUE)->Buffer); + PhSetListViewSubItem(listViewHandle, block->ListViewRowCache[ET_PROCESS_STATISTICS_INDEX_TOTALDEDICATED], 1, + PhaFormatSize(gpuStatistics.DedicatedCommitted, ULONG_MAX)->Buffer); + PhSetListViewSubItem(listViewHandle, block->ListViewRowCache[ET_PROCESS_STATISTICS_INDEX_TOTALSHARED], 1, + PhaFormatSize(gpuStatistics.SharedCommitted, ULONG_MAX)->Buffer); + PhSetListViewSubItem(listViewHandle, block->ListViewRowCache[ET_PROCESS_STATISTICS_INDEX_TOTALCOMMIT], 1, + PhaFormatSize(gpuStatistics.BytesAllocated, ULONG_MAX)->Buffer); PhSetListViewSubItem(listViewHandle, block->ListViewRowCache[ET_PROCESS_STATISTICS_INDEX_DISKREADS], 1, PhaFormatUInt64(block->DiskReadCount, TRUE)->Buffer); From 21de51e3eb5eb444d9dcf885259174b13af3c6c1 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 7 Aug 2019 10:16:43 +1000 Subject: [PATCH 2043/2058] Fix options default regression --- ProcessHacker/options.c | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/ProcessHacker/options.c b/ProcessHacker/options.c index 07e6b008c195..49579d3f7adb 100644 --- a/ProcessHacker/options.c +++ b/ProcessHacker/options.c @@ -831,31 +831,31 @@ static BOOLEAN PathMatchesPh( BOOLEAN match = FALSE; PPH_STRING fileName; - if (fileName = PhGetApplicationFileName()) - { - if (PhEqualString(OldTaskMgrDebugger, fileName, TRUE)) - { - match = TRUE; - } - // Allow for a quoted value. - else if ( - OldTaskMgrDebugger->Length == (fileName->Length + sizeof(UNICODE_NULL)) * sizeof(WCHAR) && - OldTaskMgrDebugger->Buffer[0] == '"' && - OldTaskMgrDebugger->Buffer[OldTaskMgrDebugger->Length / sizeof(WCHAR) - 1] == '"' - ) - { - PH_STRINGREF partInside; + if (!(fileName = PhGetApplicationFileName())) + return FALSE; - partInside.Buffer = &OldTaskMgrDebugger->Buffer[1]; - partInside.Length = (OldTaskMgrDebugger->Length - sizeof(UNICODE_NULL)) * sizeof(WCHAR); + if (PhEqualString(OldTaskMgrDebugger, fileName, TRUE)) + { + match = TRUE; + } + // Allow for a quoted value. + else if ( + OldTaskMgrDebugger->Length == fileName->Length + 4 && + OldTaskMgrDebugger->Buffer[0] == L'"' && + OldTaskMgrDebugger->Buffer[OldTaskMgrDebugger->Length / sizeof(WCHAR) - 1] == L'"' + ) + { + PH_STRINGREF partInside; - if (PhEqualStringRef(&partInside, &fileName->sr, TRUE)) - match = TRUE; - } + partInside.Buffer = &OldTaskMgrDebugger->Buffer[1]; + partInside.Length = OldTaskMgrDebugger->Length - sizeof(WCHAR) * sizeof(WCHAR); - PhDereferenceObject(fileName); + if (PhEqualStringRef(&partInside, &fileName->sr, TRUE)) + match = TRUE; } + PhDereferenceObject(fileName); + return match; } From da43027c091a004bb881984771da6c044089db9b Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 7 Aug 2019 10:19:58 +1000 Subject: [PATCH 2044/2058] ExtendedTools: Update stats rows --- plugins/ExtendedTools/exttools.h | 4 ++-- plugins/ExtendedTools/main.c | 20 ++++++++++---------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/plugins/ExtendedTools/exttools.h b/plugins/ExtendedTools/exttools.h index f34f7cdf093e..3a77e233ea70 100644 --- a/plugins/ExtendedTools/exttools.h +++ b/plugins/ExtendedTools/exttools.h @@ -205,8 +205,8 @@ typedef enum _ET_PROCESS_STATISTICS_INDEX { ET_PROCESS_STATISTICS_INDEX_RUNNINGTIME, ET_PROCESS_STATISTICS_INDEX_CONTEXTSWITCHES, - ET_PROCESS_STATISTICS_INDEX_TOTALNODES, - ET_PROCESS_STATISTICS_INDEX_TOTALSEGMENTS, + //ET_PROCESS_STATISTICS_INDEX_TOTALNODES, + //ET_PROCESS_STATISTICS_INDEX_TOTALSEGMENTS, ET_PROCESS_STATISTICS_INDEX_TOTALDEDICATED, ET_PROCESS_STATISTICS_INDEX_TOTALSHARED, ET_PROCESS_STATISTICS_INDEX_TOTALCOMMIT, diff --git a/plugins/ExtendedTools/main.c b/plugins/ExtendedTools/main.c index 612eae1419d4..994b6dd216b9 100644 --- a/plugins/ExtendedTools/main.c +++ b/plugins/ExtendedTools/main.c @@ -417,10 +417,10 @@ VOID NTAPI ProcessStatsEventCallback( listViewHandle, block->ListViewGroupCache[ET_PROCESS_STATISTICS_CATEGORY_GPU], MAXINT, L"Running time", NULL); block->ListViewRowCache[ET_PROCESS_STATISTICS_INDEX_CONTEXTSWITCHES] = PhAddListViewGroupItem( listViewHandle, block->ListViewGroupCache[ET_PROCESS_STATISTICS_CATEGORY_GPU], MAXINT, L"Context switches", NULL); - block->ListViewRowCache[ET_PROCESS_STATISTICS_INDEX_TOTALNODES] = PhAddListViewGroupItem( - listViewHandle, block->ListViewGroupCache[ET_PROCESS_STATISTICS_CATEGORY_GPU], MAXINT, L"Total Nodes", NULL); - block->ListViewRowCache[ET_PROCESS_STATISTICS_INDEX_TOTALSEGMENTS] = PhAddListViewGroupItem( - listViewHandle, block->ListViewGroupCache[ET_PROCESS_STATISTICS_CATEGORY_GPU], MAXINT, L"Total Segments", NULL); + //block->ListViewRowCache[ET_PROCESS_STATISTICS_INDEX_TOTALNODES] = PhAddListViewGroupItem( + // listViewHandle, block->ListViewGroupCache[ET_PROCESS_STATISTICS_CATEGORY_GPU], MAXINT, L"Total Nodes", NULL); + //block->ListViewRowCache[ET_PROCESS_STATISTICS_INDEX_TOTALSEGMENTS] = PhAddListViewGroupItem( + // listViewHandle, block->ListViewGroupCache[ET_PROCESS_STATISTICS_CATEGORY_GPU], MAXINT, L"Total Segments", NULL); block->ListViewRowCache[ET_PROCESS_STATISTICS_INDEX_TOTALDEDICATED] = PhAddListViewGroupItem( listViewHandle, block->ListViewGroupCache[ET_PROCESS_STATISTICS_CATEGORY_GPU], MAXINT, L"Total Dedicated", NULL); block->ListViewRowCache[ET_PROCESS_STATISTICS_INDEX_TOTALSHARED] = PhAddListViewGroupItem( @@ -429,7 +429,7 @@ VOID NTAPI ProcessStatsEventCallback( listViewHandle, block->ListViewGroupCache[ET_PROCESS_STATISTICS_CATEGORY_GPU], MAXINT, L"Total Commit", NULL); block->ListViewGroupCache[ET_PROCESS_STATISTICS_CATEGORY_DISK] = PhAddListViewGroup( - listViewHandle, (INT)ListView_GetGroupCount(event->Parameter), L"Disk I/O"); + listViewHandle, (INT)ListView_GetGroupCount(listViewHandle), L"Disk I/O"); block->ListViewRowCache[ET_PROCESS_STATISTICS_INDEX_DISKREADS] = PhAddListViewGroupItem( listViewHandle, block->ListViewGroupCache[ET_PROCESS_STATISTICS_CATEGORY_DISK], MAXINT, L"Reads", NULL); block->ListViewRowCache[ET_PROCESS_STATISTICS_INDEX_DISKREADBYTES] = PhAddListViewGroupItem( @@ -444,7 +444,7 @@ VOID NTAPI ProcessStatsEventCallback( listViewHandle, block->ListViewGroupCache[ET_PROCESS_STATISTICS_CATEGORY_DISK], MAXINT, L"Write bytes delta", NULL); block->ListViewGroupCache[ET_PROCESS_STATISTICS_CATEGORY_NETWORK] = PhAddListViewGroup( - listViewHandle, (INT)ListView_GetGroupCount(event->Parameter), L"Network I/O"); + listViewHandle, (INT)ListView_GetGroupCount(listViewHandle), L"Network I/O"); block->ListViewRowCache[ET_PROCESS_STATISTICS_INDEX_NETWORKREADS] = PhAddListViewGroupItem( listViewHandle, block->ListViewGroupCache[ET_PROCESS_STATISTICS_CATEGORY_NETWORK], MAXINT, L"Receives", NULL); block->ListViewRowCache[ET_PROCESS_STATISTICS_INDEX_NETWORKREADBYTES] = PhAddListViewGroupItem( @@ -479,10 +479,10 @@ VOID NTAPI ProcessStatsEventCallback( runningTimeString); PhSetListViewSubItem(listViewHandle, block->ListViewRowCache[ET_PROCESS_STATISTICS_INDEX_CONTEXTSWITCHES], 1, PhaFormatUInt64(gpuStatistics.ContextSwitches, TRUE)->Buffer); - PhSetListViewSubItem(listViewHandle, block->ListViewRowCache[ET_PROCESS_STATISTICS_INDEX_TOTALNODES], 1, - PhaFormatUInt64(gpuStatistics.NodeCount, TRUE)->Buffer); - PhSetListViewSubItem(listViewHandle, block->ListViewRowCache[ET_PROCESS_STATISTICS_INDEX_TOTALSEGMENTS], 1, - PhaFormatUInt64(gpuStatistics.SegmentCount, TRUE)->Buffer); + //PhSetListViewSubItem(listViewHandle, block->ListViewRowCache[ET_PROCESS_STATISTICS_INDEX_TOTALNODES], 1, + // PhaFormatUInt64(gpuStatistics.NodeCount, TRUE)->Buffer); + //PhSetListViewSubItem(listViewHandle, block->ListViewRowCache[ET_PROCESS_STATISTICS_INDEX_TOTALSEGMENTS], 1, + // PhaFormatUInt64(gpuStatistics.SegmentCount, TRUE)->Buffer); PhSetListViewSubItem(listViewHandle, block->ListViewRowCache[ET_PROCESS_STATISTICS_INDEX_TOTALDEDICATED], 1, PhaFormatSize(gpuStatistics.DedicatedCommitted, ULONG_MAX)->Buffer); PhSetListViewSubItem(listViewHandle, block->ListViewRowCache[ET_PROCESS_STATISTICS_INDEX_TOTALSHARED], 1, From d76c3208dd372031470ca53e4575e35ee4e7ad2c Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 13 Aug 2019 00:23:45 +1000 Subject: [PATCH 2045/2058] HardwareDevices: Add total disk delta stats; Update disk details window --- plugins/HardwareDevices/HardwareDevices.rc | 8 +- plugins/HardwareDevices/devices.h | 11 +- plugins/HardwareDevices/diskdetails.c | 243 ++++----------------- plugins/HardwareDevices/diskgraph.c | 6 +- 4 files changed, 59 insertions(+), 209 deletions(-) diff --git a/plugins/HardwareDevices/HardwareDevices.rc b/plugins/HardwareDevices/HardwareDevices.rc index 54bb4cf44fe9..2d1095b349c3 100644 --- a/plugins/HardwareDevices/HardwareDevices.rc +++ b/plugins/HardwareDevices/HardwareDevices.rc @@ -157,7 +157,7 @@ IDD_DISKDRIVE_PANEL DIALOGEX 0, 0, 330, 50 STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_SYSMENU FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN - GROUPBOX "Statistics",IDC_STATIC,139,0,136,44 + GROUPBOX "Statistics",IDC_STATIC,139,0,136,46 LTEXT "Bytes read",IDC_STATIC,148,11,38,8 LTEXT "Bytes written",IDC_STATIC,148,22,45,8 RTEXT "Static",IDC_STAT_BREAD,205,11,62,8,SS_ENDELLIPSIS @@ -166,9 +166,9 @@ BEGIN RTEXT "Static",IDC_STAT_BTOTAL,205,33,62,8,SS_ENDELLIPSIS LTEXT "Active time",IDC_STATIC,8,11,53,8,SS_ENDELLIPSIS LTEXT "Response time",IDC_STATIC,8,22,64,8,SS_ENDELLIPSIS - LTEXT "Queue length",IDC_STATIC,8,33,57,8,SS_ENDELLIPSIS - GROUPBOX "Disk",IDC_STATIC,0,0,135,44 - PUSHBUTTON "Details",IDC_DETAILS,278,30,50,14 + LTEXT "Bytes delta",IDC_STATIC,8,33,57,8,SS_ENDELLIPSIS + GROUPBOX "Disk",IDC_STATIC,0,0,135,46 + PUSHBUTTON "Details",IDC_DETAILS,278,32,50,14 RTEXT "Static",IDC_STAT_ACTIVE,65,11,62,8,SS_ENDELLIPSIS RTEXT "Static",IDC_STAT_RESPONSETIME,65,22,62,8,SS_ENDELLIPSIS RTEXT "Static",IDC_STAT_QUEUELENGTH,65,33,62,8,SS_ENDELLIPSIS diff --git a/plugins/HardwareDevices/devices.h b/plugins/HardwareDevices/devices.h index 3cdf0497fd4c..b013c4d2fac8 100644 --- a/plugins/HardwareDevices/devices.h +++ b/plugins/HardwareDevices/devices.h @@ -2,8 +2,8 @@ * Process Hacker Plugins - * Hardware Devices Plugin * - * Copyright (C) 2015-2016 dmex * Copyright (C) 2016 wj32 + * Copyright (C) 2015-2019 dmex * * This file is part of Process Hacker. * @@ -512,7 +512,7 @@ typedef enum _DISKDRIVE_DETAILS_INDEX //DISKDRIVE_DETAILS_INDEX_ROOT_INDEX_READ_BYTES, //DISKDRIVE_DETAILS_INDEX_ROOT_INDEX_WRITE_BYTES, - DISKDRIVE_DETAILS_INDEX_BITMAP_READS, + /*DISKDRIVE_DETAILS_INDEX_BITMAP_READS, DISKDRIVE_DETAILS_INDEX_BITMAP_WRITES, DISKDRIVE_DETAILS_INDEX_BITMAP_READ_BYTES, DISKDRIVE_DETAILS_INDEX_BITMAP_WRITE_BYTES, @@ -532,7 +532,7 @@ typedef enum _DISKDRIVE_DETAILS_INDEX DISKDRIVE_DETAILS_INDEX_LOGFILE_READ_BYTES, DISKDRIVE_DETAILS_INDEX_LOGFILE_WRITE_BYTES, - /*DISKDRIVE_DETAILS_INDEX_MFT_USER_LEVEL_WRITE, + DISKDRIVE_DETAILS_INDEX_MFT_USER_LEVEL_WRITE, DISKDRIVE_DETAILS_INDEX_MFT_USER_LEVEL_CREATE, DISKDRIVE_DETAILS_INDEX_MFT_USER_LEVEL_SETINFO, DISKDRIVE_DETAILS_INDEX_MFT_USER_LEVEL_FLUSH, @@ -568,7 +568,7 @@ typedef enum _DISKDRIVE_DETAILS_INDEX DISKDRIVE_DETAILS_INDEX_MFT_BITMAP_USER_LEVEL_WRITE, DISKDRIVE_DETAILS_INDEX_MFT_BITMAP_USER_LEVEL_CREATE, DISKDRIVE_DETAILS_INDEX_MFT_BITMAP_USER_LEVEL_SETINFO, - DISKDRIVE_DETAILS_INDEX_MFT_BITMAP_USER_LEVEL_FLUSH,*/ + DISKDRIVE_DETAILS_INDEX_MFT_BITMAP_USER_LEVEL_FLUSH, DISKDRIVE_DETAILS_INDEX_ALLOCATE_CALLS, DISKDRIVE_DETAILS_INDEX_ALLOCATE_CLUSTERS, @@ -579,9 +579,8 @@ typedef enum _DISKDRIVE_DETAILS_INDEX DISKDRIVE_DETAILS_INDEX_ALLOCATE_CACHE, DISKDRIVE_DETAILS_INDEX_ALLOCATE_CACHE_CLUSTERS, DISKDRIVE_DETAILS_INDEX_ALLOCATE_CACHE_MISS, - DISKDRIVE_DETAILS_INDEX_ALLOCATE_CACHE_MISS_CLUSTERS, + DISKDRIVE_DETAILS_INDEX_ALLOCATE_CACHE_MISS_CLUSTERS,*/ - DISKDRIVE_DETAILS_INDEX_LOGFILE_EXCEPTIONS, DISKDRIVE_DETAILS_INDEX_OTHER_EXCEPTIONS } DISKDRIVE_DETAILS_INDEX; diff --git a/plugins/HardwareDevices/diskdetails.c b/plugins/HardwareDevices/diskdetails.c index 8bfc8d46a76a..5e5692a36dfc 100644 --- a/plugins/HardwareDevices/diskdetails.c +++ b/plugins/HardwareDevices/diskdetails.c @@ -76,77 +76,27 @@ VOID DiskDriveAddListViewItemGroups( //PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_ROOT_INDEX_READ_BYTES, L"RootIndex read bytes", NULL); //PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_ROOT_INDEX_WRITE_BYTES, L"RootIndex write bytes", NULL); - PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_BITMAP_READS, L"Bitmap reads", NULL); - PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_BITMAP_WRITES, L"Bitmap writes", NULL); - PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_BITMAP_READ_BYTES, L"Bitmap read bytes", NULL); - PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_BITMAP_WRITE_BYTES, L"Bitmap write bytes", NULL); - - PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_BITMAP_READS, L"Mft bitmap reads", NULL); - PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_BITMAP_WRITES, L"Mft bitmap writes", NULL); - PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_BITMAP_READ_BYTES, L"Mft bitmap read bytes", NULL); - PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_BITMAP_WRITE_BYTES, L"Mft bitmap write bytes", NULL); - - PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_USER_INDEX_READS, L"User Index reads", NULL); - PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_USER_INDEX_WRITES, L"User Index writes", NULL); - PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_USER_INDEX_READ_BYTES, L"User Index read bytes", NULL); - PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_USER_INDEX_WRITE_BYTES, L"User Index write bytes", NULL); - - PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_LOGFILE_READS, L"LogFile reads", NULL); - PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_LOGFILE_WRITES, L"LogFile writes", NULL); - PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_LOGFILE_READ_BYTES, L"LogFile read bytes", NULL); - PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_LOGFILE_WRITE_BYTES, L"LogFile write bytes", NULL); - - //PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_USER_LEVEL_WRITE, L"MftWritesUserLevel-Write", NULL); - //PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_USER_LEVEL_CREATE, L"MftWritesUserLevel-Create", NULL); - //PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_USER_LEVEL_SETINFO, L"MftWritesUserLevel-SetInfo", NULL); - //PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_USER_LEVEL_FLUSH, L"MftWritesUserLevel-Flush", NULL); - - //PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_WRITES_FLUSH_LOGFILE, L"MftWritesFlushForLogFileFull", NULL); - //PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_WRITES_LAZY_WRITER, L"MftWritesLazyWriter", NULL); - //PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_WRITES_USER_REQUEST, L"MftWritesUserRequest", NULL); - - //PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT2_WRITES, L"Mft2Writes", NULL); - //PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT2_WRITE_BYTES, L"Mft2WriteBytes", NULL); - - //PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT2_USER_LEVEL_WRITE, L"Mft2WritesUserLevel-Write", NULL); - //PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT2_USER_LEVEL_CREATE, L"Mft2WritesUserLevel-Create", NULL); - //PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT2_USER_LEVEL_SETINFO, L"Mft2WritesUserLevel-SetInfo", NULL); - //PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT2_USER_LEVEL_FLUSH, L"Mft2WritesUserLevel-Flush", NULL); - - //PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT2_WRITES_FLUSH_LOGFILE, L"Mft2WritesFlushForLogFileFull", NULL); - //PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT2_WRITES_LAZY_WRITER, L"Mft2WritesLazyWriter", NULL); - //PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT2_WRITES_USER_REQUEST, L"Mft2WritesUserRequest", NULL); - - //PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_BITMAP_WRITES_FLUSH_LOGFILE, L"BitmapWritesFlushForLogFileFull", NULL); - //PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_BITMAP_WRITES_LAZY_WRITER, L"BitmapWritesLazyWriter", NULL); - //PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_BITMAP_WRITES_USER_REQUEST, L"BitmapWritesUserRequest", NULL); - - //PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_BITMAP_WRITES_WRITE, L"BitmapWritesUserLevel-Write", NULL); - //PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_BITMAP_WRITES_CREATE, L"BitmapWritesUserLevel-Create", NULL); - //PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_BITMAP_WRITES_SETINFO, L"BitmapWritesUserLevel-SetInfo", NULL); - - //PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_BITMAP_FLUSH_LOGFILE, L"MftBitmapWritesFlushForLogFileFull", NULL); - //PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_BITMAP_LAZY_WRITER, L"MftBitmapWritesLazyWriter", NULL); - //PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_BITMAP_USER_REQUEST, L"MftBitmapWritesUserRequest", NULL); - - //PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_BITMAP_USER_LEVEL_WRITE, L"MftBitmapWritesUserLevel-Write", NULL); - //PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_BITMAP_USER_LEVEL_CREATE, L"MftBitmapWritesUserLevel-Create", NULL); - //PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_BITMAP_USER_LEVEL_SETINFO, L"MftBitmapWritesUserLevel-SetInfo", NULL); - //PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_BITMAP_USER_LEVEL_FLUSH, L"MftBitmapWritesUserLevel-Flush", NULL); - - PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_ALLOCATE_CALLS, L"Allocate-Calls", NULL); - PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_ALLOCATE_CLUSTERS, L"Allocate-Clusters", NULL); - PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_ALLOCATE_HINTS, L"Allocate-Hints", NULL); - PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_ALLOCATE_RUNS_RETURNED, L"Allocate-RunsReturned", NULL); - PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_ALLOCATE_HITS_HONORED, L"Allocate-HintsHonored", NULL); - PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_ALLOCATE_HITS_CLUSTERS, L"Allocate-HintsClusters", NULL); - PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_ALLOCATE_CACHE, L"Allocate-Cache", NULL); - PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_ALLOCATE_CACHE_CLUSTERS, L"Allocate-CacheClusters", NULL); - PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_ALLOCATE_CACHE_MISS, L"Allocate-CacheMiss", NULL); - PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_ALLOCATE_CACHE_MISS_CLUSTERS, L"Allocate-CacheMissClusters", NULL); - - PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_LOGFILE_EXCEPTIONS, L"LogFileFullExceptions", NULL); - PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_OTHER_EXCEPTIONS, L"OtherExceptions", NULL); + //PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_BITMAP_READS, L"Bitmap reads", NULL); + //PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_BITMAP_WRITES, L"Bitmap writes", NULL); + //PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_BITMAP_READ_BYTES, L"Bitmap read bytes", NULL); + //PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_BITMAP_WRITE_BYTES, L"Bitmap write bytes", NULL); + + //PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_BITMAP_READS, L"Mft bitmap reads", NULL); + //PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_BITMAP_WRITES, L"Mft bitmap writes", NULL); + //PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_BITMAP_READ_BYTES, L"Mft bitmap read bytes", NULL); + //PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_MFT_BITMAP_WRITE_BYTES, L"Mft bitmap write bytes", NULL); + + //PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_USER_INDEX_READS, L"User Index reads", NULL); + //PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_USER_INDEX_WRITES, L"User Index writes", NULL); + //PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_USER_INDEX_READ_BYTES, L"User Index read bytes", NULL); + //PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_USER_INDEX_WRITE_BYTES, L"User Index write bytes", NULL); + + //PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_LOGFILE_READS, L"LogFile reads", NULL); + //PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_LOGFILE_WRITES, L"LogFile writes", NULL); + //PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_LOGFILE_READ_BYTES, L"LogFile read bytes", NULL); + //PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_LOGFILE_WRITE_BYTES, L"LogFile write bytes", NULL); + + PhAddListViewGroupItem(ListViewHandle, DiskGroupId, DISKDRIVE_DETAILS_INDEX_OTHER_EXCEPTIONS, L"Exceptions", NULL); } VOID DiskDriveQuerySmart( @@ -209,6 +159,19 @@ VOID DiskDriveQuerySmart( ); } + //PhSetListViewSubItem( + // Context->ListViewHandle, + // lvItemIndex, + // 5, + // PhaFormatString(L"%lu", attribute->Advisory)->Buffer + // ); + //PhSetListViewSubItem( + // Context->ListViewHandle, + // lvItemIndex, + // 6, + // PhaFormatString(L"%lu", attribute->FailureImminent)->Buffer + // ); + PhFree(attribute); } @@ -260,13 +223,18 @@ VOID DiskDriveQueryFileSystem( if (volumeInfo->VolumeLabelLength > 0) { - diskGroupId = PhAddListViewGroup(Context->ListViewHandle, i, - PhaFormatString(L"Volume %wc: [%s]", diskEntry->DeviceLetter, PhaCreateStringEx(volumeInfo->VolumeLabel, volumeInfo->VolumeLabelLength)->Buffer)->Buffer); + diskGroupId = PhAddListViewGroup(Context->ListViewHandle, i, PhaFormatString( + L"Volume %wc: [%s]", + diskEntry->DeviceLetter, + PhaCreateStringEx(volumeInfo->VolumeLabel, volumeInfo->VolumeLabelLength)->Buffer + )->Buffer); } else { - diskGroupId = PhAddListViewGroup(Context->ListViewHandle, i, - PhaFormatString(L"Volume %wc:", diskEntry->DeviceLetter)->Buffer); + diskGroupId = PhAddListViewGroup(Context->ListViewHandle, i, PhaFormatString( + L"Volume %wc:", + diskEntry->DeviceLetter + )->Buffer); } DiskDriveAddListViewItemGroups(Context->ListViewHandle, diskGroupId); @@ -416,128 +384,9 @@ VOID DiskDriveQueryFileSystem( PhaFormatSize(buffer->NtfsStatistics.MftReadBytes, ULONG_MAX)->Buffer); PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_MFT_WRITE_BYTES, 1, PhaFormatSize(buffer->NtfsStatistics.MftWriteBytes, ULONG_MAX)->Buffer); - //PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_ROOT_INDEX_READS, 1, - // PhaFormatUInt64(buffer->NtfsStatistics.RootIndexReads, TRUE)->Buffer); - //PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_ROOT_INDEX_WRITES, 1, - // PhaFormatUInt64(buffer->NtfsStatistics.RootIndexWrites, TRUE)->Buffer); - //PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_ROOT_INDEX_READ_BYTES, 1, - // PhaFormatSize(buffer->NtfsStatistics.RootIndexReadBytes, -1)->Buffer); - //PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_ROOT_INDEX_WRITE_BYTES, 1, - // PhaFormatSize(buffer->NtfsStatistics.RootIndexWriteBytes, -1)->Buffer); - PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_BITMAP_READS, 1, - PhaFormatUInt64(buffer->NtfsStatistics.BitmapReads, TRUE)->Buffer); - PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_BITMAP_WRITES, 1, - PhaFormatUInt64(buffer->NtfsStatistics.BitmapWrites, TRUE)->Buffer); - PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_BITMAP_READ_BYTES, 1, - PhaFormatSize(buffer->NtfsStatistics.BitmapReadBytes, ULONG_MAX)->Buffer); - PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_BITMAP_WRITE_BYTES, 1, - PhaFormatSize(buffer->NtfsStatistics.BitmapWriteBytes, ULONG_MAX)->Buffer); - PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_MFT_BITMAP_READS, 1, - PhaFormatUInt64(buffer->NtfsStatistics.MftBitmapReads, TRUE)->Buffer); - PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_MFT_BITMAP_WRITES, 1, - PhaFormatUInt64(buffer->NtfsStatistics.MftBitmapWrites, TRUE)->Buffer); - PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_MFT_BITMAP_READ_BYTES, 1, - PhaFormatSize(buffer->NtfsStatistics.MftBitmapReadBytes, ULONG_MAX)->Buffer); - PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_MFT_BITMAP_WRITE_BYTES, 1, - PhaFormatSize(buffer->NtfsStatistics.MftBitmapWriteBytes, ULONG_MAX)->Buffer); - PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_USER_INDEX_READS, 1, - PhaFormatUInt64(buffer->NtfsStatistics.UserIndexReads, TRUE)->Buffer); - PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_USER_INDEX_WRITES, 1, - PhaFormatUInt64(buffer->NtfsStatistics.UserIndexWrites, TRUE)->Buffer); - PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_USER_INDEX_READ_BYTES, 1, - PhaFormatSize(buffer->NtfsStatistics.UserIndexReadBytes, ULONG_MAX)->Buffer); - PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_USER_INDEX_WRITE_BYTES, 1, - PhaFormatSize(buffer->NtfsStatistics.UserIndexWriteBytes, ULONG_MAX)->Buffer); - PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_LOGFILE_READS, 1, - PhaFormatUInt64(buffer->NtfsStatistics.LogFileReads, TRUE)->Buffer); - PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_LOGFILE_WRITES, 1, - PhaFormatUInt64(buffer->NtfsStatistics.LogFileWrites, TRUE)->Buffer); - PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_LOGFILE_READ_BYTES, 1, - PhaFormatSize(buffer->NtfsStatistics.LogFileReadBytes, ULONG_MAX)->Buffer); - PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_LOGFILE_WRITE_BYTES, 1, - PhaFormatSize(buffer->NtfsStatistics.LogFileWriteBytes, ULONG_MAX)->Buffer); - /*PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_MFT_USER_LEVEL_WRITE, 1, - PhaFormatUInt64(buffer->NtfsStatistics.MftWritesUserLevel.Write, TRUE)->Buffer); - PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_MFT_USER_LEVEL_CREATE, 1, - PhaFormatUInt64(buffer->NtfsStatistics.MftWritesUserLevel.Create, TRUE)->Buffer); - PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_MFT_USER_LEVEL_SETINFO, 1, - PhaFormatUInt64(buffer->NtfsStatistics.MftWritesUserLevel.SetInfo, TRUE)->Buffer); - PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_MFT_USER_LEVEL_FLUSH, 1, - PhaFormatUInt64(buffer->NtfsStatistics.MftWritesUserLevel.Flush, TRUE)->Buffer); - PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_MFT_WRITES_FLUSH_LOGFILE, 1, - PhaFormatUInt64(buffer->NtfsStatistics.MftWritesFlushForLogFileFull, TRUE)->Buffer); - PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_MFT_WRITES_LAZY_WRITER, 1, - PhaFormatUInt64(buffer->NtfsStatistics.MftWritesLazyWriter, TRUE)->Buffer); - PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_MFT_WRITES_USER_REQUEST, 1, - PhaFormatUInt64(buffer->NtfsStatistics.MftWritesUserRequest, TRUE)->Buffer); - PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_MFT2_WRITES, 1, - PhaFormatUInt64(buffer->NtfsStatistics.Mft2Writes, TRUE)->Buffer); - PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_MFT2_WRITE_BYTES, 1, - PhaFormatSize(buffer->NtfsStatistics.Mft2WriteBytes, ULONG_MAX)->Buffer); - PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_MFT2_USER_LEVEL_WRITE, 1, - PhaFormatUInt64(buffer->NtfsStatistics.Mft2WritesUserLevel.Write, TRUE)->Buffer); - PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_MFT2_USER_LEVEL_CREATE, 1, - PhaFormatUInt64(buffer->NtfsStatistics.Mft2WritesUserLevel.Create, TRUE)->Buffer); - PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_MFT2_USER_LEVEL_SETINFO, 1, - PhaFormatUInt64(buffer->NtfsStatistics.Mft2WritesUserLevel.SetInfo, TRUE)->Buffer); - PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_MFT2_USER_LEVEL_FLUSH, 1, - PhaFormatUInt64(buffer->NtfsStatistics.Mft2WritesUserLevel.Flush, TRUE)->Buffer); - PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_MFT2_WRITES_FLUSH_LOGFILE, 1, - PhaFormatUInt64(buffer->NtfsStatistics.Mft2WritesFlushForLogFileFull, TRUE)->Buffer); - PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_MFT2_WRITES_LAZY_WRITER, 1, - PhaFormatUInt64(buffer->NtfsStatistics.Mft2WritesLazyWriter, TRUE)->Buffer); - PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_MFT2_WRITES_USER_REQUEST, 1, - PhaFormatUInt64(buffer->NtfsStatistics.Mft2WritesUserRequest, TRUE)->Buffer); - PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_BITMAP_WRITES_FLUSH_LOGFILE, 1, - PhaFormatUInt64(buffer->NtfsStatistics.BitmapWritesFlushForLogFileFull, TRUE)->Buffer); - PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_BITMAP_WRITES_LAZY_WRITER, 1, - PhaFormatUInt64(buffer->NtfsStatistics.BitmapWritesLazyWriter, TRUE)->Buffer); - PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_BITMAP_WRITES_USER_REQUEST, 1, - PhaFormatUInt64(buffer->NtfsStatistics.BitmapWritesUserRequest, TRUE)->Buffer); - PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_BITMAP_WRITES_WRITE, 1, - PhaFormatUInt64(buffer->NtfsStatistics.BitmapWritesUserLevel.Write, TRUE)->Buffer); - PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_BITMAP_WRITES_CREATE, 1, - PhaFormatUInt64(buffer->NtfsStatistics.BitmapWritesUserLevel.Create, TRUE)->Buffer); - PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_BITMAP_WRITES_SETINFO, 1, - PhaFormatUInt64(buffer->NtfsStatistics.BitmapWritesUserLevel.SetInfo, TRUE)->Buffer); - PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_MFT_BITMAP_FLUSH_LOGFILE, 1, - PhaFormatUInt64(buffer->NtfsStatistics.MftBitmapWritesFlushForLogFileFull, TRUE)->Buffer); - PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_MFT_BITMAP_LAZY_WRITER, 1, - PhaFormatUInt64(buffer->NtfsStatistics.MftBitmapWritesLazyWriter, TRUE)->Buffer); - PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_MFT_BITMAP_USER_REQUEST, 1, - PhaFormatUInt64(buffer->NtfsStatistics.MftBitmapWritesUserRequest, TRUE)->Buffer); - PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_MFT_BITMAP_USER_LEVEL_WRITE, 1, - PhaFormatUInt64(buffer->NtfsStatistics.MftBitmapWritesUserLevel.Write, TRUE)->Buffer); - PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_MFT_BITMAP_USER_LEVEL_CREATE, 1, - PhaFormatUInt64(buffer->NtfsStatistics.MftBitmapWritesUserLevel.Create, TRUE)->Buffer); - PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_MFT_BITMAP_USER_LEVEL_SETINFO, 1, - PhaFormatUInt64(buffer->NtfsStatistics.MftBitmapWritesUserLevel.SetInfo, TRUE)->Buffer); - PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_MFT_BITMAP_USER_LEVEL_FLUSH, 1, - PhaFormatUInt64(buffer->NtfsStatistics.MftBitmapWritesUserLevel.Flush, TRUE)->Buffer);*/ - PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_ALLOCATE_CALLS, 1, - PhaFormatUInt64(buffer->NtfsStatistics.Allocate.Calls, TRUE)->Buffer); - PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_ALLOCATE_CLUSTERS, 1, - PhaFormatUInt64(buffer->NtfsStatistics.Allocate.Clusters, TRUE)->Buffer); - PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_ALLOCATE_HINTS, 1, - PhaFormatUInt64(buffer->NtfsStatistics.Allocate.Hints, TRUE)->Buffer); - PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_ALLOCATE_RUNS_RETURNED, 1, - PhaFormatUInt64(buffer->NtfsStatistics.Allocate.RunsReturned, TRUE)->Buffer); - PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_ALLOCATE_HITS_HONORED, 1, - PhaFormatUInt64(buffer->NtfsStatistics.Allocate.HintsHonored, TRUE)->Buffer); - PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_ALLOCATE_HITS_CLUSTERS, 1, - PhaFormatUInt64(buffer->NtfsStatistics.Allocate.HintsClusters, TRUE)->Buffer); - PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_ALLOCATE_CACHE, 1, - PhaFormatUInt64(buffer->NtfsStatistics.Allocate.Cache, TRUE)->Buffer); - PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_ALLOCATE_CACHE_CLUSTERS, 1, - PhaFormatUInt64(buffer->NtfsStatistics.Allocate.CacheClusters, TRUE)->Buffer); - PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_ALLOCATE_CACHE_MISS, 1, - PhaFormatUInt64(buffer->NtfsStatistics.Allocate.CacheMiss, TRUE)->Buffer); - PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_ALLOCATE_CACHE_MISS_CLUSTERS, 1, - PhaFormatUInt64(buffer->NtfsStatistics.Allocate.CacheMissClusters, TRUE)->Buffer); - PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_LOGFILE_EXCEPTIONS, 1, - PhaFormatUInt64(buffer->NtfsStatistics.LogFileFullExceptions, TRUE)->Buffer); + PhSetListViewSubItem(Context->ListViewHandle, DISKDRIVE_DETAILS_INDEX_OTHER_EXCEPTIONS, 1, - PhaFormatUInt64(buffer->NtfsStatistics.OtherExceptions, TRUE)->Buffer); + PhaFormatUInt64(UInt32Add32To64(buffer->NtfsStatistics.LogFileFullExceptions, buffer->NtfsStatistics.OtherExceptions), TRUE)->Buffer); // TODO: Additions for Windows 8.1 and Windows 10... } @@ -756,6 +605,8 @@ INT_PTR CALLBACK DiskDriveSmartDetailsDlgProc( PhAddListViewColumn(context->ListViewHandle, 2, 2, 2, LVCFMT_LEFT, 50, L"Best"); PhAddListViewColumn(context->ListViewHandle, 3, 3, 3, LVCFMT_LEFT, 80, L"Raw"); PhAddListViewColumn(context->ListViewHandle, 4, 4, 4, LVCFMT_LEFT, 80, L"Raw (Hex)"); + //PhAddListViewColumn(context->ListViewHandle, 5, 5, 5, LVCFMT_LEFT, 80, L"Advisory"); + //PhAddListViewColumn(context->ListViewHandle, 6, 6, 6, LVCFMT_LEFT, 80, L"Failure Imminent"); PhSetExtendedListView(context->ListViewHandle); //ExtendedListView_SetItemColorFunction(context->ListViewHandle, PhpColorItemColorFunction); PhLoadListViewColumnsFromSetting(SETTING_NAME_SMART_COUNTERS_COLUMNS, context->ListViewHandle); diff --git a/plugins/HardwareDevices/diskgraph.c b/plugins/HardwareDevices/diskgraph.c index 9a52e3104d00..a20d1265d862 100644 --- a/plugins/HardwareDevices/diskgraph.c +++ b/plugins/HardwareDevices/diskgraph.c @@ -49,7 +49,7 @@ VOID DiskDriveUpdatePanel( PhaFormatString(L"%.1f ms", Context->DiskEntry->ResponseTime / PH_TICKS_PER_MS)->Buffer ); PhSetDialogItemText(Context->PanelWindowHandle, IDC_STAT_QUEUELENGTH, - PhaFormatString(L"%lu", Context->DiskEntry->QueueDepth)->Buffer + PhaFormatString(L"%s/s", PhaFormatSize(Context->DiskEntry->BytesReadDelta.Delta + Context->DiskEntry->BytesWrittenDelta.Delta, ULONG_MAX)->Buffer)->Buffer ); } @@ -326,7 +326,7 @@ INT_PTR CALLBACK DiskDriveDialogProc( L"R: %s\nW: %s\n%s", PhaFormatSize(diskReadValue, ULONG_MAX)->Buffer, PhaFormatSize(diskWriteValue, ULONG_MAX)->Buffer, - ((PPH_STRING)PhAutoDereferenceObject(PhGetStatisticsTimeString(NULL, getTooltipText->Index)))->Buffer + ((PPH_STRING)PH_AUTO(PhGetStatisticsTimeString(NULL, getTooltipText->Index)))->Buffer )); } @@ -455,7 +455,7 @@ BOOLEAN DiskDriveSectionCallback( L"R: %s\nW: %s\n%s", PhaFormatSize(diskReadValue, ULONG_MAX)->Buffer, PhaFormatSize(diskWriteValue, ULONG_MAX)->Buffer, - ((PPH_STRING)PhAutoDereferenceObject(PhGetStatisticsTimeString(NULL, getTooltipText->Index)))->Buffer + ((PPH_STRING)PH_AUTO(PhGetStatisticsTimeString(NULL, getTooltipText->Index)))->Buffer )); getTooltipText->Text = Section->GraphState.TooltipText->sr; From f667fd624527c222d027ca8281751e0adaf60931 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 13 Aug 2019 02:59:53 +1000 Subject: [PATCH 2046/2058] HardwareDevices: Add total adapter delta stats; Update adapter panel layout --- plugins/HardwareDevices/HardwareDevices.rc | 67 ++++++++++++---------- plugins/HardwareDevices/adapter.c | 19 +++++- plugins/HardwareDevices/devices.h | 13 +++++ plugins/HardwareDevices/netdetails.c | 12 ++-- plugins/HardwareDevices/netgraph.c | 61 +++++++++++++++++--- plugins/HardwareDevices/resource.h | 8 ++- 6 files changed, 130 insertions(+), 50 deletions(-) diff --git a/plugins/HardwareDevices/HardwareDevices.rc b/plugins/HardwareDevices/HardwareDevices.rc index 2d1095b349c3..7fb0a62c1740 100644 --- a/plugins/HardwareDevices/HardwareDevices.rc +++ b/plugins/HardwareDevices/HardwareDevices.rc @@ -95,34 +95,25 @@ BEGIN CONTROL "Show hidden adapters",IDC_SHOW_HIDDEN_ADAPTERS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,159,87,10 END -IDD_NETADAPTER_DIALOG DIALOGEX 0, 0, 269, 130 -STYLE DS_SETFONT | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME -EXSTYLE WS_EX_APPWINDOW -CAPTION "Dialog" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "",IDC_GRAPH_LAYOUT,0,21,269,53,NOT WS_VISIBLE | WS_BORDER - LTEXT "Static",IDC_ADAPTERNAME,0,0,269,21 - LTEXT "Panel layout",IDC_LAYOUT,0,91,268,36,NOT WS_VISIBLE -END - -IDD_NETADAPTER_PANEL DIALOGEX 0, 0, 254, 50 +IDD_NETADAPTER_PANEL DIALOGEX 0, 0, 330, 50 STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_SYSMENU FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN - LTEXT "Link speed",IDC_STATIC,7,11,35,8 - RTEXT "Static",IDC_LINK_SPEED,50,11,54,8,SS_ENDELLIPSIS - GROUPBOX "Adapter",IDC_STATIC,0,0,111,34 - LTEXT "Link state",IDC_STATIC,7,23,32,8 - RTEXT "Static",IDC_LINK_STATE,50,23,54,8,SS_ENDELLIPSIS - GROUPBOX "Statistics",IDC_STATIC,116,0,136,45 - LTEXT "Bytes sent",IDC_STATIC,125,11,36,8 - LTEXT "Bytes received",IDC_STATIC,125,22,50,8 - RTEXT "Static",IDC_STAT_BSENT,182,11,62,8,SS_ENDELLIPSIS - RTEXT "Static",IDC_STAT_BRECEIVED,182,22,62,8,SS_ENDELLIPSIS - LTEXT "Bytes total",IDC_STATIC,125,33,37,8 - RTEXT "Static",IDC_STAT_BTOTAL,182,33,62,8,SS_ENDELLIPSIS - PUSHBUTTON "Details",IDC_DETAILS,0,35,50,14 + LTEXT "Bytes sent",IDC_STATIC,148,11,36,8 + LTEXT "Bytes received",IDC_STATIC,148,22,50,8 + RTEXT "Static",IDC_STAT_BSENT,205,11,62,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_STAT_BRECEIVED,205,22,62,8,SS_ENDELLIPSIS + LTEXT "Bytes total",IDC_STATIC,148,33,37,8 + RTEXT "Static",IDC_STAT_BTOTAL,205,33,62,8,SS_ENDELLIPSIS + PUSHBUTTON "Details",IDC_DETAILS,278,32,50,14 + LTEXT "Link speed",IDC_STATIC,8,11,53,8,SS_ENDELLIPSIS + LTEXT "Link state",IDC_STATIC,8,22,64,8,SS_ENDELLIPSIS + LTEXT "Bytes delta",IDC_STATIC,8,33,57,8,SS_ENDELLIPSIS + GROUPBOX "Adapter",IDC_STATIC,0,0,135,46 + RTEXT "Static",IDC_LINK_SPEED,65,11,62,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_LINK_STATE,65,22,62,8,SS_ENDELLIPSIS + RTEXT "Static",IDC_STAT_QUEUELENGTH,65,33,62,8,SS_ENDELLIPSIS + GROUPBOX "Statistics",IDC_STATIC,139,0,136,46 END IDD_NETADAPTER_DETAILS DIALOGEX 0, 0, 309, 265 @@ -190,6 +181,18 @@ BEGIN CONTROL "",IDC_DETAILS_LIST,"SysListView32",LVS_REPORT | LVS_ALIGNLEFT | WS_TABSTOP,0,0,309,265 END +IDD_NETADAPTER_DIALOG DIALOGEX 0, 0, 315, 135 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME +EXSTYLE WS_EX_APPWINDOW +CAPTION "Dialog" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "",IDC_GRAPH_LAYOUT,0,21,314,60,NOT WS_VISIBLE | WS_BORDER + LTEXT "Adapter",IDC_ADAPTERTEXT,0,0,105,21 + LTEXT "Panel layout",IDC_LAYOUT,0,98,314,36,NOT WS_VISIBLE + RTEXT "Adapter name",IDC_ADAPTERNAME,107,4,207,16,SS_WORDELLIPSIS +END + ///////////////////////////////////////////////////////////////////////////// // @@ -207,14 +210,10 @@ BEGIN BOTTOMMARGIN, 170 END - IDD_NETADAPTER_DIALOG, DIALOG - BEGIN - END - IDD_NETADAPTER_PANEL, DIALOG BEGIN - RIGHTMARGIN, 253 - TOPMARGIN, 1 + RIGHTMARGIN, 329 + BOTTOMMARGIN, 49 END IDD_NETADAPTER_DETAILS, DIALOG @@ -248,6 +247,12 @@ BEGIN IDD_DISKDRIVE_DETAILS_FILESYSTEM, DIALOG BEGIN END + + IDD_NETADAPTER_DIALOG, DIALOG + BEGIN + RIGHTMARGIN, 314 + BOTTOMMARGIN, 134 + END END #endif // APSTUDIO_INVOKED diff --git a/plugins/HardwareDevices/adapter.c b/plugins/HardwareDevices/adapter.c index 0b1f97d0a4c1..ad65f26bdf01 100644 --- a/plugins/HardwareDevices/adapter.c +++ b/plugins/HardwareDevices/adapter.c @@ -65,6 +65,7 @@ VOID NetAdaptersUpdate( ULONG64 networkOutOctets = 0; ULONG64 networkRcvSpeed = 0; ULONG64 networkXmitSpeed = 0; + ULONG64 linkSpeedValue = 0; NDIS_MEDIA_CONNECT_STATE mediaState = MediaConnectStateUnknown; entry = PhReferenceObjectSafe(NetworkAdaptersList->Items[i]); @@ -114,6 +115,11 @@ VOID NetAdaptersUpdate( if (NT_SUCCESS(NetworkAdapterQueryLinkState(deviceHandle, &interfaceState))) { mediaState = interfaceState.MediaConnectState; + linkSpeedValue = interfaceState.XmitLinkSpeed; + } + else + { + NetworkAdapterQueryLinkSpeed(deviceHandle, &linkSpeedValue); } if (NT_SUCCESS(NetworkAdapterQueryStatistics(deviceHandle, &interfaceStats))) @@ -174,8 +180,17 @@ VOID NetAdaptersUpdate( if (mediaState == MediaConnectStateUnknown) { // We don't want incorrect data when the adapter is disabled. - networkRcvSpeed = 0; - networkXmitSpeed = 0; + entry->HaveFirstSample = FALSE; + } + + if (networkRcvSpeed > linkSpeedValue) + { + entry->HaveFirstSample = FALSE; + } + + if (networkXmitSpeed > linkSpeedValue) + { + entry->HaveFirstSample = FALSE; } if (!entry->HaveFirstSample) diff --git a/plugins/HardwareDevices/devices.h b/plugins/HardwareDevices/devices.h index b013c4d2fac8..ce4da3a19843 100644 --- a/plugins/HardwareDevices/devices.h +++ b/plugins/HardwareDevices/devices.h @@ -119,6 +119,19 @@ typedef struct _DV_NETADAPTER_SYSINFO_CONTEXT PPH_SYSINFO_SECTION SysinfoSection; PH_GRAPH_STATE GraphState; PH_LAYOUT_MANAGER LayoutManager; + + union + { + BOOLEAN Flags; + struct + { + BOOLEAN HaveFirstSample : 1; + BOOLEAN Spare : 7; + }; + }; + + ULONG64 LastInboundValue; + ULONG64 LastOutboundValue; } DV_NETADAPTER_SYSINFO_CONTEXT, *PDV_NETADAPTER_SYSINFO_CONTEXT; typedef struct _DV_NETADAPTER_DETAILS_CONTEXT diff --git a/plugins/HardwareDevices/netdetails.c b/plugins/HardwareDevices/netdetails.c index dea0aa54f327..3d71617b4880 100644 --- a/plugins/HardwareDevices/netdetails.c +++ b/plugins/HardwareDevices/netdetails.c @@ -448,12 +448,12 @@ VOID NetAdapterUpdateDetails( } PhSetListViewSubItem(Context->ListViewHandle, NETADAPTER_DETAILS_INDEX_STATE, 1, mediaState == MediaConnectStateConnected ? L"Connected" : L"Disconnected"); - PhSetListViewSubItem(Context->ListViewHandle, NETADAPTER_DETAILS_INDEX_LINKSPEED, 1, PhaFormatString(L"%s/s", PhaFormatSize(interfaceLinkSpeed / BITS_IN_ONE_BYTE, -1)->Buffer)->Buffer); - PhSetListViewSubItem(Context->ListViewHandle, NETADAPTER_DETAILS_INDEX_SENT, 1, PhaFormatSize(interfaceStats.ifHCOutOctets, -1)->Buffer); - PhSetListViewSubItem(Context->ListViewHandle, NETADAPTER_DETAILS_INDEX_RECEIVED, 1, PhaFormatSize(interfaceStats.ifHCInOctets, -1)->Buffer); - PhSetListViewSubItem(Context->ListViewHandle, NETADAPTER_DETAILS_INDEX_TOTAL, 1, PhaFormatSize(interfaceStats.ifHCInOctets + interfaceStats.ifHCOutOctets, -1)->Buffer); - PhSetListViewSubItem(Context->ListViewHandle, NETADAPTER_DETAILS_INDEX_SENDING, 1, interfaceXmitSpeed != 0 ? PhaFormatString(L"%s/s", PhaFormatSize(interfaceXmitSpeed, -1)->Buffer)->Buffer : L""); - PhSetListViewSubItem(Context->ListViewHandle, NETADAPTER_DETAILS_INDEX_RECEIVING, 1, interfaceRcvSpeed != 0 ? PhaFormatString(L"%s/s", PhaFormatSize(interfaceRcvSpeed, -1)->Buffer)->Buffer : L""); + PhSetListViewSubItem(Context->ListViewHandle, NETADAPTER_DETAILS_INDEX_LINKSPEED, 1, PhaFormatString(L"%s/s", PhaFormatSize(interfaceLinkSpeed / BITS_IN_ONE_BYTE, ULONG_MAX)->Buffer)->Buffer); + PhSetListViewSubItem(Context->ListViewHandle, NETADAPTER_DETAILS_INDEX_SENT, 1, PhaFormatSize(interfaceStats.ifHCOutOctets, ULONG_MAX)->Buffer); + PhSetListViewSubItem(Context->ListViewHandle, NETADAPTER_DETAILS_INDEX_RECEIVED, 1, PhaFormatSize(interfaceStats.ifHCInOctets, ULONG_MAX)->Buffer); + PhSetListViewSubItem(Context->ListViewHandle, NETADAPTER_DETAILS_INDEX_TOTAL, 1, PhaFormatSize(interfaceStats.ifHCInOctets + interfaceStats.ifHCOutOctets, ULONG_MAX)->Buffer); + PhSetListViewSubItem(Context->ListViewHandle, NETADAPTER_DETAILS_INDEX_SENDING, 1, interfaceXmitSpeed != 0 ? PhaFormatString(L"%s/s", PhaFormatSize(interfaceXmitSpeed, ULONG_MAX)->Buffer)->Buffer : L""); + PhSetListViewSubItem(Context->ListViewHandle, NETADAPTER_DETAILS_INDEX_RECEIVING, 1, interfaceRcvSpeed != 0 ? PhaFormatString(L"%s/s", PhaFormatSize(interfaceRcvSpeed, ULONG_MAX)->Buffer)->Buffer : L""); if (interfaceLinkSpeed > 0) { diff --git a/plugins/HardwareDevices/netgraph.c b/plugins/HardwareDevices/netgraph.c index 710311bf4918..66f2a167bc7e 100644 --- a/plugins/HardwareDevices/netgraph.c +++ b/plugins/HardwareDevices/netgraph.c @@ -2,7 +2,7 @@ * Process Hacker Plugins - * Hardware Devices Plugin * - * Copyright (C) 2015-2016 dmex + * Copyright (C) 2015-2019 dmex * Copyright (C) 2016 wj32 * * This file is part of Process Hacker. @@ -42,6 +42,8 @@ VOID NetAdapterUpdatePanel( ULONG64 inOctetsValue = 0; ULONG64 outOctetsValue = 0; ULONG64 linkSpeedValue = 0; + ULONG64 interfaceRcvSpeed = 0; + ULONG64 interfaceXmitSpeed = 0; NDIS_MEDIA_CONNECT_STATE mediaState = MediaConnectStateUnknown; HANDLE deviceHandle = NULL; @@ -96,13 +98,9 @@ VOID NetAdapterUpdatePanel( } else { - // Note: The above code fails for some drivers that don't implement statistics (even though statistics are mandatory). - // NDIS handles these two OIDs for all miniport drivers and we can use these for those special cases. - // https://msdn.microsoft.com/en-us/library/ff569443.aspx - inOctetsValue = NetworkAdapterQueryValue(deviceHandle, OID_GEN_BYTES_RCV); - // https://msdn.microsoft.com/en-us/library/ff569445.aspx + inOctetsValue = NetworkAdapterQueryValue(deviceHandle, OID_GEN_BYTES_RCV); outOctetsValue = NetworkAdapterQueryValue(deviceHandle, OID_GEN_BYTES_XMIT); } @@ -131,6 +129,21 @@ VOID NetAdapterUpdatePanel( } } + interfaceRcvSpeed = inOctetsValue - Context->LastInboundValue; + interfaceXmitSpeed = outOctetsValue - Context->LastOutboundValue; + Context->LastInboundValue = inOctetsValue; + Context->LastOutboundValue = outOctetsValue; + + //interfaceRcvUnicastSpeed = interfaceStats.ifHCInUcastOctets - Context->LastDetailsInboundUnicastValue; + //interfaceXmitUnicastSpeed = interfaceStats.ifHCOutUcastOctets - Context->LastDetailsIOutboundUnicastValue; + + if (!Context->HaveFirstSample) + { + interfaceRcvSpeed = 0; + interfaceXmitSpeed = 0; + Context->HaveFirstSample = TRUE; + } + PhSetDialogItemText(Context->PanelWindowHandle, IDC_STAT_BSENT, PhaFormatSize(outOctetsValue, ULONG_MAX)->Buffer); PhSetDialogItemText(Context->PanelWindowHandle, IDC_STAT_BRECEIVED, PhaFormatSize(inOctetsValue, ULONG_MAX)->Buffer); PhSetDialogItemText(Context->PanelWindowHandle, IDC_STAT_BTOTAL, PhaFormatSize(inOctetsValue + outOctetsValue, ULONG_MAX)->Buffer); @@ -138,24 +151,43 @@ VOID NetAdapterUpdatePanel( if (mediaState == MediaConnectStateConnected) { PhSetDialogItemText(Context->PanelWindowHandle, IDC_LINK_STATE, L"Connected"); - PhSetDialogItemText(Context->PanelWindowHandle, IDC_LINK_SPEED, PhaFormatString(L"%s/s", PhaFormatSize(linkSpeedValue / BITS_IN_ONE_BYTE, ULONG_MAX)->Buffer)->Buffer); + PhSetDialogItemText(Context->PanelWindowHandle, IDC_LINK_SPEED, PhaFormatString( + L"%s/s", + PhaFormatSize(linkSpeedValue / BITS_IN_ONE_BYTE, ULONG_MAX)->Buffer + )->Buffer); } else { PhSetDialogItemText(Context->PanelWindowHandle, IDC_LINK_STATE, L"Disconnected"); PhSetDialogItemText(Context->PanelWindowHandle, IDC_LINK_SPEED, L"N/A"); } + + PhSetDialogItemText(Context->PanelWindowHandle, IDC_STAT_QUEUELENGTH, PhaFormatString( + L"%s/s", + PhaFormatSize(interfaceRcvSpeed + interfaceXmitSpeed, ULONG_MAX)->Buffer)->Buffer + ); } VOID UpdateNetAdapterDialog( _Inout_ PDV_NETADAPTER_SYSINFO_CONTEXT Context ) { + MIB_IF_ROW2 interfaceRow; + if (Context->AdapterEntry->AdapterName) PhSetDialogItemText(Context->WindowHandle, IDC_ADAPTERNAME, Context->AdapterEntry->AdapterName->Buffer); else PhSetDialogItemText(Context->WindowHandle, IDC_ADAPTERNAME, L"Unknown network adapter"); + if (QueryInterfaceRow(&Context->AdapterEntry->AdapterId, &interfaceRow)) + { + PhSetDialogItemText(Context->WindowHandle, IDC_ADAPTERTEXT, interfaceRow.Alias); + } + else + { + PhSetDialogItemText(Context->WindowHandle, IDC_ADAPTERTEXT, L""); + } + NetAdapterUpdateGraphs(Context); NetAdapterUpdatePanel(Context); } @@ -238,6 +270,7 @@ INT_PTR CALLBACK NetAdapterDialogProc( { PPH_LAYOUT_ITEM graphItem; PPH_LAYOUT_ITEM panelItem; + MIB_IF_ROW2 interfaceRow; context->WindowHandle = hwndDlg; @@ -248,7 +281,19 @@ INT_PTR CALLBACK NetAdapterDialogProc( graphItem = PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_GRAPH_LAYOUT), NULL, PH_ANCHOR_ALL); panelItem = PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_LAYOUT), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); - SetWindowFont(GetDlgItem(hwndDlg, IDC_ADAPTERNAME), context->SysinfoSection->Parameters->LargeFont, FALSE); + SetWindowFont(GetDlgItem(hwndDlg, IDC_ADAPTERTEXT), context->SysinfoSection->Parameters->LargeFont, FALSE); + SetWindowFont(GetDlgItem(hwndDlg, IDC_ADAPTERNAME), context->SysinfoSection->Parameters->MediumFont, FALSE); + + if (QueryInterfaceRow(&context->AdapterEntry->AdapterId, &interfaceRow)) + { + PhSetDialogItemText(hwndDlg, IDC_ADAPTERTEXT, interfaceRow.Alias); + } + else + { + PhSetDialogItemText(hwndDlg, IDC_ADAPTERTEXT, L""); + } + + //SetWindowFont(GetDlgItem(hwndDlg, IDC_ADAPTERNAME), context->SysinfoSection->Parameters->LargeFont, FALSE); PhSetDialogItemText(hwndDlg, IDC_ADAPTERNAME, PhGetStringOrDefault(context->AdapterEntry->AdapterName, L"Unknown network adapter")); context->PanelWindowHandle = CreateDialogParam(PluginInstance->DllBase, MAKEINTRESOURCE(IDD_NETADAPTER_PANEL), hwndDlg, NetAdapterPanelDialogProc, (LPARAM)context); diff --git a/plugins/HardwareDevices/resource.h b/plugins/HardwareDevices/resource.h index bf9845766341..a83aa9d3ed54 100644 --- a/plugins/HardwareDevices/resource.h +++ b/plugins/HardwareDevices/resource.h @@ -10,7 +10,6 @@ #define IDD_DISKDRIVE_DETAILS_FILESYSTEM 109 #define IDC_NETADAPTERS_LISTVIEW 1001 #define IDC_LINK_SPEED 1002 -#define IDC_ADAPTERNAME 1003 #define IDC_LAYOUT 1004 #define IDC_LINK_STATE 1005 #define IDC_STAT_BSENT 1006 @@ -25,8 +24,11 @@ #define IDD_DISKDRIVE_DETAILS_SMART 1017 #define IDC_DISKDRIVE_LISTVIEW 1017 #define IDC_DISKMOUNTPATH 1018 +#define IDD_NETADAPTER_DIALOG 1018 #define IDC_STAT_BREAD 1020 #define IDC_STAT_BWRITE 1021 +#define IDC_ADAPTERNAME 1021 +#define IDC_ADAPTERTEXT 1022 #define IDC_STAT_ACTIVE 1023 #define IDC_STAT_RESPONSETIME 1024 #define IDC_STAT_QUEUELENGTH 1025 @@ -36,9 +38,9 @@ // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 114 +#define _APS_NEXT_RESOURCE_VALUE 117 #define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1021 +#define _APS_NEXT_CONTROL_VALUE 1023 #define _APS_NEXT_SYMED_VALUE 106 #endif #endif From f2e80128e5b0a5e98c55d651d0756267a43f00dc Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 13 Aug 2019 03:33:39 +1000 Subject: [PATCH 2047/2058] Update resource.h --- plugins/HardwareDevices/resource.h | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/HardwareDevices/resource.h b/plugins/HardwareDevices/resource.h index a83aa9d3ed54..1abb9e692752 100644 --- a/plugins/HardwareDevices/resource.h +++ b/plugins/HardwareDevices/resource.h @@ -3,7 +3,6 @@ // Used by HardwareDevices.rc // #define IDD_NETADAPTER_OPTIONS 101 -#define IDD_NETADAPTER_DIALOG 102 #define IDC_GRAPH_LAYOUT 103 #define IDD_NETADAPTER_PANEL 104 #define IDD_NETADAPTER_DETAILS 105 From a8ecb36740f4e43b0d9d01fa5e98578e01482435 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 13 Aug 2019 04:24:52 +1000 Subject: [PATCH 2048/2058] Add inital system module highlighting --- ProcessHacker/include/modlist.h | 6 +++++- ProcessHacker/modlist.c | 22 +++++++++++++++++++++- ProcessHacker/prpgmod.c | 18 ++++++++++++++++++ 3 files changed, 44 insertions(+), 2 deletions(-) diff --git a/ProcessHacker/include/modlist.h b/ProcessHacker/include/modlist.h index 2d1ca06dd982..bf14ac60db92 100644 --- a/ProcessHacker/include/modlist.h +++ b/ProcessHacker/include/modlist.h @@ -70,6 +70,8 @@ typedef struct _PH_MODULE_NODE #define PH_MODULE_FLAGS_HIGHLIGHT_RELOCATED_OPTION 8 #define PH_MODULE_FLAGS_LOAD_MODULE_OPTION 9 #define PH_MODULE_FLAGS_MODULE_STRINGS_OPTION 10 +#define PH_MODULE_FLAGS_SYSTEM_OPTION 11 +#define PH_MODULE_FLAGS_HIGHLIGHT_SYSTEM_OPTION 12 typedef struct _PH_MODULE_LIST_CONTEXT { @@ -94,7 +96,9 @@ typedef struct _PH_MODULE_LIST_CONTEXT ULONG HighlightDotNetModules : 1; ULONG HighlightImmersiveModules : 1; ULONG HighlightRelocatedModules : 1; - ULONG Spare : 23; + ULONG HideSystemModules : 1; + ULONG HighlightSystemModules : 1; + ULONG Spare : 21; }; }; diff --git a/ProcessHacker/modlist.c b/ProcessHacker/modlist.c index 21e82fd4731a..f1627ecb1af0 100644 --- a/ProcessHacker/modlist.c +++ b/ProcessHacker/modlist.c @@ -233,6 +233,12 @@ VOID PhSetOptionsModuleList( case PH_MODULE_FLAGS_HIGHLIGHT_RELOCATED_OPTION: Context->HighlightRelocatedModules = !Context->HighlightRelocatedModules; break; + case PH_MODULE_FLAGS_SYSTEM_OPTION: + Context->HideSystemModules = !Context->HideSystemModules; + break; + case PH_MODULE_FLAGS_HIGHLIGHT_SYSTEM_OPTION: + Context->HighlightSystemModules = !Context->HighlightSystemModules; + break; } } @@ -999,14 +1005,28 @@ BOOLEAN NTAPI PhpModuleTreeNewCallback( if (!moduleItem) ; // Dummy - else if (PhEnableProcessQueryStage2 && context->HighlightUntrustedModules && moduleItem->VerifyResult != VrTrusted && moduleItem->Type != PH_MODULE_TYPE_ELF_MAPPED_IMAGE) + else if (PhEnableProcessQueryStage2 && + context->HighlightUntrustedModules && + moduleItem->VerifyResult != VrTrusted && + moduleItem->Type != PH_MODULE_TYPE_ELF_MAPPED_IMAGE + ) + { getNodeColor->BackColor = PhCsColorUnknown; + } else if (context->HighlightDotNetModules && (moduleItem->Flags & LDRP_COR_IMAGE)) getNodeColor->BackColor = PhCsColorDotNet; else if (context->HighlightImmersiveModules && (moduleItem->ImageDllCharacteristics & IMAGE_DLLCHARACTERISTICS_APPCONTAINER)) getNodeColor->BackColor = PhCsColorImmersiveProcesses; else if (context->HighlightRelocatedModules && (moduleItem->Flags & LDRP_IMAGE_NOT_AT_BASE)) getNodeColor->BackColor = PhCsColorRelocatedModules; + else if (PhEnableProcessQueryStage2 && + context->HighlightSystemModules && + moduleItem->VerifyResult == VrTrusted && + PhEqualStringRef2(&moduleItem->VerifySignerName->sr, L"Microsoft Windows", TRUE) + ) + { + getNodeColor->BackColor = PhCsColorSystemProcesses; + } getNodeColor->Flags = TN_AUTO_FORECOLOR; } diff --git a/ProcessHacker/prpgmod.c b/ProcessHacker/prpgmod.c index 70f14986a8df..afee83ac64f4 100644 --- a/ProcessHacker/prpgmod.c +++ b/ProcessHacker/prpgmod.c @@ -254,6 +254,16 @@ BOOLEAN PhpModulesTreeFilterCallback( if (Context->ListContext.HideSignedModules && moduleItem->VerifyResult == VrTrusted) return FALSE; + if ( + PhEnableProcessQueryStage2 && + Context->ListContext.HideSystemModules && + moduleItem->VerifyResult == VrTrusted && + PhEqualStringRef2(&moduleItem->VerifySignerName->sr, L"Microsoft Windows", TRUE) + ) + { + return FALSE; + } + if (PhIsNullOrEmptyString(Context->SearchboxText)) return TRUE; @@ -667,7 +677,9 @@ INT_PTR CALLBACK PhpProcessModulesDlgProc( PPH_EMENU_ITEM mappedItem; PPH_EMENU_ITEM staticItem; PPH_EMENU_ITEM verifiedItem; + PPH_EMENU_ITEM systemItem; PPH_EMENU_ITEM untrustedItem; + PPH_EMENU_ITEM systemHighlightItem; PPH_EMENU_ITEM dotnetItem; PPH_EMENU_ITEM immersiveItem; PPH_EMENU_ITEM relocatedItem; @@ -680,11 +692,13 @@ INT_PTR CALLBACK PhpProcessModulesDlgProc( PhInsertEMenuItem(menu, mappedItem = PhCreateEMenuItem(0, PH_MODULE_FLAGS_MAPPED_OPTION, L"Hide mapped", NULL, NULL), ULONG_MAX); PhInsertEMenuItem(menu, staticItem = PhCreateEMenuItem(0, PH_MODULE_FLAGS_STATIC_OPTION, L"Hide static", NULL, NULL), ULONG_MAX); PhInsertEMenuItem(menu, verifiedItem = PhCreateEMenuItem(0, PH_MODULE_FLAGS_SIGNED_OPTION, L"Hide verified", NULL, NULL), ULONG_MAX); + PhInsertEMenuItem(menu, systemItem = PhCreateEMenuItem(0, PH_MODULE_FLAGS_SYSTEM_OPTION, L"Hide system", NULL, NULL), ULONG_MAX); PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX); PhInsertEMenuItem(menu, dotnetItem = PhCreateEMenuItem(0, PH_MODULE_FLAGS_HIGHLIGHT_DOTNET_OPTION, L"Highlight .NET modules", NULL, NULL), ULONG_MAX); PhInsertEMenuItem(menu, immersiveItem = PhCreateEMenuItem(0, PH_MODULE_FLAGS_HIGHLIGHT_IMMERSIVE_OPTION, L"Highlight immersive modules", NULL, NULL), ULONG_MAX); PhInsertEMenuItem(menu, relocatedItem = PhCreateEMenuItem(0, PH_MODULE_FLAGS_HIGHLIGHT_RELOCATED_OPTION, L"Highlight relocated modules", NULL, NULL), ULONG_MAX); PhInsertEMenuItem(menu, untrustedItem = PhCreateEMenuItem(0, PH_MODULE_FLAGS_HIGHLIGHT_UNSIGNED_OPTION, L"Highlight untrusted modules", NULL, NULL), ULONG_MAX); + PhInsertEMenuItem(menu, systemHighlightItem = PhCreateEMenuItem(0, PH_MODULE_FLAGS_HIGHLIGHT_SYSTEM_OPTION, L"Highlight system modules", NULL, NULL), ULONG_MAX); PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX); PhInsertEMenuItem(menu, PhCreateEMenuItem(0, PH_MODULE_FLAGS_LOAD_MODULE_OPTION, L"Load module...", NULL, NULL), ULONG_MAX); //PhInsertEMenuItem(menu, PhCreateEMenuSeparator(), ULONG_MAX); @@ -698,6 +712,8 @@ INT_PTR CALLBACK PhpProcessModulesDlgProc( staticItem->Flags |= PH_EMENU_CHECKED; if (modulesContext->ListContext.HideSignedModules) verifiedItem->Flags |= PH_EMENU_CHECKED; + if (modulesContext->ListContext.HideSystemModules) + systemItem->Flags |= PH_EMENU_CHECKED; if (modulesContext->ListContext.HighlightDotNetModules) dotnetItem->Flags |= PH_EMENU_CHECKED; if (modulesContext->ListContext.HighlightImmersiveModules) @@ -706,6 +722,8 @@ INT_PTR CALLBACK PhpProcessModulesDlgProc( relocatedItem->Flags |= PH_EMENU_CHECKED; if (modulesContext->ListContext.HighlightUntrustedModules) untrustedItem->Flags |= PH_EMENU_CHECKED; + if (modulesContext->ListContext.HighlightSystemModules) + systemHighlightItem->Flags |= PH_EMENU_CHECKED; selectedItem = PhShowEMenu( menu, From cc42cdd298792978535920725bb19a1c8dd4a2cb Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 15 Aug 2019 15:22:41 +1000 Subject: [PATCH 2049/2058] ExtendedTools: Improve stats caching --- plugins/ExtendedTools/exttools.h | 1 + plugins/ExtendedTools/gpumon.c | 22 +++++++++++++++++ plugins/ExtendedTools/gpuprprp.c | 42 +++++++++++++++----------------- plugins/ExtendedTools/main.c | 16 ++++-------- 4 files changed, 48 insertions(+), 33 deletions(-) diff --git a/plugins/ExtendedTools/exttools.h b/plugins/ExtendedTools/exttools.h index 3a77e233ea70..fe6145d91e9c 100644 --- a/plugins/ExtendedTools/exttools.h +++ b/plugins/ExtendedTools/exttools.h @@ -274,6 +274,7 @@ typedef struct _ET_PROCESS_BLOCK ULONG64 GpuDedicatedUsage; ULONG64 GpuSharedUsage; ULONG64 GpuCommitUsage; + ULONG64 GpuContextSwitches; PH_UINT32_DELTA HardFaultsDelta; diff --git a/plugins/ExtendedTools/gpumon.c b/plugins/ExtendedTools/gpumon.c index cda289ee5b3a..59c72100f75b 100644 --- a/plugins/ExtendedTools/gpumon.c +++ b/plugins/ExtendedTools/gpumon.c @@ -738,12 +738,14 @@ VOID EtpUpdateProcessSegmentInformation( D3DKMT_QUERYSTATISTICS queryStatistics; ULONG64 dedicatedUsage; ULONG64 sharedUsage; + ULONG64 commitUsage; if (!Block->ProcessItem->QueryHandle) return; dedicatedUsage = 0; sharedUsage = 0; + commitUsage = 0; for (ULONG i = 0; i < EtpGpuAdapterList->Count; i++) { @@ -774,8 +776,24 @@ VOID EtpUpdateProcessSegmentInformation( } } + for (ULONG i = 0; i < EtpGpuAdapterList->Count; i++) + { + gpuAdapter = EtpGpuAdapterList->Items[i]; + + memset(&queryStatistics, 0, sizeof(D3DKMT_QUERYSTATISTICS)); + queryStatistics.Type = D3DKMT_QUERYSTATISTICS_PROCESS; + queryStatistics.AdapterLuid = gpuAdapter->AdapterLuid; + queryStatistics.ProcessHandle = Block->ProcessItem->QueryHandle; + + if (NT_SUCCESS(D3DKMTQueryStatistics(&queryStatistics))) + { + commitUsage += queryStatistics.QueryResult.ProcessInformation.SystemMemory.BytesAllocated; + } + } + Block->GpuDedicatedUsage = dedicatedUsage; Block->GpuSharedUsage = sharedUsage; + Block->GpuCommitUsage = commitUsage; } VOID EtpUpdateSystemSegmentInformation( @@ -829,11 +847,13 @@ VOID EtpUpdateProcessNodeInformation( PETP_GPU_ADAPTER gpuAdapter; D3DKMT_QUERYSTATISTICS queryStatistics; ULONG64 totalRunningTime; + ULONG64 totalContextSwitches; if (!Block->ProcessItem->QueryHandle) return; totalRunningTime = 0; + totalContextSwitches = 0; for (ULONG i = 0; i < EtpGpuAdapterList->Count; i++) { @@ -854,11 +874,13 @@ VOID EtpUpdateProcessNodeInformation( //PhUpdateDelta(&Block->GpuTotalRunningTimeDelta[j], runningTime); totalRunningTime += queryStatistics.QueryResult.ProcessNodeInformation.RunningTime.QuadPart; + totalContextSwitches += queryStatistics.QueryResult.ProcessNodeInformation.ContextSwitch; } } } PhUpdateDelta(&Block->GpuRunningTimeDelta, totalRunningTime); + Block->GpuContextSwitches = totalContextSwitches; } VOID EtpUpdateSystemNodeInformation( diff --git a/plugins/ExtendedTools/gpuprprp.c b/plugins/ExtendedTools/gpuprprp.c index 57e6baad547b..3d5c98cdb41f 100644 --- a/plugins/ExtendedTools/gpuprprp.c +++ b/plugins/ExtendedTools/gpuprprp.c @@ -57,8 +57,6 @@ typedef struct _ET_GPU_CONTEXT PH_CIRCULAR_BUFFER_ULONG MemoryHistory; PH_CIRCULAR_BUFFER_ULONG MemorySharedHistory; PH_CIRCULAR_BUFFER_ULONG GpuCommittedHistory; - - ET_PROCESS_GPU_STATISTICS GpuStatistics; } ET_GPU_CONTEXT, *PET_GPU_CONTEXT; static RECT NormalGraphTextMargin = { 5, 5, 5, 5 }; @@ -400,27 +398,32 @@ VOID GpuPropUpdatePanel( ) { WCHAR runningTimeString[PH_TIMESPAN_STR_LEN_1] = L"N/A"; + ET_PROCESS_GPU_STATISTICS processGpuStatistics; - PhPrintTimeSpan(runningTimeString, Context->GpuStatistics.RunningTime * 10, PH_TIMESPAN_HMSM); + if (Context->Block->ProcessItem->QueryHandle) + EtQueryProcessGpuStatistics(Context->Block->ProcessItem->QueryHandle, &processGpuStatistics); + else + memset(&processGpuStatistics, 0, sizeof(ET_PROCESS_GPU_STATISTICS)); + PhPrintTimeSpan(runningTimeString, processGpuStatistics.RunningTime * 10, PH_TIMESPAN_HMSM); PhSetDialogItemText(Context->PanelHandle, IDC_ZRUNNINGTIME_V, runningTimeString); - PhSetDialogItemText(Context->PanelHandle, IDC_ZCONTEXTSWITCHES_V, PhaFormatUInt64(Context->GpuStatistics.ContextSwitches, TRUE)->Buffer); - PhSetDialogItemText(Context->PanelHandle, IDC_ZTOTALNODES_V, PhaFormatUInt64(Context->GpuStatistics.NodeCount, TRUE)->Buffer); - PhSetDialogItemText(Context->PanelHandle, IDC_ZTOTALSEGMENTS_V, PhaFormatUInt64(Context->GpuStatistics.SegmentCount, TRUE)->Buffer); + PhSetDialogItemText(Context->PanelHandle, IDC_ZCONTEXTSWITCHES_V, PhaFormatUInt64(processGpuStatistics.ContextSwitches, TRUE)->Buffer); + PhSetDialogItemText(Context->PanelHandle, IDC_ZTOTALNODES_V, PhaFormatUInt64(processGpuStatistics.NodeCount, TRUE)->Buffer); + PhSetDialogItemText(Context->PanelHandle, IDC_ZTOTALSEGMENTS_V, PhaFormatUInt64(processGpuStatistics.SegmentCount, TRUE)->Buffer); if (Context->DetailsHandle) { // Note: no lock is needed because we only ever update the 'details' dialog text on this same thread. - PhSetDialogItemText(Context->DetailsHandle, IDC_ZDEDICATEDCOMMITTED_V, PhaFormatSize(Context->GpuStatistics.DedicatedCommitted, ULONG_MAX)->Buffer); - PhSetDialogItemText(Context->DetailsHandle, IDC_ZSHAREDCOMMITTED_V, PhaFormatSize(Context->GpuStatistics.SharedCommitted, ULONG_MAX)->Buffer); - PhSetDialogItemText(Context->DetailsHandle, IDC_ZTOTALALLOCATED_V, PhaFormatSize(Context->GpuStatistics.BytesAllocated, ULONG_MAX)->Buffer); - PhSetDialogItemText(Context->DetailsHandle, IDC_ZTOTALRESERVED_V, PhaFormatSize(Context->GpuStatistics.BytesReserved, ULONG_MAX)->Buffer); - PhSetDialogItemText(Context->DetailsHandle, IDC_ZWRITECOMBINEDALLOCATED_V, PhaFormatSize(Context->GpuStatistics.WriteCombinedBytesAllocated, ULONG_MAX)->Buffer); - PhSetDialogItemText(Context->DetailsHandle, IDC_ZWRITECOMBINEDRESERVED_V, PhaFormatSize(Context->GpuStatistics.WriteCombinedBytesReserved, ULONG_MAX)->Buffer); - PhSetDialogItemText(Context->DetailsHandle, IDC_ZCACHEDALLOCATED_V, PhaFormatSize(Context->GpuStatistics.CachedBytesAllocated, ULONG_MAX)->Buffer); - PhSetDialogItemText(Context->DetailsHandle, IDC_ZCACHEDRESERVED_V, PhaFormatSize(Context->GpuStatistics.CachedBytesReserved, ULONG_MAX)->Buffer); - PhSetDialogItemText(Context->DetailsHandle, IDC_ZSECTIONALLOCATED_V, PhaFormatSize(Context->GpuStatistics.SectionBytesAllocated, ULONG_MAX)->Buffer); - PhSetDialogItemText(Context->DetailsHandle, IDC_ZSECTIONRESERVED_V, PhaFormatSize(Context->GpuStatistics.SectionBytesReserved, ULONG_MAX)->Buffer); + PhSetDialogItemText(Context->DetailsHandle, IDC_ZDEDICATEDCOMMITTED_V, PhaFormatSize(processGpuStatistics.DedicatedCommitted, ULONG_MAX)->Buffer); + PhSetDialogItemText(Context->DetailsHandle, IDC_ZSHAREDCOMMITTED_V, PhaFormatSize(processGpuStatistics.SharedCommitted, ULONG_MAX)->Buffer); + PhSetDialogItemText(Context->DetailsHandle, IDC_ZTOTALALLOCATED_V, PhaFormatSize(processGpuStatistics.BytesAllocated, ULONG_MAX)->Buffer); + PhSetDialogItemText(Context->DetailsHandle, IDC_ZTOTALRESERVED_V, PhaFormatSize(processGpuStatistics.BytesReserved, ULONG_MAX)->Buffer); + PhSetDialogItemText(Context->DetailsHandle, IDC_ZWRITECOMBINEDALLOCATED_V, PhaFormatSize(processGpuStatistics.WriteCombinedBytesAllocated, ULONG_MAX)->Buffer); + PhSetDialogItemText(Context->DetailsHandle, IDC_ZWRITECOMBINEDRESERVED_V, PhaFormatSize(processGpuStatistics.WriteCombinedBytesReserved, ULONG_MAX)->Buffer); + PhSetDialogItemText(Context->DetailsHandle, IDC_ZCACHEDALLOCATED_V, PhaFormatSize(processGpuStatistics.CachedBytesAllocated, ULONG_MAX)->Buffer); + PhSetDialogItemText(Context->DetailsHandle, IDC_ZCACHEDRESERVED_V, PhaFormatSize(processGpuStatistics.CachedBytesReserved, ULONG_MAX)->Buffer); + PhSetDialogItemText(Context->DetailsHandle, IDC_ZSECTIONALLOCATED_V, PhaFormatSize(processGpuStatistics.SectionBytesAllocated, ULONG_MAX)->Buffer); + PhSetDialogItemText(Context->DetailsHandle, IDC_ZSECTIONRESERVED_V, PhaFormatSize(processGpuStatistics.SectionBytesReserved, ULONG_MAX)->Buffer); } } @@ -430,15 +433,10 @@ VOID GpuPropUpdateInfo( { PET_PROCESS_BLOCK block = Context->Block; - if (Context->Block->ProcessItem->QueryHandle) - EtQueryProcessGpuStatistics(Context->Block->ProcessItem->QueryHandle, &Context->GpuStatistics); - else - memset(&Context->GpuStatistics, 0, sizeof(ET_PROCESS_GPU_STATISTICS)); - Context->CurrentGpuUsage = block->GpuNodeUsage; Context->CurrentMemUsage = (ULONG)(block->GpuDedicatedUsage / PAGE_SIZE); Context->CurrentMemSharedUsage = (ULONG)(block->GpuSharedUsage / PAGE_SIZE); - Context->CurrentCommitUsage = (ULONG)(Context->GpuStatistics.BytesAllocated / PAGE_SIZE); // HACK HACK HACK + Context->CurrentCommitUsage = (ULONG)(block->GpuCommitUsage / PAGE_SIZE); PhAddItemCircularBuffer_FLOAT(&Context->GpuHistory, Context->CurrentGpuUsage); PhAddItemCircularBuffer_ULONG(&Context->MemoryHistory, Context->CurrentMemUsage); diff --git a/plugins/ExtendedTools/main.c b/plugins/ExtendedTools/main.c index 994b6dd216b9..9442acb41e0a 100644 --- a/plugins/ExtendedTools/main.c +++ b/plugins/ExtendedTools/main.c @@ -463,32 +463,26 @@ VOID NTAPI ProcessStatsEventCallback( { HWND listViewHandle = event->Parameter; PET_PROCESS_BLOCK block; - ET_PROCESS_GPU_STATISTICS gpuStatistics; WCHAR runningTimeString[PH_TIMESPAN_STR_LEN_1] = L"N/A"; if (!(block = EtGetProcessBlock(event->ProcessItem))) break; - if (block->ProcessItem->QueryHandle) - EtQueryProcessGpuStatistics(block->ProcessItem->QueryHandle, &gpuStatistics); - else - memset(&gpuStatistics, 0, sizeof(ET_PROCESS_GPU_STATISTICS)); - - PhPrintTimeSpan(runningTimeString, gpuStatistics.RunningTime * 10, PH_TIMESPAN_HMSM); + PhPrintTimeSpan(runningTimeString, block->GpuRunningTimeDelta.Value * 10, PH_TIMESPAN_HMSM); PhSetListViewSubItem(listViewHandle, block->ListViewRowCache[ET_PROCESS_STATISTICS_INDEX_RUNNINGTIME], 1, runningTimeString); PhSetListViewSubItem(listViewHandle, block->ListViewRowCache[ET_PROCESS_STATISTICS_INDEX_CONTEXTSWITCHES], 1, - PhaFormatUInt64(gpuStatistics.ContextSwitches, TRUE)->Buffer); + PhaFormatUInt64(block->GpuContextSwitches, TRUE)->Buffer); //PhSetListViewSubItem(listViewHandle, block->ListViewRowCache[ET_PROCESS_STATISTICS_INDEX_TOTALNODES], 1, // PhaFormatUInt64(gpuStatistics.NodeCount, TRUE)->Buffer); //PhSetListViewSubItem(listViewHandle, block->ListViewRowCache[ET_PROCESS_STATISTICS_INDEX_TOTALSEGMENTS], 1, // PhaFormatUInt64(gpuStatistics.SegmentCount, TRUE)->Buffer); PhSetListViewSubItem(listViewHandle, block->ListViewRowCache[ET_PROCESS_STATISTICS_INDEX_TOTALDEDICATED], 1, - PhaFormatSize(gpuStatistics.DedicatedCommitted, ULONG_MAX)->Buffer); + PhaFormatSize(block->GpuDedicatedUsage, ULONG_MAX)->Buffer); PhSetListViewSubItem(listViewHandle, block->ListViewRowCache[ET_PROCESS_STATISTICS_INDEX_TOTALSHARED], 1, - PhaFormatSize(gpuStatistics.SharedCommitted, ULONG_MAX)->Buffer); + PhaFormatSize(block->GpuSharedUsage, ULONG_MAX)->Buffer); PhSetListViewSubItem(listViewHandle, block->ListViewRowCache[ET_PROCESS_STATISTICS_INDEX_TOTALCOMMIT], 1, - PhaFormatSize(gpuStatistics.BytesAllocated, ULONG_MAX)->Buffer); + PhaFormatSize(block->GpuCommitUsage, ULONG_MAX)->Buffer); PhSetListViewSubItem(listViewHandle, block->ListViewRowCache[ET_PROCESS_STATISTICS_INDEX_DISKREADS], 1, PhaFormatUInt64(block->DiskReadCount, TRUE)->Buffer); From 90d8340d65be46e964e80cd2ccf79f84cec10517 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 15 Aug 2019 15:47:26 +1000 Subject: [PATCH 2050/2058] ExtendedTools: Improve stats caching --- plugins/ExtendedTools/exttools.h | 2 ++ plugins/ExtendedTools/gpumon.c | 10 ++++++++++ plugins/ExtendedTools/gpuprprp.c | 23 ++++++++++++----------- 3 files changed, 24 insertions(+), 11 deletions(-) diff --git a/plugins/ExtendedTools/exttools.h b/plugins/ExtendedTools/exttools.h index fe6145d91e9c..a62bc84b1d96 100644 --- a/plugins/ExtendedTools/exttools.h +++ b/plugins/ExtendedTools/exttools.h @@ -270,6 +270,8 @@ typedef struct _ET_PROCESS_BLOCK //PPH_UINT64_DELTA GpuTotalRunningTimeDelta; //PPH_CIRCULAR_BUFFER_FLOAT GpuTotalNodesHistory; + ULONG GpuNodeCount; + ULONG GpuSegmentCount; FLOAT GpuNodeUsage; ULONG64 GpuDedicatedUsage; ULONG64 GpuSharedUsage; diff --git a/plugins/ExtendedTools/gpumon.c b/plugins/ExtendedTools/gpumon.c index 59c72100f75b..95743c4cc419 100644 --- a/plugins/ExtendedTools/gpumon.c +++ b/plugins/ExtendedTools/gpumon.c @@ -739,6 +739,7 @@ VOID EtpUpdateProcessSegmentInformation( ULONG64 dedicatedUsage; ULONG64 sharedUsage; ULONG64 commitUsage; + ULONG segmentCount; if (!Block->ProcessItem->QueryHandle) return; @@ -746,6 +747,7 @@ VOID EtpUpdateProcessSegmentInformation( dedicatedUsage = 0; sharedUsage = 0; commitUsage = 0; + segmentCount = 0; for (ULONG i = 0; i < EtpGpuAdapterList->Count; i++) { @@ -773,6 +775,8 @@ VOID EtpUpdateProcessSegmentInformation( else dedicatedUsage += bytesCommitted; } + + segmentCount++; } } @@ -794,6 +798,7 @@ VOID EtpUpdateProcessSegmentInformation( Block->GpuDedicatedUsage = dedicatedUsage; Block->GpuSharedUsage = sharedUsage; Block->GpuCommitUsage = commitUsage; + Block->GpuSegmentCount = segmentCount; } VOID EtpUpdateSystemSegmentInformation( @@ -848,12 +853,14 @@ VOID EtpUpdateProcessNodeInformation( D3DKMT_QUERYSTATISTICS queryStatistics; ULONG64 totalRunningTime; ULONG64 totalContextSwitches; + ULONG totalNodes; if (!Block->ProcessItem->QueryHandle) return; totalRunningTime = 0; totalContextSwitches = 0; + totalNodes = 0; for (ULONG i = 0; i < EtpGpuAdapterList->Count; i++) { @@ -876,11 +883,14 @@ VOID EtpUpdateProcessNodeInformation( totalRunningTime += queryStatistics.QueryResult.ProcessNodeInformation.RunningTime.QuadPart; totalContextSwitches += queryStatistics.QueryResult.ProcessNodeInformation.ContextSwitch; } + + totalNodes++; } } PhUpdateDelta(&Block->GpuRunningTimeDelta, totalRunningTime); Block->GpuContextSwitches = totalContextSwitches; + Block->GpuNodeCount = totalNodes; } VOID EtpUpdateSystemNodeInformation( diff --git a/plugins/ExtendedTools/gpuprprp.c b/plugins/ExtendedTools/gpuprprp.c index 3d5c98cdb41f..d617bb7e6aa3 100644 --- a/plugins/ExtendedTools/gpuprprp.c +++ b/plugins/ExtendedTools/gpuprprp.c @@ -397,23 +397,24 @@ VOID GpuPropUpdatePanel( _Inout_ PET_GPU_CONTEXT Context ) { + PET_PROCESS_BLOCK block = Context->Block; WCHAR runningTimeString[PH_TIMESPAN_STR_LEN_1] = L"N/A"; - ET_PROCESS_GPU_STATISTICS processGpuStatistics; - - if (Context->Block->ProcessItem->QueryHandle) - EtQueryProcessGpuStatistics(Context->Block->ProcessItem->QueryHandle, &processGpuStatistics); - else - memset(&processGpuStatistics, 0, sizeof(ET_PROCESS_GPU_STATISTICS)); - PhPrintTimeSpan(runningTimeString, processGpuStatistics.RunningTime * 10, PH_TIMESPAN_HMSM); + PhPrintTimeSpan(runningTimeString, block->GpuRunningTimeDelta.Value * 10, PH_TIMESPAN_HMSM); PhSetDialogItemText(Context->PanelHandle, IDC_ZRUNNINGTIME_V, runningTimeString); - PhSetDialogItemText(Context->PanelHandle, IDC_ZCONTEXTSWITCHES_V, PhaFormatUInt64(processGpuStatistics.ContextSwitches, TRUE)->Buffer); - PhSetDialogItemText(Context->PanelHandle, IDC_ZTOTALNODES_V, PhaFormatUInt64(processGpuStatistics.NodeCount, TRUE)->Buffer); - PhSetDialogItemText(Context->PanelHandle, IDC_ZTOTALSEGMENTS_V, PhaFormatUInt64(processGpuStatistics.SegmentCount, TRUE)->Buffer); + PhSetDialogItemText(Context->PanelHandle, IDC_ZCONTEXTSWITCHES_V, PhaFormatUInt64(block->GpuContextSwitches, TRUE)->Buffer); + PhSetDialogItemText(Context->PanelHandle, IDC_ZTOTALNODES_V, PhaFormatUInt64(block->GpuNodeCount, TRUE)->Buffer); + PhSetDialogItemText(Context->PanelHandle, IDC_ZTOTALSEGMENTS_V, PhaFormatUInt64(block->GpuSegmentCount, TRUE)->Buffer); if (Context->DetailsHandle) { - // Note: no lock is needed because we only ever update the 'details' dialog text on this same thread. + ET_PROCESS_GPU_STATISTICS processGpuStatistics; + + if (Context->Block->ProcessItem->QueryHandle) + EtQueryProcessGpuStatistics(Context->Block->ProcessItem->QueryHandle, &processGpuStatistics); + else + memset(&processGpuStatistics, 0, sizeof(ET_PROCESS_GPU_STATISTICS)); + PhSetDialogItemText(Context->DetailsHandle, IDC_ZDEDICATEDCOMMITTED_V, PhaFormatSize(processGpuStatistics.DedicatedCommitted, ULONG_MAX)->Buffer); PhSetDialogItemText(Context->DetailsHandle, IDC_ZSHAREDCOMMITTED_V, PhaFormatSize(processGpuStatistics.SharedCommitted, ULONG_MAX)->Buffer); PhSetDialogItemText(Context->DetailsHandle, IDC_ZTOTALALLOCATED_V, PhaFormatSize(processGpuStatistics.BytesAllocated, ULONG_MAX)->Buffer); From 7717c61f4f4929a209b858014611a4b78b74c02b Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 15 Aug 2019 21:06:39 +1000 Subject: [PATCH 2051/2058] Add PhGetGlobalTimerQueue --- ProcessHacker/ProcessHacker.def | 1 + phlib/guisup.c | 17 +++++++++++++++++ phlib/include/guisup.h | 7 +++++++ 3 files changed, 25 insertions(+) diff --git a/ProcessHacker/ProcessHacker.def b/ProcessHacker/ProcessHacker.def index 4f928d5cc488..820c7f55006c 100644 --- a/ProcessHacker/ProcessHacker.def +++ b/ProcessHacker/ProcessHacker.def @@ -538,6 +538,7 @@ EXPORTS PhInitializeWindowTheme PhReInitializeWindowTheme PhInitializeWindowThemeStatusBar + PhGetGlobalTimerQueue ; hndlinfo PhEnumObjectTypes diff --git a/phlib/guisup.c b/phlib/guisup.c index 7b69669bc065..740cc4d6c6da 100644 --- a/phlib/guisup.c +++ b/phlib/guisup.c @@ -1696,3 +1696,20 @@ HICON PhGetInternalWindowIcon( return InternalGetWindowIcon_I(WindowHandle, Type); } + +HANDLE PhGetGlobalTimerQueue( + VOID + ) +{ + static HANDLE PhTimerQueueHandle = NULL; + static PH_INITONCE PhTimerQueueHandleInitOnce = PH_INITONCE_INIT; + + if (PhBeginInitOnce(&PhTimerQueueHandleInitOnce)) + { + RtlCreateTimerQueue(&PhTimerQueueHandle); + + PhEndInitOnce(&PhTimerQueueHandleInitOnce); + } + + return PhTimerQueueHandle; +} diff --git a/phlib/include/guisup.h b/phlib/include/guisup.h index bfea5fe03086..fab1134fe434 100644 --- a/phlib/include/guisup.h +++ b/phlib/include/guisup.h @@ -893,6 +893,13 @@ PhWindowNotifyTopMostEvent( _In_ BOOLEAN TopMost ); +PHLIBAPI +HANDLE +NTAPI +PhGetGlobalTimerQueue( + VOID + ); + // theme support (theme.c) PHLIBAPI extern HFONT PhApplicationFont; // phapppub From 6132276aa193758830d0807a0e627c3c52aa451f Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 15 Aug 2019 21:09:29 +1000 Subject: [PATCH 2052/2058] Remove unused handles --- ProcessHacker/findobj.c | 36 +++++++++++++----------------------- tools/peview/pdbprp.c | 39 ++++++++++++--------------------------- 2 files changed, 25 insertions(+), 50 deletions(-) diff --git a/ProcessHacker/findobj.c b/ProcessHacker/findobj.c index b3570f40789d..50311eee5b28 100644 --- a/ProcessHacker/findobj.c +++ b/ProcessHacker/findobj.c @@ -62,7 +62,6 @@ typedef struct _PH_HANDLE_SEARCH_CONTEXT PPH_HASHTABLE NodeHashtable; PPH_LIST NodeList; - HANDLE TimerQueueHandle; HANDLE UpdateTimerHandle; HANDLE SearchThreadHandle; @@ -761,14 +760,14 @@ VOID CALLBACK PhpFindObjectTreeUpdateCallback( { if (!Context->SearchThreadHandle) { - RtlUpdateTimer(Context->TimerQueueHandle, Context->UpdateTimerHandle, 1000, INFINITE); + RtlUpdateTimer(PhGetGlobalTimerQueue(), Context->UpdateTimerHandle, 1000, INFINITE); return; } // Update the search results. PhpFindObjectAddResultEntries(Context); - RtlUpdateTimer(Context->TimerQueueHandle, Context->UpdateTimerHandle, 1000, INFINITE); + RtlUpdateTimer(PhGetGlobalTimerQueue(), Context->UpdateTimerHandle, 1000, INFINITE); } static BOOLEAN MatchSearchString( @@ -1179,18 +1178,15 @@ INT_PTR CALLBACK PhpFindObjectsDlgProc( context->SearchResults = PhCreateList(128); context->SearchResultsAddIndex = 0; - if (NT_SUCCESS(RtlCreateTimerQueue(&context->TimerQueueHandle))) - { - RtlCreateTimer( - context->TimerQueueHandle, - &context->UpdateTimerHandle, - PhpFindObjectTreeUpdateCallback, - context, - 0, - 1000, - 0 - ); - } + RtlCreateTimer( + PhGetGlobalTimerQueue(), + &context->UpdateTimerHandle, + PhpFindObjectTreeUpdateCallback, + context, + 0, + 1000, + 0 + ); Edit_SetSel(context->SearchWindowHandle, 0, -1); Button_SetCheck(GetDlgItem(hwndDlg, IDC_REGEX), PhGetIntegerSetting(L"FindObjRegex") ? BST_CHECKED : BST_UNCHECKED); @@ -1204,14 +1200,8 @@ INT_PTR CALLBACK PhpFindObjectsDlgProc( if (context->UpdateTimerHandle) { - RtlDeleteTimer(context->TimerQueueHandle, context->UpdateTimerHandle, NULL); - context->TimerQueueHandle = NULL; - } - - if (context->TimerQueueHandle) - { - RtlDeleteTimerQueue(context->TimerQueueHandle); - context->TimerQueueHandle = NULL; + RtlDeleteTimer(PhGetGlobalTimerQueue(), context->UpdateTimerHandle, NULL); + context->UpdateTimerHandle = NULL; } if (context->SearchThreadHandle) diff --git a/tools/peview/pdbprp.c b/tools/peview/pdbprp.c index c86f32c99fbe..328514e32675 100644 --- a/tools/peview/pdbprp.c +++ b/tools/peview/pdbprp.c @@ -1058,7 +1058,7 @@ VOID CALLBACK PvSymbolTreeUpdateCallback( TreeNew_NodesStructured(Context->TreeNewHandle); TreeNew_SetRedraw(Context->TreeNewHandle, TRUE); - RtlUpdateTimer(Context->TimerQueueHandle, Context->UpdateTimerHandle, 1000, INFINITE); + RtlUpdateTimer(PhGetGlobalTimerQueue(), Context->UpdateTimerHandle, 1000, INFINITE); } INT_PTR CALLBACK PvpSymbolsDlgProc( @@ -1105,18 +1105,15 @@ INT_PTR CALLBACK PvpSymbolsDlgProc( PhCreateThread2(PeDumpFileSymbols, context); - if (NT_SUCCESS(RtlCreateTimerQueue(&context->TimerQueueHandle))) - { - RtlCreateTimer( - context->TimerQueueHandle, - &context->UpdateTimerHandle, - PvSymbolTreeUpdateCallback, - context, - 0, - 1000, - 0 - ); - } + RtlCreateTimer( + PhGetGlobalTimerQueue(), + &context->UpdateTimerHandle, + PvSymbolTreeUpdateCallback, + context, + 0, + 1000, + 0 + ); EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); } @@ -1125,16 +1122,10 @@ INT_PTR CALLBACK PvpSymbolsDlgProc( { if (context->UpdateTimerHandle) { - RtlDeleteTimer(context->TimerQueueHandle, context->UpdateTimerHandle, NULL); + RtlDeleteTimer(PhGetGlobalTimerQueue(), context->UpdateTimerHandle, NULL); context->UpdateTimerHandle = NULL; } - if (context->TimerQueueHandle) - { - RtlDeleteTimerQueue(context->TimerQueueHandle); - context->TimerQueueHandle = NULL; - } - PvDeleteSymbolTree(context); } break; @@ -1193,15 +1184,9 @@ INT_PTR CALLBACK PvpSymbolsDlgProc( //if (context->UpdateTimerHandle) //{ - // RtlDeleteTimer(context->TimerQueueHandle, context->UpdateTimerHandle, NULL); + // RtlDeleteTimer(PhGetGlobalTimerQueue(), context->UpdateTimerHandle, NULL); // context->UpdateTimerHandle = NULL; //} - - //if (context->TimerQueueHandle) - //{ - // RtlDeleteTimerQueue(context->TimerQueueHandle); - // context->TimerQueueHandle = NULL; - //} } break; case WM_PV_SEARCH_SHOWMENU: From 38ee30dac99806d0feef76cabb77b36d568fa798 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 15 Aug 2019 21:12:32 +1000 Subject: [PATCH 2053/2058] Remove PhGetFileShellIcon --- ProcessHacker/chproc.c | 15 ++++++++++++--- ProcessHacker/procrec.c | 24 +++++++++++++++++++----- 2 files changed, 31 insertions(+), 8 deletions(-) diff --git a/ProcessHacker/chproc.c b/ProcessHacker/chproc.c index 73c96962c15c..de817e5c6c91 100644 --- a/ProcessHacker/chproc.c +++ b/ProcessHacker/chproc.c @@ -102,7 +102,7 @@ static VOID PhpRefreshProcessList( HICON icon = NULL; WCHAR processIdString[PH_INT32_STR_LEN_1]; PPH_STRING userName = NULL; - INT imageIndex; + INT imageIndex = INT_MAX; if (process->UniqueProcessId != SYSTEM_IDLE_PROCESS_ID) name = PhCreateStringFromUnicodeString(&process->ImageName); @@ -144,15 +144,24 @@ static VOID PhpRefreshProcessList( if (fileName) PhMoveReference(&fileName, PhGetFileName(fileName)); - icon = PhGetFileShellIcon(PhGetString(fileName), L".exe", FALSE); - // Icon + if (!PhIsNullOrEmptyString(fileName)) + { + PhExtractIcon(PhGetString(fileName), NULL, &icon); + } + if (icon) { imageIndex = ImageList_AddIcon(Context->ImageList, icon); PhSetListViewItemImageIndex(Context->ListViewHandle, lvItemIndex, imageIndex); DestroyIcon(icon); } + else + { + PhGetStockApplicationIcon(NULL, &icon); + imageIndex = ImageList_AddIcon(Context->ImageList, icon); + PhSetListViewItemImageIndex(Context->ListViewHandle, lvItemIndex, imageIndex); + } // PID PhPrintUInt32(processIdString, HandleToUlong(process->UniqueProcessId)); diff --git a/ProcessHacker/procrec.c b/ProcessHacker/procrec.c index 534ea05decc1..4a2a2cc093db 100644 --- a/ProcessHacker/procrec.c +++ b/ProcessHacker/procrec.c @@ -77,7 +77,7 @@ PPH_STRING PhpaGetRelativeTimeString( } FORCEINLINE PWSTR PhpGetStringOrNa( - _In_ PPH_STRING String + _In_ _Maybenull_ PPH_STRING String ) { if (String) @@ -175,17 +175,31 @@ INT_PTR CALLBACK PhpProcessRecordDlgProc( if (context->Record->FileName) { + PhExtractIcon( + context->Record->FileName->Buffer, + &context->FileIcon, + NULL + ); + if (PhInitializeImageVersionInfo(&versionInfo, context->Record->FileName->Buffer)) versionInfoInitialized = TRUE; } - context->FileIcon = PhGetFileShellIcon(PhGetString(context->Record->FileName), L".exe", TRUE); + if (context->FileIcon) + { + SendMessage(GetDlgItem(hwndDlg, IDC_FILEICON), STM_SETICON, (WPARAM)context->FileIcon, 0); + } + else + { + HICON largeIcon; + + PhGetStockApplicationIcon(NULL, &largeIcon); + SendMessage(GetDlgItem(hwndDlg, IDC_FILEICON), STM_SETICON, (WPARAM)largeIcon, 0); + } SendMessage(GetDlgItem(hwndDlg, IDC_OPENFILENAME), BM_SETIMAGE, IMAGE_ICON, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhInstanceHandle, MAKEINTRESOURCE(IDI_FOLDER))); - SendMessage(GetDlgItem(hwndDlg, IDC_FILEICON), STM_SETICON, - (WPARAM)context->FileIcon, 0); - + PhSetDialogItemText(hwndDlg, IDC_NAME, PhpGetStringOrNa(versionInfo.FileDescription)); PhSetDialogItemText(hwndDlg, IDC_COMPANYNAME, PhpGetStringOrNa(versionInfo.CompanyName)); PhSetDialogItemText(hwndDlg, IDC_VERSION, PhpGetStringOrNa(versionInfo.FileVersion)); From 8dc37766a7505d911066d1c75bbb8fc8f0d9a0cf Mon Sep 17 00:00:00 2001 From: Andrew Boyarshin Date: Sun, 18 Aug 2019 08:38:22 +0700 Subject: [PATCH 2054/2058] Implement PhEnumerateSymbols as front-end for SymEnumSymbolsW (#457) --- phlib/include/symprv.h | 32 +++++++++++++++ phlib/symprv.c | 90 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 122 insertions(+) diff --git a/phlib/include/symprv.h b/phlib/include/symprv.h index 302abe97562a..9970de6a583d 100644 --- a/phlib/include/symprv.h +++ b/phlib/include/symprv.h @@ -287,6 +287,38 @@ PhUndecorateSymbolName( _In_ PWSTR DecoratedName ); +typedef struct _PH_SYMBOL_INFO { + PH_STRINGREF Name; + ULONG TypeIndex; // Type Index of symbol + ULONG Index; + ULONG Size; + ULONG64 ModBase; // Base Address of module comtaining this symbol + ULONG Flags; + ULONG64 Value; // Value of symbol, ValuePresent should be 1 + ULONG64 Address; // Address of symbol including base address of module + ULONG Register; // register holding value or pointer to value + ULONG Scope; // scope of the symbol + ULONG Tag; // pdb classification +} PH_SYMBOL_INFO, *PPH_SYMBOL_INFO; + +typedef BOOLEAN (NTAPI* PPH_ENUMERATE_SYMBOLS_CALLBACK)( + _In_ PPH_SYMBOL_INFO pSymInfo, + _In_ ULONG SymbolSize, + _In_opt_ PVOID UserContext + ); + +PHLIBAPI +BOOLEAN +NTAPI +PhEnumerateSymbols( + _In_ PPH_SYMBOL_PROVIDER SymbolProvider, + _In_ HANDLE ProcessHandle, + _In_ ULONG64 BaseOfDll, + _In_opt_ PCWSTR Mask, + _In_ PPH_ENUMERATE_SYMBOLS_CALLBACK EnumSymbolsCallback, + _In_opt_ const PVOID UserContext + ); + #ifdef __cplusplus } #endif diff --git a/phlib/symprv.c b/phlib/symprv.c index 14253d8e8470..bf4181a53e24 100644 --- a/phlib/symprv.c +++ b/phlib/symprv.c @@ -1687,3 +1687,93 @@ PPH_STRING PhUndecorateSymbolName( return undecoratedSymbolName; } + +typedef struct _PH_ENUMERATE_SYMBOLS_CONTEXT +{ + PVOID UserContext; + PPH_ENUMERATE_SYMBOLS_CALLBACK UserCallback; +} PH_ENUMERATE_SYMBOLS_CONTEXT, *PPH_ENUMERATE_SYMBOLS_CONTEXT; + +BOOL +CALLBACK +PhEnumerateSymbolsCallback( + _In_ PSYMBOL_INFOW pSymInfo, + _In_ ULONG SymbolSize, + _In_ PVOID Context + ) +{ + PPH_ENUMERATE_SYMBOLS_CONTEXT phContext = (PPH_ENUMERATE_SYMBOLS_CONTEXT)Context; + BOOLEAN result; + PH_SYMBOL_INFO symbolInfo = { 0 }; + + if (pSymInfo->MaxNameLen) + { + SIZE_T SuggestedLength; + + symbolInfo.Name.Buffer = pSymInfo->Name; + symbolInfo.Name.Length = min(pSymInfo->NameLen, pSymInfo->MaxNameLen - 1) * sizeof(WCHAR); + + // NameLen is unreliable, might be greater that expected + + SuggestedLength = PhCountStringZ(symbolInfo.Name.Buffer) * sizeof(WCHAR); + symbolInfo.Name.Length = min(symbolInfo.Name.Length, SuggestedLength); + } + else + { + PhInitializeEmptyStringRef(&symbolInfo.Name); + } + + symbolInfo.TypeIndex = pSymInfo->TypeIndex; + symbolInfo.Index = pSymInfo->Index; + symbolInfo.Size = pSymInfo->Size; + symbolInfo.ModBase = pSymInfo->ModBase; + symbolInfo.Flags = pSymInfo->Flags; + symbolInfo.Value = pSymInfo->Value; + symbolInfo.Address = pSymInfo->Address; + symbolInfo.Register = pSymInfo->Register; + symbolInfo.Scope = pSymInfo->Scope; + symbolInfo.Tag = pSymInfo->Tag; + + result = phContext->UserCallback(&symbolInfo, SymbolSize, phContext->UserContext); + + return (BOOL)result; +} + +BOOLEAN PhEnumerateSymbols( + _In_ PPH_SYMBOL_PROVIDER SymbolProvider, + _In_ HANDLE ProcessHandle, + _In_ ULONG64 BaseOfDll, + _In_opt_ PCWSTR Mask, + _In_ PPH_ENUMERATE_SYMBOLS_CALLBACK EnumSymbolsCallback, + _In_opt_ const PVOID UserContext + ) +{ + BOOLEAN result; + + PhpRegisterSymbolProvider(SymbolProvider); + + if (!SymEnumSymbolsW_I) + { + SetLastError(ERROR_PROC_NOT_FOUND); + return FALSE; + } + + PH_ENUMERATE_SYMBOLS_CONTEXT Context = { 0 }; + Context.UserContext = UserContext; + Context.UserCallback = EnumSymbolsCallback; + + PH_LOCK_SYMBOLS(); + + result = SymEnumSymbolsW_I( + ProcessHandle, + BaseOfDll, + Mask, + PhEnumerateSymbolsCallback, + &Context + ); + + PH_UNLOCK_SYMBOLS(); + + return result; +} + From 707287a0ddd1ed2d0f8c94578036f1672dd695b6 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 18 Aug 2019 22:17:48 +1000 Subject: [PATCH 2055/2058] peview: Add properties link to imports tab --- tools/peview/impprp.c | 14 ++++++++++---- tools/peview/include/peview.h | 2 -- tools/peview/main.c | 8 +++++--- 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/tools/peview/impprp.c b/tools/peview/impprp.c index 006d1388d3eb..435260d53225 100644 --- a/tools/peview/impprp.c +++ b/tools/peview/impprp.c @@ -135,14 +135,14 @@ INT PvpAddListViewGroup( memset(&group, 0, sizeof(LVGROUP)); group.cbSize = sizeof(LVGROUP); - group.mask = LVGF_HEADER | LVGF_ALIGN | LVGF_STATE | LVGF_GROUPID;// | LVGF_TASK; + group.mask = LVGF_HEADER | LVGF_ALIGN | LVGF_STATE | LVGF_GROUPID | LVGF_TASK; group.uAlign = LVGA_HEADER_LEFT; group.state = LVGS_COLLAPSIBLE; group.iGroupId = (INT)ListView_GetGroupCount(ListViewHandle); group.pszHeader = Text; - //group.pszTask = L"Properties"; + group.pszTask = L"Properties"; - return (INT)ListView_InsertGroup(ListViewHandle, MAXINT, &group); + return (INT)ListView_InsertGroup(ListViewHandle, group.iGroupId, &group); } BOOLEAN PvpCheckGroupExists( @@ -254,7 +254,7 @@ VOID PvpProcessImports( } PhPrintUInt32(number, ++(*Count)); // HACK - lvItemIndex = PhAddListViewGroupItem(ListViewHandle, groupId, MAXINT, number, NULL); // PhAddListViewItem(ListViewHandle, MAXINT, number, NULL); + lvItemIndex = PhAddListViewGroupItem(ListViewHandle, groupId, MAXINT, number, NULL); PhSetListViewSubItem(ListViewHandle, lvItemIndex, 1, name->Buffer); PhDereferenceObject(name); @@ -351,6 +351,7 @@ INT_PTR CALLBACK PvpPeImportsDlgProc( ExtendedListView_AddFallbackColumns(lvHandle, 3, fallbackColumns); PhLoadListViewColumnsFromSetting(L"ImageImportsListViewColumns", lvHandle); + ExtendedListView_SetRedraw(lvHandle, FALSE); ListView_EnableGroupView(lvHandle, TRUE); if (NT_SUCCESS(PhGetMappedImageImports(&imports, &PvMappedImage))) @@ -364,6 +365,7 @@ INT_PTR CALLBACK PvpPeImportsDlgProc( } ExtendedListView_SortItems(lvHandle); + ExtendedListView_SetRedraw(lvHandle, TRUE); EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); } @@ -446,6 +448,10 @@ INT_PTR CALLBACK PvpPeImportsDlgProc( PhDereferenceObject(filePath); } + else + { + PhShowStatus(hwndDlg, L"Unable to locate the DLL", 0, ERROR_FILE_NOT_FOUND); + } PhDereferenceObject(applicationFileName); } diff --git a/tools/peview/include/peview.h b/tools/peview/include/peview.h index 4cf8ebc40eff..67035a1b5985 100644 --- a/tools/peview/include/peview.h +++ b/tools/peview/include/peview.h @@ -263,8 +263,6 @@ typedef struct _PDB_SYMBOL_CONTEXT HWND SearchHandle; HWND TreeNewHandle; HWND ParentWindowHandle; - - HANDLE TimerQueueHandle; HANDLE UpdateTimerHandle; ULONG64 BaseAddress; diff --git a/tools/peview/main.c b/tools/peview/main.c index 2fa7380e4846..1db30524b2f3 100644 --- a/tools/peview/main.c +++ b/tools/peview/main.c @@ -134,10 +134,11 @@ INT WINAPI wWinMain( if (PhShowFileDialog(NULL, fileDialog)) { - PPH_STRING applicationFileName; - if (PvFileName = PhGetFileDialogFileName(fileDialog)) { +#ifndef DEBUG + PPH_STRING applicationFileName; + if (applicationFileName = PhGetApplicationFileName()) { PhMoveReference(&PvFileName, PhConcatStrings(3, L"\"", PvFileName->Buffer, L"\"")); @@ -155,13 +156,14 @@ INT WINAPI wWinMain( RtlExitUserProcess(STATUS_SUCCESS); } } +#endif } } PhFreeFileDialog(fileDialog); } - if (!PvFileName) + if (PhIsNullOrEmptyString(PvFileName)) return 1; if (PhEndsWithString2(PvFileName, L".lnk", TRUE)) From f49a22845dc32b4e326ab2793921b5a50a92cc5a Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 19 Aug 2019 13:41:31 +1000 Subject: [PATCH 2056/2058] Update msvc build flags --- ProcessHacker/ProcessHacker.vcxproj | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ProcessHacker/ProcessHacker.vcxproj b/ProcessHacker/ProcessHacker.vcxproj index 6a83f0e98fb6..00285a8f03ad 100644 --- a/ProcessHacker/ProcessHacker.vcxproj +++ b/ProcessHacker/ProcessHacker.vcxproj @@ -114,6 +114,7 @@ $(SolutionDir)phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) ProcessHacker.def advapi32.dll;aclui.dll;comdlg32.dll;comctl32.dll;dnsapi.dll;gdi32.dll;iphlpapi.dll;oleaut32.dll;ole32.dll;shell32.dll;shlwapi.dll;userenv.dll;user32.dll;uxtheme.dll;version.dll;winsta.dll;ws2_32.dll;%(DelayLoadDLLs) + /DEPENDENTLOADFLAG:0xA00 %(AdditionalOptions) _UNICODE;UNICODE;%(PreprocessorDefinitions);$(ExternalCompilerOptions) @@ -146,6 +147,7 @@ $(SolutionDir)phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) ProcessHacker.def advapi32.dll;aclui.dll;comdlg32.dll;comctl32.dll;dnsapi.dll;gdi32.dll;iphlpapi.dll;oleaut32.dll;ole32.dll;shell32.dll;shlwapi.dll;userenv.dll;user32.dll;uxtheme.dll;version.dll;winsta.dll;ws2_32.dll;%(DelayLoadDLLs) + /DEPENDENTLOADFLAG:0xA00 %(AdditionalOptions) _UNICODE;UNICODE;%(PreprocessorDefinitions);$(ExternalCompilerOptions) @@ -186,6 +188,7 @@ ProcessHacker.def advapi32.dll;aclui.dll;comdlg32.dll;comctl32.dll;dnsapi.dll;gdi32.dll;iphlpapi.dll;oleaut32.dll;ole32.dll;shell32.dll;shlwapi.dll;userenv.dll;user32.dll;uxtheme.dll;version.dll;winsta.dll;ws2_32.dll;%(DelayLoadDLLs) true + /DEPENDENTLOADFLAG:0xA00 %(AdditionalOptions) _UNICODE;UNICODE;%(PreprocessorDefinitions);$(ExternalCompilerOptions) @@ -224,6 +227,7 @@ ProcessHacker.def advapi32.dll;aclui.dll;comdlg32.dll;comctl32.dll;dnsapi.dll;gdi32.dll;iphlpapi.dll;oleaut32.dll;ole32.dll;shell32.dll;shlwapi.dll;userenv.dll;user32.dll;uxtheme.dll;version.dll;winsta.dll;ws2_32.dll;%(DelayLoadDLLs) true + /DEPENDENTLOADFLAG:0xA00 %(AdditionalOptions) _UNICODE;UNICODE;%(PreprocessorDefinitions);$(ExternalCompilerOptions) From 627a577cddac894a6e8952f97a2adb69b9770092 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 19 Aug 2019 14:28:14 +1000 Subject: [PATCH 2057/2058] peview: Fix properties link for delay imports --- tools/peview/impprp.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/tools/peview/impprp.c b/tools/peview/impprp.c index 435260d53225..46c872aeee3a 100644 --- a/tools/peview/impprp.c +++ b/tools/peview/impprp.c @@ -430,9 +430,21 @@ INT_PTR CALLBACK PvpPeImportsDlgProc( if (applicationFileName = PhGetApplicationFileName()) { + PH_STRINGREF delayTextSr = PH_STRINGREF_INIT(L" (Delay)"); + PH_STRINGREF headerTextSr; + PPH_STRING fileName; PPH_STRING filePath; - if (filePath = PhSearchFilePath(headerText, NULL)) + PhInitializeStringRefLongHint(&headerTextSr, headerText); + + if (PhEndsWithStringRef(&headerTextSr, &delayTextSr, TRUE)) + { + headerTextSr.Length -= delayTextSr.Length; + } + + fileName = PhCreateString2(&headerTextSr); + + if (filePath = PhSearchFilePath(fileName->Buffer, NULL)) { PhMoveReference(&filePath, PhConcatStrings(3, L"\"", filePath->Buffer, L"\"")); @@ -440,7 +452,7 @@ INT_PTR CALLBACK PvpPeImportsDlgProc( hwndDlg, PhGetString(applicationFileName), PhGetString(filePath), - SW_SHOW, + SW_SHOWNORMAL, 0, 0, NULL @@ -453,6 +465,7 @@ INT_PTR CALLBACK PvpPeImportsDlgProc( PhShowStatus(hwndDlg, L"Unable to locate the DLL", 0, ERROR_FILE_NOT_FOUND); } + PhDereferenceObject(fileName); PhDereferenceObject(applicationFileName); } break; From 6f47f0558f0f25755e1094f5683f5f62549f7c67 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 31 Aug 2019 11:47:24 +1000 Subject: [PATCH 2058/2058] Add commandline arguments to information dialog --- ProcessHacker/prpggen.c | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/ProcessHacker/prpggen.c b/ProcessHacker/prpggen.c index 1d5c21fc003f..d84de296043e 100644 --- a/ProcessHacker/prpggen.c +++ b/ProcessHacker/prpggen.c @@ -34,6 +34,8 @@ #include #include +#include + static PWSTR ProtectedSignerStrings[] = { L"", L" (Authenticode)", L" (CodeGen)", L" (Antimalware)", L" (Lsa)", L" (Windows)", L" (WinTcb)", L" (WinSystem)", L" (StoreApp)" }; @@ -487,7 +489,37 @@ INT_PTR CALLBACK PhpProcessGeneralDlgProc( case IDC_VIEWCOMMANDLINE: { if (processItem->CommandLine) - PhShowInformationDialog(hwndDlg, processItem->CommandLine->Buffer, 0); + { + PPH_STRING commandLineString; + INT stringArgCount; + PWSTR* stringArgList; + + if (stringArgList = CommandLineToArgvW(processItem->CommandLine->Buffer, &stringArgCount)) + { + PH_STRING_BUILDER sb; + + PhInitializeStringBuilder(&sb, 260); + + for (INT i = 0; i < stringArgCount; i++) + { + PhAppendFormatStringBuilder(&sb, L"[%d] %s\r\n\r\n", i, stringArgList[i]); + } + + PhAppendFormatStringBuilder(&sb, L"[FULL] %s\r\n", processItem->CommandLine->Buffer); + + commandLineString = PhFinalStringBuilderString(&sb); + + LocalFree(stringArgList); + } + else + { + commandLineString = PhReferenceObject(processItem->CommandLine); + } + + PhShowInformationDialog(hwndDlg, commandLineString->Buffer, 0); + + PhDereferenceObject(commandLineString); + } } break; case IDC_VIEWPARENTPROCESS:

    h%W2^n8dJt9#YJ@Z95qc&(ug1c`c@T#D@iOvB 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 XB=PdD#LL=G4;bz**kzq$xTO6DPHGc< diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb b/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb index 42caff8fcff3014e0967704ce7c810d20b5ca778..35f67156d93bdef34ac2cd7d84e41cda7d6639d0 100644 GIT binary patch delta 3651 zcmZ`+e^gXu8ouv1LqK9fpg15Bj1x;^i!kbhBMu{&P>bOfvZZ7!Vymqn8vYs)l3$^q z;+uOzqyRxlmTh^XctWP^=P!LbXs>3cm5pPlZ)(KJ4a~-2AGW>)hPn=2kbq?&i~O?s9Xt zo6mzYFwYRU2s{ifRtp7%mk^X9@j18*d<`rwK@Q#TcQ|*xSCMNd5&@>VMz&Pw2N9s;glpXV)<%1O^#X$_Yn z&g22a8(EVVqT3jAXW9NJ(pg*&VA=oU*t{;xwQ^e!`)|`?J~@g*GzXCpbIST<=xA5; z4x$)W^ev(|rtL<|FMATVYq177dLB`#E2=}Zh8^%^y7UC}M#*bOkc!6HuuBh2+GSR0 z7V_R*d&taW57(I&-dX8P6t@o7BCOQRHoJ)uInSQsHNHUhkg$~d9`QT8`*&oPp4|Nb zc}}=Dhkd`B#ff{KARn&XlY{r!ryz%Bb3V|(qXlWI2@CIA6UfgLYGKJOG{RB~oQ*h$ zzeLs`N0Rmhf1<5y*c%Q^-g}Z-d3>)Ps4KG2Sxzl7Qx{hP&+|ahL7L#yVm)wYv4wu- z_F}Wj!^}5|7h(=W$w3@R?In8PrzIA8gr}EU@JOvJEyK{CmafL2V`V{{QdWln#>%=V zUTS@DJ9#$Uxuuz$u+LxBWZ@N!VZ3|aF=~=@`|l>|Wv zoI-HbzFa`%QgHQMMElrq)CgR8)P!@l6vQmcrfy7Oh89X8)b9Gu}Ip+ zRmWOrpA=ggP826)z4A8UI5*UV1C#4srA<7FcoR>rH_;JJs<+c;JW&5QT6GQa$fq|v z>-E`UW!nSf7e@M`A%SRw4UOTzsC+O?X&~ww~^MOeZHlH=% zrA|K^Pd_3T@2S51_(uKYf4F^)>TV0)-@b(WIIG?28F;(#>Q7j6yMe;^E2JZCr&s=r zJ3MEgD9$=(p@+C07{^zD%URc<$B`7kL#wha;yv2}`E-XCwdzAt3XcNQ zT!#5?XjN+!!!vJaQJ&m4j3`enFwbT95{7)mpzYM6PNAJf)F~OrF2hTmT2+l==!Kzy zooG76lR$^dknpBf)u|XZzo|v#UU<`p%C!QAU54*r_(U<>*QG@Xqq>YJVLEWsWoYcu zs>T(=B^Z9>t6fHw+QQSiAE3Lrsym3E=+>(IEUx=3?AB5sl19|62N>ZpsC%@kD8(?Z zM~kZ2dW@*rCg5_}Af4^mtRi1F^oFQ>!`)}ed_LB@2A_(tz7U?-Hx-eg?=dRiygoa% zAZr8$pAVo9c)@u)O|s*>5qRZ%4h3*>zllQlg?$rQeoo^gW;4W zB@gO}(m8jih=zE4NDtIqG|?BFe6fhWXXiyDaPndRaQbj0{lLqHBUMut@V4Q-^c3G5 z4hM!_3ZT6lbLngO$Z$T2v2&fry@uv1CrUVH?Dpe%AN~eIieqT> z*!U|!unFQTJ{YD&bizoJ;;1~D9$(>Vm8(V5jbnSBm@y5bT^DWBV7e}*gEU!Df-uL` zpeaZAjN%y)9kOSgI3#-(nFJwQbfUAS8DX0%q%<+~9(abtSdiv>-0phOb`LyH;S+k$ z71D@UC40ujR@ozee;11m*|QblA~95p^|Xqlg=fM=ns~DyEO#|%_8~mSeOvrA@(~s% z;#W)%%@D836s*u3g^UVCD-@$poI=YLTA@&?LTePtbdg5>1#>~Hk{1&#M%|0yW5i^c zY>G-$REna~6tz}S>lKx)s60jGE2>yg6^dd-)hMb#QKuB;P*kU)dKGm+QNxP*L{XnB z>YAcP6*aD?9~Gq*ZPO_T=b^abUJ4{XMFzTMm?9(GGD?vTxn-Opm%HU-V(1LiVU-vQ z(#XFmJw)3K)Tvx)I3!ld?M-5<+%Eq{nl6S0pxs9d4nTvyh&YI5E6U&^&0KtIZDN&d m+a%`7?VpL2GL4C^1&~ptitYGo0R3A1i~kyS%$h}Cdi@`xT(j8# delta 3656 zcmZ`+ZB$g(6@6!%K_G&IpfDgs#E~Q;K{DV(9ypF*5~NrOS~LcmiKVGY6~`~okq-r& z7)63deL=y9f}bUT0}=x)8IgP}6-7EK)G%Ge@q-|1cm!|v88<)SzT5s>O&)xUF z`_6su-l61@y5y3&S?wG0aPPdOBnZNPqgQqBTzLHDs*%vdwPUnvoD+Sgc?AvTk9l-r z=zi0evF2NQUUE!+dim;aTP*c-dYref?@vkShrgeaob>HII{gc8wf9?>2a>Lb-5|;4 zOMz7j!g==O0`-?IC!3v}lm8q{?YuY9OzqAu60?b3<(MQRWwABMM3cB0=*Rs@Ce?_* zzR5G_OSUANsGBz?i*$J(%)uC9y?H5Z z;ePWGy2tBh8-R7Q9W;fXv6PZGH(JazkB1P)vu%!8zl&G)g}m|0?Hxk!l;u@NkH*aSWdy$5^* zyboLtejj`k+z37fJ`FwzZsiv1S91j_PlJ>j2Sh*8f4I+fFMGqIRW&Qdqw#0yuY79#*++Rjh8F_+(9QU@a$MfhU18 z`QfT!%ICtox2cft0LysM>TLA2+QRs=)f0V`o+QL@_fRBwan);qyuhYK zN2|?*j@7mu-g&6!|i64*RVWDUH+C znP~xUN1V;Qh?lWueS~h=%qP19oBD( z0;X*;sU9To)=foZV6sQ+3^Sh0Gz7&xgews)OOyEiW; zgLBE|i{yRRvp5{^&x!nU(Ly4wEy~09>{pye1-Q z3mk_yjBg>UlOv~gOAyhUtlt_9%-DL2>iEa4Q9xa(NXL0msfn7n0(gddODpLvFDi=y zZY&e&pWIevQvGKJ-z%Ged+5t6u_d*YM*+Vo7ikuc-zMUf%G~C_&|hs^ib01RVZ6X` z2m=f|I>_W~d?%m0tDihl2&cXqq^cHqe*I+L{B8|ZJ9RsrB5G#+&M08o&L+Ca4|YcA zZcckrLvPe?A+A)^a1qB<6vNX}5e59BA`8=eW|y6oaKo-VynW*c5VUOk$qi1qsoz|8$d?7QXr&DhU+_lp$Fbij@mqws(c*m9tW z-e7A@EWO25HK(Y^nOqx96z|MEc#g20>kmZ(GY)+~RvtoZK%ADzNjyz#k{B?R<-zf-gSH)Uu_se zn|Yu?RFyr?2aiqV*+<7v1!o*BrRTW+s0mncJl$^u`_~A*h&0sb6}BD|aq2{#i1yow z+;LvJJXqsMZee?WKR z8erFnPie7p`$?1%w>|Ye)i^i)@f3Ma#p{g)64){l$mS3A_`q^MG~_vUdYZtu zkq&>H&iokyB6hg zp(&Mzfaz{S{6|_OiedG~S`=@~#|9Ly5!mB4{0oMQieXZR7FCSvFrbP# zz(Kd6zC)|JqZqEjaGwV|462bt_V0Wa)svrdVW(C#T68~WNvD?lxvJBEx^)4=5r?t5 zORLf=hUr~eRL#<5K-E?PMcLqN?OLrO4ePrjRGMhdb`sAu-LK)a7!m;?KI3S=MBJt^Lg|XXY?2;khk=RRK;CAr?3gExDW-bxL_wc z`}D@*OqDX@X`dA1UY~!m1LH6H^au?*AAFie6zp8_d4~!M zr@s_U>CTKxQAC++yIe{x{_%1YP}gUq8=TQsO5bsRp8@!=FBmxfN-X`rbFajz{vFR7 zu56|G{NPG7F!E|JZQz+#zn6E7{&b9O>p$Y-idQz3Xtr(+5|nSqurD&{xIE?azL6T zae^?#-JmH%_`2d5kXmHVV(GH%dCn*ZtE7H(*3=+ua)*>IMUI8XB_)G2-{En8Ct1eA zGasjDr8}ensS1tKdt>p0&0{G`w1Zw1sEMCHInK1H|24xCRC`6$Mg{CSLqfop;qC#^NN>gZoLfLN8$iHJgld9y& zOqJrsVfYv+L#6~pB`GRZQR#}xQq-%8dP7kw6lGIXfuc$jXa#DrCAXod_m_>ZhdkKLyis>i_%yVf)01bj#;|*-x>5 From 67f489e0786a32900779a53373bb90d52c08be29 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 16 Jul 2018 20:02:13 +1000 Subject: [PATCH 1115/2058] BuildTools: Update appveyor format --- tools/CustomBuildTool/Source Files/Build.cs | 63 +++++++++--------- .../bin/Release/CustomBuildTool.exe | Bin 164864 -> 164864 bytes .../bin/Release/CustomBuildTool.pdb | Bin 75264 -> 77312 bytes 3 files changed, 33 insertions(+), 30 deletions(-) diff --git a/tools/CustomBuildTool/Source Files/Build.cs b/tools/CustomBuildTool/Source Files/Build.cs index 6ce39d7b47a3..475634f95441 100644 --- a/tools/CustomBuildTool/Source Files/Build.cs +++ b/tools/CustomBuildTool/Source Files/Build.cs @@ -155,8 +155,9 @@ public static class Build public static bool InitializeBuildEnvironment(bool CheckDependencies) { + System.Net.ServicePointManager.Expect100Continue = false; TimeStart = DateTime.Now; - BuildOutputFolder = "build\\output\\"; + BuildOutputFolder = "build\\output"; MSBuildExePath = VisualStudio.GetMsbuildFilePath(); GitExePath = Win32.SearchFile("git.exe"); CustomSignToolPath = "tools\\CustomSignTool\\bin\\Release32\\CustomSignTool.exe"; @@ -1052,7 +1053,7 @@ public static void WebServiceUpdateConfig() if (httpTask.Result.IsSuccessStatusCode) { // Update Appveyor build version string. - Win32.ShellExecute("appveyor", "UpdateBuild -Version \"" + BuildVersion + "\" "); + Win32.ShellExecute("appveyor", $"UpdateBuild -Version \"{BuildVersion}\" "); } else { @@ -1101,13 +1102,14 @@ public static bool AppveyorUploadBuildFiles() { foreach (string file in buildFileArray) { - var destinationFile = file.Replace("-build-", $"-{BuildVersion}-"); + string sourceFile = BuildOutputFolder + file; + string destinationFile = BuildOutputFolder + file.Replace("-build-", $"-{BuildVersion}-"); - if (File.Exists(BuildOutputFolder + destinationFile)) - File.Delete(BuildOutputFolder + destinationFile); + if (File.Exists(destinationFile)) + File.Delete(destinationFile); - if (File.Exists(BuildOutputFolder + file)) - File.Move(BuildOutputFolder + file, BuildOutputFolder + destinationFile); + if (File.Exists(sourceFile)) + File.Move(sourceFile, destinationFile); } } catch (Exception ex) @@ -1120,17 +1122,16 @@ public static bool AppveyorUploadBuildFiles() { foreach (string file in buildFileArray) { - var sourceFile = file.Replace("-build-", $"-{BuildVersion}-"); + string sourceFile = BuildOutputFolder + file.Replace("-build-", $"-{BuildVersion}-"); + string filename = Path.GetFileName(BuildOutputFolder + sourceFile); - if (File.Exists(BuildOutputFolder + sourceFile)) + if (File.Exists(sourceFile)) { - string filename = Path.GetFileName(BuildOutputFolder + sourceFile); - using (HttpClient httpClient = new HttpClient()) - using (FileStream fileStream = File.OpenRead(BuildOutputFolder + sourceFile)) + using (FileStream fileStream = File.OpenRead(sourceFile)) using (HttpContent httpContent = new StreamContent(fileStream)) - using (MultipartFormDataContent httpFormData = new MultipartFormDataContent()) { + httpClient.DefaultRequestHeaders.TransferEncodingChunked = true; httpClient.DefaultRequestHeaders.Add("X-ApiKey", buildPostKey); httpContent.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/octet-stream"); httpContent.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("form-data") @@ -1138,24 +1139,26 @@ public static bool AppveyorUploadBuildFiles() Name = "\"file\"", FileName = $"\"{filename}\"", }; - httpFormData.Add(httpContent, "file", filename); Console.WriteLine($"Uploading {filename}..."); - var response = httpClient.PostAsync(buildPostUrl, httpFormData); - response.Wait(); - - if (!response.Result.IsSuccessStatusCode) + using (HttpRequestMessage requestMessage = new HttpRequestMessage(new HttpMethod("POST"), buildPostUrl)) { - Program.PrintColorMessage("[UploadBuildWebServiceStatusCode] " + response.Result, ConsoleColor.Red); + requestMessage.Headers.TransferEncodingChunked = true; + requestMessage.Content = httpContent; + + var response = httpClient.SendAsync(requestMessage, HttpCompletionOption.ResponseHeadersRead); + response.Wait(); + + response.Result.EnsureSuccessStatusCode(); } } } } } - catch (Exception) + catch (Exception ex) { - Program.PrintColorMessage("[UploadBuildWebServiceAsync-Exception]", ConsoleColor.Red); + Program.PrintColorMessage("[UploadBuildWebServiceAsync-Exception]" + ex, ConsoleColor.Red); return false; } @@ -1163,11 +1166,11 @@ public static bool AppveyorUploadBuildFiles() { foreach (string file in releaseFileArray) { - var sourceFile = file.Replace("-build-", $"-{BuildVersion}-"); + var sourceFile = BuildOutputFolder + file.Replace("-build-", $"-{BuildVersion}-"); - if (File.Exists(BuildOutputFolder + sourceFile)) + if (File.Exists(sourceFile)) { - Win32.ShellExecute("appveyor", "PushArtifact " + BuildOutputFolder + sourceFile); + Win32.ShellExecute("appveyor", "PushArtifact " + sourceFile); } else { @@ -1206,9 +1209,9 @@ public static bool BuildSolution(string Solution, BuildFlags Flags) if (Flags.HasFlag(BuildFlags.BuildApi)) compilerOptions.Append("PH_BUILD_API;"); if (!string.IsNullOrEmpty(BuildCommit)) - compilerOptions.Append("PHAPP_VERSION_COMMITHASH=\"" + BuildCommit.Substring(0, 8) + "\";"); - compilerOptions.Append("PHAPP_VERSION_REVISION=\"" + BuildRevision + "\";"); - compilerOptions.Append("PHAPP_VERSION_BUILD=\"" + BuildCount + "\""); + compilerOptions.Append($"PHAPP_VERSION_COMMITHASH=\"{BuildCommit.Substring(0, 8)}\";"); + compilerOptions.Append($"PHAPP_VERSION_REVISION=\"{BuildRevision}\";"); + compilerOptions.Append($"PHAPP_VERSION_BUILD=\"{BuildCount}\""); string error32 = Win32.ShellExecute( MSBuildExePath, @@ -1237,9 +1240,9 @@ public static bool BuildSolution(string Solution, BuildFlags Flags) if (Flags.HasFlag(BuildFlags.BuildApi)) compilerOptions.Append("PH_BUILD_API;"); if (!string.IsNullOrEmpty(BuildCommit)) - compilerOptions.Append("PHAPP_VERSION_COMMITHASH=\"" + BuildCommit.Substring(0, 8) + "\";"); - compilerOptions.Append("PHAPP_VERSION_REVISION=\"" + BuildRevision + "\";"); - compilerOptions.Append("PHAPP_VERSION_BUILD=\"" + BuildCount + "\""); + compilerOptions.Append($"PHAPP_VERSION_COMMITHASH=\"{BuildCommit.Substring(0, 8)}\";"); + compilerOptions.Append($"PHAPP_VERSION_REVISION=\"{BuildRevision}\";"); + compilerOptions.Append($"PHAPP_VERSION_BUILD=\"{BuildCount}\""); string error64 = Win32.ShellExecute( MSBuildExePath, diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe b/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe index ac93ee318ce823de299a3c037c1b1791b4b875f2..90a887ca8d5cc89d2e8a174524802751494aa5ed 100644 GIT binary patch delta 23612 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 delta 23484 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 F{{mO)+#dh{ diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb b/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb index 35f67156d93bdef34ac2cd7d84e41cda7d6639d0..342331eda69f72b86cb1a9feaa4154d967461d23 100644 GIT binary patch delta 11457 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 ioG(D#@yNA}rrKx9hS?JZ<4=sxOj`&}Y8?n9s delta 11358 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 From 6bdb0b252b836bc834ad52954c6519c3a34f70b1 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 17 Jul 2018 16:31:59 +1000 Subject: [PATCH 1116/2058] Update readme format --- README.md | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 8b33bb795fa4..d68a161b90b8 100644 --- a/README.md +++ b/README.md @@ -2,13 +2,11 @@ A free, powerful, multi-purpose tool that helps you monitor system resources, debug software and detect malware. -[![Build status](https://ci.appveyor.com/api/projects/status/5einmgmy3mnsfjdn?svg=true)](https://ci.appveyor.com/project/processhacker/processhacker2) -[![Licence](https://img.shields.io/badge/license-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0.en.html) +[![Build status](https://img.shields.io/github/downloads/processhacker/processhacker/total.svg?style=for-the-badge)](https://ci.appveyor.com/project/processhacker/processhacker) +[![Build status](https://img.shields.io/appveyor/ci/processhacker/processhacker.svg?style=for-the-badge)](https://ci.appveyor.com/project/processhacker/processhacker) +[![Licence](https://img.shields.io/badge/license-GPLv3-blue.svg?style=for-the-badge)](https://www.gnu.org/licenses/gpl-3.0.en.html) -![Logo](https://raw.githubusercontent.com/processhacker2/processhacker/master/ProcessHacker/resources/ProcessHacker.png) - -* [Official Website](http://processhacker.sourceforge.net/) -* [FAQ](http://processhacker.sourceforge.net/faq.php) +* [Official Website](https://processhacker.sourceforge.io/) * [Nightly Builds](https://wj32.org/processhacker/nightly.php) ## System requirements @@ -100,4 +98,3 @@ to show details for all processes when it is not running as administrator: not using an official build, you may need to set it to 0 instead. 4. Restart the KProcessHacker3 service (sc stop KProcessHacker3, sc start KProcessHacker3). - From 81db72882371a333f7343460ba8f350a8f03112b Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 17 Jul 2018 16:50:18 +1000 Subject: [PATCH 1117/2058] Fix typo --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index d68a161b90b8..5a2158f32d76 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,12 @@ +[![Build status](https://img.shields.io/github/downloads/processhacker/processhacker/total.svg?style=for-the-badge)](https://github.com/processhacker/processhacker/releases) +[![Build status](https://img.shields.io/appveyor/ci/processhacker/processhacker.svg?style=for-the-badge)](https://ci.appveyor.com/project/processhacker/processhacker) +[![Build status](https://img.shields.io/github/contributors/processhacker/processhacker.svg?style=for-the-badge)](https://github.com/processhacker/processhacker/graphs/contributors) +[![Licence](https://img.shields.io/badge/license-GPLv3-blue.svg?style=for-the-badge)](https://www.gnu.org/licenses/gpl-3.0.en.html) + ## Process Hacker A free, powerful, multi-purpose tool that helps you monitor system resources, debug software and detect malware. -[![Build status](https://img.shields.io/github/downloads/processhacker/processhacker/total.svg?style=for-the-badge)](https://ci.appveyor.com/project/processhacker/processhacker) -[![Build status](https://img.shields.io/appveyor/ci/processhacker/processhacker.svg?style=for-the-badge)](https://ci.appveyor.com/project/processhacker/processhacker) -[![Licence](https://img.shields.io/badge/license-GPLv3-blue.svg?style=for-the-badge)](https://www.gnu.org/licenses/gpl-3.0.en.html) - * [Official Website](https://processhacker.sourceforge.io/) * [Nightly Builds](https://wj32.org/processhacker/nightly.php) @@ -15,7 +16,6 @@ Windows 7 or higher, 32-bit or 64-bit. ## Features - * A detailed overview of system activity with highlighting. * Graphs and statistics allow you quickly to track down resource hogs and runaway processes. * Can't edit or delete a file? Discover which processes are using that file. From 81db9d4b6e380f0c8a59f37222b08553409c4831 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 18 Jul 2018 12:44:40 +1000 Subject: [PATCH 1118/2058] Updater: Improve caching --- plugins/Updater/updater.c | 41 +++++++-------------------------------- plugins/Updater/updater.h | 2 ++ 2 files changed, 9 insertions(+), 34 deletions(-) diff --git a/plugins/Updater/updater.c b/plugins/Updater/updater.c index 4ba653d17db1..4023bf7d0fcb 100644 --- a/plugins/Updater/updater.c +++ b/plugins/Updater/updater.c @@ -316,6 +316,9 @@ BOOLEAN QueryUpdateData( Context->SetupFileSignature = PhGetJsonValueAsString(jsonObject, "setup_sig"); Context->BuildMessage = PhGetJsonValueAsString(jsonObject, "changelog"); + Context->CurrentVersion = ParseVersionString(Context->CurrentVersionString); + Context->LatestVersion = ParseVersionString(Context->Version); + PhFreeJsonParser(jsonObject); if (PhIsNullOrEmptyString(Context->Version)) @@ -367,9 +370,7 @@ NTSTATUS UpdateCheckSilentThread( _In_ PVOID Parameter ) { - PPH_UPDATER_CONTEXT context = NULL; - ULONGLONG currentVersion = 0; - ULONGLONG latestVersion = 0; + PPH_UPDATER_CONTEXT context; context = CreateUpdateContext(TRUE); @@ -384,21 +385,8 @@ NTSTATUS UpdateCheckSilentThread( if (!QueryUpdateData(context)) goto CleanupExit; - currentVersion = ParseVersionString(context->CurrentVersionString); - -#ifdef FORCE_UPDATE_CHECK - latestVersion = MAKE_VERSION_ULONGLONG( - 9999, - 9999, - 9999, - 0 - ); -#else - latestVersion = ParseVersionString(context->Version); -#endif - // Compare the current version against the latest available version - if (currentVersion < latestVersion) + if (context->CurrentVersion < context->LatestVersion) { // Check if the user hasn't already opened the dialog. if (!UpdateDialogHandle) @@ -424,8 +412,6 @@ NTSTATUS UpdateCheckThread( ) { PPH_UPDATER_CONTEXT context; - ULONGLONG currentVersion = 0; - ULONGLONG latestVersion = 0; PH_AUTO_POOL autoPool; context = (PPH_UPDATER_CONTEXT)Parameter; @@ -448,25 +434,12 @@ NTSTATUS UpdateCheckThread( return STATUS_SUCCESS; } - currentVersion = ParseVersionString(context->CurrentVersionString); - -#ifdef FORCE_UPDATE_CHECK - latestVersion = MAKE_VERSION_ULONGLONG( - 9999, - 9999, - 9999, - 0 - ); -#else - latestVersion = ParseVersionString(context->Version); -#endif - - if (currentVersion == latestVersion) + if (context->CurrentVersion == context->LatestVersion) { // User is running the latest version ShowLatestVersionDialog(context); } - else if (currentVersion > latestVersion) + else if (context->CurrentVersion > context->LatestVersion) { // User is running a newer version ShowNewerVersionDialog(context); diff --git a/plugins/Updater/updater.h b/plugins/Updater/updater.h index d7749ce02c92..d0ffba8c625f 100644 --- a/plugins/Updater/updater.h +++ b/plugins/Updater/updater.h @@ -88,6 +88,8 @@ typedef struct _PH_UPDATER_CONTEXT WNDPROC DefaultWindowProc; ULONG ErrorCode; + ULONG64 CurrentVersion; + ULONG64 LatestVersion; PPH_STRING SetupFilePath; PPH_STRING CurrentVersionString; PPH_STRING Version; From e2313069b4a9f5b0effd14b8d92d5d5de11228eb Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 18 Jul 2018 12:52:21 +1000 Subject: [PATCH 1119/2058] Remove unused variable --- ProcessHacker/mainwnd.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index 668f791ce397..2d23ca07369c 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -91,8 +91,6 @@ static HFONT CurrentCustomFont; static HMENU SubMenuHandles[5]; static PPH_EMENU SubMenuObjects[5]; -static PH_CALLBACK_REGISTRATION SymInitRegistration; - static ULONG SelectedRunAsMode; static ULONG SelectedUserSessionId; From 7fa1af709726100771bc053e75b680ab20215a6a Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 18 Jul 2018 12:54:15 +1000 Subject: [PATCH 1120/2058] Fix token username query --- ProcessHacker/mainwnd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index 2d23ca07369c..15a7c090c251 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -125,7 +125,7 @@ BOOLEAN PhMainWndInitialization( PhAppendStringBuilder2(&stringBuilder, L"Process Hacker"); - if (currentUserName = PhGetTokenUserString(PhGetOwnTokenAttributes().TokenHandle, TRUE)) + if (currentUserName = PhGetSidFullName(PhGetOwnTokenAttributes().TokenSid, TRUE, NULL)) { PhAppendStringBuilder2(&stringBuilder, L" ["); PhAppendStringBuilder(&stringBuilder, ¤tUserName->sr); From e58db6f593804e00a3e54043ab6b8f9c23d5471c Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 18 Jul 2018 13:01:03 +1000 Subject: [PATCH 1121/2058] Fix view > processes from other users' regression --- ProcessHacker/mainwnd.c | 1 - ProcessHacker/mwpgproc.c | 3 --- ProcessHacker/proctree.c | 1 - 3 files changed, 5 deletions(-) diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index 15a7c090c251..6b5f95184a34 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -2986,7 +2986,6 @@ VOID PhMwpAddIconProcesses( if ( processItem->CpuUsage == 0 || - processItem->SessionId != NtCurrentPeb()->SessionId || (processItem->Sid && !RtlEqualSid(processItem->Sid, PhGetOwnTokenAttributes().TokenSid)) ) { diff --git a/ProcessHacker/mwpgproc.c b/ProcessHacker/mwpgproc.c index f27f6b17b807..aa31f05410dc 100644 --- a/ProcessHacker/mwpgproc.c +++ b/ProcessHacker/mwpgproc.c @@ -256,9 +256,6 @@ BOOLEAN PhMwpCurrentUserProcessTreeFilter( { PPH_PROCESS_NODE processNode = (PPH_PROCESS_NODE)Node; - if (processNode->ProcessItem->SessionId != NtCurrentPeb()->SessionId) - return FALSE; - if (!processNode->ProcessItem->Sid) return FALSE; diff --git a/ProcessHacker/proctree.c b/ProcessHacker/proctree.c index d24bc564577b..cc6e2b1d5184 100644 --- a/ProcessHacker/proctree.c +++ b/ProcessHacker/proctree.c @@ -2951,7 +2951,6 @@ BOOLEAN NTAPI PhpProcessTreeNewCallback( getNodeColor->BackColor = PhCsColorSystemProcesses; else if ( PhCsUseColorOwnProcesses && - processItem->SessionId == NtCurrentPeb()->SessionId && processItem->Sid && RtlEqualSid(processItem->Sid, PhGetOwnTokenAttributes().TokenSid) ) From 8e3bbdd1bc21d626beead87d85482c0d4d271f9d Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 18 Jul 2018 13:05:49 +1000 Subject: [PATCH 1122/2058] HardwareDevices: Show options window device icons --- plugins/HardwareDevices/devices.h | 9 +- plugins/HardwareDevices/disk.c | 26 ++++-- plugins/HardwareDevices/diskdetails.c | 10 ++- plugins/HardwareDevices/diskoptions.c | 121 +++++++++++++++++--------- plugins/HardwareDevices/main.c | 2 +- plugins/HardwareDevices/netoptions.c | 121 +++++++++++++++++--------- plugins/HardwareDevices/storage.c | 16 ---- 7 files changed, 197 insertions(+), 108 deletions(-) diff --git a/plugins/HardwareDevices/devices.h b/plugins/HardwareDevices/devices.h index 610ace5a1e6e..850f8cd3f6eb 100644 --- a/plugins/HardwareDevices/devices.h +++ b/plugins/HardwareDevices/devices.h @@ -159,7 +159,7 @@ typedef struct _DV_NETADAPTER_DETAILS_CONTEXT typedef struct _DV_NETADAPTER_CONTEXT { HWND ListViewHandle; - //HIMAGELIST ImageList; + HIMAGELIST ImageList; BOOLEAN OptionsChanged; BOOLEAN UseAlternateMethod; PH_LAYOUT_MANAGER LayoutManager; @@ -413,7 +413,7 @@ typedef struct _DV_DISK_SYSINFO_CONTEXT typedef struct _DV_DISK_OPTIONS_CONTEXT { HWND ListViewHandle; - //HIMAGELIST ImageList; + HIMAGELIST ImageList; BOOLEAN OptionsChanged; PH_LAYOUT_MANAGER LayoutManager; } DV_DISK_OPTIONS_CONTEXT, *PDV_DISK_OPTIONS_CONTEXT; @@ -602,11 +602,6 @@ VOID AddRemoveDeviceChangeCallback( // storage.c -NTSTATUS DiskDriveCreateHandle( - _Out_ PHANDLE DeviceHandle, - _In_ PPH_STRING DevicePath - ); - PPH_STRING DiskDriveQueryDosMountPoints( _In_ ULONG DeviceNumber ); diff --git a/plugins/HardwareDevices/disk.c b/plugins/HardwareDevices/disk.c index 0b7e04b83255..64e193a9d2f8 100644 --- a/plugins/HardwareDevices/disk.c +++ b/plugins/HardwareDevices/disk.c @@ -69,7 +69,15 @@ VOID DiskDrivesUpdate( if (!entry) continue; - if (NT_SUCCESS(DiskDriveCreateHandle(&deviceHandle, entry->Id.DevicePath))) + if (NT_SUCCESS(PhCreateFileWin32( + &deviceHandle, + PhGetString(entry->Id.DevicePath), + FILE_READ_ATTRIBUTES | SYNCHRONIZE, + FILE_ATTRIBUTE_NORMAL, + FILE_SHARE_READ | FILE_SHARE_WRITE, + FILE_OPEN, + FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT + ))) { DISK_PERFORMANCE diskPerformance; @@ -205,13 +213,21 @@ VOID DiskDriveUpdateDeviceInfo( { HANDLE deviceHandle = NULL; - if (!DeviceHandle) + if (DeviceHandle) { - DiskDriveCreateHandle(&deviceHandle, DiskEntry->Id.DevicePath); + deviceHandle = DeviceHandle; } else { - deviceHandle = DeviceHandle; + PhCreateFileWin32( + &deviceHandle, + PhGetString(DiskEntry->Id.DevicePath), + FILE_READ_ATTRIBUTES | SYNCHRONIZE, + FILE_ATTRIBUTE_NORMAL, + FILE_SHARE_READ | FILE_SHARE_WRITE, + FILE_OPEN, + FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT + ); } if (deviceHandle) @@ -236,7 +252,7 @@ VOID DiskDriveUpdateDeviceInfo( } } - if (!DeviceHandle) + if (!DeviceHandle && deviceHandle) { NtClose(deviceHandle); } diff --git a/plugins/HardwareDevices/diskdetails.c b/plugins/HardwareDevices/diskdetails.c index 21c86e7cbb89..e4a55b1018e5 100644 --- a/plugins/HardwareDevices/diskdetails.c +++ b/plugins/HardwareDevices/diskdetails.c @@ -156,7 +156,15 @@ VOID DiskDriveQuerySmart( PPH_LIST attributes; HANDLE deviceHandle; - if (NT_SUCCESS(DiskDriveCreateHandle(&deviceHandle, Context->PageContext->DiskId.DevicePath))) + if (NT_SUCCESS(PhCreateFileWin32( + &deviceHandle, + PhGetString(Context->PageContext->DiskId.DevicePath), + FILE_READ_ATTRIBUTES | SYNCHRONIZE, + FILE_ATTRIBUTE_NORMAL, + FILE_SHARE_READ | FILE_SHARE_WRITE, + FILE_OPEN, + FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT + ))) { if (NT_SUCCESS(DiskDriveQueryImminentFailure(deviceHandle, &attributes))) { diff --git a/plugins/HardwareDevices/diskoptions.c b/plugins/HardwareDevices/diskoptions.c index 8d20bd017028..3277ccc5e52a 100644 --- a/plugins/HardwareDevices/diskoptions.c +++ b/plugins/HardwareDevices/diskoptions.c @@ -21,6 +21,7 @@ */ #include "devices.h" +#include typedef struct _DISK_ENUM_ENTRY { @@ -360,7 +361,15 @@ VOID FindDiskDrives( diskEntry->DeviceName = PhCreateString2(&deviceDescription->sr); diskEntry->DevicePath = PhCreateString(deviceInterface); - if (NT_SUCCESS(DiskDriveCreateHandle(&deviceHandle, diskEntry->DevicePath))) + if (NT_SUCCESS(PhCreateFileWin32( + &deviceHandle, + PhGetString(diskEntry->DevicePath), + FILE_READ_ATTRIBUTES | SYNCHRONIZE, + FILE_ATTRIBUTE_NORMAL, + FILE_SHARE_READ | FILE_SHARE_WRITE, + FILE_OPEN, + FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT + ))) { ULONG diskIndex = ULONG_MAX; // Note: Do not initialize to zero @@ -541,44 +550,77 @@ PPH_STRING FindDiskDeviceInstance( return deviceInstanceString; } -//VOID LoadDiskDriveImages( -// _In_ PDV_DISK_OPTIONS_CONTEXT Context -// ) -//{ -// HICON smallIcon = NULL; -// -// Context->ImageList = ImageList_Create( -// GetSystemMetrics(SM_CXSMICON), -// GetSystemMetrics(SM_CYSMICON), -// ILC_COLOR32, -// 1, -// 1 -// ); -// -// // We could use SetupDiLoadClassIcon but this works. -// // Copied from HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\Class\{4d36e967-e325-11ce-bfc1-08002be10318}\\IconPath -// // The index is only valid on Vista and above. -// ExtractIconEx( -// L"%SystemRoot%\\system32\\imageres.dll", -// -32, -// NULL, -// &smallIcon, -// 1 -// ); -// -// if (smallIcon) -// { -// ImageList_AddIcon(Context->ImageList, smallIcon); -// DestroyIcon(smallIcon); -// -// // Set the imagelist only if the image was loaded. -// ListView_SetImageList( -// Context->ListViewHandle, -// Context->ImageList, -// LVSIL_SMALL -// ); -// } -//} +VOID LoadDiskDriveImages( + _In_ PDV_DISK_OPTIONS_CONTEXT Context + ) +{ + HICON smallIcon; + + Context->ImageList = ImageList_Create( + GetSystemMetrics(SM_CXICON), + GetSystemMetrics(SM_CYICON), + ILC_COLOR32, + 1, + 1 + ); + + CONFIGRET result; + DEVPROPTYPE devicePropertyType; + ULONG deviceInstanceIdLength = MAX_DEVICE_ID_LEN; + WCHAR deviceInstanceId[MAX_DEVICE_ID_LEN + 1] = L""; + + ULONG bufferSize = 0x40; + PPH_STRING deviceDescription = PhCreateStringEx(NULL, bufferSize); + + if ((result = CM_Get_Class_Property( + &GUID_DEVCLASS_DISKDRIVE, + &DEVPKEY_DeviceClass_IconPath, + &devicePropertyType, + (PBYTE)deviceDescription->Buffer, + &bufferSize, + 0 + )) != CR_SUCCESS) + { + PhDereferenceObject(deviceDescription); + deviceDescription = PhCreateStringEx(NULL, bufferSize); + + result = CM_Get_Class_Property( + &GUID_DEVCLASS_DISKDRIVE, + &DEVPKEY_DeviceClass_IconPath, + &devicePropertyType, + (PBYTE)deviceDescription->Buffer, + &bufferSize, + 0 + ); + } + + // %SystemRoot%\System32\setupapi.dll,-53 + + PH_STRINGREF dllPartSr; + PH_STRINGREF indexPartSr; + ULONG64 index; + + PhSplitStringRefAtChar(&deviceDescription->sr, ',', &dllPartSr, &indexPartSr); + PhStringToInteger64(&indexPartSr, 10, &index); + PhMoveReference(&deviceDescription, PhExpandEnvironmentStrings(&dllPartSr)); + + // We could use SetupDiLoadClassIcon but this works. + // Copied from HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\Class\{4d36e967-e325-11ce-bfc1-08002be10318}\\IconPath + // The index is only valid on Vista and above. + + if (PhExtractIconEx(deviceDescription->Buffer, (INT)index, &smallIcon, NULL)) + { + ImageList_AddIcon(Context->ImageList, smallIcon); + DestroyIcon(smallIcon); + + // Set the imagelist only if the image was loaded. + ListView_SetImageList( + Context->ListViewHandle, + Context->ImageList, + LVSIL_SMALL + ); + } +} INT_PTR CALLBACK DiskDriveOptionsDlgProc( _In_ HWND hwndDlg, @@ -627,6 +669,7 @@ INT_PTR CALLBACK DiskDriveOptionsDlgProc( PhSetControlTheme(context->ListViewHandle, L"explorer"); PhAddListViewColumn(context->ListViewHandle, 0, 0, 0, LVCFMT_LEFT, 350, L"Disk Drives"); PhSetExtendedListView(context->ListViewHandle); + LoadDiskDriveImages(context); ListView_EnableGroupView(context->ListViewHandle, TRUE); PhAddListViewGroup(context->ListViewHandle, 0, L"Connected"); diff --git a/plugins/HardwareDevices/main.c b/plugins/HardwareDevices/main.c index 7cc3482b8984..5e6a28bdec6e 100644 --- a/plugins/HardwareDevices/main.c +++ b/plugins/HardwareDevices/main.c @@ -386,7 +386,7 @@ LOGICAL DllMain( &SystemInformationInitializingCallbackRegistration ); - PhAddSettings(settings, ARRAYSIZE(settings)); + PhAddSettings(settings, RTL_NUMBER_OF(settings)); } break; } diff --git a/plugins/HardwareDevices/netoptions.c b/plugins/HardwareDevices/netoptions.c index 4794cdd33d99..21a96327e8c6 100644 --- a/plugins/HardwareDevices/netoptions.c +++ b/plugins/HardwareDevices/netoptions.c @@ -24,6 +24,7 @@ #define INITGUID #include "devices.h" #include +#include typedef struct _NET_ENUM_ENTRY { @@ -378,6 +379,7 @@ VOID FindNetworkAdapters( } else { + static PH_STRINGREF devicePathSr = PH_STRINGREF_INIT(L"\\\\.\\"); PPH_LIST deviceList; PWSTR deviceInterfaceList; ULONG deviceInterfaceListLength = 0; @@ -435,7 +437,7 @@ VOID FindNetworkAdapters( memset(adapterEntry, 0, sizeof(NET_ENUM_ENTRY)); adapterEntry->DeviceGuid = PhQueryRegistryString(keyHandle, L"NetCfgInstanceId"); - adapterEntry->DeviceInterface = PhConcatStrings2(L"\\\\.\\", adapterEntry->DeviceGuid->Buffer); + adapterEntry->DeviceInterface = PhConcatStringRef2(&devicePathSr, &adapterEntry->DeviceGuid->sr); adapterEntry->DeviceLuid.Info.IfType = PhQueryRegistryUlong64(keyHandle, L"*IfType"); adapterEntry->DeviceLuid.Info.NetLuidIndex = PhQueryRegistryUlong64(keyHandle, L"NetLuidIndex"); @@ -663,44 +665,84 @@ PPH_STRING FindNetworkDeviceInstance( return deviceInstanceString; } -//VOID LoadNetworkAdapterImages( -// _In_ PDV_NETADAPTER_CONTEXT Context -// ) -//{ -// HICON smallIcon = NULL; -// -// Context->ImageList = ImageList_Create( -// GetSystemMetrics(SM_CXSMICON), -// GetSystemMetrics(SM_CYSMICON), -// ILC_COLOR32, -// 1, -// 1 -// ); -// -// // We could use SetupDiLoadClassIcon but this works. -// // Copied from HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\Class\{4d36e972-e325-11ce-bfc1-08002be10318}\\IconPath -// // The path and index hasn't changed since Win2k. -// ExtractIconEx( -// L"%SystemRoot%\\system32\\setupapi.dll", -// -5, -// NULL, -// &smallIcon, -// 1 -// ); -// -// if (smallIcon) -// { -// ImageList_AddIcon(Context->ImageList, smallIcon); -// DestroyIcon(smallIcon); -// -// // Set the imagelist only if the image was loaded. -// ListView_SetImageList( -// Context->ListViewHandle, -// Context->ImageList, -// LVSIL_SMALL -// ); -// } -//} +VOID LoadNetworkAdapterImages( + _In_ PDV_NETADAPTER_CONTEXT Context + ) +{ + HICON smallIcon; + CONFIGRET result; + ULONG deviceIconPathLength; + DEVPROPTYPE deviceIconPathPropertyType; + PPH_STRING deviceIconPath; + + deviceIconPathLength = 0x40; + deviceIconPath = PhCreateStringEx(NULL, deviceIconPathLength); + + if ((result = CM_Get_Class_Property( + &GUID_DEVCLASS_NET, + &DEVPKEY_DeviceClass_IconPath, + &deviceIconPathPropertyType, + (PBYTE)deviceIconPath->Buffer, + &deviceIconPathLength, + 0 + )) != CR_SUCCESS) + { + PhDereferenceObject(deviceIconPath); + deviceIconPath = PhCreateStringEx(NULL, deviceIconPathLength); + + result = CM_Get_Class_Property( + &GUID_DEVCLASS_NET, + &DEVPKEY_DeviceClass_IconPath, + &deviceIconPathPropertyType, + (PBYTE)deviceIconPath->Buffer, + &deviceIconPathLength, + 0 + ); + } + + if (result != CR_SUCCESS) + { + PhDereferenceObject(deviceIconPath); + return; + } + + PhTrimToNullTerminatorString(deviceIconPath); + + { + PPH_STRING dllIconPath; + PH_STRINGREF dllPartSr; + PH_STRINGREF indexPartSr; + ULONG64 index = 0; + + if ( + PhSplitStringRefAtChar(&deviceIconPath->sr, ',', &dllPartSr, &indexPartSr) && + PhStringToInteger64(&indexPartSr, 10, &index) + ) + { + if (dllIconPath = PhExpandEnvironmentStrings(&dllPartSr)) + { + if (PhExtractIconEx(dllIconPath->Buffer, (INT)index, &smallIcon, NULL)) + { + Context->ImageList = ImageList_Create( + GetSystemMetrics(SM_CXICON), + GetSystemMetrics(SM_CYICON), + ILC_COLOR32, + 1, + 1 + ); + + ImageList_AddIcon(Context->ImageList, smallIcon); + ListView_SetImageList(Context->ListViewHandle, Context->ImageList, LVSIL_SMALL); + DestroyIcon(smallIcon); + } + + PhDereferenceObject(dllIconPath); + } + } + } + + PhDereferenceObject(deviceIconPath); +} INT_PTR CALLBACK NetworkAdapterOptionsDlgProc( _In_ HWND hwndDlg, @@ -748,6 +790,7 @@ INT_PTR CALLBACK NetworkAdapterOptionsDlgProc( PhSetControlTheme(context->ListViewHandle, L"explorer"); PhAddListViewColumn(context->ListViewHandle, 0, 0, 0, LVCFMT_LEFT, 350, L"Network Adapters"); PhSetExtendedListView(context->ListViewHandle); + LoadNetworkAdapterImages(context); ListView_EnableGroupView(context->ListViewHandle, TRUE); PhAddListViewGroup(context->ListViewHandle, 0, L"Connected"); diff --git a/plugins/HardwareDevices/storage.c b/plugins/HardwareDevices/storage.c index 654151433752..2296febe33ea 100644 --- a/plugins/HardwareDevices/storage.c +++ b/plugins/HardwareDevices/storage.c @@ -23,22 +23,6 @@ #include "devices.h" #include -NTSTATUS DiskDriveCreateHandle( - _Out_ PHANDLE DeviceHandle, - _In_ PPH_STRING DevicePath - ) -{ - return PhCreateFileWin32( - DeviceHandle, - DevicePath->Buffer, - FILE_READ_ATTRIBUTES | SYNCHRONIZE, - FILE_ATTRIBUTE_NORMAL, - FILE_SHARE_READ | FILE_SHARE_WRITE, - FILE_OPEN, - FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT // FILE_RANDOM_ACCESS - ); -} - ULONG DiskDriveQueryDeviceMap( VOID ) From 322f94d415ab0afa8a967e854f3c408e04b2d15c Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 18 Jul 2018 13:48:05 +1000 Subject: [PATCH 1123/2058] BuildTools: Fix sdk detection, Tidy up filename handling, Move appx support --- tools/CustomBuildTool/CustomBuildTool.csproj | 1 + .../CustomBuildTool/Source Files/AppxBuild.cs | 301 ++++++++ tools/CustomBuildTool/Source Files/Build.cs | 650 ++++++------------ tools/CustomBuildTool/Source Files/Program.cs | 14 +- tools/CustomBuildTool/Source Files/Utils.cs | 91 +++ .../bin/Release/CustomBuildTool.exe | Bin 164864 -> 166400 bytes .../bin/Release/CustomBuildTool.pdb | Bin 77312 -> 81408 bytes 7 files changed, 610 insertions(+), 447 deletions(-) create mode 100644 tools/CustomBuildTool/Source Files/AppxBuild.cs diff --git a/tools/CustomBuildTool/CustomBuildTool.csproj b/tools/CustomBuildTool/CustomBuildTool.csproj index 86a7da4e9202..7c3f771214cf 100644 --- a/tools/CustomBuildTool/CustomBuildTool.csproj +++ b/tools/CustomBuildTool/CustomBuildTool.csproj @@ -79,6 +79,7 @@ + True True diff --git a/tools/CustomBuildTool/Source Files/AppxBuild.cs b/tools/CustomBuildTool/Source Files/AppxBuild.cs new file mode 100644 index 000000000000..62cceb489384 --- /dev/null +++ b/tools/CustomBuildTool/Source Files/AppxBuild.cs @@ -0,0 +1,301 @@ +using System; +using System.IO; +using System.Text; +using System.Security.Cryptography.X509Certificates; +using Microsoft.Win32; + +namespace CustomBuildTool +{ + public static class AppxBuild + { + public static void BuildAppxPackage(string BuildOutputFolder, string BuildLongVersion, BuildFlags Flags) + { + string sdkRootPath = string.Empty; + string[] cleanupAppxArray = + { + BuildOutputFolder + "\\AppxManifest32.xml", + BuildOutputFolder + "\\AppxManifest64.xml", + BuildOutputFolder + "\\package32.map", + BuildOutputFolder + "\\package64.map", + BuildOutputFolder + "\\bundle.map", + BuildOutputFolder + "\\ProcessHacker-44.png", + BuildOutputFolder + "\\ProcessHacker-50.png", + BuildOutputFolder + "\\ProcessHacker-150.png" + }; + + Program.PrintColorMessage("Building processhacker-build-package.appxbundle...", ConsoleColor.Cyan); + + using (var view32 = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32)) + { + using (var kitsroot = view32.OpenSubKey("Microsoft\\Windows Kits\\Installed Roots\\", false)) + { + sdkRootPath = (string)kitsroot.GetValue("WdkBinRootVersioned", string.Empty); + } + } + + if (!string.IsNullOrEmpty(sdkRootPath)) + { + Program.PrintColorMessage("[Skipped] Windows SDK", ConsoleColor.Red); + return ; + } + + string makeAppxExePath = Environment.ExpandEnvironmentVariables(sdkRootPath + "\\x64\\MakeAppx.exe"); + string signToolExePath = Environment.ExpandEnvironmentVariables(sdkRootPath + "\\x64\\SignTool.exe"); + + try + { + Win32.ImageResizeFile(44, "ProcessHacker\\resources\\ProcessHacker.png", BuildOutputFolder + "\\ProcessHacker-44.png"); + Win32.ImageResizeFile(50, "ProcessHacker\\resources\\ProcessHacker.png", BuildOutputFolder + "\\ProcessHacker-50.png"); + Win32.ImageResizeFile(150, "ProcessHacker\\resources\\ProcessHacker.png", BuildOutputFolder + "\\ProcessHacker-150.png"); + + if ((Flags & BuildFlags.Build32bit) == BuildFlags.Build32bit) + { + // create the package manifest + string appxManifestString = Properties.Resources.AppxManifest; + appxManifestString = appxManifestString.Replace("PH_APPX_ARCH", "x86"); + appxManifestString = appxManifestString.Replace("PH_APPX_VERSION", BuildLongVersion); + File.WriteAllText(BuildOutputFolder + "\\AppxManifest32.xml", appxManifestString); + + // create the package mapping file + StringBuilder packageMap32 = new StringBuilder(0x100); + packageMap32.AppendLine("[Files]"); + packageMap32.AppendLine("\"" + BuildOutputFolder + "\\AppxManifest32.xml\" \"AppxManifest.xml\""); + packageMap32.AppendLine("\"" + BuildOutputFolder + "\\ProcessHacker-44.png\" \"Assets\\ProcessHacker-44.png\""); + packageMap32.AppendLine("\"" + BuildOutputFolder + "\\ProcessHacker-50.png\" \"Assets\\ProcessHacker-50.png\""); + packageMap32.AppendLine("\"" + BuildOutputFolder + "\\ProcessHacker-150.png\" \"Assets\\ProcessHacker-150.png\""); + + var filesToAdd = Directory.GetFiles("bin\\Release32", "*", SearchOption.AllDirectories); + foreach (string filePath in filesToAdd) + { + // Ignore junk files + if (filePath.EndsWith(".pdb", StringComparison.OrdinalIgnoreCase) || + filePath.EndsWith(".iobj", StringComparison.OrdinalIgnoreCase) || + filePath.EndsWith(".ipdb", StringComparison.OrdinalIgnoreCase) || + filePath.EndsWith(".exp", StringComparison.OrdinalIgnoreCase) || + filePath.EndsWith(".lib", StringComparison.OrdinalIgnoreCase)) + { + continue; + } + + packageMap32.AppendLine("\"" + filePath + "\" \"" + filePath.Substring("bin\\Release32\\".Length) + "\""); + } + File.WriteAllText(BuildOutputFolder + "\\package32.map", packageMap32.ToString()); + + // create the package + Win32.ShellExecute( + makeAppxExePath, + "pack /o /f " + BuildOutputFolder + "\\package32.map /p " + + BuildOutputFolder + "\\processhacker-build-package-x32.appx" + ); + //Program.PrintColorMessage(Environment.NewLine + error, ConsoleColor.Gray); + + // sign the package + Win32.ShellExecute( + signToolExePath, + "sign /v /fd SHA256 /a /f " + BuildOutputFolder + "\\processhacker-appx.pfx /td SHA256 " + + BuildOutputFolder + "\\processhacker-build-package-x32.appx" + ); + //Program.PrintColorMessage(Environment.NewLine + error, ConsoleColor.Gray); + } + + if ((Flags & BuildFlags.Build64bit) == BuildFlags.Build64bit) + { + // create the package manifest + string appxManifestString = Properties.Resources.AppxManifest; + appxManifestString = appxManifestString.Replace("PH_APPX_ARCH", "x64"); + appxManifestString = appxManifestString.Replace("PH_APPX_VERSION", BuildLongVersion); + File.WriteAllText(BuildOutputFolder + "\\AppxManifest64.xml", appxManifestString); + + StringBuilder packageMap64 = new StringBuilder(0x100); + packageMap64.AppendLine("[Files]"); + packageMap64.AppendLine("\"" + BuildOutputFolder + "\\AppxManifest64.xml\" \"AppxManifest.xml\""); + packageMap64.AppendLine("\"" + BuildOutputFolder + "\\ProcessHacker-44.png\" \"Assets\\ProcessHacker-44.png\""); + packageMap64.AppendLine("\"" + BuildOutputFolder + "\\ProcessHacker-50.png\" \"Assets\\ProcessHacker-50.png\""); + packageMap64.AppendLine("\"" + BuildOutputFolder + "\\ProcessHacker-150.png\" \"Assets\\ProcessHacker-150.png\""); + + var filesToAdd = Directory.GetFiles("bin\\Release64", "*", SearchOption.AllDirectories); + foreach (string filePath in filesToAdd) + { + // Ignore junk files + if (filePath.EndsWith(".pdb", StringComparison.OrdinalIgnoreCase) || + filePath.EndsWith(".iobj", StringComparison.OrdinalIgnoreCase) || + filePath.EndsWith(".ipdb", StringComparison.OrdinalIgnoreCase) || + filePath.EndsWith(".exp", StringComparison.OrdinalIgnoreCase) || + filePath.EndsWith(".lib", StringComparison.OrdinalIgnoreCase)) + { + continue; + } + + packageMap64.AppendLine("\"" + filePath + "\" \"" + filePath.Substring("bin\\Release64\\".Length) + "\""); + } + File.WriteAllText(BuildOutputFolder + "\\package64.map", packageMap64.ToString()); + + // create the package + Win32.ShellExecute( + makeAppxExePath, + "pack /o /f " + BuildOutputFolder + "\\package64.map /p " + + BuildOutputFolder + "\\processhacker-build-package-x64.appx" + ); + //Program.PrintColorMessage(Environment.NewLine + error, ConsoleColor.Gray); + + // sign the package + Win32.ShellExecute( + signToolExePath, + "sign /v /fd SHA256 /a /f " + BuildOutputFolder + "\\processhacker-appx.pfx /td SHA256 " + + BuildOutputFolder + "\\processhacker-build-package-x64.appx" + ); + //Program.PrintColorMessage(Environment.NewLine + error, ConsoleColor.Gray); + } + + { + // create the appx bundle map + StringBuilder bundleMap = new StringBuilder(0x100); + bundleMap.AppendLine("[Files]"); + bundleMap.AppendLine("\"" + BuildOutputFolder + "\\processhacker-build-package-x32.appx\" \"processhacker-build-package-x32.appx\""); + bundleMap.AppendLine("\"" + BuildOutputFolder + "\\processhacker-build-package-x64.appx\" \"processhacker-build-package-x64.appx\""); + File.WriteAllText(BuildOutputFolder + "\\bundle.map", bundleMap.ToString()); + + if (File.Exists(BuildOutputFolder + "\\processhacker-build-package.appxbundle")) + File.Delete(BuildOutputFolder + "\\processhacker-build-package.appxbundle"); + + // create the appx bundle package + Win32.ShellExecute( + makeAppxExePath, + "bundle /f " + BuildOutputFolder + "\\bundle.map /p " + + BuildOutputFolder + "\\processhacker-build-package.appxbundle" + ); + //Program.PrintColorMessage(Environment.NewLine + error, ConsoleColor.Gray); + + // sign the appx bundle package + Win32.ShellExecute( + signToolExePath, + "sign /v /fd SHA256 /a /f " + BuildOutputFolder + "\\processhacker-appx.pfx /td SHA256 " + + BuildOutputFolder + "\\processhacker-build-package.appxbundle" + ); + //Program.PrintColorMessage(Environment.NewLine + error, ConsoleColor.Gray); + } + + foreach (string file in cleanupAppxArray) + { + if (File.Exists(file)) + File.Delete(file); + } + } + catch (Exception ex) + { + Program.PrintColorMessage("[ERROR] " + ex, ConsoleColor.Red); + } + } + + public static bool BuildAppxSignature(string BuildOutputFolder) + { + string sdkRootPath = string.Empty; + string[] cleanupAppxArray = + { + BuildOutputFolder + "\\processhacker-appx.pvk", + BuildOutputFolder + "\\processhacker-appx.cer", + BuildOutputFolder + "\\processhacker-appx.pfx" + }; + + Program.PrintColorMessage("Building Appx Signature...", ConsoleColor.Cyan); + + using (var view32 = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32)) + { + using (var kitsroot = view32.OpenSubKey("Microsoft\\Windows Kits\\Installed Roots\\", false)) + { + sdkRootPath = (string)kitsroot.GetValue("WdkBinRootVersioned", string.Empty); + } + } + + if (!string.IsNullOrEmpty(sdkRootPath)) + { + Program.PrintColorMessage("[Skipped] Windows SDK", ConsoleColor.Red); + return false; + } + + string makeCertExePath = Environment.ExpandEnvironmentVariables(sdkRootPath + "\\x64\\MakeCert.exe"); + string pvk2PfxExePath = Environment.ExpandEnvironmentVariables(sdkRootPath + "\\x64\\Pvk2Pfx.exe"); + string certUtilExePath = Win32.SearchFile("certutil.exe"); + + try + { + foreach (string file in cleanupAppxArray) + { + if (File.Exists(file)) + File.Delete(file); + } + + string output = Win32.ShellExecute(makeCertExePath, + "/n " + + "\"CN=ProcessHacker, O=ProcessHacker, C=AU\" " + + "/r /h 0 " + + "/eku \"1.3.6.1.5.5.7.3.3,1.3.6.1.4.1.311.10.3.13\" " + + "/sv " + + BuildOutputFolder + "\\processhacker-appx.pvk " + + BuildOutputFolder + "\\processhacker-appx.cer " + ); + + if (!string.IsNullOrEmpty(output) && !output.Equals("Succeeded", StringComparison.OrdinalIgnoreCase)) + { + Program.PrintColorMessage("[MakeCert] " + output, ConsoleColor.Red); + return false; + } + + output = Win32.ShellExecute(pvk2PfxExePath, + "/pvk " + BuildOutputFolder + "\\processhacker-appx.pvk " + + "/spc " + BuildOutputFolder + "\\processhacker-appx.cer " + + "/pfx " + BuildOutputFolder + "\\processhacker-appx.pfx " + ); + + if (!string.IsNullOrEmpty(output)) + { + Program.PrintColorMessage("[Pvk2Pfx] " + output, ConsoleColor.Red); + return false; + } + + output = Win32.ShellExecute(certUtilExePath, + "-addStore TrustedPeople " + BuildOutputFolder + "\\processhacker-appx.cer" + ); + + if (!string.IsNullOrEmpty(output) && !output.Contains("command completed successfully")) + { + Program.PrintColorMessage("[Certutil] " + output, ConsoleColor.Red); + return false; + } + } + catch (Exception ex) + { + Program.PrintColorMessage("[ERROR] " + ex, ConsoleColor.Red); + return false; + } + + return true; + } + + public static bool CleanupAppxSignature() + { + try + { + X509Store store = new X509Store(StoreName.TrustedPeople, StoreLocation.LocalMachine); + + store.Open(OpenFlags.ReadWrite); + + foreach (X509Certificate2 c in store.Certificates) + { + if (c.Subject.Equals("CN=ProcessHacker, O=ProcessHacker, C=AU", StringComparison.OrdinalIgnoreCase)) + { + Console.WriteLine("Removing: {0}", c.Subject); + store.Remove(c); + } + } + } + catch (Exception ex) + { + Program.PrintColorMessage("[ERROR] " + ex, ConsoleColor.Red); + return false; + } + + return true; + } + } +} diff --git a/tools/CustomBuildTool/Source Files/Build.cs b/tools/CustomBuildTool/Source Files/Build.cs index 475634f95441..7a7109b93164 100644 --- a/tools/CustomBuildTool/Source Files/Build.cs +++ b/tools/CustomBuildTool/Source Files/Build.cs @@ -22,9 +22,9 @@ using System; using System.IO; +using System.Net; using System.Net.Http; using System.Security; -using System.Security.Cryptography.X509Certificates; using System.Text; namespace CustomBuildTool @@ -32,7 +32,6 @@ namespace CustomBuildTool [SuppressUnmanagedCodeSecurity] public static class Build { - private static readonly string SdkVersion = "10.0.16299.0"; private static DateTime TimeStart; private static bool BuildNightly; private static bool GitExportBuild; @@ -57,12 +56,25 @@ public static class Build private static string BuildSetupHash; private static string BuildSetupSig; - //private static string BuildWebSetupVersion; - //private static long BuildWebSetupFileLength; - //private static string BuildWebSetupHash; - //private static string BuildWebSetupSig; +#region Build Config + private static readonly string[] Build_Release_Files = + { + "\\processhacker-build-checksums.txt", + "\\processhacker-build-setup.exe", + "\\processhacker-build-bin.zip", + "\\processhacker-build-src.zip", + "\\processhacker-build-sdk.zip", + "\\processhacker-build-pdb.zip" + }; + private static readonly string[] Build_Nightly_Files = + { + "\\processhacker-build-checksums.txt", + "\\processhacker-build-setup.exe", + "\\processhacker-build-bin.zip", + //"\\processhacker-build-src.zip", + //"\\processhacker-build-sdk.zip" + }; - #region Build Config private static readonly string[] sdk_directories = { "sdk", @@ -155,7 +167,6 @@ public static class Build public static bool InitializeBuildEnvironment(bool CheckDependencies) { - System.Net.ServicePointManager.Expect100Continue = false; TimeStart = DateTime.Now; BuildOutputFolder = "build\\output"; MSBuildExePath = VisualStudio.GetMsbuildFilePath(); @@ -227,20 +238,20 @@ public static bool InitializeBuildEnvironment(bool CheckDependencies) public static void CleanupBuildEnvironment() { - string[] cleanupFileArray = - { - BuildOutputFolder, - "bin", - "sdk", - }; - try { - foreach (string file in cleanupFileArray) + foreach (string file in Build_Release_Files) { - if (Directory.Exists(file)) - Directory.Delete(file, true); + string sourceFile = BuildOutputFolder + file; + + if (File.Exists(file)) + File.Delete(file); } + + if (Directory.Exists("sdk")) + { + Directory.Delete("sdk", true); + } } catch (Exception ex) { @@ -970,12 +981,103 @@ public static bool BuildUpdateSignature() return true; } + //public static bool BuildRenameReleaseFiles() + //{ + // try + // { + // foreach (string file in Build_Release_Files) + // { + // string sourceFile = BuildOutputFolder + file; + // string destinationFile = BuildOutputFolder + file.Replace("-build-", $"-{BuildVersion}-"); + // + // if (File.Exists(destinationFile)) + // File.Delete(destinationFile); + // + // if (File.Exists(sourceFile)) + // File.Move(sourceFile, destinationFile); + // } + // } + // catch (Exception ex) + // { + // Program.PrintColorMessage("[WebServiceUploadBuild] " + ex, ConsoleColor.Red); + // return false; + // } + // + // return true; + //} + public static string GetBuildLogString() { return Win32.ShellExecute(GitExePath, "log -n 1800 --graph --pretty=format:\"%C(yellow)%h%Creset %C(bold blue)%an%Creset %s %C(dim green)(%cr)\" --abbrev-commit ").Trim(); } - public static void WebServiceUpdateConfig() + public static bool BuildSolution(string Solution, BuildFlags Flags) + { + if ((Flags & BuildFlags.Build32bit) == BuildFlags.Build32bit) + { + StringBuilder compilerOptions = new StringBuilder(); + Program.PrintColorMessage("Building " + Path.GetFileNameWithoutExtension(Solution) + " (", ConsoleColor.Cyan, false, Flags); + Program.PrintColorMessage("x32", ConsoleColor.Green, false, Flags); + Program.PrintColorMessage(")...", ConsoleColor.Cyan, true, Flags); + + if (Flags.HasFlag(BuildFlags.BuildApi)) + compilerOptions.Append("PH_BUILD_API;"); + if (!string.IsNullOrEmpty(BuildCommit)) + compilerOptions.Append($"PHAPP_VERSION_COMMITHASH=\"{BuildCommit.Substring(0, 8)}\";"); + compilerOptions.Append($"PHAPP_VERSION_REVISION=\"{BuildRevision}\";"); + compilerOptions.Append($"PHAPP_VERSION_BUILD=\"{BuildCount}\""); + + string error32 = Win32.ShellExecute( + MSBuildExePath, + "/m /nologo /verbosity:quiet " + + "/p:Configuration=" + (Flags.HasFlag(BuildFlags.BuildDebug) ? "Debug " : "Release ") + + "/p:Platform=Win32 " + + "/p:ExternalCompilerOptions=\"" + compilerOptions.ToString() + "\" " + + Solution + ); + + if (!string.IsNullOrEmpty(error32)) + { + Program.PrintColorMessage("[ERROR] " + error32, ConsoleColor.Red, true, Flags | BuildFlags.BuildVerbose); + return false; + } + } + + if ((Flags & BuildFlags.Build64bit) == BuildFlags.Build64bit) + { + StringBuilder compilerOptions = new StringBuilder(); + Program.PrintColorMessage("Building " + Path.GetFileNameWithoutExtension(Solution) + " (", ConsoleColor.Cyan, false, Flags); + Program.PrintColorMessage("x64", ConsoleColor.Green, false, Flags); + Program.PrintColorMessage(")...", ConsoleColor.Cyan, true, Flags); + + if (Flags.HasFlag(BuildFlags.BuildApi)) + compilerOptions.Append("PH_BUILD_API;"); + if (!string.IsNullOrEmpty(BuildCommit)) + compilerOptions.Append($"PHAPP_VERSION_COMMITHASH=\"{BuildCommit.Substring(0, 8)}\";"); + compilerOptions.Append($"PHAPP_VERSION_REVISION=\"{BuildRevision}\";"); + compilerOptions.Append($"PHAPP_VERSION_BUILD=\"{BuildCount}\""); + + string error64 = Win32.ShellExecute( + MSBuildExePath, + "/m /nologo /verbosity:quiet " + + "/p:Configuration=" + (Flags.HasFlag(BuildFlags.BuildDebug) ? "Debug " : "Release ") + + "/p:Platform=x64 " + + "/p:ExternalCompilerOptions=\"" + compilerOptions.ToString() + "\" " + + Solution + ); + + if (!string.IsNullOrEmpty(error64)) + { + Program.PrintColorMessage("[ERROR] " + error64, ConsoleColor.Red, true, Flags | BuildFlags.BuildVerbose); + return false; + } + } + + return true; + } + + + public static bool BuildDeployUpdateConfig() { string accountName; string projectName; @@ -986,30 +1088,30 @@ public static void WebServiceUpdateConfig() string buildMessage; string buildPostString; - if (string.IsNullOrEmpty(BuildVersion)) - return; - if (string.IsNullOrEmpty(BuildSetupHash)) - return; - if (string.IsNullOrEmpty(BuildSetupSig)) - return; - if (string.IsNullOrEmpty(BuildBinHash)) - return; - if (string.IsNullOrEmpty(BuildBinSig)) - return; - accountName = Environment.ExpandEnvironmentVariables("%APPVEYOR_ACCOUNT_NAME%").Replace("%APPVEYOR_ACCOUNT_NAME%", string.Empty); projectName = Environment.ExpandEnvironmentVariables("%APPVEYOR_PROJECT_NAME%").Replace("%APPVEYOR_PROJECT_NAME%", string.Empty); buildPostUrl = Environment.ExpandEnvironmentVariables("%APPVEYOR_BUILD_API%").Replace("%APPVEYOR_BUILD_API%", string.Empty); buildPostApiKey = Environment.ExpandEnvironmentVariables("%APPVEYOR_BUILD_KEY%").Replace("%APPVEYOR_BUILD_KEY%", string.Empty); if (string.IsNullOrEmpty(accountName)) - return; + return true; if (string.IsNullOrEmpty(projectName)) - return; + return true; if (string.IsNullOrEmpty(buildPostUrl)) - return; + return true; if (string.IsNullOrEmpty(buildPostApiKey)) - return; + return true; + + if (string.IsNullOrEmpty(BuildVersion)) + return true; + if (string.IsNullOrEmpty(BuildSetupHash)) + return true; + if (string.IsNullOrEmpty(BuildSetupSig)) + return true; + if (string.IsNullOrEmpty(BuildBinHash)) + return true; + if (string.IsNullOrEmpty(BuildBinSig)) + return true; buildChangelog = Win32.ShellExecute(GitExePath, "log -n 30 --date=format:%Y-%m-%d --pretty=format:\"[%cd] %s (%an)\""); buildSummary = Win32.ShellExecute(GitExePath, "log -n 5 --date=format:%Y-%m-%d --pretty=format:\"[%cd] %s (%an)\" --abbrev-commit"); @@ -1022,12 +1124,12 @@ public static void WebServiceUpdateConfig() BuildCommit = BuildCommit, BuildMessage = buildMessage, - BinUrl = $"https://ci.appveyor.com/api/projects/%7BaccountName%7D/%7BprojectName%7D/artifacts/processhacker-%7BBuildVersion%7D-bin.zip", + BinUrl = $"https://ci.appveyor.com/api/projects/%7BaccountName%7D/%7BprojectName%7D/artifacts/processhacker-build-bin.zip", BinLength = BuildBinFileLength.ToString(), BinHash = BuildBinHash, BinSig = BuildBinSig, - SetupUrl = $"https://ci.appveyor.com/api/projects/%7BaccountName%7D/%7BprojectName%7D/artifacts/processhacker-%7BBuildVersion%7D-setup.exe", + SetupUrl = $"https://ci.appveyor.com/api/projects/%7BaccountName%7D/%7BprojectName%7D/artifacts/processhacker-build-setup.exe", SetupLength = BuildSetupFileLength.ToString(), SetupHash = BuildSetupHash, SetupSig = BuildSetupSig, @@ -1037,7 +1139,7 @@ public static void WebServiceUpdateConfig() }); if (string.IsNullOrEmpty(buildPostString)) - return; + return false; Program.PrintColorMessage("Updating Build WebService... " + BuildVersion, ConsoleColor.Cyan); @@ -1050,107 +1152,93 @@ public static void WebServiceUpdateConfig() var httpTask = client.PostAsync(buildPostUrl, new StringContent(buildPostString, Encoding.UTF8, "application/json")); httpTask.Wait(); - if (httpTask.Result.IsSuccessStatusCode) - { - // Update Appveyor build version string. - Win32.ShellExecute("appveyor", $"UpdateBuild -Version \"{BuildVersion}\" "); - } - else + if (!httpTask.Result.IsSuccessStatusCode) { Program.PrintColorMessage("[UpdateBuildWebService] " + httpTask.Result, ConsoleColor.Red); + return false; } } } catch (Exception ex) { Program.PrintColorMessage("[UpdateBuildWebService] " + ex, ConsoleColor.Red); + return false; } - } - - public static bool AppveyorUploadBuildFiles() - { - string buildPostKey; - string buildPostUrl; - string[] buildFileArray = - { - //"\\processhacker-build-websetup.exe", - "\\processhacker-build-setup.exe", - "\\processhacker-build-bin.zip", - "\\processhacker-build-checksums.txt", - "\\processhacker-build-pdb.zip" - }; - string[] releaseFileArray = - { - //"\\processhacker-build-websetup.exe", - "\\processhacker-build-setup.exe", - "\\processhacker-build-bin.zip", - "\\processhacker-build-checksums.txt" - }; - if (!BuildNightly) + if (!AppVeyor.UpdateBuildVersion(BuildVersion)) // HACK: Update Appveyor build version string. + { return false; + } + + return true; + } - buildPostKey = Environment.ExpandEnvironmentVariables("%APPVEYOR_BUILD_KEY%").Replace("%APPVEYOR_BUILD_KEY%", string.Empty); - buildPostUrl = Environment.ExpandEnvironmentVariables("%APPVEYOR_BUILD_URL%").Replace("%APPVEYOR_BUILD_URL%", string.Empty); + public static bool BuildDeployUploadArtifacts() + { + string buildPostUrl = Environment.ExpandEnvironmentVariables("%APPVEYOR_NIGHTLY_URL%").Replace("%APPVEYOR_NIGHTLY_URL%", string.Empty); + string buildPostKey = Environment.ExpandEnvironmentVariables("%APPVEYOR_BUILD_KEY%").Replace("%APPVEYOR_BUILD_KEY%", string.Empty); if (string.IsNullOrEmpty(buildPostKey)) return false; if (string.IsNullOrEmpty(buildPostUrl)) return false; - try - { - foreach (string file in buildFileArray) - { - string sourceFile = BuildOutputFolder + file; - string destinationFile = BuildOutputFolder + file.Replace("-build-", $"-{BuildVersion}-"); - - if (File.Exists(destinationFile)) - File.Delete(destinationFile); - - if (File.Exists(sourceFile)) - File.Move(sourceFile, destinationFile); - } - } - catch (Exception ex) - { - Program.PrintColorMessage("[WebServiceUploadBuild] " + ex, ConsoleColor.Red); - return false; - } + Console.Write(Environment.NewLine); try { - foreach (string file in buildFileArray) + foreach (string file in Build_Release_Files) { - string sourceFile = BuildOutputFolder + file.Replace("-build-", $"-{BuildVersion}-"); - string filename = Path.GetFileName(BuildOutputFolder + sourceFile); + string sourceFile = BuildOutputFolder + file; + string filename = Path.GetFileName(sourceFile); if (File.Exists(sourceFile)) { - using (HttpClient httpClient = new HttpClient()) + string boundary = "---------------------------" + Guid.NewGuid().ToString(); + byte[] boundarybytes = Encoding.ASCII.GetBytes("\r\n--" + boundary + "\r\n"); + byte[] headerbytes = Encoding.UTF8.GetBytes($"Content-Disposition: form-data; name=\"file\"; filename=\"{filename}\"\r\n\r\n"); + + HttpWebRequest request = (HttpWebRequest)WebRequest.Create(new Uri(buildPostUrl)); + request.KeepAlive = true; + request.SendChunked = true; + request.AllowWriteStreamBuffering = true; + request.ServicePoint.Expect100Continue = false; + request.ServicePoint.ReceiveBufferSize = 4096; + request.ServicePoint.ConnectionLeaseTimeout = System.Threading.Timeout.Infinite; + request.ReadWriteTimeout = System.Threading.Timeout.Infinite; + request.Timeout = System.Threading.Timeout.Infinite; + request.Method = WebRequestMethods.Http.Post; + request.ContentType = "multipart/form-data; boundary=" + boundary; + request.Headers.Add("X-ApiKey", buildPostKey); + + Program.PrintColorMessage($"Uploading {filename}...", ConsoleColor.Cyan, true); + using (FileStream fileStream = File.OpenRead(sourceFile)) - using (HttpContent httpContent = new StreamContent(fileStream)) + using (BufferedStream localStream = new BufferedStream(fileStream)) + using (BufferedStream remoteStream = new BufferedStream(request.GetRequestStream())) { - httpClient.DefaultRequestHeaders.TransferEncodingChunked = true; - httpClient.DefaultRequestHeaders.Add("X-ApiKey", buildPostKey); - httpContent.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/octet-stream"); - httpContent.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("form-data") - { - Name = "\"file\"", - FileName = $"\"{filename}\"", - }; + int bytesRead = 0; + var totalRead = 0; + byte[] buffer = new byte[4096]; - Console.WriteLine($"Uploading {filename}..."); + remoteStream.Write(boundarybytes, 0, boundarybytes.Length); + remoteStream.Write(headerbytes, 0, headerbytes.Length); - using (HttpRequestMessage requestMessage = new HttpRequestMessage(new HttpMethod("POST"), buildPostUrl)) + while ((bytesRead = localStream.Read(buffer, 0, buffer.Length)) != 0) { - requestMessage.Headers.TransferEncodingChunked = true; - requestMessage.Content = httpContent; + totalRead += bytesRead; + remoteStream.Write(buffer, 0, bytesRead); + } - var response = httpClient.SendAsync(requestMessage, HttpCompletionOption.ResponseHeadersRead); - response.Wait(); + remoteStream.Write(boundarybytes, 0, boundarybytes.Length); + } - response.Result.EnsureSuccessStatusCode(); + using (HttpWebResponse response = (HttpWebResponse)request.GetResponse()) + { + if (response.StatusCode != HttpStatusCode.OK) + { + Program.PrintColorMessage("[HttpWebResponse]" + response.StatusDescription, ConsoleColor.Red); + return false; } } } @@ -1162,19 +1250,29 @@ public static bool AppveyorUploadBuildFiles() return false; } + if (!AppVeyor.AppVeyorNightlyBuild()) + { + Program.PrintColorMessage("[SKIPPED] (Appveyor missing)", ConsoleColor.Yellow); + return true; + } + try { - foreach (string file in releaseFileArray) + foreach (string file in Build_Nightly_Files) { - var sourceFile = BuildOutputFolder + file.Replace("-build-", $"-{BuildVersion}-"); + var sourceFile = BuildOutputFolder + file; if (File.Exists(sourceFile)) { - Win32.ShellExecute("appveyor", "PushArtifact " + sourceFile); + if (!AppVeyor.UploadFile(sourceFile)) + { + Program.PrintColorMessage("[WebServiceAppveyorUploadFile]", ConsoleColor.Red); + return false; + } } else { - Program.PrintColorMessage("[Build] missing file: " + sourceFile, ConsoleColor.Yellow); + Program.PrintColorMessage("[SKIPPED] missing file: " + sourceFile, ConsoleColor.Yellow); } } } @@ -1184,346 +1282,18 @@ public static bool AppveyorUploadBuildFiles() return false; } - try - { - Win32.ShellExecute("appveyor", $"UpdateBuild -Version \"{BuildVersion}\" "); - } - catch (Exception ex) - { - Program.PrintColorMessage("[WebServiceAppveyorUpdateBuild] " + ex, ConsoleColor.Red); - return false; - } - return true; } - public static bool BuildSolution(string Solution, BuildFlags Flags) - { - if ((Flags & BuildFlags.Build32bit) == BuildFlags.Build32bit) - { - StringBuilder compilerOptions = new StringBuilder(); - Program.PrintColorMessage("Building " + Path.GetFileNameWithoutExtension(Solution) + " (", ConsoleColor.Cyan, false, Flags); - Program.PrintColorMessage("x32", ConsoleColor.Green, false, Flags); - Program.PrintColorMessage(")...", ConsoleColor.Cyan, true, Flags); - - if (Flags.HasFlag(BuildFlags.BuildApi)) - compilerOptions.Append("PH_BUILD_API;"); - if (!string.IsNullOrEmpty(BuildCommit)) - compilerOptions.Append($"PHAPP_VERSION_COMMITHASH=\"{BuildCommit.Substring(0, 8)}\";"); - compilerOptions.Append($"PHAPP_VERSION_REVISION=\"{BuildRevision}\";"); - compilerOptions.Append($"PHAPP_VERSION_BUILD=\"{BuildCount}\""); - - string error32 = Win32.ShellExecute( - MSBuildExePath, - "/m /nologo /verbosity:quiet " + - "/p:Configuration=" + (Flags.HasFlag(BuildFlags.BuildDebug) ? "Debug " : "Release ") + - "/p:Platform=Win32 " + - "/p:ExternalCompilerOptions=\"" + compilerOptions.ToString() + "\" " + - "/p:ExternalDebugOptions=\"" + (Flags.HasFlag(BuildFlags.BuildDebug) ? "true" : "false") + "\" " + - Solution - ); - - if (!string.IsNullOrEmpty(error32)) - { - Program.PrintColorMessage("[ERROR] " + error32, ConsoleColor.Red, true, Flags | BuildFlags.BuildVerbose); - return false; - } - } - - if ((Flags & BuildFlags.Build64bit) == BuildFlags.Build64bit) - { - StringBuilder compilerOptions = new StringBuilder(); - Program.PrintColorMessage("Building " + Path.GetFileNameWithoutExtension(Solution) + " (", ConsoleColor.Cyan, false, Flags); - Program.PrintColorMessage("x64", ConsoleColor.Green, false, Flags); - Program.PrintColorMessage(")...", ConsoleColor.Cyan, true, Flags); - - if (Flags.HasFlag(BuildFlags.BuildApi)) - compilerOptions.Append("PH_BUILD_API;"); - if (!string.IsNullOrEmpty(BuildCommit)) - compilerOptions.Append($"PHAPP_VERSION_COMMITHASH=\"{BuildCommit.Substring(0, 8)}\";"); - compilerOptions.Append($"PHAPP_VERSION_REVISION=\"{BuildRevision}\";"); - compilerOptions.Append($"PHAPP_VERSION_BUILD=\"{BuildCount}\""); - - string error64 = Win32.ShellExecute( - MSBuildExePath, - "/m /nologo /verbosity:quiet " + - "/p:Configuration=" + (Flags.HasFlag(BuildFlags.BuildDebug) ? "Debug " : "Release ") + - "/p:Platform=x64 " + - "/p:ExternalCompilerOptions=\"" + compilerOptions.ToString() + "\" " + - "/p:ExternalDebugOptions=\"" + (Flags.HasFlag(BuildFlags.BuildDebug) ? "true" : "false") + "\" " + - Solution - ); - - if (!string.IsNullOrEmpty(error64)) - { - Program.PrintColorMessage("[ERROR] " + error64, ConsoleColor.Red, true, Flags | BuildFlags.BuildVerbose); - return false; - } - } - - return true; - } -#region Appx Package public static void BuildAppxPackage(BuildFlags Flags) { - string[] cleanupAppxArray = - { - BuildOutputFolder + "\\AppxManifest32.xml", - BuildOutputFolder + "\\AppxManifest64.xml", - BuildOutputFolder + "\\package32.map", - BuildOutputFolder + "\\package64.map", - BuildOutputFolder + "\\bundle.map", - BuildOutputFolder + "\\ProcessHacker-44.png", - BuildOutputFolder + "\\ProcessHacker-50.png", - BuildOutputFolder + "\\ProcessHacker-150.png" - }; - - Program.PrintColorMessage("Building processhacker-build-package.appxbundle...", ConsoleColor.Cyan); - - string makeAppxExePath = Environment.ExpandEnvironmentVariables("%ProgramFiles(x86)%\\Windows Kits\\10\\bin\\" + SdkVersion + "\\x64\\MakeAppx.exe"); - string signToolExePath = Environment.ExpandEnvironmentVariables("%ProgramFiles(x86)%\\Windows Kits\\10\\bin\\" + SdkVersion + "\\x64\\SignTool.exe"); - - try - { - Win32.ImageResizeFile(44, "ProcessHacker\\resources\\ProcessHacker.png", BuildOutputFolder + "\\ProcessHacker-44.png"); - Win32.ImageResizeFile(50, "ProcessHacker\\resources\\ProcessHacker.png", BuildOutputFolder + "\\ProcessHacker-50.png"); - Win32.ImageResizeFile(150, "ProcessHacker\\resources\\ProcessHacker.png", BuildOutputFolder + "\\ProcessHacker-150.png"); - - if ((Flags & BuildFlags.Build32bit) == BuildFlags.Build32bit) - { - // create the package manifest - string appxManifestString = Properties.Resources.AppxManifest; - appxManifestString = appxManifestString.Replace("PH_APPX_ARCH", "x86"); - appxManifestString = appxManifestString.Replace("PH_APPX_VERSION", BuildLongVersion); - File.WriteAllText(BuildOutputFolder + "\\AppxManifest32.xml", appxManifestString); - - // create the package mapping file - StringBuilder packageMap32 = new StringBuilder(0x100); - packageMap32.AppendLine("[Files]"); - packageMap32.AppendLine("\"" + BuildOutputFolder + "\\AppxManifest32.xml\" \"AppxManifest.xml\""); - packageMap32.AppendLine("\"" + BuildOutputFolder + "\\ProcessHacker-44.png\" \"Assets\\ProcessHacker-44.png\""); - packageMap32.AppendLine("\"" + BuildOutputFolder + "\\ProcessHacker-50.png\" \"Assets\\ProcessHacker-50.png\""); - packageMap32.AppendLine("\"" + BuildOutputFolder + "\\ProcessHacker-150.png\" \"Assets\\ProcessHacker-150.png\""); - - var filesToAdd = Directory.GetFiles("bin\\Release32", "*", SearchOption.AllDirectories); - foreach (string filePath in filesToAdd) - { - // Ignore junk files - if (filePath.EndsWith(".pdb", StringComparison.OrdinalIgnoreCase) || - filePath.EndsWith(".iobj", StringComparison.OrdinalIgnoreCase) || - filePath.EndsWith(".ipdb", StringComparison.OrdinalIgnoreCase) || - filePath.EndsWith(".exp", StringComparison.OrdinalIgnoreCase) || - filePath.EndsWith(".lib", StringComparison.OrdinalIgnoreCase)) - { - continue; - } - - packageMap32.AppendLine("\"" + filePath + "\" \"" + filePath.Substring("bin\\Release32\\".Length) + "\""); - } - File.WriteAllText(BuildOutputFolder + "\\package32.map", packageMap32.ToString()); - - // create the package - Win32.ShellExecute( - makeAppxExePath, - "pack /o /f " + BuildOutputFolder + "\\package32.map /p " + - BuildOutputFolder + "\\processhacker-build-package-x32.appx" - ); - //Program.PrintColorMessage(Environment.NewLine + error, ConsoleColor.Gray); - - // sign the package - Win32.ShellExecute( - signToolExePath, - "sign /v /fd SHA256 /a /f " + BuildOutputFolder + "\\processhacker-appx.pfx /td SHA256 " + - BuildOutputFolder + "\\processhacker-build-package-x32.appx" - ); - //Program.PrintColorMessage(Environment.NewLine + error, ConsoleColor.Gray); - } - - if ((Flags & BuildFlags.Build64bit) == BuildFlags.Build64bit) - { - // create the package manifest - string appxManifestString = Properties.Resources.AppxManifest; - appxManifestString = appxManifestString.Replace("PH_APPX_ARCH", "x64"); - appxManifestString = appxManifestString.Replace("PH_APPX_VERSION", BuildLongVersion); - File.WriteAllText(BuildOutputFolder + "\\AppxManifest64.xml", appxManifestString); - - StringBuilder packageMap64 = new StringBuilder(0x100); - packageMap64.AppendLine("[Files]"); - packageMap64.AppendLine("\"" + BuildOutputFolder + "\\AppxManifest64.xml\" \"AppxManifest.xml\""); - packageMap64.AppendLine("\"" + BuildOutputFolder + "\\ProcessHacker-44.png\" \"Assets\\ProcessHacker-44.png\""); - packageMap64.AppendLine("\"" + BuildOutputFolder + "\\ProcessHacker-50.png\" \"Assets\\ProcessHacker-50.png\""); - packageMap64.AppendLine("\"" + BuildOutputFolder + "\\ProcessHacker-150.png\" \"Assets\\ProcessHacker-150.png\""); - - var filesToAdd = Directory.GetFiles("bin\\Release64", "*", SearchOption.AllDirectories); - foreach (string filePath in filesToAdd) - { - // Ignore junk files - if (filePath.EndsWith(".pdb", StringComparison.OrdinalIgnoreCase) || - filePath.EndsWith(".iobj", StringComparison.OrdinalIgnoreCase) || - filePath.EndsWith(".ipdb", StringComparison.OrdinalIgnoreCase) || - filePath.EndsWith(".exp", StringComparison.OrdinalIgnoreCase) || - filePath.EndsWith(".lib", StringComparison.OrdinalIgnoreCase)) - { - continue; - } - - packageMap64.AppendLine("\"" + filePath + "\" \"" + filePath.Substring("bin\\Release64\\".Length) + "\""); - } - File.WriteAllText(BuildOutputFolder + "\\package64.map", packageMap64.ToString()); - - // create the package - Win32.ShellExecute( - makeAppxExePath, - "pack /o /f " + BuildOutputFolder + "\\package64.map /p " + - BuildOutputFolder + "\\processhacker-build-package-x64.appx" - ); - //Program.PrintColorMessage(Environment.NewLine + error, ConsoleColor.Gray); - - // sign the package - Win32.ShellExecute( - signToolExePath, - "sign /v /fd SHA256 /a /f " + BuildOutputFolder + "\\processhacker-appx.pfx /td SHA256 " + - BuildOutputFolder + "\\processhacker-build-package-x64.appx" - ); - //Program.PrintColorMessage(Environment.NewLine + error, ConsoleColor.Gray); - } - - { - // create the appx bundle map - StringBuilder bundleMap = new StringBuilder(0x100); - bundleMap.AppendLine("[Files]"); - bundleMap.AppendLine("\"" + BuildOutputFolder + "\\processhacker-build-package-x32.appx\" \"processhacker-build-package-x32.appx\""); - bundleMap.AppendLine("\"" + BuildOutputFolder + "\\processhacker-build-package-x64.appx\" \"processhacker-build-package-x64.appx\""); - File.WriteAllText(BuildOutputFolder + "\\bundle.map", bundleMap.ToString()); - - if (File.Exists(BuildOutputFolder + "\\processhacker-build-package.appxbundle")) - File.Delete(BuildOutputFolder + "\\processhacker-build-package.appxbundle"); - - // create the appx bundle package - Win32.ShellExecute( - makeAppxExePath, - "bundle /f " + BuildOutputFolder + "\\bundle.map /p " + - BuildOutputFolder + "\\processhacker-build-package.appxbundle" - ); - //Program.PrintColorMessage(Environment.NewLine + error, ConsoleColor.Gray); - - // sign the appx bundle package - Win32.ShellExecute( - signToolExePath, - "sign /v /fd SHA256 /a /f " + BuildOutputFolder + "\\processhacker-appx.pfx /td SHA256 " + - BuildOutputFolder + "\\processhacker-build-package.appxbundle" - ); - //Program.PrintColorMessage(Environment.NewLine + error, ConsoleColor.Gray); - } - - foreach (string file in cleanupAppxArray) - { - if (File.Exists(file)) - File.Delete(file); - } - } - catch (Exception ex) - { - Program.PrintColorMessage("[ERROR] " + ex, ConsoleColor.Red); - } + AppxBuild.BuildAppxPackage(BuildOutputFolder, BuildLongVersion, BuildFlags.Build32bit | BuildFlags.Build64bit | BuildFlags.BuildVerbose); } public static bool BuildAppxSignature() { - string[] cleanupAppxArray = - { - BuildOutputFolder + "\\processhacker-appx.pvk", - BuildOutputFolder + "\\processhacker-appx.cer", - BuildOutputFolder + "\\processhacker-appx.pfx" - }; - - Program.PrintColorMessage("Building Appx Signature...", ConsoleColor.Cyan); - - string makeCertExePath = Environment.ExpandEnvironmentVariables("%ProgramFiles(x86)%\\Windows Kits\\10\\bin\\" + SdkVersion + "\\x64\\MakeCert.exe"); - string pvk2PfxExePath = Environment.ExpandEnvironmentVariables("%ProgramFiles(x86)%\\Windows Kits\\10\\bin\\" + SdkVersion + "\\x64\\Pvk2Pfx.exe"); - string certUtilExePath = Win32.SearchFile("certutil.exe"); - - try - { - foreach (string file in cleanupAppxArray) - { - if (File.Exists(file)) - File.Delete(file); - } - - string output = Win32.ShellExecute(makeCertExePath, - "/n " + - "\"CN=ProcessHacker, O=ProcessHacker, C=AU\" " + - "/r /h 0 " + - "/eku \"1.3.6.1.5.5.7.3.3,1.3.6.1.4.1.311.10.3.13\" " + - "/sv " + - BuildOutputFolder + "\\processhacker-appx.pvk " + - BuildOutputFolder + "\\processhacker-appx.cer " - ); - - if (!string.IsNullOrEmpty(output) && !output.Equals("Succeeded", StringComparison.OrdinalIgnoreCase)) - { - Program.PrintColorMessage("[MakeCert] " + output, ConsoleColor.Red); - return false; - } - - output = Win32.ShellExecute(pvk2PfxExePath, - "/pvk " + BuildOutputFolder + "\\processhacker-appx.pvk " + - "/spc " + BuildOutputFolder + "\\processhacker-appx.cer " + - "/pfx " + BuildOutputFolder + "\\processhacker-appx.pfx " - ); - - if (!string.IsNullOrEmpty(output)) - { - Program.PrintColorMessage("[Pvk2Pfx] " + output, ConsoleColor.Red); - return false; - } - - output = Win32.ShellExecute(certUtilExePath, - "-addStore TrustedPeople " + BuildOutputFolder + "\\processhacker-appx.cer" - ); - - if (!string.IsNullOrEmpty(output) && !output.Contains("command completed successfully")) - { - Program.PrintColorMessage("[Certutil] " + output, ConsoleColor.Red); - return false; - } - } - catch (Exception ex) - { - Program.PrintColorMessage("[ERROR] " + ex, ConsoleColor.Red); - return false; - } - - return true; + return AppxBuild.BuildAppxSignature(BuildOutputFolder); } - - public static bool CleanupAppxSignature() - { - try - { - X509Store store = new X509Store(StoreName.TrustedPeople, StoreLocation.LocalMachine); - - store.Open(OpenFlags.ReadWrite); - - foreach (X509Certificate2 c in store.Certificates) - { - if (c.Subject.Equals("CN=ProcessHacker, O=ProcessHacker, C=AU", StringComparison.OrdinalIgnoreCase)) - { - Console.WriteLine("Removing: {0}", c.Subject); - store.Remove(c); - } - } - } - catch (Exception ex) - { - Program.PrintColorMessage("[ERROR] " + ex, ConsoleColor.Red); - return false; - } - - return true; - } -#endregion } } diff --git a/tools/CustomBuildTool/Source Files/Program.cs b/tools/CustomBuildTool/Source Files/Program.cs index ce29ceb0e980..fb1198e55f55 100644 --- a/tools/CustomBuildTool/Source Files/Program.cs +++ b/tools/CustomBuildTool/Source Files/Program.cs @@ -60,9 +60,7 @@ public static void Main(string[] args) if (!Build.InitializeBuildEnvironment(true)) return; - Build.CleanupAppxSignature(); Build.CleanupBuildEnvironment(); - Build.ShowBuildStats(); } else if (ProgramArgs.ContainsKey("-phapppub_gen")) @@ -226,22 +224,24 @@ public static void Main(string[] args) if (!Build.BuildBinZip()) Environment.Exit(1); - if (!Build.BuildPdbZip()) - Environment.Exit(1); //if (!Build.BuildWebSetupExe()) // Environment.Exit(1); if (!Build.BuildSetupExe()) Environment.Exit(1); + if (!Build.BuildPdbZip()) + Environment.Exit(1); + //Build.BuildSdkZip(); + //Build.BuildSrcZip(); if (!Build.BuildChecksumsFile()) Environment.Exit(1); if (!Build.BuildUpdateSignature()) Environment.Exit(1); - if (!Build.AppveyorUploadBuildFiles()) + if (!Build.BuildDeployUploadArtifacts()) + Environment.Exit(1); + if (!Build.BuildDeployUpdateConfig()) Environment.Exit(1); - - Build.WebServiceUpdateConfig(); } else if (ProgramArgs.ContainsKey("-appxbuild")) { diff --git a/tools/CustomBuildTool/Source Files/Utils.cs b/tools/CustomBuildTool/Source Files/Utils.cs index 9c2920eed7ec..558b0613d4f1 100644 --- a/tools/CustomBuildTool/Source Files/Utils.cs +++ b/tools/CustomBuildTool/Source Files/Utils.cs @@ -305,6 +305,97 @@ private static VisualStudioInstance FindVisualStudioInstance() } } + public static class AppVeyor + { + public static readonly string AppVeyorPath = string.Empty; + + static AppVeyor() + { + try + { + AppVeyorPath = Win32.SearchFile("appveyor"); + } + catch (Exception) { } + } + + public static bool AppVeyorNightlyBuild() + { + return !string.IsNullOrWhiteSpace(AppVeyorPath); + } + + public static bool UpdateBuildVersion(string BuildVersion) + { + try + { + if (!string.IsNullOrWhiteSpace(AppVeyorPath)) + { + Win32.ShellExecute("appveyor", $"UpdateBuild -Version \"{BuildVersion}\" "); + } + } + catch (Exception ex) + { + Program.PrintColorMessage("[VisualStudioInstance] " + ex, ConsoleColor.Red, true); + return false; + } + + return true; + } + + public static bool UploadFile(string FileName) + { + try + { + if (!string.IsNullOrWhiteSpace(AppVeyorPath)) + { + Win32.ShellExecute("appveyor", $"PushArtifact \"{FileName}\" "); + } + } + catch (Exception ex) + { + Program.PrintColorMessage("[UploadFile] " + ex, ConsoleColor.Red, true); + return false; + } + + return true; + } + + private static VisualStudioInstance FindVisualStudioInstance() + { + var setupConfiguration = new SetupConfiguration() as ISetupConfiguration2; + var instanceEnumerator = setupConfiguration.EnumAllInstances(); + var instances = new ISetupInstance2[3]; + + instanceEnumerator.Next(instances.Length, instances, out var instancesFetched); + + if (instancesFetched == 0) + return null; + + do + { + for (int i = 0; i < instancesFetched; i++) + { + var instance = new VisualStudioInstance(instances[i]); + var state = instances[i].GetState(); + var packages = instances[i].GetPackages().Where(package => package.GetId().Contains("Microsoft.Component.MSBuild")); + + if ( + state.HasFlag(InstanceState.Local | InstanceState.Registered | InstanceState.Complete) && + packages.Count() > 0 && + instance.Version.StartsWith("15.0", StringComparison.OrdinalIgnoreCase) + ) + { + return instance; + } + } + + instanceEnumerator.Next(instances.Length, instances, out instancesFetched); + } + while (instancesFetched != 0); + + return null; + } + } + public class VisualStudioInstance { public bool IsLaunchable { get; } diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe b/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe index 90a887ca8d5cc89d2e8a174524802751494aa5ed..62e69c0eafda02487b16f49983610ccb24f871de 100644 GIT binary patch delta 31015 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 L|J*!H{YLqJj{%^; diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb b/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb index 342331eda69f72b86cb1a9feaa4154d967461d23..a5b26fd5605a224bc547a773dc4a2c5429e3b369 100644 GIT binary patch literal 81408 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 Date: Wed, 18 Jul 2018 13:58:35 +1000 Subject: [PATCH 1124/2058] Fix kph ifdef --- phnt/include/ntpsapi.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/phnt/include/ntpsapi.h b/phnt/include/ntpsapi.h index feb7fb06dd0a..7b41008284ae 100644 --- a/phnt/include/ntpsapi.h +++ b/phnt/include/ntpsapi.h @@ -987,6 +987,7 @@ typedef struct _THREAD_NAME_INFORMATION UNICODE_STRING ThreadName; } THREAD_NAME_INFORMATION, *PTHREAD_NAME_INFORMATION; +#if (PHNT_MODE != PHNT_MODE_KERNEL) // private typedef enum _SUBSYSTEM_INFORMATION_TYPE { @@ -994,6 +995,7 @@ typedef enum _SUBSYSTEM_INFORMATION_TYPE SubsystemInformationTypeWSL, MaxSubsystemInformationType } SUBSYSTEM_INFORMATION_TYPE; +#endif // Processes From bbc3abbfce1566c3b429b07668eff9914e8b903d Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 18 Jul 2018 14:01:31 +1000 Subject: [PATCH 1125/2058] Fix kph ifdef --- phnt/include/ntnls.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/phnt/include/ntnls.h b/phnt/include/ntnls.h index 8795b3d06f59..dd6778f02df7 100644 --- a/phnt/include/ntnls.h +++ b/phnt/include/ntnls.h @@ -47,8 +47,10 @@ typedef struct _NLSTABLEINFO PUSHORT LowerCaseTable; } NLSTABLEINFO, *PNLSTABLEINFO; +#if (PHNT_MODE != PHNT_MODE_KERNEL) NTSYSAPI USHORT NlsAnsiCodePage; NTSYSAPI BOOLEAN NlsMbCodePageTag; NTSYSAPI BOOLEAN NlsMbOemCodePageTag; +#endif #endif From 67c1cd7a5b9dc6bab74d8028d928eaea19401c4f Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 18 Jul 2018 14:32:14 +1000 Subject: [PATCH 1126/2058] Update readme layout --- README.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 5a2158f32d76..c76812b24508 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,10 @@ -[![Build status](https://img.shields.io/github/downloads/processhacker/processhacker/total.svg?style=for-the-badge)](https://github.com/processhacker/processhacker/releases) [![Build status](https://img.shields.io/appveyor/ci/processhacker/processhacker.svg?style=for-the-badge)](https://ci.appveyor.com/project/processhacker/processhacker) -[![Build status](https://img.shields.io/github/contributors/processhacker/processhacker.svg?style=for-the-badge)](https://github.com/processhacker/processhacker/graphs/contributors) +[![Build contributors](https://img.shields.io/github/contributors/processhacker/processhacker.svg?style=for-the-badge)](https://github.com/processhacker/processhacker/graphs/contributors) [![Licence](https://img.shields.io/badge/license-GPLv3-blue.svg?style=for-the-badge)](https://www.gnu.org/licenses/gpl-3.0.en.html) +[![Github stats](https://img.shields.io/github/downloads/processhacker/processhacker/total.svg?style=for-the-badge&label=Github%20Downloads)](https://github.com/processhacker/processhacker/releases) +[![SourceForge stats](https://img.shields.io/sourceforge/dt/processhacker.svg?style=for-the-badge&label=SourceForge%20Downloads)](https://sourceforge.net/projects/processhacker/) + +![Logo](https://raw.githubusercontent.com/processhacker2/processhacker/master/ProcessHacker/resources/ProcessHacker.png) ## Process Hacker From b1be7080eea8d6020013fceb9bdc6e9c857fde86 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 18 Jul 2018 14:33:25 +1000 Subject: [PATCH 1127/2058] Fix typo --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c76812b24508..83df32910073 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ [![Build status](https://img.shields.io/appveyor/ci/processhacker/processhacker.svg?style=for-the-badge)](https://ci.appveyor.com/project/processhacker/processhacker) [![Build contributors](https://img.shields.io/github/contributors/processhacker/processhacker.svg?style=for-the-badge)](https://github.com/processhacker/processhacker/graphs/contributors) [![Licence](https://img.shields.io/badge/license-GPLv3-blue.svg?style=for-the-badge)](https://www.gnu.org/licenses/gpl-3.0.en.html) -[![Github stats](https://img.shields.io/github/downloads/processhacker/processhacker/total.svg?style=for-the-badge&label=Github%20Downloads)](https://github.com/processhacker/processhacker/releases) -[![SourceForge stats](https://img.shields.io/sourceforge/dt/processhacker.svg?style=for-the-badge&label=SourceForge%20Downloads)](https://sourceforge.net/projects/processhacker/) +[![Github stats](https://img.shields.io/github/downloads/processhacker/processhacker/total.svg?style=for-the-badge)](https://github.com/processhacker/processhacker/releases) +[![SourceForge stats](https://img.shields.io/sourceforge/dt/processhacker.svg?style=for-the-badge)](https://sourceforge.net/projects/processhacker/) ![Logo](https://raw.githubusercontent.com/processhacker2/processhacker/master/ProcessHacker/resources/ProcessHacker.png) From 3e26da375c1396ea442b22ad938f68cf1270862e Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 18 Jul 2018 18:31:39 +1000 Subject: [PATCH 1128/2058] Improve symbol provider initialization Co-Authored-By: MagicAndre1981 --- phlib/symprv.c | 81 ++++++++++++++++++++++++++++---------------------- 1 file changed, 45 insertions(+), 36 deletions(-) diff --git a/phlib/symprv.c b/phlib/symprv.c index 9a5052e4c3db..d9c313b24f8c 100644 --- a/phlib/symprv.c +++ b/phlib/symprv.c @@ -245,29 +245,16 @@ VOID PhpSymbolProviderCompleteInitialization( VOID ) { - static PH_STRINGREF dbghelpFileName = PH_STRINGREF_INIT(L"dbghelp.dll"); - static PH_STRINGREF symsrvFileName = PH_STRINGREF_INIT(L"symsrv.dll"); - static struct - { - PH_STRINGREF AppendPath; - } locations[] = - { #ifdef _WIN64 - PH_STRINGREF_INIT(L"%ProgramFiles(x86)%\\Windows Kits\\10\\Debuggers\\x64\\"), - PH_STRINGREF_INIT(L"%ProgramFiles%\\Windows Kits\\10\\Debuggers\\x64\\"), - PH_STRINGREF_INIT(L"%ProgramFiles(x86)%\\Windows Kits\\8.1\\Debuggers\\x64\\"), - PH_STRINGREF_INIT(L"%ProgramFiles(x86)%\\Windows Kits\\8.0\\Debuggers\\x64\\"), - PH_STRINGREF_INIT(L"%ProgramFiles%\\Debugging Tools for Windows (x64)\\") + static PH_STRINGREF windowsKitsRootKeyName = PH_STRINGREF_INIT(L"Software\\Wow6432Node\\Microsoft\\Windows Kits\\Installed Roots"); #else - PH_STRINGREF_INIT(L"%ProgramFiles%\\Windows Kits\\10\\Debuggers\\x86\\"), - PH_STRINGREF_INIT(L"%ProgramFiles%\\Windows Kits\\8.1\\Debuggers\\x86\\"), - PH_STRINGREF_INIT(L"%ProgramFiles%\\Windows Kits\\8.0\\Debuggers\\x86\\"), - PH_STRINGREF_INIT(L"%ProgramFiles%\\Debugging Tools for Windows (x86)\\") + static PH_STRINGREF windowsKitsRootKeyName = PH_STRINGREF_INIT(L"Software\\Microsoft\\Windows Kits\\Installed Roots"); #endif - }; - PVOID dbghelpHandle = NULL; - PVOID symsrvHandle = NULL; - ULONG i; + static PH_STRINGREF dbghelpFileName = PH_STRINGREF_INIT(L"dbghelp.dll"); + static PH_STRINGREF symsrvFileName = PH_STRINGREF_INIT(L"symsrv.dll"); + PVOID dbghelpHandle; + PVOID symsrvHandle; + HANDLE keyHandle; if (PhFindLoaderEntry(NULL, NULL, &dbghelpFileName) && PhFindLoaderEntry(NULL, NULL, &symsrvFileName)) @@ -275,34 +262,56 @@ VOID PhpSymbolProviderCompleteInitialization( return; } - for (i = 0; i < RTL_NUMBER_OF(locations); i++) + dbghelpHandle = NULL; + symsrvHandle = NULL; + + if (NT_SUCCESS(PhOpenKey( + &keyHandle, + KEY_READ, + PH_KEY_LOCAL_MACHINE, + &windowsKitsRootKeyName, + 0 + ))) { - PPH_STRING dbghelpPath; + PPH_STRING winsdkPath; PPH_STRING dbghelpName; PPH_STRING symsrvName; - if (!(dbghelpPath = PhExpandEnvironmentStrings(&locations[i].AppendPath))) - continue; + winsdkPath = PhQueryRegistryString(keyHandle, L"KitsRoot10"); // Windows 10 SDK + + if (PhIsNullOrEmptyString(winsdkPath)) + PhMoveReference(&winsdkPath, PhQueryRegistryString(keyHandle, L"KitsRoot81")); // Windows 8.1 SDK - dbghelpName = PhConcatStringRef2(&dbghelpPath->sr, &dbghelpFileName); - symsrvName = PhConcatStringRef2(&dbghelpPath->sr, &symsrvFileName); + if (PhIsNullOrEmptyString(winsdkPath)) + PhMoveReference(&winsdkPath, PhQueryRegistryString(keyHandle, L"KitsRoot")); // Windows 8 SDK - if (RtlDoesFileExists_U(dbghelpName->Buffer)) + if (!PhIsNullOrEmptyString(winsdkPath)) { - dbghelpHandle = LoadLibrary(dbghelpName->Buffer); +#ifdef _WIN64 + PhMoveReference(&winsdkPath, PhConcatStringRefZ(&winsdkPath->sr, L"\\Debuggers\\x64\\")); +#else + PhMoveReference(&winsdkPath, PhConcatStringRefZ(&winsdkPath->sr, L"\\Debuggers\\x64\\")); +#endif } - if (RtlDoesFileExists_U(symsrvName->Buffer)) + if (winsdkPath) { - symsrvHandle = LoadLibrary(symsrvName->Buffer); - } + if (dbghelpName = PhConcatStringRef2(&winsdkPath->sr, &dbghelpFileName)) + { + dbghelpHandle = LoadLibrary(dbghelpName->Buffer); + PhDereferenceObject(dbghelpName); + } + + if (symsrvName = PhConcatStringRef2(&winsdkPath->sr, &symsrvFileName)) + { + symsrvHandle = LoadLibrary(symsrvName->Buffer); + PhDereferenceObject(symsrvName); + } - PhDereferenceObject(symsrvName); - PhDereferenceObject(dbghelpName); - PhDereferenceObject(dbghelpPath); + PhDereferenceObject(winsdkPath); + } - if (dbghelpHandle) - break; + NtClose(keyHandle); } if (!dbghelpHandle) From 6f30b16c58096f82f968ce9fa39ffec9b9c60da9 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 18 Jul 2018 18:48:12 +1000 Subject: [PATCH 1129/2058] Plugins: update sdk version --- plugins/DotNetTools/DotNetTools.vcxproj | 2 +- plugins/ExtendedNotifications/ExtendedNotifications.vcxproj | 2 +- plugins/ExtendedServices/ExtendedServices.vcxproj | 2 +- plugins/ExtendedTools/ExtendedTools.vcxproj | 2 +- plugins/HardwareDevices/HardwareDevices.vcxproj | 2 +- plugins/NetworkTools/NetworkTools.vcxproj | 2 +- plugins/OnlineChecks/OnlineChecks.vcxproj | 2 +- plugins/ToolStatus/ToolStatus.vcxproj | 2 +- plugins/Updater/Updater.vcxproj | 2 +- plugins/UserNotes/UserNotes.vcxproj | 2 +- plugins/WindowExplorer/WindowExplorer.vcxproj | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/plugins/DotNetTools/DotNetTools.vcxproj b/plugins/DotNetTools/DotNetTools.vcxproj index 60fe4cddde3e..98bcc6c571f7 100644 --- a/plugins/DotNetTools/DotNetTools.vcxproj +++ b/plugins/DotNetTools/DotNetTools.vcxproj @@ -23,7 +23,7 @@ DotNetTools Win32Proj DotNetTools - 10.0.16299.0 + 10.0.17134.0 diff --git a/plugins/ExtendedNotifications/ExtendedNotifications.vcxproj b/plugins/ExtendedNotifications/ExtendedNotifications.vcxproj index 4c13d33c0dc2..239358abb274 100644 --- a/plugins/ExtendedNotifications/ExtendedNotifications.vcxproj +++ b/plugins/ExtendedNotifications/ExtendedNotifications.vcxproj @@ -23,7 +23,7 @@ ExtendedNotifications Win32Proj ExtendedNotifications - 10.0.16299.0 + 10.0.17134.0 diff --git a/plugins/ExtendedServices/ExtendedServices.vcxproj b/plugins/ExtendedServices/ExtendedServices.vcxproj index 4c2f84f3736b..1d56e72aa6ed 100644 --- a/plugins/ExtendedServices/ExtendedServices.vcxproj +++ b/plugins/ExtendedServices/ExtendedServices.vcxproj @@ -23,7 +23,7 @@ ExtendedServices Win32Proj ExtendedServices - 10.0.16299.0 + 10.0.17134.0 diff --git a/plugins/ExtendedTools/ExtendedTools.vcxproj b/plugins/ExtendedTools/ExtendedTools.vcxproj index 34eb747e9ab8..348b15da9481 100644 --- a/plugins/ExtendedTools/ExtendedTools.vcxproj +++ b/plugins/ExtendedTools/ExtendedTools.vcxproj @@ -23,7 +23,7 @@ ExtendedTools Win32Proj ExtendedTools - 10.0.16299.0 + 10.0.17134.0 diff --git a/plugins/HardwareDevices/HardwareDevices.vcxproj b/plugins/HardwareDevices/HardwareDevices.vcxproj index 754c8b7765ab..71417d9be759 100644 --- a/plugins/HardwareDevices/HardwareDevices.vcxproj +++ b/plugins/HardwareDevices/HardwareDevices.vcxproj @@ -23,7 +23,7 @@ HardwareDevices Win32Proj HardwareDevices - 10.0.16299.0 + 10.0.17134.0 diff --git a/plugins/NetworkTools/NetworkTools.vcxproj b/plugins/NetworkTools/NetworkTools.vcxproj index fa9d18f8b524..a18d8560613a 100644 --- a/plugins/NetworkTools/NetworkTools.vcxproj +++ b/plugins/NetworkTools/NetworkTools.vcxproj @@ -23,7 +23,7 @@ NetworkTools Win32Proj NetworkTools - 10.0.16299.0 + 10.0.17134.0 diff --git a/plugins/OnlineChecks/OnlineChecks.vcxproj b/plugins/OnlineChecks/OnlineChecks.vcxproj index a041a2316bb4..764cec17f922 100644 --- a/plugins/OnlineChecks/OnlineChecks.vcxproj +++ b/plugins/OnlineChecks/OnlineChecks.vcxproj @@ -23,7 +23,7 @@ OnlineChecks Win32Proj OnlineChecks - 10.0.16299.0 + 10.0.17134.0 diff --git a/plugins/ToolStatus/ToolStatus.vcxproj b/plugins/ToolStatus/ToolStatus.vcxproj index 17a8c126440c..6fc67d6814d2 100644 --- a/plugins/ToolStatus/ToolStatus.vcxproj +++ b/plugins/ToolStatus/ToolStatus.vcxproj @@ -23,7 +23,7 @@ ToolStatus Win32Proj ToolStatus - 10.0.16299.0 + 10.0.17134.0 diff --git a/plugins/Updater/Updater.vcxproj b/plugins/Updater/Updater.vcxproj index a906bc3ca17c..16bf8cf84c43 100644 --- a/plugins/Updater/Updater.vcxproj +++ b/plugins/Updater/Updater.vcxproj @@ -23,7 +23,7 @@ Updater Win32Proj Updater - 10.0.16299.0 + 10.0.17134.0 diff --git a/plugins/UserNotes/UserNotes.vcxproj b/plugins/UserNotes/UserNotes.vcxproj index 891f9462e957..8d379f625a0d 100644 --- a/plugins/UserNotes/UserNotes.vcxproj +++ b/plugins/UserNotes/UserNotes.vcxproj @@ -23,7 +23,7 @@ UserNotes Win32Proj UserNotes - 10.0.16299.0 + 10.0.17134.0 diff --git a/plugins/WindowExplorer/WindowExplorer.vcxproj b/plugins/WindowExplorer/WindowExplorer.vcxproj index 3bd826bcf330..b88021030029 100644 --- a/plugins/WindowExplorer/WindowExplorer.vcxproj +++ b/plugins/WindowExplorer/WindowExplorer.vcxproj @@ -23,7 +23,7 @@ WindowExplorer Win32Proj WindowExplorer - 10.0.16299.0 + 10.0.17134.0 From 7b394edcdd1759b61d1f744a1031ace718fe570f Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 18 Jul 2018 21:11:01 +1000 Subject: [PATCH 1130/2058] Update DelayLoadDLLs --- ProcessHacker/ProcessHacker.vcxproj | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/ProcessHacker/ProcessHacker.vcxproj b/ProcessHacker/ProcessHacker.vcxproj index fa3f4a316964..4a4afd7750bd 100644 --- a/ProcessHacker/ProcessHacker.vcxproj +++ b/ProcessHacker/ProcessHacker.vcxproj @@ -113,7 +113,7 @@ 6.01 $(SolutionDir)phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) ProcessHacker.def - aclui.dll;comdlg32.dll;iphlpapi.dll;userenv.dll;winsta.dll;ws2_32.dll;%(DelayLoadDLLs) + advapi32.dll;aclui.dll;comdlg32.dll;comctl32.dll;gdi32.dll;iphlpapi.dll;oleaut32.dll;ole32.dll;shell32.dll;userenv.dll;user32.dll;uxtheme.dll;version.dll;winsta.dll;ws2_32.dll;%(DelayLoadDLLs) _UNICODE;UNICODE;%(PreprocessorDefinitions);$(ExternalCompilerOptions) @@ -145,7 +145,7 @@ 6.01 $(SolutionDir)phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) ProcessHacker.def - aclui.dll;comdlg32.dll;iphlpapi.dll;userenv.dll;winsta.dll;ws2_32.dll;%(DelayLoadDLLs) + advapi32.dll;aclui.dll;comdlg32.dll;comctl32.dll;gdi32.dll;iphlpapi.dll;oleaut32.dll;ole32.dll;shell32.dll;userenv.dll;user32.dll;uxtheme.dll;version.dll;winsta.dll;ws2_32.dll;%(DelayLoadDLLs) _UNICODE;UNICODE;%(PreprocessorDefinitions);$(ExternalCompilerOptions) @@ -184,8 +184,8 @@ 6.01 $(SolutionDir)phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) ProcessHacker.def - aclui.dll;comdlg32.dll;iphlpapi.dll;userenv.dll;winsta.dll;ws2_32.dll;%(DelayLoadDLLs) - $(ExternalDebugOptions) + advapi32.dll;aclui.dll;comdlg32.dll;comctl32.dll;gdi32.dll;iphlpapi.dll;oleaut32.dll;ole32.dll;shell32.dll;userenv.dll;user32.dll;uxtheme.dll;version.dll;winsta.dll;ws2_32.dll;%(DelayLoadDLLs) + true _UNICODE;UNICODE;%(PreprocessorDefinitions);$(ExternalCompilerOptions) @@ -222,8 +222,8 @@ 6.01 $(SolutionDir)phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) ProcessHacker.def - aclui.dll;comdlg32.dll;iphlpapi.dll;userenv.dll;winsta.dll;ws2_32.dll;%(DelayLoadDLLs) - $(ExternalDebugOptions) + advapi32.dll;aclui.dll;comdlg32.dll;comctl32.dll;gdi32.dll;iphlpapi.dll;oleaut32.dll;ole32.dll;shell32.dll;userenv.dll;user32.dll;uxtheme.dll;version.dll;winsta.dll;ws2_32.dll;%(DelayLoadDLLs) + true _UNICODE;UNICODE;%(PreprocessorDefinitions);$(ExternalCompilerOptions) From c7a1558d8faaadc26ab5dcd61763f6e4c75277ed Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 18 Jul 2018 22:44:00 +1000 Subject: [PATCH 1131/2058] WindowExplorer: Add window icon --- plugins/WindowExplorer/wnddlg.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/plugins/WindowExplorer/wnddlg.c b/plugins/WindowExplorer/wnddlg.c index 645b4d12acdf..9af42a442e51 100644 --- a/plugins/WindowExplorer/wnddlg.c +++ b/plugins/WindowExplorer/wnddlg.c @@ -348,6 +348,9 @@ INT_PTR CALLBACK WepWindowsDlgProc( { PH_RECTANGLE windowRectangle; + SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL((*(PVOID *)WeGetProcedureAddress("PhInstanceHandle")), MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); + SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE((*(PVOID *)WeGetProcedureAddress("PhInstanceHandle")), MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); + context->TreeNewHandle = GetDlgItem(hwndDlg, IDC_LIST); context->SearchBoxHandle = GetDlgItem(hwndDlg, IDC_SEARCHEDIT); From 50244a09748db0fd8e12ef5448f03a2b105bf2a9 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 18 Jul 2018 22:52:02 +1000 Subject: [PATCH 1132/2058] BuildTools: Fix build --- tools/CustomBuildTool/Source Files/Build.cs | 100 +++++++++++------- .../bin/Release/CustomBuildTool.exe | Bin 166400 -> 165376 bytes .../bin/Release/CustomBuildTool.pdb | Bin 81408 -> 81408 bytes 3 files changed, 64 insertions(+), 36 deletions(-) diff --git a/tools/CustomBuildTool/Source Files/Build.cs b/tools/CustomBuildTool/Source Files/Build.cs index 7a7109b93164..ae218f5ec2be 100644 --- a/tools/CustomBuildTool/Source Files/Build.cs +++ b/tools/CustomBuildTool/Source Files/Build.cs @@ -1176,11 +1176,14 @@ public static bool BuildDeployUpdateConfig() public static bool BuildDeployUploadArtifacts() { string buildPostUrl = Environment.ExpandEnvironmentVariables("%APPVEYOR_NIGHTLY_URL%").Replace("%APPVEYOR_NIGHTLY_URL%", string.Empty); - string buildPostKey = Environment.ExpandEnvironmentVariables("%APPVEYOR_BUILD_KEY%").Replace("%APPVEYOR_BUILD_KEY%", string.Empty); + string buildPostKey = Environment.ExpandEnvironmentVariables("%APPVEYOR_NIGHTLY_KEY%").Replace("%APPVEYOR_NIGHTLY_KEY%", string.Empty); + string buildPostName = Environment.ExpandEnvironmentVariables("%APPVEYOR_NIGHTLY_NAME%").Replace("%APPVEYOR_NIGHTLY_NAME%", string.Empty); + if (string.IsNullOrEmpty(buildPostUrl)) + return false; if (string.IsNullOrEmpty(buildPostKey)) return false; - if (string.IsNullOrEmpty(buildPostUrl)) + if (string.IsNullOrEmpty(buildPostName)) return false; Console.Write(Environment.NewLine); @@ -1194,53 +1197,78 @@ public static bool BuildDeployUploadArtifacts() if (File.Exists(sourceFile)) { - string boundary = "---------------------------" + Guid.NewGuid().ToString(); - byte[] boundarybytes = Encoding.ASCII.GetBytes("\r\n--" + boundary + "\r\n"); - byte[] headerbytes = Encoding.UTF8.GetBytes($"Content-Disposition: form-data; name=\"file\"; filename=\"{filename}\"\r\n\r\n"); - - HttpWebRequest request = (HttpWebRequest)WebRequest.Create(new Uri(buildPostUrl)); - request.KeepAlive = true; - request.SendChunked = true; - request.AllowWriteStreamBuffering = true; - request.ServicePoint.Expect100Continue = false; - request.ServicePoint.ReceiveBufferSize = 4096; - request.ServicePoint.ConnectionLeaseTimeout = System.Threading.Timeout.Infinite; - request.ReadWriteTimeout = System.Threading.Timeout.Infinite; + FtpWebRequest request = (FtpWebRequest)WebRequest.Create(buildPostUrl + filename); + request.Credentials = new NetworkCredential(buildPostKey, buildPostName); + request.Method = WebRequestMethods.Ftp.UploadFile; request.Timeout = System.Threading.Timeout.Infinite; - request.Method = WebRequestMethods.Http.Post; - request.ContentType = "multipart/form-data; boundary=" + boundary; - request.Headers.Add("X-ApiKey", buildPostKey); + request.EnableSsl = true; + request.UsePassive = true; + request.UseBinary = true; Program.PrintColorMessage($"Uploading {filename}...", ConsoleColor.Cyan, true); - using (FileStream fileStream = File.OpenRead(sourceFile)) - using (BufferedStream localStream = new BufferedStream(fileStream)) + using (BufferedStream localStream = new BufferedStream(File.OpenRead(sourceFile))) using (BufferedStream remoteStream = new BufferedStream(request.GetRequestStream())) { - int bytesRead = 0; - var totalRead = 0; - byte[] buffer = new byte[4096]; - - remoteStream.Write(boundarybytes, 0, boundarybytes.Length); - remoteStream.Write(headerbytes, 0, headerbytes.Length); - - while ((bytesRead = localStream.Read(buffer, 0, buffer.Length)) != 0) - { - totalRead += bytesRead; - remoteStream.Write(buffer, 0, bytesRead); - } - - remoteStream.Write(boundarybytes, 0, boundarybytes.Length); + localStream.CopyTo(remoteStream, 4096); } - using (HttpWebResponse response = (HttpWebResponse)request.GetResponse()) + using (FtpWebResponse response = (FtpWebResponse)request.GetResponse()) { - if (response.StatusCode != HttpStatusCode.OK) + if (response.StatusCode != FtpStatusCode.CommandOK && response.StatusCode != FtpStatusCode.ClosingData) { - Program.PrintColorMessage("[HttpWebResponse]" + response.StatusDescription, ConsoleColor.Red); + Program.PrintColorMessage($"[HttpWebResponse] {response.StatusDescription}", ConsoleColor.Red); return false; } } + + //string boundary = "---------------------------" + Guid.NewGuid().ToString(); + //byte[] boundarybytes = Encoding.ASCII.GetBytes("\r\n--" + boundary + "\r\n"); + //byte[] headerbytes = Encoding.UTF8.GetBytes($"Content-Disposition: form-data; name=\"file\"; filename=\"{filename}\"\r\n\r\n"); + // + //HttpWebRequest request = (HttpWebRequest)WebRequest.Create(new Uri(buildPostUrl)); + //request.KeepAlive = true; + //request.SendChunked = true; + //request.AllowWriteStreamBuffering = true; + //request.ServicePoint.Expect100Continue = false; + //request.ServicePoint.ReceiveBufferSize = 4096; + //request.ServicePoint.ConnectionLeaseTimeout = System.Threading.Timeout.Infinite; + //request.ReadWriteTimeout = System.Threading.Timeout.Infinite; + //request.Timeout = System.Threading.Timeout.Infinite; + //request.Method = WebRequestMethods.Http.Post; + //request.ContentType = "multipart/form-data; boundary=" + boundary; + //request.Headers.Add("X-ApiKey", buildPostKey); + // + //Program.PrintColorMessage($"Uploading {filename}...", ConsoleColor.Cyan, true); + // + //using (FileStream fileStream = File.OpenRead(sourceFile)) + //using (BufferedStream localStream = new BufferedStream(fileStream)) + //using (BufferedStream remoteStream = new BufferedStream(request.GetRequestStream())) + //{ + // int bytesRead = 0; + // var totalRead = 0; + // byte[] buffer = new byte[4096]; + // + // remoteStream.Write(boundarybytes, 0, boundarybytes.Length); + // remoteStream.Write(headerbytes, 0, headerbytes.Length); + // + // while ((bytesRead = localStream.Read(buffer, 0, buffer.Length)) != 0) + // { + // totalRead += bytesRead; + // remoteStream.Write(buffer, 0, bytesRead); + // } + // + // remoteStream.Write(boundarybytes, 0, boundarybytes.Length); + //} + // + //using (HttpWebResponse response = (HttpWebResponse)request.GetResponse()) + //{ + // if (response.StatusCode != HttpStatusCode.OK) + // { + // Program.PrintColorMessage("[HttpWebResponse]" + response.StatusDescription, ConsoleColor.Red); + // return false; + // } + //} } } } diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe b/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe index 62e69c0eafda02487b16f49983610ccb24f871de..d501135417b881239583e01e2efe9a57ab814fb0 100644 GIT binary patch delta 16453 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 V(yM_>(swK5!&ko=x=H@0^gm8&j_m*d delta 17057 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 Yt@i);wEsux$2NIw|EGhO$lpo-4}g}43;+NC diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb b/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb index a5b26fd5605a224bc547a773dc4a2c5429e3b369..6fb04ceca884cc12538e9cf7027570a42f0da2ed 100644 GIT binary patch delta 5187 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 delta 5630 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 NzdP;U`SRhZ{|g@a`4a#D From a6dabf865d26c03af769215a90fa5146759374be Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 18 Jul 2018 22:52:33 +1000 Subject: [PATCH 1133/2058] SetupTool: Remove legacy shell wrappers --- tools/CustomSetupTool/CustomSetupTool/setup.c | 76 +++++++++++++------ 1 file changed, 52 insertions(+), 24 deletions(-) diff --git a/tools/CustomSetupTool/CustomSetupTool/setup.c b/tools/CustomSetupTool/CustomSetupTool/setup.c index 628df65576ba..5d49b5b73d1e 100644 --- a/tools/CustomSetupTool/CustomSetupTool/setup.c +++ b/tools/CustomSetupTool/CustomSetupTool/setup.c @@ -455,18 +455,23 @@ VOID SetupSetWindowsOptions( _In_ PPH_SETUP_CONTEXT Context ) { + static PH_STRINGREF desktopStartmenuPathSr = PH_STRINGREF_INIT(L"%ALLUSERSPROFILE%\\Microsoft\\Windows\\Start Menu\\Programs\\Process Hacker.lnk"); + static PH_STRINGREF peviewerShortcutPathSr = PH_STRINGREF_INIT(L"%ALLUSERSPROFILE%\\Microsoft\\Windows\\Start Menu\\Programs\\PE Viewer.lnk"); + static PH_STRINGREF userShortcutPathSr = PH_STRINGREF_INIT(L"%USERPROFILE%\\Desktop\\Process Hacker.lnk"); + static PH_STRINGREF desktopAllusersPathSr = PH_STRINGREF_INIT(L"%PUBLIC%\\Desktop\\Process Hacker.lnk"); PPH_STRING clientPathString; PPH_STRING startmenuFolderString; clientPathString = PhConcatStrings2(PhGetString(SetupInstallPath), L"\\ProcessHacker.exe"); // Create the startmenu shortcut. - if (startmenuFolderString = PhGetKnownLocation(CSIDL_COMMON_PROGRAMS, L"\\Process Hacker.lnk")) + // PhGetKnownLocation(CSIDL_COMMON_PROGRAMS, L"\\Process Hacker.lnk")) + if (startmenuFolderString = PhExpandEnvironmentStrings(&desktopStartmenuPathSr)) { SetupCreateLink( - L"ProcessHacker.Desktop.App", - PhGetString(startmenuFolderString), - PhGetString(clientPathString), + L"ProcessHacker.Desktop.App", + PhGetString(startmenuFolderString), + PhGetString(clientPathString), PhGetString(SetupInstallPath) ); PhDereferenceObject(startmenuFolderString); @@ -475,7 +480,8 @@ VOID SetupSetWindowsOptions( // Create the all users shortcut. if (Context->SetupCreateDesktopShortcutAllUsers) { - if (startmenuFolderString = PhGetKnownLocation(CSIDL_COMMON_DESKTOPDIRECTORY, L"\\Process Hacker.lnk")) + // PhGetKnownLocation(CSIDL_COMMON_DESKTOPDIRECTORY, L"\\Process Hacker.lnk") + if (startmenuFolderString = PhExpandEnvironmentStrings(&desktopAllusersPathSr)) { SetupCreateLink( L"ProcessHacker.Desktop.App", @@ -491,7 +497,8 @@ VOID SetupSetWindowsOptions( // Create the desktop shortcut. if (Context->SetupCreateDesktopShortcut) { - if (startmenuFolderString = PhGetKnownLocation(CSIDL_DESKTOPDIRECTORY, L"\\Process Hacker.lnk")) + // PhGetKnownLocation(CSIDL_DESKTOPDIRECTORY, L"\\Process Hacker.lnk") + if (startmenuFolderString = PhExpandEnvironmentStrings(&userShortcutPathSr)) { SetupCreateLink( L"ProcessHacker.Desktop.App", @@ -505,7 +512,8 @@ VOID SetupSetWindowsOptions( } // Create the PE Viewer startmenu shortcut. - if (startmenuFolderString = PhGetKnownLocation(CSIDL_COMMON_PROGRAMS, L"\\PE Viewer.lnk")) + // PhGetKnownLocation(CSIDL_COMMON_PROGRAMS, L"\\PE Viewer.lnk") + if (startmenuFolderString = PhExpandEnvironmentStrings(&peviewerShortcutPathSr)) { PPH_STRING peviewPathString = PhConcatStrings2(PhGetString(SetupInstallPath), L"\\peview.exe"); @@ -523,11 +531,18 @@ VOID SetupSetWindowsOptions( // Reset the settings file. if (Context->SetupResetSettings) { - PPH_STRING settingsFileName = PhGetKnownLocation(CSIDL_APPDATA, L"\\Process Hacker\\settings.xml"); + static PH_STRINGREF settingsPath = PH_STRINGREF_INIT(L"%APPDATA%\\Process Hacker\\settings.xml"); + PPH_STRING settingsFilePath; - PhDeleteFileWin32(settingsFileName->Buffer); + if (settingsFilePath = PhExpandEnvironmentStrings(&settingsPath)) + { + if (RtlDoesFileExists_U(settingsFilePath->Buffer)) + { + PhDeleteFileWin32(settingsFilePath->Buffer); + } - PhDereferenceObject(settingsFileName); + PhDereferenceObject(settingsFilePath); + } } // Set the Windows default Task Manager. @@ -611,30 +626,38 @@ VOID SetupDeleteWindowsOptions( _In_ PPH_SETUP_CONTEXT Context ) { + static PH_STRINGREF desktopShortcutPathSr = PH_STRINGREF_INIT(L"%ALLUSERSPROFILE%\\Microsoft\\Windows\\Start Menu\\Programs\\Process Hacker.lnk"); + static PH_STRINGREF peviewerShortcutPathSr = PH_STRINGREF_INIT(L"%ALLUSERSPROFILE%\\Microsoft\\Windows\\Start Menu\\Programs\\PE Viewer.lnk"); + static PH_STRINGREF userShortcutPathSr = PH_STRINGREF_INIT(L"%USERPROFILE%\\Desktop\\Process Hacker.lnk"); + static PH_STRINGREF desktopAllusersPathSr = PH_STRINGREF_INIT(L"%PUBLIC%\\Desktop\\Process Hacker.lnk"); PPH_STRING startmenuFolderString; HANDLE keyHandle; - if (startmenuFolderString = PhGetKnownLocation(CSIDL_COMMON_PROGRAMS, L"\\Process Hacker.lnk")) + // PhGetKnownLocation(CSIDL_COMMON_PROGRAMS, L"\\Process Hacker.lnk") + if (startmenuFolderString = PhExpandEnvironmentStrings(&desktopShortcutPathSr)) { PhDeleteFileWin32(PhGetString(startmenuFolderString)); PhDereferenceObject(startmenuFolderString); } - if (startmenuFolderString = PhGetKnownLocation(CSIDL_COMMON_PROGRAMS, L"\\PE Viewer.lnk")) + // PhGetKnownLocation(CSIDL_COMMON_PROGRAMS, L"\\PE Viewer.lnk") + if (startmenuFolderString = PhExpandEnvironmentStrings(&peviewerShortcutPathSr)) { PhDeleteFileWin32(PhGetString(startmenuFolderString)); PhDereferenceObject(startmenuFolderString); } - if (startmenuFolderString = PhGetKnownLocation(CSIDL_DESKTOPDIRECTORY, L"\\Process Hacker.lnk")) + // PhGetKnownLocation(CSIDL_DESKTOPDIRECTORY, L"\\Process Hacker.lnk") + if (startmenuFolderString = PhExpandEnvironmentStrings(&userShortcutPathSr)) { - PhDeleteFileWin32(PhGetString(startmenuFolderString)); + PhDeleteFileWin32(startmenuFolderString->Buffer); PhDereferenceObject(startmenuFolderString); } - if (startmenuFolderString = PhGetKnownLocation(CSIDL_COMMON_DESKTOPDIRECTORY, L"\\Process Hacker.lnk")) + // PhGetKnownLocation(CSIDL_COMMON_DESKTOPDIRECTORY, L"\\Process Hacker.lnk") + if (startmenuFolderString = PhExpandEnvironmentStrings(&desktopAllusersPathSr)) { - PhDeleteFileWin32(PhGetString(startmenuFolderString)); + PhDeleteFileWin32(startmenuFolderString->Buffer); PhDereferenceObject(startmenuFolderString); } @@ -717,19 +740,24 @@ VOID SetupUpgradeSettingsFile( VOID ) { + static PH_STRINGREF settingsPath = PH_STRINGREF_INIT(L"%APPDATA%\\Process Hacker\\settings.xml"); + static PH_STRINGREF settingsLegacyPath = PH_STRINGREF_INIT(L"%APPDATA%\\Process Hacker 2\\settings.xml"); PPH_STRING settingsFilePath; PPH_STRING oldSettingsFileName; - - settingsFilePath = PhGetKnownLocation(CSIDL_APPDATA, L"\\Process Hacker\\settings.xml"); - oldSettingsFileName = PhGetKnownLocation(CSIDL_APPDATA, L"\\Process Hacker 2\\settings.xml"); - if (!RtlDoesFileExists_U(settingsFilePath->Buffer)) + settingsFilePath = PhExpandEnvironmentStrings(&settingsPath); + oldSettingsFileName = PhExpandEnvironmentStrings(&settingsLegacyPath); + + if (settingsFilePath && oldSettingsFileName) { - CopyFile(oldSettingsFileName->Buffer, settingsFilePath->Buffer, FALSE); + if (!RtlDoesFileExists_U(settingsFilePath->Buffer)) + { + CopyFile(oldSettingsFileName->Buffer, settingsFilePath->Buffer, FALSE); + } } - - PhDereferenceObject(oldSettingsFileName); - PhDereferenceObject(settingsFilePath); + + if (oldSettingsFileName) PhDereferenceObject(oldSettingsFileName); + if (settingsFilePath) PhDereferenceObject(settingsFilePath); } VOID SetupCreateImageFileExecutionOptions( From 8514315a4cb2787f82179cc1d07a6253de9da993 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 18 Jul 2018 22:58:03 +1000 Subject: [PATCH 1134/2058] WindowExplorer: Fix headers --- plugins/WindowExplorer/wnddlg.c | 3 --- plugins/WindowExplorer/wndexp.h | 7 +++++++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/plugins/WindowExplorer/wnddlg.c b/plugins/WindowExplorer/wnddlg.c index 9af42a442e51..dc58e5e8ca47 100644 --- a/plugins/WindowExplorer/wnddlg.c +++ b/plugins/WindowExplorer/wnddlg.c @@ -22,9 +22,6 @@ */ #include "wndexp.h" -#include "resource.h" -#include -#include typedef struct _WINDOWS_CONTEXT { diff --git a/plugins/WindowExplorer/wndexp.h b/plugins/WindowExplorer/wndexp.h index dba7a96bc9a2..a16a72386f84 100644 --- a/plugins/WindowExplorer/wndexp.h +++ b/plugins/WindowExplorer/wndexp.h @@ -3,7 +3,14 @@ #include #include +#include #include + +#include + +#include + +#include "resource.h" #include "wndtree.h" extern BOOLEAN IsHookClient; From b3f39e32aee8e6baede11c8323a804fee8a90370 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 18 Jul 2018 23:22:43 +1000 Subject: [PATCH 1135/2058] BuildTools: Enable sdk builds --- tools/CustomBuildTool/Source Files/Program.cs | 6 ++++-- .../bin/Release/CustomBuildTool.exe | Bin 165376 -> 165376 bytes .../bin/Release/CustomBuildTool.pdb | Bin 81408 -> 81408 bytes 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/tools/CustomBuildTool/Source Files/Program.cs b/tools/CustomBuildTool/Source Files/Program.cs index fb1198e55f55..9c1e77d6cb4e 100644 --- a/tools/CustomBuildTool/Source Files/Program.cs +++ b/tools/CustomBuildTool/Source Files/Program.cs @@ -230,8 +230,10 @@ public static void Main(string[] args) Environment.Exit(1); if (!Build.BuildPdbZip()) Environment.Exit(1); - //Build.BuildSdkZip(); - //Build.BuildSrcZip(); + if (!Build.BuildSdkZip()) + Environment.Exit(1); + if (!Build.BuildSrcZip()) + Environment.Exit(1); if (!Build.BuildChecksumsFile()) Environment.Exit(1); diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe b/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe index d501135417b881239583e01e2efe9a57ab814fb0..6839186aff1f6bca89478e2f061897f032875207 100644 GIT binary patch delta 1545 zcmY+^drVtZ90&04X#nf#Xl~02*L1vzKH$Rwg6+1Q4zumR;&#(Q&)p;=gzY-lk& z0| z>$&Y22+Dz=JU?pjl#aiWCT@>U*NY395V`Sf$pTxnrI<%+6uIIz?PU?jTuc$rUwi3o zK|DS?1dL7r`e-YVus@t>ncXJR!%N%k7O|#9ize(zG`=+mQw!^*Us#iNMYnGRb}mY`pIrmj4Y;x~fSv{YaGPUIL00nT*G zP7JaBcDyBb;ifqg-?`>wIdYoKpq1=-xf_$LWl{xl4w^L&#qPr>Ya^*oc+uQqE=-e7rT1T~mtJuVf}JnP})2x_rFqWlqSX|h7R#>GTe1U@XW+%AQ*%nH!4)nSEo zI!Ph@!pe3=P><#b1| z;MQ#T*7rwL&qJkE#+_rKxGe(cr~A1-22|JVs`>fK%^O+e&Zo|uo~n$E{ct1P7qbdw ofp2TQ!DagV+FX%E6^q*R9q*uhZh}cU*PUS^gCN0v{b%UjP6A delta 1515 zcmYM!du&r>7zXg?YuK!(TRrPod$6zzQ`g0Ulgy39OH?)nNGa~Vwyf*gB5|9SFwKI| zZkb!CG;{TkAqmMyz+^_FmST`Uj6yKpXaqMSx)>WmA~DQl3Fx*s^*!gj#3oJ7@4G#3 z-qU_V327)HO&m0xs!hI8EWS^^+b)JwAu4jV*#*|B3yW^GQ&fm6>ad8FopuOlpKbIt zAqO8tfrHb4HW~zSH>b-?A6AK+^yN)flbBJn)l=!C4+Vul`mdUm;#jst+nq$Xv`?x) zv{ln2dZa6jhjLH}-u>+5}gJp(#=|&}nF( zpcgeb%qp{tV>7<8G7BsTsSXi!xUC`fuTKwBir2N~Y(bvi*bZBXX$$&T{}j9@)#HM$ zBz`GMNe##g7%Q)qe=i5FPQg@eL_`Yt^W7tNnZ9=KxEHtL8T z??FV@B=(!_cX%+svMOcv5vGR3wvEJ9Umlav1t$gnGKI;X^i$Oz* zvhHhApa)w1nE3|9??$A@C}zbWllobg)@SfEUSeg}%cR#>KT<>!##q-^$)q<~ZYhIi z9AP~w$)w|~2kjZOV46hvW9CQfGBL%I`9&GD;w;NqB$LjwV$`-ae8W0aD3fMb<+cpk zF~{0ylS$WDjTG2{8>|+}>%c8dF^aFGz)r02WE}-|A~$UG;v@z7U}c@6Kpz~e1`70} zgw;fWez;g63Jjo%^&$lZPBy3@2I?ZYv3jo*3yNgf-5&GIa6vMve5(u;n&1hpDkh0W53Q8nmy z-j(FBQru(d#|bs=cZy{C9e?BN^8R=<`c&|&XWGAeE`IA}NBZwy_bKjFtyjNZOmx&* z0YvEbjVuC9&GpUKHoSH37m3*?-=4oX^1J1OrS!z2S;*6T7i;0?>G?>i+N6ln>bWJ4 Z`nXU=tjlMt%VIfhnyo!^&L#d7{{fi~RM!9i diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb b/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb index 6fb04ceca884cc12538e9cf7027570a42f0da2ed..02d1789c1c083cfb7d6882e3d78fd200a95d256d 100644 GIT binary patch delta 3944 zcmZ{n3s4kS7KZ1vfPhRK0)zn!3gbXzaFIvkF&M;0lpsNjk1`_4Ml@)6C`2VZW(X2O z)TkUyCm_fW-3ZDmwn7j=shIMSveb%+Yj#nIVpa_%?rJouAy$8qrS+vb@wY>VZG;_klAG$Kg;`I#oo5WopeC&?BtR&L2aBP zx%)pD>ezN8e&@%m4Z7%Xr|QQd>F+`D6P%M#B6r`GLk3P=;!ep@<`OeeGS_ESQ8OEt zj)a}MG|zdz*Uu6;8USy#l$k**f_37l1>M`++xZ*HUq$d?b(DVFuK_2cKC@8=k((8q% z$vOS^pW2^aSv`r;rH!jaa-J1$pQr#w8o|@o&ZcEtzc!C@SzDAxYq=EG!h=Qggjw-i zo9)Ys-_fCDwaA{NEA}Ls&c>2p*p!mb=v}^FVu1B2HB&XuDUGJh zyb)I9FH1Mk8J<&SfGsLB(*-_M7EOQULD=uvXxSv_$8)+%#-jNRjz0pA!Oe&U_`!J}fe~Oe=nrlK zM}c)K78XO1x6&L|t03*R~z!$;G;CS%L5;!rq zVGxW*;12i__zRc-J^&NJ$KWLJ2{;*a!Y?@m912bawcyL32RIG%0h2&~Fj)%UR7w=W zJ2wA{)$+*}KT9f7!{kK(YQb5cJ9y`($5s!!)`PPV4+iIg;ov;*C2&5N2)+(Z1{Z=a zgNwjaa50z$W`eJQOTfio7MO$INcp0b2*_W&23*clYvy73*4OyO<{{>USU!lwt62rg zgDe1bU?C_EZZ+r+t^p0;TE1Ij!s36P{nAPhlY5kc^1T+&7qo&SK>0zR2iK9NQXcRJ zh|2?B56-f4Hn0X1%J8KOb?m1 z6$@U`T(&JjMoUYRwhN#hJw-6i7A2z+h=XSW!LhjpP7P7**!4||58{Kd+rZiSK509`P zt*2aY%sgmxr{TP@DOsy*VywO-JVPXB+RS9;fKP+98xZ>$S0Lh3_`I#cx%6oVtt&bd zH@Qb%l3|9~LetLpprRtqSNEjZ$AMUzE zrBczK_K-WwOTw}OlZ;1S*r}vhjVN$DwYNb=H3j{0%H$d_9WCQu*`9yHS!9&^Y{;hY5pU=etbu)I9DAp|xhp7thHesq3!cJ2Pc6RH8RJGt73g&V@QW>o6 zF=4*subADV6LQo7YmW|-wgssY?uM;U3LK8=g!O8{xT8AETH;X?W-SNSCKpHtkLLSR zC>t*aQ>c`3*+3M*E3Z^w%I;q=!1`Q`q(hu?wSrFZ`Ku<_->!PYdiBd|b1Lj#`0f4* z3gch^G2~W5zg~@k+$82X3*ray05< z@rw9Xb>&keS8=IS%o&YaLh<#h#eTU?9!ap`(kZbQNeUDD0Oj0i)luD+nL{8{dl|`l_)I|yX87B?CfvFUb#-* z}yn%si;)3K?SR*Rbf-HTg5&V z?JBxe92d_Aqvr;3PzH;MF93C_YEo5;s@hc5sj6eDI;pC&s=BDE%c{DeszFuVSJfj$ zVdIE*g2|VLi4;P9*fy&4Rb`-Ej!|W}UB;+#qFqi?WvX4yRb_@X@#pbSF)b9!aK9KHiiznHQvk1LKYS8iAi$)1oAmz%2?#1#BxL^S*(|lE_RM3oQ@p>V`=37{|~og zLEE+0=3F11*tb-0|w=J6CspLARrPhXR^7@;y;rMODO&KSZ!hHZ(%iMF?e KpQSA`$NdMR@{lP2 delta 3899 zcmZ{n4OCQR8prQ*WfYXDK_M8%1(61nQE>zvWFX|jEwU*I%}v7v6%!Q@{76J#hz#8_ z&}ZSAf%0W;Aoy`bRK(z6;C!4dJ|1!^VU#U$JT?iif?ZXhBX%1DVG-(*=Q5* zge~IpMHM9T!s1}qf?_+J=JsM6_3$9ELP53U-1K;5jf7JP*!7{v|LP`Z5>;egejVSCinx!MO&` z0SCZ%@LMne90U`=AHgJW2%HQ44n7RJ;fW^8DHTP;pH^PSTDY*wRN_Ej3?A|0pdOqL zdV$}4KkOXm(thBRXb%M!fL3rJ_z<`Vj0gV&CW6?`oqq(=z$d_^U<&wWFcn+|ri07D zY&;qDLV0LVF8mz0iZ||FgvI&(Zqw{+w2eet4v3{GtOJ!v=79z z4q^+Iwu4P6ThOMAQ3xu1i$H&{7#t5OH~I(gc@nlM6W)$?Wx_kaCtX|sz68A#+{vf- zx!u(d(p)xITVPYFBd{-StB#{L_$#b0J|u{1+L^PvWP9riC}g;!#L$(*q# z9G{?Fds=9&9Q$f0DOv9x_LrS|n~2u3xh53WQL~>~c@Tap`_x9z6;7@#B!50%n~JD$ zUn1Jm_C4$2ukL#!_;S!0Z@CZc)WqhxP*_J@Ikw6xbtM$Y3+uzhKr6q}^eA7f_oPI= zT5lKUS$SV$2+wKo#8&5MD09D!M~kTn(uFbTbEm;eysh@pE0e#Ab(D;tkuw_Y6vROX zLiI1B?FPyXhHuD^^0xLJo2$rb1xL3_|; zxd-+Op&Mrt_Z)be0_7dAk0ABJ2d~p|x!`XtB=*|aKPj5inWNSF!RCeH zu#JbC!;HhOz`c(~I_|`XVJC8YOCiN^S4%K#UyCm$72mRipOM`8nL~b}GYXF?gli6Y z;#>B{p~KY1Pq&8C3Et7#;?b)PN?J@C&jrX;MDHnaWtr!C)A1)!MeBtmC z5zD}QEDoQ>OxRLB0K1(BU@O@y$C1RDu>1J{?CU%L+s5YOHfrZI*e+p(P%+;&f=iC^e6h^5h7oa4_&It{r09)v1+ z5LQwXBF`Aa{aQl$83PKDcgBK3)WWu_3D=O&r6m};45&y@mjxAZz+O@l{@P^_Kh_eu zk$@$emombFZiASrB{;hcDB3QBmT?zsmYU$!V-WMS zgy}s7R4u;8f~sZ1mMaPJ@t$=7G?vYuhtgQt@p&-eJD%59hLYXx3x+lJN6>5R=r5zg z+}m$~{jJ{@*5?alZO(-~%NxHaBOf06A`~|0nlHuj>}&rNnN9GRtzR#X5DlZH9DkbFaneM$JV+S*P>i%{rXb9dQbKVx z`9JP3+=taxnk#iFdB4n3rre|CDKB}TWSs<8*|%n6%XZebxBhnYpP#U*EMxhQ$v~(B$`4d(cLb6HyH)EUz5Hr8KB7! zmz=7}nJyWl$t0JYr^!^8T&&4uE}5mtJeS<8NvBJet5R2ipSq)@lxZk@wPc-!vb-fZ z0NsUu2Xq(V`e-==QoWKBC3PuqNM7McU4TV1TIx~8SgN*AriQgrvJ!7aJX>;vBknJi zqJ^wdt%3yUR5)R4>=+2A!2kb;wPSoFJ?19f(o3tOXomh(EYQ6;l_mPJbRdc%IzEY_ ni=;0?!&aPyIE$rI(PTTCWFXyZkTo*>{5#2ppKs8v`JVp*RS|@< From 16a2a478bcda3e28520a4c461a9406be82bb94c6 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 18 Jul 2018 23:53:06 +1000 Subject: [PATCH 1136/2058] SetupTool: Fix updater creating uninstall entries for portable releases --- tools/CustomSetupTool/CustomSetupTool/update.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/CustomSetupTool/CustomSetupTool/update.c b/tools/CustomSetupTool/CustomSetupTool/update.c index dfbfd600ba01..ccbbff4cb2a3 100644 --- a/tools/CustomSetupTool/CustomSetupTool/update.c +++ b/tools/CustomSetupTool/CustomSetupTool/update.c @@ -39,7 +39,7 @@ NTSTATUS SetupUpdateBuild( if (!SetupCreateUninstallFile(Context)) goto CleanupExit; - SetupCreateUninstallKey(Context); + //SetupCreateUninstallKey(Context); if (!SetupExtractBuild(Context)) goto CleanupExit; From 6b58649ee12b40dc5e13a07c17b6612b5e51b289 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 19 Jul 2018 01:32:57 +1000 Subject: [PATCH 1137/2058] Update network node count --- ProcessHacker/include/netlist.h | 2 +- ProcessHacker/netlist.c | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/ProcessHacker/include/netlist.h b/ProcessHacker/include/netlist.h index e1ebe044ef1c..77e9537b3f46 100644 --- a/ProcessHacker/include/netlist.h +++ b/ProcessHacker/include/netlist.h @@ -30,7 +30,7 @@ typedef struct _PH_NETWORK_NODE PH_STRINGREF TextCache[PHNETLC_MAXIMUM]; - ULONG UniqueId; + ULONG64 UniqueId; PPH_STRING ProcessNameText; PPH_STRING TimeStampText; diff --git a/ProcessHacker/netlist.c b/ProcessHacker/netlist.c index 9268608cc7d2..678fb69a5a2b 100644 --- a/ProcessHacker/netlist.c +++ b/ProcessHacker/netlist.c @@ -74,7 +74,7 @@ static PH_CM_MANAGER NetworkTreeListCm; static PPH_HASHTABLE NetworkNodeHashtable; // hashtable of all nodes static PPH_LIST NetworkNodeList; // list of all nodes -static ULONG NextUniqueId = 1; +static ULONG64 NextUniqueId = 0; BOOLEAN PhNetworkTreeListStateHighlighting = TRUE; static PPH_POINTER_LIST NetworkNodeStateList = NULL; // list of nodes which need to be processed @@ -215,7 +215,7 @@ PPH_NETWORK_NODE PhAddNetworkNode( networkNode->NetworkItem = NetworkItem; PhReferenceObject(NetworkItem); - networkNode->UniqueId = NextUniqueId++; // used to stabilize sorting + networkNode->UniqueId = ++NextUniqueId; // used to stabilize sorting memset(networkNode->TextCache, 0, sizeof(PH_STRINGREF) * PHNETLC_MAXIMUM); networkNode->Node.TextCache = networkNode->TextCache; @@ -345,7 +345,7 @@ VOID PhTickNetworkNodes( #define END_SORT_FUNCTION \ if (sortResult == 0) \ - sortResult = uintcmp(node1->UniqueId, node2->UniqueId); \ + sortResult = uint64cmp(node1->UniqueId, node2->UniqueId); \ \ return PhModifySort(sortResult, NetworkTreeListSortOrder); \ } @@ -358,7 +358,7 @@ LONG PhpNetworkTreeNewPostSortFunction( ) { if (Result == 0) - Result = uintcmp(((PPH_NETWORK_NODE)Node1)->UniqueId, ((PPH_NETWORK_NODE)Node2)->UniqueId); + Result = uint64cmp(((PPH_NETWORK_NODE)Node1)->UniqueId, ((PPH_NETWORK_NODE)Node2)->UniqueId); return PhModifySort(Result, SortOrder); } From 65caf7ed6ef3661c64f238c8421f1c02ac80daa4 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 19 Jul 2018 09:56:38 +1000 Subject: [PATCH 1138/2058] Plugins: Update DelayLoadDLLs --- plugins/DotNetTools/DotNetTools.vcxproj | 4 ++++ .../ExtendedNotifications.vcxproj | 8 ++++---- .../ExtendedServices/ExtendedServices.vcxproj | 20 +++++++++++++++++++ plugins/ExtendedTools/ExtendedTools.vcxproj | 4 ++++ .../HardwareDevices/HardwareDevices.vcxproj | 8 ++++---- plugins/NetworkTools/NetworkTools.vcxproj | 8 ++++---- plugins/OnlineChecks/OnlineChecks.vcxproj | 8 ++++---- plugins/ToolStatus/ToolStatus.vcxproj | 4 ++++ plugins/Updater/Updater.vcxproj | 8 ++++---- plugins/UserNotes/UserNotes.vcxproj | 4 ++++ plugins/WindowExplorer/WindowExplorer.vcxproj | 8 ++++---- 11 files changed, 60 insertions(+), 24 deletions(-) diff --git a/plugins/DotNetTools/DotNetTools.vcxproj b/plugins/DotNetTools/DotNetTools.vcxproj index 98bcc6c571f7..4ab20fb53f4e 100644 --- a/plugins/DotNetTools/DotNetTools.vcxproj +++ b/plugins/DotNetTools/DotNetTools.vcxproj @@ -55,21 +55,25 @@ uxtheme.lib;%(AdditionalDependencies) + advapi32.dll;user32.dll;uxtheme.dll;%(DelayLoadDLLs) uxtheme.lib;%(AdditionalDependencies) + advapi32.dll;user32.dll;uxtheme.dll;%(DelayLoadDLLs) uxtheme.lib;%(AdditionalDependencies) + advapi32.dll;user32.dll;uxtheme.dll;%(DelayLoadDLLs) uxtheme.lib;%(AdditionalDependencies) + advapi32.dll;user32.dll;uxtheme.dll;%(DelayLoadDLLs) diff --git a/plugins/ExtendedNotifications/ExtendedNotifications.vcxproj b/plugins/ExtendedNotifications/ExtendedNotifications.vcxproj index 239358abb274..efc911ed6ee4 100644 --- a/plugins/ExtendedNotifications/ExtendedNotifications.vcxproj +++ b/plugins/ExtendedNotifications/ExtendedNotifications.vcxproj @@ -54,25 +54,25 @@ ws2_32.lib;%(AdditionalDependencies) - ws2_32.dll;%(DelayLoadDLLs) + user32.dll;ws2_32.dll;%(DelayLoadDLLs) ws2_32.lib;%(AdditionalDependencies) - ws2_32.dll;%(DelayLoadDLLs) + user32.dll;ws2_32.dll;%(DelayLoadDLLs) ws2_32.lib;%(AdditionalDependencies) - ws2_32.dll;%(DelayLoadDLLs) + user32.dll;ws2_32.dll;%(DelayLoadDLLs) ws2_32.lib;%(AdditionalDependencies) - ws2_32.dll;%(DelayLoadDLLs) + user32.dll;ws2_32.dll;%(DelayLoadDLLs) diff --git a/plugins/ExtendedServices/ExtendedServices.vcxproj b/plugins/ExtendedServices/ExtendedServices.vcxproj index 1d56e72aa6ed..4d3e69179c81 100644 --- a/plugins/ExtendedServices/ExtendedServices.vcxproj +++ b/plugins/ExtendedServices/ExtendedServices.vcxproj @@ -51,6 +51,26 @@ + + + advapi32.dll;comctl32.dll;user32.dll;%(DelayLoadDLLs) + + + + + advapi32.dll;comctl32.dll;user32.dll;%(DelayLoadDLLs) + + + + + advapi32.dll;comctl32.dll;user32.dll;%(DelayLoadDLLs) + + + + + advapi32.dll;comctl32.dll;user32.dll;%(DelayLoadDLLs) + + diff --git a/plugins/ExtendedTools/ExtendedTools.vcxproj b/plugins/ExtendedTools/ExtendedTools.vcxproj index 348b15da9481..a6260111c748 100644 --- a/plugins/ExtendedTools/ExtendedTools.vcxproj +++ b/plugins/ExtendedTools/ExtendedTools.vcxproj @@ -54,21 +54,25 @@ cfgmgr32.lib;uxtheme.lib;%(AdditionalDependencies) + advapi32.dll;comctl32.dll;cfgmgr32.dll;gdi32.dll;ole32.dll;oleaut32.dll;user32.dll;uxtheme.dll;%(DelayLoadDLLs) cfgmgr32.lib;uxtheme.lib;%(AdditionalDependencies) + advapi32.dll;comctl32.dll;cfgmgr32.dll;gdi32.dll;ole32.dll;oleaut32.dll;user32.dll;uxtheme.dll;%(DelayLoadDLLs) cfgmgr32.lib;uxtheme.lib;%(AdditionalDependencies) + advapi32.dll;comctl32.dll;cfgmgr32.dll;gdi32.dll;ole32.dll;oleaut32.dll;user32.dll;uxtheme.dll;%(DelayLoadDLLs) cfgmgr32.lib;uxtheme.lib;%(AdditionalDependencies) + advapi32.dll;comctl32.dll;cfgmgr32.dll;gdi32.dll;ole32.dll;oleaut32.dll;user32.dll;uxtheme.dll;%(DelayLoadDLLs) diff --git a/plugins/HardwareDevices/HardwareDevices.vcxproj b/plugins/HardwareDevices/HardwareDevices.vcxproj index 71417d9be759..a34fc5115510 100644 --- a/plugins/HardwareDevices/HardwareDevices.vcxproj +++ b/plugins/HardwareDevices/HardwareDevices.vcxproj @@ -54,26 +54,26 @@ cfgmgr32.lib;iphlpapi.lib;uxtheme.lib;%(AdditionalDependencies) - cfgmgr32.dll;iphlpapi.dll;%(DelayLoadDLLs) + comctl32.dll;cfgmgr32.dll;iphlpapi.dll;user32.dll;uxtheme.dll;%(DelayLoadDLLs) cfgmgr32.lib;iphlpapi.lib;uxtheme.lib;%(AdditionalDependencies) - cfgmgr32.dll;iphlpapi.dll;%(DelayLoadDLLs) + comctl32.dll;cfgmgr32.dll;iphlpapi.dll;user32.dll;uxtheme.dll;%(DelayLoadDLLs) cfgmgr32.lib;iphlpapi.lib;uxtheme.lib;%(AdditionalDependencies) - cfgmgr32.dll;iphlpapi.dll;%(DelayLoadDLLs) + comctl32.dll;cfgmgr32.dll;iphlpapi.dll;user32.dll;uxtheme.dll;%(DelayLoadDLLs) cfgmgr32.lib;iphlpapi.lib;uxtheme.lib;%(AdditionalDependencies) - cfgmgr32.dll;iphlpapi.dll;%(DelayLoadDLLs) + comctl32.dll;cfgmgr32.dll;iphlpapi.dll;user32.dll;uxtheme.dll;%(DelayLoadDLLs) diff --git a/plugins/NetworkTools/NetworkTools.vcxproj b/plugins/NetworkTools/NetworkTools.vcxproj index a18d8560613a..73271669ee00 100644 --- a/plugins/NetworkTools/NetworkTools.vcxproj +++ b/plugins/NetworkTools/NetworkTools.vcxproj @@ -57,26 +57,26 @@ iphlpapi.lib;winhttp.lib;ws2_32.lib;uxtheme.lib;%(AdditionalDependencies) - iphlpapi.dll;winhttp.dll;ws2_32.dll;%(DelayLoadDLLs) + comctl32.dll;gdi32.dll;iphlpapi.dll;winhttp.dll;ws2_32.dll;user32.dll;uxtheme.dll;%(DelayLoadDLLs) iphlpapi.lib;winhttp.lib;ws2_32.lib;uxtheme.lib;%(AdditionalDependencies) - iphlpapi.dll;winhttp.dll;ws2_32.dll;%(DelayLoadDLLs) + comctl32.dll;gdi32.dll;iphlpapi.dll;winhttp.dll;ws2_32.dll;user32.dll;uxtheme.dll;%(DelayLoadDLLs) iphlpapi.lib;winhttp.lib;ws2_32.lib;uxtheme.lib;%(AdditionalDependencies) - iphlpapi.dll;winhttp.dll;ws2_32.dll;%(DelayLoadDLLs) + comctl32.dll;gdi32.dll;iphlpapi.dll;winhttp.dll;ws2_32.dll;user32.dll;uxtheme.dll;%(DelayLoadDLLs) iphlpapi.lib;winhttp.lib;ws2_32.lib;uxtheme.lib;%(AdditionalDependencies) - iphlpapi.dll;winhttp.dll;ws2_32.dll;%(DelayLoadDLLs) + comctl32.dll;gdi32.dll;iphlpapi.dll;winhttp.dll;ws2_32.dll;user32.dll;uxtheme.dll;%(DelayLoadDLLs) diff --git a/plugins/OnlineChecks/OnlineChecks.vcxproj b/plugins/OnlineChecks/OnlineChecks.vcxproj index 764cec17f922..ef6144e5ac96 100644 --- a/plugins/OnlineChecks/OnlineChecks.vcxproj +++ b/plugins/OnlineChecks/OnlineChecks.vcxproj @@ -57,25 +57,25 @@ winhttp.lib;%(AdditionalDependencies) - winhttp.dll;%(DelayLoadDLLs) + comctl32.dll;ole32.dll;user32.dll;winhttp.dll;%(DelayLoadDLLs) winhttp.lib;%(AdditionalDependencies) - winhttp.dll;%(DelayLoadDLLs) + comctl32.dll;ole32.dll;user32.dll;winhttp.dll;%(DelayLoadDLLs) winhttp.lib;%(AdditionalDependencies) - winhttp.dll;%(DelayLoadDLLs) + comctl32.dll;ole32.dll;user32.dll;winhttp.dll;%(DelayLoadDLLs) winhttp.lib;%(AdditionalDependencies) - winhttp.dll;%(DelayLoadDLLs) + comctl32.dll;ole32.dll;user32.dll;winhttp.dll;%(DelayLoadDLLs) diff --git a/plugins/ToolStatus/ToolStatus.vcxproj b/plugins/ToolStatus/ToolStatus.vcxproj index 6fc67d6814d2..b60b882c7f35 100644 --- a/plugins/ToolStatus/ToolStatus.vcxproj +++ b/plugins/ToolStatus/ToolStatus.vcxproj @@ -54,21 +54,25 @@ uxtheme.lib;%(AdditionalDependencies) + comctl32.dll;gdi32.dll;user32.dll;%(DelayLoadDLLs) uxtheme.lib;%(AdditionalDependencies) + comctl32.dll;gdi32.dll;user32.dll;%(DelayLoadDLLs) uxtheme.lib;%(AdditionalDependencies) + comctl32.dll;gdi32.dll;user32.dll;%(DelayLoadDLLs) uxtheme.lib;%(AdditionalDependencies) + comctl32.dll;gdi32.dll;user32.dll;%(DelayLoadDLLs) diff --git a/plugins/Updater/Updater.vcxproj b/plugins/Updater/Updater.vcxproj index 16bf8cf84c43..c9e89da0b5b4 100644 --- a/plugins/Updater/Updater.vcxproj +++ b/plugins/Updater/Updater.vcxproj @@ -57,25 +57,25 @@ bcrypt.lib;winhttp.lib;%(AdditionalDependencies) - bcrypt.dll;winhttp.dll;%(DelayLoadDLLs) + comctl32.dll;bcrypt.dll;shell32.dll;user32.dll;winhttp.dll;%(DelayLoadDLLs) bcrypt.lib;winhttp.lib;%(AdditionalDependencies) - bcrypt.dll;winhttp.dll;%(DelayLoadDLLs) + comctl32.dll;bcrypt.dll;shell32.dll;user32.dll;winhttp.dll;%(DelayLoadDLLs) bcrypt.lib;winhttp.lib;%(AdditionalDependencies) - bcrypt.dll;winhttp.dll;%(DelayLoadDLLs) + comctl32.dll;bcrypt.dll;shell32.dll;user32.dll;winhttp.dll;%(DelayLoadDLLs) bcrypt.lib;winhttp.lib;%(AdditionalDependencies) - bcrypt.dll;winhttp.dll;%(DelayLoadDLLs) + comctl32.dll;bcrypt.dll;shell32.dll;user32.dll;winhttp.dll;%(DelayLoadDLLs) diff --git a/plugins/UserNotes/UserNotes.vcxproj b/plugins/UserNotes/UserNotes.vcxproj index 8d379f625a0d..cbeef00a707c 100644 --- a/plugins/UserNotes/UserNotes.vcxproj +++ b/plugins/UserNotes/UserNotes.vcxproj @@ -54,21 +54,25 @@ uxtheme.lib;%(AdditionalDependencies) + comctl32.dll;comdlg32.dll;user32.dll;uxtheme.dll;%(DelayLoadDLLs) uxtheme.lib;%(AdditionalDependencies) + comctl32.dll;comdlg32.dll;user32.dll;uxtheme.dll;%(DelayLoadDLLs) uxtheme.lib;%(AdditionalDependencies) + comctl32.dll;comdlg32.dll;user32.dll;uxtheme.dll;%(DelayLoadDLLs) uxtheme.lib;%(AdditionalDependencies) + comctl32.dll;comdlg32.dll;user32.dll;uxtheme.dll;%(DelayLoadDLLs) diff --git a/plugins/WindowExplorer/WindowExplorer.vcxproj b/plugins/WindowExplorer/WindowExplorer.vcxproj index b88021030029..9220ad3b18c4 100644 --- a/plugins/WindowExplorer/WindowExplorer.vcxproj +++ b/plugins/WindowExplorer/WindowExplorer.vcxproj @@ -53,22 +53,22 @@ - ProcessHacker.exe;comctl32.dll;%(DelayLoadDLLs) + gdi32.dll;ProcessHacker.exe;user32.dll;%(DelayLoadDLLs) - ProcessHacker.exe;comctl32.dll;%(DelayLoadDLLs) + gdi32.dll;ProcessHacker.exe;user32.dll;%(DelayLoadDLLs) - ProcessHacker.exe;comctl32.dll;%(DelayLoadDLLs) + gdi32.dll;ProcessHacker.exe;user32.dll;%(DelayLoadDLLs) - ProcessHacker.exe;comctl32.dll;%(DelayLoadDLLs) + gdi32.dll;ProcessHacker.exe;user32.dll;%(DelayLoadDLLs) From 6477f9c0e0ed7e387dc5464308cdbc34d4c4bf35 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 19 Jul 2018 12:00:57 +1000 Subject: [PATCH 1139/2058] Add PhEditSecurity window thread support --- ProcessHacker/hndlprp.c | 26 ++---- ProcessHacker/jobprp.c | 26 ++---- ProcessHacker/prpggen.c | 30 ++----- ProcessHacker/prpgthrd.c | 29 ++----- ProcessHacker/srvprp.c | 72 ++++++++-------- ProcessHacker/tokprp.c | 29 ++----- phlib/include/secedit.h | 21 ++--- phlib/include/seceditp.h | 22 +++-- phlib/secedit.c | 180 +++++++++++++++++++++------------------ 9 files changed, 195 insertions(+), 240 deletions(-) diff --git a/ProcessHacker/hndlprp.c b/ProcessHacker/hndlprp.c index e6d73b2d955b..46ed9dfb1034 100644 --- a/ProcessHacker/hndlprp.c +++ b/ProcessHacker/hndlprp.c @@ -150,9 +150,6 @@ VOID PhShowHandleProperties( PROPSHEETPAGE propSheetPage; HPROPSHEETPAGE pages[16]; HANDLE_PROPERTIES_CONTEXT context; - PH_STD_OBJECT_SECURITY stdObjectSecurity; - PPH_ACCESS_ENTRY accessEntries; - ULONG numberOfAccessEntries; context.ProcessId = ProcessId; context.HandleItem = HandleItem; @@ -242,22 +239,13 @@ VOID PhShowHandleProperties( } // Security page - stdObjectSecurity.OpenObject = PhpDuplicateHandleFromProcess; - stdObjectSecurity.ObjectType = PhGetStringOrEmpty(HandleItem->TypeName); - stdObjectSecurity.Context = &context; - - if (PhGetAccessEntries(PhGetStringOrEmpty(HandleItem->TypeName), &accessEntries, &numberOfAccessEntries)) - { - pages[propSheetHeader.nPages++] = PhCreateSecurityPage( - PhGetStringOrEmpty(HandleItem->BestObjectName), - PhStdGetObjectSecurity, - PhStdSetObjectSecurity, - &stdObjectSecurity, - accessEntries, - numberOfAccessEntries - ); - PhFree(accessEntries); - } + pages[propSheetHeader.nPages++] = PhCreateSecurityPage( + PhGetStringOrEmpty(HandleItem->BestObjectName), + PhGetStringOrEmpty(HandleItem->TypeName), + PhpDuplicateHandleFromProcess, + NULL, + &context + ); if (PhPluginsEnabled) { diff --git a/ProcessHacker/jobprp.c b/ProcessHacker/jobprp.c index 00d72d998795..c6244eae5766 100644 --- a/ProcessHacker/jobprp.c +++ b/ProcessHacker/jobprp.c @@ -493,9 +493,6 @@ VOID PhpShowJobAdvancedProperties( PROPSHEETHEADER propSheetHeader = { sizeof(propSheetHeader) }; HPROPSHEETPAGE pages[2]; PROPSHEETPAGE statisticsPage; - PH_STD_OBJECT_SECURITY stdObjectSecurity; - PPH_ACCESS_ENTRY accessEntries; - ULONG numberOfAccessEntries; propSheetHeader.dwFlags = PSH_NOAPPLYNOW | @@ -520,22 +517,13 @@ VOID PhpShowJobAdvancedProperties( // Security - stdObjectSecurity.OpenObject = Context->OpenObject; - stdObjectSecurity.ObjectType = L"Job"; - stdObjectSecurity.Context = Context->Context; - - if (PhGetAccessEntries(L"Job", &accessEntries, &numberOfAccessEntries)) - { - pages[1] = PhCreateSecurityPage( - L"Job", - PhStdGetObjectSecurity, - PhStdSetObjectSecurity, - &stdObjectSecurity, - accessEntries, - numberOfAccessEntries - ); - PhFree(accessEntries); - } + pages[1] = PhCreateSecurityPage( + L"Job", + L"Job", + Context->OpenObject, + NULL, + Context->Context + ); PhModalPropertySheet(&propSheetHeader); } diff --git a/ProcessHacker/prpggen.c b/ProcessHacker/prpggen.c index e325ad64bf12..fc699c067078 100644 --- a/ProcessHacker/prpggen.c +++ b/ProcessHacker/prpggen.c @@ -31,6 +31,7 @@ #include #include +#include #include #include #include @@ -554,27 +555,14 @@ INT_PTR CALLBACK PhpProcessGeneralDlgProc( break; case IDC_PERMISSIONS: { - PH_STD_OBJECT_SECURITY stdObjectSecurity; - PPH_ACCESS_ENTRY accessEntries; - ULONG numberOfAccessEntries; - - stdObjectSecurity.OpenObject = PhpProcessGeneralOpenProcess; - stdObjectSecurity.ObjectType = L"Process"; - stdObjectSecurity.Context = processItem->ProcessId; - - if (PhGetAccessEntries(L"Process", &accessEntries, &numberOfAccessEntries)) - { - PhEditSecurity( - hwndDlg, - processItem->ProcessName->Buffer, - PhStdGetObjectSecurity, - PhStdSetObjectSecurity, - &stdObjectSecurity, - accessEntries, - numberOfAccessEntries - ); - PhFree(accessEntries); - } + PhEditSecurity( + PhCsForceNoParent ? NULL : hwndDlg, + PhGetStringOrEmpty(processItem->ProcessName), + L"Process", + PhpProcessGeneralOpenProcess, + NULL, + processItem->ProcessId + ); } break; } diff --git a/ProcessHacker/prpgthrd.c b/ProcessHacker/prpgthrd.c index b7b8cdba460c..a3177c992573 100644 --- a/ProcessHacker/prpgthrd.c +++ b/ProcessHacker/prpgthrd.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -788,29 +789,17 @@ INT_PTR CALLBACK PhpProcessThreadsDlgProc( case ID_THREAD_PERMISSIONS: { PPH_THREAD_ITEM threadItem = PhGetSelectedThreadItem(&threadsContext->ListContext); - PH_STD_OBJECT_SECURITY stdObjectSecurity; - PPH_ACCESS_ENTRY accessEntries; - ULONG numberOfAccessEntries; if (threadItem) { - stdObjectSecurity.OpenObject = PhpThreadPermissionsOpenThread; - stdObjectSecurity.ObjectType = L"Thread"; - stdObjectSecurity.Context = threadItem->ThreadId; - - if (PhGetAccessEntries(L"Thread", &accessEntries, &numberOfAccessEntries)) - { - PhEditSecurity( - hwndDlg, - PhaFormatString(L"Thread %u", HandleToUlong(threadItem->ThreadId))->Buffer, - PhStdGetObjectSecurity, - PhStdSetObjectSecurity, - &stdObjectSecurity, - accessEntries, - numberOfAccessEntries - ); - PhFree(accessEntries); - } + PhEditSecurity( + PhCsForceNoParent ? NULL : hwndDlg, + PhaFormatString(L"Thread %u", HandleToUlong(threadItem->ThreadId))->Buffer, + L"Thread", + PhpThreadPermissionsOpenThread, + NULL, + threadItem->ThreadId + ); } } break; diff --git a/ProcessHacker/srvprp.c b/ProcessHacker/srvprp.c index 0bd7c7a1772c..9597b2442ccf 100644 --- a/ProcessHacker/srvprp.c +++ b/ProcessHacker/srvprp.c @@ -58,14 +58,30 @@ static NTSTATUS PhpOpenService( ) { SC_HANDLE serviceHandle; + PPH_SERVICE_ITEM serviceItem; + + serviceItem = ((PPH_SERVICE_ITEM)Context); - if (!(serviceHandle = PhOpenService( - ((PPH_SERVICE_ITEM)Context)->Name->Buffer, + if (serviceHandle = PhOpenService( + serviceItem->Name->Buffer, DesiredAccess - ))) - return PhGetLastWin32ErrorAsNtStatus(); + )) + { + *Handle = serviceHandle; + return STATUS_SUCCESS; + } - *Handle = serviceHandle; + return PhGetLastWin32ErrorAsNtStatus(); +} + +NTSTATUS PhpCloseServiceCallback( + _In_opt_ PVOID Context + ) +{ + PPH_SERVICE_ITEM serviceItem; + + serviceItem = ((PPH_SERVICE_ITEM)Context); + PhDereferenceObject(serviceItem); return STATUS_SUCCESS; } @@ -254,12 +270,9 @@ INT_PTR CALLBACK PhpServiceGeneralDlgProc( else PhLoadWindowPlacementFromSetting(L"ServiceWindowPosition", NULL, GetParent(hwndDlg)); - PhAddComboBoxStrings(GetDlgItem(hwndDlg, IDC_TYPE), PhServiceTypeStrings, - sizeof(PhServiceTypeStrings) / sizeof(WCHAR *)); - PhAddComboBoxStrings(GetDlgItem(hwndDlg, IDC_STARTTYPE), PhServiceStartTypeStrings, - sizeof(PhServiceStartTypeStrings) / sizeof(WCHAR *)); - PhAddComboBoxStrings(GetDlgItem(hwndDlg, IDC_ERRORCONTROL), PhServiceErrorControlStrings, - sizeof(PhServiceErrorControlStrings) / sizeof(WCHAR *)); + PhAddComboBoxStrings(GetDlgItem(hwndDlg, IDC_TYPE), PhServiceTypeStrings, RTL_NUMBER_OF(PhServiceTypeStrings)); + PhAddComboBoxStrings(GetDlgItem(hwndDlg, IDC_STARTTYPE), PhServiceStartTypeStrings, RTL_NUMBER_OF(PhServiceStartTypeStrings)); + PhAddComboBoxStrings(GetDlgItem(hwndDlg, IDC_ERRORCONTROL), PhServiceErrorControlStrings, RTL_NUMBER_OF(PhServiceErrorControlStrings)); PhSetDialogItemText(hwndDlg, IDC_DESCRIPTION, PhGetStringOrEmpty(serviceItem->DisplayName)); PhSelectComboBoxString(GetDlgItem(hwndDlg, IDC_TYPE), PhGetServiceTypeString(serviceItem->Type), FALSE); @@ -307,10 +320,8 @@ INT_PTR CALLBACK PhpServiceGeneralDlgProc( CloseServiceHandle(serviceHandle); } - PhSelectComboBoxString(GetDlgItem(hwndDlg, IDC_STARTTYPE), - PhGetServiceStartTypeString(startType), FALSE); - PhSelectComboBoxString(GetDlgItem(hwndDlg, IDC_ERRORCONTROL), - PhGetServiceErrorControlString(errorControl), FALSE); + PhSelectComboBoxString(GetDlgItem(hwndDlg, IDC_STARTTYPE), PhGetServiceStartTypeString(startType), FALSE); + PhSelectComboBoxString(GetDlgItem(hwndDlg, IDC_ERRORCONTROL), PhGetServiceErrorControlString(errorControl), FALSE); PhSetDialogItemText(hwndDlg, IDC_PASSWORD, L"password"); Button_SetCheck(GetDlgItem(hwndDlg, IDC_PASSWORDCHECK), BST_UNCHECKED); @@ -406,27 +417,16 @@ INT_PTR CALLBACK PhpServiceGeneralDlgProc( break; case IDC_PERMISSIONS: { - PH_STD_OBJECT_SECURITY stdObjectSecurity; - PPH_ACCESS_ENTRY accessEntries; - ULONG numberOfAccessEntries; - - stdObjectSecurity.OpenObject = PhpOpenService; - stdObjectSecurity.ObjectType = L"Service"; - stdObjectSecurity.Context = context->ServiceItem; - - if (PhGetAccessEntries(L"Service", &accessEntries, &numberOfAccessEntries)) - { - PhEditSecurity( - hwndDlg, - context->ServiceItem->DisplayName->Buffer, - PhStdGetObjectSecurity, - PhStdSetObjectSecurity, - &stdObjectSecurity, - accessEntries, - numberOfAccessEntries - ); - PhFree(accessEntries); - } + PhReferenceObject(context->ServiceItem); + + PhEditSecurity( + PhCsForceNoParent ? NULL : hwndDlg, + PhGetStringOrEmpty(context->ServiceItem->DisplayName), + L"Service", + PhpOpenService, + PhpCloseServiceCallback, + context->ServiceItem + ); } break; } diff --git a/ProcessHacker/tokprp.c b/ProcessHacker/tokprp.c index 18e433834982..b104316cf11e 100644 --- a/ProcessHacker/tokprp.c +++ b/ProcessHacker/tokprp.c @@ -893,27 +893,14 @@ INT_PTR CALLBACK PhpTokenPageProc( break; case IDC_PERMISSIONS: { - PH_STD_OBJECT_SECURITY stdObjectSecurity; - PPH_ACCESS_ENTRY accessEntries; - ULONG numberOfAccessEntries; - - stdObjectSecurity.OpenObject = tokenPageContext->OpenObject; - stdObjectSecurity.ObjectType = L"Token"; - stdObjectSecurity.Context = tokenPageContext->Context; - - if (PhGetAccessEntries(L"Token", &accessEntries, &numberOfAccessEntries)) - { - PhEditSecurity( - hwndDlg, - L"Token", - PhStdGetObjectSecurity, - PhStdSetObjectSecurity, - &stdObjectSecurity, - accessEntries, - numberOfAccessEntries - ); - PhFree(accessEntries); - } + PhEditSecurity( + PhCsForceNoParent ? NULL : hwndDlg, + L"Token", + L"Token", + tokenPageContext->OpenObject, + NULL, + tokenPageContext->Context + ); } break; case IDC_INTEGRITY: diff --git a/phlib/include/secedit.h b/phlib/include/secedit.h index cde07e7702d4..2c013cabb84c 100644 --- a/phlib/include/secedit.h +++ b/phlib/include/secedit.h @@ -23,29 +23,26 @@ HPROPSHEETPAGE NTAPI PhCreateSecurityPage( _In_ PWSTR ObjectName, - _In_ PPH_GET_OBJECT_SECURITY GetObjectSecurity, - _In_ PPH_SET_OBJECT_SECURITY SetObjectSecurity, - _In_opt_ PVOID Context, - _In_ PPH_ACCESS_ENTRY AccessEntries, - _In_ ULONG NumberOfAccessEntries + _In_ PWSTR ObjectType, + _In_ PPH_OPEN_OBJECT OpenObject, + _In_ PPH_CLOSE_OBJECT CloseObject, + _In_opt_ PVOID Context ); PHLIBAPI VOID NTAPI PhEditSecurity( - _In_ HWND hWnd, + _In_ HWND WindowHandle, _In_ PWSTR ObjectName, - _In_ PPH_GET_OBJECT_SECURITY GetObjectSecurity, - _In_ PPH_SET_OBJECT_SECURITY SetObjectSecurity, - _In_opt_ PVOID Context, - _In_ PPH_ACCESS_ENTRY AccessEntries, - _In_ ULONG NumberOfAccessEntries + _In_ PWSTR ObjectType, + _In_ PPH_OPEN_OBJECT OpenCallback, + _In_ PPH_CLOSE_OBJECT CloseCallback, + _In_opt_ PVOID Context ); typedef struct _PH_STD_OBJECT_SECURITY { - PPH_OPEN_OBJECT OpenObject; PWSTR ObjectType; PVOID Context; } PH_STD_OBJECT_SECURITY, *PPH_STD_OBJECT_SECURITY; diff --git a/phlib/include/seceditp.h b/phlib/include/seceditp.h index 3bd325245600..f0a8db0b1c9c 100644 --- a/phlib/include/seceditp.h +++ b/phlib/include/seceditp.h @@ -10,13 +10,17 @@ typedef struct ULONG RefCount; - PPH_STRING ObjectName; - PPH_GET_OBJECT_SECURITY GetObjectSecurity; - PPH_SET_OBJECT_SECURITY SetObjectSecurity; - PVOID Context; + HWND WindowHandle; + BOOLEAN IsPage; + PPH_ACCESS_ENTRY AccessEntriesArray; PSI_ACCESS AccessEntries; ULONG NumberOfAccessEntries; - BOOLEAN IsPage; + + PPH_STRING ObjectName; + PPH_STRING ObjectType; + PPH_OPEN_OBJECT OpenObject; + PPH_CLOSE_OBJECT CloseObject; + PVOID Context; } PhSecurityInformation; typedef struct @@ -39,12 +43,12 @@ typedef struct } PhSecurityIDataObject; ISecurityInformation *PhSecurityInformation_Create( + _In_ HWND WindowHandle, _In_ PWSTR ObjectName, - _In_ PPH_GET_OBJECT_SECURITY GetObjectSecurity, - _In_ PPH_SET_OBJECT_SECURITY SetObjectSecurity, + _In_ PWSTR ObjectType, + _In_ PPH_OPEN_OBJECT OpenObject, + _In_ PPH_CLOSE_OBJECT CloseObject, _In_opt_ PVOID Context, - _In_ PPH_ACCESS_ENTRY AccessEntries, - _In_ ULONG NumberOfAccessEntries, _In_ BOOLEAN IsPage ); diff --git a/phlib/secedit.c b/phlib/secedit.c index 22b8203200c9..2893016c046b 100644 --- a/phlib/secedit.c +++ b/phlib/secedit.c @@ -74,33 +74,27 @@ static IDataObjectVtbl PhDataObject_VTable = * Creates a security editor page. * * \param ObjectName The name of the object. - * \param GetObjectSecurity A callback function executed to retrieve the security descriptor of the - * object. - * \param SetObjectSecurity A callback function executed to modify the security descriptor of the - * object. + * \param ObjectType The type name of the object. * \param Context A user-defined value to pass to the callback functions. - * \param AccessEntries An array of access mask descriptors. - * \param NumberOfAccessEntries The number of elements in \a AccessEntries. */ HPROPSHEETPAGE PhCreateSecurityPage( _In_ PWSTR ObjectName, - _In_ PPH_GET_OBJECT_SECURITY GetObjectSecurity, - _In_ PPH_SET_OBJECT_SECURITY SetObjectSecurity, - _In_opt_ PVOID Context, - _In_ PPH_ACCESS_ENTRY AccessEntries, - _In_ ULONG NumberOfAccessEntries + _In_ PWSTR ObjectType, + _In_ PPH_OPEN_OBJECT OpenObject, + _In_ PPH_CLOSE_OBJECT CloseObject, + _In_opt_ PVOID Context ) { ISecurityInformation *info; HPROPSHEETPAGE page; info = PhSecurityInformation_Create( + NULL, ObjectName, - GetObjectSecurity, - SetObjectSecurity, + ObjectType, + OpenObject, + CloseObject, Context, - AccessEntries, - NumberOfAccessEntries, TRUE ); @@ -111,84 +105,98 @@ HPROPSHEETPAGE PhCreateSecurityPage( return page; } +static NTSTATUS PhpEditSecurityInformationThread( + _In_opt_ PVOID Context + ) +{ + PhSecurityInformation *this = (PhSecurityInformation *)Context; + + if (WindowsVersion >= WINDOWS_8 && PhGetIntegerSetting(L"EnableSecurityAdvancedDialog")) + EditSecurityAdvanced(this->WindowHandle, Context, COMBINE_PAGE_ACTIVATION(SI_PAGE_PERM, SI_SHOW_PERM_ACTIVATED)); + else + EditSecurity(this->WindowHandle, Context); + + PhSecurityInformation_Release(Context); + + return STATUS_SUCCESS; +} + /** * Displays a security editor dialog. * * \param hWnd The parent window of the dialog. * \param ObjectName The name of the object. - * \param GetObjectSecurity A callback function executed to retrieve the security descriptor of the - * object. - * \param SetObjectSecurity A callback function executed to modify the security descriptor of the - * object. * \param Context A user-defined value to pass to the callback functions. - * \param AccessEntries An array of access mask descriptors. - * \param NumberOfAccessEntries The number of elements in \a AccessEntries. */ VOID PhEditSecurity( - _In_ HWND hWnd, + _In_ HWND WindowHandle, _In_ PWSTR ObjectName, - _In_ PPH_GET_OBJECT_SECURITY GetObjectSecurity, - _In_ PPH_SET_OBJECT_SECURITY SetObjectSecurity, - _In_opt_ PVOID Context, - _In_ PPH_ACCESS_ENTRY AccessEntries, - _In_ ULONG NumberOfAccessEntries + _In_ PWSTR ObjectType, + _In_ PPH_OPEN_OBJECT OpenObject, + _In_ PPH_CLOSE_OBJECT CloseObject, + _In_opt_ PVOID Context ) { ISecurityInformation *info; info = PhSecurityInformation_Create( + WindowHandle, ObjectName, - GetObjectSecurity, - SetObjectSecurity, + ObjectType, + OpenObject, + CloseObject, Context, - AccessEntries, - NumberOfAccessEntries, FALSE ); - if (WindowsVersion >= WINDOWS_8 && PhGetIntegerSetting(L"EnableSecurityAdvancedDialog")) - EditSecurityAdvanced(hWnd, info, COMBINE_PAGE_ACTIVATION(SI_PAGE_PERM, SI_SHOW_PERM_ACTIVATED)); - else - EditSecurity(hWnd, info); - - PhSecurityInformation_Release(info); + PhCreateThread2(PhpEditSecurityInformationThread, info); } ISecurityInformation *PhSecurityInformation_Create( + _In_ HWND WindowHandle, _In_ PWSTR ObjectName, - _In_ PPH_GET_OBJECT_SECURITY GetObjectSecurity, - _In_ PPH_SET_OBJECT_SECURITY SetObjectSecurity, + _In_ PWSTR ObjectType, + _In_ PPH_OPEN_OBJECT OpenObject, + _In_ PPH_CLOSE_OBJECT CloseObject, _In_opt_ PVOID Context, - _In_ PPH_ACCESS_ENTRY AccessEntries, - _In_ ULONG NumberOfAccessEntries, _In_ BOOLEAN IsPage ) { PhSecurityInformation *info; + PPH_ACCESS_ENTRY accessEntries; + ULONG numberOfAccessEntries; ULONG i; info = PhAllocate(sizeof(PhSecurityInformation)); info->VTable = &PhSecurityInformation_VTable; info->RefCount = 1; + info->WindowHandle = WindowHandle; info->ObjectName = PhCreateString(ObjectName); - info->GetObjectSecurity = GetObjectSecurity; - info->SetObjectSecurity = SetObjectSecurity; - info->Context = Context; - info->AccessEntries = PhAllocate(sizeof(SI_ACCESS) * NumberOfAccessEntries); - info->NumberOfAccessEntries = NumberOfAccessEntries; + info->ObjectType = PhCreateString(ObjectType); + info->OpenObject = OpenObject; + info->CloseObject = CloseObject; + info->Context = Context; info->IsPage = IsPage; - for (i = 0; i < NumberOfAccessEntries; i++) + if (PhGetAccessEntries(ObjectType, &accessEntries, &numberOfAccessEntries)) { - memset(&info->AccessEntries[i], 0, sizeof(SI_ACCESS)); - info->AccessEntries[i].pszName = AccessEntries[i].Name; - info->AccessEntries[i].mask = AccessEntries[i].Access; - - if (AccessEntries[i].General) - info->AccessEntries[i].dwFlags |= SI_ACCESS_GENERAL; - if (AccessEntries[i].Specific) - info->AccessEntries[i].dwFlags |= SI_ACCESS_SPECIFIC; + info->AccessEntries = PhAllocate(sizeof(SI_ACCESS) * numberOfAccessEntries); + info->NumberOfAccessEntries = numberOfAccessEntries; + + for (i = 0; i < numberOfAccessEntries; i++) + { + memset(&info->AccessEntries[i], 0, sizeof(SI_ACCESS)); + info->AccessEntries[i].pszName = accessEntries[i].Name; + info->AccessEntries[i].mask = accessEntries[i].Access; + + if (accessEntries[i].General) + info->AccessEntries[i].dwFlags |= SI_ACCESS_GENERAL; + if (accessEntries[i].Specific) + info->AccessEntries[i].dwFlags |= SI_ACCESS_SPECIFIC; + } + + info->AccessEntriesArray = accessEntries; } return (ISecurityInformation *)info; @@ -249,8 +257,17 @@ ULONG STDMETHODCALLTYPE PhSecurityInformation_Release( if (this->RefCount == 0) { - if (this->ObjectName) PhDereferenceObject(this->ObjectName); - PhFree(this->AccessEntries); + if (this->CloseObject) + this->CloseObject(this->Context); + + if (this->ObjectName) + PhDereferenceObject(this->ObjectName); + if (this->ObjectType) + PhDereferenceObject(this->ObjectType); + if (this->AccessEntries) + PhFree(this->AccessEntries); + if (this->AccessEntriesArray) + PhFree(this->AccessEntriesArray); PhFree(this); @@ -268,8 +285,8 @@ HRESULT STDMETHODCALLTYPE PhSecurityInformation_GetObjectInformation( PhSecurityInformation *this = (PhSecurityInformation *)This; memset(ObjectInfo, 0, sizeof(SI_OBJECT_INFO)); - ObjectInfo->dwFlags = SI_EDIT_ALL | SI_ADVANCED; - ObjectInfo->pszObjectName = this->ObjectName->Buffer; + ObjectInfo->dwFlags = SI_EDIT_ALL | SI_ADVANCED | SI_MAY_WRITE; + ObjectInfo->pszObjectName = PhGetString(this->ObjectName); return S_OK; } @@ -287,10 +304,10 @@ HRESULT STDMETHODCALLTYPE PhSecurityInformation_GetSecurity( ULONG sdLength; PSECURITY_DESCRIPTOR newSd; - status = this->GetObjectSecurity( + status = PhStdGetObjectSecurity( &securityDescriptor, RequestedInformation, - this->Context + this ); if (!NT_SUCCESS(status)) @@ -315,10 +332,10 @@ HRESULT STDMETHODCALLTYPE PhSecurityInformation_SetSecurity( PhSecurityInformation *this = (PhSecurityInformation *)This; NTSTATUS status; - status = this->SetObjectSecurity( + status = PhStdSetObjectSecurity( SecurityDescriptor, SecurityInformation, - this->Context + this ); if (!NT_SUCCESS(status)) @@ -520,23 +537,24 @@ HRESULT STDMETHODCALLTYPE PhSecurityDataObject_GetData( { PhSecurityIDataObject *this = (PhSecurityIDataObject *)This; PSID_INFO_LIST sidInfoList; + ULONG i; sidInfoList = (PSID_INFO_LIST)GlobalAlloc(GMEM_ZEROINIT, sizeof(SID_INFO_LIST) + (sizeof(SID_INFO) * this->SidCount)); sidInfoList->cItems = this->SidCount; - for (ULONG i = 0; i < this->SidCount; i++) + for (i = 0; i < this->SidCount; i++) { SID_INFO sidInfo; PPH_STRING sidString; - SID_NAME_USE sidUse; + SID_NAME_USE sidNameUse; memset(&sidInfo, 0, sizeof(SID_INFO)); sidInfo.pSid = this->Sids[i]; - if (sidString = PhGetSidFullName(sidInfo.pSid, FALSE, &sidUse)) + if (sidString = PhGetSidFullName(sidInfo.pSid, FALSE, &sidNameUse)) { - switch (sidUse) + switch (sidNameUse) { case SidTypeUser: case SidTypeLogonSession: @@ -715,27 +733,25 @@ _Callback_ NTSTATUS PhStdGetObjectSecurity( _In_opt_ PVOID Context ) { + PhSecurityInformation *this = (PhSecurityInformation *)Context; NTSTATUS status; - PPH_STD_OBJECT_SECURITY stdObjectSecurity; HANDLE handle; - stdObjectSecurity = (PPH_STD_OBJECT_SECURITY)Context; - - status = stdObjectSecurity->OpenObject( + status = this->OpenObject( &handle, PhGetAccessForGetSecurity(SecurityInformation), - stdObjectSecurity->Context + this->Context ); if (!NT_SUCCESS(status)) return status; - if (PhEqualStringZ(stdObjectSecurity->ObjectType, L"Service", TRUE)) + if (PhEqualString2(this->ObjectType, L"Service", TRUE)) { status = PhGetSeObjectSecurity(handle, SE_SERVICE, SecurityInformation, SecurityDescriptor); CloseServiceHandle(handle); } - else if (PhEqualStringZ(stdObjectSecurity->ObjectType, L"File", TRUE)) + else if (PhEqualString2(this->ObjectType, L"File", TRUE)) { status = PhpGetObjectSecurityWithTimeout(handle, SecurityInformation, SecurityDescriptor); NtClose(handle); @@ -765,22 +781,20 @@ _Callback_ NTSTATUS PhStdSetObjectSecurity( _In_opt_ PVOID Context ) { + PhSecurityInformation *this = (PhSecurityInformation *)Context; NTSTATUS status; - PPH_STD_OBJECT_SECURITY stdObjectSecurity; HANDLE handle; - stdObjectSecurity = (PPH_STD_OBJECT_SECURITY)Context; - - status = stdObjectSecurity->OpenObject( + status = this->OpenObject( &handle, PhGetAccessForSetSecurity(SecurityInformation), - stdObjectSecurity->Context + this->Context ); if (!NT_SUCCESS(status)) return status; - if (PhEqualStringZ(stdObjectSecurity->ObjectType, L"Service", TRUE)) + if (PhEqualString2(this->ObjectType, L"Service", TRUE)) { status = PhSetSeObjectSecurity(handle, SE_SERVICE, SecurityInformation, SecurityDescriptor); CloseServiceHandle(handle); @@ -831,10 +845,10 @@ NTSTATUS PhSetSeObjectSecurity( _In_ PSECURITY_DESCRIPTOR SecurityDescriptor ) { - ULONG win32Result; + ULONG win32Result = NO_ERROR; SECURITY_INFORMATION securityInformation = 0; - BOOLEAN present; - BOOLEAN defaulted; + BOOLEAN present = FALSE; + BOOLEAN defaulted = FALSE; PSID owner = NULL; PSID group = NULL; PACL dacl = NULL; From 80ec63109fa652dbcc44feffe50bf7a09b106f79 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 19 Jul 2018 12:04:48 +1000 Subject: [PATCH 1140/2058] Fix previous commit --- phlib/include/phnative.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/phlib/include/phnative.h b/phlib/include/phnative.h index 3cb2a3e8b949..4d74d0376a29 100644 --- a/phlib/include/phnative.h +++ b/phlib/include/phnative.h @@ -20,6 +20,10 @@ typedef NTSTATUS (NTAPI *PPH_OPEN_OBJECT)( _In_opt_ PVOID Context ); +typedef NTSTATUS (NTAPI *PPH_CLOSE_OBJECT)( + _In_opt_ PVOID Context + ); + typedef NTSTATUS (NTAPI *PPH_GET_OBJECT_SECURITY)( _Out_ PSECURITY_DESCRIPTOR *SecurityDescriptor, _In_ SECURITY_INFORMATION SecurityInformation, From 14ff046a89d0a12ae572e89cc8bc37b54d336623 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 19 Jul 2018 12:07:48 +1000 Subject: [PATCH 1141/2058] Add missing include --- ProcessHacker/tokprp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/ProcessHacker/tokprp.c b/ProcessHacker/tokprp.c index b104316cf11e..4302d6a306e1 100644 --- a/ProcessHacker/tokprp.c +++ b/ProcessHacker/tokprp.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include From 892aade735dc79fed960373a92216291c46cc10f Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 19 Jul 2018 12:18:56 +1000 Subject: [PATCH 1142/2058] BuildTools: Fix typo --- tools/CustomBuildTool/Source Files/Build.cs | 3 ++- .../bin/Release/CustomBuildTool.exe | Bin 165376 -> 165376 bytes .../bin/Release/CustomBuildTool.pdb | Bin 81408 -> 81408 bytes 3 files changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/CustomBuildTool/Source Files/Build.cs b/tools/CustomBuildTool/Source Files/Build.cs index ae218f5ec2be..85e739b7d44d 100644 --- a/tools/CustomBuildTool/Source Files/Build.cs +++ b/tools/CustomBuildTool/Source Files/Build.cs @@ -1141,6 +1141,7 @@ public static bool BuildDeployUpdateConfig() if (string.IsNullOrEmpty(buildPostString)) return false; + Console.Write(Environment.NewLine); Program.PrintColorMessage("Updating Build WebService... " + BuildVersion, ConsoleColor.Cyan); try @@ -1288,7 +1289,7 @@ public static bool BuildDeployUploadArtifacts() { foreach (string file in Build_Nightly_Files) { - var sourceFile = BuildOutputFolder + file; + string sourceFile = BuildOutputFolder + file; if (File.Exists(sourceFile)) { diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe b/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe index 6839186aff1f6bca89478e2f061897f032875207..2668397378ee2541908e88b7a57fe0adc67d7364 100644 GIT binary patch delta 1991 zcmY+_4@{J090&04a~|;CdvM%=9A}8fAOBqKG;I#k%+?SE5+PIsL5}|t3K+P?wE1dx zGEro**REWpR$94SNoU!nEiE?9x>BQMx|T6ZSJ`HfA)57j-}gs#w{g6m=l6S`?{oLQ z_q?0BvTrT#hLQIKjbP9}DZw!0YGBHIAtDA+AK9DS+y>jW# zgeaV?2e!TeXrn$Lx-^t-`ZG`5iMt;rKS)zsf! zMM{($QY%SrJ5ODf)*3o=NRlJQQ>zVLp~3b#I%=gbInm;o^Yb(7YYJH|yS|q*x5FO3xnMncR3l&bzbI`xtvtGSNxsa_D zgAf_c7#prFFm%;2V6ovgYj2!0CLYp4t=8+Bkh&}?9y9Vab-G-s(TK;~26B#>26P4SN^*ld8CYi2YSY%p zQ?Nx>5H)g#?7<k*^DqA$Fr=<8Ftbh*4GqKjMrG#%y!b-EUz5K z5*%ecEZa#ZSTmeqEX8RO<#$SRop$0mF2*H==|262m6Bv94YCya+Dh;fYkQ)d^gAmv zA&lj?&6<{ACzQMtlciE3R+r?kaoCpK|0j}}vjHdX~KrV<-i zCulJ~_*v&@F+Oy&e6*M<>|(XjVyf^GYb;%gY8+st(WR)yTZR-VizcnXdt97Plh#CR zNVP1#zCG3Agx;x2*HgZbYjKNpD()*1XpaR{>C3oFB#C97*dgj7=Bz`SUh_lg!3{b~ z(P``g^%1T0*v_q=VokF&yMU5y>AWg@}41_yK*OKXmprWt+QnTCnhW_cOxT--vdm1G++H}hYMY=um--}AmdtGkW6_w)RI@AG}Q z_r2%c6;O8t)cswStc5)?7XYwi;-G4xNhP zjG0+02d~iJHXj|e)X`gl&1q|)X;u1Ykb{l%Ham4|^b^=3hxEqjC2mTbDp&Bk@Re95 zQaHVCh*qC|arz$76e^oh;G~bfoOd4b59Z2Z5F*_bWy{9!~siW zt;d~`ToM(BSfdERHF$FOLvsb122xF0Szx!t(|**M0UX5WX$G0bw>1L^{_ z>D{II{-g>c$oM95;V~2h;!`cT*u(nU`M#Qm%VsBjN<5+F!&7PIjAWcr7vl(Ph*SX2 zdb5^AsmsyD8c%2yg{Z7D@-U!$t`=gEpKh857orethJx6pxMB(sU^(2~D8x-xw7nZE zu-yCKG)0(0w;5ePrB|IRijd9v#3A)G>j!%nMOe%lO^{kq<2O$nPLeF;;*N<@RV;n7 zR0HeDNm83xv4);!9W(S2tIjGrJ0G0qII9+6zbU%Y&Xcy+LgsfWHz|H4+UO@DbuURH zb+880!&rq^Si|WWDaiVsB8u@A>ldp=dXJT*hOrvQSx>1N=@jcxR~Tz>hD7zIFrV4V$lIuQ0i>by=)&*KjHTJNoX)#^|SS_>| zFJ5O&qDxVO!>lyA6g7C)lwZlFNo(;T7xQS++K3Iw$7(mWCm&83ow{;s%Gat7qpWkW z-;u^x-^Bh%0`0MYu2?;-qAp_2I=GEmJN)}FN_{UFH21^$h}L?vbL&?aQR{J#bplt_ z2K2Fh6}Qwz9Anumchn|)%<@>G?9WEb*^JX%+tq}4dow1|LjY*Upm5tapo3K+;_Vx8 z*pRujO%c;3Nb42H691VR?am}h9@@7ZdCY*I#K0r_+_u|?O!q0 z{qv>JfiXpBXZT?$|BWF!e&fV^i(3rn=kMhA%v0JO<0l>CV!YdOGv}nU)bgkJ2hC@j A*#H0l diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb b/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb index 02d1789c1c083cfb7d6882e3d78fd200a95d256d..ec965c50d763cfb581cb5e43300124e283420a28 100644 GIT binary patch delta 4162 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 L;n=k2s7d`F)aMya delta 4191 zcmZ{o3s4kC8pr1wSzQp4MIpRI1hTATO^_@J!pbf9I3)xPKF=r$iD*y}@f8iif{03# zGw>yjK~Wa*R8SE|d;}NS9Eg~*jFpGSV<3PQQQ`ML}2_tW=UviCFnX;Y#HDb8lO3qs<04q3B1j5OhOE5f}m%gArf} z7z37qQ^3vObZ{#;6a4P`Uy3qZ%mm9&{wnw;m<4VJ-vG-&EBF?;4Xkt%9xEzG@D2)g zfIE48`WpT*eVSD}LLG1^N|oPuT%!j#L!k=Ufe3elG2k9>3b+@X1?~g?0M>vRpbdNl ztOb{V`@v=40dOsN7_@@QG&ZT;TJ$D@22|_Ni)=Y4g&Om9s+@CpA zta!<@a^aKO6zowML(y_T7^jd894+cY$kzgp_WE0+1wDK0~u{ZXCwK-7J)Oi%5s$q5N) zcaM%4k>wW7?Dy9U57Y` zZ=%$yM6xd5hiEeEHyEI)8xGP&zPlkD8c<-SGM-rwOK)*GRN{_;9dwyz7KTID7n!Vi{Q}X8tn|#Dy%{-+hj5loBgHR4E^&ncw`px0c}d5V9^;T4}zV%GX3%!1|p=XxdH_-jvdv7Wy-H>@WAdYrG;#zM>MQoQcrT)KyCl8luyaprzAnK|@;!D~Cp ze!vxm@(Fx(e+dK6Vp?bsAhqK8)rjI)Nsyx+_On z8?IJ%9O$Gtx$I9^QQY_7Z7Pu0A8H`+b}R=@i06#@ky?*2t~a^Z6DQQc`k8q659^Hq z{;u*zdnE(UH2|HC<)nsun#1;naAOeE3Ks zUF11Oqv%5}JKErWJ65?F2_c-h8YkAV7s-RGj~Q{xu47hom)vNjD!Hq1u80S%KViXf zkOke%2cWgw2d!tlY@sI3f}Z6A&^GRaUS$2rSh~XL&};n8Ni%)USE0AqtJzHboD99o zrOmP8gLrOjexBU;E{XL6z zd^q}yk*0F`nej9WUipsdJ7b|NXI>a48=YD9DGa=@jPCTn7WSrAs z8S>5%_ZiLK_kuI1AhCZv2DY6YKL3 ziG%s7J%}f?>cpXD=U7&>>abA7twt==QD~$y;U7qdRue{?*I~t?&l|B~>Cj2egu3%O zajKf|ArfYBFRJFVSDO*brrcsin@-G86N=h&Si1^TZD2dJ#F^mc(23jBgwYNi7B9(R z#Ny>ZZAyZC(y>CszSXyfh@E=Z$rZzU+UL;-zS9xH{vDo(^c_>_IbPF|j}PZN9Y$#I z1wSh0=Pu-v%uN@J(4GsqI2%(tP4o#DcbaKB+dCWZah-iJ99n)cpAy);D~f*4aa|Ug z&Fi~N^gbU&NdWhBEyW;`FIjP~u1nk8GY#r1KaKNJhw_RKwvsI0{~(vBTh6}RGK5C4 z{!0Uml2gA7Cwi9idQ0%A@Aig61FoC!&7OL_gu3|ZbtClQbw8-@4P`$~g#Lxs+$f;$3+Xmr_PWbm(n88L4lM5XhvaTYo%T#N13C+8B&+zP;#QA9wnz0AM>8h zir`BK$Ke!HegjoF6^9#Aq77&?SxN;o8}Y4>BBdG7@#Wt_@|SE%&H~A<nl&2~8D_(@)j<6;iQM@w$pa6{RY+t6&vXDr_nasc2Mj zN`+lTyL2@YeQuZf6|j`_6tG)$wW_OEU6bn0s;*6S7gcvfb=Oq)x$17Iu3vR`RrkQ@ zL^reaT_gq4V5!1LK{z5*8>reamyJ|yw9AfBZKBIgQteciou%6OE}Ny=9G6|K+6^vS zqS|dPTdCSAm$f;q<}f~N21#kp;L#kHqMyOS^hl|I=EiRonr{*MI&*@R@1W_fSHtUn zUXf{%U1`5q@{U6L<@gBnkQ_?K>zpNIRk2x0R_Z%ZpChG4p*}_`MhT@z)e7cGXQK#z dB~JH6QHb0B{qKU)!(wQp8;v|YaSXL+{tbPO7+wGX From 9858e936dbafd740e0057a65a4e1b1057d865fd5 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 19 Jul 2018 12:23:52 +1000 Subject: [PATCH 1143/2058] BuildTools: disable changelog.txt --- tools/CustomBuildTool/Source Files/Build.cs | 2 +- .../bin/Release/CustomBuildTool.exe | Bin 165376 -> 165376 bytes .../bin/Release/CustomBuildTool.pdb | Bin 81408 -> 81408 bytes 3 files changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/CustomBuildTool/Source Files/Build.cs b/tools/CustomBuildTool/Source Files/Build.cs index 85e739b7d44d..a29b619ec2c4 100644 --- a/tools/CustomBuildTool/Source Files/Build.cs +++ b/tools/CustomBuildTool/Source Files/Build.cs @@ -332,7 +332,7 @@ public static bool CopyTextFiles() try { Win32.CopyIfNewer("README.txt", "bin\\README.txt"); - Win32.CopyIfNewer("CHANGELOG.txt", "bin\\CHANGELOG.txt"); + //Win32.CopyIfNewer("CHANGELOG.txt", "bin\\CHANGELOG.txt"); // TODO: Git log Win32.CopyIfNewer("COPYRIGHT.txt", "bin\\COPYRIGHT.txt"); Win32.CopyIfNewer("LICENSE.txt", "bin\\LICENSE.txt"); } diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe b/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe index 2668397378ee2541908e88b7a57fe0adc67d7364..ee3c1715077a5ed838d1a00f712f87ebca7d12f8 100644 GIT binary patch delta 6882 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 K>@B+M+W!L;atMt8 delta 6908 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 diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb b/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb index ec965c50d763cfb581cb5e43300124e283420a28..9933bc0f0a0c124f2971f2c3694bc48d33355ca8 100644 GIT binary patch delta 4312 zcmZ`-eN2zQNn$qy#i;| z-JN}_r*_@dMF)PBeW!fi4@*zYZBK8Z6MOZ@>vd~lUo3Vy; zK09y6E6jdF4k^%WD9*%ZVE2qVn46Q%YWa$N= z9!b^A=h7G#JWUA_+n+ zk{a|JPEU5x%iN!AGQ1poUvnPyQ}M(vKy#SyCEI8+C#JZ_!tE(0gC*p?@(fhcWX;=C zd>fkWT##xuZ2y_23iaoZeu=fQo7+>Z2*Y@)iv-TI7tyEuvAqy;vtYIfSTH+S{4SLD z&CVe!Uzy!Z8+mVLbY59NpQoE(Y1Rx)##5aRJQzY@tqS@6qw9*9SEp1Np<^UR3B&Ab4ycDe6? z_0zo;;zUsQxLhDo6faxvPYad2^>(6#+_0e%OWXMD6ySnq3%%Ox6VfXp1@lMG`Wt>M zQ4fgoa55F1rh-rKy=Tkl0+(*wOrP;Tf#bYtQ#SnM<%jW^P2t{JOA=x@a&N$a`~>d{ zZs#OS;->rnUY;+ZVP3us4d2Lrl{T~SIR|ay4bR!BgqxnTQ8`}(Rcz&l0qutQs550S&}U}XS-Kf?hXl(tvk$+GyscWhw(L(?ocg7 zas?92W8+Q}(7E$1D&>Fgi~<@;?X-timD=c4t^pq4k<#DN8D6z33RtqsPJiRhT{ilJ zZvro|vFx{)oX)Z+;KedKg>q22on~-mc_lnwEMEhkw=2SUc|{}I->>0OjZ_FO%1Q zeq5?}q!6CJCs6#4otHLF=7iTo6NBc;_O4J(OoQLvt zZ*KIqxaXgQV2W{cl>+%1Z6cPNIq1={i`Tv#BGx7IE_nvmzwL`1{O7li(_eY@ zQ477#)koXBuiMnlNSMNTFXF^HwuJQDaLkM@M~{`kUB>Y;s#8XfuMsiP#uE-42OCZ} zc>0OSeDXvruLs`&w}6wBSiS~+2|QgvJ$OC%juMM5jU6^R%j-I9JiSBWmX2t;$YULL zehs%pS1Hgos)Uj$yf^FqbD5{!8cFZ zX*$p9vQso~09v^TXy;2^4w}nN-GLn6ZKlP%u6rJ3BCoz{$GaWe*d4?vJ!ZZJE&)&P z3F02`dhlIv3pnL3X4=Oa{$j^_y9rpwmw@$b=#4@Y(t6E^!fjhg;0K{ zSK>{*;b0wK?)Bx@V0-mRJOobYlf({9mW!g0zHrX%)A8^6e0e_X?mh{TQT<(m@b8*X z>X-NoDy4oM&*}H&Z(wigmk=gZ_*%at-qM6a5El1`^ALo$AZ&phG9d9e@caQue8BD= z-xd_j90=zv13GRT@Z~JnX9gsMaI8O!zkx7X6HXnJ_yQ`Y4(fRMpfBqN!?}1+LQGX* z%b+AK)`aIEtU~3vLEV8NU+#c8b4a3Gw=Qc)5;tkO@*#BUgj1#9|0@t5jOJRI_ zWD19j_`))dETcHyKH|cy?DmKm81Zf}?c~IFU384w-!%g-y<3QL*7=^5&T++ic3R5) z@3rCPmVYJ+SaZfj$?QF9p>$3eb&+G3D<2g+%9-{1193lZlO&O=MD>m!pVcc`Bnhig5}4w~jY^H(0e% znB1Ew|6@(zSZqnB=NPy;S;w>K62&^I4G72Kzb9V z=Oy`ys!?akz0-4zidFz4c2SAY1J{OO0|UhtITO=vVvc7pV! zxIH}~XPV&n%ugl-$W5vyNA6cO5)SxJ+pj4 zM62H{SEv=+G%C@kT%$^j_G?t9QN2dZ8XeK7U88P|2Ia9?@L4I}RB6AQ{s@J2{m(4= z-a~#WmLzJE<6}{AL3V=lpW*W3DQCuF+~Y8V+-8J&C0aQV5iH=Jerjx-a=+UCY1!X` z_W8IE`pCm*Petw$+M!W}oT1jALVbbkw4mN1SD=Iz$_*-I%RLq{)26O*3r*4e*Z(QH R!V_qwj%Ic(NTy!>{{uK~RG9z( delta 4381 zcmZ`-dsI}_8b9B0M!`T2Z$>}_97i4H(EtOEIwDwMp`xNGT2g9~5fG*5h=4ET8aMST zkG8--#=3@PctAx!n64<~)g?E3c-P_!$bq&Ky(!xwF>({l2sJZ-0BA zZ$Hl7Q}(;A?04PAx}m`Xw`XUQAPAE#{!;YG%dV9DSMNQ)x$T2ZO6brD9{xUsM_;ck z+Lzlox~0zKOg8Dn@&6H( zS4=uRWpm*KOIS8ki@XIvZ75I}e7hd*rM@?b$2HAE2nP<<2MjkeN< zoDgHBZ#fUx#|L8^bdMuq&A^PgxjJ_>LADm0CJH_1v7oRI9Gsoa=sGE5DAsO*MH^3}Y(#J8Z? z!g-U-hAoe1wxj$K(sP&_ySZ_a1z{MNU%q0u0KKPeraioCnuV&lYuZBU z;II@6MRI0}m14OvC6!k3g_I`|?ttkQ3gUF&NG_RfM+5EC9VBydYQD#zNbSvJ63L&> zq|T=%#gNvZE8U4eXtSFHb*8I7%m87F+Y*FXB$Q!h3bVl@!E?Y9!I|L6;JM(b;CWy> zI14-vya2oqya>Dqycp~wqzOL4%=_sH!CM%{*7Pt>ZRL>A#wm;ZxFG!u6(|Wa?L@`O z8&BUL1aE0ZJtj8Ik}+xb&DueIigETlkuEFiG9l~YmbtB-GXm6CB%z#LbNzVdyjo0} zxcQ}+Dax_=-x4Onz6C#cYC}xI6WsfeAJ;BiPFocHvlhabB`^9KV`f;4Ri(^W%!IMI zlKs3$zDn|Qse=&6k{qk27Dy5vU&NSww$jJ&M~=G1T!xcT@H7hS;=3zL=?0g) zw3=@6_rTknwQ3>!t43fTYLq$hkaJtsD?9E+Y#j|U;|$O9%JuUY#uGi_d8stCqKTi z+M5er3C8wNiL!Hll=%!s+1IZa=_2d%!VMSi=c}*eKS&UokjCScvUy5gEBcZ7Y6$zk zDxoi`H4WBwSZ4G`ecp@bJ#Om^tQxoVBP=IVz8QT}HBaSB=$~r64y(m&)xzrJMrh8t zpMS&iMa8oq1oMTBuSEgVU$fG6E`P0*0-1_ThQI{v<9kU*S|gLk608YS7UYN_6v|H(&!rkQ%Y}^(FOy72t4)dLD;fBNJhcWd)NaiD@Au=HxS5Zpmxv?S&_<6-V^mE*H z2c_}B?fKZt0xF|`$(0rG=Blix!^(<3y*Px~w*<_Si(x%A&lU!ns7Y02}3_l)*WBW3Uc)?QNi3Wy(GiiQ!iM^ymns>|H0( zPBvDXfEm^AQ7_+w-OB+r7P`afHR{Kqt7aZb4f|7(zjXggo>Sf9PeKq!wD~Lj$fs^L z)|!ABwH25#pVyXBDreQjh^cY>XXi}5ROdx6abKNH%#Y*!^<#M20WS=B#(~Xb;NAmP zV3qS}@83j0_zlY>9g&*CIrTPt5F-wnyx&CLk4V_Yg<0HNzZu`~-UGq%NG}@34yO+u ztDFn5Dst*$yf5Q)QjF6_F~kb0Tc{0HUiAD4&z(r!>^gXkQkBa05mB`J!4FiStous? zi9cI;MA{@?_Tg9$|D^jfx!emo)CV7CVcy*R&}@jjpZ~{NS%z^n!08j5(%_&MxxFC@ z*xwL@E~PYN^Ag#EmmCfjok_e=9>dj#y|9809X?8b=S4?i=pS5pq`~uNtJ)X|;hgij zAJ6&d8GNK_J~E@po{vi5F8ydJIhCHH*&;iS`Eug1Xub|!10JpT@^SET@GoE|I8i}4 zc#RTGf8~RUoj&CO#m;XxNgUramag#9CM)&xJ54tFj(eMIyro&<(B=vBE2lTx=)b(R z*(wgU@#*G7ahQ#NX`Vy@9CzGCVVrl|PNVtAaXT+R;mh}qk0%R{J7FUmuK-TxI^az1 zJ7MSAlc;mj%-6xqCx>&{$x%GIB|wh$qoLe!(#XqO0{9LDPH=Jygy41H(We5qrNxXd z)uK4lnuv#I-ryLfDLSDjpDakL;2ZOi95ktS|#z|B;NSy2>uvZ z!EK>n9e>m6#c8lT+9WOj$AhcE%fQ`k*743ZFTM@?WSfKtxmvLewMk;X=1gjrxVSx( zrFI=pYxiO&>{aa&0;USzZkNRWYQjzk$DR)5P6&U5a6atd(-N0~(@slbn9bd}0%U!K ztb)@zu08F=x{grpJ}n`b<)=gVHiR}!II2V9?I;}8q2oCnUfcw`xI>~$x6s)kiHkJh zB?yx`L-|sNZg-~_FNZm{Q=)vgZhogEuGMs9of3bC!m>^se+;3&E0n*2u*xmexg_x& zO&IHvcrOZLT{>RoQm1X6Oa1VmgG!UDK*U~PJQFVV8t?Ch@mzgo361AlUEv(uGtOD)Yc4-$qov$_t^sGj-0mn~ zRkwqlWY3-$n#0LGcFN&(Jr?>KA3;tO_w}qsC(=JHMO!_e?tuTS^YzrO+&Q05bWO>< z(CSNxZ2ZPViAu&dQACruuzxc)=%4$efQG9U949lbZl=$;_o^9q_i7L@;F`KFX8^DA z8`n1DVsYo12^eub2pvei{)5;Zuk8~968skq)O#MbXbafnUcj;6J_9!;-+qQlnK!anj)GYfDN@Q^2}x#~S=o7<#&a&IJs=+(Q-EKR3g zR+2Td59Y6$?y{T`1)X}mDANknvtYSqo`v~@W~!Hk^;#?Ho#3RFtDXq&3)Hjy4$bFq zIbt+?em_DG0^GX6_h1%_a&#mG4qg+6`<-T!ue?iD%GjEHHIM2U@iDDZ6U?wd?n=}v zlaWGbyc`D7uQuWEEJqkAXmC5sF(gklQXpNE3sunuxk{zO@*!1w9#^+@@-Ap8P3~87 zR>k73VpdP_EH-jo#8|k47~b zIW=m~=$J+=8g*)PPNR!*?>GuMF?u}xK1lv;97%F)H0fmB1PazGI5ZEDGo#V9Q*vB1 zn!X`tfb=&X6zFfm3~+10)Kigq&ryGv#}9sLh?dChYW+glCkFM4p&Tl^RL7g#IaI09 zPB~pI??ri@oDqZasd71TC`+zUX{Fo}LuOigVjzaXb^rIzjuWBrG*(CPCuSs3tNwoz CMQZH; From 00e6dba07caefe50bb8eb378bfa1a16af6855b8e Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 19 Jul 2018 13:02:12 +1000 Subject: [PATCH 1144/2058] Add menu patch --- ProcessHacker/mainwnd.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index 6b5f95184a34..258b8e12cdda 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -158,8 +158,22 @@ BOOLEAN PhMainWndInitialization( if (!PhMainWndHandle) return FALSE; - PhMainWndMenuHandle = GetMenu(PhMainWndHandle); - PhMwpInitializeMainMenu(PhMainWndMenuHandle); + { + PhMainWndMenuHandle = LoadMenu(PhInstanceHandle, MAKEINTRESOURCE(IDR_MAINWND)); + SetMenu(PhMainWndHandle, PhMainWndMenuHandle); + PhMwpInitializeMainMenu(PhMainWndMenuHandle); + + // TODO: plugin suppport -dmex + //PPH_EMENU menu; + // + //menu = PhCreateEMenu(); + //PhLoadResourceEMenuItem(menu, PhInstanceHandle, MAKEINTRESOURCE(IDR_MAINWND), ULONG_MAX); + // + //PhMainWndMenuHandle = CreateMenu(); + //PhEMenuToHMenu2(PhMainWndMenuHandle, menu, 0, NULL); + //SetMenu(PhMainWndHandle, PhMainWndMenuHandle); + //PhMwpInitializeMainMenu(PhMainWndMenuHandle); + } // Choose a more appropriate rectangle for the window. PhAdjustRectangleToWorkingArea(PhMainWndHandle, &windowRectangle); @@ -330,14 +344,10 @@ RTL_ATOM PhMwpInitializeWindowClass( memset(&wcex, 0, sizeof(WNDCLASSEX)); wcex.cbSize = sizeof(WNDCLASSEX); - wcex.style = 0; wcex.lpfnWndProc = PhMwpWndProc; - wcex.cbClsExtra = 0; - wcex.cbWndExtra = 0; wcex.hInstance = PhInstanceHandle; className = PhaGetStringSetting(L"MainWindowClassName"); wcex.lpszClassName = PhGetStringOrDefault(className, L"MainWindowClassName"); - wcex.lpszMenuName = MAKEINTRESOURCE(IDR_MAINWND); wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hIcon = PH_LOAD_SHARED_ICON_LARGE(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER)); wcex.hIconSm = PH_LOAD_SHARED_ICON_SMALL(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER)); From 30e4061540120c62d65177bf2908b7c06343c4ea Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 19 Jul 2018 13:53:49 +1000 Subject: [PATCH 1145/2058] Enable menu menu auto dismiss after 10 seconds --- ProcessHacker/mainwnd.c | 54 +++++++++++++++++++++++------------------ 1 file changed, 31 insertions(+), 23 deletions(-) diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index 258b8e12cdda..43d08fe691b2 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -99,7 +99,7 @@ BOOLEAN PhMainWndInitialization( ) { RTL_ATOM windowAtom; - PH_STRING_BUILDER stringBuilder; + PPH_STRING windowName; PH_RECTANGLE windowRectangle; // Set FirstRun default settings. @@ -116,13 +116,14 @@ BOOLEAN PhMainWndInitialization( windowRectangle.Size = PhGetScalableIntegerPairSetting(L"MainWindowSize", TRUE).Pair; // Create the window title. - - PhInitializeStringBuilder(&stringBuilder, 100); + windowName = NULL; if (PhGetIntegerSetting(L"EnableWindowText")) { + PH_STRING_BUILDER stringBuilder; PPH_STRING currentUserName; + PhInitializeStringBuilder(&stringBuilder, 100); PhAppendStringBuilder2(&stringBuilder, L"Process Hacker"); if (currentUserName = PhGetSidFullName(PhGetOwnTokenAttributes().TokenSid, TRUE, NULL)) @@ -136,13 +137,15 @@ BOOLEAN PhMainWndInitialization( if (PhGetOwnTokenAttributes().ElevationType == TokenElevationTypeFull) PhAppendStringBuilder2(&stringBuilder, L" (Administrator)"); + + windowName = PhFinalStringBuilderString(&stringBuilder); } // Create the window. PhMainWndHandle = CreateWindow( MAKEINTATOM(windowAtom), - stringBuilder.String->Buffer, + PhGetString(windowName), WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN, windowRectangle.Left, windowRectangle.Top, @@ -153,29 +156,34 @@ BOOLEAN PhMainWndInitialization( PhInstanceHandle, NULL ); - PhDeleteStringBuilder(&stringBuilder); + PhClearReference(&windowName); if (!PhMainWndHandle) return FALSE; + if (PhGetIntegerSetting(L"EnableWindowText")) // HACK { - PhMainWndMenuHandle = LoadMenu(PhInstanceHandle, MAKEINTRESOURCE(IDR_MAINWND)); - SetMenu(PhMainWndHandle, PhMainWndMenuHandle); - PhMwpInitializeMainMenu(PhMainWndMenuHandle); - - // TODO: plugin suppport -dmex - //PPH_EMENU menu; - // - //menu = PhCreateEMenu(); - //PhLoadResourceEMenuItem(menu, PhInstanceHandle, MAKEINTRESOURCE(IDR_MAINWND), ULONG_MAX); - // - //PhMainWndMenuHandle = CreateMenu(); - //PhEMenuToHMenu2(PhMainWndMenuHandle, menu, 0, NULL); - //SetMenu(PhMainWndHandle, PhMainWndMenuHandle); - //PhMwpInitializeMainMenu(PhMainWndMenuHandle); + SendMessage(PhMainWndHandle, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER))); + SendMessage(PhMainWndHandle, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER))); } + // TODO: plugin suppport -dmex + //PPH_EMENU menu; + //menu = PhCreateEMenu(); + //PhLoadResourceEMenuItem(menu, PhInstanceHandle, MAKEINTRESOURCE(IDR_MAINWND), ULONG_MAX); + //PhMainWndMenuHandle = CreateMenu(); + //PhEMenuToHMenu2(PhMainWndMenuHandle, menu, 0, NULL); + //SetMenu(PhMainWndHandle, PhMainWndMenuHandle); + //PhMwpInitializeMainMenu(PhMainWndMenuHandle); + + // Load the main menu + + PhMainWndMenuHandle = LoadMenu(PhInstanceHandle, MAKEINTRESOURCE(IDR_MAINWND)); + SetMenu(PhMainWndHandle, PhMainWndMenuHandle); + PhMwpInitializeMainMenu(PhMainWndMenuHandle); + // Choose a more appropriate rectangle for the window. + PhAdjustRectangleToWorkingArea(PhMainWndHandle, &windowRectangle); MoveWindow( PhMainWndHandle, @@ -349,8 +357,6 @@ RTL_ATOM PhMwpInitializeWindowClass( className = PhaGetStringSetting(L"MainWindowClassName"); wcex.lpszClassName = PhGetStringOrDefault(className, L"MainWindowClassName"); wcex.hCursor = LoadCursor(NULL, IDC_ARROW); - wcex.hIcon = PH_LOAD_SHARED_ICON_LARGE(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER)); - wcex.hIconSm = PH_LOAD_SHARED_ICON_SMALL(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER)); return RegisterClassEx(&wcex); } @@ -2310,12 +2316,14 @@ VOID PhMwpInitializeMainMenu( MENUINFO menuInfo; ULONG i; + memset(&menuInfo, 0, sizeof(MENUINFO)); menuInfo.cbSize = sizeof(MENUINFO); menuInfo.fMask = MIM_STYLE; - menuInfo.dwStyle = MNS_NOTIFYBYPOS; + menuInfo.dwStyle = MNS_NOTIFYBYPOS | MNS_AUTODISMISS; + SetMenuInfo(Menu, &menuInfo); - for (i = 0; i < sizeof(SubMenuHandles) / sizeof(HMENU); i++) + for (i = 0; i < RTL_NUMBER_OF(SubMenuHandles); i++) { SubMenuHandles[i] = GetSubMenu(PhMainWndMenuHandle, i); } From 8be2c5fde2a1b1b249108067826330680720363e Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 19 Jul 2018 14:12:34 +1000 Subject: [PATCH 1146/2058] SetupTool: Fix duplicate uninstaller --- tools/CustomSetupTool/CustomSetupTool/setup.c | 40 +++++++++++-------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/tools/CustomSetupTool/CustomSetupTool/setup.c b/tools/CustomSetupTool/CustomSetupTool/setup.c index 5d49b5b73d1e..6549d0890fc2 100644 --- a/tools/CustomSetupTool/CustomSetupTool/setup.c +++ b/tools/CustomSetupTool/CustomSetupTool/setup.c @@ -177,33 +177,41 @@ BOOLEAN SetupCreateUninstallFile( uninstallFilePath = PhConcatStrings2(PhGetString(SetupInstallPath), L"\\processhacker-setup.exe"); if (RtlDoesFileExists_U(backupFilePath->Buffer)) - { - if (!NT_SUCCESS(PhDeleteFileWin32(backupFilePath->Buffer))) - { - PPH_STRING tempFileName; - PPH_STRING tempFilePath; - - tempFileName = PhCreateString(L"processhacker-setup.bak"); - tempFilePath = PhCreateCacheFile(tempFileName); + { + PPH_STRING tempFileName; + PPH_STRING tempFilePath; - if (!MoveFile(backupFilePath->Buffer, tempFilePath->Buffer)) - { - Context->ErrorCode = GetLastError(); - return FALSE; - } + tempFileName = PhCreateString(L"processhacker-setup.bak"); + tempFilePath = PhCreateCacheFile(tempFileName); - PhDereferenceObject(tempFilePath); - PhDereferenceObject(tempFileName); + //if (!NT_SUCCESS(PhDeleteFileWin32(backupFilePath->Buffer))) + if (!MoveFile(backupFilePath->Buffer, tempFilePath->Buffer)) + { + Context->ErrorCode = GetLastError(); + return FALSE; } + + PhDereferenceObject(tempFilePath); + PhDereferenceObject(tempFileName); } if (RtlDoesFileExists_U(uninstallFilePath->Buffer)) { - if (!MoveFile(uninstallFilePath->Buffer, backupFilePath->Buffer)) + PPH_STRING tempFileName; + PPH_STRING tempFilePath; + + //if (!NT_SUCCESS(PhDeleteFileWin32(uninstallFilePath->Buffer))) + tempFileName = PhCreateString(L"processhacker-setup.exe"); + tempFilePath = PhCreateCacheFile(tempFileName); + + if (!MoveFile(uninstallFilePath->Buffer, tempFilePath->Buffer)) { Context->ErrorCode = GetLastError(); return FALSE; } + + PhDereferenceObject(tempFilePath); + PhDereferenceObject(tempFileName); } if (!CopyFile(currentFilePath->Buffer, uninstallFilePath->Buffer, TRUE)) From 73e08a934e99ade890e415a04d94675fb7e85b50 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 19 Jul 2018 14:43:33 +1000 Subject: [PATCH 1147/2058] Updater: Fix elevation check for portable releases --- plugins/Updater/page5.c | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/plugins/Updater/page5.c b/plugins/Updater/page5.c index f662a465cf61..728bc94936ba 100644 --- a/plugins/Updater/page5.c +++ b/plugins/Updater/page5.c @@ -29,6 +29,34 @@ static TASKDIALOG_BUTTON TaskDialogButtonArray[] = { IDYES, L"Install" } }; +BOOLEAN UpdaterCheckApplicationDirectory( + VOID + ) +{ + HANDLE fileHandle; + PPH_STRING directory; + PPH_STRING file; + + directory = PH_AUTO(PhGetApplicationDirectory()); + file = PH_AUTO(PhConcatStrings(2, PhGetStringOrEmpty(directory), L"\\processhacker.update")); + + if (NT_SUCCESS(PhCreateFileWin32( + &fileHandle, + PhGetString(file), + FILE_GENERIC_WRITE | DELETE, + FILE_ATTRIBUTE_NORMAL, + FILE_SHARE_READ | FILE_SHARE_DELETE, + FILE_OPEN_IF, + FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_DELETE_ON_CLOSE + ))) + { + NtClose(fileHandle); + return TRUE; + } + + return FALSE; +} + HRESULT CALLBACK FinalTaskDialogCallbackProc( _In_ HWND hwndDlg, _In_ UINT uMsg, @@ -43,7 +71,7 @@ HRESULT CALLBACK FinalTaskDialogCallbackProc( { case TDN_NAVIGATED: { - if (!PhGetOwnTokenAttributes().Elevated) + if (!UpdaterCheckApplicationDirectory()) { SendMessage(hwndDlg, TDM_SET_BUTTON_ELEVATION_REQUIRED_STATE, IDYES, TRUE); } @@ -72,7 +100,7 @@ HRESULT CALLBACK FinalTaskDialogCallbackProc( info.lpFile = PhGetStringOrEmpty(context->SetupFilePath); info.lpParameters = PhGetString(parameters); - info.lpVerb = PhGetOwnTokenAttributes().Elevated ? NULL : L"runas"; + info.lpVerb = UpdaterCheckApplicationDirectory() ? NULL : L"runas"; info.nShow = SW_SHOW; info.hwnd = hwndDlg; info.fMask = SEE_MASK_NOASYNC | SEE_MASK_FLAG_NO_UI; From 16646c1f87224ae472056e13bbfe3ed9c66d4576 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 19 Jul 2018 14:53:17 +1000 Subject: [PATCH 1148/2058] Add flag --- ProcessHacker/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ProcessHacker/main.c b/ProcessHacker/main.c index aefc7a76445e..b1328fb999b9 100644 --- a/ProcessHacker/main.c +++ b/ProcessHacker/main.c @@ -954,7 +954,7 @@ VOID PhpInitializeSettings( &fileHandle, PhSettingsFileName->Buffer, FILE_GENERIC_WRITE, - 0, + FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_DELETE, FILE_OVERWRITE, FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT From 219045097193df59841a5df0d1bdc824314944d5 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 19 Jul 2018 16:03:40 +1000 Subject: [PATCH 1149/2058] SetupTool: Fix elevation check for portable releases --- .../CustomSetupTool/CustomSetupTool.vcxproj | 2 -- .../CustomSetupTool/resources/app.manifest | 2 +- .../CustomSetupTool/startpage.c | 33 +++++++++++++++++-- 3 files changed, 32 insertions(+), 5 deletions(-) diff --git a/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj b/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj index 9d38d024a4c5..b1db7a0f7826 100644 --- a/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj +++ b/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj @@ -68,7 +68,6 @@ uxtheme.lib;winhttp.lib;phlib.lib;ntdll.lib;userenv.lib;%(AdditionalDependencies) $(SolutionDir)..\..\phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) Windows - RequireAdministrator 6.01 %(DelayLoadDLLs) @@ -103,7 +102,6 @@ Windows 6.01 true - RequireAdministrator %(DelayLoadDLLs) diff --git a/tools/CustomSetupTool/CustomSetupTool/resources/app.manifest b/tools/CustomSetupTool/CustomSetupTool/resources/app.manifest index 29e66e8a95a7..42ab6aaaa71e 100644 --- a/tools/CustomSetupTool/CustomSetupTool/resources/app.manifest +++ b/tools/CustomSetupTool/CustomSetupTool/resources/app.manifest @@ -10,7 +10,7 @@ - + diff --git a/tools/CustomSetupTool/CustomSetupTool/startpage.c b/tools/CustomSetupTool/CustomSetupTool/startpage.c index a17ec722412f..b767b75a384d 100644 --- a/tools/CustomSetupTool/CustomSetupTool/startpage.c +++ b/tools/CustomSetupTool/CustomSetupTool/startpage.c @@ -2,8 +2,6 @@ * Process Hacker Toolchain - * project setup * - * Copyright (C) 2017 dmex - * * This file is part of Process Hacker. * * Process Hacker is free software; you can redistribute it and/or modify @@ -21,6 +19,8 @@ */ #include +#include +#include VOID SetupPropSheetCenterWindow( _In_ PPH_SETUP_CONTEXT Context @@ -106,6 +106,30 @@ INT_PTR CALLBACK SetupPropPage1_WndProc( switch (pageNotify->hdr.code) { + case PSN_WIZNEXT: + { + if (!PhGetOwnTokenAttributes().Elevated) + { + SHELLEXECUTEINFO info = { sizeof(SHELLEXECUTEINFO) }; + info.lpFile = NtCurrentPeb()->ProcessParameters->ImagePathName.Buffer; + info.lpParameters = NtCurrentPeb()->ProcessParameters->CommandLine.Buffer; + info.lpVerb = L"runas"; + info.nShow = SW_SHOW; + info.hwnd = hwndDlg; + info.fMask = SEE_MASK_NOASYNC | SEE_MASK_FLAG_NO_UI; + + if (ShellExecuteEx(&info)) + { + NtTerminateProcess(NtCurrentProcess(), STATUS_SUCCESS); + } + else + { + SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, (LPARAM)TRUE); + return TRUE; + } + } + } + break; case PSN_SETACTIVE: { //#ifdef _DEBUG @@ -113,6 +137,11 @@ INT_PTR CALLBACK SetupPropPage1_WndProc( //#endif // Reset the button state. PropSheet_SetWizButtons(context->DialogHandle, PSWIZB_NEXT); + + if (!PhGetOwnTokenAttributes().Elevated) + { + Button_SetElevationRequiredState(GetDlgItem(context->DialogHandle, IDC_PROPSHEET_NEXT), TRUE); + } } break; case PSN_KILLACTIVE: From 2f895cf139106737a5c0653bbbf1235f6d16d0d9 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 19 Jul 2018 18:51:38 +1000 Subject: [PATCH 1150/2058] Fix debug console symbol path regression --- ProcessHacker/dbgcon.c | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/ProcessHacker/dbgcon.c b/ProcessHacker/dbgcon.c index 0737c465fed2..684e336645bc 100644 --- a/ProcessHacker/dbgcon.c +++ b/ProcessHacker/dbgcon.c @@ -30,6 +30,7 @@ #include #include +#include #include #include #include @@ -671,6 +672,45 @@ NTSTATUS PhpDebugConsoleThreadStart( DebugConsoleSymbolProvider = PhCreateSymbolProvider(NtCurrentProcessId()); PhLoadSymbolProviderOptions(DebugConsoleSymbolProvider); + + { + static UNICODE_STRING variableNameUs = RTL_CONSTANT_STRING(L"_NT_SYMBOL_PATH"); + UNICODE_STRING variableValueUs; + PPH_STRING newSearchPath; + WCHAR buffer[MAX_PATH]; + + RtlInitEmptyUnicodeString(&variableValueUs, buffer, sizeof(buffer)); + + if (NT_SUCCESS(RtlQueryEnvironmentVariable_U(NULL, &variableNameUs, &variableValueUs))) + { + PPH_STRING currentDirectory = PhGetApplicationDirectory(); + PPH_STRING currentSearchPath = PhGetStringSetting(L"DbgHelpSearchPath"); + + if (currentSearchPath->Length != 0) + { + newSearchPath = PhFormatString( + L"%s;%s;%s", + buffer, + PhGetStringOrEmpty(currentSearchPath), + PhGetStringOrEmpty(currentDirectory) + ); + } + else + { + newSearchPath = PhFormatString( + L"%s;%s", + buffer, + PhGetStringOrEmpty(currentDirectory) + ); + } + + PhSetSearchPathSymbolProvider(DebugConsoleSymbolProvider, PhGetString(newSearchPath)); + + PhDereferenceObject(newSearchPath); + PhDereferenceObject(currentDirectory); + } + } + PhEnumGenericModules( NtCurrentProcessId(), NtCurrentProcess(), From 10e3021b652342bba0dd13c9d34df5931bba5ac9 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 19 Jul 2018 19:16:33 +1000 Subject: [PATCH 1151/2058] SetupTool: Fix updating service from portable releases --- .../CustomSetupTool/include/setup.h | 3 +-- tools/CustomSetupTool/CustomSetupTool/setup.c | 24 ++++++++++++++----- .../CustomSetupTool/CustomSetupTool/update.c | 6 ++--- 3 files changed, 21 insertions(+), 12 deletions(-) diff --git a/tools/CustomSetupTool/CustomSetupTool/include/setup.h b/tools/CustomSetupTool/CustomSetupTool/include/setup.h index 12b68b88549c..98dec8c03455 100644 --- a/tools/CustomSetupTool/CustomSetupTool/include/setup.h +++ b/tools/CustomSetupTool/CustomSetupTool/include/setup.h @@ -76,8 +76,6 @@ typedef enum _SETUP_COMMAND_TYPE typedef struct _PH_SETUP_CONTEXT { - SETUP_COMMAND_TYPE SetupMode; - HWND DialogHandle; HWND PropSheetBackHandle; HWND PropSheetForwardHandle; @@ -147,6 +145,7 @@ typedef struct _PH_SETUP_CONTEXT WNDPROC TaskDialogWndProc; } PH_SETUP_CONTEXT, *PPH_SETUP_CONTEXT; +extern SETUP_COMMAND_TYPE SetupMode; extern PPH_STRING SetupInstallPath; VOID SetupLoadImage( diff --git a/tools/CustomSetupTool/CustomSetupTool/setup.c b/tools/CustomSetupTool/CustomSetupTool/setup.c index 6549d0890fc2..e8019f80eb17 100644 --- a/tools/CustomSetupTool/CustomSetupTool/setup.c +++ b/tools/CustomSetupTool/CustomSetupTool/setup.c @@ -318,7 +318,8 @@ VOID SetupStartService( } VOID SetupStopService( - _In_ PWSTR ServiceName + _In_ PWSTR ServiceName, + _In_ BOOLEAN RemoveService ) { SC_HANDLE serviceHandle; @@ -374,8 +375,11 @@ VOID SetupStopService( } while (--attempts != 0); } } - - DeleteService(serviceHandle); + + if (RemoveService) + { + DeleteService(serviceHandle); + } CloseServiceHandle(serviceHandle); } @@ -427,7 +431,7 @@ VOID SetupStartKph( if (PhShellExecuteEx( NULL, PhGetString(clientPath), - L"-installkph", + L"-installkph -s", SW_NORMAL, 0, 0, @@ -453,8 +457,16 @@ BOOLEAN SetupUninstallKph( Context->SetupKphInstallRequired = SetupKphCheckInstallState(); // Stop and uninstall the current installation. - SetupStopService(L"KProcessHacker2"); - SetupStopService(L"KProcessHacker3"); + if (SetupMode == SETUP_COMMAND_UPDATE) + { + SetupStopService(L"KProcessHacker2", TRUE); + SetupStopService(L"KProcessHacker3", FALSE); + } + else + { + SetupStopService(L"KProcessHacker2", TRUE); + SetupStopService(L"KProcessHacker3", TRUE); + } return TRUE; } diff --git a/tools/CustomSetupTool/CustomSetupTool/update.c b/tools/CustomSetupTool/CustomSetupTool/update.c index ccbbff4cb2a3..2abe20862db3 100644 --- a/tools/CustomSetupTool/CustomSetupTool/update.c +++ b/tools/CustomSetupTool/CustomSetupTool/update.c @@ -65,7 +65,7 @@ NTSTATUS SetupUpdateBuild( } PPH_SETUP_CONTEXT CreateUpdateContext( - _In_ SETUP_COMMAND_TYPE SetupMode + VOID ) { PPH_SETUP_CONTEXT context; @@ -73,8 +73,6 @@ PPH_SETUP_CONTEXT CreateUpdateContext( context = (PPH_SETUP_CONTEXT)PhCreateAlloc(sizeof(PH_SETUP_CONTEXT)); memset(context, 0, sizeof(PH_SETUP_CONTEXT)); - context->SetupMode = SetupMode; - return context; } @@ -239,7 +237,7 @@ VOID SetupShowUpdatingDialog( config.lpCallbackData = (LONG_PTR)Context; config.pszWindowTitle = PhApplicationName; - if (Context->SetupMode = SETUP_COMMAND_SILENTINSTALL) + if (SetupMode = SETUP_COMMAND_SILENTINSTALL) { config.pszMainInstruction = PhaFormatString( L"Installing Process Hacker %lu.%lu.%lu...", From e6108394a0dd5aafb666fc576fa573e993e53521 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 19 Jul 2018 19:40:16 +1000 Subject: [PATCH 1152/2058] Add missing file from previous commit --- tools/CustomSetupTool/CustomSetupTool/include/setup.h | 2 +- tools/CustomSetupTool/CustomSetupTool/main.c | 2 +- tools/CustomSetupTool/CustomSetupTool/update.c | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tools/CustomSetupTool/CustomSetupTool/include/setup.h b/tools/CustomSetupTool/CustomSetupTool/include/setup.h index 98dec8c03455..e27cda0b9918 100644 --- a/tools/CustomSetupTool/CustomSetupTool/include/setup.h +++ b/tools/CustomSetupTool/CustomSetupTool/include/setup.h @@ -276,7 +276,7 @@ BOOLEAN SetupExtractBuild( // update.c VOID SetupShowUpdateDialog( - _In_ SETUP_COMMAND_TYPE SetupMode + VOID ); // updatesetup.c diff --git a/tools/CustomSetupTool/CustomSetupTool/main.c b/tools/CustomSetupTool/CustomSetupTool/main.c index 85fb5737db2e..3f50629ce0a3 100644 --- a/tools/CustomSetupTool/CustomSetupTool/main.c +++ b/tools/CustomSetupTool/CustomSetupTool/main.c @@ -313,7 +313,7 @@ INT WINAPI wWinMain( break; case SETUP_COMMAND_UPDATE: case SETUP_COMMAND_SILENTINSTALL: - SetupShowUpdateDialog(SetupMode); + SetupShowUpdateDialog(); break; case SETUP_COMMAND_REPAIR: break; diff --git a/tools/CustomSetupTool/CustomSetupTool/update.c b/tools/CustomSetupTool/CustomSetupTool/update.c index 2abe20862db3..4c55e5d505f1 100644 --- a/tools/CustomSetupTool/CustomSetupTool/update.c +++ b/tools/CustomSetupTool/CustomSetupTool/update.c @@ -297,7 +297,7 @@ HRESULT CALLBACK TaskDialogBootstrapCallback( } VOID SetupShowUpdateDialog( - _In_ SETUP_COMMAND_TYPE SetupMode + VOID ) { TASKDIALOGCONFIG config; @@ -312,7 +312,7 @@ VOID SetupShowUpdateDialog( config.dwCommonButtons = TDCBF_CANCEL_BUTTON; config.pszWindowTitle = PhApplicationName; config.pfCallback = TaskDialogBootstrapCallback; - config.lpCallbackData = (LONG_PTR)CreateUpdateContext(SetupMode); + config.lpCallbackData = (LONG_PTR)CreateUpdateContext(); TaskDialogIndirect(&config, NULL, NULL, NULL); From 33640454d70324ebca8fcae6d648aa2ec35f7f99 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 19 Jul 2018 20:02:46 +1000 Subject: [PATCH 1153/2058] SetupTool: remove legacy driver --- tools/CustomSetupTool/CustomSetupTool/setup.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/tools/CustomSetupTool/CustomSetupTool/setup.c b/tools/CustomSetupTool/CustomSetupTool/setup.c index e8019f80eb17..f7fe5a91604e 100644 --- a/tools/CustomSetupTool/CustomSetupTool/setup.c +++ b/tools/CustomSetupTool/CustomSetupTool/setup.c @@ -287,7 +287,7 @@ VOID SetupStartService( { if (status.dwCurrentState != SERVICE_RUNNING) { - ULONG attempts = 5; + ULONG attempts = 10; do { @@ -346,7 +346,7 @@ VOID SetupStopService( { if (status.dwCurrentState != SERVICE_STOPPED) { - ULONG attempts = 5; + ULONG attempts = 10; do { @@ -459,12 +459,10 @@ BOOLEAN SetupUninstallKph( // Stop and uninstall the current installation. if (SetupMode == SETUP_COMMAND_UPDATE) { - SetupStopService(L"KProcessHacker2", TRUE); SetupStopService(L"KProcessHacker3", FALSE); } else { - SetupStopService(L"KProcessHacker2", TRUE); SetupStopService(L"KProcessHacker3", TRUE); } From 8cfe630ee3c6f0bdd3e1b0868b5be06e27f060fe Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 20 Jul 2018 16:41:35 +1000 Subject: [PATCH 1154/2058] SetupTool: Fix updating kph from portable releases --- tools/CustomSetupTool/CustomSetupTool/setup.c | 23 +++++++++++-------- .../CustomSetupTool/CustomSetupTool/update.c | 8 +++---- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/tools/CustomSetupTool/CustomSetupTool/setup.c b/tools/CustomSetupTool/CustomSetupTool/setup.c index f7fe5a91604e..16a48d216494 100644 --- a/tools/CustomSetupTool/CustomSetupTool/setup.c +++ b/tools/CustomSetupTool/CustomSetupTool/setup.c @@ -324,12 +324,10 @@ VOID SetupStopService( { SC_HANDLE serviceHandle; - serviceHandle = PhOpenService( + if (serviceHandle = PhOpenService( ServiceName, - SERVICE_QUERY_STATUS | SERVICE_STOP | DELETE - ); - - if (serviceHandle) + SERVICE_QUERY_STATUS | SERVICE_STOP + )) { ULONG statusLength = 0; SERVICE_STATUS_PROCESS status; @@ -375,13 +373,20 @@ VOID SetupStopService( } while (--attempts != 0); } } - - if (RemoveService) + + CloseServiceHandle(serviceHandle); + } + + if (RemoveService) + { + if (serviceHandle = PhOpenService( + ServiceName, + DELETE + )) { DeleteService(serviceHandle); + CloseServiceHandle(serviceHandle); } - - CloseServiceHandle(serviceHandle); } } diff --git a/tools/CustomSetupTool/CustomSetupTool/update.c b/tools/CustomSetupTool/CustomSetupTool/update.c index 4c55e5d505f1..f1826fd71af1 100644 --- a/tools/CustomSetupTool/CustomSetupTool/update.c +++ b/tools/CustomSetupTool/CustomSetupTool/update.c @@ -33,13 +33,11 @@ NTSTATUS SetupUpdateBuild( if (!ShutdownProcessHacker()) goto CleanupExit; - if (!SetupUninstallKph(Context)) - goto CleanupExit; - if (!SetupCreateUninstallFile(Context)) goto CleanupExit; - //SetupCreateUninstallKey(Context); + if (!SetupUninstallKph(Context)) + goto CleanupExit; if (!SetupExtractBuild(Context)) goto CleanupExit; @@ -237,7 +235,7 @@ VOID SetupShowUpdatingDialog( config.lpCallbackData = (LONG_PTR)Context; config.pszWindowTitle = PhApplicationName; - if (SetupMode = SETUP_COMMAND_SILENTINSTALL) + if (SetupMode == SETUP_COMMAND_SILENTINSTALL) { config.pszMainInstruction = PhaFormatString( L"Installing Process Hacker %lu.%lu.%lu...", From 531a5d31b16d2908446946c85e80f7523e0965f3 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 20 Jul 2018 19:52:19 +1000 Subject: [PATCH 1155/2058] Fix memory leak --- ProcessHacker/plugin.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ProcessHacker/plugin.c b/ProcessHacker/plugin.c index 637ee19cfb88..25a9cc62ef81 100644 --- a/ProcessHacker/plugin.c +++ b/ProcessHacker/plugin.c @@ -254,7 +254,7 @@ VOID PhLoadPlugins( if (applicationDirectory = PhGetApplicationDirectory()) { - PhMoveReference(&PluginsDirectory, PhConcatStrings( // Not absolute. Make sure it is. + PhMoveReference(&pluginsDirectory, PhConcatStrings( // Not absolute. Make sure it is. 4, applicationDirectory->Buffer, L"\\", @@ -262,7 +262,7 @@ VOID PhLoadPlugins( L"\\" )); - PhDereferenceObject(pluginsDirectory); + PhDereferenceObject(applicationDirectory); } } From 17f687bd79de82f3cc22980912af8cb29507e953 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 20 Jul 2018 19:54:25 +1000 Subject: [PATCH 1156/2058] Tidy up --- ProcessHacker/ProcessHacker.rc | 10 ---------- ProcessHacker/main.c | 4 ++-- ProcessHacker/mainwnd.c | 3 +-- 3 files changed, 3 insertions(+), 14 deletions(-) diff --git a/ProcessHacker/ProcessHacker.rc b/ProcessHacker/ProcessHacker.rc index deb6cdec88aa..abcb75c46c88 100644 --- a/ProcessHacker/ProcessHacker.rc +++ b/ProcessHacker/ProcessHacker.rc @@ -2393,16 +2393,6 @@ IDB_SEARCH_ACTIVE PNG "resources\\active_search.png" IDB_SEARCH_INACTIVE PNG "resources\\inactive_search.png" -///////////////////////////////////////////////////////////////////////////// -// -// AFX_DIALOG_LAYOUT -// - -IDD_OPTGENERAL AFX_DIALOG_LAYOUT -BEGIN - 0 -END - #endif // English (Australia) resources ///////////////////////////////////////////////////////////////////////////// diff --git a/ProcessHacker/main.c b/ProcessHacker/main.c index b1328fb999b9..3650ae5877f3 100644 --- a/ProcessHacker/main.c +++ b/ProcessHacker/main.c @@ -358,7 +358,7 @@ VOID PhUnregisterDialog( PhRemoveItemList(DialogList, indexOfDialog); } -struct _PH_MESSAGE_LOOP_FILTER_ENTRY *PhRegisterMessageLoopFilter( +PPH_MESSAGE_LOOP_FILTER_ENTRY PhRegisterMessageLoopFilter( _In_ PPH_MESSAGE_LOOP_FILTER Filter, _In_opt_ PVOID Context ) @@ -377,7 +377,7 @@ struct _PH_MESSAGE_LOOP_FILTER_ENTRY *PhRegisterMessageLoopFilter( } VOID PhUnregisterMessageLoopFilter( - _In_ struct _PH_MESSAGE_LOOP_FILTER_ENTRY *FilterEntry + _In_ PPH_MESSAGE_LOOP_FILTER_ENTRY FilterEntry ) { ULONG indexOfFilter; diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index 43d08fe691b2..5e51ce9767a9 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -75,7 +75,6 @@ PH_MWP_NOTIFICATION_DETAILS PhMwpLastNotificationDetails; static BOOLEAN NeedsMaximize = FALSE; static BOOLEAN AlwaysOnTop = FALSE; - static BOOLEAN DelayedLoadCompleted = FALSE; static PH_CALLBACK_DECLARE(LayoutPaddingCallback); @@ -2325,7 +2324,7 @@ VOID PhMwpInitializeMainMenu( for (i = 0; i < RTL_NUMBER_OF(SubMenuHandles); i++) { - SubMenuHandles[i] = GetSubMenu(PhMainWndMenuHandle, i); + SubMenuHandles[i] = GetSubMenu(Menu, i); } } From 29415c3d42fe23eef698350df8f069487c9c44ff Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 20 Jul 2018 20:06:54 +1000 Subject: [PATCH 1157/2058] Remove unused code --- ProcessHacker/cmdmode.c | 32 -------------------------------- 1 file changed, 32 deletions(-) diff --git a/ProcessHacker/cmdmode.c b/ProcessHacker/cmdmode.c index 5599787ab505..fdc08b3a7dea 100644 --- a/ProcessHacker/cmdmode.c +++ b/ProcessHacker/cmdmode.c @@ -225,38 +225,6 @@ NTSTATUS PhCommandModeStart( NtClose(processHandle); } } - //else if (PhEqualString2(PhStartupParameters.CommandAction, L"unloaddll", TRUE)) - //{ - // if (!PhStartupParameters.CommandValue) - // return STATUS_INVALID_PARAMETER; - // - // if (NT_SUCCESS(status = PhOpenProcessPublic( - // &processHandle, - // ProcessQueryAccess | PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE, - // processId - // ))) - // { - // PVOID baseAddress; - // - // if (NT_SUCCESS(status = PhpGetDllBaseRemote( - // processHandle, - // &PhStartupParameters.CommandValue->sr, - // &baseAddress - // ))) - // { - // LARGE_INTEGER timeout; - // - // timeout.QuadPart = -(LONGLONG)UInt32x32To64(5, PH_TIMEOUT_SEC); - // status = PhUnloadDllProcess( - // processHandle, - // baseAddress, - // &timeout - // ); - // } - // - // NtClose(processHandle); - // } - //} } else if (PhEqualString2(PhStartupParameters.CommandType, L"service", TRUE)) { From 298f397129e95f3b25cfb730881ceca5afeca875 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 22 Jul 2018 14:13:32 +1000 Subject: [PATCH 1158/2058] Update plugin callback events --- ProcessHacker/include/mainwnd.h | 6 +++--- ProcessHacker/include/netprv.h | 5 ----- ProcessHacker/include/phapp.h | 4 ++-- ProcessHacker/include/phplug.h | 20 +++++++++++++++++++- ProcessHacker/include/procprv.h | 6 ------ ProcessHacker/include/srvprv.h | 6 ------ ProcessHacker/memlists.c | 5 +++-- ProcessHacker/miniinfo.c | 4 ++-- ProcessHacker/mwpgnet.c | 9 +++++---- ProcessHacker/mwpgproc.c | 8 ++++---- ProcessHacker/mwpgsrv.c | 8 ++++---- ProcessHacker/netprv.c | 14 +++++--------- ProcessHacker/notifico.c | 2 +- ProcessHacker/procprv.c | 13 ++++--------- ProcessHacker/prpgperf.c | 5 +++-- ProcessHacker/prpgstat.c | 5 +++-- ProcessHacker/prpgwmi.c | 5 +++-- ProcessHacker/srvctl.c | 6 +++--- ProcessHacker/srvprv.c | 14 +++++--------- ProcessHacker/sysinfo.c | 4 ++-- ProcessHacker/thrdprv.c | 5 +++-- 21 files changed, 74 insertions(+), 80 deletions(-) diff --git a/ProcessHacker/include/mainwnd.h b/ProcessHacker/include/mainwnd.h index 48808da1c56c..aa5fb72bfa7b 100644 --- a/ProcessHacker/include/mainwnd.h +++ b/ProcessHacker/include/mainwnd.h @@ -8,9 +8,9 @@ extern BOOLEAN PhMainWndExiting; #define WM_PH_ACTIVATE (WM_APP + 99) #define PH_ACTIVATE_REPLY 0x1119 -#define WM_PH_PROCESSES_UPDATED (WM_APP + 104) -#define WM_PH_SERVICES_UPDATED (WM_APP + 108) -#define WM_PH_NETWORK_ITEMS_UPDATED (WM_APP + 112) +#define WM_PH_PROCESSES_UPDATED (WM_APP + 100) +#define WM_PH_SERVICES_UPDATED (WM_APP + 101) +#define WM_PH_NETWORK_ITEMS_UPDATED (WM_APP + 102) // begin_phapppub #define WM_PH_SHOW_PROCESS_PROPERTIES (WM_APP + 120) diff --git a/ProcessHacker/include/netprv.h b/ProcessHacker/include/netprv.h index a314f07430b2..c86269ac90ef 100644 --- a/ProcessHacker/include/netprv.h +++ b/ProcessHacker/include/netprv.h @@ -2,11 +2,6 @@ #define PH_NETPRV_H extern PPH_OBJECT_TYPE PhNetworkItemType; -PHAPPAPI extern PH_CALLBACK PhNetworkItemAddedEvent; // phapppub -PHAPPAPI extern PH_CALLBACK PhNetworkItemModifiedEvent; // phapppub -PHAPPAPI extern PH_CALLBACK PhNetworkItemRemovedEvent; // phapppub -PHAPPAPI extern PH_CALLBACK PhNetworkItemsUpdatedEvent; // phapppub - extern BOOLEAN PhEnableNetworkProviderResolve; // begin_phapppub diff --git a/ProcessHacker/include/phapp.h b/ProcessHacker/include/phapp.h index 2e2958f9bb30..ba5565440715 100644 --- a/ProcessHacker/include/phapp.h +++ b/ProcessHacker/include/phapp.h @@ -111,7 +111,7 @@ typedef struct _PH_MESSAGE_LOOP_FILTER_ENTRY } PH_MESSAGE_LOOP_FILTER_ENTRY, *PPH_MESSAGE_LOOP_FILTER_ENTRY; PHAPPAPI -struct _PH_MESSAGE_LOOP_FILTER_ENTRY * +PPH_MESSAGE_LOOP_FILTER_ENTRY NTAPI PhRegisterMessageLoopFilter( _In_ PPH_MESSAGE_LOOP_FILTER Filter, @@ -122,7 +122,7 @@ PHAPPAPI VOID NTAPI PhUnregisterMessageLoopFilter( - _In_ struct _PH_MESSAGE_LOOP_FILTER_ENTRY *FilterEntry + _In_ PPH_MESSAGE_LOOP_FILTER_ENTRY FilterEntry ); // end_phapppub diff --git a/ProcessHacker/include/phplug.h b/ProcessHacker/include/phplug.h index 35c23d954785..f2dfeafb67c7 100644 --- a/ProcessHacker/include/phplug.h +++ b/ProcessHacker/include/phplug.h @@ -44,7 +44,23 @@ typedef enum _PH_GENERAL_CALLBACK GeneralCallbackMemoryItemListControl = 31, // PPH_PLUGIN_MEMORY_ITEM_LIST_CONTROL Data [properties thread] GeneralCallbackMiniInformationInitializing = 32, // PPH_PLUGIN_MINIINFO_POINTERS Data [main thread] GeneralCallbackMiListSectionMenuInitializing = 33, // PPH_PLUGIN_MENU_INFORMATION Data [main thread] - GeneralCallbackOptionsWindowInitializing, // PPH_PLUGIN_OBJECT_PROPERTIES Data [main thread] + GeneralCallbackOptionsWindowInitializing = 34, // PPH_PLUGIN_OBJECT_PROPERTIES Data [main thread] + + GeneralCallbackProcessProviderAddedEvent, // [process provider thread] + GeneralCallbackProcessProviderModifiedEvent, // [process provider thread] + GeneralCallbackProcessProviderRemovedEvent, // [process provider thread] + GeneralCallbackProcessProviderUpdatedEvent, // [process provider thread] + + GeneralCallbackServiceProviderAddedEvent, // [service provider thread] + GeneralCallbackServiceProviderModifiedEvent, // [service provider thread] + GeneralCallbackServiceProviderRemovedEvent, // [service provider thread] + GeneralCallbackServiceProviderUpdatedEvent, // [service provider thread] + + GeneralCallbackNetworkProviderAddedEvent, // [network provider thread] + GeneralCallbackNetworkProviderModifiedEvent, // [network provider thread] + GeneralCallbackNetworkProviderRemovedEvent, // [network provider thread] + GeneralCallbackNetworkProviderUpdatedEvent, // [network provider thread] + GeneralCallbackTrayIconsInitializing, GeneralCallbackMaximum } PH_GENERAL_CALLBACK, *PPH_GENERAL_CALLBACK; @@ -579,6 +595,8 @@ typedef struct _PH_PLUGIN_MENU_ITEM #define PH_MENU_ITEM_LOCATION_HACKER 0 #define PH_MENU_ITEM_LOCATION_VIEW 1 #define PH_MENU_ITEM_LOCATION_TOOLS 2 +#define PH_MENU_ITEM_LOCATION_USERS 3 +#define PH_MENU_ITEM_LOCATION_HELP 4 typedef struct _PH_PLUGIN_SYSTEM_STATISTICS { diff --git a/ProcessHacker/include/procprv.h b/ProcessHacker/include/procprv.h index b47d4dc62a37..40b1de696bcb 100644 --- a/ProcessHacker/include/procprv.h +++ b/ProcessHacker/include/procprv.h @@ -4,12 +4,6 @@ #define PH_RECORD_MAX_USAGE extern PPH_OBJECT_TYPE PhProcessItemType; - -PHAPPAPI extern PH_CALLBACK PhProcessAddedEvent; // phapppub -PHAPPAPI extern PH_CALLBACK PhProcessModifiedEvent; // phapppub -PHAPPAPI extern PH_CALLBACK PhProcessRemovedEvent; // phapppub -PHAPPAPI extern PH_CALLBACK PhProcessesUpdatedEvent; // phapppub - extern PPH_LIST PhProcessRecordList; extern PH_QUEUED_LOCK PhProcessRecordListLock; diff --git a/ProcessHacker/include/srvprv.h b/ProcessHacker/include/srvprv.h index a884dd2d9f20..3b403b6db480 100644 --- a/ProcessHacker/include/srvprv.h +++ b/ProcessHacker/include/srvprv.h @@ -2,12 +2,6 @@ #define PH_SRVPRV_H extern PPH_OBJECT_TYPE PhServiceItemType; - -PHAPPAPI extern PH_CALLBACK PhServiceAddedEvent; // phapppub -PHAPPAPI extern PH_CALLBACK PhServiceModifiedEvent; // phapppub -PHAPPAPI extern PH_CALLBACK PhServiceRemovedEvent; // phapppub -PHAPPAPI extern PH_CALLBACK PhServicesUpdatedEvent; // phapppub - extern BOOLEAN PhEnableServiceNonPoll; // begin_phapppub diff --git a/ProcessHacker/memlists.c b/ProcessHacker/memlists.c index fd1a094a0396..6c037877201b 100644 --- a/ProcessHacker/memlists.c +++ b/ProcessHacker/memlists.c @@ -21,6 +21,7 @@ */ #include +#include #include #include #include @@ -178,7 +179,7 @@ INT_PTR CALLBACK PhpMemoryListsDlgProc( NtClose(tokenHandle); } - PhRegisterCallback(&PhProcessesUpdatedEvent, ProcessesUpdatedCallback, NULL, &ProcessesUpdatedRegistration); + PhRegisterCallback(PhGetGeneralCallback(GeneralCallbackProcessProviderUpdatedEvent), ProcessesUpdatedCallback, NULL, &ProcessesUpdatedRegistration); PhpUpdateMemoryListInfo(hwndDlg); PhLoadWindowPlacementFromSetting(L"MemoryListsWindowPosition", NULL, hwndDlg); @@ -190,7 +191,7 @@ INT_PTR CALLBACK PhpMemoryListsDlgProc( PhUnregisterDialog(hwndDlg); PhSaveWindowPlacementToSetting(L"MemoryListsWindowPosition", NULL, hwndDlg); - PhUnregisterCallback(&PhProcessesUpdatedEvent, &ProcessesUpdatedRegistration); + PhUnregisterCallback(PhGetGeneralCallback(GeneralCallbackProcessProviderUpdatedEvent), &ProcessesUpdatedRegistration); UnregisterDialogFunction(hwndDlg); PhMemoryListsWindowHandle = NULL; diff --git a/ProcessHacker/miniinfo.c b/ProcessHacker/miniinfo.c index a371a5bb97fc..46669acdaa19 100644 --- a/ProcessHacker/miniinfo.c +++ b/ProcessHacker/miniinfo.c @@ -342,7 +342,7 @@ VOID PhMipContainerOnShowWindow( PhMipMessageLoopFilterEntry = PhRegisterMessageLoopFilter(PhMipMessageLoopFilter, NULL); PhRegisterCallback( - &PhProcessesUpdatedEvent, + PhGetGeneralCallback(GeneralCallbackProcessProviderUpdatedEvent), PhMipUpdateHandler, NULL, &ProcessesUpdatedRegistration @@ -362,7 +362,7 @@ VOID PhMipContainerOnShowWindow( PhSetIntegerSetting(L"MiniInfoWindowPinned", FALSE); PhUnregisterCallback( - &PhProcessesUpdatedEvent, + PhGetGeneralCallback(GeneralCallbackProcessProviderUpdatedEvent), &ProcessesUpdatedRegistration ); diff --git a/ProcessHacker/mwpgnet.c b/ProcessHacker/mwpgnet.c index e87dd26a01c9..985bf6346d80 100644 --- a/ProcessHacker/mwpgnet.c +++ b/ProcessHacker/mwpgnet.c @@ -22,6 +22,7 @@ */ #include +#include #include #include @@ -65,25 +66,25 @@ BOOLEAN PhMwpNetworkPageCallback( PhInitializeProviderEventQueue(&PhMwpNetworkEventQueue, 100); PhRegisterCallback( - &PhNetworkItemAddedEvent, + PhGetGeneralCallback(GeneralCallbackNetworkProviderAddedEvent), PhMwpNetworkItemAddedHandler, NULL, &NetworkItemAddedRegistration ); PhRegisterCallback( - &PhNetworkItemModifiedEvent, + PhGetGeneralCallback(GeneralCallbackNetworkProviderModifiedEvent), PhMwpNetworkItemModifiedHandler, NULL, &NetworkItemModifiedRegistration ); PhRegisterCallback( - &PhNetworkItemRemovedEvent, + PhGetGeneralCallback(GeneralCallbackNetworkProviderRemovedEvent), PhMwpNetworkItemRemovedHandler, NULL, &NetworkItemRemovedRegistration ); PhRegisterCallback( - &PhNetworkItemsUpdatedEvent, + PhGetGeneralCallback(GeneralCallbackNetworkProviderUpdatedEvent), PhMwpNetworkItemsUpdatedHandler, NULL, &NetworkItemsUpdatedRegistration diff --git a/ProcessHacker/mwpgproc.c b/ProcessHacker/mwpgproc.c index aa31f05410dc..6ac15435c197 100644 --- a/ProcessHacker/mwpgproc.c +++ b/ProcessHacker/mwpgproc.c @@ -73,25 +73,25 @@ BOOLEAN PhMwpProcessesPageCallback( PhInitializeProviderEventQueue(&PhMwpProcessEventQueue, 100); PhRegisterCallback( - &PhProcessAddedEvent, + PhGetGeneralCallback(GeneralCallbackProcessProviderAddedEvent), PhMwpProcessAddedHandler, NULL, &ProcessAddedRegistration ); PhRegisterCallback( - &PhProcessModifiedEvent, + PhGetGeneralCallback(GeneralCallbackProcessProviderModifiedEvent), PhMwpProcessModifiedHandler, NULL, &ProcessModifiedRegistration ); PhRegisterCallback( - &PhProcessRemovedEvent, + PhGetGeneralCallback(GeneralCallbackProcessProviderRemovedEvent), PhMwpProcessRemovedHandler, NULL, &ProcessRemovedRegistration ); PhRegisterCallback( - &PhProcessesUpdatedEvent, + PhGetGeneralCallback(GeneralCallbackProcessProviderUpdatedEvent), PhMwpProcessesUpdatedHandler, NULL, &ProcessesUpdatedRegistration diff --git a/ProcessHacker/mwpgsrv.c b/ProcessHacker/mwpgsrv.c index 9d07c0cedab9..be043cac2d5d 100644 --- a/ProcessHacker/mwpgsrv.c +++ b/ProcessHacker/mwpgsrv.c @@ -64,25 +64,25 @@ BOOLEAN PhMwpServicesPageCallback( PhInitializeProviderEventQueue(&PhMwpServiceEventQueue, 100); PhRegisterCallback( - &PhServiceAddedEvent, + PhGetGeneralCallback(GeneralCallbackServiceProviderAddedEvent), PhMwpServiceAddedHandler, NULL, &ServiceAddedRegistration ); PhRegisterCallback( - &PhServiceModifiedEvent, + PhGetGeneralCallback(GeneralCallbackServiceProviderModifiedEvent), PhMwpServiceModifiedHandler, NULL, &ServiceModifiedRegistration ); PhRegisterCallback( - &PhServiceRemovedEvent, + PhGetGeneralCallback(GeneralCallbackServiceProviderRemovedEvent), PhMwpServiceRemovedHandler, NULL, &ServiceRemovedRegistration ); PhRegisterCallback( - &PhServicesUpdatedEvent, + PhGetGeneralCallback(GeneralCallbackServiceProviderUpdatedEvent), PhMwpServicesUpdatedHandler, NULL, &ServicesUpdatedRegistration diff --git a/ProcessHacker/netprv.c b/ProcessHacker/netprv.c index c3323744add7..1480df59452e 100644 --- a/ProcessHacker/netprv.c +++ b/ProcessHacker/netprv.c @@ -22,6 +22,7 @@ */ #include +#include #include #include #include @@ -91,11 +92,6 @@ PPH_OBJECT_TYPE PhNetworkItemType; PPH_HASHTABLE PhNetworkHashtable; PH_QUEUED_LOCK PhNetworkHashtableLock = PH_QUEUED_LOCK_INIT; -PHAPPAPI PH_CALLBACK_DECLARE(PhNetworkItemAddedEvent); -PHAPPAPI PH_CALLBACK_DECLARE(PhNetworkItemModifiedEvent); -PHAPPAPI PH_CALLBACK_DECLARE(PhNetworkItemRemovedEvent); -PHAPPAPI PH_CALLBACK_DECLARE(PhNetworkItemsUpdatedEvent); - PH_INITONCE PhNetworkProviderWorkQueueInitOnce = PH_INITONCE_INIT; PH_WORK_QUEUE PhNetworkProviderWorkQueue; SLIST_HEADER PhNetworkItemQueryListHead; @@ -530,7 +526,7 @@ VOID PhNetworkProviderUpdate( if (!found) { - PhInvokeCallback(&PhNetworkItemRemovedEvent, *networkItem); + PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackNetworkProviderRemovedEvent), *networkItem); if (!connectionsToRemove) connectionsToRemove = PhCreateList(2); @@ -675,7 +671,7 @@ VOID PhNetworkProviderUpdate( PhReleaseQueuedLockExclusive(&PhNetworkHashtableLock); // Raise the network item added event. - PhInvokeCallback(&PhNetworkItemAddedEvent, networkItem); + PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackNetworkProviderAddedEvent), networkItem); } else { @@ -717,7 +713,7 @@ VOID PhNetworkProviderUpdate( if (modified) { // Raise the network item modified event. - PhInvokeCallback(&PhNetworkItemModifiedEvent, networkItem); + PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackNetworkProviderModifiedEvent), networkItem); } PhDereferenceObject(networkItem); @@ -726,7 +722,7 @@ VOID PhNetworkProviderUpdate( PhFree(connections); - PhInvokeCallback(&PhNetworkItemsUpdatedEvent, NULL); + PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackNetworkProviderUpdatedEvent), NULL); } PWSTR PhGetProtocolTypeName( diff --git a/ProcessHacker/notifico.c b/ProcessHacker/notifico.c index a767031bc1ee..9df586a1f858 100644 --- a/ProcessHacker/notifico.c +++ b/ProcessHacker/notifico.c @@ -186,7 +186,7 @@ VOID PhNfLoadStage2( } PhRegisterCallback( - &PhProcessesUpdatedEvent, + PhGetGeneralCallback(GeneralCallbackProcessProviderUpdatedEvent), PhNfpProcessesUpdatedHandler, NULL, &PhNfpProcessesUpdatedRegistration diff --git a/ProcessHacker/procprv.c b/ProcessHacker/procprv.c index a13ba5ba229e..fd7606d78b09 100644 --- a/ProcessHacker/procprv.c +++ b/ProcessHacker/procprv.c @@ -161,11 +161,6 @@ PH_QUEUED_LOCK PhProcessHashSetLock = PH_QUEUED_LOCK_INIT; SLIST_HEADER PhProcessQueryDataListHead; -PHAPPAPI PH_CALLBACK_DECLARE(PhProcessAddedEvent); -PHAPPAPI PH_CALLBACK_DECLARE(PhProcessModifiedEvent); -PHAPPAPI PH_CALLBACK_DECLARE(PhProcessRemovedEvent); -PHAPPAPI PH_CALLBACK_DECLARE(PhProcessesUpdatedEvent); - PPH_LIST PhProcessRecordList; PH_QUEUED_LOCK PhProcessRecordListLock = PH_QUEUED_LOCK_INIT; @@ -1959,7 +1954,7 @@ VOID PhProcessProviderUpdate( processItem->Record->ExitTime = exitTime; // Raise the process removed event. - PhInvokeCallback(&PhProcessRemovedEvent, processItem); + PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackProcessProviderRemovedEvent), processItem); if (!processesToRemove) processesToRemove = PhCreateList(2); @@ -2068,7 +2063,7 @@ VOID PhProcessProviderUpdate( PhReleaseQueuedLockExclusive(&PhProcessHashSetLock); // Raise the process added event. - PhInvokeCallback(&PhProcessAddedEvent, processItem); + PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackProcessProviderAddedEvent), processItem); // (Ref: for the process item being in the hashtable.) // Instead of referencing then dereferencing we simply don't do anything. @@ -2231,7 +2226,7 @@ VOID PhProcessProviderUpdate( if (modified) { - PhInvokeCallback(&PhProcessModifiedEvent, processItem); + PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackProcessProviderModifiedEvent), processItem); } // No reference added by PhpLookupProcessItem. @@ -2326,7 +2321,7 @@ VOID PhProcessProviderUpdate( } } - PhInvokeCallback(&PhProcessesUpdatedEvent, NULL); + PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackProcessProviderUpdatedEvent), NULL); runCount++; } diff --git a/ProcessHacker/prpgperf.c b/ProcessHacker/prpgperf.c index 217a973de8ec..301aa82eab5d 100644 --- a/ProcessHacker/prpgperf.c +++ b/ProcessHacker/prpgperf.c @@ -21,6 +21,7 @@ */ #include +#include #include #include @@ -74,7 +75,7 @@ INT_PTR CALLBACK PhpProcessPerformanceDlgProc( performanceContext->WindowHandle = hwndDlg; PhRegisterCallback( - &PhProcessesUpdatedEvent, + PhGetGeneralCallback(GeneralCallbackProcessProviderUpdatedEvent), PerformanceUpdateHandler, performanceContext, &performanceContext->ProcessesUpdatedRegistration @@ -113,7 +114,7 @@ INT_PTR CALLBACK PhpProcessPerformanceDlgProc( PhDeleteGraphState(&performanceContext->IoGraphState); PhUnregisterCallback( - &PhProcessesUpdatedEvent, + PhGetGeneralCallback(GeneralCallbackProcessProviderUpdatedEvent), &performanceContext->ProcessesUpdatedRegistration ); PhFree(performanceContext); diff --git a/ProcessHacker/prpgstat.c b/ProcessHacker/prpgstat.c index 6bf227603184..80bd55c1b66a 100644 --- a/ProcessHacker/prpgstat.c +++ b/ProcessHacker/prpgstat.c @@ -22,6 +22,7 @@ */ #include +#include #include #include #include @@ -320,7 +321,7 @@ INT_PTR CALLBACK PhpProcessStatisticsDlgProc( PhpUpdateStatisticsAddListViewGroups(statisticsContext->ListViewHandle); PhRegisterCallback( - &PhProcessesUpdatedEvent, + PhGetGeneralCallback(GeneralCallbackProcessProviderUpdatedEvent), StatisticsUpdateHandler, statisticsContext, &statisticsContext->ProcessesUpdatedRegistration @@ -334,7 +335,7 @@ INT_PTR CALLBACK PhpProcessStatisticsDlgProc( case WM_DESTROY: { PhUnregisterCallback( - &PhProcessesUpdatedEvent, + PhGetGeneralCallback(GeneralCallbackProcessProviderUpdatedEvent), &statisticsContext->ProcessesUpdatedRegistration ); diff --git a/ProcessHacker/prpgwmi.c b/ProcessHacker/prpgwmi.c index 874f5326ca87..7219863531d0 100644 --- a/ProcessHacker/prpgwmi.c +++ b/ProcessHacker/prpgwmi.c @@ -21,6 +21,7 @@ */ #include +#include #include #include #include @@ -603,7 +604,7 @@ INT_PTR CALLBACK PhpProcessWmiProvidersDlgProc( PhpRefreshWmiProviders(hwndDlg, context, processItem); PhRegisterCallback( - &PhProcessesUpdatedEvent, + PhGetGeneralCallback(GeneralCallbackProcessProviderUpdatedEvent), PhpWmiProviderUpdateHandler, context, &context->ProcessesUpdatedRegistration @@ -612,7 +613,7 @@ INT_PTR CALLBACK PhpProcessWmiProvidersDlgProc( break; case WM_DESTROY: { - PhUnregisterCallback(&PhProcessesUpdatedEvent, &context->ProcessesUpdatedRegistration); + PhUnregisterCallback(PhGetGeneralCallback(GeneralCallbackProcessProviderUpdatedEvent), &context->ProcessesUpdatedRegistration); PhSaveListViewColumnsToSetting(L"WmiProviderListViewColumns", context->ListViewHandle); diff --git a/ProcessHacker/srvctl.c b/ProcessHacker/srvctl.c index 06e2d0201934..5c0819d4b199 100644 --- a/ProcessHacker/srvctl.c +++ b/ProcessHacker/srvctl.c @@ -21,7 +21,7 @@ */ #include - +#include #include #include @@ -231,7 +231,7 @@ INT_PTR CALLBACK PhpServicesPageProc( ULONG i; PhRegisterCallback( - &PhServiceModifiedEvent, + PhGetGeneralCallback(GeneralCallbackServiceProviderModifiedEvent), ServiceModifiedHandler, context, &context->ModifiedEventRegistration @@ -294,7 +294,7 @@ INT_PTR CALLBACK PhpServicesPageProc( PhFree(context->Services); PhUnregisterCallback( - &PhServiceModifiedEvent, + PhGetGeneralCallback(GeneralCallbackServiceProviderModifiedEvent), &context->ModifiedEventRegistration ); diff --git a/ProcessHacker/srvprv.c b/ProcessHacker/srvprv.c index 61d9d51d867d..9539dea68c57 100644 --- a/ProcessHacker/srvprv.c +++ b/ProcessHacker/srvprv.c @@ -22,6 +22,7 @@ */ #include +#include #include #include @@ -139,11 +140,6 @@ PPH_OBJECT_TYPE PhServiceItemType; PPH_HASHTABLE PhServiceHashtable; PH_QUEUED_LOCK PhServiceHashtableLock = PH_QUEUED_LOCK_INIT; -PHAPPAPI PH_CALLBACK_DECLARE(PhServiceAddedEvent); -PHAPPAPI PH_CALLBACK_DECLARE(PhServiceModifiedEvent); -PHAPPAPI PH_CALLBACK_DECLARE(PhServiceRemovedEvent); -PHAPPAPI PH_CALLBACK_DECLARE(PhServicesUpdatedEvent); - BOOLEAN PhEnableServiceNonPoll = FALSE; static BOOLEAN PhpNonPollInitialized = FALSE; static BOOLEAN PhpNonPollActive = FALSE; @@ -826,7 +822,7 @@ VOID PhServiceProviderUpdate( } // Raise the service removed event. - PhInvokeCallback(&PhServiceRemovedEvent, *serviceItem); + PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackServiceProviderRemovedEvent), *serviceItem); if (!servicesToRemove) servicesToRemove = PhCreateList(2); @@ -919,7 +915,7 @@ VOID PhServiceProviderUpdate( PhReleaseQueuedLockExclusive(&PhServiceHashtableLock); // Raise the service added event. - PhInvokeCallback(&PhServiceAddedEvent, serviceItem); + PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackServiceProviderAddedEvent), serviceItem); } else { @@ -1027,7 +1023,7 @@ VOID PhServiceProviderUpdate( serviceItem->JustProcessed = FALSE; // Raise the service modified event. - PhInvokeCallback(&PhServiceModifiedEvent, &serviceModifiedData); + PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackServiceProviderModifiedEvent), &serviceModifiedData); } } } @@ -1036,7 +1032,7 @@ VOID PhServiceProviderUpdate( PhFree(services); UpdateEnd: - PhInvokeCallback(&PhServicesUpdatedEvent, NULL); + PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackServiceProviderUpdatedEvent), NULL); runCount++; } diff --git a/ProcessHacker/sysinfo.c b/ProcessHacker/sysinfo.c index 1085d5372d33..e367d4b8e9ae 100644 --- a/ProcessHacker/sysinfo.c +++ b/ProcessHacker/sysinfo.c @@ -292,7 +292,7 @@ VOID PhSipOnInitDialog( PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(PhSipWindow, IDOK), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); PhRegisterCallback( - &PhProcessesUpdatedEvent, + PhGetGeneralCallback(GeneralCallbackProcessProviderUpdatedEvent), PhSipSysInfoUpdateHandler, NULL, &ProcessesUpdatedRegistration @@ -315,7 +315,7 @@ VOID PhSipOnDestroy( ) { PhUnregisterCallback( - &PhProcessesUpdatedEvent, + PhGetGeneralCallback(GeneralCallbackProcessProviderUpdatedEvent), &ProcessesUpdatedRegistration ); diff --git a/ProcessHacker/thrdprv.c b/ProcessHacker/thrdprv.c index 7404f1137278..9ccbe2587a5a 100644 --- a/ProcessHacker/thrdprv.c +++ b/ProcessHacker/thrdprv.c @@ -27,6 +27,7 @@ */ #include +#include #include #include @@ -215,7 +216,7 @@ VOID PhRegisterThreadProvider( ) { PhReferenceObject(ThreadProvider); - PhRegisterCallback(&PhProcessesUpdatedEvent, PhpThreadProviderCallbackHandler, ThreadProvider, CallbackRegistration); + PhRegisterCallback(PhGetGeneralCallback(GeneralCallbackProcessProviderUpdatedEvent), PhpThreadProviderCallbackHandler, ThreadProvider, CallbackRegistration); } VOID PhUnregisterThreadProvider( @@ -223,7 +224,7 @@ VOID PhUnregisterThreadProvider( _In_ PPH_CALLBACK_REGISTRATION CallbackRegistration ) { - PhUnregisterCallback(&PhProcessesUpdatedEvent, CallbackRegistration); + PhUnregisterCallback(PhGetGeneralCallback(GeneralCallbackProcessProviderUpdatedEvent), CallbackRegistration); PhDereferenceObject(ThreadProvider); } From 4c17cd8dc465a72bb12701864ca497528c13c2d5 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 22 Jul 2018 14:17:02 +1000 Subject: [PATCH 1159/2058] Plugins: Update callback events --- plugins/ExtendedTools/etwdisk.c | 2 +- plugins/ExtendedTools/etwprprp.c | 4 ++-- plugins/ExtendedTools/etwstat.c | 4 ++-- plugins/ExtendedTools/gpudetails.c | 4 ++-- plugins/ExtendedTools/gpumon.c | 2 +- plugins/ExtendedTools/gpunodes.c | 4 ++-- plugins/ExtendedTools/gpuprprp.c | 4 ++-- plugins/ExtendedTools/main.c | 4 ++-- plugins/HardwareDevices/main.c | 2 +- plugins/HardwareDevices/netdetails.c | 4 ++-- plugins/NetworkTools/ping.c | 4 ++-- plugins/UserNotes/main.c | 5 +++-- 12 files changed, 22 insertions(+), 21 deletions(-) diff --git a/plugins/ExtendedTools/etwdisk.c b/plugins/ExtendedTools/etwdisk.c index c8512f20a01d..f0d3c4215d1d 100644 --- a/plugins/ExtendedTools/etwdisk.c +++ b/plugins/ExtendedTools/etwdisk.c @@ -95,7 +95,7 @@ VOID EtInitializeDiskInformation( EtStartEtwRundown(); PhRegisterCallback( - &PhProcessesUpdatedEvent, + PhGetGeneralCallback(GeneralCallbackProcessProviderUpdatedEvent), EtpDiskProcessesUpdatedCallback, NULL, &ProcessesUpdatedCallbackRegistration diff --git a/plugins/ExtendedTools/etwprprp.c b/plugins/ExtendedTools/etwprprp.c index 14e3e9728318..ffe4f3f12d0b 100644 --- a/plugins/ExtendedTools/etwprprp.c +++ b/plugins/ExtendedTools/etwprprp.c @@ -332,7 +332,7 @@ INT_PTR CALLBACK EtwDiskNetworkPageDlgProc( EtwDiskNetworkUpdatePanel(context); PhRegisterCallback( - &PhProcessesUpdatedEvent, + PhGetGeneralCallback(GeneralCallbackProcessProviderUpdatedEvent), EtwDiskNetworkUpdateHandler, context, &context->ProcessesUpdatedRegistration @@ -358,7 +358,7 @@ INT_PTR CALLBACK EtwDiskNetworkPageDlgProc( if (context->PanelHandle) DestroyWindow(context->PanelHandle); - PhUnregisterCallback(&PhProcessesUpdatedEvent, &context->ProcessesUpdatedRegistration); + PhUnregisterCallback(PhGetGeneralCallback(GeneralCallbackProcessProviderUpdatedEvent), &context->ProcessesUpdatedRegistration); PhFree(context); PhPropPageDlgProcDestroy(hwndDlg); diff --git a/plugins/ExtendedTools/etwstat.c b/plugins/ExtendedTools/etwstat.c index 33ee65dd33ee..b67eea9ceea1 100644 --- a/plugins/ExtendedTools/etwstat.c +++ b/plugins/ExtendedTools/etwstat.c @@ -85,13 +85,13 @@ VOID EtEtwStatisticsInitialization( PhInitializeCircularBuffer_ULONG(&EtMaxNetworkHistory, sampleCount); PhRegisterCallback( - &PhProcessesUpdatedEvent, + PhGetGeneralCallback(GeneralCallbackProcessProviderUpdatedEvent), EtEtwProcessesUpdatedCallback, NULL, &EtpProcessesUpdatedCallbackRegistration ); PhRegisterCallback( - &PhNetworkItemsUpdatedEvent, + PhGetGeneralCallback(GeneralCallbackNetworkProviderUpdatedEvent), EtEtwNetworkItemsUpdatedCallback, NULL, &EtpNetworkItemsUpdatedCallbackRegistration diff --git a/plugins/ExtendedTools/gpudetails.c b/plugins/ExtendedTools/gpudetails.c index f9c25c2b5aa6..f8c0ff217048 100644 --- a/plugins/ExtendedTools/gpudetails.c +++ b/plugins/ExtendedTools/gpudetails.c @@ -344,7 +344,7 @@ INT_PTR CALLBACK EtpGpuDetailsDlgProc( EtpGpuDetailsEnumAdapters(listViewHandle); PhRegisterCallback( - &PhProcessesUpdatedEvent, + PhGetGeneralCallback(GeneralCallbackProcessProviderUpdatedEvent), ProcessesUpdatedCallback, hwndDlg, &ProcessesUpdatedCallbackRegistration @@ -355,7 +355,7 @@ INT_PTR CALLBACK EtpGpuDetailsDlgProc( break; case WM_DESTROY: { - PhUnregisterCallback(&PhProcessesUpdatedEvent, &ProcessesUpdatedCallbackRegistration); + PhUnregisterCallback(PhGetGeneralCallback(GeneralCallbackProcessProviderUpdatedEvent), &ProcessesUpdatedCallbackRegistration); PhDeleteLayoutManager(&LayoutManager); } diff --git a/plugins/ExtendedTools/gpumon.c b/plugins/ExtendedTools/gpumon.c index d6b686e172e1..893b13ceb3cf 100644 --- a/plugins/ExtendedTools/gpumon.c +++ b/plugins/ExtendedTools/gpumon.c @@ -86,7 +86,7 @@ VOID EtGpuMonitorInitialization( } PhRegisterCallback( - &PhProcessesUpdatedEvent, + PhGetGeneralCallback(GeneralCallbackProcessProviderUpdatedEvent), EtGpuProcessesUpdatedCallback, NULL, &ProcessesUpdatedCallbackRegistration diff --git a/plugins/ExtendedTools/gpunodes.c b/plugins/ExtendedTools/gpunodes.c index af860bf08dde..c6c92aed9b2e 100644 --- a/plugins/ExtendedTools/gpunodes.c +++ b/plugins/ExtendedTools/gpunodes.c @@ -184,7 +184,7 @@ INT_PTR CALLBACK EtpGpuNodesDlgProc( PhCenterWindow(hwndDlg, (HWND)lParam); PhRegisterCallback( - &PhProcessesUpdatedEvent, + PhGetGeneralCallback(GeneralCallbackProcessProviderUpdatedEvent), ProcessesUpdatedCallback, hwndDlg, &ProcessesUpdatedCallbackRegistration @@ -197,7 +197,7 @@ INT_PTR CALLBACK EtpGpuNodesDlgProc( { PhSaveWindowPlacementToSetting(SETTING_NAME_GPU_NODES_WINDOW_POSITION, SETTING_NAME_GPU_NODES_WINDOW_SIZE, hwndDlg); - PhUnregisterCallback(&PhProcessesUpdatedEvent, &ProcessesUpdatedCallbackRegistration); + PhUnregisterCallback(PhGetGeneralCallback(GeneralCallbackProcessProviderUpdatedEvent), &ProcessesUpdatedCallbackRegistration); for (ULONG i = 0; i < EtGpuTotalNodeCount; i++) { diff --git a/plugins/ExtendedTools/gpuprprp.c b/plugins/ExtendedTools/gpuprprp.c index a0e460533bd3..44724a55eb68 100644 --- a/plugins/ExtendedTools/gpuprprp.c +++ b/plugins/ExtendedTools/gpuprprp.c @@ -525,7 +525,7 @@ INT_PTR CALLBACK EtpGpuPageDlgProc( GpuPropUpdatePanel(context); PhRegisterCallback( - &PhProcessesUpdatedEvent, + PhGetGeneralCallback(GeneralCallbackProcessProviderUpdatedEvent), ProcessesUpdatedHandler, context, &context->ProcessesUpdatedRegistration @@ -557,7 +557,7 @@ INT_PTR CALLBACK EtpGpuPageDlgProc( if (context->PanelHandle) DestroyWindow(context->PanelHandle); - PhUnregisterCallback(&PhProcessesUpdatedEvent, &context->ProcessesUpdatedRegistration); + PhUnregisterCallback(PhGetGeneralCallback(GeneralCallbackProcessProviderUpdatedEvent), &context->ProcessesUpdatedRegistration); PhFree(context); PhPropPageDlgProcDestroy(hwndDlg); diff --git a/plugins/ExtendedTools/main.c b/plugins/ExtendedTools/main.c index 9983172076ba..0ec016639a2b 100644 --- a/plugins/ExtendedTools/main.c +++ b/plugins/ExtendedTools/main.c @@ -611,13 +611,13 @@ LOGICAL DllMain( ); PhRegisterCallback( - &PhProcessesUpdatedEvent, + PhGetGeneralCallback(GeneralCallbackProcessProviderUpdatedEvent), ProcessesUpdatedCallback, NULL, &ProcessesUpdatedCallbackRegistration ); PhRegisterCallback( - &PhNetworkItemsUpdatedEvent, + PhGetGeneralCallback(GeneralCallbackNetworkProviderUpdatedEvent), NetworkItemsUpdatedCallback, NULL, &NetworkItemsUpdatedCallbackRegistration diff --git a/plugins/HardwareDevices/main.c b/plugins/HardwareDevices/main.c index 5e6a28bdec6e..9de149b19435 100644 --- a/plugins/HardwareDevices/main.c +++ b/plugins/HardwareDevices/main.c @@ -373,7 +373,7 @@ LOGICAL DllMain( ); PhRegisterCallback( - &PhProcessesUpdatedEvent, + PhGetGeneralCallback(GeneralCallbackProcessProviderUpdatedEvent), ProcessesUpdatedCallback, NULL, &ProcessesUpdatedCallbackRegistration diff --git a/plugins/HardwareDevices/netdetails.c b/plugins/HardwareDevices/netdetails.c index 6bbb13460d46..ec0ef1141518 100644 --- a/plugins/HardwareDevices/netdetails.c +++ b/plugins/HardwareDevices/netdetails.c @@ -544,7 +544,7 @@ INT_PTR CALLBACK NetAdapterDetailsDlgProc( NetAdapterAddListViewItemGroups(context->ListViewHandle); PhRegisterCallback( - &PhProcessesUpdatedEvent, + PhGetGeneralCallback(GeneralCallbackProcessProviderUpdatedEvent), NetAdapterProcessesUpdatedHandler, context, &context->ProcessesUpdatedRegistration @@ -564,7 +564,7 @@ INT_PTR CALLBACK NetAdapterDetailsDlgProc( break; case WM_DESTROY: { - PhUnregisterCallback(&PhProcessesUpdatedEvent, &context->ProcessesUpdatedRegistration); + PhUnregisterCallback(PhGetGeneralCallback(GeneralCallbackProcessProviderUpdatedEvent), &context->ProcessesUpdatedRegistration); if (context->NotifyHandle) CancelMibChangeNotify2(context->NotifyHandle); diff --git a/plugins/NetworkTools/ping.c b/plugins/NetworkTools/ping.c index e69ab3e28e87..36ce4c8a92b5 100644 --- a/plugins/NetworkTools/ping.c +++ b/plugins/NetworkTools/ping.c @@ -342,7 +342,7 @@ INT_PTR CALLBACK NetworkPingWndProc( ); PhRegisterCallback( - &PhProcessesUpdatedEvent, + PhGetGeneralCallback(GeneralCallbackProcessProviderUpdatedEvent), NetworkPingUpdateHandler, context, &context->ProcessesUpdatedRegistration @@ -365,7 +365,7 @@ INT_PTR CALLBACK NetworkPingWndProc( case WM_DESTROY: { PhUnregisterCallback( - &PhProcessesUpdatedEvent, + PhGetGeneralCallback(GeneralCallbackProcessProviderUpdatedEvent), &context->ProcessesUpdatedRegistration ); diff --git a/plugins/UserNotes/main.c b/plugins/UserNotes/main.c index 29ca7bc1e931..d695db123185 100644 --- a/plugins/UserNotes/main.c +++ b/plugins/UserNotes/main.c @@ -1502,13 +1502,14 @@ LOGICAL DllMain( NULL, &MiListSectionMenuInitializingCallbackRegistration ); - PhRegisterCallback(&PhProcessModifiedEvent, + PhRegisterCallback( + PhGetGeneralCallback(GeneralCallbackProcessProviderModifiedEvent), ProcessModifiedCallback, NULL, &ProcessModifiedCallbackRegistration ); PhRegisterCallback( - &PhProcessesUpdatedEvent, + PhGetGeneralCallback(GeneralCallbackProcessProviderUpdatedEvent), ProcessesUpdatedCallback, NULL, &ProcessesUpdatedCallbackRegistration From 2bc9ec4dddc71dffc10f54c1787716d04abf87a5 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 22 Jul 2018 15:00:15 +1000 Subject: [PATCH 1160/2058] Fix RtlGetFullPathName_UEx type --- phnt/include/ntrtl.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phnt/include/ntrtl.h b/phnt/include/ntrtl.h index 3092ca1d9150..98a95b1f9fbf 100644 --- a/phnt/include/ntrtl.h +++ b/phnt/include/ntrtl.h @@ -3429,7 +3429,7 @@ RtlGetFullPathName_UEx( _In_ ULONG BufferLength, _Out_writes_bytes_(BufferLength) PWSTR Buffer, _Out_opt_ PWSTR *FilePart, - _Out_opt_ RTL_PATH_TYPE *InputPathType + _Out_opt_ ULONG *BytesRequired ); #endif From 0c71f927596abbd14ab2be95bd0958d6686e9f74 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 22 Jul 2018 15:07:02 +1000 Subject: [PATCH 1161/2058] Add PhGetFullPathEx --- phlib/include/phutil.h | 9 +++++++ phlib/util.c | 53 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+) diff --git a/phlib/include/phutil.h b/phlib/include/phutil.h index 71b134fe0176..9936413e5115 100644 --- a/phlib/include/phutil.h +++ b/phlib/include/phutil.h @@ -562,6 +562,15 @@ PhGetFullPath( _Out_opt_ PULONG IndexOfFileName ); +PHLIBAPI +NTSTATUS +NTAPI +PhGetFullPathEx( + _In_ PWSTR FileName, + _Out_opt_ PULONG IndexOfFileName, + _Out_ PPH_STRING *FullPath + ); + PHLIBAPI PPH_STRING NTAPI diff --git a/phlib/util.c b/phlib/util.c index b63d4b2ab530..d67865b9c234 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -1881,6 +1881,59 @@ PPH_STRING PhGetFullPath( return fullPath; } +NTSTATUS PhGetFullPathEx( + _In_ PWSTR FileName, + _Out_opt_ PULONG IndexOfFileName, + _Out_ PPH_STRING *FullPath + ) +{ + NTSTATUS status; + PPH_STRING fullPath; + ULONG bufferSize; + ULONG returnLength; + PWSTR filePart; + + bufferSize = 0x80; + fullPath = PhCreateStringEx(NULL, bufferSize * sizeof(WCHAR)); + + status = RtlGetFullPathName_UEx(FileName, bufferSize, fullPath->Buffer, &filePart, &returnLength); + + if (returnLength > bufferSize) + { + PhDereferenceObject(fullPath); + bufferSize = returnLength; + fullPath = PhCreateStringEx(NULL, bufferSize * sizeof(WCHAR)); + + status = RtlGetFullPathName_UEx(FileName, bufferSize, fullPath->Buffer, &filePart, &returnLength); + } + + if (!NT_SUCCESS(status)) + { + PhDereferenceObject(fullPath); + return status; + } + + PhTrimToNullTerminatorString(fullPath); + + if (IndexOfFileName) + { + if (filePart) + { + // The path points to a file. + *IndexOfFileName = (ULONG)(filePart - fullPath->Buffer); + } + else + { + // The path points to a directory. + *IndexOfFileName = -1; + } + } + + *FullPath = fullPath; + + return status; +} + /** * Expands environment variables in a string. * From 5e845cc2035aad1234bc9f7e9b6d9569786e07b6 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 22 Jul 2018 15:14:31 +1000 Subject: [PATCH 1162/2058] Fix tabspace --- phlib/util.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/phlib/util.c b/phlib/util.c index d67865b9c234..40e78e630302 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -1896,7 +1896,13 @@ NTSTATUS PhGetFullPathEx( bufferSize = 0x80; fullPath = PhCreateStringEx(NULL, bufferSize * sizeof(WCHAR)); - status = RtlGetFullPathName_UEx(FileName, bufferSize, fullPath->Buffer, &filePart, &returnLength); + status = RtlGetFullPathName_UEx( + FileName, + bufferSize, + fullPath->Buffer, + &filePart, + &returnLength + ); if (returnLength > bufferSize) { @@ -1904,7 +1910,13 @@ NTSTATUS PhGetFullPathEx( bufferSize = returnLength; fullPath = PhCreateStringEx(NULL, bufferSize * sizeof(WCHAR)); - status = RtlGetFullPathName_UEx(FileName, bufferSize, fullPath->Buffer, &filePart, &returnLength); + status = RtlGetFullPathName_UEx( + FileName, + bufferSize, + fullPath->Buffer, + &filePart, + &returnLength + ); } if (!NT_SUCCESS(status)) From d093f9d95ee3b28a2a96676645aaee0e94443cda Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 22 Jul 2018 15:52:02 +1000 Subject: [PATCH 1163/2058] Add disable/delete options to plugin error window --- ProcessHacker/plugin.c | 164 +++++++++++++++++++++++++++++------------ 1 file changed, 118 insertions(+), 46 deletions(-) diff --git a/ProcessHacker/plugin.c b/ProcessHacker/plugin.c index 25a9cc62ef81..2974fc2018b1 100644 --- a/ProcessHacker/plugin.c +++ b/ProcessHacker/plugin.c @@ -51,7 +51,7 @@ INT NTAPI PhpPluginsCompareFunction( _In_ PPH_AVL_LINKS Links2 ); -BOOLEAN PhLoadPlugin( +NTSTATUS PhLoadPlugin( _In_ PPH_STRING FileName ); @@ -61,10 +61,8 @@ VOID PhpExecuteCallbackForAllPlugins( ); PH_AVL_TREE PhPluginsByName = PH_AVL_TREE_INIT(PhpPluginsCompareFunction); - static PH_CALLBACK GeneralCallbacks[GeneralCallbackMaximum]; static PPH_STRING PluginsDirectory; -static PPH_LIST LoadErrors; static ULONG NextPluginId = IDPLUGINS + 1; VOID PhPluginsInitialization( @@ -211,6 +209,10 @@ static BOOLEAN EnumPluginsDirectoryCallback( baseName.Buffer = Information->FileName; baseName.Length = Information->FileNameLength; + // dmex: make sure we have a valid file extension and not something like ".dll_" + //if (!PhEndsWithStringRef2(&baseName, L".dll", FALSE)) + // return TRUE; + for (ULONG i = 0; i < RTL_NUMBER_OF(PhpPluginBlocklist); i++) { if (PhEndsWithStringRef2(&baseName, PhpPluginBlocklist[i], TRUE)) @@ -228,7 +230,27 @@ static BOOLEAN EnumPluginsDirectoryCallback( } else if (!PhIsPluginDisabled(&baseName)) { - PhLoadPlugin(fileName); + NTSTATUS status; + + status = PhLoadPlugin(fileName); + + if (!NT_SUCCESS(status)) + { + PPH_LIST pluginLoadErrors = Context; + PPHP_PLUGIN_LOAD_ERROR loadError; + PPH_STRING errorMessage; + + loadError = PhAllocate(sizeof(PHP_PLUGIN_LOAD_ERROR)); + PhSetReference(&loadError->FileName, fileName); + + if (errorMessage = PhGetNtMessage(status)) + { + PhSetReference(&loadError->ErrorMessage, errorMessage); + PhDereferenceObject(errorMessage); + } + + PhAddItemList(pluginLoadErrors, loadError); + } } PhDereferenceObject(fileName); @@ -243,9 +265,12 @@ VOID PhLoadPlugins( VOID ) { + ULONG i; HANDLE pluginsDirectoryHandle; PPH_STRING pluginsDirectory; + PPH_LIST pluginLoadErrors; + pluginLoadErrors = PhCreateList(1); pluginsDirectory = PhGetStringSetting(L"PluginsDirectory"); if (RtlDetermineDosPathNameType_U(pluginsDirectory->Buffer) == RtlPathTypeRelative) @@ -283,38 +308,86 @@ VOID PhLoadPlugins( { UNICODE_STRING pattern = RTL_CONSTANT_STRING(L"*.dll"); - PhEnumDirectoryFile(pluginsDirectoryHandle, &pattern, EnumPluginsDirectoryCallback, NULL); + PhEnumDirectoryFile(pluginsDirectoryHandle, &pattern, EnumPluginsDirectoryCallback, pluginLoadErrors); NtClose(pluginsDirectoryHandle); } // Handle load errors. // In certain startup modes we want to ignore all plugin load errors. - if (LoadErrors && LoadErrors->Count != 0 && !PhStartupParameters.PhSvc) + if (pluginLoadErrors->Count != 0 && !PhStartupParameters.PhSvc) { - PH_STRING_BUILDER sb; - ULONG i; + PH_STRING_BUILDER stringBuilder; PPHP_PLUGIN_LOAD_ERROR loadError; PPH_STRING baseName; + TASKDIALOGCONFIG config = { sizeof(TASKDIALOGCONFIG) }; + TASKDIALOG_BUTTON buttons[2]; + INT result; - PhInitializeStringBuilder(&sb, 100); + PhInitializeStringBuilder(&stringBuilder, 100); - for (i = 0; i < LoadErrors->Count; i++) + for (i = 0; i < pluginLoadErrors->Count; i++) { - loadError = LoadErrors->Items[i]; + loadError = pluginLoadErrors->Items[i]; baseName = PhGetBaseName(loadError->FileName); - PhAppendFormatStringBuilder(&sb, L"%s: %s\n", - baseName->Buffer, PhGetStringOrDefault(loadError->ErrorMessage, L"An unknown error occurred.")); + + PhAppendFormatStringBuilder( + &stringBuilder, + L"%s: %s\n", + baseName->Buffer, + PhGetStringOrDefault(loadError->ErrorMessage, L"An unknown error occurred.") + ); + PhDereferenceObject(baseName); } - PhShowError2( - NULL, - L"Unable to load the following plugin(s)", - L"%s", - sb.String->Buffer - ); + config.dwFlags = TDF_ALLOW_DIALOG_CANCELLATION; + config.dwCommonButtons = TDCBF_CANCEL_BUTTON; + config.pszWindowTitle = PhApplicationName; + config.pszMainIcon = TD_ERROR_ICON; + config.pszMainInstruction = L"Unable to load the following plugin(s)"; + config.pszContent = PhGetString(PhFinalStringBuilderString(&stringBuilder)); + + buttons[0].nButtonID = IDYES; + buttons[0].pszButtonText = L"Delete plugins"; + buttons[1].nButtonID = IDNO; + buttons[1].pszButtonText = L"Disable plugins"; + + config.cButtons = 2; + config.pButtons = buttons; + config.nDefaultButton = IDCANCEL; + + if (TaskDialogIndirect( + &config, + &result, + NULL, + NULL + ) == S_OK) + { + switch (result) + { + case IDNO: + for (i = 0; i < pluginLoadErrors->Count; i++) + { + loadError = pluginLoadErrors->Items[i]; + baseName = PhGetBaseName(loadError->FileName); + + PhSetPluginDisabled(&baseName->sr, TRUE); + + PhDereferenceObject(baseName); + } + break; + case IDYES: + for (i = 0; i < pluginLoadErrors->Count; i++) + { + loadError = pluginLoadErrors->Items[i]; + + PhDeleteFileWin32(loadError->FileName->Buffer); + } + break; + } + } - PhDeleteStringBuilder(&sb); + PhDeleteStringBuilder(&stringBuilder); } // When we loaded settings before, we didn't know about plugin settings, so they @@ -325,6 +398,22 @@ VOID PhLoadPlugins( PhConvertIgnoredSettings(); PhpExecuteCallbackForAllPlugins(PluginCallbackLoad, TRUE); + + for (i = 0; i < pluginLoadErrors->Count; i++) + { + PPHP_PLUGIN_LOAD_ERROR loadError; + + loadError = pluginLoadErrors->Items[i]; + + if (loadError->FileName) + PhDereferenceObject(loadError->FileName); + if (loadError->ErrorMessage) + PhDereferenceObject(loadError->ErrorMessage); + + PhFree(loadError); + } + + PhDereferenceObject(pluginLoadErrors); } /** @@ -342,44 +431,27 @@ VOID PhUnloadPlugins( * * \param FileName The full file name of the plugin. */ -BOOLEAN PhLoadPlugin( +NTSTATUS PhLoadPlugin( _In_ PPH_STRING FileName ) { NTSTATUS status; PPH_STRING fileName; - PPH_STRING errorMessage; - PPHP_PLUGIN_LOAD_ERROR loadError; - - fileName = PhGetFullPath(FileName->Buffer, NULL); - if (!fileName) - PhSetReference(&fileName, FileName); - - status = PhLoadPluginImage(fileName, NULL); + status = PhGetFullPathEx( + FileName->Buffer, + NULL, + &fileName + ); if (NT_SUCCESS(status)) { + status = PhLoadPluginImage(fileName, NULL); + PhDereferenceObject(fileName); - return TRUE; } - errorMessage = PhGetNtMessage(status); - - loadError = PhAllocate(sizeof(PHP_PLUGIN_LOAD_ERROR)); - PhSetReference(&loadError->FileName, fileName); - PhSetReference(&loadError->ErrorMessage, errorMessage); - - if (!LoadErrors) - LoadErrors = PhCreateList(2); - - PhAddItemList(LoadErrors, loadError); - - if (errorMessage) - PhDereferenceObject(errorMessage); - - PhDereferenceObject(fileName); - return FALSE; + return status; } VOID PhpExecuteCallbackForAllPlugins( From 6cfc08cbbbbadfa72839b2c9164a3bc6a29f437a Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 22 Jul 2018 15:59:35 +1000 Subject: [PATCH 1164/2058] Add wrapper for PhGetFullPathEx --- phlib/util.c | 38 +------------------------------------- 1 file changed, 1 insertion(+), 37 deletions(-) diff --git a/phlib/util.c b/phlib/util.c index 40e78e630302..63dc7ef951e2 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -1838,45 +1838,9 @@ PPH_STRING PhGetFullPath( ) { PPH_STRING fullPath; - ULONG bufferSize; - ULONG returnLength; - PWSTR filePart; - bufferSize = 0x80; - fullPath = PhCreateStringEx(NULL, bufferSize * sizeof(WCHAR)); - - returnLength = RtlGetFullPathName_U(FileName, bufferSize, fullPath->Buffer, &filePart); - - if (returnLength > bufferSize) - { - PhDereferenceObject(fullPath); - bufferSize = returnLength; - fullPath = PhCreateStringEx(NULL, bufferSize * sizeof(WCHAR)); - - returnLength = RtlGetFullPathName_U(FileName, bufferSize, fullPath->Buffer, &filePart); - } - - if (returnLength == 0) - { - PhDereferenceObject(fullPath); + if (!NT_SUCCESS(PhGetFullPathEx(FileName, IndexOfFileName, &fullPath))) return NULL; - } - - PhTrimToNullTerminatorString(fullPath); - - if (IndexOfFileName) - { - if (filePart) - { - // The path points to a file. - *IndexOfFileName = (ULONG)(filePart - fullPath->Buffer); - } - else - { - // The path points to a directory. - *IndexOfFileName = -1; - } - } return fullPath; } From cb777554505081fc310ffb6dd911a2ba6a5e302f Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 22 Jul 2018 19:25:55 +1000 Subject: [PATCH 1165/2058] ToolStatus: Add toolbar/statusbar font support --- plugins/ToolStatus/main.c | 49 ++++++++++++++++++++++++++++++++- plugins/ToolStatus/toolbar.c | 30 ++++++++++++++++++-- plugins/ToolStatus/toolstatus.h | 8 ++++++ 3 files changed, 83 insertions(+), 4 deletions(-) diff --git a/plugins/ToolStatus/main.c b/plugins/ToolStatus/main.c index 197abf634798..891e7d7eb9ee 100644 --- a/plugins/ToolStatus/main.c +++ b/plugins/ToolStatus/main.c @@ -621,6 +621,33 @@ VOID DrawWindowBorderForTargeting( } } +HFONT ToolStatusGetTreeWindowFont( + VOID + ) +{ + PPH_STRING fontHexString; + LOGFONT font; + + fontHexString = PhaGetStringSetting(L"Font"); + + if ( + fontHexString->Length / sizeof(WCHAR) / 2 == sizeof(LOGFONT) && + PhHexStringToBuffer(&fontHexString->sr, (PUCHAR)&font) + ) + { + HFONT newFont; + + newFont = CreateFontIndirect(&font); + + if (newFont) + { + return newFont; + } + } + + return NULL; +} + LRESULT CALLBACK MainWndSubclassProc( _In_ HWND hWnd, _In_ UINT uMsg, @@ -1309,6 +1336,26 @@ LRESULT CALLBACK MainWndSubclassProc( } } break; + case PHAPP_WM_PLUGIN_UPDATE_FONT: + { + HFONT newFont; + + // Let Process Hacker perform the default processing. + CallWindowProc(MainWindowHookProc, hWnd, uMsg, wParam, lParam); + + if (newFont = ToolStatusGetTreeWindowFont()) + { + if (ToolStatusWindowFont) + DeleteObject(ToolStatusWindowFont); + ToolStatusWindowFont = newFont; + + SendMessage(ToolBarHandle, WM_SETFONT, (WPARAM)ToolStatusWindowFont, TRUE); + SendMessage(StatusBarHandle, WM_SETFONT, (WPARAM)ToolStatusWindowFont, TRUE); + + ToolbarLoadSettings(); + } + } + break; } return CallWindowProc(MainWindowHookProc, hWnd, uMsg, wParam, lParam); @@ -1466,4 +1513,4 @@ LOGICAL DllMain( } return TRUE; -} \ No newline at end of file +} diff --git a/plugins/ToolStatus/toolbar.c b/plugins/ToolStatus/toolbar.c index e34c86469804..62d14bb5d49a 100644 --- a/plugins/ToolStatus/toolbar.c +++ b/plugins/ToolStatus/toolbar.c @@ -25,7 +25,7 @@ SIZE ToolBarImageSize = { 16, 16 }; HIMAGELIST ToolBarImageList = NULL; - +HFONT ToolStatusWindowFont = NULL; TBBUTTON ToolbarButtons[MAX_TOOLBAR_ITEMS] = { // Default toolbar buttons (displayed) @@ -56,7 +56,7 @@ VOID RebarBandInsert( { sizeof(REBARBANDINFO), RBBIM_STYLE | RBBIM_ID | RBBIM_CHILD | RBBIM_CHILDSIZE, - RBBS_USECHEVRON // RBBS_NOGRIPPER | RBBS_HIDETITLE | RBBS_TOPALIGN + RBBS_USECHEVRON | RBBS_VARIABLEHEIGHT // RBBS_NOGRIPPER | RBBS_HIDETITLE | RBBS_TOPALIGN }; rebarBandInfo.wID = BandID; @@ -132,7 +132,7 @@ VOID RebarLoadSettings( 0, TOOLBARCLASSNAME, NULL, - WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | CCS_NORESIZE | CCS_NOPARENTALIGN | CCS_NODIVIDER | TBSTYLE_FLAT | TBSTYLE_LIST | TBSTYLE_TRANSPARENT | TBSTYLE_TOOLTIPS | TBSTYLE_AUTOSIZE, + WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | CCS_NOPARENTALIGN | CCS_NODIVIDER | TBSTYLE_FLAT | TBSTYLE_LIST | TBSTYLE_TRANSPARENT | TBSTYLE_TOOLTIPS | TBSTYLE_AUTOSIZE, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, RebarHandle, NULL, @@ -196,6 +196,30 @@ VOID RebarLoadSettings( ); } + { + HFONT newFont; + + if (newFont = ToolStatusGetTreeWindowFont()) + { + if (ToolStatusWindowFont) + DeleteObject(ToolStatusWindowFont); + ToolStatusWindowFont = newFont; + + if (ToolBarHandle) + { + SendMessage(ToolBarHandle, WM_SETFONT, (WPARAM)ToolStatusWindowFont, FALSE); + SendMessage(ToolBarHandle, TB_AUTOSIZE, 0, 0); + //InvalidateRect(ToolBarHandle, NULL, TRUE); + } + + if (StatusBarHandle) + { + SendMessage(StatusBarHandle, WM_SETFONT, (WPARAM)ToolStatusWindowFont, FALSE); + InvalidateRect(StatusBarHandle, NULL, TRUE); + } + } + } + // Hide or show controls (Note: don't unload or remove at runtime). if (ToolStatusConfig.ToolBarEnabled) { diff --git a/plugins/ToolStatus/toolstatus.h b/plugins/ToolStatus/toolstatus.h index b5e370dcf73f..391f5a9cdeb3 100644 --- a/plugins/ToolStatus/toolstatus.h +++ b/plugins/ToolStatus/toolstatus.h @@ -217,6 +217,10 @@ HWND GetCurrentTreeNewHandle( VOID ); +HFONT ToolStatusGetTreeWindowFont( + VOID + ); + VOID ShowCustomizeMenu( VOID ); @@ -378,4 +382,8 @@ BOOLEAN CreateSearchboxControl( VOID ); +// +extern HFONT ToolStatusWindowFont; +#define PHAPP_WM_PLUGIN_UPDATE_FONT (WM_APP + 136) + #endif \ No newline at end of file From 5760f8abebe4d8329caaedfd9595ff6ce63890ee Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 22 Jul 2018 19:36:32 +1000 Subject: [PATCH 1166/2058] ToolStatus: Fix font cache --- plugins/ToolStatus/toolbar.c | 35 ++++++++++++++--------------------- 1 file changed, 14 insertions(+), 21 deletions(-) diff --git a/plugins/ToolStatus/toolbar.c b/plugins/ToolStatus/toolbar.c index 62d14bb5d49a..70719c1fd893 100644 --- a/plugins/ToolStatus/toolbar.c +++ b/plugins/ToolStatus/toolbar.c @@ -112,6 +112,15 @@ VOID RebarLoadSettings( ToolBarImageSize.cx = GetSystemMetrics(SM_CXSMICON); ToolBarImageSize.cy = GetSystemMetrics(SM_CYSMICON); ToolBarImageList = ImageList_Create(ToolBarImageSize.cx, ToolBarImageSize.cy, ILC_COLOR32, 0, 0); + + HFONT newFont; + + if (newFont = ToolStatusGetTreeWindowFont()) + { + if (ToolStatusWindowFont) + DeleteObject(ToolStatusWindowFont); + ToolStatusWindowFont = newFont; + } } if (ToolStatusConfig.ToolBarEnabled && !RebarHandle) @@ -150,6 +159,8 @@ VOID RebarLoadSettings( SendMessage(ToolBarHandle, TB_SETIMAGELIST, 0, (LPARAM)ToolBarImageList); // Add the buttons to the toolbar. ToolbarLoadButtonSettings(); + + SendMessage(ToolBarHandle, WM_SETFONT, (WPARAM)ToolStatusWindowFont, FALSE); // Resize the toolbar. SendMessage(ToolBarHandle, TB_AUTOSIZE, 0, 0); @@ -178,6 +189,7 @@ VOID RebarLoadSettings( )) { PhCreateSearchControl(RebarHandle, SearchboxHandle, L"Search Processes (Ctrl+K)"); + //SendMessage(SearchboxHandle, WM_SETFONT, (WPARAM)ToolStatusWindowFont, TRUE); } } @@ -194,29 +206,10 @@ VOID RebarLoadSettings( NULL, NULL ); - } - - { - HFONT newFont; - if (newFont = ToolStatusGetTreeWindowFont()) + if (StatusBarHandle) { - if (ToolStatusWindowFont) - DeleteObject(ToolStatusWindowFont); - ToolStatusWindowFont = newFont; - - if (ToolBarHandle) - { - SendMessage(ToolBarHandle, WM_SETFONT, (WPARAM)ToolStatusWindowFont, FALSE); - SendMessage(ToolBarHandle, TB_AUTOSIZE, 0, 0); - //InvalidateRect(ToolBarHandle, NULL, TRUE); - } - - if (StatusBarHandle) - { - SendMessage(StatusBarHandle, WM_SETFONT, (WPARAM)ToolStatusWindowFont, FALSE); - InvalidateRect(StatusBarHandle, NULL, TRUE); - } + SendMessage(StatusBarHandle, WM_SETFONT, (WPARAM)ToolStatusWindowFont, TRUE); } } From b6dc857d59fb4fdf302ee97dd86989082d7acb5b Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 22 Jul 2018 19:44:26 +1000 Subject: [PATCH 1167/2058] ToolStatus: Fix typo --- plugins/ToolStatus/toolbar.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/plugins/ToolStatus/toolbar.c b/plugins/ToolStatus/toolbar.c index 70719c1fd893..68c375b3226a 100644 --- a/plugins/ToolStatus/toolbar.c +++ b/plugins/ToolStatus/toolbar.c @@ -159,7 +159,6 @@ VOID RebarLoadSettings( SendMessage(ToolBarHandle, TB_SETIMAGELIST, 0, (LPARAM)ToolBarImageList); // Add the buttons to the toolbar. ToolbarLoadButtonSettings(); - SendMessage(ToolBarHandle, WM_SETFONT, (WPARAM)ToolStatusWindowFont, FALSE); // Resize the toolbar. SendMessage(ToolBarHandle, TB_AUTOSIZE, 0, 0); @@ -209,7 +208,7 @@ VOID RebarLoadSettings( if (StatusBarHandle) { - SendMessage(StatusBarHandle, WM_SETFONT, (WPARAM)ToolStatusWindowFont, TRUE); + SendMessage(StatusBarHandle, WM_SETFONT, (WPARAM)ToolStatusWindowFont, FALSE); } } From c9d0b9e1cfbf2b04575298cdf93bfa22f258f187 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 22 Jul 2018 20:06:10 +1000 Subject: [PATCH 1168/2058] Update sysinfo layout; Add graph mouseover highlighting --- ProcessHacker/ProcessHacker.rc | 3 - ProcessHacker/include/phplug.h | 65 ++++++++++++++++++- ProcessHacker/include/procprpp.h | 2 +- ProcessHacker/mainwnd.c | 3 + ProcessHacker/plugin.c | 100 +++++++++++++++++++++++++++++ ProcessHacker/sysinfo.c | 104 +++++++++++++------------------ 6 files changed, 210 insertions(+), 67 deletions(-) diff --git a/ProcessHacker/ProcessHacker.rc b/ProcessHacker/ProcessHacker.rc index abcb75c46c88..bb7842b24b90 100644 --- a/ProcessHacker/ProcessHacker.rc +++ b/ProcessHacker/ProcessHacker.rc @@ -1008,9 +1008,6 @@ EXSTYLE WS_EX_APPWINDOW CAPTION "System Information" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN - LTEXT "Click a graph to view details for that section.",IDC_INSTRUCTION,7,228,144,8 - CONTROL "Always on &top",IDC_ALWAYSONTOP,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,297,228,63,10 - DEFPUSHBUTTON "Close",IDOK,366,226,50,14 END IDD_EDITMESSAGE DIALOGEX 0, 0, 282, 163 diff --git a/ProcessHacker/include/phplug.h b/ProcessHacker/include/phplug.h index f2dfeafb67c7..c4534925df39 100644 --- a/ProcessHacker/include/phplug.h +++ b/ProcessHacker/include/phplug.h @@ -50,18 +50,17 @@ typedef enum _PH_GENERAL_CALLBACK GeneralCallbackProcessProviderModifiedEvent, // [process provider thread] GeneralCallbackProcessProviderRemovedEvent, // [process provider thread] GeneralCallbackProcessProviderUpdatedEvent, // [process provider thread] - GeneralCallbackServiceProviderAddedEvent, // [service provider thread] GeneralCallbackServiceProviderModifiedEvent, // [service provider thread] GeneralCallbackServiceProviderRemovedEvent, // [service provider thread] GeneralCallbackServiceProviderUpdatedEvent, // [service provider thread] - GeneralCallbackNetworkProviderAddedEvent, // [network provider thread] GeneralCallbackNetworkProviderModifiedEvent, // [network provider thread] GeneralCallbackNetworkProviderRemovedEvent, // [network provider thread] GeneralCallbackNetworkProviderUpdatedEvent, // [network provider thread] GeneralCallbackTrayIconsInitializing, + GeneralCallbackWindowNotifyEvent, GeneralCallbackMaximum } PH_GENERAL_CALLBACK, *PPH_GENERAL_CALLBACK; @@ -738,6 +737,68 @@ PhPluginCallPhSvc( _Out_writes_bytes_opt_(OutLength) PVOID OutBuffer, _In_ ULONG OutLength ); + +typedef enum _PH_PLUGIN_WINDOW_EVENT_TYPE +{ + PH_PLUGIN_WINDOW_EVENT_TYPE_NONE, + PH_PLUGIN_WINDOW_EVENT_TYPE_TOPMOST, + PH_PLUGIN_WINDOW_EVENT_TYPE_FONT, + PH_PLUGIN_WINDOW_EVENT_TYPE_MAX +} PH_PLUGIN_WINDOW_EVENT_TYPE; + +typedef struct _PH_PLUGIN_WINDOW_CALLBACK_REGISTRATION +{ + HWND WindowHandle; + PH_PLUGIN_WINDOW_EVENT_TYPE Type; + PH_CALLBACK_REGISTRATION Registration; +} PH_PLUGIN_WINDOW_CALLBACK_REGISTRATION, *PPH_PLUGIN_WINDOW_CALLBACK_REGISTRATION; + +typedef struct _PH_PLUGIN_WINDOW_NOTIFY_EVENT +{ + PH_PLUGIN_WINDOW_EVENT_TYPE Type; + union + { + BOOLEAN TopMost; + HFONT FontHandle; + }; +} PH_PLUGIN_WINDOW_NOTIFY_EVENT, *PPH_PLUGIN_WINDOW_NOTIFY_EVENT; + +typedef struct _PH_PLUGIN_MAINWINDOW_NOTIFY_EVENT +{ + PPH_PLUGIN_WINDOW_NOTIFY_EVENT Event; + PPH_PLUGIN_WINDOW_CALLBACK_REGISTRATION Callback; +} PH_PLUGIN_MAINWINDOW_NOTIFY_EVENT, *PPH_PLUGIN_MAINWINDOW_NOTIFY_EVENT; + +PHAPPAPI +PPH_PLUGIN_WINDOW_CALLBACK_REGISTRATION +NTAPI +PhRegisterWindowNotifyEvents( + _In_ HWND WindowHandle, + _In_ PH_PLUGIN_WINDOW_EVENT_TYPE Type + ); + +PHAPPAPI +VOID +NTAPI +PhUnregisterWindowNotifyEvents( + _In_ HWND WindowHandle, + _In_ PPH_PLUGIN_WINDOW_CALLBACK_REGISTRATION Callback + ); + +PHAPPAPI +VOID +NTAPI +PhWindowNotifyTopMostEvent( + _In_ BOOLEAN TopMost + ); + +PHAPPAPI +VOID +NTAPI +PhWindowNotifyFontUpdateEvent( + _In_ HFONT FontHandle + ); + // end_phapppub #endif diff --git a/ProcessHacker/include/procprpp.h b/ProcessHacker/include/procprpp.h index e9cd1484c987..7e0f8867d6c1 100644 --- a/ProcessHacker/include/procprpp.h +++ b/ProcessHacker/include/procprpp.h @@ -244,9 +244,9 @@ typedef struct _PH_MODULES_CONTEXT PH_PROVIDER_EVENT_QUEUE EventQueue; NTSTATUS LastRunStatus; PPH_STRING ErrorMessage; - PPH_STRING SearchboxText; PPH_TN_FILTER_ENTRY FilterEntry; + struct _PH_PLUGIN_WINDOW_CALLBACK_REGISTRATION *WindowCallback; // begin_phapppub } PH_MODULES_CONTEXT, *PPH_MODULES_CONTEXT; // end_phapppub diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index 5e51ce9767a9..07253e086ffe 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -771,6 +771,8 @@ VOID PhMwpOnCommand( SetWindowPos(PhMainWndHandle, AlwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE); PhSetIntegerSetting(L"MainWindowAlwaysOnTop", AlwaysOnTop); + + PhWindowNotifyTopMostEvent(AlwaysOnTop); } break; case ID_OPACITY_10: @@ -2057,6 +2059,7 @@ ULONG_PTR PhMwpOnUserMessage( CurrentCustomFont = newFont; PhMwpNotifyAllPages(MainTabPageFontChanged, newFont, NULL); + PhWindowNotifyFontUpdateEvent(newFont); } } } diff --git a/ProcessHacker/plugin.c b/ProcessHacker/plugin.c index 2974fc2018b1..f7cc3e01d0b7 100644 --- a/ProcessHacker/plugin.c +++ b/ProcessHacker/plugin.c @@ -1033,3 +1033,103 @@ NTSTATUS PhPluginCallPhSvc( return status; } + +static VOID PhPluginWindowNotifyEventCallback( + _In_opt_ PVOID Parameter, + _In_opt_ PVOID Context + ) +{ + PPH_PLUGIN_WINDOW_NOTIFY_EVENT Event = Parameter; + PPH_PLUGIN_WINDOW_CALLBACK_REGISTRATION callback = Context; + + switch (Event->Type) + { + case PH_PLUGIN_WINDOW_EVENT_TYPE_TOPMOST: + { + if (callback->Type != PH_PLUGIN_WINDOW_EVENT_TYPE_TOPMOST) + break; + + PhSetWindowAlwaysOnTop(callback->WindowHandle, Event->TopMost); + } + break; + case PH_PLUGIN_WINDOW_EVENT_TYPE_FONT: + { + if (callback->Type != PH_PLUGIN_WINDOW_EVENT_TYPE_FONT) + break; + + SendMessage(callback->WindowHandle, WM_SETFONT, (WPARAM)Event->FontHandle, TRUE); + } + break; + } +} + +PPH_PLUGIN_WINDOW_CALLBACK_REGISTRATION PhRegisterWindowNotifyEvents( + _In_ HWND WindowHandle, + _In_ PH_PLUGIN_WINDOW_EVENT_TYPE Type + ) +{ + PPH_PLUGIN_WINDOW_CALLBACK_REGISTRATION callback; + + callback = PhAllocateZero(sizeof(PH_PLUGIN_WINDOW_CALLBACK_REGISTRATION)); + callback->WindowHandle = WindowHandle; + callback->Type = Type; + + switch (Type) + { + case PH_PLUGIN_WINDOW_EVENT_TYPE_TOPMOST: + if (PhGetIntegerSetting(L"MainWindowAlwaysOnTop")) + PhSetWindowAlwaysOnTop(WindowHandle, TRUE); + break; + case PH_PLUGIN_WINDOW_EVENT_TYPE_FONT: + SendMessage(WindowHandle, WM_SETFONT, (WPARAM)PhTreeWindowFont, TRUE); + break; + } + + PhRegisterCallback( + PhGetGeneralCallback(GeneralCallbackWindowNotifyEvent), + PhPluginWindowNotifyEventCallback, + callback, + &callback->Registration + ); + + return callback; +} + +VOID PhUnregisterWindowNotifyEvents( + _In_ HWND WindowHandle, + _In_ PPH_PLUGIN_WINDOW_CALLBACK_REGISTRATION Callback + ) +{ + PhUnregisterCallback(PhGetGeneralCallback(GeneralCallbackWindowNotifyEvent), &Callback->Registration); + PhFree(Callback); +} + +VOID PhWindowNotifyTopMostEvent( + _In_ BOOLEAN TopMost + ) +{ + PPH_PLUGIN_WINDOW_NOTIFY_EVENT event; + + event = PhAllocateZero(sizeof(PH_PLUGIN_WINDOW_NOTIFY_EVENT)); + event->Type = PH_PLUGIN_WINDOW_EVENT_TYPE_TOPMOST; + event->TopMost = TopMost; + + PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackWindowNotifyEvent), event); + + PhFree(event); +} + +VOID PhWindowNotifyFontUpdateEvent( + _In_ HFONT FontHandle + ) +{ + PPH_PLUGIN_WINDOW_NOTIFY_EVENT event; + + event = PhAllocateZero(sizeof(PH_PLUGIN_WINDOW_NOTIFY_EVENT)); + event->Type = PH_PLUGIN_WINDOW_EVENT_TYPE_FONT; + event->FontHandle = FontHandle; + + PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackWindowNotifyEvent), event); + + PhFree(event); +} diff --git a/ProcessHacker/sysinfo.c b/ProcessHacker/sysinfo.c index e367d4b8e9ae..4312233ed204 100644 --- a/ProcessHacker/sysinfo.c +++ b/ProcessHacker/sysinfo.c @@ -64,9 +64,9 @@ HWND PhSipWindow = NULL; static PPH_LIST PhSipDialogList = NULL; static PH_EVENT InitializedEvent = PH_EVENT_INIT; static PWSTR InitialSectionName; -static PH_LAYOUT_MANAGER WindowLayoutManager; static RECT MinimumSize; static PH_CALLBACK_REGISTRATION ProcessesUpdatedRegistration; +static PPH_PLUGIN_WINDOW_CALLBACK_REGISTRATION WindowEventsRegistration = NULL; static PPH_LIST SectionList; static PH_SYSINFO_PARAMETERS CurrentParameters; @@ -78,12 +78,9 @@ static HWND RestoreSummaryControl; static WNDPROC RestoreSummaryControlOldWndProc; static BOOLEAN RestoreSummaryControlHot; static BOOLEAN RestoreSummaryControlHasFocus; - static HTHEME ThemeData; static BOOLEAN ThemeHasItemBackground; -static BOOLEAN AlwaysOnTop; - VOID PhShowSystemInformationDialog( _In_opt_ PWSTR SectionName ) @@ -285,12 +282,6 @@ VOID PhSipOnInitDialog( SendMessage(PhSipWindow, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER))); SendMessage(PhSipWindow, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER))); - PhInitializeLayoutManager(&WindowLayoutManager, PhSipWindow); - - PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(PhSipWindow, IDC_INSTRUCTION), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_BOTTOM); - PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(PhSipWindow, IDC_ALWAYSONTOP), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); - PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(PhSipWindow, IDOK), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); - PhRegisterCallback( PhGetGeneralCallback(GeneralCallbackProcessProviderUpdatedEvent), PhSipSysInfoUpdateHandler, @@ -314,18 +305,14 @@ VOID PhSipOnDestroy( VOID ) { - PhUnregisterCallback( - PhGetGeneralCallback(GeneralCallbackProcessProviderUpdatedEvent), - &ProcessesUpdatedRegistration - ); + PhUnregisterCallback(PhGetGeneralCallback(GeneralCallbackProcessProviderUpdatedEvent), &ProcessesUpdatedRegistration); + PhUnregisterWindowNotifyEvents(PhSipWindow, WindowEventsRegistration); if (CurrentSection) PhSetStringSetting2(L"SysInfoWindowSection", &CurrentSection->Name); else PhSetStringSetting(L"SysInfoWindowSection", L""); - PhSetIntegerSetting(L"SysInfoWindowAlwaysOnTop", AlwaysOnTop); - PhSaveWindowPlacementToSetting(L"SysInfoWindowPosition", L"SysInfoWindowSize", PhSipWindow); PhSipSaveWindowState(); } @@ -353,7 +340,6 @@ VOID PhSipOnNcDestroy( ThemeData = NULL; } - PhDeleteLayoutManager(&WindowLayoutManager); PostQuitMessage(0); } @@ -362,7 +348,7 @@ VOID PhSipOnShowWindow( _In_ ULONG State ) { - RECT buttonRect; + //RECT buttonRect; RECT clientRect; PH_STRINGREF sectionName; PPH_SYSINFO_SECTION section; @@ -425,10 +411,7 @@ VOID PhSipOnShowWindow( EnableThemeDialogTexture(ContainerControl, ETDT_ENABLETAB); - GetWindowRect(GetDlgItem(PhSipWindow, IDOK), &buttonRect); - MapWindowPoints(NULL, PhSipWindow, (POINT *)&buttonRect, 2); GetClientRect(PhSipWindow, &clientRect); - MinimumSize.left = 0; MinimumSize.top = 0; MinimumSize.right = 430; @@ -441,20 +424,20 @@ VOID PhSipOnShowWindow( if (SectionList->Count != 0) { - ULONG newMinimumHeight; - - newMinimumHeight = - GetSystemMetrics(SM_CYCAPTION) + - CurrentParameters.WindowPadding + - CurrentParameters.MinimumGraphHeight * SectionList->Count + - CurrentParameters.MinimumGraphHeight + // Back button - CurrentParameters.GraphPadding * SectionList->Count + - CurrentParameters.WindowPadding + - clientRect.bottom - buttonRect.top + - GetSystemMetrics(SM_CYFRAME) * 2; - - if (newMinimumHeight > (ULONG)MinimumSize.bottom) - MinimumSize.bottom = newMinimumHeight; + //ULONG newMinimumHeight; + // + //newMinimumHeight = + // GetSystemMetrics(SM_CYCAPTION) + + // CurrentParameters.WindowPadding + + // CurrentParameters.MinimumGraphHeight * SectionList->Count + + // CurrentParameters.MinimumGraphHeight + // Back button + // CurrentParameters.GraphPadding * SectionList->Count + + // CurrentParameters.WindowPadding + + // clientRect.bottom - buttonRect.top + + // GetSystemMetrics(SM_CYFRAME) * 2; + // + //if (newMinimumHeight > (ULONG)MinimumSize.bottom) + // MinimumSize.bottom = newMinimumHeight; } PhLoadWindowPlacementFromSetting(L"SysInfoWindowPosition", L"SysInfoWindowSize", PhSipWindow); @@ -472,9 +455,9 @@ VOID PhSipOnShowWindow( PhSipEnterSectionView(section); } - AlwaysOnTop = !!PhGetIntegerSetting(L"SysInfoWindowAlwaysOnTop"); - Button_SetCheck(GetDlgItem(PhSipWindow, IDC_ALWAYSONTOP), AlwaysOnTop ? BST_CHECKED : BST_UNCHECKED); - PhSetWindowAlwaysOnTop(PhSipWindow, AlwaysOnTop); + if (PhGetIntegerSetting(L"MainWindowAlwaysOnTop")) + PhSetWindowAlwaysOnTop(PhSipWindow, TRUE); + WindowEventsRegistration = PhRegisterWindowNotifyEvents(PhSipWindow, PH_PLUGIN_WINDOW_EVENT_TYPE_TOPMOST); PhSipOnSize(); PhSipOnUserMessage(SI_MSG_SYSINFO_UPDATE, 0, 0); @@ -503,8 +486,6 @@ VOID PhSipOnSize( VOID ) { - PhLayoutManagerLayout(&WindowLayoutManager); - if (SectionList && SectionList->Count != 0) { if (CurrentView == SysInfoSummaryView) @@ -537,16 +518,8 @@ VOID PhSipOnCommand( switch (Id) { case IDCANCEL: - case IDOK: DestroyWindow(PhSipWindow); break; - case IDC_ALWAYSONTOP: - { - AlwaysOnTop = Button_GetCheck(GetDlgItem(PhSipWindow, IDC_ALWAYSONTOP)) == BST_CHECKED; - PhSetIntegerSetting(L"SysInfoWindowAlwaysOnTop", AlwaysOnTop); - PhSetWindowAlwaysOnTop(PhSipWindow, AlwaysOnTop); - } - break; case IDC_RESET: { if (Code == STN_CLICKED) @@ -1311,7 +1284,21 @@ VOID PhSipDefaultDrawPanel( if (ThemeHasItemBackground) { - if (CurrentView == SysInfoSectionView) + if (CurrentView == SysInfoSummaryView) + { + if (Section->GraphHot) + { + DrawThemeBackground( + ThemeData, + hdc, + TVP_TREEITEM, + TREIS_HOT, + &DrawPanel->Rect, + &DrawPanel->Rect + ); + } + } + else if (CurrentView == SysInfoSectionView) { INT stateId; @@ -1482,7 +1469,6 @@ VOID PhSipLayoutSummaryView( VOID ) { - RECT buttonRect; RECT clientRect; ULONG availableHeight; ULONG availableWidth; @@ -1492,11 +1478,9 @@ VOID PhSipLayoutSummaryView( HDWP deferHandle; ULONG y; - GetWindowRect(GetDlgItem(PhSipWindow, IDOK), &buttonRect); - MapWindowPoints(NULL, PhSipWindow, (POINT *)&buttonRect, 2); GetClientRect(PhSipWindow, &clientRect); - availableHeight = buttonRect.top - CurrentParameters.WindowPadding * 2; + availableHeight = clientRect.bottom - CurrentParameters.WindowPadding * 2; availableWidth = clientRect.right - CurrentParameters.WindowPadding * 2; graphHeight = (availableHeight - CurrentParameters.GraphPadding * (SectionList->Count - 1)) / SectionList->Count; @@ -1529,7 +1513,6 @@ VOID PhSipLayoutSectionView( VOID ) { - RECT buttonRect; RECT clientRect; ULONG availableHeight; ULONG availableWidth; @@ -1540,11 +1523,9 @@ VOID PhSipLayoutSectionView( ULONG y; ULONG containerLeft; - GetWindowRect(GetDlgItem(PhSipWindow, IDOK), &buttonRect); - MapWindowPoints(NULL, PhSipWindow, (POINT *)&buttonRect, 2); GetClientRect(PhSipWindow, &clientRect); - availableHeight = buttonRect.top - CurrentParameters.WindowPadding * 2; + availableHeight = clientRect.bottom - CurrentParameters.WindowPadding * 2; availableWidth = clientRect.right - CurrentParameters.WindowPadding * 2; graphHeight = (availableHeight - CurrentParameters.SmallGraphPadding * SectionList->Count) / (SectionList->Count + 1); @@ -1656,7 +1637,7 @@ VOID PhSipEnterSectionView( oldSection = CurrentSection; CurrentSection = NewSection; - deferHandle = BeginDeferWindowPos(SectionList->Count + 4); + deferHandle = BeginDeferWindowPos(SectionList->Count + 3); containerDeferHandle = BeginDeferWindowPos(SectionList->Count); PhSipEnterSectionViewInner(NewSection, fromSummaryView, &deferHandle, &containerDeferHandle); @@ -1673,7 +1654,6 @@ VOID PhSipEnterSectionView( deferHandle = DeferWindowPos(deferHandle, ContainerControl, NULL, 0, 0, 0, 0, SWP_SHOWWINDOW_ONLY); deferHandle = DeferWindowPos(deferHandle, RestoreSummaryControl, NULL, 0, 0, 0, 0, SWP_SHOWWINDOW_ONLY); deferHandle = DeferWindowPos(deferHandle, SeparatorControl, NULL, 0, 0, 0, 0, SWP_SHOWWINDOW_ONLY); - deferHandle = DeferWindowPos(deferHandle, GetDlgItem(PhSipWindow, IDC_INSTRUCTION), NULL, 0, 0, 0, 0, SWP_HIDEWINDOW_ONLY); EndDeferWindowPos(deferHandle); EndDeferWindowPos(containerDeferHandle); @@ -1744,7 +1724,6 @@ VOID PhSipRestoreSummaryView( ShowWindow(ContainerControl, SW_HIDE); ShowWindow(RestoreSummaryControl, SW_HIDE); ShowWindow(SeparatorControl, SW_HIDE); - ShowWindow(GetDlgItem(PhSipWindow, IDC_INSTRUCTION), SW_SHOW); PhSipLayoutSummaryView(); } @@ -1876,12 +1855,15 @@ LRESULT CALLBACK PhSipGraphHookWndProc( if (!(section->GraphHot || section->PanelHot)) { section->GraphHot = TRUE; - InvalidateRect(section->PanelHandle, NULL, TRUE); } else { section->GraphHot = TRUE; } + + Graph_Draw(section->GraphHandle); + InvalidateRect(section->GraphHandle, NULL, TRUE); + InvalidateRect(section->PanelHandle, NULL, TRUE); } break; case WM_MOUSELEAVE: From 82ab3b45a4e1e406051b8dc0a625800b13c32ee4 Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 22 Jul 2018 20:10:54 +1000 Subject: [PATCH 1169/2058] Update font caching --- ProcessHacker/include/phapp.h | 1 + ProcessHacker/main.c | 1 + ProcessHacker/mainwnd.c | 11 +++++------ 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/ProcessHacker/include/phapp.h b/ProcessHacker/include/phapp.h index ba5565440715..d83a9a33eb08 100644 --- a/ProcessHacker/include/phapp.h +++ b/ProcessHacker/include/phapp.h @@ -73,6 +73,7 @@ typedef struct _PH_STARTUP_PARAMETERS } PH_STARTUP_PARAMETERS, *PPH_STARTUP_PARAMETERS; PHAPPAPI extern HFONT PhApplicationFont; // phapppub +PHAPPAPI extern HFONT PhTreeWindowFont; // phapppub extern BOOLEAN PhPluginsEnabled; extern PPH_STRING PhSettingsFileName; extern PH_INTEGER_PAIR PhSmallIconSize; diff --git a/ProcessHacker/main.c b/ProcessHacker/main.c index 3650ae5877f3..76832da39670 100644 --- a/ProcessHacker/main.c +++ b/ProcessHacker/main.c @@ -89,6 +89,7 @@ BOOLEAN PhInitializeMitigationPolicy( ); PHAPPAPI HFONT PhApplicationFont = NULL; +PHAPPAPI HFONT PhTreeWindowFont = NULL; BOOLEAN PhPluginsEnabled = FALSE; PPH_STRING PhSettingsFileName = NULL; PH_INTEGER_PAIR PhSmallIconSize = { 16, 16 }; diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index 07253e086ffe..d40ced9e0be8 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -85,7 +85,6 @@ static HWND TabControlHandle; static PPH_LIST PageList; static PPH_MAIN_TAB_PAGE CurrentPage; static INT OldTabIndex; -static HFONT CurrentCustomFont; static HMENU SubMenuHandles[5]; static PPH_EMENU SubMenuObjects[5]; @@ -2054,9 +2053,9 @@ ULONG_PTR PhMwpOnUserMessage( if (newFont) { - if (CurrentCustomFont) - DeleteObject(CurrentCustomFont); - CurrentCustomFont = newFont; + if (PhTreeWindowFont) + DeleteObject(PhTreeWindowFont); + PhTreeWindowFont = newFont; PhMwpNotifyAllPages(MainTabPageFontChanged, newFont, NULL); PhWindowNotifyFontUpdateEvent(newFont); @@ -2685,8 +2684,8 @@ VOID PhMwpSelectionChangedTabControl( if (page->WindowHandle) BringWindowToTop(page->WindowHandle); - if (CurrentCustomFont) - page->Callback(page, MainTabPageFontChanged, CurrentCustomFont, NULL); + if (PhTreeWindowFont) + page->Callback(page, MainTabPageFontChanged, PhTreeWindowFont, NULL); } page->Callback(page, MainTabPageSelected, (PVOID)TRUE, NULL); From 3ff417354d9aae105e5cc942645933a07039000c Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 22 Jul 2018 20:37:05 +1000 Subject: [PATCH 1170/2058] Fix options window fonts --- ProcessHacker/options.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/ProcessHacker/options.c b/ProcessHacker/options.c index c0dc87fa6bb4..06d00e221eba 100644 --- a/ProcessHacker/options.c +++ b/ProcessHacker/options.c @@ -1208,7 +1208,11 @@ INT_PTR CALLBACK PhpOptionsGeneralDlgProc( CurrentFontInstance = CreateFontIndirect(&font); if (CurrentFontInstance) + { + SendMessage(OptionsTreeControl, WM_SETFONT, (WPARAM)CurrentFontInstance, TRUE); // HACK + SendMessage(listviewHandle, WM_SETFONT, (WPARAM)CurrentFontInstance, TRUE); SendMessage(GetDlgItem(hwndDlg, IDC_FONT), WM_SETFONT, (WPARAM)CurrentFontInstance, TRUE); + } } PhpAdvancedPageLoad(hwndDlg); @@ -1270,7 +1274,11 @@ INT_PTR CALLBACK PhpOptionsGeneralDlgProc( DeleteObject(CurrentFontInstance); CurrentFontInstance = CreateFontIndirect(&font); + + SendMessage(OptionsTreeControl, WM_SETFONT, (WPARAM)CurrentFontInstance, TRUE); // HACK + SendMessage(GetDlgItem(hwndDlg, IDC_SETTINGS), WM_SETFONT, (WPARAM)CurrentFontInstance, TRUE); SendMessage(GetDlgItem(hwndDlg, IDC_FONT), WM_SETFONT, (WPARAM)CurrentFontInstance, TRUE); + RestartRequired = TRUE; // HACK: Fix ToolStatus plugin toolbar resize on font change } } break; From 94075f7db37645bce0799e4034f811b91ccc7e5b Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 22 Jul 2018 21:12:34 +1000 Subject: [PATCH 1171/2058] Update appveyor build format --- appveyor.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index fcbc818fe0f8..c71e48f79d57 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -2,7 +2,7 @@ image: Visual Studio 2017 # Version format. -version: "3.0.{build}" +version: "#{build}" # Only build the master branch. branches: @@ -15,10 +15,10 @@ pull_requests: # Do not start a new build when a new Git tag is created. skip_tags: true - + # Set the clone directory on the buildbot. clone_folder: C:\projects\processhacker - + # Immediately finish build if something fails. matrix: fast_finish: true @@ -28,4 +28,4 @@ test: off # Run custom build script. build_script: -- cmd: tools\CustomBuildTool\bin\Release\CustomBuildTool.exe -appveyor \ No newline at end of file +- cmd: tools\CustomBuildTool\bin\Release\CustomBuildTool.exe -appveyor From 7a04a4a48f26c3e68938a898965c65564efc0103 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 23 Jul 2018 12:49:17 +1000 Subject: [PATCH 1172/2058] peview: skip empty exports --- tools/peview/expprp.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tools/peview/expprp.c b/tools/peview/expprp.c index e37d38df8a4e..bcf48bde8d20 100644 --- a/tools/peview/expprp.c +++ b/tools/peview/expprp.c @@ -70,6 +70,10 @@ INT_PTR CALLBACK PvpPeExportsDlgProc( WCHAR number[PH_INT32_STR_LEN_1]; WCHAR pointer[PH_PTR_STR_LEN_1]; + // HACK: Skip exports with an empty RVA (TODO: make optional) -dmex + if (!exportFunction.Function) + continue; + PhPrintUInt64(number, i + 1); lvItemIndex = PhAddListViewItem(lvHandle, MAXINT, number, NULL); From 81a4f5726468379bb5b3d233e240187e6f33fe65 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 23 Jul 2018 14:06:02 +1000 Subject: [PATCH 1173/2058] HardwareDevices: Add fmifs.h header --- plugins/HardwareDevices/fmifs.h | 455 ++++++++++++++++++++++++++++++++ 1 file changed, 455 insertions(+) create mode 100644 plugins/HardwareDevices/fmifs.h diff --git a/plugins/HardwareDevices/fmifs.h b/plugins/HardwareDevices/fmifs.h new file mode 100644 index 000000000000..bd42899e7d3b --- /dev/null +++ b/plugins/HardwareDevices/fmifs.h @@ -0,0 +1,455 @@ +/******************************************************************** + + fmifs.h + + This header file contains the specification of the interface + between the file manager and fmifs.dll for the purposes of + accomplishing IFS functions. + + Copyright (c) Microsoft Corporation. All rights reserved. + Licensed under the MIT License. + +********************************************************************/ + +#if !defined(_FMIFS_DEFN_) +#define _FMIFS_DEFN_ + +// +// These are the defines for 'PacketType'. +// +typedef enum _FMIFS_PACKET_TYPE +{ + FmIfsPercentCompleted, + FmIfsFormatReport, + FmIfsInsertDisk, + FmIfsIncompatibleFileSystem, + FmIfsFormattingDestination, + FmIfsIncompatibleMedia, + FmIfsAccessDenied, + FmIfsMediaWriteProtected, + FmIfsCantLock, + FmIfsCantQuickFormat, + FmIfsIoError, + FmIfsFinished, + FmIfsBadLabel, +#if defined(DBLSPACE_ENABLED) + FmIfsDblspaceCreateFailed, + FmIfsDblspaceMountFailed, + FmIfsDblspaceDriveLetterFailed, + FmIfsDblspaceCreated, + FmIfsDblspaceMounted, +#endif + FmIfsCheckOnReboot, + FmIfsTextMessage, + FmIfsHiddenStatus +} FMIFS_PACKET_TYPE, *PFMIFS_PACKET_TYPE; + +typedef struct _FMIFS_PERCENT_COMPLETE_INFORMATION +{ + ULONG PercentCompleted; +} FMIFS_PERCENT_COMPLETE_INFORMATION, *PFMIFS_PERCENT_COMPLETE_INFORMATION; + +typedef struct _FMIFS_FORMAT_REPORT_INFORMATION +{ + ULONG KiloBytesTotalDiskSpace; + ULONG KiloBytesAvailable; +} FMIFS_FORMAT_REPORT_INFORMATION, *PFMIFS_FORMAT_REPORT_INFORMATION; + +// The packet for FmIfsDblspaceCreated is a Unicode string +// giving the name of the Compressed Volume File; it is not +// necessarily zero-terminated. +#define DISK_TYPE_GENERIC 0 +#define DISK_TYPE_SOURCE 1 +#define DISK_TYPE_TARGET 2 +#define DISK_TYPE_SOURCE_AND_TARGET 3 + +typedef struct _FMIFS_INSERT_DISK_INFORMATION +{ + ULONG DiskType; +} FMIFS_INSERT_DISK_INFORMATION, *PFMIFS_INSERT_DISK_INFORMATION; + +typedef struct _FMIFS_IO_ERROR_INFORMATION +{ + ULONG DiskType; + ULONG Head; + ULONG Track; +} FMIFS_IO_ERROR_INFORMATION, *PFMIFS_IO_ERROR_INFORMATION; + +typedef struct _FMIFS_FINISHED_INFORMATION +{ + BOOLEAN Success; +} FMIFS_FINISHED_INFORMATION, *PFMIFS_FINISHED_INFORMATION; + +typedef struct _FMIFS_CHECKONREBOOT_INFORMATION +{ + _Out_ BOOLEAN QueryResult; // TRUE for "yes", FALSE for "no" +} FMIFS_CHECKONREBOOT_INFORMATION, *PFMIFS_CHECKONREBOOT_INFORMATION; + +typedef enum _TEXT_MESSAGE_TYPE +{ + MESSAGE_TYPE_PROGRESS, + MESSAGE_TYPE_RESULTS, + MESSAGE_TYPE_FINAL +} TEXT_MESSAGE_TYPE, *PTEXT_MESSAGE_TYPE; + +typedef struct _FMIFS_TEXT_MESSAGE +{ + _In_ TEXT_MESSAGE_TYPE MessageType; + _In_ PSTR Message; +} FMIFS_TEXT_MESSAGE, *PFMIFS_TEXT_MESSAGE; + +// This is a list of supported floppy media types for format. +typedef enum _FMIFS_MEDIA_TYPE +{ + FmMediaUnknown, + FmMediaF5_160_512, // 5.25", 160KB, 512 bytes/sector + FmMediaF5_180_512, // 5.25", 180KB, 512 bytes/sector + FmMediaF5_320_512, // 5.25", 320KB, 512 bytes/sector + FmMediaF5_320_1024, // 5.25", 320KB, 1024 bytes/sector + FmMediaF5_360_512, // 5.25", 360KB, 512 bytes/sector + FmMediaF3_720_512, // 3.5", 720KB, 512 bytes/sector + FmMediaF5_1Pt2_512, // 5.25", 1.2MB, 512 bytes/sector + FmMediaF3_1Pt44_512, // 3.5", 1.44MB, 512 bytes/sector + FmMediaF3_2Pt88_512, // 3.5", 2.88MB, 512 bytes/sector + FmMediaF3_20Pt8_512, // 3.5", 20.8MB, 512 bytes/sector + FmMediaRemovable, // Removable media other than floppy + FmMediaFixed, + FmMediaF3_120M_512 // 3.5", 120M Floppy +} FMIFS_MEDIA_TYPE, *PFMIFS_MEDIA_TYPE; + +// +// The structure below defines information to be passed into ChkdskEx. +// When new fields are added, the version number will have to be upgraded +// so that only new code will reference those new fields. +// +typedef struct +{ + UCHAR Major; // initial version is 1.0 + UCHAR Minor; + ULONG Flags; + PWSTR PathToCheck; +} FMIFS_CHKDSKEX_PARAM, *PFMIFS_CHKDSKEX_PARAM; + +// +// Internal definitions for Flags field in FMIFS_CHKDSKEX_PARAM +// +#define FMIFS_CHKDSK_RECOVER_FREE_SPACE 0x00000002UL +#define FMIFS_CHKDSK_RECOVER_ALLOC_SPACE 0x00000004UL + +// +// External definitions for Flags field in FMIFS_CHKDSKEX_PARAM +// +// FMIFS_CHKDSK_VERBOSE +// - For FAT, chkdsk will print every filename being processed +// - For NTFS, chkdsk will print clean up messages +// FMIFS_CHKDSK_RECOVER +// - Perform sector checking on free and allocated space +// FMIFS_CHKDSK_EXTEND +// - For NTFS, chkdsk will extend a volume +// FMIFS_CHKDSK_DOWNGRADE (for NT 5 or later but obsolete anyway) +// - For NTFS, this downgrade a volume from most recent NTFS version +// FMIFS_CHKDSK_ENABLE_UPGRADE (for NT 5 or later but obsolete anyway) +// - For NTFS, this upgrades a volume to most recent NTFS version +// FMIFS_CHKDSK_CHECK_IF_DIRTY +// - Perform consistency check only if the volume is dirty +// FMIFS_CHKDSK_FORCE (for NT 5 or later) +// - Forces the volume to dismount first if necessary +// FMIFS_CHKDSK_SKIP_INDEX_SCAN +// - Skip the scanning of each index entry +// FMIFS_CHKDSK_SKIP_CYCLE_SCAN +// - Skip the checking of cycles within the directory tree +// +#define FMIFS_CHKDSK_VERBOSE 0x00000001UL +#define FMIFS_CHKDSK_RECOVER (FMIFS_CHKDSK_RECOVER_FREE_SPACE | FMIFS_CHKDSK_RECOVER_ALLOC_SPACE) +#define FMIFS_CHKDSK_EXTEND 0x00000008UL +#define FMIFS_CHKDSK_DOWNGRADE 0x00000010UL +#define FMIFS_CHKDSK_ENABLE_UPGRADE 0x00000020UL +#define FMIFS_CHKDSK_CHECK_IF_DIRTY 0x00000080UL +#define FMIFS_CHKDSK_FORCE 0x00000100UL +#define FMIFS_CHKDSK_SKIP_INDEX_SCAN 0x00000200UL +#define FMIFS_CHKDSK_SKIP_CYCLE_SCAN 0x00000400UL + +// Function types/interfaces. + +typedef BOOLEAN (NTAPI *FMIFS_CALLBACK)( + _In_ FMIFS_PACKET_TYPE PacketType, + _In_ ULONG PacketLength, + _In_ PVOID PacketData + ); + +typedef VOID (NTAPI *PFMIFS_FORMAT_ROUTINE)( + _In_ PWSTR DriveName, + _In_ FMIFS_MEDIA_TYPE MediaType, + _In_ PWSTR FileSystemName, + _In_ PWSTR Label, + _In_ BOOLEAN Quick, + _In_ FMIFS_CALLBACK Callback + ); + +typedef VOID (NTAPI *PFMIFS_FORMATEX_ROUTINE)( + _In_ PWSTR DriveName, + _In_ FMIFS_MEDIA_TYPE MediaType, + _In_ PWSTR FileSystemName, + _In_ PWSTR Label, + _In_ BOOLEAN Quick, + _In_ ULONG ClusterSize, + _In_ FMIFS_CALLBACK Callback + ); + +typedef BOOLEAN (NTAPI *PFMIFS_ENABLECOMP_ROUTINE)( + _In_ PWSTR DriveName, + _In_ USHORT CompressionFormat + ); + +typedef VOID (NTAPI *PFMIFS_CHKDSK_ROUTINE)( + _In_ PWSTR DriveName, + _In_ PWSTR FileSystemName, + _In_ BOOLEAN FixErrors, + _In_ BOOLEAN Verbose, + _In_ BOOLEAN OnlyIfDirty, + _In_ BOOLEAN Recover, + _In_ PWSTR PathToCheck, + _In_ BOOLEAN Extend, + _In_ FMIFS_CALLBACK Callback + ); + +typedef VOID (NTAPI *PFMIFS_CHKDSKEX_ROUTINE)( + _In_ PWSTR DriveName, + _In_ PWSTR FileSystemName, + _In_ BOOLEAN FixErrors, + _In_ PFMIFS_CHKDSKEX_PARAM Param, + _In_ FMIFS_CALLBACK Callback + ); + +typedef VOID (NTAPI *PFMIFS_EXTEND_ROUTINE)( + _In_ PWSTR DriveName, + _In_ BOOLEAN Verify, + _In_ FMIFS_CALLBACK Callback + ); + +typedef VOID (NTAPI *PFMIFS_DISKCOPY_ROUTINE)( + _In_ PWSTR SourceDrive, + _In_ PWSTR DestDrive, + _In_ BOOLEAN Verify, + _In_ FMIFS_CALLBACK Callback + ); + +typedef BOOLEAN (NTAPI *PFMIFS_SETLABEL_ROUTINE)( + _In_ PWSTR DriveName, + _In_ PWSTR Label + ); + +typedef BOOLEAN (NTAPI *PFMIFS_QSUPMEDIA_ROUTINE)( + _In_ PWSTR DriveName, + _Out_opt_ PFMIFS_MEDIA_TYPE MediaTypeArray, + _In_ ULONG NumberOfArrayEntries, + _Out_ PULONG NumberOfMediaTypes + ); + +#if defined(DBLSPACE_ENABLED) +typedef VOID (NTAPI *PFMIFS_DOUBLESPACE_CREATE_ROUTINE)( + _In_ PWSTR HostDriveName, + _In_ ULONG Size, + _In_ PWSTR Label, + _In_ PWSTR NewDriveName, + _In_ FMIFS_CALLBACK Callback + ); + +typedef VOID (NTAPI *PFMIFS_DOUBLESPACE_DELETE_ROUTINE)( + _In_ PWSTR DblspaceDriveName, + _In_ FMIFS_CALLBACK Callback + ); + +typedef VOID (NTAPI *PFMIFS_DOUBLESPACE_MOUNT_ROUTINE)( + _In_ PWSTR HostDriveName, + _In_ PWSTR CvfName, + _In_ PWSTR NewDriveName, + _In_ FMIFS_CALLBACK Callback + ); + +typedef VOID (NTAPI *PFMIFS_DOUBLESPACE_DISMOUNT_ROUTINE)( + _In_ PWSTR DblspaceDriveName, + _In_ FMIFS_CALLBACK Callback + ); + +typedef BOOLEAN (NTAPI *PFMIFS_DOUBLESPACE_QUERY_INFO_ROUTINE)( + _In_ PWSTR DosDriveName, + _Out_ PBOOLEAN IsRemovable, + _Out_ PBOOLEAN IsFloppy, + _Out_ PBOOLEAN IsCompressed, + _Out_ PBOOLEAN Error, + _Out_ PWSTR NtDriveName, + _In_ ULONG MaxNtDriveNameLength, + _Out_ PWSTR CvfFileName, + _In_ ULONG MaxCvfFileNameLength, + _Out_ PWSTR HostDriveName, + _In_ ULONG MaxHostDriveNameLength + ); + +typedef BOOLEAN (NTAPI *PFMIFS_DOUBLESPACE_SET_AUTMOUNT_ROUTINE)( + _In_ BOOLEAN EnableAutomount + ); +#endif // DBLSPACE_ENABLED + +NTSYSAPI +VOID +NTAPI +Format( + _In_ PWSTR DriveName, + _In_ FMIFS_MEDIA_TYPE MediaType, + _In_ PWSTR FileSystemName, + _In_ PWSTR Label, + _In_ BOOLEAN Quick, + _In_ FMIFS_CALLBACK Callback + ); + +NTSYSAPI +VOID +NTAPI +FormatEx( + _In_ PWSTR DriveName, + _In_ FMIFS_MEDIA_TYPE MediaType, + _In_ PWSTR FileSystemName, + _In_ PWSTR Label, + _In_ BOOLEAN Quick, + _In_ ULONG ClusterSize, + _In_ FMIFS_CALLBACK Callback + ); + +NTSYSAPI +BOOLEAN +NTAPI +EnableVolumeCompression( + _In_ PWSTR DriveName, + _In_ USHORT CompressionFormat + ); + +NTSYSAPI +VOID +NTAPI +Chkdsk( + _In_ PWSTR DriveName, + _In_ PWSTR FileSystemName, + _In_ BOOLEAN FixErrors, + _In_ BOOLEAN Verbose, + _In_ BOOLEAN OnlyIfDirty, + _In_ BOOLEAN Recover, + _In_ PWSTR PathToCheck, + _In_ BOOLEAN Extend, + _In_ FMIFS_CALLBACK Callback + ); + +NTSYSAPI +VOID +NTAPI +ChkdskEx( + _In_ PWSTR DriveName, + _In_ PWSTR FileSystemName, + _In_ BOOLEAN FixErrors, + _In_ PFMIFS_CHKDSKEX_PARAM Param, + _In_ FMIFS_CALLBACK Callback + ); + +NTSYSAPI +VOID +NTAPI +Extend( + _In_ PWSTR DriveName, + _In_ BOOLEAN Verify, + _In_ FMIFS_CALLBACK Callback + ); + +NTSYSAPI +VOID +NTAPI +DiskCopy( + _In_ PWSTR SourceDrive, + _In_ PWSTR DestDrive, + _In_ BOOLEAN Verify, + _In_ FMIFS_CALLBACK Callback + ); + +NTSYSAPI +BOOLEAN +NTAPI +SetLabel( + _In_ PWSTR DriveName, + _In_ PWSTR Label + ); + +NTSYSAPI +BOOLEAN +NTAPI +QuerySupportedMedia( + _In_ PWSTR DriveName, + _Out_opt_ PFMIFS_MEDIA_TYPE MediaTypeArray, + _In_ ULONG NumberOfArrayEntries, + _Out_ PULONG NumberOfMediaTypes + ); + +#if defined(DBLSPACE_ENABLED) +NTSYSAPI +VOID +NTAPI +DoubleSpaceCreate( + _In_ PWSTR HostDriveName, + _In_ ULONG Size, + _In_ PWSTR Label, + _In_ PWSTR NewDriveName, + _In_ FMIFS_CALLBACK Callback + ); + +NTSYSAPI +VOID +NTAPI +DoubleSpaceDelete( + _In_ PWSTR DblspaceDriveName, + _In_ FMIFS_CALLBACK Callback + ); + +NTSYSAPI +VOID +NTAPI +DoubleSpaceMount( + _In_ PWSTR HostDriveName, + _In_ PWSTR CvfName, + _In_ PWSTR NewDriveName, + _In_ FMIFS_CALLBACK Callback + ); + +NTSYSAPI +VOID +NTAPI +DoubleSpaceDismount( + _In_ PWSTR DblspaceDriveName, + _In_ FMIFS_CALLBACK Callback + ); +#endif + +// Miscellaneous + +NTSYSAPI +BOOLEAN +NTAPI +FmifsQueryDriveInformation( + _In_ PWSTR DosDriveName, + _Out_ PBOOLEAN IsRemovable, + _Out_ PBOOLEAN IsFloppy, + _Out_ PBOOLEAN IsCompressed, + _Out_ PBOOLEAN Error, + _Out_ PWSTR NtDriveName, + _In_ ULONG MaxNtDriveNameLength, + _Out_ PWSTR CvfFileName, + _In_ ULONG MaxCvfFileNameLength, + _Out_ PWSTR HostDriveName, + _In_ ULONG MaxHostDriveNameLength + ); + +NTSYSAPI +BOOLEAN +NTAPI +FmifsSetAutomount( + _In_ BOOLEAN EnableAutomount + ); + +#endif From 5984d016143de73f0a64e66706eb0e4e95e4f820 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 23 Jul 2018 14:06:50 +1000 Subject: [PATCH 1174/2058] BuildTools: Fix cleanup path typo --- tools/CustomBuildTool/Source Files/Build.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/CustomBuildTool/Source Files/Build.cs b/tools/CustomBuildTool/Source Files/Build.cs index a29b619ec2c4..cc8185c57be2 100644 --- a/tools/CustomBuildTool/Source Files/Build.cs +++ b/tools/CustomBuildTool/Source Files/Build.cs @@ -244,8 +244,8 @@ public static void CleanupBuildEnvironment() { string sourceFile = BuildOutputFolder + file; - if (File.Exists(file)) - File.Delete(file); + if (File.Exists(sourceFile)) + File.Delete(sourceFile); } if (Directory.Exists("sdk")) From fdc14b295e6550ab5393a88e6876937ca18edf63 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 23 Jul 2018 14:10:39 +1000 Subject: [PATCH 1175/2058] Move fonts to phlib --- ProcessHacker/include/phapp.h | 4 ---- ProcessHacker/main.c | 9 --------- phlib/guisup.c | 14 +++++++++++--- phlib/include/guisup.h | 5 +++++ 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/ProcessHacker/include/phapp.h b/ProcessHacker/include/phapp.h index d83a9a33eb08..a067dd739c59 100644 --- a/ProcessHacker/include/phapp.h +++ b/ProcessHacker/include/phapp.h @@ -72,12 +72,8 @@ typedef struct _PH_STARTUP_PARAMETERS PPH_STRING SysInfo; } PH_STARTUP_PARAMETERS, *PPH_STARTUP_PARAMETERS; -PHAPPAPI extern HFONT PhApplicationFont; // phapppub -PHAPPAPI extern HFONT PhTreeWindowFont; // phapppub extern BOOLEAN PhPluginsEnabled; extern PPH_STRING PhSettingsFileName; -extern PH_INTEGER_PAIR PhSmallIconSize; -extern PH_INTEGER_PAIR PhLargeIconSize; extern PH_STARTUP_PARAMETERS PhStartupParameters; extern PH_PROVIDER_THREAD PhPrimaryProviderThread; diff --git a/ProcessHacker/main.c b/ProcessHacker/main.c index 76832da39670..88697f765a63 100644 --- a/ProcessHacker/main.c +++ b/ProcessHacker/main.c @@ -88,12 +88,8 @@ BOOLEAN PhInitializeMitigationPolicy( VOID ); -PHAPPAPI HFONT PhApplicationFont = NULL; -PHAPPAPI HFONT PhTreeWindowFont = NULL; BOOLEAN PhPluginsEnabled = FALSE; PPH_STRING PhSettingsFileName = NULL; -PH_INTEGER_PAIR PhSmallIconSize = { 16, 16 }; -PH_INTEGER_PAIR PhLargeIconSize = { 32, 32 }; PH_STARTUP_PARAMETERS PhStartupParameters; PH_PROVIDER_THREAD PhPrimaryProviderThread; @@ -184,11 +180,6 @@ INT WINAPI wWinMain( PhHexEditInitialization(); PhColorBoxInitialization(); - PhSmallIconSize.X = GetSystemMetrics(SM_CXSMICON); - PhSmallIconSize.Y = GetSystemMetrics(SM_CYSMICON); - PhLargeIconSize.X = GetSystemMetrics(SM_CXICON); - PhLargeIconSize.Y = GetSystemMetrics(SM_CYICON); - if (PhStartupParameters.ShowOptions) { // Elevated options dialog for changing the value of Replace Task Manager with Process Hacker. diff --git a/phlib/guisup.c b/phlib/guisup.c index 40d4a2e0b49c..209a3c224f45 100644 --- a/phlib/guisup.c +++ b/phlib/guisup.c @@ -48,9 +48,12 @@ typedef struct _PH_WINDOW_PROPERTY_CONTEXT PVOID Context; } PH_WINDOW_PROPERTY_CONTEXT, *PPH_WINDOW_PROPERTY_CONTEXT; -_IsImmersiveProcess IsImmersiveProcess_I; -_RunFileDlg RunFileDlg; -_SHAutoComplete SHAutoComplete_I; +_IsImmersiveProcess IsImmersiveProcess_I = NULL; +_RunFileDlg RunFileDlg = NULL; +_SHAutoComplete SHAutoComplete_I = NULL; + +PH_INTEGER_PAIR PhSmallIconSize = { 16, 16 }; +PH_INTEGER_PAIR PhLargeIconSize = { 32, 32 }; static PH_INITONCE SharedIconCacheInitOnce = PH_INITONCE_INIT; static PPH_HASHTABLE SharedIconCacheHashtable; @@ -74,6 +77,11 @@ VOID PhGuiSupportInitialization( 10 ); + PhSmallIconSize.X = GetSystemMetrics(SM_CXSMICON); + PhSmallIconSize.Y = GetSystemMetrics(SM_CYSMICON); + PhLargeIconSize.X = GetSystemMetrics(SM_CXICON); + PhLargeIconSize.Y = GetSystemMetrics(SM_CYICON); + if (hdc = GetDC(NULL)) { PhGlobalDpi = GetDeviceCaps(hdc, LOGPIXELSY); diff --git a/phlib/include/guisup.h b/phlib/include/guisup.h index eb4b748a689b..b106e7b8156a 100644 --- a/phlib/include/guisup.h +++ b/phlib/include/guisup.h @@ -61,6 +61,9 @@ extern _IsImmersiveProcess IsImmersiveProcess_I; extern _RunFileDlg RunFileDlg; extern _SHAutoComplete SHAutoComplete_I; +extern PH_INTEGER_PAIR PhSmallIconSize; +extern PH_INTEGER_PAIR PhLargeIconSize; + PHLIBAPI VOID PhGuiSupportInitialization( VOID @@ -829,6 +832,8 @@ PhMakeColorBrighter( return RGB(r, g, b); } +PHLIBAPI extern HFONT PhApplicationFont; // phapppub +PHLIBAPI extern HFONT PhTreeWindowFont; // phapppub #ifdef __cplusplus } #endif From 0c1baf68bf62f685aba3112dafb4957ebd1da3d1 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 23 Jul 2018 14:32:19 +1000 Subject: [PATCH 1176/2058] Update phlib font exports --- ProcessHacker/ProcessHacker.def | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ProcessHacker/ProcessHacker.def b/ProcessHacker/ProcessHacker.def index c9e4f11ae616..ed94b9b71980 100644 --- a/ProcessHacker/ProcessHacker.def +++ b/ProcessHacker/ProcessHacker.def @@ -523,6 +523,8 @@ EXPORTS PhGetDialogItemValue PhSetDialogItemValue PhSetDialogItemText + PhApplicationFont + PhTreeWindowFont ; hndlinfo PhEnumObjectTypes From ba99eefe9a10014d104cdb228bcc2172328daf17 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 23 Jul 2018 14:49:29 +1000 Subject: [PATCH 1177/2058] Fix build --- phlib/guisup.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/phlib/guisup.c b/phlib/guisup.c index 209a3c224f45..37ebf1ab39cb 100644 --- a/phlib/guisup.c +++ b/phlib/guisup.c @@ -52,6 +52,8 @@ _IsImmersiveProcess IsImmersiveProcess_I = NULL; _RunFileDlg RunFileDlg = NULL; _SHAutoComplete SHAutoComplete_I = NULL; +HFONT PhApplicationFont = NULL; +HFONT PhTreeWindowFont = NULL; PH_INTEGER_PAIR PhSmallIconSize = { 16, 16 }; PH_INTEGER_PAIR PhLargeIconSize = { 32, 32 }; From eaeb3c1a0fccd6aee39ce0eec20d15cca6252eb8 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 24 Jul 2018 18:20:08 +1000 Subject: [PATCH 1178/2058] Add ShowPluginLoadErrors setting --- ProcessHacker/plugin.c | 8 +++---- ProcessHacker/settings.c | 1 + phlib/util.c | 51 ++++++++++++++++++++++++++++++++++------ 3 files changed, 49 insertions(+), 11 deletions(-) diff --git a/ProcessHacker/plugin.c b/ProcessHacker/plugin.c index f7cc3e01d0b7..c50f9cd8eb38 100644 --- a/ProcessHacker/plugin.c +++ b/ProcessHacker/plugin.c @@ -209,9 +209,9 @@ static BOOLEAN EnumPluginsDirectoryCallback( baseName.Buffer = Information->FileName; baseName.Length = Information->FileNameLength; - // dmex: make sure we have a valid file extension and not something like ".dll_" - //if (!PhEndsWithStringRef2(&baseName, L".dll", FALSE)) - // return TRUE; + // Note: The *.dll pattern passed to NtQueryDirectoryFile includes extensions other than dll (For example: *.dll* or .dllmanifest). (dmex) + if (!PhEndsWithStringRef2(&baseName, L".dll", FALSE)) + return TRUE; for (ULONG i = 0; i < RTL_NUMBER_OF(PhpPluginBlocklist); i++) { @@ -314,7 +314,7 @@ VOID PhLoadPlugins( // Handle load errors. // In certain startup modes we want to ignore all plugin load errors. - if (pluginLoadErrors->Count != 0 && !PhStartupParameters.PhSvc) + if (PhGetIntegerSetting(L"ShowPluginLoadErrors") && pluginLoadErrors->Count != 0 && !PhStartupParameters.PhSvc) { PH_STRING_BUILDER stringBuilder; PPHP_PLUGIN_LOAD_ERROR loadError; diff --git a/ProcessHacker/settings.c b/ProcessHacker/settings.c index 736d0d22e476..92a26726a3ea 100644 --- a/ProcessHacker/settings.c +++ b/ProcessHacker/settings.c @@ -150,6 +150,7 @@ VOID PhAddDefaultSettings( PhpAddStringSetting(L"ServiceTreeListColumns", L""); PhpAddStringSetting(L"ServiceTreeListSort", L"0,1"); // 0, AscendingSortOrder PhpAddIntegerPairSetting(L"SessionShadowHotkey", L"106,2"); // VK_MULTIPLY,KBDCTRL + PhpAddIntegerSetting(L"ShowPluginLoadErrors", L"0"); PhpAddIntegerSetting(L"ShowCommitInSummary", L"1"); PhpAddIntegerSetting(L"ShowCpuBelow001", L"0"); PhpAddIntegerSetting(L"ShowHexId", L"0"); diff --git a/phlib/util.c b/phlib/util.c index 63dc7ef951e2..4ff1f19637a1 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -5377,13 +5377,11 @@ PPH_STRING PhGetDllFileName( return NULL; newFileName = PhGetFileName(fileName); - PhDereferenceObject(fileName); - fileName = newFileName; + PhMoveReference(&fileName, newFileName); if (newFileName = PhGetFullPath(fileName->Buffer, NULL)) // HACK PhGetApplicationDirectory (dmex) { - PhDereferenceObject(fileName); - fileName = newFileName; + PhMoveReference(&fileName, newFileName); } if (IndexOfFileName) @@ -5747,8 +5745,27 @@ static NTSTATUS PhpFixupLoaderEntryImageImports( if (!procedureAddress) { - status = STATUS_ORDINAL_NOT_FOUND; - PhShowError(NULL, L"Error locating ordinal: %u\r\nModule: %hs", procedureOrdinal, importName); + if (PhGetIntegerSetting(L"ShowPluginLoadErrors")) // HACK abstraction violation (dmex) + { + PPH_STRING fileName; + + if (NT_SUCCESS(PhGetProcessMappedFileName(NtCurrentProcess(), BaseAddress, &fileName))) + { + PhMoveReference(&fileName, PhResolveDevicePrefix(fileName)); + PhMoveReference(&fileName, PhGetBaseName(fileName)); + + PhShowError( + NULL, + L"Unable to load plugin.\r\nName: %s\r\nOrdinal: %u\r\nModule: %hs", + PhGetStringOrEmpty(fileName), + procedureOrdinal, + importName + ); + + PhDereferenceObject(fileName); + } + + status = STATUS_INVALID_PARAMETER;STATUS_ORDINAL_NOT_FOUND; goto CleanupExit; } @@ -5764,8 +5781,28 @@ static NTSTATUS PhpFixupLoaderEntryImageImports( if (!procedureAddress) { + if (PhGetIntegerSetting(L"ShowPluginLoadErrors")) // HACK abstraction violation (dmex) + { + PPH_STRING fileName; + + if (NT_SUCCESS(PhGetProcessMappedFileName(NtCurrentProcess(), BaseAddress, &fileName))) + { + PhMoveReference(&fileName, PhResolveDevicePrefix(fileName)); + PhMoveReference(&fileName, PhGetBaseName(fileName)); + + PhShowError( + NULL, + L"Unable to load plugin.\r\nName: %s\r\nFunction: %hs\r\nModule: %hs", + PhGetStringOrEmpty(fileName), + importByName->Name, + importName + ); + + PhDereferenceObject(fileName); + } + } + status = STATUS_PROCEDURE_NOT_FOUND; - PhShowError(NULL, L"Error locating procedure: %hs\r\nModule: %hs", importByName->Name, importName); goto CleanupExit; } From b472c50122d3fa325815b5f37dbd3451401e9be8 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 24 Jul 2018 19:05:22 +1000 Subject: [PATCH 1179/2058] Improve window font consistency, Improve changing font at runtime --- ProcessHacker/include/phplug.h | 62 -------------- ProcessHacker/include/procprpp.h | 2 - ProcessHacker/plugin.c | 100 ----------------------- ProcessHacker/prpgenv.c | 2 + ProcessHacker/prpghndl.c | 3 + ProcessHacker/prpgmem.c | 3 + ProcessHacker/prpgmod.c | 3 + ProcessHacker/prpgstat.c | 3 + ProcessHacker/prpgthrd.c | 4 +- phlib/guisup.c | 133 ++++++++++++++++++++++++++++++- phlib/include/guisup.h | 62 ++++++++++++++ phlib/util.c | 1 + 12 files changed, 211 insertions(+), 167 deletions(-) diff --git a/ProcessHacker/include/phplug.h b/ProcessHacker/include/phplug.h index c4534925df39..3f75714b35f0 100644 --- a/ProcessHacker/include/phplug.h +++ b/ProcessHacker/include/phplug.h @@ -737,68 +737,6 @@ PhPluginCallPhSvc( _Out_writes_bytes_opt_(OutLength) PVOID OutBuffer, _In_ ULONG OutLength ); - -typedef enum _PH_PLUGIN_WINDOW_EVENT_TYPE -{ - PH_PLUGIN_WINDOW_EVENT_TYPE_NONE, - PH_PLUGIN_WINDOW_EVENT_TYPE_TOPMOST, - PH_PLUGIN_WINDOW_EVENT_TYPE_FONT, - PH_PLUGIN_WINDOW_EVENT_TYPE_MAX -} PH_PLUGIN_WINDOW_EVENT_TYPE; - -typedef struct _PH_PLUGIN_WINDOW_CALLBACK_REGISTRATION -{ - HWND WindowHandle; - PH_PLUGIN_WINDOW_EVENT_TYPE Type; - PH_CALLBACK_REGISTRATION Registration; -} PH_PLUGIN_WINDOW_CALLBACK_REGISTRATION, *PPH_PLUGIN_WINDOW_CALLBACK_REGISTRATION; - -typedef struct _PH_PLUGIN_WINDOW_NOTIFY_EVENT -{ - PH_PLUGIN_WINDOW_EVENT_TYPE Type; - union - { - BOOLEAN TopMost; - HFONT FontHandle; - }; -} PH_PLUGIN_WINDOW_NOTIFY_EVENT, *PPH_PLUGIN_WINDOW_NOTIFY_EVENT; - -typedef struct _PH_PLUGIN_MAINWINDOW_NOTIFY_EVENT -{ - PPH_PLUGIN_WINDOW_NOTIFY_EVENT Event; - PPH_PLUGIN_WINDOW_CALLBACK_REGISTRATION Callback; -} PH_PLUGIN_MAINWINDOW_NOTIFY_EVENT, *PPH_PLUGIN_MAINWINDOW_NOTIFY_EVENT; - -PHAPPAPI -PPH_PLUGIN_WINDOW_CALLBACK_REGISTRATION -NTAPI -PhRegisterWindowNotifyEvents( - _In_ HWND WindowHandle, - _In_ PH_PLUGIN_WINDOW_EVENT_TYPE Type - ); - -PHAPPAPI -VOID -NTAPI -PhUnregisterWindowNotifyEvents( - _In_ HWND WindowHandle, - _In_ PPH_PLUGIN_WINDOW_CALLBACK_REGISTRATION Callback - ); - -PHAPPAPI -VOID -NTAPI -PhWindowNotifyTopMostEvent( - _In_ BOOLEAN TopMost - ); - -PHAPPAPI -VOID -NTAPI -PhWindowNotifyFontUpdateEvent( - _In_ HFONT FontHandle - ); - // end_phapppub #endif diff --git a/ProcessHacker/include/procprpp.h b/ProcessHacker/include/procprpp.h index 7e0f8867d6c1..6f8ceccf2b03 100644 --- a/ProcessHacker/include/procprpp.h +++ b/ProcessHacker/include/procprpp.h @@ -246,7 +246,6 @@ typedef struct _PH_MODULES_CONTEXT PPH_STRING ErrorMessage; PPH_STRING SearchboxText; PPH_TN_FILTER_ENTRY FilterEntry; - struct _PH_PLUGIN_WINDOW_CALLBACK_REGISTRATION *WindowCallback; // begin_phapppub } PH_MODULES_CONTEXT, *PPH_MODULES_CONTEXT; // end_phapppub @@ -324,7 +323,6 @@ typedef struct _PH_MEMORY_CONTEXT typedef struct _PH_STATISTICS_CONTEXT { PH_CALLBACK_REGISTRATION ProcessesUpdatedRegistration; - HWND WindowHandle; HWND ListViewHandle; BOOLEAN Enabled; diff --git a/ProcessHacker/plugin.c b/ProcessHacker/plugin.c index c50f9cd8eb38..bc55f5501745 100644 --- a/ProcessHacker/plugin.c +++ b/ProcessHacker/plugin.c @@ -1033,103 +1033,3 @@ NTSTATUS PhPluginCallPhSvc( return status; } - -static VOID PhPluginWindowNotifyEventCallback( - _In_opt_ PVOID Parameter, - _In_opt_ PVOID Context - ) -{ - PPH_PLUGIN_WINDOW_NOTIFY_EVENT Event = Parameter; - PPH_PLUGIN_WINDOW_CALLBACK_REGISTRATION callback = Context; - - switch (Event->Type) - { - case PH_PLUGIN_WINDOW_EVENT_TYPE_TOPMOST: - { - if (callback->Type != PH_PLUGIN_WINDOW_EVENT_TYPE_TOPMOST) - break; - - PhSetWindowAlwaysOnTop(callback->WindowHandle, Event->TopMost); - } - break; - case PH_PLUGIN_WINDOW_EVENT_TYPE_FONT: - { - if (callback->Type != PH_PLUGIN_WINDOW_EVENT_TYPE_FONT) - break; - - SendMessage(callback->WindowHandle, WM_SETFONT, (WPARAM)Event->FontHandle, TRUE); - } - break; - } -} - -PPH_PLUGIN_WINDOW_CALLBACK_REGISTRATION PhRegisterWindowNotifyEvents( - _In_ HWND WindowHandle, - _In_ PH_PLUGIN_WINDOW_EVENT_TYPE Type - ) -{ - PPH_PLUGIN_WINDOW_CALLBACK_REGISTRATION callback; - - callback = PhAllocateZero(sizeof(PH_PLUGIN_WINDOW_CALLBACK_REGISTRATION)); - callback->WindowHandle = WindowHandle; - callback->Type = Type; - - switch (Type) - { - case PH_PLUGIN_WINDOW_EVENT_TYPE_TOPMOST: - if (PhGetIntegerSetting(L"MainWindowAlwaysOnTop")) - PhSetWindowAlwaysOnTop(WindowHandle, TRUE); - break; - case PH_PLUGIN_WINDOW_EVENT_TYPE_FONT: - SendMessage(WindowHandle, WM_SETFONT, (WPARAM)PhTreeWindowFont, TRUE); - break; - } - - PhRegisterCallback( - PhGetGeneralCallback(GeneralCallbackWindowNotifyEvent), - PhPluginWindowNotifyEventCallback, - callback, - &callback->Registration - ); - - return callback; -} - -VOID PhUnregisterWindowNotifyEvents( - _In_ HWND WindowHandle, - _In_ PPH_PLUGIN_WINDOW_CALLBACK_REGISTRATION Callback - ) -{ - PhUnregisterCallback(PhGetGeneralCallback(GeneralCallbackWindowNotifyEvent), &Callback->Registration); - PhFree(Callback); -} - -VOID PhWindowNotifyTopMostEvent( - _In_ BOOLEAN TopMost - ) -{ - PPH_PLUGIN_WINDOW_NOTIFY_EVENT event; - - event = PhAllocateZero(sizeof(PH_PLUGIN_WINDOW_NOTIFY_EVENT)); - event->Type = PH_PLUGIN_WINDOW_EVENT_TYPE_TOPMOST; - event->TopMost = TopMost; - - PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackWindowNotifyEvent), event); - - PhFree(event); -} - -VOID PhWindowNotifyFontUpdateEvent( - _In_ HFONT FontHandle - ) -{ - PPH_PLUGIN_WINDOW_NOTIFY_EVENT event; - - event = PhAllocateZero(sizeof(PH_PLUGIN_WINDOW_NOTIFY_EVENT)); - event->Type = PH_PLUGIN_WINDOW_EVENT_TYPE_FONT; - event->FontHandle = FontHandle; - - PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackWindowNotifyEvent), event); - - PhFree(event); -} diff --git a/ProcessHacker/prpgenv.c b/ProcessHacker/prpgenv.c index 6b8cb2c42c0c..481de4af9b6d 100644 --- a/ProcessHacker/prpgenv.c +++ b/ProcessHacker/prpgenv.c @@ -1258,6 +1258,7 @@ INT_PTR CALLBACK PhpProcessEnvironmentDlgProc( PhInitializeArray(&context->Items, sizeof(PH_ENVIRONMENT_ITEM), 100); context->TreeFilterEntry = PhAddTreeNewFilter(&context->TreeFilterSupport, PhpProcessEnvironmentTreeFilterCallback, context); + PhRegisterWindowCallback(context->TreeNewHandle, PH_PLUGIN_WINDOW_EVENT_TYPE_FONT, NULL); PhMoveReference(&context->StatusMessage, PhCreateString(L"There are no environment variables to display.")); TreeNew_SetEmptyText(context->TreeNewHandle, &context->StatusMessage->sr, 0); @@ -1270,6 +1271,7 @@ INT_PTR CALLBACK PhpProcessEnvironmentDlgProc( break; case WM_DESTROY: { + PhUnregisterWindowCallback(context->TreeNewHandle); PhSaveSettingsEnvironmentList(context); PhpDeleteEnvironmentTree(context); diff --git a/ProcessHacker/prpghndl.c b/ProcessHacker/prpghndl.c index a28983797cb2..e6d70fb85778 100644 --- a/ProcessHacker/prpghndl.c +++ b/ProcessHacker/prpghndl.c @@ -398,6 +398,7 @@ INT_PTR CALLBACK PhpProcessHandlesDlgProc( handlesContext->ErrorMessage = NULL; handlesContext->SearchboxText = PhReferenceEmptyString(); handlesContext->FilterEntry = PhAddTreeNewFilter(&handlesContext->ListContext.TreeFilterSupport, PhpHandleTreeFilterCallback, handlesContext); + PhRegisterWindowCallback(tnHandle, PH_PLUGIN_WINDOW_EVENT_TYPE_FONT, NULL); PhEmCallObjectOperation(EmHandlesContextType, handlesContext, EmObjectCreate); @@ -423,6 +424,8 @@ INT_PTR CALLBACK PhpProcessHandlesDlgProc( break; case WM_DESTROY: { + PhUnregisterWindowCallback(tnHandle); + PhEmCallObjectOperation(EmHandlesContextType, handlesContext, EmObjectDelete); PhUnregisterCallback( diff --git a/ProcessHacker/prpgmem.c b/ProcessHacker/prpgmem.c index 39d1df21be55..271efb38232e 100644 --- a/ProcessHacker/prpgmem.c +++ b/ProcessHacker/prpgmem.c @@ -341,6 +341,7 @@ INT_PTR CALLBACK PhpProcessMemoryDlgProc( BringWindowToTop(tnHandle); PhInitializeMemoryList(hwndDlg, tnHandle, &memoryContext->ListContext); TreeNew_SetEmptyText(tnHandle, &PhpLoadingText, 0); + PhRegisterWindowCallback(tnHandle, PH_PLUGIN_WINDOW_EVENT_TYPE_FONT, NULL); memoryContext->LastRunStatus = -1; memoryContext->ErrorMessage = NULL; memoryContext->SearchboxText = PhReferenceEmptyString(); @@ -366,6 +367,8 @@ INT_PTR CALLBACK PhpProcessMemoryDlgProc( break; case WM_DESTROY: { + PhUnregisterWindowCallback(tnHandle); + PhEmCallObjectOperation(EmMemoryContextType, memoryContext, EmObjectDelete); if (PhPluginsEnabled) diff --git a/ProcessHacker/prpgmod.c b/ProcessHacker/prpgmod.c index e570936d77b4..701b4ac11be4 100644 --- a/ProcessHacker/prpgmod.c +++ b/ProcessHacker/prpgmod.c @@ -480,6 +480,7 @@ INT_PTR CALLBACK PhpProcessModulesDlgProc( modulesContext->ErrorMessage = NULL; modulesContext->SearchboxText = PhReferenceEmptyString(); modulesContext->FilterEntry = PhAddTreeNewFilter(&modulesContext->ListContext.TreeFilterSupport, PhpModulesTreeFilterCallback, modulesContext); + PhRegisterWindowCallback(tnHandle, PH_PLUGIN_WINDOW_EVENT_TYPE_FONT, NULL); PhEmCallObjectOperation(EmModulesContextType, modulesContext, EmObjectCreate); @@ -503,6 +504,8 @@ INT_PTR CALLBACK PhpProcessModulesDlgProc( break; case WM_DESTROY: { + PhUnregisterWindowCallback(tnHandle); + PhEmCallObjectOperation(EmModulesContextType, modulesContext, EmObjectDelete); PhUnregisterCallback( diff --git a/ProcessHacker/prpgstat.c b/ProcessHacker/prpgstat.c index 80bd55c1b66a..21bf6960e67d 100644 --- a/ProcessHacker/prpgstat.c +++ b/ProcessHacker/prpgstat.c @@ -317,6 +317,7 @@ INT_PTR CALLBACK PhpProcessStatisticsDlgProc( PhAddListViewColumn(statisticsContext->ListViewHandle, 0, 0, 0, LVCFMT_LEFT, 135, L"Property"); PhAddListViewColumn(statisticsContext->ListViewHandle, 1, 1, 1, LVCFMT_LEFT, 150, L"Value"); PhSetExtendedListView(statisticsContext->ListViewHandle); + PhRegisterWindowCallback(statisticsContext->ListViewHandle, PH_PLUGIN_WINDOW_EVENT_TYPE_FONT, NULL); PhpUpdateStatisticsAddListViewGroups(statisticsContext->ListViewHandle); @@ -334,6 +335,8 @@ INT_PTR CALLBACK PhpProcessStatisticsDlgProc( break; case WM_DESTROY: { + PhUnregisterWindowCallback(statisticsContext->ListViewHandle); + PhUnregisterCallback( PhGetGeneralCallback(GeneralCallbackProcessProviderUpdatedEvent), &statisticsContext->ProcessesUpdatedRegistration diff --git a/ProcessHacker/prpgthrd.c b/ProcessHacker/prpgthrd.c index a3177c992573..6e5a7c01b0d7 100644 --- a/ProcessHacker/prpgthrd.c +++ b/ProcessHacker/prpgthrd.c @@ -557,7 +557,7 @@ INT_PTR CALLBACK PhpProcessThreadsDlgProc( PhInitializeThreadList(hwndDlg, tnHandle, &threadsContext->ListContext); TreeNew_SetEmptyText(tnHandle, &EmptyThreadsText, 0); PhInitializeProviderEventQueue(&threadsContext->EventQueue, 100); - + PhRegisterWindowCallback(tnHandle, PH_PLUGIN_WINDOW_EVENT_TYPE_FONT, NULL); // Use Cycles instead of Context Switches on Vista and above, but only when we can // open the process, since cycle time information requires sufficient access to the // threads. @@ -616,6 +616,8 @@ INT_PTR CALLBACK PhpProcessThreadsDlgProc( break; case WM_DESTROY: { + PhUnregisterWindowCallback(tnHandle); + PhEmCallObjectOperation(EmThreadsContextType, threadsContext, EmObjectDelete); PhUnregisterCallback( diff --git a/phlib/guisup.c b/phlib/guisup.c index 37ebf1ab39cb..e1cb61a89c6b 100644 --- a/phlib/guisup.c +++ b/phlib/guisup.c @@ -23,7 +23,7 @@ #include #include - +#include #include #include #include @@ -36,10 +36,16 @@ BOOLEAN NTAPI PhpWindowContextHashtableEqualFunction( _In_ PVOID Entry1, _In_ PVOID Entry2 ); - ULONG NTAPI PhpWindowContextHashtableHashFunction( _In_ PVOID Entry ); +BOOLEAN NTAPI PhpWindowCallbackHashtableEqualFunction( + _In_ PVOID Entry1, + _In_ PVOID Entry2 + ); +ULONG NTAPI PhpWindowCallbackHashtableHashFunction( + _In_ PVOID Entry + ); typedef struct _PH_WINDOW_PROPERTY_CONTEXT { @@ -61,6 +67,8 @@ static PH_INITONCE SharedIconCacheInitOnce = PH_INITONCE_INIT; static PPH_HASHTABLE SharedIconCacheHashtable; static PH_QUEUED_LOCK SharedIconCacheLock = PH_QUEUED_LOCK_INIT; +static PPH_HASHTABLE WindowCallbackHashTable = NULL; +static PH_QUEUED_LOCK WindowCallbackListLock = PH_QUEUED_LOCK_INIT; static PPH_HASHTABLE WindowContextHashTable = NULL; static PH_QUEUED_LOCK WindowContextListLock = PH_QUEUED_LOCK_INIT; @@ -72,6 +80,12 @@ VOID PhGuiSupportInitialization( PVOID shell32Handle; PVOID shlwapiHandle; + WindowCallbackHashTable = PhCreateHashtable( + sizeof(PH_PLUGIN_WINDOW_CALLBACK_REGISTRATION), + PhpWindowCallbackHashtableEqualFunction, + PhpWindowCallbackHashtableHashFunction, + 10 + ); WindowContextHashTable = PhCreateHashtable( sizeof(PH_WINDOW_PROPERTY_CONTEXT), PhpWindowContextHashtableEqualFunction, @@ -1539,3 +1553,118 @@ VOID PhSetWindowAlwaysOnTop( SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE ); } + +static BOOLEAN NTAPI PhpWindowCallbackHashtableEqualFunction( + _In_ PVOID Entry1, + _In_ PVOID Entry2 + ) +{ + return + (*(PPH_PLUGIN_WINDOW_CALLBACK_REGISTRATION *)Entry1)->WindowHandle == + (*(PPH_PLUGIN_WINDOW_CALLBACK_REGISTRATION *)Entry2)->WindowHandle; +} + +static ULONG NTAPI PhpWindowCallbackHashtableHashFunction( + _In_ PVOID Entry + ) +{ + return PhHashIntPtr((ULONG_PTR)(*(PPH_PLUGIN_WINDOW_CALLBACK_REGISTRATION *)Entry)->WindowHandle); +} + +VOID PhRegisterWindowCallback( + _In_ HWND WindowHandle, + _In_ PH_PLUGIN_WINDOW_EVENT_TYPE Type, + _In_ PVOID Context + ) +{ + PPH_PLUGIN_WINDOW_CALLBACK_REGISTRATION entry; + + entry = PhAllocate(sizeof(PH_PLUGIN_WINDOW_CALLBACK_REGISTRATION)); + entry->WindowHandle = WindowHandle; + entry->Type = Type; + + switch (Type) // HACK + { + case PH_PLUGIN_WINDOW_EVENT_TYPE_TOPMOST: + if (PhGetIntegerSetting(L"MainWindowAlwaysOnTop")) + PhSetWindowAlwaysOnTop(WindowHandle, TRUE); + break; + case PH_PLUGIN_WINDOW_EVENT_TYPE_FONT: + SendMessage(WindowHandle, WM_SETFONT, (WPARAM)PhTreeWindowFont, TRUE); + break; + } + + PhAcquireQueuedLockExclusive(&WindowCallbackListLock); + PhAddEntryHashtable(WindowCallbackHashTable, &entry); + PhReleaseQueuedLockExclusive(&WindowCallbackListLock); +} + +VOID PhUnregisterWindowCallback( + _In_ HWND WindowHandle + ) +{ + PH_PLUGIN_WINDOW_CALLBACK_REGISTRATION lookupEntry; + PPH_PLUGIN_WINDOW_CALLBACK_REGISTRATION lookupEntryPtr = &lookupEntry; + PPH_PLUGIN_WINDOW_CALLBACK_REGISTRATION *entryPtr; + PPH_PLUGIN_WINDOW_CALLBACK_REGISTRATION entry; + + lookupEntry.WindowHandle = WindowHandle; + + PhAcquireQueuedLockExclusive(&WindowCallbackListLock); + + entryPtr = (PPH_PLUGIN_WINDOW_CALLBACK_REGISTRATION*)PhFindEntryHashtable( + WindowCallbackHashTable, + &lookupEntryPtr + ); + + assert(entryPtr); + + if (entryPtr && PhRemoveEntryHashtable(WindowCallbackHashTable, entryPtr)) + { + entry = *entryPtr; + PhFree(entry); + } + + PhReleaseQueuedLockExclusive(&WindowCallbackListLock); +} + +VOID PhWindowNotifyTopMostEvent( + _In_ BOOLEAN TopMost + ) +{ + PPH_PLUGIN_WINDOW_CALLBACK_REGISTRATION *entry; + ULONG i = 0; + + PhAcquireQueuedLockExclusive(&WindowCallbackListLock); + + while (PhEnumHashtable(WindowCallbackHashTable, (PVOID*)&entry, &i)) + { + if ((*entry)->Type & PH_PLUGIN_WINDOW_EVENT_TYPE_TOPMOST) + { + PhSetWindowAlwaysOnTop((*entry)->WindowHandle, TopMost); + } + } + + PhReleaseQueuedLockExclusive(&WindowCallbackListLock); +} + +VOID PhWindowNotifyFontUpdateEvent( + _In_ HFONT FontHandle + ) +{ + PPH_PLUGIN_WINDOW_CALLBACK_REGISTRATION *entry; + ULONG i = 0; + + PhAcquireQueuedLockExclusive(&WindowCallbackListLock); + + while (PhEnumHashtable(WindowCallbackHashTable, (PVOID*)&entry, &i)) + { + if ((*entry)->Type & PH_PLUGIN_WINDOW_EVENT_TYPE_FONT) + { + SendMessage((*entry)->WindowHandle, WM_SETFONT, (WPARAM)FontHandle, TRUE); + InvalidateRect((*entry)->WindowHandle, NULL, TRUE); // HACK + } + } + + PhReleaseQueuedLockExclusive(&WindowCallbackListLock); +} diff --git a/phlib/include/guisup.h b/phlib/include/guisup.h index b106e7b8156a..21f0e473f10a 100644 --- a/phlib/include/guisup.h +++ b/phlib/include/guisup.h @@ -832,6 +832,68 @@ PhMakeColorBrighter( return RGB(r, g, b); } +// Window plugin support + +typedef enum _PH_PLUGIN_WINDOW_EVENT_TYPE +{ + PH_PLUGIN_WINDOW_EVENT_TYPE_NONE = 0, + PH_PLUGIN_WINDOW_EVENT_TYPE_TOPMOST = 1, + PH_PLUGIN_WINDOW_EVENT_TYPE_FONT = 2, + PH_PLUGIN_WINDOW_EVENT_TYPE_MAX = 4 +} PH_PLUGIN_WINDOW_EVENT_TYPE; + +typedef struct _PH_PLUGIN_WINDOW_CALLBACK_REGISTRATION +{ + HWND WindowHandle; + PH_PLUGIN_WINDOW_EVENT_TYPE Type; +} PH_PLUGIN_WINDOW_CALLBACK_REGISTRATION, *PPH_PLUGIN_WINDOW_CALLBACK_REGISTRATION; + +typedef struct _PH_PLUGIN_WINDOW_NOTIFY_EVENT +{ + PH_PLUGIN_WINDOW_EVENT_TYPE Type; + union + { + BOOLEAN TopMost; + HFONT FontHandle; + }; +} PH_PLUGIN_WINDOW_NOTIFY_EVENT, *PPH_PLUGIN_WINDOW_NOTIFY_EVENT; + +typedef struct _PH_PLUGIN_MAINWINDOW_NOTIFY_EVENT +{ + PPH_PLUGIN_WINDOW_NOTIFY_EVENT Event; + PPH_PLUGIN_WINDOW_CALLBACK_REGISTRATION Callback; +} PH_PLUGIN_MAINWINDOW_NOTIFY_EVENT, *PPH_PLUGIN_MAINWINDOW_NOTIFY_EVENT; + +PHLIBAPI +VOID +NTAPI +PhRegisterWindowCallback( + _In_ HWND WindowHandle, + _In_ PH_PLUGIN_WINDOW_EVENT_TYPE Type, + _In_ PVOID Context + ); + +PHLIBAPI +VOID +NTAPI +PhUnregisterWindowCallback( + _In_ HWND WindowHandle + ); + +PHLIBAPI +VOID +NTAPI +PhWindowNotifyTopMostEvent( + _In_ BOOLEAN TopMost + ); + +PHLIBAPI +VOID +NTAPI +PhWindowNotifyFontUpdateEvent( + _In_ HFONT FontHandle + ); + PHLIBAPI extern HFONT PhApplicationFont; // phapppub PHLIBAPI extern HFONT PhTreeWindowFont; // phapppub #ifdef __cplusplus diff --git a/phlib/util.c b/phlib/util.c index 4ff1f19637a1..aa7f0a65ebb3 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -5764,6 +5764,7 @@ static NTSTATUS PhpFixupLoaderEntryImageImports( PhDereferenceObject(fileName); } + } status = STATUS_INVALID_PARAMETER;STATUS_ORDINAL_NOT_FOUND; goto CleanupExit; From 9430ac948d2f50457ed0cc853b03a433ffd12c21 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 24 Jul 2018 19:08:27 +1000 Subject: [PATCH 1180/2058] Fix #40 (no graphs in win10 tablet mode) --- ProcessHacker/include/sysinfop.h | 5 -- ProcessHacker/sysinfo.c | 116 +++++++++++++++---------------- 2 files changed, 56 insertions(+), 65 deletions(-) diff --git a/ProcessHacker/include/sysinfop.h b/ProcessHacker/include/sysinfop.h index bf13d42a853a..1b6a9692bad2 100644 --- a/ProcessHacker/include/sysinfop.h +++ b/ProcessHacker/include/sysinfop.h @@ -56,11 +56,6 @@ VOID PhSipOnNcDestroy( VOID ); -VOID PhSipOnShowWindow( - _In_ BOOLEAN Showing, - _In_ ULONG State - ); - BOOLEAN PhSipOnSysCommand( _In_ ULONG Type, _In_ LONG CursorScreenX, diff --git a/ProcessHacker/sysinfo.c b/ProcessHacker/sysinfo.c index 4312233ed204..5e4025220db9 100644 --- a/ProcessHacker/sysinfo.c +++ b/ProcessHacker/sysinfo.c @@ -66,7 +66,6 @@ static PH_EVENT InitializedEvent = PH_EVENT_INIT; static PWSTR InitialSectionName; static RECT MinimumSize; static PH_CALLBACK_REGISTRATION ProcessesUpdatedRegistration; -static PPH_PLUGIN_WINDOW_CALLBACK_REGISTRATION WindowEventsRegistration = NULL; static PPH_LIST SectionList; static PH_SYSINFO_PARAMETERS CurrentParameters; @@ -207,11 +206,6 @@ INT_PTR CALLBACK PhSipSysInfoDialogProc( PhSipOnNcDestroy(); } break; - case WM_SHOWWINDOW: - { - PhSipOnShowWindow(!!wParam, (ULONG)lParam); - } - break; case WM_SYSCOMMAND: { if (PhSipOnSysCommand((ULONG)wParam, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))) @@ -279,6 +273,10 @@ VOID PhSipOnInitDialog( VOID ) { + RECT clientRect; + PH_STRINGREF sectionName; + PPH_SYSINFO_SECTION section; + SendMessage(PhSipWindow, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER))); SendMessage(PhSipWindow, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER))); @@ -299,63 +297,20 @@ VOID PhSipOnInitDialog( PhSetControlTheme(PhSipWindow, L"explorer"); PhSipUpdateThemeData(); -} - -VOID PhSipOnDestroy( - VOID - ) -{ - PhUnregisterCallback(PhGetGeneralCallback(GeneralCallbackProcessProviderUpdatedEvent), &ProcessesUpdatedRegistration); - PhUnregisterWindowNotifyEvents(PhSipWindow, WindowEventsRegistration); - - if (CurrentSection) - PhSetStringSetting2(L"SysInfoWindowSection", &CurrentSection->Name); - else - PhSetStringSetting(L"SysInfoWindowSection", L""); - - PhSaveWindowPlacementToSetting(L"SysInfoWindowPosition", L"SysInfoWindowSize", PhSipWindow); - PhSipSaveWindowState(); -} - -VOID PhSipOnNcDestroy( - VOID - ) -{ - ULONG i; - PPH_SYSINFO_SECTION section; - - for (i = 0; i < SectionList->Count; i++) + if (SectionList) // TODO: Remove (dmex) { - section = SectionList->Items[i]; - PhSipDestroySection(section); - } + ULONG i; + PPH_SYSINFO_SECTION section; - PhDereferenceObject(SectionList); - SectionList = NULL; - PhSipDeleteParameters(); + for (i = 0; i < SectionList->Count; i++) + { + section = SectionList->Items[i]; + PhSipDestroySection(section); + } - if (ThemeData) - { - CloseThemeData(ThemeData); - ThemeData = NULL; + PhDereferenceObject(SectionList); } - PostQuitMessage(0); -} - -VOID PhSipOnShowWindow( - _In_ BOOLEAN Showing, - _In_ ULONG State - ) -{ - //RECT buttonRect; - RECT clientRect; - PH_STRINGREF sectionName; - PPH_SYSINFO_SECTION section; - - if (SectionList) - return; - SectionList = PhCreateList(8); PhSipInitializeParameters(); CurrentView = SysInfoSummaryView; @@ -390,7 +345,6 @@ VOID PhSipOnShowWindow( PhInstanceHandle, NULL ); - RestoreSummaryControl = CreateWindow( WC_STATIC, NULL, @@ -457,12 +411,54 @@ VOID PhSipOnShowWindow( if (PhGetIntegerSetting(L"MainWindowAlwaysOnTop")) PhSetWindowAlwaysOnTop(PhSipWindow, TRUE); - WindowEventsRegistration = PhRegisterWindowNotifyEvents(PhSipWindow, PH_PLUGIN_WINDOW_EVENT_TYPE_TOPMOST); + PhRegisterWindowCallback(PhSipWindow, PH_PLUGIN_WINDOW_EVENT_TYPE_TOPMOST, NULL); PhSipOnSize(); PhSipOnUserMessage(SI_MSG_SYSINFO_UPDATE, 0, 0); } +VOID PhSipOnDestroy( + VOID + ) +{ + PhUnregisterWindowCallback(PhSipWindow); + PhUnregisterCallback(PhGetGeneralCallback(GeneralCallbackProcessProviderUpdatedEvent), &ProcessesUpdatedRegistration); + + if (CurrentSection) + PhSetStringSetting2(L"SysInfoWindowSection", &CurrentSection->Name); + else + PhSetStringSetting(L"SysInfoWindowSection", L""); + + PhSaveWindowPlacementToSetting(L"SysInfoWindowPosition", L"SysInfoWindowSize", PhSipWindow); + PhSipSaveWindowState(); +} + +VOID PhSipOnNcDestroy( + VOID + ) +{ + ULONG i; + PPH_SYSINFO_SECTION section; + + for (i = 0; i < SectionList->Count; i++) + { + section = SectionList->Items[i]; + PhSipDestroySection(section); + } + + PhDereferenceObject(SectionList); + SectionList = NULL; + PhSipDeleteParameters(); + + if (ThemeData) + { + CloseThemeData(ThemeData); + ThemeData = NULL; + } + + PostQuitMessage(0); +} + BOOLEAN PhSipOnSysCommand( _In_ ULONG Type, _In_ LONG CursorScreenX, From 5ffb532da8d03d2d691dcc7257324a1259ead8b1 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 24 Jul 2018 19:58:07 +1000 Subject: [PATCH 1181/2058] Fix build --- tools/CustomSetupTool/CustomSetupTool/main.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tools/CustomSetupTool/CustomSetupTool/main.c b/tools/CustomSetupTool/CustomSetupTool/main.c index 3f50629ce0a3..271d066bd1e3 100644 --- a/tools/CustomSetupTool/CustomSetupTool/main.c +++ b/tools/CustomSetupTool/CustomSetupTool/main.c @@ -23,6 +23,20 @@ SETUP_COMMAND_TYPE SetupMode = SETUP_COMMAND_INSTALL; PPH_STRING SetupInstallPath = NULL; +VOID PhAddDefaultSettings( + VOID + ) +{ + NOTHING; +} + +VOID PhUpdateCachedSettings( + VOID + ) +{ + NOTHING; +} + VOID SetupInitializeDpi( VOID ) From a53366ad9167a0daf9286036e92312467d8d7f59 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 24 Jul 2018 21:49:24 +1000 Subject: [PATCH 1182/2058] Add PhInitializeWindowTheme --- phlib/include/guisup.h | 8 + phlib/theme.c | 565 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 573 insertions(+) create mode 100644 phlib/theme.c diff --git a/phlib/include/guisup.h b/phlib/include/guisup.h index 21f0e473f10a..d36cdbc8e370 100644 --- a/phlib/include/guisup.h +++ b/phlib/include/guisup.h @@ -894,8 +894,16 @@ PhWindowNotifyFontUpdateEvent( _In_ HFONT FontHandle ); +// theme support (theme.c) + PHLIBAPI extern HFONT PhApplicationFont; // phapppub PHLIBAPI extern HFONT PhTreeWindowFont; // phapppub + +VOID PhInitializeWindowTheme( + _In_ HWND WindowHandle, + _In_ BOOLEAN EnableThemeSupport + ); + #ifdef __cplusplus } #endif diff --git a/phlib/theme.c b/phlib/theme.c new file mode 100644 index 000000000000..060d13313819 --- /dev/null +++ b/phlib/theme.c @@ -0,0 +1,565 @@ +/* +* Process Hacker - +* Window theme support functions +* +* Copyright (C) 2018 dmex +* +* This file is part of Process Hacker. +* +* Process Hacker is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* Process Hacker is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with Process Hacker. If not, see . +*/ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +BOOLEAN CALLBACK PhpThemeWindowEnumChildWindows( + _In_ HWND WindowHandle, + _In_opt_ PVOID Context + ); + +BOOLEAN CALLBACK PhpReInitializeWindowThemeEnumChildWindows( + _In_ HWND WindowHandle, + _In_opt_ PVOID Context + ); + +LRESULT PhpWindowThemeDrawButton( + _In_ LPNMCUSTOMDRAW DrawInfo + ); + +COLORREF PhpThemeWindowForegroundColor = RGB(28, 28, 28); +COLORREF PhpThemeWindowBackgroundColor = RGB(64, 64, 64); +COLORREF PhpThemeWindowTextColor = RGB(0xff, 0xff, 0xff); +HFONT PhpGroupboxFontHandle = NULL; + +LRESULT CALLBACK PhpThemeWindowSubclassProc( + _In_ HWND hWnd, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + WNDPROC oldWndProc; + + if (!(oldWndProc = PhGetWindowContext(hWnd, SHRT_MAX))) + return FALSE; + + switch (uMsg) + { + case WM_DESTROY: + { + PhRemoveWindowContext(hWnd, SHRT_MAX); + SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)oldWndProc); + } + break; + case WM_NOTIFY: + { + LPNMHDR data = (LPNMHDR)lParam; + + switch (data->code) + { + case NM_CUSTOMDRAW: + { + LPNMCUSTOMDRAW customDraw = (LPNMCUSTOMDRAW)lParam; + WCHAR className[MAX_PATH]; + + if (!GetClassName(customDraw->hdr.hwndFrom, className, RTL_NUMBER_OF(className))) + className[0] = 0; + + if (PhEqualStringZ(className, L"Button", FALSE)) + { + return PhpWindowThemeDrawButton(customDraw); + } + else if (PhEqualStringZ(className, L"ReBarWindow32", FALSE)) + { + NOTHING; + } + else if (PhEqualStringZ(className, L"ToolbarWindow32", FALSE)) + { + NOTHING; + } + else if (PhEqualStringZ(className, L"SysTabControl32", FALSE)) + { + NOTHING; + } + else if (PhEqualStringZ(className, L"SysListView32", FALSE)) + { + NOTHING; + } + } + } + } + break; + case WM_CTLCOLOREDIT: + { + SetBkMode((HDC)wParam, TRANSPARENT); + + switch (PhGetIntegerSetting(L"GraphColorMode")) + { + case 0: // New colors + SetTextColor((HDC)wParam, RGB(0x0, 0x0, 0x0)); + SetDCBrushColor((HDC)wParam, PhpThemeWindowTextColor); + return (INT_PTR)GetStockObject(DC_BRUSH); + case 1: // Old colors + SetTextColor((HDC)wParam, PhpThemeWindowTextColor); + SetDCBrushColor((HDC)wParam, RGB(60, 60, 60)); + return (INT_PTR)GetStockObject(DC_BRUSH); + } + } + break; + case WM_CTLCOLORBTN: + case WM_CTLCOLORDLG: + case WM_CTLCOLORSTATIC: + { + SetBkMode((HDC)wParam, TRANSPARENT); + + switch (PhGetIntegerSetting(L"GraphColorMode")) + { + case 0: // New colors + SetTextColor((HDC)wParam, RGB(0x0, 0x0, 0x0)); + SetDCBrushColor((HDC)wParam, PhpThemeWindowTextColor); + return (INT_PTR)GetStockObject(DC_BRUSH); + case 1: // Old colors + SetTextColor((HDC)wParam, PhpThemeWindowTextColor); + SetDCBrushColor((HDC)wParam, RGB(30, 30, 30)); + return (INT_PTR)GetStockObject(DC_BRUSH); + } + } + break; + } + + return CallWindowProc(oldWndProc, hWnd, uMsg, wParam, lParam); +} + +LRESULT CALLBACK PhpThemeWindowGroupBoxSubclassProc( + _In_ HWND hWnd, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + WNDPROC oldWndProc; + + if (!(oldWndProc = PhGetWindowContext(hWnd, SHRT_MAX))) + return 0; + + switch (uMsg) + { + case WM_DESTROY: + PhRemoveWindowContext(hWnd, SHRT_MAX); + SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)oldWndProc); + break; + case WM_ERASEBKGND: + return 1; + case WM_PAINT: + { + RECT clientRect; + HDC hdc; + PAINTSTRUCT ps; + PPH_STRING windowText; + SIZE nameSize; + RECT textRect; + + if (!(hdc = BeginPaint(hWnd, &ps))) + break; + + GetClientRect(hWnd, &clientRect); + + SetBkMode(hdc, TRANSPARENT); + + switch (PhGetIntegerSetting(L"GraphColorMode")) + { + case 0: // New colors + SetTextColor(hdc, RGB(0x0, 0x0, 0x0)); + SetDCBrushColor(hdc, RGB(0xff, 0xff, 0xff)); + //FillRect(hdc, &windowRect, GetStockObject(DC_BRUSH)); + break; + case 1: // Old colors + SetTextColor(hdc, RGB(0xff, 0xff, 0xff)); + SetDCBrushColor(hdc, RGB(0, 0, 0)); // RGB(28, 28, 28)); // RGB(65, 65, 65)); + //FillRect(hdc, &windowRect, GetStockObject(DC_BRUSH)); + break; + } + + if (!PhpGroupboxFontHandle) // HACK + { + NONCLIENTMETRICS metrics = { sizeof(NONCLIENTMETRICS) }; + + if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, &metrics, 0)) + { + metrics.lfMessageFont.lfHeight = -12; + metrics.lfMessageFont.lfWeight = FW_BOLD; + + PhpGroupboxFontHandle = CreateFontIndirect(&metrics.lfMessageFont); + } + } + + SelectObject(hdc, PhpGroupboxFontHandle); + SetTextColor(hdc, RGB(255, 69, 0)); + SetDCBrushColor(hdc, RGB(65, 65, 65)); + //clientRect.top += 6; + FrameRect(hdc, &clientRect, GetStockObject(DC_BRUSH)); + //clientRect.top -= 6; + + windowText = PhGetWindowText(hWnd); + GetTextExtentPoint32( + hdc, + windowText->Buffer, + (ULONG)windowText->Length / sizeof(WCHAR), + &nameSize + ); + + textRect.left = 0; + textRect.top = 0; + textRect.right = clientRect.right; + textRect.bottom = nameSize.cy; + FillRect(hdc, &textRect, GetStockObject(DC_BRUSH)); + + textRect.left += 10; + DrawText( + hdc, + windowText->Buffer, + (ULONG)windowText->Length / sizeof(WCHAR), + &textRect, + DT_LEFT | DT_END_ELLIPSIS | DT_SINGLELINE + ); + textRect.left -= 10; + + PhDereferenceObject(windowText); + + EndPaint(hWnd, &ps); + } + return FALSE; + } + + return CallWindowProc(oldWndProc, hWnd, uMsg, wParam, lParam); +} + +VOID PhInitializeWindowTheme( + _In_ HWND WindowHandle, + _In_ BOOLEAN EnableThemeSupport + ) +{ + if (EnableThemeSupport) + { + WNDPROC defaultWindowProc; + + defaultWindowProc = (WNDPROC)GetWindowLongPtr(WindowHandle, GWLP_WNDPROC); + PhSetWindowContext(WindowHandle, SHRT_MAX, defaultWindowProc); + SetWindowLongPtr(WindowHandle, GWLP_WNDPROC, (LONG_PTR)PhpThemeWindowSubclassProc); + + PhEnumChildWindows( + WindowHandle, + 0x1000, + PhpThemeWindowEnumChildWindows, + 0 + ); + + InvalidateRect(WindowHandle, NULL, FALSE); // HACK + } + else + { + EnableThemeDialogTexture(WindowHandle, ETDT_ENABLETAB); + } +} + +VOID PhReInitializeWindowTheme( + _In_ HWND WindowHandle + ) +{ + PhEnumChildWindows( + WindowHandle, + 0x1000, + PhpReInitializeWindowThemeEnumChildWindows, + 0 + ); + + //HWND currentWindow = NULL; + // + //do + //{ + // if (currentWindow = FindWindowEx(NULL, currentWindow, NULL, NULL)) + // { + // ULONG processID = 0; + // + // GetWindowThreadProcessId(currentWindow, &processID); + // + // if (UlongToHandle(processID) == NtCurrentProcessId()) + // { + // if (currentWindow != WindowHandle) + // { + // InvalidateRect(currentWindow, NULL, TRUE); + // } + // } + // } + //} while (currentWindow); + + InvalidateRect(WindowHandle, NULL, FALSE); +} + +BOOLEAN CALLBACK PhpThemeWindowEnumChildWindows( + _In_ HWND WindowHandle, + _In_opt_ PVOID Context + ) +{ + WCHAR className[MAX_PATH]; + + PhEnumChildWindows( + WindowHandle, + 0x1000, + PhpThemeWindowEnumChildWindows, + 0 + ); + + if (!GetClassName(WindowHandle, className, RTL_NUMBER_OF(className))) + className[0] = 0; + + if (PhEqualStringZ(className, L"Button", FALSE)) + { + ULONG buttonWindowStyle = (ULONG)GetWindowLongPtr(WindowHandle, GWL_STYLE); + + if ((buttonWindowStyle & BS_GROUPBOX) == BS_GROUPBOX) + { + WNDPROC groupboxWindowProc; + + groupboxWindowProc = (WNDPROC)GetWindowLongPtr(WindowHandle, GWLP_WNDPROC); + PhSetWindowContext(WindowHandle, SHRT_MAX, groupboxWindowProc); + SetWindowLongPtr(WindowHandle, GWLP_WNDPROC, (LONG_PTR)PhpThemeWindowGroupBoxSubclassProc); + } + } + + if (PhEqualStringZ(className, L"Edit", FALSE)) + { + PhSetWindowStyle(WindowHandle, WS_BORDER, 0); + PhSetWindowExStyle(WindowHandle, WS_EX_CLIENTEDGE, 0); + } + else if (PhEqualStringZ(className, L"#32770", FALSE)) + { + PhInitializeWindowTheme(WindowHandle, TRUE); + } + else if (PhEqualStringZ(className, L"SysTabControl32", FALSE)) + { + NOTHING; + } + else if (PhEqualStringZ(className, L"msctls_statusbar32", FALSE)) + { + NOTHING; + } + else if (PhEqualStringZ(className, L"SysHeader32", FALSE)) + { + NOTHING; + } + else if (PhEqualStringZ(className, L"SysListView32", FALSE)) + { + NOTHING; + } + else if (PhEqualStringZ(className, L"ScrollBar", FALSE)) + { + NOTHING; + } + + return TRUE; +} + +BOOLEAN CALLBACK PhpReInitializeWindowThemeEnumChildWindows( + _In_ HWND WindowHandle, + _In_opt_ PVOID Context + ) +{ + ULONG processID = 0; + + PhEnumChildWindows( + WindowHandle, + 0x1000, + PhpReInitializeWindowThemeEnumChildWindows, + 0 + ); + + GetWindowThreadProcessId(WindowHandle, &processID); + + if (UlongToHandle(processID) == NtCurrentProcessId()) + { + InvalidateRect(WindowHandle, NULL, FALSE); + } + + return TRUE; +} + +LRESULT PhpWindowThemeDrawButton( + _In_ LPNMCUSTOMDRAW DrawInfo + ) +{ + BOOLEAN isGrayed = (DrawInfo->uItemState & CDIS_GRAYED) == CDIS_GRAYED; + BOOLEAN isChecked = (DrawInfo->uItemState & CDIS_CHECKED) == CDIS_CHECKED; + BOOLEAN isDisabled = (DrawInfo->uItemState & CDIS_DISABLED) == CDIS_DISABLED; + BOOLEAN isSelected = (DrawInfo->uItemState & CDIS_SELECTED) == CDIS_SELECTED; + BOOLEAN isHighlighted = (DrawInfo->uItemState & CDIS_HOT) == CDIS_HOT; + BOOLEAN isFocused = (DrawInfo->uItemState & CDIS_FOCUS) == CDIS_FOCUS; + + switch (DrawInfo->dwDrawStage) + { + case CDDS_PREPAINT: + { + PPH_STRING buttonText; + HFONT oldFont; + COLORREF oldColor; + + buttonText = PhGetWindowText(DrawInfo->hdr.hwndFrom); + + if (isSelected) + { + switch (PhGetIntegerSetting(L"GraphColorMode")) + { + case 0: // New colors + oldColor = SetTextColor(DrawInfo->hdc, RGB(0, 0, 0xff)); + SetDCBrushColor(DrawInfo->hdc, PhpThemeWindowTextColor); + break; + case 1: // Old colors + //SetBkColor(drawInfo->hdc, GetSysColor(COLOR_HIGHLIGHT)); + oldColor = SetTextColor(DrawInfo->hdc, GetSysColor(COLOR_HIGHLIGHTTEXT)); + SetDCBrushColor(DrawInfo->hdc, RGB(78, 78, 78)); + FillRect(DrawInfo->hdc, &DrawInfo->rc, GetStockObject(DC_BRUSH)); + break; + } + } + else if (isHighlighted) + { + switch (PhGetIntegerSetting(L"GraphColorMode")) + { + case 0: // New colors + oldColor = SetTextColor(DrawInfo->hdc, RGB(0, 0, 0xff)); + SetDCBrushColor(DrawInfo->hdc, PhpThemeWindowTextColor); + break; + case 1: // Old colors + //SetBkColor(drawInfo->hdc, GetSysColor(COLOR_HIGHLIGHT)); + oldColor = SetTextColor(DrawInfo->hdc, GetSysColor(COLOR_HIGHLIGHTTEXT)); + SetDCBrushColor(DrawInfo->hdc, RGB(65, 65, 65)); + break; + } + + FillRect(DrawInfo->hdc, &DrawInfo->rc, GetStockObject(DC_BRUSH)); + } + else + { + switch (PhGetIntegerSetting(L"GraphColorMode")) + { + case 0: // New colors + oldColor = SetTextColor(DrawInfo->hdc, RGB(0x0, 0x0, 0x0)); + SetDCBrushColor(DrawInfo->hdc, PhpThemeWindowTextColor); + break; + case 1: // Old colors + //SetBkColor(DrawInfo->hdc, RGB(0xff, 0xff, 0xff)); + oldColor = SetTextColor(DrawInfo->hdc, PhpThemeWindowTextColor); + SetDCBrushColor(DrawInfo->hdc, RGB(42, 42, 42)); // WindowForegroundColor + break; + } + + FillRect(DrawInfo->hdc, &DrawInfo->rc, GetStockObject(DC_BRUSH)); + } + + if ((GetWindowLongPtr(DrawInfo->hdr.hwndFrom, GWL_STYLE) & BS_CHECKBOX) != 0) + { + HFONT newFont = PhDuplicateFontWithNewHeight(PhApplicationFont, 22); + oldFont = SelectFont(DrawInfo->hdc, newFont); + + if (Button_GetCheck(DrawInfo->hdr.hwndFrom) == BST_CHECKED) + { + DrawText( + DrawInfo->hdc, + L"\u2611", + -1, + &DrawInfo->rc, + DT_LEFT | DT_SINGLELINE | DT_VCENTER + ); + } + else + { + DrawText( + DrawInfo->hdc, + L"\u2610", + -1, + &DrawInfo->rc, + DT_LEFT | DT_SINGLELINE | DT_VCENTER + ); + } + + SetTextColor(DrawInfo->hdc, oldColor); + SelectFont(DrawInfo->hdc, oldFont); + DeleteFont(newFont); + + DrawInfo->rc.left += 10; + DrawText( + DrawInfo->hdc, + buttonText->Buffer, + (UINT)buttonText->Length / sizeof(WCHAR), + &DrawInfo->rc, + DT_CENTER | DT_SINGLELINE | DT_VCENTER | DT_HIDEPREFIX + ); + DrawInfo->rc.left -= 10; + } + else + { + RECT bufferRect = + { + 0, 0, + DrawInfo->rc.right - DrawInfo->rc.left, + DrawInfo->rc.bottom - DrawInfo->rc.top + }; + HICON buttonIcon; + + if (!(buttonIcon = Static_GetIcon(DrawInfo->hdr.hwndFrom, 0))) + { + buttonIcon = (HICON)SendMessage(DrawInfo->hdr.hwndFrom, BM_GETIMAGE, IMAGE_ICON, 0); + } + + if (buttonIcon) + { + DrawIconEx( + DrawInfo->hdc, + bufferRect.left + ((bufferRect.right - bufferRect.left) - 16) / 2, + bufferRect.top + ((bufferRect.bottom - bufferRect.top) - 16 ) / 2, + buttonIcon, + 16, + 16, + 0, + NULL, + DI_NORMAL + ); + } + else + { + DrawText( + DrawInfo->hdc, + buttonText->Buffer, + (UINT)buttonText->Length / sizeof(WCHAR), + &DrawInfo->rc, + DT_CENTER | DT_SINGLELINE | DT_VCENTER | DT_HIDEPREFIX + ); + } + } + + PhDereferenceObject(buttonText); + } + return CDRF_SKIPDEFAULT; + } + + return CDRF_DODEFAULT; +} From 8b1fced15ea2120b7244185e52709886c18f50cf Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 24 Jul 2018 21:53:26 +1000 Subject: [PATCH 1183/2058] Add PhEnableThemeSupport setting --- ProcessHacker/include/phsettings.h | 1 + ProcessHacker/mainwnd.c | 1 + ProcessHacker/settings.c | 1 + 3 files changed, 3 insertions(+) diff --git a/ProcessHacker/include/phsettings.h b/ProcessHacker/include/phsettings.h index 1c26890f8660..b9746e370878 100644 --- a/ProcessHacker/include/phsettings.h +++ b/ProcessHacker/include/phsettings.h @@ -13,6 +13,7 @@ EXT BOOLEAN PhEnableProcessQueryStage2; EXT BOOLEAN PhEnableServiceQueryStage2; +EXT BOOLEAN PhEnableThemeSupport; EXT BOOLEAN PhEnableHexId; EXT ULONG PhCsCollapseServicesOnStart; diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index d40ced9e0be8..53924c4cdb48 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -2137,6 +2137,7 @@ VOID PhMwpLoadSettings( PhEnableNetworkProviderResolve = !!PhGetIntegerSetting(L"EnableNetworkResolve"); PhEnableProcessQueryStage2 = !!PhGetIntegerSetting(L"EnableStage2"); PhEnableServiceQueryStage2 = !!PhGetIntegerSetting(L"EnableServiceStage2"); + PhEnableThemeSupport = !!PhGetIntegerSetting(L"EnableThemeSupport"); PhEnableHexId = !!PhGetIntegerSetting(L"ShowHexId"); PhMwpNotifyIconNotifyMask = PhGetIntegerSetting(L"IconNotifyMask"); diff --git a/ProcessHacker/settings.c b/ProcessHacker/settings.c index 92a26726a3ea..57cd073a13f6 100644 --- a/ProcessHacker/settings.c +++ b/ProcessHacker/settings.c @@ -52,6 +52,7 @@ VOID PhAddDefaultSettings( PhpAddIntegerSetting(L"EnableServiceStage2", L"0"); PhpAddIntegerSetting(L"EnableWarnings", L"1"); PhpAddIntegerSetting(L"EnableWindowText", L"1"); + PhpAddIntegerSetting(L"EnableThemeSupport", L"0"); PhpAddIntegerSetting(L"EnableSecurityAdvancedDialog", L"1"); PhpAddStringSetting(L"EnvironmentTreeListColumns", L""); PhpAddStringSetting(L"EnvironmentTreeListSort", L"0,0"); // 0, NoSortOrder From ff173efc24197294e4338d742bfae450a1cb81eb Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 24 Jul 2018 21:57:11 +1000 Subject: [PATCH 1184/2058] Add sysinfo theme support, Fix remaining sysinfo flickering issues --- ProcessHacker/sysinfo.c | 249 +++++++++++++++++++++++++++++++++++----- 1 file changed, 220 insertions(+), 29 deletions(-) diff --git a/ProcessHacker/sysinfo.c b/ProcessHacker/sysinfo.c index 5e4025220db9..bc7110724e37 100644 --- a/ProcessHacker/sysinfo.c +++ b/ProcessHacker/sysinfo.c @@ -249,6 +249,30 @@ INT_PTR CALLBACK PhSipSysInfoDialogProc( return TRUE; } break; + case WM_CTLCOLORBTN: // TODO: theme subclass sysinfo window. + case WM_CTLCOLORDLG: + case WM_CTLCOLORSTATIC: + { + if (!PhEnableThemeSupport) + break; + + SetBkMode((HDC)wParam, TRANSPARENT); + + switch (PhCsGraphColorMode) + { + case 0: // New colors + SetTextColor((HDC)wParam, RGB(0x0, 0x0, 0x0)); + SetDCBrushColor((HDC)wParam, RGB(0xef, 0xef, 0xef)); // GetSysColor(COLOR_WINDOW) + break; + case 1: // Old colors + SetTextColor((HDC)wParam, RGB(0xff, 0xff, 0xff)); + SetDCBrushColor((HDC)wParam, RGB(30, 30, 30)); + break; + } + + return (INT_PTR)GetStockObject(DC_BRUSH); + } + break; } if (uMsg >= SI_MSG_SYSINFO_FIRST && uMsg <= SI_MSG_SYSINFO_LAST) @@ -266,6 +290,34 @@ INT_PTR CALLBACK PhSipContainerDialogProc( _In_ LPARAM lParam ) { + switch (uMsg) + { + case WM_CTLCOLORBTN: // TODO: theme subclass sysinfo window. + case WM_CTLCOLORDLG: + case WM_CTLCOLORSTATIC: + { + if (!PhEnableThemeSupport) + break; + + SetBkMode((HDC)wParam, TRANSPARENT); + + switch (PhCsGraphColorMode) + { + case 0: // New colors + SetTextColor((HDC)wParam, RGB(0x0, 0x0, 0x0)); + SetDCBrushColor((HDC)wParam, GetSysColor(COLOR_WINDOW)); + break; + case 1: // Old colors + SetTextColor((HDC)wParam, RGB(0xff, 0xff, 0xff)); + SetDCBrushColor((HDC)wParam, RGB(30, 30, 30)); + break; + } + + return (INT_PTR)GetStockObject(DC_BRUSH); + } + break; + } + return FALSE; } @@ -277,6 +329,7 @@ VOID PhSipOnInitDialog( PH_STRINGREF sectionName; PPH_SYSINFO_SECTION section; + PhSetControlTheme(PhSipWindow, L"explorer"); SendMessage(PhSipWindow, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER))); SendMessage(PhSipWindow, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER))); @@ -294,8 +347,8 @@ VOID PhSipOnInitDialog( PhSipContainerDialogProc ); - PhSetControlTheme(PhSipWindow, L"explorer"); PhSipUpdateThemeData(); + PhInitializeWindowTheme(ContainerControl, PhEnableThemeSupport); if (SectionList) // TODO: Remove (dmex) { @@ -363,8 +416,6 @@ VOID PhSipOnInitDialog( SetWindowLongPtr(RestoreSummaryControl, GWLP_WNDPROC, (LONG_PTR)PhSipPanelHookWndProc); RestoreSummaryControlHot = FALSE; - EnableThemeDialogTexture(ContainerControl, ETDT_ENABLETAB); - GetClientRect(PhSipWindow, &clientRect); MinimumSize.left = 0; MinimumSize.top = 0; @@ -725,7 +776,7 @@ BOOLEAN PhSipOnNotify( BOOLEAN PhSipOnDrawItem( _In_ ULONG_PTR Id, - _In_ DRAWITEMSTRUCT *DrawItemStruct + _In_ PDRAWITEMSTRUCT DrawItemStruct ) { ULONG i; @@ -733,12 +784,12 @@ BOOLEAN PhSipOnDrawItem( if (Id == IDC_RESET) { - PhSipDrawRestoreSummaryPanel(DrawItemStruct->hDC, &DrawItemStruct->rcItem); + PhSipDrawRestoreSummaryPanel(DrawItemStruct); return TRUE; } else if (Id == IDC_SEPARATOR) { - PhSipDrawSeparator(DrawItemStruct->hDC, &DrawItemStruct->rcItem); + PhSipDrawSeparator(DrawItemStruct); return TRUE; } @@ -1127,6 +1178,8 @@ PPH_SYSINFO_SECTION PhSipCreateSection( PhInstanceHandle, NULL ); + + PhInitializeWindowTheme(section->PanelHandle, PhEnableThemeSupport); section->GraphWindowProc = (WNDPROC)GetWindowLongPtr(section->GraphHandle, GWLP_WNDPROC); section->PanelWindowProc = (WNDPROC)GetWindowLongPtr(section->PanelHandle, GWLP_WNDPROC); @@ -1189,11 +1242,49 @@ PPH_SYSINFO_SECTION PhSipCreateInternalSection( } VOID PhSipDrawRestoreSummaryPanel( - _In_ HDC hdc, - _In_ PRECT Rect + _In_ PDRAWITEMSTRUCT DrawItemStruct ) { - FillRect(hdc, Rect, GetSysColorBrush(COLOR_3DFACE)); + HDC hdc; + HDC bufferDc; + HBITMAP bufferBitmap; + HBITMAP oldBufferBitmap; + RECT bufferRect = + { + 0, 0, + DrawItemStruct->rcItem.right - DrawItemStruct->rcItem.left, + DrawItemStruct->rcItem.bottom - DrawItemStruct->rcItem.top + }; + + if (!(hdc = GetWindowDC(DrawItemStruct->hwndItem))) + return; + + bufferDc = CreateCompatibleDC(hdc); + bufferBitmap = CreateCompatibleBitmap(hdc, bufferRect.right, bufferRect.bottom); + oldBufferBitmap = SelectObject(bufferDc, bufferBitmap); + + SetBkMode(bufferDc, TRANSPARENT); + + if (PhEnableThemeSupport) + { + switch (PhCsGraphColorMode) + { + case 0: // New colors + SetTextColor(bufferDc, GetSysColor(COLOR_WINDOWTEXT)); + FillRect(bufferDc, &bufferRect, GetSysColorBrush(COLOR_3DFACE)); + break; + case 1: // Old colors + SetTextColor(bufferDc, CurrentParameters.PanelForeColor); + SetDCBrushColor(bufferDc, RGB(30, 30, 30)); + FillRect(bufferDc, &bufferRect, GetStockObject(DC_BRUSH)); + break; + } + } + else + { + SetTextColor(bufferDc, GetSysColor(COLOR_WINDOWTEXT)); + FillRect(bufferDc, &bufferRect, GetSysColorBrush(COLOR_3DFACE)); + } if (RestoreSummaryControlHot || RestoreSummaryControlHasFocus) { @@ -1201,37 +1292,110 @@ VOID PhSipDrawRestoreSummaryPanel( { DrawThemeBackground( ThemeData, - hdc, + bufferDc, TVP_TREEITEM, TREIS_HOT, - Rect, - Rect + &bufferRect, + &bufferRect ); } else { - FillRect(hdc, Rect, GetSysColorBrush(COLOR_WINDOW)); + FillRect(bufferDc, &bufferRect, GetSysColorBrush(COLOR_WINDOW)); } } - SetTextColor(hdc, GetSysColor(COLOR_WINDOWTEXT)); - SetBkMode(hdc, TRANSPARENT); + SelectObject(bufferDc, CurrentParameters.MediumFont); + DrawText(bufferDc, L"Back", 4, &bufferRect, DT_CENTER | DT_VCENTER | DT_SINGLELINE); - SelectObject(hdc, CurrentParameters.MediumFont); - DrawText(hdc, L"Back", 4, Rect, DT_CENTER | DT_VCENTER | DT_SINGLELINE); + BitBlt( + hdc, + DrawItemStruct->rcItem.left, + DrawItemStruct->rcItem.top, + DrawItemStruct->rcItem.right, + DrawItemStruct->rcItem.bottom, + bufferDc, + 0, + 0, + SRCCOPY + ); + + SelectObject(bufferDc, oldBufferBitmap); + DeleteObject(bufferBitmap); + DeleteDC(bufferDc); + + ReleaseDC(DrawItemStruct->hwndItem, hdc); } VOID PhSipDrawSeparator( - _In_ HDC hdc, - _In_ PRECT Rect + _In_ PDRAWITEMSTRUCT DrawItemStruct ) { - RECT rect; + HDC hdc; + HDC bufferDc; + HBITMAP bufferBitmap; + HBITMAP oldBufferBitmap; + RECT bufferRect = + { + 0, 0, + DrawItemStruct->rcItem.right - DrawItemStruct->rcItem.left, + DrawItemStruct->rcItem.bottom - DrawItemStruct->rcItem.top + }; + + if (!(hdc = GetWindowDC(DrawItemStruct->hwndItem))) + return; + + bufferDc = CreateCompatibleDC(hdc); + bufferBitmap = CreateCompatibleBitmap(hdc, bufferRect.right, bufferRect.bottom); + oldBufferBitmap = SelectObject(bufferDc, bufferBitmap); + + SetBkMode(bufferDc, TRANSPARENT); + + if (PhEnableThemeSupport) + { + switch (PhCsGraphColorMode) + { + case 0: // New colors + { + FillRect(bufferDc, &bufferRect, GetSysColorBrush(COLOR_3DFACE)); + bufferRect.left += 1; + FillRect(bufferDc, &bufferRect, GetSysColorBrush(COLOR_3DSHADOW)); + bufferRect.left -= 1; + } + break; + case 1: // Old colors + { + SetDCBrushColor(bufferDc, RGB(0, 0, 0)); + FillRect(bufferDc, &bufferRect, GetStockObject(DC_BRUSH)); + } + break; + } + } + else + { + FillRect(bufferDc, &bufferRect, GetSysColorBrush(COLOR_3DHIGHLIGHT)); + bufferRect.left += 1; + FillRect(bufferDc, &bufferRect, GetSysColorBrush(COLOR_3DSHADOW)); + bufferRect.left -= 1; + } + + BitBlt( + hdc, + DrawItemStruct->rcItem.left, + DrawItemStruct->rcItem.top, + DrawItemStruct->rcItem.right, + DrawItemStruct->rcItem.bottom, + bufferDc, + 0, + 0, + SRCCOPY + ); - rect = *Rect; - FillRect(hdc, &rect, GetSysColorBrush(COLOR_3DHIGHLIGHT)); - rect.left += 1; - FillRect(hdc, &rect, GetSysColorBrush(COLOR_3DSHADOW)); + SelectObject(bufferDc, oldBufferBitmap); + DeleteObject(bufferBitmap); + DeleteDC(bufferDc); + + ReleaseDC(DrawItemStruct->hwndItem, hdc); } VOID PhSipDrawPanel( @@ -1243,7 +1407,25 @@ VOID PhSipDrawPanel( PH_SYSINFO_DRAW_PANEL sysInfoDrawPanel; if (CurrentView == SysInfoSectionView) - FillRect(hdc, Rect, GetSysColorBrush(COLOR_3DFACE)); + { + if (PhEnableThemeSupport) + { + switch (PhCsGraphColorMode) + { + case 0: // New colors + FillRect(hdc, Rect, GetSysColorBrush(COLOR_3DFACE)); + break; + case 1: // Old colors + SetDCBrushColor(hdc, RGB(30, 30, 30)); + FillRect(hdc, Rect, GetStockObject(DC_BRUSH)); + break; + } + } + else + { + FillRect(hdc, Rect, GetSysColorBrush(COLOR_3DFACE)); + } + } sysInfoDrawPanel.hdc = hdc; sysInfoDrawPanel.Rect = *Rect; @@ -1365,12 +1547,19 @@ VOID PhSipDefaultDrawPanel( } } - if (CurrentView == SysInfoSummaryView) + SetBkMode(hdc, TRANSPARENT); + + if (PhEnableThemeSupport) + { SetTextColor(hdc, CurrentParameters.PanelForeColor); + } else - SetTextColor(hdc, GetSysColor(COLOR_WINDOWTEXT)); - - SetBkMode(hdc, TRANSPARENT); + { + if (CurrentView == SysInfoSummaryView) + SetTextColor(hdc, CurrentParameters.PanelForeColor); + else + SetTextColor(hdc, GetSysColor(COLOR_WINDOWTEXT)); + } rect.left = CurrentParameters.SmallGraphPadding + CurrentParameters.PanelPadding; rect.top = CurrentParameters.PanelPadding; @@ -1744,6 +1933,8 @@ VOID PhSipCreateSectionDialog( createDialog.DialogProc, createDialog.Parameter ); + + PhInitializeWindowTheme(Section->DialogHandle, PhEnableThemeSupport); } } } From 184cfd4f28cbd4fc43bb2b953defc0862ca42c6b Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 24 Jul 2018 22:00:37 +1000 Subject: [PATCH 1185/2058] Add missing header --- ProcessHacker/include/sysinfop.h | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/ProcessHacker/include/sysinfop.h b/ProcessHacker/include/sysinfop.h index 1b6a9692bad2..cb21404d50ac 100644 --- a/ProcessHacker/include/sysinfop.h +++ b/ProcessHacker/include/sysinfop.h @@ -87,7 +87,7 @@ BOOLEAN PhSipOnNotify( BOOLEAN PhSipOnDrawItem( _In_ ULONG_PTR Id, - _In_ DRAWITEMSTRUCT *DrawItemStruct + _In_ PDRAWITEMSTRUCT DrawItemStruct ); VOID PhSipOnUserMessage( @@ -137,13 +137,11 @@ PPH_SYSINFO_SECTION PhSipCreateInternalSection( ); VOID PhSipDrawRestoreSummaryPanel( - _In_ HDC hdc, - _In_ PRECT Rect + _In_ PDRAWITEMSTRUCT DrawItemStruct ); VOID PhSipDrawSeparator( - _In_ HDC hdc, - _In_ PRECT Rect + _In_ PDRAWITEMSTRUCT DrawItemStruct ); VOID PhSipDrawPanel( From 6c8ab5abcde619e5b719b1fda1705cab1b75a099 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 24 Jul 2018 22:14:34 +1000 Subject: [PATCH 1186/2058] Update phlib theme exports --- ProcessHacker/ProcessHacker.def | 1 + phlib/include/guisup.h | 5 ++++- phlib/phlib.vcxproj | 1 + phlib/phlib.vcxproj.filters | 3 +++ 4 files changed, 9 insertions(+), 1 deletion(-) diff --git a/ProcessHacker/ProcessHacker.def b/ProcessHacker/ProcessHacker.def index ed94b9b71980..3be1da55191d 100644 --- a/ProcessHacker/ProcessHacker.def +++ b/ProcessHacker/ProcessHacker.def @@ -525,6 +525,7 @@ EXPORTS PhSetDialogItemText PhApplicationFont PhTreeWindowFont + PhInitializeWindowTheme ; hndlinfo PhEnumObjectTypes diff --git a/phlib/include/guisup.h b/phlib/include/guisup.h index d36cdbc8e370..6567648ae5b4 100644 --- a/phlib/include/guisup.h +++ b/phlib/include/guisup.h @@ -899,7 +899,10 @@ PhWindowNotifyFontUpdateEvent( PHLIBAPI extern HFONT PhApplicationFont; // phapppub PHLIBAPI extern HFONT PhTreeWindowFont; // phapppub -VOID PhInitializeWindowTheme( +PHLIBAPI +VOID +NTAPI +PhInitializeWindowTheme( _In_ HWND WindowHandle, _In_ BOOLEAN EnableThemeSupport ); diff --git a/phlib/phlib.vcxproj b/phlib/phlib.vcxproj index 12755d5d85a7..bb62d0be9420 100644 --- a/phlib/phlib.vcxproj +++ b/phlib/phlib.vcxproj @@ -217,6 +217,7 @@ + diff --git a/phlib/phlib.vcxproj.filters b/phlib/phlib.vcxproj.filters index 975dbd7fe210..f8e72caf3f65 100644 --- a/phlib/phlib.vcxproj.filters +++ b/phlib/phlib.vcxproj.filters @@ -236,6 +236,9 @@ Json-C + + Source Files + From 19064ef6e8ab238b9c8936cab08b0002f18c1e48 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 24 Jul 2018 22:16:37 +1000 Subject: [PATCH 1187/2058] HardwareDevices: Update includes --- plugins/HardwareDevices/HardwareDevices.vcxproj | 1 + plugins/HardwareDevices/HardwareDevices.vcxproj.filters | 1 + 2 files changed, 2 insertions(+) diff --git a/plugins/HardwareDevices/HardwareDevices.vcxproj b/plugins/HardwareDevices/HardwareDevices.vcxproj index a34fc5115510..fb6a6dbc5e6a 100644 --- a/plugins/HardwareDevices/HardwareDevices.vcxproj +++ b/plugins/HardwareDevices/HardwareDevices.vcxproj @@ -93,6 +93,7 @@ + diff --git a/plugins/HardwareDevices/HardwareDevices.vcxproj.filters b/plugins/HardwareDevices/HardwareDevices.vcxproj.filters index 7edc128bdafd..f996d7a718ae 100644 --- a/plugins/HardwareDevices/HardwareDevices.vcxproj.filters +++ b/plugins/HardwareDevices/HardwareDevices.vcxproj.filters @@ -27,6 +27,7 @@ Header Files + From bd0a1f30f4d7dc2d3a52fc07aa040a08af8891bc Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 24 Jul 2018 22:17:58 +1000 Subject: [PATCH 1188/2058] Add PhDuplicateFontWithNewHeight --- phlib/include/guisup.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/phlib/include/guisup.h b/phlib/include/guisup.h index 6567648ae5b4..9fcb4df40a8a 100644 --- a/phlib/include/guisup.h +++ b/phlib/include/guisup.h @@ -907,6 +907,24 @@ PhInitializeWindowTheme( _In_ BOOLEAN EnableThemeSupport ); +FORCEINLINE +HFONT +PhDuplicateFontWithNewHeight( + _In_ HFONT Font, + _In_ LONG NewHeight + ) +{ + LOGFONT logFont; + + if (GetObject(Font, sizeof(LOGFONT), &logFont)) + { + logFont.lfHeight = NewHeight; + return CreateFontIndirect(&logFont); + } + + return NULL; +} + #ifdef __cplusplus } #endif From 2c3c9e804829808d7ec4256d4eaae0213b3cc34a Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 24 Jul 2018 22:44:25 +1000 Subject: [PATCH 1189/2058] Add EnableTooltipSupport setting --- ProcessHacker/include/phsettings.h | 1 + ProcessHacker/mainwnd.c | 1 + ProcessHacker/proctree.c | 3 ++- ProcessHacker/settings.c | 1 + ProcessHacker/sysinfo.c | 2 +- 5 files changed, 6 insertions(+), 2 deletions(-) diff --git a/ProcessHacker/include/phsettings.h b/ProcessHacker/include/phsettings.h index b9746e370878..bae52f79a88f 100644 --- a/ProcessHacker/include/phsettings.h +++ b/ProcessHacker/include/phsettings.h @@ -14,6 +14,7 @@ EXT BOOLEAN PhEnableProcessQueryStage2; EXT BOOLEAN PhEnableServiceQueryStage2; EXT BOOLEAN PhEnableThemeSupport; +EXT BOOLEAN PhEnableTooltipSupport; EXT BOOLEAN PhEnableHexId; EXT ULONG PhCsCollapseServicesOnStart; diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index 53924c4cdb48..59c0c7e8ad5f 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -2138,6 +2138,7 @@ VOID PhMwpLoadSettings( PhEnableProcessQueryStage2 = !!PhGetIntegerSetting(L"EnableStage2"); PhEnableServiceQueryStage2 = !!PhGetIntegerSetting(L"EnableServiceStage2"); PhEnableThemeSupport = !!PhGetIntegerSetting(L"EnableThemeSupport"); + PhEnableTooltipSupport = !!PhGetIntegerSetting(L"EnableTooltipSupport"); PhEnableHexId = !!PhGetIntegerSetting(L"ShowHexId"); PhMwpNotifyIconNotifyMask = PhGetIntegerSetting(L"IconNotifyMask"); diff --git a/ProcessHacker/proctree.c b/ProcessHacker/proctree.c index cc6e2b1d5184..d94bcccf304a 100644 --- a/ProcessHacker/proctree.c +++ b/ProcessHacker/proctree.c @@ -2989,7 +2989,8 @@ BOOLEAN NTAPI PhpProcessTreeNewCallback( if ((LONG64)(node->TooltipTextValidToTickCount - tickCount) < 0) PhClearReference(&node->TooltipText); - if (!node->TooltipText) + + if (PhEnableTooltipSupport && !node->TooltipText) node->TooltipText = PhGetProcessTooltipText(node->ProcessItem, &node->TooltipTextValidToTickCount); if (!PhIsNullOrEmptyString(node->TooltipText)) diff --git a/ProcessHacker/settings.c b/ProcessHacker/settings.c index 57cd073a13f6..f8c068a0001d 100644 --- a/ProcessHacker/settings.c +++ b/ProcessHacker/settings.c @@ -53,6 +53,7 @@ VOID PhAddDefaultSettings( PhpAddIntegerSetting(L"EnableWarnings", L"1"); PhpAddIntegerSetting(L"EnableWindowText", L"1"); PhpAddIntegerSetting(L"EnableThemeSupport", L"0"); + PhpAddIntegerSetting(L"EnableTooltipSupport", L"1"); PhpAddIntegerSetting(L"EnableSecurityAdvancedDialog", L"1"); PhpAddStringSetting(L"EnvironmentTreeListColumns", L""); PhpAddStringSetting(L"EnvironmentTreeListSort", L"0,0"); // 0, NoSortOrder diff --git a/ProcessHacker/sysinfo.c b/ProcessHacker/sysinfo.c index bc7110724e37..d068873680fe 100644 --- a/ProcessHacker/sysinfo.c +++ b/ProcessHacker/sysinfo.c @@ -1162,7 +1162,7 @@ PPH_SYSINFO_SECTION PhSipCreateSection( options.FadeOutWidth = CurrentParameters.PanelWidth + PH_SYSINFO_FADE_ADD; options.DefaultCursor = LoadCursor(NULL, IDC_HAND); Graph_SetOptions(section->GraphHandle, &options); - Graph_SetTooltip(section->GraphHandle, TRUE); + if (PhEnableTooltipSupport) Graph_SetTooltip(section->GraphHandle, TRUE); section->PanelId = IDDYNAMIC + SectionList->Count * 2 + 2; section->PanelHandle = CreateWindow( From 8808b2361c87db54d2296bfdee7fc8f1635f1242 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 24 Jul 2018 22:45:54 +1000 Subject: [PATCH 1190/2058] Fix emenu macro usage --- phlib/emenu.c | 120 ++++++++++++++++++++++---------------------------- 1 file changed, 52 insertions(+), 68 deletions(-) diff --git a/phlib/emenu.c b/phlib/emenu.c index 920a2d0f0e2a..7534f4225824 100644 --- a/phlib/emenu.c +++ b/phlib/emenu.c @@ -40,18 +40,6 @@ static const PH_FLAG_MAPPING EMenuStateMappings[] = { PH_EMENU_HIGHLIGHT, MFS_HILITE } }; -PPH_EMENU_ITEM PhAllocateEMenuItem( - VOID - ) -{ - PPH_EMENU_ITEM item; - - item = PhAllocate(sizeof(PH_EMENU_ITEM)); - memset(item, 0, sizeof(PH_EMENU_ITEM)); - - return item; -} - /** * Creates a menu item. * @@ -79,13 +67,13 @@ PPH_EMENU_ITEM PhCreateEMenuItem( { PPH_EMENU_ITEM item; - item = PhAllocateEMenuItem(); + item = PhAllocate(sizeof(PH_EMENU_ITEM)); + memset(item, 0, sizeof(PH_EMENU_ITEM)); item->Flags = Flags; item->Id = Id; item->Text = Text; item->Bitmap = Bitmap; - item->Context = Context; return item; @@ -113,12 +101,8 @@ VOID PhpDestroyEMenuItem( if (Item->Items) { - ULONG i; - - for (i = 0; i < Item->Items->Count; i++) - { + for (ULONG i = 0; i < Item->Items->Count; i++) PhpDestroyEMenuItem(Item->Items->Items[i]); - } PhDereferenceObject(Item->Items); } @@ -139,7 +123,7 @@ VOID PhDestroyEMenuItem( { // Remove the item from its parent, if it has one. if (Item->Parent) - PhRemoveEMenuItem(NULL, Item, -1); + PhRemoveEMenuItem(NULL, Item, ULONG_MAX); PhpDestroyEMenuItem(Item); } @@ -282,7 +266,7 @@ ULONG PhIndexOfEMenuItem( ) { if (!Parent->Items) - return -1; + return ULONG_MAX; return PhFindItemList(Parent->Items, Item); } @@ -311,7 +295,7 @@ VOID PhInsertEMenuItem( if (Index > Parent->Items->Count) Index = Parent->Items->Count; - if (Index == -1) + if (Index == ULONG_MAX) PhAddItemList(Parent->Items, Item); else PhInsertItemList(Parent->Items, Index, Item); @@ -342,7 +326,7 @@ BOOLEAN PhRemoveEMenuItem( Index = PhFindItemList(Parent->Items, Item); - if (Index == -1) + if (Index == ULONG_MAX) return FALSE; } else @@ -606,51 +590,51 @@ VOID PhHMenuToEMenuItem( count = GetMenuItemCount(MenuHandle); - if (count != -1) + if (count == -1) + return; + + for (i = 0; i < count; i++) { - for (i = 0; i < count; i++) - { - MENUITEMINFO menuItemInfo; - WCHAR buffer[256]; - PPH_EMENU_ITEM menuItem; - - menuItemInfo.cbSize = sizeof(menuItemInfo); - menuItemInfo.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STATE | MIIM_STRING | MIIM_SUBMENU; - menuItemInfo.cch = sizeof(buffer) / sizeof(WCHAR); - menuItemInfo.dwTypeData = buffer; - - if (!GetMenuItemInfo(MenuHandle, i, TRUE, &menuItemInfo)) - continue; - - menuItem = PhCreateEMenuItem( - PH_EMENU_TEXT_OWNED, - menuItemInfo.wID, - PhDuplicateStringZ(buffer), - NULL, - NULL - ); - - if (menuItemInfo.fType & MFT_SEPARATOR) - menuItem->Flags |= PH_EMENU_SEPARATOR; - - PhMapFlags2( - &menuItem->Flags, - menuItemInfo.fType, - EMenuTypeMappings, - sizeof(EMenuTypeMappings) / sizeof(PH_FLAG_MAPPING) - ); - PhMapFlags2( - &menuItem->Flags, - menuItemInfo.fState, - EMenuStateMappings, - sizeof(EMenuStateMappings) / sizeof(PH_FLAG_MAPPING) - ); - - if (menuItemInfo.hSubMenu) - PhHMenuToEMenuItem(menuItem, menuItemInfo.hSubMenu); - - PhInsertEMenuItem(MenuItem, menuItem, -1); - } + MENUITEMINFO menuItemInfo; + PPH_EMENU_ITEM menuItem; + WCHAR buffer[MAX_PATH]; + + menuItemInfo.cbSize = sizeof(menuItemInfo); + menuItemInfo.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STATE | MIIM_STRING | MIIM_SUBMENU; + menuItemInfo.cch = RTL_NUMBER_OF(buffer); + menuItemInfo.dwTypeData = buffer; + + if (!GetMenuItemInfo(MenuHandle, i, TRUE, &menuItemInfo)) + continue; + + menuItem = PhCreateEMenuItem( + PH_EMENU_TEXT_OWNED, + menuItemInfo.wID, + PhDuplicateStringZ(buffer), + NULL, + NULL + ); + + if (menuItemInfo.fType & MFT_SEPARATOR) + menuItem->Flags |= PH_EMENU_SEPARATOR; + + PhMapFlags2( + &menuItem->Flags, + menuItemInfo.fType, + EMenuTypeMappings, + RTL_NUMBER_OF(EMenuTypeMappings) + ); + PhMapFlags2( + &menuItem->Flags, + menuItemInfo.fState, + EMenuStateMappings, + RTL_NUMBER_OF(EMenuStateMappings) + ); + + if (menuItemInfo.hSubMenu) + PhHMenuToEMenuItem(menuItem, menuItemInfo.hSubMenu); + + PhInsertEMenuItem(MenuItem, menuItem, ULONG_MAX); } } @@ -674,7 +658,7 @@ VOID PhLoadResourceEMenuItem( menu = LoadMenu(InstanceHandle, Resource); - if (SubMenuIndex != -1) + if (SubMenuIndex != ULONG_MAX) realMenu = GetSubMenu(menu, SubMenuIndex); else realMenu = menu; From 50aabff6fc249fa107a918a057c22590028d656e Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 24 Jul 2018 23:07:48 +1000 Subject: [PATCH 1191/2058] Plugins: Remove uxtheme dependencies (1/2) --- plugins/ExtendedTools/ExtendedTools.vcxproj | 16 ++++++++-------- plugins/ExtendedTools/gpudetails.c | 3 +-- plugins/ExtendedTools/gpunodes.c | 3 +-- plugins/HardwareDevices/HardwareDevices.vcxproj | 16 ++++++++-------- plugins/HardwareDevices/devices.h | 1 - plugins/HardwareDevices/diskdetails.c | 7 ++----- plugins/HardwareDevices/diskoptions.c | 2 -- plugins/HardwareDevices/netdetails.c | 2 ++ 8 files changed, 22 insertions(+), 28 deletions(-) diff --git a/plugins/ExtendedTools/ExtendedTools.vcxproj b/plugins/ExtendedTools/ExtendedTools.vcxproj index a6260111c748..31f1688029db 100644 --- a/plugins/ExtendedTools/ExtendedTools.vcxproj +++ b/plugins/ExtendedTools/ExtendedTools.vcxproj @@ -53,26 +53,26 @@ - cfgmgr32.lib;uxtheme.lib;%(AdditionalDependencies) - advapi32.dll;comctl32.dll;cfgmgr32.dll;gdi32.dll;ole32.dll;oleaut32.dll;user32.dll;uxtheme.dll;%(DelayLoadDLLs) + cfgmgr32.lib;%(AdditionalDependencies) + advapi32.dll;comctl32.dll;cfgmgr32.dll;gdi32.dll;ole32.dll;oleaut32.dll;user32.dll;%(DelayLoadDLLs) - cfgmgr32.lib;uxtheme.lib;%(AdditionalDependencies) - advapi32.dll;comctl32.dll;cfgmgr32.dll;gdi32.dll;ole32.dll;oleaut32.dll;user32.dll;uxtheme.dll;%(DelayLoadDLLs) + cfgmgr32.lib;%(AdditionalDependencies) + advapi32.dll;comctl32.dll;cfgmgr32.dll;gdi32.dll;ole32.dll;oleaut32.dll;user32.dll;%(DelayLoadDLLs) - cfgmgr32.lib;uxtheme.lib;%(AdditionalDependencies) - advapi32.dll;comctl32.dll;cfgmgr32.dll;gdi32.dll;ole32.dll;oleaut32.dll;user32.dll;uxtheme.dll;%(DelayLoadDLLs) + cfgmgr32.lib;%(AdditionalDependencies) + advapi32.dll;comctl32.dll;cfgmgr32.dll;gdi32.dll;ole32.dll;oleaut32.dll;user32.dll;%(DelayLoadDLLs) - cfgmgr32.lib;uxtheme.lib;%(AdditionalDependencies) - advapi32.dll;comctl32.dll;cfgmgr32.dll;gdi32.dll;ole32.dll;oleaut32.dll;user32.dll;uxtheme.dll;%(DelayLoadDLLs) + cfgmgr32.lib;%(AdditionalDependencies) + advapi32.dll;comctl32.dll;cfgmgr32.dll;gdi32.dll;ole32.dll;oleaut32.dll;user32.dll;%(DelayLoadDLLs) diff --git a/plugins/ExtendedTools/gpudetails.c b/plugins/ExtendedTools/gpudetails.c index f8c0ff217048..7cbad0336831 100644 --- a/plugins/ExtendedTools/gpudetails.c +++ b/plugins/ExtendedTools/gpudetails.c @@ -22,7 +22,6 @@ #include "exttools.h" #include "gpumon.h" -#include static PH_CALLBACK_REGISTRATION ProcessesUpdatedCallbackRegistration; static PH_LAYOUT_MANAGER LayoutManager; @@ -350,7 +349,7 @@ INT_PTR CALLBACK EtpGpuDetailsDlgProc( &ProcessesUpdatedCallbackRegistration ); - EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); + PhInitializeWindowTheme(hwndDlg, !!PhGetIntegerSetting(L"EnableThemeSupport")); } break; case WM_DESTROY: diff --git a/plugins/ExtendedTools/gpunodes.c b/plugins/ExtendedTools/gpunodes.c index c6c92aed9b2e..fde3b1e93c1e 100644 --- a/plugins/ExtendedTools/gpunodes.c +++ b/plugins/ExtendedTools/gpunodes.c @@ -22,7 +22,6 @@ */ #include "exttools.h" -#include #define GRAPH_PADDING 5 static RECT NormalGraphTextMargin = { 5, 5, 5, 5 }; @@ -190,7 +189,7 @@ INT_PTR CALLBACK EtpGpuNodesDlgProc( &ProcessesUpdatedCallbackRegistration ); - EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); + PhInitializeWindowTheme(hwndDlg, !!PhGetIntegerSetting(L"EnableThemeSupport")); } break; case WM_DESTROY: diff --git a/plugins/HardwareDevices/HardwareDevices.vcxproj b/plugins/HardwareDevices/HardwareDevices.vcxproj index fb6a6dbc5e6a..a606468d867c 100644 --- a/plugins/HardwareDevices/HardwareDevices.vcxproj +++ b/plugins/HardwareDevices/HardwareDevices.vcxproj @@ -53,27 +53,27 @@ - cfgmgr32.lib;iphlpapi.lib;uxtheme.lib;%(AdditionalDependencies) - comctl32.dll;cfgmgr32.dll;iphlpapi.dll;user32.dll;uxtheme.dll;%(DelayLoadDLLs) + cfgmgr32.lib;iphlpapi.lib;%(AdditionalDependencies) + comctl32.dll;cfgmgr32.dll;iphlpapi.dll;user32.dll;%(DelayLoadDLLs) - cfgmgr32.lib;iphlpapi.lib;uxtheme.lib;%(AdditionalDependencies) - comctl32.dll;cfgmgr32.dll;iphlpapi.dll;user32.dll;uxtheme.dll;%(DelayLoadDLLs) + cfgmgr32.lib;iphlpapi.lib;%(AdditionalDependencies) + comctl32.dll;cfgmgr32.dll;iphlpapi.dll;user32.dll;%(DelayLoadDLLs) - cfgmgr32.lib;iphlpapi.lib;uxtheme.lib;%(AdditionalDependencies) - comctl32.dll;cfgmgr32.dll;iphlpapi.dll;user32.dll;uxtheme.dll;%(DelayLoadDLLs) + cfgmgr32.lib;iphlpapi.lib;%(AdditionalDependencies) + comctl32.dll;cfgmgr32.dll;iphlpapi.dll;user32.dll;%(DelayLoadDLLs) - cfgmgr32.lib;iphlpapi.lib;uxtheme.lib;%(AdditionalDependencies) - comctl32.dll;cfgmgr32.dll;iphlpapi.dll;user32.dll;uxtheme.dll;%(DelayLoadDLLs) + cfgmgr32.lib;iphlpapi.lib;%(AdditionalDependencies) + comctl32.dll;cfgmgr32.dll;iphlpapi.dll;user32.dll;%(DelayLoadDLLs) diff --git a/plugins/HardwareDevices/devices.h b/plugins/HardwareDevices/devices.h index 850f8cd3f6eb..d6f526d471d1 100644 --- a/plugins/HardwareDevices/devices.h +++ b/plugins/HardwareDevices/devices.h @@ -40,7 +40,6 @@ #include #include -#include #include #include diff --git a/plugins/HardwareDevices/diskdetails.c b/plugins/HardwareDevices/diskdetails.c index e4a55b1018e5..d26c3f46ef9d 100644 --- a/plugins/HardwareDevices/diskdetails.c +++ b/plugins/HardwareDevices/diskdetails.c @@ -608,7 +608,8 @@ INT_PTR CALLBACK DiskDriveFileSystemDetailsDlgProc( context->WindowHandle = hwndDlg; context->ListViewHandle = GetDlgItem(hwndDlg, IDC_DETAILS_LIST); - PhCenterWindow(GetParent(hwndDlg), NULL); + PhCenterWindow(GetParent(hwndDlg), NULL); // HACK + PhInitializeWindowTheme(GetParent(hwndDlg), !!PhGetIntegerSetting(L"EnableThemeSupport")); // HACK PhSetListViewStyle(context->ListViewHandle, FALSE, TRUE); PhSetControlTheme(context->ListViewHandle, L"explorer"); @@ -618,8 +619,6 @@ INT_PTR CALLBACK DiskDriveFileSystemDetailsDlgProc( ListView_EnableGroupView(context->ListViewHandle, TRUE); PhLoadListViewColumnsFromSetting(SETTING_NAME_DISK_COUNTERS_COLUMNS, context->ListViewHandle); - EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); - DiskDriveQueryFileSystem(context); } break; @@ -699,8 +698,6 @@ INT_PTR CALLBACK DiskDriveSmartDetailsDlgProc( //ExtendedListView_SetItemColorFunction(context->ListViewHandle, PhpColorItemColorFunction); PhLoadListViewColumnsFromSetting(SETTING_NAME_SMART_COUNTERS_COLUMNS, context->ListViewHandle); - EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); - DiskDriveQuerySmart(context); } break; diff --git a/plugins/HardwareDevices/diskoptions.c b/plugins/HardwareDevices/diskoptions.c index 3277ccc5e52a..f57c3f259212 100644 --- a/plugins/HardwareDevices/diskoptions.c +++ b/plugins/HardwareDevices/diskoptions.c @@ -678,8 +678,6 @@ INT_PTR CALLBACK DiskDriveOptionsDlgProc( PhInitializeLayoutManager(&context->LayoutManager, hwndDlg); PhAddLayoutItem(&context->LayoutManager, context->ListViewHandle, NULL, PH_ANCHOR_ALL); - EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); - FindDiskDrives(context); context->OptionsChanged = FALSE; diff --git a/plugins/HardwareDevices/netdetails.c b/plugins/HardwareDevices/netdetails.c index ec0ef1141518..8bcc41f9df77 100644 --- a/plugins/HardwareDevices/netdetails.c +++ b/plugins/HardwareDevices/netdetails.c @@ -560,6 +560,8 @@ INT_PTR CALLBACK NetAdapterDetailsDlgProc( FALSE, &context->NotifyHandle ); + + PhInitializeWindowTheme(hwndDlg, !!PhGetIntegerSetting(L"EnableThemeSupport")); // HACK } break; case WM_DESTROY: From e841eda8ab26d86d666a39a32a86567737f48b2e Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 24 Jul 2018 23:28:55 +1000 Subject: [PATCH 1192/2058] Add more theme support, Fix process properties window topmost setting --- ProcessHacker/about.c | 3 ++- ProcessHacker/infodlg.c | 4 +++- ProcessHacker/memlists.c | 3 +++ ProcessHacker/procprp.c | 4 ++++ plugins/HardwareDevices/diskdetails.c | 2 ++ plugins/NetworkTools/NetworkTools.vcxproj | 16 ++++++++-------- plugins/NetworkTools/nettools.h | 1 - plugins/NetworkTools/ping.c | 2 +- plugins/NetworkTools/tracert.c | 2 +- plugins/NetworkTools/whois.c | 2 +- 10 files changed, 25 insertions(+), 14 deletions(-) diff --git a/ProcessHacker/about.c b/ProcessHacker/about.c index 8c7cf704c7bc..674914134708 100644 --- a/ProcessHacker/about.c +++ b/ProcessHacker/about.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -95,7 +96,7 @@ static INT_PTR CALLBACK PhpAboutDlgProc( PhSetDialogFocus(hwndDlg, GetDlgItem(hwndDlg, IDOK)); - EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); + PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport); } break; case WM_DESTROY: diff --git a/ProcessHacker/infodlg.c b/ProcessHacker/infodlg.c index 035805ed3769..5d209dbfb363 100644 --- a/ProcessHacker/infodlg.c +++ b/ProcessHacker/infodlg.c @@ -21,7 +21,7 @@ */ #include - +#include #include typedef struct _INFORMATION_CONTEXT @@ -86,6 +86,8 @@ static INT_PTR CALLBACK PhpInformationDlgProc( PhSetDialogItemText(hwndDlg, IDC_TEXT, context->String); PhSetDialogFocus(hwndDlg, GetDlgItem(hwndDlg, IDOK)); + + PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport); } break; case WM_DESTROY: diff --git a/ProcessHacker/memlists.c b/ProcessHacker/memlists.c index 6c037877201b..4cc62e751e2e 100644 --- a/ProcessHacker/memlists.c +++ b/ProcessHacker/memlists.c @@ -22,6 +22,7 @@ #include #include +#include #include #include #include @@ -184,6 +185,8 @@ INT_PTR CALLBACK PhpMemoryListsDlgProc( PhLoadWindowPlacementFromSetting(L"MemoryListsWindowPosition", NULL, hwndDlg); PhRegisterDialog(hwndDlg); + + PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport); } break; case WM_DESTROY: diff --git a/ProcessHacker/procprp.c b/ProcessHacker/procprp.c index 308f772f9ad9..fdfddbf9097d 100644 --- a/ProcessHacker/procprp.c +++ b/ProcessHacker/procprp.c @@ -177,6 +177,8 @@ INT CALLBACK PhpPropSheetProc( PhSetWindowContext(hwndDlg, 0xF, propSheetContext); SetWindowLongPtr(hwndDlg, GWLP_WNDPROC, (LONG_PTR)PhpPropSheetWndProc); + PhRegisterWindowCallback(hwndDlg, PH_PLUGIN_WINDOW_EVENT_TYPE_TOPMOST, NULL); + if (MinimumSize.left == -1) { RECT rect; @@ -248,6 +250,8 @@ LRESULT CALLBACK PhpPropSheetWndProc( break; case WM_NCDESTROY: { + PhUnregisterWindowCallback(hwnd); + SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)oldWndProc); PhRemoveWindowContext(hwnd, 0xF); diff --git a/plugins/HardwareDevices/diskdetails.c b/plugins/HardwareDevices/diskdetails.c index d26c3f46ef9d..30d251588615 100644 --- a/plugins/HardwareDevices/diskdetails.c +++ b/plugins/HardwareDevices/diskdetails.c @@ -699,6 +699,8 @@ INT_PTR CALLBACK DiskDriveSmartDetailsDlgProc( PhLoadListViewColumnsFromSetting(SETTING_NAME_SMART_COUNTERS_COLUMNS, context->ListViewHandle); DiskDriveQuerySmart(context); + + PhInitializeWindowTheme(hwndDlg, !!PhGetIntegerSetting(L"EnableThemeSupport")); } break; case WM_SHOWWINDOW: diff --git a/plugins/NetworkTools/NetworkTools.vcxproj b/plugins/NetworkTools/NetworkTools.vcxproj index 73271669ee00..9e81f5632366 100644 --- a/plugins/NetworkTools/NetworkTools.vcxproj +++ b/plugins/NetworkTools/NetworkTools.vcxproj @@ -56,27 +56,27 @@ - iphlpapi.lib;winhttp.lib;ws2_32.lib;uxtheme.lib;%(AdditionalDependencies) - comctl32.dll;gdi32.dll;iphlpapi.dll;winhttp.dll;ws2_32.dll;user32.dll;uxtheme.dll;%(DelayLoadDLLs) + iphlpapi.lib;winhttp.lib;ws2_32.lib;%(AdditionalDependencies) + comctl32.dll;gdi32.dll;iphlpapi.dll;winhttp.dll;ws2_32.dll;user32.dll;%(DelayLoadDLLs) - iphlpapi.lib;winhttp.lib;ws2_32.lib;uxtheme.lib;%(AdditionalDependencies) - comctl32.dll;gdi32.dll;iphlpapi.dll;winhttp.dll;ws2_32.dll;user32.dll;uxtheme.dll;%(DelayLoadDLLs) + iphlpapi.lib;winhttp.lib;ws2_32.lib;%(AdditionalDependencies) + comctl32.dll;gdi32.dll;iphlpapi.dll;winhttp.dll;ws2_32.dll;user32.dll;%(DelayLoadDLLs) - iphlpapi.lib;winhttp.lib;ws2_32.lib;uxtheme.lib;%(AdditionalDependencies) - comctl32.dll;gdi32.dll;iphlpapi.dll;winhttp.dll;ws2_32.dll;user32.dll;uxtheme.dll;%(DelayLoadDLLs) + iphlpapi.lib;winhttp.lib;ws2_32.lib;%(AdditionalDependencies) + comctl32.dll;gdi32.dll;iphlpapi.dll;winhttp.dll;ws2_32.dll;user32.dll;%(DelayLoadDLLs) - iphlpapi.lib;winhttp.lib;ws2_32.lib;uxtheme.lib;%(AdditionalDependencies) - comctl32.dll;gdi32.dll;iphlpapi.dll;winhttp.dll;ws2_32.dll;user32.dll;uxtheme.dll;%(DelayLoadDLLs) + iphlpapi.lib;winhttp.lib;ws2_32.lib;%(AdditionalDependencies) + comctl32.dll;gdi32.dll;iphlpapi.dll;winhttp.dll;ws2_32.dll;user32.dll;%(DelayLoadDLLs) diff --git a/plugins/NetworkTools/nettools.h b/plugins/NetworkTools/nettools.h index 25597642a7b1..da58b79eadda 100644 --- a/plugins/NetworkTools/nettools.h +++ b/plugins/NetworkTools/nettools.h @@ -35,7 +35,6 @@ #include #include #include -#include #include diff --git a/plugins/NetworkTools/ping.c b/plugins/NetworkTools/ping.c index 36ce4c8a92b5..3261f0800dc7 100644 --- a/plugins/NetworkTools/ping.c +++ b/plugins/NetworkTools/ping.c @@ -348,7 +348,7 @@ INT_PTR CALLBACK NetworkPingWndProc( &context->ProcessesUpdatedRegistration ); - EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); + PhInitializeWindowTheme(hwndDlg, !!PhGetIntegerSetting(L"EnableThemeSupport")); } break; case WM_COMMAND: diff --git a/plugins/NetworkTools/tracert.c b/plugins/NetworkTools/tracert.c index 41a9b7851de0..719d73f9ab29 100644 --- a/plugins/NetworkTools/tracert.c +++ b/plugins/NetworkTools/tracert.c @@ -663,7 +663,7 @@ INT_PTR CALLBACK TracertDlgProc( PhReferenceObject(context); PhCreateThread2(NetworkTracertThreadStart, (PVOID)context); - EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); + PhInitializeWindowTheme(hwndDlg, !!PhGetIntegerSetting(L"EnableThemeSupport")); } break; case WM_COMMAND: diff --git a/plugins/NetworkTools/whois.c b/plugins/NetworkTools/whois.c index 686dc934ccb5..e315d3b09443 100644 --- a/plugins/NetworkTools/whois.c +++ b/plugins/NetworkTools/whois.c @@ -418,7 +418,7 @@ INT_PTR CALLBACK NetworkOutputDlgProc( PhCreateThread2(NetworkWhoisThreadStart, (PVOID)context); - EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); + PhInitializeWindowTheme(hwndDlg, !!PhGetIntegerSetting(L"EnableThemeSupport")); } break; case WM_COMMAND: From 6989996a79e3e812cb55bc5f7031f38fd72a271f Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 25 Jul 2018 00:03:25 +1000 Subject: [PATCH 1193/2058] Add process token tab font settings --- ProcessHacker/tokprp.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ProcessHacker/tokprp.c b/ProcessHacker/tokprp.c index 4302d6a306e1..5b8a23fc11c2 100644 --- a/ProcessHacker/tokprp.c +++ b/ProcessHacker/tokprp.c @@ -589,6 +589,7 @@ INT_PTR CALLBACK PhpTokenPageProc( PhAddListViewGroup(tokenPageContext->ListViewHandle, PH_PROCESS_TOKEN_CATEGORY_PRIVILEGES, L"Privileges"); PhAddListViewGroup(tokenPageContext->ListViewHandle, PH_PROCESS_TOKEN_CATEGORY_GROUPS, L"Groups"); ListView_SetImageList(tokenPageContext->ListViewHandle, tokenPageContext->ListViewImageList, LVSIL_SMALL); + PhRegisterWindowCallback(tokenPageContext->ListViewHandle, PH_PLUGIN_WINDOW_EVENT_TYPE_FONT, NULL); PhSetDialogItemText(hwndDlg, IDC_USER, L"Unknown"); PhSetDialogItemText(hwndDlg, IDC_USERSID, L"Unknown"); @@ -705,6 +706,7 @@ INT_PTR CALLBACK PhpTokenPageProc( PhpTokenPageFreeListViewEntries(tokenPageContext); + PhUnregisterWindowCallback(tokenPageContext->ListViewHandle); PhSaveListViewColumnsToSetting(L"TokenGroupsListViewColumns", tokenPageContext->ListViewHandle); if (tokenPageContext->Groups) PhFree(tokenPageContext->Groups); From ac49afeb92c92115fbf20ce80ab10dd266b5bfba Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 25 Jul 2018 00:04:40 +1000 Subject: [PATCH 1194/2058] ExtendedTools: Remove gpu nodes window close button --- plugins/ExtendedTools/ExtendedTools.rc | 3 +-- plugins/ExtendedTools/gpunodes.c | 6 +----- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/plugins/ExtendedTools/ExtendedTools.rc b/plugins/ExtendedTools/ExtendedTools.rc index 445ca8fb8fe9..78bbd69af1ae 100644 --- a/plugins/ExtendedTools/ExtendedTools.rc +++ b/plugins/ExtendedTools/ExtendedTools.rc @@ -249,8 +249,7 @@ STYLE DS_SETFONT | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS CAPTION "GPU Nodes" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN - LTEXT "Graph layout",IDC_LAYOUT,3,3,311,161,NOT WS_VISIBLE - DEFPUSHBUTTON "OK",IDOK,265,166,50,14 + LTEXT "Graph layout",IDC_LAYOUT,3,3,311,177,NOT WS_VISIBLE END IDD_PROCGPU_PANEL DIALOGEX 0, 0, 248, 46 diff --git a/plugins/ExtendedTools/gpunodes.c b/plugins/ExtendedTools/gpunodes.c index fde3b1e93c1e..8e1cd20c54e3 100644 --- a/plugins/ExtendedTools/gpunodes.c +++ b/plugins/ExtendedTools/gpunodes.c @@ -136,7 +136,6 @@ INT_PTR CALLBACK EtpGpuNodesDlgProc( SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhInstanceHandle, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); PhInitializeLayoutManager(&LayoutManager, hwndDlg); - PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDOK), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); LayoutMargin = PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDC_LAYOUT), NULL, PH_ANCHOR_ALL)->Margin; GraphHandle = PhAllocate(sizeof(HWND) * EtGpuTotalNodeCount); @@ -284,10 +283,7 @@ INT_PTR CALLBACK EtpGpuNodesDlgProc( switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDCANCEL: - case IDOK: - { - DestroyWindow(hwndDlg); - } + DestroyWindow(hwndDlg); break; } } From bdb3b4ca57033f7fafb23a6292a46bace7d94477 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 25 Jul 2018 00:08:55 +1000 Subject: [PATCH 1195/2058] Fix changing theme modes --- ProcessHacker/options.c | 2 ++ phlib/theme.c | 44 +++++++++++++++++++++-------------------- 2 files changed, 25 insertions(+), 21 deletions(-) diff --git a/ProcessHacker/options.c b/ProcessHacker/options.c index 06d00e221eba..9f428737d9f9 100644 --- a/ProcessHacker/options.c +++ b/ProcessHacker/options.c @@ -1046,6 +1046,8 @@ static VOID PhpOptionsNotifyChangeCallback( PhReloadSettingsProcessTreeList(); PhSiNotifyChangeSettings(); + PhReInitializeWindowTheme(PhMainWndHandle); + if (RestartRequired) { if (PhShowMessage2( diff --git a/phlib/theme.c b/phlib/theme.c index 060d13313819..9b0ad86851d9 100644 --- a/phlib/theme.c +++ b/phlib/theme.c @@ -164,8 +164,10 @@ LRESULT CALLBACK PhpThemeWindowGroupBoxSubclassProc( switch (uMsg) { case WM_DESTROY: - PhRemoveWindowContext(hWnd, SHRT_MAX); - SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)oldWndProc); + { + PhRemoveWindowContext(hWnd, SHRT_MAX); + SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)oldWndProc); + } break; case WM_ERASEBKGND: return 1; @@ -292,25 +294,25 @@ VOID PhReInitializeWindowTheme( 0 ); - //HWND currentWindow = NULL; - // - //do - //{ - // if (currentWindow = FindWindowEx(NULL, currentWindow, NULL, NULL)) - // { - // ULONG processID = 0; - // - // GetWindowThreadProcessId(currentWindow, &processID); - // - // if (UlongToHandle(processID) == NtCurrentProcessId()) - // { - // if (currentWindow != WindowHandle) - // { - // InvalidateRect(currentWindow, NULL, TRUE); - // } - // } - // } - //} while (currentWindow); + HWND currentWindow = NULL; + + do + { + if (currentWindow = FindWindowEx(NULL, currentWindow, NULL, NULL)) + { + ULONG processID = 0; + + GetWindowThreadProcessId(currentWindow, &processID); + + if (UlongToHandle(processID) == NtCurrentProcessId()) + { + if (currentWindow != WindowHandle) + { + InvalidateRect(currentWindow, NULL, TRUE); + } + } + } + } while (currentWindow); InvalidateRect(WindowHandle, NULL, FALSE); } From 6f61d0b2d79b61cb9e1b23d66e35e23d56920057 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 25 Jul 2018 00:13:17 +1000 Subject: [PATCH 1196/2058] Update sdk includes --- ProcessHacker/about.c | 1 - ProcessHacker/affinity.c | 2 -- ProcessHacker/chcol.c | 3 --- ProcessHacker/chdlg.c | 3 --- ProcessHacker/chproc.c | 1 - ProcessHacker/colsetmgr.c | 1 - ProcessHacker/findobj.c | 3 --- ProcessHacker/gdihndl.c | 1 - ProcessHacker/hidnproc.c | 1 - ProcessHacker/hndlstat.c | 1 - ProcessHacker/infodlg.c | 1 - ProcessHacker/jobprp.c | 1 - ProcessHacker/logwnd.c | 2 -- ProcessHacker/mainwnd.c | 1 - ProcessHacker/mdump.c | 1 - ProcessHacker/memedit.c | 3 --- ProcessHacker/memlists.c | 1 - ProcessHacker/memprot.c | 3 --- ProcessHacker/memrslt.c | 3 --- ProcessHacker/memsrch.c | 3 --- ProcessHacker/miniinfo.c | 1 - ProcessHacker/mtgndlg.c | 1 - ProcessHacker/options.c | 1 - ProcessHacker/tokprp.c | 1 - phlib/extlv.c | 3 --- phlib/graph.c | 2 -- phlib/guisup.c | 1 - phlib/hexedit.c | 16 +++++----------- phnt/include/phnt_windows.h | 1 + tools/peview/include/peview.h | 1 - tools/peview/searchbox.c | 1 - 31 files changed, 6 insertions(+), 59 deletions(-) diff --git a/ProcessHacker/about.c b/ProcessHacker/about.c index 674914134708..a22f52282131 100644 --- a/ProcessHacker/about.c +++ b/ProcessHacker/about.c @@ -35,7 +35,6 @@ #include #include -#include #include static HWND PhAboutWindowHandle = NULL; diff --git a/ProcessHacker/affinity.c b/ProcessHacker/affinity.c index a46695abf7b9..408a5b671f18 100644 --- a/ProcessHacker/affinity.c +++ b/ProcessHacker/affinity.c @@ -28,8 +28,6 @@ #include -#include - #include #include diff --git a/ProcessHacker/chcol.c b/ProcessHacker/chcol.c index 96b422507398..bbe58a5f8f68 100644 --- a/ProcessHacker/chcol.c +++ b/ProcessHacker/chcol.c @@ -21,9 +21,6 @@ */ #include - -#include - #include typedef struct _COLUMNS_DIALOG_CONTEXT diff --git a/ProcessHacker/chdlg.c b/ProcessHacker/chdlg.c index 7f511969f748..70f2793ad0cc 100644 --- a/ProcessHacker/chdlg.c +++ b/ProcessHacker/chdlg.c @@ -21,9 +21,6 @@ */ #include - -#include - #include typedef struct _CHOICE_DIALOG_CONTEXT diff --git a/ProcessHacker/chproc.c b/ProcessHacker/chproc.c index b5ca4ce9ba91..c29aeddd32e7 100644 --- a/ProcessHacker/chproc.c +++ b/ProcessHacker/chproc.c @@ -22,7 +22,6 @@ #include #include -#include typedef struct _CHOOSE_PROCESS_DIALOG_CONTEXT { diff --git a/ProcessHacker/colsetmgr.c b/ProcessHacker/colsetmgr.c index 26516aa53d30..2d524f8f8df4 100644 --- a/ProcessHacker/colsetmgr.c +++ b/ProcessHacker/colsetmgr.c @@ -24,7 +24,6 @@ #include #include #include -#include PPH_LIST PhInitializeColumnSetList( _In_ PWSTR SettingName diff --git a/ProcessHacker/findobj.c b/ProcessHacker/findobj.c index a43a132ef168..943186f6ed5d 100644 --- a/ProcessHacker/findobj.c +++ b/ProcessHacker/findobj.c @@ -22,9 +22,6 @@ */ #include - -#include - #include #include #include diff --git a/ProcessHacker/gdihndl.c b/ProcessHacker/gdihndl.c index 762c404c1e4c..b667b7b58331 100644 --- a/ProcessHacker/gdihndl.c +++ b/ProcessHacker/gdihndl.c @@ -23,7 +23,6 @@ #include #include #include -#include typedef struct _GDI_HANDLES_CONTEXT { diff --git a/ProcessHacker/hidnproc.c b/ProcessHacker/hidnproc.c index 6a7ed098c030..31db1d5e4a62 100644 --- a/ProcessHacker/hidnproc.c +++ b/ProcessHacker/hidnproc.c @@ -43,7 +43,6 @@ #include #include -#include #include diff --git a/ProcessHacker/hndlstat.c b/ProcessHacker/hndlstat.c index 15c9e45bd720..c299d533c01d 100644 --- a/ProcessHacker/hndlstat.c +++ b/ProcessHacker/hndlstat.c @@ -23,7 +23,6 @@ #include #include #include -#include typedef struct _HANDLE_STATISTICS_ENTRY { diff --git a/ProcessHacker/infodlg.c b/ProcessHacker/infodlg.c index 5d209dbfb363..7e68454fa77c 100644 --- a/ProcessHacker/infodlg.c +++ b/ProcessHacker/infodlg.c @@ -22,7 +22,6 @@ #include #include -#include typedef struct _INFORMATION_CONTEXT { diff --git a/ProcessHacker/jobprp.c b/ProcessHacker/jobprp.c index c6244eae5766..3184922c2f73 100644 --- a/ProcessHacker/jobprp.c +++ b/ProcessHacker/jobprp.c @@ -25,7 +25,6 @@ #include #include #include -#include typedef struct _JOB_PAGE_CONTEXT { diff --git a/ProcessHacker/logwnd.c b/ProcessHacker/logwnd.c index fc8bf864716e..b570c7e23256 100644 --- a/ProcessHacker/logwnd.c +++ b/ProcessHacker/logwnd.c @@ -23,8 +23,6 @@ #include #include -#include - #include #define WM_PH_LOG_UPDATED (WM_APP + 300) diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index 59c0c7e8ad5f..52ab4918d082 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -25,7 +25,6 @@ #include #include -#include #include #include diff --git a/ProcessHacker/mdump.c b/ProcessHacker/mdump.c index 492dc9665a72..ac3c37967c21 100644 --- a/ProcessHacker/mdump.c +++ b/ProcessHacker/mdump.c @@ -22,7 +22,6 @@ #include -#include #include #include diff --git a/ProcessHacker/memedit.c b/ProcessHacker/memedit.c index 079ac2c343c6..ab0a0b3fdf4a 100644 --- a/ProcessHacker/memedit.c +++ b/ProcessHacker/memedit.c @@ -21,9 +21,6 @@ */ #include - -#include - #include #include diff --git a/ProcessHacker/memlists.c b/ProcessHacker/memlists.c index 4cc62e751e2e..303ea92b70ff 100644 --- a/ProcessHacker/memlists.c +++ b/ProcessHacker/memlists.c @@ -28,7 +28,6 @@ #include #include #include -#include #define MSG_UPDATE (WM_APP + 1) diff --git a/ProcessHacker/memprot.c b/ProcessHacker/memprot.c index 80dfa060a5e3..5182ac42182b 100644 --- a/ProcessHacker/memprot.c +++ b/ProcessHacker/memprot.c @@ -21,9 +21,6 @@ */ #include - -#include - #include #include diff --git a/ProcessHacker/memrslt.c b/ProcessHacker/memrslt.c index 8c0b206e9634..655222f6760f 100644 --- a/ProcessHacker/memrslt.c +++ b/ProcessHacker/memrslt.c @@ -22,9 +22,6 @@ */ #include - -#include - #include #include diff --git a/ProcessHacker/memsrch.c b/ProcessHacker/memsrch.c index bd0e9258ec96..ab64a7e93731 100644 --- a/ProcessHacker/memsrch.c +++ b/ProcessHacker/memsrch.c @@ -22,9 +22,6 @@ */ #include - -#include - #include #include #include diff --git a/ProcessHacker/miniinfo.c b/ProcessHacker/miniinfo.c index 46669acdaa19..2a9493ea0e2b 100644 --- a/ProcessHacker/miniinfo.c +++ b/ProcessHacker/miniinfo.c @@ -27,7 +27,6 @@ #include #include -#include #include #include diff --git a/ProcessHacker/mtgndlg.c b/ProcessHacker/mtgndlg.c index 31127ad8f5ec..f1d708277a41 100644 --- a/ProcessHacker/mtgndlg.c +++ b/ProcessHacker/mtgndlg.c @@ -23,7 +23,6 @@ #include #include -#include typedef struct _MITIGATION_POLICY_ENTRY { diff --git a/ProcessHacker/options.c b/ProcessHacker/options.c index 9f428737d9f9..404f44bd0c37 100644 --- a/ProcessHacker/options.c +++ b/ProcessHacker/options.c @@ -24,7 +24,6 @@ #include #include -#include #include #include diff --git a/ProcessHacker/tokprp.c b/ProcessHacker/tokprp.c index 5b8a23fc11c2..042db2a5b57a 100644 --- a/ProcessHacker/tokprp.c +++ b/ProcessHacker/tokprp.c @@ -31,7 +31,6 @@ #include #include -#include #include typedef enum _PH_PROCESS_TOKEN_CATEGORY diff --git a/phlib/extlv.c b/phlib/extlv.c index 35f442bea4d9..b6076971037d 100644 --- a/phlib/extlv.c +++ b/phlib/extlv.c @@ -28,9 +28,6 @@ */ #include - -#include - #include #define PH_MAX_COMPARE_FUNCTIONS 16 diff --git a/phlib/graph.c b/phlib/graph.c index 350bdf04311b..6808bd0c7dc9 100644 --- a/phlib/graph.c +++ b/phlib/graph.c @@ -22,8 +22,6 @@ */ #include - -#include #include #include diff --git a/phlib/guisup.c b/phlib/guisup.c index e1cb61a89c6b..8d52ab2d7087 100644 --- a/phlib/guisup.c +++ b/phlib/guisup.c @@ -26,7 +26,6 @@ #include #include #include -#include #include diff --git a/phlib/hexedit.c b/phlib/hexedit.c index 4eb36d9b375a..3d2894404874 100644 --- a/phlib/hexedit.c +++ b/phlib/hexedit.c @@ -24,30 +24,24 @@ #include #include #include - #include -#include - // Code originally from http://www.codeguru.com/Cpp/controls/editctrl/article.php/c539 BOOLEAN PhHexEditInitialization( VOID ) { - WNDCLASSEX c = { sizeof(c) }; + WNDCLASSEX c; + memset(&c, 0, sizeof(WNDCLASSEX)); + c.cbSize = sizeof(WNDCLASSEX); + c.lpszClassName = PH_HEXEDIT_CLASSNAME; c.style = CS_GLOBALCLASS; - c.lpfnWndProc = PhpHexEditWndProc; - c.cbClsExtra = 0; c.cbWndExtra = sizeof(PVOID); c.hInstance = PhInstanceHandle; - c.hIcon = NULL; + c.lpfnWndProc = PhpHexEditWndProc; c.hCursor = LoadCursor(NULL, IDC_ARROW); - c.hbrBackground = NULL; - c.lpszMenuName = NULL; - c.lpszClassName = PH_HEXEDIT_CLASSNAME; - c.hIconSm = NULL; if (!RegisterClassEx(&c)) return FALSE; diff --git a/phnt/include/phnt_windows.h b/phnt/include/phnt_windows.h index fbce9252ca61..8f24ddb60f6a 100644 --- a/phnt/include/phnt_windows.h +++ b/phnt/include/phnt_windows.h @@ -6,6 +6,7 @@ #define WIN32_LEAN_AND_MEAN #define WIN32_NO_STATUS #include +#include #undef WIN32_NO_STATUS #include #include diff --git a/tools/peview/include/peview.h b/tools/peview/include/peview.h index 105ddca4d85c..27cfedee9054 100644 --- a/tools/peview/include/peview.h +++ b/tools/peview/include/peview.h @@ -37,7 +37,6 @@ #include #include -#include #include "resource.h" diff --git a/tools/peview/searchbox.c b/tools/peview/searchbox.c index c3e78f5ba471..b616faa1199b 100644 --- a/tools/peview/searchbox.c +++ b/tools/peview/searchbox.c @@ -25,7 +25,6 @@ #include #define CINTERFACE #define COBJMACROS -#include #include #include #include From 31a1c77c6ea1dca766e6f3029662e0c87b803ca7 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 25 Jul 2018 00:15:10 +1000 Subject: [PATCH 1197/2058] Update phlib theme exports --- ProcessHacker/ProcessHacker.def | 1 + phlib/include/guisup.h | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/ProcessHacker/ProcessHacker.def b/ProcessHacker/ProcessHacker.def index 3be1da55191d..5be4bccf13a1 100644 --- a/ProcessHacker/ProcessHacker.def +++ b/ProcessHacker/ProcessHacker.def @@ -526,6 +526,7 @@ EXPORTS PhApplicationFont PhTreeWindowFont PhInitializeWindowTheme + PhReInitializeWindowTheme ; hndlinfo PhEnumObjectTypes diff --git a/phlib/include/guisup.h b/phlib/include/guisup.h index 9fcb4df40a8a..c0b11b8b0b28 100644 --- a/phlib/include/guisup.h +++ b/phlib/include/guisup.h @@ -907,6 +907,13 @@ PhInitializeWindowTheme( _In_ BOOLEAN EnableThemeSupport ); +PHLIBAPI +VOID +NTAPI +PhReInitializeWindowTheme( + _In_ HWND WindowHandle + ); + FORCEINLINE HFONT PhDuplicateFontWithNewHeight( From d798340d9de204a751d856803017a861ecaff90e Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 25 Jul 2018 00:44:46 +1000 Subject: [PATCH 1198/2058] Update phlib headers --- ProcessHacker/itemtips.c | 2 -- ProcessHacker/miniinfo.c | 1 - ProcessHacker/netstk.c | 1 - ProcessHacker/ntobjprp.c | 2 -- ProcessHacker/plugman.c | 1 - ProcessHacker/procprp.c | 3 --- ProcessHacker/prpgenv.c | 1 - ProcessHacker/prpggen.c | 2 -- ProcessHacker/prpghndl.c | 2 -- ProcessHacker/prpgmem.c | 2 -- ProcessHacker/prpgmod.c | 1 - ProcessHacker/prpgwmi.c | 3 --- ProcessHacker/runas.c | 4 +--- ProcessHacker/searchbox.c | 3 --- ProcessHacker/sessmsg.c | 2 +- ProcessHacker/sessshad.c | 1 - ProcessHacker/splitter.c | 1 - ProcessHacker/srvcr.c | 3 --- ProcessHacker/srvctl.c | 2 -- ProcessHacker/srvprp.c | 2 -- ProcessHacker/sysinfo.c | 1 - ProcessHacker/syssccpu.c | 1 - phlib/appresolver.c | 2 -- phlib/dspick.c | 8 +++----- phlib/theme.c | 1 - phlib/treenew.c | 2 -- phlib/util.c | 4 ---- phnt/include/phnt_windows.h | 18 ++++++++++++++++++ plugins/DotNetTools/clrsup.h | 4 ---- plugins/DotNetTools/dn.h | 3 --- plugins/ExtendedNotifications/main.c | 2 +- plugins/ExtendedServices/extsrv.h | 1 - plugins/ExtendedTools/exttools.h | 5 +---- plugins/ExtendedTools/gpumon.c | 1 - plugins/ExtendedTools/treeext.c | 2 -- plugins/HardwareDevices/devices.h | 4 ---- plugins/HardwareDevices/ndis.c | 1 + plugins/HardwareDevices/netoptions.c | 1 - plugins/NetworkTools/nettools.h | 3 --- plugins/OnlineChecks/onlnchk.h | 3 --- plugins/ToolStatus/toolstatus.h | 5 +---- plugins/Updater/updater.h | 4 ---- plugins/UserNotes/usernotes.h | 1 - plugins/WindowExplorer/wndexp.h | 2 -- plugins/WindowExplorer/wndprp.c | 1 - tools/peview/misc.c | 6 ++---- 46 files changed, 29 insertions(+), 96 deletions(-) diff --git a/ProcessHacker/itemtips.c b/ProcessHacker/itemtips.c index 6c7e536de13e..61e1db6eff6f 100644 --- a/ProcessHacker/itemtips.c +++ b/ProcessHacker/itemtips.c @@ -22,8 +22,6 @@ #include -#define CINTERFACE -#define COBJMACROS #include #include diff --git a/ProcessHacker/miniinfo.c b/ProcessHacker/miniinfo.c index 2a9493ea0e2b..bcb857c65571 100644 --- a/ProcessHacker/miniinfo.c +++ b/ProcessHacker/miniinfo.c @@ -26,7 +26,6 @@ #include #include -#include #include #include diff --git a/ProcessHacker/netstk.c b/ProcessHacker/netstk.c index 5ab9e2c76ce8..2854b06a8eaf 100644 --- a/ProcessHacker/netstk.c +++ b/ProcessHacker/netstk.c @@ -23,7 +23,6 @@ #include #include #include -#include typedef struct NETWORK_STACK_CONTEXT { diff --git a/ProcessHacker/ntobjprp.c b/ProcessHacker/ntobjprp.c index e74f956951c0..ff950c13fbc1 100644 --- a/ProcessHacker/ntobjprp.c +++ b/ProcessHacker/ntobjprp.c @@ -26,8 +26,6 @@ #include #include -#include - typedef struct _COMMON_PAGE_CONTEXT { PPH_OPEN_OBJECT OpenObject; diff --git a/ProcessHacker/plugman.c b/ProcessHacker/plugman.c index 3faa63da81f5..56113f6d8685 100644 --- a/ProcessHacker/plugman.c +++ b/ProcessHacker/plugman.c @@ -27,7 +27,6 @@ #include #include #include -#include #define WM_PH_PLUGINS_SHOWDIALOG (WM_APP + 401) #define WM_PH_PLUGINS_SHOWPROPERTIES (WM_APP + 402) diff --git a/ProcessHacker/procprp.c b/ProcessHacker/procprp.c index fdfddbf9097d..e8d1be0ddbe3 100644 --- a/ProcessHacker/procprp.c +++ b/ProcessHacker/procprp.c @@ -24,9 +24,6 @@ #include #include -#include -#include - #include #include diff --git a/ProcessHacker/prpgenv.c b/ProcessHacker/prpgenv.c index 481de4af9b6d..d5701a58e575 100644 --- a/ProcessHacker/prpgenv.c +++ b/ProcessHacker/prpgenv.c @@ -33,7 +33,6 @@ #include #include -#include #include typedef enum _ENVIRONMENT_TREE_MENU_ITEM diff --git a/ProcessHacker/prpggen.c b/ProcessHacker/prpggen.c index fc699c067078..2199d52b71e2 100644 --- a/ProcessHacker/prpggen.c +++ b/ProcessHacker/prpggen.c @@ -24,8 +24,6 @@ #include #include -#include - #include #include diff --git a/ProcessHacker/prpghndl.c b/ProcessHacker/prpghndl.c index e6d70fb85778..b88b2b9783b5 100644 --- a/ProcessHacker/prpghndl.c +++ b/ProcessHacker/prpghndl.c @@ -25,8 +25,6 @@ #include #include -#include - #include #include #include diff --git a/ProcessHacker/prpgmem.c b/ProcessHacker/prpgmem.c index 271efb38232e..ca801506959a 100644 --- a/ProcessHacker/prpgmem.c +++ b/ProcessHacker/prpgmem.c @@ -25,8 +25,6 @@ #include #include -#include - #include #include diff --git a/ProcessHacker/prpgmod.c b/ProcessHacker/prpgmod.c index 701b4ac11be4..1e1610a4da65 100644 --- a/ProcessHacker/prpgmod.c +++ b/ProcessHacker/prpgmod.c @@ -26,7 +26,6 @@ #include #include -#include #include #include diff --git a/ProcessHacker/prpgwmi.c b/ProcessHacker/prpgwmi.c index 7219863531d0..deeadc635d34 100644 --- a/ProcessHacker/prpgwmi.c +++ b/ProcessHacker/prpgwmi.c @@ -28,9 +28,6 @@ #include #include -#define CINTERFACE -#define COBJMACROS -#include #include #include diff --git a/ProcessHacker/runas.c b/ProcessHacker/runas.c index d3612349aa89..a3e41a348f50 100644 --- a/ProcessHacker/runas.c +++ b/ProcessHacker/runas.c @@ -62,10 +62,8 @@ #include #include -#include #include #include -#include #include #include @@ -941,7 +939,7 @@ INT_PTR CALLBACK PhpRunAsDlgProc( //if (!PhGetOwnTokenAttributes().Elevated) // SendMessage(GetDlgItem(hwndDlg, IDOK), BCM_SETSHIELD, 0, TRUE); - EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); + PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport); } break; case WM_DESTROY: diff --git a/ProcessHacker/searchbox.c b/ProcessHacker/searchbox.c index 436e91e94d8f..4e645806c560 100644 --- a/ProcessHacker/searchbox.c +++ b/ProcessHacker/searchbox.c @@ -23,9 +23,6 @@ #include #include -#define CINTERFACE -#define COBJMACROS -#include #include #include #include diff --git a/ProcessHacker/sessmsg.c b/ProcessHacker/sessmsg.c index e090c21de114..053e2751c88e 100644 --- a/ProcessHacker/sessmsg.c +++ b/ProcessHacker/sessmsg.c @@ -22,7 +22,7 @@ #include #include -#include + #include #define SIP(String, Integer) { (String), (PVOID)(Integer) } diff --git a/ProcessHacker/sessshad.c b/ProcessHacker/sessshad.c index 23b156373480..3d4994b7b6e2 100644 --- a/ProcessHacker/sessshad.c +++ b/ProcessHacker/sessshad.c @@ -23,7 +23,6 @@ #include #include -#include #include #define SIP(String, Integer) { (String), (PVOID)(Integer) } diff --git a/ProcessHacker/splitter.c b/ProcessHacker/splitter.c index 74a9eb79a3e9..7ba2d0246737 100644 --- a/ProcessHacker/splitter.c +++ b/ProcessHacker/splitter.c @@ -24,7 +24,6 @@ #include #include #include -#include #define SPLITTER_PADDING 6 diff --git a/ProcessHacker/srvcr.c b/ProcessHacker/srvcr.c index d52a209e80ee..dedb5ec21a35 100644 --- a/ProcessHacker/srvcr.c +++ b/ProcessHacker/srvcr.c @@ -21,9 +21,6 @@ */ #include - -#include - #include #include diff --git a/ProcessHacker/srvctl.c b/ProcessHacker/srvctl.c index 5c0819d4b199..28d178b6d6dc 100644 --- a/ProcessHacker/srvctl.c +++ b/ProcessHacker/srvctl.c @@ -29,8 +29,6 @@ #include #include -#include - typedef struct _PH_SERVICES_CONTEXT { PPH_SERVICE_ITEM *Services; diff --git a/ProcessHacker/srvprp.c b/ProcessHacker/srvprp.c index 9597b2442ccf..bf6f8eda2952 100644 --- a/ProcessHacker/srvprp.c +++ b/ProcessHacker/srvprp.c @@ -22,8 +22,6 @@ #include -#include - #include #include #include diff --git a/ProcessHacker/sysinfo.c b/ProcessHacker/sysinfo.c index d068873680fe..d0df050a3d05 100644 --- a/ProcessHacker/sysinfo.c +++ b/ProcessHacker/sysinfo.c @@ -52,7 +52,6 @@ #include #include -#include #include #include diff --git a/ProcessHacker/syssccpu.c b/ProcessHacker/syssccpu.c index 6b7e6567670b..645db6ce55af 100644 --- a/ProcessHacker/syssccpu.c +++ b/ProcessHacker/syssccpu.c @@ -26,7 +26,6 @@ #include #include -#include #include #include diff --git a/phlib/appresolver.c b/phlib/appresolver.c index 0591fec3dbc9..6dd5018de2e6 100644 --- a/phlib/appresolver.c +++ b/phlib/appresolver.c @@ -20,8 +20,6 @@ * along with Process Hacker. If not, see . */ -#define COBJMACROS -#define CINTERFACE #include #include diff --git a/phlib/dspick.c b/phlib/dspick.c index 5bbc7f1cad6e..b5b410b751f7 100644 --- a/phlib/dspick.c +++ b/phlib/dspick.c @@ -24,16 +24,14 @@ #include #include -#define CINTERFACE -#define COBJMACROS #include #include #include -#define IDataObject_AddRef(This) ((This)->lpVtbl->AddRef(This)) -#define IDataObject_Release(This) ((This)->lpVtbl->Release(This)) -#define IDataObject_GetData(This, pformatetcIn, pmedium) ((This)->lpVtbl->GetData(This, pformatetcIn, pmedium)) +//#define IDataObject_AddRef(This) ((This)->lpVtbl->AddRef(This)) +//#define IDataObject_Release(This) ((This)->lpVtbl->Release(This)) +//#define IDataObject_GetData(This, pformatetcIn, pmedium) ((This)->lpVtbl->GetData(This, pformatetcIn, pmedium)) #define IDsObjectPicker_QueryInterface(This, riid, ppvObject) ((This)->lpVtbl->QueryInterface(This, riid, ppvObject)) #define IDsObjectPicker_AddRef(This) ((This)->lpVtbl->AddRef(This)) diff --git a/phlib/theme.c b/phlib/theme.c index 9b0ad86851d9..11512843ff93 100644 --- a/phlib/theme.c +++ b/phlib/theme.c @@ -29,7 +29,6 @@ #include #include #include -#include BOOLEAN CALLBACK PhpThemeWindowEnumChildWindows( _In_ HWND WindowHandle, diff --git a/phlib/treenew.c b/phlib/treenew.c index 204c717ad202..2744f71ea06a 100644 --- a/phlib/treenew.c +++ b/phlib/treenew.c @@ -46,10 +46,8 @@ #include #include -#include #include - #include static PVOID ComCtl32Handle; diff --git a/phlib/util.c b/phlib/util.c index aa7f0a65ebb3..1fc4a59216b3 100644 --- a/phlib/util.c +++ b/phlib/util.c @@ -26,11 +26,7 @@ #include #include #include -#define CINTERFACE -#define COBJMACROS #include -#undef CINTERFACE -#undef COBJMACROS #include #include diff --git a/phnt/include/phnt_windows.h b/phnt/include/phnt_windows.h index 8f24ddb60f6a..5d28bc57d79b 100644 --- a/phnt/include/phnt_windows.h +++ b/phnt/include/phnt_windows.h @@ -3,8 +3,26 @@ // This header file provides access to Win32, plus NTSTATUS values and some access mask values. +#ifndef CINTERFACE +#define CINTERFACE +#endif + +#ifndef COBJMACROS +#define COBJMACROS +#endif + +#ifndef INITGUID +#define INITGUID +#endif + +#ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN +#endif + +#ifndef WIN32_NO_STATUS #define WIN32_NO_STATUS +#endif + #include #include #undef WIN32_NO_STATUS diff --git a/plugins/DotNetTools/clrsup.h b/plugins/DotNetTools/clrsup.h index 82a0b13962ae..8acdb28ee26e 100644 --- a/plugins/DotNetTools/clrsup.h +++ b/plugins/DotNetTools/clrsup.h @@ -23,11 +23,7 @@ #ifndef CLRSUP_H #define CLRSUP_H -#define CINTERFACE -#define COBJMACROS #include "clr/clrdata.h" -#undef CINTERFACE -#undef COBJMACROS // General interfaces diff --git a/plugins/DotNetTools/dn.h b/plugins/DotNetTools/dn.h index 95b2a6323cac..23a3993e09ce 100644 --- a/plugins/DotNetTools/dn.h +++ b/plugins/DotNetTools/dn.h @@ -23,11 +23,8 @@ #ifndef DN_H #define DN_H -#define CINTERFACE -#define COBJMACROS #include #include -#include #include "resource.h" diff --git a/plugins/ExtendedNotifications/main.c b/plugins/ExtendedNotifications/main.c index e9905e86acf7..a7b01133b27a 100644 --- a/plugins/ExtendedNotifications/main.c +++ b/plugins/ExtendedNotifications/main.c @@ -24,7 +24,7 @@ #include #include #include -#include + #include "extnoti.h" #include "resource.h" #include "gntp-send/growl.h" diff --git a/plugins/ExtendedServices/extsrv.h b/plugins/ExtendedServices/extsrv.h index 45ee3d50f048..9c4d768a6f75 100644 --- a/plugins/ExtendedServices/extsrv.h +++ b/plugins/ExtendedServices/extsrv.h @@ -3,7 +3,6 @@ #include #include -#include #include "resource.h" diff --git a/plugins/ExtendedTools/exttools.h b/plugins/ExtendedTools/exttools.h index deed500a2461..f92e234f60f7 100644 --- a/plugins/ExtendedTools/exttools.h +++ b/plugins/ExtendedTools/exttools.h @@ -4,14 +4,11 @@ #include #include #include -#include #include #include "resource.h" -#define CINTERFACE -#define COBJMACROS -#include +#include #include "d3dkmt.h" extern PPH_PLUGIN PluginInstance; diff --git a/plugins/ExtendedTools/gpumon.c b/plugins/ExtendedTools/gpumon.c index 893b13ceb3cf..36ccc352daa9 100644 --- a/plugins/ExtendedTools/gpumon.c +++ b/plugins/ExtendedTools/gpumon.c @@ -21,7 +21,6 @@ * along with Process Hacker. If not, see . */ -#define INITGUID #include "exttools.h" #include #include diff --git a/plugins/ExtendedTools/treeext.c b/plugins/ExtendedTools/treeext.c index 345019c24c8f..d24fddb8a16a 100644 --- a/plugins/ExtendedTools/treeext.c +++ b/plugins/ExtendedTools/treeext.c @@ -21,8 +21,6 @@ */ #include "exttools.h" -#define CINTERFACE -#define COBJMACROS #include LONG EtpProcessTreeNewSortFunction( diff --git a/plugins/HardwareDevices/devices.h b/plugins/HardwareDevices/devices.h index d6f526d471d1..d29381554152 100644 --- a/plugins/HardwareDevices/devices.h +++ b/plugins/HardwareDevices/devices.h @@ -33,14 +33,10 @@ #define SETTING_NAME_DISK_COUNTERS_COLUMNS (PLUGIN_NAME L".DiskListColumns") #define SETTING_NAME_SMART_COUNTERS_COLUMNS (PLUGIN_NAME L".SmartListColumns") -#define CINTERFACE -#define COBJMACROS #include #include #include -#include - #include #include #include diff --git a/plugins/HardwareDevices/ndis.c b/plugins/HardwareDevices/ndis.c index 512527d787b9..45d3e4d55c0e 100644 --- a/plugins/HardwareDevices/ndis.c +++ b/plugins/HardwareDevices/ndis.c @@ -21,6 +21,7 @@ */ #include "devices.h" +#include #include PVOID IphlpHandle = NULL; diff --git a/plugins/HardwareDevices/netoptions.c b/plugins/HardwareDevices/netoptions.c index 21a96327e8c6..6e09056252f6 100644 --- a/plugins/HardwareDevices/netoptions.c +++ b/plugins/HardwareDevices/netoptions.c @@ -21,7 +21,6 @@ * along with Process Hacker. If not, see . */ -#define INITGUID #include "devices.h" #include #include diff --git a/plugins/NetworkTools/nettools.h b/plugins/NetworkTools/nettools.h index da58b79eadda..2cea48acc746 100644 --- a/plugins/NetworkTools/nettools.h +++ b/plugins/NetworkTools/nettools.h @@ -24,15 +24,12 @@ #ifndef _NET_TOOLS_H_ #define _NET_TOOLS_H_ -#define CINTERFACE -#define COBJMACROS #include #include #include #include #include -#include #include #include diff --git a/plugins/OnlineChecks/onlnchk.h b/plugins/OnlineChecks/onlnchk.h index 10b1c6ed7fe8..662c9f214f12 100644 --- a/plugins/OnlineChecks/onlnchk.h +++ b/plugins/OnlineChecks/onlnchk.h @@ -24,8 +24,6 @@ #ifndef ONLNCHK_H #define ONLNCHK_H -#define CINTERFACE -#define COBJMACROS #include #include #include @@ -36,7 +34,6 @@ #include #include -#include #include "resource.h" #include "db.h" diff --git a/plugins/ToolStatus/toolstatus.h b/plugins/ToolStatus/toolstatus.h index 391f5a9cdeb3..6ea6bcdd7092 100644 --- a/plugins/ToolStatus/toolstatus.h +++ b/plugins/ToolStatus/toolstatus.h @@ -24,14 +24,11 @@ #ifndef _TOOLSTATUS_H #define _TOOLSTATUS_H -#define CINTERFACE -#define COBJMACROS -#define INITGUID #include #include #include #include -#include + #include #include diff --git a/plugins/Updater/updater.h b/plugins/Updater/updater.h index d0ffba8c625f..6742f7e2cdf3 100644 --- a/plugins/Updater/updater.h +++ b/plugins/Updater/updater.h @@ -23,9 +23,6 @@ #ifndef __UPDATER_H__ #define __UPDATER_H__ -#define CINTERFACE -#define COBJMACROS -#define INITGUID #include #include #include @@ -33,7 +30,6 @@ #include #include -#include #include #include diff --git a/plugins/UserNotes/usernotes.h b/plugins/UserNotes/usernotes.h index afe98aa95911..645c3077d065 100644 --- a/plugins/UserNotes/usernotes.h +++ b/plugins/UserNotes/usernotes.h @@ -29,7 +29,6 @@ #include #include -#include #include #include diff --git a/plugins/WindowExplorer/wndexp.h b/plugins/WindowExplorer/wndexp.h index a16a72386f84..e77a7c45121e 100644 --- a/plugins/WindowExplorer/wndexp.h +++ b/plugins/WindowExplorer/wndexp.h @@ -8,8 +8,6 @@ #include -#include - #include "resource.h" #include "wndtree.h" diff --git a/plugins/WindowExplorer/wndprp.c b/plugins/WindowExplorer/wndprp.c index e4c5d065fd7f..8d19d487a161 100644 --- a/plugins/WindowExplorer/wndprp.c +++ b/plugins/WindowExplorer/wndprp.c @@ -27,7 +27,6 @@ #include "resource.h" #include #include -#include #define NUMBER_OF_PAGES 4 #define WEM_RESOLVE_DONE (WM_APP + 1234) diff --git a/tools/peview/misc.c b/tools/peview/misc.c index fc036c831520..5551683d9201 100644 --- a/tools/peview/misc.c +++ b/tools/peview/misc.c @@ -20,12 +20,10 @@ * along with Process Hacker. If not, see . */ -#define CINTERFACE -#define COBJMACROS #include + #include -#undef CINTERFACE -#undef COBJMACROS + #include static GUID CLSID_ShellLink_I = { 0x00021401, 0x0000, 0x0000, { 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46 } }; From fe2822cc88791ac23aeaaa9e4cf8eb24fcc428c9 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 25 Jul 2018 00:47:52 +1000 Subject: [PATCH 1199/2058] Add initial listview theme support --- phlib/theme.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/phlib/theme.c b/phlib/theme.c index 11512843ff93..831a05193dd5 100644 --- a/phlib/theme.c +++ b/phlib/theme.c @@ -370,7 +370,9 @@ BOOLEAN CALLBACK PhpThemeWindowEnumChildWindows( } else if (PhEqualStringZ(className, L"SysListView32", FALSE)) { - NOTHING; + ListView_SetBkColor(WindowHandle, RGB(30, 30, 30)); + ListView_SetTextBkColor(WindowHandle, RGB(30, 30, 30)); + ListView_SetTextColor(WindowHandle, RGB(0xff, 0xff, 0xff)); } else if (PhEqualStringZ(className, L"ScrollBar", FALSE)) { From 8fc1b866445e82913ae1c0dd46eb86833c4aad13 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 25 Jul 2018 01:25:07 +1000 Subject: [PATCH 1200/2058] SetupTool: Update to latest sdk --- tools/CustomSetupTool/CustomSetupTool/appsup.c | 2 +- tools/CustomSetupTool/CustomSetupTool/main.c | 14 -------------- 2 files changed, 1 insertion(+), 15 deletions(-) diff --git a/tools/CustomSetupTool/CustomSetupTool/appsup.c b/tools/CustomSetupTool/CustomSetupTool/appsup.c index d2251da295d3..54655f40f367 100644 --- a/tools/CustomSetupTool/CustomSetupTool/appsup.c +++ b/tools/CustomSetupTool/CustomSetupTool/appsup.c @@ -311,7 +311,7 @@ VOID SetupCreateLink( IPersistFile* persistFilePtr = NULL; IPropertyStore* propertyStorePtr; - if (FAILED(CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, &IID_IShellLink, &shellLinkPtr))) + if (FAILED(CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, &IID_IShellLinkW, &shellLinkPtr))) goto CleanupExit; if (FAILED(IShellLinkW_QueryInterface(shellLinkPtr, &IID_IPersistFile, &persistFilePtr))) diff --git a/tools/CustomSetupTool/CustomSetupTool/main.c b/tools/CustomSetupTool/CustomSetupTool/main.c index 271d066bd1e3..4200a23d58f3 100644 --- a/tools/CustomSetupTool/CustomSetupTool/main.c +++ b/tools/CustomSetupTool/CustomSetupTool/main.c @@ -37,19 +37,6 @@ VOID PhUpdateCachedSettings( NOTHING; } -VOID SetupInitializeDpi( - VOID - ) -{ - HDC hdc; - - if (hdc = CreateIC(L"DISPLAY", NULL, NULL, NULL)) - { - PhGlobalDpi = GetDeviceCaps(hdc, LOGPIXELSY); - ReleaseDC(NULL, hdc); - } -} - INT CALLBACK MainPropSheet_Callback( _In_ HWND hwndDlg, _In_ UINT uMsg, @@ -313,7 +300,6 @@ INT WINAPI wWinMain( SetupInitializeMutant(); PhGuiSupportInitialization(); - SetupInitializeDpi(); SetupParseCommandLine(); switch (SetupMode) From 70fa15645d6024030d882a781ac414aa4aff43bf Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 25 Jul 2018 01:30:44 +1000 Subject: [PATCH 1201/2058] SetupTool: Update library dependencies --- .../CustomSetupTool/CustomSetupTool.vcxproj | 4 ++-- tools/CustomSetupTool/CustomSetupTool/include/setup.h | 11 ++--------- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj b/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj index b1db7a0f7826..7a5ea370b908 100644 --- a/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj +++ b/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj @@ -65,7 +65,7 @@ true - uxtheme.lib;winhttp.lib;phlib.lib;ntdll.lib;userenv.lib;%(AdditionalDependencies) + comctl32.lib;uxtheme.lib;winhttp.lib;ntdll.lib;phlib.lib;shlwapi.lib;userenv.lib;windowscodecs.lib;%(AdditionalDependencies) $(SolutionDir)..\..\phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) Windows 6.01 @@ -97,7 +97,7 @@ true true true - uxtheme.lib;winhttp.lib;phlib.lib;ntdll.lib;userenv.lib;%(AdditionalDependencies) + comctl32.lib;uxtheme.lib;winhttp.lib;ntdll.lib;phlib.lib;shlwapi.lib;userenv.lib;windowscodecs.lib;%(AdditionalDependencies) $(SolutionDir)..\..\phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories) Windows 6.01 diff --git a/tools/CustomSetupTool/CustomSetupTool/include/setup.h b/tools/CustomSetupTool/CustomSetupTool/include/setup.h index e27cda0b9918..13f3aea379c8 100644 --- a/tools/CustomSetupTool/CustomSetupTool/include/setup.h +++ b/tools/CustomSetupTool/CustomSetupTool/include/setup.h @@ -23,12 +23,6 @@ #ifndef _SETUP_H #define _SETUP_H -#pragma comment(lib, "Comctl32.lib") -#pragma comment(lib, "Shlwapi.lib") -#pragma comment(lib, "WindowsCodecs.lib") - -#define CINTERFACE -#define COBJMACROS #include #include #include @@ -37,10 +31,9 @@ #include #include -#include -#include +#include #include -#include +#include #include #include From 63243c7a77e3beeb303f0bf35824690056f8d00c Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 25 Jul 2018 02:55:29 +1000 Subject: [PATCH 1202/2058] Add theme support to process properties window --- ProcessHacker/findobj.c | 3 +++ ProcessHacker/mtgndlg.c | 3 +++ ProcessHacker/procprp.c | 2 ++ ProcessHacker/prpgenv.c | 6 +++--- ProcessHacker/prpggen.c | 1 + ProcessHacker/prpghndl.c | 3 +++ ProcessHacker/prpgmem.c | 3 +++ ProcessHacker/prpgmod.c | 5 ++--- ProcessHacker/prpgperf.c | 2 ++ ProcessHacker/prpgstat.c | 3 ++- ProcessHacker/prpgthrd.c | 2 ++ plugins/ExtendedTools/gpuprprp.c | 4 ++++ plugins/ExtendedTools/unldll.c | 2 ++ plugins/ExtendedTools/wswatch.c | 2 ++ plugins/UserNotes/UserNotes.vcxproj | 12 ++++-------- plugins/UserNotes/main.c | 6 ++++-- plugins/UserNotes/usernotes.h | 2 -- plugins/WindowExplorer/wnddlg.c | 4 ++++ tools/peview/searchbox.c | 2 -- 19 files changed, 46 insertions(+), 21 deletions(-) diff --git a/ProcessHacker/findobj.c b/ProcessHacker/findobj.c index 943186f6ed5d..fd1490fc4664 100644 --- a/ProcessHacker/findobj.c +++ b/ProcessHacker/findobj.c @@ -22,6 +22,7 @@ */ #include +#include #include #include #include @@ -1186,6 +1187,8 @@ INT_PTR CALLBACK PhpFindObjectsDlgProc( Edit_SetSel(context->SearchWindowHandle, 0, -1); Button_SetCheck(GetDlgItem(hwndDlg, IDC_REGEX), PhGetIntegerSetting(L"FindObjRegex") ? BST_CHECKED : BST_UNCHECKED); + + PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport); } break; case WM_DESTROY: diff --git a/ProcessHacker/mtgndlg.c b/ProcessHacker/mtgndlg.c index f1d708277a41..b939477723e2 100644 --- a/ProcessHacker/mtgndlg.c +++ b/ProcessHacker/mtgndlg.c @@ -22,6 +22,7 @@ */ #include +#include #include typedef struct _MITIGATION_POLICY_ENTRY @@ -222,6 +223,8 @@ INT_PTR CALLBACK PhpProcessMitigationPolicyDlgProc( ListView_SetItemState(lvHandle, 0, LVIS_FOCUSED | LVIS_SELECTED, LVIS_FOCUSED | LVIS_SELECTED); PhSetDialogFocus(hwndDlg, lvHandle); + + PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport); } break; case WM_DESTROY: diff --git a/ProcessHacker/procprp.c b/ProcessHacker/procprp.c index e8d1be0ddbe3..233050654d01 100644 --- a/ProcessHacker/procprp.c +++ b/ProcessHacker/procprp.c @@ -174,6 +174,8 @@ INT CALLBACK PhpPropSheetProc( PhSetWindowContext(hwndDlg, 0xF, propSheetContext); SetWindowLongPtr(hwndDlg, GWLP_WNDPROC, (LONG_PTR)PhpPropSheetWndProc); + PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport); + PhRegisterWindowCallback(hwndDlg, PH_PLUGIN_WINDOW_EVENT_TYPE_TOPMOST, NULL); if (MinimumSize.left == -1) diff --git a/ProcessHacker/prpgenv.c b/ProcessHacker/prpgenv.c index d5701a58e575..32b1c65da2fe 100644 --- a/ProcessHacker/prpgenv.c +++ b/ProcessHacker/prpgenv.c @@ -33,8 +33,6 @@ #include #include -#include - typedef enum _ENVIRONMENT_TREE_MENU_ITEM { ENVIRONMENT_TREE_MENU_ITEM_HIDE_PROCESS_TYPE = 1, @@ -335,6 +333,8 @@ INT_PTR CALLBACK PhpEditEnvDlgProc( PhSetDialogItemText(hwndDlg, IDC_VALUE, context->Value ? context->Value : L""); PhSetDialogFocus(hwndDlg, GetDlgItem(hwndDlg, IDCANCEL)); + + PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport); } break; case WM_DESTROY: @@ -1265,7 +1265,7 @@ INT_PTR CALLBACK PhpProcessEnvironmentDlgProc( PhpRefreshEnvironmentList(hwndDlg, context, processItem); - EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); + PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport); } break; case WM_DESTROY: diff --git a/ProcessHacker/prpggen.c b/ProcessHacker/prpggen.c index 2199d52b71e2..5912ce10c777 100644 --- a/ProcessHacker/prpggen.c +++ b/ProcessHacker/prpggen.c @@ -418,6 +418,7 @@ INT_PTR CALLBACK PhpProcessGeneralDlgProc( ShowWindow(GetDlgItem(hwndDlg, IDC_PROCESSTYPELABEL), SW_SHOW); ShowWindow(GetDlgItem(hwndDlg, IDC_PROCESSTYPETEXT), SW_SHOW); #endif + PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport); } break; case WM_DESTROY: diff --git a/ProcessHacker/prpghndl.c b/ProcessHacker/prpghndl.c index b88b2b9783b5..33b4544827f9 100644 --- a/ProcessHacker/prpghndl.c +++ b/ProcessHacker/prpghndl.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include @@ -418,6 +419,8 @@ INT_PTR CALLBACK PhpProcessHandlesDlgProc( PhSetEnabledProvider(&handlesContext->ProviderRegistration, TRUE); PhBoostProvider(&handlesContext->ProviderRegistration, NULL); + + PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport); } break; case WM_DESTROY: diff --git a/ProcessHacker/prpgmem.c b/ProcessHacker/prpgmem.c index ca801506959a..5908bb22dab8 100644 --- a/ProcessHacker/prpgmem.c +++ b/ProcessHacker/prpgmem.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include @@ -361,6 +362,8 @@ INT_PTR CALLBACK PhpProcessMemoryDlgProc( PhLoadSettingsMemoryList(&memoryContext->ListContext); PhpRefreshProcessMemoryList(hwndDlg, propPageContext); + + PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport); } break; case WM_DESTROY: diff --git a/ProcessHacker/prpgmod.c b/ProcessHacker/prpgmod.c index 1e1610a4da65..bd6239edf151 100644 --- a/ProcessHacker/prpgmod.c +++ b/ProcessHacker/prpgmod.c @@ -25,8 +25,6 @@ #include #include -#include - #include #include @@ -35,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -498,7 +497,7 @@ INT_PTR CALLBACK PhpProcessModulesDlgProc( PhSetEnabledProvider(&modulesContext->ProviderRegistration, TRUE); PhBoostProvider(&modulesContext->ProviderRegistration, NULL); - EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); + PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport); } break; case WM_DESTROY: diff --git a/ProcessHacker/prpgperf.c b/ProcessHacker/prpgperf.c index 301aa82eab5d..ea689c1806db 100644 --- a/ProcessHacker/prpgperf.c +++ b/ProcessHacker/prpgperf.c @@ -105,6 +105,8 @@ INT_PTR CALLBACK PhpProcessPerformanceDlgProc( PhSetWindowStyle(performanceContext->IoGraphHandle, WS_BORDER, WS_BORDER); Graph_SetTooltip(performanceContext->IoGraphHandle, TRUE); BringWindowToTop(performanceContext->IoGraphHandle); + + PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport); } break; case WM_DESTROY: diff --git a/ProcessHacker/prpgstat.c b/ProcessHacker/prpgstat.c index 21bf6960e67d..f3f1af914f9c 100644 --- a/ProcessHacker/prpgstat.c +++ b/ProcessHacker/prpgstat.c @@ -22,6 +22,7 @@ */ #include +#include #include #include #include @@ -330,7 +331,7 @@ INT_PTR CALLBACK PhpProcessStatisticsDlgProc( PhpUpdateProcessStatistics(processItem, statisticsContext); - EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); + PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport); } break; case WM_DESTROY: diff --git a/ProcessHacker/prpgthrd.c b/ProcessHacker/prpgthrd.c index 6e5a7c01b0d7..f7a766f50d7e 100644 --- a/ProcessHacker/prpgthrd.c +++ b/ProcessHacker/prpgthrd.c @@ -612,6 +612,8 @@ INT_PTR CALLBACK PhpProcessThreadsDlgProc( PhRegisterThreadProvider(threadsContext->Provider, &threadsContext->ProviderRegistration); SET_BUTTON_ICON(IDC_OPENSTARTMODULE, PH_LOAD_SHARED_ICON_SMALL(PhInstanceHandle, MAKEINTRESOURCE(IDI_FOLDER))); + + PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport); } break; case WM_DESTROY: diff --git a/plugins/ExtendedTools/gpuprprp.c b/plugins/ExtendedTools/gpuprprp.c index 44724a55eb68..4b4f8b5e1e1c 100644 --- a/plugins/ExtendedTools/gpuprprp.c +++ b/plugins/ExtendedTools/gpuprprp.c @@ -104,6 +104,8 @@ INT_PTR CALLBACK GpuDetailsDialogProc( PhCenterWindow(hwndDlg, GetParent(hwndDlg)); GpuPropUpdatePanel(context); + + PhInitializeWindowTheme(hwndDlg, !!PhGetIntegerSetting(L"EnableThemeSupport")); } break; case WM_COMMAND: @@ -530,6 +532,8 @@ INT_PTR CALLBACK EtpGpuPageDlgProc( context, &context->ProcessesUpdatedRegistration ); + + PhInitializeWindowTheme(hwndDlg, !!PhGetIntegerSetting(L"EnableThemeSupport")); } break; case WM_DESTROY: diff --git a/plugins/ExtendedTools/unldll.c b/plugins/ExtendedTools/unldll.c index d76a6d84bf03..5a0657fffa8f 100644 --- a/plugins/ExtendedTools/unldll.c +++ b/plugins/ExtendedTools/unldll.c @@ -276,6 +276,8 @@ INT_PTR CALLBACK EtpUnloadedDllsDlgProc( EndDialog(hwndDlg, IDCANCEL); return FALSE; } + + PhInitializeWindowTheme(hwndDlg, !!PhGetIntegerSetting(L"EnableThemeSupport")); } break; case WM_DESTROY: diff --git a/plugins/ExtendedTools/wswatch.c b/plugins/ExtendedTools/wswatch.c index e8aa9d969a13..25d1df502cbf 100644 --- a/plugins/ExtendedTools/wswatch.c +++ b/plugins/ExtendedTools/wswatch.c @@ -490,6 +490,8 @@ INT_PTR CALLBACK EtpWsWatchDlgProc( { // WS Watch has not yet been enabled for the process. } + + PhInitializeWindowTheme(hwndDlg, !!PhGetIntegerSetting(L"EnableThemeSupport")); } break; case WM_DESTROY: diff --git a/plugins/UserNotes/UserNotes.vcxproj b/plugins/UserNotes/UserNotes.vcxproj index cbeef00a707c..ee6737ebeea7 100644 --- a/plugins/UserNotes/UserNotes.vcxproj +++ b/plugins/UserNotes/UserNotes.vcxproj @@ -53,26 +53,22 @@ - uxtheme.lib;%(AdditionalDependencies) - comctl32.dll;comdlg32.dll;user32.dll;uxtheme.dll;%(DelayLoadDLLs) + comctl32.dll;comdlg32.dll;user32.dll;%(DelayLoadDLLs) - uxtheme.lib;%(AdditionalDependencies) - comctl32.dll;comdlg32.dll;user32.dll;uxtheme.dll;%(DelayLoadDLLs) + comctl32.dll;comdlg32.dll;user32.dll;%(DelayLoadDLLs) - uxtheme.lib;%(AdditionalDependencies) - comctl32.dll;comdlg32.dll;user32.dll;uxtheme.dll;%(DelayLoadDLLs) + comctl32.dll;comdlg32.dll;user32.dll;%(DelayLoadDLLs) - uxtheme.lib;%(AdditionalDependencies) - comctl32.dll;comdlg32.dll;user32.dll;uxtheme.dll;%(DelayLoadDLLs) + comctl32.dll;comdlg32.dll;user32.dll;%(DelayLoadDLLs) diff --git a/plugins/UserNotes/main.c b/plugins/UserNotes/main.c index d695db123185..72cd99506a4b 100644 --- a/plugins/UserNotes/main.c +++ b/plugins/UserNotes/main.c @@ -1674,6 +1674,8 @@ INT_PTR CALLBACK ProcessCommentPageDlgProc( if (!processItem->CommandLine) EnableWindow(context->MatchCommandlineHandle, FALSE); + + PhInitializeWindowTheme(hwndDlg, !!PhGetIntegerSetting(L"EnableThemeSupport")); } break; case WM_DESTROY: @@ -1873,7 +1875,7 @@ INT_PTR CALLBACK ServiceCommentPageDlgProc( PhSetDialogItemText(hwndDlg, IDC_COMMENT, comment->Buffer); - EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); + PhInitializeWindowTheme(hwndDlg, !!PhGetIntegerSetting(L"EnableThemeSupport")); } break; case WM_DESTROY: @@ -1959,7 +1961,7 @@ UINT_PTR CALLBACK ColorDlgHookProc( { PhCenterWindow(hwndDlg, PhMainWndHandle); - EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); + PhInitializeWindowTheme(hwndDlg, !!PhGetIntegerSetting(L"EnableThemeSupport")); } break; } diff --git a/plugins/UserNotes/usernotes.h b/plugins/UserNotes/usernotes.h index 645c3077d065..95576b60d95f 100644 --- a/plugins/UserNotes/usernotes.h +++ b/plugins/UserNotes/usernotes.h @@ -28,9 +28,7 @@ #include #include #include - #include -#include #include "db.h" #include "resource.h" diff --git a/plugins/WindowExplorer/wnddlg.c b/plugins/WindowExplorer/wnddlg.c index dc58e5e8ca47..784332a1ac81 100644 --- a/plugins/WindowExplorer/wnddlg.c +++ b/plugins/WindowExplorer/wnddlg.c @@ -379,6 +379,8 @@ INT_PTR CALLBACK WepWindowsDlgProc( // HACK PhSetDialogFocus(GetParent(hwndDlg), GetDlgItem(GetParent(hwndDlg), IDCANCEL)); + + PhInitializeWindowTheme(hwndDlg, !!PhGetIntegerSetting(L"EnableThemeSupport")); } break; case WM_DESTROY: @@ -816,6 +818,8 @@ INT_PTR CALLBACK WepWindowsPageProc( PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_LIST), NULL, PH_ANCHOR_ALL); WepRefreshWindows(context); + + PhInitializeWindowTheme(hwndDlg, !!PhGetIntegerSetting(L"EnableThemeSupport")); } break; case WM_SHOWWINDOW: diff --git a/tools/peview/searchbox.c b/tools/peview/searchbox.c index b616faa1199b..5ebf3afed508 100644 --- a/tools/peview/searchbox.c +++ b/tools/peview/searchbox.c @@ -23,8 +23,6 @@ #include #include -#define CINTERFACE -#define COBJMACROS #include #include #include From 2340ff3c7c45ab970612a1826a5cee223a0d5e1e Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 25 Jul 2018 02:57:29 +1000 Subject: [PATCH 1203/2058] Add header, listview and tab control theme support --- phlib/theme.c | 605 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 600 insertions(+), 5 deletions(-) diff --git a/phlib/theme.c b/phlib/theme.c index 831a05193dd5..446347495e2a 100644 --- a/phlib/theme.c +++ b/phlib/theme.c @@ -30,6 +30,12 @@ #include #include +typedef struct _PHP_THEME_WINDOW_TAB_CONTEXT +{ + WNDPROC DefaultWindowProc; + BOOLEAN MouseActive; +} PHP_THEME_WINDOW_TAB_CONTEXT, *PPHP_THEME_WINDOW_TAB_CONTEXT; + BOOLEAN CALLBACK PhpThemeWindowEnumChildWindows( _In_ HWND WindowHandle, _In_opt_ PVOID Context @@ -44,6 +50,10 @@ LRESULT PhpWindowThemeDrawButton( _In_ LPNMCUSTOMDRAW DrawInfo ); +LRESULT PhpWindowThemeDrawListViewGroup( + _In_ LPNMLVCUSTOMDRAW DrawInfo + ); + COLORREF PhpThemeWindowForegroundColor = RGB(28, 28, 28); COLORREF PhpThemeWindowBackgroundColor = RGB(64, 64, 64); COLORREF PhpThemeWindowTextColor = RGB(0xff, 0xff, 0xff); @@ -101,7 +111,12 @@ LRESULT CALLBACK PhpThemeWindowSubclassProc( } else if (PhEqualStringZ(className, L"SysListView32", FALSE)) { - NOTHING; + LPNMLVCUSTOMDRAW listViewCustomDraw = (LPNMLVCUSTOMDRAW)customDraw; + + if (listViewCustomDraw->dwItemType == LVCDI_GROUP) + { + return PhpWindowThemeDrawListViewGroup(listViewCustomDraw); + } } } } @@ -254,6 +269,472 @@ LRESULT CALLBACK PhpThemeWindowGroupBoxSubclassProc( return CallWindowProc(oldWndProc, hWnd, uMsg, wParam, lParam); } +LRESULT CALLBACK PhpThemeWindowTabControlWndSubclassProc( + _In_ HWND WindowHandle, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam, + _In_ UINT_PTR uIdSubclass, + _In_ ULONG_PTR dwRefData + ) +{ + PPHP_THEME_WINDOW_TAB_CONTEXT context; + WNDPROC oldWndProc; + + if (!(context = PhGetWindowContext(WindowHandle, SHRT_MAX))) + return 0; + + oldWndProc = context->DefaultWindowProc; + + switch (uMsg) + { + case WM_DESTROY: + { + PhRemoveWindowContext(WindowHandle, SHRT_MAX); + SetWindowLongPtr(WindowHandle, GWLP_WNDPROC, (LONG_PTR)oldWndProc); + + PhFree(context); + } + break; + case WM_ERASEBKGND: + return 1; + case WM_MOUSEMOVE: + { + POINT pt; + INT count; + INT i; + + GetCursorPos(&pt); + MapWindowPoints(NULL, WindowHandle, &pt, 1); + + count = TabCtrl_GetItemCount(WindowHandle); + + for (i = 0; i < count; i++) + { + RECT rect = { 0, 0, 0, 0 }; + TCITEM entry = + { + TCIF_STATE, + 0, + TCIS_HIGHLIGHTED + }; + + TabCtrl_GetItemRect(WindowHandle, i, &rect); + entry.dwState = PtInRect(&rect, pt) ? TCIS_HIGHLIGHTED : 0; + TabCtrl_SetItem(WindowHandle, i, &entry); + } + + if (!context->MouseActive) + { + TRACKMOUSEEVENT trackEvent = + { + sizeof(TRACKMOUSEEVENT), + TME_LEAVE, + WindowHandle, + 0 + }; + + TrackMouseEvent(&trackEvent); + context->MouseActive = TRUE; + } + + InvalidateRect(WindowHandle, NULL, FALSE); + } + break; + case WM_MOUSELEAVE: + { + INT count; + INT i; + + count = TabCtrl_GetItemCount(WindowHandle); + + for (i = 0; i < count; i++) + { + TCITEM entry = + { + TCIF_STATE, + 0, + TCIS_HIGHLIGHTED + }; + + TabCtrl_SetItem(WindowHandle, i, &entry); + } + + InvalidateRect(WindowHandle, NULL, FALSE); + context->MouseActive = FALSE; + } + break; + case WM_PAINT: + { + RECT clientRect, itemRect; + TCITEMW tcItem; + PAINTSTRUCT ps; + WCHAR szText[MAX_PATH]; + + BeginPaint(WindowHandle, &ps); + + GetClientRect(WindowHandle, &clientRect); + + ZeroMemory(&tcItem, sizeof(TCITEMW)); + tcItem.mask = TCIF_TEXT | TCIF_IMAGE | TCIF_STATE; + tcItem.dwStateMask = TCIS_BUTTONPRESSED | TCIS_HIGHLIGHTED; + tcItem.pszText = szText; + tcItem.cchTextMax = MAX_PATH; + + RECT rcSpin = clientRect; + HWND hWndSpin = GetDlgItem(WindowHandle, 1); + if (hWndSpin) + { + GetWindowRect(hWndSpin, &rcSpin); + MapWindowPoints(NULL, WindowHandle, (LPPOINT)&rcSpin, 2); + rcSpin.right = rcSpin.left; + rcSpin.left = rcSpin.top = 0; + rcSpin.bottom = clientRect.bottom; + } + + HDC hdc = CreateCompatibleDC(ps.hdc); + HBITMAP hbm = CreateCompatibleBitmap(ps.hdc, clientRect.right, clientRect.bottom); + SelectObject(hdc, hbm); + + SetBkMode(hdc, TRANSPARENT); + + static HFONT fontHandle = NULL; + if (!fontHandle) + { + NONCLIENTMETRICS metrics = { sizeof(NONCLIENTMETRICS) }; + if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, &metrics, 0)) + { + fontHandle = CreateFontIndirect(&metrics.lfMessageFont); + } + } + + SelectObject(hdc, fontHandle); + + switch (PhGetIntegerSetting(L"GraphColorMode")) + { + case 0: // New colors + //SetTextColor(hdc, RGB(0x0, 0xff, 0x0)); + SetDCBrushColor(hdc, PhpThemeWindowTextColor); + FillRect(hdc, &clientRect, GetStockObject(DC_BRUSH)); + break; + case 1: // Old colors + //SetTextColor(hdc, PhpThemeWindowTextColor); + SetDCBrushColor(hdc, RGB(65, 65, 65)); //WindowForegroundColor); // RGB(65, 65, 65)); + FillRect(hdc, &clientRect, GetStockObject(DC_BRUSH)); + break; + } + + + HDC hdcTab = CreateCompatibleDC(hdc); + + INT count = TabCtrl_GetItemCount(WindowHandle); + for (INT i = 0; i < count; i++) + { + TabCtrl_GetItemRect(WindowHandle, i, &itemRect); + TabCtrl_GetItem(WindowHandle, i, &tcItem); + + POINT pt; + GetCursorPos(&pt); + MapWindowPoints(NULL, WindowHandle, &pt, 1); + + if (PtInRect(&itemRect, pt)) + { + OffsetRect(&itemRect, 2, 2); + + switch (PhGetIntegerSetting(L"GraphColorMode")) + { + case 0: // New colors + { + if (TabCtrl_GetCurSel(WindowHandle) == i) + { + SetDCBrushColor(hdc, RGB(128, 128, 128)); + FillRect(hdc, &itemRect, GetStockObject(DC_BRUSH)); + } + else + { + //SetTextColor(hdc, PhpThemeWindowTextColor); + SetDCBrushColor(hdc, PhpThemeWindowTextColor); + FillRect(hdc, &itemRect, GetStockObject(DC_BRUSH)); + } + } + break; + case 1: // Old colors + SetTextColor(hdc, PhpThemeWindowTextColor); + SetDCBrushColor(hdc, RGB(128, 128, 128)); + FillRect(hdc, &itemRect, GetStockObject(DC_BRUSH)); + break; + } + + //FrameRect(hdc, &itemRect, GetSysColorBrush(COLOR_HIGHLIGHT)); + } + else + { + OffsetRect(&itemRect, 2, 2); + + switch (PhGetIntegerSetting(L"GraphColorMode")) + { + case 0: // New colors + { + if (TabCtrl_GetCurSel(WindowHandle) == i) + { + SetDCBrushColor(hdc, RGB(128, 128, 128)); + FillRect(hdc, &itemRect, GetStockObject(DC_BRUSH)); + } + else + { + //SetTextColor(hdc, PhpThemeWindowTextColor); + SetDCBrushColor(hdc, PhpThemeWindowTextColor); + FillRect(hdc, &itemRect, GetStockObject(DC_BRUSH)); + } + } + break; + case 1: // Old colors + { + if (TabCtrl_GetCurSel(WindowHandle) == i) + { + SetTextColor(hdc, PhpThemeWindowTextColor); + SetDCBrushColor(hdc, PhpThemeWindowForegroundColor); + FillRect(hdc, &itemRect, GetStockObject(DC_BRUSH)); + } + else + { + SetTextColor(hdc, PhpThemeWindowTextColor); + SetDCBrushColor(hdc, PhpThemeWindowBackgroundColor); + FillRect(hdc, &itemRect, GetStockObject(DC_BRUSH)); + } + } + break; + } + } + + DrawText( + hdc, + tcItem.pszText, + -1, + &itemRect, + DT_CENTER | DT_VCENTER | DT_SINGLELINE | DT_HIDEPREFIX //| DT_WORD_ELLIPSIS + ); + } + + DeleteDC(hdcTab); + + BitBlt(ps.hdc, 0, 0, clientRect.right, clientRect.bottom, hdc, 0, 0, SRCCOPY); + + DeleteDC(hdc); + DeleteObject(hbm); + EndPaint(WindowHandle, &ps); + + InvalidateRect(WindowHandle, NULL, FALSE); // HACK + } + return DefWindowProc(WindowHandle, uMsg, wParam, lParam); + } + + return CallWindowProc(oldWndProc, WindowHandle, uMsg, wParam, lParam); +} + +LRESULT CALLBACK PhpThemeWindowHeaderSubclassProc( + _In_ HWND hWnd, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + static BOOLEAN MouseActive = FALSE; + WNDPROC oldWndProc; + + if (!(oldWndProc = PhGetWindowContext(hWnd, SHRT_MAX))) + return 0; + + switch (uMsg) + { + case WM_DESTROY: + { + PhRemoveWindowContext(hWnd, SHRT_MAX); + SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)oldWndProc); + } + break; + //case WM_ERASEBKGND: + // return 1; + case WM_MOUSEMOVE: + { + //POINT pt; + //RECT rcItem; + //TCITEM tcItem; + //tcItem.mask = TCIF_STATE; + //tcItem.dwStateMask = TCIS_HIGHLIGHTED; + //GetCursorPos(&pt); + //MapWindowPoints(NULL, hWnd, &pt, 1); + //int nCount = TabCtrl_GetItemCount(hWnd); + //for (int i = 0; i < nCount; i++) + //{ + // TabCtrl_GetItemRect(hWnd, i, &rcItem); + // tcItem.dwState = PtInRect(&rcItem, pt) ? TCIS_HIGHLIGHTED : 0; + // TabCtrl_SetItem(hWnd, i, &tcItem); + //} + + if (!MouseActive) + { + TRACKMOUSEEVENT trackEvent = + { + sizeof(TRACKMOUSEEVENT), + TME_LEAVE, + hWnd, + 0 + }; + + TrackMouseEvent(&trackEvent); + MouseActive = TRUE; + } + + InvalidateRect(hWnd, NULL, FALSE); + } + break; + case WM_CONTEXTMENU: + { + LRESULT result = DefSubclassProc(hWnd, uMsg, wParam, lParam); + + InvalidateRect(hWnd, NULL, TRUE); + + return result; + } + break; + case WM_MOUSELEAVE: + { + // TCITEM tcItem = { TCIF_STATE, 0, TCIS_HIGHLIGHTED }; + //// int nCount = TabCtrl_GetItemCount(hWnd); + // for (int i = 0; i < nCount; i++) + // { + // //TabCtrl_SetItem(hWnd, i, &tcItem); + // } + + InvalidateRect(hWnd, NULL, TRUE); + MouseActive = FALSE; + } + break; + case WM_PAINT: + { + //HTHEME hTheme = OpenThemeData(hWnd, L"HEADER"); + WCHAR szText[MAX_PATH + 1]; + RECT rcClient; + HDITEM tcItem; + PAINTSTRUCT ps; + + //InvalidateRect(hWnd, NULL, FALSE); + BeginPaint(hWnd, &ps); + + GetClientRect(hWnd, &rcClient); + + ZeroMemory(&tcItem, sizeof(tcItem)); + tcItem.mask = HDI_TEXT | HDI_IMAGE | HDI_STATE; + tcItem.pszText = szText; + tcItem.cchTextMax = MAX_PATH; + + HDC hdc = CreateCompatibleDC(ps.hdc); + HBITMAP hbm = CreateCompatibleBitmap(ps.hdc, rcClient.right, rcClient.bottom); + + SelectObject(hdc, hbm); + + static HFONT fontHandle = NULL; + if (!fontHandle) + { + NONCLIENTMETRICS metrics = { sizeof(metrics) }; + if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, &metrics, 0)) + { + fontHandle = CreateFontIndirect(&metrics.lfMessageFont); + } + } + SelectObject(hdc, fontHandle); + + SetBkMode(hdc, TRANSPARENT); + + switch (PhGetIntegerSetting(L"GraphColorMode")) + { + case 0: // New colors + SetTextColor(hdc, RGB(0x0, 0x0, 0x0)); + SetDCBrushColor(hdc, PhpThemeWindowTextColor); + FillRect(hdc, &rcClient, GetStockObject(DC_BRUSH)); + break; + case 1: // Old colors + SetTextColor(hdc, PhpThemeWindowTextColor); + SetDCBrushColor(hdc, RGB(65, 65, 65)); //WindowForegroundColor); // RGB(65, 65, 65)); + FillRect(hdc, &rcClient, GetStockObject(DC_BRUSH)); + break; + } + + HDC hdcTab = CreateCompatibleDC(hdc); + + INT nCount = Header_GetItemCount(hWnd); + for (INT i = 0; i < nCount; i++) + { + RECT headerRect; + POINT pt; + + Header_GetItemRect(hWnd, i, &headerRect); + Header_GetItem(hWnd, i, &tcItem); + + GetCursorPos(&pt); + MapWindowPoints(NULL, hWnd, &pt, 1); + + if (PtInRect(&headerRect, pt)) + { + switch (PhGetIntegerSetting(L"GraphColorMode")) + { + case 0: // New colors + SetTextColor(hdc, PhpThemeWindowTextColor); + SetDCBrushColor(hdc, PhpThemeWindowBackgroundColor); + FillRect(hdc, &headerRect, GetStockObject(DC_BRUSH)); + break; + case 1: // Old colors + SetTextColor(hdc, PhpThemeWindowTextColor); + SetDCBrushColor(hdc, RGB(128, 128, 128)); + FillRect(hdc, &headerRect, GetStockObject(DC_BRUSH)); + break; + } + + //FrameRect(hdc, &headerRect, GetSysColorBrush(COLOR_HIGHLIGHT)); + } + else + { + switch (PhGetIntegerSetting(L"GraphColorMode")) + { + case 0: // New colors + SetTextColor(hdc, RGB(0x0, 0x0, 0x0)); + SetDCBrushColor(hdc, PhpThemeWindowTextColor); + FillRect(hdc, &headerRect, GetStockObject(DC_BRUSH)); + break; + case 1: // Old colors + SetTextColor(hdc, PhpThemeWindowTextColor); + SetDCBrushColor(hdc, PhpThemeWindowBackgroundColor); + FillRect(hdc, &headerRect, GetStockObject(DC_BRUSH)); + break; + } + + //FrameRect(hdc, &headerRect, GetSysColorBrush(COLOR_HIGHLIGHT)); + } + + DrawText( + hdc, + tcItem.pszText, + -1, + &headerRect, + DT_VCENTER | DT_CENTER | DT_SINGLELINE | DT_HIDEPREFIX + ); + } + + DeleteDC(hdcTab); + + BitBlt(ps.hdc, 0, 0, rcClient.right, rcClient.bottom, hdc, 0, 0, SRCCOPY); + + DeleteDC(hdc); + DeleteObject(hbm); + EndPaint(hWnd, &ps); + } + return DefWindowProc(hWnd, uMsg, wParam, lParam); + } + + return CallWindowProc(oldWndProc, hWnd, uMsg, wParam, lParam); +} + VOID PhInitializeWindowTheme( _In_ HWND WindowHandle, _In_ BOOLEAN EnableThemeSupport @@ -286,6 +767,8 @@ VOID PhReInitializeWindowTheme( _In_ HWND WindowHandle ) { + HWND currentWindow = NULL; + PhEnumChildWindows( WindowHandle, 0x1000, @@ -293,8 +776,6 @@ VOID PhReInitializeWindowTheme( 0 ); - HWND currentWindow = NULL; - do { if (currentWindow = FindWindowEx(NULL, currentWindow, NULL, NULL)) @@ -358,7 +839,36 @@ BOOLEAN CALLBACK PhpThemeWindowEnumChildWindows( } else if (PhEqualStringZ(className, L"SysTabControl32", FALSE)) { - NOTHING; + PPHP_THEME_WINDOW_TAB_CONTEXT tabControlContext; + + tabControlContext = PhAllocateZero(sizeof(PHP_THEME_WINDOW_TAB_CONTEXT)); + tabControlContext->DefaultWindowProc = (WNDPROC)GetWindowLongPtr(WindowHandle, GWLP_WNDPROC); + PhSetWindowContext(WindowHandle, SHRT_MAX, tabControlContext); + SetWindowLongPtr(WindowHandle, GWLP_WNDPROC, (LONG_PTR)PhpThemeWindowTabControlWndSubclassProc); + + PhSetWindowStyle(WindowHandle, TCS_OWNERDRAWFIXED, TCS_OWNERDRAWFIXED); + + //SendMessage( + // WindowHandle, + // WM_SETFONT, + // (WPARAM)CreateFont( + // -(LONG)PhMultiplyDivide(15, PhGlobalDpi, 96), + // 0, + // 0, + // 0, + // FW_SEMIBOLD, + // FALSE, + // FALSE, + // FALSE, + // ANSI_CHARSET, + // OUT_DEFAULT_PRECIS, + // CLIP_DEFAULT_PRECIS, + // DEFAULT_QUALITY, + // DEFAULT_PITCH, + // L"Tahoma" + // ), FALSE); + + InvalidateRect(WindowHandle, NULL, FALSE); } else if (PhEqualStringZ(className, L"msctls_statusbar32", FALSE)) { @@ -366,7 +876,11 @@ BOOLEAN CALLBACK PhpThemeWindowEnumChildWindows( } else if (PhEqualStringZ(className, L"SysHeader32", FALSE)) { - NOTHING; + WNDPROC headerWindowProc; + + headerWindowProc = (WNDPROC)GetWindowLongPtr(WindowHandle, GWLP_WNDPROC); + PhSetWindowContext(WindowHandle, SHRT_MAX, headerWindowProc); + SetWindowLongPtr(WindowHandle, GWLP_WNDPROC, (LONG_PTR)PhpThemeWindowHeaderSubclassProc); } else if (PhEqualStringZ(className, L"SysListView32", FALSE)) { @@ -566,3 +1080,84 @@ LRESULT PhpWindowThemeDrawButton( return CDRF_DODEFAULT; } + +LRESULT PhpWindowThemeDrawListViewGroup( + _In_ LPNMLVCUSTOMDRAW DrawInfo + ) +{ + switch (DrawInfo->nmcd.dwDrawStage) + { + case CDDS_PREPAINT: + { + SetBkMode(DrawInfo->nmcd.hdc, TRANSPARENT); + + switch (PhGetIntegerSetting(L"GraphColorMode")) + { + case 0: // New colors + SetTextColor(DrawInfo->nmcd.hdc, RGB(0x0, 0x0, 0x0)); + SetDCBrushColor(DrawInfo->nmcd.hdc, PhpThemeWindowTextColor); + //FillRect(DrawInfo->nmcd.hdc, &DrawInfo->nmcd.rc, GetStockObject(DC_BRUSH)); + break; + case 1: // Old colors + SetTextColor(DrawInfo->nmcd.hdc, RGB(0x0, 0x0, 0x0)); + SetDCBrushColor(DrawInfo->nmcd.hdc, RGB(128, 128, 128)); + //FillRect(DrawInfo->nmcd.hdc, &DrawInfo->nmcd.rc, GetStockObject(DC_BRUSH)); + break; + } + + static HFONT fontHandle = NULL; + if (!fontHandle) + { + NONCLIENTMETRICS metrics = { sizeof(metrics) }; + if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, &metrics, 0)) + { + metrics.lfMessageFont.lfHeight = -11; + metrics.lfMessageFont.lfWeight = FW_BOLD; + fontHandle = CreateFontIndirect(&metrics.lfMessageFont); + } + } + SelectObject(DrawInfo->nmcd.hdc, fontHandle); + + LVGROUP groupInfo = { sizeof(LVGROUP) }; + groupInfo.mask = LVGF_HEADER; + if (ListView_GetGroupInfo(DrawInfo->nmcd.hdr.hwndFrom, (ULONG)DrawInfo->nmcd.dwItemSpec, &groupInfo) == -1) + { + break; + } + + + SetTextColor(DrawInfo->nmcd.hdc, RGB(255, 69, 0)); + SetDCBrushColor(DrawInfo->nmcd.hdc, RGB(65, 65, 65)); + + //GetClientRect(hWnd, &clientRect); + //clientRect.top += 6; + //FrameRect(DrawInfo->nmcd.hdc, &clientRect, GetStockObject(DC_BRUSH)); + //clientRect.top -= 6; + //PPH_STRING windowText = PhGetWindowText(hWnd); + //clientRect.left += 10; + DrawInfo->rcText.top += 2; + DrawInfo->rcText.bottom -= 2; + FillRect(DrawInfo->nmcd.hdc, &DrawInfo->rcText, GetStockObject(DC_BRUSH)); + DrawInfo->rcText.top -= 2; + DrawInfo->rcText.bottom += 2; + + SetTextColor(DrawInfo->nmcd.hdc, RGB(255, 69, 0)); + SetDCBrushColor(DrawInfo->nmcd.hdc, RGB(65, 65, 65)); + + DrawInfo->rcText.left += 10; + DrawText( + DrawInfo->nmcd.hdc, + groupInfo.pszHeader, + -1, + &DrawInfo->rcText, + DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_HIDEPREFIX + ); + DrawInfo->rcText.left -= 10; + //DrawInfo->clrText = RGB(0x0, 0xff, 0); + //return TBCDRF_USECDCOLORS | CDRF_NEWFONT; + } + return CDRF_SKIPDEFAULT; + } + + return CDRF_DODEFAULT; +} \ No newline at end of file From 398ded934742521de1e955678f3b423e2a063370 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 25 Jul 2018 03:18:19 +1000 Subject: [PATCH 1204/2058] Fix tab control theme, Add additional theme support --- ProcessHacker/jobprp.c | 5 +++++ ProcessHacker/plugman.c | 7 +++++++ ProcessHacker/prpgstat.c | 1 - ProcessHacker/prpgwmi.c | 6 +++--- phlib/theme.c | 40 +++++++++++++++++++++------------------- 5 files changed, 36 insertions(+), 23 deletions(-) diff --git a/ProcessHacker/jobprp.c b/ProcessHacker/jobprp.c index 3184922c2f73..a754b28f59da 100644 --- a/ProcessHacker/jobprp.c +++ b/ProcessHacker/jobprp.c @@ -21,6 +21,7 @@ */ #include +#include #include #include #include @@ -382,6 +383,8 @@ INT_PTR CALLBACK PhpJobPageProc( NtClose(jobHandle); } + + PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport); } break; case WM_DESTROY: @@ -633,6 +636,8 @@ INT_PTR CALLBACK PhpJobStatisticsPageProc( PhpRefreshJobStatisticsInfo(hwndDlg, jobPageContext); SetTimer(hwndDlg, 1, PhGetIntegerSetting(L"UpdateInterval"), NULL); + + PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport); } break; case WM_TIMER: diff --git a/ProcessHacker/plugman.c b/ProcessHacker/plugman.c index 56113f6d8685..1df304a26bd9 100644 --- a/ProcessHacker/plugman.c +++ b/ProcessHacker/plugman.c @@ -27,6 +27,7 @@ #include #include #include +#include #define WM_PH_PLUGINS_SHOWDIALOG (WM_APP + 401) #define WM_PH_PLUGINS_SHOWPROPERTIES (WM_APP + 402) @@ -668,6 +669,8 @@ INT_PTR CALLBACK PhpPluginsDlgProc( PhpEnumerateLoadedPlugins(context); TreeNew_AutoSizeColumn(context->TreeNewHandle, PH_PLUGIN_TREE_COLUMN_ITEM_NAME, TN_AUTOSIZE_REMAINING_SPACE); SetWindowText(GetDlgItem(hwndDlg, IDC_DISABLED), PhaFormatString(L"Disabled Plugins (%lu)", PhpDisabledPluginsCount())->Buffer); + + PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport); } break; case WM_DESTROY: @@ -980,6 +983,8 @@ INT_PTR CALLBACK PhpPluginPropertiesDlgProc( PhpRefreshPluginDetails(hwndDlg, selectedPlugin); PhSetDialogFocus(hwndDlg, GetDlgItem(hwndDlg, IDOK)); + + PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport); } break; case WM_COMMAND: @@ -1135,6 +1140,8 @@ INT_PTR CALLBACK PhpPluginsDisabledDlgProc( ExtendedListView_SetColumnWidth(context->ListViewHandle, 0, ELVSCW_AUTOSIZE_REMAININGSPACE); PhSetDialogFocus(hwndDlg, GetDlgItem(hwndDlg, IDOK)); + + PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport); } break; case WM_COMMAND: diff --git a/ProcessHacker/prpgstat.c b/ProcessHacker/prpgstat.c index f3f1af914f9c..526ba9aea218 100644 --- a/ProcessHacker/prpgstat.c +++ b/ProcessHacker/prpgstat.c @@ -27,7 +27,6 @@ #include #include #include -#include typedef enum _PH_PROCESS_STATISTICS_CATEGORY { diff --git a/ProcessHacker/prpgwmi.c b/ProcessHacker/prpgwmi.c index deeadc635d34..5566c294eaaa 100644 --- a/ProcessHacker/prpgwmi.c +++ b/ProcessHacker/prpgwmi.c @@ -22,13 +22,13 @@ #include #include +#include #include #include #include #include #include -#include #include #define WM_PH_WMI_UPDATE (WM_APP + 251) @@ -596,8 +596,6 @@ INT_PTR CALLBACK PhpProcessWmiProvidersDlgProc( PhSetExtendedListView(context->ListViewHandle); PhLoadListViewColumnsFromSetting(L"WmiProviderListViewColumns", context->ListViewHandle); - EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); - PhpRefreshWmiProviders(hwndDlg, context, processItem); PhRegisterCallback( @@ -606,6 +604,8 @@ INT_PTR CALLBACK PhpProcessWmiProvidersDlgProc( context, &context->ProcessesUpdatedRegistration ); + + PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport); } break; case WM_DESTROY: diff --git a/phlib/theme.c b/phlib/theme.c index 446347495e2a..641948fb2a3c 100644 --- a/phlib/theme.c +++ b/phlib/theme.c @@ -57,6 +57,7 @@ LRESULT PhpWindowThemeDrawListViewGroup( COLORREF PhpThemeWindowForegroundColor = RGB(28, 28, 28); COLORREF PhpThemeWindowBackgroundColor = RGB(64, 64, 64); COLORREF PhpThemeWindowTextColor = RGB(0xff, 0xff, 0xff); +HFONT PhpTabControlFontHandle = NULL; HFONT PhpGroupboxFontHandle = NULL; LRESULT CALLBACK PhpThemeWindowSubclassProc( @@ -848,26 +849,27 @@ BOOLEAN CALLBACK PhpThemeWindowEnumChildWindows( PhSetWindowStyle(WindowHandle, TCS_OWNERDRAWFIXED, TCS_OWNERDRAWFIXED); - //SendMessage( - // WindowHandle, - // WM_SETFONT, - // (WPARAM)CreateFont( - // -(LONG)PhMultiplyDivide(15, PhGlobalDpi, 96), - // 0, - // 0, - // 0, - // FW_SEMIBOLD, - // FALSE, - // FALSE, - // FALSE, - // ANSI_CHARSET, - // OUT_DEFAULT_PRECIS, - // CLIP_DEFAULT_PRECIS, - // DEFAULT_QUALITY, - // DEFAULT_PITCH, - // L"Tahoma" - // ), FALSE); + if (!PhpTabControlFontHandle) + { + PhpTabControlFontHandle = CreateFont( + -(LONG)PhMultiplyDivide(15, PhGlobalDpi, 96), + 0, + 0, + 0, + FW_SEMIBOLD, + FALSE, + FALSE, + FALSE, + ANSI_CHARSET, + OUT_DEFAULT_PRECIS, + CLIP_DEFAULT_PRECIS, + DEFAULT_QUALITY, + DEFAULT_PITCH, + L"Tahoma" + ); + } + SendMessage(WindowHandle, WM_SETFONT, (WPARAM)PhpTabControlFontHandle, FALSE); InvalidateRect(WindowHandle, NULL, FALSE); } else if (PhEqualStringZ(className, L"msctls_statusbar32", FALSE)) From 2a54e92a8bd6b56611529ea1497ee926e883e84e Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 25 Jul 2018 03:27:08 +1000 Subject: [PATCH 1205/2058] Update default theme window styles --- phlib/theme.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/phlib/theme.c b/phlib/theme.c index 641948fb2a3c..aa14a338c967 100644 --- a/phlib/theme.c +++ b/phlib/theme.c @@ -886,6 +886,9 @@ BOOLEAN CALLBACK PhpThemeWindowEnumChildWindows( } else if (PhEqualStringZ(className, L"SysListView32", FALSE)) { + PhSetWindowStyle(WindowHandle, WS_BORDER, 0); + PhSetWindowExStyle(WindowHandle, WS_EX_CLIENTEDGE, 0); + ListView_SetBkColor(WindowHandle, RGB(30, 30, 30)); ListView_SetTextBkColor(WindowHandle, RGB(30, 30, 30)); ListView_SetTextColor(WindowHandle, RGB(0xff, 0xff, 0xff)); @@ -894,6 +897,11 @@ BOOLEAN CALLBACK PhpThemeWindowEnumChildWindows( { NOTHING; } + else if (PhEqualStringZ(className, L"PhTreeNew", FALSE)) + { + PhSetWindowStyle(WindowHandle, WS_BORDER, 0); + PhSetWindowExStyle(WindowHandle, WS_EX_CLIENTEDGE, 0); + } return TRUE; } From 7fd2b9ea16569376080ec717776bf8379caa6441 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 25 Jul 2018 03:48:45 +1000 Subject: [PATCH 1206/2058] Update light button theme, Add token page theme support --- ProcessHacker/tokprp.c | 8 ++--- phlib/theme.c | 72 ++++++++++++++++++++++++------------------ 2 files changed, 46 insertions(+), 34 deletions(-) diff --git a/ProcessHacker/tokprp.c b/ProcessHacker/tokprp.c index 042db2a5b57a..ac6bad7515c4 100644 --- a/ProcessHacker/tokprp.c +++ b/ProcessHacker/tokprp.c @@ -31,8 +31,6 @@ #include #include -#include - typedef enum _PH_PROCESS_TOKEN_CATEGORY { PH_PROCESS_TOKEN_CATEGORY_PRIVILEGES, @@ -696,6 +694,8 @@ INT_PTR CALLBACK PhpTokenPageProc( NtClose(tokenHandle); } + + PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport); } break; case WM_DESTROY: @@ -2020,7 +2020,7 @@ INT_PTR CALLBACK PhpTokenClaimsPageProc( TreeNew_NodesStructured(tnHandle); TreeNew_SetRedraw(tnHandle, TRUE); - EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); + PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport); } break; case WM_DESTROY: @@ -2123,7 +2123,7 @@ INT_PTR CALLBACK PhpTokenAttributesPageProc( TreeNew_NodesStructured(tnHandle); TreeNew_SetRedraw(tnHandle, TRUE); - EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); + PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport); } break; case WM_DESTROY: diff --git a/phlib/theme.c b/phlib/theme.c index aa14a338c967..e3f3ddf88a54 100644 --- a/phlib/theme.c +++ b/phlib/theme.c @@ -815,7 +815,11 @@ BOOLEAN CALLBACK PhpThemeWindowEnumChildWindows( if (!GetClassName(WindowHandle, className, RTL_NUMBER_OF(className))) className[0] = 0; - if (PhEqualStringZ(className, L"Button", FALSE)) + if (PhEqualStringZ(className, L"#32770", FALSE)) + { + PhInitializeWindowTheme(WindowHandle, TRUE); + } + else if (PhEqualStringZ(className, L"Button", FALSE)) { ULONG buttonWindowStyle = (ULONG)GetWindowLongPtr(WindowHandle, GWL_STYLE); @@ -828,16 +832,20 @@ BOOLEAN CALLBACK PhpThemeWindowEnumChildWindows( SetWindowLongPtr(WindowHandle, GWLP_WNDPROC, (LONG_PTR)PhpThemeWindowGroupBoxSubclassProc); } } - - if (PhEqualStringZ(className, L"Edit", FALSE)) + else if (PhEqualStringZ(className, L"Edit", FALSE)) { - PhSetWindowStyle(WindowHandle, WS_BORDER, 0); - PhSetWindowExStyle(WindowHandle, WS_EX_CLIENTEDGE, 0); - } - else if (PhEqualStringZ(className, L"#32770", FALSE)) - { - PhInitializeWindowTheme(WindowHandle, TRUE); - } + switch (PhGetIntegerSetting(L"GraphColorMode")) + { + case 0: // New colors + //PhSetWindowStyle(WindowHandle, WS_BORDER, WS_BORDER); + //PhSetWindowExStyle(WindowHandle, WS_EX_CLIENTEDGE, WS_EX_CLIENTEDGE); + break; + case 1: // Old colors + PhSetWindowStyle(WindowHandle, WS_BORDER, 0); + PhSetWindowExStyle(WindowHandle, WS_EX_CLIENTEDGE, 0); + break; + } + } else if (PhEqualStringZ(className, L"SysTabControl32", FALSE)) { PPHP_THEME_WINDOW_TAB_CONTEXT tabControlContext; @@ -889,9 +897,16 @@ BOOLEAN CALLBACK PhpThemeWindowEnumChildWindows( PhSetWindowStyle(WindowHandle, WS_BORDER, 0); PhSetWindowExStyle(WindowHandle, WS_EX_CLIENTEDGE, 0); - ListView_SetBkColor(WindowHandle, RGB(30, 30, 30)); - ListView_SetTextBkColor(WindowHandle, RGB(30, 30, 30)); - ListView_SetTextColor(WindowHandle, RGB(0xff, 0xff, 0xff)); + switch (PhGetIntegerSetting(L"GraphColorMode")) + { + case 0: // New colors + break; + case 1: // Old colors + ListView_SetBkColor(WindowHandle, RGB(30, 30, 30)); + ListView_SetTextBkColor(WindowHandle, RGB(30, 30, 30)); + ListView_SetTextColor(WindowHandle, RGB(0xff, 0xff, 0xff)); + break; + } } else if (PhEqualStringZ(className, L"ScrollBar", FALSE)) { @@ -947,7 +962,6 @@ LRESULT PhpWindowThemeDrawButton( { PPH_STRING buttonText; HFONT oldFont; - COLORREF oldColor; buttonText = PhGetWindowText(DrawInfo->hdr.hwndFrom); @@ -956,28 +970,27 @@ LRESULT PhpWindowThemeDrawButton( switch (PhGetIntegerSetting(L"GraphColorMode")) { case 0: // New colors - oldColor = SetTextColor(DrawInfo->hdc, RGB(0, 0, 0xff)); - SetDCBrushColor(DrawInfo->hdc, PhpThemeWindowTextColor); + //SetTextColor(DrawInfo->hdc, RGB(0, 0, 0xff)); + SetDCBrushColor(DrawInfo->hdc, GetSysColor(COLOR_HIGHLIGHT)); break; case 1: // Old colors - //SetBkColor(drawInfo->hdc, GetSysColor(COLOR_HIGHLIGHT)); - oldColor = SetTextColor(DrawInfo->hdc, GetSysColor(COLOR_HIGHLIGHTTEXT)); + SetTextColor(DrawInfo->hdc, GetSysColor(COLOR_HIGHLIGHTTEXT)); SetDCBrushColor(DrawInfo->hdc, RGB(78, 78, 78)); - FillRect(DrawInfo->hdc, &DrawInfo->rc, GetStockObject(DC_BRUSH)); break; } + + FillRect(DrawInfo->hdc, &DrawInfo->rc, GetStockObject(DC_BRUSH)); } else if (isHighlighted) { switch (PhGetIntegerSetting(L"GraphColorMode")) { case 0: // New colors - oldColor = SetTextColor(DrawInfo->hdc, RGB(0, 0, 0xff)); - SetDCBrushColor(DrawInfo->hdc, PhpThemeWindowTextColor); + //SetTextColor(DrawInfo->hdc, RGB(0, 0, 0xff)); + SetDCBrushColor(DrawInfo->hdc, GetSysColor(COLOR_HIGHLIGHT)); break; case 1: // Old colors - //SetBkColor(drawInfo->hdc, GetSysColor(COLOR_HIGHLIGHT)); - oldColor = SetTextColor(DrawInfo->hdc, GetSysColor(COLOR_HIGHLIGHTTEXT)); + SetTextColor(DrawInfo->hdc, GetSysColor(COLOR_HIGHLIGHTTEXT)); SetDCBrushColor(DrawInfo->hdc, RGB(65, 65, 65)); break; } @@ -989,17 +1002,16 @@ LRESULT PhpWindowThemeDrawButton( switch (PhGetIntegerSetting(L"GraphColorMode")) { case 0: // New colors - oldColor = SetTextColor(DrawInfo->hdc, RGB(0x0, 0x0, 0x0)); - SetDCBrushColor(DrawInfo->hdc, PhpThemeWindowTextColor); + //SetTextColor(DrawInfo->hdc, RGB(0x0, 0x0, 0x0)); + //SetDCBrushColor(DrawInfo->hdc, GetSysColor(COLOR_3DFACE)); + //FillRect(DrawInfo->hdc, &DrawInfo->rc, GetStockObject(DC_BRUSH)); break; case 1: // Old colors - //SetBkColor(DrawInfo->hdc, RGB(0xff, 0xff, 0xff)); - oldColor = SetTextColor(DrawInfo->hdc, PhpThemeWindowTextColor); + SetTextColor(DrawInfo->hdc, PhpThemeWindowTextColor); SetDCBrushColor(DrawInfo->hdc, RGB(42, 42, 42)); // WindowForegroundColor + FillRect(DrawInfo->hdc, &DrawInfo->rc, GetStockObject(DC_BRUSH)); break; } - - FillRect(DrawInfo->hdc, &DrawInfo->rc, GetStockObject(DC_BRUSH)); } if ((GetWindowLongPtr(DrawInfo->hdr.hwndFrom, GWL_STYLE) & BS_CHECKBOX) != 0) @@ -1028,7 +1040,6 @@ LRESULT PhpWindowThemeDrawButton( ); } - SetTextColor(DrawInfo->hdc, oldColor); SelectFont(DrawInfo->hdc, oldFont); DeleteFont(newFont); @@ -1085,6 +1096,7 @@ LRESULT PhpWindowThemeDrawButton( PhDereferenceObject(buttonText); } + return CDRF_SKIPDEFAULT; } From 1b259080f4d9300f7bae9095d5282f5b711ee601 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 25 Jul 2018 03:56:11 +1000 Subject: [PATCH 1207/2058] Fix typo --- ProcessHacker/tokprp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ProcessHacker/tokprp.c b/ProcessHacker/tokprp.c index ac6bad7515c4..12bf449eb7de 100644 --- a/ProcessHacker/tokprp.c +++ b/ProcessHacker/tokprp.c @@ -553,6 +553,7 @@ INT_PTR CALLBACK PhpTokenPageProc( PTOKEN_PAGE_CONTEXT tokenPageContext; tokenPageContext = PhpTokenPageHeader(hwndDlg, uMsg, wParam, lParam); + tokenPageContext = PhpGenericPropertyPageHeader(hwndDlg, uMsg, wParam, lParam, 3); if (!tokenPageContext) return FALSE; @@ -1601,7 +1602,7 @@ INT_PTR CALLBACK PhpTokenCapabilitiesPageProc( NtClose(tokenHandle); } - EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); + PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport); } break; case WM_DESTROY: From 497a27142b151dd39f947b93cc269535ae9685a8 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 25 Jul 2018 04:26:32 +1000 Subject: [PATCH 1208/2058] Add service properties theme support --- ProcessHacker/prpgsrv.c | 4 +++- ProcessHacker/srvcr.c | 2 ++ ProcessHacker/srvctl.c | 3 +++ ProcessHacker/srvprp.c | 3 +++ phlib/theme.c | 27 ++++++++++++--------------- plugins/ExtendedServices/depend.c | 4 ++++ plugins/ExtendedServices/other.c | 2 ++ plugins/ExtendedServices/recovery.c | 4 ++++ plugins/ExtendedServices/srvprgrs.c | 2 ++ plugins/ExtendedServices/trigger.c | 4 ++++ plugins/ExtendedServices/triggpg.c | 2 ++ 11 files changed, 41 insertions(+), 16 deletions(-) diff --git a/ProcessHacker/prpgsrv.c b/ProcessHacker/prpgsrv.c index 19b74bc130a9..cfac35ff7a17 100644 --- a/ProcessHacker/prpgsrv.c +++ b/ProcessHacker/prpgsrv.c @@ -21,9 +21,9 @@ */ #include +#include #include #include - #include static VOID PhpLayoutServiceListControl( @@ -103,6 +103,8 @@ INT_PTR CALLBACK PhpProcessServicesDlgProc( ShowWindow(serviceListHandle, SW_SHOW); propPageContext->Context = serviceListHandle; + + PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport); } break; case WM_DESTROY: diff --git a/ProcessHacker/srvcr.c b/ProcessHacker/srvcr.c index dedb5ec21a35..3d9cd0dc2b6f 100644 --- a/ProcessHacker/srvcr.c +++ b/ProcessHacker/srvcr.c @@ -21,6 +21,7 @@ */ #include +#include #include #include @@ -75,6 +76,7 @@ INT_PTR CALLBACK PhpCreateServiceDlgProc( } PhSetDialogFocus(hwndDlg, GetDlgItem(hwndDlg, IDC_NAME)); + PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport); } break; case WM_COMMAND: diff --git a/ProcessHacker/srvctl.c b/ProcessHacker/srvctl.c index 28d178b6d6dc..deaf1f057c89 100644 --- a/ProcessHacker/srvctl.c +++ b/ProcessHacker/srvctl.c @@ -22,6 +22,7 @@ #include #include +#include #include #include @@ -280,6 +281,8 @@ INT_PTR CALLBACK PhpServicesPageProc( PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_DESCRIPTION), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_START), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_PAUSE), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); + + PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport); } break; case WM_DESTROY: diff --git a/ProcessHacker/srvprp.c b/ProcessHacker/srvprp.c index bf6f8eda2952..3150cefb1be0 100644 --- a/ProcessHacker/srvprp.c +++ b/ProcessHacker/srvprp.c @@ -337,6 +337,9 @@ INT_PTR CALLBACK PhpServiceGeneralDlgProc( PhpRefreshControls(hwndDlg); context->Ready = TRUE; + + PhInitializeWindowTheme(GetParent(hwndDlg), PhEnableThemeSupport); // HACK + //PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport); } break; case WM_DESTROY: diff --git a/phlib/theme.c b/phlib/theme.c index e3f3ddf88a54..0351e753d6d3 100644 --- a/phlib/theme.c +++ b/phlib/theme.c @@ -58,6 +58,7 @@ COLORREF PhpThemeWindowForegroundColor = RGB(28, 28, 28); COLORREF PhpThemeWindowBackgroundColor = RGB(64, 64, 64); COLORREF PhpThemeWindowTextColor = RGB(0xff, 0xff, 0xff); HFONT PhpTabControlFontHandle = NULL; +HFONT PhpListViewFontHandle = NULL; HFONT PhpGroupboxFontHandle = NULL; LRESULT CALLBACK PhpThemeWindowSubclassProc( @@ -1127,36 +1128,34 @@ LRESULT PhpWindowThemeDrawListViewGroup( break; } - static HFONT fontHandle = NULL; - if (!fontHandle) + if (!PhpListViewFontHandle) { - NONCLIENTMETRICS metrics = { sizeof(metrics) }; + NONCLIENTMETRICS metrics = { sizeof(NONCLIENTMETRICS) }; + if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, &metrics, 0)) { metrics.lfMessageFont.lfHeight = -11; metrics.lfMessageFont.lfWeight = FW_BOLD; - fontHandle = CreateFontIndirect(&metrics.lfMessageFont); + + PhpListViewFontHandle = CreateFontIndirect(&metrics.lfMessageFont); } } - SelectObject(DrawInfo->nmcd.hdc, fontHandle); + SelectObject(DrawInfo->nmcd.hdc, PhpListViewFontHandle); LVGROUP groupInfo = { sizeof(LVGROUP) }; groupInfo.mask = LVGF_HEADER; - if (ListView_GetGroupInfo(DrawInfo->nmcd.hdr.hwndFrom, (ULONG)DrawInfo->nmcd.dwItemSpec, &groupInfo) == -1) + if (ListView_GetGroupInfo( + DrawInfo->nmcd.hdr.hwndFrom, + (ULONG)DrawInfo->nmcd.dwItemSpec, + &groupInfo + ) == -1) { break; } - SetTextColor(DrawInfo->nmcd.hdc, RGB(255, 69, 0)); SetDCBrushColor(DrawInfo->nmcd.hdc, RGB(65, 65, 65)); - //GetClientRect(hWnd, &clientRect); - //clientRect.top += 6; - //FrameRect(DrawInfo->nmcd.hdc, &clientRect, GetStockObject(DC_BRUSH)); - //clientRect.top -= 6; - //PPH_STRING windowText = PhGetWindowText(hWnd); - //clientRect.left += 10; DrawInfo->rcText.top += 2; DrawInfo->rcText.bottom -= 2; FillRect(DrawInfo->nmcd.hdc, &DrawInfo->rcText, GetStockObject(DC_BRUSH)); @@ -1175,8 +1174,6 @@ LRESULT PhpWindowThemeDrawListViewGroup( DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_HIDEPREFIX ); DrawInfo->rcText.left -= 10; - //DrawInfo->clrText = RGB(0x0, 0xff, 0); - //return TBCDRF_USECDCOLORS | CDRF_NEWFONT; } return CDRF_SKIPDEFAULT; } diff --git a/plugins/ExtendedServices/depend.c b/plugins/ExtendedServices/depend.c index 4aee76d26def..9ed76d38e253 100644 --- a/plugins/ExtendedServices/depend.c +++ b/plugins/ExtendedServices/depend.c @@ -210,6 +210,8 @@ INT_PTR CALLBACK EspServiceDependenciesDlgProc( ((PPH_STRING)PH_AUTO(PhGetWin32Message(win32Result)))->Buffer)->Buffer); ShowWindow(GetDlgItem(hwndDlg, IDC_SERVICES_LAYOUT), SW_SHOW); } + + PhInitializeWindowTheme(hwndDlg, !!PhGetIntegerSetting(L"EnableThemeSupport")); } break; case WM_DESTROY: @@ -322,6 +324,8 @@ INT_PTR CALLBACK EspServiceDependentsDlgProc( ((PPH_STRING)PH_AUTO(PhGetWin32Message(win32Result)))->Buffer)->Buffer); ShowWindow(GetDlgItem(hwndDlg, IDC_SERVICES_LAYOUT), SW_SHOW); } + + PhInitializeWindowTheme(hwndDlg, !!PhGetIntegerSetting(L"EnableThemeSupport")); } break; case WM_DESTROY: diff --git a/plugins/ExtendedServices/other.c b/plugins/ExtendedServices/other.c index 309e6644b5a4..fafe5dc61678 100644 --- a/plugins/ExtendedServices/other.c +++ b/plugins/ExtendedServices/other.c @@ -380,6 +380,8 @@ INT_PTR CALLBACK EspServiceOtherDlgProc( } context->Ready = TRUE; + + PhInitializeWindowTheme(hwndDlg, !!PhGetIntegerSetting(L"EnableThemeSupport")); } break; case WM_DESTROY: diff --git a/plugins/ExtendedServices/recovery.c b/plugins/ExtendedServices/recovery.c index 66436e7c9894..6404ce75318d 100644 --- a/plugins/ExtendedServices/recovery.c +++ b/plugins/ExtendedServices/recovery.c @@ -329,6 +329,8 @@ INT_PTR CALLBACK EspServiceRecoveryDlgProc( EspFixControls(hwndDlg, context); context->Ready = TRUE; + + PhInitializeWindowTheme(hwndDlg, !!PhGetIntegerSetting(L"EnableThemeSupport")); } break; case WM_DESTROY: @@ -619,6 +621,8 @@ INT_PTR CALLBACK RestartComputerDlgProc( PhSetDialogFocus(hwndDlg, GetDlgItem(hwndDlg, IDC_RESTARTCOMPAFTER)); Edit_SetSel(GetDlgItem(hwndDlg, IDC_RESTARTCOMPAFTER), 0, -1); + + PhInitializeWindowTheme(hwndDlg, !!PhGetIntegerSetting(L"EnableThemeSupport")); } break; case WM_COMMAND: diff --git a/plugins/ExtendedServices/srvprgrs.c b/plugins/ExtendedServices/srvprgrs.c index df1046898faf..0e8bcaabd939 100644 --- a/plugins/ExtendedServices/srvprgrs.c +++ b/plugins/ExtendedServices/srvprgrs.c @@ -75,6 +75,8 @@ INT_PTR CALLBACK EspRestartServiceDlgProc( { EndDialog(hwndDlg, IDCANCEL); } + + PhInitializeWindowTheme(hwndDlg, !!PhGetIntegerSetting(L"EnableThemeSupport")); } break; case WM_COMMAND: diff --git a/plugins/ExtendedServices/trigger.c b/plugins/ExtendedServices/trigger.c index f9c84703a697..0284f228d940 100644 --- a/plugins/ExtendedServices/trigger.c +++ b/plugins/ExtendedServices/trigger.c @@ -1367,6 +1367,8 @@ INT_PTR CALLBACK EspServiceTriggerDlgProc( EnableWindow(GetDlgItem(hwndDlg, IDC_EDIT), FALSE); EnableWindow(GetDlgItem(hwndDlg, IDC_DELETE), FALSE); + + PhInitializeWindowTheme(hwndDlg, !!PhGetIntegerSetting(L"EnableThemeSupport")); } break; case WM_DESTROY: @@ -1698,6 +1700,8 @@ INT_PTR CALLBACK ValueDlgProc( PhSetDialogItemText(hwndDlg, IDC_VALUES, context->EditingValue->Buffer); PhSetDialogFocus(hwndDlg, GetDlgItem(hwndDlg, IDC_VALUES)); Edit_SetSel(GetDlgItem(hwndDlg, IDC_VALUES), 0, -1); + + PhInitializeWindowTheme(hwndDlg, !!PhGetIntegerSetting(L"EnableThemeSupport")); } break; case WM_COMMAND: diff --git a/plugins/ExtendedServices/triggpg.c b/plugins/ExtendedServices/triggpg.c index 103ee6672e7f..f9e8b191f9f5 100644 --- a/plugins/ExtendedServices/triggpg.c +++ b/plugins/ExtendedServices/triggpg.c @@ -97,6 +97,8 @@ INT_PTR CALLBACK EspServiceTriggersDlgProc( PhShowWarning(hwndDlg, L"Unable to query service trigger information: %s", ((PPH_STRING)PH_AUTO(PhGetNtMessage(status)))->Buffer); } + + PhInitializeWindowTheme(hwndDlg, !!PhGetIntegerSetting(L"EnableThemeSupport")); } break; case WM_DESTROY: From 1d4219eef339b38184072a3439a1f20883097e6d Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 25 Jul 2018 04:43:35 +1000 Subject: [PATCH 1209/2058] Add handle properties theme support --- ProcessHacker/hndlprp.c | 5 ++--- phlib/secedit.c | 7 +++++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/ProcessHacker/hndlprp.c b/ProcessHacker/hndlprp.c index 46ed9dfb1034..3f9471b7bdae 100644 --- a/ProcessHacker/hndlprp.c +++ b/ProcessHacker/hndlprp.c @@ -29,8 +29,7 @@ #include #include - -#include +#include typedef enum _PHP_HANDLE_GENERAL_CATEGORY { @@ -916,7 +915,7 @@ INT_PTR CALLBACK PhpHandleGeneralDlgProc( PhpUpdateHandleGeneralListViewGroups(context); PhpUpdateHandleGeneral(context); - EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); + PhInitializeWindowTheme(GetParent(hwndDlg), PhEnableThemeSupport); // HACK } break; case WM_DESTROY: diff --git a/phlib/secedit.c b/phlib/secedit.c index 2893016c046b..d15cb65b18b9 100644 --- a/phlib/secedit.c +++ b/phlib/secedit.c @@ -390,10 +390,13 @@ HRESULT STDMETHODCALLTYPE PhSecurityInformation_PropertySheetPageCallback( { PhSecurityInformation *this = (PhSecurityInformation *)This; - if (uMsg == PSPCB_SI_INITDIALOG && !this->IsPage) + if (uMsg == PSPCB_SI_INITDIALOG) { // Center the security editor window. - PhCenterWindow(GetParent(hwnd), GetParent(GetParent(hwnd))); + if (!this->IsPage) + PhCenterWindow(GetParent(hwnd), GetParent(GetParent(hwnd))); + + PhInitializeWindowTheme(hwnd, !!PhGetIntegerSetting(L"EnableThemeSupport")); } return E_NOTIMPL; From 3f448872a7858d8228f4b315d4a7316a92c71d6f Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 25 Jul 2018 05:07:51 +1000 Subject: [PATCH 1210/2058] Plugins: Update theme margins --- ProcessHacker/ProcessHacker.rc | 4 --- plugins/ExtendedTools/ExtendedTools.rc | 9 ++--- plugins/ExtendedTools/gpudetails.c | 10 ++---- plugins/HardwareDevices/HardwareDevices.rc | 13 ++----- plugins/HardwareDevices/diskoptions.c | 42 +++++++++------------- plugins/HardwareDevices/netdetails.c | 13 +++---- 6 files changed, 29 insertions(+), 62 deletions(-) diff --git a/ProcessHacker/ProcessHacker.rc b/ProcessHacker/ProcessHacker.rc index bb7842b24b90..f8219db5ea13 100644 --- a/ProcessHacker/ProcessHacker.rc +++ b/ProcessHacker/ProcessHacker.rc @@ -1981,10 +1981,6 @@ BEGIN IDD_SYSINFO, DIALOG BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 416 - TOPMARGIN, 7 - BOTTOMMARGIN, 240 END IDD_EDITMESSAGE, DIALOG diff --git a/plugins/ExtendedTools/ExtendedTools.rc b/plugins/ExtendedTools/ExtendedTools.rc index 78bbd69af1ae..10fe98326d29 100644 --- a/plugins/ExtendedTools/ExtendedTools.rc +++ b/plugins/ExtendedTools/ExtendedTools.rc @@ -339,13 +339,12 @@ BEGIN RTEXT "Static",IDC_ZSECTIONRESERVED_V,111,117,54,8,SS_ENDELLIPSIS END -IDD_SYSINFO_GPUDETAILS DIALOGEX 0, 0, 309, 211 +IDD_SYSINFO_GPUDETAILS DIALOGEX 0, 0, 309, 210 STYLE DS_SETFONT | DS_FIXEDSYS | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME CAPTION "GPU Adapter Details" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN - DEFPUSHBUTTON "OK",IDOK,258,195,50,14 - CONTROL "",IDC_GPULIST,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,2,2,305,191 + CONTROL "",IDC_GPULIST,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_ALIGNLEFT | WS_TABSTOP,0,0,309,210 END @@ -472,10 +471,6 @@ BEGIN IDD_SYSINFO_GPUDETAILS, DIALOG BEGIN - LEFTMARGIN, 2 - RIGHTMARGIN, 307 - TOPMARGIN, 2 - BOTTOMMARGIN, 209 END END #endif // APSTUDIO_INVOKED diff --git a/plugins/ExtendedTools/gpudetails.c b/plugins/ExtendedTools/gpudetails.c index 7cbad0336831..dc6cc4ee201f 100644 --- a/plugins/ExtendedTools/gpudetails.c +++ b/plugins/ExtendedTools/gpudetails.c @@ -327,6 +327,8 @@ INT_PTR CALLBACK EtpGpuDetailsDlgProc( SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhInstanceHandle, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhInstanceHandle, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); + PhCenterWindow(hwndDlg, GetParent(hwndDlg)); + PhSetListViewStyle(listViewHandle, FALSE, TRUE); PhSetControlTheme(listViewHandle, L"explorer"); PhAddListViewColumn(listViewHandle, 0, 0, 0, LVCFMT_LEFT, 230, L"Property"); @@ -336,9 +338,6 @@ INT_PTR CALLBACK EtpGpuDetailsDlgProc( PhInitializeLayoutManager(&LayoutManager, hwndDlg); PhAddLayoutItem(&LayoutManager, listViewHandle, NULL, PH_ANCHOR_ALL); - PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDOK), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); - - PhCenterWindow(hwndDlg, GetParent(hwndDlg)); EtpGpuDetailsEnumAdapters(listViewHandle); @@ -364,10 +363,7 @@ INT_PTR CALLBACK EtpGpuDetailsDlgProc( switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDCANCEL: - case IDOK: - { - EndDialog(hwndDlg, IDOK); - } + EndDialog(hwndDlg, IDOK); break; } } diff --git a/plugins/HardwareDevices/HardwareDevices.rc b/plugins/HardwareDevices/HardwareDevices.rc index b036823b8352..a4ed0eff794d 100644 --- a/plugins/HardwareDevices/HardwareDevices.rc +++ b/plugins/HardwareDevices/HardwareDevices.rc @@ -130,8 +130,7 @@ STYLE DS_SETFONT | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS CAPTION "Adapter Details" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN - PUSHBUTTON "Close",IDOK,253,244,50,14 - CONTROL "",IDC_DETAILS_LIST,"SysListView32",LVS_REPORT | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,7,295,235 + CONTROL "",IDC_DETAILS_LIST,"SysListView32",LVS_REPORT | LVS_ALIGNLEFT | WS_TABSTOP,0,0,309,265 END IDD_DISKDRIVE_OPTIONS DIALOGEX 0, 0, 265, 177 @@ -180,7 +179,7 @@ STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSM CAPTION "SMART" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN - CONTROL "",IDC_DETAILS_LIST,"SysListView32",LVS_REPORT | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,0,1,309,264 + CONTROL "",IDC_DETAILS_LIST,"SysListView32",LVS_REPORT | LVS_ALIGNLEFT | WS_TABSTOP,0,0,309,265 END IDD_DISKDRIVE_DETAILS_FILESYSTEM DIALOGEX 0, 0, 309, 265 @@ -188,7 +187,7 @@ STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSM CAPTION "Volume(s)" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN - CONTROL "",IDC_DETAILS_LIST,"SysListView32",LVS_REPORT | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,0,1,309,264 + CONTROL "",IDC_DETAILS_LIST,"SysListView32",LVS_REPORT | LVS_ALIGNLEFT | WS_TABSTOP,0,0,309,265 END @@ -220,10 +219,6 @@ BEGIN IDD_NETADAPTER_DETAILS, DIALOG BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 302 - TOPMARGIN, 7 - BOTTOMMARGIN, 258 END IDD_DISKDRIVE_OPTIONS, DIALOG @@ -248,12 +243,10 @@ BEGIN IDD_DISKDRIVE_DETAILS_SMART, DIALOG BEGIN - TOPMARGIN, 1 END IDD_DISKDRIVE_DETAILS_FILESYSTEM, DIALOG BEGIN - TOPMARGIN, 1 END END #endif // APSTUDIO_INVOKED diff --git a/plugins/HardwareDevices/diskoptions.c b/plugins/HardwareDevices/diskoptions.c index f57c3f259212..3a6bb4d0fd7c 100644 --- a/plugins/HardwareDevices/diskoptions.c +++ b/plugins/HardwareDevices/diskoptions.c @@ -555,22 +555,18 @@ VOID LoadDiskDriveImages( ) { HICON smallIcon; - - Context->ImageList = ImageList_Create( - GetSystemMetrics(SM_CXICON), - GetSystemMetrics(SM_CYICON), - ILC_COLOR32, - 1, - 1 - ); - CONFIGRET result; + ULONG bufferSize; + PPH_STRING deviceDescription; + PH_STRINGREF dllPartSr; + PH_STRINGREF indexPartSr; + ULONG64 index; DEVPROPTYPE devicePropertyType; ULONG deviceInstanceIdLength = MAX_DEVICE_ID_LEN; WCHAR deviceInstanceId[MAX_DEVICE_ID_LEN + 1] = L""; - ULONG bufferSize = 0x40; - PPH_STRING deviceDescription = PhCreateStringEx(NULL, bufferSize); + bufferSize = 0x40; + deviceDescription = PhCreateStringEx(NULL, bufferSize); if ((result = CM_Get_Class_Property( &GUID_DEVCLASS_DISKDRIVE, @@ -595,30 +591,24 @@ VOID LoadDiskDriveImages( } // %SystemRoot%\System32\setupapi.dll,-53 - - PH_STRINGREF dllPartSr; - PH_STRINGREF indexPartSr; - ULONG64 index; - PhSplitStringRefAtChar(&deviceDescription->sr, ',', &dllPartSr, &indexPartSr); PhStringToInteger64(&indexPartSr, 10, &index); PhMoveReference(&deviceDescription, PhExpandEnvironmentStrings(&dllPartSr)); - // We could use SetupDiLoadClassIcon but this works. - // Copied from HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\Class\{4d36e967-e325-11ce-bfc1-08002be10318}\\IconPath - // The index is only valid on Vista and above. - if (PhExtractIconEx(deviceDescription->Buffer, (INT)index, &smallIcon, NULL)) { + Context->ImageList = ImageList_Create( + GetSystemMetrics(SM_CXICON), + GetSystemMetrics(SM_CYICON), + ILC_COLOR32, + 1, + 1 + ); + ImageList_AddIcon(Context->ImageList, smallIcon); DestroyIcon(smallIcon); - // Set the imagelist only if the image was loaded. - ListView_SetImageList( - Context->ListViewHandle, - Context->ImageList, - LVSIL_SMALL - ); + ListView_SetImageList(Context->ListViewHandle, Context->ImageList, LVSIL_SMALL); } } diff --git a/plugins/HardwareDevices/netdetails.c b/plugins/HardwareDevices/netdetails.c index 8bcc41f9df77..db01f6d41656 100644 --- a/plugins/HardwareDevices/netdetails.c +++ b/plugins/HardwareDevices/netdetails.c @@ -525,21 +525,19 @@ INT_PTR CALLBACK NetAdapterDetailsDlgProc( context->WindowHandle = hwndDlg; context->ListViewHandle = GetDlgItem(hwndDlg, IDC_DETAILS_LIST); - if (context->AdapterName) - SetWindowText(hwndDlg, context->AdapterName->Buffer); - else - SetWindowText(hwndDlg, L"Unknown network adapter"); + SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhInstanceHandle, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); + SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhInstanceHandle, MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); + SetWindowText(hwndDlg, PhGetStringOrDefault(context->AdapterName, L"Unknown network adapter")); PhCenterWindow(hwndDlg, context->ParentHandle); PhSetListViewStyle(context->ListViewHandle, FALSE, TRUE); PhSetControlTheme(context->ListViewHandle, L"explorer"); - PhAddListViewColumn(context->ListViewHandle, 0, 0, 0, LVCFMT_LEFT, 135, L"Property"); - PhAddListViewColumn(context->ListViewHandle, 1, 1, 1, LVCFMT_LEFT, 262, L"Value"); + PhAddListViewColumn(context->ListViewHandle, 0, 0, 0, LVCFMT_LEFT, 200, L"Property"); + PhAddListViewColumn(context->ListViewHandle, 1, 1, 1, LVCFMT_LEFT, 240, L"Value"); PhInitializeLayoutManager(&context->LayoutManager, hwndDlg); PhAddLayoutItem(&context->LayoutManager, context->ListViewHandle, NULL, PH_ANCHOR_ALL); - PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDOK), NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_RIGHT); NetAdapterAddListViewItemGroups(context->ListViewHandle); @@ -580,7 +578,6 @@ INT_PTR CALLBACK NetAdapterDetailsDlgProc( switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDCANCEL: - case IDOK: DestroyWindow(hwndDlg); break; } From 5ddf1a33aa60025cea7dd3f2ab21858e57945fdf Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 25 Jul 2018 06:26:39 +1000 Subject: [PATCH 1211/2058] Fix handle properties parenting --- ProcessHacker/hndlprp.c | 95 +++++++++++++++++++++++++--------------- ProcessHacker/settings.c | 2 + 2 files changed, 61 insertions(+), 36 deletions(-) diff --git a/ProcessHacker/hndlprp.c b/ProcessHacker/hndlprp.c index 3f9471b7bdae..74f77013a378 100644 --- a/ProcessHacker/hndlprp.c +++ b/ProcessHacker/hndlprp.c @@ -22,7 +22,7 @@ */ #include - +#include #include #include #include @@ -139,26 +139,32 @@ static NTSTATUS PhpDuplicateHandleFromProcess( return status; } -VOID PhShowHandleProperties( - _In_ HWND ParentWindowHandle, - _In_ HANDLE ProcessId, - _In_ PPH_HANDLE_ITEM HandleItem +typedef struct _HANDLE_PROPERTIES_THREAD_CONTEXT +{ + HWND ParentWindowHandle; + HANDLE ProcessId; + PPH_HANDLE_ITEM HandleItem; +} HANDLE_PROPERTIES_THREAD_CONTEXT, *PHANDLE_PROPERTIES_THREAD_CONTEXT; + +NTSTATUS PhpShowHandlePropertiesThread( + _In_ PVOID Parameter ) { - PROPSHEETHEADER propSheetHeader = { sizeof(propSheetHeader) }; + PHANDLE_PROPERTIES_THREAD_CONTEXT handleContext = Parameter; + PROPSHEETHEADER propSheetHeader = { sizeof(PROPSHEETHEADER) }; PROPSHEETPAGE propSheetPage; HPROPSHEETPAGE pages[16]; HANDLE_PROPERTIES_CONTEXT context; - context.ProcessId = ProcessId; - context.HandleItem = HandleItem; + context.ProcessId = handleContext->ProcessId; + context.HandleItem = handleContext->HandleItem; propSheetHeader.dwFlags = PSH_NOAPPLYNOW | PSH_NOCONTEXTHELP | PSH_PROPTITLE; propSheetHeader.hInstance = PhInstanceHandle; - propSheetHeader.hwndParent = ParentWindowHandle; + propSheetHeader.hwndParent = handleContext->ParentWindowHandle; propSheetHeader.pszCaption = L"Handle"; propSheetHeader.nPages = 0; propSheetHeader.nStartPage = 0; @@ -174,25 +180,25 @@ VOID PhShowHandleProperties( pages[propSheetHeader.nPages++] = CreatePropertySheetPage(&propSheetPage); // Object-specific page - if (PhIsNullOrEmptyString(HandleItem->TypeName)) + if (PhIsNullOrEmptyString(handleContext->HandleItem->TypeName)) { NOTHING; } - else if (PhEqualString2(HandleItem->TypeName, L"Event", TRUE)) + else if (PhEqualString2(handleContext->HandleItem->TypeName, L"Event", TRUE)) { pages[propSheetHeader.nPages++] = PhCreateEventPage( PhpDuplicateHandleFromProcess, &context ); } - else if (PhEqualString2(HandleItem->TypeName, L"EventPair", TRUE)) + else if (PhEqualString2(handleContext->HandleItem->TypeName, L"EventPair", TRUE)) { pages[propSheetHeader.nPages++] = PhCreateEventPairPage( PhpDuplicateHandleFromProcess, &context ); } - else if (PhEqualString2(HandleItem->TypeName, L"Job", TRUE)) + else if (PhEqualString2(handleContext->HandleItem->TypeName, L"Job", TRUE)) { pages[propSheetHeader.nPages++] = PhCreateJobPage( PhpDuplicateHandleFromProcess, @@ -200,35 +206,21 @@ VOID PhShowHandleProperties( NULL ); } - //else if (PhEqualString2(HandleItem->TypeName, L"Mutant", TRUE)) - //{ - // pages[propSheetHeader.nPages++] = PhCreateMutantPage( - // PhpDuplicateHandleFromProcess, - // &context - // ); - //} - //else if (PhEqualString2(HandleItem->TypeName, L"Section", TRUE)) - //{ - // pages[propSheetHeader.nPages++] = PhCreateSectionPage( - // PhpDuplicateHandleFromProcess, - // &context - // ); - //} - else if (PhEqualString2(HandleItem->TypeName, L"Semaphore", TRUE)) + else if (PhEqualString2(handleContext->HandleItem->TypeName, L"Semaphore", TRUE)) { pages[propSheetHeader.nPages++] = PhCreateSemaphorePage( PhpDuplicateHandleFromProcess, &context ); } - else if (PhEqualString2(HandleItem->TypeName, L"Timer", TRUE)) + else if (PhEqualString2(handleContext->HandleItem->TypeName, L"Timer", TRUE)) { pages[propSheetHeader.nPages++] = PhCreateTimerPage( PhpDuplicateHandleFromProcess, &context ); } - else if (PhEqualString2(HandleItem->TypeName, L"Token", TRUE)) + else if (PhEqualString2(handleContext->HandleItem->TypeName, L"Token", TRUE)) { pages[propSheetHeader.nPages++] = PhCreateTokenPage( PhpDuplicateHandleFromProcess, @@ -239,8 +231,8 @@ VOID PhShowHandleProperties( // Security page pages[propSheetHeader.nPages++] = PhCreateSecurityPage( - PhGetStringOrEmpty(HandleItem->BestObjectName), - PhGetStringOrEmpty(HandleItem->TypeName), + PhGetStringOrEmpty(handleContext->HandleItem->BestObjectName), + PhGetStringOrEmpty(handleContext->HandleItem->TypeName), PhpDuplicateHandleFromProcess, NULL, &context @@ -251,12 +243,12 @@ VOID PhShowHandleProperties( PH_PLUGIN_OBJECT_PROPERTIES objectProperties; PH_PLUGIN_HANDLE_PROPERTIES_CONTEXT propertiesContext; - propertiesContext.ProcessId = ProcessId; - propertiesContext.HandleItem = HandleItem; + propertiesContext.ProcessId = handleContext->ProcessId; + propertiesContext.HandleItem = handleContext->HandleItem; objectProperties.Parameter = &propertiesContext; objectProperties.NumberOfPages = propSheetHeader.nPages; - objectProperties.MaximumNumberOfPages = sizeof(pages) / sizeof(HPROPSHEETPAGE); + objectProperties.MaximumNumberOfPages = RTL_NUMBER_OF(pages); objectProperties.Pages = pages; PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackHandlePropertiesInitializing), &objectProperties); @@ -265,6 +257,28 @@ VOID PhShowHandleProperties( } PhModalPropertySheet(&propSheetHeader); + + PhDereferenceObject(handleContext->HandleItem); + PhFree(handleContext); + + return STATUS_SUCCESS; +} + +VOID PhShowHandleProperties( + _In_ HWND ParentWindowHandle, + _In_ HANDLE ProcessId, + _In_ PPH_HANDLE_ITEM HandleItem + ) +{ + PHANDLE_PROPERTIES_THREAD_CONTEXT context; + + context = PhAllocate(sizeof(HANDLE_PROPERTIES_THREAD_CONTEXT)); + context->ParentWindowHandle = PhCsForceNoParent ? NULL : ParentWindowHandle; + context->ProcessId = ProcessId; + context->HandleItem = HandleItem; + PhReferenceObject(HandleItem); + + PhCreateThread2(PhpShowHandlePropertiesThread, context); } VOID PhpUpdateHandleGeneralListViewGroups( @@ -900,7 +914,8 @@ INT_PTR CALLBACK PhpHandleGeneralDlgProc( case WM_INITDIALOG: { // HACK - PhCenterWindow(GetParent(hwndDlg), GetParent(GetParent(hwndDlg))); + SendMessage(GetParent(hwndDlg), WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER))); + SendMessage(GetParent(hwndDlg), WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER))); context->ListViewHandle = GetDlgItem(hwndDlg, IDC_LIST); PhSetListViewStyle(context->ListViewHandle, FALSE, TRUE); @@ -909,6 +924,12 @@ INT_PTR CALLBACK PhpHandleGeneralDlgProc( PhAddListViewColumn(context->ListViewHandle, 1, 1, 1, LVCFMT_LEFT, 250, L"Value"); PhSetExtendedListView(context->ListViewHandle); + // HACK + if (PhGetIntegerPairSetting(L"HandlePropertiesWindowPosition").X != 0) + PhLoadWindowPlacementFromSetting(L"HandlePropertiesWindowPosition", L"HandlePropertiesWindowSize", GetParent(hwndDlg)); + else + PhCenterWindow(GetParent(hwndDlg), GetParent(GetParent(hwndDlg))); // HACK + PhInitializeLayoutManager(&context->LayoutManager, hwndDlg); PhAddLayoutItem(&context->LayoutManager, context->ListViewHandle, NULL, PH_ANCHOR_ALL); @@ -920,6 +941,8 @@ INT_PTR CALLBACK PhpHandleGeneralDlgProc( break; case WM_DESTROY: { + PhSaveWindowPlacementToSetting(L"HandlePropertiesWindowPosition", L"HandlePropertiesWindowSize", GetParent(hwndDlg)); // HACK + PhDeleteLayoutManager(&context->LayoutManager); PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT); diff --git a/ProcessHacker/settings.c b/ProcessHacker/settings.c index f8c068a0001d..ec634ce57035 100644 --- a/ProcessHacker/settings.c +++ b/ProcessHacker/settings.c @@ -68,6 +68,8 @@ VOID PhAddDefaultSettings( PhpAddIntegerSetting(L"ForceNoParent", L"1"); PhpAddStringSetting(L"HandleTreeListColumns", L""); PhpAddStringSetting(L"HandleTreeListSort", L"0,1"); // 0, AscendingSortOrder + PhpAddIntegerPairSetting(L"HandlePropertiesWindowPosition", L"0,0"); + PhpAddScalableIntegerPairSetting(L"HandlePropertiesWindowSize", L"@96|260,260"); PhpAddIntegerSetting(L"HiddenProcessesMenuEnabled", L"0"); PhpAddStringSetting(L"HiddenProcessesListViewColumns", L""); PhpAddIntegerPairSetting(L"HiddenProcessesWindowPosition", L"400,400"); From bfec8f5bf818c9f6f68fb57671591a85c9f11fbc Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 25 Jul 2018 06:34:14 +1000 Subject: [PATCH 1212/2058] Fix regression --- phlib/secedit.c | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/phlib/secedit.c b/phlib/secedit.c index d15cb65b18b9..7110cb24d6c9 100644 --- a/phlib/secedit.c +++ b/phlib/secedit.c @@ -163,8 +163,6 @@ ISecurityInformation *PhSecurityInformation_Create( ) { PhSecurityInformation *info; - PPH_ACCESS_ENTRY accessEntries; - ULONG numberOfAccessEntries; ULONG i; info = PhAllocate(sizeof(PhSecurityInformation)); @@ -179,24 +177,21 @@ ISecurityInformation *PhSecurityInformation_Create( info->Context = Context; info->IsPage = IsPage; - if (PhGetAccessEntries(ObjectType, &accessEntries, &numberOfAccessEntries)) + if (PhGetAccessEntries(ObjectType, &info->AccessEntriesArray, &info->NumberOfAccessEntries)) { - info->AccessEntries = PhAllocate(sizeof(SI_ACCESS) * numberOfAccessEntries); - info->NumberOfAccessEntries = numberOfAccessEntries; + info->AccessEntries = PhAllocate(sizeof(SI_ACCESS) * info->NumberOfAccessEntries); - for (i = 0; i < numberOfAccessEntries; i++) + for (i = 0; i < info->NumberOfAccessEntries; i++) { memset(&info->AccessEntries[i], 0, sizeof(SI_ACCESS)); - info->AccessEntries[i].pszName = accessEntries[i].Name; - info->AccessEntries[i].mask = accessEntries[i].Access; + info->AccessEntries[i].pszName = info->AccessEntriesArray[i].Name; + info->AccessEntries[i].mask = info->AccessEntriesArray[i].Access; - if (accessEntries[i].General) + if (info->AccessEntriesArray[i].General) info->AccessEntries[i].dwFlags |= SI_ACCESS_GENERAL; - if (accessEntries[i].Specific) + if (info->AccessEntriesArray[i].Specific) info->AccessEntries[i].dwFlags |= SI_ACCESS_SPECIFIC; } - - info->AccessEntriesArray = accessEntries; } return (ISecurityInformation *)info; From ed6ab455598ec0eab985079d840f3ee28eeb1fde Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 25 Jul 2018 06:59:00 +1000 Subject: [PATCH 1213/2058] Update general options --- ProcessHacker/options.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/ProcessHacker/options.c b/ProcessHacker/options.c index 404f44bd0c37..0550da310a4e 100644 --- a/ProcessHacker/options.c +++ b/ProcessHacker/options.c @@ -962,9 +962,10 @@ typedef enum _PHP_OPTIONS_INDEX PHP_OPTIONS_INDEX_ENABLE_WARNINGS, PHP_OPTIONS_INDEX_ENABLE_PLUGINS, PHP_OPTIONS_INDEX_ENABLE_UNDECORATE_SYMBOLS, + PHP_OPTIONS_INDEX_ENABLE_CYCLE_CPU_USAGE, + PHP_OPTIONS_INDEX_ENABLE_THEME_SUPPORT, PHP_OPTIONS_INDEX_ENABLE_NETWORK_RESOLVE, PHP_OPTIONS_INDEX_ENABLE_INSTANT_TOOLTIPS, - PHP_OPTIONS_INDEX_ENABLE_CYCLE_CPU_USAGE, PHP_OPTIONS_INDEX_ENABLE_STAGE2, PHP_OPTIONS_INDEX_ENABLE_SERVICE_STAGE2, PHP_OPTIONS_INDEX_COLLAPSE_SERVICES_ON_START, @@ -999,17 +1000,18 @@ static VOID PhpAdvancedPageLoad( PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_WARNINGS, L"Enable warnings", NULL); PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_PLUGINS, L"Enable plugins", NULL); PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_UNDECORATE_SYMBOLS, L"Enable undecorated symbols", NULL); - PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_NETWORK_RESOLVE, L"Resolve network addresses", NULL); - PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_INSTANT_TOOLTIPS, L"Show tooltips instantly", NULL); PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_CYCLE_CPU_USAGE, L"Enable cycle-based CPU usage", NULL); + PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_THEME_SUPPORT, L"Enable theme support (experimental)", NULL); + PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_NETWORK_RESOLVE, L"Resolve network addresses", NULL); + PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_INSTANT_TOOLTIPS, L"Show tooltips instantly", NULL); PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_STAGE2, L"Check images for digital signatures", NULL); PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_SERVICE_STAGE2, L"Check services for digital signatures", NULL); PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_COLLAPSE_SERVICES_ON_START, L"Collapse services on start", NULL); PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_ICON_SINGLE_CLICK, L"Single-click tray icons", NULL); PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_ICON_TOGGLE_VISIBILITY, L"Icon click toggles visibility", NULL); PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_PROPAGATE_CPU_USAGE, L"Include usage of collapsed processes", NULL); - PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_SHOW_HEX_ID, L"Show hexadecimal IDs", NULL); - PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_SHOW_ADVANCED_OPTIONS, L"Show advanced options", NULL); + PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_SHOW_HEX_ID, L"Show hexadecimal IDs (experimental)", NULL); + PhAddListViewItem(listViewHandle, PHP_OPTIONS_INDEX_SHOW_ADVANCED_OPTIONS, L"Show advanced options (experimental)", NULL); SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_SINGLE_INSTANCE, L"AllowOnlyOneInstance"); SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_HIDE_WHENCLOSED, L"HideOnClose"); @@ -1020,9 +1022,10 @@ static VOID PhpAdvancedPageLoad( SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_WARNINGS, L"EnableWarnings"); SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_PLUGINS, L"EnablePlugins"); SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_UNDECORATE_SYMBOLS, L"DbgHelpUndecorate"); + SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_CYCLE_CPU_USAGE, L"EnableCycleCpuUsage"); + SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_THEME_SUPPORT, L"EnableThemeSupport"); SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_NETWORK_RESOLVE, L"EnableNetworkResolve"); SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_INSTANT_TOOLTIPS, L"EnableInstantTooltips"); - SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_CYCLE_CPU_USAGE, L"EnableCycleCpuUsage"); SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_STAGE2, L"EnableStage2"); SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_SERVICE_STAGE2, L"EnableServiceStage2"); SetLvItemCheckForSetting(listViewHandle, PHP_OPTIONS_INDEX_COLLAPSE_SERVICES_ON_START, L"CollapseServicesOnStart"); @@ -1111,9 +1114,10 @@ static VOID PhpAdvancedPageSave( SetSettingForLvItemCheck(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_WARNINGS, L"EnableWarnings"); SetSettingForLvItemCheckRestartRequired(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_PLUGINS, L"EnablePlugins"); SetSettingForLvItemCheck(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_UNDECORATE_SYMBOLS, L"DbgHelpUndecorate"); + SetSettingForLvItemCheckRestartRequired(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_CYCLE_CPU_USAGE, L"EnableCycleCpuUsage"); + SetSettingForLvItemCheckRestartRequired(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_THEME_SUPPORT, L"EnableThemeSupport"); SetSettingForLvItemCheckRestartRequired(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_NETWORK_RESOLVE, L"EnableNetworkResolve"); SetSettingForLvItemCheck(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_INSTANT_TOOLTIPS, L"EnableInstantTooltips"); - SetSettingForLvItemCheckRestartRequired(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_CYCLE_CPU_USAGE, L"EnableCycleCpuUsage"); SetSettingForLvItemCheckRestartRequired(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_STAGE2, L"EnableStage2"); SetSettingForLvItemCheckRestartRequired(listViewHandle, PHP_OPTIONS_INDEX_ENABLE_SERVICE_STAGE2, L"EnableServiceStage2"); SetSettingForLvItemCheck(listViewHandle, PHP_OPTIONS_INDEX_COLLAPSE_SERVICES_ON_START, L"CollapseServicesOnStart"); From 610d49d4c8c44189145bb0917e7e09934ef83cb0 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 25 Jul 2018 17:23:02 +1000 Subject: [PATCH 1214/2058] Add options window theme support --- ProcessHacker/options.c | 39 ++++++++++++++++++++++++++++++++------- 1 file changed, 32 insertions(+), 7 deletions(-) diff --git a/ProcessHacker/options.c b/ProcessHacker/options.c index 0550da310a4e..210a6efd9a54 100644 --- a/ProcessHacker/options.c +++ b/ProcessHacker/options.c @@ -24,7 +24,6 @@ #include #include -#include #include #include @@ -292,6 +291,8 @@ INT_PTR CALLBACK PhOptionsDialogProc( //PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDC_APPLY), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDOK), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); + PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport); + { PPH_OPTIONS_SECTION section; @@ -321,8 +322,6 @@ INT_PTR CALLBACK PhOptionsDialogProc( PhCenterWindow(hwndDlg, PhMainWndHandle); PhLoadWindowPlacementFromSetting(L"OptionsWindowPosition", L"OptionsWindowSize", hwndDlg); - - EnableThemeDialogTexture(ContainerControl, ETDT_ENABLETAB); } break; case WM_DESTROY: @@ -421,9 +420,33 @@ INT_PTR CALLBACK PhOptionsDialogProc( rect = drawInfo->rcItem; rect.right = 2; - FillRect(drawInfo->hDC, &rect, GetSysColorBrush(COLOR_3DHIGHLIGHT)); - rect.left += 1; - FillRect(drawInfo->hDC, &rect, GetSysColorBrush(COLOR_3DSHADOW)); + + if (PhEnableThemeSupport) + { + switch (PhCsGraphColorMode) + { + case 0: // New colors + { + FillRect(drawInfo->hDC, &rect, GetSysColorBrush(COLOR_3DHIGHLIGHT)); + rect.left += 1; + FillRect(drawInfo->hDC, &rect, GetSysColorBrush(COLOR_3DSHADOW)); + } + break; + case 1: // Old colors + { + SetDCBrushColor(drawInfo->hDC, RGB(0, 0, 0)); + FillRect(drawInfo->hDC, &rect, GetStockObject(DC_BRUSH)); + } + break; + } + } + else + { + FillRect(drawInfo->hDC, &rect, GetSysColorBrush(COLOR_3DHIGHLIGHT)); + rect.left += 1; + FillRect(drawInfo->hDC, &rect, GetSysColorBrush(COLOR_3DSHADOW)); + } + return TRUE; } } @@ -643,6 +666,8 @@ VOID PhOptionsCreateSectionDialog( Section->DialogProc, Section->Parameter ); + + PhInitializeWindowTheme(Section->DialogHandle, PhEnableThemeSupport); } #define SetDlgItemCheckForSetting(hwndDlg, Id, Name) \ @@ -1670,7 +1695,7 @@ UINT_PTR CALLBACK PhpColorDlgHookProc( { PhCenterWindow(hwndDlg, PhOptionsWindowHandle); - EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); + PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport); } break; } From 928b805ba5d5714a6758d495687519e8365b5187 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 25 Jul 2018 17:41:40 +1000 Subject: [PATCH 1215/2058] Fix treeview theme --- phlib/theme.c | 599 +++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 515 insertions(+), 84 deletions(-) diff --git a/phlib/theme.c b/phlib/theme.c index 0351e753d6d3..f336d242c126 100644 --- a/phlib/theme.c +++ b/phlib/theme.c @@ -36,21 +36,27 @@ typedef struct _PHP_THEME_WINDOW_TAB_CONTEXT BOOLEAN MouseActive; } PHP_THEME_WINDOW_TAB_CONTEXT, *PPHP_THEME_WINDOW_TAB_CONTEXT; +typedef struct _PHP_THEME_WINDOW_HEADER_CONTEXT +{ + WNDPROC DefaultWindowProc; + BOOLEAN MouseActive; +} PHP_THEME_WINDOW_HEADER_CONTEXT, *PPHP_THEME_WINDOW_HEADER_CONTEXT; + BOOLEAN CALLBACK PhpThemeWindowEnumChildWindows( _In_ HWND WindowHandle, _In_opt_ PVOID Context ); -BOOLEAN CALLBACK PhpReInitializeWindowThemeEnumChildWindows( +BOOLEAN CALLBACK PhpReInitializeThemeWindowEnumChildWindows( _In_ HWND WindowHandle, _In_opt_ PVOID Context ); -LRESULT PhpWindowThemeDrawButton( +LRESULT PhpThemeWindowDrawButton( _In_ LPNMCUSTOMDRAW DrawInfo ); -LRESULT PhpWindowThemeDrawListViewGroup( +LRESULT PhpThemeWindowDrawListViewGroup( _In_ LPNMLVCUSTOMDRAW DrawInfo ); @@ -58,6 +64,7 @@ COLORREF PhpThemeWindowForegroundColor = RGB(28, 28, 28); COLORREF PhpThemeWindowBackgroundColor = RGB(64, 64, 64); COLORREF PhpThemeWindowTextColor = RGB(0xff, 0xff, 0xff); HFONT PhpTabControlFontHandle = NULL; +HFONT PhpToolBarFontHandle = NULL; HFONT PhpListViewFontHandle = NULL; HFONT PhpGroupboxFontHandle = NULL; @@ -97,7 +104,7 @@ LRESULT CALLBACK PhpThemeWindowSubclassProc( if (PhEqualStringZ(className, L"Button", FALSE)) { - return PhpWindowThemeDrawButton(customDraw); + return PhpThemeWindowDrawButton(customDraw); } else if (PhEqualStringZ(className, L"ReBarWindow32", FALSE)) { @@ -117,7 +124,7 @@ LRESULT CALLBACK PhpThemeWindowSubclassProc( if (listViewCustomDraw->dwItemType == LVCDI_GROUP) { - return PhpWindowThemeDrawListViewGroup(listViewCustomDraw); + return PhpThemeWindowDrawListViewGroup(listViewCustomDraw); } } } @@ -275,9 +282,7 @@ LRESULT CALLBACK PhpThemeWindowTabControlWndSubclassProc( _In_ HWND WindowHandle, _In_ UINT uMsg, _In_ WPARAM wParam, - _In_ LPARAM lParam, - _In_ UINT_PTR uIdSubclass, - _In_ ULONG_PTR dwRefData + _In_ LPARAM lParam ) { PPHP_THEME_WINDOW_TAB_CONTEXT context; @@ -535,24 +540,27 @@ LRESULT CALLBACK PhpThemeWindowTabControlWndSubclassProc( } LRESULT CALLBACK PhpThemeWindowHeaderSubclassProc( - _In_ HWND hWnd, + _In_ HWND WindowHandle, _In_ UINT uMsg, _In_ WPARAM wParam, _In_ LPARAM lParam ) { - static BOOLEAN MouseActive = FALSE; + PPHP_THEME_WINDOW_HEADER_CONTEXT context; WNDPROC oldWndProc; - if (!(oldWndProc = PhGetWindowContext(hWnd, SHRT_MAX))) - return 0; + if (!(context = PhGetWindowContext(WindowHandle, SHRT_MAX))) + return FALSE; + + oldWndProc = context->DefaultWindowProc; switch (uMsg) { - case WM_DESTROY: + case WM_NCDESTROY: { - PhRemoveWindowContext(hWnd, SHRT_MAX); - SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)oldWndProc); + PhRemoveWindowContext(WindowHandle, SHRT_MAX); + SetWindowLongPtr(WindowHandle, GWLP_WNDPROC, (LONG_PTR)oldWndProc); + PhFree(context); } break; //case WM_ERASEBKGND: @@ -565,37 +573,37 @@ LRESULT CALLBACK PhpThemeWindowHeaderSubclassProc( //tcItem.mask = TCIF_STATE; //tcItem.dwStateMask = TCIS_HIGHLIGHTED; //GetCursorPos(&pt); - //MapWindowPoints(NULL, hWnd, &pt, 1); - //int nCount = TabCtrl_GetItemCount(hWnd); + //MapWindowPoints(NULL, WindowHandle, &pt, 1); + //int nCount = TabCtrl_GetItemCount(WindowHandle); //for (int i = 0; i < nCount; i++) //{ - // TabCtrl_GetItemRect(hWnd, i, &rcItem); + // TabCtrl_GetItemRect(WindowHandle, i, &rcItem); // tcItem.dwState = PtInRect(&rcItem, pt) ? TCIS_HIGHLIGHTED : 0; - // TabCtrl_SetItem(hWnd, i, &tcItem); + // TabCtrl_SetItem(WindowHandle, i, &tcItem); //} - if (!MouseActive) + if (!context->MouseActive) { TRACKMOUSEEVENT trackEvent = { sizeof(TRACKMOUSEEVENT), TME_LEAVE, - hWnd, + WindowHandle, 0 }; TrackMouseEvent(&trackEvent); - MouseActive = TRUE; + context->MouseActive = TRUE; } - InvalidateRect(hWnd, NULL, FALSE); + InvalidateRect(WindowHandle, NULL, FALSE); } break; case WM_CONTEXTMENU: { - LRESULT result = DefSubclassProc(hWnd, uMsg, wParam, lParam); + LRESULT result = DefSubclassProc(WindowHandle, uMsg, wParam, lParam); - InvalidateRect(hWnd, NULL, TRUE); + InvalidateRect(WindowHandle, NULL, TRUE); return result; } @@ -603,28 +611,28 @@ LRESULT CALLBACK PhpThemeWindowHeaderSubclassProc( case WM_MOUSELEAVE: { // TCITEM tcItem = { TCIF_STATE, 0, TCIS_HIGHLIGHTED }; - //// int nCount = TabCtrl_GetItemCount(hWnd); + //// int nCount = TabCtrl_GetItemCount(WindowHandle); // for (int i = 0; i < nCount; i++) // { - // //TabCtrl_SetItem(hWnd, i, &tcItem); + // //TabCtrl_SetItem(WindowHandle, i, &tcItem); // } - InvalidateRect(hWnd, NULL, TRUE); - MouseActive = FALSE; + InvalidateRect(WindowHandle, NULL, TRUE); + context->MouseActive = FALSE; } break; case WM_PAINT: { - //HTHEME hTheme = OpenThemeData(hWnd, L"HEADER"); + //HTHEME hTheme = OpenThemeData(WindowHandle, L"HEADER"); WCHAR szText[MAX_PATH + 1]; RECT rcClient; HDITEM tcItem; PAINTSTRUCT ps; - //InvalidateRect(hWnd, NULL, FALSE); - BeginPaint(hWnd, &ps); + //InvalidateRect(WindowHandle, NULL, FALSE); + BeginPaint(WindowHandle, &ps); - GetClientRect(hWnd, &rcClient); + GetClientRect(WindowHandle, &rcClient); ZeroMemory(&tcItem, sizeof(tcItem)); tcItem.mask = HDI_TEXT | HDI_IMAGE | HDI_STATE; @@ -665,17 +673,17 @@ LRESULT CALLBACK PhpThemeWindowHeaderSubclassProc( HDC hdcTab = CreateCompatibleDC(hdc); - INT nCount = Header_GetItemCount(hWnd); + INT nCount = Header_GetItemCount(WindowHandle); for (INT i = 0; i < nCount; i++) { RECT headerRect; POINT pt; - Header_GetItemRect(hWnd, i, &headerRect); - Header_GetItem(hWnd, i, &tcItem); + Header_GetItemRect(WindowHandle, i, &headerRect); + Header_GetItem(WindowHandle, i, &tcItem); GetCursorPos(&pt); - MapWindowPoints(NULL, hWnd, &pt, 1); + MapWindowPoints(NULL, WindowHandle, &pt, 1); if (PtInRect(&headerRect, pt)) { @@ -727,6 +735,175 @@ LRESULT CALLBACK PhpThemeWindowHeaderSubclassProc( BitBlt(ps.hdc, 0, 0, rcClient.right, rcClient.bottom, hdc, 0, 0, SRCCOPY); + DeleteDC(hdc); + DeleteObject(hbm); + EndPaint(WindowHandle, &ps); + } + + return DefWindowProc(WindowHandle, uMsg, wParam, lParam); + } + + return CallWindowProc(oldWndProc, WindowHandle, uMsg, wParam, lParam); +} + +LRESULT CALLBACK PhpThemeWindowStatusbarWndSubclassProc( + _In_ HWND hWnd, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + WNDPROC oldWndProc; + + if (!(oldWndProc = PhGetWindowContext(hWnd, SHRT_MAX))) + return FALSE; + + static BOOLEAN MouseActive = FALSE; + + switch (uMsg) + { + case WM_NCDESTROY: + { + PhRemoveWindowContext(hWnd, SHRT_MAX); + SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)oldWndProc); + } + break; + case WM_ERASEBKGND: + return 1; + case WM_MOUSEMOVE: + { + if (!MouseActive) + { + TRACKMOUSEEVENT trackEvent = + { + sizeof(TRACKMOUSEEVENT), + TME_LEAVE, + hWnd, + 0 + }; + + TrackMouseEvent(&trackEvent); + MouseActive = TRUE; + } + + InvalidateRect(hWnd, NULL, FALSE); + } + break; + case WM_MOUSELEAVE: + { + InvalidateRect(hWnd, NULL, FALSE); + MouseActive = FALSE; + } + break; + case WM_PAINT: + { + RECT rcClient; + PAINTSTRUCT ps; + INT blockCoord[128]; + INT blockCount = (INT)SendMessage(hWnd, (UINT)SB_GETPARTS, (WPARAM)ARRAYSIZE(blockCoord), (WPARAM)blockCoord); + + InvalidateRect(hWnd, NULL, FALSE); + + BeginPaint(hWnd, &ps); + + GetClientRect(hWnd, &rcClient); + + HDC hdc = CreateCompatibleDC(ps.hdc); + HBITMAP hbm = CreateCompatibleBitmap(ps.hdc, rcClient.right, rcClient.bottom); + + SetBkMode(hdc, TRANSPARENT); + + SelectObject(hdc, hbm); + + static HFONT fontHandle = NULL; + if (!fontHandle) + { + NONCLIENTMETRICS metrics = { sizeof(metrics) }; + if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, &metrics, 0)) + { + fontHandle = CreateFontIndirect(&metrics.lfMessageFont); + } + } + SelectObject(hdc, fontHandle); + + + switch (PhGetIntegerSetting(L"GraphColorMode")) + { + case 0: // New colors + SetTextColor(hdc, RGB(0x0, 0x0, 0x0)); + SetDCBrushColor(hdc, RGB(0xff, 0xff, 0xff)); + FillRect(hdc, &rcClient, GetStockObject(DC_BRUSH)); + break; + case 1: // Old colors + SetTextColor(hdc, RGB(0xff, 0xff, 0xff)); + SetDCBrushColor(hdc, RGB(65, 65, 65)); //RGB(28, 28, 28)); // RGB(65, 65, 65)); + FillRect(hdc, &rcClient, GetStockObject(DC_BRUSH)); + break; + } + + HDC hdcTab = CreateCompatibleDC(hdc); + + for (INT i = 0; i < blockCount; i++) + { + RECT blockRect; + WCHAR buffer[260] = L""; + SendMessage(hWnd, SB_GETRECT, (WPARAM)i, (WPARAM)&blockRect); + SendMessage(hWnd, SB_GETTEXT, (WPARAM)i, (LPARAM)buffer); + + POINT pt; + GetCursorPos(&pt); + MapWindowPoints(NULL, hWnd, &pt, 1); + + if (PtInRect(&blockRect, pt)) + { + switch (PhGetIntegerSetting(L"GraphColorMode")) + { + case 0: // New colors + SetTextColor(hdc, RGB(0x0, 0x0, 0x0)); + SetDCBrushColor(hdc, RGB(0xff, 0xff, 0xff)); + FillRect(hdc, &blockRect, GetStockObject(DC_BRUSH)); + //FrameRect(hdc, &blockRect, GetSysColorBrush(COLOR_HIGHLIGHT)); + break; + case 1: // Old colors + SetTextColor(hdc, RGB(0xff, 0xff, 0xff)); + SetDCBrushColor(hdc, RGB(128, 128, 128)); + FillRect(hdc, &blockRect, GetStockObject(DC_BRUSH)); + //FrameRect(hdc, &blockRect, GetSysColorBrush(COLOR_HIGHLIGHT)); + break; + } + } + else + { + switch (PhGetIntegerSetting(L"GraphColorMode")) + { + case 0: // New colors + SetTextColor(hdc, RGB(0x0, 0x0, 0x0)); + SetDCBrushColor(hdc, RGB(0xff, 0xff, 0xff)); + FillRect(hdc, &blockRect, GetStockObject(DC_BRUSH)); + //FrameRect(hdc, &blockRect, GetSysColorBrush(COLOR_HIGHLIGHT)); + break; + case 1: // Old colors + SetTextColor(hdc, RGB(0xff, 0xff, 0xff)); + SetDCBrushColor(hdc, RGB(64, 64, 64)); + FillRect(hdc, &blockRect, GetStockObject(DC_BRUSH)); + //FrameRect(hdc, &blockRect, GetSysColorBrush(COLOR_HIGHLIGHT)); + break; + } + } + + DrawText( + hdc, + buffer, + -1, + &blockRect, + DT_CENTER | DT_VCENTER | DT_SINGLELINE | DT_HIDEPREFIX //| DT_WORD_ELLIPSIS + ); + } + + DeleteDC(hdcTab); + + BitBlt(ps.hdc, 0, 0, rcClient.right, rcClient.bottom, hdc, 0, 0, SRCCOPY); + DeleteDC(hdc); DeleteObject(hbm); EndPaint(hWnd, &ps); @@ -774,7 +951,7 @@ VOID PhReInitializeWindowTheme( PhEnumChildWindows( WindowHandle, 0x1000, - PhpReInitializeWindowThemeEnumChildWindows, + PhpReInitializeThemeWindowEnumChildWindows, 0 ); @@ -799,6 +976,84 @@ VOID PhReInitializeWindowTheme( InvalidateRect(WindowHandle, NULL, FALSE); } +VOID PhInitializeThemeWindowHeader( + _In_ HWND HeaderWindow + ) +{ + PPHP_THEME_WINDOW_HEADER_CONTEXT headerControlContext; + + headerControlContext = PhAllocateZero(sizeof(PHP_THEME_WINDOW_HEADER_CONTEXT)); + headerControlContext->DefaultWindowProc = (WNDPROC)GetWindowLongPtr(HeaderWindow, GWLP_WNDPROC); + PhSetWindowContext(HeaderWindow, SHRT_MAX, headerControlContext); + SetWindowLongPtr(HeaderWindow, GWLP_WNDPROC, (LONG_PTR)PhpThemeWindowHeaderSubclassProc); + + InvalidateRect(HeaderWindow, NULL, FALSE); +} + +VOID PhInitializeThemeWindowTabControl( + _In_ HWND TabControlWindow + ) +{ + PPHP_THEME_WINDOW_TAB_CONTEXT tabControlContext; + + tabControlContext = PhAllocateZero(sizeof(PHP_THEME_WINDOW_TAB_CONTEXT)); + tabControlContext->DefaultWindowProc = (WNDPROC)GetWindowLongPtr(TabControlWindow, GWLP_WNDPROC); + PhSetWindowContext(TabControlWindow, SHRT_MAX, tabControlContext); + SetWindowLongPtr(TabControlWindow, GWLP_WNDPROC, (LONG_PTR)PhpThemeWindowTabControlWndSubclassProc); + + PhSetWindowStyle(TabControlWindow, TCS_OWNERDRAWFIXED, TCS_OWNERDRAWFIXED); + + if (!PhpTabControlFontHandle) + { + PhpTabControlFontHandle = CreateFont( + -(LONG)PhMultiplyDivide(15, PhGlobalDpi, 96), + 0, + 0, + 0, + FW_SEMIBOLD, + FALSE, + FALSE, + FALSE, + ANSI_CHARSET, + OUT_DEFAULT_PRECIS, + CLIP_DEFAULT_PRECIS, + DEFAULT_QUALITY, + DEFAULT_PITCH, + L"Tahoma" + ); + } + + SendMessage(TabControlWindow, WM_SETFONT, (WPARAM)PhpTabControlFontHandle, FALSE); + + InvalidateRect(TabControlWindow, NULL, FALSE); +} + +VOID PhInitializeThemeWindowStatusBar( + _In_ HWND StatusBarHandle + ) +{ + WNDPROC defaultWindowProc; + + defaultWindowProc = (WNDPROC)GetWindowLongPtr(StatusBarHandle, GWLP_WNDPROC); + PhSetWindowContext(StatusBarHandle, SHRT_MAX, defaultWindowProc); + SetWindowLongPtr(StatusBarHandle, GWLP_WNDPROC, (LONG_PTR)PhpThemeWindowStatusbarWndSubclassProc); + + InvalidateRect(StatusBarHandle, NULL, FALSE); +} + +VOID PhInitializeThemeWindowGroupBox( + _In_ HWND GroupBoxHandle + ) +{ + WNDPROC groupboxWindowProc; + + groupboxWindowProc = (WNDPROC)GetWindowLongPtr(GroupBoxHandle, GWLP_WNDPROC); + PhSetWindowContext(GroupBoxHandle, SHRT_MAX, groupboxWindowProc); + SetWindowLongPtr(GroupBoxHandle, GWLP_WNDPROC, (LONG_PTR)PhpThemeWindowGroupBoxSubclassProc); + + InvalidateRect(GroupBoxHandle, NULL, FALSE); +} + BOOLEAN CALLBACK PhpThemeWindowEnumChildWindows( _In_ HWND WindowHandle, _In_opt_ PVOID Context @@ -826,11 +1081,7 @@ BOOLEAN CALLBACK PhpThemeWindowEnumChildWindows( if ((buttonWindowStyle & BS_GROUPBOX) == BS_GROUPBOX) { - WNDPROC groupboxWindowProc; - - groupboxWindowProc = (WNDPROC)GetWindowLongPtr(WindowHandle, GWLP_WNDPROC); - PhSetWindowContext(WindowHandle, SHRT_MAX, groupboxWindowProc); - SetWindowLongPtr(WindowHandle, GWLP_WNDPROC, (LONG_PTR)PhpThemeWindowGroupBoxSubclassProc); + PhInitializeThemeWindowGroupBox(WindowHandle); } } else if (PhEqualStringZ(className, L"Edit", FALSE)) @@ -849,49 +1100,15 @@ BOOLEAN CALLBACK PhpThemeWindowEnumChildWindows( } else if (PhEqualStringZ(className, L"SysTabControl32", FALSE)) { - PPHP_THEME_WINDOW_TAB_CONTEXT tabControlContext; - - tabControlContext = PhAllocateZero(sizeof(PHP_THEME_WINDOW_TAB_CONTEXT)); - tabControlContext->DefaultWindowProc = (WNDPROC)GetWindowLongPtr(WindowHandle, GWLP_WNDPROC); - PhSetWindowContext(WindowHandle, SHRT_MAX, tabControlContext); - SetWindowLongPtr(WindowHandle, GWLP_WNDPROC, (LONG_PTR)PhpThemeWindowTabControlWndSubclassProc); - - PhSetWindowStyle(WindowHandle, TCS_OWNERDRAWFIXED, TCS_OWNERDRAWFIXED); - - if (!PhpTabControlFontHandle) - { - PhpTabControlFontHandle = CreateFont( - -(LONG)PhMultiplyDivide(15, PhGlobalDpi, 96), - 0, - 0, - 0, - FW_SEMIBOLD, - FALSE, - FALSE, - FALSE, - ANSI_CHARSET, - OUT_DEFAULT_PRECIS, - CLIP_DEFAULT_PRECIS, - DEFAULT_QUALITY, - DEFAULT_PITCH, - L"Tahoma" - ); - } - - SendMessage(WindowHandle, WM_SETFONT, (WPARAM)PhpTabControlFontHandle, FALSE); - InvalidateRect(WindowHandle, NULL, FALSE); + PhInitializeThemeWindowTabControl(WindowHandle); } else if (PhEqualStringZ(className, L"msctls_statusbar32", FALSE)) { - NOTHING; + PhInitializeThemeWindowStatusBar(WindowHandle); } else if (PhEqualStringZ(className, L"SysHeader32", FALSE)) { - WNDPROC headerWindowProc; - - headerWindowProc = (WNDPROC)GetWindowLongPtr(WindowHandle, GWLP_WNDPROC); - PhSetWindowContext(WindowHandle, SHRT_MAX, headerWindowProc); - SetWindowLongPtr(WindowHandle, GWLP_WNDPROC, (LONG_PTR)PhpThemeWindowHeaderSubclassProc); + PhInitializeThemeWindowHeader(WindowHandle); } else if (PhEqualStringZ(className, L"SysListView32", FALSE)) { @@ -909,6 +1126,22 @@ BOOLEAN CALLBACK PhpThemeWindowEnumChildWindows( break; } } + else if (PhEqualStringZ(className, L"SysTreeView32", FALSE)) + { + //PhSetWindowStyle(WindowHandle, WS_BORDER, 0); + //PhSetWindowExStyle(WindowHandle, WS_EX_CLIENTEDGE, 0); + + switch (PhGetIntegerSetting(L"GraphColorMode")) + { + case 0: // New colors + break; + case 1: // Old colors + TreeView_SetBkColor(WindowHandle, RGB(30, 30, 30)); + //TreeView_SetTextBkColor(WindowHandle, RGB(30, 30, 30)); + TreeView_SetTextColor(WindowHandle, RGB(0xff, 0xff, 0xff)); + break; + } + } else if (PhEqualStringZ(className, L"ScrollBar", FALSE)) { NOTHING; @@ -922,7 +1155,7 @@ BOOLEAN CALLBACK PhpThemeWindowEnumChildWindows( return TRUE; } -BOOLEAN CALLBACK PhpReInitializeWindowThemeEnumChildWindows( +BOOLEAN CALLBACK PhpReInitializeThemeWindowEnumChildWindows( _In_ HWND WindowHandle, _In_opt_ PVOID Context ) @@ -932,7 +1165,7 @@ BOOLEAN CALLBACK PhpReInitializeWindowThemeEnumChildWindows( PhEnumChildWindows( WindowHandle, 0x1000, - PhpReInitializeWindowThemeEnumChildWindows, + PhpReInitializeThemeWindowEnumChildWindows, 0 ); @@ -946,7 +1179,7 @@ BOOLEAN CALLBACK PhpReInitializeWindowThemeEnumChildWindows( return TRUE; } -LRESULT PhpWindowThemeDrawButton( +LRESULT PhpThemeWindowDrawButton( _In_ LPNMCUSTOMDRAW DrawInfo ) { @@ -1104,7 +1337,205 @@ LRESULT PhpWindowThemeDrawButton( return CDRF_DODEFAULT; } -LRESULT PhpWindowThemeDrawListViewGroup( +LRESULT PhThemeWindowDrawRebar( + _In_ LPNMCUSTOMDRAW DrawInfo + ) +{ + switch (DrawInfo->dwDrawStage) + { + case CDDS_PREPAINT: + { + switch (PhGetIntegerSetting(L"GraphColorMode")) + { + case 0: // New colors + SetTextColor(DrawInfo->hdc, RGB(0x0, 0x0, 0x0)); + SetDCBrushColor(DrawInfo->hdc, RGB(0xff, 0xff, 0xff)); + break; + case 1: // Old colors + SetTextColor(DrawInfo->hdc, RGB(0xff, 0xff, 0xff)); + SetDCBrushColor(DrawInfo->hdc, RGB(65, 65, 65)); + break; + } + + FillRect(DrawInfo->hdc, &DrawInfo->rc, GetStockObject(DC_BRUSH)); + } + return CDRF_NOTIFYITEMDRAW; + case CDDS_ITEMPREPAINT: + { + switch (PhGetIntegerSetting(L"GraphColorMode")) + { + case 0: // New colors + SetTextColor(DrawInfo->hdc, RGB(0x0, 0x0, 0x0)); + SetDCBrushColor(DrawInfo->hdc, RGB(0x0, 0x0, 0x0)); + case 1: // Old colors + SetTextColor(DrawInfo->hdc, RGB(0xff, 0xff, 0xff)); + SetDCBrushColor(DrawInfo->hdc, RGB(65, 65, 65)); + break; + } + + FillRect(DrawInfo->hdc, &DrawInfo->rc, GetStockObject(DC_BRUSH)); + } + return CDRF_SKIPDEFAULT; + } + + return CDRF_DODEFAULT; +} + +LRESULT PhThemeWindowDrawToolbar( + _In_ LPNMTBCUSTOMDRAW DrawInfo + ) +{ + switch (DrawInfo->nmcd.dwDrawStage) + { + case CDDS_PREPAINT: + return CDRF_NOTIFYITEMDRAW | CDRF_NOTIFYPOSTPAINT; + case CDDS_ITEMPREPAINT: + { + TBBUTTONINFO buttonInfo = + { + sizeof(TBBUTTONINFO), + TBIF_STYLE | TBIF_COMMAND | TBIF_STATE | TBIF_IMAGE + }; + + SetBkMode(DrawInfo->nmcd.hdc, TRANSPARENT); + + ULONG currentIndex = (ULONG)SendMessage( + DrawInfo->nmcd.hdr.hwndFrom, + TB_COMMANDTOINDEX, + DrawInfo->nmcd.dwItemSpec, + 0 + ); + BOOLEAN isHighlighted = SendMessage( + DrawInfo->nmcd.hdr.hwndFrom, + TB_GETHOTITEM, + 0, + 0 + ) == currentIndex; + BOOLEAN isMouseDown = SendMessage( + DrawInfo->nmcd.hdr.hwndFrom, + TB_ISBUTTONPRESSED, + DrawInfo->nmcd.dwItemSpec, + 0 + ) == 0; + + //if (isMouseDown) + //{ + // SetTextColor(DrawInfo->nmcd.hdc, RGB(0xff, 0xff, 0xff)); + // SetDCBrushColor(DrawInfo->nmcd.hdc, RGB(0xff, 0xff, 0xff)); + // FillRect(DrawInfo->nmcd.hdc, &DrawInfo->nmcd.rc, GetStockObject(DC_BRUSH)); + //} + + if (isHighlighted) + { + switch (PhGetIntegerSetting(L"GraphColorMode")) + { + case 0: // New colors + SetTextColor(DrawInfo->nmcd.hdc, RGB(0x0, 0x0, 0x0)); + SetDCBrushColor(DrawInfo->nmcd.hdc, RGB(0xff, 0xff, 0xff)); + FillRect(DrawInfo->nmcd.hdc, &DrawInfo->nmcd.rc, GetStockObject(DC_BRUSH)); + break; + case 1: // Old colors + SetTextColor(DrawInfo->nmcd.hdc, RGB(0xff, 0xff, 0xff)); + SetDCBrushColor(DrawInfo->nmcd.hdc, RGB(128, 128, 128)); + FillRect(DrawInfo->nmcd.hdc, &DrawInfo->nmcd.rc, GetStockObject(DC_BRUSH)); + break; + } + } + else + { + switch (PhGetIntegerSetting(L"GraphColorMode")) + { + case 0: // New colors + SetTextColor(DrawInfo->nmcd.hdc, RGB(0x0, 0x0, 0x0)); + SetDCBrushColor(DrawInfo->nmcd.hdc, RGB(0xff, 0xff, 0xff)); + FillRect(DrawInfo->nmcd.hdc, &DrawInfo->nmcd.rc, GetStockObject(DC_BRUSH)); + break; + case 1: // Old colors + SetTextColor(DrawInfo->nmcd.hdc, RGB(0xff, 0xff, 0xff)); + SetDCBrushColor(DrawInfo->nmcd.hdc, RGB(65, 65, 65)); //RGB(28, 28, 28)); // RGB(65, 65, 65)); + FillRect(DrawInfo->nmcd.hdc, &DrawInfo->nmcd.rc, GetStockObject(DC_BRUSH)); + break; + } + } + + if (!PhpToolBarFontHandle) + { + NONCLIENTMETRICS metrics = { sizeof(NONCLIENTMETRICS) }; + + if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, &metrics, 0)) + { + PhpToolBarFontHandle = CreateFontIndirect(&metrics.lfMessageFont); + } + } + + SelectObject(DrawInfo->nmcd.hdc, PhpToolBarFontHandle); + + + if (SendMessage( + DrawInfo->nmcd.hdr.hwndFrom, + TB_GETBUTTONINFO, + (ULONG)DrawInfo->nmcd.dwItemSpec, + (LPARAM)&buttonInfo + ) == -1) + { + break; + } + + if (buttonInfo.iImage != -1) + { + HIMAGELIST toolbarImageList; + + if (toolbarImageList = (HIMAGELIST)SendMessage( + DrawInfo->nmcd.hdr.hwndFrom, + TB_GETIMAGELIST, + 0, + 0 + )) + { + DrawInfo->nmcd.rc.left += 5; + + ImageList_Draw( + toolbarImageList, + buttonInfo.iImage, + DrawInfo->nmcd.hdc, + DrawInfo->nmcd.rc.left, + DrawInfo->nmcd.rc.top + 3, + ILD_NORMAL + ); + } + } + + if (buttonInfo.fsStyle & BTNS_SHOWTEXT) + { + WCHAR buttonText[0x100] = L""; + + SendMessage( + DrawInfo->nmcd.hdr.hwndFrom, + TB_GETBUTTONTEXT, + (ULONG)DrawInfo->nmcd.dwItemSpec, + (LPARAM)buttonText + ); + + DrawInfo->nmcd.rc.left += 10; + DrawText( + DrawInfo->nmcd.hdc, + buttonText, + -1, + &DrawInfo->nmcd.rc, + DT_CENTER | DT_VCENTER | DT_SINGLELINE | DT_HIDEPREFIX + ); + } + + //DrawInfo->clrText = RGB(0x0, 0xff, 0); + //return TBCDRF_USECDCOLORS | CDRF_NEWFONT; + } + return CDRF_SKIPDEFAULT; + } + + return CDRF_DODEFAULT; +} + +LRESULT PhpThemeWindowDrawListViewGroup( _In_ LPNMLVCUSTOMDRAW DrawInfo ) { From bd8df50e3d683e8e4d1a49b66306e58e3261e45c Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 26 Jul 2018 00:05:39 +1000 Subject: [PATCH 1216/2058] Update logging callback, Add log window theme support --- ProcessHacker/include/phplug.h | 1 + ProcessHacker/log.c | 5 ++--- ProcessHacker/logwnd.c | 27 +++++++++++-------------- plugins/ExtendedNotifications/filelog.c | 2 +- 4 files changed, 16 insertions(+), 19 deletions(-) diff --git a/ProcessHacker/include/phplug.h b/ProcessHacker/include/phplug.h index 3f75714b35f0..a353e7bb6e50 100644 --- a/ProcessHacker/include/phplug.h +++ b/ProcessHacker/include/phplug.h @@ -59,6 +59,7 @@ typedef enum _PH_GENERAL_CALLBACK GeneralCallbackNetworkProviderRemovedEvent, // [network provider thread] GeneralCallbackNetworkProviderUpdatedEvent, // [network provider thread] + GeneralCallbackLoggedEvent, GeneralCallbackTrayIconsInitializing, GeneralCallbackWindowNotifyEvent, GeneralCallbackMaximum diff --git a/ProcessHacker/log.c b/ProcessHacker/log.c index a57862b1c614..b5334c064109 100644 --- a/ProcessHacker/log.c +++ b/ProcessHacker/log.c @@ -21,11 +21,10 @@ */ #include - +#include #include PH_CIRCULAR_BUFFER_PVOID PhLogBuffer; -PHAPPAPI PH_CALLBACK_DECLARE(PhLoggedCallback); VOID PhLogInitialization( VOID @@ -155,7 +154,7 @@ VOID PhpLogEntry( if (oldEntry) PhpFreeLogEntry(oldEntry); - PhInvokeCallback(&PhLoggedCallback, Entry); + PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackLoggedEvent), Entry); } VOID PhClearLogEntries( diff --git a/ProcessHacker/logwnd.c b/ProcessHacker/logwnd.c index b570c7e23256..4618c35c7456 100644 --- a/ProcessHacker/logwnd.c +++ b/ProcessHacker/logwnd.c @@ -21,8 +21,9 @@ */ #include +#include +#include #include - #include #define WM_PH_LOG_UPDATED (WM_APP + 300) @@ -165,18 +166,12 @@ INT_PTR CALLBACK PhpLogDlgProc( PhLoadListViewColumnsFromSetting(L"LogListViewColumns", ListViewHandle); PhInitializeLayoutManager(&WindowLayoutManager, hwndDlg); - PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDC_LIST), NULL, - PH_ANCHOR_ALL); - PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDOK), NULL, - PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); - PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDC_COPY), NULL, - PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); - PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDC_SAVE), NULL, - PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); - PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDC_AUTOSCROLL), NULL, - PH_ANCHOR_BOTTOM | PH_ANCHOR_LEFT); - PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDC_CLEAR), NULL, - PH_ANCHOR_BOTTOM | PH_ANCHOR_LEFT); + PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDC_LIST), NULL, PH_ANCHOR_ALL); + PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDOK), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); + PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDC_COPY), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); + PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDC_SAVE), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); + PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDC_AUTOSCROLL), NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_LEFT); + PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDC_CLEAR), NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_LEFT); MinimumSize.left = 0; MinimumSize.top = 0; @@ -188,9 +183,11 @@ INT_PTR CALLBACK PhpLogDlgProc( Button_SetCheck(GetDlgItem(hwndDlg, IDC_AUTOSCROLL), BST_CHECKED); - PhRegisterCallback(&PhLoggedCallback, LoggedCallback, NULL, &LoggedRegistration); + PhRegisterCallback(PhGetGeneralCallback(GeneralCallbackLoggedEvent), LoggedCallback, NULL, &LoggedRegistration); PhpUpdateLogList(); ListView_EnsureVisible(ListViewHandle, ListViewCount - 1, FALSE); + + PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport); } break; case WM_DESTROY: @@ -200,7 +197,7 @@ INT_PTR CALLBACK PhpLogDlgProc( PhDeleteLayoutManager(&WindowLayoutManager); - PhUnregisterCallback(&PhLoggedCallback, &LoggedRegistration); + PhUnregisterCallback(PhGetGeneralCallback(GeneralCallbackLoggedEvent), &LoggedRegistration); PhUnregisterDialog(PhLogWindowHandle); PhLogWindowHandle = NULL; } diff --git a/plugins/ExtendedNotifications/filelog.c b/plugins/ExtendedNotifications/filelog.c index b6a8dda4826b..8b98c8672560 100644 --- a/plugins/ExtendedNotifications/filelog.c +++ b/plugins/ExtendedNotifications/filelog.c @@ -55,7 +55,7 @@ VOID FileLogInitialization( if (NT_SUCCESS(status)) { PhRegisterCallback( - &PhLoggedCallback, + PhGetGeneralCallback(GeneralCallbackLoggedEvent), LoggedCallback, NULL, &LoggedCallbackRegistration From 4f1388106a4f43777dc6dc3995540e0b65ce1898 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 26 Jul 2018 02:05:31 +1000 Subject: [PATCH 1217/2058] Add treenew custom theme support --- phlib/include/treenew.h | 6 +- phlib/include/treenewp.h | 3 +- phlib/treenew.c | 157 ++++++++++++++++++++++++++++++++------- 3 files changed, 137 insertions(+), 29 deletions(-) diff --git a/phlib/include/treenew.h b/phlib/include/treenew.h index 61d08081b1c2..ae1fb9e58a61 100644 --- a/phlib/include/treenew.h +++ b/phlib/include/treenew.h @@ -406,7 +406,8 @@ typedef struct _PH_TREENEW_SEARCH_EVENT #define TNM_SETEMPTYTEXT (WM_USER + 43) #define TNM_SETROWHEIGHT (WM_USER + 44) #define TNM_ISFLATNODEVALID (WM_USER + 45) -#define TNM_LAST (WM_USER + 45) +#define TNM_THEMESUPPORT (WM_USER + 46) +#define TNM_LAST (WM_USER + 47) #define TreeNew_SetCallback(hWnd, Callback, Context) \ SendMessage((hWnd), TNM_SETCALLBACK, (WPARAM)(Context), (LPARAM)(Callback)) @@ -537,6 +538,9 @@ typedef struct _PH_TREENEW_SEARCH_EVENT #define TreeNew_IsFlatNodeValid(hWnd) \ ((BOOLEAN)SendMessage((hWnd), TNM_ISFLATNODEVALID, 0, 0)) +#define TreeNew_ThemeSupport(hWnd, Enable) \ + SendMessage((hWnd), TNM_THEMESUPPORT, (WPARAM)(Enable), 0); + typedef struct _PH_TREENEW_VIEW_PARTS { RECT ClientRect; diff --git a/phlib/include/treenewp.h b/phlib/include/treenewp.h index e1d9eb397500..03d798c876d5 100644 --- a/phlib/include/treenewp.h +++ b/phlib/include/treenewp.h @@ -59,7 +59,8 @@ typedef struct _PH_TREENEW_CONTEXT ULONG CustomRowHeight : 1; ULONG CustomColors : 1; ULONG ContextMenuActive : 1; - ULONG Spare : 2; + ULONG ThemeSupport : 1; + ULONG Spare : 1; }; ULONG Flags; }; diff --git a/phlib/treenew.c b/phlib/treenew.c index 2744f71ea06a..b6a1b5abe2e4 100644 --- a/phlib/treenew.c +++ b/phlib/treenew.c @@ -1998,6 +1998,9 @@ ULONG_PTR PhTnpOnUserMessage( return TRUE; case TNM_ISFLATNODEVALID: return !Context->SuspendUpdateStructure; + case TNM_THEMESUPPORT: + Context->ThemeSupport = !!WParam; + return TRUE; } return 0; @@ -5071,44 +5074,124 @@ VOID PhTnpPaint( PhTnpPrepareRowForDraw(Context, hdc, node); - if (node->Selected && (Context->CustomColors || !Context->ThemeHasItemBackground)) + if (Context->ThemeSupport) { - // Non-themed background + HDC tempDc; + BITMAPINFOHEADER header; + HBITMAP bitmap; + HBITMAP oldBitmap; + PVOID bits; + RECT tempRect; + BLENDFUNCTION blendFunction; + + SetTextColor(hdc, RGB(0xff, 0xff, 0xff)); + SetDCBrushColor(hdc, RGB(30, 30, 30)); + FillRect(hdc, &rowRect, GetStockObject(DC_BRUSH)); - if (Context->HasFocus) + if (tempDc = CreateCompatibleDC(hdc)) { - if (Context->CustomColors) + memset(&header, 0, sizeof(BITMAPINFOHEADER)); + header.biSize = sizeof(BITMAPINFOHEADER); + header.biWidth = 1; + header.biHeight = 1; + header.biPlanes = 1; + header.biBitCount = 24; + bitmap = CreateDIBSection(tempDc, (BITMAPINFO *)&header, DIB_RGB_COLORS, &bits, NULL, 0); + + if (bitmap) { - SetTextColor(hdc, Context->CustomTextColor); - SetDCBrushColor(hdc, Context->CustomFocusColor); - FillRect(hdc, &rowRect, GetStockObject(DC_BRUSH)); - } - else - { - SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT)); - FillRect(hdc, &rowRect, GetSysColorBrush(COLOR_HIGHLIGHT)); + // Draw the outline of the selection rectangle. + //FrameRect(hdc, &rowRect, GetSysColorBrush(COLOR_HIGHLIGHT)); + + // Fill in the selection rectangle. + oldBitmap = SelectObject(tempDc, bitmap); + tempRect.left = 0; + tempRect.top = 0; + tempRect.right = 1; + tempRect.bottom = 1; + + SetTextColor(tempDc, node->s.DrawForeColor); + + if (node->s.DrawBackColor != 16777215) + { + SetDCBrushColor(tempDc, node->s.DrawBackColor); + FillRect(tempDc, &tempRect, GetStockObject(DC_BRUSH)); + } + else + { + SetDCBrushColor(tempDc, RGB(30, 30, 30)); + FillRect(tempDc, &tempRect, GetStockObject(DC_BRUSH)); + } + + blendFunction.BlendOp = AC_SRC_OVER; + blendFunction.BlendFlags = 0; + blendFunction.SourceConstantAlpha = 96; + blendFunction.AlphaFormat = 0; + + GdiAlphaBlend( + hdc, + rowRect.left, + rowRect.top, + rowRect.right - rowRect.left, + rowRect.bottom - rowRect.top, + tempDc, + 0, + 0, + 1, + 1, + blendFunction + ); + + //drewWithAlpha = TRUE; + + SelectObject(tempDc, oldBitmap); + DeleteObject(bitmap); } + + DeleteDC(tempDc); } - else + } + else + { + if (node->Selected && (Context->CustomColors || !Context->ThemeHasItemBackground)) { - if (Context->CustomColors) + // Non-themed background + + if (Context->HasFocus) { - SetTextColor(hdc, Context->CustomTextColor); - SetDCBrushColor(hdc, Context->CustomSelectedColor); - FillRect(hdc, &rowRect, GetStockObject(DC_BRUSH)); + if (Context->CustomColors) + { + SetTextColor(hdc, Context->CustomTextColor); + SetDCBrushColor(hdc, Context->CustomFocusColor); + FillRect(hdc, &rowRect, GetStockObject(DC_BRUSH)); + } + else + { + SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT)); + FillRect(hdc, &rowRect, GetSysColorBrush(COLOR_HIGHLIGHT)); + } } else { - SetTextColor(hdc, GetSysColor(COLOR_BTNTEXT)); - FillRect(hdc, &rowRect, GetSysColorBrush(COLOR_BTNFACE)); + if (Context->CustomColors) + { + SetTextColor(hdc, Context->CustomTextColor); + SetDCBrushColor(hdc, Context->CustomSelectedColor); + FillRect(hdc, &rowRect, GetStockObject(DC_BRUSH)); + } + else + { + SetTextColor(hdc, GetSysColor(COLOR_BTNTEXT)); + FillRect(hdc, &rowRect, GetSysColorBrush(COLOR_BTNFACE)); + } } } - } - else - { - SetTextColor(hdc, node->s.DrawForeColor); - SetDCBrushColor(hdc, node->s.DrawBackColor); - FillRect(hdc, &rowRect, GetStockObject(DC_BRUSH)); + else + { + SetTextColor(hdc, node->s.DrawForeColor); + SetDCBrushColor(hdc, node->s.DrawBackColor); + FillRect(hdc, &rowRect, GetStockObject(DC_BRUSH)); + } } if (!Context->CustomColors && Context->ThemeHasItemBackground) @@ -5208,7 +5291,17 @@ VOID PhTnpPaint( { // Fill the rest of the space on the bottom with the window color. rowRect.bottom = viewRect.bottom; - FillRect(hdc, &rowRect, GetSysColorBrush(COLOR_WINDOW)); + + if (Context->ThemeSupport) + { + SetTextColor(hdc, RGB(0xff, 0xff, 0xff)); + SetDCBrushColor(hdc, RGB(30, 30, 30)); + FillRect(hdc, &rowRect, GetStockObject(DC_BRUSH)); + } + else + { + FillRect(hdc, &rowRect, GetSysColorBrush(COLOR_WINDOW)); + } } if (normalTotalX < viewRect.right && viewRect.right > PaintRect->left && normalTotalX < PaintRect->right) @@ -5218,7 +5311,17 @@ VOID PhTnpPaint( rowRect.top = Context->HeaderHeight; rowRect.right = viewRect.right; rowRect.bottom = viewRect.bottom; - FillRect(hdc, &rowRect, GetSysColorBrush(COLOR_WINDOW)); + + if (Context->ThemeSupport) + { + SetTextColor(hdc, RGB(0xff, 0xff, 0xff)); + SetDCBrushColor(hdc, RGB(30, 30, 30)); + FillRect(hdc, &rowRect, GetStockObject(DC_BRUSH)); + } + else + { + FillRect(hdc, &rowRect, GetSysColorBrush(COLOR_WINDOW)); + } } if (Context->FlatList->Count == 0 && Context->EmptyText.Length != 0) From b2ebda50d1e500ea8ed351a916c8abf90c3ee9de Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 26 Jul 2018 02:06:44 +1000 Subject: [PATCH 1218/2058] Fix error checking --- ProcessHacker/hndlprv.c | 46 ++++++++++++++++++++--------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/ProcessHacker/hndlprv.c b/ProcessHacker/hndlprv.c index fd5a2a24aa2f..afb96c5fcdc8 100644 --- a/ProcessHacker/hndlprv.c +++ b/ProcessHacker/hndlprv.c @@ -303,30 +303,33 @@ NTSTATUS PhEnumHandlesGeneric( // * On Windows XP and later, NtQuerySystemInformation with SystemExtendedHandleInformation. // * Otherwise, NtQuerySystemInformation with SystemHandleInformation can be used. - if (WindowsVersion >= WINDOWS_8 && !!PhGetIntegerSetting(L"EnableHandleSnapshot")) + if (KphIsConnected()) { - PPROCESS_HANDLE_SNAPSHOT_INFORMATION handles; + PKPH_PROCESS_HANDLE_INFORMATION handles; PSYSTEM_HANDLE_INFORMATION_EX convertedHandles; ULONG i; - if (!NT_SUCCESS(status = PhEnumHandlesEx2(ProcessHandle, &handles))) + // Enumerate handles using KProcessHacker. Unlike with NtQuerySystemInformation, + // this only enumerates handles for a single process and saves a lot of processing. + + if (!NT_SUCCESS(status = KphEnumerateProcessHandles2(ProcessHandle, &handles))) goto FAILED; convertedHandles = PhAllocate( FIELD_OFFSET(SYSTEM_HANDLE_INFORMATION_EX, Handles) + - sizeof(SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX) * handles->NumberOfHandles + sizeof(SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX) * handles->HandleCount ); - convertedHandles->NumberOfHandles = handles->NumberOfHandles; + convertedHandles->NumberOfHandles = handles->HandleCount; - for (i = 0; i < handles->NumberOfHandles; i++) + for (i = 0; i < handles->HandleCount; i++) { - convertedHandles->Handles[i].Object = 0; + convertedHandles->Handles[i].Object = handles->Handles[i].Object; convertedHandles->Handles[i].UniqueProcessId = (ULONG_PTR)ProcessId; - convertedHandles->Handles[i].HandleValue = (ULONG_PTR)handles->Handles[i].HandleValue; - convertedHandles->Handles[i].GrantedAccess = handles->Handles[i].GrantedAccess; + convertedHandles->Handles[i].HandleValue = (ULONG_PTR)handles->Handles[i].Handle; + convertedHandles->Handles[i].GrantedAccess = (ULONG)handles->Handles[i].GrantedAccess; convertedHandles->Handles[i].CreatorBackTraceIndex = 0; - convertedHandles->Handles[i].ObjectTypeIndex = (USHORT)handles->Handles[i].ObjectTypeIndex; + convertedHandles->Handles[i].ObjectTypeIndex = handles->Handles[i].ObjectTypeIndex; convertedHandles->Handles[i].HandleAttributes = handles->Handles[i].HandleAttributes; } @@ -335,33 +338,30 @@ NTSTATUS PhEnumHandlesGeneric( *Handles = convertedHandles; *FilterNeeded = FALSE; } - else if (KphIsConnected()) + else if (WindowsVersion >= WINDOWS_8 && PhGetIntegerSetting(L"EnableHandleSnapshot")) { - PKPH_PROCESS_HANDLE_INFORMATION handles; + PPROCESS_HANDLE_SNAPSHOT_INFORMATION handles; PSYSTEM_HANDLE_INFORMATION_EX convertedHandles; ULONG i; - // Enumerate handles using KProcessHacker. Unlike with NtQuerySystemInformation, - // this only enumerates handles for a single process and saves a lot of processing. - - if (!NT_SUCCESS(status = KphEnumerateProcessHandles2(ProcessHandle, &handles))) + if (!NT_SUCCESS(status = PhEnumHandlesEx2(ProcessHandle, &handles))) goto FAILED; convertedHandles = PhAllocate( FIELD_OFFSET(SYSTEM_HANDLE_INFORMATION_EX, Handles) + - sizeof(SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX) * handles->HandleCount + sizeof(SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX) * handles->NumberOfHandles ); - convertedHandles->NumberOfHandles = handles->HandleCount; + convertedHandles->NumberOfHandles = handles->NumberOfHandles; - for (i = 0; i < handles->HandleCount; i++) + for (i = 0; i < handles->NumberOfHandles; i++) { - convertedHandles->Handles[i].Object = handles->Handles[i].Object; + convertedHandles->Handles[i].Object = 0; convertedHandles->Handles[i].UniqueProcessId = (ULONG_PTR)ProcessId; - convertedHandles->Handles[i].HandleValue = (ULONG_PTR)handles->Handles[i].Handle; - convertedHandles->Handles[i].GrantedAccess = (ULONG)handles->Handles[i].GrantedAccess; + convertedHandles->Handles[i].HandleValue = (ULONG_PTR)handles->Handles[i].HandleValue; + convertedHandles->Handles[i].GrantedAccess = handles->Handles[i].GrantedAccess; convertedHandles->Handles[i].CreatorBackTraceIndex = 0; - convertedHandles->Handles[i].ObjectTypeIndex = handles->Handles[i].ObjectTypeIndex; + convertedHandles->Handles[i].ObjectTypeIndex = (USHORT)handles->Handles[i].ObjectTypeIndex; convertedHandles->Handles[i].HandleAttributes = handles->Handles[i].HandleAttributes; } From 838e4cda689beb54196968a1b89a0eb20d13b98e Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 26 Jul 2018 02:07:58 +1000 Subject: [PATCH 1219/2058] Add main window theme support --- ProcessHacker/mainwnd.c | 2 + phlib/theme.c | 2533 ++++++++++++++++++++------------------- 2 files changed, 1305 insertions(+), 1230 deletions(-) diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index 52ab4918d082..f81eb2f6139e 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -201,6 +201,8 @@ BOOLEAN PhMainWndInitialization( PhMwpLoadSettings(); PhLogInitialization(); + PhInitializeWindowTheme(PhMainWndHandle, PhEnableThemeSupport); // HACK + // Initialize the main providers. PhMwpInitializeProviders(); diff --git a/phlib/theme.c b/phlib/theme.c index f336d242c126..706ef2095a6c 100644 --- a/phlib/theme.c +++ b/phlib/theme.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -42,22 +43,51 @@ typedef struct _PHP_THEME_WINDOW_HEADER_CONTEXT BOOLEAN MouseActive; } PHP_THEME_WINDOW_HEADER_CONTEXT, *PPHP_THEME_WINDOW_HEADER_CONTEXT; +typedef struct _PHP_THEME_WINDOW_STATUSBAR_CONTEXT +{ + WNDPROC DefaultWindowProc; + BOOLEAN MouseActive; + HTHEME StatusThemeData; +} PHP_THEME_WINDOW_STATUSBAR_CONTEXT, *PPHP_THEME_WINDOW_STATUSBAR_CONTEXT; + BOOLEAN CALLBACK PhpThemeWindowEnumChildWindows( _In_ HWND WindowHandle, _In_opt_ PVOID Context ); - BOOLEAN CALLBACK PhpReInitializeThemeWindowEnumChildWindows( _In_ HWND WindowHandle, _In_opt_ PVOID Context ); -LRESULT PhpThemeWindowDrawButton( - _In_ LPNMCUSTOMDRAW DrawInfo +LRESULT CALLBACK PhpThemeWindowSubclassProc( + _In_ HWND hWnd, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam ); - -LRESULT PhpThemeWindowDrawListViewGroup( - _In_ LPNMLVCUSTOMDRAW DrawInfo +LRESULT CALLBACK PhpThemeWindowGroupBoxSubclassProc( + _In_ HWND hWnd, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); +LRESULT CALLBACK PhpThemeWindowTabControlWndSubclassProc( + _In_ HWND WindowHandle, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); +LRESULT CALLBACK PhpThemeWindowHeaderSubclassProc( + _In_ HWND WindowHandle, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); +LRESULT CALLBACK PhpThemeWindowStatusbarWndSubclassProc( + _In_ HWND WindowHandle, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam ); COLORREF PhpThemeWindowForegroundColor = RGB(28, 28, 28); @@ -65,688 +95,736 @@ COLORREF PhpThemeWindowBackgroundColor = RGB(64, 64, 64); COLORREF PhpThemeWindowTextColor = RGB(0xff, 0xff, 0xff); HFONT PhpTabControlFontHandle = NULL; HFONT PhpToolBarFontHandle = NULL; +HFONT PhpHeaderFontHandle = NULL; HFONT PhpListViewFontHandle = NULL; HFONT PhpGroupboxFontHandle = NULL; +HFONT PhpStatusBarFontHandle = NULL; -LRESULT CALLBACK PhpThemeWindowSubclassProc( - _In_ HWND hWnd, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam +VOID PhInitializeWindowTheme( + _In_ HWND WindowHandle, + _In_ BOOLEAN EnableThemeSupport ) { - WNDPROC oldWndProc; - - if (!(oldWndProc = PhGetWindowContext(hWnd, SHRT_MAX))) - return FALSE; - - switch (uMsg) + if (EnableThemeSupport) { - case WM_DESTROY: - { - PhRemoveWindowContext(hWnd, SHRT_MAX); - SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)oldWndProc); - } - break; - case WM_NOTIFY: - { - LPNMHDR data = (LPNMHDR)lParam; - - switch (data->code) - { - case NM_CUSTOMDRAW: - { - LPNMCUSTOMDRAW customDraw = (LPNMCUSTOMDRAW)lParam; - WCHAR className[MAX_PATH]; - - if (!GetClassName(customDraw->hdr.hwndFrom, className, RTL_NUMBER_OF(className))) - className[0] = 0; - - if (PhEqualStringZ(className, L"Button", FALSE)) - { - return PhpThemeWindowDrawButton(customDraw); - } - else if (PhEqualStringZ(className, L"ReBarWindow32", FALSE)) - { - NOTHING; - } - else if (PhEqualStringZ(className, L"ToolbarWindow32", FALSE)) - { - NOTHING; - } - else if (PhEqualStringZ(className, L"SysTabControl32", FALSE)) - { - NOTHING; - } - else if (PhEqualStringZ(className, L"SysListView32", FALSE)) - { - LPNMLVCUSTOMDRAW listViewCustomDraw = (LPNMLVCUSTOMDRAW)customDraw; + WNDPROC defaultWindowProc; - if (listViewCustomDraw->dwItemType == LVCDI_GROUP) - { - return PhpThemeWindowDrawListViewGroup(listViewCustomDraw); - } - } - } - } - } - break; - case WM_CTLCOLOREDIT: - { - SetBkMode((HDC)wParam, TRANSPARENT); + defaultWindowProc = (WNDPROC)GetWindowLongPtr(WindowHandle, GWLP_WNDPROC); + PhSetWindowContext(WindowHandle, SHRT_MAX, defaultWindowProc); + SetWindowLongPtr(WindowHandle, GWLP_WNDPROC, (LONG_PTR)PhpThemeWindowSubclassProc); - switch (PhGetIntegerSetting(L"GraphColorMode")) - { - case 0: // New colors - SetTextColor((HDC)wParam, RGB(0x0, 0x0, 0x0)); - SetDCBrushColor((HDC)wParam, PhpThemeWindowTextColor); - return (INT_PTR)GetStockObject(DC_BRUSH); - case 1: // Old colors - SetTextColor((HDC)wParam, PhpThemeWindowTextColor); - SetDCBrushColor((HDC)wParam, RGB(60, 60, 60)); - return (INT_PTR)GetStockObject(DC_BRUSH); - } - } - break; - case WM_CTLCOLORBTN: - case WM_CTLCOLORDLG: - case WM_CTLCOLORSTATIC: - { - SetBkMode((HDC)wParam, TRANSPARENT); + PhEnumChildWindows( + WindowHandle, + 0x1000, + PhpThemeWindowEnumChildWindows, + 0 + ); - switch (PhGetIntegerSetting(L"GraphColorMode")) - { - case 0: // New colors - SetTextColor((HDC)wParam, RGB(0x0, 0x0, 0x0)); - SetDCBrushColor((HDC)wParam, PhpThemeWindowTextColor); - return (INT_PTR)GetStockObject(DC_BRUSH); - case 1: // Old colors - SetTextColor((HDC)wParam, PhpThemeWindowTextColor); - SetDCBrushColor((HDC)wParam, RGB(30, 30, 30)); - return (INT_PTR)GetStockObject(DC_BRUSH); - } - } - break; + InvalidateRect(WindowHandle, NULL, FALSE); // HACK + } + else + { + EnableThemeDialogTexture(WindowHandle, ETDT_ENABLETAB); } - - return CallWindowProc(oldWndProc, hWnd, uMsg, wParam, lParam); } -LRESULT CALLBACK PhpThemeWindowGroupBoxSubclassProc( - _In_ HWND hWnd, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam +VOID PhReInitializeWindowTheme( + _In_ HWND WindowHandle ) { - WNDPROC oldWndProc; + HWND currentWindow = NULL; - if (!(oldWndProc = PhGetWindowContext(hWnd, SHRT_MAX))) - return 0; + PhEnumChildWindows( + WindowHandle, + 0x1000, + PhpReInitializeThemeWindowEnumChildWindows, + 0 + ); - switch (uMsg) + do { - case WM_DESTROY: + if (currentWindow = FindWindowEx(NULL, currentWindow, NULL, NULL)) { - PhRemoveWindowContext(hWnd, SHRT_MAX); - SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)oldWndProc); + ULONG processID = 0; + + GetWindowThreadProcessId(currentWindow, &processID); + + if (UlongToHandle(processID) == NtCurrentProcessId()) + { + if (currentWindow != WindowHandle) + { + InvalidateRect(currentWindow, NULL, TRUE); + } + } } - break; - case WM_ERASEBKGND: - return 1; - case WM_PAINT: - { - RECT clientRect; - HDC hdc; - PAINTSTRUCT ps; - PPH_STRING windowText; - SIZE nameSize; - RECT textRect; + } while (currentWindow); - if (!(hdc = BeginPaint(hWnd, &ps))) - break; + InvalidateRect(WindowHandle, NULL, FALSE); +} - GetClientRect(hWnd, &clientRect); +VOID PhInitializeThemeWindowHeader( + _In_ HWND HeaderWindow + ) +{ + PPHP_THEME_WINDOW_HEADER_CONTEXT headerControlContext; - SetBkMode(hdc, TRANSPARENT); + headerControlContext = PhAllocateZero(sizeof(PHP_THEME_WINDOW_HEADER_CONTEXT)); + headerControlContext->DefaultWindowProc = (WNDPROC)GetWindowLongPtr(HeaderWindow, GWLP_WNDPROC); - switch (PhGetIntegerSetting(L"GraphColorMode")) - { - case 0: // New colors - SetTextColor(hdc, RGB(0x0, 0x0, 0x0)); - SetDCBrushColor(hdc, RGB(0xff, 0xff, 0xff)); - //FillRect(hdc, &windowRect, GetStockObject(DC_BRUSH)); - break; - case 1: // Old colors - SetTextColor(hdc, RGB(0xff, 0xff, 0xff)); - SetDCBrushColor(hdc, RGB(0, 0, 0)); // RGB(28, 28, 28)); // RGB(65, 65, 65)); - //FillRect(hdc, &windowRect, GetStockObject(DC_BRUSH)); - break; - } + PhSetWindowContext(HeaderWindow, SHRT_MAX, headerControlContext); + SetWindowLongPtr(HeaderWindow, GWLP_WNDPROC, (LONG_PTR)PhpThemeWindowHeaderSubclassProc); - if (!PhpGroupboxFontHandle) // HACK - { - NONCLIENTMETRICS metrics = { sizeof(NONCLIENTMETRICS) }; + InvalidateRect(HeaderWindow, NULL, FALSE); +} - if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, &metrics, 0)) - { - metrics.lfMessageFont.lfHeight = -12; - metrics.lfMessageFont.lfWeight = FW_BOLD; +VOID PhInitializeThemeWindowTabControl( + _In_ HWND TabControlWindow + ) +{ + PPHP_THEME_WINDOW_TAB_CONTEXT tabControlContext; - PhpGroupboxFontHandle = CreateFontIndirect(&metrics.lfMessageFont); - } - } + tabControlContext = PhAllocateZero(sizeof(PHP_THEME_WINDOW_TAB_CONTEXT)); + tabControlContext->DefaultWindowProc = (WNDPROC)GetWindowLongPtr(TabControlWindow, GWLP_WNDPROC); - SelectObject(hdc, PhpGroupboxFontHandle); - SetTextColor(hdc, RGB(255, 69, 0)); - SetDCBrushColor(hdc, RGB(65, 65, 65)); - //clientRect.top += 6; - FrameRect(hdc, &clientRect, GetStockObject(DC_BRUSH)); - //clientRect.top -= 6; + PhSetWindowContext(TabControlWindow, SHRT_MAX, tabControlContext); + SetWindowLongPtr(TabControlWindow, GWLP_WNDPROC, (LONG_PTR)PhpThemeWindowTabControlWndSubclassProc); - windowText = PhGetWindowText(hWnd); - GetTextExtentPoint32( - hdc, - windowText->Buffer, - (ULONG)windowText->Length / sizeof(WCHAR), - &nameSize - ); + PhSetWindowStyle(TabControlWindow, TCS_OWNERDRAWFIXED, TCS_OWNERDRAWFIXED); - textRect.left = 0; - textRect.top = 0; - textRect.right = clientRect.right; - textRect.bottom = nameSize.cy; - FillRect(hdc, &textRect, GetStockObject(DC_BRUSH)); - - textRect.left += 10; - DrawText( - hdc, - windowText->Buffer, - (ULONG)windowText->Length / sizeof(WCHAR), - &textRect, - DT_LEFT | DT_END_ELLIPSIS | DT_SINGLELINE - ); - textRect.left -= 10; - - PhDereferenceObject(windowText); - - EndPaint(hWnd, &ps); - } - return FALSE; + if (!PhpTabControlFontHandle) + { + PhpTabControlFontHandle = CreateFont( + -(LONG)PhMultiplyDivide(15, PhGlobalDpi, 96), + 0, + 0, + 0, + FW_SEMIBOLD, + FALSE, + FALSE, + FALSE, + ANSI_CHARSET, + OUT_DEFAULT_PRECIS, + CLIP_DEFAULT_PRECIS, + DEFAULT_QUALITY, + DEFAULT_PITCH, + L"Tahoma" + ); } - return CallWindowProc(oldWndProc, hWnd, uMsg, wParam, lParam); + SendMessage(TabControlWindow, WM_SETFONT, (WPARAM)PhpTabControlFontHandle, FALSE); + + InvalidateRect(TabControlWindow, NULL, FALSE); } -LRESULT CALLBACK PhpThemeWindowTabControlWndSubclassProc( - _In_ HWND WindowHandle, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam +VOID PhInitializeWindowThemeStatusBar( + _In_ HWND StatusBarHandle ) { - PPHP_THEME_WINDOW_TAB_CONTEXT context; - WNDPROC oldWndProc; + PPHP_THEME_WINDOW_STATUSBAR_CONTEXT statusbarContext; - if (!(context = PhGetWindowContext(WindowHandle, SHRT_MAX))) - return 0; + statusbarContext = PhAllocateZero(sizeof(PHP_THEME_WINDOW_STATUSBAR_CONTEXT)); + statusbarContext->DefaultWindowProc = (WNDPROC)GetWindowLongPtr(StatusBarHandle, GWLP_WNDPROC); + statusbarContext->StatusThemeData = OpenThemeData(StatusBarHandle, VSCLASS_STATUS); - oldWndProc = context->DefaultWindowProc; + PhSetWindowContext(StatusBarHandle, SHRT_MAX, statusbarContext); + SetWindowLongPtr(StatusBarHandle, GWLP_WNDPROC, (LONG_PTR)PhpThemeWindowStatusbarWndSubclassProc); - switch (uMsg) - { - case WM_DESTROY: - { - PhRemoveWindowContext(WindowHandle, SHRT_MAX); - SetWindowLongPtr(WindowHandle, GWLP_WNDPROC, (LONG_PTR)oldWndProc); + InvalidateRect(StatusBarHandle, NULL, FALSE); +} - PhFree(context); - } - break; - case WM_ERASEBKGND: - return 1; - case WM_MOUSEMOVE: - { - POINT pt; - INT count; - INT i; +VOID PhInitializeThemeWindowGroupBox( + _In_ HWND GroupBoxHandle + ) +{ + WNDPROC groupboxWindowProc; - GetCursorPos(&pt); - MapWindowPoints(NULL, WindowHandle, &pt, 1); + groupboxWindowProc = (WNDPROC)GetWindowLongPtr(GroupBoxHandle, GWLP_WNDPROC); + PhSetWindowContext(GroupBoxHandle, SHRT_MAX, groupboxWindowProc); + SetWindowLongPtr(GroupBoxHandle, GWLP_WNDPROC, (LONG_PTR)PhpThemeWindowGroupBoxSubclassProc); - count = TabCtrl_GetItemCount(WindowHandle); + InvalidateRect(GroupBoxHandle, NULL, FALSE); +} - for (i = 0; i < count; i++) - { - RECT rect = { 0, 0, 0, 0 }; - TCITEM entry = - { - TCIF_STATE, - 0, - TCIS_HIGHLIGHTED - }; +BOOLEAN CALLBACK PhpThemeWindowEnumChildWindows( + _In_ HWND WindowHandle, + _In_opt_ PVOID Context + ) +{ + WCHAR windowClassName[MAX_PATH]; - TabCtrl_GetItemRect(WindowHandle, i, &rect); - entry.dwState = PtInRect(&rect, pt) ? TCIS_HIGHLIGHTED : 0; - TabCtrl_SetItem(WindowHandle, i, &entry); - } + PhEnumChildWindows( + WindowHandle, + 0x1000, + PhpThemeWindowEnumChildWindows, + 0 + ); - if (!context->MouseActive) - { - TRACKMOUSEEVENT trackEvent = - { - sizeof(TRACKMOUSEEVENT), - TME_LEAVE, - WindowHandle, - 0 - }; + if (PhGetWindowContext(WindowHandle, SHRT_MAX)) // HACK + return TRUE; - TrackMouseEvent(&trackEvent); - context->MouseActive = TRUE; - } + if (!GetClassName(WindowHandle, windowClassName, RTL_NUMBER_OF(windowClassName))) + windowClassName[0] = 0; - InvalidateRect(WindowHandle, NULL, FALSE); + if (PhEqualStringZ(windowClassName, L"#32770", FALSE)) + { + PhInitializeWindowTheme(WindowHandle, TRUE); + } + else if (PhEqualStringZ(windowClassName, L"Button", FALSE)) + { + ULONG buttonWindowStyle = (ULONG)GetWindowLongPtr(WindowHandle, GWL_STYLE); + + if ((buttonWindowStyle & BS_GROUPBOX) == BS_GROUPBOX) + { + PhInitializeThemeWindowGroupBox(WindowHandle); } - break; - case WM_MOUSELEAVE: + } + else if (PhEqualStringZ(windowClassName, L"Edit", FALSE)) + { + switch (PhGetIntegerSetting(L"GraphColorMode")) { - INT count; - INT i; + case 0: // New colors + //PhSetWindowStyle(WindowHandle, WS_BORDER, WS_BORDER); + //PhSetWindowExStyle(WindowHandle, WS_EX_CLIENTEDGE, WS_EX_CLIENTEDGE); + break; + case 1: // Old colors + //PhSetWindowStyle(WindowHandle, WS_BORDER, 0); + //PhSetWindowExStyle(WindowHandle, WS_EX_CLIENTEDGE, 0); + break; + } - count = TabCtrl_GetItemCount(WindowHandle); + //InvalidateRect(WindowHandle, NULL, FALSE); + } + else if (PhEqualStringZ(windowClassName, L"SysTabControl32", FALSE)) + { + PhInitializeThemeWindowTabControl(WindowHandle); + } + else if (PhEqualStringZ(windowClassName, L"msctls_statusbar32", FALSE)) + { + PhInitializeWindowThemeStatusBar(WindowHandle); + } + else if (PhEqualStringZ(windowClassName, L"SysHeader32", FALSE)) + { + PhInitializeThemeWindowHeader(WindowHandle); + } + else if (PhEqualStringZ(windowClassName, L"SysListView32", FALSE)) + { + PhSetWindowStyle(WindowHandle, WS_BORDER, 0); + PhSetWindowExStyle(WindowHandle, WS_EX_CLIENTEDGE, 0); - for (i = 0; i < count; i++) - { - TCITEM entry = - { - TCIF_STATE, - 0, - TCIS_HIGHLIGHTED - }; + switch (PhGetIntegerSetting(L"GraphColorMode")) + { + case 0: // New colors + break; + case 1: // Old colors + ListView_SetBkColor(WindowHandle, RGB(30, 30, 30)); + ListView_SetTextBkColor(WindowHandle, RGB(30, 30, 30)); + ListView_SetTextColor(WindowHandle, RGB(0xff, 0xff, 0xff)); + break; + } - TabCtrl_SetItem(WindowHandle, i, &entry); - } + InvalidateRect(WindowHandle, NULL, FALSE); + } + else if (PhEqualStringZ(windowClassName, L"SysTreeView32", FALSE)) + { + //PhSetWindowStyle(WindowHandle, WS_BORDER, 0); + //PhSetWindowExStyle(WindowHandle, WS_EX_CLIENTEDGE, 0); - InvalidateRect(WindowHandle, NULL, FALSE); - context->MouseActive = FALSE; + switch (PhGetIntegerSetting(L"GraphColorMode")) + { + case 0: // New colors + break; + case 1: // Old colors + TreeView_SetBkColor(WindowHandle, RGB(30, 30, 30)); + //TreeView_SetTextBkColor(WindowHandle, RGB(30, 30, 30)); + TreeView_SetTextColor(WindowHandle, RGB(0xff, 0xff, 0xff)); + break; } - break; - case WM_PAINT: + + InvalidateRect(WindowHandle, NULL, FALSE); + } + else if (PhEqualStringZ(windowClassName, L"PhTreeNew", FALSE)) + { + switch (PhGetIntegerSetting(L"GraphColorMode")) { - RECT clientRect, itemRect; - TCITEMW tcItem; - PAINTSTRUCT ps; - WCHAR szText[MAX_PATH]; + case 0: // New colors + PhSetWindowStyle(WindowHandle, WS_BORDER, WS_BORDER); + PhSetWindowExStyle(WindowHandle, WS_EX_CLIENTEDGE, WS_EX_CLIENTEDGE); + break; + case 1: // Old colors + PhSetWindowStyle(WindowHandle, WS_BORDER, 0); + PhSetWindowExStyle(WindowHandle, WS_EX_CLIENTEDGE, 0); + break; + } - BeginPaint(WindowHandle, &ps); + TreeNew_ThemeSupport(WindowHandle, TRUE); + } + else if (PhEqualStringZ(windowClassName, L"ScrollBar", FALSE)) + { + NOTHING; + } - GetClientRect(WindowHandle, &clientRect); + return TRUE; +} - ZeroMemory(&tcItem, sizeof(TCITEMW)); - tcItem.mask = TCIF_TEXT | TCIF_IMAGE | TCIF_STATE; - tcItem.dwStateMask = TCIS_BUTTONPRESSED | TCIS_HIGHLIGHTED; - tcItem.pszText = szText; - tcItem.cchTextMax = MAX_PATH; +BOOLEAN CALLBACK PhpReInitializeThemeWindowEnumChildWindows( + _In_ HWND WindowHandle, + _In_opt_ PVOID Context + ) +{ + ULONG processID = 0; - RECT rcSpin = clientRect; - HWND hWndSpin = GetDlgItem(WindowHandle, 1); - if (hWndSpin) - { - GetWindowRect(hWndSpin, &rcSpin); - MapWindowPoints(NULL, WindowHandle, (LPPOINT)&rcSpin, 2); - rcSpin.right = rcSpin.left; - rcSpin.left = rcSpin.top = 0; - rcSpin.bottom = clientRect.bottom; - } + PhEnumChildWindows( + WindowHandle, + 0x1000, + PhpReInitializeThemeWindowEnumChildWindows, + 0 + ); - HDC hdc = CreateCompatibleDC(ps.hdc); - HBITMAP hbm = CreateCompatibleBitmap(ps.hdc, clientRect.right, clientRect.bottom); - SelectObject(hdc, hbm); + GetWindowThreadProcessId(WindowHandle, &processID); - SetBkMode(hdc, TRANSPARENT); + if (UlongToHandle(processID) == NtCurrentProcessId()) + { + InvalidateRect(WindowHandle, NULL, FALSE); + } - static HFONT fontHandle = NULL; - if (!fontHandle) - { - NONCLIENTMETRICS metrics = { sizeof(NONCLIENTMETRICS) }; - if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, &metrics, 0)) - { - fontHandle = CreateFontIndirect(&metrics.lfMessageFont); - } - } + return TRUE; +} - SelectObject(hdc, fontHandle); +LRESULT CALLBACK PhpThemeWindowDrawButton( + _In_ LPNMCUSTOMDRAW DrawInfo + ) +{ + BOOLEAN isGrayed = (DrawInfo->uItemState & CDIS_GRAYED) == CDIS_GRAYED; + BOOLEAN isChecked = (DrawInfo->uItemState & CDIS_CHECKED) == CDIS_CHECKED; + BOOLEAN isDisabled = (DrawInfo->uItemState & CDIS_DISABLED) == CDIS_DISABLED; + BOOLEAN isSelected = (DrawInfo->uItemState & CDIS_SELECTED) == CDIS_SELECTED; + BOOLEAN isHighlighted = (DrawInfo->uItemState & CDIS_HOT) == CDIS_HOT; + BOOLEAN isFocused = (DrawInfo->uItemState & CDIS_FOCUS) == CDIS_FOCUS; - switch (PhGetIntegerSetting(L"GraphColorMode")) - { - case 0: // New colors - //SetTextColor(hdc, RGB(0x0, 0xff, 0x0)); - SetDCBrushColor(hdc, PhpThemeWindowTextColor); - FillRect(hdc, &clientRect, GetStockObject(DC_BRUSH)); - break; - case 1: // Old colors - //SetTextColor(hdc, PhpThemeWindowTextColor); - SetDCBrushColor(hdc, RGB(65, 65, 65)); //WindowForegroundColor); // RGB(65, 65, 65)); - FillRect(hdc, &clientRect, GetStockObject(DC_BRUSH)); - break; - } - + switch (DrawInfo->dwDrawStage) + { + case CDDS_PREPAINT: + { + PPH_STRING buttonText; + HFONT oldFont; - HDC hdcTab = CreateCompatibleDC(hdc); + buttonText = PhGetWindowText(DrawInfo->hdr.hwndFrom); - INT count = TabCtrl_GetItemCount(WindowHandle); - for (INT i = 0; i < count; i++) + if (isSelected) { - TabCtrl_GetItemRect(WindowHandle, i, &itemRect); - TabCtrl_GetItem(WindowHandle, i, &tcItem); + switch (PhGetIntegerSetting(L"GraphColorMode")) + { + case 0: // New colors + //SetTextColor(DrawInfo->hdc, RGB(0, 0, 0xff)); + SetDCBrushColor(DrawInfo->hdc, GetSysColor(COLOR_HIGHLIGHT)); + break; + case 1: // Old colors + SetTextColor(DrawInfo->hdc, GetSysColor(COLOR_HIGHLIGHTTEXT)); + SetDCBrushColor(DrawInfo->hdc, RGB(78, 78, 78)); + break; + } - POINT pt; - GetCursorPos(&pt); - MapWindowPoints(NULL, WindowHandle, &pt, 1); + FillRect(DrawInfo->hdc, &DrawInfo->rc, GetStockObject(DC_BRUSH)); + } + else if (isHighlighted) + { + switch (PhGetIntegerSetting(L"GraphColorMode")) + { + case 0: // New colors + //SetTextColor(DrawInfo->hdc, RGB(0, 0, 0xff)); + SetDCBrushColor(DrawInfo->hdc, GetSysColor(COLOR_HIGHLIGHT)); + break; + case 1: // Old colors + SetTextColor(DrawInfo->hdc, GetSysColor(COLOR_HIGHLIGHTTEXT)); + SetDCBrushColor(DrawInfo->hdc, RGB(65, 65, 65)); + break; + } - if (PtInRect(&itemRect, pt)) + FillRect(DrawInfo->hdc, &DrawInfo->rc, GetStockObject(DC_BRUSH)); + } + else + { + switch (PhGetIntegerSetting(L"GraphColorMode")) { - OffsetRect(&itemRect, 2, 2); + case 0: // New colors + //SetTextColor(DrawInfo->hdc, PhpThemeWindowTextColor); + SetDCBrushColor(DrawInfo->hdc, PhpThemeWindowTextColor); + break; + case 1: // Old colors + SetTextColor(DrawInfo->hdc, PhpThemeWindowTextColor); + SetDCBrushColor(DrawInfo->hdc, RGB(42, 42, 42)); // WindowForegroundColor + break; + } - switch (PhGetIntegerSetting(L"GraphColorMode")) - { - case 0: // New colors - { - if (TabCtrl_GetCurSel(WindowHandle) == i) - { - SetDCBrushColor(hdc, RGB(128, 128, 128)); - FillRect(hdc, &itemRect, GetStockObject(DC_BRUSH)); - } - else - { - //SetTextColor(hdc, PhpThemeWindowTextColor); - SetDCBrushColor(hdc, PhpThemeWindowTextColor); - FillRect(hdc, &itemRect, GetStockObject(DC_BRUSH)); - } - } - break; - case 1: // Old colors - SetTextColor(hdc, PhpThemeWindowTextColor); - SetDCBrushColor(hdc, RGB(128, 128, 128)); - FillRect(hdc, &itemRect, GetStockObject(DC_BRUSH)); - break; - } + FillRect(DrawInfo->hdc, &DrawInfo->rc, GetStockObject(DC_BRUSH)); + } - //FrameRect(hdc, &itemRect, GetSysColorBrush(COLOR_HIGHLIGHT)); + if ((GetWindowLongPtr(DrawInfo->hdr.hwndFrom, GWL_STYLE) & BS_CHECKBOX) != 0) + { + HFONT newFont = PhDuplicateFontWithNewHeight(PhApplicationFont, 22); + oldFont = SelectFont(DrawInfo->hdc, newFont); + + if (Button_GetCheck(DrawInfo->hdr.hwndFrom) == BST_CHECKED) + { + DrawText( + DrawInfo->hdc, + L"\u2611", + -1, + &DrawInfo->rc, + DT_LEFT | DT_SINGLELINE | DT_VCENTER + ); } else { - OffsetRect(&itemRect, 2, 2); - - switch (PhGetIntegerSetting(L"GraphColorMode")) - { - case 0: // New colors - { - if (TabCtrl_GetCurSel(WindowHandle) == i) - { - SetDCBrushColor(hdc, RGB(128, 128, 128)); - FillRect(hdc, &itemRect, GetStockObject(DC_BRUSH)); - } - else - { - //SetTextColor(hdc, PhpThemeWindowTextColor); - SetDCBrushColor(hdc, PhpThemeWindowTextColor); - FillRect(hdc, &itemRect, GetStockObject(DC_BRUSH)); - } - } - break; - case 1: // Old colors - { - if (TabCtrl_GetCurSel(WindowHandle) == i) - { - SetTextColor(hdc, PhpThemeWindowTextColor); - SetDCBrushColor(hdc, PhpThemeWindowForegroundColor); - FillRect(hdc, &itemRect, GetStockObject(DC_BRUSH)); - } - else - { - SetTextColor(hdc, PhpThemeWindowTextColor); - SetDCBrushColor(hdc, PhpThemeWindowBackgroundColor); - FillRect(hdc, &itemRect, GetStockObject(DC_BRUSH)); - } - } - break; - } + DrawText( + DrawInfo->hdc, + L"\u2610", + -1, + &DrawInfo->rc, + DT_LEFT | DT_SINGLELINE | DT_VCENTER + ); } + SelectFont(DrawInfo->hdc, oldFont); + DeleteFont(newFont); + + DrawInfo->rc.left += 10; DrawText( - hdc, - tcItem.pszText, - -1, - &itemRect, - DT_CENTER | DT_VCENTER | DT_SINGLELINE | DT_HIDEPREFIX //| DT_WORD_ELLIPSIS + DrawInfo->hdc, + buttonText->Buffer, + (UINT)buttonText->Length / sizeof(WCHAR), + &DrawInfo->rc, + DT_CENTER | DT_SINGLELINE | DT_VCENTER | DT_HIDEPREFIX ); + DrawInfo->rc.left -= 10; } + else + { + RECT bufferRect = + { + 0, 0, + DrawInfo->rc.right - DrawInfo->rc.left, + DrawInfo->rc.bottom - DrawInfo->rc.top + }; + HICON buttonIcon; - DeleteDC(hdcTab); - - BitBlt(ps.hdc, 0, 0, clientRect.right, clientRect.bottom, hdc, 0, 0, SRCCOPY); + if (!(buttonIcon = Static_GetIcon(DrawInfo->hdr.hwndFrom, 0))) + { + buttonIcon = (HICON)SendMessage(DrawInfo->hdr.hwndFrom, BM_GETIMAGE, IMAGE_ICON, 0); + } - DeleteDC(hdc); - DeleteObject(hbm); - EndPaint(WindowHandle, &ps); + if (buttonIcon) + { + DrawIconEx( + DrawInfo->hdc, + bufferRect.left + ((bufferRect.right - bufferRect.left) - 16) / 2, + bufferRect.top + ((bufferRect.bottom - bufferRect.top) - 16 ) / 2, + buttonIcon, + 16, + 16, + 0, + NULL, + DI_NORMAL + ); + } + else + { + DrawText( + DrawInfo->hdc, + buttonText->Buffer, + (UINT)buttonText->Length / sizeof(WCHAR), + &DrawInfo->rc, + DT_CENTER | DT_SINGLELINE | DT_VCENTER | DT_HIDEPREFIX + ); + } + } - InvalidateRect(WindowHandle, NULL, FALSE); // HACK + PhDereferenceObject(buttonText); } - return DefWindowProc(WindowHandle, uMsg, wParam, lParam); + + return CDRF_SKIPDEFAULT; } - return CallWindowProc(oldWndProc, WindowHandle, uMsg, wParam, lParam); + return CDRF_DODEFAULT; } -LRESULT CALLBACK PhpThemeWindowHeaderSubclassProc( - _In_ HWND WindowHandle, - _In_ UINT uMsg, - _In_ WPARAM wParam, - _In_ LPARAM lParam +LRESULT CALLBACK PhThemeWindowDrawRebar( + _In_ LPNMCUSTOMDRAW DrawInfo ) { - PPHP_THEME_WINDOW_HEADER_CONTEXT context; - WNDPROC oldWndProc; - - if (!(context = PhGetWindowContext(WindowHandle, SHRT_MAX))) - return FALSE; - - oldWndProc = context->DefaultWindowProc; - - switch (uMsg) + switch (DrawInfo->dwDrawStage) { - case WM_NCDESTROY: + case CDDS_PREPAINT: { - PhRemoveWindowContext(WindowHandle, SHRT_MAX); - SetWindowLongPtr(WindowHandle, GWLP_WNDPROC, (LONG_PTR)oldWndProc); - PhFree(context); - } - break; - //case WM_ERASEBKGND: - // return 1; - case WM_MOUSEMOVE: - { - //POINT pt; - //RECT rcItem; - //TCITEM tcItem; - //tcItem.mask = TCIF_STATE; - //tcItem.dwStateMask = TCIS_HIGHLIGHTED; - //GetCursorPos(&pt); - //MapWindowPoints(NULL, WindowHandle, &pt, 1); - //int nCount = TabCtrl_GetItemCount(WindowHandle); - //for (int i = 0; i < nCount; i++) - //{ - // TabCtrl_GetItemRect(WindowHandle, i, &rcItem); - // tcItem.dwState = PtInRect(&rcItem, pt) ? TCIS_HIGHLIGHTED : 0; - // TabCtrl_SetItem(WindowHandle, i, &tcItem); - //} - - if (!context->MouseActive) + switch (PhGetIntegerSetting(L"GraphColorMode")) { - TRACKMOUSEEVENT trackEvent = - { - sizeof(TRACKMOUSEEVENT), - TME_LEAVE, - WindowHandle, - 0 - }; - - TrackMouseEvent(&trackEvent); - context->MouseActive = TRUE; + case 0: // New colors + SetTextColor(DrawInfo->hdc, RGB(0x0, 0x0, 0x0)); + SetDCBrushColor(DrawInfo->hdc, RGB(0xff, 0xff, 0xff)); + break; + case 1: // Old colors + SetTextColor(DrawInfo->hdc, RGB(0xff, 0xff, 0xff)); + SetDCBrushColor(DrawInfo->hdc, RGB(65, 65, 65)); + break; } - InvalidateRect(WindowHandle, NULL, FALSE); + FillRect(DrawInfo->hdc, &DrawInfo->rc, GetStockObject(DC_BRUSH)); } - break; - case WM_CONTEXTMENU: + return CDRF_NOTIFYITEMDRAW; + case CDDS_ITEMPREPAINT: { - LRESULT result = DefSubclassProc(WindowHandle, uMsg, wParam, lParam); - - InvalidateRect(WindowHandle, NULL, TRUE); + switch (PhGetIntegerSetting(L"GraphColorMode")) + { + case 0: // New colors + SetTextColor(DrawInfo->hdc, RGB(0x0, 0x0, 0x0)); + SetDCBrushColor(DrawInfo->hdc, RGB(0x0, 0x0, 0x0)); + case 1: // Old colors + SetTextColor(DrawInfo->hdc, RGB(0xff, 0xff, 0xff)); + SetDCBrushColor(DrawInfo->hdc, RGB(65, 65, 65)); + break; + } - return result; + FillRect(DrawInfo->hdc, &DrawInfo->rc, GetStockObject(DC_BRUSH)); } - break; - case WM_MOUSELEAVE: - { - // TCITEM tcItem = { TCIF_STATE, 0, TCIS_HIGHLIGHTED }; - //// int nCount = TabCtrl_GetItemCount(WindowHandle); - // for (int i = 0; i < nCount; i++) - // { - // //TabCtrl_SetItem(WindowHandle, i, &tcItem); - // } + return CDRF_SKIPDEFAULT; + } - InvalidateRect(WindowHandle, NULL, TRUE); - context->MouseActive = FALSE; - } - break; - case WM_PAINT: - { - //HTHEME hTheme = OpenThemeData(WindowHandle, L"HEADER"); - WCHAR szText[MAX_PATH + 1]; - RECT rcClient; - HDITEM tcItem; - PAINTSTRUCT ps; + return CDRF_DODEFAULT; +} - //InvalidateRect(WindowHandle, NULL, FALSE); - BeginPaint(WindowHandle, &ps); +LRESULT CALLBACK PhThemeWindowDrawToolbar( + _In_ LPNMTBCUSTOMDRAW DrawInfo + ) +{ + switch (DrawInfo->nmcd.dwDrawStage) + { + case CDDS_PREPAINT: + return CDRF_NOTIFYITEMDRAW | CDRF_NOTIFYPOSTPAINT; + case CDDS_ITEMPREPAINT: + { + TBBUTTONINFO buttonInfo = + { + sizeof(TBBUTTONINFO), + TBIF_STYLE | TBIF_COMMAND | TBIF_STATE | TBIF_IMAGE + }; - GetClientRect(WindowHandle, &rcClient); + SetBkMode(DrawInfo->nmcd.hdc, TRANSPARENT); - ZeroMemory(&tcItem, sizeof(tcItem)); - tcItem.mask = HDI_TEXT | HDI_IMAGE | HDI_STATE; - tcItem.pszText = szText; - tcItem.cchTextMax = MAX_PATH; + ULONG currentIndex = (ULONG)SendMessage( + DrawInfo->nmcd.hdr.hwndFrom, + TB_COMMANDTOINDEX, + DrawInfo->nmcd.dwItemSpec, + 0 + ); + BOOLEAN isHighlighted = SendMessage( + DrawInfo->nmcd.hdr.hwndFrom, + TB_GETHOTITEM, + 0, + 0 + ) == currentIndex; + BOOLEAN isMouseDown = SendMessage( + DrawInfo->nmcd.hdr.hwndFrom, + TB_ISBUTTONPRESSED, + DrawInfo->nmcd.dwItemSpec, + 0 + ) == 0; - HDC hdc = CreateCompatibleDC(ps.hdc); - HBITMAP hbm = CreateCompatibleBitmap(ps.hdc, rcClient.right, rcClient.bottom); + //if (isMouseDown) + //{ + // SetTextColor(DrawInfo->nmcd.hdc, RGB(0xff, 0xff, 0xff)); + // SetDCBrushColor(DrawInfo->nmcd.hdc, RGB(0xff, 0xff, 0xff)); + // FillRect(DrawInfo->nmcd.hdc, &DrawInfo->nmcd.rc, GetStockObject(DC_BRUSH)); + //} - SelectObject(hdc, hbm); + if (isHighlighted) + { + switch (PhGetIntegerSetting(L"GraphColorMode")) + { + case 0: // New colors + SetTextColor(DrawInfo->nmcd.hdc, RGB(0x0, 0x0, 0x0)); + SetDCBrushColor(DrawInfo->nmcd.hdc, RGB(0xff, 0xff, 0xff)); + FillRect(DrawInfo->nmcd.hdc, &DrawInfo->nmcd.rc, GetStockObject(DC_BRUSH)); + break; + case 1: // Old colors + SetTextColor(DrawInfo->nmcd.hdc, RGB(0xff, 0xff, 0xff)); + SetDCBrushColor(DrawInfo->nmcd.hdc, RGB(128, 128, 128)); + FillRect(DrawInfo->nmcd.hdc, &DrawInfo->nmcd.rc, GetStockObject(DC_BRUSH)); + break; + } + } + else + { + switch (PhGetIntegerSetting(L"GraphColorMode")) + { + case 0: // New colors + SetTextColor(DrawInfo->nmcd.hdc, RGB(0x0, 0x0, 0x0)); + SetDCBrushColor(DrawInfo->nmcd.hdc, RGB(0xff, 0xff, 0xff)); + FillRect(DrawInfo->nmcd.hdc, &DrawInfo->nmcd.rc, GetStockObject(DC_BRUSH)); + break; + case 1: // Old colors + SetTextColor(DrawInfo->nmcd.hdc, RGB(0xff, 0xff, 0xff)); + SetDCBrushColor(DrawInfo->nmcd.hdc, RGB(65, 65, 65)); //RGB(28, 28, 28)); // RGB(65, 65, 65)); + FillRect(DrawInfo->nmcd.hdc, &DrawInfo->nmcd.rc, GetStockObject(DC_BRUSH)); + break; + } + } - static HFONT fontHandle = NULL; - if (!fontHandle) + if (!PhpToolBarFontHandle) { - NONCLIENTMETRICS metrics = { sizeof(metrics) }; + NONCLIENTMETRICS metrics = { sizeof(NONCLIENTMETRICS) }; + if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, &metrics, 0)) { - fontHandle = CreateFontIndirect(&metrics.lfMessageFont); + PhpToolBarFontHandle = CreateFontIndirect(&metrics.lfMessageFont); } } - SelectObject(hdc, fontHandle); - SetBkMode(hdc, TRANSPARENT); + SelectFont(DrawInfo->nmcd.hdc, PhpToolBarFontHandle); - switch (PhGetIntegerSetting(L"GraphColorMode")) + + if (SendMessage( + DrawInfo->nmcd.hdr.hwndFrom, + TB_GETBUTTONINFO, + (ULONG)DrawInfo->nmcd.dwItemSpec, + (LPARAM)&buttonInfo + ) == -1) { - case 0: // New colors - SetTextColor(hdc, RGB(0x0, 0x0, 0x0)); - SetDCBrushColor(hdc, PhpThemeWindowTextColor); - FillRect(hdc, &rcClient, GetStockObject(DC_BRUSH)); - break; - case 1: // Old colors - SetTextColor(hdc, PhpThemeWindowTextColor); - SetDCBrushColor(hdc, RGB(65, 65, 65)); //WindowForegroundColor); // RGB(65, 65, 65)); - FillRect(hdc, &rcClient, GetStockObject(DC_BRUSH)); break; } - HDC hdcTab = CreateCompatibleDC(hdc); - - INT nCount = Header_GetItemCount(WindowHandle); - for (INT i = 0; i < nCount; i++) + if (buttonInfo.iImage != -1) { - RECT headerRect; - POINT pt; - - Header_GetItemRect(WindowHandle, i, &headerRect); - Header_GetItem(WindowHandle, i, &tcItem); - - GetCursorPos(&pt); - MapWindowPoints(NULL, WindowHandle, &pt, 1); + HIMAGELIST toolbarImageList; - if (PtInRect(&headerRect, pt)) + if (toolbarImageList = (HIMAGELIST)SendMessage( + DrawInfo->nmcd.hdr.hwndFrom, + TB_GETIMAGELIST, + 0, + 0 + )) { - switch (PhGetIntegerSetting(L"GraphColorMode")) - { - case 0: // New colors - SetTextColor(hdc, PhpThemeWindowTextColor); - SetDCBrushColor(hdc, PhpThemeWindowBackgroundColor); - FillRect(hdc, &headerRect, GetStockObject(DC_BRUSH)); - break; - case 1: // Old colors - SetTextColor(hdc, PhpThemeWindowTextColor); - SetDCBrushColor(hdc, RGB(128, 128, 128)); - FillRect(hdc, &headerRect, GetStockObject(DC_BRUSH)); - break; - } + DrawInfo->nmcd.rc.left += 5; - //FrameRect(hdc, &headerRect, GetSysColorBrush(COLOR_HIGHLIGHT)); + ImageList_Draw( + toolbarImageList, + buttonInfo.iImage, + DrawInfo->nmcd.hdc, + DrawInfo->nmcd.rc.left, + DrawInfo->nmcd.rc.top + 3, + ILD_NORMAL + ); } - else - { - switch (PhGetIntegerSetting(L"GraphColorMode")) - { - case 0: // New colors - SetTextColor(hdc, RGB(0x0, 0x0, 0x0)); - SetDCBrushColor(hdc, PhpThemeWindowTextColor); - FillRect(hdc, &headerRect, GetStockObject(DC_BRUSH)); - break; - case 1: // Old colors - SetTextColor(hdc, PhpThemeWindowTextColor); - SetDCBrushColor(hdc, PhpThemeWindowBackgroundColor); - FillRect(hdc, &headerRect, GetStockObject(DC_BRUSH)); - break; - } + } - //FrameRect(hdc, &headerRect, GetSysColorBrush(COLOR_HIGHLIGHT)); - } + if (buttonInfo.fsStyle & BTNS_SHOWTEXT) + { + WCHAR buttonText[0x100] = L""; - DrawText( - hdc, - tcItem.pszText, + SendMessage( + DrawInfo->nmcd.hdr.hwndFrom, + TB_GETBUTTONTEXT, + (ULONG)DrawInfo->nmcd.dwItemSpec, + (LPARAM)buttonText + ); + + DrawInfo->nmcd.rc.left += 10; + DrawText( + DrawInfo->nmcd.hdc, + buttonText, -1, - &headerRect, - DT_VCENTER | DT_CENTER | DT_SINGLELINE | DT_HIDEPREFIX + &DrawInfo->nmcd.rc, + DT_CENTER | DT_VCENTER | DT_SINGLELINE | DT_HIDEPREFIX ); } - DeleteDC(hdcTab); + //DrawInfo->clrText = RGB(0x0, 0xff, 0); + //return TBCDRF_USECDCOLORS | CDRF_NEWFONT; + } + return CDRF_SKIPDEFAULT; + } - BitBlt(ps.hdc, 0, 0, rcClient.right, rcClient.bottom, hdc, 0, 0, SRCCOPY); + return CDRF_DODEFAULT; +} - DeleteDC(hdc); - DeleteObject(hbm); - EndPaint(WindowHandle, &ps); - } +LRESULT CALLBACK PhpThemeWindowDrawListViewGroup( + _In_ LPNMLVCUSTOMDRAW DrawInfo + ) +{ + switch (DrawInfo->nmcd.dwDrawStage) + { + case CDDS_PREPAINT: + { + SetBkMode(DrawInfo->nmcd.hdc, TRANSPARENT); - return DefWindowProc(WindowHandle, uMsg, wParam, lParam); + switch (PhGetIntegerSetting(L"GraphColorMode")) + { + case 0: // New colors + SetTextColor(DrawInfo->nmcd.hdc, RGB(0x0, 0x0, 0x0)); + SetDCBrushColor(DrawInfo->nmcd.hdc, PhpThemeWindowTextColor); + //FillRect(DrawInfo->nmcd.hdc, &DrawInfo->nmcd.rc, GetStockObject(DC_BRUSH)); + break; + case 1: // Old colors + SetTextColor(DrawInfo->nmcd.hdc, RGB(0x0, 0x0, 0x0)); + SetDCBrushColor(DrawInfo->nmcd.hdc, RGB(128, 128, 128)); + //FillRect(DrawInfo->nmcd.hdc, &DrawInfo->nmcd.rc, GetStockObject(DC_BRUSH)); + break; + } + + if (!PhpListViewFontHandle) + { + NONCLIENTMETRICS metrics = { sizeof(NONCLIENTMETRICS) }; + + if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, &metrics, 0)) + { + metrics.lfMessageFont.lfHeight = -11; + metrics.lfMessageFont.lfWeight = FW_BOLD; + + PhpListViewFontHandle = CreateFontIndirect(&metrics.lfMessageFont); + } + } + + SelectFont(DrawInfo->nmcd.hdc, PhpListViewFontHandle); + + LVGROUP groupInfo = { sizeof(LVGROUP) }; + groupInfo.mask = LVGF_HEADER; + if (ListView_GetGroupInfo( + DrawInfo->nmcd.hdr.hwndFrom, + (ULONG)DrawInfo->nmcd.dwItemSpec, + &groupInfo + ) == -1) + { + break; + } + + SetTextColor(DrawInfo->nmcd.hdc, RGB(255, 69, 0)); + SetDCBrushColor(DrawInfo->nmcd.hdc, RGB(65, 65, 65)); + + DrawInfo->rcText.top += 2; + DrawInfo->rcText.bottom -= 2; + FillRect(DrawInfo->nmcd.hdc, &DrawInfo->rcText, GetStockObject(DC_BRUSH)); + DrawInfo->rcText.top -= 2; + DrawInfo->rcText.bottom += 2; + + SetTextColor(DrawInfo->nmcd.hdc, RGB(255, 69, 0)); + SetDCBrushColor(DrawInfo->nmcd.hdc, RGB(65, 65, 65)); + + DrawInfo->rcText.left += 10; + DrawText( + DrawInfo->nmcd.hdc, + groupInfo.pszHeader, + -1, + &DrawInfo->rcText, + DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_HIDEPREFIX + ); + DrawInfo->rcText.left -= 10; + } + return CDRF_SKIPDEFAULT; } - return CallWindowProc(oldWndProc, WindowHandle, uMsg, wParam, lParam); + return CDRF_DODEFAULT; } -LRESULT CALLBACK PhpThemeWindowStatusbarWndSubclassProc( +LRESULT CALLBACK PhpThemeWindowSubclassProc( _In_ HWND hWnd, _In_ UINT uMsg, _In_ WPARAM wParam, @@ -758,856 +836,851 @@ LRESULT CALLBACK PhpThemeWindowStatusbarWndSubclassProc( if (!(oldWndProc = PhGetWindowContext(hWnd, SHRT_MAX))) return FALSE; - static BOOLEAN MouseActive = FALSE; - switch (uMsg) { - case WM_NCDESTROY: + case WM_DESTROY: { PhRemoveWindowContext(hWnd, SHRT_MAX); SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)oldWndProc); } break; - case WM_ERASEBKGND: - return 1; - case WM_MOUSEMOVE: + case WM_NOTIFY: { - if (!MouseActive) + LPNMHDR data = (LPNMHDR)lParam; + + switch (data->code) { - TRACKMOUSEEVENT trackEvent = - { - sizeof(TRACKMOUSEEVENT), - TME_LEAVE, - hWnd, - 0 - }; + case NM_CUSTOMDRAW: + { + LPNMCUSTOMDRAW customDraw = (LPNMCUSTOMDRAW)lParam; + WCHAR className[MAX_PATH]; - TrackMouseEvent(&trackEvent); - MouseActive = TRUE; - } + if (!GetClassName(customDraw->hdr.hwndFrom, className, RTL_NUMBER_OF(className))) + className[0] = 0; - InvalidateRect(hWnd, NULL, FALSE); + dprintf("ClassName: %S\r\n", className); + + if (PhEqualStringZ(className, L"Button", FALSE)) + { + return PhpThemeWindowDrawButton(customDraw); + } + else if (PhEqualStringZ(className, L"ReBarWindow32", FALSE)) + { + NOTHING; + } + else if (PhEqualStringZ(className, L"ToolbarWindow32", FALSE)) + { + NOTHING; + } + else if (PhEqualStringZ(className, L"SysTabControl32", FALSE)) + { + NOTHING; + } + else if (PhEqualStringZ(className, L"SysListView32", FALSE)) + { + LPNMLVCUSTOMDRAW listViewCustomDraw = (LPNMLVCUSTOMDRAW)customDraw; + + if (listViewCustomDraw->dwItemType == LVCDI_GROUP) + { + return PhpThemeWindowDrawListViewGroup(listViewCustomDraw); + } + } + } + } } break; - case WM_MOUSELEAVE: + case WM_CTLCOLOREDIT: { - InvalidateRect(hWnd, NULL, FALSE); - MouseActive = FALSE; + SetBkMode((HDC)wParam, TRANSPARENT); + + switch (PhGetIntegerSetting(L"GraphColorMode")) + { + case 0: // New colors + SetTextColor((HDC)wParam, RGB(0x0, 0x0, 0x0)); + SetDCBrushColor((HDC)wParam, PhpThemeWindowTextColor); + return (INT_PTR)GetStockObject(DC_BRUSH); + case 1: // Old colors + SetTextColor((HDC)wParam, PhpThemeWindowTextColor); + SetDCBrushColor((HDC)wParam, RGB(60, 60, 60)); + return (INT_PTR)GetStockObject(DC_BRUSH); + } } break; - case WM_PAINT: + case WM_CTLCOLORBTN: + case WM_CTLCOLORDLG: + case WM_CTLCOLORSTATIC: { - RECT rcClient; - PAINTSTRUCT ps; - INT blockCoord[128]; - INT blockCount = (INT)SendMessage(hWnd, (UINT)SB_GETPARTS, (WPARAM)ARRAYSIZE(blockCoord), (WPARAM)blockCoord); + SetBkMode((HDC)wParam, TRANSPARENT); + + switch (PhGetIntegerSetting(L"GraphColorMode")) + { + case 0: // New colors + SetTextColor((HDC)wParam, RGB(0x0, 0x0, 0x0)); + SetDCBrushColor((HDC)wParam, PhpThemeWindowTextColor); + return (INT_PTR)GetStockObject(DC_BRUSH); + case 1: // Old colors + SetTextColor((HDC)wParam, PhpThemeWindowTextColor); + SetDCBrushColor((HDC)wParam, RGB(30, 30, 30)); + return (INT_PTR)GetStockObject(DC_BRUSH); + } + } + break; + } - InvalidateRect(hWnd, NULL, FALSE); + return CallWindowProc(oldWndProc, hWnd, uMsg, wParam, lParam); +} - BeginPaint(hWnd, &ps); +LRESULT CALLBACK PhpThemeWindowGroupBoxSubclassProc( + _In_ HWND hWnd, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + WNDPROC oldWndProc; - GetClientRect(hWnd, &rcClient); + if (!(oldWndProc = PhGetWindowContext(hWnd, SHRT_MAX))) + return FALSE; - HDC hdc = CreateCompatibleDC(ps.hdc); - HBITMAP hbm = CreateCompatibleBitmap(ps.hdc, rcClient.right, rcClient.bottom); - - SetBkMode(hdc, TRANSPARENT); + switch (uMsg) + { + case WM_DESTROY: + { + PhRemoveWindowContext(hWnd, SHRT_MAX); + SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)oldWndProc); + } + break; + case WM_ERASEBKGND: + return TRUE; + case WM_PAINT: + { + RECT clientRect; + HDC hdc; + PAINTSTRUCT ps; + PPH_STRING windowText; + SIZE nameSize; + RECT textRect; - SelectObject(hdc, hbm); + if (!(hdc = BeginPaint(hWnd, &ps))) + break; - static HFONT fontHandle = NULL; - if (!fontHandle) - { - NONCLIENTMETRICS metrics = { sizeof(metrics) }; - if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, &metrics, 0)) - { - fontHandle = CreateFontIndirect(&metrics.lfMessageFont); - } - } - SelectObject(hdc, fontHandle); + GetClientRect(hWnd, &clientRect); + SetBkMode(hdc, TRANSPARENT); switch (PhGetIntegerSetting(L"GraphColorMode")) { case 0: // New colors SetTextColor(hdc, RGB(0x0, 0x0, 0x0)); SetDCBrushColor(hdc, RGB(0xff, 0xff, 0xff)); - FillRect(hdc, &rcClient, GetStockObject(DC_BRUSH)); + //FillRect(hdc, &windowRect, GetStockObject(DC_BRUSH)); break; case 1: // Old colors SetTextColor(hdc, RGB(0xff, 0xff, 0xff)); - SetDCBrushColor(hdc, RGB(65, 65, 65)); //RGB(28, 28, 28)); // RGB(65, 65, 65)); - FillRect(hdc, &rcClient, GetStockObject(DC_BRUSH)); + SetDCBrushColor(hdc, RGB(0, 0, 0)); // RGB(28, 28, 28)); // RGB(65, 65, 65)); + //FillRect(hdc, &windowRect, GetStockObject(DC_BRUSH)); break; } - HDC hdcTab = CreateCompatibleDC(hdc); - - for (INT i = 0; i < blockCount; i++) + if (!PhpGroupboxFontHandle) // HACK { - RECT blockRect; - WCHAR buffer[260] = L""; - SendMessage(hWnd, SB_GETRECT, (WPARAM)i, (WPARAM)&blockRect); - SendMessage(hWnd, SB_GETTEXT, (WPARAM)i, (LPARAM)buffer); - - POINT pt; - GetCursorPos(&pt); - MapWindowPoints(NULL, hWnd, &pt, 1); + NONCLIENTMETRICS metrics = { sizeof(NONCLIENTMETRICS) }; - if (PtInRect(&blockRect, pt)) + if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, &metrics, 0)) { - switch (PhGetIntegerSetting(L"GraphColorMode")) - { - case 0: // New colors - SetTextColor(hdc, RGB(0x0, 0x0, 0x0)); - SetDCBrushColor(hdc, RGB(0xff, 0xff, 0xff)); - FillRect(hdc, &blockRect, GetStockObject(DC_BRUSH)); - //FrameRect(hdc, &blockRect, GetSysColorBrush(COLOR_HIGHLIGHT)); - break; - case 1: // Old colors - SetTextColor(hdc, RGB(0xff, 0xff, 0xff)); - SetDCBrushColor(hdc, RGB(128, 128, 128)); - FillRect(hdc, &blockRect, GetStockObject(DC_BRUSH)); - //FrameRect(hdc, &blockRect, GetSysColorBrush(COLOR_HIGHLIGHT)); - break; - } - } - else - { - switch (PhGetIntegerSetting(L"GraphColorMode")) - { - case 0: // New colors - SetTextColor(hdc, RGB(0x0, 0x0, 0x0)); - SetDCBrushColor(hdc, RGB(0xff, 0xff, 0xff)); - FillRect(hdc, &blockRect, GetStockObject(DC_BRUSH)); - //FrameRect(hdc, &blockRect, GetSysColorBrush(COLOR_HIGHLIGHT)); - break; - case 1: // Old colors - SetTextColor(hdc, RGB(0xff, 0xff, 0xff)); - SetDCBrushColor(hdc, RGB(64, 64, 64)); - FillRect(hdc, &blockRect, GetStockObject(DC_BRUSH)); - //FrameRect(hdc, &blockRect, GetSysColorBrush(COLOR_HIGHLIGHT)); - break; - } - } + metrics.lfMessageFont.lfHeight = -12; + metrics.lfMessageFont.lfWeight = FW_BOLD; - DrawText( - hdc, - buffer, - -1, - &blockRect, - DT_CENTER | DT_VCENTER | DT_SINGLELINE | DT_HIDEPREFIX //| DT_WORD_ELLIPSIS - ); + PhpGroupboxFontHandle = CreateFontIndirect(&metrics.lfMessageFont); + } } - DeleteDC(hdcTab); + SelectFont(hdc, PhpGroupboxFontHandle); + SetTextColor(hdc, RGB(255, 69, 0)); + SetDCBrushColor(hdc, RGB(65, 65, 65)); + //clientRect.top += 6; + FrameRect(hdc, &clientRect, GetStockObject(DC_BRUSH)); + //clientRect.top -= 6; - BitBlt(ps.hdc, 0, 0, rcClient.right, rcClient.bottom, hdc, 0, 0, SRCCOPY); + windowText = PhGetWindowText(hWnd); + GetTextExtentPoint32( + hdc, + windowText->Buffer, + (ULONG)windowText->Length / sizeof(WCHAR), + &nameSize + ); + + textRect.left = 0; + textRect.top = 0; + textRect.right = clientRect.right; + textRect.bottom = nameSize.cy; + FillRect(hdc, &textRect, GetStockObject(DC_BRUSH)); + + textRect.left += 10; + DrawText( + hdc, + windowText->Buffer, + (ULONG)windowText->Length / sizeof(WCHAR), + &textRect, + DT_LEFT | DT_END_ELLIPSIS | DT_SINGLELINE + ); + textRect.left -= 10; + + PhDereferenceObject(windowText); - DeleteDC(hdc); - DeleteObject(hbm); EndPaint(hWnd, &ps); } - return DefWindowProc(hWnd, uMsg, wParam, lParam); + return FALSE; } return CallWindowProc(oldWndProc, hWnd, uMsg, wParam, lParam); } -VOID PhInitializeWindowTheme( +LRESULT CALLBACK PhpThemeWindowTabControlWndSubclassProc( _In_ HWND WindowHandle, - _In_ BOOLEAN EnableThemeSupport + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam ) { - if (EnableThemeSupport) - { - WNDPROC defaultWindowProc; + PPHP_THEME_WINDOW_TAB_CONTEXT context; + WNDPROC oldWndProc; - defaultWindowProc = (WNDPROC)GetWindowLongPtr(WindowHandle, GWLP_WNDPROC); - PhSetWindowContext(WindowHandle, SHRT_MAX, defaultWindowProc); - SetWindowLongPtr(WindowHandle, GWLP_WNDPROC, (LONG_PTR)PhpThemeWindowSubclassProc); + if (!(context = PhGetWindowContext(WindowHandle, SHRT_MAX))) + return FALSE; - PhEnumChildWindows( - WindowHandle, - 0x1000, - PhpThemeWindowEnumChildWindows, - 0 - ); + oldWndProc = context->DefaultWindowProc; - InvalidateRect(WindowHandle, NULL, FALSE); // HACK - } - else + switch (uMsg) { - EnableThemeDialogTexture(WindowHandle, ETDT_ENABLETAB); - } -} + case WM_DESTROY: + { + PhRemoveWindowContext(WindowHandle, SHRT_MAX); + SetWindowLongPtr(WindowHandle, GWLP_WNDPROC, (LONG_PTR)oldWndProc); -VOID PhReInitializeWindowTheme( - _In_ HWND WindowHandle - ) -{ - HWND currentWindow = NULL; + PhFree(context); + } + break; + case WM_ERASEBKGND: + return TRUE; + case WM_MOUSEMOVE: + { + POINT pt; + INT count; + INT i; - PhEnumChildWindows( - WindowHandle, - 0x1000, - PhpReInitializeThemeWindowEnumChildWindows, - 0 - ); + GetCursorPos(&pt); + MapWindowPoints(NULL, WindowHandle, &pt, 1); - do - { - if (currentWindow = FindWindowEx(NULL, currentWindow, NULL, NULL)) - { - ULONG processID = 0; - - GetWindowThreadProcessId(currentWindow, &processID); - - if (UlongToHandle(processID) == NtCurrentProcessId()) + count = TabCtrl_GetItemCount(WindowHandle); + + for (i = 0; i < count; i++) { - if (currentWindow != WindowHandle) + RECT rect = { 0, 0, 0, 0 }; + TCITEM entry = { - InvalidateRect(currentWindow, NULL, TRUE); - } - } - } - } while (currentWindow); + TCIF_STATE, + 0, + TCIS_HIGHLIGHTED + }; - InvalidateRect(WindowHandle, NULL, FALSE); -} + TabCtrl_GetItemRect(WindowHandle, i, &rect); + entry.dwState = PtInRect(&rect, pt) ? TCIS_HIGHLIGHTED : 0; + TabCtrl_SetItem(WindowHandle, i, &entry); + } -VOID PhInitializeThemeWindowHeader( - _In_ HWND HeaderWindow - ) -{ - PPHP_THEME_WINDOW_HEADER_CONTEXT headerControlContext; + if (!context->MouseActive) + { + TRACKMOUSEEVENT trackEvent = + { + sizeof(TRACKMOUSEEVENT), + TME_LEAVE, + WindowHandle, + 0 + }; - headerControlContext = PhAllocateZero(sizeof(PHP_THEME_WINDOW_HEADER_CONTEXT)); - headerControlContext->DefaultWindowProc = (WNDPROC)GetWindowLongPtr(HeaderWindow, GWLP_WNDPROC); - PhSetWindowContext(HeaderWindow, SHRT_MAX, headerControlContext); - SetWindowLongPtr(HeaderWindow, GWLP_WNDPROC, (LONG_PTR)PhpThemeWindowHeaderSubclassProc); + TrackMouseEvent(&trackEvent); + context->MouseActive = TRUE; + } - InvalidateRect(HeaderWindow, NULL, FALSE); -} + InvalidateRect(WindowHandle, NULL, FALSE); + } + break; + case WM_MOUSELEAVE: + { + INT count; + INT i; -VOID PhInitializeThemeWindowTabControl( - _In_ HWND TabControlWindow - ) -{ - PPHP_THEME_WINDOW_TAB_CONTEXT tabControlContext; + count = TabCtrl_GetItemCount(WindowHandle); - tabControlContext = PhAllocateZero(sizeof(PHP_THEME_WINDOW_TAB_CONTEXT)); - tabControlContext->DefaultWindowProc = (WNDPROC)GetWindowLongPtr(TabControlWindow, GWLP_WNDPROC); - PhSetWindowContext(TabControlWindow, SHRT_MAX, tabControlContext); - SetWindowLongPtr(TabControlWindow, GWLP_WNDPROC, (LONG_PTR)PhpThemeWindowTabControlWndSubclassProc); + for (i = 0; i < count; i++) + { + TCITEM entry = + { + TCIF_STATE, + 0, + TCIS_HIGHLIGHTED + }; - PhSetWindowStyle(TabControlWindow, TCS_OWNERDRAWFIXED, TCS_OWNERDRAWFIXED); + TabCtrl_SetItem(WindowHandle, i, &entry); + } - if (!PhpTabControlFontHandle) - { - PhpTabControlFontHandle = CreateFont( - -(LONG)PhMultiplyDivide(15, PhGlobalDpi, 96), - 0, - 0, - 0, - FW_SEMIBOLD, - FALSE, - FALSE, - FALSE, - ANSI_CHARSET, - OUT_DEFAULT_PRECIS, - CLIP_DEFAULT_PRECIS, - DEFAULT_QUALITY, - DEFAULT_PITCH, - L"Tahoma" - ); - } + InvalidateRect(WindowHandle, NULL, FALSE); + context->MouseActive = FALSE; + } + break; + case WM_PAINT: + { + RECT clientRect, itemRect; + TCITEMW tcItem; + PAINTSTRUCT ps; + WCHAR szText[MAX_PATH]; - SendMessage(TabControlWindow, WM_SETFONT, (WPARAM)PhpTabControlFontHandle, FALSE); + BeginPaint(WindowHandle, &ps); - InvalidateRect(TabControlWindow, NULL, FALSE); -} + GetClientRect(WindowHandle, &clientRect); -VOID PhInitializeThemeWindowStatusBar( - _In_ HWND StatusBarHandle - ) -{ - WNDPROC defaultWindowProc; + ZeroMemory(&tcItem, sizeof(TCITEMW)); + tcItem.mask = TCIF_TEXT | TCIF_IMAGE | TCIF_STATE; + tcItem.dwStateMask = TCIS_BUTTONPRESSED | TCIS_HIGHLIGHTED; + tcItem.pszText = szText; + tcItem.cchTextMax = MAX_PATH; - defaultWindowProc = (WNDPROC)GetWindowLongPtr(StatusBarHandle, GWLP_WNDPROC); - PhSetWindowContext(StatusBarHandle, SHRT_MAX, defaultWindowProc); - SetWindowLongPtr(StatusBarHandle, GWLP_WNDPROC, (LONG_PTR)PhpThemeWindowStatusbarWndSubclassProc); - - InvalidateRect(StatusBarHandle, NULL, FALSE); -} - -VOID PhInitializeThemeWindowGroupBox( - _In_ HWND GroupBoxHandle - ) -{ - WNDPROC groupboxWindowProc; - - groupboxWindowProc = (WNDPROC)GetWindowLongPtr(GroupBoxHandle, GWLP_WNDPROC); - PhSetWindowContext(GroupBoxHandle, SHRT_MAX, groupboxWindowProc); - SetWindowLongPtr(GroupBoxHandle, GWLP_WNDPROC, (LONG_PTR)PhpThemeWindowGroupBoxSubclassProc); - - InvalidateRect(GroupBoxHandle, NULL, FALSE); -} - -BOOLEAN CALLBACK PhpThemeWindowEnumChildWindows( - _In_ HWND WindowHandle, - _In_opt_ PVOID Context - ) -{ - WCHAR className[MAX_PATH]; - - PhEnumChildWindows( - WindowHandle, - 0x1000, - PhpThemeWindowEnumChildWindows, - 0 - ); - - if (!GetClassName(WindowHandle, className, RTL_NUMBER_OF(className))) - className[0] = 0; - - if (PhEqualStringZ(className, L"#32770", FALSE)) - { - PhInitializeWindowTheme(WindowHandle, TRUE); - } - else if (PhEqualStringZ(className, L"Button", FALSE)) - { - ULONG buttonWindowStyle = (ULONG)GetWindowLongPtr(WindowHandle, GWL_STYLE); - - if ((buttonWindowStyle & BS_GROUPBOX) == BS_GROUPBOX) - { - PhInitializeThemeWindowGroupBox(WindowHandle); - } - } - else if (PhEqualStringZ(className, L"Edit", FALSE)) - { - switch (PhGetIntegerSetting(L"GraphColorMode")) - { - case 0: // New colors - //PhSetWindowStyle(WindowHandle, WS_BORDER, WS_BORDER); - //PhSetWindowExStyle(WindowHandle, WS_EX_CLIENTEDGE, WS_EX_CLIENTEDGE); - break; - case 1: // Old colors - PhSetWindowStyle(WindowHandle, WS_BORDER, 0); - PhSetWindowExStyle(WindowHandle, WS_EX_CLIENTEDGE, 0); - break; - } - } - else if (PhEqualStringZ(className, L"SysTabControl32", FALSE)) - { - PhInitializeThemeWindowTabControl(WindowHandle); - } - else if (PhEqualStringZ(className, L"msctls_statusbar32", FALSE)) - { - PhInitializeThemeWindowStatusBar(WindowHandle); - } - else if (PhEqualStringZ(className, L"SysHeader32", FALSE)) - { - PhInitializeThemeWindowHeader(WindowHandle); - } - else if (PhEqualStringZ(className, L"SysListView32", FALSE)) - { - PhSetWindowStyle(WindowHandle, WS_BORDER, 0); - PhSetWindowExStyle(WindowHandle, WS_EX_CLIENTEDGE, 0); - - switch (PhGetIntegerSetting(L"GraphColorMode")) - { - case 0: // New colors - break; - case 1: // Old colors - ListView_SetBkColor(WindowHandle, RGB(30, 30, 30)); - ListView_SetTextBkColor(WindowHandle, RGB(30, 30, 30)); - ListView_SetTextColor(WindowHandle, RGB(0xff, 0xff, 0xff)); - break; - } - } - else if (PhEqualStringZ(className, L"SysTreeView32", FALSE)) - { - //PhSetWindowStyle(WindowHandle, WS_BORDER, 0); - //PhSetWindowExStyle(WindowHandle, WS_EX_CLIENTEDGE, 0); - - switch (PhGetIntegerSetting(L"GraphColorMode")) - { - case 0: // New colors - break; - case 1: // Old colors - TreeView_SetBkColor(WindowHandle, RGB(30, 30, 30)); - //TreeView_SetTextBkColor(WindowHandle, RGB(30, 30, 30)); - TreeView_SetTextColor(WindowHandle, RGB(0xff, 0xff, 0xff)); - break; - } - } - else if (PhEqualStringZ(className, L"ScrollBar", FALSE)) - { - NOTHING; - } - else if (PhEqualStringZ(className, L"PhTreeNew", FALSE)) - { - PhSetWindowStyle(WindowHandle, WS_BORDER, 0); - PhSetWindowExStyle(WindowHandle, WS_EX_CLIENTEDGE, 0); - } - - return TRUE; -} - -BOOLEAN CALLBACK PhpReInitializeThemeWindowEnumChildWindows( - _In_ HWND WindowHandle, - _In_opt_ PVOID Context - ) -{ - ULONG processID = 0; - - PhEnumChildWindows( - WindowHandle, - 0x1000, - PhpReInitializeThemeWindowEnumChildWindows, - 0 - ); - - GetWindowThreadProcessId(WindowHandle, &processID); - - if (UlongToHandle(processID) == NtCurrentProcessId()) - { - InvalidateRect(WindowHandle, NULL, FALSE); - } - - return TRUE; -} - -LRESULT PhpThemeWindowDrawButton( - _In_ LPNMCUSTOMDRAW DrawInfo - ) -{ - BOOLEAN isGrayed = (DrawInfo->uItemState & CDIS_GRAYED) == CDIS_GRAYED; - BOOLEAN isChecked = (DrawInfo->uItemState & CDIS_CHECKED) == CDIS_CHECKED; - BOOLEAN isDisabled = (DrawInfo->uItemState & CDIS_DISABLED) == CDIS_DISABLED; - BOOLEAN isSelected = (DrawInfo->uItemState & CDIS_SELECTED) == CDIS_SELECTED; - BOOLEAN isHighlighted = (DrawInfo->uItemState & CDIS_HOT) == CDIS_HOT; - BOOLEAN isFocused = (DrawInfo->uItemState & CDIS_FOCUS) == CDIS_FOCUS; + RECT rcSpin = clientRect; + HWND hWndSpin = GetDlgItem(WindowHandle, 1); + if (hWndSpin) + { + GetWindowRect(hWndSpin, &rcSpin); + MapWindowPoints(NULL, WindowHandle, (LPPOINT)&rcSpin, 2); + rcSpin.right = rcSpin.left; + rcSpin.left = rcSpin.top = 0; + rcSpin.bottom = clientRect.bottom; + } - switch (DrawInfo->dwDrawStage) - { - case CDDS_PREPAINT: - { - PPH_STRING buttonText; - HFONT oldFont; + HDC hdc = CreateCompatibleDC(ps.hdc); + HDC hdcTab = CreateCompatibleDC(hdc); + HBITMAP hbm = CreateCompatibleBitmap(ps.hdc, clientRect.right, clientRect.bottom); + SelectObject(hdc, hbm); - buttonText = PhGetWindowText(DrawInfo->hdr.hwndFrom); + SetBkMode(hdc, TRANSPARENT); - if (isSelected) + if (!PhpTabControlFontHandle) { - switch (PhGetIntegerSetting(L"GraphColorMode")) - { - case 0: // New colors - //SetTextColor(DrawInfo->hdc, RGB(0, 0, 0xff)); - SetDCBrushColor(DrawInfo->hdc, GetSysColor(COLOR_HIGHLIGHT)); - break; - case 1: // Old colors - SetTextColor(DrawInfo->hdc, GetSysColor(COLOR_HIGHLIGHTTEXT)); - SetDCBrushColor(DrawInfo->hdc, RGB(78, 78, 78)); - break; - } + NONCLIENTMETRICS metrics = { sizeof(NONCLIENTMETRICS) }; - FillRect(DrawInfo->hdc, &DrawInfo->rc, GetStockObject(DC_BRUSH)); - } - else if (isHighlighted) - { - switch (PhGetIntegerSetting(L"GraphColorMode")) + if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, &metrics, 0)) { - case 0: // New colors - //SetTextColor(DrawInfo->hdc, RGB(0, 0, 0xff)); - SetDCBrushColor(DrawInfo->hdc, GetSysColor(COLOR_HIGHLIGHT)); - break; - case 1: // Old colors - SetTextColor(DrawInfo->hdc, GetSysColor(COLOR_HIGHLIGHTTEXT)); - SetDCBrushColor(DrawInfo->hdc, RGB(65, 65, 65)); - break; + PhpTabControlFontHandle = CreateFontIndirect(&metrics.lfMessageFont); } - - FillRect(DrawInfo->hdc, &DrawInfo->rc, GetStockObject(DC_BRUSH)); } - else + + SelectFont(hdc, PhpTabControlFontHandle); + + switch (PhGetIntegerSetting(L"GraphColorMode")) { - switch (PhGetIntegerSetting(L"GraphColorMode")) - { - case 0: // New colors - //SetTextColor(DrawInfo->hdc, RGB(0x0, 0x0, 0x0)); - //SetDCBrushColor(DrawInfo->hdc, GetSysColor(COLOR_3DFACE)); - //FillRect(DrawInfo->hdc, &DrawInfo->rc, GetStockObject(DC_BRUSH)); - break; - case 1: // Old colors - SetTextColor(DrawInfo->hdc, PhpThemeWindowTextColor); - SetDCBrushColor(DrawInfo->hdc, RGB(42, 42, 42)); // WindowForegroundColor - FillRect(DrawInfo->hdc, &DrawInfo->rc, GetStockObject(DC_BRUSH)); - break; - } + case 0: // New colors + //SetTextColor(hdc, RGB(0x0, 0xff, 0x0)); + SetDCBrushColor(hdc, PhpThemeWindowTextColor); + FillRect(hdc, &clientRect, GetStockObject(DC_BRUSH)); + break; + case 1: // Old colors + //SetTextColor(hdc, PhpThemeWindowTextColor); + SetDCBrushColor(hdc, RGB(65, 65, 65)); //WindowForegroundColor); // RGB(65, 65, 65)); + FillRect(hdc, &clientRect, GetStockObject(DC_BRUSH)); + break; } + - if ((GetWindowLongPtr(DrawInfo->hdr.hwndFrom, GWL_STYLE) & BS_CHECKBOX) != 0) + INT count = TabCtrl_GetItemCount(WindowHandle); + for (INT i = 0; i < count; i++) { - HFONT newFont = PhDuplicateFontWithNewHeight(PhApplicationFont, 22); - oldFont = SelectFont(DrawInfo->hdc, newFont); - - if (Button_GetCheck(DrawInfo->hdr.hwndFrom) == BST_CHECKED) - { - DrawText( - DrawInfo->hdc, - L"\u2611", - -1, - &DrawInfo->rc, - DT_LEFT | DT_SINGLELINE | DT_VCENTER - ); - } - else - { - DrawText( - DrawInfo->hdc, - L"\u2610", - -1, - &DrawInfo->rc, - DT_LEFT | DT_SINGLELINE | DT_VCENTER - ); - } + TabCtrl_GetItemRect(WindowHandle, i, &itemRect); + TabCtrl_GetItem(WindowHandle, i, &tcItem); - SelectFont(DrawInfo->hdc, oldFont); - DeleteFont(newFont); + POINT pt; + GetCursorPos(&pt); + MapWindowPoints(NULL, WindowHandle, &pt, 1); - DrawInfo->rc.left += 10; - DrawText( - DrawInfo->hdc, - buttonText->Buffer, - (UINT)buttonText->Length / sizeof(WCHAR), - &DrawInfo->rc, - DT_CENTER | DT_SINGLELINE | DT_VCENTER | DT_HIDEPREFIX - ); - DrawInfo->rc.left -= 10; - } - else - { - RECT bufferRect = + if (PtInRect(&itemRect, pt)) { - 0, 0, - DrawInfo->rc.right - DrawInfo->rc.left, - DrawInfo->rc.bottom - DrawInfo->rc.top - }; - HICON buttonIcon; + OffsetRect(&itemRect, 2, 2); - if (!(buttonIcon = Static_GetIcon(DrawInfo->hdr.hwndFrom, 0))) - { - buttonIcon = (HICON)SendMessage(DrawInfo->hdr.hwndFrom, BM_GETIMAGE, IMAGE_ICON, 0); - } + switch (PhGetIntegerSetting(L"GraphColorMode")) + { + case 0: // New colors + { + if (TabCtrl_GetCurSel(WindowHandle) == i) + { + SetDCBrushColor(hdc, RGB(128, 128, 128)); + FillRect(hdc, &itemRect, GetStockObject(DC_BRUSH)); + } + else + { + //SetTextColor(hdc, PhpThemeWindowTextColor); + SetDCBrushColor(hdc, PhpThemeWindowTextColor); + FillRect(hdc, &itemRect, GetStockObject(DC_BRUSH)); + } + } + break; + case 1: // Old colors + SetTextColor(hdc, PhpThemeWindowTextColor); + SetDCBrushColor(hdc, RGB(128, 128, 128)); + FillRect(hdc, &itemRect, GetStockObject(DC_BRUSH)); + break; + } - if (buttonIcon) - { - DrawIconEx( - DrawInfo->hdc, - bufferRect.left + ((bufferRect.right - bufferRect.left) - 16) / 2, - bufferRect.top + ((bufferRect.bottom - bufferRect.top) - 16 ) / 2, - buttonIcon, - 16, - 16, - 0, - NULL, - DI_NORMAL - ); + //FrameRect(hdc, &itemRect, GetSysColorBrush(COLOR_HIGHLIGHT)); } else { - DrawText( - DrawInfo->hdc, - buttonText->Buffer, - (UINT)buttonText->Length / sizeof(WCHAR), - &DrawInfo->rc, - DT_CENTER | DT_SINGLELINE | DT_VCENTER | DT_HIDEPREFIX - ); + OffsetRect(&itemRect, 2, 2); + + switch (PhGetIntegerSetting(L"GraphColorMode")) + { + case 0: // New colors + { + if (TabCtrl_GetCurSel(WindowHandle) == i) + { + SetDCBrushColor(hdc, RGB(128, 128, 128)); + FillRect(hdc, &itemRect, GetStockObject(DC_BRUSH)); + } + else + { + //SetTextColor(hdc, PhpThemeWindowTextColor); + SetDCBrushColor(hdc, PhpThemeWindowTextColor); + FillRect(hdc, &itemRect, GetStockObject(DC_BRUSH)); + } + } + break; + case 1: // Old colors + { + if (TabCtrl_GetCurSel(WindowHandle) == i) + { + SetTextColor(hdc, PhpThemeWindowTextColor); + SetDCBrushColor(hdc, PhpThemeWindowForegroundColor); + FillRect(hdc, &itemRect, GetStockObject(DC_BRUSH)); + } + else + { + SetTextColor(hdc, PhpThemeWindowTextColor); + SetDCBrushColor(hdc, PhpThemeWindowBackgroundColor); + FillRect(hdc, &itemRect, GetStockObject(DC_BRUSH)); + } + } + break; + } } + + DrawText( + hdc, + tcItem.pszText, + -1, + &itemRect, + DT_CENTER | DT_VCENTER | DT_SINGLELINE | DT_HIDEPREFIX //| DT_WORD_ELLIPSIS + ); } - PhDereferenceObject(buttonText); - } + DeleteDC(hdcTab); - return CDRF_SKIPDEFAULT; + BitBlt(ps.hdc, 0, 0, clientRect.right, clientRect.bottom, hdc, 0, 0, SRCCOPY); + + DeleteDC(hdc); + DeleteObject(hbm); + EndPaint(WindowHandle, &ps); + + InvalidateRect(WindowHandle, NULL, FALSE); // HACK + } + return DefWindowProc(WindowHandle, uMsg, wParam, lParam); } - return CDRF_DODEFAULT; + return CallWindowProc(oldWndProc, WindowHandle, uMsg, wParam, lParam); } -LRESULT PhThemeWindowDrawRebar( - _In_ LPNMCUSTOMDRAW DrawInfo +LRESULT CALLBACK PhpThemeWindowHeaderSubclassProc( + _In_ HWND WindowHandle, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam ) { - switch (DrawInfo->dwDrawStage) + PPHP_THEME_WINDOW_HEADER_CONTEXT context; + WNDPROC oldWndProc; + + if (!(context = PhGetWindowContext(WindowHandle, SHRT_MAX))) + return FALSE; + + oldWndProc = context->DefaultWindowProc; + + switch (uMsg) { - case CDDS_PREPAINT: + case WM_NCDESTROY: { - switch (PhGetIntegerSetting(L"GraphColorMode")) - { - case 0: // New colors - SetTextColor(DrawInfo->hdc, RGB(0x0, 0x0, 0x0)); - SetDCBrushColor(DrawInfo->hdc, RGB(0xff, 0xff, 0xff)); - break; - case 1: // Old colors - SetTextColor(DrawInfo->hdc, RGB(0xff, 0xff, 0xff)); - SetDCBrushColor(DrawInfo->hdc, RGB(65, 65, 65)); - break; - } + PhRemoveWindowContext(WindowHandle, SHRT_MAX); + SetWindowLongPtr(WindowHandle, GWLP_WNDPROC, (LONG_PTR)oldWndProc); - FillRect(DrawInfo->hdc, &DrawInfo->rc, GetStockObject(DC_BRUSH)); + PhFree(context); } - return CDRF_NOTIFYITEMDRAW; - case CDDS_ITEMPREPAINT: + break; + //case WM_ERASEBKGND: + // return 1; + case WM_MOUSEMOVE: { - switch (PhGetIntegerSetting(L"GraphColorMode")) + //POINT pt; + //RECT rcItem; + //TCITEM tcItem; + //tcItem.mask = TCIF_STATE; + //tcItem.dwStateMask = TCIS_HIGHLIGHTED; + //GetCursorPos(&pt); + //MapWindowPoints(NULL, WindowHandle, &pt, 1); + //int nCount = TabCtrl_GetItemCount(WindowHandle); + //for (int i = 0; i < nCount; i++) + //{ + // TabCtrl_GetItemRect(WindowHandle, i, &rcItem); + // tcItem.dwState = PtInRect(&rcItem, pt) ? TCIS_HIGHLIGHTED : 0; + // TabCtrl_SetItem(WindowHandle, i, &tcItem); + //} + + if (!context->MouseActive) { - case 0: // New colors - SetTextColor(DrawInfo->hdc, RGB(0x0, 0x0, 0x0)); - SetDCBrushColor(DrawInfo->hdc, RGB(0x0, 0x0, 0x0)); - case 1: // Old colors - SetTextColor(DrawInfo->hdc, RGB(0xff, 0xff, 0xff)); - SetDCBrushColor(DrawInfo->hdc, RGB(65, 65, 65)); - break; + TRACKMOUSEEVENT trackEvent = + { + sizeof(TRACKMOUSEEVENT), + TME_LEAVE, + WindowHandle, + 0 + }; + + TrackMouseEvent(&trackEvent); + context->MouseActive = TRUE; } - FillRect(DrawInfo->hdc, &DrawInfo->rc, GetStockObject(DC_BRUSH)); + InvalidateRect(WindowHandle, NULL, FALSE); } - return CDRF_SKIPDEFAULT; - } + break; + case WM_CONTEXTMENU: + { + LRESULT result = DefSubclassProc(WindowHandle, uMsg, wParam, lParam); - return CDRF_DODEFAULT; -} + InvalidateRect(WindowHandle, NULL, TRUE); -LRESULT PhThemeWindowDrawToolbar( - _In_ LPNMTBCUSTOMDRAW DrawInfo - ) -{ - switch (DrawInfo->nmcd.dwDrawStage) - { - case CDDS_PREPAINT: - return CDRF_NOTIFYITEMDRAW | CDRF_NOTIFYPOSTPAINT; - case CDDS_ITEMPREPAINT: + return result; + } + break; + case WM_MOUSELEAVE: { - TBBUTTONINFO buttonInfo = - { - sizeof(TBBUTTONINFO), - TBIF_STYLE | TBIF_COMMAND | TBIF_STATE | TBIF_IMAGE - }; + // TCITEM tcItem = { TCIF_STATE, 0, TCIS_HIGHLIGHTED }; + //// int nCount = TabCtrl_GetItemCount(WindowHandle); + // for (int i = 0; i < nCount; i++) + // { + // //TabCtrl_SetItem(WindowHandle, i, &tcItem); + // } - SetBkMode(DrawInfo->nmcd.hdc, TRANSPARENT); + InvalidateRect(WindowHandle, NULL, TRUE); + context->MouseActive = FALSE; + } + break; + case WM_PAINT: + { + //HTHEME hTheme = OpenThemeData(WindowHandle, L"HEADER"); + WCHAR szText[MAX_PATH + 1]; + RECT rcClient; + HDITEM tcItem; + PAINTSTRUCT ps; - ULONG currentIndex = (ULONG)SendMessage( - DrawInfo->nmcd.hdr.hwndFrom, - TB_COMMANDTOINDEX, - DrawInfo->nmcd.dwItemSpec, - 0 - ); - BOOLEAN isHighlighted = SendMessage( - DrawInfo->nmcd.hdr.hwndFrom, - TB_GETHOTITEM, - 0, - 0 - ) == currentIndex; - BOOLEAN isMouseDown = SendMessage( - DrawInfo->nmcd.hdr.hwndFrom, - TB_ISBUTTONPRESSED, - DrawInfo->nmcd.dwItemSpec, - 0 - ) == 0; + //InvalidateRect(WindowHandle, NULL, FALSE); + BeginPaint(WindowHandle, &ps); - //if (isMouseDown) - //{ - // SetTextColor(DrawInfo->nmcd.hdc, RGB(0xff, 0xff, 0xff)); - // SetDCBrushColor(DrawInfo->nmcd.hdc, RGB(0xff, 0xff, 0xff)); - // FillRect(DrawInfo->nmcd.hdc, &DrawInfo->nmcd.rc, GetStockObject(DC_BRUSH)); - //} + GetClientRect(WindowHandle, &rcClient); - if (isHighlighted) - { - switch (PhGetIntegerSetting(L"GraphColorMode")) - { - case 0: // New colors - SetTextColor(DrawInfo->nmcd.hdc, RGB(0x0, 0x0, 0x0)); - SetDCBrushColor(DrawInfo->nmcd.hdc, RGB(0xff, 0xff, 0xff)); - FillRect(DrawInfo->nmcd.hdc, &DrawInfo->nmcd.rc, GetStockObject(DC_BRUSH)); - break; - case 1: // Old colors - SetTextColor(DrawInfo->nmcd.hdc, RGB(0xff, 0xff, 0xff)); - SetDCBrushColor(DrawInfo->nmcd.hdc, RGB(128, 128, 128)); - FillRect(DrawInfo->nmcd.hdc, &DrawInfo->nmcd.rc, GetStockObject(DC_BRUSH)); - break; - } - } - else - { - switch (PhGetIntegerSetting(L"GraphColorMode")) - { - case 0: // New colors - SetTextColor(DrawInfo->nmcd.hdc, RGB(0x0, 0x0, 0x0)); - SetDCBrushColor(DrawInfo->nmcd.hdc, RGB(0xff, 0xff, 0xff)); - FillRect(DrawInfo->nmcd.hdc, &DrawInfo->nmcd.rc, GetStockObject(DC_BRUSH)); - break; - case 1: // Old colors - SetTextColor(DrawInfo->nmcd.hdc, RGB(0xff, 0xff, 0xff)); - SetDCBrushColor(DrawInfo->nmcd.hdc, RGB(65, 65, 65)); //RGB(28, 28, 28)); // RGB(65, 65, 65)); - FillRect(DrawInfo->nmcd.hdc, &DrawInfo->nmcd.rc, GetStockObject(DC_BRUSH)); - break; - } - } + ZeroMemory(&tcItem, sizeof(tcItem)); + tcItem.mask = HDI_TEXT | HDI_IMAGE | HDI_STATE; + tcItem.pszText = szText; + tcItem.cchTextMax = MAX_PATH; - if (!PhpToolBarFontHandle) - { - NONCLIENTMETRICS metrics = { sizeof(NONCLIENTMETRICS) }; + HDC hdc = CreateCompatibleDC(ps.hdc); + HBITMAP hbm = CreateCompatibleBitmap(ps.hdc, rcClient.right, rcClient.bottom); + SelectObject(hdc, hbm); + + if (!PhpHeaderFontHandle) + { + NONCLIENTMETRICS metrics = { sizeof(metrics) }; if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, &metrics, 0)) { - PhpToolBarFontHandle = CreateFontIndirect(&metrics.lfMessageFont); + PhpHeaderFontHandle = CreateFontIndirect(&metrics.lfMessageFont); } } + SelectFont(hdc, PhpHeaderFontHandle); - SelectObject(DrawInfo->nmcd.hdc, PhpToolBarFontHandle); - + SetBkMode(hdc, TRANSPARENT); - if (SendMessage( - DrawInfo->nmcd.hdr.hwndFrom, - TB_GETBUTTONINFO, - (ULONG)DrawInfo->nmcd.dwItemSpec, - (LPARAM)&buttonInfo - ) == -1) + switch (PhGetIntegerSetting(L"GraphColorMode")) { + case 0: // New colors + SetTextColor(hdc, RGB(0x0, 0x0, 0x0)); + SetDCBrushColor(hdc, PhpThemeWindowTextColor); + FillRect(hdc, &rcClient, GetStockObject(DC_BRUSH)); + break; + case 1: // Old colors + SetTextColor(hdc, PhpThemeWindowTextColor); + SetDCBrushColor(hdc, RGB(65, 65, 65)); //WindowForegroundColor); // RGB(65, 65, 65)); + FillRect(hdc, &rcClient, GetStockObject(DC_BRUSH)); break; } - if (buttonInfo.iImage != -1) + HDC hdcTab = CreateCompatibleDC(hdc); + + INT nCount = Header_GetItemCount(WindowHandle); + for (INT i = 0; i < nCount; i++) { - HIMAGELIST toolbarImageList; + RECT headerRect; + POINT pt; - if (toolbarImageList = (HIMAGELIST)SendMessage( - DrawInfo->nmcd.hdr.hwndFrom, - TB_GETIMAGELIST, - 0, - 0 - )) + Header_GetItemRect(WindowHandle, i, &headerRect); + Header_GetItem(WindowHandle, i, &tcItem); + + GetCursorPos(&pt); + MapWindowPoints(NULL, WindowHandle, &pt, 1); + + if (PtInRect(&headerRect, pt)) { - DrawInfo->nmcd.rc.left += 5; + switch (PhGetIntegerSetting(L"GraphColorMode")) + { + case 0: // New colors + SetTextColor(hdc, PhpThemeWindowTextColor); + SetDCBrushColor(hdc, PhpThemeWindowBackgroundColor); + FillRect(hdc, &headerRect, GetStockObject(DC_BRUSH)); + break; + case 1: // Old colors + SetTextColor(hdc, PhpThemeWindowTextColor); + SetDCBrushColor(hdc, RGB(128, 128, 128)); + FillRect(hdc, &headerRect, GetStockObject(DC_BRUSH)); + break; + } - ImageList_Draw( - toolbarImageList, - buttonInfo.iImage, - DrawInfo->nmcd.hdc, - DrawInfo->nmcd.rc.left, - DrawInfo->nmcd.rc.top + 3, - ILD_NORMAL - ); + //FrameRect(hdc, &headerRect, GetSysColorBrush(COLOR_HIGHLIGHT)); } - } - - if (buttonInfo.fsStyle & BTNS_SHOWTEXT) - { - WCHAR buttonText[0x100] = L""; + else + { + switch (PhGetIntegerSetting(L"GraphColorMode")) + { + case 0: // New colors + SetTextColor(hdc, RGB(0x0, 0x0, 0x0)); + SetDCBrushColor(hdc, PhpThemeWindowTextColor); + FillRect(hdc, &headerRect, GetStockObject(DC_BRUSH)); + break; + case 1: // Old colors + SetTextColor(hdc, PhpThemeWindowTextColor); + SetDCBrushColor(hdc, PhpThemeWindowBackgroundColor); + FillRect(hdc, &headerRect, GetStockObject(DC_BRUSH)); + break; + } - SendMessage( - DrawInfo->nmcd.hdr.hwndFrom, - TB_GETBUTTONTEXT, - (ULONG)DrawInfo->nmcd.dwItemSpec, - (LPARAM)buttonText - ); + //FrameRect(hdc, &headerRect, GetSysColorBrush(COLOR_HIGHLIGHT)); + } - DrawInfo->nmcd.rc.left += 10; DrawText( - DrawInfo->nmcd.hdc, - buttonText, + hdc, + tcItem.pszText, -1, - &DrawInfo->nmcd.rc, - DT_CENTER | DT_VCENTER | DT_SINGLELINE | DT_HIDEPREFIX + &headerRect, + DT_VCENTER | DT_CENTER | DT_SINGLELINE | DT_HIDEPREFIX ); } - //DrawInfo->clrText = RGB(0x0, 0xff, 0); - //return TBCDRF_USECDCOLORS | CDRF_NEWFONT; + DeleteDC(hdcTab); + + BitBlt(ps.hdc, 0, 0, rcClient.right, rcClient.bottom, hdc, 0, 0, SRCCOPY); + + DeleteDC(hdc); + DeleteObject(hbm); + EndPaint(WindowHandle, &ps); } - return CDRF_SKIPDEFAULT; + + return DefWindowProc(WindowHandle, uMsg, wParam, lParam); } - return CDRF_DODEFAULT; + return CallWindowProc(oldWndProc, WindowHandle, uMsg, wParam, lParam); } -LRESULT PhpThemeWindowDrawListViewGroup( - _In_ LPNMLVCUSTOMDRAW DrawInfo +LRESULT CALLBACK PhpThemeWindowStatusbarWndSubclassProc( + _In_ HWND WindowHandle, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam ) { - switch (DrawInfo->nmcd.dwDrawStage) + PPHP_THEME_WINDOW_STATUSBAR_CONTEXT context; + WNDPROC oldWndProc; + + if (!(context = PhGetWindowContext(WindowHandle, SHRT_MAX))) + return FALSE; + + oldWndProc = context->DefaultWindowProc; + + switch (uMsg) { - case CDDS_PREPAINT: + case WM_NCDESTROY: { - SetBkMode(DrawInfo->nmcd.hdc, TRANSPARENT); + PhRemoveWindowContext(WindowHandle, SHRT_MAX); + SetWindowLongPtr(WindowHandle, GWLP_WNDPROC, (LONG_PTR)oldWndProc); + + PhFree(context); + } + break; + case WM_ERASEBKGND: + return FALSE; + case WM_MOUSEMOVE: + { + if (!context->MouseActive) + { + TRACKMOUSEEVENT trackEvent = + { + sizeof(TRACKMOUSEEVENT), + TME_LEAVE, + WindowHandle, + 0 + }; + + TrackMouseEvent(&trackEvent); + context->MouseActive = TRUE; + } + + InvalidateRect(WindowHandle, NULL, FALSE); + } + break; + case WM_MOUSELEAVE: + { + InvalidateRect(WindowHandle, NULL, FALSE); + context->MouseActive = FALSE; + } + break; + case WM_PAINT: + { + RECT rcClient; + PAINTSTRUCT ps; + INT blockCoord[128]; + INT blockCount = (INT)SendMessage(WindowHandle, (UINT)SB_GETPARTS, (WPARAM)ARRAYSIZE(blockCoord), (WPARAM)blockCoord); + + // InvalidateRect(WindowHandle, NULL, FALSE); + BeginPaint(WindowHandle, &ps); + GetClientRect(WindowHandle, &rcClient); + + HDC hdc = CreateCompatibleDC(ps.hdc); + HBITMAP hbm = CreateCompatibleBitmap(ps.hdc, rcClient.right, rcClient.bottom); + SelectObject(hdc, hbm); + + SetBkMode(hdc, TRANSPARENT); + + if (!PhpStatusBarFontHandle) + { + NONCLIENTMETRICS metrics = { sizeof(NONCLIENTMETRICS) }; + + if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, &metrics, 0)) + { + PhpStatusBarFontHandle = CreateFontIndirect(&metrics.lfMessageFont); + } + } + + SelectFont(hdc, PhpStatusBarFontHandle); switch (PhGetIntegerSetting(L"GraphColorMode")) { case 0: // New colors - SetTextColor(DrawInfo->nmcd.hdc, RGB(0x0, 0x0, 0x0)); - SetDCBrushColor(DrawInfo->nmcd.hdc, PhpThemeWindowTextColor); - //FillRect(DrawInfo->nmcd.hdc, &DrawInfo->nmcd.rc, GetStockObject(DC_BRUSH)); + SetTextColor(hdc, RGB(0x0, 0x0, 0x0)); + SetDCBrushColor(hdc, RGB(0xff, 0xff, 0xff)); + FillRect(hdc, &rcClient, GetStockObject(DC_BRUSH)); break; case 1: // Old colors - SetTextColor(DrawInfo->nmcd.hdc, RGB(0x0, 0x0, 0x0)); - SetDCBrushColor(DrawInfo->nmcd.hdc, RGB(128, 128, 128)); - //FillRect(DrawInfo->nmcd.hdc, &DrawInfo->nmcd.rc, GetStockObject(DC_BRUSH)); + SetTextColor(hdc, RGB(0xff, 0xff, 0xff)); + SetDCBrushColor(hdc, RGB(65, 65, 65)); //RGB(28, 28, 28)); // RGB(65, 65, 65)); + FillRect(hdc, &rcClient, GetStockObject(DC_BRUSH)); break; } - if (!PhpListViewFontHandle) + for (INT i = 0; i < blockCount; i++) { - NONCLIENTMETRICS metrics = { sizeof(NONCLIENTMETRICS) }; + RECT blockRect = { 0, 0, 0, 0 }; + WCHAR buffer[MAX_PATH] = L""; - if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, &metrics, 0)) - { - metrics.lfMessageFont.lfHeight = -11; - metrics.lfMessageFont.lfWeight = FW_BOLD; + if (!SendMessage(WindowHandle, SB_GETRECT, (WPARAM)i, (WPARAM)&blockRect)) + continue; - PhpListViewFontHandle = CreateFontIndirect(&metrics.lfMessageFont); + SendMessage(WindowHandle, SB_GETTEXT, (WPARAM)i, (LPARAM)buffer); + + POINT pt; + GetCursorPos(&pt); + MapWindowPoints(NULL, WindowHandle, &pt, 1); + + if (PtInRect(&blockRect, pt)) + { + switch (PhGetIntegerSetting(L"GraphColorMode")) + { + case 0: // New colors + SetTextColor(hdc, RGB(0x0, 0x0, 0x0)); + SetDCBrushColor(hdc, RGB(0xff, 0xff, 0xff)); + FillRect(hdc, &blockRect, GetStockObject(DC_BRUSH)); + //FrameRect(hdc, &blockRect, GetSysColorBrush(COLOR_HIGHLIGHT)); + break; + case 1: // Old colors + SetTextColor(hdc, RGB(0xff, 0xff, 0xff)); + SetDCBrushColor(hdc, RGB(128, 128, 128)); + FillRect(hdc, &blockRect, GetStockObject(DC_BRUSH)); + //FrameRect(hdc, &blockRect, GetSysColorBrush(COLOR_HIGHLIGHT)); + break; + } + } + else + { + switch (PhGetIntegerSetting(L"GraphColorMode")) + { + case 0: // New colors + SetTextColor(hdc, RGB(0x0, 0x0, 0x0)); + SetDCBrushColor(hdc, RGB(0xff, 0xff, 0xff)); + FillRect(hdc, &blockRect, GetStockObject(DC_BRUSH)); + //FrameRect(hdc, &blockRect, GetSysColorBrush(COLOR_HIGHLIGHT)); + break; + case 1: // Old colors + SetTextColor(hdc, RGB(0xff, 0xff, 0xff)); + SetDCBrushColor(hdc, RGB(64, 64, 64)); + FillRect(hdc, &blockRect, GetStockObject(DC_BRUSH)); + //FrameRect(hdc, &blockRect, GetSysColorBrush(COLOR_HIGHLIGHT)); + break; + } } + + DrawText( + hdc, + buffer, + -1, + &blockRect, + DT_CENTER | DT_VCENTER | DT_SINGLELINE | DT_HIDEPREFIX + ); } - SelectObject(DrawInfo->nmcd.hdc, PhpListViewFontHandle); - LVGROUP groupInfo = { sizeof(LVGROUP) }; - groupInfo.mask = LVGF_HEADER; - if (ListView_GetGroupInfo( - DrawInfo->nmcd.hdr.hwndFrom, - (ULONG)DrawInfo->nmcd.dwItemSpec, - &groupInfo - ) == -1) { - break; - } + RECT sizeGripRect; - SetTextColor(DrawInfo->nmcd.hdc, RGB(255, 69, 0)); - SetDCBrushColor(DrawInfo->nmcd.hdc, RGB(65, 65, 65)); + GetClientRect(WindowHandle, &sizeGripRect); - DrawInfo->rcText.top += 2; - DrawInfo->rcText.bottom -= 2; - FillRect(DrawInfo->nmcd.hdc, &DrawInfo->rcText, GetStockObject(DC_BRUSH)); - DrawInfo->rcText.top -= 2; - DrawInfo->rcText.bottom += 2; + sizeGripRect.left = sizeGripRect.right - GetSystemMetrics(SM_CXHSCROLL); + sizeGripRect.top = sizeGripRect.bottom - GetSystemMetrics(SM_CYVSCROLL); - SetTextColor(DrawInfo->nmcd.hdc, RGB(255, 69, 0)); - SetDCBrushColor(DrawInfo->nmcd.hdc, RGB(65, 65, 65)); + if (context->StatusThemeData) + DrawThemeBackground(context->StatusThemeData, hdc, SP_GRIPPER, 0, &sizeGripRect, &sizeGripRect); + else + DrawFrameControl(hdc, &sizeGripRect, DFC_SCROLL, DFCS_SCROLLSIZEGRIP); + } - DrawInfo->rcText.left += 10; - DrawText( - DrawInfo->nmcd.hdc, - groupInfo.pszHeader, - -1, - &DrawInfo->rcText, - DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_HIDEPREFIX - ); - DrawInfo->rcText.left -= 10; + BitBlt(ps.hdc, 0, 0, rcClient.right, rcClient.bottom, hdc, 0, 0, SRCCOPY); + + DeleteDC(hdc); + DeleteObject(hbm); + EndPaint(WindowHandle, &ps); } - return CDRF_SKIPDEFAULT; + + return DefWindowProc(WindowHandle, uMsg, wParam, lParam); } - return CDRF_DODEFAULT; -} \ No newline at end of file + return CallWindowProc(oldWndProc, WindowHandle, uMsg, wParam, lParam); +} From 50c7801abf1ae8968f46f2e300e96dd5f5cc8837 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 26 Jul 2018 13:18:18 +1000 Subject: [PATCH 1220/2058] Fix plugin error message --- ProcessHacker/plugin.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ProcessHacker/plugin.c b/ProcessHacker/plugin.c index bc55f5501745..f686d8d7639b 100644 --- a/ProcessHacker/plugin.c +++ b/ProcessHacker/plugin.c @@ -340,6 +340,9 @@ VOID PhLoadPlugins( PhDereferenceObject(baseName); } + if (PhEndsWithStringRef2(&stringBuilder.String->sr, L"\n", FALSE)) + PhRemoveEndStringBuilder(&stringBuilder, 2); + config.dwFlags = TDF_ALLOW_DIALOG_CANCELLATION; config.dwCommonButtons = TDCBF_CANCEL_BUTTON; config.pszWindowTitle = PhApplicationName; From 28fce7bc661ae40d4042bffb04bf33b8cbcbd5ff Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 26 Jul 2018 16:49:17 +1000 Subject: [PATCH 1221/2058] Add StatusBar theme support --- ProcessHacker/ProcessHacker.def | 3 +++ ProcessHacker/sysinfo.c | 3 --- phlib/include/guisup.h | 7 +++++++ phlib/theme.c | 12 ++++++------ plugins/ToolStatus/toolbar.c | 7 +++++-- 5 files changed, 21 insertions(+), 11 deletions(-) diff --git a/ProcessHacker/ProcessHacker.def b/ProcessHacker/ProcessHacker.def index 5be4bccf13a1..b6c57736547b 100644 --- a/ProcessHacker/ProcessHacker.def +++ b/ProcessHacker/ProcessHacker.def @@ -525,8 +525,11 @@ EXPORTS PhSetDialogItemText PhApplicationFont PhTreeWindowFont + PhRegisterWindowCallback + PhUnregisterWindowCallback PhInitializeWindowTheme PhReInitializeWindowTheme + PhInitializeWindowThemeStatusBar ; hndlinfo PhEnumObjectTypes diff --git a/ProcessHacker/sysinfo.c b/ProcessHacker/sysinfo.c index d0df050a3d05..81afd4b51ddb 100644 --- a/ProcessHacker/sysinfo.c +++ b/ProcessHacker/sysinfo.c @@ -347,7 +347,6 @@ VOID PhSipOnInitDialog( ); PhSipUpdateThemeData(); - PhInitializeWindowTheme(ContainerControl, PhEnableThemeSupport); if (SectionList) // TODO: Remove (dmex) { @@ -1177,8 +1176,6 @@ PPH_SYSINFO_SECTION PhSipCreateSection( PhInstanceHandle, NULL ); - - PhInitializeWindowTheme(section->PanelHandle, PhEnableThemeSupport); section->GraphWindowProc = (WNDPROC)GetWindowLongPtr(section->GraphHandle, GWLP_WNDPROC); section->PanelWindowProc = (WNDPROC)GetWindowLongPtr(section->PanelHandle, GWLP_WNDPROC); diff --git a/phlib/include/guisup.h b/phlib/include/guisup.h index c0b11b8b0b28..83040f102180 100644 --- a/phlib/include/guisup.h +++ b/phlib/include/guisup.h @@ -914,6 +914,13 @@ PhReInitializeWindowTheme( _In_ HWND WindowHandle ); +PHLIBAPI +VOID +NTAPI +PhInitializeWindowThemeStatusBar( + _In_ HWND StatusBarHandle + ); + FORCEINLINE HFONT PhDuplicateFontWithNewHeight( diff --git a/phlib/theme.c b/phlib/theme.c index 706ef2095a6c..16751e2b0085 100644 --- a/phlib/theme.c +++ b/phlib/theme.c @@ -308,8 +308,8 @@ BOOLEAN CALLBACK PhpThemeWindowEnumChildWindows( } else if (PhEqualStringZ(windowClassName, L"SysListView32", FALSE)) { - PhSetWindowStyle(WindowHandle, WS_BORDER, 0); - PhSetWindowExStyle(WindowHandle, WS_EX_CLIENTEDGE, 0); + //PhSetWindowStyle(WindowHandle, WS_BORDER, 0); + //PhSetWindowExStyle(WindowHandle, WS_EX_CLIENTEDGE, 0); switch (PhGetIntegerSetting(L"GraphColorMode")) { @@ -347,12 +347,12 @@ BOOLEAN CALLBACK PhpThemeWindowEnumChildWindows( switch (PhGetIntegerSetting(L"GraphColorMode")) { case 0: // New colors - PhSetWindowStyle(WindowHandle, WS_BORDER, WS_BORDER); - PhSetWindowExStyle(WindowHandle, WS_EX_CLIENTEDGE, WS_EX_CLIENTEDGE); + //PhSetWindowStyle(WindowHandle, WS_BORDER, WS_BORDER); + //PhSetWindowExStyle(WindowHandle, WS_EX_CLIENTEDGE, WS_EX_CLIENTEDGE); break; case 1: // Old colors - PhSetWindowStyle(WindowHandle, WS_BORDER, 0); - PhSetWindowExStyle(WindowHandle, WS_EX_CLIENTEDGE, 0); + //PhSetWindowStyle(WindowHandle, WS_BORDER, 0); + //PhSetWindowExStyle(WindowHandle, WS_EX_CLIENTEDGE, 0); break; } diff --git a/plugins/ToolStatus/toolbar.c b/plugins/ToolStatus/toolbar.c index 68c375b3226a..e790bb63844a 100644 --- a/plugins/ToolStatus/toolbar.c +++ b/plugins/ToolStatus/toolbar.c @@ -188,7 +188,7 @@ VOID RebarLoadSettings( )) { PhCreateSearchControl(RebarHandle, SearchboxHandle, L"Search Processes (Ctrl+K)"); - //SendMessage(SearchboxHandle, WM_SETFONT, (WPARAM)ToolStatusWindowFont, TRUE); + PhRegisterWindowCallback(SearchboxHandle, PH_PLUGIN_WINDOW_EVENT_TYPE_FONT, NULL); } } @@ -208,7 +208,10 @@ VOID RebarLoadSettings( if (StatusBarHandle) { - SendMessage(StatusBarHandle, WM_SETFONT, (WPARAM)ToolStatusWindowFont, FALSE); + PhRegisterWindowCallback(StatusBarHandle, PH_PLUGIN_WINDOW_EVENT_TYPE_FONT, NULL); + + if (PhGetIntegerSetting(L"EnableThemeSupport")) + PhInitializeWindowThemeStatusBar(StatusBarHandle); } } From abb43bd230236f264efe0200994d9272eab63386 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 27 Jul 2018 01:33:26 +1000 Subject: [PATCH 1222/2058] Fix changing treenew theme --- phlib/theme.c | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/phlib/theme.c b/phlib/theme.c index 16751e2b0085..c9c7d3e47826 100644 --- a/phlib/theme.c +++ b/phlib/theme.c @@ -349,14 +349,14 @@ BOOLEAN CALLBACK PhpThemeWindowEnumChildWindows( case 0: // New colors //PhSetWindowStyle(WindowHandle, WS_BORDER, WS_BORDER); //PhSetWindowExStyle(WindowHandle, WS_EX_CLIENTEDGE, WS_EX_CLIENTEDGE); + TreeNew_ThemeSupport(WindowHandle, FALSE); break; case 1: // Old colors //PhSetWindowStyle(WindowHandle, WS_BORDER, 0); //PhSetWindowExStyle(WindowHandle, WS_EX_CLIENTEDGE, 0); + TreeNew_ThemeSupport(WindowHandle, TRUE); break; } - - TreeNew_ThemeSupport(WindowHandle, TRUE); } else if (PhEqualStringZ(windowClassName, L"ScrollBar", FALSE)) { @@ -372,6 +372,7 @@ BOOLEAN CALLBACK PhpReInitializeThemeWindowEnumChildWindows( ) { ULONG processID = 0; + WCHAR windowClassName[MAX_PATH]; PhEnumChildWindows( WindowHandle, @@ -380,6 +381,26 @@ BOOLEAN CALLBACK PhpReInitializeThemeWindowEnumChildWindows( 0 ); + if (!GetClassName(WindowHandle, windowClassName, RTL_NUMBER_OF(windowClassName))) + windowClassName[0] = 0; + + if (PhEqualStringZ(windowClassName, L"PhTreeNew", FALSE)) + { + switch (PhGetIntegerSetting(L"GraphColorMode")) + { + case 0: // New colors + //PhSetWindowStyle(WindowHandle, WS_BORDER, WS_BORDER); + //PhSetWindowExStyle(WindowHandle, WS_EX_CLIENTEDGE, WS_EX_CLIENTEDGE); + TreeNew_ThemeSupport(WindowHandle, FALSE); + break; + case 1: // Old colors + //PhSetWindowStyle(WindowHandle, WS_BORDER, 0); + //PhSetWindowExStyle(WindowHandle, WS_EX_CLIENTEDGE, 0); + TreeNew_ThemeSupport(WindowHandle, TRUE); + break; + } + } + GetWindowThreadProcessId(WindowHandle, &processID); if (UlongToHandle(processID) == NtCurrentProcessId()) From ce7326cba02e6dd0cf484f29c02609ef62fa59a8 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 27 Jul 2018 15:46:45 +1000 Subject: [PATCH 1223/2058] Add toolbar theme support, Update light theme --- phlib/theme.c | 172 +++++++++++++++++--------------------- plugins/ToolStatus/main.c | 6 +- 2 files changed, 81 insertions(+), 97 deletions(-) diff --git a/phlib/theme.c b/phlib/theme.c index c9c7d3e47826..d9a3f0dab35b 100644 --- a/phlib/theme.c +++ b/phlib/theme.c @@ -194,7 +194,7 @@ VOID PhInitializeThemeWindowTabControl( if (!PhpTabControlFontHandle) { PhpTabControlFontHandle = CreateFont( - -(LONG)PhMultiplyDivide(15, PhGlobalDpi, 96), + -PhMultiplyDivideSigned(-14, PhGlobalDpi, 96), 0, 0, 0, @@ -371,7 +371,6 @@ BOOLEAN CALLBACK PhpReInitializeThemeWindowEnumChildWindows( _In_opt_ PVOID Context ) { - ULONG processID = 0; WCHAR windowClassName[MAX_PATH]; PhEnumChildWindows( @@ -389,24 +388,15 @@ BOOLEAN CALLBACK PhpReInitializeThemeWindowEnumChildWindows( switch (PhGetIntegerSetting(L"GraphColorMode")) { case 0: // New colors - //PhSetWindowStyle(WindowHandle, WS_BORDER, WS_BORDER); - //PhSetWindowExStyle(WindowHandle, WS_EX_CLIENTEDGE, WS_EX_CLIENTEDGE); TreeNew_ThemeSupport(WindowHandle, FALSE); break; case 1: // Old colors - //PhSetWindowStyle(WindowHandle, WS_BORDER, 0); - //PhSetWindowExStyle(WindowHandle, WS_EX_CLIENTEDGE, 0); TreeNew_ThemeSupport(WindowHandle, TRUE); break; } } - GetWindowThreadProcessId(WindowHandle, &processID); - - if (UlongToHandle(processID) == NtCurrentProcessId()) - { - InvalidateRect(WindowHandle, NULL, FALSE); - } + InvalidateRect(WindowHandle, NULL, FALSE); return TRUE; } @@ -650,6 +640,16 @@ LRESULT CALLBACK PhThemeWindowDrawToolbar( 0 ) == 0; + if (SendMessage( + DrawInfo->nmcd.hdr.hwndFrom, + TB_GETBUTTONINFO, + (ULONG)DrawInfo->nmcd.dwItemSpec, + (LPARAM)&buttonInfo + ) == -1) + { + break; + } + //if (isMouseDown) //{ // SetTextColor(DrawInfo->nmcd.hdc, RGB(0xff, 0xff, 0xff)); @@ -662,8 +662,8 @@ LRESULT CALLBACK PhThemeWindowDrawToolbar( switch (PhGetIntegerSetting(L"GraphColorMode")) { case 0: // New colors - SetTextColor(DrawInfo->nmcd.hdc, RGB(0x0, 0x0, 0x0)); - SetDCBrushColor(DrawInfo->nmcd.hdc, RGB(0xff, 0xff, 0xff)); + SetTextColor(DrawInfo->nmcd.hdc, PhpThemeWindowTextColor); + SetDCBrushColor(DrawInfo->nmcd.hdc, PhpThemeWindowBackgroundColor); FillRect(DrawInfo->nmcd.hdc, &DrawInfo->nmcd.rc, GetStockObject(DC_BRUSH)); break; case 1: // Old colors @@ -703,15 +703,7 @@ LRESULT CALLBACK PhThemeWindowDrawToolbar( SelectFont(DrawInfo->nmcd.hdc, PhpToolBarFontHandle); - if (SendMessage( - DrawInfo->nmcd.hdr.hwndFrom, - TB_GETBUTTONINFO, - (ULONG)DrawInfo->nmcd.dwItemSpec, - (LPARAM)&buttonInfo - ) == -1) - { - break; - } + if (buttonInfo.iImage != -1) { @@ -887,11 +879,11 @@ LRESULT CALLBACK PhpThemeWindowSubclassProc( } else if (PhEqualStringZ(className, L"ReBarWindow32", FALSE)) { - NOTHING; + return PhThemeWindowDrawRebar(customDraw); } else if (PhEqualStringZ(className, L"ToolbarWindow32", FALSE)) { - NOTHING; + return PhThemeWindowDrawToolbar((LPNMTBCUSTOMDRAW)customDraw); } else if (PhEqualStringZ(className, L"SysTabControl32", FALSE)) { @@ -1153,19 +1145,11 @@ LRESULT CALLBACK PhpThemeWindowTabControlWndSubclassProc( case WM_PAINT: { RECT clientRect, itemRect; - TCITEMW tcItem; PAINTSTRUCT ps; - WCHAR szText[MAX_PATH]; - + BeginPaint(WindowHandle, &ps); - GetClientRect(WindowHandle, &clientRect); - ZeroMemory(&tcItem, sizeof(TCITEMW)); - tcItem.mask = TCIF_TEXT | TCIF_IMAGE | TCIF_STATE; - tcItem.dwStateMask = TCIS_BUTTONPRESSED | TCIS_HIGHLIGHTED; - tcItem.pszText = szText; - tcItem.cchTextMax = MAX_PATH; RECT rcSpin = clientRect; HWND hWndSpin = GetDlgItem(WindowHandle, 1); @@ -1181,20 +1165,10 @@ LRESULT CALLBACK PhpThemeWindowTabControlWndSubclassProc( HDC hdc = CreateCompatibleDC(ps.hdc); HDC hdcTab = CreateCompatibleDC(hdc); HBITMAP hbm = CreateCompatibleBitmap(ps.hdc, clientRect.right, clientRect.bottom); - SelectObject(hdc, hbm); + SelectBitmap(hdc, hbm); SetBkMode(hdc, TRANSPARENT); - if (!PhpTabControlFontHandle) - { - NONCLIENTMETRICS metrics = { sizeof(NONCLIENTMETRICS) }; - - if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, &metrics, 0)) - { - PhpTabControlFontHandle = CreateFontIndirect(&metrics.lfMessageFont); - } - } - SelectFont(hdc, PhpTabControlFontHandle); switch (PhGetIntegerSetting(L"GraphColorMode")) @@ -1211,16 +1185,14 @@ LRESULT CALLBACK PhpThemeWindowTabControlWndSubclassProc( break; } + POINT pt; + GetCursorPos(&pt); + MapWindowPoints(NULL, WindowHandle, &pt, 1); INT count = TabCtrl_GetItemCount(WindowHandle); for (INT i = 0; i < count; i++) { TabCtrl_GetItemRect(WindowHandle, i, &itemRect); - TabCtrl_GetItem(WindowHandle, i, &tcItem); - - POINT pt; - GetCursorPos(&pt); - MapWindowPoints(NULL, WindowHandle, &pt, 1); if (PtInRect(&itemRect, pt)) { @@ -1232,13 +1204,14 @@ LRESULT CALLBACK PhpThemeWindowTabControlWndSubclassProc( { if (TabCtrl_GetCurSel(WindowHandle) == i) { + SetTextColor(hdc, RGB(0xff, 0xff, 0xff)); SetDCBrushColor(hdc, RGB(128, 128, 128)); FillRect(hdc, &itemRect, GetStockObject(DC_BRUSH)); } else { - //SetTextColor(hdc, PhpThemeWindowTextColor); - SetDCBrushColor(hdc, PhpThemeWindowTextColor); + SetTextColor(hdc, PhpThemeWindowTextColor); + SetDCBrushColor(hdc, PhpThemeWindowBackgroundColor); FillRect(hdc, &itemRect, GetStockObject(DC_BRUSH)); } } @@ -1262,12 +1235,13 @@ LRESULT CALLBACK PhpThemeWindowTabControlWndSubclassProc( { if (TabCtrl_GetCurSel(WindowHandle) == i) { + SetTextColor(hdc, RGB(0xff, 0xff, 0xff)); SetDCBrushColor(hdc, RGB(128, 128, 128)); FillRect(hdc, &itemRect, GetStockObject(DC_BRUSH)); } else { - //SetTextColor(hdc, PhpThemeWindowTextColor); + SetTextColor(hdc, RGB(0, 0, 0)); SetDCBrushColor(hdc, PhpThemeWindowTextColor); FillRect(hdc, &itemRect, GetStockObject(DC_BRUSH)); } @@ -1292,21 +1266,30 @@ LRESULT CALLBACK PhpThemeWindowTabControlWndSubclassProc( } } + WCHAR szText[MAX_PATH]; + + TCITEM entry; + ZeroMemory(&entry, sizeof(TCITEM)); + entry.mask = TCIF_TEXT | TCIF_IMAGE | TCIF_STATE; + entry.dwStateMask = TCIS_BUTTONPRESSED | TCIS_HIGHLIGHTED; + entry.pszText = szText; + entry.cchTextMax = MAX_PATH; + + TabCtrl_GetItem(WindowHandle, i, &entry); DrawText( hdc, - tcItem.pszText, + entry.pszText, -1, &itemRect, - DT_CENTER | DT_VCENTER | DT_SINGLELINE | DT_HIDEPREFIX //| DT_WORD_ELLIPSIS + DT_CENTER | DT_VCENTER | DT_SINGLELINE | DT_HIDEPREFIX ); } - DeleteDC(hdcTab); - BitBlt(ps.hdc, 0, 0, clientRect.right, clientRect.bottom, hdc, 0, 0, SRCCOPY); + DeleteDC(hdcTab); DeleteDC(hdc); - DeleteObject(hbm); + DeleteBitmap(hbm); EndPaint(WindowHandle, &ps); InvalidateRect(WindowHandle, NULL, FALSE); // HACK @@ -1403,25 +1386,19 @@ LRESULT CALLBACK PhpThemeWindowHeaderSubclassProc( case WM_PAINT: { //HTHEME hTheme = OpenThemeData(WindowHandle, L"HEADER"); - WCHAR szText[MAX_PATH + 1]; - RECT rcClient; + WCHAR szText[MAX_PATH]; + RECT clientRect; HDITEM tcItem; PAINTSTRUCT ps; //InvalidateRect(WindowHandle, NULL, FALSE); BeginPaint(WindowHandle, &ps); - - GetClientRect(WindowHandle, &rcClient); - - ZeroMemory(&tcItem, sizeof(tcItem)); - tcItem.mask = HDI_TEXT | HDI_IMAGE | HDI_STATE; - tcItem.pszText = szText; - tcItem.cchTextMax = MAX_PATH; + GetClientRect(WindowHandle, &clientRect); HDC hdc = CreateCompatibleDC(ps.hdc); - HBITMAP hbm = CreateCompatibleBitmap(ps.hdc, rcClient.right, rcClient.bottom); - - SelectObject(hdc, hbm); + HDC hdcTab = CreateCompatibleDC(hdc); + HBITMAP hbm = CreateCompatibleBitmap(ps.hdc, clientRect.right, clientRect.bottom); + SelectBitmap(hdc, hbm); if (!PhpHeaderFontHandle) { @@ -1440,25 +1417,23 @@ LRESULT CALLBACK PhpThemeWindowHeaderSubclassProc( case 0: // New colors SetTextColor(hdc, RGB(0x0, 0x0, 0x0)); SetDCBrushColor(hdc, PhpThemeWindowTextColor); - FillRect(hdc, &rcClient, GetStockObject(DC_BRUSH)); + FillRect(hdc, &clientRect, GetStockObject(DC_BRUSH)); break; case 1: // Old colors SetTextColor(hdc, PhpThemeWindowTextColor); SetDCBrushColor(hdc, RGB(65, 65, 65)); //WindowForegroundColor); // RGB(65, 65, 65)); - FillRect(hdc, &rcClient, GetStockObject(DC_BRUSH)); + FillRect(hdc, &clientRect, GetStockObject(DC_BRUSH)); break; } - HDC hdcTab = CreateCompatibleDC(hdc); - INT nCount = Header_GetItemCount(WindowHandle); + for (INT i = 0; i < nCount; i++) { RECT headerRect; POINT pt; Header_GetItemRect(WindowHandle, i, &headerRect); - Header_GetItem(WindowHandle, i, &tcItem); GetCursorPos(&pt); MapWindowPoints(NULL, WindowHandle, &pt, 1); @@ -1500,6 +1475,13 @@ LRESULT CALLBACK PhpThemeWindowHeaderSubclassProc( //FrameRect(hdc, &headerRect, GetSysColorBrush(COLOR_HIGHLIGHT)); } + ZeroMemory(&tcItem, sizeof(HDITEM)); + tcItem.mask = HDI_TEXT | HDI_IMAGE | HDI_STATE; + tcItem.pszText = szText; + tcItem.cchTextMax = MAX_PATH; + + Header_GetItem(WindowHandle, i, &tcItem); + DrawText( hdc, tcItem.pszText, @@ -1509,12 +1491,11 @@ LRESULT CALLBACK PhpThemeWindowHeaderSubclassProc( ); } - DeleteDC(hdcTab); - - BitBlt(ps.hdc, 0, 0, rcClient.right, rcClient.bottom, hdc, 0, 0, SRCCOPY); + BitBlt(ps.hdc, 0, 0, clientRect.right, clientRect.bottom, hdc, 0, 0, SRCCOPY); + DeleteDC(hdcTab); DeleteDC(hdc); - DeleteObject(hbm); + DeleteBitmap(hbm); EndPaint(WindowHandle, &ps); } @@ -1578,18 +1559,18 @@ LRESULT CALLBACK PhpThemeWindowStatusbarWndSubclassProc( break; case WM_PAINT: { - RECT rcClient; + RECT clientRect; PAINTSTRUCT ps; INT blockCoord[128]; INT blockCount = (INT)SendMessage(WindowHandle, (UINT)SB_GETPARTS, (WPARAM)ARRAYSIZE(blockCoord), (WPARAM)blockCoord); // InvalidateRect(WindowHandle, NULL, FALSE); BeginPaint(WindowHandle, &ps); - GetClientRect(WindowHandle, &rcClient); + GetClientRect(WindowHandle, &clientRect); HDC hdc = CreateCompatibleDC(ps.hdc); - HBITMAP hbm = CreateCompatibleBitmap(ps.hdc, rcClient.right, rcClient.bottom); - SelectObject(hdc, hbm); + HBITMAP hbm = CreateCompatibleBitmap(ps.hdc, clientRect.right, clientRect.bottom); + SelectBitmap(hdc, hbm); SetBkMode(hdc, TRANSPARENT); @@ -1610,12 +1591,12 @@ LRESULT CALLBACK PhpThemeWindowStatusbarWndSubclassProc( case 0: // New colors SetTextColor(hdc, RGB(0x0, 0x0, 0x0)); SetDCBrushColor(hdc, RGB(0xff, 0xff, 0xff)); - FillRect(hdc, &rcClient, GetStockObject(DC_BRUSH)); + FillRect(hdc, &clientRect, GetStockObject(DC_BRUSH)); break; case 1: // Old colors SetTextColor(hdc, RGB(0xff, 0xff, 0xff)); SetDCBrushColor(hdc, RGB(65, 65, 65)); //RGB(28, 28, 28)); // RGB(65, 65, 65)); - FillRect(hdc, &rcClient, GetStockObject(DC_BRUSH)); + FillRect(hdc, &clientRect, GetStockObject(DC_BRUSH)); break; } @@ -1626,8 +1607,8 @@ LRESULT CALLBACK PhpThemeWindowStatusbarWndSubclassProc( if (!SendMessage(WindowHandle, SB_GETRECT, (WPARAM)i, (WPARAM)&blockRect)) continue; - - SendMessage(WindowHandle, SB_GETTEXT, (WPARAM)i, (LPARAM)buffer); + if (!SendMessage(WindowHandle, SB_GETTEXT, (WPARAM)i, (LPARAM)buffer)) + continue; POINT pt; GetCursorPos(&pt); @@ -1638,10 +1619,9 @@ LRESULT CALLBACK PhpThemeWindowStatusbarWndSubclassProc( switch (PhGetIntegerSetting(L"GraphColorMode")) { case 0: // New colors - SetTextColor(hdc, RGB(0x0, 0x0, 0x0)); - SetDCBrushColor(hdc, RGB(0xff, 0xff, 0xff)); + SetTextColor(hdc, PhpThemeWindowTextColor); + SetDCBrushColor(hdc, PhpThemeWindowBackgroundColor); FillRect(hdc, &blockRect, GetStockObject(DC_BRUSH)); - //FrameRect(hdc, &blockRect, GetSysColorBrush(COLOR_HIGHLIGHT)); break; case 1: // Old colors SetTextColor(hdc, RGB(0xff, 0xff, 0xff)); @@ -1682,10 +1662,10 @@ LRESULT CALLBACK PhpThemeWindowStatusbarWndSubclassProc( { RECT sizeGripRect; - GetClientRect(WindowHandle, &sizeGripRect); - - sizeGripRect.left = sizeGripRect.right - GetSystemMetrics(SM_CXHSCROLL); - sizeGripRect.top = sizeGripRect.bottom - GetSystemMetrics(SM_CYVSCROLL); + sizeGripRect.left = clientRect.right - GetSystemMetrics(SM_CXHSCROLL); + sizeGripRect.top = clientRect.bottom - GetSystemMetrics(SM_CYVSCROLL); + sizeGripRect.right = clientRect.right; + sizeGripRect.bottom = clientRect.bottom; if (context->StatusThemeData) DrawThemeBackground(context->StatusThemeData, hdc, SP_GRIPPER, 0, &sizeGripRect, &sizeGripRect); @@ -1693,10 +1673,10 @@ LRESULT CALLBACK PhpThemeWindowStatusbarWndSubclassProc( DrawFrameControl(hdc, &sizeGripRect, DFC_SCROLL, DFCS_SCROLLSIZEGRIP); } - BitBlt(ps.hdc, 0, 0, rcClient.right, rcClient.bottom, hdc, 0, 0, SRCCOPY); + BitBlt(ps.hdc, 0, 0, clientRect.right, clientRect.bottom, hdc, 0, 0, SRCCOPY); DeleteDC(hdc); - DeleteObject(hbm); + DeleteBitmap(hbm); EndPaint(WindowHandle, &ps); } diff --git a/plugins/ToolStatus/main.c b/plugins/ToolStatus/main.c index 891e7d7eb9ee..def71184d29a 100644 --- a/plugins/ToolStatus/main.c +++ b/plugins/ToolStatus/main.c @@ -754,7 +754,7 @@ LRESULT CALLBACK MainWndSubclassProc( CallWindowProc(MainWindowHookProc, hWnd, uMsg, wParam, lParam); // Query the settings. - BOOLEAN isAlwaysOnTopEnabled = (BOOLEAN)PhGetIntegerSetting(L"MainWindowAlwaysOnTop"); + BOOLEAN isAlwaysOnTopEnabled = !!PhGetIntegerSetting(L"MainWindowAlwaysOnTop"); // Set the pressed button state. SendMessage(ToolBarHandle, TB_PRESSBUTTON, (WPARAM)PHAPP_ID_VIEW_ALWAYSONTOP, (LPARAM)(MAKELONG(isAlwaysOnTopEnabled, 0))); @@ -929,6 +929,8 @@ LRESULT CALLBACK MainWndSubclassProc( ReBarSaveLayoutSettings(); } break; + case NM_CUSTOMDRAW: + return CallWindowProc(MainWindowHookProc, hWnd, uMsg, wParam, lParam); // HACK } goto DefaultWndProc; @@ -1079,6 +1081,8 @@ LRESULT CALLBACK MainWndSubclassProc( ShowCustomizeMenu(); } break; + case NM_CUSTOMDRAW: + return CallWindowProc(MainWindowHookProc, hWnd, uMsg, wParam, lParam); // HACK } goto DefaultWndProc; From 0c9083c12f245c01400392fa86bca7a9b9aa32f3 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 31 Jul 2018 11:50:07 +1000 Subject: [PATCH 1224/2058] Fix default colors and fonts --- ProcessHacker/options.c | 30 +++++++++++++++++++++++++++--- ProcessHacker/prpgenv.c | 2 -- ProcessHacker/prpgmem.c | 3 --- ProcessHacker/prpgmod.c | 3 --- ProcessHacker/prpgstat.c | 3 --- ProcessHacker/prpgthrd.c | 3 --- ProcessHacker/sysinfo.c | 25 +++++++++++++++---------- phlib/guisup.c | 24 ------------------------ phlib/include/guisup.h | 18 +++++------------- plugins/ToolStatus/toolbar.c | 8 ++------ 10 files changed, 49 insertions(+), 70 deletions(-) diff --git a/ProcessHacker/options.c b/ProcessHacker/options.c index 210a6efd9a54..a8f4ad9ce2ef 100644 --- a/ProcessHacker/options.c +++ b/ProcessHacker/options.c @@ -320,8 +320,10 @@ INT_PTR CALLBACK PhOptionsDialogProc( PhOptionsOnSize(); } - PhCenterWindow(hwndDlg, PhMainWndHandle); - PhLoadWindowPlacementFromSetting(L"OptionsWindowPosition", L"OptionsWindowSize", hwndDlg); + if (PhGetIntegerPairSetting(L"OptionsWindowPosition").X) + PhLoadWindowPlacementFromSetting(L"OptionsWindowPosition", L"OptionsWindowSize", hwndDlg); + else + PhCenterWindow(hwndDlg, PhMainWndHandle); } break; case WM_DESTROY: @@ -1182,6 +1184,27 @@ static NTSTATUS PhpElevateAdvancedThreadStart( return STATUS_SUCCESS; } +UINT_PTR CALLBACK PhpChooseFontDlgHookProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + switch (uMsg) + { + case WM_INITDIALOG: + { + PhCenterWindow(hwndDlg, PhOptionsWindowHandle); + + PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport); + } + break; + } + + return FALSE; +} + INT_PTR CALLBACK PhpOptionsGeneralDlgProc( _In_ HWND hwndDlg, _In_ UINT uMsg, @@ -1291,8 +1314,9 @@ INT_PTR CALLBACK PhpOptionsGeneralDlgProc( memset(&chooseFont, 0, sizeof(CHOOSEFONT)); chooseFont.lStructSize = sizeof(CHOOSEFONT); chooseFont.hwndOwner = hwndDlg; + chooseFont.lpfnHook = PhpChooseFontDlgHookProc; chooseFont.lpLogFont = &font; - chooseFont.Flags = CF_FORCEFONTEXIST | CF_INITTOLOGFONTSTRUCT | CF_SCREENFONTS; + chooseFont.Flags = CF_FORCEFONTEXIST | CF_INITTOLOGFONTSTRUCT | CF_ENABLEHOOK | CF_SCREENFONTS; if (ChooseFont(&chooseFont)) { diff --git a/ProcessHacker/prpgenv.c b/ProcessHacker/prpgenv.c index 32b1c65da2fe..c0231f9861ed 100644 --- a/ProcessHacker/prpgenv.c +++ b/ProcessHacker/prpgenv.c @@ -1257,7 +1257,6 @@ INT_PTR CALLBACK PhpProcessEnvironmentDlgProc( PhInitializeArray(&context->Items, sizeof(PH_ENVIRONMENT_ITEM), 100); context->TreeFilterEntry = PhAddTreeNewFilter(&context->TreeFilterSupport, PhpProcessEnvironmentTreeFilterCallback, context); - PhRegisterWindowCallback(context->TreeNewHandle, PH_PLUGIN_WINDOW_EVENT_TYPE_FONT, NULL); PhMoveReference(&context->StatusMessage, PhCreateString(L"There are no environment variables to display.")); TreeNew_SetEmptyText(context->TreeNewHandle, &context->StatusMessage->sr, 0); @@ -1270,7 +1269,6 @@ INT_PTR CALLBACK PhpProcessEnvironmentDlgProc( break; case WM_DESTROY: { - PhUnregisterWindowCallback(context->TreeNewHandle); PhSaveSettingsEnvironmentList(context); PhpDeleteEnvironmentTree(context); diff --git a/ProcessHacker/prpgmem.c b/ProcessHacker/prpgmem.c index 5908bb22dab8..509016ff2758 100644 --- a/ProcessHacker/prpgmem.c +++ b/ProcessHacker/prpgmem.c @@ -340,7 +340,6 @@ INT_PTR CALLBACK PhpProcessMemoryDlgProc( BringWindowToTop(tnHandle); PhInitializeMemoryList(hwndDlg, tnHandle, &memoryContext->ListContext); TreeNew_SetEmptyText(tnHandle, &PhpLoadingText, 0); - PhRegisterWindowCallback(tnHandle, PH_PLUGIN_WINDOW_EVENT_TYPE_FONT, NULL); memoryContext->LastRunStatus = -1; memoryContext->ErrorMessage = NULL; memoryContext->SearchboxText = PhReferenceEmptyString(); @@ -368,8 +367,6 @@ INT_PTR CALLBACK PhpProcessMemoryDlgProc( break; case WM_DESTROY: { - PhUnregisterWindowCallback(tnHandle); - PhEmCallObjectOperation(EmMemoryContextType, memoryContext, EmObjectDelete); if (PhPluginsEnabled) diff --git a/ProcessHacker/prpgmod.c b/ProcessHacker/prpgmod.c index bd6239edf151..5fcdc255bd59 100644 --- a/ProcessHacker/prpgmod.c +++ b/ProcessHacker/prpgmod.c @@ -478,7 +478,6 @@ INT_PTR CALLBACK PhpProcessModulesDlgProc( modulesContext->ErrorMessage = NULL; modulesContext->SearchboxText = PhReferenceEmptyString(); modulesContext->FilterEntry = PhAddTreeNewFilter(&modulesContext->ListContext.TreeFilterSupport, PhpModulesTreeFilterCallback, modulesContext); - PhRegisterWindowCallback(tnHandle, PH_PLUGIN_WINDOW_EVENT_TYPE_FONT, NULL); PhEmCallObjectOperation(EmModulesContextType, modulesContext, EmObjectCreate); @@ -502,8 +501,6 @@ INT_PTR CALLBACK PhpProcessModulesDlgProc( break; case WM_DESTROY: { - PhUnregisterWindowCallback(tnHandle); - PhEmCallObjectOperation(EmModulesContextType, modulesContext, EmObjectDelete); PhUnregisterCallback( diff --git a/ProcessHacker/prpgstat.c b/ProcessHacker/prpgstat.c index 526ba9aea218..215e139570fc 100644 --- a/ProcessHacker/prpgstat.c +++ b/ProcessHacker/prpgstat.c @@ -317,7 +317,6 @@ INT_PTR CALLBACK PhpProcessStatisticsDlgProc( PhAddListViewColumn(statisticsContext->ListViewHandle, 0, 0, 0, LVCFMT_LEFT, 135, L"Property"); PhAddListViewColumn(statisticsContext->ListViewHandle, 1, 1, 1, LVCFMT_LEFT, 150, L"Value"); PhSetExtendedListView(statisticsContext->ListViewHandle); - PhRegisterWindowCallback(statisticsContext->ListViewHandle, PH_PLUGIN_WINDOW_EVENT_TYPE_FONT, NULL); PhpUpdateStatisticsAddListViewGroups(statisticsContext->ListViewHandle); @@ -335,8 +334,6 @@ INT_PTR CALLBACK PhpProcessStatisticsDlgProc( break; case WM_DESTROY: { - PhUnregisterWindowCallback(statisticsContext->ListViewHandle); - PhUnregisterCallback( PhGetGeneralCallback(GeneralCallbackProcessProviderUpdatedEvent), &statisticsContext->ProcessesUpdatedRegistration diff --git a/ProcessHacker/prpgthrd.c b/ProcessHacker/prpgthrd.c index f7a766f50d7e..82352767a5ca 100644 --- a/ProcessHacker/prpgthrd.c +++ b/ProcessHacker/prpgthrd.c @@ -557,7 +557,6 @@ INT_PTR CALLBACK PhpProcessThreadsDlgProc( PhInitializeThreadList(hwndDlg, tnHandle, &threadsContext->ListContext); TreeNew_SetEmptyText(tnHandle, &EmptyThreadsText, 0); PhInitializeProviderEventQueue(&threadsContext->EventQueue, 100); - PhRegisterWindowCallback(tnHandle, PH_PLUGIN_WINDOW_EVENT_TYPE_FONT, NULL); // Use Cycles instead of Context Switches on Vista and above, but only when we can // open the process, since cycle time information requires sufficient access to the // threads. @@ -618,8 +617,6 @@ INT_PTR CALLBACK PhpProcessThreadsDlgProc( break; case WM_DESTROY: { - PhUnregisterWindowCallback(tnHandle); - PhEmCallObjectOperation(EmThreadsContextType, threadsContext, EmObjectDelete); PhUnregisterCallback( diff --git a/ProcessHacker/sysinfo.c b/ProcessHacker/sysinfo.c index 81afd4b51ddb..7c0253af6292 100644 --- a/ProcessHacker/sysinfo.c +++ b/ProcessHacker/sysinfo.c @@ -295,21 +295,26 @@ INT_PTR CALLBACK PhSipContainerDialogProc( case WM_CTLCOLORDLG: case WM_CTLCOLORSTATIC: { - if (!PhEnableThemeSupport) - break; - SetBkMode((HDC)wParam, TRANSPARENT); - switch (PhCsGraphColorMode) + if (PhEnableThemeSupport) + { + switch (PhCsGraphColorMode) + { + case 0: // New colors + SetTextColor((HDC)wParam, RGB(0x0, 0x0, 0x0)); + SetDCBrushColor((HDC)wParam, GetSysColor(COLOR_WINDOW)); + break; + case 1: // Old colors + SetTextColor((HDC)wParam, RGB(0xff, 0xff, 0xff)); + SetDCBrushColor((HDC)wParam, RGB(30, 30, 30)); + break; + } + } + else { - case 0: // New colors SetTextColor((HDC)wParam, RGB(0x0, 0x0, 0x0)); SetDCBrushColor((HDC)wParam, GetSysColor(COLOR_WINDOW)); - break; - case 1: // Old colors - SetTextColor((HDC)wParam, RGB(0xff, 0xff, 0xff)); - SetDCBrushColor((HDC)wParam, RGB(30, 30, 30)); - break; } return (INT_PTR)GetStockObject(DC_BRUSH); diff --git a/phlib/guisup.c b/phlib/guisup.c index 8d52ab2d7087..9afb0611cafe 100644 --- a/phlib/guisup.c +++ b/phlib/guisup.c @@ -1588,9 +1588,6 @@ VOID PhRegisterWindowCallback( if (PhGetIntegerSetting(L"MainWindowAlwaysOnTop")) PhSetWindowAlwaysOnTop(WindowHandle, TRUE); break; - case PH_PLUGIN_WINDOW_EVENT_TYPE_FONT: - SendMessage(WindowHandle, WM_SETFONT, (WPARAM)PhTreeWindowFont, TRUE); - break; } PhAcquireQueuedLockExclusive(&WindowCallbackListLock); @@ -1646,24 +1643,3 @@ VOID PhWindowNotifyTopMostEvent( PhReleaseQueuedLockExclusive(&WindowCallbackListLock); } - -VOID PhWindowNotifyFontUpdateEvent( - _In_ HFONT FontHandle - ) -{ - PPH_PLUGIN_WINDOW_CALLBACK_REGISTRATION *entry; - ULONG i = 0; - - PhAcquireQueuedLockExclusive(&WindowCallbackListLock); - - while (PhEnumHashtable(WindowCallbackHashTable, (PVOID*)&entry, &i)) - { - if ((*entry)->Type & PH_PLUGIN_WINDOW_EVENT_TYPE_FONT) - { - SendMessage((*entry)->WindowHandle, WM_SETFONT, (WPARAM)FontHandle, TRUE); - InvalidateRect((*entry)->WindowHandle, NULL, TRUE); // HACK - } - } - - PhReleaseQueuedLockExclusive(&WindowCallbackListLock); -} diff --git a/phlib/include/guisup.h b/phlib/include/guisup.h index 83040f102180..f8f2de1f3f70 100644 --- a/phlib/include/guisup.h +++ b/phlib/include/guisup.h @@ -832,14 +832,13 @@ PhMakeColorBrighter( return RGB(r, g, b); } -// Window plugin support +// Window support typedef enum _PH_PLUGIN_WINDOW_EVENT_TYPE { - PH_PLUGIN_WINDOW_EVENT_TYPE_NONE = 0, - PH_PLUGIN_WINDOW_EVENT_TYPE_TOPMOST = 1, - PH_PLUGIN_WINDOW_EVENT_TYPE_FONT = 2, - PH_PLUGIN_WINDOW_EVENT_TYPE_MAX = 4 + PH_PLUGIN_WINDOW_EVENT_TYPE_NONE, + PH_PLUGIN_WINDOW_EVENT_TYPE_TOPMOST, + PH_PLUGIN_WINDOW_EVENT_TYPE_MAX } PH_PLUGIN_WINDOW_EVENT_TYPE; typedef struct _PH_PLUGIN_WINDOW_CALLBACK_REGISTRATION @@ -854,7 +853,7 @@ typedef struct _PH_PLUGIN_WINDOW_NOTIFY_EVENT union { BOOLEAN TopMost; - HFONT FontHandle; + //HFONT FontHandle; }; } PH_PLUGIN_WINDOW_NOTIFY_EVENT, *PPH_PLUGIN_WINDOW_NOTIFY_EVENT; @@ -887,13 +886,6 @@ PhWindowNotifyTopMostEvent( _In_ BOOLEAN TopMost ); -PHLIBAPI -VOID -NTAPI -PhWindowNotifyFontUpdateEvent( - _In_ HFONT FontHandle - ); - // theme support (theme.c) PHLIBAPI extern HFONT PhApplicationFont; // phapppub diff --git a/plugins/ToolStatus/toolbar.c b/plugins/ToolStatus/toolbar.c index e790bb63844a..d59a091ba407 100644 --- a/plugins/ToolStatus/toolbar.c +++ b/plugins/ToolStatus/toolbar.c @@ -188,7 +188,6 @@ VOID RebarLoadSettings( )) { PhCreateSearchControl(RebarHandle, SearchboxHandle, L"Search Processes (Ctrl+K)"); - PhRegisterWindowCallback(SearchboxHandle, PH_PLUGIN_WINDOW_EVENT_TYPE_FONT, NULL); } } @@ -206,12 +205,9 @@ VOID RebarLoadSettings( NULL ); - if (StatusBarHandle) + if (StatusBarHandle && PhGetIntegerSetting(L"EnableThemeSupport")) { - PhRegisterWindowCallback(StatusBarHandle, PH_PLUGIN_WINDOW_EVENT_TYPE_FONT, NULL); - - if (PhGetIntegerSetting(L"EnableThemeSupport")) - PhInitializeWindowThemeStatusBar(StatusBarHandle); + PhInitializeWindowThemeStatusBar(StatusBarHandle); } } From ea4f66b66366b5ede407aa8024c1bc3f86eda030 Mon Sep 17 00:00:00 2001 From: ge0rdi Date: Tue, 31 Jul 2018 04:16:21 +0200 Subject: [PATCH 1225/2058] Add .editorconfig file (#294) --- .editorconfig | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 000000000000..8926f7673208 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,7 @@ +root=true + +[*] +indent_style=space +indent_size=4 +trim_trailing_whitespace=true +insert_final_newline=true From 9bfa7d612f92eeb39edb70c54c4197bddf86f1d1 Mon Sep 17 00:00:00 2001 From: Gisle Vanem Date: Tue, 31 Jul 2018 04:17:11 +0200 Subject: [PATCH 1226/2058] Another 'uninitialized' warning from clang-cl (#292) --- KProcessHacker/vm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/KProcessHacker/vm.c b/KProcessHacker/vm.c index 63e4e2d0657c..32f0057a4089 100644 --- a/KProcessHacker/vm.c +++ b/KProcessHacker/vm.c @@ -323,7 +323,7 @@ NTSTATUS KpiReadVirtualMemoryUnsafe( { NTSTATUS status; PEPROCESS process; - SIZE_T numberOfBytesRead; + SIZE_T numberOfBytesRead = 0; PAGED_CODE(); From e2898d3126584d5ca7565a02fba65f9cba473864 Mon Sep 17 00:00:00 2001 From: dmex Date: Tue, 31 Jul 2018 13:05:43 +1000 Subject: [PATCH 1227/2058] Fix theme regressions --- ProcessHacker/anawait.c | 1 + ProcessHacker/chproc.c | 1 + ProcessHacker/hndlprp.c | 10 ++++++++-- ProcessHacker/hndlstat.c | 1 + ProcessHacker/mainwnd.c | 21 ++++++++++----------- 5 files changed, 21 insertions(+), 13 deletions(-) diff --git a/ProcessHacker/anawait.c b/ProcessHacker/anawait.c index f29fb8589f01..917147d77510 100644 --- a/ProcessHacker/anawait.c +++ b/ProcessHacker/anawait.c @@ -149,6 +149,7 @@ VOID PhUiAnalyzeWaitThread( return; } + memset(&context, 0, sizeof(ANALYZE_WAIT_CONTEXT)); context.ProcessId = ProcessId; context.ThreadId = ThreadId; diff --git a/ProcessHacker/chproc.c b/ProcessHacker/chproc.c index c29aeddd32e7..8dac71dd0d94 100644 --- a/ProcessHacker/chproc.c +++ b/ProcessHacker/chproc.c @@ -49,6 +49,7 @@ BOOLEAN PhShowChooseProcessDialog( { CHOOSE_PROCESS_DIALOG_CONTEXT context; + memset(&context, 0, sizeof(CHOOSE_PROCESS_DIALOG_CONTEXT)); context.Message = Message; context.ProcessId = NULL; diff --git a/ProcessHacker/hndlprp.c b/ProcessHacker/hndlprp.c index 74f77013a378..817a5e8b4557 100644 --- a/ProcessHacker/hndlprp.c +++ b/ProcessHacker/hndlprp.c @@ -155,11 +155,15 @@ NTSTATUS PhpShowHandlePropertiesThread( PROPSHEETPAGE propSheetPage; HPROPSHEETPAGE pages[16]; HANDLE_PROPERTIES_CONTEXT context; + PH_AUTO_POOL autoPool; context.ProcessId = handleContext->ProcessId; context.HandleItem = handleContext->HandleItem; + PhInitializeAutoPool(&autoPool); + propSheetHeader.dwFlags = + PSH_MODELESS | PSH_NOAPPLYNOW | PSH_NOCONTEXTHELP | PSH_PROPTITLE; @@ -258,6 +262,8 @@ NTSTATUS PhpShowHandlePropertiesThread( PhModalPropertySheet(&propSheetHeader); + PhDeleteAutoPool(&autoPool); + PhDereferenceObject(handleContext->HandleItem); PhFree(handleContext); @@ -926,7 +932,7 @@ INT_PTR CALLBACK PhpHandleGeneralDlgProc( // HACK if (PhGetIntegerPairSetting(L"HandlePropertiesWindowPosition").X != 0) - PhLoadWindowPlacementFromSetting(L"HandlePropertiesWindowPosition", L"HandlePropertiesWindowSize", GetParent(hwndDlg)); + PhLoadWindowPlacementFromSetting(L"HandlePropertiesWindowPosition", NULL, GetParent(hwndDlg)); else PhCenterWindow(GetParent(hwndDlg), GetParent(GetParent(hwndDlg))); // HACK @@ -941,7 +947,7 @@ INT_PTR CALLBACK PhpHandleGeneralDlgProc( break; case WM_DESTROY: { - PhSaveWindowPlacementToSetting(L"HandlePropertiesWindowPosition", L"HandlePropertiesWindowSize", GetParent(hwndDlg)); // HACK + PhSaveWindowPlacementToSetting(L"HandlePropertiesWindowPosition", NULL, GetParent(hwndDlg)); // HACK PhDeleteLayoutManager(&context->LayoutManager); diff --git a/ProcessHacker/hndlstat.c b/ProcessHacker/hndlstat.c index c299d533c01d..72d5b9501f66 100644 --- a/ProcessHacker/hndlstat.c +++ b/ProcessHacker/hndlstat.c @@ -56,6 +56,7 @@ VOID PhShowHandleStatisticsDialog( BOOLEAN filterNeeded; ULONG i; + memset(&context, 0, sizeof(HANDLE_STATISTICS_CONTEXT)); context.ProcessId = ProcessId; if (!NT_SUCCESS(status = PhOpenProcess( diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index f81eb2f6139e..d9a2aefd6012 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -58,18 +58,18 @@ #define RUNAS_MODE_ADMIN 1 #define RUNAS_MODE_LIMITED 2 -PHAPPAPI HWND PhMainWndHandle; +PHAPPAPI HWND PhMainWndHandle = NULL; BOOLEAN PhMainWndExiting = FALSE; BOOLEAN PhMainWndEarlyExit = FALSE; -HMENU PhMainWndMenuHandle; +HMENU PhMainWndMenuHandle = NULL; PH_PROVIDER_REGISTRATION PhMwpProcessProviderRegistration; PH_PROVIDER_REGISTRATION PhMwpServiceProviderRegistration; PH_PROVIDER_REGISTRATION PhMwpNetworkProviderRegistration; BOOLEAN PhMwpUpdateAutomatically = TRUE; -ULONG PhMwpNotifyIconNotifyMask; -ULONG PhMwpLastNotificationType; +ULONG PhMwpNotifyIconNotifyMask = 0; +ULONG PhMwpLastNotificationType = 0; PH_MWP_NOTIFICATION_DETAILS PhMwpLastNotificationDetails; static BOOLEAN NeedsMaximize = FALSE; @@ -80,16 +80,16 @@ static PH_CALLBACK_DECLARE(LayoutPaddingCallback); static RECT LayoutPadding = { 0, 0, 0, 0 }; static BOOLEAN LayoutPaddingValid = TRUE; -static HWND TabControlHandle; -static PPH_LIST PageList; -static PPH_MAIN_TAB_PAGE CurrentPage; -static INT OldTabIndex; +static HWND TabControlHandle = NULL; +static PPH_LIST PageList = NULL; +static PPH_MAIN_TAB_PAGE CurrentPage = NULL; +static INT OldTabIndex = 0; static HMENU SubMenuHandles[5]; static PPH_EMENU SubMenuObjects[5]; -static ULONG SelectedRunAsMode; -static ULONG SelectedUserSessionId; +static ULONG SelectedRunAsMode = ULONG_MAX; +static ULONG SelectedUserSessionId = ULONG_MAX; BOOLEAN PhMainWndInitialization( _In_ INT ShowCommand @@ -2059,7 +2059,6 @@ ULONG_PTR PhMwpOnUserMessage( PhTreeWindowFont = newFont; PhMwpNotifyAllPages(MainTabPageFontChanged, newFont, NULL); - PhWindowNotifyFontUpdateEvent(newFont); } } } From 49b3bae7d0aef133841dc4f565d9f6605ee1621c Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 1 Aug 2018 02:05:40 +1000 Subject: [PATCH 1228/2058] WindowExplorer: Add filename for window instance handle --- plugins/WindowExplorer/wndprp.c | 46 ++++++++++++++++++++++++++++++--- 1 file changed, 42 insertions(+), 4 deletions(-) diff --git a/plugins/WindowExplorer/wndprp.c b/plugins/WindowExplorer/wndprp.c index 8d19d487a161..de3d01958806 100644 --- a/plugins/WindowExplorer/wndprp.c +++ b/plugins/WindowExplorer/wndprp.c @@ -768,6 +768,17 @@ static VOID WepRefreshWindowGeneralInfo( WINDOWINFO windowInfo = { sizeof(WINDOWINFO) }; WINDOWPLACEMENT windowPlacement = { sizeof(WINDOWPLACEMENT) }; MONITORINFO monitorInfo = { sizeof(MONITORINFO) }; + HANDLE processHandle; + PPH_STRING fileName = NULL; + HMENU menuHandle; + PVOID instanceHandle; + PVOID userdataHandle; + ULONG windowId; + + menuHandle = GetMenu(Context->WindowHandle); + instanceHandle = (PVOID)GetWindowLongPtr(Context->WindowHandle, GWLP_HINSTANCE); + userdataHandle = (PVOID)GetWindowLongPtr(Context->WindowHandle, GWLP_USERDATA); + windowId = (ULONG)GetWindowLongPtr(Context->WindowHandle, GWLP_ID); PhSetDialogItemText(hwndDlg, IDC_THREAD, PH_AUTO_T(PH_STRING, PhGetClientIdName(&Context->ClientId))->Buffer); PhSetDialogItemText(hwndDlg, IDC_TEXT, PhGetStringOrEmpty(PH_AUTO(PhGetWindowText(Context->WindowHandle)))); @@ -801,11 +812,38 @@ static VOID WepRefreshWindowGeneralInfo( PhSetDialogItemText(hwndDlg, IDC_NORMALRECTANGLE, L"N/A"); } - PhSetDialogItemText(hwndDlg, IDC_INSTANCEHANDLE, PhaFormatString(L"0x%Ix", GetWindowLongPtr(Context->WindowHandle, GWLP_HINSTANCE))->Buffer); - PhSetDialogItemText(hwndDlg, IDC_MENUHANDLE, PhaFormatString(L"0x%Ix", GetMenu(Context->WindowHandle))->Buffer); - PhSetDialogItemText(hwndDlg, IDC_USERDATA, PhaFormatString(L"0x%Ix", GetWindowLongPtr(Context->WindowHandle, GWLP_USERDATA))->Buffer); + if (NT_SUCCESS(PhOpenProcess(&processHandle, *(PULONG)WeGetProcedureAddress("ProcessQueryAccess"), Context->ClientId.UniqueProcess))) + { + if (NT_SUCCESS(PhGetProcessMappedFileName(processHandle, instanceHandle, &fileName))) + { + PhMoveReference(&fileName, PhResolveDevicePrefix(fileName)); + PhMoveReference(&fileName, PhGetBaseName(fileName)); + } + + NtClose(processHandle); + } + + if (fileName) + { + PhSetDialogItemText(hwndDlg, IDC_INSTANCEHANDLE, PhaFormatString( + L"0x%Ix (%s)", + instanceHandle, + PhGetStringOrEmpty(fileName) + )->Buffer); + PhDereferenceObject(fileName); + } + else + { + PhSetDialogItemText(hwndDlg, IDC_INSTANCEHANDLE, PhaFormatString( + L"0x%Ix", + instanceHandle + )->Buffer); + } + + PhSetDialogItemText(hwndDlg, IDC_MENUHANDLE, PhaFormatString(L"0x%Ix", menuHandle)->Buffer); + PhSetDialogItemText(hwndDlg, IDC_USERDATA, PhaFormatString(L"0x%Ix", userdataHandle)->Buffer); PhSetDialogItemText(hwndDlg, IDC_UNICODE, IsWindowUnicode(Context->WindowHandle) ? L"Yes" : L"No"); - PhSetDialogItemText(hwndDlg, IDC_CTRLID, PhaFormatString(L"%lu", GetWindowLongPtr(Context->WindowHandle, GWLP_ID))->Buffer); + PhSetDialogItemText(hwndDlg, IDC_CTRLID, PhaFormatString(L"%lu", windowId)->Buffer); WepEnsureHookDataValid(Context); From 145aa430a40bfb39cddf849dd58ebd25854e2634 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 1 Aug 2018 02:20:21 +1000 Subject: [PATCH 1229/2058] Fix build --- ProcessHacker/tokprp.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/ProcessHacker/tokprp.c b/ProcessHacker/tokprp.c index 12bf449eb7de..cdfb98cbac97 100644 --- a/ProcessHacker/tokprp.c +++ b/ProcessHacker/tokprp.c @@ -581,13 +581,11 @@ INT_PTR CALLBACK PhpTokenPageProc( PhSetExtendedListView(tokenPageContext->ListViewHandle); ExtendedListView_SetItemColorFunction(tokenPageContext->ListViewHandle, PhpTokenGroupColorFunction); - PhLoadListViewColumnsFromSetting(L"TokenGroupsListViewColumns", tokenPageContext->ListViewHandle); - ListView_EnableGroupView(tokenPageContext->ListViewHandle, TRUE); PhAddListViewGroup(tokenPageContext->ListViewHandle, PH_PROCESS_TOKEN_CATEGORY_PRIVILEGES, L"Privileges"); PhAddListViewGroup(tokenPageContext->ListViewHandle, PH_PROCESS_TOKEN_CATEGORY_GROUPS, L"Groups"); ListView_SetImageList(tokenPageContext->ListViewHandle, tokenPageContext->ListViewImageList, LVSIL_SMALL); - PhRegisterWindowCallback(tokenPageContext->ListViewHandle, PH_PLUGIN_WINDOW_EVENT_TYPE_FONT, NULL); + PhLoadListViewColumnsFromSetting(L"TokenGroupsListViewColumns", tokenPageContext->ListViewHandle); PhSetDialogItemText(hwndDlg, IDC_USER, L"Unknown"); PhSetDialogItemText(hwndDlg, IDC_USERSID, L"Unknown"); @@ -706,7 +704,6 @@ INT_PTR CALLBACK PhpTokenPageProc( PhpTokenPageFreeListViewEntries(tokenPageContext); - PhUnregisterWindowCallback(tokenPageContext->ListViewHandle); PhSaveListViewColumnsToSetting(L"TokenGroupsListViewColumns", tokenPageContext->ListViewHandle); if (tokenPageContext->Groups) PhFree(tokenPageContext->Groups); From 41b2d91a1d9370c7261921cb0bc4e83152e3ef0a Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 1 Aug 2018 02:26:00 +1000 Subject: [PATCH 1230/2058] Remove unused code --- ProcessHacker/prpghndl.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/ProcessHacker/prpghndl.c b/ProcessHacker/prpghndl.c index 33b4544827f9..b86429b4f99f 100644 --- a/ProcessHacker/prpghndl.c +++ b/ProcessHacker/prpghndl.c @@ -397,7 +397,6 @@ INT_PTR CALLBACK PhpProcessHandlesDlgProc( handlesContext->ErrorMessage = NULL; handlesContext->SearchboxText = PhReferenceEmptyString(); handlesContext->FilterEntry = PhAddTreeNewFilter(&handlesContext->ListContext.TreeFilterSupport, PhpHandleTreeFilterCallback, handlesContext); - PhRegisterWindowCallback(tnHandle, PH_PLUGIN_WINDOW_EVENT_TYPE_FONT, NULL); PhEmCallObjectOperation(EmHandlesContextType, handlesContext, EmObjectCreate); @@ -425,8 +424,6 @@ INT_PTR CALLBACK PhpProcessHandlesDlgProc( break; case WM_DESTROY: { - PhUnregisterWindowCallback(tnHandle); - PhEmCallObjectOperation(EmHandlesContextType, handlesContext, EmObjectDelete); PhUnregisterCallback( From 49fd997470baf71dc8c4b879a16932aa093903fc Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 1 Aug 2018 07:30:18 +1000 Subject: [PATCH 1231/2058] Fix service trigger tab layout --- plugins/ExtendedServices/triggpg.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/plugins/ExtendedServices/triggpg.c b/plugins/ExtendedServices/triggpg.c index f9e8b191f9f5..1355a3a58300 100644 --- a/plugins/ExtendedServices/triggpg.c +++ b/plugins/ExtendedServices/triggpg.c @@ -26,6 +26,7 @@ typedef struct _SERVICE_TRIGGERS_CONTEXT { PPH_SERVICE_ITEM ServiceItem; HWND TriggersLv; + PH_LAYOUT_MANAGER LayoutManager; struct _ES_TRIGGER_CONTEXT *TriggerContext; } SERVICE_TRIGGERS_CONTEXT, *PSERVICE_TRIGGERS_CONTEXT; @@ -98,11 +99,19 @@ INT_PTR CALLBACK EspServiceTriggersDlgProc( ((PPH_STRING)PH_AUTO(PhGetNtMessage(status)))->Buffer); } + PhInitializeLayoutManager(&context->LayoutManager, hwndDlg); + PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_TRIGGERS), NULL, PH_ANCHOR_ALL); + PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_NEW), NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_RIGHT); + PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_EDIT), NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_RIGHT); + PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_DELETE), NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_RIGHT); + PhInitializeWindowTheme(hwndDlg, !!PhGetIntegerSetting(L"EnableThemeSupport")); } break; case WM_DESTROY: { + PhDeleteLayoutManager(&context->LayoutManager); + EsDestroyServiceTriggerContext(context->TriggerContext); PhFree(context); } @@ -178,6 +187,11 @@ INT_PTR CALLBACK EspServiceTriggersDlgProc( } } break; + case WM_SIZE: + { + PhLayoutManagerLayout(&context->LayoutManager); + } + break; } return FALSE; From e2228b9c4de2e92d503cb706abd541988c769d89 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 1 Aug 2018 07:41:17 +1000 Subject: [PATCH 1232/2058] Update ProcessServicesControls default selection --- ProcessHacker/srvctl.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/ProcessHacker/srvctl.c b/ProcessHacker/srvctl.c index deaf1f057c89..c7c5b9690b1a 100644 --- a/ProcessHacker/srvctl.c +++ b/ProcessHacker/srvctl.c @@ -274,7 +274,17 @@ INT_PTR CALLBACK PhpServicesPageProc( ExtendedListView_SortItems(context->ListViewHandle); - PhpFixProcessServicesControls(hwndDlg, NULL); + if (context->NumberOfServices > 0) + { + SetFocus(context->ListViewHandle); + ListView_SetItemState(context->ListViewHandle, 0, LVNI_SELECTED, LVNI_SELECTED); + ListView_EnsureVisible(context->ListViewHandle, 0, FALSE); + PhpFixProcessServicesControls(hwndDlg, context->Services[0]); + } + else + { + PhpFixProcessServicesControls(hwndDlg, NULL); + } PhInitializeLayoutManager(&context->LayoutManager, hwndDlg); PhAddLayoutItem(&context->LayoutManager, context->ListViewHandle, NULL, PH_ANCHOR_ALL); From b1560a3ec3c63436c269330bb353f879b5867a70 Mon Sep 17 00:00:00 2001 From: dmex Date: Wed, 1 Aug 2018 11:51:53 +1000 Subject: [PATCH 1233/2058] WindowExplorer: Add filename for window class module --- plugins/WindowExplorer/wndprp.c | 35 ++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/plugins/WindowExplorer/wndprp.c b/plugins/WindowExplorer/wndprp.c index de3d01958806..f1ecfbc699cc 100644 --- a/plugins/WindowExplorer/wndprp.c +++ b/plugins/WindowExplorer/wndprp.c @@ -1053,6 +1053,9 @@ static VOID WepRefreshWindowClassInfo( { WCHAR className[256]; PH_STRING_BUILDER stringBuilder; + HANDLE processHandle; + PPH_STRING fileName = NULL; + PVOID instanceHandle; ULONG i; if (!GetClassName(Context->WindowHandle, className, sizeof(className) / sizeof(WCHAR))) @@ -1066,9 +1069,39 @@ static VOID WepRefreshWindowClassInfo( GetClassInfoEx(NULL, className, &Context->ClassInfo); } + instanceHandle = (PVOID)GetClassLongPtr(Context->WindowHandle, GCLP_HMODULE); + // TODO: GetWindowLongPtr(Context->WindowHandle, GCLP_WNDPROC); + + if (NT_SUCCESS(PhOpenProcess(&processHandle, *(PULONG)WeGetProcedureAddress("ProcessQueryAccess"), Context->ClientId.UniqueProcess))) + { + if (NT_SUCCESS(PhGetProcessMappedFileName(processHandle, instanceHandle, &fileName))) + { + PhMoveReference(&fileName, PhResolveDevicePrefix(fileName)); + PhMoveReference(&fileName, PhGetBaseName(fileName)); + } + + NtClose(processHandle); + } + + if (fileName) + { + PhSetDialogItemText(hwndDlg, IDC_INSTANCEHANDLE, PhaFormatString( + L"0x%Ix (%s)", + instanceHandle, + PhGetStringOrEmpty(fileName) + )->Buffer); + PhDereferenceObject(fileName); + } + else + { + PhSetDialogItemText(hwndDlg, IDC_INSTANCEHANDLE, PhaFormatString( + L"0x%Ix", + instanceHandle + )->Buffer); + } + PhSetDialogItemText(hwndDlg, IDC_NAME, className); PhSetDialogItemText(hwndDlg, IDC_ATOM, PhaFormatString(L"0x%x", GetClassWord(Context->WindowHandle, GCW_ATOM))->Buffer); - PhSetDialogItemText(hwndDlg, IDC_INSTANCEHANDLE, PhaFormatString(L"0x%Ix", GetClassLongPtr(Context->WindowHandle, GCLP_HMODULE))->Buffer); PhSetDialogItemText(hwndDlg, IDC_ICONHANDLE, PhaFormatString(L"0x%Ix", Context->ClassInfo.hIcon)->Buffer); PhSetDialogItemText(hwndDlg, IDC_SMALLICONHANDLE, PhaFormatString(L"0x%Ix", Context->ClassInfo.hIconSm)->Buffer); PhSetDialogItemText(hwndDlg, IDC_MENUNAME, PhaFormatString(L"0x%Ix", Context->ClassInfo.lpszMenuName)->Buffer); From 3e37aaa1f8462d71348863778e4d1ddcba336eee Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 2 Aug 2018 03:29:00 +1000 Subject: [PATCH 1234/2058] Add PhGetWindowTextToBuffer --- phlib/guisup.c | 25 +++++++++++++++++++++++++ phlib/include/guisup.h | 11 +++++++++++ 2 files changed, 36 insertions(+) diff --git a/phlib/guisup.c b/phlib/guisup.c index 9afb0611cafe..60089646f1ec 100644 --- a/phlib/guisup.c +++ b/phlib/guisup.c @@ -404,6 +404,31 @@ ULONG PhGetWindowTextEx( } } +ULONG PhGetWindowTextToBuffer( + _In_ HWND hwnd, + _In_ ULONG Flags, + _Out_writes_bytes_opt_(BufferLength) PWSTR Buffer, + _In_opt_ ULONG BufferLength, + _Out_opt_ PULONG ReturnLength + ) +{ + ULONG status = ERROR_SUCCESS; + ULONG length; + + if (Flags & PH_GET_WINDOW_TEXT_INTERNAL) + length = InternalGetWindowText(hwnd, Buffer, BufferLength); + else + length = GetWindowText(hwnd, Buffer, BufferLength); + + if (length == 0) + status = GetLastError(); + + if (ReturnLength) + *ReturnLength = length; + + return status; +} + VOID PhAddComboBoxStrings( _In_ HWND hWnd, _In_ PWSTR *Strings, diff --git a/phlib/include/guisup.h b/phlib/include/guisup.h index f8f2de1f3f70..d6b865c878f2 100644 --- a/phlib/include/guisup.h +++ b/phlib/include/guisup.h @@ -294,6 +294,17 @@ ULONG PhGetWindowTextEx( _Out_opt_ PPH_STRING *Text ); +PHLIBAPI +ULONG +NTAPI +PhGetWindowTextToBuffer( + _In_ HWND hwnd, + _In_ ULONG Flags, + _Out_writes_bytes_opt_(BufferLength) PWSTR Buffer, + _In_opt_ ULONG BufferLength, + _Out_opt_ PULONG ReturnLength + ); + PHLIBAPI VOID PhAddComboBoxStrings( _In_ HWND hWnd, From acf175ab5966b9df22ad076458e35bda817586ab Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 2 Aug 2018 03:33:49 +1000 Subject: [PATCH 1235/2058] Remove unused flags --- phlib/filestream.c | 34 +++++++++++--------- phlib/global.c | 64 ++++++++++---------------------------- phlib/include/filestream.h | 6 ---- phlib/include/phconfig.h | 20 ++---------- phlib/include/symprv.h | 7 ----- phlib/symprv.c | 58 +++++++++++++++++----------------- 6 files changed, 67 insertions(+), 122 deletions(-) diff --git a/phlib/filestream.c b/phlib/filestream.c index d38da05ec6a0..6d12bc6f3741 100644 --- a/phlib/filestream.c +++ b/phlib/filestream.c @@ -24,21 +24,7 @@ #include #include -PPH_OBJECT_TYPE PhFileStreamType; - -BOOLEAN PhFileStreamInitialization( - VOID - ) -{ - PH_OBJECT_TYPE_PARAMETERS parameters; - - parameters.FreeListSize = sizeof(PH_FILE_STREAM); - parameters.FreeListCount = 16; - - PhFileStreamType = PhCreateObjectTypeEx(L"FileStream", PH_OBJECT_TYPE_USE_FREE_LIST, PhpFileStreamDeleteProcedure, ¶meters); - - return TRUE; -} +PPH_OBJECT_TYPE PhFileStreamType = NULL; NTSTATUS PhCreateFileStream( _Out_ PPH_FILE_STREAM *FileStream, @@ -110,8 +96,26 @@ NTSTATUS PhCreateFileStream2( _In_ ULONG BufferLength ) { + static PH_INITONCE fileStreamInitOnce = PH_INITONCE_INIT; PPH_FILE_STREAM fileStream; + if (PhBeginInitOnce(&fileStreamInitOnce)) + { + PH_OBJECT_TYPE_PARAMETERS parameters; + + parameters.FreeListSize = sizeof(PH_FILE_STREAM); + parameters.FreeListCount = 16; + + PhFileStreamType = PhCreateObjectTypeEx( + L"FileStream", + PH_OBJECT_TYPE_USE_FREE_LIST, + PhpFileStreamDeleteProcedure, + ¶meters + ); + + PhEndInitOnce(&fileStreamInitOnce); + } + fileStream = PhCreateObject(sizeof(PH_FILE_STREAM), PhFileStreamType); fileStream->FileHandle = FileHandle; fileStream->Flags = Flags; diff --git a/phlib/global.c b/phlib/global.c index 0f7c03b11c38..90979ba46b00 100644 --- a/phlib/global.c +++ b/phlib/global.c @@ -22,15 +22,10 @@ */ #include - #include #include #include -BOOLEAN PhInitializeSystem( - _In_ ULONG Flags - ); - VOID PhInitializeSystemInformation( VOID ); @@ -39,19 +34,19 @@ VOID PhInitializeWindowsVersion( VOID ); -PHLIBAPI PVOID PhInstanceHandle; -PHLIBAPI PWSTR PhApplicationName; +PHLIBAPI PVOID PhInstanceHandle = NULL; +PHLIBAPI PWSTR PhApplicationName = NULL; PHLIBAPI ULONG PhGlobalDpi = 96; -PHLIBAPI PVOID PhHeapHandle; -PHLIBAPI RTL_OSVERSIONINFOEXW PhOsVersion; -PHLIBAPI SYSTEM_BASIC_INFORMATION PhSystemBasicInformation; -PHLIBAPI ULONG WindowsVersion; +PHLIBAPI PVOID PhHeapHandle = NULL; +PHLIBAPI RTL_OSVERSIONINFOEXW PhOsVersion = { 0 }; +PHLIBAPI SYSTEM_BASIC_INFORMATION PhSystemBasicInformation = { 0 }; +PHLIBAPI ULONG WindowsVersion = WINDOWS_NEW; -PHLIBAPI ACCESS_MASK ProcessQueryAccess; -PHLIBAPI ACCESS_MASK ProcessAllAccess; -PHLIBAPI ACCESS_MASK ThreadQueryAccess; -PHLIBAPI ACCESS_MASK ThreadSetAccess; -PHLIBAPI ACCESS_MASK ThreadAllAccess; +PHLIBAPI ACCESS_MASK ProcessQueryAccess = PROCESS_QUERY_LIMITED_INFORMATION; +PHLIBAPI ACCESS_MASK ProcessAllAccess = STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x1fff; +PHLIBAPI ACCESS_MASK ThreadQueryAccess = THREAD_QUERY_LIMITED_INFORMATION; +PHLIBAPI ACCESS_MASK ThreadSetAccess = THREAD_SET_LIMITED_INFORMATION; +PHLIBAPI ACCESS_MASK ThreadAllAccess = STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xfff; // Internal data #ifdef DEBUG @@ -101,20 +96,18 @@ NTSTATUS PhInitializePhLibEx( if (!NT_SUCCESS(PhRefInitialization())) return STATUS_UNSUCCESSFUL; - if (!PhBaseInitialization()) - return STATUS_UNSUCCESSFUL; - if (!PhInitializeSystem(Flags)) + if (!PhBaseInitialization()) return STATUS_UNSUCCESSFUL; return STATUS_SUCCESS; } -#ifndef _WIN64 BOOLEAN PhIsExecutingInWow64( VOID ) { +#ifndef _WIN64 static BOOLEAN valid = FALSE; static BOOLEAN isWow64; @@ -126,29 +119,12 @@ BOOLEAN PhIsExecutingInWow64( } return isWow64; -} -#endif - -static BOOLEAN PhInitializeSystem( - _In_ ULONG Flags - ) -{ - if (Flags & PHLIB_INIT_MODULE_FILE_STREAM) - { - if (!PhFileStreamInitialization()) - return FALSE; - } - - if (Flags & PHLIB_INIT_MODULE_SYMBOL_PROVIDER) - { - if (!PhSymbolProviderInitialization()) - return FALSE; - } - +#else return TRUE; +#endif } -static VOID PhInitializeSystemInformation( +VOID PhInitializeSystemInformation( VOID ) { @@ -160,7 +136,7 @@ static VOID PhInitializeSystemInformation( ); } -static VOID PhInitializeWindowsVersion( +VOID PhInitializeWindowsVersion( VOID ) { @@ -229,10 +205,4 @@ static VOID PhInitializeWindowsVersion( { WindowsVersion = WINDOWS_NEW; } - - ProcessQueryAccess = PROCESS_QUERY_LIMITED_INFORMATION; - ProcessAllAccess = STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x1fff; - ThreadQueryAccess = THREAD_QUERY_LIMITED_INFORMATION; - ThreadSetAccess = THREAD_SET_LIMITED_INFORMATION; - ThreadAllAccess = STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xfff; } diff --git a/phlib/include/filestream.h b/phlib/include/filestream.h index ec4a2077bc47..769f2c0f280f 100644 --- a/phlib/include/filestream.h +++ b/phlib/include/filestream.h @@ -55,12 +55,6 @@ typedef struct _PH_FILE_STREAM extern PPH_OBJECT_TYPE PhFileStreamType; -BOOLEAN -NTAPI -PhFileStreamInitialization( - VOID - ); - PHLIBAPI NTSTATUS NTAPI diff --git a/phlib/include/phconfig.h b/phlib/include/phconfig.h index 4d1d7d8bbe48..06917148b91e 100644 --- a/phlib/include/phconfig.h +++ b/phlib/include/phconfig.h @@ -55,14 +55,11 @@ PHLIBAPI extern ACCESS_MASK ThreadAllAccess; #define PHLIB_INIT_MODULE_RESERVED1 0x1 #define PHLIB_INIT_MODULE_RESERVED2 0x2 -/** Needed to use work queues. */ #define PHLIB_INIT_MODULE_RESERVED3 0x4 #define PHLIB_INIT_MODULE_RESERVED4 0x8 -/** Needed to use file streams. */ -#define PHLIB_INIT_MODULE_FILE_STREAM 0x10 -/** Needed to use symbol providers. */ -#define PHLIB_INIT_MODULE_SYMBOL_PROVIDER 0x20 -#define PHLIB_INIT_MODULE_RESERVED5 0x40 +#define PHLIB_INIT_MODULE_RESERVED5 0x10 +#define PHLIB_INIT_MODULE_RESERVED6 0x20 +#define PHLIB_INIT_MODULE_RESERVED7 0x40 PHLIBAPI NTSTATUS @@ -82,23 +79,12 @@ PhInitializePhLibEx( _In_opt_ SIZE_T HeapCommitSize ); -#ifdef _WIN64 -FORCEINLINE -BOOLEAN -PhIsExecutingInWow64( - VOID - ) -{ - return FALSE; -} -#else PHLIBAPI BOOLEAN NTAPI PhIsExecutingInWow64( VOID ); -#endif #ifdef __cplusplus } diff --git a/phlib/include/symprv.h b/phlib/include/symprv.h index f9bd4c6216f4..3148e8e842cc 100644 --- a/phlib/include/symprv.h +++ b/phlib/include/symprv.h @@ -64,13 +64,6 @@ typedef struct _PH_SYMBOL_EVENT_DATA PPH_STRING FileName; } PH_SYMBOL_EVENT_DATA, *PPH_SYMBOL_EVENT_DATA; -PHLIBAPI -BOOLEAN -NTAPI -PhSymbolProviderInitialization( - VOID - ); - PHLIBAPI PPH_SYMBOL_PROVIDER NTAPI diff --git a/phlib/symprv.c b/phlib/symprv.c index d9c313b24f8c..f2d676cc28ee 100644 --- a/phlib/symprv.c +++ b/phlib/symprv.c @@ -61,49 +61,47 @@ LONG NTAPI PhpSymbolModuleCompareFunction( _In_ PPH_AVL_LINKS Links2 ); -PPH_OBJECT_TYPE PhSymbolProviderType; +PPH_OBJECT_TYPE PhSymbolProviderType = NULL; static PH_INITONCE PhSymInitOnce = PH_INITONCE_INIT; static HANDLE PhNextFakeHandle = (HANDLE)0; static PH_FAST_LOCK PhSymMutex = PH_FAST_LOCK_INIT; #define PH_LOCK_SYMBOLS() PhAcquireFastLockExclusive(&PhSymMutex) #define PH_UNLOCK_SYMBOLS() PhReleaseFastLockExclusive(&PhSymMutex) -_SymInitializeW SymInitializeW_I; -_SymCleanup SymCleanup_I; -_SymEnumSymbolsW SymEnumSymbolsW_I; -_SymFromAddrW SymFromAddrW_I; -_SymFromNameW SymFromNameW_I; -_SymGetLineFromAddrW64 SymGetLineFromAddrW64_I; -_SymLoadModuleExW SymLoadModuleExW_I; -_SymGetOptions SymGetOptions_I; -_SymSetOptions SymSetOptions_I; -_SymGetSearchPathW SymGetSearchPathW_I; -_SymSetSearchPathW SymSetSearchPathW_I; -_SymUnloadModule64 SymUnloadModule64_I; -_SymFunctionTableAccess64 SymFunctionTableAccess64_I; -_SymGetModuleBase64 SymGetModuleBase64_I; -_SymRegisterCallbackW64 SymRegisterCallbackW64_I; -_StackWalk64 StackWalk64_I; -_MiniDumpWriteDump MiniDumpWriteDump_I; -_SymbolServerGetOptions SymbolServerGetOptions; -_SymbolServerSetOptions SymbolServerSetOptions; -_UnDecorateSymbolNameW UnDecorateSymbolNameW_I; - -BOOLEAN PhSymbolProviderInitialization( - VOID - ) -{ - PhSymbolProviderType = PhCreateObjectType(L"SymbolProvider", 0, PhpSymbolProviderDeleteProcedure); - - return TRUE; -} +_SymInitializeW SymInitializeW_I = NULL; +_SymCleanup SymCleanup_I = NULL; +_SymEnumSymbolsW SymEnumSymbolsW_I = NULL; +_SymFromAddrW SymFromAddrW_I = NULL; +_SymFromNameW SymFromNameW_I = NULL; +_SymGetLineFromAddrW64 SymGetLineFromAddrW64_I = NULL; +_SymLoadModuleExW SymLoadModuleExW_I = NULL; +_SymGetOptions SymGetOptions_I = NULL; +_SymSetOptions SymSetOptions_I = NULL; +_SymGetSearchPathW SymGetSearchPathW_I = NULL; +_SymSetSearchPathW SymSetSearchPathW_I = NULL; +_SymUnloadModule64 SymUnloadModule64_I = NULL; +_SymFunctionTableAccess64 SymFunctionTableAccess64_I = NULL; +_SymGetModuleBase64 SymGetModuleBase64_I = NULL; +_SymRegisterCallbackW64 SymRegisterCallbackW64_I = NULL; +_StackWalk64 StackWalk64_I = NULL; +_MiniDumpWriteDump MiniDumpWriteDump_I = NULL; +_SymbolServerGetOptions SymbolServerGetOptions = NULL; +_SymbolServerSetOptions SymbolServerSetOptions = NULL; +_UnDecorateSymbolNameW UnDecorateSymbolNameW_I = NULL; PPH_SYMBOL_PROVIDER PhCreateSymbolProvider( _In_opt_ HANDLE ProcessId ) { + static PH_INITONCE symbolProviderInitOnce = PH_INITONCE_INIT; PPH_SYMBOL_PROVIDER symbolProvider; + if (PhBeginInitOnce(&symbolProviderInitOnce)) + { + PhSymbolProviderType = PhCreateObjectType(L"SymbolProvider", 0, PhpSymbolProviderDeleteProcedure); + PhEndInitOnce(&symbolProviderInitOnce); + } + symbolProvider = PhCreateObject(sizeof(PH_SYMBOL_PROVIDER), PhSymbolProviderType); memset(symbolProvider, 0, sizeof(PH_SYMBOL_PROVIDER)); InitializeListHead(&symbolProvider->ModulesListHead); From 8286502b30d085e6653cfcab812e72fb15688c24 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 2 Aug 2018 03:34:14 +1000 Subject: [PATCH 1236/2058] DotNetTools: Add theme support --- plugins/DotNetTools/DotNetTools.vcxproj | 12 ++++-------- plugins/DotNetTools/asmpage.c | 3 +-- plugins/DotNetTools/perfpage.c | 4 +++- 3 files changed, 8 insertions(+), 11 deletions(-) diff --git a/plugins/DotNetTools/DotNetTools.vcxproj b/plugins/DotNetTools/DotNetTools.vcxproj index 4ab20fb53f4e..7b5daab17c0c 100644 --- a/plugins/DotNetTools/DotNetTools.vcxproj +++ b/plugins/DotNetTools/DotNetTools.vcxproj @@ -54,26 +54,22 @@ - uxtheme.lib;%(AdditionalDependencies) - advapi32.dll;user32.dll;uxtheme.dll;%(DelayLoadDLLs) + advapi32.dll;user32.dll;%(DelayLoadDLLs) - uxtheme.lib;%(AdditionalDependencies) - advapi32.dll;user32.dll;uxtheme.dll;%(DelayLoadDLLs) + advapi32.dll;user32.dll;%(DelayLoadDLLs) - uxtheme.lib;%(AdditionalDependencies) - advapi32.dll;user32.dll;uxtheme.dll;%(DelayLoadDLLs) + advapi32.dll;user32.dll;%(DelayLoadDLLs) - uxtheme.lib;%(AdditionalDependencies) - advapi32.dll;user32.dll;uxtheme.dll;%(DelayLoadDLLs) + advapi32.dll;user32.dll;%(DelayLoadDLLs) diff --git a/plugins/DotNetTools/asmpage.c b/plugins/DotNetTools/asmpage.c index dc8f62bec3ef..013c40b6756e 100644 --- a/plugins/DotNetTools/asmpage.c +++ b/plugins/DotNetTools/asmpage.c @@ -24,7 +24,6 @@ #include "dn.h" #include "clretw.h" #include -#include #define DNATNC_STRUCTURE 0 #define DNATNC_ID 1 @@ -1249,7 +1248,7 @@ INT_PTR CALLBACK DotNetAsmPageDlgProc( InvalidateRect(tnHandle, NULL, FALSE); } - EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); + PhInitializeWindowTheme(hwndDlg, !!PhGetIntegerSetting(L"EnableThemeSupport")); } break; case WM_DESTROY: diff --git a/plugins/DotNetTools/perfpage.c b/plugins/DotNetTools/perfpage.c index c5cf54c72bcf..d60689fad10f 100644 --- a/plugins/DotNetTools/perfpage.c +++ b/plugins/DotNetTools/perfpage.c @@ -829,6 +829,8 @@ INT_PTR CALLBACK DotNetPerfPageDlgProc( context, &context->ProcessesUpdatedCallbackRegistration ); + + PhInitializeWindowTheme(hwndDlg, !!PhGetIntegerSetting(L"EnableThemeSupport")); } break; case WM_DESTROY: @@ -956,4 +958,4 @@ VOID AddPerfPageToPropContext( PropContext->PropContext, PhCreateProcessPropPageContextEx(PluginInstance->DllBase, MAKEINTRESOURCE(IDD_PROCDOTNETPERF), DotNetPerfPageDlgProc, NULL) ); -} \ No newline at end of file +} From e9eabf76ecb8bc3873b15bade6bd7b4ec2a59991 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 2 Aug 2018 05:07:36 +1000 Subject: [PATCH 1237/2058] Fix build --- phlib/basesup.c | 10 +++++----- tools/peview/peprp.c | 10 +++------- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/phlib/basesup.c b/phlib/basesup.c index 35387098bef1..4a436709e17c 100644 --- a/phlib/basesup.c +++ b/phlib/basesup.c @@ -95,11 +95,11 @@ VOID NTAPI PhpHashtableDeleteProcedure( // Types -PPH_OBJECT_TYPE PhStringType; -PPH_OBJECT_TYPE PhBytesType; -PPH_OBJECT_TYPE PhListType; -PPH_OBJECT_TYPE PhPointerListType; -PPH_OBJECT_TYPE PhHashtableType; +PPH_OBJECT_TYPE PhStringType = NULL; +PPH_OBJECT_TYPE PhBytesType = NULL; +PPH_OBJECT_TYPE PhListType = NULL; +PPH_OBJECT_TYPE PhPointerListType = NULL; +PPH_OBJECT_TYPE PhHashtableType = NULL; // Misc. diff --git a/tools/peview/peprp.c b/tools/peview/peprp.c index 3fded8916d2c..2aa34aa05fab 100644 --- a/tools/peview/peprp.c +++ b/tools/peview/peprp.c @@ -797,14 +797,9 @@ BOOLEAN PvpLoadDbgHelp( UNICODE_STRING symbolPathUs; WCHAR buffer[512]; + // Load symbol path from _NT_SYMBOL_PATH if configured by the user. RtlInitEmptyUnicodeString(&symbolPathUs, buffer, sizeof(buffer)); - - if (!PhSymbolProviderInitialization()) - return FALSE; - - symbolProvider = PhCreateSymbolProvider(NULL); - // Load symbol path from _NT_SYMBOL_PATH if configured by the user. if (NT_SUCCESS(RtlQueryEnvironmentVariable_U(NULL, &symbolPathVarName, &symbolPathUs))) { symbolSearchPath = PhCreateStringFromUnicodeString(&symbolPathUs); @@ -815,9 +810,10 @@ BOOLEAN PvpLoadDbgHelp( symbolSearchPath = PhCreateString(L"SRV*C:\\Symbols*http://msdl.microsoft.com/download/symbols"); } + symbolProvider = PhCreateSymbolProvider(NULL); PhSetSearchPathSymbolProvider(symbolProvider, symbolSearchPath->Buffer); PhDereferenceObject(symbolSearchPath); *SymbolProvider = symbolProvider; return TRUE; -} \ No newline at end of file +} From 26bc12de6b04eebd69566a7c77a51e106defb807 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 2 Aug 2018 05:16:25 +1000 Subject: [PATCH 1238/2058] peview: Fix typo --- tools/peview/pdb.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/tools/peview/pdb.c b/tools/peview/pdb.c index ee704a7b3fc0..f319fcecc395 100644 --- a/tools/peview/pdb.c +++ b/tools/peview/pdb.c @@ -112,19 +112,19 @@ typedef BOOL (WINAPI *_SymSetContext)( _In_opt_ PIMAGEHLP_CONTEXT Context ); -_SymInitializeW SymInitializeW_I = NULL; -_SymCleanup SymCleanup_I = NULL; -_SymEnumSymbolsW SymEnumSymbolsW_I = NULL; -_SymEnumTypesW SymEnumTypesW_I = NULL; -_SymSetSearchPathW SymSetSearchPathW_I = NULL; -_SymGetOptions SymGetOptions_I = NULL; -_SymSetOptions SymSetOptions_I = NULL; -_SymLoadModuleExW SymLoadModuleExW_I = NULL; -_SymGetModuleInfoW64 SymGetModuleInfoW64_I = NULL; -_SymGetTypeFromNameW SymGetTypeFromNameW_I = NULL; -_SymGetTypeInfo SymGetTypeInfo_I = NULL; -_SymSetContext SymSetContext_I = NULL; -_SymSearchW SymSearchW_I = NULL; +static _SymInitializeW SymInitializeW_I = NULL; +static _SymCleanup SymCleanup_I = NULL; +static _SymEnumSymbolsW SymEnumSymbolsW_I = NULL; +static _SymEnumTypesW SymEnumTypesW_I = NULL; +static _SymSetSearchPathW SymSetSearchPathW_I = NULL; +static _SymGetOptions SymGetOptions_I = NULL; +static _SymSetOptions SymSetOptions_I = NULL; +static _SymLoadModuleExW SymLoadModuleExW_I = NULL; +static _SymGetModuleInfoW64 SymGetModuleInfoW64_I = NULL; +static _SymGetTypeFromNameW SymGetTypeFromNameW_I = NULL; +static _SymGetTypeInfo SymGetTypeInfo_I = NULL; +static _SymSetContext SymSetContext_I = NULL; +static _SymSearchW SymSearchW_I = NULL; ULONG SearchResultsAddIndex = 0; PPH_LIST SearchResults = NULL; @@ -2449,4 +2449,4 @@ VOID PdbDumpAddress( SymSetContext_I(NtCurrentProcess(), &sf, 0); SymEnumSymbolsW_I(NtCurrentProcess(), 0, NULL, EnumCallbackProc, Context); -} \ No newline at end of file +} From fb7434777512401b9ff27a07305936304e16af74 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 2 Aug 2018 06:34:48 +1000 Subject: [PATCH 1239/2058] Fix typo --- phlib/global.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phlib/global.c b/phlib/global.c index 90979ba46b00..a58b2736bb38 100644 --- a/phlib/global.c +++ b/phlib/global.c @@ -120,7 +120,7 @@ BOOLEAN PhIsExecutingInWow64( return isWow64; #else - return TRUE; + return FALSE; #endif } From cacdc4e8b2fb8ef649ce088550fe35e96534480c Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 2 Aug 2018 11:19:59 +1000 Subject: [PATCH 1240/2058] BuildTools: Add build timestamp --- tools/CustomBuildTool/Source Files/Build.cs | 38 +++++++++++--- tools/CustomBuildTool/Source Files/Program.cs | 2 +- tools/CustomBuildTool/Source Files/Utils.cs | 49 +++++++++++++++++- .../bin/Release/CustomBuildTool.exe | Bin 165376 -> 166912 bytes .../bin/Release/CustomBuildTool.pdb | Bin 81408 -> 83456 bytes 5 files changed, 80 insertions(+), 9 deletions(-) diff --git a/tools/CustomBuildTool/Source Files/Build.cs b/tools/CustomBuildTool/Source Files/Build.cs index cc8185c57be2..1e9878bab192 100644 --- a/tools/CustomBuildTool/Source Files/Build.cs +++ b/tools/CustomBuildTool/Source Files/Build.cs @@ -316,6 +316,11 @@ public static void ShowBuildEnvironment(string Platform, bool ShowBuildInfo, boo } } + public static string BuildTimeStamp() + { + return "[" + (DateTime.Now - TimeStart).ToString("mm\\:ss") + "] "; + } + public static void ShowBuildStats() { TimeSpan buildTime = DateTime.Now - TimeStart; @@ -545,6 +550,7 @@ public static bool FixupResourceHeader() public static bool BuildPublicHeaderFiles() { + Program.PrintColorMessage(BuildTimeStamp(), ConsoleColor.DarkGray, false); Program.PrintColorMessage("Building public SDK headers...", ConsoleColor.Cyan); try @@ -712,6 +718,7 @@ public static bool CopyKeyFiles() public static bool BuildWebSetupExe() { + Program.PrintColorMessage(BuildTimeStamp(), ConsoleColor.DarkGray, false); Program.PrintColorMessage("Building build-websetup.exe...", ConsoleColor.Cyan); if (!BuildSolution("tools\\CustomSetupTool\\CustomSetupTool.sln", BuildFlags.Build32bit)) @@ -749,7 +756,8 @@ public static bool BuildWebSetupExe() public static bool BuildSetupExe() { - Program.PrintColorMessage("Building build-setup.exe...", ConsoleColor.Cyan); + Program.PrintColorMessage(BuildTimeStamp(), ConsoleColor.DarkGray, false); + Program.PrintColorMessage("Building build-setup.exe... ", ConsoleColor.Cyan, false); if (!BuildSolution("tools\\CustomSetupTool\\CustomSetupTool.sln", BuildFlags.Build32bit | BuildFlags.BuildApi)) return false; @@ -763,6 +771,8 @@ public static bool BuildSetupExe() "tools\\CustomSetupTool\\CustomSetupTool\\bin\\Release32\\CustomSetupTool.exe", BuildOutputFolder + "\\processhacker-build-setup.exe" ); + + Program.PrintColorMessage(new FileInfo(BuildOutputFolder + "\\processhacker-build-setup.exe").Length.ToPrettySize(), ConsoleColor.Green); } catch (Exception ex) { @@ -775,11 +785,14 @@ public static bool BuildSetupExe() public static bool BuildSdkZip() { - Program.PrintColorMessage("Building build-sdk.zip...", ConsoleColor.Cyan); + Program.PrintColorMessage(BuildTimeStamp(), ConsoleColor.DarkGray, false); + Program.PrintColorMessage("Building build-sdk.zip... ", ConsoleColor.Cyan, false); try { Zip.CreateCompressedSdkFromFolder("sdk", BuildOutputFolder + "\\processhacker-build-sdk.zip"); + + Program.PrintColorMessage(new FileInfo(BuildOutputFolder + "\\processhacker-build-sdk.zip").Length.ToPrettySize(), ConsoleColor.Green); } catch (Exception ex) { @@ -792,7 +805,8 @@ public static bool BuildSdkZip() public static bool BuildBinZip() { - Program.PrintColorMessage("Building build-bin.zip...", ConsoleColor.Cyan); + Program.PrintColorMessage(BuildTimeStamp(), ConsoleColor.DarkGray, false); + Program.PrintColorMessage("Building build-bin.zip... ", ConsoleColor.Cyan, false); try { @@ -835,6 +849,8 @@ public static bool BuildBinZip() Directory.Move("bin\\x32", "bin\\Release32"); Directory.Move("bin\\x64", "bin\\Release64"); + + Program.PrintColorMessage(new FileInfo(BuildOutputFolder + "\\processhacker-build-bin.zip").Length.ToPrettySize(), ConsoleColor.Green); } catch (Exception ex) { @@ -847,7 +863,8 @@ public static bool BuildBinZip() public static bool BuildSrcZip() { - Program.PrintColorMessage("Building build-src.zip...", ConsoleColor.Cyan); + Program.PrintColorMessage(BuildTimeStamp(), ConsoleColor.DarkGray, false); + Program.PrintColorMessage("Building build-src.zip... ", ConsoleColor.Cyan, false); if (!File.Exists(GitExePath)) { @@ -874,23 +891,28 @@ public static bool BuildSrcZip() Program.PrintColorMessage("[ERROR] " + output, ConsoleColor.Red); return false; } + + Program.PrintColorMessage(new FileInfo(BuildOutputFolder + "\\processhacker-build-src.zip").Length.ToPrettySize(), ConsoleColor.Green); } catch (Exception ex) { Program.PrintColorMessage("[ERROR] " + ex, ConsoleColor.Red); return false; } - + return true; } public static bool BuildPdbZip() { - Program.PrintColorMessage("Building build-pdb.zip...", ConsoleColor.Cyan); + Program.PrintColorMessage(BuildTimeStamp(), ConsoleColor.DarkGray, false); + Program.PrintColorMessage("Building build-pdb.zip... ", ConsoleColor.Cyan, false); try { Zip.CreateCompressedPdbFromFolder(".\\", BuildOutputFolder + "\\processhacker-build-pdb.zip"); + + Program.PrintColorMessage(new FileInfo(BuildOutputFolder + "\\processhacker-build-pdb.zip").Length.ToPrettySize(), ConsoleColor.Green); } catch (Exception ex) { @@ -903,6 +925,7 @@ public static bool BuildPdbZip() public static bool BuildChecksumsFile() { + Program.PrintColorMessage(BuildTimeStamp(), ConsoleColor.DarkGray, false); Program.PrintColorMessage("Building build-checksums.txt...", ConsoleColor.Cyan); try @@ -944,6 +967,7 @@ public static bool BuildChecksumsFile() public static bool BuildUpdateSignature() { + Program.PrintColorMessage(BuildTimeStamp(), ConsoleColor.DarkGray, false); Program.PrintColorMessage("Building release signatures...", ConsoleColor.Cyan); if (!File.Exists(CustomSignToolPath)) @@ -1016,6 +1040,7 @@ public static bool BuildSolution(string Solution, BuildFlags Flags) if ((Flags & BuildFlags.Build32bit) == BuildFlags.Build32bit) { StringBuilder compilerOptions = new StringBuilder(); + Program.PrintColorMessage(BuildTimeStamp(), ConsoleColor.DarkGray, false, Flags); Program.PrintColorMessage("Building " + Path.GetFileNameWithoutExtension(Solution) + " (", ConsoleColor.Cyan, false, Flags); Program.PrintColorMessage("x32", ConsoleColor.Green, false, Flags); Program.PrintColorMessage(")...", ConsoleColor.Cyan, true, Flags); @@ -1046,6 +1071,7 @@ public static bool BuildSolution(string Solution, BuildFlags Flags) if ((Flags & BuildFlags.Build64bit) == BuildFlags.Build64bit) { StringBuilder compilerOptions = new StringBuilder(); + Program.PrintColorMessage(BuildTimeStamp(), ConsoleColor.DarkGray, false, Flags); Program.PrintColorMessage("Building " + Path.GetFileNameWithoutExtension(Solution) + " (", ConsoleColor.Cyan, false, Flags); Program.PrintColorMessage("x64", ConsoleColor.Green, false, Flags); Program.PrintColorMessage(")...", ConsoleColor.Cyan, true, Flags); diff --git a/tools/CustomBuildTool/Source Files/Program.cs b/tools/CustomBuildTool/Source Files/Program.cs index 9c1e77d6cb4e..dd7074721c65 100644 --- a/tools/CustomBuildTool/Source Files/Program.cs +++ b/tools/CustomBuildTool/Source Files/Program.cs @@ -410,4 +410,4 @@ public enum BuildFlags BuildVerbose = 8, BuildApi = 16, } -} \ No newline at end of file +} diff --git a/tools/CustomBuildTool/Source Files/Utils.cs b/tools/CustomBuildTool/Source Files/Utils.cs index 558b0613d4f1..4eb77de7b978 100644 --- a/tools/CustomBuildTool/Source Files/Utils.cs +++ b/tools/CustomBuildTool/Source Files/Utils.cs @@ -35,6 +35,24 @@ namespace CustomBuildTool [System.Security.SuppressUnmanagedCodeSecurity] public static class Win32 { + public static int CreateProcess(string FileName, string args) + { + using (Process process = Process.Start(new ProcessStartInfo + { + UseShellExecute = false, + FileName = FileName, + CreateNoWindow = true + })) + { + process.StartInfo.Arguments = args; + process.Start(); + + process.WaitForExit(); + + return process.ExitCode; + } + } + public static string ShellExecute(string FileName, string args) { string output = string.Empty; @@ -49,10 +67,10 @@ public static string ShellExecute(string FileName, string args) process.StartInfo.Arguments = args; process.Start(); + process.WaitForExit(); + output = process.StandardOutput.ReadToEnd(); output = output.Replace("\n\n", "\r\n").Trim(); - - process.WaitForExit(); } return output; @@ -475,6 +493,33 @@ public class BuildUpdateRequest [DataMember(Name = "changelog")] public string Changelog { get; set; } } + public static class Extextensions + { + private const long OneKb = 1024; + private const long OneMb = OneKb * 1024; + private const long OneGb = OneMb * 1024; + private const long OneTb = OneGb * 1024; + + public static string ToPrettySize(this int value, int decimalPlaces = 0) + { + return ((long)value).ToPrettySize(decimalPlaces); + } + + public static string ToPrettySize(this long value, int decimalPlaces = 0) + { + double asTb = Math.Round((double)value / OneTb, decimalPlaces); + double asGb = Math.Round((double)value / OneGb, decimalPlaces); + double asMb = Math.Round((double)value / OneMb, decimalPlaces); + double asKb = Math.Round((double)value / OneKb, decimalPlaces); + string chosenValue = asTb > 1 ? string.Format("{0}Tb", asTb) + : asGb > 1 ? string.Format("{0}Gb", asGb) + : asMb > 1 ? string.Format("{0}Mb", asMb) + : asKb > 1 ? string.Format("{0}Kb", asKb) + : string.Format("{0}B", Math.Round((double)value, decimalPlaces)); + return chosenValue; + } + } + [Flags] public enum ConsoleMode : uint { diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe b/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe index ee3c1715077a5ed838d1a00f712f87ebca7d12f8..5d8bc7e4dad4ae480f54ebc689ec36f84d21f8df 100644 GIT binary patch delta 29134 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 diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb b/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb index 9933bc0f0a0c124f2971f2c3694bc48d33355ca8..ff3e72f4401443b8ea9deb313344deeb0d412759 100644 GIT binary patch delta 23553 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 Y%LqPzJcuk`QSnRoCIXwerT)eIe>DkwF8}}l delta 22303 zcmaL934ByV*06tXCux$9gme~2I(q^MTObJ}WMN6zK~`A=L`;AHVFv*Lfh3A-3ImjI z0RaI)(NP3J76o@4P+-JCUuDz}K9>;%x6v6#QNQQhTirDC_y6AfPM)e$r}k5Im%iO~ z4~EoT4_@0m@)5%@esJ-RWBb7j_gm((u2`2@chGcQHP^f28a6Y2|2>$*-+vD}V!F)B z=K9dMgK=&W!-Eqd|26P-lf^7f`>+On5e{IZ{-@O$*XItFYEr%{y{rHSkQ=YOD6G+^U zz2(cbH9rn`V!@UF^N+axYi=3i`N2+14t0f3>LiUdj7goOL0_BCriZ%SAAd4rMuRjJ zmHlLJ(ZTlytK-?tgTG#Wb%FXKyDm6<(RcX=r{)X|9z0sQ!m-GK{l9@>xIc<84C#n5 zWYUbgyUwkdI)2EUsyTNVjg27B(ICTUPCm)wvr9G7J!0NKEpB~VVnT?74Wpj}`+q2< zj#SrLClywb_ftetM@BmJNV%KPT|yGkukh=gazoXD_Cpdc=yHz-lp995d(;!TNrlOz z?m#4Uk3WBqXDGU@h?Lts%2!`NxixFuPJy9zmz{7pGJRQ+3MM`ec zJChKuF6T8#5sRaU3|vc`Nk*qJ9TbKu8Mq&qYdHouu>Uj9?p~@sKdbNu^1h6Pr1tXX z5Aw7}w*qM!pwHCq+E9IvpA{(<#}TP{zB1e0zP@c}`c)i24r#FOz#ZHhbkWw+ZZn}o zX8b3z9>rQLeW{`^MpuV0I>w{^1_g9EQ7jH2Qt^QR3sa@!-R6BzGIIPoz)zSo_c@PR z(k?akTQZKoM3T?>GY5HE<4f}q*%f}*dapX4AFDoW7acFD`*mvX7-y8d%2Qycrby}+ zI(3ULRXbUPI^QnIwn(Q|DgBcG3-$!#hQ&}U#D#X_t-g6=Wn&@BcsG+K$9E3w|G0|# zq)I7FN?A+ZnOI2bNuA%fy+o>Eg=s3ZeS~Mq%t^OYFE9*AktGnR))gkjpCa#6@_Nx& zak_3bt9`6$o!2{YJo6_i4pQ3M#UM49q{ziW! zzr8Khq%$jW)H|^MGc@iZZEZLkX!V@AGkeUh7OxKSOrpfAh~)9viGByVFLZ5N{;;+W zb!|NZYGat(M{cfd{FG5OGsQ$oZAzZKh~)9viGDP?-H7z<(jV34-NeMmu~4Q_9}JHB z*LXF(*jsps%;PbUVtl`|c*HWr??NE15@N zBFT6A3t$^WFH2}T`dwNt+o0r+vOQERh7y;mV-jvuEnX5O{^u3Hmm_cl8&h@L1eIFq zEnG|HI7}qDt-pXE&nfiL=%wHhe!Ww5sLIG2;_WD#Gsgn~gGC$Na}(6X($w63WDdnd zlIQvh2=c5z|28rP{e3>YnpG03ipwHWBsG{^Qtc=Fld^sLVk6lXz58{w7o~1}P>kE~ zs&i$d($kqQIT&64K{@V=tP&~A@`RbO>h_MEYAUtKe0>2V<`}uZ(U#hgXH1WW$M8^_^}@Kg1Bru{EI8Nwj)mitgXyFf%FBE_OUc)?qHDzGUCt z;!%a2(@c*VX8%859;ddIH?*tqD2YAYxe=)+I%o0!vi(1#i-aYuQ=^e zv(F}tMMmB&>g`UU>2dT|j{5_KfE@0ibUg$o!p!6p8Q7zgb&2T^OJAxzEov5hGWnn2 zwl`KoP3fH4d_dJSHY|JWu9H)|p*3@{T$d~Tlgo=3E-zwLdPQ(b9gcS$@5;t%wYHKT zxoxY8iZs={ON5$Q5#99=mOo(`gysH#@?^YldH;CLuAViw`mQ;48zQhjipbK8%}}el zc-8wA(JAGq4k0a3XJp*)7S50~Eu?Esykz_V8HHw~wn$ayyTq!YUDH#fYwhV8<7=GM zsWQmy{N!KPwTW%97mI;tLNjknEgg1X@4%VeE3~y`hO=T{>ek8ogSHfR@ExgGZpl=QyASt{kUBV0 zWVPsnPP+GG9$eP_xGSU;yGpBry?V_x-BU^aC_;VR+nZlu8g%K4hGSc$uA^ zq0?ph-$O4`Cix0bY^*UjbPS^qej{X_= zF?eLEWlOsbBj9gPmg4VF9D@^C zU5Nme!64WXhCp!;HyjGX;Bd$d&VUYPFSU6MR=6hFv? zQcoKw%Pt>wfCW%(9oX8%jmVn=y|qQeWehq%DYqC(c_mQFD}&8oCn)80f#t9Q%2;%T zBVczZe$xYr-}HeC;Vp0_><>4?0dOZA1fLVX8cg5_isA5OI0Bx5qu}4+Xej=32mB|z z6EqwtpBYmj`|@4V#3z`n=eY!Cqqy5;+$Vmt znD}Z~OMEL_N}MggSPq|rE77xZjXx1T3D*(704?IIHe(ZH)fihKK5IM-zlYl)K59Gy zBaH&ikty8xR1JQ?lKBbtfj`p{*&2T%E-m;SRzow$s9OMCa53a^Q_c^eT)D{%k5n%VO;o`{ zlOv_M&W)RC^i=2f$9488JNReKr=b+M4|YKRJS>JMVF^4BOW}vG zBa~gB6Z{!=fzjq*!zd>p%f2h@1iQn2um`*y_Jnu9UT_TT17)@Mh4Wy4I3EsxjI8=* z_+k}3FuC?qDsgUIP5)i42i^OK9JgXGBRdp&;c(a--Uej`rDLt&XyO&{4k)Ym&LCsC zIL##D^>8xW0H;71uxapNws&JXfvqTJLYAj73(6Xs0}sQwP#WB8LkHinZC+$Ic;M}X5_I*1l``)Jxy&OMb8wP)d zjo>dZ7hZ>D@K-2n{dXv9+6Xr4YJdsnLKl=a1wmQ5!NEqYeP!nkHkKz*Nh1=npa+(~ z7+3}y!|pHv_JxUX67)h@YDsV@Oo5wVD%=gz;C`46&%zAI)uNFJ{{x!_w=kA-d0^zC z7z5kFIWP~-gY99Y(U)DZhk9mo7xn$<&b7`10@MFoL3X=-*viojdzsGeP)<2Lpg3wz zI0^QKGhrV%8}@|@;Vp0x><5>^{%{!_0N22QkZCmr%ZSO^y%oiFI0VY>Hxxbvhry$8 zID8)72H$`q;3+r~UVx+Edyo%$>@)8j@F(J9pj`V@1{>-WoJ*V=0An8f8=N0pYt(&2 zU;&CB;bO?uu2Bo47=?Psm7{Sl%!5l|XSfV<0cI?RTyPmH;hj)+v&ouVP#LSxPlFG@ z8E`e^I>}fAxjr)1i4SZbpdc4U#zwdqTI%GOw`zmZoi%qq8acWloH6Xmpd<8xWWm`H3{|*nqPvCPwFQG!k3_2kbeD* zT2q;w@e0xLL|=olbWg%9@D0cvrg2KWTbWiXt$&%=FYr}(9lj2KgWQoBzeDb{3|ELz z$DNcB4F3f~;7?E{PS#L3ac*PmIJYr&JOW0b_rfTc1*2hW7z0aPtf^Q6T~P3;VBJtC z1&)GJ;8>Uh$3s59tK$;fNQL*nG*|~S;k_{H;EAdxX6cGdXXaxVFgZvu3hw>cOXZR z4-vWW=2py*zH#dzcL~N?go|q94Du;r;DHGU*C56qWGb>0*@3X*8yAqPNNBJjdzH}< zVMVjrC@a_~6Av-YAXgD4!bnGokxFDfvKu*$e2DyjB)D;Vq_=xr#l`g#(j!iCZ`rex zjF3FoZDgjZz7ra|dUjF+KL3{*F|oS@w@>t%>FU_TBzGlQ*OE1R{iJmF0kZBcQ`wVJ zU7+Wr$?j*-{JBgWp42Ae&+PkBraVKGeI=bpI($~^z3RZeSd~!I(LA7r)nvI3lJ)&E zwWOviidRq^Lh*5#`qEb9PR??3vT}b`riM@M86!2zli%+tP{%)PQNF?)wOCC{b$&E+x3NM4cmeKfy;!RMhk$_cDS{mZ-kdOWn%}9wYKxajZj5joK5__=Ypi~yj$WR%5;byE{~1YUj;fiFl$aCn zoOJ4pyX{ZI$cD|f8Mnktq;TJ`HbqNkm(29WtTW{ztGRz+&~Z_(N1bV8`_&ABs1@o| zp1sT5NFfY}s2}<-HG?DS4X87WW`1i1O4J)sH#1uJ)eM@bqt2=W}yKCN@HQuiqF z1CX1UmhxcFeui-f9wXs7DChMfkTq>T@cRpVNu8ZNqs9IPT<9TRAfchGM5GuQgiJ!@ zIp0>~khomkPx)PRy?iiI4;NUXIehR%FHYU#S)n&nrP^LmoBV9Dh;U<+oFULhAN6quL z;L^!H5pd~*Khj7jJBwsuo!OK|?^4_5wT+wP>!|us)pFnX}N43OOoJ8>=iiI83*Z1^{;fdEx&FJ4z zuJcvpqG%U|;_K=`f)uxXQA?K;g62~+WS3y{;^eTnhTQ!kBUJ9YIG+ zOsopK z8c?LTZI(J&m*aUaK=@#it_cSsk&0%%Hs{t zN@`Qp?A}(MY^`lfKc%9ks_Nb*W>dA`-hnr5z(Yx6WG~+9&3FQDYfSV>m<-tf>`jL2 zdi$>TX%&B8S`TMfP2(0Un zeO-DuqxZ+<;Z}BeFGDHs6)5Gs3Z=Z)VM}<@F7FM>D|62$&Uo!x>Mc1>vNVTBeD)LT zcVQy&_h1HmAIfTz)z?k4JG`jO`#Yo*M{p5@OhuL=TaiP^8RSznc=4atFH4UQZ~s|e zYsflEQoWXWTtAno0lPBQqGcV;7V6ltJ4NALKFWQatW6`=RV-V-BHcZPtkYVl>=l_V z(09d??mN+JYo&f(k=kNgs~fvnD6={gk)}nocJ#ipZWC3pvX?nVtz4Pqt|a^Mw(8lH znYqW?-fWf-a6%qmGY;o2x+wbGLrYu~IAFuRW*u>;p@_UM!^N_(3E7XFLcTx@93kOg#>U@G_dLoU zRiv^vwG10oq&uuKYGc*ZO$namS|f`^8rV#2*wohbVv$-?>s3!}iBMNJ#d-dzjeNas z#^;>fSmDDqXSsRe?2hiBmTWEvi|*i*o~8OD_fHI|IwD4mt#6jrAwV3_SRme|B~SoXB>=A zp_lmQuo=7pbKzG!-;#63_rxn8cW$;f{|JW>{}-%+Kf!TOynQ_Ujre59^x03_U2rMU zAZW?CKZL+$6mIx1#1HM~b=;rVvC@r(kd@A(esk+M7en>t0dFm1?R-iEV@QmJvgYDp z3)lqW!v?45x;8Kw=0j-}lVPM1mtLg7evkpFy9Z{P#?q%@bK?7<N~3J?b%`V`aGDaUU`Qz%Ju}a zrK;cFjdR_}?OE%73JZ=S!VO=Gvr=R%+xUl4IK=S#EYGciT?t zjYqoPbTTA|L5>z<^ynRqqEP!lqVFpEzd{Poh-S1F`D(t^`j4qbV(tmdVENRhRcPQP+13 zjbPHY>ZPEy+*OJg59@mP|2`_Tx`2%RHSmzShw?MYJ+yCXc6 zIz{%PAZlV{9&e(`cSl6l1hgSoUEY^)yn|ZS zy_6lS>ZvUE0u&*|YSmMHQM`*{A&S^y_1jY|Tf`Ro+=RE{@Rv$N)@cX7-np%lH^^j1 z-0*akn|0_OTC84tIi0~9=e2+`efw&xT13iQIz^`I5BJu@z$^Po+V{D=8=FR&s+t$uqKLhM3uB`r zl-Bbxi~R{+XP8V}mISu!# zJUWF<;Xo+c^6d8}W@y0_mnk^6+0Pi5@w*|*&cBf^AYMUyA(V~u9w-~>V!e^xM_e{i$tN4BP&QIN zPH;9-K2NYW(g)Z`?`+l`PaBQQLFDDj{fNBMcohlt7)$_9dk%j0Y+F;kJU!U8yi{c$ zDs?}=l&>jO6AqQC^h3d}jiu@_f|Uffm8#DP?jX1a+viHvC4x_3OECSpU>Avx5v(Nm z0=5Kq5PS{W!v*RR!8c3Q7=r1CgI({Gs*Q(>qBc<52VBtMk9-QQwjcJY9}dTezerR4Q)J6cL;7Lm{O*`K3e2{gkaM$)$&-8dk4YRWoiP!odnyJsa?m4ROPW? zS6P|*_*kj?QM6slRO<7k?%f3YmZ>q%caGXaaB!Kg?N(Zn8LwV?KEwSO`jKVo^XE$= z9w%6-O|0`tW}GU2AzfX1KG-#h`WU427lK_g%G6^7D+%6BHiA0{F5&svafX=SGHj3Y zJn49F_-cQBYWi`ndi{8usyrU-+CV#x7rCFIx~*Kdp2(EhOB(*#5&G}MsG|BW9>K>erd}_z(d;=k= zeT@PBRD4e|ok3k;^zf^{xTz*d?a5PVUy-<`Wa3k!o0|9Un=(miVDs=?$s})1bu)VT z%W~WEtefYN)ZRuve`=H(JTobgP5h>5ioYq3qy|n?ik;^?+Q4CGdQ%=r4IGBncAj_8 z2DYu;O?f0Wux({_o(pILU8rkdo(7Ui+f=Wa%@W@wJebc_eWU2CC|}PdbvW-@`cg;Q zrN4)EpfSX+b(WYfkE9MYM)*@FNgg%gM6|55$tPNxciW2nC!)ia1U5_UKM|}horo}( z+3A%p2FI6k2j{EWS$et>MQUW=KyI)b_IIidoZYQ~<%dXWAGPkAIQ!!=cHcUWI`>-V zT6x)fC^8dSfyj3qjwA0Q-y#ulEMBA>8G+0}9z^ycFC!l!KOoWZTx=t~5qSYyZoD@k zhmbSK7YG-bMl#YK8H7w~Y_u^}5ZHmdjL3_`*O9m;JP1SvA#;!ik^RUib?o&l@9POv zi~NK{a~^JubVn)^4^+6!^>3uRGuVq>ZKkr{NOb|{-nzZo`o@R|PPOi&9DO;Nk;?n0 zv48P|`7~ZtUoMx$q3chFk~H`)St)tiSgr)QI5Zd%2G2PrsRJ`Qm>KHyU$P>yD0uWu z1vfn9agEMVsizu8E($2bRP}%9MW&UfvfS*7?tMAx*;6e&`?QJgPCZ^7*cB_yh*x2! zWp{6OI>&P=z$lnD#H%|_XL;V%TDi!T3!Zqj?sO~9faXpweHT0N>g?$>%DHxW2(?$d zndRm(!+oK-n*3&FE~MWPw)Wavx5UT<`Yw0p zqh%KRo>}5b%298gStX-7{Om5*zMO+UpPg>HE;K(l`LExb&F13+4xehgFm~pNnR(_u2SdB_+Tm@19gWyBZtG6N{}y02M%rd3U>zP0+UnuXPN+pv~|!=PedPnsh_&T@r2j3zo_cSxpQvU%-o@kVZjtV;p>}>5>z+&pTeervf9cJApQ7Z0%RiC5 zWqY3&^L0pcr;xtrZ`Jx#b@_`}75A0gleYLOiT^#m%HjXCuLidCRn$gTG+q`5hj_T} zm_fD2+ROcye;Q=F--_heJu&_MCl~f>bv{o5 zEJbvKNw5dZf<0j~*hg)?mgRcAoqF+_w`2gy1}F!@MsN^htLI|QdHrz+Y)X6>l>XcX zDUhf7p07LbT7I9ed(}EqV%pO~(oL@@-GRMqHe+BItc0904938InQ=VKAzlp`LxVA~ z-$TZ|?I%f$js2O}6i8c*X?%-G#%nfl#F&ex*U7-KAK5RvEP!i>-=ms+b4%DU+bc}I z8_312xmd0Krb$bwCXa#Xhm1#LkTxMlk++enNH8~!$;k&QW}EB34Xu?=z|Ms5PA7Yj zxcqlGyfBg;3FTE5;p#YtBQ<$h&er$gEGy}=m=<9bWeI-`cSz^$_(`@!(Ql4)I1R@n z-qpCmkV!%dT@bHN*zqbIPmFTn!<-DpH5x4TVY;D-%JXfL+IW|veL{1mZk|V%(n&XO zkFR;UIU%~48JyXr)M^|>c)zZ#kFKR&bDOUH8h4dqXFB!N8Xx(_MfWdESNNkI*IeDO z1-jx+y5c9?PC;{Zfd_Q{dYyh&H)N+Sr$#q`4_fU8@U|wb5x}uMC2li;D;KyP&47*whl<1)`iAa329+BsC z!%pi8*6D`vhL&x2Mf*skZs;EJO8)-3#~XA*GPDm&)A9b=t}2G{mkf(_MT7MSn7ZY> zQfQ|?rz`qE`^HCls!H^b|EL>Yqo-`A<{mv#Rk{Js=_x$V?k4qa2xI&uuvr_d)-7wH zN1%spScQ(S(+xbW*WO^?$mvzEK--1s5vtb>->gUEgl^Ct-I2svJ-6|?zz=lGYjn@v z)#=ytNPMOnkfAFWrl+P_S8zpFkf=wbUN`W(PXA1gz+hcpZJ0J#trdy7qGOt;^_=lt zK6|7N=&9j#Ks#Qq8+t-dNq^r|=!Txq9jM^MC?kDYkMI>|3TlmCeNLhqlCN93Sud9m z?X5j@#re9x9@?7+>xPZgQxLBkNz~C^``cfS=yer zzwN0xts7LOD_E?j$fFz7L$jG~$Xs21Ria-1&-vD|ZutQ{r&lza>1EbTxBNTZ;{&>& zCv<}j=!!nlan8x*;o)&yuyOfdH`OrGd4aH;cwGjsJl2L7(cugeBWr&QCy=8YsY^%C zYu+tgdIHgr*Qf*KNF5QAsdDv|_nqzcD$v@8tDFW%emgxpz1&gj|0`T|<@kc6tLXm> ztG(A{yv%h04T^>wjD~%<>}KgmsNteMBRH(wSm9Vixc2HaX^dTo%N1;zW~dQtx6tJ) zh-A5BN#_@gOJhc>@PW;}h`8ridJ=Mil!F z-^thzW_}iR^N;0hxNatgd5vbaL8Ud)G?UCqtHLy!n90^^Vk3Ct)o>YkMR{_RNNJ9- z{I-nizkhUwS{fTI?82OMov%thcysbS#CS-)jczm9>qNBC*c*i#q4G09zne#X4KjmV zR=?nZ$>gj&%-|N-#K@FTgTr?C(UVpe%_7t?~SxZH84{X<@Y*#W#;GKD07mv zu7R0UBtNj>PcFET+?378rGLo4_Zu0$ac$bj+SkBr?7Gy*`niGWH7{A08<*IHGfCO=%l-1w7=ZVZC_?1M{PDvh(A4mBIP`o&mFLe0izxph9& z%<`7AclmP_-{|I{SSu>bOznRtFdZN94V^q%^!3B{gAD$D*lBv`@DJZ~jkgwrnK@qh z6$F2kct%S-8%LX1&xe^U6XiDo{ONdu&n*+IU&G9_!~{-c{$!lN=Y1=z!f-RI|BAq5 ze4(+=S8RQoapUI9m@P}j*Vvx|?eUE^+MXT3@Yt^~Td#$i9xEc&4C~0K#{{HD8g1<2 zd}T?VNWGxO;uF56JtTT7v7wn&;7<M+4t z7GbtE^Q^-WW;-+A`Z5Be0xL7p>|kAqFdJIqBh6g1y|rExBO_5<5Ji#Yib8Q(6y2jx z6kD^S%vNTJwLQu%?p%~z+{SP-*J{geRYb<afcBQrL!k#B@>4d2`@ zVuTu5+Zr*y{^Wp7R9E~fs zo{Xb$CD!MHDl0Rdkr-M zIl=l|44!U`LGvaU5e7%X;!a5 zR#X!GYj5=x6k5xG)h9_RN;31Q`L`sjimjq#!oP}selk6%vK~W0*FR3C$Z=Lo3MGA% zO!A-NX#^%)?^vk6PwbMp?t5besgY_mC*_t`2mCxj!iFXmL$p#36wYm$WM;_ z+p#;zDe5~%D_`HPbAs~y>3Sz9-(2qL1m#Df7CPDFyRkep`56>zOiT9iSDWz# zIqRcbijWVmDy&xs^5KZ}Vy@}s(-G?;yt z@?x+K%8SpvY^`flku@d{L)kmuv#Rnily`d4tn(5KVI@S_L04?Cbq+(`tg#s)?;E}6 zBuy!?I_Hx#TXTVCo#t}QHJTeVw`xAB`K0Cn&7%%O;W3Ri;()vAm$dW|K(yf(Uz|eR!;G#b%mo zQYY)hVzY5j4Exak6r0T~SBaTvWtNx)M@E#GdtK`WUHadCE%r!qNAuI57&a**9r?*+ ze+Ff|lwie_bK+}WX7wyLJLmtvDPb))X4l!u%du&nY=8gI*g~F%5gF^%$QtBN$Xe@( uax>@1rE>FvnYaYSVq_5_Prd4pdgNZ~Y*(|@f$kAz$X24; Date: Fri, 3 Aug 2018 12:51:49 +1000 Subject: [PATCH 1241/2058] ExtendedServices: Update services other tab layout --- plugins/ExtendedServices/other.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/plugins/ExtendedServices/other.c b/plugins/ExtendedServices/other.c index fafe5dc61678..93a35003787b 100644 --- a/plugins/ExtendedServices/other.c +++ b/plugins/ExtendedServices/other.c @@ -37,7 +37,7 @@ typedef struct _SERVICE_OTHER_CONTEXT }; HWND PrivilegesLv; PPH_LIST PrivilegeList; - + PH_LAYOUT_MANAGER LayoutManager; ULONG OriginalLaunchProtected; } SERVICE_OTHER_CONTEXT, *PSERVICE_OTHER_CONTEXT; @@ -381,11 +381,18 @@ INT_PTR CALLBACK EspServiceOtherDlgProc( context->Ready = TRUE; + PhInitializeLayoutManager(&context->LayoutManager, hwndDlg); + PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_PRIVILEGES), NULL, PH_ANCHOR_ALL); + PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_ADD), NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_RIGHT); + PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_REMOVE), NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_RIGHT); + PhInitializeWindowTheme(hwndDlg, !!PhGetIntegerSetting(L"EnableThemeSupport")); } break; case WM_DESTROY: { + PhDeleteLayoutManager(&context->LayoutManager); + if (context->PrivilegeList) { PhDereferenceObjects(context->PrivilegeList->Items, context->PrivilegeList->Count); @@ -728,7 +735,12 @@ INT_PTR CALLBACK EspServiceOtherDlgProc( } } break; + case WM_SIZE: + { + PhLayoutManagerLayout(&context->LayoutManager); + } + break; } return FALSE; -} \ No newline at end of file +} From 55f1b4ab8f0c4503a01aa2748465a7fe68c04f1b Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 3 Aug 2018 15:01:23 +1000 Subject: [PATCH 1242/2058] NetworkTools: Fix tracert theme support --- plugins/NetworkTools/country.c | 5 +---- plugins/NetworkTools/ping.c | 2 +- plugins/NetworkTools/tracert.c | 2 +- plugins/NetworkTools/update.c | 13 ++++--------- plugins/NetworkTools/whois.c | 34 ++++++++++++++++++++++++++-------- 5 files changed, 33 insertions(+), 23 deletions(-) diff --git a/plugins/NetworkTools/country.c b/plugins/NetworkTools/country.c index 8cbcf4fbd088..e8611b915e23 100644 --- a/plugins/NetworkTools/country.c +++ b/plugins/NetworkTools/country.c @@ -38,10 +38,7 @@ VOID LoadGeoLiteDb( dbpath = PhGetExpandStringSetting(SETTING_NAME_DB_LOCATION); if (PhIsNullOrEmptyString(dbpath)) - { - PH_STRINGREF defaultDbPathSr = PH_STRINGREF_INIT(L"%APPDATA%\\Process Hacker\\GeoLite2-Country.mmdb"); - PhMoveReference(&dbpath, PhExpandEnvironmentStrings(&defaultDbPathSr)); - } + return; if (MMDB_open(PhGetString(dbpath), MMDB_MODE_MMAP, &GeoDb) == MMDB_SUCCESS) { diff --git a/plugins/NetworkTools/ping.c b/plugins/NetworkTools/ping.c index 3261f0800dc7..d0d722780921 100644 --- a/plugins/NetworkTools/ping.c +++ b/plugins/NetworkTools/ping.c @@ -603,4 +603,4 @@ VOID ShowPingWindowFromAddress( context->RemoteEndpoint = RemoteEndpoint; PhCreateThread2(NetworkPingDialogThreadStart, (PVOID)context); -} \ No newline at end of file +} diff --git a/plugins/NetworkTools/tracert.c b/plugins/NetworkTools/tracert.c index 719d73f9ab29..df92a503dc60 100644 --- a/plugins/NetworkTools/tracert.c +++ b/plugins/NetworkTools/tracert.c @@ -887,4 +887,4 @@ VOID ShowTracertWindowFromAddress( } PhCreateThread2(TracertDialogThreadStart, (PVOID)context); -} \ No newline at end of file +} diff --git a/plugins/NetworkTools/update.c b/plugins/NetworkTools/update.c index 6616e5fb36ef..fca4731661d3 100644 --- a/plugins/NetworkTools/update.c +++ b/plugins/NetworkTools/update.c @@ -333,7 +333,7 @@ NTSTATUS GeoIPUpdateThread( goto CleanupExit; } - downloadedBytes += (DWORD)isb.Information; + downloadedBytes += (ULONG)isb.Information; // Check the number of bytes written are the same we downloaded. if (bytesDownloaded != isb.Information) @@ -375,11 +375,7 @@ NTSTATUS GeoIPUpdateThread( dbpath = PhGetExpandStringSetting(SETTING_NAME_DB_LOCATION); if (PhIsNullOrEmptyString(dbpath)) - { - PH_STRINGREF defaultDbPathSr = PH_STRINGREF_INIT(L"%APPDATA%\\Process Hacker\\GeoLite2-Country.mmdb"); - - PhMoveReference(&dbpath, PhExpandEnvironmentStrings(&defaultDbPathSr)); - } + goto CleanupExit; if (RtlDoesFileExists_U(PhGetString(dbpath))) { @@ -388,11 +384,10 @@ NTSTATUS GeoIPUpdateThread( } else { - // Create the directory if it does not exist. - PPH_STRING fullPath; ULONG indexOfFileName; + // Create the directory if it does not exist. if (fullPath = PhGetFullPath(dbpath->Buffer, &indexOfFileName)) { if (indexOfFileName != -1) @@ -607,4 +602,4 @@ VOID ShowGeoIPUpdateDialog( ) { PhCreateThread2(GeoIPUpdateDialogThread, Parent); -} \ No newline at end of file +} diff --git a/plugins/NetworkTools/whois.c b/plugins/NetworkTools/whois.c index e315d3b09443..41834bec4169 100644 --- a/plugins/NetworkTools/whois.c +++ b/plugins/NetworkTools/whois.c @@ -29,16 +29,34 @@ VOID RichEditSetText( _In_ PWSTR Text ) { - SendMessage(RichEditHandle, WM_SETREDRAW, FALSE, 0); + if (!!PhGetIntegerSetting(L"EnableThemeSupport")) + { + CHARFORMAT cf; - // Update the Richedit text. - SendMessage(RichEditHandle, EM_REPLACESEL, FALSE, (LPARAM)Text); - // NOTE: EM_LINESCROLL and WM_VSCROLL won't update the scroll position - // if the Richedit control doesn't have keyboard focus (e.g. SetFocus). - SendMessage(RichEditHandle, WM_VSCROLL, SB_TOP, 0); + memset(&cf, 0, sizeof(CHARFORMAT)); + cf.cbSize = sizeof(CHARFORMAT); + cf.dwMask = CFM_COLOR; + + switch (PhGetIntegerSetting(L"GraphColorMode")) + { + case 0: // New colors + cf.crTextColor = RGB(0x0, 0x0, 0x0); + break; + case 1: // Old colors + cf.crTextColor = RGB(0xff, 0xff, 0xff); + break; + } + + SendMessage(RichEditHandle, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM)&cf); + } - // Redraw the Richedit with the new text. + SetFocus(RichEditHandle); + SendMessage(RichEditHandle, WM_SETREDRAW, FALSE, 0); + SendMessage(RichEditHandle, EM_SETSEL, -2, -1); + SendMessage(RichEditHandle, EM_REPLACESEL, FALSE, (LPARAM)Text); + SendMessage(RichEditHandle, WM_VSCROLL, SB_TOP, 0); // requires SetFocus() SendMessage(RichEditHandle, WM_SETREDRAW, TRUE, 0); + InvalidateRect(RichEditHandle, NULL, FALSE); } @@ -590,4 +608,4 @@ VOID ShowWhoisWindowFromAddress( } PhCreateThread2(NetworkWhoisDialogThreadStart, (PVOID)context); -} \ No newline at end of file +} From 08faa4dd72ccd3070a3c23a89b9176bc045ff4a1 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 3 Aug 2018 15:06:28 +1000 Subject: [PATCH 1243/2058] Add theme fixes, Add context menu theme support --- ProcessHacker/mainwnd.c | 2 +- ProcessHacker/miniinfo.c | 2 +- phlib/emenu.c | 28 +- phlib/include/guisup.h | 17 +- phlib/theme.c | 859 ++++++++++++++++++++++++++++++--------- phlib/treenew.c | 18 +- 6 files changed, 725 insertions(+), 201 deletions(-) diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index d9a2aefd6012..408a91ffb028 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -419,7 +419,7 @@ VOID PhMwpInitializeControls( BringWindowToTop(TabControlHandle); thinRows = PhGetIntegerSetting(L"ThinRows") ? TN_STYLE_THIN_ROWS : 0; - treelistBorder = PhGetIntegerSetting(L"TreeListBorderEnable") ? WS_BORDER : 0; + treelistBorder = (PhGetIntegerSetting(L"TreeListBorderEnable") && !PhEnableThemeSupport) ? WS_BORDER : 0; treelistCustomColors = PhGetIntegerSetting(L"TreeListCustomColorsEnable") ? TN_STYLE_CUSTOM_COLORS : 0; if (treelistCustomColors) diff --git a/ProcessHacker/miniinfo.c b/ProcessHacker/miniinfo.c index bcb857c65571..b346b0f06a8f 100644 --- a/ProcessHacker/miniinfo.c +++ b/ProcessHacker/miniinfo.c @@ -777,7 +777,7 @@ VOID PhMipInitializeParameters( hdc = GetDC(PhMipWindow); - logFont.lfHeight -= PhMultiplyDivide(2, GetDeviceCaps(hdc, LOGPIXELSY), 72); + logFont.lfHeight -= PhMultiplyDivide(2, PhGlobalDpi, 72); CurrentParameters.MediumFont = CreateFontIndirect(&logFont); originalFont = SelectObject(hdc, CurrentParameters.Font); diff --git a/phlib/emenu.c b/phlib/emenu.c index 7534f4225824..46f5ff42468c 100644 --- a/phlib/emenu.c +++ b/phlib/emenu.c @@ -22,7 +22,7 @@ #include #include - +#include #include static const PH_FLAG_MAPPING EMenuTypeMappings[] = @@ -459,6 +459,13 @@ HMENU PhEMenuToHMenu( menuInfo.cbSize = sizeof(MENUINFO); menuInfo.fMask = MIM_STYLE; menuInfo.dwStyle = MNS_CHECKORBMP; + + if (PhGetIntegerSetting(L"EnableThemeSupport")) + { + menuInfo.fMask |= MIM_BACKGROUND; + menuInfo.hbrBack = PhMenuBackgroundBrush; + } + SetMenuInfo(menuHandle, &menuInfo); } @@ -520,7 +527,9 @@ VOID PhEMenuToHMenu2( if (item->Bitmap) { - menuItemInfo.fMask |= MIIM_BITMAP; + if (!PhGetIntegerSetting(L"EnableThemeSupport")) + menuItemInfo.fMask |= MIIM_BITMAP; // HACK + menuItemInfo.hbmpItem = item->Bitmap; } @@ -570,6 +579,21 @@ VOID PhEMenuToHMenu2( menuItemInfo.hSubMenu = PhEMenuToHMenu(item, Flags, Data); } + // Theme + + if (PhGetIntegerSetting(L"EnableThemeSupport")) // HACK + { + switch (PhGetIntegerSetting(L"GraphColorMode")) + { + case 0: // New colors + menuItemInfo.fType |= MFT_OWNERDRAW; + break; + case 1: // Old colors + menuItemInfo.fType |= MFT_OWNERDRAW; + break; + } + } + InsertMenuItem(MenuHandle, MAXINT, TRUE, &menuItemInfo); } } diff --git a/phlib/include/guisup.h b/phlib/include/guisup.h index d6b865c878f2..d68db82f5361 100644 --- a/phlib/include/guisup.h +++ b/phlib/include/guisup.h @@ -901,6 +901,7 @@ PhWindowNotifyTopMostEvent( PHLIBAPI extern HFONT PhApplicationFont; // phapppub PHLIBAPI extern HFONT PhTreeWindowFont; // phapppub +PHLIBAPI extern HBRUSH PhMenuBackgroundBrush; PHLIBAPI VOID @@ -917,6 +918,20 @@ PhReInitializeWindowTheme( _In_ HWND WindowHandle ); +PHLIBAPI +BOOLEAN +NTAPI +PhThemeWindowDrawItem( + _In_ PDRAWITEMSTRUCT DrawInfo + ); + +PHLIBAPI +BOOLEAN +NTAPI +PhThemeWindowMeasureItem( + _In_ PMEASUREITEMSTRUCT DrawInfo + ); + PHLIBAPI VOID NTAPI @@ -946,4 +961,4 @@ PhDuplicateFontWithNewHeight( } #endif -#endif \ No newline at end of file +#endif diff --git a/phlib/theme.c b/phlib/theme.c index d9a3f0dab35b..422722a33200 100644 --- a/phlib/theme.c +++ b/phlib/theme.c @@ -90,6 +90,9 @@ LRESULT CALLBACK PhpThemeWindowStatusbarWndSubclassProc( _In_ LPARAM lParam ); +ULONG PhpThemeColorMode = 0; +BOOLEAN PhpThemeBorderEnable = TRUE; +HBRUSH PhMenuBackgroundBrush = NULL; COLORREF PhpThemeWindowForegroundColor = RGB(28, 28, 28); COLORREF PhpThemeWindowBackgroundColor = RGB(64, 64, 64); COLORREF PhpThemeWindowTextColor = RGB(0xff, 0xff, 0xff); @@ -97,6 +100,7 @@ HFONT PhpTabControlFontHandle = NULL; HFONT PhpToolBarFontHandle = NULL; HFONT PhpHeaderFontHandle = NULL; HFONT PhpListViewFontHandle = NULL; +HFONT PhpMenuFontHandle = NULL; HFONT PhpGroupboxFontHandle = NULL; HFONT PhpStatusBarFontHandle = NULL; @@ -105,6 +109,22 @@ VOID PhInitializeWindowTheme( _In_ BOOLEAN EnableThemeSupport ) { + PhpThemeColorMode = PhGetIntegerSetting(L"GraphColorMode"); + PhpThemeBorderEnable = !!PhGetIntegerSetting(L"TreeListBorderEnable"); + + if (!PhMenuBackgroundBrush) // HACK + { + switch (PhpThemeColorMode) // HACK + { + case 0: // New colors + PhMenuBackgroundBrush = CreateSolidBrush(PhpThemeWindowTextColor); + break; + case 1: // Old colors + PhMenuBackgroundBrush = CreateSolidBrush(PhpThemeWindowForegroundColor); + break; + } + } + if (EnableThemeSupport) { WNDPROC defaultWindowProc; @@ -134,6 +154,27 @@ VOID PhReInitializeWindowTheme( { HWND currentWindow = NULL; + // HACK + { + if (PhMenuBackgroundBrush) + { + DeleteBrush(PhMenuBackgroundBrush); + } + + PhpThemeColorMode = PhGetIntegerSetting(L"GraphColorMode"); + PhpThemeBorderEnable = !!PhGetIntegerSetting(L"TreeListBorderEnable"); + + switch (PhpThemeColorMode) + { + case 0: // New colors + PhMenuBackgroundBrush = CreateSolidBrush(PhpThemeWindowTextColor); + break; + case 1: // Old colors + PhMenuBackgroundBrush = CreateSolidBrush(PhpThemeWindowForegroundColor); + break; + } + } + PhEnumChildWindows( WindowHandle, 0x1000, @@ -151,8 +192,26 @@ VOID PhReInitializeWindowTheme( if (UlongToHandle(processID) == NtCurrentProcessId()) { + WCHAR windowClassName[MAX_PATH]; + + if (!GetClassName(currentWindow, windowClassName, RTL_NUMBER_OF(windowClassName))) + windowClassName[0] = 0; + + //dprintf("PhReInitializeWindowTheme: %S\r\n", windowClassName); + if (currentWindow != WindowHandle) { + if (PhEqualStringZ(windowClassName, L"#32770", FALSE)) + { + PhEnumChildWindows( + currentWindow, + 0x1000, + PhpReInitializeThemeWindowEnumChildWindows, + 0 + ); + //PhReInitializeWindowTheme(currentWindow); + } + InvalidateRect(currentWindow, NULL, TRUE); } } @@ -183,6 +242,9 @@ VOID PhInitializeThemeWindowTabControl( { PPHP_THEME_WINDOW_TAB_CONTEXT tabControlContext; + if (!PhpTabControlFontHandle) + PhpTabControlFontHandle = PhDuplicateFontWithNewHeight(PhApplicationFont, 15); + tabControlContext = PhAllocateZero(sizeof(PHP_THEME_WINDOW_TAB_CONTEXT)); tabControlContext->DefaultWindowProc = (WNDPROC)GetWindowLongPtr(TabControlWindow, GWLP_WNDPROC); @@ -191,26 +253,6 @@ VOID PhInitializeThemeWindowTabControl( PhSetWindowStyle(TabControlWindow, TCS_OWNERDRAWFIXED, TCS_OWNERDRAWFIXED); - if (!PhpTabControlFontHandle) - { - PhpTabControlFontHandle = CreateFont( - -PhMultiplyDivideSigned(-14, PhGlobalDpi, 96), - 0, - 0, - 0, - FW_SEMIBOLD, - FALSE, - FALSE, - FALSE, - ANSI_CHARSET, - OUT_DEFAULT_PRECIS, - CLIP_DEFAULT_PRECIS, - DEFAULT_QUALITY, - DEFAULT_PITCH, - L"Tahoma" - ); - } - SendMessage(TabControlWindow, WM_SETFONT, (WPARAM)PhpTabControlFontHandle, FALSE); InvalidateRect(TabControlWindow, NULL, FALSE); @@ -265,7 +307,9 @@ BOOLEAN CALLBACK PhpThemeWindowEnumChildWindows( if (!GetClassName(WindowHandle, windowClassName, RTL_NUMBER_OF(windowClassName))) windowClassName[0] = 0; - if (PhEqualStringZ(windowClassName, L"#32770", FALSE)) + //dprintf("PhpThemeWindowEnumChildWindows: %S\r\n", windowClassName); + + if (PhEqualStringZ(windowClassName, L"#32770", TRUE)) { PhInitializeWindowTheme(WindowHandle, TRUE); } @@ -278,22 +322,6 @@ BOOLEAN CALLBACK PhpThemeWindowEnumChildWindows( PhInitializeThemeWindowGroupBox(WindowHandle); } } - else if (PhEqualStringZ(windowClassName, L"Edit", FALSE)) - { - switch (PhGetIntegerSetting(L"GraphColorMode")) - { - case 0: // New colors - //PhSetWindowStyle(WindowHandle, WS_BORDER, WS_BORDER); - //PhSetWindowExStyle(WindowHandle, WS_EX_CLIENTEDGE, WS_EX_CLIENTEDGE); - break; - case 1: // Old colors - //PhSetWindowStyle(WindowHandle, WS_BORDER, 0); - //PhSetWindowExStyle(WindowHandle, WS_EX_CLIENTEDGE, 0); - break; - } - - //InvalidateRect(WindowHandle, NULL, FALSE); - } else if (PhEqualStringZ(windowClassName, L"SysTabControl32", FALSE)) { PhInitializeThemeWindowTabControl(WindowHandle); @@ -302,18 +330,39 @@ BOOLEAN CALLBACK PhpThemeWindowEnumChildWindows( { PhInitializeWindowThemeStatusBar(WindowHandle); } - else if (PhEqualStringZ(windowClassName, L"SysHeader32", FALSE)) + else if (PhEqualStringZ(windowClassName, L"Edit", TRUE)) + { + NOTHING; + } + else if (PhEqualStringZ(windowClassName, L"ScrollBar", FALSE)) + { + NOTHING; + } + else if (PhEqualStringZ(windowClassName, L"SysHeader32", TRUE)) { PhInitializeThemeWindowHeader(WindowHandle); } else if (PhEqualStringZ(windowClassName, L"SysListView32", FALSE)) { - //PhSetWindowStyle(WindowHandle, WS_BORDER, 0); - //PhSetWindowExStyle(WindowHandle, WS_EX_CLIENTEDGE, 0); + if (PhpThemeBorderEnable) + { + PhSetWindowStyle(WindowHandle, WS_BORDER, WS_BORDER); + PhSetWindowExStyle(WindowHandle, WS_EX_CLIENTEDGE, WS_EX_CLIENTEDGE); + } + else + { + PhSetWindowStyle(WindowHandle, WS_BORDER, 0); + PhSetWindowExStyle(WindowHandle, WS_EX_CLIENTEDGE, 0); + } + + SetWindowPos(WindowHandle, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_FRAMECHANGED); - switch (PhGetIntegerSetting(L"GraphColorMode")) + switch (PhpThemeColorMode) { case 0: // New colors + ListView_SetBkColor(WindowHandle, RGB(0xff, 0xff, 0xff)); + ListView_SetTextBkColor(WindowHandle, RGB(0xff, 0xff, 0xff)); + ListView_SetTextColor(WindowHandle, RGB(0x0, 0x0, 0x0)); break; case 1: // Old colors ListView_SetBkColor(WindowHandle, RGB(30, 30, 30)); @@ -322,14 +371,11 @@ BOOLEAN CALLBACK PhpThemeWindowEnumChildWindows( break; } - InvalidateRect(WindowHandle, NULL, FALSE); + //InvalidateRect(WindowHandle, NULL, FALSE); } else if (PhEqualStringZ(windowClassName, L"SysTreeView32", FALSE)) { - //PhSetWindowStyle(WindowHandle, WS_BORDER, 0); - //PhSetWindowExStyle(WindowHandle, WS_EX_CLIENTEDGE, 0); - - switch (PhGetIntegerSetting(L"GraphColorMode")) + switch (PhpThemeColorMode) { case 0: // New colors break; @@ -340,27 +386,50 @@ BOOLEAN CALLBACK PhpThemeWindowEnumChildWindows( break; } - InvalidateRect(WindowHandle, NULL, FALSE); + //InvalidateRect(WindowHandle, NULL, FALSE); + } + else if (PhEqualStringZ(windowClassName, L"RICHEDIT50W", FALSE)) + { + if (PhpThemeBorderEnable) + PhSetWindowStyle(WindowHandle, WS_BORDER, WS_BORDER); + else + PhSetWindowStyle(WindowHandle, WS_BORDER, 0); + + SetWindowPos(WindowHandle, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_FRAMECHANGED); + +#define EM_SETBKGNDCOLOR (WM_USER + 67) + switch (PhpThemeColorMode) + { + case 0: // New colors + SendMessage(WindowHandle, EM_SETBKGNDCOLOR, 0, RGB(0xff, 0xff, 0xff)); + break; + case 1: // Old colors + SendMessage(WindowHandle, EM_SETBKGNDCOLOR, 0, RGB(30, 30, 30)); + break; + } + + //InvalidateRect(WindowHandle, NULL, FALSE); } else if (PhEqualStringZ(windowClassName, L"PhTreeNew", FALSE)) { - switch (PhGetIntegerSetting(L"GraphColorMode")) + if (PhpThemeBorderEnable) + PhSetWindowExStyle(WindowHandle, WS_EX_CLIENTEDGE, WS_EX_CLIENTEDGE); + else + PhSetWindowExStyle(WindowHandle, WS_EX_CLIENTEDGE, 0); + + SetWindowPos(WindowHandle, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_FRAMECHANGED); + + switch (PhpThemeColorMode) { case 0: // New colors - //PhSetWindowStyle(WindowHandle, WS_BORDER, WS_BORDER); - //PhSetWindowExStyle(WindowHandle, WS_EX_CLIENTEDGE, WS_EX_CLIENTEDGE); TreeNew_ThemeSupport(WindowHandle, FALSE); break; case 1: // Old colors - //PhSetWindowStyle(WindowHandle, WS_BORDER, 0); - //PhSetWindowExStyle(WindowHandle, WS_EX_CLIENTEDGE, 0); TreeNew_ThemeSupport(WindowHandle, TRUE); break; } - } - else if (PhEqualStringZ(windowClassName, L"ScrollBar", FALSE)) - { - NOTHING; + + //InvalidateRect(WindowHandle, NULL, TRUE); } return TRUE; @@ -383,9 +452,27 @@ BOOLEAN CALLBACK PhpReInitializeThemeWindowEnumChildWindows( if (!GetClassName(WindowHandle, windowClassName, RTL_NUMBER_OF(windowClassName))) windowClassName[0] = 0; - if (PhEqualStringZ(windowClassName, L"PhTreeNew", FALSE)) + //dprintf("PhpReInitializeThemeWindowEnumChildWindows: %S\r\n", windowClassName); + + if (PhEqualStringZ(windowClassName, L"SysListView32", FALSE)) { - switch (PhGetIntegerSetting(L"GraphColorMode")) + switch (PhpThemeColorMode) + { + case 0: // New colors + ListView_SetBkColor(WindowHandle, RGB(0xff, 0xff, 0xff)); + ListView_SetTextBkColor(WindowHandle, RGB(0xff, 0xff, 0xff)); + ListView_SetTextColor(WindowHandle, RGB(0x0, 0x0, 0x0)); + break; + case 1: // Old colors + ListView_SetBkColor(WindowHandle, RGB(30, 30, 30)); + ListView_SetTextBkColor(WindowHandle, RGB(30, 30, 30)); + ListView_SetTextColor(WindowHandle, RGB(0xff, 0xff, 0xff)); + break; + } + } + else if (PhEqualStringZ(windowClassName, L"PhTreeNew", FALSE)) + { + switch (PhpThemeColorMode) { case 0: // New colors TreeNew_ThemeSupport(WindowHandle, FALSE); @@ -396,11 +483,334 @@ BOOLEAN CALLBACK PhpReInitializeThemeWindowEnumChildWindows( } } - InvalidateRect(WindowHandle, NULL, FALSE); + InvalidateRect(WindowHandle, NULL, TRUE); return TRUE; } +BOOLEAN PhThemeWindowDrawItem( + _In_ PDRAWITEMSTRUCT DrawInfo + ) +{ + BOOLEAN isGrayed = (DrawInfo->itemState & CDIS_GRAYED) == CDIS_GRAYED; + BOOLEAN isChecked = (DrawInfo->itemState & CDIS_CHECKED) == CDIS_CHECKED; + BOOLEAN isDisabled = (DrawInfo->itemState & CDIS_DISABLED) == CDIS_DISABLED; + BOOLEAN isSelected = (DrawInfo->itemState & CDIS_SELECTED) == CDIS_SELECTED; + //BOOLEAN isHighlighted = (DrawInfo->itemState & CDIS_HOT) == CDIS_HOT; + BOOLEAN isFocused = (DrawInfo->itemState & CDIS_FOCUS) == CDIS_FOCUS; + //BOOLEAN isGrayed = (DrawInfo->itemState & ODS_GRAYED) == ODS_GRAYED; + //BOOLEAN isChecked = (DrawInfo->itemState & ODS_CHECKED) == ODS_CHECKED; + //BOOLEAN isDisabled = (DrawInfo->itemState & ODS_DISABLED) == ODS_DISABLED; + //BOOLEAN isSelected = (DrawInfo->itemState & ODS_SELECTED) == ODS_SELECTED; + BOOLEAN isHighlighted = (DrawInfo->itemState & ODS_HOTLIGHT) == ODS_HOTLIGHT; + + SetBkMode(DrawInfo->hDC, TRANSPARENT); + + switch (DrawInfo->CtlType) + { + case ODT_STATIC: + break; + case ODT_HEADER: + { + HDITEM headerItem; + WCHAR headerText[MAX_PATH]; + + SetTextColor(DrawInfo->hDC, GetSysColor(COLOR_HIGHLIGHTTEXT)); + SetDCBrushColor(DrawInfo->hDC, RGB(30, 30, 30)); + + FillRect(DrawInfo->hDC, &DrawInfo->rcItem, GetStockObject(DC_BRUSH)); + DrawEdge(DrawInfo->hDC, &DrawInfo->rcItem, BDR_RAISEDOUTER, BF_RIGHT); + + memset(headerText, 0, sizeof(headerText)); + memset(&headerItem, 0, sizeof(HDITEM)); + headerItem.mask = HDI_TEXT; + headerItem.cchTextMax = RTL_NUMBER_OF(headerText); + headerItem.pszText = headerText; + + if (Header_GetItem(DrawInfo->hwndItem, DrawInfo->itemID, &headerItem)) + { + DrawText( + DrawInfo->hDC, + headerText, + (UINT)PhCountStringZ(headerText), + &DrawInfo->rcItem, + DT_LEFT | DT_END_ELLIPSIS | DT_SINGLELINE //DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_HIDEPREFIX | DT_NOCLIP + ); + } + } + return TRUE; + case ODT_MENU: + { + PPH_EMENU_ITEM menuItemInfo = (PPH_EMENU_ITEM)DrawInfo->itemData; + + //FillRect( + // DrawInfo->hDC, + // &DrawInfo->rcItem, + // CreateSolidBrush(RGB(0, 0, 0)) + // ); + //SetTextColor(DrawInfo->hDC, RGB(0xff, 0xff, 0xff)); + + if (isDisabled) + { + switch (PhpThemeColorMode) + { + case 0: // New colors + SetTextColor(DrawInfo->hDC, GetSysColor(COLOR_GRAYTEXT)); + SetDCBrushColor(DrawInfo->hDC, RGB(0xff, 0xff, 0xff)); + break; + case 1: // Old colors + SetTextColor(DrawInfo->hDC, GetSysColor(COLOR_GRAYTEXT)); + SetDCBrushColor(DrawInfo->hDC, RGB(28, 28, 28)); + break; + } + + FillRect(DrawInfo->hDC, &DrawInfo->rcItem, GetStockObject(DC_BRUSH)); + } + else if (isSelected) + { + switch (PhpThemeColorMode) + { + case 0: // New colors + SetTextColor(DrawInfo->hDC, PhpThemeWindowTextColor); + SetDCBrushColor(DrawInfo->hDC, PhpThemeWindowBackgroundColor); + break; + case 1: // Old colors + SetTextColor(DrawInfo->hDC, RGB(0xff, 0xff, 0xff)); + SetDCBrushColor(DrawInfo->hDC, RGB(128, 128, 128)); + break; + } + + FillRect(DrawInfo->hDC, &DrawInfo->rcItem, GetStockObject(DC_BRUSH)); + } + else + { + switch (PhpThemeColorMode) + { + case 0: // New colors + SetTextColor(DrawInfo->hDC, GetSysColor(COLOR_WINDOWTEXT)); + SetDCBrushColor(DrawInfo->hDC, RGB(0xff, 0xff, 0xff)); + break; + case 1: // Old colors + SetTextColor(DrawInfo->hDC, GetSysColor(COLOR_HIGHLIGHTTEXT)); + SetDCBrushColor(DrawInfo->hDC, RGB(28, 28, 28)); + break; + } + + FillRect(DrawInfo->hDC, &DrawInfo->rcItem, GetStockObject(DC_BRUSH)); + } + + if (isChecked) + { + static PH_STRINGREF menuCheckText = PH_STRINGREF_INIT(L"\u2713"); + COLORREF oldTextColor; + + //HFONT marlettFontHandle = CreateFont( + // 0, 0, 0, 0, + // FW_DONTCARE, + // FALSE, + // FALSE, + // FALSE, + // DEFAULT_CHARSET, + // OUT_OUTLINE_PRECIS, + // CLIP_DEFAULT_PRECIS, + // CLEARTYPE_QUALITY, + // VARIABLE_PITCH, + // L"Arial Unicode MS" + // ); + + switch (PhpThemeColorMode) + { + case 0: // New colors + oldTextColor = SetTextColor(DrawInfo->hDC, GetSysColor(COLOR_WINDOWTEXT)); + break; + case 1: // Old colors + oldTextColor = SetTextColor(DrawInfo->hDC, RGB(0xff, 0xff, 0xff)); + //FillRect(DrawInfo->hDC, &DrawInfo->rcItem, GetStockObject(DC_BRUSH)); + //SetTextColor(DrawInfo->hDC, RGB(0xff, 0xff, 0xff)); + break; + } + + DrawInfo->rcItem.left += 8; + DrawInfo->rcItem.top += 3; + DrawText( + DrawInfo->hDC, + menuCheckText.Buffer, + (UINT)menuCheckText.Length / sizeof(WCHAR), + &DrawInfo->rcItem, + DT_VCENTER | DT_NOCLIP + ); + DrawInfo->rcItem.left -= 8; + DrawInfo->rcItem.top -= 3; + + SetTextColor(DrawInfo->hDC, oldTextColor); + } + + if (menuItemInfo->Flags & PH_EMENU_SEPARATOR) + { + switch (PhpThemeColorMode) + { + case 0: // New colors + SetDCBrushColor(DrawInfo->hDC, RGB(0xff, 0xff, 0xff)); + FillRect(DrawInfo->hDC, &DrawInfo->rcItem, GetStockObject(DC_BRUSH)); + break; + case 1: // Old colors + SetDCBrushColor(DrawInfo->hDC, RGB(28, 28, 28)); + FillRect(DrawInfo->hDC, &DrawInfo->rcItem, GetStockObject(DC_BRUSH)); + break; + } + + //DrawInfo->rcItem.top += 1; + //DrawInfo->rcItem.bottom -= 2; + //DrawFocusRect(drawInfo->hDC, &drawInfo->rcItem); + + SetRect( + &DrawInfo->rcItem, + DrawInfo->rcItem.left + 25, + DrawInfo->rcItem.top + 2, + DrawInfo->rcItem.right, + DrawInfo->rcItem.bottom - 2 + ); + + switch (PhpThemeColorMode) + { + case 0: // New colors + SetDCBrushColor(DrawInfo->hDC, RGB(0xff, 0xff, 0xff)); + FillRect(DrawInfo->hDC, &DrawInfo->rcItem, GetStockObject(DC_BRUSH)); + break; + case 1: // Old colors + SetDCBrushColor(DrawInfo->hDC, RGB(78, 78, 78)); + FillRect(DrawInfo->hDC, &DrawInfo->rcItem, GetStockObject(DC_BRUSH)); + break; + } + + //DrawEdge(drawInfo->hDC, &drawInfo->rcItem, BDR_RAISEDINNER, BF_TOP); + } + else + { + PH_STRINGREF part; + PH_STRINGREF firstPart; + PH_STRINGREF secondPart; + + PhInitializeStringRef(&part, menuItemInfo->Text); + PhSplitStringRefAtLastChar(&part, '\b', &firstPart, &secondPart); + + //SetDCBrushColor(DrawInfo->hDC, RGB(28, 28, 28)); + //FillRect(DrawInfo->hDC, &DrawInfo->rcItem, GetStockObject(DC_BRUSH)); + + if (menuItemInfo->Bitmap) + { + HDC hdcMem; + BLENDFUNCTION blendFunction; + + blendFunction.BlendOp = AC_SRC_OVER; + blendFunction.BlendFlags = 0; + blendFunction.SourceConstantAlpha = 255; + blendFunction.AlphaFormat = AC_SRC_ALPHA; + + hdcMem = CreateCompatibleDC(DrawInfo->hDC); + SelectBitmap(hdcMem, menuItemInfo->Bitmap); + + GdiAlphaBlend( + DrawInfo->hDC, + DrawInfo->rcItem.left + 4, + DrawInfo->rcItem.top + 4, + 16, + 16, + hdcMem, + 0, + 0, + 16, + 16, + blendFunction + ); + + DeleteDC(hdcMem); + } + + DrawInfo->rcItem.left += 25; + DrawInfo->rcItem.right -= 25; + + DrawText( + DrawInfo->hDC, + firstPart.Buffer, + (UINT)firstPart.Length / sizeof(WCHAR), + &DrawInfo->rcItem, + DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_HIDEPREFIX | DT_NOCLIP + ); + + DrawText( + DrawInfo->hDC, + secondPart.Buffer, + (UINT)secondPart.Length / sizeof(WCHAR), + &DrawInfo->rcItem, + DT_RIGHT | DT_VCENTER | DT_SINGLELINE | DT_HIDEPREFIX | DT_NOCLIP + ); + } + + return TRUE; + } + } + + return FALSE; +} + +BOOLEAN PhThemeWindowMeasureItem( + _In_ PMEASUREITEMSTRUCT DrawInfo + ) +{ + if (DrawInfo->CtlType == ODT_MENU) + { + PPH_EMENU_ITEM menuItemInfo = (PPH_EMENU_ITEM)DrawInfo->itemData; + + DrawInfo->itemWidth = 150; + DrawInfo->itemHeight = 26; + + if ((menuItemInfo->Flags & PH_EMENU_SEPARATOR) == PH_EMENU_SEPARATOR) + { + DrawInfo->itemHeight = GetSystemMetrics(SM_CYMENU) >> 2; + } + else if (menuItemInfo->Text) + { + HDC hdc; + + if (!PhpMenuFontHandle) + { + NONCLIENTMETRICS metrics = { sizeof(NONCLIENTMETRICS) }; + + if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, &metrics, 0)) + { + PhpMenuFontHandle = CreateFontIndirect(&metrics.lfMessageFont); + } + } + + if (hdc = GetDC(NULL)) + { + PWSTR text; + SIZE_T textCount; + SIZE textSize; + HFONT oldFont; + + text = menuItemInfo->Text; + textCount = PhCountStringZ(text); + oldFont = SelectFont(hdc, PhpMenuFontHandle); + + if (GetTextExtentPoint32(hdc, text, (ULONG)textCount, &textSize)) + { + DrawInfo->itemWidth = textSize.cx + (GetSystemMetrics(SM_CYBORDER) * 2) + 90; // HACK + DrawInfo->itemHeight = GetSystemMetrics(SM_CYMENU) + (GetSystemMetrics(SM_CYBORDER) * 2) + 1; + } + + SelectFont(hdc, oldFont); + ReleaseDC(NULL, hdc); + } + } + + return TRUE; + } + + return FALSE; +} + LRESULT CALLBACK PhpThemeWindowDrawButton( _In_ LPNMCUSTOMDRAW DrawInfo ) @@ -423,7 +833,7 @@ LRESULT CALLBACK PhpThemeWindowDrawButton( if (isSelected) { - switch (PhGetIntegerSetting(L"GraphColorMode")) + switch (PhpThemeColorMode) { case 0: // New colors //SetTextColor(DrawInfo->hdc, RGB(0, 0, 0xff)); @@ -439,7 +849,7 @@ LRESULT CALLBACK PhpThemeWindowDrawButton( } else if (isHighlighted) { - switch (PhGetIntegerSetting(L"GraphColorMode")) + switch (PhpThemeColorMode) { case 0: // New colors //SetTextColor(DrawInfo->hdc, RGB(0, 0, 0xff)); @@ -455,7 +865,7 @@ LRESULT CALLBACK PhpThemeWindowDrawButton( } else { - switch (PhGetIntegerSetting(L"GraphColorMode")) + switch (PhpThemeColorMode) { case 0: // New colors //SetTextColor(DrawInfo->hdc, PhpThemeWindowTextColor); @@ -567,11 +977,11 @@ LRESULT CALLBACK PhThemeWindowDrawRebar( { case CDDS_PREPAINT: { - switch (PhGetIntegerSetting(L"GraphColorMode")) + switch (PhpThemeColorMode) { case 0: // New colors SetTextColor(DrawInfo->hdc, RGB(0x0, 0x0, 0x0)); - SetDCBrushColor(DrawInfo->hdc, RGB(0xff, 0xff, 0xff)); + SetDCBrushColor(DrawInfo->hdc, GetSysColor(COLOR_3DFACE)); // RGB(0xff, 0xff, 0xff)); break; case 1: // Old colors SetTextColor(DrawInfo->hdc, RGB(0xff, 0xff, 0xff)); @@ -584,11 +994,11 @@ LRESULT CALLBACK PhThemeWindowDrawRebar( return CDRF_NOTIFYITEMDRAW; case CDDS_ITEMPREPAINT: { - switch (PhGetIntegerSetting(L"GraphColorMode")) + switch (PhpThemeColorMode) { case 0: // New colors SetTextColor(DrawInfo->hdc, RGB(0x0, 0x0, 0x0)); - SetDCBrushColor(DrawInfo->hdc, RGB(0x0, 0x0, 0x0)); + SetDCBrushColor(DrawInfo->hdc, GetSysColor(COLOR_3DFACE)); // RGB(0x0, 0x0, 0x0)); case 1: // Old colors SetTextColor(DrawInfo->hdc, RGB(0xff, 0xff, 0xff)); SetDCBrushColor(DrawInfo->hdc, RGB(65, 65, 65)); @@ -659,7 +1069,39 @@ LRESULT CALLBACK PhThemeWindowDrawToolbar( if (isHighlighted) { - switch (PhGetIntegerSetting(L"GraphColorMode")) + //INT stateId; + + //// Themed background + + //if (node->Selected) + //{ + // if (i == Context->HotNodeIndex) + // stateId = TREIS_HOTSELECTED; + // else if (!Context->HasFocus) + // stateId = TREIS_SELECTEDNOTFOCUS; + // else + // stateId = TREIS_SELECTED; + //} + //else + //{ + // if (i == Context->HotNodeIndex) + // stateId = TREIS_HOT; + // else + // stateId = INT_MAX; + //} + + //// Themed background + + //if (stateId != INT_MAX) + { + //if (!Context->FixedColumnVisible) + //{ + // rowRect.left = Context->NormalLeft - hScrollPosition; + //} + + } + + switch (PhpThemeColorMode) { case 0: // New colors SetTextColor(DrawInfo->nmcd.hdc, PhpThemeWindowTextColor); @@ -675,11 +1117,11 @@ LRESULT CALLBACK PhThemeWindowDrawToolbar( } else { - switch (PhGetIntegerSetting(L"GraphColorMode")) + switch (PhpThemeColorMode) { case 0: // New colors SetTextColor(DrawInfo->nmcd.hdc, RGB(0x0, 0x0, 0x0)); - SetDCBrushColor(DrawInfo->nmcd.hdc, RGB(0xff, 0xff, 0xff)); + SetDCBrushColor(DrawInfo->nmcd.hdc, GetSysColor(COLOR_3DFACE));// RGB(0xff, 0xff, 0xff)); FillRect(DrawInfo->nmcd.hdc, &DrawInfo->nmcd.rc, GetStockObject(DC_BRUSH)); break; case 1: // Old colors @@ -702,9 +1144,6 @@ LRESULT CALLBACK PhThemeWindowDrawToolbar( SelectFont(DrawInfo->nmcd.hdc, PhpToolBarFontHandle); - - - if (buttonInfo.iImage != -1) { HIMAGELIST toolbarImageList; @@ -731,7 +1170,7 @@ LRESULT CALLBACK PhThemeWindowDrawToolbar( if (buttonInfo.fsStyle & BTNS_SHOWTEXT) { - WCHAR buttonText[0x100] = L""; + WCHAR buttonText[MAX_PATH] = L""; SendMessage( DrawInfo->nmcd.hdr.hwndFrom, @@ -744,7 +1183,7 @@ LRESULT CALLBACK PhThemeWindowDrawToolbar( DrawText( DrawInfo->nmcd.hdc, buttonText, - -1, + (UINT)PhCountStringZ(buttonText), &DrawInfo->nmcd.rc, DT_CENTER | DT_VCENTER | DT_SINGLELINE | DT_HIDEPREFIX ); @@ -769,7 +1208,7 @@ LRESULT CALLBACK PhpThemeWindowDrawListViewGroup( { SetBkMode(DrawInfo->nmcd.hdc, TRANSPARENT); - switch (PhGetIntegerSetting(L"GraphColorMode")) + switch (PhpThemeColorMode) { case 0: // New colors SetTextColor(DrawInfo->nmcd.hdc, RGB(0x0, 0x0, 0x0)); @@ -818,8 +1257,8 @@ LRESULT CALLBACK PhpThemeWindowDrawListViewGroup( DrawInfo->rcText.top -= 2; DrawInfo->rcText.bottom += 2; - SetTextColor(DrawInfo->nmcd.hdc, RGB(255, 69, 0)); - SetDCBrushColor(DrawInfo->nmcd.hdc, RGB(65, 65, 65)); + //SetTextColor(DrawInfo->nmcd.hdc, RGB(255, 69, 0)); + //SetDCBrushColor(DrawInfo->nmcd.hdc, RGB(65, 65, 65)); DrawInfo->rcText.left += 10; DrawText( @@ -871,7 +1310,7 @@ LRESULT CALLBACK PhpThemeWindowSubclassProc( if (!GetClassName(customDraw->hdr.hwndFrom, className, RTL_NUMBER_OF(className))) className[0] = 0; - dprintf("ClassName: %S\r\n", className); + //dprintf("NM_CUSTOMDRAW: %S\r\n", className); if (PhEqualStringZ(className, L"Button", FALSE)) { @@ -885,10 +1324,6 @@ LRESULT CALLBACK PhpThemeWindowSubclassProc( { return PhThemeWindowDrawToolbar((LPNMTBCUSTOMDRAW)customDraw); } - else if (PhEqualStringZ(className, L"SysTabControl32", FALSE)) - { - NOTHING; - } else if (PhEqualStringZ(className, L"SysListView32", FALSE)) { LPNMLVCUSTOMDRAW listViewCustomDraw = (LPNMLVCUSTOMDRAW)customDraw; @@ -906,7 +1341,7 @@ LRESULT CALLBACK PhpThemeWindowSubclassProc( { SetBkMode((HDC)wParam, TRANSPARENT); - switch (PhGetIntegerSetting(L"GraphColorMode")) + switch (PhpThemeColorMode) { case 0: // New colors SetTextColor((HDC)wParam, RGB(0x0, 0x0, 0x0)); @@ -925,7 +1360,7 @@ LRESULT CALLBACK PhpThemeWindowSubclassProc( { SetBkMode((HDC)wParam, TRANSPARENT); - switch (PhGetIntegerSetting(L"GraphColorMode")) + switch (PhpThemeColorMode) { case 0: // New colors SetTextColor((HDC)wParam, RGB(0x0, 0x0, 0x0)); @@ -938,13 +1373,21 @@ LRESULT CALLBACK PhpThemeWindowSubclassProc( } } break; + case WM_MEASUREITEM: + if (PhThemeWindowMeasureItem((LPMEASUREITEMSTRUCT)lParam)) + return TRUE; + break; + case WM_DRAWITEM: + if (PhThemeWindowDrawItem((LPDRAWITEMSTRUCT)lParam)) + return TRUE; + break; } return CallWindowProc(oldWndProc, hWnd, uMsg, wParam, lParam); } LRESULT CALLBACK PhpThemeWindowGroupBoxSubclassProc( - _In_ HWND hWnd, + _In_ HWND WindowHandle, _In_ UINT uMsg, _In_ WPARAM wParam, _In_ LPARAM lParam @@ -952,48 +1395,33 @@ LRESULT CALLBACK PhpThemeWindowGroupBoxSubclassProc( { WNDPROC oldWndProc; - if (!(oldWndProc = PhGetWindowContext(hWnd, SHRT_MAX))) + if (!(oldWndProc = PhGetWindowContext(WindowHandle, SHRT_MAX))) return FALSE; switch (uMsg) { case WM_DESTROY: { - PhRemoveWindowContext(hWnd, SHRT_MAX); - SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)oldWndProc); + SetWindowLongPtr(WindowHandle, GWLP_WNDPROC, (LONG_PTR)oldWndProc); + PhRemoveWindowContext(WindowHandle, SHRT_MAX); } break; case WM_ERASEBKGND: return TRUE; case WM_PAINT: { - RECT clientRect; HDC hdc; PAINTSTRUCT ps; - PPH_STRING windowText; SIZE nameSize; + RECT clientRect; RECT textRect; + ULONG returnLength; + WCHAR text[MAX_PATH]; - if (!(hdc = BeginPaint(hWnd, &ps))) + if (!(hdc = BeginPaint(WindowHandle, &ps))) break; - GetClientRect(hWnd, &clientRect); - - SetBkMode(hdc, TRANSPARENT); - - switch (PhGetIntegerSetting(L"GraphColorMode")) - { - case 0: // New colors - SetTextColor(hdc, RGB(0x0, 0x0, 0x0)); - SetDCBrushColor(hdc, RGB(0xff, 0xff, 0xff)); - //FillRect(hdc, &windowRect, GetStockObject(DC_BRUSH)); - break; - case 1: // Old colors - SetTextColor(hdc, RGB(0xff, 0xff, 0xff)); - SetDCBrushColor(hdc, RGB(0, 0, 0)); // RGB(28, 28, 28)); // RGB(65, 65, 65)); - //FillRect(hdc, &windowRect, GetStockObject(DC_BRUSH)); - break; - } + GetClientRect(WindowHandle, &clientRect); if (!PhpGroupboxFontHandle) // HACK { @@ -1008,45 +1436,81 @@ LRESULT CALLBACK PhpThemeWindowGroupBoxSubclassProc( } } - SelectFont(hdc, PhpGroupboxFontHandle); - SetTextColor(hdc, RGB(255, 69, 0)); - SetDCBrushColor(hdc, RGB(65, 65, 65)); - //clientRect.top += 6; - FrameRect(hdc, &clientRect, GetStockObject(DC_BRUSH)); - //clientRect.top -= 6; - - windowText = PhGetWindowText(hWnd); - GetTextExtentPoint32( - hdc, - windowText->Buffer, - (ULONG)windowText->Length / sizeof(WCHAR), - &nameSize - ); + if (PhGetWindowTextToBuffer(WindowHandle, PH_GET_WINDOW_TEXT_INTERNAL, text, RTL_NUMBER_OF(text), &returnLength) == ERROR_SUCCESS) + { + HFONT oldFont; - textRect.left = 0; - textRect.top = 0; - textRect.right = clientRect.right; - textRect.bottom = nameSize.cy; - FillRect(hdc, &textRect, GetStockObject(DC_BRUSH)); + SetBkMode(hdc, TRANSPARENT); - textRect.left += 10; - DrawText( - hdc, - windowText->Buffer, - (ULONG)windowText->Length / sizeof(WCHAR), - &textRect, - DT_LEFT | DT_END_ELLIPSIS | DT_SINGLELINE - ); - textRect.left -= 10; + oldFont = SelectFont(hdc, PhpGroupboxFontHandle); + GetTextExtentPoint32( + hdc, + text, + returnLength, + &nameSize + ); - PhDereferenceObject(windowText); + //if (PhpThemeBorderEnable) + //switch (PhpThemeColorMode) + //{ + //case 0: // New colors + // SetTextColor(hdc, GetSysColor(COLOR_GRAYTEXT)); + // SetDCBrushColor(hdc, RGB(0xff, 0xff, 0xff)); + // FrameRect(hdc, &clientRect, GetStockObject(DC_BRUSH)); + // break; + //case 1: // Old colors + // SetTextColor(hdc, GetSysColor(COLOR_GRAYTEXT)); + // SetDCBrushColor(hdc, RGB(0, 0, 0)); // RGB(28, 28, 28)); // RGB(65, 65, 65)); + // FrameRect(hdc, &clientRect, GetStockObject(DC_BRUSH)); + // break; + //} + + textRect.left = 0; + textRect.top = 0; + textRect.right = clientRect.right; + textRect.bottom = nameSize.cy; + + SetTextColor(hdc, RGB(255, 69, 0)); + SetDCBrushColor(hdc, RGB(65, 65, 65)); + FillRect(hdc, &textRect, GetStockObject(DC_BRUSH)); + + switch (PhpThemeColorMode) + { + case 0: // New colors + SetTextColor(hdc, RGB(255, 69, 0)); + SetDCBrushColor(hdc, RGB(65, 65, 65)); + //SetTextColor(hdc, RGB(0x0, 0x0, 0x0)); + //SetDCBrushColor(hdc, PhpThemeWindowTextColor); + //FrameRect(hdc, &clientRect, GetStockObject(DC_BRUSH)); + break; + case 1: // Old colors + SetTextColor(hdc, RGB(255, 69, 0)); + SetDCBrushColor(hdc, RGB(65, 65, 65)); + //SetTextColor(hdc, PhpThemeWindowTextColor); + //SetDCBrushColor(hdc, PhpThemeWindowBackgroundColor); + //FrameRect(hdc, &clientRect, GetStockObject(DC_BRUSH)); + break; + } + + textRect.left += 10; + DrawText( + hdc, + text, + returnLength, + &textRect, + DT_LEFT | DT_END_ELLIPSIS | DT_SINGLELINE + ); + textRect.left -= 10; - EndPaint(hWnd, &ps); + SelectFont(hdc, oldFont); + } + + EndPaint(WindowHandle, &ps); } - return FALSE; + return TRUE; } - return CallWindowProc(oldWndProc, hWnd, uMsg, wParam, lParam); + return CallWindowProc(oldWndProc, WindowHandle, uMsg, wParam, lParam); } LRESULT CALLBACK PhpThemeWindowTabControlWndSubclassProc( @@ -1075,6 +1539,9 @@ LRESULT CALLBACK PhpThemeWindowTabControlWndSubclassProc( } break; case WM_ERASEBKGND: + { + //ExcludeClipRect(ps.hdc, clientRect.left, clientRect.top, clientRect.right, clientRect.bottom); + } return TRUE; case WM_MOUSEMOVE: { @@ -1144,23 +1611,25 @@ LRESULT CALLBACK PhpThemeWindowTabControlWndSubclassProc( break; case WM_PAINT: { - RECT clientRect, itemRect; + RECT itemRect; + RECT windowRect; + RECT clientRect; PAINTSTRUCT ps; - + BeginPaint(WindowHandle, &ps); + + GetWindowRect(WindowHandle, &windowRect); GetClientRect(WindowHandle, &clientRect); + windowRect.right -= windowRect.left; + windowRect.bottom -= windowRect.top; + windowRect.left = 0; + windowRect.top = 0; - RECT rcSpin = clientRect; - HWND hWndSpin = GetDlgItem(WindowHandle, 1); - if (hWndSpin) - { - GetWindowRect(hWndSpin, &rcSpin); - MapWindowPoints(NULL, WindowHandle, (LPPOINT)&rcSpin, 2); - rcSpin.right = rcSpin.left; - rcSpin.left = rcSpin.top = 0; - rcSpin.bottom = clientRect.bottom; - } + clientRect.left = windowRect.left; + clientRect.top = windowRect.top; + clientRect.right = windowRect.right; + clientRect.bottom = windowRect.bottom; HDC hdc = CreateCompatibleDC(ps.hdc); HDC hdcTab = CreateCompatibleDC(hdc); @@ -1168,14 +1637,13 @@ LRESULT CALLBACK PhpThemeWindowTabControlWndSubclassProc( SelectBitmap(hdc, hbm); SetBkMode(hdc, TRANSPARENT); - SelectFont(hdc, PhpTabControlFontHandle); - switch (PhGetIntegerSetting(L"GraphColorMode")) + switch (PhpThemeColorMode) { case 0: // New colors //SetTextColor(hdc, RGB(0x0, 0xff, 0x0)); - SetDCBrushColor(hdc, PhpThemeWindowTextColor); + SetDCBrushColor(hdc, GetSysColor(COLOR_3DFACE));// PhpThemeWindowTextColor); FillRect(hdc, &clientRect, GetStockObject(DC_BRUSH)); break; case 1: // Old colors @@ -1198,7 +1666,7 @@ LRESULT CALLBACK PhpThemeWindowTabControlWndSubclassProc( { OffsetRect(&itemRect, 2, 2); - switch (PhGetIntegerSetting(L"GraphColorMode")) + switch (PhpThemeColorMode) { case 0: // New colors { @@ -1229,20 +1697,20 @@ LRESULT CALLBACK PhpThemeWindowTabControlWndSubclassProc( { OffsetRect(&itemRect, 2, 2); - switch (PhGetIntegerSetting(L"GraphColorMode")) + switch (PhpThemeColorMode) { case 0: // New colors { if (TabCtrl_GetCurSel(WindowHandle) == i) { - SetTextColor(hdc, RGB(0xff, 0xff, 0xff)); - SetDCBrushColor(hdc, RGB(128, 128, 128)); + SetTextColor(hdc, RGB(0x0, 0x0, 0x0)); + SetDCBrushColor(hdc, RGB(0xff, 0xff, 0xff)); FillRect(hdc, &itemRect, GetStockObject(DC_BRUSH)); } else { SetTextColor(hdc, RGB(0, 0, 0)); - SetDCBrushColor(hdc, PhpThemeWindowTextColor); + SetDCBrushColor(hdc, GetSysColor(COLOR_3DFACE));// PhpThemeWindowTextColor); FillRect(hdc, &itemRect, GetStockObject(DC_BRUSH)); } } @@ -1266,23 +1734,29 @@ LRESULT CALLBACK PhpThemeWindowTabControlWndSubclassProc( } } - WCHAR szText[MAX_PATH]; + { + TCITEM tabItem; + WCHAR tabHeaderText[MAX_PATH]; - TCITEM entry; - ZeroMemory(&entry, sizeof(TCITEM)); - entry.mask = TCIF_TEXT | TCIF_IMAGE | TCIF_STATE; - entry.dwStateMask = TCIS_BUTTONPRESSED | TCIS_HIGHLIGHTED; - entry.pszText = szText; - entry.cchTextMax = MAX_PATH; + memset(tabHeaderText, 0, sizeof(tabHeaderText)); + memset(&tabItem, 0, sizeof(TCITEM)); - TabCtrl_GetItem(WindowHandle, i, &entry); - DrawText( - hdc, - entry.pszText, - -1, - &itemRect, - DT_CENTER | DT_VCENTER | DT_SINGLELINE | DT_HIDEPREFIX - ); + tabItem.mask = TCIF_TEXT | TCIF_IMAGE | TCIF_STATE; + tabItem.dwStateMask = TCIS_BUTTONPRESSED | TCIS_HIGHLIGHTED; + tabItem.cchTextMax = RTL_NUMBER_OF(tabHeaderText); + tabItem.pszText = tabHeaderText; + + if (TabCtrl_GetItem(WindowHandle, i, &tabItem)) + { + DrawText( + hdc, + tabItem.pszText, + (UINT)PhCountStringZ(tabItem.pszText), + &itemRect, + DT_CENTER | DT_VCENTER | DT_SINGLELINE | DT_HIDEPREFIX + ); + } + } } BitBlt(ps.hdc, 0, 0, clientRect.right, clientRect.bottom, hdc, 0, 0, SRCCOPY); @@ -1291,13 +1765,14 @@ LRESULT CALLBACK PhpThemeWindowTabControlWndSubclassProc( DeleteDC(hdc); DeleteBitmap(hbm); EndPaint(WindowHandle, &ps); - - InvalidateRect(WindowHandle, NULL, FALSE); // HACK } - return DefWindowProc(WindowHandle, uMsg, wParam, lParam); + goto DefaultWndProc; } return CallWindowProc(oldWndProc, WindowHandle, uMsg, wParam, lParam); + +DefaultWndProc: + return DefWindowProc(WindowHandle, uMsg, wParam, lParam); } LRESULT CALLBACK PhpThemeWindowHeaderSubclassProc( @@ -1412,7 +1887,7 @@ LRESULT CALLBACK PhpThemeWindowHeaderSubclassProc( SetBkMode(hdc, TRANSPARENT); - switch (PhGetIntegerSetting(L"GraphColorMode")) + switch (PhpThemeColorMode) { case 0: // New colors SetTextColor(hdc, RGB(0x0, 0x0, 0x0)); @@ -1440,7 +1915,7 @@ LRESULT CALLBACK PhpThemeWindowHeaderSubclassProc( if (PtInRect(&headerRect, pt)) { - switch (PhGetIntegerSetting(L"GraphColorMode")) + switch (PhpThemeColorMode) { case 0: // New colors SetTextColor(hdc, PhpThemeWindowTextColor); @@ -1458,7 +1933,7 @@ LRESULT CALLBACK PhpThemeWindowHeaderSubclassProc( } else { - switch (PhGetIntegerSetting(L"GraphColorMode")) + switch (PhpThemeColorMode) { case 0: // New colors SetTextColor(hdc, RGB(0x0, 0x0, 0x0)); @@ -1498,11 +1973,13 @@ LRESULT CALLBACK PhpThemeWindowHeaderSubclassProc( DeleteBitmap(hbm); EndPaint(WindowHandle, &ps); } - - return DefWindowProc(WindowHandle, uMsg, wParam, lParam); + goto DefaultWndProc; } return CallWindowProc(oldWndProc, WindowHandle, uMsg, wParam, lParam); + +DefaultWndProc: + return DefWindowProc(WindowHandle, uMsg, wParam, lParam); } LRESULT CALLBACK PhpThemeWindowStatusbarWndSubclassProc( @@ -1586,11 +2063,11 @@ LRESULT CALLBACK PhpThemeWindowStatusbarWndSubclassProc( SelectFont(hdc, PhpStatusBarFontHandle); - switch (PhGetIntegerSetting(L"GraphColorMode")) + switch (PhpThemeColorMode) { case 0: // New colors SetTextColor(hdc, RGB(0x0, 0x0, 0x0)); - SetDCBrushColor(hdc, RGB(0xff, 0xff, 0xff)); + SetDCBrushColor(hdc, GetSysColor(COLOR_3DFACE)); // RGB(0xff, 0xff, 0xff)); FillRect(hdc, &clientRect, GetStockObject(DC_BRUSH)); break; case 1: // Old colors @@ -1616,7 +2093,7 @@ LRESULT CALLBACK PhpThemeWindowStatusbarWndSubclassProc( if (PtInRect(&blockRect, pt)) { - switch (PhGetIntegerSetting(L"GraphColorMode")) + switch (PhpThemeColorMode) { case 0: // New colors SetTextColor(hdc, PhpThemeWindowTextColor); @@ -1633,11 +2110,11 @@ LRESULT CALLBACK PhpThemeWindowStatusbarWndSubclassProc( } else { - switch (PhGetIntegerSetting(L"GraphColorMode")) + switch (PhpThemeColorMode) { case 0: // New colors SetTextColor(hdc, RGB(0x0, 0x0, 0x0)); - SetDCBrushColor(hdc, RGB(0xff, 0xff, 0xff)); + SetDCBrushColor(hdc, GetSysColor(COLOR_3DFACE)); // RGB(0xff, 0xff, 0xff)); FillRect(hdc, &blockRect, GetStockObject(DC_BRUSH)); //FrameRect(hdc, &blockRect, GetSysColorBrush(COLOR_HIGHLIGHT)); break; @@ -1679,9 +2156,11 @@ LRESULT CALLBACK PhpThemeWindowStatusbarWndSubclassProc( DeleteBitmap(hbm); EndPaint(WindowHandle, &ps); } - - return DefWindowProc(WindowHandle, uMsg, wParam, lParam); + goto DefaultWndProc; } return CallWindowProc(oldWndProc, WindowHandle, uMsg, wParam, lParam); + +DefaultWndProc: + return DefWindowProc(WindowHandle, uMsg, wParam, lParam); } diff --git a/phlib/treenew.c b/phlib/treenew.c index b6a1b5abe2e4..965ddaafc145 100644 --- a/phlib/treenew.c +++ b/phlib/treenew.c @@ -293,6 +293,14 @@ LRESULT CALLBACK PhTnpWndProc( return result; } break; + case WM_MEASUREITEM: + if (PhThemeWindowMeasureItem((LPMEASUREITEMSTRUCT)lParam)) + return TRUE; + break; + case WM_DRAWITEM: + if (PhThemeWindowDrawItem((LPDRAWITEMSTRUCT)lParam)) + return TRUE; + break; } if (uMsg >= TNM_FIRST && uMsg <= TNM_LAST) @@ -5063,7 +5071,7 @@ VOID PhTnpPaint( // Paint the rows. - SelectObject(hdc, Context->Font); + SelectFont(hdc, Context->Font); SetBkMode(hdc, TRANSPARENT); for (i = firstRowToUpdate; i <= lastRowToUpdate; i++) @@ -5140,12 +5148,10 @@ VOID PhTnpPaint( 1, 1, blendFunction - ); - - //drewWithAlpha = TRUE; + ); - SelectObject(tempDc, oldBitmap); - DeleteObject(bitmap); + SelectBitmap(tempDc, oldBitmap); + DeleteBitmap(bitmap); } DeleteDC(tempDc); From 0daf6062a3c8630730e3418459afa070f9b4e2e8 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 3 Aug 2018 15:29:35 +1000 Subject: [PATCH 1244/2058] Fix main window menu theme --- ProcessHacker/mainwnd.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/ProcessHacker/mainwnd.c b/ProcessHacker/mainwnd.c index 408a91ffb028..2efa44348977 100644 --- a/ProcessHacker/mainwnd.c +++ b/ProcessHacker/mainwnd.c @@ -1622,6 +1622,13 @@ VOID PhMwpOnInitMenuPopup( menuInfo.cbSize = sizeof(MENUINFO); menuInfo.fMask = MIM_STYLE; menuInfo.dwStyle = MNS_CHECKORBMP; + + if (PhEnableThemeSupport) + { + menuInfo.fMask |= MIM_BACKGROUND; + menuInfo.hbrBack = PhMenuBackgroundBrush; + } + SetMenuInfo(Menu, &menuInfo); menu = PhCreateEMenu(); From 2e007f066be6f1adf3ec812392787c563291c550 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 3 Aug 2018 17:28:48 +1000 Subject: [PATCH 1245/2058] BuildTools: Add ExtendedTools x86 plugin on 64bit --- tools/CustomBuildTool/Source Files/Build.cs | 10 ++++++++++ .../bin/Release/CustomBuildTool.exe | Bin 166912 -> 167424 bytes .../bin/Release/CustomBuildTool.pdb | Bin 83456 -> 83456 bytes 3 files changed, 10 insertions(+) diff --git a/tools/CustomBuildTool/Source Files/Build.cs b/tools/CustomBuildTool/Source Files/Build.cs index 1e9878bab192..ee51c0070995 100644 --- a/tools/CustomBuildTool/Source Files/Build.cs +++ b/tools/CustomBuildTool/Source Files/Build.cs @@ -417,6 +417,8 @@ public static bool CopyWow64Files(BuildFlags Flags) Win32.CopyIfNewer("bin\\Debug32\\ProcessHacker.pdb", "bin\\Debug64\\x86\\ProcessHacker.pdb"); Win32.CopyIfNewer("bin\\Debug32\\plugins\\DotNetTools.dll", "bin\\Debug64\\x86\\plugins\\DotNetTools.dll"); Win32.CopyIfNewer("bin\\Debug32\\plugins\\DotNetTools.pdb", "bin\\Debug64\\x86\\plugins\\DotNetTools.pdb"); + Win32.CopyIfNewer("bin\\Debug32\\plugins\\ExtendedTools.dll", "bin\\Debug64\\x86\\plugins\\ExtendedTools.dll"); + Win32.CopyIfNewer("bin\\Debug32\\plugins\\ExtendedTools.pdb", "bin\\Debug64\\x86\\plugins\\ExtendedTools.pdb"); } else { @@ -441,6 +443,14 @@ public static bool CopyWow64Files(BuildFlags Flags) "bin\\Release32\\plugins\\DotNetTools.pdb", "bin\\Release64\\x86\\plugins\\DotNetTools.pdb" ); + Win32.CopyIfNewer( + "bin\\Release32\\plugins\\ExtendedTools.dll", + "bin\\Release64\\x86\\plugins\\ExtendedTools.dll" + ); + Win32.CopyIfNewer( + "bin\\Release32\\plugins\\ExtendedTools.pdb", + "bin\\Release64\\x86\\plugins\\ExtendedTools.pdb" + ); } } catch (Exception ex) diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe b/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe index 5d8bc7e4dad4ae480f54ebc689ec36f84d21f8df..7ab91c38d8baad6dfc01fc95cb13ff23652aec69 100644 GIT binary patch delta 7510 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

7uv&-vhT>IfZ4%Z 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 diff --git a/tools/CustomSetupTool/CustomSetupTool/extract.c b/tools/CustomSetupTool/CustomSetupTool/extract.c index 8d157c0a3cbc..405c429a6cb0 100644 --- a/tools/CustomSetupTool/CustomSetupTool/extract.c +++ b/tools/CustomSetupTool/CustomSetupTool/extract.c @@ -98,7 +98,6 @@ BOOLEAN SetupExtractBuild( } InterlockedExchange64(&ExtractTotalLength, totalLength); - SendMessage(Context, WM_START_SETUP, 0, 0); for (mz_uint i = 0; i < mz_zip_reader_get_num_files(&zip_archive); i++) @@ -153,7 +152,6 @@ BOOLEAN SetupExtractBuild( goto CleanupExit; extractPath = PhConcatStrings(3, PhGetString(SetupInstallPath), L"\\", PhGetString(fileName)); - //OutputDebugString(PhFormatString(L"%s\r\n", extractPath->Buffer)->Buffer); if (fullSetupPath = PhGetFullPath(extractPath->Buffer, &indexOfFileName)) { @@ -211,7 +209,9 @@ BOOLEAN SetupExtractBuild( goto CleanupExit; currentLength += bufferLength; + InterlockedExchange64(&ExtractCurrentLength, currentLength); + SendMessage(Context, WM_UPDATE_SETUP, 0, (LPARAM)PhGetBaseName(extractPath)); NtClose(fileHandle); From f338e2b7abf9bdbc284ccf3a453a0cac542c0de7 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 18 May 2017 10:08:18 +1000 Subject: [PATCH 0114/2058] BuildTools: Improve build version definitions, Remove legacy version resources --- ProcessHacker/ProcessHacker.rc | 114 ++++++------------ ProcessHacker/ProcessHacker.vcxproj | 24 ++-- ProcessHacker/ProcessHacker.vcxproj.filters | 5 +- ProcessHacker/about.c | 2 +- ProcessHacker/include/phappres.h | 21 ++-- ProcessHacker/include/phapprev.h | 6 - ProcessHacker/include/phapprev_in.h | 6 - ProcessHacker/version.rc | 35 ------ tools/CustomBuildTool/Source Files/Build.cs | 23 ++-- tools/CustomBuildTool/Source Files/Program.cs | 2 - .../bin/Release/CustomBuildTool.exe | Bin 160256 -> 160768 bytes .../bin/Release/CustomBuildTool.pdb | Bin 73216 -> 73216 bytes .../CustomSetupTool/include/setup.h | 3 +- tools/peview/peview.rc | 75 ++++++------ tools/peview/peview.vcxproj | 16 ++- tools/peview/peview.vcxproj.filters | 3 - tools/peview/version.rc | 35 ------ 17 files changed, 121 insertions(+), 249 deletions(-) delete mode 100644 ProcessHacker/include/phapprev.h delete mode 100644 ProcessHacker/include/phapprev_in.h delete mode 100644 ProcessHacker/version.rc delete mode 100644 tools/peview/version.rc diff --git a/ProcessHacker/ProcessHacker.rc b/ProcessHacker/ProcessHacker.rc index 4bc346f7cf65..e9bcdd06a676 100644 --- a/ProcessHacker/ProcessHacker.rc +++ b/ProcessHacker/ProcessHacker.rc @@ -2527,93 +2527,51 @@ IDR_RT_MANIFEST RT_MANIFEST "ProcessHacker.manifest" ///////////////////////////////////////////////////////////////////////////// // -// AFX_DIALOG_LAYOUT +// PNG // -IDD_FINDOBJECTS AFX_DIALOG_LAYOUT -BEGIN - 0 -END - -IDD_OPTADVANCED AFX_DIALOG_LAYOUT -BEGIN - 0 -END - -IDD_SYSINFO_MEMPANEL AFX_DIALOG_LAYOUT -BEGIN - 0 -END - -IDD_ABOUT AFX_DIALOG_LAYOUT -BEGIN - 0 -END - -IDD_PROCGENERAL AFX_DIALOG_LAYOUT -BEGIN - 0 -END - -IDD_MITIGATION AFX_DIALOG_LAYOUT -BEGIN - 0 -END - -IDD_INFORMATION AFX_DIALOG_LAYOUT -BEGIN - 0 -END - -IDD_OPTGENERAL AFX_DIALOG_LAYOUT -BEGIN - 0 -END - -IDD_MINIINFO AFX_DIALOG_LAYOUT -BEGIN - 0 -END - -IDD_PROCTHREADS AFX_DIALOG_LAYOUT -BEGIN - 0 -END - -IDD_PROCRECORD AFX_DIALOG_LAYOUT -BEGIN - 0 -END - -IDD_PROCENVIRONMENT AFX_DIALOG_LAYOUT -BEGIN - 0 -END - -IDD_EDITENV AFX_DIALOG_LAYOUT -BEGIN - 0 -END - -IDD_PROCHANDLES AFX_DIALOG_LAYOUT -BEGIN - 0 -END +IDB_SEARCH_ACTIVE PNG "resources\\active_search.png" -IDD_OBJTOKEN AFX_DIALOG_LAYOUT -BEGIN - 0 -END +IDB_SEARCH_INACTIVE PNG "resources\\inactive_search.png" ///////////////////////////////////////////////////////////////////////////// // -// PNG +// Version // -IDB_SEARCH_ACTIVE PNG "resources\\active_search.png" - -IDB_SEARCH_INACTIVE PNG "resources\\inactive_search.png" +VS_VERSION_INFO VERSIONINFO + FILEVERSION PHAPP_VERSION_NUMBER + PRODUCTVERSION PHAPP_VERSION_NUMBER + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "0c0904b0" + BEGIN + VALUE "CompanyName", "Process Hacker" + VALUE "FileDescription", "Process Hacker" + VALUE "FileVersion", PHAPP_VERSION_STRING + VALUE "InternalName", "ProcessHacker.exe" + VALUE "LegalCopyright", "Licensed under the GNU GPL, v3. Copyright (C) 2017" + VALUE "OriginalFilename", "ProcessHacker.exe" + VALUE "ProductName", "Process Hacker" + VALUE "ProductVersion", PHAPP_VERSION_STRING + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0xc09, 1200 + END +END #endif // English (Australia) resources ///////////////////////////////////////////////////////////////////////////// diff --git a/ProcessHacker/ProcessHacker.vcxproj b/ProcessHacker/ProcessHacker.vcxproj index f212a670d21b..ddbc487bed92 100644 --- a/ProcessHacker/ProcessHacker.vcxproj +++ b/ProcessHacker/ProcessHacker.vcxproj @@ -85,7 +85,7 @@ Disabled ..\phnt\include;..\phlib\include;include;%(AdditionalIncludeDirectories) - _PHLIB_;_PHAPP_;_WINDOWS;WIN32;DEBUG;%(PreprocessorDefinitions) + _PHLIB_;_PHAPP_;_WINDOWS;WIN32;DEBUG;%(PreprocessorDefinitions);$(ExternalCompilerOptions) EnableFastChecks MultiThreadedDebug Level3 @@ -104,14 +104,12 @@ ProcessHacker.def aclui.dll;iphlpapi.dll;ws2_32.dll;%(DelayLoadDLLs) - - Disabled ..\phnt\include;..\phlib\include;include;%(AdditionalIncludeDirectories) - _PHLIB_;_PHAPP_;_WINDOWS;WIN64;DEBUG;%(PreprocessorDefinitions) + _PHLIB_;_PHAPP_;_WINDOWS;WIN64;DEBUG;%(PreprocessorDefinitions);$(ExternalCompilerOptions) EnableFastChecks MultiThreadedDebug Level3 @@ -130,15 +128,13 @@ ProcessHacker.def aclui.dll;iphlpapi.dll;ws2_32.dll;%(DelayLoadDLLs) - - MaxSpeed true ..\phnt\include;..\phlib\include;include;%(AdditionalIncludeDirectories) - _PHLIB_;_PHAPP_;_WINDOWS;WIN32;NDEBUG;%(PreprocessorDefinitions) + _PHLIB_;_PHAPP_;_WINDOWS;WIN32;NDEBUG;%(PreprocessorDefinitions);$(ExternalCompilerOptions) true MultiThreaded false @@ -163,15 +159,13 @@ ProcessHacker.def aclui.dll;iphlpapi.dll;ws2_32.dll;%(DelayLoadDLLs) - - MaxSpeed true ..\phnt\include;..\phlib\include;include;%(AdditionalIncludeDirectories) - _PHLIB_;_PHAPP_;_WINDOWS;WIN64;NDEBUG;%(PreprocessorDefinitions) + _PHLIB_;_PHAPP_;_WINDOWS;WIN64;NDEBUG;%(PreprocessorDefinitions);$(ExternalCompilerOptions) true MultiThreaded false @@ -195,8 +189,6 @@ ProcessHacker.def aclui.dll;iphlpapi.dll;ws2_32.dll;%(DelayLoadDLLs) - - @@ -385,8 +377,12 @@ - - + + _UNICODE;UNICODE;%(PreprocessorDefinitions);$(ExternalCompilerOptions) + _UNICODE;UNICODE;%(PreprocessorDefinitions);$(ExternalCompilerOptions) + _UNICODE;UNICODE;%(PreprocessorDefinitions);$(ExternalCompilerOptions) + _UNICODE;UNICODE;%(PreprocessorDefinitions);$(ExternalCompilerOptions) + diff --git a/ProcessHacker/ProcessHacker.vcxproj.filters b/ProcessHacker/ProcessHacker.vcxproj.filters index 5517737409be..e4fac5fddc0e 100644 --- a/ProcessHacker/ProcessHacker.vcxproj.filters +++ b/ProcessHacker/ProcessHacker.vcxproj.filters @@ -1,4 +1,4 @@ - + @@ -576,9 +576,6 @@ Resources - - Resources - diff --git a/ProcessHacker/about.c b/ProcessHacker/about.c index 957c741c0b97..4a8b262e16f0 100644 --- a/ProcessHacker/about.c +++ b/ProcessHacker/about.c @@ -49,7 +49,7 @@ static INT_PTR CALLBACK PhpAboutDlgProc( PhCenterWindow(hwndDlg, GetParent(hwndDlg)); -#if (PHAPP_VERSION_REVISION != 0x0D06F00D) +#if (PHAPP_VERSION_REVISION != 0) appName = PhFormatString( L"Process Hacker %u.%u.%u", PHAPP_VERSION_MAJOR, diff --git a/ProcessHacker/include/phappres.h b/ProcessHacker/include/phappres.h index 3f8215df22e9..c0267bfd3ea9 100644 --- a/ProcessHacker/include/phappres.h +++ b/ProcessHacker/include/phappres.h @@ -1,14 +1,21 @@ -// Notes: -// * Do not use /* comments */ since ISPP is buggy and it will throw an error. - #ifndef PH_PHAPPRES_H #define PH_PHAPPRES_H -#include "phapprev.h" - +#ifndef PHAPP_VERSION_MAJOR #define PHAPP_VERSION_MAJOR 3 +#endif + +#ifndef PHAPP_VERSION_MINOR #define PHAPP_VERSION_MINOR 0 +#endif + +#ifndef PHAPP_VERSION_BUILD #define PHAPP_VERSION_BUILD 0 +#endif + +#ifndef PHAPP_VERSION_REVISION +#define PHAPP_VERSION_REVISION 0 +#endif #if (PHAPP_VERSION_BUILD == 0) #define TWO_DIGIT_VER 1 @@ -19,8 +26,6 @@ #define DO_MAKE_STR(x) #x #define MAKE_STR(x) DO_MAKE_STR(x) -#ifndef ISPP_INVOKED - #if defined(TWO_DIGIT_VER) #define PHAPP_VERSION_STRING MAKE_STR(PHAPP_VERSION_MAJOR) "." MAKE_STR(PHAPP_VERSION_MINOR) ".0" "." MAKE_STR(PHAPP_VERSION_REVISION) #elif defined(THREE_DIGIT_VER) @@ -29,6 +34,4 @@ #define PHAPP_VERSION_NUMBER PHAPP_VERSION_MAJOR,PHAPP_VERSION_MINOR,PHAPP_VERSION_BUILD,PHAPP_VERSION_REVISION -#endif // ISPP_INVOKED - #endif // PHAPPRES_H diff --git a/ProcessHacker/include/phapprev.h b/ProcessHacker/include/phapprev.h deleted file mode 100644 index cbb6d2096029..000000000000 --- a/ProcessHacker/include/phapprev.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef PHAPPREV_H -#define PHAPPREV_H - -#define PHAPP_VERSION_REVISION 0x0D06F00D - -#endif // PHAPPREV_H diff --git a/ProcessHacker/include/phapprev_in.h b/ProcessHacker/include/phapprev_in.h deleted file mode 100644 index c1e40313fd88..000000000000 --- a/ProcessHacker/include/phapprev_in.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef PHAPPREV_H -#define PHAPPREV_H - -#define PHAPP_VERSION_REVISION $COMMITS$ - -#endif // PHAPPREV_H diff --git a/ProcessHacker/version.rc b/ProcessHacker/version.rc deleted file mode 100644 index 6caa53e40114..000000000000 --- a/ProcessHacker/version.rc +++ /dev/null @@ -1,35 +0,0 @@ -#include "winres.h" -#include "include/phappres.h" - -VS_VERSION_INFO VERSIONINFO - FILEVERSION PHAPP_VERSION_NUMBER - PRODUCTVERSION PHAPP_VERSION_NUMBER - FILEFLAGSMASK 0x17L -#ifdef _DEBUG - FILEFLAGS 0x1L -#else - FILEFLAGS 0x0L -#endif - FILEOS 0x4L - FILETYPE 0x1L - FILESUBTYPE 0x0L -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "0c0904b0" - BEGIN - VALUE "CompanyName", "wj32" - VALUE "FileDescription", "Process Hacker" - VALUE "FileVersion", PHAPP_VERSION_STRING - VALUE "InternalName", "Process Hacker" - VALUE "LegalCopyright", "Licensed under the GNU GPL, v3." - VALUE "OriginalFilename", "ProcessHacker.exe" - VALUE "ProductName", "Process Hacker" - VALUE "ProductVersion", PHAPP_VERSION_STRING - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0xc09, 1200 - END -END diff --git a/tools/CustomBuildTool/Source Files/Build.cs b/tools/CustomBuildTool/Source Files/Build.cs index f0073edf10fd..d79db942fab8 100644 --- a/tools/CustomBuildTool/Source Files/Build.cs +++ b/tools/CustomBuildTool/Source Files/Build.cs @@ -12,8 +12,9 @@ public static class Build { private static DateTime TimeStart; private static bool BuildNightly = false; - private static string BuildBranch = "master"; + private static string BuildBranch; private static string BuildOutputFolder = "build"; + private static string BuildCommit; private static string BuildVersion; private static string BuildLongVersion; private static string BuildCount; @@ -231,12 +232,12 @@ public static string GetBuildLogString() public static void ShowBuildEnvironment(string Platform, bool ShowBuildInfo, bool ShowLogInfo) { - string currentBranch = Win32.ShellExecute(GitExePath, "rev-parse --abbrev-ref HEAD"); - string currentCommitTag = Win32.ShellExecute(GitExePath, "rev-parse --short HEAD"); // rev-parse HEAD + BuildBranch = Win32.ShellExecute(GitExePath, "rev-parse --abbrev-ref HEAD"); + BuildCommit = Win32.ShellExecute(GitExePath, "rev-parse --short HEAD"); // rev-parse HEAD Program.PrintColorMessage("Branch: ", ConsoleColor.Cyan, false); - Program.PrintColorMessage(currentBranch, ConsoleColor.White); + Program.PrintColorMessage(BuildBranch, ConsoleColor.White); Program.PrintColorMessage("Commit: ", ConsoleColor.Cyan, false); - Program.PrintColorMessage(currentCommitTag, ConsoleColor.White); + Program.PrintColorMessage(BuildCommit, ConsoleColor.White); string currentGitTag = Win32.ShellExecute(GitExePath, "describe --abbrev=0 --tags --always").Trim(); BuildRevision = Win32.ShellExecute(GitExePath, "rev-list --count \"" + currentGitTag + ".." + BuildBranch + "\"").Trim(); @@ -1012,7 +1013,7 @@ public static bool AppveyorUploadBuildFiles() { try { - Win32.ShellExecute("appveyor", "UpdateBuild -Version \"1.0 -$version\" "); + Win32.ShellExecute("appveyor", "UpdateBuild -Version \"" + BuildLongVersion + " (" + BuildCommit + ")\" "); } catch (Exception ex) { @@ -1026,8 +1027,6 @@ public static bool AppveyorUploadBuildFiles() public static bool BuildSolution(string Solution, BuildFlags Flags) { - //string buildParams = "/p:DefineConstants=\"PH_BUILD_API=1;PHAPP_VERSION_REVISION=" + BuildRevision + "\" "; - if ((Flags & BuildFlags.Build32bit) == BuildFlags.Build32bit) { Program.PrintColorMessage("Building " + Path.GetFileNameWithoutExtension(Solution) + " (", ConsoleColor.Cyan, false, Flags); @@ -1038,8 +1037,8 @@ public static bool BuildSolution(string Solution, BuildFlags Flags) MSBuildExePath, "/m /nologo /verbosity:quiet " + "/p:Configuration=" + (Flags.HasFlag(BuildFlags.BuildDebug) ? "Debug" : "Release") + " " + - "/p:Platform=Win32 " + - //buildParams + + "/p:Platform=Win32 " + + "/p:ExternalCompilerOptions=\"PH_BUILD_API;PHAPP_VERSION_REVISION=\"" + BuildRevision + "\";PHAPP_VERSION_BUILD=\"" + BuildCount + "\"\" " + Solution ); @@ -1060,8 +1059,8 @@ public static bool BuildSolution(string Solution, BuildFlags Flags) MSBuildExePath, "/m /nologo /verbosity:quiet " + "/p:Configuration=" + (Flags.HasFlag(BuildFlags.BuildDebug) ? "Debug" : "Release") + " " + - "/p:Platform=x64 " + - //buildParams + + "/p:Platform=x64 " + + "/p:ExternalCompilerOptions=\"PH_BUILD_API;PHAPP_VERSION_REVISION=\"" + BuildRevision + "\";PHAPP_VERSION_BUILD=\"" + BuildCount + "\"\" " + Solution ); diff --git a/tools/CustomBuildTool/Source Files/Program.cs b/tools/CustomBuildTool/Source Files/Program.cs index 960cad65053f..65f25f628144 100644 --- a/tools/CustomBuildTool/Source Files/Program.cs +++ b/tools/CustomBuildTool/Source Files/Program.cs @@ -77,8 +77,6 @@ public static void Main(string[] args) BuildFlags.Build32bit | BuildFlags.Build64bit | BuildFlags.BuildDebug | BuildFlags.BuildVerbose ); - - Build.ShowBuildStats(); } else if (ProgramArgs.ContainsKey("-cleansdk")) { diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe b/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe index bf9224ba705bdcae546ae48bdc28a10b30dc3005..242914120060012e249192a8733fa077e6dd59d1 100644 GIT binary patch delta 12065 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 diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb b/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb index c9b211b16d3120a19e8d603bc851328efeb954d4..fcd1d1fea1e2a11a6ecf117d3056ba78e778ba97 100644 GIT binary patch delta 14140 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 AO8@`> diff --git a/tools/CustomSetupTool/CustomSetupTool/include/setup.h b/tools/CustomSetupTool/CustomSetupTool/include/setup.h index bca1fad59bc9..f703b2f2a180 100644 --- a/tools/CustomSetupTool/CustomSetupTool/include/setup.h +++ b/tools/CustomSetupTool/CustomSetupTool/include/setup.h @@ -43,8 +43,7 @@ #include "resource.h" #include -#include "..\..\..\ProcessHacker\include\phappres.h" -#include "..\..\..\ProcessHacker\include\phapprev.h" +#include "..\..\ProcessHacker\include\phappres.h" // Win32 PropertySheet Control IDs #define IDD_PROPSHEET_ID 1006 // ID of the propsheet dialog template in comctl32.dll diff --git a/tools/peview/peview.rc b/tools/peview/peview.rc index 4a1db839071e..55f303c4af91 100644 --- a/tools/peview/peview.rc +++ b/tools/peview/peview.rc @@ -223,42 +223,6 @@ BEGIN END -///////////////////////////////////////////////////////////////////////////// -// -// AFX_DIALOG_LAYOUT -// - -IDD_PESYMBOLS AFX_DIALOG_LAYOUT -BEGIN - 0 -END - -IDD_PELOADCONFIG AFX_DIALOG_LAYOUT -BEGIN - 0 -END - -IDD_PEIMPORTS AFX_DIALOG_LAYOUT -BEGIN - 0 -END - -IDD_PEEXPORTS AFX_DIALOG_LAYOUT -BEGIN - 0 -END - -IDD_PECFG AFX_DIALOG_LAYOUT -BEGIN - 0 -END - -IDD_LIBEXPORTS AFX_DIALOG_LAYOUT -BEGIN - 0 -END - - ///////////////////////////////////////////////////////////////////////////// // // Bitmap @@ -278,6 +242,45 @@ IDB_SEARCH_ACTIVE PNG "resources\\active_search.png" IDB_SEARCH_INACTIVE PNG "resources\\inactive_search.png" + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION PHAPP_VERSION_NUMBER + PRODUCTVERSION PHAPP_VERSION_NUMBER + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "0c0904b0" + BEGIN + VALUE "CompanyName", "Process Hacker" + VALUE "FileDescription", "PE Viewer" + VALUE "FileVersion", PHAPP_VERSION_STRING + VALUE "InternalName", "peview.exe" + VALUE "LegalCopyright", "Licensed under the GNU GPL, v3. Copyright (C) 2017" + VALUE "OriginalFilename", "peview.exe" + VALUE "ProductName", "PE Viewer" + VALUE "ProductVersion", PHAPP_VERSION_STRING + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0xc09, 1200 + END +END + #endif // English (Australia) resources ///////////////////////////////////////////////////////////////////////////// diff --git a/tools/peview/peview.vcxproj b/tools/peview/peview.vcxproj index 1ce6cc5d5354..7457b997abb7 100644 --- a/tools/peview/peview.vcxproj +++ b/tools/peview/peview.vcxproj @@ -85,7 +85,7 @@ Disabled ..\..\phnt\include;..\..\phlib\include;include;%(AdditionalIncludeDirectories) - _PHLIB_;_WINDOWS;WIN32;DEBUG;%(PreprocessorDefinitions) + _PHLIB_;_WINDOWS;WIN32;DEBUG;%(PreprocessorDefinitions);$(ExternalCompilerOptions) EnableFastChecks MultiThreadedDebug Level3 @@ -110,7 +110,7 @@ Disabled ..\..\phnt\include;..\..\phlib\include;include;%(AdditionalIncludeDirectories) - _PHLIB_;_WINDOWS;WIN64;DEBUG;%(PreprocessorDefinitions) + _PHLIB_;_WINDOWS;WIN64;DEBUG;%(PreprocessorDefinitions);$(ExternalCompilerOptions) EnableFastChecks MultiThreadedDebug Level3 @@ -136,7 +136,7 @@ MaxSpeed true ..\..\phnt\include;..\..\phlib\include;include;%(AdditionalIncludeDirectories) - _PHLIB_;_WINDOWS;WIN32;NDEBUG;%(PreprocessorDefinitions) + _PHLIB_;_WINDOWS;WIN32;NDEBUG;%(PreprocessorDefinitions);$(ExternalCompilerOptions) MultiThreaded true Level3 @@ -167,7 +167,7 @@ MaxSpeed true ..\..\phnt\include;..\..\phlib\include;include;%(AdditionalIncludeDirectories) - _PHLIB_;_WINDOWS;WIN64;DEBUG;%(PreprocessorDefinitions) + _PHLIB_;_WINDOWS;WIN64;DEBUG;%(PreprocessorDefinitions);$(ExternalCompilerOptions) MultiThreaded true Level3 @@ -217,8 +217,12 @@ - - + + _UNICODE;UNICODE;%(PreprocessorDefinitions);$(ExternalCompilerOptions) + _UNICODE;UNICODE;%(PreprocessorDefinitions);$(ExternalCompilerOptions) + _UNICODE;UNICODE;%(PreprocessorDefinitions);$(ExternalCompilerOptions) + _UNICODE;UNICODE;%(PreprocessorDefinitions);$(ExternalCompilerOptions) + diff --git a/tools/peview/peview.vcxproj.filters b/tools/peview/peview.vcxproj.filters index 95f381deb897..d81436dc0011 100644 --- a/tools/peview/peview.vcxproj.filters +++ b/tools/peview/peview.vcxproj.filters @@ -82,9 +82,6 @@ Resource Files - - Resource Files - diff --git a/tools/peview/version.rc b/tools/peview/version.rc deleted file mode 100644 index 1e412bb16d5e..000000000000 --- a/tools/peview/version.rc +++ /dev/null @@ -1,35 +0,0 @@ -#include "winres.h" -#include "../../ProcessHacker/include/phappres.h" - -VS_VERSION_INFO VERSIONINFO - FILEVERSION PHAPP_VERSION_NUMBER - PRODUCTVERSION PHAPP_VERSION_NUMBER - FILEFLAGSMASK 0x17L -#ifdef _DEBUG - FILEFLAGS 0x1L -#else - FILEFLAGS 0x0L -#endif - FILEOS 0x4L - FILETYPE 0x1L - FILESUBTYPE 0x0L -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "0c0904b0" - BEGIN - VALUE "CompanyName", "wj32" - VALUE "FileDescription", "PE Viewer" - VALUE "FileVersion", PHAPP_VERSION_STRING - VALUE "InternalName", "peview" - VALUE "LegalCopyright", "Licensed under the GNU GPL, v3." - VALUE "OriginalFilename", "peview.exe" - VALUE "ProductName", "Process Hacker" - VALUE "ProductVersion", PHAPP_VERSION_STRING - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0xc09, 1200 - END -END From 2ecc25aa9dfe0eb2a6792df014028b1e8c47aaf5 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 18 May 2017 10:21:16 +1000 Subject: [PATCH 0115/2058] BuildTools: Update binaries --- build/plugins.s | Bin 0 -> 112 bytes .../bin/Release/CustomBuildTool.exe | Bin 160768 -> 160768 bytes .../bin/Release/CustomBuildTool.pdb | Bin 73216 -> 73216 bytes 3 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 build/plugins.s diff --git a/build/plugins.s b/build/plugins.s new file mode 100644 index 0000000000000000000000000000000000000000..cf600c72ece7f007e4c7fea3f91d26a642a64f07 GIT binary patch literal 112 zcmV-$0FVE19B3RV%BJN2*Xa7QP$(n4dkQvD{M6^>5V73a3XNE>>QL;PM18Z`(*d1_ zq0rOx<9QyGEJ+6XGfmWn_M>jSfOpSkV}m=Z%76D7^z7aM*)fO5h?2mxZle=VJVP?q S%2OMjKC?GHLq`A(iP=RzO*!5G literal 0 HcmV?d00001 diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe b/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe index 242914120060012e249192a8733fa077e6dd59d1..7f7c097739684e258963a386f59e66dad60e2d35 100644 GIT binary patch delta 91 zcmZp8!P)SFb3zBx)E67O?9K_Kc`p|zG%xp9;9A-v_IZqiFf`VOw6JB0wpT%&?WtJ?TD6f3?wdM^^w{LjL7|;g*mE|L~ delta 91 zcmZp8!P)SFb3zBxg@+rv?9K^n_gg-F!LNFP2E1xcSDpHDWp!9?C>A009#a v%P=x9%wc9^nDdl@At=}-cv&X9+CpVszd37~I+wlgzummy>Glmz83XzNI?*Qe diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb b/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb index fcd1d1fea1e2a11a6ecf117d3056ba78e778ba97..bc235b89c2dcbb1092f5428f2f5908a299532850 100644 GIT binary patch delta 2264 zcmaKuT}TvB6vzLw&bn%DVX_*sX7p)>8I=!NltL7}i1bp?Lq7SUzVsj_(il=v_E0Rc zB9in{521(~TC@fRp?wfyABJTFT2x3_6c$v|IlFU5@7TTPW#)f>_kZp=ckT?+5;t4o zW}lg{s{Ld5m;s>r)A;#LOz!W@Umgk;w7ralGiKNMCpuH>>teyJ%lb`&X2rtqK7_21 za+;qAHeL+^2OJH^Y=+pRg56sV+*YuL73!REi(nhCoCtZrgIT~8fjq^$BKAz-yO|C6 ze8MQ_>o{%;KS%eBh24@Dy6G8W{R-F}D3?4I-Gp{C*1v!>F3ql%=Z=|H7|wG!K_V8g`f zXa|xZ?@Vzf@Kqp;1k1%e7a05gXQhuGO?#SAGUvQ0pP!&00p zUzqg~t8vD>ET<6IpkTW#g4-0ZmKbenBHW`-iWfXdEG>!PWlb928IRBHpOaqD7%zK_ z&f1A$IyAm+jqgSwEM2EnCzc@uQk4Djqfx2#QuAq z;Wv%(mu5j@^TG>5FR~k4=ssfO&gm4aif1s)Dh5umpb(JnnO!8do&|-M^%AR1q6CXJ zrx;CiYAZ{C=E!hkb~)lIoGvElJ&#)O|@kl+>7{CM5M% zQtu@-OKOzsG`WXpm*2>v&PuieFQV7{Mu>#D1E^03`dmck{KkNIqU2!L=+1@jH+_`c zU^Yceyx?9oLoCCY?PXsyz8_mO@Heq~Cuxwb(W-!vNB;*RxTwL#fN{xG{;v#%GmV+7 Ef63z5d;kCd delta 2440 zcmaKuT}V_x6vzLw&bphqhJ_lkeUN2pm{BQYk@!;dp!o4n(L+6ilzJh0kP_)yQeXuY zBI|=BzSu)4=C)d-MJ<6@g!Dm?8HLtENLeHneQf8hckF|61UIw7!uqVAe%~#xd?NnpOmkT37f80cxyXRNz!9zjc`h`9G`jK#T(EsjZ zl3uCN{Agnc@ykA7hZumJjT3tH^v(zY>d{RoXuv>=?5`c z5g*Zx`-P@ElFD)e`vi2b)5Q8EtS}ZxmIS(+%5X-)^ieOcN3v+{0-#vJ8i;L|uzSR+ zsRA?2UYYE8;HyBW^w}Os@cW;|#{FvcvMl{>wU}na{x==iW)8SuWg(uw7N{{A8|H;!t%?{GHQG3)3d}AT!rD<{UJ0vJcqbj6<^6=UMum9MAzFiJ zQFv_%?@9)AX@*@2u~)I-fWmt)$20RcO8QtKKA$7bJJfnGA|497J3ch(tA;6d$?^1)?sD3L+rFd2fLwQw-xNZg6R(x za9F`!D%e{E`(S68wz5qS95l;qFKM|JXmztxPq~(}5qJ@3ce5n=;F|y~`r)D(lWx|l zw^(jc9v|F1`$s7rd6vV? Date: Thu, 18 May 2017 10:34:19 +1000 Subject: [PATCH 0116/2058] BuildTools: Fix resource definitions, Bump version --- ProcessHacker/ProcessHacker.vcxproj | 5 +---- ProcessHacker/include/phappres.h | 2 +- tools/CustomBuildTool/Source Files/Build.cs | 4 ++-- .../bin/Release/CustomBuildTool.exe | Bin 160768 -> 160768 bytes .../bin/Release/CustomBuildTool.pdb | Bin 73216 -> 73216 bytes tools/peview/peview.vcxproj | 5 +---- 6 files changed, 5 insertions(+), 11 deletions(-) diff --git a/ProcessHacker/ProcessHacker.vcxproj b/ProcessHacker/ProcessHacker.vcxproj index ddbc487bed92..1869be83ebda 100644 --- a/ProcessHacker/ProcessHacker.vcxproj +++ b/ProcessHacker/ProcessHacker.vcxproj @@ -378,10 +378,7 @@ - _UNICODE;UNICODE;%(PreprocessorDefinitions);$(ExternalCompilerOptions) - _UNICODE;UNICODE;%(PreprocessorDefinitions);$(ExternalCompilerOptions) - _UNICODE;UNICODE;%(PreprocessorDefinitions);$(ExternalCompilerOptions) - _UNICODE;UNICODE;%(PreprocessorDefinitions);$(ExternalCompilerOptions) + _UNICODE;UNICODE;%(PreprocessorDefinitions);$(ExternalCompilerOptions) diff --git a/ProcessHacker/include/phappres.h b/ProcessHacker/include/phappres.h index c0267bfd3ea9..566ab7e62649 100644 --- a/ProcessHacker/include/phappres.h +++ b/ProcessHacker/include/phappres.h @@ -6,7 +6,7 @@ #endif #ifndef PHAPP_VERSION_MINOR -#define PHAPP_VERSION_MINOR 0 +#define PHAPP_VERSION_MINOR 1 #endif #ifndef PHAPP_VERSION_BUILD diff --git a/tools/CustomBuildTool/Source Files/Build.cs b/tools/CustomBuildTool/Source Files/Build.cs index d79db942fab8..97fd86fb868d 100644 --- a/tools/CustomBuildTool/Source Files/Build.cs +++ b/tools/CustomBuildTool/Source Files/Build.cs @@ -248,8 +248,8 @@ public static void ShowBuildEnvironment(string Platform, bool ShowBuildInfo, boo if (string.IsNullOrEmpty(BuildCount)) BuildCount = "0"; - BuildVersion = "3.0." + BuildRevision; - BuildLongVersion = "3.0." + BuildCount + "." + BuildRevision; + BuildVersion = "3.1." + BuildRevision; + BuildLongVersion = "3.1." + BuildCount + "." + BuildRevision; if (ShowBuildInfo) { diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe b/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe index 7f7c097739684e258963a386f59e66dad60e2d35..ed3777f571bd6771a2d2729f905bd1c11732ad64 100644 GIT binary patch delta 98 zcmZp8!P)SFb3zAG>g$bN^E(&~H*0mya}^N($DO}-ftdShj<6FNW(OW^zHx4im`=)T znMej8U;<(pMh1pC%!~|ko-!~51-k?rES0uBZ9c_eX1KJ-#iBPs%^RL>-|&<%pbr3X CwI#s- delta 98 zcmZp8!P)SFb3zBx)E67O=65g}Y}V?W=PHoqyC)7JY`@A3U&!jczLOP7Q-!h)6`b!!GPL=25Iq60^*?uk$MoZo)l56QiT=@fkcXz zmPq5)MnSxY1+fj0ZKz^;uSt=pXF;%fF%(ggcu0(ICbPPol6RST@Au6&^B&1YGjcQ| zr)0JL(l_5Z0swtaJC5cK&juf!?Qp%jRT$EJ>b`bYa&jXUE$;SA1^+x7EM_`ycU}DX zBD6rBSbJ1uzJF!s4c&g=Jdr1q*BA7W-uaa3&!HJy8S&?I->0wc_-WNf?H}6#PR2v6 z+TM~gKB#IZ*uv2GjyiHtT?UhBy5XVCl)O~GRB{d&H2^Aj-U=W||7*sMvPCz*Ba_R$ zvKN(_uk6J`Mo@ma6W|p-tD7cWy8u=iIBMatw;3R?2OxCcPCUvu?uO`2%QJJmP`)eE zOTrcLlFwLn<0Y)Y-jhq+(OFb8vV?V$I z*NSWkSx*C&M0U+!7Q8SKwvg$5?5!TO!E7(UTb|>nH?aqO09a#Tg<35Ul!;fubr{!y zT8$(2!&nrwX0{}-M2h>YZS{F0Xw5!(fhD??`g@MxD!k{5pf&pxkgf6p>uZMlENu0W z4+320S{u&5>~j-Y(!}PP$XujW8#@GWhL^V)dRz&NW>=Bn--JaA=6uW8M`XshMYfJi zZE$YGd@drG7R^v#6=X(lc7a_D0C@O?n^`OyMdsjaJH-AqA%O(Tv(02wZuo&)_O+08 F$6vX{;Q;^u delta 1350 zcmZ{kO=uHQ5Xa|jH=j0@7^5ZRL!^faY6Z4Kat z$a&e_KC&1*L;&E(x6=76yiaCBZGKNA^F|B0H@C07u=mVQ*HBXX+jDa`aOY#syKD0! z_YygB%h};}zRlYEdS8`@(qHvm-XGH9TRVyT{ppjO*4uSEuS6;~8xYjif}g(n!!vR0 z!i=`N;Q{F8KEO;|*{~Fl@YuN&h&5&otZvK{MO3ALEJH8Mu>4Y8CAUK5t`9(xmNUhT z7LWS@uA5Y@RM;rNN}#)Olw%=)N1_sk7FSvu2?IR-Zv$OdQk6hV*P|N&61>J}hdu#a zA3%1X2~&zVkgjXx%0-#JQL1WvqtDnFm*Cbo*dJuCjdoaGtg`jWD^$+e@I{4)Wxa$Q zV4YbdUSleUYt~t!E`WVaRL&yXWnxOcuJVE%+F~s%;i3=wsg4HUNh*J?T^T z$YhN&H|bW7@(bhRf-~>F@YIJQd)}P=OmLQ66rS2?5W%qyce%O)AaB>dWH z&PD<;z6c(4czHWO9}nS2FpRQ(WD`6>*{Ge2;`5){0dSCqSMie`v}6{U_`$VW*au_| z9<#CqWbP*Hhq(^>8%7)cHbaBdhp8eHyLl|^cobkgk6Bq7nU}LRQ=J47OkH)5lXBC4 L$Ejc|S@8Y?`w!wL diff --git a/tools/peview/peview.vcxproj b/tools/peview/peview.vcxproj index 7457b997abb7..dd34e986d496 100644 --- a/tools/peview/peview.vcxproj +++ b/tools/peview/peview.vcxproj @@ -218,10 +218,7 @@ - _UNICODE;UNICODE;%(PreprocessorDefinitions);$(ExternalCompilerOptions) - _UNICODE;UNICODE;%(PreprocessorDefinitions);$(ExternalCompilerOptions) - _UNICODE;UNICODE;%(PreprocessorDefinitions);$(ExternalCompilerOptions) - _UNICODE;UNICODE;%(PreprocessorDefinitions);$(ExternalCompilerOptions) + _UNICODE;UNICODE;%(PreprocessorDefinitions);$(ExternalCompilerOptions) From 4ccf1f85717aa1c77978d9a819d6f60ca1713c1f Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 18 May 2017 10:55:25 +1000 Subject: [PATCH 0117/2058] Update solution resource includes --- ProcessHacker.sln | 19 ------------------- ProcessHacker/ProcessHacker.vcxproj | 1 + tools/peview/peview.vcxproj | 1 + 3 files changed, 2 insertions(+), 19 deletions(-) diff --git a/ProcessHacker.sln b/ProcessHacker.sln index c2fa6bcc9b31..4e87a04af677 100644 --- a/ProcessHacker.sln +++ b/ProcessHacker.sln @@ -3,8 +3,6 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 VisualStudioVersion = 15.0.26430.6 MinimumVisualStudioVersion = 15.0.26228.4 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tools", "Tools", "{2758DC86-368B-430C-9D29-F1EF20032A71}" -EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ProcessHacker", "ProcessHacker\ProcessHacker.vcxproj", "{0271DD27-6707-4290-8DFE-285702B7115D}" ProjectSection(ProjectDependencies) = postProject {477D0215-F252-41A1-874B-F27E3EA1ED17} = {477D0215-F252-41A1-874B-F27E3EA1ED17} @@ -12,12 +10,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ProcessHacker", "ProcessHac EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "phlib", "phlib\phlib.vcxproj", "{477D0215-F252-41A1-874B-F27E3EA1ED17}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fixlib", "tools\fixlib\fixlib.vcxproj", "{31F4AA06-7ED5-4A6D-B901-19AD4BD16175}" -EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "peview", "tools\peview\peview.vcxproj", "{72C124A2-3C80-41C6-ABA1-C4948B713204}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CustomSignTool", "tools\CustomSignTool\CustomSignTool.vcxproj", "{E8CD0A41-1537-4EA6-98AC-E80CD59C478E}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 @@ -42,10 +36,6 @@ Global {477D0215-F252-41A1-874B-F27E3EA1ED17}.Release|Win32.Build.0 = Release|Win32 {477D0215-F252-41A1-874B-F27E3EA1ED17}.Release|x64.ActiveCfg = Release|x64 {477D0215-F252-41A1-874B-F27E3EA1ED17}.Release|x64.Build.0 = Release|x64 - {31F4AA06-7ED5-4A6D-B901-19AD4BD16175}.Debug|Win32.ActiveCfg = Debug|Win32 - {31F4AA06-7ED5-4A6D-B901-19AD4BD16175}.Debug|x64.ActiveCfg = Debug|Win32 - {31F4AA06-7ED5-4A6D-B901-19AD4BD16175}.Release|Win32.ActiveCfg = Release|Win32 - {31F4AA06-7ED5-4A6D-B901-19AD4BD16175}.Release|x64.ActiveCfg = Release|Win32 {72C124A2-3C80-41C6-ABA1-C4948B713204}.Debug|Win32.ActiveCfg = Debug|Win32 {72C124A2-3C80-41C6-ABA1-C4948B713204}.Debug|Win32.Build.0 = Debug|Win32 {72C124A2-3C80-41C6-ABA1-C4948B713204}.Debug|x64.ActiveCfg = Debug|x64 @@ -54,17 +44,8 @@ Global {72C124A2-3C80-41C6-ABA1-C4948B713204}.Release|Win32.Build.0 = Release|Win32 {72C124A2-3C80-41C6-ABA1-C4948B713204}.Release|x64.ActiveCfg = Release|x64 {72C124A2-3C80-41C6-ABA1-C4948B713204}.Release|x64.Build.0 = Release|x64 - {E8CD0A41-1537-4EA6-98AC-E80CD59C478E}.Debug|Win32.ActiveCfg = Debug|Win32 - {E8CD0A41-1537-4EA6-98AC-E80CD59C478E}.Debug|x64.ActiveCfg = Debug|x64 - {E8CD0A41-1537-4EA6-98AC-E80CD59C478E}.Release|Win32.ActiveCfg = Release|Win32 - {E8CD0A41-1537-4EA6-98AC-E80CD59C478E}.Release|x64.ActiveCfg = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection - GlobalSection(NestedProjects) = preSolution - {31F4AA06-7ED5-4A6D-B901-19AD4BD16175} = {2758DC86-368B-430C-9D29-F1EF20032A71} - {72C124A2-3C80-41C6-ABA1-C4948B713204} = {2758DC86-368B-430C-9D29-F1EF20032A71} - {E8CD0A41-1537-4EA6-98AC-E80CD59C478E} = {2758DC86-368B-430C-9D29-F1EF20032A71} - EndGlobalSection EndGlobal diff --git a/ProcessHacker/ProcessHacker.vcxproj b/ProcessHacker/ProcessHacker.vcxproj index 1869be83ebda..1c52fe1b7730 100644 --- a/ProcessHacker/ProcessHacker.vcxproj +++ b/ProcessHacker/ProcessHacker.vcxproj @@ -379,6 +379,7 @@ _UNICODE;UNICODE;%(PreprocessorDefinitions);$(ExternalCompilerOptions) + ..\phnt\include;..\phlib\include;include;%(AdditionalIncludeDirectories) diff --git a/tools/peview/peview.vcxproj b/tools/peview/peview.vcxproj index dd34e986d496..616289ae31be 100644 --- a/tools/peview/peview.vcxproj +++ b/tools/peview/peview.vcxproj @@ -219,6 +219,7 @@ _UNICODE;UNICODE;%(PreprocessorDefinitions);$(ExternalCompilerOptions) + ..\..\phnt\include;..\..\phlib\include;include;%(AdditionalIncludeDirectories) From 793f1e5128d99834a2c0c6195e9ba85145973191 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 18 May 2017 10:59:55 +1000 Subject: [PATCH 0118/2058] Update appveryor config --- appveyor.yml | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 1eb83fda0bb2..d8da52ff95a5 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,8 +1,5 @@ -# Build image. -image: Visual Studio 2017 - # Version format. -version: "3.0.{build}" +version: "3.1.{build}" # Only build the master branch. branches: @@ -15,8 +12,10 @@ pull_requests: # Do not start a new build when a new Git tag is created. skip_tags: true - + # Set the clone directory on the buildbot. +clone_depth: 1 +shallow_clone: true clone_folder: C:\projects\processhacker # Immediately finish build if something fails. @@ -28,13 +27,4 @@ test: off # Run custom build script. build_script: -- cmd: tools\CustomBuildTool\bin\Release\CustomBuildTool.exe -appveyor - -# Setup build notifications. -notifications: -- provider: Email - to: - - dmex04@gmail.com - on_build_success: false - on_build_failure: true - on_build_status_changed: false \ No newline at end of file +- cmd: tools\CustomBuildTool\bin\Release\CustomBuildTool.exe -appveyor \ No newline at end of file From 6f42ddcd38f919c3a5ade3d1a6c0d51e9cb0d44b Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 18 May 2017 11:23:26 +1000 Subject: [PATCH 0119/2058] Fix build --- appveyor.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index d8da52ff95a5..8ff4ed33c3c6 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -14,8 +14,6 @@ pull_requests: skip_tags: true # Set the clone directory on the buildbot. -clone_depth: 1 -shallow_clone: true clone_folder: C:\projects\processhacker # Immediately finish build if something fails. From ab295b20b10854310d643061edc9187b3e0c5c88 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 18 May 2017 11:33:28 +1000 Subject: [PATCH 0120/2058] Fix appx builds --- .../CustomBuildTool/Properties/Resources.resx | 2 +- tools/CustomBuildTool/Source Files/Build.cs | 21 ++++++++---------- .../bin/Release/CustomBuildTool.exe | Bin 160768 -> 160768 bytes .../bin/Release/CustomBuildTool.pdb | Bin 73216 -> 73216 bytes 4 files changed, 10 insertions(+), 13 deletions(-) diff --git a/tools/CustomBuildTool/Properties/Resources.resx b/tools/CustomBuildTool/Properties/Resources.resx index 083dd1a65c62..646f2393cb4d 100644 --- a/tools/CustomBuildTool/Properties/Resources.resx +++ b/tools/CustomBuildTool/Properties/Resources.resx @@ -139,7 +139,7 @@ <Resource Language="en-US" /> </Resources> <Dependencies> - <TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.14316.0" MaxVersionTested="10.0.15063.0" /> + <TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.10240.0" MaxVersionTested="10.0.15063.0" /> </Dependencies> <Capabilities> <rescap:Capability Name="runFullTrust"/> diff --git a/tools/CustomBuildTool/Source Files/Build.cs b/tools/CustomBuildTool/Source Files/Build.cs index 97fd86fb868d..e28f5d2e6679 100644 --- a/tools/CustomBuildTool/Source Files/Build.cs +++ b/tools/CustomBuildTool/Source Files/Build.cs @@ -254,22 +254,19 @@ public static void ShowBuildEnvironment(string Platform, bool ShowBuildInfo, boo if (ShowBuildInfo) { Program.PrintColorMessage("Version: ", ConsoleColor.Cyan, false); - Program.PrintColorMessage(BuildLongVersion + Environment.NewLine, ConsoleColor.White); + Program.PrintColorMessage(BuildVersion + Environment.NewLine, ConsoleColor.White); - if (ShowLogInfo) + if (!BuildNightly && ShowLogInfo) { - if (BuildNightly) - BuildMessage = Win32.ShellExecute(GitExePath, "log -n 5 --date=format:%Y-%m-%d --pretty=format:\"[%cd] %an: %<(65,trunc)%s (%h)\" --abbrev-commit"); - else - { - Win32.GetConsoleMode(Win32.GetStdHandle(Win32.STD_OUTPUT_HANDLE), out ConsoleMode mode); - Win32.SetConsoleMode(Win32.GetStdHandle(Win32.STD_OUTPUT_HANDLE), mode | ConsoleMode.ENABLE_VIRTUAL_TERMINAL_PROCESSING); - - //BuildMessage = Win32.ShellExecute(GitExePath, "log -n 5 --date=format:%Y-%m-%d --pretty=format:\"[%cd] %an %s\" --abbrev-commit"); - BuildMessage = Win32.ShellExecute(GitExePath, "log -n 5 --date=format:%Y-%m-%d --pretty=format:\"%C(green)[%cd]%Creset %C(bold blue)%an%Creset %<(65,trunc)%s%Creset (%C(yellow)%h%Creset)\" --abbrev-commit"); - } + Win32.GetConsoleMode(Win32.GetStdHandle(Win32.STD_OUTPUT_HANDLE), out ConsoleMode mode); + Win32.SetConsoleMode(Win32.GetStdHandle(Win32.STD_OUTPUT_HANDLE), mode | ConsoleMode.ENABLE_VIRTUAL_TERMINAL_PROCESSING); + BuildMessage = Win32.ShellExecute(GitExePath, "log -n 5 --date=format:%Y-%m-%d --pretty=format:\"%C(green)[%cd]%Creset %C(bold blue)%an%Creset %<(65,trunc)%s%Creset (%C(yellow)%h%Creset)\" --abbrev-commit"); Console.WriteLine(BuildMessage + Environment.NewLine); + + //BuildMessage = Win32.ShellExecute(GitExePath, "log -n 5 --date=format:%Y-%m-%d --pretty=format:\"[%cd] %an %s\" --abbrev-commit"); + //BuildMessage = Win32.ShellExecute(GitExePath, "log -n 1 --date=format:%Y-%m-%d --pretty=format:\"[%cd] %an: %<(65,trunc)%s (%h)\" --abbrev-commit"); + //Console.WriteLine(BuildMessage + Environment.NewLine); } } } diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe b/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe index ed3777f571bd6771a2d2729f905bd1c11732ad64..08ce7bfcb34d89826a121b6c5048bbcddc46aad4 100644 GIT binary patch delta 7410 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 diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb b/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb index 00c761c02ccc38c87155b28f1e5a63649c6f227b..6dc929151821cb21836568e5c81657a06f51ad72 100644 GIT binary patch delta 8845 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 Date: Thu, 18 May 2017 11:57:38 +1000 Subject: [PATCH 0121/2058] Fix Appveyor build image --- appveyor.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/appveyor.yml b/appveyor.yml index 8ff4ed33c3c6..c97fce5fff29 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,3 +1,6 @@ +# Build image. +image: Visual Studio 2017 + # Version format. version: "3.1.{build}" From fb64f5c9061bbb67e096e2189837e96833141908 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 18 May 2017 12:08:33 +1000 Subject: [PATCH 0122/2058] BuildTools: Update binary --- tools/CustomBuildTool/Source Files/Build.cs | 23 +++--------------- tools/CustomBuildTool/Source Files/Program.cs | 1 + .../bin/Release/CustomBuildTool.exe | Bin 160768 -> 160256 bytes .../bin/Release/CustomBuildTool.pdb | Bin 73216 -> 73216 bytes 4 files changed, 4 insertions(+), 20 deletions(-) diff --git a/tools/CustomBuildTool/Source Files/Build.cs b/tools/CustomBuildTool/Source Files/Build.cs index e28f5d2e6679..bf8d9f3ab76f 100644 --- a/tools/CustomBuildTool/Source Files/Build.cs +++ b/tools/CustomBuildTool/Source Files/Build.cs @@ -874,10 +874,6 @@ public static bool BuildUpdateSignature() public static void WebServiceUpdateConfig() { - string buildPostString; - string buildPosturl; - string buildPostApiKey; - if (string.IsNullOrEmpty(BuildSetupHash)) return; if (string.IsNullOrEmpty(BuildBinHash)) @@ -887,7 +883,7 @@ public static void WebServiceUpdateConfig() if (string.IsNullOrEmpty(BuildMessage)) return; - buildPostString = Json.Serialize(new BuildUpdateRequest + string buildPostString = Json.Serialize(new BuildUpdateRequest { Updated = TimeStart.ToString("o"), Version = BuildVersion, @@ -904,8 +900,8 @@ public static void WebServiceUpdateConfig() if (string.IsNullOrEmpty(buildPostString)) return; - buildPosturl = Environment.ExpandEnvironmentVariables("%APPVEYOR_BUILD_API%").Replace("%APPVEYOR_BUILD_API%", string.Empty); - buildPostApiKey = Environment.ExpandEnvironmentVariables("%APPVEYOR_BUILD_KEY%").Replace("%APPVEYOR_BUILD_KEY%", string.Empty); + string buildPosturl = Environment.ExpandEnvironmentVariables("%APPVEYOR_BUILD_API%").Replace("%APPVEYOR_BUILD_API%", string.Empty); + string buildPostApiKey = Environment.ExpandEnvironmentVariables("%APPVEYOR_BUILD_KEY%").Replace("%APPVEYOR_BUILD_KEY%", string.Empty); if (string.IsNullOrEmpty(buildPosturl)) return; @@ -1006,19 +1002,6 @@ public static bool AppveyorUploadBuildFiles() } } - if (File.Exists(releaseFileArray[0])) - { - try - { - Win32.ShellExecute("appveyor", "UpdateBuild -Version \"" + BuildLongVersion + " (" + BuildCommit + ")\" "); - } - catch (Exception ex) - { - Program.PrintColorMessage("[WebServicePushArtifact] " + ex, ConsoleColor.Red); - return false; - } - } - return true; } diff --git a/tools/CustomBuildTool/Source Files/Program.cs b/tools/CustomBuildTool/Source Files/Program.cs index 65f25f628144..09f0d6b1ff10 100644 --- a/tools/CustomBuildTool/Source Files/Program.cs +++ b/tools/CustomBuildTool/Source Files/Program.cs @@ -176,6 +176,7 @@ public static void Main(string[] args) if (!Build.CopyKProcessHacker(false)) return; + if (!BuildSdk(BuildFlags.Build32bit | BuildFlags.Build64bit | BuildFlags.BuildVerbose)) return; diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe b/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe index 08ce7bfcb34d89826a121b6c5048bbcddc46aad4..ed095f0207c5e65154ea749ffa73790d17ca4d0d 100644 GIT binary patch delta 8251 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ⅅljuiXUdF23ldH#yfZGH_Eyu9B0k8H1Bb} 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 W@t60+UuM^rN;&y^4kWRk*#7`7z<@~r diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb b/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb index 6dc929151821cb21836568e5c81657a06f51ad72..d828175e2ea5c88db29efd0da8cb60fbd4b673d2 100644 GIT binary patch delta 8249 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 delta 7988 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 Date: Thu, 18 May 2017 12:17:07 +1000 Subject: [PATCH 0123/2058] Add build debugging --- .../bin/Release/CustomBuildTool.exe | Bin 160256 -> 160768 bytes .../bin/Release/CustomBuildTool.pdb | Bin 73216 -> 73216 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe b/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe index ed095f0207c5e65154ea749ffa73790d17ca4d0d..403baffd8b299f948b8c40af4d1bc1b6ac289c8e 100644 GIT binary patch delta 5517 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 EUyg6le*gdg delta 5127 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 From cb7db95f93d5578f5bb61181d0b261d397a94b56 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 18 May 2017 12:26:07 +1000 Subject: [PATCH 0124/2058] Fix appveyor build --- tools/CustomBuildTool/Source Files/Build.cs | 5 ++--- .../bin/Release/CustomBuildTool.exe | Bin 160768 -> 160768 bytes .../bin/Release/CustomBuildTool.pdb | Bin 73216 -> 73216 bytes 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/tools/CustomBuildTool/Source Files/Build.cs b/tools/CustomBuildTool/Source Files/Build.cs index bf8d9f3ab76f..1f929a3ec506 100644 --- a/tools/CustomBuildTool/Source Files/Build.cs +++ b/tools/CustomBuildTool/Source Files/Build.cs @@ -880,9 +880,8 @@ public static void WebServiceUpdateConfig() return; if (string.IsNullOrEmpty(BuildSetupSig)) return; - if (string.IsNullOrEmpty(BuildMessage)) - return; + string appveyorMessage = Win32.ShellExecute(GitExePath, "log -n 5 --date=format:%Y-%m-%d --pretty=format:\"[%cd] %an %s\" --abbrev-commit"); string buildPostString = Json.Serialize(new BuildUpdateRequest { Updated = TimeStart.ToString("o"), @@ -894,7 +893,7 @@ public static void WebServiceUpdateConfig() HashSetup = BuildSetupHash, HashBin = BuildBinHash, sig = BuildSetupSig, - Message = BuildMessage + Message = appveyorMessage }); if (string.IsNullOrEmpty(buildPostString)) diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe b/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe index 403baffd8b299f948b8c40af4d1bc1b6ac289c8e..a922dfbf78d445fbde7a9cd7675ce0c457899a42 100644 GIT binary patch delta 8946 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 delta 9334 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 delta 6015 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 jch3w^E>+mDE Date: Thu, 18 May 2017 13:27:16 +1000 Subject: [PATCH 0125/2058] BuildTool: Update setup solution --- .../CustomSetupTool/CustomSetupTool.vcxproj | 19 ++++++------------- .../CustomSetupTool/resource.rc | 12 +++++++----- 2 files changed, 13 insertions(+), 18 deletions(-) diff --git a/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj b/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj index 253d75de4c0e..ec82116e1157 100644 --- a/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj +++ b/tools/CustomSetupTool/CustomSetupTool/CustomSetupTool.vcxproj @@ -57,7 +57,7 @@ false StdCall MultiThreadedDebug - _PHLIB_;_WINDOWS;WIN32;DEBUG;%(PreprocessorDefinitions) + _PHLIB_;_WINDOWS;WIN32;DEBUG;%(PreprocessorDefinitions);$(ExternalCompilerOptions) true ProgramDatabase true @@ -69,11 +69,6 @@ Windows RequireAdministrator - - - - - @@ -84,7 +79,7 @@ true ..\..\..\phnt\include;..\..\..\phlib\include;include;%(AdditionalIncludeDirectories) StdCall - _PHLIB_;_WINDOWS;WIN32;NDEBUG;%(PreprocessorDefinitions) + _PHLIB_;_WINDOWS;WIN32;NDEBUG;%(PreprocessorDefinitions);$(ExternalCompilerOptions) MultiThreaded true AnySuitable @@ -102,11 +97,6 @@ true RequireAdministrator - - - - - @@ -128,7 +118,10 @@ - + + _UNICODE;UNICODE;%(PreprocessorDefinitions);$(ExternalCompilerOptions) + ..\..\..\phnt\include;..\..\..\phlib\include;include;%(AdditionalIncludeDirectories) + diff --git a/tools/CustomSetupTool/CustomSetupTool/resource.rc b/tools/CustomSetupTool/CustomSetupTool/resource.rc index cf68f769845f..887108157590 100644 --- a/tools/CustomSetupTool/CustomSetupTool/resource.rc +++ b/tools/CustomSetupTool/CustomSetupTool/resource.rc @@ -8,6 +8,7 @@ // Generated from the TEXTINCLUDE 2 resource. // #include "winres.h" +#include "../../../ProcessHacker/include/phappres.h" ///////////////////////////////////////////////////////////////////////////// #undef APSTUDIO_READONLY_SYMBOLS @@ -179,8 +180,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,0,0,0 - PRODUCTVERSION 1,0,0,0 + FILEVERSION PHAPP_VERSION_NUMBER + PRODUCTVERSION PHAPP_VERSION_NUMBER FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -197,12 +198,12 @@ BEGIN BEGIN VALUE "CompanyName", "Process Hacker" VALUE "FileDescription", "Process Hacker Setup" - VALUE "FileVersion", "1.0" + VALUE "FileVersion", PHAPP_VERSION_STRING VALUE "InternalName", "Process Hacker Setup" - VALUE "LegalCopyright", "(C) Process Hacker Team. Licensed under the GNU GPL, v3." + VALUE "LegalCopyright", "Licensed under the GNU GPL, v3. Copyright (C) 2017" VALUE "OriginalFilename", "ProcessHackerSetup.exe" VALUE "ProductName", "Process Hacker Setup" - VALUE "ProductVersion", "1.0" + VALUE "ProductVersion", PHAPP_VERSION_STRING END END BLOCK "VarFileInfo" @@ -254,6 +255,7 @@ END 2 TEXTINCLUDE BEGIN "#include ""winres.h""\r\n" + "#include ""../../../include/phappres.h""\r\n" "\0" END From 43bca697d2082a6d367295b432bcf424357fc126 Mon Sep 17 00:00:00 2001 From: dmex Date: Thu, 18 May 2017 20:54:34 +1000 Subject: [PATCH 0126/2058] BuilldTools: Revert version test --- ProcessHacker/include/phappres.h | 2 +- tools/CustomBuildTool/Source Files/Build.cs | 4 ++-- .../bin/Release/CustomBuildTool.exe | Bin 160768 -> 160768 bytes .../bin/Release/CustomBuildTool.pdb | Bin 73216 -> 73216 bytes 4 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ProcessHacker/include/phappres.h b/ProcessHacker/include/phappres.h index 566ab7e62649..c0267bfd3ea9 100644 --- a/ProcessHacker/include/phappres.h +++ b/ProcessHacker/include/phappres.h @@ -6,7 +6,7 @@ #endif #ifndef PHAPP_VERSION_MINOR -#define PHAPP_VERSION_MINOR 1 +#define PHAPP_VERSION_MINOR 0 #endif #ifndef PHAPP_VERSION_BUILD diff --git a/tools/CustomBuildTool/Source Files/Build.cs b/tools/CustomBuildTool/Source Files/Build.cs index 1f929a3ec506..677ae2aa0adf 100644 --- a/tools/CustomBuildTool/Source Files/Build.cs +++ b/tools/CustomBuildTool/Source Files/Build.cs @@ -248,8 +248,8 @@ public static void ShowBuildEnvironment(string Platform, bool ShowBuildInfo, boo if (string.IsNullOrEmpty(BuildCount)) BuildCount = "0"; - BuildVersion = "3.1." + BuildRevision; - BuildLongVersion = "3.1." + BuildCount + "." + BuildRevision; + BuildVersion = "3.0." + BuildRevision; + BuildLongVersion = "3.0." + BuildCount + "." + BuildRevision; if (ShowBuildInfo) { diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe b/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe index a922dfbf78d445fbde7a9cd7675ce0c457899a42..06ce779430fce6fa5fada71005b8058b72fc6bd0 100644 GIT binary patch delta 98 zcmZp8!P)SFb3zA`Q|-ns@eW3V&5JsmTm`sHyh{TYUw55l{(Pg(KDngLU(T)(({Zeo zjbs1YRCynfcBCT)uN=)|z&;rd_?R zy2k|fk6)_*=w5WO*0J#Aypyf(lx+>g86lrLW6Y?DyCz(HdMT~?xw;^@+O;6i-(1&p zBiO7oI#b>D`HqL~`yo$OsiJC+d!~mfvaeis#Zz18dz}*v`Ch$G(%wY%YyD8rq8|1D zMT3|0*J_<)F9dca5x6C=^5Nn(FKdKH_36b9Ylk@_fa3;ng9(#$3vy??z*&LiCIRP7 zrWx()v+qm>zNp3>>tJq=12RoP<0(D&(Fe2{H@JZ|jt6er3^cdtEn7bc8e)q}PHo4Q zMt@X+x2$b45M(*tev&O0Sn(7fjRN|?=XR$6C)i*Htv>Hpa{aM>duVL$GF5AdO@2K~ z^BX|FUnj60YL!aM4)Ziy)Lyc7LGC8?SZ>5Lu6ABKP--A&m1OM#n?{997IZkr0UQ#T z_P`002pXN>0+tA@f^3$+n#d|x&H0KZCjeiEavsaO82a{mq)qddscFDW_7Dx+v`K8y zIb?I0+3?Vmw?%7BIjgm(cgU((E{>~gz8~0R7{4Uv2&Wpz1@DsO{MY=E&twi}D*O?4 zN;}ja`9Vg7j~%>e{gR+PT^#g~i8>r5$@#1~%`(yyNpQL~XvyVCa)pvyFrB_nPC;oF zNrFoy9hOLP<$TWgKI-eVSrV+|gKW@xu1b>IFU$qhgJhcVTG{2pOf++Z)f zoyq|AumSLvmR9rJ3zMVzqx^dF0y?% z-5;ko>pQC5E(HSvOR|9{_2Fu-rkB7+FPpK&om_cRBsNWAxe_ZFGL3enbv?S@%bZ^M`(E6S#f2fy~$uylo+Kvo?9#ZO*OX8r@?? pi-kLC$c(vp5bj{@Q%%AhpU6hD8@jbtIFvK0@c-FXUxM;>#2*O-OC|sS delta 2641 zcmaKuTS!zv7{~u7&$_F*mU+o)ElX1~?~0h+G*BqavJ4F$v>wuEix3i|%Q2(-OC_1z z2$K*Z!rH_HEhLB_>_G~lUWB3tAu6aaDYtKS=WIKJbLM6C`+oDE?=m~H+cu=P4e5P) zc>Lnfgxwl|^IH<#!}E`n-MzX#qcaU_S^QfnNx6CP()ou&__t*Q37vwQn4Z?ox|R@mrqO?-|uR=uX3eS?KK>jcWV z4Tx-%*n0)*jRc-5Sp7Wpp7#ub7g=QA5Ci5!0hdiAB{M>7T%qfV2CgeuZY*#sh#BVo z%r_bbeA7*jn9T4JATvm4u41l97cgi#q(plXfZ;hN4BoR}Z%Bjz-_a7+u(r`$rlDUS zTn?0Shs>sl?NG3a6+nvShqA6Y3Ano20KWg%Ifc9E`SEwb9HU>?Q-F1Rk$9j$39(I_1!9oR3TzM3 ziOlPLMy!SFLg4lCkEHW@3sQl7CNm^>gWyUNO6)nYoLL$0m6)BgzzrjtCHjjPHQqO5 zX3SU!ZE0$ulb9-CjD^l6>H_bBFViFo;c8LH>+x5ZXQ3;$(3Pf9e21bnn=ORfEdthB z=;~#iSwB0cMhoE~S;&)Sx)uxFaSPpPVupFG=(-06+w=v&u@JvYW>+(SR=!$hk(ofU zg5?oAATodbEZ}W|#T Date: Thu, 18 May 2017 20:55:41 +1000 Subject: [PATCH 0127/2058] Appveyor: revert version test --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index c97fce5fff29..fcbc818fe0f8 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -2,7 +2,7 @@ image: Visual Studio 2017 # Version format. -version: "3.1.{build}" +version: "3.0.{build}" # Only build the master branch. branches: From 574d2325061c4c801f7ca9313c8a3e1996729100 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 19 May 2017 00:21:28 +1000 Subject: [PATCH 0128/2058] BuildTools: Cleanup solution --- tools/CustomBuildTool/CustomBuildTool.csproj | 5 +- tools/CustomBuildTool/Source Files/Build.cs | 47 ++- .../CustomBuildTool/Source Files/HeaderGen.cs | 24 +- tools/CustomBuildTool/Source Files/Json.cs | 35 -- .../Source Files/NativeMethods.cs | 126 ++---- tools/CustomBuildTool/Source Files/Nightly.cs | 38 -- tools/CustomBuildTool/Source Files/Program.cs | 24 +- tools/CustomBuildTool/Source Files/Utils.cs | 380 ++++++++++++++++++ tools/CustomBuildTool/Source Files/Verify.cs | 59 --- .../Source Files/VisualStudio.cs | 133 ------ tools/CustomBuildTool/Source Files/Zip.cs | 25 +- .../bin/Release/CustomBuildTool.exe | Bin 160768 -> 160768 bytes .../bin/Release/CustomBuildTool.pdb | Bin 73216 -> 69120 bytes 13 files changed, 513 insertions(+), 383 deletions(-) delete mode 100644 tools/CustomBuildTool/Source Files/Json.cs delete mode 100644 tools/CustomBuildTool/Source Files/Nightly.cs create mode 100644 tools/CustomBuildTool/Source Files/Utils.cs delete mode 100644 tools/CustomBuildTool/Source Files/Verify.cs delete mode 100644 tools/CustomBuildTool/Source Files/VisualStudio.cs diff --git a/tools/CustomBuildTool/CustomBuildTool.csproj b/tools/CustomBuildTool/CustomBuildTool.csproj index 2e456e11dfed..83a5df2111b6 100644 --- a/tools/CustomBuildTool/CustomBuildTool.csproj +++ b/tools/CustomBuildTool/CustomBuildTool.csproj @@ -86,14 +86,11 @@ - - - - + diff --git a/tools/CustomBuildTool/Source Files/Build.cs b/tools/CustomBuildTool/Source Files/Build.cs index 677ae2aa0adf..136c97c1f0a6 100644 --- a/tools/CustomBuildTool/Source Files/Build.cs +++ b/tools/CustomBuildTool/Source Files/Build.cs @@ -1,4 +1,26 @@ -using System; +/* + * Process Hacker Toolchain - + * Build script + * + * Copyright (C) 2017 dmex + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +using System; using System.IO; using System.Net.Http; using System.Security; @@ -11,7 +33,7 @@ namespace CustomBuildTool public static class Build { private static DateTime TimeStart; - private static bool BuildNightly = false; + private static bool BuildNightly; private static string BuildBranch; private static string BuildOutputFolder = "build"; private static string BuildCommit; @@ -232,8 +254,8 @@ public static string GetBuildLogString() public static void ShowBuildEnvironment(string Platform, bool ShowBuildInfo, bool ShowLogInfo) { - BuildBranch = Win32.ShellExecute(GitExePath, "rev-parse --abbrev-ref HEAD"); - BuildCommit = Win32.ShellExecute(GitExePath, "rev-parse --short HEAD"); // rev-parse HEAD + BuildBranch = Win32.ShellExecute(GitExePath, "rev-parse --abbrev-ref HEAD").Trim(); + BuildCommit = Win32.ShellExecute(GitExePath, "rev-parse --short HEAD").Trim(); // rev-parse HEAD Program.PrintColorMessage("Branch: ", ConsoleColor.Cyan, false); Program.PrintColorMessage(BuildBranch, ConsoleColor.White); Program.PrintColorMessage("Commit: ", ConsoleColor.Cyan, false); @@ -681,7 +703,7 @@ public static bool BuildSetupExe() { Program.PrintColorMessage("Building build-setup.exe...", ConsoleColor.Cyan, true, BuildFlags.BuildVerbose); - if (!BuildSolution("tools\\CustomSetupTool\\CustomSetupTool.sln", BuildFlags.Build32bit)) + if (!BuildSolution("tools\\CustomSetupTool\\CustomSetupTool.sln", BuildFlags.Build32bit | BuildFlags.BuildVerbose)) return false; try @@ -951,6 +973,7 @@ public static bool AppveyorUploadBuildFiles() if (!BuildNightly) return false; + // Cleanup existing output files for (int i = 0; i < releaseFileArray.Length; i++) { if (File.Exists(releaseFileArray[i])) @@ -967,6 +990,7 @@ public static bool AppveyorUploadBuildFiles() } } + // Rename files with the current build version -3.1- for (int i = 0; i < buildFileArray.Length; i++) { if (File.Exists(buildFileArray[i])) @@ -983,6 +1007,7 @@ public static bool AppveyorUploadBuildFiles() } } + // Upload build files to Appveyor storage. for (int i = 0; i < releaseFileArray.Length; i++) { if (File.Exists(releaseFileArray[i])) @@ -1001,6 +1026,14 @@ public static bool AppveyorUploadBuildFiles() } } + try + { + // Update Appveyor build version string. + Win32.ShellExecute("appveyor", "UpdateBuild -Version \"" + BuildLongVersion + " (" + BuildCommit + ")\" "); + } + catch (Exception) + { } + return true; } @@ -1015,7 +1048,7 @@ public static bool BuildSolution(string Solution, BuildFlags Flags) string error32 = Win32.ShellExecute( MSBuildExePath, "/m /nologo /verbosity:quiet " + - "/p:Configuration=" + (Flags.HasFlag(BuildFlags.BuildDebug) ? "Debug" : "Release") + " " + + "/p:Configuration=" + (Flags.HasFlag(BuildFlags.BuildDebug) ? "Debug " : "Release ") + "/p:Platform=Win32 " + "/p:ExternalCompilerOptions=\"PH_BUILD_API;PHAPP_VERSION_REVISION=\"" + BuildRevision + "\";PHAPP_VERSION_BUILD=\"" + BuildCount + "\"\" " + Solution @@ -1037,7 +1070,7 @@ public static bool BuildSolution(string Solution, BuildFlags Flags) string error64 = Win32.ShellExecute( MSBuildExePath, "/m /nologo /verbosity:quiet " + - "/p:Configuration=" + (Flags.HasFlag(BuildFlags.BuildDebug) ? "Debug" : "Release") + " " + + "/p:Configuration=" + (Flags.HasFlag(BuildFlags.BuildDebug) ? "Debug " : "Release ") + "/p:Platform=x64 " + "/p:ExternalCompilerOptions=\"PH_BUILD_API;PHAPP_VERSION_REVISION=\"" + BuildRevision + "\";PHAPP_VERSION_BUILD=\"" + BuildCount + "\"\" " + Solution diff --git a/tools/CustomBuildTool/Source Files/HeaderGen.cs b/tools/CustomBuildTool/Source Files/HeaderGen.cs index cd4c1dbe70a4..dd4f9b9e5b53 100644 --- a/tools/CustomBuildTool/Source Files/HeaderGen.cs +++ b/tools/CustomBuildTool/Source Files/HeaderGen.cs @@ -1,4 +1,26 @@ -using System; +/* + * Process Hacker Toolchain - + * Build script + * + * Copyright (C) 2017 dmex + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +using System; using System.IO; using System.Linq; using System.Collections.Generic; diff --git a/tools/CustomBuildTool/Source Files/Json.cs b/tools/CustomBuildTool/Source Files/Json.cs deleted file mode 100644 index ea01ac43c211..000000000000 --- a/tools/CustomBuildTool/Source Files/Json.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Runtime.Serialization.Json; -using System.Text; -using System.Threading.Tasks; - -namespace CustomBuildTool -{ - public static class Json where T : class - { - public static string Serialize(T instance) - { - DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(T)); - - using (MemoryStream stream = new MemoryStream()) - { - serializer.WriteObject(stream, instance); - - return Encoding.Default.GetString(stream.ToArray()); - } - } - - public static T DeSerialize(string json) - { - using (MemoryStream stream = new MemoryStream(Encoding.Default.GetBytes(json))) - { - DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(T)); - - return (T)serializer.ReadObject(stream); - } - } - } -} diff --git a/tools/CustomBuildTool/Source Files/NativeMethods.cs b/tools/CustomBuildTool/Source Files/NativeMethods.cs index 6478cdda836d..30770f760157 100644 --- a/tools/CustomBuildTool/Source Files/NativeMethods.cs +++ b/tools/CustomBuildTool/Source Files/NativeMethods.cs @@ -1,112 +1,32 @@ -using System; +/* + * Process Hacker Toolchain - + * Build script + * + * Copyright (C) 2017 dmex + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +using System; using System.Diagnostics; using System.IO; using System.Runtime.InteropServices; namespace CustomBuildTool { - [System.Security.SuppressUnmanagedCodeSecurity] - public static class Win32 - { - public static string ShellExecute(string FileName, string args) - { - string output = string.Empty; - using (Process process = Process.Start(new ProcessStartInfo - { - UseShellExecute = false, - RedirectStandardOutput = true, - FileName = FileName, - CreateNoWindow = true - })) - { - process.StartInfo.Arguments = args; - process.Start(); - - output = process.StandardOutput.ReadToEnd(); - output = output.Replace("\n\n", "\r\n").Trim(); - - process.WaitForExit(); - } - - return output; - } - - public static void ImageResizeFile(int size, string FileName, string OutName) - { - using (var src = System.Drawing.Image.FromFile(FileName)) - using (var dst = new System.Drawing.Bitmap(size, size)) - using (var g = System.Drawing.Graphics.FromImage(dst)) - { - g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias; - g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic; - - g.DrawImage(src, 0, 0, dst.Width, dst.Height); - - dst.Save(OutName, System.Drawing.Imaging.ImageFormat.Png); - } - } - - public static void CopyIfNewer(string CurrentFile, string NewFile) - { - if (!File.Exists(CurrentFile)) - return; - - if (File.GetLastWriteTime(CurrentFile) > File.GetLastWriteTime(NewFile)) - { - File.Copy(CurrentFile, NewFile, true); - } - } - - public const int SW_HIDE = 0; - public const int SW_SHOW = 5; - public static readonly IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1); - public static readonly IntPtr STD_OUTPUT_HANDLE = new IntPtr(-11); - public static readonly IntPtr STD_INPUT_HANDLE = new IntPtr(-10); - public static readonly IntPtr STD_ERROR_HANDLE = new IntPtr(-12); - - [DllImport("kernel32.dll", ExactSpelling = true)] - public static extern IntPtr GetStdHandle(IntPtr StdHandle); - [DllImport("kernel32.dll", ExactSpelling = true)] - public static extern bool GetConsoleMode(IntPtr ConsoleHandle, out ConsoleMode Mode); - [DllImport("kernel32.dll", ExactSpelling = true)] - public static extern bool SetConsoleMode(IntPtr ConsoleHandle, ConsoleMode Mode); - [DllImport("kernel32.dll", ExactSpelling = true)] - public static extern IntPtr GetConsoleWindow(); - [DllImport("user32.dll", ExactSpelling = true)] - public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow); - } - - [Flags] - public enum ConsoleMode : uint - { - DEFAULT, - ENABLE_PROCESSED_INPUT = 0x0001, - ENABLE_LINE_INPUT = 0x0002, - ENABLE_ECHO_INPUT = 0x0004, - ENABLE_WINDOW_INPUT = 0x0008, - ENABLE_MOUSE_INPUT = 0x0010, - ENABLE_INSERT_MODE = 0x0020, - ENABLE_QUICK_EDIT_MODE = 0x0040, - ENABLE_EXTENDED_FLAGS = 0x0080, - ENABLE_AUTO_POSITION = 0x0100, - ENABLE_PROCESSED_OUTPUT = 0x0001, - ENABLE_WRAP_AT_EOL_OUTPUT = 0x0002, - ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0004, - DISABLE_NEWLINE_AUTO_RETURN = 0x0008, - ENABLE_LVB_GRID_WORLDWIDE = 0x0010, - } - - [Flags] - public enum InstanceState : uint - { - None = 0u, - Local = 1u, - Registered = 2u, - NoRebootRequired = 4u, - NoErrors = 8u, - Complete = 4294967295u - } - [ComImport, ClassInterface(ClassInterfaceType.AutoDispatch), Guid("177F0C4A-1CD3-4DE7-A32C-71DBBB9FA36D")] public class SetupConfigurationClass { diff --git a/tools/CustomBuildTool/Source Files/Nightly.cs b/tools/CustomBuildTool/Source Files/Nightly.cs deleted file mode 100644 index a9452fb42f97..000000000000 --- a/tools/CustomBuildTool/Source Files/Nightly.cs +++ /dev/null @@ -1,38 +0,0 @@ -using System.Runtime.Serialization; - -namespace CustomBuildTool -{ - [DataContract] - public class BuildUpdateRequest - { - [DataMember(Name = "updated")] - public string Updated { get; set; } - - [DataMember(Name = "version")] - public string Version { get; set; } - - [DataMember(Name = "size")] - public string FileLength { get; set; } - - [DataMember(Name = "forum_url")] - public string ForumUrl { get; set; } - - [DataMember(Name = "setup_url")] - public string Setupurl { get; set; } - - [DataMember(Name = "bin_url")] - public string Binurl { get; set; } - - [DataMember(Name = "hash_setup")] - public string HashSetup { get; set; } - - [DataMember(Name = "hash_bin")] - public string HashBin { get; set; } - - [DataMember(Name = "sig")] - public string sig { get; set; } - - [DataMember(Name = "message")] - public string Message { get; set; } - } -} diff --git a/tools/CustomBuildTool/Source Files/Program.cs b/tools/CustomBuildTool/Source Files/Program.cs index 09f0d6b1ff10..f123314e63a1 100644 --- a/tools/CustomBuildTool/Source Files/Program.cs +++ b/tools/CustomBuildTool/Source Files/Program.cs @@ -1,4 +1,26 @@ -using System; +/* + * Process Hacker Toolchain - + * Build script + * + * Copyright (C) 2017 dmex + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +using System; using System.Collections.Generic; using System.Security.Principal; diff --git a/tools/CustomBuildTool/Source Files/Utils.cs b/tools/CustomBuildTool/Source Files/Utils.cs new file mode 100644 index 000000000000..ab413c2166cf --- /dev/null +++ b/tools/CustomBuildTool/Source Files/Utils.cs @@ -0,0 +1,380 @@ +/* + * Process Hacker Toolchain - + * Build script + * + * Copyright (C) 2017 dmex + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +using System; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Runtime.InteropServices; +using System.Runtime.Serialization; +using System.Runtime.Serialization.Json; +using System.Security.Cryptography; +using System.Text; + +namespace CustomBuildTool +{ + [System.Security.SuppressUnmanagedCodeSecurity] + public static class Win32 + { + public static string ShellExecute(string FileName, string args) + { + string output = string.Empty; + using (Process process = Process.Start(new ProcessStartInfo + { + UseShellExecute = false, + RedirectStandardOutput = true, + FileName = FileName, + CreateNoWindow = true + })) + { + process.StartInfo.Arguments = args; + process.Start(); + + output = process.StandardOutput.ReadToEnd(); + output = output.Replace("\n\n", "\r\n").Trim(); + + process.WaitForExit(); + } + + return output; + } + + public static void ImageResizeFile(int size, string FileName, string OutName) + { + using (var src = System.Drawing.Image.FromFile(FileName)) + using (var dst = new System.Drawing.Bitmap(size, size)) + using (var g = System.Drawing.Graphics.FromImage(dst)) + { + g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias; + g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic; + + g.DrawImage(src, 0, 0, dst.Width, dst.Height); + + dst.Save(OutName, System.Drawing.Imaging.ImageFormat.Png); + } + } + + public static void CopyIfNewer(string CurrentFile, string NewFile) + { + if (!File.Exists(CurrentFile)) + return; + + if (File.GetLastWriteTime(CurrentFile) > File.GetLastWriteTime(NewFile)) + { + File.Copy(CurrentFile, NewFile, true); + } + } + + public const int SW_HIDE = 0; + public const int SW_SHOW = 5; + public static readonly IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1); + public static readonly IntPtr STD_OUTPUT_HANDLE = new IntPtr(-11); + public static readonly IntPtr STD_INPUT_HANDLE = new IntPtr(-10); + public static readonly IntPtr STD_ERROR_HANDLE = new IntPtr(-12); + + [DllImport("kernel32.dll", ExactSpelling = true)] + public static extern IntPtr GetStdHandle(IntPtr StdHandle); + [DllImport("kernel32.dll", ExactSpelling = true)] + public static extern bool GetConsoleMode(IntPtr ConsoleHandle, out ConsoleMode Mode); + [DllImport("kernel32.dll", ExactSpelling = true)] + public static extern bool SetConsoleMode(IntPtr ConsoleHandle, ConsoleMode Mode); + [DllImport("kernel32.dll", ExactSpelling = true)] + public static extern IntPtr GetConsoleWindow(); + [DllImport("user32.dll", ExactSpelling = true)] + public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow); + } + + public static class Json where T : class + { + public static string Serialize(T instance) + { + DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(T)); + + using (MemoryStream stream = new MemoryStream()) + { + serializer.WriteObject(stream, instance); + + return Encoding.Default.GetString(stream.ToArray()); + } + } + + public static T DeSerialize(string json) + { + using (MemoryStream stream = new MemoryStream(Encoding.Default.GetBytes(json))) + { + DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(T)); + + return (T)serializer.ReadObject(stream); + } + } + } + + public static class Verify + { + private static Rijndael GetRijndael(string secret) + { + Rfc2898DeriveBytes rfc2898DeriveBytes = new Rfc2898DeriveBytes(secret, Convert.FromBase64String("e0U0RTY2RjU5LUNBRjItNEMzOS1BN0Y4LTQ2MDk3QjFDNDYxQn0="), 10000); + Rijndael rijndael = Rijndael.Create(); + rijndael.Key = rfc2898DeriveBytes.GetBytes(32); + rijndael.IV = rfc2898DeriveBytes.GetBytes(16); + return rijndael; + } + + public static void Encrypt(string fileName, string outFileName, string secret) + { + using (Rijndael rijndael = GetRijndael(secret)) + using (FileStream fileStream = File.OpenRead(fileName)) + using (FileStream fileStream2 = File.Create(outFileName)) + using (CryptoStream cryptoStream = new CryptoStream(fileStream2, rijndael.CreateEncryptor(), CryptoStreamMode.Write)) + { + fileStream.CopyTo(cryptoStream); + } + } + + public static void Decrypt(string FileName, string outFileName, string secret) + { + using (Rijndael rijndael = GetRijndael(secret)) + using (FileStream fileStream = File.OpenRead(FileName)) + using (FileStream fileStream2 = File.Create(outFileName)) + using (CryptoStream cryptoStream = new CryptoStream(fileStream2, rijndael.CreateDecryptor(), CryptoStreamMode.Write)) + { + fileStream.CopyTo(cryptoStream); + } + } + + public static string HashFile(string FileName) + { + //using (HashAlgorithm algorithm = new SHA256CryptoServiceProvider()) + //{ + // byte[] inputBytes = Encoding.UTF8.GetBytes(input); + // byte[] hashBytes = algorithm.ComputeHash(inputBytes); + // return BitConverter.ToString(hashBytes).Replace("-", String.Empty); + //} + + using (FileStream stream = File.OpenRead(FileName)) + using (BufferedStream bufferedStream = new BufferedStream(stream, 0x1000)) + { + SHA256Managed sha = new SHA256Managed(); + byte[] checksum = sha.ComputeHash(bufferedStream); + + return BitConverter.ToString(checksum).Replace("-", string.Empty); + } + } + } + + public static class VisualStudio + { + public static string GetMsbuildFilePath() + { + string vswhere = Environment.ExpandEnvironmentVariables("%ProgramFiles(x86)%\\Microsoft Visual Studio\\Installer\\vswhere.exe"); + + // Note: vswere.exe was only released with build 15.0.26418.1 + if (File.Exists(vswhere)) + { + string vswhereResult = Win32.ShellExecute(vswhere, + "-latest " + + "-requires Microsoft.Component.MSBuild " + + "-property installationPath " + ); + + if (string.IsNullOrEmpty(vswhereResult)) + return null; + + if (File.Exists(vswhereResult + "\\MSBuild\\15.0\\Bin\\MSBuild.exe")) + return vswhereResult + "\\MSBuild\\15.0\\Bin\\MSBuild.exe"; + + return null; + } + else + { + try + { + VisualStudioInstance instance = FindVisualStudioInstance(); + + if (instance != null) + { + if (File.Exists(instance.Path + "\\MSBuild\\15.0\\Bin\\MSBuild.exe")) + return instance.Path + "\\MSBuild\\15.0\\Bin\\MSBuild.exe"; + } + } + catch (Exception ex) + { + Program.PrintColorMessage("[VisualStudioInstance] " + ex, ConsoleColor.Red, true); + } + + return null; + } + } + + private static VisualStudioInstance FindVisualStudioInstance() + { + var setupConfiguration = new SetupConfiguration() as ISetupConfiguration2; + var instanceEnumerator = setupConfiguration.EnumAllInstances(); + var instances = new ISetupInstance2[3]; + + instanceEnumerator.Next(instances.Length, instances, out var instancesFetched); + + if (instancesFetched == 0) + return null; + + do + { + for (int i = 0; i < instancesFetched; i++) + { + var instance = new VisualStudioInstance(instances[i]); + var state = instances[i].GetState(); + var packages = instances[i].GetPackages().Where(package => package.GetId().Contains("Microsoft.Component.MSBuild")); + + if ( + state.HasFlag(InstanceState.Local | InstanceState.Registered | InstanceState.Complete) && + packages.Count() > 0 && + instance.Version.StartsWith("15.0", StringComparison.OrdinalIgnoreCase) + ) + { + return instance; + } + } + + instanceEnumerator.Next(instances.Length, instances, out instancesFetched); + } + while (instancesFetched != 0); + + return null; + } + } + + public class VisualStudioInstance + { + public bool IsLaunchable { get; } + public bool IsComplete { get; } + public string Name { get; } + public string Path { get; } + public string Version { get; } + public string DisplayName { get; } + public string Description { get; } + public string ResolvePath { get; } + public string EnginePath { get; } + public string ProductPath { get; } + public string InstanceId { get; } + public DateTime InstallDate { get; } + + public VisualStudioInstance(ISetupInstance2 FromInstance) + { + this.IsLaunchable = FromInstance.IsLaunchable(); + this.IsComplete = FromInstance.IsComplete(); + this.Name = FromInstance.GetInstallationName(); + this.Path = FromInstance.GetInstallationPath(); + this.Version = FromInstance.GetInstallationVersion(); + this.DisplayName = FromInstance.GetDisplayName(); + this.Description = FromInstance.GetDescription(); + this.ResolvePath = FromInstance.ResolvePath(); + this.EnginePath = FromInstance.GetEnginePath(); + this.InstanceId = FromInstance.GetInstanceId(); + this.ProductPath = FromInstance.GetProductPath(); + + try + { + var time = FromInstance.GetInstallDate(); + ulong high = (ulong)time.dwHighDateTime; + uint low = (uint)time.dwLowDateTime; + long fileTime = (long)((high << 32) + low); + + this.InstallDate = DateTime.FromFileTimeUtc(fileTime); + } + catch + { + this.InstallDate = DateTime.UtcNow; + } + + // FromInstance.GetState(); + // FromInstance.GetPackages(); + // FromInstance.GetProduct(); + // FromInstance.GetProperties(); + // FromInstance.GetErrors(); + } + } + + [DataContract] + public class BuildUpdateRequest + { + [DataMember(Name = "updated")] + public string Updated { get; set; } + + [DataMember(Name = "version")] + public string Version { get; set; } + + [DataMember(Name = "size")] + public string FileLength { get; set; } + + [DataMember(Name = "forum_url")] + public string ForumUrl { get; set; } + + [DataMember(Name = "setup_url")] + public string Setupurl { get; set; } + + [DataMember(Name = "bin_url")] + public string Binurl { get; set; } + + [DataMember(Name = "hash_setup")] + public string HashSetup { get; set; } + + [DataMember(Name = "hash_bin")] + public string HashBin { get; set; } + + [DataMember(Name = "sig")] + public string sig { get; set; } + + [DataMember(Name = "message")] + public string Message { get; set; } + } + + [Flags] + public enum ConsoleMode : uint + { + DEFAULT, + ENABLE_PROCESSED_INPUT = 0x0001, + ENABLE_LINE_INPUT = 0x0002, + ENABLE_ECHO_INPUT = 0x0004, + ENABLE_WINDOW_INPUT = 0x0008, + ENABLE_MOUSE_INPUT = 0x0010, + ENABLE_INSERT_MODE = 0x0020, + ENABLE_QUICK_EDIT_MODE = 0x0040, + ENABLE_EXTENDED_FLAGS = 0x0080, + ENABLE_AUTO_POSITION = 0x0100, + ENABLE_PROCESSED_OUTPUT = 0x0001, + ENABLE_WRAP_AT_EOL_OUTPUT = 0x0002, + ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0004, + DISABLE_NEWLINE_AUTO_RETURN = 0x0008, + ENABLE_LVB_GRID_WORLDWIDE = 0x0010, + } + + [Flags] + public enum InstanceState : uint + { + None = 0u, + Local = 1u, + Registered = 2u, + NoRebootRequired = 4u, + NoErrors = 8u, + Complete = 4294967295u + } +} diff --git a/tools/CustomBuildTool/Source Files/Verify.cs b/tools/CustomBuildTool/Source Files/Verify.cs deleted file mode 100644 index f652094cb16f..000000000000 --- a/tools/CustomBuildTool/Source Files/Verify.cs +++ /dev/null @@ -1,59 +0,0 @@ -using System; -using System.IO; -using System.Security.Cryptography; - -namespace CustomBuildTool -{ - public static class Verify - { - private static Rijndael GetRijndael(string secret) - { - Rfc2898DeriveBytes rfc2898DeriveBytes = new Rfc2898DeriveBytes(secret, Convert.FromBase64String("e0U0RTY2RjU5LUNBRjItNEMzOS1BN0Y4LTQ2MDk3QjFDNDYxQn0="), 10000); - Rijndael rijndael = Rijndael.Create(); - rijndael.Key = rfc2898DeriveBytes.GetBytes(32); - rijndael.IV = rfc2898DeriveBytes.GetBytes(16); - return rijndael; - } - - public static void Encrypt(string fileName, string outFileName, string secret) - { - using (Rijndael rijndael = GetRijndael(secret)) - using (FileStream fileStream = File.OpenRead(fileName)) - using (FileStream fileStream2 = File.Create(outFileName)) - using (CryptoStream cryptoStream = new CryptoStream(fileStream2, rijndael.CreateEncryptor(), CryptoStreamMode.Write)) - { - fileStream.CopyTo(cryptoStream); - } - } - - public static void Decrypt(string FileName, string outFileName, string secret) - { - using (Rijndael rijndael = GetRijndael(secret)) - using (FileStream fileStream = File.OpenRead(FileName)) - using (FileStream fileStream2 = File.Create(outFileName)) - using (CryptoStream cryptoStream = new CryptoStream(fileStream2, rijndael.CreateDecryptor(), CryptoStreamMode.Write)) - { - fileStream.CopyTo(cryptoStream); - } - } - - public static string HashFile(string FileName) - { - //using (HashAlgorithm algorithm = new SHA256CryptoServiceProvider()) - //{ - // byte[] inputBytes = Encoding.UTF8.GetBytes(input); - // byte[] hashBytes = algorithm.ComputeHash(inputBytes); - // return BitConverter.ToString(hashBytes).Replace("-", String.Empty); - //} - - using (FileStream stream = File.OpenRead(FileName)) - using (BufferedStream bufferedStream = new BufferedStream(stream, 0x1000)) - { - SHA256Managed sha = new SHA256Managed(); - byte[] checksum = sha.ComputeHash(bufferedStream); - - return BitConverter.ToString(checksum).Replace("-", string.Empty); - } - } - } -} diff --git a/tools/CustomBuildTool/Source Files/VisualStudio.cs b/tools/CustomBuildTool/Source Files/VisualStudio.cs deleted file mode 100644 index adef9214779a..000000000000 --- a/tools/CustomBuildTool/Source Files/VisualStudio.cs +++ /dev/null @@ -1,133 +0,0 @@ -using System; -using System.IO; -using System.Linq; - -namespace CustomBuildTool -{ - [System.Security.SuppressUnmanagedCodeSecurity] - public static class VisualStudio - { - public static string GetMsbuildFilePath() - { - string vswhere = Environment.ExpandEnvironmentVariables("%ProgramFiles(x86)%\\Microsoft Visual Studio\\Installer\\vswhere.exe"); - - // Note: vswere.exe was only released with build 15.0.26418.1 - if (File.Exists(vswhere)) - { - string vswhereResult = Win32.ShellExecute(vswhere, - "-latest " + - "-requires Microsoft.Component.MSBuild " + - "-property installationPath " - ); - - if (string.IsNullOrEmpty(vswhereResult)) - return null; - - if (File.Exists(vswhereResult + "\\MSBuild\\15.0\\Bin\\MSBuild.exe")) - return vswhereResult + "\\MSBuild\\15.0\\Bin\\MSBuild.exe"; - - return null; - } - else - { - VisualStudioInstance instance = FindVisualStudioInstance(); - - if (instance != null) - { - if (File.Exists(instance.Path + "\\MSBuild\\15.0\\Bin\\MSBuild.exe")) - return instance.Path + "\\MSBuild\\15.0\\Bin\\MSBuild.exe"; - } - - return null; - } - } - - private static VisualStudioInstance FindVisualStudioInstance() - { - var setupConfiguration = new SetupConfiguration() as ISetupConfiguration2; - var instanceEnumerator = setupConfiguration.EnumAllInstances(); - var instances = new ISetupInstance2[3]; - - instanceEnumerator.Next(instances.Length, instances, out var instancesFetched); - - if (instancesFetched == 0) - return null; - - do - { - for (int i = 0; i < instancesFetched; i++) - { - var instance = new VisualStudioInstance(instances[i]); - var state = instances[i].GetState(); - var packages = instances[i].GetPackages().Where(package => package.GetId().Contains("Microsoft.Component.MSBuild")); - - if ( - state.HasFlag(InstanceState.Local | InstanceState.Registered | InstanceState.Complete) && - packages.Count() > 0 && - instance.Version.StartsWith("15.0", StringComparison.OrdinalIgnoreCase) - ) - { - return instance; - } - } - - instanceEnumerator.Next(instances.Length, instances, out instancesFetched); - } - while (instancesFetched != 0); - - return null; - } - } - - - public class VisualStudioInstance - { - public bool IsLaunchable { get; } - public bool IsComplete { get; } - public string Name { get; } - public string Path { get; } - public string Version { get; } - public string DisplayName { get; } - public string Description { get; } - public string ResolvePath { get; } - public string EnginePath { get; } - public string ProductPath { get; } - public string InstanceId { get; } - public DateTime InstallDate { get; } - - public VisualStudioInstance(ISetupInstance2 FromInstance) - { - this.IsLaunchable = FromInstance.IsLaunchable(); - this.IsComplete = FromInstance.IsComplete(); - this.Name = FromInstance.GetInstallationName(); - this.Path = FromInstance.GetInstallationPath(); - this.Version = FromInstance.GetInstallationVersion(); - this.DisplayName = FromInstance.GetDisplayName(); - this.Description = FromInstance.GetDescription(); - this.ResolvePath = FromInstance.ResolvePath(); - this.EnginePath = FromInstance.GetEnginePath(); - this.InstanceId = FromInstance.GetInstanceId(); - this.ProductPath = FromInstance.GetProductPath(); - - try - { - var time = FromInstance.GetInstallDate(); - ulong high = (ulong)time.dwHighDateTime; - uint low = (uint)time.dwLowDateTime; - long fileTime = (long)((high << 32) + low); - - this.InstallDate = DateTime.FromFileTimeUtc(fileTime); - } - catch - { - this.InstallDate = DateTime.UtcNow; - } - - // FromInstance.GetState(); - // FromInstance.GetPackages(); - // FromInstance.GetProduct(); - // FromInstance.GetProperties(); - // FromInstance.GetErrors(); - } - } -} diff --git a/tools/CustomBuildTool/Source Files/Zip.cs b/tools/CustomBuildTool/Source Files/Zip.cs index cddb9f950b88..826659de53f8 100644 --- a/tools/CustomBuildTool/Source Files/Zip.cs +++ b/tools/CustomBuildTool/Source Files/Zip.cs @@ -1,7 +1,28 @@ -using System; +/* + * Process Hacker Toolchain - + * Build script + * + * Copyright (C) 2017 dmex + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +using System; using System.IO; using System.IO.Compression; -using System.Text; namespace CustomBuildTool { diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe b/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe index 06ce779430fce6fa5fada71005b8058b72fc6bd0..9177a7a24ba8204a88c65a85ee637ab037780de5 100644 GIT binary patch delta 14947 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 delta 14585 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 XYR^a8Js(NmuEGDpw%u1RpOO9_;|W{U diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb b/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb index e566f8f63d56e5b85f14f00d06efa403dae6cfe3..60f23aad14bf323c3aad4586f2eba905471898ba 100644 GIT binary patch literal 69120 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 literal 73216 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 M4II|M|EC)Ge^3x)Hvj+t From 5eb02dad517e4d515e58f9c9d2f310761f769291 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 19 May 2017 00:30:16 +1000 Subject: [PATCH 0129/2058] Updater: Add Changelog window --- plugins/Updater/Updater.rc | 22 ++++++++++++++++ plugins/Updater/options.c | 53 ++++++++++++++++++++++++++++++++++++++ plugins/Updater/page3.c | 3 +-- plugins/Updater/page4.c | 3 +-- plugins/Updater/page5.c | 4 +-- plugins/Updater/resource.h | 13 ++++++---- plugins/Updater/updater.c | 42 +++++++++++++++--------------- plugins/Updater/updater.h | 10 +++++++ 8 files changed, 117 insertions(+), 33 deletions(-) diff --git a/plugins/Updater/Updater.rc b/plugins/Updater/Updater.rc index 3819a0a7ca80..42c50c87d468 100644 --- a/plugins/Updater/Updater.rc +++ b/plugins/Updater/Updater.rc @@ -99,6 +99,15 @@ BEGIN DEFPUSHBUTTON "Close",IDCANCEL,158,33,50,14 END +IDD_TEXT DIALOGEX 0, 0, 309, 176 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME +CAPTION "Changelog" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + EDITTEXT IDC_TEXT,1,1,307,154,ES_MULTILINE | WS_VSCROLL + DEFPUSHBUTTON "OK",IDCANCEL,258,159,50,14 +END + ///////////////////////////////////////////////////////////////////////////// // @@ -115,6 +124,14 @@ BEGIN TOPMARGIN, 7 BOTTOMMARGIN, 47 END + + IDD_TEXT, DIALOG + BEGIN + LEFTMARGIN, 1 + RIGHTMARGIN, 308 + TOPMARGIN, 1 + BOTTOMMARGIN, 173 + END END #endif // APSTUDIO_INVOKED @@ -129,6 +146,11 @@ BEGIN 0 END +IDD_TEXT AFX_DIALOG_LAYOUT +BEGIN + 0 +END + #endif // English (Australia) resources ///////////////////////////////////////////////////////////////////////////// diff --git a/plugins/Updater/options.c b/plugins/Updater/options.c index cbef57deb360..77c0c978bda6 100644 --- a/plugins/Updater/options.c +++ b/plugins/Updater/options.c @@ -69,4 +69,57 @@ VOID ShowOptionsDialog( Parent, OptionsDlgProc ); +} + +INT_PTR CALLBACK TextDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + static PH_LAYOUT_MANAGER LayoutManager; + + switch (uMsg) + { + case WM_INITDIALOG: + { + PPH_UPDATER_CONTEXT context = (PPH_UPDATER_CONTEXT)lParam; + + PhCenterWindow(hwndDlg, GetParent(hwndDlg)); + + SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)UT_LOAD_SHARED_ICON_SMALL(MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); + SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)UT_LOAD_SHARED_ICON_LARGE(MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER))); + + PhInitializeLayoutManager(&LayoutManager, hwndDlg); + PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDC_TEXT), NULL, PH_ANCHOR_ALL); + + SetWindowText(GetDlgItem(hwndDlg, IDC_TEXT), PhGetString(context->BuildMessage)); + + SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hwndDlg, IDCANCEL), TRUE); + } + break; + case WM_DESTROY: + { + PhDeleteLayoutManager(&LayoutManager); + } + break; + case WM_SIZE: + { + PhLayoutManagerLayout(&LayoutManager); + } + break; + case WM_COMMAND: + { + switch (GET_WM_COMMAND_ID(wParam, lParam)) + { + case IDCANCEL: + EndDialog(hwndDlg, IDCANCEL); + break; + } + } + break; + } + + return FALSE; } \ No newline at end of file diff --git a/plugins/Updater/page3.c b/plugins/Updater/page3.c index 740dae4589f1..c5fe5c051573 100644 --- a/plugins/Updater/page3.c +++ b/plugins/Updater/page3.c @@ -77,7 +77,7 @@ VOID ShowAvailableDialog( memset(&config, 0, sizeof(TASKDIALOGCONFIG)); config.cbSize = sizeof(TASKDIALOGCONFIG); - config.dwFlags = TDF_USE_HICON_MAIN | TDF_ALLOW_DIALOG_CANCELLATION | TDF_CAN_BE_MINIMIZED | TDF_ENABLE_HYPERLINKS | TDF_EXPAND_FOOTER_AREA; + config.dwFlags = TDF_USE_HICON_MAIN | TDF_ALLOW_DIALOG_CANCELLATION | TDF_CAN_BE_MINIMIZED | TDF_ENABLE_HYPERLINKS; config.dwCommonButtons = TDCBF_CANCEL_BUTTON; config.hMainIcon = Context->IconLargeHandle; config.cxWidth = 200; @@ -94,7 +94,6 @@ VOID ShowAvailableDialog( Context->RevisionVersion, PhGetStringOrEmpty(Context->Size) )->Buffer; - config.pszExpandedInformation = PhGetString(Context->BuildMessage); SendMessage(Context->DialogHandle, TDM_NAVIGATE_PAGE, 0, (LPARAM)&config); } \ No newline at end of file diff --git a/plugins/Updater/page4.c b/plugins/Updater/page4.c index 237e49e5de0b..a8df5182aaa4 100644 --- a/plugins/Updater/page4.c +++ b/plugins/Updater/page4.c @@ -62,7 +62,7 @@ VOID ShowProgressDialog( memset(&config, 0, sizeof(TASKDIALOGCONFIG)); config.cbSize = sizeof(TASKDIALOGCONFIG); - config.dwFlags = TDF_USE_HICON_MAIN | TDF_ALLOW_DIALOG_CANCELLATION | TDF_CAN_BE_MINIMIZED | TDF_ENABLE_HYPERLINKS | TDF_SHOW_PROGRESS_BAR | TDF_EXPAND_FOOTER_AREA; + config.dwFlags = TDF_USE_HICON_MAIN | TDF_ALLOW_DIALOG_CANCELLATION | TDF_CAN_BE_MINIMIZED | TDF_ENABLE_HYPERLINKS | TDF_SHOW_PROGRESS_BAR; config.dwCommonButtons = TDCBF_CANCEL_BUTTON; config.hMainIcon = Context->IconLargeHandle; config.cxWidth = 200; @@ -76,7 +76,6 @@ VOID ShowProgressDialog( Context->RevisionVersion )->Buffer; config.pszContent = L"Downloaded: ~ of ~ (0%)\r\nSpeed: ~ KB/s"; - config.pszExpandedInformation = PhGetString(Context->BuildMessage); SendMessage(Context->DialogHandle, TDM_NAVIGATE_PAGE, 0, (LPARAM)&config); } \ No newline at end of file diff --git a/plugins/Updater/page5.c b/plugins/Updater/page5.c index 36b9860d61b0..0b766debcfeb 100644 --- a/plugins/Updater/page5.c +++ b/plugins/Updater/page5.c @@ -118,7 +118,7 @@ VOID ShowUpdateInstallDialog( config.cButtons = ARRAYSIZE(TaskDialogButtonArray); config.pszWindowTitle = L"Process Hacker - Updater"; - config.pszMainInstruction = L"Ready to install update"; + config.pszMainInstruction = L"Ready to install update?"; config.pszContent = L"The update has been successfully downloaded and verified.\r\n\r\nClick Install to continue."; SendMessage(Context->DialogHandle, TDM_NAVIGATE_PAGE, 0, (LPARAM)&config); @@ -158,7 +158,6 @@ VOID ShowLatestVersionDialog( Context->CurrentRevisionVersion, PhaFormatDateTime(&systemTime)->Buffer )->Buffer; - config.pszExpandedInformation = PhGetString(Context->BuildMessage); SendMessage(Context->DialogHandle, TDM_NAVIGATE_PAGE, 0, (LPARAM)&config); } @@ -186,7 +185,6 @@ VOID ShowNewerVersionDialog( Context->CurrentMinorVersion, Context->CurrentRevisionVersion )->Buffer; - config.pszExpandedInformation = PhGetString(Context->BuildMessage); SendMessage(Context->DialogHandle, TDM_NAVIGATE_PAGE, 0, (LPARAM)&config); } diff --git a/plugins/Updater/resource.h b/plugins/Updater/resource.h index 11f1b12fef3e..67f9ce64bd40 100644 --- a/plugins/Updater/resource.h +++ b/plugins/Updater/resource.h @@ -2,16 +2,19 @@ // Microsoft Visual C++ generated include file. // Used by Updater.rc // -#define IDD_OPTIONS 103 -#define IDC_AUTOCHECKBOX 1002 +#define IDD_OPTIONS 101 +#define IDD_TEXT 102 +#define IDC_AUTOCHECKBOX 1001 +#define IDC_TEXT 1002 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 107 +#define _APS_NEXT_RESOURCE_VALUE 103 + #define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1010 -#define _APS_NEXT_SYMED_VALUE 103 +#define _APS_NEXT_CONTROL_VALUE 1003 +#define _APS_NEXT_SYMED_VALUE 104 #endif #endif diff --git a/plugins/Updater/updater.c b/plugins/Updater/updater.c index 55c88a814a7f..8e71e80d5df9 100644 --- a/plugins/Updater/updater.c +++ b/plugins/Updater/updater.c @@ -63,12 +63,6 @@ VOID FreeUpdateContext( PhClearReference(&Context->SetupFileDownloadUrl); PhClearReference(&Context->BuildMessage); - if (Context->IconLargeHandle) - DestroyIcon(Context->IconLargeHandle); - - if (Context->IconSmallHandle) - DestroyIcon(Context->IconSmallHandle); - PhDereferenceObject(Context); } @@ -76,20 +70,8 @@ VOID TaskDialogCreateIcons( _In_ PPH_UPDATER_CONTEXT Context ) { - Context->IconLargeHandle = PhLoadIcon( - NtCurrentPeb()->ImageBaseAddress, - MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER), - PH_LOAD_ICON_SIZE_LARGE, - GetSystemMetrics(SM_CXICON), - GetSystemMetrics(SM_CYICON) - ); - Context->IconSmallHandle = PhLoadIcon( - NtCurrentPeb()->ImageBaseAddress, - MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER), - PH_LOAD_ICON_SIZE_LARGE, - GetSystemMetrics(SM_CXICON), - GetSystemMetrics(SM_CYICON) - ); + Context->IconSmallHandle = UT_LOAD_SHARED_ICON_SMALL(MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER)); + Context->IconLargeHandle = UT_LOAD_SHARED_ICON_LARGE(MAKEINTRESOURCE(PHAPP_IDI_PROCESSHACKER)); SendMessage(Context->DialogHandle, WM_SETICON, ICON_SMALL, (LPARAM)Context->IconSmallHandle); SendMessage(Context->DialogHandle, WM_SETICON, ICON_BIG, (LPARAM)Context->IconLargeHandle); @@ -101,7 +83,13 @@ VOID TaskDialogLinkClicked( { if (!PhIsNullOrEmptyString(Context->ReleaseNotesUrl)) { - PhShellExecute(Context->DialogHandle, PhGetStringOrEmpty(Context->ReleaseNotesUrl), NULL); + DialogBoxParam( + PluginInstance->DllBase, + MAKEINTRESOURCE(IDD_TEXT), + Context->DialogHandle, + TextDlgProc, + (LPARAM)Context + ); } } @@ -441,6 +429,18 @@ BOOLEAN QueryUpdateData( Context->SetupFileDownloadUrl = PhConvertUtf8ToUtf16(GetJsonValueAsString(jsonObject, "setup_url")); Context->BuildMessage = PhConvertUtf8ToUtf16(GetJsonValueAsString(jsonObject, "message")); + PH_STRING_BUILDER sb; + PhInitializeStringBuilder(&sb, 0x100); + + for (size_t i = 0; i < Context->BuildMessage->Length; i++) + { + if (Context->BuildMessage->Data[i] == '\n') + PhAppendFormatStringBuilder(&sb, L"\r\n"); + else + PhAppendCharStringBuilder(&sb, Context->BuildMessage->Data[i]); + } + PhMoveReference(&Context->BuildMessage, PhFinalStringBuilderString(&sb)); + CleanupJsonParser(jsonObject); if (PhIsNullOrEmptyString(Context->Signature)) diff --git a/plugins/Updater/updater.h b/plugins/Updater/updater.h index a6835fa9268b..ab8b850a635c 100644 --- a/plugins/Updater/updater.h +++ b/plugins/Updater/updater.h @@ -55,6 +55,9 @@ ((ULONGLONG)(build) << 16) | \ ((ULONGLONG)(revision) << 0)) +#define UT_LOAD_SHARED_ICON_SMALL(Name) PhLoadIcon(PhLibImageBase, (Name), PH_LOAD_ICON_SHARED | PH_LOAD_ICON_SIZE_SMALL, 0, 0) +#define UT_LOAD_SHARED_ICON_LARGE(Name) PhLoadIcon(PhLibImageBase, (Name), PH_LOAD_ICON_SHARED | PH_LOAD_ICON_SIZE_LARGE, 0, 0) + #ifdef _DEBUG // Force update checks to succeed (most of the below flags require this to be defined). //#define FORCE_UPDATE_CHECK @@ -178,6 +181,13 @@ VOID ShowOptionsDialog( _In_opt_ HWND Parent ); +INT_PTR CALLBACK TextDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + // verify.c typedef struct _UPDATER_HASH_CONTEXT From d0d9c7d7c3d20d979463dc4ebce5d5344399bfd9 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 19 May 2017 01:45:55 +1000 Subject: [PATCH 0130/2058] Updater: Add nightly build location --- plugins/Updater/updater.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/Updater/updater.c b/plugins/Updater/updater.c index 8e71e80d5df9..6ade85239887 100644 --- a/plugins/Updater/updater.c +++ b/plugins/Updater/updater.c @@ -352,7 +352,7 @@ BOOLEAN QueryUpdateData( if (!(httpRequestHandle = WinHttpOpenRequest( httpConnectionHandle, NULL, - L"/processhacker/plugins/nightly.php", + L"/processhacker/nightly.php?phupdater", NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, From be4ec6c094bed48834cd93b371d421749a042f95 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 19 May 2017 01:51:16 +1000 Subject: [PATCH 0131/2058] Updater: Fix typo --- plugins/Updater/updater.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/plugins/Updater/updater.c b/plugins/Updater/updater.c index 6ade85239887..6cc3cdc1facd 100644 --- a/plugins/Updater/updater.c +++ b/plugins/Updater/updater.c @@ -309,6 +309,7 @@ BOOLEAN QueryUpdateData( HINTERNET httpRequestHandle = NULL; ULONG stringBufferLength = 0; PSTR stringBuffer = NULL; + PH_STRING_BUILDER sb; PVOID jsonObject = NULL; mxml_node_t* xmlNode = NULL; PPH_STRING versionHeader = UpdateVersionString(); @@ -429,13 +430,11 @@ BOOLEAN QueryUpdateData( Context->SetupFileDownloadUrl = PhConvertUtf8ToUtf16(GetJsonValueAsString(jsonObject, "setup_url")); Context->BuildMessage = PhConvertUtf8ToUtf16(GetJsonValueAsString(jsonObject, "message")); - PH_STRING_BUILDER sb; PhInitializeStringBuilder(&sb, 0x100); - - for (size_t i = 0; i < Context->BuildMessage->Length; i++) + for (SIZE_T i = 0; i < Context->BuildMessage->Length; i++) { if (Context->BuildMessage->Data[i] == '\n') - PhAppendFormatStringBuilder(&sb, L"\r\n"); + PhAppendStringBuilder2(&sb, L"\r\n"); else PhAppendCharStringBuilder(&sb, Context->BuildMessage->Data[i]); } From 7cbed97282fbb0c635da7fe614dca545bf00dff7 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 19 May 2017 18:27:30 +1000 Subject: [PATCH 0132/2058] Update solutions, Fix peview clr layout --- ProcessHacker/ProcessHacker.vcxproj | 21 +++++++++++++++++---- tools/peview/peview.rc | 3 +-- tools/peview/peview.vcxproj | 21 +++++++++++++++++---- 3 files changed, 35 insertions(+), 10 deletions(-) diff --git a/ProcessHacker/ProcessHacker.vcxproj b/ProcessHacker/ProcessHacker.vcxproj index 1c52fe1b7730..60b6c8f4be98 100644 --- a/ProcessHacker/ProcessHacker.vcxproj +++ b/ProcessHacker/ProcessHacker.vcxproj @@ -104,6 +104,10 @@ ProcessHacker.def aclui.dll;iphlpapi.dll;ws2_32.dll;%(DelayLoadDLLs) + + _UNICODE;UNICODE;%(PreprocessorDefinitions);$(ExternalCompilerOptions) + ..\phnt\include;..\phlib\include;include;%(AdditionalIncludeDirectories) + @@ -128,6 +132,10 @@ ProcessHacker.def aclui.dll;iphlpapi.dll;ws2_32.dll;%(DelayLoadDLLs) + + _UNICODE;UNICODE;%(PreprocessorDefinitions);$(ExternalCompilerOptions) + ..\phnt\include;..\phlib\include;include;%(AdditionalIncludeDirectories) + @@ -159,6 +167,10 @@ ProcessHacker.def aclui.dll;iphlpapi.dll;ws2_32.dll;%(DelayLoadDLLs) + + _UNICODE;UNICODE;%(PreprocessorDefinitions);$(ExternalCompilerOptions) + ..\phnt\include;..\phlib\include;include;%(AdditionalIncludeDirectories) + @@ -189,6 +201,10 @@ ProcessHacker.def aclui.dll;iphlpapi.dll;ws2_32.dll;%(DelayLoadDLLs) + + _UNICODE;UNICODE;%(PreprocessorDefinitions);$(ExternalCompilerOptions) + ..\phnt\include;..\phlib\include;include;%(AdditionalIncludeDirectories) + @@ -377,10 +393,7 @@ - - _UNICODE;UNICODE;%(PreprocessorDefinitions);$(ExternalCompilerOptions) - ..\phnt\include;..\phlib\include;include;%(AdditionalIncludeDirectories) - + diff --git a/tools/peview/peview.rc b/tools/peview/peview.rc index 55f303c4af91..c9dd19af9d33 100644 --- a/tools/peview/peview.rc +++ b/tools/peview/peview.rc @@ -192,9 +192,8 @@ BEGIN EDITTEXT IDC_FLAGS,76,19,217,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER LTEXT "Version String:",IDC_STATIC,7,31,48,8 LTEXT "Static",IDC_VERSIONSTRING,78,31,215,8 - CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,57,286,85 + CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,57,286,216 LTEXT "Sections:",IDC_STATIC,7,47,30,8 - CONTROL "",IDC_SECTION,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,145,286,128 END IDD_PELOADCONFIG DIALOGEX 0, 0, 300, 280 diff --git a/tools/peview/peview.vcxproj b/tools/peview/peview.vcxproj index 616289ae31be..a5a6ae577e12 100644 --- a/tools/peview/peview.vcxproj +++ b/tools/peview/peview.vcxproj @@ -105,6 +105,10 @@ MachineX86 6.01 + + ..\..\phnt\include;..\..\phlib\include;include;%(AdditionalIncludeDirectories) + _UNICODE;UNICODE;%(PreprocessorDefinitions);$(ExternalCompilerOptions) + @@ -130,6 +134,10 @@ MachineX64 6.01 + + ..\..\phnt\include;..\..\phlib\include;include;%(AdditionalIncludeDirectories) + _UNICODE;UNICODE;%(PreprocessorDefinitions);$(ExternalCompilerOptions) + @@ -161,6 +169,10 @@ true 6.01 + + ..\..\phnt\include;..\..\phlib\include;include;%(AdditionalIncludeDirectories) + _UNICODE;UNICODE;%(PreprocessorDefinitions);$(ExternalCompilerOptions) + @@ -191,6 +203,10 @@ true 6.01 + + ..\..\phnt\include;..\..\phlib\include;include;%(AdditionalIncludeDirectories) + _UNICODE;UNICODE;%(PreprocessorDefinitions);$(ExternalCompilerOptions) + @@ -217,10 +233,7 @@ - - _UNICODE;UNICODE;%(PreprocessorDefinitions);$(ExternalCompilerOptions) - ..\..\phnt\include;..\..\phlib\include;include;%(AdditionalIncludeDirectories) - + From 5866671772ce702f459fdde3fac5e51b88b5c77d Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 19 May 2017 19:56:54 +1000 Subject: [PATCH 0133/2058] Peview: Fix type filter, Fix crash. Update build tools. --- tools/CustomBuildTool/Source Files/Build.cs | 49 ++-- tools/CustomBuildTool/Source Files/Utils.cs | 5 +- .../bin/Release/CustomBuildTool.exe | Bin 160768 -> 160768 bytes .../bin/Release/CustomBuildTool.pdb | Bin 69120 -> 69120 bytes tools/peview/pdb.c | 276 ++++++------------ 5 files changed, 118 insertions(+), 212 deletions(-) diff --git a/tools/CustomBuildTool/Source Files/Build.cs b/tools/CustomBuildTool/Source Files/Build.cs index 136c97c1f0a6..6242b16b4135 100644 --- a/tools/CustomBuildTool/Source Files/Build.cs +++ b/tools/CustomBuildTool/Source Files/Build.cs @@ -35,7 +35,7 @@ public static class Build private static DateTime TimeStart; private static bool BuildNightly; private static string BuildBranch; - private static string BuildOutputFolder = "build"; + private static string BuildOutputFolder; private static string BuildCommit; private static string BuildVersion; private static string BuildLongVersion; @@ -145,6 +145,7 @@ public static class Build public static bool InitializeBuildEnvironment(bool CheckDependencies) { TimeStart = DateTime.Now; + BuildOutputFolder = "build\\output"; MSBuildExePath = VisualStudio.GetMsbuildFilePath(); CustomSignToolPath = "tools\\CustomSignTool\\bin\\Release32\\CustomSignTool.exe"; GitExePath = Environment.ExpandEnvironmentVariables("%ProgramFiles%\\Git\\cmd\\git.exe"); @@ -182,7 +183,7 @@ public static bool InitializeBuildEnvironment(bool CheckDependencies) if (!File.Exists(MSBuildExePath)) { - Program.PrintColorMessage("MsBuild not installed.\r\nExiting...\r\n", ConsoleColor.Red); + Program.PrintColorMessage("MsBuild not installed. Exiting.", ConsoleColor.Red); return false; } @@ -215,47 +216,29 @@ public static void CleanupBuildEnvironment() { string[] cleanupFileArray = { - BuildOutputFolder + "\\processhacker-build-setup.exe", - BuildOutputFolder + "\\processhacker-build-bin.zip", - BuildOutputFolder + "\\processhacker-build-src.zip", - BuildOutputFolder + "\\processhacker-build-sdk.zip", - BuildOutputFolder + "\\processhacker-build-pdb.zip", - BuildOutputFolder + "\\processhacker-build-checksums.txt", - BuildOutputFolder + "\\processhacker-build-package.appxbundle", - BuildOutputFolder + "\\processhacker-" + BuildVersion + "-setup.exe", - BuildOutputFolder + "\\processhacker-" + BuildVersion + "-bin.zip", - BuildOutputFolder + "\\processhacker-" + BuildVersion + "-src.zip", - BuildOutputFolder + "\\processhacker-" + BuildVersion + "-sdk.zip", - BuildOutputFolder + "\\processhacker-" + BuildVersion + "-pdb.zip", - BuildOutputFolder + "\\processhacker-" + BuildVersion + "-checksums.txt" + BuildOutputFolder, + "bin", + "sdk", }; try { - if (Directory.Exists("build\\output")) - Directory.Delete("build\\output", true); - for (int i = 0; i < cleanupFileArray.Length; i++) { - if (File.Exists(cleanupFileArray[i])) - File.Delete(cleanupFileArray[i]); + if (Directory.Exists(cleanupFileArray[i])) + Directory.Delete(cleanupFileArray[i], true); } } catch (Exception ex) { - Program.PrintColorMessage("[CleanupBuildEnvironment] " + ex, ConsoleColor.Red); + Program.PrintColorMessage("[Cleanup] " + ex, ConsoleColor.Red); } } - public static string GetBuildLogString() - { - return Win32.ShellExecute(GitExePath, "log -n 1800 --graph --pretty=format:\"%C(yellow)%h%Creset %C(bold blue)%an%Creset %s %C(dim green)(%cr)\" --abbrev-commit ").Trim(); - } - public static void ShowBuildEnvironment(string Platform, bool ShowBuildInfo, bool ShowLogInfo) { BuildBranch = Win32.ShellExecute(GitExePath, "rev-parse --abbrev-ref HEAD").Trim(); - BuildCommit = Win32.ShellExecute(GitExePath, "rev-parse --short HEAD").Trim(); // rev-parse HEAD + BuildCommit = Win32.ShellExecute(GitExePath, "rev-parse --short HEAD").Trim(); Program.PrintColorMessage("Branch: ", ConsoleColor.Cyan, false); Program.PrintColorMessage(BuildBranch, ConsoleColor.White); Program.PrintColorMessage("Commit: ", ConsoleColor.Cyan, false); @@ -486,6 +469,7 @@ public static bool CopyVersionHeader() Win32.CopyIfNewer("ProcessHacker\\sdk\\phapppub.h", "sdk\\include\\phapppub.h"); Win32.CopyIfNewer("ProcessHacker\\sdk\\phdk.h", "sdk\\include\\phdk.h"); Win32.CopyIfNewer("ProcessHacker\\resource.h", "sdk\\include\\phappresource.h"); + } catch (Exception ex) { @@ -894,6 +878,11 @@ public static bool BuildUpdateSignature() return true; } + public static string GetBuildLogString() + { + return Win32.ShellExecute(GitExePath, "log -n 1800 --graph --pretty=format:\"%C(yellow)%h%Creset %C(bold blue)%an%Creset %s %C(dim green)(%cr)\" --abbrev-commit ").Trim(); + } + public static void WebServiceUpdateConfig() { if (string.IsNullOrEmpty(BuildSetupHash)) @@ -903,7 +892,8 @@ public static void WebServiceUpdateConfig() if (string.IsNullOrEmpty(BuildSetupSig)) return; - string appveyorMessage = Win32.ShellExecute(GitExePath, "log -n 5 --date=format:%Y-%m-%d --pretty=format:\"[%cd] %an %s\" --abbrev-commit"); + string buildChangelog = Win32.ShellExecute(GitExePath, "log -n 30 --pretty=format:\"%h %an %s (%cr)\""); + string buildSummary = Win32.ShellExecute(GitExePath, "log -n 5 --date=format:%Y-%m-%d --pretty=format:\"[%cd] %an %s\" --abbrev-commit"); string buildPostString = Json.Serialize(new BuildUpdateRequest { Updated = TimeStart.ToString("o"), @@ -915,7 +905,8 @@ public static void WebServiceUpdateConfig() HashSetup = BuildSetupHash, HashBin = BuildBinHash, sig = BuildSetupSig, - Message = appveyorMessage + Message = buildSummary, + Changelog = buildChangelog, }); if (string.IsNullOrEmpty(buildPostString)) diff --git a/tools/CustomBuildTool/Source Files/Utils.cs b/tools/CustomBuildTool/Source Files/Utils.cs index ab413c2166cf..99a974c973ec 100644 --- a/tools/CustomBuildTool/Source Files/Utils.cs +++ b/tools/CustomBuildTool/Source Files/Utils.cs @@ -79,9 +79,7 @@ public static void CopyIfNewer(string CurrentFile, string NewFile) return; if (File.GetLastWriteTime(CurrentFile) > File.GetLastWriteTime(NewFile)) - { File.Copy(CurrentFile, NewFile, true); - } } public const int SW_HIDE = 0; @@ -345,6 +343,9 @@ public class BuildUpdateRequest [DataMember(Name = "message")] public string Message { get; set; } + + [DataMember(Name = "changelog")] + public string Changelog { get; set; } } [Flags] diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe b/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe index 9177a7a24ba8204a88c65a85ee637ab037780de5..b6f79ef199c0234d41ce3ff314eedc43bcf75b03 100644 GIT binary patch delta 18521 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 E8^~)Ff&c&j delta 18440 zcmbt*37k~bmHv6Js$Q*KUDZo1T~*!HKtuJ$4ub59vWbW+ilTtD0*W+Tj0#9sLmPt% zO7jr+1w6rQ)>3`a zt`Yyn;-5|qT04{I>-&gUdl8Y*YF6ug(z8MF|6nRkD=IzQBS%Y^9?#KIrgOE7vq-U2CGv%S&{}miu7h!D6*QjudZXF=K=*0w<{$Nb+HNyx zs~GFnk+(Cw2LqfKv!w{Xp}=J(CjwpuN0?zB~;H8hQA zK26$9@vyYEzg9F#i?ST+>7+I^6IBaV6|I{DRZXbH&K14ThMIIjO}5m8EzO;IO~lf? zmDfZqO_4p9tHRQx$K+KpOSLMmiCdaqZDQV5-v^x}+eh_f%tBfzfxW@wS}Nqjs^}6-6|7MGmKGK|d{kate?Fzbv&x+n5^;_I*|;6V{9I!0aN<_?OKP^uT~ zYp21wr6#J{MO^`P@4PyucCb3t2dY#LKpn+;+UY_JI>sfa_QI;(2BhX;wAEKki#-|I zMfHKGCS|!=%Jk+eJreb(9UgOKpu)5}Ye)4(^oBF_wOFL|uwY75#p+eg=JsZyS{{)C zk7;TQjH=CRE_Q~7WHRkz)xXG8tZY8XlnKkV8RbK5qUP_MiS#rWtGt;mw~DMNC~~1P z;ULdaqt}wVq5fUft^&2lmil8ZtEwndmYNGm-Jhc$Gp+Y$ttMNjDJJ>c)28C&#K$fn6q<)p7u^{L?fH+&dK#R?EpxTVMC;Fd-CFqbD zsNM~lOWi&E$64jdsUCAD(#0iQ1i&hB22(Rfzv2o!o}*u~wMS{zxfzn$pQDa4(2D?8 zsE)&U%9yG9+4COGt9o;L|?J>!*uW%ss2bBDlvd>R`h zzmXaM`AA^^x4GFH*Ox@i=e;rKC`=k>^FZ^ccff#0ku^6TTku5ZcTcwXGcz?@r#e@l zW|>WSScN&+SC;14msKr;xzPRH0{7BbN81u`$%my)WZoCl&kD36i&pHX!`?h7=aiud z@<@%5l(#DY57&o<|XymDQN6YD7V}((36EK#h6;J4F{eP0^SjS`FSzB#o zN88Qd+4_qtHT`vgR%FqNJzsw@SoAE^)T+O?DpO0ZGh6@XpmJIZbiv_=$47nkkKT7D z&4530=KdrmLv1yJ$pbnMl6o~u>noMmy`4JPCuZr9s88Jr;xcDdhs^8!iS$7>@p(_N z)G`=SW|ke#Sy;+jyeil^n}?;m#n*zFU#nsXO4U> zYZnZtM>}R9^)VDOFP$mHE7D(?$GXsB!{Wmrs!IVb;YTWp)XiPYtBVH(9)&VD?bRQ; zn0t%MM&%BB*4UO=N1nV^#&b{&n$_`am>Pnf$*uD-vrnM1;T5>$3!tvqOu3_BYA$M= z%QPVEf=e!gRY2~j*`Yppt<+~Q@@3CnEL&$Ubyk6z<&1hJL?u~<^0;2hR9r_0-w1wc z*_Uw7au&szQ{u;2B(u<5D>|EZ1k3e%x|)v$BMaVuPr>k#6*qTS?$D;ZmfK_<n#*hrgv_RrM8h8B$aSXrIu|K-3QslVd;e!81Ezgn zn8B)P?tI>%rg^Q@^puIf%VR_4e14(LJiRm?$q!ed@lKn$s5G9=&n+=#t`B+bQq;1w z2rWN#Pzv4iC5XEp?n_6YA|6AXp2Eg35^`5VT@AT~V_C)=|9%7-yLI8r+3UEB`P>Y&wh-W?jWx)y0)maxCI#=wG$N7}CRIz*HmW$Eo0 zgPJs=*wtp%jz);)>scu$>E;{6?&TO~uxSl*^$=W}ZxZpZ5DPAGT+imUr�)Cze}K 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 OqaN?Kdv8cPq5VH_`}I-) diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb b/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb index 60f23aad14bf323c3aad4586f2eba905471898ba..372d398db27ce85002681c32d8b6b0690eca97d9 100644 GIT binary patch delta 17059 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, + Index, + TI_GET_CHILDRENCOUNT, + &symbolCount + )) + { + return FALSE; + } + + if (symbolCount == 0) + return TRUE; + + length = sizeof(TI_FINDCHILDREN_PARAMS) + symbolCount * sizeof(ULONG); + symbols = _alloca(length); + memset(symbols, 0, length); + + symbols->Count = symbolCount; + + if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, Index, TI_FINDCHILDREN, symbols)) + return FALSE; + + *Count = symbolCount; + *Params = symbols; + + return TRUE; +} + BOOLEAN SymbolInfo_UdtVariables( _Inout_ PPDB_SYMBOL_CONTEXT Context, _In_ ULONG Index, @@ -928,6 +968,7 @@ BOOLEAN SymbolInfo_UdtVariables( ) { ULONG childrenLength = 0; + TI_FINDCHILDREN_PARAMS* symbolParams; if (!SymbolInfo_CheckTag(Context, Index, SymTagUDT)) return FALSE; @@ -935,33 +976,16 @@ BOOLEAN SymbolInfo_UdtVariables( if (MaxVars <= 0) return FALSE; - // Get the number of children - if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, Index, TI_GET_CHILDRENCOUNT, &childrenLength)) - return FALSE; - - if (childrenLength == 0) - { - *Vars = 0; - return TRUE; // No children -> no member variables - } - - // Get the children - ULONG FindChildrenSize = sizeof(TI_FINDCHILDREN_PARAMS) + childrenLength * sizeof(ULONG); - TI_FINDCHILDREN_PARAMS* params = (TI_FINDCHILDREN_PARAMS*)_alloca(FindChildrenSize); - memset(params, 0, FindChildrenSize); - params->Count = childrenLength; - - if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, Index, TI_FINDCHILDREN, params)) - return FALSE; + if (!PdbGetSymbolChildren(Context, Index, &childrenLength, &symbolParams)) + return FALSE; *Vars = 0; - // Enumerate children, looking for base classes, and copy their indexes. for (ULONG i = 0; i < childrenLength; i++) { - if (SymbolInfo_CheckTag(Context, params->ChildId[i], SymTagData)) + if (SymbolInfo_CheckTag(Context, symbolParams->ChildId[i], SymTagData)) { - pVars[*Vars] = params->ChildId[i]; + pVars[*Vars] = symbolParams->ChildId[i]; (*Vars)++; @@ -982,6 +1006,7 @@ BOOLEAN SymbolInfo_UdtFunctions( ) { ULONG childrenLength = 0; + TI_FINDCHILDREN_PARAMS* symbolParams; if (!SymbolInfo_CheckTag(Context, Index, SymTagUDT)) return FALSE; @@ -989,34 +1014,16 @@ BOOLEAN SymbolInfo_UdtFunctions( if (MaxFuncs <= 0) return FALSE; - // Get the number of children - if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, Index, TI_GET_CHILDRENCOUNT, &childrenLength)) - return FALSE; - - if (childrenLength == 0) - { - *Funcs = 0; // No children -> no member variables - return TRUE; - } - - // Get the children - ULONG FindChildrenSize = sizeof(TI_FINDCHILDREN_PARAMS) + childrenLength * sizeof(ULONG); - TI_FINDCHILDREN_PARAMS* params = (TI_FINDCHILDREN_PARAMS*)_alloca(FindChildrenSize); - memset(params, 0, FindChildrenSize); - - params->Count = childrenLength; - - if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, Index, TI_FINDCHILDREN, params)) - return FALSE; + if (!PdbGetSymbolChildren(Context, Index, &childrenLength, &symbolParams)) + return FALSE; *Funcs = 0; - // Enumerate children, looking for base classes, and copy their indexes. for (ULONG i = 0; i < childrenLength; i++) { - if (SymbolInfo_CheckTag(Context, params->ChildId[i], SymTagFunction)) + if (SymbolInfo_CheckTag(Context, symbolParams->ChildId[i], SymTagFunction)) { - pFuncs[*Funcs] = params->ChildId[i]; + pFuncs[*Funcs] = symbolParams->ChildId[i]; (*Funcs)++; @@ -1037,6 +1044,7 @@ BOOLEAN SymbolInfo_UdtBaseClasses( ) { ULONG childrenLength = 0; + TI_FINDCHILDREN_PARAMS* symbolParams; if (!SymbolInfo_CheckTag(Context, Index, SymTagUDT)) return FALSE; @@ -1044,34 +1052,16 @@ BOOLEAN SymbolInfo_UdtBaseClasses( if (MaxBases <= 0) return FALSE; - // Get the number of children - if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, Index, TI_GET_CHILDRENCOUNT, &childrenLength)) - return FALSE; - - if (childrenLength == 0) - { - *Bases = 0; // No children -> no member variables - return TRUE; - } - - // Get the children - ULONG FindChildrenSize = sizeof(TI_FINDCHILDREN_PARAMS) + childrenLength * sizeof(ULONG); - TI_FINDCHILDREN_PARAMS* params = (TI_FINDCHILDREN_PARAMS*)_alloca(FindChildrenSize); - memset(params, 0, FindChildrenSize); - - params->Count = childrenLength; - - if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, Index, TI_FINDCHILDREN, params)) - return FALSE; + if (!PdbGetSymbolChildren(Context, Index, &childrenLength, &symbolParams)) + return FALSE; *Bases = 0; - // Enumerate children, looking for base classes, and copy their indexes. for (ULONG i = 0; i < childrenLength; i++) { - if (SymbolInfo_CheckTag(Context, params->ChildId[i], SymTagBaseClass)) + if (SymbolInfo_CheckTag(Context, symbolParams->ChildId[i], SymTagBaseClass)) { - pBases[*Bases] = params->ChildId[i]; + pBases[*Bases] = symbolParams->ChildId[i]; (*Bases)++; @@ -1092,6 +1082,7 @@ BOOLEAN SymbolInfo_UdtUnionMembers( ) { ULONG childrenLength = 0; + TI_FINDCHILDREN_PARAMS* symbolParams; if (!SymbolInfo_CheckTag(Context, Index, SymTagUDT)) return FALSE; @@ -1099,34 +1090,16 @@ BOOLEAN SymbolInfo_UdtUnionMembers( if (MaxMembers <= 0) return FALSE; - // Get the number of children - if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, Index, TI_GET_CHILDRENCOUNT, &childrenLength)) - return FALSE; - - if (childrenLength == 0) - { - *Members = 0; - return TRUE; // No children -> no members - } - - // Get the children - ULONG FindChildrenSize = sizeof(TI_FINDCHILDREN_PARAMS) + childrenLength * sizeof(ULONG); - TI_FINDCHILDREN_PARAMS* params = (TI_FINDCHILDREN_PARAMS*)_alloca(FindChildrenSize); - memset(params, 0, FindChildrenSize); - - params->Count = childrenLength; - - if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, Index, TI_FINDCHILDREN, params)) - return FALSE; + if (!PdbGetSymbolChildren(Context, Index, &childrenLength, &symbolParams)) + return FALSE; *Members = 0; - // Enumerate children, looking for enumerators, and copy their indexes. for (ULONG i = 0; i < childrenLength; i++) { - if (SymbolInfo_CheckTag(Context, params->ChildId[i], SymTagData)) + if (SymbolInfo_CheckTag(Context, symbolParams->ChildId[i], SymTagData)) { - pMembers[*Members] = params->ChildId[i]; + pMembers[*Members] = symbolParams->ChildId[i]; (*Members)++; @@ -1147,6 +1120,7 @@ BOOLEAN SymbolInfo_FunctionArguments( ) { ULONG childrenLength = 0; + TI_FINDCHILDREN_PARAMS* symbolParams; if (!SymbolInfo_CheckTag(Context, Index, SymTagFunctionType)) return FALSE; @@ -1154,34 +1128,16 @@ BOOLEAN SymbolInfo_FunctionArguments( if (MaxArgs <= 0) return FALSE; - // Get the number of children - if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, Index, TI_GET_CHILDRENCOUNT, &childrenLength)) - return FALSE; - - if (childrenLength == 0) - { - *Args = 0; - return TRUE; // No children -> no member variables - } - - // Get the children - ULONG FindChildrenSize = sizeof(TI_FINDCHILDREN_PARAMS) + childrenLength * sizeof(ULONG); - TI_FINDCHILDREN_PARAMS* params = (TI_FINDCHILDREN_PARAMS*)_alloca(FindChildrenSize); - memset(params, 0, FindChildrenSize); - - params->Count = childrenLength; - - if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, Index, TI_FINDCHILDREN, params)) - return FALSE; + if (!PdbGetSymbolChildren(Context, Index, &childrenLength, &symbolParams)) + return FALSE; *Args = 0; - // Enumerate children, looking for enumerators, and copy their indexes. for (ULONG i = 0; i < childrenLength; i++) { - if (SymbolInfo_CheckTag(Context, params->ChildId[i], SymTagFunctionArgType)) + if (SymbolInfo_CheckTag(Context, symbolParams->ChildId[i], SymTagFunctionArgType)) { - pArgs[*Args] = params->ChildId[i]; + pArgs[*Args] = symbolParams->ChildId[i]; (*Args)++; @@ -1202,6 +1158,7 @@ BOOLEAN SymbolInfo_Enumerators( ) { ULONG childrenLength = 0; + TI_FINDCHILDREN_PARAMS* symbolParams; if (!SymbolInfo_CheckTag(Context, Index, SymTagEnum)) return FALSE; @@ -1209,34 +1166,16 @@ BOOLEAN SymbolInfo_Enumerators( if (MaxEnums <= 0) return FALSE; - // Get the number of children - if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, Index, TI_GET_CHILDRENCOUNT, &childrenLength)) - return FALSE; - - if (childrenLength == 0) - { - // No children -> no enumerators - *Enums = 0; - return TRUE; - } - - ULONG FindChildrenSize = sizeof(TI_FINDCHILDREN_PARAMS) + childrenLength * sizeof(ULONG); - TI_FINDCHILDREN_PARAMS* params = (TI_FINDCHILDREN_PARAMS*)_alloca(FindChildrenSize); - memset(params, 0, FindChildrenSize); - params->Count = childrenLength; - - // Get the children - if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, Index, TI_FINDCHILDREN, params)) - return FALSE; + if (!PdbGetSymbolChildren(Context, Index, &childrenLength, &symbolParams)) + return FALSE; *Enums = 0; - // Enumerate children, looking for enumerators, and copy their indexes. for (ULONG i = 0; i < childrenLength; i++) { - if (SymbolInfo_CheckTag(Context, params->ChildId[i], SymTagData)) + if (SymbolInfo_CheckTag(Context, symbolParams->ChildId[i], SymTagData)) { - pEnums[*Enums] = params->ChildId[i]; + pEnums[*Enums] = symbolParams->ChildId[i]; (*Enums)++; @@ -1311,21 +1250,19 @@ BOOLEAN SymbolInfo_GetTypeNameHelper( { TypeInfo Info; - // Get the type information if (!SymbolInfo_DumpType(Obj, Index, &Info)) { return FALSE; } else { - // Is it a pointer ? ULONG numPointers = 0; if (Info.Tag == SymTagPointerType) { - // Yes, get the number of * to show ULONG typeIndex = 0; + // Yes, get the number of * to show if (!SymbolInfo_PointerType(Obj, Index, &typeIndex, &numPointers)) return FALSE; @@ -1345,12 +1282,10 @@ BOOLEAN SymbolInfo_GetTypeNameHelper( PhAppendStringBuilder2(TypeName, SymbolInfo_BaseTypeStr(Info.sBaseTypeInfo.BaseType, Info.sBaseTypeInfo.Length)); PhAppendStringBuilder2(TypeName, L" "); break; - case SymTagTypedef: PhAppendStringBuilder2(TypeName, Info.sTypedefInfo.Name); PhAppendStringBuilder2(TypeName, L" "); break; - case SymTagUDT: { if (Info.UdtKind) @@ -1370,17 +1305,13 @@ BOOLEAN SymbolInfo_GetTypeNameHelper( } } break; - case SymTagEnum: PhAppendStringBuilder2(TypeName, Info.sEnumInfo.Name); break; - case SymTagFunctionType: { if (Info.sFunctionTypeInfo.MemberFunction && Info.sFunctionTypeInfo.StaticFunction) - { PhAppendStringBuilder2(TypeName, L"static "); - } // return value if (!SymbolInfo_GetTypeNameHelper(Info.sFunctionTypeInfo.RetTypeIndex, Obj, VarName, TypeName)) @@ -1395,15 +1326,15 @@ BOOLEAN SymbolInfo_GetTypeNameHelper( { PhAddItemList(Obj->UdtList, UlongToPtr(Info.sFunctionTypeInfo.ClassIndex)); - /* - // It is not needed to print the class name here, because it is contained in the function name + /* + // It is not needed to print the class name here, because it is contained in the function name if (!SymbolInfo_GetTypeNameHelper(Info.sFunctionTypeInfo.ClassIndex, Obj, VarName, TypeName)) return false; TypeName += "::"); */ } - // Print that it is a function + // Print name PhAppendStringBuilder2(TypeName, *VarName); // Print parameters @@ -1415,24 +1346,14 @@ BOOLEAN SymbolInfo_GetTypeNameHelper( return FALSE; if (i < (Info.sFunctionTypeInfo.NumArgs - 1)) - { PhAppendStringBuilder2(TypeName, L", "); - } } PhAppendStringBuilder2(TypeName, L") "); // Print "this" adjustment value if (Info.sFunctionTypeInfo.MemberFunction && Info.sFunctionTypeInfo.ThisAdjust != 0) - { - WCHAR buffer[MAX_PATH + 1] = L""; - - _snwprintf(buffer, ARRAYSIZE(buffer), L"this+%u", Info.sFunctionTypeInfo.ThisAdjust); - - PhAppendStringBuilder2(TypeName, L": "); - PhAppendStringBuilder2(TypeName, buffer); - PhAppendStringBuilder2(TypeName, L" "); - } + PhAppendFormatStringBuilder(TypeName, L": this+%u ", Info.sFunctionTypeInfo.ThisAdjust); } break; @@ -1442,7 +1363,6 @@ BOOLEAN SymbolInfo_GetTypeNameHelper( return FALSE; } break; - case SymTagArrayType: { // Print element type name @@ -1450,26 +1370,15 @@ BOOLEAN SymbolInfo_GetTypeNameHelper( return FALSE; PhAppendStringBuilder2(TypeName, L" "); - //PhAppendStringBuilder2(TypeName, *VarName); // Print dimensions for (ULONG i = 0; i < Info.sArrayTypeInfo.NumDimensions; i++) - { - WCHAR buffer[MAX_PATH + 1] = L""; - - _snwprintf(buffer, ARRAYSIZE(buffer), L"[%I64u]", Info.sArrayTypeInfo.Dimensions[i]); - - PhAppendStringBuilder2(TypeName, buffer); - } + PhAppendFormatStringBuilder(TypeName, L"[%I64u]", Info.sArrayTypeInfo.Dimensions[i]); } break; default: { - WCHAR buffer[MAX_PATH + 1] = L""; - - _snwprintf(buffer, ARRAYSIZE(buffer), L"Unknown(%lu)", Info.Tag); - - PhAppendStringBuilder2(TypeName, buffer); + PhAppendFormatStringBuilder(TypeName, L"Unknown+%lu", Info.Tag); } break; } @@ -1575,7 +1484,7 @@ PWSTR SymbolInfo_TagStr( return L"Dimension"; } - return L"Unknown"; + return L"UNKNOWN"; } @@ -1587,7 +1496,7 @@ PWSTR SymbolInfo_BaseTypeStr( switch (Type) { case btNoType: - return L"NoType"; + return L""; case btVoid: return L"void"; case btChar: @@ -1666,7 +1575,7 @@ PWSTR SymbolInfo_BaseTypeStr( return L"HRESULT"; } - return L"Unknown"; + return L"UNKNOWN"; } @@ -1677,7 +1586,7 @@ PWSTR SymbolInfo_CallConvStr( switch (CallConv) { case CV_CALL_NEAR_C: - return L"NEAR_C"; + return L"__cdecl"; case CV_CALL_FAR_C: return L"FAR_C"; case CV_CALL_NEAR_PASCAL: @@ -1685,21 +1594,21 @@ PWSTR SymbolInfo_CallConvStr( case CV_CALL_FAR_PASCAL: return L"FAR_PASCAL"; case CV_CALL_NEAR_FAST: - return L"NEAR_FAST"; + return L"__fastcall"; case CV_CALL_FAR_FAST: return L"FAR_FAST"; case CV_CALL_SKIPPED: return L"SKIPPED"; case CV_CALL_NEAR_STD: - return L"NEAR_STD"; + return L"__stdcall"; case CV_CALL_FAR_STD: return L"FAR_STD"; case CV_CALL_NEAR_SYS: - return L"NEAR_SYS"; + return L"__syscall"; case CV_CALL_FAR_SYS: return L"FAR_SYS"; case CV_CALL_THISCALL: - return L"THISCALL"; + return L"__thiscall"; case CV_CALL_MIPSCALL: return L"MIPSCALL"; case CV_CALL_GENERIC: @@ -1794,6 +1703,7 @@ VOID SymbolInfo_SymbolLocationStr( _swprintf(szReg, L"Reg+%u", SymbolInfo->Register); _swprintf(Buffer, L"%s+%I64u", szReg, SymbolInfo->Address); + //PhPrintPointer(Buffer, PTR_ADD_OFFSET(SymbolInfo->ModBase, SymbolInfo->Address)); } else if (SymbolInfo->Flags & SYMFLAG_FRAMEREL) { @@ -1948,11 +1858,12 @@ BOOL CALLBACK EnumCallbackProc( symDataKind = SymbolInfo_DataKindStr(dataKindType); - if ( - dataKindType == DataIsLocal || - dataKindType == DataIsParam - ) // || dataKindType == DataIsObjectPtr) + if (dataKindType == DataIsLocal || + dataKindType == DataIsParam || + dataKindType == DataIsObjectPtr) + { break; + } symbol = PhAllocate(sizeof(PV_SYMBOL_NODE)); memset(symbol, 0, sizeof(PV_SYMBOL_NODE)); @@ -1960,7 +1871,10 @@ BOOL CALLBACK EnumCallbackProc( switch (dataKindType) { case DataIsLocal: - symbol->Type = PV_SYMBOL_TYPE_LOCAL_VAR; + { + SymbolInfo->Address = SymbolInfo->ModBase + SymbolInfo->Address; + symbol->Type = PV_SYMBOL_TYPE_LOCAL_VAR; + } break; case DataIsStaticLocal: symbol->Type = PV_SYMBOL_TYPE_STATIC_LOCAL_VAR; From df225fb30d0788cdfc2773ae08dfb4975f29e8bd Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 19 May 2017 22:07:38 +1000 Subject: [PATCH 0134/2058] Update gitignore, Add sdk build during debug, Fix build output path --- .gitignore | 7 +- ProcessHacker/ProcessHacker.vcxproj | 7 + tools/CustomBuildTool/Source Files/Build.cs | 151 ++++++++++-------- tools/CustomBuildTool/Source Files/Utils.cs | 2 + .../bin/Release/CustomBuildTool.exe | Bin 160768 -> 160768 bytes .../bin/Release/CustomBuildTool.pdb | Bin 69120 -> 69120 bytes 6 files changed, 97 insertions(+), 70 deletions(-) diff --git a/.gitignore b/.gitignore index d38240e8b4e3..325569e78592 100644 --- a/.gitignore +++ b/.gitignore @@ -74,12 +74,9 @@ Desktop.ini ## Project specific rules ########################## -build/*.exe -build/*.zip -build/*.h -ProcessHacker/sdk/phapppub.h +build/output/ plugins-extra/ -/sdk/ +sdk/ KProcessHacker/*.log KProcessHacker/*.err diff --git a/ProcessHacker/ProcessHacker.vcxproj b/ProcessHacker/ProcessHacker.vcxproj index 60b6c8f4be98..5e3e2d24f2de 100644 --- a/ProcessHacker/ProcessHacker.vcxproj +++ b/ProcessHacker/ProcessHacker.vcxproj @@ -108,6 +108,9 @@ _UNICODE;UNICODE;%(PreprocessorDefinitions);$(ExternalCompilerOptions) ..\phnt\include;..\phlib\include;include;%(AdditionalIncludeDirectories) + + ..\build\build_sdk.cmd + @@ -136,6 +139,10 @@ _UNICODE;UNICODE;%(PreprocessorDefinitions);$(ExternalCompilerOptions) ..\phnt\include;..\phlib\include;include;%(AdditionalIncludeDirectories) + + + ..\build\build_sdk.cmd + diff --git a/tools/CustomBuildTool/Source Files/Build.cs b/tools/CustomBuildTool/Source Files/Build.cs index 6242b16b4135..8e010b9ace8b 100644 --- a/tools/CustomBuildTool/Source Files/Build.cs +++ b/tools/CustomBuildTool/Source Files/Build.cs @@ -1080,22 +1080,14 @@ public static bool BuildSolution(string Solution, BuildFlags Flags) #region Appx Package public static void BuildAppxPackage(BuildFlags Flags) { - string error; - string signToolExePath = Environment.ExpandEnvironmentVariables("%ProgramFiles(x86)%\\Windows Kits\\10\\bin\\x64\\SignTool.exe"); - Program.PrintColorMessage("Building processhacker-build-package.appxbundle...", ConsoleColor.Cyan); + string signToolExePath = Environment.ExpandEnvironmentVariables("%ProgramFiles(x86)%\\Windows Kits\\10\\bin\\x64\\SignTool.exe"); try { - if (!Directory.Exists("build\\output")) - Directory.CreateDirectory("build\\output"); - - if (File.Exists(BuildOutputFolder + "\\processhacker-build-package.appxbundle")) - File.Delete(BuildOutputFolder + "\\processhacker-build-package.appxbundle"); - - Win32.ImageResizeFile(44, "ProcessHacker\\resources\\ProcessHacker.png", "build\\output\\ProcessHacker-44.png"); - Win32.ImageResizeFile(50, "ProcessHacker\\resources\\ProcessHacker.png", "build\\output\\ProcessHacker-50.png"); - Win32.ImageResizeFile(150, "ProcessHacker\\resources\\ProcessHacker.png", "build\\output\\ProcessHacker-150.png"); + Win32.ImageResizeFile(44, "ProcessHacker\\resources\\ProcessHacker.png", BuildOutputFolder + "\\ProcessHacker-44.png"); + Win32.ImageResizeFile(50, "ProcessHacker\\resources\\ProcessHacker.png", BuildOutputFolder + "\\ProcessHacker-50.png"); + Win32.ImageResizeFile(150, "ProcessHacker\\resources\\ProcessHacker.png", BuildOutputFolder + "\\ProcessHacker-150.png"); if ((Flags & BuildFlags.Build32bit) == BuildFlags.Build32bit) { @@ -1103,15 +1095,15 @@ public static void BuildAppxPackage(BuildFlags Flags) string appxManifestString = Properties.Resources.AppxManifest; appxManifestString = appxManifestString.Replace("PH_APPX_ARCH", "x86"); appxManifestString = appxManifestString.Replace("PH_APPX_VERSION", BuildLongVersion); - File.WriteAllText("build\\output\\AppxManifest32.xml", appxManifestString); + File.WriteAllText(BuildOutputFolder + "\\AppxManifest32.xml", appxManifestString); // create the package mapping file StringBuilder packageMap32 = new StringBuilder(0x100); packageMap32.AppendLine("[Files]"); - packageMap32.AppendLine("\"build\\output\\AppxManifest32.xml\" \"AppxManifest.xml\""); - packageMap32.AppendLine("\"build\\output\\ProcessHacker-44.png\" \"Assets\\ProcessHacker-44.png\""); - packageMap32.AppendLine("\"build\\output\\ProcessHacker-50.png\" \"Assets\\ProcessHacker-50.png\""); - packageMap32.AppendLine("\"build\\output\\ProcessHacker-150.png\" \"Assets\\ProcessHacker-150.png\""); + packageMap32.AppendLine("\"" + BuildOutputFolder + "\\AppxManifest32.xml\" \"AppxManifest.xml\""); + packageMap32.AppendLine("\"" + BuildOutputFolder + "\\ProcessHacker-44.png\" \"Assets\\ProcessHacker-44.png\""); + packageMap32.AppendLine("\"" + BuildOutputFolder + "\\ProcessHacker-50.png\" \"Assets\\ProcessHacker-50.png\""); + packageMap32.AppendLine("\"" + BuildOutputFolder + "\\ProcessHacker-150.png\" \"Assets\\ProcessHacker-150.png\""); var filesToAdd = Directory.GetFiles("bin\\Release32", "*", SearchOption.AllDirectories); for (int i = 0; i < filesToAdd.Length; i++) @@ -1130,21 +1122,23 @@ public static void BuildAppxPackage(BuildFlags Flags) packageMap32.AppendLine("\"" + filePath + "\" \"" + filePath.Substring("bin\\Release32\\".Length) + "\""); } - File.WriteAllText("build\\output\\package32.map", packageMap32.ToString()); + File.WriteAllText(BuildOutputFolder + "\\package32.map", packageMap32.ToString()); // create the package - error = Win32.ShellExecute( + Win32.ShellExecute( MakeAppxExePath, - "pack /o /f build\\output\\package32.map /p " + BuildOutputFolder + "\\output\\processhacker-build-package-x32.appx" + "pack /o /f " + BuildOutputFolder + "\\package32.map /p " + + BuildOutputFolder + "\\processhacker-build-package-x32.appx" ); - Program.PrintColorMessage(Environment.NewLine + error, ConsoleColor.Gray); + //Program.PrintColorMessage(Environment.NewLine + error, ConsoleColor.Gray); // sign the package - error = Win32.ShellExecute( + Win32.ShellExecute( signToolExePath, - "sign /v /fd SHA256 /a /f build\\processhacker-appx.pfx /td SHA256 " + BuildOutputFolder + "\\output\\processhacker-build-package-x32.appx" + "sign /v /fd SHA256 /a /f " + BuildOutputFolder + "\\processhacker-appx.pfx /td SHA256 " + + BuildOutputFolder + "\\processhacker-build-package-x32.appx" ); - Program.PrintColorMessage(Environment.NewLine + error, ConsoleColor.Gray); + //Program.PrintColorMessage(Environment.NewLine + error, ConsoleColor.Gray); } if ((Flags & BuildFlags.Build64bit) == BuildFlags.Build64bit) @@ -1153,14 +1147,14 @@ public static void BuildAppxPackage(BuildFlags Flags) string appxManifestString = Properties.Resources.AppxManifest; appxManifestString = appxManifestString.Replace("PH_APPX_ARCH", "x64"); appxManifestString = appxManifestString.Replace("PH_APPX_VERSION", BuildLongVersion); - File.WriteAllText("build\\output\\AppxManifest64.xml", appxManifestString); + File.WriteAllText(BuildOutputFolder + "\\AppxManifest64.xml", appxManifestString); StringBuilder packageMap64 = new StringBuilder(0x100); packageMap64.AppendLine("[Files]"); - packageMap64.AppendLine("\"build\\output\\AppxManifest64.xml\" \"AppxManifest.xml\""); - packageMap64.AppendLine("\"build\\output\\ProcessHacker-44.png\" \"Assets\\ProcessHacker-44.png\""); - packageMap64.AppendLine("\"build\\output\\ProcessHacker-50.png\" \"Assets\\ProcessHacker-50.png\""); - packageMap64.AppendLine("\"build\\output\\ProcessHacker-150.png\" \"Assets\\ProcessHacker-150.png\""); + packageMap64.AppendLine("\"" + BuildOutputFolder + "\\AppxManifest64.xml\" \"AppxManifest.xml\""); + packageMap64.AppendLine("\"" + BuildOutputFolder + "\\ProcessHacker-44.png\" \"Assets\\ProcessHacker-44.png\""); + packageMap64.AppendLine("\"" + BuildOutputFolder + "\\ProcessHacker-50.png\" \"Assets\\ProcessHacker-50.png\""); + packageMap64.AppendLine("\"" + BuildOutputFolder + "\\ProcessHacker-150.png\" \"Assets\\ProcessHacker-150.png\""); var filesToAdd = Directory.GetFiles("bin\\Release64", "*", SearchOption.AllDirectories); for (int i = 0; i < filesToAdd.Length; i++) @@ -1179,47 +1173,74 @@ public static void BuildAppxPackage(BuildFlags Flags) packageMap64.AppendLine("\"" + filePath + "\" \"" + filePath.Substring("bin\\Release64\\".Length) + "\""); } - File.WriteAllText("build\\output\\package64.map", packageMap64.ToString()); + File.WriteAllText(BuildOutputFolder + "\\package64.map", packageMap64.ToString()); // create the package - error = Win32.ShellExecute( + Win32.ShellExecute( MakeAppxExePath, - "pack /o /f build\\output\\package64.map /p " + BuildOutputFolder + "\\output\\processhacker-build-package-x64.appx" + "pack /o /f " + BuildOutputFolder + "\\package64.map /p " + + BuildOutputFolder + "\\processhacker-build-package-x64.appx" ); - Program.PrintColorMessage(Environment.NewLine + error, ConsoleColor.Gray); + //Program.PrintColorMessage(Environment.NewLine + error, ConsoleColor.Gray); // sign the package - error = Win32.ShellExecute( + Win32.ShellExecute( signToolExePath, - "sign /v /fd SHA256 /a /f build\\processhacker-appx.pfx /td SHA256 " + BuildOutputFolder + "\\output\\processhacker-build-package-x64.appx" + "sign /v /fd SHA256 /a /f " + BuildOutputFolder + "\\processhacker-appx.pfx /td SHA256 " + + BuildOutputFolder + "\\processhacker-build-package-x64.appx" ); - Program.PrintColorMessage(Environment.NewLine + error, ConsoleColor.Gray); + //Program.PrintColorMessage(Environment.NewLine + error, ConsoleColor.Gray); } { // create the appx bundle map StringBuilder bundleMap = new StringBuilder(0x100); bundleMap.AppendLine("[Files]"); - bundleMap.AppendLine("\"" + BuildOutputFolder + "\\output\\processhacker-build-package-x32.appx\" \"processhacker-build-package-x32.appx\""); - bundleMap.AppendLine("\"" + BuildOutputFolder + "\\output\\processhacker-build-package-x64.appx\" \"processhacker-build-package-x64.appx\""); - File.WriteAllText("build\\output\\bundle.map", bundleMap.ToString()); + bundleMap.AppendLine("\"" + BuildOutputFolder + "\\processhacker-build-package-x32.appx\" \"processhacker-build-package-x32.appx\""); + bundleMap.AppendLine("\"" + BuildOutputFolder + "\\processhacker-build-package-x64.appx\" \"processhacker-build-package-x64.appx\""); + File.WriteAllText(BuildOutputFolder + "\\bundle.map", bundleMap.ToString()); + + if (File.Exists(BuildOutputFolder + "\\processhacker-build-package.appxbundle")) + File.Delete(BuildOutputFolder + "\\processhacker-build-package.appxbundle"); // create the appx bundle package - error = Win32.ShellExecute( + Win32.ShellExecute( MakeAppxExePath, - "bundle /f build\\output\\bundle.map /p " + BuildOutputFolder + "\\processhacker-build-package.appxbundle" + "bundle /f " + BuildOutputFolder + "\\bundle.map /p " + + BuildOutputFolder + "\\processhacker-build-package.appxbundle" ); - Program.PrintColorMessage(Environment.NewLine + error, ConsoleColor.Gray); + //Program.PrintColorMessage(Environment.NewLine + error, ConsoleColor.Gray); // sign the appx bundle package - error = Win32.ShellExecute( + Win32.ShellExecute( signToolExePath, - "sign /v /fd SHA256 /a /f build\\processhacker-appx.pfx /td SHA256 " + BuildOutputFolder + "\\processhacker-build-package.appxbundle" + "sign /v /fd SHA256 /a /f " + BuildOutputFolder + "\\processhacker-appx.pfx /td SHA256 " + + BuildOutputFolder + "\\processhacker-build-package.appxbundle" ); - Program.PrintColorMessage(Environment.NewLine + error, ConsoleColor.Gray); + //Program.PrintColorMessage(Environment.NewLine + error, ConsoleColor.Gray); } - Directory.Delete("build\\output", true); + try + { + string[] cleanupAppxArray = + { + BuildOutputFolder + "\\AppxManifest32.xml", + BuildOutputFolder + "\\AppxManifest64.xml", + BuildOutputFolder + "\\package32.map", + BuildOutputFolder + "\\package64.map", + BuildOutputFolder + "\\bundle.map", + BuildOutputFolder + "\\ProcessHacker-44.png", + BuildOutputFolder + "\\ProcessHacker-50.png", + BuildOutputFolder + "\\ProcessHacker-150.png" + }; + + for (int i = 0; i < cleanupAppxArray.Length; i++) + { + if (File.Exists(cleanupAppxArray[i])) + File.Delete(cleanupAppxArray[i]); + } + } + catch (Exception) { } } catch (Exception ex) { @@ -1236,12 +1257,18 @@ public static bool BuildAppxSignature() try { - if (File.Exists("build\\processhacker-appx.pvk")) - File.Delete("build\\processhacker-appx.pvk"); - if (File.Exists("build\\processhacker-appx.cer")) - File.Delete("build\\processhacker-appx.cer"); - if (File.Exists("build\\processhacker-appx.pfx")) - File.Delete("build\\processhacker-appx.pfx"); + string[] cleanupAppxArray = + { + BuildOutputFolder + "\\processhacker-appx.pvk", + BuildOutputFolder + "\\processhacker-appx.cer", + BuildOutputFolder + "\\processhacker-appx.pfx" + }; + + for (int i = 0; i < cleanupAppxArray.Length; i++) + { + if (File.Exists(cleanupAppxArray[i])) + File.Delete(cleanupAppxArray[i]); + } string output = Win32.ShellExecute(makeCertExePath, "/n " + @@ -1249,8 +1276,8 @@ public static bool BuildAppxSignature() "/r /h 0 " + "/eku \"1.3.6.1.5.5.7.3.3,1.3.6.1.4.1.311.10.3.13\" " + "/sv " + - "build\\processhacker-appx.pvk " + - "build\\processhacker-appx.cer " + BuildOutputFolder + "\\processhacker-appx.pvk " + + BuildOutputFolder + "\\processhacker-appx.cer " ); if (!string.IsNullOrEmpty(output) && !output.Equals("Succeeded", StringComparison.OrdinalIgnoreCase)) @@ -1260,9 +1287,9 @@ public static bool BuildAppxSignature() } output = Win32.ShellExecute(pvk2PfxExePath, - "/pvk build\\processhacker-appx.pvk " + - "/spc build\\processhacker-appx.cer " + - "/pfx build\\processhacker-appx.pfx " + "/pvk " + BuildOutputFolder + "\\processhacker-appx.pvk " + + "/spc " + BuildOutputFolder + "\\processhacker-appx.cer " + + "/pfx " + BuildOutputFolder + "\\processhacker-appx.pfx " ); if (!string.IsNullOrEmpty(output)) @@ -1272,7 +1299,7 @@ public static bool BuildAppxSignature() } output = Win32.ShellExecute(CertUtilExePath, - "-addStore TrustedPeople build\\processhacker-appx.cer" + "-addStore TrustedPeople " + BuildOutputFolder + "\\processhacker-appx.cer" ); if (!string.IsNullOrEmpty(output) && !output.Contains("command completed successfully")) @@ -1295,6 +1322,7 @@ public static bool CleanupAppxSignature() try { X509Store store = new X509Store(StoreName.TrustedPeople, StoreLocation.LocalMachine); + store.Open(OpenFlags.ReadWrite); foreach (X509Certificate2 c in store.Certificates) @@ -1305,13 +1333,6 @@ public static bool CleanupAppxSignature() store.Remove(c); } } - - if (File.Exists("build\\processhacker-appx.pvk")) - File.Delete("build\\processhacker-appx.pvk"); - if (File.Exists("build\\processhacker-appx.cer")) - File.Delete("build\\processhacker-appx.cer"); - if (File.Exists("build\\processhacker-appx.pfx")) - File.Delete("build\\processhacker-appx.pfx"); } catch (Exception ex) { diff --git a/tools/CustomBuildTool/Source Files/Utils.cs b/tools/CustomBuildTool/Source Files/Utils.cs index 99a974c973ec..3f3c9a5008a2 100644 --- a/tools/CustomBuildTool/Source Files/Utils.cs +++ b/tools/CustomBuildTool/Source Files/Utils.cs @@ -99,6 +99,8 @@ public static void CopyIfNewer(string CurrentFile, string NewFile) public static extern IntPtr GetConsoleWindow(); [DllImport("user32.dll", ExactSpelling = true)] public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow); + [DllImport("user32.dll", CharSet = CharSet.Unicode)] + public static extern int MessageBox(IntPtr hWnd, string m, string c, int type); } public static class Json where T : class diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe b/tools/CustomBuildTool/bin/Release/CustomBuildTool.exe index b6f79ef199c0234d41ce3ff314eedc43bcf75b03..fc9e59071d2563b2d76ea3a8c6eb0350d3a977b5 100644 GIT binary patch delta 12485 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 BXwd)w delta 12532 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 diff --git a/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb b/tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb index 372d398db27ce85002681c32d8b6b0690eca97d9..8a6ef390251d29c386caf969281fd9efd5b8d05d 100644 GIT binary patch delta 7357 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 F{{a3D`?df8 From c8db767248cd2d6d68e527809e6801e7f6900115 Mon Sep 17 00:00:00 2001 From: dmex Date: Fri, 19 May 2017 22:14:51 +1000 Subject: [PATCH 0135/2058] peview: Add missing debug directory check --- tools/peview/peprp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/peview/peprp.c b/tools/peview/peprp.c index 73ee2331031a..75ce0487a33f 100644 --- a/tools/peview/peprp.c +++ b/tools/peview/peprp.c @@ -174,6 +174,7 @@ VOID PvPeProperties( } // Symbols page + if (NT_SUCCESS(PhGetMappedImageDataEntry(&PvMappedImage, IMAGE_DIRECTORY_ENTRY_DEBUG, &entry)) && entry->VirtualAddress) { newPage = PvCreatePropPageContext( MAKEINTRESOURCE(IDD_PESYMBOLS), From 29ee346f5379a2b76799d4048cf100307f61e0d8 Mon Sep 17 00:00:00 2001 From: dmex Date: Sat, 20 May 2017 22:50:37 +1000 Subject: [PATCH 0136/2058] peview: Fix symbol tab crash --- tools/peview/pdb.c | 123 +++++++++++++++++++++++---------------------- 1 file changed, 63 insertions(+), 60 deletions(-) diff --git a/tools/peview/pdb.c b/tools/peview/pdb.c index 10d74158e9ff..7fac14523a91 100644 --- a/tools/peview/pdb.c +++ b/tools/peview/pdb.c @@ -920,43 +920,43 @@ BOOLEAN SymbolInfo_ArrayDims( } BOOLEAN PdbGetSymbolChildren( - _Inout_ PPDB_SYMBOL_CONTEXT Context, - _In_ ULONG Index, - _Inout_ ULONG* Count, - _Inout_ TI_FINDCHILDREN_PARAMS **Params - ) + _Inout_ PPDB_SYMBOL_CONTEXT Context, + _In_ ULONG Index, + _Inout_ ULONG* Count, + _Inout_ TI_FINDCHILDREN_PARAMS **Params + ) { - ULONG length; - ULONG symbolCount = 0; - TI_FINDCHILDREN_PARAMS* symbols; - - if (!SymGetTypeInfo_I( - NtCurrentProcess(), - Context->BaseAddress, - Index, - TI_GET_CHILDRENCOUNT, - &symbolCount - )) - { - return FALSE; - } - - if (symbolCount == 0) - return TRUE; - - length = sizeof(TI_FINDCHILDREN_PARAMS) + symbolCount * sizeof(ULONG); - symbols = _alloca(length); - memset(symbols, 0, length); - - symbols->Count = symbolCount; - - if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, Index, TI_FINDCHILDREN, symbols)) - return FALSE; - - *Count = symbolCount; - *Params = symbols; - - return TRUE; + ULONG length; + ULONG symbolCount = 0; + TI_FINDCHILDREN_PARAMS* symbols; + + if (!SymGetTypeInfo_I( + NtCurrentProcess(), + Context->BaseAddress, + Index, + TI_GET_CHILDRENCOUNT, + &symbolCount + )) + { + return FALSE; + } + + if (symbolCount == 0) + return TRUE; + + length = sizeof(TI_FINDCHILDREN_PARAMS) + symbolCount * sizeof(ULONG); + symbols = _alloca(length); + memset(symbols, 0, length); + + symbols->Count = symbolCount; + + if (!SymGetTypeInfo_I(NtCurrentProcess(), Context->BaseAddress, Index, TI_FINDCHILDREN, symbols)) + return FALSE; + + *Count = symbolCount; + *Params = symbols; + + return TRUE; } BOOLEAN SymbolInfo_UdtVariables( @@ -968,7 +968,7 @@ BOOLEAN SymbolInfo_UdtVariables( ) { ULONG childrenLength = 0; - TI_FINDCHILDREN_PARAMS* symbolParams; + TI_FINDCHILDREN_PARAMS* symbolParams; if (!SymbolInfo_CheckTag(Context, Index, SymTagUDT)) return FALSE; @@ -976,8 +976,8 @@ BOOLEAN SymbolInfo_UdtVariables( if (MaxVars <= 0) return FALSE; - if (!PdbGetSymbolChildren(Context, Index, &childrenLength, &symbolParams)) - return FALSE; + if (!PdbGetSymbolChildren(Context, Index, &childrenLength, &symbolParams)) + return FALSE; *Vars = 0; @@ -1006,7 +1006,7 @@ BOOLEAN SymbolInfo_UdtFunctions( ) { ULONG childrenLength = 0; - TI_FINDCHILDREN_PARAMS* symbolParams; + TI_FINDCHILDREN_PARAMS* symbolParams; if (!SymbolInfo_CheckTag(Context, Index, SymTagUDT)) return FALSE; @@ -1014,8 +1014,8 @@ BOOLEAN SymbolInfo_UdtFunctions( if (MaxFuncs <= 0) return FALSE; - if (!PdbGetSymbolChildren(Context, Index, &childrenLength, &symbolParams)) - return FALSE; + if (!PdbGetSymbolChildren(Context, Index, &childrenLength, &symbolParams)) + return FALSE; *Funcs = 0; @@ -1044,7 +1044,7 @@ BOOLEAN SymbolInfo_UdtBaseClasses( ) { ULONG childrenLength = 0; - TI_FINDCHILDREN_PARAMS* symbolParams; + TI_FINDCHILDREN_PARAMS* symbolParams; if (!SymbolInfo_CheckTag(Context, Index, SymTagUDT)) return FALSE; @@ -1052,8 +1052,8 @@ BOOLEAN SymbolInfo_UdtBaseClasses( if (MaxBases <= 0) return FALSE; - if (!PdbGetSymbolChildren(Context, Index, &childrenLength, &symbolParams)) - return FALSE; + if (!PdbGetSymbolChildren(Context, Index, &childrenLength, &symbolParams)) + return FALSE; *Bases = 0; @@ -1082,7 +1082,7 @@ BOOLEAN SymbolInfo_UdtUnionMembers( ) { ULONG childrenLength = 0; - TI_FINDCHILDREN_PARAMS* symbolParams; + TI_FINDCHILDREN_PARAMS* symbolParams; if (!SymbolInfo_CheckTag(Context, Index, SymTagUDT)) return FALSE; @@ -1090,8 +1090,8 @@ BOOLEAN SymbolInfo_UdtUnionMembers( if (MaxMembers <= 0) return FALSE; - if (!PdbGetSymbolChildren(Context, Index, &childrenLength, &symbolParams)) - return FALSE; + if (!PdbGetSymbolChildren(Context, Index, &childrenLength, &symbolParams)) + return FALSE; *Members = 0; @@ -1120,7 +1120,7 @@ BOOLEAN SymbolInfo_FunctionArguments( ) { ULONG childrenLength = 0; - TI_FINDCHILDREN_PARAMS* symbolParams; + TI_FINDCHILDREN_PARAMS* symbolParams; if (!SymbolInfo_CheckTag(Context, Index, SymTagFunctionType)) return FALSE; @@ -1128,8 +1128,8 @@ BOOLEAN SymbolInfo_FunctionArguments( if (MaxArgs <= 0) return FALSE; - if (!PdbGetSymbolChildren(Context, Index, &childrenLength, &symbolParams)) - return FALSE; + if (!PdbGetSymbolChildren(Context, Index, &childrenLength, &symbolParams)) + return FALSE; *Args = 0; @@ -1158,7 +1158,7 @@ BOOLEAN SymbolInfo_Enumerators( ) { ULONG childrenLength = 0; - TI_FINDCHILDREN_PARAMS* symbolParams; + TI_FINDCHILDREN_PARAMS* symbolParams; if (!SymbolInfo_CheckTag(Context, Index, SymTagEnum)) return FALSE; @@ -1166,8 +1166,8 @@ BOOLEAN SymbolInfo_Enumerators( if (MaxEnums <= 0) return FALSE; - if (!PdbGetSymbolChildren(Context, Index, &childrenLength, &symbolParams)) - return FALSE; + if (!PdbGetSymbolChildren(Context, Index, &childrenLength, &symbolParams)) + return FALSE; *Enums = 0; @@ -1262,7 +1262,7 @@ BOOLEAN SymbolInfo_GetTypeNameHelper( { ULONG typeIndex = 0; - // Yes, get the number of * to show + // Yes, get the number of * to show if (!SymbolInfo_PointerType(Obj, Index, &typeIndex, &numPointers)) return FALSE; @@ -1327,7 +1327,7 @@ BOOLEAN SymbolInfo_GetTypeNameHelper( PhAddItemList(Obj->UdtList, UlongToPtr(Info.sFunctionTypeInfo.ClassIndex)); /* - // It is not needed to print the class name here, because it is contained in the function name + // It is not needed to print the class name here, because it is contained in the function name if (!SymbolInfo_GetTypeNameHelper(Info.sFunctionTypeInfo.ClassIndex, Obj, VarName, TypeName)) return false; TypeName += "::"); @@ -1353,7 +1353,7 @@ BOOLEAN SymbolInfo_GetTypeNameHelper( // Print "this" adjustment value if (Info.sFunctionTypeInfo.MemberFunction && Info.sFunctionTypeInfo.ThisAdjust != 0) - PhAppendFormatStringBuilder(TypeName, L": this+%u ", Info.sFunctionTypeInfo.ThisAdjust); + PhAppendFormatStringBuilder(TypeName, L": this+%u ", Info.sFunctionTypeInfo.ThisAdjust); } break; @@ -1373,7 +1373,7 @@ BOOLEAN SymbolInfo_GetTypeNameHelper( // Print dimensions for (ULONG i = 0; i < Info.sArrayTypeInfo.NumDimensions; i++) - PhAppendFormatStringBuilder(TypeName, L"[%I64u]", Info.sArrayTypeInfo.Dimensions[i]); + PhAppendFormatStringBuilder(TypeName, L"[%I64u]", Info.sArrayTypeInfo.Dimensions[i]); } break; default: @@ -2299,8 +2299,11 @@ NTSTATUS PeDumpFileSymbols( PPH_STRING dbghelpPath; PPH_STRING symsrvPath; - dbghelpPath = PvFindDbghelpPath(FALSE); - symsrvPath = PvFindDbghelpPath(TRUE); + if (!(dbghelpPath = PvFindDbghelpPath(FALSE))) + return 1; + if (!(symsrvPath = PvFindDbghelpPath(TRUE))) + return 1; + dbghelpHandle = LoadLibrary(dbghelpPath->Buffer); symsrvHandle = LoadLibrary(symsrvPath->Buffer); From ee84c5e84c542707ce602ced6fdaff0f9e29a38a Mon Sep 17 00:00:00 2001 From: dmex Date: Sun, 21 May 2017 05:54:59 +1000 Subject: [PATCH 0137/2058] [Tools] Add delaylib --- .gitignore | 2 + tools/delaylib/bin/Debug32/delaylib.lib | Bin 0 -> 20588 bytes tools/delaylib/bin/Debug32/delaylib.pdb | Bin 0 -> 135168 bytes tools/delaylib/bin/Debug64/delaylib.lib | Bin 0 -> 21430 bytes tools/delaylib/bin/Debug64/delaylib.pdb | Bin 0 -> 135168 bytes tools/delaylib/bin/Release32/delaylib.lib | Bin 0 -> 226114 bytes tools/delaylib/bin/Release64/delaylib.lib | Bin 0 -> 225886 bytes tools/delaylib/delaylib.sln | 28 ++++ tools/delaylib/delaylib.vcxproj | 184 ++++++++++++++++++++++ tools/delaylib/delaylib.vcxproj.filters | 22 +++ tools/delaylib/main.c | 125 +++++++++++++++ 11 files changed, 361 insertions(+) create mode 100644 tools/delaylib/bin/Debug32/delaylib.lib create mode 100644 tools/delaylib/bin/Debug32/delaylib.pdb create mode 100644 tools/delaylib/bin/Debug64/delaylib.lib create mode 100644 tools/delaylib/bin/Debug64/delaylib.pdb create mode 100644 tools/delaylib/bin/Release32/delaylib.lib create mode 100644 tools/delaylib/bin/Release64/delaylib.lib create mode 100644 tools/delaylib/delaylib.sln create mode 100644 tools/delaylib/delaylib.vcxproj create mode 100644 tools/delaylib/delaylib.vcxproj.filters create mode 100644 tools/delaylib/main.c diff --git a/.gitignore b/.gitignore index 325569e78592..53afad1c8da7 100644 --- a/.gitignore +++ b/.gitignore @@ -115,3 +115,5 @@ tools/fixlib/bin/Release/* tools/GenerateZw/GenerateZw/bin/Debug/ tools/GenerateZw/GenerateZw/bin/Release/* !tools/GenerateZw/GenerateZw/bin/Release/GenerateZw.exe + +!tools/delaylib/bin/ diff --git a/tools/delaylib/bin/Debug32/delaylib.lib b/tools/delaylib/bin/Debug32/delaylib.lib new file mode 100644 index 0000000000000000000000000000000000000000..418c0549ec1d5c58d058709cb9f229f93ce16b8c GIT binary patch literal 20588 zcmdUXd3;;do$pbc*oqy9m4(o-DZ!8gLh2J|wqztZTcI^C zEYUNWfwnB&hIUFzroijWlmWWY0O6&)4|M3lFn!I?P||@6X&XwImqOai_j}I0*OFz2 zp~*k*Ch|G=ceda8?dRNk?wre$`P9ZM>p$+Uyjm8oSkl(g+}yIP65edywybC~bJy1k zA!>z~aPwHdtFF?$?Rs;Ex4okyvQi6%L+z1#E@c!7-O1FAM*gbB#unqMCXc6G=%J!_ zFrPQF#kjG)y;V=(<1K zm&qFbY|+T~<AHb@?gk@OEHFc+Zj?-IU02NI`U>kLsrxeP z*X7pVu+C?!AKcK^x~@N&$u0r_RJVl5lBscI4q~`;=~B15WySIpEwb+Q^#R9J@yy@2 z*Z!|AA+7)icrAi}q>7sibtl9v$n=3T6<2*D>JgQum<3<6Oo)T1=eblt&O_2J8avE- zajV|-$ZWpMx>KpFS2VU1oBFd>Nd$epihA>|RFHF!xJBgpMWgC90PeraYNb+lBkGO9 z?yvBk}MCLQ7cb{1o-DAFHy?AB4ub|FDqv}EAKJL>xJ&8a(;P1F} zZnl{2>sti5o?8h|<@!^_zP8peiZ&VfLME3TqXa#AgK^)euEGId$P?6JbKOM#9sIWA zrwIpnB~DWDE)|!%gnNRh6VpY#_#P-~rNK-ppDW~gi|+Z+1@7=bG1H&f2J`Cn=K2RR zeMVl0_b`4FkuWa``wrxt=KVrs=Hbr5`&%eqF1jS%Vp=16 zw=QcG+}}G5$Y1I@cKrD9Ga#C$i7Dk{e5Bh((cogwebYhXY%#x8oC(MjKste)zkeW? zFPiR0oQ0CZ7_$Zwlt!=2H;I`jJc7aj6lP?zP_o|;vjN@*Z~^^~faA&aeTJBUvJX(^ z#%Ni?NEbTuh9PDF`WB!ZU$y8?X49xnR1cV4!BYZNRy_m=5$eyS2m1`O>KQ25Z&p=( zs1aw18k(J<$kwy=V*@zh5JPPB}#R}IwXw2(z%!K#s=^Zq52PY_|3_yZc8X#&}na(Wc^Zsez!aO8(5!*h^cjPxR;^dHC%bt7Gf zbT!gTkoF?|IMPodZ9!T>+KO}-=@O(5BZUtddIafmq~r+v$Iz=tVWWrMMS3;T_mPH> z)&hqJQnDk8)QvQTv=u45)ey;zv4=X4u0a|{`U#|@=(R{UA_awq?nMgRh8{=SkMt>| zHz9o<>1L$ALb?^{ACMxt8+s2Zoa)d!z~lQDa;|l*`7?xYh^xaLdbs0i%^TN4T3nBM z;+pOahvLz2K-WT^j(~;i-#ifeIipji+ zj|&ADX&9~3Tt_h(bs-+^Pi`xz2TX8m0T{-1_i(hHQXmQUTcaqCeZ4%l9XX z@J|vARs_K-Dkl6|#aaajvFgt`s+uR8_UAmQRBkX^1V-gOlhW*Y@<8dc0$znkx zQHI4=$j%tmPMmKR%u)qCnS60D*_YWSd-e47yV99sRnoF_N@+>OCdq-$99CV$ zcz&=@^yL`4b84auBmEAjPY^zTEE4dng|c`0yY!gX6AJht{Nboii~2)dx<3@xq5+Rr z^NG1=)FDY3Gy0PQ8_{zWd&s_(vQ9kHZ{(}WsQ|x0c|Ccb=^yNmZ_FFXG*qETKU?Rz z2w2av3RfpH#i)@iK(gH^dm2Im%c+(sRb9_CYfQ9i5QBnb1RK^_V7ZWqAS94QaNwdw zL_penqG04rtPr@U;bvN`JiWacELpb(lZ6{4CD`YgR%y%>iZWHS5T0$-S)JRwbaA<0 z%`wL~*Qy~gQ|fKT0Hg>9nqyTNQ5PG%OeRD}xav2d4*7S&To!Ggfj z#J~;&AP7)Ncosr3jp|Zr75hEI?6-^@GyyDv@<@>ynXiQmG)9(GOqXn0VG6ahj#YE{ zm~gtzg_Lv#!k#!)BIfDQbWc?CAUbinno*>C6H%W(3VCq4mhfI%SbiqX=pPQVkF7a;g1JB5eSXb#RZt22>HEXpQgv+ zG;uHkPS<%5fp~bO7Sdt4u4I5%&9EsfX~)5Dl8COxG^Bn|?e$7AX+$lI zCRSSUmY5F+W7ZQztSUCV1T`0_nr3LL*yHhf!-Cm5Y_j|nVAylUF(G|l4IpF zlG?I_A`wg=R)jpS4r$Sf8dFWAZ4Pj*G!v$kAYtcWBr1K!+PD^rYModZf^nGX2;V4O zv`l&oVL44n8MY=}sTu!+l0Xv?&^)0;MDL1*6A?rSPFEMPjA;=4?r>BaL#?U!%Q(Wg zQ=#lo!At=k(JxNvj~Lk$!6~>kMbHx!ynB=Vb|w5isU`QA)3rrL+8?>ZfZ|K;H<0@Q zPqd5Vj%!_7RNAl)*wR)4a}oi6&|e{EQh4Wpe4DXjoQLqzc)p1qN#j)sEdh;Q?LnK4 zK-jxdD%Z>CSYN3{Ls~#j#K1ywIwlsOA*E)-l$m3WBQ{jphtSokgvWSb0)e8D@(hx(K(SJeK+beE-3kZ%HP|2(+VmTAH8gW$ zSh;=@lNu%spWc!12N34LD8h%t)5EQ24zGX+k)Q z_kp4GctAVu$7;=19-r2c=tAJ)l&c4G7S$R>Z{-C0yL^5#Rl@3lN$BDFGZNKe8U=^_EBOIookt(zq!zq!8cPBzC zb)P5hX=|0Hte2wF=?`eqHMi7q*qBAL~X$ z2Z_fNr15wj?IWrKe=x$pr2~t7?CDBEf8He4h&^LY?@WZGsg^Fj5j~6w8zcf~DkM!Q zF*O`!v>+t>2ph>7*;!2DQxDdU1VCK1g<}wL1ZNc4KcgEx0(lMiqG}EdYVxE`wYrnD zG+8i=uvwI=`$_TgFjEWl_@i(+J#BI-udzH)X`HE*Pg5%^!PGD=0Hryt@QbF;qM!W_ z^fz8$%55k51j^)|a+9d*Qd*>$42FFP1i73#7mWH!Y1|RL#y}888ykQ^AYuz3?W@D2 zhO!*oQTL+Z#8TwrH^y>Ne4!0;6}uUY(vO+h8r4zm`BID1lpm;qY3;~>njzH z)4V;&8F>Bu8+?3D%r#_Q&i!(TTp;3wR!RG0TQ(UYlYcLOQk|YCEtFKa5@obpCv4YD zQo3jhV~DHbQZTrDFnvnJ`hjM120B)D7PgUb$v27OSe``6_aw?Q;>x(cLq+qT70@tu z(In_qj^+*cWw7m&8u}^*p{kp)j*N1s9d7g{DZwY^+&Pi{mK$PL&{ypxDCu1AVvn_I z#Y?l|LRnb8asyZym#YrBxG9gJ zsJ=I|gW!7Vh*6XgBdyXXqjVN3a*yWG}Uq?^Czg&XzO1c+*0r7QpK&v zjSB`!(q8s8rjz2#ej#<05uHVX@+E{M$I|j%CGDpZA}4FE_-J1q!#IqHx)GwlDR(3~ zJK;?!U*APZrLxf?oB=3Envgr>aG%%#4u{mj87pWlAPr<4Dk=Y1ErOOol|}*vmD>d` zNX$NbyMW?*m#Mrl3=V{?ZF?#Fzr?r^#&$A>!d^@iUfpIRY2Cvb-83zT#Sw+bX0yob zahs7AWYLJbwRrR{I#YL_*EZ5KLjO7)*0)g-raN>mLu^gZE4G$MmldJ(n7Glm;s z2N9EBav>>=Yc0E!nnrP>sSSAH07z2yZ3S>tl~0*uvgm_IOZt5|G>wG0Fsx<}{YQZs zNqt&YOb+W zK+af}yM44JRkW`jlQ?fPg$AL%XRVAl7zpdtkua6{bxdd6O+;=~Que7bl>HH%A!E27 zYp&}kLTWRJBsxw6M&#rKBqF*oc7x89j8pX5%n2yJDg%rMr7Xj)5*Y3I%O-iF3@8mgH4jod7TEc(4MsTe4bD+d@vRyAmB zmdoV}K>EPo`o2s`8YHgY5tYgHJ3~RfO)}1owr!#5_>OVvV}?*%UH=i&uhN7QudeCl zDXnS~VnkSJC27IUt=dWhPU}P`8yVNfl1(L&ZM5T%1f{s>74kyP{EXOJ42fZHeAM2b z3^>0cD^))z5&>{4o(y@;S?dFKRN zDSM8<1;j<@SUIyX_8TcK9Z(=H%Ov~xdQ3zG6%vIp*H_Y#zYXNf4We=Om`J)q9Q{N> z&8>2J#AuI4lCjsEv$Y>$ZAvkiBOgx01};!f!)&A$nU5G~tr)2Gt2h;uWvy3$7B(s5 zwlh_Wgo+YXZjMC9AQZh4XKd|>jWcD&phF}f!rcf}P?`^-WX;E3caZdNVo13o%Xa7; zZijXw5tB$R;B?D2q|ZSm?hBNM(q-EM6fHNKpp6=Z0S}?v$gSKHpqry#GdWEn*{fx_ z6T(gX+s%no>|-Nx!`>G5+|2hbB&J*fN6J>foDTP!?A1P9&!DxP?d@Da8ikMOL( z2N|XaSI0ec6?}fJuQa8R6x3uWcQZz$Yfw&=?tmn<{T9hXLX13}k+*!}Vm@$TDY_Qa zN=Oc;bv{+u+EpNcjx}0{?6@^(v8`R< z@>MUb8<#aCycr&lP9T#|F(sAc-#B=cP3EHMvu4wgojqDO+xajim`1@(MXh2l{+?j~Lcs5MBCY-j~M;1M02+f?Sr;gmR)X{q?dWULuxo&pEH|acQ^inlS60 zUE!KpVCYK{{<+U?xN7*$eGi=e&I6O)-FC-wLL8IuoiASg>G{9!d+f(w4}{OW^+!L0 zEyKW#j&0NKfA-m%W+z_$>J3lqU+{^gLVQ8OpF41M^q1#;Yv+#0q=Sz%E;|TZCH$O! zNj3Ccw{rVylkXU4S`hhLA!cI^jgGJ1-y3~=;&1=$2VcAJ_!mC6<7;@ARKmCYBa0iGP0BQFHLNCvK05+t%U5 zcL|^U%*}TlJAcg&?%Zz*m21`&-+K=NhSQi zeT!RGZ@usr-~HH>e|cu=on9fHmhjSZZ*BeTPlFS71s^t+&1`iG@p}osWXd_OJUhH= z=|x}gH|)LVU@hKB##`czj?PeO_8V)CESx-W_Wn;VIr>Aq&nV$W>D=3139WkHJ?oL+ ztRH?J{M{qr-}vIicekE%R_?XoV}~z)!Fea%ZQp!{^QV_FbOd|JXA z+aA7RX|^`?ug`tw;5Qz5@=^3r$9}$jRp7|6OPBua-h;32O*v9O7Gk4>H(k8;=WRbd zaOKf`zkKk)xx4RzJV^K%Q_}u_UUjJdq6_XX-Msai?+NjSgx|5}zLjUZ)zg3OUr*}3 zrbPQu1`hhJ3Q$-HTVZ3-0+_mM>kfZgVD^&TTHZZ_MD-MoaU$Og7aw zm^P4I)V!!=N%PXSMa}C5``7gw{kin&pk&Q-N<`YhfKXCQe0PDZJ*!70l*BF`dbMl*!yQXbc)@9%VWe zc<}Yj?1od(lQkoVNNQlKUO34Wh@OlhU0E1Wpar`$?VbsS(E_-Y)$}B-zaO4#y`-zkOz8Q>K8|P2Gj!AOw9~E6xsr z5&ivxeC=`Frj&UotiOP4%i={aIIT-q$5Qz%{rxzm2O<41>?-Xy6w%-nx241qdnSSF>^|ci{(g8YD&_i zPRz|H%`?u*^mNdVvksGEYiS&q^x-0r5P)tO3ws z6SUX_iNCb_zqp}|myMQ?XXtpwt5yVDJFw1p0Qn~T>cjyv*C5_9bM>Mb(RMTL8syO> z=IX^&fVD`N*UZ(65OO%#gL+XjS1+zbZjpo~&0M`$kEolYHHcm_S1)$juzPIS^ET`S z8}_~p`?C#eLzJ!hTW03!h1Z64*|3-mTW!NqHf)0pyV-^f*|0W5u&om3WoE7(?_=X! zmY6y7x3B%W=9NF)-}UJHL;tk%jq^Tj|?ZA!yQfp@3_<68V)*# zS53L~S$Uh-FY7j1b@y!~csOw+N`{N=dz`oL9&D8P;r8a?Zf7ZY=?3~L95owvRY=umOaFzzQ@ za2$twOWLEu!ADo!fVzhi>Lu;)+iq3+8OR3cu#2U;qQlyuh>7yy?YA5jgVzlQ4-C6* zeOA^=Jhb&0Q zB=2tBvjY>m?2x<}{>`<|I>prU@OHntcwmvU;APE-c^+Wo?_A_B$FEkj;V-4RR(R}O z#Lnqaq@v9YIz~6cJ&5%}u9FM2n++ojmTs zgBi-C_8@H?b-b5tScj|7ziq@Hc{$2I?|=zTvrDWRDs|sI4fDY%Oz{T*++~IAcR41F z{~)Zoz8@1qQ;;Ql>Uh{u<{AWcB4n;!8hVyCh%ebNOnUpFrXFcmO4`1Xw!fqufZ2e8 zL#0aEk&<>4X6CDCpbXCTTc(KO$0^}EA;3x&kL*nBkKQ15Le*eyDy16jp_sD9u+|uX zQjSq$`z=SsEfd>zzg;t|?XOaTG9B2yr>RT(9`z+xc-e<*ty9Z3 zK%Tapk1ChrS1a1_cP@T21Q|I8zgnIUH6>?@4g0hW`#f?u>xz1RgTG4Zcy3im-9I6x zq;3y#7voneUdG>rGPe(ZaUK@1u|y3PPKqAc$!ia0)`FUrsL`)pHcHgkhH}jGm$pDT z#{6=Kl({BUv@Uk6E;k-{o~py-JkU*^@PUP|ug^S)WgRG&Ti!f?#$)65;c#M3Ht+>2 zRWjJW-pJ#5j5^!Rz0OJ&@)$Zf&Qa_Vi`y;~9!23abjfXu!2+I^t#HM0%j+m~i}#z< zt-MznCsl5v31&jN(lXT}rAqPAgcu^tc_JC7mbp_pyX}s zR7ZL@(j-#a(e+5lYuZVry38rnWv*U4jK2#dj1tCNy?6qDDMJn7yJoIlJdYe@twFqC z=IX`Ik)xb8h<`P6^`PUs2AR@-OF*uQiScx?_~k{`eUw)~KvA z3HLP)Qj3@C$-nxNjJd3_VDZ$PYaCA@$J)Fm$z1tZb%545XjD(bFY+I!!wzyDGqPn6W=UUO4T5!eQ6_jzvLP!JK>k&AqE(O$RgiM| zP^}n}@S1G*{A~pQ4Xx2%G9eRf$Qvev(WdI>{VK>zhXu0gG*v;`Dj-dPket?TG?aW7 zfGlS(KPrbTC4_dxu0x+H_LoCimf&taP?NICep(g-(p&*)1td@bX#=F&hTulq@5sQsW?2BOPNvd2KU6vW{wHerriu z%W+!WW45v^st~(Iy2j|=!`*-HOK;`N4Sr2d$2V|vJ(|oE415>Pz_*QZ+4h#DRslb| z6UeO3C-Ym|7h6ES^lkz@Wzckf%n#F{uPS$nugjg_J9gDyJVO0;yg1?2y&H|xjjaE&DLY cNBKxyMX$CLsKKn>C75i+C?nWPJVpI~0c*v{=-v}xqihj>ib?SYqw*bkNuVWx|J4#$_P@Gxt-`e=(2_t)0xb!&B+!yT zO9Cwkv?S1yKuZEG3A7~8k^m*}k3an54?N$`Kl2}dn9o1|8P-3D#~<$ZLKW&HG^`%o zvru`RyeF{ma;5s!yn~h6?dgR6f63%zv7F52CsWyUvXIZ@%IRWBtvW9<-VoB=twk*Qo*rX`R-4e;8-H_^Y&kQrtDH{OkgEoOqABxyp?RVTFFD}gu$qUk zQYd96H=PF#;}#&UP0dZ%IOY%GczwyMLQ?+45`U4DzeAVFuja|}u0mS<(a52UbZyGQ<|dMpm11%( zwbQ~YfI|+VBH790WPU1LNX?{?7s~`)^Ex$sAmX#AT4oO0`!3TG6a^Ss>1pS-Z#-I8$Fy&kT&H_j+K{#YF z7T|SuIq5e_yp`wq2p0gidbt2n+e{qL*dn-;CuvxopBuz$9tII+dX|?wJWtYJ6yRz5 zX3KD~#9JPQ5oTJKhY6uESwq9}kPhNC52FY(J!ME9W+eS=fY-SKFw4Uw5^s5kAk4Hb z4_ToxS3|?{kPqTD4{?NGOhKA)~mme>> zeTAvJ=S%$gjr*;!(PVFAaIh!RyCE4J-WZFI3@109W=woz7DM@9yH zLJT0K>DON@X`75YnD1aTGCV$-Tpu49AN7e;#R?xU5n5JuY^VHlW%n}Tfal8vx2G}B zk>0V`#>iLP@Y!_?m{(h$qML;v6b>WL|L2PM|zL$>6bCYYmi2%!F+C}zml6QXYx6v$5F4< z@uL_vW=iFBu58B*uQTz*%=T27V};XYtnhjrPg)#zoKwl=Qgi94Q_88Cb9EW3Vo`@C2o(I#(KKv?_ zG1-W1N^aA-h9HP=&+n^bxRG^*>NDfN-CAy=`Fz&Y=SvZ8SH0PEDpx72FXk%+6aR9= zFRF^~P30!j+1^w(JCT~)X6v0g*Qw&E$#h>fD|!4I(k@jIXbqGBS@-5K&)8Yk_4sPQ zmZ|-^35-KA`fqs2_Vm?`fv{82xSRf)`HX|;zoYawKI zHSq0cWwqpEA z|0%fd6vWH`Ub#KyWYs1c4`J`NhTzr0!KomxU;cnj#+59UsO?pLi^6T0o4U0XP(`Q48m z3g7qSTh`yW^0yy<%}wOw9s@Wn=W;&+Vl)AQM%B8JqR&UMZCbN~PG=8pHy=u*~R-b;_s?}R7SQOYgnJ=dCy=qqN zS*+$CvLE@x->;Dq!v{+ErwC&ncnEWweD>BtF+WpG&2>HfJm<(;&d-nbJ&eE0;wC@Z z0fu)F^n zrG?F9`92AHTnku<@;&=$(xY`t6*3@ZXx#=n3-LFxzbVUiC0vs54-jTq`q3>h?;lAx zBH@Q5Jg&zl^AGujgp&wEkDgXpbLC<=3(lC&Z$XFkI0g-3c#njiE8#y&ctXN|MVK;~ zMO_m=gh4mMB?-49%yJ}!@BJjaR>J#B_!J3uAk6&ViEq+dif__;7w8rDu2XZqdyMUw zQYDq`DwQi!nf%tZtJju6PJhh*K^}HGOi&IdgNGx*Lj*irxOX``?e?79Q7S`FzHas)uP)?uIP!}B zPvuqGRoYrAr`VWTo+9#CfjqV#4~9z;K2yRkK$y1W(WlzhvY83L0t>UHN&y*3yS)Ll zjsq>~=*Itn^1xyg(^FfaB^0%`5ZXT6j(k=kpC^#dQ?fTM&zDxxmGl(W)VBHc@Ey=Q z5%iXeOnxQdyBCA>ny-w|7I zf`or8;nO92qS&Z}gkL(}(BCTIJ0*OPgzuH`#S;F3geN5Y6A4dA_#O#QOZdwYE=u^L z=p0#|9TGkt11N@HAmOVdyj#Ng{S5pH34cMtZ<26KZ1meC{0j^$N$)xde@w#HBTUE42SCy!=4I2MGKp68@~fe72l4+Q;dv5XEcgo~yz~TvzevLSNtlZ(OnEgU_&S82eqGMZxpjFK zXr;l+i9)+u!s{g5BYAyG!Z8WoFX0Umo-cJ5m+<}wKPBE=8(5gFlrtQOm@(2u(8_|h zF39PBq8}2w?Hg^jn=QyAhdkc)Ka@vhPWlB}Tj}ejkVgS|TqyNDjWGL(4v}FVVd~#Y zdyT$bD&dz%xFX@j65b)<0}y^nGIqwbxpE;rQBF^QHQi^u4Yarpc%$(45ee^y@c*gt z)>Jy1+Lf7OkF9z76nMA{JaG`qI{J!~_lX`8{+7V|0Y6cN^jP;$;3tzQZe7l#{q0M$ z)l^JRXLdrT4i{YR%Oodfw_|x>YI1g4l4}yH1olZ}zNf#X$*URJS)Kp~h(n_Y7K9l1S%Y%gt=lj!GGpT}Y zLAp&?#z@E0SaT@>7^L%Ie!>8DQFVT6PIuB-m?W!$P1fWGpwFid3li=*L}WEvogeDU z)P;?gBp64Uc&>T7<#OfW!)zi)R$S|L3f_1qbcYQ zOp2cPOHhAt!taJ#zgrS$NuVWxmIPW7Xi1XX9LE+iKn8usYn*LYjW`Ju^lc89^JDMK230r zLHjiM9Qa5^2FIfDVYtxQ7)?gvy#ukaXz$o~JenNaGOFD&z`4m@aZoJezZSk=0v`{_ z!AN|4G#P_Op7qf<7h>F^I{Lo_ePNEl+&VGCbW6SnZ91;0yp z$2abfn0)ka`2T6*muNFw5sgLZ&b0nb2FtT+00F=g^`hUoIKkTrL#2&dnTcBQXr6)T0Z?^lEIOI2bQoDa?E zNTJ90F623vzA&Fl_heEf<0ppYKUu}*;K6XXGB=Sff*Z>NVXIsiU3fq?%>Of>w^|LC zO-}KAz8v_SInx_T?L>2!+%{IEv%3aK)kC28Ly z)R9pyKD<7WPET3)KaSitd+W3LiBuM(GPp$t4?XcpE}Pz-7N0=4f~&Urd{UMu>|8<9 zW*IK_hRZ#bOm@mh)Q_J+{Ae*hRhcZ0(d8t0>;nF*=fuWJI$K)@pM{(=UOZh&7q_RU zR_ipZmrJ~1Z9kBbemwHUNO5u&*XAb6l_LF1+45(R=TPdBe6c|}3xs8Ib+B8JXPG=1 z%KhmSi5fpsEZ@g`e%AP9yTy+?O~=uf+h??l64{LSOrqb9+dRkkHR1VouLt@R)c@y^ z?hemr8gwR8)OFHFM_PV4@AeWE6n`jH+UCpkUT*`e@kC{2CS8o?QWIG;FDvu=yrE1v zGovYu=HX&Ag93^Ud;$60=M8U8R0@TBv8=(nM5bTVutanqP>w42?Hb-&DfVTGed+BP zh%m7&Qz)dT`twD&fTF!84`0%Fwq8v+zKpp0eL0@)%kcqE`-)1#PgE(NO+zq-24(yM zuP;-YqZ!e*M5kdLJ?KH{N3)gED4HSNlREnSFxpbdwp{cr+tCJnOXKLyFFm8cBh#a^ zyGohKRF=)p=s_3q_^p>nO{ZB`LvVs>%E0*Fc^fmuGQ5z82P@;H%<#-I{@yR+nzb%p zk9Y~~T>>?ma?`v9X&&+VCT60=V!k-aDuFuEa2T5Oxn|&Kq`F3JZ5#MkESzjvkjUc> z3ybC8p(C43qt@7pEE?&iDQT=xPAGbDOWPL|Ci{zNxbDbJIzGqR!=|0m zE1AWoJ}z?NkCM6?t%&!X8b)m-nJz_&B%6KVNMBe zEbGZZTEDF1ZFRUepWl}8+X!*jNgNTG2g`gW;&clX*`h_KXW$YpHzl=?mPuU7uN!&I zrN;~CKhlG^M{UbX*g&`kH=B9QI_Re%O+W3Z53lOqiK6v^G&WQILGoB`vY4K8`cmRt zOq?nb0UG)20?up`I*HlLv~6F+%QUBDP(?R%-xMCtLD6t`+;0`eI0??TA>V8`3RhdH z?P=**NJtTc2lYx!j91yTjCN+8Wb859VpvjZB#4y09L{^uxbbbSIh;b#|n{ z|AW5k`tTqwv#(F*(xw+NjG1;wncd*$yH4jzox3SqB}6@VqWlQEg>um`h6ee#Eo|&{ zP3d*r(bwzk0@v;Y4Fek1g|uJt^FK@HPkDZsd9ay^y}J)IbX?D_LaJ1%vK9ARn5h*_ zSNES?M6a2^P6MmqGqNXPkC3e$xL5N|*2 z3zBsct-Z~^YUU~94JInpaoyeUec+CztNqQf4vfD!?SyU*eam^^@%t{1Pr=vb`A;Jc z>I40j(VMch0ZP$C86H?h%u(k55IFE3UR@qD8LN&%8P_)U(Ki@NjKRt5SbU2SY7j;m z`WgH&@}Qr=6~h06ny-Es95XgzxJ~uwF!P{nexh;6zveHX*(49rU>;58--+1p`oUwH+~EfJo7ruiABTTHEEA@KNfhe!BmuOntyt&8^aAWiaoVPm<*#|D#q zTZSV;vEJlBBr%X2i}aujRX%L@jwAB_mE^;<0qTO0fA4H6lN*3b46Prg4ls_{K8R}J z04=Z|?eN<Jj@~r3TZvnPA<5ah}4u2A3WLM0piZ4%pHPI@BV|#=NOVk2~dny>F7Y z@kM(MaOtbHqVo-@C&&-#_iw@%e={H2F8DlZ)P}}~W4$AN(W-o^}zVu?!l)J%Nyo5%G<phfM8jSWS_D|`?ZSuPS;uBx&vG#ew+m_QDtWKCy9jZWC{#Nujs2K0lrYx0-; zNQd>^#1Fn{Kc}sATkmOWCGCO2>%XGYD`k-q5_maQSW7m%}SC9`TPtfB- zgtsHjT0FDECz+gsLngfh&tE79*U`HHAp%@7>b2`aO_(gXaQZ-Z!(BCD+AJ4N`(nd4 zOT8Y0IHkZtvZDP*Q3nsxWoO(pByQ~g;eK33`-LLjGlDqn`-ySOgE&8}(PPrf_<0=R z<5hfmM+R{|y`zFSO^B;H>>J1y{=xOz9m{~jK5YfQ`F6)C z_-1=p#qZtxZSV*u9`T8{TJY8g9(;ivt66@}l{8x=jV&ATo6BULx=7L`B^}zNerw0R6_pC&b(@|*n7Uxz z6bPwFNk8S|d7U~9bl0{ss}nY@X|rK9BWY(PZIf{d*5u2lugk#t=)s;J^xNAdlHR_l zK>FJd7uW|+WhJjU!EHRIByF7wfB5wCOoQ_LNZKOn4j$gi$*J^qJC~uYZ(|(x(%iWD zjGN=uh_SICg+2>$bg{Y3*k{HqWLzcV?{_k85#wfpIOf~QxFRz)^f-Q8%D57r`7m+p zmzFUO`yhB~LH7ZS>tftob=*qEVHuEklnGordzUhE`K$)KRwk^cdc34xF^%fU)(z)5 zwRKZQezbWNe(yHF&juc4-efE|G{M}`rm~VYgc_s%?gSmHzq^Fyv#Z9i$xZNQs^@AP zub8?^_TV)|J^y8RKIUu8fpuxegU<&o`@y)w=4y&-L&C!fAX*+?C_LCUY5N1pqP{Pi zr(R5a$YZypv-XCzdk5o?uD1Vssib+Cq;c&Haj83v^P8_;E@`ijw9LBze9GVQd?jGC zBaQQ)r(Pj6UMVzOyKeJu&cg!rYDxbZNpJbL`8LmczIvUceZ8c$cBe6~Vf9AAf0N)_ z`7*D@Y1-7ACC$|h(pcVV>*N|qbFHMYZGd@H<9h0Cg8O#CwdL2k0=YMr-F*F41ncZw zlGc`o`7|rfyCuJWmo%=->iG++>jnQm1b-Oq$((r_&L^-NI|7?T-@oR(Q=~MR&Q0MY zMgT%PBFs}b8&wD7TUf#Qr}rX{P-SNhO?js)|EH15GPa_Nn}HZT|a& z=l2WGwv4oy?336}1btap-6;4UtifknZiN3~!M~{npSHFU{znA=qc!+;>{H9n#|8i9 z8hr9&|HwaoFTg8&w+Q|x1>cUZSzh9WHC{-4TJS#O<9VIj_o3|#=mq2E&k0`R{&~Q@ zx|U38OX!5VyR{wryre%wY_RG7E4fO^oOL4I5c-`j0?&T1KC@T4w zZ-4efzV7+}^Z1s~xkqrDtm{GRFBp%G;}GNENbd&I+f>JiobMGncK?KWffqmYVJOn3 zjPD1I{a~(8O{WQM%CHNG$TR)XQ`QeiURKukAxu2#SQ}*YJ;H(aeZeD)dg#*lp${`M zA`S8!(DBrdh0cRMuGQl}KOd@t1^GWLuzr+Z)xUKWlz&qsHkRyZB;f!ea{jr{v~LOj z0%5%Pr1z;fo?y65abG8sugDoY#@wfZ1tS-B_FPQe~mEf={Nk|O_-^Rf1;jg!z?cA?RSFvd%?B+ z4Dq;j$28RQpsw50Ba&uM4gJ3W&-Q`FE_v#Yg8Qc$`fNAEr)+BJKPGAZB5ABX5?Aw% zv~06~6}%?|ugSO)`VifSJtbeBIs_R~Mt}G7n74#uL^HlKzdLY7^hH%;Ow;bD5C1?q zymo=nsu`dEQ-|Z}>6(3i4_@BQ89$>VT}TyHk?pBWmisk0YJ#&5LW44CQ~KD}0L~m| z8P76d9`0e{<$o|vZCWN<*H40hcYavE5qLNp>C7UCVSD~D?UElH?nCsIT|0~QEI=2 zYvP6Pg~B)KHMW~I>Gn#`tfTA?nt_Z%>Hy{e884Q+w7zQj2QV5M+4QyaxADFv34em$qlQ;2t5k&E;X1>EqFUpK(7%>h>t1QL{%> zwbw_R=I#mDy`Q6z)_#nfeCkc|Gjg)FbOjRA9vvg)Id-4r>De+CO}NFe5q|w1_Y}%Q zTid8SE9=T*$@|5z5jsCxpIu02%Vh2MiR1%yf0FQH$J@l!e<(Za6hX)!tWFX9Re~SX zcK};0u*PFgJtJ_obfNvGI(*rz^=SupIy|huTU$+Cz*>&K7O;ZBntk6|U7$^0hji^q zAIQ?{D@@m}B3ZnbqEDZ?XIE*f7dbG_TUZ|2>SyWvb*5ZT_Y2@l-zkrkJ^5jNl-FrU z&-QT!zA5`N`MsOJjowl2#Is}nXA9ohg2#Oj_GP5!K`x}hG^F9yAM@-2j$41{39arL zeDcJRKs@`8U(89cR~IN)jSp6a|ECb~_z?hIp~Y>G=dxyLY_78BD+mOk9ydJ zJee=D*ZXltJK?o5e%Jzhyl`5cKGTemF0^56SW#w7ui;!S#$FZle*SZT^Hko!o~X(r zmMc`ud6+Ix#O??damVq3rn&FHxOsluTAerJ=KFEx4g}*C_;KrWf6Fob^EBT8;?w>V z&LP_IlPPb&8)X#mrm&7;&N3t&`tzRxeLFTV@-y^F3wrFO99j+JI9_|+!PXVuGj!|f zVjGsany_J~t|k%JKpu5(mgl6dx|jv-(@o~N+!TzPL&_}QQYVPx;hq%gv+4{o1K#$MOxwQnJ6;-T+sPu5=B_A~=}uC2AUopvN> ze_@p&9@^g}g5P|cYdVZ%&v+ zmS;F^0l6K}qM$vTUy_OI0quHdMt*-lWHJH1BgTwTj3IUszBblC--d zZM=$aqu$mIwgvT4rS~i&?hWF0pm`gf_-2g4xRT}vHrRW%p|{R8Z32gWkFYt+{W z%jwa~*#^lb*5%ehmzU!=9^l z&j2qCY!Nf(>0ymeyR%I5!>FJhmSfC>3yuDmu1nRo?_-_zP1)kvVehTr*?v}5*H=T? zHt$FMI&tq=)YLytr%V03UF6*OTmcsFBXU-izmTR{FWH_szBDpn9kn^@$?w$l(379S zJvQ=7y?mEbPGg&&9>1i?_DB7BxBNa=+6wotFm5ZQ$7VC7{!BVMHJ0zq7k04^r(Q%f zye~hTFS|(koURAn-sA8FdsJ6;>M+ab+LQkf9;{t@Gs4sj;?mAi-``6d@Oy)gYsXW; zddm9+X6L^gE06}inct0sgT@C1&*n#d?0U4p_0)$2_ofa`Oz=3^TX@IGr!f>4gcj zF|$W2@Cz#Wa%wO$#|xpTU$aLmuo$WxjgXrYj1OZ^L*EDAI9CyBvG#GPm3 zc+GLNn91WkSKgl{Y`%rXQyB-SVGArwU)tt9Uqi3m#^Whk_!7WPp9B?VE`UI^tEGs#o3hM0E-jLlM%B9 zFLGLJVWW9m)t(wJ;c8DLHzh(g={qdWrhIW5H_FrHO{wyv_K`r|IxQS6Oka15jf@V8 z{0_7*bL%gX#Z4jJ`|KyP{h6H=^k1a0#Nt``_hxZb(7+C|uuX7F;tED&u++j$$^7vn z=^kuhk?CppVJPpCJ0gS~VqrEHnT?k_wJtk^A7AGyZL8h||J&z^qXbXdm*%rk36*k`7 za828_M#7G^tE8ZkF{{Q?##Gn+Bhwndf6Rk;k~;ivuQSRBe&yi zJY53#92$AAv@mmbocU{E@lN;z+!0t?bArVin}uMfFlnFM7ObM0d``4DHEkuj)4)%% z@T$7ql*wUTf#o~74i42TP|SwcQ!L!-v$?XZTRYRQvT*azb-`a*BL3|CvY zwocW)5$xq%=C#J+$u;uvfWx-4rg9L1Z;?{G8HdUl$H8-1#Sue0zP*B90{Kg+`5 z&mc9InY1H6ePhg}CU)XI z6}K?)=y`P?@f?eTN}x{&w09Rp(>d4T82yOuoK00q+AFKXfE=O;|@-K-2wzr~5cMMehRImCXfxAA%$fZLR|YafA(x6|>CC{;GE z_q{2H0h=aPnZu1vIP1W(^ssgCBIM)5EKct%9PkLgE?c6z=UY7bG+JLw6=pM&C2PkT z;BT<_zARiMQ`SL?6UCX1nO*u20OvL2eaOPJYXJ0{uzC4%88 zWSL)r_ahyVn<2-eSgTlY@EGO>-2443#;V+g?~NvKQM-SncQBGjaCXKcel^kE-TKXX zeUF0kfm@N5-+C-8V{k-aY(GzZj$>eq?Qi4v?&fO?CJP)?NZ^(?8Hf)#j=O||dN5cq zYgJzm`c39~qtPCjYDRnfG`CBd_sbj$L42Y+;j{|k!zm%im~*Qy0f6yzdV=HT$kbF3 z16m7XnX$*{4!U$2(psdd2HO7Ix>I4#0uEYimDsfo%5W*xxo6WDn8PtqF+W#}xQA;X zT=V|2VU`SItY)jIUO-anX5!Vdm;g=H;2eV_if$f@4)@`x+de9%IUaJM4%`8r&HQ%W z63XpR_>Joix&9)8wNKV3)^+Vf$zO9=F6XdVFZ4gOT*Y7>bT{C;HL-O=|3if9;im}O z!svTQ(sF*%2PD)9(=BsG!R*tI=`vImEagv_Io} z#>CUl5aY4pp3lu>cX5Pk>zn?CG)%h}vJ4uXqi-P%t2ObWlV5{;maD*T5bN*&=*8C^ zz2LdD|H(RRvM#d$J`tmXN$uHj4E`Xs*%(jOMQdH79(+Ue;6iD4Jm;#Ek+2@gN*Nj7 zuG^y--%|FB>r@-yrZJtZ#a+hrk)pvRuV_x*H>>4Q$CPOwbHkkGFKutY0BPg}h46O6JaPPX-yQLQ{PuRMet6O6nP`CGNj-k3KEXY*mDp^>w zDLr>IK9~q=SMZO=wRjzG<^<%+Ls`G?l$C3nqLYpDtX9j$IN;0fQ`C+jxR%E37N7_C zA?p}6<4647jj_f&tIK9`>h}f8BVnR=7?QqiSXISE^dTU>=O`576 z-q&jbi_I0V9G5pM4`!uH>-~J8%i9&j3><3~^^7gbg?^j&0>Np%Y-HLH{DWxT^$Eez zRL0)x*iYgwsGvb}!HP3%3}1?6J5Vv{7Yg2m>0*8?Tk1{24IJC%{t`c$F6!AxZc-+L zQpQCBkIcn*P}(pdW9I_|7Mn`L1)+6IY36~8EnQh8F-uN{mkxn}U9b`<7E`+{vs!MQ zmTn0~!`xZXydEg=1DUBb2S?V2q?P3ofj3wV(sU29`R>SIRc|molbYORhWUoCrGCD4 zCCS`{pqvgCSm2?Nt0tzbhuCz!1vK%8N_? zTwbSJX<>RkC$_q%o;K1~mdIPk8^eu}^wPMbxBt1K@QGut+$i}7>;tLnyu zp3dV`fk(<%A;eypNKwO9v(FDiV5Xd)%RYaN^!X3MrYFY+;?YQ7?Ub`77M%ss+Ix@e zFMfiw&E}jBNuTjk=`)5K_pK(6X0w`RP_V-O=x0KEZDZQKgE1U2NLpt&eh{f2-SgUg z%s1bKF>aee3up7UmJ#LW`1cpc7yUFmPUq-}SI4bDU)kAY4$3_P+33-@NRIhpwOyfn zI1c+If$~{yYvx~&Pm{5XNVM^AzziAoilSxLWIVFhgin>WJ05ZM%N>vWmi3PM{~f<~ zV?ASm8IOb%7Te4g1B9EIY;3rU{r75c^(K^SXr%q&lx!7E>0)D86vg(9q19G{Gakdj z8}{<`s;Iy3=hM-iY+)nnvZT$JAJD=9jFD-i;_%7kOxunH0bT?yt|v1XOVX7$r_g2( z&`o0aY!A{H`Q)Zz`Nl%hdF&V9>owvjoMYpLs7skVFAVU&E=CkCg2-|I0H>}yBaKA? z9NXuaY0O<%kcRmk5a4R~#!MbV>6#U2$#-#pTbnOBJ0q8l00&)3TuV|fr#C1^r-SQ@ z+bl6^n|oj*xOBp{Z(S1LKvA^w@-=Q&l*d8!IBRQhme%8(R*Q3RJxZz^f9x;B^If!|C$gb?;~gcQ0*Zt<|#?0e;hVLLXMtfnx$(vj~*PWbIhz z*Z{^@Z9801GyO9I9ABralt{{ZTm!r+MH0N@8{kzbli;mvfLEnZf_Fj#yeg#tw36s?4aXFJ5 zs&)FmAZ|6*16iZA2b8Oa`g~mDngQm;PObjGDc2@@8?_ZQ7#qS>^SU*{eWLkw_k`5l zeA&-1YuZ>bACkEn>s$0*%g*hSD3{tcU}bf&-LEwp z^L28cqU~$~n}x2Vwn>c{9H@=)Tg^JpYPg?X!zd%p?es$lWEr1=TMx}kZl+B^6KIYJ z8C|rmx-grEW8BG^!$)q7CNcvKfvi6AeW5y@+xiX=PwPMEUw~RPG!WuEdRm;?a zX+E1|_`uq*rh!dwOe}HULgKMD%y>JYOiv{;Qx=AGVV%a`ypk~t)`S^v%8vtjYVGYBvpPu~A7#8HrnIxMOJjuhbu4E@urg<;*dDvhlRtobq?2f?ifFwc`YHP(Cy!weP@ za2vnmg|%P8s}GgQ5f4ir>%jFm_TZV&!Fn)p_|U}+kL$YihP7bA#$$#HEkmpUGY%&V zr&4s_?XGuX9hfjY&w*!Z;KGi&fi+-FzoehzvMYE-FR%toSZ}J3n!o~XnYRI$25Y~J zcTVCRq0+j;$1) z=B=kDxL60S#%)Yl=Z*E?Aa7~GEHBoB8_}q0<5(9aj$L1Iie+SpwPC_zzAC|PlQ!0a z881eCtcXKuriz7stOpyoKBL7IY3%t+d%-%e&J*1(mR|BXCsSP>tN|0=lgr2OK9ydj z(0QJs*JcR{#@y#)%zX;%CHG?I!)7MOMm9vN_O_Gmk)S3}m}>CtuG206t!CrzcG`3F zt^4tNH*RCgJ~j64$Xrz$7Q?6c7aLmz@2{A5jVM#Gw^eZ6(L&}uC@1e~u$=n`<%|wS zH|q07?o*DYkkufRQ13l25}upfv#UueE09{GK0V#99a+_v>2k+PhI4TH=pNE%Kh}Z# z><9hWQ>MRH{`gQL9xaLWN=Iy{2C?9f^>d(zxd=SE1&bHS<#W66lA5tSAwM3wN7xv$i*?qfdI8+smDPHK zlW;Ejb4(Wpk31_voj900CZfIL`Vc~FXcRM`5kC2egC5Y4=pd^SXA<^?!gAPo zz`O%lYo=c9xgW;i%vhy7%MzHyM!S}8&bI`w>A7cImV!6wGyHc74?!Hx3AttU?S~z6 z;ynj*a2SU(@m8bn&vXSiJJ!N{mqx*Of2GnU&fizF^muk#hB8$!mJ4%w-1?r*q^D3K z$d>xYJ79-`Py0F3>TjTFZUYHoA;>24Q_<9s@p!L(cy(M_L_)_P9rgAw1L=zOG^G&CQ~0K-f9(wbN;>kXE?m$?883u=GmhL=jlwk!PxKyoTbwNx72Pt__yaz zXgd|=fWeT(+}Wm0IMU(Ew+Swtz0jxKVOtiTL;eKb9;0A?z&zL{x{!}?!R5}7tNH`& zlB*tyfJ~3 zv2lrAxk;P_&dFnm22^Fwjt4D~i(}6W2iBh1JM1fgE3)?6E~k*Rx*%CK5lk~E7$NP|K5cUb)ht!mGf?_UgtiY|D0iEp zWTtv{@z@891MLRm=c&j9#@cu6nDpyFH7@ePx`%^!JsSC)@w&4a-nRb)R|O%VD6XIDWcUwfj7DL zr2BWK$88I7>*Q*y)@9w#6UWR9%`qAmOLQK7FzoFS91_W;vQ6^T=NElcyGqTr8k}D| z6LR99Ko1n0%BX4>P2s4N8asIw=rwB_&t~00f6wOk?xttzZEj5(M^iAEF}CtKK7IGS z15})UC?Qyn^!-{u?Cv~-?Sx~RcDo*_S1CE>GHv8M8!&w$|iTCvKyaO@Mw~j0kO87iMoDo}R;@ zGtAxf5a0GESi7Tas`?TScK8C&upf>=b=m&~ewvJ@;X@$~;}zlSkfu;>3`){u9tkXZ zlUa|77>&dN$6{`zmcu2Yhhw@Nqj?@y#N~;2q*E!vr-%<(l^A#!~xGK!F{L5 z>}ajXJGP`#W*o(^r*`1HYW2H*ZE8nfYS+m0rgYkWrTYUvx0CWpE_YhhK@_cx=>vM6@|v>VKQiU#QGouA|^*f#IQ8sze>YN)(3)r3ty^wFqxQYOvJ&% z{iR$spK|XR`{XPwtl^`7peCVRYnm|RCSzacNCWjg-NBCQ)8=T1h48Z*xAXOVvE*2^2PZ7XdIt>a zRZ+;VB0lsmkO^7JrlOPp@Y$I8@6vI+VHVR-{g+&djIWE{sL#s z#vJDE(MUWAA7njIJLss1ZJwU;h+v|&F`Dd;M{HkN8;kU`qgRR!)6TKa=!CrN?+|RB z|J!qZhn?ST&hL57@A=N}1)JYbjB z@8R-TW5wKgMytV=K=zzQ{(V^|Fk; zaVV2?>?K-0&r!W4>@@PYykW}Wvm0Yb+?F!&TptkFWsp&yzDs)ATH7;Oc|0Gm8#T;_ z_<7x?HjQj@l306nyS-PZ1!CT_Vtczo^%oNP=`zfrb~jML=HLu=;JNn9v@bwjclv!J z?54f&RO7$J^7caDFABl+06a!o?$$_|j=~0UOpUUWK7j*h$`Wx#1_4DJn;1;Zn`Er>L{9asr@o%0> zQ*iY3CXJ)@Zxpvd{66esLHwAFXWO}j@lNy6YAN(y3?4r-U+b(e6X@)2z&^HMCW~Sf z=(9=>9Ha~{0c`XBGuc|5V19Qx@jQ=f%XT;7oh2{dR@@uJ`*9B-&drZ>e}FhyNsae9 zbRT5ATs5dr0|YPHpTzYJ;BVq8B=Wb^Q{rpx_fj!!!f$L$u!hO~EVoSJjWu&BdI5^Zw0 z3=?S5Uk;j`9eoos3GVXiv-Q3%FYBoGSjMuy9QeySYTAtCa|K}C9lG6N57g|X*}56+ zz^yHNVjyLF7EtD69lXVv%}nS~Q6PiO9nta*dIsURF=coq{?-oYQUW&D!Dl`o9n}E0F1tW?%9q<{YHGFNgYjuMeoYWR?Z)GsTk=8t znVNj8{Uh(Q9qTKpA~rhGdO?12n{f^7>vh(riMpe>oO&&|uo2_8h(wVigr9FU~a`umGa{{ojbt!r<7dzu}ilmG4x)9~q{PFIPv zd-__uoO+3E;S{d<;q;DHTFcv&9YdAOdR%cVY7_0($E!PHC1+>YA8V7}*LMu#7BFpB zpbuAd6cV$UIh{3WbG&m+$3Qw&kYh~#O+}+yguk@|Gv0m_glJ4j)|@iE-RcbVFIP(G zrGK%Kx=vmJy}HimIqvjwQ#R1s>pS|hB}X^O_YEEBC~#;DPc#jtax)c3(D%hc_>CPr z3`Cp&%(4)6Q^yee|FDu=sL79Y^fAiO5tv<{VmWW=(B44MJD8)mr1?tleoKe;!C`@T zg5BJwXPQqzCom(lNpyMn?hxar;mEU++r}PJ*Vn5+>r=1=#>FCxoUDbtTF2uET7PCD zUDU$RbY7$56WcNcqcfQ8qB2cgzE;C6aReHL&>3n%Gxk8aBPIt`Df?5U#|`~})J z^m+~J&2mG_P&PE*VDhUJ3Pl`v(_9Xf#JBq!HB35GieH=AO{uKBrTQk5Upea!FATSK z4d5ybCl{GiRx+i0-)!qG)E_i`xZYgUF0aoj-jqGG$1F_Y~8Y6 zYhVQqzf48x>ho>IXFA4q<`R?n0)1HHgqe(HbbV2uZVTY>8RUcg^tbzP+v5egb_d$c zBgo-P}s>cj4J?aHR9X&0P8 zu_x?X9_)xtPjmN+&fkLT&w6f#Ijr|q;MmV29h^g&*&}{*n>k~9C-1594L|#q_uG+% z^L@^nIL0@>=Pl_1PDtiQ`nSxF^lzCT>EALx(!XVXq<>?6)NI`vbGgC3xL%Ji48qfs z9|KOw%YO)8+}CI@ACHfT^BU{aVl={OA$+9Ev8cTuXjw3i_evi9&GWzl8;)8<2JI%7 z;g`f~A;S0je0iERw!#slw@9!3RqnN6IqV-Ov+xfo>%suRC+tGV$x*GpegL<{!l;wKC z8HD#Ia51aRn2g;l9o9*kGUqScIJ^hI61p3%T0Z{?nv2xn6n%iOoHros`=%Ym=m-7^ z=^vOd(q5`CUNqA}zi(%}@8gwyx6pb&Xu-!8Tz$abSl`mAKW)UlQD=>!j2Qre*3@$tLizu)e*{gU0t1ESyt>k>*Y)p zDP(Xh8s1ekJ*GKFxnoJ)2cf$(^~N;agoAzTq3bj^qFjAJobDv8ZVhU?Fp|seGQ68> zDOA~@{~A>T`Ldpsx`!}KejMA51vK1%J2<882{g&w4(ET)t>o<1@yYMMvG5&025tA@+#v-t_Q;m=~KrFEP8w*}}n z6m${`T;>c3m*w+#oXAPL6MK@WLLxoGbv2n0y6_jcaN|SNucO@>*2jDGxb;2;f8bd< z+vn)0G@H-*dPyEHufipoUP)_+d!=7q@@8xVX}sE=&#>Y!U|n9;(d+HKB`2P;ze-`Q zXsX@}>y2XTbcA1H(_u_lgjE_yXA5?0#(dw-^nJblW{q}jATp#ax=uOMEl0N3tC7S| z>XLjBj?6ebbme*jVVPVVjAQZ}0qd#21*zOhpdK^+Lx}H9^jT`Y4Z8{Pqc}T14IgOs zj4t{9n6b^i`xH0-TWVm<`20*QUIU()*KO5z_3SK6d-x{*AB3E4ryNZU)UAOGhOpmm zJr;8S9EYO9-;L#&^)woCZGtp@k@tr{f2;vq8v>_J?hOUL?8w*mpf?YMbk8}5=3jM( zk+27AVCKWdo(fvbM8Yi z9mfdW9&In|ZVd|I93ymlgBgrnm|+cuDa(hU&)uG$w+md0N9WIZ(}0IP1Jem{(A%(c zvoag?#tH>9;ViIP^pHvFk@YoJ1GoBp6L{F_aZPC?Cj)K@$5>CK=N{P&b=DXnPPJop=VROv{yPk2dRqb=A0?i`Ek&&XGLxn zdZhgc`TdcqJ>8ii4Y(b@vu@i|aeJz7aL_$x&v=}L*`6Ah%Uj)L+#<%sB4buIjO)~K zZ~-Z@WZY85nXPmno4REDGRDi+IRJheTaI%V?3U5Quv2d4keD-hpF|n#rwcZC-}3M} z`3Ak6+kV=S2j9N5L4XuiMh#CI+|rE6~w^Ysw? zGSb+Ozc>Cg^0ntydLc8GQOib`)l+v!S-&cLK?j$FkQsG5INuUdUl+VP1+TG=YXzqT z(0v3?DOANk2Kz|IPC>T~KOJL`?u}J?KRIFblkK8S6*5zDu7x_%t_p=|Ipan>S)@vr z;q-|f<9!qGPBoRa^DdTinVLnzz~n-7n>x2#fdr$RcF+aA=8lQp8FlpfZqT$J-0NW@ z->VF4ePof2eU4in_aN?8DJyLv&*;DuV(cc{fP64Ocp@C<@nDnFH3+7S65gpsaNVic z6uwN;hdIubu(}(pi!p7Np{@ zxGyp|G8|2A92vx82j(s#{H`@mvoSIl>r3_zM%E{&{} z(u|Dvh5F?)&`CLsHjV zo0P>My|!oSpZ3W3y7W}MlH*Bg$c8Z7|G-tJsR{dj3eFPC%RopDxe{ldlKnhM1OE!N zJ;=t)C5f{DHq>l21$nir_1M|dVW_(V6`$J#H%+SGd@H*`e3fNNb^;UmJq~ z2F?E9>Cm73MSmWKoRS;Fl_76I>SMgPY+4m(bc6T0*l$x0usVZ{H}eKE>#0qL*Xnv= zc)kvwro%i3V&1P_r{9KyDf52r)DOUN?cGY{!Y zXxBSwt5~tJNoi>=weikeh4{;iuHisq%zvAj@$k)09Yp*{rOZdGojkgHnCZcp$1hRF zW9>PizDyB|O7PxbY$)fqs})8LTtJrg&$u(q`T=A0K#g=5-wj^<$8!XqJPo+#yd<8o z7$iSMZf=`Ch;gHS+!n1jj2i=8bo-laSs1t3#BFiowwgHJHZE;;^10ZF-{QniDQqbO zhlTz8W_dmf4=Ndv2jl&$O3dbW)WcZzf}|PC;0+hagYi32-=%Fhm#;^Jh8E*@gBE;Y zSFI&nNqbT@$81wV{ymw@{Kej%Z=#32H+Ho{F636S-bci-SoEVMv#`KF5&M`Z~I8hzI)TUeIRvrH$4};S$8kV{%B-uJTA9Is^gHD z`-Oi1FVryzwrcMY6}sm*@pX0#;jk@y%V?@Utp_A_Er2k*;bCAKwHK0Xx(0{zJDvMI z3~PJKXT=opLAslshc>hPzL7+70G_n%dFa|$r02TMpTGmxby&9?8yH!uJvpgM z#^FR(5*v@1N#IcyjPnpTIf3b_l#_97jKjN@7H2-g#q6Yu)2?w+#aZlDTD*mbo8y`O zEGF3wy+w>q?W~JmjQEo5)iU2shMjzuAUs*B==)SQkEMvqI5>xBoPgJ52xq5LcJ~@!F{tX#NZ8^s(FUx5%a8)duEOE zG298#2LW+AMZX1$t3!J0ifIU63b@$|t;H~Hia7Aw0uM|wv(d{cjd3ZbV_`%22qDjG z%|NlNeI?)Uzc^bdW1s|TKG>1{$v)gjpZi!`8=-&3Cmoq$ZNxo2V`S;ZK!z{!=VYUJ zqOiy<8%+31*x)qtppf$8;aJ0hY~Sp|VmX>>*l*L{`tdTLxASm6Ufv#5u%!zQo(H}; z-~K0fHzOK-orA9ijba259X38;FmckuojM?jfq8qwIZbqPZ*)}O;g3hx!!?qz%Dfwk zv5gVPUQs}r_b$B7&{ETm_?vew*rsllHst}vcjn~LWM6Ms&+tjWqxE_N-O)eBRr!iE zZOT8_!Rs8_j+r(U92O)E>U*cMgHEG=#KZgV#feP02q#Xu9_5OLp#vTH?Fgld33P2Uqxd>dTpnP`DPV&n{vAGnnUxg1WFc3EWMc)DSaBlaIT-8@`F}S z{fOQ??vuh-{djH%rY=ZNeTAsCzV3%|Bm?!~=xro{GhwFNhq^X|p*WC5leJr4;57toKGXBeLa#(m^f95t;x6<6gfA!>)DT6!P>QTB7!xWNIV)bl!FL^OnQj2S z8@^FRC*AN(Dw=Y`A47V(A4Gm{QBe$G1A3n!KfM7zx2dR+s$)-Y2TyLAJD4V6(i{f4 z+zDHUCzoNO>|L{xwg-nnrw(^?>Q1j(gS~)@C$zzshJwwMM|%WNoNt1zthB{Q_`zr&RCI4CG~v^bb=QWEV{0j(e^19A&WmBH;b0OjZ(7uIx`yHWM$2Z2UZ% z7ha!nIMsVBIA^Z=(4!%PbFkWvGpLxb>0@87nm)$MBg5-?{vZ)sKkTplVNJankNz~#t>A^M z_?FQTEPzRVySX+|gNq?}?*=`CrOyGKZyWHuT0G4^hX4K1I16Cpj=@iIBhK;Dd*@K( ze1>q3tO-n~nFqQ~n%MA2+%GGx8Nhk#7`!*Kh}g*(Ua!v)TUj8T-d&HyD{v_O=X3Ezc@hnXSXq*FjIDzFhqN_{b2}eTO2$ z@GN5FPyO)eRl}jyW0BZ!GBP^aH!_4@Ru6uDhXa_OtDL<#@W;{>I%k?>;r{ZFrS-;`wsd=NNo2q{d~Ev zk0;mtcheT&Oi93nvGF{^;&USPf_>ehaHH+ULWZlk(ee8uzJ?nezX-7E?0tAR(AQ<=St1Nq(sKpO<0b9Uh})7$XECqWY6(r!Wn6)H-h^@U zIR6x-O(tLC}d)vO-(nt85%UMmmJ zdz0I6++h-Jj0b=@U*TE%w%R)lkPl&8t8BOD_*n`10J53GuYldexSVT~RcpSCH+wix zBdoO;U@(@)o(%3&n0X0#TW;QeujNfYF-{(cbEFxcZ{kuM*S|SFKM8WNpRUGh!cTeq z`w5X9?{{Fgn|ChQOt}!CWyE;Ct$}#w0eVv=!uW1+ri4r7nLM7Ca8n03eEYWw$Dw5B zja?=WHr4)AC5x-OJZu-p?pT4F=2yK3ZT+%H+XOI3$M*ohRnU|Jq&=5Fo?PQQ#gQl0 zgJJ&VjFs^<__Q9qYWC)oJ=etjckFcfYbq>1*Oc02O^9usXHPuvb*jS`&WpLnNBpxV z)oUpA^FgewY9E4JS0v3f4o$3~RPTT48C6YOw^{3;Zu9RP%zfW4I>WHDrmJsT+xmo$ zXS>#0HDBi%8umsl%*+g=z9>pO&K0mDTJ$SEhJI;82 zBc#q4^3<>Y?y1ud_u}2y!GBRmoz)Fr2*+ZL<%qEQ*$z)VAK{n0I;_5NjiUqxyscFdg&D(JR_l%I*jPiWo2VwQVA4BT* zAM(@({(^n(lu{qQEv){O_0)^r8d68y?WwC@9##hd?{ja({P0Lmz3oBVnn4*q@g3|< zybbxbh1J@3pbYVl>V6OMnM8iqhSWc<45^0_A$8X~!s^+JLTc-KJ+=K7oKQf$-T5_7 z-F}}^Kc9tvy#ENPk3Sw#M}Giv{CG%RxElBWuT$!EF|2IA)>A*YE3AI^MWp#)Nd4!E zusUgHNOgWJqy|3Ysh4$x)PB1{>Z%dkxw*kpCw*6`Ux1Gri=KM?e(-e{(tjbWa`=Af zCzX2F_muka2bFpT%5cF)v2L|Aq+W{03zyy(R?B9?>dUyTa_y%*_4EBa^@_)ode#$R zwG^`31!u)8t`4bpj4AaKczgcfC6N7>L#q8Zp8C_VA@%Kl!#XU|?EhhT|X82+qYj>Jpr9B=ajnQ{hs>m^F!*5FT*{J zLp=41yi#Af2L3Uia}VF8)Ni(V>cLNj)T!V1)D!OwtKEa1`Vsj07Rr@k1n}0*w z`RYeQ>YFK)6*_y#0-fIgI#Mljo`ZE`^(ThaSGysbezg0aBJOriod+HN^*_VvU56`m%Aub61lsof zup9rx;pq5Aw4eJBOq4&WqK|k&~A*^0@OGteH`o0Rh z4E`acUb#Q?Gdmc8yOPrdHlc<~YP{=n9d`osHi77RM{)&oQ8!;t&?!RvmX zMLYU@SnYx>{OpY(6`oV-EhyJ5Uka-aFGiii{=emH=5ZtRiy?l!e?rgI&${K_5M({{3%go0}kW*n{>zL66P}sVmWr_5=Pu$|3b5w1J@? z!meL}vmn3?ealnVf%oB`hg2Hn+x_n$b;(Ypc0KN?wh5&^iMCexc1T@-di>dou|IR0 zrw$$QRR33@!+F@ZzoR}wxV>0X>c9t;`cKI2HJf4k-iUP2ogeq2{pN7O;_i@IwGy`L zvaos*He~G^mHOfDVUu8oKMFoZ|0}HC_WZC~+2*O&0@nXl)ZevXb@>w5@FMKerm#9K z1{uwG>bPH`O`R7~r@zWmFF=2LFY@^!+Tqv_LhAlkdg_v?kUG5Vshc6=TL;i~P{#*< z7JUS0J-!BB)sW_8CwS`G4Ekc!WBB}#`p!E&^`%chZfBqldOUS%1U|=N@WTqbd;G`o zCfs>p_2-juwg~O(qBC(1_DJZ)QDIdH1wtCMerZWYkiqYeLY)>B7323}wfo{KvAB>0-VCam6oGKJA+ zZMrF}u7Dl63VHtxZRxSAp|4k>e%FN5yWfQuNYNj?`D>nfXA*DFpq@4iW32E3rAnEw z`o+6&YV?M%de!4NCws4_)}S6<{JoGmeTDG3xJEA$2Wm z$bH{b>b>uQjDLx?4I9vXI?9T6eF*IE3%7*T8>d5R24&oNO-P-+9DNUL;pE}a!K=|{ zp^bMzuRr)}w2_OEC-mz_N1-o%ZdhIY3-n2URO%nshSc^iW1R6B_#-+iq`rr`jKj9~ ze?Fu#=ojulyA7Y?snRdPYT~;g_4m)io}j(_*Jm+igI-<%oBz-*PyOus&Z!j!7E+fVigtmx3m3um9qp-Q*bPV)J@vaUL8qWEze1gD z`7*`|kl}YB-;Y3U!=tdT??+z_yRjAh>?@w(sk^^~e(as_1+_J#K6fX|4n6KenX=o% z>O|=L65t;7M~o@9!?$ZUY#;J??Ks9vXa_4G(+SArGV~kYxD@RQee3?~pywDrLN(M+ zU+<~kK%Q-5VRh<%qAgcomk&VtZ(wYPKJL~T=nCx0eHarx@Cx)dp!or`kps`hSnQ*) zpK0`+Xd9=)HqKv(G3+|_m9RtSqfHzfQvVV4)O%q6PW*LPUHKKIDjz|Ad0t4p3bx=H z*w~lD&RzX->~Vm`SDp`>oJ83U!&m`!aGZTc*Q@-&alCdh+QkIy$0aDot*^pZW1CXzH;2@3&_^Bu`#1N1Qs+GiSs#ObCk)=dfj;#o zO6`6}NafJhirX=+Qqb?0fF^9o&%TJU73{)G-iI+GUie6XiGm+suwzX?Ixw(aS^^>j=IE{?7OF6+ygm$_@%z7lng{g}1%2FFR`L$9EpW)5Lpfj|Fp zDZcNCi1XX0S<|GW&V<8RtM60dY{D;{dnpOH;%sgxaUQ>%@k+mXej|3k=gg|0t!U$8mqZ2N&MAEv zUy|j%XCJU)Ucv@d5of_GQK##Ea7u1vKR^ED2h5SH4rR^8I;ML-)Vb+W)|Bt@P5PIa z7xv&C@`i}>-mzfQGv98wm-X)H_)FIP&c(=H8F9AUT;g1eZF5WU4-d0$_z=JHCUwF` zT<|Bxe+#}4JFdk?eaJfQ4+pX?e}i%Q409g+HAersfx0el!&mlooP+VRbAHL1;YYOd zdhYp-h&Wr<;oHwStiYjK>D>3>gN&-`A;cz=)a zfgQhtBWq>u9)vG^g>iB6OSH{o`rU^m&dj^;@ys_@+>d>*@x{B*Z;!|Cti>PRzd?d(C}mx>Z^Su&P{jHDB~fP+{q85HvHoS9@t4um?+A3hjrDd1_XlN;)6JUuc>3Tq zhtsb*c*9BCJ@qR4sc)o?uW%0q|Cved^BF7Wvo2oxJpShww8wOw1>B48dbGr8fcM2X z>zMmkW6?gt&%qxu-dmK0#lXzc;w{Eu*gc@;-J7 z_XS-0o=Tq@M0sa9&U&ujxPki`uA?`y_j5ny)t8;{FSI~tfzSe>1wspi76>g6S|GGQ zXo1iIp#?$<{J*lmo{x@+Op+RLpFEL!-@ACG)W`YwV;(>7KMykb`z2`-rttd!?)BwQ zu!tm;r&tCrL-O}OhiAono6S=^9{L3TV&DqpVzU3IBN5BEI2C3)Rzr^|Q>GaFfvCt_ z!*ja7FSCV>!tNK}!IC6aW$mW2deg6yZ}pSSt8neDbT->KDIeoR`x;)?Mtr*-)OzRagUto2LCO|e?Et?qC|@cU%jBColJ2(S zg2DrdUOfk>Y-#g@QQ6{(57c;jKJ?zEPF^#|b8M28Jpl5}yFAMUJ5;+sXLAgoApwiB z>3PzzgQj=HV{+z4h8+~xTIxh!1CRnH{bLWoKU^mdw;Oq)mjsJZEj@Z)sTai!lIt4z z9Vrzax85$Ub%Zp@vlmxM8LWARXdYXJm0zO#LQ5H+QvRVu{QE;o=uZghG)&^qX}Db1 zxH`%Bvu$yZ7auK^-vdYyy~VDUNBCuo_5qulpRRlv==_aR`G=|;gC*@Id1;3il_9ch zJxh=yb(8W;UL%+HC@S|T%^Tz|Bd(agT=^@MU+S;|nYIp<8gH?$#{^`EEV_v^R%MLy zWJF6>ppV$imM^sAoj?$Mg_d@isCkbGf}Po{YBQR7?tuXXvSdGV1_9#eY!GrV~C(ckuq3_R8^&-Qp+eQjA) zfp~H0mVa(hyydSB#EZ_Be?cH#bhGg%`|&)j=9?I3v2%vsa@Ikeq+^SEpRcqmkbj}Z zTYH`aogv-!%RR8dBH=;CV&xTkiVUmsXZ?7i!#rroFZC52mTLZGKA-V#whpIiywzbo zwB!xy(5y1zMKY`o2|wQGPy;Rb#fG9oo91u#`ASEUW_37CU=vEmki)2_GR(tWZ{SLN+s%@ed=)qKHHcX8JmVm+m(%r6zy=X~hm`dlD9)aOFw?XPDTy1vpq&oB~k z&$k~*KN`W=k``;_BJzNu!D)N5@+pG`>h4n&j8Mm6Z)TQ5T4ZOlt}8BfG0!6}n0NwAsE1r| z>?>ep!Y}W>*|RKoJjv7DR4dVxdl~7&n6ZWTYy2*AY>DgjGEp@WLMQ8ba*be;N%%byOWqe-c<%#Ue>uzIH zv8(a@TxDzqgYj9!??KCLki5va#?!%F7oQ33`?iSlZRNX8`K%ulKB=$I8+E>;yf-MX zU8@PN*hB2#^Yguf@S(#^a;5G;*~LETX63!52VSwAFE{Gkro6Wo@!B<`@Ve{8sB?$% z-l@ET^+e5Z6~VvQ+`7ee^)stu^;H~F!6<4dh+*)^+U0I!*!l7vl{dLyOmS8>8;0#( za#;s}zsEsfW4t}?636~);>Madi#_#y&&ojiTUGj_lP94u)vcbijSYMWM091lLU z#!K7P1H5j}aIhmo(bDN7ZhmREdd^Gqj#74!6EZUBtt@G)0-gdFAm?VevfMHQvI?dI zpHJGeK%TgSQ)U?19)77T0r?g1#5y};@$OtE zIc8#vqaeMqgK7Dqv@wBv*_dP%d{Ecs6D7^P1&?KOEy;8&BL|tc#?pFHFy&i2Y|opG zH>G@5YlmY+W_Nt0N-}M-gS2dnxnT!s8A-GK)XH>A>~M)}0X+E1R9<)_aT7iuhip*Gd)@BUaq$poO zy^GRJy{#^;{j-5a_3KcaCK+wJHM;d%S!}Pu_(FTdtW9jDz!)e>Gy2=I&Nlg4y>4f9 zFN`lNt1wM8_kE+LSuMPNS`aVd0{UH`x_e5HX7yWFkmmPoiSN#)+$@3euW zhQ=4xr!dW}kInbhg7Ra=b~f!YH!bcJ7N}EET0y_KvM`^)nzu5GY+?GZwZ*k=zU^#V z5U;kid9Ei)g`fYDYwI!yuwA5I9}wLB#Tt!YNG8>HZ1dq3@_r@Iria_$gkfF!)R@imj?&!Gkv zs%4%aB6+&IJX7N<@|+*zGXNsek5=MUDjD_CQqh2y5M zhGLLge?FXrLrpt)nsVw3*xuY|%}BPIT9|t+E9)r3=hwrXnW!&qU}YU{7HCeCG* zSxy)|drmQY=G=!a@GCWaEcasWd^FRf&s>q`kY+#CpC>C#x&e>O%9QUhp^KH_@&GAS z#9{m899ITs%=@`*-djxCjC_VC<=kDm49K>5r(qT9%%Qg`9k$lgSPu_9x zc_(Y@K7)S+EzhY2u+FslcFOo`&4MdCaeNYetzB;l*g%bLWWI-lS~=Y!?!`_g(IPu%<*1F>th9un^IzC!#y=)u+_ zQ@1UemrsB_y~dmJ;^`EtD65y9Fl8KD{a=8uroDB$f$Sd1?XQO_d|kjT11F8Taerji z?KdG~Wjq`2sUbfHO?zUk%#mI5n zFdJJK(0MXt(2r9ciPR^uS&X{bGCwdjo9f~Tf}>~cP~zG_M0#WN0peI|*ES`y0+9=X zu`fr?AQikoi-~J>e~3JI%j$Fsr$V^!=BG&A7OHLI#znRrZPMPdI{4wy7k%zYlNK*(gc`su6&0zAi zVv}H7st+yj!&dLN&|AjB?0)FF3+$8c6g#%HNRJe|yp8-p=+vKmNVY#d23?F-Y|}<* zzXNg2?RHBzb585lqpvVa2)|DZB|q*2&`?H`w#^^WL44qemF{?dU+Gs*bm_k;y?&nG zcD;@N7=6(8wF=djvyTFEpr3xHrU%B6Ig`fLDM{I!zLt=i{rWWPiKY%q8vA`jx;(F+ zLcg*$I)pgwSMFe@p0>}OB>kqypL#bBj6qxOxjpges@0Yw=Omkf=fR-)&lFxJKYs6& zrsWBI%69J0=+47DWA~fb^I`2Z!`IzEbS5ws4yCTKL{}H50C{8KL*i&s;}>i_OO0Kv z-&N#C215>yDMw3KzTWI1{lnJvPV@@kYfrU(XLqf`&yJF3Y3>+ng4Z@uecC;n-aM?) z{??Z~GS7X3HcRzBraF`Hu5>otnk(Z7EY?Y7*<79*_r|f6V~%N*c_+_9hSiPT@x~la zVX}>#S$>WgUx7~=J3)BtJdjuw&*XH>$vF^}v=0~44uiA~8>xf!!Fg$af9m#ZeGGat z7v<8dYb~$5=6e9SZR+et*wzB#da%JWEB6J$7p z(&p`D%;J*Vd1!=|d0(K+cd6g@^Uz7@<^|2N!0_smHe;$b(a9Z<>wKr>lO3F|gls#0 zCm9}tW2!te%{L%Y-!jTR9la;h2ds^LZ^|y5vvdYD{b;1-VcE8;=ATrqBiqDKF!Dzs ze=dFKhdk&P9S>9cESu%GNpE(QvmC7bzia9)>*lIlqO&g9nUUp1wml~Y*}-RhNwwd1 z#4VWfd8O>pTK08R*2FTBi zSNN9a=akJoV?LLj!QHOj@oJy2{m_n=e5T85)5SgLoOPcHc|1MOpYCLB>mctQs+%$k zlZllJTE(FP_ua&Oi!J+hDTljt7C~Ozof4HOc39$#iq9m6xiXjeG7pu8l?K z3e|Zl_kQ-d!;bu<|B%A(@4fgpmh*mJYcsZ6lITjiXPeZgjRCQo>ys+cL*|Nc%oTQw z{La{}6~`b;2zMD{?OFjZ>tW;jisHmId1I%yxn0(1wr$^|EVtcFp9nrc@%)Et9pJ z)oq|FN9VpBuZ48Yr1yc_^VvEK!v3*%yP2b!I0jkfeA|y(g8i8Gwe2&GJal_=KWOdl zKWFIq8N&p%$*p{pI9At5Gj@F6>#l&zV~&nwGi7&cp6SOm(y-=!PP~Y{pR4xPRtw#= zRb60h#Zw<$TP>X4SZ~%=)ph&~uC1Drsm3|!Y;Mt{iH+PLHcp>ckyyo8e^<*bkC&BK z^`da_M*Z(`QX{*T>z%dG3Vxm?$+GfPx+C3|E-OD}9AQyec}udXEky;A@$7N&jwTMC zLE~&oM_GAwOrAXhmX*(* zMd(Dp%sE;458<`-)5jpa9?`Sw%F0_a$7Q+_aqivA%9q5CTN&r>IhHfO!9}i%r!#Is zGS$HW59B$$th|1DS$Pw$`B$HwKs2`kY2LwQ(p@=3al|aSt498-T3lDtBjsBN_c_eJ zvb3gLM`vr?HsQ!!QqMtZvWv_^9d?6|Rw)(KW*S~z!d zs8cd{cjrtr{Q^N&v*!`MNO*Uflo9@g76>g6S|GGQXo1iIp#?$buMxHqUMD<4c!IEPb} z*Uf~N3Boe~+`&PF{RsOK1``e<{2AD z6UIcHC%H~31$&U|vxLS^f$=;7`Gg^aGD1JXeuUwKC4@FYf-sj*MOZ+nCM+f_BS`v% zgo_B@BwVZX#axHn4!$baCkW3IULgDrVb33f;m-9n!dAlLgl7p)6NE?N-yjU2PNjr_ zgdv0j2?r5|6AmF9PB@Gpe1i!45QJ|iVFY0yn4Y7!&Lvb4>It=k#e@T2bDX7IUmFMR zG}osmMx6y*s|gDUjf7JP%Ls2BK)txGBP<;Z1|-)f2%8D>mQp^rqmi4zJmkH84fvZK z4{~+`xbB0%zP;{3aNC!bID3POc^LSM1He5!XEL~%;7B&CVV?-NmH8xi$l!=R1}5(b z;7|5{vc%a7tk#FXoxK{&%zL(h<;{b!5uc7aH%UG%@`35MiQuq~&9Exirg)@{c|oL6Y?Sr35a&#u@pZ_!7=L`|OIIHzp{ zlbv!;1c!6oY{&UMdrH@%!;9-3=TBhRu6POj-{-*0-U4ps-y+Wb;5=WI1T**;`r}!S zvym5~M_mX1c*nWswusXX&+t3InFdGsW#s($YOv=oYF9b@}GcR{W@6ao8YZw&)FjS-CevpYoWhg2970|rN@G)@de%i zekKL}CwQH^eHV=6uScCr4~set7x13>gotw#IIp9?D*fpY_F93*x;{fYe*{kLUEl|U zZ}~Fq_s{_)2EX|=e&4_t8Gc37d4t~$IIKrK#F-BKUNDqC%Josg`Z(hh-0VK2$75iO zgY)|o@zb9n4{h+d>!Qxl)U{6~xbruIn|=|vuiez^ze}7w_hx)u47NP{*WS-JDKCJH z3jS~93iNrHeeOqtWlY+q!3chi>uojcY6NpMwvzK3#D2tWA#5c)KtJ1K3^=ynw7zvE zSkc67yBzFW}L)V7lIYHFyo3V6xu> zjx#*BpG<$h798>4lsJb%F9eTu?q)Ex!8{c`P65}rAJ?DS(8+;Hx|Eno{r8CQMi&wqUgyD}y&jg~l5K7$V=&sWxf zp`I^srvDKvMR@y z&pWhBCD`&umN>Vf%gxKcj>c|mv^0OC_FN)Zc@Jc6PjDNUG;r0Uu~qk@-9KPe3yB8ty|t@O0QB{upuP9LFun6oq+})Xt3Dg zlkT;W@3~^BT*1Dddyyym%vAKfznbk#?--Rzl=%Q~I+?|5@o~rT+pg zHsO(w;g8TSh2~b<(0!q$9x>IspVDKM-c#vvrT2!G@~`45D>;DnZLicEjXTID-D7K)pft& zokm$@l*J>7UFSQptFw)=2Sxi?7iEm33?9{(cFrn2N$Jl+i!XWila95(N0scF%;qx` zq$+tC4F=k?hB-sh^fuaK;sV|q@2-|!%-)n%-;lcUXf4a6D_h4-fM^Fk#{8W zctmS#^rq50*4ugcnf7LOpBLCgkR{8J|Axx%t2B=wOnC#8K11pKmHwmBBb9z$eZdh* z|61vZN*}2{s!r*(%uCXz819ektMsW#Z&tcl=~t9)QTl16Ta|uT=`N-3+`}zz zrP3$$b?MJ5eYw(Wluq;Qy6AVV(mzr9GNr53N3U0UtL``1p!8izUk5F|i)Q-==8H@= zIA8n_S+X}Uu5I-*r9W2sai#ld+dQQ-kAqEJo>7|Pcm4rglIfr>&ml{&C!^ZVzf#$M zR$VqLy_crHqVx|m{Y|BLL~nHaozgr4GxR&qGG|;_;nIIm`f#2BOS}9{>37-dAarDq z%m0zmyDL3V`Q`i|k+HU=c+h~`6u+raC`T(V$RsLa0KcVzN zN`Fo1gP~=v=NKfT?`UZ07jfox!#|7Fh{& zIZ|a$QF^@6)3mHjN>?fU3#I2O-ACK5R%u={eKOsGJ}}ds&n0Cg;?6@0ktH|;W!Py~ ztYLLOx97B_?<}T_6lL%lVwaS`o@jSo5O1qBgh7mMz$#QfJ|e7W_($%;@qp*McK7_T2oh7k_~`#zp_fsGvz8+|8l?2KX3*GKa)9zAmf1wspi76>g6S|GGQXo1iI ip#?$+L(MY-$D`r_vg? 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 Ju0mRQ{x96H!7l&+ literal 0 HcmV?d00001 diff --git a/tools/delaylib/bin/Debug64/delaylib.pdb b/tools/delaylib/bin/Debug64/delaylib.pdb new file mode 100644 index 0000000000000000000000000000000000000000..4f5770e5944b0847f1b65f42e03d24b05b22a533 GIT binary patch literal 135168 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